Legal Information

Windows Driver Development Kit

Information in this document, including URL and other Internet Web site references, is subject to change without notice. Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, e-mail address, logo, person, place or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation.

Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property.

© 1985 – 2001 Microsoft Corporation. All rights reserved.

ActiveX, BackOffice, Developer Studio, Direct3D, DirectDraw, DirectInput, DirectMusic, DirectPlay, DirectShow, DirectSound, DirectX, DirectAnimation, JScript, Microsoft, Microsoft Press, MSDN, MS-DOS, MSN, Natural, NetShow, OpenType, Visual Basic, Visual C++, Visual Studio, WebTV, Win32, Win32s, Win64, Windows, Windows NT, and XENIX are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries.

Macintosh and TrueType are registered trademarks of Apple Computer, Inc.

Kodak is a registered trademark of Eastman Kodak Company.

3D Studio is a registered trademark of Autodesk, Inc.

OpenGL is a registered trademark of Silicon Graphics, Inc.

Intel is a registered trademark of Intel Corporation.

Itanium is a registered trademark of Intel Corporation.

Unix is a registered trademark of The Open Group.

The names of actual companies and products mentioned herein may be the trademarks of their respective owners.

Built on Wednesday, July 11, 2001


Operating Systems Supported by the DDK

The Windows DDK supports driver development for the following Windows operating systems:

  • Microsoft® Windows® XP (32-bit and 64-bit environments)
  • Microsoft Windows 2000
  • Microsoft Windows Millennium Edition (Windows Me)

When you install the DDK, you can select which sections of the DDK to install, based on the systems for which you will be developing drivers. For example, the Windows Me section is one such installation option.

If you decide after installing the DDK that your driver should run on an additional operating system, use the Add/Remove Programs utility in the Control Panel to add the section for that system.

Once you install the DDK support for your target operating system, you can develop your driver on any of these systems. In other words, you can code and build a Windows Me driver on a Windows 2000 operating system, or a Windows 2000 driver on a Windows XP operating system. However, you must test the driver on the target operating system itself.


Using This Documentation

This chapter provides the following information to assist you in using DDK documentation:

Using the DDK Viewer

Documentation Conventions

To assist the DDK documentation group in improving this documentation, please fill out the Documentation Survey and send it to Microsoft.

The Windows DDK is constantly being updated. For information about where to find the latest copy of the Windows DDK, go to http://www.microsoft.com/ddk.


Using the DDK Viewer

DDK documentation uses the viewer supplied with Microsoft HTML Help (hh.exe). This viewer provides a table of contents and an index. Additionally, the viewer enables you to search for text strings, print one or several pages, and create subsets that hide topics you don't want to see.

The Contents Tab

The Contents tab provides an expandable view of the DDK documentation's table of contents. This view provides a single top node, called "Windows DDK."

The DDK is organized as a set of "books," and clicking the "Windows DDK" node's icon exposes a set of nodes representing these books. Each book contains one of the DDK's major topics.

Most books are divided into "Design Guide" and "Reference" sections.

The icon for each table of contents node is clickable. Some nodes display text when their icons are clicked; others just expand to a set of subnodes, and others do both.

The type of icon displayed for a table of contents node usually does not indicate whether clicking will display text, subnodes, or both.

The Index Tab

The Index tab displays the DDK documentation index. This index contains the following:

  • The title of every topic contained in the documentation
  • The name of every function, structure, IRP, IOCTL, or other item for which a "reference" page exists
  • Every glossary entry

The Search Tab

The Search tab gives you the ability to search for any text string contained in the documentation. You can search all text, or limit your search to topic titles. You can search for strings that are exact matches, strings that are similar to a specified string, or strings that are near other strings.

The Favorites Tab

The Favorites Tab lets you save the titles of commonly visited topics. While viewing a topic, select the Favorites tab and click the Add button. Later, you can use the Delete button to remove topics.

Printing Topics

To print one or more topics, select a topic icon on the Contents tab. Then click the Print button on the taskbar. You will be asked whether you'd like to print just the selected topic, or that topic and all of its subtopics. You can also print the topic you are viewing by right-clicking within the view window, and selecting Print....

Searching within a Topic

To search for a text string within the topic you are viewing, press CTRL+F, or select Find in this Topic... from the Edit menu.

Creating Documentation Subsets

If you don't want to view the entire documentation set, you can create a subset by selecting Define Subset... from the View menu. You can select the set of books you'd like the subset to contain, then assign a name to the subset. Then you can select the subset using the Active Subset dropdown list.

After you have selected a subset, only the books in the subset are available when you use the Contents, Index, and Search tabs.


Documentation Conventions

This documentation uses the following typographic conventions:

Convention | Indicates
bold | System-supplied or system-defined functions and support routines, structure members, enumerators, and registry key names. For example, EngCreatePath is a system-supplied function provided to support graphics drivers. These items appear in the system header files provided by this DDK exactly as shown in this documentation.
italic Placeholder function names, formal parameters, or any other text that is meant to be replaced by driver writers.

For example:

AddDevice is a placeholder name for a required function whose actual name is defined by the driver writer.

DeviceObject is a formal parameter to a number of system-supplied support routines called by kernel-mode drivers.

Italic items in registry paths are placeholders that the driver writer should replace with driver- or device-specific text.
UPPERCASE | Constant identifiers, structure and array types, bitwise operators, Microsoft MS-DOS® device names, and system-supplied macros. For example, FONTOBJ and IO_STACK_LOCATION are system-defined structures. Uppercase identifiers must be typed exactly as shown.
monospace
 Code examples, such as:
    hwInitData.DeviceIdLength=4;

Note Some of the interfaces described in the Graphics Driver Design Guide and Graphics Driver Reference follow the convention known as Hungarian notation for formal parameters and variable names. That is, these are prefixed with lowercase letters indicating their data type. For example, lpszNewDocname is a long pointer to a zero-terminated string. For more information about Hungarian notation, see Programming Windows by Charles Petzold, published by Microsoft Press®.


Documentation Survey

Please help us to improve this documentation by taking a few minutes to fill out the following survey. Instructions for how to send us your feedback are listed at the end of the survey. Thanks for your time.

  1. On what date was this DDK documentation built? (To find the date, please scroll down to the bottom of this page.)

  2. Which sections of the documentation do you use most frequently?

  3. Which topics in those sections are of most use to you?

  4. Are the topics organized logically for the work you do?

  5. Is it easy to navigate through the information? (For example, are there enough jumps? Is the index useful? Is the text search capability useful?)

  6. Is the information presented in a usable form? (For example, does the Design Guide information clearly explain when and how to use the functions described in Reference pages? Are there enough diagrams?)

  7. Have you found any errors or missing information? If so, please provide specific details.

  8. Can you suggest any additional improvements you would like to see in this documentation?

  9. What kinds of drivers are you writing? What kinds have you written in the past?

  10. For which operating system environments are you writing drivers? For which environments have you written drivers in the past?

  11. What is your technical background?

  12. How many years have you been a device driver writer?

To send your survey responses, please copy the survey questions and paste them into an e-mail message with your responses, addressed to:

ddksurv1@microsoft.com

Use this email address for documentation feedback only. The documentation team cannot provide technical support.


New for Windows XP

This section summarizes new features of Microsoft® Windows® XP that affect the design and development of drivers. This information will be useful to both new and experienced driver writers.

This section is divided into the following topics:

New Table of Contents
All driver writers should read this.
New for Kernel-Mode Drivers
All driver writers should read this.
New for 64-Bit Architectures
All driver writers should read this.
New for Device Installation
All driver writers should read this.
New for Graphics Drivers
Developers of display, print, and other graphics drivers should read this.
New for Kernel Streaming Drivers
Developers of drivers for multimedia devices such as sound cards, DVD players, and TV tuner cards should read this.
New for Modem Drivers
Developers of modem drivers should read this.
New for Network Drivers
Developers of NIC drivers, intermediate network drivers, and transport drivers should read this.
New for Still Image Drivers
Developers of drivers for imaging devices such as digital cameras and scanners should read this.
New for the Build Utility
All driver writers should read this.
New for Testing and Debugging Tools
All driver writers should read this.
New for USB Drivers
Developers of drivers for USB devices should read this.

For additional information specific to Windows XP, type "Windows XP" in the DDK viewer's Search tab.


New Table of Contents

DDK documentation has been reorganized and expanded to achieve the following goals:

  • Group all related information together and eliminate duplication.
  • Separate device-type-specific information from general driver architecture information.
  • Add new introductory and "getting started" information.


New for Kernel-Mode Drivers

Drivers for Microsoft® Windows® XP that need to queue IRPs can now use the new Cancel-Safe IRP Queues to simplify handling the work of queuing and canceling IRPs.


New for 64-Bit Architectures

Windows XP supports Intel's Itanium™ architecture. For information on how this support affects driver development, see 64-Bit Issues.


New for Device Installation

INF files support the following new features:

  • Decorations for installations specific to 64-bit platforms. See Creating INF Files for Multiple Platforms and Operating Systems.
  • Operating system version numbers in INF Manufacturer sections.
  • An INF CopyINF directive, which is useful for copying INF files for multifunction devices.

Setup introduces "trusted" and "untrusted" hardware ID matches. See How Setup Selects Drivers.

Setup provides additional logging options. See Using SetupAPI Logging.

The Device Manager provides a new Details tab and new error messages. See Using the Device Manager.


New for Graphics Drivers

Display-specific updates that are new in this release include:

  • DualView can be enabled in video miniport drivers for adapters that can drive two or more different display devices at the same time. For more information, see Supporting DualView.
  • Microsoft® DirectDraw® and Direct3D® are DirectX® 8.0 Beta-compatible. For more information, see DirectX 8.0 Release Notes.
  • The video port driver provides support for bus-master DMA in video miniport drivers. For more information, see Video Port Driver Support for Busmaster DMA.
  • GDI provides support for events in display drivers. For more information, see GDI Event Services.
  • The video port driver provides support for events in video miniport drivers. For more information, see Using Events in Video Miniport Drivers.
  • The video port driver provides support for spin locks in video miniport drivers. For more information, see Using Spin Locks in Video Miniport Drivers.
  • DirectX Video Acceleration is a specification for hardware acceleration of digital video decoding processing. For more information, see DirectX Video Acceleration Overview.

Printer-specific updates that are new in this release include:

  • Developers of Pscript printer minidrivers can now add support for two features: AddEuro and TrueGray.
  • Windows XP supports versioning in Unidrv and Pscript printer minidrivers, as well as in IHV monolithic printer drivers. This feature ensures that when users upgrade to newer operating system versions, the most recent printer files will be installed. For more information, see Specifying Printer Driver Version Numbers.
  • Several COM interfaces for printer UI and rendering plug-ins are new for Windows XP. The interfaces for UI plug-ins include the following:

    IPrintOemUI2 COM Interface

    IPrintCoreUI2 COM Interface

    The interfaces for rendering plug-ins include the following:

    IPrintOemPS2 COM Interface

    IPrintOemUni2 COM Interface

    IPrintCorePS2 COM Interface

  • The Microsoft Unidrv printer driver now supports the following vector graphics capabilities: HP-GL/2 monochrome (PCL-5e), PCL XL monochrome (PCL-6, and pseudo-vector graphics). For more information, see Using Unidrv Vector Graphics Capabilities.
  • The installation of a port monitor no longer requires an older-style Windows NT® 3.1 INF file. Port monitor installation can now be done from within an ordinary printer driver INF file.


New for Kernel Streaming Drivers

Microsoft® Windows® XP includes support for AVStream, which is an extension to Kernel Streaming 1.0 system services. For more information, see AVStream Overview. New material on AVStream for Windows XP includes the AVStream Minidriver Routines reference chapter.

Windows XP also includes support for writing a Broadcast Driver Architecture (BDA) minidriver, which is a specific type of AVStream minidriver that controls hardware on a TV tuner card. For more information, see Broadcast Driver Architecture Minidrivers.

The documentation covering USBCAMD and USBCAMD2 minidriver library has been updated. For more information, see USB Camera Minidriver Library Design Guide.

Also supported is the AV/C protocol for AV/C subunits. For more information, see Introduction to AV/C Drivers.

Implementing still pin support in a video capture source filter enables an application to capture a higher resolution still than from the regular stream. A user may also capture a still by physically triggering the capture if a device supports this (that is, a device has a hardware trigger button). For more information, see USB Camera with a Still Pin.

WDM audio drivers can now provide GFX (global effects) filtering for audio capture and rendering streams. A GFX filter for a rendering stream, for example, might provide equalization, bass enhancement, or speaker correction. For more information, see GFX Filters.

Hardware vendors can now display their company logos and proprietary device names in the Sounds and Audio Devices control panel next to the controls for their audio devices. For more information, see Control Panel Branding by Vendors.


New for Network Drivers

Network-specific updates that are new in this release include:

  • Plug and Play event notification for miniport drivers.

    Through a new miniport driver function, MiniportPnPEventNotify, miniport drivers are notified of changes in the system power profile (battery or AC power) and when a miniport driver's NIC is removed without prior notification to the driver (a surprise removal).

  • 64-bit statistical counters.

    All 100 Mbps and faster NICs must support 64-bit counters for certain statistical OIDs. For more information, see General Objects and Connection-Oriented Objects.

  • Canceling send packets.

    Protocol drivers and intermediate drivers can set packet cancellation IDs in packets and request the cancellation of the pending transmission of marked packets. For more information, see NdisGeneratePartialCancelId, NDIS_SET_PACKET_CANCEL_ID, NDIS_GET_PACKET_CANCEL_ID, NdisCancelSendPackets, and MiniportCancelSendPackets.

  • Registering a MiniportShutdown function.

    Miniport and intermediate drivers must register a MiniportShutdown function when calling NdisMRegisterMiniport or NdisIMRegisterLayeredMiniport, respectively. Such drivers should no longer call NdisMRegisterAdapterShutdownHandler to register a MiniportShutdown function.

  • OID_GEN_MACHINE_NAME

    This OID, which is optional, indicates the system name. NDIS sets OID_GEN_MACHINE_NAME only once after a miniport driver completes initialization. NDIS does not dynamically notify miniport drivers of a change in the system name. After changing the system name, a user must reboot the system so that NDIS notifies miniport drivers of the new system name.

  • •NdisMInitializeScatterGatherDma is supported for serialized miniport drivers.

    Serialized miniport drivers can now call NdisMInitializeScatterGatherDma instead of allocating map registers.

  • Packet stacking for intermediate drivers.

    Each NDIS packet now contains two NDIS_PACKET_STACK structures. After calling NdisIMGetCurrentPacketStack to obtain a pointer to an NDIS_PACKET_STACK structure, an intermediate driver can store and retrieve driver-defined information at locations referenced by the pointers in this structure. This capability allows the intermediate driver to reuse a packet — that is, pass the packet to the adjacent driver without having to allocate an additional packet into which the intermediate driver copies the original packet.

  • Notification of Plug and Play events by intermediate drivers.

    An intermediate driver calls NdisIMNotifyPnPEvent in the context of its ProtocolPnPEvent function to propagate notification of a Plug and Play or Power Management event to the overlying driver.

  • New miniport driver attributes.

    Callers of NdisMSetAttributesExcan set three new AttributeFlags: NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK, NDIS_ATTRIBUTE_SAFE_BUFFER_APIS, and NDIS_ATTRIBUTE_NOT_CO_NDIS.

  • Miscellaneous new NDIS functions.

    See NdisCopyFromPacketToPacketSafe, NdisGetPoolFromPacket, NdisQueryPendingIoCount, NdisGetFirstBufferFromPacketSafe, and NdisGetSharedDataAlignment.

  • Identifying allocated resources.

    Miniport drivers must now use NdisMQueryAdapterResources to identify allocated system resources.

  • Miniport drivers must have default values.

    Miniport drivers must have a default value for every key that they read from the registry.

  • Safe functions.

    NDIS 5.1 miniport drivers must call the safe version of functions (NdisBufferVirtualAddressSafe, NdisGetFirstBufferFromPacketSafe, and NdisQueryBufferSafe) instead of their non-safe versions.

  • Obsolete functions.

    The following functions are not supported in Windows® XP and later versions of the operating system. NDIS 5.1 drivers should never call these functions. These functions are supported only for legacy NDIS V5.0 and V4.0 drivers:

    NdisGetCacheFillSize
    NdisImmediateReadPciSlotInformation
    NdisImmediateReadPortUchar
    NdisImmediateReadPortUlong
    NdisImmediateReadPortUshort
    NdisImmediateReadImmediateSharedMemory
    NdisImmediateWritePciSlotInformation
    NdisImmediateWritePortUchar
    NdisImmediateWritePortUlong
    NdisImmediateWritePortUshort
    NdisImmediateWriteSharedMemory
    NdisMPciAssignResources
    NdisReadEisaSlotInformation
    NdisReadEisaSlotInformationEx

    Windows XP and later versions do not support NdisQueryMapRegisterCount for any NDIS drivers.

  • Remote NDIS.

    Remote NDIS is a bus-independent class specification for Ethernet (802.3) network devices on dynamic PnP busses such as USB, 1394, Bluetooth, and InfiniBand. Remote NDIS defines a bus-independent message protocol between a host PC and a Remote NDIS device over abstract control and data channels.

  • NDIS 3.0 protocol drivers are not supported.

    Only NDIS 4.0 and 5.0 protocol drivers are supported. All protocol drivers must supply ProtocolBindAdapter and ProtocolUnbindAdapter functions.

  • Intermediate drivers must be deserialized.
  • The EISA bus is no longer supported.


New for Modem Drivers

Microsoft® Windows® XP supports Country/Region Select.

Windows XP does not support the following:

  • Non-Plug and Play modems
  • Unimodem IDs
  • Modems with a baud rate of less than 28.8K


New for Still Image Drivers

Microsoft® Windows® XP supports a new imaging architecture called Windows Image Acquisition (WIA). Vendors of imaging devices such as digital cameras and scanners should see Windows Image Acquisition Drivers for details on providing drivers for this new architecture.

The WIA Video Snapshot filter is an addition to WIA that ships with Windows XP and later operating systems. It is a filter driver that enables frames to be captured from the video stream. To capture high-resolution stills from a video stream, still pin support must be implemented in the video capture source filter. For more information, see USB Camera with a Still Pin.


New for the Build Utility

Microsoft® Windows® XP has many new features in the Build utility.

The Build utility should be used to compile and build all drivers that will run on NT-based operating systems, as well as on Windows 98/Me. The documentation of the Build utility has been completely revised.

For full details, see Using the Build Utility and Build Utility Reference.


New for Testing and Debugging Tools

Microsoft® Windows® XP features some expansions to Driver Verifier, as well as a radically new set of debuggers.

Driver Verifier

Driver Verifier has several new options and features:

  • Enhanced I/O Verification tests
  • DMA Verification option
  • Deadlock Detection option
  • SCSI Verification option
  • Improved Driver Verifier Manager graphical interface
  • Expanded volatile settings

For details, see Driver Verifier.

Debugging Tools for Windows

A number of powerful debugging tools, including WinDbg, KD, and CDB, have been completely revised and updated since the release of Windows 2000. These debuggers are part of the Debugging Tools for Windows package.

Debugging Tools for Windows can be installed from the Windows DDK CD. (Note that this is a change from the Windows 2000 DDK, where the debugger package was installed during the DDK installation.)

For more details, see Debugging Tools for NT-Based Operating Systems.

Routines for Debugging Drivers

Two new routines have been added to assist kernel-mode drivers in sending messages to a kernel debugger. These routines allow you to indicate the severity and cause of each message. When debugging your driver, you can choose which messages to display and which to ignore. For more information, see DbgPrintEx and KdPrintEx.


New for USB Drivers

Microsoft® Windows® XP features new USB driver and stack architectures. For more information, see Windows XP USB Driver Stack and Windows XP USB Device Stack. In Windows XP the generic parent facility formerly provided by the USB hub driver, usbhub.sys, is now provided by a separate generic parent driver, usbccgp.sys. For more information, see USB Common Class Generic Parent Driver. The new generic parent driver supports certain features of USB content security. For more information see Content Security Features in the Composite Client Generic Parent Driver.


Overview of Windows Driver Development

This document guides you through the planning and decision-making process involved in developing a Windows device driver, starting with design and continuing through distribution.

Given the wide variation among devices and the intricate nature of driver operations, no single driver design or development plan can cover every possible technology. However, any driver development project will proceed more smoothly and efficiently if you:

  • Follow industry standards for hardware and drivers
  • Understand important operating system and driver concepts
  • Decide early in the design process which operating system platforms to support
  • Test for device and driver compatibility with all Windows operating systems you plan to support
  • Use up-to-date driver development, debugging, and testing tools

This guide is intended for programmers who are new to Windows driver development. It assumes that you know C and might have written a driver for other operating systems (including MS-DOS®, Windows® 95, or Windows NT® 4.0 and earlier), but have not written a driver for Windows 2000 or later, or for Windows 98/Me.

The following sections provide further introductory material:

Components of a Driver Package

Steps in Driver Development

Additional Resources for Driver Writers

Because the purpose of most drivers is to operate a physical device, this guide is aimed at those writing such drivers. If you're writing a file system driver or file system filter, see the Installable File System Kit (IFS Kit). You can order the IFS Kit through the Microsoft web site at www.microsoft.com/ddk/ifskit.


Components of a Driver Package

Supporting a device on a Windows operating system typically involves the following components:

  • The device
  • Driver files
  • Installation files
  • Other files

A brief description of each component follows.

The Device

If you're involved in designing and building a new device, follow industry hardware standards. Building devices that conform to industry standards can streamline your driver development process as well as reduce support costs. Not only do test suites exist for such devices, but in many cases generic drivers exist for standard types, so you might not need to write a new driver.

See the Microsoft Hardware Development web site at www.microsoft.com/hwdev for information about industry standards and specifications.

Driver Files

The driver is the part of the package that provides the I/O interface for a device. Typically, a driver is a dynamic-link library with the .sys filename extension. When a device is installed, Setup copies the .sys file to the %windir%\system32\drivers directory.

The software required to support a particular device depends on the features of the device and the bus or port to which it connects. Microsoft ships drivers for many common devices and nearly all buses with the operating system. If your device can be serviced by one of these drivers, you might need to write only a device-specific minidriver. A minidriver handles device-specific features on behalf of a system-supplied driver. For some types of devices, even a minidriver is not necessary. For example, modems can typically be supported with just installation files.

Installation Files

In addition to the device and the driver, a driver package also contains one or more of the following files, which provide driver installation:

  • A device setup information file (INF file)

    An INF file contains information that the system Setup components use to install support for the device. Setup copies this file to the %windir%\inf directory when it installs the device. Every device must have an INF file.

    For more information, see Supplying an INF File.

  • A driver catalog (.cat) file

    A driver catalog file contains digital signatures. All driver packages should be signed.

    To get a driver package digitally signed, you must submit the package to the Windows Hardware Quality Lab (WHQL) for testing and signing. WHQL returns the package with a catalog file. See Driver Signing for details.

  • One or more optional co-installers

    A co-installer is a Win32® DLL that assists in device installation NT-based operating systems. For example, an IHV might provide a co-installer to provide Finish Install wizard pages or to copy additional INF files. Co-installers are optional. See Supplying a Co-Installer for details.

    Co-installers are not supported on Windows 98 or Me.

Other Files

A driver package can also contain other files, such as a device installation application, a device icon, and so forth. For more information, see the following topics:

Supplying a Device Installation Application

Providing Device Property Pages

Installing a Boot Driver


Steps in Driver Development

This guide organizes driver development into six steps, listed below. Each step corresponds to a section in the DDK.

  • Step 1: Understand Driver and Operating System Basics

    Before starting design, you should understand the fundamentals of how drivers work in Windows operating systems. Knowing the fundamentals will help you make appropriate design decisions and streamline your development process.

  • Step 2: Determine Device-Specific Driver Requirements

    Each Windows device class has specific hardware and software requirements. Devices and drivers should conform to these requirements to operate correctly with other system components.

    Understanding and following these requirements during hardware and software design can save you time and money.

  • Step 3: Make Driver Design Decisions

    Before you write any code, you need to make some fundamental decisions about driver design. For example, you should decide which Windows operating systems and hardware platforms your driver will run on, and whether you can modify an existing sample or legacy driver or instead should start from scratch.

  • Step 4: Build, Test, and Debug the Driver

    Building a driver is not the same as building a user-mode application. This section gives tips on how to use the "free" and "checked" operating system builds and how to configure the build environment for a driver.

    Iterative testing and debugging on as many hardware configurations as possible helps to ensure a working driver.

  • Step 5: Provide an Installation Package

    Exactly how a driver must be installed depends on the type of driver and device. This section helps you determine which device installation components you must provide and outlines what Windows expects during device installation.

  • Step 6: Distribute the Driver

    The final step in driver development is to distribute the driver. If your driver meets the quality standards defined for the Microsoft Windows Logo program, you can distribute it through Microsoft's Windows Update program.


Additional Resources for Driver Writers

In addition to the Windows DDK, Microsoft provides several other resources for driver writers:

  • The DDK web site, www.microsoft.com/ddk
  • The hardware development web site, www.microsoft.com/hwdev
  • The hardware test web site, www.microsoft.com/hwtest
  • The Microsoft Developer Network (MSDN®) web site, at msdn.microsoft.com. The Platform SDK, which describes the Win32® API, is available from MSDN.
  • The IFS Kit web site, www.microsoft.com/ddk/ifskit
  • The Microsoft Hardware Newsletter, available under nondisclosure agreement to qualified vendors

Books on driver development and Windows internals are available from Microsoft Press and other publishers. Such books include the following:

  • Inside Windows 2000, Third Edition (previously titled Inside Windows NT), by David Solomon, published by Microsoft Press.
  • Programming the Microsoft Windows Driver Model, by Walter Oney, published by Microsoft Press.

Because driver structure and requirements changed significantly with the releases of Windows 98 and Windows 2000, which introduced the Windows Driver Model (WDM), make sure that any resource you consult has been updated for these releases.


Understanding Driver and Operating System Basics

This section provides fundamental information about the following for driver writers:

Overview of System Components for Driver Writers

User-Mode Drivers and Kernel-Mode Drivers

Layered Driver Architecture

Device Drivers and File System Drivers Defined

Windows Driver Model (WDM) Defined

Operating System Concepts for Driver Writers


Overview of System Components for Driver Writers

The following figure shows a broad overview of the system components that are relevant to drivers:

Windows Component Overview

As the preceding figure shows, the operating system includes kernel-mode components and user-mode components.

User-mode drivers and applications can use routines defined in the Win32® Application Programming Interface (API), which is described in the Platform SDK. The Win32 API, in turn, calls exported driver and operating system kernel routines.

Kernel-mode drivers can use support routines that are defined and exported by various components of the operating system kernel. These routines support I/O, configuration, Plug and Play, power management, memory management, and numerous other operating system features. The Overview of Windows Components describes these components in greater detail.

The NT-based operating system's kernel is designed to be portable and hardware-independent, and thus is layered on top of the hardware abstraction layer (HAL). The HAL provides hardware-dependent features. Windows 98/Me does not support this level of hardware independence.


User-Mode Drivers and Kernel-Mode Drivers

Windows® drivers can run in either user mode or kernel mode.

  • User-mode drivers run in the non-privileged processor mode in which other application code, including protected subsystem code, executes. User-mode drivers cannot gain access to system data except by calling the Win32® API which, in turn, calls system services.
  • Kernel-mode drivers run as part of the operating system's executive, the underlying operating system component that supports one or more protected subsystems.

User-mode and kernel-mode drivers have different structures, different entry points, and different system interfaces. Whether a device requires a user-mode or kernel-mode driver depends on the type of device and the support already provided for it in the operating system.

Some device drivers can run wholly or partially in user mode. User-mode drivers have unlimited stack space, access to the Win32 API, and easier debugging (with user-mode debuggers).

For example, printer drivers are divided into user interface and rendering components. The user interface component runs in user mode, and calls the Win32 API to render images. The Win32 API, in turn, calls the rendering component, which can run in either kernel mode or user mode.

Most device drivers run in kernel mode. Kernel-mode drivers can perform certain protected operations and can access system structures that user-mode drivers cannot access. The increased access comes at the price, however, of more difficult debugging and a greater chance of system corruption. When code runs in the privileged kernel-mode environment, the operating system, by design, performs fewer checks on data integrity and the validity of requests.

To determine which type of driver your device requires, see System-Supplied Drivers.


Device Drivers and File System Drivers Defined

A Windows® driver can support a device or a file system:

Device driver
A device driver provides I/O services for an underlying device. For example, all of the following are considered device drivers: the IEEE 1394 bus driver, a video class driver that manages streaming input data for a variety of video devices, a video miniclass driver that communicates with the class driver to support a specific video device, and a filter driver that filters the streaming data. Some device drivers — particularly those for audio, video, and print devices — run in user mode, but most run in kernel mode.
File system driver
A file system driver handles I/O independent of any underlying physical device. File system drivers include drivers for the system-supplied NTFS and file allocation table (FAT) file systems. On the NT-based operating system, file system drivers are kernel-mode drivers. File system filter drivers provide additional capabilities above a standard file system driver, typically by implementing such value-added services as virus screening.

Although the support is not visible to the writer of a file system driver, every file system driver ultimately depends on support from one or more underlying peripheral devices. File system drivers might also rely on support from one or more Plug and Play (PnP) hardware bus drivers.

This guide, as well as the bulk of the Windows DDK, applies to device drivers. If you are writing a file system driver or filter, see the Installable File Systems Kit (IFS Kit). You can order the IFS Kit through the Microsoft Web site at www.microsoft.com/ddk/ifskit.


Windows Driver Model (WDM) Defined

Any kernel-mode device driver that conforms to the Windows Driver Model (WDM) is considered a WDM driver. The Windows Driver Model defines a unified approach to writing kernel-mode device drivers for all Windows® operating systems.

Any device driver that will run on both Microsoft® Windows 98/Me and Windows 2000 and later operating systems must be a WDM driver. With a few special-case statements in the code, WDM drivers can be source-compatible across the Windows 98/Me and Windows 2000 and later operating systems. For more information, see Introduction to WDM.


Layered Driver Architecture

Windows® operating systems support a layered driver architecture. Every device is serviced by a chain of drivers, typically called a driver stack. Each driver in the stack isolates some hardware-dependent features from the drivers above it.

The following figure shows the types of drivers that could potentially be in a driver stack for a hypothetical device. In reality, few (if any) driver stacks contain all these types of drivers.

Layered Driver Architecture

As the preceding figure shows:

  1. Above the driver stack is an application. The application handles requests from users and other applications, and calls either the Win32® API or a routine that is exposed by the user-mode client driver.
  2. A user-mode client driver handles requests from applications or from the Win32 API. For requests that require kernel-mode services, the user-mode client driver calls the Win32 API, which calls the appropriate kernel-mode client or support routine to carry out the request. User-mode client drivers are usually implemented as dynamic-link libraries (DLL). Printers support many operations that can be performed in user mode, and so typically have user-mode clients; disks and other storage devices, networks, and input devices do not.
  3. A kernel-mode client driver handles requests similar to those handled by the user-mode client, except that these requests are carried out in kernel mode, rather than in user mode.
  4. A device class and miniclass driver pair provides the bulk of the device-specific support. The class driver supplies system-required but hardware-independent support for a particular class of device. Class drivers are typically supplied by Microsoft.

    A miniclass driver handles operations for a specific type of device of a particular class. For example, the battery class driver supports common operations for any battery, while a miniclass driver for a vendor's UPS device handles details unique to that particular device. Miniclass drivers are typically supplied by hardware vendors.

  5. A corresponding port driver (for some devices, this is a host controller or host adapter driver) supports required I/O operations on an underlying port, hub, or other physical device through which the device attaches. Whether any such drivers are present depends on the type of device and the bus to which it eventually connects.

    All driver stacks for storage devices have a port driver. For example, the SCSI port driver provides support for I/O over the SCSI bus.

    For USB devices, a hub and host controller driver pair perform the duties of the port driver. These drivers handle I/O between the devices on the USB bus and the bus itself.

    A corresponding miniport driver handles device-specific operations for the port driver. For most types of devices, the port driver is supplied with the operating system, and the miniport driver is supplied by the device vendor.

  6. At the bottom of the figure is the hardware bus driver. Microsoft supplies bus drivers for all the major buses as part of the operating system. You should not attempt to replace these drivers.

Network drivers have their own unique terminology, defined in Windows 2000 and Later Network Architecture and the OSI Model. Nevertheless, network drivers are similarly layered, and each layer isolates device-specific or protocol-specific functionality from the layer above it.

Exactly which drivers are present, and what they are called, depends on the type of device and the bus to which it connects.

Graphics cards, for example, require a display driver, a video port driver, and a video miniport driver. The display driver is analogous to the kernel-mode client driver in the previous figure. It provides general drawing capabilities and can often work with more than one graphics card. The video port driver supports device-independent graphics operations. It works in tandem with the video miniport driver, which provides functionality that is specific to one graphics card (or a family of graphics cards). The paired video port/miniport drivers are analogous to the port/miniport drivers in the figure, and no class/miniclass drivers are present. For more information, see Display Architecture.

For simplicity, filter drivers are not shown in the previous figure. However, a filter driver can fit in at any layer of the driver stack above the hardware bus driver. A filter driver adds value to an existing driver by "filtering" — intercepting and manipulating device I/O. As a general rule, filter drivers do not operate the hardware directly, but work only on data and I/O requests passed to them from the next-higher or next-lower driver.

DirectShow®, the Microsoft software for video capture, includes system-supplied filter drivers that run in user mode. These filters act as clients of the kernel-mode stream class driver to expose the underlying video capture technology.


Operating System Concepts for Driver Writers

Familiarity with common operating system structures and concepts is critical to writing robust drivers that can be readily debugged, maintained, and ported.

If your device requires a user-mode driver, refer to the device-specific documentation in the Windows® DDK, and see the Platform SDK documentation for details on the Win32® API and services.

The Kernel-Mode Driver Architecture node in the Windows DDK provides comprehensive material on the operating system features available to kernel-mode drivers, and how to use them. If you have not previously written a driver, or have written drivers only for Windows® 95 and other single-processor operating systems, you should pay particular attention to the following topics:

Multiprocessor-Safe

Packet-Driven I/O with Reusable IRPs

Supporting Asynchronous I/O

Managing Hardware Priorities

For a list of information sources outside the Windows DDK, see Additional resources for driver writers.


Determining Device-Specific Driver Requirements

Before beginning to design or code a Windows driver, you must determine what kind of driver your device requires. In some cases, you might conclude that you do not need to write a driver after all. This section provides information on the following:

Overview of Device Classes

System-Supplied Drivers


Overview of Device Classes

Windows defines two types of device classes:

  • A device setup class is a group of devices that are set up and configured in the same way.
  • A device interface class describes a set of device features, regardless of the bus to which the device is connected.

Understanding the distinction between these two classes, and how your device is characterized within each class, is an essential early step in driver design. For more information, see Setup Classes versus Interface Classes.


System-Supplied Drivers

Drivers for most standard types of devices ship with the operating system. These drivers include bus drivers for the most common buses, port and host controller drivers, class drivers, and file system drivers.

In addition, the Windows DDK provides sample drivers and documentation for a wide variety of devices, and documents interfaces for common buses so that, if necessary, you can write a driver for a device of a new type.

To determine what type of driver your device requires, and whether such a driver is already present, consult the technology-specific information contained in this DDK documentation. Use the DDK viewer's table of contents, index, and search capability to locate information about driver support for your device type. If your device is a multifunction device, you should also see Supporting Multifunction Devices.

If a class driver is available for your device type, you probably do not need to write a complete driver, but instead only a minidriver that provides device-specific support and works with the class driver.

The system-supplied class drivers are designed to hide bus-specific requirements from minidrivers. For example, the mouse class driver mouclass.sys interfaces with the HID class driver for USB mice, and with the I8042 port driver for PS/2 mice. As a result, supporting a new type of mouse on either of these buses is fairly straightforward. Similarly, the storage class drivers work with the storage port driver, isolating bus-related details from device-specific storage miniport drivers.

If a class driver is not available for your device type, or if the available class drivers do not support the bus or port to which your device attaches, your device probably requires a new driver. The driver should include both the "top-end" device-specific functionality and the "bottom-end" functionality to communicate with the next-lower driver (usually a bus or port driver). For suggestions on how to streamline the development process, see Driver Design and Implementation Strategies.

Do not attempt to replace the system-supplied bus drivers.


Making Driver Design Decisions

After determining what kind of driver your device requires, you can begin designing your driver. Among the design issues to consider are the following:

Choosing a Programming Language

Driver Design and Implementation Strategies

Using the DDK Samples

Upgrading a Legacy Driver

Writing Drivers for Multiple Platforms and Operating Systems

Planning for 64 Bits

Providing Driver Localization


Choosing a Programming Language

For maximum portability, drivers should be written in a high-level language, typically C for kernel-mode drivers, and C or C++ for user-mode drivers. The following are exceptions:

  • Audio/Video streaming (AVStream) client minidrivers (Microsoft® DirectX® 8.0, Microsoft® Windows® XP and later versions of the operating system) are typically written in C++.
  • WDM audio miniport drivers use kernel-mode COM components and are typically written in C++.
  • Windows Image Acquisition (WIA) drivers, most of which run in user mode, are typically written in C++.
  • Display drivers are typically written in C. However, the system-supplied Graphics Display Interface (GDI) defines the public portions of its internal data structures as user objects. GDI also defines numerous service routines to manipulate these objects. Display drivers written in C++ can treat these routines as methods on the user object; drivers written in C can call these routines in the usual manner.

Most DDK sample and system-supplied drivers are written in C. In general, driver code should conform to the ANSI C standard, and should avoid depending on anything that the standard describes as "implementation defined." However, driver writers should take advantage of implementation-defined structured exception handling, if possible.

In particular, to write portable drivers, it is best to avoid the following:

  • Dependencies on data types that can vary in size or layout from one platform to another
  • Calling any standard C run-time library function that maintains state
  • Calling any standard C run-time library function for which the operating system provides an alternative support routine

To ensure compatibility across hardware platforms, drivers should not contain assembly language code.


Driver Design and Implementation Strategies

Support for a new device typically requires a device-specific driver or minidriver that interoperates with existing drivers above and below it in the driver stack.

You can add a driver to the driver stack or replace an existing driver. The location of a new (or replacement) driver in the driver stack depends partly on the hardware configuration of the individual machine, and partly on how much support the new driver can get from existing system drivers.

At minimum, a replacement driver must implement the same set of features as the driver it replaces.


Structured Exception Handling

Whether you're writing a user-mode or kernel-mode driver, you should implement structured exception handlers to improve the reliability of your code. The Visual C++® compiler provides the try/except mechanism, which can be used by any driver. See the Visual C++ documentation for details.

Both the Win32® API and the operating system include additional support routines for structured exception handling. For information on support routines in the Win32 API (user mode only), see the Platform SDK.

The following operating system routines (kernel mode only) support structured exception handling:

ExRaiseStatus

ExRaiseAccessViolation

ExRaiseDatatypeMisalignment


Using the DDK Samples

The Windows® DDK includes sample source code for a variety of drivers. The samples can be useful blueprints for writing your own drivers. Samples are installed in the \src directory.

Each sample is distributed with a Readme file. The Readme file notes what the sample does, which operating systems it has been tested on, and how to build it. The Readme also lists the files that make up each sample.

The following table lists some of the sample directories and their contents. For more information about DDK samples, see the device type-specific documentation in this DDK.

Sample Directory | Contents
Audio | Microsoft® DirectMusic® and Audio Compression Manager (ACM) filters.
General | Sample programs to install and remove drivers; other generic driver samples.
IME | Input Method Editor (IME) DLLs and samples.
Input | Keyboard and mouse class filter drivers.
Kernel-Mode | Drivers for parallel and serial devices and specific chipsets.
Networks | Samples for various types of network drivers.
Print | DLLs, user interface tools, and sample skeleton drivers for printers and plotters.
SmartCard | Drivers for serial and PCMCIA Smartcard readers.
Storage | Storage drivers and installation applications.
VDD | Virtual device drivers for DOS compatibility.
Video | Display drivers and a mirroring driver.
WDM | WDM-compatible drivers for a variety of devices. All support Plug and Play and are source-compatible across Windows 2000 and later versions of the operating system, and Windows 98/Me. Also includes a WMI filter for any WDM driver.

If you choose to base your code on one or more of the samples, keep in mind the following:

  • Some samples are not complete drivers, but instead provide guidelines for how such drivers could be written. For instance, samples might omit error-handling code in the interest of brevity and clarity.
  • Make sure to use a driver sample written for the type of driver that you are writing. For example, if you are writing a WDM function driver, use a sample WDM function driver. If you are writing a storage filter driver, use a sample storage filter driver.
  • Be sure to update the sample INF file for your driver. In particular, make sure that the device ID of your hardware matches the device ID specified in the INF file.


Upgrading a Legacy Driver

Although Microsoft® Windows® 2000 and later versions of the operating system continue to support some legacy drivers written for Windows NT®, new drivers should be WDM drivers. The system-supplied device drivers have been modified to support WDM, which includes Plug and Play and power management.

Drivers that support WDM, or at least Plug and Play, differ in structure from legacy drivers. For example, while legacy drivers create named device objects and symbolic links in a DriverEntry routine, WDM and Plug and Play function drivers create unnamed device objects in an AddDevice routine, and register and enable a device interface using I/O Manager routines and device installation functions. In addition, WDM and Plug and Play drivers have different requirements for resource allocation, registry usage, and device enumeration, among others.

Because of these considerable differences, in most cases it is more efficient to start with a sample WDM driver for your device type and replace device-specific routines than to revise an existing legacy driver. For examples, see the Toaster sample in \src\general and the device-type-specific sample WDM drivers in \src\wdm.

However, if you choose to try to upgrade a driver, your driver will require the following types of changes:

  • Conforming to changes to the registry for devices and drivers

    These changes, made to support Plug and Play and WDM drivers, make the layout of the registry similar to that of the Windows® 95 registry tree for devices and their drivers. In fact, the boot code used in Windows 2000 and later versions of the operating system transfers all registry information from the legacy HARDWARE\....\CurrentControlSet... registry tree into a Windows 95-style "devnode" registry tree at installation. For more information, see Driver Information in the Registry.

  • Updating or replacing the driver's installation script (an INF file)

    INF files for Windows 2000 and later versions of the operating system and for Windows 98/Me combine features from Windows NT 4.0 INF files and Windows 95 INF files to support Plug and Play and WDM drivers. For more information, see Creating an INF File.

  • Supporting Plug and Play

    Windows operating systems include a set of Plug and Play/WDM hardware bus drivers for nearly every type of common I/O bus found in PCs. Drivers of devices connected on such an I/O bus should support Plug and Play.

    For some types of drivers, support for Plug and Play is provided by the operating system components that export the interfaces used by those drivers. For example, Plug and Play support is built into the system-supplied network and video port drivers. To upgrade a legacy network or display driver, ensure that it uses the system-supplied Plug and Play support.

  • Supporting power management

    Because power management and Plug and Play technologies are interdependent, every legacy driver that is upgraded to support Plug and Play must also be upgraded to support power management.

  • Turning a legacy driver into a WDM driver, if possible

    WDM drivers must include the master DDK header file wdm.h instead of ntddk.h, so a WDM driver can call only the exported support routines and use only the types, macros, and constants defined in wdm.h.

    Some types of legacy drivers, particularly drivers of devices connected on newer, dynamically configurable PC I/O buses, can be modified to become WDM drivers.

Additional device-type specific changes might also be required. For details about specific devices, see the Design Guide for your device type.


Writing Drivers for Multiple Platforms and Operating Systems

This topic provides information useful for designing drivers to run on multiple Windows hardware platforms and operating systems. See also Planning for 64 Bits and Building Multiple Targets from One Subdirectory.

WDM Multiplatform Issues

Although Windows 2000 and later versions of the NT-based operating system, along with Windows 98/Me, all support the Windows Driver Model, the model's features have changed slightly as later operating systems have been released. Before writing a WDM driver, be sure to see WDM Versions.

For cross-system compatibility, thoroughly test drivers on all target operating systems. Operating system differences can produce slightly different driver behavior. Differences are most apparent between single processor and multiprocessor platforms.

Differences in DirectX Versions

DirectX, particularly the DirectDraw DDI, includes a number of features that operate differently on Windows 98/Me and Windows 2000 and later. For more information, see the DirectDraw DDI.

Differences Related to Physical Address Extension (PAE)

Windows 2000 and later Advanced Server and Datacenter support Physical Address Extension (PAE), which supports up to 8 gigabytes (for Advanced Server) or 32 gigabytes (for Datacenter) of physical RAM.

Special hardware compatibility (HCL) and test requirements apply to devices supported on these systems. Drivers for such devices should comply with the guidelines listed in Physical Address Extension (PAE) and in Large Memory Enabled Device Driver Hardware and Software Requirements. Note the special guidelines for NDIS and SCSI miniport drivers, also described in Physical Address Extension (PAE).

Differences in INFs

A driver can use a single INF file for installation on both Windows 2000 and later versions of the operating system and on Windows 98/Me systems, provided that any operating system-specific details are listed in the appropriate INF DDInstall section. For more information, see Creating INF Files for Multiple Platforms and Operating Systems.

Windows XP and later systems also provide a way for an INF file to distinguish installations on different versions of the NT-based operating system. For more information, see the INF Manufacturer section.


Planning for 64 Bits

Whether you are writing a new driver or modifying an existing driver, you should consider making it compatible with 64-bit Windows. The Windows DDK includes a partial 64-bit build environment you can use to evaluate your driver source code for the upcoming 64-bit version of the Windows operating system. For details, see 64-Bit Issues.

Many of the driver samples included with the DDK are designed for 64-bit compatibility, as noted in the Readme files for the individual samples.


Providing Driver Localization

If your device/driver package will be distributed in the international marketplace, you should plan for localization of the package. The following are simple steps towards localization:

  • Use UNICODE strings throughout the driver.
  • Isolate text to a resource file or header file.
  • Make an international INF file for device installation.
  • Make sure that any user interfaces, such as device property pages, display correctly when translated into another language.

Several of the system-supplied class and port drivers, along with the WMI service, include "hooks" for locale-specific information. Check the documentation for your device type for details.


Building, Debugging, and Testing a Driver

This section provides basic information and guidance on building, debugging and testing drivers. It covers the following topics:

Overview of Build, Debug, and Test Process

Using Free and Checked System Builds

Building a Driver

Debugging a Driver

Testing a Driver


Overview of Build, Debug, and Test Process

Building, testing, and debugging a driver is an iterative process that involves the following steps:

  1. Writing the driver code, which should include debugging routines and macros that are flagged for conditional compilation
  2. Building a checked version of the driver
  3. Testing and debugging a checked version of the driver on a checked build of each target operating system
  4. Testing and debugging the free version of the driver on a free build
  5. Tuning the performance of the driver on the free build
  6. Final testing and verification using the free build


Using Free and Checked System Builds

To test and debug a driver, you should use both the free build and the checked build of the target operating system.

  • The free build is the same as the build of the operating system that is sold to customers, and is thus sometimes referred to as the retail build. The system and drivers are built with full optimization, and debugging asserts are disabled.
  • The checked build serves as a testing and debugging aid for both the operating system and for kernel-mode drivers. The checked build contains extra error checking, argument verification, and debugging information that is not available in the free build. You can isolate and track down driver problems much more quickly than on a free build. A checked build of the system and drivers is larger and slower, and uses more memory, than the free build.

For full details on how these builds differ and how they can be used, see The Checked Build of Windows.

In the early stages of driver development you should use the checked build to debug the driver. The additional debugging code in the checked build protects against many driver errors, such as recursive spin locks.

Performance tuning, final testing, and verification of the driver should be done on the free build. The faster speed of the free build makes it possible to detect race conditions and other synchronization problems.

Note The free and checked Windows builds are not related to the free and checked build environments. For information about the build environment windows, see Setting Up the Build Environment.


Building a Driver

The Windows DDK includes an environment for building drivers that closely matches the build environment used internally at Microsoft®. This environment includes various tools useful in developing drivers, including build utilities (build.exe and nmake.exe), a C compiler (cl.exe), and a linker (link.exe). The Build utility automatically invokes nmake, the compiler, and the linker according to the command-line options you specify.

For a description of how to use the Build utility, see Overview of the Build Utility.


Debugging a Driver

The Microsoft® Windows® DDK includes the Debugging Tools for Windows package. This package contains extremely powerful user-mode and kernel-mode debuggers that can debug applications, drivers, and services running on any NT-based operating system. See Debugging Tools for NT-Based Operating Systems for more information on these tools.

For debugging on Windows 98/Me, you should use the Windows System Debugger (debugger.exe, wdeb386.exe, wdeb98.exe). Several other tools, such as the AMLI Debugger, are also available for use on Windows 98/Me. See Windows ME Debugger and Other Tools for more information on these tools.

In addition, the Microsoft Visual Studio® debugger can be used to debug user-mode programs on all Windows operating systems. See the Visual Studio documentation for details on this debugger.

Debugging-Related Routines

There are a number of user-mode and kernel-mode routines that allow your driver to interact with a debugger. See Overview of Debugging Routines for details.


Testing a Driver

This section covers the following topics:

"Designed for Windows" Logo Testing

Tips for Testing Drivers


"Designed for Windows" Logo Testing

Microsoft's Windows Hardware Quality Labs (WHQL) tests drivers for compliance with requirements of the Windows Logo Program for hardware. Through this program, device manufacturers can license the Windows Logo for use on product packaging, advertising, and other marketing materials for all systems and components that pass compliance testing.

Hardware and drivers must pass WHQL testing to receive a "Designed for Windows" logo, to receive a digital signature, to be included on the Hardware Compatibility List (HCL), and to be distributed as part of the Windows Update program. See Driver Signing for additional details.

WHQL requirements vary depending on the type of device. However, if the device class is supported under the Windows Driver Model (WDM), the driver must use WDM.

For most device classes, WHQL provides a test kit that you can download. Details vary by device class; see the Microsoft Windows Hardware Quality Labs web site at www.microsoft.com/hwtest for current information, kits, and download instructions.

See also the Windows Driver and Hardware Development web site at www.microsoft.com/hwdev for additional information on device and driver testing.


Tips for Testing Drivers

The following are some suggestions for testing your driver package:

  • Create the INF file early in the development process and use it throughout testing. If necessary, use GenINF to create a skeleton INF.
  • Use the ChkINF tool to verify the structure and syntax of the INF file, and to assist in diagnosing INF and other installation related issues.
  • Use Driver Verifier.
  • Run the Hardware Compatibility Tests (HCT) and the WHQL test kit for your device type, even if you do not intend to submit your device and driver for the "Designed for Windows" Logo program. See the Microsoft Windows Hardware Quality Labs web site at www.microsoft.com/hwtest for current information, test kits, and download instructions.
  • Test your driver and device on as many different hardware configurations as you possibly can. Varying the hardware can help you find conflicts between devices and other errors in device interactions.
  • Test your driver and device on multiprocessor systems. Race conditions and other timing problems appear on multiprocessor systems that would not otherwise be found.
  • Test your driver and device for specific system and hardware conditions, particularly edge conditions. For example, these might include "D3 hot" and "D3 cold." Make sure your driver and device can return correctly from device power state D3 "hot" (without losing power) and D3 "cold" (when power is removed from the device).

Microsoft's Hardware Test group regularly sponsors testing events ("plugfests") that are open to industry participants. System OEMs and independent hardware vendors (IHVs) who attend these plugfests can test their products with a variety of configurations. For details on upcoming plugfests, see the Hardware Test web site at www.microsoft.com/hwtest.

Special Interest Groups (SIGs) in the hardware industry may sponsor similar events for those working with devices of specific types. See www.microsoft.com/hwdev for links to device-class-specific SIGs.


Providing an Installation Package

Installing a device or driver involves system- and vendor-supplied components. The system provides generic installation software for all device classes. Vendors must supply one or more device-specific components.

This section provides information to help you determine which components to supply, along with some guidelines for installation design. It covers the following topics:

Installation Component Overview

Supplying an INF File

Supplying a Co-Installer

Supplying a Device Installation Application

Guidelines for Device and Driver Installation


Installation Component Overview

Installing a device or driver is substantially different from installing an application. When installing an application, a user might start the Add/Remove Programs Wizard whereas, when installing a device, he or she might start the Add Hardware Wizard. (Alternatively, the user might insert a distribution disk into a CD-ROM drive, causing an Autorun-invoked setup application to start the installation.) Installation of applications relies on the Windows Installer and corresponding Msi functions (described in the Platform SDK). Installation of devices and drivers relies on the system's Setup component and corresponding general Setup functions, device installation functions, and PnP Configuration Manager functions.

The Device Installation Overview provides details on how the Microsoft® Windows® operating system finds and installs devices and drivers, and on the components involved in such an installation.

To install a device or a driver, the operating system requires the following information at a minimum:

  • The name and version number of each operating system on which the device or drivers are supported
  • The device's setup class GUID and setup class
  • Driver version information
  • The names of the driver files along with their source and destination locations
  • Device-specific information, including hardware ID and compatible IDs
  • The name of a catalog (.cat) file
  • Information on how and when to load the services provided by each driver (Windows 2000 and later systems)

All this information can be supplied in an INF file for the device. For most device and driver combinations, an INF file is the only installation component required. All devices and drivers require an INF file. For more information, see Supplying an INF File.

In addition to the system requirements, drivers often have their own requirements. For example, some drivers use the registry to share information with other components. Through a driver's INF file, you can add, change, or delete information from the registry. The INF file cannot, however, read directly from the registry.

If installation depends on reading from the registry, requesting input from the user, or acquiring any other dynamic information, you will need to supply an additional component, typically a co-installer. A co-installer is a DLL that handles device installation function codes sent by the system Setup component. For more information, see Supplying a Co-installer.

If the installation package includes vendor-supplied applications associated with the device, you'll probably also provide a device installation application. For more information, see Supplying a Device Installation Application.

The following table lists the installation components that a device/driver combination might require.

Component | When required
INF file | Required for all devices and drivers.
Device co-installer | Required if installation requires information from the user or from the registry. Often supplied by vendors.
Class co-installer | Required only if installation of all devices of this class requires information from the user or from the registry. System-supplied for classes that require them; vendors should rarely supply them.
Class installer | Required only for new device setup classes; system-supplied for existing classes. As a rule, vendors should not define new setup classes, and thus should not supply class installers.
Device installation application | Recommended when value-added software is provided with device and driver, or when driver replaces a previous driver that might already be installed

If your device is involved in booting the system, installation requirements differ. See Installing a Boot Driver.


Supplying an INF File

Every driver package must include an INF file, which the system Setup component reads when installing the device. An INF file is not an installation script; it is an ASCII or Unicode text file that provides device and driver information, including the driver files, registry entries, device IDs, catalog files, and version information required to install the device or driver. The INF is used not only when the device or driver is first installed, but also when the user requests a driver update through the Device Manager.

The exact contents and format of the INF file depend on the device setup class. The Summary of INF Sections describes the information required in each type of INF. In general, per-manufacturer information resides in an INF Models section; entries in the Models section refer to INF DDInstall sections that contain model-specific details.

The GenINF tool, provided in the \tools directory of the DDK, creates a skeleton ASCII INF file (Windows 2000 or later) for a device of any standard setup class. You must edit the resulting file to supply device-specific information, and to support additional operating systems or hardware platforms.

The ChkINF tool, in the same directory, checks the syntax and structure of all cross-class INF sections and directives, along with the class-specific extensions for all setup classes except for Printers.

You can use a single INF file for installation on all Windows 2000 and later operating systems and on Windows 98/Me. For more information, see Creating INF Files for Multiple Platforms and Operating Systems. If your device will be sold in the international market, you should create an international INF file. Depending on the localities involved, an international INF file might have to be a Unicode file rather than ASCII.

For more information, see Creating an INF File, the documentation for GenINF and ChkINF, the device-specific documentation in the DDK, and the INF files supplied with sample drivers for devices similar to yours.


Supplying a Co-Installer

A co-installer is a user-mode Win32 DLL. Typically, a co-installer performs installation tasks that require dynamic information that is not available when the INF for its device or device class is written. For example, a co-installer is typically used when the user must supply information for device-specific settings through a property page.

A co-installer can perform installation operations for one particular device or for all the devices in a setup class.

  • A device co-installer handles custom installation requirements for a specific device or family of devices. For example, a hypothetical xyzcam.dll device co-installer could support all the still-image cameras shipped by the Xyz Company.
  • A class co-installer performs identical actions for every device in its class. For example, a hypothetical image.dll co-installer could support all the possible devices of the imaging class, such as still-image capture devices, digital cameras (including that of the Xyz Company), and scanners.

Microsoft supplies class co-installers for classes that require them; third parties seldom do. Do not supply a class co-installer with your device unless you can guarantee that every device in its setup class requires the actions of your class co-installer.

On the other hand, vendors often supply device co-installers. You should write a device co-installer if you need to display property pages or custom Finish pages during device or driver installation.

For more information, see Writing a Co-Installer and Providing Device Property Pages.

If your co-installer displays a custom Finish page or other user interface elements, make sure that those elements conform to the user interface guidelines described in the MSDN® Library and the Wizard 97 section of the Platform SDK.


Supplying a Device Installation Application

A device installation application can handle a variety of installation tasks, from setting up the hardware to installing device-specific application software.

Consider writing a device installation application if either of the following apply:

  • You supply value-added software that should be installed at the same time as the driver.
  • The driver shipped with your device replaces a similar driver that ships with the operating system. For example, a generic driver for your device ships with the operating system, but you supply a driver with additional features designed specifically for your device.

Any device installation application should be able to handle the following scenarios:

  1. The user installs the software package before installing the hardware.
  2. The user installs the hardware before installing the software package.

For more information, see Writing a Device Installation Application.

A device installation application should conform to the user interface guidelines described in the MSDN Library and in the Wizard 97 section of the Platform SDK.


Guidelines for Device and Driver Installation

The fundamental goal for device/driver installation on Windows® operating systems is to make the process as simple as possible for the user. Your installation procedures should work seamlessly with the operating system's setup components. Ideally, device installation should not require any user prompts, except for the system's request to insert the distribution medium.

Some devices, however, require user settings that are input to property pages or custom Finish pages. Such pages can be displayed by a device co-installer after the driver has been loaded and started. Other devices ship with value-added software that is most readily installed at the same time as the device itself, by means of a device installation application.

In either case, any user interface presented as part of installation should conform to the look and feel of the Windows user interface in general and, more specifically, the Device Manager and the device installation wizards. (The wizard names vary from one operating system release to the next, but include Found New Hardware, Add/Remove Hardware, Hardware Update, and so on).

To provide the best possible user experience, follow these rules in designing and implementing your installation procedures:

  • Do not reboot the system or require the user to do so.
  • Leave your INF files on the system after installation; do not delete them. The INF file is used not only when the device or driver is first installed, but also when the user requests a driver update through the Device Manager.
  • Use system-supplied interfaces (including user interface items) whenever possible.
  • Conform to the Windows user interface design specifications described in the MSDN® Library, available at msdn.microsoft.com.
  • Although you cannot use the Windows Installer to install a device or driver, you should use it to install value-added software that ships along with your driver package. The Windows Installer is described in the Platform SDK.
  • Use one of the system-defined device setup classes. Do not define your own setup class unless there is a compelling reason to do so.


Distributing a Driver

A driver package can be distributed through the Windows® Update program if it has passed WHQL testing, received a digital signature, and qualified for the Windows® Logo program. This section includes basic information on the following to help guide you through the process:

Driver Signing

Protection for System Files

Windows Update

Program requirements are frequently updated, so be sure to check the web sites referenced in the text for the latest information.


Driver Signing

Driver packages that pass WHQL testing can be digitally signed by Microsoft. Driver packages must be digitally signed if they are to be distributed through the Windows Update program or any other Microsoft-supported distribution mechanism.

You can apply for a digital signature through the WHQL web site at www.microsoft.com/hwtest. The digital signature does not change the driver binaries or the INF file submitted for testing.

To receive a digital signature, a driver package must meet the following criteria:

  • A WHQL test program must be available for the driver, and the driver must have passed the test. For more information, see "Designed for Windows" Logo Testing.
  • The driver must be installed by an INF file.
  • The INF file must not contain errors that can be identified by the ChkINF or INFCatReady (InfCatR.exe) programs.
  • The driver package must not include replacements for, or duplicates of, any Microsoft-supplied system files.

After your driver package has been signed, you should test it in every supported installation path on every target operating system to make sure that it installs without any errors or warnings.

See the following for additional information about digital signing:

The Catalog File

Enforcement of Digital Signatures


The Catalog File

A digital signature consists of a digitally signed catalog (.cat) file provided by Microsoft. The .cat file contains a record of every file that the driver package copies to the system.

The .cat file is a collection of tags, each of which corresponds to a file installed by the driver package. On Windows® 2000 and later, and on Windows Millennium Edition (Me), each tag is a cryptographic checksum value. On Windows 98, each tag is a text filename. Regardless of the intended operating system, WHQL uses cryptographic technology to digitally sign the catalog file.

The CatalogFile entry in the INF Version section of the driver's INF file specifies the name of the catalog file. At testing time, WHQL reads this entry and generates a catalog file with the specified name.

At driver installation, the system uses the CatalogFile entry to identify and validate the catalog. The system copies the catalog file to the %System%\CatRoot directory, and copies the INF to the %System%\Inf directory.

Changing or replacing any of the files in the driver package, including the INF file or the catalog file itself, breaks the digital signature. Even a single-byte change, for example, to correct a misspelling, will break the signature, and you will have to resubmit the package to WHQL for a new signature.

Similarly, changes to the device hardware or firmware require a revised device ID value, so that the system can detect the updated device and install the correct driver. Because the revised device ID value must appear in the INF, such a driver package must be resubmitted to WHQL even if the binaries do not change.

For more information, see Enforcement of Digital Signatures.

As a general rule, there should be one catalog file for each INF in a driver package. If the driver package installs the same binaries on both Windows 98/Me and Windows 2000 and later platforms, the INF can contain a single, undecorated CatalogFile directive. However, if the package installs different binaries, the INF should contain decorated CatalogFile directives. See the INF Version Section for details.

If you have more than one driver package, you should create a separate catalog file for each such package, and give each catalog file a unique name. Two unrelated driver packages cannot share a single catalog file. A single driver package that serves multiple devices needs only one catalog file.

Signed catalog files are valid for 20 years.


Enforcement of Digital Signatures

Windows checks the digital signature any time the driver's INF is used to install the driver; that is, when any of the following occurs:

  • A plug and play event occurs for any of the driver's devices.
  • The Add Hardware Wizard runs.
  • The user selects Update Driver.
  • An application calls the UpdateDriverForPlugAndPlayDevices function.
  • An application calls the SetupCopyOEMInf function. This function is documented in the Windows SDK.

At driver installation, Windows inspects the INF to determine the name of the catalog file, then finds the catalog file and verifies the digital signature. For each file installed as part of the driver package, the system verifies its checksum against the checksum listed in the catalog file.

If the driver signature is incorrect or if any file's checksum differs from the one in the catalog file, Windows takes one of the following actions, depending on the Driver Signing Options set by the administrator of the local machine:

  • Warns the user
  • Blocks installation
  • Ignores the error and installs the driver anyway

Windows 2000 and Later Behavior

By default, Windows 2000 and later systems warn the user for most device setup classes.

Windows 2000 trusts the DriverVer entry (which specifies the date of the driver package) in the INF only if the driver package is signed.

Windows Me Behavior

For the following device setup classes, Windows Me blocks installation of unsigned drivers if a signed driver already exists on the system:

  • Media, including WDM and VxD audio, joysticks, and certain other multimedia devices
  • Display

At installation, Windows Me checks both the device setup class in the INF and the device ID of the device. If a signed driver from the correct device setup class matches the device ID, Windows Me uses the driver package with the closest match, and then checks to ensure that the package has been signed. (See How Setup Selects Drivers for more information on device IDs, compatible IDs, and driver matching.) If Windows Me cannot find a driver package that matches the device ID, it uses the INF that most closely fits.

During an upgrade, Windows Me does not replace a working driver for the Display or Media classes, unless known problems exist in that driver.

Windows Me always trusts the DriverVer entry in the INF.


Protection for System Files

Windows File Protection (Windows 2000 and later) and System File Protection (Windows Me) protect Windows operating system files from being replaced with unknown or incompatible versions. System File Protection is not supported on Windows 98.

File protection is implemented slightly differently on Windows 2000 and later systems, and on Windows Me, as described in the next two sections.


Windows File Protection (Windows 2000 and later)

Windows File Protection (WFP) protects system files required for Windows 2000 and later operation. Protected system files include .sys, .exe, .ocx, and .dll files that ship "in the box" with the operating system.

During WHQL testing, the InfCatReady program checks a driver's INF to ensure that it does not attempt to replace system files. A driver package that attempts to replace system files cannot receive a digital signature. A driver package can, however, contain updated versions of files that the vendor supplied Microsoft to ship with Windows 2000 or later.

For additional information about Windows File Protection, see documentation in the Platform SDK.


System File Protection (Windows Me only

Previous Next

System File Protection (Windows Me only)

On Windows Me, System File Protection extends to all Microsoft system files. A list of protected files appears on the Windows Me CD in the windows\system\restore directory. Third-party and "in-box" drivers are not protected. System File Protection is not related to driver signing.

Only Microsoft-approved redistribution packages can update protected system files. Driver packages cannot replace protected files, even if the driver package has a digital signature.

If a driver or application tries to replace a protected file, the system automatically restores the original, protected version of the file.


Windows Update

The Microsoft® Windows® Update web site offers downloadable drivers for Windows 2000 and later, and Windows 98/Me.

Driver packages that pass WHQL testing and receive the Windows Logo can be considered for publication on Windows Update if they meet certain additional requirements.

These requirements ensure that Windows Update can determine the correct driver package for the user's device, legally distribute it, and automatically download it.

For more information about how to have your driver published on the Windows Update web site, see http://www.microsoft.com/hwdev/ntdrivers/winup.htm.


Introduction to Windows Drivers

This section provides an introduction to design concepts for Windows drivers. It contains the following sections:

Overview of Windows Components

Types of Windows Drivers

Design Goals for Kernel-Mode Drivers


Overview of Windows Components

The following figure shows the major internal components of the NT-based operating system.

NT Component Overview

The NT-based operating system includes some components that run in user mode and others that run in kernel mode. File system, intermediate, and lowest-level drivers are shown at the lower left, included with the kernel-mode I/O Manager.

As this figure shows, the operating system includes a number of kernel-mode components with well-defined functionality isolated in each component. Those of most interest to kernel-mode driver writers are the Kernel, I/O Manager, Plug and Play Manager, Power Manager, Hardware Abstraction Layer (HAL), Configuration Manager, Memory Manager, Executive Support, and Process Structure components. Additional components of interest to some driver writers include the Object Manager and Security Reference Monitor.


Types of Windows Drivers

There are two basic kinds of Windows drivers:

  • User-mode drivers (such as some printer driver components, along with Win32® VDDs for MS-DOS® applications and application-dedicated devices) or another protected subsystem's drivers.

    User-mode drivers are subsystem-specific. See Introduction to Printing for more information about printer driver components.

  • Kernel-mode drivers for logical, virtual, or physical devices.

    These drivers run as part of the Executive, which consists of kernel-mode operating system components that manage I/O, Plug and Play, memory, processes and threads, security, and so on.

    Some kernel-mode drivers are also WDM drivers, which conform to the Windows Driver Model (WDM). All WDM drivers are PnP drivers that support power management. WDM drivers are source-compatible (but not binary-compatible) across the Microsoft Windows® 98/Me and Windows 2000 and later operating systems.

Like the operating system itself, kernel-mode drivers are implemented as discrete, modular components with a well-defined set of required functionality. All supply a set of system-defined standard driver routines.

Types of Kernel-Mode Drivers

There are three basic types of kernel-mode drivers, as shown in the previous figure. Each type has a slightly different structure and quite different functionality:

  1. Highest level drivers, such as the system-supplied FAT, NTFS, and CDFS file system drivers (FSDs). Highest-level drivers always depend on support from underlying lower level drivers.

    While a particular file system driver might or might not get support from one or more intermediate drivers, every file system driver ultimately depends on support from one or more underlying peripheral device (and possibly PnP hardware bus) drivers.

  2. Intermediate drivers, such as a virtual disk, mirror, or device-type-specific class driver. Intermediate drivers also depend on support from underlying lower level drivers.

    PnP function drivers that control specific peripheral devices on an I/O bus controlled by a PnP hardware bus driver are intermediate drivers, as are PnP filter drivers that insert themselves above or below PnP function drivers in the driver stack for any particular peripheral device. A subset of PnP function and filter drivers are also WDM function and filter drivers.

    Any system-supplied class driver that exports a system-defined WDM class/miniclass interface is, in effect, an intermediate driver with one or more linked WDM miniclass drivers (sometimes called WDM minidrivers). Each linked WDM class/minidriver pair provides functionality equivalent to that of a WDM function driver or a WDM "software" bus driver.

    PnP software bus drivers that present a set of child devices to which still higher level class, function, and/or filter drivers can attach themselves are also intermediate drivers. For example, a driver that controls a multifunction adapter with an on-board set of heterogeneous devices is a PnP software bus driver. Depending on the nature of the on-board devices and the interfaces used by its driver, such a driver also might be a WDM software bus driver. It would appear to still higher level drivers to be a PnP/WDM bus driver. To the operating system, the driver would appear as a PnP/WDM function driver for its own adapter that inserted itself into the driver stack over an underlying PnP hardware bus driver.

  3. Lowest-level drivers, such as PnP hardware bus drivers that control an I/O bus on which some number of peripheral devices are connected. Lowest-level drivers do not depend on lower-level drivers, but control a physical peripheral device such as a bus.

    Legacy drivers that control a physical peripheral device directly are lowest-level drivers, as are drivers such as the SCSI HBA (host bus adapter) driver.

    PnP hardware bus drivers are system-supplied and usually control dynamically configurable I/O buses. The driver collaborates with the Plug and Play Manager to configure and reconfigure system hardware resources (such as mappings for device memory and IRQs) for all child devices connected to the I/O buses it controls. For its I/O buses, a PnP hardware bus driver subsumes some of the functionality that was provided exclusively by the HAL component in releases of the NT-based operating system prior to Windows 2000.

Network drivers also can be classified as one of the preceding basic types of drivers. For example, an NT-based server or redirector is a specialized file system driver; any driver in a transport stack is an intermediate driver; and a physical netcard (sometimes called a network interface controller or NIC) driver is a lowest-level device driver. The system provides specialized interfaces and support for network drivers, such as the NDIS (Network Device Interface Specification) library for drivers of NICs and for intermediate drivers at the lower edge of network transport stacks.

While the information in this section provides some useful overviews and background information for file system and network driver writers, it is primarily a design guide for writers of kernel-mode device and intermediate drivers, including WDM drivers. Writers of network intermediate and device drivers also should consult the Using the Network Driver Design Guide. File system driver writers should consult the IFS Kit.


Design Goals for Kernel-Mode Drivers

Kernel-mode drivers share many of the design goals of the operating system, in particular, those of the system's I/O Manager. These design goals include the following:

  • Portable from one platform to another
  • Configurable to various hardware and software platforms
  • Always preemptible and always interruptible
  • Multiprocessor-safe on multiprocessor platforms
  • Object-based
  • Packet-driven I/O with reusable I/O request packets (IRPs)
  • Supporting asynchronous I/O


Portable

The system provides two runtime libraries that contain functions beginning with the prefix Rtl. Kernel-mode drivers can use the same kernel-mode Rtl Xxx routines as the executive components, but cannot call user-mode Rtl Xxx routines.

Each NT executive component exports a set of kernel-mode support routines that drivers and all other kernel-mode components call. If the underlying implementation of a support routine changes over time, its callers remain portable because the interface to the defining component does not change.

Most operating system components are coded entirely in C, with only small pieces of the HAL and Kernel written in assembly language, so that the operating system is readily portable across hardware platforms. A kernel-mode driver should also be written in C so that it can be recompiled with a system-compatible C compiler, relinked, and run on different Windows platforms without recoding parts of the driver or replacing modules in the driver.

Drivers should not rely on the features of any particular system-compatible C compiler or C support library if the same features are not guaranteed to be supported by other system-compatible compilers. In general, driver code should conform to the ANSI C standard, and avoid depending on anything this standard describes as "implementation defined."

In particular, to write portable drivers, it is best to avoid the following:

  • Dependencies on data types that can vary in size or layout from one platform to another
  • Calling any standard C runtime library function that maintains state
  • Calling any standard C runtime library function for which the operating system provides an alternative support routine

The DDK supplies a set of include files defining system-specific data types and constants that drivers (and all other kernel-mode components) use to help maintain portability from one platform to another. Most drivers include one of the master DDK kernel-mode include files, ntddk.h or wdm.h. The master include files pull in not only system-supplied headers that define the basic kernel-mode types, but also appropriate selections from any processor-architecture-specific header(s) when a driver is compiled with the corresponding compiler directive.

For WDM drivers, the DDK supplies a set of include files that export a subset of the NT kernel-mode support routines, macros, constants, and types. WDM drivers use the master DDK include file wdm.h instead of ntddk.h. The inclusion of wdm.h and exclusive use of its exported support routines, macros, constants, and types allows a WDM driver to be recompiled to run on Windows 98/Me as well as Windows 2000 and later.

If a driver requires platform-dependent definitions, it's best to isolate those definitions within #ifdef statements, so that each driver can be compiled and linked for the appropriate hardware platform. However, you can almost always avoid implementing any platform-specific conditionally-compiled code in a driver simply by using the support routines, macros, constants, and types provided in the DDK master header files.

Some drivers, such as SCSI miniport drivers, NDIS drivers, and video miniport drivers, include other system-supplied header files to maintain portability across Windows platforms.


Configurable

Because Windows is a portable operating system, devices and their drivers must be both hardware-configurable and software-configurable.

For example, in a hot-plug RAID (Redundant Array of Inexpensive Disks) configuration, a user can swap disks while they are running. Such a device is hardware-configurable. Its driver cannot assume that a given disk device will be fixed at a particular location. Therefore, to remain portable, its driver must not contain hard-coded machine-dependent values.

The driver of this type of disk device might provide hardware-level support to one or more file systems in any given machine, depending on how the user partitions the disks. In addition, an intermediate driver might support fault tolerance (mirrored partitions, stripe sets, and/or volume sets) for higher level file system drivers in machines with sufficient mass storage capacity. In other words, the same physical disk driver could provide support to more than one type of higher level driver in some machines but not in others. Such a disk driver is software-configurable, as are all intermediate and file system drivers that ultimately depend on support from underlying device and/or Plug and Play (PnP) hardware bus drivers.

The HAL component, implemented as a dynamic-link library, is responsible for all hardware-level, platform-specific support needed by every other component in the system, including kernel-mode drivers. The HAL exports support routines that hide platform-specific hardware details about caches, I/O buses, interrupts, and so forth, to provide an interface between the platform's hardware and the system's software components, including all drivers.

The system-supplied PnP hardware bus drivers, in cooperation with the PnP Manager, provide similar functionality to the HAL component. That is, the PnP Manager and each PnP hardware bus driver collaborate to provide an interface between the platform's hardware for a specific type of I/O bus and the system's software.

The PnP Manager builds a device tree, with nodes representing all the devices on the system, including buses and the devices connected to them. For each device, the PnP Manager maintains two lists: a list of the hardware resources the device is capable of using and a list of the hardware resources actually assigned to the device. Device drivers assist the PnP Manager in creating these lists, which are maintained in the registry. As devices are added to and removed from the system, the PnP Manager reassigns resources as necessary and updates the lists.


Always Preemptible and Always Interruptible

The Kernel component determines when a particular sequence of code is run according to one of the following prioritizing criteria:

  • The Kernel-defined run-time priority scheme for threads

    Every thread in the system has an associated priority attribute. In general, most threads in the system have variable priority attributes: they are always preemptible and are scheduled to run round-robin with all other threads currently at the same priority level. Some threads in the system have real-time priority attributes: these time-critical threads are preemptible by any thread with a higher real-time priority attribute, but otherwise run until they relinquish control.

    Whatever its priority attribute, any thread in the system can be preempted when hardware and certain kinds of software interrupts occur.

  • The Kernel-defined interrupt request level (IRQL) to which a particular interrupt vector is assigned on a given platform

    The Kernel also prioritizes hardware and software interrupts so that some kernel-mode code runs at higher IRQLs, thereby making it, including most drivers, have a higher scheduling priority than all threads in the system.

    The particular IRQL at which a piece of kernel-mode code executes determines its hardware priority. Kernel-mode code is always interruptible: an interrupt with a higher IRQL value can occur at any time, thereby causing another piece of kernel-mode code with the system-assigned higher IRQL to be run immediately on that processor. In other words, when a piece of code runs at a given IRQL, the Kernel masks off all interrupt vectors with a lesser or equal IRQL value on the microprocessor.

In general, threads run at IRQL=PASSIVE_LEVEL no interrupt vectors are masked. Software interrupts are assigned relatively low IRQL values (APC_LEVEL, DISPATCH_LEVEL, or, for kernel debugging, WAKE_LEVEL). Device interrupts have higher IRQL values, and the Kernel reserves the highest IRQL values for system-critical interrupts such as the system clock or bus-error interrupts.

Some system support routines run at IRQL=PASSIVE_LEVEL both because some kernel-mode components set up their own threads and because some support routines are implemented as pageable code and/or access pageable data.

Similarly, certain standard driver routines usually run at IRQL = PASSIVE_LEVEL. However, several standard driver routines run either at IRQL=DISPATCH_LEVEL or, for a lowest-level driver, at device IRQL (also called DIRQL). See Managing Hardware Priorities for a detailed discussion of IRQLs.

In general, only a highest-level driver is called in the context of the thread that is requesting the driver's current I/O operation. An intermediate or lowest level driver can never assume that it is executing in the context of the thread that requested its current I/O operation.

For performance reasons (avoiding context switches), very few drivers set up their own threads. Consequently, driver routines usually execute in the context of whatever thread happens to be current when a standard driver routine is called to get some work done. That is, they execute in an arbitrary thread context.

While any kernel-mode routine that is run at higher than PASSIVE_LEVEL IRQL has a higher priority than all threads in the system, every routine in a driver is interruptible: any kernel-mode routine running at a particular IRQL retains control of the processor only if no interrupt with a higher Kernel-assigned IRQL occurs while that routine is running.

Even a lowest-level driver's interrupt service routine (ISR) can be interrupted by another routine (for example, by another driver's ISR) that runs at higher IRQL. Unlike the drivers in some older PC operating systems, a Windows driver's ISR is never the workhorse routine that does almost all of the driver's I/O processing because the driver's ISR does not necessarily retain control of the CPU it is currently running on until it returns.

Instead, a lowest-level driver must carry out most of its I/O operations at a lower IRQL than the DIRQL of its ISR. For good overall system performance, all kernel-mode routines that run at high IRQLs must relinquish control of the CPU quickly. Such routines do only what must be done at high IRQL and generally queue a deferred procedure call (DPC) to complete any operations that can be done at a lower IRQL (DISPATCH_LEVEL).

The goal of the interruptible, preemptible design of the operating system is to maximize average performance. Any driver's ISR can be interrupted in favor of a routine that runs at a higher IRQL, and any thread can be preempted by a thread with a higher priority. Although some threads have real-time priority attributes, even these threads can be preempted by a thread with a still-higher priority. Thus the Windows architecture does not provide an inherently real-time system.


Multiprocessor-Safe

In any Windows multiprocessor platform, the following conditions hold:

  • All CPUs are identical, and either all have identical coprocessors or none has a coprocessor.
  • All CPUs share memory and have uniform access to memory.
  • In a symmetric platform, every CPU can access memory, take an interrupt, and access I/O control registers. (By contrast, in an asymmetric multiprocessor machine, one CPU would take all interrupts for a set of slave CPUs.)

The NT-based operating system is designed to run uniformly on uniprocessor and symmetric multiprocessor platforms, and kernel-mode drivers should be designed to do likewise.

To run safely on a symmetric multiprocessor (SMP) platform, any operating system must solve this problem: how to guarantee that code executing on one processor does not simultaneously access and modify data that is being accessed and modified from another processor. For example, a lowest-level driver's ISR that is handling a device interrupt on one processor must have exclusive access to critical, driver-defined data (or the device registers) in case its device interrupts simultaneously on another processor.

Furthermore, drivers' I/O operations that are serialized in a uniprocessor machine can be overlapped in an SMP machine. That is, a driver's routine that processes incoming I/O requests can be executing on one processor while another routine that communicates with the device executes concurrently on another processor. Whether they are running on a uniprocessor or symmetric multiprocessor machine, this situation requires all kernel-mode drivers, including WDM drivers, to synchronize access to any driver-defined data or system-provided resources that are shared among driver routines and to synchronize access to the physical device, if any.

The NT Kernel component exports a mechanism, called a spin lock, that is used to protect shared data (or device registers) from simultaneous access by one or more routines running concurrently on a symmetric multiprocessor platform. The Kernel enforces two policies regarding the use of spin locks:

  • Only one routine can hold a particular spin lock at any given moment; only the holder of a spin lock can access the data it protects. Another routine must acquire the spin lock in order to access the same data, but the spin lock cannot be acquired until the current holder releases it.
  • Like a hardware or software interrupt vector, the Kernel assigns each spin lock in the system an associated IRQL value. A kernel-mode routine can acquire a particular spin lock only when the routine is run at the spin lock's assigned IRQL.

These policies prevent a driver routine that usually runs at a lower IRQL but is currently holding a spin lock from being preempted by a higher priority driver routine that is trying to acquire the same spin lock, thereby causing a deadlock.

The IRQL assigned to a spin lock is generally that of the highest-IRQL routine that can acquire the spin lock. For example, a lowest-level driver's ISR frequently shares a state area with the driver's DPC routine, which calls a driver-supplied critical-section routine to access the shared area. In this case, the spin lock protecting the shared area has an IRQL equal to the DIRQL at which the device interrupts. While the critical-section routine holds the spin lock and accesses the shared area at DIRQL, the ISR cannot be run in a uniprocessor machine because the device interrupt is masked off, as mentioned in Always Preemptible and Always Interruptible. And in a symmetric multiprocessor machine, the ISR still cannot acquire the spin lock protecting the shared data while the critical-section routine holds the spin lock and accesses the shared data at DIRQL.

A set of kernel-mode threads can synchronize access to shared data or resources by waiting on one of the Kernel's dispatcher objects: an event, mutex, semaphore, timer, or another thread. However, most drivers do not set up their own threads because they have better performance when they avoid thread-context switches. Time-critical kernel-mode support routines and drivers must use the Kernel's spin locks to synchronize access to shared data or resources whenever they run at IRQL = DISPATCH_LEVEL or at DIRQL.

For more information, see Spin Locks, Managing Hardware Priorities, and Kernel Dispatcher Objects.


Object-Based

The NT-based operating system is object-based. Various components in the executive define one or more object types. Each component exports kernel-mode-only support routines that manipulate instances of its object types when these routines are called. No component is allowed to access any instance of another component's object types directly. Each component must call the exported support routines in order to use another component's objects.

Strict adherence to these conventions allows the operating system to be both portable and flexible. For example, a future release of the operating system could contain a wholly or partially recoded Kernel component that defines the same object types, possibly with entirely different internal structures, and exports a set of support routines with the same names and parameters as the existing set. This hypothetical recoded version of the Kernel would have no effect on the portability of any other executive component in the existing system. In other words, operating system components do not practice back-door communication, and drivers also must shun this practice to remain portable and configurable.

Like the operating system, drivers and their devices are also object-based. To all other components in the system, including user-mode code, a connection to a device is represented as an open operation of one of the I/O Manager's file objects. Within the I/O system, each driver's logical, virtual, and/or physical devices are represented as device objects. Within the I/O Manager, each driver's load image is represented as a driver object. The I/O Manager defines the object types for file objects, device objects, and driver objects.

Like any other executive component, drivers use objects by calling kernel-mode support routines exported by the I/O Manager and other system components. Kernel-mode support routines generally have names that identify the specific object each manipulates and the operation each performs on that object. These support routine names have the form:

PrefixOperationObject

where

Prefix
Identifies the kernel-mode component that exports the support routine and, usually, the component that defined the object type. Most prefixes have two letters.

Operation
Describes what is done to the object.

Object
Identifies the type of object.

For example, IoCreateDevice, which each kernel-mode driver calls one or more times during device initialization, creates a device object to represent a physical, logical, or virtual device as the target of I/O requests.

For convenience, one system component can export routines that call another component's support routines. The I/O Manager, in particular, exports certain routines that make it easier to develop drivers. For example, IoConnectInterrupt, which lowest-level drivers call to register their ISRs, calls the Kernel's support routines for interrupt objects.

Object Opacity

Some system-defined objects are opaque: only the defining system component "knows" an object type's internal structure and can directly access all the data an object contains. The system component that defines an object usually exports support routines that drivers and other kernel-mode components can call to manipulate that object. For example, the system's Kernel component exports support routines that the I/O Manager calls to initialize and connect interrupt objects when a lowest-level driver registers its ISR.

Note To maintain driver portability, drivers must use the system-supplied support routines to manipulate system-defined objects. The defining system component can change the internal structure of its object types at any time.


Packet-Driven I/O with Reusable IRPs

The I/O Manager's chief job is to accept I/O requests (usually originating from user-mode applications), to create I/O request packets (IRP) to represent them, to route the IRPs to the appropriate drivers, to track them until they are completed, and to return status to the original requester of each I/O operation. The I/O Manager, Plug and Play Manager, and Power Manager use IRPs to communicate with kernel-mode drivers, including WDM drivers, and to allow drivers to communicate with each other.

An IRP might be routed to more than one driver. For example, a request to open a file on a disk might go first to a file system driver, through an intermediate mirror driver, and ultimately to a disk driver and, possibly, to a PnP hardware bus driver.

Therefore, each IRP has a fixed part and one or more driver-specific I/O stack locations:

  • In the fixed part (or header), the I/O Manager maintains information about the original request, such as the caller's thread ID and parameters, the address of the device object on which a file is open, and so forth. The fixed part also contains an I/O status block, in which drivers set information about the status of the requested I/O operation.
  • In the highest level driver's I/O stack location, the I/O Manager, Plug and Play Manager, or Power Manager sets driver-specific parameters, such as the particular operation requested (represented as a function code) and context used by the corresponding driver to determine what it is supposed to be doing. In turn, each higher level driver sets up the I/O stack location of the next lower driver, if any.

As a given IRP is processed through each driver's set of standard routines, each standard routine can access that driver's I/O stack location in the IRP, thereby reusing the IRP at each stage of the driver's operations. In addition, higher level drivers can create (or reuse) IRPs to send requests down to still lower drivers.

For a detailed discussion of IRPs, see Handling IRPs.


Supporting Asynchronous I/O

The I/O Manager provides asynchronous I/O support so that the originator of an I/O request (usually a user-mode application, but sometimes another driver) can continue executing, rather than waiting for its I/O request to be completed. Providing asynchronous I/O support improves overall system throughput, as well as the performance of any code that makes an I/O request.

As a consequence, kernel-mode drivers do not necessarily process I/O requests in the same order they were sent to the I/O Manager. The I/O Manager or a higher level driver can reorder I/O requests as they are received or can split a large data transfer request into smaller transfer requests. Moreover, a driver can overlap I/O request processing, particularly in a symmetric multiprocessor platform, as mentioned in Multiprocessor Safe.

Furthermore, a kernel-mode driver's processing of an individual I/O request is not necessarily serialized. That is, a driver does not process each IRP to completion before it starts processing the next incoming I/O request, as drivers naturally do in a single-tasking operating system written to support synchronous I/O in uniprocessor machines.

Instead, a driver responds to the current IRP as it is passed to the driver's standard routines by carrying out whatever routine-specific operations are necessary to eventually satisfy the current request. However, a lowest level driver is required to help the I/O Manager and any higher level drivers processing the same IRPs to track the status of each request by setting the I/O status block in the IRP.

Drivers also can maintain state information about their current I/O operations in a special part of their device objects, called a device extension.

For more information, see Handling IRPs and Input/Output Techniques.


Windows Driver Model

This section discusses the Windows Driver Model (WDM). It includes the following sections:

Introduction to WDM

Types of WDM Drivers

Device Configurations and Layered Drivers

WDM Versions


Introduction to WDM

To allow driver developers to write device drivers that are source-code compatible across all Microsoft® Windows® operating systems, the Windows Driver Model (WDM) was introduced. Kernel-mode drivers that follow WDM rules are called WDM drivers. All WDM drivers must:

  • Include wdm.h, not ntddk.h. (Note that wdm.h is a subset of ntddk.h.)
  • Be designed as a bus driver, a function driver, or a filter driver, as described in Types of WDM Drivers.
  • Create device objects as described in WDM Device Objects and Device Stacks.
  • Support Plug and Play.
  • Support Power Management.
  • Support Windows Management Instrumentation (WMI)

Does this DDK Cover non-WDM Drivers?

While this DDK emphasizes development of WDM drivers for kernel mode, information pertinent to kernel-mode drivers that do not follow WDM rules is also provided when necessary. This allows you to maintain existing non-WDM drivers and to write new drivers that interface with these existing drivers.

Should You Always Write a WDM Driver?

If you are writing new kernel-mode drivers, they should be WDM drivers unless you are writing a driver that will be inserted into a stack of non-WDM drivers. Please read the documentation for device type-specific Microsoft-supplied drivers, contained in this DDK documentation, to determine how new drivers must interface with Microsoft-supplied drivers.

Note All new driver stacks should consist of WDM drivers.

There are cross-platform issues to consider, whether you are developing WDM or non-WDM drivers. For more information, see Writing Drivers for Multiple Platforms and Operating Systems.


Types of WDM Drivers

There are three kinds of WDM drivers:

Bus drivers, which drive an I/O bus and provide per-slot functionality that is device-independent.

Function drivers, which drive an individual device.

Filter drivers, which filter I/O requests for a device, a class of devices, or a bus.

In this context, a bus is any device to which other physical, logical, or virtual devices are attached; a bus includes traditional buses such as SCSI and PCI, as well as parallel ports, serial ports, and i8042 ports.

It is important for driver writers to understand the different kinds of WDM drivers and to know which kind of driver they are writing. For example, whether or not a driver handles each Plug and Play IRP and how to handle such IRPs depends on what kind of driver is being written (bus driver, function driver, or filter driver).

The following figure shows the relationship between the bus driver, function driver, and filter drivers for a device.

Possible Driver Layers

Each device typically has a bus driver for the parent I/O bus, a function driver for the device, and zero or more filter drivers for the device. A driver design that requires many filter drivers does not yield optimal performance.

The drivers in the previous figure are the following:

  1. A bus driver services a bus controller, adapter, or bridge. Bus drivers are required drivers; there is one bus driver for each type of bus on a machine. Microsoft provides bus drivers for most common buses. IHVs and OEMs can provide other bus drivers.
  2. A bus filter driver typically adds value to a bus and is supplied by Microsoft or a system OEM. There can be any number of bus filter drivers for a bus.
  3. Lower-level filter drivers typically modify the behavior of device hardware. They are optional and are typically supplied by IHVs. There can be any number of lower-level filter drivers for a device.
  4. A function driver is the main driver for a device. A function driver is typically written by the device vendor and is required (unless the device is being used in raw mode).
  5. Upper-level filter drivers typically provide added-value features for a device. They are optional and are typically provided by IHVs.

The following sections describe the general types of drivers (bus drivers, function drivers, filter drivers) in detail.


Bus Drivers

A bus driver services a bus controller, adapter, or bridge (see the Possible Driver Layers figure). Microsoft provides bus drivers for most common buses, such as PCI, PnpISA, SCSI, and USB. Other bus drivers can be provided by IHVs or OEMs. Bus drivers are required drivers; there is one bus driver for each type of bus on a machine. A bus driver can service more than one bus if there is more than one bus of the same type on the machine.

The primary responsibilities of a bus driver are to:

  • Enumerate the devices on its bus.
  • Respond to Plug and Play IRPs and power management IRPs.
  • Multiplex access to the bus (for some buses).
  • Generically administer the devices on its bus.

During enumeration, a bus driver identifies the devices on its bus and creates device objects for them. (For information about device objects, see Device Objects and Device Stacks.) The method a bus driver uses to identify connected devices depends on the particular bus.

A bus driver performs certain operations on behalf of the devices on its bus, including accessing device registers to physically change the power state of a device. For example, when the device goes to sleep, the bus driver sets device registers to put the device in the proper device power state.

Note, however, that a bus driver does not handle read and write requests for the devices on its bus. Read and write requests to a device are handled by the device's function driver. Only if the device is being used in raw mode does the parent bus driver handle reads and writes for the device.

A bus driver acts as the function driver for its controller, adapter, or bridge, and therefore manages device power policy for these components.

A bus driver can be implemented as a driver/minidriver pair, the way a SCSI port/miniport driver pair drives a SCSI host bus adapter (HBA). In such driver pairs, the minidriver is linked to the second driver, which is a DLL.


Function Drivers

A function driver is the main driver for a device (see the Possible Driver Layers figure). A function driver is typically written by the device vendor and is required (unless the device is being used in raw mode). The PnP Manager loads at most one function driver for a device. A function driver can service one or more devices.

A function driver provides the operational interface for its device. Typically the function driver handles reads and writes to the device and manages device power policy.

The function driver for a device can be implemented as a driver/minidriver pair, such as a port/miniport driver pair or a class/miniclass driver pair. In such driver pairs, the minidriver is linked to the second driver, which is a DLL.

If a device is being driven in raw mode, it has no function driver and no upper or lower-level filter drivers. All raw-mode I/O is done by the bus driver and optional bus filter drivers.


Filter Drivers

Filter drivers are optional drivers that add value to or modify the behavior of a device. A filter driver can service one or more devices.

Bus Filter Drivers

Bus filter drivers typically add value to a bus and are supplied by Microsoft or a system OEM (see the Possible Driver Layers figure). Bus filter drivers are optional. There can be any number of bus filter drivers for a bus.

A bus filter driver could, for example, implement proprietary enhancements to standard bus hardware.

For devices described by an ACPI BIOS, the Power Manager inserts a Microsoft-supplied ACPI filter (bus filter driver) above the bus driver for each such device. The ACPI filter carries out device power policy and powers on and off devices. The ACPI filter is transparent to other drivers and is not present on non-ACPI machines.

Lower-Level Filter Drivers

Lower-level filter drivers typically modify the behavior of device hardware (see the Possible Driver Layers figure). They are typically supplied by IHVs and are optional. There can be any number of lower-level filter drivers for a device.

A lower-level device filter driver monitors and/or modifies I/O requests to a particular device. Typically, such filters redefine hardware behavior to match expected specifications.

A lower-level class filter driver monitors and/or modifies I/O requests for a class of devices. For example, a lower-level class filter driver for mouse devices could provide acceleration, performing a nonlinear conversion of mouse movement data.

Upper-Level Filter Drivers

Upper-level filter drivers typically provide added-value features for a device (see the Possible Driver Layers figure). Such drivers are usually provided by IHVs and are optional. There can be any number of upper-level filter drivers for a device.

An upper-level device filter driver adds value for a particular device. For example, an upper-level device filter driver for a keyboard could enforce additional security checks.

An upper-level class filter driver adds value for all devices of a particular class.


WDM Driver Layers -- An Example

Previous Next

WDM Driver Layers — An Example

This section describes a possible set of WDM drivers for USB hardware to illustrate WDM driver layers.

The following figure shows a sample PnP hardware configuration for a USB joystick.

Sample PnP Hardware — USB Joystick

In this figure, the USB joystick plugs into a port on a USB hub. The USB hub in this example resides on the USB Host Controller board and is plugged into the single port on the USB host controller board. The USB host controller plugs into a PCI bus. From a PnP perspective, the USB hub, the USB host controller, and the PCI bus are all bus devices because they each provide ports. The joystick is not a bus device.

The following figure shows a sample set of drivers that might be loaded for the USB joystick hardware in the previous figure.

Sample PnP Driver Layers — USB Joystick

Starting at the bottom of the previous figure, the drivers in the sample stack include:

  • A PCI driver that drives the PCI bus. This is a PnP bus driver. The PCI bus driver is provided with the system by Microsoft.
  • The bus driver for the USB host controller is implemented as a class/miniclass driver pair. The USB host controller class and miniclass drivers are provided with the system by Microsoft.
  • The USB hub bus driver that drives the USB hub. The USB hub driver is provided with the system by Microsoft.
  • Three drivers for the joystick device; one of them is a class/miniclass pair.

    The function driver, the main driver for the joystick device, is the HID class driver/HID USB miniclass driver pair. (HID represents "human interface device".) The HID USB miniclass driver supports the USB-specific semantics of HID devices, relying on the HID class driver DLL for general HID support.

    A function driver can be specific to a particular device, or, as in the case of HID, a function driver can service a group of devices. In this example, the HID class driver/HID USB miniclass driver pair services any HID-compliant device in the system on a USB bus. A HID class driver/HID 1394 miniclass driver pair would service any HID-compliant device on a 1394 bus.

    A function driver can be written by the device vendor or by Microsoft. In this example, the function driver (the HID class/HID USB miniclass driver pair) is written by Microsoft.

    There are two filter drivers for the joystick device in this example: an upper-level class filter that adds a macro button feature and a lower-level device filter that enables the joystick to emulate a mouse device.

    The upper-level filter is written by someone who needs to filter the joystick I/O and the lower-level filter driver is written by the joystick vendor.

  • The kernel-mode and user-mode HID clients and the application are not drivers but are shown for completeness.


Device Configurations and Layered Drivers

For the most common kinds of devices, this DDK supplies a sample set of fully functional, system drivers. Individual sample drivers can be used as models when developing new drivers for similar kinds of devices. However, the system's drivers had an additional design requirement: to make it easy to develop new device drivers. Consequently, many of the system's drivers have a layered architecture so that certain drivers can be reused to support new drivers for similar devices.

In most cases, the DDK-supplied reusable drivers are WDM drivers that support PnP and handle hardware-independent operations for a system-supplied device-specific lowest-level (PnP bus) driver. In some cases, such as the parallel port and SCSI port drivers, these reusable drivers provide support for higher-level, device-type-specific class drivers. Note that none of the system's reusable drivers precludes the development of new intermediate drivers to be added to a chain of existing drivers.

Where a new (or replacement) driver fits in the chain of drivers for a device depends partly on the hardware configuration of devices in a given Windows platform, and partly on how much support a new driver can get from existing system drivers.


Sample Device and Driver Configuration

This section illustrates the relationship between the hardware and driver configurations, using the keyboard and mouse devices as an example. Configurations differ for other devices. For complete information on any device configuration, see the device-specific documentation in this DDK.

The following figure shows two possible hardware configurations for the keyboard and mouse devices:

  • Each connected directly somewhere on the system bus
  • Both connected through a keyboard and auxiliary device controller

Keyboard and Mouse Hardware Configurations

The following figure illustrates the corresponding layered drivers for I/O operations on the devices shown in the previous figure.

Keyboard and Mouse Driver Layers

Note that drivers of keyboard and mouse devices, whatever the hardware configuration, can use the system's keyboard class and mouse class drivers to handle hardware-independent operations. These are called class drivers because each supplies system-required but hardware-independent support for a particular class of device.

A corresponding port driver implements the device-specific support to carry out required I/O operations on each physical device. The system's (i8042) keyboard and auxiliary device port driver for x86-based platforms manages device-specific operations for both mouse and keyboard. In a hardware configuration where each device is separately connected, as shown in the figure illustrating the keyboard and mouse hardware configurations, each system class driver can be layered over separate device-specific port drivers, or a single driver for each device could be implemented as a separate, monolithic (lowest-level) driver.

A new intermediate driver, such as a PnP filter driver, could be added to the configuration in the figure illustrating the keyboard and mouse driver layers. For example, a filter driver added above the keyboard class driver might filter keyboard input in a platform-specific manner before passing it through the I/O services to the subsystem that requested it. Such a filter driver must recognize the same IRPs and IOCTLs as the keyboard class driver.


Points to Consider When Adding Drivers

Keep the following points in mind when designing a kernel-mode driver:

  • The system-supplied SCSI and video port drivers cannot be replaced.
  • A replacement lowest-level driver must implement the same functionality as the driver it replaces. For example, a replacement keyboard or mouse port driver must use the system-defined interface between itself and a system-supplied class driver that it reuses, and vice versa.
  • A new intermediate driver, inserted between any pair of system-supplied drivers, must interoperate with those drivers so that the functionality of the upper and lower drivers is not reduced.


WDM Versions

Although Microsoft® Windows® XP, Windows 2000, Windows 98, and Windows Me all support WDM, incremental changes to WDM have resulted in later-released operating systems supporting additional WDM features that earlier releases do not support. Later versions of WDM generally support all the features available in earlier versions of WDM; that is, each new version of WDM is a superset of the previous WDM version. When possible, a cross-system driver should conform to the lowest WDM version on any operating system.

This section provides the following topics:

Determining the WDM Version

Differences in WDM Versions


Determining the WDM Version

A cross-system WDM driver should use the IoIsWdmVersionAvailable routine to determine which version of WDM is supported by the system on which it is running. The reference page for IoIsWdmVersionAvailable provides a list of WDM version numbers.

For information about differences in WDM that drivers should handle, see Differences in WDM Versions.


Differences in WDM Versions

The simplest way to ensure cross-system compatibility is to write a driver that uses only those features supported by the lowest version of WDM. However, this is not always possible. In some situations, drivers require additional code to take advantage of features available in later versions of WDM or to compensate for differences between Windows operating systems.

WDM Differences in Driver Support Routines

The DDK reference page for each driver support routine indicates if the routine is restricted to specific versions of WDM, or if its behavior is different on different operating system versions. Before using any driver support routine in a cross-system driver, be sure to understand any version-specific restrictions or behaviors.

WDM Differences in Plug and Play

The following Plug and Play features are supported only in Windows 2000 and later versions of the operating system (WDM version 1.10 and later):

IRP_MN_SURPRISE_REMOVAL

In addition, the following features work differently on Windows 98/Me from Windows 2000 and later versions of the operating system:

IRP_MN_STOP_DEVICE and IRP_MN_REMOVE_DEVICE

IRP_MN_QUERY_REMOVE_DEVICE

WDM Differences in Power Management

The following power management features differ in operation on Windows 98/Me and Windows 2000 and later versions of the operating system:

PoSetPowerState

PoRequestPowerIrp

PoRegisterDeviceForIdleDetection

IRP_MN_QUERY_POWER

IRP_MN_SET_POWER

Completing power IRPs. Drivers on Windows 98/Me must complete power IRPs at IRQL = PASSIVE_LEVEL, while drivers on Windows 2000 and later versions of the operating system can complete such IRPs at IRQL = PASSIVE_LEVEL or IRQL = DISPATCH_LEVEL.

DO_POWER_PAGABLE flag in DEVICE_OBJECT

WDM Differences in Kernel-Mode Driver Operation

Kernel-mode WDM drivers for Windows 98/Me must follow certain guidelines for using floating-point operations, MMX, 3DNOW!, or Intel's SSE extensions. For more information, see Using Floating Point or MMX in a WDM Driver.

Windows 98/Me provides a fixed number of worker threads that might not be adequate for some drivers. For more information about this and other Windows 98/Me-specific WDM issues, see Cross-Platform Issues for WDM Drivers.


Device Objects and Device Stacks

This section discusses device objects and their arrangement in device stacks. It contains the following sections:

Introduction to Device Objects

WDM Device Objects and Device Stacks

Creating a Device Object

Specifying Device Types

Initializing a Device Object

Device Extensions

Points to Consider About Device Objects


Introduction to Device Objects

A driver creates a device object for each device it controls. The device object represents the device to the driver.

Every kernel-mode driver (except for certain miniport drivers) creates at least one device object. Some drivers must create more than one device object: whatever a particular driver's level in a chain of layered drivers, a separate device object represents each physical, logical, and/or virtual device for which the driver handles I/O requests.

Some miniport drivers do not create device objects because a system-supplied port or class driver creates and manages all necessary system-defined objects on their behalf.

Each driver object represents a single driver that can create one or more device objects. The I/O Manager maintains a list of device objects created by each driver, and stores a pointer to this list in the driver object.

Each standard driver routine that is passed an IRP is also passed a pointer to the target device object for the I/O request. Most drivers use the device extension of the target device object to maintain device state information or driver-specified context data for the I/O request.

A device object, like a driver object, is partially opaque to drivers. Driver writers must know about certain field names and system-defined symbolic constants associated with device objects because their drivers must access these fields through the DeviceObject pointer returned by IoCreateDevice and passed to most standard driver routines.

Keep in mind that the location of any field that is accessible through a returned DeviceObject pointer can change from one Windows platform or version to another. In addition, "unpublished" fields within any object are, in effect, inaccessible: that is, drivers should never access them. A driver that has dependencies on the location of any field in a system-defined object, or that accesses undocumented fields within an object, also compromises its own future portability and interoperability with other drivers.

The following figure illustrates a device object, representing a physical, logical, or virtual device within the system. A driver creates one or more device objects by calling IoCreateDevice from its AddDevice routine.

Device Object

This figure shows field names and constants that are particularly important for writers of lowest-level and intermediate driver. These fields are described in greater detail in the following subsections.


WDM Device Objects and Device Stacks

This section describes the types of devices objects that are defined by WDM, and explains their arrangement in device stacks. It contains the following topics:

Types of WDM Device Objects

Example WDM Device Objects

When Are WDM Device Objects Created?

Example WDM Device Stack


Types of WDM Device Objects

There are three kinds of WDM device objects:

  1. Physical Device Object (PDO) – represents a device on a bus to a bus driver.
  2. Functional Device Object (FDO) – represents a device to a function driver.
  3. Filter Device Object (filter DO) – represents a device to a filter driver.

The three kinds of device objects are all of the type DEVICE_OBJECT, but are used differently and can have different device extensions.

A driver adds itself to the stack of drivers that handle I/O for a device by creating a device object (IoCreateDevice) and attaching it to the device stack (IoAttachDeviceToDeviceStack). IoAttachDeviceToDeviceStack determines the current top of the device stack and attaches the new device object to the top of the device stack.


Example WDM Device Objects

The following figure illustrates the device objects that represent the keyboard and mouse devices shown previously in the figure illustrating Keyboard and Mouse Hardware Configurations. The keyboard and mouse drivers shown in the figure illustrating Keyboard and Mouse Driver Layers create these device objects by calling an I/O support routine (IoCreateDevice).

Keyboard and Mouse Device Objects

For the keyboard and mouse devices, both their respective port and class drivers create device objects. The port driver creates a physical device object (PDO) to represent the physical port. Each class driver creates its own functional device object (FDO) to represent the keyboard or mouse device as a target for I/O requests.

Each class driver calls an I/O support routine to get a pointer to the next-lower-level driver's device object, so the class driver can chain itself above that driver, which is the port driver. Then the class driver can send I/O requests down to the port driver for the target PDO representing its physical device.

An optional filter driver added to the configuration would create a filter device object (filter DO). Like the class driver, an optional filter driver chains itself to the next-lower driver in the device stack and sends I/O requests for the target PDO down to the next-lower driver.

As shown previously in the Keyboard and Mouse Driver Layers figure, each port driver is a bus (lowest-level) driver, so every port driver of a device that generates interrupts must set up interrupt object(s) and register an ISR.

A dual-device port driver, like the i8042 driver for the keyboard and auxiliary device controller shown in the Keyboard and Mouse Hardware Configurations, must set up device-specific interrupt objects if each device uses a different interrupt vector. When writing such a driver, you can either implement separate ISRs for each device or implement a single ISR for both devices.


When Are WDM Device Objects Created?

This section describes each kind of device object and mentions when each is created.

The following figure shows the possible kinds of device objects that can be attached in a device stack, representing the drivers handling I/O requests for a device.

Possible Device Object Layers for a Device

Starting at the bottom of this figure:

  • A bus driver creates a PDO for each device that it enumerates on its bus.

    A bus driver creates a PDO for a child device when it enumerates the device. A bus driver enumerates a device in response to an IRP_MN_QUERY_DEVICE_RELATIONS request for BusRelations from the PnP Manager. The bus driver creates a PDO for a child device if the device has been added to the bus since the last time the bus driver responded to a query-relations request for BusRelations (or if this is the first query-relations request since the machine was booted).

    A PDO represents the device to the bus driver, as well as to other kernel-mode system components such as the Power Manager, the PnP Manager, and the I/O Manager.

    Other drivers for a device attach device objects on top of the PDO, but the PDO is always at the bottom of the device stack.

  • Optional bus filter drivers create filter DOs for each device they filter.

    When the PnP Manager detects a new device in a BusRelations list, it determines whether there are any bus filter drivers for the device. If so, for each such driver the PnP Manager ensures it is loaded (calls DriverEntry if necessary) and calls the driver's AddDevice routine. If the bus filter driver filters operations for this device, the filter driver creates a device object and attaches it to the device stack in its AddDevice routine. If more than one bus filter driver exists and is relevant to this device, each such filter driver creates and attaches its own device object.

  • Optional, lower-level filter drivers create filter DOs for each device they filter.

    If an optional, lower-level filter driver exists for this device, the PnP Manager ensures that such a driver is loaded after the bus driver and any bus filter drivers. The PnP Manager calls the filter driver's AddDevice routine. In its AddDevice routine, the lower-level filter driver creates a filter DO for the device and attaches it to the device stack. If more than one lower-level filter driver exists, each such driver would create and attach its own filter DO.

  • The function driver creates an FDO for the device.

    The PnP Manager ensures that the function driver for the device is loaded and calls the function driver's AddDevice routine. The function driver creates an FDO and attaches it to the device stack.

  • Optional, upper-level filter drivers create a filter DO for each device they filter.

    If any optional, upper-level filter drivers exist for the device, the PnP Manager ensures they are loaded after the function driver and calls their AddDevice routines. Each such filter driver attaches its device object to the device stack.

In summary, the device stack contains a device object for each driver that is involved in handling I/O to a particular device. The parent bus driver has a PDO, the function driver has an FDO, and each optional filter driver has a filter DO.

Note that all devices, bus adapter/controller devices and non-bus devices, have a PDO and an FDO in their device stack. The PDO for a bus adapter/controller is created by the bus driver for the parent bus. For example, if a SCSI adapter plugs into a PCI bus, the PCI bus driver creates a PDO for the SCSI adapter.

If a device is being used in raw mode, there are no function or filter drivers (no FDO or filter DOs). There is just a PDO for the parent bus driver and zero or more bus filter DOs.

See Creating a Device Object for information about which driver routines are responsible for creating and attaching device objects.

The device stack plus some additional information constitutes the devnode for a device. The PnP Manager maintains information in a device's devnode such as whether the device has been started and which drivers, if any, have registered for notification of changes on the device. The kernel debugger command !devnode displays information about a devnode.


Example WDM Device Stack

This section describes the device objects created by a possible set of drivers for USB hardware to illustrate WDM device objects and how they are layered.

The following figure shows the device objects that are created by the sample drivers described in WDM Driver Layers – An Example.

Sample WDM Device Object Layers — USB Joystick

Starting at the bottom of this figure, the device objects in the sample device stacks include:

  1. A PDO and an FDO for the PCI bus.

    The root bus driver enumerates the internal system bus (the root bus) and creates a PDO for each device it finds. One of these PDOs is for the PCI bus. (The PDO and FDO for the root bus are not shown in the figure.)

    The PnP Manager identifies the PCI driver as the function driver for the PCI bus, loads the driver (if it is not already loaded), and passes the PDO to the PCI driver. In its AddDevice routine, the PCI driver creates an FDO for the PCI bus (IoCreateDevice ) and attaches the FDO to the device stack (IoAttachDeviceToDeviceStack) for the PCI bus. The PCI driver creates and attaches this FDO as part of its responsibilities as the function driver for the PCI bus.

    There are no filter drivers for the PCI bus in this example.

  2. A PDO and an FDO for the USB host controller.

    The PnP Manager directs the PCI driver to start its device (IRP_MN_START_DEVICE) and then queries the PCI driver for its children (IRP_MN_QUERY_DEVICE_RELATIONS with relation type of BusRelations). In response, the PCI driver enumerates the devices on its bus. In this example, the PCI driver finds a USB host controller and creates a PDO for that device. The wide arrow in the figure indicates that the USB host controller is a "child" of the PCI bus. The PCI driver creates PDOs for its child devices as part of its responsibilities as the bus driver for the PCI bus.

    The PnP Manager identifies the USB host controller miniclass/class driver pair as the function driver for the USB host controller and loads the driver pair. The PnP Manager calls the driver pair at the appropriate time to create and attach an FDO for the USB host controller.

    There are no filter drivers for the USB host controller in this example.

  3. A PDO and an FDO for the USB hub.

    The USB host controller enumerates its bus, locates the USB hub in the sole port, and creates a PDO for the hub. The USB hub driver creates and attaches an FDO for the hub.

    There are no filter drivers for the USB hub in this example.

  4. A PDO, an FDO, and two filter DOs for the joystick device.

    The USB hub driver enumerates its bus, locates a HID device (the joystick), and creates a PDO for the joystick.

    In this example, a lower-level filter driver has been set up in the registry for joystick devices, so the PnP Manager loads the filter driver. The filter driver determines that it is relevant to the device and creates and attaches a filter DO to the device stack.

    The PnP Manager determines that the function driver for the joystick device is the HID class/miniclass driver pair and loads those drivers. The driver pair consists of a miniclass driver linked to a class driver DLL; together they act as one function driver for the device. The class/miniclass driver pair creates one device object, the FDO, and attaches it to the device stack.

    An upper-level filter driver creates and attaches a filter DO to the device stack, in a manner similar to the lower-level filter.

Note that the PDO created by the parent bus driver is always at the bottom of the device stack for a particular device. When drivers handle PnP or power IRPs, they must pass each IRP all the way down the device stack to the PDO and its associated bus driver.

The following figure shows the same device stacks as the previous figure, but emphasizes which device objects are created and managed by which drivers.

Sample Device Object Layers — From the Driver Perspective

A bus driver spans more than one device stack. A bus driver creates the FDO for its bus adapter/controller and creates a PDO for each of its child devices.


Creating a Device Object

Most drivers call IoCreateDevice from their AddDevice routines. A bus driver calls IoCreateDevice when it is enumerating a new device in response to an IRP_MN_QUERY_DEVICE_RELATIONS request, if the relation type is BusRelations. Some drivers, such as disk drivers that must respond to drive layout IOCTLs, call IoCreateDevice from a dispatch routine.

Except for certain minidrivers, which are paired with a class driver that creates the device object, every driver must call IoCreateDevice one or more times from its AddDevice routine to create a device object to represent each physical, logical, or virtual device for which it handles I/O requests. A driver will not receive IRPs for any target device for which it did not create a device object.

Each driver specifies the size of the device extension in the DeviceExtensionSize parameter when it calls IoCreateDevice to set up a device object.

In addition to the size of the device extension, IoCreateDevice requires arguments that determine the following:

  • A system-defined constant, indicating the DeviceType represented by the device object. For more information, see Specifying Device Types.
  • One or more ORed, system-defined constants, indicating the DeviceCharacteristics for certain kinds of devices (floppy drive, CD-ROM, and WORM removable-media devices). Otherwise, the DeviceCharacteristics value passed to IoCreateDevice must be zero.
  • A Boolean (Exclusive) value that specifies whether a bit in the device object's Flags should be set with DO_EXCLUSIVE, indicating the driver services an exclusive device, such as a video, serial, parallel, or sound device. WDM drivers must set Exclusive to FALSE.
  • A pointer to the DriverObject that was input to the driver's AddDevice routine, associating the driver object with the physical, logical, or virtual device for which the caller handles IRPs.
  • An optional pointer to a zero-terminated Unicode string (DeviceName) naming the device. PnP drivers should not supply a device name; doing so bypasses the PnP Manager's security features. PnP drivers can chain themselves to the driver of an unnamed device by calling IoAttachDeviceToDeviceStack.

    If a user-mode component needs a symbolic link to the device, register a device interface (see IoRegisterDeviceInterface). If a kernel-mode component needs a legacy device name, the driver must name the device object, but naming is not recommended.

For every driver except file system drivers (FSD), the I/O Manager also sets up an associated device queue object for every successful call to IoCreateDevice, as shown in the Device Object figure. The device queue object associated with a device object represents a queue of IRPs bound for a driver's StartIo routine after the driver is loaded. Drivers that manage their own internal IRP queues, such as the system floppy controller driver, do not use the device queues associated with their device objects. Such drivers can create their own device queue objects. See Managing Device Queues for more information.

If the call to IoCreateDevice succeeds, the I/O Manager provides storage for the device object itself and for all other data structures associated with the device object, including the driver's device extension, which it initializes with zeros.

If the caller creates more than one device object, the I/O Manager links its subsequently created device objects to the input driver object by maintaining NextDevice pointers in the device objects.


Specifying Device Types

Every kernel-mode driver that creates a device object must specify an appropriate device type value when calling IoCreateDevice. The IoCreateDevice routine uses the supplied device type to initialize the DeviceType member of the DEVICE_OBJECT structure.

The system defines the following device type values, listed in alphabetical order:

#define FILE_DEVICE_8042_PORT           0x00000027
#define FILE_DEVICE_ACPI                0x00000032
#define FILE_DEVICE_BATTERY             0x00000029
#define FILE_DEVICE_BEEP                0x00000001
#define FILE_DEVICE_BUS_EXTENDER        0x0000002a
#define FILE_DEVICE_CD_ROM              0x00000002
#define FILE_DEVICE_CD_ROM_FILE_SYSTEM  0x00000003
#define FILE_DEVICE_CHANGER             0x00000030
#define FILE_DEVICE_CONTROLLER          0x00000004
#define FILE_DEVICE_DATALINK            0x00000005
#define FILE_DEVICE_DFS                 0x00000006
#define FILE_DEVICE_DFS_FILE_SYSTEM     0x00000035
#define FILE_DEVICE_DFS_VOLUME          0x00000036
#define FILE_DEVICE_DISK                0x00000007
#define FILE_DEVICE_DISK_FILE_SYSTEM    0x00000008
#define FILE_DEVICE_DVD                 0x00000033
#define FILE_DEVICE_FILE_SYSTEM         0x00000009
#define FILE_DEVICE_FULLSCREEN_VIDEO    0x00000034
#define FILE_DEVICE_INPORT_PORT         0x0000000a
#define FILE_DEVICE_KEYBOARD            0x0000000b
#define FILE_DEVICE_KS                  0x0000002f
#define FILE_DEVICE_KSEC                0x00000039
#define FILE_DEVICE_MAILSLOT            0x0000000c
#define FILE_DEVICE_MASS_STORAGE        0x0000002d
#define FILE_DEVICE_MIDI_IN             0x0000000d
#define FILE_DEVICE_MIDI_OUT            0x0000000e
#define FILE_DEVICE_MODEM               0x0000002b
#define FILE_DEVICE_MOUSE               0x0000000f
#define FILE_DEVICE_MULTI_UNC_PROVIDER  0x00000010
#define FILE_DEVICE_NAMED_PIPE          0x00000011
#define FILE_DEVICE_NETWORK             0x00000012
#define FILE_DEVICE_NETWORK_BROWSER     0x00000013
#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014
#define FILE_DEVICE_NETWORK_REDIRECTOR  0x00000028
#define FILE_DEVICE_NULL                0x00000015
#define FILE_DEVICE_PARALLEL_PORT       0x00000016
#define FILE_DEVICE_PHYSICAL_NETCARD    0x00000017
#define FILE_DEVICE_PRINTER             0x00000018
#define FILE_DEVICE_SCANNER             0x00000019
#define FILE_DEVICE_SCREEN              0x0000001c
#define FILE_DEVICE_SERENUM             0x00000037
#define FILE_DEVICE_SERIAL_MOUSE_PORT   0x0000001a
#define FILE_DEVICE_SERIAL_PORT         0x0000001b
#define FILE_DEVICE_SMARTCARD           0x00000031
#define FILE_DEVICE_SMB                 0x0000002e
#define FILE_DEVICE_SOUND               0x0000001d
#define FILE_DEVICE_STREAMS             0x0000001e
#define FILE_DEVICE_TAPE                0x0000001f
#define FILE_DEVICE_TAPE_FILE_SYSTEM    0x00000020
#define FILE_DEVICE_TERMSRV             0x00000038
#define FILE_DEVICE_TRANSPORT           0x00000021
#define FILE_DEVICE_UNKNOWN             0x00000022
#define FILE_DEVICE_VDM                 0x0000002c
#define FILE_DEVICE_VIDEO               0x00000023
#define FILE_DEVICE_VIRTUAL_DISK        0x00000024
#define FILE_DEVICE_WAVE_IN             0x00000025
#define FILE_DEVICE_WAVE_OUT            0x00000026

These constants are defined in ntddk.h and wdm.h. Check these files to see if additional device types have been defined.

The FILE_DEVICE_DISK specification covers both floppy and fixed-disk devices, as well as disk partitions.

Intermediate drivers usually specify device types that represent the underlying device. For example, the system-supplied fault-tolerant disk driver, ftdisk, creates device objects of type FILE_DEVICE_DISK; it does not define new device types for the mirror sets, stripe sets, and volume sets it manages.

FILE_DEVICE_XXX values in the range of 0 through 32767 are reserved for Microsoft. All driver writers must use these system-defined constants for devices belonging to the system-defined device types.

Driver writers can define new device type values for a new kinds of devices. Values in the range of 32768 through 65535 are available for Microsoft customers who develop drivers for such devices.


Initializing a Device Object

After IoCreateDevice returns, giving the caller a pointer to a DeviceObject that contains a pointer to the device extension, drivers must set up certain fields in the device objects for their respective physical, logical, and/or virtual devices.

IoCreateDevice sets the StackSize field of a newly created device object to one. A lowest-level driver can ignore this field. When a higher-level driver calls IoAttachDeviceToDeviceStack to attach itself to the next-lower driver, that routine automatically sets the StackSize field in the device object to that of the next-lower driver's device object plus one. For some device types, however, the higher-level driver might need to set the StackSize field to a greater value, as noted in the device-specific documentation. Setting the stack size ensures that IRPs sent to the higher-level driver will contain a driver-specific I/O stack location, plus the correct number of I/O stack locations for all lower-level drivers in the chain.

IoCreateDevice sets the AlignmentRequirement field of a newly created device object to the processor's data cache line size minus one, to ensure that buffers used in direct I/O are aligned correctly. After IoCreateDevice returns, lowest-level physical device drivers must do the following:

  1. Subtract one from the alignment requirement of the device.
  2. Compare the result of Step 1 with the current value of the device object's AlignmentRequirement.
  3. If the device's alignment requirement is greater, set AlignmentRequirement to the result of Step 1. Otherwise, leave the AlignmentRequirement value as set by IoCreateDevice.

After any higher-level driver chains itself over another driver by calling IoGetDeviceObjectPointer, the higher-level driver must set the AlignmentRequirement field of its newly created device object to that of the next-lower-level driver's device object. As a general rule, a higher-level driver should not change this value. If a higher-level driver calls IoAttachDevice or IoAttachDeviceToDeviceStack, those routines automatically set the AlignmentRequirement field in the device object to that of the lower-level driver's device object.

IoGetDeviceObjectPointer returns pointers both to the lower-level driver's device object and to the associated file object. Only an FSD (or, possibly, another highest-level driver) can use the returned file object pointer. An intermediate driver that calls IoGetDeviceObjectPointer should save this file object pointer so it can be dereferenced by calling ObDereferenceObject when the driver is unloaded.

After an FSD mounts the volume containing the file object that represents a lower driver's device object, an intermediate driver cannot chain itself between the file system and the lower driver by calling IoAttachDevice or IoAttachDeviceToDeviceStack.

An intermediate or lowest-level driver also sets a bit in the device object's Flags by ORing it either with DO_DIRECT_IO or with DO_BUFFERED_IO in every device object it creates. Highest-level drivers of logical or virtual devices can avoid setting Flags for either buffered or direct I/O if the driver writer decides the additional work involved will pay off in better driver performance. An intermediate driver must set up the Flags field of its device object to match that of the next-lower driver's device object.

Setting up a device object Flags field with DO_DIRECT_IO or DO_BUFFERED_IO determines how the I/O Manager passes access to user buffers in all data transfer requests subsequently sent to the driver.

The driver can then set any other device-dependent values in the device object. For example, non-WDM drivers for removable-media devices must OR the device object's Flags member with DO_VERIFY_VOLUME if they detect (or suspect) a change in media during I/O operations. (See Supporting Removable Media for more information.) Drivers of devices that require inrush power must OR the Flags member with DO_POWER_INRUSH, and drivers of devices that are not on the system paging path must OR the Flags member with DO_POWER_PAGABLE. Function and filter drivers must clear the DO_DEVICE_INITIALIZING flag.

After initializing the device object, a driver can also initialize any Kernel-defined objects and other system-defined data structures for which it has provided storage in the device extension. Precisely when a driver performs these tasks depends on its device, the type of the object, and/or the nature of the data. In general, any objects or data structures that can persist through PnP start and stop requests can be initialized in the AddDevice routine. Those that require resource information provided with a PnP IRP_MN_START_DEVICE request, or that might require changes when the device is stopped and/or restarted, should be initialized when the driver handles the IRP_MN_START_DEVICE request.


Device Extensions

For most intermediate and lowest-level drivers, the device extension is the most important data structure associated with a device object. Its internal structure is driver-defined, and it is typically used to:

  • Maintain device state information.
  • Provide storage for any Kernel-defined objects or other system resources, such as spin locks, used by the driver.
  • Hold any data the driver must have resident and in system space to carry out its I/O operations.

Because most bus, function, and filter drivers (lowest-level and intermediate drivers) execute in an arbitrary thread context (that of whatever thread happens to be current), a device extension is each driver's primary place to maintain device state and all other device-specific data the driver needs. For example, any driver that implements a CustomTimerDpc or CustomDpc routine usually provides storage for the required Kernel-defined timer and/or DPC objects in a device extension.

Every driver that has an ISR must provide storage for a pointer to a set of Kernel-defined interrupt objects, and most device drivers store this pointer in a device extension. Each driver determines the size of the device extension when it creates a device object, and each driver defines the contents and structure of its own device extensions.

The I/O Manager's IoCreateDevice routine allocates memory for the device object and extension from the nonpaged memory pool.

Every standard driver routine that receives an IRP also receives a pointer to a device object representing the target device for the requested I/O operation. These driver routines can access the corresponding device extension through this pointer. Usually, a DeviceObject pointer is also an input parameter to a lowest-level driver's ISR.

The following figure shows a representative set of driver-defined data for the device extension of a lowest-level driver's device object. A higher-level driver would not provide storage for an interrupt object pointer returned by IoConnectInterrupt and passed to KeSynchronizeExecution and IoDisconnectInterrupt. However, a higher-level driver would provide storage for the timer and DPC objects shown in the following figure if the driver has a CustomTimerDpc routine. A higher-level driver also might provide storage for an executive spin lock and interlocked work queue.

Sample Device Extension for Lowest-Level Driver

In addition to providing storage for an interrupt object pointer, a lowest-level device driver must supply storage for an interrupt spin lock if its ISR handles interrupts for two or more devices on different vectors or if it has more than one ISR. For more information about registering an ISR, see Interrupt Objects and ISRs.

Typically, drivers store pointers to their device objects in their device extensions, as shown in the figure. A driver might also keep a copy of the resource list for the device in the extension.

A higher-level driver typically stores a pointer to the next-lower driver's device object in its device extension. A higher-level driver must pass a pointer to the next-lower driver's device object to IoCallDriver, after it has set up the next-lower driver's I/O stack location in an IRP, as explained in Handling IRPs.

Note also that any higher-level driver that allocates IRPs for lower-level drivers must specify how many stack locations the new IRPs should have. In particular, if a higher-level driver calls IoMakeAssociatedIrp (non-WDM only), IoAllocateIrp, or IoInitializeIrp, it must access the target device object of the next-lower-level driver to read its StackSize value, in order to supply the correct StackSize as an argument to these support routines.

While a higher-level driver can read data from the next-lower-level driver's device object through the pointer returned by IoAttachDeviceToDeviceStack, such a driver must follow these implementation guidelines:

  • Never attempt to write data to the lower driver's device object.

    The only exceptions to this guideline are file systems, which set and clear DO_VERIFY_VOLUME in the Flags of lower-level removable-media drivers' device objects.

  • Never attempt to access the lower driver's device extension for the following reasons:
    • There is no safe way to synchronize access to a single device extension between two drivers.
    • A pair of drivers that implement such a backdoor communication scheme cannot be upgraded individually, cannot have an intermediate driver inserted between them without changing existing driver source, and cannot be recompiled and moved readily from one Windows platform to the next.

To preserve their interoperability with lower-level drivers from one Windows platform or version to the next, higher-level drivers either must reuse the IRPs given them or must create new IRPs, and they must use IoCallDriver to communicate requests to lower-level drivers.


Points to Consider About Device Objects

Keep the following points in mind when designing a kernel-mode driver:

  • Except for certain miniport drivers, every driver must create a named device object to represent each physical, logical, or virtual device that could be a target for an I/O request.

    For example, a replacement parallel port or serial driver should create a physical device object for each port. By contrast, a new virtual disk driver that presented every hard disk in the system as one big disk device could create a single functional device object to represent its disk, plus some number of additional functional device objects representing disk partitions for the file systems layered over such an intermediate driver.

  • A lowest-level driver, such as a PnP hardware bus driver, creates a physical device object (PDO) for each device it controls. An intermediate driver, such as a PnP function driver, creates a functional device object (FDO).

    A WDM driver creates device objects in its AddDevice routine, which is called by the PnP Manager after device enumeration.

  • For most lowest-level and intermediate drivers, the device extension of each device object is each driver's primary (and frequently only) global data storage area. Many drivers maintain device state and all other device-specific data and resources a driver requires in the driver-defined device extension of each driver-created device object.

    (Additionally, the driver-specific I/O stack location associated with an IRP can be considered an operation-specific local storage area for some kinds of data.)

See the device-type-specific documentation in the DDK for more information on the device objects a specific driver must create.


Kernel-Mode Driver Components

This section introduces the standard routines contained in kernel-mode drivers. Some of these standard driver routines are required; others are optional. The section also introduces driver objects, which contain pointers to each driver's standard routines.

Some drivers interact with a system-supplied port driver or class driver that defines much of the driver's required functionality. For example, a SCSI miniport driver primarily interacts with the SCSI port driver. For such drivers, see the class-specific documentation for details of required and optional driver support.

This section includes:

Introduction to Standard Driver Routines

Standard Driver Routine Requirements

Introduction to Driver Objects

Writing a DriverEntry Routine

Writing a Reinitialize Routine

Writing an AddDevice Routine

Writing Dispatch Routines

Writing an Unload Routine


Introduction to Standard Driver Routines

Each kernel-mode driver is constructed around a set of system-defined, standard driver routines. Kernel-mode drivers process I/O request packets (IRPs) within these standard routines by calling system-supplied driver support routines.

All drivers, regardless of their level in a chain of attached drivers, must have a basic set of standard routines in order to process IRPs. Whether a driver must implement additional standard routines depends on whether the driver controls a physical device or is layered over a physical device driver, as well as on the nature of the underlying physical device. Lowest-level drivers that control physical devices have more required routines than higher-level drivers, which typically pass IRPs to a lower driver for processing.

Standard driver routines can be divided into two groups: those that each kernel-mode driver must have, and those that are optional, depending on the driver type and location in the device stack.

This section describes required standard routines. Other sections describe the optional routines.

Following are two tables. The first table lists required standard routines. The second lists most of the optional routines.

Required Standard Driver Routines
DriverEntry
 | Purpose: Initializes the driver and its driver object. Where Described: Writing a DriverEntry Routine
AddDevice
 | Purpose: Initializes devices and creates device objects. Where Described: Writing an AddDevice Routine
Dispatch Routines
 | Purpose: Receive and process IRPs. Where Described: Writing Dispatch Routines
Unload
 | Purpose: Release system resources acquired by the driver. Where Described: Writing an Unload Routine

Optional Standard Driver Routines
Reinitialize
 | Purpose: Completes driver initialization if DriverEntry cannot. Where Described: Writing a Reinitialize Routine
StartIo
 | Purpose: Starts an I/O operation on a physical device. Where Described: Writing a StartIo Routine
Interrupt Service Routine
 | Purpose: Saves the state of a device when it interrupts. Where Described: Writing an ISR
Deferred Procedure Calls
 | Purpose: Completes the processing of a device interrupt after an ISR saves the device state. Where Described: DPC Objects and DPCs
SynchCritSection
 | Purpose: Synchronizes access to driver data. Where Described: Using Critical Sections
AdapterControl
 | Purpose: Initiates DMA operations. Where Described: Adapter Objects and DMA
IoCompletion
 | Purpose: Completes a driver's processing of an IRP. Where Described: Completing IRPs
Cancel
 | Purpose: Cancels a driver's processing of an IRP. Where Described: Canceling IRPs
CustomTimerDpc, IoTimer
 | Purpose: Timing and synchronizing events Where Described: Synchronization Techniques

The current IRP and target device object are input parameters to many standard routines. Every driver processes each IRP in stages through its set of standard routines.

By convention, the system-supplied drivers prepend an identifying, driver-specific or device-specific prefix to the name of every standard routine except DriverEntry. As an example, this documentation uses "DD", as shown in the figure of a Driver Object. Following this convention makes it easier to debug and maintain drivers.


Standard Driver Routine Requirements

Keep the following points in mind when designing a kernel-mode driver:

  • Each driver must have a DriverEntry routine, which initializes driver-wide data structures and resources. The I/O Manager calls the DriverEntry routine when it loads the driver.
  • Every driver must have at least one dispatch routine, and it must place a dispatch routine's entry point in its DRIVER_OBJECT structure for each IRP_MJ_XXX function code it handles. A driver can have a separate dispatch routine for each of the IRP_MJ_XXX function codes the driver handles.
  • Every driver must have an Unload routine, and must place the Unload routine's entry point in its driver object, if the driver can be replaced while the system is running. An Unload routine is responsible for releasing any system resources, such as system-defined objects or driver-allocated memory, that the driver is using before the driver itself is unloaded from the system.
  • Every PnP driver must have an AddDevice routine and define its entry point in the driver extension of the driver object. An AddDevice routine is responsible for creating and initializing device objects for each PnP device the driver controls.
  • A driver can have a StartIo routine and place its entry point in the driver object. Any lowest-level driver that does not have a StartIo routine must set up and manage internal queues of the IRPs sent to its dispatch routines, unless it can complete every IRP it gets within its dispatch routines. Higher-level drivers can have a StartIo routine, but seldom do because higher-level drivers usually pass IRPs on to lower-level drivers directly from their dispatch routines.
  • Certain miniport drivers are exceptions to the preceding requirements. See the device-type-specific documentation in this DDK for information about the requirements for miniport drivers.
  • Whether a driver has any other kind of standard routine depends on its functionality and on how that driver fits into the system (for example, whether it interoperates with system-supplied drivers). See the device-type specific documentation in this DDK for details.


Introduction to Driver Objects

The I/O manager creates a driver object for each driver that has been installed and loaded. Driver objects are defined using DRIVER_OBJECT structures.

When the I/O manager calls a driver's DriverEntry routine, it supplies the address of the driver's driver object. The driver object contains storage for entry points to many of a driver's standard routines. The driver is responsible for filling in these entry points.

The following figure illustrates a driver object, with the set of system-defined standard routines that lowest-level and higher-level drivers can or must have.

Each standard routine with an asterisk beside its name receives an IRP as input. Each of these standard routine also receives a pointer to the target device object for the I/O request.

Driver Object

The I/O Manager defines the driver object type and uses driver objects to register and track information about the loaded images of drivers. Note that the dispatch entry points (DDDispatchXxx through DDDispatchYyy) in the driver object correspond to the major function codes (IRP_MJ_XXX) that are passed in the I/O stack locations of IRPs.

The I/O Manager routes each IRP first to a driver-supplied dispatch routine. A lowest-level driver's dispatch routine usually calls an I/O support routine (IoStartPacket) to queue (or pass on) each IRP that has valid arguments to the driver's StartIo routine. The StartIo routine starts the requested I/O operation on a particular device. Higher-level drivers usually do not have StartIo routines, but they can.


Driver Entry Points in Driver Objects

A kernel-mode driver must specify the following entry points in its driver object:

  • At least one dispatch routine's entry point, in order to get IRPs requesting PnP, power, and I/O operations.
  • The entry point of its AddDevice routine, at DriverObject –> DriverExtension –> AddDevice.
  • The entry point of its StartIo routine, if it manages its own queue of IRPs.
  • If the driver can be loaded and/or replaced dynamically, an Unload entry point in order to free any system resources, such as system objects or memory, that the driver has allocated. (Drivers that cannot be replaced while the system is running, such as a keyboard driver, need not supply an Unload routine.)

These requirements do not apply to some miniport drivers, for which the corresponding class or port driver defines the entry points in the driver object. See the device-type-specific documentation for details.

The I/O Manager maintains information about driver-created device objects in the corresponding driver object.

When a driver is loaded, its DriverEntry routine is called with a pointer to the driver object. When a driver's DriverEntry routine is called, it sets Dispatch, StartIo (if any), and Unload (if any) entry points directly in the driver object as follows:

DriverObject->MajorFunction[IRP_MJ_xxx] = DDDispatchXxx;
              :    :
DriverObject->MajorFunction[IRP_MJ_yyy] = DDDispatchYyy;
              :    :
DriverObject->DriverStartIo = DDStartIo;
DriverObject->DriverUnload = DDUnload;
              :    :

The DriverEntry routine also sets the entry point of its AddDevice routine, in the DriverExtension of its driver object, as follows:

DriverObject->DriverExtension->AddDevice = DDAddDevice;

A DriverEntry or optional Reinitialize routine also can use a field in the driver object (not shown in the Driver Object figure) to get information from and/or set information in the Configuration Manager's registry database. For more information, see Driver Information in the Registry.

The I/O Manager exports no support routines to manipulate driver objects, which are DRIVER_OBJECT structures. Driver objects are used by the I/O Manager to keep track of currently loaded drivers. Some members of a driver object are used only by the I/O Manager. Others members are also used by driver writers; for example, you must know certain member names to define AddDevice, Dispatch, StartIo, and Unload entry points. You should neither attempt to use undocumented members within a DRIVER_OBJECT structure, nor make assumptions about the locations of any driver object members that are named in this documentation. Otherwise, you cannot maintain the portability of a driver from one Windows platform to another.


Other Standard Driver Routines

As the Driver Object figure shows, kernel-mode drivers have other standard routines along with those for which they set entry points in their respective driver objects. Most standard driver routines and some of the configuration-dependent objects they use are defined by the I/O Manager. The ISR, SynchCritSection routine, and those shown in the Driver Object figure with names containing the word "custom" are defined by the NT Kernel.

Most drivers use the device extension of each device object they create to maintain device-specific state about their I/O operations and to store pointers to any system resources that they must allocate in order to have other standard routines. For example, the DDCustomTimerDpc routine shown in the Driver Object figure requires the driver to supply storage for Kernel-defined timer and DPC objects.

The set of standard driver routines for lowest-level drivers shown on the left in the Driver Object figure is necessarily different from the set for higher-level drivers. Some of the routines shown in this figure are device-dependent or configuration-dependent requirements. Others are optional: you may choose to implement such a routine depending on the nature or configuration of the driver's devices, on the driver's design, and on the driver's position in a chain of layered drivers.


Writing a DriverEntry Routine

Each driver must have a DriverEntry routine, which initializes driver-wide data structures and resources. The I/O Manager calls the DriverEntry routine when it loads the driver.

In a driver that supports Plug and Play (PnP), as all drivers should, the DriverEntry routine is responsible for driver initialization, while the AddDevice routine (and, possibly, the dispatch routine that handles a PnP IRP_MN_START_DEVICE request) is responsible for device initialization. Driver initialization includes exporting the driver's other entry points, initializing certain objects the driver uses, and setting up various per-driver system resources. (Legacy, non-PnP drivers have significantly different requirements, as described in the DDK for Windows NT® 4.0 and earlier.)

DriverEntry routines are called in the context of a system thread at IRQL = PASSIVE_LEVEL.

A DriverEntry routine can be pageable and should be in an INIT segment so it will be discarded.

This section contains the following topics:

DriverEntry's Required Responsibilities

DriverEntry's Optional Responsibilities

DriverEntry Return Values


DriverEntry's Required Responsibilities

The required, ordered responsibilities of a DriverEntry routine are as follows:

  1. Supply entry points for the driver's standard routines.

    The driver stores entry points for many of its standard routines in the driver object or driver extension. Such entry points include those for the driver's AddDevice routine, dispatch routines, StartIo routine, and Unload routine. For example, a driver would set the entry points for its AddDevice, DispatchPnP, and DispatchPower routines with statements like the following (Xxx is a placeholder for a vendor-supplied prefix identifying the driver):

        :
DriverObject->DriverExtension->AddDevice = XxxAddDevice;
DriverObject->MajorFunction[IRP_MJ_PNP] = XxxDispatchPnp;
DriverObject->MajorFunction[IRP_MJ_POWER] = XxxDispatchPower;
    :

    Additional standard routines, such as ISRs or IoCompletion routines, are specified by calling system support routines. For more information, see the descriptions of individual standard driver routines.

  2. Create and/or initialize various driver-wide objects, types, or resources the driver uses. Note that most standard routines use objects on a per-device basis, so drivers should set up such objects in their AddDevice routines or after receiving an IRP_MN_START_DEVICE request.

    If the driver has a device-dedicated thread or waits on any Kernel-defined dispatcher objects, the DriverEntry routine might initialize kernel dispatcher objects. (Depending on how the driver uses the object(s), it might instead perform this task in its AddDevice routine or after receiving an IRP_MN_START_DEVICE request.)

  3. Free any memory that it allocated and is no longer required.
  4. Return NTSTATUS indicating whether the driver successfully loaded and can accept and process requests from the PnP Manager to configure, add, and start its devices. (See DriverEntry Return Values.)


DriverEntry's Optional Responsibilities

Depending on the position of a particular driver in a chain of layered drivers, the nature of the underlying device, and the design of the driver, a DriverEntry routine also can be responsible for the following:

  • Calling IoAllocateDriverObjectExtension to create and initialize a driver object extension, if the driver requires storage for data on a driver-wide basis. The driver object extension is a driver-specific data structure. For example, a driver might use its driver object extension to store a registry path or other global information.
  • Calling PsCreateSystemThread to create executive worker threads, if the driver is a highest-level driver (such as a file system driver) that uses such threads. In this case, the driver must also have a callback routine of type WORKER_THREAD_ROUTINE, which takes a single input PVOID Parameter.
  • Registering a Reinitialize routine. (See Writing a Reinitialize Routine.)
  • Handling class-specific initialization requirements that differ from those discussed here, such as those that a device-specific miniport or miniclass driver working in tandem with a port or class driver might have. See the device-type specific documentation in this DDK for details.

Providing Storage for System Resources

Per-device objects should be allocated in the AddDevice routine or in the Dispatch routine that handles the PnP IRP_MN_START_DEVICE request, not in DriverEntry.

However, a driver might need to allocate additional system-space memory for other driver-wide uses. If so, the DriverEntry routine can call one (or more) of the following routines:

  • IoAllocateDriverObjectExtension, to create a context area associated with the driver object
  • ExAllocatePool for paged or nonpaged system-space memory
  • MmAllocateNonCachedMemory or MmAllocateContiguousMemory for cache-aligned nonpaged system-space memory (used for I/O buffers)

Every DriverEntry routine is run in the context of a system thread at IRQL = PASSIVE_LEVEL. Therefore, any memory allocated with ExAllocatePool for use exclusively during initialization can be from paged pool, as long as the driver does not control the device that holds the system page file. The allocated memory must be released with ExFreePool before DriverEntry returns control. However, a driver that sets a Reinitialize routine can pass a pointer to this memory when it calls IoRegisterDriverReinitialization, thus making the driver's Reinitialize routine responsible for freeing the memory allocation.

Claiming Hardware Resources

Older, non-PnP drivers claimed resources from the registry. PnP drivers, on the other hand, neither claim device resources from nor directly write resource requirements to the registry. Instead, these drivers report requirements in response to certain PnP IRPs, as part of the PnP Manager's enumeration process. A PnP driver receives its allocated resources in a PnP IRP_MN_START_DEVICE request.

Drivers that do not interact directly with the PnP Manager, such as certain miniport drivers, might have different reporting requirements imposed by a class or port driver that does interact with the PnP Manager. Such requirements are specific to the device class. For device-specific and class-specific details, see the documentation for the relevant device class in this DDK.

Using the Registry

A DriverEntry routine might use the registry to get some of the information it needs to initialize the driver, or it might set information in the registry for other drivers or protected subsystems to use. The nature of the information depends on the type of device. Drivers can access the registry using Zw Xxx and Rtl Xxx routines. The DriverEntry routine's RegistryPath parameter points to a counted Unicode string that specifies a path to the driver's registry key, \Registry\Machine\System\CurrentControlSet\Services\DriverName. The routine should save a copy of the string, not the pointer itself, since the pointer is no longer valid after DriverEntry returns.


DriverEntry Return Values

A DriverEntry routine returns an NTSTATUS value, either STATUS_SUCCESS or an appropriate error status.

The DriverEntry routine should postpone any call to IoRegisterDriverReinitialization until just before it returns STATUS_SUCCESS. It must not make this call unless it will return STATUS_SUCCESS.

If a DriverEntry routine returns something other than STATUS_SUCCESS, that driver does not remain loaded.

A DriverEntry routine that will fail initialization must free any system objects, system resources, and registry resources it has already set up before it returns control. It should reset the driver's dispatch entry points in the driver object for IRP_MJ_FLUSH_BUFFERS and IRP_MJ_SHUTDOWN to NULL if the driver supports these requests.

If a driver will fail initialization, the DriverEntry routine also should log an error before returning control. See Logging Errors.

Note that a driver's Unload routine is not called if a driver's DriverEntry routine returns a failure status.


Writing a Reinitialize Routine

Any driver that needs to initialize itself in stages can contain a Reinitialize routine. A Reinitialize routine is called after the DriverEntry routine has returned control and other drivers have initialized themselves . Typically, the Reinitialize routine performs tasks that must be done after another driver starts.

For example, the system's keyboard class driver, kbdclass, supports both PnP and legacy keyboard ports. If a system includes one or more legacy ports that the PnP Manager cannot detect, the keyboard class driver must nevertheless create a device object for each port and layer itself over lower-level drivers for the port. Consequently, the class driver has a Reinitialize routine to be called after its DriverEntry and AddDevice routines have been called and other drivers have been loaded. The Reinitialize routine detects the port, creates a device object for it, and layers the driver over other lower-level drivers for the device.

A driver's DriverEntry routine calls IoRegisterDriverReinitialization to queue a Reinitialize routine for execution. The Reinitialize routine can also call IoRegisterDriverReinitialization itself, which causes the routine to be re-queued. One of the parameters to Reinitialize indicates the number of times it has been called.

The call to IoRegisterDriverReinitialization can include a pointer to driver-defined context data, which the system supplies as input to Reinitialize. If the Reinitialize routine uses the registry, the context data should include the RegistryPath pointer that was passed to the DriverEntry routine because this pointer is not an input parameter to the Reinitialize routine.

The Reinitialize routine will not be called if DriverEntry does not return STATUS_SUCCESS.

Usually, a driver with a Reinitialize routine is a higher-level driver that controls both PnP and legacy devices. In addition to creating device objects for the devices that the PnP Manager detects (and for which the PnP Manager calls the driver's AddDevice routine), the driver must also create device objects for legacy devices that the PnP Manager does not enumerate. The Reinitialize routine creates those device objects and layers the driver over the next-lower driver for the underlying device.

If a driver has a Reinitialize routine, it initializes in the same basic steps described in Writing a DriverEntry Routine, and it also has the same basic requirements as its DriverEntry routine.


Writing an AddDevice Routine

Any driver that supports PnP must have an AddDevice routine. The AddDevice routine creates one or more device objects representing the physical, logical, or virtual devices for which the driver carries out I/O requests. It also attaches the device object to the device stack, so the device stack will contain a device object for each driver associated with the device.

The PnP Manager calls a driver's AddDevice routine for each device controlled by the driver. AddDevice routines are called during system initialization (when devices are first enumerated), and any time a new device is enumerated while the system is running.

This section contains the following topics:

AddDevice Routines in Function or Filter Drivers

AddDevice Routines in Bus Drivers

Guidelines for Writing AddDevice Routines


AddDevice Routines in Function or Filter Drivers

An AddDevice routine in a function or filter driver should take the following steps:

  1. Call IoCreateDevice to create a functional or filter device object (an FDO or filter DO) for the device being added.

    Do not specify a DeviceName for the device object, because doing so bypasses the PnP Manager's security. If a user-mode component needs a symbolic link to the device, register a device interface (see the next step below). If a kernel-mode component needs a legacy device name, the driver must name the device object, but naming is not recommended.

    Include FILE_DEVICE_SECURE_OPEN in the DeviceCharacteristics parameter. This characteristic directs the I/O Manager to perform security checks against the device object for all open requests, including relative opens and trailing file name opens.

  2. [optional] Create one or more symbolic links to the device.

    Call IoRegisterDeviceInterface to register device functionality and create a symbolic link that applications or system components can use to open the device. The driver should enable the interface by calling IoSetDeviceInterfaceState when it handles the IRP_MN_START_DEVICE request. For more information, see Device Interface Classes.

  3. Store the pointer to the device's PDO in the device extension.

    The PnP Manager supplies a pointer to the PDO as the PhysicalDeviceObject parameter to AddDevice. Drivers use the PDO pointer in calls to routines such as IoGetDeviceProperty.

  4. Define flags in the device extension to track certain PnP states of the device, such as device paused, removed, and surprise-removed.

    For example, define one flag to indicate that incoming IRPs should be held while the device is in a paused state. Create a queue for holding IRPs, if the driver does not already have a mechanism for queuing IRPs. See Queuing and Dequeuing IRPs for more information.

    Also allocate an IO_REMOVE_LOCK structure in the device extension and call IoInitializeRemoveLock to initialize this structure.

  5. Set the DO_POWER_INRUSH or DO_POWER_PAGABLE flag for power management, if necessary. Drivers that are pageable must set the DO_POWER_PAGABLE flag. The device object flags are typically set by the bus driver when it creates the PDO for the device. However, higher-level drivers may occasionally need to alter the values of these flags in their AddDevice routines when they create the FDO or filter DO. See Setting Device Object Flags for Power Management for details.
  6. Create and/or initialize any other software resources the driver uses to manage this device, such as events, spin locks, or other objects. (Hardware resources, such as I/O ports, are configured later, in response to an IRP_MN_START_DEVICE request.)

    Because an AddDevice routine runs in a system thread context at IRQL = PASSIVE_LEVEL, any memory allocated with ExAllocatePool for use exclusively during initialization can be from paged pool, as long as the driver does not control the device that holds the system page file. Such a memory allocation must be released with ExFreePool before AddDevice returns control.

  7. Attach the device object to the device stack (IoAttachDeviceToDeviceStack).

    Specify a pointer to the device's PDO in the TargetDevice parameter.

    Store the pointer returned by IoAttachDeviceToDeviceStack. This pointer, which points to the device object of the next-lower driver for the device, is a required parameter to IoCallDriver and PoCallDriver when passing IRPs down the device stack.

  8. Clear the DO_DEVICE_INITIALIZING flag in the FDO or filter DO with a statement like the following:
    FunctionalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  9. Be prepared to handle PnP IRPs for the device (such as IRP_MN_QUERY_RESOURCE_REQUIREMENTS and IRP_MN_START_DEVICE).

A driver must not start controlling the device until it receives an IRP_MN_START_DEVICE containing the list of hardware resources assigned to the device by the PnP Manager.


AddDevice Routines in Bus Drivers

A PnP bus driver has an AddDivice routine, but it is called when the bus driver is acting as the function driver for its controller or adapter. For example, the PnP Manager calls the USB Hub bus driver's AddDevice routine to add the hub device. The hub driver's AddDevice routine is not called for a child of the hub (a device that plugs into the hub).


Guidelines for Writing AddDevice Routines

Consider the following design guidelines when writing an AddDevice routine:

  • If a filter driver determines its AddDevice routine was called for a device it does not need to service, the filter driver must return STATUS_SUCCESS to allow the rest of the device stack to be loaded for the device. The filter driver does not create a device object nor attach it to the device stack; the filter driver just returns success and allows the rest of the drivers to be added to the stack.
  • A driver must provide storage, usually in the device extension of a device object, for any Kernel-defined objects and executive spin locks it uses. A driver also must provide storage for pointers to certain objects obtained from the I/O Manager or other system components.

    You might decide to allocate additional system-space memory for the driver's needs, such as for long-term I/O buffers or a lookaside list. If so, an AddDevice routine can call the following routines:

    • ExAllocatePool for paged or nonpaged system-space memory
    • ExInitializePagedLookasideList or ExInitializeNPagedLookasideList to initialize a paged or nonpaged lookaside list
  • If the driver has a device-dedicated thread or waits on any Kernel-defined dispatcher objects, the AddDevice routine might initialize kernel dispatcher objects.
  • If the driver uses any executive spin locks or provides the storage for an interrupt spin lock, the AddDevice routine might initialize these spin locks. See Spin Locks for more information.
  • Tighten file-open security when calling IoCreateDevice.

    Specify the FILE_DEVICE_SECURE_OPEN characteristic on the call to IoCreateDevice. This characteristic is supported on Windows NT® 4.0 SP5 and later. It directs the I/O Manager to perform security checks against the device object for all open requests. Vendors should specify this characteristic on calls to IoCreateDevice if the FILE_DEVICE_SECURE_OPEN characteristic is not set in the device's class-installer INF or the device's INF and the drivers do not perform their own security checks on opens. (For more information, see Tightening File-Open Security in a Device INF File.)

    If a driver sets the FILE_DEVICE_SECURE_OPEN characteristic when it calls IoCreateDevice, the I/O Manager applies the security descriptor of the device object to any relative opens or trailing-filename opens. For example, if FILE_DEVICE_SECURE_OPEN is set for \Device\foo, and if \Device\foo can only be opened by the administrator, then \Device\foo\abc can also be opened by the administrator. The I/O Manager, however, prevents a normal user from opening \Device\foo and \Device\foo\abc.

    If one driver for a device sets this characteristic, the PnP Manager propagates it to all the device objects for the device.


Writing Dispatch Routines

Processing any IRP begins in a dispatch routine that the DriverEntry routine supplies to handle a major I/O function code (IRP_MJ_XXX). The DriverEntry routine exports entry points for dispatch routines in a dispatch table within the driver's DRIVER_OBJECT structure.

A driver can provide a separate dispatch routine for each major I/O function code that it handles. Alternatively, dispatch routines can be written to handle multiple I/O function codes.


Dispatch Routine Functionality

The required functionality of a particular dispatch routine varies, depending on the I/O function code it handles, on the individual driver's position in a chain of drivers, and on the type of underlying physical device.

Most dispatch routines process incoming IRPs as follows:

  1. Check the driver's I/O stack location in the IRP to determine what to do and check the parameters, if any, for validity.

    Whether a driver must check its I/O stack location to determine what to do and to check parameters depends on the given IRP_MJ_XXX, as well as on whether that driver set up a separate Dispatch routine for each IRP_MJ_XXX that the driver handles.

  2. Satisfy the request and complete the IRP if possible; otherwise, pass it on for further processing by lower-level drivers or by other device driver routines.

    Whether a driver must pass on an IRP for further processing depends on the validity of the parameters, if any, as well as on the IRP_MJ_XXX and on the driver's level, if any, in a chain of layered drivers.


Required Dispatch Routines

Most drivers must handle the following Dispatch routines:

  • DispatchPnP

    IRP_MJ_PNP indicates a request involving PnP device recognition, hardware configuration, or resource allocation. Such requests are typically sent to a device driver from the PnP Manager or from a closely coupled higher-level driver.

  • DispatchPower

    IRP_MJ_POWER indicates a request pertaining to the power state of either the device or the system. Such requests are sent to the device driver by either the Power Manager or a closely coupled higher-level driver.

  • DispatchCreate

    IRP_MJ_CREATE indicates either that a user-mode protected subsystem, possibly on behalf of an application or subsystem-specific driver, has requested a handle for the file object associated with the target device object, or that a higher-level driver is connecting or attaching its device object to the target device object.

  • DispatchCleanup

    IRP_MJ_CLEANUP indicates that the handle for the file object, representing the target device object, is being closed, so any IRPs currently queued to the target device for the given file object, found in the driver's I/O stack location of the cleanup IRP, should be cancelled.

  • DispatchClose

    IRP_MJ_CLOSE indicates that the handle of the file object that represents the target device object or a pointer to the target device object has been closed and that there are no outstanding references to the file object pointer.

  • DispatchRead

    IRP_MJ_READ indicates an I/O request to transfer data from the underlying physical device to the system.

  • DispatchWrite

    IRP_MJ_WRITE indicates an I/O request to transfer data from the system to the underlying physical device.

  • DispatchDeviceControl

    IRP_MJ_DEVICE_CONTROL indicates a request that contains a system-defined, device-type-specific I/O control code specifying a device type-specific operation. Higher-level drivers pass these IRPs on to their underlying device drivers, which typically process the request by accessing the device.

  • DispatchInternalDeviceControl

    IRP_MJ_INTERNAL_DEVICE_CONTROL indicates a request sent to the device driver, in most cases from a closely coupled higher-level driver, usually with a privately defined, driver-specific and device-type-specific or device-specific I/O control code requesting a device-type-specific or device-specific operation.

    Only certain kinds of drivers are required to handle system-defined internal device I/O control requests, including certain SCSI drivers, keyboard or mouse device drivers, and parallel drivers that interoperate with system-supplied drivers.

  • DispatchSystemControl

    IRP_MJ_SYSTEM_CONTROL is used to specify WMI requests to drivers. For more information about WMI, see Windows Management Instrumentation.

The dispatch routines that a driver must provide vary according to the type and functionality of the underlying physical device. For device-type-specific information about IRP major function codes that drivers must handle, see the device-type specific documentation in this DDK.


Optional Dispatch Routines

Drivers might include the following dispatch routines:

  • DispatchQueryInformation, DispatchSetInformation

    Some highest-level drivers might have to process IRP_MJ_QUERY_INFORMATION and IRP_MJ_SET_INFORMATION IRPs. Such requests indicate that a user-mode application, kernel-mode component, or driver has requested information about the length of the file object (representing the driver's device object) for which the user-mode requester has a handle, or that the user-mode requester is attempting to set an end-of-file on that file object.

    Parallel class and serial device drivers handle these requests by setting the FILE_STANDARD_INFORMATION or FILE_POSITION_INFORMATION length or position to zero. Other highest-level device drivers should support these requests, particularly if a user-mode application or kernel-mode driver might call C runtime functions to manipulate the file object. File system drivers must support these requests more fully than these highest-level device drivers.

  • DispatchFlushBuffers

    A driver that caches data in a device or buffers data internally in driver-allocated memory might receive IRP_MJ_FLUSH_BUFFERS. Receipt of this request indicates that the driver should write its buffered data or flush the cached data out to the device, or should discard buffered or cached data that was read from the device.

    For example, the system keyboard and mouse class drivers, which have internal ring buffers for input data from their devices, support the flush request. Drivers of mass-storage devices and drivers layered above them also support this request.

  • DispatchShutdown

    Any driver that is likely to be called before the system shuts down must handle IRP_MJ_SHUTDOWN. The DispatchShutdown routine should do whatever driver-determined cleanup is necessary before the Power Manager sends a system set-power IRP to shut down the system. If the underlying device is not a mass-storage device, a driver can call IoRegisterShutdownNotification to register for showdown notification.

Drivers for mass-storage devices and intermediate drivers layered over them can rely on a highest-level file system driver to send them shutdown IRPs when the system is about to shut down. That is, the FSD is responsible for making sure that any cached file data is written out to peripheral devices, calling underlying drivers to flush data from their device caches or buffers (if any), and so forth before the system is shut down.

The driver of a mass-storage device that caches data internally must provide DispatchShutdown and DispatchFlushBuffers routines. If a mass-storage driver buffers data in memory but its device has no internal cache, it also must provide DispatchShutdown and DispatchFlushBuffers routines.

Any intermediate driver layered above a driver that handles IRP_MJ_FLUSH and IRP_MJ_SHUTDOWN requests also provide DispatchShutdown and DispatchFlushBuffers routines.


Dispatch Routines and IRQLs

Most drivers' dispatch routines are called in an arbitrary thread context at IRQL = PASSIVE_LEVEL, with the following exceptions:

  • Any highest-level driver's dispatch routines are called in the context of the thread that originated the I/O request, which is commonly a user-mode application thread.

    In other words, the dispatch routines of file system drivers and other highest-level drivers are called in a nonarbitrary thread context at IRQL = PASSIVE_LEVEL.

  • The DispatchRead, DispatchWrite, and DispatchDeviceControl routines of lowest-level device drivers, and of intermediate drivers layered above them in the system paging path, can be called at IRQL = APC_LEVEL and in an arbitrary thread context.

    The DispatchRead and/or DispatchWrite routines, and any other routine that also processes read and/or write requests in such a lowest-level device or intermediate driver, must be resident at all times. These driver routines can neither be pageable nor be part of a driver's pageable-image section; they must not access any pageable memory. Furthermore, they should not be dependent on any blocking calls (such as KeWaitForSingleObject with a nonzero time-out).

  • The DispatchPower routine of drivers in the hibernation and/or paging paths can be called at IRQL DISPATCH_LEVEL. The DispatchPnP routines of such drivers must be prepared to handle PnP IRP_MN_DEVICE_USAGE_NOTIFICATION requests.
  • The DispatchPower routine of drivers that require inrush power at start-up can be called at IRQL DISPATCH_LEVEL.

For additional information, see Managing Hardware Priorities.


When to Check the Driver's I/O Stack Location

A major I/O function code is set in the driver's I/O stack location for each incoming IRP.

A driver's dispatch routine must check the driver's I/O stack location for the IRP to determine what to do if any of the following conditions hold:

  • The dispatch routine handles more than one major I/O function code.
  • The dispatch routine must handle a set of minor function codes for certain major function codes. IRPs with minor function codes include IRP_MJ_PNP and IRP_MJ_POWER, as well as certain IRPs that the SCSI port driver and file system drivers must handle.
  • The dispatch routine of a device driver or of a closely coupled higher-level driver handles IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL requests, which have an associated set of I/O control codes.

To get a pointer to a driver's I/O stack location, its dispatch routine calls IoGetCurrentIrpStackLocation.

Higher-level drivers' dispatch routines always call IoGetCurrentIrpStackLocation and also call IoGetNextIrpStackLocation to get a pointer to the next-lower driver's I/O stack location for IRPs that they set up for the next-lower driver, when passing IRPs down the driver stack.

The DispatchDeviceControl routine or DispatchInternalDeviceControl routine of a device driver, or possibly of its closely coupled class driver(s), must determine which I/O control code is set in the driver's I/O stack location at Parameters.DeviceIoControl.IoControlCode for each request. The I/O control code is contained in the driver's I/O stack location.

In most cases, the DispatchDeviceControl or DispatchInternalDeviceControl routine of a higher-level driver simply passes an IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL request on to the next-lower driver, after setting up its stack location in the IRP. However, SCSI class drivers must check for certain SCSI port I/O control codes so that they can set up the SCSI port driver's I/O stack location correctly before passing on these requests.


DispatchCreate, DispatchClose, and DispatchCreateClose Routines

A driver's DispatchCreate and DispatchClose routines handle IRPs with I/O function codes of IRP_MJ_CREATE and IRP_MJ_CLOSE, respectively. Alternatively, a combined DispatchCreateClose routine can handle IRPs for both of these I/O function codes.

A create request can originate either from a user-mode subsystem's attempt to get a handle to a file object representing a device (possibly on behalf of an application or subsystem-level driver) or in a higher-level driver's call to IoGetDeviceObjectPointer or IoAttachDevice.

A reciprocal close request originates from a user-mode subsystem's close of the file object handle associated with the driver's device object.

Each of these requests is inherently synchronous.


Separate DispatchCreate and DispatchClose Routines

A driver's Dispatch routines for IRP_MJ_CREATE and IRP_MJ_CLOSE requests might do nothing more than complete the input IRP with STATUS_SUCCESS. For more information, see Completing IRPs.

Another driver's Dispatch routines for IRP_MJ_CREATE and IRP_MJ_CLOSE requests might do more work, depending on the underlying device driver or on the underlying device. Consider the following scenarios:

  • On receipt of a create request, a class driver might initialize an internal queue and send an IRP_MJ_INTERNAL_DEVICE_CONTROL request down to the corresponding port driver requesting device configuration information or exclusive access to a controller port.
  • On receipt of a close request, a highest-level driver might need to delay until it has completed device I/O processing for all outstanding IRPs currently queued to the target device object.
  • On receipt of a create request, a driver of an infrequently used device might call MmLockPagableCodeSection to make resident some of the driver routines that process other IRP_MJ_XXX requests. On receipt of a reciprocal close request, the driver might call MmUnlockPagableImageSection to conserve system memory by having its pageable-image section paged out when all file object handles for such a driver's device object(s) are closed.

Some drivers handle IRP_MJ_CLOSE requests only for symmetry because, after their device objects have been opened by a protected subsystem or higher-level driver, the lower-level drivers' device objects are not closed until the system itself is shut down. For example, keyboard and mouse drivers set up device objects representing physical devices that must be functional while the system is running, so these drivers might have minimalist DispatchClose routines for symmetry or combined DispatchCreateClose routines.

If the device controlled by a lower-level driver must be available for the system to continue running, the driver's DispatchClose routine generally will not be called. For example, some of the system disk drivers have no DispatchClose routine, but these drivers usually have DispatchFlushBuffer and DispatchShutdown routines to complete any outstanding file I/O operations before the system is shut down.

While you can implement separate DispatchCreate and DispatchClose routines, drivers sometimes have a single DispatchCreateClose routine for handling both create and close requests.


A Single DispatchCreateClose Routine

Many drivers, particularly lower-level drivers in a chain of layered drivers, merely need to establish their existence on receipt of a create request and merely need to acknowledge the receipt of a close request.

For example, a port driver for a device controller with one or more closely coupled class drivers that call IoGetDeviceObjectPointer might have a minimal DispatchCreateClose routine. The routine might do nothing more than complete the IRP as follows:

    :    :
{
    Irp->IoStatus.Status = STATUS_SUCCESS;
    Irp->IoStatus.Information = 0;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);
    return STATUS_SUCCESS;
}

This minimal DispatchCreateClose routine sets the Information member of the I/O status block to zero, indicating the file object is opened for a create request; Information has no meaning for a close request. The routine sets the Status member to STATUS_SUCCESS and also returns this status value, indicating that the driver is ready to accept I/O requests.

This minimal DispatchCreateClose routine completes the create IRP without boosting the priority of the originator of the IRP (IO_NO_INCREMENT), because the originator is assumed to wait for an indeterminate but very small interval for the request to complete.

How much work a DispatchCreateClose routine does depends partly on the nature of the driver's device or the underlying device and partly on the design of the driver. If a driver performs very different operations for create and close requests, it should handle these requests in separate DispatchCreate and DispatchClose routines.

To handle a create request to open a file object representing a logical or physical device, a highest-level driver should do the following:

  1. Call IoGetCurrentIrpStackLocation to get a pointer to its I/O stack location in the IRP.
  2. Check FileObject.FileName in the I/O stack location and complete the IRP with STATUS_SUCCESS if the Unicode string at FileName has a zero length; otherwise, complete the IRP with STATUS_INVALID_PARAMETER.

Following the preceding steps ensures that no attempt to open a pseudo-file on a device can cause problems later. For example, this prevents attempts to open a nonexistent \\device\parallel0\temp.dat.


Rules for Implementing DispatchCreate, DispatchClose, and DispatchCreateClose Routines

Keep the following points in mind when implementing DispatchCreate, DispatchClose, and DispatchCreateClose routines:

  • At a minimum, the routine must do the following:
    1. Set the Status field of the input IRP's I/O status block with an appropriate NTSTATUS, usually STATUS_SUCCESS.
    2. Set the Information field of the input IRP's I/O status block to zero.
    3. Call IoCompleteRequest with the IRP and a PriorityBoost of IO_NO_INCREMENT.
    4. Return the NTSTATUS that it set in the Status field of the IRP's I/O status block.
  • In a highest-level or intermediate driver, the routine might have to do additional work to process a create or close request, depending on the nature of its device or of the underlying device, and on the design of the driver.
  • For a create request to open a file object that represents a logical or physical device, a highest-level driver should check the FileObject.FileName in the I/O stack location and complete the IRP with STATUS_SUCCESS if the Unicode string at FileName has a zero length. Otherwise, it should complete the IRP with STATUS_INVALID_PARAMETER.
  • The routines of lowest-level drivers are called only when the next-higher-level driver calls IoAttachDeviceToDeviceStack, IoGetDeviceObjectPointer, or IoAttachDevice. The lowest-level driver in a chain of layered drivers frequently does only the minimum required processing of a create or close request.


DispatchCleanup Routines

A driver's DispatchCleanup routine handles IRPs for the IRP_MJ_CLEANUP I/O function code.

Any driver in which IRPs can be held for an indefinite interval should have a DispatchCleanup routine. If IRPs might be queued when a user-mode handle for a file object that represents the underlying physical or logical device is closed, the highest-level driver holding IRPs bound for that device must have a DispatchCleanup routine.

A driver's DispatchCleanup routine should cancel all IRPs that are currently queued to the target device object associated with the file object that is specified in the driver's I/O stack location.

In general, a DispatchCleanup routine must process an IRP_MJ_CLEANUP request by doing the following for every IRP currently in the device queue (or in the driver's internal queue of IRPs) for the target device object and given file object:

  • Call IoSetCancelRoutine to set the Cancel routine pointer to NULL.
  • Cancel every IRP currently in the queue for the target device object and the file object specified in the driver's I/O stack location.
  • Call IoCompleteRequest to complete the IRP, and return STATUS_SUCCESS.

The DispatchCleanup routine must set up the I/O status block as follows in each IRP queued to the target device object for the given file object, before it completes each IRP to be canceled:

Status | set to STATUS_CANCELLED
Information | set to zero

The DispatchCleanup routine specifies IO_NO_INCREMENT when it calls IoCompleteRequest for each canceled IRP. After it has canceled all queued IRPs for the given file object, the DispatchCleanup routine completes the cleanup request itself with STATUS_SUCCESS and a PriorityBoost of IO_NO_INCREMENT.

If a driver manages its own internal queue of IRPs, rather than using the device queue associated with its device object, the driver should set up an interlocked queue that is protected with an executive spin lock. Otherwise, another driver routine (running on another processor in an SMP machine) might dequeue an IRP that should be canceled by the DispatchCleanup routine. To remove an IRP from such a queue and cancel it, the DispatchCleanup routine calls an ExInterlocked..List support routine with a driver-supplied executive spin lock.

Any area in the device extension of the target device object that is shared between the DispatchCleanup routine and another driver routine also must be protected by a spin lock.

Each driver must synchronize its access to cancelable IRPs with the I/O Manager and with its own Cancel routines, if any.

Consider the following guidelines for managing spin locks within a DispatchCleanup routine that must synchronize with one or more Cancel routines:

  • If the DispatchCleanup routine must acquire both the system cancel spin lock and one or more of the driver's own spin locks, it should call IoAcquireCancelSpinLock before it acquires its own spin locks.

    The DispatchCleanup routine must release any nested spin lock acquisitions in inverse order: that is, it must release its own spin locks before it calls IoReleaseCancelSpinLock.

  • If a driver uses the I/O-manager-supplied device queue in the device object, then its DispatchCleanup routine must call IoAcquireCancelSpinLock before it calls IoSetCancelRoutine to reset the Cancel entry point in an IRP to NULL.

    If a driver manages its own queues of IRPs, then the DispatchCleanup routine should usually acquire the cancel spin lock before calling IoSetCancelRoutine. See Canceling IRPs for additional information.

  • The DispatchCleanup routine must release every spin lock it is holding before it calls IoCompleteRequest with an IRP, including each IRP that it cancels.


DispatchRead, DispatchWrite, and DispathReadWrite Routines

A driver's DispatchRead and DispatchWrite routines handle IRPs with I/O function codes of IRP_MJ_READ and IRP_MJ_WRITE, respectively. Alternatively, a combined DispatchReadWrite routine can handle IRPs for both of these I/O function codes.

Every driver of a device from which data can be transferred to the system must have a DispatchRead routine. Every driver of a device to which data can be transferred from the system must have a DispatchWrite routine. Any driver that transfers data in both directions can have a combined DispatchReadWrite routine.

Lower-level drivers handle IRP_MJ_READ and IRP_MJ_WRITE requests asynchronously. Therefore, DispatchRead and/or DispatchWrite routines in highest-level drivers must pass these requests on for further processing, provided that the request has valid parameters in that driver's I/O stack location of the IRP.

Whether a driver sets up its device objects for buffered or direct I/O affects how it handles transfer requests. In particular, a driver that uses direct I/O to do DMA operations might need to split up large transfer requests into a sequence of smaller transfer operations in order to satisfy an IRP_MJ_READ or IRP_MJ_WRITE request. For more information, see Input/Output Techniques.

The following subsections discuss some of the design and implementation considerations for DispatchReadWrite routines in lowest-level device drivers that use buffered I/O and direct I/O, as well as in higher-level drivers layered above them.


Handling Transfers Asynchronously

Except for highest-level drivers, all drivers handle IRP_MJ_READ and IRP_MJ_WRITE requests asynchronously. The DispatchRead and DispatchWrite routines in even a highest-level driver cannot wait for lower-level drivers to finish processing an asynchronous read or write request; they must pass such a request on to lower drivers and return STATUS_PENDING.

Similarly, a lowest-level device driver's DispatchReadWrite routine must pass the transfer request on to other driver routines that process device I/O requests and then return STATUS_PENDING.

A higher-level driver sometimes must set up partial-transfer IRPs and pass them on to lower drivers. The higher-level driver can complete the original read/write IRP only when its partial-transfer requests have been completed by the lower drivers.

For example, a SCSI class driver's DispatchReadWrite routine is required to split large transfer requests that exceed the underlying HBA's transfer capabilities into a set of partial-transfer requests. The class driver must set up the parameters in its partial-transfer IRPs so that the SCSI port/miniport drivers can satisfy each partial-transfer request in a single DMA operation.

Other device drivers that use DMA or PIO also might need to split up large transfer requests for themselves.

For more information about using DMA and PIO, see Input/Output_Techniques.


DispatchReadWrite Using Buffered I/O

Any lowest-level device driver that sets up its device objects for buffered I/O satisfies a read request by returning data transferred from its device into a locked down system-space buffer at Irp->AssociatedIrp.SystemBuffer. It satisfies a write request by transferring data from the same buffer out to its device.

Consequently, the DispatchReadWrite routine of such a device driver usually does the following on receipt of a transfer request:

  1. Calls IoGetCurrentIrpStackLocation and determines the direction of the transfer request.
  2. Checks the validity of the parameters for the request.
    • For a read request, the routine usually checks the driver's IoStackLocation->Parameters.Read.Length value to determine whether the buffer is large enough to receive data transferred from the device.

      For example, the system keyboard class driver processes read requests that come only from the Win32® user input thread. This driver defines a structure, KEYBOARD_INPUT_DATA, in which to store keystrokes from the device and, at any given moment, holds some number of these structures in an internal ring buffer in order to satisfy read requests as they come in.

    • For a write request, the routine usually checks the value at Parameters.Write.Length, and checks the data at Irp->AssociatedIrp.SystemBuffer for validity if necessary: that is, if its device accepts only structured data packets containing members with defined value ranges.
  3. If any parameters are invalid, the DispatchReadWrite routine completes the IRP immediately, as already described in Completing IRPs. Otherwise, the routine passes the IRP on for further processing by other driver routines, as described in Passing IRPs Down the Driver Stack.

Lowest-level device drivers that use buffered I/O usually must satisfy a transfer request by reading or writing data of a size specified by that the originator of the request. Such a driver is likely to define a structure for data coming in from or being sent to its device and is likely to buffer structured data internally, as the system keyboard class driver does.

Drivers that buffer data internally should support IRP_MJ_FLUSH_BUFFERS requests, and can also support IRP_MJ_SHUTDOWN requests.

The highest-level driver in a chain is usually responsible for checking the input IRP's parameters before passing a read/write request on to lower drivers. Consequently, many lower-level drivers can assume that their I/O stack locations in a read/write IRP have valid parameters. If a lowest-level driver in a chain is aware of device-specific constraints on data transfers, that driver is required to check the validity of the parameters in its I/O stack location


DispatchReadWrite Using Direct I/O

Any lower-level device driver that sets up its device objects for direct I/O satisfies a read request by returning data transferred from its device to system physical memory, which is described by the MDL at Irp->MdlAddress. It satisfies a write request by transferring data from system physical memory out to its device.

Lower-level drivers must handle read/write requests asynchronously. Therefore, every lower-level driver's DispatchReadWrite routine must pass IRP_MJ_READ and IRP_MJ_WRITE IRPs with valid parameters on to other driver routines, as described in Passing IRPs Down the Driver Stack.

For read/write IRPs sent to lower-level drivers, the paged physical memory described by the MDL at Irp->MdlAddress has already been probed for the correct access rights to carry out the requested transfer and has already been locked down by the highest-level driver in the chain or by the I/O Manager. Any intermediate or lowest-level driver that sets up its device objects for direct I/O should not call MmProbeAndLockPages because this has already been done. A lowest-level non-WDM driver calls MmGetSystemAddressForMdlSafe and a lowest-level WDM driver calls MmGetSystemAddressForMdl to get mapped system virtual addresses if its device uses PIO to transfer data.

Any intermediate or lowest-level device driver's DispatchReadWrite routine should validate the parameters in its I/O stack location of read/write IRPs if it cannot trust a higher-level driver to pass down only IRPs with valid parameters. If the DispatchReadWrite routine finds a parameter error, it should complete the IRP with an appropriate error STATUS_XXX value as already described in Completing IRPs. If parameters are valid, an intermediate driver's DispatchReadWrite routine must pass the request on for further processing, according to the guidelines in DispatchReadWrite in Higher Level Drivers.

A lowest-level device driver's DispatchReadWrite routine must call IoMarkIrpPending with the transfer request, pass the IRP on for further processing by other driver routines, and return STATUS_PENDING, as described in Passing IRPs Down the Driver Stack.

Note that a device driver's DispatchReadWrite routine can control the order in which IRPs are queued to its device for faster I/O throughput by calling IoStartPacket with a driver-determined Key value. Another routine in the driver dequeues the IRP later, determines whether the requested length must be split into partial-transfer operations, and programs the device to transfer data.

In general, a device driver that must split up large transfer requests to suit the limitations of its device should postpone these operations until just before setting up the device for a given transfer request. Such a device driver's DispatchReadWrite routine should not check the I/O stack location of incoming IRPs for any device-specific transfer constraints, nor attempt to calculate partial-transfer ranges, when the driver can postpone these checks until just before its StartIo (or other driver routine) programs the device for a transfer operation.


DispatchReadWrite in Higher-Level Drivers

Except for file system drivers, a higher-level driver usually does not have any internal driver queues for IRPs. Such a driver's DispatchReadWrite routine can pass IRPs with valid parameters on to lower drivers, possibly after setting up its IoCompletion routine, as described in Passing IRPs Down the Driver Stack.

However, a SCSI class driver's DispatchReadWrite routine is responsible for splitting up large transfer requests, if necessary, before it sends an IRP with the major function code IRP_MJ_READ or IRP_MJ_WRITE to the SCSI port/miniport driver pair. For more information, see Storage Class Driver's SplitTransferRequest Routine.

If a higher-level driver allocates one or more IRPs, which it sets up for the next-lower driver in its DispatchReadWrite routine, to request some number of partial transfers, the DispatchReadWrite routine must call IoSetCompletionRoutine with each driver-allocated IRP. The driver must register its IoCompletion routine to track how much data is transferred in each partial-transfer operation so that the IoCompletion routine can release all driver-allocated IRPs and, eventually, complete the original request.

If the underlying driver controls a removable-media device, any IRPs allocated by the higher-level driver must have a thread context. To set up a thread context, the allocating driver must set the Irp->Tail.Overlay.Thread in each newly allocated IRP from the same value in the incoming transfer IRP. For more information, see Supporting Removable Media.

If the underlying device driver returns an IRP for a partial transfer with an error, the IoCompletion routine can either retry the partial-transfer request or complete the original IRP with its I/O status block set with the returned error, after freeing any IRPs and memory the higher-level driver has allocated.

If a higher-level driver's DispatchReadWrite routine allocates memory for partial-transfer operations and its allocation will be accessed by the driver's IoCompletion routine (or by the underlying device driver), the DispatchReadWrite routine must allocate that memory from nonpaged pool.


Summary of Read/Write Dispatch Routines

Keep the following points in mind when implementing a DispatchRead, DispatchWrite, or DispatchReadWrite routine:

  • It is the responsibility of the highest-level driver in a chain of layered drivers to check the parameters of incoming read/write IRPs for validity before setting up the next-lower-level driver's I/O stack location in an IRP.
  • Intermediate and lowest-level drivers generally can rely on the highest-level driver in their chain to pass down transfer requests with valid parameters. However, any driver can perform sanity checks on the parameters in its I/O stack location of an IRP, and each device driver should check the parameters for conditions that might violate any restrictions imposed by its device.
  • If a DispatchReadWrite routine completes an IRP with an error, it should set the I/O stack location Status member with an appropriate NTSTATUS-type value, set the Information member to zero, and call IoCompleteRequest with the IRP and a PriorityBoost of IO_NO_INCREMENT.
  • If a driver uses buffered I/O, it might need to define a structure to contain data to be transferred and might need to buffer some number of these structures internally.
  • If a driver uses direct I/O, it might need to check whether the MDL at Irp->MdlAddress describes a buffer containing too much data (or too many page breaks) for the underlying device to handle in a single transfer operation. If so, the driver must split up the original transfer request into a sequence of smaller transfer operations.

    A closely coupled class driver might split up such a request in its DispatchReadWrite routine for its underlying port driver. SCSI class drivers, particularly for mass-storage devices, are required to do this. For more information about requirements for SCSI drivers, see Storage Drivers.

  • A lower-level device driver's DispatchReadWrite routine should postpone splitting a large transfer request into partial transfers until another driver routine dequeues the IRP to set up the device for the transfer.
  • If a lower-level device driver queues a read/write IRP for further processing by its own routines, it must call IoMarkIrpPending before it queues the IRP. The DispatchReadWrite routine also must return control with STATUS_PENDING in these circumstances.
  • If the DispatchReadWrite routine passes an IRP on to lower drivers, it must set up the I/O stack location for the next-lower driver in the IRP. Whether the higher-level driver also sets an IoCompletion routine in the IRP before passing it on with IoCallDriver depends on the design of the driver and of those layered under it.

    However, a higher-level driver must call IoSetCompletionRoutine before it calls IoCallDriver if it allocates any resources, such as IRPs or memory. Its IoCompletion routine must free any driver-allocated resources when lower drivers have completed the request but before the IoCompletion routine calls IoCompleteRequest with the original IRP.

  • If a higher-level driver allocates IRPs for lower drivers that might include an underlying removable-media device driver, the allocating driver must establish the thread context in each IRP it allocates.


DispatchDeviceControl and DispatchInternalDeviceControl Routines

A driver's DispatchDeviceControl and DispatchInternalDeviceControl routines handle IRPs with I/O function codes of IRP_MJ_DEVICE_CONTROL and IRP_MJ_INTERNAL_DEVICE_CONTROL, respectively.

For every common type of peripheral device, the system defines a set of I/O control codes for IRP_MJ_DEVICE_CONTROL requests. New drivers for each type of device must support these requests. In most cases, these public I/O control codes for each type of device are not exported to user-mode applications.

Some of these system-defined I/O control codes are used by higher-level drivers that create IRPs for the underlying device driver by calling IoBuildDeviceIoControlRequest. Others are used by Win32® components to communicate with an underlying device driver by calling the Win32 function DeviceIoControl (described in Platform SDK documentation) which, in turn, calls a system service. The I/O Manager sets up an IRP, and stores the major function code IRP_MJ_DEVICE_CONTROL and the given I/O control code in the IO_STACK_LOCATION structure at Parameters.DeviceIoControl.IoControlCode. Then, the I/O Manager calls the DispatchDeviceControl routine of the highest-level driver in the chain.

For certain system-supplied drivers designed to interoperate with and support new drivers, the operating system also defines a set of I/O control codes for IRP_MJ_INTERNAL_DEVICE_CONTROL requests. In most cases, these public I/O control codes allow add-on higher-level drivers to interoperate with an underlying device driver.

As an example, the system-supplied parallel drivers support a set of internal I/O control codes that vendor-supplied drivers send in IRP_MJ_INTERNAL_DEVICE_CONTROL requests. For more information, see Internal Device Control Requests for Parallel Ports and Internal Device Control Requests for Parallel Devices.

Almost all operations requested through system-defined I/O control codes use buffered I/O, because this type of request seldom requires the transfer of large amounts of data. That is, even drivers that set up their device objects for direct I/O are sent IRPs for device control requests with data to be transferred into or out of the buffer at Irp->AssociatedIrp.SystemBuffer (except for certain types of highest-level device drivers with closely coupled Win32 multimedia drivers).

In addition, a driver can define a set of private I/O control codes that other drivers can use to communicate with it. New public I/O control codes can be added to the system only with the cooperation of Microsoft Corporation, because public I/O control codes are built into the operating system itself.

For specific information about the set of public I/O control codes that different kinds of drivers must support and about defining private I/O control codes, see the device-specific reference sections of this DDK.


DispatchDeviceControl in Lowest-Level Drivers

An IRP_MJ_DEVICE_CONTROL request for a lowest-level driver requires that the driver either change the state of its device or provide information about the state of its device. Because most kinds of drivers are required to handle a number of I/O control codes, their DispatchDeviceControl routines usually contain a switch statement somewhat like the following:

    :    :
switch(irpSp->Parameters.DeviceIoControl.IoControlCode) {
    case IOCTL_DeviceType_XXX:
    case IOCTL_DeviceType_YYY:
        if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
(sizeof(IOCTL_XXXYYY_STRUCTURE))) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
} else {
            IoMarkIrpPending(Irp);
     :    : // pass IRP on for further processing
    case ...
     :    :

As this code fragment shows, a DispatchDeviceControl routine also checks parameters, sometimes on each I/O control code that the driver must support, sometimes on groups of these I/O control codes.

Consider the following implementation guidelines for device drivers' DispatchDeviceControl routines:

  • DispatchDeviceControl must check the parameters for validity, and immediately complete IRPs with parameter errors, as described in Completing Irps.
  • Grouping I/O control codes in a case statement (where practical) when testing for valid parameters is economical in terms of driver performance and size and in code maintenance. As the preceding code fragment suggests, I/O control codes that use a common structure are natural candidates for such a case group.
  • Switching first on any I/O control codes for which the DispatchDeviceControl routine can satisfy and complete the IRP improves performance because the driver can return control faster.
  • Switching later on I/O control codes that specify infrequently requested operations also can improve the driver's performance in processing IRP_MJ_DEVICE_CONTROL_REQUESTS.
  • For better performance, every lowest-level device driver's DispatchDeviceControl routine should satisfy any device control request that it can, without queuing the IRP to other driver routines.

If the DispatchDeviceControl routine can complete the IRP, it should call IoCompleteRequest with a PriorityBoost of IO_NO_INCREMENT. If the DispatchDeviceControl routine must queue the IRP for further processing, it must call IoMarkIrpPending and return STATUS_PENDING.


DispatchDeviceControl in Higher-Level Drivers

Usually, the DispatchDeviceControl routine of a higher-level driver simply sets up the I/O stack location for the next-lower-level driver and passes the IRP it on with IoCallDriver. The DispatchDeviceControl routine seldom checks the validity of parameters in the input IRP because the underlying device driver is assumed to have better information about how to handle each device-type-specific I/O control request.

A possible exception to this general rule is the DispatchDeviceControl routine in the class driver of a class/port driver pair. For more information about handling device control requests in paired class/port drivers, see Dispatch(Internal)DeviceControl in Class/Port Drivers.

Any new higher-level driver that is not closely associated with a particular device driver should simply set up the I/O stack location for the next-lower-level driver and pass the IRP_MJ_DEVICE_CONTROL request on for further processing.

A device control request is usually handled synchronously. That is, a higher-level driver's DispatchDeviceControl routine can frequently return control to the system as follows:

        :    :
    return IoCallDriver(DeviceObject->NextDeviceObject, Irp);

However, a higher-level driver cannot use the preceding technique if a lower driver might return STATUS_PENDING for such a request. In that case, the higher-level driver should call IoSetCompletionRoutine to register an IoCompletion routine. When the IoCompletion routine is called, it can check the I/O status block to determine whether the IRP is still pending. If it is, the IoCompletion routine might retry the request or, possibly, call IoMarkIrpPending before it calls IoCompleteRequest and returns STATUS_PENDING. A higher-level driver must not complete an IRP with STATUS_PENDING unless it has called IoMarkIrpPending for that IRP first.

If the underlying device driver must process much data transferred from the device before it completes the request, then a higher-level driver might handle such a device control request asynchronously. That is, the higher-level driver might call IoSetCompletionRoutine to register an IoCompletion routine, pass the IRP on to lower drivers, and return control from its own DispatchDeviceControl routine.

Almost all system-defined I/O control codes require the underlying device driver to transfer only modest amounts of data, usually much less than a PAGE_SIZE amount. As a general rule, higher-level drivers should handle these requests synchronously, as shown in the preceding code fragment, because the lower drivers return control so quickly. That is, the overhead of calling the higher-level driver's IoCompletion routine does not compensate for whatever additional IRP processing that driver can get done in such a short interval.

A higher-level driver that allocates IRPs with IoBuildDeviceIoControlRequest for an underlying device driver can handle these device control requests synchronously. The higher-level driver can wait on an optional event object that is passed to IoBuildDeviceIoControlRequest and associated with the driver-allocated IRP.


Dispatch(Internal)DeviceControl in Class/Port Drivers

The higher-level driver of a class/port pair can sometimes complete IRPs in its DispatchDeviceControl routine. For example a class driver could, during initialization, gather and store information about the features of the underlying device, which might be sought in a subsequent IRP_MJ_DEVICE_CONTROL request, and thus save processing time by satisfying the request without passing it on to the underlying device driver. A class driver might also be designed to check the IRP's parameters and send only requests with valid parameters to the port driver.

Closely coupled class/port drivers also can define a set of driver-specific or device-specific internal I/O control codes that the class driver can use for IRP_MJ_INTERNAL_DEVICE_CONTROL requests to the port driver.

For example, the DispatchCreateClose routines in the system keyboard and mouse class drivers send system-defined internal device control requests to enable or disable keyboard and mouse interrupts to the underlying port drivers. These system class drivers set up IRP_MJ_INTERNAL_DEVICE_CONTROL requests for an underlying port driver. Any new keyboard or mouse port driver that interoperates with these system class drivers also must support these public internal device control requests.

The system parallel class/port driver model has similar features. New parallel class drivers can get support from the system parallel port driver by setting up IRPs for IRP_MJ_INTERNAL_DEVICE_CONTROL requests with public IOCTL_PARALLEL_PORT_XXX control codes. You can replace the system parallel port driver, but any new driver also must support this set of public internal device control requests.

For more information about these public internal device control requests, see device-specific documentation in this DDK. For information about how to define private I/O control codes, see Defining I/O Control Codes.

For a closely coupled pair of port/class drivers, the class driver might handle the processing of certain device control requests without passing them on to the port driver. In a new class/port driver pair, the class driver's DispatchDeviceControl routine can do either of the following:

  • Check the validity of the parameters in its own I/O stack location, set the I/O status block if it finds any parameter errors, and call IoCompleteRequest with a PriorityBoost of IO_NO_INCREMENT; otherwise, call IoGetNextIrpStackLocation copy its own I/O stack location into the port driver's, and pass the IRP on with IoCallDriver.
  • Or, do nothing more than set up the port driver's I/O stack location in the IRP without checking parameters and pass it on to the port driver for processing.

SCSI class drivers have special requirements for handling device control requests. For more information about these requirements, see Storage Drivers.


Guidelines for Writing Dispatch(Internal)DeviceControl Routines

Keep the following points in mind when writing a DispatchDeviceControl or DispatchInternalDeviceControl routine:

  • At a minimum, a higher-level driver must copy the parameters for an IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL request from its own I/O stack location in the IRP to the next-lower-level driver's I/O stack location. Then, it must call IoCallDriver with a pointer to the next-lower driver's device object and the IRP.

    The higher-level driver should propagate the status value returned by IoCallDriver or set it in the returned IRP's I/O status block when it returns control for a request that lower drivers handle synchronously.

  • The underlying device driver must process device control requests unless it has a closely coupled class driver that completes a subset of these requests on its behalf. A device driver's DispatchDeviceControl routine usually begins processing these requests by switching on the Parameters.DeviceIoControl.IoControlCode in its I/O stack location of each IRP.
  • A lower-level device driver should check the parameters passed in with the request and fail the IRP with an appropriate error if any parameter is invalid. The most common check on the validity of parameters to these requests has the form:
        if (Irp->Parameters.DeviceIoControl.InputBufferLength <
            (sizeof(IOCTL_SPECIFIC_STRUCTURE))) {
        status = STATUS_XXX;

    or

        if (Irp->Parameters.DeviceIoControl.OutputBufferLength <
            (sizeof(IOCTL_SPECIFIC_STRUCTURE))) {
        status = STATUS_XXX;

    where the status value set is one of STATUS_BUFFER_TOO_SMALL or STATUS_INVALID_PARAMETER.

  • Every device driver's DispatchDeviceControl or DispatchInternalDeviceControl routine must handle the receipt of an unrecognized I/O control code by setting the I/O status block with an appropriate NTSTATUS value, setting its Information field to zero, and completing the IRP with a PriorityBoost of IO_NO_INCREMENT.
  • The particular I/O control codes a device driver handles must include any device-type-specific, system-defined I/O control codes for the same type of device. See the device-specific sections of this DDK for more information about the system requirements for each type of device and the corresponding (SDK) header files, each beginning with the prefix ntdd, for declarations of the system-defined structures for these I/O control codes.
  • The class driver of a closely coupled class/port driver pair can process and complete a subset of device control requests without passing them on to the underlying port driver. However, such a class driver must pass on all valid device control requests that require a change of state for the device and those that require the return of volatile information about the device, such as its current baud rate, volume, or video mode.


DispatchPnP Routines

A driver's DispatchPnP routine handles IRPs for the IRP_MJ_PNP I/O function code. Associated with the IRP_MJ_PNP function code are several minor I/O function codes (see Plug and Play IRPs), some of which all drivers must handle and some of which can be optionally handled. The PnP Manager uses these minor function codes to direct drivers to start, stop, and remove devices and to query drivers about their devices.

All drivers for a device must have the opportunity to handle PnP IRPs for the device, except in a few cases where a function or filter driver is allowed to fail the IRP.

Each driver's DispatchPnP routine must follow these rules:

  • A function or filter driver must pass PnP IRPs down to the next driver in the device stack, unless the function or filter driver handles the IRP and encounters a failure (due to insufficient resources, for example).

    All drivers for a device must have the opportunity to handle PnP IRPs for the device unless one of the drivers encounters an error. The PnP Manager sends IRPs to the top driver in a device stack. Function and filter drivers pass the IRP down to the next driver, and the parent bus driver completes the IRP. See Passing PnP IRPs Down the Device Stack for more information.

    A driver can fail an IRP if it tries to handle the IRP and encounters an error (such as insufficient resources). If a driver receives an IRP with a code it does not handle, the driver must not fail the IRP. It must pass such an IRP down to the next driver without modifying the IRP's status.

  • A driver must handle certain PnP IRPs and may optionally handle others.

    Each PnP driver is required to handle certain IRPs, such as IRP_MN_REMOVE_DEVICE, and can optionally handle others. See Plug and Play IRPs for information on which IRPs are required and optional for each kind of driver (function drivers, filter drivers, and bus drivers).

    A driver can fail a required PnP IRP with an appropriate error status, but a driver must not return STATUS_NOT_SUPPORTED for such an IRP.

  • If a driver handles a PnP IRP successfully, the driver sets the IRP status to success. It does not depend on another driver in the stack to set the status.

    A driver sets Irp->IoStatus.Status to STATUS_SUCCESS to inform the PnP Manager that the driver handled the IRP successfully. For some IRPs, a non-bus driver might be able to rely on its parent bus driver to set the status to success. However, this is a risky practice. For consistency and robustness, a driver must set the IRP status to success for each PnP IRP it handles successfully.

  • If a driver fails an IRP, the driver completes the IRP with an error status and does not pass the IRP down to the next driver.

    To fail an IRP like IRP_MN_QUERY_STOP, a driver sets Irp->IoStatus.Status to STATUS_UNSUCCESSFUL. Additional error status values for other IRPs include STATUS_INSUFFICIENT_RESOURCES and STATUS_INVALID_DEVICE_STATE.

    Drivers do not set STATUS_NOT_SUPPORTED for IRPs that they handle. This is the initial status set by the PnP Manager. If an IRP is completed with this status, it means that no drivers in the stack handled the IRP; all drivers just passed the IRP to the next driver.

  • A driver must handle a PnP IRP in its dispatch routine (on the IRP's way down the device stack), in an IoCompletion routine (on the IRP's way back up the device stack), or both, as specified in the reference page for the IRP.

    Some PnP IRPs, such as IRP_MN_REMOVE_DEVICE, must be handled first by the driver at the top of the device stack and then by each next-lower driver. Others, such as IRP_MN_START_DEVICE, must be handled first by the parent bus driver. Still others, such as IRP_MN_QUERY_CAPABILITIES, can be handled both on the way down the device stack and the way back up. See Plug and Play IRPs for the rules that apply to each PnP IRP. See Postponing PnP IRP Processing Until Lower Drivers Finish for information on handling PnP IRPs that must be processed first by the parent bus driver.

  • A driver must add information to an IRP on the IRP's way down the device stack and modify or remove information on the IRP's way back up.

    When returning information in response to a PnP query IRP, a driver must follow this convention to enable orderly information passing by the layered drivers for a device.

  • Except where explicitly documented, a driver must not depend on PnP IRPs being sent in any particular order.
  • When a driver sends a PnP IRP, it must send the IRP to the top driver in the device stack.

    Most PnP IRPs are sent by the PnP Manager, but some can be sent by drivers (for example, IRP_MN_QUERY_INTERFACE). A driver must send a PnP IRP to the driver at the top of the device stack. Call IoGetAttachedDeviceReference to get a pointer to the device object for the driver at the top of the device stack.

You should test your drivers with a checked build of the operating system. The checked build of the system verifies whether a driver follows many of the PnP rules listed above.


DispatchPower Routines

A driver's DispatchPower routine handles IRPs for the IRP_MJ_POWER I/O function code. Associated with the IRP_MJ_POWER function code are several minor I/O function codes for Power Management. The Power Manager uses these minor function codes to direct drivers to change power states, to wait for and respond to system wake-up events, and to query drivers about their devices.

Each driver's DispatchPower routine performs the following tasks:

  • Handle the IRP if possible.
  • Pass the IRP to the next lower driver in the device stack, using PoCallDriver.
  • If a bus driver, perform the requested power operation on the device and complete the IRP.

All drivers for a device must have the opportunity to handle power IRPs for the device, except in a few cases where a function or filter driver is allowed to fail the IRP. Most function and filter drivers either perform some processing or set an IoCompletion routine for each power IRP, then pass the IRP down to the next lower driver without completing it. Eventually the IRP reaches the bus driver, which physically changes the power state of the device if required and completes the IRP.

When the IRP has been completed, the I/O Manager calls any IoCompletion routines set by drivers as the IRP traveled down the device stack. Whether a driver needs to set a completion routine depends upon the type of IRP and the driver's individual requirements.

Power IRPs that power up a device must be handled first by the lowest driver in the device stack (the underlying bus driver) and then by each successive driver up the stack. Power IRPs that power down a device must be handled first by the driver at the top of the device stack and then by each successive driver going down the stack.

Special Handling for Removable Devices

In their DispatchPower routines, drivers of removable devices should check to see whether the device is still present. If the device has been removed, the driver should not pass the IRP down to the next lower driver. Instead, the driver should do the following:

  • Call PoStartNextPowerIrp to begin processing the next power IRP.
  • Set Irp->IoStatus.Status to STATUS_DELETE_PENDING.
  • Call IoCompleteRequest, specifying IO_NO_INCREMENT, to complete the IRP.
  • Return STATUS_DELETE_PENDING.


DispatchQueryInformation Routines

A driver's DispatchQueryInformation routine handles IRPs for the IRP_MJ_QUERY_INFORMATION I/O function code. Driver support for this I/O function code is optional, and typically appears in higher-level or file system drivers. This request is sent by the I/O Manager and other operating system components, as well as other kernel-mode drivers. For example, it is sent when a user-mode application calls GetFileInformationByHandle (described in Platform SDK documentation), and when a kernel-mode component calls ZwQueryInformationFile.


DispatchSetInformation Routines

A driver's DispatchSetInformation routine handles IRPs for the IRP_MJ_SET_INFORMATION I/O function code. Driver support for this I/O function code is optional, and typically appears in higher-level or file system drivers. This request is sent by the I/O Manager and other operating system components, as well as other kernel-mode drivers. For example, it is sent when a user-mode application calls SetEndOfFile (described in Platform SDK documentation), and when a kernel-mode component calls ZwSetInformationFile.


DispatchFlushBuffers Routines

A driver's DispatchFlushBuffers routine handles IRPs for the IRP_MJ_FLUSH_BUFFERS I/O function code. Driver support for this I/O function code is optional, but all file system and filter drivers that maintain internal data buffers must handle it to preserve changes to file data or metadata across system shutdowns. This request is sent by the I/O Manager and other operating system components, as well as other kernel-mode drivers, when buffered data needs to be flushed to disk. For example, it is sent when a user-mode application calls FlushFileBuffers (described in Platform SDK documentation).


DispatchShutdown Routines

A driver's DispatchShutdown routine handles IRPs for the IRP_MJ_SHUTDOWN I/O function code. Drivers of mass-storage devices that have internal caches for data must handle this request. Drivers of mass-storage devices and intermediate drivers layered over them also must handle this request if an underlying driver maintains internal buffers for data.


DispatchSystemControl Routines

A driver's DispatchSystemControl routine handles IRPs for the IRP_MJ_SYSTEM_CONTROL I/O function code.

All drivers must provide a DispatchSystemControl routine. The purpose of this routine is to provide support for Windows Management Instrumentation (WMI). Whether or not a driver supports WMI, this routine must pass the IRP to the next-lower driver.

To learn how to implement a DispatchSystemControl routine, and how to support WMI in general, see Windows Management Instrumentation.


Writing an Unload Routine

Any driver that can be replaced, or unloaded and reloaded, while the system is running must have an Unload routine. All WDM drivers must have Unload routines.

Driver stacks for video, keyboard, or mouse devices, and for mass-storage devices that can hold the system page file currently do not have Unload routines because these types of devices must be available while the system is running and are thus never unloaded.

Although Unload routines are optional for non-WDM drivers, Driver Verifier will fail any driver that does not provide an Unload routine.


Unload Routine Environment

The operating system unloads a driver when the driver is being replaced, when all the devices the driver services have been removed, or when driver initialization fails. The PnP Manager calls a PnP driver's Unload routine if the driver has no more device objects after it handles an IRP_MN_REMOVE_DEVICE request.

At the start of the unloading sequence, the I/O Manager or PnP Manager marks the driver object and its device objects as "Unload Pending". After a driver has been marked as "Unload Pending", no additional drivers can attach to that driver, nor can any additional references be made to the driver's device objects. The driver can complete outstanding IRPs, but the system will not send any new IRPs to the driver.

The I/O Manager calls a driver's Unload routine when all of the following are true:

  • No references remain to any of the device objects the driver has created. In other words, no files associated with the underlying device can be open, nor can any IRPs be outstanding for any of the driver's device objects.
  • No other drivers remain attached to this driver.
  • The driver has called IoUnregisterPlugPlayNotification to unregister all PnP notifications for which it previously registered.

Note that the Unload routine is not called if a driver's DriverEntry routine returns a failure status. In this case, the I/O manager simply frees the memory space taken up by the driver.

Neither the PnP Manager nor the I/O Manager calls Unload routines at system shutdown time. A driver that must perform shutdown processing should register a DispatchShutdown routine.


Unload Routine Functionality

The responsibilities of a driver's Unload routine depend on whether the driver supports PnP or not. Just as the DriverEntry routines of PnP drivers are usually simple, so are their Unload routines, as described in A PnP Driver's Unload Routine.

A non-PnP driver's Unload routine must free device objects and release driver-allocated resources. In short, it must undo the work performed by its corresponding DriverEntry and Reinitialize routines in initializing the driver, its devices, and its resources. See A Non-PnP Driver's Unload Routine for details.


A PnP Driver's Unload Routine

A PnP driver must have an Unload routine that removes any driver-specific resources, such as memory, threads, and events, that are created by the DriverEntry routine. If there are no driver-specific resources to remove, the driver must still have an Unload routine but it can simply return.

A driver's Unload routine can be called at any time after all the driver's devices have been removed. The PnP Manager calls a driver's Unload routine in the context of a system thread at IRQL = PASSIVE_LEVEL.

PnP drivers free device-specific resources and device objects in response to PnP device-removal IRPs. The PnP Manager sends these IRPs on behalf of each PnP device it enumerates as well as any root-enumerated legacy devices a driver reports using IoReportDetectedDevice.

Consequently, the Unload routines of PnP drivers are usually simple, often consisting only of a Return statement. However, if the driver allocated any driver-wide resources in its DriverEntry routine, it must deallocate those resources in its Unload routine unless it has already done so. In general, the process of unloading a PnP driver is a synchronous operation.

The I/O Manager frees the driver object and any driver object extension that the driver allocated using IoAllocateDriverObjectExtension.


A Non-PnP Driver's Unload Routine

Legacy drivers and high-level file system drivers, which do not handle PnP device-removal requests, must release resources, delete device objects, and detach from the device stack in their Unload routines.

If it has not done so already, the first thing a legacy device driver should do in its Unload routine is to disable interrupts from the device. Otherwise, its ISR might be called to handle a device interrupt while the Unload routine is releasing resources in the device extension that the ISR needs to handle the interrupt. Even if its ISR runs successfully in these circumstances, the DpcForIsr or CustomDpc routine that the ISR queues, and possibly other driver routines that run at IRQL >= DISPATCH_LEVEL, will execute before the Unload routine regains control, thereby increasing the likelihood that the Unload routine has deleted a resource that another driver routine references. See Managing Hardware Priorities for more information.

After disabling interrupts, file system and legacy drivers must release resources and objects. For details, see the following two sections:

Releasing Driver-Allocated Resources

Releasing Device and Controller Objects


Releasing Driver-Allocated Resources

The specifics of how a driver uses the registry, sets up system objects and resources in its device extensions, controller extension, or driver-allocated nonpaged pool varies from driver to driver. However, any Unload routine must release the resources a driver is using in stages.

Any driver's Unload routine must ensure that no other driver routine is currently using or might shortly be using a particular resource before it releases that resource.

In general, an Unload routine releases all driver-allocated resources in the following stages:

  1. If the driver has not already done so, disable interrupts on any physical devices, if possible, and then call IoDisconnectInterrupt as soon as interrupts are disabled.
  2. Ensure that no other driver routine can reference the resources that the Unload routine intends to release.

    For example, an Unload routine must call IoStopTimer if the driver's IoTimer routine is currently enabled for a particular device object. It must ensure that no thread is waiting on any of the driver's dispatcher objects and that its timer objects are not queued for calls to its CustomTimerDpc routines before it frees the storage for its dispatcher objects. It must call KeRemoveQueueDpc if it has a CustomDpc routine that the ISR might have queued, and so on.

    If the driver called IoQueueWorkItem, it must ensure that the work item has completed. IoQueueWorkItem takes out a reference on the associated device object; the driver cannot be unloaded if any such references remain.

    If the driver called PsCreateSystemThread, the Unload routine also must cause the driver-created thread to be run so that the thread itself can call PsTerminateSystemThread before the driver is unloaded. A driver cannot release a driver-created system thread by calling ZwClose with the ThreadHandle returned by PsCreateSystemThread.

  3. Release any device-specific resources that the driver allocated. Doing so might involve calling the following system support routines:
    • IoDeleteSymbolicLink if the DriverEntry or Reinitialize routine called IoCreateSymbolicLink or IoCreateUnprotectedSymbolicLink, and IoDeassignArcName if the driver called IoAssignArcName
    • ExFreePool if DriverEntry or any other driver routine called ExAllocatePool and the driver has not yet released the allocated memory
    • MmUnmapIoSpace if the DriverEntry or Reinitialize routine called MmMapIoSpace
    • MmFreeNonCachedMemory if the DriverEntry or Reinitialize routine called MmAllocateNonCachedMemory
    • MmFreeContiguousMemory if the DriverEntry or Reinitialize routine called MmAllocateContiguousMemory
    • FreeCommonBuffer if the DriverEntry or Reinitialize routine called AllocateCommonBuffer
    • IoAssignResources or IoReportResourceUsage if the DriverEntry or Reinitialize routine called one of these support routines or HalAssignSlotResources to claim hardware resources in the configuration registry for itself and/or for its physical devices individually
  4. Release system objects and resources that the DriverEntry or Reinitialize routine set up in the device extension of the device objects or in the controller extension of the controller object (if it created one). In particular, the driver must do the following before it attempts to delete the device object (IoDeleteDevice) or controller object (IoDeleteController):
    • Call IoDisconnectInterrupt to free the interrupt object pointer stored in the corresponding device or controller extension.
    • Call ObDereferenceObject with the pointer to the next-lower driver's file object if it called IoGetDeviceObjectPointer and stored this pointer in a device or controller extension.
    • Call IoDetachDevice with the pointer to the lower driver's device object if it called IoAttachDevice or IoAttachDeviceToDeviceStack and stored this pointer in a device or controller extension
  5. Free the hardware resources that the DriverEntry or Reinitialize routine claimed for the driver's physical devices, if any, in the registry under the \Registry\Machine\Hardware\ResourceMap tree.
  6. Remove any names for its devices that the DriverEntry or Reinitialize routine stored in the registry under the \Registry..\DeviceMap tree, as well.

After the driver has released device, system, and hardware resources, it can delete its device and controller objects, as described in the following section.


Releasing Device and Controller Objects

Before a driver deletes a device or controller object, it must release its references to external resources, such as pointers to other drivers' objects and/or to interrupt objects, that it stored in the corresponding device or controller extension. It can then call IoDeleteDevice for each device object that the driver created. A non-WDM driver that previously called IoCreateController must also call IoDeleteController.

Any Kernel-defined object for which the driver provides storage in a device extension is automatically freed when the Unload routine calls IoDeleteDevice with the corresponding device object. In general, any object that the DriverEntry or Reinitialize routine set up by calling KeInitialize Xxx can be freed by a call to IoDeleteDevice if the driver provided storage for that object in its device extension. For example, if a driver has a CustomTimerDpc routine and has provided storage for the necessary DPC and timer objects in its device extension, the call to IoDeleteDevice releases these system resources.

Similarly, any Kernel-defined object for which the driver provides storage in a controller extension is automatically freed when the Unload routine calls IoDeleteController with the corresponding controller object.

If the DriverEntry or Reinitialize routine called IoGetConfigurationInformation to increment the count for a particular type of device, the Unload routine also must call IoGetConfigurationInformation and decrement the count for its devices in the I/O Manager's global configuration information structure as it deletes the corresponding device objects.

Before it returns control, an Unload routine also is responsible for freeing any other driver-allocated resources that have not yet been freed by other driver routines.


Handling IRPs

This section describes how kernel mode drivers handle I/O request packets (IRPs). It contains the following sections:

Overview of the Windows I/O Model

End-User I/O Requests and File Objects

The Life of an I/O Request

I/O Stack Locations

I/O Status Blocks

Passing IRPs down the Driver Stack

Creating IRPs for Lower-Level Drivers

Queuing and Dequeuing IRPs

Completing IRPs

Canceling IRPs

Reusing IRPs

IRP Processing Examples


Overview of the Windows I/O Model

Every operating system has an implicit or explicit I/O model for handling the flow of data to and from peripheral devices. One feature of the Microsoft® Windows® I/O model is its support for asynchronous I/O. In addition, the I/O model has the following general features:

  • The I/O Manager presents a consistent interface to all kernel-mode drivers, including lowest-level, intermediate, and file system drivers. All I/O requests to drivers are sent as I/O request packets (IRPs).
  • I/O operations are layered. The I/O Manager exports I/O system services, which user-mode protected subsystems call to carry out I/O operations on behalf of their applications and/or end users. The I/O Manager intercepts these calls, sets up one or more IRPs, and routes them through possibly layered drivers to physical devices.
  • The I/O Manager defines a set of standard routines, some required and others optional, that drivers can support. All drivers follow a relatively consistent implementation model, given the differences among peripheral devices and the differing functionality required of bus, function, filter, and file system drivers.
  • Like the operating system itself, drivers are object-based. Drivers, their devices, and system hardware are represented as objects. The I/O Manager and other operating system components export kernel-mode support routines that drivers can call to get work done by manipulating the appropriate objects.

In addition to using IRPs to convey traditional I/O requests, the I/O Manager works with the PnP and Power Managers to send IRPs containing PnP and power requests.


End-User I/O Requests and File Objects

Kernel-mode drivers are hidden from end users by a protected subsystem that implements an already familiar programming interface, such as Windows or POSIX. Devices are visible to user-mode code, which includes protected subsystems, only as named file objects controlled by the I/O Manager.

The following figure illustrates this relationship between an end user, a subsystem, and the I/O Manager.

File Objects Represent Files, Volumes, and Devices

A protected subsystem, such as the Win32® subsystem, passes I/O requests to the appropriate kernel-mode driver through the I/O system services. The subsystem shown in the previous figure depends on support from the display, video adapter, keyboard, and mouse device drivers.

A protected subsystem insulates its end users and applications from having to know anything about kernel-mode components, including drivers. In turn, the I/O Manager insulates protected subsystems from having to know anything about machine-specific device configurations or about drivers' implementations.

The I/O Manager's layered approach also insulates most drivers from having to know anything about the following:

  • Whether an I/O request originated in any particular protected subsystem, such as Win32 or POSIX
  • Whether a given protected subsystem has particular kinds of user-mode drivers
  • What any protected subsystem's I/O model and interface to drivers is

The I/O Manager supplies drivers with a single I/O model, a set of kernel-mode support routines that drivers can use to carry out I/O operations, and a consistent interface between the originator of an I/O request and the drivers that must respond to it.

As shown in the previous figure, a subsystem and its native applications can access a driver's device or a file on a mass-storage device only through file object handles supplied by the I/O Manager. To open such a file object or to obtain a handle for I/O to a device or a data file, a subsystem calls the I/O system services with a request to open a named file. The named file can have a subsystem-specific alias (symbolic link) to the kernel-mode name for the file object.

The I/O Manager, which exports these system services, is then responsible for locating or creating the file object that represents the device or data file and for locating the appropriate driver(s).


The Life of an I/O Request

This section describes the path taken by an IRP from creation by the operating system to its completion by the set of drivers responsible for controlling the target device. The section contains the following topics:

Example I/O Request – An Overview

Example I/O Request – The Details

Driver Thread Context

Points to Consider about User I/O Requests


Example I/O Request - An Overview

Previous Next

Example I/O Request – An Overview

The following figure shows an overview of what happens when a subsystem opens a file object representing a data file on behalf of an application.

Opening a File Object

  1. The subsystem calls an I/O system service to open a named file.
  2. The I/O Manager calls the Object Manager to look up the named file and to help it resolve any symbolic links for the file object. It also calls the Security Reference Monitor to check that the subsystem has the correct access rights to open that file object.
  3. If the volume is not yet mounted, the I/O Manager suspends the open request temporarily and calls one or more file systems until one of them recognizes the file object as something it has stored on one of the mass-storage devices the file system uses. When the file system has mounted the volume, the I/O Manager resumes the request.
  4. The I/O Manager allocates memory for and initializes an IRP for the open request. To drivers, an open is equivalent to a "create" request.
  5. The I/O Manager calls the file system driver, passing it the IRP. The file system driver accesses its I/O stack location in the IRP to determine what operation it must carry out, checks parameters, determines if the requested file is in cache, and, if not, sets up the next-lower driver's I/O stack location in the IRP.
  6. Both drivers process the IRP and complete the requested I/O operation, calling kernel-mode support routines supplied by the I/O Manager and by other system components (not shown in the previous figure).
  7. The drivers return the IRP to the I/O Manager with the I/O status block set in the IRP to indicate whether the requested operation succeeded or why it failed.
  8. The I/O Manager gets the I/O status from the IRP, so it can return status information through the protected subsystem to the original caller.
  9. The I/O Manager frees the completed IRP.
  10. The I/O Manager returns a handle for the file object to the subsystem if the open operation was successful. If there was an error, it returns appropriate status to the subsystem.

After a subsystem successfully opens a file object that represents a data file, a device, or a volume, the subsystem uses the returned handle to identify the file object in subsequent requests for device I/O operations (usually read, write, or device I/O control requests). To make such a request, the subsystem calls I/O system services. The I/O Manager routes these requests as IRPs sent to appropriate drivers.


Example I/O Request - The Details

Previous Next

Example I/O Request – The Details

The figure illustrating Opening a File Object shows an IRP with two I/O stack locations, but an IRP can have any number of I/O stack locations, depending on how many layered drivers will handle a given request.

The following figure illustrates in more detail how the drivers in the Opening a File Object figure use I/O support routines (IoXxx routines) to process the IRP for a read or write request.

Processing IRPs in Layered Drivers

  1. The I/O Manager calls the file system driver (FSD) with the IRP it has allocated for the subsystem's read/write request. The FSD accesses its I/O stack location in the IRP to determine what operation it should carry out.
  2. The FSD can break the original request into smaller requests (possibly for more than one device driver) by calling an I/O support routine (IoAllocateIrp) one or more times to allocate additional IRPs. The additional IRPs are returned to the FSD with zero-filled I/O stack location(s) for lower-level driver(s). At its discretion, the FSD can reuse the original IRP, rather than allocating additional IRPs as shown in the previous figure, by setting up the next-lower driver's I/O stack location in the original IRP and passing it on to lower drivers.
  3. For each driver-allocated IRP, the FSD in the previous figure calls an I/O support routine to register an FSD-supplied completion routine; in the completion routine, the FSD can determine whether lower drivers satisfied the request and can free each driver-allocated IRP when lower drivers have completed it. The I/O Manager will call the FSD-supplied completion routine whether each driver-allocated IRP was completed successfully, completed with an error status, or cancelled. A higher-level driver is responsible for freeing any IRPs it allocates and sets up on its own behalf for lower-level drivers. The I/O Manager frees the IRPs that it allocates after all drivers have completed them.

    Next, the FSD calls an I/O support routine (IoGetNextIrpStackLocation) to access the next-lower-level driver's I/O stack location in order to set up the request for the next-lower driver. (In the previous figure, the next lower driver happens to be the lowest-level driver.) The FSD then calls an I/O support routine (IoCallDriver) to pass that IRP on to the next-lower driver.

  4. When it is called with the IRP, the lowest-level driver checks its I/O stack location to determine what operation (indicated by the IRP_MJ_XXX function code) it should carry out on the target device. The target device is represented by the device object in its designated I/O stack location and is passed with the IRP to the driver. The lowest-level driver can assume that the I/O Manager has routed the IRP to an entry point that the driver defined for the IRP_MJ_XXX operation (here IRP_MJ_READ or IRP_MJ_WRITE) and that the higher-level driver has checked the validity of other parameters for the request.

    If there were no higher-level driver, the lowest-level driver would check whether the input parameters for an IRP_MJ_XXX operation are valid. If they are, the driver usually calls I/O support routines to tell the I/O Manager that a device operation is pending on the IRP and to either queue the IRP or pass it on to another driver-supplied routine that accesses the target device (here, a physical or logical device: the disk or a partition on the disk).

  5. The I/O Manager determines whether the driver is already busy processing another IRP for the target device, queues the IRP if it is, and returns. Otherwise, the I/O Manager routes the IRP to a driver-supplied routine that starts the I/O operation on its device. (At this stage, both drivers in the previous figure and the I/O Manager return control.)
  6. When the device interrupts, the driver's interrupt service routine (ISR) does only as much work as it must to stop the device from interrupting and to save necessary context about the operation. The ISR then calls an I/O support routine (IoRequestDpc) with the IRP to queue a driver-supplied DPC (Deferred Procedure Call) routine to complete the requested operation at a lower hardware priority than the ISR.
  7. When the driver's DPC gets control, it uses the context (passed in the ISR's call to IoRequestDpc) to complete the I/O operation. The DPC calls a support routine to dequeue the next IRP (if any) and to pass that IRP on to the driver-supplied routine that starts I/O operations on the device (see Step 5). The DPC then sets status about the just-completed operation in the IRP's I/O status block and returns it to the I/O Manager with IoCompleteRequest.
  8. The I/O Manager zeroes the lowest-level driver's I/O stack location in the IRP and calls the file system's registered completion routine (see Step 3) with the FSD-allocated IRP. This completion routine checks the I/O status block to determine whether to retry the request or to update any internal state maintained about the original request and to free its driver-allocated IRP. The file system can collect status information for all driver-allocated IRPs it sends to lower-level drivers so that it can set I/O status and complete the original IRP. When the file system has completed the original IRP, the I/O Manager returns and NTSTATUS value to the original requester (the subsystem's native function) of the I/O operation.

Like the file system driver shown in the Processing IRPs in Layered Drivers figure, any new driver that is added to a chain of existing drivers can do all of the following:

  • Set its own completion routine into an IRP. The IoCompletion routine checks the I/O status block to determine whether lower drivers completed the IRP successfully, cancelled the IRP, and/or completed it with an error. The completion routine can also update any IRP-specific state the driver might have saved, release any operation-specific resources the driver might have allocated, and so forth, before completing the IRP. In addition, the completion routine can postpone IRP completion (by informing the I/O Manager that more processing is required on the IRP), and can send another request to the next-lower-level driver before allowing the IRP to complete.
  • Set up the next-lower-level driver's I/O stack location in the IRPs it allocates and send requests to the next-lower-level driver.
  • Pass any incoming requests on to lower drivers by setting up the next-lower driver's I/O stack location in each IRP and calling IoCallDriver. (Note that for IRPs with major function code IRP_MJ_POWER, drivers must use PoCallDriver.)

Each driver-created device object represents a physical, logical, or virtual device for which a particular driver carries out I/O requests. For detailed information about creating and setting up a device object, see Device Objects and Device Stacks.

As the Processing IRPs in Layered Drivers figure also shows, most drivers process each IRP in stages through a driver-supplied set of system-defined standard routines, but drivers at different levels in a chain necessarily have different standard routines. For example, only lowest-level drivers handle interrupts from a physical device, so only a lowest-level driver would have an ISR and a DPC that completes interrupt-driven I/O operations. On the other hand, because such a driver knows that I/O is complete when it receives an interrupt from its device, it has no need for a completion routine. Only a higher-level driver would have one or more completion routines like the FSD in this figure.


Driver Thread Context

As shown in the Processing IRPs in Layered Drivers figure, a file system is a two-part driver:

  1. A file system driver (FSD), which executes in the context of a user-mode thread that calls an I/O system service

    The I/O Manager sends the corresponding IRP to the FSD. If the FSD sets up a completion routine for an IRP, its completion routine is not necessarily called in the original user-mode thread's context.

  2. A set of file system threads, and possibly an FSP (file system process)

    An FSD can create a set of driver-dedicated system threads, but most FSDs use system worker threads in order to get work done without tying up user-mode threads that make I/O requests. Any FSD might set up its own process address space in which its driver-dedicated threads execute, but the system-supplied FSDs avoid this practice to conserve system memory.

File systems generally use system worker threads to set up and manage internal work queues of IRPs that they send to one or more lower-level drivers, possibly for different devices.

While the lowest-level driver shown in the Processing IRPs in Layered Drivers figure processes each IRP in stages through a set of discrete, driver-supplied routines, it does not use system threads as the file system does. A lowest-level driver does not need its own thread context unless setting up its device for I/O is such a protracted process that it has a noticeable effect on system performance. Few lowest-level or intermediate drivers need to set up their own driver-dedicated or device-dedicated system threads, and those that do pay a performance penalty caused by context switches to their threads.

Most kernel-mode drivers, like the physical device driver in the Processing IRPs in Layered Drivers figure, execute in an arbitrary thread context: that of whatever thread happens to be current when they are called to process an IRP. Consequently, drivers usually maintain state about their I/O operations and the devices they service in a driver-defined part of their device objects, called a device extension.


Points to Consider about User I/O Requests

Keep the following points in mind when designing a kernel-mode driver:

  • Drivers can be layered, and more than one driver can process a single I/O request (IRP).
  • A driver cannot make any assumptions about which other drivers will be in the device stack. Therefore, each driver should be prepared to receive requests from any other driver and should handle all potential error cases.
  • Drivers communicate the success or failure of a requested I/O operation in the I/O status block of the IRP. The I/O Manager communicates the success or failure of a requested I/O operation to a user-mode requester.
  • Drivers need not and should not be designed to provide application-specific support. A protected subsystem or its subsystem-specific, user-mode drivers supply this kind of support. There is one exception to this rule: an MS-DOS® application that relies on an application-dedicated device can require a kernel-mode driver to control the device and a closely coupled Win32 user-mode virtual device driver (VDD). See the Virtual Device Drivers documentation in the DDK for more information about VDDs.
  • A new driver must handle the same set of IRP_MJ_XXX as any system-supplied driver it replaces. The I/O Manager returns STATUS_INVALID_DEVICE_REQUEST for a given I/O request to a target device if its driver does not define an entry point for that IRP_MJ_XXX. A device driver also must handle the same I/O control codes for IRP_MJ_DEVICE_CONTROL requests as any system-supplied driver it replaces. In other words, a new device driver must not "break applications" by implementing less functionality than an existing driver for the same type of device.
  • A new intermediate driver inserted into a chain of existing drivers should recognize the same set of IRP_MJ_XXX as the driver it displaces. The new driver can simply pass on IRPs for those requests that it does not process to the next-lower-level driver. However, a new intermediate driver must not "break the chain" for drivers above and below it by neglecting to define an entry point for an IRP_MJ_XXX request that the newly displaced, next-lower-level driver does handle.
  • A lowest-level driver can access only its own I/O stack location in any IRP that it is sent. A higher-level driver can access only its own and the next-lower-level driver's I/O stack locations in any IRP that it is sent.
  • Every driver communicates information to higher-level drivers (and ultimately, to user-mode applications via the I/O Manager) only in the I/O status blocks of IRPs because the I/O Manager zeros the corresponding I/O stack location as each driver in a chain completes an IRP. Any new driver that attempts to implement back-door communication with a particular higher (or lower) driver compromises its portability and its interoperability with other drivers from one Windows platform or version to the next.
  • A pair of drivers can define a set of device-specific (also called private) I/O control codes for IRP_MJ_INTERNAL_DEVICE_CONTROL requests that the higher of the pair can send down to the lower of the pair. However, such a pair of drivers must follow all of the preceding guidelines if they are to remain portable and interoperable with other drivers from one Windows platform or version to another. If you design a pair of drivers with a private interface, consider the set of I/O control codes to be defined carefully. Make them as generally useful as possible and design your paired drivers to follow the preceding guidelines, so that you (or someone else) can reuse, replace, or displace either or both of your new drivers easily as they migrate from one Windows platform or version to another.


I/O Stack Locations

The I/O Manager gives each driver in a chain of layered drivers an I/O stack location for every IRP that it sets up. Each I/O stack location consists of an IO_STACK_LOCATION structure.

The I/O manager creates an array of I/O stack locations for each IRP, with an array element corresponding to each driver in a chain of layered drivers. Each driver owns one of the stack locations in the packet and calls IoGetCurrentIrpStackLocation to obtain driver-specific information about the I/O operation.

Each driver in such a chain is responsible for calling IoGetNextIrpStacklocation, then setting up the next-lower driver's I/O stack location. Any higher-level driver's I/O stack location can also be used to store context about an operation so that the driver's IoCompletion routine can perform its cleanup operations.

The Processing IRPs in Layered Drivers figure shows two I/O stack locations in the original IRP because it shows two drivers, a file system driver and a mass-storage device driver. The driver-allocated IRPs in the Processing IRPs in Layered Drivers figure do not have a stack location for the FSD that created them. Any higher-level driver that allocates IRPs for lower-level drivers also determines how many I/O stack locations the new IRPs should have, according to the StackSize value of the next-lower driver's device object.

The following figure shows the contents of the IRP in more detail.

Contents of I/O Stack Location in an IRP

As shown in the figure, each driver-specific I/O stack location in an IRP contains the following general information:

  • The major function code (IRP_MJ_XXX), indicating the basic operation the driver should carry out
  • For some major function codes handled by FSDs, higher-level SCSI drivers, and all PnP drivers, a minor function code (IRP_MN_XXX), indicating which sub-case of the basic operation the driver should carry out
  • A set of operation-specific arguments, such as the length and starting location of a buffer into which or from which the driver transfers data
  • A pointer to the driver-created device object, representing the target (physical, logical, or virtual) device for the requested operation
  • A pointer to the file object, representing an open file, device, directory, or volume

    A file system driver accesses the file object through its I/O stack location in IRPs. Other drivers usually ignore the file object.

The set of IRP major and minor function codes that a particular driver handles can be device-type-specific. However, lowest-level drivers and intermediate drivers (including PnP function and filter drivers) usually handle the following set of basic requests:

  • IRP_MJ_CREATE — open the target device object, indicating that it is present and available for I/O operations
  • IRP_MJ_READ — transfer data from the device
  • IRP_MJ_WRITE — transfer data to the device
  • IRP_MJ_DEVICE_CONTROL — set up (or reset) the device, according to a system-defined, device-type-specific I/O control code (IOCTL)
  • IRP_MJ_CLOSE — close the target device object
  • IRP_MJ_PNP — perform a plug-and-play operation on the device. An IRP_MJ_PNP request is sent by the PnP Manager through the I/O Manager.
  • IRP_MJ_POWER — perform a power operation on the device. An IRP_MJ_POWER request is sent by the Power Manager through the I/O Manager.

For more information about the major IRP function codes and device I/O control codes that drivers for particular kinds of devices are required to handle, see IRP Function Codes and IOCTLs.

In general, the I/O Manager sends IRPs with at least two I/O stack locations to mass-storage device drivers because a file system is layered over other drivers for mass-storage devices. The I/O Manager sends IRPs with a single stack location to any driver that has no other driver layered above it.

However, the I/O Manager provides support for adding a new driver to any chain of existing drivers in the system. For example, an intermediate mirror driver that backs up data on a given disk partition might be inserted between a pair of drivers, such as the file system driver and lowest-level driver shown in the Processing IRPs in Layered Drivers figure. When this new driver attaches itself to the device stack, the I/O Manager adjusts the number of I/O stack locations in all IRPs it sends to the file system, mirror, and lowest-level drivers. Every IRP that the file system in the Processing IRPs in Layered Drivers figure allocated would also contain another I/O stack location for such a new mirror driver.

Note that this support for adding new drivers to an existing chain implies certain restrictions on any particular driver's access to the I/O stack locations in IRPs:

  • A higher-level driver in a chain of layered drivers can safely access only its own and the next-lower-level driver's I/O stack locations in any IRP. Such a driver must set up the I/O stack location for the next-lower-level driver in IRPs. However, when designing such a higher-level driver, you cannot predict when (or whether) a new driver will be added to the existing chain just below your driver.

    Therefore, you should assume that any subsequently added driver will handle the same IRP major function codes (IRP_MJ_XXX) as the displaced next-lower-level driver did.

  • The lowest-level driver in a chain of layered drivers can safely access only its own I/O stack location in any IRP. When designing such a driver, you cannot predict when (or whether) a new driver will be added to the existing chain above your device driver.

    In designing a lowest-level driver, assume that the driver can continue to process IRPs using the information passed in its own I/O stack location, whatever the originating source of a given IRP and however many drivers are layered above it.


I/O Status Blocks

An I/O status block, which consists of an IO_STATUS_BLOCK structure, part of each IRP. An I/O status block serves two purposes:

  • It provides a higher-level driver's IoCompletion routine a way of determining whether or not the service worked when the IRP is completed.
  • It provides more information about why the service either worked or did not work.

Upon completion of a IRP, the Status field indicates whether the drivers that processed the IRP actually satisfied the request or failed the IRP with an error status. The Information field supplies the caller with more information about what actually occurred. For example, it contains the number of bytes actually transferred after a read or write operation.

For more information, see Setting the I/O Status Block in an IRP.


Passing IRPs down the Driver Stack

When a dispatch routine has checked its own I/O stack location in an input IRP and determined that any parameters are valid, it must pass the IRP on for further processing by lower-level drivers or by other device driver routines if it cannot satisfy and complete the given request in the dispatch routine itself.

A higher-level driver should pass such a request on to a next-lower driver as follows:

  1. Call IoGetCurrentIrpStackLocation with the input IRP, if the dispatch routine has not already done so, to get a pointer for its own I/O stack location in the IRP.

    In most circumstances, a higher-level driver's dispatch routine has already made this call. However, a dispatch routine devoted exclusively to handling a particular IRP_MJ_XXX with parameters that the driver cannot validate or with no parameters might call IoGetCurrentIrpStackLocation.

  2. Call IoGetNextIrpStackLocation if the driver will pass the input IRP on to the next lower-level driver. If it allocates additional IRP(s) for one or more lower drivers, the dispatch routine makes either of the following sets of calls with each of the IRPs it allocates:
    • IoGetNextIrpStackLocation to get a pointer to the next-lower driver's I/O stack location if the driver allocated no stack location of its own in the new IRP
    • IoSetNextIrpStackLocation, followed by IoGetCurrentIrpStackLocation, to get a pointer to its own stack location in a new IRP, where it can set up whatever context its IoCompletion routine needs; then, IoGetNextIrpStackLocation to get a pointer to the next-lower driver's I/O stack location
  3. Set up the next-lower driver(s)' I/O stack location, usually by copying the contents of its own I/O stack location in the original IRP to the next-lower driver's. However, the dispatch routine can modify some of the parameters in the next-lower driver's I/O stack location for certain requests.

    For example, a higher-level driver might modify the parameters for a large transfer request when the underlying device has a known limit in transfer capacity, and reuse the IRP to send partial-transfer requests to the underlying device driver.

  4. Call IoSetCompletionRoutine with each IRP that the dispatch routine allocated so the driver's IoCompletion routine releases each such IRP when lower drivers have completed it.

    The dispatch routine also can call IoSetCompletionRoutine with an input IRP in which it has set up the next-lower driver's I/O stack location. Then, its IoCompletion routine can check on how lower drivers completed the request, reuse the IRP for partial transfers, update whatever state the driver maintains if it tracks IRPs, possibly retry a request returned with an error, and so forth.

    For more information about IoCompletion routines, see Completing IRPs.

  5. Call IoCallDriver with each IRP to be processed by lower driver(s).
  6. Return an appropriate NTSTATUS value, such as:
    • Usually, STATUS_PENDING if the input IRP is an asynchronous request, such as IRP_MJ_READ or IRP_MJ_WRITE
    • Frequently, the result of the call to IoCallDriver if the input IRP is a synchronous request, such as IRP_MJ_CREATE or IRP_MJ_DEVICE_CONTROL

A lowest-level device driver passes any IRP that it cannot complete in its dispatch routine on to other driver routines as follows:

  1. Call IoMarkIrpPending with the input IRP.
  2. Call IoStartPacket to pass on or queue the IRP to the driver's StartIo routine, unless the driver manages its own internal IRP queuing, as described in Driver-Managed IRP Queues.

    If the driver does not have a StartIo routine but handles cancelable IRPs, it must call IoSetCancelRoutine with the entry point for a Cancel routine and the IRP before queuing the IRP for further processing. See Canceling IRPs for more information about Cancel routines.

  3. Return STATUS_PENDING.


Creating IRPs for Lower-Level Drivers

To allocate an IRP for an asynchronous request, which will be processed in an arbitrary thread context by lower drivers, a DispatchReadWrite routine can call one of the following support routines:

  • IoAllocateIrp, which allocates an IRP and a number of zero-initialized I/O stack locations

    The dispatch routine must set up the next-lower driver's I/O stack location for the newly allocated IRP, usually by copying (possibly modified) information from its own stack location in the original IRP. If a higher-level driver allocates an I/O stack location of its own for a newly-allocated IRP, the dispatch routine can set up per-request context information there for the IoCompletion routine to use.

  • IoBuildAsynchronousFsdRequest, which sets up the next-lower driver's I/O stack location for the caller, according to caller-specified parameters

    Higher-level drivers can call this routine to allocate IRPs for IRP_MJ_READ, IRP_MJ_WRITE, IRP_MJ_FLUSH_BUFFERS, and IRP_MJ_SHUTDOWN requests.

    When an IoCompletion routine is called for such an IRP, it can check the I/O status block, and if necessary (or possible) set up the next-lower driver's I/O stack location in the IRP again and retry the request or reuse it. However, the IoCompletion routine has no local context storage for itself in the IRP, so the driver must maintain context about the original request elsewhere in resident memory.

  • IoMakeAssociatedIrp, which allocates an IRP and a number of zero-initialized I/O stack locations, and associates the IRP with a master IRP.

    Intermediate drivers cannot call IoMakeAssociatedIrp to create IRPs for lower drivers.

    Any highest-level driver that calls IoMakeAssociatedIrp to create IRPs for lower drivers can return control to the I/O Manager after sending its associated IRPs on and calling IoMarkIrpPending for the original, master IRP. A highest-level driver can rely on the I/O Manager to complete the master IRP when all associated IRPs have been completed by lower drivers.

    Drivers seldom set an IoCompletion routine for an associated IRP. If a highest-level driver calls IoSetCompletionRoutine for an associated IRP it creates, the I/O Manager does not complete the master IRP if the driver returns STATUS_MORE_PROCESSING_REQUIRED from its IoCompletion routine. In these circumstances, the driver's IoCompletion routine must explicitly complete the master IRP with IoCompleteRequest.

If a driver allocates an I/O stack location of its own in an IRP, the dispatch routine must call IoSetNextIrpStackLocation before it calls IoGetCurrentIrpStackLocation to set up context in its own I/O stack location for the IoCompletion routine. (See Passing IRPs Down the Driver Stack.)

The dispatch routine must call IoMarkIrpPending with the original IRP, but not with any driver-allocated IRPs because the IoCompletion routine will free them.

If the dispatch routine is allocating IRPs for partial transfers and the underlying device driver might control a removable-media device, the dispatch routine must set up the thread context in its newly allocated IRPs from the value at Tail.Overlay.Thread in the original IRP.

An underlying driver for a removable-media device might call IoSetHardErrorOrVerifyDevice, which references the pointer at Irp->Tail.Overlay.Thread, for a driver-allocated IRP. If the driver calls this support routine, the file system driver can send a popup to the appropriate user thread that prompts the user to cancel, retry, or fail an operation that the driver could not satisfy. See Supporting Removable Media for more information.

Dispatch routines must return STATUS_PENDING after sending all driver-allocated IRPs on to lower drivers.

A driver's IoCompletion routine should free all driver-allocated IRPs with IoFreeIrp before it calls IoCompleteRequest for the original IRP. When it completes the original IRP, the IoCompletion routine must free all driver-allocated IRPs before it returns control.

Each higher-level driver sets up any driver-allocated (and reused) IRPs for lower drivers in such a way that it is immaterial to the underlying device driver whether a given request comes from an intermediate driver or originates from any other source, such as a file system or user-mode application.

Highest-level drivers can call IoMakeAssociatedIrp to allocate IRPs and set them up for a chain of lower drivers. The I/O Manager automatically completes the original IRP when all its associated IRPs have been completed, as long as the driver does not call IoSetCompletionRoutine with the original IRP or with any of the associated IRPs it allocates. Highest-level drivers must not, however, allocate associated IRPs for any IRP that requests a buffered I/O operation.

An intermediate-level driver cannot allocate IRPs for lower-level drivers by calling IoMakeAssociatedIrp. Any IRP an intermediate driver receives might already be an associated IRP, and a driver cannot associate another IRP with such an IRP.

Instead, if an intermediate driver creates IRPs for lower drivers, it should call IoAllocateIrp, IoBuildDeviceIoControlRequest, IoBuildSynchronousFsdRequest, or IoBuildAsynchronousFsdRequest. However, IoBuildSynchronousFsdRequest can be called only in the following circumstances:

  • By a driver-created thread to build IRPs for read or write requests, because such a thread can wait in a nonarbitrary thread context (its own) on a dispatcher object, such as a driver-initialized Event passed to IoBuildSynchronousFsdRequest
  • In the system thread context during initialization or while unloading
  • To build IRPs for inherently synchronous operations, such as create, flush, shutdown, close, and device control requests

However, a driver is more likely to call IoBuildDeviceIoControlRequest to allocate device control IRPs than IoBuildSynchronousFsdRequest.


Queuing and Dequeuing IRPs

Because the I/O Manager supports asynchronous I/O within a multitasking and multithreaded system, I/O requests to a device can come in faster than its driver can process them to completion, particularly in multiprocessor machines. Consequently, IRPs bound to any particular device must be queued in the driver when its device is already busy processing another IRP.

Therefore, a lowest-level driver requires one of the following:

  • A StartIo routine, which the I/O Manager calls to start I/O operations for IRPs the driver has queued to a system-supplied IRP queue (see IoStartPacket).
  • An internal IRP-queuing and de-queuing mechanism, which the driver uses to manage IRPs that come in faster than it can satisfy them. Drivers can use device queues, interlocked queues, or cancel-safe queues. For more information, see Driver-Managed IRP Queues.

Only a lowest-level device driver that can satisfy and complete every possible IRP in its dispatch routines needs no StartIo routine and no driver-managed queues for IRPs.

Higher-level drivers almost never have StartIo routines. Most intermediate drivers had neither StartIo routines nor internal queues; an intermediate driver can usually pass IRPs with valid parameters on from its dispatch routines and do whatever post-processing is required for any IRP in its IoCompletion routine.

The following describes, in general, some of the design considerations for determining whether to implement a StartIo routine with or without internal, driver-managed queues for IRPs.

StartIo Routines in Drivers

For PC peripheral devices capable of handling only one device I/O operation at a time, device drivers can implement StartIo routines. For these drivers, the I/O Manager provides IoStartPacket and IoStartNextPacket routines to queue and dequeue IRPs to and from a system-supplied IRP queue.

For more information about StartIo routines, see Writing a StartIo Routine.

Internal Queues for IRPs in Drivers

If an device can support more than one concurrent I/O operation, its lowest-level device driver must set up internal request queues and manage its own queuing of IRPs. For example, the system serial driver maintains separate queues for read, write, purge, and wait operations on its devices because it supports full-duplex serial devices.

A higher-level driver that sends requests to some number of underlying device drivers also might maintain internal queues of IRPs. For example, file system drivers almost always have internal queues for IRPs.

For more information, see Driver-Managed IRP Queues.

Internal Queues with StartIo Routines in Drivers

A driver that manages its own internal queues can also have a StartIo routine, but need not. Most lowest-level device drivers either have a StartIo routine or manage their own queuing of IRPs, but not both.

An exception to this is the SCSI port driver, which has a StartIo routine and manages internal queues of IRPs. The I/O Manager queues IRPs to the port driver's StartIo routine in the device queue associated with the driver-created device object that represents a SCSI HBA. The SCSI port driver also sets up and manages device queues for IRPs to each target device (corresponding to a SCSI logical unit) on any HBA-driven SCSI bus in the machine.

The SCSI port driver uses its supplemental device queues to hold IRPs sent down from the SCSI class drivers in LU-specific queues whenever any device on a SCSI bus is particularly busy. In effect, this driver's supplemental, LU-specific device queues allow the SCSI port driver to serialize operations for heterogeneous SCSI devices through an HBA while keeping each device on that HBA's SCSI bus(es) as busy as possible.

Internal Queues and Driver Threads

Drivers with device-dedicated threads and highest-level drivers that use executive worker threads (including most file system drivers) usually set up an interlocked queue for IRPs. The queue is shared by the driver thread or driver-supplied worker thread callback and by other driver routines that process IRPs.

The driver's dispatch routines insert IRPs into the interlocked queue and a driver-created thread or the driver's worker-thread callback removes them by calling the ExInterlocked..List support routines.

For example, the system floppy controller driver uses an interlocked queue. Its device-dedicated thread handles the same processing of IRPs that is done by other device drivers' StartIo routines and some of the same processing of IRPs that is done by other device drivers' DpcForIsr routines.


Writing a StartIo Routine

As its name suggests, a StartIo routine is responsible for starting an I/O operation on the physical device.

Most lowest-level drivers provide a StartIo routine and rely on the I/O Manager to queue IRPs to a system-supplied device queue. Some lowest-level drivers are designed to set up and manage their own supplemental IRP queues, but even these usually also provide a StartIo routine. (For more information about supplemental queues, see Driver-Managed IRP Queues.)

Higher-level drivers, including FSDs and PnP function and filter drivers, seldom have a StartIo routine because it can hamper performance. Instead, most file system drivers set up and maintain internal queues of IRPs. Other higher-level drivers either have internal queues for IRPs or simply pass IRPs on to lower drivers from their dispatch routines.

This section contains the following topics:

  • StartIo Routines in Lowest-Level Drivers
  • StartIo Routines in Higher-Level Drivers
  • Points to Consider For StartIo Routines


StartIo Routines in Lowest-Level Drivers

The I/O Manager's call to a driver's dispatch routine is the first stage in satisfying a device I/O request. The StartIo routine is the second stage. Every device driver with a StartIo routine is likely to call IoStartPacket from its DispatchRead and DispatchWrite routines, and usually for a subset of the I/O control codes it supports in its DispatchDeviceControl routine. The IoStartPacket routine adds the IRP to the device's system-supplied device queue or, if the queue is empty, immediately calls the driver's StartIo routine to process the IRP.

You can assume that when a driver's StartIo routine is called, the target device is not busy. This is because the I/O manager calls StartIo under two circumstances; either one of the driver's dispatch routines has just called IoStartPacket and the device queue was empty, or the driver's DpcForIsr routine is completing another request and has just called IoStartNextPacket to dequeue the next IRP.

Before the StartIo routine in a highest-level device driver is called, that driver's dispatch routine should have probed and locked down the user buffer, if necessary, to set up valid mapped buffer addresses in the IRP queued to its StartIo routine. If a highest-level device driver sets up its device objects for direct I/O (or for neither buffered nor direct I/O), the driver cannot defer locking down a user buffer to its StartIo routine; every StartIo routine is called in an arbitrary thread context at IRQL DISPATCH_LEVEL.

Keep in mind the following fact:

Any buffer memory to be accessed by a driver's StartIo routine must be locked down or allocated from resident, system-space memory and must be accessible in an arbitrary thread context.

In general, any lower-level device driver's StartIo routine is responsible for calling IoGetCurrentIrpStackLocation with the input IRP and then doing whatever request-specific processing is necessary to start the I/O operation on its device. Request-specific processing can include the following:

  • Setting up or updating any state information about the current request that the driver maintains. The state information might be stored in the device extension of the target device object or elsewhere in nonpaged pool allocated by the driver.

    For example, if a device driver maintains an InterruptExpected Boolean for the current transfer operation, its StartIo routine might set this variable to TRUE. If the driver maintains a time-out counter for the current operation, its StartIo routine might set up this value, or the StartIo routine might queue the driver's CustomTimerDpc routine.

    If the StartIo routine shares access to state information or hardware resources with other driver routines, the state information or resource must be protected by a spin lock. (See Spin Locks.)

    If the StartIo routine shares access to state information or resources with the driver's InterruptService routine, StartIo must use KeSynchronizeExecution to call a SynchCritSection routine that accesses the state or resource information. (See Using Critical Sections.)

  • Assigning a sequence number to the IRP in case the driver must log a device I/O error while processing the IRP

    See Logging Errors for more information.

  • If necessary, translating the parameters in the driver's I/O stack location into device-specific values

    For example, a disk driver might need to calculate the starting sector or byte offset to the physical disk address for a transfer operation, and whether the requested length of the transfer will cross a particular sector boundary or exceed the transfer capacity of its physical device.

  • If the driver controls a removable-media device, checking for media changes before programming the device for I/O and notifying its overlying file system if the media has changed

    For more information, see Supporting Removable Media.

  • If the device uses DMA, checking whether the requested Length (number of bytes to be transferred, found in the driver's I/O stack location of the IRP) should be split into partial-transfer operations, as explained in Input/Output Techniques, assuming a closely coupled higher-level driver does not pre-split large transfers for the device driver

    The StartIo routine of such a device driver also can be responsible for calling KeFlushIoBuffers and, if the driver uses packet-based DMA, for calling AllocateAdapterChannel with the driver's AdapterControl routine.

    See Adapter Objects and DMA, and Maintaining Cache Coherency, for additional details.

  • If the device uses PIO, mapping the base virtual address of the buffer, described in the IRP at Irp->MdlAddress, to a system-space address with MmGetSystemAddressForMdlSafe.

    For read requests, the device driver's StartIo routine can be responsible for calling KeFlushIoBuffers before PIO operations begin. See Maintaining Cache Coherency for more information.

  • If a non-WDM driver uses a controller object, calling IoAllocateController to register its ControllerControl routine
  • If the driver handles cancelable IRPs, checking whether the input IRP has already been canceled
  • If an input IRP can be canceled before it is processed to completion, the StartIo routine must call IoSetCancelRoutine with the IRP and the entry point of the driver's Cancel routine. The StartIo routine must acquire the cancel spin lock for its call to IoSetCancelRoutine.

As a general rule, a driver that uses buffered I/O has a simpler StartIo routine than one that uses direct I/O. Drivers that use buffered I/O transfer small amounts of data for each transfer request, while those that use direct I/O (whether DMA or PIO) transfer large amounts of data to or from locked-down buffers that can span physical page boundaries in system memory.

Higher-level drivers layered above physical device drivers usually set up their device objects to match those of their respective device drivers. However, a highest-level driver, particularly a file system driver, can set up device objects for neither direct nor buffered I/O.

Drivers that set up their device objects for buffered I/O can rely on the I/O Manager to pass valid buffers in all IRPs it sends to the driver. Lower-level drivers that set up device objects for direct I/O can rely on the highest-level driver in their chain to pass valid buffers in all IRPs sent through any intermediate drivers to the underlying lower-level device driver.

Using Buffered I/O in StartIo Routines

If a driver's DispatchRead, DispatchWrite, or DispatchDeviceControl routine determines that a request is valid and calls IoStartPacket, the I/O Manager calls a the driver's StartIo routine to process the IRP immediately if the device queue is empty. If the queue is not empty, IoStartPacket queues the IRP. Eventually, a call to IoStartNextPacket from the driver's DpcForIsr or CustomDpc routine causes the I/O manager to dequeue the IRP and call the driver's StartIo routine.

The StartIo routine calls IoGetCurrentIrpStackLocation and determines which operation must be performed to satisfy the request. It preprocesses the IRP in any way necessary before programming the physical device to carry out the I/O request.

If access to the physical device (or the device extension) must be synchronized with an InterruptService routine, the StartIo routine must call a SynchCritSection routine to perform the necessary device programming. For more information, see Using Critical Sections.

A physical device driver that uses buffered I/O transfers data either to or from a system-space buffer, allocated by the I/O Manager, that the driver finds in each IRP at Irp->AssociatedIrp.SystemBuffer.

Using Direct I/O in StartIo Routines

If a driver's DispatchRead, DispatchWrite, or DispatchDeviceControl routine determines that a request is valid and calls IoStartPacket, the I/O Manager calls a the driver's StartIo routine to process the IRP immediately if the device queue is empty. If the queue is not empty, IoStartPacket queues the IRP. Eventually, a call to IoStartNextPacket from the driver's DpcForIsr or CustomDpc routine causes the I/O manager to dequeue the IRP and call the driver's StartIo routine.

The StartIo routine calls IoGetCurrentIrpStackLocation and determines which operation must be performed to satisfy the request. It preprocesses the IRP in any way necessary, such as splitting up a large DMA transfer request into partial-transfer ranges and saving state about the Length of an incoming transfer request that must be split. Then it programs the physical device to carry out the I/O request.

If access to the physical device (or the device extension) must be synchronized with the driver's ISR, the StartIo routine must use a driver-supplied SynchCritSection routine to perform the necessary programming. For more information, see Using Critical Sections.

Any driver that uses direct I/O either reads data into or writes data from a locked-down buffer, described by a memory descriptor list (MDL), that the driver finds in the IRP at Irp->MdlAddress. Such a driver commonly uses buffered I/O for device control requests. For more information, see Handling I/O Control Requests in StartIo Routines.

As a type defined by, used exclusively by, and changeable by the Memory Manager, all MDLs are opaque to drivers. Consider the following an implementation guideline:

Drivers cannot use the address mappings contained in any MDL, including an MDL at Irp->MdlAddress, directly.

Instead, drivers that use PIO remap user-space buffers by calling MmGetSystemAddressForMdlSafe with the Irp->MdlAddress. Drivers that use DMA also pass Irp->MdlAddress to support routines during their transfer operations to have the buffer addresses remapped to logical ranges for their devices.

Unless a closely coupled higher-level driver pre-splits large DMA transfer requests for the underlying device driver, a lowest-level device driver's StartIo routine must split up each transfer request that is larger than its device can manage in a single transfer operation. Drivers that use system DMA are required to split transfer requests that are too large for the system DMA controller or for their devices to handle in a single transfer operation.

If the device is a slave DMA device, its driver must synchronize transfers through a system DMA controller with a driver-allocated adapter object, representing the DMA channel, and a driver-supplied AdapterControl routine. The driver of a bus master DMA device also must use a driver-allocated adapter object to synchronize its transfers and must supply an AdapterControl routine if it uses the system's packet-based DMA support, or an AdapterListControl routine if it uses the system's scatter/gather support.

Depending on the driver's design, it might synchronize transfer and device control operations on a physical device with a controller object and supply a ControllerControl routine.

See Adapter Objects and DMA and Controller Objects for more information.

Handling I/O Control Requests in StartIo Routines

In general, only a subset of device I/O control requests are passed on from a driver's DispatchDeviceControl or DispatchInternalDeviceControl routine for further processing by the driver's StartIo routine. The driver's StartIo routine only has to handle valid device control requests that require device state changes or return volatile information about the current device state.

Each new driver must support the same set of public I/O control codes as all other drivers for the same kind of device. The system defines public, device-type-specific I/O control codes for IRP_MJ_DEVICE_CONTROL requests as buffered requests.

Consequently, physical device drivers make data transfers to or from a system-space buffer that each driver finds in the IRP at Irp->AssociatedIrp.SystemBuffer for device control requests. Even drivers that set up their device objects for direct I/O use buffered I/O to satisfy device control requests with public I/O control codes.

The definition of each I/O control code determines whether data transferred for that request is buffered. Any privately defined I/O control codes for driver-specific IRP_MJ_INTERNAL_DEVICE_CONTROL requests between paired drivers can define a code with method buffered, method direct, or method neither. As a general rule, any privately defined I/O control code should be defined with method neither if a closely coupled higher-level driver must allocate a buffer for that request.

Programming the Device for I/O Operations

Usually, the StartIo routine in a lowest-level device driver must synchronize access to any memory or device registers it shares with the driver's ISR by using KeSynchronizeExecution to call a driver-supplied SynchCritSection routine. The driver's StartIo routine uses the SynchCritSection routine to actually program the physical device for I/O at DIRQL. For more information, see Using Critical Sections.

Before calling KeSynchronizeExecution, the StartIo routine must do any preprocessing necessary for the request. Preprocessing might include calculating an initial partial-transfer range and saving any state information about the original request for other driver routines.

If a device driver uses DMA, its StartIo routine usually calls AllocateAdapterChannel with a driver-supplied AdapterControl routine. In these circumstances, the StartIo routine postpones the responsibility for programming the physical device to the AdapterControl routine. It, in turn, can call KeSynchronizeExecution to have a driver-supplied SynchCritSection routine program the device for a DMA transfer.


StartIo Routines in Higher-Level Drivers

Any higher-level driver can have a StartIo routine. However, such a driver is unlikely to be interoperable with existing lower-level drivers and is likely to exhibit poor performance characteristics.

A StartIo routine in a higher-level driver has the following effects:

  • Incoming IRPs can be queued by calling IoStartPacket from the driver's Dispatch routine(s) and IoStartNextPacket from its IoCompletion routine(s), thereby causing IRPs to be processed one at a time through the StartIo routine.
  • The driver's I/O throughput could become noticeably slower during periods of heavy I/O demand, because its StartIo routine can become a bottleneck.
  • The driver's StartIo routine calls IoCallDriver with each IRP at IRQL DISPATCH_LEVEL, thereby causing all lower-level drivers' dispatch routines also to run at IRQL DISPATCH_LEVEL. This restricts the set of support routines that lower drivers can call in their dispatch routines. Because most driver writers assume their drivers' dispatch routines run at IRQL < DISPATCH_LEVEL, the higher-level driver is unlikely to be interoperable with many existing lower-level drivers.
  • The StartIo routine reduces overall system throughput because it and the dispatch routines of all lower-level drivers in its chain are run at raised IRQL.

    For more information about the IRQLs at which standard driver routines are run, see Managing Hardware Priorities.

None of the system-supplied higher-level drivers has a StartIo routine, because it can slow IRP processing for the driver itself, for all drivers above and below it, and for the system overall.

Most higher-level drivers simply send IRPs to lower-level drivers from their dispatch routines and do any necessary clean-up processing in their IoCompletion routines.

However, higher-level drivers can set up internal queues for IRPs that request particular kinds of operations, or set up internal queues to hold IRPs bound for a set of heterogeneous underlying devices like the SCSI port driver. For more information, see Queuing and Dequeuing IRPs.


Points to Consider For StartIo Routines

Keep the following points in mind when implementing a StartIo routine:

  • A StartIo routine must synchronize its access to a physical device and to any shared state information or resources that the driver maintains in the device extension with the driver's other routines that access the same device, memory location, or resources.

    If the StartIo routine shares the device or state with the ISR, it must use KeSynchronizeExecution to call a driver-supplied SynchCritSection routine to program the device or to access the shared state. For more information, see Using Critical Sections.

    If the StartIo routine shares state or resources with routines other than the ISR, it must protect the shared state or resources with a driver-initialized executive spin lock for which the driver provides the storage. For more information, see Spin Locks.

  • If a monolithic non-WDM device driver sets up a controller object, its StartIo routine can use the controller object to synchronize operations through a shared physical device with attached (similar) devices.

    See Controller Objects for more information.

  • Unless a closely coupled higher-level driver pre-splits large DMA transfer requests for its underlying device driver, the underlying device driver's StartIo routine must split large transfer requests into partial-transfer ranges and the driver must carry out a sequence of partial-transfer device operations. Each partial transfer must be sized to suit the capabilities of the hardware: either the capabilities of the driver's device or, for a slave DMA device, the capabilities of the system DMA controller, whichever has stricter constraints.

    See Adapter Objects and DMA for more information about using system or busmaster DMA.

  • The StartIo routine of a driver that uses DMA must synchronize transfers using an adapter object.
  • A StartIo routine is run at IRQL DISPATCH_LEVEL, which restricts the set of support routines it can call.

    For example, a StartIo routine can neither access nor allocate pageable memory, and it cannot wait on a dispatcher object. On the other hand, a StartIo routine can acquire and release a driver-allocated executive spin lock with KeAcquireSpinLockAtDpcLevel and KeReleaseSpinLockFromDpcLevel, which run faster than KeAcquireSpinLock and KeReleaseSpinLock.

    See Managing Hardware Priorities and Spin Locks for more information.

  • If the driver holds IRPs in a cancelable state, its StartIo routine must check whether the input IRP has already been canceled before it begins any processing for that request on its device. For more information, see Canceling IRPs.


Driver-Managed IRP Queues

Except for file system drivers, the I/O Manager associates a device queue object (for queuing IRPs) with each device object that a driver creates.

Most device drivers call the I/O Manager's support routines to use the associated device queue, which holds IRPs whenever device I/O requests for a target device object come in faster than the driver can process them to completion. With this technique, IRPs are queued to a driver-supplied StartIo routine.

For good performance, most intermediate drivers simply pass IRPs on to lower drivers as fast as they come in, so intermediate drivers almost never use the device queues associated with their respective device objects.

However, you can design a driver to manage internal queues of IRPs by explicitly setting up one or more device queues, interlocked queues, or cancel-safe queues. This approach can be particularly useful if the driver controls a device that overlaps I/O operations. For such a device, it can be difficult to manage concurrent processing of two or more IRPs for the same target device object using only a single queue.

You also might opt to set up supplemental queues for IRPs in the driver of a device controller for a set of heterogeneous physical devices.

For example, the SCSI port driver uses device queue objects for internal queues. This driver both has a StartIo routine and sets up device queue objects as supplemental queues, in addition to the device queue associated with the device object it creates to represent an HBA. The SCSI port driver uses its supplemental device queues to hold IRPs bound for particular logical units on the HBA-controlled SCSI bus(es).

The system floppy controller driver is an example of a driver that has no StartIo routine and uses an interlocked queue. This driver sets up a doubly linked interlocked queue into which and from which the driver and its device-dedicated thread insert and remove IRPs.

The Kernel defines the device queue object type. The Executive Support component provides routines for inserting and removing IRPs in interlocked queues. Drivers for Windows XP and later operating systems can use cancel-safe IRP queues to handle IRP queuing.

The following sections explain how to use device queues, interlocked queues, and cancel-safe queues:

Setting Up and Using Device Queues

Managing Device Queues

Setting Up and Using Interlocked Queues

Managing Interlocked Queues with a Driver-Created Thread

Cancel-Safe IRP Queues


Setting up and Using Device Queues

A driver sets up a device queue object by calling KeInitializeDeviceQueue at driver or device initialization. After starting its device(s), the driver inserts IRPs into this queue by calling KeInsertDeviceQueue or KeInsertByKeyDeviceQueue. The following figure illustrates these calls.

Using a Device Queue Object

As the previous figure shows, the driver must provide the storage for a device queue object, which must be resident. Drivers that set up a device queue object usually provide the necessary storage in the device extension of a driver-created device object, but the storage can be in a controller extension if the driver uses a controller object or in nonpaged pool allocated by the driver.

If the driver provides storage for the device queue object in a device extension, it calls KeInitializeDeviceQueue after creating the device object and before starting the device. In other words, the driver can initialize the queue from its AddDevice routine or when it handles a PnP IRP_MN_START_DEVICE request. In the call to KeInitializeDeviceQueue, the driver passes a pointer to the storage it provides for the device queue object.

After starting its device(s), the driver can insert an IRP into its device queue by calling KeInsertDeviceQueue, which places the IRP at the tail of the queue, or KeInsertByKeyDeviceQueue, which places the IRP into the queue according to a driver-determined SortKey value, as shown in the previous figure.

Each of these support routines returns a Boolean value indicating whether the IRP was inserted into the queue. Each of these calls also sets the state of the device queue object to Busy if the queue is currently empty (Not-Busy). However, if the queue is empty (Not-Busy), neither KeInsert..DeviceQueue routine inserts the IRP into the queue. Instead, it sets the state of the device queue object to Busy and returns FALSE. Because the IRP has not been queued, the driver must pass it on to another driver routine for further processing.

When setting up supplemental device queues, follow this implementation guideline:

When a call to KeInsert..DeviceQueue returns FALSE, the caller must pass the IRP it attempted to queue on for further processing to another driver routine.

However, the call to KeInsert..DeviceQueue changes the state of the device queue object to Busy, so the next IRP to come in is inserted in the queue unless the driver calls KeRemove..DeviceQueue first.

When the device queue object's state is set to Busy, the driver can dequeue an IRP for further processing or reset the state to Not-Busy by calling one of the following support routines:

  • KeRemoveDeviceQueue to remove the IRP at the head of the queue
  • KeRemoveByKeyDeviceQueue to remove an IRP chosen according to a driver-determined SortKey value
  • KeRemoveEntryDeviceQueue to remove a particular IRP in the queue or to determine whether a particular IRP is in the queue

    KeRemoveEntryDeviceQueue returns a Boolean indicating whether the IRP was in the device queue.

Calling any of these routines to remove an entry from a device queue that is empty but Busy changes the queue state to Not-Busy.

Each device queue object is protected by a built-in executive spin lock (not shown in the previous figure). As a result, a driver can insert IRPs into the queue and remove them in a multiprocessor-safe manner from any driver routine running at less than or equal to IRQL DISPATCH_LEVEL. Because of this IRQL restriction, a driver cannot call any Ke..DeviceQueue routine from its ISR or SynchCritSection routines, which run at DIRQL.

See Managing Hardware Priorities and Spin Locks for more information. For IRQL requirements for a specific support routine, see the routine's reference page.


Managing Device Queues

The I/O Manager usually (except for FSDs) creates an associated device queue object when a driver calls IoCreateDevice. It also provides IoStartPacket and IoStartNextPacket, which drivers can call to have the I/O Manager insert IRPs into the associated device queue or call their StartIo routines.

Consequently, it is rarely necessary (or particularly useful) for a driver to set up its own device queue objects for IRPs. Likely candidates are drivers, such as the SCSI port driver, that must coordinate incoming IRPs from some number of closely coupled class drivers for heterogeneous devices that are serviced through a single controller or bus adapter.

In other words, a driver for a disk array controller is more likely to use a driver-created controller object than to set up supplemental device queue object(s), while a driver for an add-on bus adapter and of a set of class drivers is slightly more likely to use supplemental device queues.

Using Supplemental Device Queues with a StartIo Routine

By calling IoStartPacket and IoStartNextPacket, a driver's Dispatch and DpcForIsr (or CustomDpc) routines synchronize calls to its StartIo routine using the device queue that the I/O Manager created when the driver created the device object. For a port driver with a StartIo routine, IoStartPacket and IoStartNextPacket insert and remove IRPs in the device queue for the port driver's shared device controller/adapter. If the port driver also sets up supplemental device queues to hold requests coming in from closely coupled higher-level class drivers, it must "sort" incoming IRPs into its supplemental device queues, usually in its StartIo routine.

The port driver must determine which supplemental device queue each IRP belongs in before trying to insert that IRP into the appropriate queue. A pointer to the target device object is passed with the IRP to the driver's Dispatch routine. The driver should save the pointer for use in "sorting" the incoming IRPs. Note that the device object pointer passed to the StartIo routine is the driver's own device object, which represents the device controller/adapter, so it cannot be used for this purpose.

After queuing any IRPs, the driver programs its shared controller/adapter to carry out the request. Thus, the port driver can process incoming requests for all devices on a first-come, first-served basis until a call to KeInsertDeviceQueue puts an IRP into a particular class driver's device queue.

By using its own device queue for all IRPs to be processed through its StartIo routine, the underlying port driver serializes operations through the shared device (or bus) controller/adapter to all attached devices. By sometimes holding IRPs for each supported device in a separate device queue, this port driver inhibits the processing of IRPs for an already busy device while increasing I/O throughput for every other device that does I/O through its shared hardware.

In response to the call to IoStartPacket from the port driver's Dispatch routine, the I/O Manager either calls that driver's StartIo routine immediately or puts the IRP into the device queue associated with the device object for the port driver's shared controller/adapter.

The port driver must maintain its own state information about each of the heterogeneous devices that it services through the shared device controller/adapter.

Keep in mind the following when designing class/port drivers with supplemental device queues:

  • A driver cannot easily get a pointer to a device object created by any driver layered above itself, except for the device object at the top of its device stack.

    By design, the I/O Manager does not provide a support routine for getting such a pointer. Moreover, the order in which drivers are loaded makes it impossible for lower drivers to get pointers for higher-level drivers' device objects, which have not yet been created when any lower-level driver is adding its device.

    Although IoGetAtttachedDeviceReference returns a pointer to the highest-level device object in a driver's stack, a driver should use this pointer only to designate a target for I/O requests to its stack. A driver should not attempt to read or write the device object.

  • A driver cannot use a pointer to a device object created by any driver layered above itself, except to send requests to the top of its own device stack.

    There is no way to synchronize access to a single device object (and its device extension) between two drivers in a multiprocessor-safe manner. Neither driver can make any assumptions about what I/O processing the other driver is currently doing.

Even for closely coupled class/port drivers, each class driver should use the pointer to the port driver's device object(s) only to pass on IRPs using IoCallDriver. The underlying port driver must maintain its own state, probably in the port driver's device extension, about requests that it processes for any closely coupled class driver(s)' device(s).

Managing Supplemental Device Queues Across Driver Routines

Any port driver that queues IRPs in supplemental device queues for a closely coupled set of class drivers also must handle the following situation efficiently:

  1. Its Dispatch routines have inserted IRPs for a particular device in the driver-created device queue for that device.
  2. IRPs for other devices continue to come in, to be queued to the driver's StartIo routine with IoStartPacket, and to be processed through the shared device controller.
  3. The device controller does not become idle, but each IRP held in the driver-created device queue also must be queued to the driver's StartIo routine as soon as possible.

Consequently, the port driver's DpcForIsr routine must attempt to transfer an IRP from the driver's internal device queue for a particular device into the device queue for the shared adapter/controller whenever the port driver completes an IRP, as follows:

  1. The DpcForIsr routine calls IoStartNextPacket to have the StartIo routine begin processing the next IRP queued to the shared device controller.
  2. The DpcForIsr routine calls KeRemoveDeviceQueue to dequeue the next IRP (if any) that it is holding in its internal device queue for the device on whose behalf it is about to complete an IRP.
  3. If KeRemoveDeviceQueue returns a nonNULL pointer, the DpcForIsr routine calls IoStartPacket with the just dequeued IRP to have it queued to the shared device controller/adapter. Otherwise, the call to KeRemoveDeviceQueue simply resets the state of the device queue object to Not-Busy, and the DpcForIsr routine omits the call to IoStartPacket.
  4. Then, the DpcForIsr routine calls IoCompleteRequest with the input IRP for which the port driver has just completed I/O processing, either by setting the I/O status block with an error or by satisfying the I/O request.

Note that the preceding sequence implies that the DpcForIsr routine also must determine the device for which it is completing the current (input) IRP in order to manage internal queuing of IRPs efficiently.

If the port driver attempts to wait until its shared controller/adapter is idle before dequeuing IRPs held in its supplemental device queues, the driver might starve a device for which there was heavy I/O demand while it promptly serviced every other device for which the current I/O demand was actually much lighter.


Setting up and Using Interlocked Queues

Drivers with device-dedicated threads or drivers that use executive worker threads, such as most system FSDs, are the most likely types of drivers to manage their own run-time internal queuing of IRPs in an interlocked queue. All PnP drivers, including WDM drivers, also must queue certain IRPs internally while making PnP and power state transitions.

Usually, these drivers set up a doubly linked interlocked queue; every IRP contains a member of type LIST_ENTRY, which a driver can use to doubly link IRPs that it is currently holding. A driver cannot requeue IRPs for retries if it sets up a singly linked interlocked queue.

A driver must set up its interlocked queue at device initialization. The following figure illustrates a doubly linked interlocked queue, the support routines a driver must call to set up such a queue, and a set of ExInterlocked Xxx routines a driver can call to insert IRPs into and remove IRPs from the queue.

Using an Interlocked Queue

As the previous figure shows, a driver must provide the storage for the queue itself and for the following in order to set up a doubly linked interlocked queue:

  • An executive spin lock, which the driver must call KeInitializeSpinLock to initialize. Usually, a driver initializes the spin lock when it sets up the device extension(s) for its device object(s) in its AddDevice routine.
  • The list head for the queue, which the driver must initialize by calling InitializeListHead.

Most drivers that use doubly linked interlocked queues provide the necessary storage in the device extension of a driver-created device object. The queue and executive spin lock can instead be in a controller extension if the driver uses a controller object) or in nonpaged pool allocated by the driver.

While the driver is accepting I/O requests, it can insert an IRP into its queue by calling either of the following support routines if the ListHead is of type LIST_ENTRY, as shown in the previous figure:

  • ExInterlockedInsertTailList to place the IRP at the end of the queue
  • ExInterlockedInsertHeadList to place the IRP at the front of the queue. Drivers usually call this routine only when they must retry a particular request.

The driver must pass pointers to the IRP (ListEntry), as well the ListHead and executive spin lock (Lock) pointers that it previously initialized, to each of these ExInterlockedInsert..List routines. Only pointers to the ListHead and Lock are required when the driver dequeues an IRP by calling ExInterlockedRemoveHeadList. To prevent deadlocks, the driver must not be holding an ExecutiveSpinLock that it passes to any ExInterlocked Xxx routine.

Because an interlocked queue is protected by the executive spin lock, the driver can insert IRPs into its doubly linked queue and remove them in a multiprocessor-safe manner from any driver routine running at less than or equal to IRQL DISPATCH_LEVEL.

A queue with a ListHead of type LIST_ENTRY, as shown in the previous figure, is a doubly linked list. One with a ListHead of type SLIST_HEADER is a sequenced, singly linked list. A driver initializes the ListHead for a sequenced singly linked interlocked queue by calling ExInitializeSListHead.

A driver that never retries I/O operations can use ExInterlockedPushEntrySList and ExInterlockedPopEntrySList to manage its queuing of IRPs internally in a sequenced, singly linked interlocked queue. Any driver that uses this type of interlocked queue also must provide resident storage for a ListHead of type SLIST_HEADER and for an ExecutiveSpinLock, as shown in the previous figure. It must initialize the spin lock and set up its queue before calling ExInterlockedPushEntrySList to insert the initial entry into its queue.

For more information, see Managing Hardware Priorities and Spin Locks. For IRQL requirements for a specific support routine, see the routine's reference page.


Managing Interlocked Queues with a Driver-Created Thread

Like the system floppy controller driver, a driver with a device-dedicated thread, rather than a StartIo routine, usually manages its own queuing of IRPs in a doubly linked interlocked queue. The driver's thread pulls IRPs from its interlocked queue when there is work to be done on the device.

In general, the driver must manage synchronization with its thread to any resources shared between the thread and other driver routines. The driver also must have some way to notify its driver-created thread that IRPs are queued. Usually, the thread waits on a dispatcher object, stored in the device extension, until the driver's Dispatch routines set the dispatcher object to the Signaled state after inserting an IRP into the interlocked queue.

When the driver's Dispatch routines are called, each checks the parameters in the I/O stack location of the input IRP and, if they are valid, queues the request for further processing. For each IRP queued to a driver-dedicated thread, the dispatch routine should set up whatever context its thread needs to process that IRP before it calls ExInterlockedInsert..List. The driver's I/O stack location in each IRP gives the driver's thread access to the device extension of the target device object, where the driver can share context information with its thread, as the thread removes each IRP from the queue.

Any driver-created thread runs at IRQL PASSIVE_LEVEL and at a base runtime priority previously set when the driver called PsCreateSystemThread. The thread's call to ExInterlockedRemoveHeadList temporarily raises the IRQL to DISPATCH_LEVEL on the current processor while the IRP is being removed from the driver's internal queue. The original IRQL is restored to PASSIVE_LEVEL on return from this call.

Any driver thread (or driver-supplied worker-thread callback) must manage the IRQLs at which it runs carefully. For example, consider the following:

  • Because system threads generally run at IRQL PASSIVE_LEVEL, it is possible for a driver thread to wait on Kernel-defined dispatcher objects.

    For example, a device-dedicated thread might wait on an event for other driver routines to satisfy and complete some number of partial-transfer IRPs that the thread sets up with IoBuildSynchronousFsdRequest.

  • However, such a device-dedicated thread must raise IRQL on the current processor before it calls certain support routines.

    For example, if a driver uses DMA, its device-dedicated thread must nest its calls to AllocateAdapterChannel and FreeAdapterChannel between calls to KeRaiseIrql and KeLowerIrql because these routines and certain other support routines for DMA operations must be called at IRQL DISPATCH_LEVEL.

    Remember that StartIo routines are run at DISPATCH_LEVEL, so drivers that use DMA need not make calls to the Ke..Irql routines from their StartIo routines.

  • A driver-created thread can access pageable memory because it runs in a nonarbitrary thread context (its own) at IRQL PASSIVE_LEVEL, but many other standard driver routines run at raised IRQL.

    Consequently, if a driver-created thread allocates memory that can be accessed by other driver routines, it must allocate the memory from nonpaged pool. For example, if a device-dedicated thread allocates any buffer that will be accessed later by the driver's ISR or SynchCritSection, AdapterControl, AdapterListControl, ControllerControl, DpcForIsr, CustomDpc, IoTimer, CustomTimerDpc, or, in a higher-level driver, IoCompletion routine, the thread-allocated memory cannot be pageable.

  • If the driver maintains shared state information or resources in a device extension, a driver thread (like a StartIo routine) must synchronize its access to a physical device and to the shared data with the driver's other routines that access the same device, memory location, or resources.

    If the thread shares the device or state with the ISR, it must use KeSynchronizeExecution to call a driver-supplied SynchCritSection routine to program the device or to access the shared state. See Using Critical Sections.

    If the thread shares state or resources with routines other than the ISR, the driver must protect the shared state or resources with a driver-initialized executive spin lock for which the driver provides the storage. For more information, see Spin Locks.

For more information about the design tradeoffs of a using a driver thread for a slow device, see Polling a Device. See also Managing Hardware Priorities. For specific information about IRQLs for particular support routines, see the routine's reference page.


Cancel-Safe IRP Queues

On Windows® XP and later operating systems, drivers can use cancel-safe IRP queues to implement IRP queuing. Cancel-safe IRP queues split IRP handling into two parts:

  1. Whenever drivers are required to manipulate the IRP queue, they use one of the IoCsqXxx system routines. See Using the Cancel-Safe IRP Queue for details.
  2. The system handles all synchronization and IRP canceling logic inside the IoCsqXxx routines. For driver-specific functionality, it dispatches to routines provided by the driver. See Implementing the Cancel-Safe IRP Queue for details.

Drivers that use cancel-safe IRP queues do not implement Cancel routines to support IRP cancellation.

A complete sample of how to use cancel-safe IRP queues is available in the src\general\cancel directory of the DDK.

Using the Cancel-Safe IRP Queue

Drivers use the following system routines when queuing and dequeuing IRPs.

  • IoCsqInsertIrp to insert an IRP into the queue.
  • IoCsqRemoveNextIrp to remove the next IRP in the queue. The driver can optionally specify a key value.
  • IoCsqRemoveIrp to remove the specified IRP from the queue.

These routines, in turn, dispatch to driver-supplied routines.

There are several natural ways to use the IoCsqXxxIrp routines to queue and dequeue IRPs. For example, a driver could simply use the IRP queue as a FIFO. The driver could queue an IRP as follows:

    IoCsqInsertIrp(IoCsq, Irp, NULL);

If the driver is not required to distinguish between particular IRPs, it could then simply dequeue them in the order they were queued, as follows:

    IoCsqRemoveNextIrp(IoCsq, NULL);

Alternatively, the driver could queue and dequeue specific IRPs. The routines use the opaque IO_CSQ_IRP_CONTEXT structure to identify particular IRPs in the queue. The driver queues the IRP as follows:

    IO_CSQ_IRP_CONTEXT ParticularIrpInQueue;
    IoCsqInsertIrp(IoCsq, Irp, &ParticularIrpInQueue);

The driver can then dequeue the same IRP by using the IO_CSQ_IRP_CONTEXT value.

    IoCsqRemoveIrp(IoCsq, Irp, &ParticularIrpInQueue);

The driver might also require to remove IRPs from the queue based on a particular criterion. For example, the driver might associate a priority to each IRP, such that higher priority IRPs get dequeued first. The driver might pass a PeekContext value to IoCsqRemoveNextIrp, which the system passes back to the driver when it requests the next IRP in the queue.

Implementing the Cancel-Safe IRP Queue

To implement a cancel-safe IRP queue, drivers must provide the following routines:

  • An XxxCsqInsertIrp routine that inserts IRPs into the queue.
  • An XxxCsqRemoveIrp routine that removes the specified IRP from the queue.
  • An XxxCsqPeekNextIrp routine that returns a pointer to the next IRP in the queue, following the specified IRP. This is where the system passes the PeekContext value it receives from IoCsqRemoveNextIrp. The driver can interpret that value in any way.
  • XxxCsqAcquireLock and XxxCsqReleaseLock routines to allow the system to lock and unlock the IRP queue.
  • An XxxCompleteCanceledIrp routine that completes a canceled IRP.

The driver writer has complete implementation freedom in providing an IRP queuing mechanism, as long as the appropriate dispatch routines can be provided. For example, the driver could implement the queue as a linked list, or as a priority queue.

Pointers to the driver's routines are stored in an IO_CSQ structure that serves as a dispatch table. Use the IoCsqInitialize routine to initialize the dispatch table. A pointer to the IO_CSQ structure must be passed to each IoCsqXxxIrp routine. Each such routine uses the dispatch table to delegate driver-specific operations. The IO_CSQ structure is guaranteed to remain a fixed size, so a driver can safely embed the structure inside its device extension.

The system automatically locks and unlocks the queue as necessary. Drivers do not implement any locking inside their XxxCsqInsertIrp, XxxCsqRemoveIrp, and XxxCsqPeekNextIrp routines.

Drivers can use any of the operating system's synchronization primitives to implement their XxxCsqAcquireLock and XxxCsqReleaseLock routines, such as Spin Locks or Mutex Objects.

Here is an example of how a driver can implement locking with spin locks.

/*
  The driver has previously initialized the SpinLock variable with
  KeInitializeSpinLock.
 */

XxxCsqAcquireLock(PIO_CSQ IoCsq, PKIRQL PIrql)
{
    KeAcquireSpinLock(SpinLock, PIrql);
}

XxxCsqReleaseLock(PIO_CSQ IoCsq, PKIRQL PIrql)
{
    KeReleaseSpinLock(SpinLock, PIrql);
}

To enable the driver to correctly use a spin lock, when the system locks and unlocks the queue, it passes a pointer to the same memory location in the second parameter of XxxCsqAcquireLock and XxxCsqRemoveLock.

Drivers are not required to use spin locks. For example, the driver could use a mutex to lock the queue. See Synchronization Techniques for a description of the synchronization techniques available to drivers.


Completing IRPs

"Completing an IRP" is a shorthand phrase that means "allowing all members of the driver stack to complete an I/O operation". After the IRP has been completed, the I/O manager notifies the initiating application that the requested I/O operation has finished.

When a driver has finished processing an IRP, it calls IoCompleteRequest (typically from within a DpcForIsr routine). This causes the I/O Manager to determine whether any higher-level drivers have set up IoCompletion routines for the IRP. If so, each IoCompletion routine is called, in turn, until every layered driver in the chain has completed the IRP.

When all drivers have completed the IRP, the I/O Manager returns status to the original requester of the operation. Note that a higher-level driver that sets up a driver-created IRP must supply an IoCompletion routine to release the IRP it created.


When to Complete an IRP

A driver should initiate IRP completion when any of the following conditions is met:

  • The driver determines that IRP processing cannot progress because of invalid parameters or other conditions.
  • The driver is able to handle the requested I/O operation without passing the IRP down the driver stack, and the operation has finished.
  • The IRP is being canceled. (See Canceling IRPs.)

If these conditions are not met, a driver's dispatch routine must pass the IRP down to the next-lower driver, or it must handle processing of the I/O request. If one of the conditions is met, the driver must call IoCompleteRequest.

If a driver completes a request because processing cannot progress, or if it completes a request by handling the requested operation without actually accessing the device, it typically calls IoCompleteRequest from one of its dispatch routines. For more information, see Completing IRPs in Dispatch Routines.

If a driver must access a device to satisfy the request, it typically calls IoCompleteRequest from a DpcForIsr routine. These routines are discussed extensively in Servicing Interrupts.


Completing IRPs in Dispatch Routines

This section describes completing IRPs in dispatch routines, and contains the following topics:

How to Complete an IRP in a Dispatch Routine

When to Complete an IRP in a Dispatch Routine


How to Complete an IRP in a Dispatch Routine

If an input IRP can be completed immediately, a dispatch routine does the following:

  1. Sets the Status and Information members of the IRP's I/O status block with appropriate values, in general:
    • The dispatch routine sets Status either to STATUS_SUCCESS or to an appropriate error STATUS_XXX, which can be the value returned by a call to a support routine or, for certain synchronous requests, by a lower driver.

      If a lower-level driver returns STATUS_PENDING, a higher-level driver should not call IoCompleteRequest with an IRP unless it calls IoMarkIrpPending with that IRP first. However, a higher-level driver's dispatch routine is unlikely to complete any IRP for which lower driver(s) return STATUS_PENDING.

    • It sets Information to the number of bytes successfully transferred if a request to transfer data, such as a read or write request, was satisfied.
    • It sets Information to a value that varies according to the specific request for other IRPs that it completes with STATUS_SUCCESS.
    • It sets Information to a value that varies according to the specific request for IRPs that it completes with a warning STATUS_XXX. For example, it would set Information to the number of bytes transferred for such a warning as STATUS_BUFFER_OVERFLOW.
    • Usually, it sets Information to zero for requests that it completes with an error STATUS_XXX.
  2. Calls IoCompleteRequest with the IRP and the PriorityBoost IO_NO_INCREMENT.
  3. Returns the appropriate STATUS_XXX that it already set in the I/O status block. Note that a call to IoCompleteRequest makes the given IRP inaccessible by the caller, so the return value from a dispatch routine cannot be set from the I/O status block of an already completed IRP.

Follow this implementation guideline for calling IoCompleteRequest with an IRP:

Always release any spin lock(s) the driver is holding before calling IoCompleteRequest.

It takes an indeterminate amount of time to complete an IRP, particularly in a chain of layered drivers. Moreover, a deadlock can occur if a higher-level driver's IoCompletion routine sends an IRP back down to a lower driver that is holding a spin lock.


When to Complete an IRP in a Dispatch Routine

Usually, drivers do not complete IRPs in their dispatch routines unless the parameters for the given request are invalid or, in a device driver, unless the particular IRP_MJ_XXX requires no device I/O operations.

Every driver in a chain of layered drivers can check the validity of parameters in its own I/O stack location, for each IRP received by the driver's dispatch routines. Completing IRPs with invalid parameters in the dispatch routine of the highest possible driver improves I/O throughput for any chain of drivers and for the system overall.

A dispatch routine in a higher-level driver should either complete an IRP or pass it on for processing by lower drivers, according to the following guidelines:

  • If the dispatch routine determines that any parameters in its own I/O stack location are invalid, it should complete that IRP immediately with an appropriate error status, such as STATUS_INVALID_PARAMETER.
  • If the IRP contains the function code IRP_MJ_CLEANUP, the DispatchCleanup routine must complete every IRP currently queued to the target device object, for the file object specified in the driver's I/O stack location, and complete the cleanup IRP.

    A cleanup request indicates that an application is being terminated or has closed a file handle for the file object that represents the driver's device object. When the DispatchCleanup routine returns, usually the driver's DispatchClose routine is called next.

  • Otherwise, a higher-level driver can satisfy the request only by passing it on to the next-lower driver.

A dispatch routine in a lowest-level driver should complete an IRP according to the following guidelines:

  • If the dispatch routine determines that any parameters in its own I/O stack location are invalid, it should complete that IRP immediately with an appropriate error status.

    Usually, any higher-level driver has already checked the parameters for a requested operation, but lowest-level device drivers can perform their own parameters checks as well. Lowest-level device drivers typically need not check the parameters of IRP_MJ_INTERNAL_DEVICE_CONTROL requests, because a closely coupled higher-level driver is responsible for setting up the parameters for these requests.

  • If the IRP contains the function code IRP_MJ_CLEANUP, the DispatchCleanup routine must complete every IRP currently queued to the target device object, for the given file object in the driver's I/O stack location, and then complete the cleanup IRP.

    A cleanup request indicates that an application is being terminated or has closed a file handle for the file object that represents the driver's device object. When the DispatchCleanup routine returns, usually the driver's DispatchClose routine is called next.

  • If the request requires no device I/O operation, the dispatch routine should satisfy the request and complete the IRP.

    For example, a driver might save the current mode of its device in the device extension, particularly if it seldom changes device modes after initialization. Its DispatchDeviceControl routine could then satisfy a request that queried the current device mode by returning this stored information.

Otherwise, the dispatch routine must call IoMarkIrpPending, queue the IRP to other driver routines for further processing, and return STATUS_PENDING.


Using IoCompletion Routines

Higher-level drivers that monitor on an IRP-specific basis how lower-level drivers carried out particular requests can have one or more IoCompletion routines. Higher-level drivers that allocate IRPs to send requests to lower drivers must have an IoCompletion routine.

A highest-level or intermediate driver's DispatchRead or DispatchWrite routine is most likely to set an IoCompletion routine for an IRP, because lower-level drivers must handle transfer requests asynchronously.

The lowest-level driver in a driver stack cannot register IoCompletion routines.

Drivers generally do not register IoCompletion routines for IRPs associated with synchronous I/O operations. For instance, a higher-level driver's DispatchDeviceControl routine can allocate an IRP using IoBuildDeviceIoControlRequest. In this case the dispatch routine typically doesn't register an IoCompletion routine, because device control requests are generally handled synchronously. Instead, the driver can allocate and initialize an event object, and its DispatchDeviceControl routine can wait on an event when it sends on driver-allocated IRPs. Usually, a higher-level driver does not register an IoCompletion routine for an IRP allocated with IoBuildSynchronousFsdRequest, for the same reason.


Registering an IoCompletion Routine

To register an IoCompletion routine, a dispatch routine calls IoSetCompletionRoutine, supplying the IoCompletion routine's address and the IRP that it will subsequently pass on to lower drivers using IoCallDriver.

When it calls IoSetCompletionRoutine, the dispatch routine specifies the circumstances in which the I/O manager should call the specified IoCompletion routine. You can choose to have the IoCompletion routine called if a lower level driver completes the IRP successfully (InvokeOnSuccess), completes the IRP with an error status value (InvokeOnError), or cancels the IRP (InvokeOnCancel), in any combination.

The purpose of an IoCompletion routine is to monitor what lower-level drivers did with the IRP and to do additional completion processing, if necessary. Specifically, the most common uses for a driver's IoCompletion routines are the following:

  • To dispose of an IRP that the driver allocated with IoAllocateIrp or IoBuildAsynchronousFsdRequest

    Any higher-level driver that allocates an IRP using either of these support routines must supply an IoCompletion routine for that IRP. The IoCompletion routine must call IoFreeIrp to dispose of driver-allocated IRPs.

  • To reuse an incoming IRP to request that lower drivers complete some number of operations, such as partial transfers, until the original request can be satisfied and completed by the IoCompletion routine
  • To retry a request that a lower driver completed with an error

    Highest-level drivers, such as file systems, are more likely to have IoCompletion routines that attempt to retry requests than are intermediate drivers, except possibly class drivers layered above a closely coupled port driver. However, any intermediate driver use IoCompletion routines to retry requests.

While a highest-level or intermediate driver's DispatchReadWrite routine is most likely to process IRPs that require an IoCompletion routine, any dispatch routine in any driver that passes IRPs on to lower drivers can register an IoCompletion routine.

For driver-allocated IRPs and reused IRPs, the dispatch routine must call IoSetCompletionRoutine with the following Boolean parameters:

  • InvokeOnSuccess set to TRUE
  • InvokeOnError set to TRUE
  • InvokeOnCancel set to TRUE if any lower driver in the chain might handle cancelable IRPs

    Usually, InvokeOnCancel is set to TRUE, whether or not an IRP might be returned with STATUS_CANCELLED, to ensure that the IoCompletion routine frees each driver-allocated IRP or checks the completion status of each reuse of an IRP.

A dispatch routine that allocates IRPs for lower drivers using IoAllocateIrp or IoBuildAsynchronousFsdRequest must set an IoCompletion routine for each driver-allocated IRP.

  • The dispatch routine must set up state about both the original IRP and its allocated IRP(s) for the IoCompletion routine to use. At a minimum, the IoCompletion routine needs access to the original IRP and a count of how many additional IRPs were allocated.
  • The dispatch routine should call IoSetCompletion Routine with all InvokeOnXxx parameters set to TRUE for the IRP(s) it allocates.

A dispatch routine that reuses IRPs for a sequence of operations, or that retries I/O operation, must call IoSetCompletionRoutine for each IRP that will be reused or retried.

  • The dispatch routine must save the original IRP's state information, for subsequent use by the IoCompletion routine.

    For example, a DispatchReadWrite routine must save the relevant transfer parameters of an input IRP for the IoCompletion routine before setting up a partial transfer for the next-lower driver in that IRP. Saving the parameters is particularly important if the DispatchReadWrite routine modifies any parameters that the IoCompletion routine needs to determine when the original request has been satisfied.

  • If the IoCompletion routine can retry the request, the dispatch routine must set up a driver-determined upper limit for the number of retries its IoCompletion routine should attempt before it completes the original IRP with an error.
  • If an IRP is to be reused, the dispatch routine should call IoSetCompletionRoutine with all InvokeOnXxx parameters set to TRUE.
  • For an asynchronous request, the dispatch routine of any intermediate driver must call IoMarkIrpPending for the original IRP. It must then return STATUS_PENDING after it has sent the IRP on to lower drivers.


Implementing an IoCompletion Routine

On entry, an IoCompletion routine receives a Context pointer. When a dispatch routine calls IoSetCompletionRoutine, it can supply a Context pointer. This pointer can reference whatever driver-determined context information the IoCompletion routine requires to process an IRP. Note that the context area cannot be pageable because the IoCompletion routine can be called at IRQL DISPATCH_LEVEL.

Consider the following implementation guidelines for IoCompletion routines:

  • If the input IRP was allocated by the dispatch routine using IoAllocateIrp or IoBuildAsynchronousFsdRequest, the IoCompletion routine must call IoFreeIrp to release that IRP, preferably before it completes the original IRP.
    • The IoCompletion routine must release any per-IRP resources the dispatch routine allocated for the driver-allocated IRP, preferably before it frees the corresponding IRP.

      For example, if the dispatch routine allocates an MDL with IoAllocateMdl and calls IoBuildPartialMdl for a partial-transfer IRP it allocates, the IoCompletion routine must release the MDL with IoFreeMdl. If it allocates resources to maintain state about the original IRP, it must free those resources, preferably before it calls IoCompleteRequest with the original IRP and definitely before it returns control.

      In general, before freeing or completing an IRP, the IoCompletion routine should free any per-IRP resources allocated by the Dispatch routine. Otherwise, the driver must maintain state about the resources to be freed before its IoCompletion routine returns control from completing the original request.

    • If the IoCompletion routine cannot complete the original IRP with STATUS_SUCCESS, it must set the I/O status block in the original IRP to the value returned in the driver-allocated IRP that caused the IoCompletion routine to fail the original request.
    • If the IoCompletion routine will complete the original request with STATUS_PENDING, it must call IoMarkIrpPending with the original IRP before it calls IoCompleteRequest.
    • If the IoCompletion routine must fail the original IRP with an error STATUS_XXX, it can log an error. However, it is the responsibility of the underlying device driver to log any device I/O errors that occur, so IoCompletion routines usually do not log errors.

      See Error Logging and NTSTATUS Values for more information.

    • When the IoCompletion routine has processed and freed the driver-allocated IRP, the routine must return control with STATUS_MORE_PROCESSING_REQUIRED.

      Returning STATUS_MORE_PROCESSING_REQUIRED from the IoCompletion routine forestalls the I/O Manager's completion processing for a driver-allocated and freed IRP. A second call to IoCompleteRequest causes the I/O Manager to resume calling the IRP's completion routines, starting with the completion routine immediately above the routine that returned STATUS_MORE_PROCESSING_REQUIRED.

  • If the IoCompletion routine reuses an incoming IRP to send one or more requests to lower drivers, or if the routine retries failed operations, it should update whatever context the IoCompletion routine maintains about each reuse or retry of the IRP. Then it can set up the next-lower driver's I/O stack location again, call IoSetCompletionRoutine with its own entry point, and call IoCallDriver for the IRP.
    • The IoCompletion routine should not call IoMarkIrpPending at each reuse or retry of the IRP.

      The dispatch routine already marked the original IRP as pending. Until all drivers in the chain complete the original IRP with IoCompleteRequest, it remains pending.

    • Before retrying a request, the IoCompletion routine should reset the I/O status block with STATUS_SUCCESS for Status and zero for Information, possibly after saving the returned error information.

      For each retry, the IoCompletion routine usually decrements a retry count set up by the Dispatch routine. Typically, the IoCompletion routine must call IoCompleteRequest to fail the IRP when some limited number of retries have failed.

    • The IoCompletion routine must return STATUS_MORE_PROCESSING_REQUIRED after it calls IoSetCompletionRoutine and IoCallDriver with an IRP that is being reused or retried.

      Returning STATUS_MORE_PROCESSING_REQUIRED from the IoCompletion routine forestalls the I/O Manager's completion processing of a reused or retried IRP.

    • If the IoCompletion routine cannot complete the original IRP with STATUS_SUCCESS, it must leave the I/O status block as returned by lower drivers for the reuse or retry operation that causes the IoCompletion routine to fail the IRP.
    • If the IoCompletion routine will complete the original request with STATUS_PENDING, it must call IoMarkIrpPending with the original IRP before it calls IoCompleteRequest.
    • If the IoCompletion routine must fail the original IRP with an error STATUS_XXX, it can log an error. However, it is the responsibility of the underlying device driver to log any device I/O errors that occur, so IoCompletion routines usually do not log errors.

      See Logging Errors for more information.

  • Any driver that sets an IoCompletion routine in an IRP and then passes the IRP down to a lower driver should check the IRP->PendingReturned flag in the IoCompletion routine. If the flag is set, the IoCompletion routine must call IoMarkIrpPending with the IRP. Note, however, that a driver that passes down the IRP and then waits on an event should not mark the IRP pending. Instead, its IoCompletion routine should signal the event and return STATUS_MORE_PROCESSING_REQUIRED.
  • The IoCompletion routine must release any resources the dispatch routine allocated for processing the original IRP, preferably before the IoCompletion routine calls IoCompleteRequest with the original IRP and definitely before the IoCompletion routine returns control from completing the original IRP.

If any still-higher-level driver has set its IoCompletion routine in the original IRP, that driver's IoCompletion routine is not called until all lower-level drivers have called IoCompleteRequest with the original IRP.

Supplying a Priority Boost in Calls to IoCompleteRequest

If a lowest-level device driver can complete an IRP in its dispatch routine, it calls IoCompleteRequest with a PriorityBoost of IO_NO_INCREMENT. No run-time priority increase is needed because the driver can assume that the original requester did not wait on its I/O operation.

Otherwise, the lowest-level driver supplies a system-defined and device-type-specific value that boosts the requester's runtime priority to compensate for the time the requester waited on its device I/O request. See wdm.h or ntddk.h for the boost values.

Higher-level drivers apply the same PriorityBoost as their respective underlying device drivers when they call IoCompleteRequest.

Effect of Calling IoCompleteRequest

When a driver calls IoCompleteRequest, the I/O Manager fills that driver's I/O stack location with zeros before calling the next higher-level driver, if any, that has set up an IoCompletion routine to be called for the IRP.

A higher-level driver's IoCompletion routine can check only the IRP's I/O status block to determine how all lower drivers handled the request.

The caller of IoCompleteRequest must not attempt to access the just-completed IRP. Such an attempt is a programming error that causes a system crash.


Canceling IRPs

Drivers in which IRPs might remain queued for an indefinite interval (so a user could cancel a previously submitted I/O request) must have one or more Cancel routines to complete user-canceled I/O requests. Examples of drivers that should have Cancel routines are keyboard, mouse, parallel, serial, and sound device drivers (or drivers layered over them), and file system drivers.

Drivers for Windows XP and later operating systems can use Cancel-Safe IRP Queues rather than implement their own Cancel routines.

To "cancel an IRP" means to complete the IRP as quickly as possible while still maintaining system integrity. For a general discussion of IRP completion, see Completing IRPs.

The cancellation process begins when either the system or a driver calls IoCancelIrp. Drivers can only cancel IRPs that they have created (see Creating IRPs for Lower-Level Drivers.)


Introduction to Cancel Routines

Any driver in which IRPs can be held in a pending state for an indefinite interval must have one or more Cancel routines. For example, a keyboard driver might wait indefinitely for a user to press a key. Conversely, if a driver will never queue more IRPs than it can complete in five minutes, it probably does not need a Cancel routine.

Suppose a user-mode thread makes an I/O request, which is queued by a highest-level device driver's dispatch routine, and the requesting thread is terminated while the IRP is queued. IRPs queued on behalf of a terminated thread should be canceled. Consequently, the driver must set a driver-supplied Cancel routine in each IRP that it queues.

A driver that creates associated IRPs must cancel them when the master IRP is canceled. Because associated IRPs are not associated with a requesting thread, the master IRP's Cancel routine is responsible for canceling any associated IRPs when the master IRP is canceled.

The number of Cancel routines any driver has depends on the driver's design. In general, a driver should have a Cancel routine for each stage in its I/O processing at which an IRP might be held in a pending state for an indefinite interval. Such pending IRPS are said to be held in a cancelable state.

Consider the following design guidelines:

  • The highest-level driver in a chain of layered drivers must have at least one Cancel routine if it queues IRPs or otherwise holds IRPs in a cancelable state. It can have more than one Cancel routine, if necessary.
  • Lower-level drivers in which IRPs can be held in a cancelable state for relatively long intervals also should have one or more Cancel routines.
  • If a driver manages its own internal queues of IRPs, it should have a separate Cancel routine for each of its queues.

Some highest-level drivers for interactive devices, such as keyboard, mouse, sound, parallel class and serial drivers, must have Cancel routines. Some lower-level drivers, such as a parallel port driver that holds IRPs queued for some number of higher-level class drivers for relatively long intervals, also should have Cancel routines.

Mass-storage device drivers, along with intermediate drivers layered over them, are unlikely to have Cancel routines. It is the responsibility of a file system driver to handle the cancellation of file I/O requests, while the IRPs input to lower-level mass-storage drivers are usually processed to completion too quickly to be cancelable.


Registering a Cancel Routine

If a device driver has a StartIo routine, its dispatch routines can register a Cancel routine by supplying its address as input to IoStartPacket.

If a driver does not have a StartIo routine, its dispatch routines must do the following before queuing an IRP for further processing by other driver routines:

  1. Call IoAcquireCancelSpinLock.
  2. Call IoSetCancelRoutine with the input IRP and the entry point for a driver-supplied Cancel routine.
  3. Call IoReleaseCancelSpinLock.

For information about the cancel spin lock, see Using the System's Cancel Spin Lock.

Drivers that manage their own queues of IRPs, rather than using the I/O Manager-supplied device queue, do not need to acquire the cancel spin lock when calling IoSetCancelRoutine. However, these drivers should check the Cancel routine pointer that IoSetCancelRoutine returns to determine whether the Cancel routine has already started.


Synchronizing IRP Cancellation

From a driver's perspective, an IRP can be canceled at any time. IRP cancellation occurs asynchronously; therefore, drivers must be able to handle a number of potential race conditions, created if the IRP is canceled at any of the following points:

  • After a driver routine is called, but before it queues an IRP.
  • After a driver routine is called, but before it tries to process an IRP. For example, an IRP might be canceled after a driver's StartIo routine is called, but before the StartIo routine removes the IRP from the device queue.
  • After the driver routine dequeues the IRP, but before it starts the requested I/O.

Note that after a driver queues an IRP and releases any spin locks that protect the queue, another thread can access and change the IRP. When the original thread resumes — even as soon as the next line of code — the IRP might have already been canceled or otherwise changed.

The following members of an IRP contain information about cancellation:

  • Irp->Cancel indicates whether an IRP is being canceled or should be canceled.
  • Irp->CancelRoutine indicates whether an IRP is cancelable. If this member contains a pointer to a cancel routine, then the IRP is cancelable. If this member is NULL, then the IRP is not cancelable. If this member is NULL, but Irp->Cancel is set, that indicates that the cancel routine is running and the IRP is in the process of being canceled.

If a driver handles cancelable IRPs, it is responsible for setting the appropriate Cancel routine in each IRP that it holds in a cancelable state.


Using the System's Cancel Spin Lock

The system provides a single cancel spin lock, which is acquired or released when certain system routines are called.

Driver routines that change the state of cancelable IRPs, including all routines that might complete an IRP with STATUS_CANCELLED, must acquire and release the system cancel spin lock according to the guidelines in this section.

In drivers that use the I/O Manager-supplied device queue, any driver routine other than the Cancel routine that changes the cancelable state of an IRP must first call IoAcquireCancelSpinLock to acquire the system cancel spin lock.

Acquiring the cancel spin lock ensures that only the caller can change the cancelable state of that IRP. While the caller holds the spin lock, the I/O Manager cannot call the driver's Cancel routine for that IRP. Likewise, another driver routine, such as a DispatchCleanup routine, cannot simultaneously try to change the cancelable state of that IRP.

In drivers that manage their own queues of IRPs and use driver-supplied spin locks to synchronize queue access, the driver routines do not need to acquire the cancel spin lock before calling IoSetCancelRoutine. However, these drivers should check the Cancel routine pointer that IoSetCancelRoutine returns to determine whether the Cancel routine has already started. See Using a Driver-Supplied Spin Lock for details.

Any driver routine that calls IoAcquireCancelSpinLock must call IoReleaseCancelSpinLock as soon as possible.

A driver must never call IoCompleteRequest with an IRP while holding a spin lock. Attempting to complete an IRP while holding a spin lock can cause a deadlock.


Synchronizing Cancellation in Driver Routines that Process IRPs

Any driver routine that dequeues or is called with an IRP that is held in a cancelable state, including a driver's StartIo routine, must do the following:

  1. Call IoAcquireCancelSpinLock.
  2. Check to make sure that Irp equals DeviceObject->CurrentIrp. If not, call IoReleaseCancelSpinLock and return control.

    If the two are not the same, the CurrentIrp might have been canceled between the time that IoStartPacket released the cancel spin lock and this routine acquired it.

  3. Call IoSetCancelRoutine with a NULL CancelRoutine pointer to remove the IRP from the cancelable state.
  4. Check the Irp->Cancel field to determine whether to cancel the IRP or to begin processing the I/O request.

    If Irp->Cancel is set to TRUE, do the following:

    • Call IoReleaseCancelSpinLock.
    • Set Irp->IoStatus.Status to STATUS_CANCELLED.
    • Set Irp->IoStatus.Information to 0.
    • Call IoStartNextPacket (in a StartIo routine) to start the next packet.
    • Call IoCompleteRequest with a priority boost of IO_NO_INCREMENT to complete the IRP.

    If Irp->Cancel is set to FALSE, call IoReleaseCancelSpinLock and start the requested processing the I/O request or pass the IRP to the next lower driver, as appropriate.

Drivers that manage their own queues of IRPs, rather than using the I/O Manager-supplied device queue, do not need to acquire the cancel spin lock when calling IoSetCancelRoutine. However, these drivers should check the Cancel routine pointer that IoSetCancelRoutine returns to determine whether the cancel routine has already started.

In any driver that handles cancelable IRPs, every driver routine that processes an IRP before the underlying device has been programmed for the requested I/O operation should check the cancelable state of all incoming IRPs. Specifically, a highest-level device driver with both StartIo and ControllerControl routines should process incoming IRPs in both these driver routines as already described.


Synchronizing Cancellation in Higher-Level Drivers without Cancel Routines

A higher-level driver can make no assumptions about whether or how existing lower-level drivers handle cancelable IRPs. As soon as any higher-level driver calls IoCallDriver for an IRP, it no longer owns that IRP and it can neither ascertain nor control processing of the IRP by lower-level drivers.

However, any higher-level driver can set an IoCompletion routine for an IRP by calling IoSetCompletionRoutine before it calls IoCallDriver. The higher-level driver can determine whether any pending IRP is canceled in a lower driver by calling IoSetCompletionRoutine with the InvokeOnCancel parameter set to TRUE before it passes the IRP on to lower drivers. Doing so ensures that the driver's IoCompletion routine will be called whether the IRP is canceled or completed.

A higher-level driver can call IoCancelIrp with any pending IRP that the driver has allocated. However, making this call does not ensure that the driver-allocated IRP will be completed with its I/O status block set to STATUS_CANCELLED; another thread might already be completing the IRP. To check whether the IRP was canceled, the higher-level driver must call IoSetCompletionRoutine with the InvokeOnCancel parameter set to TRUE before passing the IRP on to the next lower driver. See Completing IRPs for more information about completion routines.

A higher-level driver must not call IoCancelIrp with an IRP that it did not allocate.


Using a Driver-Supplied Spin Lock

Drivers that manage their own queues of IRPs can use a driver-supplied spin lock, instead of the system cancel spin lock, to synchronize access to the queues. You can improve performance by avoiding use of the cancel spin lock except when absolutely necessary. Because the system has only one cancel spin lock, a driver might sometimes have to wait for that spin lock to become available. Using a driver-supplied spin lock eliminates this potential delay and makes the cancel spin lock available for the I/O Manager and other drivers. Although the system still acquires the cancel spin lock when it calls the driver's Cancel routine, a driver can use its own spin lock to protect its queue of IRPs.

Even if a driver does not queue pending IRPs, but retains ownership in some other way, that driver must set a Cancel routine for the IRP and must use a spin lock to protect the IRP pointer. For example, suppose a driver marks an IRP pending, then passes the IRP pointer as context to an IoTimer routine. The driver must set a Cancel routine that cancels the timer and must use the same spin lock in both the Cancel routine and the timer callback when accessing the IRP.

Any driver that queues its own IRPs and uses its own spin lock must do the following:

  • Create a spin lock to protect the queue.
  • Set and clear the Cancel routine only while holding this spin lock.
  • If the Cancel routine starts running while the driver is dequeuing an IRP, allow the Cancel routine to complete the IRP.
  • Acquire the lock that protects the queue in the Cancel routine.

To create the spin lock, the driver calls KeInitializeSpinLock. In the following example, the driver saves the spin lock in a DEVICE_CONTEXT structure along with the queue it has created:

typedef struct {
LIST_ENTRY    irpQueue;
    KSPIN_LOCK     irpQueueSpinLock;
    …
    } DEVICE_CONTEXT;

VOID InitDeviceContext(DEVICE_CONTEXT *deviceContext)
{
    InitializeListHead(&deviceContext->irpQueue);
    KeInitializeSpinLock(&deviceContext->irpQueueSpinLock);
}

To queue an IRP, the driver acquires the spin lock, calls InsertTailList, and then marks the IRP pending, as in the following example:

NTSTATUS QueueIrp(DEVICE_CONTEXT *deviceContext, PIRP Irp)
{
    PDRIVER_CANCEL  oldCancelRoutine;
    KIRQL  oldIrql;
    NTSTATUS status = STATUS_PENDING;

KeAcquireSpinLock(&deviceContext->irpQueueSpinLock, &oldIrql);

//  Queue the IRP and call IoMarkIrpPending
//  to indicate that the IRP may complete on a different thread.
//  N.B. It's okay to call these inside the spin lock because they're macros, not functions.
IoMarkIrpPending(Irp);
InsertTailList(&deviceContext->irpQueue, &Irp->Tail.Overlay.ListEntry);

//  Must set a Cancel routine before checking the Cancel flag.
oldCancelRoutine = IoSetCancelRoutine(Irp, IrpCancelRoutine);
ASSERT(!oldCancelRoutine);

if (Irp->Cancel){
    //  The IRP was canceled.  Check whether our cancel routine was called.
    oldCancelRoutine = IoSetCancelRoutine(Irp, NULL);
    if (oldCancelRoutine){
        //  The cancel routine was NOT called.
        //  So dequeue the IRP now and complete it after releasing the spinlock.
        RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
        status = Irp->IoStatus.Status = STATUS_CANCELLED;
    } //endif
    else {
        //  The cancel routine WAS called.
        //  As soon as we drop our spin lock it will dequeue and complete the IRP.
        //  So leave the IRP in the queue and otherwise don't touch it.
        //  Return pending since we're not completing the IRP here.
    }  //end else
} // endif

KeReleaseSpinLock(&deviceContext->irpQueueSpinLock, oldIrql);

// Normally you shouldn't call IoMarkIrpPending
// and return a status other than STATUS_PENDING.
// But you can break this rule if you complete the IRP.
if (status != STATUS_PENDING){
    IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
return status;
}

As the example shows, the driver holds its spin lock while it sets and clears the Cancel routine. The sample queuing routine contains two calls to IoSetCancelRoutine.

The first call sets the Cancel routine for the IRP. However, because the IRP might have been canceled while the queuing routine is running, the driver must check the Cancel member of the IRP.

  • If Cancel is set, then cancellation has been requested, and the driver must make a second call to IoSetCancelRoutine to see whether the previously set Cancel routine was called.
  • If the IRP has been canceled but the Cancel routine has not yet been called, then the current routine dequeues the IRP and completes it with STATUS_CANCELLED.
  • If the IRP has been canceled and the Cancel routine has already been called, then the current return marks the IRP pending and returns STATUS_PENDING. The Cancel routine will complete the IRP.

The following example shows how to remove an IRP from the previously created queue:

PIRP DequeueIrp(DEVICE_CONTEXT *deviceContext)
{
KIRQL oldIrql;
PIRP nextIrp = NULL;

KeAcquireSpinLock(&deviceContext ->irpQueueSpinLock, &oldIrql);

while (!nextIrp && !IsListEmpty(&deviceContext ->irpQueue)){
    PDRIVER_CANCEL oldCancelRoutine;
    PLIST_ENTRY listEntry = RemoveHeadList(&deviceContext ->irpQueue);

    // Get the next IRP off the queue.
    nextIrp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);

    //  Clear the IRP's cancel routine
    oldCancelRoutine = IoSetCancelRoutine(nextIrp, NULL);
    //  IoCancelIrp() could have just been called on this IRP.
    //  What we're interested in is not whether IoCancelIrp() was called (nextIrp->Cancel flag set),
    //  but whether IoCancelIrp() called (or is about to call) our cancel routine.
    //  To check that, check the result of the test-and-set macro IoSetCancelRoutine.
    if (oldCancelRoutine){
        //  Cancel routine not called for this IRP.  Return this IRP.
        ASSERT(oldCancelRoutine == IrpCancelRoutine);
    }
    else {
        //  This IRP was just canceled and the cancel routine was (or will be) called.
        //  The cancel routine will complete this IRP as soon as we drop the spin lock,
        //  so don't do anything with the IRP.
        //  Also, the cancel routine will try to dequeue the IRP,
        //  so make the IRP's listEntry point to itself.
        ASSERT(nextIrp->Cancel);
        InitializeListHead(&nextIrp->Tail.Overlay.ListEntry);
        nextIrp = NULL;
    }
}

KeReleaseSpinLock(&deviceContext ->irpQueueSpinLock, oldIrql);

return nextIrp;
}

In the example, the driver acquires the associated spin lock before it accesses the queue. While holding the spin lock, it checks that the queue is not empty and gets the next IRP off the queue. Then it calls IoSetCancelRoutine to reset the Cancel routine for the IRP. Because the IRP could be canceled while the driver dequeues the IRP and resets the Cancel routine, the driver must check the value returned by IoSetCancelRoutine. If IoSetCancelRoutine returns NULL, which indicates that the Cancel routine either has been or will soon be called, then the dequeuing routine lets the Cancel routine complete the IRP. It then releases the lock that protects the queue and returns.

Note the use of InitializeListHead in the preceding routine. The driver could requeue the IRP, so that the Cancel routine can dequeue it, but it's simpler to call InitializeListHead, which reinitializes the IRP's ListEntry field so that it points to the IRP itself. Using the self-referencing pointer is important because the structure of the list could change before the Cancel routine acquires the spin lock. And if the list structure changes, possibly making the original value of ListEntry invalid, the Cancel routine could corrupt the list when it dequeues the IRP. But if ListEntry points to the IRP itself, then the Cancel routine will always use the correct IRP.

The Cancel routine, in turn, simply does the following:

VOID IrpCancelRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
DEVICE_CONTEXT *deviceContext = DeviceObject->DeviceExtension;
KIRQL oldIrql;

//  Release the global cancel spin lock.
//  Do this while not holding any other spin locks so that we exit at the right IRQL.
IoReleaseCancelSpinLock(Irp->CancelIrql);

//
//  Dequeue and complete the IRP.
//  The enqueue and dequeue functions synchronize properly so that if this cancel routine is called,
//  the dequeue is safe and only the cancel routine will complete the IRP. Hold the spin lock for the IRP
//  queue while we do this.
//

KeAcquireSpinLock(&deviceContext->irpQueueSpinLock, &oldIrql);

RemoveEntryList(&Irp->Tail.Overlay.ListEntry);

KeReleaseSpinLock(&deviceContext->irpQueueSpinLock, oldIrql);

//  Complete the IRP.  This is a call outside the driver, so all spin locks must be released by this point.
Irp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return;
}

The I/O Manager always acquires the global cancel spin lock before it calls a Cancel routine, so the first task of the Cancel routine is to release this spin lock. It then acquires the spin lock that protects the driver's queue of IRPs, removes the current IRP from the queue, releases its spin lock, completes the IRP with STATUS_CANCELLED and no priority boost, and returns.


Implementing a Cancel Routine

The I/O Manager calls a driver-supplied Cancel routine with an input IRP to be canceled and a DeviceObject pointer that represents the target device for the I/O request.

The IRP could be one that the driver's DispatchReadWrite routine has queued just as the current Win32 application is being closed by the user. The IRP also could be one that a higher-level driver explicitly canceled, depending on the nature of the underlying device.

When the Cancel routine is called, the input IRP might already be the CurrentIrp in the target device object or might already be in the device queue associated with the target device object if the driver has a StartIo routine. If the driver has no StartIo routine, the IRP might be in a driver-managed internal queue of IRPs when its Cancel routine is called. In any case, the I/O Manager resets the Cancel member in the incoming IRP to NULL before it calls the Cancel routine for that IRP.

The Cancel routine for a master IRP that has associated IRPs is responsible for calling IoCancelIrp to cancel those associated IRPs.

All Cancel routines must follow these guidelines:

  • Call IoReleaseCancelSpinLock to release the system's cancel spin lock.
  • Set the I/O status block's Status member to STATUS_CANCELLED, and set it's Information member to zero.
  • Complete the specified IRP by calling IoCompleteRequest.
  • Because a Cancel routine is always called with the system cancel spin lock held, this routine must not call IoAcquireCancelSpinLock unless it calls IoReleaseCancelSpinLock first.
  • A Cancel routine cannot be holding the system cancel spin lock when it returns control. That is, every Cancel routine must call IoReleaseCancelSpinLock at least once before it returns control.
  • If it calls IoAcquireCancelSpinLock, a Cancel routine must make the reciprocal call to IoReleaseCancelSpinLock as quickly as possible.
  • Never call IoCompleteRequest with an IRP while holding a spin lock. Attempting to complete an IRP while holding a spin lock can cause deadlocks.


Cancel Routines in Drivers with StartIo Routines

The I/O Manager maintains the CurrentIrp field in a device object only if IRPs are queued in the associated device queue object. That is, the field is valid only if the driver has a StartIo routine.

In a driver that has a StartIo routine, a typical Cancel routine must do the following:

  1. Check whether the pointer for the input IRP matches the target device object's CurrentIrp address.

    If these pointers are equivalent, the Cancel routine calls IoReleaseCancelSpinLock, passing Irp-> CancelIrql, and returns control.

  2. If the canceled IRP is not the current IRP, check whether the input canceled IRP is in the device queue associated with the target device object by calling KeRemoveEntryDeviceQueue with the IRP's Tail.Overlay.DeviceQueueEntry pointer.
    • If the IRP is in the device queue, calling KeRemoveEntryDeviceQueue removes it from the queue. The Cancel routine calls IoReleaseCancelSpinLock, sets the IRP's I/O status block with STATUS_CANCELLED for Status and zero for Information, calls IoCompleteRequest with the canceled IRP, and returns control.
    • If the IRP is not in the device queue, the Cancel routine calls IoReleaseCancelSpinLock and returns control.

The driver's Cancel routine should call KeRemoveEntryDeviceQueue to test whether the IRP is in the device queue. This support routine either removes the given IRP from the device queue or does nothing except return FALSE, indicating that the given entry was not queued. A Cancel routine cannot assume that the input IRP is at any particular position in the device queue, so it cannot call KeRemoveDeviceQueue or KeRemoveByKeyDeviceQueue to compare the pointers to the returned IRP and input IRP.

Drivers with Cancel routines can handle IRP_MJ_CLEANUP requests as well. See DispatchCleanup for more information about IRP_MJ_CLEANUP requests.


Cancel Routines in Drivers without StartIo Routines

The I/O Manager maintains the CurrentIrp field in a device object only if IRPs are queued in the associated device queue object.

Drivers that do not have StartIo routines manage their own internal queues of IRPs. In such a driver, a Cancel routine can be called with an input IRP that is neither the CurrentIrp for the input target device object, nor an IRP in the driver's internal queue. The driver must maintain its own state about which IRP is currently being processed and should have a Cancel routine for each of its queues. The driver's internal queue should be an interlocked queue because its internal queue must be protected by an executive spin lock.

When the driver's Cancel routine is called, it typically does the following:

  1. Calls IoReleaseCancelSpinLock, passing Irp->CancelIrql.
  2. Acquires the spin lock that protects its interlocked queue and walks the queue to find an IRP with Irp->Cancel set to TRUE.
    • If it finds such an IRP in the interlocked queue, dequeues it, releases the spin lock protecting the queue, sets the IRP's I/O status block with STATUS_CANCELLED for Status and zero for Information, starts the next queued IRP, calls IoCompleteRequest with the canceled IRP, and returns control
    • If it does not find such an IRP, the Cancel routine releases any spin locks it is holding and returns control.

      The driver usually assumes that I/O processing for the input IRP has already begun if the IRP is not queued.

Drivers with Cancel routines can handle IRP_MJ_CLEANUP requests as well. See DispatchCleanup for more information about IRP_MJ_CLEANUP requests.


Points to Consider When Canceling IRPs

This section discusses guidelines for implementing a Cancel routine and handling cancelable IRPs.

General Guidelines for All Cancel Routines

The I/O Manager holds the cancel spin lock any time it calls a driver's Cancel routine. Consequently, every Cancel routine must:

  • Call IoReleaseCancelSpinLock before it returns control.
  • Not call IoAcquireCancelSpinLock unless it calls IoReleaseCancelSpinLock first.
  • Make a reciprocal call to IoReleaseCancelSpinLock for each call it makes to IoAcquireCancelSpinLock.

Each time the Cancel routine calls IoReleaseCancelSpinLock, it must pass the IRQL returned by the most recent call to IoAcquireCancelSpinLock. When releasing the spin lock acquired by the I/O Manager (and held when the Cancel routine was called), the Cancel routine must pass Irp->CancelIrql.

A driver must not call outside routines (such as IoCompleteRequest) while holding a spin lock because a deadlock can result.

Using the Queue Defined by the I/O Manager

Unless a driver manages its own internal queues of IRPs, its Cancel routine is called with an incoming IRP that could be either of the following:

  • The CurrentIrp in the input target device object
  • An entry in the device queue associated with the target device object

Unless a driver manages its own internal queues of IRPs, its Cancel routine should call KeRemoveEntryDeviceQueue with the input IRP to test whether it is an entry in the device queue associated with the target device object. The driver's Cancel routine cannot call KeRemoveDeviceQueue or KeRemoveByKeyDeviceQueue because it cannot assume that the given IRP is at any particular position in the device queue.

Current State of the Input IRP

If a Cancel routine is called with an IRP for which the driver has already started I/O processing and the request will be completed soon, the Cancel routine should release the system cancel spin lock and return control.

If the current state of the input IRP is Pending, a Cancel routine must do the following:

  1. Set the input IRP's I/O status block with STATUS_CANCELLED for Status and zero for Information.
  2. Release any spin locks it is holding, including the system cancel spin lock.
  3. Call IoCompleteRequest with the given IRP.

Holding IRPs in a Cancelable State

Any driver routine that holds an IRP in a cancelable state must call IoMarkIrpPending and must call IoSetCancelRoutine to set its entry point for the Cancel routine in the IRP. Only then can that driver routine call additional support routines such as IoStartPacket, IoAllocateController, or an ExInterlockedInsert..List routine.

Any driver routine that subsequently processes cancelable IRPs must check whether an IRP has already been canceled before it begins operations to satisfy the request. The routine must call IoSetCancelRoutine to reset its entry point for the Cancel routine to NULL in the IRP. Only then can that routine begin its I/O processing for the input IRP.

A routine might have to reset the entry point for a Cancel routine in an IRP if it, too, passes IRPs on for further processing by other driver routines and those IRPs might be held in a cancelable state.

Any higher-level driver that holds an IRP in a cancelable state must reset its Cancel entry point to NULL before it passes the IRP on to the next-lower driver with IoCallDriver.

Canceling an IRP

Any higher-level driver can call IoCancelIrp with an IRP that it has allocated and passed on for further processing by lower-level drivers. However, such a driver cannot assume that the given IRP will be completed with STATUS_CANCELLED by lower drivers.

Synchronization

A driver can (or must, depending on its design) maintain additional state information in its device extension to track the cancelable status of IRPs. If this state is shared by driver routines running at IRQL <= DISPATCH_LEVEL, the shared data should be protected with a driver-allocated and initialized spin lock.

The driver should manage its acquisitions and releases of the system cancel spin lock and its own spin locks carefully. It should hold the system cancel spin lock for the shortest possible intervals. Before accessing a cancelable IRP, such a driver should always check the return value of IoSetCancelRoutine to determine whether the Cancel routine is already running (or is about to run); if so, it should let the Cancel routine complete the IRP.

If a device driver maintains state information about cancelable IRPs that various driver routines share with its ISR, these other routines must synchronize access to the shared state with the ISR. Only a driver-supplied SynchCritSection routine can access state information that is shared with the ISR in a multiprocessor-safe way.

For more information, see Synchronization Techniques.


Reusing IRPs

Under certain circumstances, drivers can reuse IRPs. The driver can allocate a pool of memory buffers that it uses to hold IRPs as they need to be created.

Drivers must not attempt to reuse IRPs issued by the I/O Manager. In particular, drivers should not attempt to reuse IRPs created by the IoMakeAssociatedIrp, IoBuildSynchronousFsdRequest, IoBuildAsynchronousFsdRequest, or IoBuildDeviceIoControlRequest routines.

Drivers can safely reuse IRPs that they have created, as follows:

  1. If a driver allocates an IRP as raw memory (for example, by calling ExAllocatePool), and then initializes it with IoInitializeIrp, then it can safely call IoInitializeIrp or IoReuseIrp to reinitialize the memory buffer.
  2. On Microsoft® Windows® 2000 and later operating systems, drivers that create an IRP with IoAllocateIrp can reuse the IRP by calling IoReuseIrp.
  3. If a driver allocates an IRP with IoAllocateIrp and with the ChargeQuota parameter set to FALSE, then it can safely use IoInitializeIrp to reinitialize the IRP. Drivers that must also work on Windows 98 can use this method as a work-around. Drivers strictly for Windows 2000 and later operating systems should use the previous method.


IRP Processing Examples

The following sections describe how IRPs might be processed in two prototype drivers. One is a prototype of a lowest-level driver for a mass storage device. The other is a prototype for an intermediate-level mirror driver, which would exist above the lowest-level driver in a stack of storage drivers. (A mirror driver duplicates all write requests to multiple driver, and alternates read requests among the duplicate drives.)

See the following sections:

Processing IRPs in a Lowest-Level Driver

Processing IRPs in an Intermediate-Level Driver


Processing IRPs in a Lowest-Level Driver

Lowest-level physical drivers have certain standard routines that higher-level drivers do not need. The set of standard routines for lowest-level drivers also varies according to the following criteria:

  • The nature of the device each driver controls
  • Whether the driver sets up its device objects for direct or buffered I/O
  • The design of the individual driver

To illustrate the roles of the standard driver routines, the following figure shows the path a sample IRP might take as it is processed by a lowest-level mass-storage device driver. The driver in the figure has the following characteristics:

  • The device generates interrupts at the end of each I/O operation, so this driver has ISR and DpcForIsr routines.
  • The driver has a StartIo routine, rather than setting up internal queues for IRPs and managing its own queuing.
  • The driver uses system DMA, so it sets its device objects' Flags for direct I/O, and has an AdapterControl routine.

IRP Path Through Lowest-Level Driver Routines

As the previous figure shows, the I/O manager creates an IRP and sends it to the driver's dispatch routine for the given major function code. Assuming the function code is either IRP_MJ_READ or IRP_MJ_WRITE, the dispatch routine is DDDispatchReadWrite.

Calling IoGetCurrentIrpStackLocation

Any driver routine that requires IRP parameters must call IoGetCurrentIrpStackLocation to obtain the driver's I/O stack location. Such routines include dispatch routines that handle more than one major I/O function code (IRP_MJ_XXX), handle a function that supports minor functions (IRP_MN_XXX), or handle device I/O control requests (IRP_MJ_DEVICE_CONTROL and/or IRP_MJ_INTERNAL_DEVICE_CONTROL), along with every other driver routine that processes an IRP.

This driver's I/O stack location is the lowest one, with an indefinite number of higher-level drivers' I/O stack locations shown shaded. For simplicity, calls to IoGetCurrentIrpStackLocation from the DispatchReadWrite, StartIo, AdapterControl, and DpcForIsr routines are not shown in the previous figure.

Calling IoMarkIrpPending and IoStartPacket

The sample driver does not complete the IRP in its dispatch routine, but instead processes the IRP in its StartIo routine. Before it can do so, the dispatch routine calls IoMarkIrpPending to indicate that the IRP is not yet completed. Then it calls IoStartPacket to queue the IRP for further processing by the driver's StartIo routine. The dispatch routine also returns the NTSTATUS value STATUS_PENDING.

The following figure illustrates the call to IoStartPacket.

Calling IoStartPacket

If the driver is busy processing another IRP on the device, IoStartPacket inserts the IRP into the device queue associated with the device object. The driver can optionally supply a Key value as a parameter to IoStartPacket to impose a driver-determined order on IRPs in the device queue.

If the driver is not busy and the device queue is empty, the I/O Manager immediately calls its StartIo routine, passing the input IRP.

For mass-storage devices, the lowest-level driver does not need to supply a Cancel routine when it calls IoStartPacket for two reasons:

  1. A file system layered over such a driver typically handles the cancellation of file I/O requests.
  2. Mass-storage device drivers process IRPs quickly.

Usually, the highest-level driver in a chain of layered drivers handles the cancellation of IRPs.

Calling AllocateAdapterChannel and MapTransfer

Assuming the StartIo routine, shown in the figure illustrating an IRP path through the lowest-level driver routines, determines that the transfer request can be done by a single DMA operation, the StartIo routine calls AllocateAdapterChannel with the entry point of the driver's AdapterControl routine and the IRP.

When the system DMA controller is available, the I/O Manager calls the driver's AdapterControl routine to set up the transfer operation. The AdapterControl routine calls MapTransfer to set up the system DMA controller. Then the driver programs its device for the DMA operation and returns. (For more information about using DMA and adapter objects, see Input/Output Techniques.)

Calling IoRequestDpc from the Driver's ISR

When the device interrupts to indicate its transfer operation is complete, the driver's ISR stops the device from generating interrupts and calls IoRequestDpc, as shown in the figure illustrating an IRP path through the lowest-level driver routines.

This call queues the driver's DpcForIsr routine to complete as much of the transfer operation as possible at a lower hardware priority (IRQL).

Calling IoStartNextPacket and IoCompleteRequest

When the DpcForIsr routine has finished processing the transfer, it calls IoStartNextPacket promptly so that the driver's StartIo routine will be called with the next IRP in the device queue, if any are queued. The DpcForIsr routine also sets the just-completed IRP's I/O status block and then calls IoCompleteRequest for the IRP.

The following figure illustrates this driver's calls to IoStartNextPacket and IoCompleteRequest.

Calling IoStartNextPacket and IoCompleteRequest

Drivers should call IoStartNextPacket or IoStartNextPacketByKey to begin the next requested I/O operation as soon as possible, preferably before they call IoCompleteRequest.

If any IRPs are queued for the device, IoStartNextPacket calls KeRemoveDeviceQueue to remove the next IRP from the queue. The I/O Manager then calls the driver's StartIo routine, passing the dequeued IRP. If no IRPs are currently in the device queue, IoStartNextPacket merely returns to the caller.

Setting the I/O Status Block in an IRP

Every lowest-level driver must set the IRP's I/O status block (in the previous figure, the second shaded area denotes the status block) before calling IoCompleteRequest. The I/O status block supplies information to higher-level drivers and, ultimately, to the original requester of the I/O operation. Any higher-level driver layered above the driver in the previous figure might have set up an IoCompletion routine that reads the I/O status block set by this driver. Higher-level drivers usually do not modify the I/O status block in an IRP that has been completed by a device driver, unless the higher-level driver is retrying the IRP, in which case it reinitializes the I/O status block.

Every higher-level driver that completes an IRP without sending it on to the next lower driver also must set the I/O status block in that IRP before calling IoCompleteRequest. For good overall I/O throughput, a higher-level driver should check the parameters in its own I/O stack location of each IRP and, if the parameters are invalid, should set the I/O status block and complete the request itself. Whenever possible, a driver should avoid passing an invalid request on to lower drivers in the chain.

Assuming the transfer operation in the previous figure is successful, the DpcForIsr routine, shown in the figure illustrating an IRP path through the lowest-level driver routines, sets STATUS_SUCCESS in Status and the number of bytes transferred in Information for the IRP's I/O status block.

Many of the standard driver routines also return NTSTATUS-type values. For more information about NTSTATUS constants like STATUS_SUCCESS, see Logging Errors.


Processing IRPs in an Intermediate-Level Driver

Higher-level drivers have a different set of standard routines than lowest-level device drivers, with an overlapping subset of standard routines common to both types of drivers.

The set of routines for intermediate and highest-level drivers also varies according to the following criteria:

  • The nature of the underlying physical device
  • Whether an underlying device driver sets up device objects for direct or buffered I/O
  • The design of the individual higher-level driver

The following figure illustrates the path an IRP might take through the standard routines of an intermediate mirror driver layered somewhere over the lowest-level device driver described in the previous section.

The driver shown in the following figure has the following characteristics:

  • The driver is layered over more than one physical device and possibly over more than one device driver.
  • The driver sometimes allocates additional IRPs for lower-level drivers, depending on the requested operation in the input IRP.
  • The driver has at least one file system driver layered above it, and that file system driver might be layered over other intermediate drivers at a higher level than this one.

IRP Path through Intermediate Driver Routines

As the previous figure shows, the I/O manager creates an IRP and sends it to the driver's dispatch routine for the given major function code. Assuming the function code is IRP_MJ_WRITE, the dispatch routine is DDDispatchWrite. The intermediate driver's I/O stack location is shown in the middle, with an indefinite number of I/O stack locations for higher- and lower-level drivers shown shaded.

Allocating IRPs

The mirror driver's purpose is to send write requests to several physical devices, and to send read requests alternately to the drivers of these devices. For write requests, the driver creates duplicate IRPs for each device on which the data is to be written, assuming the parameters in the input IRP are valid.

The previous figure shows a call to IoAllocateIrp but higher-level drivers can call other support routines to allocate IRPs for lower-level drivers. See Creating IRPs for Lower-Level Drivers.

When the dispatch routine calls IoAllocateIrp, it specifies the number of I/O stack locations needed for the IRP. The driver must specify a stack location for each lower driver in the chain, getting the appropriate value from the device objects of each driver just below the mirror driver. Optionally, the driver can add one to this value when it calls IoAllocateIrp to get a stack location of its own for each IRP it allocates, as the driver in the previous figure does.

This intermediate driver's dispatch routine calls IoGetCurrentIrpStackLocation (not shown) with the original IRP, to check parameters.

It calls IoSetNextIrpStackLocation because it allocated its own stack location in each newly created IRP and IoGetCurrentIrpStackLocation to create a context for itself that it uses later in the IoCompletion routine.

Next, it calls IoGetNextIrpStackLocation with each newly created IRP so that it can set up the next lower-level drivers' I/O stack locations in the IRPs it allocated. The mirror driver's dispatch routine copies the IRP function codes and parameters (pointer to the transfer buffer, length in bytes to be transferred for IRP_MJ_WRITE) into the I/O stack locations for the next-lower drivers. These drivers, in turn, will set up the I/O stack locations for the drivers just below them, if any.

Calling IoSetCompletionRoutine and IoCallDriver

The dispatch routine in the previous figure calls IoSetCompletionRoutine for each IRP it allocated. Because the driver in the previous figure must dispose of the IRPs it allocated, this driver sets its IoCompletion routine to be called when lower drivers complete its IRPs, whether the I/O operation completed successfully, failed, or was canceled.

Because the driver in the previous figure mirrors in parallel, it passes both IRPs that it allocated on to the next-lower-level drivers by calling IoCallDriver twice, once for each target device object representing a mirrored partition.

Processing IRPs in the Driver's IoCompletion Routine

When either set of lower-level drivers completes the requested operation, the I/O Manager calls the intermediate mirror driver's IoCompletion routine. The mirror driver maintains a count in its own I/O stack location for the original IRP, to track when the lower drivers have completed all the duplicate IRPs.

Assuming that the I/O status block indicates that one set of lower drivers has completed the duplicate IRP shown in the previous figure successfully, the mirror driver's IoCompletion routine decrements its count but cannot complete the original IRP until it decrements the count to zero. If the decremented count is not yet zero, the IoCompletion routine calls IoFreeIrp with the first-returned IRP (DupIRP1 in Figure 4.5) that the driver allocated and returns STATUS_MORE_PROCESSING_REQUIRED.

When the mirror driver's IoCompletion routine is called again with the DupIRP2 shown in the previous figure, the IoCompletion routine decrements the count in the original IRP and determines that both sets of lower-level drivers have carried out the requested operations.

Assuming the I/O status block in DupIRP2 also is set with STATUS_SUCCESS, the IoCompletion routine copies the I/O status block from DupIRP2 into the original IRP and frees DupIRP2. It calls IoCompleteRequest with the original IRP and returns STATUS_MORE_PROCESSING_REQUIRED. Returning this status prevents the I/O Manager from attempting any further completion processing on DupIRP2; because the IRP is not associated with a thread, its completion processing should end with the driver that created it.

If either set of lower-level drivers does not complete the mirror driver's IRPs successfully, the mirror driver's IoCompletion routine should log an error and attempt appropriate mirrored-data recovery. For more information, see Logging Errors.


Plug and Play

This section describes Plug and Play concepts and operating system components, and explains how to support Plug and Play capabilities of device hardware in kernel-mode drivers. The chapter contains the following sections:

Introduction to Plug and Play

Adding a PnP Device to a Running System

Passing PnP IRPs Down the Device Stack

Postponing PnP IRP Processing Until Lower Drivers Finish

Starting a Device

Stopping a Device

Removing a Device

Using PnP Notification


Introduction to Plug and Play

Plug and Play (PnP) is a combination of hardware and software support that enables a computer system to recognize and adapt to hardware configuration changes with little or no intervention by a user. A user can add devices to, and remove devices from, a computer system without having to do awkward and confusing manual configuration, and without having knowledge of intricate computer hardware. For example, a user can dock a portable computer and use the docking station keyboard, mouse, and monitor without making manual configuration changes.

PnP requires support from device hardware, system software, and drivers. Initiatives in the hardware industry define standards (such as the PnP ISA definition and the PC Card standard) for easy identification of add-in boards and basic system components. This DDK documentation focuses on the system software support for PnP and how drivers use that support to implement PnP.

The system software support for PnP, together with PnP drivers provides the following:

  • Automatic and dynamic recognition of installed hardware

    The system software recognizes hardware during initial system installation, recognizes PnP hardware changes that occur between system boots, and responds to run-time hardware events such as docking or undocking and device insertion or removal.

  • Hardware resource allocation (and reallocation)

    The PnP Manager determines the hardware resources requested by each device (for example, input/output ports [I/O], interrupt requests [IRQs], direct memory access [DMA] channels, and memory locations) and assigns hardware resources appropriately. The PnP Manager reconfigures resource assignments when necessary, such as when a new device is added to the system that requires resources already in use.

    Drivers for PnP devices do not assign resources; instead, the requested resources for a device are identified when the device is enumerated. The PnP Manager retrieves the requirements for each device during resource allocation. Resources are not dynamically configurable for legacy devices, so the PnP Manager assigns resources to legacy devices first.

  • Loading of appropriate drivers

    The PnP Manager determines which drivers are required to support each device and loads those drivers.

  • A programming interface for drivers to interact with the PnP system

    The interface includes I/O Manager routines, Plug and Play IRPs, required standard driver routines, and information in the registry.

  • Mechanisms for drivers and applications to learn of changes in the hardware environment and take appropriate actions

    PnP enables drivers and user-mode code to register for, and be notified of, certain hardware events.

PnP drivers are an important part of PnP support. For a driver to qualify as PnP it must provide the required PnP entry points, handle the required PnP IRPs, and follow PnP guidelines.

This section contains the following additional topics:

PnP Components

Levels of Support for PnP

PnP Driver Design Guidelines

Device Tree

Hardware Resources

PnP Device States


PnP Components

The following figure shows the components that work together to support PnP.

PnP Software Components

The PnP Manager has two parts: the kernel-mode PnP Manager and the user-mode PnP Manager. The kernel-mode PnP Manager interacts with OS components and drivers to configure, manage, and maintain devices. The user-mode PnP Manager interacts with user-mode setup components, such as Class Installers, to configure and install devices. The user-mode PnP Manager also interacts with applications to, for example, register an application for notification of device changes and notify the application when a device event occurs.

PnP drivers support the physical, logical, and virtual devices on a machine. The term "PnP driver" refers to any Windows driver that supports the interfaces described in this chapter. While most PnP drivers are also WDM drivers and thus source-compatible across Windows platforms, a few drivers support PnP without fully implementing WDM.

All drivers should support PnP and power management. If a single driver does not support PnP and power management, it constrains the PnP and power management support of the system as a whole.

See Device Installation Overview for information on device and driver setup, including .inf files, .cat files, and the registry.


Levels of Support for PnP

The extent to which a device supports PnP depends on the PnP support in both the device hardware and the device drivers (see the following table).

 | PnP Driver | Non-PnP Driver
PnP Device | Full PnP | No PnP
Non-PnP Device | Possible partial PnP | No PnP

Any device that supports PnP should have PnP support in its drivers.

A non-PnP device can have some PnP capability if it is driven by a PnP driver. For example, an ISA sound card or an EISA network card can be manually installed and then a PnP driver can treat the card like a PnP device.

If a driver does not support PnP, its devices behave as non-PnP devices regardless of any hardware PnP support. A non-PnP driver can constrain the PnP and power management capabilities of the whole system.

Legacy drivers (that is, drivers written before the operating system supported PnP) continue to work as they did previously, without any PnP capability. New drivers should include PnP support.


PnP Driver Design Guidelines

Plug and Play provides:

  • Automatic and dynamic recognition of installed hardware
  • Hardware resource allocation (and reallocation)
  • Loading of appropriate drivers
  • An interface for drivers to interact with the PnP system
  • Mechanisms for drivers and applications to learn of changes in the hardware environment

To support PnP, a driver must follow these guidelines:

  • It must contain a DispatchPnP routine.

    This dispatch routine must handle IRP_MJ_PNP requests and associated minor function codes. For more information, see DispatchPnP Routines.

  • It must not search for hardware.

    The PnP Manager is responsible for determining the presence of hardware devices. When the PnP Manager detects a device, it notifies the driver by calling its AddDevice routine. Hardware can be detected when the system is booted, or any time that a user adds a device to, or removes one from, a running system.

  • It must not allocate hardware resources.

    A PnP driver must provide the PnP Manager with lists of resources that a device can potentially use. The PnP Manager is responsible for assigning resources to each device, and notifying the driver of each device's assignments when it sends an IRP_MN_START_DEVICE request. The driver must thus be capable of working with various configurations of hardware resources.

Some drivers are insulated from the details of the PnP and power management by system-supplied port or class drivers. For example, a SCSI port driver insulates a SCSI miniport driver from many of the details of the power and PnP systems, so a SCSI miniport driver doesn't need to handle power and PnP IRPs directly. For such drivers, see the driver-specific documentation for details of the required PnP support.


Device Tree

The PnP Manager maintains a device tree that keeps track of the devices in the system. The following figure shows the device tree for a sample system configuration.

Sample PnP Device Tree

The device tree contains information about the devices present on the system. The PnP Manager builds this tree when the machine boots, using information from drivers and other components, and updates the tree as devices are added or removed.

Each node of the device tree is called a device node, or devnode. A devnode consists of the device objects for the device's drivers, plus internal information maintained by the system. See Types of WDM Drivers for more information.

The PnP Manager asks a bus driver for a list of its child devices using an IRP_MN_QUERY_DEVICE_RELATIONS request. The bus driver determines its list of children according to its bus protocol. For example, the ACPI driver looks in the ACPI name space, the PCI driver queries PCI configuration space, and a USB hub driver follows the USB bus protocol.

The device tree is hierarchical, with devices on a bus represented as "children" of the bus adapter, controller or other bus device. (A bus device is any device to which other physical, logical, or virtual devices can be attached.) You can see the hierarchy of devices in the device tree using the Device Manager and choosing the view option that allows you to view devices by connection.

The hierarchy of the device tree reflects the structure in which the devices are attached in the machine. The PnP Manager uses this hierarchy as it manages the devices. For example, if a user requests to unplug the USB controller from the machine represented by the previous figure, the PnP Manager determines from the device tree that this action would result in three other devices also being unplugged (the USB hub, the joystick, and the camera). When the PnP Manager queries the drivers for the USB controller to determine if it is safe to remove the controller, it also queries the drivers of the controller's descendants (the hub, joystick, and camera).

The device tree is dynamic. As devices are added to, and removed from the machine, the PnP Manager (together with drivers) maintains a current picture of the devices on the system.

There are other relationships between devices on the machine besides the hierarchical relationships represented in the device tree. These include removal relations and ejection relations. See the reference page for IRP_MN_QUERY_DEVICE_RELATIONS for more information.

You cannot make any assumptions about the order in which the device tree is built, except that a bus device is configured before any of its child devices. For example, you should not assume that one device on a bus is configured before another device on the bus.


Hardware Resources

Hardware resources are the assignable, addressable bus paths that allow peripheral devices and system processors to communicate with each other. Hardware resources typically include I/O port addresses, interrupt vectors, and blocks of bus-relative memory addresses.

Before the system can communicate with a device instance, the PnP Manager must assign hardware resources to the device instance based on knowledge of which resources are available and which ones the device instance is capable of using. Resources are assigned to each device node in the device tree (assuming that the represented device needs resources and those resources are available). The PnP Manager keeps track of hardware resources using lists, which it associates with device nodes. It uses two types of lists:

Resource Requirements List
Devices are typically designed to operate within ranges of resource assignments. For instance, a device might require only one interrupt vector, but it might be able to use any one of a range of vectors. For each device instance, the PnP Manager maintains a resource requirements list that specifies all of the ranges of hardware resources in which the device can operate. The list's name stems from the fact that the PnP Manager is required to choose resources from this list when assigning them to the device.

Kernel-mode code specifies resource requirements lists using IO_RESOURCE_REQUIREMENTS_LIST structures (either as input to system routines or in response to IRPs). User-mode code specifies resource requirements lists using PnP Configuration Manager structures as input to PnP Configuration Manager functions.

Resource List
When the PnP Manager assigns resources to a device, it keeps track of these assignments by creating a list of assigned resources for each device instance. These lists could be called resource assignment lists, but that name is typically shorted to resource lists. The PnP Manager can change resource list contents as devices are added to or removed from a system and resources are subsequently reallocated. (Resources can also be assigned by a PnP BIOS. Also, installation software – using INF files or user input – can force the PnP Manager to assign specific resources to a device.)

Kernel-mode code specifies resource lists by using CM_RESOURCE_LIST structures (either as input to system routines or in response to IRPs). User-mode code specifies resource lists using PnP Configuration Manager structures as input to PnP Configuration Manager functions.

The PnP Manager stores resource requirements lists and resource lists in the registry, where they can be viewed using regedit.exe. Drivers can access these lists indirectly through Plug and Play routines and Plug and Play IRPs. User-mode applications can use PnP Configuration Manager functions. (Drivers and applications must not directly access these lists using registry functions because the storage format is subject to change in a future release.)

Logical Configurations

Both resource requirements lists and resource lists are used to specify logical configurations. Each logical configuration identifies either a range of acceptable resources, or a set of specific resources for a specific device instance. Each logical configuration consists of either a single resource requirements list or a single resource list. Additionally, each logical configuration for a device instance belongs to one of the logical configuration types. Configuration types are listed in the following tables. Several logical configurations, of the same or different types, might be assigned to each device instance.

Logical Configuration Types for Resource Requirements Lists

Basic Configuration
A resource requirements list identifying resource ranges supplied by a Plug and Play device. A driver should return this list when it receives the IRP_MN_QUERY_RESOURCE_REQUIREMENTS IRP. (The basic configuration for a non-PnP device can be described in an INF file. In this case, device installation software reads the INF file and calls PnP Configuration Manager functions to create a requirements list.)
Filtered Configuration
A resource requirements list that has been supplied to a driver stack, possibly modified, then returned by the driver stack, in response to the IRP_MN_FILTER_RESOURCE_REQUIREMENTS IRP. The PnP Manager uses the resulting filtered configuration as the basis for allocating resources.
Override Configuration
A resource requirements list that overrides basic configurations. Typically, a device installer creates an override configuration if the device's INF file includes an INF DDInstall.LogConfigOverride section. An override configuration is not removed if its device is physically removed from the system.

Logical Configuration Types for Resource Lists

Boot Configuration
A resource list identifying the resources assigned to a device instance when the system is booted. (For PnP devices, this is the configuration supplied by the BIOS; for non-PnP devices, these resources might be selected by jumpers on the card.) A driver should return this resource list when it receives the IRP_MN_QUERY_RESOURCES IRP. (A boot configuration can be partially empty if the BIOS cannot determine all resources used by a device.) The PnP Manager can modify this list if a device is removed or restarted. For non-PnP devices, this configuration type can be used instead of a forced configuration, in which case it has a lower configuration priority than an equivalent forced configuration. Only one boot configuration can exist for each device instance.
Forced Configuration
A resource list identifying resources that a device instance must use. A forced configuration prevents the PnP Manager from assigning other resources to the device instance. A device installer might create a forced configuration based on information that is either contained in an INF or received from a user. A forced configuration is not removed if its device is physically removed from the system. Only one forced configuration can exist for each device instance.
Allocated Configuration
A resource list identifying resources currently in use by a device instance. Only one allocated configuration can exist for each device instance.

Device drivers are responsible for determining a PnP-compatible device's basic configuration, filtered configuration, and boot configuration, and for returning that information in response to IRPs sent by the PnP Manager. (For more information, see Adding a PnP Device to a Running System.) Driver installation software can create override configurations, forced configurations, and, for non-PnP devices, boot configurations. The PnP Manager maintains each device instance's allocated configuration.

A priority is assigned to each configuration when it is created. If the PnP Manager finds that a device instance has been assigned several logical configurations of the same type, it attempts to use the one with the highest priority first. If that configuration results in resource conflicts, it tries the configuration with the next lower priority. (For a list of configuration priorities, see Cm_Add_Empty_Log_Conf.)


PnP Device States

On a PnP system, a device transitions through various PnP states as it is configured, started, possibly stopped to rebalance resources, and possibly removed. This section provides an overview of the PnP device states. The overview is a road map for much of the PnP support required in a driver. Other parts of this documentation describe each state transition in detail.

The following figure shows the PnP states for a device and how a device transitions from one state to another.

Device States from the PnP Perspective

Starting at the top left of the previous figure, a PnP device is physically present in the system because either the user just inserted the device or the device was present at boot time. The device is not yet known to the system software.

To begin software configuration for the device, the PnP Manager and the parent bus driver enumerate the device. The PnP Manager, possibly with help from user-mode components, identifies the drivers for the device, including the function driver and any optional filter drivers. The PnP manager calls the DriverEntry routine of each driver if the driver is not yet loaded. See Adding a PnP Device to a Running System for more information on reporting and enumerating a PnP device.

Once a driver is initialized, it must be ready to initialize its devices. The PnP Manager calls a driver's AddDevice routine for each device the driver controls.

When a driver receives an IRP_MN_START_DEVICE request from the PnP Manager, the driver starts the device and is ready to process I/O requests for the device. See Starting a Device for information on handling an IRP_MN_START_DEVICE request.

If the PnP Manager must reconfigure the hardware resources of an active device, it sends IRP_MN_QUERY_STOP_DEVICE and IRP_MN_STOP_DEVICE requests to the device's drivers. After it reconfigures the hardware resources, the PnP Manager directs the drivers to restart the device by sending an IRP_MN_START_DEVICE request. See Stopping a Device for information on handling stop IRPs. (The drivers for a boot-configured device can receive IRP_MN_QUERY_STOP_DEVICE and IRP_MN_STOP_DEVICE requests before the device has been started, although this step is not shown in the previous figure.)

On Windows 98/Me, the PnP Manager also sends IRP_MN_QUERY_STOP_DEVICE and IRP_MN_STOP_DEVICE requests when a device is being disabled. Drivers on these systems also receive an IRP_MN_STOP_DEVICE request after a failed start.

When a PnP device is being physically removed from the system or has already been removed, the PnP Manager sends various remove IRPs to the device's drivers, directing them to remove the device's software representation (device objects, and so forth). See Removing a Device for information on handling remove IRPs.

At some point after all of a driver's devices have been removed, the PnP Manager calls the drivers Unload routine and unloads the driver.


Adding a PnP Device to a Running System

This section describes the sequence of events that occur when the system configures a PnP device that a user has added to a running machine. This discussion highlights the roles of the PnP Manager, bus drivers, and function and filter drivers in enumerating and configuring a new device.

Most of this discussion is also relevant to configuring a PnP device that is present when the machine is booted. Specifically, devices whose drivers are marked SERVICE_DEMAND_START in an INF file are configured in essentially the same way whether the device is added dynamically or is present at boot time.

The following figure shows the first steps in configuring the device, starting from when the user plugs the hardware into the machine.

Enumerating and Reporting a PnP Device

The following notes correspond to the circled numbers in the previous figure:

  1. A user plugs a PnP device into a free slot on a PnP bus.

    In this example, the user plugs a PnP USB joystick into the hub on a USB host controller. The USB hub is a PnP bus device because child devices can be attached to it.

  2. The function driver for the bus device determines that a new device is on its bus.

    How the driver determines this depends on the bus architecture. For some buses, the bus function driver receives hot-plug notification of new devices. If the bus does not support hot-plug notification, the user must take appropriate action in a dialog box or applet to cause the bus to be enumerated.

    In this example, the USB bus supports hot-plug notification so the function driver for the USB bus is notified that its children have changed.

  3. The function driver for the bus device notifies the PnP Manager that its set of child devices has changed.

    The function driver notifies the PnP Manager by calling IoInvalidateDeviceRelations with a Type of BusRelations.

  4. The PnP Manager queries the bus's drivers for the current list of devices on the bus.

    The PnP Manager sends an IRP_MN_QUERY_DEVICE_RELATIONS request to the device stack for the bus. The Parameters.QueryDeviceRelations.Type value is BusRelations, indicating that the PnP Manager is asking for the current list of devices present on the bus (bus relations).

    The PnP Manager sends the IRP to the top driver in the device stack for the bus. According to the rules for PnP IRPs, each driver in the stack handles the IRP, if appropriate, and passes the IRP down to the next driver.

  5. The function driver for the bus device handles the IRP.

    See the reference page for IRP_MN_QUERY_DEVICE_RELATIONS for detailed information on handling this IRP.

    In this example, the USB hub driver handles this IRP for the hub FDO. The hub driver creates a PDO for the joystick device and includes a referenced pointer to the joystick PDO in its list of child devices returned with the IRP.

    When the USB hub's parent bus driver (the USB host controller class/miniclass driver pair) completes the IRP, the IRP travels back up the device stack by means of any IoCompletion routines registered by the hub drivers.

Note that the bus function driver reports a change in its list of children by requesting that the PnP Manager query for its list of child devices. The resulting IRP_MN_QUERY_DEVICE_RELATIONS request is seen by all the drivers for the bus device. Typically, the bus function driver is the only driver to handle the IRP and report children. In some device stacks, a bus filter driver is present and participates in constructing the list of bus relations. One example is ACPI, which attaches as a bus filter driver for ACPI devices. In some device stacks, non-bus filter drivers handle the IRP_MN_QUERY_DEVICE_RELATIONS request, but this is not typical.

At this point, the PnP Manager has the current list of devices on the bus. The PnP Manager then determines whether any devices are newly arrived or have been removed. In this example, there is one new device. The following figure shows the PnP Manager creating a devnode for the new device and beginning to configure the device.

Creating a Devnode for a New PnP Device

The following notes correspond to the circled numbers in the previous figure:

  6. The PnP Manager creates devnodes for any new child devices on the bus.

    The PnP Manager compares the list of bus relations returned in the IRP_MN_QUERY_DEVICE_RELATIONS IRP to the list of children for the bus currently recorded in the PnP device tree. The PnP Manager creates a devnode for each new device and initiates removal processing for any devices that have been removed.

    In this example, there is one new device (a joystick), so the PnP Manager creates a devnode for the joystick. At this point, the only driver that is configured for the joystick is the parent USB hub bus driver, which created the joystick's PDO. Any optional bus filter drivers would also be present in the device stack, but the example omits bus filter drivers for simplicity.

    The wide arrow between the two devnodes in the previous figure indicates that the joystick devnode is a child of the USB hub devnode.

  7. The PnP Manager gathers information about the new device and begins configuring the device.

    The PnP Manager sends a sequence of IRPs to the device stack to gather information about the device. At this point, the device stack consists of only the PDO created by the device's parent bus driver and filter DOs for any optional bus filter drivers. Therefore, the bus driver and bus filter drivers are the only drivers that respond to these IRPs. In this example, the only driver in the joystick device stack is the parent bus driver, the USB hub driver.

    The PnP Manager gathers information about a new device by sending IRPs to the device stack. These IRPs include the following:

    • IRP_MN_QUERY_ID, a separate IRP for each of the following types of hardware IDs:

      BusQueryDeviceID
      BusQueryInstanceID
      BusQueryHardwareIDs
      BusQueryCompatibleIDs

    • IRP_MN_QUERY_CAPABILITIES
    • IRP_MN_QUERY_DEVICE_TEXT, a separate IRP for each of the following items:

      DeviceTextDescription
      DeviceTextLocationInformation

    • IRP_MN_QUERY_BUS_INFORMATION
    • IRP_MN_QUERY_RESOURCES
    • IRP_MN_QUERY_RESOURCE_REQUIREMENTS

    The PnP Manager sends the IRPs listed above at this stage of processing a new PnP device, but not necessarily in the order listed, so you should not make assumptions about the order in which the IRPs are sent. Also, you should not assume that the PnP Manager sends only the IRPs listed above.

    The PnP Manager checks the registry to determine whether the device has been installed on this machine previously. The PnP Manager checks for an <enumerator>\<deviceID> subkey for the device under the Enum branch. In this example, the device is new and must be configured "from scratch."

  8. The PnP Manager stores information about the device in the registry.

    The registry's Enum branch is reserved for use by operating system components and its layout is subject to change. Driver writers must use system routines to extract information related to drivers. Do not access the Enum branch directly from a driver. The following Enum information is listed for debugging purposes only.

    • The PnP Manager creates a subkey for the device under the key for the device's enumerator.

      The PnP Manager creates a subkey named HKLM\System\CurrentControlSet\Enum\<enumerator>\<deviceID>. It creates the <enumerator> subkey if it does not already exist.

      An enumerator is a component that discovers PnP devices based on a PnP hardware standard. The tasks of an enumerator are carried out by a PnP bus driver in partnership with the PnP Manager. A device is typically enumerated by its parent bus driver, such as PCI or PCMCIA. Some devices are enumerated by a bus filter driver, such as ACPI.

    • The PnP Manager creates a subkey for this instance of the device.

      If Capabilities.UniqueID is returned as TRUE for IRP_MN_QUERY_CAPABILITIES, the device's unique ID is unique across the system. If not, the PnP Manager modifies the ID so that it is unique system-wide.

      The PnP Manager creates a subkey named HKLM\System\CurrentControlSet\Enum\<enumerator>\<deviceID>\<instanceID>.

    • The PnP Manager writes information about the device to the subkey for the device instance.

      The PnP Manager stores information, including the following, if it was supplied for the device:

      DeviceDesc — from IRP_MN_QUERY_DEVICE_TEXT
      Location — from IRP_MN_QUERY_DEVICE_TEXT
      Capabilities — the flags from IRP_MN_QUERY_CAPABILITES
      UINumber — from IRP_MN_QUERY_CAPABILITIES
      HardwareID — from IRP_MN_QUERY_ID
      CompatibleIDs — from IRP_MN_QUERY_ID
      LogConf\BootConfig — from IRP_MN_QUERY_RESOURCES
      LogConf\BasicConfigVector — from IRP_MN_QUERY_
      RESOURCE_REQUIREMENTS

      Do not access these registry keys directly in a driver! They are listed here for debugging purposes only.

      In kernel mode, you access this information with the IoGetDeviceProperty routine or an IRP_MN_QUERY_CAPABILITIES request. In user mode, you access this information through device installation functions or PnP Configuration Manager functions.

At this point, the PnP Manager is ready to locate the function driver and filter drivers for the device, if any. (See the following figure.)

Finding Function and Filter Drivers

The following notes correspond to the numbered circles in the previous figure:

  9. The kernel-mode PnP Manager coordinates with the user-mode PnP Manager and user-mode Setup components to find the function and filter drivers for the device, if there are any.

    The kernel-mode PnP Manager queues an event to the user-mode PnP Manager, identifying a device that needs to be installed. Once a privileged user logs in, the user-mode components proceed with finding drivers. See the Device Installation Overview for information on Setup components and their role in installing a device.

  10. The user-mode Setup components direct the kernel-mode PnP Manager to load the function and filter drivers.

    The user-mode components call back to kernel mode to get the drivers loaded, causing their AddDevice routines to be called.

The following figure shows the PnP Manager loading the drivers (if appropriate), calling their AddDevice routines, and directing the drivers to start the device.

Calling AddDevice Routines and Starting the New Device

The following notes correspond to the numbered circles in the previous figure:

  11. Lower-filter drivers

    Before the function driver attaches to the device stack, the PnP Manager processes any lower-filter drivers. For each lower-filter driver, the PnP Manager calls the driver's DriverEntry routine if the driver is not yet loaded. Then the PnP Manager calls the driver's AddDevice routine. In its AddDevice routine, the filter driver creates a filter device object (filter DO) and attaches it to the device stack (IoAttachDeviceToDeviceStack). Once it attaches its device object to the device stack, the driver is engaged as a driver for the device.

    In the USB joystick example, there is one lower-filter driver for the device.

  12. Function driver

    After any lower filters are attached, the PnP Manager processes the function driver. The PnP Manager calls the function driver's DriverEntry routine if the driver is not yet loaded and calls the function driver's AddDevice routine. The function driver creates a function device object (FDO) and attaches it to the device stack.

    In this example, the function driver for the USB joystick is actually a pair of drivers: the HID class driver and the HID miniclass driver. The two drivers work together to serve as the function driver. The driver pair creates only one FDO and attaches it to the device stack.

  13. Upper-filter drivers

    After the function driver is attached, the PnP Manager processes any upper-filter drivers.

    In this example, there is one upper-filter driver for the device.

  14. Assigning resources and starting the device

    The PnP Manager assigns resources to the device, if needed, and issues an IRP to start the device.

    • Assigning resources

      Earlier in the configuration process, the PnP Manager gathered the hardware resource requirements for the device from the device's parent bus driver. After the full set of drivers is loaded for the device, the PnP Manager sends an IRP_MN_FILTER_RESOURCE_REQUIREMENTS request to the device stack. All drivers in the stack have the opportunity to handle this IRP and modify the device's resource requirements list, if necessary.

      The PnP Manager assigns resources to the device, if the device requires any, based on the device's requirements and the resources currently available.

      The PnP Manager might need to rearrange the resource assignments of existing devices to satisfy the needs of the new device. This reassignment of resources is called "rebalancing." The drivers for the existing devices receive a sequence of stop and start IRPs during a rebalance, but the rebalance must be transparent to users.

      In the example of the USB joystick, USB devices do not require hardware resources so the PnP Manager sets the resource list to NULL.

    • Starting the device (IRP_MN_START_DEVICE)

      Once the PnP Manager assigns resources to the device, it sends an IRP_MN_START_DEVICE IRP to the device stack to direct the drivers to start the device.

    After the device is started, the PnP Manager sends three more IRPs to the drivers for the device:

    • IRP_MN_QUERY_CAPABILITIES

      After the start IRP completes successfully, the PnP Manager sends another IRP_MN_QUERY_CAPABILITIES IRP to the device stack. All the drivers for the device have the option of handling the IRP. The PnP Manager sends this IRP at this time, after all drivers are attached and the device is started, because the function or filter drivers might need to access the device to collect capability information.

    • IRP_MN_QUERY_PNP_DEVICE_STATE

      This IRP gives a driver the opportunity to, for example, report that the device should not be displayed in user interfaces such as the Device Manager and the Hotplug Applet. This is useful for devices that are present on a system but are not usable in the current configuration, such as a game port on a laptop that is not usable when the laptop is undocked.

    • IRP_MN_QUERY_DEVICE_RELATIONS for bus relations

      The PnP Manager sends this IRP to determine whether the device has any child devices. If so, the PnP Manager configures each child device.


Passing PnP IRPs Down the Device Stack

The PnP Manager uses IRPs to direct drivers to start, stop, and remove devices and to query drivers about their devices. All PnP IRPs have the major function code IRP_MJ_PNP, and all PnP drivers must provide a DispatchPnP routine to service this function code. The PnP Manager initializes Irp->IoStatus.Status to STATUS_NOT_SUPPORTED when it sends an IRP. For more information, see DispatchPnP Routines.

All drivers for a device must have the opportunity to respond to a PnP IRP unless a driver in the stack fails the IRP. (See the following figure.)

Passing a PnP IRP Down the Device Stack

No single driver for a device can assume that it is the only driver that will respond to a PnP IRP. Consider, for example, a function driver that responds to an IRP_MN_QUERY_CAPABILITIES request and completes the IRP without passing it to the next-lower driver. None of the capabilities supported by lower drivers, such as a unique instance ID or power management capabilities supported by the parent bus driver, is reported.

A PnP IRP travels back up the device stack when the parent bus driver calls IoCompleteRequest and the I/O Manager calls any IoCompletion routines registered by the function driver or filter drivers.

A function or filter driver must do the following when it receives a PnP IRP:

  • If the driver performs actions in response to the IRP:
    1. Perform the appropriate actions.
    2. Set Irp->IoStatus.Status to an appropriate status, such as STATUS_SUCCESS. Set Irp->IoStatus.Information, if appropriate for the IRP.
    3. Set up the next stack location with IoSkipCurrentIrpStackLocation or IoCopyCurrentIrpStackLocationToNext. Call the latter routine if you set an IoCompletion routine.
    4. Set an IoCompletion routine, if necessary.
    5. Do not complete the IRP. (Do not call IoCompleteRequest.) The parent bus driver will complete the IRP.
  • If the driver does not perform actions for this IRP, it simply prepares to pass the IRP to the next driver:
    1. Call IoSkipCurrentIrpStackLocation to remove its stack location from the IRP.
    2. Do not set any fields in Irp->IoStatus.
    3. Do not set an IoCompletion routine.
    4. Do not complete the IRP. (Do not call IoCompleteRequest.) The parent bus driver will complete the IRP.

If a function or filter driver did not fail the IRP, it passes the IRP to the next-lower driver with IoCallDriver. A driver has a pointer to the next-lower driver; that pointer was returned from the IoAttachDeviceToDeviceStack call in the higher driver's AddDevice routine.

The parent bus driver completes the IRP after performing any tasks to respond to the IRP. After the bus driver calls IoCompleteRequest, the I/O Manager calls any IoCompletion routines registered by the function or filter drivers for the device.


Postponing PnP IRP Processing Until Lower Drivers Finish

Some PnP and power IRPs must be processed first by the parent bus driver for a device and then by each next-higher driver in the device stack. For example, the parent bus driver must be the first driver to perform its start operations for a device (IRP_MN_START_DEVICE), followed by each next-higher driver. For such an IRP, function and filter drivers must set an I/O completion routine, pass the IRP to the next-lower driver, and postpone any activities to process the IRP until the lower drivers have finished with the IRP.

An IoCompletion routine can be called at IRQL DISPATCH_LEVEL, but a function or filter driver might need to process the IRP at IRQL PASSIVE_LEVEL. To return to passive IRQL from an IoCompletion routine, a driver can use a kernel event. The driver registers an IoCompletion routine that sets a kernel-mode event and then the driver waits on the event in its DispatchPnP routine. When the event is set, lower drivers have completed the IRP and the driver is allowed to process the IRP.

Note that a driver must not use this technique to wait for lower drivers to finish a power IRP (IRP_MJ_POWER). Waiting on an event in the DispatchPower routine that is set in the IoCompletion routine can cause a deadlock. See Passing Power IRPs for more information.

The following two figures show an example of how a driver waits for lower drivers to complete a PnP IRP. The example shows what the function and bus drivers must do, plus how they interact with the PnP Manager and the I/O Manager.

Postponing PnP IRP Handling — Part 1

The following notes correspond to the circled numbers in the previous figure:

  1. The PnP Manager calls the I/O Manager to send an IRP to the top driver in the device stack.
  2. The I/O Manager calls the DispatchPnP routine of the top driver. In this example, there are only two drivers in the device stack (the function driver and the parent bus driver) and the function driver is the top driver.
  3. The function driver declares and initializes a kernel-mode event, sets up the stack location for the next-lower driver, and sets an IoCompletion routine for this IRP.

    The function driver can use IoCopyCurrentIrpStackLocationToNext to set up the stack location.

    In the call to IoSetCompletionRoutine, the function driver sets InvokeOnSuccess, InvokeOnError, and InvokeOnCancel to TRUE and passes the kernel-mode event as part of the context parameter.

  4. The function driver passes the IRP down the device stack with IoCallDriver before performing any operations to handle the IRP.
  5. The I/O Manager sends the IRP to the next-lower driver in the device stack by calling that driver's DispatchPnP routine.
  6. The next-lower driver in this example is the lowest driver in the device stack, the parent bus driver. The bus driver performs its operations to start the device. The bus driver sets Irp->IoStatus.Status, sets Irp->IoStatus.Information if relevant to this IRP, and completes the IRP by calling IoCompleteRequest.

    If the bus driver calls other driver routines or sends I/O to the device in order to start it, the bus driver does not complete the PnP IRP in its DispatchPnP routine. Instead, it must mark the IRP pending with IoMarkIrpPending and return STATUS_PENDING from its DIspatchPnP routine. The driver later calls IoCompleteRequest from another driver routine, possibly a DPC routine.

The following figure shows the second part of the example, where the higher drivers in the device stack resume their postponed IRP processing.

Postponing PnP IRP Handling — Part 2

The following notes correspond to the circled numbers in the previous figure:

  7. When the bus driver calls IoCompleteRequest, the I/O Manager examines the stack locations of the higher drivers and calls any IoCompletion routines it finds. In this example, the I/O Manager locates and calls the IoCompletion routine for the next-higher driver, the function driver.
  8. The function driver's IoCompletion routine sets the kernel-mode event supplied in the context parameter and returns STATUS_MORE_PROCESSING_REQUIRED.

    The IoCompletion routine must return STATUS_MORE_PROCESSING_REQUIRED to prevent the I/O Manager from calling IoCompletion routines set by higher drivers at this time. The IoCompletion routine uses this status to forestall completion so its driver's DispatchPnP routine can regain control. The I/O Manager will resume calling higher drivers' IoCompletion routines for this IRP when this driver's DispatchPnI routine completes the IRP.

  9. The I/O Manager stops completing the IRP and returns control to the routine that called IoCompleteRequest, which in this example is the bus driver's DispatchPnP routine.
  10. The bus driver returns from its DispatchPnp routine with status indicating the result of its IRP processing: either STATUS_SUCCESS or an error status.
  11. IoCallDriver returns control to its caller, which in this example is the function driver's DispatchPnP routine.
  12. The function driver's DispatchPnP routine resumes processing the IRP.

    If IoCallDriver returns STATUS_PENDING, the DispatchPnP routine has resumed execution before its IoCompletion routine has been called. The DispatchPnP routine, therefore, must wait for the kernel event to be signaled by its IoCompletion routine. This ensures that the DispatchPnP routine will not continue processing the IRP until all lower drivers have completed it.

    If Irp->IoStatus.Status is set to an error, a lower driver has failed the IRP and the function driver must not continue handling the IRP (except for any necessary cleanup).

  13. Once lower drivers have successfully completed the IRP, the function driver processes the IRP.

    For IRPs being handled first by the parent bus driver, the bus driver typically sets a successful status in Irp->IoStatus.Status and optionally sets a value in Irp->IoStatus.Information. Function and filter drivers leave the values in IoStatus as is unless they fail the IRP.

    The function driver's DispatchPnP routine calls IoCompleteRequest to complete the IRP. The I/O Manager resumes I/O completion processing. In this example, there are no filter drivers above the function driver, and thus no more IoCompletion routines to call. When IoCompleteRequest returns control to the function driver DispatchPnP routine, the DispatchPnP routine returns status.

For some IRPs, if a function or filter driver fails the IRP on its way back up the device stack, the PnP Manager informs the lower drivers. For example, if a function or filter driver fails an IRP_MN_START_DEVICE, the PnP Manager sends an IRP_MN_REMOVE_DEVICE to the device stack.


Starting a Device

The PnP Manager sends an IRP_MN_START_DEVICE request to drivers either to start a newly enumerated device or to restart an existing device that was stopped for resource rebalancing.

Function and filter drivers must set an IoCompletion routine, pass the IRP_MN_START_DEVICE request down the device stack, and postpone their start operations until all lower drivers have finished with the IRP. The parent bus driver, the bottom driver in the device stack, must be the first driver to perform its start operations on a device before the device is accessed by other drivers.

To ensure proper sequencing of start operations, the PnP Manager on Windows 2000 and later systems postpones exposing device interfaces and blocks create requests for the device until the start IRP succeeds.

If a driver for a device fails the IRP_MN_START_DEVICE request, the PnP Manager sends an IRP_MN_REMOVE_DEVICE request to the device stack (on Windows 2000 and later systems). In response to this IRP, the drivers for the device undo their start operations (if they succeeded the start IRP), undo their AddDevice operations, and detach from the device stack. The PnP Manager marks such a device "failed start."

This section covers the following topics:

Starting a Device in a Function Driver

Starting a Device in a Filter Driver

Starting a Device in a Bus Driver

Design Guidelines for Starting Devices


Starting a Device in a Function Driver

A function driver sets an IoCompletion routine, passes an IRP_MN_START_DEVICE request down the device stack, and postpones its start operations until all lower drivers have finished with the IRP. See Postponing PnP IRP Processing Until Lower Drivers Finish for detailed information on using a kernel event and an IoCompletion routine to postpone IRP processing.

When its DispatchPnP routine regains control after all lower drivers have finished with the IRP, the function driver performs its tasks for starting the device. A function driver starts the device with a procedure like the following:

  1. If a lower driver failed the IRP (IoCallDriver returned an error), do not continue processing the IRP. Do any necessary cleanup and return from the DispatchPnP routine (go to the last step in this list).
  2. If lower drivers processed the IRP successfully, start the device.

    The exact steps to start a device vary from device to device. Such steps might include mapping I/O space, initializing hardware registers, setting the device in the D0 power state, and connecting the interrupt with IoConnectInterrupt. If the driver is restarting a device after an IRP_MN_STOP_DEVICE request, the driver might have device state to restore.

    The device must be powered on before any drivers can access it. See Powering Up a Device for more information.

    If the device should be enabled for wake-up, its power policy owner (usually the function driver) should send a wait/wake IRP after it powers up the device and before it completes the IRP_MN_START_DEVICE request. For details, see Sending a Wait/Wake IRP.

  3. Start IRPs in the IRP-holding queue.

    Clear the driver-defined HOLD_NEW_REQUESTS flag and start the IRPs in the IRP-holding queue. Drivers should do this when starting a device for the first time and when restarting a device after a query-stop or stop IRP. See Holding Incoming IRPs When a Device is Paused for more information.

  4. [Optional] Enable interfaces for the device by calling IoSetDeviceInterfaceState.

    Enable the interfaces, if any, that the driver previously registered in its AddDevice routine (or in an INF or by another component such as a coinstaller).

    On Windows 2000 and later systems, the PnP Manager does not send notification of device-interface arrivals until the IRP_MN_START_DEVICE IRP completes, indicating that all the drivers for the device have completed their start operations. The PnP Manager also fails any create requests that arrive before all the drivers for the device complete the start IRP.

  5. Complete the IRP.

    The function driver's IoCompletion routine returned STATUS_MORE_PROCESSING_REQUIRED, as described in Postponing PnP IRP Processing Until Lower Drivers Finish, so the function driver's DispatchPnP routine must call IoCompleteRequest to resume I/O completion processing.

    If the function driver's start operations were successful, the driver sets Irp->IoStatus.Status to STATUS_SUCCESS, calls IoCompleteRequest with a priority boost of IO_NO_INCREMENT, and returns STATUS_SUCCESS from its DispatchPnP routine.

    If the function driver encounters an error during its start operations, the driver sets an error status in the IRP, calls IoCompleteRequest with IO_NO_INCREMENT, and returns the error from its DispatchPnP routine.

    If a lower driver failed the IRP (IoCallDriver returned an error), the function driver calls IoCompleteRequest with IO_NO_INCREMENT and returns the IoCallDriver error from its DispatchPnP routine. The function driver does not set Irp->IoStatus.Status in this case because the status has already been set by the lower driver that failed the IRP.

When a function driver receives an IRP_MN_START_DEVICE request, it should examine the structures at IrpSp->Parameters.StartDevice.AllocatedResources and IrpSp->Parameters.StartDevice.AllocatedResourcesTranslated, which describe the raw and translated resources, respectively, that the PnP Manager has assigned to the device. Drivers should save a copy of each resource list in the device extension a debugging aid.

The resource lists are paired CM_RESOURCE_LIST structures, in which each element of the raw list corresponds to the same element of the translated list. For example, if AllocatedResources.List[0] describes a raw I/O port range, then AllocatedResourcesTranslated.List[0] describes the same range after translation. Each translated resource includes a physical address and the type of the resource.

If a driver is assigned a translated memory resource (CmResourceTypeMemory), it must call MmMapIoSpace to map the physical address into a virtual address through which it can access device registers. For a driver to operate in a platform independent manner, it should check each returned, translated resource and map it, if necessary.

A function driver should do the following in response to an IRP_MN_START_DEVICE to ensure access to all device resources:

  1. Copy IrpSp->Parameters.StartDevice.AllocatedResources to the device extension.
  2. Copy IrpSp->Parameters.StartDevice.AllocatedResourcesTranslated to the device extension.
  3. In a loop, inspect each descriptor element in AllocatedResourcesTranslated. If the descriptor resource type is CmResourceTypeMemory, call MmMapIoSpace, passing the physical address and length of the translated resource.

When the driver receives an IRP_MN_STOP_DEVICE, IRP_MN_REMOVE_DEVICE, or IRP_MN_SURPRISE_REMOVAL request, it must release the mappings by calling MmUnmapIoSpace in a similar loop. The driver should also call MmUnmapIoSpace if it must fail the IRP_MN_START_DEVICE request.

See Mapping Bus-Relative Addresses to Virtual Addresses for more information.


Starting a Device in a Filter Driver

An upper-level filter driver might augment any of the start activities of the function driver.

A lower-level filter typically augments the features of the device and might participate in starting the device.


Starting a Device in a Bus Driver

A bus driver starts a child device (child PDO) with a procedure such as the following in its DispatchPnP routine:

  1. Start the device.

    The exact steps vary from device to device.

    For example, the PCI bus driver programs its mapping registers to enable requests on the PCI bus. The PnP ISA bus driver enables the PnP ISA card so the function driver can access it.

  2. Complete the IRP.

    If the bus driver's start operations were successful, the driver sets Irp->IoStatus.Status to STATUS_SUCCESS and calls IoCompleteRequest specifying a priority boost of IO_NO_INCREMENT. The bus driver returns STATUS_SUCCESS from its DispatchPnP routine.

    If the bus driver encounters an error during its start operations, the driver sets an error status in the IRP, calls IoCompleteRequest with IO_NO_INCREMENT, and returns the error from its DispatchPnP routine.

If a bus driver requires some time to start the device, it can mark the IRP as pending and return STATUS_PENDING.


Design Guidelines for Starting Devices

  • The PnP Manager fails create requests for the device until the IRP_MN_START_DEVICE IRP completes, indicating that all the drivers for the device have performed their start operations.
  • Because a DispatchPnP routine runs in the context of a system thread at IRQL PASSIVE_LEVEL, any memory allocated with ExAllocatePoolWithTag for use exclusively during initialization can be from paged pool as long as the driver does not control the device that holds a system page file. Such a memory allocation must be released with ExFreePool before the DispatchPnP routine returns control.
  • A WDM device driver's ISR should be capable of determining whether it has been called with a spurious interrupt even during device startup. On return from the call to IoConnectInterrupt in the code path that handles IRP_MN_START_DEVICE, the ISR can be called immediately if interrupts are enabled on the device.


Stopping a Device

The PnP Manager directs drivers to stop a device in the following situations:

  • To rebalance the hardware resources being used by the device. Rebalancing is typically necessary when a new device is enumerated that requires a resource already in use.
  • To disable the device in response to a Device Manager request (Windows 98/Me only). Windows 2000 and later systems send remove IRPs in this situation; see Understanding When Remove IRPs Are Issued.
  • After a failed IRP_MN_START_DEVICE request (Windows 98/Me only)

This section covers the following topics:

Stopping a Device to Rebalance Resources

Stopping a Device to Disable It (Windows 98/Me)

Stopping a Device after a Failed Start (Windows 98/Me)

Handling Stop IRPs (Windows 2000 and Later)

Handling Stop IRPs (Windows 98/Me)


Stopping a Device to Rebalance Resources

The following figure shows the sequence of IRPs involved in stopping and restarting a device to rebalance resources.

Stopping a Device to Rebalance Resources

The following notes correspond to the circled numbers in the previous figure:

  1. The PnP Manager issues an IRP_MN_QUERY_STOP_DEVICE to ask whether the drivers for a device can stop the device and release its hardware resources.

    If all the drivers in the device stack return STATUS_SUCCESS, the drivers have put the device into a state (stop-pending) from which the device can be quickly stopped.

    The PnP Manager queries as many device stacks as necessary to rebalance the required resources.

  2. The PnP Manager issues an IRP_MN_STOP_DEVICE to stop the device.

    On Windows 2000 and later systems, the PnP Manager sends a stop IRP only if a previous query-stop IRP for the device completed successfully. In response to a stop IRP, drivers release the device's hardware resources (such as its I/O ports) and hold any IRPs that require access to the device.

  3. After successfully rebalancing resources, the PnP Manager issues IRP_MN_START_DEVICE requests to restart any devices that it stopped during the rebalance.
  4. Otherwise, the PnP Manager cancels a query-stop IRP by sending an IRP_MN_CANCEL_STOP_DEVICE.

    In response to an IRP_MN_CANCEL_STOP_DEVICE, the drivers for a device return the device to the started state and resume processing I/O requests for the device.

    The PnP Manager cancels the query-stop for a device stack if one driver in the stack failed the request or if the overall rebalance operation failed and it is canceling all its query-stop requests. When the PnP Manager cancels the query-stop on just one device stack, it sends the IRP_MN_CANCEL_STOP_DEVICE request because any drivers attached above the driver that failed the query have the device in the stop-pending state. When the IRP_MN_CANCEL_STOP_DEVICE succeeds, drivers have returned the device to the started state.

  5. If a driver fails to restart the device after rebalancing resources, the PnP Manager sends remove IRPs to the device stack (on Windows 2000 and later systems).

    The PnP Manager first sends an IRP_MN_SURPRISE_REMOVAL request. Then it sends an IRP_MN_REMOVE_DEVICE request, but only after all open handles to the device are closed.

Rebalancing the hardware resources of a PnP device must be transparent to applications and end users. Users might experience a temporary delay in operation, but data must not be lost. You must take that into consideration when you handle stop IRPs.


Stopping a Device to Disable It (Windows 98/Me)

On Windows 98/Me, the PnP Manager issues stop IRPs when the Device Manager disables the device. (Windows 2000 and later systems issue remove IRPS in this situation).

The PnP Manager sends the stop IRPs in the following sequence:

  1. The PnP Manager issues an IRP_MN_QUERY_STOP_DEVICE to ask whether the drivers for a device can stop the device.

    If all the drivers in the device stack return STATUS_SUCCESS, the drivers have put the device into a state (stop-pending) from which the device can be quickly stopped.

    The PnP Manager queries as many device stacks as necessary to disable the device.

  2. If the IRP_MN_QUERY_STOP_DEVICE succeeds, the PnP Manager issues an IRP_MN_STOP_DEVICE to stop the device.

    The PnP Manager sends the stop IRP only if the previous query-stop IRP for the device completed successfully. In response to the stop IRP, drivers release the device's hardware resources (such as its I/O ports) and fail any IRPs that require access to the device.

  3. If the IRP_MN_QUERY_STOP_DEVICE fails, the PnP Manager sends an IRP_MN_CANCEL_STOP_DEVICE to cancel the query.

    In response to an IRP_MN_CANCEL_STOP_DEVICE, the drivers for a device return the device to the started state and resume processing I/O requests for the device.

    The PnP Manager cancels the query-stop for a device stack if one driver in the stack failed the request. When the PnP Manager cancels the query-stop on just one device stack, it sends the IRP_MN_CANCEL_STOP_DEVICE request because any drivers attached above the driver that failed the query have the device in the stop-pending state. When the IRP_MN_CANCEL_STOP_DEVICE succeeds, drivers have returned the device to the started state.

When a device is being disabled, its drivers cannot queue incoming IRPs because there is no guarantee when the device might be re-enabled. Consequently, data might be lost.


Stopping a Device after a Failed Start

Previous Next

Stopping a Device after a Failed Start (Windows 98/Me)

On Windows 98/Me, the PnP Manager issues an IRP_MN_STOP_DEVICE request without a preceding query when the drivers for a device fail an IRP_MN_START_DEVICE request. (On Windows 2000 and later, the PnP Manager sends remove IRPs in this situation. See Understanding When Remove IRPs Are Issued.)

In response to the stop IRP, drivers release the device's hardware resources (such as its I/O ports), disable and deregister any user-mode interfaces, and fail any incoming I/O requests that require access to the device.


Handling Stop IRPs (Windows 2000 and Later)

Drivers that run only on Windows 2000 and later systems (WDM versions 0x10 and greater) receive stop IRPs only when the PnP Manager rebalances resources. The following sections describe techniques such drivers should use in handling stop IRPs:

Handling an IRP_MN_QUERY_STOP_DEVICE Request (Windows 2000 and Later)

Handling an IRP_MN_STOP_DEVICE Request (Windows 2000 and Later)

Handling an IRP_MN_CANCEL_STOP_DEVICE Request (Windows 2000 and Later)

Holding Incoming IRPs When A Device Is Paused

WDM drivers that also run on Windows 98/Me must handle these IRPs differently. See Handling Stop IRPs (Windows 98/Me) for details.


Handling an IRP_MN_QUERY_STOP_DEVICE Request (Windows2000 and later)

Previous Next

Handling an IRP_MN_QUERY_STOP_DEVICE Request (Windows 2000 and later)

An IRP_MN_QUERY_STOP_DEVICE request is handled first by the top driver in the device stack and then by each next lower driver. A driver handles stop IRPs in its DispatchPnP routine.

In response to an IRP_MN_QUERY_STOP_DEVICE, a driver must do the following:

  1. Determine whether the device can be stopped, and its hardware resources released, without adverse affects.

    A driver must fail a query-stop IRP if any of the following are true:

    • A driver has been notified (through IRP_MN_DEVICE_USAGE_NOTIFICATION) that the device is in the path of a paging, hibernation, or crash dump file.
    • The device's hardware resources cannot be released.

    A driver might fail a query-stop IRP if the following is true:

    • The driver must not drop I/O requests and does not have a mechanism for queuing IRPs.

      While the device is in the stopped state, a driver must hold IRPs that require access to the device. If a driver does not queue IRPs, it must not allow the device to be stopped and thus must fail a query-stop IRP.

      The exception to this rule is a device that is allowed to drop I/O. The drivers for such a device can succeed query-stop and stop requests without queuing IRPs.

  2. If the device cannot be stopped, fail the query-stop IRP.

    Set Irp->IoStatus.Status to an appropriate error status, call IoCompleteRequest with IO_NO_INCREMENT, and return from the driver's DispatchPnP routine. Do not pass the IRP to the next lower driver.

  3. If the device can be stopped and the driver queues IRPs, set the HOLD_NEW_REQUESTS flag in the device extension so subsequent IRPs will be queued (see Holding Incoming IRPs When a Device is Paused).

    Alternatively, the drivers for a device can defer completely pausing the device until the drivers receive the subsequent IRP_MN_STOP_DEVICE request. Such drivers, however, must queue any requests that would prevent them from immediately succeeding the stop IRP when it arrives. Until the device is restarted, such drivers must queue requests such as the following:

    • IRP_MN_DEVICE_USAGE_NOTIFICATION requests (for example, to put a paging file on the device).
    • Requests for isochronous transfers.
    • Create requests that would prevent the drivers from succeeding a stop IRP.
  4. If the device cannot have an IRP in progress fail, ensure that any outstanding requests that were passed to other driver routines and to lower drivers have completed.

    One way that a driver can achieve this is to use a reference count and an event to ensure that all requests have been completed:

    • In its AddDevice routine, the driver defines an I/O reference count in the device extension and initializes the count to one.
    • Also in its AddDevice routine, the driver creates an event with KeInitializeEvent and initializes the event to the Not-Signaled state with KeClearEvent.
    • Each time it processes an IRP, the driver increments the reference count with InterlockedIncrement.
    • Each time it completes a request, the driver decrements the reference count with InterlockedDecrement.

      The driver decrements the reference count in the IoCompletion routine, if the request has one, or right after the call to IoCallDriver if the driver uses no IoCompletion routine for the request.

    • When the driver receives an IRP_MN_QUERY_STOP_DEVICE, it decrements the reference count with InterlockedDecrement. If there are no outstanding requests, this reduces the reference count to zero.
    • When the reference count reaches zero, the driver sets the event with KeSetEvent signaling that the query-stop code can continue.

    As an alternative to the above procedure, a driver can serialize the IRP_MN_QUERY_STOP_DEVICE IRP behind any IRPs in progress.

  5. Perform any other steps required to put the device in the stop-pending state.

    After a driver succeeds a query-stop IRP, it must be ready to succeed an IRP_MN_STOP_DEVICE.

  6. Finish the IRP.

    In a function or filter driver:

    • Set Irp->IoStatus.Status to STATUS_SUCCESS.
    • Set up the next stack location with IoSkipCurrentIrpStackLocation and pass the IRP to the next lower driver with IoCallDriver.
    • Propagate the status from IoCallDriver as the return status from the DispatchPnP routine.
    • Do not complete the IRP.

    In a bus driver:

    • Set Irp->IoStatus.Status to STATUS_SUCCESS.

      If, however, the devices on the bus use hardware resources, re-evaluate the resource requirements of the bus and the child devices. If any of the requirements have changed, return STATUS_RESOURCE_REQUIREMENTS_CHANGED instead of STATUS_SUCCESS. This status indicates success but requests that the PnP Manager requery your resources before sending the stop IRP.

    • Complete the IRP (IoCompleteRequest) with IO_NO_INCREMENT.
    • Return from the DispatchPnP routine.

If any driver in the device stack fails the IRP_MN_QUERY_STOP_DEVICE, the PnP Manager sends an IRP_MN_CANCEL_STOP_DEVICE to the device stack. This prevents drivers from requiring an IoCompletion routine for a query-stop IRP to detect whether a lower driver failed the IRP.


Handling an IRP_MN_STOP_DEVICE Request (Windows2000 and later)

Previous Next

Handling an IRP_MN_STOP_DEVICE Request (Windows 2000 and later)

An IRP_MN_STOP_DEVICE request is handled first by the top driver in the device stack and then by each next lower driver. A driver handles stop IRPs in its DispatchPnP routine.

A driver handles an IRP_MN_STOP_DEVICE request with a procedure such as the following:

  1. Ensure that the device is paused.

    If a driver did not completely pause the device in response to the IRP_MN_QUERY_STOP request, it must do so now. Set a HOLD_NEW_REQUESTS flag in the device extension and perform any other necessary operations to pause the device.

    The device might lose power during the resource-rebalance operation and thus might lose device state. Drivers for the device should save any device state information and restore it when they receive the subsequent IRP_MN_START_DEVICE request.

  2. Release the hardware resources for the device.

    In a function driver, the exact operations depend on the device and the driver but can include disconnecting an interrupt with IoDisconnectInterrupt, freeing physical address ranges with MmUnmapIoSpace, and freeing I/O ports.

    If a filter or bus driver acquired any hardware resources for the device, that driver must release the resources in response to an IRP_MN_STOP_DEVICE request.

  3. Set Irp->IoStatus.Status to STATUS_SUCCESS.
  4. Pass the IRP to the next lower driver or complete the IRP.
    • In a function or filter driver, set up the next stack location with IoSkipCurrentIrpStackLocation, pass the IRP to the next lower driver with IoCallDriver, and return the status from IoCallDriver as the return status from the DispatchPnP routine. Do not complete the IRP.
    • In a bus driver, complete the IRP using IoCompleteRequest with IO_NO_INCREMENT and return from the DispatchPnP routine.

While the device is stopped to rebalance resources, a driver cannot start any IRPs that access the device. A driver must queue such IRPs, as described in Holding Incoming IRPs When a Device is Paused, or fail them if the driver does not implement an IRP-holding queue and must not drop I/O requests.


Handling an IRP_MN_CANCEL_STOP_DEVICE Request (Windows2000 and later)

Previous Next

Handling an IRP_MN_CANCEL_STOP_DEVICE Request (Windows 2000 and later)

An IRP_MN_CANCEL_STOP_DEVICE request must be handled first by the parent bus driver for a device and then by each next higher driver in the device stack. A driver handles stop IRPs in its DispatchPnP routine.

In response to an IRP_MN_CANCEL_STOP_DEVICE request, a driver must return the device to its started state and resume normal operation. Drivers must succeed a cancel-stop IRP.

A driver handles an IRP_MN_CANCEL_STOP_DEVICE request with a procedure such as the following:

  1. Postpone restarting the device until lower drivers have completed their restart operations. (See Postponing PnP IRP Processing Until Lower Drivers Finish.)
  2. After lower drivers finish, return the device to its started state.

    Exact operations depend on the device and the driver.

  3. Start IRPs in the IRP-holding queue.

    If the driver was holding requests while the device was in the stop-pending state, clear the HOLD_NEW_REQUESTS flag and start the IRPs in the IRP-holding queue. See Holding Incoming IRPs When a Device is Paused for more information.

  4. Complete the IRP with IoCompleteRequest.
    • In a function or filter driver:

      The driver's IoCompletion routine returned STATUS_MORE_PROCESSING_REQUIRED, as described in Postponing PnP IRP Processing Until Lower Drivers Finish., so the driver's DispatchPnP routine must call IoCompleteRequest to resume I/O completion processing.

      The driver sets Irp->IoStatus.Status to STATUS_SUCCESS, calls IoCompleteRequest with a priority boost of IO_NO_INCREMENT, and returns STATUS_SUCCESS from its DispatchPnP routine.

      Drivers must not fail this operation. If a driver fails the restart IRP, the device is in an inconsistent state and will not operate properly.

    • In a parent bus driver:

      The driver sets Irp->IoStatus.Status to STATUS_SUCCESS and calls IoCompleteRequest specifying a priority boost of IO_NO_INCREMENT. The bus driver returns STATUS_SUCCESS from its DispatchPnP routine.

      A bus driver must not fail this operation. If a driver fails the restart IRP, the device is in an inconsistent state and will not operate properly.

A driver might receive a spurious cancel-stop request when the device is started and active. This can occur, for example, if the driver (or a driver higher in the device stack) failed an IRP_MN_QUERY_STOP_DEVICE request. When a device is started and active, drivers can safely succeed spurious cancel-stop requests for the device.


Holding Incoming IRPs When A Device Is Paused

The drivers for a device must pause the device when its resources are being rebalanced. During resource rebalancing, some drivers pause the device in response to an IRP_MN_QUERY_STOP_DEVICE request and other drivers delay pausing the device until they receive the IRP_MN_STOP_DEVICE request. In either case, the device must be paused when the IRP_MN_STOP_DEVICE succeeds.

The drivers must finish any IRPs in progress on the device and refrain from starting any new IRPs that require access to the device.

To hold IRPs while a device is paused, a driver implements a procedure such as the following:

  1. In its AddDevice routine, define a flag in the device extension with a name like HOLD_NEW_REQUESTS. Clear the flag.
  2. Create a FIFO queue for holding IRPs.

    If the driver already queues IRPs, it can reuse the same queue because the driver is required to finish any outstanding requests before pausing the device.

    If the driver does not already have an IRP queue, it must create one in its AddDevice routine. What kind of queue it creates depends on how the driver flushes the queue. A driver might use an interlocked, doubly-linked list and the ExInterlocked..List routines.

  3. In its DispatchPnP code for IRP_MN_QUERY_STOP_DEVICE (or IRP_MN_STOP_DEVICE), finish any outstanding requests and set the HOLD_NEW_REQUESTS flag.
  4. In a dispatch routine that accesses the device, such as DispatchWrite or DispatchRead, check whether the HOLD_NEW_REQUESTS flag is set. If so, the driver must mark the IRP pending and queue it.

    The driver's DispatchPnP routine must continue to process PnP IRPs rather than hold them and the DispatchPower routine must continue to process power IRPs.

  5. In DispatchPnP, in response to a start or cancel-stop IRP, clear the HOLD_NEW_REQUESTS flag and start the IRPs in the IRP-holding queue.

    These actions are probably the last steps for processing these PnP IRPs. For example, in response to a start IRP, the driver must first perform any operations to start the device and then it can start the IRPs in the IRP-holding queue.

    Errors in processing IRPs from the IRP-holding queue do not affect the status returned for the start or cancel-stop IRPs.


Handling Stop IRPs (Windows98/Me)

Previous Next

Handling Stop IRPs (Windows 98/Me)

On Windows 98/Me, the PnP Manager can send stop IRPs for the following reasons:

  • To pause the device while rebalancing resources
  • To stop the device when the Device Manager disables it
  • To stop the device after a failed IRP_MN_START_DEVICE request

A driver cannot determine from the IRP why it was sent. Consequently, WDM drivers that run on Windows 98/Me must handle all stop IRPs as if the device were being disabled. In short, this means that such drivers fail incoming I/O requests rather than queuing them (as on Windows 2000 and later).

The following topics provide step-by-step details on handling each of the stop IRPs:

Handling an IRP_MN_QUERY_STOP_DEVICE Request (Windows 98/Me)

Handling an IRP_MN_STOP_DEVICE Request(Windows 98/Me)

Handling an IRP_MN_CANCEL_STOP_DEVICE Request (Windows 98/Me)


Handling an IRP_MN_QUERY_STOP_DEVICE Request (Windows98/Me)

Previous Next

Handling an IRP_MN_QUERY_STOP_DEVICE Request (Windows 98/Me)

An IRP_MN_QUERY_STOP_DEVICE request is handled first by the top driver in the device stack and then by each next lower driver. A driver handles stop IRPs in its DispatchPnP routine.

In response to an IRP_MN_QUERY_STOP_DEVICE, a driver must do the following:

  1. Determine whether the device can be stopped without adverse affects.

    A driver must fail a query-stop IRP if any of the following are true:

    • A driver has been notified (through IRP_MN_DEVICE_USAGE_NOTIFICATION) that the device is in the path of a paging, hibernation, or crash dump file.
    • The device's hardware resources cannot be released.
    • There are open handles to the device.

    A driver might fail a query-stop IRP if the following is true:

    • The driver must not drop I/O requests.
  2. If the device cannot be stopped, fail the query-stop IRP.

    Set Irp->IoStatus.Status to an appropriate error status, call IoCompleteRequest with IO_NO_INCREMENT, and return from the driver's DispatchPnP routine. Do not pass the IRP to the next lower driver.

  3. If the device can be stopped, call IoSetDeviceInterfaceState and IoRegisterDeviceInterface to disable and deregister any user-mode interfaces. Then start failing any incoming I/O requests that require access to the device.

    Alternatively, the drivers for a device can defer completely pausing the device until the drivers receive the subsequent IRP_MN_STOP_DEVICE request. Such drivers, however, should disable and deregister their user-mode interfaces while handling the query-stop request to prevent the opening of any additional handles to the device.

    Furthermore, such drivers must fail any requests that would prevent them from immediately succeeding the stop IRP when it arrives. Until the device is restarted, such drivers must fail requests such as the following:

    • IRP_MN_DEVICE_USAGE_NOTIFICATION requests (for example, to put a paging file on the device).
    • Requests for isochronous transfers.
    • Create requests that would prevent the drivers from succeeding a stop IRP.
  4. If the device cannot allow an IRP in progress to fail, ensure that any outstanding requests that were passed to other driver routines and to lower drivers have completed.

    One way that a driver can achieve this is to use a reference count and an event to ensure that all requests have been completed:

    • In its AddDevice routine, the driver defines an I/O reference count in the device extension and initializes the count to one.
    • Also in its AddDevice routine, the driver creates an event with KeInitializeEvent and initializes the event to the Not-Signaled state with KeClearEvent.
    • Each time it processes an IRP, the driver increments the reference count with InterlockedIncrement.
    • Each time it completes a request, the driver decrements the reference count with InterlockedDecrement.

      The driver decrements the reference count in the IoCompletion routine, if the request has one, or immediately after the call to IoCallDriver if the driver uses no IoCompletion routine for the request.

    • When the driver receives an IRP_MN_QUERY_STOP_DEVICE, it decrements the reference count with InterlockedDecrement. If there are no outstanding requests, this reduces the reference count to zero.
    • When the reference count reaches zero, the driver sets the event with KeSetEvent signaling that the query-stop code can continue.

    As an alternative to the above procedure, a driver can serialize the IRP_MN_QUERY_STOP_DEVICE IRP behind any IRPs in progress.

  5. Perform any other steps required to put the device in the stop-pending state.

    After a driver succeeds a query-stop IRP, it must be ready to succeed an IRP_MN_STOP_DEVICE.

  6. Finish the IRP.

    In a function or filter driver:

    • Set Irp->IoStatus.Status to STATUS_SUCCESS.
    • Set up the next stack location with IoSkipCurrentIrpStackLocation and pass the IRP to the next lower driver with IoCallDriver.
    • Propagate the status from IoCallDriver as the return status from the DispatchPnP routine.
    • Do not complete the IRP.

    In a bus driver:

    • Set Irp->IoStatus.Status to STATUS_SUCCESS.

      If, however, the devices on the bus use hardware resources, re-evaluate the resource requirements of the bus and the child devices. If any of the requirements have changed, return STATUS_RESOURCE_REQUIREMENTS_CHANGED instead of STATUS_SUCCESS. This status indicates success but requests that the PnP Manager requery your resources before sending the stop IRP.

    • Complete the IRP (IoCompleteRequest) with IO_NO_INCREMENT.
    • Return from the DispatchPnP routine.

If any driver in the device stack fails the IRP_MN_QUERY_STOP_DEVICE, the PnP Manager sends an IRP_MN_CANCEL_STOP_DEVICE to the device stack. This prevents drivers from requiring an IoCompletion routine for a query-stop IRP to detect whether a lower driver failed the IRP.


Handling an IRP_MN_STOP_DEVICE Request (Windows98/Me)

Previous Next

Handling an IRP_MN_STOP_DEVICE Request (Windows 98/Me)

On Windows 98/Me, the PnP Manager usually sends an IRP_MN_STOP_DEVICE request after a successful query-stop. However, if the device stack previously failed an IRP_MN_START_DEVICE request, the PnP Manager sends an IRP_MN_STOP_DEVICE request without a preceding query.

An IRP_MN_STOP_DEVICE request is handled first by the top driver in the device stack and then by each next lower driver. A driver handles stop IRPs in its DispatchPnP routine.

A driver handles an IRP_MN_STOP_DEVICE request with a procedure such as the following:

  1. Ensure that the device is paused.

    If a driver did not completely pause the device in response to an IRP_MN_QUERY_STOP request, it must do so now.

    The device might lose power while it is stopped and thus might lose device state. Drivers for the device should save any device state information and restore it when they receive the subsequent IRP_MN_START_DEVICE request.

  2. Release the hardware resources for the device.

    In a function driver, the exact operations depend on the device and the driver but can include disconnecting an interrupt with IoDisconnectInterrupt, freeing physical address ranges with MmUnmapIoSpace, and freeing I/O ports.

    If a filter or bus driver acquired any hardware resources for the device, that driver must release the resources in response to an IRP_MN_STOP_DEVICE request.

  3. Set Irp->IoStatus.Status to STATUS_SUCCESS.
  4. Pass the IRP to the next lower driver or complete the IRP.
    • In a function or filter driver, set up the next stack location with IoSkipCurrentIrpStackLocation, pass the IRP to the next lower driver with IoCallDriver, and return the status from IoCallDriver as the return status from the DispatchPnP routine. Do not complete the IRP.
    • In a bus driver, complete the IRP using IoCompleteRequest with IO_NO_INCREMENT and return from the DispatchPnP routine.

A driver cannot start any IRPs that access the device while the device is stopped. A driver must fail such IRPs.


Handling an IRP_MN_CANCEL_STOP_DEVICE Request (Windows98/Me)

Previous Next

Handling an IRP_MN_CANCEL_STOP_DEVICE Request (Windows 98/Me)

An IRP_MN_CANCEL_STOP_DEVICE request must be handled first by the parent bus driver for a device and then by each next higher driver in the device stack. A driver handles stop IRPs in its DispatchPnP routine.

In response to an IRP_MN_CANCEL_STOP_DEVICE request, a driver must return the device to its started state and resume normal operation. Drivers must succeed a cancel-stop IRP.

A driver handles an IRP_MN_CANCEL_STOP_DEVICE request with a procedure such as the following:

  1. Postpone restarting the device until lower drivers have completed their restart operations. (See Postponing PnP IRP Processing Until Lower Drivers Finish.)
  2. After lower drivers finish, return the device to its started state.

    Exact operations depend on the device and the driver.

  3. Restart I/O.
  4. Complete the IRP with IoCompleteRequest.
    • In a function or filter driver:

      The driver's IoCompletion routine returned STATUS_MORE_PROCESSING_REQUIRED, as described in Postponing PnP IRP Processing Until Lower Drivers Finish, so the driver's DispatchPnP routine must call IoCompleteRequest to resume I/O completion processing.

      The driver sets Irp->IoStatus.Status to STATUS_SUCCESS, calls IoCompleteRequest with a priority boost of IO_NO_INCREMENT, and returns STATUS_SUCCESS from its DispatchPnP routine.

      Drivers must not fail this operation. If a driver fails the restart IRP, the device is in an inconsistent state and will not operate properly.

    • In a parent bus driver:

      The driver sets Irp->IoStatus.Status to STATUS_SUCCESS and calls IoCompleteRequest specifying a priority boost of IO_NO_INCREMENT. The bus driver returns STATUS_SUCCESS from its DispatchPnP routine.

      A bus driver must not fail this operation. If a driver fails the restart IRP, the device is in an inconsistent state and will not operate properly.

A driver might receive a spurious cancel-stop request when the device is started and active. This can occur, for example, if the driver (or a driver higher in the device stack) failed an IRP_MN_QUERY_STOP_DEVICE request. When a device is started and active, drivers can safely succeed spurious cancel-stop requests for the device.


Removing a Device

The PnP Manager directs drivers to remove their device objects for a device when the device has been, or is being, physically removed from the machine. The PnP Manager also sends a remove IRP when a user requests to update the drivers for a device and, on Windows 2000 and later, when the device is disabled or fails to start.

The following sections describe when the PnP Manager issues remove IRPs and what drivers must do to respond to those IRPs. This section covers the following topics:

Understanding When Remove IRPs are Issued

Handling an IRP_MN_QUERY_REMOVE_DEVICE Request

Handling an IRP_MN_REMOVE_DEVICE Request

Handling an IRP_MN_CANCEL_REMOVE_DEVICE Request

Handling an IRP_MN_SURPRISE_REMOVAL Request


Understanding When Remove IRPs Are Issued

The following figure shows the typical sequence of IRPs involved in removing the drivers for a device.

Typical Remove IRP Transitions

The following notes correspond to the circled numbers in the previous figure:

  1. Query remove

    The PnP Manager issues an IRP_MN_QUERY_REMOVE_DEVICE to ask whether a device can be removed without disrupting the machine. It also sends this IRP when a user requests to update driver(s) for the device and (on Windows 2000 and later) when the Device Manager disables the device. (On Windows 98/Me, the PnP Manager sends stop IRPs in this situation; see Stopping a Device for details.)

    If all drivers in the device stack return STATUS_SUCCESS, the drivers have put the device into the remove-pending state. In this state, the drivers must not start any operations that prevent the device from being removed.

    In this "clean" removal case, the PnP Manager sends a query-remove IRP before it sends a remove IRP. See step (5) for a description of "surprise" removal.

    Although it is not shown in the above diagram, a bus driver might receive an IRP_MN_QUERY_REMOVE_DEVICE for a device that is not started. This can happen if a user requests to dynamically remove a device that is physically present on the machine but is disabled.

  2. Remove after successful query

    The PnP Manager issues an IRP_MN_REMOVE_DEVICE to remove the drivers for a device.

    Drivers must succeed this request. The drivers for the device perform any necessary clean-up, detach from the device stack, and delete the FDO and any filter DOs. The parent bus driver retains the PDO until the user physically removes the device from the machine.

    Note that drivers might receive an IRP_MN_STOP_DEVICE prior to a remove IRP, but it is not required. On Windows 2000 and later, IRP_MN_STOP_DEVICE is used only to pause a device for resource rebalancing; it is not a step toward removal. If a user removes the device hardware while the device is stopped, the PnP Manager sends a remove IRP at some point after the stop IRP, but a stop is not a prerequisite for a remove.

  3. Re-enumerate the device

    If the device is re-enumerated after drivers have deleted their device objects, the PnP Manager calls the drivers' AddDevice routines and issues an IRP_MN_START_DEVICE to reinstate the device (See also Device States from the PnP Perspective figure.)

  4. Cancel a query remove

    The PnP Manager issues an IRP_MN_CANCEL_REMOVE_DEVICE to cancel a query-remove request.

    In response to an IRP_MN_CANCEL_REMOVE_DEVICE, the drivers return the device to its started state.

  5. Surprise remove (Windows 2000 and later systems)

    On Windows® 2000 and later systems, if a user unplugs a device from the machine without first going through the Unplug or Eject Hardware applet, the PnP Manager sends an IRP_MN_SURPRISE_REMOVAL IRP.

    This case is called "surprise" removal because the drivers receive no advance warning.

    In response to an IRP_MN_SURPRISE_REMOVAL IRP, the drivers for the device fail any outstanding I/O and release the hardware resources used by the device. The drivers must ensure that no components attempt to access the device because it is no longer present.

    All drivers must handle an IRP_MN_SURPRISE_REMOVAL IRP and must set status to STATUS_SUCCESS.

    An IRP_MN_SURPRISE_REMOVAL cannot be canceled.

  6. Remove after surprise remove (Windows 2000 and later systems)

    When all open handles to the device are closed, the PnP Manager sends an IRP_MN_REMOVE_DEVICE request to the drivers for the device. Each driver detaches from the device stack and deletes its device object.

  7. Surprise remove (Windows 98/Me)

    On Windows® 98/Me, a driver does not receive an IRP_MN_SURPRISE_REMOVAL when a device is removed without warning. The PnP Manager sends only an IRP_MN_REMOVE_DEVICE. WDM drivers must have code to handle both an IRP_MN_SURPRISE_REMOVAL followed by an IRP_MN_REMOVE_DEVICE (the Windows 2000 and later behavior for surprise removal) and an IRP_MN_REMOVE_DEVICE without a prior surprise-remove IRP (the Windows 98/Me behavior).

  8. Remove after a failed start (Windows 2000 and later)

    If one of the drivers for a device fails an IRP_MN_START_DEVICE, the PnP Manager sends an IRP_MN_REMOVE_DEVICE request to the device stack. Such a remove IRP ensures that all drivers for the device are notified that the device was not successfully started. In response to the IRP_MN_REMOVE_DEVICE IRP, the drivers for the device undo their start operations (if they succeeded the start IRP) and undo their AddDevice operations. The PnP Manager marks such a device as "failed start."

    This behavior applies to Windows 2000 and later platforms only. On Windows 98/Me, the PnP Manager sends an IRP_MN_STOP_DEVICE in response to a failed start.

A driver for a PnP device can receive an IRP_MN_SURPRISE_REMOVAL in more situations than those shown in the figure illustrating typical remove IRP transitions. For example, a user could insert a PC Card into the machine and then remove it before the device is started. In that case, the PnP Manager issues a surprise-remove IRP after the drivers' AddDevice routines are called but before issuing the IRP_MN_START_DEVICE request. A driver for a PnP device must be prepared to handle remove IRPs at any time after the driver's AddDevice routine is called.


Handling an IRP_MN_QUERY_REMOVE_DEVICE Request

The PnP Manager sends this IRP to inform drivers that a device is about to be removed from the machine and to ask whether the device can be removed without disrupting the machine. It also sends this IRP when a user requests to update drivers for the device.

The PnP Manager sends this IRP at IRQL PASSIVE_LEVEL in the context of a system thread.

It does the following before sending this IRP to the drivers for a device:

  • Notifies all user-mode applications that registered for notification on the device (or a related device).

    This includes applications that registered for notification on the device, on one of the device's descendants (child device, child of child, and so forth.), or on one of the device's removal relations. An application registers for such notification by calling RegisterDeviceNotifcation.

    In response to this notification, an application either prepares for device removal (closes handles to the device) or fails the query.

  • Notifies all kernel-mode drivers that registered for notification on the device (or a related device).

    This includes drivers that registered for notification on the device, on one of the device's descendants, or on one of the device's removal relations. A driver registers for this notification by calling IoRegisterPlugPlayNotification with an event category of EventCategoryTargetDeviceChange.

    In response to this notification, a driver either prepares for device removal (closes handles to the device) or fails the query.

  • Sends IRP_MN_QUERY_REMOVE_DEVICE IRPs to the drivers for the device's descendants.
  • (Windows 2000 and later systems) If a file system is mounted on the device, the PnP Manager sends a query-remove request to the file system and any file system filters. If there are open handles to the device, the file system typically fails the query-remove request. If not, the file system typically locks the volume to prevent future creates from succeeding. If a mounted file system does not support a query-remove request, the PnP Manager fails the query-remove request for the device.

If all of the above steps succeed, the PnP Manager sends the IRP_MN_QUERY_REMOVE_DEVICE to the drivers for the device.

An IRP_MN_QUERY_REMOVE_DEVICE request is handled first by the top driver in the device stack and then by each next lower driver. A driver handles remove IRPs in its DispatchPnP routine.

In response to an IRP_MN_QUERY_REMOVE_DEVICE, a driver must do the following:

  1. Determine whether the device can be removed from the machine without disrupting operation.

    A driver must fail a query-remove IRP if any of the following are true:

    • If removing the device could result in losing data.
    • If a component has an open handle to the device. (This is an issue on Windows 98/Me only. Windows 2000 and later systems track open handles and fail the query if there are open handles after the IRP_MN_QUERY_REMOVE_DEVICE completes.)
    • If a driver has been notified (through an IRP_MN_DEVICE_USAGE_NOTIFICATION IRP) that the device is in the path for a paging, crash dump, or hibernation file.
    • If the driver has an outstanding interface reference against the device. That is, the driver provided an interface in response to an IRP_MN_QUERY_INTERFACE request and the interface has not been de-referenced.
  2. If the device cannot be removed, fail the query-remove IRP.

    Set Irp->IoStatus.Status to an appropriate error status (typically STATUS_UNSUCCESSFUL), call IoCompleteRequest with IO_NO_INCREMENT, and return from the driver's DispatchPnP routine. Do not pass the IRP to the next lower driver.

  3. If the driver previously sent an IRP_MN_WAIT_WAKE request to enable the device for wake-up, cancel the wait-wake IRP.
  4. Record the previous PnP state of the device.

    A driver should record the PnP state that the device was in when the driver received the IRP_MN_QUERY_REMOVE_DEVICE request because the driver must return the device to that state if the query is canceled (IRP_MN_CANCEL_REMOVE_DEVICE). The previous state is typically "started", but it might not be if, for example, the device was disabled.

  5. Finish the IRP:

    In a function or filter driver:

    • Set Irp->IoStatus.Status to STATUS_SUCCESS.
    • Set up the next stack location with IoSkipCurrentIrpStackLocation and pass the IRP to the next lower driver with IoCallDriver.
    • Propagate the status from IoCallDriver as the return status from the DispatchPnP routine.
    • Do not complete the IRP.

    In a bus driver:

    • Set Irp->IoStatus.Status to STATUS_SUCCESS.
    • Complete the IRP (IoCompleteRequest) with IO_NO_INCREMENT.
    • Return from the DispatchPnP routine.

If any driver in the device stack fails an IRP_MN_QUERY_REMOVE_DEVICE, the PnP Manager sends an IRP_MN_CANCEL_REMOVE_DEVICE to the device stack. This prevents drivers from requiring an IoCompletion routine for a query-remove IRP to detect whether a lower driver failed the IRP.

Once a driver succeeds an IRP_MN_QUERY_REMOVE_DEVICE and it considers the device to be in the remove-pending state, the driver must fail any subsequent create requests for the device. The driver processes all other IRPs as usual, until the driver receives an IRP_MN_CANCEL_REMOVE_DEVICE or an IRP_MN_REMOVE_DEVICE.


Handling an IRP_MN_REMOVE_DEVICE Request

The PnP Manager uses this IRP to direct drivers to remove a device's software representation (device objects, and so forth). The PnP Manager sends this IRP when a device has been removed in an orderly fashion (for example, initiated by a user in the Unplug or Eject Hardware applet), by surprise (a user pulls the device from its slot without prior warning), or when the user requests to update drivers.

On Windows 2000 and later systems, the PnP Manager sends this IRP when the Device Manager disables the device. On Windows 98/Me, the Pnp Manager sends stop IRPs instead. See Stopping a Device for details.

The PnP Manager does the following before sending this IRP to the drivers for a device:

  • Sends IRP_MN_REMOVE_DEVICE requests to the device's children, if any.
  • Notifies any user-mode components and kernel-mode drivers that registered for notification that the device is being removed. The PnP Manager calls any user-mode components that registered for target device notification on a handle to the device and calls any kernel-mode drivers that registered for EventCategoryTargetDeviceChange.
  • (On Windows 2000 and later systems) If a file system is mounted on the device, the PnP Manager sends a remove request to the file system and any file system filters. In response, a file system typically dismounts the volume.

The top driver in a device stack handles a remove IRP and passes it to the next lower driver. The parent bus driver for a device is the last driver to perform its remove-device operations. A driver handles remove IRPs in its DispatchPnP routine.

Before a driver returns success for an IRP_MN_REMOVE_DEVICE request, it must ensure that all resources for the device have been released. This IRP could be the last call before the driver is unloaded.

Removing one device can create the need to remove a series of other devices. The PnP Manager coordinates the removal of the additional device objects from the top level down to the root-device level.

This section describes:

Removing a Device in a Function Driver

Removing a Device in a Filter Driver

Removing a Device in a Bus Driver


Removing a Device in a Function Driver

When removing a device, a function driver must undo any operations it performed to add and start the device. This discussion includes function drivers for peripheral devices and function drivers for bus devices.

A function driver removes a device using a procedure such as the following in its DispatchPnP routine:

  1. Is this a function driver for a bus device?

    If so, possibly delete any outstanding child PDOs for devices on the bus.

    If the bus driver handled a previous IRP_MN_SURPRISE_REMOVAL request for the child device, but the driver has not yet received the subsequent IRP_MN_REMOVE_DEVICE request, the bus driver leaves the child PDO intact. At some later time, when all handles to the child device are closed, the PnP Manager will send the remove IRP for the child device and the bus driver deletes the child PDO at that time.

    If the bus driver handled a previous IRP_MN_REMOVE_DEVICE request for the device, and there has been no subsequent IRP_MN_SURPRISE_REMOVAL request, then the bus driver deletes the child PDO. In this case, the PnP Manager ensures that any function and filter drivers have been removed from the child device (FDO and filter DOs have been deleted) before it sends a remove IRP to the parent bus device. The child PDO might still be present, so the bus driver must delete the child PDO before it removes the bus device.

  2. Has the driver already handled a previous IRP_MN_SURPRISE_REMOVAL request for this FDO?

    If so, perform any remaining clean-up and skip to step (7), IoCallDriver.

    A driver typically maintains a flag in the device extension that indicates whether the driver has handled an IRP_MN_SURPRISE_REMOVAL request for the device.

  3. If the driver previously enabled the device for wake-up, cancel the IRP_MN_WAIT_WAKE request.
  4. Ensure that the device is inactive.

    If the device is not already inactive in response to a prior IRP_MN_QUERY_REMOVE_DEVICE, the driver must mark the device as not accepting new requests and must complete any requests queued in this driver. The driver must fail any outstanding requests that require access to the device.

    A driver can use the Io..RemoveLock.. routines to count outstanding I/O and to set an event indicating that remove processing can continue.

  5. Perform any power-down operations.

    Each driver for the device performs its power-down operations, if any, when it receives the IRP_MN_REMOVE_DEVICE request. The power policy owner for the device, typically the function driver, does not send a separate IRP_MN_SET_POWER request to set the device power state to D3. The parent bus driver typically powers down the slot and notifies the Power Manager with PoSetPowerState when the bus driver gets the remove IRP. For additional information, see Power Management.

  6. Disable any device interfaces by calling IoSetDeviceInterfaceState.
  7. Free any hardware resources for the device in use by the driver.

    The exact operations depend on the device and the driver but can include disconnecting an interrupt with IoDisconnectInterrupt, freeing physical address ranges with MmUnmapIoSpace, and freeing I/O ports.

  8. Pass the IRP_MN_REMOVE_DEVICE request down to the next driver.

    Set up the IRP stack location for the next lower driver with IoSkipCurrentIrpStackLocation and pass the IRP to the next driver with IoCallDriver.

    A driver is not required to wait for underlying drivers to finish their remove operations before continuing with its remove activities.

  9. Remove the device object from the device stack with IoDetachDevice.

    Specify a pointer to the next lower device object as the TargetDevice parameter. The driver receives such a pointer from the call to IoAttachDeviceToDeviceStack in the driver's AddDevice routine.

  10. Clean up any device-specific allocations, memory, events, and so forth.
  11. Free the FDO with IoDeleteDevice.
  12. Return from the DispatchPnP routine, propagating the return status from IoCallDriver.

A function driver does not specify an IoCompletion routine for a remove IRP, nor does it complete the IRP. Remove IRPs are completed by the parent bus driver.


Removing a Device in a Filter Driver

When removing a device, a filter driver must undo any operations it performed to add and start the device. A filter driver follows essentially the same procedure as a function driver when removing a device.


Removing a Device in a Bus Driver

When removing a child device (child PDO), the parent bus driver must undo any operations it performed to add and start the device.

A bus driver removes a child device with a procedure such as the following in its DispatchPnP routine:

  1. Has the driver handled a previous IRP_MN_SURPRISE_REMOVAL request for this PDO?

    If so, perform any remaining clean-up and skip to step (4).

    A driver typically maintains a flag in the device extension that indicates whether the driver has handled an IRP_MN_SURPRISE_REMOVAL request for the device.

  2. Complete any requests queued in the driver.
  3. Remove power from the device, if the bus driver is capable of doing so, and notify the Power Manager by calling PoSetPowerState.

    The bus driver powers down the child device, if possible, and notifies the Power Manager of the device's change in power state. The bus driver does this in response to the IRP_MN_REMOVE_DEVICE request; the device's power policy owner does not send an IRP_MN_SET_POWER request when the device is being removed. For additional information, see Power Management.

  4. If the bus driver reported this device in its most recent response to an IRP_MN_QUERY_DEVICE_RELATIONS request for BusRelations, the device is still physically present on the machine. In this case, the bus driver:
    • Retains the PDO for the device until the device has been physically removed.
    • Sets Irp->IoStatus.Status to STATUS_SUCCESS.
    • Completes the IRP with IoCompleteRequest.
    • Returns from the DispatchPnP routine

    The bus driver must continue to report this device in subsequent enumerations (IRP_MN_QUERY_DEVICE_RELATIONS for BusRelations) until the device is physically removed. The PnP Manager keeps track of whether an enumerated device has been added and started.

  5. If the device was not included in the bus driver's most recent response to an IRP_MN_QUERY_DEVICE_RELATIONS request for BusRelations, the bus driver considers the device to be physically removed from the machine. In this case, the bus driver does the following:
    • Cleans up device-specific allocations, memory, events, and so forth
    • Sets Irp->IoStatus.Status to STATUS_SUCCESS
    • Completes the IRP with IoCompleteRequest
    • Frees the PDO with IoDeleteDevice

      The bus driver must delete the PDO if the driver omitted the device from its most recent BusRelations list. If a user plugs the device into the machine again, the bus driver must create a new PDO in response to the next BusRelations query. If a bus driver reuses the same PDO for a new instance of a device, the machine will not operate properly.

    • Returns from the DispatchPnP routine.

If the device is still present when the PnP Manager sends the IRP_MN_REMOVE_DEVICE request, the bus driver retains the PDO. If, at some later time, the device is physically removed from the bus, the PnP Manager sends another IRP_MN_REMOVE_DEVICE. Upon receipt of the subsequent remove IRP, the bus driver deletes the PDO for the device.

A bus driver must be able to handle an IRP_MN_REMOVE_DEVICE for a device it has already removed and whose PDO is marked for deletion. In response to such an IRP, the bus driver can succeed the IRP or return STATUS_NO_SUCH_DEVICE. The PDO for the device has not yet been deleted in this case, despite the bus driver's previous call to IoDeleteDevice, because some component still has a reference to the object. Therefore, the bus driver can access the PDO while handling the second remove IRP. The bus driver must not call IoDeleteDevice a second time for the PDO; the I/O system deletes the PDO when its reference count reaches zero.

A bus driver does not remove its data structures for a child device until it receives an IRP_MN_REMOVE_DEVICE request for the device. A bus driver might detect that a device has been removed and call IoInvalidateDeviceRelations, but it must not delete the device's PDO until the PnP Manager sends an IRP_MN_REMOVE_DEVICE request.


Handling an IRP_MN_CANCEL_REMOVE_DEVICE Request

In response to an IRP_MN_CANCEL_REMOVE_DEVICE request, the drivers for a device must return the device to the state it was in prior to receiving the IRP_MN_QUERY_REMOVE_DEVICE request. Typically, drivers return the device to the started state.

In addition to sending an IRP_MN_CANCEL_REMOVE_DEVICE to a device, the PnP Manager sends the IRP to the device's removal relations, if any. The PnP Manager also sends a cancel-remove IRP to the device's children.

The PnP Manager calls any EventCategoryTargetDeviceChange notification callbacks after the IRP_MN_CANCEL_REMOVE_DEVICE request completes. Such callbacks were registered on the device by calling IoRegisterPlugPlayNotification. The PnP Manager also calls any user-mode components that registered for such notification by calling RegisterDeviceNotification.

An IRP_MN_CANCEL_REMOVE_DEVICE request must be handled first by the parent bus driver for a device and then by each higher driver in the device stack. A driver handles remove IRPs in its DispatchPnP routine.

A driver handles an IRP_MN_CANCEL_REMOVE_DEVICE request with a procedure such as the following in its DispatchPnP routine:

  1. In a function or filter driver, postpone restarting the device until lower drivers have completed their restart operations.

    A function or filter driver sets an IoCompletion routine, passes the IRP_MN_CANCEL_REMOVE_DEVICE down the device stack, and postpones its restart operations until all lower drivers have finished with the IRP. (See Postponing PnP IRP Processing Until Lower Drivers Finish.)

  2. After lower drivers finish, return the device to its previous PnP state.

    The drivers return the device to the state it was in prior to receiving the IRP_MN_QUERY_REMOVE_DEVICE request. Typically, drivers return the device to the started state. Exact operations depend on the device and the driver.

    If the device was previously enabled for wake-up, the device power policy owner (typically the function driver) should send an IRP_MN_WAIT_WAKE request to re-enable wake-up. See Power Management for details.

  3. Set Irp->IoStatus.Status to STATUS_SUCCESS and complete the IRP with IoCompleteRequest.

    As with any PnP IRP, a bus driver completes the IRP.

    A function or filter driver also completes the IRP, in this case because the driver's IoCompletion routine interrupted completion processing by returning STATUS_MORE_PROCESSING_REQUIRED.

    Drivers must succeed this IRP. If any driver fails this IRP, the device is left in an inconsistent state.

A driver might receive a spurious cancel-remove request when the device is started and active. This can occur, for example, if the driver (or a driver higher in the device stack) failed an IRP_MN_QUERY_REMOVE_DEVICE request. When a device is started and active, a driver simply succeeds a spurious cancel-remove request for the device.


Using PnP Notification

In a PnP environment, drivers and applications need to react to changes in the configuration of devices on the machine. For example, an application needs to know when a device of interest has been added to the machine and a driver needs to know when a change occurs on a particular device.

The PnP Manager provides a mechanism for drivers and applications to be notified when certain PnP events occur. This section describes how to use PnP notification in kernel-mode code. Writers of user-mode applications should see the Platform SDK documentation for information on the RegisterDeviceNotification function and related functions.


PnP Notification Overview

The PnP Manager provides a mechanism for drivers and applications to be notified when certain events occur on a specific device or on the system in general. A driver can register for notification of the following categories of events:

  • EventCategoryDeviceInterfaceChange

    When a driver registers for this category of events on a device interface, the PnP Manager notifies the driver of the following events:

    GUID_DEVICE_INTERFACE_ARRIVAL
    Indicates that a device interface of the specified class has been enabled. For example, a user added a new disk to the machine and the volume manager enabled a new volume (a device interface of the class "volume").
    GUID_DEVICE_INTERFACE_REMOVAL
    Indicates that a device interface of the specified class has been disabled.

    See IoRegisterDeviceInterface and related routines for more information on device interfaces.

  • EventCategoryTargetDeviceChange

    When a driver registers for this category of events on a device, the PnP Manager notifies the driver when the following events occur on the device:

    GUID_TARGET_DEVICE_QUERY_REMOVE
    Indicates that the PnP Manager is about to remove the drivers for the device. Several actions can cause this event, including: a user has requested to remove the specified device from the machine or a user has issued an update-driver request for the device. This notification requests the drivers for the device to either approve or veto the impending remove operation.
    GUID_TARGET_DEVICE_REMOVE_COMPLETE
    Indicates that the specified device has been removed from the machine or that a user is changing the driver(s) for the device.
    GUID_TARGET_DEVICE_REMOVE_CANCELLED
    Indicates that an impending remove operation on the specified device has been cancelled.
    GUID_Xxx (custom events)
    Indicates that a custom event has occurred on the specified device.

    A driver writer can define a custom event for a device. When the driver (or another related component) notifies the PnP Manager that the custom event has occurred, the PnP Manager notifies any components that registered for target device change notifications on the device.

    Unlike registering for device interface changes, which can be considered a "passive" interest in the interface, registering for target device changes indicates an "active" interest in a device.

  • EventCategoryHardwareProfileChange

    This category includes the following events:

    GUID_HWPROFILE_QUERY_CHANGE
    Indicates that a user has requested to change the hardware profile of the machine. The PnP Manager uses this notification to ask registered components whether it can change the hardware profile without disrupting system operation. Registered components typically succeed these query requests.
    GUID_HWPROFILE_CHANGE_COMPLETE
    Indicates that the hardware profile of the machine has changed. If a driver maintains profile-specific settings, such a driver should refresh those settings after a hardware profile change.
    GUID_HWPROFILE_CHANGE_CANCELLED
    Indicates that an impending hardware profile change has been cancelled.

PnP notification works as follows for kernel-mode components:

  1. A driver registers for notification on a category of events by calling IoRegisterPlugPlayNotification.

    A PnP notification callback routine remains registered until the driver explicitly removes the registration.

  2. The PnP Manager calls the driver's callback routine when an event in the registered category occurs.
  3. The driver removes the callback registration by calling IoUnregisterPlugPlayNotification.

Drivers must not generate a synchronous event or wait on an asynchronous event during the processing of a close.

For further information on PnP notification, see the following sections:

Guidelines for Writing PnP Notification Callback Routines

Using PnP Device Interface Change Notification

Using PnP Target Device Change Notification

Using PnP Hardware Profile Change Notification

Using PnP Custom Notification


Guidelines for Writing PnP Notification Callback Routines

The PnP Manager calls notification callback routines at IRQL PASSIVE_LEVEL.

To ensure smooth operation of the PnP subsystem, a PnP notification callback routine must follow these guidelines:

  1. A notification callback routine must not block.
  2. A notification callback routine must not call, or cause a call to, synchronous routines that generate PnP events or any routine that blocks waiting for device installation or removal.

    Calling such routines during a notifcation callback can cause a system deadlock.

    For example, a driver must not call IoReportTargetDeviceChange in a notification callback routine. Call IoReportTargetDeviceChangeAsynchronous instead.

  3. A notification callback routine should return success for any events it does not explicitly fail.

    When a driver registers for notification on an event category, the PnP Manager notifies the driver of all events in that category, present and future. If a driver returns an error status for events it does not handle, the driver risks failing a new query event by mistake.

    A driver correctly returns an error status when, for example, the driver fails a query notification to veto the event being proposed.

  4. A notification callback routine should be paged code.


Using PnP Device Interface Change Notification

A driver registers for EventCategoryDeviceInterfaceChange notification so the driver can be notified when device interfaces of a particular class arrive (are enabled) or are removed (disabled) on the machine. For example, a composite battery driver might register for notification of device interfaces of class battery so it can provide information to the operating system about total available battery power.

The following subsections discuss how to register for device interface change notification and how to handle device interface change events in a PnP notification callback routine:

Registering for Device Interface Change Notification

Handling Device Interface Change Events

See IoRegisterDeviceInterface and related routines for information on device interfaces.


Registering for Device Interface Change Notification

A driver registers for notification of device interface arrival and removal events by calling IoRegisterPlugPlayNotification.

The following information applies to calling this routine for device interface change notification:

  • Specify an EventCategory of EventCategoryDeviceInterfaceChange.
  • EventCategoryData must point to the GUID for a device interface class.

    The GUID for a interface class is typically defined in a header file with the structures, constants, and so forth, for the interface.

  • Specify an EventCategoryFlags of PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES.

    This flag directs the PnP Manager to register the CallbackRoutine for future device interface arrivals and departures of the specified class and to call the CallbackRoutine immediately for any relevant device interfaces that are already active.

    A driver can call IoGetDeviceInterfaces to get a list of existing interfaces of a specific class and then register its callback routine without this flag, but using the flag is easier and avoids a potential timing issue.

  • Specify a driver-defined Context, if appropriate, that the PnP Manager will pass to the callback routine.

A driver that opens a handle to a device in response to a device interface arrival notification should register for EventCategoryTargetDeviceChange events on the device. (See Using PnP Target Device Change Notification.)

A driver cancels notification registration by calling IoUnregisterPlugPlayNotification with the NotificationEntry returned by IoRegisterPlugPlayNotification.


Handling Device Interface Change Events

When driver or user-mode component enables or disables a device interface, the PnP Manager calls any notification callback routines that registered for EventCategoryDeviceInterfaceChange on the device interface class. The PnP Manager specifies a NotificationStructure.Event of GUID_DEVICE_INTERFACE_ARRIVAL or GUID_DEVICE_INTERFACE_REMOVAL.

When handling a GUID_DEVICE_INTERFACE_ARRIVAL event, a notification callback routine should:

  • Perform driver-defined tasks for handling the new interface.

    A callback routine might, for example, queue a worker routine to open the device. A callback routine must not open the device directly. If the provider of the interface causes blocking PnP events, the notification callback routine can cause a deadlock if it tries to open the device in the callback thread.

    A callback routine might enable an interface of its own in response to the availability of the new interface.

When handling a GUID_DEVICE_INTERFACE_REMOVAL event, a notification callback routine should:

  • Undo whatever operations it performed when the interface was enabled.


Using PnP Target Device Change Notification

A driver registers for EventCategoryTargetDeviceChange notification on a device so the driver can be notified when the device is about to be removed. For example, if a driver opens a handle to a device, the driver should register for EventCategoryTargetDeviceChange notification on the device so the driver can close its handle when the PnP Manager needs to remove the device.

Drivers can also use EventCategoryTargetDeviceChange notification for custom notification. (See Using PnP Custom Notification.)

The following subsections discuss how to register for target device change notification and how to handle target device change events in a PnP notification callback routine:

Registering for Target Device Change Notification

Handling a GUID_TARGET_DEVICE_QUERY_REMOVE Event

Handling a GUID_TARGET_DEVICE_REMOVE_COMPLETE Event

Handling a GUID_TARGET_DEVICE_REMOVE_CANCELLED Event


Registering for Target Device Change Notification

A driver registers for notification of PnP target device change events by calling IoRegisterPlugPlayNotification.

The following information applies to calling this routine for target device change notification:

  • Specify an EventCategory of EventCategoryTargetDeviceChange.
  • EventCategoryData must point to the file object for the device on which notification is requested.

    If the driver's callback routine requires access to the file object, the driver should take out a reference on the file object before calling IoRegisterPlugPlayNotification.

    If the driver's callback routine does not require access to the file object, the driver does not need to reference the object.

    After the file object is closed, the driver continues to receive notifications for the device until the driver removes its notification registration. This design allows the driver to receive notification of GUID_TARGET_DEVICE_REMOVE_CANCELLED events, for example.

  • Specify a driver-defined Context that the PnP Manager will pass to the callback routine.

    A driver might use the Context parameter to maintain information about the current state of the file object (for example, has it been closed/deleted).

    A driver might also use the Context to store the path it used to originally open the device. A driver can use this path to reopen the device after a cancelled remove operation. (See Handling a GUID_TARGET_DEVICE_REMOVE_CANCELLED_Event for more information.)

A driver removes a notification registration by calling IoUnregisterPlugPlayNotification with the NotificationEntry returned by IoRegisterPlugPlayNotification. If the driver took out a reference on the file object when it registered for notification and that reference is still outstanding, the driver must release the reference after it removes the registration.


Handling a GUID_TARGET_DEVICE_QUERY_REMOVE Event

Before the PnP Manager sends an IRP_MN_QUERY_REMOVE_DEVICE IRP to the drivers for a device, it calls any notification callback routines that registered for EventCategoryTargetDeviceChange on the device. The PnP Manager specifies a NotificationStructure.Event of GUID_TARGET_DEVICE_QUERY_REMOVE.

In response to such a notification, the callback routine determines whether the device can be removed without disrupting the system.

If the device should not be removed, the callback routine returns STATUS_UNSUCCESSFUL. In response to this status, the PnP Manager aborts query-remove processing and the device will not be removed.

If the device can be removed, the callback routine should perform any appropriate operations to prepare for device removal, such as closing any handles open on the device (if possible). If handles remain open on the device, the PnP Manager cannot remove the device, and the PnP Manager aborts query-remove processing.

When successfully handling a GUID_TARGET_DEVICE_QUERY_REMOVE event, a notification callback routine should:

  • Close any open handles to the device.
  • If the driver has an outstanding reference on the file object, dereference the file object.
  • Remain registered for future EventCategoryTargetDeviceChange notifications. This is important because the impending remove operation might be cancelled.

Closing a handle to a device does not cancel a driver's registration for PnP target device change notification. The PnP Manager can still call the driver's notification callback routine, but in such calls the file object in the NotificationStructure is not valid.


Handling a GUID_TARGET_DEVICE_REMOVE_COMPLETE Event

Before the PnP Manager sends an IRP_MN_REMOVE_DEVICE IRP to the drivers for a device, the PnP Manager calls any kernel-mode notification callback routines that registered for EventCategoryTargetDeviceChange on the device. The PnP Manager specifies a NotificationStructure.Event of GUID_TARGET_DEVICE_REMOVE_COMPLETE.

When handling a GUID_TARGET_DEVICE_REMOVE_COMPLETE event, a notification callback routine should:

  • Remove notification registration on the device.

    The device has been removed, so the driver calls IoUnregisterPlugPlayNotification to remove the notification registration.

    The device may still be physically present on the machine, but all device objects have been deleted and the device is not available for use.

  • Perform surprise-remove processing if the driver did not receive a previous query-remove notification.

    If a device is surprise-removed, the PnP Manager sends registered drivers a remove-complete notification without a prior query-remove notification. In this case a driver has to perform any necessary cleanup, such as closing any handles to the device and removing any outstanding references to the file object.


Handling a GUID_TARGET_DEVICE_REMOVE_CANCELLED Event

If an IRP_MN_QUERY_REMOVE_DEVICE request fails, the PnP Manager sends an IRP_MN_CANCEL_REMOVE_DEVICE IRP to the drivers for the device. After the cancel-remove IRP completes successfully, the PnP Manager calls any notification callback routines that registered for EventCategoryTargetDeviceChange on the device. The PnP Manager specifies a NotificationStructure.Event of GUID_TARGET_DEVICE_REMOVE_CANCELLED.

When handling a GUID_TARGET_DEVICE_REMOVE_CANCELLED event, a notification callback routine should:

  • Reregister for target device notification.

    Because the driver closed the previous registration handle in response to the query-remove notification, the driver must open a new handle. The driver must:

    1. Remove the old registration with IoUnregisterPlugPlayNotification.
    2. Open a new handle to the device.
    3. Reregister for notification on the new handle with IoRegisterPlugPlayNotification.


Using PnP Hardware Profile Change Notification

A driver registers for EventCategoryHardwareProfileChange notification so the driver can be notified when the machine transitions from one hardware profile to another. For example, a driver can use this mechanism to be notified when a laptop is docked or undocked.

The following subsections discuss how to register for hardware profile change notification and how to handle hardware profile change events in a PnP notification callback routine:

Registering for Hardware Profile Change Notification

Handling Hardware Profile Change Events


Registering for Hardware Profile Change Notification

A driver registers for notification of hardware profile changes by calling IoRegisterPlugPlayNotification.

The following information applies to calling this routine for hardware profile change notification:

  • Specify an EventCategory of EventCategoryHardwareProfileChange.
  • EventCategoryData must be NULL.
  • Specify a driver-defined Context, if appropriate, that the PnP Manager will pass to the callback routine.

A driver removes notification registration by calling IoUnregisterPlugPlayNotification with the NotificationEntry returned by IoRegisterPlugPlayNotification.


Handling Hardware Profile Change Events

At specific times during a hardware profile change, the PnP Manager calls notification callback routines that registered for EventCategoryHardwareProfileChange:

  • Before there is a change in the machine's hardware profile, the PnP Manager calls registered notification callback routines and specifies a NotificationStructure.Event of GUID_HWPROFILE_QUERY_CHANGE.
  • After the machine's hardware profile change is complete, the PnP Manager calls registered notification callback routines and specifies a NotificationStructure.Event of GUID_HWPROFILE_CHANGE_COMPLETE.
  • If the machine's hardware profile change is canceled, the PnP Manager calls registered notification callback routines and specifies a NotificationStructure.Event of GUID_HWPROFILE_CHANGE_CANCELLED.

For a GUID_HWPROFILE_QUERY_CHANGE event the PnP Manager calls user-mode callback routines and then calls kernel-mode callback routines. In response to a GUID_HWPROFILE_QUERY_CHANGE event, a driver's notification callback routine typically just returns STATUS_SUCCESS.

For a GUID_HWPROFILE_CHANGE_COMPLETE event the PnP Manager calls kernel-mode callback routines and then calls user-mode callback routines. In response to such an event, a driver's callback routine might refresh its hardware-profile-specific settings.

For a GUID_HWPROFILE_CHANGE_CANCELLED event the PnP Manager calls kernel-mode callback routines and then user-mode routines. In response to such an event, a driver's callback routine typically just returns STATUS_SUCCESS. If the driver performed any operations in response to the GUID_HWPROFILE_QUERY_CHANGE event, the driver would undo those operations in response to the cancellation event.


Using PnP Custom Notification

A driver can use the target device change notification mechanism to be notified of custom events on a device.

The programmer that defines the custom event must do the following:

  1. Define a new GUID for the custom event.

    Generate the GUID with uuidgen or guidgen. Publish the GUID in an appropriate header file and documentation.

  2. Write code to trigger the custom event.

    In kernel mode, a driver calls IoReportTargetDeviceChange with the custom GUID and a pointer to the PDO for the device. Custom events can only be triggered from kernel mode.

A driver writer uses custom notification with a procedure like the following:

  1. The driver (or application) registers for notification of the custom event.

    In kernel mode, a driver calls IoRegisterPlugPlayNotification and registers for an EventCategoryTargetDeviceChange on the device.

    In user mode, an application registers using RegisterDeviceNotification. See the Platform SDK for further information.

  2. A kernel-mode component triggers the custom event.
  3. The PnP Manager calls notification routines registered on the device.

    The PnP Manager calls the registered user-mode callback routines and then calls the kernel-mode callback routines.

  4. When user-mode notification is complete, the kernel-mode driver notification callback routine(s) respond to the custom event.

    See Guidelines for Writing PnP Notification Callback Routines for general guidelines for notification callback routines. In addition to those guidelines, a custom notification callback routine must not open a handle to a device from within the callback routine thread.


Power Management

This section describes power management concepts and operating system components, and explains how to support power management in kernel-mode drivers. It covers the following topics:

Introduction to Power Management

Kernel-Mode Power Management Components

Power Management Responsibilities for Drivers

Rules for Handling Power IRPs

Managing Power for Individual Devices

Handling System Power State Requests

Supporting Devices that Have Wake-Up Capabilities


Introduction to Power Management

Power management is a system-wide, integrated approach to the use and conservation of power. Computer systems that include hardware and software support for power management provide for the following:

  • Minimal startup and shutdown delays

    The system can sleep in a low-power state from which it can resume operation without a complete reboot. From the user's perspective, waking the computer from such a state is roughly comparable to switching on a television set.

  • Greater overall power efficiency and battery life

    Power is applied to devices only when they are delivering function to the user. If a device is not in use, it can be powered off and then powered up later, on demand.

  • Quieter operation

    Powering down unused devices reduces noise. In addition, hardware and software can manage electrical current load and thermal load, resulting in computers that are nearly inaudible when sleeping.

The industry-wide OnNow Initiative defines the hardware and software requirements for power management. See Industry Initiatives for Power Management for more information.

In systems that support power management, the computer and its peripheral devices are maintained at the lowest feasible power level to accomplish the tasks at hand. Drivers cooperate with the operating system to manage power for their devices. If all drivers support power management, the operating system can manage power consumption on a system-wide basis, thus conserving power, shutting down and resuming quickly, and waking up when required.

This integrated approach to power management — involving the operating system, system hardware, device drivers, and device hardware — results in the following:

  • More intelligent power management decisions. At each level, the best-informed component directs power usage.
  • Greater reliability. Better power management decisions reduce the chance of ill-timed shutdowns and loss of data.
  • Platform independence. The operating system manages power in a controlled, uniform way across different hardware platforms, allowing maximum conservation of power on various devices.
  • Better device integration. Device drivers that conform to industry-wide specifications ensure maximum conservation regardless of the hardware platform.

Combined, these advantages result in greater power conservation and more efficient usage than has previously been possible.


Industry Initiatives for Power Management

The OnNow Initiative defines hardware and software support required for power management.

The Advanced Configuration and Power Management Interface Specification, part of the OnNow initiative, defines a hardware-level interface that enables operating systems to implement power management in a consistent, platform-independent way.

A Device Class Power Management Reference Specification is available for each common device class, such as audio or communications devices. Each of these specifications defines power management requirements for a class of device. Driver writers should refer to these specifications, available through the Microsoft web site, for device-specific details.


Levels of Support for Power Management

Drivers that support power management must also support Plug and Play (PnP), because some power management operations are closely tied to adding and removing devices, and drivers receive notification of these events by means of PnP IRPs. Additionally, drivers report a device's support for power management in response to PnP queries for device capabilities.

Power management works on two levels, one applying to individual devices and the other to the system as a whole.

The Power Manager, part of the operating system kernel, manages the power level of the entire system. If all drivers in the system support power management, the Power Manager can manage power consumption on a system-wide basis, utilizing not only the fully-on and fully-off states, but also various intermediate system sleep states.

Legacy drivers written before the operating system supported power management continue to work as they did previously. However, systems that include legacy drivers cannot enter any of the intermediate system sleep states; they can operate only in the fully on or fully off states as before.

Device power management applies to individual devices. A driver that supports power management can turn its device on when it is needed and off when it is not in use. Devices that have the hardware capability can enter intermediate device power states. The presence of legacy drivers in the system does not affect the ability of newer drivers to manage power for their devices.


System-Wide Overview of Power Management

Power management requires support from system and device hardware and from system software and drivers. Required hardware support is covered in the industry specifications, as described in the previous section. This document covers the software support — specifically, what drivers must do to conform to operating system requirements and to manage power as appropriate for their devices.

The following figure shows a system-wide overview of power management.

System-Wide Overview of Power Management

Through APIs and the control panel, applications and users have input to power management decisions. Users can set certain power options through the control panel, including device-specific GUID controls that the user interface presents if the corresponding drivers support them. Through WMI, the control panel notifies the Power Manager and drivers of changes in the GUID controls.

The Power Manager administers the system-wide power policy, the rules that govern the system's power usage. (See System Power Policy for details.) Using information from the control panel and APIs, the Power Manager can determine when applications are using, or might need to use, various devices, so that it can adjust the system's power policy appropriately.

The Power Manager also provides an interface for drivers, comprising power management support routines, power management IRPs, and required driver entry points.

When the Power Manager requests a change to the system power state, Drivers respond by putting their devices in an appropriate device power state. In addition, drivers can perform idle detection for their devices and put unused devices in a sleep state. Bus-specific mechanisms report device power capabilities, set and report device status, and change device power. Exactly how and when device power is changed depends on the type of device and the capabilities of the device hardware .

Although ACPI hardware realizes the greatest power savings, the hardware need not be ACPI-compliant for power management in drivers to be effective.


Power States

A power state indicates the level of power consumption — and thus the extent of computing activity — by the system or by a single device. The Power Manager sets the power state of the system as a whole. Device drivers set the power state of their individual devices.

The ACPI specification defines two sets of discrete power states – system power states and device power states. Each power state has a unique name.

System power states are named Sx, where x is a state number between 0 and 5. Device power states are named Dx, where x is a state number between 0 and 3. The state number is inversely related to power consumption: higher numbered states use less power. States S0 and D0 are the highest-powered, most functional, fully on states. States S5 and D3 are the lowest-powered states and have the longest wake-up latency.

These clearly defined power states allow many devices from various manufacturers to work together consistently and predictably. For example, when the Power Manager sets the system in state S3, it can rely upon drivers that support power management not only to put their devices in the corresponding device state but also to return to the working state in a predictable fashion.

For detailed information about power states, see System Power States and Device Power States.


Kernel-Mode Power Management Components

The following sections provide a brief introduction to the role of three kernel-mode components in power management:

ACPI BIOS

ACPI Driver

Power Manager

Driver Role in Power Management


ACPI BIOS

The integrated power management features supported by Microsoft® Windows operating systems are available only on computers that have an Advanced Configuration and Power Interface (ACPI) BIOS.

An ACPI BIOS provides features at the hardware level that make software power management possible. At boot time, the operating system loader checks whether such a BIOS is loaded. If so, ACPI is enabled in the operating system. If such a BIOS is not loaded, ACPI is disabled and the less robust Advanced Power Management (APM) model is used instead.

By default, Windows 2000 and later systems assume that any ACPI BIOS dated January 1, 1999 or later is Windows 2000 ready. However, if such a BIOS is known to exhibit ACPI problems, the loader disables ACPI and instead uses APM.

The Device Manager shows whether an individual computer supports ACPI.


ACPI Driver

Microsoft supplies the ACPI driver as part of the operating system. On systems that have an ACPI BIOS, the HAL causes the ACPI driver to be loaded during system start-up at the base of the device tree, where it acts as the interface between the operating system and the BIOS. The ACPI driver is transparent to other drivers.

The ACPI driver's responsibilities include support for PnP and power management. For example, ACPI tasks on a system might include reprogramming the resources for a COM port or enabling the USB controller for system wake-up.

For each device described in the ACPI name space (part of the ACPI BIOS set up by the hardware vendor), the ACPI driver creates either a filter device object (filter DO) or a physical device object (PDO). If the device is integrated into the system board, the driver creates a filter device object, representing a ACPI bus filter, and attaches it to the device stack immediately above the bus driver (PDO). For other devices described in the ACPI name space but not on the system board, ACPI creates the PDO. ACPI provides power management and PnP features to the device stack by means of these device objects.

The devices for which ACPI creates a device object vary from one system to the next, depending on the machine's BIOS and the configuration of the motherboard. Note that an ACPI bus filter is loaded only for devices described in the ACPI name space and integrated into the system board. Not all motherboard devices have an ACPI bus filter.

All ACPI functionality is transparent to higher-level drivers. Drivers must make no assumptions about the presence or absence of an ACPI filter in any given device stack.


Power Manager

The Power Manager is responsible for managing power usage for the system. It administers the system-wide power policy and tracks the path of power IRPs through the system.

The Power Manager requests power operations by sending IRP_MJ_POWER requests to drivers. A request can specify a new power state or can query whether a change in power state is feasible.

When sleep, hibernation, or shutdown is required, the Power Manager sends an IRP_MJ_POWER request to each leaf node in the device tree requesting the appropriate power action. The Power Manager considers the following in determining whether the system should sleep, hibernate, or shut down:

  • System activity level
  • System battery level
  • Shutdown, hibernate, or sleep requests from applications
  • User actions, such as pressing the power button
  • Control panel settings


Driver Role in Power Management

Drivers support power management in two ways:

  1. Drivers respond to system-wide power requests issued by the Power Manager.
  2. Drivers manage power for their individual devices.

Every driver must have a DispatchPower routine to handle IRP_MJ_POWER requests. The DispatchPower routine must inspect each power IRP and either handle it or pass it down to the next lower driver.

For a device to participate in power management, every driver in the device stack for the device must respond to or pass power IRPs appropriately. Failure of a single driver to act correctly can cause power management to be disabled across the entire system.

One driver for each device manages power policy for its device. That driver can send power IRPs to its own device stack to perform power operations on its device. The power policy manager is responsible for issuing device power IRPs that correspond to system power IRPs.

In addition, drivers might perform certain power tasks, such as powering on a device at start-up or powering off a device at removal, without receiving a power IRP. These are considered implicit power requests.

For more information, see Power Management Responsibilities for Drivers.


Power Management Responsibilities for Drivers

Drivers that support power management are responsible for the following:

  • Reporting device power capabilities during PnP enumeration
  • Setting device object flags for power management
  • Handling power IRPs sent by the Power Manager or a driver
  • Powering up a device as soon as needed after system start-up or idle shutdown
  • Powering down a device at system shutdown time or putting it to sleep when idle
  • Enabling device wake-up, if the device supports wake-up capabilities

Not every driver in every device stack performs all these tasks. Typically, the bus driver reports capabilities, sets flags, and manipulates the physical device, and the device power policy manager (usually the function driver) issues requests to put the device to sleep and to enable wake-up.

With few exceptions, drivers power on and power off their devices, and enable devices for wake-up, in response to power IRPs, that is, IRPs with the major code IRP_MJ_POWER. Power IRPs can be sent by the Power Manager and, in some cases, by a driver.


Reporting Device Power Capabilities

During enumeration, drivers report device-specific information in response to a PnP IRP_MN_QUERY_CAPABILITIES request. Along with other such information, drivers report a device's power management capabilities in the DEVICE_CAPABILITIES structure. Typically, the bus driver fills in this structure.

Higher-level drivers should set an IoCompletion routine for the query-capabilities IRP so that they can make a local copy of the structure and ensure that it contains appropriate values. As a general rule, higher-level drivers should not change these values. However, if a change is necessary, a driver can further restrict device capabilities but cannot add to them. In other words, a driver can make the rules more restrictive but cannot loosen them.

After the IRP is complete and all drivers' completion routines have been run, the structure is cached and a driver cannot change its contents.

The following DEVICE_CAPABILITIES fields pertain to power management:

DeviceD1 and DeviceD2

WakeFromD0, WakeFromD1, WakeFromD2, and WakeFromD3

DeviceState

SystemWake

DeviceWake

D1Latency, D2Latency, and D3Latency


DeviceD1 and DeviceD2

The DeviceD1 and DeviceD2 fields indicate whether the device hardware supports these device states. Each is a single bit, which is set if the device supports the state and is clear if the device does not support the state. The operating system assumes that all devices support the D0 and D3 device power states.


WakeFromD0, WakeFromD1, WakeFromD2, and WakeFromD3

Each of these fields indicates whether the device can awaken in response to an external signal that arrives when the device is in the specified state.

For a device that supports all four device power states (D0, D1, D2, D3) but can awaken only from states D0 and D1, the WakeFromD0 and WakeFromD1 bits are set and the WakeFromD2 and WakeFromD3 bits are clear.


DeviceState

The DeviceState field is an array of DEVICE_POWER_STATE values indexed by SYSTEM_POWER_STATE values ranging from PowerSystemWorking to PowerSystemShutdown. Each element of the array contains the maximum (highest-powered) device state that the device can support for the system state denoted by the index, or PowerDeviceUnspecified if the system state is not supported.

For example, on a system that supports only S0, S4, and S5 system power states, the DeviceState array for a device that supports only the D0 and D3 states contains the following:

DeviceState Element | Value
DeviceState[PowerSystemWorking] | PowerDeviceD0
DeviceState[PowerSystemSleeping1] | PowerDeviceUnspecified
DeviceState[PowerSystemSleeping2] | PowerDeviceUnspecified
DeviceState[PowerSystemSleeping3] | PowerDeviceUnspecified
DeviceState[PowerSystemHibernate] | PowerDeviceD3
DeviceState[PowerSystemShutdown] | PowerDeviceD3

On a system that supports all the system power states, the array contains the following for a device that must be in the D2 state or lower whenever the system goes to any intermediate sleep state, and must be in the D3 state when the system hibernates:

DeviceState Element | Value
DeviceState[PowerSystemWorking] | PowerDeviceD0
DeviceState[PowerSystemSleeping1] | PowerDeviceD2
DeviceState[PowerSystemSleeping2] | PowerDeviceD2
DeviceState[PowerSystemSleeping3] | PowerDeviceD2
DeviceState[PowerSystemHibernate] | PowerDeviceD3
DeviceState[PowerSystemShutdown] | PowerDeviceD3

Note that the entries in the DeviceState array signify the highest-powered state that the device can support for the corresponding system state. In the preceding example, the device could be in state D3 for any system power state, state D2 for system states PowerSystemWorking through PowerSystemSleeping3, and state D1 for system state PowerSystemWorking.

The bus driver or ACPI filter sets these values based on the capabilities of the parent device node.

As a general rule, higher-level drivers should not change these values. However, in the rare circumstances in which such a change is necessary, a driver can specify a lower (less-powered) state than the bus driver or ACPI filter originally returned. For example, assume that DeviceState[PowerSystemSleeping1] maps to PowerDeviceD2, as in the table above. A driver can change this value to PowerDeviceD3, but not to PowerDeviceD1 or PowerDeviceD0.


SystemWake

The SystemWake field contains the lowest (least-powered) system power state from which the device can wake the system, or PowerSystemUndefined if the device cannot wake the system.

The bus driver sets this value at enumeration. A higher-level driver can change the value to a higher-powered state but cannot change it to a lower-powered state. For example, if the bus driver sets SystemWake to S3 but a driver further up the device stack supports wake-up only from S2, the higher-level driver can change the value to S2. If a driver changes SystemWake, it might also have to change DeviceWake, as explained in the next section.

Drivers rarely need to propagate changed values back down the device stack. Because changes make the device capabilities more restrictive, lower drivers do not see requests that they cannot handle. In the previous example, a higher-level driver fails any request to wake the system from a lower-powered state than S2, so lower drivers never see such a request. However, if a lower driver must be aware of any changes, it can send a PnP IRP_MN_QUERY_CAPABILITIES to its own device stack during its processing of an IRP_MN_START_DEVICE.

If both the SystemWake and DeviceWake fields are nonzero (that is, not PowerSystemUnspecified), then the device and its drivers support wake-up on this system.

On non-ACPI hardware, this field always contains zero (PowerSystemUnspecified).


DeviceWake

The DeviceWake field contains the lowest (least-powered) device power state from which the device can signal a wake event, or PowerDeviceUnspecified if the device cannot wake in response to an external signal.

The bus driver sets this value. A higher-level driver can change the value to a higher-powered state. For example, if the bus driver sets DeviceWake to D3 but a driver further up the device stack supports wake-up only from D2, the higher-level driver can change the value to D2.

Note that if a driver changes DeviceWake, it might also have to change SystemWake to avoid conflicts with the system-to-device mappings in the DeviceState array. For example, assume that the bus driver sets the following:

  • DeviceState[PowerSystemSleeping1] = PowerDeviceD1
  • DeviceState[PowerSystemSleeping2] = PowerDeviceD3
  • DeviceWake = PowerDeviceD3
  • SystemWake = PowerSystemSleeping2

If a higher-level driver determines that its device cannot wake the system from D3, but only from D2 or higher, it can change DeviceWake to D2. However, this change causes the mapping from S2 to D3 to be impossible. Remember that the DeviceState array lists the highest-powered state a device can support for a given system state. If the system state in the example is PowerSystemSleeping2, the device state cannot be PowerDeviceD2. To eliminate this problem, the driver must also change SystemWake to PowerSystemSleeping1. The same is true for the WakeFromDx and DeviceDx settings. A driver must ensure that any changes it makes to SystemWake or DeviceWake do not conflict with the WakeFromD x and DeviceD x values. The values of WakeFromD x and DeviceD x reflect hardware characteristics that a driver cannot change.

If both the SystemWake and DeviceWake fields are nonzero (that is, not PowerSystemUnspecified), then the device and its drivers support wake-up on this system.

On non-ACPI hardware, the DeviceWake field contains zero (PowerSystemUnspecified).


D1Latency, D2Latency, and D3Latency

The D1Latency, D2Latency, and D3Latency fields contain the approximate time, in 100-microsecond units, that the device requires to return to the D0 state from each of the sleeping states. A driver should specify a latency time of zero for any device state that it does not support.


Setting Device Object Flags for Power Management

In its AddDevice routine, each driver creates a device object (filter DO, FDO, or PDO) and sets DO_Xxxx flags as required. The following device object flags pertain to power management:

  • DO_POWER_INRUSH
  • DO_POWER_PAGABLE

The device object flags are typically set by the bus driver when it creates the PDO for the device. However, some function drivers might need to alter the values of these flags as part of their AddDevice routines. In general, the values of the flags should be consistent throughout all the device objects in the entire device stack.

On Windows 2000 and later systems, drivers of devices that are in the paging path must not set the DO_POWER_PAGABLE flag. Drivers that do not set the flag must be callable at IRQL DISPATCH_LEVEL.

In general, drivers should not alter the bus driver's value for this flag, and a driver must never set the flag if a lower-level driver has cleared it. When handling transitions involving PnP paging requests (typically in response to an IRP_MJ_PNP with IRP_MN_DEVICE_USAGE_NOTIFICATION request), a storage driver must carefully sequence its setting and clearing of the flag.

Windows 2000 and later drivers that can be paged must set the DO_POWER_PAGABLE flag. The Power Manager calls such drivers at IRQL PASSIVE_LEVEL. All WDM and Windows 98/Me drivers must set DO_POWER_PAGABLE. In addition, Windows 98/Me drivers must not complete power IRPs at IRQL DISPATCH_LEVEL.

Drivers for devices that require an inrush of power at start-up must set the DO_POWER_INRUSH flag in the device object before clearing the DO_DEVICE_INITIALIZING flag. Only one driver in the stack, typically the bus driver (PDO), needs to set DO_POWER_INRUSH. The flag notifies the Power Manager that such devices must be powered up one at a time, in sequence with other such devices. The Power Manager ensures that only one power inrush IRP is active anywhere in the system at any given time.

The Power Manager can send inrush IRPs at IRQL DISPATCH_LEVEL. While handling an inrush IRP, a driver must not access any pageable code or data.

Drivers cannot set both DO_POWER_PAGABLE and DO_POWER_INRUSH.


Handling Power IRPs

Drivers handle power IRPs in a DispatchPower routine. All power management requests have the major IRP code IRP_MJ_POWER and one of the following minor codes:

  • IRP_MN_QUERY_POWER — Queries to determine whether changing power state is feasible
  • IRP_MN_SET_POWER — Requests a change from one power state to another
  • IRP_MN_WAIT_WAKE— Requests that a device be enabled to wake itself or the system
  • IRP_MN_POWER_SEQUENCE — Requests information to optimize power restoration to a particular device

Support for IRP_MN_SET_POWER and IRP_MN_QUERY_POWER is required. All drivers must be prepared to handle these IRPs.

Support for IRP_MN_WAIT_WAKE is required for all drivers in the device stack for any device that can awaken in response to an external signal. A driver sends this IRP to enable the device for wake-up.

Support for IRP_MN_POWER_SEQUENCE is optional. This IRP provides an optimization for devices that take a long time to restore power.

A power IRP can specify a system power operation or a device power operation. Power IRPs for the system and power IRPs for a device take slightly different paths through a device stack, as explained in the following sections.


Power IRPs for the System

A system power IRP specifies major IRP code IRP_MJ_POWER, one of the minor power IRP codes listed below, and the value SystemPowerState in the Power.Type member of the IRP stack. Only the Power Manager can send such an IRP; a driver cannot send a system power IRP.

The Power Manager sends a system power IRP for one of the following reasons:

  • To change the system power state in response to an idle time-out, a change in system activity, a user request, or an expiring battery (IRP_MN_SET_POWER)
  • To query devices to determine whether the system can go to sleep (IRP_MN_QUERY_POWER)
  • To reaffirm the current system power state after a query (IRP_MN_SET_POWER)

The Power Manager sends IRP_MN_QUERY_POWER and IRP_MN_SET_POWER requests on behalf of the system. A driver can fail an IRP_MN_QUERY_POWER request but cannot fail IRP_MN_SET_POWER.

For example, to change the system power state, the Power Manager sends a system power IRP to the top driver in the stack at each device node of the device tree. The following figure shows how drivers within a single device stack handle a system power IRP.

Path of a System Power IRP

As the previous figure shows:

  1. The Power Manager calls the I/O Manager to send a system power IRP to each leaf node in the device tree.
  2. Drivers handle the IRP if possible, set IoCompletion routines if necessary, and forward the IRP down the stack (using PoCallDriver). If a driver must fail the IRP, it does so immediately and completes the IRP. Drivers can fail IRP_MN_QUERY_POWER IRPs but must not fail IRP_MN_SET_POWER IRPs.
  3. When the driver that owns power policy for the device receives the IRP, that driver sets an IoCompletion routine for the system IRP and then forwards the IRP.
  4. Any other drivers in the stack handle the IRP if possible, set IoCompletion routines if necessary, and forward the IRP to the next-lower driver, as in step 2.
  5. Eventually, the bus driver receives and completes the system IRP.
  6. The I/O Manager calls any IoCompletion routines that were set as drivers passed the system IRP down the device stack.
  7. In its IoCompletion routine, the device power policy owner calls PoRequestPowerIrp to send a device power IRP, specifying a device power state that is valid for the system power state in the system IRP. The driver sets a callback routine to be invoked when the device power IRP completes.

    If necessary, the driver consults the DeviceState field in its cached copy of the DEVICE_CAPABILITIES structure (see Reporting Device Power Capabilities) to determine which device power states correspond to the system power state in the IRP.

  8. After the device IRP is complete and any device IRP completion routines have run, the power policy owner's callback routine is invoked. In the callback routine, the driver copies its returned status into the system IRP. It calls PoStartNextPowerIrp and then calls IoCompleteRequest to complete the system IRP.

See Handling System Power State Requests for details.

Because some devices require an inrush of current when they power on, system inrush power IRPs are handled synchronously and serially throughout the system. Only one such IRP can be active at a time. See Using PoCallDriver for details.


Power IRPs for Individual Devices

A device power IRP specifies major IRP code IRP_MJ_POWER, one of the minor power IRP codes listed below, and the value DevicePowerState in the Power.Type member.

IRP_MN_QUERY_POWER

IRP_MN_SET_POWER

IRP_MN_WAIT_WAKE

IRP_MN_POWER_SEQUENCE

All drivers in a device stack receive such IRPs; normally, only the device power policy manager can send these IRPs. However, the Power Manager can send a device power IRP when performing idle detection on behalf of a device, as explained in Using Power Manager Routines for Idle Detection.

A driver sends a device power IRP for any of the following reasons:

  • To query or change the device power state in response to a system power IRP
  • To put the device in a sleep state to conserve power
  • To return the device to the working state after it has been asleep
  • To enable the device to awaken in response to an external signal
  • To get a power sequence value when powering up a device

Path of a Device Power IRP

As the previous figure shows, a device power IRP is sent, forwarded, and completed in the following steps:

  1. The device power policy owner calls PoRequestPowerIrp to allocate a device power IRP, specifying the PDO that is the target of the IRP and a callback routine to be invoked when the IRP is complete.
  2. The Power Manager allocates a device power IRP and sends it to the top driver in the device stack for the target PDO.
  3. The driver performs any required actions; sets an IoCompletion routine; sets the IRP stack location; and then calls PoCallDriver to pass the IRP down to the next lower driver.

    Each driver in the stack does this until the IRP reaches the bus driver. If a driver must fail the IRP, it should do so immediately and call IoCompleteRequest.

  4. The bus driver, which maintains the device PDO, performs the requested action, and then calls IoCompleteRequest to complete the IRP.
  5. The I/O Manager calls IoCompletion routines that were set by drivers as they passed the IRP down the stack. After all the IoCompletion routines have been called, the callback routine is run.

See Managing Power for Individual Devices and Supporting Devices that Have Wake-Up Capabilities for more information on device power IRPs. For details on the power sequence IRP, see IRP_MN_POWER_SEQUENCE.


Powering Up a Device

When a bus driver handles an PnP IRP_MN_START_DEVICE request for one of its child devices, it should power on the device and call PoSetPowerState to report the device state to the Power Manager. Powering on the device is an implicit part of device start-up. The device power policy owner does not send an IRP_MN_SET_POWER request for PowerDeviceD0, so drivers should not expect to receive these IRPs at start-up.

When a device has been powered down to conserve power, its drivers should power it up when an I/O request arrives. In this case, the device power policy owner must send an IRP_MN_SET_POWER to return the device to the working state. When the IRP completes, the drivers for the device stop queuing I/O and begin to process requests off the queue.


Powering Down a Device

Unless a device is enabled for wake-up, its drivers power it off when the system shuts down. Devices must always be powered off upon removal or surprise removal.

When a device is removed, the PnP Manager sends an IRP_MN_REMOVE_DEVICE request to the device stack. In response to this IRP, the drivers for the device should ensure that the device powers down. Powering down the device is an implicit part of removal handling; the device power policy owner is not required to send an IRP_MN_SET_POWER for PowerDeviceD3.

As drivers handle the IRP_MN_REMOVE_DEVICE request, they wait for pending I/O to complete, perform any necessary removal processing, call PoSetPowerState to notify the Power Manager that the device is in state D3, and delete the device objects they created for this device. Typically, the bus driver turns off power to the device.

If a device is unexpectedly removed from a Windows 2000 or later system, the PnP Manager sends an IRP_MN_SURPRISE_REMOVAL request. In response to this IRP, the drivers should power off the device and perform additional removal processing, as described in Handling an IRP_MN_SURPRISE_REMOVAL Request.

At system shutdown, the Power Manager sends an IRP_MN_SET_POWER for a system power state (either S4 or S5). When the device power policy owner receives this IRP, it should send an IRP_MN_SET_POWER for PowerDeviceD3 so that lower drivers can finish their work and power down the device.

A driver can optionally perform idle detection for its device, or can request that the Power Manager perform idle detection, so that the device can be powered down when not in use. See Detecting an Idle Device for details.


Enabling Device Wake-Up

If a device supports wake-up, its power policy owner must be able to enable and disable wake-up for the device. A driver enables wake up by sending an IRP_MJ_POWER request with minor function code IRP_MN_WAIT_WAKE and disables wake-up by canceling a previously sent IRP_MN_WAIT_WAKE. A device can have only one IRP_MN_WAIT_WAKE request pending at a time.

To determine whether its device supports wake-up, the device states from which it can signal wake-up, and the system states from which the device can wake the system, a driver inspects the SystemWake, DeviceWake, and WakeFromD x fields in the DEVICE_CAPABILITIES structure.

See Supporting Devices That Have Wake-Up Capabilities for details on enabling, disabling, and responding to wake-up signals in a driver.


Rules for Handling Power IRPs

Drivers that support power management must conform to certain rules pertaining to the following:

Using PoCallDriver, not IoCallDriver, to pass power IRPs

Calling PoStartNextPowerIrp

Passing power IRPs down to the next lower driver

Queuing I/O requests while a device is sleeping

Handling unsupported or unrecognized power IRPs

The sections that follow describe how drivers should perform these tasks.


Using PoCallDriver

Drivers must use PoCallDriver, not IoCallDriver, to pass power IRPs to the next lower driver. Along with PoRequestPowerIrp and PoStartNextPowerIrp, PoCallDriver ensures that the Power Manager properly synchronizes power IRPs throughout the system.

The system limits the number of active power IRPs as follows:

  • No more than one system power IRP (IRP_MN_SET_POWER, IRP_MN_QUERY_POWER) can be active for each physical device object (PDO) at any given time.
  • No more than one device set-power IRP (IRP_MN_SET_POWER) can be active for each PDO at any given time.
  • No more than one device power IRP that requires an inrush of power can be active anywhere in the system at any given time.

To ensure that two inrush devices do not attempt to power up simultaneously, the Power Manager keeps track of active inrush power IRPs across the whole system and allows only one to be active at a time. An additional inrush IRP cannot start until the active inrush IRP has completed.

Because of these restrictions on inrush IRPs, a device power IRP might block while an inrush IRP for another device completes. Driver writers should be aware of this behavior while debugging.


Calling PoStartNextPowerIrp

When a driver has finished with a system or device set-power or query-power IRP, it calls PoStartNextPowerIrp to notify the Power Manager that it is ready to receive another power IRP. Drivers must call PoStartNextPowerIrp while the IRP stack location points to the current driver and before calling PoCallDriver.

A driver must call this routine once for each IRP_MN_QUERY_POWER or IRP_MN_SET_POWER request that it receives. Drivers do not need to call PoStartNextPowerIrp when handling IRP_MN_WAIT_WAKE or IRP_MN_POWER_SEQUENCE requests.

When a driver calls PoStartNextPowerIrp, the current IRP stack location must point to the current driver. As a general rule, this call is best made from an IoCompletion routine. PoStartNextPowerIrp must be called before IoCompleteRequest, IoSkipCurrentIrpStackLocation, and PoCallDriver. Calling the routines in the other order might cause a system deadlock.

Even if a driver fails the IRP, it must nevertheless call PoStartNextPowerIrp to inform the Power Manager that it is ready to handle another power IRP.

The following sections clarify when each type of driver should call this routine:

  • Calling PoStartNextPowerIrp from a Filter Driver
  • Calling PoStartNextPowerIrp from a Device Power Policy Owner
  • Calling PoStartNextPowerIrp from a Bus Driver


Calling PoStartNextPowerIrp from a Filter Driver

A filter driver calls PoStartNextPowerIrp once for every IRP_MN_QUERY_POWER or IRP_MN_SET_POWER request it receives. When the call occurs depends on the type of request and whether the driver will fail or succeed the request, as the following table shows.

Request | If succeeding the request: | If failing the request:
IRP_MN_QUERY_POWER (device power state) | In an IoCompletion routine, immediately before returning. | In DispatchPower routine, before calling IoCompleteRequest.
IRP_MN_QUERY_POWER (system power state) | In DispatchPower routine, after acquiring remove lock and before setting IRP stack location. | In DispatchPower routine, before calling IoCompleteRequest.
IRP_MN_SET_POWER (device power state) | In an IoCompletion routine, immediately before returning. | Not allowed.
IRP_MN_SET_POWER (system power state) | In DispatchPower routine, after acquiring remove lock and before setting IRP stack location. | Not allowed.


Calling PoStartNextPowerIrp from a Device Power Policy Owner

A function driver that owns device power policy calls PoStartNextPowerIrp once for every IRP_MN_QUERY_POWER or IRP_MN_SET_POWER request it receives. When the call occurs depends on the type of request and whether the driver will fail or succeed the request, as the following table shows.

Request | If succeeding the request: | If failing the request:
IRP_MN_QUERY_POWER (device power state) | In an IoCompletion routine, immediately before returning. | In DispatchPower routine, before calling IoCompleteRequest.
IRP_MN_QUERY_POWER (system power state) | In the PoRequestPowerIrp callback routine for the related device IRP, immediately before completing the system IRP. | In DispatchPower routine, before calling IoCompleteRequest.
IRP_MN_SET_POWER (device power state) | In an IoCompletion routine, immediately before returning. | Not allowed.
IRP_MN_SET_POWER (system power state) | In the PoRequestPowerIrp callback routine for the related device IRP, immediately before completing the system IRP. | Not allowed.


Calling PoStartNextPowerIrp from a Bus Driver

A bus driver calls PoStartNextPowerIrp once for every IRP_MN_QUERY_POWER or IRP_MN_SET_POWER request it receives.

A bus driver always calls this routine in its DispatchPower routine, before calling IoCompleteRequest.


Passing Power IRPs

Power IRPs must be passed all the way down the device stack to the PDO to ensure that power transitions are managed cleanly. Drivers handle an IRP that reduces device power as the IRP travels down the device stack. Drivers handle an IRP that applies device power in IoCompletion routines as the IRP travels back up the device stack.

The following figure shows the steps involved in passing down a power IRP.

Passing Down a Power IRP

As the previous figure shows, a driver must do the following:

  1. Depending on the type of driver, possibly call PoStartNextPowerIrp. See Calling PoStartNextPowerIrp for details.
  2. Call IoCopyCurrentIrpStackLocationToNext if setting an IoCompletion routine, or IoSkipCurrentIrpStackLocation if not setting an IoCompletion routine.

    These two routines set the IRP stack location for the next lower driver. Copying the current stack location ensures that the IRP stack pointer is set to the correct location when the IoCompletion routine runs.

  3. Call IoSetCompletionRoutine to set an IoCompletion routine. In the IoCompletion routine, most drivers call PoStartNextPowerIrp to indicate that it is ready to handle the next power IRP.
  4. Call PoCallDriver to pass the IRP to the next lower driver in the stack.

    Drivers must use PoCallDriver, rather than IoCallDriver (as for other IRPs) to ensure that the system synchronizes power IRPs properly. See Using PoCallDriver for details.

Remember that IoCompletion routines can be called at IRQL DISPATCH_LEVEL. Therefore, if a driver requires additional processing at IRQL PASSIVE_LEVEL after lower level drivers have finished with the IRP, the driver's completion routine should queue a work item and then return STATUS_MORE_PROCESSING_REQUIRED. The worker thread must complete the IRP.

Drivers on Windows 98/Me must complete power IRPs at IRQL PASSIVE_LEVEL.

Do Not Block While Handling a Power IRP

Drivers must not cause long delays while handling power IRPs.

When passing down a power IRP, a driver should return from its DispatchPower routine as soon as possible after calling PoCallDriver. A driver must not wait on a kernel event or otherwise delay before returning. If a driver cannot handle a power IRP in a brief time, it should return STATUS_PENDING and queue all incoming IRPs until the power IRP completes. (Note that this behavior is different from that of PnP IRPs and DispatchPnP routines, which are allowed to block.)

If the driver must wait for a power action by another driver further down the device stack, it should return STATUS_PENDING from its DispatchPower routine and set an IoCompletion routine for the power IRP. In the IoCompletion routine, it can perform whatever tasks it requires, and then call PoStartNextPowerIrp and IoCompleteRequest.

For example, the power policy owner for a device typically sends a device power IRP while holding a system power IRP in order to set the device power state appropriate for the requested system state.

In this situation, the power policy owner should set an IoCompletion routine in the system power IRP, pass the system power IRP to the next lower driver, and return STATUS_PENDING from its DispatchPower routine.

In the IoCompletion routine, it calls PoRequestPowerIrp to send the device power IRP, passing a pointer to a callback routine in the request. The IoCompletion routine should return STATUS_MORE_PROCESSING_REQUIRED.

Finally, the driver passes down the system IRP from the callback routine. The driver must not wait on a kernel event in its DispatchPower routine and signal with the IoCompletion routine for the IRP it is currently handling; a system deadlock might occur. See Handling a System Set-Power IRP in a Device Power Policy Owner for details.

In a similar situation, when the system is going to sleep, a power policy owner might need to complete some pending I/O before it sends the device IRP to power down its device. Instead of signaling an event when the I/O completes and waiting in its DispatchPower routine, the driver should queue a work item and return STATUS_PENDING from the DispatchPower routine. In the worker thread, it waits for I/O to complete and then sends the device power IRP. See IoAllocateWorkItem for more information. (This routine is not available on Windows 98.)


Queuing I/O Requests While a Device Is Sleeping

While a device is asleep, its drivers should queue any I/O requests directed to the device. The IoAllocateWorkItem, IoQueueWorkItem, and IoFreeWorkItem support routines provide one way of queuing IRPs for delayed processing. For an example, see the queuing mechanism described for PnP drivers in Holding Incoming IRPs When a Device Is Paused.

A driver can access its device only when the device is in the Working (D0) state. A driver cannot touch any device registers when the device is in a sleep state; the device must first be returned to the Working state.


Handling Unsupported or Unrecognized Power IRPs

If a driver does not support a particular power IRP, it must nevertheless pass the IRP down the device stack to the next lower driver. A driver further down the stack might be prepared to handle the IRP and must have the opportunity to do so.

To pass an unsupported or unrecognized power IRP, a driver should call PoStartNextPowerIrp, IoSkipCurrentIrpStackLocation, and PoCallDriver, in the sequence described in Passing Power IRPs. The driver should not change anything in the IRP before passing it down.


Managing Power for Individual Devices

Drivers manage power for their devices by responding to system power state changes, detecting and shutting down idle devices, and powering up devices when they are needed.

This section covers the following topics related to device power management:

  • Device Power States
  • Managing Device Power Policy
  • Handling IRP_MN_SET_POWER for Device Power States
  • Handling IRP_MN_QUERY_POWER for Device Power States
  • Sending IRP_MN_QUERY_POWER or IRP_MN_SET_POWER for Device Power States
  • Detecting an Idle Device


Device Working State D0

In the D0 state, the device is fully on and operational.

Power consumption
Highest level of continuous power consumption for the device
Device context
All context retained
Device driver behavior
Normal operation
Restore time
Not applicable
Wake-up Capability
Not applicable


Device Sleeping States D1, D2, and D3

Device states D1, D2, and D3 are the device sleeping states.

D1 and D2 are intermediate sleeping states. Many classes of devices do not define these states. All devices must define state D3.

Device State D1

Device state D1 is the highest-powered sleeping state. It has the following characteristics:

Power consumption
Consumption is less than in the D0 state but greater than or equal to that in the D2 state.
Device context
In general, device context is preserved by the hardware and need not be restored by the driver.
Device driver behavior
Drivers must save and restore or reinitialize any context lost by the hardware. Typically, however, devices lose little context upon entering this state.
Restore time
In general, the time required to restore the device to D0 from D1 should be less than restoration from D2 to D0.
Wake-up Capability
A device in state D1 might be able to request wake-up.

To minimize the user's perception of delay, restoring a device to state D0 from D1 should incur the least possible delay. Minimizing delay in the state transition is more important than reducing power consumption.

Device State D2

State D2 is an intermediate sleeping state with the following characteristics:

Power consumption
Consumption is less than or equal to that in the D1 state.
Device context
In general, most device context is lost by the hardware.
Device driver behavior
Device drivers must save and restore or reinitialize any context lost by the hardware. A typical device loses most context when it enters D2.
Restore time
Restoring the device from D2 to D0 takes at least as long as restoring the device from D1 to D0.
Wake-up Capability
A device in state D2 might be able to request wake-up.

In state D2, power consumption drops to the lowest level from which drivers can recover in a reasonable amount of time, that is, without a delay that most users would find noticeably slow for a device of that type. While the priority for state D1 is the user's perception of delay, the priority for state D2 is power conservation. As a result, the restore time from state D2 to state D0 typically exceeds that from state D1 to D0. In state D2, for example, reduced power on the bus might cause a device to turn off some of its functionality, thus requiring additional time to restart and restore the device.

Many classes of device do not define this state.

Device State D3

State D3 is the lowest-powered sleeping state. All devices must support this state. It has the following characteristics:

Power consumption
Power might have been fully removed from the device and/or from the system.
Device context
The device driver is solely responsible for restoring device context. The driver must preserve and then restore device context or must reinitialize the device upon transition to a different power state.
Device driver behavior
The device driver is solely responsible for restoring device context, typically from the most recent working configuration.
Restore time
Total restore time is the highest of any of the device states.
Wake-up capability
Devices in state D3 cannot wake a sleeping system.

In state D3, power has been completely removed from the device or only minimal trickle current is available. Drivers and hardware must be prepared for the absence of power. When power is restored, the operating system applies any necessary hardware-reset signals. To return the device to the working state, the device's drivers must be able to restore and reinitialize the device without depending on the BIOS code being run.

The Power Manager might remove system power from the parent of any device that enters D3.

All classes of device define this state.


Required Support for Device Power States

Consult the relevant Device Class Power Management Reference Specification to find out which device states are defined for the class of device with which you are working with and what the operational requirements are for each state. These specifications are available at www.microsoft.com/hwdev.

Legacy devices and other devices for which no power management specification exists should follow the Default Device Class Power Management Specification. In essence, the default specification requires the following:

  • Support for the D0 and D3 states
  • A driver that saves and restores or reinitializes device context when the device is powered on
  • A driver that manages the device power policy

Class and port drivers supplied with the system and by IHVs typically support power management. If you are writing a minidriver that links to such a driver, check the relevant class or port driver documentation in this DDK to find out the extent of power management support required in the minidriver. The following general guidelines apply:

  • Network adapter drivers must conform to the NDIS 5.0 specification and power management interfaces, described in the device class reference specifications and elsewhere in this DDK.
  • Streaming drivers use the power management interfaces in the streaming class driver to handle device states D0 and D3. To handle device states D1 and D2, these drivers must use the power management interfaces described in this chapter.
  • The SCSI port driver manages most of the PnP and power management requirements for the miniport. SCSI miniport drivers must support PnP and power management interfaces along with related routines such as HwScsiAdapterControl.
  • The video port driver manages most of the PnP and power management requirements for the miniport. Video miniport drivers must support miniport-specific routines, which are described elsewhere in this DDK.


Managing Device Power Policy

Just as the Power Manager maintains and administers power policy for the system, one driver in the device stack for each device maintains and administers power policy for the device. This driver is the device power policy owner for the device.

The device power policy owner is the driver that has the most information about the device usage and power state. It need not physically be able to set the device registers to power the device on and off, but it must be able to determine when the device is in use, when it is idle, and when it should change power state.

Typically, the function driver for a device is its power policy owner, although for some devices another driver or system component might assume this role. See Types of WDM Drivers for more information on the types of drivers involved in power management.

Some drivers act as the function driver for one device (creating an FDO) and the bus driver (creating a PDO) for an enumerated child device. In its Dispatch routines for power and PnP IRPs, such a driver must distinguish its handling of IRPs sent to the FDO and those sent to the PDO.

For example, the driver for a SCSI adapter might perform the roles of function driver (creating an FDO) for the adapter itself and bus driver (creating a PDO) for the disks attached to the adapter. In its capacity as function driver/policy owner for the SCSI adapter, this driver receives system IRPs and requests device IRPs for the SCSI adapter. In its capacity as bus driver for the disks, it handles and completes device IRPs that specify the disk PDOs it creates. Just because the driver owns power policy for one device (FDO) does not mean that it owns power policy for the child device (PDO).

The device power policy owner is responsible for the following:

  • Setting the initial power state of the device to D0 by calling PoSetPowerState as it handles the PnP Manager's IRP_MN_START_DEVICE request.

    Devices should power on as needed; for example, a device must power on to handle an I/O request. The device power policy owner is responsible for determining when its device is needed, ensuring that device power is on, and setting the correct device power state. The typical device should be powered on by the time the PnP start-device IRP has completed.

    As a general rule, most devices should be powered off when not in use, even when the system is in the working state.

  • Sending a device power request in response to a system power request by calling PoRequestPowerIrp.

    For example, when the policy owner receives a system set-power IRP, it sends a device set-power IRP. Most devices enter D3 when the system enters any sleeping state. The DeviceState array in the DEVICE_CAPABILITIES structure lists the highest-powered state the device can maintain for each system state. (See Reporting Device Power Capabilities.)

  • Detecting when the device is idle and putting it to sleep to conserve energy.

    Either the Power Manager or the device policy owner can detect an idle device and send a device power IRP to change its state. See Detecting an Idle Device for details.

  • Returning its device to the working state when required.

    When an I/O request arrives for a sleeping device, the device's drivers should return it to the working state.

  • Enabling and disabling wake-up for its device when requested.

    The device power policy owner sends and cancels wait/wake IRPs, as described in Supporting Devices that Have Wake-Up Capabilities.


Handling IRP_MN_SET_POWER for Device Power States

A device set-power IRP requests a change of state for a single device and is sent to all the drivers in the stack for the device. Such an IRP specifies DevicePowerState in the Power.Type member of the I/O stack location.

Drivers handle power-down IRPs as they travel down the stack. For power-up IRPs, drivers set IoCompletion routines as the IRPs travel down the stack, and then handle the IRPs in the IoCompletion routines as the IRPs travel back up the stack. The drivers in a typical device stack handle a device set-power IRP as follows:

  • Most filter drivers should simply call IoMarkIrpPending, pass the IRP to the next lower driver (see Passing Power IRPs), and return STATUS_PENDING from the DispatchPower routine. Some filter drivers, however, might first need to perform device-specific tasks, such as queuing incoming IRPs or saving device state.
  • A function driver calls IoMarkIrpPending, performs device-specific tasks (such as completing pending I/O requests, queuing incoming I/O requests, saving device context, or changing device power), sets an IoCompletion routine if necessary, and passes the device power IRP to the next lower driver (see Passing Power IRPs). It returns STATUS_PENDING from its DispatchPower routine.
  • The bus driver changes device power if it is capable of doing so, calls PoSetPowerState to notify the Power Manager of the new device state, and calls PoStartNextPowerIrp to start the next power IRP. It then completes the IRP, specifying IO_NO_INCREMENT. If the driver cannot complete the IRP immediately, it calls IoMarkIrpPending, returns STATUS_PENDING from its DispatchPower routine, and completes the IRP later.

A driver should not fail an IRP_MN_SET_POWER request.

Even if the target device is already in the requested power state, each function or filter driver must pass the IRP down to the next lower driver. Every set-power IRP must travel all the way down the device stack to the bus driver, which completes it.

Each time a device changes state, its drivers must call PoSetPowerState to inform the Power Manager of the change. Like other driver tasks associated with device power-up and power-down, the call to PoSetPowerState must occur after the device powers on (if the new state is D0) or before the device powers off (if the new state is any other state).

Each driver should keep track of the power state of its device. The Power Manager does not supply this information to drivers.

While handling an IRP_MN_SET_POWER request for a device power state, a driver should return from the DispatchPower routine as quickly as possible. A driver must not wait in its DispatchPower routine for a kernel event signaled by code that handles the same IRP. Because power IRPs are synchronized throughout the system, a deadlock might occur.

The exact steps a driver must take to handle a power IRP depend upon whether the device is powering up or down, as described in the following sections:

Handling Device Power-Down IRPs

Handling Device Power-Up IRPs


Handling Device Power-Down IRPs

A device power-down IRP specifies the minor function code IRP_MN_SET_POWER and a device state (PowerDeviceD0, PowerDeviceD1, PowerDeviceD2, or PowerDeviceD3) that is less-powered or equal to the current device power state. Drivers must handle the power-down IRP as the IRP travels down the device stack. Higher-level drivers must handle the IRP before lower-level drivers. Drivers that have no device-specific tasks to perform should promptly pass the IRP to the next lower driver.

The following figure shows the steps involved in handling such an IRP:

Handling a Device Power-Down Request

If the IRP specifies PowerDeviceD3, the function driver should typically perform the following tasks:

  • Call IoAcquireRemoveLock, passing the current IRP, to ensure that the driver does not receive a PnP IRP_MN_REMOVE_DEVICE request while handling the power IRP.

    If IoAcquireRemoveLock returns a failure status, the driver should not continue processing the IRP. Instead, it should call PoStartNextPowerIrp, then complete the IRP (IoCompleteRequest), and then return the failure status.

  • Perform any device-specific tasks that must be done before device power is removed, such as closing the device, completing or flushing any pending I/O, disabling interrupts, queuing subsequent incoming IRPs, and saving device context from which to restore or reinitialize the device.

    The driver should not cause a long delay (for example, a delay that a user might find unreasonable for this type of device) while handling the IRP.

    The driver should queue any incoming I/O requests until the device has returned to the working state.

  • Possibly check the value at Parameters.Power.ShutdownType. If a system set-power IRP is active, the ShutdownType provides information about the system IRP. See System Power Actions for details about this value.

    Drivers of devices on the hibernate path must inspect this value. If the ShutdownType is PowerActionHibernate, the driver should save any context required to restore the device but should not power down the device.

  • Change the physical power state of the device if the driver is capable of doing so and if the change is appropriate.
  • Call PoSetPowerState to notify the Power Manager of the new device power state.
  • Call IoCopyCurrentIrpStackLocationtoNext to set up the stack location for the next lower driver.
  • Set an IoCompletion routine that calls PoStartNextPowerIrp, which indicates that the driver is ready to handle the next power IRP.
  • Call PoCallDriver to pass the IRP to the next lower driver. The IRP must be passed all the way down to the bus driver, which completes it.
  • Call IoReleaseRemoveLock to release the previously acquired lock.
  • Return STATUS_PENDING.

Drivers must save any device context information and set the new power state before forwarding the IRP. The context information should contain, at minimum, the requested new power state. It should also include any additional information the driver will need upon power-up. After the IRP has been completed and the device has been powered off, the driver can no longer access the device and device context is not available.

Each driver must pass the IRP to the next-lower driver. When the IRP reaches the bus driver, the bus driver powers off the device (if it is capable of this), calls PoSetPowerState to inform the Power Manager, and completes the IRP.

However, if the bus driver services the hibernation device, it should check whether the value of ShutdownType in the IRP is PowerSystemHibernate. If so, the bus driver should call PoSetPowerState to report PowerDeviceD3 but should not power down the device. The device will power down after the hibernate file is saved, along with the rest of the system.

After all its child devices power down, a bus driver might choose to power down its bus also. Such behavior is device-dependent.

If the IRP specifies any other state (D0, D1 or D2), required driver actions are device-dependent. Typically, devices that support these states can quickly return to the working state when an I/O request arrives. A driver for such a device must complete any pending I/O requests, queue any new requests, and save all necessary context before forwarding the IRP to the next lower driver. When the IRP reaches the bus driver, it sets the hardware in the requested state. A driver cannot access the device while it is asleep.

Under some circumstances, a function or filter driver might receive a device power IRP specifying PowerDeviceD0 when the device is already in the D0 state. The driver should handle this IRP as it would any other set-power IRP: complete pending I/O requests, queue incoming I/O requests, set an IoCompletion routine, and pass the IRP down to the next lower driver. A driver must not, however, change the device's hardware settings. When the bus driver receives the IRP, it should simply complete the IRP. When the IRP completes, function and filter drivers can handle any queued requests. Queuing I/O until the IRP completes eliminates any possibility of lower drivers attempting to change device registers while a higher driver attempts I/O.


Handling Device Power-Up IRPs

Device power-up IRPs specify IRP_MN_SET_POWER and a device state that requires more power than the current device state. Typically, a power-up IRP specifies the device working state PowerDeviceD0.

Requests to power up a device must be handled first by the underlying bus driver for the device, and then by each successive driver going back up the stack.

The following figure shows the steps involved in handling a power-up IRP.

Handling a Device Power-Up Request

When handling an IRP_MN_SET_POWER request for power-up, a function or filter driver must:

  • Call IoAcquireRemoveLock to ensure that the driver does not receive an IRP_MN_REMOVE_DEVICE request while handling the power-up IRP.

    If IoAcquireRemoveLock returns a failure status, the driver should not continue processing the IRP. Instead, it should call PoStartNextPowerIrp, then complete the IRP (IoCompleteRequest), and return the failure status.

  • Call IoMarkIrpPending to mark the IRP pending.
  • Call IoCopyCurrentIrpStackLocationToNext to set the IRP stack location. A driver must not call IoSkipCurrentIrpStackLocation if it sets an IoCompletion routine.
  • Call IoSetCompletionRoutine to set a power-up IoCompletion routine.

    When handling a device power-up IRP, the driver should set an IoCompletion routine to restore context, release the remove lock, and perform other required tasks after the IRP is complete and the device powers on. The driver should not restore context before the IRP has completed. See IoCompletion Routines for Device Power IRPs for details.

  • Call PoCallDriver to pass the IRP to the next-lower driver.

    The IRP must travel all the way down the device stack to the bus driver. Only the bus driver is allowed to complete the IRP.

  • Return STATUS_PENDING.

When the bus driver receives the IRP, it should first check to ensure the device is still present and has not been removed or replaced while asleep. If the device is no longer present, the bus driver should call IoInvalidateDeviceRelations on the parent device to notify the PnP Manager that the device has disappeared. In this situation, the bus driver can fail the power IRP.

If the device is still present, the bus driver then performs the tasks required to return the device to an operating condition, calls PoSetPowerState to inform the Power Manager of the new device state, and completes the IRP (IoCompleteRequest). If drivers have queued I/O while the device was sleeping, or if the device requires inrush power, the bus driver applies power to the device. Otherwise, the bus driver applies power as soon as it has to communicate with the device.


IoCompletion Routines for Device Power IRPs

After the bus driver completes the IRP, the I/O Manager calls the IoCompletion routines registered by higher-level drivers as they passed the IRP down the stack.

Whenever a device enters the D0 state, each of its drivers should set an IoCompletion routine that performs most of the tasks required to return it to the working state. Drivers should set an IoCompletion routine for any transition to the D0 state, whether the device is returning from a sleeping state or entering D0 at system start-up. The following figure shows the tasks such an IoCompletion routine should perform:

Device Power-Up IoCompletion Routine

These tasks include:

  • Restoring device state or reinitializing the device, as required, and preparing to handle any I/O queued by drivers while the device was not in the working state
  • Calling PoSetPowerState to notify the Power Manager that the device is in the D0 power state.
  • Calling PoStartNextPowerIrp to receive the next power IRP, if the driver did not originally send the current power IRP.
  • Freeing memory allocated for the device context.
  • Calling IoReleaseRemoveLock to free the lock that the driver acquired in its DispatchPower routine when it received the IRP.
  • Returning STATUS_SUCCESS.

The bus driver does not power up the device until it or higher drivers must communicate with the device.

When its device enters a sleeping state, a driver should set an IoCompletion routine that simply calls PoStartNextPowerIrp and releases the remove lock. Remember that a driver cannot access its device while the device is in a sleeping state.


Handling IRP_MN_QUERY_POWER for Device Power States

A device query-power IRP queries about a change of state for a single device and is sent to all the drivers in the stack for the device. Such an IRP specifies DevicePowerState in the Power.Type member of the I/O stack location.

Drivers handle query-power IRPs as they travel down the stack.

A function or filter driver can fail an IRP_MN_QUERY_POWER request if any of the following is true:

  • The device is enabled for wake-up and the requested power state is below the state from which the device can wake the system. For example, a device that can wake the system from D2 but not from D3 would fail a query for D3 but succeed a query for D2.
  • Entering the requested state would force the driver to abandon an operation that would lose data, such as an open modem connection. A driver rarely will fail a query for this reason; under most circumstances, the application handles such cases.

To fail an IRP_MN_QUERY_POWER request, a driver takes the following steps:

  1. Call PoStartNextPowerIrp to indicate its readiness to handle the next power IRP.
  2. Set Irp->IoStatus.Status to a failure status and call IoCompleteRequest, specifying IO_NO_INCREMENT. The driver does not pass the IRP further down the device stack.
  3. Return an error status from its DispatchPower routine.

If the driver succeeds the query IRP, it must not start any operations or take any other action that would prevent its successful completion of a subsequent IRP_MN_SET_POWER request to the queried power state.

A driver that succeeds the IRP must prepare for a set-power IRP for the queried state and pass down the query IRP, as follows:

  1. Finish any outstanding I/O operations.
  2. Queue incoming I/O requests.
  3. Avoid starting any other new activities that would interfere with a transition to the specified power state. However, the driver should not save device context or take other steps toward shutdown.
  4. Call IoCopyCurrentIrpStackLocationToNext to set the IRP stack location for the next lower driver.
  5. Set an IoCompletion routine. In the IoCompletion routine, call PoStartNextPowerIrp to indicate the driver's readiness to handle the next power IRP.
  6. Call PoCallDriver to pass the query IRP to the next lower driver. Do not complete the IRP.
  7. Return STATUS_PENDING. The driver must not change the value at Irp->IoStatus.Status.

When the query IRP reaches the bus driver, the bus driver calls PoStartNextPowerIrp and sets Irp->IoStatus.Status to STATUS_SUCCESS if it can change to the specified power state or sets a failure status if it cannot. It then calls IoCompleteRequest, specifying IO_NO_INCREMENT.

The drivers in a typical device stack handle a device query-power IRP as follows:

  • Most filter drivers should simply pass the IRP to the next lower driver (see Passing Power IRPs) and return STATUS_PENDING. Some filter drivers, however, might first need to perform device-specific tasks, such as queuing incoming IRPs or saving device state.
  • A function driver performs device-specific tasks (such as, completing pending I/O requests, queuing incoming I/O requests, saving device context, or changing device power), sets an IoCompletion routine, and passes the device power IRP to the next lower driver (see Passing Power IRPs). It returns STATUS_PENDING from its DispatchPower routine.
  • The bus driver calls PoStartNextPowerIrp to start the next power IRP. It then completes the IRP, specifying IO_NO_INCREMENT. If the driver cannot complete the IRP immediately, it calls IoMarkIrpPending, returns STATUS_PENDING from its DispatchPower routine, and completes the IRP later.

Even if the target device is already in the queried power state, each function or filter driver must queue I/O and pass the IRP down to the next lower driver. The IRP must travel all the way down the device stack to the bus driver, which completes it.

While handling an IRP_MN_QUERY_POWER request, a driver should return from the DispatchPower routine as quickly as possible. A driver must not wait in its DispatchPower routine for a kernel event signaled by code that handles the same IRP. Because power IRPs are synchronized throughout the system, a deadlock might occur.


Sending IRP_MN_QUERY_POWER or IRP_MN_SET_POWER for Device Power States

A device power policy owner sends a device query-power IRP (IRP_MN_QUERY_POWER) to determine whether lower drivers can accommodate a change in device power state, and a device set-power IRP (IRP_MN_SET_POWER) to change the device power state. (This driver can also send a wait/wake IRP to enable its device to awaken in response to an external signal; see Supporting Devices that Have Wake-Up Capabilities for details.)

The driver should send an IRP_MN_QUERY_POWER request when either of the following is true:

  • The driver receives a system query-power IRP.
  • The driver is preparing to put an idle device in a sleep state, so must query lower drivers to find out whether doing so is feasible.

The driver should send an IRP_MN_SET_POWER request when any of the following is true:

  • The driver has determined that the device is idle and can be put to sleep.
  • The device is sleeping and must reenter the working state to handle waiting I/O.
  • The driver receives a system set-power IRP.

A driver must not allocate its own power IRP; the Power Manager provides the PoRequestPowerIrp routine for this purpose. PoRequestPowerIrp allocates and sends the IRP, and along with PoCallDriver, ensures that all power requests are properly synchronized, as Rules for Handling Power IRPs explains. Callers of PoRequestPowerIrp must be running at IRQL <= DISPATCH_LEVEL.

The following is the prototype for this routine:

NTSTATUS
PoRequestPowerIrp (
    IN PDEVICE_OBJECT DeviceObject,
    IN UCHAR MinorFunction,
    IN POWER_STATE PowerState,
    IN PREQUEST_POWER_COMPLETE CompletionFunction,
    IN PVOID Context,
    OUT PIRP *Irp OPTIONAL
    );

To send the IRP, the driver calls PoRequestPowerIrp, specifying a pointer to the target device object in DeviceObject, the minor IRP code IRP_MN_SET_POWER or IRP_MN_QUERY_POWER in MinorFunction, the value DevicePowerState in the PowerState.Type, and a device power state in PowerState.State. On Windows 98/Me, DeviceObject must specify the PDO of the underlying device; on Windows 2000 and later systems, this value can point to either the PDO or an FDO of a driver in the same device stack.

If the driver must perform additional tasks after all other drivers have completed the IRP, it should pass a pointer to a power completion function in CompletionFunction. The I/O Manager calls the CompletionFunction after calling all the IoCompletion routines set by drivers as they passed the IRP down the stack.

Whenever a device power policy owner sends a device power query IRP, it should subsequently send a device set-power IRP from the callback routine (CompletionFunction) that it specified in the call to PoRequestPowerIrp. If the query succeeded, the set-power IRP specifies the queried power state. If the query failed, the set-power IRP reasserts the current device power state. Reasserting the current state is important because drivers queue I/O in response to the query; the policy owner must send the set-power IRP to notify drivers in its device stack to begin processing queued I/O requests.

Keep in mind that the policy owner for a device not only sends the device power IRP but also handles the IRP as it is passed down the device stack. Therefore, such a driver often sets an IoCompletion routine (with IoSetCompletionRoutine) as part of its IRP-handling code, particularly when the device is powering up. The IoCompletion routine is called in sequence with IoCompletion routines set by other drivers and before the CompletionFunction. See IoCompletion Routines for Device Power IRPs for details.

Because the IRP has been completed by all drivers when the CompletionFunction is called, the CompletionFunction must not call PoStartNextPowerIrp or PoCallDriver with the IRP it originated. (It might, however, call these routines for a different power IRP.) Instead, this routine performs any additional actions required by the driver that originated the IRP. If the driver sent the device IRP in response to a system IRP, the CompletionFunction might complete the system IRP. See Handling a System Set-Power IRP in a Device Power Policy Owner for details.

In response to the call to PoRequestPowerIrp, the Power Manager allocates a power IRP and sends it to the top of the device stack for the device. The Power Manager returns a pointer to the allocated IRP.

If no errors occur, PoRequestPowerIrp returns STATUS_PENDING. This status means that the IRP has been sent successfully and is pending completion. The call fails if the Power Manager cannot allocate the IRP or if the caller has specified an invalid minor power IRP code.

Requests to power up a device must be handled first by the underlying bus driver for the device and then by each successively higher driver in the stack. Therefore, when sending a PowerDeviceD0 request, the driver must ensure that its CompletionFunction performs required tasks after the IRP is complete and the device is powered on.

When powering off a device (PowerDeviceD3), each driver in the device stack must save all of its necessary context and do any necessary clean-up before sending the IRP to the next lower driver. The extent of the context information and clean-up depends on the type of driver. A function driver must save hardware context; a filter driver might need to save its own software context. A CompletionFunction set in this situation can take actions associated with a completed power IRP, but the driver cannot access the device.


Detecting an Idle Device

The power policy owner for each device is responsible for determining when the device is idle and can be put to sleep to conserve power. The policy owner has two options for detecting an idle device:

Use Power Manager routines for idle detection

Perform device-specific idle detection


Using Power Manager Routines for Idle Detection

The Power Manager provides support for idle detection through the PoRegisterDeviceForIdleDetection and PoSetDeviceBusy routines.

To enable idle detection for its device, a device power policy owner calls PoRegisterDeviceForIdleDetection, specifying the following:

  • The idle time-out value to apply when the system optimizes for performance
  • The idle time-out value to apply when the system optimizes for conservation
  • The device power state to which the device should transition when idle.

PoRegisterDeviceForIdleDetection returns a pointer to an idle counter, which the driver uses later to disable idle detection. Callers of PoRegisterDeviceForIdleDetection must be running at IRQL < DISPATCH_LEVEL.

A driver can register its device for idle detection any time after the device has been started and is ready to handle device power IRPs. For example, a driver might enable idle detection as part of its IoCompletion routine for a PnP start-device IRP.

The time-out values for any given device should be proportional to the device's power-up latency and based on observed device behavior. For devices of certain types, a driver can specify conservation and performance time-out values of -1 to use the standard power policy time-outs for the device class. See the device-specific documentation for details.

When the device is in use, the driver must call PoSetDeviceBusy, passing the pointer returned by PoRegisterDeviceForIdleDetection. PoSetDeviceBusy resets the idle counter, thus restarting the idle countdown for the device. The driver should call PoSetDeviceBusy on every I/O operation.

To determine whether the device is idle, the Power Manager compares the value of the idle counter with the driver-specified idle time-out value for the current system power policy (either conservation or performance). See the Platform SDK for functions pertaining to the system power policy.

When the device satisfies the time-out value, the Power Manager sends a device set-power IRP, specifying the device power state that the driver passed in its call to PoRegisterDeviceForIdleDetection. The Power Manager does not send a query IRP before sending the set-power IRP. The drivers in the stack handle the set-power IRP as they would handle any other; they must complete it in a timely manner and they cannot fail it. (See Handling Device Power-Down IRPs.)

When the driver no longer requires idle detection or is not prepared to handle device power-down IRPs, it should call PoRegisterDeviceForIdleDetection again, passing zero for both time-out values. Setting the time-outs to zero disables idle detection for both conservation (battery) and performance (AC) power policies. The driver can quickly re-enable idle detection; it simply calls PoRegisterDeviceForIdleDetection with nonzero time-out values. Once the driver has registered the device, it can enable and disable idle detection by changing the time-out values, even if the device has been powered down and reawakened.


Performing Device-Specific Idle Detection

Instead of using the Power Manager's idle detection routines, a driver can perform its own idle detection based on device-specific criteria.

Such a driver should put its idle device in the lowest possible sleep state that is valid for the current system state. To do so, the driver requests a power IRP (PoRequestPowerIrp) with minor IRP code IRP_MN_SET_POWER, specifying the device power state to which the device should transition.


Handling System Power State Requests

All drivers must be able to respond to system power state requests if the system is to sleep, hibernate, and wake successfully.

If any driver does not support system power management, individual devices can sleep and wake, but the Power Manager cannot put the system as a whole into a sleeping state.

The following topics cover details of handling system power state requests:

  • System Power States
  • System Power Policy
  • Preventing System Power State Changes
  • Handling IRP_MN_QUERY_POWER for System Power States
  • Handling IRP_MN_SET_POWER for System Power States


System Power States

System power states describe the power consumption of the system as a whole. The operating system supports six system power states, referred to as S0 (fully on and operational) through S5 (power off). Each state is characterized by the following:

  • Power consumption: how much power does the computer use?
  • Software resumption: from what point does the operating system restart?
  • Hardware latency: how long does it take to return the computer to the working state?
  • System hardware context (such as the content of volatile processor registers, memory caches, and RAM): how much system hardware context is retained? Must the operating system reboot to return to the working state?

State S0 is the working state. States S1, S2, S3, and S4 are sleeping states, in which the computer appears off because of reduced power consumption but retains enough context to return to the working state without restarting the operating system. State S5 is the shutdown or off state.

A system is waking when it is in transition from the shutdown state (S5) or any sleeping state (S1-S4) to the working state (S0), and it is going to sleep when it is in transition from the working state to any sleep state or the shutdown state. The following figure shows the possible system power state transitions.

Possible System Power State Transitions

As the previous figure shows, the system cannot enter one sleep state directly from another; it must always enter the working state before entering any sleep state. For example, a system cannot transition from state S2 to S4, nor from state S4 to S2. It must first return to S0, from which it can enter the next sleep state. Because a system in an intermediate sleep state has already lost some operating context, it must return to the working state to restore that context before it can make an additional state transition.


System Working State S0

System state S0, the system working state, has the following characteristics:

Power consumption
Maximum. However, the power state of individual devices can change dynamically as power conservation takes place on a per-device basis. Unused devices can be powered down and powered up as needed.
Software resumption
Not applicable.
Hardware latency
None.
System hardware context
All context is retained.


System Sleeping States S1, S2, S3, S4

States S1, S2, S3, and S4 are the sleeping states. A system in one of these states is not performing any computational tasks and appears to be off. Unlike a system in the shutdown state (S5), however, a sleeping system retains memory state, either in the hardware or on disk. The operating system need not be rebooted to return the computer to the working state.

Some devices can wake the system from a sleeping state when certain events occur, such as an incoming call to a modem. In addition, on some computers, an external indicator tells the user that the system is merely sleeping.

With each successive sleep state, from S1 to S4, more of the computer is shut down. All ACPI-compliant computers shut off their processor clocks at S1 and lose system hardware context at S4 (unless a hibernate file is written before shutdown), as listed in the sections below. Details of the intermediate sleep states can vary depending on how the manufacturer has designed the machine. For example, on some machines certain chips on the motherboard might lose power at S3, while on others such chips retain power until S4. Furthermore, some devices might be able to wake the system only from S1 and not from deeper sleep states.

System State S1

System state S1 is a sleeping state with the following characteristics:

Power consumption
Less consumption than in S0 and greater than in the other sleep states. Processor clock is off and bus clocks are stopped.
Software resumption
Control restarts where it left off.
Hardware latency
Typically no more than two seconds.
System hardware context
All context retained and maintained by hardware.

System State S2

System state S2 is similar to S1 except that the CPU context and contents of the system cache are lost because the processor loses lower. State S2 has the following characteristics:

Power consumption
Less consumption than in state S1 and greater than in S3. Processor is off. Bus clocks are stopped; some buses might lose power.
Software resumption
After wake-up, control starts from the processor's reset vector.
Hardware latency
Two seconds or more; greater than or equal to the latency for S1.
System hardware context
CPU context and system cache contents are lost.

System State S3

System state S3 is a sleeping state with the following characteristics:

Power consumption
Less consumption than in state S2. Processor is off and some chips on the motherboard also might be off.
Software resumption
After the wake-up event, control starts from the processor's reset vector.
Hardware latency
Almost indistinguishable from S2.
System hardware context
Only system memory is retained. CPU context, cache contents, and chip set context are lost.

System State S4

System state S4, the hibernate state, is the lowest-powered sleeping state and has the longest wake-up latency. To reduce power consumption to a minimum, the hardware powers off all devices. Operating system context, however, is maintained in a hibernate file (an image of memory) that the system writes to disk before entering the S4 state. Upon restart, the loader reads this file and jumps to the system's previous, pre-hibernation location.

If a computer in state S1, S2, or S3 loses all AC or battery power, it loses system hardware context and therefore must reboot to return to S0. A computer in state S4, however, can restart from its previous location even after it loses battery or AC power because operating system context is retained in the hibernate file. A computer in the hibernate state uses no power (with the possible exception of trickle current).

State S4 has the following characteristics:

Power consumption
Off, except for trickle current to the power button and similar devices.
Software resumption
System restarts from the saved hibernate file. If the hibernate file cannot be loaded, rebooting is required. Reconfiguring the hardware while the system is in the S4 state might result in changes that prevent the hibernate file from loading correctly.
Hardware latency
Long and undefined. Only physical interaction returns the system to the working state. Such interaction might include the user pressing the ON switch or, if the appropriate hardware is present and wake-up is enabled, an incoming ring for the modem or activity on a LAN. The machine can also awaken from a resume timer if the hardware supports it.
System hardware context
None retained in hardware. The system writes an image of memory in the hibernate file before powering down. When the operating system is loaded, it reads this file and jumps to its previous location.


System Shutdown State S5

In the S5, or shutdown, state, the machine has no memory state and is not performing any computational tasks.

The only difference between states S4 and S5 is that the computer can restart from the hibernate file in state S4, while restarting from state S5 requires rebooting the system.

State S5 has the following characteristics:

Power consumption
Off, except for trickle current to devices such as the power button.
Software resumption
Boot is required upon awakening.
Hardware latency
Long and undefined. Only physical interaction, such as the user pressing the ON switch, returns the system to the working state. The BIOS can also awaken from a resume timer if the system is so configured.
System hardware context
None retained.


System Power Actions

When the Power Manager sends an IRP to set or query the system power state, it specifies a system power state along with an additional parameter that gives information about the power state change. This parameter, passed at Irp->Parameters.Power.ShutdownType, is an enumerator of the POWER_ACTION type. The enumerator characterizes the system power state request, as shown in the following table:

POWER_ACTION Enumerator | System Power State Requested
PowerActionNone | S0 or no system power IRP active
PowerActionSleep | S1, S2, or S3
PowerActionHibernate | S4
PowerActionShutdown (Microsoft® Windows® 2000 and later systems only) | S5
PowerActionShutdownReset | S5
PowerActionShutdownOff | S5

When a driver receives a system query or set-power IRP for S5, it can check ShutdownType for more information on the requested shutdown. A driver can use this information to optimize its shutdown sequence when the machine is resetting instead of shutting off power indefinitely. Drivers of most devices retain power when the system resets. However, for certain devices, such as a video streaming device that performs DMA, a driver might choose to power down its device when the system is resetting, thus stopping any ongoing I/O.

When a device power policy owner sends a device power IRP to its device stack in response to a system power IRP, drivers can use the ShutdownType parameter to get information about the current system power IRP. In this case, the value of ShutdownType indicates the currently requested system power state, or it is PowerActionNone if a system request is not outstanding. Drivers should not, however, rely on this information if the device IRP requests state D0.

On Windows 98/Me, this field always contains PowerActionNone when the IRP requests a device power state.


System Power Policy

In its role as system power policy manager, the Power Manager keeps track of system activity, determines the appropriate system power state, and sends IRP_MJ_POWER requests to query or change the system power state. It also provides interfaces through which applications can read and write power policy settings (see the Platform SDK).

The Power Manager maintains two separate power policies — one for AC (wall current) and one for DC (battery or UPS) — and automatically switches between these two policies depending on the current power source. Typically, AC power policy emphasizes performance over conservation, while DC power policy emphasizes conservation over performance. To find out when the system changes from one policy to the other, a driver can register for notification with the system's \Callback\PowerState callback object. See ExCreateCallback and Callback Objects for details.

Computers that comply with the APCI specification automatically switch from AC to battery power, and from one battery to another, as each such power source goes off line. If the computer hardware allows the operating system to select the power source, the Power Manager tracks which battery is the least charged but still functional and selects it to power the computer.

As soon as AC power becomes available, the computer hardware automatically starts to charge a battery. If the hardware allows the operating system to select which battery to charge, the Power Manager selects the least discharged battery for recharging; this increases the chances that the system will have at least one well-charged battery at all times.

Regardless of any other settings, the Power Manager carries out the DC power policy for a critical battery if a battery that is rechargeable or supplies system power reports the hardware condition "critical" and is in the discharging state for two seconds or longer. Power policy in this situation typically requires a transition to the hibernate or shutdown state.


Preventing System Power State Changes

Although drivers cannot directly set system power policy, the Power Manager provides three routines through which a driver can prevent system transitions out of the working state: PoSetSystemState, PoRegisterSystemState, and PoUnregisterSystemState.

By calling PoRegisterSystemState or PoSetSystemState, a driver can notify the Power Manager that a user is present or that the driver requires use of the system or display.

PoRegisterSystemState allows a driver to register a continuous busy state. It returns a handle through which the driver can later change its settings. As long as the state registration is in effect, the Power Manager does not attempt to put the system to sleep. The driver cancels the state registration by calling PoUnregisterSystemState.

With PoSetSystemState, a driver notifies the Power Manager of the same conditions (user present, system required, display required), but this setting is not continuous. It has the effect of restarting any idle count downs associated with the specified conditions.

Using these routines, a driver can forestall many, but not all, transitions out of the working state. The Power Manager always shuts down the system when loss of power is imminent or when a user explicitly requests shutdown.


Handling IRP_MN_QUERY_POWER for System Power States

The Power Manager sends a power IRP with the minor IRP code IRP_MN_QUERY_POWER and SystemPowerState in Parameters.Power.Type to determine whether it can safely change to a specified system power state (S1-S5) and to allow drivers to prepare for such a change.

Whenever possible, the Power Manager queries before sending an IRP_MN_SET_POWER that requests a lower (less powered) state. However, in cases of a failing battery or imminent loss of power, the Power Manager sends the set-power IRP without querying first. The Power Manager never sends a query before sending an IRP to set the system in the working state (S0).

An IRP_MN_QUERY_POWER request for a system power state requires action only if a driver must fail the IRP, and by the device power policy owner. Most filter drivers should simply pass the IRP to the next lower driver until it reaches the bus driver, which completes it. A driver never sends a device IRP_MN_SET_POWER request in response to a system query; it requests such an IRP only after it receives a system set-power request.

See the following for more information on how to handle system power queries:

Failing a System Query-Power IRP

Handling a System Query-Power IRP in a Device Power Policy Owner

Handling a System Query-Power IRP in a Bus Driver

Handling a System Query-Power IRP in a Filter Driver

Because the Power Manager sends the system query IRP to each device stack on the system, it is possible that a driver for one device might fail the query while drivers for other devices complete it successfully. It is also possible that a battery might expire while a query is active, requiring an immediate shutdown. Consequently, after a query IRP, drivers must be prepared to receive any of the following power IRPs:

  • An IRP_MN_SET_POWER to the queried state
  • An IRP_MN_SET_POWER to a different power state
  • An IRP_MN_SET_POWER to the current power state
  • An IRP_MN_QUERY_POWER to any state

Usually, however, a driver receives a system set-power IRP following a system query IRP. If the query succeeded, the set-power IRP specifies the queried state. If the query failed, the set-power IRP reaffirms the current power state.


Failing a System Query-Power IRP

A function or filter driver can fail an IRP_MN_QUERY_POWER request if either of the following is true:

  • The device is enabled for wake-up and the requested system power state is less powered than the value of SystemWake, which specifies the least-powered state from which the device can wake the system. For example, a device that can wake the system from S2 but not from S3 would fail a query for S3 but succeed a query for S2.
  • Entering a device state that corresponds to the requested state would force the driver to abandon an operation that would lose data, such as an open modem connection. A driver rarely will fail a query for this reason; under most circumstances, the application handles such cases.

To fail an IRP_MN_QUERY_POWER request for a system power state, a driver should take the following steps:

  1. Call PoStartNextPowerIrp to indicate its readiness to handle the next power IRP.
  2. Set Irp->IoStatus.Status to a failure status and call IoCompleteRequest, specifying IO_NO_INCREMENT. Do not pass the IRP further down the device stack.
  3. Call IoReleaseRemoveLock to release the previously acquired lock.
  4. Return a failure status from its DispatchPower routine.


Handling a System Query-Power IRP in a Device Power Policy Owner

When a device power policy owner receives an IRP_MN_QUERY_POWER for a system state, it responds by passing down the query and, in an IoCompletion routine, sending an IRP_MN_QUERY_POWER for a device power state. When all drivers in the stack have completed the device query, the device power policy owner completes the system query.

A device power policy owner should take the following steps in its DispatchPower routine to respond to a system query:

  1. Call IoAcquireRemoveLock, passing the current IRP, to ensure that the driver does not receive a PnP IRP_MN_REMOVE_DEVICE request while handling the power IRP.

    If IoAcquireRemoveLock returns a failure status, the driver should not continue processing the IRP. Instead, it should call PoStartNextPowerIrp, then complete the IRP (IoCompleteRequest), and return the failure status.

  2. Ensure that the driver can support the queried system power state, as described in Failing a System Query-Power IRP. If not, complete the IRP with a failure status as described in that section.

    However, a driver must not fail a query for S4 (PowerSystemHibernate) if its device is enabled for wake-up but it cannot wake the system from the hibernate state. In this case, the power policy owner for the driver (which sent the IRP_MN_WAIT_WAKE) must cancel the wait/wake IRP and succeed the system query. See Canceling a Wait/Wake IRP for more information.

  3. If the driver can support the queried system power state, call IoMarkIrpPending.
  4. Set up the IRP stack location for the next lower driver by calling IoCopyCurrentIrpStackLocationToNext.
  5. Set an IoCompletion routine in the system query power IRP.
  6. Call PoCallDriver to pass the IRP to the next lower driver.
  7. Return STATUS_PENDING.

The IoCompletion routine should do the following:

  1. Check Irp->IoStatus.Status to ensure that lower drivers have completed the IRP successfully. If any driver has failed the IRP, call IoCompleteRequest to complete the IRP and return the failure status.
  2. If lower drivers have successfully completed the IRP, call PoRequestPowerIrp to send a device query-power IRP for a device state that is valid for the queried system state. If necessary, consult the DEVICE_STATE array in the DEVICE_CAPABILITIES structure to determine which device states are valid for the queried system state.
  3. Specify a callback routine (CompletionFunction) in the call to PoRequestPowerIrp and pass the system IRP in the Context area.
  4. Return STATUS_MORE_PROCESSING_REQUIRED from the IoCompletion routine, so the driver can finish processing the system query IRP in the callback routine.

After the IRP has been completed and all IoCompletion routines set during IRP processing have been run, the Power Manager, through the I/O Manager, calls the power policy manager's callback routine. The callback routine, in turn, must do the following:

  1. Call PoStartNextPowerIrp to start the next power IRP.
  2. Complete the system query-power IRP (IoCompleteRequest) with the status returned for the device query-power IRP.
  3. Call IoReleaseRemoveLock to free the previously acquired lock.
  4. Return the status with which the query IRPs completed.

Remember that the device power policy owner not only sends the device query but also must handle it on its way down the device stack. See Handling IRP_MN_QUERY_POWER for Device Power States for details.


Handling a System Query-Power IRP in a Bus Driver

When the system query IRP reaches the bus driver, the bus driver ensures that it can support a device state that corresponds to the queried system state and, if wake-up is enabled, that the queried system state would not prevent its device from waking the system.

The bus driver calls PoStartNextPowerIrp, and it sets Irp->IoStatus.Status to STATUS_SUCCESS if it can change to the specified power state or sets a failure status if it cannot. It then calls IoCompleteRequest, specifying IO_NO_INCREMENT.

After the bus driver completes the IRP, the Power Manager calls IoCompletion routines set by other drivers as they passed the IRP down the stack.


Handling a System Query-Power IRP in a Filter Driver

All filter drivers and any function driver that does not own power policy for its device stack should pass a system query-power IRP to the next lower driver, in the following steps:

  1. Call IoAcquireRemoveLock, passing the current IRP, to ensure that the driver does not receive a PnP IRP_MN_REMOVE_DEVICE request while handling the power IRP.

    If IoAcquireRemoveLock returns a failure status, the driver should not continue processing the IRP. Instead, it should call PoStartNextPowerIrp, then complete the IRP (IoCompleteRequest), and return the failure status.

  2. Determine whether it should fail the query. For guidelines, see Failing a System Query Power IRP and complete processing as described in that section.
  3. Call PoStartNextPowerIrp.
  4. Set the IRP stack location (IoSkipCurrentIrpStackLocation or IoCopyCurrentIrpStackLocationToNext). The driver can set an IoCompletion routine in the IRP, but doing so is rarely necessary.
  5. Pass the IRP to the next lower driver (PoCallDriver).
  6. Call IoReleaseRemoveLock. However, if the driver set an IoCompletion routine for the IRP, make this call from the IoCompletion routine instead.
  7. Return STATUS_PENDING from its DispatchPower routine.


Handling IRP_MN_SET_POWER for System Power States

The Power Manager sends a power IRP that specifies the minor code IRP_MN_SET_POWER and a system power state for one of the following reasons:

  • To change the system power state.
  • To reaffirm the current power state after a failed IRP_MN_QUERY_POWER request.

Through the I/O Manager, the Power Manager sends the IRP to the top driver in the device stack at each PnP device node. The IRP notifies all drivers in the stack of the correct system power state.

To ensure an orderly start-up, the Power Manager sequences system power-up IRPs so that parent devices have the opportunity to power up before their children do. The Power Manager does not query before sending a system power-up IRP.

Similarly, to ensure that the computer sleeps or shuts down in an orderly way, the Power Manager sends system IRPs that specify sleep, hibernation, or shutdown in a defined sequence, so that devices farther from the root power down before devices nearer the root. Whenever possible, the Power Manager queries before sending such an IRP. For more information, see Handling IRP_MN_QUERY_POWER for System Power States.

The system power IRP is not a direct request to change power state — it is a notification. A driver must not change the power state of its device as a direct response to the system power IRP; a driver changes its device's power state only in response to a device power IRP. (The device power policy owner sends the device power IRP; see Handling a System Set-Power IRP in a Device Power Policy Owner.)

Even if the device is already in a device power state that is valid for the requested system power state, each driver must nevertheless pass the system set-power IRP to the next lower driver, until it reaches the bus driver. Only the bus driver is allowed to complete this IRP.

How a driver handles this IRP depends upon its role in the device stack, as described in the following sections:

Handling a System Set-Power IRP in a Device Power Policy Owner

Handling a System Set-Power IRP in a Bus Driver

Handling a System Set-Power IRP in a Filter Driver

A driver cannot fail an IRP_MN_SET_POWER request. The Power Manager ignores any failure status returned for this IRP.


Handling a System Set-Power IRP in a Device Power Policy Owner

The device power policy owner in each device stack is responsible for putting its device stack into an appropriate device power state for the system power state specified in each system set-power IRP.

When a device power policy owner receives an IRP_MN_SET_POWER for a system power state, it responds by passing down the IRP and, in an IoCompletion routine, sending an IRP_MN_SET_POWER for a corresponding device power state. When all drivers in the stack have completed the device IRP, the device power policy owner completes the system IRP.

See the following for details:

Determining the Correct Device Power State

Sending a Device Set-Power IRP in Response to a System Set-Power IRP


Determining the Correct Device Power State

The power policy owner inspects the DeviceState array in the DEVICE_CAPABILITIES structure to determine the valid range of device power states for each system state. The array lists the highest-powered state the underlying device can support for each system state.

When choosing a specific state from this range, consider the following:

  • Most devices enter the D0 state when the system enters the S0 state.
  • Most devices enter the D3 state when the system enters any sleeping state. However, a device that is enabled for wake-up might be required to enter D1 or D2 instead, if it supports such states. See Reporting Device Power Capabilities for more information.
  • Special rules apply for the device that will hold the hibernation file. If the system IRP requests PowerSystemHibernate, the device that will hold the hibernation file must not power off. The power policy owner for such a device should request device state D3 and save context, but the device's drivers must not power off the device.

If the system IRP requests PowerSystemShutdown, the driver should check the POWER_ACTION value at Irp->Parameters.Power.ShutdownType to determine the reason for the state change. See System Power Actions for more information.

The device power policy owner must send a device set-power IRP for each system set-power IRP, even if the device is already in the correct device state. If the driver previously suspended device operations in response to a query-power IRP, the set-power IRP notifies it to stop queuing IRPs and return to normal operation for its current power state. The only exception occurs when the device is in the D3 state; in this case, the driver need not send an additional IRP_MN_SET_POWER request for D3.


Sending a Device Set-Power IRP in Response to a System Set-Power IRP

The device power policy owner should take the following steps to respond to a system set-power IRP:

  1. Call IoAcquireRemoveLock, passing the current IRP, to ensure that the driver does not receive a PnP IRP_MN_REMOVE_DEVICE request while handling the power IRP.

    If IoAcquireRemoveLock returns a failure status, the driver should not continue processing the IRP. Instead, it should call PoStartNextPowerIrp, then complete the IRP (IoCompleteRequest), and return the failure status.

  2. Set up the IRP stack location for the next lower driver by calling IoCopyCurrentIrpStackLocationToNext.
  3. Set an IoCompletion routine in the system set-power IRP.
  4. Call IoMarkIrpPending.
  5. Call PoCallDriver to pass the IRP to the next lower driver.
  6. Return STATUS_PENDING from its DispatchPower routine.

In the IoCompletion routine, the driver sends a device set-power IRP as follows:

  1. Inspect the IRP to get the requested system power state. Choose an appropriate device power state for that system state. See Determining the Correct Device Power State for details.
  2. Call PoRequestPowerIrp to send an IRP_MN_SET_POWER for the device power state determined in Step 1. The power policy owner must send the device set-power request even if the device is already in that state.
  3. Specify a callback routine (CompletionFunction) in the call to PoRequestPowerIrp and pass the system IRP in the Context area.
  4. Return STATUS_MORE_PROCESSING_REQUIRED from the IoCompletion routine, so that the driver can finish processing the system set-power IRP in the callback routine.

Remember that the device power policy owner not only sends the device set-power IRP but also must handle it as it travels through the device stack. Consequently, a device power policy owner might have not only a callback routine associated with the device set-power IRP and an IoCompletion routine for the system set-power IRP, but also an IoCompletion routine for the device set-power IRP. See Handling IRP_MN_SET_POWER for Device Power States for details.

After the I/O Manager calls all the IoCompletion routines set as the device set-power IRP traveled down the device stack, the I/O Manager calls the callback routine. By this time, all drivers in the stack have completed the device set-power IRP and the device power transition is complete.

The callback routine must do the following:

  1. Call PoStartNextPowerIrp to start the next power IRP.
  2. Complete the system set-power IRP (IoCompleteRequest) with the status returned for the device set-power IRP.
  3. Call IoReleaseRemoveLock to free the previously acquired lock.
  4. Return the status with which the set-power IRPs completed.


Handling a System Set-Power IRP in a Bus Driver

When a bus driver receives a system set-power IRP, it must take the following steps:

  1. Call PoStartNextPowerIrp to start the next power IRP.
  2. Set Irp->IoStatus.Status to STATUS_SUCCESS. The driver cannot fail a system set-power IRP.
  3. Call IoCompleteRequest, specifying IO_NO_INCREMENT, to complete the IRP.

The bus driver does not change device power settings until it receives a power IRP that requests a device power state.


Handling a System Set-Power IRP in a Filter Driver

All filter drivers and any function driver that does not own power policy for its device stack should simply pass the system set-power IRP to the next lower driver, in the following steps:

  1. Call IoAcquireRemoveLock, passing the current IRP, to ensure that the driver does not receive a PnP IRP_MN_REMOVE_DEVICE request while handling the power IRP.

    If IoAcquireRemoveLock returns a failure status, the driver should not continue processing the IRP. Instead, it should call PoStartNextPowerIrp, then complete the IRP (IoCompleteRequest), and return the failure status.

  2. Call PoStartNextPowerIrp.
  3. Set the IRP stack location (IoSkipCurrentIrpStackLocation or IoCopyCurrentIrpStackLocationToNext). The driver can set an IoCompletion routine in the IRP, but doing so is rarely necessary.
  4. Pass the IRP to the next lower driver (PoCallDriver).
  5. Call IoReleaseRemoveLock. However, if the driver set an IoCompletion routine for the IRP, make this call from the IoCompletion routine instead.
  6. Return STATUS_PENDING from its DispatchPower routine.


Supporting Devices that Have Wake-Up Capabilities

Drivers for devices that can respond to external wake signals must be able to handle IRP_MN_WAIT_WAKE requests (wait/wake IRPs). The power policy owner for such a device must be able to send an IRP_MN_WAIT_WAKE request.

Typically, whatever causes the device to assert the wake signal is also a normal service event for the device. For example, user input, which might cause a keyboard to wake up the system, is a normal event for the keyboard and its drivers.

The first topic of this section, Overview of Wait/Wake Operation, contains information useful in writing any driver. The following additional topics provide detailed information on handling and sending wait/wake IRPs:

Receiving a Wait/Wake IRP

Sending a Wait/Wake IRP

Canceling a Wait/Wake IRP


Overview of Wait/Wake Operation

In essence, the operating system's wake-up mechanism works as shown in the following figure:

Overview of IRP_MN_WAIT_WAKE Processing

  1. While the system and device are in the working state, the power policy owner for a device determines that its device should be enabled ("armed") for wake-up. The power policy owner requests a power IRP (PoRequestPowerIrp with minor code IRP_MN_WAIT_WAKE) to be sent to its PDO to inform all drivers in its device stack. In the request, the policy owner specifies a callback routine (not the same as an IoCompletion routine).
  2. The Power Manager, through the I/O Manager, sends the IRP to the top of the device stack.
  3. Drivers set IoCompletion routines and pass the IRP down until it reaches the bus driver.
  4. The bus driver enables wake-up on the physical device, if it can, and marks the IRP pending. If necessary, it also requests a wait/wake IRP for its parent.
  5. Sometime later, an external wake-up signal arrives.
  6. The bus driver completes the IRP_MN_WAIT_WAKE.
  7. I/O Manager calls IoCompletion routines that were set as drivers passed the IRP down the stack.
  8. I/O Manager calls the callback routine set by the policy owner when it requested the IRP.

The IRP_MN_WAIT_WAKE request does not change the power state of the device or the system. It merely enables wake-up on the device so that later, if the device enters an appropriate sleep state, an external signal will cause the device (and possibly the system) to awaken.

When a wake-up signal arrives, the drivers' behavior is the same whether the device wakes the system or only itself. If the device is enabled for wake-up and the system is in a sleep state from which the device can awaken it, the device will awaken the system. If the device is enabled for wake-up and the system is in the working state, only the device will awaken.

Because computers and devices vary in design, particularly with respect to power planes, the supported system and device power states — and thus the states that can support wait/wake — are not the same on all hardware configurations. Therefore, any driver that owns power policy for its device — and every bus driver — must pay careful attention to the capabilities of the individual configuration on which it is running. See Determining Whether a Device Can Wake the System for more information.

For further details on wait/wake operations, see Understanding the Path of Wait/Wake IRPs through a Device Tree and Overview of Wait/Wake IRP Completion.


Determining Whether a Device Can Wake the System

Some devices, such as keyboards, modems, and network cards, can respond to external signals while in a device sleep state. As part of its power management technology, the operating system provides a way for such devices to wake a sleeping system, which can then restore its previous context. The software wake-up mechanism allows a system to awaken from any state except S5 (PowerSystemShutdown), depending on support in the system and device hardware and BIOS. A system in state S5 must always be rebooted.

Although the operating system is designed to awaken from any of the intermediate sleep states, the exact wake-up capabilities vary from computer to computer and device to device. Not all computers support all system sleep states; therefore, the ability to wake from certain states is meaningless on some computers.

Similarly, most devices neither support all device states (D0 through D3) nor support wake-up from all the device states that they do support.

The sleep states that a device can enter, along with the states from which it supports wake up, are described at enumeration by the bus driver and are stored in the DEVICE_CAPABILITIES structure. The following table lists the members of this structure that are relevant to wait/wake support.

Member | Description
DeviceD1 | True if device supports state PowerDeviceD1.
DeviceD2 | True if device supports state PowerDeviceD2.
WakeFromD0 | True if device can wake from PowerDeviceD0.
WakeFromD1 | True if device can wake from PowerDeviceD1.
WakeFromD2 | True if device can wake from PowerDeviceD2.
WakeFromD3 | True if device can wake from PowerDeviceD3.
DeviceState [PowerSystemMaximum] | Specifies highest-powered device state that this device can support for each system state, from PowerSystemUnspecified to PowerSystemShutdown.
SystemWake | Specifies lowest-powered state (S0 through S4) from which the system can be awakened.
DeviceWake | Specifies lowest-powered state (D0 through D3) from which the device can awaken.

The DeviceWake entry lists the lowest-powered device state from which the device can respond to a wake-up signal. The value PowerDeviceUnspecified indicates that the device cannot wake the system. The SystemWake entry lists the lowest-powered state from which the system can be awakened. These values are based on the capabilities of the parent devnode and drivers should not change them. See Reporting Device Power Capabilities for more information.

In general, a device can wake the system if the following are true:

  • The device is in a power state equal to or more-powered than the DeviceWake value.
  • The system is in a power state equal to or more powered than the SystemWake value.


Understanding the Path of Wait/Wake IRPs through a Device Tree

Within a single device stack, the power policy owner sends a wait/wake IRP and all drivers handle the wait/wake IRP, as outlined in Overview of Wait/Wake Operation and detailed in Sending a Wait/Wake IRP and Receiving a Wait/Wake IRP, respectively.

Within a branch of the device tree (which comprises a leaf devnode and the devnodes of its parents, grandparents, and so forth), drivers must cooperate to ensure that a wait/wake IRP reaches a driver that can enable all the necessary hardware for wake-up.

On ACPI computers, ACPI is responsible for enabling the system-specific General Purpose Event (GPE) register associated with the wake-up signal from each leaf device. Consequently, drivers must request and forward wait/wake IRPs until one reaches either an ACPI filter driver (inserted in the device stack at start-up) or the underlying ACPI driver. In response, ACPI enables the register, holds the IRP pending until the signal arrives, and then completes the IRP. Because ACPI can respond to the wake-up signal, it does not forward the IRP to a lower driver.

ACPI filter drivers, like the underlying ACPI driver itself, are transparent to other drivers. To provide maximum flexibility in hardware design, the exact position of an ACPI filter driver in any device stack is device- and system-specific. In designing a driver, you cannot make any assumptions about the presence or position of an ACPI filter in the device stack.

Keep in mind that drivers that enumerate children create a PDO for each child device and an FDO for the parent device. The driver thus acts as the bus driver for a child device and the function driver/policy owner for a parent device. Therefore, whenever a bus driver receives a wait/wake IRP for a child PDO, it should request another wait/wake IRP for its parent PDO.

The following figure shows a sample configuration in which such a situation occurs.

Sample USB Configuration

In the sample configuration, the keyboard and modem are children of the USB hub, which in turn is a child of the USB host controller, which is enumerated by the PCI bus. The following figure shows the device stacks for the keyboard in the sample configuration.

Device Stacks for Sample USB Keyboard Configuration

As the previous figure shows, reading from the bottom up:

  1. The ACPI driver creates the PDO for PCI.
  2. The PCI driver creates the PCI FDO and the USB host controller PDO and owns policy for the PCI device stack.
  3. The USB host controller driver (a host controller/bus driver pair) creates the USB Host Controller FDO and the USB Hub PDO. It owns policy for the USB host controller device stack. Note that the ACPI driver creates a filter DO in this stack as well.
  4. The USB hub driver creates the USB Hub FDO and the keyboard PDO. This driver owns power policy for the USB hub device stack.
  5. The function driver for the keyboard is the USB HID class driver/minidriver pair. This driver creates the FDO for the keyboard and owns its power policy. Because the keyboard has no child devices, this driver creates no PDOs.

Note that each device stack might include additional optional filter DOs that are not shown.

To allow keyboard input to awaken the system, the policy owner for the keyboard requests an IRP_MN_WAIT_WAKE for its PDO. That IRP sets off a chain of other wait/wake IRPs, as shown in the following figure:

Wait/Wake IRP Requests for Sample USB Configuration

When a bus driver receives an IRP_MN_WAIT_WAKE targeted to a PDO it created, it must request another IRP_MN_WAIT_WAKE for the device stack for which it owns power policy and created an FDO.

As the previous figure shows:

  1. The keyboard driver calls PoRequestPowerIrp to send a wait/wake IRP (IRP1) to its PDO.

    The Power Manager allocates the IRP and sends it through the I/O Manager to the top of the device stack for the keyboard. Drivers set IoCompletion routines and pass the IRP down the stack until it reaches the keyboard PDO. The USB hub driver, which acts as the bus driver for the keyboard, holds IRP1 pending.

  2. Because the USB hub driver cannot wake the system when the wake-up signal arrives, the USB hub driver must call PoRequestPowerIrp to request a wait/wake IRP (IRP2) for the USB hub device stack.

    The Power Manager sends this IRP to the top of the USB hub device stack. The drivers in this stack set IoCompletion routines and pass the IRP down to the USB host controller driver (which acts as the bus driver for the USB hub). The USB host controller driver holds IRP2 pending until the keyboard signals a wake event.

  3. Similarly, the USB host controller driver cannot wake the system, so the USB host controller driver calls PoRequestPowerIrp to send a wait/wake IRP (IRP3) to the USB host controller device stack.

    The Power Manager sends this IRP to the top of the USB host controller device stack, where drivers set IoCompletion routines and pass the IRP down to the PCI driver (which acts as the bus driver for the USB hub). The PCI driver holds IRP3 pending until the keyboard signals a wake event.

  4. The PCI driver cannot wake the system, so the PCI driver calls PoRequestPowerIrp to send a wait/wake IRP (IRP4) to the PCI device stack. Its parent is the root device, for which ACPI is the bus driver.

    The Power Manager sends the IRP to the top of the PCI bus device stack; its drivers set completion routines and pass the IRP down to the ACPI driver.

  5. The ACPI driver can wake the system, so it does not send a wait/wake IRP to any other PDO. The ACPI driver holds IRP4 pending until a wake signal arrives.

When the keyboard asserts the wake-up signal, the ACPI driver intercepts it. ACPI, however, cannot determine that the keyboard asserted the signal, only that the signal came through the root device. The ACPI driver then completes IRP4, and the I/O Manager calls IoCompletion routines traveling back up the PCI device stack. When IRP4 is complete and all IoCompletion routines have run, the PCI driver's callback routine is invoked. In its callback routine, the PCI driver determines that the signal came through the USB host controller. The PCI driver then completes IRP3. The same sequence occurs through the USB host controller stack and the USB hub stack, until the keyboard driver receives IRP1. At that point, the keyboard driver can service the wake-up event as necessary.

Each time a driver sends a wait/wake IRP to a parent PDO, it must set a Cancel routine for its own IRP. Setting a Cancel routine gives the driver an opportunity to cancel the new IRP if the IRP that triggered it is canceled. In the USB example, if the keyboard driver cancels its wait/wake IRP (thus disabling keyboard wake-up), the USB hub, USB host controller, and PCI drivers must cancel the IRPs that they sent as a consequence of the keyboard IRP. See Cancel Routines for Wait/Wake IRPs for details.

Although a parent driver might enumerate more than one child that can be enabled for wait/wake, only one wait/wake IRP can be pending for a PDO. In such cases, the parent driver should make sure that it keeps a wait/wake IRP pending whenever any of its devices is enabled for wake-up. To do so, the driver should increment an internal counter each time it receives a wait/wake IRP. Each time the driver completes a wait/wake IRP, it decrements the count and, if the resulting value is nonzero, sends another wait/wake IRP to its device stack.

For example, in the USB configuration shown previously in the Sample USB Configuration figure, the USB hub enumerates two devices, a keyboard and a modem. When the USB hub driver receives a wait/wake IRP for the keyboard PDO, it increments a count of wait/wake IRPs before requesting an IRP for its own PDO. If the modem's policy owner later enables wake-up for the modem, the USB hub driver pends the new IRP for the modem PDO, but it does not request a new IRP for its own PDO. Because its PDO cannot have two pending wait/wake IRPs simultaneously, the USB hub driver increments its wait/wake reference count and fails the new IRP.

When a wake-up signal arrives from either the keyboard or modem, the USB hub driver determines which device signaled, completes the corresponding IRP, and decrements its reference count. Because both devices were enabled for wake-up (and thus its reference count is nonzero), it must send its own device stack another wait/wake IRP to "rearm" its own PDO for wake-up. (The same is true of the USB host controller and PCI driver.)

A driver does not, however, send itself an IRP to reenable wait/wake on the same device on which a wake-up signal just arrived. Only the device power policy manager can do that. Re-enabling wait/wake is not automatic.


Overview of Wait/Wake IRP Completion

A wait/wake IRP completes when a wake-up signal arrives. The wake-up signal is device-specific but is generally a normal service event for the device. For example, an incoming ring might cause a sleeping modem to awaken.

The following figure shows the steps in completing a wait/wake IRP.

Steps for Completing a Wait/Wake IRP

When the signal occurs, control reenters the bus driver at the point where the bus detects that the device has awakened. The bus driver services the event as required and calls IoCompleteRequest to complete the IRP_MN_WAIT_WAKE IRP for its PDO.

The I/O Manager then calls the IoCompletion routine set by the next higher driver in the device stack. In the IoCompletion routine, that driver services the wake-up signal as necessary and calls IoCompleteRequest to complete the IRP. The I/O Manager continues to call IoCompletion routines working back up the device stack until all drivers have completed the IRP.

In its IoCompletion routine, any driver that enumerates more than one child device (creates more than one PDO) and has received wait/wake requests from more than one such device must send itself a wait/wake IRP to rearm itself for wait/wake on another child. For details, see Understanding the Path of Wait/Wake IRPs Through a Device Tree.

After calling IoCompletion routines set by drivers as they passed the IRP down the stack, the I/O Manager invokes the callback routine set by the power policy owner when it requested the wait/wake IRP. In the callback routine, the policy owner should return its device to the working state and complete a pending wait/wake IRP for its child's PDO, if any.

Completing the child's IRP causes the I/O Manager to call IoCompletion routines set by drivers in the child's device stack, and so on. Eventually, the policy owner that started the original wait/wake IRP on the devnode determines that its device asserted the wake-up signal, and all the pending wait/wake IRPs will be complete.


Receiving a Wait/Wake IRP

All PnP drivers must be prepared to receive power IRPs with minor IRP code IRP_MN_WAIT_WAKE. How a driver handles a wait/wake IRP depends on its position in the device stack, the type of device(s) it controls, and the specific states from which its device supports wake-up.

The following sections provide guidelines for handling this IRP based on the type of driver and its level of wait/wake support.


Handling a Wait/Wake IRP in a Function (FDO) or Filter Driver (Filter DO)

When a driver that creates an FDO or filter DO receives an IRP_MN_WAIT_WAKE request for the associated PDO, it can either simply pass the IRP down to the next lower driver or take certain actions before passing down the IRP.

For Devices That Support Wake-up

Upon receiving a wait/wake IRP, a function or filter driver should take the following steps:

  1. Call IoAcquireRemoveLock, passing the current IRP, to ensure that the driver does not receive a PnP IRP_MN_REMOVE_DEVICE request while handling the wait/wake IRP.

    If IoAcquireRemoveLock returns a failure status, the driver should not continue processing the IRP. Instead, it complete the IRP (IoCompleteRequest), and return the failure status.

  2. Inspect the value at Irp->Parameters.WaitWake.SystemWake and compare the current device power state with DeviceState[SystemWake] in the DEVICE_CAPABILITIES structure.

    If the device supports wake-up, but not from the specified SystemWake state or not from the current device power state, the driver should fail the IRP as follows:

    • Set STATUS_INVALID_DEVICE_STATE in Irp->IoStatus.Status.
    • Complete the IRP (IoCompleteRequest), specifying a priority boost of IO_NO_INCREMENT.
    • Return the status set in Irp->IoStatus.Status from the DispatchPower routine.
  3. Otherwise, set an IoCompletion routine for the IRP, using IoSetCompletionRoutine. The IoCompletion routine should perform whatever tasks the driver requires to return the device to the working state.

    The IoCompletion routine will also be called if the IRP is canceled.

  4. Save any information the driver might need in its IoCompletion routine.
  6. Call PoCallDriver to pass the wait/wake IRP to the next lower driver.
  7. Call IoReleaseRemoveLock to release the previously acquired lock.
  8. Return STATUS_PENDING from the DispatchPower routine. The driver must not change the value in Irp->IoStatus.Status while it holds the IRP.

For Devices That Do Not Support Wake-up

If a function or filter driver receives a wait/wake IRP for a device that does not support wake-up, the driver should fail the IRP as follows:

  2. Complete the IRP (IoCompleteRequest), specifying a priority boost of IO_NO_INCREMENT.
  3. Return the status set in Irp->IoStatus.Status from the DispatchPower routine.


Handling a Wait/Wake IRP in a Bus Driver (PDO)

Like other power IRPs, each wait/wake IRP must be passed all the way down the device stack to the bus driver (PDO), which is ultimately responsible for completing the IRP. Upon receiving the IRP, the bus driver can either fail it immediately or hold it pending for later completion. The following are the steps the bus driver must take:

  1. Inspect the value at Irp->Parameters.WaitWake.SystemWake. If the device supports wake-up, but not from the specified SystemWake state or not from the current device power state, the driver should fail the IRP as follows:
    • Set STATUS_INVALID_DEVICE_STATE in Irp->IoStatus.Status.
    • Complete the IRP (IoCompleteRequest), specifying a priority boost of IO_NO_INCREMENT.
    • Return the status set in Irp->IoStatus.Status from the DispatchPower routine.
  2. Check whether a wait/wake IRP is already pending for the PDO. If so, set Irp->IoStatus.Status to STATUS_DEVICE_BUSY, increment the driver's internal count of wait/wake IRPs, and complete the IRP as described in the previous step.

    Only one wait/wake IRP can be pending for a PDO.

  3. If the device supports wake-up from the specified system state and no wait/wake IRP is already pending, call IoMarkIrpPending to indicate to the I/O Manager that the IRP will be completed or canceled later. Do not set an IoCompletion routine.
  4. Set the device hardware to enable wake-up.

    The specific mechanism by which a bus driver enables its hardware for wake-up is device-dependent. For a PCI device, pci.sys is responsible for setting the PME-enable bit because this driver owns the PME register. For other devices, refer to the device-class-specific documentation.

  5. If the PDO is the child of an FDO, request a wait/wake IRP for the FDO, making sure to set a Cancel routine for the current IRP (the IRP that it holds pending). Do not attempt to pass on or reuse the current IRP.
  6. Return STATUS_PENDING from the DispatchPower routine.
  7. When a wake-up signal arrives, call IoCompleteRequest to complete the pending wait/wake IRP, setting Irp-IoStatus.Status to STATUS_SUCCESS, and specifying a priority boost of IO_NO_INCREMENT.

For Devices That Do Not Support Wake-up

If the device does not support wake-up, the bus driver (PDO) should proceed as follows:

  2. Complete the wait/wake IRP by calling IoCompleteRequest, specifying IO_NO_INCREMENT.
  3. Return from the DispatchPower routine, passing the value at Irp->IoStatus.Status as its return value.


IoCompletion Routines for Wait/Wake IRPs

The I/O Manager calls a driver's wait/wake IoCompletion routine after the next lower driver in the device stack has completed the wait/wake IRP. Each function and filter (FDO) driver that handles a wait/wake IRP should set an IoCompletion routine for the IRP.

Each function or filter driver sets an IoCompletion routine as it handles the wait/wake IRP on its way down the device stack. The device power policy owner, which sends the IRP, might therefore have an IoCompletion routine in addition to a callback routine. Keep in mind that the callback routine is invoked after the IoCompletion routine and that the two have different requirements. See Wait/Wake Callback Routines for more information.

The actions required in a wait/wake IoCompletion routine depend on the device and the type of driver. The following are some actions a driver might need to perform in its wait/wake IoCompletion routine:

  1. Reset any relevant fields in the device extension. For example, when a wait/wake IRP is pending, most drivers set a flag and keep a pointer to the IRP in the device extension.
  2. Reset the Cancel routine, if any, for the IRP by calling IoSetCancelRoutine, specifying a NULL pointer for the routine.
  4. Call IoCompleteRequest, specifying IO_NO_INCREMENT, to complete the IRP.

As each successive driver completes the IRP, the I/O Manager passes control to the IoCompletion routine of the next higher driver going back up the stack.

After calling the IoCompletion routines set by drivers as they passed the wait/wake IRP down the device stack, the I/O Manager calls the callback routine passed to PoRequestPowerIrp by the driver that sent the IRP. See Wait/Wake Callback Routines for details.


Sending a Wait/Wake IRP

The minor power IRP code IRP_MN_WAIT_WAKE provides for waking a device or waking the system. Drivers of devices that can wake themselves or the system send IRP_MN_WAIT_WAKE requests. The system sends IRP_MN_WAIT_WAKE requests only to devices that always wake the system, such as the power-on switch.

A driver sends an IRP_MN_WAIT_WAKE request for one of two reasons:

  1. Its device must be able to return to the working state from a sleep state in response to an external wake-up signal.

    For example, a modem's driver might send it a wait/wake IRP before setting it in power state D1 to conserve energy. The wait/wake IRP enables the modem to respond to an incoming call.

  2. Its device must be able to wake the system in response to a wake-up signal.

    When the system goes to sleep, the modem might remain in state D1 with an IRP_MN_WAIT_WAKE pending. In this case, an incoming call would wake the system as well as the modem.

Whether a device is prepared to wake itself or the system, the actions its drivers must take are the same. The primary difference lies in how the device and system hardware respond to the initial wake-up signal. Driver behavior is the same in either case.


Determining When to Send a Wait/Wake IRP

The driver that owns device power policy sends wait/wake IRPs on behalf of its device. Such a driver must send a wait/wake IRP when one of the following occurs:

  • The driver is putting the device to sleep but the device must be able to awaken in response to an external wake-up signal.
  • The system is going to sleep and the device must be able to awaken it.

The power policy owner should send the wait/wake IRP before any such conditions are imminent. It can send the IRP any time its device is in D0, but it must not send such an IRP while it is handling another set-power or query-power IRP. As a general rule, the driver should send the IRP during its handling of the PnP Manager's IRP_MN_START_DEVICE request, after it has initialized and started the device.


Wait/Wake IRP Requests

To send an IRP_MN_WAIT_WAKE, a driver calls PoRequestPowerIrp, passing (among other parameters) a pointer to the target PDO, a system power state, and a pointer to a callback routine.

The system power state specifies the least-powered state from which this IRP can wake the system. The value must be equal to or more powered than the SystemWake state in the DEVICE_CAPABILITIES structure. For example, if a driver passes PowerSystemSleeping2 in the IRP, the associated IRP could cause the system to wake from states S0, S1, and S2. In such a case, the system must support S0 and S2 (the highest- and lowest-powered states in the range) but need not support S1.

Every driver that requests a wait/wake IRP should specify a callback routine, which is invoked after all other drivers have completed the IRP. In this routine, the driver can do whatever is necessary to return its device to the working state.

In response to PoRequestPowerIrp, the Power Manager allocates a power IRP with minor code IRP_MN_WAIT_WAKE and sends it to the top of the device stack for the target PDO. The caller is returned a pointer to the allocated IRP, which it can use later if it has to cancel the IRP.

If no errors occur, PoRequestPowerIrp returns STATUS_PENDING. This status means that the IRP has been sent successfully and is pending completion.

A wait/wake IRP does not change the power state of the system or of a device. It simply enables a device's wake-up signal. The IRP remains pending until an external signal causes the system or device to awaken.


Wait/Wake Callback Routines

When a driver requests a wait/wake IRP, it must specify a callback routine so that it can return the device to the working state (D0) when the wake-up event occurs. After the wake-up event occurs and all drivers have completed the IRP, the system calls the callback routine passed to PoRequestPowerIrp.

Because this callback routine is set on behalf of the driver that originated the IRP — and not for a driver that is handling the IRP — it must not call PoStartNextPowerIrp; only the IoCompletion routines set as drivers pass the IRP down the stack should start the next power IRP. Keep in mind that the policy owner not only sends the IRP but handles it, and it therefore might set an IoCompletion routine as it passes the IRP down the stack in addition to setting a callback routine when it requests the wait/wake IRP.

The callback routine has the following responsibilities:

  1. If the driver controls more than one device, determine which of its devices signaled the wake-up.
  2. Service the event that caused the wake-up signal.
  3. Set the device that signaled the wake-up in the D0 state by calling PoRequestPowerIrp to send a PowerDeviceD0 request. The driver must also call PoSetPowerState to inform the Power Manager of the new device state. For more information, see Sending IRP_MN_QUERY_POWER or IRP_MN_SET_POWER for Device Power States.
  4. If the driver set a Cancel routine for the IRP, call IoSetCancelRoutine to reset the Cancel routine to NULL.
  5. If the driver owns power policy for more than one device, decrement its wait/wake reference count. If the count is nonzero, indicating that another device had previously sent a wait/wake IRP, request another wait/wake IRP (PoRequestPowerIrp) for its PDO.

    For example, a PCI device might have wait/wake enabled for both a modem and a Network Interface Card (NIC). If the NIC wakes the system (thus completing the IRP), the PCI FDO must send another wait/wake IRP to itself so that the modem will still be able to wake up.

Because the driver that requested the wait/wake IRP controls power policy for its device stack, it is responsible for returning its device to the working state when the IRP completes. Although lower drivers might already have physically applied power to the device, the policy owner must call PoRequestPowerIrp to send an IRP_MN_SET_POWER request for device state D0. Only after all drivers in the device stack have handled this power-up IRP will the device be returned to the working state.


Canceling a Wait/Wake IRP

Only the driver that sent a wait/wake IRP can cancel that IRP.

A driver might need to cancel a pending wait/wake IRP under the following circumstances:

  • The driver receives a PnP IRP_MN_STOP_DEVICE, IRP_MN_QUERY_REMOVE_DEVICE, IRP_MN_REMOVE_DEVICE, or IRP_MN_SURPRISE_REMOVAL request for the device. The driver should re-issue the wait/wake IRP (PoRequestPowerIrp) after the device is restarted.
  • The system is going to sleep, but the device should not be enabled to wake the system.

    For example, the USB hub driver might send an IRP_MN_WAIT_WAKE request at device start-up in case it later puts one of its input devices into a sleep state. While the system is in the working state, a wake signal from the device returns the device to the working state (but has no effect on the system power state). When the system prepares to shut down, the USB hub driver cancels this IRP if the device should not be allowed to awaken the system.

  • The system is entering a sleep state from which the device cannot awaken it. That is, it is entering a state less powered than the SystemWake value specified in its DEVICE_CAPABILITIES structure.
  • The device is entering a power state from which it cannot respond to a wake-up signal. That is, it is entering a state less-powered than the DeviceWake value specified in its DEVICE_CAPABILITIES structure.

To cancel a wait/wake IRP, the driver that sent the IRP calls IoCancelIrp, passing the pointer to the IRP that was previously returned when the driver called PoRequestPowerIrp.

A driver must not cancel a wait/wake IRP that it did not send.

Cancel Routines for Wait/Wake IRPs

Many function and bus drivers should set Cancel routines for pending wait/wake IRPs; the following types of drivers must set such routines:

  • Drivers that change device settings to enable or disable wake-up.
  • Drivers that send IRP_MN_WAIT_WAKE requests to drivers of parent devices.

A Cancel routine allows a driver to disable wake-up for its device and to clean up any data related to the pending wait/wake IRP. Drivers that request wait/wake IRPs for parent devices can cancel those IRPs as well.

In its wait/wake Cancel routine, a driver should take the following steps:

  1. Call IoSetCancelRoutine to reset the Cancel routine for the IRP to NULL.
  2. Call IoReleaseCancelSpinLock, passing the CancelIRQL specified in the IRP to release the cancel spin lock for the IRP.
  3. Reset any relevant fields in the device extension. For example, when a wait/wake IRP is pending, most drivers set a flag and keep a pointer to the IRP in the device extension.

    Note that it is possible for a driver to receive a wait/wake IRP while it is canceling another such IRP. The driver must check to see whether it already has an IRP under spin lock protection (or its equivalent). If so, the driver must carefully synchronize its handling to ensure that it cancels the correct IRP. See Canceling IRPs for more information on using spin locks in Cancel routines.

  4. Change any required device settings. For example, a modem driver would disable the device's wake setting.
  5. Set Irp->IoStatus.Status to STATUS_CANCELLED.
  7. Call IoCompleteRequest to complete the wait/wake IRP, specifying IO_NO_INCREMENT.
  8. If the driver previously requested a related IRP_MN_WAIT_WAKE for a parent device, the driver should cancel that IRP from within its Cancel routine. The driver must release the cancel spin lock before it cancels the parent's IRP.

    For example, a driver that acts as a bus driver for a device and owns power policy driver for its parent should cancel a related wait/wake IRP that it earlier sent to its parent. Calling IoCancelIrp would invoke the parent's Cancel routine, and so on down the device stack.


Input/Output Techniques

This section describes common I/O techniques used in kernel-mode drivers. It contains the following sections:

Methods for Accessing Data Buffers

Adapter Objects and DMA

Controller Objects

Splitting Transfer Requests

Maintaining Cache Coherency

Polling a Device

Accessing Device Configuration Space


Methods for Accessing Data Buffers

One of the primary responsibilities of driver stacks is transferring data between user-mode applications and a system's devices. The operating system provides the following three methods for accessing data buffers:

Buffered I/O
The operating system creates a nonpaged system buffer, equal in size to the application's buffer. For write operations, the I/O Manager copies user data into the system buffer before calling the driver stack. For read operations, the I/O Manager copies data from the system buffer into the application's buffer after the driver stack completes the requested operation.

For more information, see Using Buffered I/O.

Direct I/O
The operating system locks the application's buffer in memory. It then creates a memory descriptor list (MDL) that identifies the locked memory pages, and passes the MDL to the driver stack. Drivers access the locked pages through the MDL.

For more information, see Using Direct I/O.

Neither Buffered Nor Direct I/O
The operating system passes the application buffer's virtual starting address and size to the driver stack. The buffer is only accessible from drivers that execute in the application's thread context.

For more information, see Using Neither Buffered Nor Direct I/O.

Drivers specify the buffer access method using the DO_BUFFERED_IO and DO_DIRECT_IO flags in a device's DEVICE_OBJECT structure. All drivers in a driver stack must specify the same buffer access method, except possibly for the highest-level driver (which can use the "neither" method, regardless of the method used by lower drivers).


Using Buffered I/O

A driver that services an interactive or slow device, or one that usually transfers relatively small amounts of data at a time, should use the buffered I/O transfer method. Using buffered I/O for small, interactive transfers improves overall physical memory usage, because the Memory Manager doesn't need to lock down a full physical page for each transfer, as it does for drivers that request direct I/O. Generally, video, keyboard, mouse, serial, and parallel drivers request buffered I/O.

The following figure illustrates how the I/O Manager sets up an I/O request for a transfer operation using buffered I/O.

Buffered I/O for User Buffers

The previous figure shows an overview of how drivers can use the SystemBuffer pointer in the IRP to transfer data for a read request, when a driver has ORed the device object's Flags with DO_BUFFERED_IO:

  1. Some range of user-space virtual addresses represents the current thread's buffer, and that buffer's contents might be stored somewhere within a range of page-based physical addresses (dark shading in the previous figure).
  2. The I/O Manager services the current thread's read request, for which the thread passes a range of user-space virtual addresses representing a buffer.
  3. The I/O Manager checks the user-supplied buffer for accessibility and calls ExAllocatePool to create a resident system-space buffer (SystemBuffer) the size of the user-supplied buffer.
  4. The I/O Manager provides access to the newly allocated SystemBuffer in the IRP it sends to the driver.

    If the figure showed a write request, the I/O Manager would copy data from the user buffer into the system buffer before it sent the IRP to the driver.

  5. For the read request shown in the previous figure, the driver reads data from the device into the system-space buffer. When the read request has been satisfied, the driver calls IoCompleteRequest with the IRP.
  6. When the original thread is again active, the I/O Manager copies the read-in data from the system buffer into the user buffer. It also calls ExFreePool to release the system buffer.

After the I/O Manager has created a system-space buffer for the driver, the requesting user-mode thread can be swapped out and its physical memory can be reused by another thread, possibly by a thread belonging to another process. However, the system-space virtual address range supplied in the IRP remains valid until the driver calls IoCompleteRequest with the IRP.

Drivers that transfer large amounts of data at a time, in particular, drivers that do multi-page transfers, should not attempt to use buffered I/O. As the system runs, nonpaged pool can become fragmented so that the I/O Manager cannot allocate large, contiguous system-space buffers to send in IRPs for such a driver.

Typically, a driver uses buffered I/O for some types of IRPs, such as IRP_MJ_DEVICE_CONTROL requests, even if it also uses direct I/O. Drivers that use direct I/O typically only do so for IRP_MJ_READ and IRP_MJ_WRITE requests, and possibly driver-defined IRP_MJ_INTERNAL_DEVICE_CONTROL requests that require large data transfers.


Using Direct I/O

Drivers for devices that can transfer large amounts of data at a time should use direct I/O for those transfers. Using direct I/O for large transfers improves a driver's performance, both by reducing its interrupt overhead and by eliminating the memory allocation and copying operations inherent in buffered I/O. Generally, mass-storage device drivers request direct I/O for transfer requests, including lowest-level drivers that use direct memory access (DMA) or programmed I/O (PIO), as well as any intermediate drivers chained above them.

Even drivers that request direct I/O use buffered I/O to satisfy certain IRPs. In particular, drivers typically use buffered I/O for some I/O control codes for IRP_MJ_DEVICE_CONTROL requests that require data transfers, whether or not the driver uses direct I/O for read and write operations.

Setting up a direct I/O transfers varies slightly, depending on whether DMA or PIO is being used. For more information, see:

Using Direct I/O with DMA

Using Direct I/O with PIO

Drivers must take steps to maintain cache coherency during DMA and PIO transfers. For more information, see Maintaining Cache Coherency.


Using Direct I/O with DMA

The following figure illustrates how the I/O Manager sets up an I/O request for a DMA transfer operation using direct I/O.

Direct I/O on User Buffers for Devices that Use DMA

The previous figure illustrates how drivers can use the IRP's MdlAddress to transfer data for a read request. The driver in the figure uses packet-based system or bus-master DMA, and has ORed the device object's Flags with DO_DIRECT_IO.

  1. Some range of user-space virtual addresses represents the current thread's buffer, and that buffer's contents might actually be stored on some number of physically discontiguous pages (dark shading in the previous figure). The I/O Manager creates an MDL to describe this buffer. An MDL is an opaque data structure, defined by the Memory Manager, that maps a particular virtual address range to one or more page-based physical address ranges.
  2. The I/O Manager services the current thread's read request, for which the thread passes a range of user-space virtual addresses that represent a buffer.
  3. The I/O Manager or FSD checks the user-supplied buffer for accessibility and calls MmProbeAndLockPages with the previously created MDL. MmProbeAndLockPages also fills in the corresponding physical address range in the MDL.

    As the previous figure shows, an MDL for a virtual range can have several corresponding page-based physical address entries, and the virtual range for a buffer might begin and end at some byte offset from the start of the first and last pages described by an MDL.

  4. The I/O Manager provides a pointer to the MDL (MdlAddress) in an IRP that requests a transfer operation. Until the I/O Manager or file system calls MmUnlockPages after the driver completes the IRP, the physical pages described in the MDL remain locked down and assigned to the buffer. However, the virtual addresses in such an MDL can become invisible (and invalid), even before the IRP is sent to the device driver or to any intermediate driver that might be layered above the device driver.
  5. If the driver uses packet-based system or bus-master DMA, its AdapterControl routine calls MmGetMdlVirtualAddress with the IRP's MdlAddress pointer to get the base virtual address for the MDL's page-based entries. The AdapterControl routine then calls MapTransfer with the base address returned by MmGetMdlVirtualAddress, to read data from the device directly into physical memory. (For more information, see Adapter Objects and DMA.)

Drivers should always check buffer lengths. Note that the I/O Manager does not create an MDL for a zero-length buffer.


Using Direct I/O with PIO

A device that uses programmed I/O (PIO) rather than DMA must doubly map user-space buffers into a system-space address range, as shown in the following figure.

Direct I/O for Devices that Use PIO

The previous figure shows how a device that uses PIO handles the same task.

  1. Some range of user-space virtual addresses represents the current thread's buffer, and that buffer's contents might actually be stored on some number of physically discontiguous pages. If the buffer length is nonzero, the I/O Manager creates an MDL to describe this buffer.
  2. The I/O Manager services the current thread's read request, for which the thread passes a range of user-space virtual addresses representing a buffer.
  3. The I/O Manager or FSD checks the user-supplied buffer for accessibility. If the I/O Manager has created an MDL, it calls MmProbeAndLockPages with an MDL, which specifies the range of virtual addresses for the user buffer. MmProbeAndLockPages also fills in the corresponding physical address range in the MDL.
  4. The I/O Manager provides a pointer to the MDL (MdlAddress) in an IRP that requests a transfer operation. Until the I/O Manager or file system calls MmUnlockPages after the driver completes the IRP, the physical pages described in the MDL remain locked down and assigned to the buffer. However, the virtual addresses in such an MDL can become invisible (and invalid), even before the IRP is sent to the device driver or to any intermediate driver that might be layered above the device driver.
  5. If the driver requires system (virtual) addresses, the driver calls MmGetSystemAddressForMdlSafe with the IRP's MdlAddress pointer to doubly map the user-space virtual addresses in the MDL to a system-space address range. In the previous figure, AliasBuff represents the MDL that describes the doubly-mapped addresses.
  6. The driver uses the system-space virtual address range from the doubly mapped MDL (AliasBuff) to read data into memory.

When the driver completes the IRP by calling IoCompleteRequest, the I/O Manager or file system releases the MDL's doubly mapped system-space range if the driver called MmGetSystemAddressForMdlSafe. The I/O manager or file system unlocks the pages described in the MDL, and disposes of the MDL and IRP on the driver's behalf. For better performance, drivers should avoid doubly mapping MDL physical addresses to system space, as described in step 3, unless they must use virtual addresses. Doing so uses system page-table entries unnecessarily and can decrease both driver performance and scalability. In addition, the system might crash if it runs out of page-table entries, because most older drivers cannot handle this situation.

The current user thread's buffers and the thread itself are guaranteed to be resident in physical memory only while that thread is current. For the thread shown in the previous figure, its user buffer's contents could be paged out to secondary storage while another process's threads are run. When another process's thread is run, the system physical memory for the requesting thread's buffer can be overwritten unless the Memory Manager has locked down and preserved the corresponding physical pages that contain the original thread's buffer.

However, the original thread's virtual addresses for its buffer do not remain visible while another thread is current, even if the Memory Manager preserves the buffer's physical pages. Consequently, drivers cannot use a virtual address returned by MmGetMdlVirtualAddress to access memory. Callers of this routine must pass its results to MapTransfer (along with the IRP's MdlAddress pointer) in order to transfer data using packet-based system or bus-master DMA.


Using Neither Buffered Nor Direct I/O

If device objects specify neither direct or buffered I/O, then the I/O Manager will pass the original user-space virtual addresses in IRPs sent to the driver. Because the driver must be executing in the context of the calling thread to access these buffers safely, typically only highest-level drivers, such as FSDs, can use this method for accessing buffers.

An intermediate or lowest-level driver cannot always meet this condition. For example, if a requesting thread waits on the completion of an I/O request or if a higher-level driver is layered over the intermediate or lowest-level driver, then the lower-level driver's routines are unlikely to be called in the context of the requesting thread.

When the I/O Manager sends an IRP with the current thread's user-space virtual addresses for a buffer, a driver that did not OR the device object Flags with DO_BUFFERED_IO or DO_DIRECT_IO must do the following:

  1. Check the validity of the user buffer's address range and check whether the appropriate read or write access is permitted, using the ProbeForRead and ProbeForWrite support routines. The driver must enclose its accesses to the buffer's address range within a driver-supplied exception handler so that a user thread cannot change the access rights for the buffer while the driver is accessing memory. If the probe raises an exception, the driver should return an error. The driver must call these routines within the context of the thread that made the I/O request; therefore, only a higher-level driver can perform this task.
  2. Manage buffers and memory operations in one of the following ways:
    • Carry out its own double-buffering operations, as the I/O Manager does for drivers that use buffered I/O.
    • Create its own MDLs and lock down the buffer by calling the Memory Manager's support routines, as the I/O Manager does for drivers that use direct I/O.
    • Perform all necessary operations on the user buffer directly in the context of the calling thread. The driver must wrap its access to the buffer within a driver-supplied exception handler in case a user thread changes either the access rights for the buffer or the data in the buffer while the driver is accessing memory.

In effect, the driver must choose on a per-IRP basis whether to do buffered I/O, direct I/O, or I/O in the context of the calling thread, and it must handle any exceptions that might occur in a user-mode thread context. The driver must manage its own user buffer accesses, double-buffering operations, and memory mappings, as necessary, instead of letting the I/O Manager handle these operations for the driver.


Adapter Objects and DMA

This section describes adapter objects and AdapterControl routines, and how they are used to control DMA operations. The section contains the following topics:

Introduction to Adapter Objects

Getting an Adapter Object

Using System DMA

Using Bus-Master DMA

Using Scatter/Gather DMA

Writing AdapterControl Routines


Introduction to Adapter Objects

Any driver that uses direct I/O and DMA must create an adapter object. The adapter object represents either a DMA controller channel or port, or a bus-master device.

Two kinds of lowest-level drivers must use adapter objects:

  • Drivers for devices that use the system DMA controller. Such devices are called slave devices and are said to "use system (or slave) DMA."
  • Drivers for devices that are bus-master adapters. Such devices arbitrate with the system for use of the I/O bus, and thus use bus-master DMA.

Drivers provide storage, usually in a device extension, for a pointer to the adapter object.

To carry out DMA transfers, drivers of devices that use either of these DMA methods usually have an AdapterControl routine and call system-supplied support routines that manipulate adapter objects. (Drivers that do not require AdapterControl routines include those that use scatter/gather DMA and those that use common-buffer, bus-master DMA.)

As part of device start-up operations, drivers that handle DMA operations call the I/O Manager, which in turn calls the platform-specific HAL to create a set of adapter objects. On any Windows platform, the set of adapter objects usually includes an adapter object for:

  • Each system DMA controller channel or port to which a slave device is attached.
  • Each bus-master DMA device in the machine.

(For SCSI devices capable of bus-master DMA, the SCSI port driver sets up adapter objects for HBA-specific SCSI miniport drivers. The miniport driver's HwScsiFindAdapter routine supplies the port driver with adapter-specific data.)

See Using System DMA and Using Bus-Master DMA for more information about when and how drivers use adapter objects and AdapterControl routines.


Getting an Adapter Object

At device start-up, a driver that uses system or bus-master DMA calls IoGetDmaAdapter to get a pointer to an adapter object and to determine the maximum number of map registers available for each transfer operation. When a driver calls IoGetDmaAdapter, the I/O Manager, in turn, calls the HAL to get the necessary platform-specific information.

A driver must supply certain information in a system-defined DEVICE_DESCRIPTION structure in its call to IoGetDmaAdapter. Drivers must use RtlZeroMemory to initialize the DEVICE_DESCRIPTION structure with zeros before setting values in it.

The required data includes information about the features of the driver's device, such as whether the device is a busmaster, if it has scatter/gather capabilities, and how many bytes of data the device can transfer at a time (MaximumLength).

The required device description data also includes platform-specific information, such as the platform-specific and system-assigned number of the bus that a driver of a bus-master device controls. A driver can obtain this information by calling IoGetDeviceProperty.

The DEVICE_DESCRIPTION structure includes some fields that might be irrelevant to some DMA devices or drivers. For example, the BusNumber field is not used in WDM drivers. Each driver should supply values for the relevant structure members and should set the values for all other members to zero.

The driver of a slave device should not pass TRUE in the ScatterGather field unless the device is capable of waiting for the system DMA controller to be reprogrammed when a request must be broken up into two or more DMA operations.

IoGetDmaAdapter returns both a pointer to an adapter object and a platform-specific or device-specific value indicating how many map registers are available with the adapter object for each DMA transfer operation.

The returned adapter object contains three fields that are accessible to drivers:

  • Version number (Version)
  • Size (Size),
  • Pointer to a DMA_OPERATIONS structure (DmaOperations)

The DMA_OPERATIONS structure comprises a table of pointers to functions the driver must use to perform DMA operations on its device. The functions are accessible only through the pointers in this data structure; a driver cannot call them directly by name. (Note that these routines replace HalXxx supported in previous versions of Windows NT. To ensure compatibility for legacy drivers, the wdm.h and ntddk.h header files supply macros with the obsolete names, but new drivers should always call the functions through the data structure.)

The number of map registers can vary from device to device and from platform to platform. Generally, the HAL assigns a number of map registers according to the following criteria:

  • If possible, the HAL returns a value that is one more than the number of map registers needed to transfer MaximumLength bytes, as specified in the driver's call to IoGetDmaAdapter.
  • Otherwise, the HAL returns a lesser value that is as large as possible for the particular platform.

In other words, the HAL usually gives each driver enough map registers to maximize DMA throughput for its device, but the HAL can return a lesser value on some Windows platforms. There is no guarantee that a driver will get the number of map registers it requests, so drivers should always check the returned value.

Any DMA device driver must provide storage for the adapter object pointer and NumberOfMapRegisters value returned by IoGetDmaAdapter. This pointer is a required parameter to the system-supplied support routines used for DMA. Because many of these support routines must be called at IRQL DISPATCH_LEVEL, the driver-allocated storage must be resident. Most DMA drivers provide the necessary storage in a device extension. However, the storage can be in a controller extension if the driver also uses a controller object or in nonpaged pool that is allocated by the driver. See Allocating System-Space Memory and Managing Hardware Priorities for more information.

When the driver has completed all DMA operations, it calls PutDmaAdapter to free the adapter object.

The following sections (Using System DMA and Using Bus-Master DMA) describe how monolithic drivers of DMA devices use support routines to satisfy transfer requests. These sections assume that the driver has the following:

  • A standard StartIo routine, rather than setting up and managing an internal queue of IRPs
  • An internal routine to split transfer requests for which an insufficient number of map registers is available
  • No device-specific DMA constraints

In other words, these sections describe the simplest possible technique for drivers' DMA operations, but individual drivers do not necessarily use exactly the same techniques. For any driver of a DMA device, which driver routines should split up large DMA transfer requests depends on the driver model (class/port or monolithic), on the device's features, and on any device-specific DMA constraints that driver must handle.


Using System DMA

Drivers of slave DMA devices use one of the following types of system-provided DMA support:

  • Packet-based DMA, if the driver need not use a system DMA controller's auto-initialize mode. See Using Packet-Based System DMA.
  • Common-buffer DMA, if the driver does use the auto-initialize mode. See Using Common-Buffer System DMA.

In addition, any driver that uses packet-based DMA can use support routines intended to streamline scatter/gather DMA, whether or not its device has built-in scatter/gather support. See Using Scatter/Gather DMA for details.


Using Packet-Based System DMA

Drivers of slave devices that use packet-based DMA call the following general sequence of support routines as they process an IRP requesting a DMA transfer:

  • KeFlushIoBuffers just before attempting to allocate the system DMA controller (for more information, see Maintaining Cache Coherency)
  • AllocateAdapterChannel when the driver is ready to program its device for DMA and needs the system DMA controller

    AllocateAdapterChannel, in turn, calls the driver's AdapterControl routine.

  • MmGetMdlVirtualAddress to get an index into the MDL, required as an parameter in the initial call to MapTransfer
  • MapTransfer to program the system DMA controller for the transfer operation

    A driver might need to call MapTransfer more than once to transfer all the requested data, as explained in Splitting Transfer Requests.

  • FlushAdapterBuffers just after each DMA transfer operation to/from the slave device

    If a driver must call MapTransfer more than once to transfer all the requested data, it must call FlushAdapterBuffers as many times as it calls MapTransfer.

  • FreeAdapterChannel either as soon as all the requested data has been transferred or if the driver fails the IRP because of a device I/O error

The adapter object pointer returned by IoGetDmaAdapter is a required parameter to each of these routines except KeFlushIoBuffers and MmGetMdlVirtualAddress, which require the pointer to the MDL passed at Irp->MdlAddress.

Individual drivers call this sequence of support routines at different points, depending on how each driver is implemented to service its device. For example, one driver's StartIo routine might make the call to AllocateAdapterChannel, another driver might make this call from a routine that removes IRPs from a driver-created interlocked queue, and still another driver might make this call when its slave DMA device indicates it is ready to transfer data.


Allocating an Adapter Channel for Packet-Based DMA

To prepare for packet-based system DMA, a driver calls KeFlushIoBuffers and AllocateAdapterChannel after receiving an IRP_MJ_READ or IRP_MJ_WRITE request.

Before the driver calls these routines, its DispatchRead or DispatchWrite routine (or any other dispatch routine that handles a DMA transfer) should already have checked the validity of the IRP's parameters. The dispatch routine might also have queued the IRP to another driver routine for further processing.

The driver routine that calls AllocateAdapterChannel must be executing at IRQL DISPATCH_LEVEL. Along with a pointer to the adapter object returned by IoGetDmaAdapter, a driver must supply the following when it calls AllocateAdapterChannel:

  • A pointer to the target device object
  • The entry point for its AdapterControl routine
  • A pointer to any driver-determined context information the AdapterControl routine will use

AllocateAdapterChannel queues the driver's AdapterControl routine, which runs when the system DMA controller is assigned to this driver and a set of map registers has been allocated for the driver's DMA operation(s).

On entry, the AdapterControl routine receives the DeviceObject and Context pointers passed in the call to AllocateAdapterChannel, as well as a handle (MapRegisterBase) for the allocated map registers.

The AdapterControl routine also receives a pointer to the DeviceObject->CurrentIrp if the driver has a StartIo routine. If the driver manages its own queuing of IRPs (instead of having a StartIo routine), the driver should include a pointer to the current IRP as part of the context it passes when it calls AllocateAdapterChannel.

The AdapterControl routine typically does the following:

  1. Saves or initializes whatever context the driver maintains about DMA operations. The context might include the input MapRegisterBase handle the driver must pass to MapTransfer and FlushAdapterBuffers and, possibly, the Length of the requested transfer from its I/O stack location in the IRP.
  2. Calls MmGetMdlVirtualAddress followed by MapTransfer. See Setting Up the System DMA Controller for Packet-Based DMA.
  3. Sets up the slave device to start the transfer operation.
  4. Returns the value KeepObject.

Every AdapterControl routine must return a system-defined value of type IO_ALLOCATION_ACTION. For drivers that use system DMA, the AdapterControl routine must return the value KeepObject. This allows the driver to retain "ownership" of the system DMA controller and allocated map registers until it has transferred all the requested data.

Because an AdapterControl routine cannot wait for the slave device to carry out the DMA operation, each AdapterControl routine must, at a minimum, do the following:

  1. Save context information, particularly the MapRegisterBase handle, in the driver's device extension, controller extension, or other driver-accessible resident storage area (nonpaged pool allocated by the driver).
  2. Return KeepObject.

For additional information, see Writing AdapterControl Routines.

Another driver routine (probably the DpcForIsr routine) must call FlushAdapterBuffers when each DMA transfer operation is complete. This routine also must call MapTransfer and FlushAdapterBuffers again if it is necessary to set up the DMA controller more than once to satisfy the current IRP's transfer request.

When a driver has satisfied the current IRP's request, it must call FreeAdapterChannel. This support routine should be called immediately following the last call to FlushAdapterBuffers for the current IRP so that the system DMA controller can be made available for use (by any driver) to satisfy other transfer requests expeditiously.

The driver of a slave device with scatter/gather capabilities should also return KeepObject from its AdapterControl routine. The device must be capable of waiting while the system DMA controller is reprogrammed between DMA operations when the driver must split up a given DMA request. On some Windows platforms, such devices can transfer at most a page of data per DMA operation because the HAL can assign only a single map register to the driver of that device.


Setting Up the System DMA Controller for Packet-Based DMA

When AllocateAdapterChannel transfers control to a driver's AdapterControl routine, the driver "owns" the system DMA controller and a set of map registers. Then, the driver must set up the DMA controller for a transfer operation, as shown in the following figure.

Programming the System DMA Controller

If the driver has a StartIo routine, AllocateAdapterChannel passes a pointer to DeviceObject->CurrentIrp in the PIrp parameter to the AdapterControl routine. If, however, the driver manages its own queue of IRPs, the driver should include a pointer to the current IRP as part of the context it passes to AdapterControl.

As the previous figure shows, the driver's AdapterControl routine sets up the DMA transfer, as follows:

  1. The AdapterControl routine gets the address at which to start the transfer. For the initial transfer required to satisfy an IRP, the AdapterControl routine calls MmGetMdlVirtualAddress, passing a pointer to the MDL at Irp->MdlAddress, which describes the buffer for this DMA transfer.

    MmGetMdlVirtualAddress returns a virtual address that the driver can use as an index for the system physical address where the transfer should start.

    If the IRP requires more than one transfer operation, the driver calculates an updated starting address, as described later in this section.

  2. The AdapterControl routine saves the address returned by MmGetMdlVirtualAddress or calculated in Step 1. This address is a required parameter (CurrentVa) to MapTransfer.
  3. The AdapterControl routine calls MapTransfer to set up the system DMA controller, supplying the following parameters:
    • The adapter object pointer returned by IoGetDmaAdapter
    • A pointer (Mdl) to the MDL at Irp->MdlAddress for the current IRP
    • The MapRegisterBase handle passed to the driver's AdapterControl routine by AllocateAdapterChannel
    • The value (CurrentVa) returned by MmGetMdlVirtualAddress if this is the first call to MapTransfer for the IRP

      Otherwise, the driver supplies an updated CurrentVa value, indicating where in the buffer the next transfer operation should start.

    • A pointer to a variable (Length) indicating the number of bytes for this transfer

      If the driver can transfer all the requested data with a single call to MapTransfer and has no device-specific constraints on its DMA operations, Length can be set to the value of Length in the driver's I/O stack location of the IRP. At most, the length in bytes can be (PAGE_SIZE * the NumberOfMapRegisters returned by IoGetDmaAdapter). Otherwise, the driver must split up the request, as explained in Splitting Transfer Requests, and must update the value of Length in subsequent calls to MapTransfer for the current IRP.

    • A Boolean value (WriteToDevice), indicating the direction of the transfer operation (TRUE to transfer data from system memory to the device)

    MapTransfer returns a logical address. Drivers that use system DMA must ignore this value.

  4. The AdapterControl routine sets up the device for the DMA operation.
  5. The AdapterControl routine returns KeepObject.

When the device indicates that its current DMA operation has completed, the driver should call FlushAdapterBuffers, usually from the driver's DpcForIsr routine.

The DpcForIsr routine or another driver routine that completes a DMA operation calls FlushAdapterBuffers to ensure that any data cached in the system DMA controller is read into system memory or written out to the device. The same routine also must call MapTransfer again if it is necessary to reprogram the system DMA controller to transfer more data for the current IRP. Similarly, it must call FlushAdapterBuffers again following each transfer operation.

If a driver must call MapTransfer more than once for the current IRP, it supplies the same adapter object pointer, Mdl pointer, MapRegisterBase handle, and transfer direction in every call. However, the driver must update the CurrentVa and Length parameters before it makes the second and any subsequent calls to MapTransfer. To calculate an updated value for each of these parameters, use the following formulas:

  • CurrentVa = CurrentVa + (Length requested in the preceding call to MapTransfer)
  • Length = Minimum (remaining Length to be transferred, (PAGE_SIZE * NumberOfMapRegisters returned by IoGetDmaAdapter))

The context information each driver should maintain about its DMA transfers depends on the needs of its particular device. Typical context might include the current virtual address in the MDL (CurrentVa), the number of bytes transferred so far, the number of bytes remaining to transfer, possibly a pointer to the current IRP, and any other information the driver writer deems useful.

When the requested transfer is complete, or if the driver must return an error status for the IRP, the driver should call FreeAdapterChannel promptly to release the system DMA controller for other drivers and this driver to use.


Using Common-Buffer System DMA

A driver that uses a system DMA controller's auto-initialize mode must allocate memory for a buffer into which or from which DMA transfers can be carried out. The driver calls AllocateCommonBuffer to get this buffer, typically from the DispatchPnP routine that handles an IRP_MN_START_DEVICE request. The following figure shows how a driver allocates the buffer and maps its virtual address range to system physical memory.

Allocating a Common Buffer for System DMA

As the previous figure shows, a driver takes the following steps to allocate a buffer for system DMA:

  1. The driver calls AllocateCommonBuffer, passing a pointer to the adapter object that was returned by IoGetDmaAdapter, along with the length in bytes requested for its buffer. To use memory economically, the input Length value for the buffer should either be less than or equal to PAGE_SIZE or should be an integral multiple of PAGE_SIZE.
  2. If AllocateCommonBuffer returns a NULL pointer, the driver should free any system resources it has already claimed and return STATUS_INSUFFICIENT_RESOURCES in response to the IRP_MN_START_DEVICE request.

    Otherwise, AllocateCommonBuffer allocates the requested amount of memory in system virtual address space and returns two different types of pointers to that buffer:

    • The LogicalAddress of the buffer (BufferLogicalAddress in the previous figure), for which the driver must provide storage but which it should ignore thereafter
    • The virtual address of the buffer (BufferVirtualAddress in the previous figure), which the driver also must store so that it can build an MDL describing its buffer for DMA operations

    The driver should store these pointers in the device extension or other driver-allocated resident memory.

  3. The driver calls IoAllocateMdl to allocate an MDL for the buffer. The driver passes the VirtualAddress of the buffer returned by AllocateCommonBuffer and the Length of its buffer to allocate an MDL.
  4. The driver calls MmBuildMdlForNonPagedPool with the pointer returned by IoAllocateMdl to map the virtual address range for its resident buffer to system physical memory

After allocating a common buffer and mapping its virtual address range, the driver of a slave device can begin to process an IRP that requests a DMA transfer. To do so, the driver calls the following general sequence of support routines:

  1. At the driver writer's discretion, RtlMoveMemory to copy data from a locked-down user buffer into the driver-allocated common buffer for a transfer to the device
  2. AllocateAdapterChannel when the driver is ready to program its device for DMA and needs the system DMA controller
  3. MapTransfer, with the MDL that describes the driver-allocated common buffer, to set up the system DMA controller for the transfer operation

    Note that the driver calls MapTransfer only once to set up the system DMA controller to use its common buffer. During a transfer, the driver can call ReadDmaCounter to determine how many bytes remain to be transferred, and if necessary, call RtlMoveMemory to copy more data to or from a user buffer.

  4. FlushAdapterBuffers when the driver has completed its DMA transfer to/from the slave device
  5. FreeAdapterChannel as soon as all the requested data has been transferred or if the driver must fail the IRP because of a device I/O error

The adapter object pointer returned by IoGetDmaAdapter is a required parameter to each of these support routines except RtlMoveMemory.

Individual drivers call this sequence of support routines at different points, depending on how each driver is implemented to service its device. For example, one driver's StartIo routine might make the call to AllocateAdapterChannel, another driver might make this call from a routine that removes IRPs from a driver-created interlocked queue, and still another driver might make this call when its slave DMA device indicates it is ready to transfer data.


Allocating an Adapter Channel for Common-Buffer System DMA

A driver calls AllocateAdapterChannel after its DispatchRead or DispatchWrite routine (or any other dispatch routine that handles a DMA transfer) has checked the validity of the IRP's parameters, possibly queued one or more IRPs to another driver routine for further processing, and possibly loaded its common buffer with data to be transferred, if appropriate.

The driver routine that calls AllocateAdapterChannel must be executing at IRQL DISPATCH_LEVEL. The AllocateAdapterChannel routine queues the driver's AdapterControl routine, which runs after the system DMA controller has been assigned to this driver and a set of map registers has been allocated for the driver's DMA operation.

On entry, the AdapterControl routine is given pointers to the device object and context passed in the call to AllocateAdapterChannel, as well as a handle for the allocated map registers. The AdapterControl routine also is given a pointer to the DeviceObject->CurrentIrp if the driver has a StartIo routine. If the driver manages its own queuing of IRPs instead of having a StartIo routine, the driver should include a pointer to the current IRP as part of the context data it passes when it calls AllocateAdapterChannel.

The AdapterControl routine typically does the following:

  1. Saves or initializes whatever context the driver maintains about DMA operations. The context might include the input MapRegisterBase handle the driver must pass to MapTransfer and FlushAdapterBuffers and, possibly, the Length of the requested transfer from its I/O stack location in the IRP.
  2. Sets up the slave device to start the transfer operation.
  3. Returns the value KeepObject.

For additional information, see Writing AdapterControl Routines.

For drivers that use a system DMA controller's auto-initialize mode, the AdapterControl routine must return the value KeepObject. This allows the driver to retain "ownership" of the system DMA controller and allocated map register(s) until it has transferred all the data.

Because an AdapterControl routine cannot wait for the slave device to carry out the DMA operation, the AdapterControl routine must at least do the following:

  1. Save context information, particularly the MapRegisterBase handle, in the driver's device extension, controller extension, or other driver-accessible resident storage area (nonpaged pool allocated by the driver).
  2. Return KeepObject.

Another driver routine (probably the DpcForIsr routine) must call FlushAdapterBuffers and FreeAdapterChannel when the DMA transfer operation is complete.


Setting Up the System DMA Controller for Common-Buffer DMA

When AllocateAdapterChannel transfers control to a driver's AdapterControl routine, the driver "owns" the system DMA controller and a set of map registers. Then, the driver must call MapTransfer to set up the system DMA controller to use the driver-allocated common buffer before the driver sets up its device for the transfer operation.

The driver supplies the following parameters to MapTransfer:

  • The adapter object pointer returned by IoGetDmaAdapter
  • A pointer to the MDL describing the driver-allocated common buffer
  • The MapRegisterBase handle passed to the driver's AdapterControl routine by AllocateAdapterChannel
  • A pointer to a variable (Length) indicating the size in bytes of the driver-allocated common buffer
  • A Boolean value, indicating the direction of the transfer operation (TRUE for a requested transfer from system memory to the device)

MapTransfer returns a logical address, which drivers that use system DMA must ignore. When MapTransfer returns control, the driver should set up its device for the DMA operation. The driver calls MapTransfer only once but continues to copy data between its common buffer and a locked-down user buffer until the requested transfer is done.

The driver can call ReadDmaCounter to determine how many bytes currently remain to be transferred in the common buffer; the driver can then continue to fill its common buffer with user data or copy data from its common buffer to the user buffer, depending on the direction of the DMA operation.

When the transfer is complete or if the driver must return an error status for the IRP, the driver calls FlushAdapterBuffers to ensure that any data cached in the system DMA controller is read into system memory or written out to the device. Then the driver should call FreeAdapterChannel promptly to release the system DMA controller for use by any driver (including itself).


Using Bus-Master DMA

Drivers of bus-master DMA devices can use the following kinds of system-supplied DMA support:

  • Packet-based DMA if the bus-master adapter allows the driver to determine when a DMA transfer operation is done and/or when to begin another transfer operation for a given IRP. See Using Packet-Based, Bus-Master DMA for details.
  • Common-buffer DMA (also called continuous DMA) if the bus-master adapter does not provide a way for the driver to determine readily when a transfer operation will begin or when a transfer is complete, or if a single buffer area is used continuously or repeatedly for DMA transfers. See Using Common-Buffer, Bus-Master DMA for details.

Depending on the nature of the bus-master adapter, some drivers use packet-based DMA exclusively, some use common-buffer DMA exclusively, and some use both. For example, the driver of a bus-master adapter that uses a mailbox scheme to communicate status information and commands might use a common buffer for the mailboxes shared between the driver and its adapter, together with packet-based DMA for data transfers.


Using Packet-Based, Bus-Master DMA

To use packet-based DMA, drivers of bus-master DMA devices call the following general sequence of support routines as they process an IRP requesting a DMA transfer:

  • KeFlushIoBuffers just before attempting to allocate map registers for a transfer request (for more information, see Maintaining Cache Coherency)
  • AllocateAdapterChannel when the driver is ready to program the bus-master adapter for DMA
  • MmGetMdlVirtualAddress to get an index into the MDL, required as an initial parameter to MapTransfer, and MapTransfer to make the system physical memory that backs the IRP's buffer device-accessible

    Note that any driver might need to carry out more than one transfer operation in order to satisfy the current IRP, as explained in Splitting Transfer Requests. Drivers of devices that do not have scatter/gather capabilities can call MapTransfer once per transfer operation. Drivers of devices that have scatter/gather capabilities can call MapTransfer more than once to set up each transfer operation. Alternatively, these drivers can use the system's built-in scatter/gather support, described in Using Scatter/Gather DMA.

  • FlushAdapterBuffers at the end of each DMA transfer operation to/from the target device, in order to determine whether all the requested data has been completely transferred
  • FreeMapRegisters as soon as all DMA operations for the current IRP are done, because all the requested data has been completely transferred or because the driver must fail the IRP due to a device or bus I/O error

The adapter object pointer returned by IoGetDmaAdapter is a required parameter to AllocateAdapterChannel, MapTransfer, FlushAdapterBuffers, and FreeMapRegisters. Note that in versions of Windows NT prior to Windows 2000, bus-master devices could pass a NULL adapter object pointer to MapTransfer and FlushAdapterBuffers. In Windows 2000 and later, drivers can no longer do so.

KeFlushIoBuffers and MmGetMdlVirtualAddress require a pointer to the MDL at Irp->MdlAddress.

Individual drivers call this sequence of support routines at different points, depending on how each driver is implemented to service its device. For example, one driver's StartIo routine might make the call to AllocateAdapterChannel, while another driver might make this call from a routine that removes IRPs from a driver-created interlocked queue or device queue.

Instead of using the routines described in this section, any driver that uses packet-based DMA can use support routines intended to streamline scatter/gather DMA, whether or not its device has built-in scatter/gather support. See Using Scatter/Gather DMA for details.


Allocating the Bus-Master Adapter Object

To prepare for packet-based, bus-master DMA, a driver calls KeFlushIoBuffers and AllocateAdapterChannel after receiving an IRP_MJ_READ or IRP_MJ_WRITE. Before the driver calls these routines, its dispatch routine should check the validity of the IRP's parameters. It might also queue the IRP to another driver routine for further processing. The transfer request is the current IRP requiring a device I/O operation.

The driver routine that calls AllocateAdapterChannel must be executing at IRQL DISPATCH_LEVEL. Along with a pointer to the adapter object returned by IoGetDmaAdapter, a driver must supply the following when it calls AllocateAdapterChannel:

  • A pointer to the target device object for the current IRP
  • The entry point for its AdapterControl routine
  • A pointer to any driver-determined context information the AdapterControl routine will use

AllocateAdapterChannel queues the driver's AdapterControl routine, which runs when the adapter object is free and a set of map registers has been allocated for the driver's DMA operations to or from the target device.

On entry, an AdapterControl routine is given the DeviceObject and Context pointers passed in the call to AllocateAdapterChannel, as well as a handle (MapRegisterBase) for the allocated map registers.

The AdapterControl routine also is given a pointer to the DeviceObject->CurrentIrp if the driver has a StartIo routine. If the driver manages its own queuing of IRPs instead of having a StartIo routine, the driver should include a pointer to the current IRP as part of the context it passes when it calls AllocateAdapterChannel.

For the driver of a bus-master DMA device without scatter/gather capabilities, the AdapterControl routine usually does the following:

  1. Saves or initializes whatever context the driver maintains about DMA operations. The context might include the input MapRegisterBase handle the driver must pass to MapTransfer and FlushAdapterBuffers, the Length in bytes of the requested transfer from its I/O stack location in the IRP, and so forth
  2. Calls MmGetMdlVirtualAddress followed by MapTransfer (described in Setting Up a Transfer Operation, next) to get the logical address its device can use to start the transfer operation
  3. Sets up the bus-master adapter to start the transfer operation
  4. Returns the value DeallocateObjectKeepRegisters

For the driver of a bus-master device with scatter/gather capabilities, the AdapterControl routine usually does the following:

  1. Saves or initializes whatever state the driver maintains about DMA operations, such as saving the MapRegisterBase handle the driver must pass to MapTransfer and FlushAdapterBuffers, the Length in bytes of the requested transfer from its I/O stack location in the IRP, and so forth
  2. Calls MmGetMdlVirtualAddress followed by MapTransfer (described in the next subsection) to get the logical address its device can use to start the transfer operation

    The AdapterControl routine calls MapTransfer repeatedly until it has used all the available map registers to build a scatter/gather list for the bus-master adapter.

  3. Sets up the bus-master adapter to start the transfer operation
  4. Returns the value DeallocateObjectKeepRegisters

For additional information, see Writing AdapterControl Routines.

Note that drivers that perform bus-master DMA can use the GetScatterGatherList and PutScatterGatherList routines whether or not their devices support scatter/gather DMA. Using these routines changes the requirements for the driver's AdapterControl routine; see Using Scatter/Gather DMA for details.

An AdapterControl routine must return a system-defined value of type IO_ALLOCATION_ACTION. For drivers that use bus-master DMA, the AdapterControl routine should typically return the value DeallocateObjectKeepRegisters, which allows the driver to retain the allocated map registers for the target device object until it has transferred all the requested data for the current IRP. After the transfer is complete, the DPC routine should call FreeMapRegisters to free the allocated map registers. In cases where the device does not support command queuing, however, the AdapterControl routine can return KeepObject when the transfer for the current IRP is complete, and the DPC routine can call FreeAdapterChannel instead.

An AdapterControl routine cannot wait for the bus-master adapter to complete a DMA operation.

Whether or not the bus-master adapter supports scatter/gather, the AdapterControl routine must at least do the following:

  1. Save necessary context information — particularly the MapRegisterBase handle — in the driver's device extension, controller extension, or other driver-accessible resident storage area (nonpaged pool, allocated by the driver). The driver must pass this handle when it calls MapTransfer and FlushAdapterBuffers.
  2. Return DeallocateObjectKeepRegisters.

Another driver routine (probably the DpcForIsr routine) must call FlushAdapterBuffers when each DMA transfer operation is done. This routine also must set up any additional DMA operations necessary to satisfy the current IRP.

When the driver has satisfied the current IRP's transfer request or must fail the IRP due to a device or bus I/O error, it must call FreeMapRegisters. This call should occur immediately following the last call to FlushAdapterBuffers for the current IRP, so that the driver can service other DMA requests, possibly for other devices on the bus.


Setting Up a Transfer Operation

When AllocateAdapterChannel transfers control to a driver's AdapterControl routine, it has allocated a set of map registers. However, the driver must map system physical memory for the current IRP's transfer request to the bus-master adapter's logical address range, as follows:

  1. Call MmGetMdlVirtualAddress with the MDL at Irp->MdlAddress to get an index for the system physical address where the transfer should start.

    The return value is a required parameter (CurrentVa) to MapTransfer.

  2. Call MapTransfer to map the system physical address ranges for the IRP's buffer to the bus-master adapter's logical address range.

The driver can then set up the adapter for the transfer operation. The following figure shows the steps involved in setting up the transfer.

Setting Up a Logical Range for DMA

As the previous figure shows, a driver's AdapterControl routine sets up a bus-master DMA operation as follows:

  1. The AdapterControl routine gets the address at which to start the transfer. For the initial transfer required to satisfy an IRP, the AdapterControl routine calls MmGetMdlVirtualAddress, passing a pointer to the MDL at Irp->MdlAddress, which describes the buffer for this DMA transfer.

    MmGetMdlVirtualAddress returns a virtual address that the driver can use as an index for the system physical address where the transfer should start.

    If the IRP requires more than one transfer operation, the driver calculates an updated starting address, as described later in this section.

  2. The AdapterControl routine saves the address returned by MmGetMdlVirtualAddress or calculated in Step 1. This address is a required parameter (CurrentVa) to MapTransfer.
  3. The AdapterControl routine calls MapTransfer, which returns a logical address at which the driver can program the bus-master adapter to begin the transfer operation. In the call to MapTransfer, the driver supplies the following parameters:
    • The adapter object pointer returned by IoGetDmaAdapter
    • A pointer to the MDL at Irp->MdlAddress for the current IRP
    • The MapRegisterBase handle passed to the driver's AdapterControl routine by AllocateAdapterChannel (see Allocating the Bus-Master Adapter Object)
    • The value returned by MmGetMdlVirtualAddress if this is the first call to MapTransfer for the current IRP

      Otherwise, the driver supplies an updated CurrentVa value, indicating the next physical-to-logical mapping to be done. (How to calculate an updated CurrentVa is described later in this section.)

    • A pointer to a variable (Length), which indicates the number of bytes for this transfer

      If the driver has enough map registers to transfer all the requested data in a single DMA operation and has no device-specific constraints on its DMA operations, the Length can be set to the value of Length in the driver's I/O stack location of the IRP. At most, the input length in bytes can be (PAGE_SIZE * the NumberOfMapRegisters returned by IoGetDmaAdapter). Otherwise, the driver must split up the request, as explained in Splitting Transfer Requests, and must update the value of Length in subsequent calls to MapTransfer for the current IRP.

    • A Boolean value (WriteToDevice), indicating the direction of the transfer operation (TRUE to transfer data from memory to the device)
  4. The AdapterControl routine sets up the device for the DMA operation.
  5. The AdapterControl routine returns DeallocateObjectKeepRegisters.

If the driver must call MapTransfer more than once to satisfy the current IRP, it supplies the same adapter object pointer, Mdl pointer, MapRegisterBase handle, and transfer direction in every call to MapTransfer. However, the driver must supply updated CurrentVa and Length values in its second and subsequent calls to MapTransfer. Use the following formulas to calculate these values:

  • CurrentVa = CurrentVa + (Length requested in preceding call to MapTransfer)
  • Length = Minimum (remaining Length to be transferred, (PAGE_SIZE * NumberOfMapRegisters returned by IoGetDmaAdapter))

The context information each driver should maintain about its DMA transfers depends on the needs of its particular device. Typical context might include the current virtual address in the MDL (CurrentVa), the number of bytes transferred so far, the number of bytes remaining to transfer, and possibly a pointer to the current IRP.

For drivers of devices with scatter/gather capabilities, the Length parameter to MapTransfer is both an input and output parameter. On return from MapTransfer, it indicates how many bytes of data the system has mapped. That is, the return value of Length, in combination with the returned logical address, indicates the range of logical addresses the bus-master adapter can use for this piece of the transfer in this DMA operation.

Note Since Length is overwritten by MapTransfer, follow this implementation guideline:

Never pass a pointer to the Length in the driver's I/O stack location of an IRP as the Length parameter to MapTransfer if your device supports scatter/gather.

Doing this could destroy the value in the current IRP, making it impossible to determine whether the driver has transferred all the requested data.

At the end of each DMA operation, the driver must call FlushAdapterBuffers with a valid adapter object pointer and the MapRegisterBase handle to be sure that all the data has been transferred, and to release the physical-to-logical mappings for the current DMA operation. If the driver must set up additional DMA operations to satisfy the current IRP, it must call FlushAdapterBuffers after each transfer operation is complete.

When all the requested transfer is complete or the driver must return an error status for the IRP, the driver should call FreeMapRegisters immediately after its last call to FlushAdapterBuffers in order to get the best possible throughput for the busmaster adapter. In its call to FreeMapRegisters, the driver must pass the adapter object pointer that it passed in the preceding call to AllocateAdapterChannel.


Using Common-Buffer, Bus-Master DMA

Use common-buffer DMA economically. Setting up a common buffer can tie up some (or all, depending on the size of the requested buffer) of the map registers associated with the adapter object that represents the bus-master adapter.

Setting up common-buffer areas economically, such as using PAGE_SIZE chunks or a single allocation, leaves more map registers available for packet-based DMA operations. It also leaves more system memory free for other purposes, thus yielding better overall driver and system performance.

To set up a common buffer for bus-master DMA, a bus-master DMA device driver must call AllocateCommonBuffer with the adapter object pointer returned by IoGetDmaAdapter. Typically, a driver makes this call from its DispatchPnP routine for IRP_MN_START_DEVICE requests. A driver should allocate a common buffer only if it will use the buffer repeatedly for its DMA operations while the driver remains loaded. The following figure illustrates such a call to AllocateCommonBuffer.

Allocating a Common Buffer for Busmaster DMA

The requested size for the buffer, shown in the previous figure as LengthForBuffer, determines how many map registers must be used to provide a virtual-to-logical mapping for the common buffer. Use the BYTES_TO_PAGES macro to determine the maximum number of pages needed (BYTES_TO_PAGES (LengthForBuffer)). This value cannot be greater than the NumberOfMapRegisters returned by IoGetDmaAdapter.

In addition, the caller must supply the following:

  • A Boolean that indicates whether caching should be enabled
  • A pointer to a driver-defined variable that will contain the device-accessible base Logical Address for the buffer (BufferLogicalAddress in the previous figure) on return from AllocateCommonBuffer

If the call succeeds, AllocateCommonBuffer returns a driver-accessible base virtual address for the buffer (BufferVirtualAddress in the previous figure), which the driver must save in its device extension, controller extension, or other driver-accessible resident storage area (nonpaged pool allocated by the driver).

AllocateCommonBuffer returns NULL if it cannot allocate memory for the buffer. If the returned base virtual address is NULL, the driver either must use the system's packet-based DMA support exclusively or the driver must fail the IRP_MN_START_DEVICE request, returning STATUS_INSUFFICIENT_RESOURCES.

Otherwise, the driver can use the allocated common buffer as a driver- and adapter-accessible storage area for DMA transfers.

When the PnP Manager sends an IRP that stops or removes the device, the driver must call FreeCommonBuffer to release each common buffer it has allocated.


Using Scatter/Gather DMA

Drivers that perform system or bus-master, packet-based DMA can use support routines designed especially for scatter/gather DMA. Instead of calling the sequence of routines outlined in Using Packet-Based System DMA and Packet-Based Bus-Master DMA, a driver can use GetScatterGatherList and PutScatterGatherList.

A device does not need to have built-in scatter/gather support for its driver to use these routines.

Drivers that use packet-based DMA call the following general sequence of support routines for scatter/gather operations:

  1. KeFlushIoBuffers before calling GetScatterGatherList (for more information, see Maintaining Cache Coherency)
  2. MmGetMdlVirtualAddress to get an index into the MDL, required as an parameter in the call to GetScatterGatherList
  3. GetScatterGatherList when the driver is ready to program its device for DMA and needs the system DMA controller or bus-master adapter

    GetScatterGatherList allocates the system DMA controller or bus-master adapter, determines how many map registers are required and allocates them, fills in the scatter/gather list, and calls the driver's AdapterListControl routine when the DMA controller or adapter and map registers are available.

  4. PutScatterGatherList as soon as all the requested data has been transferred or the driver fails the IRP because of a device I/O error

    PutScatterGatherList flushes the adapter buffers, frees the map registers, and frees the scatter/gather list. The driver must call PutScatterGatherList before it can access the data in the buffer.

The adapter object pointer returned by IoGetDmaAdapter is a required parameter to each of these routines except KeFlushIoBuffers and MmGetMdlVirtualAddress, which require a pointer to the MDL at Irp->MdlAddress.

The GetScatterGatherList routine includes calls to AllocateAdapterChannel and MapTransfer, so the driver does not have to make these calls. The routine takes the following as parameters:

  • A pointer to the DMA_ADAPTER structure returned by IoGetDmaAdapter
  • A pointer to the target device object for the DMA operation
  • A pointer to the MDL that describes the buffer at Irp->MdlAddress
  • A pointer to the current virtual address in the buffer described by the Mdl
  • The number of bytes to be mapped
  • A pointer to an AdapterListControl routine that performs the transfer.
  • A pointer to a driver-defined context area to be passed to the AdapterListControl routine
  • A Boolean value: TRUE for a transfer to the device; FALSE otherwise

After determining the number of map registers required, allocating the adapter channel and map registers, filling in the scatter/gather list and preparing for the transfer, GetScatterGatherList calls the driver-supplied AdapterListControl routine. The AdapterListControl routine is run in an arbitrary thread context at IRQL DISPATCH_LEVEL.

The AdapterListControl routine a driver supplies in calls to GetScatterGatherList differs from the AdapterControl routine passed to AllocateAdapterChannel in the following important respects:

  • The AdapterListControl routine has no return value, whereas the AdapterControl routine returns an IO_ALLOCATION_ACTION.
  • Rather than a pointer to the MapRegisterBase for the system-allocated map registers, the third parameter to an AdapterListControl routine instead points to a SCATTER_GATHER_LIST structure through which the driver can perform DMA.
  • The AdapterListControl routine performs a subset of the tasks required in an AdapterControl routine.

    The AdapterListContol routine does not call AllocateAdapterChannel or MapTransfer. Its only responsibilities are to save the input scatter/gather list pointer, set up its device, and use the scatter/gather list to perform DMA.

The scatter/gather list structure includes an array of SCATTER_GATHER_ELEMENTS and the number of elements in the array. Each element of the array provides the length and starting physical address of a physically contiguous scatter/gather region. A driver uses the length and address in data transfers.

A driver can use GetScatterGatherList whether or not its device supports scatter/gather DMA. For a device that does not support scatter/gather DMA, the scatter/gather list will contain only one element.

Using the scatter/gather routines can improve performance over calling AllocateAdapterChannel (as previously described in Using Packet-Based System DMA and Using Packet-Based, Bus-Master DMA). Unlike calls to AllocateAdapterChannel, more than one call to GetScatterGatherList can be queued for a device object at any one time. A driver can call GetScatterGatherList again for another DMA operation on the same driver object before its AdapterListControl routine has completed execution.

On return from the driver-supplied AdapterListControl routine, GetScatterGatherList keeps the map registers but frees the DMA adapter structure.

When the driver has satisfied the current IRP's transfer request or must fail the IRP due to a device or bus I/O error, it must call PutScatterGatherList before it can access the transferred data in the buffer. PutScatterGatherList flushes the adapter buffers and frees the map registers and scatter/gather list.


Writing AdapterControl Routines

Most drivers of DMA devices have an AdapterControl routine, which is responsible for initiating DMA operations. (Drivers that do not require AdapterControl routines include those that use scatter/gather DMA and those that use common-buffer, bus-master DMA.)

When a driver calls AllocateAdapterChannel, its AdapterControl routine is run immediately if the system DMA controller or bus-master adapter is available for a DMA operation, and if enough map registers are available. Otherwise, the AdapterControl routine is queued until these resources are available.


Storage Requirements for AdapterControl Routines

If it has an AdapterControl routine, a driver must provide resident storage for the following:

  • Context information to be used in its DMA operations
  • An adapter object pointer returned by IoGetDmaAdapter
  • A ULONG-type variable to hold the system-determined maximum NumberOfMapRegisters available for any given DMA transfer request

The driver can provide the necessary storage in a device extension, in a controller extension, or in nonpaged pool allocated by the driver.


Setting Up AdapterControl Routines

A driver's dispatch routine for a PnP IRP_MN_START_DEVICE request must do the following for an AdapterControl routine:

  1. Set up the adapter object for the device's DMA capabilities by filling in a DEVICE_DESCRIPTION structure and calling IoGetDmaAdapter.
  2. Save the adapter object pointer and NumberOfMapRegisters returned by IoGetDmaAdapter.

    The platform-specific maximum NumberOfMapRegisters returned by IoGetDmaAdapter or the transfer capabilities of the driver's device, whichever is more restrictive, determines whether the driver must split up a given transfer request and carry out more than one DMA operation on its device to satisfy that IRP.

The returned adapter object pointer, the entry point of the driver's AdapterControl routine, the DeviceObject pointer representing the target device for the current IRP, a Context pointer to an area already set up for the AdapterControl routine, and a NumberOfMapRegisters value, which can be less than the maximum possible number for smaller transfer requests, must be passed in calls to AllocateAdapterChannel. Usually, a driver's StartIo (or possibly ControllerControl) routine sets up the area at Context before it calls AllocateAdapterChannel.


AdapterControl Routine Requirements

At a minimum, an AdapterControl routine must do the following:

  1. Save the input MapRegisterBase value along with any other context information that the driver needs to carry out one or more DMA transfer operations for the current IRP. The driver must pass the MapRegisterBase value to FlushAdapterBuffers when each DMA transfer operation is complete.
  2. Return the appropriate IO_ALLOCATION_ACTION value:
    • KeepObject if the device is a slave so the driver uses system DMA.
    • DeallocateObjectKeepRegisters if the device is a bus master so the driver uses packet-based, bus-master DMA.

Depending on the driver's design, its AdapterControl routine also can do the following before it returns control:

  1. Determine the starting location for the transfer on its device.
  2. Calculate the size of the transfer possible, given any limitations of its device due to the starting location of the transfer.

    In general, it is the responsibility of the routine that calls AllocateAdapterChannel to determine whether a transfer request must be split up into partial transfers due to any platform-specific limitations on the NumberOfMapRegisters available for each DMA transfer operation, as mentioned in the preceding section and detailed in Splitting Transfer Requests.

  3. Set up any driver-maintained state about each transfer request in the device (or controller) extension.

    For example, an AdapterControl routine might call KeSetTimer with the entry point for a CustomTimerDpc routine that times out DMA transfer operations for the driver.

  4. Call MmGetMdlVirtualAddress with the MDL pointer passed at Irp->MdlAddress to get an index for the start of the transfer, suitable for passing to MapTransfer.
  5. Call MapTransfer to set up the system DMA controller or to obtain a physical-to-logical address mapping for a bus-master device.
  6. Program the driver's device for a transfer operation, by using a SynchCritSection routine that is invoked by calling KeSynchronizeExecution. For more information, see Using Critical Sections.

If a transfer request requires the driver to perform a sequence of partial-transfer operations to satisfy the current IRP, the driver's DpcForIsr or CustomDpc routine is typically responsible for reprogramming the device for subsequent transfer operations. An AdapterControl routine is called only once for each incoming transfer IRP.

The driver routine that completes the current transfer IRP, usually the DpcForIsr or CustomDPC routine, also is responsible for releasing the system DMA controller or bus-master adapter by calling FreeAdapterChannel or FreeMapRegisters, respectively. This driver routine should make the appropriate call as soon as possible when its last partial-transfer operation is done so that drivers of slave DMA devices can allocate the system DMA controller or a bus-master driver can begin processing the next transfer IRP promptly.


Controller Objects

This section describes the use of controller objects and ControllerControl routines. It contains the following topics:

Introduction to Controller Objects

Creating Controller Objects and Controller Extensions

Allocating Controller Objects for I/O Operations

Writing ControllerControl Routines


Introduction to Controller Objects

As its name suggests, a controller object usually represents a physical device controller with attached devices. A lowest-level non-WDM driver for a set of similar devices coordinated by a physical controller can create a controller object and use it to synchronize I/O operations between the attached devices. The driver implements a ControllerControl routine and calls the I/O Manager's controller object support routines.

Use of controller objects is not supported in WDM drivers.

Generally, drivers use controller objects to synchronize operations to attached devices if the following criteria hold:

  • The controller does not carry out long operations without interrupting, so the driver does not need to create a device-dedicated thread or use system worker threads.
  • The devices connected to the controller are similar. That is, they are not devices with entirely different physical properties or operational functionality, such as the keyboard and mouse devices that can be connected to the keyboard and auxiliary device controller.
  • The driver is designed to be monolithic: single-layered in relation to the device controller and attached physical devices, rather than being designed as a port driver (for the controller) with one or more class drivers (for attached devices) layered over the port driver.

Drivers of devices with I/O channels and a set of logical device objects also might use a controller object to synchronize their I/O operations between or among the channels of such a device.

A controller object has no name and thus is not the target of I/O requests. It is simply a synchronization mechanism to serialize I/O from a set of device objects. Because a controller object has no name, it is invisible to user-mode protected subsystems, which cannot make device I/O requests without getting a handle for the file object that represents the target device object. A controller object is also invisible to higher-level drivers, which cannot attach their own device objects to a controller object. In other words, neither the I/O Manager nor a higher-level driver can set up an IRP requesting I/O on a device represented by a controller object. I/O requests are always issued to device objects. Only the driver can use the controller object.

Synchronization and Overlapped I/O

Monolithic drivers of physical devices with features like those of the "AT" disk controller are not required to use a controller object to synchronize their device I/O operations. For example, a driver writer could try something like the following synchronization technique instead of using a controller object:

  • Set up named device objects to represent the devices that are targets for I/O requests.
  • Maintain state information (perhaps a set of Device Busy flags in each device extension or in a single device extension) indicating which device object is the target of the current I/O operation.
  • Carry out I/O operations for the currently busy device object and re-queue incoming IRPs for other device objects until the current IRP is completed.

The preceding synchronization technique serializes IRP processing for all of the driver's target device objects. Note that it also forces the driver to complete the current IRP before its StartIo routine can begin processing the next IRP, which unfortunately decreases driver performance.

If certain device operations can be overlapped, using a controller object can increase a driver's I/O throughput, because this synchronization technique allows the driver to determine whether it can overlap operations just before it sets up the physical device. For example, a disk controller might allow the driver to overlap seeks on one disk with read/write operations on another disk.

Moreover, using a controller object is a relatively easy way to synchronize I/O operations for more than one target device object through a single physical device, such as an "AT" disk controller. Using a controller object allows a monolithic driver to synchronize I/O operations across a set of named device objects without having to maintain state about every device and the device controller in one or more device extensions, and without having to re-queue IRPs.

However, some devices that are designed to overlap I/O operations, such as full-duplex serial controllers or bus-master adapters, generally have drivers that set up internal queues for IRPs.


Creating Controller Objects and Controller Extensions

If a driver uses a controller object, it must call IoCreateController after it has created device objects and its device is ready for I/O, typically after receiving a PnP IRP_MN_START_DEVICE request. The following figure illustrates the call.

Controller Object

Every controller object has an associated controller extension. As the previous figure shows, the caller of IoCreateController determines the Size of the controller extension. Its structure and contents are driver-defined.

In addition to whatever device-specific state information the driver maintains about the physical controller (or device with channels), the previous figure shows a representative set of driver-defined data for a controller extension.

The PtrToControllerObject pointer, returned by IoCreateController, must be passed in the driver's calls to IoAllocateController and IoFreeController, described in Allocating Controller Objects for I/O Operations. The driver must store the returned controller object pointer in the device extensions of its driver-created device objects or in another driver-accessible resident storage area (nonpaged pool, allocated by the driver). If the driver is unloaded, it also must pass the controller object pointer to IoDeleteController.

Most drivers that set up controller objects find it convenient to store a pointer to the current target device object or device extension in the controller extension. Usually, such a driver stores the controller object pointer in every one of its device extensions so that it can use the ControllerObject->ControllerExtension pointer to access driver-maintained, controller-specific state about I/O operations for every target device object.

If the physical controller represented by a controller object generates interrupts, a driver also can use the controller extension as storage for PtrToInterruptObject pointers returned by IoConnectInterrupt. See Interrupt Objects and ISRs for more information.

IoCreateController allocates resident storage for the controller object and extension, which it initializes with zeros. If it cannot allocate the memory, IoCreateController returns a NULL pointer. If this occurs, the driver must fail device startup and should return STATUS_INSUFFICIENT_RESOURCES.


Allocating Controller Objects for I/O Operations

After a driver that uses a controller object has started its device, it is ready to process IRPs sent to its target device objects. Whenever an IRP requires the driver to program the physical device represented by the controller object for an I/O operation, the driver calls IoAllocateController. The following figure illustrates such a call.

Allocating a Controller Object for I/O

As the previous figure shows, a driver must supply more than the ControllerObject pointer that was returned by IoCreateController when it calls IoAllocateController. Along with this pointer, it must pass pointers to the device object representing the target of the current I/O request, to a driver-supplied ControllerControl routine, and to whatever Context its ControllerControl routine will need to set up the device for the requested I/O operation.

IoAllocateController queues the driver-supplied ControllerControl routine if the device represented by the controller object is busy. Otherwise, the ControllerControl routine is called immediately with the input parameters shown in the previous figure. The input Context pointer to IoAllocateController is passed to the driver's ControllerControl routine when it is run.

Use the following guidelines to determine where to store context information:

  • The driver-supplied context area should not be in the controller extension unless the driver processes each IRP to completion before starting another operation on the physical controller. Otherwise, a context area in the controller extension could be overwritten by other driver routines or on receipt of a new IRP.
  • Even if the driver overlaps a device I/O operation for another device object, a context area in the device extension of the target device object cannot be overwritten.
  • If another I/O request is made for a particular device object and the driver has a StartIo routine, a context area in its device extension also cannot be overwritten because the incoming IRP will be queued when the driver calls IoStartPacket and the same IRP will remain in the device queue until the driver calls IoStartNextPacket just before it completes the current IRP for that device object.

The I/O Manager passes a pointer to the DeviceObject->CurrentIrp to a ControllerControl routine if the driver has a StartIo routine. If a driver manages its own queuing of IRPs instead of having a StartIo routine, the I/O Manager cannot give the ControllerControl routine a pointer to the current IRP. When the driver calls IoAllocateController, it should pass the current IRP as part of the Context-accessible data.

The driver routine that calls IoAllocateController must be executing at IRQL DISPATCH_LEVEL when the call occurs. A driver that makes this call from its StartIo routine is already running at DISPATCH_LEVEL.

The ControllerControl routine sets up the physical controller for the IRP's requested operation.

As shown in the previous figure, the ControllerControl routine returns a value of type IO_ALLOCATION_ACTION, which can be either of the following system-defined values:

  • If the ControllerControl routine can start another operation on the physical controller, it should return DeallocateObject so the driver can overlap the next requested I/O operation.

    For example, if the ControllerControl routine can program a disk controller for a seek operation on one disk, complete that IRP, and return DeallocateObject, the ControllerControl routine can be called again to program the disk controller for a transfer operation on the other disk if any transfer requests currently are queued to the other disk.

  • If the current IRP requires further processing by other driver routines, the ControllerControl routine must return KeepObject.

    For example, if the driver programs a disk controller for a transfer operation but cannot complete the IRP until the transfer is complete, the ControllerControl routine must return KeepObject.

When a ControllerControl routine returns KeepObject, usually the driver's ISR runs when the device interrupts, and its DpcForIsr or CustomDPC routine completes the I/O operation and the current IRP for the target device object.

Whenever the ControllerControl routine returns KeepObject, the routine that completes the IRP must call IoFreeController. Such a driver routine should call IoFreeController as soon as possible so that its next device I/O operation can be set up promptly.


Writing ControllerControl Routines

Drivers that use a controller object must supply a ControllerControl routine to initiate I/O operations.

A lowest-level device driver that must synchronize operations through a physical controller, such as an "AT" disk controller, to similar devices can have a ControllerControl routine.

When a driver calls IoAllocateController, its ControllerControl routine is run immediately if the hardware represented by the controller object is available for an I/O operation. Otherwise, the ControllerControl routine is queued until the controller is free.

WDM drivers cannot use controller objects and ControllerControl routines.


Storage Requirements for ControllerControl Routines

If it has a ControllerControl routine, a non-WDM driver must provide resident storage for a ControllerObject pointer returned by IoCreateController.

A driver can provide the necessary storage in a device extension or in nonpaged pool allocated by the driver. Usually, drivers that use controller objects store the ControllerObject pointer in the device extension of each device object that represents a physical or logical device controlled by the hardware represented by the controller object.

The driver writer determines the size and internal structure of the ControllerObject->ControllerExtension.

A controller object, which cannot be given a name, cannot be the target of an I/O request. The hardware it represents usually controls a set of homogeneous devices that are the actual targets of I/O requests.


Setting Up ControllerControl Routines

A driver's DispatchPnP routine must do the following when it receives an IRP_MN_START_DEVICE request, to set up a ControllerControl routine:

  1. Call IoCreateController to set up the controller object, specifying the driver-determined Size for the controller extension, which the system allocates from nonpaged pool and initializes with zeros.
  2. Save the ControllerObject pointer returned by IoCreateController, usually in the device extension of each device object representing a physical or logical device that is controlled by the hardware represented by the controller object.
  3. Set up and/or initialize the driver-determined contents of the ControllerObject->ControllerExtension.

The returned ControllerObject pointer, the entry point of the driver's ControllerControl routine, the DeviceObject pointer representing the target device for the current IRP, and a Context pointer to an area already set up for the ControllerControl routine must be passed in the driver's calls to IoAllocateController. Usually, a driver's StartIo routine sets up the area at Context before it calls IoAllocateController.


ControllerControl Routine Requirements

As its name implies, a ControllerControl routine is associated with a controller object. When the ControllerControl routine executes, the hardware represented by the controller object is free and the controller extension generally is not being accessed by another driver routine unless the controller extension contains context that is shared with the driver's ISR.

Usually, a ControllerControl routine does at least the following:

  1. Updates or initializes whatever context the driver maintains in the device extension of the target device object and in the controller extension

    If the driver uses DMA, its ControllerControl routine usually is responsible for determining whether a given transfer request must be split up into partial transfers due to any system-imposed or device-imposed limitations on the size of each DMA transfer. In these circumstances, the ControllerControl routine also is responsible for calling AllocateAdapterChannel if the driver has an AdapterControl routine.

    If the driver uses PIO, its ControllerControl routine also is responsible for splitting transfer requests, if its hardware requires it, into partial-transfer ranges and for calling MmGetSystemAddressForMdlSafe with the MDL at Irp->MdlAddress.

  2. Programs its hardware for the requested I/O operation

    If the device or controller extension can be accessed from the ISR, the ControllerControl routine must use a SynchCritSection routine that is invoked by calling KeSynchronizeExecution. For more information, see Using Critical Sections.

If the driver has a Cancel routine, its ControllerControl routine also must check the Irp->Cancel field to determine whether the current IRP should be canceled, and do either of the following:

If Irp->Cancel is set to TRUE, the ControllerControl routine must do the following:

  1. Set STATUS_CANCELLED for Status and zero for Information in the I/O status block of the IRP.
  2. Call IoFreeController to release the controller object so the next device operation can be started promptly.
  3. Call IoStartNextPacket or dequeue the next IRP if the driver manages its own queuing.
  4. Complete the canceled IRP with IoCompleteRequest and return control.

If Irp->Cancel is not set to TRUE, the ControllerControl routine instead must do the following:

  1. Call IoSetCancelRoutine to reset the Cancel routine entry point for the IRP to NULL. Acquire the cancel spin lock for this call if the driver uses the I/O-manager-supplied device queue in the device object.
  2. Program the hardware for the requested I/O operation, using a SynchCritSection routine that is invoked by calling KeSynchronizeExecution. For more information, see Using Critical Sections

For more information about handling cancelable IRPs, see Canceling IRPs.

For most interrupt-driven I/O operations except overlapped operations on different devices attached to the physical controller/adapter, a ControllerControl routine should return KeepObject because the DpcForIsr or CustomDpc routine completes the operation and the IRP.

As soon as the I/O operation(s) to satisfy the current request are done, the routine that will complete the IRP should call IoFreeController and IoStartNextPacket so that the next request can be processed as quickly as possible.

If the ControllerControl routine itself completes an IRP or if it can set up an operation, such as a disk seek, for one target device object (disk) that could be overlapped with an operation for another device object, the ControllerControl routine should return DeallocateObject.


Splitting Transfer Requests

Any driver might need to split up a transfer request and carry out more than one DMA transfer operation to satisfy a given IRP, depending on the following:

  • The number of map registers returned by IoGetDmaAdapter
  • The bytes of data to be transferred, contained in the Length member of the driver's I/O stack location for the IRP
  • The number of page boundaries, in system physical memory, for the buffer into which or from which the driver is to transfer data
  • Device-specific constraints on the driver's DMA operations. For example, the system "AT" disk driver must split up transfer requests for more than 256 sectors due to the disk controller's limitations.

A driver can determine the number of map registers needed to transfer all the data specified by an IRP as follows:

  1. Call MmGetMdlVirtualAddress, passing a pointer to the MDL at Irp->MdlAddress, to get the starting virtual address for the buffer. Note that a driver must not attempt to access memory using this virtual address. The value returned by MmGetMdlVirtualAddress is an index into the MDL, not necessarily a valid address.
  2. Pass the returned index and the value of Length in the driver's I/O stack location of the IRP to the ADDRESS_AND_SIZE_TO_SPAN_PAGES macro.

If the value returned by ADDRESS_AND_SIZE_TO_SPAN_PAGES is greater than the NumberOfMapRegisters value returned by IoGetDmaAdapter, the driver cannot transfer all requested data for this IRP in a single DMA operation. Instead, it must do the following:

  1. Split the buffer into pieces that are sized to suit the number of available map registers (and any device-specific DMA constraints).
  2. Carry out as many DMA operations as it takes to satisfy the transfer request.

For example, suppose ADDRESS_AND_SIZE_TO_SPAN_PAGES indicates that twelve map registers are needed to satisfy a transfer request, but the NumberOfMapRegisters value returned by IoGetDmaAdapter is only five. (Assume no device-specific DMA constraints.) In this case, the driver must carry out three DMA transfer operations, calling MapTransfer three times to transfer all the data requested by the IRP.

The system's DMA device drivers use various techniques to split up a DMA transfer when there are not enough map registers to satisfy an IRP with a single I/O operation. One technique to use is the following:

  1. Call IoAllocateMdl to allocate an MDL describing a portion of the user buffer.
  2. Call MmProbeAndLockPages to lock down that portion of the user buffer.
  3. Transfer the data for that portion of the buffer.
  4. Call MmUnlockPages and do either of the following:
    • If the MDL that the driver allocated in Step 1 is large enough for the next piece of the transfer, call MmPrepareMdlForReuse and repeat Steps 2 through 4.
    • Otherwise, call IoFreeMdl and repeat Steps 1 through 4.
  5. Call MmUnlockPages and IoFreeMdl when all the data has been transferred.

If a highest-level driver cannot lock down the entire user buffer with MmProbeAndLockPages in a machine with limited memory, it can do the following:

  1. Call IoBuildSynchronousFsdRequest to allocate a partial-transfer IRP and lock down a portion of the user buffer. The locked-down area is usually either a multiple of PAGE_SIZE or is sized to suit the underlying device's transfer capacity.
  2. Call IoCallDriver for the partial-transfer IRP, and call KeWaitForSingleObject to wait on an event object that the driver set up to be associated with its partial-transfer IRP, if lower drivers return STATUS_PENDING.
  3. When it regains control, repeat Steps 1 and 2 until all the data has been transferred, and, then, complete the original IRP.

When a storage class driver splits up large transfer requests for underlying SCSI port/miniport drivers, it allocates an additional IRP for each piece of the transfer request. It registers an IoCompletion routine for each driver-allocated IRP, to track the status of the full transfer request and to free the driver-allocated IRPs. Then it sends these IRPs on to the port driver using IoCallDriver.

Other class/port drivers can use this technique only if the class driver can determine how many map registers are available to the port driver. The port driver must store this configuration information in the registry for the paired class driver, or the paired drivers must define a private interface, using internal device I/O control requests, to pass configuration information about the number of available map registers from the port driver to the class driver.

A monolithic driver (that is, a driver not part of a class/port pair) for a DMA device must split up large transfer requests for itself. Such drivers usually split a large request into pieces and carry out a sequence of DMA operations in order to satisfy the IRP.

If a transfer request is too large for the underlying device driver to handle, a higher-level driver can call MmGetMdlVirtualAddress and IoBuildPartialMdl, then set up a sequence of partial-transfer IRPs for underlying device drivers.


Maintaining Cache Coherency

When a driver is transferring data between system memory and its device, data can be cached in one or more processor caches and/or in the system DMA controller's cache. Drivers that use DMA or PIO to service read/write IRPs or any device I/O control request that requires a DMA or PIO data transfer operation should ensure the integrity of possibly cached data during transfer operations. This section explains how to do so.

This section contains the following topics:

Flushing Cached Data During DMA Operations

Flushing Cached Data During PIO Operations


Flushing Cached Data during DMA Operations

In some platforms, the processor and system DMA controller (or busmaster DMA adapters) exhibit cache coherency anomalies.

To maintain data integrity during DMA operations, lowest-level drivers must follow these guidelines

  1. Call KeFlushIoBuffers before beginning a transfer operation to maintain consistency between data that might be cached in the processor and the data in memory.

    If a driver calls AllocateCommonBuffer with the CacheEnabled parameter set to TRUE, the driver must call KeFlushIoBuffers before beginning a transfer operation to/from its buffer.

  2. Call FlushAdapterBuffers at the end of each device transfer operation to be sure any remainder bytes in the system DMA controller's buffers have been written into memory or to the slave device.

    Or, call FlushAdapterBuffers at the end of each transfer operation for a given IRP to be sure all data has been read into system memory or written out to a busmaster DMA device.

The following figure shows why it is important to flush the processor cache before a read or write operation using DMA if the host processor and DMA controller do not automatically maintain cache coherency.

Read and Write Operations Using DMA

An asynchronous DMA read or write operation accesses data in memory, not in the processor cache. Unless this cache has been flushed by calling KeFlushIoBuffers just before a read, the data transferred into system memory by the DMA operation could be overwritten with stale data if the processor cache is flushed later. Unless the processor cache has been flushed by calling KeFlushIoBuffers just before a write, the data in this cache might be more up-to-date than the copy in memory.

KeFlushIoBuffers does nothing if the processor and DMA controller can be relied on to maintain cache coherency, so calls to this support routine have almost no overhead in such a platform.

As also shown in the previous figure, DMA controllers, which are represented by adapter objects, can have internal buffers. Such a DMA controller can transfer cached data in fixed-size chunks, usually eight or more bytes at a time. Moreover, these DMA controllers can wait until their internal buffers are full before each transfer operation.

Consider the case of a lowest-level driver that uses slave DMA to read data in variable-sized chunks or in fixed-size chunks that are not an integral multiple of a system DMA controller's cache size. Unless this driver calls FlushAdapterBuffers at the end of each device transfer, it cannot be sure when every byte the driver requested actually will be transferred.

The driver of a bus-master DMA device also should call FlushAdapterBuffers at the end of each transfer operation for an IRP to be sure that all data has been transferred into system memory or out to the device.

FlushAdapterBuffers returns a Boolean, value that indicates whether the requested flush operation was successful. A driver can use this value to determine how to set the I/O status block when completing an IRP for a DMA read or write operation.


Flushing Cached Data during PIO Operations

On some platforms, the instruction and data caches in the processor exhibit cache coherency anomalies during PIO read operations.

Note To maintain data integrity during their read operations, drivers that use PIO must follow this guideline:

Call KeFlushIoBuffers at the end of each read operation.

For example, a driver making a PIO transfer from its device to system memory should call KeFlushIoBuffers at the end of each device transfer operation. As another example, a driver that reads a sequence of device registers into system memory should call KeFlushIoBuffers at the end of the sequence. Otherwise, such a driver might attempt to access data that is still in the processor's data cache, rather than in system memory, on some platforms.

KeFlushIoBuffers does nothing if the processor can be relied on to maintain cache coherency, so calls to this support routine have almost no overhead in such a platform.


Polling a Device

A device driver should avoid polling its device unless absolutely necessary, and should never use a whole time-slice for polling. Polling a device is an expensive operation that makes any operating system compute-bound within the polling driver. A device driver that does much polling interferes with I/O operations on other devices and can make the system slow and unresponsive to users.

Recently developed devices, which are as technologically advanced as the processors on which Windows is designed to run, seldom require a driver to poll its device, either to ensure that the device is ready to start an I/O operation or that an operation is complete.

Nevertheless, some devices still in use were designed to work with old processors, which had narrow data buses, slow clock rates, and single-user, single-tasking operating systems that did synchronous I/O. Such devices might require polling or some other means of waiting for the device to update its registers.

Although it might seem logical to solve a slow-device problem by coding a simple loop that increments a counter, thereby "wasting" a minimum interval while the device updates registers, such a driver is unlikely to be portable across Windows platforms. The loop counter maximum would require customization for each platform. Furthermore, if the driver is compiled with a good optimizing compiler, the compiler might remove the driver's counter variable and the loop(s) where it is incremented.

Note Follow this implementation guideline if the driver must stall while the device hardware updates state:

A driver can call KeStallExecutionProcessor before it reads device registers. The driver should minimize the interval it stalls and should, in general, specify a stall interval no longer than 50 microseconds.

The granularity of a KeStallExecutionProcessor interval is one microsecond.

If the device frequently requires more than 50 microseconds to update state, consider setting up a device-dedicated thread in the driver.


Accessing Device Configuration Space

Some buses provide a way of accessing a special configuration space for each device attached to the bus. This section explains how a driver can get information from a target device's configuration space, provided the driver is loaded in the same driver stack as the driver for the target device, either as a function driver or a filter driver.

In Microsoft® Windows NT® 4.0, drivers get information from a target device's configuration space by scanning the bus and calling the HalGetBusData and HalGetBusDataByOffset routines. In Windows® 2000 and later operating systems, the hardware buses are controlled by their respective bus drivers and not by HAL. Therefore, all of the HAL routines that used to help drivers retrieve bus-related information are obsolete in Windows2000.

The configuration space for a device contains a description of the device and its resource requirements. On Windows 2000 and later operating systems, a driver does not need to query a device to find resources. The driver gets the resources from the Plug and Play (PnP) manager in its IRP_MN_START_DEVICE request. Typically, a well-written driver would not require any of this information to function correctly. If for some reason the driver requires this information, the code sample in the Obtaining Device Configuration Information at Passive IRQL section shows how to get the resources. The driver must be part of the target device's driver stack, because it requires the underlying physical device objects (PDO) of the target device to send the appropriate PnP request.


Obtaining Device Configuration Information at Passive IRQL

The following code sample demonstrates how to get the configuration information:

NTSTATUS
ReadWriteConfigSpace(
    IN PDEVICE_OBJECT DeviceObject,
    IN ULONG          ReadOrWrite, // 0 for read 1 for write
    IN PVOID          Buffer,
    IN ULONG          Offset,
    IN ULONG          Length
    )
{
    KEVENT event;
    NTSTATUS status;
    PIRP irp;
    IO_STATUS_BLOCK ioStatusBlock;
    PIO_STACK_LOCATION irpStack;
    PDEVICE_OBJECT targetObject;

    PAGED_CODE();
    KeInitializeEvent( &event, NotificationEvent, FALSE );
    targetObject = IoGetAttachedDeviceReference( DeviceObject );
    irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP,
                                        targetObject,
                                        NULL,
                                        0,
                                        NULL,
                                        &event,
                                        &ioStatusBlock );
    if (irp == NULL) {
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto End;
    }
    irpStack = IoGetNextIrpStackLocation( irp );
    if (ReadOrWrite == 0) {
        irpStack->MinorFunction = IRP_MN_READ_CONFIG;
    }else {
        irpStack->MinorFunction = IRP_MN_WRITE_CONFIG;
    }
    irpStack->Parameters.ReadWriteConfig.WhichSpace = PCI_WHICHSPACE_CONFIG;
    irpStack->Parameters.ReadWriteConfig.Buffer = Buffer;
    irpStack->Parameters.ReadWriteConfig.Offset = Offset;
    irpStack->Parameters.ReadWriteConfig.Length = Length;
    // Initialize the status to error in case the bus driver does not
    // set it correctly.
    irp->IoStatus.Status = STATUS_NOT_SUPPORTED ;
    status = IoCallDriver( targetObject, irp );
    if (status == STATUS_PENDING) {
        KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );
        status = ioStatusBlock.Status;
    }
End:
    // Done with reference
    ObDereferenceObject( targetObject );
    return status;
}


Obtaining Device Configuration Information at Raised IRQL

The method illustrated in the Obtaining Device Configuration Information at Passive IRQL section makes use of I/O request packets (IRPs) and therefore is only valid for drivers running at IRQL = PASSIVE_LEVEL. Drivers running at IRQL = DISPATCH_LEVEL must use a bus interface to obtain device configuration space data. To obtain this data, you can use a bus-specific interface or the system-supplied bus-independent bus interface, BUS_INTERFACE_STANDARD.

It is preferable to use BUS_INTERFACE_STANDARD where possible, because a bus number is not required to retrieve configuration information when using BUS_INTERFACE_STANDARD, whereas drivers must often identify the bus number when retrieving bus-specific interfaces. Bus numbers for some buses, such as PCI, can change dynamically. Therefore, drivers should not depend on the bus number to access the PCI ports directly. Doing so might lead to system failure.

Three steps are required when accessing the configuration space of a PCI device at IRQL = DISPATCH_LEVEL:

  1. Send an IRP_MN_QUERY_INTERFACE request at IRQL = PASSIVE_LEVEL to get the direct-call interface structure (BUS_INTERFACE_STANDARD) from the PCI bus driver. Store this in a nonpaged pool memory (typically in a device extension).
  2. Call the BUS_INTERFACE_STANDARD interface routines, SetBusData and GetBusData, to access the PCI configuration space at IRQL = DISPATCH_LEVEL.
  3. Dereference the interface. The PCI bus driver takes a reference count on the interface before it returns, so the driver that accesses the interface must dereference it, once it is no longer needed.

The following code sample demonstrates how to implement these three steps:

NTSTATUS
GetPCIBusInterfaceStandard(
    IN  PDEVICE_OBJECT DeviceObject,
    OUT PBUS_INTERFACE_STANDARD    BusInterfaceStandard
    )
/*++
Routine Description:
    This routine gets the bus interface standard information from the PDO.
Arguments:
    DeviceObject - Device object to query for this information.
    BusInterface - Supplies a pointer to the retrieved information.
Return Value:
    NT status.
--*/
{
    KEVENT event;
    NTSTATUS status;
    PIRP irp;
    IO_STATUS_BLOCK ioStatusBlock;
    PIO_STACK_LOCATION irpStack;
    PDEVICE_OBJECT targetObject;

    Bus_KdPrint(("GetPciBusInterfaceStandard entered.\n"));
    KeInitializeEvent( &event, NotificationEvent, FALSE );
    targetObject = IoGetAttachedDeviceReference( DeviceObject );
    irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP,
                                        targetObject,
                                        NULL,
                                        0,
                                        NULL,
                                        &event,
                                        &ioStatusBlock );
    if (irp == NULL) {
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto End;
    }
    irpStack = IoGetNextIrpStackLocation( irp );
    irpStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
    irpStack->Parameters.QueryInterface.InterfaceType =
                        (LPGUID) &GUID_BUS_INTERFACE_STANDARD ;
    irpStack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);
    irpStack->Parameters.QueryInterface.Version = 1;
    irpStack->Parameters.QueryInterface.Interface = (PINTERFACE)
BusInterfaceStandard;
    irpStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
    // Initialize the status to error in case the bus driver does not
    // set it correctly.
    irp->IoStatus.Status = STATUS_NOT_SUPPORTED ;
    status = IoCallDriver( targetObject, irp );
    if (status == STATUS_PENDING) {
        KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );
        status = ioStatusBlock.Status;
    }
End:
    // Done with reference
    ObDereferenceObject( targetObject );
    return status;
}

The following code snippet shows how to use the GetBusData interface routine to get the configuration space data (step 2).

    bytes = busInterfaceStandard.GetBusData(<BR/>
                    busInterfaceStandard.Context,
                    PCI_WHICHSPACE_CONFIG,
                    Buffer
                    Offset,
                    Length);

When the driver is done with the interface, it can use code similar to the following snippet to dereference the interface (step 3). Drivers must not call interface routines after dereferencing the interface.

    (busInterfaceStandard.InterfaceDereference)(
                (PVOID)busInterfaceStandard.Context);

The interface synchronizes the caller's access to the bus hardware with the PCI bus driver's access. The driver writer need not worry about creating spin locks to avoid contending with the PCI bus driver for access to bus hardware.

Note, that if all that is needed are bus, function, and device numbers, it is usually unnecessary to resort to a bus interface to obtain this information. This data can be retrieved indirectly by passing the PDO of the target device to the IoGetDeviceProperty function as follows:

    ULONG   propertyAddress, length;
    USHORT  FunctionNumber; DeviceNumber;
    // Get the BusNumber. Be warned that bus numbers may be
    // dynamic and therefore subject to change unpredictably!!!
    IoGetDeviceProperty(PhysicalDeviceObject,
                        DevicePropertyBusNumber,
                        sizeof(ULONG),
                        (PVOID)&BusNumber,
                        &length);
    // Get the DevicePropertyAddress
    IoGetDeviceProperty(PhysicalDeviceObject,
                     DevicePropertyAddress,
                     sizeof(ULONG),
                     (PVOID)&propertyAddress,
                     &length);
    // For PCI, the DevicePropertyAddress has device number
    // in the high word and the function number in the low word.
    FunctionNumber = (USHORT)((propertyAddress) & 0x0000FFFF);
    DeviceNumber = (USHORT)(((propertyAddress) >> 16) & 0x0000FFFF);


Obtaining Configuration Information from Other Driver Stacks

At times you need to obtain information from the configuration space of a device whose driver is on a stack other than the one that your driver is on. For instance, suppose you want to set a bit in the configuration space of a PCI-to-PCI bridge and you do not have a pointer to the PDO of the bridge. Although the operating system enumerates PCI-to-PCI bridges and creates a PDO for every bridge on the system, it does not register device interfaces for these devices. Therefore, you cannot use the device interface mechanism to access the configuration space of these bridges. For more information on device interfaces see Introduction to Device Interfaces.

In Windows NT 4.0, drivers could access the configuration space of such devices using the HalGetBusData and HalSetBusData routines. In Windows 2000 and later operating systems, this is no longer the case.

Windows 2000 and later operating systems do not allow drivers to access hardware belonging to other driver stacks. A filter driver can be written to provide the functionality needed. If you wish to access bridge hardware, for instance, you must design a filter driver that implements the required operations on the bridge's configuration space. You must also provide an INF file that specifies the bridge hardware's possible hardware IDs, so the PnP Manager can load the filter driver onto the bridge's driver stack when it detects the device ID of the bridge.

Alternatively, you can install a filter programmatically using SetupDiXxx functions in the coinstaller for your device.

The filter driver can then access the bridge using the BUS_INTERFACE_STANDARD interface.


Servicing Interrupts

This section contains the following sections:

Interrupt Objects and ISRs

DPC Objects and DPCs

Using Critical Sections

Managing Hardware Priorities


Interrupt Objects and ISRs

This section contains the following topics:

Introduction to Interrupt Objects

Registering an ISR

Providing ISR Context Information

Writing an ISR

Synchronizing Access to Device Data


Introduction to Interrupt Objects

Each driver of a physical device that generates interrupts must register an InterruptService routine (ISR) before it starts the device. When a driver registers an ISR, the system creates an interrupt object. These system-defined objects are used to store the following information:

  • The set of processors on which interrupts can occur (processor affinity)

    The system creates an interrupt object for each processor the device is capable of interrupting. However, the system can perform load balancing by restricting a particular device interrupt to a subset of available processors.

  • The system-assigned interrupt vectors for each device on each I/O bus in the machine

    For multibus machines, the PnP Manager maps bus-relative interrupt vectors of the devices on each I/O bus to a set of system-assigned interrupt vectors.

  • The DIRQL assigned to each system interrupt vector

    For a lowest-level driver, the DIRQL value assigned to its mapped system vector determines the hardware priority at which that driver's ISR executes.

  • The address of the InterruptService routine, which will be called when the device interrupts.
  • Additional information for internal use by the system.

The PnP Manager queries bus drivers for configuration information (such as processor affinity, DIRQ, interrupt vector, and so on) during enumeration, and passes the information to drivers as hardware resources during device start-up operations.

A platform-specific HAL provides hardware-specific software support for the I/O buses, peripherals, and processors in each machine. The PnP Manager communicates with the HAL to obtain information about platform-specific support, which it can then supply to drivers. Drivers then use this information when registering ISRs.

Use of interrupt objects enables drivers to be portable across all Windows platforms, including SMP machines with several I/O buses of various types (ISA, EISA, PCI and so forth). This portability is possible because drivers do not access hardware directly; instead, they pass interrupt object pointers to system routines that access object contents.

Drivers do not directly access the contents of interrupt objects, and their structure is not documented.

For more information about interrupt objects, see Inside Windows NT, from Microsoft Press.


Registering an ISR

To register an ISR, a driver's DispatchPnP routine must call IoConnectInterrupt when it receives an IRP_MN_START_DEVICE request. In response, the I/O Manager creates an interrupt object for each processor that the device can interrupt.

Connecting to a Single Interrupt Vector

If the ISR handles a single device that uses a single interrupt vector, the driver should specify the following parameters when calling IoConnectInterrupt:

  • The address of a driver-allocated location that receives the interrupt object pointer returned by IoConnectInterrupt.
  • The ISR's entry point.
  • A pointer to driver-supplied information the ISR will use when it is called (see Providing ISR Context Information).
  • A NULL spin lock pointer, which indicates that the driver will use an internal interrupt spin lock provided by the system (see Synchronizing Access to Device Data).
  • The device's interrupt vector, obtained from a CmResourceTypeInterrupt resource in the CM_RESOURCE_LIST structure for translated resources, received in the IRP_MN_START_DEVICE IRP.
  • The device's DIRQL, obtained from a CmResourceTypeInterrupt resource in the CM_RESOURCE_LIST structure for translated resources, received in the IRP_MN_START_DEVICE IRP. (Use this value for both the Irql and SynchronizeIrql parameters.)
  • The device's interrupt triggering mode (level-sensitive or latched), obtained from the Flags member of a CmResourceTypeInterrupt resource, in the CM_RESOURCE_LIST structure for translated resources received in the IRP_MN_START_DEVICE IRP.
  • A Boolean value indicating whether the device can share the vector, calculated by examining the ShareDisposition member of a CmResourceTypeInterrupt resource, in the CM_RESOURCE_LIST structure for translated resources received in the IRP_MN_START_DEVICE IRP.
  • A processor affinity mask value, indicating the set of processors the device can interrupt on the machine, obtained from a CmResourceTypeInterrupt resource in the CM_RESOURCE_LIST structure for translated resources, received in the IRP_MN_START_DEVICE IRP.
  • A value indicating whether the system should save floating-point registers when the device interrupts (this must be FALSE for platform-independent drivers).

In response to the IoConnectInterrupt call, the I/O Manager does the following

  1. Allocates sufficient resident memory for as many interrupt objects as the processor affinity mask indicates, which could be as many interrupt objects as processors in SMP machines or could be a lesser number. The I/O Manager also provides an internal interrupt spin lock and initializes it if the driver passes a NULL pointer to IoConnectInterrupt.
  2. Initializes each interrupt object and connects it to a particular processor in the machine. To connect the interrupt object, this call sets the specified interrupt vector in the kernel's Interrupt Dispatch Table (IDT) for each specified processor. (For more information about IDTs, see Inside Windows NT from Microsoft Press.)

When all interrupt objects have been initialized and connected to the processors, IoConnectInterrupt returns a pointer to the set of interrupt objects. Driver routines must pass the returned pointer when calling KeSynchronizeExecution.

When a device interrupts one of a machine's processors, the driver's ISR executes on that processor at DIRQL and receives the context pointer that the driver specified when calling IoConnectInterrupt.

Connecting to Multiple Interrupt Vectors

If a driver must handle interrupts from more than one device, each with a different interrupt vector, or if a single device can interrupt through more than one interrupt vector, the driver can have a single multi-vector ISR, or it can have multiple ISRs.

Such a driver must call IoConnectInterrupt for each interrupt vector. It must also allocate a spin lock for each interrupt vector. The following steps must be used:

  1. The driver must call KeInitializeSpinLock with a pointer to driver-provided, resident storage for an interrupt spin lock (in a device extension, controller extension, or nonpaged pool allocated by the driver).
  2. For each interrupt vector a driver's devices use, the driver calls IoConnectInterrupt as described previously for connecting to a single interrupt vector, except for the following parameters:
    • The SpinLock value must be the spin lock pointer initialized by KeInitializeSpinlock.
    • The SynchronizeIrql value must be the highest DIRQL assigned to any device for which its ISRs handle interrupts.

For more information, see Synchronizing Access to Device Data.


Providing ISR Context Information

On entry, an ISR receives a pointer to whatever context area the driver set up when it called IoConnectInterrupt.

Most drivers set the context pointer to the device object that represents the physical device that generates interrupts, or to that device object's device extension. In the device extension, the driver can store state information for the driver's ISR and DpcForIsr routine, the latter of which usually does almost all of the I/O processing to satisfy each request that caused the device to interrupt.

Typically, drivers use the device extension to store pointers to each of the device's interrupt objects (returned from calls to IoConnectInterrupt). Drivers also typically store information in the device extension that allows an ISR to determine if an interrupt was issued by a device the ISR supports.

(Alternatively, interrupt object pointers can be stored in nonpaged pool allocated by the driver, or in a controller extension if a non-WDM driver creates a controller object.)


Writing an ISR

Drivers for physical devices that generate interrupts must have at least one InterruptService routine (ISR). The ISR must do whatever is appropriate to the device to dismiss the interrupt, possibly including stopping the device from interrupting. Then, it should do only what is necessary to save state and queue a DPC to finish the I/O operation at a lower priority (IRQL) than that at which the ISR executes.

A driver's ISR executes in an interrupt context, at some system-assigned DIRQL, as specified by the SynchronizeIrql parameter to IoConnectInterrupt.

ISRs are interruptible. Another device with a higher system-assigned DIRQL can interrupt, or a high-IRQL system interrupt can occur, at any time.

Before the system calls an ISR, it acquires the interrupt's spin lock so the ISR cannot simultaneously execute on another processor. After the ISR returns, the system releases the spin lock.

Because an ISR runs at a relatively high IRQL, which masks off interrupts with an equivalent or lower IRQL on the current processor, it should return control as quickly as possible. Additionally, running an ISR at DIRQL restricts the set of support routines the ISR can call. For more information see Managing Hardware Priorities.

Typically, an ISR performs the following general steps:

  • If the device that caused the interrupt is not one supported by the ISR, the ISR immediately returns FALSE.
  • Otherwise, the ISR clears the interrupt, saving whatever device context is necessary, and queues a DPC to complete the I/O operation at a lower IRQL. See DPC Objects and DPCs for more information. The ISR must then return TRUE.

Specifically, in drivers that do not overlap device I/O operations, the ISR should do the following:

  1. Determine whether the interrupt is spurious. If so, return FALSE immediately so the ISR of the device that interrupted will be called promptly. Otherwise, continue interrupt processing.
  2. Stop the device from interrupting.
  3. Gather whatever context information the DpcForIsr (or CustomDpc) routine will need to complete I/O processing for the current operation.
  4. Store this context in an area accessible to the DpcForIsr or CustomDpc routine, usually in the device extension of the target device object for which processing the current I/O request caused the interrupt.

    If a driver overlaps I/O operations, the context information must include a count of outstanding requests the DPC routine is required to complete, along with whatever context the DPC routine needs to complete each request. If the ISR is called to handle another interrupt before the DPC has run, it must not overwrite the saved context for a request that has not yet been completed by the DPC.

  5. If the driver has a DpcForIsr routine, call IoRequestDpc with pointers to the current IRP, the target device object, and the saved context. IoRequestDpc queues the DpcForIsr routine to be run as soon as IRQL falls below DISPATCH_LEVEL on a processor.

    If the driver has a CustomDpc routine, call KeInsertQueueDpc with a pointer to the DPC object (associated with the CustomDpc routine) and pointer(s) to any saved context the CustomDpc routine will need to complete the operation. Usually, the ISR also passes pointers to the current IRP and the target device object. The CustomDpc routine is run as soon as IRQL falls below DISPATCH_LEVEL on a processor.

  6. Return TRUE to indicate that its device generated the interrupt.

In general, an ISR does no actual I/O processing to satisfy an IRP. Instead, it stops its device from interrupting, sets up necessary state information, and queues the driver's DpcForIsr or CustomDpc to do whatever I/O processing is necessary to satisfy the current request that caused the device to interrupt.

An ISR must run at DIRQL for the shortest possible interval. Following this guideline increases I/O throughput for every device in the machine because running at DIRQL masks off all interrupts to which the system has assigned a lesser or equal IRQL value.

The SynchronizeIrql of the driver's interrupt objects, specified when the driver called IoConnectInterrupt, determines the DIRQL at which the driver's ISR executes. For more information, see Synchronizing Access to Device Data.


Synchronizing Access to Device Data

Typically, a driver's InterruptService routines (ISRs) must share access to driver data and hardware resources with other driver routines. Since ISRs execute in an interrupt context at an elevated IRQL, and since a system might have multiple processors, it is important to synchronize access to shared data and resources so that each routine can be guaranteed to temporarily have exclusive access to this shared information, without interruption.

The system supports this synchronization by enabling you to define critical sections of code. These critical sections must be the only places where shared data and resources are accessed. The system guarantees this code exclusive access to shared information by raising the processor's IRQL and acquiring a spin lock before executing the code. Critical sections reside only in ISRs and SynchCritSection routines. The system calls an ISR when a device interrupts. Drivers call SyncCritSection routines by using KeSynchronizeExecution.

Raising the processor's IRQL to the device's DIRQL value prevents the current processor from being interrupted, except by a higher-priority device. Acquiring a spin lock prevents other processors from executing any critical section code associated with that spin lock. (This spin lock is sometimes called an interrupt spin lock.)

A driver specifies the DIRQL value and spin lock the system will use by supplying SynchronizeIrql and SpinLock parameters when calling IoConnectInterrupt. The values specified for these parameters should be determined as follows:

SynchronizeIrql
If a device uses a single interrupt vector, SynchronizeIrq should be set to the device's DIRQL. If the driver supports multiple interrupt vectors and must access the same set of registers or data for each vector, it must call IoConnectInterrupt for each vector and the SynchronizeIrql value must be the highest DIRQL used with any of the vectors.
SpinLock
If a device uses a single interrupt vector, SpinLock should be NULL, which causes the system to allocate a spin lock for the vector. If the driver supports multiple interrupt vectors and must access the same set of registers or data for each vector, the driver must call KeInitializeSpinLock to allocate a spin lock, and then specify that spin lock to each call to IoConnectInterrupt.

For a driver that supports a single vector, critical sections execute at the device's DIRQL, and they use a system-supplied spin lock. For a driver that supports multiple vectors and a single set of resources, all critical sections execute at the highest DIRQL used by any interrupt, and they all use a single, driver-supplied spin lock.

For information about writing and calling critical sections, see Using Critical Sections.

The alternative to using critical sections is to serialize IRP processing. That is, a driver would have to complete each I/O request before starting device I/O operations for the next IRP. While this makes it almost impossible for the ISR and another routine, such as a DpcForIsr or CustomDpc routine, to access shared state concurrently, handling IRPs in this manner severely limits I/O throughput for most devices. Note that a driver that serializes its IRP processing can run no faster on SMP machines than in uniprocessor machines.


DPC Objects and DPCs

This section contains the following topics:

Introduction to DPC Objects

Introduction to DPCs

Which Type of DPC Should You Use?

Registering and Queuing a DpcForIsr Routine

Registering and Queuing a CustomDpc Routine

Handling Overlapped I/O Operations

Writing DPC Routines

Guidelines for Writing DPC Routines


Introduction to DPC Objects

Because ISRs must execute as quickly as possible, drivers must usually postpone the completion of servicing an interrupt until after the ISR returns. Therefore, the system provides support for deferred procedure calls (DPCs), which can be queued from ISRs and which are executed at a later time and a lower IRQL than the ISR.

Each DPC is associated with a system-defined DPC object. The system supplies one DPC object for each device object. The system initializes this DPC object when a driver registers a DPC routine known as the DpcForIsr routine. A driver can create additional DPC objects if more than one DPC is needed. These extra DPCs are known as CustomDPC routines.

DPC object contents should not be directly referenced by drivers. The object's structure is not documented. Drivers do not have access to the system-supplied DPC object assigned to each device object. Drivers allocate storage for extra DPCs, but the contents of these DPC objects should only be referenced by system routines.

DPC objects and DPCs can also be used with timers. For more information, see Timer Objects and DPCs.


Introduction to DPCs

Any driver that has an ISR typically also has at least one DpcForIsr or CustomDpc routine to complete processing of interrupt-driven I/O operations. A typical lowest-level driver's DpcForIsr or CustomDpc routine does the following:

  • Finishes handling an I/O operation that the ISR began processing.
  • Dequeues the next IRP so that the driver can begin processing it.
  • Completes the current IRP, if possible.

Sometimes the current IRP can't be completed because several data transfers are required, or a recoverable error was detected. In these cases, the DpcForIsr or CustomDpc routine typically reprograms the device for either another transfer or a re-try of the last operation.

A DpcForIsr or CustomDpc routine is called in an arbitrary DPC context at IRQL DISPATCH_LEVEL. Running at DISPATCH_LEVEL restricts the set of support routines a DpcForIsr or CustomDpc routine can call. See Managing Hardware Priorities for more information.

DPC objects and DPCs can also be used with timers. For more information, see Timer Objects and DPCs.


Which Type of DPC Should You Use?

Depending on a driver's design, it can have any of the following:

  • A single DpcForIsr to complete all interrupt-driven I/O operations
  • A set of one or more CustomDpc routines.
  • Both a DpcForIsr and a set of operation-specific CustomDpc routines

Whether a driver has a single DpcForIsr routine, a set of CustomDpc routines, or both, depends on the nature of its underlying device and the set of I/O requests it must support.

Most lowest-level device drivers have a single DpcForIsr routine to complete I/O processing for each IRP that requires one or more operations on their respective devices. Using a single DpcForIsr to complete per-request, interrupt-driven I/O operations on a device that does one operation at a time is relatively easy. Such a driver's ISR need only call IoRequestDpc for each interrupt-driven I/O operation.

Few lowest-level drivers have CustomDpc routines unless their devices require more than one DPC to complete a varied set of interrupt-driven I/O operations.

Using a single DpcForIsr to complete overlapped, interrupt-driven I/O operations on a device that can do concurrent operations is possible with careful design, but can be relatively difficult. In addition to or instead of queuing a DpcForIsr, an ISR can queue a set of operation-specific, driver-supplied CustomDpc routines by calling KeInsertQueueDpc.

For example, consider some of the design challenges involved in writing a serial driver. As the driver of a full-duplex device, a serial driver cannot rely on a one-to-one correspondence between the order in which IRPs are queued to a StartIo routine and the sequence of interrupts from its device in a multitasking, multiprocessor system. Furthermore, serial drivers must handle timing out requests and asynchronous user-generated requests to cancel previously requested operations, to purge buffered data, and so forth.

Consequently, a serial driver might maintain internal queues for the read, write, purge, and wait operations that user-mode COM port applications can request. It also could maintain reference counts or use some other tracking mechanism, such as a set of flags, for the IRPs in its internal queues. Its ISR would call KeInsertQueueDpc with any of a number of driver-allocated and initialized DPC objects, each associated with a driver-supplied CustomDpc routine.


Registering and Queuing a DpcForIsr Routine

A driver registers a DpcForIsr routine for a device object by calling IoInitializeDpcRequest after it has created the device object. The driver can make this call from its AddDevice routine, or from DispatchPnP code that handles IRP_MN_START_DEVICE requests.

To queue the DpcForIsr routine for execution, the driver's ISR calls IoRequestDpc just before it returns. The following figure illustrates calls to these routines.

Using a DPC Object for a DpcForIsr Routine

As the previous figure shows, calling IoInitializeDpcRequest associates a DPC object with a driver-supplied DpcForIsr routine and a driver-created device object. The I/O Manager allocates memory for the DPC object and calls KeInitializeDpc on the driver's behalf.

When the ISR is called to handle a device interrupt at DIRQL, it should return control to the system as soon as possible for better overall system and driver performance. Usually, an ISR merely clears the interrupt, gathers whatever context information the DpcForIsr routine needs to complete the operation that caused the interrupt, calls IoRequestDpc, and returns.

When the ISR calls IoRequestDpc, it passes a pointer to the device object, a pointer to the DeviceObject->CurrentIrp, and a pointer to a driver-determined context. The I/O Manager calls KeInsertQueueDpc on the driver's behalf, which queues the DPC object. When IRQL falls below DISPATCH_LEVEL on a processor, the kernel dequeues the DPC object and runs the driver's DpcForIsr routine on that processor at IRQL DISPATCH_LEVEL.

The DpcForIsr routine is responsible for doing whatever is necessary to complete the I/O requested in the current IRP. On entry, the routine receives a pointer to the DPC object, along with pointers to the device object, IRP, and context area, which were passed in the ISR's call to IoRequestDpc. The context area must be in resident memory, and is usually in the device extension. Alternatively, it can be in nonpaged pool allocated by the driver, or in a controller extension if the driver uses a controller object.

Because ISR and DpcForIsr routines can run concurrently on SMP machines, you must follow these guidelines:

  • The ISR must call IoRequestDpc just before it returns control. Otherwise, the DpcForIsr routine might be run on another processor before the ISR has finished setting up the context area for the DpcForIsr routine.
  • The DpcForIsr routine and any other driver routine that shares a context area with the ISR must call KeSynchronizeExecution, specifying a driver-supplied SynchCritSection routine that accesses the shared context area in a multiprocessor-safe manner.
  • If a driver uses the device extension to maintain context about its device I/O operations, the DpcForIsr routine should never call IoStartNextPacket for the input device object (nor dequeue an IRP for the input device object, if the driver manages its own IRP queuing) until just before it calls IoCompleteRequest.

    Otherwise, the driver's StartIo (or queue-management routines) might start another I/O operation that overwrites the shared context area before the DpcForIsr routine can complete the current operation. This is because the ISR can be called again if the device interrupts while or before the DpcForIsr routine executes (assuming interrupts are still enabled).

Even on a uniprocessor machine, the ISR could be called again if the device interrupts while or before the DpcForIsr routine is run. If this occurs, the DpcForIsr routine is run only once. In other words, there is no one-to-one correspondence between an ISR's calls to IoRequestDpc and instantiations of the DpcForIsr routine if a driver overlaps I/O operations for its target device objects.


Registering and Queuing a CustomDpc Routine

A driver registers a CustomDpc routine for a device object by calling KeInitializeDpc after it has created the device object. The driver can make this call from its AddDevice routine, or from DispatchPnP code that handles IRP_MN_START_DEVICE requests.

Just before the driver's ISR returns control, it can call KeInsertQueueDpc to queue the CustomDpc routine for execution. The following figure illustrates calls to these routines.

Using a DPC Object for a CustomDpc Routine

As the previous figure shows, a driver that has a CustomDpc routine must provide the storage for a DPC object. Because the driver must pass a pointer to the DPC object from its ISR, the storage must be in resident, system-space memory. Most drivers with CustomDpc routines provide storage for their DPC objects in the device extension, but the storage can be in a controller extension if the driver uses a controller object or in nonpaged pool allocated by the driver.

When the driver calls KeInitializeDpc, it must pass the entry point for its CustomDpc routine, along with pointers to the driver-allocated storage for the DPC object and to a driver-defined context area, which is passed to the CustomDpc routine when it is called. Because the context area must be accessible at raised IRQL, it also must be in resident memory.

Unlike a DpcForIsr routine, a CustomDpc routine is not associated with a device object. Nevertheless, drivers typically include pointers to the target device object and current IRP in the context information supplied to the CustomDpc routine. Like a DpcForIsr routine, the CustomDpc routine uses this information to complete an interrupt-driven I/O operation at a lower IRQL than the ISR.

As the previous figure shows, the ISR passes pointers to the DPC object and to two additional parameters, which are driver-defined, to KeInsertQueueDpc. If all processors in the machine currently have code running at an IRQL greater than or equal to DISPATCH_LEVEL, the DPC object is queued until the IRQL falls below DISPATCH_LEVEL on a processor. Then, the kernel dequeues the DPC object and the driver's CustomDpc routine is run on the processor at IRQL DISPATCH_LEVEL.

Only a single instantiation of any one DPC object can be queued at any given moment. Thus if an ISR calls KeInsertQueueDpc more than once with the same Dpc pointer before the driver's CustomDpc routine is run, the CustomDpc routine runs only once after IRQL falls below DISPATCH_LEVEL on a processor.

A CustomDpc routine is responsible for doing whatever is necessary to complete the I/O operation that caused the interrupt.

The ISR and CustomDpc routines can be run concurrently on an SMP machine. Therefore, when writing CustomDpc routines, follow the guidelines set out in the previous section, Registering and Queuing a DpcForIsr Routine.


Handling Overlapped I/O Operations

The DpcForIsr or CustomDpc routine of a driver that overlaps operations on its device cannot rely on a one-to-one correspondence between requests input to the StartIo routine and the ISR's calls to IoRequestDpc or KeInsertQueueDpc. Such a driver's DpcForIsr or CustomDpc cannot necessarily use the input pointers to the IRP and ISR-supplied context, or the CurrentIrp pointer in the target device object, to complete only that IRP.

At any given moment, the same DPC object cannot be queued twice. If an ISR calls IoRequestDpc or KeInsertQueueDpc more than once before the corresponding DpcForIsr or CustomDpc executes, the DPC routine runs only once when the IRQL on a processor falls below DISPATCH_LEVEL. On the other hand, if the ISR calls IoRequestDpc or KeInsertQueueDpc while the corresponding DpcForIsr or CustomDpc is running on another processor, the DPC routine can run on two processors concurrently.

Therefore, any driver that overlaps interrupt-driven I/O operations on its device must have the following:

  • A DpcForIsr or CustomDpc routine that can complete some driver-maintained count of outstanding requests each time it is called
  • An ISR that never overwrites the context information that it passes to a DpcForIsr or CustomDpc routine, until that routine has used the context information and completed the IRP to which the context information belongs
  • A SynchCritSection routine that accesses the ISR's context area on behalf of the DpcForIsr or CustomDpc routine


Writing DPC Routines

The primary responsibilities of DpcForIsr and CustomDpc routines are ensuring that the next device I/O operation is started promptly and completing the current IRP.

Additional work done by any DpcForIsr or CustomDpc routine depends on the driver's design and the nature of the device. For example, a DpcForIsr or CustomDpc routine also can do any of the following:

  • Retry an operation that has timed out or failed.
  • Call IoAllocateErrorLogEntry, set up an error log packet to report a device I/O error, and call IoWriteErrorLogEntry.

    For more information about handling I/O errors, see Logging Errors.

  • If the driver uses buffered I/O, or if the IRP specifies a device control operation, transfer data read in from the device to the system buffer at Irp->AssociatedIrp.SystemBuffer before completing the IRP.
  • If the driver uses direct I/O and must break large transfers into smaller pieces, save state about each just-completed partial-transfer operation, calculate the next partial-transfer range, and use a driver-supplied SynchCritSection routine to program the device for the next partial-transfer operation.

    Even a driver that uses buffered I/O might have to split up a transfer request if its device has limited transfer capabilities.

  • If the driver uses packet-based DMA, call FlushAdapterBuffers after each device transfer operation, and call FreeAdapterChannel or FreeMapRegisters when a sequence of partial transfers is done and the full transfer request is satisfied.

    If a requested transfer is only partly satisfied by a single DMA operation, the DpcForIsr or CustomDpc routine is usually responsible for setting up one or more DMA operations until the IRP's specified number of bytes have been fully transferred.

    For more information about using DMA, see Adapter Objects and DMA.

  • If the driver uses programmed I/O (PIO), call KeFlushIoBuffers at the end of each transfer operation if the current IRP requests a read.

    If a requested transfer is only partly satisfied by a single PIO operation, the DpcForIsr or CustomDpc routine is usually responsible for setting up one or more transfer operations until the IRP's specified number of bytes have been fully transferred.

    For more information about using PIO, see Using Direct I/O.

  • If a non-WDM driver has a ControllerControl routine, call IoFreeController when a requested operation is complete.

Note that a DpcForIsr or CustomDpc routine usually does most of the driver's device I/O processing to satisfy IRPs. These routines also share some of the responsibility for queuing IRPs to the device with the driver's dispatch routines.

Consider the following a general design guidelines.

  • Any DpcForIsr or CustomDpc routine should call IoStartNextPacket as soon as it can safely make this call: that is, without possibly causing a resource conflict or race condition with the driver's StartIo routine or with any other routine the StartIo routine causes to run.
  • If a driver manages its own queuing of IRPs, its DpcForIsr or CustomDpc routine should notify the driver as soon as it is safe to dequeue the next IRP and to set up the device for the next request.

A DpcForIsr or CustomDpc routine must call IoStartNextPacket, or otherwise notify the appropriate driver routine when device I/O processing for the next request can be started. Depending on the driver and its device, this can occur well before the DpcForIsr or CustomDpc routine completes the current IRP with IoCompleteRequest, or it can occur immediately before this routine completes the current IRP and returns control.


Guidelines for Writing DPC Routines

Keep the following points in mind when writing a DpcForIsr or CustomDpc routine:

  • A DpcForIsr or CustomDpc routine must synchronize its access to a physical device, and to any shared state information or resources that the driver maintains, with the driver's other routines that access the same device or memory locations.

    If a DpcForIsr or CustomDpc routine shares the device or state with an ISR, it must call KeSynchronizeExecution, supplying the address of a driver-supplied SynchCritSection routine that programs the device or accesses the shared state. For more information, see Using Critical Sections.

    If a DpcForIsr or CustomDpc routine shares state or resources, such as an interlocked queue or a timer object, with routines other than an ISR, it must protect the shared state or resources with a driver-initialized executive spin lock. For more information, see Spin Locks.

  • DpcForIsr and CustomDpc routines run at IRQL DISPATCH_LEVEL, which restricts the set of support routines they can call.

    For example, DpcForIsr and CustomDpc routines can neither access nor allocate pageable memory, and they cannot wait on kernel dispatcher objects. On the other hand, they can acquire and release a driver's executive spin lock with KeAcquireSpinLockAtDpcLevel and KeReleaseSpinLockFromDpcLevel, which run faster than KeAcquireSpinLock and KeReleaseSpinLock.

  • DpcForIsr and CustomDpc routines are typically responsible for starting the next I/O operation on the device.

    For lowest-level physical device drivers that use direct I/O, this responsibility can include using a SynchCritSection routine to program the device to transfer more data in order to satisfy the current IRP before the driver calls IoStartNextPacket.

  • If the driver uses DMA and its AdapterControl routine returns KeepObject or DeallocateObjectKeepRegisters (thereby retaining the system DMA controller channel or bus-master adapter for additional transfer operations), the DpcForIsr or CustomDpc routine is responsible for releasing the adapter object or map registers with FreeAdapterChannel or FreeMapRegisters before it completes the current IRP and returns control.
  • If a lowest-level physical device driver sets up a controller object to synchronize I/O operations through the controller to attached devices, its DpcForIsr or CustomDpc routine is responsible for releasing the controller object using IoFreeController before it completes the current IRP and returns control.
  • DpcForIsr and CustomDpc routines are generally responsible for logging any device errors that occurred during the processing of a given request, retrying the current request if necessary and possible, and for setting the I/O status block and calling IoCompleteRequest for the current IRP.
  • If the driver and device support overlapped I/O operations, the driver must follow the rules for handling overlapped I/O operations.
  • The DpcForIsr or CustomDpc routine of any driver usually completes the I/O processing only for a subset of the public I/O control codes that the driver must support. In particular, the DPC routine completes operations for device control requests with the following characteristics:
    • Requests that change the state of the physical device
    • Requests that require the return of inherently volatile information about the physical device


Using Critical Sections

Any driver that contains an InterruptService routine will most likely require one or more critical sections to synchronize access to hardware resources or driver data among the ISR and other routines.

This section includes the following topics:

Introduction to SynchCritSection Routines

Writing SynchCritSection Routines


Introduction to SynchCritSection Routines

Critical sections are sections of code that require exclusive access to hardware resources or driver data. That is, the code must not be interrupted by other code that can reference the same resources or data, and the resources or data must not be referenced by more than one processor at a time.

Critical sections should be confined to ISRs and SynchCritSection routines. The system calls these routines only after raising the current processor's IRQL to the device's DIRQL value and acquiring a spin lock. After a SynchCritSection routine returns, the system releases the spin lock and lowers the processor's IRQL.

Raising the processor's IRQL to the device's DIRQL value prevents the current processor from being interrupted, except by a higher-priority device. Acquiring a spin lock prevents other processors from executing any critical section code associated with that spin lock. (This spin lock is sometimes called an interrupt spin lock.)

A device driver's StartIo and DpcForIsr or CustomDpc routines frequently must access some of the same hardware resources (such as device registers or other bus-relative memory) or driver-maintained data as the driver's ISR. Depending on the driver's device or design, its dispatch, AdapterControl, ControllerControl, or timer routines also might access hardware resources or driver-maintained data.

To call any non-ISR critical section, a driver must use the KeSynchronizeExecution routine. This routine accepts the address of a SynchCritSection routine as input, along with driver-defined context information and an interrupt object pointer. The system uses the interrupt object pointer to determine the DIRQL and spin lock to use with the SynchCritSection routine. (The driver previously supplied these values, using the IoConnectInterrupt function's SpinLock and SynchronizeIrql parameters.)


Writing SynchCritSection Routines

Drivers use their SynchCritSection routines for either of two basic purposes:

Programming a device for an I/O operation

Accessing shared state information

Like an ISR, a SynchCritSection routine must execute as quickly as possible, doing only what is necessary to set up device registers or update context data, before returning.

Because KeSynchronizeExecution holds a device driver's interrupt spin lock while its SynchCritSection routine runs, the driver's ISR cannot execute until the SynchCritSection routine returns control.

For any received IRP, a device driver should do as much I/O processing as possible either at IRQL PASSIVE_LEVEL in its dispatch routines (or possibly device-dedicated threads), or at IRQL DISPATCH_LEVEL in its StartIo routine and DPC routines.

For additional information about how critical sections are synchronized, see Using Spin Locks – An Example.


Programming a Device for an I/O Operation

Use the following general guidelines for designing, writing, and calling SynchCritSection routines that program a device for I/O operations:

  • A SynchCritSection routine that programs the device for I/O operations must return control as quickly as possible.

    For this reason, the SynchCritSection routine should do only what is necessary to set up the device for I/O. Therefore, the driver should perform all IRP preprocessing, initializing state information for other driver routines, and acquiring hardware resources before it calls the SynchCritSection routine.

  • A device driver can have multiple SynchCritSection routines to program the device.

    For example, the driver of a device for which setting up a read request differs markedly from setting up certain device control requests might have separate SynchCritSection routines to program its device for each type of request.

  • Every SynchCritSection routine must return control as quickly as possible, because running any SynchCritSection routine prevents the driver's ISR from executing.

    You should not write a single, large, general-purpose SynchCritSection routine with a switch statement or many nested if..then..else statements to determine what operations it will carry out or what state information to update. On the other hand, you should avoid writing numerous SynchCritSection routines that program only a single device register.


Accessing Shared State Information

Use the following general guidelines for designing and writing SynchCritSection routines that maintain state:

  • To access data that an ISR also accesses, a driver routine must call a SynchCritSection routine. Non-critical section code can be interrupted. Remember that it is not sufficient to simply acquire a spin lock to protect data that ISRs also access, because ISRs execute at DIRQL and acquiring a spin lock (KeAcquireSpinLock) only raises IRQL to DISPATCH_LEVEL, which allows an interrupt to invoke the ISR on the current processor.
  • Give each SynchCritSection routine that maintains state information responsibility for a discrete set of state variables. That is, avoid writing SynchCritSection routines that maintain overlapping state information.

    This prevents contention, and possibly race conditions, between SynchCritSection routines (and the ISR) trying to access the same state concurrently.

    This also ensures that each SyncCritSection routine returns control as quickly as possible because one SynchCritSection routine never has to wait for another that updates some of the same state information to return control.

  • Avoid writing a single, large, general-purpose SynchCritSection routine that does more testing of conditions to determine what to do than actually doing useful work. On the other hand, avoid having many SynchCritSection routines that never execute a conditional statement because each updates only a single byte of state information.
  • Every SynchCritSection routine must return control as quickly as possible, because running any SynchCritSection routine prevents the driver's ISR from executing.

Following is a technique for maintaining a timer counter in a device extension. Assume the driver uses the counter to determine if an I/O operation has timed out. Also assume the driver does not overlap I/O operations.

  • The driver's StartIo routine initializes the timer counter to some initial value for each I/O request. The driver then adds a second to its device-time-out value, in case its IoTimer routine has just returned control.
  • The driver's ISR must set this timer counter to minus one.
  • The driver's IoTimer routine is called once per second to read the time counter and determine whether the ISR has already set it to minus one. If not, the IoTimer routine decrements the counter by using KeSynchronizeExecution to call a SynchCritSection_1 routine.

    If the counter goes to zero, indicating that the request timed out, the SynchCritSection_1 routine calls a SynchCritSection_2 routine to program a device reset operation. If the counter is minus one, the IoTimer routine simply returns.

  • If the driver's DpcForIsr routine must reprogram the device to begin a partial-transfer operation, it must reinitialize the timer counter as the StartIo routine did.

    The DpcForIsr routine also must use KeSynchronizeExecution to call the SynchCritSection_2 routine, or possibly a SynchCritSection_3 routine, to program the device for another transfer operation.

In this scenario, the driver has more than one SynchCritSection routine, each with discrete, specific responsibilities; one to maintain its timer counter, and one or more others to program the device. Each SynchCritSection routine can return control quickly because it performs a single, discrete task.

Note that the driver has a single SynchCritSection_1 routine which, along with the driver's ISR, maintains the state to the timer counter. Thus, there is no contention for access to the timer counter among several SynchCritSection routines and the ISR.


Managing Hardware Priorities

The IRQL at which a driver routine executes determines which kernel-mode driver support routines it can call. For example, some driver support routines require that the caller be running at IRQL DISPATCH_LEVEL. Others cannot be called safely if the caller is running any raised IRQL; that is, at any IRQL higher than PASSIVE_LEVEL.

Following is a list of IRQLs at which the most commonly implemented standard driver routines are called. The IRQLs are listed from lowest to highest priority.

PASSIVE_LEVEL
Interrupts Masked Off — None.

Driver Routines Called at PASSIVE_LEVEL — DriverEntry, AddDevice, Reinitialize, Unload routines, most dispatch routines, driver-created threads, worker-thread callbacks.

APC_LEVEL
Interrupts Masked Off — APC_LEVEL interrupts are masked off.

Driver Routines Called at APC_LEVEL — Some dispatch routines (see Dispatch Routines and IRQLs).

DISPATCH_LEVEL
Interrupts Masked Off — DISPATCH_LEVEL and APC_LEVEL interrupts are masked off. Device, clock, and power failure interrupts can occur.

Driver Routines Called at DISPATCH_LEVEL — StartIo, AdapterControl, AdapterListControl, ControllerControl, IoTimer, Cancel (while holding the cancel spin lock), DpcForIsr, CustomTimerDpc, CustomDPC routines.

DIRQL
Interrupts Masked Off — All interrupts at IRQL<= DIRQL of driver's interrupt object. Device interrupts with a higher DIRQL value can occur, along with clock and power failure interrupts.

Driver Routines Called at DIRQL — InterruptService, SyncCritSection routines.

The only difference between APC_LEVEL and PASSIVE_LEVEL is that a process executing at APC_LEVEL cannot get APC interrupts. But both IRQLs imply a thread context and both imply that the code can be paged out.

Lowest-level drivers process IRPs while running at one of three IRQLs:

  • PASSIVE_LEVEL, with no interrupts masked off on the processor, in the driver's Dispatch routine(s)

    DriverEntry, AddDevice, Reinitialize, and Unload routines also are run at PASSIVE_LEVEL, as are any driver-created system threads.

  • DISPATCH_LEVEL, with DISPATCH_LEVEL and APC_LEVEL interrupts masked off on the processor, in the StartIo routine

    AdapterControl, AdapterListControl, ControllerControl, IoTimer, Cancel (while it holds the cancel spin lock), and CustomTimerDpc routines also are run at DISPATCH_LEVEL, as are DpcForIsr and CustomDpc routines.

  • Device IRQL (DIRQL), with all interrupts at less than or equal to the SynchronizeIrql of the driver's interrupt object(s) masked off on the processor, in the ISR and SynchCritSection routines

Most higher-level drivers process IRPs while running at either of two IRQLs:

  • PASSIVE_LEVEL, with no interrupts masked off on the processor, in the driver's dispatch routines

    DriverEntry, Reinitialize, AddDevice, and Unload routines also are run at PASSIVE_LEVEL, as are any driver-created system threads or worker-thread callback routines or file system drivers.

  • DISPATCH_LEVEL, with DISPATCH_LEVEL and APC_LEVEL interrupts masked off on the processor, in the driver's IoCompletion routine(s)

    IoTimer, Cancel, and CustomTimerDpc routines also are run at DISPATCH_LEVEL.

In some circumstances, intermediate and lowest-level drivers of mass-storage devices are called at IRQL APC_LEVEL. In particular, this can occur at a page fault for which a file system driver sends an IRP_MJ_READ request to lower drivers.

Most standard driver routines are run at an IRQL that allows them simply to call the appropriate support routines. For example, a device driver must call AllocateAdapterChannel while running at IRQL DISPATCH_LEVEL. Since most device drivers call these routines from a StartIo routine, usually they are running at DISPATCH_LEVEL already.

Note that a device driver that has no StartIo routine because it sets up and manages its own queues of IRPs is not necessarily running at DISPATCH_LEVEL IRQL when it should call AllocateAdapterChannel. Such a driver must nest its call to AllocateAdapterChannel between calls to KeRaiseIrql and KeLowerIrql so that it runs at the required IRQL when it calls AllocateAdapterChannel and restores the original IRQL when the calling routine regains control.

When calling driver support routines, be aware of the following.

  • Calling KeRaiseIrql with an input NewIrql value that is less than the current IRQL causes a fatal error. Calling KeLowerIrql except to restore the original IRQL (that is, after a call to KeRaiseIrql) also causes a fatal error.
  • While running at raised IRQL, calling KeWaitForSingleObject or KeWaitForMultipleObjects for kernel-defined dispatcher objects to wait for a nonzero interval causes a fatal error.
  • The only driver routines that can safely wait on events, semaphores, mutexes, or timers are those that run in a nonarbitrary thread context at IRQL PASSIVE_LEVEL, such as driver-created threads, the DriverEntry and Reinitialize routines, or dispatch routines for inherently synchronous I/O operations (such as most device I/O control requests).
  • Even while running at IRQL PASSIVE_LEVEL, pageable driver code must not call KeSetEvent, KeReleaseSemaphore, or KeReleaseMutex with the input Wait parameter set to TRUE. Such a call can cause a fatal page fault.
  • Any routine that is running at greater than IRQL APC_LEVEL can neither allocate memory from paged pool nor access memory in paged pool safely. If a routine running at IRQL greater than APC_LEVEL causes a page fault, it is a fatal error.
  • A driver must be running at IRQL DISPATCH_LEVEL when it calls KeAcquireSpinLockAtDpcLevel and KeReleaseSpinLockFromDpcLevel.

    A driver can be running at IRQL <= DISPATCH_LEVEL when it calls KeAcquireSpinLock but it must release that spin lock by calling KeReleaseSpinLock. In other words, it is a programming error to release a spin lock acquired with KeAcquireSpinLock by calling KeReleaseSpinLockFromDpcLevel.

    A driver must not call KeAcquireSpinLockAtDpcLevel, KeReleaseSpinLockFromDpcLevel, KeAcquireSpinLock, or KeReleaseSpinLock while running at IRQL>DISPATCH_LEVEL.

  • Calling a support routine that uses a spin lock, such as an ExInterlocked Xxx routine, raises IRQL on the current processor either to DISPATCH_LEVEL or to DIRQL if the caller is not already running at raised IRQL.
  • Driver code that runs at raised IRQL should execute as quickly as possible. The higher the IRQL at which a routine runs, the more important it is for good overall performance to tune that routine to execute as quickly as possible. For example, any driver that calls KeRaiseIrql should make the reciprocal call to KeLowerIrql as soon as it can.


Memory Management

While many drivers use the system-allocated space within their device extensions as their sole global storage areas, drivers can allocate additional system-space memory if needed. Additionally, they can use the kernel stack to pass small amounts of data to their internal routines.

This section includes the following topics:

Overview of Windows Memory Space

Allocating System-Space Memory

Map Registers

Mapping Bus-Relative Addresses to Virtual Addresses

Using the Kernel Stack

Using Lookaside Lists

Making Drivers Pageable

Accessing Read-Only System Memory

Accessing User-Space Memory


Overview of Windows Memory Space

The following figure illustrates the NT-based operating system's virtual memory spaces and their relationship to system physical memory.

Virtual Memory Spaces and Physical Memory

As this figure shows, virtual memory is backed by paged physical memory, and a virtual address range can be backed by discontiguous physical memory pages. User-space virtual memory and system-space memory allocated from paged pool are always pageable. That is, any noncurrent process and its data can be paged out to secondary storage, usually on a disk.

The hyperspace area shown in the figure is a dedicated range of system-space addresses that the Memory Manager uses to map the current process's virtual address space to a set of physical pages. Note that any noncurrent process's virtual addresses are not visible, so its memory space is inaccessible.

For an extensive discussion of memory management, see Inside Windows NT from Microsoft Press.


Allocating System-Space Memory

To allocate I/O buffer space, a driver can call MmAllocateNonCachedMemory, MmAllocateContiguousMemory, AllocateCommonBuffer (if the driver's device uses bus-master DMA or a system DMA controller's auto-initialize mode), or ExAllocatePool.

Nonpaged pool tends to become fragmented as the system runs, so a driver's DriverEntry routine should call these routines to set up any long-term I/O buffers the driver needs. Each of these routines, except possibly ExAllocatePool, allocates memory that is aligned on a processor-specific boundary (determined by the processor's data-cache-line size) to prevent cache and coherency problems.

Drivers should allocate I/O buffers as economically as possible, because nonpaged pool memory is a limited system resource. In general, a driver should avoid calling these support routines repeatedly to request allocations of less than PAGE_SIZE.

Allocating Driver Buffer Space Economically

To allocate I/O buffer memory economically, keep in mind the following:

  • Each call to MmAllocateNonCachedMemory ties up at least a full page of nonpaged system-space memory, whatever the size of the requested allocation. For requests less than a page, any remainder bytes on the page are wasted: inaccessible by the driver that called MmAllocateNonCachedMemory and unusable by other kernel-mode code.
  • Each call to MmAllocateContiguousMemory allocates up to a page if the specified number of bytes is less than or equal to a page. For requests greater than a page, any remainder bytes on the last-allocated page are wasted: inaccessible to the driver that called MmAllocateContiguousMemory and unusable by other kernel-mode code.
  • Each call to AllocateCommonBuffer uses at least one adapter object map register, which maps at least one byte and at most one page. For more information about map registers and using common buffers, see Adapter Objects and DMA.

Allocating Memory with ExAllocatePool or ExAllocatePoolWithTag

Drivers also can call ExAllocatePool or ExAllocatePoolWithTag, specifying one of the following system-defined POOL_TYPE values for the PoolType parameter:

  • NonPagedPool for any objects or resources not stored in a device extension or controller extension that the driver might access while running at IRQL > APC_LEVEL

    For this PoolType value, ExAllocatePool or ExAllocatePoolWithTag allocates exactly the amount of memory requested if the specified NumberOfBytes is less than or equal to PAGE_SIZE. Otherwise, any remainder bytes on the last-allocated page are wasted: inaccessible to the caller and unusable by other kernel-mode code.

    For example, on an x86, an allocation request of 5K returns two 4K pages. The last 3K of the second page is unavailable to the caller or another caller. To avoid wasting nonpaged pool, the driver should allocate multiple pages efficiently. In this case, for example, the driver could make two allocations, one for PAGE_SIZE and the other for 1K, to allocate a total of 5K.

  • NonPagedPoolCacheAligned for a permanent I/O buffer, such as a SCSI class driver's buffer for request-sense data

    A driver could instead call MmAllocateNonCachedMemory or MmAllocateContiguousMemory to allocate a permanent I/O buffer.

  • PagedPool for a temporary buffer, used by the DriverEntry or Reinitialize routine to contain objects, data, or resources necessary for initialization, if the buffer will be released before the caller returns, or for a storage area that will be accessed only by one or more driver-created threads

    A driver's Unload routine also can allocate memory from paged pool if the buffer will be released before the Unload routine returns control.

  • PagedPoolCacheAligned for a file system driver's I/O buffer that it locks down and passes in an IRP requesting a DMA transfer by an underlying mass-storage device driver

ExAllocatePool and ExAllocatePoolWithTag return a NULL pointer if they cannot allocate the requested number of bytes. Drivers should always check the returned pointer. If its value is NULL, the DriverEntry routine (or any other driver routine that returns NTSTATUS) should return STATUS_INSUFFICIENT_RESOURCES or handle the error condition if possible.

For the ...CacheAligned... PoolType values, ExAllocatePool and ExAllocatePoolWithTag allocate memory that is aligned on a processor-specific boundary (determined by the processor's data-cache-line size) to prevent cache and coherency problems.


Map Registers

Drivers that perform DMA use three different address spaces, as shown in the following figure.

Physical, Logical, and Virtual Address Mappings

On any Windows platform, a driver has access to the full virtual address space supported by the processor. On a 32-bit processor, the virtual address space represents four gigabytes. The CPU translates addresses in the virtual address space to addresses in the system's physical address space by means of a page table. Each page table entry (PTE) maps one page of virtual memory to a page of physical memory, resulting in a paging operation when necessary. An MDL (memory descriptor list) provides a similar mapping for a buffer associated with driver DMA operations.

Devices vary in their ability to access the system's full virtual address space. A device uses addresses in logical (device) address space. Each HAL uses map registers to translate a device or logical address to a physical address (a location in physical RAM). For the device hardware, map registers perform the same function that the MDL (and page table) performs for the software (drivers): they translate addresses to physical memory.

Because these address spaces are separately addressed, a driver cannot use a pointer in virtual address space to address a location in physical memory, and vice versa. The driver must first translate the virtual address to a physical address. Similarly, a driver cannot use a logical address to access physical memory; it must first translate the address.

A HAL must set up adapter objects that support DMA for a wide variety of DMA devices and I/O buses on different machines. For example, most ISA DMA controllers, slave devices, and bus-master devices do not have enough address lines to access the full four-gigabyte system physical address space of a 32-bit processor. By contrast, EISA DMA devices generally have more than enough address lines to access the full system physical address space in 32-bit processors. Consequently, every HAL provides mappings between the logical address ranges that DMA devices can access and physical address ranges of each individual machine.

Each adapter object is associated with one or more map registers, depending on the amount of data to be transferred and the amount of available memory. During DMA transfers, the HAL uses each map register to alias a device-accessible logical page to a page of physical memory in the CPU. In effect, map registers provide scatter/gather support for drivers that use DMA whether or not their devices have scatter/gather capabilities.

The following figure illustrates such a physical-to-logical address mapping for the driver of an ISA DMA device that does not have scatter/gather capabilities.

Address Mapping for Sample ISA DMA Device

The previous figure shows the following types of mappings:

  1. Each map register maps a range of physical addresses (pointed to by solid lines) to low-order logical addresses (dotted lines) for an ISA DMA device.

    Here, three map registers are used to alias three paged ranges of data in system physical memory to three page-sized ranges of low-order logical addresses for an ISA DMA device.

  2. The ISA device uses the mapped logical addresses to access system memory during DMA operations.

    For a comparable EISA DMA device, three map registers would also be used for three page-sized ranges of data. However, the mapped logical address ranges would not necessarily be identical to the corresponding physical address ranges, so an EISA device would also use logical addresses to access system memory.

  3. Each entry in the MDL maps a location in virtual address space to a physical address.

Note the correspondence between a map register and a virtual-to-physical entry in the MDL:

  • Each map register and each virtual entry in an MDL maps at most a full physical page of data for a DMA transfer operation.
  • Each map register and each virtual entry in an MDL might map less than a full page of data. For example, the initial virtual entry in an MDL can map to an offset from the physical page boundary, as shown previously in the Physical, Logical, and Virtual Address Mappings figure.
  • Each map register and each virtual entry in an MDL maps, at a minimum, one byte.

In an IRP requesting a read or write operation, each virtual entry in the opaque-to-drivers MDL at Irp->MdlAddress represents a page boundary in the system physical memory for a user buffer. Similarly, each additional map register needed for a single DMA transfer represents a page boundary in the device-accessible logical address range aliased to system physical memory.

On every Windows platform, each adapter object has an associated set of one or more map registers located at a platform-specific (and opaque-to-drivers) base address. From a driver's point of view, the map register base shown in the figure illustrating address mapping for a sample ISA DMA device is a handle for a set of map registers that could be hardware registers in a chip, in a system DMA controller, or in a bus-master adapter, or could even be HAL-created virtual registers in system memory.

The number of map registers available with an adapter object can vary for different devices and Windows platforms. For example, the HAL can make more map registers available to drivers that use system DMA on some platforms than on others because the DMA controllers on different Windows platforms have different capabilities.


Mapping Bus-Relative Addresses to Virtual Addresses

Some processors implement separate memory and I/O address spaces, while others do not. Because of these differences in hardware platforms, the mechanism drivers use to access I/O- or memory-resident device resources differs from platform to platform.

A driver requests device I/O and memory resources in response to the PnP Manager's IRP_MN_QUERY_RESOURCE_REQUIREMENTS IRP. Depending on the hardware architecture, the HAL can assign I/O resources in I/O space or in memory space, and can assign memory resources in I/O space or in memory space.

If the HAL uses bus-relative memory space to access device resources (such as device registers), a driver must map I/O space into virtual memory so that it can access these resources. The driver can determine whether the resources are I/O- or memory-resident by inspecting the translated resources passed to the driver by the PnP Manager at device start-up. If the HAL uses I/O space, no mapping is required.

Specifically, when a driver receives an IRP_MN_START_DEVICE request, it should examine the structures at IrpSp->Parameters.StartDevice.AllocatedResources and IrpSp->Parameters.StartDevice.AllocatedResourcesTranslated, which describe the raw and translated resources, respectively, that the PnP Manager has assigned to the device. Drivers should save a copy of each resource list in the device extension as an aid to debugging.

The resource lists are paired CM_RESOURCE_LIST structures, in which each element of the raw list corresponds to the same element of the translated list. For example, if AllocatedResources.List[0] describes a raw I/O port range, then AllocatedResourcesTranslated.List[0] describes the same range after translation. Each translated resource includes a physical address and the type of the resource.

If a driver is assigned a translated memory resource (CmResourceTypeMemory), it must call MmMapIoSpace to map the physical address into a virtual address through which it can access device registers. For a driver to operate in a platform independent manner, it should check each returned, translated resource and map it, if necessary.

The following are the steps each driver should take in response to an IRP_MN_START_DEVICE to ensure access to all device resources

  1. Copy IrpSp->Parameters.StartDevice.AllocatedResources to the device extension.
  2. Copy IrpSp->Parameters.StartDevice.AllocatedResourcesTranslated to the device extension.
  3. In a loop, inspect each descriptor element in AllocatedResourcesTranslated. If the descriptor resource type is CmResourceTypeMemory, call MmMapIoSpace, passing the physical address and length of the translated resource.

When the driver receives an IRP_MN_STOP_DEVICE or IRP_MN_REMOVE_DEVICE request from the PnP Manager, it must release the mappings by calling MmUnmapIoSpace in a similar loop. The driver should also call MmUnmapIoSpace if it must fail the IRP_MN_START_DEVICE request.

The raw resource type indicates which HAL access routine a driver should call (READ_REGISTER_ Xxx, WRITE_REGISTER_Xxxx, READ_PORT_Xxx, WRITE_PORT_Xxx). Most drivers need not check the raw resource list to determine which of these routines to use, because either the driver itself requested the resource or the driver writer knows the required type given the nature of the device hardware.

For a resource in I/O space (CmResourceTypePort, CmResourceTypeInterrupt, CmResourceTypeDma), the driver should use the low-order 32 bits of the returned physical address to access the device resource, for example, through the HAL's read and write READ_REGISTER_ Xxx, WRITE_REGISTER_Xxxx, READ_PORT_Xxx, and WRITE_PORT_Xxx routines.


Using the Kernel Stack

While a driver can pass data to its internal routines, the size of the kernel-mode stack is around two pages. Consequently, drivers cannot pass large amounts of data on the kernel stack.

To avoid running out of kernel-mode stack space, follow these design guidelines.

  • Avoid making deeply nested calls from one internal driver routine to another if each routine passes data on the kernel stack.
  • Take care to limit the number of recursive calls that can occur if you design a driver with a recursive routine.

In other words, the call-tree structure of a driver should be relatively flat. While nonpaged pool is also a limited system resource, it is better for a driver to allocate a system-space buffer than to run out of kernel stack space.

The kernel-mode stack is in cached memory. Consequently, drivers cannot transfer data on the stack using DMA.

To avoid DMA data alignment and/or data integrity problems, follow this design guideline.

Never attempt to transfer data on the kernel stack using DMA.

Drivers of devices that use DMA can buffer data to be transferred, if necessary, either by calling ExAllocatePool or ExAllocatePoolWithTag for a NonPagedPoolCacheAligned-type buffer or, for some drivers, by using common-buffer DMA. See Using Common-Buffer System DMA and Using Common-Buffer, Bus-Master DMA for more information.


Using Lookaside Lists

Drivers that must allocate fixed-size buffers dynamically to carry out on-demand I/O operations can use the Ex..LookasideList support routines. After such a driver initializes its lookaside list, the operating system will hold some number of dynamically allocated buffers of the given size in the driver's lookaside list, effectively reserving a set of reusable, fixed-size buffers for the driver. The format and contents of a driver's fixed-size buffers (also called entries) in its lookaside list are driver-determined.

For example, storage class drivers that must set up SCSI request blocks (SRBs) for the underlying SCSI port/miniport drivers use lookaside lists. Such a class driver allocates buffers for SRBs on an as-needed basis from its lookaside list and releases each SRB buffer to be held the lookaside list whenever an SRB is returned to the class driver in a completed IRP. Because a storage class driver cannot predetermine how many SRBs it will need to use at any given moment as I/O demand on the driver rises and falls, a lookaside list is a convenient and economical way to manage the allocation and deallocation of buffers for fixed-size SRBs in such a driver.

The OS maintains state about all paged and nonpaged lookaside lists currently in use, dynamically tracking the demand for allocations and deallocations of entries in all lists, as well as available system pool for new entries. When demand for allocations is high, the OS increases the number of entries it holds in each lookaside list. When demand falls again, it frees surplus lookaside entries back to system pool.

In drivers that use the Ex..LookasideList routines, follow these design guidelines.

  • Set up a nonpaged lookaside list with ExInitializeNPagedLookasideList if the driver itself or any underlying driver to which it passes its lookaside list entries might access these entries at IRQL >= DISPATCH_LEVEL or in an arbitrary thread context.
  • Set up a lookaside list with paged entries only if accesses to the driver's lookaside list entries cannot possibly cause a fatal page fault.
  • Provide resident storage in nonpaged system space for the lookaside list head, even if the driver sets up a paged lookaside list with ExInitializePagedLookasideList.
  • For better performance, pass NULL pointers for Allocate and Free when calling ExInitialize(N)PagedLookasideList unless these optional driver-supplied routines do more than merely allocate and release memory for lookaside list entries, such as maintaining state about the driver's own usage of dynamically allocated buffers.
  • Use the given input parameters (PoolType, Tag, and Size) to the driver-supplied Allocate routine whenever it calls ExAllocatePoolWithTag, if the driver provides such a routine.
  • For every call to ExAllocateFrom(N)PagedLookasideList, make the reciprocal call to ExFreeTo(N)PagedLookasideList as soon as possible whenever a previously allocated entry is no longer in use.

For a paged lookaside list, the entries are allocated from paged pool but the head of such a list must be in resident memory.

Supplying Allocate and Free routines that do nothing more than call ExAllocatePoolWithTag and ExFreePool, respectively, wastes CPU cycles. ExAllocateFrom(N)PagedLookasideList and ExFreeTo(N)PagedLookasideList make the necessary calls to ExAllocatePoolWithTag and ExFreePool automatically when a driver passes NULL Allocate and Free pointers to ExInitialize(N)PagedLookasideList.

Any driver-supplied Allocate routine must not allocate memory for an entry from paged pool to be held in a nonpaged lookaside list or vice versa. It must allocate fixed-size entries, as well, because any subsequent driver call to ExAllocateFrom(N)PagedLookasideList returns the first entry currently held in the lookaside list unless the list is empty. That is, a call to ExAllocateFrom(N)PagedLookasideList causes a call to the driver-supplied Allocate routine only if the given lookaside list is currently empty. Consequently, at each call to ExAllocateFrom(N)PagedLookasideList, the returned entry will be exactly the size that the driver needs only if all entries in the lookaside list are of a fixed size. A driver-supplied Allocate routine also should not change the Tag value that the driver originally passed to ExInitialize(N)PagedLookasideList, because changes in the pool-tag value would make debugging and tracking the driver's memory usage more difficult.

Calls to ExFreeTo(N)PagedLookasideList return previously allocated entries to be held in the lookaside list unless the list already contains the system-determined maximum number of entries. For better performance, a driver should make reciprocal calls to ExFreeTo(N)PagedLookasideList as promptly as it can for every call that it makes to ExAllocateFrom(N)PagedLookasideList. When a driver frees entries back to its lookaside list promptly, that driver's next call to ExAllocateFrom(N)PagedLookasideList is far less likely to incur the performance penalty of explicitly allocating additional memory for another entry.


Making Drivers Pageable

The system-space virtual memory shown in the Virtual Memory Spaces and Physical Memory figure consists of a limited amount of paged pool and an even more limited amount of nonpaged pool.

Paged code runs at IRQL < DISPATCH_LEVEL; it can be paged in when referenced without bringing down the system or adversely affecting a driver's operation. Nonpaged code is always memory-resident; it runs at IRQL >= DISPATCH_LEVEL and never takes a page fault.


When Should Code and Data be Pageable?

You can make all or a portion of some drivers pageable. Paging driver code reduces the size of the driver's load image, thus freeing system space for other uses. It is most practical for drivers of sporadically-used devices, such as modems and CD-ROMs, or for portions of drivers that are rarely called.

Performance-critical sections of code in frequently-used drivers (such as keyboard and mouse drivers) should not be made pageable. Paging in their code on demand can negatively impact driver and system performance.

Driver code must be pageable if any of the following are true:

  • It accesses paged pool.
  • It calls another pageable routine.
  • It references user buffers in the context of the user thread.

Driver code that does any of the following must be resident; it cannot be made pageable:

  • Runs at or above IRQL DISPATCH_LEVEL
  • Acquires spin locks
  • Calls any of the Kernel's object support routines, such as KeReleaseMutex or KeReleaseSemaphore, in which the Wait parameter is set to TRUE. If the Kernel is called with Wait set to TRUE, the call returns with IRQL at DISPATCH_LEVEL and the dispatcher database locked.

As a general rule, it is worthwhile making a pageable section if the total amount of all the pageable code (or data) is at least 4K. Whenever possible, you should isolate purely pageable code (or data) into a separate section from code (or data) that must be pageable or locked-on-demand. For instance, combining purely pageable and locked-on-demand code causes more system space to be locked down for the combined section than is necessary. However, if a driver has less than 4K of possibly pageable code (or data), you might combine that code (or data) with locked-on-demand code (or data) into one section, saving system space.


Making Driver Code or Data Pageable

To make a driver routine pageable, you must ensure that it runs at IRQL < DISPATCH_LEVEL and that it does not acquire any spin locks.

This section contains the following topics:

Detecting Code that can be Pageable

Isolating Pageable Code

Locking Pageable Code or Data

Paging an Entire Driver


Detecting Code that can be Pageable

To detect code that runs at IRQL >= DISPATCH_LEVEL, use the PAGED_CODE() macro. In debug mode, this macro generates a message if the code runs at IRQL >= DISPATCH_LEVEL. Place the macro as the first statement in a routine to mark the entire routine as paged code, as the following example shows:

NTSTATUS
MyDriverXxx(
    IN OUT PVOID ParseContext OPTIONAL,
    OUT PHANDLE Handle
    )
{
    NTSTATUS Status;

    PAGED_CODE();
    .
    .
    .
}

To ensure that you are doing this correctly, run the Driver Verifier against your finished driver with the Force IRQL Checking option enabled. This option causes the system to automatically page out your pageable code each time the driver raises IRQL to DISPATCH_LEVEL or above. Using the Driver Verifier, you can quickly find any driver bugs in this area. Otherwise, these bugs will typically be found only by customers and they can often be very hard for you to reproduce.


Isolating Pageable Code

A routine that uses a spin lock cannot be paged. However, in some cases you can isolate the operations that require a spin lock in a separate routine that will not be included in the pageable section.

For example, consider the following fragment:

//  PAGED_CODE();

KeInitializeEvent( &event, NotificationEvent, FALSE );
irp = IoBuildDeviceIoControlRequest( IRP_MJ_DEVICE_CONTROL,
                                     DeviceObject,
                                     (PVOID) NULL,
                                     0,
                                     (PVOID) NULL,
                                     0,
                                     FALSE,
                                     &event,
                                     &ioStatus );
if (irp) {
   irpSp = IoGetNextIrpStackLocation( irp );
   irpSp->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
   irpSp->MinorFunction = IRP_MN_LOAD_FILE_SYSTEM;
   status = IoCallDriver( DeviceObject, irp );
   if (status == STATUS_PENDING) {
   (VOID) KeWaitForSingleObject( &event,
                                 Executive,
                                 KernelMode,
                                 FALSE,
                                 (PLARGE_INTEGER) NULL );
    }
    }

SPINLOCKUSE !
ExAcquireSpinLock( &IopDatabaseLock, &irql );
// Code inside spin lock …

DeviceObject->ReferenceCount--;

if (!DeviceObject->ReferenceCount && !DeviceObject->AttachedDevice) {
   //Unload the driver
   .
   .
   .
} else {
   ExReleaseSpinLock( &IopDatabaseLock, irql );
}

The preceding routine could be made pageable (saving about 160 bytes) by moving the few lines of code that reference a spin lock into a separate routine.

In addition, remember that driver code must not be marked as pageable if it calls any KeXxx support routines, such as KeReleaseMutex or KeReleaseSemaphore, in which the Wait parameter is set to TRUE. Such a call returns with IRQL at DISPATCH_LEVEL and the dispatcher database locked.


Locking Pageable Code or Data

Certain drivers, such as the serial and parallel drivers, need not be resident unless the devices they manage are open. However, as long as there is an active connection or port, some part of the driver code that manages that port must be resident to service the device. When the port or connection is not in use, the driver code is not required. In contrast, a driver for a disk that contains system code, application code, or the system paging file must always be memory-resident because the driver constantly transfers data between its device and the system.

A driver for a sporadically used device (such as a modem) can free system space when the device it manages is not active. If you place in a single section the code that must be resident to service an active device, and if your driver locks the code in memory while the device is in use, that section can be designated as pageable. When the driver's device is opened, the operating system brings the pageable section into memory and the driver locks it there until no longer needed.

The system CD audio driver code uses this technique. Code for the driver is grouped into pageable sections according to the manufacturer of CD device. Certain brands might never be present on a given system. Furthermore, even if a CD-ROM exists on a system, it might be accessed infrequently, so grouping code into pageable sections by CD type ensures that code for devices that don't exist on a particular machine will never be loaded. However, when the device is accessed, the system loads the code for the appropriate CD device. Then the driver calls MmLockPagableCodeSection, as described below, to lock its code into memory while its device is in use.

To isolate the pageable code into a named section, mark it with the following compiler directive:

#pragma alloc_text(PAGE Xxxx, RoutineName)

The section name must start with PAGE and must be followed by one to four characters that uniquely identify the driver's pageable section. The section name is case-sensitive; that is, PAGE must be capitalized. The RoutineName identifies an entry point to be included in the pageable section.

For example, the following identifies RdrCreateConnection as an entry point within the PAGELK section:

#ifdef  ALLOC_PRAGMA
#pragma alloc_text(PAGELK, RdrCreateConnection)
#endif

To make pageable driver code resident and locked, a driver calls MmLockPagableCodeSection, passing an address — usually the entry point of a driver routine — that is in the pageable code section. MmLockPagableCodeSection locks in the entire contents of the section that contains the routine referenced in the call. In other words, it makes resident and locks every routine associated with the same PAGEXxxx identifier.

A call to MmLockPagableCodeSection fails only if the symbolic address passed is not contained within a pageable section.

MmLockPagableCodeSection returns a handle to be used when unlocking the section (MmUnlockPagableImageSection) or when the driver must lock the section from additional places in its code.

A driver can also treat seldom-used data as pageable so that it, too, can be paged out until the device it supports is active. For example, the system mixer driver uses pageable data. The mixer device has no asynchronous I/O associated with it, so this driver can make its data pageable.

To create a pageable data section, use the following compiler directive at the beginning of the data module:

#pragma data_seg ("PAGE")

At the end of the module, use the following directive:

#pragma data_seg ()

The keyword PAGE is case-sensitive, so it must be capitalized.

To make resident and lock the data section, a driver calls MmLockPagableDataSection, passing a data item that appears in the pageable data section. MmLockPagableDataSection returns a handle to be used in subsequent locking or unlocking requests.

To restore a locked section's pageable status, call MmUnlockPagableImageSection, passing the handle value returned by MmLockPagableCodeSection or MmLockPagableDataSection, as appropriate. A driver's Unload routine must call MmUnlockPagableImageSection to release each handle it has obtained for lockable code and data sections.

Locking a section is an expensive operation because the Memory Manager must search its loaded module list before locking the pages into memory. If a driver locks a section from many places in its code, it should use the more efficient MmLockPagableSectionByHandle after its initial call to MmLockPagableXxxxSection.

The handle passed to MmLockPagableSectionByHandle is the handle returned by the earlier call to MmLockPagableCodeSection or MmLockPagableDataSection.

The Memory Manager maintains a count for each section handle and increments this count each time a driver calls MmLockPagableXxx for that section. A call to MmUnlockPagableImageSection decrements the count. While the counter for any section handle is nonzero, that section remains locked in memory.

The handle to a section is valid as long as its driver is loaded. Therefore, a driver should call MmLockPagableXxxxSection only once. If the driver requires additional locking calls, it should use MmLockPagableSectionByHandle.

If a driver calls any MmLockPagableXxxx routine for a section that is already locked, the Memory Manager simply increments the reference count for the section. If the section is paged out when the lock routine is called, the Memory Manager pages in the section and set its reference count to one.

Using this technique minimizes the driver's impact on system resources. When the driver runs, it can lock into memory the code and data that need to be resident. When there are no outstanding I/O requests for its device, (that is, when the device is closed or if the device was never opened), the driver can unlock the same code or data, making it available to be paged out.

However, after a driver has connected interrupts, any driver code that can be called during interrupt processing always must be memory resident. While some device drivers can be made pageable or locked into memory on demand, some core set of such a driver's code and data must be permanently resident in system space.

Consider the following implementation guidelines for locking a code or data section.

  • The primary use of the Mm(Un)LockXxx routines is to allow normally nonpaged code or data to be made pageable and brought in as nonpaged code or data. Drivers such as the serial driver and the parallel driver are good examples: if there are no open handles to a device such a driver manages, portions of code are not needed and can remain paged out. The redirector and server are also good examples of drivers that can use this technique. When there are no active connections, both of these components can be paged out.
  • The entire pageable section is locked into memory.
  • One section for code and one for data per driver is efficient. Many named, pageable sections are generally inefficient.
  • Keep purely pageable sections and paged but locked-on-demand sections separate.
  • Keep in mind that MmLockPagableCodeSection and MmLockPagableDataSection should not be called frequently. These routines can cause heavy I/O when the Memory Manager loads the section. If a driver must lock a section from several places in its code, it should use MmLockPagableSectionByHandle.

Using MmLockPagableCodeSection and MmUnlockPagableImageSection reduces the size of each driver's loaded image at a cost to the driver's and system's performance. Drivers of performance-critical devices, such as keyboard and mouse drivers, and drivers of devices that are constantly in use, such as disk drivers, generally should not have pageable sections. The loss in performance is simply not worth the temporary reduction in driver image size.


Paging an Entire Driver

A driver that uses the MmLockPagableXxx support routines and specifies paged and discardable sections consists of nonpaged sections, paged sections, and an INIT section that is discarded after driver initialization.

After a device driver connects interrupts for the devices it manages, the driver's interrupt handling path must be resident in system space. The interrupt-handling code must be part of the driver section that cannot be paged out, in case an interrupt occurs.

Two additional Memory Manager routines, MmPageEntireDriver and MmResetDriverPaging, can be used to override the pageable or nonpageable attributes of all sections that make up a driver image. These routines allow a driver to be paged out in its entirety when the device it manages is not in use and cannot generate interrupts.

Examples of system drivers that are completely pageable are the win32.sys driver, the serial driver, the mailslot driver, the beep driver and the null driver.

A serial driver is typically used intermittently. Until a port it manages is opened, a serial driver can be paged out entirely. As soon as a port is opened, the parts of the serial driver that must be memory-resident must be brought into nonpaged system space. Other parts of the driver can remain pageable.

A driver that can be completely paged out should call MmPageEntireDriver during driver initialization before interrupts are connected. PnP drivers should not use this routine.

When a device managed by a paged-out driver receives an open request, the driver is paged in. Then, the driver must call MmResetDriverPaging before it connects to interrupts. Calling MmResetDriverPaging causes the Memory Manager to treat the driver's sections according to the attributes acquired during compilation and linkage. Any section that is nonpaged, such as a text section, will be paged into nonpaged system memory; pageable sections will be paged in as they are referenced.

Such a driver must keep a reference count of open handles to its devices. The driver increments the count at each open request for any device and decrements the count at each close request. When the count reaches zero, the driver should disconnect interrupts and then call MmPageEntireDriver. If a driver manages more than one device, the count must be zero for all such devices before the driver can call MmPageEntireDriver.

It is the driver's responsibility to do whatever synchronization is necessary when changing the reference count; and to prevent the reference count from changing while the pageable state of the driver is changing. That is, in SMP machines, the driver must ensure that MmPageEntireDriver cannot be in progress on one processor, while on another processor, an open call is causing interrupts to be connected and the reference count to be incremented.


Accessing Read-Only System Memory

The Microsoft® Windows® Memory Manager enforces read-only access of pages that are not marked as writable.

Read-only memory has always been protected in user mode. However, in Windows NT® 4.0 and earlier versions, read-only memory was not protected in kernel mode.

If a Windows kernel-mode driver or application attempts to write to a read-only memory segment, the system issues a bug check. See Bug Check 0xBE for full details.

Intercepting System Calls

Some drivers intercept system calls by overwriting the driver's own code and inserting jump instructions or other changes. Since the driver's own code is read-only, this technique will cause a bug check to be issued.

Global Strings

If a global string is to be modified, it must not be declared as a pointer to a constant value:

CHAR *myString = "This string cannot be modified.";

In this case, the linker might place the string in a read-only memory segment. Then an attempt to modify the string will result in a bug check.

Instead, the string should be explicitly declared as an array of L-value characters:

CHAR myString[] = "This string can be modified.";

This ensures that the string is placed in writable memory.


Accessing User-Space Memory

Drivers cannot allocate user-space virtual memory because they run in kernel mode. In addition, a driver cannot access memory through user-mode virtual addresses unless it is running in the context of the user-mode thread that caused the driver's current I/O operation and it is using that thread's virtual addresses.

Only highest-level drivers, such as FSDs, can be sure their dispatch routines will be called in the context of such a user-mode thread. A highest-level driver can call MmProbeAndLockPages to lock down a user buffer before setting up an IRP for lower drivers.

Lowest-level and intermediate drivers that set up their device objects for buffered I/O or direct I/O can rely on the I/O Manager or a highest-level driver to pass valid access to locked-down user buffers or to system-space buffers in IRPs.


Synchronization Techniques

This section provides information about the techniques you can use to synchronize driver activities in a multiprocessor-safe manner. The following sections are provided:

Kernel Dispatcher Objects

Callback Objects

Spin Locks

Additional Timers and Counters


Kernel Dispatcher Objects

This section includes the following topics:

Introduction to Kernel Dispatcher Objects

Timer Objects and DPCs

Event Objects

Semaphore Objects

Mutex Objects

Thread Objects

Do Waiting Threads Receive Alerts and APCs?


Introduction to Kernel Dispatcher Objects

The Kernel defines a set of object types called Kernel dispatcher objects, or just dispatcher objects. Dispatcher objects include timer objects, event objects, semaphore objects, mutex objects, and thread objects.

Drivers can use dispatcher objects as synchronization mechanisms within a nonarbitrary thread context while executing at IRQL PASSIVE_LEVEL.

Dispatcher Object States

Every Kernel-defined dispatcher object type has a state that is either set to Signaled or set to Not-Signaled.

A group of threads can synchronize their operations if one or more threads call KeWaitForSingleObject, KeWaitForMutexObject, or KeWaitForMultipleObjects. These functions take dispatcher object pointers as input and wait until another routine or thread sets one or more dispatcher objects to the Signaled state.

When a thread calls the KeWaitForSingleObject to wait for a dispatcher object (or KeWaitForMutexObject for a mutex), the thread is put into a wait state until the dispatcher object is set to the Signaled state. A thread can call KeWaitForMultipleObjects to wait either for any, or for all, of a set of dispatcher objects to be set to Signaled.

Whenever a dispatcher object is set to the Signaled state, the Kernel changes the state of any thread waiting on that object to ready: (Synchronization timers and synchronization events are exceptions to this rule; when a synchronization event or timer is signaled, only one waiting thread is set to the ready state. For more information, see Timer Objects and DPCs and Event Objects.) A thread in the ready state will be scheduled to run according to its current run-time thread priority and the current availability of processors for any thread with that priority.

When Can Drivers Wait on Dispatcher Objects?

In general, drivers can wait on dispatcher objects only if at least one of the following circumstances is true:

  • The driver is executing in a non-arbitrary thread context.

    That is, you can identify the thread that will enter a wait state. In practice, the only driver routines that execute in a non-arbitrary thread context are the DriverEntry, AddDevice, Reinitialize, and Unload routines of any driver, plus the dispatch routines of highest-level drivers. All these routines are called directly by the system.

  • The driver is performing a completely synchronous I/O request.

    That is, no driver queues any operations while handling the I/O request, and no driver returns until the driver below it has finished handling the request.

Additionally, a driver cannot enter a wait state if it is executing at or above IRQL DISPATCH_LEVEL.

Based on these limitations, you must use the following rules:

  • The DriverEntry, AddDevice, Reinitialize, and Unload routines of any driver can wait on dispatcher objects.
  • The dispatch routines of a highest-level driver can wait on dispatcher objects.
  • The dispatch routines of lower-level drivers can wait on dispatch objects, if the I/O operation is synchronous, such as create, flush, shutdown, and close operations, some device I/O control operations, and some PnP and power operations.
  • The dispatch routines of lower-level drivers cannot wait on a dispatcher object for the completion of asynchronous I/O operations.
  • A driver routine that is executing at or above IRQL DISPATCH_LEVEL must not wait on a dispatcher object.
  • A driver must not attempt to wait on a dispatcher object for the completion of a transfer operation to or from a paging device.
  • Driver dispatch routines servicing read/write requests generally cannot wait on a dispatcher object.
  • A dispatch routine for a device I/O control request can wait on a dispatcher object only if the transfer type for the I/O control code is METHOD_BUFFERED.
  • SCSI miniport drivers should not use kernel dispatcher objects. SCSI miniport drivers should call only ScsiPort routines.

Every other standard driver routine executes in an arbitrary thread context: that of whatever thread happens to be current when the driver routine is called to process a queued operation or to handle a device interrupt. Moreover, most standard driver routines are run at raised IRQL, either at DISPATCH_LEVEL, or for device drivers, at DIRQL.

If necessary, a driver can create a device-dedicated thread, which can wait on a dispatcher object that the driver's other routines (except an ISR or SynchCritSection routine) can set to the Signaled state and reset to the Not-Signaled state.

As a general guideline, if you expect that your new device driver will often need to stall for longer than 50 microseconds while it waits for device-state changes during I/O operations, consider implementing a driver with a device-dedicated thread. If the device driver is also a highest-level driver, consider using system worker threads and implementing one or more worker-thread callback routines. See PsCreateSystemThread and Managing Interlocked Queues with a Driver Created Thread.


Timer Objects and DPCs

Any driver can use a timer object within a nonarbitrary thread context to time out operations within the driver's other routines, or to perform a periodic operation. A driver calls KeInitializeTimer or KeInitializeTimerEx to set up a timer object.

A timer can be set to expire just once, or to expire repeatedly after a given interval. KeSetTimer always sets a timer that will expire just once. KeSetTimerEx accepts an optional Period parameter, which specifies a recurring timer interval.

An optional CustomTimerDpc routine (a type of deferred procedure call) can be associated with either a notification timer or a synchronization timer. This routine executes when the specified time interval expires. For more information, see Using

A timer can be a notification timer or a synchronization timer.

  • When a notification timer is signaled, all waiting threads have their wait satisfied. The state of the timer remains signaled until it is explicitly reset.
  • When a synchronization timer expires, its state is set to Signaled until a single waiting thread is released. Then the timer is reset to the Not-Signaled state.

KeInitializeTimer always creates notification timers. KeInitializeTimerEx accepts a Type parameter, which can be NotificationTimer or SynchronizationTimer.

This section contains the following topics, which provide more information about timer objects and DPCs:

Using Timer Objects

Registering and Queuing a CustomTimerDpc Routine

Providing CustomTimerDpc Context Information

Using a CustomTimerDpc Routine


Using Timer Objects

The following figure illustrates the use of a notification timer to set up a time-out interval for an operation and then wait while other driver routines process an I/O request.

Waiting on a Timer Object

As the previous figure shows, a driver must provide storage for the timer object, which must be initialized by a call to KeInitializeTimer with a pointer to this storage. A driver typically makes this call from its AddDevice routine.

Within the context of a particular thread, such as a driver-created thread or a thread requesting a synchronous I/O operation, the driver can wait on its timer object as shown in the previous figure:

  1. The thread calls KeSetTimer with a pointer to the timer object and a given DueTime value, expressed in units of 100 nanoseconds. A positive value for DueTime specifies an absolute time at which the timer object should be removed from the Kernel's timer queue and set to the Signaled state. A negative value for DueTime specifies an interval relative to the current system time.

    Note that the thread (or driver routine running in a system thread) passes a NULL pointer for the DPC object (shown previously in the figure illustrating using timer and DPC objects for a CustomTimerDpc routine) when it calls KeSetTimer if it waits on the timer object instead of queuing a CustomTimerDpc routine.

  2. The thread calls KeWaitForSingleObject with a pointer to the timer object, which puts the thread into a wait state while the timer object is in the Kernel's timer queue.
  3. The given DueTime expires.
  4. The Kernel dequeues the timer object, sets it to the Signaled state, and changes the thread's state from waiting to ready.
  5. The Kernel dispatches the thread for execution as soon as a processor is available: that is, no other thread with a higher priority is currently in the ready state and there are no kernel-mode routines to be run at raised IRQL (greater than PASSIVE_LEVEL).

Driver routines that run at raised IRQL can time out requests by using a timer object with an associated DPC object to queue a driver-supplied CustomTimerDpc routine . Only driver routines that run within a nonarbitrary thread context can wait for a nonzero interval on a timer object, as shown in the previous figure.

Like every other thread, a driver-created thread is represented by a Kernel thread object, which is also a dispatcher object. Consequently, a driver need not have its driver-created thread use a timer object to voluntarily put itself into a wait state for a given interval. Instead, the thread can call KeDelayExecutionThread with a caller-supplied interval. For more information about this technique, see Polling a Device.

DriverEntry, Reinitialize, and Unload routines also run in a system thread context, so drivers can call KeWaitForSingleObject with a driver-initialized timer object or KeDelayExecutionThread while they are initializing or unloading. A device driver can call KeStallExecutionProcessor for a very short interval (preferably something less than 50 microseconds) if it must wait for the device to update state during its initialization.

However, higher-level drivers generally use another synchronization mechanism in their DriverEntry and Reinitialize routines instead of using a timer object. Higher-level drivers should always be designed to layer themselves over any lower-level driver of a particular type or types of device. Therefore, a higher-level driver tends to become slow-to-load if it waits on a timer object or calls KeDelayExecutionThread because such a driver must wait for an interval long enough to accommodate the slowest possible device supporting it. Note also that a "safe" but minimum interval for such a wait is very difficult to determine.

Similarly, PnP drivers should not wait for other actions to occur, but instead should use the PnP Manager's notification mechanism.

If the system time changes before a timer expires, a relative timer is not affected but the system adjusts each absolute timer. A relative timer always expires after the specified number of time units elapse, regardless of the absolute system time. An absolute timer expires at a specific system time, so a change in the system time changes the wait duration of an absolute timer.


Registering and Queuing a CustomTimerDpc Routine

A driver can register a CustomTimerDpc routine by calling the following routines, usually from its AddDevice routine:

  1. KeInitializeDpc to register its CustomTimerDpc routine
  2. KeInitializeTimer or KeInitializeTimerEx to set up a timer object

Subsequently, the driver can call KeSetTimer or KeSetTimerEx to specify an expiration time and to add the timer object to the system's timer queue. When the expiration time is reached, the system dequeues the timer object and calls the CustomTimerDpc routine. The following figure illustrates these calls:

Using Timer and DPC Objects for a CustomTimerDpc Routine

As the previous figure shows, the driver must supply storage for both a DPC object and a timer object. Most drivers provide the storage for these objects in a device extension or in other driver-allocated, resident memory.

In the call to KeSetTimer, the driver passes pointers to the Dpc and Timer objects, along with a DueTime expressed in units of 100 nanoseconds, as shown in the previous figure. A positive value for DueTime specifies an absolute expiration time (since January 1, 1601) at which the CustomTimerDpc routine should be called. A negative value for DueTime specifies a relative expiration time.

An absolute timer expires at a specific system time, so if the system time changes before the timer expires, the wait duration of an absolute timer is not affected. On the other hand, a relative timer always expires after the specified number of time units elapses, regardless of changes to the absolute system time.

To invoke a CustomTimerDpc routine repeatedly, use KeSetTimerEx to set the timer and specify a recurring interval in the Period parameter. KeSetTimerEx is just like KeSetTimer except for this additional parameter.

As shown in the previous figure, the call to KeSetTimer or KeSetTimerEx queues the timer object for a specified interval as follows:

  1. When the DueTime expires, the timer object is dequeued and set to the Signaled state.
  2. If every processor in the machine is currently running code at an IRQL greater than or equal to DISPATCH_LEVEL, the DPC object associated with the timer object is put in a DPC queue. Otherwise, the CustomTimerDpc routine is called.
  3. If the DPC object was already in the queue when the DueTime interval expired, the CustomTimerDpc routine is called as soon the IRQL on any processor in the machine falls below DISPATCH_LEVEL.

    The CustomTimerDpc routine, like all DPCs, is called at IRQL DISPATCH_LEVEL.

The smallest time interval that can be specified to KeSetTimer and KeSetTimerEx is approximately ten milliseconds, so a driver can use a CustomTimerDpc routine when timing smaller intervals than an IoTimer routine, which is run once per second, can handle.

Only one instantiation of a given timer object can be queued at any given moment. Calling KeSetTimer or KeSetTimerEx again with the same Timer object pointer cancels the queued timer object and resets it.

Setting up a CustomTimerDpc routine is exactly like setting up a CustomDpc routine, with an additional step to initialize the timer object. In fact, their prototypes are identical, but CustomTimerDpc routine cannot use the two SystemArgument pointers declared in its prototype.


Providing CustomTimerDpc Context Information

The DeferredContext pointer passed to KeInitializeDpc points to a context area where other driver routines, and the CustomTimerDpc routine itself, can maintain state. The Kernel passes the DeferredContext pointer in every call to the DPC routine.

Unlike an IoTimer routine, a CustomTimerDpc has no particular associations with a driver-created device object. However, a driver can associate a CustomTimerDpc routine with a driver-created device object by including a pointer to the device object in its context area.

The context area must be in resident, driver-allocated memory. Usually, this context area is in a device extension, but it can also be in nonpaged pool. If the driver uses a controller object, It can be in a controller extension. The contents of the context area are driver-determined.

If a CustomTimerDpc routine shares context information with the driver's ISR, the CustomTimerDpc routine must use KeSynchronizeExecution to call a SynchCritSection routine that accesses the shared context. For more information, see Using Critical Sections.

If the CustomTimerDpc shares the context information with other non-ISR driver routines, the area at DeferredContext must be protected by an executive spin lock. For more information, see Spin Locks.


Using a CustomTimerDpc Routine

To disable a previously set timer object, a driver calls KeCancelTimer. This routine removes the timer object for the system's timer queue. Generally, the timer object is not set to the signaled state and the CustomTimerDpc routine is not queued for execution. However, if the timer is about to expire when KeCancelTimer is called, expiration might occur before KeCancelTimer has a chance to access the time queue, in which case signaling and DPC queuing will occur.

Re-calling KeSetTimer or KeSetTimerEx, with previously specified Timer and Dpc pointers, before the previously specified interval expires, has the following effects:

  • The Kernel removes the timer object from the timer queue, without setting the object to the signaled state or queuing the CustomTimerDpc routine.
  • The kernel re-inserts the timer object in the timer queue, using the new DueTime value.

Using the same timer object for different purposes can cause race conditions or serious driver errors. For example, assume a driver specifies a single timer object both to set up a call to a CustomTimerDpc routine and to set up waits in a driver-dedicated thread. Whenever the driver-dedicated thread calls KeSetTimer, KeSetTimerEx, or KeCancelTimer for the common timer object, the thread would cancel calls to the CustomTimerDpc routine, if the timer object was already queued for a CustomTimerDpc call.

If a driver has CustomTimerDpc routines, and also waits on timer objects in a nonarbitrary thread context, it should:

  • Never use a thread-context-sensitive timer object in a nonarbitrary thread context, or vice versa.
  • Allocate a separate timer object for each CustomTimerDpc routine. Each set of driver threads or driver routines that are called in a nonarbitrary thread context should have its own set of "waitable" timer objects.

If you use a CustomTimerDpc routine, choose carefully the interval the driver passes in calls to KeSetTimer or KeSetTimerEx. In addition, consider all possible effects of a call to KeCancelTimer with the same timer object from any driver routine that makes this call, particularly on SMP platforms.

Keep in mind the following fact about CustomTimerDpc routines

Only one instantiation of a DPC object representing a particular DPC routine can be queued for execution at any given moment.

If a second driver routine calls KeSetTimer or KeSetTimerEx to run the same CustomTimerDpc routine before the interval specified by the first caller expires, the CustomTimerDpc routine is run only after the interval specified by the second caller expires. In these circumstances, the CustomTimerDpc does none of the work for which the first routine called KeSetTimer or KeSetTimerEx.

For drivers that have CustomTimerDpc routines and use periodic timers:

A driver cannot deallocate a periodic timer from a DPC routine. Drivers can deallocate only non-periodic timers from a DPC routine.

Consider the following a design guideline for drivers that have both CustomDpc and CustomTimerDpc routines

To prevent race conditions, never pass the same Dpc pointer to KeSetTimer or KeSetTimerEx and KeInsertQueueDpc.

In other words, suppose a driver's StartIo routine calls KeSetTimer or KeSetTimerEx to queue a CustomTimerDpc routine, and the driver's ISR calls KeInsertQueueDpc simultaneously from another processor with the same Dpc pointer. That DPC routine will be run when IRQL on a processor falls below DISPATCH_LEVEL or the timer interval expires, whichever comes first. Whichever does come first, some essential work for the StartIo or ISR would simply be dropped by the DPC routine.

In addition, a DPC used by two standard driver routines with very different functionality would have poorer performance characteristics than separate CustomTimerDpc and CustomDpc routines. The DPC would have to determine which operations to carry out, depending on the conditions that caused the StartIo routine or ISR to queue it. Testing for these conditions in the DPC would use additional CPU cycles.


Event Objects

A driver can use an event object to wait while the next-lower driver processes an IRP set up by the waiting driver. Drivers that have driver-created threads or driver dispatch routines that wait on the completion of a synchronous I/O request also can use an event object to synchronize operations between their threads and/or other driver routines.

Any driver that uses an event object must call KeInitializeEvent, IoCreateNotificationEvent, or IoCreateSynchronizationEvent before it waits on, sets, clears, or resets the event. The following figure illustrates how a driver with a thread can use an event object for synchronization.

Waiting on an Event Object

As the previous figure shows, such a driver must provide the storage for the event object, which must be resident. The driver can use the device extension of a driver-created device object, the controller extension if it uses a controller object, or nonpaged pool allocated by the driver.

When the driver calls KeInitializeEvent, it must pass a pointer to the driver's resident storage for the event object. In addition, the caller must specify the initial state (signaled or not-signaled) for the event object. The caller also must specify the event type, which can be either of the following:

  • SynchronizationEvent

    When a synchronization event is set to the Signaled state, a single thread that is waiting on the event becomes eligible for execution and the event's state is automatically reset to Not-Signaled.

    This type of event is sometimes called an autoclearing event, because its Signaled state is automatically reset each time a wait is satisfied.

  • NotificationEvent

    When a notification event is set to the Signaled state, all threads that were waiting on the event become eligible for execution and the event remains in the Signaled state until an explicit reset to Not-Signaled occurs: that is, there is a call to KeClearEvent or KeResetEvent with the given Event pointer.

Few device or intermediate drivers have a single driver-dedicated thread, let alone a set of threads that might synchronize their operations by waiting on an event that protects a shared resource.

Most drivers that use event objects to wait for the completion of an I/O operation set the input Type to NotificationEvent when they call KeInitializeEvent. An event object set up for IRPs that a driver creates with IoBuildSynchronousFsdRequest or IoBuildDeviceIoControlRequest is almost always initialized as a NotificationEvent because the caller will wait on the event for notification that its request has been satisfied by one or more lower-level drivers.

After the driver has initialized itself, its driver-dedicated thread, if any, and other routines can synchronize their operations on the event. For example, a driver with a thread that manages the queuing of IRPs, such as the system floppy controller driver, might synchronize IRP processing on an event, as shown in the previous figure:

  1. The thread, which has dequeued an IRP for processing on the device, calls KeWaitForSingleObject with a pointer to the driver-supplied storage for the initialized event object.
  2. Other driver routines carry out device I/O operations necessary to satisfy the IRP, and, when these operations are complete, the driver's DpcForIsr routine calls KeSetEvent with a pointer to the event object, a driver-determined priority boost for the thread (Increment, as shown in the previous figure), and a Boolean Wait set to FALSE. Calling KeSetEvent sets the event object to the Signaled state, thereby changing the waiting thread's state to ready.
  3. The Kernel dispatches the thread for execution as soon as a processor is available: that is, no other thread with a higher priority is currently in the ready state and there are no kernel-mode routines to be run at raised IRQL (greater than PASSIVE_LEVEL).

    The thread now can complete the IRP if the DpcForIsr has not called IoCompleteRequest with the IRP already, and can dequeue another IRP to be processed on the device.

Calling KeSetEvent with the Wait parameter set to TRUE indicates the caller's intention to immediately call a KeWaitForSingleObject or KeWaitForMultipleObjects support routine on return from KeSetEvent.

Consider the following guidelines for setting the Wait parameter to KeSetEvent:

A pageable thread or pageable driver routine that runs at IRQL PASSIVE_LEVEL should never call KeSetEvent with the Wait parameter set to TRUE. Such a call causes a fatal page fault if the caller happens to be paged out between the calls to KeSetEvent and KeWaitForSingleObject or KeWaitForMultipleObjects.

Any standard driver routine that runs at an IRQL greater than PASSIVE_LEVEL cannot wait for a nonzero interval on any dispatcher object(s) without bringing down the system. However, such a routine can call KeSetEvent while running at an IRQL less than or equal to DISPATCH_LEVEL.

For a summary of the IRQLs at which standard driver routines run, see Managing Hardware Priorities.

KeResetEvent returns the previous state of a given Event: whether it was set to Signaled or not when the call to KeResetEvent occurred. KeClearEvent simply sets the state of the given Event to Not-Signaled.

Consider the following a guideline for when to call the preceding support routines:

For better performance, every driver should call KeClearEvent unless the caller needs the information returned by KeResetEvent to determine what to do next.


Semaphore Objects

Any driver can use a semaphore object to synchronize operations between its driver-created threads and other driver routines. For example, a driver-dedicated thread might put itself into a wait state when there are no outstanding I/O requests for the driver, and the driver's dispatch routines might set the semaphore to the Signaled state just after they queue an IRP.

The dispatch routines of highest-level drivers, which are run in the context of the thread requesting an I/O operation, might use a semaphore to protect a resource shared among the dispatch routines. Lower-level driver dispatch routines for synchronous I/O operations also might use a semaphore to protect a resource shared among that subset of dispatch routines or with a driver-created thread.

Any driver that uses a semaphore object must call KeInitializeSemaphore before it waits on or releases the semaphore. The following figure illustrates how a driver with a thread can use a semaphore object.

Waiting on a Semaphore Object

As the previous figure shows, such a driver must provide the storage for the semaphore object, which should be resident. The driver can use the device extension of a driver-created device object, the controller extension if it uses a controller object, or nonpaged pool allocated by the driver.

When the driver's AddDevice routine calls KeInitializeSemaphore, it must pass a pointer to the driver's resident storage for the semaphore object. In addition, the caller must specify a Count for the semaphore object, as shown in the previous figure, that determines its initial state (nonzero for Signaled).

The caller also must specify a Limit for the semaphore, which can be either of the following:

  • Limit = 1

    When this semaphore is set to the Signaled state, a single thread waiting on the semaphore becomes eligible for execution and can access whatever resource is protected by the semaphore.

    This type of semaphore is also called a binary semaphore because a thread either has or does not have exclusive access to the semaphore-protected resource.

  • Limit > 1

    When this semaphore is set to the Signaled state, some number of threads waiting on the semaphore object become eligible for execution and can access whatever resource is protected by the semaphore.

    This type of semaphore is called a counting semaphore because the routine that sets the semaphore to the Signaled state also specifies how many waiting threads can have their states changed from waiting to ready. The number of such waiting threads can be the Limit set when the semaphore was initialized or some number less than this preset Limit.

Few device or intermediate drivers have a single driver-created thread; even fewer have a set of threads that might wait on a semaphore. Few system-supplied drivers use semaphore objects, and, of those that do, even fewer use a binary semaphore. Although a binary semaphore might seem to be similar in functionality to a mutex object, a binary semaphore does not provide the built-in protection against deadlocks that a mutex object has for system threads running in SMP machines.

After a driver with an initialized semaphore is loaded, it can synchronize operations on the semaphore that protects a shared resource. For example, a driver with a device-dedicated thread that manages the queuing of IRPs, such as the system floppy controller driver, might synchronize IRP queuing on a semaphore, as shown in the previous figure:

  1. The thread calls KeWaitForSingleObject with a pointer to the driver-supplied storage for the initialized semaphore object to put itself into a wait state.
  2. IRPs begin to come in that require device I/O operations. The driver's dispatch routines insert each such IRP into an interlocked queue under spin-lock control and call KeReleaseSemaphore with a pointer to the semaphore object, a driver-determined priority boost for the thread (Increment, as shown in the previous figure), an Adjustment of one that is added to the semaphore's Count as each IRP is queued, and a Boolean Wait set to FALSE. A nonzero semaphore Count sets the semaphore object to the Signaled state, thereby changing the waiting thread's state to ready.
  3. The Kernel dispatches the thread for execution as soon as a processor is available: that is, no other thread with a higher priority is currently in the ready state and there are no kernel-mode routines to be run at raised IRQL (greater than PASSIVE_LEVEL).

    The thread removes an IRP from the interlocked queue under spin-lock control, passes it on to other driver routines for further processing, and calls KeWaitForSingleObject again. If the semaphore is still set to the Signaled state (that is, its Count remains nonzero, indicating that more IRPs are in the driver's interlocked queue), the Kernel again changes the thread's state from waiting to ready.

    By using a counting semaphore in this manner, such a driver thread "knows" there is an IRP to be removed from the interlocked queue whenever that thread is run.

Calling KeReleaseSemaphore with the Wait parameter set to TRUE indicates the caller's intention to immediately call a KeWait..Object(s) support routine on return from KeReleaseSemaphore.

Consider the following guidelines for setting the Wait parameter to KeReleaseSemaphore:

A pageable thread or pageable driver routine that runs at IRQL PASSIVE_LEVEL should never call KeReleaseSemaphore with the Wait parameter set to TRUE. Such a call causes a fatal page fault if the caller happens to be paged out between the calls to KeReleaseSemaphore and KeWait..Object(s).

Any standard driver routine that runs at an IRQL greater than PASSIVE_LEVEL cannot wait for a nonzero interval on any dispatcher object(s) without bringing down the system; see Kernel Dispatcher Objects for details. However, such a routine can call KeReleaseSemaphore while running at an IRQL less than or equal to DISPATCH_LEVEL.

See Managing Hardware Priorities for a summary of the IRQLs at which standard driver routines run. For IRQL requirements of a specific support routine, see the routine's reference page.


Mutex Objects

As its name suggests, a mutex object is a synchronization mechanism designed to ensure mutually exclusive access to a single resource shared among a set of kernel-mode threads. Only highest-level drivers, such as FSDs that use executive worker threads, are likely to use a mutex object.

Possibly, a highest-level driver with driver-created threads and/or worker-thread callback routines might use a mutex object. However, any driver with pageable thread(s) or worker-thread callbacks must manage the acquisitions of, waits on, and releases of its mutex object(s) very carefully.

As already mentioned in the preceding section, mutex objects have built-in features that provide system (kernel-mode only) threads mutually exclusive, deadlock-free access to shared resources in SMP machines. Every mutex object has two basic built-in features that provide this protection for resources shared between or among system threads:

  • Ownership

    The Kernel assigns ownership of a given mutex to a single thread at a time, which has the following effects:

    • Raises the owning thread's runtime priority to the lowest real-time priority if that thread's priority is not already in the real-time range
    • Prevents the owning thread's process from leaving the balance set: that is, the process will not be paged out to secondary storage
    • Prevents the delivery of normal kernel-mode asynchronous procedure calls (APCs). The thread will not be preempted by an APC unless the Kernel issues an APC_LEVEL software interrupt to run a special kernel APC, such as the I/O Manager's IRP completion routine that returns results to the original requester of an I/O operation

    A thread can acquire ownership of a mutex object that it already owns (recursive ownership), but a recursively acquired mutex object is not set to the Signaled state until the thread releases its ownership completely. Such a thread must explicitly releases the mutex as many times as it acquired ownership before another thread can acquire the mutex.

    The Kernel never permits a thread that owns a mutex to cause a transition to user mode without first releasing the mutex and setting it to the Signaled state. If any FSD- or driver-created thread that owns a mutex attempts to return control to the I/O Manager before releasing ownership of the mutex, the Kernel brings down the system.

  • Level

    A driver thread can acquire more than one mutex. In this case, the driver should be designed so that the Level of each mutex object determines whether such a thread can acquire ownership of the mutex at any particular time. Specifically, the driver should enforce the following policy:

    • A thread should acquire mutexes in ascending order of assigned Level. The driver can assign a nonzero Level when it initializes the mutex.

    Thus, the owner of a mutex must not attempt to acquire another mutex with a lower Level since this other mutex might already be owned by another thread that is trying to acquire the first thread's higher Level mutex. If a driver does not enforce this policy, the scenario that results would cause deadlocks since neither thread could acquire ownership of the other thread's currently held mutex.

Any driver that uses a mutex object must call KeInitializeMutex once before it waits on or releases its mutex object. The following figure illustrates how two system threads might use a mutex object.

Waiting on a Mutex Object

As the previous figure shows, such a driver must provide the storage for the mutex object. Because drivers can wait on and release mutexes only within a thread context, a driver that creates its own system threads can provide storage for its mutex objects in paged pool, allocated by the driver.

If such a highest-level driver uses system worker threads or waits on the mutex in its dispatch routines, it must provide resident storage in the device extension of a driver-created device object), in the controller extension if it uses a controller object, or in nonpaged pool allocated by the driver.

When a driver calls KeInitializeMutex (typically from its AddDevice routine), it must pass a pointer to the driver's storage for the mutex object, which the Kernel initializes to the Signaled state. In addition, the caller can specify a nonzero Level for the mutex object (as shown in the previous figure) to control the order of acquisition if the caller uses more than one mutex.

After such a highest-level driver has initialized, it can manage mutually exclusive access to a shared resource as shown in the previous figure. For example, a driver's dispatch routines for inherently synchronous operations and thread(s) might use a mutex to protect a driver-created queue for IRPs.

Because KeInitializeMutex always sets the initial state of a mutex object to Signaled, as the previous figure shows:

  1. A dispatch routine's initial call to KeWaitForSingleObject with the Mutex pointer puts the current thread immediately into the ready state, gives the thread ownership of the mutex, and resets the mutex state to Not-Signaled. As soon as the dispatch routine resumes running, it can safely insert an IRP into the mutex-protected queue.
  2. When a second thread (another dispatch routine, driver-supplied worker-thread callback routine, or driver-created thread) calls KeWaitForSingleObject with the Mutex pointer, the second thread is put into the wait state.
  3. When the dispatch routine finishes queuing the IRP as described in Step 1, it calls KeReleaseMutex with the Mutex pointer and a Boolean Wait value, which indicates whether it intends to call KeWaitForSingleObject (or KeWaitForMutexObject) with the Mutex as soon as KeReleaseMutex returns control.
  4. Assuming the dispatch routine released its ownership of the mutex in Step 3 (Wait set to FALSE), the mutex is set to the Signaled state by KeReleaseMutex. The mutex currently has no owner, so the Kernel determines whether another thread is waiting on that mutex. If so, the Kernel makes the second thread (see Step 2) the mutex owner, possibly boosts the thread's priority to the lowest real-time priority value, and changes its state to ready.
  5. The Kernel dispatches the second thread for execution as soon as a processor is available: that is, when no other thread with a higher priority is currently in the ready state and there are no kernel-mode routines to be run at raised IRQL (greater than PASSIVE_LEVEL). The second thread (a dispatch routine queuing an IRP, or the driver's worker-thread callback routine or driver-created thread dequeuing an IRP) can now safely access the mutex-protected queue of IRPs until it calls KeReleaseMutex.

If a thread acquires ownership of a mutex object recursively, that thread must explicitly call KeReleaseMutex as many times as it waited on the mutex in order to set the mutex object to the Signaled state. For example, if a thread calls KeWaitForSingleObject and then KeWaitForMutexObject with the same Mutex pointer, it must call KeReleaseMutex twice when it acquires the mutex in order to set that mutex object to the Signaled state.

Calling KeReleaseMutex with the Wait parameter set to TRUE indicates the caller's intention to immediately call a KeWait..Object(s) support routine on return from KeReleaseMutex.

Consider the following guidelines for setting the Wait parameter to KeReleaseMutex:

A pageable thread or pageable driver routine that runs at IRQL PASSIVE_LEVEL should never call KeReleaseMutex with the Wait parameter set to TRUE. Such a call causes a fatal page fault if the caller happens to be paged out between the calls to KeReleaseMutex and KeWait..Object(s).

Any standard driver routine that runs at an IRQL greater than PASSIVE_LEVEL cannot wait for a nonzero interval on any dispatcher object(s) without bringing down the system. However, such a routine can call KeReleaseMutex if it owns the mutex while running at an IRQL less than or equal to DISPATCH_LEVEL.

See Managing Hardware Priorities for a summary of the IRQLs at which standard driver routines run.


Thread Objects

This section contains the following topics:

Introduction to Thread Objects

Thread Priorities

Device-Dedicated Threads

System Worker Threads


Introduction to Thread Objects

A user-mode thread object represents a path of execution within the current process. Every user-mode thread object is implemented through the use of an embedded kernel-mode thread object.

A kernel-mode thread object is an instance of a Kernel-defined dispatcher object type. The thread that it represents is the basic schedulable entity in the OS.

A thread object:

  • Is dispatched for execution by the Kernel
  • Has the following properties at any given moment:
    • Dispatch state
    • Priority
    • Context
    • Execution mode (kernel or user)
    • Affinity
  • Is "owned by" a process object but can attach itself to another process's address space

Usually, most drivers execute in the context of the currently running thread, that is, in an arbitrary thread context. While a file system driver can create an independent process for its own device-dedicated threads, file systems usually avoid setting up a driver-created process and threads in order to conserve system memory and to avoid the overhead of context switches.

FSs (and other drivers) can set up device-dedicated (system-process) threads and/or FSs can use system worker threads if they need a driver-specific thread context in which to execute. Drivers use kernel-mode Ps (Process Structure) routines to create processes and/or device-dedicated threads. FSs call routines supplied by the Executive Support component to use system worker threads.


Thread Priorities

Some drivers create their own driver- or device-dedicated system threads and set their thread's base priority to the lowest real-time priority value. Other highest-level drivers, particularly file system drivers, use system worker threads with a base priority that is usually set to the highest variable priority value. The Kernel schedules a thread with the lowest real-time priority to run ahead of every thread with a variable priority, which includes almost every user-mode thread in the system.

Most standard driver routines are run in an arbitrary thread context, ahead of all threads that are currently in the ready state.

Threads, whatever their respective runtime priorities, are run at IRQL PASSIVE_LEVEL. Many standard driver routines are run at raised IRQL: that is, at a hardware priority greater than PASSIVE_LEVEL, such as IRQL DISPATCH_LEVEL or DIRQL.


Device-Dedicated Threads

The driver of a slow device or a device that is seldom used (like the floppy controller) can solve many "waiting" problems by creating a device-dedicated system thread. Additionally, most file system drivers use system worker threads and supply worker-thread callback routines.

If a device driver has its own thread context or is running in a system-thread context, the device-dedicated thread or highest-level driver's worker-thread callback routine can synchronize operations on a dispatcher object, such as an event object or semaphore object, in a shared communication region of the driver's device extension. For example, a device-dedicated thread can wait for a shared dispatcher object, while the thread's device is not in use, by calling KeWaitForSingleObject for a semaphore. Until the device driver is called to carry out an I/O operation (at which point it sets the semaphore to the Signaled state), its waiting thread uses no CPU time.

A driver can call PsCreateSystemThread to create a driver- or device-dedicated thread, and then call KeSetBasePriorityThread to set the thread's base priority. The driver should specify a priority value that avoids runtime priority inversions in SMP machines. That is, setting the base priority of a driver-created thread too high can create delays in the execution of lower priority threads that submit I/O requests for that driver.

Since thread objects are themselves a type of dispatcher object, a thread can wait for another thread to complete. To obtain the thread object pointer associated with a thread, a driver can call ObReferenceObjectByHandle, passing in the thread handle received from PsCreateSystemThread.

A thread can call KeDelayExecutionThread to wait for an interval that could be a full time slice or longer. The granularity of a KeDelayExecutionThread interval is around 10 milliseconds. Because KeDelayExecutionThread is a timer-driven routine, the granularity of its interval is slightly faster or slower than 10 milliseconds, depending on the platform.


System Worker Threads

System worker thread are kernel-mode threads provided by the Executive that drivers, particularly FSDs, can use to get work done within a nonarbitrary thread/process context. A driver calls IoAllocateWorkItem, then IoQueueWorkItem, to set up a work queue item and specify a driver-supplied callback routine. The Kernel queues the callback routine to be run by a system worker thread.


Do Waiting Threads Receive Alerts and APCs?

The way a waiting thread responds to alerts and APC delivery depends on a number of factors. In some cases, an alert will cause a wait to be aborted, while in others it will not. Likewise, APCs are delivered to waiting threads only under certain circumstances. The following table summarizes the treatment of alerts and APCs by threads waiting on dispatcher objects.

Four kernel support routines initiate a wait on a dispatcher object: KeWaitForSingleObject, KeWaitForMultipleObjects, KeWaitForMutexObject, and KeDelayExecutionThread. All four of these routines take a pair of Boolean parameters called Alertable and WaitMode. The effects of the values that can be assigned to these two parameters are complex. Assigning a value of TRUE to the Alertable parameter, for instance, does not guarantee that the waiting thread can be alerted. The rest of this section provides a summary of how the settings of the Alertable and WaitMode parameters affect the behavior of the waiting thread.

Parameter Settings of KeWaitForXxx Routines | Special Kernel-Mode APC |  | Normal Kernel-Mode APC |  | User-Mode APC |  | Alerts
 | Wait Aborted? | APC Delivered and Executed? | Wait Aborted? | APC Delivered and Executed? | Wait Aborted? | APC Delivered and Executed? | Wait Aborted?
Alertable = TRUE WaitMode = User | No | If (A) then Yes | No | If (B) then Yes | Yes | Yes, after thread returns to user mode | Yes
Alertable = TRUE WaitMode = Kernel | No | If (A) then Yes | No | If (B) then Yes | No (since WaitMode = Kernel) | No | Yes
Alertable = FALSE WaitMode = User | No | If (A) then Yes | No | If (B) then Yes | No (since Alertable = FALSE) | No (with exceptions, EX. ^C to terminate) | No
Alertable = FALSE WaitMode = Kernel | No | If (A) then Yes | No | If (B) then Yes | No (since Alertable = FALSE and since WaitMode = Kernel) | No | No

  1. IRQL < APC_LEVEL
  2. IRQL < APC_LEVEL, thread not already in an APC, thread not in a critical section

The Alertable parameter specifies whether the thread can be alerted and its wait state aborted by an alert originating from an undocumented internal kernel routine or by a user-mode APC. If the value of Alertable is FALSE then the thread cannot be alerted, no matter what the value of the WaitMode parameter or the origin of the alert. The only exception to this rule is that of a terminating thread. A thread is automatically made alertable, for instance, when terminated by a user with a Ctrl+C.

If the value of Alertable is TRUE and one of the following conditions is present, the thread will be alerted:

  1. The origin of the alert is an internal, undocumented kernel-mode routine used to alert threads.
  2. The origin of the alert is a user-mode APC, and the value of the WaitMode parameter is UserMode.

In the first of these two cases, the thread's wait is satisfied with the completion status STATUS_ALERTED; in the second case, it is satisfied with the completion status STATUS_USER_APC.

The thread must be alertable for a user-mode APC to be delivered. However, a kernel-mode APC can be delivered and executed even though the thread is not alerted. Once the APC's execution completes, the thread's wait resumes. A thread is never alerted, nor is its wait aborted, by the delivery of a kernel-mode APC.

The delivery of kernel-mode APCs to a waiting thread does not depend on whether the thread can be alerted. If the APC is a special kernel-mode APC, then the APC is delivered provided that IRQL < APC_LEVEL. If the APC is a normal kernel-mode APC, then the APC is delivered provided that the following three conditions hold: (1) IRQL < APC_LEVEL; (2) no kernel-mode APC is in progress; and (3) the thread is not in a critical section.

Note that unlike the KeWait Xxx routines, the routine KeDelayExecutionThread does not take an Object parameter. KeDelayExecutionThread initiates a wait on the dispatcher object associated with the calling thread. Threads waiting on thread-dispatcher objects respond to alerts and APC delivery in the same manner as threads waiting on other dispatcher objects.


Callback Objects

The Kernel's callback mechanism provides a general way for drivers to request and provide notification when certain conditions are satisfied.

A driver can create a callback object, and other drivers can request notification for conditions associated with this driver-defined callback. In addition, the system defines two callback objects for driver use.

Every callback object has a name and a set of attributes, defined when the object is created. The system-defined callback objects are named \Callback\SetSystemTime and \Callback\PowerState; driver-defined callbacks must not duplicate these names.

To request notification from a system- or driver-defined callback, a driver opens the callback object and registers a callback routine. When the conditions defined for the callback become true, its creator triggers notification. In turn, the system calls all the callback routines registered for the callback.

This section contains the following topics:

Defining a Callback Object

Using a Driver-Defined Callback Object

Using a System-Defined Callback Object


Defining a Callback Object

A driver can create a callback object, through which other drivers can request notification of conditions defined by the creating driver. The following figure shows the steps involved in defining a callback object.

Defining a Callback Object

Before creating the object, the driver calls InitializeObjectAttributes to set its attributes. A callback object must have a name, which cannot match the name of a system-defined callback; it can have whatever other attributes its creator deems appropriate, typically OBJ_CASE_INSENSITIVE. Next, the driver calls ExCreateCallback , passing a pointer to the initialized attributes and a location at which to receive a handle to the callback object. It also passes two Booleans, indicating whether the system should create the callback object if such a named object does not already exist, and whether the object should allow more than one registered callback routine.

The driver defines the conditions for which it will call the registered callback routines. The conditions take the form of two arguments, each pointing to a parameter defined by the driver that creates the callback. You should document these conditions, along with the name of the callback object and the IRQL at which it requests notification, for clients of the driver.

When the callback condition occurs, the driver calls ExNotifyCallback, passing its handle to the callback object and the two arguments. The system then calls all callback routines registered for the callback object, in the order in which they were registered, passing the two arguments and a pointer to the context supplied when the routine was registered. The driver must call ExNotifyCallback at IRQL <= DISPATCH_LEVEL; the system calls the callback routines at the same IRQL at which the driver made this call.

After all operations have been completed with the callback object, the driver that created the callback should call ObDereferenceObject to decrement its reference count and ensure that the object is deleted.


Using a Driver-Defined Callback Object

To use a callback object defined by another driver, a driver opens the object, then registers a routine to be called when the callback is triggered, as shown in the following figure. The driver requesting notification must know the name of the callback object and must understand the semantics of the arguments passed to the callback routine.

Registering for Callback Notification

Before it can open the object, the driver must call InitializeObjectAttributes to create an attribute block, specifying the name of the object. After it has a pointer to an attribute block, it calls ExCreateCallback, passing the attribute pointer, a location in which to receive a handle to the callback, and FALSE for the Create parameter, indicating that it requires an existing callback object.

The driver can then call ExRegisterCallback with the returned handle to register its callback routine.

The callback routine has the following prototype:

typedef VOID (*PCALLBACK_FUNCTION ) (
    IN PVOID CallbackContext,
    IN PVOID Argument1,
    IN PVOID Argument2
    );

The CallbackContext parameter is the context to be passed to the callback routine each time it is called. Unless the context is simply 32 bits of data, the caller should allocate it from nonpaged pool if the routine can be called at DISPATCH_LEVEL. The two arguments are defined by the component that created the callback. Typically, the arguments provide information about the conditions that triggered the callback.

When the creator of the callback triggers notification, the system calls the registered routine, passing a pointer to the context and the two arguments. Values for the arguments are supplied by the component that created the callback. The callback routine is called at the same IRQL at which the creating driver triggered notification, always IRQL<=DISPATCH_LEVEL.

In its callback routine, a driver can perform whatever tasks it requires for the current conditions.

When the driver no longer requires notification, it should call ExUnregisterCallback to remove its routine from the list of registered callbacks and to remove its reference to the callback object.


Using a System-Defined Callback Object

The system defines two callback objects for driver use:

\Callback\SetSystemTime

\Callback\PowerState

Drivers that use the system time (for example, file system drivers) might register for the SetSystemTime callback. This callback provides for notification when the system time changes.

The PowerState callback provides for notification when one of the following occurs:

  • The system switches from AC to DC power or vice versa.
  • The system power policy changes as the result of a user or application request.
  • A transition to a system sleep or shutdown state is imminent. A driver can request notification so that it can lock code into memory in anticipation of shutdown. Callback routines will be notified before the Power Manager sends the system set-power IRP.

To use a system-defined callback, a driver initializes an attribute block (InitializeObjectAttributes) with the callback's name, then opens the callback object (ExCreateCallback), just as for a driver-defined callback. The driver should not request that the callback object be created.

With the handle returned by ExCreateCallback, the driver calls ExRegisterCallback to register a notification routine, passing a pointer to an arbitrary context and a pointer to its routine. A driver can register its callback routine any time. When the specified condition occurs, the system calls the registered callback routine at IRQL <=DISPATCH_LEVEL.

When the driver no longer requires notification, it should call ExUnregisterCallback to delete its callback routine from the list of registered callbacks and to remove its reference to the callback object.


Spin Locks

This section contains the following topics:

Introduction to Spin Locks

Providing Storage for Spin Locks and Protected Data

Initializing Spin Locks

Calling Support Routines That Use Spin Locks

Using Spin Locks – An Example

Preventing Errors and Deadlocks While Using Spin Locks


Introduction to Spin Locks

Spin locks are kernel-defined, kernel-mode-only synchronization mechanisms, exported as an opaque type: KSPIN_LOCK. A spin lock can be used to protect shared data or resources from simultaneous access by routines that can execute concurrently and at raised IRQL in SMP machines.

Many components use spin locks, including drivers. Any kind of driver might use one or more executive spin locks. For example, most file systems use an interlocked work queue in the FSD's device extension to store IRPs that are processed both by the file system's worker-thread callback routines and by the FSD. An interlocked work queue is protected by an executive spin lock, which resolves contention among the FSD trying to insert IRPs into the queue and any threads simultaneously trying to remove IRPs. As another example, the system floppy controller driver uses two executive spin locks. One executive spin lock protects an interlocked work queue shared with this driver's device-dedicated thread; the other protects a timer object shared by three driver routines.

Drivers for Windows XP and later operating system can use KeAcquireInStackQueuedSpinLock and KeReleaseInStackQueuedSpinLock to acquire and release the spin lock as a queued spin lock. Queued spin locks provide better performance than ordinary spin locks, especially on multiprocessor machines. See Queued Spin Locks for more information. Drivers for Windows 2000 can use KeAcquireSpinLock and KeReleaseSpinLock to acquire and release a spin lock as an ordinary spin lock.

To synchronize access to simple data structures, drivers can use any of the ExInterlockedXxx routines to ensure atomic access to the data structure. Drivers that use these routines do not need to acquire or release the spin lock explicitly.

Every driver that has an ISR uses an interrupt spin lock to protect any data or hardware shared between its ISR and its SynchCritSection routines that are usually called from its StartIo and DpcForIsr routines. An interrupt spin lock is associated with the set of interrupt objects created when the driver calls IoConnectInterrupt, as described in Registering an ISR.

Follow these guidelines for using spin locks in drivers:

  • Provide the storage for any data or resource protected by a spin lock and for the corresponding spin lock in resident system-space memory (nonpaged pool, as shown in the Virtual Memory Spaces and Physical Memory figure). A driver must provide the storage for any executive spin locks it uses. However, a device driver need not provide the storage for an interrupt spin lock unless it has a multivector ISR or has more than one ISR, as described in Registering an ISR.
  • Call KeInitializeSpinLock to initialize each spin lock for which the driver provides storage before using it to synchronize access to the shared data or resource it protects.
  • Call every support routine that uses a spin lock at an appropriate IRQL, generally at <= DISPATCH_LEVEL for executive spin locks or at <= DIRQL for an interrupt spin lock associated with the driver's interrupt object(s).
  • Implement routines to execute as quickly as possible while they hold a spin lock. No routine should hold a spin lock for longer than 25 microseconds.
  • Never implement routines that do any of the following while holding a spin lock:
    • Cause hardware exceptions or raise software exceptions
    • Attempt to access pageable memory
    • Make a recursive call that would cause a deadlock or could cause a spin lock to be held for longer than 25 microseconds
    • Attempt to acquire another spin lock if doing so might cause a deadlock
    • Call an external routine that violates any of the preceding rules


Providing Storage for Spin Locks and Protected Data

As part of device start-up, a driver must allocate resident storage for any spin-lock-protected data or resources and for corresponding spin locks in one of the following places:

  • The device extension of a device object that the driver sets up by calling IoCreateDevice
  • The controller extension of a controller object that the driver sets up by calling IoCreateController
  • Nonpaged, system-space memory that the driver obtains by calling ExAllocatePool

Attempting to access pageable data while holding a spin lock causes a fatal page fault if that page is not present. Referencing a spin lock that is invalid (because it was stored in pageable memory and is currently paged-out) also causes a fatal page fault.

A driver must provide the storage for each of the following kinds of executive spin lock it might use:

  • Any spin lock that the driver explicitly acquires and releases using any of the KeXxx spin lock routines.
  • Any spin lock used as a parameter to any of the ExInterlockedXxx routines.

While a driver can make calls to the ExInterlockedXxx routines from its ISR or SynchCritSection routines, it cannot use any of the KeXxx routines to acquire and release spin locks at any IRQL greater than DISPATCH_LEVEL. Consequently, any driver that reuses a spin lock between calls to the KeXxxSpinLock and ExInterlockedXxx routines must make every call while running at IRQL <= DISPATCH_LEVEL.

A driver can pass the same spin lock to ExInterlockedInsertHeadList as it does to another ExInterlockedXxx routine, as long as both routines use the spin lock at the same IRQL. For more information about how spin lock usage affects performance, see Using Spin Locks – An Example.

In addition to the storage for its executive spin locks, a device driver must provide the storage for another spin lock to be associated with its interrupt object(s) if it has a multivector ISR or more than one ISR.


Initializing Spin Locks

Before calling any support routine that requires access to a caller-supplied executive spin lock, a driver must call KeInitializeSpinLock to initialize the corresponding executive spin lock. Support routines that require an initialized executive spin lock include the following:

  • KeAcquireSpinLock and, subsequently, KeReleaseSpinLock
  • KeAcquireSpinLockAtDpcLevel and, subsequently, KeReleaseSpinLockFromDpcLevel
  • KeAcquireInStackQueuedSpinLock and, subsequently, KeReleaseInStackQueuedSpinLock
  • KeAcquireInStackQueuedSpinLockAtDpcLevel and, subsequently, KeReleaseInStackQueuedSpinLockFromDpcLevel
  • An ExInterlocked Xxx routine

Before calling IoConnectInterrupt and KeSynchronizeExecution, a lowest-level driver must call KeInitializeSpinLock to initialize an interrupt spin lock for which it provides storage.


Calling Support Routines That Use Spin Locks

Calling KeAcquireSpinLock or KeAcquireInStackQueuedSpinLock sets the IRQL on the current processor to DISPATCH_LEVEL until a corresponding call to KeReleaseSpinLock or KeReleaseInStackQueuedSpinLock restores the previous IRQL. Consequently, drivers must be executing at IRQL <= DISPATCH_LEVEL when they call KeAcquireSpinLock or KeAcquireInStackQueuedSpinLock.

Callers of KeAcquireSpinLockAtDpcLevel, KeAcquireInStackQueuedSpinLockAtDpcLevel, KeReleaseInStackQueuedSpinLockFromDpcLevel, and KeReleaseSpinLockFromDpcLevel run faster because they are already running at IRQL DISPATCH_LEVEL so these support routines need not reset IRQL on the current processor. Consequently, it is a fatal error on most Windows platforms to call KeAcquireSpinLockAtDpcLevel or KeAcquireInStackQueuedSpinLock while running at IRQL less than DISPATCH_LEVEL. It is also an error to release a spin lock that was acquired with KeAcquireSpinLock by calling KeReleaseSpinLockFromDpcLevel because the caller's original IRQL is not restored.

Routines that hold an executive spin lock, such as the ExInterlocked Xxx, usually execute at IRQL DISPATCH_LEVEL until they release the spin lock and return control to the caller. However, it is possible for a driver's InterruptService routine and SynchCritSection routines (which run at DIRQL) to call certain ExInterlocked Xxx routines, such as the ExInterlocked..List routines, as long as the spin lock passed to the routine is used exclusively by the ISR and SynchCritSection routines.

Each routine that holds an interrupt spin lock executes at the DIRQL of an associated set of interrupt objects. Therefore, a driver must not call KeAcquireSpinLock and KeReleaseSpinLock nor any other routine that uses an executive spin lock from its ISR or SynchCritSection routine(s). Such a call is an error that can cause a system deadlock, requiring the user to reboot his or her machine. Note that if a driver's ISR or SynchCritSection routine calls an ExInterlocked..List routine, the driver cannot reuse the spin lock it passes to the ExInterlocked..List routines in calls to the Ke..SpinLock or Ke..SpinLock..DpcLevel support routines.

If a driver has a multivector ISR or more than one ISR, its routines can call KeSynchronizeExecution while executing at any IRQL up to the SynchronizeIrql value specified for the associated interrupt objects when they were connected.


Preventing Errors and Deadlocks While Using Spin Locks

While a driver routine holds a spin lock, it cannot cause a hardware exception or raise a software exception without bringing down the system. In other words, a driver's ISR and any SynchCritSection routine that the driver supplies in a call to KeSynchronizeExecution must not cause a fault or trap, such as a page fault or an arithmetic exception, and cannot raise a software exception. A routine that calls KeAcquireSpinLock or KeAcquireInStackQueuedSpinLock also cannot cause a hardware exception or raise a software exception until it has released its executive spin lock and is no longer running at IRQL DISPATCH_LEVEL.

Pageable Data and Support Routines

While holding a spin lock, drivers must not call routines that access pageable data. Remember that drivers can call certain support routines that access pageable data if and only if their calls occur while executing at an IRQL strictly less than DISPATCH_LEVEL. This IRQL restriction precludes calling these support routines while holding a spin lock. For IRQL requirements for any specific support routine, see the routine's reference page.

Recursion

Attempting to acquire a spin lock recursively is guaranteed to cause a deadlock: the holding instantiation of a recursive routine cannot release the spin lock while a second instantiation spins, trying to acquire the same spin lock.

Follow these guidelines concerning spin lock usage with recursive routines:

  • The recursive routine must not call itself while holding a spin lock, or must not attempt to acquire the same spin lock on subsequent calls.
  • While the recursive routine holds a spin lock, another driver routine must not call the recursive routine if recursion might cause a deadlock or could cause the caller to hold the spin lock for longer than 25 microseconds.

For more information about recursive driver routines, see also Using the Kernel Stack.

Nested Spin Lock Acquisitions

Attempting to acquire a second spin lock while holding another spin lock also can cause deadlocks or poor driver performance.

Follow these implementation guidelines in drivers holding a spin lock:

  • The driver must not call a support routine that uses a spin lock unless a deadlock cannot occur.
  • Even if a deadlock cannot occur, the driver should not call a support routine that uses a spin lock unless alternate coding techniques cannot provide comparable driver performance and functionality.
  • If a driver makes nested calls to acquire spin locks, it must release those spin locks in inverse order: that is, if a driver acquires spin lock A before acquiring spin lock B, it must release spin lock B before it releases spin lock A.

In general, avoid using nested spin locks to protect overlapping subsets or discrete sets of shared data and resources. Consider what can happen if a driver uses two executive spin locks to protect discrete resources, such as a pair of timer objects that might be set individually and collectively by various driver routines. The driver would deadlock intermittently in an SMP machine, whenever either of two routines, each holding one spin lock, tried to acquire the other spin lock.

Even if a deadlock-proof driver can be designed to use nested spin locks, it could be difficult to implement successfully. Nested spin locks are difficult to debug and to test adequately in an SMP machine. Moreover, using nested spin locks can severely degrade both driver and system performance.


Queued Spin Locks

Queued spin locks are a more efficient version of spin locks. On multiprocessor machines, using queued spin locks guarantees that processors acquire the spin lock on a first-come first-served basis. Drivers for Windows XP and later operating systems should use queued spin locks instead of ordinary spin locks.

The driver supplies storage for the spin lock, and initializes it with KeInitializeSpinLock. The driver uses KeAcquireInStackQueuedSpinLock to acquire the queued spin lock, and KeReleaseInStackQueuedSpinLock to release it.

The driver allocates a KLOCK_QUEUE_HANDLE structure that it passes by pointer to KeAcquireInStackQueuedSpinLock. The driver passes the same structure by pointer to KeReleaseInStackQueuedSpinLock when it releases the spin lock. Drivers should normally allocate the structure on the stack each time they acquire the lock.

Drivers must not mix calls to the queued spin lock routines and the ordinary KeXxxSpinLock routines on the same spin lock.

If the driver is already at IRQL = DISPATCH_LEVEL, it can call KeAcquireInStackQueuedSpinLockAtDpcLevel and KeReleaseInStackQueuedSpinLockFromDpcLevel instead.


Additional Timers and Counters

This section contains information about additional timers and counters provided by the system for driver use. It includes the following topics:

IoTimer Routines

Counters


IoTimer Routines

Drivers that need to be called periodically to determine if a device operation has timed out, to update some driver-defined variable (such as a counter), to time any operation for which small time intervals are not required can use an IoTimer routine. An IoTimer routine is actually a DPC routine, associated with a device object, that the I/O Manager calls once per second. A driver can have an IoTimer routine for each device object that it creates.

In general, a driver should use an IoTimer routine to time operations that require regular one-second intervals. To time operations that require variable intervals or intervals shorter than once per second, a driver should allocate a timer object. For more information, see Timer Objects and DPCs.

This section contains the following topics:

Registering and Enabling an IoTimer Routine

Providing IoTimer Context Information

Using an IoTimer Routine


Registering and Enabling an IoTimer Routine

Any driver can register an IoTimer routine, after it creates one or more device objects, by calling IoInitializeTimer. The driver can then start the timer by calling IoStartTimer. The following figure illustrates these calls.

Using an IoTimer Routine

After calling IoCreateDevice to create device objects, a driver can call IoInitializeTimer with the entry point of its IoTimer routine, along with pointers to a driver-created device object and a context area in which the driver maintains whatever context its IoTimer routine uses. The I/O Manager associates the device object with a Kernel-allocated timer object and sets up the timer object to time out every second.

After the driver calls IoStartTimer, its IoTimer routine is called once per second until the driver calls IoStopTimer. A driver can re-enable calls to its IoTimer routine with IoStartTimer. (Frequently, when a driver calls IoStartTimer, it supplies the device object pointer obtained from the I/O stack location of the current IRP.)

On entry, the IoTimer routine is passed the device object pointer, along with the context pointer that the driver supplied when it called IoInitializeTimer.

Drivers must not call IoStopTimer from within an IoTimer routine.

The I/O Manager unregisters the timer routine for a specified device object and frees its associated context when the driver calls IoDeleteDevice.


Providing IoTimer Context Information

The Context pointer passed to IoInitializeTimer identifies a context area where other driver routines, and the IoTimer routine itself, can maintain state about timed operations. The I/O Manager passes the Context pointer whenever it calls the IoTimer routine.

Because an IoTimer routine is run at IRQL DISPATCH_LEVEL, its context area must be in resident, system-space memory. Most drivers that have IoTimer routines use the device extension of the associated device object as a Context-accessible area, but the context can instead be in a controller extension if the driver uses a controller object or in nonpaged pool allocated by the driver.

Follow these guidelines for an IoTimer routine's context area:

  • If the IoTimer routine shares its context area with the driver's ISR, it must use KeSynchronizeExecution to call a SynchCritSection routine that accesses the context area in a multiprocessor-safe manner. For more information, see Using Critical Sections.
  • If the IoTimer routine does not share its context area with an ISR, but does share it with another driver routine, the driver must protect the shared context area with an initialized executive spin lock, in order to access the context information in a multiprocessor-safe manner. For more information, see Spin Locks.


Using an IoTimer Routine

While the timer for the associated device object is enabled, the IoTimer routine is called approximately once per second. However, the intervals at which each IoTimer routine is called depends on the resolution of the system clock, so you should not assume that an IoTimer routine will be called precisely on a one-second boundary.

Perhaps the most common use for an IoTimer routine is to time-out device I/O operations for an IRP. Consider the following scenario for using an IoTimer routine as a running timer within a device driver:

  1. When it starts the device, the driver initializes a timer counter in the device extension to minus one, indicating no current device I/O operations, and calls IoStartTimer just before it returns STATUS_SUCCESS.

    Each time the IoTimer routine is called, it checks whether the timer counter is minus one, and, if so, returns control.

  2. The driver's StartIo routine initializes the timer counter in the device extension to an upper limit, plus an additional second in case the IoTimer routine has just been run. It then uses KeSynchronizeExecution to call a SynchCritSection_1 routine, which programs the physical device for the operation requested by the current IRP.
  3. The driver's ISR resets the timer counter to minus one before queuing the driver's DpcForIsr routine or a CustomDpc routine.
  4. Each time the IoTimer routine is called, it checks whether the timer counter has been reset by the ISR to minus one, and, if so, returns control. If not, the IoTimer routine uses KeSynchronizeExecution to call a SynchCritSection_2 routine, which adjusts the timer counter by some driver-determined number of seconds.
  5. The SynchCritSection_2 routine returns TRUE to the IoTimer routine as long as the current request has not yet timed out. If the timer counter goes to zero, the SynchCritSection_2 routine resets the timer counter to a driver-determined reset-time-out value, sets a reset-expected flag for itself (and for the DpcForIsr) in its context area, attempts to reset the device, and returns TRUE.

    The SynchCritSection_2 routine will be called again if its reset operation also times out on the device, when it returns FALSE. If its reset succeeds, the DpcForIsr routine determines that the device has been reset from the reset-expected flag and retries the request, repeating the actions of the StartIo routine as described in Step 2.

  6. If the SynchCritSection_2 routine returns FALSE, the IoTimer routine assumes the physical device is in an unknown state because an attempt to reset it has already failed. In these circumstances, the IoTimer routine queues a CustomDpc routine and returns. This CustomDpc routine logs a device I/O error, calls IoStartNextPacket, fails the current IRP, and returns.

If this device driver's ISR resets the shared timer counter to minus one, as described in Step 3, the driver's DpcForIsr routine completes the interrupt-driven I/O processing of the current IRP. The reset timer counter indicates that this device I/O operation has not timed out, so the IoTimer routine does not need to change the timer counter.

Under most circumstances, the preceding SynchCritSection_2 routine simply decrements the timer counter. The SynchCritSection_2 routine attempts to reset the device only if the current I/O operation has timed out, indicated when the timer counter goes to zero. And only if an attempt to reset the device has already failed does the SynchCritSection_2 routine return FALSE to the IoTimer routine.

Consequently, both the preceding IoTimer routine and its helper SynchCritSection_2 routine take very little time to execute under normal circumstances. By using an IoTimer routine in this manner, a device driver ensures that each valid device I/O request can be retried, if necessary, and that a CustomDpc routine will fail an IRP only if an uncorrectable hardware failure prevents the IRP from being satisfied. Moreover, the driver provides this functionality at very little cost in execution time.

The simplicity of the preceding scenario depends on a device that does only one operation at a time and on a driver that does not normally overlap I/O operations. A driver that carries out overlapped device I/O operations, or a higher-level driver that uses an IoTimer routine to time out a set of driver-allocated IRPs sent to more than one chain of lower drivers, would have more complex time-out scenarios to manage.


Counters

The system provides several driver support routines that return various count values.

KeQuerySystemTime

KeQueryInterruptTime

KeQueryTickCount

KeQueryPerformanceCounter

KeQueryTimeIncrement


Windows Management Instrumentation

This section describes Windows® Management Instrumentation (WMI) extensions to WDM. These extensions provide the mechanism by which drivers can make measurement and instrumentation data available to user-mode applications. User mode applications access WMI data through a user mode API. For more information on the user mode WMI API, refer to the Platform SDK. This chapter contains the following sections:

Introduction to WMI

WMI Architecture

WMI Requirements for WDM Drivers

MOF Syntax for WMI Data and Event Blocks

Designing WMI Data and Event Blocks

Publishing a WMI Schema

Registering as a WMI Data Provider

Handling WMI Requests

Sending WMI Events

WMI Property Sheets

Using wmimofck.exe

WMI Support for Tracing Driver Operation

Testing WMI Support in WDM Drivers


Introduction to WMI

Windows Management Instrumentation (WMI) is a kernel-mode service that drivers can use to make measurement and instrumentation data available to user-mode applications. A driver can use WMI mechanisms to publish information, permit configuration of its device, and supply notifications and logging of events.

WMI provides several capabilities that driver writers can use. A driver that supports WMI can:

  • Make custom data generally available to user-mode applications.

    WMI makes driver-defined data and events accessible to user-mode applications. Any application that is a WMI client can access the data that a driver provides to WMI. The driver writer does not need to define and document public I/O control codes or write a custom user-mode application.

    To make data available, the driver writer defines WMI data blocks, each uniquely identified by a GUID and containing one or more data items. Descriptions of data blocks are written in Managed Object Format (MOF) and typically compiled as a resource in the driver's binary image file. Management applications use the MOF descriptions to interpret a driver's custom data.

    At driver initialization, the driver registers its GUIDs with WMI, which adds the driver's data blocks to the CIMOM (Common Information Model Object Manager) database, making the driver's blocks accessible to WMI client applications.

    When a WMI client accesses a given data block, the WMI kernel component sends a query request to the driver for its data. The format of the driver-defined data is transparent to WMI, which simply passes the data to the user mode client.

  • Permit user-mode applications to configure a device through a standard interface rather than a custom control panel application.

    A driver's data blocks can define read/write items that WMI clients can set. When a WMI client user sets the value of such an item, the WMI kernel component sends a set request with the new value to the driver.

    A driver writer can also associate a method (routine) with a data block by including a driver-defined method in a data block. When a WMI client user executes that method, the WMI kernel component sends an execute-method request with the method ID to the driver. In this respect, WMI methods are functionally equivalent to IOCTLs.

  • Notify user-mode applications of driver-defined events without requiring the application to poll or send IRPs.

    A driver writer can define certain blocks as event blocks, which establish the events the driver can send. When a WMI client user requests notification of an event, the WMI kernel component sends an enable-event request to the driver. After an event is enabled, the driver sends the event block to WMI whenever the event occurs, until WMI sends a disable-event request. WMI routes the event block to all users that have requested notification of the event.

  • Reduce driver overhead by collecting and sending only requested data to a single destination.

    After a driver registers its data and event blocks, it needs to provide data and events only when users request them. If ongoing collection of a given data block might affect driver performance, a driver writer can designate that block as expensive to collect. A driver need not accumulate data for such a block until the first user requests it, which causes WMI to send an enable-collection request to the driver. The driver can stop accumulating data after WMI sends a disable-collection request.

    Similarly, a driver need not generate an event until the first user requests notification, which causes WMI to send an enable-event request to the driver. The driver can stop sending the event after WMI sends a disable-event request.

    The WMI kernel component routes a driver's events and data blocks to all WMI clients that have requested them.

  • Document data and event blocks implicitly with descriptive class names and optional descriptions.

    WMI clients can access the driver-defined class names and optional descriptions of all data and event blocks and can display them to users, making a driver's data and event blocks self-documenting.


WMI Architecture

This section describes WMI architecture and how the WMI extensions to WDM provide WMI with a means for collecting and setting data and events.

WMI is a unifying architecture that allows access to data from a variety of underlying technologies. These technologies include, for example, WMI extensions to WDM, the Desktop Management Interface (DMI), and the Simple Network Management Protocol (SNMP). WMI is based on the Common Information Model (CIM) schema, which is an industry standard specification driven by the Distributed Management Task Force (DMTF).

WMI provides a three-tiered approach for collecting and providing management data. This approach consists of a standard mechanism for storing data (a CIM-compliant data repository), a standard protocol for obtaining and distributing management data (for example, COM and DCOM), and a WMI provider. A WMI provider is a Win32® dynamic-link library (DLL) that supplies instrumentation data for parts of the CIM schema. The WMI provider for WDM acts as an interface to the kernel-mode WMI component. The kernel-mode WMI component provides services for WMI-enabled drivers and interfaces with the WMI provider for WDM.

Although the kernel-mode WMI component is part of the WDM architecture, it can also be used with other types of drivers as well if class or port drivers for those driver types are implemented to register with WMI and to handle WMI requests. For example, the NDIS class driver maps WMI I/O request packets (IRPs) to either object identifiers (OIDs) or status codes, and the SCSI port driver maps WMI IRPs to stream request blocks (SRBs). These mappings allow driver writers to implement WMI services with a familiar model. That is, to provide WMI services, NDIS miniport drivers can use OIDs and status codes, and SCSI miniport drivers can use SRBs. For example, an NDIS miniport driver does not require any WMI-specific code to indicate a change in status for its NIC. If the NDIS miniport driver indicates status about which a WMI client application has requested notification, the NDIS class driver maps that status indication to a WMI value, and passes the status indication to WMI. WMI then passes the status indication to the WMI client application.

The following figure shows the architecture of WMI.

WMI Architecture

Built on Wednesday, July 11, 2001


WMI Requirements for WDM Drivers

Any WDM driver that handles IRPs must set a dispatch table entry point for a DispatchSystemControl routine to handle IRP_MJ_SYSTEM_CONTROL requests, whether or not such a driver supports WMI. A driver that does not support WMI should simply forward WMI requests to the next-lower driver.

Drivers that support WMI fall into two general categories:

  • If the driver handles IRPs, it registers with WMI as a data provider and handles WMI requests as described later in this chapter. System-supplied storage port drivers, class drivers, and NDIS protocol drivers fall into this category.
  • If the driver does not handle IRPs (such as a miniport driver), it supplies WMI data to a second driver that does handle IRPs (such as the corresponding class driver), using the mechanism and format defined by the second driver. The second driver registers with WMI and handles WMI requests on the first driver's behalf. SCSI miniports, NDIS miniports, and NDIS named VCs fall into this category.

If a driver exposes custom data or event blocks, it must publish them in a WMI schema, which a driver writer typically does by including a MOF resource that defines the data and event blocks in the driver's binary image. A driver's schema should define only those blocks that are unique to that driver. If a driver supports data or event blocks defined by another driver or by the system, it registers them with WMI but does not need to define them in its own schema. For more information, see Publishing a WMI Schema.

A driver that supports WMI as a data provider must do the following:

  • At driver initialization, register as a WMI data provider by calling IoWMIRegistrationControl with the action WMIREG_ACTION_REGISTER and a pointer to the device object created in the driver's AddDevice routine.
  • In response to an IRP_MN_REGINFO or IRP_MN_REGINFO_EX request with the action WMIREGISTER, supply WMI with registration information about all data and event blocks the driver supports.
  • Drivers can handle WMI IRPs in one of two ways:
  • Call the kernel-mode WMI library routines declared in wmilib.h. Only drivers that do not use dynamic instance names, and that base static instance names on a single base name string or the device instance ID of a PDO, can use these routines.
  • Process and complete any such request tagged with a pointer to the device object that the driver passed in its call to IoWMIRegistrationControl, and forward other IRP_MJ_SYSTEM_CONTROL requests to the next lower driver.

For information about instance names and other data block design issues, see Designing WMI Data and Event Blocks.

For information about registering as a WMI data provider, see Registering as a WMI Data Provider.

For information about handling WMI requests, see Handling WMI Requests.

A driver that supplies WMI data to a class or port driver must support the driver-type-specific WMI interfaces defined by the class or port driver. For example, a SCSI miniport must set WmiDataProvider to TRUE in the PORT_CONFIGURATION_INFORMATION structure and handle SRB_FUNCTION_WMI requests from the SCSI port driver. A connection-oriented NDIS miniport that defines custom data blocks must support OILD_GEN_CO_SUPPORTED_GUIDS; otherwise, NDIS maps those OIDs and status indications returned from OID_GEN_SUPPORTED_LIST that are common and known to NDIS to GUIDs defined by NDIS.

The rest of this chapter describes how to support WMI in a driver that handles IRPs. For more information about driver-type-specific WMI support requirements, writers of network drivers should consult the DDK's design guide chapters for network drivers. Writers of SCSI miniport drivers should see Scsi Miniport Drivers.


MOF Syntax for WMI Data and Event Blocks

A driver's WMI schema describes its data blocks, which define the information that a driver can provide and the methods it can execute in response to WMI requests. A driver's schema also describes its event blocks, which are data blocks that the driver sends to WMI when a driver-determined event occurs for which a WMI client user has requested notification.

A driver writer defines a driver's schema in Managed Object Format (MOF). MOF is a compiled language created by the Desktop Management Task force (DMTF) and based on Interface Definition language (IDL). A driver's MOF file contains a MOF class definition for each data block and event block the driver exposes to WMI.

A MOF class definition for a WMI data block follows this syntax:

[ Required and optional class qualifiers ]

class ClassName : OptionalBaseClass
{
[key, read]
string InstanceName;
[read]
boolean Active;

[ Required and optional property qualifiers ]
datatype itemname1;

[ Required and optional property qualifiers ]
datatype itemnameN;
};

The following topics describe the syntax elements shown above:

WMI Class Qualifiers

WMI Class Names and Base Classes

Required Items in WMI Classes

WMI Property Qualifiers

Driver-defined WMI Data Items

WMI Class Examples

For a general discussion of MOF syntax as it pertains to WMI clients and other kinds of applications, see the Platform SDK.


WMI Class Qualifiers

The following table lists the required and optional MOF class qualifiers that can be used to describe a driver's WMI data blocks and event blocks.

An embedded class, which is a class used solely as a data item in another class and not exposed as a WMI data block, requires only the WMI and guid qualifiers. The other qualifiers are irrelevant to embedded classes and are ignored. For more information about embedded classes, see Driver-Defined WMI Data Items.

Dynamic and Static are standard MOF qualifiers. For information about other standard MOF qualifiers, see the Platform SDK.

Qualifier | Description
Dynamic | Indicates that the data provider supplies instances of the data block at run time, rather than providing instances of static data in the MOF file. All data and event blocks that a driver registers with WMI must be defined with the Dynamic qualifier.
Static | Indicates that the data provider supplies instances of static data in the MOF file, rather than supplying instances of the data block at run time. The class definition of such a static instance must also include the InstanceOf qualifier. A driver does not register static data blocks with WMI, because the static data resides in the WMI database. Classes marked as Static in the MOF file should not be registered by the driver's IRP_MN_REGINFO or IRP_MN_REGINFO_EX handlers.
Provider("WMIProv")
 | (Required) Indicates that the provider of the class is a WMI provider.
WMI | (Required) Indicates that the class is a WMI class.
Description("description-string")
 | (Optional) Specifies a description of the block for the locale specified by the Locale qualifier. If defined, WMI clients can display the description string to users. A driver writer can use Description to document a class.
Guid("guid-string")
 | (Required) Specifies the GUID, in string format, that uniquely identifies the block to WMI. A driver writer should generate a GUID for each data block in the driver's MOF file, using either guidgen.exe or uuidgen.exe. A driver passes this value in GUID format to WMI when the driver registers its blocks. WMI then uses the GUID to look up the block's definition in the driver's MOF resource.
Locale("MS\\locale-identifier")
 | (Optional) Specifies the language identifier and locale for the string specified by Description. For example, a locale-identifier of 0x409 specifies American English. A single MOF file can contain blocks with different locales, but typically all of the blocks in a MOF file have the same locale.
WmiExpense(expense-value)
 | (Optional) Specifies the average number of CPU cycles needed to collect data for the data block. For example, a WMI client might check a data block's WmiExpense value to determine how often to query for its data. If WmiExpense is omitted, expense-value is assumed to be 0. WmiExpense is unrelated to registering a data block as expensive to collect.


WMI Class Names and Base Classes

WMI class names are case-insensitive, must start with a letter, and cannot begin or end with an underscore. All remaining characters must be letters, digits, or underscores.

WMI client applications can access a driver's WMI class names and display them to users. Descriptive class names can help make classes more intuitive to use.

WMI class names must be unique within the WMI name space. Consequently a driver's WMI class names cannot duplicate those defined by another driver.

To help prevent name collisions, a driver writer can define a driver-specific base class and derive all of the driver's WMI classes from that base class. The class name and base class name together are more likely to yield a unique name. For example, the following shows an abstract base class for a serial driver's data blocks:

// Serial driver's base class for data blocks
[abstract]
class MSSerial {
}

// Example class definition for a data block
[
    //Class qualifiers
]
class MSSerial_StandardSerialInformation : MSSerial
{
    //Data items
}

Device-specific custom data blocks should include the manufacturer, model, and type of driver or device in the base class name. For example:

[abstract]
class Adaptec1542 {
}

class Adaptec1542_Bandwidth : Adaptec1542 {
    //Data items
}

class Adaptec1542_Speed : Adaptec1542 {
    //Data items
}

WMI allows only one abstract base class in a given class hierarchy. Classes that define event blocks must derive from WmiEvent, which is an abstract base class, so the abstract qualifier cannot be used in a driver-defined base class for event blocks. Instead, derive a non-abstract base class from WmiEvent, then derive individual event classes from that base class. For example:

//Serial driver's base class for event blocks
class MSSerialEvent : WmiEvent
{
}

//Example class definition for an event block
[
    //Class qualifiers
]
class MSSerial_SendEvent : MSSerialEvent
{
    //Data items
}

For more information about defining base classes in MOF format, see the Platform SDK.


Required Items in WMI Classes

All class definitions except embedded classes must include the items InstanceName and Active, which must appear exactly as shown:

//WMI class definition
[
    //Class qualifiers
]
ClassName : BaseClassName
{
    [key, read]
     string InstanceName;
    [read]
     boolean Active;

    // Driver-defined data items
}

The InstanceName and Active items are required and used internally by WMI. The MOF class definitions of a driver's data and event blocks must include these items, but the driver must not set these items when responding to a query for the data block or sending an event, because they are not part of the driver's data block.


WMI Property Qualifiers

The following table lists the required and optional MOF property qualifiers that can be used to define items in a WMI data or event block.

The following are standard MOF qualifiers: key, read, write, ValueMap, and Values. For more information about these and other standard MOF qualifiers, see the Platform SDK.

Qualifier | Description
key | Indicates that the data item is a key property that uniquely identifies each instance of the class. Only the InstanceName property can be declared a key.
read | Indicates that a WMI client can read the data item.
write | Indicates that a WMI client can set the data item.
BitMap | Specifies a list of string values (flag names) that represent bits set in the data item. The bit position of a flag is defined by the corresponding position specified in BitValue.
BitValue | Specifies the bit positions of the corresponding string values specified in BitMap.
DisplayInHex | Specifies that any WMI client that displays the property value should do so in hexadecimal.
DisplayName("string")
 | Specifies a caption that a WMI client can use to display as the property name.
MaxLen(uint) | For string properties, MaxLen specifies the maximum length of the string in characters. The uint value can be any 32-bit unsigned integer. If MaxLen is omitted, or uint is zero, then the length of the string is unlimited.
Values | Specifies a list of possible values for this data item. If the data item is an enumeration, ValueMap contains the index value that corresponds to the enumeration value specified in Values.
ValueMap | Specifies the integer values of the corresponding string values in Values.
WmiDataId(data-item-ID)
 | (Required) Identifies a data item within a data block. Data item IDs must be assigned to all items in a block except the required items InstanceName and Active. Data item IDs must be assigned in a contiguous series, starting with 1. An item's data ID determines the order in which the item appears in an instance of the data block; the order of items in the MOF class definition is irrelevant.
WmiMethodId(method-item-ID)
 | Identifies a method within a data block.
WmiSizeIs("data-item-name")
 | Specifies the name of another data item in this block that indicates the number of elements in the variable-length array at this data item. WmiSizeIs is valid only for data items that define arrays.
WmiScale(scale-factor)
 | Specifies the scaling factor, as a power of 10, that the driver uses when returning the value of this data item. For example, if scale-factor is 5, the value returned by the driver is multiplied by 105. If WmiScale is omitted, scale-factor can be assumed to be 0.
WmiTimeStamp
 | Specifies that a 64-bit data item is a time stamp in units of 100 nanoseconds since 1/1/1601. WmiTimeStamp is valid only for 64-bit data items.
WmiComplexity("level")
 | Specifies the level of complexity associated with the data item, which a WMI client might use to restrict access to the data. Valid complexity levels are: Novice Advanced Expert Wizard If WmiComplexity is omitted, level is assumed to be Novice.
WmiVolatility(interval)
 | Specifies the interval, in milliseconds, between updates of this data item. For example, if a data item is updated once each second, interval would be 1000. A WMI client might check WmiVolatility to determine how often to query for a potentially new value. If WmiVolatility is omitted, interval is undefined.
WmiEventTrigger("data-item-name")
 | Specifies the name of a data item in an event block that a WMI client can set to define the trigger value for the event. For example, if the event TooHot is qualified with WmiEventTrigger("TooHotTemperature"), a WMI client could set TooHotTemperature to instruct the driver to send the TooHot event when the device reached the user-specified value for TooHotTemperature. Typically a driver would define the trigger value. By exposing a WmiEventTrigger data item, the driver allows a client to control when a particular event is fired.
WmiEventRate("data-item-name")
 | Specifies the name of a data item in an event block that a WMI client can set to control the frequency at which this event will be sent. For example, if the data item TooHot is qualified with WmiEventRate("SendEventRate"), a WMI client user could set SendEventRate to instruct the driver to send TooHot at the user-specified interval.


Driver-defined WMI Data Items

A data item in a class definition of WMI data or event block can be one of the following:

  • A basic data type such as a string or an unsigned integer.
  • An embedded class. An embedded class is used only as a data item in another class definition and is not exposed as a data block or event block.
  • A fixed-length or variable-length array of a basic data type or embedded class.

When sending a data block to WMI, a driver must align the start of the block on an 8-byte boundary. All subsequent data items in the block must be aligned on the corresponding alignment for the data type. A boolean or uint8 should be aligned on a 1 byte boundary. A sint16, uint16, or string item should be aligned on a 2 byte boundary, etc. Arrays should be aligned based upon the base type of the array. An array of bytes should be aligned on a byte boundary, an array of uint64 should be aligned on an 8 byte boundary, etc. An embedded class should be aligned based upon the natural alignment of the embedded class which is defined to be the largest element within the embedded class. For example, if an embedded class has a uint64 then the class should be aligned on an 8 byte boundary. WMI data item alignment follows the same conventions as the /Zp8 switch on the Microsoft C compiler.

A driver writer does not necessarily have to define data items in a block other than the required items InstanceName and Active. For example, an empty event block can serve as notification that an event occurred, without additional data. Or a data block might simply enumerate instance names in response to an IRP_MN_QUERY_ALL_DATA request.

The following table lists the MOF data types that can be used to define items in a WMI data or event block. For more information about MOF data types, see the Platform SDK.

Data type Data format Alignment
(in bytes)
string | A USHORT specifying the string length in bytes, followed by the Unicode string data. The string data may optionally include a terminating 0 followed by padding. If so, the string length must include the terminating 0 and padding. Drivers can use the MaxLen qualifier to specify the maximum length in characters of the string. Drivers that specify a maximum string length can use a fixed size buffer to hold the string. If the string is strictly smaller than the size of the buffer, then the driver can pad the rest of the string with zeroes. | 2
boolean | A one-byte value where 0 is FALSE and any non-zero value is TRUE | 1
sint8 | Signed 8-bit integer | 1
uint8 | Unsigned 8-bit integer | 1
sint16 | Signed 16-bit integer | 2
uint16 | Unsigned 16-bit integer | 2
sint32 | Signed 32-bit integer | 4
uint32 | Unsigned 32-bit integer | 4
sint64 | Signed 64-bit integer | 8
uint64 | Unsigned 64-bit integer | 8
datetime A fixed-length 25-character Unicode string that specifies an absolute date or time interval. A datetime value has the following format:

yyyymmddhhmmss.mmmmmmsutc

where:

yyyy is the 4-digit year

mm is the 2-digit month

dd is the 2-digit day of the month

hh is the hour according to a 24-hour clock

mm is the minute

ss is the seconds

mmmmmm is the number of microseconds

s is a plus sign (+) or minus sign (-), indicating whether utc is a positive or negative offset from Universal Time Coordinates; or a colon (:), indicating that the datetime value is an interval.

utc is the offset in minutes from Universal Time Coordinates. If utc is zero (000), the datetime value is an interval.

Values must be zero-padded. Fields that are not significant can be filled with asterisks (*).

2


WMI Class Examples

The following examples show class definitions from the schema of a serial port driver. Note that the guid values shown in these examples are placeholders. Each class definition must have a unique GUID generated by guidgen.exe or uuidgen.exe.

// Standard class for reporting serial port information
// Class qualifiers
[WMI, guid("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"),
Dynamic, Provider("WMIProv"),
WmiExpense(1),
Locale("MS\\0x409"),
Description("Description of class"]

//Class name
class Vendor_SerialInfo {

//Required items
    [key, read]
     string InstanceName;
    [read]
     boolean Active;

// Bytes sent on port
// Property qualifiers
    [read,
     WmiDataId(1),
     WmiScale(0),
     WmiComplexity(1),
     WmiVolatility(1000)]
     Description("Description of property")]
// Data item
     uint64 BytesSent;

// Bytes received on port
    [read,
     write,
     WmiDataId(2),
     WmiScale(0),
     WmiVolatility(1000)]
     uint64 BytesReceived;

// Who owns the port
    [read,
     WmiDataId(4),
     WmiScale(0),
     WmiVolatility(60000)]
    string Owner;

// Status bit array
    [read, write,
     WmiDataId(3),
     WmiScale(0)]
     byte Status[16];

//The number of items in the XmitBufferSize array
    [read,
     WmiDataId(5),
     WmiScale(0),
     WmiComplexity(1),
     WmiVolatility(1000)]
     uint32 XmitDescriptorCount;

//Array of XmitDescriptor classes
    [read,
     WmiDataId(6),
     WmiSizeIs("XmitDescriptorCount"),
     WmiScale(0),
     WmiComplexity(1),
     WmiVolatility(1000)]
    Vendor_XmitDescriptor XmitBufferSize[];
}

The following is the class definition for the embedded class shown in the previous example. Note that this class does not contain InstanceName or Active items.

// Example of an embedded class
[WMI, guid("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"),
class Vendor_XmitDescriptor {
    [read, WmiDataId(1)] int32 DestinationIndex;
    [read, WmiDataId(2)] int32 DestinationTarget;
}

The following is a class definition for an event block. The class is derived from WmiEvent.

// Example of an event
 [WMI, guid("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"),
 Dynamic, Provider("WMIProv"),
 locale("MS\\0x409"),
 Description("Serial Send Event"),
 WmiExpense(1)]
class Vendor_SerialSendEvent : WMIEvent
{
// Required items
    [key, read]
      string InstanceName;
    [read]
      boolean Active;


Designing WMI Data and Event Blocks

For best performance and ease of use by WMI clients, a driver should support standard data blocks, and driver writers should follow certain guidelines in designing custom WMI data and event blocks. In particular, driver writers should be aware of performance tradeoffs in choosing static versus dynamic instance names for data blocks. The following topics discuss issues and guidelines for designing WMI data and event blocks.


Supporting Standard WMI Blocks

Each driver should support any standard blocks defined for drivers of its type. Standard blocks provide WMI clients with consistent data for all devices of a given type, regardless of vendor.

To support a standard block, a driver:

  • Registers the block with WMI, along with the other standard and custom blocks supported by the driver, as described in Registering as a WMI Data Provider.
  • Handles all WMI requests that specify the driver's device object pointer at Parameters.WMI.ProviderId and the GUID of the standard block at Parameters.WMI.DataPath, as described in Handling WMI Requests.

MOF classes for standard blocks are published in system-supplied MOF files. A driver must not redefine a standard block in its own MOF file, because doing so would duplicate the block in the WMI database.

Currently, class definitions of standard blocks are published in the file wmicore.mof, which is included in this DDK.


Implementing Custom WMI Blocks

A driver can implement custom blocks that expose device-specific instrumentation. For example, a driver for a disk drive that can report temperature might implement a custom event block that notifies WMI clients when the drive's temperature increases beyond a safe threshold.

To implement a custom block, a driver:

  • Defines a class in its MOF file, compiles the MOF file into a resource, and includes the resource in the driver, as described in Publishing a WMI Schema.
  • Registers the block with WMI along with the other standard and custom blocks supported by the driver, as described in Registering as a WMI Data Provider.
  • Handles all WMI requests that specify the driver's device object pointer at Parameters.WMI.ProviderId and the GUID of the standard block at Parameters.WMI.DataPath, as described in Handling WMI Requests.

Drivers cannot control the order in which binary MOF files are loaded. The only guarantee is that wmicore.mof is loaded before any driver-specific MOF file. Therefore, custom WMI classes must only inherit from either classes in the same MOF file, or in wmicore.mof.

To improve performance and ease of use of custom WMI data blocks, consider the following guidelines:

  • Put data items that are operationally grouped together in the same data block.

    For example, an i8042 port controller might maintain state information about both the keyboard and mouse ports. Rather than a single large data block containing all mouse and keyboard information, a driver might define one data block for the mouse port and another data block for the keyboard port.

  • Put frequently used data items in separate data blocks, particularly if they would otherwise be grouped with items that are infrequently used.

    For example, a driver might expose CPU utilization in a data block with a single item, so a WMI client could track CPU utilization without incurring the overhead of retrieving additional data items in the block. A WMI client cannot query for a single data item, so to obtain one item it must query for an entire instance of a data block.

  • Use event blocks to notify WMI clients of exceptional events, not as an alternative to error logging.

    Only a limited number of events can be queued at one time, and if the queue is full events will be lost. Also, the timing of delivery of events to WMI clients cannot be guaranteed.

  • Limit event blocks to a maximum size of 1K bytes.

    Event items should be defined as small data types, because there is a registry-defined size limit (initially, 1K) for the entire WNODE_EVENT_ITEM structure that contains the generated event. For large notifications, a driver can send a WNODE_EVENT_REFERENCE structure that specifies a single instance of a data block, which WMI then queries to obtain the actual event. However, this increases the time lag between the occurrence of the event and the notification.

  • Place fixed-size data items at the beginning of a data block, followed by any variable-size data items.

    For example, a data block that has three DWORD data items and one variable-length string should put the three DWORDs first, followed by the string. Placing fixed-size data items at the beginning of a block permits WMI clients to extract them more easily.

WMI does not support versioning, so a driver writer must define a new MOF class and generate a new GUID to revise an existing custom block.


Defining WMI Instance Names

An instance of a WMI block contains data supplied by a particular physical device or software component. Just as a block's GUID uniquely identifies the block, an instance's name uniquely identifies that instance of a block. WMI client applications use instance names to associate the information returned in a data block with the device or component that supplied the data. WMI uses instance names to determine which device a request should be sent to. It is strongly recommended that drivers use their PDO when defining instance names.

A driver can defines instance names for a block in either of two ways:

  • The driver passes a list of static instance names to WMI when it registers the block.

    After the block is registered, both the driver and WMI specify an instance name by its index into this list. Static instance names can be based on the driver's PDO or a driver-defined base name, or the driver can define a list of instance name strings. Static instance names persist until the driver explicitly changes them by re-registering the block.

  • The driver generates dynamic instance names as instances are created.

    The driver indicates that it will generate dynamic instance names for a block when it registers the block. After the block is registered, both the driver and WMI pass dynamic instance names as strings in the buffer at Parameters.WMI.Buffer.

A driver should generate dynamic instance names only if the number of instances or instance names of a data block change frequently at runtime. For example, a driver might use process IDs or the IP addresses of TCP/IP connections as instance names. Such instance names should be dynamic; if they were static, the driver would incur considerable overhead because it would have to call IoWMIRegistrationControl to update the number and names of instances each time a change occurred.

In most cases, static instance names are preferable to dynamic instance names for the following reasons:

  • Static instance names improve a driver's performance because the driver does not need to return instance name strings in response to WMI requests, as it must for dynamic instance names.
  • WMI can detect static instance name collisions at registration and automatically mangle the instance names if necessary, so that all instance names are unique for a given block no matter how many drivers register the block.

    WMI cannot detect instance name collisions for dynamic instance names, so the driver is responsible for generating unique names using IoWMIAllocateInstanceIds.

  • A driver can use the WMI Library routines to handle IRPs for a block that uses static instance names, as long as the names are based on the driver's PDO or a driver-defined base name.

    A driver cannot use WMI Library routines to handle IRPs for a data block that uses dynamic instance names.

A driver indicates whether a block uses static or dynamic instance names, and the type of static instance names, by setting or clearing WMIREG_FLAG_XXX in the WMIREGGUID or WMIGUIDREGINFO structure it passes to WMI when it registers the block. For more information, see Registering as a WMI Data Provider.


Publishing a WMI Schema

To publish a WMI schema, a driver writer first creates a text file in Managed Object Format (MOF) language that contains a class definition for each data block and event block in the schema, as described in MOF Syntax for WMI Data and Event Blocks.

A driver writer can then publish a driver's WMI schema in one of the following ways:

  1. Compile the MOF file and include it as a resource in the driver's binary image. For more information, see Compiling a Driver's MOF File.
  2. Include the compiled MOF file as a resource in a different file, such as a DLL, and add the registry value MofImagePath with a path to the file that contains the MOF under the driver's Service key. A schema published in this way can be updated without recompiling the driver. For more information, see Setting the MofImagePath Registry Key.
  3. Include binary data within the driver and return it when WMI requests it. A schema published in this way can be changed dynamically at runtime. For more information, see Implementing Dynamic MOF Data.


Compiling a Driver's MOF File

To compile a MOF file that defines WMI data and event blocks, use the following syntax:

mofcomp -WMI -B:filename.bmf filename.mof

where:

-WMI
Validates all classes in filename.mof for use with WMI. If any class definition is invalid, mofcomp deletes the output file filename.bmf. If -WMI is omitted, the driver writer should run wmimofck on filename.bmf to validate the classes. A driver must either use the WMI switch or run wmimofck to validate the MOF. Failure to do so can result in the MOF file not loading correctly into the WMI schema.
-B:filename.bmf
Requests that the compiler create a platform-independent binary version of the MOF file in filename.bmf without making any modifications to the CIMOM object repository.
filename.mof
Specifies the name of the input MOF file.

To include the compiled MOF file as a resource in the driver's binary image, add the following line to the driver's resource script (RC) file:

MofResource MOFDATA filename.bmf

A driver specifies its MOF resource name in response to a registration request (an IRP_MN_REGINFO or IRP_MN_REGINFO_EX request with Parameters.WMI.DataPath set to WMIREGISTER):

  • If the driver is using the WMI Llibrary routines to handle WMI IRPs, it specifies the MOF resource name in its DpWmiQueryReginfo routine.
  • If the driver is handling WMI IRPs directly, it specifies the MOF resource name in the WMIREGINFO structure the driver passes to WMI.

For information about handling IRP_MN_REGINFO and IRP_MN_REGINFO_EX requests, see Registering as a WMI Data Provider. For information about handling WMI IRPs using WMI Library routines, see Handling WMI Requests.

For more information about the MOF compiler, and for information about defining and including resources in executable files, see the Platform SDK.


Setting the MofImagePath Registry Key

A driver's schema can be published by including a compiled MOF resource in a separate file, such as a DLL, and setting MofImagePath in the registry to the path of that file. A schema published in this way can be updated without recompiling the driver.

To publish a driver's schema in a separate file:

  1. Compile the MOF file as described in Compiling a Driver's MOF File.
  2. Include the compiled MOF file as a resource in a file such as a DLL.
  3. Add the MofImagePath registry key under the driver's Services key. For example, the following shows the registry value for a driver named DriverName:
    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services
    \DriverName
        MofImagePath    "\SystemRoot\System32\Drivers\DriverNameMof.dll"


Implementing Dynamic MOF Data

A driver's schema can be published dynamically by including binary MOF data in the driver's binary and returning selected schema information at runtime. To supply dynamic MOF data, a driver should follow these steps:

  1. Compile the MOF file as described in Compiling a Driver's MOF File.
  2. Use wmimofck.exe to create a .x file which will contain a hexadecimal dump of the .bmf file created by the MOF compiler.
  3. Use #include to include the hex data created in step 2 with the driver's source.
  4. Register as supporting MSWmi_MofData_GUID, which is a GUID defined in wmidata.h.
  5. Return selected binary data to WMI in response to both the IRP_MN_QUERY_ALL_DATA or IRP_MN_QUERY_SINGLE_INSTANCE requests for MSWmi_MofData_GUID.

For more information about the wmimofck utility see Using wmimofck.exe.


Localizing MOF Files

Since WMI property qualifiers are often displayable strings, Windows XP and later versions of the operating system provide a mechanism for localizing these qualifiers.


Creating the Localized MOF File

On Windows XP and later versions of the operating system, drivers localize a WMI schema by making an amended version of each class. An amended version of a class updates property qualifiers that depend on the locale.

An amended version of a class has the same format as a class declaration, preceded by the amendment qualifier. The amended class declaration also includes a locale(0xXXX) qualifier, where XXX specifies the locale identifier (LCID) for the locale.

The amended declaration includes the modified property declarations. Each localized property qualifier has the :amended modifier attached to it. For example, the localized version of Description("a description string") would be Description("localized description string"):amended.

Here is an example of a declaration of the basic class, followed by its amendment for American English.

[guid(xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx)]
class MyClass
{
    [key] sint32 KeyProp;
    string Name;
    uint64 Timestamp;
}

[amendment, locale(0x409)
 Description("Localized version of MyClass for American English"):amended]

class MyClass
{
    [DisplayName("Key Property"):amended,
     Description("The description of KeyProp"):amended]
    sint32 KeyProp;

    [DisplayName("User Name"):amended,
     Description("The description of Name"):amended]
    string Name;
}

Only the properties that have been modified need to be included in the amended class. The class and property names cannot be localized. Only property qualifiers can be localized.

Localized classes are organized in child namespaces of the namespace containing the original class. Classes for a given locale are found in the MS_XXX child namespace, where XXX represents the hexadecimal LCID for that locale. For example, drivers are in the \root\wmi namespace by default. An amended class, localized for American English, is found in the \root\wmi\MS_409 namespace.

More information on WMI localization can be found in the following whitepaper: http://www.microsoft.com/windows2000/library/howitworks/management/WMIgloba.asp.


Building and Deploying the Localized MOF File

International versions of Windows XP and later versions of the operating system come in two flavors — single-language (localized) versions, and Multilanguage User Interface (MUI) versions. An MUI version of Windows can support several languages simultaneously.

Drivers that are deployed on a localized version of Windows should contain a MOF resource that contains the language-neutral version of all the classes, as well as the localized language amendment and the American English language amendment.

On an MUI version of Windows, the driver image itself should contain the language-neutral and American English versions of the WMI classes. For each additional language supported, a resource-only image can be placed in the %windir%\system32\drivers\MUI\langid directory, where langid is the LCID of the for the locale.

Optionally, the driver image itself can contain every language supported.

If a language is not supported by one of these mechanisms, the English language version is used.

Building Distinct MOF Files For Each Language

Driver writers can use one master MOF text file to contain the basic class, and all of its amendments.

You can use the MOF compiler to generate a file containing the language-neutral classes as well as a file to contain the amended classes for a particular language.

mofcomp -amendment:namespace [ -MOF:mof] [ -MFL:mfl] masterfile

The namespace parameter is of the form MS_XXX, where XXX is the LCID for the locale to be generated. The mof file created contains the language-neutral classes, and the mfl file created contains the amended classes.

When building your driver on NT-based operating systems, you can merge the two files by using the copy command. On Windows® 98/Me, the copy command does not correctly append Unicode files, but the following command can be used.

wmimofck localizedfile -ymof -zmfl

You can combine any number of languages into a single text file.

The localized file can then be compiled into a binary file by the same method as for the MOF files that have not been localized:

mofcomp -B:binaryfile localizedfile

For a single-language version of Windows, drivers attach the binary MOF as a resource to the driver image. See Compiling a Driver's MOF File for details.

On an MUI system, the driver image itself must be built for American English. For each additional language, install each localized binary MOF file as a resource in a separate image file in the appropriate %windir%\system32\drivers\MUI\langid directory, where langid is the hexadecimal LCID for the locale (for example, 409 for American English). The file name must be either drivername.sys or drivername.sys.mui, where drivername.sys is the name of the driver binary.

Building One MOF File for All Supported Languages

If the driver image will contain every supported language, there is a simpler way to build a MOF file supporting every language. By using #pragma directives in the MOF text file, drivers can also combine all of the amended classes in one binary. Since each localization exists in a distinct namespace, they can safely be combined in a single binary.

When writing the combined MOF text file, driver writers must precede each amended class declaration with a #pragma directive as follows

#pragma namespace ("namespace")

where namespace is the correct namespace for the declaration. For example, the amended class declaration for American English must be preceded with a declaration of the form:

#pragma namespace ("\\\\.\\root\\wmi\\ms_409")

For example, you declare a class and its amendments as follows.

#pragma namespace ("\\\\.\\root\\wmi)

[guid(xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx)]
class MyClass
{
}

#pragma namespace(\\\\.\\root\\wmi\\ms_409)
[amendment, locale(0x407)]
class MyClass
{
}

Using this approach, building the binary MOF file is identical to the non-localized approach. See Compiling A Driver's MOF File for details.


Registering as a WMI Data Provider

A driver that supports WMI must register as a WMI data provider to make its data and event blocks available to WMI clients. A driver typically registers with WMI when starting its device, after the device has been initialized to the point that the driver can handle WMI IRPs. During the registration process, the driver passes WMI a pointer to its device object and information about the data and event blocks it supports.

A driver registers with WMI in two phases:

  1. The driver calls IoWMIRegistrationControl with the action WMIREG_ACTION_REGISTER and a pointer to the device object passed to the driver's AddDevice routine.
  2. The driver handles the IRP_MN_REGINFO or IRP_MN_REGINFO_EX request that WMI sends in response to the driver's IoWMIRegistrationControl call. The Parameters.WMI.DataPath member of the IRP is set to WMIREGISTER and Parameters.WMI.ProviderId is set to the driver's device object pointer. The driver supplies WMI with registration information about its data and event blocks, either by using the WMI Library as described in Using the WMI Library to Register Blocks, or by handling the IRP_MN_REGINFO or IRP_MN_REGINFO_EX requests as described in Handling IRP_MN_REGINFO and IRP_MN_REGINFO_EX to Register Blocks.


Using the WMI Library to Register Blocks

A driver can use the WMI Library to handle IRP_MN_REGINFO and IRP_MN_REGINFO_EX requests if it is registering blocks that do not use dynamic instance names, or that use static instance names based on a PDO or driver-defined base name string. In this case, the driver:

  1. Calls WmiSystemControl with a pointer to the driver's device object, a pointer to a WMILIB_CONTEXT structure, and a pointer to the IRP

    The WMILIB_CONTEXT structure indicates the number of blocks to register (GuidCount) and points to a list of WMIGUIDREGINFO structures (GuidList) that specify the GUID, the number of instances, and registration flags that pertain to the corresponding block. It also defines entry points for the driver's required and optional DpWmiXxx callback routines.

  2. When WMI calls the driver's DpWmiQueryReginfo routine, the driver specifies the driver's registry path, its MOF resource name, registration flags that pertain to all of its blocks, and information that WMI uses to name instances of the driver's data blocks, which could be either a pointer to the physical device object passed to the driver's AddDevice routine or a string on which to base static instance names.

A driver must initialize entry points for its DpWmiXxx callback routines in the WMILIB_CONTEXT structure before calling WmiSystemControl, but can postpone initialization of GuidCount and GuidList in the WMILIB_CONTEXT structure until WMI calls the driver's DpWmiQueryReginfo routine.


Handling IRP_MN_REGINFO and IRP_MN_REGINFO_EX to Register Blocks

On Windows 98 and Windows 2000, the system sends the IRP_MN_REGINFO request to a driver to allow a driver to register its WMI classes. On Windows XP and later, the system sends the IRP_MN_REGINFO_EX request instead. Most drivers can handle these requests by using WmiSystemControl to provide a callback routine. See Using the WMI Library to Register Blocks for details.

A driver must handle IRP_MN_REGINFO or IRP_MN_REGINFO_EX requests to register blocks that use dynamic instance names or that use a list of driver-defined static instance names; it cannot call WmiSystemControl to register such blocks. A driver can optionally handle this request to register blocks that use static instance names based on the PDO or a driver-defined base name string.

In this case, the driver:

  1. Fills in a WMIREGINFO structure at Parameters.WMI.Buffer that specifies:
    • The number of bytes of all registration data supplied by the driver, including data supplied on behalf of another driver.
    • The driver's registry path.
    • The name of the driver's MOF resource.
    • The number of blocks to register.
    • An array of WMIREGGUID structures, one for each block.
  2. For each block, the driver fills in a WMIREGGUID structure that specifies:
    • The GUID that represents the block.
    • Flags that provide information about instance names and other characteristics of the block, such as whether the block is expensive to collect. For more information, see WMI Registration Flags.

    If the block is being registered with static instance names, the driver sets one of the following members to specify static instance name data for the block:

    • If the driver sets Flags with WMIREG_FLAG_INSTANCE_LIST, it sets InstanceNameList to an offset to a list of static instance name strings. WMI specifies instances in subsequent requests by index into this list.
    • If the driver sets Flags with WMIREG_FLAG_INSTANCE_BASENAME, it sets BaseNameOffset to an offset to a base name string. WMI uses this string to generate static instance names for the block.
    • If the driver sets Flags with WMIREG_FLAG_INSTANCE_PDO, it sets Pdo to the PDO passed to the driver's AddDevice routine. WMI uses the device instance path of the PDO to generate static instance names for the block. When handling an IRP_MN_REGINFO_EX request, drivers must call the ObReferenceObject routine on the physical device object passed in Pdo.

    The driver writes instance name strings or a base name string at the offset indicated by InstanceNameList or BaseName, respectively.

  3. If the driver is registering blocks on behalf of another driver (as a class driver might on behalf of a miniclass driver), the driver fills in another WMIREGINFO structure and list of WMIREGGUID structures with registration information for the other driver's blocks, and sets NextWmiRegInfo in the first WMIREGINFO to the offset in bytes from the beginning of the first WMIREGINFO to the beginning of the second WMIREGINFO structure.


WMI Registration Flags

A driver indicates whether a block uses static or dynamic instance names and specifies other characteristics of the block by setting flags in the WMIGUIDREGINFO or WMIREGGUID structure that it passes to WMI to register the block.

A driver indicates that a block uses static instance names by setting one of the following flags:

  • WMIREG_FLAG_INSTANCE_LIST indicates that the driver provides all instance names in a static list.

    A driver can set this flag only if it registers blocks by handling the IRP_MN_REGINFO or IRP_MN_REGINFO_EX requests, not by calling WmiSystemControl. The driver writes the instance name strings at the byte offset indicated by InstanceNameList in the block's WMIREGGUID structure.

  • WMIREG_FLAG_INSTANCE_BASENAME instructs WMI to generate static instance names from a driver-defined base name string.

    A driver that handles an IRP_MN_REGINFO or IRP_MN_REGINFO_EX request writes the base name string at the offset indicated by BaseNameOffset in the block's WMIREGGUID structure.

    A driver that calls WmiSystemControl specifies the base name string in the InstanceName parameter of its DpWmiQueryReginfo routine.

  • WMIREG_FLAG_INSTANCE_PDO instructs WMI to generate static instance names from the device instance ID of the driver's PDO.

    A driver that handles an IRP_MN_REGINFO or IRP_MN_REGINFO_EX request writes a pointer to the PDO at the Pdo member of the block's WMIREGGUID structure. If the request is IRP_MN_REGINFO_EX, the driver must increase the reference count on each PDO passed by calling the ObReferenceObject routine.

    A driver that calls WmiSystemControl writes a pointer to the PDO in the Pdo parameter of its DpWmiQueryReginfo routine.

To indicate that a block uses dynamic instance names, the driver must not set any of the following flags: WMIREG_FLAG_INSTANCE_LIST, WMIREG_FLAG_INSTANCE_PDO, or WMIREG_FLAG_INSTANCE_BASENAME.

A driver indicates that a data block is expensive to collect by setting WMIREG_FLAG_EXPENSIVE. This instructs WMI to send an IRP_MN_ENABLE_COLLECTION request the first time a WMI client opens the data block and an IRP_MN_DISABLE_COLLECTION request when the last WMI client closes the block. The driver need not collect data for such a block until it receives an IRP_MN_ENABLE_COLLECTION request.

A driver indicates an event block by setting WMIREG_FLAG_EVENT_ONLY_GUID. This indicates that the block can be enabled or disabled as an event only, and cannot be queried or set.

A driver instructs WMI to remove a previously registered block by setting WMIREG_FLAG_REMOVE_GUID. This flag is valid only in response to a request to update registration information (IRP_MN_REGINFO or IRP_MN_REGINFO_EX with WMIUPDATE). For more information, see Updating WMI Registration Information.


Updating WMI Registration Information

After its initial registration with WMI, a driver changes its registration information by calling IoWMIRegistrationControl with one of the following actions:

  • WMIREG_ACTION_REREGISTER to replace all registration information previously supplied by the driver with new information.

    In response, WMI sends either an IRP_MN_REGINFO request or an IRP_MN_REGINFO_EX request to the driver, with Parameters.WMI.DataPath set to WMIREGISTER. (On Windows 98 and Windows 2000, the system sends the IRP_MN_REGINFO request. On Windows XP and later, the system sends the IRP_MN_REGINFO_EX request.)

    The driver supplies WMI with new registration information for all blocks it supports, as described in Using the WMI Library to Register Blocks and Handling IRP_MN_REGINFO and IRP_MN_REGINFO_EX to Register Blocks.

  • WMIREG_ACTION_UPDATE_GUID to add or remove support for blocks or to change the static instance names of registered blocks.

    In response, WMI sends an IRP_MN_REGINFO or IRP_MN_REGINFO_EX request to the driver, with Parameters.Wmi.DataPath set to WMIUPDATE.

    The driver supplies WMI with an updated registration information in which:

    • The driver sets WMIREG_FLAG_REMOVE_GUID to remove support for that block.
    • The driver clears WMIREG_FLAG_REMOVE_GUID to add a new block or update an existing block.
    • The driver sets or clears WMIREG_FLAG_INSTANCE_XXX and supplies any necessary instance name information to change a block's static instance names or change it to use dynamic instance names.
  • WMIREG_ACTION_DEREGISTER to instruct WMI that the driver will no longer provide WMI information.

    WMI does not send an IRP_MN_REGINFO or IRP_MN_REGINFO_EX request in response to this call, because it requires no further information from the driver. A driver typically deregisters its blocks in response to an IRP_MN_REMOVE_DEVICE request. Note that the deregister call will block until all WMI IRPs to the device have been completed. If a driver queues WMI IRPs, it must cancel them before calling IoWMIRegistrationControl to deregister.


Handling WMI Requests

All drivers must set a dispatch table entry point for a DispatchSystemControl routine to handle WMI requests. If a driver registers as a WMI data provider, it must handle all WMI requests. Otherwise, the driver must forward all WMI requests to the next lower driver.

All WMI IRPs have the major code IRP_MJ_SYSTEM_CONTROL and a one of the following minor codes:

  • IRP_MN_REGINFO, IRP_MN_REGINFO_EX—Queries or updates a driver's registration information after the driver has called IoWMIRegistrationControl.
  • IRP_MN_QUERY_ALL_DATA, IRP_MN_QUERY_SINGLE_INSTANCE—Queries for all instances or a single instance of a given data block.
  • IRP_MN_CHANGE_SINGLE_ITEM, IRP_MN_CHANGE_SINGLE_INSTANCE—Requests the driver to change a single item or multiple items in an instance of a data block.
  • IRP_MN_ENABLE_COLLECTION, IRP_MN_DISABLE_COLLECTION—Requests the driver to start accumulating data for a block that the driver registered as expensive to collect, or to stop accumulating data for such a block.
  • IRP_MN_ENABLE_EVENTS, IRP_MN_DISABLE_EVENTS—Requests the driver to start sending notification of a given event if the event occurs while it is enabled, or to stop sending notification of such an event.
  • IRP_MN_EXECUTE_METHOD—Requests the driver to execute a method associated with a data block.

The WMI kernel-mode component sends WMI IRPs any time following a driver's successful registration as a WMI data provider, typically when a user-mode data consumer has requested WMI information for a driver's device. If a driver registers as a WMI data provider by calling IoWMIRegistrationControl, it must handle each subsequent WMI request in one of the following ways:

  • Call the kernel-mode WMI library routine WmiSystemControl. A driver can call WmiSystemControl to handle requests concerning only blocks that do not use dynamic instance names, and that base static instance names on a single base name string or the device instance ID of a PDO. For more information, see Calling WmiSystemControl to Handle WMI IRPs.
  • In its DispatchSystemControl routine, process and complete any such request tagged with the pointer to its device object that the driver passed in its call to IoWMIRegistrationControl, and forward other IRP_MJ_SYSTEM_CONTROL requests to the next lower driver. For more information, see Processing WMI IRPs in a DispatchSystemControl Routine.


Calling WmiSystemControl to Handle WMI IRPs

WMI library routines simplify handling of WMI requests because instead of processing each such request, a driver calls WmiSystemControl. In the WmiSystemControl call, the driver passes an initialized WMILIB_CONTEXT structure that contains entry points to the driver's DpWmiXxx calllback routines and information about the driver's data blocks and event blocks.

Because the WMI library provides no mechanism for passing dynamic instance names or a static instance name list, a driver can use the WMI library to handle requests involving only data blocks with static instance names based on a PDO or a single base name string. However, nothing prevents a driver from using the WMI library to handle requests for such blocks and processing requests for other blocks in its DispatchSystemControl routine. For more information, see Processing WMI IRPs in a DispatchSystemControl Routine.

To handle WMI IRPs by calling WmiSystemControl, a driver must implement certain required DpWmiXxx callback routines, and might implement additional optional DpWmiXxx callback routines:

  • DpWmiQueryReginfo—(Required) Provides information about the data and event blocks being registered by the driver. WMI calls a driver's DpWmiQueryReginfo routine to process an IRP_MN_REGINFO or IRP_MN_REGINFO_EX request. For more information, see Using the WMI Library to Register Blocks.
  • DpWmiQueryDataBlock—(Required) Returns either a single instance or all instances of a data block. WMI calls a driver's DpWmiQueryDataBlock routine to process an IRP_MN_QUERY_SINGLE_INSTANCE or IRP_MN_QUERY_ALL_DATA request.
  • DpWmiSetDataBlock—(Optional) Changes all data items in a single instance of a data block. WMI calls a driver's DpWmiSetDataBlock routine to process an IRP_MN_CHANGE_SINGLE_INSTANCE request.
  • DpWmiSetDataItem—(Optional) Changes a single data item in an instance of a data block. WMI calls a driver's DpWmiSetDataItem routine to process an IRP_MN_CHANGE_SINGLE_ITEM request.
  • DpWmiFunctionControl—(Optional) Enables and disables event notification and data collection for blocks registered as expensive to collect. WMI calls a driver's DpWmiFunctionControl routine to process an IRP_MN_ENABLE_COLLECTION, IRP_MN_DISABLE_COLLECTION, IRP_MN_ENABLE_EVENTS, or IRP_MN_DISABLE_EVENTS request.
  • DpWmiExecuteMethod—(Optional) Executes a method associated with a data block. WMI calls a driver's DpWmiExecuteMethod routine to process an IRP_MN_EXECUTE_METHOD request.

A driver's DpWmiXxx routines can have any names chosen by the driver writer.

Before calling WmiSystemControl, the driver must initialize a WMILIB_CONTEXT structure with entry points to its DpWmiXxx routines and information about its data blocks and event blocks.

When the driver receives a WMI request:

  1. The driver calls WmiSystemControl with a pointer to its initialized WMILIB_CONTEXT structure, a pointer to its device object, and a pointer to the IRP.
  2. WMI validates the IRP parameters and calls the driver's DpWmiXxx routine that processes the request. If the driver set no entry point in its WMILIB_CONTEXT for an optional DpWmiXxx routine, WMI completes the IRP with default values and status.
  3. In its DpWmiXxx routine, the driver processes the request and writes any output to the caller-supplied buffer. For example, a driver's DpWmiQueryDataBlock routine would write the requested instance(s) of the specified block to the buffer.
  4. In all DpWmiXxx routines except DpWmiQueryReginfo, the driver calls WmiCompleteRequest to complete the request, or returns STATUS_PENDING to postpone completion, as for any IRP.
  5. WMI performs any necessary post-processing, packages any output in an appropriate WNODE_XXX structure, and passes the output and status to the data consumer.


Processing WMI IRPs in a DispatchSystemControl Routine

A driver that handles WMI IRPs in its DispatchSystemControl routine must handle such an IRP only if the device object pointer at Parameters.WMI.ProviderId matches the pointer passed by the driver in its call to IoWMIRegistrationControl. Otherwise, the driver must forward the IRP to the next lower driver.

If the driver handles the request, it must:

  1. Check the GUID at Parameters.WMI.DataPath to determine whether it represents a data block supported by the driver and, if not, fail the IRP with STATUS_WMI_GUID_NOT_FOUND.
  2. A driver should check the input WNODE_XXX structure at Parameters.WMI.Buffer for the instance name when handling any of the following requests:

    IRP_MN_QUERY_SINGLE_INSTANCE
    IRP_MN_CHANGE_SINGLE_INSTANCE
    IRP_MN_CHANGE_SINGLE_ITEM
    IRP_MN_EXECUTE_METHOD

    The driver should check for the instance name as follows:

    • If WNODE_FLAG_STATIC_INSTANCE_NAMES is set in WnodeHeader.Flags, use InstanceIndex as an index into the driver's list of static instance names for that block.
    • If WNODE_FLAG_STATIC_INSTANCE_NAMES is clear in WnodeHeader.Flags, use OffsetInstanceName as an offset to the instance name string in the input WNODE_XXX structure. OffsetInstanceName is the offset in bytes from the beginning of the structure to a USHORT that indicates the length of the instance name string in bytes (not characters), including the NUL terminator if present, followed by the string itself in Unicode.

    If the driver cannot locate the instance specified by InstanceIndex or OffsetInstanceName, it must fail the IRP with STATUS_WMI_INSTANCE_NOT_FOUND.

  3. For an IRP_MN_EXECUTE_METHOD request, check MethodID in the input WNODE_METHOD_ITEM and, if the method is not valid for that data block, fail the IRP with STATUS_WMI_ITEM_ID_NOT_FOUND.
  4. If the request generates output, a driver should check the size of the buffer at Parameters.WMI.BufferSize when handling any of the following requests:

    IRP_MN_QUERY_ALL_DATA
    IRP_MN_QUERY_SINGLE_INSTANCE
    IRP_MN_EXECUTE_METHOD

    If the buffer is too small to receive the output, the driver should succeed the IRP and write a WNODE_TOO_SMALL structure to the buffer at Parameters.WMI.Buffer.

  5. If the request generates output and the buffer size is adequate, write the following output to the buffer at Parameters.WMI.Buffer:
    • For an IRP_MN_QUERY_ALL_DATA request, the driver writes a WNODE_ALL_DATA structure that contains data for all instances of the specified data block
    • For an IRP_MN_QUERY_SINGLE_INSTANCE request, the driver writes a WNODE_SINGLE_INSTANCE structure that contains data for the specified instance of a data block.
    • For an IRP_MN_EXECUTE_METHOD if the method generates output, the driver writes the method output in driver-determined format following the input WNODE_METHOD_ITEM in the buffer (overwriting input data, if any).
  6. Set Irp–>IoStatus.Information to the number of bytes written to the buffer at Parameters.WMI.Buffer and Irp–>IoStatus.Status to STATUS_SUCCESS.
  7. Call IoCompleteRequest to complete the IRP.

For more information, see WMI WNODE_XXX structures.


WMI WNODE_XXX Structures

WMI uses a set of standard data structures called WNODE_XXX to pass data between user-mode data consumers and kernel-mode data providers such as drivers. If a driver handles WMI requests by calling WmiSystemControl, the driver is not required to read or write WNODE_XXX structures. Otherwise, the driver must interpret the input WNODE_XXX at Parameters.WMI.Buffer and/or write an output WNODE_XXX to that location.

The following table lists WMI IRPs and their corresponding WNODE_XXX structures.

WMI IRP | Related WNODE_XXX Structure
IRP_MN_CHANGE_SINGLE _INSTANCE | WNODE_SINGLE_INSTANCE
IRP_MN_CHANGE_SINGLE_ITEM | WNODE_SINGLE_ITEM
IRP_MN_EXECUTE_METHOD | WNODE_METHOD_ITEM
IRP_MN_QUERY_ALL_DATA | WNODE_ALL_DATA
IRP_MN_QUERY_SINGLE_ INSTANCE | WNODE_SINGLE_INSTANCE

Two additional WNODE_XXX structures, WNODE_EVENT_ITEM and WNODE_EVENT_REFERENCE, are used to send notifications of enabled events. A driver that registers event blocks will, if an event is enabled and the event occurs, send notification of the event to WMI by calling IoWMIWriteEvent and passing a WNODE_EVENT_XXX structure. For information about sending WMI events, see Sending WMI Events.

Each WNODE_XXX structure consists of the following:

  • An embedded WNODE_HEADER structure that contains information common to all WNODE_XXX including the size of the buffer, the GUID that represents the data block, and flags that indicate the type of WNODE_XXX structure, whether it uses static or dynamic instance names, and other characteristics of the block.
  • The fixed members of the particular WNODE_XXX structure, such as offsets to instance names and data.

A WNODE_XXX structure in an IRP buffer (Parameters.WMI.Buffer) is typically followed by variable data related to the request, such as dynamic instance names, static instance name strings, input for or output from a method, or data for one or more instances of a data block. The size of the buffer must therefore exceed sizeof(WNODE_XXX) by the amount of variable data involved.

Note that WMI does not perform type-checking on variable data supplied by a driver. The driver must align output data on an appropriate boundary in the output buffer so that a data consumer can parse the data correctly. In particular, each instance must start on an 8-byte boundary and each of its items must be aligned on a natural boundary according to the data block schema previously registered by the driver. Dynamic instance names can be aligned on a 2-byte boundary.

The following figure shows a block diagram of an IRP buffer containing a WNODE_SINGLE_INSTANCE structure that a driver might return in response to an IRP_MN_QUERY_SINGLE_INSTANCE request.

An IRP Buffer Containing a WNODE_SINGLE_INSTANCE

Starting at the top of the previous figure:

  • The WNODE_HEADER structure at the beginning of the WNODE_SINGLE_INSTANCE is contained in a WnodeHeader member. WMI fills in all members of the WNODE_HEADER before sending the request. In the WNODE_HEADER:
    • WnodeHeader.Buffersize indicates the size of the WNODE_SINGLE_INSTANCE, including data that follows the fixed members of the structure. (The value of WnodeHeader.Buffersize is typically less than Parameters.WMI.Buffersize, which indicates the size of the buffer allocated by WMI to receive output from the driver.)
    • WnodeHeader.Guid contains the GUID that identifies the data block.
    • In this example, WnodeHeader.Flags indicates that this structure is a WNODE_SINGLE_INSTANCE and that the data block uses static instance names.
  • Because the data block uses static instance names, WMI sets InstanceIndex to the index of the instance in the list of static instance names passed by the driver when it registered the block. OffsetInstanceNames is not used.
  • WMI sets DataBlockOffset to indicate the offset from the beginning of the buffer to the first byte of instance data. (The driver must not change this value) Again because the data block uses static instance names, this offset indicates the same location as VariableData. If the data block used dynamic instance names, the instance names would start at VariableData and DataBlockOffset would specify a greater offset into the buffer.
  • The driver sets SizeDataBlock to the number of bytes of instance data being returned.
  • At VariableData (after instance name data, if present), the driver writes instance data for the requested instance in the output buffer.

A driver reads and writes WNODE_METHOD_ITEM and WNODE_SINGLE_ITEM structures in much the same way as WNODE_SINGLE_INSTANCE. These structures resemble each other in that each has the fixed members OffsetInstanceName, InstanceIndex, DataBlockOffset, SizeDataBlock (or, in the case of WNODE_SINGLE_ITEM, SizeDataItem) and VariableData. WNODE_METHOD_ITEM includes a MethodId and WNODE_SINGLE_ITEM includes an ItemId which WNODE_SINGLE_INSTANCE lacks.

WNODE_ALL_DATA differs from the preceding structures in that it is used to pass multiple instances of a data block, possibly including dynamic instance names and possibly of different sizes.

The following figure shows a block diagram of an IRP buffer containing a WNODE_ALL_DATA that a driver might return in response to an IRP_MN_QUERY_ALL_DATA request.

An IRP Buffer Containing a WNODE_ALL_DATA

Starting at the top of the previous figure:

  • As described in the previous figure, the WNODE_HEADER structure at the beginning of the WNODE_ALL_DATA is contained in a WnodeHeader member. WnodeHeader.Buffersize and WnodeHeader.Guid indicate the size of the WNODE_ALL_DATA and the GUID of the data block, respectively.

    In this example, WMI sets WnodeHeader.Flags to indicate that this structure is a WNODE_ALL_DATA and that the data block was registered with dynamic instance names (that is, WMI clears WNODE_FLAG_STATIC_INSTANCE_NAMES and WNODE_FLAG_PDO_INSTANCE_NAMES). On output, the driver sets WNODE_FLAG_FIXED_INSTANCE_SIZE to indicate that all of the instances are the same size.

  • WMI sets DataBlockOffset to indicate the offset from the beginning of the buffer to the first byte of instance data. (The driver must not change this value). In this example, instance data follows the instance names at OffsetInstanceNameOffsets.
  • The driver sets InstanceCount to indicate the number of instances being returned.
  • WNODE_XXX for data blocks that use dynamic instance names always contain the instance name strings. Because this example uses dynamic instance names, OffsetInstanceNameOffsets indicates the offset from the beginning of the buffer to an array of offsets to dynamic instance names in the buffer.
  • FixedInstanceSize indicates the number of bytes of data in each instance being returned by the driver. If instances of this data block were to vary in size, the driver would clear WNODE_FLAG_FIXED_INSTANCE_SIZE in WnodeHeader.Flags and set OffsetInstanceDataAndLength to an array of OFFSETINSTANCEDATAANDLENGTH structures, each specifying an offset to the data for one instance and the number of bytes in that instance instead of setting FixedInstanceSize.

For more information about WNODE_XXX structures, see WMI Structures.


Sending WMI Events

A driver can use WMI events to notify user-mode applications of events without requiring the applications to poll or send IRPs. A driver should use WMI events to notify WMI clients of exceptional conditions, not as an alternative to error logging. A driver should support any standard event blocks defined for its device type in wmicore.mof, and might define and register additional custom event blocks to support device-specific notifications.

An event block is simply a data block that derives from the abstract base class WMIEvent. An event block can contain any of the same data as a data block, or it can be empty—that is, an event block need not contain any driver-defined data items. If an event block does contain data, the total size of the WNODE_XXX plus the data should not exceed the registry-defined limit of 1K. In general, smaller events result in better system performance and more timely notification. For information about defining blocks, see MOF Syntax for WMI Data and Event Blocks and Designing WMI Data and Event Blocks.

A driver indicates support for an event by registering the corresponding event block with WMIREG_FLAG_EVENT_ONLY_GUID set in the block's WMIREGGUID structure. For information about registering blocks, see Registering as a WMI Data Provider.

When a WMI client user requests notification of an event, WMI sends an IRP_MN_ENABLE_EVENTS request to the driver, which alerts the driver to begin monitoring the event's driver-determined trigger condition. Then, when the trigger condition occurs, the driver sends the event to WMI, which delivers it to all data consumers that have registered for the event.

A driver sends an event to WMI in one of the following ways:

  • Call the kernel-mode WMI library routine WmiFireEvent. A driver can call WmiFireEvent to send only events that do not use dynamic instance names, and that base static instance names on a single base name string or the device instance ID of a PDO. Furthermore, the event must be a single instance—that is, a driver cannot call WmiFireEvent to send an event that consists of a single item or multiple instances. For more information, see Sending an Event with WmiFireEvent.
  • Call the kernel-mode routine IoWmiWriteEvent with a pointer to a driver-allocated and initialized WNODE_XXX structure that contains the event's data. For more information, see Sending an Event with IoWMIWriteEvent.


Sending an Event with WmiFireEvent

A driver can call WmiFireEvent to send events that do not use dynamic instance names, and that base static instance names on a single base name string or the device instance ID of a PDO.

The event must be a single instance of a block—that is, a driver cannot call WmiFireEvent to send an event that consists of a single item or multiple instances. To send such events, a driver must call IoWMIWriteEvent, as described in Sending an Event with IoWMIWriteEvent.

A driver should not send events until WMI has enabled the event. After the event has been enabled, when the event's trigger condition occurs, the driver:

  1. Allocates a buffer from the nonpaged pool and writes the event data to the buffer. If the event has no data, the driver can skip this step.
  2. Calls WmiFireEvent with the following parameters:
    • A pointer to the driver's device object
    • A pointer to the GUID that represents the event block
    • If the event block has multiple instances, the index of the instance
    • If data is to be sent with the event, the number of bytes of data, or 0 if none
    • If data is to be sent with the event, a pointer to the driver-allocated buffer that contains the data, or NULL if none

    The driver must allocate all parameters passed to WmiFireEvent, including the event data buffer, from nonpaged pool. WMI releases the driver-allocated memory without further intervention by the driver.

After WmiFireEvent returns, the driver resumes monitoring the event's trigger condition and sends the event each time its trigger condition occurs until WMI disables that event.


Sending an Event with IoWMIWriteEvent

A driver can call IoWMIWriteEvent to send any event. The event can consist of a single item, a single instance, or all instances of a data block, and it can use dynamic instance names.

Unlike WNODE_XXX structures passed with query or change requests, which are allocated and partially initialized by WMI, the driver must allocate and initialize all members of the WNODE_XXX structure that contains an event.

A driver must send an event only after WMI has sent an IRP_MN_ENABLE_EVENTS request to enable the event. Then, when the event's trigger condition occurs, the driver:

  1. Allocates a buffer from nonpaged pool to contain the WNODE_XXX structure needed for the event, including space for variable data, if any.

    Depending on the event, the driver might allocate a WNODE_SINGLE_ITEM, a WNODE_SINGLE_INSTANCE, or a WNODE_ALL_DATA for the event. The size of the WNODE_XXX plus variable data must not exceed the registry-defined limit of 1K.

  2. Initializes all members of the WNODE_XXX structure, including WnodeHeader.Flags:
    • The driver sets WNODE_FLAG_EVENT_ITEM to indicate that the structure is an event.
    • The driver sets one of the following to indicate the type of WNODE_XXX structure:

      WNODE_FLAG_ALL_DATA
      WNODE_FLAG_SINGLE_INSTANCE
      WNODE_FLAG_SINGLE_ITEM

    • The driver sets or clears the following flags to indicate whether the block uses static or dynamic instance names:

      WNODE_FLAG_STATIC_INSTANCE_NAMES
      WNODE_FLAG_PDO_INSTANCE_NAMES

    • The driver might set additional flags depending on the event.
  3. Casts a pointer to the WNODE_XXX to a PWNODE_EVENT_ITEM.
  4. Calls IoWMIWriteEvent with the pointer.

    If IoWMIWriteEvent completes successfully, WMI releases the driver-allocated memory for the event.

After IoWmiWriteEvent returns, the driver resumes monitoring the event's trigger condition and sending the event each time its trigger condition occurs, until WMI sends an IRP_MN_DISABLE_EVENTS request to disable that event.

If the size of an event exceeds the registry-defined maximum of 1K (not recommended) the driver should call IoWmiWriteEvent with an initialized WNODE_EVENT_REFERENCE that specifies the event's GUID, its size, and its instance index (for static instance names) or name (for dynamic instance names). WMI will use the information in the WNODE_EVENT_REFERENCE to query for the event.

A driver can send an events that does not use dynamic instance names and that consists of a single instance by calling the WMI library routine WmiFireEvent. The driver does not need to allocate and initialize a WNODE_XXX structure for a WmiFireEvent call. WMI packages the driver's event data in a WNODE_SINGLE_INSTANCE and delivers it to data consumers. For more information about sending events with WmiFireEvent, see Sending an Event with WmiFireEvent.


WMI Property Sheets

A user-friendly driver allows users to control its settings through its Device Manager property sheet. See Using the Device Manager for a description of the Device Manager.

Drivers can automatically expose any WMI classes they implement on their property sheet by using the WMI Generic Property Page Provider.

Drivers can enable certain controls on the Power Management tab of their Device Manager property sheet by supporting certain particular WMI class GUIDs. See WMI and the Power Management Tab for details.


WMI Generic Property Page Provider

In Windows 2000 and later operating systems, drivers can expose their WMI classes through the WMI generic property page provider. The provider uses each class declarations to create a simple property page for the class properties.

How Property Qualifiers Determine the Property Page

The WMI generic property page provider uses a control appropriate for the data type of each property in the class. The following property qualifiers modify the type of control used:

  • Write

    A property with the write qualifier can be changed through the property page. Otherwise the property is read-only.

  • Values and ValuesMap

    The generic property page provider uses a list box to represent the possible values.

  • Range

    The generic property page provider validates that the data entered conforms to the specified range.

  • DisplayName

    The generic property page provider uses the value of this property qualifier as the label for the property.

  • DisplayInHex

    If present, the property value is displayed in hexadecimal.

Driver writers should localize property qualifiers that are strings. See Localizing MOF Files for details.

Enabling the Generic Property Page Provider

To use the WMI generic property page provider with your driver, you must enable wmiprop.dll as a device co-installer.

In the CoInstaller add-registry-section, register wmiprop.dll as a co-installer for the WMI class by adding a value entry for the class GUID under the HKLM\System\CurrentControlSet\Control\CoDeviceInstallers key. The value for the value entry is "WmiProp.dll, WmiPropCoInstaller". For example:

; This section is defined in the CoInstaller section, as follows.
; [CoInstaller]
; AddReg = CoInstaller_AddReg

[CoInstaller_AddReg]
HKLM, System\CurrentControlSet\Control\CoDeviceInstallers, ClassGUID,
    0x00010000, "WmiProp.dll, WmiPropCoInstaller"

ClassGUID is the GUID for the WMI class. See Registering a Class Co-installer for details.

You must also specify the particular WMI classes to be exposed through the generic property provider. To do this, set the WmiConfigClasses value-entry to be a comma-separated list of the WMI classes in the add-registry-section of the device class or device hardware instance.

; the device class AddReg section.
[device_class_AddReg]
HKR,,"WmiConfigClasses",0x00000000,"class1,class2"

; the device hardware instance AddReg section.
[device_hw_inst_AddReg]
HKR,,"WmiConfigClasses",0x00000000,"class3"

See INF AddReg Directive for a description of an add-registry-section in INF files.


WMI and the Power Management Tab

Drivers that support power management can automatically enable the Power Management tab for the device property sheet in the Device Manager. If a driver handles the GUID_POWER_DEVICE_ENABLE or GUID_POWER_DEVICE_WAKE_ENABLE WMI class GUIDs, the Device Manager displays a Power Management tab on the device property sheet. Certain controls on the property page are enabled depending on which WMI class GUIDs the driver supports.

The GUID_POWER_DEVICE_XXX class GUIDs enable controls on the property page as follows:

  • GUID_POWER_DEVICE_ENABLE

    Enables a check box to activate or deactivate power management for the device. The data block for the WMI class consists of a single BOOLEAN value that indicates whether power management is enabled. The meaning of the value is device-dependent.

  • GUID_POWER_DEVICE_WAKE_ENABLE

    Enables a check box to activate or deactivate sending wait/wake IRPs. When selected, the driver should send an IRP_MN_WAIT_WAKE request to its physical device object. This enables the device to wake the system in response to an external event. For example, when enabled for the keyboard class driver, the keyboard device will wake the system when a key is pressed. When the check box is not selected, the driver should cancel the IRP_MN_WAIT_WAKE request. The data block for the WMI class consists of a single BOOLEAN value that indicates the current state of the check box.

WMI query requests are sent for the GUID_POWER_DEVICE_XXX WMI class GUIDs whenever the property sheet for the driver is opened in the Device Manager. The WMI change requests are sent whenever one of the check box values on the Power Management tab changes. Users will expect the value they set to persist between driver loads and unloads, so drivers should store the current value of either property in the registry.

The mouse or keyboard class sample drivers both handle the GUID_POWER_DEVICE_WAKE_ENABLE WMI class GUID. See src\input\kbdclass and src\input\mouclass in the DDK.


Using wmimofck.exe

Included with the DDK is the wmimofck.exe utility. This application takes as input a binary MOF file (a .bmf file), which was generated by the MOF compiler (mofcomp.exe). Wmimofck.exe will check that the classes, properties, methods and events specified in the .bmf file are valid for WMI use. Wmimofck.exe is also capable of generating the following files:

  • C language header file (.h file) that can then be used to keep header file in sync with MOF definitions.
  • C language source file which contains stubs for WMI driver code.
  • Hex version of .bmf data which can be included in the driver source for supplying dynamic MOF data at runtime.
  • Test application templates in VBScript or HTML.

To run the wmimofck utility, use the following syntax:

wmimofck [-h filename] [-c filename] [-x filename] [-t filename] [-w directory] [-yfilename] [-zfilename]

If the -h parameter is specified, a C language header file is created that defines the GUIDs, data structures, and method indices specified in the MOF file. If the caller specifies the -m flag as well, then the header file will include structure definitions for the input and output of each WMI method. By default, wmimofck does not generate member definitions for WMI classes that contain variable length properties. If the caller specifies -u, then wmimofck will generate member definitions for every property that has a fixed size, including string properties that specify a MaxLen qualifier. If the -t parameter is specified, a VBScript applet is created that will query all data blocks and properties specified in the MOF file.

If the -x parameter is specified a text file is created that contains the text representation of the binary MOF data. This can be included in the source of the driver if the driver supports reporting the binary MOF via a WMI query rather than a resource on the driver image file.

If the -c parameter is specified, a C language source file is generated that contains a template for implementing WMI code in a device driver.

If the -w parameter is specified, a set of HTML files are generated that create a rudimentary UI that can be used to access the WMI data blocks.

The -y and -z flags can only be used together. The -y specifies a file containing language-independent WMI class declarations, and -z specifies the class amendments for a particular language. The command wmimofck localizedfile -y mof -z mfl merges the mof and mfl files to form the complete localized version of MOF file. See Building and Deploying the Localized MOF File for details.

This form of the wmimofck command is used to combine a


WMI Support for Tracing Driver Operation

This section describes the following topics about WMI support in Microsoft® Windows® 2000 and later for tracing the operation of a kernel-mode driver.

WMI Event Tracing

WPP Software Tracing


WMI Event Tracing

This section describes the WMI extensions to WDM (supported by Windows 2000 and later) that kernel-mode drivers, as information providers, can use to provide information to information consumers. Drivers typically provide information that a consumer uses to determine the driver's configuration and resource usage. In addition to the WMI extensions to WDM, a user-mode API supports providers or consumers of WMI event information — see the Platform SDK for more information.

The event tracing logger supports up to 32 instances. One of the instances is reserved for tracing the kernel. The logger supports tracing a high event rate.

Trace events are defined in the same manner as other WMI events. WMI events are described in the MOF file. For more information on WMI event descriptions, see MOF Syntax for WMI Data and Event Blocks.

The process by which kernel-mode drivers log information is integrated into the existing WMI infrastructure. To log trace events, a driver does the following:

  1. Register as a WMI provider by calling IoWMIRegistrationControl.
  2. Mark events as traceable by setting WMIREG_FLAG_TRACED_GUID in the Flags member of the WMIREGGUID structure that is passed when the driver registers events with WMI.
  3. Specify one event as the control event for overall enabling/disabling of a set of trace events by setting WMIREG_FLAG_TRACE_CONTROL_GUID in the Flags member of the WMIREGGUID structure that is passed when the driver registers events with WMI.
  4. Upon receiving a request from WMI to enable events where the GUID matches the trace control GUID, the driver should store the handle to the logger. The value will be needed when writing an event. The logger handle value is contained in the HistoricalContext member of the WNODE_HEADER portion of the WMI buffer that this is part of the parameters in the enable events request.
  5. Decide whether the trace event will be sent to WMI event consumers or is targeted for the WMI event logger only. This will determine where the memory for the EVENT_TRACE_HEADER structure should come from. This memory will eventually be passed to IoWMIWriteEvent.

    If the event is a log event only, the memory will not be deleted by WMI. In this case, the driver should pass in a buffer on the stack or should be reusing an allocated buffer for this purpose. For performance reasons, the driver should minimize any unnecessary calls to allocate or free memory. Failure to comply with this recommendation will compromise the integrity of the timing information contained in the log file.

    If the event is to be sent to both the logger and to WMI event consumers, then the memory must be allocated from a nonpaged pool. In this case the event will be sent to the logger and then forwarded to WMI to be sent to WMI event consumers who have requested notification of the event. The memory for the event will then be freed by WMI according to the behavior of IoWMIWriteEvent.

  6. After the memory for the EVENT_TRACE_HEADER and any driver event data, if any, has been secured, the following information should be set:

    Set the Size member to the sizeof(EVENT_TRACE_HEADER) plus the size of any additional driver event data that will be appended on to the end of EVENT_TRACE_HEADER.

    Set the Flags member to WNODE_FLAG_TRACED_GUID to have the event sent to the logger. If the event is to be sent to WMI event consumers as well, set the WNODE_FLAG_LOG_WNODE. Note, it is not necessary to set WNODE_FLAG_TRACED_GUID if setting WNODE_FLAG_LOG_WNODE. If both are set, WNODE_FLAG_TRACED_GUID will take precedence and the event will not be sent to WMI event consumers.

    Set the Guid or the GuidPtr member. If using GuidPtr, set WNODE_FLAG_USE_GUID_PTR in the Flags member.

    Optionally, specify a value for TimeStamp. If the driver does not specify a TimeStamp value the logger will fill this in. If the driver does not want the logger to set the time stamp then it should set WNODE_FLAG_USE_TIMESTAMP in the Flags member.

    Set any of the following EVENT_TRACE_HEADER members that have meaning to the driver: Class.Type, Class.Level, and Class.Version.

    Finally cast the EVENT_TRACE_HEADER to a WNODE_HEADER and set the HistoricalContext value of the Wnode to the logger handle that was saved in step 4 above.

  7. Call IoWMIWriteEvent with the pointer to the EVENT_TRACE_HEADER structure.

The driver should continue logging trace events associated with the control GUID until the driver receives notification to disable event logging via an IRP_MN_DISABLE_EVENTS request.


WPP Software Tracing

This section describes how to use the Windows software trace preprocessor (WPP) to trace a driver's operation. WPP software tracing supplements and enhances WMI event tracing by adding conventions and mechanisms that simplify tracing a driver's operation.

The main components of WPP software tracing are:

  • WPP preprocessor
  • WMI support routines that a driver uses to log trace messages
  • Utilities to start and stop tracing and to interpret a message log

WPP software tracing is an efficient way for a driver to log real-time binary messages. The log can be later interpreted to produce a readable trace of the driver's operation. Logging messages with WPP software tracing is similar to using the Windows event logging services. The driver logs a message ID and raw data. Subsequently, a postprocessor uses an analog of a message compiler file to interpret and display the data. However, the message format supported by WPP software tracing is more capable and flexible than that supported by message compiler files. For example, WPP software tracing supports IP addresses, GUIDs, system IDs, time stamps, and many others. In addition, users can add types relevant to their application.

Detailed information about WPP software tracing will be provided in a future release of the DDK.

For information about WMI library support routines that support WPP software tracing, see:

WmiQueryTraceInformation

WmiTraceMessage

WmiTraceMessageVa


Testing WMI Support in WDM Drivers

To test a driver for WMI support, a WMI client application can be written using the WMI user-mode API. For more information about this user-mode API, which allows applications to provide or consume WMI information, refer to the Windows Management Instrumentation information in the Platform SDK.

A WMI client application performs the following tasks to test a driver:

  • Installs the WMI provider for WDM. To install the provider, the application registers the provider and registers specific class definitions of WMI data blocks to which the application requires access. These WMI data blocks define information that a driver can provide. These WMI data blocks are either defined by a class or port driver or defined by the driver itself in one or more Managed Object Format (MOF) files.
  • Connects to WMI. To connect to WMI, the application can call the Component Object Model (COM) function CoCreateInstance to retrieve a pointer to the IWbemLocator interface. The application then calls the IWbemLocator::ConnectServer method to connect to WMI. From this call, the application receives a pointer to the IWbemServices interface.
  • Accesses information in the driver. To access information and to register for events, the application uses the methods of the IWbemServices interface.

Alternatively, the vbscript or HTML output from wmimofck.exe can be used to test a driver for WMI support. For more information about the wmimofck utility see Using wmimofck.exe .


Driver Programming Techniques

This section contains sections on various topics of interest to driver writers. It includes the following sections:

64-Bit Issues

Using GUIDs in Drivers

Logging Errors

Supporting Removable Media

Driver Reliability Issues


64-Bit Issues

This section discusses issues you need to be concerned about when providing drivers for 64-bit environments. It includes the following sections:

Porting Your Driver To 64-Bit Windows

Supporting 32-Bit I/O in Your 64-Bit Driver


Porting Your Driver to 64-Bit Windows

The 64-bit version of Microsoft® Windows® is designed to make it possible for developers to use a single source-code base for their Win32®- and Win64™-based applications. To a large extent, this is also true for 32-bit and 64-bit Windows drivers.

For user-mode applications, 64-bit Windows includes a Windows on Windows (WOW64) thunking layer that enables Win32 applications to execute (with some performance degradation) on Win64 systems. It does this by intercepting Win32 function calls and converting pointer-precision parameter types to fixed-precision types as appropriate before making the transition to the 64-bit kernel. This conversion process is called thunking.

Note This thunking is only done for 32-bit applications; 32-bit drivers are not supported on 64-bit Windows.


What's Changed

On 32-bit Windows, the integer, long, and pointer data types are all the same size — 32 bits. This convenient uniformity in data type sizes has been a boon to clever C programmers, many of whom have come to take it for granted.

On 64-bit Windows, however, this assumption of uniformity is no longer valid. Pointers are now 64 bits in length, but integer and long data types remain the same size as before — 32 bits. This is because, while 64-bit pointers are needed to accommodate systems with as much as 16 TB of virtual memory, most data still fits comfortably into 32-bit integers. For most applications, changing the default integer size to 64 bits would only be a waste of space.

On 32-bit Windows platforms, the operating system automatically fixes kernel-mode memory alignment faults and makes them invisible to the application. It does this for the calling process and any descendant processes. This feature, which often dramatically reduces performance, has not been implemented in 64-bit Windows. Thus, if your 32-bit driver contains misalignment bugs, you will need to fix them when porting to 64-bit Windows.


The New Data Types

There are three classes of new data types: fixed-precision integer types, pointer-precision integer types, and specific-precision pointer types. These types were added to the Microsoft® Windows® environment (specifically, to Basetsd.h) to allow developers to prepare for 64-bit Windows well before its introduction. These new types were derived from the basic C-language integer and long types, so they work in existing code. Therefore, use these data types in your code now, test your code on 32-bit Windows, and use the 64-bit compiler to find and fix portability problems in advance, so your driver can be ready when 64-bit Windows is available for testing.

In addition, adopting these new data types will make your code more robust. To use these data types, you must scan your code for potentially unsafe pointer usage, polymorphism, and data definitions. To be safe, use the new types. For example, when a variable is of type ULONG_PTR, it is clear that it will be used for casting pointers for arithmetic operations or polymorphism. It is not possible to indicate such usage directly by using the native Win32® data types. You can do this by using derived type naming or Hungarian notation, but both techniques are prone to errors.

Fixed-Precision Integer Types

Fixed-precision data types are the same length for 32-bit and 64-bit programming. To help you remember this, their precision is part of the name of the data type. The following are the fixed-precision data types.

Type | Definition
DWORD32 | 32-bit unsigned integer
DWORD64 | 64-bit unsigned integer
INT32 | 32-bit signed integer
INT64 | 64-bit signed integer
LONG32 | 32-bit signed integer
LONG64 | 64-bit signed integer
UINT32 | Unsigned INT32
UINT64 | Unsigned INT64
ULONG32 | Unsigned LONG32
ULONG64 | Unsigned LONG64

Pointer-Precision Integer Types

As the pointer precision changes (that is, as it becomes 32 bits when compiled for 32-bit platforms, 64 bits when compiled for 64-bit platforms), these data types reflect the precision accordingly. Therefore, it is safe to cast a pointer to one of these types when performing pointer arithmetic; if the pointer precision is 64 bits, the type is 64 bits. The count types also reflect the maximum size to which a pointer can refer. The following are the pointer-precision and count types.

Type | Definition
DWORD_PTR | Unsigned long type for pointer precision.
HALF_PTR | Signed integral type for half-pointer precision (16 bits on 32-bit systems, 32 bits on 64-bit systems).
INT_PTR | Signed integral type for pointer precision.
LONG_PTR | Signed long type for pointer precision.
SIZE_T | The maximum number of bytes to which a pointer can refer. Use this type for a count that must span the full range of a pointer.
SSIZE_T | Signed SIZE_T.
UHALF_PTR | Unsigned HALF_PTR.
UINT_PTR | Unsigned INT_PTR.
ULONG_PTR | Unsigned LONG_PTR.

Fixed-Precision Pointer Types

There are also new pointer types that explicitly size the pointer. Be cautious when using these pointer types in 64-bit code: If you declare the pointer using a 32-bit type, the system creates the pointer by truncating a 64-bit pointer.

Type | Definition
POINTER_32 | A 32-bit pointer. On a 32-bit system, this is a native pointer. On a 64-bit system, this is a truncated 64-bit pointer.
POINTER_64 | A 64-bit pointer. On a 64-bit system, this is a native pointer. On a 32-bit system, this is a sign-extended 32-bit pointer. Note that it is not safe to assume the state of the high pointer bit.

Win64 Helper Functions

The following inline functions (defined in Basetsd.h) can help you safely convert values from one type to another:

unsigned long HandleToUlong( const void *h )
long HandleToLong( const void *h )
void *LongToHandle( const long h )
unsigned long PtrToUlong( const void *p )
unsigned int PtrToUint( const void *p )
unsigned short PtrToUshort( const void *p )
long PtrToLong( const void *p )
int PtrToInt( const void *p )
short PtrToShort( const void *p )
void * IntToPtr( const int i )
void * UIntToPtr( const unsigned int ui )
void * LongToPtr( const long l )
void * ULongToPtr( const unsigned long ul )

Warning: IntToPtr sign-extends the int value, UIntToPtr zero-extends the unsigned int value, LongToPtr sign-extends the long value, and ULongToPtr zero-extends the unsigned long value.


64-Bit Compiler

The Microsoft® Windows® DDK and IFS Kit include a partial 64-bit build environment you can use to evaluate your driver source code for the upcoming 64-bit version of Windows. This environment includes a 64-bit compiler that you can use to identify pointer truncation, improper type casts, and other 64-bit-specific problems. Better tools will be available in future releases, but this tool will get you started.

The first time you run the compiler, it will probably generate many pointer truncation or type mismatch warnings such as the following:

warning C4311: 'type cast' : pointer truncation from 'unsigned char *' to 'unsigned long '

Use these warnings as a guide to make your code more robust. It is good practice to eliminate all warnings, especially pointer-truncation warnings. For example, the following code can generate the C4311 warning:

buffer = (PUCHAR)srbControl;
(ULONG)buffer += srbControl->HeaderLength;

To correct the code, make the following changes:

buffer = (PUCHAR)srbControl;
(ULONG_PTR)buffer += srbControl->HeaderLength;

Predefined Macros

The compiler defines the following macros to identify the platform.

Macro | Meaning
_WIN64 | A 64-bit platform.
_WIN32 | A 32-bit platform. This value is also defined by the 64-bit compiler for backward compatibility.
_WIN16 | A 16-bit platform.

The following macros are specific to the architecture.

Macro | Meaning
_M_IA64 | A 64-bit Intel platform.
_M_IX86 | A 32-bit Intel platform.
_M_ALPHA_64 | A 64-bit Alpha platform.
_M_ALPHA32 | A 32-bit Alpha platform.
_M_ALPHA | An Alpha platform, either 32-bit or 64-bit.

Do not use these macros except with architecture-specific code. Instead, use _WIN64, _WIN32, and _WIN16 whenever possible.

64-Bit Compiler Switches and Warnings

There is a warning option to assist porting to 64-bit Windows. The -Wp64-W3 switch enables the following warnings:

  • C4305: Truncation warning. For example, "return": truncation from "unsigned int64" to "long."
  • C4311: Truncation warning. For example, "type cast": pointer truncation from "int*_ptr64" to "int."
  • C4312: Conversion to bigger-size warning. For example, "type cast": conversion from "int" to "int*_ptr64" of greater size.
  • C4318: Passing zero length. For example, passing constant zero as the length to the memset function.
  • C4319: Not operator. For example, "~": zero extending "unsigned long" to "unsigned _int64" of greater size.
  • C4313: Calling the printf family of functions with conflicting conversion type specifiers and arguments. For example, "printf": "%p" in format string conflicts with argument 2 of type "_int64." Another example is the call printf("%x", pointer_value); this causes a truncation of the upper 32 bits. The correct call is printf("%p", pointer_value).
  • C4244: Same as the existing warning C4242. For example, "return": conversion from "_int64" to "unsigned int," possible loss of data.


Performing DMA in 64-Bit Windows

Adding 64-bit addressing support to your driver can significantly improve overall system performance. This is particularly important for device drivers that perform direct memory access (DMA). In 64-bit Microsoft® Windows®, device drivers that perform DMA but do not support 64-bit addressing are double-buffered, which results in lower relative performance.

Although double-buffering usually has a relatively small impact (single percentage points) on 8 GB systems, this is enough to impact I/O-intensive tasks, such as database activity. As the amount of physical memory increases, this negative performance impact increases as well.

To support 64-bit DMA, drivers should observe the following guidelines:

  1. Use PHYSICAL_ADDRESS structures for physical address calculations.
  2. Treat the entire 64-bit address as a valid physical address. For example, drivers should not call MmGetPhysicalAddress on a locked buffer, discard the high 32 bits, and pass the truncated address to a 32-bit component adapter. This results in corrupted memory, lost I/O, and system failure.
  3. Use the high-performance scatter/gather routines (GetScatterGatherList and PutScatterGatherList) that were added in Windows 2000.
  4. Check the value of the Mm64BitPhysicalAddress global system variable. If it is TRUE, the system supports 64-bit physical addressing.
  5. Set the Dma64BitAddresses member of the DEVICE_DESCRIPTION structure to TRUE to indicate that your driver supports 64-bit DMA addresses.

The DMA routines in 32-bit Windows are 64-bit-ready. If your device driver uses these routines correctly, your DMA code should work without modification on 64-bit Windows.


Porting Issues Checklist

General

  • Use the new Win64-safe data types.

    The new Microsoft® Win64™-safe data types, described earlier in this document, are defined in basetsd.h. This header file is included in ntdef.h, which is included in ntddk.h, wdm.h, I, and ntifs.h.

  • Use the platform compiler macros carefully.

    The following assumption is no longer valid:

    #ifdef _WIN32 // Win32 code
...
#else         // Win16 code
...
#endif

    However, the 64-bit compiler defines _WIN32 for backward compatibility.

    Also, the following assumption is no longer valid:

    #ifdef _WIN16 // Win16 code
...
#else         // Win32 code
...
#endif

    In this case, the else clause can represent _WIN32 or _WIN64.

  • Use the proper format specifiers with printf and wsprintf.

    Use %p to print pointers in hexadecimal. This is the best choice for printing pointers.

    Note A future version of Visual C++ will support %I to print polymorphic data. It will treat values as 64 bits in Win64 and 32 bits in Win32®. Visual C++ will also support %I64 to print values that are 64 bits.

  • Know your address space.

    Do not blindly assume, for example, that if an address is a kernel address, its high-order bit must be set. To obtain the lowest system address, use the MM_LOWEST_SYSTEM_ADDRESS macro.

Pointer Arithmetic

  • Be careful when performing unsigned and signed operations.

    Consider the following:

    ULONG x;
LONG y;
LONG *pVar1;
LONG *pVar2;

pVar2 = pVar1 + y * (x - 1);

    The problem arises because x is unsigned, which makes the entire expression unsigned. This works fine unless y is negative. In this case, y is converted to an unsigned value, the expression is evaluated using 32-bit precision, scaled, and added to pVar1. On 64-bit Windows®, this 32-bit unsigned negative number becomes a large 64-bit positive number, which gives the wrong result. To fix this problem, declare x as a signed value or explicitly typecast it to LONG in the expression.

  • Be careful when using hexadecimal constants and unsigned values.

    The following assertion is not true on 64-bit systems:

    ~((UINT64)(PAGE_SIZE-1)) == (UINT64)~(PAGE_SIZE-1)
PAGE_SIZE = 0x1000UL // Unsigned Long - 32 bits
PAGE_SIZE - 1 = 0x00000fff

    LHS expression:

    // Unsigned expansion(UINT64)(PAGE_SIZE -1 ) = 0x0000000000000fff
~((UINT64)(PAGE_SIZE -1 )) = 0xfffffffffffff000

    RHS expression:

    ~(PAGE_SIZE-1) = 0xfffff000
(UINT64)(~(PAGE_SIZE - 1)) = 0x00000000fffff000

    Hence:

    ~((UINT64)(PAGE_SIZE-1)) != (UINT64)(~(PAGE_SIZE-1))
  • Be careful with NOT operations.

    Consider the following:

    UINT_PTR a; ULONG b;
a = a & ~(b - 1);

    The problem is that ~(b–1) produces 0x0000 0000 xxxx xxxx and not 0xFFFF FFFF xxxx xxxx. The compiler will not detect this. To fix this, change the code as follows:

    a = a & ~((UINT_PTR)b - 1);
  • Be careful when computing buffer sizes.

    Consider the following:

    len = ptr2 – ptr1
/* len could be greater than 2**32 */

    Cast pointers to PCHAR for pointer arithmetic.

Note If len is declared INT or ULONG, this will generate a compiler warning. Buffer sizes, even when computed correctly, may still exceed the capacity of ULONG.

  • Avoid using computed or hard-coded pointer offsets.

    When working with structures, use the FIELD_OFFSET macro wherever possible to determine the offset of structure members.

  • Avoid using hard-coded pointer or handle values.

    Do not pass hard-coded pointers or handles such as (HANDLE)0xFFFFFFFF to routines such as ZwCreateSection. Instead, use constants, such as INVALID_HANDLE_VALUE, that can be defined to have the appropriate value for each platform.

  • Be aware that in 64-bit Windows, 0xFFFFFFFF Is not the same as -1.

    For example:

    DWORD index = 0;
CHAR *p;

// if (p[index – 1] == '0') causes access violation on Win64!

    On 32-bit machines:

    p[index-1] == p[0xffffffff] == p[-1]

    On 64-bit machines:

    p[index-1] == p[0x00000000ffffffff] != p[-1]

    This problem can be avoided by changing the type of index from DWORD to DWORD_PTR.

Polymorphism

  • Be careful with polymorphic interfaces.

    Do not create functions that accept parameters of type DWORD (or other fixed-precision types) for polymorphic data. If the data can be a pointer or an integral value, the parameter type should be UINT_PTR or PVOID, not DWORD.

    For example, do not create a function that accepts an array of exception parameters typed as DWORD values. The array should be an array of DWORD_PTR values. Therefore, the array elements can hold addresses or 32-bit integral values. The general rule is that if the original type is DWORD and it needs to be pointer width, convert it to a DWORD_PTR value. That is why there are corresponding pointer-precision types for the native Win32 types. If you have code that uses DWORD, ULONG, or other 32-bit types in a polymorphic way (that is, you really want the parameter or structure member to hold an address), use UINT_PTR in place of the current type.

  • Be careful when calling functions that have pointer OUT parameters.

    Do not do this:

    void GetBufferAddress(OUT PULONG *ptr);
{
  *ptr=0x1000100010001000;
}
void foo()
{
  ULONG bufAddress;
  //
  // this call causes memory corruption
  //
  GetBufferAddress((PULONG *)&bufAddress);
}

    Typecasting bufAddress to (PULONG *) PULONG * prevents a compiler error. However, GetBufferAddress will write a 64-bit value into the memory location at &bufAddress. Because bufAddress is only a 32-bit value, the 32 bits immediately following bufAddress will get overwritten. This is a very subtle, hard-to-find bug.

  • Do not cast pointers to INT, LONG, ULONG, or DWORD.

    If you must cast a pointer to test some bits, set or clear bits, or otherwise manipulate its contents, use the UINT_PTR or INT_PTR type. These types are integral types that scale to the size of a pointer for both 32-bit and 64-bit Windows (for example, ULONG for 32-bit Windows and _int64 for 64-bit Windows). For example, assume you are porting the following code:

    ImageBase = (PVOID)((ULONG)ImageBase | 1);

    As a part of the porting process, you would change the code as follows:

    ImageBase = (PVOID)((ULONG_PTR)ImageBase | 1);

    Use UINT_PTR and INT_PTR where appropriate (and if you are uncertain whether they are required, there is no harm in using them just in case). Do not cast your pointers to the types ULONG, LONG, INT, UINT, or DWORD.

    Note HANDLE is defined as a void *, so typecasting a HANDLE value to a ULONG value to test, set, or clear the low two bits is a programming error.

  • Use PtrToLong and PtrToUlong to truncate pointers.

    If you must truncate a pointer to a 32-bit value, use the PtrToLong or PtrToUlong function (defined in basetsd.h). This function disables the pointer truncation warning for the duration of the call.

    Use these functions carefully. After you truncate a pointer variable using one of these functions, never cast the resulting LONG or ULONG back to a pointer. These functions truncate the upper 32 bits of an address, which are usually needed to access the memory originally referenced by pointer. Using these functions without careful consideration will result in fragile code.

Data Structures and Structure Alignment

  • Carefully examine all uses of data structure pointers.

    The following are common trouble areas:

    • Data structures that are stored on disk or exchanged with 32-bit processes.
    • Explicit and implicit unions with pointers.
    • Security descriptors.
  • Use the FIELD_OFFSET macro.

    For example:

    struct xx {
   DWORD NumberOfPointers;
   PVOID Pointers[1];
};

    The following allocation is incorrect in 64-bit Windows because the compiler will pad the structure with an additional 4 bytes to make the 8-byte alignment requirement:

    malloc(sizeof(DWORD)+100*sizeof(PVOID));

    Here is how to do it correctly:

    malloc(FIELD_OFFSET(struct xx, Pointers) +100*sizeof(PVOID));
  • Use the TYPE_ALIGNMENT macro.

    The TYPE_ALIGNMENT macro returns the alignment requirement for a given data type on the current platform. For example:

    TYPE_ALIGNMENT(KFLOATING_SAVE) == 4 on x86, 8 on IA-64
TYPE_ALIGNMENT(UCHAR) == 1 everywhere

    As an example, code such as this:

    ProbeForRead(UserBuffer, UserBufferLength, sizeof(ULONG));

    becomes more portable when changed to:

    ProbeForRead(UserBuffer, UserBufferLength, TYPE_ALIGNMENT(ULONG));
  • Watch for data type changes in public kernel structures.

    For example, the Information field in the IO_STATUS_BLOCK structure is now of type ULONG_PTR.

  • Be cautious when using structure packing directives.

    On 64-bit Windows, if a data structure is misaligned, routines that manipulate the structure, such as RtlCopyMemory and memcpy, will not fault. Instead, they will raise an exception. For example:

    #pragma pack (1) /* also set by /Zp switch */
struct Buffer {
    ULONG size;
    void *ptr;
};

void SetPointer(void *p) {
    struct Buffer s;
    s.ptr = p;  /* will cause alignment fault */
...
}

    You could use the UNALIGNED macro to fix this:

    void SetPointer(void *p) {
    struct Buffer s;
    *(UNALIGNED void *)&s.ptr = p;
}

    Unfortunately, using the UNALIGNED macro is very expensive on IA64 processors. A better solution is to put 64-bit values and pointers at the beginning of the structure.

Note If possible, avoid using different packing levels in the same header file.

Additional Information

  • Supporting 32-Bit I/O in Your 64-Bit Driver
  • "Getting Ready for 64-bit Windows" user-mode application porting guide in the Platform SDK documentation
  • Other information available at http://www.microsoft.com/windows2000/guide/platform/strategic/64bit.asp


Supporting 32-Bit I/O in Your 64-Bit Driver

Windows on Windows (WOW64) enables Microsoft® Win32® user-mode applications to run on 64-bit Windows®. It does this by intercepting Win32 function calls and converting parameters from pointer-precision types to fixed-precision types as appropriate before making the transition to the 64-bit kernel. This conversion, which is called thunking, is done automatically for all Win32 functions, with one important exception: the data buffers passed to DeviceIoControl. The contents of these buffers, which are pointed to by the InputBuffer and OutputBuffer parameters, are not thunked, because their structure is driver-specific.

Note Although the buffer contents are not thunked, the buffer pointers are converted into 64-bit pointers.

User-mode applications call DeviceIoControl to send an I/O request directly to a specified kernel-mode driver. This request contains an I/O control code (IOCTL) or file system control code (FSCTL) and pointers to input and output data buffers. The format of these data buffers is specific to the IOCTL or FSCTL, which in turn is defined by the kernel-mode driver. Because the buffer format is arbitrary, and because it is known to the driver and not WOW64, the task of thunking the data is left to the driver.

Your 64-bit driver must support 32-bit I/O if all of the following are true:

  • The driver exposes an IOCTL (or FSCTL) to user-mode applications.
  • At least one of the I/O buffers used by the IOCTL contains pointer-precision data types.
  • Your IOCTL code cannot easily be rewritten to eliminate the use of pointer-precision buffer data types.


Why Thunking Is Necessary

Kernel-mode drivers must validate the size of any I/O buffer passed in from a user-mode application. If a 32-bit application passes a buffer containing pointer-precision data types to a 64-bit driver, and no thunking takes place, the driver will expect the buffer to be larger than it actually is. This is because pointer precision is 32 bits on 32-bit Microsoft® Windows® and 64 bits on 64-bit Windows. For example, consider the following structure definition:

typedef struct _DRIVER_DATA
{
    HANDLE           Event;
    UNICODE_STRING   ObjectName;
} DRIVER_DATA;

On 32-bit Windows, the size of the DRIVER_DATA structure is 12 bytes.

HANDLE Event | UNICODE_STRING ObjectName
 | USHORT Length | USHORT Maximum- Length | PWSTR Buffer
32 bits (4 bytes) | 16 bits (2 bytes) | 16 bits (2 bytes) | 32 bits (4 bytes)

On 64-bit Windows, the size of the DRIVER_DATA structure is 24 bytes. (The 4 bytes of structure padding are required so that the Buffer member can be aligned on an 8-byte boundary.)

HANDLE Event | UNICODE_STRING ObjectName
 | USHORT Length | USHORT Maximum- Length | Empty (Structure Padding) | PWSTR Buffer
64 bits (8 bytes) | 16 bits (2 bytes) | 16 bits (2 bytes) | 32 bits (4 bytes) | 64 bits (8 bytes)

If a 64-bit driver receives 12 bytes of DRIVER_DATA when it expected 24 bytes, the size validation will fail. To prevent this, the driver must detect whether a DRIVER_DATA structure was sent by a 32-bit application, and if so, thunk it appropriately before performing the validation.

For example, a thunked version of the above DRIVER_DATA structure could be defined as follows:

typedef struct _DRIVER_DATA32
{
    VOID *POINTER_32   Event;
    UNICODE_STRING32   ObjectName;
} DRIVER_DATA32;

Because it contains only fixed-precision data types, this new structure is the same size on 32-bit Windows and 64-bit Windows.

POINTER_32 Event | UNICODE_STRING32 ObjectName
 | USHORT Length | USHORT Maximum- Length | ULONG Buffer
32 bits (4 bytes) | 16 bits (2 bytes) | 16 bits (2 bytes) | 32 bits (4 bytes)


Which Data Types Need Thunking

The following table lists common data types that require thunking, along with their thunked equivalents.

Pointer-Precision Data Type (before thunking) | Equivalent 32-Bit Fixed-Precision Data Type (after thunking)
HANDLE | VOID * POINTER_32
INT_PTR | INT32
LONG_PTR | LONG32
LPARAM | LONG32
PCHAR | Char * POINTER_32
PDWORD | DWORD * POINTER_32
PHANDLE | VOID ** POINTER_32
PULONG | ULONG * POINTER_32
PVOID | VOID * POINTER_32
PWORD | WORD * POINTER_32
SIZE_T | INT32
ULONG_PTR | ULONG32
UNICODE_STRING | UNICODE_STRING32


How Drivers Identify 32-Bit Callers

There are two ways for drivers to determine whether the originator of an IOCTL or FSCTL request is a 32-bit or 64-bit application. The first is for the application to identify itself. The second is for the driver to determine on its own whether the application is 32-bit or 64-bit.

The first technique involves defining a "64Bit" field in the IOCTL or FSCTL control code. This field contains a single bit, which is set only for 64-bit callers. Thus 64-bit callers identify themselves by using a separate set of 64-bit control codes in which this bit is set. 32-bit callers use a similar set of control codes in which this bit is not set.

The second technique permits 32- and 64-bit applications to continue using the same IOCTL or FSCTL codes. Instead, the driver determines whether the user-mode process is 32- or 64-bit by calling IoIs32bitProcess.

The first technique is more efficient, because the driver checks a bit flag instead of calling a kernel-mode routine. However, the second technique requires no changes to user-mode code. Which technique you should use depends on the requirements of your driver and the applications that send I/O requests to it.


Technique 1: Defining a "64Bit" Field

The "64Bit" field is defined in the IOCTL or FSCTL control code. This field contains a bit flag that is always set for 64-bit callers, but is always clear for 32-bit. Which bit in the control code is chosen as the "64Bit" field is driver-specific, but it must be a bit that is never set for 32-bit callers. A good choice for most drivers is the most significant bit (MSB) in the Function field.

For example, the IOCTL (FSCTL) control codes used in 32-bit drivers contain four bit fields:

Device Type | Access | Function | Method
16 bits | 2 bits | 12 bits | 2 bits

As long as none of the existing driver-defined control codes set the MSB in the Function field, these control codes can continue to be used by 32-bit user-mode applications.

To accommodate 64-bit callers, the driver defines a Function field that is shorter by one bit. This bit is redefined as a "64Bit" field:

Device Type | Access | 64Bit | Function | Method
16 bits | 2 bits | 1 bit | 11 bits | 2 bits

The following code example shows how to define a "64Bit" field in a driver header file:

#define REGISTER_FUNCTION 0     // Define the IOCTL function code

#ifdef  _WIN64
#define CLIENT_64BIT   0x800
#define REGISTER_FUNCTION 0
#define IOCTL_REGISTER   CTL_CODE(FILE_DEVICE_UNKNOWN, \
  CLIENT_64BIT|REGISTER_FUNCTION, METHOD_BUFFERED, FILE_ANY_ACCESS)
#else
#define IOCTL_REGISTER   CTL_CODE(FILE_DEVICE_UNKNOWN, \
  REGISTER_FUNCTION, METHOD_BUFFERED, FILE_ANY_ACCESS)
#endif

typedef struct _IOCTL_PARAMETERS {
    PVOID   Addr;
    SIZE_T  Length;
    HANDLE  Handle;
} IOCTL_PARAMETERS, *PIOCTL_PARAMETERS;


Technique 2: Using IoIs32bitProcess

In cases where it is not practical to define separate IOCTL or FSCTL control codes for I/O requests from 32-bit and 64-bit applications, it is left to the driver to determine which type of application sent the I/O request. The 64-bit version of Microsoft® Windows® introduces a new kernel-mode routine, IoIs32bitProcess, that detects whether the current I/O request originated in a 32-bit user-mode process. Its prototype is:

BOOLEAN
  IoIs32bitProcess(
  IN PIRP Irp OPTIONAL   //NULL for fast I/O call, IRP otherwise
  );

IoIs32bitProcess returns TRUE if the originator of the current I/O request is a 32-bit user-mode application.

The following code sample shows how to use IoIs32bitProcess:

typedef struct _IOCTL_PARAMETERS {
    PVOID   Addr;
    SIZE_T  Length;
    HANDLE  Handle;
} IOCTL_PARAMETERS, *PIOCTL_PARAMETERS;

typedef struct _IOCTL_PARAMETERS_32 {
    VOID*POINTER_32  Addr;
    INT32            Length;
    VOID*POINTER_32  Handle;
} IOCTL_PARAMETERS_32, *PIOCTL_PARAMETERS_32;
.
.
.
if (IoIs32bitProcess(Irp)) { /* 32-bit process IOCTL */
  params32 = (PIOCTL_PARAMETERS_32)
             (Irp->AssociatedIrp.SystemBuffer);
  if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
      sizeof(IOCTL_PARAMETERS_32)) {
    status = STATUS_INVALID_PARAMETER;
  } else {
    LocalParam.Addr = params32->Addr;
    LocalParam.Handle = params32->Handle;
    LocalParam.Length = params32->Length;
    /* Handle the IOCTL here */
    status = STATUS_SUCCESS;
    Irp->IoStatus.Information = 0;
  }
} else { /* 64-bit process IOCTL */
  params = (PIOCTL_PARAMETERS)
           (Irp->AssociatedIrp.SystemBuffer);
  if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
      sizeof(IOCTL_PARAMETERS)) {
    status = STATUS_INVALID_PARAMETER;
  } else {
    RtlCopyMemory(&LocalParam,
                  params,
                  sizeof(IOCTL_PARAMETERS));
     /* Handle the ioctl here */
     status = STATUS_SUCCESS;
  }
  Irp->IoStatus.Information = 0;
}


Extended Example: Defining a "64Bit" Field

The following example shows how to modify a 32-bit driver for 64-bit by adding a "64Bit" field to the IOCTL control code. Note that this example shows only the portions of the driver code that need to be modified.

Original Driver Code

The following is the 32-bit version of the driver:

Header File

#define REGISTER_FUNCTION 0     // Define the IOCTL function code

#define IOCTL_REGISTER   CTL_CODE(FILE_DEVICE_UNKNOWN, \
  REGISTER_FUNCTION, METHOD_BUFFERED, FILE_ANY_ACCESS)

typedef struct _IOCTL_PARAMETERS {
    PVOID   Addr;
    SIZE_T  Length;
    HANDLE  Handle;
} IOCTL_PARAMETERS, *PIOCTL_PARAMETERS;

DeviceControl Dispatch Routine

NTSTATUS
TestdrvDeviceControl(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
{
    PIO_STACK_LOCATION irpSp;
    NTSTATUS status;
    PIOCTL_PARAMETERS params;
    IOCTL_PARAMETERS  LocalParam;
    PIOCTL_PARAMETERS_32 params32;

    //
    //Get a pointer to the current parameters for this request. The
    //information is contained in the current stack location.
    //
    irpSp = IoGetCurrentIrpStackLocation(Irp);
    //
    // Case on the device control code
    //
    switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
    case IOCTL_REGISTER:
        params = (PIOCTL_PARAMETERS)
            (Irp->AssociatedIrp.SystemBuffer);
        if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
               sizeof(IOCTL_PARAMETERS)) {
            status = STATUS_INVALID_PARAMETER;
        } else {
            RtlCopyMemory(&LocalParam,  params,
              sizeof(IOCTL_PARAMETERS));
            /*  Handle the ioctl here */
            status = STATUS_SUCCESS;
        }
        Irp->IoStatus.Information = 0;
            break;
    //
    // Unrecognized device control request
    //
    default:
        Irp->IoStatus.Information = 0;
        status = STATUS_INVALID_PARAMETER;
        break;
    }
    //
    // If status is pending, mark the IRP pending and start the
    // request in a cancellable state. Otherwise, complete the IRP.
    //
    Irp->IoStatus.Status = status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);
    return(status);
}

Driver Code With Thunking Support

The following is the 64-bit version of the driver:

Header File

#define REGISTER_FUNCTION 0     // Define the IOCTL function code

#ifdef  _WIN64
#define CLIENT_64BIT   0x800
#define REGISTER_FUNCTION 0
#define IOCTL_REGISTER   CTL_CODE(FILE_DEVICE_UNKNOWN, \
  CLIENT_64BIT|REGISTER_FUNCTION, METHOD_BUFFERED, FILE_ANY_ACCESS)
#else
#define IOCTL_REGISTER   CTL_CODE(FILE_DEVICE_UNKNOWN, \
  REGISTER_FUNCTION, METHOD_BUFFERED, FILE_ANY_ACCESS)
#endif

typedef struct _IOCTL_PARAMETERS {
    PVOID   Addr;
    SIZE_T  Length;
    HANDLE  Handle;
} IOCTL_PARAMETERS, *PIOCTL_PARAMETERS;

DeviceControl Dispatch Routine

#ifdef _WIN64
#define IOCTL_REGISTER_32   CTL_CODE(FILE_DEVICE_UNKNOWN, \
  REGISTER_FUNCTION, METHOD_BUFFERED, FILE_ANY_ACCESS)
#endif
.
.
.
#ifdef _WIN64
typedef struct _IOCTL_PARAMETERS_32 {
    VOID*POINTER_32  Addr;
    INT32            Length;
    VOID*POINTER_32  Handle;
} IOCTL_PARAMETERS_32, *PIOCTL_PARAMETERS_32;
#endif
.
.
.
NTSTATUS
TestdrvDeviceControl(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
{
    PIO_STACK_LOCATION irpSp;
    NTSTATUS status;
    PIOCTL_PARAMETERS params;
    IOCTL_PARAMETERS  LocalParam;
    PIOCTL_PARAMETERS_32 params32;

    //
    //Get a pointer to the current parameters for this request. The
    //information is contained in the current stack location.
    //
    irpSp = IoGetCurrentIrpStackLocation(Irp);
    //
    // Case on the device control code
    //
    switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
#ifdef  _WIN64
    case IOCTL_REGISTER_32:
        params32 = (PIOCTL_PARAMETERS_32)
          (Irp->AssociatedIrp.SystemBuffer);
        if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
            sizeof(IOCTL_PARAMETERS_32)) {
            status = STATUS_INVALID_PARAMETER;
        } else {
            LocalParam.Addr = params32->Addr;
            LocalParam.Handle = params32->Handle;
            LocalParam.Length = params32->Length;
            /* Handle the ioctl here */
            status = STATUS_SUCCESS;
            Irp->IoStatus.Information = 0;
        }
        break;
#endif
    case IOCTL_REGISTER:
        params = (PIOCTL_PARAMETERS)
            (Irp->AssociatedIrp.SystemBuffer);
        if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
            sizeof(IOCTL_PARAMETERS)) {
            status = STATUS_INVALID_PARAMETER;
        } else {
            RtlCopyMemory(&LocalParam, params,
                sizeof(IOCTL_PARAMETERS));
            /* Handle the ioctl here */
            status = STATUS_SUCCESS;
        }
        Irp->IoStatus.Information = 0;
        break;
    //
    // Unrecognized device control request
    //
    default:
        Irp->IoStatus.Information = 0;
        status = STATUS_INVALID_PARAMETER;
        break;
    }
    //
    // If status is pending, mark the IRP pending and start the
    // request in a cancellable state. Otherwise, complete the IRP.
    //
    Irp->IoStatus.Status = status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);
    return(status);
}


Extended Example: Using IoIs32bitProcess

The following example shows how to modify a 32-bit driver for 64-bit by adding a call to IoIs32bitProcess. Note that this example shows only the portions of the driver code that need to be modified.

Original Driver Code

typedef struct _TESTDRV_EVENT_BUFFER {
     HANDLE Handle;
     ULONG Key;
} TESTDRV_EVENT_BUFFER, *PTESTDRV_EVENT_BUFFER;

NTSTATUS
TestdrvFsControl (
    IN PTESTDRV_DEVICE_OBJECT TestdrvDeviceObject,
    IN PIRP Irp
    )
{
.
.
    InputBufferLength =
        IrpSp->Parameters.FileSystemControl.InputBufferLength;

    if (InputBufferLength < sizeof(TESTDRV_EVENT_BUFFER)) {

        DebugTrace(0, Dbg, "System buffer size is too small\n", 0);

        FsRtlCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
        return STATUS_INVALID_PARAMETER;
    }

    Buffer = Irp->AssociatedIrp.SystemBuffer;

    // start using the event buffer
.
.
.
}

Driver Code With Thunking Support

typedef struct _TESTDRV_EVENT_BUFFER {
     HANDLE Handle;
     ULONG Key;
} TESTDRV_EVENT_BUFFER, *PTESTDRV_EVENT_BUFFER;

//
// Define a 32-bit thunking structure
//

#if defined(_WIN64)
typedef struct _TESTDRV_EVENT_BUFFER32 {
     UINT32 Handle;
     ULONG Key;
} TESTDRV_EVENT_BUFFER32, *PTESTDRV_EVENT_BUFFER32;
#endif

//
// Intercept the input buffer as a 32-bit structure and thunk it to
//    64-bit
NTSTATUS
TestdrvFsControl (
    IN PTESTDRV_DEVICE_OBJECT TestdrvDeviceObject,
    IN PIRP Irp
    )
{
    TESTDRV_EVENT_BUFFER LocalBuffer;
.
.
    InputBufferLength  =
             IrpSp->Parameters.FileSystemControl.InputBufferLength;

#if defined(_WIN64)
    if (IoIs32bitProcess(Irp)) {
        PTESTDRV_EVENT_BUFFER32 Buffer32;

        if (InputBufferLength < sizeof(TESTDRV_EVENT_BUFFER32)) {
            DebugTrace(0, Dbg, "Irp32 : System buffer size is too
                        small\n", 0);

            FsRtlCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
            return STATUS_INVALID_PARAMETER;
        }
        Buffer = &LocalBuffer;
        Buffer32 = Irp->AssociatedIrp.SystemBuffer;
        Buffer->Handle = (HANDLE)Buffer32->Handle;
        Buffer->Key = Buffer32->Key;
    }
    else {
#endif
    if (InputBufferLength < sizeof(TESTDRV_EVENT_BUFFER)) {

        DebugTrace(0, Dbg, "System buffer size is too small\n", 0);

        FsRtlCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
        return STATUS_INVALID_PARAMETER;
    }

    Buffer = Irp->AssociatedIrp.SystemBuffer;
#if defined(_WIN64)
    }
#endif

    // start using the Event Buffer
.
.
.

}


Avoiding Misalignment of Fixed-Precision Data Types

Unfortunately, it is possible for a data type to have the same size, but different alignment requirements, for 32-bit and 64-bit programming. Thus not all IOCTL/FSCTL buffer misalignment problems can be avoided by changing pointer-precision data types to fixed-precision types. This means that kernel-mode driver IOCTLs and FSCTLs that pass buffers containing certain fixed-precision data types (or pointers to them) may also need to be thunked.

Which Data Types Are Affected

The problem affects fixed-precision data types that are themselves structures. This is because the rules for determining alignment requirements for structures are platform-specific.

For example, __int64, LARGE_INTEGER, and KFLOATING_SAVE must be aligned on a 4-byte boundary on x86 platforms. However, on IA64 machines, they must be aligned on an 8-byte boundary.

To determine the alignment requirement for a given data type on a particular platform, use the TYPE_ALIGNMENT macro on that platform.

How To Fix the Problem

In the following example, the IOCTL is a METHOD_NEITHER IOCTL, so the Irp->UserBuffer pointer is passed directly from the user-mode application to the kernel-mode driver. No validation is performed on buffers used in IOCTLs and FSCTLs. Thus a call to ProbeForRead or ProbeForWrite is required before the buffer pointer can be safely dereferenced.

Assuming that the 32-bit application has passed a valid value for Irp->UserBuffer, the LARGE_INTEGER structure pointed to by p->DeviceTime will be aligned on a 4-byte boundary. ProbeForRead checks this alignment against the value passed in its Alignment parameter, which in this case is TYPE_ALIGNMENT (LARGE_INTEGER). On x86 platforms, this macro expression returns 4 (bytes). However, on IA64 machines, it returns 8, causing ProbeForRead to raise a STATUS_DATATYPE_MISALIGNMENT exception.

Note Removing the ProbeForRead call does not fix the problem, but only makes it harder to diagnose.

typedef struct _IOCTL_PARAMETERS2 {
    LARGE_INTEGER DeviceTime;
} IOCTL_PARAMETERS2, *PIOCTL_PARAMETERS2;

#define SETTIME_FUNCTION 1
#define IOCTL_SETTIME CTL_CODE(FILE_DEVICE_UNKNOWN, \
            SETTIME_FUNCTION, METHOD_NEITHER, FILE_ANY_ACCESS)
.
.
.
case IOCTL_SETTIME:
    PIOCTL_PARAMETERS2 p = (PIOCTL_PARAMETERS2)Irp->UserBuffer;

    try {
        if (Irp->RequestorMode != KernelMode) {
            ProbeForRead ( p->DeviceTime,
                      sizeof( LARGE_INTEGER ),
                      TYPE_ALIGNMENT( LARGE_INTEGER ));
    }
    status = DoSomeWork(p->DeviceTime);

 } except( EXCEPTION_EXECUTE_HANDLER ) {

The following sections tell how to fix the problem described above. Note that all code snippets have been edited for brevity.

Solution 1: Copy the Buffer

The safest way to avoid misalignment problems is to make a copy of the buffer before accessing its contents, as in the following example.

case IOCTL_SETTIME: {
    PIOCTL_PARAMETERS2 p = (PIOCTL_PARAMETERS2)Irp->UserBuffer;
#if _WIN64
    IOCTL_PARAMETERS2 LocalParams2;

    RtlCopyMemory(&LocalParams2, p, sizeof(IOCTL_PARAMETERS2));
    p = &LocalParams2;
#endif

    status = DoSomeWork(p->DeviceTime);
    break;
}

This solution can be optimized for better performance by first checking whether the buffer contents are correctly aligned. If so, the buffer can be used as is. Otherwise, the driver makes a copy of the buffer.

case IOCTL_SETTIME: {
    PIOCTL_PARAMETERS2 p = (PIOCTL_PARAMETERS2)Irp->UserBuffer;
#if _WIN64
    IOCTL_PARAMETERS2 LocalParams2;

    if ( (ULONG_PTR)p & (TYPE_ALIGNMENT(IOCTL_PARAMETERS2)-1)) {
        // The buffer contents are not correctly aligned for this
        // platform, so copy them into a properly aligned local
        // buffer.
        RtlCopyMemory(&LocalParams2, p, sizeof(IOCTL_PARAMETERS2));
           p = &LocalParams2;
    }
#endif

    status = DoSomeWork(p->DeviceTime);
    break;
}

Solution 2: Use the UNALIGNED Macro

The UNALIGNED macro tells the C compiler to generate code that can access the DeviceTime field without taking an alignment fault. Note that using this macro on IA64 platforms is likely to make your driver significantly larger and slower.

typedef struct _IOCTL_PARAMETERS2 {
    LARGE_INTEGER DeviceTime;
} IOCTL_PARAMETERS2;
typedef IOCTL_PARAMETERS2 UNALIGNED *PIOCTL_PARAMETERS2;

Pointers Are Also Affected

The misalignment problem described earlier can also occur in buffered I/O requests. In the following example, the IOCTL buffer contains an embedded pointer to a LARGE_INTEGER structure.

typedef struct _IOCTL_PARAMETERS3 {
    LARGE_INTEGER *pDeviceCount;
} IOCTL_PARAMETERS3, *PIOCTL_PARAMETERS3;

#define COUNT_FUNCTION 1
#define IOCTL_GETCOUNT CTL_CODE(FILE_DEVICE_UNKNOWN, \
            COUNT_FUNCTION, METHOD_BUFFERED, FILE_ANY_ACCESS)

Like the METHOD_NEITHER IOCTL and FSCTL buffer pointers described earlier, pointers embedded in buffered I/O requests are also passed directly from the user-mode application to the kernel-mode driver. No validation is performed on these pointers. Thus a call to ProbeForRead or ProbeForWrite, enclosed in a try/except block, is required before the embedded pointer can be safely dereferenced.

As in the earlier example, assuming that the 32-bit application has passed a valid value for pDeviceCount, the LARGE_INTEGER structure pointed to by pDeviceCount will be aligned on a 4-byte boundary. ProbeForRead and ProbeForWrite check this alignment against the value of the Alignment parameter, which in this case is TYPE_ALIGNMENT (LARGE_INTEGER). On x86 platforms, this macro expression returns 4 (bytes). However, on IA64 machines, it returns 8, causing ProbeForRead or ProbeForWrite to raise a STATUS_DATATYPE_MISALIGNMENT exception.

This problem can be fixed either by making a properly aligned copy of the LARGE_INTEGER structure, as in Solution 1, or by using the UNALIGNED macro as follows:

typedef struct _IOCTL_PARAMETERS3 {
    LARGE_INTEGER UNALIGNED *pDeviceCount;
} IOCTL_PARAMETERS3, *PIOCTL_PARAMETERS3;


Using GUIDs in Drivers

Drivers and other system components use globally unique identifiers (GUIDs) to identify a variety of items. System components define GUIDs for items such as device setup classes, PnP events, WMI events, and still image events. Driver writers can create GUIDs for items such as device interface classes, custom PnP events, and custom WMI events. Drivers and applications include header files that define the GUIDs that they use.

This section includes the following topics:

Defining and Exporting New GUIDs

Including GUIDs in Driver Code

For information about using GUIDs in user-mode applications, see Platform SDK documentation.


Defining and Exporting New GUIDs

You define a new GUID for an item the driver exports to other system components, drivers, or applications. For example, you define a new GUID for a custom PnP event on one of its devices. To define and export a new GUID, you must do the following:

  1. Choose a symbolic name for the GUID.

    Choose a name that represents the purpose of the GUID. For example, the operating system uses such names as GUID_BUS_TYPE_PCI and PARPORT_WMI_ALLOCATE_FREE_COUNTS_GUID.

  2. Generate a value for the GUID using uuidgen.exe or guidgen.exe.

    These utilities generate a unique, formatted string that represents a 128-bit value. The "-s" switch on uuidgen.exe outputs the GUID formatted as a C structure.

  3. Define the GUID in an appropriate header file.

    Use the DEFINE_GUID macro (defined in guiddef.h) to associate the GUID symbolic name with its value (see Example 1).

    Example 1: Defining GUIDs in a GUID-Only Header File

    :

DEFINE_GUID( GUID_BUS_TYPE_PCMCIA, 0x09343630L, 0xaf9f, 0x11d0,
    0x92,0x9f, 0x00, 0xc0, 0x4f, 0xc3, 0x40, 0xb1 );
DEFINE_GUID( GUID_BUS_TYPE_PCI, 0xc8ebdfb0L, 0xb510, 0x11d0,
    0x80,0xE9, 0x00, 0x00, 0xf8, 0x1e, 0x1b, 0x30 );

:

    If the GUID is defined in a header file that contains statements other than GUID definitions, you must take an extra step to ensure that the GUID is instantiated in drivers that include the header file. The DEFINE_GUID statement must occur outside any #ifdef statements that prevent multiple inclusion. Otherwise, if the header file is included in a precompiled header, the GUID will not be instantiated in drivers that use the header file. See Example 2 for a sample GUID definition in a mixed header file.

    Example 2: Defining GUIDs in a Mixed Header File

    #ifndef _NTDDSER_    // this ex. is from a serial driver .h file
#define _NTDDSER_

:
// put other header file definitions here
:

#endif  // _NTDDSER_

#ifdef DEFINE_GUID   // don't break compiles of drivers that
                     // include this header but don't want the
                     // GUIDs
//
// Put GUID definitions outside of the multiple inclusion
// protection

DEFINE_GUID(GUID_CLASS_COMPORT, 0x86e0d1e0L, 0x8089, 0x11d0, 0x9c,
    0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73);

DEFINE_GUID (GUID_SERENUM_BUS_ENUMERATOR, 0x4D36E978, 0xE325,
    0x11CE, 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18);

:
#endif  // DEFINE_GUID

    Putting a GUID definition outside statements that prevent multiple inclusion does not cause multiple instances of the GUID in a driver because DEFINE_GUID defines the GUID as an EXTERN_C variable. Multiple declarations of an EXTERN variable are allowed as long as the types match.

  4. When creating a GUID for a new device setup class or device interface class, the following rules apply:
    • Do not use a single GUID to identify both a device setup class and a device interface class.
    • When creating a symbolic name to associate with the GUID, use the following convention:

      For device setup classes, use the format GUID_DEVCLASS_xxxx.

      For device interface classes, use the format GUID_DEVINTERFACE_xxxx.


Including GUIDs in Driver Code

To use GUIDs in a kernel-mode driver, you must do two things:

  1. Include the initguid.h header file that redefines the DEFINE_GUID macro.

    The initguid.h header file redefines the DEFINE_GUID macro to instantiate GUIDs (versus just declaring an EXTERN reference). Include this header file in the driver source file where the GUIDs should be instantiated. (User-mode applications include <objbase.h> before including header files containing GUID definitions.)

  2. Include the header file(s) that define the GUIDs.

    After the statement to include initguid.h, you include the header files containing the GUID definitions. A driver might include more than one header file that contains GUID definitions, including system-supplied header files and third-party header files.

The following code excerpt shows the sequence of statements for including GUIDs:

:
// include system headers here such as wdm.h

#include <initguid.h>

// include system and driver-specific header files here that contain
// GUID definitions

:

Put the above statements in one module of the driver; typically the main module. When the above statements are present, the driver refers to a GUID using its symbolic name.


Logging Errors

The NT-based operating system is designed to be both more robust and more "user-friendly" than some PC operating systems with respect to runtime errors. That is, the system is designed to do the following:

  • To continue running without allowing one component (or thread) to corrupt other components' code or data when an error occurs
  • To continue running without sending a flood of cryptic error messages to end users whenever errors occur

Granted that some I/O errors are user-induced. For example, a request to read data from a file on removable media when the user has supplied the wrong diskette, tape, or CD-ROM causes a user-induced I/O error. Such an error can be corrected readily when the user is prompted to supply the appropriate media, as discussed in Supporting Removable Media.

Other I/O errors cannot be readily corrected by the majority of end users. For these kinds of I/O errors, the operating system continues to run without forcing the user to become aware of errors that the user cannot fix immediately. Instead, it provides a system error-logging thread that formats and stores information about I/O errors as entries in a file.

The Win32 event viewer, which reads and displays this error log file, allows users, system administrators, or support technicians to monitor the condition of the hardware in a given machine and replace failing hardware as necessary, to tune the configuration of devices in the machine for better performance, and to debug hardware problems if they occur.


Calling IoAllocateErrorLogEntry

When a driver discovers an I/O error in processing an IRP, it should call IoAllocateErrorLogEntry as follows:

size = sizeof(IO_ERROR_LOG_PACKET) + (n * sizeof(ULONG))
                                   + sizeof(InsertionStrings);
                    // where n depends on how much
                    // DumpData the driver will supply
errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
    deviceExtension->DeviceObject,
                            // target device for current operation
    size);

Error log packets are limited in size. The system-defined limit includes any dump data and insertion strings that the driver supplies with a packet. Drivers can call IoAllocateErrorLogEntry with a specified EntrySize value that is, at most, ERROR_LOG_MAXIMUM_SIZE.

IoAllocateErrorLogEntry returns a pointer to an error log packet. If the returned pointer is NULL, the driver need not log an error. It should simply continue running and assume that, if the same error occurs again, it can be logged at that point.


Filling in an Error Log Packet

The error log packet is defined as follows:

typedef struct _IO_ERROR_LOG_PACKET {
    UCHAR MajorFunctionCode;
    UCHAR RetryCount;
    USHORT DumpDataSize;
    USHORT NumberOfStrings;
    USHORT StringOffset;
    USHORT EventCategory;
    NTSTATUS ErrorCode;
    ULONG UniqueErrorValue;
    NTSTATUS FinalStatus;
    ULONG SequenceNumber;
    ULONG IoControlCode;
    LARGE_INTEGER DeviceOffset;
    ULONG DumpData[1];
} IO_ERROR_LOG_PACKET, *PIO_ERROR_LOG_PACKET;

The driver should fill in an error log packet with the following data:

MajorFunctionCode
Indicates the IRP_MJ_XXX from the driver's I/O stack location in the current IRP.
RetryCount
Indicates how many times the driver has retried the operation and encountered this error.

RetryCount is a zero-based value. That is, the driver should set it to zero when an error is first encountered for the current IRP.

DumpDataSize
Indicates the size in bytes required for any DumpData the driver will set in the packet.

The specified value should be an integral multiple of sizeof(ULONG).

NumberOfStrings
Indicates how many insertion strings the driver will supply with this packet. Drivers set this value to zero for errors that need no insertion strings.

The error-logging thread can use these driver-supplied, zero-terminated Unicode strings to fill in messages written into the Win32 event log, which can be examined using the Win32 event viewer. The I/O Manager assumes that the initial insertion string, if any, is either the name of the driver or of the device on which the error occurred.

Insertion strings provided by a driver should be language independent. Drivers that log errors and use insertion strings should use strings read from the registry or use names which are language independent or are the same in any language, for example, file names.

In most cases, device and intermediate drivers can simply log I/O errors without supplying insertion strings for a higher-level event-logging component and/or without setting up a driver-specific event-logging component. Of the system-supplied drivers, only network device drivers currently supply insertion strings in error log packets.

StringOffset
Indicates the offset, immediately following the DumpData, at which any driver-supplied insertion string data begins.

If a driver supplies this data, each string must be a zero-terminated Unicode string.

EventCategory
For drivers that install themselves in the registry as event-logging components, this is a driver-defined value that was specified in the driver's message file for categories.
ErrorCode
Indicates the type of error.

This is a system-defined or driver-defined constant; see Defining Error Codes.

UniqueErrorValue
Indicates where the error was detected in the driver.
FinalStatus
Indicates the value set in the I/O status block of the IRP when it was completed or the STATUS_XXX returned by a support routine the driver called.
SequenceNumber
Indicates a driver-assigned sequence number for the current IRP, which should be constant for the life of a given request.
IoControlCode
Indicates the I/O control code from the driver's I/O stack location in the current IRP if the MajorFunctionCode is IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL. Otherwise, this value should be zero.

For more information about I/O control codes and device I/O control requests, see IRP Function Codes and IOCTLs.

DeviceOffset
Indicates the offset into the device where the error occurred.
DumpData
Can be used to store driver-specific data, such as register values or any other information useful in identifying the cause of the error.

Any driver-supplied insertion strings must be supplied immediately following the dump data, starting at StringOffset.


Setting NTSTATUS Values in Error Log Packets

Both the ErrorCode and FinalStatus members of the error log packet are of type NTSTATUS. The following figure shows the layout for NTSTATUS values.

NTSTATUS Layout

Drivers must set an NTSTATUS-type IO_ERR_XXX value for ErrorCode and a STATUS_XXX value for FinalStatus in each error log packet.

The system supplies a set of public IO_ERR_XXX constants for setting the ErrorCode in an error log packet. For example, drivers can use the following system-defined constants:

IO_ERR_RETRY_SUCCEEDED
IO_ERR_INSUFFICIENT_RESOURCES
IO_ERR_CONFIGURATION_ERROR
IO_ERR_INCORRECT_IRQL
IO_ERR_INVALID_IOBASE
IO_ERR_DRIVER_ERROR
IO_ERR_PARITY
    :     :
IO_ERR_OVERRUN_ERROR
IO_ERR_TIMEOUT
IO_ERR_CONTROLLER_ERROR
IO_ERR_INTERNAL_ERROR

The system also supplies a set of public STATUS_XXX values that drivers can use to set FinalStatus in error log packets and can return from their standard driver routines for NTSTATUS. For example, drivers can return the following system-defined constants for NTSTATUS from their standard driver routines, can set any of the following in the I/O status block of IRPs, and can set some of the following for FinalStatus in error log packets:

STATUS_SUCCESS
STATUS_DEVICE_CONFIGURATION_ERROR
STATUS_DRIVER_INTERNAL_ERROR
STATUS_INVALID_DEVICE_STATE
STATUS_IO_DEVICE_ERROR
    :     :
STATUS_DEVICE_BUSY
STATUS_DEVICE_DOES_NOT_EXIST
STATUS_ADAPTER_HARDWARE_ERROR

Public IO_ERR_XXX and STATUS_XXX constants are system resources. Each STATUS_XXX is mapped to a corresponding Win32 constant by the system. Because they are built into the operating system, public IO_ERR_XXX and STATUS_XXX constants can be added to the system only with the cooperation of Microsoft Corporation.


Calling IoWriteErrorLogEntry

When a driver has filled in the data for the packet returned by IoAllocateErrorLogEntry, it must call IoWriteErrorLogEntry so that the error-logging thread can write its entry in the error log file.

Whenever possible, a driver should log an error, and fail the IRP if necessary, but continue to run upon encountering unusual or unexpected I/O errors.

A retail driver should never call KeBugCheckEx (nor KeBugCheck) to bring down the system. However, KeBugCheckEx can be used for debugging under-development drivers.


Defining Error Codes

You can create driver-specific private IO_ERR_XXX codes of type NTSTATUS within the driver's xxxlog.mc resource file.

The NTSTATUS Facility field, shown in the NTSTATUS Layout figure, for such an error must be set to FACILITY_IO_ERROR_CODE. You must supply a Sev value and a unique Code value for each new IO_ERR_XXX. The driver also must set the C bit in its new IO_ERR_XXX.

The Sev field shown in the NTSTATUS Layout figure indicates the severity code, which must be one of the following system-defined values:

STATUS_SEVERITY_SUCCESS
Indicates STATUS_SUCCESS was set for FinalStatus, and a value such as IO_ERR_RETRY_SUCCEEDED was set for an ErrorCode value in error log packets.

While STATUS_PENDING also belongs to the STATUS_SEVERITY_SUCCESS category, drivers would not log an error on a pending IRP.

STATUS_SEVERITY_INFORMATIONAL
Indicates an informational NTSTATUS value, such as STATUS_SERIAL_MORE_WRITES.
STATUS_SEVERITY_WARNING
Indicates a warning NTSTATUS value, such as STATUS_DEVICE_PAPER_EMPTY.
STATUS_SEVERITY_ERROR
Indicates an error NTSTATUS value, such as STATUS_INSUFFICIENT_RESOURCES for a FinalStatus value or IO_ERR_CONFIGURATION_ERROR for an ErrorCode value in error log packets.

Most public IO_ERR_XXX constants belong to the STATUS_SEVERITY_ERROR category.

To make a set of driver-defined errors visible to system administrators or end users through the Win32 event viewer, a driver must set itself up as an error-logging component in the registry.


Defining Private NTSTATUS Constants

A new pair of drivers (such as class/port drivers or video display/miniport) can define driver-specific STATUS_XXX values to communicate information about privately defined IRP_MJ_INTERNAL_DEVICE_CONTROL requests from the lower to the higher driver of the pair.

The class driver must map any private STATUS_XXX value to a system-defined NTSTATUS value when it completes an IRP if an existing higher-level driver's IoCompletion routine might be called for that IRP.

For paired display and video miniport drivers, the video port driver does the mapping between public STATUS_XXX values and the Win32-defined constants returned by video miniport drivers. For more information, see video miniport drivers.

A driver that defines private STATUS_XXX values for a set of IRP_MJ_INTERNAL_DEVICE_CONTROL requests must do the following:

  • Set the Facility field, shown in the NTSTATUS Layout figure, to an appropriate driver-defined constant that identifies the type of device.
  • Set the customer code flag, labelled C in the NTSTATUS Layout figure.
  • Set the Sev field with an appropriate value; see Defining Error Codes.


Supporting Removable Media

File systems and removable-media device drivers share the responsibility for ensuring that the correct media is mounted when a file is opened on a removable-media device and that the correct media remains mounted during operations that access the media. Any intermediate driver layered between a file system and a removable-media device driver also shares this responsibility.

Drivers that work with removable-media devices therefore should be capable of doing one or more of the following:

Responding to check-verify requests from the file system

Notifying the file system of possible media changes

Checking Flags in the Device Object

Setting up IRPs in intermediate drivers


Responding to Check-Verify Requests from the File System

At its discretion, the file system can send an IRP to the device driver's Dispatch entry point for IRP_MJ_DEVICE_CONTROL requests with Parameters.DeviceIoControl.IoControlCode in the I/O stack location set to the following:

IOCTL_XXX_CHECK_VERIFY
where XXX is the type of device, such as DISK, TAPE, or CDROM.

The type DISK includes both unpartitionable (floppy) and partitionable removable-media devices.

If the underlying device driver determines that the media has not changed, the driver should complete the IRP, returning the IoStatus block with the following values:

Status | set to STATUS_SUCCESS
Information | set to zero

In addition, if the device type is DISK or CDROM and the caller specified an output buffer, the driver returns the media change count in the buffer at
Irp->AssociatedSystemBuffer and sets IoStatus.Information to sizeof(ULONG). By returning this count, the driver gives the caller an opportunity to determine whether the media has changed from its perspective.

If the underlying device driver determines that the media has changed, it takes a different action depending on whether the volume is mounted. If the volume is mounted (the VPB_MOUNTED flag is set in the VPB), the driver should do the following:

  1. Set the Flags in the DeviceObject by ORing Flags with DO_VERIFY_VOLUME.
  2. Set the IoStatus block in the IRP to the following:
    • Status set to STATUS_VERIFY_REQUIRED
    • Information set to zero
  3. Call IoCompleteRequest with the input IRP.

If the volume is not mounted, the driver must not set the DO_VERIFY_VOLUME bit. The driver should set IoStatus.Status to STATUS_IO_DEVICE_ERROR, set IoStatus.Information to zero, and call IoCompleteRequest with the IRP.


Notifying the File System of Possible Media Changes

A removable-media device driver must ensure that the media is not changed for the device represented by the DeviceObject (input to every driver routine that is sent an IRP) whenever the driver processes an IRP that requests a transfer to/from the media or a device I/O control operation that affects the media. The best possible time to check for changed media is just after the transition from a no-media-present state to a media-present state if the physical device always notifies the driver about these state changes.

If its physical device indicates that the state of the media might have changed before the driver begins an I/O operation or during an operation, the driver must do the following:

  1. Ensure that the volume is mounted by checking the VPB_MOUNTED flag in the VPB. (If the volume is not mounted, the driver must not set the DO_VERIFY_VOLUME bit. The driver should set IoStatus.Status to STATUS_IO_DEVICE_ERROR, set IoStatus.Information to zero, and call IoCompleteRequest with the IRP.)
  2. Set the Flags in the DeviceObject by ORing Flags with DO_VERIFY_VOLUME.
  3. Set the IoStatus block in the IRP to the following:
    • Status set to STATUS_VERIFY_REQUIRED
    • Information set to zero
  4. Before completing any IRP with an IoStatus block in which the Status field is not set to STATUS_SUCCESS, the driver must call IoIsErrorUserInduced, which returns a Boolean TRUE for any of the following Status values:

    STATUS_VERIFY_REQUIRED
    STATUS_NO_MEDIA_IN_DEVICE
    STATUS_WRONG_VOLUME
    STATUS_UNRECOGNIZED_MEDIA
    STATUS_MEDIA_WRITE_PROTECTED
    STATUS_IO_TIMEOUT
    STATUS_DEVICE_NOT_READY

    If IoIsErrorUserInduced returns TRUE, the driver must call IoSetHardErrorOrVerifyDevice so the FSD can send a popup to the user, who can then supply the correct media, decide to retry the original request, or decide to cancel the requested operation.


Checking Flags in the Device Object

For each IRP requesting an I/O operation to/from removable media, a removable-media device driver must determine whether DO_VERIFY_VOLUME is already set in its DeviceObject->Flags. If this value is set, the driver must do the following:

  • For IRP_MJ_READ, IRP_MJ_WRITE, and IRP_MJ_DEVICE_CONTROL requests, check whether SL_OVERRIDE_VERIFY_VOLUME is set in the Flags member of the driver's IO_STACK_LOCATION structure. If it is, continue the requested operation.

    Device control requests that return information about the logical structure of the underlying media have SL_OVERRIDE_VERIFY_VOLUME set in the I/O stack location's Flags member when an IFS mounts or remounts a removable-media volume.

  • Otherwise, the driver must refuse to carry out I/O requests for the corresponding drive, device, or partition while DO_VERIFY_VOLUME is set in its DeviceObject->Flags. A removable media driver must fail IRPs sent to the corresponding device as described in the preceding subsection, repeating both Steps 2 and 3 for each IRP until the FSD clears DO_VERIFY_VOLUME in the removable-media driver's DeviceObject->Flags.

If a removable-media device driver does not fail IRPs when DO_VERIFY_VOLUME is set and SL_OVERRIDE_VERIFY_VOLUME is not set for the preceding transfer requests, the file system can neither maintain the integrity of cached file data nor cause the user to be prompted to remount the media that holds an open file.


Setting up IRPs in Intermediate Drivers

Any intermediate driver layered between a file system driver and a removable-media device driver must set up the next-lower-level driver's I/O stack location in IRPs. From incoming IRP_MJ_READ, IRP_MJ_WRITE, and IRP_MJ_DEVICE_CONTROL requests, the intermediate driver must copy its own I/O stack location Flags into the next-lower-level driver's I/O stack location when it sets up the I/O stack location for the lower driver.

If the intermediate driver allocates new IRPs for lower-level removable-media drivers, it must set up those IRPs as follows:

  • For transfer requests, it must set up the thread context in each driver-allocated IRP from the value at Tail.Overlay.Thread in the original IRP.
  • For IRP_MJ_READ, IRP_MJ_WRITE, and IRP_MJ_DEVICE_CONTROL requests, it must copy the I/O stack location Flags from the original IRP to each driver-allocated IRP.

Otherwise, the file system can neither maintain the integrity of cached file data nor cause the user to be prompted to remount the media that holds an open file.


Driver Reliability Issues

Drivers occupy a significant portion of the total code base executed in kernel mode. Consequently, efforts to improve the reliability of the system must involve this large code base.

The most important tool you can use to ensure the reliability of your driver is the Driver Verifier. The Driver Verifier can check for a variety of common driver problems, including some of those discussed in this section.

This section contains guidelines to help you avoid common driver problems involving the following:

Buffered I/O

Addresses in user space

Direct I/O

Input data and device states

Dispatch routines

Multiprocessor environments

Handling IRPs

Many of the descriptions include code snippets that show typical errors and how to correct them. (The code has been edited for brevity.)


Errors in Buffered I/O

Failing to check the size of buffers is perhaps the most common driver problem. This problem can occur in many contexts, but is particularly troublesome in the cases described below.

Failure to check size of buffers in IOCTLs and FSCTLs

When handling buffered IOCTLs and FSCTLs, a driver should always check the sizes of the input and output buffers to ensure that the buffers can hold all the requested data. If the request specifies FILE_ANY_ACCESS, as most driver IOCTLs and FSCTLs do, any caller that has a handle to the device has access to buffered IOCTL or FSCTL requests for that device, and could read or write data beyond the end of the buffer.

For example, assume that the following code appears in a routine that is called from a Dispatch routine, and that the driver has not validated the buffer sizes passed in the IRP:

   switch (ControlCode)
      …
      …
      case IOCTL_NEW_ADDRESS:{
         tNEW_ADDRESS *pNewAddress =
           pIrp->AssociatedIrp.SystemBuffer;

         pDeviceContext->Addr = ntohl (pNewAddress->Address);

The example does not check the buffer sizes before the assignment statement (highlighted). As a result, the pNewAddress->Address reference in the next line can fault if the input buffer is not big enough to contain a tNEW_ADDRESS structure.

The following code checks the buffer sizes, avoiding the potential problem:

   case IOCTL_NEW_ADDRESS: {
      tNEW_ADDRESS *pNewAddress =
        pIrp->AssociatedIrp.SystemBuffer;

     if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength >=
         sizeof(tNEW_ADDRESS)){
         pDeviceContext->Addr = ntohl (pNewAddress->Address);

Code to handle other buffered I/O, such as WMI requests that use variable size buffers, can have similar errors.

Failure to check buffer sizes for buffered IOCTL and FSCTL output requests

Output buffer problems are similar to input buffer problems. They can easily corrupt pool, and user-mode callers may be unaware that any error has occurred.

In the following example, the driver fails to check the size of the SystemBuffer:

   case IOCTL_GET_INFO: {

       Info = Irp->AssociatedIrp.SystemBuffer;

       Info->NumIF = NumIF;
       …
       …
       Irp->IoStatus.Information =
             NumIF*sizeof(GET_INFO_ITEM)+sizeof(ULONG);
       Irp->IoStatus.Status = ntStatus;
   }

Assuming that the NumIF field of the system buffer specifies the number of input items, this example can set IoStatus.Information to a value larger than the output buffer and thus return too much information to the user-mode code. If an application is improperly coded, and calls with too small an output buffer, the preceding code could corrupt the pool by writing beyond the end of the system buffer.

Keep in mind that the I/O Manager assumes that the value in the Information field is valid. If a caller passes in a valid kernel-mode address for the output buffer and a size of zero bytes, serious problems can occur if the driver does not check the output buffer size and thus find the error.

Returning uninitialized data to the caller in the buffered I/O paths

Drivers should initialize all output buffers with zeros before returning them to the caller. Failing to initialize a buffer can result in garbage data in any uninitialized bytes.

In the following example, a driver returns garbage in unused bytes.

   case IOCTL_GET_NAME: {
…
…
outputBufferLength =
   ioStack->Parameters.DeviceIoControl.OutputBufferLength;
outputBuffer = (PGET_NAME) Irp->AssociatedIrp.SystemBuffer;

if (outputBufferLength >= sizeof(GET_NAME)) {
        length = outputBufferLength - sizeof(GET_NAME);

        ntStatus = IoGetDeviceProperty(
                  DeviceExtension->PhysicalDeviceObject,
                  DevicePropertyDriverKeyName,
                  length,
                  outputBuffer->DriverKeyName,
                  &length);

        outputBuffer->ActualLength =
                  length + sizeof(GET_NAME);

        Irp->IoStatus.Information = outputBufferLength;

     } else {
    ntStatus = STATUS_BUFFER_TOO_SMALL;
     }

Setting IoStatus.Information to the output buffer size causes the whole output buffer to be returned to the caller. The I/O Manager does not initialize the data beyond the size of the input buffer—the input and output buffers overlap for a buffered request. Because the system support routine IoGetDeviceProperty does not write the entire buffer, this IOCTL returns uninitialized data to the caller.

Some drivers use the Information field to return codes that provide extra details about I/O requests. Before doing so, such drivers should check the IRP flags to ensure that IRP_INPUT_OPERATION is not set. When this flag is not set, the IOCTL or FSCTL does not have an output buffer, so the Information field need not supply a buffer size. In this case. the driver can safely use the Information field to return its own code.

Failure to validate variable length buffers, causing integer underflows and overflows

Drivers often accept input buffers with fixed headers and trailing variable length data, as in the following example:

   typedef struct _WAIT_FOR_BUFFER {
      LARGE_INTEGER Timeout;
      ULONG NameLength;
      BOOLEAN TimeoutSpecified;
      WCHAR Name[1];
   } WAIT_FOR_BUFFER, *PWAIT_FOR_BUFFER;

   if (InputBufferLength < sizeof(WAIT_FOR_BUFFER)) {
      IoCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
      Return( STATUS_INVALID_PARAMETER );
   }

   WaitBuffer = Irp->AssociatedIrp.SystemBuffer;

   if (FIELD_OFFSET(WAIT_FOR_BUFFER, Name[0]) +
       WaitBuffer->NameLength > InputBufferLength) {
       IoCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
       return( STATUS_INVALID_PARAMETER );
   }

If WaitBuffer->NameLength is a very large ULONG value, adding it to the offset could cause an integer overflow. Instead, a driver should subtract the offset from the InputBufferLength, and compare the result with WaitBuffer->NameLength, as in the following example:

   if (InputBufferLength < sizeof(WAIT_FOR_BUFFER)) {
      IoCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
      Return( STATUS_INVALID_PARAMETER );
   }

   WaitBuffer = Irp->AssociatedIrp.SystemBuffer;

   if ((InputBufferLength –
       FIELD_OFFSET(WAIT_FOR_BUFFER, Name[0])  >
       WaitBuffer->NameLength) {
      IoCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
      return( STATUS_INVALID_PARAMETER );
   }

The subtraction above cannot underflow because the first if statement ensures that the InputBufferLength is greater than or equal to the size of WAIT_FOR_BUFFER.

The following shows a more complicated overflow problem:

   case IOCTL_SET_VALUE:
      dwSize = sizeof(SET_VALUE);

      if(inputBufferLength < dwSize) {
         ntStatus = STATUS_BUFFER_TOO_SMALL;
         break;
      }

      dwSize = FIELD_OFFSET(SET_VALUE, pInfo[0]) +
              pSetValue->NumEntries * sizeof(SET_VALUE_INFO);

      if(inputBufferLength < dwSize) {
         ntStatus = STATUS_BUFFER_TOO_SMALL;
         break;
      }

In this example, an integer overflow can occur during multiplication. If the size of the SET_VALUE_INFO structure is a multiple of 2, a NumEntries value such as 0x80000000 results in an overflow, when the bits are shifted left during multiplication. However, the buffer size will nevertheless pass the validation test, because the overflow causes dwSize to appear quite small. To avoid this problem, subtract the lengths as in the previous example, divide by sizeof(SET_VALUE_INFO), and compare the result with NumEntries.


Errors in Referencing User-Space Addresses

A driver should validate any address in user space before trying to use it. The I/O Manager does not validate such addresses, nor does it validate pointers that are embedded in buffers passed to drivers.

Failure to Validate Addresses Passed in Type3 (METHOD_NEITHER) IOCTLs and FSCTLs

The I/O Manager does no validation whatsoever for METHOD_NEITHER IOCTLs and FSCTLs. To ensure that user-space addresses are valid, the driver must use the ProbeForRead and ProbeForWrite routines, enclosing all buffer references in try/except blocks.

In the following example, the driver assumes that the value passed in the Type3InputBuffer represents a valid address.

   case IOCTL_GET_HANDLER: {
      PULONG EntryPoint;

      EntryPoint =
         IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
      *EntryPoint = (ULONG) DriverEntryPoint;

The following code avoids this problem:

   case IOCTL_GET_HANDLER: {
      PULONG_PTR EntryPoint;

      EntryPoint =
         IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;

 try {
   if (Irp->RequestorMode != KernelMode) {
       ProbeForWrite( EntryPoint,
                      sizeof( ULONG_PTR ),
                      TYPE_ALIGNMENT( ULONG_PTR ));
   }
   *EntryPoint = (ULONG_PTR)DriverEntryPoint;

 } except( EXCEPTION_EXECUTE_HANDLER ) {
…

Note also that the correct code casts DriverEntryPoint to a ULONG_PTR, instead of a ULONG. This change allows for future use in a 64-bit Windows environment.

Failure to validate pointers embedded in buffered I/O requests

Often drivers embed pointers within buffered requests, as in the following example:

   struct ret_buf {
      void   *arg; // Pointer embedded in request
      int     rval;
   };

   pBuf = Irp->AssociatedIrp.SystemBuffer;
   ...
   arg = pBuf->arg; // Fetch the embedded pointer
   ...
   // If the pointer is invalid,
   //this statement can corrupt the system.
   RtlMoveMemory(arg, &info, sizeof(info));

In this example, the driver should validate the embedded pointer by using the ProbeXxx routines enclosed in a try/except block in the same way as for the METHOD_NEITHER IOCTLs described earlier. Although embedding a pointer allows a driver to return extra information, a driver can more efficiently achieve the same result by using a relative offset or a variable length buffer.


Errors in Direct I/O

The most common direct I/O problem is failing to handle zero length buffers correctly. Because the I/O Manager does not create MDLs for zero-length transfers, a zero-length buffer results in a NULL value at Irp->MdlAddress.

To map the address space, drivers should use MmGetSystemAddressForMdlSafe, which returns NULL if mapping fails, as it will if a driver passes a NULL MdlAddress. Drivers should always check for a NULL return before attempting to use the returned address.

Direct I/O involves double-mapping the user's address space to a system address buffer, so that two different virtual addresses have the same physical address. Double-mapping has the following consequences, which can sometimes cause problems for drivers:

  • The offset into the virtual page of the user's address becomes the offset into the system page.

    Access beyond the end of these system buffers may go unnoticed for long periods of time depending on the page granularity of the mapping. Unless a caller's buffer is allocated near the end of a page, data written beyond the end of the buffer will nevertheless appear in the buffer, and the caller will be unaware that any error has occurred. If the end of the buffer coincides with the end of a page, the system virtual addresses beyond the end could point to anything or could be invalid. Such problems can be extremely difficult to find.

  • If the calling process has another thread that modifies the user's mapping of the memory, the contents of the system buffer will change when the user's memory mapping changes.

    In this situation, using the system buffer to store scratch data can cause problems. Two fetches from the same memory location might yield different values.

    The following code snippet receives a string in a direct I/O request, then tries to convert that string to uppercase characters:

    PWCHAR  PortName = NULL;

PortName = (PWCHAR)MmGetSystemAddressFromMdl (irp->MdlAddress);

//
// Null-terminate the PortName so that RtlInitUnicodeString will not
// be invalid.
//
PortName[Size / sizeof(WCHAR) - 1] = UNICODE_NULL;

RtlInitUnicodeString(&AdapterName, PortName);

    Because the buffer might not be correctly formed, the code attempts to force a Unicode NULL as the last buffer character. However, if the underlying physical memory is doubly mapped to both a user- and a kernel-mode address, another thread in the process can overwrite the buffer as soon as this write operation completes.

    Conversely, if the NULL is not present, then the call to RtlInitUnicodeString can exceed the range of the buffer and possibly cause a bug check if it falls outside the system mapping.

If a driver creates and maps its own MDL, it should ensure that it accesses the MDL only with the method for which it has probed. That is, when the driver calls MmProbeAndLockPages, it specifies an access method (IoReadAccess, IoWriteAccess, or IoModifyAccess). If the driver specifies IoReadAccess, it must not later attempt to write to the system buffer made available by MmGetSystemAddressForMdl or MmGetSystemAddressForMdlSafe.


Errors in Caller Input and Device State

Drivers should validate any input from a caller. A driver can never be certain that callers will pass the correct type or amount of data or will call only when the device or driver is in the correct state.

Failure to validate device state

In the following example, the driver uses the ASSERT macro to check for the correct device state in the checked build, but does not check device state in the free build:

   case IOCTL_WAIT_FOR_EVENT:

      ASSERT((!Extension->WaitEventIrp));
      Extension->WaitEventIrp = Irp;      IoMarkIrpPending(Irp);
      status = STATUS_PENDING;

In the checked build, if the driver already holds the IRP pending, the system will assert. In the free build, however, the driver does not check for this error. Two calls to the same IOCTL cause the driver to lose track of an IRP.

On a multiprocessor system, this code fragment might cause additional problems. Assume that on entry this routine has ownership of (the right to manipulate) this IRP. When the routine saves the Irp pointer in the global structure at Extension->WaitEventIrp, another thread can get the IRP address from that global structure and perform operations on the IRP. To prevent this problem, the driver should mark the IRP pending before it saves the IRP and should include both the call to IoMarkIrpPending and the assignment in an interlocked sequence. A Cancel routine for the IRP might also be necessary.

Receiving unexpected I/O requests for strange device objects

Many drivers create more than one kind of device object by calling IoCreateDevice. Some drivers create control device objects in their DriverEntry routines to allow applications to communicate with the driver, even before the driver creates an FDO. For example, file system drivers create device objects to handle file system notifications when they register themselves as file systems with IoRegisterFileSystem.

A driver should be ready for Create requests on any device object it creates. After completing the Create request with a success status, the driver should expect to receive any user-accessible I/O requests on the created file object. Consequently, any driver that creates more than one device object must check which device object each I/O request specifies.

For example, a driver might expect that an I/O request specifies an FDO for a specific device, when in fact the request specifies its control device object. If the driver has not initialized the same fields in the device extension of the control device object as in the other device objects, the driver could crash when trying to use device extension information from the control device object.

Failure to validate handles

Some drivers must manipulate objects passed to them by callers or must handle two file objects at the same time. For example, a modem driver might receive a handle to an event object, or a network driver might receive handles to two different file objects. The driver must validate these handles. Because they are passed by a caller, and not through the I/O Manager, the I/O Manager cannot perform any validation checks.

For example, in the following code snippet, the driver has been passed the handle AscInfo->AddressHandle, but has not validated it before calling ObReferenceObjectByHandle:

   //
   // This handle is embedded in a buffered request.
   //
   status = ObReferenceObjectByHandle(
                      AscInfo->AddressHandle,
                      0,
                      NULL,
                      KernelMode,
                      &fileObject,
                      NULL);

   if (NT_SUCCESS(status)) {
      if ( (fileObject->DeviceObject == DeviceObject) &&
           (fileObject->FsContext2 == TRANSPORT_SOCK) ) {

Although the call to ObReferenceObjectByHandle succeeds, the code fails to ensure that the returned pointer references a file object; it trusts the caller to pass in the correct information.

Even if all the parameters for the call to ObReferenceObjectByHandle are correct, and the call succeeds, a driver can still get unexpected results if the file object is not intended for its driver. In the following code fragment, the driver assumes that a successful call returns a pointer to the file object it expected:

   status = ObReferenceObjectByHandle (
                             AcpInfo->Handle,
                             0L,
                             DesiredAccess,
                             *IoFileObjectType,
                             Irp->RequestorMode,
                             (PVOID *)&AcpEndpointFileObject,
                             NULL);

   if ( !NT_SUCCESS(status) ) {
      goto complete;
   }
   AcpEndpoint = AcpEndpointFileObject->FsContext;

   if ( AcpEndpoint->Type != BlockTypeEndpoint )

Although ObReferenceObjectByHandle returns a pointer to a file object, the driver has no guarantee that the pointer references the file object it expected. In this case, the driver should validate the pointer before accessing the driver-specific data at AcpEndpointFileObject->FsContext.

To avoid such problems, a driver should check for valid data, as follows:

  • Check the object type to make sure it is what the driver expects.
  • Ensure that the requested access is appropriate for the object type and required tasks. If your driver performs a fast file copy, for instance, make sure the handle has read access.
  • Be sure to specify the correct access mode (UserMode or KernelMode) and that the access mode is compatible with the access requested.
  • If the driver expects a handle to a file object that the driver itself created, validate the handle against the device object or driver. However, be careful not to break filters that send I/O requests for strange devices.
  • If your driver supports multiple kinds of file objects (such as the control channels, address objects, and connections of TDI drivers or Volume, Directory, and File objects of file systems), make sure you have a way to differentiate them.


Errors in Dispatch Routines

Some drivers fail to distinguish the tasks required in DispatchCleanup and DispatchClose routines. The I/O Manager calls a driver's DispatchCleanup routine when the last handle to a file object is closed. The DispatchClose routine is called when the last reference is released from the file object. A driver should not attempt to free resources in its DispatchCleanup routine that are attached to a file object or might be used by other Dispatch routines.

When calling dispatch routines, the I/O Manager holds a reference to the file object for normal I/O calls. As a result, a driver can receive I/O requests for a file object after its DispatchCleanup routine has been called but before its DispatchClose routine is called. For example, a user-mode caller might close the file handle while an I/O Manager request is in progress from another thread. If the driver has deleted or freed necessary resources before the I/O Manager calls its DispatchClose routine, invalid pointer references and other problems could occur.

Converging public IOCTL and private IOCTL paths

As a general rule, drivers should not contain converging execution paths for private (internal) and public IOCTLs. A driver cannot determine whether an IOCTL originated in kernel mode or user mode merely by looking at the IOCTL code. Consequently, handling both along the same path (or performing minimal validation and then calling the same routines) can open a driver to security breaches. If a private IOCTL is privileged, then unprivileged users who know the IOCTL codes might be able to gain access to it. Therefore, if your driver creates private IOCTLs, make sure it handles such IOCTLs separately from any public IOCTLs it must also support.


Errors in a Multiprocessor Environment

On the NT-based operating system, drivers are multithreaded; they can receive multiple I/O requests from different threads at the same time. In designing a driver, you must assume that it will be run on an SMP system and take the appropriate measures to ensure data integrity.

Specifically, whenever a driver changes global or file object data, it must use a lock or an interlocked sequence to prevent race conditions.

Encountering a race condition when referencing global or file object-specific data

In the following code snippet, a race condition could occur when the driver accesses the global data at Data.LpcInfo:

   PLPC_INFO pLpcInfo = &Data.LpcInfo; //Pointer to global data
   ...
   ...
   // This saved pointer may be overwritten by another thread.
   pLpcInfo->LpcPortName.Buffer = ExAllocatePool(
                                     PagedPool,
                                     arg->PortName.Length);

Multiple threads entering this code as a result of an IOCTL call could cause a memory leak as the pointer is overwritten. To avoid this problem, the driver should use the ExInterlockedXxx routines or some type of lock when it changes the global data. The driver's requirements determine the acceptable types of locks. See Spin Locks, Kernel Dispatcher Objects, and ExAcquireResourceLite for details.

The following example attempts to reallocate a file-specific buffer (Endpoint->LocalAddress) to hold the endpoint address:

   Endpoint = FileObject->FsContext;

   if ( Endpoint->LocalAddress != NULL &&
        Endpoint->LocalAddressLength <
                  ListenEndpoint->LocalAddressLength ) {

      FREE_POOL (Endpoint->LocalAddress,
                 LOCAL_ADDRESS_POOL_TAG
                 );
      Endpoint->LocalAddress  = NULL;
   }

   if ( Endpoint->LocalAddress == NULL ) {
      Endpoint->LocalAddress =
            ALLOCATE_POOL (NonPagedPool,
                           ListenEndpoint->LocalAddressLength,
                           LOCAL_ADDRESS_POOL_TAG);
   }

In this example, a race condition could occur with accesses to the file object. Because the driver does not hold any locks, two requests for the same file object can enter this function. The result might be references to freed memory, multiple attempts to free the same memory, or memory leaks. To avoid these errors, the two if statements should be enclosed in a spin lock.


Errors in Handling IRPs

The following are common errors drivers make in handling IRPs.

Lost or double-completed IRPs

These problems, along with missing calls to I/O Manager routines such as IoStartNextPacket, often occur in error-handling paths. Quick reviews of driver paths can find such problems.

Copying stack locations incorrectly

When passing an IRP down the stack, always use the standard functions IoSkipCurrentIrpStackLocation and IoCopyCurrentIrpStackLocationToNext, rather than writing driver-specific code to copy the stack location. Using the standard routines ensures that the driver does not duplicate the Cancel routine of a driver layered above it.

Returning success when completing an IRP that the driver does not handle

A driver must not return STATUS_SUCCESS for an IRP that it does not handle. For example, some drivers incorrectly complete query IRPs with success statuses, despite not implementing the functionality required. Doing so can easily crash or corrupt the system, particularly during operations like filename look-ups, if the I/O Manager or another component attempts to use data that was left uninitialized by the Dispatch routine. Unless otherwise noted in the documentation for a specific IRP, a driver should return STATUS_NOT_SUPPORTED for any IRP it does not handle.

Causing a deadlock with the cancel spin lock

The I/O Manager holds the cancel spin lock whenever it calls a driver's Cancel routine. A deadlock can occur if a driver's Cancel routine obtains a second spin lock, as can happen when another thread within the driver obtains the locks in the reverse order.


Using Floating Point or MMX in a WDM Driver

Kernel-mode WDM drivers for Windows Me, Windows 98, Windows 98 SE, and Windows 2000 and later must follow certain guidelines for using floating-point operations, MMX, 3DNOW!, or Intel's SSE extensions.

Kernel-mode WDM drivers must wrap use of the floating-point unit (FPU) between calls to KeSaveFloatingPointState and KeRestoreFloatingPointState. Failure to use these routines can cause calculation errors in concurrent user-mode applications.

KeSaveFloatingPointState saves the FPU state of the currently running application in a system-provided buffer and reinitializes the FPU for the driver. The routine takes a single parameter, a driver-allocated buffer, which provides support for nested calls. If KeSaveFloatingPointState is called twice at the same IRQL without an intervening call to KeRestoreFloatingPointState, the nonvolatile FPU state is saved in the driver-allocated buffer. (The caller must save volatile state from ST0-ST7, MMX0-MMX7, and XMM0-XMM7.)

If the system is low on memory, KeSaveFloatingPointState can fail. Drivers must check the returned status and, if a failure occurs, must not access the FPU.

When a driver has finished using the FPU, it calls KeRestoreFloatingPointState to restore the previous application state.

The following example shows how a WDM driver should wrap its FPU access:

KFLOATING_SAVE     saveData;
NTSTATUS         status;
double         floatValue;

status = KeSaveFloatingPointState(&saveData);

if (NT_SUCCESS(status)) {

    floatValue = 1.0;
    KeRestoreFloatingPointState(&saveData);
}

In the example, the assignment to the floating-point variable occurs between calls to KeSaveFloatingPointState and KeRestoreFloatingPointState. Because any assignment to a floating-point variable uses the FPU, drivers must ensure that KeSaveFloatingPointState has returned without error before initializing such a variable.

WDM drivers can call KeSaveFloatingPointState at IRQL <= DISPATCH_LEVEL. However, use of floating-point operations is not supported in interrupt service routines (ISRs).

On NT-based systems, the FPU is set to long real precision (that is, double or 53-bit), with all exceptions masked, upon return from KeSaveFloatingPointState. On Windows Me, Windows 98, and Windows 98 SE, drivers that use the FPU must adhere to the following guidelines:

  • Access the FPU only from passive-level work items or worker threads.
  • Do not call KeSaveFloatingPointState or attempt to use the FPU or MMX from a DPC, from an IOCTL handler, or from any other handler called from user mode. Do not try to circumvent this rule; drivers cannot implement a workaround that is guaranteed to operate correctly on all processors.
  • Reload the FPU control word with 0x27F after KeSaveFloatingPointState returns. Doing so ensures that the FPU is set to long real precision (double or 53-bit), with all exceptions masked, as on NT-based systems.
  • For Windows 98 and Windows 98 SE only, always call KeSaveFloatingPointState at IRQL PASSIVE_LEVEL. Calling this routine at IRQL DISPATCH_LEVEL can cause a system crash.


Standard Driver Routines

This chapter describes the required and optional routines supplied by kernel-mode drivers.


AdapterControl

AdapterControl starts a DMA data transfer operation.

IO_ALLOCATION_ACTION
  AdapterControl(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp,
    IN PVOID  MapRegisterBase,
    IN PVOID  Context
    );

Parameters

DeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure. This is the device object for the target device, previously created by the driver's AddDevice routine.
Irp
Caller-supplied pointer to an IRP structure that describes the I/O operation if the driver has a StartIo routine. Otherwise, not used.
MapRegisterBase
Caller-supplied pointer to the base address of the map registers the system has assigned for this transfer operation. (The number of registers needed is specified in a previous call to AllocateAdapterChannel.)
Context
Caller-supplied pointer to driver-defined context information, specified in a previous call to AllocateAdapterChannel.

Return Value

The routine must return one of the enumerated values defined by IO_ALLOCATION_ACTION.

Comments

A driver's AdapterControl routine executes in an arbitrary thread context at IRQL DISPATCH_LEVEL.

To register an AdapterControl routine for a specific device object, a driver must call IoGetDmaAdapter to obtain an adapter object, then call AllocateAdapterChannel to request use of the adapter and to supply the AdapterControl routine's address. When the adapter is free, the system calls the AdapterControl routine.

For detailed information about implementing an AdapterControl routine, see Writing AdapterControl Routines.


AdapterListControl

AdapterListControl starts a direct memory access (DMA) scatter/gather operation.

VOID
  AdapterListControl(
    IN struct _DEVICE_OBJECT  *DeviceObject,
    IN struct _IRP  *Irp,
    IN PSCATTER_GATHER_LIST  ScatterGather,
    IN PVOID  Context
    );

Parameters

DeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure. This is the device object for the target device, previously created by the driver's AddDevice routine.
Irp
Caller-supplied pointer to an IRP structure that describes the I/O operation, if the driver has a StartIo routine. Otherwise, not used.
ScatterGather
Caller-supplied pointer to a SCATTER_GATHER_LIST structure describing scatter/gather regions.
Context
Caller-supplied pointer to driver-defined context information, specified in a previous call to AllocateAdapterChannel.

Return Value

None

Comments

A driver's AdapterListControl routine executes in an arbitrary thread context at IRQL DISPATCH_LEVEL.

To register an AdapterListControl routine for a specific device object, a driver must call IoGetDmaAdapter to obtain an adapter object, then call GetScatterGatherList to request use of the adapter and to supply the AdapterListControl routine's address. When the adapter is free, the system calls the AdapterListControl routine.

For detailed information about implementing an AdapterListControl routine, see Using Scatter/Gather DMA.


AddDevice

AddDevice is responsible for creating functional device objects (FDO) or filter device objects (filter DO) for devices enumerated by the Plug and Play (PnP) Manager.

NTSTATUS
  XxxAddDevice(
    IN PDRIVER_OBJECT  DriverObject,
    IN PDEVICE_OBJECT  PhysicalDeviceObject
    );

Parameters

DriverObject
Caller-supplied pointer to a DRIVER_OBJECT structure. This is the driver's driver object.
PhysicalDeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure representing a physical device object (PDO) created by a lower-level driver.

Return Value

If the routine succeeds, it must return STATUS_SUCCESS. Otherwise, it must return one of the error status values defined in ntstatus.h.

Comments

All kernel-mode drivers that support PnP must provide an AddDevice routine.

A driver's AddDevice routine executes in a system thread context at IRQL PASSIVE_LEVEL.

A driver's AddDevice routine should be named Xxx AddDevice, where Xxx is a driver-specific prefix. The driver's DriverEntry routine must store the AddDevice routine's address in DriverObject->DriverExtension->AddDevice.

An AddDevice routine's primary responsibilities are calling IoCreateDevice to create a device object, then calling IoAttachDeviceToDeviceStack to attach the device object to the device stack. For detailed information about implementing a driver's AddDevice routine, see Writing an AddDevice Routine.


Cancel

Cancel cancels an I/O operation.

VOID
  Cancel(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure. This is the device object for the target device, previously created by the driver's AddDevice routine.
Irp
Caller-supplied pointer to an IRP structure that describes the I/O operation to be canceled.

Return Value

None

Comments

When a driver or other system component calls IoCancelIrp, the I/O Manager calls all Cancel routines (if any) that are currently registered for the IRP.

The I/O Manager calls IoAcquireCancelSpinLock before calling a driver's Cancel routine, so the Cancel routine must call IoReleaseCancelSpinLock at some point. The routine should not hold the spin lock longer than necessary.

The Cancel routine executes in an arbitrary thread context at IRQL DISPATCH_LEVEL until it calls IoReleaseCancelSpinLock, which changes the IRQL to a caller-supplied value. The driver should specify Irp->CancelIrql for this value.

To register a Cancel routine for an IRP, a driver can use the following two methods:

  • A driver that provides a StartIo routine and uses the I/O Manager-supplied device queue can specify a Cancel routine when calling IoStartPacket.
  • A driver that creates and manages supplemental device queues can register a Cancel routine by calling IoSetCancelRoutine.

The Cancel routine must set the I/O status block's Status member to STATUS_CANCELLED, and set its Information member to zero. The routine must then complete the specified IRP by calling IoCompleteRequest.

For detailed information about implementing a driver's Cancel routine, see Canceling IRPs.


ControllerControl

ControllerControl starts a data transfer operation.

IO_ALLOCATION_ACTION
  ControllerControl(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp,
    IN PVOID  MapRegisterBase,
    IN PVOID  Context
    );

Parameters

DeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure. This is the device object for the target device, previously created by the driver's AddDevice routine.
Irp
Caller-supplied pointer to an IRP structure that describes the I/O operation, if the driver has a StartIo routine. Otherwise, not used.
MapRegisterBase
Not used.
Context
Caller-supplied pointer to driver-defined context information, specified in a previous call to IoAllocateController.

Return Value

The routine must return one of the enumerated values defined by IO_ALLOCATION_ACTION.

Comments

A driver's ControllerControl routine executes in an arbitrary thread context at IRQL DISPATCH_LEVEL.

To register a ControllerrControl routine for a specific device object, a driver must call IoCreateController to obtain a controller object, then call IoAllocateController to request use of the controller and to supply the ControllerControl routine's address. When the controller is free, the system calls the ControllerControl routine.

For detailed information about implementing a ControllerControl routine, see Writing ControllerControl Routines. Also see Controller Objects.


CustomDPC

CustomDpc finishes the servicing of an I/O operation, after an InterruptService routine returns.

VOID
  CustomDPC(
    IN struct _KDPC  *Dpc,
    IN PVOID  DeferredContext,
    IN PVOID  SystemArgument1,
    IN PVOID  SystemArgument2
    );

Parameters

Dpc
Caller-supplied pointer to the DPC object associated with this CustomDpc routine.
DeferredContext
Caller-supplied pointer to driver-defined context information, specified in a previous call to KeInitializeDpc.
SystemArgument1
Caller-supplied pointer to driver-supplied information, specified in a previous call to KeInsertQueueDpc.
SystemArgument2
Caller-supplied pointer to driver-supplied information, specified in a previous call to KeInsertQueueDpc.

Return Value

None

Comments

A driver's CustomDpc routine executes in a DPC context, at IRQL DISPATCH_LEVEL.

To create a DPC object and register a CustomDpc routine for that object, a driver must call KeInitializeDPC. (If you need only one DPC routine, you can use a DpcForIsr routine and the system-allocated DPC object.)

To queue a CustomDpc routine for execution, a driver's InterruptService routine must call KeInsertQueueDpc.

One or more CustomDpc routines can be used instead of, or in conjunction with, a DpcForIsr routine. A driver that maintains several internal IRP queues typically supplies a CustomDpc routine for each queue. Each CustomDpc routine is typically responsible for at least the following tasks:

  • Completing the I/O operation described by the current IRP.
  • Dequeuing the next IRP from one of the driver's IRP queues. (Drivers using the system-supplied IRP queue, along with a StartIo routine, call IoStartNextPacket.)
  • Setting the I/O status block in the current IRP and calling IoCompleteRequest for the completed request.

A CustomDpc routine might also retry a failed operation or set up the next transfer for a large I/O request that has been broken into smaller pieces.

For more information about CustomDpc routines, see DPC Objects and DPCs.


CustomTimerDPC

CustomTimerDpc executes after a timer object's time interval has expired.

VOID
  CustomTimerDPC(
    IN struct _KDPC  *Dpc,
    IN PVOID  DeferredContext,
    IN PVOID  SystemArgument1,
    IN PVOID  SystemArgument2
    );

Parameters

Dpc
Caller-supplied pointer to the DPC object associated with this CustomTimerDpc routine.
DeferredContext
Caller-supplied pointer to driver-defined context information, specified in a previous call to KeInitializeDpc.
SystemArgument1
Not used.
SystemArgument2
Not used.

Return Value

None

Comments

A driver's CustomTimerDpc routine executes in a DPC context, at IRQL DISPATCH_LEVEL.

To create a DPC object and register a CustomTimerDpc routine for that object, a driver must call KeInitializeDPC.

To queue a CustomTimerDpc routine for execution, a driver routine must call KeSetTimer or KeSetTimerEx, supplying a DPC object pointer returned by KeInitializeDPC. The system calls the CustomTimerDpc routine when the timer interval expires.

For more information about CustomTimerDpc routines, see Timer Objects and DPCs.


DispatchCleanup

DispatchCleanup services IRPs containing the IRP_MJ_CLEANUP I/O function code.

NTSTATUS
  XxxDispatchCleanup(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure. This is the device object for the target device, previously created by the driver's AddDevice routine.
Irp
Caller-supplied pointer to an IRP structure that describes the requested I/O operation.

Return Value

If the routine succeeds, it must return STATUS_SUCCESS. Otherwise, it must return one of the error status values defined in ntstatus.h.

Comments

A driver's DispatchCleanup routine should be named Xxx DispatchCleanup, where Xxx is a driver-specific prefix. The driver's DriverEntry routine must store the DispatchCleanup routine's address in DriverObject->MajorFunction[IRP_MJ_CLEANUP].

Input parameters for all Dispatch routines are supplied in the IRP structure pointed to by Irp. Additional parameters are supplied in the driver's associated I/O stack location, which is described by the IO_STACK_LOCATION structure and can be obtained by calling IoGetCurrentIrpStackLocation.

Generally, all Dispatch routines execute in an arbitrary thread context at IRQL PASSIVE_LEVEL, but there are exceptions. For more information, see Dispatch Routines and IRQLs.

For more information about DispatchCleanup routines, see Writing Dispatch Routines. For more information about IRPs, see Handling IRPs.


DispatchClose

DispatchClose services IRPs containing the IRP_MJ_CLOSE I/O function code.

NTSTATUS
  XxxDispatchClose(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure. This is the device object for the target device, previously created by the driver's AddDevice routine.
Irp
Caller-supplied pointer to an IRP structure that describes the requested I/O operation.

Return Value

If the routine succeeds, it must return STATUS_SUCCESS. Otherwise, it must return one of the error status values defined in ntstatus.h.

Comments

A driver's DispatchClose routine should be named Xxx DispatchClose, where Xxx is a driver-specific prefix. The driver's DriverEntry routine must store the DispatchClose routine's address in DriverObject->MajorFunction[IRP_MJ_CLOSE].

Input parameters for all Dispatch routines are supplied in the IRP structure pointed to by Irp. Additional parameters are supplied in the driver's associated I/O stack location, which is described by the IO_STACK_LOCATION structure and can be obtained by calling IoGetCurrentIrpStackLocation.

Generally, all Dispatch routines execute in an arbitrary thread context at IRQL PASSIVE_LEVEL, but there are exceptions. For more information, see Dispatch Routines and IRQLs.

For more information about DispatchClose routines, see Writing Dispatch Routines. For more information about IRPs, see Handling IRPs.


DispatchCreate

DispatchCreate services IRPs containing the IRP_MJ_CREATE I/O function code.

NTSTATUS
  XxxDispatchCreate(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure. This is the device object for the target device, previously created by the driver's AddDevice routine.
Irp
Caller-supplied pointer to an IRP structure that describes the requested I/O operation.

Return Value

If the routine succeeds, it must return STATUS_SUCCESS. Otherwise, it must return one of the error status values defined in ntstatus.h.

Comments

A driver's DispatchCreate routine should be named Xxx DispatchCreate, where Xxx is a driver-specific prefix. The driver's DriverEntry routine must store the DispatchCreate routine's address in DriverObject->MajorFunction[IRP_MJ_CREATE].

Input parameters for all Dispatch routines are supplied in the IRP structure pointed to by Irp. Additional parameters are supplied in the driver's associated I/O stack location, which is described by the IO_STACK_LOCATION structure and can be obtained by calling IoGetCurrentIrpStackLocation.

Generally, all Dispatch routines execute in an arbitrary thread context at IRQL PASSIVE_LEVEL, but there are exceptions. For more information, see Dispatch Routines and IRQLs.

For more information about DispatchCreate routines, see Writing Dispatch Routines. For more information about IRPs, see Handling IRPs.


DispatchCreateClose

DispatchCreateClose services IRPs containing the IRP_MJ_CREATE or IRP_MJ_CLOSE I/O function code.

NTSTATUS
  XxxDispatchCreateClose(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure. This is the device object for the target device, previously created by the driver's AddDevice routine.
Irp
Caller-supplied pointer to an IRP structure that describes the requested I/O operation.

Return Value

If the routine succeeds, it must return STATUS_SUCCESS. Otherwise, it must return one of the error status values defined in ntstatus.h.

Comments

A driver can provide a single DispatchCreateClose routine instead of separate DispatchCreate and DispatchClose routines.

A driver's DispatchCreateClose routine should be named Xxx DispatchCreateClose, where Xxx is a driver-specific prefix. The driver's DriverEntry routine must store the DispatchCreateClose routine's address in DriverObject->MajorFunction[IRP_MJ_CREATE] and in DriverObject->MajorFunction[IRP_MJ_CLOSE].

Input parameters for all Dispatch routines are supplied in the IRP structure pointed to by Irp. Additional parameters are supplied in the driver's associated I/O stack location, which is described by the IO_STACK_LOCATION structure and can be obtained by calling IoGetCurrentIrpStackLocation.

Generally, all Dispatch routines execute in an arbitrary thread context at IRQL PASSIVE_LEVEL, but there are exceptions. For more information, see Dispatch Routines and IRQLs.

For more information about DispatchCreateClose routines, see Writing Dispatch Routines. For more information about IRPs, see Handling IRPs.


DispatchDeviceControl

DispatchDeviceControl services IRPs containing the IRP_MJ_DEVICE_CONTROL I/O function code.

NTSTATUS
  XxxDispatchDeviceControl(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure. This is the device object for the target device, previously created by the driver's AddDevice routine.
Irp
Caller-supplied pointer to an IRP structure that describes the requested I/O operation.

Return Value

If the routine succeeds, it must return STATUS_SUCCESS. Otherwise, it must return one of the error status values defined in ntstatus.h.

Comments

A driver's DispatchDeviceControl routine should be named Xxx DispatchDeviceControl, where Xxx is a driver-specific prefix. The driver's DriverEntry routine must store the DispatchDeviceControl routine's address in DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL].

Input parameters for all Dispatch routines are supplied in the IRP structure pointed to by Irp. Additional parameters are supplied in the driver's associated I/O stack location, which is described by the IO_STACK_LOCATION structure and can be obtained by calling IoGetCurrentIrpStackLocation. The I/O stack location contains the I/O control code specifying the device control operation to be performed.

Generally, all Dispatch routines execute in an arbitrary thread context at IRQL PASSIVE_LEVEL, but there are exceptions. For more information, see Dispatch Routines and IRQLs.

For more information about DispatchDeviceControl routines, see Writing Dispatch Routines. For more information about IRPs, see Handling IRPs.


DispatchFlushBuffers

DispatchFlushBuffers services IRPs containing the IRP_MJ_FLUSH_BUFFERS I/O function code.

NTSTATUS
  XxxDispatchFlushBuffers(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure. This is the device object for the target device, previously created by the driver's AddDevice routine.
Irp
Caller-supplied pointer to an IRP structure that describes the requested I/O operation.

Return Value

If the routine succeeds, it must return STATUS_SUCCESS. Otherwise, it must return one of the error status values defined in ntstatus.h.

Comments

A driver's DispatchFlushBuffers routine should be named Xxx DispatchFlushBuffers, where Xxx is a driver-specific prefix. The driver's DriverEntry routine must store the DispatchFlushBuffers routine's address in DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS].

Input parameters for all Dispatch routines are supplied in the IRP structure pointed to by Irp. Additional parameters are supplied in the driver's associated I/O stack location, which is described by the IO_STACK_LOCATION structure and can be obtained by calling IoGetCurrentIrpStackLocation.

Generally, all Dispatch routines execute in an arbitrary thread context at IRQL PASSIVE_LEVEL, but there are exceptions. For more information, see Dispatch Routines and IRQLs.

For more information about DispatchFlushBuffers routines, see Writing Dispatch Routines. For more information about IRPs, see Handling IRPs.


DispatchInternalDeviceControl

DispatchDeviceControl services IRPs containing the IRP_MJ_INTERNAL_DEVICE_CONTROL I/O function code.

NTSTATUS
  XxxDispatchInternalDeviceControl(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure. This is the device object for the target device, previously created by the driver's AddDevice routine.
Irp
Caller-supplied pointer to an IRP structure that describes the requested I/O operation.

Return Value

If the routine succeeds, it must return STATUS_SUCCESS. Otherwise, it must return one of the error status values defined in ntstatus.h.

Comments

A driver's DispatchInternalDeviceControl routine should be named Xxx DispatchInternalDeviceControl, where Xxx is a driver-specific prefix. The driver's DriverEntry routine must store the DispatchInternalDeviceControl routine's address in DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL].

Input parameters for all Dispatch routines are supplied in the IRP structure pointed to by Irp. Additional parameters are supplied in the driver's associated I/O stack location, which is described by the IO_STACK_LOCATION structure and can be obtained by calling IoGetCurrentIrpStackLocation. The I/O stack location contains the I/O control code specifying the device control operation to be performed.

Generally, all Dispatch routines execute in an arbitrary thread context at IRQL PASSIVE_LEVEL, but there are exceptions. For more information, see Dispatch Routines and IRQLs.

For more information about DispatchInternalDeviceControl routines, see Writing Dispatch Routines. For more information about IRPs, see Handling IRPs.


DispatchPnP

DispatchPnP services IRPs containing the IRP_MJ_PNP I/O function code.

NTSTATUS
  XxxDispatchPnP(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure. This is the device object for the target device, previously created by the driver's AddDevice routine.
Irp
Caller-supplied pointer to an IRP structure that describes the requested I/O operation.

Return Value

If the routine succeeds, it must return STATUS_SUCCESS. Otherwise, it must return one of the error status values defined in ntstatus.h.

Comments

A driver's DispatchPnP routine should be named Xxx DispatchPnP, where Xxx is a driver-specific prefix. The driver's DriverEntry routine must store the DispatchPnP routine's address in DriverObject->MajorFunction[IRP_MJ_PNP].

Input parameters for all Dispatch routines are supplied in the IRP structure pointed to by Irp. Additional parameters are supplied in the driver's associated I/O stack location, which is described by the IO_STACK_LOCATION structure and can be obtained by calling IoGetCurrentIrpStackLocation.

Generally, all Dispatch routines execute in an arbitrary thread context at IRQL PASSIVE_LEVEL, but there are exceptions. For more information, see Dispatch Routines and IRQLs.

For more information about DispatchPnP routines, see Writing Dispatch Routines. For more information about IRPs, see Handling IRPs.


DispatchPower

DispatchPower services IRPs containing the IRP_MJ_POWER I/O function code.

NTSTATUS
  XxxDispatchPower(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure. This is the device object for the target device, previously created by the driver's AddDevice routine.
Irp
Caller-supplied pointer to an IRP structure that describes the requested I/O operation.

Return Value

If the routine succeeds, it must return STATUS_SUCCESS. Otherwise, it must return one of the error status values defined in ntstatus.h.

Comments

A driver's DispatchPower routine should be named Xxx DispatchPower, where Xxx is a driver-specific prefix. The driver's DriverEntry routine must store the DispatchPower routine's address in DriverObject->MajorFunction[IRP_MJ_POWER].

Input parameters for all Dispatch routines are supplied in the IRP structure pointed to by Irp. Additional parameters are supplied in the driver's associated I/O stack location, which is described by the IO_STACK_LOCATION structure and can be obtained by calling IoGetCurrentIrpStackLocation.

Generally, all Dispatch routines execute in an arbitrary thread context at IRQL PASSIVE_LEVEL, but there are exceptions. For more information, see Dispatch Routines and IRQLs.

For more information about DispatchPower routines, see Writing Dispatch Routines. For more information about IRPs, see Handling IRPs.


DispatchQueryInformation

DispatchQueryInformation services IRPs containing the IRP_MJ_QUERY_INFORMATION I/O function code.

NTSTATUS
  XxxDispatchQueryInformation(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure. This is the device object for the target device, previously created by the driver's AddDevice routine.
Irp
Caller-supplied pointer to an IRP structure that describes the requested I/O operation.

Return Value

If the routine succeeds, it must return STATUS_SUCCESS. Otherwise, it must return one of the error status values defined in ntstatus.h.

Comments

A driver's DispatchQueryInformation routine should be named Xxx DispatchQueryInformation, where Xxx is a driver-specific prefix. The driver's DriverEntry routine must store the DispatchQueryInformation routine's address in DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION].

Input parameters for all Dispatch routines are supplied in the IRP structure pointed to by Irp. Additional parameters are supplied in the driver's associated I/O stack location, which is described by the IO_STACK_LOCATION structure and can be obtained by calling IoGetCurrentIrpStackLocation.

Generally, all Dispatch routines execute in an arbitrary thread context at IRQL PASSIVE_LEVEL, but there are exceptions. For more information, see Dispatch Routines and IRQLs.

For more information about DispatchQueryInformation routines, see Writing Dispatch Routines. For more information about IRPs, see Handling IRPs.


DispatchRead

DispatchRead services IRPs containing the IRP_MJ_READ I/O function code.

NTSTATUS
  XxxDispatchRead(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure. This is the device object for the target device, previously created by the driver's AddDevice routine.
Irp
Caller-supplied pointer to an IRP structure that describes the requested I/O operation.

Return Value

If the routine succeeds, it must return STATUS_SUCCESS. Otherwise, it must return one of the error status values defined in ntstatus.h.

Comments

A driver's DispatchRead routine should be named Xxx DispatchRead, where Xxx is a driver-specific prefix. The driver's DriverEntry routine must store the DispatchRead routine's address in DriverObject->MajorFunction[IRP_MJ_READ].

Input parameters for all Dispatch routines are supplied in the IRP structure pointed to by Irp. Additional parameters are supplied in the driver's associated I/O stack location, which is described by the IO_STACK_LOCATION structure and can be obtained by calling IoGetCurrentIrpStackLocation.

Generally, all Dispatch routines execute in an arbitrary thread context at IRQL PASSIVE_LEVEL, but there are exceptions. For more information, see Dispatch Routines and IRQLs.

For more information about DispatchRead routines, see Writing Dispatch Routines. For more information about IRPs, see Handling IRPs.


DispatchReadWrite

DispatchReadWrite services IRPs containing the IRP_MJ_READ or IRP_MJ_WRITE I/O function code.

NTSTATUS
  XxxDispatchReadWrite(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure. This is the device object for the target device, previously created by the driver's AddDevice routine.
Irp
Caller-supplied pointer to an IRP structure that describes the requested I/O operation.

Return Value

If the routine succeeds, it must return STATUS_SUCCESS. Otherwise it must return one of the error status values defined in ntstatus.h.

Comments

A driver can provide a single DispatchReadWrite routine instead of separate DispatchRead and DispatchWrite routines.

A driver's DispatchReadWrite routine should be named Xxx DispatchReadWrite, where Xxx is a driver-specific prefix. The driver's DriverEntry routine must store the DispatchReadWrite routine's address in DriverObject->MajorFunction[IRP_MJ_READ] and in DriverObject->MajorFunction[IRP_MJ_WRITE].

Input parameters for all Dispatch routines are supplied in the IRP structure pointed to by Irp. Additional parameters are supplied in the driver's associated I/O stack location, which is described by the IO_STACK_LOCATION structure and can be obtained by calling IoGetCurrentIrpStackLocation.

Generally, all Dispatch routines execute in an arbitrary thread context at IRQL PASSIVE_LEVEL, but there are exceptions. For more information, see Dispatch Routines and IRQLs.

For more information about DispatchReadWrite routines, see Writing Dispatch Routines. For more information about IRPs, see Handling IRPs.


DispatchSetInformation

DispatchSetInformation services IRPs containing the IRP_MJ_SET_INFORMATION I/O function code.

NTSTATUS
  XxxDispatchSetInformation(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure. This is the device object for the target device, previously created by the driver's AddDevice routine.
Irp
Caller-supplied pointer to an IRP structure that describes the requested I/O operation.

Return Value

If the routine succeeds, it must return STATUS_SUCCESS. Otherwise, it must return one of the error status values defined in ntstatus.h.

Comments

A driver's DispatchSetInformation routine should be named Xxx DispatchSetInformation, where Xxx is a driver-specific prefix. The driver's DriverEntry routine must store the DispatchSetInformation routine's address in DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION].

Input parameters for all Dispatch routines are supplied in the IRP structure pointed to by Irp. Additional parameters are supplied in the driver's associated I/O stack location, which is described by the IO_STACK_LOCATION structure and can be obtained by calling IoGetCurrentIrpStackLocation.

Generally, all Dispatch routines execute in an arbitrary thread context at IRQL PASSIVE_LEVEL, but there are exceptions. For more information, see Dispatch Routines and IRQLs.

For more information about DispatchSetInformation routines, see Writing Dispatch Routines. For more information about IRPs, see Handling IRPs.


DispatchShutdown

DispatchShutdown services IRPs containing the IRP_MJ_SHUTDOWN I/O function code.

NTSTATUS
  XxxDispatchShutdown(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure. This is the device object for the target device, previously created by the driver's AddDevice routine.
Irp
Caller-supplied pointer to an IRP structure that describes the requested I/O operation.

Return Value

If the routine succeeds, it must return STATUS_SUCCESS. Otherwise, it must return one of the error status values defined in ntstatus.h.

Comments

A driver's DispatchShutdown routine should be named Xxx DispatchShutdown, where Xxx is a driver-specific prefix. The driver's DriverEntry routine must store the DispatchShutdown routine's address in DriverObject->MajorFunction[IRP_MJ_SHUTDOWN].

Additionally, in order to receive IRP_MJ_SHUTDOWN requests, a driver must call IoRegisterShutdownNotification to register its DispatchShutdown routine with the system.

Input parameters for all Dispatch routines are supplied in the IRP structure pointed to by Irp. Additional parameters are supplied in the driver's associated I/O stack location, which is described by the IO_STACK_LOCATION structure and can be obtained by calling IoGetCurrentIrpStackLocation.

Generally, all Dispatch routines execute in an arbitrary thread context at IRQL PASSIVE_LEVEL, but there are exceptions. For more information, see Dispatch Routines and IRQLs.

For more information about DispatchShutdown routines, see Writing Dispatch Routines. For more information about IRPs, see Handling IRPs.


DispatchSystemControl

DispatchSystemControl services IRPs containing the IRP_MJ_SYSTEM_CONTROL I/O function code.

NTSTATUS
  XxxDispatchSystemControl(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure. This is the device object for the target device, previously created by the driver's AddDevice routine.
Irp
Caller-supplied pointer to an IRP structure that describes the requested I/O operation.

Return Value

If the routine succeeds, it must return STATUS_SUCCESS. Otherwise, it must return one of the error status values defined in ntstatus.h.

Comments

A driver's DispatchSystemControl routine should be named Xxx DispatchSystemControl, where Xxx is a driver-specific prefix. The driver's DriverEntry routine must store the DispatchSystemControl routine's address in DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL].

Input parameters for all Dispatch routines are supplied in the IRP structure pointed to by Irp. Additional parameters are supplied in the driver's associated I/O stack location, which is described by the IO_STACK_LOCATION structure and can be obtained by calling IoGetCurrentIrpStackLocation.

Generally, all Dispatch routines execute in an arbitrary thread context at IRQL PASSIVE_LEVEL, but there are exceptions. For more information, see Dispatch Routines and IRQLs.

For more information about DispatchSystemControl routines, see Writing Dispatch Routines. For more information about IRPs, see Handling IRPs.


DispatchWrite

DispatchWrite services IRPs containing the IRP_MJ_WRITE I/O function code.

NTSTATUS
  XxxDispatchWrite(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure. This is the device object for the target device, previously created by the driver's AddDevice routine.
Irp
Caller-supplied pointer to an IRP structure that describes the requested I/O operation.

Return Value

If the routine succeeds, it must return STATUS_SUCCESS. Otherwise, it must return one of the error status values defined in ntstatus.h.

Comments

A driver's DispatchWrite routine should be named Xxx DispatchWrite, where Xxx is a driver-specific prefix. The driver's DriverEntry routine must store the DispatchWrite routine's address in DriverObject->MajorFunction[IRP_MJ_WRITE].

Input parameters for all Dispatch routines are supplied in the IRP structure pointed to by Irp. Additional parameters are supplied in the driver's associated I/O stack location, which is described by the IO_STACK_LOCATION structure and can be obtained by calling IoGetCurrentIrpStackLocation.

Generally, all Dispatch routines execute in an arbitrary thread context at IRQL PASSIVE_LEVEL, but there are exceptions. For more information, see Dispatch Routines and IRQLs.

For more information about DispatchWrite routines, see Writing Dispatch Routines. For more information about IRPs, see Handling IRPs.


DpcForIsr

DpcForIsr finishes the servicing of an I/O operation, after an InterruptService routine returns.

VOID
  DpcForIsr(
    IN PKDPC  Dpc,
    IN struct _DEVICE_OBJECT  *DeviceObject,
    IN struct _IRP  *Irp,
    IN PVOID  Context
    );

Parameters

Dpc
Caller-supplied pointer to the system-supplied DPC object associated with this DpcForIsr routine.
DeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure. This is the device object for the target device, previously created by the driver's AddDevice routine.
Irp
Caller-supplied pointer to an IRP structure that describes the I/O operation.
Context
Caller-supplied pointer to driver-defined context information, specified in a previous call to IoInitializeDpcRequest.

Return Value

None

Comments

A driver's DpcForIsr routine executes in a DPC context, at IRQL DISPATCH_LEVEL.

To register a DpcForIsr routine for a specific device object, a driver must call IoInitializeDpcRequest, which causes the system to allocate and initialize one DPC object. (If you need multiple DPC routines, use CustomDpc routines.)

To queue a DpcForIsr routine for execution, a driver's InterruptService routine must call IoRequestDPC.

A DpcForIsr routine is typically responsible for at least the following tasks:

  • Completing the I/O operation described by the received IRP
  • Dequeuing next IRP

    If the driver uses the system-supplied IRP queue, the DcpForIsr routine should call IoStartNextPacket or IoStartNextPacketByKey, so the driver's StartIo routine will start processing the next I/O request.

    If the driver uses internal IRP queues, the DpcForIsr routine should dequeue the next IRP and begin processing for the next I/O request.

  • Setting the I/O status block in the received IRP and calling IoCompleteRequest for the completed request

A DpcForIsr routine might also retry a failed operation or set up the next transfer for a large I/O request that has been broken into smaller pieces.

For more information about DpcForIsr routines, see DPC Objects and DPCs.


DllInitialize

The system calls a kernel-mode DLL's DllInitialize routine when the DLL is first loaded.

NTSTATUS
  DllInitialize(
    IN PUNICODE_STRING  RegistryPath
    );

Parameters

RegistryPath
Pointer to a counted Unicode string specifying the path to the DLL's registry key, HKEY_LOCAL_MACHINE\CurrentControlSet\Services\DllName. DLL routines can use this key to store DLL-specific information. The buffer pointed to by RegistryPath is freed once DllInitialize exits. Therefore, if the DLL makes use of the key, DllInitialize must duplicate the key name.

Return Value

The routine should return STATUS_SUCCESS if the DLL is successfully initialized, or the appropriate error code on failure. If the routine does not return STATUS_SUCCESS, the DLL is not loaded.

Comments

You can use the DllInitialize routine to acquire or initialize resources required by the routines in the DLL.

See Also

DllUnload


DllUnload

The system calls a kernel-mode DLL's DllUnload routine when it unloads the DLL.

NTSTATUS
  DllUnload(
    );

Return Value

The routine should return STATUS_SUCCESS on success, or the appropriate error code on failure. The system only unloads the DLL if DllUnload returns STATUS_SUCCESS.

Comments

You can use the DllUnload routine to release any resources used by the routines in the DLL.

See Also

DllInitialize


DriverEntry

DriverEntry is the first routine called after a driver is loaded, and is responsible for initializing the driver.

NTSTATUS
  DriverEntry(
    IN PDRIVER_OBJECT  DriverObject,
    IN PUNICODE_STRING  RegistryPath
    );

Parameters

DriverObject
Caller-supplied pointer to a DRIVER_OBJECT structure. This is the driver's driver object.
RegistryPath
Pointer to a counted Unicode string specifying the path to the driver's registry key.

Return Value

If the routine succeeds, it must return STATUS_SUCCESS. Otherwise, it must return one of the error status values defined in ntstatus.h.

Comments

The DriverObject parameter supplies the DriverEntry routine with a pointer to the driver's driver object, which is allocated by the I/O Manager. The DriverEntry routine must fill in the driver object with entry points for the driver's standard routines.

The DriverObject pointer gives the driver access to DriverObject->HardwareDatabase, which points to a counted Unicode string that specifies a path to the registry's \Registry\Machine\Hardware tree.

The registry path string pointed to by RegistryPath is of the form \Registry\Machine\System\CurrentControlSet\Services\DriverName. A driver can use this path to store driver-specific information; see Driver Information in the Registry. The DriverEntry routine should save a copy of the Unicode string, not the pointer, since the I/O Manager frees the RegistryPath buffer after DriverEntry returns.

A driver's DriverEntry routine executes in a system thread context at IRQL PASSIVE_LEVEL.

For more information about implementing a DriverEntry routine, see Writing a DriverEntry Routine.

While it is possible to name this routine something other than DriverEntry, doing so is not recommended. The DDK-supplied build tools automatically inform the linker that the driver's entry point is called DriverEntry, so giving the routine another name requires you to modify the build tools. For more information about build tools, see Building a Driver.


InterruptService

InterruptService quickly services a device interrupt and schedules post-interrupt processing of received data, if necessary.

BOOLEAN
InterruptService(
    IN struct _KINTERRUPT  *Interrupt,
    IN PVOID  ServiceContext
    );

Parameters

Interrupt
Caller-supplied pointer to an interrupt object.
ServiceContext
Caller-supplied pointer to context information, specified in a previous call to IoConnectInterrupt.

Return Value

If the routine determines that the interrupt did not come from one of the driver's devices, it must return FALSE. Otherwise, the routine must service the interrupt and return TRUE.

Comments

To register an ISR for a specific interrupt vector and processor affinity, a driver must call IoConnectInterrupt.

A driver's InterruptService routine (ISR) executes in an interrupt context, at some system-assigned DIRQL, as specified by the SynchronizeIrql parameter to IoConnectInterrupt. (Other devices, with higher DIRQL values, can interrupt the ISR.)

Before the system calls an ISR, it acquires the interrupt's spin lock (the SpinLock parameter to IoConnectInterrupt), so the ISR cannot simultaneously execute on another processor. After the ISR returns, the system releases the spin lock.

An ISR must first determine if the interrupt came from one of the driver's devices, by examining context information supplied by Context. If the interrupt is not from one of the driver's devices, the routine must immediately return FALSE so the I/O Manager can call other drivers that have registered ISRs for the same processor and interrupt vector.

For more information about implementing ISRs, see Interrupt Objects and ISRs.


IoCompletion

IoCompletion completes the processing of I/O operations.

NTSTATUS
  IoCompletion(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp,
    IN PVOID  Context
    );

Parameters

DeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure. This is the device object for the target device, previously created by the driver's AddDevice routine.
Irp
Caller-supplied pointer to an IRP structure that describes the I/O operation.
Context
Caller-supplied pointer to driver-specific context information, previously supplied when calling IoSetCompletionRoutine, or IoSetCompletionRoutineEx. Context information must be stored in nonpaged memory, since an IoCompletion routine can be called at DISPATCH_LEVEL (see the following Comments section).

Return Value

If the routine succeeds, it must return STATUS_SUCCESS. Otherwise, it must return one of the error status values defined in ntstatus.h. For more information, see the following Comments section.

Comments

A driver's IoCompletion routine executes in an arbitrary thread or DPC context, and at an IRQL that is less than or equal to DISPATCH_LEVEL. Because code written to execute at DISPATCH_LEVEL will also execute at lower levels, IoCompletion routines should be designed for execution at DISPATCH_LEVEL. However, because these routines are not guaranteed to run at DISPATCH_LEVEL, they must not call system routines that actually require execution at DISPATCH_LEVEL. (For more information about IRQLs, see Managing Hardware Priorities.)

To register an IoCompletion routine for a specific IRP, a driver must call IoSetCompletionRoutine or IoSetCompletionRoutineEx, which stores the IoCompletion routine's address in the next-lower driver's I/O stack location. (Thus, a lowest-level driver cannot register an IoCompletion routine.) A driver typically calls IoSetCompletionRoutine or IoSetCompletionRoutineEx from one of its dispatch routines, each time an IRP is received. Most drivers, including all PnP drivers, can use IoSetCompletionRoutine to register their IoCompletion routine. Non-PnP drivers that may be unloaded before their IoCompletion routine executes should use IoSetCompletionRoutineEx instead.

When any driver completes an IRP, it calls IoCompleteRequest, which in turn calls the IoCompletion routine of each higher-level driver, from the next-highest to the highest, until all higher IoCompletion routines have been called or until one routine returns STATUS_MORE_PROCESSING_REQUIRED.

If an IoCompletion routine returns STATUS_MORE_PROCESSING_REQUIRED, the lower driver's call to IoCompleteRequest immediately returns. In this case, a higher-level driver will have to call IoCompleteRequest to complete the IRP.

For more information about implementing IoCompletion routines, see Completing IRPs.


IoTimer

IoTimer is a DPC that, if registered, is called once per second.

VOID
  IoTimer(
    IN struct DEVICE_OBJECT  *DeviceObject,
    IN PVOID  Context
    );

Parameters

DeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure. This is the device object for the target device, previously created by the driver's AddDevice routine.
Context
Caller-supplied pointer to driver-defined context information, specified in a previous call to IoInitializeTimer.

Return Value

None

Comments

A driver's IoTimer routine executes in a DPC context, at IRQL DISPATCH_LEVEL.

A driver can associate an IoTimer routine with each device object it creates. (You can use a single IoTimer routine with multiple device objects, or a separate routine with each device object.) To register an IoTimer routine, a driver must call IoInitializeTimer, supplying the IoTimer routine's address and a device object pointer.

To queue an IoTimer routine for execution, a driver routine must call IoStartTimer. The system calls the IoTimer routine once per second until the driver calls IoStopTimer.

For more information about IoTimer routines, see IoTimer Routines.


Reinitialize

Reinitialize continues driver and device initialization after the driver's DriverEntry routine returns.

VOID
  Reinitialize(
    IN PDRIVER_OBJECT  DriverObject,
    IN PVOID  Context,
    IN ULONG  Count
    );

Parameters

DriverObject
Caller-supplied pointer to a DRIVER_OBJECT structure. This is the driver's driver object.
Context
Caller-supplied pointer to context information, specified in a previous call to IoRegisterDriverReinitialization.
Count
Caller-supplied value representing the number of times the Reinitialize routine has been called, including the current call.

Return Value

None

Comments

A driver's Reinitialize routine executes in a system thread context at IRQL PASSIVE_LEVEL.

To queue a Reinitialize routine for execution, a driver's DriverEntry routine must call IoRegisterDriverReinitialization. The Reinitialize routine can also call IoRegisterDriverReinitialization itself, which causes the routine to be re-queued. This re-queuing can occur multiple times, and the routine's Count parameter indicates the number of times it has been called. The first call to IoRegisterDriverReinitialization must be made from DriverEntry, and DriverEntry must return STATUS_SUCCESS.

For more information about implementing a Reinitialize routine, see Writing a Reinitialize Routine.


StartIo

StartIo starts the I/O operation described by an IRP.

NTSTATUS
  XxxStartIo(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure. This is the device object for the target device, previously created by the driver's AddDevice routine.
Irp
Caller-supplied pointer to an IRP structure that describes the requested I/O operation.

Return Value

If the routine succeeds, it must return STATUS_SUCCESS. Otherwise, it must return one of the error status values defined in ntstatus.h.

Comments

A driver's StartIo routine executes in an arbitrary thread context at IRQL DISPATCH_LEVEL.

The StartIo routine is optional. A driver's StartIo routine, if supplied, should be named Xxx StartIo, where Xxx is a driver-specific prefix. The driver's DriverEntry routine must store the StartIo routine's address in DriverObject->DriverStartIo. (If no routine is supplied, this pointer must be NULL.)

A driver can use IoSetStartIoAttributes to set attributes on when it's StartIo routine is called.

For detailed information about implementing a driver's StartIo routine, see Writing a StartIo Routine.


SynchCritSection

SynchCritSection is used to access hardware resources or driver data that are shared with a driver's InterruptService routine.

BOOLEAN
  SynchCritSection(
    IN PVOID  SynchronizeContext
    );

Parameters

SynchronizeContext
Caller-supplied context information, specified by the driver's call to KeSynchronizeExecution.

Return Value

If the routine's operation succeeds, the routine should return TRUE; otherwise, it should return FALSE. (Success and failure of this routine are driver-defined.) The specified return value becomes the return value for KeSynchronizeExecution.

Comments

Drivers must use SynchCritSection routines to access hardware resources or driver data that can also be accessed by an InterruptService routine (ISR).

The system calls a driver's SynchCritSection routine when the driver calls KeSynchronizeExecution. When a driver calls KeSynchronizeExecution, it specifies the address of a SynchCritSection routine, context information for the routine, and an interrupt object pointer. The KeSynchronizeExecution routine acquires the interrupt object's spin lock, then calls the SynchCritSection routine.

A driver's SynchCritSection routine executes at the same IRQL as the ISR with which it is associated. Specifically, it executes at some system-assigned DIRQL, as specified by the SynchronizeIrql parameter to IoConnectInterrupt. (Other devices, with higher DIRQL values, can interrupt a SynchCritSection routine.)


Unload

Unload performs any operations that are necessary before the system unloads the driver.

VOID
  XxxUnload(
    IN PDRIVER_OBJECT  DriverObject
    );

Parameters

DriverObject
Caller-supplied pointer to a DRIVER_OBJECT structure. This is the driver's driver object.

Return Value

None

Comments

A driver's Unload routine executes in a system thread context at IRQL PASSIVE_LEVEL.

The Unload routine is optional. A driver's Unload routine, if supplied, should be named Xxx Unload, where Xxx is a driver-specific prefix. The driver's DriverEntry routine must store the Unload routine's address in DriverObject->DriverUnload. (If no routine is supplied, this pointer must be NULL.)

For detailed information about implementing a driver's Unload routine, see Writing an Unload Routine.


Summary of Kernel-Mode Support Routines

This chapter summarizes the kernel-mode support routines that can be called by kernel-mode drivers. Drivers can also use routines provided by a compiler, such as C string manipulation routines.

Support routines are categorized as follows:

  • Initialization and Unload
  • IRPs
  • Synchronization
  • Memory
  • DMA
  • PIO
  • Driver-Managed Queues
  • Driver-dedicated system threads and system worker threads in Driver System Threads
  • Strings
  • Data Conversions
  • Access to and access rights on driver-managed objects in Access to Driver-managed Objects
  • Error Handling

Some routines are listed in more than one section or subsection of this chapter.


Initialization and Unload

This section summarizes kernel-mode support routines that can be called by drivers from their DriverEntry, AddDevice, Reinitialize, or Unload routines.

The categories of kernel-mode support routines include those that drivers can call to:

  • Get and report hardware configuration information about their devices and the current platform in Hardware Configuration
  • Get and report configuration information and register interfaces in the registry in Registry
  • Set up and free the objects and resources they might use in Objects and Resources
  • Initialize driver-managed internal queues in Initializing Driver-Managed Queues


Hardware Configuration

IoGetDeviceProperty
Retrieves device setup information from the registry. Use this routine, rather than accessing the registry directly, to insulate a driver from differences across platforms and from possible changes in the registry structure.
IoReportDetectedDevice
Reports a nonPnP device to the PnP Manager.
IoReportResourceForDetection
Claims hardware resources in the configuration registry for a legacy device. This routine is for drivers that detect legacy hardware which cannot be enumerated by PnP.
IoGetDmaAdapter
Returns a pointer to the DMA adapter structure that represents either the DMA channel to which a device is connected or the driver's busmaster adapter.
IoGetConfigurationInformation
Returns a pointer to the I/O Manager's configuration information structure, which indicates the number of disk, floppy, CD-ROM, tape, SCSI HBAs, serial, and parallel device objects that have already been named by previously loaded drivers, as well as whether certain address ranges have been claimed by "AT" disk-type drivers.
HalExamineMBR
Returns data from the master boot record (MBR) of a disk.
IoReadPartitionTable
Returns a list of partitions on a disk with a given sector size.
IoInvalidateDeviceRelations
Notifies the PnP manager that the relations for a device have changed. The types of device relations include bus relations, ejection relations, removal relations, and the target device relation.
IoInvalidateDeviceState
Notifies the PnP manager that some aspect of the PnP state of a device has changed. In response, the PnP Manager sends an IRP_MN_QUERY_PNP_DEVICE_STATE to the device stack.
IoRegisterPlugPlayNotification
Registers a driver callback routine to be called when a PnP event of the specified category occurs.
IoUnregisterPlugPlayNotification
Removes the registration of a driver's callback routine for a PnP event.
IoRequestDeviceEject
Notifies the PnP Manager that the device eject button was pressed. This routine reports a request for device eject, not media eject.
IoReportTargetDeviceChange
Notifies the PnP Manager that a custom event has occurred on a device. The PnP Manager sends notification of the event to drivers that registered for notification on the device.


Registry

IoGetDeviceProperty
Retrieves device setup information from the registry. Use this routine, rather than accessing the registry directly, to insulate a driver from differences across platforms and from possible changes in the registry structure.
IoOpenDeviceInterfaceRegistryKey
Returns a handle to a registry key for storing information about a particular device interface.
IoOpenDeviceRegistryKey
Returns a handle to a device-specific or a driver-specific registry key for a particular device instance.
IoRegisterDeviceInterface
Registers device functionality (a device interface) that a driver will enable for use by applications or other system components. The I/O Manager creates a registry key for the device interface. Drivers can access persistent storage under this key using IoOpenDeviceInterfaceRegistryKey.
IoSetDeviceInterfaceState
Enables or disables a previously registered device interface. Applications and other system components can open only interfaces that are enabled.
RtlCheckRegistryKey
Returns STATUS_SUCCESS if a key exists in the registry along the given relative path.
RtlCreateRegistryKey
Adds a key object in the registry along the given relative path.
RtlQueryRegistryValues
Gives the driver-supplied QueryRegistry callback (read only) access to the entries for the specified value name along the specified relative path in the registry after the QueryRegistry routine is given control.
RtlWriteRegistryValue
Writes caller-supplied data into the registry along the specified relative path at the given value name.
RtlDeleteRegistryValue
Removes the specified value name (and the associated value entries) from the registry along the given relative path.
InitializeObjectAttributes
Sets up a parameter of type OBJECT_ATTRIBUTES for a subsequent call to a ZwCreate Xxx or ZwOpen Xxx routine.
ZwCreateKey
Creates a new key in the registry with the given object's attributes, allowed access, and creation options (such as whether the key is created again when the system is booted). Alternatively, opens an existing key and returns a handle for the key object.
ZwOpenKey
Returns a handle for a key in the registry given the object's attributes (which must include a name for the key) and the desired access to the object.
ZwQueryKey
Returns information about the class of a key, and the number and sizes of its subkeys. This information includes, for example, the length of subkey names and the size of value entries.
ZwEnumerateKey
Returns the specified information about the subkeys of an opened key in the registry.
ZwEnumerateValueKey
Returns the specified information about the value entry, as selected by a zero-based index, of an opened key in the registry.
ZwQueryValueKey
Returns the value entry, as selected by a czero-based index, for an opened key in the registry.
ZwSetValueKey
Replaces (or creates) a value entry for an opened key in the registry.
ZwFlushKey
Forces changes made by ZwCreateKey or ZwSetValueKey for the opened key object to be written to disk.
ZwDeleteKey
Removes a key and its value entries from the registry as soon as the key is closed.
ZwClose
Releases the handle for an opened object, causing the handle to become invalid and decrementing the reference count of the object handle.


Objects and Resources

IoCreateDevice
Initializes a device object, which represents a physical, virtual, or logical device for which the driver is being loaded into the system. Then it allocates space for the driver-defined device extension associated with the device object.
IoDeleteDevice
Removes a device object from the system when the underlying device is removed from the system.
IoGetDeviceObjectPointer
Requests access to a named device object and returns a pointer that device object if the requested access is granted. Also returns a pointer to the file object referenced by the named device object. In effect, this routine establishes a connection between the caller and the next-lower-level driver.
IoAttachDeviceToDeviceStack
Attaches the caller's device object to the highest device object in a chain of drivers and returns a pointer to the previously highest device object. I/O requests bound for the target device are routed first to the caller.
IoGetAttachedDeviceReference
Returns a pointer to the highest level device object in a driver stack and increments the reference count on that object.
IoDetachDevice
Releases an attachment between the caller's device object and a target driver's device object.
IoAllocateDriverObjectExtension
Allocates a per-driver context area with a given unique identifier.
IoGetDriverObjectExtension
Retrieves a previously allocated per-driver context area.
IoRegisterDeviceInterface
Registers device functionality (a device interface) that a driver will enable for use by applications or other system components. The I/O Manager creates a registry key for the device interface. Drivers can access persistent storage under this key using IoOpenDeviceInterfaceRegistryKey.
IoIsWdmVersionAvailable
Checks whether a given WDM version is supported by the operating system.
IoDeleteSymbolicLink
Releases a symbolic link between a device object name and a user-visible name.
IoAssignArcName
Sets up a symbolic link between a named device object (such as a tape, floppy, or CD-ROM) and the corresponding ARC name for the device.
IoDeassignArcName
Releases the symbolic link created by calling IoAssignArcName.
IoSetShareAccess
Sets the access allowed to a given file object that represents a device. (Only highest-level drivers can call this routine.)
IoConnectInterrupt
Registers a driver's ISR according to the parameters supplied in the IRP_MN_START_DEVICE request. Returns a pointer to a set of allocated, initialized, and connected interrupt objects that is used as an argument to KeSynchronizeExecution.
IoDisconnectInterrupt
Releases a driver's interrupt objects when the driver unloads.
IoInitializeDpcRequest
Associates a driver-supplied DpcForIsr routine with a given device object, so that the DpcForIsr can complete interrupt-driven I/O operations.
IoReadPartitionTable
Returns a list of partitions on a disk with a given sector size.
IoSetPartitionInformation
Sets the partition type and number for a (disk) partition.
IoWritePartitionTable
Writes partition tables for a disk, given the device object that represents the disk, the sector size, and a pointer to a buffer containing the drive layout structure.
IoCreateController
Initializes a controller object that represents a physical device controller which is shared by two or more similar devices that have the same driver, and specifies the size of the controller extension.
IoDeleteController
Removes a controller object from the system.
KeInitializeSpinLock
Initializes a variable of type KSPIN_LOCK.
KeInitializeDpc
Initializes a DPC object, setting up a driver-supplied CustomDpc routine that can be called with a given context.
KeInitializeTimer
Initializes a notification timer object to the Not-Signaled state.
KeInitializeTimerEx
Initializes a notification or synchronization timer object to the Not-Signaled state.
KeInitializeEvent
Initializes an event object as a synchronization (single waiter) or notification (multiple waiters) type event and sets up its initial state (Signaled or Not-Signaled).
ExInitializeFastMutex
Initializes a fast mutex variable that is used to synchronize mutually exclusive access to a shared resource by a set of threads.
KeInitializeMutex
Initializes a mutex object at a given level number as set to the Signaled state.
KeInitializeSemaphore
Initializes a semaphore object to a given count and specifies an upper bound for the count.
IoCreateNotificationEvent
Initializes a named notification event to be used to synchronize access between two or more components. Notification events are not automatically reset.
IoCreateSynchronizationEvent
Initializes a named synchronization event to be used to serialize access to hardware between two otherwise unrelated drivers.
PsCreateSystemThread
Creates a kernel-mode thread that is associated with a given process object or with the default system process. Returns a handle for the thread.
PsTerminateSystemThread
Terminates the current thread and satisfies as many waits as possible for the current thread object.
KeSetBasePriorityThread
Sets up the run-time priority, relative to the system process, for a driver-created thread.
KeSetPriorityThread
Sets up the run-time priority for a driver-created thread with a real-time priority attribute.
MmIsThisAnNtAsSystem
Returns TRUE if the current platform is a server, indicating that more resources are likely to be necessary to process I/O requests than if the machine were a client.
MmQuerySystemSize
Returns an estimate (small, medium, or large) of the amount of memory available on the current platform.
ExInitializeNPagedLookasideList
Initializes a lookaside list of nonpaged memory. After a successful initialization, fixed-size blocks can be allocated from and freed to the lookaside list.
ExInitializePagedLookasideList
Initializes a lookaside list of paged memory. After a successful initialization, fixed-size blocks can be allocated from and freed to the lookaside list.
ExInitializeResourceLite
Initializes a resource, for which the caller provides the storage, to be used for synchronization by a set of threads.
ExReinitializeResourceLite
Reinitializes an existing resource variable.
ExDeleteResourceLite
Deletes a caller-initialized resource from the system's resource list.
ObReferenceObjectByHandle
Returns a pointer to the object body and handle information (attributes and granted access rights), given the handle for an object, the object's type, and a mask. Specifies the desired access to the object and the preferred access mode. A successful call increments the reference count for the object.
ObReferenceObjectByPointer
Increments the reference count for an object so the caller can ensure that the object is not removed from the system while the caller is using it.
ObReferenceObject
Increments the reference count for an object, given a pointer to the object.
ObDereferenceObject
Releases a reference to an object (decrements the reference count), given a pointer to the object body.
RtlInitString
Initializes a counted string in a buffer.
RtlInitAnsiString
Initializes a counted ANSI string in a buffer.
RtlInitUnicodeString
Initializes a counted Unicode string in a buffer.
InitializeObjectAttributes
Initializes a parameter of type OBJECT_ATTRIBUTES for a subsequent call to a ZwCreate Xxx or ZwOpen Xxx routine.
ZwCreateDirectoryObject
Creates or opens a directory object with a specified set of object attributes and requests one or more types of access for the caller. Returns a handle for the directory object.
ZwCreateFile
Creates or opens a file object that represents a physical, logical, or virtual device, a directory, a data file, or a volume. Returns a handle for the file object.
ZwCreateKey
Creates or opens a key object in the registry and returns a handle for the key object.
ZwDeleteKey
Deletes an existing, open key in the registry after the last handle for the key is closed.
ZwMakeTemporaryObject
Resets the "permanent" attribute of an opened object, so that the object and its name can be deleted when the reference count for the object becomes zero.
ZwClose
Releases the handle for an opened object, causing the handle to become invalid, and decrements the reference count of the object handle.
PsGetVersion
Indicates whether the driver is running on a free or checked build, and optionally supplies information about the operating system version and build number.
ObGetObjectSecurity
Returns a buffered security descriptor for a given object.
ObReleaseObjectSecurity
Releases the security descriptor returned by ObGetObjectSecurity.


Initializing Driver-Managed Queues

KeInitializeSpinLock
Initializes a variable of type KSPIN_LOCK. An initialized spin lock is a required parameter to the ExXxxInterlockedList routines.
InitializeListHead
Sets up a queue header for a driver's internal queue, given a pointer to driver-supplied storage for the queue header and queue.
ExInitializeSListHead
Sets up the queue header for a sequenced, interlocked, singly-linked list.
KeInitializeDeviceQueue
Initializes a device queue object to a Not Busy state, setting up an associated spin lock for multiprocessor-safe access to device queue entries.
IoCsqInitialize
Initializes the dispatch table for a driver's cancel-safe IRP queue.


IRPs

This section describes kernel-mode support routines that drivers can call:

  • While processing IRPs in Processing IRPs
  • To allocate and set up IRPs for requests from higher-level drivers to lower drivers in Driver-Allocated IRPs
  • To use file objects in File Objects


Processing IRPs

IoGetCurrentIrpStackLocation
Returns a pointer to the caller's I/O stack location in a given IRP.
IoGetNextIrpStackLocation
Returns a pointer to the next-lower-level driver's I/O stack location in a given IRP.
IoCopyCurrentIrpStackLocationToNext
Copies the IRP stack parameters from the current stack location to the stack location of the next-lower driver and allows the current driver to set an I/O completion routine.
IoSkipCurrentIrpStackLocation
Copies the IRP stack parameters from the current stack location to the stack location of the next-lower driver and does not allow the current driver to set an I/O completion routine.
IoGetRelatedDeviceObject
Returns a pointer to the device object represented by a given file object.
IoGetFunctionCodeFromCtlCode
Returns the value of the function field within a given IOCTL_XXX or FSCTL_XXX.
IoSetCompletionRoutine
Registers a driver-supplied IoCompletion routine for an IRP, so the IoCompletion routine is called when the next-lower-level driver has completed the requested operation in one or more of the following ways: successfully, with an error, or by canceling the IRP.
IoSetCompletionRoutineEx
Same as IoSetCompletionRoutine, except that it guarantees a non-Plug and Play driver is not unloaded before the IoCompletion routine exits.
IoCallDriver
Sends an IRP to a lower-level driver.
PoCallDriver
Sends an IRP with major function code IRP_MJ_POWER to the next-lower driver.
IoMarkIrpPending
Marks a given IRP indicating that STATUS_PENDING was returned because further processing is required by another driver routine or by a lower-level driver.
IoStartPacket
Calls the driver's StartIo routine with the given IRP for the given device object or inserts the IRP into the device queue if the device is already busy, specifying whether the IRP is cancelable.
IoSetStartIoAttributes
Sets attributes for when the driver's StartIo routine will execute.
IoAcquireCancelSpinLock
Synchronizes cancelable state transitions for IRPs in a multiprocessor-safe manner.
IoSetCancelRoutine
Sets or clears the Cancel routine in an IRP. Setting a Cancel routine makes an IRP cancelable.
IoReleaseCancelSpinLock
Releases the cancel spin lock when the driver has changed the cancelable state of an IRP or releases the cancel spin lock from the driver's Cancel routine.
IoCancelIrp
Marks an IRP as canceled.
IoReadPartitionTable
Returns a list of partitions on a disk with a given sector size.
IoSetPartitionInformation
Sets the partition type and number for a (disk) partition.
IoWritePartitionTable
Writes partition tables for a disk, given the device object representing the disk, the sector size, and a pointer to a buffer containing the drive geometry.
IoAllocateErrorLogEntry
Allocates and initializes an error log packet; returns a pointer so that the caller can supply error-log data and call IoWriteErrorLogEntry with the packet.
IoWriteErrorLogEntry
Queues a previously allocated and filled-in error log packet to the system error logging thread.
IoIsErrorUserInduced
Returns a Boolean value indicating whether an I/O request failed due to one of the following conditions: STATUS_IO_TIMEOUT, STATUS_DEVICE_NOT_READY, STATUS_UNRECOGNIZED_MEDIA, STATUS_VERIFY_REQUIRED, STATUS_WRONG_VOLUME, STATUS_MEDIA_WRITE_PROTECTED, or STATUS_NO_MEDIA_IN_DEVICE. If the result is TRUE, a removable-media driver must call IoSetHardErrorOrVerifyDevice before completing the IRP.
IoSetHardErrorOrVerifyDevice
Supplies the device object for which the given IRP was failed due to a user-induced error, such as supplying the incorrect media for the requested operation or changing the media before the requested operation was completed. A file system driver uses the associated device object to notify the user, who can then correct the error or retry the operation.
IoGetDeviceToVerify
Returns a pointer to the device object, representing a removable-media device that is the target of the given thread's I/O request. Useful only to file systems or other highest-level drivers.
IoRaiseHardError
Notifies the user that the given IRP was failed on the given device object for an optional VPB, so that the user can correct the error or retry the operation.
IoRaiseInformationalHardError
Notifies the user of an error, providing an I/O error status and an optional string supplying more information.
ExRaiseStatus
Raises an error status and causes a caller-supplied structured exception handler to be called. Useful only to highest-level drivers that supply exception handlers, in particular to file systems.
IoStartNextPacket
Dequeues the next IRP for a given device object, specifies whether the IRP is cancelable, and calls the driver's StartIo routine.
IoStartNextPacketByKey
Dequeues the next IRP for a device object according to a specified sort-key value, specifies whether the IRP is cancelable, and calls the driver's StartIo routine.
IoCompleteRequest
Completes an I/O request, giving a priority boost to the original caller and returning a given IRP to the I/O system for disposal: either to call any IoCompletion routines supplied by higher-level drivers, or to return status to the original requester of the operation.
IoGetCurrentProcess
Returns a pointer to the current process. Useful only to highest-level drivers.
IoGetInitialStack
Returns the initial base address of the current thread's stack. Useful only to highest-level drivers.
IoGetRemainingStackSize
Returns the amount of available stack space. Useful only to highest-level drivers.
IoGetStackLimits
Returns the boundaries of the current thread's stack frame. Useful only to highest-level drivers.
IoCsqInitialize
Initializes the dispatch table for a driver's cancel-safe IRP queue.
IoCsqInsertIrp
Inserts an IRP into a driver's cancel-safe IRP queue.
IoCsqRemoveIrp
Removes the specified IRP from a driver's cancel-safe IRP queue.
IoCsqRemoveNextIrp
Removes the next IRP from a driver's cancel-safe IRP queue.


Driver-Allocated IRPs

IoBuildAsynchronousFsdRequest
Allocates and sets up an IRP that specifies a major function code (IRP_MJ_PNP, IRP_MJ_READ, IRP_MJ_WRITE, IRP_MJ_SHUTDOWN, or IRP_MJ_FLUSH_BUFFERS) with a pointer to:
  • The lower driver's device object on which the I/O should occur
  • A pointer to a buffer which will contain the data to be read or which contains the data to be written
  • The length of the buffer in bytes
  • The starting offset on the media
  • The I/O status block where the called driver can return status information and the caller's IoCompletion routine can access it.

Returns a pointer to the IRP so the caller can set any necessary minor function code and set up its IoCompletion routine before sending the IRP to the target driver.

IoBuildSynchronousFsdRequest
Allocates and sets up an IRP specifying a major function code (IRP_MJ_PNP, IRP_MJ_READ, IRP_MJ_WRITE, IRP_MJ_SHUTDOWN, or IRP_MJ_FLUSH_BUFFERS) with a pointer to:
  • The lower driver's device object on which the I/O should occur;
  • A buffer which will contain the data to be read or which contains the data to be written
  • The length of the buffer in bytes,
  • The starting offset on the media;
  • An event object to be set to the Signaled state when the requested operation completes
  • The I/O status block where the called driver can return status information and the caller's IoCompletion routine can access it.

Returns a pointer to the IRP so the caller can set any necessary minor function code and set up its IoCompletion routine before sending the IRP to the target driver.

IoBuildDeviceIoControlRequest
Allocates and sets up an IRP specifying a major function code (either IRP_MJ_INTERNAL_DEVICE_CONTROL or IRP_MJ_DEVICE_CONTROL) with an optional input or output buffer; a pointer to the lower driver's device object; an event to be set to the Signaled state when the requested operation completes; and an I/O status block to be set by the driver that receives the IRP. Returns a pointer to the IRP so the caller can set the appropriate IOCTL_XXX before sending the IRP to the next-lower-level driver.
PoRequestPowerIrp
Allocates and initializes an IRP with major function code IRP_MJ_POWER and then sends the IRP to the top-level driver in the device stack for the specified device object.
IoSizeOfIrp
Returns the size in bytes required for an IRP with a given count of I/O stack locations.
IoAllocateIrp
Allocates an IRP, given the number of I/O stack locations (optionally, for the caller, but at least one for each driver layered under the caller) and whether to charge quota against the caller. Returns a pointer to an IRP in nonpaged system space if successful; otherwise, returns NULL.
IoInitializeIrp
Initializes an IRP, given a pointer to an already allocated IRP, its length in bytes, and its number of I/O stack locations.
IoSetNextIrpStackLocation
Sets the current IRP stack location to the caller's location in an IRP. The stack location must have been allocated by a preceding call to IoAllocateIrp that specified a stack-size argument large enough to give the caller its own stack location.
IoAllocateMdl
Allocates an MDL large enough to map the starting address and length supplied by the caller; optionally associates the MDL with a given IRP.
IoBuildPartialMdl
Builds an MDL for the specified starting virtual address and length in bytes from a given source MDL. Drivers that split large transfer requests into a number of smaller transfers can call this routine.
IoFreeMdl
Releases a given MDL allocated by the caller.
IoMakeAssociatedIrp
Allocates and initializes an IRP to be associated with a master IRP sent to the highest-level driver, allowing the driver to "split" the original request and send associated IRPs on to lower-level drivers or to the device.
IoSetCompletionRoutine
Registers a driver-supplied IoCompletion routine with a given IRP, so that the IoCompletion routine is called when lower-level drivers have completed the request. The IoCompletion routine lets the caller release the IRP it allocated with IoAllocateIrp or IoBuildAsynchronousFsdRequest; to release any other resources it allocated to set up an IRP for lower drivers; and to perform any I/O completion processing necessary.
IoSetCompletionRoutineEx
Same as IoSetCompletionRoutine, except that it guarantees a non-Plug and Play driver is not unloaded before the IoCompletion routine exits.
IoCallDriver
Sends an IRP to a lower-level driver.
IoFreeIrp
Releases an IRP that was allocated by the caller.
IoReuseIrp
Reinitializes for reuse an IRP that was previously allocated by IoAllocateIrp.


File Objects

InitializeObjectAttributes
Initializes a parameter of type OBJECT_ATTRIBUTES for a subsequent call to a ZwCreate Xxx or ZwOpen Xxx routine.
ZwCreateFile
Creates or opens a file object representing a physical, logical, or virtual device, a directory, a data file, or a volume.
ZwQueryInformationFile
Returns information about the state or attributes of an open file.
IoGetFileObjectGenericMapping
Returns information about the mapping between generic access rights and specific access rights for file objects.
ZwReadFile
Returns data from an open file.
ZwSetInformationFile
Changes information about the state or attributes of an open file.
ZwWriteFile
Transfers data to an open file.
ZwClose
Releases the handle for an opened object, causing the handle to become invalid and decrementing the reference count of the object handle.


Synchronization

This section describes the kernel-mode support routines that drivers can call to:

  • Synchronize the execution of their own standard driver routines in Driver Routines and I/O Objects
  • Temporarily change the current IRQL for a call to a support routine or that return the current IRQL in IRQL
  • Synchronize access to resources with spin locks or to perform interlocked operations without spinlocks in Spin Locks and Interlocks
  • Manage time-outs or determine system time in Timers
  • Use system threads or to manage synchronization within a non-arbitrary thread context in Driver Threads, Dispatcher Objects, and Resources


Driver Routines and I/O Objects

KeSynchronizeExecution
Synchronizes the execution of a driver-supplied SynchCritSection routine with that of the ISR associated with a set of interrupt objects, given a pointer to the interrupt objects.
IoRequestDpc
Queues a driver-supplied DpcForIsr routine to complete interrupt-driven I/O processing at a lower IRQL.
KeInsertQueueDpc
Queues a DPC to be executed as soon as the IRQL of a processor drops below DISPATCH_LEVEL; returns FALSE if the DPC object is already queued.
KeRemoveQueueDpc
Removes a given DPC object from the DPC queue; returns FALSE if the object is not in the queue.
KeSetImportanceDpc
Controls how a particular DCP is queued and, to some degree, how soon the DPC routine is run.
KeSetTargetProcessorDpc
Controls on which processor a particular DCP subsequently will be queued.
AllocateAdapterChannel
Connects a device object to an adapter object and calls a driver-supplied AdapterControl routine to carry out an I/O operation through the system DMA controller or a busmaster adapter as soon as the appropriate DMA channel and any necessary map registers are available. (This routine reserves exclusive access to a DMA channel and map registers for the specified device.)
FreeAdapterChannel
Releases an adapter object, representing a system DMA channel, and optionally releases map registers, if any were allocated.
FreeMapRegisters
Releases a set of map registers that were saved from a call to AllocateAdapterChannel, after the registers have been used by IoMapTransfer and the busmaster DMA transfer is complete.
IoAllocateController
Connects a device object to a controller object and calls a driver-supplied ControllerControl routine to carry out an I/O operation on the device controller as soon as the controller is not busy. (This routine reserves exclusive access to the hardware controller for the specified device.)
IoFreeController
Releases a controller object, provided that all device operations queued to the controller for the current IRP have completed.
IoStartTimer
Enables the timer for a given device object and calls the driver-supplied IoTimer routine once per second thereafter.
IoStopTimer
Disables the timer for a given device object so that the driver-supplied IoTimer routine is not called unless the driver re-enables the timer.
KeSetTimer
Sets the absolute or relative interval at which a timer object will be set to the Signaled state and optionally supplies a timer DPC to be executed after the interval expires.
KeSetTimerEx
Sets the absolute or relative interval at which a timer object will be set to the Signaled state, optionally supplies a timer DPC to be executed when the interval expires, and optionally supplies a recurring interval for the timer.
KeCancelTimer
Cancels a timer object before the interval passed to KeSetTimer expires; dequeues a timer DPC before the timer interval, if any was set, expires.
KeReadStateTimer
Returns whether a given timer object is set to the Signaled state.
IoStartPacket
Calls the driver's StartIo routine with the given IRP for the given device object or inserts the IRP into the device queue if the device is already busy, specifying whether the IRP is cancelable.
IoStartNextPacket
Dequeues the next IRP for a given device object, specifying whether the IRP is cancelable, and calls the driver's StartIo routine.
IoStartNextPacketByKey
Dequeues the next IRP, according to the specified sort-key value, for a given device object. Specifies whether the IRP is cancelable and calls the driver's StartIo routine.
IoSetCompletionRoutine
Registers a driver-supplied IoCompletion routine with a given IRP, so the IoCompletion routine is called when the next-lower-level driver has completed the requested operation in one or more of the following ways: successfully, with an error, or by cancelling the IRP.
IoSetCompletionRoutineEx
Same as IoSetCompletionRoutine, except that it guarantees a non-Plug and Play driver is not unloaded before the IoCompletion routine exits.
IoSetCancelRoutine
Sets or clears the Cancel routine in an IRP. Setting a Cancel routine makes an IRP cancelable.
KeStallExecutionProcessor
Stalls the caller (a device driver) for a given interval on the current processor.
ExAcquireResourceExclusiveLite
Acquires an initialized resource for exclusive access by the calling thread and optionally waits for the resource to be acquired.
ExTryToAcquireResourceExclusiveLite
Acquires a given resource for exclusive access immediately or returns FALSE.
ExAcquireResourceSharedLite
Acquires an initialized resource for shared access by the calling thread and optionally waits for the resource to be acquired.
ExAcquireSharedStarveExclusive
Acquires a given resource for shared access without waiting for any pending attempts to acquire exclusive access to the same resource.
ExAcquireSharedWaitForExclusive
Acquires a given resource for shared access, optionally waiting for any pending exclusive waiters to acquire and release the resource first.
ExReleaseResourceForThreadLite
Releases a given resource that was acquired by the given thread.
ZwReadFile
Reads data from an open file. If the caller opened the file object with certain parameters, the caller can wait on the file handle for completion of the I/O.
ZwWriteFile
Writes data to an open file. If the caller opened the file object with certain parameters, the caller can wait on the file handle for completion of the I/O.


IRQL

KeRaiseIrql
Raises the hardware priority to a given IRQL value, thereby masking off interrupts of equivalent or lower IRQL on the current processor.
KeRaiseIrqlToDpcLevel
Raises the hardware priority to IRQL DISPATCH_LEVEL, thereby masking off interrupts of equivalent or lower IRQL on the current processor.
KeLowerIrql
Restores the IRQL on the current processor to its original value.
KeGetCurrentIrql
Returns the current hardware priority IRQL value.


Spin Locks and Interlocks

IoAcquireCancelSpinLock
Synchronizes cancelable state transitions for IRPs in a multiprocessor-safe manner.
IoSetCancelRoutine
Sets or clears the Cancel routine in an IRP during a cancelable state transition. Setting a Cancel routine makes an IRP cancelable.
IoReleaseCancelSpinLock
Releases the cancel spin lock when the driver has changed the cancelable state of an IRP or releases the cancel spin lock from the driver's Cancel routine.
KeInitializeSpinLock
Initializes a variable of type KSPIN_LOCK, used to synchronize access to data shared among nonISR routines. An initialized spin lock also is a required parameter to the ExInterlocked Xxx routines.
KeAcquireSpinLock
Acquires a spin lock so the caller can synchronize access to shared data safely on multiprocessor platforms.
KeReleaseSpinLock
Releases a spin lock that was acquired by calling KeAcquireSpinLock and restores the original IRQL at which the caller was running.
KeAcquireSpinLockAtDpcLevel
Acquires a spin lock, provided that the caller is already running at IRQL DISPATCH_LEVEL.
KeReleaseSpinLockFromDpcLevel
Releases a spin lock that was acquired by calling KeAcquireSpinLockAtDpcLevel.
KeAcquireInStackQueuedSpinLock
Acquires a queued spin lock so the caller can synchronize access to shared data safely on multiprocessor platforms.
KeReleaseInStackQueuedSpinLock
Releases a queued spin lock that was acquired by calling KeAcquireInStackQueuedSpinLock.
KeAcquireInStackQueuedSpinLockAtDpcLevel
Acquires a queued spin lock, provided that the caller is already running at IRQL DISPATCH_LEVEL.
KeReleaseInStackQueuedSpinLockFromDpcLevel
Releases a queued spin lock that was acquired by calling KeAcquireInStackQueuedSpinLockAtDpcLevel.
ExInterlockedXxxList
Insert and remove IRPs in a driver-managed internal queue, which is protected by an initialized spin lock for which the driver provides the storage.
KeXxxDeviceQueue
Insert and remove IRPs in a driver-allocated and managed internal device queue object, which is protected by a built-in spin lock.
ExInterlockedAddUlong
Adds a value to a variable of type ULONG as an atomic operation, using a spin lock to ensure multiprocessor-safe access to the variable; returns the value of the variable before the call occurred.
ExInterlockedAddLargeInteger
Adds a value to a variable of type LARGE_INTEGER as an atomic operation, using a spin lock to ensure multiprocessor-safe access to the variable; returns the value of the variable before the call occurred.
InterlockedIncrement
Increments a variable of type LONG as an atomic operation. The sign of the return value is the sign of the result of the operation.
InterlockedDecrement
Decrements a variable of type LONG as an atomic operation. The sign of the return value is the sign of the result of the operation.
InterlockedExchange
Sets a variable of type LONG to a specified value as an atomic operation; returns the value of the variable before the call occurred.
InterlockedExchangeAdd
Adds a value to a given integer variable as an atomic operation; returns the value of the variable before the call occurred.
InterlockedCompareExchange
Compares the values referenced by two pointers. If the values are equal, resets one of the values to a caller-supplied value in an atomic operation.
InterlockedCompareExchangePointer
Compares the pointers referenced by two pointers. If the pointer values are equal, resets one of the values to a caller-supplied value in an atomic operation.
ExInterlockedCompareExchange64
Compares one integer variable to another and, if they are equal, resets the first variable to a caller-supplied ULONGLONG-type value as an atomic operation.
KeGetCurrentProcessorNumber
Returns the current processor number when debugging spin lock usage in SMP machines.


Timers

IoInitializeTimer
Associates a timer with the given device object and registers a driver-supplied IoTimer routine for the device object.
IoStartTimer
Enables the timer for a given device object and calls the driver-supplied IoTimer routine once every second.
IoStopTimer
Disables the timer for a given device object so the driver-supplied IoTimer routine is not called unless the driver re-enables the timer.
KeInitializeDpc
Initializes a DPC object and sets up a driver-supplied CustomTimerDpc routine that can be called with a given context.
KeInitializeTimer
Initializes a notification timer object to the Not-Signaled state.
KeInitializeTimerEx
Initializes a notification or synchronization timer object to the Not-Signaled state.
KeSetTimer
Sets the absolute or relative interval at which a timer object will be set to the Signaled state; optionally supplies a timer DPC to be executed when the interval expires.
KeSetTimerEx
Sets the absolute or relative interval at which a timer object will be set to the Signaled state; optionally supplies a timer DPC to be executed when the interval expires; and optionally supplies a recurring interval for the timer.
KeCancelTimer
Cancels a timer object before the interval passed to KeSetTimer expires; dequeues a timer DPC before the timer interval, if any was set, expires.
KeReadStateTimer
Returns TRUE if a given timer object is set to the Signaled state.
KeQuerySystemTime
Returns the current system time.
KeQueryTickCount
Returns the number of interval-timer interrupts that have occurred since the system was booted.
KeQueryTimeIncrement
Returns the number of 100-nanosecond units that are added to the system time at each interval-timer interrupt.
KeQueryInterruptTime
Returns the current value of the system interrupt-time count in 100-nanosecond units.
KeQueryPerformanceCounter
Returns the system performance counter value in hertz.


Driver Threads Dispatcher Objects and Resources

Previous Next

Driver Threads, Dispatcher Objects, and Resources

KeDelayExecutionThread
Puts the current thread into an alertable or nonalertable wait state for a given interval.
ExInitializeResourceLite
Initializes a resource, for which the caller provides the storage, to be used for synchronization by a set of threads (shared readers, exclusive writers).
ExReinitializeResourceLite
Reinitializes an existing resource variable.
ExAcquireResourceExclusiveLite
Acquires an initialized resource for exclusive access by the calling thread and optionally waits for the resource to be acquired.
ExTryToAcquireResourceExclusiveLite
Either acquires a given resource for exclusive access immediately, or returns FALSE.
ExAcquireResourceSharedLite
Acquires an initialized resource for shared access by the calling thread and optionally waits for the resource to be acquired.
ExAcquireSharedStarveExclusive
Acquires a given resource for shared access without waiting for any pending attempts to acquire exclusive access to the same resource.
ExAcquireSharedWaitForExclusive
Acquires a given resource for shared access, optionally waiting for any pending exclusive waiters to acquire and release the resource first.
ExIsResourceAcquiredExclusiveLite
Returns whether the calling thread has exclusive access to a given resource.
ExIsResourceAcquiredSharedLite
Returns how many times the calling thread has acquired shared access to a given resource.
ExGetExclusiveWaiterCount
Returns the number of threads currently waiting to acquire a given resource for exclusive access.
ExGetSharedWaiterCount
Returns the number of threads currently waiting to acquire a given resource for shared access.
ExConvertExclusiveToSharedLite
Converts a given resource from acquired for exclusive access to acquired for shared access.
ExGetCurrentResourceThread
Returns the thread ID of the current thread.
ExReleaseResourceForThreadLite
Releases a given resource that was acquired by the given thread.
ExDeleteResourceLite
Deletes a caller-initialized resource from the system's resource list.
IoQueueWorkItem
Queues an initialized work queue item so the driver-supplied routine will be called when a system worker thread is given control.
KeSetTimer
Sets the absolute or relative interval at which a timer object will be set to the Signaled state, and optionally supplies a timer DPC to be executed when the interval expires.
KeSetTimerEx
Sets the absolute or relative interval at which a timer object will be set to the Signaled state. Optionally supplies a timer DPC to be executed when the interval expires and a recurring interval for the timer.
KeCancelTimer
Cancels a timer object before the interval passed to KeSetTimer expires. Dequeues a timer DPC before the timer interval (if any) expires.
KeReadStateTimer
Returns TRUE if a given timer object is set to the Signaled state.
KeSetEvent
Returns the previous state of a given event object and sets the event (if not already Signaled) to the Signaled state.
KeClearEvent
Resets an event to the Not-Signaled state.
KeResetEvent
Returns the previous state of an event object and resets the event to the Not-Signaled state.
KeReadStateEvent
Returns the current state (nonzero for Signaled or zero for Not-Signaled) of a given event object.
ExAcquireFastMutex
Acquires an initialized fast mutex, possibly after putting the caller into a wait state until it is acquired, and gives the calling thread ownership with APCs disabled.
ExTryToAcquireFastMutex
Acquires the given fast mutex immediately for the caller with APCs disabled, or returns FALSE.
ExReleaseFastMutex
Releases ownership of a fast mutex that was acquired with ExAcquireFastMutex or ExTryToAcquireFastMutex.
ExAcquireFastMutexUnsafe
Acquires an initialized fast mutex, possibly after putting the caller into a wait state until it is acquired.
ExReleaseFastMutexUnsafe
Releases ownership of a fast mutex that was acquired with ExAcquireFastMutexUnsafe.
KeReleaseMutex
Releases a given mutex object, specifying whether the caller will call one of the KeWait Xxx routines as soon as KeReleaseMutex returns the previous value of the mutex state (a zero for Signaled; otherwise, Not-Signaled).
KeReadStateMutex
Returns the current state (one for Signaled or any other value for Not-Signaled) of a given mutex object.
KeReleaseSemaphore
Releases a given semaphore object. Supplies a (run-time) priority boost for waiting threads if the release sets the semaphore to the Signaled state. Augments the semaphore count by a given value and specifies whether the caller will call one of the KeWait Xxx routines as soon as KeReleaseSemaphore returns.
KeReadStateSemaphore
Returns the current state (zero for Not-Signaled or a positive value for Signaled) of a given semaphore object.
KeWaitForSingleObject
Puts the current thread into an alertable or nonalertable wait state until a given dispatcher object is set to the Signaled state or (optionally) until the wait times out.
KeWaitForMutexObject
Puts the current thread into an alertable or nonalertable wait state until a given mutex is set to the Signaled state or (optionally) until the wait times out.
KeWaitForMultipleObjects
Puts the current thread into an alertable or nonalertable wait state until any one or all of a number of dispatcher objects are set to the Signaled state or (optionally) until the wait times out.
PsGetCurrentThread
Returns a handle for the current thread.
KeGetCurrentThread
Returns a pointer to the opaque thread object that represents the current thread.
IoGetCurrentProcess
Returns a handle for the process of the current thread.
PsGetCurrentProcess
Returns a pointer to the process of the current thread.
KeEnterCriticalRegion
Temporarily disables the delivery of normal kernel APCs while a highest-level driver is running in the context of the user-mode thread that requested the current I/O operation. Special kernel-mode APCs are still delivered.
KeLeaveCriticalRegion
Re-enables, as soon as possible, the delivery of normal kernel-mode APCs that were disabled by a preceding call to KeEnterCriticalRegion.
KeSaveFloatingPointState
Saves the current thread's nonvolatile floating-point context so that the caller can carry out its own floating-point operations.
KeRestoreFloatingPointState
Restores the previous nonvolatile floating-point context that was saved with KeSaveFloatingPointState.
ZwSetInformationThread
Sets the priority of a given thread for which the caller has a handle.
PsGetCurrentProcessId
Returns the system-assigned identifier of the current process.
PsGetCurrentThreadId
Returns the system-assigned identifier of the current thread.
PsSetCreateProcessNotifyRoutine
Registers a highest level driver's callback that is subsequently notified whenever a new process is created or existing process deleted.
PsSetCreateThreadNotifyRoutine
Registers a highest level driver's callback that is subsequently notified whenever a new thread is created or an existing thread is deleted.
PsSetLoadImageNotifyRoutine
Registers a callback routine for a highest level system-profiling driver. The callback is subsequently notified whenever a new image is loaded for execution.


Memory

This section describes the kernel-mode support routines and macros that drivers can call to:

  • Allocate and free temporary buffers in Buffer Management
  • Allocate long-term internal driver buffers in Long-Term Internal Driver Buffers
  • Manage buffered data or to initialize driver-allocated buffers in Buffered Data and Buffer Initialization
  • Get mapped addresses and to allocate or manage MDLs (memory descriptor lists) in Address Mappings and MDLs
  • Manipulate buffers and MDLs in Buffer and MDL Management
  • Communicate with their respective devices in Device Memory Access
  • Lock and unlock their pageable code or data sections, or that they can call to make their entire driver pageable in Pageable Drivers
  • Set up mapped sections and views of memory in Sections and Views


Buffer Management

ExAllocatePool
Allocates (optionally cache-aligned) memory from paged or nonpaged system space.
ExAllocatePoolWithQuota
Allocates pool memory charging quota against the original requester of the I/O operation. (Only highest-level drivers can call this routine.)
ExAllocatePoolWithTag
Allocates (optionally cache-aligned) tagged memory from paged or nonpaged system space. The caller-supplied tag is put into any crash dump of memory that occurs.
ExAllocatePoolWithQuotaTag
Allocates tagged pool memory charging quota against the original requester of the I/O operation. The caller-supplied tag is put into any crash dump of memory that occurs. Only highest-level drivers can call this routine.
ExFreePool
Releases memory to paged or nonpaged system space.
ExInitializeNPagedLookasideList
Initializes a lookaside list of nonpaged memory. After successful initialization of the list, fixed-size blocks can be allocated from, and freed to, the lookaside list.
ExAllocateFromNPagedLookasideList
Removes the first entry from the specified lookaside list in nonpaged memory. If the lookaside list is empty, allocates an entry from nonpaged pool.
ExFreeToNPagedLookasideList
Returns an entry to the specified lookaside list in nonpaged memory. If the list has reached its maximum size, returns the entry to nonpaged pool.
ExDeleteNPagedLookasideList
Deletes a nonpaged lookaside list.
ExInitializePagedLookasideList
Initializes a lookaside list of paged memory. After successful initialization of the list, fixed-size blocks can be allocated from and freed to the lookaside list.
ExAllocateFromPagedLookasideList
Removes the first entry from the specified lookaside list in paged memory. If the lookaside list is empty, allocates an entry from paged pool.
ExFreeToPagedLookasideList
Returns an entry to the specified lookaside list in paged memory. If the list has reached its maximum size, returns the entry to paged pool.
ExDeletePagedLookasideList
Deletes a paged lookaside list.
MmQuerySystemSize
Returns an estimate (small, medium, or large) of the amount of memory available on the current platform.
MmIsThisAnNtAsSystem
Returns TRUE if the machine is running as a server. If this routine returns TRUE, the caller is likely to require more resources to process I/O requests, and the machine is a server so it is likely to have more resources available.


Long-Term Internal Driver Buffers

MmAllocateContiguousMemory
Allocates a range of physically contiguous, cache-aligned memory in nonpaged pool.
MmFreeContiguousMemory
Releases a range of physically contiguous memory when the driver unloads.
MmAllocateNonCachedMemory
Allocates a virtual address range of noncached and cache-aligned memory in nonpaged system space (pool).
MmFreeNonCachedMemory
Releases a virtual address range of noncached memory in nonpaged system space when the driver unloads.
AllocateCommonBuffer
Allocates and maps a logically contiguous region of memory that is simultaneously accessible both from the processor and from a device, given access to an adapter object, the requested length of the memory region to allocate, and access to variables where the starting logical and virtual addresses of the allocated region are returned. Returns TRUE if the requested length was allocated. Can be used for continuous busmaster DMA or for system DMA using the autoinitialize mode of a system DMA controller.
FreeCommonBuffer
Releases an allocated common buffer and unmaps it, given access to the adapter object, the length, and the starting logical and virtual addresses of the region to be freed when the driver unloads. Arguments must match those passed in the call to AllocateCommonBuffer.


Buffered Data and Buffer Initialization

RtlCompareMemory
Compares data, given pointers to caller-supplied buffers and the length in bytes for the comparison. Returns the number of bytes that are equal.
RtlCopyMemory
Copies the data from one caller-supplied buffer to another, given pointers to both buffers and the length in bytes to be copied.
RtlMoveMemory
Copies the data from one caller-supplied memory range to another, given pointers to the base of both ranges and the length in bytes to be copied.
RtlFillMemory
Fills a caller-supplied buffer with the specified UCHAR value, given a pointer to the buffer and the length in bytes to be filled.
RtlZeroMemory
Fills a buffer with zeros, given a pointer to the caller-supplied buffer and the length in bytes to be filled.
RtlStoreUshort
Stores a USHORT value at a given address, avoiding alignment faults.
RtlRetrieveUshort
Retrieves a USHORT value at a given address, avoiding alignment faults, and stores the value at a given address, that is assumed to be aligned.
RtlStoreUlong
Stores a ULONG value at a given address, avoiding alignment faults.
RtlRetrieveUlong
Retrieves a ULONG value at a given address, avoiding alignment faults, and stores the value at a given address, that is assumed to be aligned.


Address Mappings and MDLs

MmGetPhysicalAddress
Returns the corresponding physical address for a given valid virtual address.
MmGetMdlVirtualAddress
Returns a (possibly invalid) virtual address for a buffer described by a given MDL; the returned address, used as an index to a physical address entry in the MDL, can be input to MapTransfer for drivers that use DMA.
MmGetSystemAddressForMdl
Returns a system-space virtual address that maps the physical pages described by a given MDL for drivers whose devices must use PIO. If no virtual address exists, one is assigned. If none are available, a bug check is issued. Non-WDM drivers should use MmGetSystemAddressForMdlSafe instead.
MmGetSystemAddressForMdlSafe
Returns a system-space virtual address that maps the physical pages described by a given MDL for drivers whose devices must use PIO. If no virtual address exists, one is assigned.
MmBuildMdlForNonPagedPool
Fills in the corresponding physical addresses of a given MDL that specifies a range of virtual addresses in nonpaged pool.
MmGetMdlByteCount
Returns the length in bytes of the buffer mapped by a given MDL.
MmGetMdlByteOffset
Returns the byte offset within a page of the buffer described by a given MDL.
MmMapLockedPages
Maps already locked physical pages, described by a given MDL, to a returned virtual address range.
MmUnmapLockedPages
Releases a mapping set up by MmMapLockedPages.
MmIsAddressValid
Returns whether a page fault will occur if a read or write operation is done at the given virtual address.
MmSizeOfMdl
Returns the number of bytes required for an MDL describing the buffer specified by the given virtual address and length in bytes.
MmCreateMdl
Allocates and initializes an MDL describing a buffer specified by the given virtual address and length in bytes; returns a pointer to the MDL.
MmPrepareMdlForReuse
Reinitializes a caller-created MDL for reuse.
MmInitializeMdl
Initializes a caller-created MDL to describe a buffer specified by the given virtual address and length in bytes.
MmMapIoSpace
Maps a physical address range to a cached or noncached virtual address range in nonpaged system space.
MmUnmapIoSpace
Unmaps a virtual address range from a physical address range.
MmProbeAndLockPages
Probes the pages specified in an MDL for a particular kind of access, makes the pages resident, and locks them in memory; returns the MDL updated with corresponding physical addresses. (Usually, only highest-level drivers call this routine.)
MmUnlockPages
Unlocks the previously probed and locked pages specified in an MDL.
IoAllocateMdl
Allocates an MDL large enough to map the starting address and length supplied by the caller; optionally associates the MDL with a given IRP.
IoBuildPartialMdl
Builds an MDL for the specified starting virtual address and length in bytes from a given source MDL. Drivers that split large transfer requests into a number of smaller transfers can call this routine.
IoFreeMdl
Releases a given MDL allocated by the caller.


Buffer and MDL Management

ADDRESS_AND_SIZE_TO_SPAN_PAGES
Returns the number of pages required to contain a given virtual address and size in bytes.
BYTE_OFFSET
Returns the byte offset of a given virtual address within the page.
BYTES_TO_PAGES
Returns the number of pages necessary to contain a given number of bytes.
PAGE_ALIGN
Returns the page-aligned virtual address for the page that contains a given virtual address.
ROUND_TO_PAGES
Rounds a given size in bytes up to a page-size multiple.


Device Memory Access

For the following, XXX_REGISTER_XXX indicates device memory that is mapped onto system space, while XXX_PORT_XXX indicates device memory in I/O space.

READ_PORT_UCHAR
Reads a UCHAR value from the given I/O port address.
READ_PORT_USHORT
Reads a USHORT value from the given I/O port address.
READ_PORT_ULONG
Reads a ULONG value from the given I/O port address.
READ_PORT_BUFFER_UCHAR
Reads a given count of UCHAR values from the given I/O port into a given buffer.
READ_PORT_BUFFER_USHORT
Reads a given count of USHORT values from the given I/O port into a given buffer.
READ_PORT_BUFFER_ULONG
Reads a given count of ULONG values from the given I/O port into a given buffer.
WRITE_PORT_UCHAR
Writes a given UCHAR value to the given I/O port address.
WRITE_PORT_USHORT
Writes a given USHORT value to the given I/O port address.
WRITE_PORT_ULONG
Writes a given ULONG value to the given I/O port address.
WRITE_PORT_BUFFER_UCHAR
Writes a given count of UCHAR values from a given buffer to the given I/O port.
WRITE_PORT_BUFFER_USHORT
Writes a given count of USHORT values from a given buffer to the given I/O port.
WRITE_PORT_BUFFER_ULONG
Writes a given count of ULONG values from a given buffer to the given I/O port.
READ_REGISTER_UCHAR
Reads a UCHAR value from the given register address in memory space.
READ_REGISTER_USHORT
Reads a USHORT value from the given register address in memory space.
READ_REGISTER_ULONG
Reads a ULONG value from the given register address in memory space.
READ_REGISTER_BUFFER_UCHAR
Reads a given count of UCHAR values from the given register address into the given buffer.
READ_REGISTER_BUFFER_USHORT
Reads a given count of USHORT values from the given register address into the given buffer.
READ_REGISTER_BUFFER_ULONG
Reads a given count of ULONG values from the given register address into the given buffer.
WRITE_REGISTER_UCHAR
Writes a given UCHAR value to the given register address in memory space.
WRITE_REGISTER_USHORT
Writes a given USHORT value to the given register address in memory space.
WRITE_REGISTER_ULONG
Writes a given ULONG value to the given register address in memory space.
WRITE_REGISTER_BUFFER_UCHAR
Writes a given count of UCHAR values from a given buffer to the given register address.
WRITE_REGISTER_BUFFER_USHORT
Writes a given count of USHORT values from a given buffer to the given register address.
WRITE_REGISTER_BUFFER_ULONG
Writes a given count of ULONG values from a given buffer to the given register address.


Pageable Drivers

MmLockPagableCodeSection
Locks a set of driver routines marked with a special compiler directive into system space.
MmLockPagableDataSection
Locks data marked with a special compiler directive into system space, when that data is accessed infrequently, predictably, and at an IRQL less than DISPATCH_LEVEL.
MmLockPagableSectionByHandle
Locks a pageable section into system memory using a handle returned from MmLockPagableCodeSection or MmLockPagableDataSection.
MmUnlockPagableImageSection
Releases a section that was previously locked into system space when the driver is no longer processing IRPs, or when the contents of the section is no longer required.
MmPageEntireDriver
Lets a driver page all of its code and data regardless of the attributes of the various sections in the driver's image.
MmResetDriverPaging
Resets a driver's pageable status to that specified by the sections which make up the driver's image.


Sections and Views

InitializeObjectAttributes
Sets up a parameter of type OBJECT_ATTRIBUTES for a subsequent call to a ZwCreate Xxx or ZwOpen Xxx routine.
ZwOpenSection
Obtains a handle for an existing section, provided that the requested access can be allowed.
ZwMapViewOfSection
Maps a view of an open section into the virtual address space of a process. Returns an offset into the section (base of the mapped view) and the size mapped.
ZwUnMapViewOfSection
Releases a mapped view in the virtual address space of a process.


Access to Structures

ARGUMENT_PRESENT
Returns FALSE if an argument pointer is NULL; otherwise returns TRUE.
CONTAINING_RECORD
Returns the base address of an instance of a structure given the structure type and the address of a field within it.
FIELD_OFFSET
Returns the byte offset of a named field in a known structure type.


Plug and Play Routines

These routines are used by drivers to implement plug and play support. The routines are listed in alphabetical order. The following lists summarize the routines functionally.

See Plug and Play for background and task-oriented information on supporting PnP in drivers.


Device Information Routines

IoGetDeviceProperty
Retrieves information about a device such as configuration information and the name of its PDO.
IoInvalidateDeviceRelations
Notifies the PnP manager that the relations for a device have changed.
IoInvalidateDeviceState
Notifies the PnP manager that the PnP state of a device has changed. In response, the PnP Manager sends an IRP_MN_QUERY_PNP_DEVICE_STATE to the device stack.
IoReportDetectedDevice
Reports a nonPnP device to the PnP Manager.
IoReportResourceForDetection
Claims hardware resources in the configuration registry for a legacy device. This routine is for drivers that detect legacy hardware which cannot be enumerated by PnP.


Registry Routines

IoOpenDeviceInterfaceRegistryKey
Returns a handle to a registry key for storing information about a particular device interface.
IoOpenDeviceRegistryKey
Returns a handle to a device-specific or a driver-specific registry key for a particular device instance.


Device Interface Routines

IoRegisterDeviceInterface
Registers device functionality (a device interface) that a driver will enable for use by applications or other system components.
IoSetDeviceInterfaceState
Enables or disables a previously registered device interface. Applications and other system components can open only interfaces that are enabled.
IoOpenDeviceInterfaceRegistryKey
Returns a handle to a registry key for storing information about a particular device interface.
IoGetDeviceInterfaces
Returns a list of device interfaces of a particular device interface class (such as all devices on the system that support a HID interface).
IoGetDeviceInterfaceAlias
Returns the alias device interface of the specified interface class, if the alias exists. Device interfaces are considered aliases if they are exposed by the same underlying device and have identical interface reference strings, but are of different interface classes.


PnP Notification Routines

IoRegisterPlugPlayNotification
Registers a driver callback routine to be called when the specified PnP event occurs.
IoReportTargetDeviceChange
Notifies the PnP Manager that a custom event has occurred on a device. The PnP Manager sends notification of the event to drivers that registered for it. Do not use this routine to report system PnP events, such as GUID_TARGET_DEVICE_REMOVE_COMPLETE.
IoReportTargetDeviceChangeAsynchronous
Notifies the PnP Manager that a custom event has occurred on a device. Returns immediately; does not wait while the PnP Manager sends notification of the event to drivers that registered for it. Do not use this routine to report system PnP events, such as GUID_TARGET_DEVICE_REMOVE_COMPLETE.
IoUnregisterPlugPlayNotification
Removes the registration of a driver's callback routine for a PnP event.


Remove Lock Routines

IoInitializeRemoveLock
Initalizes a remove lock for a device object. A driver can use the lock to track outstanding I/O on a device and to determine when the driver can delete its device object in response to an IRP_MN_REMOVE_DEVICE request.
IoAcquireRemoveLock
Increments the count for a remove lock, indicating that the associated device object should not be detached from the device stack nor deleted.
IoReleaseRemoveLock
Releases a remove lock acquired with a previous call to IoAcquireRemoveLock.
IoReleaseRemoveLockAndWait

Releases a remove lock acquired with a previous call to IoAcquireRemoveLock and waits until all acquisitions of the lock have been released. A driver typically calls this routine in its dispatch code for an IRP_MN_REMOVE_DEVICE request.


Other PnP Routines

IoAdjustPagingPathCount
Increments or decrements a caller-supplied page-file counter as an atomic operation. This routine can be used to adjust other counters, such as counters for hibernation files or crash-dump files.
IoRequestDeviceEject
Notifies the PnP manager that the device eject button was pressed. Note that this routine reports a request for a device eject, not media eject.


Windows Management Instrumentation routines

Built on Wednesday, July 11, 2001


WMI IRP Processing Routines

Drivers can use these routines in processing WMI IRPs.

WmiCompleteRequest
If a driver uses WMISystemControl to dispatch the WMI IRP to a callback routine, then the callback routine can use WMICompleteRequest to complete the IRP.
WmiSystemControl
Dispatches a WMI IRP to a driver-supplied callback routine.


WMI IRP Sending Routines

Drivers use these routines to send WMI IRPs.

IoWMIAllocateInstanceIds
Allocates unused WMI instance IDs for a given WMI class GUID.
IoWMIDeviceObjectToInstanceName
Given a device object, determines the WMI class instance name supported by the corresponding driver. Callers can use this to determine the instance names supported by a particular driver.
IoWMIExecuteMethod
Executes the specified WMI class method.
IoWMIHandleToInstanceName
Given a file handle, determines the WMI class instance name supported by the corresponding driver. Callers can use this to determine the instance names supported by a particular driver.
IoWMIOpenBlock
Opens a WMI data block. Callers use this to submit WMI I/O requests.
IoWMIQueryAllData
Fetches the property values for every instance of the specified WMI class GUID.
IoWMIQueryAllDataMultiple
Fetches the property values for every instance of the specified set of WMI class GUIDs.
IoWMIQuerySingleInstance
Fetches the property values for a particular instance of the specified WMI class GUID.
IoWMIQuerySingleInstanceMultiple
Fetches the property values for a particular set of WMI class instances.
IoWMISetNotificationCallback
Sets a notification callback for WMI events.
IoWMISetSingleInstance
Sets the property values for a particular WMI class instance.
IoWMISetSingleItem
Sets the specified property for a particular WMI class instance.


DMA

IoGetDmaAdapter
Returns a pointer to an adapter object that represents either the DMA channel to which the driver's device is connected or the driver's busmaster adapter. Also returns the maximum number of map registers the driver can specify for each DMA transfer.
MmGetMdlVirtualAddress
Returns the base virtual address of a buffer described by a given MDL. The returned address, used as an index to a physical address entry in the MDL, can be input to MapTransfer.
MmGetSystemAddressForMdlSafe
Returns a nonpaged system-space virtual address for the base of the memory area described by an MDL. It maps the physical pages described by the MDL into system space, if they are not already mapped to system space. WDM drivers should use MmGetSystemAddressForMdl instead.
ADDRESS_AND_SIZE_TO_SPAN_PAGES
Returns the number of pages spanned by the virtual range defined by a virtual address and a length in bytes. A driver can use this macro to determine whether a transfer request must be split into partial transfers.
AllocateAdapterChannel
Reserves exclusive access to a DMA channel and map registers for a device. When the channel and registers are available, this routine calls a driver-supplied AdapterControl routine to carry out an I/O operation through either the system DMA controller or a busmaster adapter.
AllocateCommonBuffer
Allocates and maps a logically contiguous region of memory that is simultaneously accessible from both the processor and a device. This routine returns TRUE if the requested length was allocated.
BuildMdlFromScatterGatherList
Builds an MDL corresponding to a scatter/gather list.
BuildScatterGatherList
Prepares the system for scatter/gather DMA for a device and calls a driver-supplied routine to carry out the I/O operation. This function provides the same functionality as GetScatterGatherList, except it uses a driver-supplied buffer to hold the scatter/gather list.
CalculateScatterGatherListSize
Computes the buffer size needed to hold a scatter/gather list for a memory buffer.
FlushAdapterBuffers
Forces any data remaining in either a busmaster adapter's or the system DMA controller's internal buffers to be written into memory or to the device.
FreeAdapterChannel
Releases an adapter object that represents a system DMA channel, and optionally releases any allocated map registers.
FreeCommonBuffer
Releases and unmaps a previously allocated common buffer. Arguments must match those passed in an earlier call to AllocateCommonBuffer.
FreeMapRegisters
Releases a set of map registers that were saved from a call to AllocateAdapterChannel. A driver calls this routine after using the registers in one or more calls to MapTransfer, flushing the cache by calling FlushAdapterBuffers, and completing the busmaster DMA transfer.
GetDmaAlignment
Returns the buffer alignment requirements for a DMA controller or device.
GetScatterGatherList
Prepares the system for scatter/gather DMA for a device and calls a driver-supplied routine to carry out the I/O operation. For devices that support scatter/gather DMA, this routine combines the functionality of AllocateAdapterChannel and MapTransfer.
KeFlushIoBuffers
Flushes the memory region described by an MDL from all processors' caches into memory.
MapTransfer
Sets up map registers for an adapter object previously allocated by AllocateAdapterChannel to map a transfer from a locked-down buffer. Returns the logical address of the mapped region and, for busmaster devices that support scatter/gather, the number of bytes mapped.
PutDmaAdapter
Frees an adapter object previously allocated by IoGetDmaAdapter.
PutScatterGatherList
Frees map registers and scatter/gather list previously allocated by GetScatterGatherList.
ReadDmaCounter
Returns the number of bytes yet to be transferred during the current system DMA operation (in autoinitialize mode).


PIO

MmProbeAndLockPages
Probes the pages specified in an MDL for a particular kind of access, makes the pages resident, and locks them in memory; returns the MDL updated with corresponding physical addresses.
MmGetSystemAddressForMdlSafe
Returns a system-space virtual address that maps the physical pages described by a given MDL for drivers whose devices must use PIO. If no virtual address exists, one is assigned. Windows 98 drivers should use MmGetSystemAddressForMdl instead.
KeFlushIoBuffers
Flushes the memory region described by a given MDL from all processors' caches into memory.
MmUnlockPages
Unlocks the previously probed and locked pages specified in an MDL.
MmMapIoSpace
Maps a physical address range to a cached or noncached virtual address range in nonpaged system space.
MmUnmapIoSpace
Unmaps a virtual address range from a physical address range.


Driver-Managed Queues

KeInitializeSpinLock
Initializes a variable of type KSPIN_LOCK. An initialized spin lock is a required parameter to the Ex..InterlockedList routines.
InitializeListHead
Sets up a queue header for a driver's internal queue, given a pointer to driver-supplied storage for the queue header and queue. An initialized queue header is a required parameter to the ExInterlockedInsert/Remove..List routines.
ExInterlockedInsertTailList
Inserts an entry at the tail of a doubly-linked list, using a spin lock to ensure multiprocessor-safe access to the list and atomic modification of the list links.
ExInterlockedInsertHeadList
Inserts an entry at the head of a doubly-linked list, using a spin lock to ensure multiprocessor-safe access to the list and atomic modification of the links in the list.
ExInterlockedRemoveHeadList
Removes an entry from the head of a doubly-linked list, using a spin lock to ensure multiprocessor-safe access to the list and atomic modification of the links in the list.
ExInterlockedPopEntryList
Removes an entry from the head of a singly-linked list as an atomic operation, using a spin lock to ensure multiprocessor-safe access to the list.
ExInterlockedPushEntryList
Inserts an entry at the head of a singly-linked list as an atomic operation, using a spin lock to ensure multiprocessor-safe access to the list.
IsListEmpty
Returns TRUE if a queue is empty. (This type of doubly-linked list is not protected by a spin lock, unless the caller explicitly manages synchronization to queued entries with an initialized spin lock for which the caller supplies the storage.)
InsertTailList
Queues an entry at the end of the list.
InsertHeadList
Queues an entry at the head of the list.
RemoveHeadList
Dequeues an entry at the head of the list.
RemoveTailList
Dequeues an entry at the end of the list.
RemoveEntryList
Returns whether a given entry is in the given list and dequeues the entry if it is.
PushEntryList
Inserts an entry into the queue. (This type of singly-linked list is not protected by a spin lock, unless the caller explicitly manages synchronization to queued entries with an initialized spin lock for which the caller supplies the storage.)
PopEntryList
Removes an entry from the queue.
ExInterlockedPopEntrySList
Removes an entry from the head of a sequenced, singly-linked list that was set up with ExInitializeSListHead.
ExInterlockedPushEntrySList
Queues an entry at the head of a sequenced, singly-linked list that was set up with ExInitializeSListHead.
ExQueryDepthSList
Returns the number of entries currently queued in a sequenced, singly-linked list.
ExInitializeNPagedLookasideList
Sets up a lookaside list, protected by a system-supplied spin lock, in nonpaged pool from which the driver can allocate and free blocks of a fixed size.
KeInitializeDeviceQueue
Initializes a device queue object to a not-busy state, setting up an associated spin lock for multiprocessor-safe access to device queue entries.
KeInsertDeviceQueue
Acquires the device queue spin lock and queues an entry to a device driver if the device queue is not empty; otherwise, inserts the entry at the tail of the device queue.
KeInsertByKeyDeviceQueue
Acquires the device queue spin lock and queues an entry to a device driver if the device queue is not empty; otherwise, inserts the entry into the queue according to the given sort-key value.
KeRemoveDeviceQueue
Removes an entry from the head of a given device queue.
KeRemoveByKeyDeviceQueue
Removes an entry, selected according to the specified sort-key value, from the given device queue.
KeRemoveEntryDeviceQueue
Determines whether a given entry is in the given device queue and, if so, dequeues the entry.


Driver System Threads

PsCreateSystemThread
Creates a kernel-mode thread associated with a given process object or with the default system process. Returns a handle for the thread.
PsTerminateSystemThread
Terminates the current thread and satisfies as many waits as possible for the current thread object.
PsGetCurrentThread
Returns a handle for the current thread.
KeGetCurrentThread
Returns a pointer to the opaque thread object that represents the current thread.
KeQueryPriorityThread
Returns the current priority of a given thread.
KeSetBasePriorityThread
Sets up the run-time priority, relative to the system process, for a driver-created thread.
KeSetPriorityThread
Sets up the run-time priority for a driver-created thread with a real-time priority attribute.
KeDelayExecutionThread
Puts the current thread into an alertable or nonalertable wait state for a given interval.
IoQueueWorkItem
Queues an initialized work queue item so the driver-supplied routine will be called when a system worker thread is given control.
ZwSetInformationThread
Sets the priority of a given thread for which the caller has a handle.


Strings

RtlInitString
Initializes the specified string in a buffer.
RtlInitAnsiString
Initializes the specified ANSI string in a buffer.
RtlInitUnicodeString
Initializes the specified Unicode string in a buffer.
RtlAnsiStringToUnicodeSize
Returns the size in bytes required to hold a Unicode version of a given buffered ANSI string.
RtlAnsiStringToUnicodeString
Converts a buffered ANSI string to a Unicode string, given a pointer to the source-string buffer and the address of caller-supplied storage for a pointer to the destination buffer. (This routine allocates a destination buffer if the caller does not supply the storage.) You can also use the string manipulation routines provided by a compiler to convert ANSI strings to Unicode.
RtlFreeUnicodeString
Releases a buffer containing a Unicode string, given a pointer to the buffer returned by RtlAnsiStringToUnicodeString.
RtlUnicodeStringToAnsiString
Converts a buffered Unicode string to an ANSI string, given a pointer to the source-string buffer and the address of caller-supplied storage for a pointer to the destination buffer. (This routine allocates a destination buffer if the caller does not supply the storage.)
RtlFreeAnsiString
Releases a buffer containing an ANSI string, given a pointer to the buffer returned by RtlUnicodeStringToAnsiString.
RtlAppendUnicodeStringToString
Concatenates a copy of a buffered Unicode string with a buffered Unicode string, given pointers to both buffers.
RtlAppendUnicodeToString
Concatenates a given input string with a buffered Unicode string, given a pointer to the buffer.
RtlCopyString
Copies the source string to the destination, given pointers to both buffers, or sets the length of the destination string (but not the length of the destination buffer) to zero if the optional pointer to the source-string buffer is NULL.
RtlCopyUnicodeString
Copies the source string to the destination, given pointers to both buffers, or sets the length of the destination string (but not the length of the destination buffer) to zero if the optional pointer to the source-string buffer is NULL.
RtlEqualString
Returns TRUE if the given ANSI alphabetic strings are equivalent.
RtlEqualUnicodeString
Returns TRUE if the given buffered strings are equivalent.
RtlCompareString
Compares two buffered, single-byte character strings and returns a signed value indicating whether they are equivalent or which is greater.
RtlCompareUnicodeString
Compares two buffered Unicode strings and returns a signed value indicating whether they are equivalent or which is greater.
RtlUpperString
Converts a copy of a buffered string to uppercase and stores the copy in a destination buffer.
RtlUpcaseUnicodeString
Converts a copy of a buffered Unicode string to uppercase and stores the copy in a destination buffer.
RtlIntegerToUnicodeString
Converts an unsigned integer value in the specified base to one or more Unicode characters in a buffer.
RtlUnicodeStringToInteger
RtlUnicodeStringToInteger converts the Unicode string representation of an integer into its integer equivalent.


Data Conversions

InterlockedExchange
Sets a variable of type LONG to a given value as an atomic operation; returns the original value of the variable.
RtlConvertLongToLargeInteger
Converts a given LONG value to a LARGE_INTEGER value.
RtlConvertUlongToLargeInteger
Converts a given ULONG value to a LARGE_INTEGER value.
RtlTimeFieldsToTime
Converts information in a TIME_FIELDS structure to system time.
RtlTimeToTimeFields
Converts a system time value into a buffered TIME_FIELDS value.
ExSystemTimeToLocalTime
Adds the time-zone bias for the current locale to GMT system time, converting it to local time.
ExLocalTimeToSystemTime
Subtracts the time-zone bias from the local time, converting it to GMT system time.
RtlAnsiStringToUnicodeString
Converts a buffered ANSI string to a Unicode string, given a pointer to the source-string buffer and the address of caller-supplied storage for a pointer to the destination buffer. (This routine allocates a destination buffer if the caller does not supply the storage.)
RtlUnicodeStringToAnsiString
Converts a buffered Unicode string to an ANSI string, given a pointer to the source-string buffer and the address of caller-supplied storage for a pointer to the destination buffer. (This routine allocates a destination buffer if the caller does not supply the storage.)
RtlUpperString
Converts a copy of a buffered string to uppercase and stores the copy in a destination buffer.
RtlUpcaseUnicodeString
Converts a copy of a buffered Unicode string to uppercase and stores the copy in a destination buffer.
RtlCharToInteger
Converts a single-byte character value into an integer in the specified base.
RtlIntegerToUnicodeString
Converts an unsigned integer value in the specified base to one or more Unicode characters in the given buffer.
RtlUnicodeStringToInteger
Converts a Unicode string representation of an integer into its integer equivalent.


Access to Driver-Managed Objects

ExCreateCallback
Creates or opens a callback object.
ExNotifyCallback
Calls the callback routines registered with a previously created or opened callback object.
ExRegisterCallback
Registers a callback routine with a previously created or opened callback object, so that the caller can be notified when conditions defined for the callback occur.
ExUnregisterCallback
Cancels the registration of a callback routine with a callback object.
IoRegisterDeviceInterface
Registers device functionality (a device interface) that a driver can enable for use by applications or other system components.
IoSetDeviceInterfaceState
Enables or disables a previously registered device interface. Applications and other system components can open only interfaces that are enabled.
IoGetDeviceInterfaceAlias
Returns the alias device interface of the specified interface class, if the alias exists. Device interfaces are considered aliases if they are exposed by the same underlying device and have identical interface reference strings, but are of different interface classes.
IoGetDeviceInterfaces
Returns a list of device interfaces of a particular device interface class (such as all devices on the system that support a HID interface).
IoGetFileObjectGenericMapping
Returns information about the mapping between generic access rights and specific access rights for file objects.
IoSetShareAccess
Sets the access allowed to a given file object representing a device. (Only highest-level drivers can call this routine.)
IoCheckShareAccess
Checks whether a request to open a file object specifies a desired access that is compatible with the current shared access permissions for the open file object. (Only highest-level drivers can call this routine.)
IoUpdateShareAccess
Modifies the current share-access permissions on the given file object. (Only highest-level drivers can call this routine.)
IoRemoveShareAccess
Restores the shared-access permissions on the given file object that were modified by a preceding call to IoUpdateShareAccess.
RtlLengthSecurityDescriptor
Returns the size in bytes of a given security descriptor.
RtlValidSecurityDescriptor
Returns whether a given security descriptor is valid.
RtlCreateSecurityDescriptor
Initializes a new security descriptor to an absolute format with default values (in effect, with no security constraints).
RtlSetDaclSecurityDescriptor
Sets the discretionary ACL information for a given security descriptor in absolute format.
SeAssignSecurity
Builds a security descriptor for a new object, given the security descriptor of its parent directory (if any) and an originally requested security for the object.
SeDeassignSecurity
Deallocates the memory associated with a security descriptor that was created with SeAssignSecurity.
SeValidSecurityDescriptor
Returns whether a given security descriptor is structurally valid.
SeAccessCheck
Returns a Boolean indicating whether the requested access rights can be granted to an object protected by a security descriptor and, possibly, a current owner.
SeSinglePrivilegeCheck
Returns a Boolean indicating whether the current thread has at least the given privilege level.


Error Handling

IoAllocateErrorLogEntry
Allocates and initializes an error log packet; returns a pointer so the caller can supply error-log data and call IoWriteErrorLogEntry with the packet.
IoFreeErrorLogEntry
Frees an error log entry allocated by IoAllocateErrorLogEntry.
IoWriteErrorLogEntry
Queues a previously allocated error log packet, filled in by the driver, to the system error logging thread.
IoIsErrorUserInduced
Returns a Boolean indicating whether an I/O request failed due to one of the following (user-correctable) conditions: STATUS_IO_TIMEOUT, STATUS_DEVICE_NOT_READY, STATUS_UNRECOGNIZED_MEDIA, STATUS_VERIFY_REQUIRED, STATUS_WRONG_VOLUME, STATUS_MEDIA_WRITE_PROTECTED, or STATUS_NO_MEDIA_IN_DEVICE. If the result is TRUE, a removable-media driver must call IoSetHardErrorOrVerifyDevice before completing the IRP.
IoSetHardErrorOrVerifyDevice
Supplies the device object for which the given IRP was failed due to a user-induced error, such as supplying the incorrect media for the requested operation or changing the media before the requested operation was completed. (A file system driver uses the associated device object to send a popup to the user; the user can then correct the error or retry the operation.)
IoSetThreadHardErrorMode
Enables or disables error reporting for the current thread using IoRaiseHardError or IoRaiseInformationalHardError.
IoGetDeviceToVerify
Returns a pointer to the device object, representing a removable-media device, that is the target of the given thread's I/O request. (This routine is useful only to file systems or other highest-level drivers.)
IoRaiseHardError
Causes a popup to be sent to the user indicating that the given IRP was failed on the given device object for an optional VPB, so that the user can correct the error or retry the operation.
IoRaiseInformationalHardError
Causes a popup to be sent to the user, showing an I/O error status and optional string supplying more information.
ExRaiseStatus
Raises an error status so that a caller-supplied structured exception handler is called. (This routine is useful only to highest-level drivers that supply exception handlers, in particular to file systems.)
KeBugCheckEx
Brings down the system in a controlled manner, displaying the bugcheck code and possibly more information, after the caller discovers an unrecoverable inconsistency that will corrupt the system unless it is brought down. After the system is brought down, this routine displays bug-check and possibly other information. (This routine can be called when debugging under-development drivers. Otherwise, drivers should never call this routine when they can handle an error by failing an IRP and by calling IoAllocateErrorLogEntry and IoWriteErrorLogEntry.)
KeBugCheck
Brings down the system in a controlled manner when the caller discovers an unrecoverable inconsistency that will corrupt the system if the caller continues to run. KeBugCheckEx is preferable.
KeInitializeCallbackRecord
Initializes a bug-check callback record before a device driver calls KeRegisterBugCheckCallback.
KeRegisterBugCheckCallback
Registers the device driver's bug-check callback routine, that is called if a system bug check occurs. Such a driver-supplied routine saves driver-determined state information, such as the contents of device registers, that would not otherwise be written into the system crash-dump file.
KeDeregisterBugCheckCallback
Removes a device driver's callback routine from the set of registered bug-check callbacks.


DMA Routines

Drivers use the routines documented in this chapter to perform DMA operations. The routines are accessed through pointers and cannot be called directly by name.

Drivers performing DMA operations use IoGetDmaAdapter to get a pointer to the DMA_ADAPTER structure for the device. The DmaOperations member of the structure points to a DMA_OPERATIONS structure, which is a table of pointers to the DMA routines for the physical device object of that device.

DMA routines are listed in alphabetical order by the name of the member in the DMA_OPERATIONS structure. For an overview of the functionality of these routines see Summary of Kernel-Mode Support Routines.


AllocateAdapterChannel

AllocateAdapterChannel prepares the system for a DMA operation on behalf of the target device object, and then calls the driver-supplied AdapterControl routine to carry out the DMA operation.

NTSTATUS
  AllocateAdapterChannel(
    IN PDMA_ADAPTER  DmaAdapter,
    IN PDEVICE_OBJECT  DeviceObject,
    IN ULONG  NumberOfMapRegisters,
    IN PDRIVER_CONTROL  ExecutionRoutine,
    IN PVOID  Context
    );

Parameters

DmaAdapter
Points to the DMA_ADAPTER structure returned by IoGetDmaAdapter that represents the bus master adapter or DMA controller.
DeviceObject
Points to the device object that represents the target device for a requested DMA operation.
NumberOfMapRegisters
Specifies the number of map registers to be used in the transfer. This value is the lesser of (the number of map registers needed to satisfy the current transfer request) and (the number of available map registers returned by IoGetDmaAdapter).
ExecutionRoutine
Points to a driver-supplied AdapterControl routine to be called as soon the system DMA controller or bus master adapter is available. This routine is declared as follows:
IO_ALLOCATION_ACTION
(*PDRIVER_CONTROL)(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN PVOID MapRegisterBase,
    IN PVOID Context
    );
Context
Points to the driver-determined context to be passed to the AdapterControl routine.

Include

wdm.h or ntddk.h

Return Value

This routine can return one of the following NTSTATUS values:

Value | Meaning
STATUS_SUCCESS | The adapter channel has been allocated.
STATUS_INSUFFICIENT_RESOURCES | The NumberOfMapRegisters is larger than the value returned by IoGetDmaAdapter.

Comments

AllocateAdapterChannel is not a system routine that can be called directly by name. This routine is callable only by pointer from the address returned in a DMA_OPERATIONS structure. Drivers obtain the address of this routine by calling IoGetDmaAdapter.

As soon as the appropriate DMA channel and/or any necessary map registers are available, AllocateAdapterChannel calls the driver-supplied AdapterControl routine to carry out an I/O operation through the system DMA controller or a bus master adapter.

This routine reserves exclusive access to a DMA controller channel and/or map registers for the one or more DMA operations required to satisfy the current IRP's transfer request for the specified device.

If the system DMA controller or bus master adapter is already busy or if insufficient resources are available, the driver's request is queued until the controller or adapter is free and resources are available. Otherwise, the driver-supplied AdapterControl routine is called immediately. Only one such request can be queued for a driver object at any one time. Therefore, the driver should not call AllocateAdapterChannel again for another DMA operation on the same driver object until the AdapterControl routine has completed execution. In addition, a driver must not call AllocateAdapterChannel from within its AdapterControl routine.

If AllocateAdapterChannel is called from a driver's StartIo routine to process the same IRP passed in to the StartIo routine, AllocateAdapterChannel passes that Irp to the AdapterControl routine. Otherwise, the Irp has no meaning, and a driver should consider the Irp a system-reserved parameter to its AdapterControl routine.

Drivers should save the value of MapRegisterBase for use when calling FreeAdapterChannel.

The return value of the AdapterControl routine depends on whether the device is a bus master or uses system DMA. Drivers of bus master devices return DeallocateObjectKeepRegisters; drivers of slave devices return KeepObject.

Callers of AllocateAdapterChannel must be running at IRQL DISPATCH_LEVEL.

See Also

FlushAdapterBuffers, FreeAdapterChannel, FreeMapRegisters, IoGetDmaAdapter, MapTransfer, ReadDmaCounter, DMA_OPERATIONS


AllocateCommonBuffer

AllocateCommonBuffer allocates memory and maps it so that it is simultaneously accessible from both the processor and a device for DMA operations.

PVOID
  AllocateCommonBuffer(
    IN PDMA_ADAPTER  DmaAdapter,
    IN ULONG  Length,
    OUT PPHYSICAL_ADDRESS  LogicalAddress,
    IN BOOLEAN  CacheEnabled
    );

Parameters

DmaAdapter
Points to the DMA_ADAPTER structure returned by IoGetDmaAdapter that represents the bus master adapter or DMA controller.
Length
Specifies the number of bytes of memory to allocate.
LogicalAddress
Points to a variable that receives the logical address the device can use to access the allocated buffer. Use this address rather than calling MmGetPhysicalAddress because the system can take into account any platform-specific memory restrictions.
CacheEnabled
Specifies whether the allocated memory can be cached.

Include

wdm.h or ntddk.h

Return Value

AllocateCommonBuffer returns the base virtual address of the allocated range. If the buffer cannot be allocated, it returns NULL.

Comments

AllocateCommonBuffer is not a system routine that can be called directly by name. This routine is callable only by pointer from the address returned in a DMA_OPERATIONS structure. Drivers obtain the address of this routine by calling IoGetDmaAdapter.

AllocateCommonBuffer supports DMA in which the device and the processor continuously communicate through system memory, as in a control structure for a bus master DMA device.

AllocateCommonBuffer also supports slave devices whose drivers use a system DMA controller's autoinitialize mode.

AllocateCommonBuffer does the following:

  • Allocates memory that can be reached from both the processor and the device. This memory appears contiguous to the device.
  • Allocates map registers to map the buffer, if required by the system.
  • Sets up a translation for the device, including loading map registers if necessary.

To use resident system memory economically, drivers should allocate as few of these buffers per device as possible. AllocateCommonBuffer allocates at least a page of memory, regardless of the requested Length. After a successful allocation requesting fewer than PAGE_SIZE bytes, the caller can access only the requested Length. After a successful allocation requesting more than an integral multiple of PAGE_SIZE bytes, any remaining bytes on the last allocated page are inaccessible to the caller.

If a driver needs several pages of common buffer space, but the pages need not be contiguous, the driver should make several one-page requests to AllocateCommonBuffer instead of one large request. This approach conserves contiguous memory.

Drivers typically call AllocateCommonBuffer as part of device start-up, during their response to a PnP IRP_MN_START_DEVICE request. After start-up, it is possible that only one-page requests will succeed, if any.

Callers of AllocateCommonBuffer must be running at IRQL PASSIVE_LEVEL.

See Also

FreeCommonBuffer, IoGetDmaAdapter, DMA_OPERATIONS


BuildMdlFromScatterGatherList

BuildMdlFromScatterGatherList builds an MDL from a scatter/gather list allocated by the system.

NTSTATUS
  BuildMdlFromScatterGatherList(
    IN PADAPTER_OBJECT  DmaAdapter,
    IN PSCATTER_GATHER_LIST  ScatterGather,
    IN PMDL  OriginalMdl,
    OUT PMDL  *TargetMdl
    );

Parameters

DmaAdapter
Pointer to the DMA_ADAPTER structure returned by IoGetDmaAdapter that represents the bus master adapter or DMA controller.
ScatterGather
Pointer to the scatter/gather list passed to the driver's AdapterListControl routine.
OriginalMdl
Pointer to the original MDL that that the driver used to build the scatter/gather list.
TargetMdl
Pointer to a variable the routine uses to return the MDL created to hold the buffer described by the scatter/gather list. The value returned can be the same as OriginalMdl.

Return Value

BuildMdlFromScatterGatherList returns one of the following status codes.

STATUS_SUCCESS
The operation succeeded.
STATUS_INVALID_PARAMETER
The OriginalMdl parameter is NULL.
STATUS_INSUFFICIENT_RESOURCES
There is not enough memory available to allocate a new MDL.
STATUS_NONE_MAPPED
The system has already created a new MDL for the memory locations in the scatter/gather list. (This only happens if the routine is called twice on the same scatter/gather list.)

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

This routine is only available on Windows® XP and later.

BuildMdlFromScatterGatherList is not a system routine that can be called directly by name. This routine can be called only by pointer from the address returned in a DMA_OPERATIONS structure. Drivers obtain the address of this routine by calling IoGetDmaAdapter with the Version member of the DeviceDescription parameter set to DEVICE_DESCRIPTION_VERSION2. If IoGetDmaAdapter returns NULL, the routine is not available on your platform.

When a driver creates a scatter/gather list to write to a device, the system can make a copy of the data to be written, and use that copy to perform the DMA operation. Use this routine to access the memory locations in the scatter/gather list, whether or not those locations are a copy.

See Also

DEVICE_DESCRIPTION, DMA_OPERATIONS, BuildScatterGatherList, IoGetDmaAdapter


BuildScatterGatherList

BuildScatterGatherList prepares the system for a DMA operation, using a driver-supplied buffer to build the scatter/gather list.

NTSTATUS
  BuildScatterGatherList(
    IN PDMA_ADAPTER  DmaAdapter,
    IN PDEVICE_OBJECT  DeviceObject,
    IN PMDL  Mdl,
    IN PVOID  CurrentVa,
    IN ULONG  Length,
    IN PDRIVER_LIST_CONTROL  ExecutionRoutine,
    IN PVOID  Context,
    IN BOOLEAN  WriteToDevice,
    IN PVOID  ScatterGatherBuffer,
    IN ULONG  ScatterGatherBufferLength
    );

Parameters

DmaAdapter
Pointer to the DMA_ADAPTER structure returned by IoGetDmaAdapter that represents the bus master adapter or DMA controller.
DeviceObject
Pointer to the device object that represents the target device for the DMA operation.
Mdl
Pointer to the MDL that describes the buffer specified by the MdlAddress member of the current IRP.
CurrentVa
Pointer to the current virtual address in the MDL for the buffer to be mapped for a DMA transfer operation.
Length
Specifies the length, in bytes, of the buffer to be mapped.
ExecutionRoutine
Pointer to a driver-supplied AdapterListControl routine, which is called at IRQL = DISPATCH_LEVEL when the system DMA controller or bus master adapter is available.
Context
Pointer to the driver-determined context passed to ExecutionRoutine when it is called.
WriteToDevice
Indicates the direction of the DMA transfer: TRUE for a transfer from the buffer to the device, and FALSE otherwise.
ScatterGatherBuffer
Pointer to the caller-supplied buffer that the routine fills with the scatter/gather list.
ScatterGatherBufferLength
Specifies the size, in bytes, of the buffer passed in the ScatterGatherBuffer parameter.

Return Value

BuildScatterGatherList returns one of the following values.

STATUS_SUCCESS
The operation is completed successfully.
STATUS_INSUFFICIENT_RESOURCES
The system has insufficient map registers available for the transfer.
STATUS_BUFFER_TOO_SMALL
The Length parameter is too big to fit within the buffer.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

This routine is only available on Windows XP and later.

BuildScatterGatherList is not a system routine that can be called directly by name. This routine can be called only by pointer from the address returned in a DMA_OPERATIONS structure. Drivers obtain the address of this routine by calling IoGetDmaAdapter with the Version member of the DeviceDescription parameter set to DEVICE_DESCRIPTION_VERSION2. If IoGetDmaAdapter returns NULL, the routine is not available on your platform.

BuildScatterGatherList performs the same operation as GetScatterGatherList, except that it uses the buffer supplied in the ScatterGatherBuffer parameter to hold the scatter/gather list that it creates. In contrast, GetScatterGatherList dynamically allocates a buffer to hold the scatter/gather list. If insufficient memory is available to allocate the buffer, GetScatterGatherList can fail with a STATUS_INSUFFICIENT_RESOURCES error. Drivers that must avoid this scenario can pre-allocate a buffer to hold the scatter/gather list, and use BuildScatterGatherList instead.

A driver can use the CalculateScatterGatherListSize routine to determine the size of buffer to allocate to hold the scatter/gather list.

When BuildScatterGatherList creates a scatter/gather list to write to a device, the system can make a copy of the data to be written, and use that copy to perform the DMA operation. To access that copy, use BuildMdlFromScatterGatherList to access that copy.

This routine can be only be called at IRQL >= DISPATCH_LEVEL.

See Also

DEVICE_DESCRIPTION, DMA_OPERATIONS, BuildMdlFromScatterGatherList, CalculateScatterGatherListSize, GetScatterGatherList, IoGetDmaAdapter


CalculateScatterGatherListSize

CalculateScatterGatherListSize calculates the size, in bytes, of scatter/gather list necessary to hold a given buffer.

NTSTATUS
  CalculateScatterGatherListSize(
    IN PDMA_ADAPTER  DmaAdapter,
    IN OPTIONAL PMDL  Mdl,
    IN PVOID  CurrentVa,
    IN ULONG  Length,
    OUT PSIZE_T  ScatterGatherListSize,
    OUT OPTIONAL PULONG  NumberOfMapRegisters
    );

Parameters

DmaAdapter
Pointer to the DMA_ADAPTER structure returned by IoGetDmaAdapter that represents the bus master adapter or DMA controller.
Mdl
Either NULL or a pointer to the MDL that contains the buffer.
CurrentVa
Pointer to the virtual address of the beginning of the buffer.
Length
Specifies the length of the buffer, in bytes.
ScatterGatherListSize
Pointer to the variable the routine uses to return the size of the scatter/gather list, in bytes.
NumberOfMapRegisters
Either NULL or pointer to the variable the routine uses to return the number of map registers needed for DMA operations on the buffer.

Return Value

CalculateScatterGatherListSize returns one of the following status codes.

STATUS_SUCCESS
The values returned in ScatterGatherListSize and NumberOfMapRegisters are valid.
STATUS_INSUFFICIENT_RESOURCES
If the number of map registered required exceeds the number of map registers available, the routine returns.
STATUS_BUFFER_TOO_SMALL
If the Length parameter is too big to fit within the buffer, the routine returns.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

This routine is only available on Windows XP and later.

CalculateScatterGatherListSize is not a system routine that can be called directly by name. This routine can be called only by pointer from the address returned in a DMA_OPERATIONS structure. Drivers obtain the address of this routine by calling IoGetDmaAdapter with the Version member of the DeviceDescription parameter set to DEVICE_DESCRIPTION_VERSION2. If IoGetDmaAdapter returns NULL, the routine is not available on your platform..

If the caller passes NULL for the Mdl parameter, the routine calculates the maximum possible size needed to hold a scatter/gather list for the specified buffer. If the caller specifies the MDL that contains the buffer in the Mdl parameter, the routine computes the actual size needed to hold the scatter/gather list.

A driver uses CalculateScatterGatherListSize to allocate a scatter/gather list buffer to pass to BuildScatterGatherList.

See Also

DEVICE_DESCRIPTION, DMA_OPERATIONS, BuildScatterGatherList, IoGetDmaAdapter


FlushAdapterBuffers

FlushAdapterBuffers flushes any data remaining in the system DMA controller's internal cache or in a bus master adapter's internal cache at the end of a DMA transfer operation.

BOOLEAN
  FlushAdapterBuffers(
    IN PDMA_ADAPTER  DmaAdapter,
    IN PMDL  Mdl,
    IN PVOID  MapRegisterBase,
    IN PVOID  CurrentVa,
    IN ULONG  Length,
    IN BOOLEAN  WriteToDevice
    );

Parameters

DmaAdapter
Points to the DMA_ADAPTER structure returned by IoGetDmaAdapter that represents the bus master adapter or DMA controller.
Mdl
Points to the MDL that describes the buffer previously passed in the driver's call to MapTransfer.
MapRegisterBase
Points to the handle passed to the driver's AdapterControl routine by AllocateAdapterChannel.
CurrentVa
Points to the current virtual address in the buffer, described by the Mdl, where the I/O operation occurred. This value must be the same as the initial CurrentVa value passed to MapTransfer.
Length
Specifies the length, in bytes, of the buffer.
WriteToDevice
Specifies the direction of the DMA transfer operation: TRUE for a transfer from a buffer in system memory to the driver's device.

Include

wdm.h or ntddk.h

Return Value

FlushAdapterBuffers returns TRUE if any data remaining in the DMA controller's or bus master adapter's internal cache has been successfully flushed into system memory or out to the device.

Comments

FlushAdapterBuffers is not a system routine that can be called directly by name. This routine is callable only by pointer from the address returned in a DMA_OPERATIONS structure. Drivers obtain the address of this routine by calling IoGetDmaAdapter.

To ensure that a DMA transfer is complete, every driver that performs DMA operations must call FlushAdapterBuffers before completing the IRP that requested the DMA transfer and before freeing the map registers.

A driver can get the initial CurrentVa for the start of a packet-based DMA transfer by calling MmGetMdlVirtualAddress. However, the value returned is an index into the Mdl, rather than a valid virtual address. If the driver must split a large transfer request into more than one DMA operation, it must update CurrentVa and Length for each DMA operation.

Callers of FlushAdapterBuffers must be running at IRQL <= DISPATCH_LEVEL.

See Also

AllocateAdapterChannel, IoGetDmaAdapter, KeFlushIoBuffers, MapTransfer, MmGetMdlVirtualAddress, DMA_OPERATIONS


FreeAdapterChannel

FreeAdapterChannel releases the system DMA controller when a driver has completed all DMA operations necessary to satisfy the current IRP.

VOID
  FreeAdapterChannel(
    IN PDMA_ADAPTER  DmaAdapter
    );

Parameters

DmaAdapter
Points to the DMA_ADAPTER structure returned by IoGetDmaAdapter that represents the bus master adapter or DMA controller.

Include

wdm.h or ntddk.h

Comments

FreeAdapterChannel is not a system routine that can be called directly by name. This routine is callable only by pointer from the address returned in a DMA_OPERATIONS structure. Drivers obtain the address of this routine by calling IoGetDmaAdapter.

After a driver has transferred all the data and called FlushAdapterBuffers, it calls FreeAdapterChannel to release the system DMA controller that was previously allocated with a call to AllocateAdapterChannel.

FreeAdapterChannel frees any map registers that were allocated by an earlier call to AllocateAdapterChannel. A driver calls this routine only if its AdapterControl routine returns KeepObject.

Callers of FreeAdapterChannel must be running at IRQL DISPATCH_LEVEL.

See Also

AllocateAdapterChannel, FlushAdapterBuffers, FreeMapRegisters, IoGetDmaAdapter, MapTransfer, DMA_OPERATIONS


FreeCommonBuffer

FreeCommonBuffer frees a common buffer allocated by AllocateCommonBuffer, along with all resources the buffer uses.

VOID
  FreeCommonBuffer(
    IN PDMA_ADAPTER  DmaAdapter,
    IN ULONG  Length,
    IN PHYSICAL_ADDRESS  LogicalAddress,
    IN PVOID  VirtualAddress,
    IN BOOLEAN  CacheEnabled
    );

Parameters

DmaAdapter
Points to the DMA_ADAPTER structure returned by IoGetDmaAdapter that represents the bus master adapter or DMA controller.
Length
Specifies the number of bytes to deallocate.
LogicalAddress
Specifies the logical address of the allocated memory range.
VirtualAddress
Points to the corresponding virtual address of the allocated memory range.
CacheEnabled
Indicates whether the allocated memory is cached.

Include

wdm.h or ntddk.h

Comments

FreeCommonBuffer is not a system routine that can be called directly by name. This routine is callable only by pointer from the address returned in a DMA_OPERATIONS structure. Drivers obtain the address of this routine by calling IoGetDmaAdapter.

To release a common buffer, a driver calls FreeCommonBuffer to unmap both its logical and virtual addresses. The parameters passed to FreeCommonBuffer must match exactly those passed to and returned from AllocateCommonBuffer. A driver cannot free part of an allocated common buffer.

Callers of FreeCommonBuffer must be running at IRQL PASSIVE_LEVEL.

See Also

AllocateCommonBuffer, IoGetDmaAdapter, DMA_OPERATIONS


FreeMapRegisters

FreeMapRegisters releases a set of map registers that were saved from a call to AllocateAdapterChannel.

VOID
  FreeMapRegisters(
    IN PDMA_ADAPTER  DmaAdapter,
    PVOID  MapRegisterBase,
    ULONG  NumberOfMapRegisters
    );

Parameters

DmaAdapter
Points to the DMA_ADAPTER structure returned by IoGetDmaAdapter that represents the bus master adapter or DMA controller .
MapRegisterBase
Points to the handle returned by the driver's call to AllocateAdapterChannel.
NumberOfMapRegisters
Specifies the number of map registers to be released. This value must match the number specified in an earlier call to AllocateAdapterChannel.

Include

wdm.h or ntddk.h

Comments

FreeMapRegisters is not a system routine that can be called directly by name. This routine is only callable by pointer from the address returned in a DMA_OPERATIONS structure. Drivers obtain the address of this routine by calling IoGetDmaAdapter.

When the driver of a bus master device has completed the current packet-based DMA transfer request, it calls FreeMapRegisters to release the map registers previously allocated by a call to AllocateAdapterChannel and retained because its AdapterControl routine returned DeallocateObjectKeepRegisters. The driver must call FreeMapRegisters after calling FlushAdapterBuffers .

Callers of FreeMapRegisters must be running at IRQL DISPATCH_LEVEL.

See Also

AllocateAdapterChannel, IoGetDmaAdapter, MapTransfer, DMA_OPERATIONS


GetDmaAlignment

GetDmaAlignment returns the alignment requirements of the DMA system.

ULONG
  GetDmaAlignment(
    IN PDMA_ADAPTER  DmaAdapter
    );

Parameters

DmaAdapter
Points to the DMA_ADAPTER structure returned by IoGetDmaAdapter that represents the bus master adapter or DMA controller.

Include

wdm.h or ntddk.h

Return Value

GetDmaAlignment returns the alignment requirements of the DMA system.

Comments

GetDmaAlignment is not a system routine that can be called directly by name. This routine is callable only by pointer from the address returned in a DMA_OPERATIONS structure. Drivers obtain the address of this routine by calling IoGetDmaAdapter.

A driver can call this routine to determine alignment requirements for DMA buffers it allocates. The returned value should be used to set the AlignmentRequirement field in the device object. A driver may need to increase this value because of additional hardware device restrictions.

Callers of GetDmaAlignment must be running at IRQL PASSIVE_LEVEL.

See Also

IoGetDmaAdapter, DMA_OPERATIONS , DEVICE_OBJECT


GetScatterGatherList

GetScatterGatherList prepares the system for a DMA scatter/gather operation on behalf of the target device object, through either the system DMA controller or a bus master adapter.

NTSTATUS
  GetScatterGatherList (
    IN PDMA_ADAPTER  DmaAdapter,
    IN PDEVICE_OBJECT  DeviceObject,
    IN PMDL  Mdl,
    IN PVOID  CurrentVa,
    IN ULONG  Length,
    IN PDRIVER_LIST_CONTROL  ExecutionRoutine,
    IN PVOID  Context,
    IN BOOLEAN  WriteToDevice
    );

Parameters

DmaAdapter
Points to the DMA_ADAPTER structure returned by IoGetDmaAdapter that represents the bus master adapter or DMA controller.
DeviceObject
Points to the device object that represents the target device for the DMA operation.
Mdl
Points to the MDL that describes the buffer at MdlAddress in the current IRP.
CurrentVa
Points to the current virtual address in the MDL for the buffer to be mapped for a DMA transfer operation.
Length
Specifies the length, in bytes, to be mapped.
ExecutionRoutine
Points to a driver-supplied AdapterListControl routine, which is called at DISPATCH_LEVEL when the system DMA controller or bus master adapter is available.
Context
Points to the driver-determined context passed to the driver's Execution routine when it is called.
WriteToDevice
Indicates the direction of the DMA transfer: TRUE for a transfer from the buffer to the device, and FALSE otherwise.

Include

wdm.h or ntddk.h

Return Value

This routine can return one of the following NTSTATUS values:

Value | Meaning
STATUS_SUCCESS | The operation succeeded.
STATUS_INSUFFICIENT_RESOURCES | The routine could not allocate sufficient memory or the number of map registers required for the transfer is larger than the value returned by IoGetDmaAdapter.
STATUS_BUFFER_TOO_SMALL | The buffer is too small for the requested transfer.

Comments

GetScatterGatherList is not a system routine that can be called directly by name. This routine is callable only by pointer from the address returned in a DMA_OPERATIONS structure. Drivers obtain the address of this routine by calling IoGetDmaAdapter.

As soon as the appropriate DMA channel and any necessary map registers are available, GetScatterGatherList creates a scatter/gather list, initializes the map registers, and then calls the driver-supplied AdapterListControl routine to carry out the I/O operation.

GetScatterGatherList combines the actions of the AllocateAdapterChannel and MapTransfer routines for drivers that perform scatter/gather DMA. GetScatterGatherList determines how many map registers are required for the transfer, allocates the map registers, maps the buffers for DMA, and fills in the scatter/gather list. It then calls the supplied AdapterListControl routine, passing a pointer to the scatter/gather list in ScatterGather. The driver should retain this pointer for use when calling PutScatterGatherList. Note that GetScatterGatherList does not have the queuing restrictions that apply to AllocateAdapterChannel.

In its AdapterListControl routine, the driver should perform the I/O. On return from the driver-supplied routine, GetScatterGatherList keeps the map registers but frees the DMA adapter structure. The driver must call PutScatterGatherList (which flushes the buffers) before it can access the data in the buffer.

This routine can handle chained MDLs, provided that the total number of map registers required by all chained MDLs does not exceed the number available.

GetScatterGatherList is not supported on Windows 98 or Windows ME.

Callers of GetScatterGatherList must be running at IRQL DISPATCH_LEVEL.

See Also

IoGetDmaAdapter, PutScatterGatherList, AllocateAdapterChannel, DMA_OPERATIONS, SCATTER_GATHER_LIST


MapTransfer

MapTransfer sets up map registers for an adapter object to map a DMA transfer from a locked-down buffer.

PHYSICAL_ADDRESS
  MapTransfer(
    IN PDMA_ADAPTER  DmaAdapter,
    IN PMDL  Mdl,
    IN PVOID  MapRegisterBase,
    IN PVOID  CurrentVa,
    IN OUT PULONG  Length,
    IN BOOLEAN  WriteToDevice
    );

Parameters

DmaAdapter
Points to the DMA adapter object returned by IoGetDmaAdapter and previously passed to AllocateAdapterChannel for the current IRP's transfer request.
Mdl
Points to one of the following: the MDL that describes the buffer at MdlAddress in the current IRP or the MDL that describes the common buffer set up by the driver of a slave device (auto-initialize mode).
MapRegisterBase
Points to the handle previously returned by AllocateAdapterChannel for the current IRP.
CurrentVa
Points to the current virtual address of the data to be transferred for a DMA transfer operation.
Length
Specifies the length, in bytes, to be mapped. If the driver indicated that its device was a bus master with scatter/gather support when it called IoGetDmaAdapter, the value of Length on return from MapTransfer indicates how many bytes were mapped. Otherwise, the input and output values of Length are identical.
WriteToDevice
Indicates the direction of the transfer operation: TRUE for a transfer from the locked-down buffer to the device.

Include

wdm.h or ntddk.h

Return Value

MapTransfer returns the logical address of the region mapped, which the driver of a bus master adapter can use. Drivers of devices that use a system DMA controller cannot use this value and should ignore it.

Comments

MapTransfer is not a system routine that can be called directly by name. This routine is callable only by pointer from the address returned in a DMA_OPERATIONS structure. Drivers obtain the address of this routine by calling IoGetDmaAdapter.

The DmaAdapter must have already been allocated as a result of the driver's preceding call to AllocateAdapterChannel.

The number of map registers that can be set up cannot exceed the maximum returned when the driver called IoGetDmaAdapter.

A driver can get the initial CurrentVa for the start of a packet-based DMA transfer by calling MmGetMdlVirtualAddress. However, the value returned is an index into the Mdl, rather than a valid virtual address. If the driver must split a large transfer request into more than one DMA operation, it must update CurrentVa and Length for each DMA operation.

The driver of a bus master device with scatter/gather support can use the returned logical address and updated Length value to build a scatter/gather list, calling MapTransfer repeatedly until it has used all available map registers for the transfer operation. However, such a driver could more simply use the GetScatterGatherList routine.

Callers of MapTransfer must be running at IRQL <= DISPATCH_LEVEL.

See Also

ADDRESS_AND_SIZE_TO_SPAN_PAGES, AllocateCommonBuffer, IoGetDmaAdapter, AllocateAdapterChannel, FlushAdapterBuffers, FreeAdapterChannel, FreeMapRegisters, KeFlushIoBuffers, MmGetMdlVirtualAddress


PutDmaAdapter

PutDmaAdapter frees a DMA_ADAPTER structure previously allocated by IoGetDmaAdapter.

VOID
  PutDmaAdapter(
    PDMA_ADAPTER  DmaAdapter
    );

Parameters

DmaAdapter
Points to the DMA_ADAPTER structure to be released.

Include

wdm.h or ntddk.h

Comments

PutDmaAdapter is not a system routine that can be called directly by name. This routine is callable only by pointer from the address returned in a DMA_OPERATIONS structure. Drivers obtain the address of this routine by calling IoGetDmaAdapter.

PutDmaAdapter frees a DMA adapter object previously allocated by IoGetDmaAdapter. Drivers should call PutDmaAdapter after completing DMA operations and freeing any map registers and common buffer allocated with this adapter object. After PutDmaAdapter returns, the driver can no longer use the DMA adapter object.

A driver must call PutDmaAdapter when it receives a PnP IRP_MN_STOP_DEVICE request.

Callers of PutDmaAdapter must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoGetDmaAdapter, DMA_OPERATIONS


PutScatterGatherList

PutScatterGatherList frees the previously allocated map registers and scatter/gather list used in scatter/gather DMA.

VOID
  PutScatterGatherList(
    IN PDMA_ADAPTER  DmaAdapter,
    IN PSCATTER_GATHER_LIST  ScatterGather,
    IN BOOLEAN  WriteToDevice
    );

Parameters

DmaAdapter
Points to the DMA_ADAPTER structure returned by IoGetDmaAdapter that represents the bus master adapter or DMA controller.
ScatterGather
Points to a scatter/gather list previously returned by GetScatterGatherList.
WriteToDevice
Indicates the direction of the DMA transfer: specify TRUE for a transfer from the buffer to the device, and FALSE otherwise.

Include

wdm.h or ntddk.h

Return Value

This routine can return one of the following NTSTATUS values:

Value | Meaning
STATUS_SUCCESS | The map registers and scatter/gather list were successfully deallocated.

Comments

PutScatterGatherList is not a system routine that can be called directly by name. This routine is callable only by pointer from the address returned in a DMA_OPERATIONS structure. Drivers obtain the address of this routine by calling IoGetDmaAdapter.

Drivers should call PutScatterGatherList after completing scatter/gather I/O. This routine flushes the adapter buffers, frees the map registers, and frees the scatter/gather list previously allocated by GetScatterGatherList.

PutScatterGatherList is not supported on Windows 98 or Windows ME.

Callers of PutScatterGatherList must be running at IRQL DISPATCH_LEVEL.

See Also

IoGetDmaAdapter, GetScatterGatherList, DMA_OPERATIONS, SCATTER_GATHER_LIST


ReadDmaCounter

ReadDmaCounter returns the number of bytes remaining to be transferred during the current slave DMA operation.

ULONG
  ReadDmaCounter(
    IN PDMA_ADAPTER  DmaAdapter
    );

Parameters

DmaAdapter
Points to the adapter object previously returned by IoGetDmaAdapter representing the system DMA controller channel currently in use.

Include

wdm.h or ntddk.h

Return Value

ReadDmaCounter returns the number of bytes remaining to be transferred in the current DMA operation.

Comments

ReadDmaCounter is not a system routine that can be called directly by name. This routine is callable only by pointer from the address returned in a DMA_OPERATIONS structure. Drivers obtain the address of this routine by calling IoGetDmaAdapter.

ReadDmaCounter can be called only by drivers of slave DMA devices. Usually, the caller is the driver of a slave device that uses a system DMA controller's autoinitialize mode.

Callers of ReadDmaCounter must be running at IRQL <= DISPATCH_LEVEL.

See Also

AllocateCommonBuffer, IoGetDmaAdapter, FlushAdapterBuffers, MapTransfer


Executive Support Routines

References for the Ex Xxx routines are in alphabetical order.

For an overview of the functionality of these routines, see Summary of Kernel-Mode Support Routines.

The following routines are reserved for system use. Use the corresponding KeXxxSpinLock routines instead.

ExAcquireSpinLock

ExAcquireSpinLockAtDpcLevel

ExReleaseSpinLock

ExReleaseSpinLockFromDpcLevel


ExAcquireFastMutex

ExAcquireFastMutex acquires the given fast mutex with APCs to the current thread disabled.

VOID
  ExAcquireFastMutex(
    IN PFAST_MUTEX  FastMutex
    );

Parameters

FastMutex
Pointer to an initialized fast mutex for which the caller provides the storage.

Include

wdm.h or ntddk.h

Comments

ExAcquireFastMutex puts the caller into a wait state if the given fast mutex cannot be acquired immediately. Otherwise, the caller is given ownership of the fast mutex with APCs to the current thread disabled until it releases the fast mutex.

Use ExTryToAcquireFastMutex if the current thread can do other work before it waits on the acquisition of the given mutex.

Any fast mutex acquired using ExAcquireFastMutex or ExTryToAcquireFastMutex must be released with ExReleaseFastMutex.

Callers of ExAcquireFastMutex must be running at IRQL < DISPATCH_LEVEL. ExAcquireFastMutex sets the IRQL to APC_LEVEL, and the caller continues to run at APC_LEVEL after ExAcquireFastMutex returns. ExAcquireFastMutex saves the caller's previous IRQL in the mutex, however, and that IRQL is restored when the caller invokes ExReleaseFastMutex.

See Also

ExAcquireFastMutexUnsafe, ExInitializeFastMutex, ExReleaseFastMutex, ExTryToAcquireFastMutex


ExAcquireFastMutexUnsafe

ExAcquireFastMutexUnsafe acquires the given fast mutex for the current thread.

VOID
  ExAcquireFastMutexUnsafe(
  IN PFAST_MUTEX  FastMutex
    );

Parameters

FastMutex
Pointer to an initialized fast mutex for which the caller provides the storage.

Include

wdm.h or ntddk.h

Comments

ExAcquireFastMutexUnsafe puts the caller into a wait state if the given fast mutex cannot be acquired immediately. Otherwise, the caller is given ownership of the fast mutex and exclusive access to the resource it protects until it releases the fast mutex.

Any fast mutex acquired using ExAcquireFastMutexUnsafe must be released with ExReleaseFastMutexUnsafe.

Callers of ExAcquireFastMutexUnsafe must ensure that APCs are not delivered to the current thread while the fast mutex is held. This can be accomplished in two ways:

  1. Callers can set the IRQL = APC_LEVEL before calling ExAcquireFastMutexUnsafe or
  2. Callers can invoke ExAcquireFastMutexUnsafe from within a critical section by calling KeEnterCriticalRegion prior to calling ExAcquireFastMutexUnsafe.

If the caller chooses to invoke ExAcquireFastMutexUnsafe from within a critical section, then the caller must be running at IRQL < DISPATCH_LEVEL.

See Also

ExAcquireFastMutex, ExInitializeFastMutex, ExReleaseFastMutexUnsafe, KeEnterCriticalRegion, KeLeaveCriticalRegion


ExAcquireResourceExclusive

ExAcquireResourceExclusive is exported to support existing driver binaries and is obsolete; use ExAcquireResourceExclusiveLite instead.

BOOLEAN
  ExAcquireResourceExclusive(
    IN PERESOURCE  Resource,
    IN BOOLEAN  Wait
    );


ExAcquireResourceExclusiveLite

ExAcquireResourceExclusiveLite acquires the given resource for exclusive access by the calling thread.

BOOLEAN
  ExAcquireResourceExclusiveLite(
    IN PERESOURCE  Resource,
    IN BOOLEAN  Wait
    );

Include

ntddk.h

Parameters

Resource
Pointer to the resource to acquire.
Wait
Set to TRUE if the caller should be put into a wait state until the resource can be acquired if it cannot be acquired immediately.

Return Value

ExAcquireResourceExclusiveLite returns TRUE if the resource is acquired. This routine returns FALSE if the input Wait is FALSE and exclusive access cannot be granted immediately.

Comments

Normal kernel APCs must be disabled before calling ExAcquireResourceExclusiveLite. Otherwise a bugcheck occurs. Normal kernel APCs can be disabled by calling KeEnterCriticalRegion or by raising the calling thread's IRQL to APC_LEVEL.

For better performance, call ExTryToAcquireResourceExclusiveLite, rather than calling ExAcquireResourceExclusiveLite with Wait set to FALSE.

Callers of ExAcquireResourceExclusiveLite must be running at IRQL < DISPATCH_LEVEL.

See Also

ExAcquireResourceSharedLite, ExGetExclusiveWaiterCount, ExGetSharedWaiterCount, ExInitializeResourceLite, ExReinitializeResourceLite, ExIsResourceAcquiredExclusiveLite, ExReleaseResourceForThreadLite, ExTryToAcquireResourceExclusiveLite, KeEnterCriticalRegion


ExAcquireResourceShared

ExAcquireResourceShared is exported to support existing driver binaries, and is obsolete; use ExAcquireResourceSharedLite instead.

BOOLEAN
  ExAcquireResourceSharedLite(
    IN PERESOURCE  Resource,
    IN BOOLEAN  Wait
    );


ExAcquireResourceSharedLite

ExAcquireResourceSharedLite acquires the given resource for shared access by the calling thread.

BOOLEAN
  ExAcquireResourceSharedLite(
  IN PERESOURCE  Resource,
  IN BOOLEAN  Wait
    );

Parameters

Resource
Pointer to the resource to acquire.
Wait
Set to TRUE if the resource cannot be acquired immediately and if the caller should be put into a wait state until the resource can be acquired.

Include

ntddk.h

Return Value

ExAcquireResourceSharedLite returns TRUE if (or when) the resource is acquired. This routine returns FALSE if the input Wait is FALSE and shared access cannot be granted immediately.

Comments

Whether or when the caller is given shared access to the given resource depends on the following:

  • If the resource is currently unowned, shared access is granted immediately to the current thread.
  • If the caller already has acquired the resource (for shared or exclusive access), the current thread is granted the same type of access recursively. Note that making this call does not convert a caller's exclusive ownership of a given resource to shared.
  • If the resource is currently owned as shared by another thread and no thread is waiting for exclusive access to the resource, shared access is granted to the caller immediately. The caller is put into a wait state if there is an exclusive waiter.
  • If the resource is currently owned as exclusive by another thread or if there is another thread waiting for exclusive access and the caller does not already have shared access to the resource, the current thread either is put into a wait state (Wait set to TRUE) or ExAcquireResourceSharedLite returns FALSE.

Callers of ExAcquireResourceSharedLite must be running at IRQL < DISPATCH_LEVEL.

See Also

ExAcquireResourceExclusiveLite, ExAcquireSharedStarveExclusive, ExAcquireSharedWaitForExclusive, ExConvertExclusiveToSharedLite, ExGetExclusiveWaiterCount, ExGetSharedWaiterCount, ExInitializeResourceLite, ExReinitializeResourceLite, ExIsResourceAcquiredSharedLite, ExReleaseResourceForThreadLite


ExAcquireSharedStarveExclusive

ExAcquireSharedStarveExclusive acquires a given resource for shared access without waiting for any pending attempts to acquire exclusive access to the same resource.

BOOLEAN
  ExAcquireSharedStarveExclusive(
    IN PERESOURCE  Resource,
    IN BOOLEAN  Wait
    );

Parameters

Resource
Pointer to the resource to be acquired for shared access.
Wait
Set to TRUE if the caller will wait until the resource becomes available when access cannot be granted immediately.

Include

ntddk.h

Return Value

ExAcquireSharedStarveExclusive returns TRUE if the requested access is granted. This routine returns FALSE if the input Wait is FALSE and shared access cannot be granted immediately.

Comments

Whether or when the caller is given shared access to the given resource depends on the following:

  • If the resource is currently unowned, shared access is granted immediately to the current thread.
  • If the caller already has acquired the resource (for shared or exclusive access), the current thread is granted the same type of access recursively. Note that making this call does not convert a caller's exclusive ownership of a given resource to shared.
  • If the resource is currently owned as shared by another thread, shared access is granted to the caller immediately, even if another thread is waiting for exclusive access to that resource.
  • If the resource is currently owned as exclusive by another thread, the caller either is put into a wait state (Wait set to TRUE) or ExAcquireSharedStarveExclusive returns FALSE.

Callers of ExAcquireSharedStarveExclusive usually need quick access to a shared resource in order to save an exclusive accessor from doing redundant work. For example, a file system might call this routine to modify a cached resource, such as a BCB pinned in the cache, before the Cache Manager can acquire exclusive access to the resource and write the cache out to disk.

Callers of ExAcquireSharedStarveExclusive must be running at IRQL < DISPATCH_LEVEL.

See Also

ExAcquireResourceSharedLite, ExAcquireSharedWaitForExclusive, ExConvertExclusiveToSharedLite, ExGetExclusiveWaiterCount, ExIsResourceAcquiredExclusiveLite, ExIsResourceAcquiredSharedLite, ExTryToAcquireResourceExclusiveLite


ExAcquireSharedWaitForExclusive

ExAcquireSharedWaitForExclusive acquires the given resource for shared access immediately if shared access can be granted.

BOOLEAN
  ExAcquireSharedWaitForExclusive(
    IN PERESOURCE  Resource,
    IN BOOLEAN  Wait
    );

Parameters

Resource
Pointer to the resource to be acquired for shared access.
Wait
Set to TRUE if the caller will wait until the resource becomes available when access cannot be granted immediately.

Include

ntddk.h

Return Value

ExAcquireSharedWaitForExclusive returns TRUE if the requested access is granted or an exclusive owner releases the resource. This routine returns FALSE if the input Wait is FALSE and shared access cannot be granted immediately.

Comments

If shared access cannot be granted immediately, the caller can wait for other threads to acquire and release exclusive ownership of the resource.

Whether or when the caller is given shared access to the given resource depends on the following:

  • If the resource is currently unowned, shared access is granted immediately to the current thread.
  • If the caller already has exclusive access to the resource, the current thread is granted the same type of access recursively.
  • If the resource is currently owned as shared and there are no pending attempts to acquire exclusive access, shared access is granted to the caller immediately.
  • If the resource is currently owned as shared but there is a pending attempt to acquire exclusive access, the caller either is put into a wait state (Wait set to TRUE) or ExAcquireSharedWaitForExclusive returns FALSE.

    When the current thread waits to acquire the resource until after a pending exclusive ownership has been released, ExAcquireSharedWaitForExclusive returns TRUE when the current thread is granted shared access to the resource and resumes execution.

Callers of ExAcquireSharedWaitForExclusive must be running at IRQL < DISPATCH_LEVEL.

See Also

ExAcquireResourceSharedLite, ExAcquireSharedStarveExclusive, ExConvertExclusiveToSharedLite, ExGetExclusiveWaiterCount, ExIsResourceAcquiredExclusiveLite, ExIsResourceAcquiredSharedLite, ExTryToAcquireResourceExclusiveLite


ExAllocateFromNPagedLookasideList

ExAllocateFromNPagedLookasideList returns a pointer to a nonpaged entry from the given lookaside list, or it returns a pointer to a newly allocated nonpaged entry.

PVOID
  ExAllocateFromNPagedLookasideList(
    IN PNPAGED_LOOKASIDE_LIST  Lookaside
    );

Parameters

Lookaside
Pointer to the head of the lookaside list, which the caller already initialized with ExInitializeNPagedLookasideList.

Include

wdm.h or ntddk.h

Return Value

ExAllocateFromNPagedLookasideList returns a pointer to an entry if one can be allocated. Otherwise, it returns NULL.

Comments

If the given lookaside list is not empty, ExAllocateFromNPagedLookasideList removes the first entry from the list and returns a pointer to this entry. Otherwise, ExAllocateFromNPagedLookasideList either calls the Allocate routine specified at list initialization or ExAllocatePoolWithTag to return an entry pointer.

The caller then can set up the returned entry with any caller-determined data. For example, a driver might use each such fixed-size entry to set up command blocks, like SCSI SRBs, to peripheral devices on a particular type of I/O bus. The caller should release each entry with ExFreeToNPagedLookasideList when it is no longer in use.

Callers of ExAllocateFromNPagedLookasideList must be running at IRQL <= DISPATCH_LEVEL.

See Also

ExInitializeNPagedLookasideList, ExAllocateFromPagedLookasideList, ExFreeToNPagedLookasideList


ExAllocateFromPagedLookasideList

ExAllocateFromPagedLookasideList returns a pointer to a paged entry from the given lookaside list, or it returns a pointer to a newly allocated paged entry.

PVOID
  ExAllocateFromPagedLookasideList(
    IN PPAGED_LOOKASIDE_LIST  Lookaside
    );

Parameters

Lookaside
Pointer to the resident head of the lookaside list, which the caller already initialized with ExInitializePagedLookasideList.

Include

wdm.h or ntddk.h

Return Value

ExAllocateFromPagedLookasideList returns a pointer to an entry if one can be allocated. Otherwise, it returns NULL.

Comments

If the given lookaside list is not empty, ExAllocateFromPagedLookasideList removes the first entry from the list and returns a pointer to this entry. Otherwise, ExAllocateFromPagedLookasideList either calls the Allocate routine specified at list initialization or ExAllocatePoolWithTag to return an entry pointer.

The caller then can set up the returned entry with any caller-determined data. Because the entries in a paged lookaside list are allocated from pageable memory, access to these entries must not cause a page fault. Consequently, the user of a paged lookaside list must ensure that each such entry cannot be accessed from an arbitrary thread context or at raised IRQL. The caller should release each entry with ExFreeToPagedLookasideList when it is no longer in use.

Callers of ExAllocateFromPagedLookasideList must be running at IRQL < DISPATCH_LEVEL.

See Also

ExInitializePagedLookasideList, ExFreeToPagedLookasideList


ExAllocateFromZone

ExAllocateFromZone is exported to support existing driver binaries. This routine is obsolete; use lookaside lists instead. See Buffer Management for more information.

PVOID
  ExAllocateFromZone(
    IN PZONE_HEADER  Zone
    );


ExAllocatePool

ExAllocatePool allocates pool memory of the specified type and returns a pointer to the allocated block.

PVOID
  ExAllocatePool(
    IN POOL_TYPE  PoolType,
    IN SIZE_T  NumberOfBytes
    );

Parameters

PoolType
Specifies the type of pool memory to allocate. See POOL_TYPE for a description of the available pool memory types.
NumberOfBytes
Specifies the number of bytes to allocate.

Include

wdm.h or ntddk.h

Return Value

ExAllocatePool returns NULL if there is insufficient memory in the free pool to satisfy the request. Otherwise the routine returns a pointer to the allocated memory.

Comments

This routine is used for general pool allocation of memory.

If the NumberOfBytes requested is PAGE_SIZE or greater, a page-aligned buffer is allocated. Memory allocations of PAGE_SIZE or less do not cross page boundaries. Memory allocations of less than PAGE_SIZE are not necessarily page-aligned but are aligned on an 8-byte boundary.

A successful allocation requesting NumberOfBytes < PAGE_SIZE of nonpaged pool gives the caller exactly the number of requested bytes of memory. Any successful allocation that requests NumberOfBytes > PAGE_SIZE wastes all unused bytes on the last-allocated page.

Callers of ExAllocatePool must be running at IRQL <= DISPATCH_LEVEL. A caller at DISPATCH_LEVEL must specify a NonPaged Xxx PoolType. Otherwise, the caller must be running at IRQL < DISPATCH_LEVEL.

If ExAllocatePool returns NULL, the caller should return the NTSTATUS value STATUS_INSUFFICIENT_RESOURCES or should delay processing to another point in time.

See Also

ExAllocatePoolWithTag, ExFreePool


ExAllocatePoolWithQuota

ExAllocatePoolWithQuota allocates pool memory, charging quota against the current thread.

PVOID
  ExAllocatePoolWithQuota(
    IN POOL_TYPE  PoolType,
    IN SIZE_T  NumberOfBytes
    );

Parameters

PoolType
Specifies the type of pool memory to allocate. See POOL_TYPE for a description of the available pool memory types.
NumberOfBytes
Specifies the number of bytes to allocate.

Include

wdm.h or ntddk.h

Return Value

ExAllocatePoolWithQuota returns a pointer to the allocated pool.

If the request cannot be satisfied, ExAllocatePoolWithQuota raises an exception.

Comments

This routine is called by highest-level drivers that allocate memory to satisfy a request in the context of the thread that originally made the I/O request. Lower-level drivers call ExAllocatePool instead.

If the NumberOfBytes requested is >= PAGE_SIZE, a page-aligned buffer is allocated. Quota is not charged to the thread for allocations >= PAGE_SIZE.

Memory requests for < PAGE_SIZE are allocated within a page and do not cross page boundaries. Memory requests for < PAGE_SIZE are not necessarily page-aligned but are aligned on an 8-byte boundary.

ExAllocatePoolWithQuota raises an exception if the pool allocation fails.

Callers of ExAllocatePoolWithQuota must be running at IRQL < DISPATCH_LEVEL.

See Also

ExAllocatePool, ExAllocatePoolWithQuotaTag, ExFreePool


ExAllocatePoolWithQuotaTag

ExAllocatePoolWithQuotaTag allocates pool memory, charging the quota against the current thread.

PVOID
  ExAllocatePoolWithQuotaTag(
    IN POOL_TYPE  PoolType,
    IN SIZE_T  NumberOfBytes,
    IN ULONG  Tag
    );

Parameters

PoolType
Specifies the type of pool memory to allocate. See POOL_TYPE for a description of the available pool memory types.
NumberOfBytes
Specifies the number of bytes to allocate.
Tag
Specifies a string, delimited by single quote marks, with up to four characters. The string is usually specified in reversed order.

Include

wdm.h or ntddk.h

Return Value

ExAllocatePoolWithQuotaTag returns a pointer to the allocated pool.

If the request cannot be satisfied, ExAllocatePoolWithQuotaTag raises an exception.

Comments

A call to this routine is equivalent to calling ExAllocatePoolWithQuota, except it inserts a caller-supplied tag before the allocation. This tag appears in any crash dump of the system that occurs.

During driver development on a checked build of the system, this routine can be useful for crash debugging. Calling this routine, rather than ExAllocatePoolWithQuota, causes the caller-supplied tag to be inserted into a crash dump of pool memory.

The Tag passed to this routine is more readable if its bytes are reversed when this routine is called. For example, if a caller passes 'Fred' as a Tag, it would appear as 'derF' if the pool is dumped or when tracking pool usage in the debugger.

Callers of ExAllocatePoolWithQuotaTag, like callers of ExAllocatePoolWithQuota, must be running at IRQL < DISPATCH_LEVEL.

See Also

ExAllocatePoolWithQuota, ExFreePool


ExAllocatePoolWithTag

ExAllocatePoolWithTag allocates pool memory.

PVOID
  ExAllocatePoolWithTag(
    IN POOL_TYPE  PoolType,
    IN SIZE_T  NumberOfBytes,
    IN ULONG  Tag
    );

Parameters

PoolType
Specifies the type of pool memory to allocate. See POOL_TYPE for a description of the available pool memory types.
NumberOfBytes
Specifies the number of bytes to allocate.
Tag
Specifies a string, delimited by single quote marks, with up to four characters. The string is usually specified in reversed order.

Include

wdm.h or ntddk.h

Return Value

ExAllocatePoolWithTag returns NULL if there is insufficient memory in the free pool to satisfy the request. Otherwise the routine returns a pointer to the allocated memory.

Comments

A call to this routine is equivalent to calling ExAllocatePool, except that ExAllocatePoolWithTag inserts a caller-supplied tag before the allocation. This tag appears in any crash dump of the system that occurs.

During driver development on a checked build of the system, this routine can be useful for debugging system crashes. Calling this routine, rather than ExAllocatePool, inserts the caller-supplied tag into a crash dump of pool memory.

The Tag passed to this routine is more readable if its bytes are reversed when this routine is called. For example, if a caller passes 'Fred' as a Tag, it would appear as 'derF' if pool is dumped or when tracking pool usage in the debugger.

Callers of ExAllocatePoolWithTag, like callers of ExAllocatePool, can be running at IRQL DISPATCH_LEVEL only if the requested PoolType is one of the NonPaged Xxx. Otherwise, callers must be running at IRQL < DISPATCH_LEVEL.

See Also

ExAllocatePool, ExAllocatePoolWithQuotaTag, ExAllocatePoolWithTagPriority, ExFreePool


ExAllocatePoolWithTagPriority

ExAllocatePoolWithTagPriority allocates pool memory of the specified type.

NTKERNELAPI PVOID NTAPI
  ExAllocatePoolWithTagPriority(
    IN POOL_TYPE  PoolType,
    IN SIZE_T  NumberOfBytes,
    IN ULONG  Tag,
    IN EX_POOL_PRIORITY  Priority
    );

Parameters

PoolType
Specifies the type of pool memory to allocate. See POOL_TYPE for a description of the available pool memory types.
NumberOfBytes
Specifies the number of bytes to allocate.
Tag
Specifies the four-character tag used to mark the allocated buffer. See ExAllocatePoolWithTag for a description of how to use tags.
Priority
Indicates the importance of this request.
Priority Value | Description
LowPoolPriority | Specifies the system may fail the request when it runs low on resources. Driver allocations that can recover from an allocation failure use this priority.
NormalPoolPriority | Specifies the system may fail the request when it runs very low on resources. Most drivers should use this value.
HighPoolPriority | Specifies the system must not fail the request, unless it is completely out of resources. Drivers only use this value when it is critically important for the request to succeed.

The XxxSpecialPoolOverrun and XxxSpecialPoolUnderrun variants specify how memory should be allocated when Driver Verifier (or special pool) is enabled. If the driver specifies XxxSpecialPoolUnderrun, when the Memory Manager allocates memory from special pool, it allocates it at the beginning of a physical page. If the driver specifies XxxSpecialPoolOverrun, the Memory Manager allocates it at the end of a physical page.

Include

ntddk.h

Comments

Callers of ExAllocatePoolWithTagPriority, like callers of ExAllocatePoolWithTag, can be running at IRQL DISPATCH_LEVEL only if the requested PoolType is one of the NonPaged Xxx. Otherwise, callers must be running at IRQL < DISPATCH_LEVEL.

See Also

ExAllocatePool, ExAllocatePoolWithTag, ExAllocatePoolWithQuotaTag, ExFreePool


ExConvertExclusiveToShared

ExConvertExclusiveToShared is exported to support existing driver binaries, and is obsolete. Use ExConvertExclusiveToSharedLite instead.

VOID
  ExConvertExclusiveToShared(
    IN PERESOURCE  Resource
    );


ExConvertExclusiveToSharedLite

ExConvertExclusiveToSharedLite converts a given resource from acquired for exclusive access to acquired for shared access.

VOID
  ExConvertExclusiveToSharedLite(
    IN PERESOURCE  Resource
    );

Parameters

Resource
Pointer to the resource for which the access should be converted.

Include

ntddk.h

Comments

The caller must have exclusive access to the given resource. During this conversion, the current thread and any other threads waiting for shared access to the resource are given shared access.

Callers of ExConvertExclusiveToSharedLite must be running at IRQL < DISPATCH_LEVEL.

See Also

ExIsResourceAcquiredExclusiveLite


ExCreateCallback

ExCreateCallback either creates a new callback object or opens an existing callback object on behalf of the caller.

NTSTATUS
  ExCreateCallback(
    OUT PCALLBACK_OBJECT  *CallbackObject,
    IN POBJECT_ATTRIBUTES  ObjectAttributes,
    IN BOOLEAN  Create,
    IN BOOLEAN  AllowMultipleCallbacks
    );

Parameters

CallbackObject
Pointer to the newly created or opened callback object if the routine completes with STATUS_SUCCESS.
ObjectAttributes
Pointer to a structure that contains the callback object's attributes, previously initialized by InitializeObjectAttributes.
Create
Requests that a callback object be created if the requested object cannot be opened.
AllowMultipleCallbacks
Specifies whether a newly created callback object should allow multiple registered callback routines. This parameter is ignored when Create is FALSE or when opening an existing object.

Include

wdm.h or ntddk.h

Return Value

ExCreateCallback returns STATUS_SUCCESS if a callback object was opened or created. Otherwise, it returns an NTSTATUS error code to indicate the nature of the failure.

Comments

A driver calls ExCreateCallback to create a new callback object or to open an existing callback object. After the object has been created or opened, other components can call ExRegisterCallback to register callback routines with the callback object.

Before calling ExCreateCallback, the driver must call InitializeObjectAttributes to initialize the OBJECT_ATTRIBUTES structure for the callback object. The caller must specify a name for the object; otherwise, the call fails with STATUS_UNSUCCESSFUL. Unnamed callback objects are not permitted. The caller should also specify any appropriate attributes, such as OBJ_CASE_INSENSITIVE.

When all operations have been completed with the callback object, the driver must call ObDereferenceObject to ensure that the object is deleted to prevent a memory leak.

The system creates the following callback objects for driver use:

Callback Object Name | Usage
\Callback\SetSystemTime | The system calls any callback routines registered for this object whenever the system time changes.
\Callback\PowerState | The system calls any callback routines registered for this object whenever certain system power characteristics change. When a driver registers for callback notification (ExRegisterCallback), it can specify the changes for which it should be notified.

Callers of this routine must be running at IRQL PASSIVE_LEVEL.

See Also

ExRegisterCallback, ExNotifyCallback, InitializeObjectAttributes, ObDereferenceObject


ExDeleteNPagedLookasideList

ExDeleteNPagedLookasideList destroys a nonpaged lookaside list.

VOID
  ExDeleteNPagedLookasideList(
    IN PNPAGED_LOOKASIDE_LIST  Lookaside
    );

Parameters

Lookaside
Pointer to the head of the lookaside list to be deleted, which the caller originally set up with ExInitializeNPagedLookasideList.

Include

wdm.h or ntddk.h

Comments

ExDeleteNPagedLookasideList is the reciprocal of ExInitializeNPagedLookasideList. It frees any remaining entries in the specified lookaside list and then removes the list from the system-wide set of active lookaside lists.

The caller of ExDeleteNPagedLookasideList is responsible for subsequently releasing the memory that the caller provided to contain the list head.

Callers of ExDeleteNPagedLookasideList must be running at IRQL <= DISPATCH_LEVEL.

See Also

ExInitializeNPagedLookasideList


ExDeletePagedLookasideList

ExDeletePagedLookasideList destroys a paged lookaside list.

VOID
  ExDeletePagedLookasideList(
    IN PPAGED_LOOKASIDE_LIST  Lookaside
    );

Parameters

Lookaside
Pointer to the head of the lookaside list to be deleted, which the caller originally set up with ExInitializePagedLookasideList.

Include

wdm.h or ntddk.h

Comments

ExDeletePagedLookasideList is the reciprocal of ExInitializePagedLookasideList. It frees any remaining entries in the specified lookaside list and then removes the list from the system-wide set of active lookaside lists.

The caller of ExDeletePagedLookasideList is responsible for subsequently releasing the memory that the caller provided to contain the list head.

Callers of ExDeletePagedLookasideList must be running at IRQL < DISPATCH_LEVEL.

See Also

ExInitializePagedLookasideList


ExDeleteResource

ExDeleteResource is exported to support existing driver binaries and is obsolete. Use ExDeleteResourceLite instead.

NTSTATUS
  ExDeleteResource(
    IN PERESOURCE  Resource
    );


ExDeleteResourceLite

ExDeleteResourceLite deletes a given resource from the system's resource list.

NTSTATUS
  ExDeleteResourceLite(
    IN PERESOURCE  Resource
    );

Parameters

Resource
Pointer to the caller-supplied storage for the initialized resource variable to be deleted.

Include

ntddk.h

Return Value

ExDeleteResourceLite returns STATUS_SUCCESS if the resource was deleted.

Comments

After calling ExDeleteResourceLite, the caller can free the memory it allocated for its resource.

Callers of ExDeleteResourceLite must be running at IRQL < DISPATCH_LEVEL.

See Also

ExFreePool, ExInitializeResourceLite, ExReinitializeResourceLite


ExExtendZone

ExExtendZone is exported to support existing driver binaries and is obsolete. Use lookaside lists instead. See Buffer Management for more information.

NTSTATUS
  ExExtendZone(
    IN PZONE_HEADER  Zone,
    IN PVOID  Segment,
    IN ULONG  SegmentSize
    );


ExFreePool

ExFreePool deallocates a block of pool memory.

VOID
  ExFreePool(
    IN PVOID  P
    );

Parameters

P
Specifies the address of the block of pool memory being deallocated.

Include

wdm.h or ntddk.h

Comments

This routine releases memory allocated by ExAllocatePool, ExAllocatePoolWithTag, ExAllocatePoolWithQuota, or ExAllocatePoolWithQuotaTag. The memory block must not be accessed after it is freed.

Callers of ExAllocatePool must be running at IRQL <= DISPATCH_LEVEL.

A caller at DISPATCH_LEVEL must have specified a NonPaged Xxx PoolType when the memory was allocated. Otherwise, the caller must be running at IRQL < DISPATCH_LEVEL.

See Also

ExAllocatePool, ExAllocatePoolWithQuota, ExAllocatePoolWithQuotaTag, ExAllocatePoolWithTag


ExFreeToNPagedLookasideList

ExFreeToNPagedLookasideList returns a nonpaged entry to the given lookaside list or to nonpaged pool.

VOID
  ExFreeToNPagedLookasideList(
    IN PNPAGED_LOOKASIDE_LIST  Lookaside,
    IN PVOID  Entry
    );

Parameters

Lookaside
Pointer to the head of the lookaside list, which the caller already initialized with ExInitializeNPagedLookasideList.
Entry
Pointer to the entry to be freed. The caller obtained this pointer from a preceding call to ExAllocateFromNPagedLookasideList.

Include

wdm.h or ntddk.h

Comments

ExFreeToNPagedLookasideList is the reciprocal of ExAllocateFromNPagedLookasideList. It releases a caller-allocated entry back to the caller's lookaside list or to nonpaged pool when that entry is no longer in use.

The same entry can be reallocated or another entry allocated later with a subsequent call to ExAllocateFromNPagedLookasideList. The user of the lookaside list can allocate and free such entries dynamically on an asneeded basis until it calls ExDeleteNPagedLookasideList, which releases any outstanding entries in the list before it clears the system state for the given lookaside list and returns control.

If the specified lookaside list has not yet reached the system-determined maximum number of entries, ExFreeToNPagedLookasideList inserts the given entry at the front of the list. Otherwise, the buffer at Entry is released to nonpaged pool using the caller-supplied Free routine, if any, that was set up when the lookaside list was initialized or ExFreePool.

Callers of ExFreeToNPagedLookasideList must be running at IRQL <= DISPATCH_LEVEL.

See Also

ExAllocateFromNPagedLookasideList, ExDeleteNPagedLookasideList, ExInitializeNPagedLookasideList


ExFreeToPagedLookasideList

ExFreeToPagedLookasideList returns a pageable entry to the given lookaside list or to paged pool.

VOID
  ExFreeToPagedLookasideList(
    IN PPAGED_LOOKASIDE_LIST  Lookaside,
    IN PVOID  Entry
    );

Parameters

Lookaside
Pointer to the resident head of the lookaside list, which the caller already initialized with ExInitializePagedLookasideList.
Entry
Pointer to the entry to be freed. The caller obtained this pointer from a preceding call to ExAllocateFromPagedLookasideList.

Include

wdm.h or ntddk.h

Comments

ExFreeToPagedLookasideList is the reciprocal of ExAllocateFromPagedLookasideList. It releases a caller-allocated entry back to the caller's lookaside list or to paged pool when that entry is no longer in use.

The same entry can be reallocated or another entry can be allocated later with a subsequent call to ExAllocateFromPagedLookasideList. The user of a lookaside list can allocate and free such entries dynamically, as needed, until it calls ExDeletePagedLookasideList. ExDeletePagedLookasideList releases any outstanding entries in the list before it clears the system state for the given lookaside list and returns control.

If the specified lookaside list has not yet reached the system-determined maximum number of entries, ExFreeToPagedLookasideList inserts the given entry at the front of the list. Otherwise, the buffer at Entry is released back to paged pool using the caller-supplied Free routine, if any, that was set up when the lookaside list was initialized or ExFreePool.

Callers of ExFreeToPagedLookasideList must be running at IRQL < DISPATCH_LEVEL.

See Also

ExAllocateFromPagedLookasideList, ExDeletePagedLookasideList, ExInitializePagedLookasideList


ExFreeToZone

ExFreeToZone is exported to support existing driver binaries and is obsolete. Use lookaside lists instead. See Buffer Management for more information.

PVOID
  ExFreeToZone(
    PZONE_HEADER  Zone,
    PVOID  Block
    );


ExGetCurrentResourceThread

ExGetCurrentResourceThread identifies the current thread for a subsequent call to ExReleaseResourceForThreadLite.

ERESOURCE_THREAD
  ExGetCurrentResourceThread(
    );

Include

ntddk.h

Return Value

ExGetCurrentResourceThread returns the thread ID of the current thread.

Comments

Callers of ExGetCurrentResourceThread must be running at IRQL <= DISPATCH_LEVEL.

See Also

ExIsResourceAcquiredExclusiveLite, ExIsResourceAcquiredSharedLite, ExReleaseResourceForThreadLite


ExGetExclusiveWaiterCount

ExGetExclusiveWaiterCount returns the number of waiters on exclusive access to a given resource.

ULONG
  ExGetExclusiveWaiterCount(
    IN PERESOURCE  Resource
    );

Parameters

Resource
Pointer to the resource to be tested.

Include

ntddk.h

Return Value

ExGetExclusiveWaiterCount returns the number of threads currently waiting to acquire the given resource for exclusive access.

Comments

ExGetExclusiveWaiterCount can be called to get an estimate of how many other threads might be waiting to modify the data protected by a particular resource variable. The caller cannot assume that the returned value remains constant for any particular interval.

Callers of ExGetExclusiveWaiterCount can be running at IRQL <= DISPATCH_LEVEL.

See Also

ExAcquireResourceExclusiveLite, ExAcquireResourceSharedLite, ExAcquireSharedStarveExclusive, ExAcquireSharedWaitForExclusive, ExGetSharedWaiterCount, ExReleaseResourceForThreadLite


ExGetPreviousMode

ExGetPreviousMode returns the previous processor mode for the current thread.

KPROCESSOR_MODE
  ExGetPreviousMode(
    VOID
    );

Return Value

ExGetPreviousMode returns a KPROCESSOR_MODE value, one of .KernelMode or UserMode. This value specifies the previous processor mode for the current thread.

Include

wdm.h or ntddk.h

Comments

If an I/O request can originate either in user mode or kernel mode and the caller passes pointers to data structures used for I/O, the driver must be able to determine whether the caller's pointers are valid in user mode or kernel mode.

If drivers are processing I/O requests using the normal IRP-based I/O dispatch method, they can determine the previous processor mode by checking the RequestMode parameter in the IRP header. (The RequestMode parameter is set by the I/O Manager.)

Alternatively, ExGetPreviousMode can be used to determine the previous processor mode. This routine is particularly useful in situations where a previous mode parameter is not available, for example, in a file driver that uses fast I/O.

Callers of ExGetPreviousMode must be running at IRQL <= DISPATCH_LEVEL.

See Also

KeGetCurrentThread


ExGetSharedWaiterCount

ExGetSharedWaiterCount returns the number of waiters on shared access to a given resource.

ULONG
  ExGetSharedWaiterCount(
    IN PERESOURCE  Resource
    );

Parameters

Resource
Pointer to the resource to be tested.

Include

ntddk.h

Return Value

ExGetSharedWaiterCount returns the number of threads currently waiting to acquire the given resource for shared access.

Comments

ExGetSharedWaiterCount can be called to get an estimate of how many other threads might be waiting to read the data protected by a particular resource variable. The caller cannot assume that the returned value remains constant for any particular interval.

Callers of ExGetSharedWaiterCount can be running at IRQL <= DISPATCH_LEVEL.

See Also

ExAcquireResourceExclusiveLite, ExAcquireResourceSharedLite, ExAcquireSharedStarveExclusive, ExAcquireSharedWaitForExclusive, ExGetExclusiveWaiterCount, ExReleaseResourceForThreadLite


ExInitializeFastMutex

ExInitializeFastMutex initializes a fast mutex variable, used to synchronize mutually exclusive access by a set of threads to a shared resource.

VOID
  ExInitializeFastMutex(
    IN PFAST_MUTEX  FastMutex
    );

Parameters

FastMutex
Pointer to a caller-allocated FAST_MUTEX structure, which represents the fast mutex, in the nonpaged memory pool.

Include

wdm.h or ntddk.h

Comments

ExInitializeFastMutex must be called before any calls to other Ex..FastMutex routines occur.

Although the caller supplies the storage for the given fast mutex, the FAST_MUTEX structure is opaque: that is, its members are reserved for system use.

For better performance, use the Ex..FastMutex routines instead of the Ke..Mutex routines. However, a fast mutex cannot be acquired recursively, as a kernel mutex can.

Callers of ExInitializeFastMutex must be running at IRQL <= DISPATCH_LEVEL.

See Also

ExAcquireFastMutex, ExAcquireFastMutexUnsafe, ExReleaseFastMutex, ExReleaseFastMutexUnsafe, ExTryToAcquireFastMutex, KeInitializeMutex


ExInitializeNPagedLookasideList

ExInitializeNPagedLookasideList initializes a lookaside list for nonpaged entries of the specified size.

VOID
  ExInitializeNPagedLookasideList(
    IN PNPAGED_LOOKASIDE_LIST  Lookaside,
    IN PALLOCATE_FUNCTION  Allocate  OPTIONAL,
    IN PFREE_FUNCTION  Free  OPTIONAL,
    IN ULONG  Flags,
    IN SIZE_T  Size,
    IN ULONG  Tag,
    IN USHORT  Depth
    );

Parameters

Lookaside
Pointer to the caller-supplied memory for the lookaside list head to be initialized. The caller must provide at least sizeof(NPAGED_LOOKASIDE_LIST) in nonpaged system space for this opaque list head.
Allocate
Either points to a caller-supplied routine for allocating an entry when the lookaside list is empty, or this parameter can be NULL. Such a caller-supplied routine is declared as follows:
PVOID
(*PALLOCATE_FUNCTION) (
    IN_POOL_TYPE PoolType,            // NonPagedPool
    IN ULONG  NumberOfBytes,          // value of Size
    IN ULONG  Tag                     // value of Tag
    );

If Allocate is NULL, subsequent calls to ExAllocateFromNPagedLookasideList automatically allocate entries whenever the lookaside list is empty.

Free
Either points to a caller-supplied routine for freeing an entry whenever the lookaside list is full, or this parameter can be NULL. Such a caller-supplied routine is declared as follows:
VOID
(*PFREE_FUNCTION) (
    PVOID  Buffer
    );

If Free is NULL, subsequent calls to ExFreeToNPagedLookasideList automatically release the given entry back to nonpaged pool whenever the list is full, that is, currently holding the system-determined maximum number of entries.

Flags
Reserved. Must be zero.
Size
Specifies the size in bytes for each nonpaged entry to be allocated subsequently.
Tag
Specifies the pool tag for lookaside list entries. The Tag is a string of four characters delimited by single quote marks (for example, 'derF'). The characters are usually specified in reverse order so they are easier to read when dumping pool or tracking pool usage with the PoolHitTag variable in the debugger.
Depth
Reserved. Must be zero.

Include

wdm.h or ntddk.h

Comments

After calling ExInitializeNPagedLookasideList, memory blocks of the caller-specified Size can be allocated from and freed to the lookaside list with calls to ExAllocateFromNPagedLookasideList and ExFreeToNPagedLookasideList, respectively. Such dynamically allocated and freed entries can be any data structure or fixed-size buffer that the caller uses while the system is running, particularly if the caller cannot predetermine how many such entries will be in use at any given moment. The layout and contents of each fixed-size entry are caller-determined.

ExInitializeNPagedLookasideList initializes the system state to track usage of the given lookaside list, as follows:

  • Zero-initializes the counters to be maintained for entries
  • Stores the entry points of the caller-supplied Allocate and Free routines, if any, or sets these entry points to ExAllocatePoolWithTag and ExFreePool, respectively
  • Initializes a system spin lock to control allocations from and frees to the lookaside list in a multiprocessor-safe manner if necessary
  • Stores the caller-supplied entry Size and list Tag
  • Sets up the system-determined limits (minimum and maximum) on the number of entries to be held in the lookaside list, which can be adjusted subsequently if system-wide demand for entries is higher or lower than anticipated
  • Sets up the system-determined flags, which control the type of memory from which entries will be allocated subsequently

The OS maintains a set of all lookaside lists currently in use. As demand for lookaside list entries and on available nonpaged memory varies while the system runs, the OS adjusts its limits for the number of entries to be held in each nonpaged lookaside list dynamically.

ExInitializeNPagedLookasideList sets up the opaque list head at the caller-supplied location but preallocates no memory for list entries. Subsequently, the initial entries are allocated dynamically as calls to ExAllocateFromNPagedLookasideList occur, and these initial entries are held in the lookaside list as reciprocal calls to ExFreeToNPagedLookasideList occur. Entries collect in the given lookaside list until the system-determined maximum is reached, whereupon any additional entries are returned to nonpaged pool as they are freed. If the list becomes empty, allocate requests are satisfied by the Allocate routine specified at list initialization or by ExAllocatePoolWithTag.

It is more efficient to pass NULL pointers for Allocate and Free to ExInitializeNPagedLookasideList if the user of a lookaside list does nothing more than allocate and release fixed-size entries within these caller-supplied routines. However, any component that uses a lookaside list might supply these routines to do additional caller-determined processing, such as tracking its own dynamic memory usage by maintaining state about the number of entries it allocates and frees.

If the caller of ExInitializeNPagedLookasideList supplies an Allocate routine, that routine must allocate entries for the lookaside list using the given input parameters when it calls ExAllocatePoolWithTag.

Callers of ExInitializeNPagedLookasideList can be running at IRQL <= DISPATCH_LEVEL, but are usually running at PASSIVE_LEVEL.

See Also

ExAllocateFromNPagedLookasideList, ExAllocatePoolWithTag, ExDeleteNPagedLookasideList, ExFreeToNPagedLookasideList, ExFreePool, ExInitializePagedLookasideList


ExInitializePagedLookasideList

ExInitializePagedLookasideList initializes a lookaside list for pageable entries of the specified size.

VOID
  ExInitializePagedLookasideList(
    IN PPAGED_LOOKASIDE_LIST  Lookaside,
    IN PALLOCATE_FUNCTION  Allocate  OPTIONAL,
    IN PFREE_FUNCTION  Free  OPTIONAL,
    IN ULONG  Flags,
    IN SIZE_T  Size,
    IN ULONG  Tag,
    IN USHORT  Depth
    );

Parameters

Lookaside
Pointer to the caller-supplied memory for the lookaside list head to be initialized. The caller must provide at least sizeof(PAGED_LOOKASIDE_LIST) in nonpaged system space for this opaque list head, even though the entries in this lookaside list will be allocated from pageable memory.
Allocate
Either points to a caller-supplied routine for allocating an entry when the lookaside list is empty, or this parameter can be NULL. Such a caller-supplied routine is declared as follows:
PVOID
(*PALLOCATE_FUNCTION) (
    IN_POOL_TYPE PoolType,            // PagedPool
    IN ULONG  NumberOfBytes,          // value of Size
    IN ULONG  Tag                     // value of Tag
    );

If Allocate is NULL, subsequent calls to ExAllocateFromPagedLookasideList automatically allocate entries whenever the lookaside list is empty.

Free
Either points to a caller-supplied routine for freeing an entry whenever the lookaside list is full, or this parameter can be NULL. Such a caller-supplied routine is declared as follows:
VOID
(*PFREE_FUNCTION) (
    PVOID  Buffer
    );

If Free is NULL, subsequent calls to ExFreeToPagedLookasideList automatically release the given entry back to paged pool whenever the list is full, that is, currently holding the system-determined maximum number of entries.

Flags
Reserved. Must be zero.
Size
Specifies the size in bytes of each entry in the lookaside list.
Tag
Specifies the pool tag for lookaside list entries. The Tag is a string of four characters delimited by single quote marks (for example, 'derF'). The characters are usually specified in reverse order so they are easier to read when dumping pool or tracking pool usage with the PoolHitTag variable in the debugger.
Depth
Reserved. Must be zero.

Include

wdm.h or ntddk.h

Comments

After calling ExInitializePagedLookasideList, blocks of the caller-specified Size can be allocated from and freed to the lookaside list with calls to ExAllocateFromPagedLookasideList and ExFreeToPagedLookasideList, respectively. Such dynamically allocated and freed entries can be any data structure or fixed-size buffer that the caller uses while the system is running, particularly if the caller cannot predetermine how many such entries will be in use at any given moment. The layout and contents of each fixed-size entry are caller-determined.

ExInitializePagedLookasideList initializes the system state to track usage of the given lookaside list, as follows:

  • Zero-initializes the counters to be maintained for entries
  • Stores the entry points of the caller-supplied Allocate and Free routines, if any, or sets these entry points to ExAllocatePoolWithTag and ExFreePool, respectively
  • Initializes a system spin lock to control allocations from and frees to the lookaside list in a multiprocessor-safe manner if necessary
  • Stores the caller-supplied entry Size and list Tag
  • Sets up the system-determined limits (minimum and maximum) on the number of entries to be held in the lookaside list, which can be adjusted subsequently if system-wide demand for entries is higher or lower than anticipated
  • Sets up the system-determined flags, which control the type of memory from which entries will be allocated subsequently

The OS maintains a set of all lookaside lists in use. As demand for lookaside list entries and on available paged memory varies while the system runs, the OS adjusts its limits for the number of entries to be held in each paged lookaside list dynamically.

ExInitializePagedLookasideList sets up the opaque list head at the caller-supplied location but preallocates no memory for list entries. Subsequently, the initial entries are allocated dynamically as calls to ExAllocateFromPagedLookasideList occur, and these initial entries are held in the lookaside list as reciprocal calls to ExFreeToPagedLookasideList occur. Entries collect in the given lookaside list until the system-determined maximum is reached, whereupon any additional entries are returned to paged pool as they are freed. If the list becomes empty, allocate requests are satisfied by the Allocate routine specified at list initialization or by ExAllocatePoolWithTag.

It is more efficient to pass NULL pointers for Allocate and Free to ExInitializePagedLookasideList if the user of a lookaside list does nothing more than allocate and release fixed-size entries within these caller-supplied routines. However, any component that uses a lookaside list might supply these routines to do additional caller-determined processing, such as tracking its own dynamic memory usage by maintaining state about the number of entries it allocates and frees.

If the caller of ExInitializePagedLookasideList supplies an Allocate routine, that routine must allocate entries for the lookaside list using the given input parameters when it calls ExAllocatePoolWithTag.

Callers of ExInitializePagedLookasideList must be running at IRQL < DISPATCH_LEVEL.

See Also

ExAllocateFromPagedLookasideList, ExAllocatePoolWithTag, ExDeletePagedLookasideList, ExFreePool, ExFreeToPagedLookasideList, ExInitializeNPagedLookasideList


ExInitializeResource

ExInitializeResource is exported to support existing driver binaries and is obsolete. Use ExInitializeResourceLite instead.

NTSTATUS
  ExInitializeResource(
    IN PERESOURCE  Resource
    );


ExInitializeResourceLite

ExInitializeResourceLite initializes a resource variable.

NTSTATUS
  ExInitializeResourceLite(
    IN PERESOURCE  Resource
    );

Parameters

Resource
Pointer to the caller-supplied storage, which must be at least sizeof(ERESOURCE), for the resource variable being initialized.

Include

ntddk.h

Return Value

ExInitializeResourceLite returns STATUS_SUCCESS.

Comments

The storage for ERESOURCE must not be allocated from paged pool.

The resource variable can be used for synchronization by a set of threads. Although the caller provides the storage for the resource variable, the ERESOURCE structure is opaque: that is, its members are reserved for system use.

Call ExDeleteResourceLite before freeing the memory for the resource.

Callers of ExInitializeResourceLite must be running at IRQL <= DISPATCH_LEVEL.

See Also

ExAcquireResourceExclusiveLite, ExAcquireResourceSharedLite, ExAcquireSharedStarveExclusive, ExAcquireSharedWaitForExclusive, ExConvertExclusiveToSharedLite, ExDeleteResourceLite, ExIsResourceAcquiredExclusiveLite, ExIsResourceAcquiredSharedLite, ExReinitializeResourceLite, ExReleaseResourceForThreadLite, ExTryToAcquireResourceExclusiveLite


ExInitializeSListHead

ExInitializeSListHead initializes the head of a sequenced, interlocked, singly linked list.

VOID
  ExInitializeSListHead(
    IN PSLIST_HEADER  SListHead
    );

Parameters

SListHead
Pointer to caller-supplied memory for the list head to be initialized. The caller must provide at least sizeof(SLIST_HEADER) in nonpaged memory for this opaque list head.

Include

wdm.h or ntddk.h

Comments

ExInitializeSListHead initializes the system-maintained state for the S-List and sets the first-entry pointer to NULL. The caller must provide resident storage for and initialize a spin lock with KeInitializeSpinLock before inserting any caller-allocated entry into its initialized S-List.

The sequence number for an S-List is incremented each time an entry is inserted into or removed from the S-List. To determine the number of entries currently in an S-List, call ExQueryDepthSList.

Subsequent calls to ExInterlockedPushEntrySList and ExInterlockedPopEntrySList insert and remove caller-allocated entries into and from the S-List. All entries for an S-List must be allocated from nonpaged pool.

Drivers that retry I/O operations should use a doubly linked interlocked queue and the ExInterlockedInsert/Remove..List routines, rather than an S-List.

To manage a dynamically sized set of fixed-size entries, consider setting up a lookaside list with ExInitializeNPageLookasideList or ExInitializePagedLookasideList, instead of using an S-List.

Callers of ExInitializeSListHead must be running at IRQL <= DISPATCH_LEVEL.

See Also

ExInitializeNPagedLookasideList, ExInitializePagedLookasideList, ExInterlockedInsertTailList, ExInterlockedPopEntrySList, ExInterlockedPushEntrySList, ExQueryDepthSList, ExQueueWorkItem, KeInitializeSpinLock


ExInitializeWorkItem

ExInitializeWorkItem is exported to support existing driver binaries and is obsolete. Use IoAllocateWorkItem instead.

VOID
  ExInitializeWorkItem(
    IN PWORK_QUEUE_ITEM  Item,
    IN PWORKER_THREAD_ROUTINE  Routine,
    IN PVOID  Context
    );


ExInitializeZone

ExInitializeZone is exported to support existing driver binaries and is obsolete. Use lookaside lists instead. See Buffer Management for more information.

NTSTATUS
  ExInitializeZone(
    IN PZONE_HEADER  Zone,
    IN ULONG  BlockSize,
    IN PVOID  InitialSegment,
    IN ULONG  InitialSegmentSize
    );


ExInterlockedAddLargeInteger

ExInterlockedAddLargeInteger adds a large integer value to a given addend as an atomic operation.

LARGE_INTEGER
  ExInterlockedAddLargeInteger(
    IN PLARGE_INTEGER  Addend,
    IN LARGE_INTEGER  Increment,
    IN PKSPIN_LOCK  Lock
    );

Parameters

Addend
Pointer to a large integer to be adjusted by the Increment value.
Increment
Specifies a value to be added to Addend.
Lock
Pointer to a spin lock to be used to synchronize access to Addend.

Include

wdm.h or ntddk.h

Return Value

ExInterlockedAddLargeInteger returns the initial value of the Addend.

Comments

Support routines that do interlocked operations are assumed to be incapable of causing a page fault. That is, neither their code nor any of the data they touch can cause a page fault without bringing down the system. They use spin locks to achieve atomicity in SMP machines. The caller must provide resident storage for the Lock, which must be initialized with KeInitializeSpinLock before the initial call to an ExInterlocked Xxx.

The Lock passed to ExInterlockedAddLargeInteger is used to assure that the add operation on Addend is atomic with respect to any other operations on the same value which synchronize with this same spin lock.

ExInterlockedAddLargeInteger masks interrupts. Consequently, it can be used for synchronization between an ISR and other device driver code, provided that the same Lock is never reused in a call to a routine that runs at IRQL DISPATCH_LEVEL.

Note that calls to Interlocked Xxx are guaranteed to be atomic with respect to other Interlocked Xxx calls without caller supplied spin locks.

This routine is not available on Windows 98 or ME.

Callers of ExInterlockedAddLargeInteger run at any IRQL.

See Also

ExInterlockedAddUlong, InterlockedIncrement, InterlockedDecrement, KeInitializeSpinLock


ExInterlockedAddLargeStatistic

ExInterlockedAddLargeStatistic performs an interlocked addition of a ULONG increment value to a LARGE_INTEGER addend value.

VOID
  ExInterlockedAddLargeStatistic (
    IN PLARGE_INTEGER  Addend,
    IN ULONG  Increment
    );

Parameters

Addend
Pointer to a LARGE_INTEGER value that is incremented by the value of Increment.
Increment
Specifies a ULONG value that is added to the value that Addend points to.

Include

wdm.h or ntddk.h

Comments

Support routines that do interlocked operations must not cause a page fault. Neither their code nor any of the data they access can cause a page fault without bringing down the system.

ExInterlockedAddLargeStatistic masks interrupts, and can be safely used to synchronize an ISR with other driver code.

ExInterlockedAddLargeStatistic runs at any IRQL.

See Also

ExInterlockedAddLargeInteger, ExInterlockedAddUlong


ExInterlockedAddUlong

ExInterlockedAddUlong adds an unsigned long value to a given unsigned integer as an atomic operation.

ULONG
  ExInterlockedAddUlong(
    IN PULONG  Addend,
    IN ULONG  Increment,
    PKSPIN_LOCK  Lock
    );

Parameters

Addend
Pointer to an unsigned long integer whose value is to be adjusted by the Increment value.
Increment
Is an unsigned long integer to be added.
Lock
Pointer to a spin lock to be used to synchronize access to the Addend.

Include

wdm.h or ntddk.h

Return Value

ExInterlockedAddUlong returns the original (unsummed) value of the Addend.

Comments

Consider using InterlockedExchangeAdd instead of this routine. InterlockedExchangeAdd can be more efficient because it does not use a spin lock and it is inlined by the compiler.

Support routines that do interlocked operations are assumed to be incapable of causing a page fault. That is, neither their code nor any of the data they touch can cause a page fault without bringing down the system. They use spin locks to achieve atomicity in SMP machines. The caller must provide resident storage for the Lock, which must be initialized with KeInitializeSpinLock before the initial call to an ExInterlocked Xxx.

The Lock passed to ExInterlockedAddULong is used to assure that the add operation on Addend is atomic with respect to any other operations on the same value which synchronize with this same spin lock.

ExInterlockedAddUlong masks interrupts. Consequently, it can be used for synchronization between an ISR and other driver code, provided that the same Lock is never reused in a call to a routine that runs at IRQL DISPATCH_LEVEL.

Note that calls to Interlocked Xxx are guaranteed to be atomic with respect to other Interlocked Xxx calls without caller supplied spin locks.

Callers of ExInterlockedAddUlong run at any IRQL.

See Also

ExInterlockedAddLargeInteger, InterlockedIncrement, InterlockedDecrement, KeInitializeSpinLock


ExInterlockedAllocateFromZone

ExInterlockedAllocateFromZone is exported to support existing driver binaries and is obsolete. Use lookaside lists instead. See Buffer Management for more information.

PVOID
  ExInterlockedAllocateFromZone(
    IN PZONE_HEADER  Zone,
    IN PKSPIN_LOCK  Lock
    );


ExInterlockedCompareExchange64

ExInterlockedCompareExchange64 compares one integer variable to another and, if they are equal, sets the first variable to a caller-supplied value.

LONGLONG
  ExInterlockedCompareExchange64(
    IN OUT PLONGLONG  Destination,
    IN PLONGLONG  Exchange,
    IN PLONGLONG  Comparand,
    IN PKSPIN_LOCK  Lock
    );

Parameters

Destination
Pointer to an integer that will be compared and possibly replaced.
Exchange
Pointer to an integer that will replace the one at Destination if the comparison results in equality.
Comparand
Pointer to an integer with which the value at Destination will be compared.
Lock
Pointer to a caller-allocated spin-lock that is used if the host system does not support an 8-byte atomic compare and exchange operation.

Include

wdm.h or ntddk.h

Return Value

ExInterlockedCompareExchange64 returns the value of the variable at Destination when the call occurred.

Comments

ExInterlockedCompareExchange64 tests and, possibly, replaces the value of a given variable. For most underlying microprocessors, this routine is implemented inline by the compiler to execute as an atomic operation. If a spin lock is used, this routine can only be safely used on nonpaged parameters.

If the Destination and Comparand are unequal, ExInterlockedCompareExchange simply returns the value of Destination.

ExInterlockedCompareExchange64 is atomic only with respect to other (Ex)Interlocked Xxx calls.

Callers of ExInterlockedCompareExchange64 can be running at any IRQL.

See Also

InterlockedCompareExchange, InterlockedExchange, InterlockedExchangeAdd


ExInterlockedDecrementLong

ExInterlockedDecrementLong is exported to support existing driver binaries and is obsolete. Use InterlockedDecrement instead.

INTERLOCKED_RESULT
  ExInterlockedDecrementLong(
    IN PLONG  Addend,
    IN PKSPIN_LOCK  Lock
    );


ExInterlockedExchangeAddLargeInteger

ExInterlockedExchangeAddLargeInteger performs an atomic operation that increments the Addend value by the Increment value.

LARGE_INTEGER
  ExInterlockedExchangeAddLargeInteger(
    IN PLARGE_INTEGER  Addend,
    IN LARGE_INTEGER  Increment,
    IN PKSPIN_LOCK  Lock
    );

Parameters

Addend
Pointer to a value that is incremented by the value of Increment.
Increment
The increment value added to the value pointed to by Addend.
Lock
Pointer to a spin lock that is used to synchronize access to Addend. (Lock might not be used; see the Comments section).

Include

ntddk.h

Return Value

ExInterlockedExchangeAddLargeInteger returns the input value pointed to by Addend.

Comments

If supported by the processor, ExInterlockedExchangeAddLargeInteger uses a memory-locked, atomic exchange operation. If such an exchange operation is supported, the routine does not use the spin lock and is probably faster than ExInterlockedAddLargeInteger. If such an exchange operation is not supported, this routine uses the spin lock and is equivalent to ExInterlockedAddLargeInteger.

See Also

ExInterlockedAddLargeInteger, ExInterlockedAddUlong, InterlockedDecrement, InterlockedIncrement


ExInterlockedExchangeUlong

ExInterlockedExchangeUlong is exported to support existing driver binaries and is obsolete. Use InterlockedExchange instead.

ULONG
  ExInterlockedExchangeUlong(
    IN PULONG  Target,
    IN ULONG  Value,
    IN PKSPIN_LOCK  Lock
    );


ExInterlockedExtendZone

ExInterlockedExtendZone is exported to support existing driver binaries and is obsolete. Use lookaside lists instead. See Buffer Management for more information.

NTSTATUS
  ExInterlockedExtendZone(
    IN PZONE_HEADER  Zone,
    IN PVOID  Segment,
    IN ULONG  SegmentSize,
    IN PKSPIN_LOCK  Lock
    );


ExInterlockedFlushSList

ExInterlockedFlushSList removes all entries on a sequenced, single-linked list (S-List) in a synchronized, multiprocessor-safe way.

PSINGLE_LIST_ENTRY
  ExInterlockedFlushSList (
    IN PSLIST_HEADER  ListHead
    );

Parameters

ListHead
Pointer to an S-List header.

Include

ntddk.h

Return Value

If there are entries on the specified S-List, ExInterlockedFlushSList returns a pointer to the first entry on the S-List; otherwise, it returns NULL.

Comment

ExInterlockedFlushSList sets the pointer to the first entry on the specified S-List to NULL.

See Also

ExInitializeSListHead


ExInterlockedFreeToZone

ExInterlockedFreeToZone is exported to support existing driver binaries and is obsolete. Use lookaside lists instead. See Buffer Management for more information.

PVOID
  ExInterlockedFreeToZone(
    IN PZONE_HEADER  Zone,
    IN PVOID  Block,
    IN PKSPIN_LOCK  Lock
    );


ExInterlockedIncrementLong

ExInterlockedIncrementLong is exported to support existing driver binaries and is obsolete. Use InterlockedIncrement instead.

INTERLOCKED_RESULT
  ExInterlockedIncrementLong(
    IN PLONG  Addend,
    IN PKSPIN_LOCK  Lock
    );


ExInterlockedInsertHeadList

ExInterlockedInsertHeadList inserts an entry at the head of a doubly linked list so that access to the list is synchronized in a multiprocessor-safe way.

PLIST_ENTRY
  ExInterlockedInsertHeadList(
    IN PLIST_ENTRY  ListHead,
    IN PLIST_ENTRY  ListEntry,
    IN PKSPIN_LOCK  Lock
    );

Parameters

ListHead
Pointer to the head of the doubly linked list into which an entry is to be inserted.
ListEntry
Pointer to the entry to be inserted at the head of the list.
Lock
Pointer to a caller-supplied spin lock used to synchronize access to the list.

Include

wdm.h or ntddk.h

Return Value

ExInterlockedInsertHeadList returns a pointer to the entry that was at the head of the interlocked queue before this entry was inserted. If the queue was empty, it returns NULL.

Comments

Support routines that do interlocked operations are assumed to be incapable of causing a page fault. That is, neither their code nor any of the data they touch can cause a page fault without bringing down the system. They use spin locks to achieve atomicity in SMP machines. The caller must provide resident storage for the Lock, which must be initialized with KeInitializeSpinLock before the initial call to an ExInterlocked Xxx. A caller must not be holding this spin lock when it calls ExInterlockedInsertHeadList.

The caller also must supply resident storage for the interlocked queue. The ListHead must be initialized with InitializedListHead before the initial call to an ExInterlocked..List.

If the caller uses only ExInterlocked..List routines to manipulate the list, then these routines can be called from a single IRQL that is <= DIRQL. If other driver routines access the list using any other routines, such as the noninterlocked InsertHeadList, then callers of ExInterlocked..List must be at <= DISPATCH_LEVEL.

Usually, drivers call ExInterlockedInsertTailList to insert an IRP into a driver-managed interlocked queue. They call ExInterlockedInsertHeadList only to requeue an IRP for a retry.

See Also

ExInterlockedInsertTailList, ExInterlockedRemoveHeadList, InitializeListHead, KeInitializeSpinLock


ExInterlockedInsertTailList

ExInterlockedInsertTailList inserts an entry at the tail of a doubly linked list so access to the list is synchronized in a multiprocessor-safe way.

PLIST_ENTRY
  ExInterlockedInsertTailList(
    IN PLIST_ENTRY  ListHead,
    IN PLIST_ENTRY  ListEntry,
    IN PKSPIN_LOCK  Lock
    );

Parameters

ListHead
Pointer to the head of the doubly linked list into which an entry is to be inserted.
ListEntry
Pointer to the entry to be inserted at the tail of the list.
Lock
Pointer to a caller-supplied spin lock, used to synchronize access to the list.

Include

wdm.h or ntddk.h

Return Value

ExInterlockedInsertTailList returns a pointer to the entry that was at the tail of the interlocked queue before this entry was inserted. If the queue was empty, it returns NULL.

Comments

Support routines that do interlocked operations are assumed to be incapable of causing a page fault. That is, neither their code nor any of the data they touch can cause a page fault without bringing down the system. They use spin locks to achieve atomicity in SMP machines. The caller must provide resident storage for the Lock, which must be initialized with KeInitializeSpinLock before the initial call to an ExInterlocked Xxx. A caller must not be holding this spin lock when it calls ExInterlockedInsertTailList.

The caller also must supply resident storage for the interlocked queue. The ListHead must be initialized with InitializeListHead before the initial call to an ExInterlocked..List routine.

If the caller uses only ExInterlocked..List routines to manipulate the list, then these routines can be called from a single IRQL that is <= DIRQL. If other driver routines access the list using any other routines, such as the noninterlocked InsertHeadList, then callers of ExInterlocked..List must be at <= DISPATCH_LEVEL.

See Also

ExInterlockedInsertHeadList, InitializeListHead, KeInitializeSpinLock


ExInterlockedPopEntryList

ExInterlockedPopEntryList removes an entry from the front of a simple singly linked list so access to the queue is synchronized in a multiprocessor-safe way.

PSINGLE_LIST_ENTRY
  ExInterlockedPopEntryList(
    IN PSINGLE_LIST_ENTRY  ListHead,
    IN PKSPIN_LOCK  Lock
    );

Parameters

ListHead
Pointer to the head of the singly linked list from which an entry is to be removed.
Lock
Pointer to a caller-supplied spin lock.

Include

wdm.h or ntddk.h

Return Value

If the list has no entries, ExInterlockedPopEntryList returns a NULL pointer. Otherwise, it returns a pointer to the dequeued entry.

Comments

The ExInterlocked..EntryList routines manipulate a simple, singly linked list and use a spin lock for multiprocessor-safe synchronization. For greater efficiency, use the ExInterlocked..EntrySList routines that manipulate a sequenced, singly linked list (an S-List), instead of a simple singly linked list.

Drivers that retry I/O operations should use a doubly linked interlocked queue and the ExInterlockedInsert/Remove..List routines, rather than a singly linked queue or an S-List.

ExInterlockedPopEntryList removes the first entry from the specified singly linked list.

Support routines that do interlocked operations are assumed to be incapable of causing a page fault. That is, neither their code nor any of the data they touch can cause a page fault without bringing down the system. They use spin locks to achieve atomicity in SMP machines. The caller must provide resident storage for the Lock, which must be initialized with KeInitializeSpinLock before the initial call to an ExInterlocked Xxx. A caller must not be holding this spin lock when it calls ExInterlockedPush/PopEntryList.

The caller also must provide the storage for the interlocked queue. The memory at ListHead should be zero-initialized before the initial call to ExInterlockedPushEntryList.

Any of the Ex..Interlocked routines can be called at DIRQL from a device driver's ISR or SynchCritSection routine(s), provided that other driver routines do not make calls to the ExInterlocked Xxx while running at < DIRQL with the same spin lock. Otherwise, callers of ExInterlockedPopEntryList must be running at IRQL <= DISPATCH_LEVEL.

See Also

ExInitializeSListHead, ExInterlockedPopEntrySList, ExInterlockedPushEntryList, KeInitializeSpinLock


ExInterlockedPopEntrySList

ExInterlockedPopEntrySList removes the first entry from a sequenced, singly linked list so access to this queue is synchronized in a multiprocessor-safe way.

PSINGLE_LIST_ENTRY
  ExInterlockedPopEntrySList(
    IN PSLIST_HEADER  ListHead,
    IN PKSPIN_LOCK  Lock
    );

Parameters

ListHead
Pointer to the head of the sequenced, singly linked list from which an entry is to be removed.
Lock
Pointer to a caller-supplied spin lock.

Include

wdm.h or ntddk.h

Return Value

ExInterlockedPopEntrySList returns a pointer to the first entry in the list. If the list was empty, it returns NULL.

Comments

ExInterlockedPopEntrySList removes the entry at the head of the list. Before calling this routine, the list must be initialized with ExInitializeSListHead and one or more caller-allocated entries should be inserted with ExInterlockedPushEntrySList.

Drivers that retry I/O operations should use a doubly linked interlocked queue and the ExInterlockedInsert/Remove..List routines, rather than an S-List.

The caller must provide resident storage for the Lock, which must be initialized with KeInitializeSpinLock before the first call to ExInterlockedPushEntrySList. A caller must not be holding this spin lock when it calls ExInterlockedPush/PopEntrySList.

Callers of ExInterlockedPopEntrySList can be running at IRQL <= DISPATCH_LEVEL.

See Also

ExInitializeSListHead, ExInterlockedRemoveHeadList, ExInterlockedPushEntrySList, ExQueryDepthSList, KeInitializeSpinLock


ExInterlockedPushEntryList

ExInterlockedPushEntryList inserts an entry at the head of a singly linked list so access to this queue is synchronized in a multiprocessor-safe way.

PSINGLE_LIST_ENTRY
  ExInterlockedPushEntryList(
    IN PSINGLE_LIST_ENTRY  ListHead,
    IN PSINGLE_LIST_ENTRY  ListEntry,
    IN PKSPIN_LOCK  Lock
    );

Parameters

ListHead
Pointer to the head of the singly linked list into which the specified entry is to be inserted.
ListEntry
Pointer to the entry to be inserted, which the caller allocated from nonpaged pool.
Lock
Pointer to a caller-supplied spin lock, already initialized with a call to KeInitializeSpinLock.

Include

wdm.h or ntddk.h

Return Value

ExInterlockedPushEntryList returns NULL if the list had no entries. Otherwise, it returns a pointer to the entry that is pushed (the previous list head).

Comments

The ExInterlocked..EntryList routines manipulate a simple, singly linked list and use a spin lock for multiprocessor-safe synchronization. For greater efficiency, use the ExInterlocked..EntrySList routines that manipulate a sequenced, singly linked list (an S-List), rather than a simple singly linked list.

Drivers that retry I/O operations should use a doubly linked interlocked queue and the ExInterlockedInsert/Remove..List routines, rather than a singly linked list.

ExInterlockedPushEntrySList inserts a caller-allocated entry at the front of the specified singly linked list.

Support routines that do interlocked operations are assumed to be incapable of causing a page fault. That is, neither their code nor any of the data they touch can cause a page fault without bringing down the system. They use spin locks to achieve atomicity in SMP machines. The caller must provide resident storage for the Lock, which must be initialized with KeInitializeSpinLock before the first call to ExInterlockedPushEntryList. A caller must not be holding this spin lock when it calls ExInterlockedPush/PopEntryList.

The caller also must provide resident storage for the head of the interlocked queue. The memory containing the ListHead should be zero-initialized before the initial call to ExInterlockedPushEntryList.

Any of the Ex..Interlocked routines can be called at DIRQL from a device driver's ISR or SynchCritSection routine(s), provided that other driver routines do not make calls to the ExInterlocked Xxx while running at < DIRQL with the same spin lock. Otherwise, callers of ExInterlockedPushEntryList must be running at IRQL <= DISPATCH_LEVEL.

See Also

ExInitializeSListHead, ExInterlockedInsertTailList, ExInterlockedPushEntrySList, ExInterlockedPopEntryList, KeInitializeSpinLock


ExInterlockedPushEntrySList

ExInterlockedPushEntrySList inserts an entry at the head of a sequenced, singly linked list so access to the queue is synchronized in a multiprocessor-safe way.

PSINGLE_LIST_ENTRY
  ExInterlockedPushEntrySList(
    IN PSLIST_HEADER  ListHead,
    IN PSINGLE_LIST_ENTRY  ListEntry,
    IN PKSPIN_LOCK  Lock
    );

Parameters

ListHead
Pointer to the head of the sequenced, singly linked list into which the specified entry is to be inserted. The given list head must be in nonpaged system space and initialized with ExInitializeSListHead before the first call to ExInterlockedPushEntrySList.
ListEntry
Pointer to the caller-allocated entry to be inserted.
Lock
Pointer to a caller-supplied spin lock, which must be initialized with KeInitializeSpinLock before the first call to ExInterlockedPushEntrySList.

Include

wdm.h or ntddk.h

Return Value

ExInterlockedPushEntrySList returns a pointer to the previous first entry in the list, if any. If the list was empty, it returns NULL.

Comments

ExInterlockedPushEntrySList inserts ListEntry at the head of the list. Before each call to this routine, the caller either allocates the entry to be inserted or reinserts an entry obtained from a preceding call to ExInterlockedPopEntrySList. All entries in a sequenced, singly linked interlocked queue must be allocated from nonpaged pool.

Drivers that retry I/O operations should use a doubly linked interlocked queue and the ExInterlockedInsert/Remove..List routines, rather than an S-List.

The caller must provide resident storage for the ListHead and Lock, which must be initialized before the first call to ExInterlockedPushSList. A caller must not be holding this spin lock when it calls ExInterlockedPush/PopEntrySList routine.

Callers of ExInterlockedPushEntrySList should be running at IRQL <= DISPATCH_LEVEL.

See Also

ExInitializeSListHead, ExInterlockedInsertTailList, ExInterlockedPopEntrySList, ExQueryDepthSList, KeInitializeSpinLock


ExInterlockedRemoveHeadList

ExInterlockedRemoveHeadList removes an entry from the head of a doubly linked list so access to this queue is synchronized in a multiprocessor-safe way.

PLIST_ENTRY
  ExInterlockedRemoveHeadList(
    IN PLIST_ENTRY  ListHead,
    IN PKSPIN_LOCK  Lock
    );

Parameters

ListHead
Pointer to the head of the doubly linked list from which an entry is to be removed.
Lock
Pointer to a caller-supplied spin lock.

Include

wdm.h or ntddk.h

Return Value

If the list is empty, a NULL pointer is returned. Otherwise, a pointer to the dequeued entry is returned.

Comments

Support routines that do interlocked operations are assumed to be incapable of causing a page fault. That is, neither their code nor any of the data they touch can cause a page fault without bringing down the system. They use spin locks to achieve atomicity in SMP machines. The caller must provide resident storage for the Lock, which must be initialized with KeInitializeSpinLock before the initial call to an ExInterlocked Xxx. A caller must not be holding this spin lock when it calls ExInterlockedRemoveHeadList.

The caller also must supply resident storage for the interlocked queue. The ListHead must be initialized with InitializeListHead before the initial call to an ExInterlocked..List routine.

If the caller uses only ExInterlocked..List routines to manipulate the list, then these routines can be called from a single IRQL that is <= DIRQL. If other driver routines access the list using any other routines, such as the noninterlocked InsertHeadList, then callers of ExInterlocked..List must be at <= DISPATCH_LEVEL.

See Also

ExInterlockedInsertHeadList, ExInterlockedInsertTailList, InitializeListHead, KeInitializeSpinLock


ExIsFullZone

Edit hereExIsFullZone is exported to support existing driver binaries and is obsolete. Use lookaside lists instead. See Buffer Management for more information.

BOOLEAN
  ExIsFullZone(
    IN PZONE_HEADER  Zone
    );


ExIsObjectInFirstZoneSegment

ExIsObjectInFirstZoneSegment is exported to support existing driver binaries and is obsolete. Use lookaside lists instead. See Buffer Management for more information.

BOOLEAN
  ExIsObjectInFirstZoneSetment(
    IN PZONE_HEADER  Zone,
    IN PVOID  Object
    );


ExIsProcessorFeaturePresent

ExIsProcessorFeaturePresent queries for the existence of a specified processor feature.

BOOLEAN
  ExIsProcessorFeaturePresent(
    IN ULONG  ProcessorFeature
    );

Parameters

ProcessorFeature
Specifies one of the following constant values:
PF_FLOATING_POINT_PRECISION_ERRATA
Pentium processor has divide bug.
PF_FLOATING_POINT_EMULATED
Processor does not have floating point hardware.
PF_COMPARE_EXCHANGE_DOUBLE
Processor has a CMPXCHG8B instruction ( 8-byte, memory-locked compare and exchange).
PF_MMX_INSTRUCTIONS_AVAILABLE
Processor supports MMX instructions in hardware.
PF_3DNOW_INSTRUCTIONS_AVAILABLE
Processor supports AMD 3DNow instructions.
PF_RDTSC_INSTRUCTION_AVAILABLE
Processor supports a RDTSC instruction (read timestamp counter instruction).

Include

ntddk.h

Return Value

ExIsProcessorFeaturePresent returns TRUE if the specified processor feature is present; otherwise it returns FALSE.

Comments

Callers of ExIsProcessorFeaturePresent must be running at IRQL PASSIVE_LEVEL.


ExIsResourceAcquired

ExIsResourceAcquired is exported to support existing driver binaries, and is obsolete. Use ExIsResourceAcquiredLite instead.


ExIsResourceAcquiredExclusive

ExIsResourceAcquiredExclusive is exported to support existing driver binaries, and is obsolete. Use ExIsResourceAcquiredExclusiveLite instead.

BOOLEAN
  ExIsResourceAcquiredExclusive(
    IN PERESOURCE  Resource
    );


ExIsResourceAcquiredExclusiveLite

ExIsResourceAcquiredExclusiveLite returns whether the current thread has exclusive access to a given resource.

BOOLEAN
  ExIsResourceAcquiredExclusiveLite(
    IN PERESOURCE  Resource
    );

Parameters

Resource
Pointer to the resource to be queried.

Include

ntddk.h

Return Value

ExIsResourceAcquiredExclusiveLite returns TRUE if the caller already has exclusive access to the given resource.

Comments

Callers of ExIsResourceAcquiredExclusiveLite must be running at IRQL <= DISPATCH_LEVEL.

See Also

ExAcquireResourceExclusiveLite, ExIsResourceAcquiredSharedLite, ExTryToAcquireResourceExclusiveLite


ExIsResourceAcquiredLite

ExIsResourceAcquiredLite returns whether the current thread has access (either shared or exclusive) to a given resource.

USHORT
  ExIsResourceAcquiredLite(
    IN PERESOURCE  Resource
    );

Parameters

Resource
Pointer to the resource to be queried.

Include

ntddk.h

Return Value

ExIsResourceAcquiredLite returns the number of times the caller has acquired the given resource for shared or exclusive access.

Comments

The system considers exclusive access to be a subset of shared access. Therefore, a thread that has exclusive access to a resource also has shared access to the resource. Callers of ExIsResourceAcquiredLite must be running at IRQL <= DISPATCH_LEVEL.

See Also

ExAcquireResourceSharedLite, ExAcquireSharedStarveExclusive, ExAcquireSharedWaitForExclusive, ExIsResourceAcquiredExclusiveLite, ExIsResourceAcquiredSharedLite


ExIsResourceAcquiredSharedLite

ExIsResourceAcquiredSharedLite returns whether the current thread has access (either shared or exclusive) to a given resource.

USHORT
  ExIsResourceAcquiredSharedLite(
    IN PERESOURCE  Resource
    );

Parameters

Resource
Pointer to the resource to be queried.

Include

ntddk.h

Return Value

ExIsResourceAcquiredSharedLite returns the number of times the caller has acquired the given resource for shared or exclusive access.

Comments

The system considers exclusive access to be a subset of shared access. Therefore, a thread that has exclusive access to a resource also has shared access to the resource. Callers of ExIsResourceAcquiredSharedLite must be running at IRQL <= DISPATCH_LEVEL.

See Also

ExAcquireResourceSharedLite, ExAcquireSharedStarveExclusive, ExAcquireSharedWaitForExclusive, ExIsResourceAcquiredExclusiveLite


ExLocalTimeToSystemTime

ExLocalTimeToSystemTime converts a system time value for the current time zone to an unbiased, GMT value.

VOID
  ExLocalTimeToSystemTime(
    IN PLARGE_INTEGER  LocalTime,
    OUT PLARGE_INTEGER  SystemTime
    );

Parameters

LocalTime
Pointer to a variable set to the locale-specific time.
SystemTime
Pointer to the returned value for GMT system time.

Include

ntddk.h

Comments

ExLocalTimeToSystemTime adds the time-zone bias at the current locale to compute the corresponding GMT system time value.

Callers of ExLocalTimeToSystemTime can be running at any IRQL.

See Also

ExSystemTimeToLocalTime


ExNotifyCallback

ExNotifyCallback causes all callback routines registered for the given object to be called.

VOID
  ExNotifyCallback(
    IN PCALLBACK_OBJECT  CallbackObject,
    IN PVOID  Argument1,
    IN PVOID  Argument2
    );

Parameters

CallbackObject
Pointer to the callback object for which all registered callback routines will be called.
Argument1
Specifies the parameter that is passed as Argument1 of the callback routine.
Argument2
Specifies the parameter that is passed as Argument2 of the callback routine.

Include

ntddk.h

Comments

Driver writers must not call ExNotifyCallback for any of the system-defined callback objects listed in ExCreateCallback.

The system calls callback routines in order of their registration.

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL. The system calls all registered callback routines at the caller's IRQL.

See Also

ExCreateCallback, ExRegisterCallback


ExQueryDepthSList

ExQueryDepthSList returns the number of entries currently in a given sequenced, singly linked list.

USHORT
  ExQueryDepthSList(
    IN PSLIST_HEADER  SListHead
    );

Parameters

SListHead
Pointer to the head of the sequenced, singly linked list to be queried, which the caller has already initialized with ExInitializeSListHead.

Include

wdm.h or ntddk.h

Return Value

ExQueryDepthSList returns the current number of entries in the S-List.

Comments

Callers of ExQueryDepthSList can be running at IRQL <= DISPATCH_LEVEL.

See Also

ExInitializeSListHead, ExInterlockedPushEntrySList, ExInterlockedPopEntrySList


ExQueueWorkItem

ExQueueWorkItem is exported to support existing driver binaries and is obsolete. Use IoQueueWorkItem instead.

VOID
  ExQueueWorkItem(
    IN PWORK_QUEUE_ITEM  WorkItem,
    IN WORK_QUEUE_TYPE  QueueType
    );


ExRaiseAccessViolation

ExRaiseAccessViolation can be used with structured exception handling to throw a driver-determined exception for a memory access violation that occurs when a driver processes I/O requests.

VOID
  ExRaiseAccessViolation(
    VOID
    );

Include

ntddk.h

Comments

ExRaiseAccessViolation raises an exception with the exception code set to STATUS_ACCESS_VIOLATION.

Callers of ExRaiseAccessViolation must be running at IRQL PASSIVE_LEVEL.

Because ExRaiseAccessViolation can only be used at IRQL PASSIVE_LEVEL, only high-level drivers typically use this routine — for example, file system drivers.

See Also

ExRaiseDatatypeMisalignment, ExRaiseStatus, IoAllocateErrorLogEntry, KeBugCheckEx


ExRaiseDatatypeMisalignment

ExRaiseDatatypeMisalignment can used with structured exception handling to throw a driver-determined exception for a misaligned data type that occurs when a driver processes I/O requests.

VOID
  ExRaiseDatatypeMisalignment(
    VOID
    );

Include

ntddk.h

Comments

ExRaiseDatatypeMisalignment raises an exception with the exception code set to STATUS_DATATYPE_MISALIGNMENT.

Callers of ExRaiseDatatypeMisalignment must be running at IRQL PASSIVE_LEVEL.

Because ExRaiseDatatypeMisalignment can only be used at IRQL PASSIVE_LEVEL, only high-level drivers typically use this routine — for example, file system drivers.

See Also

ExRaiseAccessViolation, ExRaiseStatus, IoAllocateErrorLogEntry, KeBugCheckEx


ExRaiseStatus

ExRaiseStatus is called by drivers that supply structured exception handlers to handle particular errors that occur while they are processing I/O requests.

VOID
  ExRaiseStatus(
    IN NTSTATUS  Status
    );

Parameters

Status
Is one of the system-defined STATUS_XXX values.

Include

wdm.h or ntddk.h

Comments

Highest-level drivers, particularly file systems, can call ExRaiseStatus.

Callers of ExRaiseStatus must be running at IRQL PASSIVE_LEVEL.

See Also

ExRaiseAccessViolation, ExRaiseDatatypeMisalignment, IoAllocateErrorLogEntry, KeBugCheckEx


ExRegisterCallback

ExRegisterCallback registers a given callback routine with a given callback object.

PVOID
  ExRegisterCallback(
    IN PCALLBACK_OBJECT  CallbackObject,
    IN PCALLBACK_FUNCTION  CallbackFunction,
    IN PVOID  CallbackContext
    );

Parameters

CallbackObject
Pointer to a callback object obtained from ExCreateCallback.
CallbackFunction
Pointer to a driver callback routine, which must be nonpageable. The callback routine must conform to the following prototype:
VOID
(*PCALLBACK_FUNCTION ) (
    IN PVOID CallbackContext,
    IN PVOID Argument1,
    IN PVOID Argument2
    );

The callback routine parameters are as follows:

CallbackContext
Pointer to a driver-supplied context area as specified in the CallbackContext parameter of ExRegisterCallback.
Argument1
Pointer to a parameter defined by the callback object.
Argument2
Pointer to a parameter defined by the callback object.
CallbackContext
Pointer to a caller-defined structure of data items to be passed as the context parameter of the callback routine each time it is called. Typically the context is part of the caller's device object extension.

Include

wdm.h or ntddk.h

Return Value

ExRegisterCallback returns a pointer to a callback registration handle that should be treated as opaque and reserved for system use. This pointer is NULL if ExRegisterCallback completes with an error.

Comments

A driver calls ExRegisterCallback to register a callback routine with a specified callback object.

If the object allows only one registered callback routine, and such a routine is already registered, ExRegisterCallback returns NULL.

Callers of ExRegisterCallback must save the returned pointer for use later in a call to ExUnregisterCallback. The pointer is required when removing the callback routine from the list of registered callback routines for the callback object.

The meanings of Argument1 and Argument2 of the registered callback routine depend on the callback object and are defined by the component that created it. The following are the parameters for the system-defined callback objects:

\Callback\SetSystemTime

Argument 1
Not used.
Argument 2
Not used.

\Callback\PowerState

Argument 1
PO_CB_AC_STATUS – Indicates that the system has changed from A/C to battery power, or vice versa.

PO_CB_SYSTEM_POWER_POLICY – Indicates that the system power policy has changed.

PO_CB_SYSTEM_STATE_LOCK - Indicates that a system power state change is imminent. Drivers in the paging path can register for this callback to receive early warning of such a change, allowing them the opportunity to lock their code in memory before the power state changes.

Argument 2
If Argument1 is PO_CB_AC_STATUS, Argument2 contains TRUE if the current power source is AC and FALSE otherwise.

If Argument1 is PO_CB_SYSTEM_POWER_POLICY, Argument2 is not used.

If Argument1 is PO_CB_SYSTEM_STATE_LOCK, Argument2 contains zero if the system is about to leave S0 and one if the system has just reentered S0.

Callers of this routine must be running at IRQL < DISPATCH_LEVEL.

The system calls registered callback routines at the same IRQL at which the driver that created the callback called ExNotifyCallback.

See Also

ExCreateCallback, ExNotifyCallback, ExUnregisterCallback


ExReinitializeResourceLite

ExReinitializeResourceLite reinitializes an existing resource variable.

VOID
  ExReinitializeResourceLite(
    IN PERESOURCE  Resource
    );

Parameters

Resource
Pointer to the caller supplied resource variable to be reinitialized.

Include

ntddk.h

Return Value

ExReinitializeResourceLite returns STATUS_SUCCESS.

Comments

With a single call to ExReinitializeResource, a driver writer can replace three calls: one to ExDeleteResourceLite, another to ExAllocatePool, and a third to ExInitializeResourceLite. As contention for a resource variable increases, memory is dynamically allocated and attached to the resource in order to track this contention. As an optimization, ExReinitializeResourceLite retains and zeroes this previously allocated memory.

The ERESOURCE structure is opaque; that is, the members are reserved for system use.

Callers of ExReinitializeResourceLite must be running at IRQL <= DISPATCH_LEVEL.

See Also

ExAcquireResourceExclusiveLite, ExAcquireResourceSharedLite, ExInitializeResourceLite, ExDeleteResourceLite, ExAcquireSharedStarveExclusive, ExAcquireSharedWaitForExclusive, ExConvertExclusiveToSharedLite, ExIsResourceAcquiredExclusiveLite, ExIsResourceAcquiredSharedLite, ExReleaseResourceForThreadLite, ExTryToAcquireResourceExclusiveLite


ExReleaseFastMutex

ExReleaseFastMutex releases ownership of a fast mutex that was acquired with ExAcquireFastMutex or ExTryToAcquireFastMutex.

VOID
  ExReleaseFastMutex(
    IN PFAST_MUTEX  FastMutex
    );

Parameters

FastMutex
Pointer to the fast mutex to be released.

Include

wdm.h or ntddk.h

Comments

ExReleaseFastMutex releases ownership of the given fast mutex and reenables the delivery of APCs to the current thread.

It is a programming error to call ExReleaseFastMutex with a FastMutex that was acquired using ExAcquireFastMutexUnsafe.

Callers of ExReleaseFastMutex must be running at IRQL = APC_LEVEL. In most cases the IRQL will already be set to APC_LEVEL before ExReleaseFastMutex is called. This is because ExAcquireFastMutex has already set the IRQL to the appropriate value automatically. However, if the caller changes the IRQL after ExAcquireFastMutex returns, the caller must explicitly set the IRQL to APC_LEVEL prior to calling ExReleaseFastMutex

See Also

ExAcquireFastMutex, ExInitializeFastMutex, ExTryToAcquireFastMutex


ExReleaseFastMutexUnsafe

ExReleaseFastMutexUnsafe releases ownership of a fast mutex that was acquired using ExAcquireFastMutexUnsafe.

VOID
  ExReleaseFastMutexUnsafe(
    IN PFAST_MUTEX  FastMutex
    );

Parameters

FastMutex
Pointer to the fast mutex to be released.

Include

wdm.h or ntddk.h

Comments

It is a programming error to call ExReleaseFastMutexUnsafe with a FastMutex that was acquired using ExAcquireFastMutex or ExTryToAcquireFastMutex.

Callers of ExReleaseFastMutexUnsafe must be running at IRQL = APC_LEVEL unless the caller invokes both ExAcquireFastMutexUnsafe and ExReleaseFastMutexUnsafe from within a critical section, in which case the caller must be running at IRQL <= APC_LEVEL.

See Also

ExAcquireFastMutexUnsafe, ExInitializeFastMutex


ExReleaseResource

ExReleaseResource is exported only to support existing driver binaries and is obsolete. Use ExReleaseResourceLite instead.

VOID
  ExReleaseResource(
    IN PERESOURCE  Resource
    );


ExReleaseResourceForThread

ExReleaseResourceForThread is exported to support existing driver binaries and is obsolete. Use ExReleaseResourceForThreadLite instead.

VOID
  ExReleaseResourceForThreadLite(
    IN PERESOURCE  Resource,
    IN ERESOURCE_THREAD  ResourceThreadId
    );


ExReleaseResourceForThreadLite

ExReleaseResourceForThreadLite releases the input resource of the indicated thread.

VOID
  ExReleaseResourceForThreadLite(
    IN PERESOURCE  Resource,
    IN ERESOURCE_THREAD  ResourceThreadId
    );

Include

ntddk.h

Parameters

Resource
Pointer to the resource to release.
ResourceThreadId
Identifies the thread that originally acquired the resource.

Comments

Callers of ExReleaseResourceForThreadLite must be running at IRQL <= DISPATCH_LEVEL.

See Also

ExAcquireResourceExclusiveLite, ExAcquireResourceSharedLite, ExAcquireSharedStarveExclusive, ExAcquireSharedWaitForExclusive, ExGetCurrentResourceThread, ExInitializeResourceLite, ExReinitializeResourceLite, ExTryToAcquireResourceExclusiveLite


ExSetResourceOwnerPointer

ExSetResourceOwnerPointer sets the owner thread pointer for an executive resource.

VOID
  ExSetResourceOwnerPointer(
    IN PERESOURCE  Resource,
    IN PVOID  OwnerPointer
    );

Parameters

Resource
Pointer to an executive resource owned by the current thread.
OwnerPointer
Pointer to an owner thread pointer of type ERESOURCE_THREAD (for additional requirements, see the Comments section).

Include

ntddk.h

Comments

ExSetResourceOwnerPointer, used in conjunction with ExReleaseResourceForThreadLite, provides a means for one thread (acting as an resource manager thread) to acquire and release resources for use by another thread (acting as a resource user thread).

After calling ExSetResourceOwnerPointer for a specific resource, the only other routine that can be called for that resource is ExReleaseResourceForThreadLite.

The resource manager thread acquires ownership of the resource and passes ownership to the user thread by calling ExSetResourceOwnerPointer. The caller must allocate the memory for the ERESOURCE_THREAD value pointed to by OwnerPointer in system memory, and this memory must remain allocated until ExReleaseResourceForThreadLite returns. The caller must also set the two low-order bits of the ERESOURCE_THREAD value pointed to by OwnerPointer to one — this encoding is used internally by the resource services to distinguish between owner and thread addresses.

When the user thread is done with the resource, the resource manager thread releases the user thread's ownership of the resource by calling ExReleaseResourceForThreadLite. The ResourceThreadId input parameter is set to the value of the OwnerPointer parameter used in the previous call to ExSetResourceOwnerPointer that gave the worker thread ownership of the resource.

Callers of ExSetResourceOwnerPointer must be running at IRQL <= DISPATCH_LEVEL.

See Also

ExReleaseResourceForThreadLite


ExSetTimerResolution

ExSetTimerResolution routine modifies the frequency at which the system clock interrupts. Use this routine with extreme caution (see the following Comments section).

ULONG
  ExSetTimerResolution(
    IN ULONG  DesiredTime,
    IN BOOLEAN  SetResolution
    );

Parameters

DesiredTime
Specifies the amount of time that should elapse between each timer interrupt, in 100 nanosecond units. The minimum value is approximately 10,000 (1 millisecond) but can vary slightly by platform. (This parameter is ignored if SetResolution is FALSE.)
SetResolution
If TRUE, the call is a request to set the clock interrupt frequency to the value specified by DesiredTime. If FALSE, the call is a request to restore the clock interrupt frequency to the system's default value, which is platform-specific.

Include

wdm.h or ntddk.h

Return Value

ExSetTimerResolution returns the new timer resolution, in 100 nanosecond units.

Comments

To set the timer resolution, a driver calls this routine passing TRUE as the parameter for SetResolution. The following rules apply:

  • The routine changes the clock interrupt frequency only if the specified DesiredTime value is less than the current setting.
  • If a driver requests a DesiredTime value that is greater than what is currently set, the routine just returns the current setting.
  • If a driver requests a DesiredTime value that is less than the system clock can support, the routine uses the smallest resolution the system can support, and returns that value.

If you use this routine to change the clock interrupt frequency, your driver must restore the default interrupt frequency, typically by calling:

ExSetTimerResolution (0, FALSE);

before being unloaded. (If multiple drivers have attempted to modify the clock interrupt frequency, the system does not restore the default frequency until all of these drivers have called this routine with a SetResolution value of FALSE.)

Note that the result of changing the clock interrupt frequency is system-wide and can have a severely negative effect on system performance. Also note that higher clock interrupt frequencies can shorten a system's battery life.

Callers of this routine must be running at IRQL < DISPATCH_LEVEL.

See Also

KeSetTimerEx


ExSystemTimeToLocalTime

ExSystemTimeToLocalTime converts a GMT system time value to the local system time for the current time zone.

VOID
  ExSystemTimeToLocalTime(
    IN PLARGE_INTEGER  SystemTime,
    OUT PLARGE_INTEGER  LocalTime
    );

Parameters

SystemTime
Pointer to a variable set to the unbiased, GMT system time.
LocalTime
Pointer to the returned value for the current locale.

Include

ntddk.h

Comments

ExSystemTimeToLocalTime subtracts the time-zone bias from the GMT system time value to compute the corresponding time at the current locale.

Callers of ExSystemTimeToLocalTime can be running at any IRQL.

See Also

ExLocalTimeToSystemTime


ExTryToAcquireFastMutex

ExTryToAcquireFastMutex acquires the given fast mutex, if possible, with APCs to the current thread disabled.

BOOLEAN
  ExTryToAcquireFastMutex(
    IN PFAST_MUTEX  FastMutex
    );

Parameters

FastMutex
Pointer to the fast mutex to be acquired if it is not currently owned by another thread.

Include

ntddk.h

Return Value

ExTryToAcquireFastMutex returns TRUE if the current thread is given ownership of the fast mutex.

Comments

If the given fast mutex is currently unowned, ExTryToAcquireFastMutex gives the caller ownership with APCs to the current thread disabled until it releases the fast mutex.

Use ExAcquireFastMutex if the current thread must wait on the acquisition of the given mutex before it can do useful work.

Any fast mutex acquired with ExTryToAcquireFastMutex or ExAcquireFastMutex must be released with ExReleaseFastMutex.

Callers of ExTryToAcquireFastMutex must be running at IRQL < DISPATCH_LEVEL.

See Also

ExAcquireFastMutex, ExInitializeFastMutex, ExReleaseFastMutex


ExTryToAcquireResourceExclusiveLite

ExTryToAcquireResourceExclusiveLite attempts to acquire the given resource for exclusive access.

BOOLEAN
  ExTryToAcquireResourceExclusiveLite(
    IN PERESOURCE  Resource
    );

Parameters

Resource
Pointer to the resource to be acquired.

Include

ntddk.h

Return Value

ExTryToAcquireResourceExclusiveLite returns TRUE if the given resource has been acquired for the caller.

Comments

Use ExAcquireResourceExclusiveLite if the caller must have exclusive access to the resource before it can do further useful work.

Callers of ExTryToAcquireResourceExclusiveLite must be running at IRQL < DISPATCH_LEVEL.

See Also

ExAcquireResourceExclusiveLite, ExAcquireSharedWaitForExclusive, ExIsResourceAcquiredExclusiveLite


ExUnregisterCallback

ExUnregisterCallback removes a callback routine previously registered with a callback object from the list of routines to be called during the notification process.

VOID
  ExUnregisterCallback(
    IN PVOID  CbRegistration
    );

Parameters

CbRegistration
Is the pointer returned by ExRegisterCallback to identify this registration. This value should be treated as opaque and reserved for system use.

Include

wdm.h or ntddk.h

Comments

Callers of this routine must be running at IRQL < DISPATCH_LEVEL.

See Also

ExCreateCallback, ExRegisterCallback


ExUuidCreate

ExUuidCreate sets a new UUID (GUID) structure.

NTSTATUS
  ExUuidCreate(
    OUT UUID  *Uuid,
    );

Parameters

Uuid
Pointer to a caller-allocated UUID (GUID) structure that is set to a new UUID value.

Include

ntddk.h

Return Value

ExUuidCreate returns STATUS_SUCCESS if successful; otherwise, if the system is not ready to generate a new UUID, it returns STATUS_RETRY.

Comments

A UUID and a GUID are the same data type.

The caller can iteratively attempt to obtain a new UUID value.

This routine must run at IRQL PASSIVE_LEVEL.


InterlockedCompareExchange

InterlockedCompareExchange performs an atomic operation that compares the input value pointed to by Destination with the value of Comparand.

LONG
  InterlockedCompareExchange(
    IN OUT PLONG  Destination,
    IN LONG  Exchange,
    IN LONG  Comparand
    );

Parameters

Destination
Pointer to the input value that is compared with the value of Comparand.
Exchange
The output value pointed to by Destination if the input value pointed to by Destination equals the value of Comparand.
Comparand
The value that is compared with the input value pointed to by Destination.

Include

wdm.h or ntddk.h

Return Value

InterlockedCompareExchange returns the value pointed to by Destination.

Comments

If the value pointed to by Destination and the value of Comparand are equal, InterlockedCompareExchange sets the output value pointed to by Destination to the value of Exchange.

InterlockedCompareExchange provides a fast, atomic way to synchronize the testing and updating of a variable that is shared by multiple threads. If the input value pointed to by Destination equals the value of Comparand, the output value of Destination is set to the value of Exchange.

InterlockedCompareExchange is designed for speed and, typically, is implemented inline by a compiler. InterlockedCompareExchange is atomic only with respect to other Interlocked Xxx calls. It does not use a spin lock and can be safely used on pageable data.

Callers of InterlockedCompareExchange can be running at any IRQL.

See Also

ExInterlockedCompareExchange64, InterlockedCompareExchangePointer, InterlockedDecrement, InterlockedExchange, InterlockedExchangePointer, InterlockedIncrement


InterlockedCompareExchangePointer

InterlockedCompareExchangePointer performs an atomic operation that compares the input pointer value pointed to by Destination with the pointer value Comparand.

PVOID
  InterlockedCompareExchangePointer(
    IN OUT PVOID  *Destination,
    IN PVOID  Exchange,
    IN PVOID  Comparand
    );

Parameters

Destination
Pointer to the input pointer value compared with the pointer value of Comparand.
Exchange
The output pointer value that Destination points to if the input pointer value of Destination equals the pointer value of Comparand.
Comparand
The pointer value compared with the input pointer value pointed to by Destination.

Include

wdm.h or ntddk.h

Return Value

InterlockedCompareExchangePointer returns the pointer value pointed to by Destination.

Comments

If the value pointed to by Destination and the pointer value Comparand are equal, InterlockedCompareExchangePointer sets the output pointer value pointed to by Destination to the pointer value of Exchange.

InterlockedCompareExchangePointer provides a fast, atomic way to synchronize the testing and updating of a pointer variable that is shared by multiple threads. If the input value pointed to by Destination equals the value of Comparand, the value pointed to by Destination is set to the value of Exchange.

InterlockedCompareExchangePointer is designed for speed and, typically, is implemented inline by a compiler. InterlockedCompareExchangePointer is atomic only with respect to other Interlocked Xxx calls. It does not use a spin lock and can be safely used on pageable data.

The InterlockedCompareExchangePointer routine is atomic only with respect to other Interlocked Xxx calls.

Callers of InterlockedCompareExchangePointer can be running at any IRQL.

See Also

InterlockedCompareExchange, InterlockedExchange, InterlockedExchangePointer


InterlockedDecrement

InterlockedDecrement decrements a caller-supplied variable of type LONG as an atomic operation.

LONG
  InterlockedDecrement(
    IN PLONG  Addend
    );

Parameters

Addend
Pointer to a variable to be decremented.

Include

wdm.h or ntddk.h

Return Value

InterlockedDecrement returns the decremented value.

Comments

InterlockedDecrement should be used instead of ExInterlockedDecrementLong because it is both more efficient and faster.

InterlockedDecrement is implemented inline by the compiler when appropriate and possible. It does not require a spin lock and can therefore be safely used on pageable data.

InterlockedDecrement is atomic only with respect to other Interlocked Xxx calls.

Callers of InterlockedDecrement can be running at any IRQL.

See Also

InterlockedExchange, InterlockedIncrement, ExInterlockedAddLargeInteger, ExInterlockedAddUlong


InterlockedExchange

InterlockedExchange sets an integer variable to a given value as an atomic operation.

LONG
  InterlockedExchange(
    IN OUT PLONG  Target,
    IN LONG  Value
    );

Parameters

Target
Pointer to a variable to be set to the supplied Value as an atomic operation.
Value
Specifies the value to which the variable will be set.

Include

wdm.h or ntddk.h

Return Value

InterlockedExchange returns the value of the variable at Target when the call occurred.

Comments

InterlockedExchange should be used instead of ExInterlockedExchangeUlong, because it is both faster and more efficient.

InterlockedExchange is implemented inline by the compiler when appropriate and possible. It does not require a spin lock and can therefore be safely used on pageable data.

A call to InterlockedExchange routine is atomic only with respect to other Interlocked Xxx calls.

Callers of InterlockedExchange can be running at any IRQL.

See Also

InterlockedIncrement, InterlockedDecrement, ExInterlockedAddLargeInteger, ExInterlockedAddUlong


InterlockedExchangeAdd

InterlockedExchangeAdd adds a value to a given integer as an atomic operation and returns the original value of the given integer.

LONG
  InterlockedExchangeAdd(
    IN OUT PLONG  Addend,
    IN LONG  Value
    );

Parameters

Addend
Pointer to an integer variable.
Value
Is the value to be added to Addend.

Include

wdm.h or ntddk.h

Return Value

InterlockedExchangeAdd returns the original value of the Addend variable when the call occurred.

Comments

InterlockedExchangeAdd should be used instead of ExInterlockedAddUlong because it is both faster and more efficient.

InterlockedExchangeAddis implemented inline by the compiler when appropriate and possible. It does not require a spin lock and can therefore be safely used on pageable data.

InterlockedExchangeAdd is atomic only with respect to other Interlocked Xxx calls.

Callers of InterlockedExchangeAdd can be running at any IRQL.

See Also

InterlockedIncrement, InterlockedDecrement, ExInterlockedAddLargeInteger, ExInterlockedAddUlong


InterlockedExchangePointer

InterlockedExchangePointer performs an atomic operation that sets a pointer to a new value.

PVOID
  InterlockedExchangePointer(
    IN OUT PVOID  *Target,
    IN PVOID  Value
    );

Parameters

Target
Pointer to a pointer set to the value of Value.
Value
The new value for the pointer pointed to by Target.

Include

wdm.h or ntddk.h

Return Value

InterlockedExchangePointer returns the input value pointed to by Target.

Comments

InterlockedExchangePointer provides a fast, atomic way to synchronize updating a pointer variable that is shared by multiple threads.

InterlockedExchangePointer is designed for speed and, typically, is implemented inline by a compiler. InterlockedExchangePointer is atomic only with respect to other Interlocked Xxx calls. It does not use a spin lock and can be safely used on pageable data.

A call to InterlockedExchangePointer is atomic only with respect to other Interlocked Xxx calls.

Callers of InterlockedExchangePointer can be running at any IRQL.

See Also

InterlockedCompareExchange, InterlockedCompareExchangePointer, InterlockedExchange


InterlockedIncrement

InterlockedIncrement increments a caller supplied variable as an atomic operation.

LONG
  InterlockedIncrement(
    IN PLONG  Addend
    );

Parameters

Addend
Pointer to a variable of type LONG.

Include

wdm.h or ntddk.h

Return Value

InterlockedIncrement returns the incremented value.

Comments

InterlockedIncrement should be used instead of ExInterlockedIncrementLong because it is both more efficient and faster.

InterlockedIncrement is implemented inline by the compiler when appropriate and possible. It does not require a spin lock and can therefore be safely used on pageable data.

InterlockedIncrement is atomic only with respect to other Interlocked Xxx calls.

Callers of InterlockedIncrement can be running at any IRQL.

See Also

InterlockedDecrement, InterlockedExchange, ExInterlockedAddLargeInteger, ExInterlockedAddUlong


PAGED_CODE

PAGED_CODE ensures that the calling thread is running at an IRQL that is low enough to permit paging.

VOID
  PAGED_CODE(
    );

Include

wdm.h or ntddk.h

Comments

If the IRQL > APC_LEVEL, PAGED_CODE() causes the system to ASSERT.

A call to this macro should be made at the beginning of every driver routine that either contains pageable code or accesses pageable code.

The PAGED_CODE macro only checks IRQL at the point the code executes the macro. If the code subsequently raises IRQL, it will not be detected. Driver writers should use the driver verifier to detect when the IRQL is raised improperly.

PAGED_CODE only works in checked builds.


ProbeForRead

ProbeForRead probes a structure for read accessibility and ensures correct alignment of the structure.

VOID
  ProbeForRead(
    IN CONST VOID  *Address,
    IN ULONG  Length,
    IN ULONG  Alignment
    );

Parameters

Address
Supplies a pointer to the structure to be probed.
Length
Length of structure.
Alignment
Supplies the required alignment of the structure expressed as the number of bytes in the primitive datatype (e.g., 1 for char, 2 for short, 4 for long, and 8 for quad).

Include

wdm.h or ntddk.h

Comments

If the probed structure is not accessible or has incorrect alignment, then an exception is raised.

Kernel-mode drivers must use ProbeForRead to validate read access to buffers allocated in user space. It is most commonly used during METHOD_NEITHER I/O to valid the user buffer pointed to by Irp -> UserBuffer.

Drivers should call ProbeForRead inside a try-except block, so that any exceptions raised are handled properly, and the driver completes the IRP with an error.

Callers of ProbeForRead must be running at IRQL < APC_LEVEL.

See Also

ProbeForWrite


ProbeForWrite

ProbeForWrite probes a structure for write accessibility and ensures correct alignment of the structure.

VOID
  ProbeForWrite(
    IN CONST VOID  *Address,
    IN ULONG  Length,
    IN ULONG  Alignment
    );

Parameters

Address
Supplies a pointer to the structure to be probed.
Length
Length of structure.
Alignment
Supplies the required alignment of the structure expressed as the number of bytes in the primitive datatype (e.g., 1 for char, 2 for short, 4 for long, and 8 for quad).

Include

wdm.h or ntddk.h

Comments

If the probed structure is not accessible or has incorrect alignment, then an exception is raised.

Kernel-mode drivers must use ProbeForWrite to validate write access to buffers allocated in user space. It is most commonly used during METHOD_NEITHER I/O to valid the user buffer pointed to by Irp -> UserBuffer.

Drivers should call ProbeForWrite inside a try-except block, so that any exceptions raised are handled properly, and the driver completes the IRP with an error.

Callers of ProbeForWrite must be running at IRQL < APC_LEVEL.

See Also

ProbeForRead


Hardware Abstraction Layer Routines

References for the routines and macros described in this chapter are in alphabetical order.

For an overview of the functionality of these routines and macros, see Summary of Kernel-Mode Support Routines.


HalAllocateCommonBuffer

HalAllocateCommonBuffer is obsolete and is exported only to support existing driver binaries. See AllocateCommonBuffer instead.

PVOID
  HalAllocateCommonBuffer(
    IN PADAPTER_OBJECT  AdapterObject,
    IN ULONG  Length,
    OUT PPHYSICAL_ADDRESS  LogicalAddress,
    IN BOOLEAN  CacheEnabled
    );


HalAssignSlotResources

HalAssignSlotResources is obsolete and is exported only to support existing drivers. Drivers of PnP devices are assigned resources by the PnP Manager, which passes resource lists with each IRP_MN_START_DEVICE request. Drivers that must support a legacy device that cannot be enumerated by the PnP Manager should use IoReportDetectedDevice and IoReportResourceForDetection.

NTSTATUS
  HalAssignSlotResources(
    IN PUNICODE_STRING  RegistryPath,
    IN PUNICODE_STRING  DriverClassName,
    IN PDRIVER_OBJECT  DriverObject,
    IN PDEVICE_OBJECT  DeviceObject,
    IN INTERFACE_TYPE  BusType,
    IN ULONG  BusNumber,
    IN ULONG  SlotNumber,
    IN OUT PCM_RESOURCE_LIST  *AllocatedResources
    );

See Also

CM_RESOURCE_LIST, ExFreePool, HalGetBusData, IoAssignResources, IoReportDetectedDevice, IoReportResourceForDetection


HalExamineMBR

HalExamineMBR reads the master boot record (MBR) of a disk and returns data from the MBR if the MBR is of the type specified by the caller.

VOID
  HalExamineMBR(
    IN PDEVICE_OBJECT  DeviceObject,
    IN ULONG  SectorSize,
    IN ULONG  MBRTypeIdentifier,
    OUT PVOID  Buffer,
    );

Parameters

DeviceObject
Points to the device object for the device being examined.
SectorSize
Specifies the minimum number of bytes that an I/O operation can fetch from the device being examined. If this value is less than 512, HalExamineMBR reads 512 bytes to ensure that it reads an entire partition table.
MBRTypeIdentifier
Specifies the type of MBR that may be on the disk.
Buffer
Points to a buffer that returns data from the MBR. The layout of the buffer depends on the MBRTypeIdentifier. The caller must deallocate this buffer as soon as possible with ExFreePool. This routine returns NULL in Buffer if the MBRTypeIdentifier of the disk does not match that specified by the caller or if there is an error.

Include

ntddk.h

Comments

Callers of HalExamineMBR must be running at IRQL PASSIVE_LEVEL.

See Also

ExFreePool


HalFreeCommonBuffer

HalFreeCommonBuffer is obsolete and is exported only to support existing driver binaries. See FreeCommonBuffer instead.

VOID
  HalFreeCommonBuffer(
    IN PADAPTER_OBJECT  AdapterObject,
    IN ULONG  Length,
    IN PHYSICAL_ADDRESS  LogicalAddress,
    IN PVOID  VirtualAddress,
    IN BOOLEAN  CacheEnabled
    );


HalGetAdapter

HalGetAdapter is obsolete and is exported only for existing driver binaries. See IoGetDmaAdapter instead.

PADAPTER_OBJECT
  HalGetAdapter(
    IN PDEVICE_DESCRIPTION  DeviceDescription,
    IN OUT PULONG  NumberOfMapRegisters
    );


HalGetBusData

HalGetBusData is obsolete and is exported only to support existing drivers. Use the PnP Manager's IRP_MN_QUERY_INTERFACE and IRP_MN_READ_CONFIG requests instead.

ULONG
  HalGetBusData(
    IN BUS_DATA_TYPE  BusDataType,
    IN ULONG  BusNumber,
    IN ULONG  SlotNumber,
    IN PVOID  Buffer,
    IN ULONG  Length
    );

See Also

CM_EISA_FUNCTION_INFORMATION, CM_EISA_SLOT_INFORMATION, CM_MCA_POS_DATA, HalAssignSlotResources, HalGetAdapter, HalGetBusDataByOffset, HalGetInterruptVector, HalSetBusData, HalTranslateBusAddress, IoAssignResources, PCI_COMMON_CONFIG, PCI_SLOT_NUMBER, IRP_MN_QUERY_INTERFACE, IRP_MN_READ_CONFIG


HalGetBusDataByOffset

HalGetBusData is obsolete and is exported only to support existing drivers. Use the PnP Manager's IRP_MN_QUERY_INTERFACE request instead.

ULONG
  HalGetBusDataByOffset(
    IN BUS_DATA_TYPE  BusDataType,
    IN ULONG  BusNumber,
    IN ULONG  SlotNumber,
    IN PVOID  Buffer,
    IN ULONG  Offset,
    IN ULONG  Length
    );

See Also

HalAssignSlotResources, HalGetBusData, HalSetBusDataByOffset, HalTranslateBusAddress, IoAssignResources, PCI_COMMON_CONFIG, PCI_SLOT_NUMBER, IRP_MN_QUERY_INTERFACE, IRP_MN_READ_CONFIG


HalGetDmaAlignmentRequirement

HalGetDmaAlignmentRequirement is obsolete and exported only to support existing drivers. See GetDmaAlignment instead.

ULONG
  HalGetDmaAlignmentRequirement(
    );


HalReadDmaCounter

HalReadDmaCounter is obsolete and exported only to support existing driver binaries. See ReadDmaCounter instead.

ULONG
  HalReadDmaCounter(
    IN PADAPTER_OBJECT  AdapterObject
    );


HalSetBusData

HalSetBusData is obsolete and is exported only to support existing drivers. Use the PnP Manager's IRP_MN_QUERY_INTERFACE and IRP_MN_WRITE_CONFIG requests instead.

ULONG
  HalSetBusData(
    IN BUS_DATA_TYPE  BusDataType,
    IN ULONG  BusNumber,
    IN ULONG  SlotNumber,
    IN PVOID  Buffer,
    IN ULONG  Length
    );

See Also

HalGetBusData, HalGetBusDataByOffset, HalSetBusDataByOffset, PCI_COMMON_CONFIG, PCI_SLOT_NUMBER, IRP_MN_QUERY_INTERFACE, IRP_MN_WRITE_CONFIG


HalSetBusDataByOffset

HalSetBusDataByOffset is obsolete and is exported only to support existing drivers. Use the PnP Manager's IRP_MN_QUERY_INTERFACE and IRP_MN_WRITE_CONFIG requests instead.

ULONG
  HalSetBusDataByOffset(
    IN BUS_DATA_TYPE  BusDataType,
    IN ULONG  BusNumber,
    IN ULONG  SlotNumber,
    IN PVOID  Buffer,
    IN ULONG  Offset,
    IN ULONG  Length
    );

See Also

HalAssignSlotResources, HalGetBusData, HalGetBusDataByOffset, HalTranslateBusAddress, IoAssignResources, PCI_COMMON_CONFIG, PCI_SLOT_NUMBER, IRP_MN_QUERY_INTERFACE, IRP_MN_WRITE_CONFIG


HalTranslateBusAddress

HalTranslateBusAddress is obsolete and is exported only to support existing drivers. The PnP Manager passes lists of raw and translated resources in its IRP_MN_START_DEVICE request for each device. Consequently, PnP drivers seldom, if ever, need to translate bus addresses. However, if translation is required, drivers should use the PnP IRP_MN_QUERY_INTERFACE request to get the standard bus interface.

BOOLEAN
  HalTranslateBusAddress(
    IN INTERFACE_TYPE  InterfaceType,
    IN ULONG  BusNumber,
    IN PHYSICAL_ADDRESS  BusAddress,
    IN OUT PULONG  AddressSpace,
    OUT PPHYSICAL_ADDRESS  TranslatedAddress
    );

See Also

HalAssignSlotResources, HalGetBusData, HalGetBusDataByOffset, IoAssignResources, MmMapIoSpace, IRP_MN_QUERY_INTERFACE


READ_PORT_BUFFER_UCHAR

READ_PORT_BUFFER_UCHAR reads a number of bytes from the specified port address into a buffer.

VOID
  READ_PORT_BUFFER_UCHAR(
    IN PUCHAR  Port,
    IN PUCHAR  Buffer,
    IN ULONG  Count
    );

Parameters

Port
Points to the port, which must be a mapped memory range in I/O space.
Buffer
Points to a buffer into which an array of UCHAR values is read.
Count
Specifies the number of bytes to be read into the buffer.

Include

wdm.h or ntddk.h

Comments

The size of the buffer must be large enough to contain at least the specified number of bytes.

Callers of READ_PORT_BUFFER_UCHAR can be running at any IRQL, assuming the Buffer is resident and the Port is resident, mapped device memory.


READ_PORT_BUFFER_USHORT

READ_PORT_BUFFER_USHORT reads a number of USHORT values from the specified port address into a buffer.

VOID
  READ_PORT_BUFFER_USHORT(
    IN PUSHORT  Port,
    IN PUSHORT  Buffer,
    IN ULONG  Count
    );

Parameters

Port
Points to the port, which must be a mapped memory range in I/O space.
Buffer
Points to a buffer into which an array of USHORT values is read.
Count
Specifies the number of USHORT values to be read into the buffer.

Include

wdm.h or ntddk.h

Comments

The size of the buffer must be large enough to contain at least the specified number of USHORT values.

Callers of READ_PORT_BUFFER_USHORT can be running at any IRQL, assuming the Buffer is resident and the Port is resident, mapped device memory.


READ_PORT_UCHAR

READ_PORT_UCHAR reads a byte from the specified port address.

UCHAR
  READ_PORT_UCHAR(
    IN PUCHAR  Port
    );

Parameters

Port
Points to the port address, which must be a mapped memory range in I/O space.

Include

wdm.h or ntddk.h

Return Value

READ_PORT_UCHAR returns the byte read from the specified port address.

Comments

Callers of READ_PORT_UCHAR can be running at any IRQL, assuming the Port is resident, mapped device memory.


READ_PORT_ULONG

READ_PORT_ULONG reads a ULONG value from the specified port address.

ULONG
  READ_PORT_ULONG(
    IN PULONG  Port
    );

Parameters

Port
Points to the port address, which must be a mapped range in I/O space.

Include

wdm.h or ntddk.h

Return Value

READ_PORT_ULONG returns the ULONG value read from the specified port address.

Comments

Callers of READ_PORT_ULONG can be running at any IRQL, assuming the Port is resident, mapped device memory.


READ_PORT_USHORT

READ_PORT_USHORT reads a USHORT value from the specified port address.

USHORT
  READ_PORT_USHORT(
    IN PUSHORT  Port
    );

Parameters

Port
Points to the port address, which must be a mapped range in I/O space.

Include

wdm.h or ntddk.h

Return Value

READ_PORT_USHORT returns the USHORT value read from the specified port address.

Comments

Callers of READ_PORT_USHORT can be running at any IRQL, assuming the Port is resident, mapped device memory.


READ_REGISTER_BUFFER_UCHAR

READ_REGISTER_BUFFER_UCHAR reads a number of bytes from the specified register address into a buffer.

VOID
  READ_REGISTER_BUFFER_UCHAR(
    IN PUCHAR  Register,
    IN PUCHAR  Buffer,
    IN ULONG  Count
    );

Parameters

Register
Points to the register, which must be a mapped range in memory space.
Buffer
Points to a buffer into which an array of UCHAR values is read.
Count
Specifies the number of bytes to be read into the buffer.

Include

wdm.h or ntddk.h

Comments

The size of the buffer must be large enough to contain at least the specified number of bytes.

Callers of READ_REGISTER_BUFFER_UCHAR can be running at any IRQL, assuming the Buffer is resident and the Register is resident, mapped device memory.


READ_REGISTER_BUFFER_ULONG

READ_REGISTER_BUFFER_ULONG reads a number of ULONG values from the specified register address into a buffer.

VOID
  READ_REGISTER_BUFFER_ULONG(
    IN PULONG  Register,
    IN PULONG  Buffer,
    IN ULONG  Count
    );

Parameters

Register
Points to the register, which must be a mapped range in memory space.
Buffer
Points to a buffer into which an array of ULONG values is read.
Count
Specifies the number of ULONG values to be read into the buffer.

Include

wdm.h or ntddk.h

Comments

The size of the buffer must be large enough to contain at least the specified number of ULONG values.

Callers of READ_REGISTER_BUFFER_ULONG can be running at any IRQL, assuming the Buffer is resident and the Register is resident, mapped device memory.


READ_REGISTER_BUFFER_USHORT

READ_REGISTER_BUFFER_USHORT reads a number of USHORT values from the specified register address into a buffer.

VOID
  READ_REGISTER_BUFFER_USHORT(
    IN PUSHORT  Register,
    IN PUSHORT  Buffer,
    IN ULONG  Count
    );

Parameters

Register
Points to the register, which must be a mapped range in memory space.
Buffer
Points to a buffer into which an array of USHORT values is read.
Count
Specifies the number of USHORT values to be read into the buffer.

Include

wdm.h or ntddk.h

Comments

The size of the buffer must be large enough to contain at least the specified number of USHORT values.

Callers of READ_REGISTER_BUFFER_USHORT can be running at any IRQL, assuming the Buffer is resident and the Register is resident, mapped device memory.


READ_REGISTER_UCHAR

READ_REGISTER_UCHAR reads a byte from the specified register address.

UCHAR
  READ_REGISTER_UCHAR(
    IN PUCHAR  Register
    );

Parameters

Register
Points to the register address, which must be a mapped range in memory space.

Include

wdm.h or ntddk.h

Return Value

READ_REGISTER_UCHAR returns the byte read from the specified register address.

Comments

Callers of READ_REGISTER_UCHAR can be running at any IRQL, assuming the Register is resident, mapped device memory.


READ_REGISTER_ULONG

READ_REGISTER_ULONG reads a ULONG value from the specified register address.

ULONG
  READ_REGISTER_ULONG(
    IN PULONG  Register
    );

Parameters

Register
Points to the register address, which must be a mapped range in memory space.

Include

wdm.h or ntddk.h

Return Value

READ_REGISTER_ULONG returns the ULONG value read from the specified register address.

Comments

Callers of READ_REGISTER_ULONG can be running at any IRQL, assuming the Register is resident, mapped device memory.


READ_REGISTER_USHORT

READ_REGISTER_USHORT reads a USHORT value from the specified register address.

USHORT
  READ_REGISTER_USHORT(
    IN PUSHORT  Register
    );

Parameters

Register
Points to the register address, which must be a mapped range in memory space.

Include

wdm.h or ntddk.h

Return Value

READ_REGISTER_USHORT returns the USHORT value read from the specified register address.

Comments

Callers of READ_REGISTER_USHORT can be running at any IRQL, assuming the Register is resident, mapped device memory.


WRITE_PORT_BUFFER_UCHAR

WRITE_PORT_BUFFER_UCHAR writes a number of bytes from a buffer to the specified port.

VOID
  WRITE_PORT_BUFFER_UCHAR(
    IN PUCHAR  Port,
    IN PUCHAR  Buffer,
    IN ULONG  Count
    );

Parameters

Port
Points to the port, which must be a mapped memory range in I/O space.
Buffer
Points to a buffer from which an array of UCHAR values is to be written.
Count
Specifies the number of bytes to be written to the port.

Include

wdm.h or ntddk.h

Comments

The size of the buffer must be large enough to contain at least the specified number of bytes.

Callers of WRITE_PORT_BUFFER_UCHAR can be running at any IRQL, assuming the Buffer is resident and the Port is resident, mapped device memory.


WRITE_PORT_BUFFER_ULONG

WRITE_PORT_BUFFER_ULONG writes a number of ULONG values from a buffer to the specified port address.

VOID
  WRITE_PORT_BUFFER_ULONG(
    IN PULONG  Port,
    IN PULONG  Buffer,
    IN ULONG  Count
    );

Parameters

Port
Points to the port, which must be a mapped memory range in I/O space.
Buffer
Points to a buffer from which an array of ULONG values is to be written.
Count
Specifies the number of ULONG values to be written to the port.

Include

wdm.h or ntddk.h

Comments

The size of the buffer must be large enough to contain at least the specified number of ULONGs.

Callers of WRITE_PORT_BUFFER_ULONG can be running at any IRQL, assuming the Buffer is resident and the Port is resident, mapped device memory.


WRITE_PORT_BUFFER_USHORT

WRITE_PORT_BUFFER_USHORT writes a number of USHORT values from a buffer to the specified port address.

VOID
  WRITE_PORT_BUFFER_USHORT(
    IN PUSHORT  Port,
    IN PUSHORT  Buffer,
    IN ULONG  Count
    );

Parameters

Port
Points to the port, which must be a mapped memory range in I/O space.
Buffer
Points to a buffer from which an array of USHORT values is to be written.
Count
Specifies the number of USHORT values to be written to the port.

Include

wdm.h or ntddk.h

Comments

The size of the buffer must be large enough to contain at least the specified number of USHORTs.

Callers of WRITE_PORT_BUFFER_USHORT can be running at any IRQL, assuming the Buffer is resident and the Port is resident, mapped device memory.


WRITE_PORT_UCHAR

WRITE_PORT_UCHAR writes a byte to the specified port address.

VOID
  WRITE_PORT_UCHAR(
    IN PUCHAR  Port,
    IN UCHAR  Value
    );

Parameters

Port
Points to the port, which must be a mapped memory range in I/O space.
Value
Specifies a byte to be written to the port.

Include

wdm.h or ntddk.h

Comments

Callers of WRITE_PORT_UCHAR can be running at any IRQL, assuming the Port is resident, mapped device memory.


WRITE_PORT_ULONG

WRITE_PORT_ULONG writes a ULONG value to the specified port address.

VOID
  WRITE_PORT_ULONG(
    IN PULONG  Port,
    IN ULONG  Value
    );

Parameters

Port
Points to the port, which must be a mapped memory range in I/O space.
Value
Specifies a ULONG value to be written to the port.

Include

wdm.h or ntddk.h

Comments

Callers of WRITE_PORT_ULONG can be running at any IRQL, assuming the Port is resident, mapped device memory.


WRITE_PORT_USHORT

WRITE_PORT_USHORT writes a USHORT value to the specified port address.

VOID
  WRITE_PORT_USHORT(
    IN PUSHORT  Port,
    IN USHORT  Value
    );

Parameters

Port
Points to the port, which must be a mapped memory range in I/O space.
Value
Specifies a USHORT value to be written to the port.

Include

wdm.h or ntddk.h

Comments

Callers of WRITE_PORT_USHORT can be running at any IRQL, assuming the Port is resident, mapped device memory.


WRITE_REGISTER_BUFFER_UCHAR

WRITE_REGISTER_BUFFER_UCHAR writes a number of bytes from a buffer to the specified register.

VOID
  WRITE_REGISTER_BUFFER_UCHAR(
    IN PUCHAR  Register,
    IN PUCHAR  Buffer,
    IN ULONG  Count
    );

Parameters

Register
Points to the register, which must be a mapped range in memory space.
Buffer
Points to a buffer from which an array of UCHAR values is to be written.
Count
Specifies the number of bytes to be written to the register.

Include

wdm.h or ntddk.h

Comments

The size of the buffer must be large enough to contain at least the specified number of bytes.

Callers of WRITE_REGISTER_BUFFER_UCHAR can be running at any IRQL, assuming the Buffer is resident and the Register is resident, mapped device memory.


WRITE_REGISTER_BUFFER_ULONG

WRITE_REGISTER_BUFFER_ULONG writes a number of ULONG values from a buffer to the specified register.

VOID
  WRITE_REGISTER_BUFFER_ULONG(
    IN PULONG  Register,
    IN PULONG  Buffer,
    IN ULONG  Count
    );

Parameters

Register
Points to the register, which must be a mapped range in memory space.
Buffer
Points to a buffer from which an array of ULONG values is to be written.
Count
Specifies the number of ULONG values to be written to the register.

Include

wdm.h or ntddk.h

Comments

The size of the buffer must be large enough to contain at least the specified number of ULONGs.

Callers of WRITE_REGISTER_BUFFER_ULONG can be running at any IRQL, assuming the Buffer is resident and the Register is resident, mapped device memory.


WRITE_REGISTER_BUFFER_USHORT

WRITE_REGISTER_BUFFER_USHORT writes a number of USHORT values from a buffer to the specified register.

VOID
  WRITE_REGISTER_BUFFER_USHORT(
    IN PUSHORT  Register,
    IN PUSHORT  Buffer,
    IN ULONG  Count
    );

Parameters

Register
Points to the register, which must be a mapped range in memory space.
Buffer
Points to a buffer from which an array of USHORT values is to be written.
Count
Specifies the number of USHORT values to be written to the register.

Include

wdm.h or ntddk.h

Comments

The size of the buffer must be large enough to contain at least the specified number of USHORTs.

Callers of WRITE_REGISTER_BUFFER_USHORT can be running at any IRQL, assuming the Buffer is resident and the Register is resident, mapped device memory.


WRITE_REGISTER_UCHAR

WRITE_REGISTER_UCHAR writes a byte to the specified address.

VOID
  WRITE_REGISTER_UCHAR(
    IN PUCHAR  Register,
    IN UCHAR  Value
    );

Parameters

Register
Points to the register, which must be a mapped range in memory space.
Value
Specifies a byte to be written to the register.

Include

wdm.h or ntddk.h

Comments

Callers of WRITE_REGISTER_UCHAR can be running at any IRQL, assuming the Register is resident, mapped device memory.


WRITE_REGISTER_ULONG

WRITE_REGISTER_ULONG writes a ULONG value to the specified address.

VOID
  WRITE_REGISTER_ULONG(
    IN PULONG  Register,
    IN ULONG  Value
    );

Parameters

Register
Points to the register which must be a mapped range in memory space.
Value
Specifies a ULONG value to be written to the register.

Include

wdm.h or ntddk.h

Comments

Callers of WRITE_REGISTER_ULONG can be running at any IRQL, assuming the Register is resident, mapped device memory.


WRITE_REGISTER_USHORT

WRITE_REGISTER_USHORT writes a USHORT value to the specified address.

VOID
  WRITE_REGISTER_USHORT(
    IN PUSHORT  Register,
    IN USHORT  Value
    );

Parameters

Register
Points to the register, which must be a mapped range in memory space.
Value
Specifies a USHORT value to be written to the register.

Include

wdm.h or ntddk.h

Comments

Callers of WRITE_REGISTER_USHORT can be running at any IRQL, assuming the Register is resident, mapped device memory.


I/O Manager Routines

All kernel-mode drivers except video and SCSI miniport drivers and NDIS drivers call Io Xxx routines.

References for the Io Xxx routines are in alphabetical order.

For an overview of the functionality of these routines, see Summary of Kernel-Mode Support Routines.

The following routines are for system use. Do not use them in your driver.

IoCancelFileOpen

IoUpdateDiskGeometry


IoAcquireCancelSpinLock

IoAcquireCancelSpinLock synchronizes cancelable-state transitions for IRPs in a multiprocessor-safe way.

VOID
  IoAcquireCancelSpinLock(
    OUT PKIRQL  Irql
    );

Parameters

Irql
Points to a variable in which to save the current IRQL for a subsequent call to IoReleaseCancelSpinLock. Usually, the Irql is saved on the stack as a local variable.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

A driver that uses the I/O Manager-supplied device queues in the device object must be holding the cancel spin lock whenever it changes the cancelable state of an IRP with IoSetCancelRoutine.

A driver that manages its own IRP queue does not need to hold the cancel spin lock when calling IoSetCancelRoutine.

The holder of the cancel spin lock should release it promptly by calling IoReleaseCancelSpinLock.

A driver-supplied Cancel routine is called with the cancel spin lock held. It must release the cancel spin lock when it has completed the IRP to be canceled.

Callers of IoAcquireCancelSpinLock must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoReleaseCancelSpinlock, IoSetCancelRoutine


IoAcquireRemoveLock

IoAcquireRemoveLock increments the count for a remove lock, indicating that the associated device object should not be detached from the device stack nor deleted.

NTSTATUS
  IoAcquireRemoveLock(
    IN PIO_REMOVE_LOCK  RemoveLock,
    IN OPTIONAL PVOID  Tag
    );

Parameters

RemoveLock
Points to an IO_REMOVE_LOCK structure that the caller initialized with a previous call to IoInitializeRemoveLock.
Tag
Optionally points to a caller-supplied tag that identifies this instance of acquiring the remove lock. For example, a driver Dispatch routine typically sets this parameter to a pointer to the IRP the routine is processing.

If a driver specifies a Tag on a call to IoAcquireRemoveLock, the driver must supply the same Tag in the corresponding call to IoReleaseRemoveLock.

The Tag does not have to be unique, but should be something meaningful during debugging.

The I/O system uses this parameter on checked builds only.

Return Value

IoAcquireRemoveLock returns STATUS_SUCCESS if the call was successful. Possible error return values include:

Error Status | Description
STATUS_DELETE_PENDING | The driver has received an IRP_MN_REMOVE_DEVICE for the device and is waiting for all remove locks to clear before deleting the device object. Do not start any new operations on the device.

Headers

Declared in ntddk.h. Include ntddk.h

Comments

A driver must initialize a remove lock with a call to IoInitializeRemoveLock before using the lock.

A driver must call IoReleaseRemoveLock to release the lock when it is no longer needed.

Callers of IoAcquireRemoveLock must be running at IRQL <= DISPATCH_LEVEL.

SeeAlso

IoInitializeRemoveLock, IoReleaseRemoveLock, IoReleaseRemoveLockAndWait


IoAcquireRemoveLockEx

This routine is reserved for system use. See IoAcquireRemoveLock.


IoAdjustPagingPathCount

IoAdjustPagingPathCount increments or decrements a caller-supplied page-file counter as an atomic operation.

VOID
  IoAdjustPagingPathCount(
    IN PLONG  Count,
    IN BOOLEAN  Increment
    );

Parameters

Count
Points to a caller-supplied variable that contains a counter. A driver typically stores a page-file counter in the device extension for the device.
Increment
Specifies whether the counter is to be incremented or decremented. A value of TRUE specifies an increment operation.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

This routine is useful for maintaining a count of paging files on a device. The operating system notifies a driver that a paging file has been created on, or removed from, one of the driver's devices by sending an IRP. The IRP has the major code IRP_MJ_PNP and the minor code IRP_MN_DEVICE_USAGE_NOTIFICATION.

This routine can be used for other counters, such as counters for hibernation files or crash-dump files.

Callers of IoAdjustPagingPathCount can be running at any IRQL.

See Also

IRP_MN_DEVICE_USAGE_NOTIFICATION


IoAllocateAdapterChannel

IoAllocateAdapterChannel is obsolete and is exported only to support existing drivers. Use AllocateAdapterChannel instead.

NTSTATUS
  IoAllocateAdapterChannel(
    IN PADAPTER_OBJECT  AdapterObject,
    IN PDEVICE_OBJECT  DeviceObject,
    IN ULONG  NumberOfMapRegisters,
    IN PDRIVER_CONTROL  ExecutionRoutine,
    IN PVOID  Context
    );


IoAllocateController

IoAllocateController sets up the call to a driver-supplied ControllerControl routine as soon as the device controller, represented by the given controller object, is available to carry out an I/O operation for the target device, represented by the given device object.

VOID
  IoAllocateController(
    IN PCONTROLLER_OBJECT  ControllerObject,
    IN PDEVICE_OBJECT  DeviceObject,
    IN PDRIVER_CONTROL  ExecutionRoutine,
    IN PVOID  Context
    );

Parameters

ControllerObject
Points to a driver-created controller object, usually representing a physical controller to be allocated for an I/O operation on an attached device.
DeviceObject
Points to the device object, representing the target device of the current IRP.
ExecutionRoutine
Points to the driver-supplied ControllerControl routine.
Context
Points to a driver-determined context, passed to the driver's ControllerControl routine when it is called.

Headers

Declared in ntddk.h. Include ntddk.h

Comments

This routine reserves exclusive access to the hardware controller for the specified device.

The ControllerControl routine returns a value indicating whether the controller remains allocated to the device, either DeallocateObject or KeepObject. If it returns KeepObject, the driver must subsequently call IoFreeController to release the controller object.

Callers of IoAllocateController must be running at IRQL DISPATCH_LEVEL.

See Also

ControllerControl, IoCreateController, IoDeleteController, IoFreeController


IoAllocateDriverObjectExtension

IoAllocateDriverObjectExtension allocates a per-driver context area that has a given unique identifier.

NTSTATUS
  IoAllocateDriverObjectExtension(
    IN PDRIVER_OBJECT  DriverObject,
    IN PVOID  ClientIdentificationAddress,
    IN ULONG  DriverObjectExtensionSize,
    OUT PVOID  *DriverObjectExtension
    );

Parameters

DriverObject
Points to a driver object to which the context area will be associated.
ClientIdentificationAddress
Specifies a unique identifier for the context area to be allocated.
DriverObjectExtensionSize
Specifies the length, in bytes, of the context area to be allocated.
DriverObjectExtension
Points to, on completion, the allocated context area.

Return Value

IoAllocateDriverObjectExtension returns one of the following NTSTATUS codes:

STATUS_SUCCESS
Indicates that the routine allocated an extension of the requested size.
STATUS_INSUFFICENT_RESOURCES
Indicates that the memory could not be allocated for the driver object extension.
STATUS_OBJECT_NAME_COLLISION
Indicates that a driver object extension with the given ClientIdentificationAddress already exists.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Memory allocated by the system for the driver object extension is resident storage and is accessible from a raised IRQL.

Callers of this routine must provide a unique identifier for ClientIdentificationAddress. To retrieve a pointer to the context area, a caller passes the ClientIdentificationAddress to IoGetDriverObjectExtension.

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoGetDriverObjectExtension


IoAllocateErrorLogEntry

IoAllocateErrorLogEntry allocates an error log packet and returns a pointer to the packet so the caller can supply information about an I/O error.

PVOID
  IoAllocateErrorLogEntry(
    IN PVOID  IoObject,
    IN UCHAR  EntrySize
    );

Parameters

IoObject
Pointer to a device object representing the device on which an I/O error occurred, or to a driver object representing the driver that found an error.
EntrySize
Specifies the size in bytes of the packet to be allocated. This value cannot exceed ERROR_LOG_MAXIMUM_SIZE.

Return Value

IoAllocateErrorLogEntry returns a pointer to the allocated packet in which the driver sets up the error data, or NULL if a packet could not be allocated.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

The driver must first fill in the packet with information about the error, then call IoWriteErrorLogEntry to post the entry to the error log.

The value supplied for EntrySize depends on how much DumpData the driver includes in the error log packet, as well as any InsertionStrings it provides for the error. In general, the value of EntrySize is determined as follows:

sizeof(IO_ERROR_LOG_PACKET) + (n * sizeof(ULONG))
        + sizeof(InsertionStrings)

where n depends on how much DumpData the driver supplies with the error. If IoAllocateErrorLogPacket returns NULL, the driver should continue to run. You can assume that, if the same error occurs again, the driver can log the error at that point. The returned error log packet is defined as follows:

typedef struct _IO_ERROR_LOG_PACKET (
    UCHAR MajorFunctionCode;
    UCHAR RetryCount;
    USHORT DumpDataSize;
    USHORT NumberOfStrings;
    USHORT StringOffset;
    USHORT EventCategory;
    NTSTATUS ErrorCode;
    ULONG UniqueErrorValue;
    NTSTATUS FinalStatus;
    ULONG SequenceNumber;
    ULONG IoControlCode;
    LARGE_INTEGER DeviceOffset;
    ULONG DumpData[1];
}IO_ERROR_LOG_PACKET, *PIO_ERROR_LOG_PACKET;

Caller-supplied data in the packet includes the following:

Member | Meaning
MajorFunctionCode | The IRP_MJ_XXX of the current IRP.
RetryCount | A count of how many times the caller has retried the operation and encountered the same error.
DumpDataSize | The number of bytes of caller-supplied DumpData, if any.
NumberOfStrings | The number of insertion strings supplied following the DumpData; the initial string, if any, is assumed to be the driver name or that of the target device object.
StringOffset | The offset, immediately following any DumpData, of the caller-supplied, zero-terminated Unicode insertion strings, if any.
EventCategory | A caller-determined value matching that in the caller's message file for categories if the driver set itself up in the registry as an event-logging component; otherwise, zero.
ErrorCode | An IO_ERR_XXX value.
UniqueErrorValue | A driver-determined value that indicates where in the driver the error was encountered.
FinalStatus | The STATUS_XXX value to be set in the I/O status block of the IRP or a STATUS_XXX returned by a support routine.
SequenceNumber | A driver-assigned number for the current IRP, constant for the life of the request.
IoControlCode | An IOCTL_XXX if MajorFunctionCode is IRP_MJ_DEVICE_CONTROL, IRP_MJ_INTERNAL_DEVICE_CONTROL, or IRP_MJ_SCSI; otherwise, zero.
DeviceOffset | The offset on the device where the error occurred, or zero.
DumpData | Caller-supplied data, such as device register contents, if DumpDataSize is nonzero.

The I/O Manager uses the first insertion string for the device or driver name derived from the IoObject.

A log entry is freed once it is passed to either IoWriteErrorLogEntry or IoFreeErrorLogEntry.

Callers of IoAllocateErrorLogEntry must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoFreeErrorLogEntry, IoWriteErrorLogEntry


IoAllocateIrp

IoAllocateIrp allocates an IRP, given the number of I/O stack locations for each driver layered under the caller, and, optionally, for the caller.

PIRP
  IoAllocateIrp(
    IN CCHAR  StackSize,
    IN BOOLEAN  ChargeQuota
    );

Parameters

StackSize
Specifies the number of I/O stack locations to be allocated for the IRP. This value must be at least equal to the StackSize of the next-lower driver's device object, but can be one greater than this value. The calling driver need not allocate a stack location in the IRP for itself.
ChargeQuota
Should be set to FALSE by intermediate drivers. This can be set to TRUE only by highest-level drivers that are called in the context of the thread that originates the I/O request for which the driver is allocating another IRP.

Return Value

IoAllocateIrp returns a pointer to an IRP, which was allocated from nonpaged system space, or NULL if an IRP could not be allocated.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

An intermediate or highest-level driver can call IoAllocateIrp to create IRPs for requests it sends to lower-level drivers. Such a driver must initialize the IRP and must set its IoCompletion routine in the IRP it creates so the caller can dispose of the IRP when lower-level drivers have completed processing of the request.

Do not use IoInitializeIrp to initialize the IRP. IoAllocateIrp automatically initializes the IRP's members.

Drivers can reuse an IRP allocated by IoAllocateIrp under certain circumstances. See Reusing IRPs for details.

An intermediate or highest-level driver also can call IoBuildDeviceIoControlRequest, IoBuildAsynchronousFsdRequest or IoBuildSynchronousFsdRequest to set up requests it sends to lower-level drivers. Only a highest-level driver can call IoMakeAssociatedIrp.

Callers of IoAllocateIrp must be running at IRQL <= DISPATCH_LEVEL.

See Also

IO_STACK_LOCATION, IoBuildAsynchronousFsdRequest, IoBuildDeviceIoControlRequest, IoBuildSynchronousFsdRequest, IoFreeIrp, IoMakeAssociatedIrp, IoReuseIrp, IoSetCompletionRoutine, IRP


IoAllocateMdl

IoAllocateMdl allocates an MDL large enough to map a buffer, given its starting address and length. Optionally, this routine associates the MDL with an IRP.

PMDL
  IoAllocateMdl(
    IN PVOID  VirtualAddress,
    IN ULONG  Length,
    IN BOOLEAN  SecondaryBuffer,
    IN BOOLEAN  ChargeQuota,
    IN OUT PIRP  Irp  OPTIONAL
    );

Parameters

VirtualAddress
Points to the base virtual address of the buffer the MDL is to describe.
Length
Specifies the length in bytes of the buffer the MDL is to describe.
SecondaryBuffer
Indicates whether the buffer is a primary or secondary buffer. This parameter determines how the MDL is to be linked to the IRP. All buffers except the first buffer described by an MDL in an IRP are considered secondary buffers. This field must be FALSE if no IRP is associated with the MDL.
ChargeQuota
Should be set to FALSE by intermediate drivers. This can be set to TRUE only by highest-level drivers that are called in the context of the thread that originates the I/O request for which the driver is allocating another IRP.
Irp
Points to an IRP to be associated with the MDL. If the Irp pointer is nonNULL, the allocated MDL is associated with the specified IRP's MDL list, according to the value of SecondaryBuffer.

Return Value

IoAllocateMdl returns a pointer to an MDL or a NULL pointer if the MDL cannot be allocated.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

IoAllocateMdl can be used by a driver that needs to break a buffer into pieces, each mapped by a separate MDL, or to map a driver-allocated buffer. The driver should call MmBuildMdlForNonPagedPool with the MDL allocated by this call to set up an MDL describing a driver-allocated buffer in nonpaged pool.

Callers of IoAllocateMdl must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoBuildPartialMdl, IoFreeMdl, MmBuildMdlForNonPagedPool


IoAllocateWorkItem

IoAllocateWorkItem allocates a work item.

PIO_WORKITEM
  IoAllocateWorkItem(
    IN PDEVICE_OBJECT  DeviceObject
    );

Parameters

DeviceObject
Points to the caller's device object.

Return Value

IoAllocateWorkItem returns a pointer to a private IO_WORKITEM structure. Drivers should not make any assumptions about the format of this structure nor attempt to access information contained in this structure. IoAllocateWorkItem can return NULL in the case of insufficient resources.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Drivers queue work items allocated by IoAllocateWorkItem with IoQueueWorkItem.

It is the caller's responsibility to free the resources associated with the work item returned by IoAllocateWorkItem by calling IoFreeWorkItem in the callback routine passed to IoQueueWorkItem.

IoAllocateWorkItem is supported on Windows 2000 and later, and Windows ME, but not on Windows 98.

Callers of IoAllocateWorkItem must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoQueueWorkItem, IoFreeWorkItem


IoAssignArcName

IoAssignArcName creates a symbolic link between the ARC name of a physical device and the name of the corresponding device object when it has been created.

VOID
  IoAssignArcName(
    IN PUNICODE_STRING  ArcName,
    IN PUNICODE_STRING  DeviceName
    );

Parameters

ArcName
Points to a buffer containing the ARC name of the device. The ARC name must be a Unicode string.
DeviceName
Points to a buffer containing the name of the device object, representing the same device. The device object name must be a Unicode string.

Headers

Declared in ntddk.h. Include ntddk.h

Comments

Drivers of hard disk devices need not call this routine. Drivers of other mass-storage devices, including floppy, CD_ROM, and tape devices, should call IoAssignArcName during their initialization.

Callers of IoAssignArcName must be running at IRQL PASSIVE_LEVEL.

See Also

IoCreateDevice


IoAssignResources

IoAssignResources is obsolete and is exported only to support existing drivers. Drivers of PnP devices are assigned resources by the PnP Manager, which passes resource lists with each IRP_MN_START_DEVICE request. Drivers that must support a legacy device that cannot be enumerated by the PnP Manager should use IoReportDetectedDevice and IoReportResourceForDetection.

NTSTATUS
  IoAssignResources(
    IN PUNICODE_STRING  RegistryPath,
    IN PUNICODE_STRING  DriverClassName  OPTIONAL,
    IN PDRIVER_OBJECT  DriverObject,
    IN PDEVICE_OBJECT  DeviceObject  OPTIONAL,
    IN PIO_RESOURCE_REQUIREMENTS_LIST  RequestedResources,
    IN OUT PCM_RESOURCE_LIST  *AllocatedResources
    );


IoAttachDevice

IoAttachDevice attaches the caller's device object to a named target device object, so that I/O requests bound for the target device are routed first to the caller.

NTSTATUS
  IoAttachDevice(
    IN PDEVICE_OBJECT  SourceDevice,
    IN PUNICODE_STRING  TargetDevice,
    OUT PDEVICE_OBJECT  *AttachedDevice
    );

Parameters

SourceDevice
Points to the caller-created device object.
TargetDevice
Points to a buffer containing the name of the device object to which the specified SourceDevice is to be attached.
AttachedDevice
Points to caller-allocated storage for a pointer. On return, contains a pointer to the target device object if the attachment succeeds.

Return Value

IoAttachDevice can return one of the following NTSTATUS values:

STATUS_SUCCESS
STATUS_INVALID_PARAMETER
STATUS_OBJECT_TYPE_MISMATCH
STATUS_OBJECT_NAME_INVALID
STATUS_INSUFFICIENT_RESOURCES

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

IoAttachDevice establishes layering between drivers so that the same IRPs can be sent to each driver in the chain.

This routine is used by intermediate drivers during initialization. It allows such a driver to attach its own device object to another device in such a way that any requests being made to the original device are given first to the intermediate driver.

The caller can be layered only at the top of an existing chain of layered drivers. IoAttachDevice searches for the highest device object layered over TargetDevice and attaches to that object (that can be the TargetDevice). Therefore, this routine must not be called if a driver that must be higher-level has already layered itself over the target device.

Note that for file system drivers and drivers in the storage stack, IoAttachDevice opens the target device with FILE_READ_ATTRIBUTES and then calls IoGetRelatedDeviceObject. This does not cause a file system to be mounted. Thus, a successful call to IoAttachDevice returns the device object of the storage driver, not that of the file system driver.

This routine sets the AlignmentRequirement in SourceDevice to the value in the next-lower device object and sets the StackSize to the value in the next-lower-object plus one.

Callers of IoAttachDevice must be running at IRQL PASSIVE_LEVEL.

See Also

DEVICE_OBJECT, IoAttachDeviceToDeviceStack, IoGetRelatedDeviceObject, IoCreateDevice, IoDetachDevice


IoAttachDeviceByPointer

IoAttachDeviceByPointer is obsolete; use IoAttachDeviceToDeviceStack instead.

NTSTATUS
  IoAttachDeviceByPointer(
    IN PDEVICE_OBJECT  SourceDevice,
    IN PDEVICE_OBJECT  TargetDevice
    );


IoAttachDeviceToDeviceStack

IoAttachDeviceToDeviceStack attaches the caller's device object to the highest device object in the chain and returns a pointer to the previously highest device object.

PDEVICE_OBJECT
  IoAttachDeviceToDeviceStack(
    IN PDEVICE_OBJECT  SourceDevice,
    IN PDEVICE_OBJECT  TargetDevice
    );

Parameters

SourceDevice
Points to the caller-created device object.
TargetDevice
Points to another driver's device object, such as a pointer returned by a preceding call to IoGetDeviceObjectPointer.

Return Value

IoAttachDeviceToDeviceStack returns a pointer to the device object to which the SourceDevice was attached. The returned device object pointer can differ from TargetDevice if TargetDevice had additional drivers layered on top of it.

IoAttachDeviceToDeviceStack returns NULL if it could not attach the device object because, for example, the target device was being unloaded.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

IoAttachDeviceToDeviceStack establishes layering between drivers so that the same IRPs are sent to each driver in the chain.

An intermediate driver can use this routine during initialization to attach its own device object to another driver's device object. Subsequent I/O requests sent to TargetDevice are sent first to the intermediate driver.

This routine sets the AlignmentRequirement in SourceDevice to the value in the next-lower device object and sets the StackSize to the value in the next-lower-object plus one.

A driver writer must take care to call this routine before any drivers that must layer on top of their driver. IoAttachDeviceToDeviceStack attaches SourceDevice to the highest device object currently layered in the chain and has no way to determine whether drivers are being layered in the correct order.

A driver that acquired a pointer to the target device by calling IoGetDeviceObjectPointer should call ObDereferenceObject with the file object pointer that was returned by IoGetDeviceObjectPointer to release its reference to the file object before it detaches its own device object, for example, when such a higher-level driver is unloaded.

Callers of IoAttachDeviceToDeviceStack must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoAttachDevice, IoDetachDevice, ObDereferenceObject, IoGetDeviceObjectPointer


IoBuildAsynchronousFsdRequest

IoBuildAsynchronousFsdRequest allocates and sets up an IRP to be sent to lower-level drivers.

PIRP
  IoBuildAsynchronousFsdRequest(
    IN ULONG  MajorFunction,
    IN PDEVICE_OBJECT  DeviceObject,
    IN OUT PVOID  Buffer  OPTIONAL,
    IN ULONG  Length  OPTIONAL,
    IN PLARGE_INTEGER  StartingOffset  OPTIONAL,
    IN PIO_STATUS_BLOCK  IoStatusBlock  OPTIONAL
    );

Parameters

MajorFunction
Specifies the major function code to be set in the IRP, one of IRP_MJ_PNP, IRP_MJ_READ, IRP_MJ_WRITE, IRP_MJ_FLUSH_BUFFERS, or IRP_MJ_SHUTDOWN.
DeviceObject
Points to the next-lower driver's device object, representing the target device for the read, write, flush, or shutdown operation.
Buffer
Points to a buffer into which data is read or from which data is written. The value of this argument is NULL for flush and shutdown requests.
Length
Specifies the length in bytes of Buffer. The value of this argument is zero for flush and shutdown requests.
StartingOffset
Points to the starting offset on the input/output media. The value of this argument is zero for flush and shutdown requests.
IoStatusBlock
Points to the address of an I/O status block in which the to-be-called driver(s) return final status about the requested operation.

Return Value

IoBuildAsynchronousFsdRequest returns a pointer to an IRP or a NULL pointer if the IRP cannot be allocated.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Intermediate or highest-level drivers can call IoBuildAsynchronousFsdRequest to set up IRPs for requests sent to lower-level drivers. The calling driver must supply anIoCompletion routine for the IRP, so the IRP can be deallocated with IoFreeIrp.

The IRP that gets built contains only enough information to get the operation started and to complete the IRP. No other context information is tracked because an asynchronous request is context-independent.

Lower-level drivers might impose restrictions on parameters supplied to this routine. For example, disk drivers might require that values supplied for Length and StartingOffset be integrals of the device's sector size.

Callers of IoBuildAsynchronousFsdRequest must be running at IRQL <= DISPATCH_LEVEL.

An intermediate or highest-level driver also can call IoBuildDeviceIoControlRequest, IoAllocateIrp, or IoBuildSynchronousFsdRequest to set up requests it sends to lower-level drivers. Only a highest-level driver can call IoMakeAssociatedIrp.

See Also

IO_STACK_LOCATION, IoAllocateIrp, IoBuildDeviceIoControlRequest, IoBuildSynchronousFsdRequest, IoCallDriver, IoFreeIrp, IoMakeAssociatedIrp, IoSetCompletionRoutine, IRP


IoBuildDeviceIoControlRequest

IoBuildDeviceIoControlRequest allocates and sets up an IRP for a device control request, optionally with an I/O buffer if the I/O control code requires the caller to supply an input or output buffer.

PIRP
  IoBuildDeviceIoControlRequest(
    IN ULONG  IoControlCode,
    IN PDEVICE_OBJECT  DeviceObject,
    IN PVOID  InputBuffer  OPTIONAL,
    IN ULONG  InputBufferLength,
    OUT PVOID  OutputBuffer  OPTIONAL,
    IN ULONG  OutputBufferLength,
    IN BOOLEAN  InternalDeviceIoControl,
    IN PKEVENT  Event,
    OUT PIO_STATUS_BLOCK  IoStatusBlock
    );

Parameters

IoControlCode
Specifies the IOCTL_XXX to be set up. For more information about device-type-specific I/O codes, see device-type specific chapters in this DDK.
DeviceObject
Points to the next-lower driver's device object, representing the target device.
InputBuffer
Points to an input buffer to be passed to the lower driver or NULL if the request does not pass input data to lower driver(s).
InputBufferLength
Specifies the length in bytes of the input buffer. If InputBuffer is NULL, this value must be zero.
OutputBuffer
Points to an output buffer in which the lower driver is to return data or NULL if the request does not require lower driver(s) to return data.
OutputBufferLength
Specifies the length in bytes of the output buffer. If OutputBuffer is NULL, this value must be zero.
InternalDeviceIoControl
If InternalDeviceControl is TRUE the target driver's Dispatch routine for IRP_MJ_INTERNAL_DEVICE_CONTROL or IRP_MJ_SCSI is called; otherwise, the Dispatch routine for IRP_MJ_DEVICE_CONTROL is called.
Event
Points to an initialized event object for which the caller provides the storage. The event is set to the Signaled state when lower driver(s) have completed the requested operation. The caller can wait on the event object for the completion of the IRP allocated by this routine.
IoStatusBlock
Specifies an I/O status block to be set when the request is completed by lower drivers.

Return Value

IoBuildDeviceIoControlRequest returns a pointer to an IRP with the next-lower driver's I/O stack location partially set up from the supplied parameters. The returned pointer is NULL if an IRP cannot be allocated.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

An intermediate or highest-level driver can call IoBuildDeviceIoControlRequest to set up IRPs for requests sent to lower-level drivers. The next-lower driver's I/O stack location is set up with the given IoControlCode at Parameters.DeviceIoControl.IoControlCode. Because the caller can wait on the completion of this driver-allocated IRP by calling KeWaitForSingleObject on the given Event, the caller need not set an IoCompletion routine in the IRP before calling IoCallDriver. When the next-lower driver completes this IRP, the I/O Manager releases it.

IRPs created using IoBuildDeviceIoControlRequest must be completed by calling IoCompleteRequest and not by merely deallocating the IRP with IoFreeIrp. IoBuildDeviceIoControlRequest queues the IRPs it creates in the IRP queue of the current thread. Freeing these IRPs without completing them might result in a system crash when the thread terminates as the thread attempts to deallocate the IRP's memory.

Callers of IoBuildDeviceIoControlRequest must be running at IRQL PASSIVE_LEVEL.

See Also

IO_STACK_LOCATION, IoAllocateIrp, IoBuildAsynchronousFsdRequest, IoBuildSynchronousFsdRequest, IoCallDriver, IoCompleteRequest, IRP, KeInitializeEvent, KeWaitForSingleObject


IoBuildPartialMdl

IoBuildPartialMdl maps a portion of a buffer described by another MDL into an MDL.

VOID
  IoBuildPartialMdl(
    IN PMDL  SourceMdl,
    IN OUT PMDL  TargetMdl,
    IN PVOID  VirtualAddress,
    IN ULONG  Length
    );

Parameters

SourceMdl
Points to an MDL describing the original buffer, of which a subrange is to be mapped.
TargetMdl
Points to a caller-allocated MDL. The MDL must be large enough to map the subrange specified by VirtualAddress and Length.
VirtualAddress
Points to the base virtual address for the subrange to be mapped in the TargetMdl.
Length
Specifies the length in bytes to be mapped by the TargetMdl. This value, in combination with VirtualAddress, must specify a buffer that is a proper subrange of the buffer described by SourceMdl. If Length is zero, the subrange to be mapped starts at VirtualAddress and includes the remaining range described by the SourceMdl.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

IoBuildPartialMdl maps a subrange of a buffer currently mapped by SourceMdl. The VirtualAddress and Length parameters describe the subrange to be mapped from the SourceMdl into the TargetMdl.

Drivers that must split large transfer requests can use this routine. The caller must release the partial MDL it allocated when it has transferred all the requested data or completed the IRP with an error status.

Callers of IoBuildPartialMdl can be running at IRQL <= DISPATCH_LEVEL.

See Also

IoAllocateMdl, IoCallDriver, IoFreeMdl, IoSetCompletionRoutine


IoBuildSynchronousFsdRequest

IoBuildSynchronousFsdRequest allocates and builds an IRP to be sent synchronously to lower driver(s).

PIRP
  IoBuildSynchronousFsdRequest(
    IN ULONG  MajorFunction,
    IN PDEVICE_OBJECT  DeviceObject,
    IN OUT PVOID  Buffer  OPTIONAL,
    IN ULONG  Length  OPTIONAL,
    IN PLARGE_INTEGER  StartingOffset  OPTIONAL,
    IN PKEVENT  Event,
    OUT PIO_STATUS_BLOCK  IoStatusBlock
    );

Parameters

MajorFunction
Specifies the major function code, one of IRP_MJ_PNP, IRP_MJ_READ, IRP_MJ_WRITE, IRP_MJ_FLUSH_BUFFERS, or IRP_MJ_SHUTDOWN.
DeviceObject
Points to the next-lower driver's device object representing the target device for the read, write, flush, or shutdown operation.
Buffer
Points to a buffer containing data to be written when MajorFunction is IRP_MJ_WRITE, or is the location to receive data read when MajorFunction is IRP_MJ_READ. This parameter must be NULL for the MajorFunction IRP_MJ_FLUSH_BUFFERS or IRP_MJ_SHUTDOWN.
Length
Specifies the length, in bytes, of Buffer. For devices such as disks, this value must be an integral of 512. This parameter is required for read/write requests, but must be zero for flush and shutdown requests.
StartingOffset
Points to the offset on the disk to read/write from/to. This parameter is required for read/write requests, but must be zero for flush and shutdown requests.
Event
Points to an initialized event object for which the caller provides the storage. The event is set to the Signaled state when the requested operation completes. The caller can wait on the event object for the completion of the IRP allocated by this routine.
IoStatusBlock
Points to the I/O status block that is set when the IRP is completed by the lower driver(s).

Return Value

IoBuildSynchronousFsdRequest returns a pointer to the IRP or NULL if an IRP cannot be allocated.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Intermediate or highest-level drivers can call IoBuildSynchronousFsdRequest to set up IRPs for requests sent to lower-level drivers, only if the caller is running in a nonarbitrary thread context and at IRQL PASSIVE_LEVEL.

IoBuildSynchronousFsdRequest allocates and sets up an IRP that can be sent to a device driver to perform a synchronous read, write, flush, or shutdown operation. The IRP contains only enough information to get the operation started.

Lower-level drivers might impose restrictions on parameters supplied to this routine. For example, disk drivers might require that values supplied for Length and StartingOffset be integrals of the device's sector size.

The caller can determine when the I/O has completed by calling KeWaitForSingleObject with the Event. Performing this wait operation causes the current thread to wait. Therefore, this operation can be requested during the initialization of an intermediate driver or from an FSD in the context of a thread requesting a synchronous I/O operation. A driver cannot wait for a nonzero interval on the Event at raised IRQL in an arbitrary thread context.

Because the caller can wait on a given Event, the caller need not set an IoCompletion routine in the caller-allocated IRP before calling IoCallDriver. When the caller completes the IRP, the I/O Manager releases it.

IRPs created using IoBuildSynchronousFsdRequest must be completed by calling IoCompleteRequest and not by merely deallocating the IRP with IoFreeIrp. IoBuildSynchronousFsdRequest queues the IRPs it creates in the IRP queue of the current thread. Freeing these IRPs without completing them might result in a system crash when the thread terminates as the thread attempts to deallocate the IRP's memory.

See Also

IO_STACK_LOCATION, IoAllocateIrp, IoBuildAsynchronousFsdRequest, IoCompleteRequest, IRP, KeInitializeEvent, KeWaitForSingleObject


IoCallDriver

IoCallDriver sends an IRP to the next-lower-level driver after the caller has set up the I/O stack location in the IRP for that driver.

NTSTATUS
  IoCallDriver(
    IN PDEVICE_OBJECT  DeviceObject,
    IN OUT PIRP  Irp
    );

Parameters

DeviceObject
Points to the next-lower driver's device object, representing the target device for the requested I/O operation.
Irp
Points to the IRP.

Return Value

IoCallDriver returns the NTSTATUS value that a lower driver set in the I/O status block for the given request or STATUS_PENDING if the request was queued for additional processing.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

IoCallDriver assigns the DeviceObject input parameter to the device object field of the IRP stack location for the next lower driver.

An IRP passed in a call to IoCallDriver becomes inaccessible to the higher-level driver, unless the higher-level driver has set up its IoCompletion routine for the IRP with IoSetCompletionRoutine. If it does, the IRP input to the driver-supplied IoCompletion routine has its I/O status block set by the lower driver(s) and all lower-level driver(s)' I/O stack locations filled with zeros.

Drivers must not use IoCallDriver to pass power IRPs (IRP_MJ_POWER). Use PoCallDriver instead.

Callers of IoCallDriver must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoAllocateIrp, IoBuildAsynchronousFsdRequest, IoBuildDeviceIoControlRequest, IoBuildSynchronousFsdRequest, IoSetCompletionRoutine, PoCallDriver


IoCancelIrp

IoCancelIrp sets the cancel bit in a given IRP and calls the cancel routine for the IRP if there is one.

BOOLEAN
  IoCancelIrp(
    IN PIRP  Irp
    );

Parameters

Irp
Points to the IRP to be canceled.

Return Value

IoCancelIrp returns TRUE if the IRP was canceled and FALSE if the IRP's cancel bit was set but the IRP was not cancelable.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

If the IRP has a cancel routine, IoCancelIrp sets the cancel bit and calls the cancel routine.

If Irp->CancelRoutine is NULL, and therefore the IRP is not cancelable, IoCancelIrp sets the IRP's cancel bit and returns FALSE. The IRP should be canceled at a later time when it becomes cancelable.

If a driver that does not own the IRP calls IoCancelIrp, the results are unpredictable. The IRP might be completed with a successful status even though its cancel bit was set.

An intermediate driver should not arbitrarily call IoCancelIrp unless that driver created the IRP passed in the call. Otherwise, the intermediate driver might cancel an IRP that some higher-level driver is tracking for purposes of its own.

Callers of IoCancelIrp must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoSetCancelRoutine


IoCheckShareAccess

IoCheckShareAccess is called by FSDs or other highest-level drivers to check whether shared access to a file object is permitted.

NTSTATUS
  IoCheckShareAccess(
    IN ACCESS_MASK  DesiredAccess,
    IN ULONG  DesiredShareAccess,
    IN OUT PFILE_OBJECT  FileObject,
    IN OUT PSHARE_ACCESS  ShareAccess,
    IN BOOLEAN  Update
    );

Parameters

DesiredAccess
Specifies the ACCESS_MASK value that represents desired type of access to the given FileObject for the current open request. Generally, the value of this parameter is equal to the DesiredAccess passed to the file system or highest-level driver by the I/O Manager when the open request was made. See IoCreateFile for details.
DesiredShareAccess
Specifies the desired type of shared access to FileObject for the current open request. The value of this parameter is usually the same as the DesiredAccess passed to the file system or highest-level driver by the I/O Manager when the open request was made. This value can be zero, one, or more of the following:

FILE_SHARE_READ

FILE_SHARE_WRITE

FILE_SHARE_DELETE

FileObject
Points to the file object for which to check access for the current open request.
ShareAccess
Points to the common share-access data structure associated with FileObject. Drivers should treat this structure as opaque.
Update
Specifies whether to update the share-access status for FileObject. A Boolean value of TRUE means this routine will update the share access information for the file object if the open request is permitted.

Return Value

IoCheckShareAccess returns STATUS_SUCCESS if the requester's access to the file object is compatible with the way in which it is currently open. If the request is denied because of a sharing violation, then STATUS_SHARING_VIOLATION is returned.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

IoCheckShareAccess checks a file object open request to determine whether the types of desired and shared accesses specified are compatible with the way in which the file object is currently being accessed by other opens.

File systems maintain state about files through structures called file control blocks (FCBs). The SHARE_ACCESS is a structure describing how the file is currently accessed by all opens. This state is contained in the FCB as part of the open state for each file object. Each file object should have only one share access structure. Other highest-level drivers might call this routine to check the access requested when a file object representing such a driver's device object is opened.

IoCheckShareAccess is not an atomic operation. Therefore, drivers calling this routine must protect the shared file object passed to IoCheckShareAccess by means of some kind of lock, such as a mutex or a resource lock, in order to prevent corruption of the shared access counts.

Callers of IoCheckShareAccess must be running at IRQL PASSIVE_LEVEL.

See Also

ACCESS_MASK, IoCreateFile, IoGetRelatedDeviceObject, IoRemoveShareAccess, IoSetShareAccess, IoUpdateShareAccess


IoCompleteRequest

IoCompleteRequest indicates the caller has completed all processing for a given I/O request and is returning the given IRP to the I/O Manager.

VOID
  IoCompleteRequest(
    IN PIRP  Irp,
    IN CCHAR  PriorityBoost
    );

Parameters

Irp
Points to the IRP to be completed.
PriorityBoost
Specifies a system-defined constant by which to increment the runtime priority of the original thread that requested the operation. This value is IO_NO_INCREMENT if the original thread requested an operation the driver could complete quickly (so the requesting thread is not compensated for its assumed wait on I/O) or if the IRP is completed with an error. Otherwise, the set of PriorityBoost constants are device-type-specific. See ntddk.h or wdm.h for these constants.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

When a driver has finished all processing for a given IRP, it calls IoCompleteRequest. The I/O Manager checks the IRP to determine whether any higher-level drivers have set up an IoCompletion routine for the IRP. If so, each IoCompletion routine is called, in turn, until every layered driver in the chain has completed the IRP.

When all drivers have completed a given IRP, the I/O Manager returns status to the original requester of the operation. Note that a higher-level driver that sets up a driver-created IRP must supply an IoCompletion routine to release the IRP it created.

Callers of IoCompleteRequest must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoSetCompletionRoutine


IoConnectInterrupt

IoConnectInterrupt registers a device driver's InterruptService routine (ISR), so that it will be called when a device interrupts on any of a specified set of processors.

NTSTATUS
  IoConnectInterrupt(
    OUT PKINTERRUPT  *InterruptObject,
    IN PKSERVICE_ROUTINE  ServiceRoutine,
    IN PVOID  ServiceContext,
    IN PKSPIN_LOCK  SpinLock  OPTIONAL,
    IN ULONG  Vector,
    IN KIRQL  Irql,
    IN KIRQL  SynchronizeIrql,
    IN KINTERRUPT_MODE    InterruptMode,
    IN BOOLEAN  ShareVector,
    IN KAFFINITY  ProcessorEnableMask,
    IN BOOLEAN  FloatingSave
    );

Parameters

InterruptObject
Points to the address of driver-supplied storage for a pointer to a set of interrupt objects. This pointer must be passed in subsequent calls to KeSynchronizeExecution.
ServiceRoutine
Points to the entry point for the driver-supplied InterruptService routine.
ServiceContext
Points to the driver-determined context that will be supplied to the InterruptService routine when it is called. The ServiceContext area must be in resident memory: in the device extension of a driver-created device object, in the controller extension of a driver-created controller object, or in nonpaged pool allocated by the device driver. See Providing ISR Context Information or details.
SpinLock
Points to an initialized spin lock, for which the driver supplies the storage, that will be used to synchronize access to driver-determined data shared by other driver routines. This parameter is required if the ISR handles more than one vector or if the driver has more than one ISR. Otherwise, the driver need not allocate storage for an interrupt spin lock and the input pointer is NULL.
Vector
Specifies the interrupt vector passed in the interrupt resource at the u.Interrupt.Vector member of CM_PARTIAL_RESOURCE_DESCRIPTOR.
Irql
Specifies the DIRQL passed in the interrupt resource at the u.Interrupt.Level member of CM_PARTIAL_RESOURCE_DESCRIPTOR.
SynchronizeIrql
Specifies the DIRQL at which the ISR will execute. If the ISR handles more than one interrupt vector or the driver has more than one ISR, this value must be the highest of the Irql values passed at u.Interrupt.Level in each interrupt resource. Otherwise, the Irql and SynchronizeIrql values are identical.
InterruptMode
Specifies whether the device interrupt is LevelSensitive or Latched.
ShareVector
Specifies whether the interrupt vector is sharable.
ProcessorEnableMask
Specifies the set of processors on which device interrupts can occur in this platform. This value is passed in the interrupt resource at u.Interrupt.Affinity.
FloatingSave
Specifies whether to save the floating-point stack when the driver's device interrupts. For X86-based platforms, this value must be set to FALSE.

Return Value

IoConnectInterrupt can return one of the following NTSTATUS values:

STATUS_SUCCESS
STATUS_INVALID_PARAMETER
STATUS_INSUFFICIENT_RESOURCES

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

A PnP driver should call IoConnectInterrupt as part of device start-up, before it completes the PnP IRP_MN_START_DEVICE request.

A driver receives raw and translated hardware resources with the IRP_MN_START_DEVICE request at Irp–>Parameters.StartDevice.AllocatedResources and Irp–>Parameters.StartDevice.AllocatedResourcesTranslated, respectively. To connect its interrupt, a driver uses the resources at AllocatedResourcesTranslated.List.PartialResourceList.PartialDescriptors[]. The driver must scan the array of partial descriptors for resources of type CmResourceTypeInterrupt.

If the driver supplies the storage for the SpinLock, it must call KeInitializeSpinLock before passing its interrupt spin lock to IoConnectInterrupt.

On return from a successful call to IoConnectInterrupt, the caller's ISR can be called if interrupts are enabled on the driver's device or if ShareVector was set to TRUE.

Callers of IoConnectInterrupt must be running at IRQL PASSIVE_LEVEL.

See Also

KeInitializeSpinLock, KeSynchronizeExecution, CM_PARTIAL_RESOURCE_DESCRIPTOR


IoCopyCurrentIrpStackLocationToNext

IoCopyCurrentIrpStackLocationToNext copies the IRP stack parameters from the current I/O stack location to the stack location of the next-lower driver and allows the current driver to set an I/O completion routine.

VOID
  IoCopyCurrentIrpStackLocationToNext(
    IN PIRP  Irp
    );

Parameters

Irp
Points to the IRP.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

A driver calls IoCopyCurrentIrpStackLocationToNext to copy the IRP parameters from its stack location to the next-lower driver's stack location.

After calling this routine, a driver typically sets an I/O completion routine with IoSetCompletionRoutine before passing the IRP to the next-lower driver with IoCallDriver. Drivers that pass on their IRP parameters but do not set an I/O completion routine should call IoSkipCurrentIrpStackLocation instead of this routine.

Callers of IoCopyCurrentIrpStackLocationToNext must be running at IRQL <= DISPATCH_LEVEL.

See Also

IO_STACK_LOCATION, IoCallDriver, IoSetCompletionRoutine, IoSkipCurrentIrpStackLocation


IoCreateController

IoCreateController allocates memory for and initializes a controller object with a controller extension of a driver-determined size.

PCONTROLLER_OBJECT
  IoCreateController(
    IN ULONG  Size
    );

Parameters

Size
Specifies the number of bytes to be allocated for the controller extension.

Return Value

IoCreateController returns a pointer to the controller object or a NULL pointer if memory could not be allocated for the requested device extension.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

A controller object usually represents a physical device controller with attached devices on which a single driver carries out I/O requests. The controller extension is allocated from nonpaged pool and is guaranteed to be accessible by any driver routine and in an arbitrary thread context.

The controller object is used to synchronize I/O operations to target devices for which I/O requests can come in concurrently to a single, monolithic driver. A driver also might use a controller object to synchronize operations through device channels.

If IoCreateController returns NULL, the driver should fail device start-up.

Callers of IoCreateController must be running at IRQL PASSIVE_LEVEL.

See Also

CONTROLLER_OBJECT, IoAllocateController, IoFreeController, IoDeleteController


IoCreateDevice

IoCreateDevice allocates memory for and initializes a device object for use by a driver.

NTSTATUS
  IoCreateDevice(
    IN PDRIVER_OBJECT  DriverObject,
    IN ULONG  DeviceExtensionSize,
    IN PUNICODE_STRING  DeviceName  OPTIONAL,
    IN DEVICE_TYPE  DeviceType,
    IN ULONG  DeviceCharacteristics,
    IN BOOLEAN  Exclusive,
    OUT PDEVICE_OBJECT  *DeviceObject
    );

Parameters

DriverObject
Points to the driver object for the caller. Each driver receives a pointer to its driver object in a parameter to its DriverEntry routine. PnP function and filter drivers also receive a driver object pointer in their AddDevice routines.
DeviceExtensionSize
Specifies the driver-determined number of bytes to be allocated for the device extension of the device object. The internal structure of the device extension is driver-defined. A driver uses the device extension to maintain context about the I/O operations on the device represented by the DeviceObject.
DeviceName
Optionally points to a buffer containing a zero-terminated Unicode string that names the device object. The string must be a full path name.

Typically, only physical device objects (PDOs), which are created by PnP bus drivers, are named. PnP function drivers and filter drivers should not specify a DeviceName for a functional device object (FDO) or filter device object (filter DO). Naming an FDO or filter DO bypasses the PnP Manager's security. If a user-mode component needs a symbolic link to the device, the function or filter driver should register a device interface (see IoRegisterDeviceInterface ). If a kernel-mode component needs a legacy device name, the driver must name the FDO, but naming is not recommended.

DeviceType
Specifies one of the system-defined FILE_DEVICE_XXX constants indicating the type of device (such as FILE_DEVICE_DISK, FILE_DEVICE_KEYBOARD, etc.) or a vendor-defined value for a new type of device. For more information, see Specifying Device Types. (Because a bus driver might not know a device's type, a device type value for a PDO can be specified in an INF AddReg directive.)
DeviceCharacteristics
Specifies one or more system-defined constants, ORed together, that provide additional information about the driver's device. The constants include:
FILE_AUTOGENERATED_DEVICE_NAME
Directs the I/O Manager to generate a name for the device, instead of the caller specifying a DeviceName when calling this routine. The I/O Manager ensures that the name is unique. This characteristic is typically specified by a PnP bus driver to generate a name for a physical device object (PDO) for a child device on its bus. This characteristic is new for Windows 2000 and Windows 98.
FILE_DEVICE_IS_MOUNTED
Indicates that a filesystem is mounted on the device. Drivers should not set this characteristic.
FILE_DEVICE_SECURE_OPEN
(Windows NT®4.0 SP5 and later)

Directs the I/O manager to apply the security descriptor of the device object to relative opens and trailing filename opens on the device.

FILE_FLOPPY_DISKETTE
Indicates that the device is a floppy disk device.
FILE_READ_ONLY_DEVICE
Indicates that the device is not writeable.
FILE_REMOTE_DEVICE
Indicates that the device is remote.
FILE_REMOVABLE_MEDIA
Indicates that the storage device supports removable media.

Note that this characteristic indicates removable media, not a removable device. For example, drivers for JAZ drive devices should specify this characteristic but drivers for PCMCIA flash disks should not.

FILE_VIRTUAL_VOLUME
Indicates that the volume is virtual. Drivers should not set this characteristic.
FILE_WRITE_ONCE_MEDIA
Indicates that the device supports write-once media.

If none of the device characteristics are relevant to your device, specify zero for this parameter.

Exclusive
Indicates whether the device object represents an exclusive device. That is, only one handle at a time can send I/O requests to the corresponding device object. If the underlying device supports overlapped I/O, multiple threads of the same process can send requests through a single handle.
DeviceObject
Points to the newly created device object if the call succeeds. A device object represents a physical, virtual, or logical device that the driver is supporting.

Return Value

IoCreateDevice can return one of the following NTSTATUS values:

STATUS_SUCCESS
STATUS_INSUFFICIENT_RESOURCES
STATUS_OBJECT_NAME_EXISTS
STATUS_OBJECT_NAME_COLLISION

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

IoCreateDevice creates a device object and returns a pointer to the object. The caller is responsible for deleting the object when it is no longer needed by calling IoDeleteDevice.

Drivers call this routine to create PDOs, FDOs, and filter DOs. See Device Objects and Device Stacks for information about the kinds of device objects.

Be careful to specify the DeviceType and DeviceCharacteristics values in the correct parameters. Both parameters use system-defined FILE_XXX constants and some driver writers specify the values in the wrong parameters by mistake.

If a function or filter driver for a device sets any of the following DeviceCharacteristics, the PnP Manager propagates the characteristic(s) to the FDO and filter DOs in the device stack:

FILE_DEVICE_SECURE_OPEN
FILE_FLOPPY_DISKETTE
FILE_READ_ONLY_DEVICE
FILE_REMOVABLE_MEDIA
FILE_WRITE_ONCE_MEDIA

This routine allocates space in nonpaged pool for a driver-defined device extension associated with the device object, so that the device extension is accessible to the driver in any execution context and at any IRQL. The returned device extension is initialized with zeros.

The caller is responsible for setting certain fields in the returned device object, such as the Flags field, and for initializing the device extension with any driver-defined information. For other operations required on new device objects, see Initializing a Device Object and the device-type-specific documentation for your device.

Device objects for disks, tapes, CD ROMs, and RAM disks are given a Volume Parameter Block (VPB) that is initialized to indicate that the volume has never been mounted on the device.

If a driver's call to IoCreateDevice returns an error, it should release any resources it allocated for that device.

A PnP bus driver calls IoCreateDevice when it is enumerating a new device in response to an IRP_MN_QUERY_DEVICE_RELATIONS for BusRelations. A PnP function or filter driver calls IoCreateDevice in its AddDevice routine.

Callers of IoCreateDevice must be running at IRQL PASSIVE_LEVEL.

See Also

DEVICE_OBJECT, IoAttachDevice, IoAttachDeviceToDeviceStack, IoCreateSymbolicLink, IoDeleteDevice


IoCreateDisk

IoCreateDisk initializes a raw disk by creating a new partition table.

NTKERNELAPI
NTSTATUS
  IoCreateDisk (
    IN PDEVICE_OBJECT  DeviceObject,
    IN PCREATE_DISK  Disk
    );

Parameters

DeviceObject
Specifies the DEVICE_OBJECT for the raw disk.
Disk
Pointer to a CREATE_DISK structure that specifies the type and parameters for the partition table. If Disk is NULL, the routine deletes the partition table on the disk.

Return Value

Returns STATUS_SUCCESS on success, or the appropriate error code on failure.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

This routine is only available on Windows XP and later.

IoCreateDisk must only be used by disk drivers. Other drivers should use the IOCTL_DISK_CREATE_DISK I/O request instead.

See Also

CREATE_DISK, IOCTL_DISK_CREATE_DISK


IoCreateFile

IoCreateFile either causes a new file or directory to be created, or it opens an existing file, device, directory, or volume, giving the caller a handle for the file object.

NTSTATUS
  IoCreateFile(
    OUT PHANDLE FileHandle,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes,
    OUT PIO_STATUS_BLOCK IoStatusBlock,
    IN PLARGE_INTEGER AllocationSize OPTIONAL,
    IN ULONG FileAttributes,
    IN ULONG ShareAccess,
    IN ULONG Disposition,
    IN ULONG CreateOptions,
    IN PVOID EaBuffer OPTIONAL,
    IN ULONG EaLength,
    IN CREATE_FILE_TYPE CreateFileType,
    IN PVOID ExtraCreateParameters OPTIONAL,
    IN ULONG Options
    ) ;

Parameters

FileHandle
Points to a variable that receives the file handle if the call is successful.
DesiredAccess
Specifies the ACCESS_MASK value that represents the type of access that the caller requires to the file or directory. The set of system-defined DesiredAccess flags determines the following specific access rights for file objects:
DesiredAccess Flags | Meaning
DELETE | The file can be deleted.
FILE_READ_DATA | Data can be read from the file.
FILE_READ_ATTRIBUTES | FileAttributes flags, described later, can be read.
FILE_READ_EA | Extended attributes associated with the file can be read. This flag is irrelevant to device and intermediate drivers.
READ_CONTROL | The access control list (ACL) and ownership information associated with the file can be read.
FILE_WRITE_DATA | Data can be written to the file.
FILE_WRITE_ATTRIBUTES | FileAttributes flags can be written.
FILE_WRITE_EA | Extended attributes (EAs) associated with the file can be written. This flag is irrelevant to device and intermediate drivers.
FILE_APPEND_DATA | Data can be appended to the file.
WRITE_DAC | The discretionary access control list (DACL) associated with the file can be written.
WRITE_OWNER | Ownership information associated with the file can be written.
SYNCHRONIZE | The returned FileHandle can be waited on to synchronize with the completion of an I/O operation.
FILE_EXECUTE | Data can be read into memory from the file using system paging I/O. This flag is irrelevant to device and intermediate drivers.

Callers of IoCreateFile can specify one or a combination of the following, possibly ORed with additional compatible flags from the preceding DesiredAccess Flags list, for any file object that does not represent a directory file:
DesiredAccess to File Values | Maps to DesiredAccess Flags
GENERIC_READ | STANDARD_RIGHTS_READ, FILE_READ_DATA, FILE_READ_ATTRIBUTES, and FILE_READ_EA
GENERIC_WRITE | STANDARD_RIGHTS_WRITE, FILE_WRITE_DATA, FILE_WRITE_ATTRIBUTES, FILE_WRITE_EA, and FILE_APPEND_DATA
GENERIC_EXECUTE | STANDARD_RIGHTS_EXECUTE, SYNCHRONIZE, and FILE_EXECUTE. This value is irrelevant to device and intermediate drivers.

The STANDARD_RIGHTS_XXX are predefined system values used to enforce security on system objects.

To open or create a directory file, as also indicated with the CreateOptions parameter, callers of IoCreateFile can specify one or a combination of the following, possibly ORed with one or more compatible flags from the preceding DesiredAccess Flags list:
DesiredAccess to Directory Values | Meaning
FILE_LIST_DIRECTORY | Files in the directory can be listed.
FILE_TRAVERSE | The directory can be traversed: that is, it can be part of the pathname of a file.

The FILE_READ_DATA, FILE_WRITE_DATA, FILE_EXECUTE, and FILE_APPEND_DATA DesiredAccess flags are incompatible with creating or opening a directory file.

ObjectAttributes
Points to a structure already initialized with InitializeObjectAttributes. Members of this structure for a file object include the following:
Member Value
ULONG Length
Specifies the number of bytes of ObjectAttributes data supplied. This value must be at least sizeof(OBJECT_ATTRIBUTES).
PUNICODE_STRING ObjectName
Points to a buffered Unicode string naming the file to be created or opened. This value must be a fully qualified file specification or the name of a device object, unless it is the name of a file relative to the directory specified by RootDirectory. For example, \Device\Floppy1\myfile.dat or \??\B:\myfile.dat could be the fully qualified file specification, provided that the floppy driver and overlying file system are already loaded. (Note: \?? replaces \DosDevices as the name of the Win32 object namespace. \DosDevices will still work, but \?? is translated faster by the object manager.)
HANDLE RootDirectory
Optionally specifies a handle to a directory obtained by a preceding call to IoCreateFile. If this value is NULL, the ObjectName member must be a fully qualified file specification that includes the full path to the target file. If this value is nonNULL, the ObjectName member specifies a file name relative to this directory.
PSECURITY_DESCRIPTOR SecurityDescriptor
Optionally specifies a security descriptor to be applied to a file. ACLs specified by such a security descriptor are only applied to the file when it is created. If the value is NULL when a file is created, the ACL placed on the file is file-system-dependent; most file systems propagate some part of such an ACL from the parent directory file combined with the caller's default ACL. Device and intermediate drivers can set this member to NULL.
PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService
Specifies the access rights a server should be given to the client's security context. This value is non-NULL only when a connection to a protected server is established, allowing the caller to control which parts of the caller's security context are made available to the server and whether the server is allowed to impersonate the caller. Device and intermediate drivers usually set this member to NULL.
ULONG Attributes
Is a set of flags that controls the file object attributes. This value can be zero or OBJ_CASE_INSENSITIVE, which indicates that name-lookup code should ignore the case of ObjectName rather than performing an exact-match search. The value OBJ_INHERIT is irrelevant to device and intermediate drivers.

If the caller is not running in the system process context, it must set the OBJ_KERNEL_HANDLE attribute for ObjectAttributes.

IoStatusBlock
Points to a variable that receives the final completion status and information about the requested operation. On return from IoCreateFile, the Information member contains one of the following values:

FILE_CREATED
FILE_OPENED
FILE_OVERWRITTEN
FILE_SUPERSEDED
FILE_EXISTS
FILE_DOES_NOT_EXIST

AllocationSize
Optionally specifies the initial allocation size in bytes for the file. A nonzero value has no effect unless the file is being created, overwritten, or superseded.
FileAttributes
Explicitly specified attributes are applied only when the file is created, superseded, or, in some cases, overwritten. By default, this value is FILE_ATTRIBUTE_NORMAL, which can be overridden by an ORed combination of one or more FILE_ATTRIBUTE_xxxx flags, which are defined in wdm.h and ntddk.h. For a list of flags that can be used with IoCreateFile, see CreateFile in the Platform SDK documentation.
ShareAccess
Specifies the type of share access that the caller would like to the file, as zero, or as one or a combination of the following:
ShareAccess Flags | Meaning
FILE_SHARE_READ | The file can be opened for read access by other threads' calls to IoCreateFile.
FILE_SHARE_WRITE | The file can be opened for write access by other threads' calls to IoCreateFile.
FILE_SHARE_DELETE | The file can be opened for delete access by other threads' calls to IoCreateFile.

Device and intermediate drivers usually set ShareAccess to zero, which gives the caller exclusive access to the open file.

Disposition
Specifies what to do, depending on whether the file already exists, as one of the following:
Disposition Values | Meaning
FILE_SUPERSEDE | If the file already exists, replace it with the given file. If it does not, create the given file.
FILE_CREATE | If the file already exists, fail the request and do not create or open the given file. If it does not, create the given file.
FILE_OPEN | If the file already exists, open it instead of creating a new file. If it does not, fail the request and do not create a new file.
FILE_OPEN_IF | If the file already exists, open it. If it does not, create the given file.
FILE_OVERWRITE | If the file already exists, open it and overwrite it. If it does not, fail the request.
FILE_OVERWRITE_IF | If the file already exists, open it and overwrite it. If it does not, create the given file.

CreateOptions
Specifies the options to be applied when creating or opening the file, as a compatible combination of the following flags:
CreateOptions Flags | Meaning
FILE_DIRECTORY_FILE The file being created or opened is a directory file. With this flag, the Disposition parameter must be set to one of FILE_CREATE, FILE_OPEN, or FILE_OPEN_IF. With this flag, other compatible CreateOptions flags include only the following: FILE_SYNCHRONOUS_IO_ALERT, FILE_SYNCHRONOUS_IO
_NONALERT, FILE_WRITE_THROUGH, FILE_OPEN_FOR_BACKUP_INTENT, and FILE_OPEN_BY_FILE_ID.
FILE_NON_DIRECTORY_FILE | The file being opened must not be a directory file or this call will fail. The file object being opened can represent a data file, a logical, virtual, or physical device, or a volume.
FILE_WRITE_THROUGH System services, FSDs, and drivers that write data to the file must actually transfer the data into the file before any requested write operation is considered complete. This flag is automatically set if the CreateOptions flag FILE_NO_INTERMEDIATE
_BUFFERING is set.
FILE_SEQUENTIAL_ONLY | All accesses to the file will be sequential.
FILE_RANDOM_ACCESS | Accesses to the file can be random, so no sequential read-ahead operations should be performed on the file by FSDs or the system.
FILE_NO_INTERMEDIATE
_BUFFERING 		The file cannot be cached or buffered in a driver's internal buffers. This flag is incompatible with the DesiredAccess FILE_APPEND_DATA flag.
FILE_SYNCHRONOUS_IO_ALERT | All operations on the file are performed synchronously. Any wait on behalf of the caller is subject to premature termination from alerts. This flag also causes the I/O system to maintain the file position context. If this flag is set, the DesiredAccess SYNCHRONIZE flag also must be set.
FILE_SYNCHRONOUS_IO
_NONALERT 		All operations on the file are performed synchronously. Waits in the system to synchronize I/O queuing and completion are not subject to alerts. This flag also causes the I/O system to maintain the file position context. If this flag is set, the DesiredAccess SYNCHRONIZE flag also must be set.
FILE_CREATE_TREE
_CONNECTION 		Create a tree connection for this file in order to open it over the network. This flag is irrelevant to device and intermediate drivers.
FILE_COMPLETE_IF_OPLOCKED | Complete this operation immediately with an alternate success code if the target file is oplocked, rather than blocking the caller's thread. If the file is oplocked, another caller already has access to the file over the network. This flag is irrelevant to device and intermediate drivers.
FILE_NO_EA_KNOWLEDGE | If the extended attributes on an existing file being opened indicate that the caller must understand EAs to properly interpret the file, fail this request because the caller does not understand how to deal with EAs. Device and intermediate drivers can ignore this flag.
FILE_DELETE_ON_CLOSE | Delete the file when the last handle to it is passed to ZwClose.
FILE_OPEN_BY_FILE_ID | The file name contains the name of a device and a 64-bit ID to be used to open the file. This flag is irrelevant to device and intermediate drivers.
FILE_OPEN_FOR_BACKUP
_INTENT 		The file is being opened for backup intent, hence, the system should check for certain access rights and grant the caller the appropriate accesses to the file before checking the input DesiredAccess against the file's security descriptor. This flag is irrelevant to device and intermediate drivers.

EaBuffer
For device and intermediate drivers, this parameter must be a NULL pointer.
EaLength
For device and intermediate drivers, this parameter must be zero.
CreateFileType
Drivers must set this parameter to CreateFileTypeNone.
ExtraCreateParameters
Drivers must set this parameter to NULL.
Options
Specifies options to be used during the creation of the create request. These options can be from the following list:
Options Flags | Meaning
IO_NO_PARAMETER_CHECKING | Indicates that the parameters for this call should not be validated before attempting to issue the create request. Driver writers should use this flag with caution as certain invalid parameters can cause a system failure.
IO_FORCE_ACCESS_CHECK | Indicates that the I/O Manager must check the operation against the file's security descriptor.

Return Value

IoCreateFile either returns STATUS_SUCCESS or an appropriate error status. If it returns an error status, the caller can find additional information about the cause of the failure by checking the IoStatusBlock.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

The handle, obtained by IoCreateFile, can be used by subsequent calls to manipulate data within the file or the file object's state or attributes.

There are two alternate ways to specify the name of the file to be created or opened with IoCreateFile:

  1. As a fully qualified pathname, supplied in the ObjectName member of the input ObjectAttributes
  2. As pathname relative to the directory file represented by the handle in the RootDirectory member of the input ObjectAttributes

Certain DesiredAccess flags and combinations of flags have the following effects:

  • For a caller to synchronize an I/O completion by waiting on the returned FileHandle, the SYNCHRONIZE flag must be set. Otherwise, a caller that is a device or intermediate driver must synchronize an I/O completion by using an event object.
  • If only the FILE_APPEND_DATA and SYNCHRONIZE flags are set, the caller can write only to the end of the file, and any offset information on writes to the file is ignored. However, the file will automatically be extended as necessary for this type of write operation.
  • Setting the FILE_WRITE_DATA flag for a file also allows writes beyond the end of the file to occur. The file is automatically extended for this type of write, as well.
  • If only the FILE_EXECUTE and SYNCHRONIZE flags are set, the caller cannot directly read or write any data in the file using the returned FileHandle: that is, all operations on the file occur through the system pager in response to instruction and data accesses. Device and intermediate drivers should not set the FILE_EXECUTE flag in DesiredAccess.

The ShareAccess parameter determines whether separate threads can access the same file, possibly simultaneously. Provided that both file openers have the privilege to access a file in the specified manner, the file can be successfully opened and shared. If the original caller of IoCreateFile does not specify FILE_SHARE_READ, FILE_SHARE_WRITE, or FILE_SHARE_DELETE, no other open operations can be performed on the file: that is, the original caller is given exclusive access to the file.

In order for a shared file to be successfully opened, the requested DesiredAccess to the file must be compatible with both the DesiredAccess and ShareAccess specifications of all preceding opens that have not yet been released with ZwClose. That is, the DesiredAccess specified to IoCreateFile for a given file must not conflict with the accesses that other openers of the file have disallowed.

The Disposition value FILE_SUPERSEDE requires that the caller have DELETE access to a existing file object. If so, a successful call to IoCreateFile with FILE_SUPERSEDE on an existing file effectively deletes that file, and then recreates it. This implies that, if the file has already been opened by another thread, it opened the file by specifying a ShareAccess parameter with the FILE_SHARE_DELETE flag set. Note that this type of disposition is consistent with the POSIX style of overwriting files.

The Disposition values FILE_OVERWRITE_IF and FILE_SUPERSEDE are similar. If IoCreateFile is called with a existing file and either of these Disposition values, the file will be replaced.

Overwriting a file is semantically equivalent to a supersede operation, except for the following:

  • The caller must have write access to the file, rather than delete access. This implies that, if the file has already been opened by another thread, it opened the file with the FILE_SHARE_WRITE flag set in the input ShareAccess.
  • The specified file attributes are logically ORed with those already on the file. This implies that, if the file has already been opened by another thread, a subsequent caller of IoCreateFile cannot disable existing FileAttributes flags but can enable additional flags for the same file.

The CreateOptions FILE_DIRECTORY_FILE value specifies that the file to be created or opened is a directory file. When a directory file is created, the file system creates an appropriate structure on the disk to represent an empty directory for that particular file system's on-disk structure. If this option was specified and the given file to be opened is not a directory file, or if the caller specified an inconsistent CreateOptions or Disposition value, the call to IoCreateFile will fail.

The CreateOptions FILE_NO_INTERMEDIATE_BUFFERING flag prevents the file system from performing any intermediate buffering on behalf of the caller. Specifying this value places certain restrictions on the caller's parameters to the Zw..File routines, including the following:

  • Any optional ByteOffset passed to ZwReadFile or ZwWriteFile must be an integral of the sector size.
  • The Length passed to ZwReadFile or ZwWriteFile, must be an integral of the sector size. Note that specifying a read operation to a buffer whose length is exactly the sector size might result in a lesser number of significant bytes being transferred to that buffer if the end of the file was reached during the transfer.
  • Buffers must be aligned in accordance with the alignment requirement of the underlying device. This information can be obtained by calling IoCreateFile to get a handle for the file object that represents the physical device, and, then, calling ZwQueryInformationFile with that handle. For a list of the system FILE_XXX_ALIGNMENT values, see DEVICE_OBJECT.
  • Calls to ZwSetInformationFile with the FileInformationClass parameter set to FilePositionInformation must specify an offset that is an integral of the sector size.

The CreateOptions FILE_SYNCHRONOUS_IO_ALERT and FILE_SYNCHRONOUS_IO_NONALERT, which are mutually exclusive as their names suggest, specify that all I/O operations on the file are to be synchronous as long as they occur through the file object referred to by the returned FileHandle. All I/O on such a file is serialized across all threads using the returned handle. With either of these CreateOptions, the DesiredAccess SYNCHRONIZE flag must be set so that the I/O Manager will use the file object as a synchronization object. With either of these CreateOptions set, the I/O Manager maintains the "file position context" for the file object, an internal, current file position offset. This offset can be used in calls to ZwReadFile and ZwWriteFile. Its position also can be queried or set with ZwQueryInformationFile and ZwSetInformationFile.

Driver routines that run in a process context other than that of the system process must set the OBJ_KERNEL_HANDLE attribute for the ObjectAttributes parameter of ZwCreateFile. This restricts the use of the handle returned by ZwCreateFile to processes running only in kernel mode. Otherwise, the thread handle can be accessed by the process in whose context the driver is running. Drivers can call InitializeObjectAttributes to set the OBJ_KERNEL_HANDLE attribute as follows.

InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);

Callers of IoCreateFile must be running at IRQL PASSIVE_LEVEL.

See Also

ACCESS_MASK, ZwCreateFile


IoCreateNotificationEvent

IoCreateNotificationEvent creates or opens a named notification event used to notify one or more threads of execution that an event has occurred.

PKEVENT
  IoCreateNotificationEvent(
    IN PUNICODE_STRING  EventName,
    OUT PHANDLE  EventHandle
    );

Parameters

EventName
Points to a buffer containing a zero-terminated Unicode string that names the event.
EventHandle
Points to a location in which to return a handle for the event object. The handle includes bookkeeping information, such as a reference count and security context.

Return Value

IoCreateNotificationEvent returns a pointer to the created or opened event object or NULL if the event object could not be created or opened.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

IoCreateNotificationEvent creates and opens the event object if it does not already exist. IoCreateNotificationEvent sets the state of a new notification event to Signaled. If the event object already exists, IoCreateNotificationEvent just opens the event object.

When a notification event is set to the Signaled state it remains in that state until it is explicitly cleared.

Notification events, like synchronization events, are used to coordinate execution. Unlike a synchronization event, a notification event is not auto-resetting. Once a notification event is in the Signaled state, it remains in that state until it is explicitly reset (with a call to KeClearEvent or KeResetEvent).

To synchronize on a notification event:

  1. Open the notification event with IoCreateNotificationEvent. Identify the event with the EventName string.
  2. Wait for the event to be signaled by calling KeWaitForSingleObject with the PKEVENT returned by IoCreateNotificationEvent. More than one thread of execution can wait on a given notification event. To poll instead of stall, specify a Timeout of zero to KeWaitForSingleObject.
  3. Close the handle to the notification event with ZwClose when access to the event is no longer needed.

Sharing event objects between user mode and kernel mode requires care. The system creates user-mode event objects relative to the \\BasedNamedObjects object directory, and only those event objects are visible to user-mode programs. The Xxx user-mode event corresponds to the \\BasedNamedObjects\Xxx kernel-mode event. The preferred method to share event objects between user mode and kernel mode is for the user-mode program to create the event object and pass it to the driver through an IOCTL. The \\BasedNamedObjects object directory is not created until the Win32® system initializes. Therefore, drivers that are loaded at boot time cannot create event objects in their DriverEntry routines that are visible to user-mode programs.

Callers of IoCreateNotificationEvent must be running at IRQL PASSIVE_LEVEL.

See Also

IoCreateSynchronizationEvent, KeClearEvent, KeResetEvent, KeSetEvent, KeWaitForSingleObject, RtlInitUnicodeString, ZwClose


IoCreateSymbolicLink

IoCreateSymbolicLink sets up a symbolic link between a device object name and a user-visible name for the device.

NTSTATUS
  IoCreateSymbolicLink(
    IN PUNICODE_STRING  SymbolicLinkName,
    IN PUNICODE_STRING  DeviceName
    );

Parameters

SymbolicLinkName
Points to a buffered Unicode string that is the user-visible name.
DeviceName
Points to a buffered Unicode string that is the name of the driver-created device object.

Return Value

IoCreateSymbolicLink returns STATUS_SUCCESS if the symbolic link object was created.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

PnP drivers do not name device objects and therefore should not use this routine. Instead, a PnP driver should call IoRegisterDeviceInterface to set up a symbolic link.

Callers of IoCreateSymbolicLink must be running at IRQL PASSIVE_LEVEL.

See Also

IoRegisterDeviceInterface, IoAssignArcName, IoCreateUnprotectedSymbolicLink, IoDeleteSymbolicLink


IoCreateSynchronizationEvent

IoCreateSynchronizationEvent creates or opens a named synchronization event for use in serialization of access to hardware between two otherwise unrelated drivers.

PKEVENT
  IoCreateSynchronizationEvent(
    IN PUNICODE_STRING  EventName,
    OUT PHANDLE  EventHandle
    );

Parameters

EventName
Points to a buffer containing a zero-terminated Unicode string that names the event.
EventHandle
Points to a location in which to return a handle for the event object.

Return Value

IoCreateSynchronizationEvent returns a pointer to the created or opened event object or NULL if the event object could not be created or opened.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

The event object is created if it does not already exist. IoCreateSynchronizationEvent sets the state of a new synchronization event to Signaled. If the event object already exists, it is simply opened. The pair of drivers that use a synchronization event call KeWaitForSingleObject with the PKEVENT pointer returned by this routine.

When a synchronization event is set to the Signaled state, a single thread of execution that was waiting on the event is released, and the event is automatically reset to the Not-Signaled state.

To release the event, a driver calls ZwClose with the event handle.

Sharing event objects between user mode and kernel mode requires care. The system creates user-mode event objects relative to the \\BasedNamedObjects object directory, and only those event objects are visible to user-mode programs. The Xxx user-mode event corresponds to the \\BasedNamedObjects\Xxx kernel-mode event. The preferred method to share event objects between user mode and kernel mode is for the user-mode program to create the event object and pass it to the driver through an IOCTL. The \\BasedNamedObjects object directory is not created until the Win32® system initializes. Therefore, drivers that are loaded at boot time cannot create event objects in their DriverEntry routines that are visible to user-mode programs.

Callers of IoCreateSynchronizationEvent must be running at IRQL PASSIVE_LEVEL.

See Also

IoCreateNotificationEvent, KeWaitForSingleObject, RtlInitUnicodeString, ZwClose


IoCreateUnprotectedSymbolicLink

IoCreateUnprotectedSymbolicLink sets up an unprotected symbolic link between a device object name and a corresponding Win32®-visible name.

NTSTATUS
  IoCreateUnprotectedSymbolicLink(
    IN PUNICODE_STRING  SymbolicLinkName,
    IN PUNICODE_STRING  DeviceName
    );

Parameters

SymbolicLinkName
Supplies the symbolic link name as a Unicode string.
DeviceName
Supplies the name of the device object to which the symbolic link name refers.

Return Value

IoCreateUnprotectedSymbolicLink returns the final status of the operation.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

PnP drivers do not name device objects and therefore should not use this routine. Instead, a PnP driver should call IoRegisterDeviceInterface to set up a symbolic link.

IoCreateUnprotectedSymbolicLink can be used by drivers if the user needs to be able to manipulate the symbolic link. For example, the parallel and serial drivers create unprotected symbolic links for LPTx and COMx, so that users can manipulate and reassign them by using the MODE command.

In general, drivers should call this routine instead of IoCreateSymbolicLink if a protected subsystem lets end users change what a named device references as, for example, when using LPT1 to access a network printer.

Callers of IoCreateUnprotectedSymbolicLink must be running at IRQL PASSIVE_LEVEL.

See Also

IoRegisterDeviceInterface, IoAssignArcName, IoCreateSymbolicLink, IoDeleteSymbolicLink


IoCsqInitialize

The IoCsqInitialize routine initializes the driver's cancel-safe IRP queue dispatch table.

VOID
  IoCsqInitialize(
    PIO_CSQ  Csq,
    IN PIO_CSQ_INSERT_IRP  CsqInsertIrp,
    IN PIO_CSQ_REMOVE_IRP  CsqRemoveIrp,
    IN PIO_CSQ_PEEK_NEXT_IRP  CsqPeekNextIrp,
    IN PIO_CSQ_ACQUIRE_LOCK  CsqAcquireLock,
    IN PIO_CSQ_RELEASE_LOCK  CsqReleaseLock,
    IN PIO_CSQ_COMPLETE_CANCELED_IRP  CsqCompleteCanceledIrp
    );

Parameters

Csq
Pointer to the driver's dispatch table for cancel-safe IRP queues.
CsqInsertIrp
Pointer to a function with prototype
    VOID XxxCsqInsertIrp(PIO_CSQ Csq, PIRP Irp);

The system calls this function to insert the specified IRP in the driver's IRP queue.

CsqRemoveIrp
Pointer to a function with prototype
    VOID XxxCsqRemoveIrp(PIO_CSQ Csq, PIRP Irp);

The system calls this function to remove the specified IRP in the driver's IRP queue.

CsqPeekNextIrp
Pointer to a function with prototype
    PIRP XxxCsqPeekNextIrp(PIO_CSQ Csq, PIRP Irp, PVOID PeekContext);

The system uses this function to get a pointer to the next IRP matching PeekContext in the queue; or, if Irp is NULL, to get a pointer to the first matching IRP in the queue.

This function is called by IoCsqRemoveNextIrp, which passes the PeekContext value it receives from the caller. The meaning of PeekContext and when an IRP matches a given PeekContext is entirely defined by the driver.

CsqAcquireLock
Pointer to a function with prototype
    VOID XxxCsqAcquireLock(PIO_CSQ Csq, PKIRQL Irql);

The system calls this function to acquire the lock on the driver's IRP queue, before attempting to insert or remove an IRP from the queue. The system passes a pointer to a memory location where the function can return an IRQL. The same memory location is passed to the corresponding XxxCsqReleaseLock function.

CsqReleaseLock
Pointer to a function with prototype
    VOID XxxCsqReleaseLock(PIO_CSQ Csq, PKIRQL Irql);

The system calls this function to release the lock on the driver's IRP queue that it obtained by calling XxxCsqAcquireLock. The system calls this function with the same PKIRQL value that it calls the XxxCsqAcquireLock routine.

CsqCompleteCanceledIrp
Pointer to a function with prototype
    VOID XxxCsqCompleteCanceledIrp(PIO_CSQ Csq, PIRP Irp);

The system calls this function to signal to the driver to complete a canceled IRP.

Return Value

None

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

This routine is only available on Windows XP and later.

Drivers can use the IoCsqXxx routines to implement an IRP queue. By using these routines, drivers can make their queue cancel-safe — the system transparently handles IRP cancellation for the driver.

Drivers can use any internal implementation for the IRP queue. The system interacts with the driver's queue implementation solely through the set of dispatch routines provided by IoCsqInitialize.

The driver does not queue or dequeue IRPs directly. Instead, the driver calls the IoCsqInsertIrp, IoCsqRemoveIrp, and IoCsqRemoveNextIrp system routines. These routines, in turn, dispatch the specifics of queuing or dequeuing the IRP to the routines provided by IoCsqInitialize.

Drivers should implement the queue routines as follows.

Csq Function | Implementation
XxxCsqInsertIrp | Insert the specified IRP in the queue.
XxxCsqRemoveIrp | Remove the specified IRP from the queue.
XxxCsqPeekNextIrp | This routine should allow the system to loop through the IRPs with matching PeekContext in the queue. Irp = XxxCsqPeekNextIrp(Csq, NULL, PeekContext) should return the first matching entry in the queue, and XxxCsqPeekNextIrp(Csq, Irp, PeekContext) should return the next matching entry after the given IRP in the queue. The meaning of PeekContext and of when an IRP matches a PeekContext value is entirely driver dependent.
XxxCsqAcquireLock | This routine should lock the queue so that no other thread can access it. Drivers can use any locking mechanism to lock the queue. If the driver uses the KeAcquireSpinLock routine, the driver can use the memory location pointed to by the routine's Irql parameter to store the IRQL. Otherwise, drivers can ignore that parameter.
XxxCsqReleaseLock | This routine should unlock the queue created by XxxCsqAcquireLock. If the driver used a spin lock and returned the IRQL value in the Irql parameter of XxxCsqAcquireLock, the system will pass that value in the PIRQL parameter of XxxCsqReleaseLock. The driver can use the IRQL to unlock the spin lock by calling KeReleaseSpinLock. Otherwise, drivers can ignore the Irql parameter.
XxxCsqCompleteCanceledIrp | This routine should complete a canceled IRP. Normally, drivers can just call IoCompleteRequest(Irp, STATUS_CANCELLED). Drivers do not need to dequeue the IRP — the system automatically calls the queue's XxxCsqRemoveIrp before calling XxxCsqCompleteCanceledIrp.

See Cancel-Safe IRP Queues for an overview of how to use cancel-safe IRP queues.

The IoCsqXxx routines use the DriverContext[3] member of the IRP to hold IRP context information. Drivers that use these routines must leave that member unused.

See Also

IO_CSQ, IoCsqInsertIrp, IoCsqRemoveIrp, IoCsqRemoveNextIrp


IoCsqInsertIrp

The IoCsqInsertIrp routine inserts an IRP in the driver's cancel-safe IRP queue.

VOID
  IoCsqInsertIrp(
    IN  PIO_CSQ  Csq,
    IN  PIRP  Irp,
    IN  PIO_CSQ_IRP_CONTEXT  Context
    );

Parameters

Csq
Pointer to the driver's dispatch table for cancel-safe IRP queues. The dispatch table must be initialized by IoCsqInitialize.
Irp
Pointer to the IRP to be queued.
Context
Pointer to a memory location that the routine uses to return IRP context information. Drivers can use this information to identify a specific IRP in the queue so that it can be removed by calling IoCsqRemoveIrp.

Drivers should treat the data returned in this parameter as opaque. If the driver is not required to remove particular IRPs from the queue, this parameter can be NULL.

Return Value

None

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

This routine is only available on Windows XP and later.

IoCsqInsertIrp inserts the specified IRP into a driver's cancel-safe IRP queue.

Drivers can use the IoCsqXxx routines to implement an IRP queue. By using these routines, drivers can make their queue cancel-safe — the system transparently handles IRP cancellation for the driver.

A cancel-safe IRP queue is initialized by IoCsqInitialize. The IoCsqInsertIrp routine uses the functions provided in the queue's dispatch table to lock the queue and insert the IRP. The insert operation itself is performed by the queue's XxxCsqInsertIrp routine.

See IoCsqInitialize for details on how to create a cancel-safe IRP queue. Use IoCsqRemoveIrp to remove a particular IRP from the queue, or IoCsqRemoveNextIrp to remove the next available IRP.

See Also

IO_CSQ, IO_CSQ_IRP_CONTEXT, IoCsqInitialize, IoCsqRemoveIrp, IoCsqRemoveNextIrp


IoCsqRemoveIrp

The IoCsqRemoveIrp routine removes a particular IRP from the queue.

PIRP
  IoCsqRemoveIrp(
    IN  PIO_CSQ  Csq,
    IN  PIO_CSQ_IRP_CONTEXT  Context
    );

Parameters

Csq
Pointer to the driver's dispatch table for cancel-safe IRP queues. The dispatch table must be initialized by IoCsqInitialize.
Context
Pointer to the IRP context information that identifies a particular IRP. The IRP context information is initialized by IoCsqInsertIrp when the IRP is first inserted in the queue.

Return Value

Pointer to the IRP removed from the queue, or NULL if that IRP has been canceled.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

This routine is only available on Windows XP and later.

IoCsqRemoveIrp removes a particular IRP from the driver's cancel-safe queue. The routine can only be used to delete an IRP that has an IRP context associated with it when the IRP is inserted by IoCsqInsertIrp.

Drivers can use the IoCsqXxx routines to implement an IRP queue. By using these routines, drivers can make their queue cancel-safe — the system transparently handles IRP cancellation for the driver.

A cancel-safe IRP queue is initialized by IoCsqInitialize. The IoCsqRemoveIrp routine uses the functions provided in the queue's dispatch table to lock the queue and remove the IRP. The remove operation itself is performed by the queue's XxxCsqRemoveIrp routine.

See IoCsqInitialize for details on how to create a cancel-safe IRP queue. Use the IoCsqRemoveNextIrp routine to remove the next IRP in the queue.

See Also

IO_CSQ, IO_CSQ_IRP_CONTEXT, IoCsqInitialize, IoCsqInsertIrp, IoCsqRemoveNextIrp


IoCsqRemoveNextIrp

The IoCsqRemoveNextIrp routine removes the next matching IRP in the queue.

PIRP
  IoCsqRemoveNextIrp(
    IN PIO_CSQ  Csq,
    IN PVOID  PeekContext
    );

Parameters

Csq
Pointer to the driver's dispatch table for cancel-safe IRP queues. The dispatch table must be initialized by IoCsqInitialize.
PeekContext
Specifies the driver-specific information that identifies the matching IRP.

Return Value

Returns a pointer to the next matching IRP in the queue, or NULL if no more IRPs are available. The routine only returns IRPs that have not yet been canceled.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

This routine is only available on Windows XP and later.

IoCsqRemoveNextIrp removes the next matching IRP from the driver's cancel-safe IRP queue.

Drivers can use the IoCsqXxx routines to implement an IRP queue. By using these routines, drivers can make their queue cancel-safe — the system transparently handles IRP cancellation for the driver.

A cancel-safe IRP queue is initialized by IoCsqInitialize. The IoCsqRemoveNextIrp routine uses the functions provided in the queue's dispatch table to lock the queue and remove the next matching IRP. The remove operation itself is performed by the queue's XxxCsqRemoveIrp routine.

The routine uses the queue's XxxCsqPeekNextIrp to scan the queue for matching IRPs. The PeekContext parameter is passed to XxxCsqPeekNextIrp to loop through matching IRPs. The meaning of PeekContext and the criteria for an IRP to match a given PeekContext is entirely driver-dependent.

See IoCsqInitialize for details on how to create a cancel-safe IRP queue. Use the IoCsqRemoveIrp routine to remove a particular IRP.

See Also

IO_CSQ, IoCsqInitialize, IoCsqInsertIrp, IoCsqRemoveIrp


IoDeassignArcName

IoDeassignArcName removes a symbolic link between the ARC name for a device and the named device object.

VOID
  IoDeassignArcName(
    IN PUNICODE_STRING  ArcName
    );

Parameters

ArcName
Points to a buffered Unicode string that is the ARC name.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

IoDeassignArcName is generally called if the driver is deleting the device object, for example, when the driver is unloading.

Callers of IoDeassignArcName must be running at IRQL PASSIVE_LEVEL.

See Also

IoAssignArcName


IoDeleteController

IoDeleteController removes a given controller object from the system, for example, when the driver that created it is being unloaded.

VOID
  IoDeleteController(
    IN PCONTROLLER_OBJECT  ControllerObject
    );

Parameters

ControllerObject
Points to the controller object to be released.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

IoDeleteController deallocates the memory for the controller object, including the controller extension.

This routine must be called when a driver that created a controller object is being unloaded or when the driver encounters a fatal error during device start-up, such as being unable to properly initialize a physical device.

A driver must release certain resources for which the driver supplied storage in its controller extension before it calls IoDeleteController. For example, if the driver stores the pointer to its interrupt object(s) in the controller extension, it must call IoDisconnectInterrupt before IoDeleteController.

Callers of IoDeleteController must be running at IRQL PASSIVE_LEVEL.

See Also

IoCreateController, IoDisconnectInterrupt


IoDeleteDevice

IoDeleteDevice removes a device object from the system, for example, when the underlying device is removed from the system.

VOID
  IoDeleteDevice(
    IN PDEVICE_OBJECT  DeviceObject
    );

Parameters

DeviceObject
Points to the device object to be deleted.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

When handling a PnP IRP_MN_REMOVE_DEVICE request, a PnP driver calls IoDeleteDevice to delete any associated device objects. See Handling an IRP_MN_REMOVE_DEVICE Request for details.

A legacy driver should call this routine when it is being unloaded or when its DriverEntry routine encounters a fatal initialization error, such as being unable to properly initialize a physical device. This routine also is called when a driver reconfigures its devices dynamically. For example, a disk driver called to repartition a disk would call IoDeleteDevice to tear down the device objects representing partitions to be replaced.

A driver must release certain resources for which the driver supplied storage in its device extension before it calls IoDeleteDevice. For example, if the driver stores the pointer to its interrupt object(s) in the device extension, it must call IoDisconnectInterrupt before calling IoDeleteDevice.

A driver can call IoDeleteDevice only once for a given device object.

When a driver calls IoDeleteDevice, the I/O Manager deletes the target device object if there are no outstanding references to it. However, if any outstanding references remain, the I/O Manager marks the device object as "delete pending" and deletes the device object when the references are released.

Callers of IoDeleteDevice must be running at IRQL PASSIVE_LEVEL.

See Also

IoCreateDevice, IoDisconnectInterrupt


IoDeleteSymbolicLink

IoDeleteSymbolicLink removes a symbolic link from the system.

NTSTATUS
  IoDeleteSymbolicLink(
    IN PUNICODE_STRING  SymbolicLinkName
    );

Parameters

SymbolicLinkName
Points to a buffered Unicode string that is the user-visible name for the symbolic link.

Return Value

IoDeleteSymbolicLink returns STATUS_SUCCESS if the symbolic link object is deleted.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Callers of IoDeleteSymbolicLink must be running at IRQL PASSIVE_LEVEL.

See Also

IoCreateSymbolicLink, IoCreateUnprotectedSymbolicLink, IoDeassignArcName


IoDetachDevice

IoDetachDevice releases an attachment between the caller's device object and a lower driver's device object.

VOID
  IoDetachDevice(
    IN OUT PDEVICE_OBJECT  TargetDevice
    );

Parameters

TargetDevice
Points to the lower driver's device object. The caller previously called IoAttachDevice or IoAttachDeviceToDeviceStack successfully to get this pointer.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

IoDetachDevice decrements the reference count of the TargetDevice object. If the reference count goes to zero and the lower driver has been marked for an unload operation, the lower driver is unloaded.

Callers of IoDetachDevice must be running at IRQL PASSIVE_LEVEL.

See Also

IoAttachDevice , IoAttachDeviceToDeviceStack


IoDisconnectInterrupt

IoDisconnectInterrupt releases a device driver's set of interrupt object(s) when the device is paused or removed, or when the driver is being unloaded.

VOID
  IoDisconnectInterrupt(
    IN PKINTERRUPT  InterruptObject
    );

Parameters

InterruptObject
Specifies the pointer returned by IoConnectInterrupt.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

A driver should disable interrupts from its device before it calls IoDisconnectInterrupt.

If the driver stored the pointer to its interrupt object(s) in the device extension of its device object or in the controller extension of its controller object, it must call IoDisconnectInterrupt before it calls IoDeleteDevice or IoDeleteController.

Callers of IoDisconnectInterrupt must be running at IRQL PASSIVE_LEVEL.

See Also

IoConnectInterrupt, IoDeleteController, IoDeleteDevice


IoFlushAdapterBuffers

IoFlushAdapterBuffers is obsolete and exported only to support existing drivers. See FlushAdapterBuffers instead.

BOOLEAN
  IoFlushAdapterBuffers(
    IN PADAPTER_OBJECT  AdapterObject,
    IN PMDL  Mdl,
    IN PVOID  MapRegisterBase,
    IN PVOID  CurrentVa,
    IN ULONG  Length,
    IN BOOLEAN  WriteToDevice
    );


IoFreeAdapterChannel

IoFreeAdapterChannel is obsolete and exported only to support existing drivers. See FreeAdapterChannel instead.

VOID
  IoFreeAdapterChannel(
    IN PADAPTER_OBJECT  AdapterObject
    );


IoFreeController

IoFreeController releases a previously allocated controller object when the driver has completed an I/O request.

VOID
  IoFreeController(
    IN PCONTROLLER_OBJECT  ControllerObject
    );

Parameters

ControllerObject
Points to the driver's controller object, which was allocated for the current I/O operation on a particular device by calling IoAllocateController.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

The connection between the current target device object and the controller object is released only if no requests are currently queued to the same device. Otherwise, the driver's ControllerControl routine is called with the next IRP bound through the device controller to the target device.

Callers of IoFreeController must be running at IRQL DISPATCH_LEVEL.

See Also

IoAllocateController, IoCreateController, IoDeleteController


IoFreeErrorLogEntry

IoFreeErrorLogEntry frees an unused error log entry.

VOID
IoFreeErrorLogEntry(
    PVOID  ElEntry
    );

Parameters

ElEntry
Pointer to an error log packet allocated by IoAllocateErrorLogEntry.

Headers

Declared in ntddk.h and wdm.h. Include ntddk.h or wdm.h.

Comments

This routine is available on Windows XP and later.

Drivers use IoFreeErrorLogEntry to free an error log entry allocated by IoAllocateErrorLogEntry. IoWriteErrorLogEntry also frees any error log entries passed to it, so drivers must not call both on the same log entry.

See Also

IoAllocateErrorLogEntry, IoWriteErrorLogEntry


IoFreeIrp

IoFreeIrp releases a caller-allocated IRP from the caller's IoCompletion routine.

VOID
  IoFreeIrp(
    IN PIRP  Irp
    );

Parameters

Irp
Points to the IRP that is to be released.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

This routine is the reciprocal to IoAllocateIrp or IoBuildAsynchronousFsdRequest. The released IRP must have been allocated by the caller.

This routine also releases an IRP allocated with IoMakeAssociatedIrp in which the caller set up its IoCompletion routine that returns STATUS_MORE_PROCESSING_REQUIRED for the associated IRP.

Callers of IoFreeIrp must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoAllocateIrp, IoBuildAsynchronousFsdRequest, IoMakeAssociatedIrp, IoSetCompletionRoutine


IoFreeMapRegisters

IoFreeMapRegisters is obsolete and exported only to support existing drivers. See FreeMapRegisters instead.

VOID
  IoFreeMapRegisters(
    IN PADAPTER_OBJECT  AdapterObject,
    IN PVOID  MapRegisterBase,
    IN ULONG  NumberOfMapRegisters
    );


IoFreeMdl

IoFreeMdl releases a caller-allocated MDL.

VOID
  IoFreeMdl(
    IN PMDL  Mdl
    );

Parameters

Mdl
Points to the MDL to be released.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

If a driver allocates an MDL to describe a buffer, it must explicitly release the MDL when operations on the buffer are done.

Callers of IoFreeMdl must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoAllocateMdl, IoBuildPartialMdl


IoFreeWorkItem

IoFreeWorkItem frees the specified work item.

VOID
  IoFreeWorkItem(
    IN PIO_WORKITEM  pIOWorkItem
    );

Parameters

pIOWorkItem
Pointer to a private IO_WORKITEM structure that was returned by a previous call to IoAllocateWorkItem.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Drivers should not make any assumptions about the format of the IO_WORKITEM structure nor should they attempt to access information that is contained in this private structure.

See Also

IoAllocateWorkItem, IoQueueWorkItem


IoGetAttachedDeviceReference

IoGetAttachedDeviceReference returns a pointer to the highest level device object in a driver stack and increments the reference count on that object.

PDEVICE_OBJECT
  IoGetAttachedDeviceReference(
    IN PDEVICE_OBJECT  DeviceObject
    );

Parameters

DeviceObject
Points to the device object for which the topmost attached device object is retrieved.

Return Value

IoGetAttachedDeviceReference returns a pointer to the highest level device object in a stack of attached device objects after incrementing the reference count on the object.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

If the device object at DeviceObject has no device objects attached to it, DeviceObject and the returned pointer are equal.

Device driver writers must ensure that when they have completed all operations that required them to make this call, that they call ObDereferenceObject with the device object pointer returned by this routine. Failure to do so will prevent the system from freeing or deleting the device object because of an outstanding reference count.

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL.

See Also

ObDereferenceObject


IoGetBootDiskInformation

IoGetBootDiskInformation returns information describing the boot and system disks.

NTSTATUS
  IoGetBootDiskInformation(
    IN OUT PBOOTDISK_INFORMATION  BootDiskInformation,
    IN ULONG  Size
    );

Parameters

BootDiskInformation
Pointer to a caller-allocated buffer that the routine uses to return information on the boot and system disks. The routine fills this buffer in with either a BOOTDISK_INFORMATION or a BOOTDISK_INFORMATION_EX structure.
Size
Specifies the size, in bytes, of the buffer specified by BootDiskInformation. Should be either sizeof(BOOTDISK_INFORMATION) or sizeof(BOOTDISK_INFORMATION_EX).

Return Value

IoGetBootDiskInformation returns one of the following status values:

STATUS_SUCCESS
The routine successfully returned the requested information in the buffer specified by BootDiskInformation.
STATUS_INVALID_PARAMETER
The value of Size is less than the size, in bytes, of a BOOTDISK_INFORMATION structure.
STATUS_TOO_LATE
The driver called the routine after the system has already booted. Only boot and system drivers can call IoGetBootDiskInformation, and then only in their DriverEntry or AddDevice routines.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

IoGetBootDiskInformation can only be called by boot or system drivers. Such a driver can call IoGetBootDiskInformation in their DriverEntry or AddDevice routines.

On Windows XP and later, if the Size parameter is sizeof(BOOTDISK_INFORMATION_EX) or larger, the routine returns a BOOTDISK_INFORMATION_EX structure in the BootDiskInformation buffer. Otherwise, if Size is at least sizeof(BOOTDISK_INFORMATION), the routine returns a BOOTDISK_INFORMATION structure.

On Windows 2000, the routine only returns the BOOTDISK_INFORMATION structure.

See Also

BOOTDISK_INFORMATION, BOOTDISK_INFORMATION_EX


IoGetConfigurationInformation

IoGetConfigurationInformation returns a pointer to the I/O Manager's global configuration information structure, which contains the current values for how many physical disk, floppy, CD-ROM, tape, SCSI HBA, serial, and parallel devices have device objects created to represent them by drivers as they are loaded.

PCONFIGURATION_INFORMATION
  IoGetConfigurationInformation(
    VOID
    );

Return Value

IoGetConfigurationInformation returns a pointer to the configuration information structure. This structure is defined as follows:

typedef struct _CONFIGURATIONAL_INFORMATION{
    //
    // Each field indicates the total number of physical
    // devices of a particular type in the machine. The value
    // should be used by the driver to determine the digit
    // suffix for device object names. This field must be
    // updated as the driver finds new devices of its own.
    //
    ULONG DiskCount;            // Count of hard disks so far.
    ULONG FloppyCount;          // Count of floppy drives so far.
    ULONG CDRomCount;           // Count of CD-ROM drives so far.
    ULONG TapeCount;            // Count of tape drives so far.
    ULONG ScsiPortCount;        // Count of HBAs so far.
    ULONG SerialCount;          // Count of serial ports so far.
    ULONG ParallelCount;        // Count of parallel ports so far.
    //
    // The next two fields indicate ownership of
    // either of the two I/O address spaces
    // that are used by WD1003-compatible disk controllers.
    //
    BOOLEAN AtDiskPrimaryAddressClaimed;       //0x1F0-0x1FF
    BOOLEAN AtDiskSecondaryAddressClaimed;     //0x170-0x17F
} CONFIGURATION_INFORMATION,*PCONFIGURATION_INFORMATION

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

Certain types of device drivers can use the configuration information structure's values to construct device object names with appropriate digit suffixes when each driver creates its device objects. Note that the digit suffix for device object names is a zero-based count, while the counts maintained in the configuration information structure represent the number of device objects of a particular type already created. That is, the configuration information counts are one-based.

Any driver that calls IoGetConfigurationInformation must increment the count for its kind of device in this structure when it creates a device object to represent a physical device.

The system-supplied SCSI port driver supplies the count of SCSI HBAs present in the machine. SCSI class drivers can read this value to determine how many HBA-specific miniport drivers might control a SCSI bus with an attached device of the class driver's type.

The configuration information structure also contains a value indicating whether an already loaded driver has claimed either of the "AT" disk I/O address ranges.

Callers of IoGetConfigurationInformation must be running at IRQL PASSIVE_LEVEL.

See Also

HalAssignSlotResources, HalGetBusData, HalGetBusDataByOffset, IoAssignResources, IoQueryDeviceDescription, IoReportResourceUsage


IoGetCurrentIrpStackLocation

IoGetCurrentIrpStackLocation returns a pointer to the caller's stack location in the given IRP.

PIO_STACK_LOCATION
  IoGetCurrentIrpStackLocation(
    IN PIRP  Irp
    );

Parameters

Irp
Points to the IRP.

Return Value

The routine returns a pointer to the I/O stack location for the driver.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Every driver must call IoGetCurrentIrpStackLocation with each IRP it is sent in order to get any parameters for the current request. Unless a driver supplies a Dispatch routine for each IRP_MJ_XXX that driver handles, the driver also must check its I/O stack location in the IRP to determine what operation is being requested.

Intermediate and highest-level drivers also call IoGetCurrentIrpStackLocation so that they can copy pertinent data from their own stack location into that of the next-lower driver whenever they pass a request on to lower drivers.

See Also

IO_STACK_LOCATION, IoCallDriver, IoGetNextIrpStackLocation, IoSetNextIrpStackLocation


IoGetCurrentProcess

PEPROCESS
  IoGetCurrentProcess(
    );

Return Value

IoGetCurrentProcess returns a pointer to the current process.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

In general, highest-level drivers, particularly file systems, are most likely to call this routine. An intermediate or underlying device driver seldom is called in the context of a thread that originates the current I/O request that the driver is processing, so it cannot get access to such a thread's process space.

Callers of IoGetCurrentProcess must be running at IRQL PASSIVE_LEVEL.

See Also

PsGetCurrentThread


IoGetDeviceInterfaceAlias

IoGetDeviceInterfaceAlias returns the alias device interface of the specified device interface instance, if the alias exists.

NTSTATUS
  IoGetDeviceInterfaceAlias(
    IN PUNICODE_STRING  SymbolicLinkName,
    IN CONST GUID  *AliasInterfaceClassGuid,
    OUT PUNICODE_STRING  AliasSymbolicLinkName
    );

Parameters

SymbolicLinkName
Points to the name of the device interface instance for which to retrieve an alias. The caller typically received this string from a call to IoGetDeviceInterfaces or in a PnP notification structure.
AliasInterfaceClassGuid
Points to a GUID specifying the interface class of the alias to retrieve.
AliasSymbolicLinkName
Specifies a pointer to a NULL Unicode string. On successful return, AliasSymbolicLinkName.Buffer points to a string containing the name of the alias. The caller must free the unicode string with RtlFreeUnicodeString when it is no longer needed.

Return Value

IoGetDeviceInterfaceAlias returns STATUS_SUCCESS if the call was successful. Possible error return values include:

Error Status | Description
STATUS_OBJECT_NAME_NOT_FOUND | Possibly indicates that there is no alias of the specified interface class.
STATUS_OBJECT_PATH_NOT_FOUND | Possibly indicates that there is no alias of the specified interface class.
STATUS_INVALID_HANDLE | Possibly indicates an invalid SymbolicLinkName or an invalid AliasClassGuid.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Device interfaces are considered aliases if they are exposed by the same underlying device and have identical interface reference strings, but are of different interface classes.

The SymbolicLinkName parameter specifies a device interface instance for a particular device, belonging to a particular interface class, with a particular reference string. IoGetDeviceInterfaceAlias returns another device interface instance for the same device and reference string, but of a different interface class, if it exists.

For example, the function driver for a fault-tolerant volume could register and set two device interfaces, one of the fault-tolerant-volume interface class and one of the volume interface class. Another driver could call IoGetDeviceInterfaceAlias with the symbolic link for one of the interfaces and ask whether the other interface exists by specifying its interface class.

Two device interfaces with NULL reference strings are aliases if they are exposed by the same underlying device and have different interface class GUIDs.

Callers of IoGetDeviceInterfaceAlias must be running at IRQL PASSIVE_LEVEL in the context of a system thread.

See Also

IoRegisterDeviceInterface, RtlFreeUnicodeString


IoGetDeviceInterfaces

IoGetDeviceInterfaces returns a list of device interface instances of a particular device interface class (such as all devices on the system that support a HID interface).

NTSTATUS
  IoGetDeviceInterfaces(
    IN CONST GUID  *InterfaceClassGuid,
    IN PDEVICE_OBJECT  PhysicalDeviceObject  OPTIONAL,
    IN ULONG  Flags,
    OUT PWSTR  *SymbolicLinkList
    );

Parameters

InterfaceClassGuid
Points to a class GUID specifying the device interface class. The GUIDs for a class should be in a device-specific header file.
PhysicalDeviceObject
Points to an optional PDO that narrows the search to only the device interface instances of the device represented by the PDO.
Flags
Specifies flags that modify the search for device interfaces.
Flag | Meaning
DEVICE_INTERFACE_INCLUDE_NONACTIVE | Return disabled device interface instances in addition to enabled interface instances.

When searching for a device that supports a particular interface class, the caller requires an enabled interface instance and thus does not set the DEVICE_INTERFACE_INCLUDE_NONACTIVE flag.

A driver typically sets the DEVICE_INTERFACE_INCLUDE_NONACTIVE flag to locate disabled interface instances that the driver must enable. For example, the class installer for the device might have been directed by the INF file to register one or more interface instances for the device. The interface instances would be registered but are not usable until they are enabled by the driver (using IoSetDeviceInterfaceState). To narrow the list of interface instances returned to only those exposed by a given device, a driver can specify a PhysicalDeviceObject.

SymbolicLinkList
Points to a character pointer that is filled in on successful return with a list of Unicode strings identifying the device interface instances that match the search criteria. The newly allocated buffer contains a list of symbolic link names. Each unicode string in the list is null-terminated; the end of the whole list is marked by an additional NULL. The caller is responsible for freeing the buffer (ExFreePool) when it is no longer needed.

If no device interface instances match the search criteria, this routine returns STATUS_SUCCESS and the string contains a single NULL character.

Return Value

IoGetDeviceInterfaces returns STATUS_SUCCESS if the call was successful. Possible error return values include:

Error Status | Description
STATUS_INVALID_DEVICE_REQUEST | Possibly indicates that PhysicalDeviceObject was not a valid PDO pointer.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

IoGetDeviceInterfaces returns a list of device interface instances that match the search criteria. A kernel-mode component typically calls this routine to get a list of all enabled device interface instances of a particular device interface class. Such a component can get a pointer to the file object and/or the device object for an interface using IoGetDeviceObjectPointer or ZwCreateFile. The device object pointer returned by IoGetDeviceObjectPointer points to the top of the device stack for the device and can be used in calls to IoCallDriver.

If there is a default interface for the requested device interface class, it is listed first in SymbolicLinkList. Default interfaces can be set by user mode, but not by kernel mode.

The format of a symbolic link name is opaque; the caller should not attempt to parse a symbolic link name.

Symbolic links for device interface instances can be used across system boots.

To be notified when additional device interface instances of a particular class are enabled on the system, register for notification of a device class change with IoRegisterPlugPlayNotification.

Callers of IoGetDeviceInterfaces must be running at IRQL PASSIVE_LEVEL in the context of a system thread.

See Also

ExFreePool, IoGetDeviceObjectPointer, IoRegisterDeviceInterface, IoRegisterPlugPlayNotification, IoSetDeviceInterfaceState, ZwCreateFile


IoGetDeviceObjectPointer

IoGetDeviceObjectPointer returns a pointer to a named device object and corresponding file object, if the requested access to the objects can be granted.

NTSTATUS
  IoGetDeviceObjectPointer(
    IN PUNICODE_STRING  ObjectName,
    IN ACCESS_MASK  DesiredAccess,
    OUT PFILE_OBJECT  *FileObject,
    OUT PDEVICE_OBJECT  *DeviceObject
    );

Parameters

ObjectName
Points to a buffer containing a Unicode string that is the name of the device object.
DesiredAccess
Specifies the ACCESS_MASK value that represents the desired access. Usually DesiredAccess is FILE_READ_DATA. Infrequently, the FILE_WRITE_DATA, or FILE_ALL_ACCESS access rights are specified.
FileObject
Points to the file object that represents the corresponding device object to user-mode code if the call is successful.
DeviceObject
Points to the device object that represents the named logical, virtual, or physical device if the call is successful.

Return Value

IoGetDeviceObjectPointer can return one of the following NTSTATUS values:

STATUS_SUCCESS
STATUS_OBJECT_TYPE_MISMATCH
STATUS_INVALID_PARAMETER
STATUS_PRIVILEGE_NOT_HELD
STATUS_INSUFFICIENT_RESOURCES
STATUS_OBJECT_NAME_INVALID

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

IoGetDeviceObjectPointer establishes a "connection" between the caller and the next-lower-level driver. A successful caller can use the returned device object pointer to initialize its own device objects. It can also be used as as an argument to IoAttachDeviceToDeviceStack, IoCallDriver, and any routine that creates IRPs for lower drivers. The returned pointer is a required argument to IoCallDriver.

This routine also returns a pointer to the corresponding file object. When unloading, a driver can dereference the file object as a means of indirectly dereferencing the device object. To do so, the driver calls ObDereferenceObject from its Unload routine, passing the file object pointer returned by IoGetDeviceObjectPointer. Failure to dereference the device object in a driver's Unload routine prevents the next-lower driver from being unloaded. However, drivers that close the file object before the unload process must take out an extra reference on the device object before dereferencing the file object. Otherwise, dereferencing the file object can lead to a premature deletion of the device object.

To get a pointer to the highest-level driver in the file system driver stack, a driver must ensure that the file system is mounted; if it is not, this routine traverses the storage device stack. To ensure that the file system is mounted on the storage device, the driver must specify an appropriate access mask, such as FILE_READ_DATA or FILE_WRITE_ATTRIBUTES, in the DesiredAccess parameter. Specifying FILE_READ_ATTRIBUTES does not cause the file system to be mounted.

After any higher-level driver has chained itself over another driver by successfully calling this routine, the higher-level driver must set the StackSize field in its device object to that of the next-lower-level driver's device object plus one.

Callers of IoGetDeviceObjectPointer must be running at IRQL = PASSIVE_LEVEL.

See Also

ACCESS_MASK, DEVICE_OBJECT, IoAllocateIrp, IoAttachDevice, IoAttachDeviceToDeviceStack, ObDereferenceObject, ObReferenceObjectByPointer


IoGetDeviceProperty

IoGetDeviceProperty retrieves information about a device such as configuration information and the name of its PDO.

NTSTATUS
  IoGetDeviceProperty(
    IN PDEVICE_OBJECT  DeviceObject,
    IN DEVICE_REGISTRY_PROPERTY  DeviceProperty,
    IN ULONG  BufferLength,
    OUT PVOID  PropertyBuffer,
    OUT PULONG  ResultLength
    );

Parameters

DeviceObject
Points to the physical device object (PDO) for the device being queried.
DeviceProperty
Specifies the device property being requested. Must be one of the following:
DevicePropertyAddress
Requests the address of the device on the bus. PropertyBuffer points to a ULONG.

The interpretation of this address is bus-specific. The caller of this routine should call the routine again to request the DevicePropertyBusTypeGuid, or possibly the DevicePropertyLegacyBusType, so it can interpret the address. An address value of 0xFFFFFFFF indicates that the underlying bus driver did not supply a bus address for the device.

DevicePropertyBootConfiguration
Requests the hardware resources assigned to the device by the firmware, in raw form. PropertyBuffer points to a CM_RESOURCE_LIST structure.
DevicePropertyBootConfigurationTranslated
The hardware resources assigned to the device by the firmware, in translated form. PropertyBuffer points to a CM_RESOURCE_LIST structure.
DevicePropertyBusNumber
Requests the legacy bus number of the bus the device is connected to. PropertyBuffer points to a ULONG.
DevicePropertyBusTypeGuid
Requests the GUID for the bus that the device is connected to. The system-defined bus type GUIDs are listed in wdmguid.h. PropertyBuffer points to a GUID, which is a 16-byte structure that contains the GUID in binary form.
DevicePropertyClassGuid
Requests the GUID for the device's setup class. PropertyBuffer points to a NUL-terminated array of WCHAR. This routine returns the GUID in a string format as follows, where each "c" represents a hexadecimal character: {cccccccc-cccc-cccc-cccc-cccccccccccc}
DevicePropertyClassName
Requests the name of the device's setup class, in text format. PropertyBuffer points to a NUL-terminated WCHAR string.
DevicePropertyCompatibleIDs
Requests the compatible IDs reported by the device. PropertyBuffer points to a MULTI_SZ.
DevicePropertyDeviceDescription
Requests a string describing the device, such as "Microsoft PS/2 Port Mouse", typically defined by the manufacturer. PropertyBuffer points to a NUL-terminated WCHAR string.
DevicePropertyDriverKeyName
Requests the name of the driver-specific registry key. PropertyBuffer points to a NUL-terminated WCHAR string.
DevicePropertyEnumeratorName
Requests the name of the enumerator for the device, such as "PCI" or "root". PropertyBuffer points to NUL-terminated WCHAR string.
DevicePropertyFriendlyName
Requests a string that can be used to distinguish between two similar devices, typically defined by the class installer. PropertyBuffer points to a NUL-terminated WCHAR string.
DevicePropertyHardwareID
Requests the hardware IDs provided by the device that identify the device. PropertyBuffer points to a MULTI_SZ value.
DevicePropertyInstallState
(Windows XP and later.) Requests the device's installation state. The installation state is returned as a DEVICE_INSTALL_STATE enumeration value (see ntddk.h).
DevicePropertyLegacyBusType
Requests the bus type, such as PCIBus or PCMCIABus. PropertyBuffer points to an INTERFACE_TYPE enumeration value.
DevicePropertyLocationInformation
Requests information about the device's location on the bus; the interpretation of this information is bus-specific. PropertyBuffer points to a NUL-terminated WCHAR string.
DevicePropertyManufacturer
Requests a string identifying the manufacturer of the device. PropertyBuffer points to a NUL-terminated WCHAR string.
DevicePropertyPhysicalDeviceObjectName
Requests the name of the PDO for this device. PropertyBuffer points to a NUL-terminated WCHAR string.
DevicePropertyRemovalPolicy
(Windows XP and later.) Requests the device's current removal policy. The current removal policy is returned as a DEVICE_REMOVAL_POLICY enumeration value (see ntddk.h).
DevicePropertyUINumber
Requests a number associated with the device that can be displayed in the user interface. PropertyBuffer points to a ULONG value.

This number is typically a user-perceived slot number, such as a number printed next to the slot on the board, or some other number that makes locating the physical device easier for the user. If the device is on a bus that has no UI number convention, or if the bus driver for the device cannot determine the UI number, this value is 0xFFFFFFFF.

BufferLength
Specifies the size, in bytes, of the caller-supplied PropertyBuffer.
PropertyBuffer
Points to a caller-supplied buffer to receive the property information. The buffer can be allocated from pageable memory. The type of the buffer is determined by the DeviceProperty (see above).
ResultLength
Points to a ULONG to receive the size of the property information returned at PropertyBuffer. If IoGetDeviceProperty returns STATUS_BUFFER_TOO_SMALL, it sets this parameter to the required buffer length.

Return Value

IoGetDeviceProperty returns STATUS_SUCCESS if the call was successful. Possible error return values include:

Error Status | Description
STATUS_BUFFER_TOO_SMALL | The buffer at PropertyBuffer was too small. ResultLength points to the required buffer length.
STATUS_INVALID_PARAMETER_2 | The given DeviceProperty is not one of the properties handled by this routine.
STATUS_INVALID_DEVICE_REQUEST | Possibly indicates that the given DeviceObject was not a valid PDO pointer.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

IoGetDeviceProperty retrieves device setup information from the registry. Use this routine, rather than accessing the registry directly, to insulate a driver from differences across platforms and from possible changes in the registry structure.

For many DeviceProperty requests, it can take two or more calls to IoGetDeviceProperty to determine the required BufferLength. The first call should use a best-guess value. If the return status is STATUS_BUFFER_TOO_SMALL, the driver should free its current buffer, allocate a buffer of the size returned in ResultLength, and call IoGetDeviceProperty again. Because some of the setup properties are dynamic, the data size can change between the time the required size is returned and driver calls this routine again. Therefore, drivers should call IoGetDeviceProperty inside a loop that executes until the return status is not STATUS_BUFFER_TOO_SMALL.

Function drivers that support devices on a legacy bus and a PnP bus can use the DevicePropertyBusNumber, DevicePropertyBusTypeGuid, and DevicePropertyLegacyBusType properties to distinguish between the buses.

Callers of IoGetDeviceProperty must be running at IRQL PASSIVE_LEVEL in the context of a system thread.

See Also

ExAllocatePool, ExAllocatePoolWithTag, CM_RESOURCE_LIST, IO_RESOURCE_REQUIREMENTS_LIST, GUID


IoGetDeviceToVerify

IoGetDeviceToVerify returns a pointer to the device object, representing a removable-media device, that is the target of the given thread's I/O request.

PDEVICE_OBJECT
  IoGetDeviceToVerify(
    IN PETHREAD  Thread
    );

Parameters

Thread
Points to the thread for which a highest-level driver is attempting to verify the validity of the media on which the thread has opened a file.

Return Value

IoGetDeviceToVerify returns a pointer to the device object representing a device on which the media should be verified, or it returns NULL.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

In general, highest-level drivers, particularly file systems, are most likely to call this routine.

An underlying removable-media device driver is responsible for notifying higher-level drivers, particularly the file system, when the media appears to have changed since the last access to the target device. For more information, see Supporting Removable Media.

Callers of IoGetDeviceToVerify must be running at IRQL PASSIVE_LEVEL.

See Also

IoIsErrorUserInduced, IoSetHardErrorOrVerifyDevice, PsGetCurrentThread


IoGetDmaAdapter

IoGetDmaAdapter returns a pointer to the DMA adapter structure for a physical device object.

PDMA_ADAPTER
  IoGetDmaAdapter(
    IN PDEVICE_OBJECT  PhysicalDeviceObject,
    IN PDEVICE_DESCRIPTION  DeviceDescription,
    IN OUT PULONG  NumberOfMapRegisters
    );

Parameters

PhysicalDeviceObject
Pointer to the physical device object for the device requesting the DMA adapter structure.
DeviceDescription
Pointer to a DEVICE_DESCRIPTION structure, which describes the attributes of the physical device.
NumberOfMapRegisters
Pointer to, on output, the maximum number of map registers that the driver can allocate for any DMA transfer operation.

Return Value

IoGetDmaAdapter returns a pointer to a DMA adapter structure that contains function pointers to the system-defined set of DMA operations. If an adapter structure cannot be allocated, the routine returns NULL.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Before calling this routine, a driver must zero-initialize the structure passed at DeviceDescription and then supply the relevant information for its device.

On success, the DmaOperations member of the routine's return value points to a DMA_OPERATIONS structure, which is a table of pointers to functions that the driver can use to perform subsequent DMA operations. If the driver passes DEVICE_DESCRIPTION_VERSION or DEVICE_DESCRIPTION_VERSION1 in the Version member of the DeviceDescription parameter, IoGetDmaAdapter returns a pointer to version 1 of the DMA_OPERATIONS structure. If the driver passes DEVICE_DESCRIPTION_VERSION2, IoGetDmaAdapter returns version 2 of the table if version 2 is supported, otherwise it returns NULL. Drivers must check to see if version 2 is supported before attempting to use any version 2 function.

PnP drivers call IoGetDmaAdapter when handling a PnP IRP_MN_START_DEVICE request for a device. This IRP includes information about the device's hardware resources that the driver must supply in the DeviceDescription structure.

In NumberOfMapRegisters, the caller specifies the optimal number of map registers it can use. On output, the I/O Manager returns the number of map registers it allocated. Drivers should check the returned value; there is no guarantee a driver will receive the same number of map registers it requested.

To free the adapter object, the driver should call PutDmaAdapter through the pointer returned in the DMA_ADAPTER structure.

Drivers must call this routine while running at IRQL PASSIVE_LEVEL.

See Also

DEVICE_DESCRIPTION, DMA_ADAPTER, PutDmaAdapter


IoGetDriverObjectExtension

IoGetDriverObjectExtension retrieves a previously allocated per-driver context area.

PVOID
  IoGetDriverObjectExtension(
    IN PDRIVER_OBJECT  DriverObject,
    IN PVOID  ClientIdentificationAddress
    );

Parameters

DriverObject
Specifies the driver object with which the context area is associated.
ClientIdentificationAddress
Specifies the unique identifier, provided when it was allocated, of the context area to be retrieved.

Return Value

IoGetDriverObjectExtension returns a pointer to the context area, if any or returns NULL.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Drivers call IoGetDriverObjectExtension to retrieve a pointer to a previously allocated extension area.

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoAllocateDriverObjectExtension


IoGetFileObjectGenericMapping

IoGetFileObjectGenericMapping returns information about the mapping between each generic access right and the set of specific access rights for file objects.

PGENERIC_MAPPING
  IoGetFileObjectGenericMapping(
    );

Return Value

IoGetFileObjectGenericMapping returns a pointer to the GENERIC_MAPPING structure that describes the mapping between each generic access right and the implied set of specific access rights.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

Callers of IoGetFileObjectGenericMapping must be running at IRQL PASSIVE_LEVEL.

See Also

GENERIC_MAPPING, IoCheckShareAccess, IoSetShareAccess, ZwCreateFile


IoGetFunctionCodeFromCtlCode

IoGetFunctionCodeFromCtlCode returns the value of the Function in a given IOCTL_XXX control code.

ULONG
  IoGetFunctionCodeFromCtlCode(
    IN ULONG  ControlCode
    );

Parameters

ControlCode
Points to the IOCTL _XXX (or FSCTL_XXX) in the driver's I/O stack location of the IRP at Parameters.DeviceIoControl.IoControlCode.

Return Value

IoGetFunctionCodeFromCtlCode returns the value of the Function part of the given IOCTL_XXX code.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

See Defining I/O Control Codes for more information about the layout of IOCTL_XXX codes and using the CTL_CODE macro.

Callers of IoGetFunctionCodeFromCtlCode must be running at IRQL <= DISPATCH_LEVEL.

See Also

CTL_CODE, IoBuildDeviceIoControlRequest


IoGetInitialStack

IoGetInitialStack returns the base address of the current thread's stack.

PVOID
  IoGetInitialStack(
    );

Return Value

IoGetInitialStack returns the initial base address of the current thread's stack.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

Highest-level drivers can call this routine, particularly file systems attempting to determine whether they've been passed a pointer to a location on the current thread's stack.

Callers of IoGetInitialStack must be running at IRQL < DISPATCH_LEVEL.

See Also

IoGetRemainingStackSize, IoGetStackLimits


IoGetNextIrpStackLocation

IoGetNextIrpStackLocation gives a higher level driver access to the next-lower driver's I/O stack location in an IRP so the caller can set it up for the lower driver.

PIO_STACK_LOCATION
  IoGetNextIrpStackLocation(
    IN PIRP  Irp
    );

Parameters

Irp
Points to the IRP.

Return Value

IoGetNextIrpStackLocation returns a pointer to the next-lower-level driver's I/O stack location in the given IRP.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Each driver that passes IRPs on to lower drivers must set up the stack location for the next lower driver. A driver calls IoGetNextIrpStackLocation to get a pointer to the next-lower driver's I/O stack location.

If a driver is passing the same parameters that it received to the next-lower driver, such a driver can call IoCopyCurrentIrpStackLocationToNext or IoSkipCurrentIrpStackLocation instead of getting a pointer to the next-lower stack location and copying the parameters manually.

Callers of IoGetNextIrpStackLocation must be running at IRQL <= DISPATCH_LEVEL.

See Also

IO_STACK_LOCATION, IoCallDriver, IoGetCurrentIrpStackLocation, IoCopyCurrentIrpStackLocationToNext, IoSetNextIrpStackLocation, IoSkipCurrentIrpStackLocation


IoGetRelatedDeviceObject

Given a file object, IoGetRelatedDeviceObject returns a pointer to the corresponding device object.

PDEVICE_OBJECT
  IoGetRelatedDeviceObject(
    IN PFILE_OBJECT  FileObject
    );

Parameters

FileObject
Points to the file object.

Return Value

IoGetRelatedDeviceObject returns a pointer to the device object.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

When called on a file object that represents the underlying storage device, IoGetRelatedDeviceObject returns the highest-level device object in the storage device stack. To obtain the highest-level device object in the file system driver stack, drivers must call IoGetRelatedDeviceObject on a file object that represents the file system's driver stack, and the file system must currently be mounted. (Otherwise, the storage device stack is traversed instead of the file system stack.)

To ensure that the file system is mounted on the storage device, the driver must have specified an appropriate access mask, such as FILE_READ_DATA or FILE_WRITE_ATTRIBUTES, when opening the file or device represented by the file object. Specifying FILE_READ_ATTRIBUTES does not cause the file system to be mounted.

The caller must be running at IRQL <= DISPATCH_LEVEL. Usually, callers of this routine are running at IRQL PASSIVE_LEVEL.

See Also

IoGetDeviceObjectPointer


IoGetRemainingStackSize

IoGetRemainingStackSize returns the current amount of available kernel-mode stack space.

ULONG
  IoGetRemainingStackSize(
    );

Return Value

IoGetRemainingStackSize returns the number of bytes of stack space in the current thread context.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

Highest-level drivers, such as file systems, can call this routine, particularly drivers that use recursive code paths. Such a driver would call IoGetRemainingStackSize before launching a recursion to determine whether it should continue processing on an alternate code path.

Callers of IoGetRemainingStackSize must be running at IRQL < DISPATCH_LEVEL.

See Also

IoGetInitialStack, IoGetStackLimits


IoGetStackLimits

IoGetStackLimits returns the boundaries of the current thread's stack frame.

VOID
  IoGetStackLimits(
    OUT PULONG  LowLimit,
    OUT PULONG  HighLimit
    );

Parameters

LowLimit
Points to a caller-supplied variable in which this routine returns the lower offset of the current thread's stack frame.
HighLimit
Points to a caller-supplied variable in which this routine returns the higher offset of the current thread's stack frame.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

Highest-level drivers can call this routine, particularly file systems that have been passed a pointer to a location on the current thread's stack.

Callers of IoGetStackLimits must be running at IRQL < DISPATCH_LEVEL.

See Also

IoGetInitialStack, IoGetRemainingStackSize


IoInitializeDpcRequest

IoInitializeDpcRequest registers a driver-supplied DpcForIsr routine when a device driver initializes.

VOID
  IoInitializeDpcRequest(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIO_DPC_ROUTINE  DpcRoutine
    );

Parameters

DeviceObject
Points to the device object representing the physical device that generates interrupts.
DpcRoutine
Points to the driver-supplied DpcForIsr routine, which is declared as follows:
VOID
(*PIO_DPC_ROUTINE)(
    IN PKDPC Dpc,
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN PVOID Context
    );

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

IoInitializeDpcRequest associates a driver-supplied DpcForIsr routine with a given device object so the driver's ISR can call IoRequestDpc to queue the DpcForIsr. This routine completes interrupt-driven I/O operations at a lower IRQL than that of the ISR.

PnP drivers call IoInitializeDpcRequest from the AddDevice routine.

Callers of IoInitializeDpcRequest must be running at IRQL PASSIVE_LEVEL.

It is possible to call KeInitializeDpc to initialize another DPC at IRQL <= DISPATCH_LEVEL.

See Also

IoRequestDpc, KeInitializeDpc


IoInitializeIrp

IoInitializeIrp initializes a given IRP that was allocated by the caller.

VOID
  IoInitializeIrp(
    IN OUT PIRP  Irp,
    IN USHORT  PacketSize,
    IN CCHAR  StackSize
    );

Parameters

Irp
Points to the IRP to be initialized.
PacketSize
Specifies the size in bytes of the IRP.
StackSize
Specifies the number of stack locations in the IRP.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Drivers use IoInitializeIrp to initialize IRPs the driver allocated as raw memory. Do not use IoInitializeIrp to initialize an IRP allocated by IoAllocateIrp. IoAllocateIrp automatically initializes the members of the IRP.

Drivers can use IoInitializeIrp to reinitialize an IRP for reuse only under certain circumstances. See Reusing IRPs for details.

If the driver associates an MDL with the IRP it allocated, the driver is responsible for releasing the MDL when the IRP is completed.

An intermediate or highest-level driver also can call IoBuildDeviceIoControlRequest, IoBuildAsynchronousFsdRequest, or IoBuildSynchronousFsdRequest to set up requests it sends to lower-level drivers. Only a highest-level driver can call IoMakeAssociatedIrp.

Callers of IoInitializeIrp must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoAllocateIrp, IoAllocateMdl, IoBuildPartialMdl, IoFreeIrp, IoFreeMdl, IoReuseIrp, IoSetNextIrpStackLocation, IoSizeOfIrp, IRP


IoInitializeRemoveLock

IoInitializeRemoveLock initalizes a remove lock for a device object. A driver can use the lock to track outstanding I/O on a device and to determine when the driver can delete its device object in response to an IRP_MN_REMOVE_DEVICE request.

VOID
  IoInitializeRemoveLock(
    IN PIO_REMOVE_LOCK  Lock,
    IN ULONG  AllocateTag,
    IN ULONG  MaxLockedMinutes,
    IN ULONG  HighWatermark
    );

Parameters

Lock
Points to a caller-supplied IO_REMOVE_LOCK structure that this routine initializes with information about the lock, including a counter and a synchronization event. A driver writer must allocate this structure as part of the device object's device extension.
AllocateTag
Specifies a tag to identify the creator of the lock. Driver writers typically use a 4-character string, specified in reverse order, like the tags used for ExAllocatePoolWithTag.

The I/O system only uses this parameter on checked builds.

MaxLockedMinutes
Specifies the maximum number of minutes that this lock should be held. A value of zero means there is no limit. This value is typically used during debugging to identify a driver routine that holds the lock longer than expected.

The I/O system only uses this parameter on checked builds. If the lock is held for more than MaxLockedMinutes on a checked build, the system asserts.

HighWatermark
Specifies the maximum number of outstanding acquisitions allowed on the lock.

The I/O system only uses this parameter on checked builds. If the lock is acquired HighWatermark times on a checked build, the system asserts.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

The Io Xxx RemoveLock Xxx routines provide a way to track the number of outstanding I/O's on a device and determine when it is safe to detach and delete a driver's device object. The system provides these routines to driver writers as an alternative to implementing their own tracking mechanism.

A driver can use this mechanism for two purposes:

  1. To ensure that the driver's DispatchPnP routine will not complete an IRP_MN_REMOVE_DEVICE request while the lock is held (for example, while another driver routine is accessing the device).
  2. To count the number of reasons why the driver should not delete its device object, and to set an event when that count goes to zero.

A driver typically calls IoInitializeRemoveLock in its AddDevice routine, when the driver initializes the rest of the device extension for a device object.

A driver calls IoAcquireRemoveLock each time it starts an I/O operation. A driver calls IoReleaseRemoveLock each time it finishes an I/O operation. A driver can acquire the lock more than once; the Io Xxx RemoveLock Xxx routines maintain a count of the outstanding acquisitions of the lock.

A driver should also call IoAcquireRemoveLock when it passes out a reference to its code (for timers, DPCs, callbacks, etc.). The driver calls IoReleaseRemoveLock when the event has returned.

In its dispatch code for IRP_MN_REMOVE_DEVICE, a driver acquires the lock once more and calls IoReleaseRemoveLockAndWait. This routine causes the driver to block until all outstanding acquisitions of the lock have been released. A driver should call IoReleseRemoveLockAndWait after it passes the remove IRP to the next-lower driver but before it releases memory, calls IoDetachDevice, or calls IoDeleteDevice.

A driver stores the IO_REMOVE_LOCK structure in the device extension of a device object. The remove lock is deleted when the driver deletes the device extension as part of processing an IRP_MN_REMOVE_DEVICE request.

Callers of IoInitializeRemoveLock must be running at IRQL = PASSIVE_LEVEL.

See Also

IoAcquireRemoveLock, IoReleaseRemoveLock, IoReleaseRemoveLockAndWait


IoInitializeRemoveLockEx

This routine is reserved for system use. See IoInitializeRemoveLock.


IoInitializeTimer

IoInitializeTimer sets up a driver-supplied IoTimer routine associated with a given device object.

NTSTATUS
  IoInitializeTimer(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIO_TIMER_ROUTINE  TimerRoutine,
    IN PVOID  Context
    );

Parameters

DeviceObject
Points to a device object representing a device on which I/O operations can time out.
TimerRoutine
Points to the driver-supplied IoTimer routine, which is declared as follows:
VOID
(*PIO_TIMER_ROUTINE) (
    IN PDEVICE_OBJECT DeviceObject,
    IN PVOID Context
    );
Context
Points to the driver-determined context with which its IoTimer routine will be called.

Return Value

IoInitializeTimer returns STATUS_SUCCESS if the IoTimer routine is set up.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

A driver's IoTimer routine is called once per second after the driver enables the timer by calling IoStartTimer.

The driver can disable the timer by calling IoStopTimer and can re-enable it again with IoStartTimer.

The driver's IoTimer routine is called at IRQL DISPATCH_LEVEL and therefore must not contain pageable code.

When the timer is running, the I/O Manager calls the driver-supplied IoTimer routine once per second. Drivers whose time-out routines should be called at variable intervals or at intervals of finer granularity can set up a CustomTimerDpc routine and use the Ke..Timer routines.

Callers of IoInitializeTimer must be running at IRQL PASSIVE_LEVEL.

See Also

IoStartTimer, IoStopTimer, KeInitializeTimer, KeSetTimer


IoInvalidateDeviceRelations

IoInvalidateDeviceRelations notifies the PnP manager that the relations for a device (such as bus relations, ejection relations, removal relations, and the target device relation) have changed.

VOID
  IoInvalidateDeviceRelations(
    IN PDEVICE_OBJECT  DeviceObject,
    IN DEVICE_RELATION_TYPE  Type
    );

Parameters

DeviceObject
Points to the PDO for the device.
Type
Specifies the type of relations that have changed. Possible values include BusRelations, EjectionRelations, RemovalRelations, and TargetDeviceRelation.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

For some relation types, such as BusRelations, this routine causes the PnP or Power Manager to gather updated relations information by sending an IRP_MN_QUERY_DEVICE_RELATIONS request to the drivers for the device. For other relation types, such as EjectionRelations, the PnP Manager does not need to gather new relation information immediately; the PnP Manager queries drivers for ejection relations only when it is preparing to eject a device.

After a bus driver calls IoInvalidateDeviceRelations to inform the PnP Manager that a device has disappeared, the bus driver must continue to handle PnP IRPs for that device until it receives an IRP_MN_REMOVE_DEVICE. In response to such IRPs, the bus driver returns STATUS_NO_SUCH_DEVICE. Until it succeeds the remove IRP, the bus driver can access the device extension to check its flags for the device.

Callers of IoInvalidateDeviceRelations must be running at IRQL <= DISPATCH_LEVEL.

See Also

IRP_MN_QUERY_DEVICE_RELATIONS


IoInvalidateDeviceState

IoInvalidateDeviceState notifies the PnP manager that some aspect of the PnP state of a device has changed.

VOID
  IoInvalidateDeviceState(
    IN PDEVICE_OBJECT  PhysicalDeviceObject
    );

Parameters

PhysicalDeviceObject
Points to the PDO for the device.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Drivers call this routine to indicate that something has changed with respect to one of the following aspects of a device's PnP state:

PNP_DEVICE_DISABLED
PNP_DEVICE_DONT_DISPLAY_IN_UI
PNP_DEVICE_FAILED
PNP_DEVICE_NOT_DISABLEABLE
PNP_DEVICE_REMOVED
PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED

In response to this routine, the PnP Manager sends an IRP_MN_QUERY_PNP_DEVICE_STATE request to the device stack, to determine the current PnP state of the device.

Callers of IoInvalidateDeviceState must be running at IRQL <= DISPATCH_LEVEL.

See Also

IRP_MN_QUERY_PNP_DEVICE_STATE, PNP_DEVICE_STATE


IoIs32bitProcess

IoIs32bitProcess checks whether the originator of the current I/O request is a 32-bit user-mode application.

BOOLEAN
  IoIs32bitProcess(
  IN PIRP  Irp  OPTIONAL
  );

Parameters

Irp
Optional pointer to the IRP containing the current I/O request. Note that this must be the original IRP that was issued by the I/O manager. If the caller is a fast I/O dispatch routine (and thus there is no IRP), the caller should set this parameter to NULL.

Return Value

IoIs32bitProcess returns TRUE if the originator of the current I/O request is a 32-bit user-mode process, FALSE otherwise.

Headers

Declared in ntddk.h and wdm.h. Include ntddk.h or wdm.h.

Comments

The routine is only available in Windows XP and later, for 64-bit platforms.

Drivers call IoIs32bitProcess to determine whether an I/O request is likely to contain data elements that need to be converted, or "thunked," before they can be used in a 64-bit driver.

If the Irp parameter is NULL, and the caller is running in the context of a user-mode process, IoIs32bitProcess returns TRUE if this process is a 32-bit process.

If the Irp parameter is not NULL, it must point to an IRP that was issued by the I/O Manager on behalf of a user-mode process. IoIs32bitProcess cannot be used to check driver-allocated IRPs. Driver-allocated IRPs, as well as kernel-mode drivers, are assumed to be 64-bit-ready.

Callers of IoIs32bitProcess must be running at IRQL < DISPATCH_LEVEL.

For additional information, see 64-Bit Issues.


IoIsErrorUserInduced

IoIsErrorUserInduced determines whether an I/O error encountered while processing a request to a removable-media device was caused by the user.

BOOLEAN
  IoIsErrorUserInduced(
    IN NTSTATUS  Status
    );

Parameters

Status
Specifies the current NTSTATUS value, usually within the driver's DpcForIsr routine.

Return Value

IoIsErrorUserInduced returns TRUE if an I/O request failed because of a user-induced error.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

This routine indicates whether an I/O request failed for one of the following user-correctable conditions:

STATUS_DEVICE_NOT_READY
STATUS_IO_TIMEOUT
STATUS_MEDIA_WRITE_PROTECTED
STATUS_NO_MEDIA_IN_DEVICE
STATUS_UNRECOGNIZED_MEDIA
STATUS_VERIFY_REQUIRED
STATUS_WRONG_VOLUME

If IoIsErrorUserInduced returns TRUE, the removable-media driver must call IoSetHardErrorOrVerifyDevice before completing the IRP.

Callers of IoIsErrorUserInduced must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoSetHardErrorOrVerifyDevice, IoAllocateErrorLogEntry, IoWriteErrorLogEntry


IoIsWdmVersionAvailable

IoIsWdmVersionAvailable checks whether a given WDM version is supported by the operating system.

BOOLEAN
  IoIsWdmVersionAvailable(
    IN UCHAR  MajorVersion,
    IN UCHAR  MinorVersion
    );

Parameters

MajorVersion
Specifies the major version number of WDM that is requested.
MinorVersion
Specifies the minor version number of WDM that is requested.

Return Value

IoIsWdmVersionAvailable returns TRUE if the version of WDM that the operating system provides is greater than or equal to the version number of WDM being requested.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Cross-platform drivers should use this routine to check the WDM version before performing any operations that vary by platform or are not supported in all versions of WDM.

The constants WDM_MAJORVERSION and WDM_MINORVERSION are defined in wdm.h and ntddk.h. The following lists the WDM version provided with each operating system:

Operating System | WDM Major Version | WDM Minor Version
Windows XP | 1 | 0x20
Windows 2000 | 1 | 0x10
Windows ME | 1 | 0x05
Windows 98 | 1 | 0x00

Note that the minor version number is defined as a hexadecimal value.

Later versions of WDM support all the features available in earlier versions of WDM; that is, each version of WDM is a superset of the previous WDM version.

Callers of this routine must be running at IRQL PASSIVE_LEVEL.

The following call returns TRUE on any of the listed operating systems, because all these systems support all the features of WDM 1.0:

bVersion = IoIsWdmVersionAvailable(1,0);

The following example shows how a driver can dynamically detect the current operating system:

if (IoIsWdmVersionAvailable(1, 0x10)) {
    //
    //If WDM 1.10 is supported, this is Windows 2000
    //or better.
    //
} else if (IoIsWdmVersionAvailable(1, 5)) {
    //
    //If WDM 1.05 is supported, this is Windows ME
    //or better.
    //
} else {
    //
    //WDM 1.0 is always supported, so this is Windows 98,
    //Windows 98 SE, or better.
    //
}

As the example shows, calling IoIsWdmVersionAvailable(1, 5) returns TRUE on Windows Me, Windows 2000, and any succeeding operating systems, but FALSE on Windows 98 and Windows 98 SE.


IoMakeAssociatedIrp

IoMakeAssociatedIrp allocates and initalizes an IRP to be associated with a master IRP sent to a highest-level driver, allowing the caller to split the original request and send associated IRPs on to lower-level drivers.

PIRP
  IoMakeAssociatedIrp(
    IN PIRP  Irp,
    IN CCHAR  StackSize
    );

Parameters

Irp
Points to the master IRP that was input to a highest-level driver's Dispatch routine.
StackSize
Specifies the number of stack locations to be allocated for the associated IRP. The value must be at least equal to the StackSize of the next-lower driver's device object, but the associated IRP can have an additional stack location for the caller.

Return Value

IoMakeAssociatedIrp returns a pointer to the associated IRP or returns a NULL pointer if an IRP cannot be allocated.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

Only a highest-level driver can call this routine.

The I/O Manager completes the master IRP automatically when lower drivers have completed all associated IRPs as long as the caller has not set its IoCompletion routine in an associated IRP and returned STATUS_MORE_PROCESSING_REQUIRED from its IoCompletion routine. In these circumstances, the caller must explicitly complete the master IRP when that driver has determined that all associated IRPs were completed.

Only the master IRP is associated with a thread; associated IRPs are not. For this reason, the I/O Manager cannot call Cancel routines for associated IRPs when a thread exits. When the master IRP's thread exits, the I/O Manager calls the master IRP's cancel routine. The Cancel routine is responsible for tracking down all associated IRPs and calling IoCancelIrp to cancel them.

Callers of IoMakeAssociatedIrp must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoAllocateIrp, IoBuildAsynchronousFsdRequest, IoBuildDeviceIoControlRequest, IoBuildSynchronousFsdRequest, IoCallDriver, IoSetCompletionRoutine, IRP


IoMapTransfer

IoMapTransfer is obsolete and exported only to support existing drivers. See MapTransfer instead.

PHYSICAL_ADDRESS
  IoMapTransfer(
    IN PADAPTER_OBJECT  AdapterObject,
    IN PMDL  Mdl,
    IN PVOID  MapRegisterBase,
    IN PVOID  CurrentVa,
    IN OUT PULONG  Length,
    IN BOOLEAN  WriteToDevice
    );


IoMarkIrpPending

IoMarkIrpPending marks the given IRP, indicating that a driver's Dispatch routine returned STATUS_PENDING because further processing is required by other driver routines.

VOID
  IoMarkIrpPending(
    IN OUT PIRP  Irp
    );

Parameters

Irp
Points to the IRP to be marked as pending.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Unless a driver calls IoCompleteRequest from its Dispatch routine with a given IRP or passes the IRP on to lower drivers, it must call IoMarkIrpPending with the IRP. Otherwise, the I/O Manager attempts to complete the IRP as soon as the Dispatch routine returns control.

If a driver queues incoming IRPs, it should call IoMarkIrpPending before it queues each IRP. Otherwise, an IRP could be dequeued, completed by another driver routine, and freed by the system before the call to IoMarkIrpPending occurs, thereby causing a crash.

Any driver that sets an IoCompletion routine in an IRP and then passes the IRP down to a lower driver should check the IRP->PendingReturned flag in the IoCompletion routine. If the flag is set, the IoCompletion routine must call IoMarkIrpPending with the IRP. Note, however, that a driver that passes down the IRP and then waits on an event should not mark the IRP pending. Instead, its IoCompletion routine should signal the event and return STATUS_MORE_PROCESSING_REQUIRED.

A routine that calls IoMarkIrpPending must return STATUS_PENDING.

Callers of IoMarkIrpPending must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoCompleteRequest, IoStartPacket, IRP


IoOpenDeviceInterfaceRegistryKey

IoOpenDeviceInterfaceRegistryKey returns a handle to a registry key for storing information about a particular device interface instance.

NTSTATUS
  IoOpenDeviceInterfaceRegistryKey(
    IN PUNICODE_STRING  SymbolicLinkName,
    IN ACCESS_MASK  DesiredAccess,
    OUT PHANDLE  DeviceInterfaceKey
    );

Parameters

SymbolicLinkName
Points to a string identifying the device interface instance. This string was obtained from a previous call to IoGetDeviceInterfaces, IoGetDeviceInterfaceAlias, or IoRegisterDeviceInterface.
DesiredAccess
Specifies the ACCESS_MASK value that represents the access the caller requires to the key, such as KEY_READ, KEY_WRITE, or KEY_ALL_ACCESS. See ZwCreateKey for a description of each KEY_XXX access right.
DeviceInterfaceKey
Points to a returned handle to the requested registry key if the call is successful.

Return Value

IoOpenDeviceInterfaceRegistryKey returns STATUS_SUCCESS if the call was successful. Possible error return values include:

Error Status | Description
STATUS_OBJECT_NAME_NOT_FOUND | The routine was not able to locate a registry key for the device interface instance, probably due to an error in the SymbolicLinkName.
STATUS_OBJECT_PATH_NOT_FOUND | The routine was not able to locate a registry key for the device interface instance, probably due to an error in the SymbolicLinkName.
STATUS_INVALID_PARAMETER | Possibly indicates an error in the SymbolicLinkName.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

IoOpenDeviceInterfaceRegistryKey opens a non-volatile subkey of the registry key for the device interface instance specified by SymbolicLinkName. Drivers can store information in this subkey that is specific to this instance of the device interface, such as the default resolution for a camera. User-mode applications can access this subkey using SetupDi Xxx routines.

The driver must call ZwClose to close the handle returned from this routine when access is no longer required.

Callers of IoOpenDeviceInterfaceRegistryKey must be running at IRQL PASSIVE_LEVEL in the context of a system thread.

See Also

ACCESS_MASK, IoGetDeviceInterfaces, IoGetDeviceInterfaceAlias, IoRegisterDeviceInterface, ZwClose


IoOpenDeviceRegistryKey

IoOpenDeviceRegistryKey returns a handle to a device-specific or a driver-specific registry key for a particular device instance.

NTSTATUS
  IoOpenDeviceRegistryKey(
    IN PDEVICE_OBJECT  DeviceObject,
    IN ULONG  DevInstKeyType,
    IN ACCESS_MASK  DesiredAccess,
    OUT PHANDLE  DevInstRegKey
    );

Parameters

DeviceObject
Points to the PDO of the device instance for which the registry key is to be opened.
DevInstKeyType
Specifies flags indicating whether to open a device-specific or a driver-specific key. The flags also indicate whether the key is relative to the current hardware profile. Can be a combination of the following values:
PLUGPLAY_REGKEY_DEVICE
Open a key for storing device-specific information. The key is located under the key for the device instance specified by DeviceObject. This flag cannot be specified with PLUGPLAY_REGKEY_DRIVER.
PLUGPLAY_REGKEY_DRIVER
Open a key for storing driver-specific information. This flag cannot be specified with PLUGPLAY_REGKEY_DEVICE.
PLUGPLAY_REGKEY_CURRENT_HWPROFILE
Open a key relative to the current hardware profile for device or driver information. This allows the driver to access configuration information that is hardware-profile-specific. The caller must specify either PLUGPLAY_REGKEY_DEVICE or PLUGPLAY_REGKEY_DRIVER with this flag.
DesiredAccess
Specifies the ACCESS_MASK value that represents the access the caller needs to the key. See the ZwCreateKey routine for a description of each KEY_XXX access right.
DevInstRegKey
Points to a caller-allocated buffer that, on successful return, contains a handle to the requested registry key.

Return Value

IoOpenDeviceRegistryKey returns STATUS_SUCCESS if the call was successful. Possible error return values include:

Error Status | Description
STATUS_INVALID_PARAMETER | Possibly indicates that the caller specified an illegal set of DevInstKeyType flags.
STATUS_INVALID_DEVICE_REQUEST | Possibly indicates that the DeviceObject is not a valid PDO.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

The driver must call ZwClose to close the handle returned from this routine when access is no longer required.

The registry keys opened by this routine are non-volatile.

User-mode configuration utilities, such as Class Installers, can access these same registry keys using the configuration manager and device installer APIs.

Callers of IoOpenDeviceRegistryKey must be running at IRQL PASSIVE_LEVEL in the context of a system thread.

See Also

ACCESS_MASK, ZwClose


IoQueryDeviceDescription

IoQueryDeviceDescription is obsolete and is exported only to support existing drivers. IoQueryDeviceDescription retrieves hardware configuration information about a given bus, controller or peripheral object, or any combination of these three types from the \Registry\Machine\Hardware\Description tree. Drivers that require hardware configuration information should use IoGetDeviceProperty instead.

NTSTATUS
  IoQueryDeviceDescription(
    IN PINTERFACE_TYPE  BusType  OPTIONAL,
    IN PULONG  BusNumber  OPTIONAL,
    IN PCONFIGURATION_TYPE  ControllerType  OPTIONAL,
    IN PULONG  ControllerNumber  OPTIONAL,
    IN PCONFIGURATION_TYPE  PeripheralType  OPTIONAL,
    IN PULONG  PeripheralNumber  OPTIONAL,
    IN PIO_QUERY_DEVICE_ROUTINE  CalloutRoutine,
    IN PVOID  Context
    );


IoQueueWorkItem

IoQueueWorkItem inserts the specified work item into a queue from which a system worker thread removes the item and gives control to the specified callback routine.

VOID
  IoQueueWorkItem(
    IN PIO_WORKITEM  pIOWorkItem,
    IN PIO_WORKITEM_ROUTINE  Routine,
    IN WORK_QUEUE_TYPE  QueueType,
    IN PVOID  Context
    );

Parameters

pIOWorkItem
Points to the IO_WORKITEM structure returned by a previous call to IoAllocateWorkItem.
Routine
Points to the routine that will be called to process the work item. This routine will be called in the context of a system thread. This routine is declared as follows:
VOID
(*PIO_WORKITEM_ROUTINE) (
    IN PDEVICE_OBJECT DeviceObject,
    IN PVOID Context
    );
QueueType
Specifies the type of work queue that the work item should be inserted. QueueType can be either of the following:
CriticalWorkQueue
Insert the work item into the queue from which a system thread with a real-time priority attribute will process the work item.
DelayedWorkQueue
Insert the work item into the queue from which a system thread with a variable priority attribute will process the work item.

The QueueType value HyperCriticalWorkQueue is reserved for system use.

Context
Points to a caller-supplied context area to be passed through to the callback routine.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comment

Highest-level drivers can call IoQueueWorkItem.

The callback is run within a system thread context at IRQL PASSIVE_LEVEL. This caller-supplied routine is responsible for calling IoFreeWorkItem to reclaim the storage allocated for the work item.

A driver must not wait for its callback routine to complete an operation if it is already holding one synchronization object and might attempt to acquire another. For example, a driver should release any currently held semaphores, mutexes, resource variables, and so forth before it calls IoQueueWorkItem. Releasing synchronization resources before queuing a synchronous worker-thread operation prevents deadlocks.

The value of QueueType determines the runtime priority at which the callback routine is run, as follows:

  • If the callback runs in the system thread with a real-time priority attribute, the callback routine cannot be preempted except by threads with higher real-time priorities.
  • If the callback runs in the system thread with a variable priority attribute, the callback can be preempted by threads with higher variable and real-time priorities, and the callback is scheduled to run round-robin with other threads of the same priority for a quantum each.

Threads at either priority remain interruptible.

Callers of IoQueueWorkItem must be running at IRQL <= DISPATCH_LEVEL.

IoQueueWorkItem should be used instead of ExQueueWorkItem because IoQueueWorkItem will ensure that the device object associated with the specified work item is available for the processing of the work item.

See Also

IoAllocateWorkItem, IoFreeWorkItem


IoRaiseHardError

IoRaiseHardError causes a popup to be displayed that warns the user that a device I/O error has occurred, which might indicate that a physical device is failing.

VOID
  IoRaiseHardError(
    IN PIRP  Irp,
    IN PVPB  Vpb  OPTIONAL,
    IN PDEVICE_OBJECT  RealDeviceObject
    );

Parameters

Irp
Points to the IRP that failed because of a device I/O error.
Vpb
Points to the volume parameter block (VPB), if any, for the mounted file object. This parameter is NULL if no VPB is associated with the device object.
RealDeviceObject
Points to the device object that represents the physical device on which the I/O operation failed.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

Highest-level drivers, particularly file system drivers, call IoRaiseHardError.

Warning: Because IoRaiseHardError uses a normal kernel APC to create a user popup, a deadlock can occur if normal kernel APCs are disabled when a device error occurs. For example:

  1. An upper-level filter driver calls KeEnterCriticalRegion (which disables normal kernel APCs) and sends an I/O request to a file system driver. The filter driver waits on the completion of the request by the file system driver before the filter driver calls KeLeaveCriticalRegion (which re-enables normal kernel APCs).
  2. An error occurs on the file system and the file system driver calls IoRaiseHardError to report the error to the user. The file system driver waits on the popup.
  3. Deadlock now exists: The normal kernel APC created by IoRaiseHardError to create the popup waits for normal kernel APCs to be enabled. The file system waits on the popup before it completes the I/O request. The filter driver waits on completion of the I/O request before it calls KeLeaveCriticalRegion (which re-enables normal kernel APCs).

The behavior of this routine is dependent of the current state of hard errors for the running thread. If hard errors have been disabled by calling IoSetThreadHardErrorMode, this routine completes the IRP specified by Irp without transferring any data into user buffers. In addition, no message is sent to notify the user of this failure.

Callers of IoRaiseHardError must be running at IRQL < DISPATCH_LEVEL.

See Also

IoGetRelatedDeviceObject, IoSetHardErrorOrVerifyDevice, IoSetThreadHardErrorMode


IoRaiseInformationalHardError

IoRaiseInformationalHardError sends a popup to the user, warning about a device I/O error that indicates why a user I/O request failed.

BOOLEAN
  IoRaiseInformationalHardError(
    IN NTSTATUS  ErrorStatus,
    IN PUNICODE_STRING  String  OPTIONAL,
    IN PKTHREAD  Thread  OPTIONAL
    );

Parameters

ErrorStatus
Identifies the error status (IO_ERR_XXX).
String
Points to a Unicode string, which provides additional information about the error. Some NT status codes require a string parameter, such as a file or directory name. If the ErrorStatus does not require a parameter, then String is NULL.
Thread
Points to the thread whose IRP was failed due to the error.

Return Value

IoRaiseInformationalHardError returns TRUE if the popup was successfully queued. This routine returns FALSE if popups are disabled for Thread, a pool allocation failed, too many popups are already queued, or an equivalent popup is already pending a user response (such as waiting for the user to press RETURN).

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

IoRaiseInformationalHardError takes a system-defined NT error value as a parameter. Driver writers can use the event log APIs to communicate driver-defined event strings to the user.

If hard errors have been disabled for this thread, by calling IoSetThreadHardErrorMode, this routine returns FALSE.

Callers of IoRaiseInformationalHardError must be running at IRQL < DISPATCH_LEVEL.

See Also

IoSetHardErrorOrVerifyDevice, IoSetThreadHardErrorMode, PsGetCurrentThread


IoReadDiskSignature

IoReadDiskSignature reads the disk signature information for the partition table of a disk.

NTKERNELAPI
NTSTATUS
  IoReadDiskSignature(
    IN PDEVICE_OBJECT  DeviceObject,
    IN ULONG  BytesPerSector,
    OUT PDISK_SIGNATURE  Signature
    );

Parameters

DeviceObject
Specifies the device object for the disk to read.
BytesPerSector
Specifies the number of bytes per sector of the disk.
Signature
Pointer to a DISK_SIGNATURE structure the routine uses to return the disk signature information.

Return Value

The routine returns STATUS_SUCCESS on success, or the appropriate error code on failure. The routine returns STATUS_DISK_CORRUPT_ERROR if it detects that the disk partition table is corrupted.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

This routine is only available on Windows XP and later.

IoReadDiskSignature must only be used by disk drivers. Other drivers should use the IOCTL_DISK_GET_DRIVE_GEOMETRY_EX I/O request instead.

See Also

DISK_SIGNATURE, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX


IoReadPartitionTable

IoReadPartitionTable is obsolete and is provided only to support existing drivers. New drivers must use IoReadPartitionTableEx. IoReadPartitionTable reads a list of partitions on a disk having a specified sector size and creates an entry in the partition list for each recognized partition.

NTSTATUS
  IoReadPartitionTable(
    IN PDEVICE_OBJECT  DeviceObject,
    IN ULONG  SectorSize,
    IN BOOLEAN  ReturnRecognizedPartitions,
    OUT struct _DRIVE_LAYOUT_INFORMATION  **PartitionBuffer
    );

Parameters

DeviceObject
Points to the device object for the disk whose partitions are to be read.
SectorSize
Specifies the size of the sectors on the disk.
ReturnRecognizedPartitions
Indicates whether only recognized partitions or all partition entries should be returned.
PartitionBuffer
Is a pointer to an uninitialized address. If successful, IoReadPartitionTable allocates the memory for this buffer from nonpaged pool and returns the drive layout information in it.

Return Value

This routine returns a value of STATUS_SUCCESS if at least one sector table was read. Otherwise, it returns an error status and sets the pointer at PartitionBuffer to NULL.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

IoReadPartitionTable must only be used by disk drivers. Other drivers should use the IOCTL_DISK_GET_DRIVE_LAYOUT disk I/O request instead.

Disk device drivers call this routine during driver initialization.

It is the responsibility of the caller to deallocate the PartitionBuffer that was allocated by this routine with ExFreePool.

The algorithm used by this routine is determined by the Boolean value ReturnRecognizedPartitions:

  • Read each partition table and, for each valid and recognized partition found, fill in an element in an array of PARTITION_INFORMATION entries. The array of partition information entries is pointed to by the PartitionEntry member of a DRIVE_LAYOUT_INFORMATION structure. The DRIVE_LAYOUT_INFORMATION structure is found at the location pointed to by PartitionBuffer. Extended partitions are located in order to find other partition tables, but no entries are built for them.
  • Read each partition table and, for each and every entry, fill in a partition information entry. Extended partitions are located to find each partition on the disk; entries are built for these as well.

Callers of IoReadPartitionTable must be running at IRQL PASSIVE_LEVEL.

See Also

IOCTL_DISK_GET_PARTITION_INFO, IOCTL_DISK_GET_DRIVE_LAYOUT, IOCTL_DISK_SET_DRIVE_LAYOUT, IoSetPartitionInformation, IoWritePartitionTable


IoReadPartitionTableEx

IoReadPartitionTableEx reads a list of partitions on a disk having a specified sector size and creates an entry in the partition list for each recognized partition.

NTSTATUS
  IoReadPartitionTableEx(
    IN PDEVICE_OBJECT  DeviceObject,
    IN struct _DRIVE_LAYOUT_INFORMATION_EX  **PartitionBuffer
    );

Parameters

DeviceObject
Points to the device object for the disk whose partitions are to be read.
PartitionBuffer
Is a pointer to an uninitialized address. If successful, IoReadPartitionTableEx allocates the memory for this buffer from nonpaged pool and returns the drive layout information in it.

Return Value

This routine returns a value of STATUS_SUCCESS if at least one sector table was read. Otherwise, it returns an error status and sets the pointer at PartitionBuffer to NULL.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

IoReadPartitionTableEx must only be used by disk drivers. Other drivers should use the IOCTL_DISK_GET_DRIVE_LAYOUT_EX disk I/O request instead.

IoReadPartitionTableEx is able to read partition table information from GUID Partition Table (GPT) disks as well as legacy Master Boot Record (MBR) disks. Disk device drivers call this routine during driver initialization.

It is the responsibility of the caller to deallocate the PartitionBuffer that was allocated by this routine with ExFreePool.

Note that disk drivers also return and set partition information in response to IRP_MJ_DEVICE_CONTROL requests with the following I/O control codes:

IOCTL_DISK_GET_PARTITION_INFO_EX
IOCTL_DISK_SET_PARTITION_INFO_EX
IOCTL_DISK_GET_DRIVE_LAYOUT_EX
IOCTL_DISK_SET_DRIVE_LAYOUT_EX
IOCTL_DISK_GET_DRIVE_GEOMETRY

Callers of IoReadPartitionTableEx must be running at IRQL PASSIVE_LEVEL.

See Also

DRIVE_LAYOUT_INFORMATION_EX, PARTITION_INFORMATION_EX,

IOCTL_DISK_GET_PARTITION_INFO_EX, IOCTL_DISK_SET_PARTITION_INFO_EX, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, IOCTL_DISK_GET_DRIVE_GEOMETRY, IoSetPartitionInformation, IoWritePartitionTableEx


IoRegisterBootDriverReinitialization

IoRegisterBootDriverReinitialization is called by a boot driver to register the driver's reinitialization routine with the I/O manager to be called after all devices have been enumerated and started.

VOID
  IoRegisterBootDriverReinitialization(
    IN PDRIVER_OBJECT  DriverObject,
    IN PDRIVER_REINITIALIZE  DriverReinitializationRoutine,
    IN PVOID  Context
    );

Parameters

DriverObject
Pointer to the driver object for the boot driver to be reinitialized.
DriverReinitializationRoutine
Pointer to a caller-supplied reinitialization routine. This routine is defined as follows:
VOID
(*PDRIVER_REINITIALIZE) (
    IN struct _DRIVER_OBJECT *DriverObject,
    IN PVOID Context,
    IN ULONG Count
    );

The DriverReinitializationRoutine parameters are as follows:

DriverObject
Pointer to the file system filter driver's driver object.
Context
Optional context pointer.
Count
Number of times this routine has been called, including the current call.
Context
Optional context pointer to be passed to the driver's reinitialization routine.

Headers

Declared in ntddk.h and ntifs.h. Include ntddk.h or ntifs.h.

Comments

A boot driver normally calls IoRegisterBootDriverReinitialization from its DriverEntry routine, which is executed during boot driver initialization. IoRegisterBootDriverReinitialization registers the driver's reinitialization callback routine to be called by the I/O manager after all devices have been enumerated and started. The DriverReinitializationRoutine is run in a system thread at IRQL PASSIVE_LEVEL.

A driver should call IoRegisterBootDriverReinitialization only if its DriverEntry routine will return STATUS_SUCCESS.

If the DriverReinitializationRoutine uses the registry, the DriverEntry routine must include in IoRegisterBootDriverReinitialization's Context parameter a copy of the string to which DriverEntry's own RegistryPath parameter points.

The DriverEntry routine can call IoRegisterBootDriverReinitialization only once. If the reinitialization routine needs to be run more than once, the DriverReinitializationRoutine can call IoRegisterBootDriverReinitialization as many additional times as needed, using the Count parameter to keep track of the number of times the DriverReinitializationRoutine has been called.

Callers of IoRegisterBootDriverReinitialization must be running at IRQL PASSIVE_LEVEL.

See Also

DRIVER_OBJECT, IoRegisterDriverReinitialization


IoRegisterDeviceInterface

IoRegisterDeviceInterface registers a device interface class, if it has not been previously registered, and creates a new instance of the interface class, which a driver can subsequently enable for use by applications or other system components.

NTSTATUS
  IoRegisterDeviceInterface(
    IN PDEVICE_OBJECT  PhysicalDeviceObject,
    IN CONST GUID  *InterfaceClassGuid,
    IN PUNICODE_STRING  ReferenceString  OPTIONAL,
    OUT PUNICODE_STRING  SymbolicLinkName
    );

Parameters

PhysicalDeviceObject
Points to the PDO for the device.
InterfaceClassGuid
Points to the class GUID that identifies the functionality (the device interface class) being registered.
ReferenceString
Optionally points to a reference string. Function drivers typically specify NULL for this parameter. Filter drivers must specify NULL.

Reference strings are only used by a few bus drivers, such as swenum, which is a bus driver that uses device interface instances as placeholders for software devices created on demand. When an instance of an interface is opened, the I/O Manager passes the instance's reference string to the driver. The string becomes part of the interface instance's name (as an appended path component). The driver can then use the reference string to differentiate between two interface instances of the same class for a single device.

On Microsoft® Windows® 98/Me systems, the ReferenceString value can be no longer than MAX_PATH characters. There is no length limit on Windows 2000 and later systems.

SymbolicLinkName
Points to a unicode string structure allocated by the caller. If this routine is successful, it initializes the unicode string and allocates the string buffer containing the kernel-mode path to the symbolic link for an instance of the specified device interface class.

The caller must treat SymbolicLinkName as opaque and must not disassemble it.

The caller is responsible for freeing SymbolicLinkName with RtlFreeUnicodeString when it is no longer needed.

Return Value

IoRegisterDeviceInterface returns STATUS_SUCCESS if the call was successful. Possible error return values include:

Error Status | Description
STATUS_INVALID_DEVICE_REQUEST | Possibly indicates that the PhysicalDeviceObject is not a valid PDO pointer.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

IoRegisterDeviceInterface registers a device interface class, if it as not been previously registered, and creates a new instances of the interface class. A driver can call this routine several times for a given device to register several interface classes and create instances of the classes. A function or filter driver typically registers device interfaces in its AddDevice routine. For example, a fault-tolerant volume driver might register an instance of a fault-tolerant-volume interface and an instance of a volume interface for a particular volume.

If the device interface class has not been registered previously, the I/O Manager creates a registry key for it, along with instance-specific persistent storage under the key. Drivers can access this persistent storage using IoOpenDeviceInterfaceRegistryKey.

A driver registers an interface instance once and then calls IoSetDeviceinterfaceState to enable and disable the interface.

Registered interfaces persist across operating system reboots. If the specified interface is already registered, the I/O Manager passes its name in SymbolicLinkName and returns the informational success status STATUS_OBJECT_NAME_EXISTS.

Most drivers use a NULL reference string for a device interface instance. If a driver uses a nonNULL reference string, it must do additional work, including possibly managing its own namespace and security. A filter driver that exposes a device interface must use a NULL ReferenceString to avoid conflicts with other drivers in the device stack.

Callers of this routine are not required to remove the registration for a device interface when it is no longer needed. Device interface registrations can be removed from user mode, if necessary.

Callers of IoRegisterDeviceInterface must be running at IRQL PASSIVE_LEVEL in the context of a system thread.

See Also

IoGetDeviceInterfaces, IoOpenDeviceInterfaceRegistryKey, IoSetDeviceinterfaceState, RtlFreeUnicodeString


IoRegisterDriverReinitialization

IoRegisterDriverReinitialization is called by a driver during its initialization or reinitialization to register its Reinitialize routine to be called again before the driver's and, possibly the system's, initialization is complete.

VOID
  IoRegisterDriverReinitialization(
    IN PDRIVER_OBJECT  DriverObject,
    IN PDRIVER_REINITIALIZE  DriverReinitializationRoutine,
    IN PVOID  Context
    );

Parameters

DriverObject
Points to the driver object that was input to the DriverEntry routine.
DriverReinitializationRoutine
Specifies the entry point for the driver-supplied Reinitialize routine, which is declared as follows:
VOID
(*PDRIVER_REINITIALIZE)(
    IN PDRIVER_OBJECT DriverObject,
    IN PVOID Context,
    IN ULONG Count
    );
Context
Points to the context to be passed to the driver's Reinitialize routine.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

A driver can call this routine only if its DriverEntry routine will return STATUS_SUCCESS. If the driver-supplied Reinitialize routine must use the registry, the DriverEntry routine should include a copy of the string to which RegistryPath points as part of the context passed to the Reinitialize routine in this call.

If the driver is loaded dynamically, it is possible for this to occur during a normally running system, so all references to the reinitialization queue must be synchronized.

The Count input to a DriverReinitializationRoutine indicates how many times this routine has been called, including the current call.

The DriverEntry routine can call IoRegisterDriverReinitialization only once. If the Reinitialize routine should be run again after any other drivers' Reinitialize routines have returned control, the Reinitialize routine also can call IoRegisterDriverReinitialization as many times as the driver's Reinitialize routine should be run.

Usually, a driver with a Reinitialize routine is a higher-level driver that controls both PnP and legacy devices. Such a driver must not only create device objects for the devices that the PnP Manager detects (and for which the PnP Manager calls the driver's AddDevice routine), the driver must also create device objects for legacy devices that the PnP Manager does not detect. A driver can use a Reinitialize routine to create those device objects and layer the driver over the next-lower driver for the underlying device.

Callers of IoRegisterDriverReinitialization must be running at IRQL PASSIVE_LEVEL.

See Also

IoRegisterBootDriverReinitialization, DRIVER_OBJECT


IoRegisterPlugPlayNotification

IoRegisterPlugPlayNotification registers a driver callback routine to be called when a PnP event of the specified category occurs.

NTSTATUS
  IoRegisterPlugPlayNotification(
    IN IO_NOTIFICATION_EVENT_CATEGORY  EventCategory,
    IN ULONG  EventCategoryFlags,
    IN PVOID  EventCategoryData  OPTIONAL,
    IN PDRIVER_OBJECT  DriverObject,
    IN PDRIVER_NOTIFICATION_CALLBACK_ROUTINE  CallbackRoutine,
    IN PVOID  Context,
    OUT PVOID  *NotificationEntry
    );

Parameters

EventCategory
Specifies the category of PnP event for which the callback routine is being registered. EventCategory must be one of the following:
EventCategoryDeviceInterfaceChange
PnP events in this category include the arrival (enabling) of a new instance of a device interface class (GUID_DEVICE_INTERFACE_ARRIVAL), or the removal (disabling) of an existing device interface instance (GUID_DEVICE_INTERFACE_REMOVAL).
EventCategoryHardwareProfileChange
PnP events in this category include query-change (GUID_HWPROFILE_QUERY_CHANGE), change-complete (GUID_HWPROFILE_CHANGE_COMPLETE), and change-cancel (GUID_HWPROFILE_CHANGE_CANCELLED) of a hardware profile.
EventCategoryTargetDeviceChange
PnP events in this category include events related to removing a device: the device's drivers received a query-remove IRP (GUID_TARGET_DEVICE_QUERY_REMOVE), the drivers completed a remove IRP (GUID_TARGET_DEVICE_REMOVE_COMPLETE), or the drivers received a cancel-remove IRP (GUID_TARGET_DEVICE_REMOVE_CANCELLED). This category is also used for custom notification events.
EventCategoryFlags
Specifies flags that modify the registration operation. Possible values include:
PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
Only valid with an EventCategory of EventCategoryDeviceInterfaceChange. If set, the PnP Manager calls the driver callback routine for each device interface instance that is currently registered and active and registers the callback routine for future arrivals or removals of device interface instances.
EventCategoryData
Points to further information about the events for which CallbackRoutine is being registered. The information varies for different EventCategory values:
  • When EventCategory is EventCategoryDeviceInterfaceChange, EventCategoryData must point to a GUID specifying a device interface class. CallbackRoutine will be called when an interface of that class is enabled or removed.
  • When EventCategory is EventCategoryHardwareProfileChange, EventCategoryData must be NULL.
  • When EventCategory is EventCategoryTargetDeviceChange, EventCategoryData must point to the file object for which PnP notification is requested.
DriverObject
Points to the caller's driver object.

To ensure that the driver remains loaded while it is registered for PnP notification, this call increments the reference count on DriverObject. The PnP Manager decrements the reference count when this registration is removed.

CallbackRoutine
Points to the routine to be called when the specified PnP event occurs.

A callback routine has the following type:

typedef NTSTATUS (*PDRIVER_NOTIFICATION_CALLBACK_ROUTINE) (
    IN PVOID NotificationStructure,
    IN PVOID Context
    );

The NotificationStructure is specific to the EventCategory. For example, a callback routine for an EventCategoryDeviceInterfaceChange receives a DEVICE_INTERFACE_CHANGE_NOTIFICATION structure.

The Context parameter contains the context data the driver supplied during registration.

The PnP Manager calls driver callback routines at IRQL PASSIVE_LEVEL.

Context
Points to a caller-allocated buffer containing context that the PnP Manager passes to the callback routine.
NotificationEntry
Points to an opaque value returned by this call that identifies the registration. Pass this value to IoUnregisterPlugPlayNotification to remove the registration.

Return Value

IoRegisterPlugPlayNotification returns STATUS_SUCCESS or an appropriate error status.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

A driver registers for an event category. Each category includes one or more PnP events.

A driver can register different callback routines for different event categories or can register a single callback routine. A single callback routine can cast the NotificationStructure to a PLUGPLAY_NOTIFICATION_HEADER and use the Event field to determine the exact type of the notification structure.

Notification callback routines should complete their tasks as quickly as possible and return control to the PnP Manager, to prevent delays in notifying other drivers and applications that have registered for the event.

The PnP Manager does not take out a reference on the file object when a driver registers for notification of an EventCategoryTargetDeviceChange. If the driver's notification callback routine requires access to the file object, the driver should take out an extra reference on the file object before calling IoRegisterPlugPlayNotification.

For more information, see Using PnP Notification.

Callers of IoRegisterPlugPlayNotification must be running at IRQL PASSIVE_LEVEL.

See Also

DEVICE_INTERFACE_CHANGE_NOTIFICATION, HWPROFILE_CHANGE_NOTIFICATION, IoUnregisterPlugPlayNotification, PLUGPLAY_NOTIFICATION_HEADER, TARGET_DEVICE_CUSTOM_NOTIFICATION, TARGET_DEVICE_REMOVAL_NOTIFICATION


IoRegisterShutdownNotification

IoRegisterShutdownNotification registers a driver-supplied DispatchShutdown routine to be called before system shutdown; the driver gains control before the system is fully shut down.

NTSTATUS
  IoRegisterShutdownNotification(
    IN PDEVICE_OBJECT  DeviceObject
    );

Parameters

DeviceObject
Points to a device object.

Return Value

IoRegisterShutdownNotification returns STATUS_SUCCESS when the shutdown routine is registered.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

Only highest-level drivers chained above an underlying nonmass-storage device can register a shutdown routine by calling IoRegisterShutdownNotification. For mass-storage drivers, an FSD handles shutdown requests and calls lower drivers to flush cached or buffered data out to the device before the system is shut down.

IoRegisterShutdownNotification places the given DeviceObject on the shutdown notficiation queue, so that its DispatchShutdown routine can be called before the system shuts down. A driver can call IoRegisterShutdownNotification multiple times.

The registered DispatchShutdown routine is called before the Power Manager sends an IRP_MN_SET_POWER request for PowerSystemS5. The DispatchShutdown routine is not called for transitions to any other power states.

A driver can make no assumptions about the order in which its DispatchShutdown routine will be called in relation to other such routines or to other shutdown activities.

A PnP driver might register a shutdown routine so that it can do certain tasks before system shutdown starts, such as locking down code.

Callers of IoRegisterShutdownNotification must be running at IRQL PASSIVE_LEVEL.

See Also

IoUnregisterShutdownNotification


IoReleaseCancelSpinLock

IoReleaseCancelSpinLock releases the cancel spin lock after the driver has changed the cancelable state of an IRP.

VOID
  IoReleaseCancelSpinLock(
    IN KIRQL  Irql
    );

Parameters

Irql
Points to the IRQL returned by IoAcquireCancelSpinLock.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

This routine is a reciprocal to IoAcquireCancelSpinLock.

This routine also releases the cancel spin lock from the driver's Cancel routine.

The holder of the cancel spin lock executes at DISPATCH_LEVEL IRQL after calling IoAcquireCancelSpinLock. IoReleaseCancelSpinLock restores the original IRQL of its caller.

Callers of IoReleaseCancelSpinLock must be running at IRQL DISPATCH_LEVEL.

See Also

IoAcquireCancelSpinLock, IoSetCancelRoutine


IoReleaseRemoveLock

IoReleaseRemoveLock releases a remove lock acquired with a previous call to IoAcquireRemoveLock.

VOID
  IoReleaseRemoveLock(
    IN PIO_REMOVE_LOCK  RemoveLock,
    IN PVOID  Tag
    );

Parameters

RemoveLock
Points to an IO_REMOVE_LOCK structure that the caller passed to a previous call to IoAcquireRemoveLock.
Tag
Points to a caller-supplied tag that was passed to a previous call to IoAcquireRemoveLock.

If a driver specified a Tag when it acquired the lock, the driver must specify the same Tag when releasing the lock. If the tags do not match, this routine asserts on a checked build.

If the call to IoAcquireRemoveLock did not specify a Tag, then this parameter is NULL.

The I/O system only uses this parameter on checked builds.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

A driver calls IoReleaseRemoveLock when it has completed the I/O operation for which it called IoAcquireRemoveLock.

  • For I/O operations (including power and PnP IRPs) that set an IoCompletion routine, a driver should call IoReleaseRemoveLock in the IoCompletion routine, after calling IoCompleteRequest.
  • For I/O operations that do not set an IoCompletion routine, a driver should call IoReleaseRemoveLock after passing the current IRP to the next-lower driver, but before exiting the dispatch routine.

Each call to IoAcquireRemoveLock must have a corresponding call to IoReleaseRemoveLock.

IoReleaseRemoveLock decrements the count of outstanding acquisitions of the remove lock. If the count goes to zero and the driver has received an IRP_MN_REMOVE_DEVICE request, IoReleaseRemoveLock sets the event that allows the driver's remove dispatch code to detach and delete the device object. IoReleaseRemoveLock does not delete the lock; it decrements the count.A driver calls a similar routine, IoReleaseRemoveLockAndWait, only in its dispatch code for an IRP_MN_REMOVE_DEVICE request. A driver calls IoReleaseRemoveLockAndWait to ensure that all outstanding locks have been released before it detaches and deletes the device object.

Callers of IoReleaseRemoveLock must be running at IRQL <= DISPATCH_LEVEL.

SeeAlso

IoAcquireRemoveLock, IoInitializeRemoveLock, IoReleaseRemoveLockAndWait


IoReleaseRemoveLockAndWait

IoReleaseRemoveLockAndWait releases a remove lock acquired with a previous call to IoAcquireRemoveLock and waits until all acquisitions of the lock have been released.

VOID
  IoReleaseRemoveLockAndWait(
    IN PIO_REMOVE_LOCK  RemoveLock,
    IN PVOID  Tag
    );

Parameters

RemoveLock
Points to an IO_REMOVE_LOCK structure that the caller passed to a previous call to IoAcquireRemoveLock.
Tag
Points to a caller-supplied tag that was passed to a previous call to IoAcquireRemoveLock.

If a driver specified a Tag when it acquired the lock, the driver must specify the same Tag when releasing the lock. If the tags do not match, this routine asserts on a checked build.

If the call to IoAcquireRemoveLock did not specify a Tag, then this parameter is NULL.

The I/O system only uses this parameter on checked builds.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

A driver typically calls this routine in its dispatch code for an IRP_MN_REMOVE_DEVICE request. A driver should call IoReleseRemoveLockAndWait after it passes the remove IRP to the next-lower driver but before it releases memory, calls IoDetachDevice, or calls IoDeleteDevice.

A driver must acquire the remove lock once more before calling IoReleaseRemoveLockAndWait. Typically, a driver calls IoAcquireRemoveLock early in its DispatchPnp routine, before the switch statement. Then the lock is acquired for each PnP operation, including the acquisition required before calling IoReleaseRemoveLockAndWait in the code that handles the IRP_MN_REMOVE_DEVICE.

To release a lock from code other than the IRP_MN_REMOVE_DEVICE dispatch code, use IoReleaseRemoveLock.

Callers of IoReleaseRemoveLockAndWait must be running at IRQL PASSIVE_LEVEL.

SeeAlso

IoAcquireRemoveLock, IoInitializeRemoveLock, IoReleaseRemoveLock


IoReleaseRemoveLockAndWaitEx

This routine is reserved for system use. See IoReleaseRemoveLockAndWait.


IoReleaseRemoveLockEx

This routine is reserved for system use. See IoReleaseRemoveLock.


IoRemoveShareAccess

IoRemoveShareAccess removes the access and share-access information for a given open instance of a file object.

VOID
  IoRemoveShareAccess(
    IN PFILE_OBJECT  FileObject,
    IN OUT PSHARE_ACCESS  ShareAccess
    );

Parameters

FileObject
Points to the file object, which usually is being closed by the current thread.
ShareAccess
Points to the share-access structure that describes how the open file object is currently being accessed.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

This routine is a reciprocal to IoUpdateShareAccess.

IoRemoveShareAccess is not an atomic operation. Therefore, drivers calling this routine must protect the shared file object passed to IoRemoveShareAccess by means of some kind of lock, such as a mutex or a resource lock, in order to prevent corruption of the shared access counts.

Callers of IoRemoveShareAccess must be running at IRQL PASSIVE_LEVEL and in the context of the thread that requested that the FileObject be closed.

See Also

IoCheckShareAccess, IoSetShareAccess, IoUpdateShareAccess


IoReportDetectedDevice

IoReportDetectedDevice reports a non-PnP device to the PnP Manager.

NTSTATUS
  IoReportDetectedDevice(
    IN PDRIVER_OBJECT  DriverObject,
    IN INTERFACE_TYPE  LegacyBusType,
    IN ULONG  BusNumber,
    IN ULONG  SlotNumber,
    IN PCM_RESOURCE_LIST  ResourceList,
    IN PIO_RESOURCE_REQUIREMENTS_LIST  ResourceRequirements  OPTIONAL,
    IN BOOLEAN  ResourceAssigned,
    IN OUT PDEVICE_OBJECT  *DeviceObject
    );

Parameters

DriverObject
Points to the driver object of the driver that detected the device.
LegacyBusType
Specifies the type of bus on which the device resides. The PnP Manager uses this information to match the reported device to its PnP-enumerated instance, if one exists.

The interface types, such as PCIBus, are defined in ntddk.h. If a driver does not know the LegacyBusType for the device, the driver supplies the value InterfaceTypeUndefined for this parameter.

BusNumber
Specifies the bus number for the device. The PnP Manager uses this information to match the reported device to its PnP-enumerated instance, if one exists.

The bus number distinguishes the bus on which the device resides from other buses of the same type on the machine. The bus-numbering scheme is bus-specific. If a driver does not know the BusNumber for the device, the driver supplies the value -1 for this parameter.

SlotNumber
Specifies the logical slot number of the device. The PnP Manager uses this information to match the reported device to its PnP-enumerated instance, if one exists.

If a driver does not know the SlotNumber for the device, the driver supplies the value -1 for this parameter.

ResourceList
Points to the resource list the driver used to detect the device. Resources in this list are in raw, untranslated form.
ResourceRequirements
Optionally points to a resource requirements list for the detected device. NULL if the caller does not have this information for the device.
ResourceAssigned
Specifies whether the device's resources have already been reported to the PnP Manager. If ResourceAssigned is TRUE, the resources have already been reported, possibly with IoReportResourceForDetection, and the PnP Manager will not attempt to claim them on behalf of the device. If TRUE, the PnP Manager will also not claim resources when the device is root-enumerated on subsequent boots.
DeviceObject
Optionally points to a PDO for the detected device.

NULL if the caller does not have a PDO for the device, which is typically the case. If DeviceObject is NULL, the PnP Manager creates a PDO for the device and returns a pointer to the caller.

If the caller supplies a PDO, the PnP Manager does not create a new PDO. On a given call to this routine the DeviceObject parameter is either an IN or an OUT parameter, but not both.

Return Value

IoReportDetectedDevice returns STATUS_SUCCESS or an appropriate error status.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

A driver should only call IoReportDetectedDevice to report a legacy, nonPnP device. All PnP devices should be enumerated in response to an IRP_MN_QUERY_DEVICE_RELATIONS request.

A driver must only do detection on a device if the DoDetectionNow flag is set in the registry. This flag is typically set in the Services subkey for the driver by an installer. After reporting detected devices the driver must clear the flag. The location of this flag is driver-defined.

A driver typically calls this routine from its DriverEntry routine. A few drivers, like certain NDIS or EISA drivers, might call this routine from an AddDevice routine.

On successful completion of IoReportDetectedDevice, the caller should attach an FDO to the PDO returned at DeviceObject. Once the caller attaches its FDO, the caller is the function driver for the device, at least temporarily. There are no filter drivers. The PnP Manager owns the PDO.

The PnP Manager considers the device to be started and therefore does not call the driver's AddDevice routine and does not send an IRP_MN_START_DEVICE request. The driver must be prepared to handle all other PnP IRPs, however.

IoReportDetectedDevice marks the device as a root-enumerated device and this identification is persistent across system boots. During subsequent system boots the PnP Manager "detects" the device on the root-enumerated list and configures it like a PnP device: the PnP Manager queries for device information, identifies the appropriate drivers and calls their AddDevice routines, and sends all the appropriate PnP IRPs. The driver that orignally detected the device might or might not be in the device stack on subsequent boots. It depends on the device's hardware ID and the resulting INF match, as is true when configuring any PnP device.

In certain situations the PnP Manager removes the reporting driver from the device stack and builds a full device stack without waiting for the system to reboot. (For example, when the user-mode PnP Manager detects the new device.) In such cases, the PnP Manager sends IRP_MN_QUERY_ID requests to determine the device's hardware ID and compatible IDs searches for an INF match. If it finds a match, it sends an IRP_MN_QUERY_REMOVE_DEVICE and an IRP_MN_REMOVE_DEVICE to the device stack to remove the existing drivers (which at this point are only the driver that called IoReportDetectedDevice and the parent bus driver). The PnP Manager then rebuilds the device stack using information in the INF file and the registry.

Callers of IoReportDetectedDevice must be running at IRQL PASSIVE_LEVEL in the context of a system thread.

See Also

IoReportResourceForDetection, IRP_MN_QUERY_DEVICE_RELATIONS


IoReportResourceForDetection

IoReportResourceForDetection claims hardware resources in the configuration registry for a legacy device.

NTSTATUS
  IoReportResourceForDetection(
    IN PDRIVER_OBJECT  DriverObject,
    IN PCM_RESOURCE_LIST  DriverList  OPTIONAL,
    IN ULONG  DriverListSize  OPTIONAL,
    IN PDEVICE_OBJECT  DeviceObject  OPTIONAL,
    IN PCM_RESOURCE_LIST  DeviceList  OPTIONAL,
    IN ULONG  DeviceListSize  OPTIONAL,
    OUT PBOOLEAN  ConflictDetected
    );

Parameters

DriverObject
Points to the driver object that was input to the driver's DriverEntry routine.
DriverList
Optionally points to a caller-supplied buffer containing the driver's resource list, if the driver claims the same resources for all its devices. If the caller specifies a DeviceList, this parameter is ignored.
DriverListSize
Specifies the size in bytes of an optional DriverList. If DriverList is NULL, this parameter should be zero.
DeviceObject
Optionally points to the device object representing device for which the driver is attempting to claim resources.
DeviceList
Optionally points to the a caller-supplied buffer containing the device's resource list. If the driver claims the same resources for all its devices, the caller can specify a DriverList instead.
DeviceListSize
Specifies the size in bytes of an optional DeviceList. If DeviceList is NULL, this parameter should be zero.
ConflictDetected
Points to a caller-supplied BOOLEAN value set to TRUE on return if the resources are not available.

Return Value

IoReportResourceForDetection returns STATUS_SUCCESS if the resources are claimed. Possible error return values include:

Error Status | Description
STATUS_CONFLICTING_ADDRESSES | The resources could not be claimed because they are already in use or are needed for a PnP-enumerable device.
STATUS_UNSUCCESSFUL | The DeviceList or DriverList is invalid.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

This routine is for drivers that detect legacy hardware which cannot be enumerated by PnP.

If a driver supports only PnP hardware, it does no detection and therefore does not call IoReportResourceForDetection. The PnP system enumerates each PnP device, assigns resources to the device, and passes those resources to the device's driver(s) in an IRP_MN_START_DEVICE request.

If a PnP driver supports legacy hardware, however, it must call IoReportResourceForDetection to claim hardware resources before it attempts to detect the device.

Callers of this routine specify a CM_RESOURCE_LIST in either a DeviceList or a DriverList, allocated from paged memory. The caller is responsible for freeing the memory.

A driver that can control more than one legacy card at the same time should claim the resources for each device against the device object for the respective device (using a the DeviceObject, DeviceList, and DeviceListSize parameters). Such a driver must not claim these resources against their driver object.

A CM_RESOURCE_LIST contains two variable-sized arrays. Each array has a default size of one. If either array has more than one element, the caller must allocate memory dynamically to contain the additional elements. Only one CM_PARTIAL_RESOURCE_DESCRIPTOR can be part of each CM_FULL_RESOURCE_DESCRIPTOR in the list, except for the last full resource descriptor in the CM_RESOURCE_LIST, which can have additional partial resource descriptors in its array.

IoReportResourceForDetection, with the help of the PnP Manager, determines whether the resources being requested conflict with resources that have already been claimed.

If a conflict is detected, this routine sets the BOOLEAN at ConflictDetected to TRUE and returns STATUS_CONFLICTING_ADDRESSES.

If no conflict is detected, this routine claims the resources, sets the BOOLEAN at ConflictDetected to FALSE, and returns STATUS_SUCCESS.

If this routine succeeds and the driver detects a legacy device, the driver reports the device to the PnP Manager by calling IoReportDetectedDevice. In that call, the driver sets ResourceAssigned to TRUE so the PnP Manager does not attempt to claim the resources again.

When a driver no longer requires the resources claimed by a call to this routine, the driver calls this routine again with a DriverList or DeviceList with a Count of zero.

If a driver claims resources on a device-specific basis for more than one device, the driver must call this routine for each such device.

A driver can call this routine more than once for a given device. If one set of resources fails, the driver can call the routine again for the same device with a different set of resources. If a set of resources succeeds, the driver can call this routine again with a new list; the new list replaces the previous list.

Callers of IoReportResourceForDetection must be running at IRQL PASSIVE_LEVEL in the context of a system thread.

See Also

CM_RESOURCE_LIST, IoReportDetectedDevice


IoReportResourceUsage

This routine is obsolete, and is supported only for existing drivers. If a new driver must support a legacy device that is not PnP-enumerable, the driver should call IoReportResourceForDetection to claim resources for the device. IoReportResourceUsage claims hardware resources, such as an interrupt vector, device memory range or a particular DMA controller channel in the \Registry\Machine\Hardware\ResourceMap tree, so that a subsequently loaded driver cannot attempt to use the same resources.

NTSTATUS
  IoReportResourceUsage(
    IN PUNICODE_STRING  DriverClassName  OPTIONAL,
    IN PDRIVER_OBJECT  DriverObject,
    IN PCM_RESOURCE_LIST  DriverList  OPTIONAL,
    IN ULONG  DriverListSize  OPTIONAL,
    IN PDEVICE_OBJECT  DeviceObject,
    IN PCM_RESOURCE_LIST  DeviceList  OPTIONAL,
    IN ULONG  DeviceListSize  OPTIONAL,
    IN BOOLEAN  OverrideConflict,
    OUT PBOOLEAN  ConflictDetected
    );


IoReportTargetDeviceChange

IoReportTargetDeviceChange notifies the PnP Manager that a custom event has occurred on a device.

NTSTATUS
  IoReportTargetDeviceChange(
    IN PDEVICE_OBJECT  PhysicalDeviceObject,
    IN PVOID  NotificationStructure
    );

Parameters

PhysicalDeviceObject
Points to the PDO of the device being reported.
NotificationStructure
Points to a caller-supplied TARGET_DEVICE_CUSTOM_NOTIFICATION structure describing the custom event. The PnP Manager sends this structure to drivers that registered for notification of the event.

NotificationStructure.FileObject must be NULL. NotificationStructure.Event must contain the custom GUID for the event. The other fields of the NotificationStructure must be filled in as appropriate for the custom event.

The PnP Manager fills in the NotificationStructure.FileObject field when it sends notifications to registrants.

Return Value

IoReportTargetDeviceChange returns STATUS_SUCCESS or an appropriate error status. Possible error status values include:

Error Status | Description
STATUS_INVALID_DEVICE_REQUEST | The caller specified a system PnP event, such as GUID_TARGET_DEVICE_QUERY_REMOVE. This routine is only for custom events.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

After IoReportTargetDeviceChange notifies the PnP Manager Manager that a custom event has occurred on a device, the PnP Manager sends notification of the event to drivers that registered for notification on the device. Do not use this routine to report system PnP events, such as GUID_TARGET_DEVICE_REMOVE_COMPLETE.

A driver that defines a custom device event calls IoReportTargetDeviceChange to inform the PnP Manager that the custom event has occurred. Custom notification can be used for events like a volume label change.

A driver should call the asynchronous form of this routine, IoReportTargetDeviceChangeAsynchronous, instead of this routine, to prevent deadlocks.

Certain kernel-mode components can call this synchronous routine. For example, a file system can call IoReportTargetDeviceChange to report a "get off the volume" custom event when a component tries to open the volume for exclusive access. Clients that register for notification on file system volumes are careful to not request an exclusive open in a PnP notification callback routine.

The custom notification structure contains a driver-defined event with its own GUID. Driver writers can generate GUIDs with uuidgen.exe or guidgen.exe.

Callers of IoReportTargetDeviceChange must be running at IRQL PASSIVE_LEVEL in the context of a system thread. To report a target device change from raised IRQL, call IoReportTargetDeviceChangeAsynchronous.

IoReportTargetDeviceChange is not supported on Windows 98/Me; it returns STATUS_NOT_IMPLEMENTED.

See Also

IoReportTargetDeviceChangeAsynchronous, TARGET_DEVICE_CUSTOM_NOTIFICATION


IoReportTargetDeviceChangeAsynchronous

IoReportTargetDeviceChangeAsynchronous notifies the PnP Manager that a custom event has occurred on a device.

NTSTATUS
  IoReportTargetDeviceChangeAsynchronous(
    IN PDEVICE_OBJECT  PhysicalDeviceObject,
    IN PVOID  NotificationStructure,
    IN PDEVICE_CHANGE_COMPLETE_CALLBACK  Callback  OPTIONAL,
    IN PVOID  Context  OPTIONAL
    );

Parameters

PhysicalDeviceObject
Points to the PDO of the device being reported.
NotificationStructure
Points to a caller-supplied TARGET_DEVICE_CUSTOM_NOTIFICATION structure describing the custom event. The PnP Manager sends this structure to drivers that registered for notification of the event.

NotificationStructure.FileObject must be NULL. NotificationStructure.Event must contain the custom GUID for the event. The other fields of the NotificationStructure must be filled in as appropriate for the custom event.

The PnP Manager fills in the NotificationStructure.FileObject field when it sends notifications to registrants.

Callback
Optionally points to a caller-supplied routine that the PnP Manager calls after it finishes notifying drivers that registered for this custom event.

The callback routine has the following type:

typedef
VOID
(*PDEVICE_CHANGE_COMPLETE_CALLBACK)(
    IN PVOID Context
    );

A device-change-complete callback routine should not block and must not call synchronous routines that generate PnP events.

The PnP Manager calls device-change-complete callback routines at IRQL PASSIVE_LEVEL.

Context
Optionally points to a caller-supplied context structure that the PnP Manager passes to the Callback routine. The caller must allocate this structure from nonpaged memory.

Return Value

IoReportTargetDeviceChangeAsynchronous returns STATUS_SUCCESS or an appropriate error status. Possible error status values include:

Error Status | Description
STATUS_INVALID_DEVICE_REQUEST | The caller specified a system PnP event, such as GUID_TARGET_DEVICE_QUERY_REMOVE. This routine is only for custom events.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

After the IoReportTargetDeviceChangeAsynchronous routine notifies the PnP Manager that a custom event has occurred on a device, the routine returns immediately; it does not wait while the PnP Manager sends notification of the event to drivers that registered for notification on the device. Do not use this routine to report system PnP events, such as GUID_TARGET_DEVICE_REMOVE_COMPLETE.

A driver that defines a custom device event calls IoReportTargetDeviceChangeAsynchronous to inform the PnP Manager that the custom event has occurred. Custom notifcation can be used for events like a volume label change.

The custom notification structure contains a driver-defined event with its own GUID. Driver writers can generate GUIDs with uuidgen.exe or guidgen.exe.

When a driver calls this routine while handling an event, an IRP_MN_REMOVE_DEVICE, or an IRP_MN_SURPRISE_REMOVAL, the PnP Manager calls the driver's Callback routine after the driver returns and the stack unwinds.

Callers of IoReportTargetDeviceChangeAsynchronous must be running at IRQL <= DISPATCH_LEVEL. If a driver writer calls this routine at IRQL DISPATCH_LEVEL, the NotificationStructure must be allocated from nonpaged memory.

See Also

IoReportTargetDeviceChange, TARGET_DEVICE_CUSTOM_NOTIFICATION


IoRequestDeviceEject

IoRequestDeviceEject notifies the PnP Manager that the device eject button was pressed.

VOID
  IoRequestDeviceEject(
    IN PDEVICE_OBJECT  PhysicalDeviceObject
    );

Parameters

PhysicalDeviceObject
Points to the PDO for the device.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Note that this routine reports a request for device eject, not media eject.

Typically, a PnP bus driver calls IoRequestDeviceEject to notify the PnP Manager that a user pressed the device eject button on one of its child devices.

A driver calls this routine, rather than sending an IRP_MN_EJECT request, because this routine allows the PnP Manager to coordinate additional actions for the eject besides sending the IRP. For example, the PnP Manager notifies user-mode and kernel-mode components that registered for notification of changes on the device.

The PnP Manager directs an orderly shutdown of the device. The PnP Manager:

  1. Creates a list of other devices that are affected by this device being ejected.

    The PnP Manager queries for the device's removal relations, ejection relations, and bus relations (child devices).

  2. Determines whether the device and its related devices can be software-removed.

    The PnP Manager sends IRP_MN_QUERY_REMOVE_DEVICE IRPs to the drivers for the device and its related devices. The PnP Manager also sends notifications to any user-mode and kernel-mode components that registered for device-change notification on the device or any of its related devices. If any of the drivers or user-mode components fail the query-remove, the PnP Manager pops up a dialog box to notify the user that the eject failed.

  3. Software-removes the device and its related devices.

    If the previous steps are successful, the PnP Manager notifies registered drivers and applications that the device and its related devices are being software-removed. Then the PnP Manager sends IRP_MN_REMOVE_DEVICE IRPs to the drivers for the device and its related devices. Function and filter drivers detach from the device stack and delete their device objects for the device(s). The bus drivers retain the PDO(s) for the device(s), unless a device is physically gone and the bus driver omitted the device in its most recent response to IRP_MN_QUERY_DEVICE_RELATIONS/BusRelations for the device's parent bus.

  4. Directs the bus driver to eject the device (if possible).

    The PnP Manager takes different steps, depending on the eject capabilities of the device:

    • Hot eject is supported.

      If the EjectSupported capability is set for the device, the device can be ejected when the system is running (is in the PowerSystemWorking state). The PnP Manager sends an IRP_MN_EJECT request to the bus driver for the device. Any function and filter drivers detached previously from the stack in response to the remove IRP, so the bus driver handles the eject IRP. When the bus driver completes the IRP, the PnP Manager expects the device to be physically absent from the system.

    • Hot eject is not supported.

      In this case, the device is Removable but does not support eject. The PnP Manager marks the device as not-present/not-working-properly. The PnP Manager will not restart the device until a user physically removes it and reinserts it. In this case, the PnP Manager does not send an IRP_MN_EJECT.

    A device's parent bus driver sets the capabilities for a device, including its eject capabilities, in response to an IRP_MN_QUERY_CAPABILITIES request. A function or filter driver can optionally specify capabilities.

When a device is ejected, its child devices are physically removed from the system along with it.

A user-mode application can initiate a device eject. In that case, no driver calls this routine but the OS calls the PnP Manager to initiate the steps listed above.

Callers of IoRequestDeviceEject must be running at IRQL <= DISPATCH_LEVEL. The PnP Manager performs most of its device-eject tasks listed above at IRQL PASSIVE_LEVEL.

See Also

IRP_MN_EJECT, IRP_MN_QUERY_REMOVE_DEVICE, IRP_MN_QUERY_DEVICE_RELATIONS, IRP_MN_REMOVE_DEVICE


IoRequestDpc

IoRequestDpc queues a driver-supplied DpcForIsr routine from the ISR to complete interrupt-driven I/O processing at a lower IRQL.

VOID
  IoRequestDpc(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp,
    IN PVOID  Context
    );

Parameters

DeviceObject
Points to the device object for which the request that caused the interrupt is being processed.
Irp
Points to the current IRP for the specified device.
Context
Points to a driver-determined context to be passed to the DPC routine.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Callers of IoRequestDpc must be running at DIRQL.

Because IoRequestDpc is called from the device driver's ISR, the DIRQL is the SynchronizeIrql value that was specified when the driver called IoConnectInterrupt. However, it is actually possible to queue a DPC at any IRQL >= DISPATCH_LEVEL using the Ke..Dpc routines.

See Also

IoInitializeDpcRequest, KeInitializeDpc, KeInsertQueueDpc


IoReuseIrp

IoReuseIrp reinitializes an IRP so that it can be reused.

VOID
  IoReuseIrp(
    IN OUT PIRP  Irp,
    IN NTSTATUS  Status
    );

Parameters

Irp
Points to the IRP to be reinitialized for reuse.
Status
Specifies the NTSTATUS value to be set in the IRP after it is reinitialized.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

Drivers for Windows 2000 and later operating systems use IoReuseIrp to reuse an IRP.

A driver should use IoReuseIrp only on IRPs it previously allocated either as raw memory or with IoAllocateIrp. In particular, t should not use this routine for IRPs created with IoMakeAssociatedIrp, IoBuildSynchronousFsdRequest, IoBuildAsynchronousFsdRequest, or IoBuildDeviceIoControlRequest.

See Reusing IRPs for more details on how to reuse IRPs.

Callers of IoReuseIrp must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoInitializeIrp, IoAllocateIrp, IoMakeAssociatedIrp, IRP


IoSetCancelRoutine

IoSetCancelRoutine sets up a driver-supplied Cancel routine to be called if a given IRP is canceled.

PDRIVER_CANCEL
  IoSetCancelRoutine(
    IN PIRP  Irp,
    IN PDRIVER_CANCEL  CancelRoutine
    );

Parameters

Irp
Points to the IRP being put into or removed from a cancelable state.
CancelRoutine
Specifies the entry point of the caller-supplied Cancel routine to be called if the specified IRP is canceled or is NULL if the given IRP is being removed from the cancelable state. This routine is declared as follows:
VOID
(*PDRIVER_CANCEL)(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    );

Return Value

IoSetCancelRoutine returns the previous value of Irp->CancelRoutine. If no Cancel routine was previously set, or if IRP cancellation is already in progress, IoSetCancelRoutine returns NULL.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

This routine can disable the Cancel routine currently set in an IRP.

A driver must hold the system cancel spin lock when calling this routine if the driver uses the I/O-manager-supplied device queue in the device object. The driver executes at IRQL DISPATCH_LEVEL after calling IoAcquireCancelSpinLock until it releases the cancel spin lock with IoReleaseCancelSpinLock.

If the driver manages its own queue(s) of IRPs, then the driver need not hold the cancel spin lock when calling this routine. IoSetCancelSpinLock uses an interlocked exchange intrinsic to set the address of the Cancel routine as an atomic operation. Reduced usage of the cancel spin lock can improve driver performance and overall system performance.

Driver Cancel routines are called at IRQL DISPATCH_LEVEL with the cancel spin lock held. The Cancel routine must release the cancel spin lock before it returns control.

See Also

IoAcquireCancelSpinLock, IoReleaseCancelSpinLock


IoSetCompletionRoutine

IoSetCompletionRoutine registers an IoCompletion routine to be called when the next-lower-level driver has completed the requested operation for the given IRP.

VOID
  IoSetCompletionRoutine(
    IN PIRP  Irp,
    IN PIO_COMPLETION_ROUTINE  CompletionRoutine,
    IN PVOID  Context,
    IN BOOLEAN    InvokeOnSuccess,
    IN BOOLEAN  InvokeOnError,
    IN BOOLEAN  InvokeOnCancel
    );

Parameters

Irp
Points to the IRP that the driver wants to track.
CompletionRoutine
Specifies the entry point for the driver-supplied IoCompletion routine to be called when the next-lower driver completes the packet.
Context
Points to a driver-determined context to pass to the IoCompletion routine.
InvokeOnSuccess
Specifies whether the completion routine is called if the IRP is completed with a success status value in the IRP's IO_STATUS_BLOCK structure, based on results of the NT_SUCCESS macro (defined in ntdef.h).
InvokeOnError
Specifies whether the completion routine is called if the IRP is completed with a non-success status value in the IRP's IO_STATUS_BLOCK structure.
InvokeOnCancel
Specifies whether the completion routine is called if a driver or the kernel has called IoCancelIrp to cancel the IRP.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

This routine sets the transfer address of the IoCompletion routine in the given IRP. The lowest-level driver in a chain of layered drivers cannot call this routine.

IoSetCompletionRoutine registers the specified routine to be called when the next-lower-level driver has completed the requested operation in any or all of the following ways:

  • With a success status value
  • With a non-success status value
  • By canceling the IRP

Usually, the I/O status block is set by the underlying device driver. It is read but not altered by any higher-level drivers' IoCompletion routines.

Higher-level drivers that allocate IRP's with IoAllocateIrp or IoBuildAsynchronousFsdRequest must call this routine with all InvokeOnXxx parameters set to TRUE before passing the driver-allocated IRP to IoCallDriver. When the IoCompletion routine is called with such an IRP, it must free the driver-allocated IRP and any other resources that the driver set up for the request, such as MDLs with IoBuildPartialMdl. Such a driver should return STATUS_MORE_PROCESSING_REQUIRED when it calls IoFreeIrp to forstall the I/O Manager's completion processing for the driver-allocated IRP.

Non-PnP drivers that might be unloaded before their IoCompletion routines execute should use IoSetCompletionRoutineEx instead.

Callers of IoSetCompletionRoutine must be running at IRQL <= DISPATCH_LEVEL.

See Also

IO_STACK_LOCATION, IoAllocateIrp, IoBuildAsynchronousFsdRequest, IRP, IoBuildPartialMdl, IoFreeIrp, IoSetCompletionRoutine


IoSetCompletionRoutineEx

IoSetCompletionRoutineEx registers an IoCompletion routine to be called when the next-lower-level driver has completed the requested operation for the given IRP.

VOID
  IoSetCompletionRoutineEx(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp,
    IN PIO_COMPLETION_ROUTINE  CompletionRoutine,
    IN PVOID  Context,
    IN BOOLEAN    InvokeOnSuccess,
    IN BOOLEAN  InvokeOnError,
    IN BOOLEAN  InvokeOnCancel
    );

Parameters

DeviceObject
Pointer to the driver's device object.
Irp
Pointer to the IRP that the driver wants to track.
CompletionRoutine
Specifies the entry point for the driver-supplied IoCompletion routine to be called when the next-lower driver completes the packet.
Context
Pointer to a driver-determined context to pass to the IoCompletion routine.
InvokeOnSuccess
Specifies whether the completion routine is called if the IRP is completed with a success status value in the IRP's IO_STATUS_BLOCK structure, based on results of the NT_SUCCESS macro (defined in ntdef.h).
InvokeOnError
Specifies whether the completion routine is called if the IRP is completed with a non-success status value in the IRP's IO_STATUS_BLOCK structure.
InvokeOnCancel
Specifies whether the completion routine is called if a driver or the kernel has called IoCancelIrp to cancel the IRP.

Return Value

This routine returns STATUS_SUCCESS on success, or STATUS_INSUFFICIENT_RESOURCES if insufficient memory is available for the operation.

Headers

Declared in ntddk.h and wdm.h. Include ntddk.h or wdm.h.

Comments

This routine is only available on Windows XP and later.

The behavior of IoSetCompletionRoutineEx is the same as IoSetCompletionRoutine, except that it guarantees that a non-Plug and Play driver is not unloaded before the IoCompletion routine executes.

See Also

IO_STACK_LOCATION, IoCompletion, IoAllocateIrp, IoBuildAsynchronousFsdRequest, IRP, IoBuildPartialMdl, IoFreeIrp, IoSetCompletionRoutine


IoSetDeviceInterfaceState

IoSetDeviceInterfaceState enables or disables an instance of a previously registered device interface class.

NTSTATUS
  IoSetDeviceInterfaceState(
    IN PUNICODE_STRING  SymbolicLinkName,
    IN BOOLEAN  Enable
    );

Parameters

SymbolicLinkName
Points to a string identifying the device interface instance being enabled or disabled. This string was obtained from a previous call to IoRegisterDeviceInterface or IoGetDeviceInterfaces.
Enable
TRUE indicates that the device interface is being enabled. FALSE indicates that the device interface is being disabled.

Return Value

IoSetDeviceInterfaceState returns STATUS_SUCCESS if the call was successful. This routine returns an informational status of STATUS_OBJECT_NAME_EXISTS if the caller requested to enable a device interface that was already enabled. Possible error return values include:

Error Status | Description
STATUS_OBJECT_NAME_NOT_FOUND | The caller tried to disable a device interface that was not enabled.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

IoSetDeviceInterfaceState enables an instance of a registered device interface for use by applications and other system components. The interface class must have been previously registered with IoRegisterDeviceInterface or from user mode.

Applications and other system components can open only interfaces that are enabled.

A function or filter driver typically calls this routine with Enable set to TRUE after it successfully starts a device in response to an IRP_MN_START_DEVICE. Such a driver should disable the device interface instance (Enable equals FALSE) when it removes the device in response to an IRP_MN_REMOVE_DEVICE.

If a call to this routine successfully exposes a device interface instance, the system notifies any components that registered for PnP notification of a device class change. Similarly, if a call to this routine disables an existing device interface instance, the system sends appropriate notifications.

The PnP Manager does not send notification of interface instance arrivals until the IRP_MN_START_DEVICE IRP completes, indicating that all the drivers for the device have completed their start operations. In addition, the PnP Manager fails create requests for the device until the IRP_MN_START_DEVICE IRP completes.

Callers of IoSetDeviceInterfaceState must be running at IRQL = PASSIVE_LEVEL in the context of a system thread.

See Also

IoGetDeviceInterfaces, IoRegisterDeviceInterface, IoRegisterPlugPlayNotification


IoSetHardErrorOrVerifyDevice

Lower-level drivers call IoSetHardErrorOrVerifyDevice to identify a removable media device that has encountered an error, so that a file system driver can prompt the user to verify that the medium is valid.

VOID
  IoSetHardErrorOrVerifyDevice(
    IN PIRP  Irp,
    IN PDEVICE_OBJECT  DeviceObject
    );

Parameters

Irp
Points to the IRP for which the driver encountered a user-induced error.
DeviceObject
Points to the target device to be verified for the I/O operation.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

Lower-level drivers for removal media devices must call IoSetHardErrorOrVerifyDevice before completing an IRP, if a call to IoIsErrorUserInduced returns TRUE. For more information, see Supporting Removable Media.

Subsequently, a file system driver will use information supplied in the specified device object to send a popup to the user, who can correct the error and retry the operation or cancel it.

The IRP passed to IoSetHardErrorOrVerifyDevice must be associated with a thread. Therefore, before a driver calls IoSetHardErrorOrVerifyDevice, it must verify that irp->Tail.Overlay.Thread is not NULL. If the value is NULL, IoSetHardErrorOrVerifyDevice must not be called using the current IRP. Instead, the driver should check all IRPs subsequently received and processed, until one is received for which irp->Tail.Overlay.Thread is not NULL. At that point, IoSetHardErrorOrVerifyDevice can be called.

Callers of IoSetHardErrorOrVerifyDevice must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoIsErrorUserInduced, IoRaiseHardError, IoRaiseInformationalHardError


IoSetNextIrpStackLocation

IoSetNextIrpStackLocation sets the IRP stack location in a driver-allocated IRP to that of the caller.

VOID
  IoSetNextIrpStackLocation(
    IN OUT PIRP  Irp
    );

Parameters

Irp
Points to the IRP whose stack location is to be set.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

In general, this routine is seldom used by drivers. It is primarily used by drivers that require their own stack location in an IRP that they have allocated, on their own, to send to another driver.

IoSetNextIrpStackLocation is generally not needed because either:

  • The driver received the IRP it is passing from another, higher-level driver, and so it already owns a stack location,
  • Or, the driver allocated the IRP but does not need its own stack location because it can keep everything that it needs in a context block whose address can be passed to its IoCompletion routine.

Care should be taken if this routine is called, especially when allocating the IRP with IoAllocateIrp or IoMakeAssociatedIrp. The writer of the allocating driver must remember that a caller-specific stack location is not included in the number of stack locations required by the lower-level drivers to which it sends IRPs with IoCallDriver. A driver must explicitly specify a stack location for itself in its call to IoAllocateIrp or IoMakeAssociatedIrp if it calls IoSetNextIrpStackLocation with the IRP returned by either routine.

A driver cannot call IoSetNextIrpStackLocation with any IRP it allocates by calling IoBuildAsynchronousFsdRequest, IoBuildDeviceIoControlRequest, or IoBuildSynchronousFsdRequest.

Callers of IoSetNextIrpStackLocation must be running at IRQL <= DISPATCH_LEVEL.

See Also

IO_STACK_LOCATION, IoAllocateIrp, IoBuildAsynchronousFsdRequest, IoBuildDeviceIoControlRequest, IoBuildSynchronousFsdRequest, IoCallDriver, IoSetCompletionRoutine


IoSetPartitionInformation

IoSetPartitionInformation is obsolete and is provided only to support existing drivers. New drivers must use IoSetPartitionInformationEx.

IoSetPartitionInformation sets the partition type and number in a partition table entry for the disk represented by DeviceObject.

NTSTATUS
  IoSetPartitionInformation(
    IN PDEVICE_OBJECT  DeviceObject,
    IN ULONG  SectorSize,
    IN ULONG  PartitionNumber,
    IN ULONG  PartitionType
    );

Parameters

DeviceObject
Points to the device object representing the device on which the partition type is to be set.
SectorSize
Specifies the size, in bytes, of sectors on the disk.
PartitionNumber
Specifies the partition number on the device whose partition type is to be set.
PartitionType
Specifies the type for the partition. For a list of some of the key partition types see PARTITION_INFORMATION.

Return Value

If IoSetPartitionInformation returns STATUS_SUCCESS, the disk driver updates its notion of the partition type for this partition in its device extension.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

IoSetPartitionInformation must only be used by disk drivers. Other drivers should use the IOCTL_DISK_SET_PARTITION_INFO disk I/O request instead.

This routine is called when a disk device driver is asked to set the partition type in a partition table entry by an IRP_MJ_DEVICE_CONTROL request. This request is generally issued by the format utility, which performs I/O control functions on the partition. The driver passes a pointer to the device object representing the physical disk and the number of the partition associated with the device object that the format utility has open. Since the HAL routines that underlie IoSetPartitionInformation were developed before support of dynamic partitioning was implemented, they do not distinguish between the partition ordinal (that is the order of a partition on a disk) and the partition number (the partition number assigned to a partition in order to identify it to the system). Drivers must call IoSetPartitionInformation using the ordinal number of the partition and not the actual partition number.

This routine is synchronous and must be called by the disk driver's Dispatch routine or by a driver thread. Thus, all user and file system threads must be prepared to enter a wait state when issuing the device control request to set the partition type for the device.

This routine operates under the assumption that the partition number passed in by the disk driver actually exists.

This routine must be called at PASSIVE_LEVEL IRQL because it uses a kernel event object to synchronize I/O completion on the device. The event cannot be set to the Signaled state without queuing and executing the I/O system's special kernel APC routine for I/O completion.

See Also

IoReadPartitionTable, IoWritePartitionTable, IoSetPartitionInformationEx


IoSetPartitionInformationEx

For the disk represented by DeviceObject, IoSetPartitionInformationEx initializes a partition table entry with the information specified in the SET_PARTITION_INFORMATION_EX structure.

NTSTATUS
  IoSetPartitionInformationEx(
    IN PDEVICE_OBJECT  DeviceObject,
    IN ULONG  PartitionNumber,
    IN struct  SET_PARTITION_INFORMATION_EX *PartitionInfo
    );

Parameters

DeviceObject
Points to the device object representing the device on which the partition type is to be set.
PartitionNumber
Specifies the partition number on the device whose partition type is to be set.
PartitionInfo
A structure whose PartitionType member specifies the type for the partition. For the currently defined PartitionType values PARTITION_INFORMATION.

Return Value

If IoSetPartitionInformationEx returns STATUS_SUCCESS, the disk driver updates its notion of the partition type for this partition in its device extension.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

IoSetPartitionInformationEx must only be used by disk drivers. Other drivers should use the IOCTL_DISK_SET_PARTITION_INFO_EX disk I/O request instead.

This routine is called when a disk device driver is requested to set partition information in a partition table entry by an IRP_MJ_DEVICE_CONTROL request. This request is generally issued by the format utility, which performs I/O control functions on the partition. The driver passes a pointer to the device object representing the physical disk and the number of the partition associated with the device object that the format utility has open. Since the HAL routines that underlie IoSetPartitionInformationEx were developed before support for dynamic partitioning was implemented, they do not distinguish between the partition ordinal (that is the order of a partition on a disk) and the partition number (the partition number assigned to a partition in order to identify it to the system). Drivers must call IoSetPartitionInformationEx using the ordinal number of the partition and not the actual partition number.

If the partition is a Master Boot Record (MBR) type partition, IoSetPartitionInformationEx is limited to setting the partition style, and the partition style, which is represented as an unsigned character. See SET_PARTITION_INFORMATION_MBR for further information on these values.

If the partition is a GUID Partition Table (GPT) partition, IoSetPartitionInformationEx sets the following values: the partition style, the partition type, represented by a GUID instead of an integer as was the case with MBR partitions; a partition ID, also represented by a GUID; a set of attributes (see the Extensible Firmware Interface for a description of these attributes); and a Unicode name for the partition. See SET_PARTITION_INFORMATION_GPT for further information on these values.

This routine is synchronous and must be called by the disk driver's Dispatch routine or by a driver thread. Thus, all user and file system threads must be prepared to enter a wait state when issuing the device control request to set the partition type for the device.

This routine operates under the assumption that the partition number passed in by the disk driver actually exists.

This routine must be called at IRQL PASSIVE_LEVEL because it uses a kernel event object to synchronize I/O completion on the device. The event cannot be set to the Signaled state without queuing and executing the I/O system's special kernel APC routine for I/O completion.

See Also

IoReadPartitionTable, IoWritePartitionTable, IoSetPartitionInformation, SET_PARTITION_INFORMATION, SET_PARTITION_INFORMATION_EX


IoSetShareAccess

IoSetShareAccess sets the access rights for sharing the given file object.

VOID
  IoSetShareAccess(
    IN ACCESS_MASK  DesiredAccess,
    IN ULONG  DesiredShareAccess,
    IN OUT PFILE_OBJECT  FileObject,
    OUT PSHARE_ACCESS  ShareAccess
    );

Parameters

DesiredAccess
Specifies the type of access requested for the FileObject. See IoCreateFile for a complete list of system-defined DesiredAccess flags.
DesiredShareAccess
Specifies ACCESS_MASK value that represents the share access to be set for the file object. This value can be zero, one, or more of the following:

FILE_SHARE_READ

FILE_SHARE_WRITE

FILE_SHARE_DELETE

FileObject
Points to the file object whose share access is being set or reset.
ShareAccess
Points to the SHARE_ACCESS structure associated with FileObject. Drivers should treat this structure as opaque.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Only highest-level kernel-mode drivers should call this routine. The call must occur in the context of the first thread that attempts to open the FileObject.

This routine sets the access and share access information when the FileObject is first opened. It returns a pointer to the common share-access data structure associated with FileObject. Callers should save this pointer for later use when updating the access or closing the file.

Generally, FSDs are most likely to call this routine. However, other highest-level drivers can call IoSetShareAccess to control the kind of access allowed to a driver-created device object associated with the given FileObject.

IoSetShareAccess is not an atomic operation. Therefore, drivers calling this routine must protect the shared file object passed to IoSetShareAccess by means of some kind of lock, such as a mutex or a resource lock, in order to prevent corruption of the shared access counts.

Callers of IoSetShareAccess must be running at IRQL PASSIVE_LEVEL.

See Also

ACCESS_MASK, IoCreateFile, IoCheckShareAccess, IoGetFileObjectGenericMapping, IoGetRelatedDeviceObject, IoRemoveShareAccess, IoUpdateShareAccess


IoSetStartIoAttributes

IoSetStartIoAttributes sets attributes for the driver's StartIo routine.

VOID
  IoSetStartIoAttributes(
    IN PDEVICE_OBJECT  DeviceObject,
    IN BOOLEAN  DeferredStartIo,
    IN BOOLEAN  NonCancelable
    );

Parameters

DeviceObject
Pointer to the device object for the driver's device.
DeferredStartIo
If TRUE, the I/O Manager will defer any call to the driver's StartIo routine while the driver is already inside the routine. In particular, if the StartIo routine calls IoStartNextPacket, the StartIo routine will not be called again until the current invocation completes. The default is FALSE.
NonCancelable
If TRUE, the IRP cannot be canceled once it has been dequeued by a call to IoStartNextPacket. The default is FALSE. Drivers that set this member to FALSE must synchronize their IRP handling with the cancel spin lock.

Headers

Declared in ntddk.h and wdm.h. Include ntddk.h or wdm.h.

Comments

This routine is only available for Windows XP and later.

See Also

StartIo, IoStartNextPacket


IoSetSystemPartition

IoSetSystemPartition sets the boot partition for the system.

NTSTATUS
  IoSetSystemPartition(
    PUNICODE_STRING  VolumeNameString
    );

Parameters

VolumeNameString
Pointer to a Unicode string that specifies the MS-DOS name of the system partition.

Return Value

STATUS_SUCCESS if the boot partition can be set, or an error code on failure.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

The specified partition must contain the boot loader.


IoSetThreadHardErrorMode

IoSetThreadHardErrorMode enables or disables hard error reporting for the current thread.

BOOLEAN
  IoSetThreadHardErrorMode(
    IN BOOLEAN  EnableHardErrors
    );

Parameters

EnableHardErrors
Specifies if hard error reporting to the user should be enabled or disabled for this thread.

Return Value

IoSetThreadHardErrorMode returns TRUE if hard errors were enabled from this thread before this routine completed execution.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

If hard errors are disabled for a given thread, calls to IoRaiseHardError will not display a message to the user indicating that a serious error has occurred. In addition, the IRP that is passed to IoRaiseHardError is completed without any data being copied into user buffers. Calling IoRaiseInformationalHardError after disabling hard errors causes that routine to always return FALSE for this thread.

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoRaiseHardError, IoRaiseInformationalHardError


IoSizeOfIrp

IoSizeOfIrp determines the size in bytes for an IRP, given the number of stack locations in the IRP.

USHORT
  IoSizeOfIrp(
    IN CCHAR  StackSize
    );

Parameters

StackSize
Specifies the number of stack locations for the IRP.

Return Value

IoSizeOfIrp returns the size, in bytes, of the IRP.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Callers of IoSizeOfIrp can be running at any IRQL level.

The input StackSize value is either that of the next-lower driver's device object or one more than that value.

See Also

IoAllocateIrp, IoMakeAssociatedIrp


IoSkipCurrentIrpStackLocation

The IoSkipCurrentIrpStackLocation macro modifies the system's IO_STACK_LOCATION array pointer, so that when the current driver calls the next-lower driver, that driver receives the same IO_STACK_LOCATION structure that the current driver received.

VOID
  IoSkipCurrentIrpStackLocation(
    IN PIRP  Irp
    );

Parameters

Irp
Points to the IRP.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

When sending an IRP to the next-lower driver, your driver can call IoSkipCurrentIrpStackLocation if you do not intend to provide an IoCompletion routine (the address of which is stored in the driver's IO_STACK_LOCATION structure). If you call IoSkipCurrentIrpStackLocation before calling IoCallDriver, the next-lower driver receives the same IO_STACK_LOCATION that your driver received.

If you intend to provide an IoCompletion routine for the IRP, your driver should call IoCopyCurrentIrpStackLocationToNext instead of IoSkipCurrentIrpStackLocation.

If your driver calls IoSkipCurrentIrpStackLocation, be careful not to modify the IO_STACK_LOCATION structure in a way that could inadvertently affect the lower driver or the system's behavior with respect to that driver. Examples include modifying the IO_STACK_LOCATION structure's Parameters union or calling IoMarkIrpPending.

Callers of IoSkipCurrentIrpStackLocation must be running at IRQL <= DISPATCH_LEVEL.

See Also

IO_STACK_LOCATION, IoCallDriver, IoCopyCurrentIrpStackLocationToNext


IoStartNextPacket

IoStartNextPacket dequeues the next IRP, if any, from the given device object's associated device queue and calls the driver's StartIo routine.

VOID
  IoStartNextPacket(
    IN PDEVICE_OBJECT  DeviceObject,
    IN BOOLEAN  Cancelable
    );

Parameters

DeviceObject
Points to the device object for which the IRP is to be dequeued.
Cancelable
Specifies whether IRPs in the device queue can be canceled.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

If there are no IRPs currently in the device queue for the target DeviceObject, this routine simply returns control to the caller.

If the driver passed a pointer to a cancel routine when it called IoStartPacket, it should pass TRUE in the Cancelable parameter. If Cancelable is TRUE, the I/O Manager will use the cancel spin lock to protect the device queue and the current IRP.

Drivers that do not have a StartIo routine cannot call IoStartNextPacket.

Callers of IoStartNextPacket must be running at IRQL DISPATCH_LEVEL. Usually, this routine is called from a device driver's DpcForIsr or CustomDpc routine, both of which are run at IRQL DISPATCH_LEVEL.

See Also

DEVICE_OBJECT, IoStartNextPacketByKey, IoStartPacket


IoStartNextPacketByKey

IoStartNextPacketByKey dequeues the next packet from the given device object's associated device queue according to a specified sort-key value and calls the driver's StartIo routine with that IRP.

VOID
  IoStartNextPacketByKey(
    IN PDEVICE_OBJECT  DeviceObject,
    IN BOOLEAN  Cancelable,
    IN ULONG  Key
    );

Parameters

DeviceObject
Points to the device object for which the IRP is to be dequeued.
Cancelable
Specifies whether IRPs in the device queue can be canceled.
Key
Specifies the sort key that determines which entry to remove from the queue.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

If there are no IRPs currently in the device queue for the target device object, this routine simply returns control to the caller.

If the driver passed a pointer to a cancel routine when it called IoStartPacket, it should pass TRUE in the Cancelable parameter. If Cancelable is TRUE, the I/O Manager will use the cancel spin lock to protect the device queue and the current IRP.

Drivers that do not have a StartIo routine cannot call IoStartNextPacketByKey.

Callers of IoStartNextPacketByKey must be running at IRQL <= DISPATCH_LEVEL. Usually, this routine is called from a device driver's DpcForIsr or CustomDpc routine, both of which are run at IRQL DISPATCH_LEVEL.

See Also

DEVICE_OBJECT, IoStartNextPacket, IoStartPacket


IoStartPacket

IoStartPacket calls the driver's StartIo routine with the given IRP or inserts the IRP into the device queue associated with the given device object if the device is already busy.

VOID
  IoStartPacket(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp,
    IN PULONG  Key  OPTIONAL,
    IN PDRIVER_CANCEL  CancelFunction  OPTIONAL
    );

Parameters

DeviceObject
Points to the target device object for the IRP.
Irp
Points to the IRP to be processed.
Key
Points to a value that determines where to insert the packet into the device queue. If this is zero, the packet is inserted at the tail of the device queue.
CancelFunction
Specifies the entry point for a driver-supplied Cancel routine.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

If the driver is already busy processing a request for the target device object, then the packet is queued in the device queue. Otherwise, this routine calls the driver's StartIo routine with the specified IRP.

If a nonNULL CancelFunction pointer is supplied, it is set in the IRP so the driver's Cancel routine is called if the IRP is canceled before its completion.

Drivers that do not have a StartIo routine cannot call IoStartPacket.

Callers of IoStartPacket must be running at IRQL <= DISPATCH_LEVEL. Usually, this routine is called from a device driver's Dispatch routine at IRQL PASSIVE_LEVEL.

See Also

DEVICE_OBJECT, IoMarkIrpPending, IoSetCancelRoutine, IoStartNextPacket, IoStartNextPacketByKey


IoStartTimer

IoStartTimer enables the timer associated with a given device object so the driver-supplied IoTimer routine is called once per second.

VOID
  IoStartTimer(
    IN PDEVICE_OBJECT  DeviceObject
    );

Parameters

DeviceObject
Points to a device object whose timer routine is to be called.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

The driver must already have set up the IoTimer routine for the DeviceObject by calling IoInitializeTimer.

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoInitializeTimer, IoStopTimer, KeInitializeDpc, KeInitializeTimer, KeSetTimer


IoStopTimer

IoStopTimer disables the timer for a specified device object so the driver-supplied IoTimer routine is not called.

VOID
  IoStopTimer(
    IN PDEVICE_OBJECT  DeviceObject
    );

Parameters

DeviceObject
Points to the device object with which the IoTimer routine is associated.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

The driver-supplied IoTimer routine can be re-enabled with a call to IoStartTimer.

Do not call IoStopTimer from within a driver's IoTimer routine.

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoInitializeTimer, IoStartTimer


IoUnregisterPlugPlayNotification

IoUnregisterPlugPlayNotification removes the registration of a driver's callback routine for a PnP event.

NTSTATUS
  IoUnregisterPlugPlayNotification(
    IN PVOID  NotificationEntry
    );

Parameters

NotificationEntry
Points to an opaque value representing the registration to be removed. The value was returned by a previous call to IoRegisterPlugPlayNotification.

Return Value

IoUnregisterPlugPlayNotification returns STATUS_SUCCESS if the registration was successfully removed.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

IoUnregisterPlugPlayNotification removes one PnP notification registration; that is, the registration of one driver callback routine for one PnP event category.

Drivers should unregister a notification first, then free any related context buffer.

A driver cannot be unloaded until it removes all of its PnP notification registrations because there is a reference on its driver object for each active registration.

Callers of IoUnregisterPlugPlayNotification must be running at IRQL PASSIVE_LEVEL in the context of a system thread.

See Also

IoRegisterPlugPlayNotification


IoUnregisterShutdownNotification

IoUnregisterShutdownNotification removes a registered driver from the shutdown notification queue.

VOID
  IoUnregisterShutdownNotification(
    IN PDEVICE_OBJECT  DeviceObject
    );

Parameters

DeviceObject
Points to the driver's device object.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

The driver's DispatchShutdown routine is not called before the Power Manager sends an IRP_MN_SET_POWER request to shut down the system.

IoUnregisterShutdownNotification can be called by a driver only if that driver previously called IoRegisterShutdownNotification with the given DeviceObject. This routine is usually called from a driver's Unload routine.

Calling IoUnregisterShutdownNotification cancels all shutdown notifications that have been registered for the given DeviceObject.Callers of IoUnregisterShutdownNotification must be running at IRQL PASSIVE_LEVEL.

See Also

IoRegisterShutdownNotification


IoUpdateShareAccess

IoUpdateShareAccess updates the share access for the given file object, usually when the file is being opened.

VOID
  IoUpdateShareAccess(
    IN PFILE_OBJECT  FileObject,
    IN OUT PSHARE_ACCESS  ShareAccess
    );

Parameters

FileObject
Points to a referenced file object representing the file or associated device object for which to update the share access.
ShareAccess
Points to the common SHARE_ACCESS structure associated with the FileObject. Drivers should treat this structure as opaque.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

IoUpdateShareAccess is not an atomic operation. Therefore, drivers calling this routine must protect the shared file object passed to IoUpdateShareAccess by means of some kind of lock, such as a mutex or a resource lock, in order to prevent corruption of the shared access counts.

Before calling IoUpdateShareAccess, the caller must successfully call IoCheckShareAccess with Update set to False. Such a call to IoCheckShareAccess determines whether the requested shared access is compatible with the way the file object is currently being accessed by other opens, but it does not update the SHARE_ACCESS structure. IoUpdateShareAccess actually updates the SHARE_ACCESS structure associated with the file object.

Callers of IoUpdateShareAccess must be running at IRQL PASSIVE_LEVEL.

See Also

IoCheckShareAccess, IoRemoveShareAccess, IoSetShareAccess


IoVerifyPartitionTable

IoVerifyPartitionTable checks the validity of the partition table for a disk.

NTKERNELAPI
NTSTATUS
  IoVerifyPartitionTable(
    IN PDEVICE_OBJECT  DeviceObject,
    IN BOOLEAN  FixErrors
    );

Parameters

DeviceObject
Specifies the device object of the disk to verify.
FixErrors
Specifies if the routine should correct any correctable errors in the partition table.

Return Value

The routine returns STATUS_SUCCESS if the partition table is error-free.

If the caller specifies FALSE for the FixErrors parameter and the partition table has errors, the routine returns STATUS_DISK_CORRUPT_ERROR. If the caller specifies TRUE for FixErrors, and the routine is able to correct all errors in the partition table, it returns STATUS_SUCCESS. Otherwise it returns STATUS_DISK_CORRUPT_ERROR.

The routine might also return other NT status error codes.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

This routine is only available on Windows XP and later.

IoVerifyPartitionTable must only be used by disk drivers.


IoVolumeDeviceToDosName

IoVolumeDeviceToDosName returns the MS-DOS® path for a specified device object that represents a file system volume.

NTSTATUS
  IoVolumeDeviceToDosName(
    IN  PVOID  VolumeDeviceObject,
    OUT PUNICODE_STRING  DosName
    );

Parameters

VolumeDeviceObject
Pointer to a device object that represents a file system volume.
DosName
Pointer to a Unicode string containing the MS-DOS path of the volume device object specified by VolumeDeviceObject.

Return Value

IoVolumeDeviceToDosName returns STATUS_SUCCESS or an appropriate error status.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

This routine is only available on Windows XP and later. Drivers that must work on earlier versions of NT-based operating systems can use RtlVolumeDeviceToDosName, which behaves identically.

IoVolumeDeviceToDosName allocates the Unicode string buffer for the MS-DOS path from the memory pool. After the buffer is no longer required, a caller of this routine should use ExFreePool to free it.


IoWMIAllocateInstanceIds

IoWMIAllocateInstanceIds allocates one or more instance IDs that are unique to the GUID.

NTSTATUS
  IoWMIAllocateInstanceIds(
    IN GUID  *Guid,
    IN ULONG  InstanceCount,
    OUT ULONG  *FirstInstanceId
    );

Parameters

Guid
Points to the GUID for which to generate instance identifiers.
InstanceCount
Specifies how many instance identifiers should be provided.
FirstInstanceId
Points to the first instance identifier that the driver should use.

Return Value

IoWMIAllocateInstanceIds returns a status from the following list:

STATUS_SUCCESS
Indicates that WMI successfully provided unique instance identifiers for the GUID specified.
STATUS_UNSUCCESSFUL
Indicates that the WMI services are not available.
STATUS_INSUFFICIENT RESOURCES
Indicates that insufficient resources were available to provide the caller with instance IDs.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

If greater than one instance was requested in InstanceCount and the routine completed successfully, FirstInstanceId points to the first instance that the caller should use. For each instance requested beyond one, the caller should increment the value returned in *FirstInstanceId. For example, if the caller requested six instances and one was returned as the value of FirstInstanceId, the caller should use the values 1-6 as his unique instance identifiers.

Callers of this routine must be running at IRQL PASSIVE_LEVEL.


IoWMIDeviceObjectToProviderId

IoWMIDeviceObjectToProviderId translates the specified device object into the corresponding WMI Provider Id.

ULONG
  IoWMIDeviceObjectToProviderId(
    IN PDEVICEOBJECT  DeviceObject
    );

Parameters

DeviceObject
Points to a device object.

Return Value

IoWMIDeviceObjectToProviderId returns the WMI Provider Id associated with the specified device object.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

IoWMIDeviceObjectToProviderId should be used when filling in the ProviderId member of the WNODE_HEADER structure in those cases when the WNODEHEADER structure is being initialized as part of a WNODE_EVENT_ITEM or WNODE_EVENT_REFERENCE structure. (If the WNODE_HEADER is being used for other purposes, ProviderId is reserved.)

When running on a 32 bit OS, the provider Id and the device object are identical. When running on a 64 bit OS, IoWMIDeviceObjectToProviderId will convert the 64bit device object to a 32 bit provider id.

See Also

WNODE_HEADER, WNODE_EVENT_ITEM, WNODE_EVENT_REFERENCE


IoWMIDeviceObjectToInstanceName

IoWMIDeviceObjectToInstanceName determines the instance name for the WMI class instance implemented by the driver that is specified by a device object.

NTKERNELAPI
NTSTATUS
  IoWMIDeviceObjectToInstanceName(
    IN PVOID  DataBlockObject,
    IN PDEVICE_OBJECT  DeviceObject,
    OUT PUNICODE_STRING  InstanceName
    );

Parameters

DataBlockObject
Pointer to a WMI data block object. The caller opens the data block object for the WMI class with IoWMIOpenBlock.
DeviceObject
Specifies a device object. The routine returns the instance name for the driver corresponding to the device object.
InstanceName
Pointer to the UNICODE_STRING structure that the routine uses to return the instance name. The caller frees the returned buffer within UNICODE_STRING.

Return Value

The routine returns an NTSTATUS code. Possible return values include:

STATUS_SUCCESS
The operation succeeded. The routine stores the instance name in the UNICODE_STRING specified by the InstanceName parameter.
STATUS_WMI_INSTANCE_NOT_FOUND
The driver does not implement any instances of the WMI class specified by DataBlockObject.

Headers

Declared in ntddk.h and wdm.h. Include ntddk.h or wdm.h.

Comments

This routine is only available on Windows XP and later.

See Also

DEVICE_OBJECT, IoWMIOpenBlock, IoWMIHandleToInstanceName


IoWMIExecuteMethod

IoWMIExecuteMethod executes a WMI class method on the specified WMI data block instance.

NTKERNELAPI
NTSTATUS
  IoWMIExecuteMethod(
    IN PVOID  DataBlockObject,
    IN PUNICODE_STRING  InstanceName,
    IN ULONG  MethodId,
    IN ULONG  InBufferSize,
    IN OUT PULONG  OutBufferSize,
    IN OUT  PUCHAR  InOutBuffer
    );

Parameters

DataBlockObject
Pointer to a WMI data block object. The caller opens the data block object for the WMI class with IoWMIOpenBlock. The object must be opened with the WMIGUID_EXECUTE access right.
InstanceName
Specifies the name of the instance of the data block. This value corresponds to the value of the InstanceName property for the block.
MethodId
Specifies the method item ID for the method to be set. The value of this parameter corresponds to the value declared in the WmiMethodId qualifier for the method.
InBufferSize
Specifies the size, in bytes, of input data for the method. The actual input data is passed in the buffer pointed to by the InOutBuffer parameter.
OutBufferSize
Pointer to a ULONG that specifies the expected size, bytes, of the data output by the method. The actual output data is returned in the buffer pointed to by the InOutBuffer parameter. If the routine succeeds, it updates the memory location to specify the number of bytes actually stored in InOutBuffer. If the routine fails with STATUS_BUFFER_TOO_SMALL, it returns the number of bytes required to return the data.
InOutBuffer
Pointer to the buffer where the caller passes the WMI method's input data, and receives the WMI method's output data.

Return Value

The routine returns an NTSTATUS code. Possible return values include:

STATUS_SUCCESS
The operation succeeded. The routine returns the WMI data in the buffer pointed to by the InOutBuffer parameter. The routine also returns the size, in bytes, of the returned data in the memory location pointed to by the OutBufferSize parameter.
STATUS_WMI_GUID_NOT_FOUND
No drivers implement the WMI class.
STATUS_WMI_INSTANCE_NOT_FOUND
No driver implements an instance of the WMI class with InstanceName property equal to the value specified in the InstanceName parameter.
STATUS_WMI_ITEMID_NOT_FOUND
The WMI class does not contain a method with method ID equal to the value of MethodId.
STATUS_BUFFER_TOO_SMALL
The buffer passed by the caller in the OutBuffer parameter is too small. The routine returns the required buffer size in the memory location pointed to by the InOutBufferSize parameter.

Headers

Declared in ntddk.h and wdm.h. Include ntddk.h or wdm.h.

Comments

This routine is only available on Windows XP and later.

IoWMIExecuteMethod determines which drivers might support the specified WMI class and instance name. It issues an IRP_MN_EXECUTE_METHOD request to each such driver. The driver that exports the data block instance with matching InstanceName property then executes the specified WMI method.

See Also

IoWMIOpenBlock, IRP_MN_EXECUTE_METHOD


IoWMIHandleToInstanceName

IoWMIHandleToInstanceName determines the instance name for the WMI class instance implemented by the driver that is specified by a file handle.

NTKERNELAPI
NTSTATUS
  IoWMIHandleToInstanceName(
    IN PVOID  DataBlockObject,
    IN HANDLE  FileHandle,
    OUT PUNICODE_STRING  InstanceName
    );

Parameters

DataBlockObject
Pointer to a WMI data block object. The caller opens the data block object for the WMI class with the IoWMIOpenBlock routine.
FileHandle
Specifies a file handle. The routine returns the instance name corresponding to the driver that is represented by the file handle.
InstanceName
Pointer to the UNICODE_STRING structure that the routine uses to return the instance name. The caller frees the returned buffer within UNICODE_STRING.

Return Value

The routine returns an NTSTATUS code. Possible return values include:

STATUS_SUCCESS
The operation succeeded. The routine fills the UNICODE_STRING structure pointed to by the InstanceName parameter with the instance name.
STATUS_WMI_INSTANCE_NOT_FOUND
The driver does not implement any instances of the WMI class specified by DataBlockObject.

Headers

Declared in ntddk.h and wdm.h. Include ntddk.h or wdm.h.

Comments

This routine is only available on Windows XP and later.

See Also

DEVICE_OBJECT, IoWMIOpenBlock, IoWMIDeviceObjectToInstanceName


IoWMIOpenBlock

IoWMIOpenBlock opens the WMI data block object for the specified WMI class.

NTKERNELAPI
NTSTATUS
  IoWMIOpenBlock(
    IN GUID  *DataBlockGuid,
    IN ULONG  DesiredAccess,
    OUT PVOID  *DataBlockObject
    );

Parameters

DataBlockGuid
Specifies the GUID for WMI class.
DesiredAccess
Specifies the desired access rights to the data block object. The caller must have particular access rights to perform certain operations.

The following is a description of each access right bit and the operations it allows:

WMIGUID_EXECUTE
The data block object can be used to execute WMI class methods. This flag must be set to use IoWMIExecuteMethod on the data block object.
WMIGUID_NOTIFICATION
The data block object can be used to register event notification callbacks. This flag must be set to use IoWMISetNotificationCallback, and can only be used for WMI event blocks. Callers that specify this flag must also specify the SYNCHRONIZE flag.
WMIGUID_QUERY
The data block object can be used to query WMI class properties. This flag must be set to use any of the IoWMIQueryXxx routines on the data block object.
WMIGUID_SET
The data block object can be used to set WMI class properties. This flag must be set to use any of the IoWMISetXxx routines on the data block object.
DataBlockObject
Pointer to a memory location where the routine returns a pointer to the data block object.

Return Value

Returns STATUS_SUCCESS on success, or the appropriate NTSTATUS error code on failure.

Headers

Declared in ntddk.h and wdm.h. Include ntddk.h or wdm.h.

The WMIGUID_XXX values are declared in wmistr.h. To use them, include wmistr.h.

Comments

This routine is only available on Windows XP and later.

The caller uses IoWMIOpenBlock to create a data block object for the specified WMI class GUID. Subsequently, the caller can use the data block object to read or write WMI class properties, execute WMI class methods, and register callbacks for WMI events.

Use the IoWMIQueryXxx and IoWMISetXxx routines to read and write WMI class properties. Use IoWMIExecuteMethod to execute WMI class methods, and use IoWMISetNotificationCallback to register a WMI event notification callback.

Use ZwClose to close the data block object once it is no longer needed.

See Also

IoWMIExecuteMethod, IoWMIQueryAllData, IoWMIQueryAllDataMultiple, IoWMIQuerySingleInstance, IoWMIQuerySingleInstanceMultiple, IoWMISetNotificationCallback, IoWMISetSingleInstance, IoWMISetSingleItem, ZwClose


IoWMIQueryAllData

IoWMIQueryAllData returns all WMI data blocks that implement a given WMI class.

NTKERNELAPI
  NTSTATUS IoWMIQueryAllData (
    IN PVOID  DataBlockObject,
    IN OUT ULONG  *InOutBufferSize,
    OUT /* non paged */ PVOID  OutBuffer
);

Parameters

DataBlockObject
Pointer to a WMI data block object. The caller opens the data block object for the WMI class with the IoWMIOpenBlock routine. The object must be opened with the WMIGUID_QUERY access right.
InOutBufferSize
Pointer to a memory location that specifies the size of the buffer passed in the OutBuffer parameter. If the routine succeeds, it updates the memory location to specify the number of bytes actually stored in OutBuffer. If the routine fails with status code of STATUS_BUFFER_TOO_SMALL, it returns the number of bytes required to return the data.
OutBuffer
Pointer to the buffer where the routine returns the WMI data. The routine returns a sequence of variable-sized WNODE_ALL_DATA structures, one for each set of returned data blocks. The WnodeHeader.Linkage member of each WNODE_ALL_DATA structure contains the offset from the beginning of the current WNODE_ALL_DATA to the beginning of the next WNODE_ALL_DATA. The final block in the chain has WnodeHeader.Linkage set to zero. OutBuffer must point to a buffer allocated from nonpaged pool.

Return Value

The routine returns an NTSTATUS code. Possible return values include:

STATUS_SUCCESS
The operation succeeded. The routine returns the WMI data in the buffer pointed to by the OutBuffer parameter. The routine also returns the size, in bytes, of the returned data in the memory location pointed to by the InOutBufferSize parameter.
STATUS_WMI_GUID_NOT_FOUND
No drivers implement the specified WMI class.
STATUS_BUFFER_TOO_SMALL
The buffer passed by the caller in the OutBuffer parameter is too small. The routine returns the required buffer size in the memory location pointed to by the InOutBufferSize parameter.

Headers

Declared in ntddk.h and wdm.h. Include ntddk.h or wdm.h.

Comments

This routine is only available on Windows XP and later.

IoWMIQueryAllData determines which drivers support the specified WMI class, and issues an IRP_MN_QUERY_ALL_DATA request to every such driver.

To query for multiple WMI classes, use IoWMIQueryAllDataMultiple.

See Also

IoWMIOpenBlock, IoWMIQueryAllDataMultiple, IRP_MN_QUERY_ALL_DATA


IoWMIQueryAllDataMultiple

IoWMIQueryAllDataMultiple returns all WMI data blocks that implement one of a set of WMI classes.

NTKERNELAPI
  NTSTATUS IoWMIQueryAllDataMultiple (
    IN PVOID  *DataBlockObjectList,
    IN ULONG  ObjectCount,
    IN OUT ULONG  *InOutBufferSize,
    OUT /* non paged */ PVOID  OutBuffer
);

Parameters

DataBlockObjectList
Pointer to an array of pointers to WMI data block objects. The caller opens a data block object for each WMI class with the IoWMIOpenBlock routine. Each object must be opened with the WMIGUID_QUERY access right.
ObjectCount
Specifies the number of entries in the array passed in the DataBlockObjectList parameter.
InOutBufferSize
Pointer to a memory location that specifies the size of the buffer passed in the OutBuffer parameter. If the routine succeeds, it updates the memory location to specify the number of bytes actually stored in OutBuffer. If the routine fails with status code of STATUS_BUFFER_TOO_SMALL, it returns the number of bytes required to return the data.
OutBuffer
Pointer to the buffer where the routine returns the WMI data. The routine returns a sequence of variable-sized WNODE_ALL_DATA structures, one for each set of returned data blocks. The WnodeHeader.Linkage member of each WNODE_ALL_DATA structure contains the offset from the beginning of the current WNODE_ALL_DATA to the beginning of the next WNODE_ALL_DATA. The final block in the chain has WnodeHeader.Linkage set to zero. OutBuffer must point to a buffer allocated from nonpaged pool.

Return Value

The routine returns an NTSTATUS code. Possible return values include:

STATUS_SUCCESS
The operation succeeded. The routine returns the WMI data in the buffer pointed to by the OutBuffer parameter. The routine also returns the size, in bytes, of the returned data in the memory location pointed to by the InOutBufferSize parameter.
STATUS_BUFFER_TOO_SMALL
The buffer passed by the caller in the OutBuffer parameter is too small. The routine returns the required buffer size in the memory location pointed to by the InOutBufferSize parameter.

Headers

Declared in ntddk.h and wdm.h. Include ntddk.h or wdm.h.

Comments

This routine is only available on Windows XP and later.

IoWMIQueryAllDataMultiple determines which drivers support the specified WMI classes, and issues an IRP_MN_QUERY_ALL_DATA request to every such driver.

If no drivers implement any of the specified WMI classes, the routine returns STATUS_SUCCESS It also returns a value of zero in the memory location pointed to by the InOutBufferSize parameter.

To query a single WMI class, use IoWMIQueryAllData.

See Also

IoWMIOpenBlock, IoWMIQueryAllData, IRP_MN_QUERY_ALL_DATA


IoWMIQuerySingleInstance

IoWMIQuerySingleInstance returns the specified instance of a WMI data block.

NTKERNELAPI
NTSTATUS
  IoWMIQuerySingleInstance(
    IN PVOID  DataBlockObject,
    IN PUNICODE_STRING  InstanceName,
    IN OUT ULONG  *InOutBufferSize,
    OUT /* non paged */ PVOID OutBuffer
);

Parameters

DataBlockObject
Pointer to a WMI data block object. The caller opens the data block object for the WMI class with the IoWMIOpenBlock routine. The object must be opened with the WMIGUID_QUERY access right.
InstanceName
Specifies the name of the instance of the data block. This value corresponds to the value of the InstanceName property for the block.
InOutBufferSize
Pointer to a memory location that specifies the size of the buffer passed in the OutBuffer parameter. If the routine succeeds, it updates the memory location to specify the number of bytes actually stored in OutBuffer. If the routine fails with status code of STATUS_BUFFER_TOO_SMALL, it returns the number of bytes required to return the data.
OutBuffer
Pointer to the buffer where the routine returns the WMI data. The routine returns a variable-sized WNODE_SINGLE_INSTANCE structure. OutBuffer must point to a buffer allocated from nonpaged pool.

Return Value

The routine returns an NTSTATUS code. Possible return values include:

STATUS_SUCCESS
The operation succeeded. The routine returns the WMI data in the buffer pointed to by the OutBuffer parameter. The routine also returns the size, in bytes, of the returned data in the memory location pointed to by the InOutBufferSize parameter.
STATUS_WMI_GUID_NOT_FOUND
No drivers implement the specified WMI class.
STATUS_WMI_INSTANCE_NOT_FOUND
No driver implements an instance of the WMI class with InstanceName property equal to the value specified in the InstanceName parameter.
STATUS_BUFFER_TOO_SMALL
The buffer passed by the caller in the OutBuffer parameter is too small. The routine returns the required buffer size in the memory location pointed to by the InOutBufferSize parameter.

Headers

Declared in ntddk.h and wdm.h. Include ntddk.h or wdm.h.

Comments

This routine is only available on Windows XP and later.

IoWMIQuerySingleInstance determines which drivers might support the specified WMI class with the specified instance name, and issues an IRP_MN_QUERY_SINGLE_INSTANCE request to each such driver. The driver that exports the data block instance with matching InstanceName property returns the appropriate data.

To query for multiple WMI classes and instance names, use the IoWMIQuerySingleInstanceMultiple routine. Drivers can use the IoWMISetSingleInstance routine to update the class instance.

See Also

IoWMIOpenBlock, IoWMIQuerySingleInstanceMultiple, IoWMISetSingleInstance, IRP_MN_QUERY_SINGLE_INSTANCE


IoWMIQuerySingleInstanceMultiple

IoWMIQuerySingleInstanceMultiple returns all WMI data block instances that implement the specified WMI classes with the specified instance names.

NTKERNELAPI
NTSTATUS
  IoWMIQuerySingleInstanceMultiple(
    IN PVOID  *DataBlockObjectList,
    IN PUNICODE_STRING  InstanceNames,
    IN ULONG  ObjectCount,
    IN OUT ULONG  *InOutBufferSize,
    OUT /* non paged */ PVOID  OutBuffer
);

Parameters

DataBlockObjectList
Pointer to an array of pointers of WMI data block objects. The caller opens a data block object for each WMI class with the IoWMIOpenBlock routine. Each object must be opened with the WMIGUID_QUERY access right.
InstanceNames
Pointer to an array of UNICODE_STRING structures containing instance names. The nth instance name in the array corresponds to the value of the InstanceName property for the nth WMI class specified in the array pointed to by the DataBlockObjectList parameter.
ObjectCount
Specifies the number of entries in the arrays passed in the DataBlockObjectList and InstanceNames parameters.
InOutBufferSize
Pointer to a memory location that specifies the size of the buffer passed in the OutBuffer parameter. If the routine succeeds, it updates the memory location to specify the number of bytes actually stored in OutBuffer. If the routine fails with STATUS_BUFFER_TOO_SMALL, it returns the number of bytes required to return the data.
OutBuffer
Pointer to the buffer where the routine returns the WMI data. The routine returns a sequence of variable-sized WNODE_SINGLE_INSTANCE structures, one for each data block instance. The WnodeHeader.Linkage member of each WNODE_SINGLE_INSTANCE structure contains the offset from the beginning of the current WNODE_SINGLE_INSTANCE to the beginning of the next WNODE_SINGLE_INSTANCE. The final block in the chain has WnodeHeader.Linkage set to zero. Each distinct data block instance corresponds to a single matching WMI class and instance name. OutBuffer must point to a buffer allocated from nonpaged pool.

Return Value

The routine returns an NTSTATUS code. Possible return values include:

STATUS_SUCCESS
The operation succeeded. The routine returns the WMI data in the buffer pointed to by the OutBuffer parameter. The routine also returns the size, in bytes, of the returned data in the memory location pointed to by the InOutBufferSize parameter.
STATUS_BUFFER_TOO_SMALL
The buffer passed by the caller in the OutBuffer parameter is too small. The routine returns the required buffer size in the memory location pointed to by the InOutBufferSize parameter.

Headers

Declared in ntddk.h and wdm.h. Include ntddk.h or wdm.h.

Comments

This routine is only available on Windows XP and later.

IoWMIQuerySingleInstanceMultiple determines which drivers might support the specified WMI classes and instance names, and issues an IRP_MN_QUERY_SINGLE_INSTANCE request to each such driver. Each driver that exports the data block instance with matching InstanceName property returns the appropriate data.

If no drivers implement any of the specified WMI classes and instance names, the routine returns STATUS_SUCCESS. It also returns a value of zero in the memory location pointed to by the InOutBufferSize parameter.

To query for a single WMI class and instance name, use the IoWMIQuerySingleInstance routine. Drivers can use the IoWMISetSingleInstance routine to update a class instance.

See Also

IoWMIOpenBlock, IoWMIQuerySingleInstance, IoWMISetSingleInstance, IRP_MN_QUERY_SINGLE_INSTANCE, UNICODE_STRING


IoWMIRegistrationControl

IoWMIRegistrationControl is used to request WMI action, such as adding or removing a device object from WMI

NTSTATUS
  IoWMIRegistrationControl(
    IN PDEVICE_OBJECT  DeviceObject,
    IN ULONG  Action
    );

Parameters

DeviceObject
Points to either a device object or the address of a callback function. If the WMIREG_FLAG_CALLBACK is set in the Action parameter, then DeviceObject should contain a callback address. Otherwise, DeviceObject contains a device object pointer.
Action
Specifies the action that WMI should take based on the specified value:
Action | Action to be taken
WMIREG_ACTION_REGISTER | Specifies that WMI should register DeviceObject as a provider of WMI information.
WMIREG_ACTION_DEREGISTER | Specifies that WMI should remove DeviceObject from its list of WMI providers.
WMI_ACTION_REREGISTER | Specifies that WMI should unregister the device and then register (reregister) the device. Reregistering the device will result in WMI sending an IRP_MN_REGINFO or IRP_MN_REGINFO_EX request to the device.
WMIREG_ACTION_UPDATE_GUIDS | Specifies that WMI should requery the device object for a new list of GUID identifiers that it provides data for. This will result in WMI sending an IRP_MN_REGINFO or IRP_MN_REGINFO_EX request to the device.
WMIREG_FLAG_CALLBACK | Indicates that the value contained at DeviceObject is actually the address of a callback function. (Note: WMIREG_FLAG_CALLBACK is not supported in the Windows 98 and ME implementation of WMI.)

Return Value

IoWMIRegistrationControl returns a status code from the following list:

STATUS_SUCCESS
Indicates that WMI completed the action requested without error.
STATUS_INVALID_PARAMETER
Indicates that the action, specified in Action, was invalid.
STATUS_Xxx
Indicates that the request failed for the reason specified by the NTSTATUS value. See ntstatus.h for detailed information for the actual status return code.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Callers of this routine must be running at IRQL PASSIVE_LEVEL.


IoWMISetNotificationCallback

IoWMISetNotificationCallback registers a notification callback for a WMI event.

NTKERNELAPI
NTSTATUS
  IoWMISetNotificationCallback(
    IN PVOID  Object,
    IN WMI_NOTIFICATION_CALLBACK  Callback,
    IN PVOID  Context
    );

Parameters

Object
Pointer to a WMI data block object. The caller opens the data block object for the WMI event with the IoWMIOpenBlock routine. The object must be opened with the WMIGUID_NOTIFICATION access right.
Callback
Pointer to a function of the form:
    XxxWmiNotificationCallback(PVOID Wnode, PVOID Context);

WMI calls this function to notify the caller that the specified event has occurred. The Wnode parameter of the callback routine points to the WNODE_EVENT_ITEM structure returned by the driver triggering the event. The Context parameter of the callback routine points to the value specified in the Context parameter of the IoWMISetNotificationCallback routine.

Context
Specifies the value that WMI passes to the callback routine when the event occurs.

Return Value

This routine returns STATUS_SUCCESS on success, and the appropriate NTSTATUS error code on failure.

Headers

Declared in ntddk.h and wdm.h. Include ntddk.h or wdm.h.

Comments

This routine is only available on Windows XP and later.

See Also

IoWMIOpenBlock, WNODE_EVENT_ITEM


IoWMISetSingleInstance

IoWMISetSingleInstance sets the values for properties within the data block instance that matches the specified WMI class and instance name.

NTKERNELAPI
NTSTATUS
  IoWMISetSingleInstance(
    IN PVOID  DataBlockObject,
    IN PUNICODE_STRING  InstanceName,
    IN ULONG  Version,
    IN ULONG  ValueBufferSize,
    IN PVOID  ValueBuffer
    );

Parameters

DataBlockObject
Pointer to a WMI data block object. The caller opens the data block object for the WMI class with the IoWMIOpenBlock routine. The object must be opened with the WMIGUID_SET access right.
InstanceName
Specifies the name of the instance of the data block. This value corresponds to the value of the InstanceName property for the block.
Version
Reserved for future use. Callers must set this parameter to zero.
ValueBufferSize
Specifies the size, in bytes, of the buffer passed in the ValueBuffer parameter.
ValueBuffer
Pointer to the buffer that contains the new values for the properties within the data block.

Return Value

The routine returns an NTSTATUS code. Possible return values include:

STATUS_SUCCESS
The operation succeeded. The values of the WMI data block instance properties are updated to the contents of the buffer pointed to by the ValueBuffer parameter.
STATUS_WMI_GUID_NOT_FOUND
No drivers implement the WMI class.
STATUS_WMI_INSTANCE_NOT_FOUND
No driver implements an instance of the WMI class with InstanceName property equal to the value specified in the InstanceName parameter.
STATUS_WMI_READ_ONLY
All properties of the WMI class are read-only.
STATUS_WMI_SET_FAILURE
The driver that implements the WMI data block instance is unable to update the instance.

Headers

Declared in ntddk.h and wdm.h. Include ntddk.h or wdm.h.

Comments

This routine is only available on Windows XP and later.

IoWMISetSingleInstance determines which drivers might support the specified WMI class and instance name, and issues an IRP_MN_CHANGE_SINGLE_INSTANCE request to each such driver. The driver that exports the data block instance with matching InstanceName property updates its data block instance. Note that a data block might have both read-only and read/write properties. In this case, only the read/write properties will be updated and STATUS_SUCCESS is returned.

Drivers can also use the IoWMISetSingleItem routine to update a single property within the class instance.

See Also

IoWMIOpenBlock, IoWMIQuerySingleInstance, IoWMISetSingleItem, IRP_MN_CHANGE_SINGLE_INSTANCE


IoWMISetSingleItem

IoWMISetSingleItem sets a single property in the data block instance that matches the specified WMI class and instance name.

NTKERNELAPI
NTSTATUS
  IoWMISetSingleItem(
    IN PVOID  DataBlockObject,
    IN PUNICODE_STRING  InstanceName,
    IN ULONG  DataItemId,
    IN ULONG  Version,
    IN ULONG  ValueBufferSize,
    IN PVOID  ValueBuffer
    );

Parameters

DataBlockObject
Pointer to a WMI data block object. The caller opens the data block object for the WMI class with the IoWMIOpenBlock routine. The object must be opened with the WMIGUID_SET access right.
InstanceName
Specifies the name of the instance of the data block. This value corresponds to the value of the InstanceName property for the block.
DataItemId
Specifies the data item ID for the property to be set. The value of this parameter corresponds to the value declared in the WmiDataId qualifier for the property.
Version
Reserved for future use. Callers must set this parameter to zero.
ValueBufferSize
Specifies the size, in bytes, of the buffer passed in the ValueBuffer parameter.
ValueBuffer
Pointer to the buffer that contains the new value for the property specified by the DataItemId parameter.

Return Value

The routine returns an NTSTATUS code. Possible return values include:

STATUS_SUCCESS
The operation succeeded. The value of the property within WMI data block instance is updated to the contents of the buffer pointed to by the ValueBuffer parameter.
STATUS_WMI_GUID_NOT_FOUND
No drivers implement the WMI class.
STATUS_WMI_INSTANCE_NOT_FOUND
No driver implements an instance of the WMI data block with InstanceName property equal to the value specified in the InstanceName parameter.
STATUS_WMI_ITEMID_NOT_FOUND
The WMI class does not contain a property with data item ID equal to the value of DataItemId.
STATUS_WMI_READ_ONLY
The data item ID in the data block is read-only.
STATUS_WMI_SET_FAILURE
The driver that implements the WMI data block instance is unable to update the property specified by DataItemId.

Headers

Declared in ntddk.h and wdm.h. Include ntddk.h or wdm.h.

Comments

This routine is only available on Windows XP and later.

IoWMISetSingleItem determines which drivers might support the specified WMI class and instance name. It issues an IRP_MN_CHANGE_SINGLE_ITEM request to each such driver. The driver that exports the data block instance with matching InstanceName property updates the specified property in the data block instance.

Drivers can also use IoWMISetSingleInstance to update every property of the WMI class instance simultaneously.

See Also

IoWMIOpenBlock, IoWMIQuerySingleInstance, IoWMISetSingleInstance, IRP_MN_CHANGE_SINGLE_ITEM


IoWMISuggestInstanceName

IoWmiSuggestInstanceName is used to request that WMI suggest a base name which a driver can use to build WMI instance names for the device.

NTSTATUS
  IoWMISuggestInstanceName(
    IN PDEVICE_OBJECT  PhysicalDeviceObject OPTIONAL,
    IN PUNICODE_STRING  SymbolicLinkName OPTIONAL,
    IN BOOLEAN  CombineNames,
    OUT PUNICODE_STRING  SuggestedInstanceName
    );

Parameters

PhysicalDeviceObject
If supplied, points to the driver's physical device object.
SymbolicLinkName
If supplied, points to the symbolic link name returned from IoRegisterDeviceInterface.
CombineNames
If TRUE then the suggested names returned will combine the PhysicalDeviceObject and SymbolicLinkName information.
SuggestedInstanceName
A pointer to a buffer which upon successful completion will contain a UNICODE STRING which contains the suggested instance name. The caller is responsible for freeing this buffer when it is no longer needed.

Return Value

IoWMISuggestInstanceName returns a status code from the following list:

STATUS_SUCCESS
Indicates that WMI was able to successfully complete this function.
STATUS_UNSUCCESSFUL
Indicates that the WMI services are not available.
STATUS_INSUFFICIENT_RESOURCES
Indicates that insufficient resources were available to provide the caller with a buffer containing the UNICODE string.
STATUS_NO_MEMORY
Indicates that insufficient resources were available to provide the caller with a buffer containing the UNICODE string.

Headers

Declared in wdm.h or ntddk.h. Include wdm.h or ntddk.h.

Comments

If CombineNames is TRUE then both PhysicalDeviceObject and SymbolicLinkName must be specified. Otherwise only one of them should be specified.


IoWMIWriteEvent

IoWMIWriteEvent delivers a given event to the user mode WMI components for notification.

NTSTATUS
  IoWMIWriteEvent(
    IN PVOID  WnodeEventItem
    );

Parameters

WnodeEventItem
Points to a WNODE_EVENT_ITEM structure to be delivered to the user mode WMI components that requested notification of the event.

Return Value

IoWMIWriteEvent returns a status code from the following list:

STATUS_SUCCESS
Indicates that WMI has successfully queued the event for delivery to the user mode WMI components.
STATUS_UNSUCCESSFUL
Indicates that WMI services are unavailable.
STATUS_BUFFER_OVERFLOW
Indicates that the event item specified exceeds the maximum allowed size.
STATUS_INSUFFICENT_RESOURCES
Indicates that insufficient resources were available for WMI to queue the event for delivery.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

The WNODE_EVENT_ITEM structure that is allocated by the caller and passed in WnodeEventItem must be allocated from nonpaged pool. If IoWMIWriteEvent returns STATUS_SUCCESS, the memory for the event item will automatically be freed by the system. If IOWMIWriteEvent returns anything other than STATUS_SUCCESS, it is the caller's responsibility to free the buffer.

Drivers should only call IoWMIWriteEvent for events that have been enabled for WMI. This ensures that there is an event consumer waiting for indication on that event.

Callers of this routine must be running at IRQL < DISPATCH_LEVEL.

See Also

WNODE_EVENT_ITEM, IOWmiDeviceObjectToProviderId


IoWriteErrorLogEntry

IoWriteErrorLogEntry queues a given error log packet to the system error logging thread.

VOID
  IoWriteErrorLogEntry(
    IN PVOID  ElEntry
    );

Parameters

ElEntry
Pointer to the error log packet the driver has allocated with IoAllocateErrorLogEntry and filled in.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL.

IoWriteErrorLogEntry frees the error log entry. Drivers must not call IoFreeErrorLogEntry on a log entry that they have already passed to IoWriteErrorLogEntry.

See Also

IoAllocateErrorLogEntry, IoFreeErrorLogEntry


IoWritePartitionTable

IoWritePartitionTable is obsolete and is provided only to support existing drivers. New drivers must use IoWritePartitionTableEx.

IoWritePartitionTable writes partition tables from the entries in the partition list buffer for each partition on the disk represented by the given device object.

NTSTATUS
  IoWritePartitionTable(
    IN PDEVICE_OBJECT  DeviceObject,
    IN ULONG  SectorSize,
    IN ULONG  SectorsPerTrack,
    IN ULONG  NumberOfHeads,
    IN struct _DRIVE_LAYOUT_INFORMATION  *PartitionBuffer
);

Parameters

DeviceObject
Points to the device object representing the disk whose partition tables are to be written.
SectorSize
Specifies the size in bytes of sectors on the device.
SectorsPerTrack
Specifies the track size on the device.
NumberOfHeads
Specifies the number of tracks per cylinder.
PartitionBuffer
Points to the drive layout buffer that contains the partition list entries. For more detailed information see DRIVE_LAYOUT_INFORMATION.

Return Value

IoWritePartitionTablo returns a status code of STATUS_SUCCESS if all writes were completed without error. In case of failure, the error codes returned by IoWritePartitionTable might include, but are not limited to, the following list:

STATUS_DEVICE_NOT_READY
Indicates a failure read the correct disk geometry.
STATUS_INSUFFICIENT_RESOURCES
Indicates a failure to allocate necessary resources (for example, heap memory, IRPs, etc.).
STATUS_UNSUCCESSFUL
Indicates that sector zero did not have the expected MBR disk signature.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

IoWritePartitionTable must only be used by disk drivers. Other drivers should use the IOCTL_DISK_SET_DRIVE_LAYOUT disk I/O request instead.

IoWritePartitionTable is called when a disk device driver is requested to set the partition type in a partition table entry or to repartition the disk by an IRP_MJ_DEVICE_CONTROL request. The device control request is generally issued by the format utility, which performs I/O control functions on the partitions and disks in the machine.

To reset a partition type, the driver passes a pointer to the device object representing the physical disk and the number of the partition associated with the device object that the format utility has open. When a disk is to be repartitioned dynamically, the disk driver must tear down its set of device objects representing the current disk partitions and create a new set of device objects representing the new partitions on the disk.

Applications that create and delete partitions and require full descriptions of the system should call IoReadPartitionTable with ReturnRecognizedPartitions set to FALSE. The drive layout structure can be modified by the system format utility to reflect a new configuration of the disk.

IoWritePartitionTable is synchronous. It must be called by the disk driver's Dispatch routine or by a driver thread. Thus, all user and file system threads must be prepared to enter a wait state when issuing the device control request to reset partition types for the device.

Callers of this routine must be running at IRQL PASSIVE_LEVEL.

See Also

IoCreateDevice, IoReadPartitionTable, IoSetPartitionInformation,


IoWritePartitionTableEx

IoWritePartitionTableEx writes partition tables from the entries in the partition list buffer for each partition on the disk represented by the given device object.

NTSTATUS
  IoWritePartitionTableEx(
    IN PDEVICE_OBJECT  DeviceObject,
    IN struct _DRIVE_LAYOUT_INFORMATION_EX  *PartitionBuffer
    );

Parameters

DeviceObject
Points to the device object representing the disk whose partition tables are to be written.
PartitionBuffer
Points to the drive layout buffer that contains the partition list entries. For more detailed information see DRIVE_LAYOUT_INFORMATION_EX.

Return Value

IoWritePartitionTabloEx returns a status code of STATUS_SUCCESS if all writes were completed without error. In case of failure, the error codes returned by IoWritePartitionTableEx might include, but are not limited to, the following list:

STATUS_DEVICE_NOT_READY
Indicates a failure read the correct disk geometry.
STATUS_INSUFFICIENT_RESOURCES
Indicates a failure to allocate necessary resources (for example, heap memory, IRPs, etc.).
STATUS_UNSUCCESSFUL
Indicates that sector zero did not have the expected MBR disk signature.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

IoWritePartitionTableEx replaces the obsolete routine IoWritePartitionTable. Unlike the older routine, it can write to GUID Partition Tables as well as Master Boot Record Partition Tables.

IoWritePartitionTableEx must only be used by disk drivers. Other drivers should use the IOCTL_DISK_SET_DRIVE_LAYOUT_EX disk I/O request instead.

When a disk device driver receives an IRP_MJ_DEVICE_CONTROL request to set the partition type in a partition table entry, or to repartition the disk, it should call IoWritePartionTableEx. The device control request is generally issued by the format utility, which performs I/O control functions on the partitions and disks in the machine.

To reset a partition type, the driver passes a pointer to the device object, representing the physical disk, and the number of the partition associated with the device object that the format utility has open. When a disk is to be repartitioned dynamically, the disk driver must tear down its set of device objects representing the current disk partitions and create a new set of device objects representing the new partitions on the disk.

In order tot create or delete partitions a full description of the system must be obtained by a call to IoReadPartitionTableEx. The drive layout structure can be modified by the system format utility to reflect a new configuration of the disk.

IoWritePartitionTableEx is synchronous. It must be called by the disk driver's Dispatch routine or by a driver thread. Thus, all user and file system threads must be prepared to enter a wait state when issuing the device control request to reset partition types for the device.

Callers of this routine must be running at IRQL PASSIVE_LEVEL.

See Also

IoCreateDevice, IoReadPartitionTableEx, IoSetPartitionInformationEx


Kernel Routines

All kernel-mode drivers except video and SCSI miniport drivers and NDIS drivers are likely to call at least some Ke Xxx routines.

References for the Ke Xxx routines are in alphabetical order.

For an overview of the functionality of these routines, see Summary of Kernel-Mode Support Routines.

The following routines are reserved for system use.

KeBreakinBreakpoint

KeEnterKernelDebugger

KeGetBugMessageText


KeAcquireInStackQueuedSpinLock

KeAcquireInStackQueuedSpinLock acquires a queued spin lock.

VOID
FASTCALL
  KeAcquireInStackQueuedSpinLock (
    IN PKSPIN_LOCK  SpinLock,
    IN PKLOCK_QUEUE_HANDLE  LockHandle
    );

Parameters

SpinLock
Specifies the spin lock to acquire. This parameter must have been initialized with KeInitializeSpinLock.
LockHandle
Pointer to a caller-supplied KLOCK_QUEUE_HANDLE variable that the routine can use to return the spin lock queue handle. The caller passes this value to KeReleaseInStackQueuedSpinLock when releasing the lock.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

This routine is only available on Windows XP and later.

KeAcquireInStackQueuedSpinLock acquires a spin lock as a queued spin lock. Queued spin locks are a more efficient version of spin locks. See Queued Spin Locks for a details. The caller releases the spin lock with KeReleaseInStackQueuedSpinLock.

Like ordinary spin locks, queued spin locks must only be used in very special circumstances. See KeAcquireSpinLock for a description of when to use spin locks.

This routine raises the IRQL level to DISPATCH_LEVEL when acquiring the spin lock. If the caller is guaranteed to already be running at DISPATCH_LEVEL, it is more efficient to call KeAcquireInStackQueuedSpinLockAtDpcLevel.

Drivers must not combine calls to KeAcquireSpinLock and KeAcquireInStackQueuedSpinLock on the same spin lock. A spin lock must always be acquired or released as either a queued spin lock, or as an ordinary spin lock.

See Also

KeAcquireSpinLock, KeAcquireInStackQueuedSpinLockAtDpcLevel, KeInitializeSpinLock, KeReleaseInStackQueuedSpinLock


KeAcquireInStackQueuedSpinLockAtDpcLevel

KeAcquireInStackQueuedSpinLockAtDpcLevel acquires a queued spin lock when the caller is already running at an IRQL = DISPATCH_LEVEL.

NTKERNELAPI
VOID
FASTCALL
  KeAcquireInStackQueuedSpinLockAtDpcLevel (
    IN PKSPIN_LOCK  SpinLock,
    IN PKLOCK_QUEUE_HANDLE  LockHandle
    );

Members

SpinLock
Specifies the spin lock to acquire. This parameter must have been initialized with KeInitializeSpinLock.
LockHandle
Pointer to a caller-supplied KLOCK_QUEUE_HANDLE structure that the routine can use to return the spin lock queue handle. The caller passes this value to KeReleaseInStackQueuedSpinLockFromDpcLevel.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

This routine is only available on Windows XP and later.

For a driver running at IRQL = DISPATCH_LEVEL, KeAcquireInStackQueuedSpinLockAtDpcLevel acquires a spin lock as a queued spin lock Queued spin locks are a more efficient version of spin locks. See Queued Spin Locks for a details. The caller releases the spin lock with KeReleaseInStackQueuedSpinLockFromDpcLevel.

Drivers that are already running at an IRQL = DISPATCH_LEVEL can call this routine to acquire the queued spin lock more quickly. Otherwise, use KeAcquireInStackQueuedSpinLock to acquire the spin lock.

Like ordinary spin locks, queued spin locks must only be used in very special circumstances. See KeAcquireSpinLock for a description of when to use spin locks.

Drivers must not combine calls to KeAcquireSpinLock and KeAcquireInStackQueuedSpinLock on the same spin lock. A spin lock must always be acquired or released as either a queued spin lock, or as an ordinary spin lock.

See Also

KeAcquireSpinLock, KeAcquireInStackQueuedSpinLock, KeInitializeSpinLock, KeReleaseInStackQueuedSpinLockFromDpcLevel


KeAcquireSpinLockAtDpcLevel

KeAcquireSpinLockAtDpcLevel acquires a spin lock when the caller is already running at IRQL DISPATCH_LEVEL.

VOID
  KeAcquireSpinLockAtDpcLevel(
    IN PKSPIN_LOCK  SpinLock
    );

Parameters

SpinLock
Pointer to an initialized spin lock for which the caller must provide the storage.

Include

wdm.h or ntddk.h

Comments

Drivers for Windows XP and later should use the more efficient and reliable KeAcquireInStackQueuedSpinLockAtDpcLevel routine.

Drivers call KeAcquireSpinLockAtDpcLevel instead of KeAcquireSpinLock for better driver performance if and only if they are already running at IRQL DISPATCH_LEVEL.

If a driver is running at IRQL < DISPATCH_LEVEL, it should call KeAcquireSpinLock to have IRQL raised by that routine. KeAcquireSpinLockAtDpcLevel assumes the caller is already running at IRQL DISPATCH_LEVEL, so no raise is necessary.

The caller should release the spin lock with KeReleaseSpinLockFromDpcLevel as quickly as possible.

See Also

KeAcquireInStackQueuedSpinLockAtDpcLevel, KeAcquireSpinLock, KeInitializeSpinLock, KeReleaseSpinLock, KeReleaseSpinLockFromDpcLevel


KeBugCheck

KeBugCheck brings down the system in a controlled manner when the caller discovers an unrecoverable inconsistency that would corrupt the system if the caller continued to run.

VOID
  KeBugCheck(
    IN ULONG  BugCheckCode
    );

Parameters

BugCheckCode
Specifies a value that indicates the reason for the bug check.

Include

ntddk.h

Comments

A bug check is a system-detected error that causes an immediate, controlled shutdown of the system. Various kernel-mode components perform run-time consistency checking. When such a component discovers an unrecoverable inconsistency, it causes a bug check to be generated.

Whenever possible, all kernel-mode components should log an error and continue to run, rather than calling KeBugCheck. For example, if a driver is unable to allocate required resources, it should log an error so that the system continues to run; it must not generate a bug check.

A driver or other kernel-mode component should call this routine only in cases of a fatal, unrecoverable error that could corrupt the system itself.

KeBugCheck can be useful in the early stages of developing a driver, or while it is undergoing testing. In these circumstances, the BugCheckCode passed to this routine should be distinct from those codes already in use by Windows or its drivers. See Bug Check Codes for a list of these codes.

However, even during driver development, this routine is of only limited utility, since it results in a complete system shutdown. A more effective debugging method is to attach a kernel debugger to the system and then use routines that send messages to the debugger or break into the debugger. See Kernel-Mode Debugging Routines for full details.

When a bug check is unavoidable, most system components call KeBugCheckEx, which provides more information about the cause of such an inconsistency than KeBugCheck.

Callers of KeBugCheck can be running at any IRQL.

See Also

IoAllocateErrorLogEntry, IoWriteErrorLogEntry, KeBugCheckEx, KeRegisterBugCheckCallback


KeBugCheckEx

KeBugCheckEx brings down the system in a controlled manner when the caller discovers an unrecoverable inconsistency that would corrupt the system if the caller continued to run.

VOID
  KeBugCheckEx(
    IN ULONG  BugCheckCode,
    IN ULONG_PTR  BugCheckParameter1,
    IN ULONG_PTR  BugCheckParameter2,
    IN ULONG_PTR  BugCheckParameter3,
    IN ULONG_PTR  BugCheckParameter4
    );

Parameters

BugCheckCode
Specifies a value that indicates the reason for the bug check.
BugCheckParameterX
Supply additional information, such as the address and data where a memory-corruption error occurred, depending on the value of BugCheckCode.

Include

wdm.h or ntddk.h

Comments

A bug check is a system-detected error that causes an immediate, controlled shutdown of the system. Various kernel-mode components perform run-time consistency checking. When such a component discovers an unrecoverable inconsistency, it causes a bug check to be generated.

Whenever possible, all kernel-mode components should log an error and continue to run, rather than calling KeBugCheckEx. For example, if a driver is unable to allocate required resources, it should log an error so that the system continues to run; it must not generate a bug check.

A driver or other kernel-mode component should call this routine only in cases of a fatal, unrecoverable error that could corrupt the system itself.

KeBugCheckEx can be useful in the early stages of developing a driver, or while it is undergoing testing. In these circumstances, the BugCheckCode passed to this routine should be distinct from those codes already in use by Windows or its drivers. See Bug Check Codes for a list of these codes.

However, even during driver development, this routine is of only limited utility, since it results in a complete system shutdown. A more effective debugging method is to attach a kernel debugger to the system and then use routines that send messages to the debugger or break into the debugger. See Kernel-Mode Debugging Routines for full details.

Callers of KeBugCheckEx can be running at any IRQL.

See Also

IoAllocateErrorLogEntry, IoWriteErrorLogEntry, KeBugCheck, KeRegisterBugCheckCallback


KeCancelTimer

KeCancelTimer dequeues a timer object before the timer interval, if any was set, expires.

BOOLEAN
  KeCancelTimer(
    IN PKTIMER  Timer
    );

Parameters

Timer
Pointer to an initialized timer object, for which the caller provides the storage.

Include

wdm.h or ntddk.h

Return Value

If the specified timer object is in the system timer queue, KeCancelTimer returns TRUE.

Comments

If the timer object is currently in the system timer queue, it is removed from the queue. If a DPC object is associated with the timer, it too is canceled. Otherwise, no operation is performed.

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL.

See Also

KeInitializeTimer, KeReadStateTimer, KeSetTimer


KeClearEvent

KeClearEvent sets the given event to a not signaled state.

VOID
  KeClearEvent(
    IN PRKEVENT  Event
    );

Parameters

Event
Pointer to an initialized dispatcher object of type event for which the caller supplies the storage.

Include

wdm.h or ntddk.h

Comments

Event is set to a not signaled state, meaning its value is set to zero.

For better performance, use KeClearEvent unless the caller uses the value returned by KeResetEvent to determine what to do next.

Callers of KeClearEvent must be running at IRQL <= DISPATCH_LEVEL.

See Also

KeInitializeEvent, KeReadStateEvent, KeResetEvent, KeSetEvent


KeDelayExecutionThread

KeDelayExecutionThread routine puts the current thread into an alertable or nonalertable wait state for a given interval.

NTSTATUS
  KeDelayExecutionThread(
    IN KPROCESSOR_MODE  WaitMode,
    IN BOOLEAN  Alertable,
    IN PLARGE_INTEGER  Interval
    );

Parameters

WaitMode
Specifies the processor mode in which the caller is waiting, which can be either KernelMode or UserMode. Lower-level drivers should specify KernelMode.
Alertable
Specifies TRUE if the wait is alertable. Lower-level drivers should specify FALSE.
Interval
Specifies the absolute or relative time, in units of 100 nanoseconds, for which the wait is to occur. A negative value indicates relative time. Absolute expiration times track any changes in system time; relative expiration times are not affected by system time changes.

Include

wdm.h or ntddk.h

Return Value

KeDelayExecutionThread returns one of the following values that describes how the delay was completed:

STATUS_SUCCESS
The delay completed because the specified interval elapsed.
STATUS_ALERTED
The delay completed because the thread was alerted.
STATUS_USER_APC
A user-mode APC was delivered before the given Interval expired.

Note that the NT_SUCCESS macro recognizes all of these status values as "success" values.

Comments

The expiration time is computed and the current thread is put in a wait state. When the specified interval has passed, the thread exits the wait state and is put in the ready state, becoming eligible for execution.

The Alertable parameter specifies whether the thread can be alerted and its wait state consequently aborted. If the value of this parameter is FALSE then the thread cannot be alerted, no matter what the value of the WaitMode parameter or the origin of the alert. The only exception to this rule is that of a terminating thread. A thread is automatically made alertable, for instance, when terminated by a user with a CTRL+C.

If the value of Alertable is TRUE and one of the following conditions is present, the thread will be alerted:

  1. If the origin of the alert is an internal, undocumented kernel-mode routine used to alert threads.
  2. The origin of the alert is a user-mode APC, and the value of the WaitMode parameter is UserMode.

In the first of these two cases, the thread's wait is satisfied with a completion status of STATUS_ALERTED; in the second case, it is satisfied with a completion status of STATUS_USER_APC.

The thread must be alertable for a user-mode APC to be delivered. This is not the case for kernel-mode APCs. A kernel-mode APC can be delivered and executed even though the thread is not alerted. Once the APC's execution completes, the thread's wait resumes. A thread is never alerted, nor is its wait aborted, by the delivery of a kernel-mode APC.

The delivery of kernel-mode APCs to a thread that has called KeDelayExecutionThread does not depend on whether the thread can be alerted. If the kernel-mode APC is a special kernel-mode APC, then the APC is delivered provided that IRQL < APC_LEVEL. If the kernel-mode APC is a normal kernel-mode APC, then the APC is delivered provided that the following three conditions hold: (1) IRQL < APC_LEVEL, (2) no kernel-mode APC is in progress, and(3) the thread is not in a critical section.

If the WaitMode parameter is UserMode, the kernel stack can be swapped out during the wait. Consequently, a caller must never attempt to pass parameters on the stack when calling KeDelayExecutionThread using the UserMode argument.

It is especially important to check the return value of KeDelayExecutionThread when the WaitMode parameter is UserMode or Alertable is TRUE, because KeDelayExecutionThread might return early with a status of STATUS_USER_APC or STATUS_ALERTED.

All long term waits that can be aborted by a user should be UserMode waits and Alertable should be set to FALSE.

Where possible, Alertable should be set to FALSE and WaitMode should be set to KernelMode, in order to reduce driver complexity. The principal exception to this is when the wait is a long term wait.

The expiration time of the delay is expressed as either an absolute time at which the delay is to expire, or a time relative to the current system time. If the Interval parameter is a negative value, the expiration time is relative.

Callers of KeDelayExecutionThread must be running at IRQL = PASSIVE_LEVEL.

See Also

KeQuerySystemTime


KeDeregisterBugCheckCallback

KeDeregisterBugCheckCallback removes a device driver's callback routine from the set of registered bug-check callbacks.

BOOLEAN
  KeDeregisterBugCheckCallback(
    IN PKBUGCHECK_CALLBACK_RECORD  CallbackRecord
    );

Parameters

CallbackRecord
Pointer to the caller-allocated storage containing an initialized bug-check callback record. This pointer was previously passed in successful calls to KeInitializeCallbackRecord and KeRegisterBugCheckCallback.

Include

ntddk.h

Return Value

KeDeregisterBugCheckCallback returns TRUE if the caller-supplied bug-check callback routine will no longer be called if a bug check occurs. If the given callback record was not registered, it returns FALSE.

Comments

KeDeregisterBugCheckCallback is the reciprocal of KeRegisterBugCheckCallback.

If an unloadable device driver sets up a bug-check callback routine with KeRegisterBugCheckCallback, that driver's Unload routine must call KeDeregisterBugCheckCallback before it frees the storage it allocated at CallbackRecord.

Callers of KeDeregisterBugCheckCallback can be running at any IRQL. Usually, a device driver is running at IRQL PASSIVE_LEVEL in its Unload routine when it calls KeDeregisterBugCheckCallback.

See Also

KeBugCheck, KeBugCheckEx, KeInitializeCallbackRecord, KeRegisterBugCheckCallback


KeEnterCriticalRegion

KeEnterCriticalRegion disables the delivery of normal kernel APCs temporarily; special kernel-mode APCs are still delivered.

VOID
  KeEnterCriticalRegion(
     );

Include

ntddk.h

Comments

Highest-level drivers can call this routine while running in the context of the thread that requested the current I/O operation. Any caller of this routine should call KeLeaveCriticalRegion as quickly as possible.

Callers of KeEnterCriticalRegion must be running at IRQL PASSIVE_LEVEL.

See Also

KeLeaveCriticalRegion


KeFlushIoBuffers

KeFlushIoBuffers flushes the memory region described by an MDL from caches of all processors.

VOID
  KeFlushIoBuffers(
    IN PMDL  Mdl,
    IN BOOLEAN  ReadOperation,
    IN BOOLEAN  DmaOperation
    );

Parameters

Mdl
Pointer to an MDL that describes the range for the I/O buffer.
ReadOperation
Specifies TRUE if the flush is being performed for a read operation.
DmaOperation
Specifies TRUE for a DMA transfer, FALSE for PIO.

Include

wdm.h or ntddk.h

Comments

Drivers call KeFlushIoBuffers to maintain data integrity during DMA or PIO device transfer operations. Calling this routine affects all processors in the machine.

If ReadOperation is TRUE, the driver is reading information from the device to system memory, so valid data still might be in the processor instruction and data caches. KeFlushIoBuffers flushes data from all processors' caches to system memory, including the processor on which the caller is running.

If ReadOperation is FALSE, the driver is writing data from system memory to a device, so valid data might be in the processor's data cache but not yet transferred to the device. KeFlushIoBuffers flushes all processors' data caches, including that of the processor on which the caller is running.

As a general rule, drivers should call this routine just before beginning a DMA transfer operation or immediately following any PIO read operation.

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL.

See Also

FlushAdapterBuffers


KeGetCurrentIrql

KeGetCurrentIrql returns the current IRQL.

KIRQL
  KeGetCurrentIrql(
    );

Include

wdm.h or ntddk.h

See Also

KeAcquireSpinLockAtDpcLevel, KeLowerIrql, KeRaiseIrql


KeGetCurrentProcessorNumber

KeGetCurrentProcessorNumber returns the system-assigned number of the current processor on which the caller is running.

ULONG
  KeGetCurrentProcessorNumber(
    );

Include

ntddk.h

Comments

KeGetCurrentProcessorNumber can be called by NT drivers to debug spin lock usage on SMP machines during driver development. An NT driver also might call KeGetCurrentProcessorNumber if it maintained some per-processor data and attempted to reduce cache-line contention.

The number of processors in an SMP machine is a zero-based value.

If the call to KeGetCurrentProcessorNumber occurs at IRQL < DISPATCH_LEVEL, a processor switch can occur between instructions. Consequently, callers of KeGetCurrentProcessorNumber usually run at IRQL >= DISPATCH_LEVEL.


KeGetCurrentThread

KeGetCurrentThread identifies the current thread.

PRKTHREAD
  KeGetCurrentThread(
    );

Return Value

KeGetCurrentThread returns a pointer to an opaque thread object.

Include

wdm.h or ntddk.h

Comments

A caller of KeGetCurrentThread can use the returned pointer as an input parameter to KeQueryPriorityThread, KeSetBasePriorityThread, or KeSetPriorityThread. However, the memory containing the thread object is opaque, that is, reserved for exclusive use by the system.

Callers of KeGetCurrentThread must be running at IRQL <= DISPATCH_LEVEL.

See Also

KeQueryPriorityThread, KeSetBasePriorityThread, KeSetPriorityThread, PsGetCurrentThread


KeGetDcacheFillSize

KeGetDcacheFillSize is obsolete. Drivers should call GetDmaAlignment instead.

ULONG
  KeGetDcacheFillSize(
    );


KeInitializeCallbackRecord

Device drivers call KeInitializeCallbackRecord to initialize a bug-check callback record before calling KeRegisterBugCheckCallback.

VOID
  KeInitializeCallbackRecord(
    IN PKBUGCHECK_CALLBACK_RECORD  CallbackRecord
    );

Parameters

CallbackRecord
Pointer to a caller-allocated nonpaged buffer, which must be at least sizeof(KBUGCHECK_CALLBACK_RECORD).

Include

ntddk.h

Comments

Before a device driver calls KeRegisterBugCheckCallback, it must call KeInitializeCallbackRecord.

Such a driver must provide resident storage for a bug-check record, which can be in a device extension, in a controller extension, in nonpaged pool allocated by the driver, or statically allocated in the driver. The structure and contents of the memory at CallbackRecord should be considered opaque, but this record must be preserved unless the driver has called KeDeregisterBugCheckCallback. After this call, the device driver is responsible for freeing the memory it allocated for the bug-check record if necessary.

Callers of KeInitializeCallbackRecord can be running at any IRQL. Usually, a device driver is running at IRQL PASSIVE_LEVEL in its DriverEntry routine when it calls KeInitializeCallbackRecord.

See Also

ExAllocatePool, KeDeregisterBugCheckCallback, KeRegisterBugCheckCallback


KeInitializeDeviceQueue

KeInitializeDeviceQueue initializes a device queue object to a not busy state.

VOID
  KeInitializeDeviceQueue(
    IN PKDEVICE_QUEUE  DeviceQueue
    );

Parameters

DeviceQueue
Pointer to a device queue object for which the caller provides the storage.

Include

wdm.h or ntddk.h

Comments

KeInitializeDeviceQueue initializes the specified device queue and sets its state to not busy.

A driver should call KeInitializeDeviceQueue from its AddDevice routine after creating the device object for the associated device. Storage for the device queue object must be resident: in the device extension of a driver-created device object, in the controller extension of a driver-created controller object, or in nonpaged pool allocated by the caller.

See Also

KeInsertByKeyDeviceQueue, KeInsertDeviceQueue, KeRemoveDeviceQueue, KeRemoveEntryDeviceQueue


KeInitializeDpc

KeInitializeDpc initializes a DPC object, setting up a deferred procedure that can be called with a given context.

VOID
  KeInitializeDpc(
    IN PRKDPC  Dpc,
    IN PKDEFERRED_ROUTINE  DeferredRoutine,
    IN PVOID  DeferredContext
    );

Parameters

Dpc
Pointer to a DPC object for which the caller provides the storage.
DeferredRoutine
Specifies the entry point for a routine to be called when the DPC object is removed from the DPC queue. A DeferredRoutine is declared as follows:
VOID
(*PKDEFERRED_ROUTINE)(
    IN PKDPC Dpc,
    IN PVOID DeferredContext,
    IN PVOID SystemArgument1,
    IN PVOID SystemArgument2
    );
DeferredContext
Pointer to a caller-supplied context to be passed to the DeferredRoutine when it is called.

Include

wdm.h or ntddk.h

Comments

The caller can queue an initialized DPC with KeInsertQueueDpc. The caller also can set up a timer object associated with the initialized DPC object and queue the DPC with KeSetTimer.

Storage for the DPC object must be resident: in the device extension of a driver-created device object, in the controller extension of a driver-created controller object, or in nonpaged pool allocated by the caller.

Callers of this routine must be running at IRQL PASSIVE_LEVEL.

See Also

KeInsertQueueDpc, KeRemoveQueueDpc, KeSetTimer


KeInitializeEvent

KeInitializeEvent initializes an event object as a synchronization (single waiter) or notification type event and sets it to a signaled or not signaled state.

VOID
  KeInitializeEvent(
    IN PRKEVENT  Event,
    IN EVENT_TYPE  Type,
    IN BOOLEAN  State
    );

Parameters

Event
Pointer to an event object, for which the caller provides the storage.
Type
Specifies the event type, either NotificationEvent or SynchronizationEvent.
State
Specifies the initial state of the event. TRUE indicates a signaled state.

Include

wdm.h or ntddk.h

Comments

A caller cannot wait at raised IRQL for a nonzero interval on an event object or in a nonarbitrary thread context.

Storage for an event object must be resident: in the device extension of a driver-created device object, in the controller extension of a driver-created controller object, or in nonpaged pool allocated by the caller. If you allocate the event on the stack, you must specify a KernelMode wait when calling KeWaitForSingleObject, KeWaitForMutexObject, or KeWaitForMultipleObjects. During a KernelMode wait, the stack containing the event will not be paged out

Drivers typically use a NotificationEvent to wait for an I/O operation to complete. When a notification event is set to the signaled state, all threads that were waiting on the event become eligible for execution. The event remains in the signaled state until a thread calls KeResetEvent or KeClearEvent to set the event in the not-signaled state.

A SynchronizationEvent is also called an autoreset or autoclearing event. When such an event is set, a single waiting thread becomes eligible for execution. The Kernel automatically resets the event to the not-signaled state each time a wait is satisfied. A driver might use a synchronization event to protect a shared resource that is used in synchronizing the operations of several threads. Synchronization events are rarely used in a typical driver.

Callers of this routine must be running at IRQL PASSIVE_LEVEL.

See Also

KeClearEvent, KeReadStateEvent, KeResetEvent, KeSetEvent, KeWaitForMultipleObjects, KeWaitForSingleObject


KeInitializeMutex

KeInitializeMutex initializes a mutex object at a given level number, setting it to a signaled state.

VOID
  KeInitializeMutex(
    IN PRKMUTEX  Mutex,
    IN ULONG  Level
    );

Parameters

Mutex
Pointer to a mutex object, for which the caller provides the storage.
Level
Specifies the level number to be assigned to the mutex.

Include

wdm.h or ntddk.h

Comments

For better performance, use the ExXxxFastMutex routines instead of the KeXxxMutex routines. However, a fast mutex cannot be acquired recursively, as a kernel mutex can.

The mutex object is initialized with the specified Level and an initial state of signaled.

A driver cannot wait at raised IRQL nor in an arbitrary thread context for a nonzero interval on a mutex object.

Storage for a mutex object must be resident: in the device extension of a driver-created device object, in the controller extension of a driver-created controller object, or in nonpaged pool allocated by the caller.

Callers of this routine must be running at IRQL PASSIVE_LEVEL.

See Also

ExInitializeFastMutex, KeReadStateMutex, KeReleaseMutex, KeWaitForMultipleObjects, KeWaitForMutexObject, KeWaitForSingleObject


KeInitializeSemaphore

KeInitializeSemaphore initializes a semaphore object with a given count and specifies an upper limit that the count can attain.

VOID
  KeInitializeSemaphore(
    IN PRKSEMAPHORE  Semaphore,
    IN LONG  Count,
    IN LONG  Limit
    );

Parameters

Semaphore
Pointer to a dispatcher object of type semaphore, for which the caller provides the storage.
Count
Specifies the initial count value to be assigned to the semaphore. This value must be positive. A nonzero value sets the initial state of the semaphore to signaled.
Limit
Specifies the maximum count value that the semaphore can attain. This value must be positive. It determines how many waiting threads become eligible for execution when the semaphore is set to the signaled state and can therefore access the resource that the semaphore protects.

Include

wdm.h or ntddk.h

Comments

The semaphore object is initialized with the specified initial count and limit.

Storage for a semaphore object must be resident: in the device extension of a driver-created device object, in the controller extension of a driver-created controller object, or in nonpaged pool allocated by the caller.

Callers of KeInitializeSemaphore must be running at IRQL PASSIVE_LEVEL.

See Also

KeReadStateSemaphore, KeReleaseSemaphore, KeWaitForMultipleObjects, KeWaitForSingleObject


KeInitializeSpinLock

KeInitializeSpinLock initializes a variable of type KSPIN_LOCK.

VOID
  KeInitializeSpinLock(
    IN PKSPIN_LOCK  SpinLock
    );

Parameters

SpinLock
Pointer to a spin lock, for which the caller must provide the storage.

Include

wdm.h or ntddk.h

Comments

This routine must be called before an initial call to KeAcquireSpinLock, KeAcquireInStackQueuedSpinLock, or to any other support routine that requires a spin lock as an argument.

Storage for a spin lock object must be resident: in the device extension of a driver-created device object, in the controller extension of a driver-created controller object, or in nonpaged pool allocated by the caller.

Callers of this routine can be running at any IRQL. Usually, a caller is running at IRQL PASSIVE_LEVEL in an AddDevice routine.

See Also

KeAcquireInStackQueuedSpinLock, KeAcquireInStackQueuedSpinLockAtDpcLevel, KeAcquireSpinLock, KeAcquireSpinLockAtDpcLevel, KeReleaseInStackQueuedSpinLock, KeReleaseInStackQueuedSpinLockFromDpcLevel, KeReleaseSpinLock, KeReleaseSpinLockFromDpcLevel


KeInitializeTimer

KeInitializeTimer initializes a timer object.

VOID
  KeInitializeTimer(
    IN PKTIMER  Timer
    );

Parameters

Timer
Pointer to a timer object, for which the caller provides the storage.

Include

wdm.h or ntddk.h

Comments

The timer object is initialized to a not signaled state.

Storage for a timer object must be resident: in the device extension of a driver-created device object, in the controller extension of a driver-created controller object, or in nonpaged pool allocated by the caller.

KeInitializeTimer can only initialize a notification timer. Use KeInitializeTimerEx to initialize a notification timer or a synchronization timer.

Callers of KeInitializeTimer should be running at IRQL DISPATCH_LEVEL or lower. It is best to initialize timers at IRQL PASSIVE_LEVEL.

Use KeSetTimer or KeSetTimerEx to define when the timer will expire.

See Also

KeCancelTimer, KeInitializeTimerEx, KeReadStateTimer, KeSetTimer, KeSetTimerEx, KeWaitForMultipleObjects, KeWaitForSingleObject


KeInitializeTimerEx

KeInitializeTimerEx initializes an extended kernel timer object.

VOID
  KeInitializeTimerEx(
    IN PKTIMER  Timer,
    IN TIMER_TYPE  Type
    );

Parameters

Timer
Pointer to a timer object, for which the caller provides the storage.
Type
Specifies the type of the timer object, either NotificationTimer or SynchronizationTimer.

Include

wdm.h or ntddk.h

Comments

The timer object is initialized with a not signaled state.

Storage for a timer object must be resident: in the device extension of a driver-created device object, in the controller extension of a driver-created controller object, or in nonpaged pool allocated by the caller.

When a notification timer expires, all waiting threads are released and the timer remains in the signaled state until it is explicitly reset. When a synchronization timer expires, it is set to a signaled state until a single waiting thread is released and then the timer is reset to a not signaled state.

Callers of KeInitializeTimerEx should be running at IRQL DISPATCH_LEVEL or lower. It is best to initialize timers at IRQL PASSIVE_LEVEL.

Use KeSetTimer or KeSetTimerEx to define when the timer will expire.

See Also

KeCancelTimer, KeReadStateTimer, KeSetTimer, KeSetTimerEx, KeWaitForMultipleObjects, KeWaitForSingleObject


KeInsertByKeyDeviceQueue

KeInsertByKeyDeviceQueue acquires the spin lock for the given DeviceQueue and queues an entry according to the given sort-key value if the device queue is set to a busy state.

BOOLEAN
  KeInsertByKeyDeviceQueue(
    IN PKDEVICE_QUEUE  DeviceQueue,
    IN PKDEVICE_QUEUE_ENTRY  DeviceQueueEntry,
    IN ULONG  SortKey
    );

Parameters

DeviceQueue
Pointer to a control object of the device queue type for which the caller provides the storage.
DeviceQueueEntry
Pointer to the device queue entry to be inserted into the device queue according to the specific key value.
SortKey
Specifies the sort-key value that determines the position in the device queue in which to insert the entry.

Include

wdm.h or ntddk.h

Return Value

If the device queue is empty, FALSE is returned, meaning the DeviceQueueEntry is not inserted in the device queue.

Comments

The given device queue spin lock is acquired and the state of the device queue is checked. If the device queue is set to a busy state, the IRP specified by the DeviceQueueEntry is inserted into the device queue according to its sort key value and the device queue spin lock is released.

The new entry is positioned in the device queue after any entries in the queue with sort key values less than or equal to its sort key value and preceding any entries with sort key values that are greater.

If KeInsertByKeyDeviceQueue returns FALSE, the caller must begin processing the IRP. A call to KeInsertDeviceQueue or KeInsertByKeyDeviceQueue when the queue is empty causes the device queue to transition from a not busy state to a busy state.

This routine is for code that queues an I/O request to a device driver.

Callers of KeInsertByKeyDeviceQueue must be running at IRQL DISPATCH_LEVEL.

See Also

KeInitializeDeviceQueue, KeInsertDeviceQueue, KeRemoveDeviceQueue, KeRemoveEntryDeviceQueue


KeInsertDeviceQueue

KeInsertDeviceQueue acquires the spin lock for the given device queue object and, if the device queue is set to a busy state, queues the given entry.

BOOLEAN
  KeInsertDeviceQueue(
    IN PKDEVICE_QUEUE  DeviceQueue,
    IN PKDEVICE_QUEUE_ENTRY  DeviceQueueEntry
    );

Parameters

DeviceQueue
Pointer to a control object of type device queue for which the caller provides the storage.
DeviceQueueEntry
Pointer to the device queue entry that is to be inserted.

Include

wdm.h or ntddk.h

Return Value

If the device queue is empty, FALSE is returned and the DeviceQueueEntry is not inserted in the device queue.

Comments

If the device queue is set to a busy state, the specified DeviceQueueEntry is inserted at the tail of the device queue and the device queue spin lock is released.

If KeInsertDeviceQueue returns FALSE, the entry was not queued and the caller must begin processing the IRP. A call to KeInsertDeviceQueue or KeInsertByKeyDeviceQueue when the queue is empty causes the device queue to change from a not busy state to a busy state.

This routine is for code that queues an I/O request to a device driver.

Callers of KeInsertDeviceQueue must be running at IRQL DISPATCH_LEVEL.

See Also

KeInitializeDeviceQueue, KeInsertByKeyDeviceQueue, KeRemoveDeviceQueue, KeRemoveEntryDeviceQueue


KeInsertQueueDpc

KeInsertQueueDpc queues a DPC for execution when the IRQL of a processor drops below DISPATCH_LEVEL.

BOOLEAN
  KeInsertQueueDpc(
    IN PRKDPC  Dpc,
    IN PVOID  SystemArgument1,
    IN PVOID  SystemArgument2
    );

Parameters

Dpc
Pointer to an initialized control object of type DPC for which the caller provides the storage.
SystemArgument1, SystemArgument2
Pointer to a set of two parameters that contain untyped data.

Include

wdm.h or ntddk.h

Return Value

If the specified DPC object is not currently in the queue, KeInsertQueueDpc queues the DPC and returns TRUE.

Comments

If the specified DPC object is already in the DPC queue, no operation is performed except to return FALSE. Otherwise, the DPC object is inserted in the DPC queue and a software interrupt is requested at IRQL DISPATCH_LEVEL on the current processor.

Note that a given DPC object and the function it represents can each be queued for execution only once at any given moment. If it can make overlapped calls to KeInsertQueueDpc, particularly in SMP machines, the caller should protect its DPC object with a spinlock.

The deferred procedure is run when IRQL on the current processor drops below DISPATCH_LEVEL.

Callers of KeInsertQueueDpc must be running at IRQL >= DISPATCH_LEVEL.

See Also

KeInitializeDpc, KeRemoveQueueDpc


KeLeaveCriticalRegion

KeLeaveCriticalRegion re-enables the delivery of normal kernel-mode APCs that were disabled by a preceding call to KeEnterCriticalRegion.

VOID
  KeLeaveCriticalRegion(
    );

Include

ntddk.h

Comments

Highest-level drivers can call this routine while running in the context of the thread that requested the current I/O operation.

Callers of KeLeaveCriticalRegion must be running at IRQL PASSIVE_LEVEL.

See Also

KeEnterCriticalRegion


KeLowerIrql

KeLowerIrql restores the IRQL on the current processor to its original value.

VOID
  KeLowerIrql(
    IN KIRQL  NewIrql
    );

Parameters

NewIrql
Specifies the IRQL that was returned from KeRaiseIrql.

Include

wdm.h or ntddk.h

Comments

It is a fatal error to call KeLowerIrql using an input NewIrql that was not returned by the immediately preceding call to KeRaiseIrql.

Callers of KeLowerIrql can be running at any IRQL that was passed to KeRaiseIrql.

See Also

KeGetCurrentIrql, KeRaiseIrql


KePulseEvent

KePulseEvent atomically sets an event object to a signaled state, attempts to satisfy as many waits as possible, and then resets the event object to a not signaled state.

NTSTATUS
  KePulseEvent(
    IN PRKEVENT  Event,
    IN KPRIORITY  Increment,
    IN BOOLEAN  Wait
    );

Parameters

Event
Pointer to a dispatcher object of type event.
Increment
Specifies the priority increment that is to be applied if setting the event causes a wait to be satisfied.
Wait
Specifies a Boolean value that signifies whether the call to KePulseEvent will be immediately followed by a call to one of the kernel-mode wait functions

Include

ntddk.h

Return Value

The previous signal state of the event object.

Comments

Callers of KePulseEvent must be running at IRQL <= DISPATCH_LEVEL.

See Also

KeInitializeEvent, KeReadStateEvent, KeResetEvent, KeSetEvent


KeQueryInterruptTime

KeQueryInterruptTime returns the current value of the system interrupt-time count.

ULONGLONG
KeQueryInterruptTime(
    );

Include

wdm.h or ntddk.h

Return Value

KeQueryInterruptTime returns the current interrupt-time count of 100-nanosecond units.

Comments

KeQueryInterruptTime can be used for performance tuning. This routine returns a finer grained measurement than calling KeQueryTickCount. A call to KeQueryInterruptTime has considerably less overhead than a call to KeQueryPerformanceCounter, as well.

Consequently, interrupt time can be used to measure very fine-grained durations while the system is running because operations that set or reset the system time have no effect on the system interrupt time count.

However, power-management state changes do affect the system interrupt time count. Maintenance of the interrupt time count is suspended during system sleep states. When a subsequent wake state transition occurs, the system updates the interrupt time count to compensate for the approximate duration of such a sleep state.

Callers of KeQueryInterruptTime can be running at any IRQL.

See Also

KeQueryPerformanceCounter, KeQueryTickCount, KeQueryTimeIncrement


KeQueryPerformanceCounter

KeQueryPerformanceCounter provides the finest grained running count available in the system.

LARGE_INTEGER
  KeQueryPerformanceCounter(
    OUT PLARGE_INTEGER  PerformanceFrequency  OPTIONAL
    );

Parameters

PerformanceFrequency
Optionally specifies a pointer to a variable that receives the performance counter frequency.

Include

wdm.h or ntddk.h

Return Value

KeQueryPerformanceCounter returns the performance counter value in units of ticks.

Comments

KeQueryPerformanceCounter always returns a 64-bit integer representing the current number of ticks. Accumulating the count begins when the system is booted.

The resolution of the timer used to accumulate the current count can be obtained by specifying a pointer value for PerformanceFrequency. The value returned is the number of ticks per second.

KeQueryPerformanceCounter is intended for time-stamping packets or for computing performance and capacity measurements. It is not intended for measuring elapsed time, for computing stalls or waits, or for iterations.

Use this routine as infrequently as possible. Depending on the platform, KeQueryPerformanceCounter can disable system-wide interrupts for a minimal interval. Consequently, calling this routine frequently, as in an iteration, defeats its purpose of returning very fine-grained, running time-stamp information. Calling this routine too frequently can degrade I/O performance for the calling driver and for the system as a whole.

Callers of KeQueryPerformanceCounter can be running at any IRQL.

See Also

KeQueryInterruptTime, KeQuerySystemTime, KeQueryTickCount, KeQueryTimeIncrement


KeQueryPriorityThread

KeQueryPriorityThread returns the current priority of a given thread.

KPRIORITY
KeQueryPriorityThread(
    IN PRKTHREAD  Thread
    );

Parameters

Thread
Pointer to a dispatcher object of type KTHREAD.

Include

wdm.h or ntddk.h

Return Value

KeQueryPriorityThread returns the current priority of the given thread.

Comments

The system-defined range of possible return values runs from zero to 32, inclusive, with zero designating the lowest possible thread priority.

Callers of KeQueryPriorityThread must be running at IRQL PASSIVE_LEVEL.

See Also

KeGetCurrentThread, KeSetBasePriorityThread, KeSetPriorityThread, PsGetCurrentThread


KeQuerySystemTime

KeQuerySystemTime obtains the current system time.

VOID
  KeQuerySystemTime(
    OUT PLARGE_INTEGER  CurrentTime
    );

Parameters

CurrentTime
Pointer to the current time on return from KeQuerySystemTime.

Include

wdm.h or ntddk.h

Comments

System time is a count of 100-nanosecond intervals since January 1, 1601. System time is typically updated approximately every ten milliseconds. This value is computed for the GMT time zone. To adjust this value for the local time zone use ExSystemTimeToLocalTime.

Callers of KeQuerySystemTime can be running at any IRQL.

See Also

ExSystemTimeToLocalTime, KeQueryPerformanceCounter, KeQueryTickCount, KeQueryTimeIncrement


KeQueryTickCount

KeQueryTickCount maintains a count of the interval timer interrupts that have occurred since the system was booted.

VOID
  KeQueryTickCount(
    OUT PLARGE_INTEGER  TickCount
    );

Parameters

TickCount
Pointer to the tick count value on return from KeQueryTickCount.

Include

wdm.h or ntddk.h

Comments

The TickCount value increases by one at each interval timer interrupt while the system is running.

The preferred method of determining elapsed time is by using TickCount for relative timing and time stamps.

To determine the absolute elapsed time multiply the returned TickCount by the KeQueryTimeIncrement return value using compiler support for 64-bit integer operations.

Callers of KeQueryTickCount can be running at any IRQL.

See Also

KeQueryInterruptTime, KeQueryPerformanceCounter, KeQueryTimeIncrement


KeQueryTimeIncrement

KeQueryTimeIncrement returns the number of 100-nanosecond units that are added to the system time each time the interval clock interrupts.

ULONG
  KeQueryTimeIncrement(
    );

Include

wdm.h or ntddk.h

Comments

Callers of KeQueryTimeIncrement can be running at any IRQL.

See Also

KeQueryPerformanceCounter, KeQuerySystemTime, KeQueryTickCount


KeRaiseIrql

KeRaiseIrql raises the hardware priority to a given IRQL value, thereby masking off interrupts of equivalent or lower IRQL on the current processor.

VOID
  KeRaiseIrql(
    IN KIRQL  NewIrql,
    OUT PKIRQL  OldIrql
    );

Parameters

NewIrql
Specifies the new IRQL to which the hardware priority is to be raised.
OldIrql
Pointer to the storage for the original (unraised) IRQL value to be used in a subsequent call to KeLowerIrql.

Include

wdm.h or ntddk.h

Comments

If the new IRQL is less than the current IRQL, a bug check occurs. Otherwise, the current IRQL is set to the specified value.

Callers of this routine can be running at any IRQL. Any caller should restore the original IRQL with KeLowerIrql as soon as possible.

A call to KeLowerIrql is valid if it specifies NewIrql <= CurrentIrql. A call to KeRaiseIrql is valid if the caller specifies NewIrql >= CurrentIrql.

See Also

KeGetCurrentIrql, KeLowerIrql


KeRaiseIrqlToDpcLevel

KeRaiseIrqlToDpcLevel raises the hardware priority to IRQL DISPATCH_LEVEL, thereby masking off interrupts of equivalent or lower IRQL on the current processor.

KIRQL
  KeRaiseIrqlToDpcLevel(
    );

ReturnValue

KeRaiseIrqlToDpcLevel returns the IRQL at which the call occurred.

Include

ntddk.h

Comments

Any caller of KeRaiseIrqlToDpcLevel should save the returned IRQL value. Every such caller must restore the original IRQL as quickly as possible by passing this returned IRQL in a subsequent call to KeLowerIrql.

Callers of KeRaiseIrqlToDpcLevel must be running at IRQL <= DISPATCH_LEVEL. Otherwise, a call to this routine causes a bug check.

See Also

KeGetCurrentIrql, KeLowerIrql, KeRaiseIrql


KeReadStateEvent

KeReadStateEvent returns the current state, signaled or not signaled, of a given event object.

LONG
  KeReadStateEvent(
    IN PRKEVENT  Event
    );

Parameters

Event
Pointer to an initialized event object for which the caller provides the storage.

Include

ntddk.h

Return Value

If the event object is currently set to a signaled state, a nonzero value is returned. Otherwise, zero is returned.

Comments

It is also possible to read the state of an event from a driver's interrupt service routine at DIRQL, if the following conditions are met: the driver's event object is resident (probably in its device extension), and any other function that accesses the event synchronizes its access with the ISR.

Callers of KeReadStateEvent must be running at IRQL <= DISPATCH_LEVEL.

See Also

KeClearEvent, KeInitializeEvent, KeResetEvent, KeSetEvent


KeReadStateMutex

KeReadStateMutex returns the current state, signaled or not signaled, of a given mutex object.

LONG
  KeReadStateMutex(
    IN PRKMUTEX  Mutex
    );

Parameters

Mutex
Pointer to an initialized mutex object for which the caller provides the storage.

Include

wdm.h or ntddk.h

Return Value

If the return value is one, the state of the mutex object is signaled.

Comments

Callers of KeReadStateMutex must be running at IRQL <= DISPATCH_LEVEL.

See Also

ExInitializeFastMutex, KeInitializeMutex, KeReleaseMutex


KeReadStateSemaphore

KeReadStateSemaphore returns the current state, signaled or not signaled, of a given semaphore object.

LONG
  KeReadStateSemaphore(
    IN PRKSEMAPHORE  Semaphore
    );

Parameters

Semaphore
Pointer to an initialized semaphore object for which the caller provides the storage.

Include

wdm.h or ntddk.h

Return Value

If the return value is zero, the semaphore object is set to a not signaled state.

Comments

Callers of KeReadStateSemaphore can be running at any IRQL.

See Also

KeInitializeSemaphore, KeReleaseSemaphore


KeReadStateTimer

KeReadStateTimer reads the current state of a given timer object.

BOOLEAN
  KeReadStateTimer(
    IN PKTIMER  Timer
    );

Parameters

Timer
Pointer to an initialized timer object, for which the caller provides the storage.

Include

wdm.h or ntddk.h

Return Value

If the current state of the timer object is signaled, TRUE is returned.

Comments

Callers of KeReadStateTimer must be running at IRQL <= DISPATCH_LEVEL.

See Also

KeCancelTimer, KeInitializeTimer, KeSetTimer


KeRegisterBugCheckCallback

KeRegisterBugCheckCallback registers bug-check callback routines.

BOOLEAN
  KeRegisterBugCheckCallback(
    IN PKBUGCHECK_CALLBACK_RECORD  CallbackRecord,
    IN PKBUGCHECK_CALLBACK_ROUTINE  CallbackRoutine,
    IN PVOID  Buffer,
    IN ULONG  Length,
    IN PUCHAR  Component
    );

Parameters

CallbackRecord
Pointer to a callback record, already initialized with KeInitializeCallbackRecord, for which the caller provides nonpaged storage.
CallbackRoutine
Specifies the entry point of the caller-supplied routine to be registered, declared as follows:
VOID
(*PKBUGCHECK_CALLBACK_ROUTINE) (
    IN PVOID Buffer,
    IN ULONG Length
    );

This caller-supplied routine is responsible for writing driver-determined state information at Buffer if a bug check occurs.

Buffer
Pointer to a caller-supplied buffer, which must be allocated from nonpaged pool.
Length
Specifies the size in bytes of the caller-allocated buffer.
Component
Pointer to a zero-terminated ANSI string identifying the caller. Usually, this is the name of the device driver, or possibly of its device.

Include

ntddk.h

Return Value

KeRegisterBugCheckCallback returns TRUE if the caller-supplied routine has been successfully added to the set of registered bug-check callbacks.

Comments

Device drivers can call KeRegisterBugCheckCallback to register their bug-check callback routines. If a system bug check occurs, such a callback usually saves device-state information to be written into the system crash dump file.

KeRegisterBugCheckCallback sets up a driver-supplied routine to be called if a bug check occurs so a device driver can save state information, such as the contents of device registers, that would not otherwise be saved in a system crash-dump file.

A driver-supplied bug-check callback routine writes whatever information the driver designer chooses into the memory at Buffer. The format of the data written at Buffer is driver-determined. This memory cannot be freed unless the driver first calls KeDeregisterBugCheckCallback. Like the driver-allocated memory at Buffer, such a bug-check callback routine cannot be pageable.

When the callback routine runs, interrupts are disabled. A callback routine cannot allocate resources, such as memory, because the system is being shut down. A bug-check callback also cannot use synchronization mechanisms, such as a spin lock. However, it should not need to acquire synchronization resources because other driver routines are effectively disabled while the system is being shut down for a bug check. The callback routine can safely call the HAL's READ_PORT_XXX and/or READ_REGISTER_XXX to collect state information from the device and transfer this data to the driver-allocated buffer. It can call any Ke Xxx or Hal Xxx that neither allocates memory nor acquires a synchronization resource.

The given Component string should identify the driver to aid in crash-dump debugging. During driver development, the Component identifier can be passed to the debugger to select only that component's dump data for examination. A bug-check callback routine also can be debugged.

Callers of KeRegisterBugCheckCallback can be running at any IRQL. Usually, a device driver is running at IRQL PASSIVE_LEVEL in its DriverEntry routine when it calls KeRegisterBugCheckCallback.

See Also

ExAllocatePool, KeBugCheck, KeBugCheckEx, KeDeregisterBugCheckCallback, KeInitializeCallbackRecord


KeReleaseInStackQueuedSpinLock

KeReleaseInStackQueuedSpinLock releases a queued spin lock acquired by KeAcquireInStackQueuedSpinLock.

VOID
FASTCALL
  KeReleaseInStackQueuedSpinLock (
    IN PKLOCK_QUEUE_HANDLE  LockHandle
    );

Parameters

LockHandle
Specifies the queued spin lock handle initialized by the call to KeAcquireInStackQueuedSpinLock that acquired the lock.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

This routine is only available on Windows XP and later.

See Also

KeAcquireInStackQueuedSpinLock


KeReleaseInStackQueuedSpinLockFromDpcLevel

KeReleaseInStackQueuedSpinLockFromDpcLevel releases a queued spin lock acquired by KeAcquireInStackQueuedSpinLockAtDpcLevel.

NTKERNELAPI
VOID
FASTCALL
  KeReleaseInStackQueuedSpinLockFromDpcLevel (
    IN PKLOCK_QUEUE_HANDLE  LockHandle
    );

Parameters

LockHandle
Specifies the queued spin lock handle initialized by the call to KeAcquireInStackQueuedSpinLockAtDpcLevel that acquired the lock.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

This routine is only available on Windows XP and later.

See Also

KeAcquireInStackQueuedSpinLockAtDpcLevel


KeReleaseMutex

KeReleaseMutex releases a given mutex object, specifying whether the caller is to call one of KeWait Xxx as soon as KeReleaseMutex returns control.

LONG
  KeReleaseMutex(
    IN PRKMUTEX  Mutex,
    IN BOOLEAN  Wait
    );

Parameters

Mutex
Pointer to an initialized mutex object for which the caller provides the storage.
Wait
Specifies whether or not the call to KeReleaseMutex is to be immediately followed by a call to one of KeWait Xxx.

Include

wdm.h or ntddk.h

Return Value

If the return value is zero, the mutex object was released and attained a state of signaled.

Comments

For better performance, use the ExXxxFastMutex routines instead of the KeXxxMutex routines. However, a fast mutex cannot be acquired recursively, as a kernel mutex can.

If the mutex object attains a signaled state, an attempt is made to satisfy a wait for the mutex object.

A mutex object can be released only by the thread currently holding the mutex. If an attempt is made to release a mutex not held by the thread, a bug check occurs. An attempt to release a mutex object whose current state is signaled also causes a bug check to occur.

When a mutex object attains a signaled state, it is removed from the list of mutexes held by that thread. If the thread's owned mutex list does not contain any more entries, the thread's original priority is restored.

If the value of the Wait parameter is TRUE, the return to the caller is executed without lowering IRQL or releasing the dispatcher database spin lock. Therefore, the call to KeReleaseMutex must be followed immediately by a call to one of KeWait Xxx.

This allows the caller to release a mutex and wait as one atomic operation, preventing a possibly superfluous context switch. However, a caller cannot wait at raised IRQL nor in an arbitrary thread context for a nonzero interval on a mutex object.

If a mutex is acquired recursively, the holding thread must call KeReleaseMutex as many times as it acquired the mutex to set it to the signaled state.

Callers of KeReleaseMutex must be running at IRQL PASSIVE_LEVEL.

See Also

ExReleaseFastMutex, ExReleaseFastMutexUnsafe, KeInitializeMutex, KeReadStateMutex, KeWaitForMultipleObjects, KeWaitForMutexObject, KeWaitForSingleObject


KeReleaseSemaphore

KeReleaseSemaphore releases a given semaphore object.

LONG
  KeReleaseSemaphore(
    IN PRKSEMAPHORE  Semaphore,
    IN KPRIORITY  Increment,
    IN LONG  Adjustment,
    IN BOOLEAN  Wait
    );

Parameters

Semaphore
Pointer to an initialized semaphore object for which the caller provides the storage.
Increment
Specifies the priority increment to be applied if releasing the semaphore causes a wait to be satisfied.
Adjustment
Specifies a value to be added to the current semaphore count. This value must be positive.
Wait
Specifies whether the call to KeReleaseSemaphore is to be followed immediately by a call to one of the KeWait Xxx.

Include

wdm.h or ntddk.h

Return Value

If the return value is zero, the previous state of the semaphore object is not signaled.

Comments

KeReleaseSemaphore supplies a run-time priority boost for waiting threads. If this call sets the semaphore to the signaled state, the semaphore count is augmented by the given value. The caller can also specify whether it will call one of the KeWait Xxx routines as soon as KeReleaseSemaphore returns control.

Releasing a semaphore object causes the semaphore count to be augmented by the value of the Adjustment parameter. If the resulting value is greater than the limit of the semaphore object, the count is not adjusted and an exception, STATUS_SEMAPHORE_COUNT_EXCEEDED, is raised.

Augmenting the semaphore object count causes the semaphore to attain a signaled state, and an attempt is made to satisfy as many waits as possible on the semaphore object.

If the value of the Wait parameter is TRUE, the return to the caller is executed without lowering IRQL or releasing the dispatcher database spin lock. Therefore, the call to KeReleaseSemaphore must be followed immediately by a call to one of the KeWait Xxx.

This capability allows the caller to release a semaphore and to wait as one atomic operation, preventing a possibly superfluous context switch. However, the caller cannot wait at raised IRQL nor in an arbitrary thread context for a nonzero interval on a semaphore object.

Callers of KeReleaseSemaphore must be running at IRQL <= DISPATCH_LEVEL provided that Wait is set to FALSE. Otherwise, the caller must be running at IRQL PASSIVE_LEVEL.

See Also

KeInitializeSemaphore, KeReadStateSemaphore, KeWaitForMultipleObjects, KeWaitForSingleObject


KeReleaseSpinLock

KeReleaseSpinLock releases a spin lock and restores the original IRQL at which the caller was running.

VOID
  KeReleaseSpinLock(
    IN PKSPIN_LOCK  SpinLock,
    IN KIRQL  NewIrql
    );

Parameters

SpinLock
Pointer to a spin lock for which the caller provides the storage.
NewIrql
Specifies the IRQL value saved from the preceding call to KeAcquireSpinLock.

Include

wdm.h or ntddk.h

Comments

This call is a reciprocal to KeAcquireSpinLock. The input NewIrql value must be the OldIrql returned by KeAcquireSpinLock.

Callers of this routine are running at IRQL DISPATCH_LEVEL. On return from KeReleaseSpinLock, IRQL is restored to the NewIrql value.

See Also

KeAcquireSpinLock, KeInitializeSpinLock


KeReleaseSpinLockFromDpcLevel

KeReleaseSpinLockFromDpcLevel releases an executive spin lock.

VOID
  KeReleaseSpinLockFromDpcLevel(
    IN PKSPIN_LOCK  SpinLock
    );

Parameters

SpinLock
Pointer to an executive spin lock for which the caller provides the storage.

Include

wdm.h or ntddk.h

Comments

Drivers call KeReleaseSpinLockFromDpcLevel to release a spin lock acquired by calling KeAcquireSpinLockAtDpcLevel.

It is an error to call KeReleaseSpinLockFromDpcLevel if the given spin lock was acquired by calling KeAcquireSpinLock because the caller's original IRQL is not restored, which can cause deadlocks or fatal page faults.

Callers of KeReleaseSpinLockAtDpcLevel must be running at IRQL DISPATCH_LEVEL.

See Also

KeAcquireSpinLock, KeAcquireSpinLockAtDpcLevel, KeReleaseSpinLock


KeRemoveByKeyDeviceQueue

KeRemoveByKeyDeviceQueue removes an entry, selected according to a sort key value, from a given device queue.

PKDEVICE_QUEUE_ENTRY
  KeRemoveByKeyDeviceQueue(
    IN PKDEVICE_QUEUE  DeviceQueue,
    IN ULONG  SortKey
    );

Parameters

DeviceQueue
Pointer to an initialized device queue object for which the caller provides the storage.
SortKey
Specifies the key to be used when searching the DeviceQueue.

Include

wdm.h or ntddk.h

Return Value

KeRemoveByKeyDeviceQueue returns the device queue entry that was removed; returns NULL if the queue was empty.

Comments

This routine searches for the first entry in the device queue that has a value greater than or equal to the SortKey. After this entry is found, this routine removes the entry from the device queue and returns it. If no such entry is found, then the first entry in the queue is returned. If the device queue is empty, then the device is set to a not busy state and a NULL pointer is returned.

It is an error to call KeRemoveByKeyDeviceQueue when the device queue object is set to a not busy state.

Callers of KeRemoveByKeyDeviceQueue must be running at IRQL DISPATCH_LEVEL.

See Also

KeInitializeDeviceQueue, KeInsertByKeyDeviceQueue, KeInsertDeviceQueue, KeRemoveDeviceQueue, KeRemoveEntryDeviceQueue


KeRemoveDeviceQueue

KeRemoveDeviceQueue removes an entry from the head of a specified device queue.

PKDEVICE_QUEUE_ENTRY
  KeRemoveDeviceQueue(
    IN PKDEVICE_QUEUE  DeviceQueue
    );

Parameters

DeviceQueue
Pointer to an initialized device queue object for which the caller provides the storage.

Include

wdm.h or ntddk.h

Return Value

If the device queue is empty but is set to a busy state, KeRemoveDeviceQueue returns NULL.

Comments

The specified device queue spin lock is acquired and the state of the device queue is checked. If the device queue is set to a busy state and an IRP is queued, this routine dequeues the entry and returns a pointer to the IRP. A call to KeRemoveDeviceQueue when the device queue object is set to a busy state but no IRPs are queued causes a state change to not busy. The given device queue's spin lock is released.

It is an error to call KeRemoveDeviceQueue when the device queue object is set to a not busy state.

Callers of KeRemoveDeviceQueue must be running at IRQL DISPATCH_LEVEL.

See Also

KeInitializeDeviceQueue, KeInsertByKeyDeviceQueue, KeInsertDeviceQueue, KeRemoveByKeyDeviceQueue, KeRemoveEntryDeviceQueue


KeRemoveEntryDeviceQueue

KeRemoveEntryDeviceQueue returns whether the specified entry is in the device queue and removes it, if it was queued, from the device queue.

BOOLEAN
  KeRemoveEntryDeviceQueue(
    IN PKDEVICE_QUEUE  DeviceQueue,
    IN PKDEVICE_QUEUE_ENTRY  DeviceQueueEntry
    );

Parameters

DeviceQueue
Pointer to an initialized device queue object for which the caller provides the storage.
DeviceQueueEntry
Pointer to the entry to be removed from the specified DeviceQueue.

Include

wdm.h or ntddk.h

Return Value

If the DeviceQueueEntry is queued, it is removed and KeRemoveEntryDeviceQueue returns TRUE.

Comments

The IRQL is set to DISPATCH_LEVEL and the DeviceQueue spin lock is acquired.

If the given DeviceQueueEntry is not in the queue, the IRP either is already being processed, or the IRP has been canceled. In this case, KeRemoveEntryDeviceQueue simply returns FALSE.

The specified DeviceQueue spin lock is released and IRQL is restored to its previous value.

Callers of KeRemoveEntryDeviceQueue must be running at IRQL <= DISPATCH_LEVEL.

See Also

KeInitializeDeviceQueue, KeInsertByKeyDeviceQueue, KeInsertDeviceQueue, KeRemoveByKeyDeviceQueue, KeRemoveDeviceQueue


KeRemoveQueueDpc

KeRemoveQueueDpc removes a given DPC object from the system DPC queue.

BOOLEAN
  KeRemoveQueueDpc(
    IN PRKDPC  Dpc
    );

Parameters

Dpc
Pointer to an initialized DPC object that was queued by calling KeInsertQueueDpc.

Include

wdm.h or ntddk.h

Return Value

KeRemoveQueueDpc returns TRUE if the DPC object is in the DPC queue. If the given DPC object is not currently in the DPC queue, no operation is performed and FALSE is returned.

Comments

If the given DPC object is currently queued, it is removed from the queue, canceling a call to the associated DPC routine.

Callers of KeRemoveQueueDpc can be running at any IRQL.

See Also

KeInitializeDpc, KeInsertQueueDpc


KeResetEvent

KeResetEvent resets a specified event object to a not signaled state and returns the previous state of that event object.

LONG
  KeResetEvent(
    IN PRKEVENT  Event
    );

Parameters

Event
Pointer to an initialized dispatcher object of type event for which the caller provides the storage.

Include

wdm.h or ntddk.h

Return Value

KeResetEvent returns the previous state of the given Event, nonzero for a signaled state.

Comments

Event is reset to a not signaled state, meaning that its value is set to zero.

Unless the caller uses the value returned by KeResetEvent, setting a given event object to a not signaled state using KeClearEvent is faster.

Callers of KeResetEvent must be running at IRQL <= DISPATCH_LEVEL.

See Also

KeClearEvent, KeInitializeEvent, KeReadStateEvent, KeSetEvent, KeWaitForMultipleObjects, KeWaitForSingleObject


KeRestoreFloatingPointState

KeRestoreFloatingPointState restores the nonvolatile floating-point context saved by the preceding call to KeSaveFloatingPointState.

NTSTATUS
  KeRestoreFloatingPointState(
    IN PKFLOATING_SAVE  FloatSave
    );

Parameters

FloatSave
Specifies the pointer passed in the preceding call to KeSaveFloatingPointState.

Include

wdm.h or ntddk.h

Return Value

KeRestoreFloatingPointState returns STATUS_SUCCESS.

Comments

KeRestoreFloatingPointState is the reciprocal of KeSaveFloatingPointState.

Any routine that calls KeSaveFloatingPointState must call KeRestoreFloatingPointState before that routine returns control, and it must be running at the same IRQL as that from which the preceding call to KeSaveFloatingPointState occurred. Failure to meet either of these conditions causes a system bug check.

See Also

KeSaveFloatingPointState


KeSaveFloatingPointState

KeSaveFloatingPointState saves the nonvolatile floating-point context so the caller can carry out floating-point operations.

NTSTATUS
  KeSaveFloatingPointState(
    OUT PKFLOATING_SAVE  FloatSave
    );

Parameters

FloatSave
Pointer to a caller-allocated resident buffer, which must be at least sizeof(KFLOATING_SAVE).

Include

wdm.h or ntddk.h

Return Value

KeSaveFloatingPointState returns STATUS_SUCCESS if it saved the current thread's floating-point context and set up a fresh floating point context for the caller. Otherwise, it returns one of the following:

STATUS_ILLEGAL_FLOAT_CONTEXT
The system is configured to use floating point emulation, rather than doing FP operations in the processors.
STATUS_INSUFFICIENT_RESOURCES
KeSaveFloatingPointState could not allocate sufficient memory to save the current thread's floating-point context.

Comments

A successful call to KeSaveFloatingPointState allows the caller to carry out floating point operations of its own, but such a caller must restore the previous nonvolatile floating-point context as soon as its FP operations are done. Any routine that calls KeSaveFloatingPointState must call KeRestoreFloatingPointState before that routine returns control.

If the call to KeSaveFloatingPointState is successful, the data at FloatSave is opaque to the caller, which can release the buffer it allocated only after calling KeRestoreFloatingPointState.

For performance reasons, drivers should avoid doing any floating point operations unless absolutely necessary. The overhead of saving and restoring the current thread's nonvolatile floating point state degrades the performance of any driver that does floating-point operations.

Callers of KeSaveFloatingPointState must be running at IRQL <= DISPATCH_LEVEL.

See Also

KeGetCurrentThread, KeRestoreFloatingPointState, PsCreateSystemThread


KeSetBasePriorityThread

KeSetBasePriorityThread sets the run-time priority, relative to the current process, for a given thread.

LONG
  KeSetBasePriorityThread(
    IN PRKTHREAD  Thread,
    IN LONG  Increment
    );

Parameters

Thread
Pointer to a dispatcher object of type KTHREAD.
Increment
Is the value to be added to the base priority of the process for the Thread.

Include

ntddk.h

Return Value

KeSetBasePriorityThread returns the previous base priority increment of the given thread. The previous base priority increment is defined as the difference between the specified thread's old base priority and the base priority of the thread's process.

Comments

The new base priority is computed by adding the given Increment, which can be a negative value, to the base priority of the specified thread's process. The resultant value is stored as the base priority of the specified thread.

Drivers that set up device-dedicated threads with variable priority attributes can call this routine to set such a thread's priority relative to the system process in which the thread is created.

The new base priority is restricted to the priority class of the given thread's process. Therefore, the base priority is not allowed to cross over from a variable priority class to a real-time priority class or vice versa.

Callers of KeSetBasePriorityThread must be running at IRQL PASSIVE_LEVEL.

See Also

KeGetCurrentThread, KeQueryPriorityThread, KeSetPriorityThread


KeSetEvent

KeSetEvent sets an event object to a signaled state if the event was not already signaled, and returns the previous state of the event object.

LONG
  KeSetEvent(
    IN PRKEVENT  Event,
    IN KPRIORITY  Increment,
    IN BOOLEAN  Wait
    );

Parameters

Event
Pointer to an initialized event object for which the caller provides the storage.
Increment
Specifies the priority increment to be applied if setting the event causes a wait to be satisfied.
Wait
Specifies whether the call to KeSetEvent is to be followed immediately by a call to a KeWait Xxx.

Include

wdm.h or ntddk.h

Return Value

If the previous state of the event object was signaled, a nonzero value is returned.

Comments

Calling KeSetEvent causes the event to attain a signaled state, and therefore, an attempt is made to satisfy as many waits as possible on the event object.

If the Wait parameter is TRUE, the return to the caller is executed without lowering IRQL or releasing the dispatcher database spin lock. Therefore, the call to KeSetEvent must be followed immediately by a call to one of the KeWait Xxx.

This allows the caller to set an event and wait as one atomic operation, preventing a possibly superfluous context switch. However, the caller cannot wait at raised IRQL nor in an arbitrary thread context for a nonzero interval on an event object.

If Wait is set to FALSE, the caller can be running at IRQL <= DISPATCH_LEVEL. Otherwise, callers of KeSetEvent must be running at IRQL PASSIVE_LEVEL and in a nonarbitrary thread context.

See Also

KeClearEvent, KeInitializeEvent, KeReadStateEvent, KeResetEvent, KeWaitForMultipleObjects, KeWaitForSingleObject


KeSetImportanceDpc

KeSetImportanceDpc controls how a particular DPC is queued and, to some degree, how soon the DPC routine is run.

VOID
  KeSetImportanceDpc(
    IN PRKDPC  Dpc,
    IN KDPC_IMPORTANCE  Importance
    );

Include

ntddk.h

Parameters

Dpc
Pointer to the caller's DPC object, already initialized with KeInitializeDpc.
Importance
Specifies one of the following system-defined values:
LowImportance
Queue the DPC at the end of the target DPC queue, but do not start running queued DPC routines immediately.
MediumImportance
Queue the DPC at the end of the target DPC queue and start running the queued DPC routines immediately if possible. This is the system-assigned default value for DPC objects.
HighImportance
Queue the DPC at the front of the target processor's DPC queue and start running the queued DPC routines immediatedly if possible.

Comments

KeSetImportanceDpc can override the kernel-determined order in which DPC objects are queued for execution. By default, the kernel queues all DPCs at MediumImportance. Usually, each DPC is queued on the current processor from which the call to KeInsertQueueDpc occurs or, from a device driver's ISR, the call to IoRequestDpc occurs.

In general, an NT device driver should not call KeSetImportanceDpc to change the default priority of a driver-created DPC object that represents a CustomDpc routine queued by the driver's ISR with KeInsertQueueDpc. MediumImportance ensures that such a driver's ISR always returns control before that driver 's corresponding CustomDpc routine runs in an SMP machine. Otherwise, an NT device driver with such a CustomDpc routine must be capable of handling the following conditions:

  • Resetting a device driver's DPC to LowImportance requires that driver's CustomDpc routine to be capable of handling all post-interrupt processing for more than one execution of the driver's ISR, effectively for any number of interrupts that might occur between executions of its CustomDpc routine.
  • Resetting a device driver's DPC object to HighImportance on an SMP platform can cause the driver's ISR and CustomDpc routines to be run simultaneously on different processors, and the driver cannot determine when such concurrent executions will occur. Consequently, such a device driver's ISR and CustomDpc routine must be capable of handling any synchronization problems that might occur due to their concurrent executions.

Callers of KeSetImportanceDpc can be running at any IRQL.

See Also

IoRequestDpc, KeInitializeDpc, KeInsertQueueDpc, KeSetTargetProcessorDpc, KeSynchronizeExecution


KeSetPriorityThread

KeSetPriorityThread sets the run-time priority of a driver-created thread.

KPRIORITY
  KeSetPriorityThread(
    IN PKTHREAD  Thread,
    IN KPRIORITY  Priority
    );

Parameters

Thread
Pointer to the driver-created thread.
Priority
Specifies the priority of the driver-created thread, usually to the real-time priority value, LOW_REALTIME_PRIORITY. The value LOW_PRIORITY is reserved for system use.

Include

wdm.h or ntddk.h

Return Value

KeSetPriorityThread returns the old priority of the thread.

Comments

If a call to KeSetPriorityThread resets the thread's priority to a lower value, execution of the thread can be rescheduled even if it is currently running or is about to be dispatched for execution.

Callers of KeSetPriorityThread must be running at IRQL PASSIVE_LEVEL.

See Also

KeGetCurrentThread, KeQueryPriorityThread, KeSetBasePriorityThread


KeSetTargetProcessorDpc

KeSetTargetProcessorDpc controls on which processor a particular DPC routine subsequently will be queued.

VOID
  KeSetTargetProcessorDpc(
    IN PRKDPC  Dpc,
    IN CCHAR  Number
    );

Parameters

Dpc
Pointer to the caller's DPC object, already initialized with KeInitializeDpc.
Number
Specifies the zero-based number of the target processor on which the DPC should be queued and executed.

Include

ntddk.h

Comments

KeSetTargetProcessorDpc can be called on SMP platforms to control the target processor on which the caller's DPC will be queued and, consequently, the target processor on which the caller's DPC routine will execute.

By default, the kernel queues all DPCs on the current processor from which the call to KeInsertQueueDpc (or, from NT device drivers, to IoRequestDpc) occurs. On a uniprocessor platform, calls to KeSetTargetProcessorDpc have no effect.

Callers of KeSetTargetProcessorDpc can be running at any IRQL.

See Also

IoRequestDpc, KeGetCurrentProcessorNumber, KeInitializeDpc, KeInsertQueueDpc, KeSetImportanceDpc


KeSetTimer

KeSetTimer sets the absolute or relative interval at which a timer object is to be set to a signaled state and, optionally, supplies a CustomTimerDpc routine to be executed when that interval expires.

BOOLEAN
  KeSetTimer(
    IN PKTIMER  Timer,
    IN LARGE_INTEGER  DueTime,
    IN PKDPC  Dpc  OPTIONAL
    );

Parameters

Timer
Pointer to a timer object that was initialized with KeInitializeTimer or KeInitializeTimerEx.
DueTime
Specifies the absolute or relative time at which the timer is to expire. If the value of the DueTime parameter is negative, the expiration time is relative to the current system time. Otherwise, the expiration time is absolute. The expiration time is expressed in system time units (100-nanosecond intervals). Absolute expiration times track any changes in the system time; relative expiration times are not affected by system time changes.
Dpc
Pointer to a DPC object that was initialized by KeInitializeDpc. This parameter is optional.

Include

wdm.h or ntddk.h

Return Value

If the timer object was already in the system timer queue, KeSetTimer returns TRUE.

Comments

KeSetTimer:

  • Computes the expiration time.
  • Sets the timer to a not signaled state.
  • Inserts the timer object in the system timer queue.

If the timer object was already in the timer queue, it is implicitly canceled before being set to the new expiration time. A call to KeSetTimer before the previously specified DueTime has expired cancels both the timer and the call to the Dpc, if any, associated with the previous call.

If the Dpc parameter is specified, a DPC object is associated with the timer object. When the timer expires, the timer object is removed from the system timer queue and its state is set to signaled. If a DPC object was associated with the timer when it was set, the DPC object is inserted in the system DPC queue to be executed as soon as conditions permit after the timer interval expires.

The expiration of the timer ultimately depends on the granularity of the system clock. The value specified for DueTime guarantees that the timer object is set to a signaled state on or after the given DueTime. However, KeSetTimer cannot override the granularity of the system clock, whatever the value specified for DueTime.

Only one instantiation of a given DPC object can be queued at any given moment. To avoid potential race conditions, the DPC passed to KeSetTimer should not be passed to KeInsertQueueDpc.

A caller cannot wait at raised IRQL nor in an arbitrary thread context for a timer to expire by calling KeWait Xxx.

Callers of KeSetTimer can specify one expiration time for a timer. To set a recurring timer use KeSetTimerEx.

Callers of KeSetTimer must be running at IRQL <= DISPATCH_LEVEL.

See Also

KeCancelTimer, KeInitializeDpc, KeInitializeTimer, KeInitializeTimerEx, KeReadStateTimer, KeSetTimerEx, KeWaitForMultipleObjects, KeWaitForSingleObject


KeSetTimerEx

KeSetTimerEx sets the absolute or relative interval at which a timer object is to be set to a signaled state, optionally supplies a CustomTimerDpc routine to be executed when that interval expires, and optionally supplies a recurring interval for the timer.

BOOLEAN
  KeSetTimerEx(
    IN PKTIMER  Timer,
    IN LARGE_INTEGER  DueTime,
    IN LONG  Period  OPTIONAL,
    IN PKDPC  Dpc  OPTIONAL
    );

Parameters

Timer
Pointer to a timer object that was initialized with KeInitializeTimer or KeInitializeTimerEx.
DueTime
Specifies the absolute or relative time at which the timer is to expire. If the value of the DueTime parameter is negative, the expiration time is relative to the current system time. Otherwise, the expiration time is absolute. The expiration time is expressed in system time units (100-nanosecond intervals). Absolute expiration times track any changes in the system time; relative expiration times are not affected by system time changes.
Period
Specifies an optional period for the timer in milliseconds. Must be less than or equal to MAXLONG.
Dpc
Pointer to a DPC object that was initialized by KeInitializeDpc. This parameter is optional.

Include

wdm.h or ntddk.h

Return Value

If the timer object was already in the system timer queue, KeSetTimerEx returns TRUE.

Comments

KeSetTimerEx:

  • Computes the expiration time.
  • Sets the timer to a not signaled state.
  • Sets the recurring interval for the timer, if one was specified.
  • Inserts the timer object in the system timer queue.

If the timer object was already in the timer queue, it is implicitly canceled before being set to the new expiration time. A call to KeSetTimerEx before the previously specified DueTime has expired cancels both the timer and the call to the Dpc, if any, associated with the previous call.

The expiration of the timer ultimately depends on the granularity of the system clock. The value specified for DueTime guarantees that the timer object is set to a signaled state on or after the given DueTime. However, KeSetTimerEx cannot override the granularity of the system clock, whatever the value specified for DueTime.

If the Dpc parameter is specified, a DPC object is associated with the timer object. When the timer expires, the timer object is removed from the system timer queue and it is set to a signaled state. If a DPC object was associated with the timer when it was set, the DPC object is inserted in the system DPC queue to be executed as soon as conditions permit after the timer interval expires.

A DPC routine cannot deallocate a periodic timer. A DPC routine can deallocate a nonperiodic timer.

Only one instantiation of a given DPC object can be queued at any given moment. To avoid potential race conditions, the DPC passed to KeSetTimerEx should not be passed to KeInsertQueueDpc.

A caller cannot wait at raised IRQL nor in an arbitrary thread context for a timer to expire by calling KeWait Xxx.

Callers of KeSetTimerEx must be running at IRQL <= DISPATCH_LEVEL.

See Also

KeCancelTimer, KeInitializeDpc, KeInitializeTimer, KeInitializeTimerEx, KeReadStateTimer, KeWaitForMultipleObjects, KeWaitForSingleObject


KeStallExecutionProcessor

KeStallExecutionProcessor stalls the caller on the current processor for the given interval.

VOID
  KeStallExecutionProcessor(
    IN ULONG  MicroSeconds
    );

Parameters

MicroSeconds
Specifies the number of microseconds to stall.

Include

wdm.h or ntddk.h

Comments

KeStallExecutionProcessor is a processor-dependent routine that busy-waits for at least the specified number of microseconds, but not significantly longer.

This routine is for use by device drivers and other software that must wait for an interval of less than a clock tick but more than for a few instructions. Drivers that call this routine should minimize the number of microseconds they specify (no more than 50). If a driver must wait for a longer interval, it should use another synchronization mechanism.

Callers of KeStallExecutionProcessor can be running at any IRQL.

See Also

KeDelayExecutionThread, KeWaitForMultipleObjects, KeWaitForSingleObject


KeSynchronizeExecution

KeSynchronizeExecution synchronizes the execution of a given routine with that of the ISR associated with the given interrupt object pointer.

BOOLEAN
  KeSynchronizeExecution(
    IN PKINTERRUPT    Interrupt,
    IN PKSYNCHRONIZE_ROUTINE  SynchronizeRoutine,
    IN PVOID  SynchronizeContext
    );

Parameters

Interrupt
Is a pointer to a set of interrupt objects. This pointer was returned by IoConnectInterrupt.
SynchronizeRoutine
Is the entry point for a caller-supplied SynchCritSection routine whose execution is to be synchronized with the execution of the ISR associated with the interrupt objects. A SynchronizeRoutine is declared as follows:
BOOLEAN
(*PKSYNCHRONIZE_ROUTINE) (
    IN PVOID SynchronizeContext
    );
SynchronizeContext
Pointer to a caller-supplied context area to be passed to the SynchronizeRoutine when it is called.

Include

wdm.h or ntddk.h

Return Value

KeSynchronizeExecution returns TRUE if the operation succeeds.

Comments

When this routine is called, the following occurs:

  1. The IRQL is raised to the SynchronizeIrql specified in the call to IoConnectInterrupt.
  2. Access to SynchronizeContext is synchronized with the corresponding ISR by acquiring the associated interrupt object spin lock.
  3. The specified SynchronizeRoutine is called with the input pointer to SynchronizeContext.

The caller-supplied SynchronizeRoutine runs at DIRQL, so it must execute very quickly.

Callers of KeSynchronizeExecution must be running at IRQL <= DIRQL, that is, less than or equal to the value of the SynchronizeIrql parameter specified when the caller registered its ISRs with IoConnectInterrupt.

See Also

IoConnectInterrupt


KeWaitForMultipleObjects

KeWaitForMultipleObjects routine puts the current thread into an alertable or nonalertable wait state until any or all of a number of dispatcher objects are set to a signaled state or (optionally) until the wait times out.

NTSTATUS
  KeWaitForMultipleObjects(
    IN ULONG  Count,
    IN PVOID  Object[],
    IN WAIT_TYPE  WaitType,
    IN KWAIT_REASON  WaitReason,
    IN KPROCESSOR_MODE  WaitMode,
    IN BOOLEAN  Alertable,
    IN PLARGE_INTEGER  Timeout  OPTIONAL,
    IN PKWAIT_BLOCK  WaitBlockArray  OPTIONAL
    );

Parameters

Count
Specifies the number of objects to be waited on.
Object
Points to an array of pointers to dispatcher objects (events, mutexes, semaphores, threads, and timers) for which the caller supplies the storage.
WaitType
Specifies either WaitAll, indicating that all of the specified objects must attain a signaled state before the wait is satisfied; or WaitAny, indicating that any one of the objects must attain a signaled state before the wait is satisfied.
WaitReason
Specifies the reason for the wait. Drivers should set this value to Executive or, if the driver is doing work on behalf of a user and is running in the context of a user thread, to UserRequest.
WaitMode
Specifies whether the caller waits in KernelMode or UserMode. Intermediate and lowest level drivers should specify KernelMode. If the set of objects waited on includes a mutex, the caller must specify KernelMode.
Alertable
Specifies a Boolean value that indicates whether the thread can be alerted while it is in the waiting state.
Timeout
Points to an absolute or relative value representing the upper limit for the wait. A negative value specifies an interval relative to the current system time. The value should be expressed in units of 100 nanoseconds. Absolute expiration times track any changes in the system time; relative expiration times are not affected by system time changes.
WaitBlockArray
Points to an optional array of wait blocks that describe the wait operation.

Include

wdm.h or ntddk.h

Return Value

KeWaitForMultipleObjects can return one of the following:

STATUS_SUCCESS
Depending on the specified WaitType, one or all of the dispatcher objects in the Object array satisfied the wait.
STATUS_ALERTED
The wait is completed because of an alert to the thread.
STATUS_USER_APC
A user APC was delivered to the current thread before the specified Timeout interval expired.
STATUS_TIMEOUT
A time-out occurred before the specified set of wait conditions was met. This value can be returned when an explicit time-out value of zero is specified, but the specified set of wait conditions cannot be met immediately.

Note that the NT_SUCCESS macro recognizes all of these status values as "success" values.

If KeWaitForMultipleObjects returns STATUS_SUCCESS and if WaitAny is specified as the WaitType, KeWaitForMultipleObjects also returns the zero-based index of the object that satisfied the wait at NTSTATUS.

Comments

Each thread object has a built-in array of wait blocks that can be used to wait on several objects concurrently. Whenever possible, the built-in array of wait blocks should be used in a wait-multiple operation because no additional wait block storage needs to be allocated and later deallocated. However, if the number of objects that must be waited on concurrently is greater than the number of built-in wait blocks, use the WaitBlockArray parameter to specify an alternate set of wait blocks to be used in the wait operation.

If the WaitBlockArray parameter is NULL, the Count parameter must be less than or equal to THREAD_WAIT_OBJECTS or a bug check will occur.

If the WaitBlockArray pointer is nonNULL, the Count parameter must be less than or equal to MAXIMUM_WAIT_OBJECTS or a bug check will occur.

The current state for each of the specified objects is examined to determine whether the wait can be satisfied immediately. If the necessary side effects are performed on the objects, an appropriate value is returned.

If the wait cannot be satisfied immediately and either no time-out value or a nonzero time-out value has been specified, the current thread is put in a waiting state and a new thread is selected for execution on the current processor. If no Timeout is supplied, the calling thread will remain in a wait state until the conditions specified by Object and WaitType are satisfied.

If Timeout is specified, the wait will be automatically satisfied if none of the specified wait conditions is met when the given interval expires.

A Timeout value of zero allows the testing of a set of wait conditions, conditionally performing any side effects if the wait can be immediately satisfied, as in the acquisition of a mutex.

The Alertable parameter specifies whether the thread can be alerted and its wait state consequently aborted. If the value of this parameter is FALSE then the thread cannot be alerted, no matter what the value of the WaitMode parameter or the origin of the alert. The only exception to this rule is that of a terminating thread. A thread is automatically made alertable, for instance, when terminated by a user with a CTRL+C.

If the value of Alertable is TRUE and one of the following conditions exists, the thread will be alerted:

  1. If the origin of the alert is an internal, undocumented kernel-mode routine used to alert threads.
  2. If the origin of the alert is a user-mode APC and the value of the WaitMode parameter is UserMode.

In the first of these two cases, the thread's wait is satisfied with a completion status of STATUS_ALERTED; in the second case, it is satisfied with a completion status of STATUS_USER_APC.

The thread must be alertable for a user-mode APC to be delivered. This is not the case for kernel-mode APCs. A kernel-mode APC can be delivered and executed even though the thread is not alerted. Once the APC's execution completes, the thread's wait will resume. A thread is never alerted nor is its wait aborted by the delivery of a kernel-mode APC.

The delivery of kernel-mode APCs to a waiting thread does not depend on whether the thread can be alerted, but it depends on other conditions. If the kernel-mode APC is a special kernel-mode APC, then the APC is delivered provided that IRQL < APC_LEVEL. If the kernel-mode APC is a normal kernel-mode APC, then the APC is delivered provided that the following three conditions hold: (1) IRQL < APC_LEVEL, (2) no kernel APC is in progress, and (3) the thread is not in a critical section.

A special consideration applies when the Object parameter passed to KeWaitForMultipleObjects is a mutex. If the dispatcher object waited on is a mutex, APC delivery is the same as for all other dispatcher objects during the wait. However, once KeWaitForMultipleObjects returns with STATUS_SUCCESS and the thread actually holds the mutex, only special kernel-mode APCs are delivered. Delivery of all other APCs, both kernel-mode and user-mode, is disabled. This restriction on the delivery of APCs persists until the mutex is released.

For additional information, see Do Waiting Threads Receive Alerts and APCs?

If the WaitMode parameter is UserMode, the kernel stack can be swapped out during the wait. Consequently, a caller must never attempt to pass parameters on the stack when calling KeWaitForMultipleObjects with the UserMode argument. If you allocate the event on the stack, you must set the WaitMode parameter to KernelMode.

It is especially important to check the return value of KeWaitForMultipleObjects when the WaitMode parameter is UserMode or Alertable is TRUE, because KeWaitForMultipleObjects might return early with a status of STATUS_USER_APC or STATUS_ALERTED.

All long term waits that can be aborted by a user should be UserMode waits and Alertable should be set to FALSE.

Where possible, Alertable should be set to FALSE and WaitMode should be set to KernelMode, in order to reduce driver complexity. The principal exception to this is when the wait is a long term wait.

Callers of KeWaitForMultipleObjects can be running at IRQL <= DISPATCH_LEVEL. However, the caller cannot wait at raised IRQL for a nonzero interval nor in an arbitrary thread context on any dispatcher object. Therefore callers usually are running at IRQL PASSIVE_LEVEL. A call while running at IRQL = DISPATCH_LEVEL is valid if and only if the caller specifies a Timeout of zero. That is, a driver must not wait for a nonzero interval at IRQL = DISPATCH_LEVEL.

See Also

ExInitializeFastMutex, KeInitializeEvent, KeInitializeMutex, KeInitializeSemaphore, KeInitializeTimer, KeWaitForMutexObject, KeWaitForSingleObject


KeWaitForMutexObject

KeWaitForMutexObject routine puts the current thread into an alertable or nonalertable wait state until the given mutex object is set to a signaled state or (optionally) until the wait times out.

NTSTATUS
  KeWaitForMutexObject(
    IN PRKMUTEX  Mutex,
    IN KWAIT_REASON  WaitReason,
    IN KPROCESSOR_MODE  WaitMode,
    IN BOOLEAN  Alertable,
    IN PLARGE_INTEGER  Timeout  OPTIONAL
    );

Parameters

Mutex
Pointer to an initialized mutex object for which the caller supplies the storage.
WaitReason
Specifies the reason for the wait, which should be set to Executive. If the driver is doing work on behalf of a user and is running in the context of a user thread, this parameter should be set to UserRequest.
WaitMode
The caller must specify KernelMode.
Alertable
Specifies a Boolean value that indicates whether the wait is alertable.
Timeout
Pointer to a time-out value that specifies the absolute or relative time at which the wait is to be completed (optional). A negative value specifies an interval relative to the current time. The value should be expressed in units of 100 nanoseconds. Absolute expiration times track any changes in the system time; relative expiration times are not affected by system time changes.

Include

wdm.h or ntddk.h

Return Value

KeWaitForMutexObject can return one of the following:

STATUS_SUCCESS
The dispatcher object specified by the Mutex parameter satisfied the wait.
STATUS_ALERTED
The wait was completed because of an alert to the thread.
STATUS_USER_APC
A user APC was delivered to the current thread before the specified Timeout interval expired.
STATUS_TIMEOUT
A time-out occurred before the mutex was set to a signaled state. This value can be returned when an explicit time-out value of zero is specified and the specified set of wait conditions cannot be immediately met.

Note that the NT_SUCCESS macro recognizes all of these status values as "success" values.

Comments

KeWaitForMutexObject is a macro that converts to KeWaitForSingleObject, which can be used instead.

For better performance, use the ExXxxFastMutex routines instead of the KeXxxMutex routines. However, a fast mutex cannot be acquired recursively, as a kernel mutex can.

The current state of the given mutex object is examined to determine whether the wait can be satisfied immediately. If so, the necessary side effects are performed on the mutex. Otherwise, the current thread is put in a waiting state and a new thread is selected for execution on the current processor.

The Alertable parameter specifies whether the thread can be alerted and its wait state consequently aborted. If the value of this parameter is FALSE then the thread cannot be alerted, no matter what the value of the WaitMode parameter or the origin of the alert. The only exception to this rule is that of a terminating thread. A thread is automatically made alertable, for instance, when terminated by a user with a CTRL+C.

If the value of Alertable is TRUE and one of the following conditions is present, the thread will be alerted:

  1. If the origin of the alert is an internal, undocumented kernel-mode routine used to alert threads.
  2. The origin of the alert is a user-mode APC, and the value of the WaitMode parameter is UserMode.

In the first of these two cases, the thread's wait is satisfied with a completion status of STATUS_ALERTED; in the second case, it is satisfied with a completion status of STATUS_USER_APC.

The thread must be alertable for a user-mode APC to be delivered. This is not the case for kernel-mode APCs. A kernel-mode APC can be delivered and executed even though the thread is not alerted. Once the APC's execution completes, the thread's wait resumes. A thread is never alerted, nor is its wait aborted, by the delivery of a kernel-mode APC.

The delivery of kernel-mode APCs to a waiting thread does not depend on whether the thread can be alerted. If the kernel-mode APC is a special kernel-mode APC, then the APC is delivered provided that IRQL < APC_LEVEL. If the kernel-mode APC is a normal kernel-mode APC, then the APC is delivered provided that the following three conditions hold: (1) IRQL < APC_LEVEL, (2) no kernel APC is in progress, and (3) the thread is not in a critical section.

Since KeWaitForMutexObject initiates a wait on a mutex object, a special consideration applies. APC delivery is the same for mutexes as for all other dispatcher objects during the wait to acquire the mutex. However, once KeWaitForMutexObject returns with STATUS_SUCCESS and the thread actually holds the mutex, only special kernel-mode APCs are delivered. Delivery of all other APCs, both kernel-mode and user-mode, is disabled. This restriction on the delivery of APCs persists until the mutex is released.

For additional information, see Do Waiting Threads Receive Alerts and APCs?

If the WaitMode parameter is UserMode, the kernel stack can be swapped out during the wait. Consequently, a caller must never attempt to pass parameters on the stack when calling KeWaitForMutexObject using the UserMode argument.

It is especially important to check the return value of KeWaitForMutexObject when the WaitMode parameter is UserMode or Alertable is TRUE, because KeWaitForMutexObject might return early with a status of STATUS_USER_APC or STATUS_ALERTED.

All long term waits that can be aborted by a user should be UserMode waits and Alertable should be set to FALSE.

Where possible, Alertable should be set to FALSE and WaitMode should be set to KernelMode, in order to reduce driver complexity. The principal exception to this is when the wait is a long term wait. If no Timeout is supplied, the calling thread remains in a wait state until the Mutex is signaled.

A Timeout of zero allows the testing of a set of wait conditions and for conditionally performing any side effects if the wait can be immediately satisfied, such as acquiring the Mutex.

Callers of KeWaitForMutexObject must be running at IRQL <= DISPATCH_LEVEL. Usually, the caller must be running at IRQL = PASSIVE_LEVEL and in a nonarbitrary thread context. A call while running at IRQL = DISPATCH_LEVEL is valid if and only if the caller specifies a Timeout of zero. That is, a driver must not wait for a nonzero interval at IRQL = DISPATCH_LEVEL.

See Also

ExAcquireFastMutex, ExAcquireFastMutexUnsafe, ExInitializeFastMutex, KeBugCheckEx, KeInitializeMutex, KeReadStateMutex, KeReleaseMutex


Memory Manager Routines

References for the Mm Xxx routines and macros are in alphabetical order.

For an overview of the functionality of these routines and macros, see Summary of Kernel-Mode Support Routines.

The following routines are reserved for system use. Do not use them in your driver.

MmGetMdlBaseVa

MmGetProcedureAddress

MmGetVirtualForPhysical

MmIsDriverVerifying

MmMapUserAddressesToPage

MmMapVideoDisplay

MmMapViewInSessionSpace

MmMapViewInSystemSpace

MmProbeAndLockProcessPages

MmSecureVirtualMemory

MmUnmapVideoDisplay

MmUnmapViewInSessionSpace

MmUnmapViewInSystemSpace

MmUnsecureVirtualMemory


MmAllocateContiguousMemory

MmAllocateContiguousMemory allocates a range of physically contiguous, cache-aligned memory from nonpaged pool.

PVOID
  MmAllocateContiguousMemory(
    IN ULONG  NumberOfBytes,
    IN PHYSICAL_ADDRESS  HighestAcceptableAddress
    );

Parameters

NumberOfBytes
Specifies the size in bytes of the block of contiguous memory to be allocated.
HighestAcceptableAddress
Specifies the highest valid physical address the driver can use. For example, if a device can only reference physical memory in the lower 16MB, this value would be set to 0x00000000FFFFFF.

Include

ntddk.h

Return Value

MmAllocateContiguousMemory returns the base virtual address for the allocated memory. If the request cannot be satisfied, NULL is returned.

Comments

MmAllocateContiguousMemory can be called to allocate a contiguous block of physical memory for a long-term internal buffer, usually from the DriverEntry routine.

A device driver that must use contiguous memory should allocate only what it needs during driver initialization because nonpaged pool is likely to become fragmented as the system runs. Such a driver must deallocate the memory if it is unloaded. Contiguous allocations are aligned on an integral multiple of the processor's data-cache-line size to prevent cache and coherency problems.

Callers of MmAllocateContiguousMemory must be running at IRQL = PASSIVE_LEVEL.

See Also

AllocateCommonBuffer, KeGetDcacheFillSize, MmAllocateNonCachedMemory, MmFreeContiguousMemory


MmAllocateContiguousMemorySpecifyCache

MmAllocateContiguousMemorySpecifyCache allocates a range of physically contiguous, cache-aligned memory from non-paged pool.

NTKERNELAPI PVOID
  MmAllocateContiguousMemorySpecifyCache(
    IN SIZE_T  NumberOfBytes,
    IN PHYSICAL_ADDRESS  LowestAcceptableAddress,
    IN PHYSICAL_ADDRESS  HighestAcceptableAddress,
    IN PHYSICAL_ADDRESS  BoundaryAddressMultiple  OPTIONAL,
    IN MEMORY_CACHING_TYPE  CacheType
    );

Parameters

NumberOfBytes
Specifies the number of bytes to allocate.
LowestAcceptableAddress
Specifies the lowest valid physical address driver can use.
HighestAcceptableAddress
Specifies the highest valid physical address driver can use.
BoundaryAddressMultiple
If nonzero, this specifies the address multiple the allocated buffer must not cross.
CacheType
Specifies a MEMORY_CACHING_TYPE value, which indicates the type of caching allowed for the requested memory. The possible values that drivers can use are:
MmNonCached
The requested memory cannot be cached by the processor.
MmCached
The processor may cache the requested memory.
MmWriteCombined
The requested memory cannot be cached, but can be used as a frame buffer by the video port driver.

Include

ntddk.h

Return Value

MmAllocateContiguousMemorySpecifyCache returns the base virtual address for the allocated memory. If the system is unable to allocate the request buffer, the routine returns NULL.

Comments

Drivers use this routine to allocate memory at initialization. For more information, see MmAllocateContiguousMemory.


MmAllocateNonCachedMemory

MmAllocateNonCachedMemory allocates a virtual address range of noncached and cache-aligned memory.

PVOID
  MmAllocateNonCachedMemory(
    IN ULONG  NumberOfBytes
    );

Parameters

NumberOfBytes
Specifies the size in bytes of the range to be allocated.

Include

ntddk.h

Return Value

If the requested memory cannot be allocated, the return value is NULL. Otherwise, it is the base virtual address of the allocated range.

Comments

MmAllocateNonCachedMemory can be called from a DriverEntry routine to allocate a noncached block of virtual memory for various device-specific buffers.

A device driver that must use noncached memory should allocate only what it needs during driver initialization because nonpaged pool is likely to become fragmented as the system runs. Such a driver must deallocate the memory if it is unloaded. Noncached allocations are aligned on an integral multiple of the processor's data-cache-line size to prevent cache and coherency problems.

Callers of MmAllocateNonCachedMemory must be running at IRQL < DISPATCH_LEVEL.

See Also

AllocateCommonBuffer, KeGetDcacheFillSize, MmAllocateContiguousMemory, MmFreeNonCachedMemory


MmAllocatePagesForMdl

MmAllocatePagesForMdl allocates zero-filled, nonpaged, physical memory pages to an MDL.

PMDL
  MmAllocatePagesForMdl(
    IN PHYSICAL_ADDRESS  LowAddress,
    IN PHYSICAL_ADDRESS  HighAddress,
    IN PHYSICAL_ADDRESS  SkipBytes,
    IN SIZE_T  TotalBytes
    );

Parameters

LowAddress
Specifies the physical address of the start of the first address range from which the allocated pages can come. If MmAllocatePagesForMdl can not allocate the requested number of bytes in the first address range, it iterates through additional address ranges. At each iteration MmAllocatePagesForMdl adds the value of SkipBytes to the previous start address to obtain the start of the next address range.
HighAddress
Specifies the physical address of the end of the first address range from which the allocated pages can come.
SkipBytes
Specifies the number of bytes to skip from the start of the previous address range from which the allocated pages can come. SkipBytes must be an integer multiple of the page size, in bytes.
TotalBytes
Specifies the total number of bytes to allocate for the MDL.

Include

ntddk.h

Return Value

MmAllocatePagesForMdl returns one of the following:

MDL pointer
The MDL pointer maps a set of physical pages in the specified address range. If the requested number of bytes is not available, the MDL maps as much physical memory as is available.
NULL
There are no physical memory pages in the specified address ranges, or there is not enough virtually-contiguous nonpaged memory for the MDL.

Comments

MmAllocatedPagesForMdl is designed to be used by kernel-mode drivers that achieve substantial performance gains if physical memory for a device is allocated in a specific physical address range. A driver for an AGP graphics card is an example of such a driver.

Depending on how much physical memory is currently available in the requested ranges, MmAllocatedPagesForMdl might return an MDL that maps less memory than was requested. The routine returns NULL if no memory was allocated. A client should check the amount of memory that is actually allocated to the MDL.

The caller must use MmFreePagesFromMdl to release the memory pages that are described by an MDL that was created by MmAllocatePagesForMdl. After calling MmFreePagesFromMdl, the caller must also call ExFreePool to release the memory allocated for the MDL structure.

MmAllocatePagesForMdl runs at IRQL <= APC_LEVEL.

See Also

MmFreePagesFromMdl, MmMapLockedPages, ExFreePool


MmBuildMdlForNonPagedPool

MmBuildMdlForNonPagedPool fills in the corresponding physical page array of a given MDL for a buffer in nonpaged system space (pool).

VOID
  MmBuildMdlForNonPagedPool(
    IN OUT PMDL  MemoryDescriptorList
    );

Parameters

MemoryDescriptorList
Points to an MDL that supplies a virtual address, byte offset, and length.

Include

wdm.h or ntddk.h

Comments

The physical page portion of the MDL is updated as the pages are locked in memory. The input MDL virtual address must be within the nonpaged portion of system space.

Callers of MmBuildMdlForNonPagedPool must be running at IRQL <= DISPATCH_LEVEL.

See Also

ExAllocatePool, ExAllocatePoolWithTag, IoAllocateMdl, MmCreateMdl, MmInitializeMdl, MmIsNonPagedSystemAddressValid, MmMapIoSpace, MmSizeOfMdl


MmCreateMdl

MmCreateMdl is obsolete and is exported to support existing driver binaries only. Use IoAllocateMdl instead.

PMDL
  MmCreateMdl(
    IN PMDL  MemoryDescriptorList  OPTIONAL,
    IN PVOID  Base,
    IN SIZE_T  Length
    );


MmFreeContiguousMemory

MmFreeContiguousMemory releases a range of physically contiguous memory that was allocated with MmAllocateContiguousMemory.

VOID
  MmFreeContiguousMemory(
    IN PVOID  BaseAddress
    );

Parameters

BaseAddress
Points to the virtual address of the memory to be freed.

Include

ntddk.h

Comments

This routine is the reciprocal of MmAllocateContiguousMemory, and is usually called only when a driver is being unloaded. The input BaseAddress must have been returned by a preceding call to MmAllocateContiguousMemory.

A device driver that must use contiguous memory should allocate only what it needs during driver initialization because nonpaged pool is likely to become fragmented as the system runs. Such a driver must deallocate the memory if it is unloaded.

Callers of MmFreeContiguousMemory must be running at IRQL = PASSIVE_LEVEL.

See Also

MmAllocateContiguousMemory


MmFreeContiguousMemorySpecifyCache

MmFreeContiguousMemorySpecifyCache frees a buffer allocated by MmAllocateContiguousMemorySpecifyCache.

NTKERNELAPI VOID
  MmFreeContiguousMemorySpecifyCache(
    IN PVOID  BaseAddress,
    IN SIZE_T  NumberOfBytes,
    IN MEMORY_CACHING_TYPE  CacheType
    );

Parameters

BaseAddress
Specifies the base address of the buffer to be freed. Must match the address returned by MmAllocateContiguousMemorySpecifyCache.
NumberOfBytes
Specifies the size in bytes of the buffer to be freed. Must match the size requested when the buffer was allocated by MmAllocateContiguousMemorySpecifyCache.
CacheType
Specifies the cache type of the buffer to be freed. Must match the cache type requested when the buffer was allocated by MmAllocateContiguousMemorySpecifyCache.

Include

ntddk.h


MmFreeNonCachedMemory

MmFreeNonCachedMemory releases a range of noncached memory that was allocated with MmAllocateNonCachedMemory.

VOID
  MmFreeNonCachedMemory(
    IN PVOID  BaseAddress,
    IN SIZE_T  NumberOfBytes
    );

Parameters

BaseAddress
Points to the virtual address of the memory to be freed.
NumberOfBytes
Specifies the size of the range to be freed. The value must match the size passed in a preceding call to MmAllocateNonCachedMemory.

Include

ntddk.h

Comments

This routine is the reciprocal of MmAllocateNonCachedMemory, and is usually called only when a driver is being unloaded.

A device driver that must use noncached memory should allocate only what it needs during driver initialization because nonpaged pool is likely to become fragmented as the system runs. Such a driver must deallocate the memory if it is unloaded.

Callers of MmFreeNonCachedMemory must be running at IRQL < DISPATCH_LEVEL.

See Also

MmAllocateNonCachedMemory


MmFreePagesFromMdl

MmFreePagesFromMdl frees all the physical pages that are described by an MDL that was created by MmAllocatePagesForMdl.

VOID
  MmFreePagesFromMdl(
    IN PMDL  MemoryDescriptorList
    );

Parameters

MemoryDescriptorList
Pointer to an MDL that was created by MmAllocatePagesForMdl.

Include

ntddk.h

Comments

MmFreePagesFromMdl can only be used to free the memory pages that are described by an MDL that was created by MmAllocatePagesForMdl.

After calling MmFreePagesFromMdl, the caller must also call ExFreePool to release the memory that was allocated for the MDL structure.

MmFreePagesFromMdl runs at IRQL <= APC_LEVEL.

See Also

ExFreePool, MmAllocatePagesForMdl


MmGetMdlByteCount

MmGetMdlByteCount returns the length in bytes of the buffer described by a given MDL.

ULONG
  MmGetMdlByteCount(
    IN PMDL  Mdl
    );

Parameters

Mdl
Points to an MDL.

Include

wdm.h or ntddk.h

Return Value

MmGetMdlByteCount returns the byte count of the buffer described by Mdl.

Comments

Callers of MmGetMdlByteCount can be running at any IRQL. Usually, callers are running at IRQL <= DISPATCH_LEVEL.

See Also

MmGetMdlByteOffset


MmGetMdlByteOffset

MmGetMdlByteOffset returns the byte offset within a page of the buffer described by a given MDL.

ULONG
  MmGetMdlByteOffset(
    IN PMDL  Mdl
    );

Parameters

Mdl
Points to an MDL.

Include

wdm.h or ntddk.h

Return Value

MmGetMdlByteOffset returns the offset in bytes.

Comments

Callers of MmGetMdlByteOffset can be running at any IRQL. Usually, callers are running at IRQL <= DISPATCH_LEVEL.

See Also

MmGetMdlByteCount, MmGetMdlVirtualAddress


MmGetMdlPfnArray

MmGetMdlPfnArray returns a pointer to the beginning of the array of physical page numbers associated with the MDL.

PPFN_NUMBER
  MmGetMdlPfnArray(
    IN PMDL  Mdl
    );

Parameters

Mdl
Points to an MDL.

Include

ntddk.h or wdm.h

Return Value

A pointer to the beginning of the array of physical page numbers associated with the MDL

Comments

Callers of MmGetMdlPfnArray can be running at any IRQL.


MmGetMdlVirtualAddress

MmGetMdlVirtualAddress returns the base virtual address of a buffer described by an MDL.

PVOID
  MmGetMdlVirtualAddress(
    IN PMDL  Mdl
    );

Parameters

Mdl
Points to an MDL that describes the buffer for which to return the initial virtual address.

Include

wdm.h or ntddk.h

Return Value

MmGetMdlVirtualAddress returns the starting virtual address of the MDL.

Comments

MmGetMdlVirtualAddress returns a virtual address that is not necessarily valid in the current thread context. Lower-level drivers should not attempt to use the returned virtual address to access memory, particularly user-space memory.

The returned address, used as an index to a physical address entry in the MDL, can be input to MapTransfer.

Callers of MmGetMdlVirtualAddress can be running at any IRQL. Usually, the caller is running at IRQL DISPATCH_LEVEL because this routine is commonly called to obtain the CurrentVa parameter to MapTransfer.

See Also

MapTransfer, MmGetMdlByteOffset, MmIsAddressValid, MmIsNonPagedSystemAddressValid


MmGetPhysicalAddress

MmGetPhysicalAddress returns the physical address corresponding to a valid virtual address.

PHYSICAL_ADDRESS
  MmGetPhysicalAddress(
    IN PVOID  BaseAddress
    );

Parameters

BaseAddress
Points to the virtual address for which to return the physical address.

Include

ntddk.h

Return Value

MmGetPhysicalAddress returns the physical address that corresponds to the given virtual address.

Do not use this routine to obtain physical addresses for use with DMA operations. For information about the proper techniques for performing DMA operations, see Adapter Objects and DMA.

Comments

Callers of MmGetPhysicalAddress can be running at any IRQL, provided that the BaseAddress value is valid.

See Also

MmIsAddressValid, MmIsNonPagedSystemAddressValid, MmMapIoSpace, MmProbeAndLockPages


MmGetSystemAddressForMdl

MmGetSystemAddressForMdl is obsolete for Microsoft® Windows® 2000 and later, and for Windows Me. It is supported only for WDM drivers that must run on Windows 98. Otherwise use MmGetSystemAddressForMdlSafe.

MmGetSystemAddressForMdl is a macro that returns a nonpaged system-space virtual address for the buffer described by the MDL. It maps the physical pages described by a given MDL into system space, if they are not already mapped to system space.

PVOID
  MmGetSystemAddressForMdl(
    IN PMDL  Mdl
    );

Parameters

Mdl
Points to a buffer whose corresponding base virtual address is to be mapped.

Include

wdm.h or ntddk.h

Return Value

MmGetSystemAddressForMdl returns the base system-space virtual address that maps the physical pages described by the given MDL.

Comments

Drivers of PIO devices call this routine to translate a virtual address range, described by the MDL at Irp->MdlAddress, for a user buffer to a system-space address range.

A caller running at IRQL DISPATCH_LEVEL must supply an MDL that maps nonpageable virtual addresses. The input MDL must describe an already locked-down user-space buffer returned by MmProbeAndLockPages, a locked-down buffer returned by MmBuildMdlForNonPagedPool, or system-space memory allocated from nonpaged pool, contiguous memory, or noncached memory.

The returned base address has the same offset as the virtual address in the MDL.

Callers of MmGetSystemAddressForMdl must be running at IRQL <= DISPATCH_LEVEL.

Windows 2000 issues a bug check if the attempt to map to system space fails. On Windows 98, this routine returns NULL in case of failure.

See Also

MmGetSystemAddressForMdlSafe, MmBuildMdlForNonPagedPool, MmProbeAndLockPages ›


MmGetSystemAddressForMdlSafe

MmGetSystemAddressForMdlSafe is a macro that returns a nonpaged system-space virtual address for the buffer described by the MDL.

PVOID
  MmGetSystemAddressForMdlSafe(
    IN PMDL  Mdl,
    IN MM_PAGE_PRIORITY  Priority
    );

Parameters

Mdl
Points to a buffer whose corresponding base virtual address is to be mapped.
Priority
Specifies an MM_PAGE_PRIORITY value which indicates the importance of success under low available PTE conditions. Possible values include LowPagePriority, NormalPagePriority, and HighPagePriority.
  • LowPagePriority indicates that the mapping request can fail if system is fairly low on resources. An example of this is a non-critical network connection where the driver can handle the mapping failure.
  • NormalPagePriority indicates that the mapping request can fail if system is very low on resources. An example of this is a non-critical local file system request.
  • HighPagePriority indicates that the mapping request must not fail unless the system is completely out of resources. An example of this is the paging file path in a driver.

Include

wdm.h and ntddk.h

Return Value

MmGetSystemAddressForMdlSafe returns the base system-space virtual address that maps the physical pages described by the given MDL. If the pages are not already mapped to system space and the attempt to map them fails, NULL is returned.

Comments

MmGetSystemAddressForMdlSafe maps the physical pages described by a given MDL into system space, if they are not already mapped to system space.

Drivers of PIO devices call this routine to translate a virtual address range, described by the MDL at Irp->MdlAddress, for a user buffer to a system-space address range.

A caller running at IRQL DISPATCH_LEVEL must supply an MDL that maps nonpageable virtual addresses. The input MDL must describe an already locked-down user-space buffer returned by MmProbeAndLockPages, a locked-down buffer returned by MmBuildMdlForNonPagedPool, or system-space memory allocated from nonpaged pool, contiguous memory, or noncached memory.

The returned base address has the same offset as the virtual address in the MDL.

Callers of MmGetSystemAddressForMdlSafe must be running at IRQL <= DISPATCH_LEVEL.

Windows 98 does not support MmGetSystemAddressForMdlSafe. Use MmGetSystemAddressForMdl instead.

See Also

MmGetSystemAddressForMdl, MmBuildMdlForNonPagedPool, MmProbeAndLockPages


MmGetSystemRoutineAddress

MmGetSystemRoutineAddress returns a pointer to a function specified by SystemRoutineName.

NTKERNELAPI
PVOID
  MmGetSystemRoutineAddress(
    IN PUNICODE_STRING  SystemRoutineName
    );

Parameters

SystemRoutineName
Specifies name of system routine to resolve.

Return Value

If the function name can be resolved, the routine returns a pointer to the function. Otherwise, the routine returns NULL.

Headers

Declared in ntddk.h and wdm.h. Include ntddk.h or wdm.h.

Comments

MmGetSystemRoutineAddress is available on Windows® 2000 and later.

Drivers can use this routine to determine if a routine is available on a specific version of Windows. It can only be used for routines exported by the kernel or HAL, not for any driver-defined routine.

This routine can only be called at PASSIVE_LEVEL.

See Also

IoIsWdmVersionAvailable


MmInitializeMdl

MmInitializeMdl initializes the header of an MDL.

VOID
  MmInitializeMdl(
    IN PMDL  MemoryDescriptorList,
    IN PVOID  BaseVa,
    IN SIZE_T  Length
    );

Parameters

MemoryDescriptorList
Points to the MDL to be initialized.
BaseVa
Points to the base virtual address of a buffer.
Length
Specifies the length in bytes of the buffer to be described by the MDL.

Include

wdm.h or ntddk.h

Comments

Callers of MmInitializeMdl must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoAllocateMdl, IoBuildPartialMdl, IoFreeMdl, MmBuildMdlForNonPagedPool, MmCreateMdl, MmPrepareMdlForReuse, MmSizeOfMdl


MmIsAddressValid

MmIsAddressValid checks whether a page fault will occur for a read or write operation at a given virtual address.

BOOLEAN
  MmIsAddressValid(
    IN PVOID  VirtualAddress
    );

Parameters

VirtualAddress
Points to the virtual address to check.

Include

ntddk.h

Return Value

If no page fault will occur from reading or writing at the given virtual address, MmIsAddressValid returns TRUE.

Comments

Even if MmIsAddressValid returns TRUE, accessing the address can cause page faults unless the memory has been locked down or the address is a valid nonpaged pool address.

Callers of MmIsAddressValid must be running at IRQL <= DISPATCH_LEVEL.

See Also

MmProbeAndLockPages


MmIsNonPagedSystemAddressValid

MmIsNonPagedSystemAddressValid is obsolete and is exported to support existing drivers only.

BOOLEAN
  MmIsNonPagedSystemAddressValid(
    IN PVOID  VirtualAddress
    );


MmIsThisAnNtAsSystem

MmIsThisAnNtAsSystem checks whether the current platform is running a server version of the NT-based operating system..

BOOLEAN
  MmIsThisAnNtAsSystem(
    );

Include

ntddk.h

Return Value

If the current platform is a server, MmIsThisAnNtAsSystem returns TRUE.

Comments

Drivers can use this routine during initialization, along with MmQuerySystemSize, for sizing estimates of how many resources to allocate. For example, if MmIsThisAnNtAsSystem returns TRUE, the caller can increase the number of threads or the number of initially allocated entries for a lookaside list that it creates in medium and large systems.

Callers of MmIsThisAnNtAsSystem must be running at IRQL PASSIVE_LEVEL.

See Also

MmQuerySystemSize, ExInitializeNPagedLookasideList, ExInitializePagedLookasideList


MmLockPagableCodeSection

MmLockPagableCodeSection locks a section of driver code, containing a set of driver routines marked with a special compiler directive, into system space.

PVOID
  MmLockPagableCodeSection(
    IN PVOID  AddressWithinSection
    );

Parameters

AddressWithinSection
Is a symbolic address, usually the entry point of a driver routine, within the pageable section of driver code.

Include

wdm.h or ntddk.h

Return Value

MmLockPagableCodeSection returns a handle for the locked-down section of driver code. The handle must be passed subsequently to MmLockPagableSectionByHandle or to MmUnlockPagableImageSection.

Comments

This routine and its reciprocal, MmUnlockPagableImageSection, support drivers that can do the following:

  • Defer loading a subset of driver routines into resident memory until incoming I/O requests for the driver's device(s) make it necessary for these routines to process IRPs
  • Make the same subset of driver routines available for paging out when they have completed the processing of I/O requests and no additional requests for the driver's device(s) are currently expected

MmLockPagableCodeSection, MmLockPagableSectionByHandle and MmUnlockPagableImageSection are intended for use by device and intermediate drivers that have the following characteristics:

  • The driver has code paths that might not be needed while the system is running, but, if they are needed, the driver's code must be resident because it runs in an arbitrary thread context and/or at raised IRQL.
  • The driver can determine exactly when the pageable-routines should be loaded and when they can be paged out again.

For example, the system-supplied fault-tolerant disk driver supports the creation of mirror sets, stripe sets, and volume sets. Yet, a particular machine can be configured only with a mirror set, only with a stripe set, only with a volume set, or with any combination of these three possible options. In these circumstances, the system ftdisk driver reduces the size of its loaded image by marking routines that explictly support mirror, stripe, and volume sets as belonging to pageable-code sections. During driver initialization, pageable-code section(s) are made resident only if the user has configured the disks to have mirror, stripe, and/or volume sets. If the user repartitions the disks dynamically, the ftdisk driver loads any additional pageable-code sections necessary to support any mirror, stripe, and/or volume sets that the user requests.

As other examples, the system-supplied serial and parallel drivers have DispatchCreate and DispatchClose routines that are called when a particular port is opened for exclusive I/O and when the handle for an opened port is released, respectively. Yet, serial and parallel I/O requests are sporadic, determined by which applications the end user is currently running and which application options the end user is currently exercising. In these circumstances, the system serial and parallel drivers reduce the sizes of their loaded images by marking many routines as belonging to a pageable-code section that the DispatchCreate routine makes resident only when the first port is opened for I/O.

Note that each of the preceding system drivers satisfies both criteria for having pageable sections: the driver has code paths that might not be needed while the system is running and the driver can determine exactly when its pageable section should be loaded and can be paged out again.

Note also that calling MmLockPagableCodeSection and MmUnlockPagableImageSection reduce the size of each driver's loaded image at a cost to the driver's and system's performance. Drivers of performance-critical devices, such as keyboard and mouse drivers, and drivers of devices that are constantly in use, such as disk drivers, generally should not have pageable sections: the loss in performance is simply not worth the temporary reduction in driver image size.

Because it is an expensive operation to lock down a section, if a pageable-code section is locked down in more than place by a driver, use MmLockPagableCodeSection for the first request. Make subsequent lock requests by calling MmLockPagableSectionByHandle passing the handle returned by MmLockPagableCodeSection. Locking by handle significantly improves driver performance because the memory manager uses the handle to find the section rather than searching a loaded module list. A locked down section is unlocked by calling MmUnlockPagableImageSection.

Each driver routine within a pageable code section must be marked with the following compiler directive:

#pragma alloc_text(PAGE xxxx, DriverRoutine)

where xxxx is an optional four-character, unique identifier for the caller's pageable section and DriverRoutine is an entry point to be included within the pageable-code section. The keyword PAGE and the driver-determined suffix, which can be up to four characters, are case-sensitive, that is, PAGE must be capitalized.

A single call to MmLockPagableCodeSection in, for example, a driver's DispatchCreate routine, causes the entire section, containing every driver routine marked with the same PAGE xxxx identifier, to be locked in system space.

Certain types of driver routines cannot be made part of any driver's pageable section, including the following:

  • Never make an ISR pageable. It is possible for a device driver to receive a spurious interrupt even if its device is not in use, particularly if the interrupt vector could be shared. In general, even if a driver can explictly disable interrupts on its device, an ISR should not be made pageable.
  • Never make a DPC routine pageable if the driver cannot control when the DPC is queued, such as any DpcForIsr or CustomDpc routine that might be queued from an ISR. In general, driver routines that run at raised IRQL and that can be called in an arbitrary thread context or in response to a random external event should not be made pageable.
  • Never make the DispatchRead or DispatchWrite routine pageable in any driver that might be part of the system paging I/O path. The driver of a disk that might contain the system page file must have DispatchRead and DispatchWrite routines that are resident while the system is running, as must all drivers layered above such a disk driver.

Note that routines in a pageable section marked with the compiler directive #pragma alloc_text(PAGExxxx, ...)differ from routines marked with the compiler directive #pragma alloc_text(INIT, ...). The routines in the INIT section are not pageable and are discarded as soon as the driver returns from its DriverEntry or its Reinitialize routine, if it has one.

The Memory Manager maintains an internal lock count on any driver's pageable-section. Calls to MmLockPagableCodeSection increment this count and the reciprocal MmUnlockPagableImageSection decrements the count. A driver's pageable section is not available to be paged out unless this count is zero.

Callers of MmLockPagableCodeSection and MmLockPagableDataSection must take care to use the former for code sections and the latter for data sections. If the incorrect form of MmLockPagableXxxxSection is used, a fatal error will occur on some platforms.

For more information on creating pageable code sections, see Making Drivers Pageable.

Callers of MmLockPagableCodeSection run at IRQL PASSIVE_LEVEL.

See Also

MmUnlockPagableImageSection, MmPageEntireDriver, MmResetDriverPaging, MmLockPagableDataSection, MmLockPagableSectionByHandle


MmLockPagableDataSection

MmLockPagableDataSection locks an entire section of driver data into system space.

PVOID
  MmLockPagableDataSection(
    IN PVOID  AddressWithinSection
    );

Parameters

AddressWithinSection
Is the symbolic address of one item of data within the pageable section.

Include

wdm.h or ntddk.h

Return Value

MmLockPagableDataSection returns a handle to the section. This handle must be passed subsequently to MmLockPagableSectionByHandle or to MmUnlockPagableImageSection.

Comments

This routine, MmLockPagableSectionByHandle and MmUnlockPagableImageSection are used by drivers to make data pageable but locked in memory on demand.

Data can be pageable if:

  • The data is accessed at <DISPATCH_LEVEL.
  • The driver uses the data infrequently and predictably.

Drivers for mixer devices use pageable-data sections. Because the driver uses sufficient data to make creating a pageable-data section worthwhile and the driver knows when the data is needed, such a driver uses MmLockPagableDataSection, MmLockPagableSectionByHandle and MmUnlockPagableImageSection to bring a data section into system space when needed and make it available to be paged out when not needed.

A single call to MmLockPagableDataSection causes the entire section, containing the referenced data, to be locked into system space.

It is an expensive operation to lock down a section. If a pageable-data section is locked down in more than one place by a driver, use MmLockPagableDataSection for the first request. Make subsequent lock requests by calling MmLockPagableSectionByHandle, passing the handle returned by MmLockPagableDataSection. Locking by handle significantly improves driver performance. A locked down section is unlocked by calling MmUnlockPagableImageSection.

The memory manager maintains a reference count on the handle to a section. A pageable-data section is only available to be paged out when the reference count is zero. Every lock request increments the count; every unlock request decrements the count. A driver must unlock a section as many times as it locks a section to insure that such a section will be available to be paged out when the section is not needed. A handle is always valid, no matter what the count. If the count on a handle is zero and a call is made to MmLockPagableSectionByHandle, the count is set to one, and if the section has been paged out, it will be paged in.

Callers of MmLockPagableDataSection and MmLockPagableCodeSection must use the former for data sections and the latter for code sections. If the incorrect form of MmLockPagableXxxxSection is used, a fatal error will occur on some platforms.

Data in a pageable-data section is marked by a compiler directive. To create a pageable data section, use #pragma data_seg ("PAGE"), at the beginning of the data module, and #pragma data_seg () at the end of the module. The keyword PAGE is case-sensitive, that is, PAGE must be capitalized.

Note that there is also a #pragma data_seg("INIT") that is used to make data discardable after system initialization. Except for the use of INIT rather than PAGE, the syntax is the same. However the result is not; use of the PAGE directive makes the data section pageable. When the INIT directive is used, the data in the section is discarded as soon as the driver returns from its driver entry routine or its reinitialization routine if the driver has one.

For more information about paging data, see Making Drivers Pageable.

Callers of MmLockPagableDataSection run at IRQL PASSIVE_LEVEL.

See Also

MmLockPagableCodeSection, MmLockPagableSectionByHandle, MmPageEntireDriver, MmResetDriverPaging, MmUnlockPagableImageSection


MmLockPagableSectionByHandle

MmLockPagableSectionByHandle takes a handle returned by MmLockPagableDataSection or MmLockPagableCodeSection.

VOID
  MmLockPagableSectionByHandle(
    IN PVOID  ImageSectionHandle
    );

Parameters

ImageSectionHandle
Supplies the handle returned by a call to MmLockPagableCodeSection or MmLockPagableDataSection.

Include

ntddk.h

Comments

MmLockPagableSectionByHandle checks to see if the referenced section is resident in the caller's address space and if so, simply increments a reference count on the section. If the section is not resident, MmLockPagableImage pages in the section, locks it in system space and sets the reference count to one.

If a pageable section is locked down in more than one place by a driver, use MmLockPagableXxxxSection for the first request. Make subsequent lock requests by calling MmLockPagableSectionByHandle passing the handle returned by MmLockPagableXxxxSection. A locked down section is unlocked by calling MmUnlockPagableImageSection.

A handle returned from an MmLockPagableXxxxSection is valid until a driver is unloaded.

Locking by handle significantly improves driver performance. When MmLockPagableCodeSection or MmLockPagableDataSection is called, the memory manager walks the entire loaded module list to find the module containing the specified address. This is an expensive operation. Calling MmLockPagableImageSectionByHandle reduces this burden because if the caller supplies a handle to the section, the memory manager no longer has to search.

The memory manager maintains a reference count on the handle to the section. A pageable section is only available to be paged out when the reference count is zero. Every lock request increments the count; every unlock request decrements the count. A driver must take care to unlock a section as many times as it locks a section to insure that such a section will be eligible to be paged out when the section is not needed. Once a handle is obtained, it is always valid, no matter what the count until the driver is unloaded. If the count on a handle is zero and a call is made to MmLockPagableSectionByHandle, the count is set to one, and if the section has been paged out, it will be paged in.

A driver cannot call MmLockPagableSectionByHandle to lock down user buffers passed in IRPs. Use MmProbeAndLockPages instead.

For more information about paging code and data, see Making Drivers Pageable.

Callers of MmLockPagableSectionByHandle runs at IRQL PASSIVE_LEVEL.

See Also

MmLockPagableDataSection, MmLockPagableCodeSection, MmProbeAndLockPages, MmPageEntireDriver, MmResetDriverPaging, MmUnlockPagableImageSection


MmMapIoSpace

MmMapIoSpace maps the given physical address range to nonpaged system space.

PVOID
  MmMapIoSpace(
    IN PHYSICAL_ADDRESS  PhysicalAddress,
    IN ULONG  NumberOfBytes,
    IN MEMORY_CACHING_TYPE  CacheEnable
    );

Parameters

PhysicalAddress
Specifies the starting physical address of the I/O range to be mapped.
NumberOfBytes
Specifies the number of bytes to be mapped.
CacheEnable
Specifies whether the physical address range can be mapped as cached memory. See MmAllocateContiguousMemorySpecifyCache for a description of the possible values.

Include

wdm.h or ntddk.h

Return Value

MmMapIoSpace returns the base virtual address that maps the base physical address for the range. If space for mapping the range is insufficient, it returns NULL.

Comments

A driver must call this routine during device start-up if it receives translated resources of type CmResourceTypeMemory. MmMapIoResource maps the physical address returned in the resource list to a logical address through which the driver can access device registers.

For example, drivers of PIO devices that allocate long-term I/O buffers can call this routine to make such a buffer accessible or to make device memory accessible.

Callers of MmMapIoSpace must be running at IRQL = PASSIVE_LEVEL.

See Also

HalAllocateCommonBuffer, HalTranslateBusAddress, MmAllocateContiguousMemory, MmAllocateNonCachedMemory, MmMapLockedPages, MmUnmapIoSpace


MmMapLockedPages

MmMapLockedPages maps physical pages described by a given MDL.

PVOID
  MmMapLockedPages(
    IN PMDL  MemoryDescriptorList,
    IN KPROCESSOR_MODE  AccessMode
    );

Parameters

MemoryDescriptorList
Points to an MDL that has been updated by MmProbeAndLockPages.
AccessMode
Specifies the access mode in which to map the MDL, either KernelMode or UserMode. Lower-level drivers should use KernelMode.

Include

wdm.h or ntddk.h

Return Value

For Windows NT 4.0 SP3 and earlier versions, MmMapLockedPages returns the base virtual address (a page-aligned address) that maps the locked pages for the range described by the MDL. For versions later than Windows NT 4.0 SP3, MmMapLockedPages returns the actual virtual address (page-aligned address with offset).

Comments

The MDL in an IRP at Irp->MdlAddress does not necessarily map a buffer for the current thread when that IRP is processed by lower-level drivers. Therefore, the user-mode virtual addresses corresponding to the locked-down physical pages can be invisible or invalid.

Callers of MmMapLockedPages must be running at IRQL <= DISPATCH_LEVEL if AccessMode is KernelMode. Otherwise, the caller must be running at IRQL < DISPATCH_LEVEL.

See Also

MmGetSystemAddressForMdl, MmGetSystemAddressForMdlSafe, MmProbeAndLockPages, MmUnmapLockedPages


MmMapLockedPagesSpecifyCache

NTKERNELAPI PVOID
  MmMapLockedPagesSpecifyCache(
    IN PMDL  MemoryDescriptorList,
    IN KPROCESSOR_MODE  AccessMode,
    IN MEMORY_CACHING_TYPE  CacheType,
    IN PVOID  BaseAddress,
    IN ULONG  BugCheckOnFailure,
    IN MM_PAGE_PRIORITY  Priority
    );

Parameters

MemoryDescriptorList
Specifies the MDL to be mapped. The caller must already have probed and locked the MDL with MmProbeAndLockPages.
AccessMode
Specifies the access mode in which to map the MDL. Either KernelMode or UserMode.
CacheType
Specifies the type of caching allowed for the MDL. See MmAllocateContiguousMemorySpecifyCache for a description of the possible values of CacheType.
BaseAddress
If AccessMode = UserMode then this specifies the starting user address to map the MDL to, or NULL to allow the system to choose the starting address. The system may round down the requested address to fit address boundary requirements, so callers must check the return value.
BugCheckOnFailure
Specifies the behavior of the routine if the MDL cannot be mapped because of low system resources. If TRUE, the system bug checks. If FALSE, the routine returns NULL.
Priority
Indicates the importance of success when PTEs are scarce. See MmGetSystemAddressForMdlSafe for a description of the possible values for Priority.

Include

ntddk.h

Return Value

MmMapLockedPagesSpecifyCache returns the starting address of the mapped pages. If the pages cannot be mapped and BugCheckOnFailure is FALSE, the routine returns NULL.

Comments

If AccessMode is UserMode, then the caller must be running at IRQL <= APC_LEVEL. If AccessMode is KernelMode, then the caller must be running at IRQL <= DISPATCH_LEVEL.


MmPageEntireDriver

MmPageEntireDriver causes all of a driver's code and data to be made pageable, overriding the attributes of the various sections that make up the driver's image.

VOID
  MmPageEntireDriver(
    IN PVOID  AddressWithinSection
    );

Parameters

AddressWithinSection
Points to a symbolic address within the driver, for example, DriverEntry.

Include

wdm.h or ntddk.h

Comments

Use this routine to force a driver to be completely pageable. The driver must not have interrupts connected on its device before making this call since as a result of this call, the entire driver will be marked as pageable. If the driver is pageable, such code as the ISR code may be paged out after the driver calls MmPageEntireDriver.

MmPageEntireDriver may be called multiple times without intervening calls to MmResetDriverPaging. However, subsequent calls to MmPageEntireDriver do nothing if the driver's pageable status has not been reset by a call to MmResetDriverPaging.

For more information about paging an entire driver, see Making Drivers Pageable.

Callers of MmPageEntireDriver run at IRQL PASSIVE_LEVEL.

See Also

MmResetDriverPaging, MmLockPagableCodeSection, MmLockPagableDataSection, MmLockPagableSectionByHandle, MmUnlockPagableImageSection


MmPrepareMdlForReuse

MmPrepareMdlForReuse reinitializes a caller-allocated MDL.

VOID
  MmPrepareMdlForReuse(
    IN PMDL  MDL
    );

Parameters

MDL
Points to the MDL that will be reused.

Include

wdm.h or ntddk.h

Comments

MmPrepareMdlForReuse is called by drivers that allocate a set of MDLs that they use and reuse repeatedly. After each call to MmPrepareMdlForReuse, the given MDL must be reinitialized. Very few drivers call this routine.

Callers of MmPrepareMdlForReuse must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoAllocateMdl, IoBuildPartialMdl, IoFreeMdl, MmCreateMdl, MmInitializeMdl


MmProbeAndLockPages

MmProbeAndLockPages probes specified pages, makes them resident, and locks the physical pages mapped by the virtual address range in memory; the MDL is updated to describe the physical pages.

VOID
  MmProbeAndLockPages(
    IN OUT PMDL  MemoryDescriptorList,
    IN KPROCESSOR_MODE  AccessMode,
    IN LOCK_OPERATION  Operation
    );

Parameters

MemoryDescriptorList
Points to an MDL that supplies a virtual address, byte offset, and length. The physical page portion of the MDL is updated when the pages are locked in memory.
AccessMode
Specifies the access mode in which to probe the arguments, either KernelMode or UserMode.
Operation
Specifies the type of operation for which the caller wants the access rights probed and the pages locked, one of IoReadAccess, IoWriteAccess, or IoModifyAccess.

Include

wdm.h or ntddk.h

Comments

The highest-level driver in a chain of layered drivers that use direct I/O calls this routine. Drivers that use buffered I/O never call MmProbeAndLockPages.

If this routine fails, an exception is raised. Any driver that calls MmProbeAndLockPages must handle such an exception.

A lower-level driver cannot attempt to pass such an exception on to a higher-level driver. It cannot assume anything about a higher-level driver's exception handling capabilities. In particular, the driver cannot call ExRaiseStatus to pass on such an exception.

Callers of MmProbeAndLockPages must be running at IRQL < DISPATCH_LEVEL for pageable addresses, or at IRQL <= DISPATCH_LEVEL for nonpageable addresses.

See Also

MmUnlockPages


MmQuerySystemSize

MmQuerySystemSize returns an estimate of the amount of memory in the system.

MM_SYSTEM_SIZE
  MmQuerySystemSize(
    );

Include

wdm.h or ntddk.h

Return Value

MmQuerySystemSize returns one of MmSmallSystem, MmMediumSystem, or MmLargeSystem.

Comments

This routine can be called during driver initialization to determine how much memory it is practical to allocate for an internal buffer.

Callers of MmQuerySystemSize must be running at IRQL PASSIVE_LEVEL.

See Also

ExAllocatePool, ExAllocatePoolWithTag, ExInitializeNPagedLookasideList, ExInitializePagedLookasideList, MmIsThisAnNtAsSystem


MmResetDriverPaging

MmResetDriverPaging resets the pageable status of a driver's sections to that specified when the driver was compiled.

VOID
  MmResetDriverPaging(
    IN PVOID  AddressWithinSection
    );

Parameters

AddressWithinSection
Points to a symbolic address in the driver, for example, DriverEntry.

Include

wdm.h or ntddk.h

Comments

MmResetDriverPaging causes those routines that would not normally be pageable, to be locked into memory. Hence, image sections such as .text and .data will be locked in memory if this routine is called.

A driver that calls this routine must do so before enabling interrupts on its device.

A call to MmPageEntireDriver is not a prerequisite to calling this routine. However, calls to MmResetDriverPaging do nothing if the driver's image-section attributes have never been overridden by a call to MmPageEntireDriver.

For more information about paging an entire driver, see Making Drivers Pageable.

Callers of MmResetDriverPaging must be running at IRQL PASSIVE_LEVEL.

See Also

MmPageEntireDriver, MmLockPagableCodeSection, MmLockPagableDataSection, MmLockPagableSectionByHandle, MmUnlockPagableImageSection


MmSizeOfMdl

MmSizeOfMdl returns the number of bytes to allocate for an MDL describing a given address range.

ULONG
  MmSizeOfMdl(
    IN PVOID  Base,
    IN SIZE_T  Length
    );

Parameters

Base
Points to the base virtual address for the range.
Length
Supplies the size, in bytes, of the range.

Include

wdm.h or ntddk.h

Return Value

MmSizeOfMdl returns the number of bytes required to contain the MDL.

Comments

The given address range must be locked down if it will be accessed at raised IRQL.

Memory for the MDL itself must be allocated from nonpaged pool if the caller subsequently passes a pointer to the MDL while running at IRQL >= DISPATCH_LEVEL.

Callers of MmSizeOfMdl run at any IRQL.

See Also

MmCreateMdl, MmInitializeMdl


MmUnlockPagableImageSection

MmUnlockPagableImageSection releases a section of driver code or driver data, previously locked into system space with MmLockPagableCodeSection, MmLockPagableDataSection or MmLockPagableSectionByHandle, so the section can be paged out again.

VOID
  MmUnlockPagableImageSection(
    IN PVOID  ImageSectionHandle
    );

Parameters

ImageSectionHandle
Is the handle returned by a call to MmLockPagableCodeSection or MmLockPagableDataSection.

Include

wdm.h or ntddk.h

Comments

The handle for a driver's pageable section must not be released if the driver has any outstanding IRPs in its device queue(s) or internal queue(s). A call to MmUnlockPagableImageSection restores the pageability of that entire section when there are no more references to the handle for that section.

The memory manager maintains the reference count on the handle to a section. A pageable section is only available to be paged out when the reference count is zero. Every lock request increments the count; every unlock request decrements the count. A driver must unlock a section as many times as it locks a section to make the section available to be paged out.

A handle is always valid, no matter what the count. If the count on a handle is zero and a call is made to MmLockPagableSectionByHandle, the count is set to one, and if the section has been paged out, it will be paged in.

In most cases, MmUnlockPagableImageSection is called before a driver's Unload routine. That is, a driver with a pageable section is likely to have its DispatchClose and/or DispatchShutdown routine call MmUnlockPagableImageSection before its Unload routine is called. However, care should be taken in unloadable drivers to release any pageable section before the driver itself is unloaded from the system.

For more information on paging code and data, see Making Drivers Pageable.

Callers of MmUnlockPagableImageSection must be running at IRQL PASSIVE_LEVEL.

See Also

MmPageEntireDriver, MmResetDriverPaging, MmLockPagableCodeSection, MmLockPagableDataSection, MmLockPagableSectionByHandle


MmUnlockPages

MmUnlockPages unlocks physical pages described by a given MDL.

VOID
  MmUnlockPages(
    IN PMDL  MemoryDescriptorList
    );

Parameters

MemoryDescriptorList
Points to an MDL.

Include

wdm.h or ntddk.h

Comments

The memory described by the specified MDL must have been locked previously by a call to MmProbeAndLockPages. As the pages are unlocked, the MDL is updated.

Callers of MmUnlockPages must be running at IRQL <= DISPATCH_LEVEL.

See Also

MmProbeAndLockPages


MmUnmapIoSpace

MmUnmapIoSpace unmaps a specified range of physical addresses previously mapped by MmMapIoSpace.

VOID
  MmUnmapIoSpace(
    IN PVOID  BaseAddress,
    IN SIZE_T  NumberOfBytes
    );

Parameters

BaseAddress
Points to the base virtual address to which the physical pages were mapped.
NumberOfBytes
Specifies the number of bytes that were mapped.

Include

wdm.h or ntddk.h

Comments

If a driver calls MmMapIoSpace during device start-up, it must call MmUnmapIoSpace when it receives a PnP stop-device or remove-device IRP for the same device object.

Callers of MmUnmapIoSpace must be running at IRQL = PASSIVE_LEVEL.

See Also

MmMapIoSpace


MmUnmapLockedPages

MmUnmapLockedPages releases a mapping set up by a preceding call to MmMapLockedPages.

VOID
  MmUnmapLockedPages(
    IN PVOID  BaseAddress,
    IN PMDL  MemoryDescriptorList
    );

Parameters

BaseAddress
Points to the base virtual address to which the physical pages were mapped.
MemoryDescriptorList
Points to an MDL.

Include

wdm.h or ntddk.h

Comments

Callers of MmUnmapLockedPages must be running at IRQL <= DISPATCH_LEVEL if the pages were mapped to system space. Otherwise, the caller must be running at IRQL < DISPATCH_LEVEL.

See Also

MmMapLockedPages


ADDRESS_AND_SIZE_TO_SPAN_PAGES

ADDRESS_AND_SIZE_TO_SPAN_PAGES returns the number of pages spanned by the virtual range defined by a virtual address and the size in bytes of a transfer request.

ULONG
  ADDRESS_AND_SIZE_TO_SPAN_PAGES(
    IN PVOID  Va,
    IN ULONG  Size
    );

Parameters

Va
Points to the virtual address that is the base of the range.
Size
Specifies the size in bytes of the transfer request.

Include

wdm.h or ntddk.h

Return Value

ADDRESS_AND_SIZE_TO_SPAN_PAGES returns the number of pages spanned by the virtual range starting at Va.

Comments

Drivers that make DMA transfers call ADDRESS_AND_SIZE_TO_SPAN_PAGES to determine whether a transfer request must be split into a sequence of device DMA operations.

A driver can use the system-defined constant PAGE_SIZE to determine whether the number of bytes to be transferred is less than the page size of the current platform.

Callers of ADDRESS_AND_SIZE_TO_SPAN_PAGES can be running at any IRQL, but usually run at IRQL DISPATCH_LEVEL.

See Also

MapTransfer


ARGUMENT_PRESENT

ARGUMENT_PRESENT takes an argument pointer and returns FALSE if the pointer is NULL, TRUE otherwise.

BOOLEAN
  ARGUMENT_PRESENT(
    IN (CHAR *)  ArgumentPointer
    );

Parameters

ArgumentPointer
The value of the pointer argument to be tested.

Include

wdm.h or ntddk.h

Return Value

ARGUMENT_PRESENT returns FALSE if the value of ArgumentPointer is NULL, true otherwise.

Comments

This macro can be called in conditional code to determine whether an optional argument has been passed in a call.

Callers of ARGUMENT_PRESENT can be running at any IRQL.


BYTE_OFFSET

BYTE_OFFSET takes a virtual address and returns the byte offset of that address within the page.

ULONG
  BYTE_OFFSET(
    IN PVOID  Va
    );

Parameters

Va
Points to the virtual address.

Include

wdm.h or ntddk.h

Return Value

BYTE_OFFSET returns the offset portion of the virtual address.

Comments

Callers of BYTE_OFFSET can be running at any IRQL.


BYTES_TO_PAGES

BYTES_TO_PAGES takes the size in bytes of the transfer request and calculates the number of pages required to contain the bytes.

ULONG
  BYTES_TO_PAGES(
    IN ULONG  Size
    );

Parameters

Size
Specifies the size in bytes of the transfer request.

Include

wdm.h or ntddk.h

Return Value

BYTES_TO_PAGES returns the number of pages required to contain the specified number of bytes.

Comments

The system-defined constant PAGE_SIZE can be used to determine whether a given length in bytes for a transfer is less than the page size of the current platform.

Callers of BYTES_TO_PAGES can be running at any IRQL.

See Also

ADDRESS_AND_SIZE_TO_SPAN_PAGES


COMPUTE_PAGES_SPANNED

COMPUTE_PAGES_SPANNED is obsolete. Use ADDRESS_AND_SIZE_TO_SPAN_PAGES instead.

ULONG
  COMPUTE_PAGES_SPANNED(
    IN PVOID  Va,
    IN ULONG  Size
    );


CONTAINING_RECORD

CONTAINING_RECORD returns the base address of an instance of a structure given the type of the structure and the address of a field within the containing structure.

PCHAR
  CONTAINING_RECORD(
    IN PCHAR  Address,
    IN TYPE  Type,
    IN PCHAR  Field
    );

Parameters

Address
Points to a field in an instance of a structure of type Type.
Type
The name of the type of the structure whose base address is to be returned. For example, type IRP.
Field
The name of the field pointed to by Address and which is contained in a structure of type Type.

Include

wdm.h or ntddk.h

Return Value

Returns the address of the base of the structure containing Field.

Comments

Called to determine the base address of a structure whose type is known when the caller has a pointer to a field inside such a structure. This macro is useful for symbolically accessing other fields in a structure of known type.

Callers of CONTAINING_RECORD can be running at any IRQL as long as the structure is resident. If a page fault might occur, callers must be at or below IRQL APC_LEVEL.

See Also

FIELD_OFFSET


FIELD_OFFSET

FIELD_OFFSET returns the byte offset of a named field in a known structure type.

LONG
  FIELD_OFFSET(
    IN TYPE  Type,
    IN PCHAR  Field
    );

Parameters

Type
The name of a known structure type containing Field.
Field
The name of a field in a structure of type Type.

Include

wdm.h or ntddk.h

Return Value

Returns the byte offset of the caller supplied Field in the Type structure.

Comments

Used by device driver writers to symbolically determine the offset of a known field in a known structure type.

Callers of FIELD_OFFSET can be running at any IRQL as long as the structure is resident. If a page fault could occur, callers must be at or below IRQL APC_LEVEL.

See Also

CONTAINING_RECORD


PAGE_ALIGN

PAGE_ALIGN returns a page-aligned virtual address for a given virtual address.

PVOID
  PAGE_ALIGN(
    IN PVOID  Va
    );

Parameters

Va
Points to the virtual address.

Include

wdm.h or ntddk.h

Return Value

PAGE_ALIGN returns a pointer to the page-aligned virtual address.

Comments

Callers of PAGE_ALIGN can be running at any IRQL.


ROUND_TO_PAGES

ROUND_TO_PAGES takes a size in bytes and rounds it up to the next full page.

ULONG_PTR
  ROUND_TO_PAGES(
    IN ULONG_PTR  Size
    );

Parameters

Size
Specifies the size in bytes to round up to a page multiple.

Include

wdm.h or ntddk.h

Return Value

ROUND_TO_PAGES returns the input size rounded up to a multiple of the page size for the current platform.

Comments

Callers of ROUND_TO_PAGES can be running at any IRQL.


Object Manager Routines

References for the Ob Xxx routines are in alphabetical order. Click the browse button to view them.

For an overview of the functionality of these routines, see Summary of Kernel-Mode Support Routines.


ObDereferenceObject

ObDereferenceObject decrements the given object's reference count and performs retention checks.

VOID
  ObDereferenceObject(
    IN PVOID  Object
    );

Parameters

Object
Points to the object's body.

Include

wdm.h or ntddk.h

Comments

When the reference count for an object reaches zero, a kernel-mode component can remove the object from the system. However, a driver can remove only those objects that it created, and a driver should never attempt to remove any object that it did not create.

A named object with the permanent attribute, such as a directory object created to hold a driver's symbolic link objects, can be deleted as follows:

  1. Call ObDereferenceObject.
  2. Call the appropriate ZwOpen Xxx or ZwCreate Xxx to get a handle for the object, if necessary.
  3. Call ZwMakeTemporaryObject with the handle.
  4. Call ZwClose with the handle.

Callers of ObDereferenceObject must be running at IRQL <= DISPATCH_LEVEL.

See Also

ZwClose, ZwMakeTemporaryObject


ObGetObjectSecurity

ObGetObjectSecurity gets the security descriptor for a given object.

NTSTATUS
  ObGetObjectSecurity(
    IN PVOID  Object,
    OUT PSECURITY_DESCRIPTOR  *SecurityDescriptor,
    OUT PBOOLEAN  MemoryAllocated
    );

Parameters

Object
Points to the object.
SecurityDescriptor
Points to a caller-supplied variable that this routine sets to the address of a buffer containing the SECURITY_DESCRIPTOR for the given object. If the given object has no security descriptor, this variable is set to NULL on return from ObGetObjectSecurity.
MemoryAllocated
Points to a caller-supplied variable that this routine sets to TRUE if it allocated a buffer to contain the security descriptor.

Include

ntddk.h

Return Value

ObGetObjectSecurity either returns STATUS_SUCCESS or an error status, such as STATUS_INSUFFICIENT_RESOURCES if it could not allocate enough memory to return the requested information.

Comments

A successful call to ObGetObjectSecurity either returns a self-relative security descriptor in the buffer at *SecurityDescriptor or it returns NULL at *SecurityDescriptor if the given object has no security descriptor. For example, any unnamed object, such as an event object, has no security descriptor.

If ObGetObjectSecurity returns STATUS_SUCCESS, the caller must save the value returned at MemoryAllocated. Such a caller must pass MemoryAllocated in a reciprocal call to ObReleaseObjectSecurity eventually, thereby restoring the reference count on the security descriptor to its original value and releasing the buffer, if any, that was allocated by ObGetObjectSecurity.

Callers of ObGetObjectSecurity must be running at IRQL < DISPATCH_LEVEL.

See Also

SECURITY_DESCRIPTOR, ObReferenceObjectByHandle, ObReleaseObjectSecurity


ObReferenceObject

ObReferenceObject increments the reference count to the given object.

VOID
  ObReferenceObject(
    IN PVOID  Object
    );

Parameter

Object
Points to the object. The caller obtained this parameter either when it created the object or from a preceding call to ObReferenceObjectByHandle after it opened the object.

Include

wdm.h or ntddk.h

Comments

ObReferenceObject simply increments the pointer reference count for an object, without making any access checks on the given object, as ObReferenceObjectByHandle and ObReferenceObjectByPointer do.

ObReferenceObject prevents deletion of the object at least until the driver subsequently calls its reciprocal, ObDereferenceObject, or closes the given object. The caller must decrement the reference count with ObDereferenceObject as soon as it is done with the object.

When the reference count for an object reaches zero, a kernel-mode component can remove the object from the system. However, a driver can remove only those objects that it created, and a driver should never attempt to remove any object that it did not create.

Callers of ObReferenceObject must be running at IRQL <= DISPATCH_LEVEL.

See Also

ObReferenceObjectByHandle, ObReferenceObjectByPointer, ObDereferenceObject, ZwClose


ObReferenceObjectByHandle

ObReferenceObjectByHandle provides access validation on the object handle, and, if access can be granted, returns the corresponding pointer to the object's body.

NTSTATUS
  ObReferenceObjectByHandle(
    IN HANDLE  Handle,
    IN ACCESS_MASK  DesiredAccess,
    IN POBJECT_TYPE  ObjectType  OPTIONAL,
    IN KPROCESSOR_MODE  AccessMode,
    OUT PVOID  *Object,
    OUT POBJECT_HANDLE_INFORMATION  HandleInformation  OPTIONAL
    );

Parameters

Handle
Specifies an open handle for an object.
DesiredAccess
Specifies the requested types of access to the object. The interpretation of this field is dependent on the object type.
ObjectType
Points to the object type, which can be either of IoFileObjectType or ExEventObjectType. This parameter can be NULL if AccessMode is KernelMode.
AccessMode
Specifies the access mode to use for the access check. It must be either UserMode or KernelMode. Lower-level drivers should specify KernelMode.
Object
Points to a variable that receives a pointer to the object's body.
HandleInformation
Points to a structure that receives the handle attributes and the granted access rights for the object.

Include

wdm.h or ntddk.h

Return Value

ObReferenceObjectByHandle can return one of the following:

STATUS_SUCCESS
STATUS_OBJECT_TYPE_MISMATCH
STATUS_ACCESS_DENIED
STATUS_INVALID_HANDLE

Comments

A pointer to the object body is retrieved from the object table entry and returned to the caller by means of the Object parameter.

If the AccessMode parameter is KernelMode, the requested access is always allowed. If AccessMode is UserMode, the requested access is compared to the granted access for the object. Only highest-level drivers can safely specify UserMode for the input AccessMode.

If the call succeeds, a pointer to the object body is returned to the caller and the pointer reference count is incremented. Incrementing this count prevents the object from being deleted while the pointer is being referenced. The caller must decrement the reference count with ObDereferenceObject as soon as it is done with the object.

Callers of ObReferenceObjectByHandle must be running at IRQL PASSIVE_LEVEL.

See Also

ObDereferenceObject, ObReferenceObject, ObReferenceObjectByPointer


ObReferenceObjectByPointer

ObReferenceObjectByPointer increments the pointer reference count for a given object.

NTSTATUS
  ObReferenceObjectByPointer(
    IN PVOID  Object,
    IN ACCESS_MASK  DesiredAccess,
    IN POBJECT_TYPE  ObjectType,
    IN KPROCESSOR_MODE  AccessMode
    );

Parameters

Object
Points to the object's body.
DesiredAccess
Specifies a mask representing the requested access to the object.
ObjectType
Points to the object type, which can be either of IoFileObjectType or ExEventObjectType. This parameter can be NULL if AccessMode is KernelMode.
AccessMode
Indicates the access mode to use for the access check. It must be either UserMode or KernelMode. Lower-level drivers should specify KernelMode.

Include

wdm.h or ntddk.h

Return Value

ObReferenceObjectByPointer can return one of the following:

STATUS_SUCCESS
STATUS_OBJECT_TYPE_MISMATCH

Comments

Calling this routine prevents the object from being deleted, possibly by another component's call to ObDereferenceObject or ZwClose. The caller must decrement the reference count with ObDereferenceObject as soon as it is done with the object.

Callers of ObReferenceObjectByPointer must be running at IRQL <= DISPATCH_LEVEL.

See Also

ObDereferenceObject, ObReferenceObject, ObReferenceObjectByHandle, ZwClose


ObReleaseObjectSecurity

ObReleaseObjectSecurity is the reciprocal to ObGetObjectSecurity.

VOID
  ObReleaseObjectSecurity(
    IN PSECURITY_DESCRIPTOR  SecurityDescriptor,
    IN BOOLEAN  MemoryAllocated
    );

Parameters

SecurityDescriptor
Points to the buffered SECURITY_DESCRIPTOR to be released. The caller obtained this parameter from ObGetObjectSecurity
MemoryAllocated
Specifies the value also obtained from ObGetObjectSecurity.

Include

ntddk.h

Comments

After a successful call to ObGetObjectSecurity, a driver must call ObReleaseObjectSecurity eventually.

ObReleaseObjectSecurity releases any resources that were allocated by ObGetObjectSecurity. It also decrements the reference count on the given security descriptor.

Callers of ObReleaseObjectSecurity must be running at IRQL < DISPATCH_LEVEL.

See Also

SECURITY_DESCRIPTOR, ObGetObjectSecurity


Process Structure Routines

References for the Ps Xxx routines are in alphabetical order.

For an overview of the functionality of these routines, see Summary of Kernel-Mode Support Routines.


PsCreateSystemThread

PsCreateSystemThread creates a system thread that executes in kernel mode and returns a handle for the thread.

NTSTATUS
  PsCreateSystemThread(
    OUT PHANDLE  ThreadHandle,
    IN ULONG  DesiredAccess,
    IN POBJECT_ATTRIBUTES  ObjectAttributes  OPTIONAL,
    IN HANDLE  ProcessHandle  OPTIONAL,
    OUT PCLIENT_ID  ClientId  OPTIONAL,
    IN PKSTART_ROUTINE  StartRoutine,
    IN PVOID  StartContext
    );

Parameters

ThreadHandle
Points to a variable that will receive the handle.
DesiredAccess
Specifies the ACCESS_MASK value that represents the requested types of access to the created thread. This value can be THREAD_ALL_ACCESS or (ACCESS_MASK) 0L for a driver-created thread.
ObjectAttributes
Points to a structure that specifies the object's attributes. OBJ_PERMANENT, OBJ_EXCLUSIVE, OBJ_OPENIF, and OBJ_OPENLINK are not valid attributes for a thread object. On Windows XP and later operating systems, if the caller is running in the system process context, the this parameter can be NULL. Otherwise, the caller must set the OBJ_KERNEL_HANDLE attribute for ObjectAttributes.
ProcessHandle
Specifies an open handle for the process in whose address space the thread is to be run. The caller's thread must have PROCESS_CREATE_THREAD access to this process. If this parameter is not supplied, the thread will be created in the initial system process. This value should be NULL for a driver-created thread. Use the NtCurrentProcess() macro to specify the current process.
ClientId
Points to a structure that receives the client identifier of the new thread. This value should be NULL for a driver-created thread.
StartRoutine
Is the entry point for a driver thread.
StartContext
Supplies a single argument passed to the thread when it begins execution.

Include

wdm.h or ntddk.h

Return Value

PsCreateSystemThread returns STATUS_SUCCESS if the thread was created.

Comments

Drivers that create device-dedicated threads call this routine, either when they initialize or when I/O requests begin to come in to such a driver's Dispatch routines. For example, a driver might create such a thread when it receives an asynchronous device control request.

PsCreateSystemThread creates a kernel-mode thread that begins a separate thread of execution within the system. Such a system thread has no TEB or user-mode context and runs only in kernel mode.

If the input ProcessHandle is NULL, the created thread is associated with the system process. Such a thread continues running until either the system is shut down or the thread terminates itself by calling PsTerminateSystemThread.

Driver routines that run in a process context other than that of the system process must set the OBJ_KERNEL_HANDLE attribute for the ObjectAttributes parameter of PsCreateSystemThread. This restricts the use of the handle returned by PsCreateSystemThread to processes running in kernel mode. Otherwise, the thread handle can be accessed by the process in whose context the driver is running. Drivers can set the OBJ_KERNEL_HANDLE attribute as follows.

InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);

Callers of this routine must be running at IRQL PASSIVE_LEVEL.

See Also

InitializeObjectAttributes, KeSetBasePriorityThread, KeSetPriorityThread, PsTerminateSystemThread, ZwSetInformationThread


PsGetCurrentProcess

PsGetCurrentProcess returns a pointer to the process of the current thread.

PEPROCESS
  PsGetCurrentProcess(
    );

Include

wdm.h or ntddk.h

Comments

Highest-level drivers, file systems in particular, can call this routine. Lower-level drivers should call IoGetCurrentProcess instead.

PsGetCurrentProcess is the most efficient way to get a pointer to the current process, no matter what environment is being used.

Callers of PsGetCurrentProcess must be running at IRQL PASSIVE_LEVEL.

See Also

IoGetCurrentProcess, PsGetCurrentThread


PsGetCurrentProcessId

PsGetCurrentProcessId identifies the current process.

HANDLE
  PsGetCurrentProcessId(
    );

Include

ntddk.h

Return Value

PsGetCurrentProcessId returns the 4-byte identifier of the current process.

Comments

Highest-level drivers, such as system profilers or IFSs, that register their own callback(s) with PsSetCreateProcessNotifyRoutine, PsSetCreateThreadNotifyRoutine, and/or PsSetLoadImageNotifyRoutine are likely to call PsGetCurrentProcessId.

Callers of PsGetCurrentProcessId should treat the returned ID as a read-only value.

Callers of PsGetCurrentProcessId can be running at any IRQL.

See Also

IoGetCurrentProcess, PsGetCurrentProcess, PsGetCurrentThread, PsGetCurrentThreadId, PsSetCreateProcessNotifyRoutine, PsSetCreateThreadNotifyRoutine, PsSetLoadImageNotifyRoutine


PsGetCurrentThread

PsGetCurrentThread identifies the current thread.

PETHREAD
  PsGetCurrentThread(
    );

Include

wdm.h or ntddk.h

Return Value

PsGetCurrentThread returns a pointer to the executive thread object representing the currently executing thread.

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL.

See Also

KeGetCurrentThread, PsCreateSystemThread, PsGetCurrentProcess, PsGetCurrentProcessId


PsGetCurrentThreadId

PsGetCurrentThreadId identifies the current thread.

HANDLE
  PsGetCurrentThreadId(
    );

Include

ntddk.h

Return Value

PsGetCurrentThreadId returns the 4-byte identifier of the current thread.

Comments

Highest-level drivers, such a system profilers or IFSs, that register their own callback with PsSetCreateThreadNotifyRoutine are likely to call PsGetCurrentThreadId.

Callers of PsGetCurrentThreadId should treat the returned ID as a read-only value.

Callers of PsGetCurrentThreadId can be running at any IRQL.

See Also

KeGetCurrentThread, PsGetCurrentProcessId, PsGetCurrentThread, PsSetCreateThreadNotifyRoutine


PsGetVersion

PsGetVersion returns caller-selected information about the current version of the NT-based operating system.

BOOLEAN
  PsGetVersion(
    PULONG  MajorVersion  OPTIONAL,
    PULONG  MinorVersion  OPTIONAL,
    PULONG  BuildNumber  OPTIONAL,
    PUNICODE_STRING  CSDVersion  OPTIONAL
    );

Parameters

MajorVersion
Points to a caller-supplied variable that this routine sets to the major version of the operating system. This optional parameter can be NULL.
MinorVersion
Points to a caller-supplied variable that this routine sets to the minor version of the operating system. This optional parameter can be NULL.
BuildNumber
Points to a caller-supplied variable that this routine sets to the current build number of the operating system. This optional parameter can be NULL.
CSDVersion
Points to a caller-allocated buffer in which this routine returns the current service-pack version as a Unicode string only during system driver initialization. This optional parameter can be NULL.

Include

ntddk.h

Return Value

PsGetVersion returns whether the system is a checked or free build, as follows:

Value | Meaning
TRUE (1) | Checked build of the operating system.
FALSE (0) | Free build of the operating system.

Comments

PsGetVersion returns the requested information, depending on which optional parameter(s) the caller supplies.

To retrieve the current sevice-pack number, it is easier and more efficient to make an application-level call within the Win32® environment than to call PsGetVersion during system driver initialization, which then must parse the string it returns at CSDVersion. When the registry is initialized, a driver cannot obtain this string from PsGetVersion, but must read the CmCSDVersionString value from the registry.

Callers of PsGetVersion must be running at IRQL PASSIVE_LEVEL.


PsSetCreateProcessNotifyRoutine

PsSetCreateProcessNotifyRoutine adds a driver-supplied callback routine to, or removes it from, a list of routines to be called whenever a process is created or deleted.

NTSTATUS
  PsSetCreateProcessNotifyRoutine(
    IN PCREATE_PROCESS_NOTIFY_ROUTINE  NotifyRoutine,
    IN BOOLEAN  Remove
    );

Parameters

NotifyRoutine
Specifies the entry point of a caller-supplied process-creation callback routine.
Remove
Indicates whether the routine specified by NotifyRoutine should be added to or removed from the system's list of notification routines. If FALSE, the specified routine is added to the list. If TRUE, the specified routine is removed from the list.

Include

ntddk.h

Return Value

PsSetCreateProcessNotifyRoutine can return one of the following:

STATUS_SUCCESS
The given NotifyRoutine is now registered with the system.
STATUS_INVALID_PARAMETER
The given NotifyRoutine has already been registered so this is a redundant call, or the system has reached its limit for registering process-creation callbacks.

Comments

Highest-level drivers can call PsSetCreateProcessNotifyRoutine to set up their process-creation notify routines, declared as follows:

VOID
(*PCREATE_PROCESS_NOTIFY_ROUTINE) (
    IN HANDLE  ParentId,
    IN HANDLE  ProcessId,
    IN BOOLEAN  Create
    );

The ParentId and ProcessId parameters identify the process, and the Create parameter indicates whether the process was created (TRUE) or deleted (FALSE).

An IFS or highest-level system-profiling driver might register a process-creation callback to track the system-wide creation and deletion of processes against the driver's internal state. The system can register up to eight process-creation callbacks. Any driver that successfully registers a callback must remain loaded until the system itself is shut down.

After a driver-supplied routine is registered, it is called with Create set to TRUE just after the initial thread is created within the newly created process designated by the input ProcessId handle. The input ParentId handle identifies the parent process of the newly created process if it inherits open handles from its parent.

A driver's process-notify routine is also called with Create set to FALSE, usually when the last thread within a process has terminated and the process address space is about to be deleted. In very rare circumstances, for processes in which no thread was ever created, a driver's process-notify routine is called only at the destruction of the process.

The driver's process-creation notify routine runs at IRQL PASSIVE_LEVEL, either in the context of the initial thread within a newly created process or in the context of a system thread.

Callers of PsSetCreateProcessNotifyRoutine must be running at IRQL PASSIVE_LEVEL.

See Also

PsGetCurrentProcessId, PsSetCreateThreadNotifyRoutine, PsSetLoadImageNotifyRoutine


PsSetCreateThreadNotifyRoutine

PsSetCreateThreadNotifyRoutine registers a driver-supplied callback that is subsequently notified when a new thread is created and when such a thread is deleted.

NTSTATUS
  PsSetCreateThreadNotifyRoutine(
    IN PCREATE_THREAD_NOTIFY_ROUTINE  NotifyRoutine
    );

Parameter

NotifyRoutine
Specifies the entry point of the caller-supplied thread-creation callback.

Include

ntddk.h

Return Value

PsSetCreateThreadNotifyRoutine either returns STATUS_SUCCESS or it returns STATUS_INSUFFICIENT_RESOURCES if it failed the callback registration.

Comments

Highest-level drivers can call PsSetCreateThreadNotifyRoutine to set up their thread-creation notify routines, declared as follows:

VOID
(*PCREATE_THREAD_NOTIFY_ROUTINE) (
    IN HANDLE  ProcessId,
    IN HANDLE  ThreadId,
    IN BOOLEAN  Create
    );

For example, an IFS or highest-level system-profiling driver might register such a thread-creation callback to track the system-wide creation and deletion of threads against the driver's internal state. The system registers up to eight such thread-creation callbacks. Any driver that successfully registers such a callback must remain loaded until the system itself is shut down.

After such a driver-supplied thread-creation routine is registered, it is called with Create set to TRUE whenever a new thread is created. The input ThreadId handle identifies the newly created thread. The input ProcessId handle identifies the process in which the given thread was just created. As each such thread is deleted, such a driver's thread-notify routine is called again with Create set to FALSE.

When it is called, the driver's thread-creation notify routine runs at IRQL PASSIVE_LEVEL either in the context of the newly created thread or in the context of the exiting thread.

Callers of PsSetCreateThreadNotifyRoutine must be running at IRQL PASSIVE_LEVEL.

See Also

PsGetCurrentProcessId, PsGetCurrentThreadId, PsSetCreateProcessNotifyRoutine, PsSetLoadImageNotifyRoutine


PsSetLoadImageNotifyRoutine

PsSetLoadImageNotifyRoutine registers a driver-supplied callback that is subsequently notified whenever an image is loaded for execution.

NTSTATUS
  PsSetLoadImageNotifyRoutine(
    IN PLOAD_IMAGE_NOTIFY_ROUTINE  NotifyRoutine
    );

Parameters

NotifyRoutine
Specifies the entry point of the caller-supplied load-image callback.

Include

ntddk.h

Return Value

PsSetLoadImageNotifyRoutine either returns STATUS_SUCCESS or it returns STATUS_INSUFFICIENT_RESOURCES if it failed the callback registration

Comments

Highest-level system-profiling drivers can call PsSetLoadImageNotifyRoutine to set up their load-image notify routines, declared as follows:

VOID
(*PLOAD_IMAGE_NOTIFY_ROUTINE) (
    IN PUNICODE_STRING  FullImageName,
    IN HANDLE  ProcessId, // where image is mapped
    IN PIMAGE_INFO  ImageInfo
    );

After such a driver's callback has been registered, the system calls its load-image notify routine whenever an executable image is mapped into virtual memory, whether in system space or user space, before the execution of the image begins. The system registers up to eight such load-image callbacks. Any driver that successfully registers such a callback must remain loaded until the system itself is shut down.

When the load-image notify routine is called, the input FullImageName points to a buffered Unicode string identifying the executable image file. The ProcessId handle identifies the process in which the image has been mapped, but this handle is zero if the newly loading image is a driver. The buffered data at ImageInfo is formatted as follows:

typedef struct  _IMAGE_INFO {
    union {
        ULONG  Properties;
        struct {
            ULONG ImageAddressingMode  : 8; //code addressing mode
            ULONG SystemModeImage      : 1; //system mode image
            ULONG ImageMappedToAllPids : 1; //mapped in all processes
            ULONG Reserved             : 22;
        };
    };
    PVOID  ImageBase;
    ULONG  ImageSelector;
    ULONG  ImageSize;
    ULONG  ImageSectionNumber;
} IMAGE_INFO, *PIMAGE_INFO;

When such a profiling driver's load-image routine is called, the members of this structure contain the following information:

ImageAddressingMode
Always set to IMAGE_ADDRESSING_MODE_32BIT.
SystemModeImage
Set either to one for newly loaded kernel-mode components, such as drivers, or to zero for images that are mapped into user space.
ImageMappedToAllPids and Reserved
Always set to zero.
ImageBase
Set to the virtual base address of the image.
ImageSelector
Always set to zero.
ImageSize
Set to the virtual size, in bytes, of the image.
ImageSectionNumber
Always set to zero.

Callers of PsSetLoadImageNotifyRoutine must be running at IRQL PASSIVE_LEVEL.

See Also

PsGetCurrentProcessId, PsSetCreateProcessNotifyRoutine, PsSetCreateThreadNotifyRoutine


PsTerminateSystemThread

PsTerminateSystemThread terminates a caller-created system thread.

NTSTATUS
  PsTerminateSystemThread(
    IN NTSTATUS  ExitStatus
    );

Parameters

ExitStatus
Specifies the status of the terminating system thread to the thread creator.

Include

wdm.h or ntddk.h

Return Value

PsTerminateSystemThread returns the STATUS_XXX supplied by the caller-created thread, usually STATUS_SUCCESS.

Comments

Drivers that create a device-dedicated thread call this routine, either when the driver is unloaded or when there are no outstanding I/O requests for the driver to process. For such a driver, PsTerminateSystemThread must be called in the context of the driver's thread; that is, the driver-created thread must terminate itself by making this call.

Callers of this routine must be running at IRQL PASSIVE_LEVEL.

See Also

PsCreateSystemThread


Run-time Library Routines

References for these routines are in alphabetical order.

For an overview of the functionality of these routines, see Summary of Kernel-Mode Support Routines.

The following routines are reserved for system use. Do not use them in your driver.

RtlGetCallersAddress


InitializeListHead

InitializeListHead initializes any doubly linked, driver-managed interlocked queue or driver-maintained doubly linked list.

VOID
  InitializeListHead(
    IN PLIST_ENTRY  ListHead
    );

Parameters

ListHead
Points to the driver-allocated storage for the head of the interlocked queue or list. For an interlocked queue, the storage must be resident and the driver also must provide storage for a spin lock.

Include

wdm.h or ntddk.h

Comments

A driver that sets up internal interlocked queues for IRPs or manages internal linked lists must call InitializeListHead. A PnP driver should make the call from its AddDevice routine after creating the relevant device object; other drivers can call from the DriverEntry routine.

The ListHead of type LIST_ENTRY is doubly linked. Entries in an interlocked queue can be queued and dequeued by calling ExInterlockedInsert..List and ExInterlockedRemoveHeadList. Entries can be inserted into and removed from a driver-maintained list with Insert..List and Remove..List.

For an interlocked queue, a driver must provide resident storage: in the device extension of a driver-created device object, in the controller extension of a driver-created controller object, or in nonpaged pool allocated by the driver. The driver also must provide storage for a spin lock, which must be initialized with KeInitializeSpinLock before the driver's initial call to ExInterlocked Xxx with the spin lock.

For a driver-maintained list, the driver must synchronize access to the list so that it is impossible for any two routines to be inserting and/or removing entries from the list simultaneously in SMP machines. Consequently, most drivers use the ExInterlocked Xxx routines to manage the necessary synchronization, rather than setting up a driver-managed list, which is likely to require spin lock protection anyway.

Callers of InitializeListHead can be running at IRQL >= DISPATCH_LEVEL only if the caller-allocated storage for ListHead is resident.

See Also

ExInterlockedInsertHeadList, ExInterlockedInsertTailList, ExInterlockedRemoveHeadList, ExInterlockedPopEntryList, ExInterlockedPushEntryList, InsertHeadList, InsertTailList, IsListEmpty, KeInitializeSpinLock, PopEntryList, PushEntryList, RemoveEntryList, RemoveHeadList, RemoveTailList


InitializeObjectAttributes

The InitializeObjectAttributes macro sets up a parameter of type OBJECT_ATTRIBUTES for a subsequent call to ExCreateCallback or to a ZwCreate Xxx or ZwOpen Xxx routine.

VOID
  InitializeObjectAttributes(
    OUT POBJECT_ATTRIBUTES  InitializedAttributes,
    IN PUNICODE_STRING  ObjectName,
    IN ULONG  Attributes,
    IN HANDLE  RootDirectory,
    IN PSECURITY_DESCRIPTOR  SecurityDescriptor
    );

Parameters

InitializedAttributes
Is a pointer to an OBJECT_ATTRIBUTES structure (defined in ntdef.h) containing the initialized attributes for the object on return from InitializeObjectAttributes.
ObjectName
Is the full path name for the object.
Attributes
Is the set of attributes for the object, which can be a combination (ORed) of the following system-defined values:

OBJ_INHERIT
OBJ_PERMANENT
OBJ_EXCLUSIVE
OBJ_CASE_INSENSITIVE
OBJ_OPENIF
OBJ_KERNEL_HANDLE

The validity of these values depends on the object type.

RootDirectory
Is a handle for the root directory in which the created object should be placed, in which an object to be opened is contained, or NULL.
SecurityDescriptor
Is an initialized absolute SECURITY_DESCRIPTOR for the object or NULL.

Headers

Defined in ntdef.h. Include wdm.h or ntddk.h.

Comments

Driver routines that run in a process context other than that of the system process must set the OBJ_KERNEL_HANDLE attribute for the Attributes parameter of InitializeObjectAttributes. This restricts the use of a handle opened for that object to processes running only in kernel mode. Otherwise, the thread handle can be accessed by the process in whose context the driver is running. Drivers can call InitializeObjectAttributes to set the OBJ_KERNEL_HANDLE attribute as follows.

InitializeObjectAttributes(
    &ObjectAttributes,
    NULL,
    OBJ_KERNEL_HANDLE,
    NULL,
    NULL);

See Also

ExCreateCallback , ZwCreateDirectoryObject, ZwCreateFile, ZwCreateKey, ZwOpenKey, ZwOpenSection, SECURITY_DESCRIPTOR


InsertHeadList

InsertHeadList inserts an entry at the head of a doubly linked, driver-managed list.

VOID
  InsertHeadList(
    IN PLIST_ENTRY  ListHead,
    IN PLIST_ENTRY  Entry
    );

Parameters

ListHead
Points to the driver-allocated storage for the head of the list.

The ListHead of type LIST_ENTRY is doubly linked.

Entry
Points to an entry to be inserted in the list.

Include

wdm.h or ntddk.h

Comments

Callers of InsertHeadList can be running at IRQL >= DISPATCH_LEVEL only if the caller-allocated storage for ListHead is resident and only if pointers to every list entry remain valid at IRQL >= DISPATCH_LEVEL as well.

See Also

ExInterlockedInsertHeadList, InitializeListHead, InsertTailList, IsListEmpty, RemoveHeadList, RemoveTailList


InsertTailList

InsertTailList inserts an entry at the tail of a doubly linked, driver-managed list.

VOID
  InsertTailList(
    IN PLIST_ENTRY  ListHead,
    IN PLIST_ENTRY  Entry
    );

Parameters

ListHead
Points to the driver-allocated storage for the head of the list.

The ListHead of type LIST_ENTRY is doubly linked.

Entry
Points to an entry to be inserted in the list.

Include

wdm.h or ntddk.h

Comments

Callers of InsertTailList can be running at IRQL >= DISPATCH_LEVEL only if the caller-allocated storage for ListHead is resident and only if pointers to every list entry remain valid at IRQL >= DISPATCH_LEVEL as well.

See Also

ExInterlockedInsertTailList, InitializeListHead, InsertHeadList, IsListEmpty, RemoveHeadList, RemoveTailList


IsListEmpty

IsListEmpty indicates whether a doubly linked, driver-maintained list is empty.

BOOLEAN
  IsListEmpty(
    IN PLIST_ENTRY  ListHead
    );

Parameters

ListHead
Points to the driver-allocated storage for the head of the list.

The ListHead of type LIST_ENTRY is doubly linked.

Return Value

IsListEmpty returns TRUE if there are currently no entries in the list.

Include

wdm.h or ntddk.h

Comments

Callers of IsListEmpty can be running at IRQL >= DISPATCH_LEVEL only if the caller-allocated storage for ListHead is resident and only if pointers to every list entry remain valid at IRQL >= DISPATCH_LEVEL as well.

See Also

InitializeListHead, RemoveHeadList, RemoveTailList, RemoveEntryList


PopEntryList

PopEntryList removes an entry in a singly linked, driver-managed list.

PSINGLE_LIST_ENTRY
  PopEntryList(
    IN PSINGLE_LIST_ENTRY  ListHead
    );

Parameters

ListHead
Points to the driver-allocated storage for the head of the list.

The ListHead of type LIST_ENTRY is singly linked. The ListHead must be initialized to NULL before entries can be pushed and popped.

Include

wdm.h or ntddk.h

Return Value

PopEntryList returns a pointer to the last-pushed entry (LIFO order) or a NULL pointer if the list is currently empty.

Comments

Callers of PopEntryList can be running at IRQL >= DISPATCH_LEVEL only if the caller-allocated storage for ListHead is resident and only if pointers to every list entry remain valid at IRQL >= DISPATCH_LEVEL as well.

See Also

ExInterlockedPopEntryList, PushEntryList


PushEntryList

PushEntryList pushes an entry into a singly linked, driver-maintained list.

VOID
  PushEntryList(
    IN PSINGLE_LIST_ENTRY  ListHead,
    IN PSINGLE_LIST_ENTRY  Entry
    );

Parameters

ListHead
Points to the driver-allocated storage for the head of the list.

The ListHead of type SINGLE_LIST_ENTRY is singly linked. It must be initialized to NULL before the initial entry is pushed.

Entry
Points to the driver-allocated storage for an entry in the list.

Include

wdm.h or ntddk.h

Comments

Callers of PushEntryList can be running at IRQL >= DISPATCH_LEVEL only if the caller-allocated storage for ListHead is resident and only if pointers to every list entry remain valid at IRQL >= DISPATCH_LEVEL as well.

See Also

ExInterlockedPushEntryList, PopEntryList


RemoveEntryList

RemoveEntryList resets the links for an entry from a doubly linked, driver-managed list.

VOID
  RemoveEntryList(
    IN PLIST_ENTRY  Entry
    );

Parameters

Entry
Points to the entry.

Include

wdm.h or ntddk.h

Comments

Callers of RemoveEntryList can be running at IRQL >= DISPATCH_LEVEL only if the caller-allocated storage for Entry is resident.

RemoveEntryList sets the forward and backward links for the entry to each other.

See Also

InitializeListHead, IsListEmpty, RemoveHeadList, RemoveTailList


RemoveHeadList

RemoveHeadList removes an entry from the head of a doubly linked list.

PLIST_ENTRY
  RemoveHeadList(
    IN PLIST_ENTRY  ListHead
    );

Parameters

ListHead
Points to the driver-allocated storage for a doubly linked list with entries of type LIST_ENTRY.

Include

wdm.h or ntddk.h

Return Value

RemoveHeadList returns a pointer to the entry that was at the head of the list.

Comments

Calling RemoveHeadList with an empty list can cause a system failure. Callers of RemoveHeadList should first call IsListEmpty to determine if the list has any entries.

Callers of RemoveHeadList can be running at IRQL >= DISPATCH_LEVEL only if the caller-allocated storage for ListHead is resident and only if pointers to every list entry remain valid at IRQL >= DISPATCH_LEVEL as well.

This routine provides no inherent synchronization for the LIST_ENTRY that is being removed from the list.

See Also

ExInterlockedRemoveHeadList, InitializeListHead, IsListEmpty, RemoveTailList, RemoveEntryList


RemoveTailList

RemoveTailList removes an entry from the tail of a doubly linked list.

PLIST_ENTRY
  RemoveTailList(
    IN PLIST_ENTRY  ListHead
    );

Parameters

ListHead
Points to the driver-allocated storage for a doubly linked list with entries of type LIST_ENTRY.

Include

wdm.h or ntddk.h

Return Value

RemoveTailList returns a pointer to the entry that was at the tail of the list.

Comments

Calling RemoveTailList with an empty list can cause a system failure. Callers of RemoveTailList should first call IsListEmpty to determine if the list has any entries.

Callers of RemoveTailList can be running at IRQL >= DISPATCH_LEVEL only if the caller-allocated storage for ListHead is resident and only if pointers to every list entry remain valid at IRQL >= DISPATCH_LEVEL as well.

See Also

InitializeListHead, IsListEmpty, RemoveHeadList, RemoveEntryList


RtlAnsiStringToUnicodeSize

RtlAnsiStringToUnicodeSize returns the number of bytes required to hold an ANSI string converted into a Unicode string.

ULONG
  RtlAnsiStringToUnicodeSize(
    IN PANSI_STRING  AnsiString
    );

Parameters

AnsiString
Points to a buffer containing the ANSI string.

Return Value

RtlAnsiStringToUnicodeSize returns the necessary size in bytes for a Unicode string buffer.

Include

wdm.h or ntddk.h

Comments

Callers of RtlAnsiStringToUnicodeSize must be running at IRQL PASSIVE_LEVEL.

See Also

RtlAnsiStringToUnicodeString


RtlAnsiStringToUnicodeString

RtlAnsiStringToUnicodeString converts the given ANSI source string into a Unicode string.

NTSTATUS
  RtlAnsiStringToUnicodeString(
    IN OUT PUNICODE_STRING  DestinationString,
    IN PANSI_STRING  SourceString,
    IN BOOLEAN  AllocateDestinationString
    );

Parameters

DestinationString
Pointer to a UNICODE_STRING structure to hold the converted Unicode string. If AllocateDestinationString is TRUE, the routine allocates a new buffer to hold the string data, and updates the Buffer member of DestinationString to point to the new buffer. Otherwise, the routine uses the currently-specified buffer to hold the string.
SourceString
Points to the ANSI string to be converted to Unicode.
AllocateDestinationString
Is TRUE if this routine should allocate the buffer space for the destination string. If it does, the caller must deallocate the buffer by calling RtlFreeUnicodeString.

Include

wdm.h or ntddk.h

Return Value

If the conversion succeeds, RtlAnsiStringToUnicodeString returns STATUS_SUCCESS. On failure, the routine does not allocate any memory.

Comments

The translation conforms to the current system locale information.

If caller sets AllocateDestinationString to TRUE, the routine replaces the Buffer member of DestinationString with a pointer to the buffer it allocates. The old value can be overwritten even when the routine returns an error status code.

Callers of RtlAnsiStringToUnicodeString must be running at IRQL PASSIVE_LEVEL.

See Also

ANSI_STRING, UNICODE_STRING, RtlAnsiStringToUnicodeSize, RtlFreeUnicodeString, RtlInitAnsiString, RtlUnicodeStringToAnsiString


RtlAppendUnicodeStringToString

RtlAppendUnicodeStringToString concatenates two Unicode strings.

NTSTATUS
  RtlAppendUnicodeStringToString(
    IN OUT PUNICODE_STRING  Destination,
    IN PUNICODE_STRING  Source
    );

Parameters

Destination
Points to a buffered Unicode string.
Source
Points to the buffered string to be concatenated.

Include

wdm.h or ntddk.h

Return Value

RtlAppendUnicodeStringToString can return one of the following:

STATUS_SUCCESS
The source string was successfully appended to the destination counted string. The destination string length is updated to include the appended bytes.
STATUS_BUFFER_TOO_SMALL
The destination string length is too small to allow the source string to be concatenated. Accordingly, the destination string length is not updated.

Comments

RtlAppendUnicodeStringToString copies bytes from the source up to the length of the destination buffer.

The Destination and Source buffers must be resident if the caller is running at IRQL >= DISPATCH_LEVEL.

See Also

RtlAppendUnicodeToString


RtlAppendUnicodeToString

RtlAppendUnicodeToString concatenates the supplied Unicode string to a buffered Unicode string.

NTSTATUS
  RtlAppendUnicodeToString(
    IN OUT PUNICODE_STRING  Destination,
    IN PCWSTR  Source
    );

Parameters

Destination
Points to the buffered string.
Source
Points to the string to be appended to the Destination string.

Include

wdm.h or ntddk.h

Return Value

RtlAppendUnicodeToString can return one of the following:

STATUS_SUCCESS
The source string was successfully appended to the destination counted string. The destination string length is updated to include the appended bytes.
STATUS_BUFFER_TOO_SMALL
The destination string length was too small to allow the source string to be appended, so the destination string length is not updated.

Comments

RtlAppendUnicodeToString copies bytes from the source string to the destination string up to the end of the destination buffer.

The Destination buffer must be resident if the caller is running at IRQL >= DISPATCH_LEVEL.

See Also

RtlAppendUnicodeStringToString


RtlAreBitsClear

RtlAreBitsClear determines whether a given range of bits within a bitmap variable is clear.

BOOLEAN
  RtlAreBitsClear(
    IN PRTL_BITMAP  BitMapHeader,
    IN ULONG  StartingIndex,
    IN ULONG  Length
    );

Parameters

BitMapHeader
Points to an initialized bitmap header for the caller's bitmap variable.
StartingIndex
Specifies the start of the bit range to be tested. This is a zero-based value indicating the position of the first bit in the range.
Length
Specifies how many bits to test.

Include

ntddk.h

Return Value

RtlAreBitsClear returns TRUE if Length consecutive bits beginning at StartingIndex are clear (that is, all the bits from StartingIndex to (StartingIndex + Length) -1). It returns FALSE if any bit in the given range is set, if the given range is not a proper subset of the bitmap, or if the given Length is zero.

Comments

Callers of RtlAreBitsClear must be running at IRQL < DISPATCH_LEVEL if the memory containing the bitmap variable or at BitMapHeader is pageable. Otherwise, RtlAreBitsClear can be called at any IRQL.

See Also

RtlAreBitsSet, RtlCheckBit, RtlClearAllBits, RtlFindClearBits, RtlFindFirstRunClear, RtlFindLastBackwardRunClear, RtlFindLongestRunClear, RtlFindNextForwardRunClear, RtlInitializeBitMap


RtlAreBitsSet

RtlAreBitsSet determines whether a given range of bits within a bitmap variable is set.

BOOLEAN
  RtlAreBitsSet(
    IN PRTL_BITMAP  BitMapHeader,
    IN ULONG  StartingIndex,
    IN ULONG  Length
    );

Parameters

BitMapHeader
Points to an initialized bitmap header for the caller's bitmap variable.
StartingIndex
Specifies the start of the bit range to be tested. This is a zero-based value indicating the position of the first bit in the range.
Length
Specifies how many bits to test.

Include

ntddk.h

Return Value

RtlAreBitsSet returns TRUE if Length consecutive bits beginning at StartingIndex are set (that is, all the bits from StartingIndex to (StartingIndex + Length) –1). It returns FALSE if any bit in the given range is clear, if the given range is not a proper subset of the bitmap, or if the given Length is zero.

Comments

Callers of RtlAreBitsSet must be running at IRQL < DISPATCH_LEVEL if the memory containing the bitmap variable or at BitMapHeader is pageable. Otherwise, RtlAreBitsSet can be called at any IRQL.

See Also

RtlAreBitsClear, RtlCheckBit, RtlFindSetBits, RtlInitializeBitMap, RtlSetAllBits


RtlCharToInteger

RtlCharToInteger converts a single-byte character to an integer value in the specified base.

NTSTATUS
  RtlCharToInteger(
    IN PCSZ  String,
    IN ULONG  Base  OPTIONAL,
    IN OUT PULONG  Value
    );

Parameters

String
Points to a zero-terminated, single-byte character string.
Base
Specifies decimal, binary, octal, or hexadecimal base.
Value
Points to a location to which the converted value is returned.

Include

ntddk.h

Return Value

RtlCharToInteger returns STATUS_SUCCESS if the given character is converted. Otherwise, it can return STATUS_INVALID_PARAMETER.

Comments

RtlCharToInteger converts ANSI alphanumeric characters.

Callers of RtlCharToInteger must be running at IRQL PASSIVE_LEVEL.

See Also

RtlInitString, RtlIntegerToUnicodeString


RtlCheckBit

RtlCheckBit determines whether a particular bit in a given bitmap variable is clear or set.

ULONG
  RtlCheckBit(
    IN PRTL_BITMAP  BitMapHeader,
    IN ULONG  BitPosition
    );

Parameters

BitMapHeader
Points to an initialized bitmap header for the caller's bitmap variable.
BitPosition
Specifies which bit to check. This is a zero-based value indicating the position of the bit to be tested.

Include

ntddk.h

Return Value

RtlCheckBit returns zero if the given bit is clear or one if the given bit is set.

Comments

Callers of RtlCheckBit must be running at IRQL < DISPATCH_LEVEL if the memory containing the bitmap variable or at BitMapHeader is pageable. Otherwise, RtlCheckBit can be called at any IRQL.

See Also

RtlAreBitsClear, RtlAreBitsSet, RtlInitializeBitMap, RtlNumberOfClearBits, RtlNumberOfSetBits


RtlCheckRegistryKey

RtlCheckRegistryKey checks for the existence of a given named key in the registry.

NTSTATUS
  RtlCheckRegistryKey(
    IN ULONG  RelativeTo,
    IN PWSTR  Path
    );

Parameters

RelativeTo
Specifies whether Path is an absolute registry path or is relative to a predefined key path as one of the following:
Value Meaning
RTL_REGISTRY_ABSOLUTE
Path is an absolute registry path.
RTL_REGISTRY_SERVICES
Path is relative to \Registry\Machine\System\CurrentControlSet\Services.
RTL_REGISTRY_CONTROL
Path is relative to \Registry\Machine\System\CurrentControlSet\Control.
RTL_REGISTRY_WINDOWS_NT
Path is relative to \Registry\Machine\Software\Microsoft\
Windows NT\CurrentVersion.
RTL_REGISTRY_DEVICEMAP
Path is relative to \Registry\Machine\Hardware\DeviceMap.
RTL_REGISTRY_USER
Path is relative to \Registry\User\CurrentUser.
RTL_REGISTRY_OPTIONAL
Specifies that the key referenced by this parameter and the Path parameter are optional.
RTL_REGISTRY_HANDLE
Specifies that the Path parameter is actually a registry handle to use. This value is optional.

Path
Specifies the registry path according to the RelativeTo value. If RTL_REGISTRY_HANDLE is set, Path is a handle to be used directly.

Include

ntddk.h

Return Value

If the given, named key exists in the registry along the given relative path, RtlCheckRegistryKey returns STATUS_SUCCESS.

Comments

Callers of RtlCheckRegistryKey must be running at IRQL PASSIVE_LEVEL.

See Also

RtlQueryRegistryValues


RtlClearBits

RtlClearBits sets all bits in a given range of a given bitmap variable to zero.

VOID
  RtlClearBits(
    IN PRTL_BITMAP  BitMapHeader,
    IN ULONG  StartingIndex,
    IN ULONG  NumberToClear
    );

Parameters

BitMapHeader
Points to an initialized bitmap header for the caller's bitmap variable.
StartingIndex
Specifies the start of the bit range to be cleared. This is a zero-based value indicating the position of the first bit in the range.
NumberToClear
Specifies how many bits to clear.

Include

ntddk.h

Comments

RtlClearBits simply returns control if the input NumberToClear is zero. StartingIndex plus NumberToClear must be less than or equal to sizeof(BitMapHeader->SizeOfBitMap).

Callers of RtlClearBits must be running at IRQL < DISPATCH_LEVEL if the memory containing the bitmap variable or at BitMapHeader is pageable. Otherwise, RtlClearBits can be called at any IRQL.

See Also

RtlAreBitsSet, RtlClearAllBits, RtlFindSetBits, RtlFindSetBitsAndClear, RtlInitializeBitMap, RtlNumberOfSetBits


RtlCompareMemory

RtlCompareMemory compares blocks of memory and returns the number of bytes that are equivalent.

SIZE_T
  RtlCompareMemory(
    IN CONST VOID  *Source1,
    IN CONST VOID  *Source2,
    IN SIZE_T  Length
    );

Parameters

Source1
Points to a block of memory to compare.
Source2
Points to a block of memory to compare.
Length
Specifies the number of bytes to be compared.

Include

wdm.h or ntddk.h

Return Value

RtlCompareMemory returns the number of bytes that compare as equal. If all bytes compare as equal, the input Length is returned.

Comments

Callers of RtlCompareMemory can be running at any IRQL if both blocks of memory are resident.


RtlCompareString

RtlCompareString compares two counted strings.

LONG
  RtlCompareString(
    IN PSTRING  String1,
    IN PSTRING  String2,
    BOOLEAN  CaseInSensitive
    );

Parameters

String1
Points to the first string.
String2
Points to the second string.
CaseInSensitive
If TRUE, case should be ignored when doing the comparison.

Include

ntddk.h

Return Value

RtlCompareString returns a signed value that gives the results of the comparison:

Zero
String1 equals String2.
< Zero
String1 is less than String2.
> Zero
String1 is greater than String2.

Comments

Callers of RtlCompareString must be running at IRQL PASSIVE_LEVEL.

See Also

RtlCompareUnicodeString, RtlEqualString


RtlCompareUnicodeString

RtlCompareUnicodeString compares two Unicode strings.

LONG
  RtlCompareUnicodeString(
    IN PUNICODE_STRING  String1,
    IN PUNICODE_STRING  String2,
    IN BOOLEAN  CaseInSensitive
    );

Parameters

String1
Points to the first string.
String2
Points to the second string.
CaseInSensitive
If TRUE, case should be ignored when doing the comparison.

Include

wdm.h or ntddk.h

Return Value

RtlCompareUnicodeString returns a signed value that gives the results of the comparison:

Zero
String1 equals String2.
< Zero
String1 is less than String2.
> Zero
String1 is greater than String2.

Comments

Callers of RtlCompareUnicodeString must be running at IRQL PASSIVE_LEVEL.

See Also

RtlCompareString, RtlEqualString


RtlConvertLongToLargeInteger

RtlConvertLongToLargeInteger converts the input signed integer to a signed large integer.

LARGE_INTEGER
  RtlConvertLongToLargeInteger(
    IN LONG  SignedInteger
    );

Parameters

SignedInteger
Specifies an integer of type LONG.

Include

wdm.h or ntddk.h

Return Value

RtlConvertLongToLargeInteger returns the large integer result.

Comments

Callers of RtlConvertLongToLargeInteger can be running at any IRQL.


RtlConvertLongToLuid

RtlConvertLongToLuid converts a long integer to a locally unique identifier (LUID), which is used by the system to represent a security privilege.

LUID
  RtlConvertLongToLuid(
    LONG  Long
    );

Parameters

Long
Specifies the long integer to convert.

Include

ntddk.h

Return Value

RtlConvertLongToLuid returns the converted LUID.

Comments

RtlConvertLongToLuid is used to convert a system-defined privilege value to the locally unique identifier (LUID) used by the system to represent that privilege. Drivers typically pass a LUID to SeSinglePrivilegeCheck which is usually called by network transport drivers.

Callers of RtlConvertLongToLuid can be running at any IRQL.

See Also

RtlConvertULongToLuid, RtlEqualLuid, SeSinglePrivilegeCheck, LUID


RtlConvertUlongToLargeInteger

RtlConvertUlongToLargeInteger converts the input unsigned integer to a signed large integer.

LARGE_INTEGER
  RtlConvertUlongToLargeInteger(
    IN ULONG  UnsignedInteger
    );

Parameters

UnsignedInteger
Is a value of type ULONG.

Include

wdm.h or ntddk.h

Return Value

RtlConvertUlongToLargeInteger returns the converted large integer.

Comments

Callers of RtlConvertUlongToLargeInteger can be running at any IRQL.


RtlConvertUlongToLuid

RtlConvertUlongToLuid converts an unsigned long integer to a locally unique identifier (LUID), which is used by the system to represent a security privilege.

LUID
  RtlConvertUlongToLuid(
    ULONG  Ulong
    );

Parameters

Ulong
Specifies the unsigned long integer to convert.

Include

ntddk.h

Return Value

RtlConvertUlongToLuid returns the converted LUID.

Comments

RtlConvertUlongToLuid is used to convert a system-defined privilege value, passed as a ULONG, to a locally unique identifier (LUID) used by the system to represent that privilege. Drivers typically pass a LUID to SeSinglePrivilegeCheck which is usually called by network transport drivers.

Callers of RtlConvertUlongToLuid can be running at any IRQL.

See Also

RtlConvertLongToLuid, RtlEqualLuid, SeSinglePrivilegeCheck, LUID


RtlCopyBytes

RtlCopyBytes copies a given number of bytes from one location to another.

VOID
  RtlCopyBytes(
    IN PVOID  Destination,
    IN CONST VOID  *Source,
    IN SIZE_T  Length
    );

Parameters

Destination
Points to the destination where the bytes are to be copied.
Source
Points to the memory to be copied.
Length
Specifies the number of bytes to be copied.

Include

wdm.h or ntddk.h

Comments

The (Source + Length) can overlap the Destination range passed to RtlCopyBytes.

Callers of RtlCopyBytes can be running at any IRQL if both memory blocks are resident. Otherwise, callers must be running at IRQL<DISPATCH_LEVEL.

See Also

RtlFillMemory, RtlMoveMemory, RtlZeroMemory


RtlCopyMemory

RtlCopyMemory copies the contents of one buffer to another.

VOID
  RtlCopyMemory(
    IN VOID UNALIGNED  *Destination,
    IN CONST VOID UNALIGNED  *Source,
    IN SIZE_T  Length
    );

Parameters

Destination
Points to the destination of the move.
Source
Points to the memory to be copied.
Length
Specifies the number of bytes to be copied.

Include

wdm.h or ntddk.h

Comments

RtlCopyMemory runs faster than RtlMoveMemory. However, the (Source + Length) cannot overlap the Destination range passed in to RtlCopyMemory.

Callers of RtlCopyMemory can be running at any IRQL if both memory blocks are resident. Otherwise, the caller must be running at IRQL < DISPATCH_LEVEL.

See Also

RtlMoveMemory


RtlCopyMemory32

RtlCopyMemory32 copies the contents of one memory buffer to another non-overlapping memory buffer.

VOID
  RtlCopyMemory32 (
    VOID UNALIGNED  *Destination,
    CONST VOID UNALIGNED  *Source,
    ULONG  Length
    );

Parameters

Destination
Pointer to the memory buffer where the data is copied.
Source
Pointer to the memory buffer from which data is copied.
Length
Specifies the number of bytes to copy.

Include

ntddk.h or wdm.h

Comments

RtlCopyMemory32 is the same as RtlCopyMemory, except that it copies at most 32 bits at a time.

Callers of RtlCopyMemory can be running at any IRQL if both memory blocks are resident. Otherwise, the caller must be running at IRQL < DISPATCH_LEVEL.

See Also

RtlCopyMemory, RtlMoveMemory


RtlCopyString

RtlCopyString copies a source string to a destination string.

VOID
  RtlCopyString(
    IN OUT PSTRING  DestinationString,
    IN PSTRING  SourceString  OPTIONAL
    );

Parameters

DestinationString
Points to the destination string buffer.
SourceString
Points to the source string buffer.

Include

ntddk.h

Comments

The DestinationString Length is set to zero if no source string is supplied, but this does not affect the length of the DestinationString buffer. The MaximumLength and Buffer members of the DestinationString are not modified by this routine.

The number of bytes copied from the SourceString is either the length of SourceString or the maximum length of DestinationString, whichever is smaller.

The DestinationString and SourceString buffers must be resident if the caller is running at IRQL >= DISPATCH_LEVEL.

See Also

RtlCopyUnicodeString


RtlCopyUnicodeString

RtlCopyUnicodeString copies a source string to a destination string.

VOID
  RtlCopyUnicodeString(
    IN OUT PUNICODE_STRING  DestinationString,
    IN PUNICODE_STRING  SourceString
    );

Parameters

DestinationString
Points to the destination string buffer.
SourceString
Points to the source string buffer.

Include

wdm.h or ntddk.h

Comments

If the source string is longer than the destination string, this routine copies bytes from the source to the end of the destination buffer, effectively truncating the copied source string.

The DestinationString and SourceString buffers must be resident if the caller is running at IRQL >= DISPATCH_LEVEL.

See Also

RtlCopyString


RtlCreateRegistryKey

RtlCreateRegistryKey adds a key object in the registry along a given relative path.

NTSTATUS
  RtlCreateRegistryKey(
    IN ULONG  RelativeTo,
    IN PWSTR  Path
    );

Parameters

RelativeTo
Specifies whether Path is an absolute registry path or is relative to a predefined key path as one of the following:
Value Meaning
RTL_REGISTRY_ABSOLUTE
Path is an absolute registry path.
RTL_REGISTRY_SERVICES
Path is relative to \Registry\Machine\System\CurrentControlSet\Services.
RTL_REGISTRY_CONTROL
Path is relative to \Registry\Machine\System\CurrentControlSet\Control.
RTL_REGISTRY_WINDOWS_NT
Path is relative to \Registry\Machine\Software\Microsoft\
Windows NT\CurrentVersion.
RTL_REGISTRY_DEVICEMAP
Path is relative to \Registry\Machine\Hardware\DeviceMap.
RTL_REGISTRY_USER
Path is relative to \Registry\User\CurrentUser.
RTL_REGISTRY_OPTIONAL
Specifies that the key referenced by this parameter and the Path parameter are optional.
RTL_REGISTRY_HANDLE
Specifies that the Path parameter is actually a registry handle to use. This value is optional.

Path
Specifies the registry path according to the RelativeTo value. If RTL_REGISTRY_HANDLE is set, Path is a handle to be used directly.

Include

ntddk.h

Return Value

RtlCreateRegistryKey returns STATUS_SUCCESS if the key is created.

Comments

Callers of RtlCreateRegistryKey must be running at IRQL PASSIVE_LEVEL.

See Also

RtlCheckRegistryKey, RtlDeleteRegistryValue, RtlQueryRegistryValues, RtlWriteRegistryValue, ZwEnumerateKey, ZwOpenKey


RtlCreateSecurityDescriptor

RtlCreateSecurityDescriptor initializes a new absolute-format security descriptor. On return, the security descriptor is initialized with no system ACL, no discretionary ACL, no owner, no primary group, and all control flags set to zero.

NTSTATUS
  RtlCreateSecurityDescriptor(
    IN OUT PSECURITY_DESCRIPTOR  SecurityDescriptor,
    IN ULONG  Revision
    );

Parameters

SecurityDescriptor
Points to the buffer for the SECURITY_DESCRIPTOR to be initialized.
Revision
Specifies the revision level to assign to the security descriptor.

Include

ntddk.h

Return Value

RtlCreateSecurityDescriptor can return one of the following:

STATUS_SUCCESS
The call completed successfully.
STATUS_UNKNOWN_REVISION
The given Revision is not supported.

Comments

In effect, a successful call to this routine initializes a security descriptor without security constraints.

Callers of RtlCreateSecurityDescriptor must be running at IRQL PASSIVE_LEVEL.

See Also

RtlLengthSecurityDescriptor, RtlSetDaclSecurityDescriptor, RtlValidSecurityDescriptor, SECURITY_DESCRIPTOR


RtlDeleteRegistryValue

RtlDeleteRegistryValue removes the specified entry name and the associated values from the registry along the given relative path.

NTSTATUS
  RtlDeleteRegistryValue(
    IN ULONG  RelativeTo,
    IN PCWSTR  Path,
    IN PCWSTR  ValueName
    );

Parameters

RelativeTo
Specifies whether Path is an absolute registry path or is relative to a predefined key path as one of the following:
Value Meaning
RTL_REGISTRY_ABSOLUTE
Path is an absolute registry path.
RTL_REGISTRY_SERVICES
Path is relative to \Registry\Machine\System\CurrentControlSet\Services.
RTL_REGISTRY_CONTROL
Path is relative to \Registry\Machine\System\CurrentControlSet\Control.
RTL_REGISTRY_WINDOWS_NT
Path is relative to \Registry\Machine\Software\Microsoft\
Windows NT\CurrentVersion.
RTL_REGISTRY_DEVICEMAP
Path is relative to \Registry\Machine\Hardware\DeviceMap.
RTL_REGISTRY_USER
Path is relative to \Registry\User\CurrentUser.
RTL_REGISTRY_OPTIONAL
Specifies that the key referenced by this parameter and the Path parameter are optional.
RTL_REGISTRY_HANDLE
Specifies that the Path parameter is actually a registry handle to use. This value is optional.

Path
Specifies the registry path according to the RelativeTo value. If RTL_REGISTRY_HANDLE is set, Path is a handle to be used directly.
ValueName
Points to the value name to be removed from the registry.

Include

wdm.h or ntddk.h

Return Value

RtlDeleteRegistryValue returns STATUS_SUCCESS if the value entry was deleted.

Callers of RtlDeleteRegistryValue must be running at IRQL = PASSIVE_LEVEL.

Note that if RelativeTo is set to RTL_REGISTRY_HANDLE, the following occurs:

  • On Windows 98/Me and Windows NT 4.0, the routine closes the specified handle before returning.
  • On Windows 2000 and later versions of the NT-based operating system, the routine leaves the handle open.

See Also

RtlCheckRegistryKey, RtlQueryRegistryValues, RtlWriteRegistryValue, ZwEnumerateKey, ZwOpenKey


RtlEnlargedIntegerMultiply

RtlEnlargedIntegerMultiply is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

LARGE_INTEGER
  RtlEnlargedIntegerMultiply(
    IN LONG  Multiplicand,
    IN LONG  Multiplier
    );


RtlEnlargedUnsignedDivide

RtlEnlargedUnsignedDivide is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

ULONG
  RtlEnlargedUnsignedDivide(
    IN ULARGE_INTEGER  Dividend,
    IN ULONG  Divisor,
    IN OUT PULONG  Remainder
    );


RtlEnlargedUnsignedMultiply

RtlEnlargedUnsignedMultiply is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

LARGE_INTEGER
  RtlEnlargedUnsignedMultiply(
    IN ULONG  Multiplicand,
    IN ULONG  Multiplier
    );


RtlEqualLuid

RtlEqualLuid compares two LUIDs.

BOOLEAN
  RtlEqualLuid(
    LUID  Luid1,
    LUID  Luid2
    );

Parameters

Luid1
Points to a LUID to compare.
Luid2
Points to a LUID to compare.

Include

ntddk.h

Return Value

RtlEqualLuid returns TRUE if Luid1 and Luid2 are equivalent.

Comments

Callers of RtlEqualLuid can be running at any IRQL.

See Also

RtlConvertLongToLuid, RtlConvertULongToLuid, SeSinglePrivilegeCheck, LUID


RtlEqualMemory

RtlEqualMemory compares two blocks of memory to determine whether the specified number of bytes are identical.

ULONG
  RtlEqualMemory(
    CONST VOID  *Source1,
    CONST VOID  *Source2,
    SIZE_T  Length
    );

Parameters

Source1
Points to a caller-allocated block of memory to compare.
Source2
Points to a caller-allocated block of memory that is compared to the block of memory to which Source1 points.
Length
Specifies the number of bytes to be compared.

Include

wdm.h or ntddk.h

Return Value

RtlEqualMemory returns an unsigned value of one if Source1 and Source2 are equivalent; otherwise it returns zero.

Comments

RtlEqualMemory begins the comparison with byte zero of each block.

Callers of RtlEqualMemory can be running at any IRQL if both blocks of memory are resident.

See Also

RtlCompareMemory


RtlEqualString

RtlEqualString compares two counted strings to determine whether they are equal.

BOOLEAN
  RtlEqualString(
    IN PSTRING  String1,
    IN PSTRING  String2,
    IN BOOLEAN  CaseInSensitive
    );

Parameters

String1
Points to the first string.
String2
Points to the second string.
CaseInSensitive
If TRUE, case should be ignored when doing the comparison.

Include

ntddk.h

Return Value

RtlEqualString returns TRUE if the two strings are equal, otherwise it returns FALSE.

Comments

Callers of RtlEqualString must be running at IRQL PASSIVE_LEVEL.

See Also

RtlEqualUnicodeString


RtlEqualUnicodeString

RtlEqualUnicodeString compares two Unicode strings to determine whether they are equal.

BOOLEAN
  RtlEqualUnicodeString(
    IN CONST UNICODE_STRING  *String1,
    IN CONST UNICODE_STRING  *String2,
    IN BOOLEAN  CaseInSensitive
    );

Parameters

String1
Points to the first Unicode string.
String2
Points to the second Unicode string.
CaseInSensitive
If TRUE, case should be ignored when doing the comparison.

Include

wdm.h or ntddk.h

Return Value

RtlEqualUnicodeString returns TRUE if the two Unicode strings are equal.

Comments

Callers of RtlEqualUnicodeString must be running at IRQL PASSIVE_LEVEL.

See Also

RtlEqualString


RtlExtendedIntegerMultiply

RtlExtendedIntegerMultiply is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

LARGE_INTEGER
  RtlExtendedIntegerMultiply(
    IN LARGE_INTEGER  Multiplicand,
    IN LONG  Multiplier
    );


RtlExtendedLargeIntegerDivide

RtlExtendedLargeIntegerDivide is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

LARGE_INTEGER
  RtlExtendedLargeIntegerDivide(
    IN LARGE_INTEGER  Dividend,
    IN ULONG  Divisor,
    IN OUT PULONG  Remainder
    );


RtlExtendedMagicDivide

RtlExtendedMagicDivide is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

LARGE_INTEGER
  RtlExtendedMagicDivide(
    IN LARGE_INTEGER  Dividend,
    IN LARGE_INTEGER  MagicDivisor,
    IN CCHAR  ShiftCount
    );


RtlFillBytes

RtlFillBytes fills a caller-supplied buffer with the given unsigned character and is obsolete. For better performance, use RtlFillMemory.

VOID
  RtlFillBytes(
    PVOID  Destination,
    SIZE_T  Length,
    UCHAR  Fill
    );


RtlFillMemory

RtlFillMemory fills a caller-supplied buffer with the given character.

VOID
  RtlFillMemory(
    IN VOID UNALIGNED  *Destination,
    IN SIZE_T  Length,
    IN UCHAR  Fill
    );

Parameters

Destination
Points to the memory to be filled.
Length
Specifies the number of bytes to be filled.
Fill
Specifies the value to fill the memory.

Include

wdm.h or ntddk.h

Comments

RtlFillMemory is not supported on Windows 98 or Windows ME.

Callers of RtlFillMemory can be running at any IRQL, provided that the Destination buffer is resident.

See Also

RtlZeroMemory


RtlFindClearBits

RtlFindClearBits searches for a range of clear bits of a requested size within a bitmap.

ULONG
  RtlFindClearBits(
    IN PRTL_BITMAP  BitMapHeader,
    IN ULONG  NumberToFind,
    IN ULONG  HintIndex
    );

Parameters

BitMapHeader
Points to an initialized bitmap header for the caller's bitmap variable.
NumberToFind
Specifies how many contiguous clear bits will satisfy this request.
HintIndex
Specifies a zero-based bit position around which to start looking for a clear bit range of the given size.

Include

ntddk.h

Return Value

RtlFindClearBits either returns the zero-based starting bit index for a clear bit range of at least the requested size, or it returns 0xFFFFFFFF if it cannot find such a range within the given bitmap variable.

Comments

For a successful call, the returned bit position is not necessarily equivalent to the given HintIndex. If necessary, RtlFindClearBits searches the whole bitmap to locate a clear bit range of the requested size. However, it starts searching for the requested range near HintIndex, so callers can find such a range more quickly when they can supply appropriate hints about where to start looking.

Callers of RtlFindClearBits must be running at IRQL < DISPATCH_LEVEL if the memory containing the bitmap variable or at BitMapHeader is pageable. Otherwise, RtlFindClearBits can be called at any IRQL.

See Also

RtlAreBitsClear, RtlFindClearBitsAndSet, RtlFindFirstRunClear, RtlFindLongestRunClear, RtlInitializeBitMap, RtlNumberOfClearBits, RtlFindSetBits


RtlFindClearBitsAndSet

RtlFindClearBitsAndSet searches for a range of clear bits of a requested size within a bitmap and sets all bits in the range when it has been located.

ULONG
  RtlFindClearBitsAndSet(
    IN PRTL_BITMAP  BitMapHeader,
    IN ULONG  NumberToFind,
    IN ULONG  HintIndex
    );

Parameters

BitMapHeader
Points to an initialized bitmap header for the caller's bitmap variable.
NumberToFind
Specifies how many contiguous clear bits will satisfy this request.
HintIndex
Specifies a zero-based bit position around which to start looking for a clear bit range of the given size.

Include

ntddk.h

Return Value

RtlFindClearBitsAndSet either returns the zero-based starting bit index for a clear bit range of the requested size that it set, or it returns 0xFFFFFFFF if it cannot find such a range within the given bitmap variable.

Comments

For a successful call, the returned bit position is not necessarily equivalent to the given HintIndex. If necessary, RtlFindClearBitsAndSet searches the whole bitmap to locate a clear bit range of the requested size. However, it starts searching for the requested range near HintIndex, so callers can have such a range reset more quickly when they can supply appropriate hints about where to start looking.

Callers of RtlFindClearBitsAndSet must be running at IRQL < DISPATCH_LEVEL if the memory containing the bitmap variable or at BitMapHeader is pageable. Otherwise, RtlFindClearBitsAndSet can be called at any IRQL.

See Also

RtlAreBitsClear, RtlFindClearBits, RtlFindClearRuns, RtlFindFirstRunClear, RtlFindLastBackwardRunClear, RtlFindLongestRunClear, RtlFindNextForwardRunClear, RtlInitializeBitMap, RtlNumberOfClearBits, RtlSetAllBits, RtlSetBits


RtlFindClearRuns

RtlFindClearRuns finds the specified number of runs of clear bits within a given bitmap variable.

ULONG
  RtlFindClearRuns(
    IN PRTL_BITMAP  BitMapHeader,
    OUT PRTL_BITMAP_RUN  RunArray,
    IN ULONG  SizeOfRunArray,
    IN BOOLEAN  LocateLongestRuns
    );

Parameters

BitMapHeader
Points to an initialized bitmap header for the caller's bitmap variable.
RunArray
Points to the first element in a caller-allocated array for the bit position and length of each clear run found in the given bitmap variable.
SizeOfRunArray
Specifies the maximum number of clear runs to satisfy this request.
LocateLongestRuns
If TRUE, specifies that the routine is to search the entire bitmap for the longest clear runs it can find. Otherwise, the routine stops searching when it has found the number of clear runs specified by SizeOfRunArray.

Include

ntddk.h

Return Value

RtlFindClearRuns returns the number of clear runs found.

Comments

If LocateLongestRuns is TRUE, the clear runs indicated at RunArray are sorted from longest to shortest. A clear run can consist of a single bit.

Callers of RtlFindClearRuns must be running at IRQL < DISPATCH_LEVEL if the memory containing the bitmap variable or at BitMapHeader is pageable. Otherwise, RtlFindClearRuns can be called at any IRQL.

See Also

RtlAreBitsClear, RtlFindClearBits, RtlFindLongestRunClear, RtlFindFirstRunClear, RtlFindNextForwardRunClear, RtlFindLastBackwardRunClear, RtlInitializeBitMap


RtlFindFirstRunClear

RtlFindFirstRunClear searches for the initial contiguous range of clear bits within a given bitmap variable.

ULONG
  RtlFindFirstRunClear(
    IN PRTL_BITMAP  BitMapHeader,
    OUT PULONG  StartingIndex
    );

Parameters

BitMapHeader
Points to an initialized bitmap header for the caller's bitmap variable.
StartingIndex
Points to a variable in which the starting index of the initial clear run in the bitmap is returned. This is a zero-based value indicating the bit position of the first clear bit in the returned range. Its value is meaningless if RtlFindFirstRunClear cannot find a run of clear bits.

Include

ntddk.h

Return Value

RtlFindFirstRunClear returns either the number of bits in the run beginning at StartingIndex or zero if it cannot find a run of clear bits within the bitmap.

Comments

RtlFindFirstRunClear sets StartingIndex to 0xFFFFFFFF if it cannot find a contiguous range of clear bits within the given bitmap variable. A returned run can have a single clear bit. That is, once a clear bit is found, RtlFindFirstRunClear continues searching until it finds the next set bit and, then, returns the number of clear bits in the run it found.

Callers of RtlFindFirstRunClear must be running at IRQL < DISPATCH_LEVEL if the memory containing the bitmap variable or at BitMapHeader is pageable. Otherwise, RtlFindFirstRunClear can be called at any IRQL.

See Also

RtlAreBitsClear, RtlFindClearBits, RtlFindClearRuns, RtlFindFirstRunClear, RtlFindLastBackwardRunClear, RtlFindLongestRunClear, RtlFindNextForwardRunClear, RtlSetBits, RtlInitializeBitMap, RtlNumberOfClearBits


RtlFindLastBackwardRunClear

RtlFindLastBackwardRunClear searches a given bitmap variable for the preceding clear run of bits, starting from the specified index position.

ULONG
  RtlFindLastBackwardRunClear(
    IN PRTL_BITMAP  BitMapHeader,
    IN ULONG  FromIndex,
    OUT PULONG  StartingRunIndex
    );

Parameters

BitMapHeader
Points to an initialized bitmap header for the caller's bitmap variable.
FromIndex
Specifies a zero-based bit position at which to start looking for a clear run of bits.
StartingRunIndex
Points to a variable in which the starting index of the clear run found in the bitmap is returned. This is a zero-based value indicating the bit position of the first clear bit in the run preceding the given FromIndex. Its value is meaningless if RtlFindLastBackwardRunClear cannot find a run of clear bits.

Include

ntddk.h

Return Value

RtlFindLastBackwardRunClear returns the number of bits in the run beginning at StartingRunIndex or zero if it cannot find a run of clear bits preceding FromIndex in the bitmap.

Comments

Callers of RtlFindLastBackwardRunClear must be running at IRQL < DISPATCH_LEVEL.

See Also

RtlAreBitsClear, RtlFindClearBits, RtlFindClearRuns, RtlFindFirstRunClear, RtlFindLastBackwardRunClear, RtlFindLongestRunClear, RtlFindNextFowardRunClear, RtlInitializeBitMap


RtlFindLeastSignificantBit

RtlFindLeastSignificantBit returns the zero-based position of the least significant non-zero bit in its parameter.

CCHAR
  RtlFindLeastSignificantBit(
    IN ULONGLONG  Set
    );

Parameters

Set
The 64-bit value to be searched for its least significant non-zero bit.

Include

ntddk.h

Return Value

The zero-based bit position of the least significant non-zero bit, or -1 if every bit is zero.

See Also

RtlFindMostSignificantBit


RtlFindLongestRunClear

RtlFindLongestRunClear searches for the largest contiguous range of clear bits within a given bitmap variable.

ULONG
  RtlFindLongestRunClear(
    IN PRTL_BITMAP  BitMapHeader,
    OUT PULONG  StartingIndex
    );

Parameters

BitMapHeader
Points to an initialized bitmap header for the caller's bitmap variable.
StartingIndex
Points to a variable in which the starting index of the longest clear run in the bitmap is returned. This is a zero-based value indicating the bit position of the first clear bit in the returned range.

Include

ntddk.h

Return Value

RtlFindLongestRunClear returns either the number of bits in the run beginning at StartingIndex or zero if it it cannot find a run of clear bits within the bitmap.

Comments

RtlFindLongestRunClear sets StartingIndex to 0xFFFFFFFF if it cannot find a contiguous range of clear bits within the given bitmap variable. A returned run can have a single clear bit.

Callers of RtlFindLongestRunClear must be running at IRQL < DISPATCH_LEVEL if the memory containing the bitmap variable or at BitMapHeader is pageable. Otherwise, RtlFindLongestRunClear can be called at any IRQL.

See Also

RtlAreBitsClear, RtlFindClearBits, RtlFindClearRuns, RtlFindFirstRunClear, RtlFindLastBackwardRunClear, RtlFindLongestRunClear, RtlFindNextForwardRunClear, RtlSetBits, RtlInitializeBitMap, RtlNumberOfClearBits


RtlFindMostSignificantBit

RtlFindMostSignificantBit returns the zero-based position of the most significant non-zero bit in its parameter.

CCHAR
  RtlFindMostSignificantBit(
    IN ULONGLONG  Set
    );

Parameters

Set
The 64-bit value to be searched for its most significant non-zero bit.

Include

ntddk.h

Return Value

The zero-based bit position of the most significant non-zero bit, or -1 if every bit is zero.

See Also

RtlFindLeastSignificantBit


RtlFindNextForwardRunClear

RtlFindNextForwardRunClear searches a given bitmap variable for the next clear run of bits, starting from the specified index position.

ULONG
  RtlFindNextForwardRunClear(
    IN PRTL_BITMAP  BitMapHeader,
    IN ULONG  FromIndex,
    OUT PULONG  StartingRunIndex
    );

Parameters

BitMapHeader
Points to an initialized bitmap header for the caller's bitmap variable.
FromIndex
Specifies a zero-based bit position at which to start looking for a clear run of bits.
StartingRunIndex
Points to a variable in which the starting index of the clear run found in the bitmap is returned. This is a zero-based value indicating the bit position of the first clear bit in the run. Its value is meaningless if RtlFindNextForwardRunClear cannot find a run of clear bits.

Include

ntddk.h

Return Value

RtlFindNextFowardRunClear returns either the number of bits in the run beginning at StartingRunIndex or zero if it cannot find a run of clear bits following FromIndex in the bitmap.

Comments

Callers of RtlFindNextForwardRunClear must be running at IRQL < DISPATCH_LEVEL.

See Also

RtlAreBitsClear, RtlFindClearBits, RtlFindClearRuns, RtlFindFirstRunClear, RtlFindLastBackwardRunClear, RtlFindLongestRunClear, RtlInitializeBitMap


RtlFindSetBits

RtlFindSetBits searches for a range of set bits of a requested size within a bitmap.

ULONG
  RtlFindSetBits(
    IN PRTL_BITMAP  BitMapHeader,
    IN ULONG  NumberToFind,
    IN ULONG  HintIndex
    );

Parameters

BitMapHeader
Points to an initialized bitmap header for the caller's bitmap variable.
NumberToFind
Specifies how many contiguous set bits will satisfy this request.
HintIndex
Specifies a zero-based bit position around which to start looking for a set bit range of the given size.

Include

ntddk.h

Return Value

RtlFindSetBits either returns the zero-based starting bit index for a set bit range of the requested size, or it returns 0xFFFFFFFF if it cannot find such a range within the given bitmap variable.

Comments

For a successful call, the returned bit position is not necessarily equivalent to the given HintIndex. If necessary, RtlFindSetBits searches the whole bitmap to locate a set bit range of the requested size. However, it starts searching for the requested range near HintIndex, so callers can find such a range more quickly when they can supply appropriate hints about where to start looking.

Callers of RtlFindSetBits must be running at IRQL < DISPATCH_LEVEL if the memory containing the bitmap variable or at BitMapHeader is pageable. Otherwise, RtlFindSetBits can be called at any IRQL.

See Also

RtlAreBitsSet, RtlClearBits, RtlFindClearBits, RtlFindSetBitsAndClear, RtlInitializeBitMap, RtlNumberOfSetBits


RtlFindSetBitsAndClear

RtlFindSetBitsAndClear searches for a range of set bits of a requested size within a bitmap and clears all bits in the range when it has been located.

ULONG
  RtlFindSetBitsAndClear(
    IN PRTL_BITMAP  BitMapHeader,
    IN ULONG  NumberToFind,
    IN ULONG  HintIndex
    );

Parameters

BitMapHeader
Points to an initialized bitmap header for the caller's bitmap variable.
NumberToFind
Specifies how many contiguous set bits will satisfy this request.
HintIndex
Specifies a zero-based bit position around which to start looking for a set bit range of the given size.

Include

ntddk.h

Return Value

RtlFindSetBitsAndClear either returns the zero-based starting bit index for a set bit range of the requested size that it cleared, or it returns 0xFFFFFFFF if it cannot find such a range within the given bitmap variable.

Comments

For a successful call, the returned bit position is not necessarily equivalent to the given HintIndex. If necessary, RtlFindSetBitsAndClear searches the whole bitmap to locate a set bit range of the requested size. However, it starts searching for the requested range near HintIndex, so callers can clear such a range more quickly when they can supply appropriate hints about where to start looking.

Callers of RtlFindSetBitsAndClear must be running at IRQL < DISPATCH_LEVEL if the memory containing the bitmap variable or at BitMapHeader is pageable. Otherwise, RtlFindSetBitsAndClear can be called at any IRQL.

See Also

RtlAreBitsSet, RtlClearAllBits, RtlClearBits, RtlFindSetBits, RtlInitializeBitMap, RtlNumberOfSetBits


RtlFreeAnsiString

RtlFreeAnsiString releases storage that was allocated by RtlUnicodeStringToAnsiString.

VOID
  RtlFreeAnsiString(
    IN PANSI_STRING  AnsiString
    );

Parameters

AnsiString
Points to the ANSI string buffer previously allocated by RtlUnicodeStringToAnsiString.

Include

wdm.h or ntddk.h

Comments

This routine does not release the Unicode string buffer passed to RtlUnicodeStringToAnsiString.

Callers of RtlFreeAnsiString must be running at IRQL PASSIVE_LEVEL.

See Also

RtlUnicodeStringToAnsiString


RtlFreeUnicodeString

RtlFreeUnicodeString releases storage that was allocated by RtlAnsiStringToUnicodeString or RtlUpcaseUnicodeString.

VOID
  RtlFreeUnicodeString(
    IN PUNICODE_STRING  UnicodeString
    );

Parameters

UnicodeString
Points to the Unicode string buffer previously allocated by RtlAnsiStringToUnicodeString or RtlUpcaseUnicodeString.

Include

wdm.h or ntddk.h

Comments

This routine does not release the ANSI string buffer passed to RtlAnsiStringToUnicodeString.

Callers of RtlFreeUnicodeString must be running at IRQL PASSIVE_LEVEL.

See Also

RtlAnsiStringToUnicodeString, RtlUpcaseUnicodeString


RtlGetVersion

RtlGetVersion returns version information about the currently running operating system.

NTSTATUS
  RtlGetVersion(
    IN OUT PRTL_OSVERSIONINFOW  lpVersionInformation
    );

Parameters

lpVersionInformation
Pointer to either a RTL_OSVERSIONINFOW structure or a RTL_OSVERSIONINFOEXW structure that contains the version information about the currently running operating system. A caller specifies which input structure is used by setting the dwOSVersionInfoSize member of the structure to the size in bytes of the structure that is used.

Include

ntddk.h

Return Value

RtlGetVersion returns STATUS_SUCCESS.

Comments

This routine is supported on Windows XP and later operating system versions.

RtlGetVersion is the kernel-mode equivalent of the user-mode GetVersionEx function in the Microsoft® Platform SDK. See the example in the Platform SDK that shows how to get the system version.

When using RtlGetVersion to determine whether a particular version of the operating system is running, a caller should check for version numbers that are greater than or equal to the required version number. This ensures that a version test succeeds for later versions of the operating system.

Because operating system features can be added in a redistributable DLL, checking only the major and minor version numbers is not the most reliable way to verify the presence of a specific system feature. A driver should use RtlVerifyVersionInfo to test for the presence of a specific system feature.

See Also

RTL_OSVERSIONINFOW, RTL_OSVERSIONINFOEXW, RtlVerifyVersionInfo


RtlGUIDFromString

RtlGUIDFromString converts the given Unicode string to a GUID in binary format.

NTSTATUS
  RtlGUIDFromString(
    IN PUNICODE_STRING  GuidString,
    OUT GUID  *Guid
    );

Parameters

GuidString
Points to the buffered Unicode string to be converted to a GUID.
Guid
Points to a caller-supplied variable in which the GUID is returned.

Include

wdm.h or ntddk.h

Return Value

If the conversion succeeds, RtlGUIDFromString returns STATUS_SUCCESS. Otherwise, no conversion was done.

Comments

Callers of RtlGUIDFromString must be running at IRQL PASSIVE_LEVEL.

See Also

RtlStringFromGUID


RtlInitAnsiString

RtlInitAnsiString initializes a counted ANSI string.

VOID
  RtlInitAnsiString(
    IN OUT PANSI_STRING  DestinationString,
    IN PCSZ  SourceString
    );

Parameters

DestinationString
Points to the buffer for a counted ANSI string to be initialized.
SourceString
Points to a zero-terminated string with which to initialize the counted string.

Include

wdm.h or ntddk.h

Comments

The DestinationString is initialized to point to the SourceString. The length and maximum length for the DestinationString are initialized to the length of the SourceString. If SourceString is NULL, the lengths are zero.

Callers of RtlInitAnsiString can be running at IRQL <= DISPATCH_LEVEL if the DestinationString buffer is nonpageable. Usually, callers run at IRQL PASSIVE_LEVEL because most other Rtl..String routines cannot be called at raised IRQL.

See Also

RtlInitString, RtlInitUnicodeString


RtlInitializeBitMap

RtlInitializeBitMap initializes the header of a bitmap variable.

VOID
  RtlInitializeBitMap(
    IN PRTL_BITMAP  BitMapHeader,
    IN PULONG  BitMapBuffer,
    IN ULONG  SizeOfBitMap
    );

Parameters

BitMapHeader
Points to the bitmap header for which the caller provides storage, which must be at least sizeof(RTL_BITMAP).
BitMapBuffer
Points to caller-allocated memory for the bitmap itself. The base address of this buffer must be ULONG-aligned.
SizeOfBitMap
Specifies the number of bits in the bitmap. This value must be an integral multiple of the number of bits in a ULONG.

Include

ntddk.h

Comments

A driver can use a bitmap variable as an economical way to keep track of a set of reusable items. For example, file systems use a bitmap variable to track which clusters/sectors on a disk have already been allocated to hold file data. The system-supplied SCSI port driver uses a bitmap variable to track which queue tags have been assigned to SRBs.

RtlInitializeBitMap must be called before any other Rtl Xxx that operates on a bitmap variable. The BitMapHeader pointer is an input parameter in all subsequent calls to the Rtl Xxx that operate on the caller's bitmap variable at BitMapBuffer. The caller is responsible for synchronizing access to the bitmap variable.

If an already initialized bitmap header is reinitialized, the subsequent call to RtlInitializeBitMap has no effect on the current contents of the associated bitmap variable.

Callers of RtlInitializeBitMap must be running at IRQL < DISPATCH_LEVEL. Callers of Rtl Xxx that operate on an initialized bitmap variable must be running at IRQL < DISPATCH_LEVEL if the memory containing the bitmap variable or at BitmapHeader is pageable; otherwise, callers can be running at any IRQL.

See Also

ExInitializeFastMutex, RtlAreBitsClear, RtlAreBitsSet, RtlCheckBit, RtlClearAllBits, RtlClearBits, RtlFindClearBits, RtlFindClearBitsAndSet, RtlFindClearRuns, RtlFindFirstRunClear, RtlFindLastBackwardRunClear, RtlFindLongestRunClear, RtlFindNextForwardRunClear, RtlFindSetBits, RtlFindSetBitsAndClear, RtlNumberOfClearBits, RtlNumberOfSetBits, RtlSetAllBits, RtlSetBits


RtlInitString

RtlInitString initializes a counted string.

VOID
  RtlInitString(
    IN OUT PSTRING  DestinationString,
    IN PCSZ  SourceString
    );

Parameters

DestinationString
Points to the buffer for a counted string to be initialized.
SourceString
Points to a NUL-terminated string value with which to initialize the counted string.

Include

wdm.h or ntddk.h

Comments

DestinationString is initialized to point to SourceString and the length and maximum length for the DestinationString are initialized to the length of SourceString. The lengths are is zero if SourceString is NULL.

Callers of RtlInitString can be running at IRQL <= DISPATCH_LEVEL if the DestinationString buffer is nonpageable. Usually, callers run at IRQL PASSIVE_LEVEL because most other Rtl..String routines cannot be called at raised IRQL.

See Also

RtlInitAnsiString, RtlInitUnicodeString


RtlInitUnicodeString

RtlInitUnicodeString initializes a counted Unicode string.

VOID
  RtlInitUnicodeString(
    IN OUT PUNICODE_STRING  DestinationString,
    IN PCWSTR  SourceString
    );

Parameters

DestinationString
Points to the buffer for a counted Unicode string to be initialized.
SourceString
Points to a zero-terminated Unicode string with which to initialize the counted string.

Include

wdm.h or ntddk.h

Comments

DestinationString is initialized to point to SourceString. The length and maximum length for DestinationString are initialized to the length of SourceString. If SourceString is NULL, the length is zero.

Callers of RtlInitUnicodeString can be running at IRQL <= DISPATCH_LEVEL if the DestinationString buffer is nonpageable. Usually, callers run at IRQL PASSIVE_LEVEL because most other Rtl..String routines cannot be called at raised IRQL.

See Also

RtlInitAnsiString, RtlInitString


RtlInt64ToUnicodeString

RtlInt64ToUnicodeString converts a specified unsigned 64-bit integer value to a Unicode string that represents the value in a specified base.

NTSTATUS
  RtlInt64ToUnicodeString (
    IN ULONGLONG  Value,
    IN ULONG  Base OPTIONAL,
    IN OUT PUNICODE_STRING  String
    );

Parameters

Value
Specifies a 64-bit unsigned integer.
Base
Specifies the following base for the conversion:
Value | Base
16 | Hexadecimal
8 | Octal
2 | Binary
0 or 10 | Decimal

String
Pointer to a Unicode string that represents the value of Value. The caller must allocate the Unicode string buffer.

Include

ntddk.h or wdm.h

Return Value

RtlInt64ToUnicodeString returns one of the following values:

STATUS_SUCCESS
STATUS_BUFFER_OVERFLOW
The Unicode string buffer is too small.
STATUS_INVALID_PARAMETER
The specified code base is not valid.

Comments

Callers of RtlInt64ToUnicodeString must be running at IRQL PASSIVE_LEVEL.

See Also

RtlAppendUnicodeStringToString, RtlUnicodeStringToInteger


RtlIntegerToUnicodeString

RtlIntegerToUnicodeString converts an unsigned integer value to a NULL-terminated string of one or more Unicode characters in the specified base.

NTSTATUS
  RtlIntegerToUnicodeString(
    IN ULONG  Value,
    IN ULONG  Base  OPTIONAL,
    IN OUT PUNICODE_STRING  String
    );

Parameters

Value
Identifies an unsigned integer of type ULONG.
Base
Optional. If not zero, this must be 2, 8, 10, or 16, to specify that the returned string should represent the integer as a binary, octal, decimal, or hexadecimal number. If zero, the integer is represented as a decimal number.-
String
Points to a buffer large enough to contain the Unicode string.

Include

wdm.h or ntddk.h

Return Value

If RtlIntegerToUnicodeString succeeds, it returns STATUS_SUCCESS. Otherwise, it can return STATUS_INVALID_PARAMETER if Base is not 0, 2, 8, 10, or 16, or STATUS_BUFFER_OVERFLOW if an internal buffer overflow occurs.

Comments

Callers of RtlIntegerToUnicodeString must be running at IRQL = PASSIVE_LEVEL.

See Also

RtlUnicodeStringToInteger, RtlAppendUnicodeStringToString


RtlIntPtrToUnicodeString

RtlIntPtrToUnicodeString converts a specified PLONG value to a Unicode string that represents the pointer value in a specified base.

NTSTATUS
  RtlIntPtrToUnicodeString (
    PLONG  Value,
    ULONG  Base  OPTIONAL,
    PUNICODE_STRING  String
    );

Parameters

Value
Specifies an integer pointer.
Base
Specifies the following base for the conversion:
Value | Base
16 | Hexadecimal
8 | Octal
2 | Binary
0 or 10 | Decimal

String
Pointer to a Unicode string that represents the value of Value. The caller must allocate the Unicode string buffer.

Include

ntddk.h or wdm.h

Comments

Callers of RtlIntPtrToUnicodeString must be running at IRQL PASSIVE_LEVEL.

See Also

RtlAppendUnicodeStringToString, RtlIntegerToUnicodeString, RtlUnicodeStringToInteger


RtlIsZeroLuid

The RtlIsZeroLuid routine determines if the specified LUID is the zero LUID.

BOOLEAN
  RtlIsZeroLuid(
    PLUID  L1
    );

Parameters

L1
Specifies the LUID to check.

Return Value

TRUE if L1 is zero, false otherwise.

See Also

LUID


RtlLargeIntegerAdd

RtlLargeIntegerAdd is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

LARGE_INTEGER
  RtlLargeIntegerAdd(
    IN LARGE_INTEGER  Addend1,
    IN LARGE_INTEGER  Addend2
    );


RtlLargeIntegerAnd

RtlLargeIntegerAnd is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

VOID
  RtlLargeIntegerAnd(
    IN OUT LARGE_INTEGER  Result,
    IN LARGE_INTEGER  Source,
    IN LARGE_INTEGER  Mask
    );


RtlLargeIntegerArithmeticShift

RtlLargeIntegerArithmeticShift is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

LARGE_INTEGER
  RtlLargeIntegerArithmeticShift(
    IN LARGE_INTEGER  LargeInteger,
    IN CCHAR  ShiftCount
    );


RtlLargeIntegerDivide

RtlLargeIntegerDivide is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

LARGE_INTEGER
  RtlLargeIntegerDivide(
    IN LARGE_INTEGER  Dividend,
    IN LARGE_INTEGER  Divisor,
    IN OUT PLARGE_INTEGER  Remainder
    );


RtlLargeIntegerEqualTo

RtlLargeIntegerEqualTo is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

BOOLEAN
  RtlLargeIntegerEqualTo(
    IN LARGE_INTEGER  Operand1,
    IN LARGE_INTEGER  Operand2
    );


RtlLargeIntegerEqualToZero

RtlLargeIntegerEqualToZero is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

BOOLEAN
  RtlLargeIntegerEqualToZero(
    IN LARGE_INTEGER  Operand
    );


RtlLargeIntegerGreaterOrEqualToZero

RtlLargeIntegerGreaterOrEqualToZero is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

BOOLEAN
  RtlLargeIntegerGreaterOrEqualToZero(
    IN LARGE_INTEGER  Operand
    );


RtlLargeIntegerGreaterThan

RtlLargeIntegerGreaterThan is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

BOOLEAN
  RtlLargeIntegerGreaterThan(
    IN LARGE_INTEGER  Operand1,
    IN LARGE_INTEGER  Operand2
    );


RtlLargeIntegerGreaterThanOrEqualTo

RtlLargeIntegerGreaterThanOrEqualTo is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

BOOLEAN
  RtlLargeIntegerGreaterThanOrEqualTo(
    IN LARGE_INTEGER  Operand1,
    IN LARGE_INTEGER  Operand2
    );


RtlLargeIntegerGreaterThanZero

RtlLargeIntegerGreaterThanZero is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

BOOLEAN
  RtlLargeIntegerGreaterThanZero(
    IN LARGE_INTEGER  Operand
    );


RtlLargeIntegerLessOrEqualToZero

RtlLargeIntegerLessOrEqualToZero is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

BOOLEAN
  RtlLargeIntegerLessOrEqualToZero(
    IN LARGE_INTEGER  Operand
    );


RtlLargeIntegerLessThan

RtlLargeIntegerLessThan is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

BOOLEAN
  RtlLargeIntegerLessThan(
    IN LARGE_INTEGER  Operand1,
    IN LARGE_INTEGER  Operand2
    );


RtlLargeIntegerLessThanOrEqualTo

RtlLargeIntegerLessThanOrEqualTo is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

BOOLEAN
  RtlLargeIntegerLessThanOrEqualTo(
    IN LARGE_INTEGER  Operand1,
    IN LARGE_INTEGER  Operand2
    );


RtlLargeIntegerLessThanZero

RtlLargeIntegerLessThanZero is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

BOOLEAN
  RtlLargeIntegerLessThanZero(
    IN LARGE_INTEGER  Operand
    );


RtlLargeIntegerNegate

RtlLargeIntegerNegate is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

LARGE_INTEGER
  RtlLargeIntegerNegate(
    IN LARGE_INTEGER  Subtrahend
    );


RtlLargeIntegerNotEqualTo

RtlLargeIntegerNotEqualTo is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

BOOLEAN
  RtlLargeIntegerNotEqualTo(
    IN LARGE_INTEGER  Operand1,
    IN LARGE_INTEGER  Operand2
    );


RtlLargeIntegerNotEqualToZero

RtlLargeIntegerNotEqualToZero is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

BOOLEAN
  RtlLargeIntegerNotEqualToZero(
    IN LARGE_INTEGER  Operand
    );


RtlLargeIntegerShiftLeft

RtlLargeIntegerShiftLeft is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

LARGE_INTEGER
  RtlLargeIntegerShiftLeft(
    IN LARGE_INTEGER  LargeInteger,
    IN CCHAR  ShiftCount
    );


RtlLargeIntegerShiftRight

RtlLargeIntegerShiftRight is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

LARGE_INTEGER
  RtlLargeIntegerShiftRight(
    IN LARGE_INTEGER  LargeInteger,
    IN CCHAR  ShiftCount
    );


RtlLargeIntegerSubtract

RtlLargeIntegerSubtract is exported to support existing driver binaries and is obsolete. For better performance, use the compiler support for 64-bit integer operations.

LARGE_INTEGER
  RtlLargeIntegerSubtract(
    IN LARGE_INTEGER  Minuend,
    IN LARGE_INTEGER  Subtrahend
    );


RtlLengthSecurityDescriptor

RtlLLengthSecurityDescriptor returns the size of a given security descriptor.

ULONG
  RtlLengthSecurityDescriptor(
    IN PSECURITY_DESCRIPTOR  SecurityDescriptor
    );

Parameters

SecurityDescriptor
Points to a SECURITY_DESCRIPTOR.

Include

ntddk.h

Return Value

RtlLengthSecurityDescriptor returns the size in bytes of the descriptor.

Comments

Callers of RtlLengthSecurityDescriptor must be running at IRQL = PASSIVE_LEVEL.

See Also

RtlCreateSecurityDescriptor, RtlSetDaclSecurityDescriptor, RtlValidSecurityDescriptor, SECURITY_DESCRIPTOR


RtlMapGenericMask

The RtlMapGenericMask routine determines the nongeneric access rights specified by an ACCESS_MASK.

NTSYSAPI
VOID
NTAPI
  RtlMapGenericMask(
    PACCESS_MASK  AccessMask,
    PGENERIC_MAPPING  GenericMapping
    );

Parameters

AccessMask
Pointer to an ACCESS_MASK variable. The routine updates this to contain only those access rights that are not also granted by any GENERIC_XXX access rights originally specified the variable. The routine also clears any GENERIC_XXX bits that are set.
GenericMapping
Pointer to a GENERIC_MAPPING structure that describes the specific access rights that correspond to each generic access right.

Return Value

None

See Also

GENERIC_MAPPING


RtlMoveMemory

RtlMoveMemory moves memory either forward or backward, aligned or unaligned, in 4-byte blocks, followed by any remaining bytes.

VOID
  RtlMoveMemory(
    IN VOID UNALIGNED  *Destination,
    IN CONST VOID UNALIGNED  *Source,
    IN SIZE_T  Length
    );

Parameters

Destination
Points to the destination of the move.
Source
Points to the memory to be copied.
Length
Specifies the number of bytes to be copied.

Include

wdm.h or ntddk.h

Comments

The (Source + Length) can overlap the Destination range passed in to RtlMoveMemory.

Callers of RtlMoveMemory can be running at any IRQL if both memory blocks are resident. Otherwise, the caller must be running at IRQL < DISPATCH_LEVEL.

See Also

RtlCopyMemory


RtlNumberOfClearBits

RtlNumberOfClearBits returns a count of the clear bits in a given bitmap variable.

ULONG
  RtlNumberOfClearBits(
    IN PRTL_BITMAP  BitMapHeader
    );

Parameters

BitMapHeader
Points to an initialized bitmap header for the caller's bitmap variable.

Include

ntddk.h

Return Value

RtlNumberOfClearBits returns how many bits currently are clear.

Comments

Callers of RtlNumberOfClearBits must be running at IRQL < DISPATCH_LEVEL if the memory containing the bitmap variable or at BitMapHeader is pageable. Otherwise, RtlNumberOfClearBits can be called at any IRQL.

See Also

RtlFindClearBits, RtlFindClearRuns, RtlFindFirstRunClear, RtlFindLastBackwardRunClear, RtlFindLongestRunClear, RtlFindNextForwardRunClear, RtlInitializeBitMap, RtlNumberOfSetBits


RtlNumberOfSetBits

RtlNumberOfSetBits returns a count of the set bits in a given bitmap variable.

ULONG
  RtlNumberOfSetBits(
    IN PRTL_BITMAP  BitMapHeader
    );

Parameters

BitMapHeader
Points to an initialized bitmap header for the caller's bitmap variable.

Include

ntddk.h

Return Value

RtlNumberOfSetBits returns how many bits currently are set.

Comments

Callers of RtlNumberOfSetBits must be running at IRQL < DISPATCH_LEVEL if the memory containing the bitmap variable or at BitMapHeader is pageable. Otherwise, RtlNumberOfSetBits can be called at any IRQL.

See Also

RtlFindSetBits, RtlInitializeBitMap, RtlNumberOfClearBits


RtlPrefixUnicodeString

RtlPrefixUnicodeString compares two Unicode strings to determine whether one string is a prefix of the other.

BOOLEAN
  RtlPrefixUnicodeString(
    IN PUNICODE_STRING  String1,
    IN PUNICODE_STRING  String2,
    IN BOOLEAN  CaseInSensitive
    );

Parameters

String1
Points to the first string, which might be a prefix of the buffered Unicode string at String2.
String2
Points to the second string.
CaseInSensitive
If TRUE, case should be ignored when doing the comparison.

Include

ntddk.h

Return Value

RtlPrefixUnicodeString returns TRUE if String1 is a prefix of String2.

Comments

Callers of RtlPrefixUnicodeString must be running at IRQL PASSIVE_LEVEL.

See Also

RtlCompareUnicodeString


RtlQueryRegistryValues

RtlQueryRegistryValues allows the caller to query several values from the registry subtree with a single call.

NTSTATUS
  RtlQueryRegistryValues(
    IN ULONG  RelativeTo,
    IN PCWSTR  Path,
    IN PRTL_QUERY_REGISTRY_TABLE  QueryTable,
    IN PVOID  Context,
    IN PVOID  Environment  OPTIONAL
    );

Parameters

RelativeTo
Specifies whether Path is an absolute registry path or is relative to a predefined path as one of the following:
Value Meaning
RTL_REGISTRY_ABSOLUTE
Path is an absolute registry path.
RTL_REGISTRY_SERVICES
Path is relative to \Registry\Machine\System\CurrentControlSet\Services.
RTL_REGISTRY_CONTROL
Path is relative to \Registry\Machine\System\CurrentControlSet\Control.
RTL_REGISTRY_WINDOWS_NT
Path is relative to \Registry\Machine\Software\Microsoft\
Windows NT\CurrentVersion.
RTL_REGISTRY_DEVICEMAP
Path is relative to \Registry\Machine\Hardware\DeviceMap.
RTL_REGISTRY_USER
Path is relative to \Registry\User\CurrentUser.
RTL_REGISTRY_OPTIONAL
Specifies that the key referenced by this parameter and the Path parameter are optional.
RTL_REGISTRY_HANDLE
Specifies that the Path parameter is actually a registry handle to use. This value is optional.

Path
Points to either an absolute registry path or a path relative to the known location specified by the RelativeTo parameter. Note that the names of keys in such a path must be known to the caller, including the last key in the path. If the RTL_REGISTRY_HANDLE flag is specified, this parameter is a registry handle for an already opened key to be queried directly.
QueryTable
Points to a table of one or more value names and subkey names in which the caller is interested. Each table entry contains a caller-supplied QueryRoutine that will be called for each value name that exists in the registry. The table must be terminated with a NULL table entry, which is a table entry with a NULL QueryRoutine and a NULL Name field. The QueryTable structure is defined as follows:
typedef struct _RTL_QUERY_REGISTRY_TABLE {
    PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine;
    ULONG Flags;
    PWSTR Name;
    PVOID EntryContext;
    ULONG DefaultType;
    PVOID DefaultData;
    ULONG DefaultLength;
} RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE;

This routine is called with the name, type, data, and data length of a registry value. If this field is NULL, it marks the end of the table.

A caller-supplied QueryRoutine is declared as follows:

NTSTATUS
(*PRTL_QUERY_REGISTRY_ROUTINE)(
    IN PWSTR ValueName,
    IN ULONG ValueType,
    IN PVOID ValueData,
    IN ULONG ValueLength,
    IN PVOID Context,
    IN PVOID EntryContext
    );

The remaining members of the QueryTable structure include the following.

Flags
Control how the remaining fields are to be interpreted, as follows:
Value Meaning
RTL_QUERY_REGISTRY_SUBKEY
The Name of this table entry is another path to a registry key, and all following table entries are for that key rather than the key specified by the Path parameter. This change in focus lasts until the end of the table or until another RTL_REGISTRY_SUBKEY or RTL_QUERY_REGISTRY_TOPKEY entry is seen. Each such entry must specify a path that is relative to the Path specified in the call to RtlQueryRegistryValues.
RTL_QUERY_REGISTRY_TOPKEY
Resets the current registry key handle to the original one specified by the RelativeTo and Path parameters. This is useful for getting back to the original node after descending into subkeys with the RTL_QUERY_REGISTRY SUBKEY flag.
RTL_QUERY_REGISTRY_REQUIRED
Specifies that this value is required and, if it is not found, STATUS_OBJECT_NAME_NOT_FOUND is returned. This is used for a table entry that specifies a NULL Name so that RtlQueryRegistryValues will enumerate all of the value names under a key and return STATUS_OBJECT_NAME_NOT_FOUND only if there are no value keys under the current key.
RTL_QUERY_REGISTRY_NOVALUE
Specifies that even though there is no Name for this table entry, all the caller wants is a callback: that is, the caller does not want to enumerate all the values under the current key. The QueryRoutine is called with NULL for ValueData, REG_NONE for ValueType, and zero for ValueLength.
RTL_QUERY_REGISTRY_NOEXPAND
Specifies that, if the type of this registry value is REG_EXPAND_SZ or REG_MULTI_SZ, RtlQueryRegistryValues is not to do any preprocessing of these registry values before calling the QueryRoutine. By default, RtlQueryRegistryValues expands environment variable references into REG_EXPAND_SZ values, enumerates each zero-terminated string in a REG_MULTI_SZ value, and calls the QueryRoutine once with each, making it look like there is more than one REG_SZ value with the same ValueName.
RTL_QUERY_REGISTRY_DIRECT
The QueryRoutine is ignored, and the EntryContext points to the location to store the value. For zero-terminated strings, EntryContext points to a UNICODE_STRING structure that describes the maximum size of the buffer. If the Buffer is NULL, a buffer is allocated.
RTL_QUERY_REGISTRY_DELETE
This is used to delete value keys after they have been queried.

Name
This is the name of a Value that the caller queried. If Name is NULL, the QueryRoutine specified for this table entry is called for all values associated with the current registry key.
EntryContext
This is an arbitrary 32-bit field that is passed uninterpreted each time the QueryRoutine is called.
DefaultType
Specifies the REG_XXX type of the data to be queried if Flags is not set with RTL_REGISTRY_REQUIRED; otherwise, zero.
DefaultData
Points to default value(s) for a named value entry of the DefaultType if it is not already in the registry under Name and if Flags is not set with RTL_REGISTRY_REQUIRED; otherwise, NULL.
DefaultLength
If there is no value name that matches the name given by the Name, and the DefaultType field is not REG_NONE, the QueryRoutine for this table entry is called with the contents of the following fields as if the value had been found in the registry. If the DefaultType is REG_SZ, REG_EXPANDSZ, or REG_MULTI_SZ and the DefaultLength is zero, the value of DefaultLength will be computed based on the length of the Unicode string pointed to by DefaultData.
Context
Points to a context that is passed, uninterpreted, when each QueryRoutine is called.
Environment
Points to the environment used when expanding variable values in REG_EXPAND_SZ registry values, or a NULL pointer (optional).

Include

wdm.h or ntddk.h

Return Value

RtlQueryRegistryValues returns STATUS_SUCCESS if the entire QueryTable was processed successfully. If an error occurs, RtlQueryRegistryValues returns an error status such as:

STATUS_INVALID_PARAMETER
STATUS_OBJECT_NAME_NOT_FOUND
STATUS_XXX (an error status from a user-supplied QueryRoutine)

Comments

The caller specifies an initial key path and a table. The table contains one or more entries that describe the key values and subkey names in which the caller is interested. RtlQueryRegistryValues starts at the initial key and enumerates the entries in the table.

For each entry specifying a value name or subkey name that exists in the registry, RtlQueryRegistryValues calls the QueryRoutine associated with each table entry. Each entry's caller-supplied QueryRoutine is passed the value name, type, data, and data length.

When building the QueryTable, be sure to allocate an entry for each value being queried, plus a NULL entry at the end. Zero the table and then initialize the entries. QueryTable must be allocated from resident memory (nonpaged pool).

If an error occurs at any stage of processing the QueryTable, RtlQueryRegistryValues stops processing the table and returns the error status.

Callers of RtlQueryRegistryValues must be running at IRQL PASSIVE_LEVEL.

See Also

RtlZeroMemory, ZwEnumerateKey, ZwOpenKey


RtlRetrieveUlong

RtlRetrieveUlong retrieves a ULONG value from the source address, avoiding alignment faults. The destination address is assumed to be aligned.

VOID
  RtlRetrieveUlong(
    IN OUT PULONG  DestinationAddress,
    IN PULONG  SourceAddress
    );

Parameters

DestinationAddress
Points to a ULONG-aligned location in which to store the ULONG value.
SourceAddress
Points to a location from which to retrieve the ULONG value.

Include

wdm.h or ntddk.h

Comments

Callers of RtlRetrieveUlong can be running at any IRQL if the given addresses are in nonpaged pool. Otherwise, the caller must be running at IRQL < DISPATCH_LEVEL.

See Also

RtlStoreUlong


RtlRetrieveUshort

RtlRetrieveUshort retrieves a USHORT value from the source address, avoiding alignment faults.

VOID
  RtlRetrieveUshort(
    IN OUT PUSHORT  DestinationAddress,
    IN PUSHORT  SourceAddress
    );

Parameters

DestinationAddress
Points to a USHORT-aligned location in which to store the value.
SourceAddress
Points to a location from which to retrieve the value.

Include

wdm.h or ntddk.h

Comments

Callers of RtlRetrieveUshort can be running at any IRQL if the given addresses are in nonpaged pool. Otherwise, the caller must be running at IRQL < DISPATCH_LEVEL.

See Also

RtlStoreUshort


RtlSetAllBits

RtlSetAllBits sets all bits in a given bitmap variable.

VOID
  RtlSetAllBits(
    IN PRTL_BITMAP  BitMapHeader
    );

Parameters

BitMapHeader
Points to an initialized bitmap header for the caller's bitmap variable.

Include

ntddk.h

Comments

Callers of RtlSetAllBits must be running at IRQL < DISPATCH_LEVEL if the memory containing the bitmap variable or at BitMapHeader is pageable. Otherwise, RtlSetAllBits can be called at any IRQL.

See Also

RtlAreBitsClear, RtlAreBitsSet, RtlFindClearBits, RtlFindClearBitsAndSet, RtlFindClearRuns, RtlFindFirstRunClear, RtlInitializeBitMap, RtlFindLastBackwardRunClear, RtlFindLongestRunClear, RtlFindNextForwardRunClear, RtlInitializeBitMap, RtlSetBits, RtlNumberOfSetBits


RtlSetBits

RtlSetBits sets all bits in a given range of a given bitmap variable.

VOID
  RtlSetBits(
    IN PRTL_BITMAP  BitMapHeader,
    IN ULONG  StartingIndex,
    IN ULONG  NumberToSet
    );

Parameters

BitMapHeader
Points to an initialized bitmap header for the caller's bitmap variable.
StartingIndex
Specifies the start of the bit range to be set. This is a zero-based value indicating the position of the first bit in the range.
NumberToSet
Specifies how many bits to set.

Include

ntddk.h

Comments

RtlSetBits simply returns control if the input NumberToSet is zero. StartingIndex plus NumberToSet must be less than or equal to sizeof(BitMapHeader->SizeOfBitMap).

Callers of RtlSetBits must be running at IRQL < DISPATCH_LEVEL if the memory containing the bitmap variable or at BitMapHeader is pageable. Otherwise, RtlSetBits can be called at any IRQL.

See Also

RtlAreBitsClear, RtlFindClearBitsAndSet, RtlFindClearRuns, RtlFindFirstRunClear, RtlFindLastBackwardRunClear, RtlFindLongestRunClear, RtlFindNextForwardRunClear, RtlInitializeBitMap, RtlSetAllBits, RtlNumberOfClearBits


RtlSetDaclSecurityDescriptor

RtlSetDaclSecurityDescriptor sets the DACL information of an absolute-format security descriptor, or if there is already a DACL present in the security descriptor, it is superseded.

NTSTATUS
  RtlSetDaclSecurityDescriptor(
    IN OUT PSECURITY_DESCRIPTOR  SecurityDescriptor,
    IN BOOLEAN  DaclPresent,
    IN PACL  Dacl  OPTIONAL,
    IN BOOLEAN  DaclDefaulted  OPTIONAL
    );

Parameters

SecurityDescriptor
Points to the SECURITY_DESCRIPTOR to which the DACL is to be applied.
DaclPresent
If FALSE, indicates that the DaclPresent flag in the security descriptor should be set to FALSE. In this case, the remaining optional parameters are ignored. Otherwise, the DaclPresent control flag in the security descriptor is set to TRUE and the remaining optional parameters are not ignored.
Dacl
Points to the DACL for the security descriptor. If this parameter is NULL, a NULL ACL is assigned to the security descriptor. A NULL DACL unconditionally grants access. The DACL is referenced by, but not copied into, the security descriptor.
DaclDefaulted
When set, indicates that the DACL was picked up from some default mechanism rather than explicitly specified by the caller. This value is set in the DaclDefaulted control flag in the security descriptor. If this parameter is NULL, the DaclDefaulted flag will be cleared.

Include

ntddk.h

Return Value

RtlSetDaclSecurityDescriptor can return one of the following:

STATUS_SUCCESS
The call completed successfully.
STATUS_UNKNOWN_REVISION
The revision of the security descriptor is unknown.
STATUS_INVALID_SECURITY_DESCR
The security descriptor is not an absolute format security descriptor.

Comments

Callers of RtlSetDaclSecurityDescriptor must be running at IRQL PASSIVE_LEVEL.

See Also

RtlCreateSecurityDescriptor, RtlLengthSecurityDescriptor, RtlValidSecurityDescriptor, SECURITY_DESCRIPTOR


RtlStoreUlonglong

RtlStoreUlonglong stores a specified ULONGLONG value at a specified memory address, avoiding memory alignment faults.

VOID
  RtlStoreUlonglong (
    PULONGLONG  Address,
    ULONGLONG  Value
    );

Parameters

Address
Pointer to a memory location where the value of Value is stored.
Value
Specifies the ULONGLONG value that is stored.

Include

ntddk.h or wdm.h

Comments

RtlStoreUlonglong avoids memory alignment faults. If the address specified by Address is not aligned to the storage requirements of a ULONGLONG, RtlStoreUlonglong stores the bytes of Value beginning at the memory location (PUCHAR)Address.

RtlStoreUlonglong runs at any IRQL if Address points to nonpaged pool; otherwise it must run at IRQL < DISPATCH_LEVEL.

See Also

RtlStoreUlong, RtlStoreUlongPtr


RtlStoreUlongPtr

RtlStoreUlongPtr stores a specified ULONG_PTR value at a specified memory location, avoiding memory alignment faults.

VOID
  RtlStoreUlongPtr (
    PULONG_PTR  Address,
    ULONG_PTR  Value
    );

Parameters

Address
Pointer to a memory location where the value of Value is stored.
Value
Specifies the ULONG_PTR value that is stored.

Include

ntddk.h or wdm.h

Comments

RtlStoreUlongPtr avoids memory alignment faults. If the value of Address is not aligned to the storage requirements of a ULONG_PTR, RtlStoreUlongPtr stores the bytes of Value beginning at the memory location (PUCHAR)Address.

RtlStoreUlongPtr runs at any IRQL if Address points to nonpaged pool; otherwise it must run at IRQL < DISPATCH_LEVEL.

See Also

RtlStoreUlong, RtlStoreUlonglong


RtlStoreUshort

RtlStoreUshort stores a USHORT value at a particular address, avoiding alignment faults.

VOID
  RtlStoreUshort(
    IN PUSHORT  Address,
    IN USHORT  Value
    );

Parameters

Address
Points to a location in which to store a USHORT value.
Value
Specifies a USHORT value to be stored.

Include

wdm.h or ntddk.h

Comments

The caller can be running at any IRQL if Address points to nonpaged pool. Otherwise, the caller must be running at IRQL < DISPATCH_LEVEL.

See Also

RtlRetrieveUshort


RtlStringFromGUID

RtlStringFromGUID converts a given GUID from binary format into a Unicode string.

NTSTATUS
  RtlStringFromGUID(
    IN REFGUID  Guid,
    OUT PUNICODE_STRING  GuidString
    );

Parameters

Guid
Specifies the binary-format GUID to convert.
GuidString
Points to a caller-supplied variable in which a pointer to the converted GUID string is returned. RtlStringFromGUID allocates the buffer space for the string, which the caller must free by calling RtlFreeUnicodeString.

Include

wdm.h or ntddk.h

Return Value

If the conversion succeeds, RtlStringFromGUID returns STATUS_SUCCESS. Otherwise, no storage was allocated, nor was the conversion performed.

Comments

Callers of RtlStringFromGUID must be running at IRQL PASSIVE_LEVEL.

See Also

RtlGUIDFromString


RtlTimeFieldsToTime

RtlTimeFieldsToTime converts TIME_FIELDS information to a system time value.

BOOLEAN
  RtlTimeFieldsToTime(
    IN PTIME_FIELDS  TimeFields,
    IN PLARGE_INTEGER  Time
    );

Parameters

TimeFields
Points to the following structure, containing the time information to be converted:
typedef struct TIME_FIELDS {
    CSHORT Year;
    CSHORT Month;
    CSHORT Day;
    CSHORT Hour;
    CSHORT Minute;
    CSHORT Second;
    CSHORT Milliseconds;
    CSHORT Weekday;
} TIME_FIELDS;
Year
Is in the range from 1601 on.
Month
Is in the range from 1 to 12.
Day
Is in the range from 1 to 31.
Hour
Is in the range from 0 to 23.
Minute
Is in the range from 0 to 59.
Second
Is in the range from 0 to 59.
Milliseconds
Is in the range from 0 to 999.
Weekday
Is in the range from 0 to 6 (Sunday to Saturday).
Time
Points to a buffer, which is to contain the converted system time value as a large integer.

Include

wdm.h or ntddk.h

Return Value

RtlTimeFieldsToTime returns TRUE if the input TimeFields data was successfully converted.

Comments

RtlTimeFieldsToTime ignores the Weekday value in TimeFields.

Callers of RtlTimeFieldsToTime can be running at any IRQL if both input buffers are resident.

See Also

ExLocalTimeToSystemTime, ExSystemTimeToLocalTime, KeQuerySystemTime, RtlTimeToTimeFields


RtlTimeToTimeFields

RtlTimeToTimeFields converts system time into a TIME_FIELDS structure.

VOID
  RtlTimeToTimeFields(
    IN PLARGE_INTEGER  Time,
    IN PTIME_FIELDS  TimeFields
    );

Parameters

Time
Points to a buffer containing the absolute system time as a large integer, accurate to 100-nanosecond resolution.
TimeFields
Points to a caller-allocated buffer, which must be at least sizeof(TIME_FIELDS), to contain the returned information.

Include

wdm.h or ntddk.h

Comments

Callers of RtlTimeToTimeFields can be running at any IRQL if both input buffers are resident.

See Also

ExLocalTimeToSystemTime, ExSystemTimeToLocalTime, KeQuerySystemTime, RtlTimeFieldsToTime


RtlUlongByteSwap

RtlUlongByteSwap converts a ULONG from little-endian to big-endian, and vice versa.

ULONG FASTCALL
  RtlUlongByteSwap(
    IN ULONG  Source
    );

Parameters

Source
ULONG to convert.

Include

wdm.h or ntddk.h

Return Value

The converted ULONG value.

Comments

This routine is not supported on Windows 98 or Windows ME.

See Also

RtlUlonglongByteSwap, RtlUshortByteSwap


RtlUlonglongByteSwap

RtlUlonglongByteSwap converts a ULONGLONG from little-endian to big-endian, and vice versa.

ULONGLONG FASTCALL
  RtlUlonglongByteSwap(
    IN ULONGLONG  Source
    );

Parameters

Source
ULONGLONG to convert.

Include

wdm.h or ntddk.h

Return Value

The converted ULONGLONG value.

Comments

This routine is not supported on Windows 98 or Windows ME.

See Also

RtlUlongByteSwap, RtlUshortByteSwap


RtlUnicodeStringToAnsiSize

RtlUnicodeStringToAnsiSize returns the number of bytes required for a NULL-terminated ANSI string that is equivalent to a specified Unicode string.

ULONG
  RtlUnicodeStringToAnsiSize(
    PUNICODE_STRING  UnicodeString
    );

Parameters

UnicodeString
Pointer to the Unicode string for which to compute the number of bytes required for an equivalent NULL-terminated ANSI string.

Include

wdm.h

Return Value

If the Unicode string can be translated into an ANSI string using the current system locale information, RtlUnicodeStringToAnsiSize returns the number of bytes required for an equivalent NULL-terminated ANSI string. Otherwise, RtlUnicodeStringToAnsiSize returns zero.

Comments

The Unicode string is interpreted for the current system locale.

RtlUnicodeStringToAnsiSize performs the same operation as RtlxUnicodeStringToAnsiSize, but executes faster if the system does not use multibyte code pages.

RtlUnicodeStringToAnsiSize runs at IRQL PASSIVE_LEVEL.

See Also

RtlxUnicodeStringToAnsiSize


RtlUnicodeStringToAnsiString

RtlUnicodeStringToAnsiString converts a given Unicode string into an ANSI string.

NTSTATUS
  RtlUnicodeStringToAnsiString(
    IN OUT PANSI_STRING  DestinationString,
    IN PUNICODE_STRING  SourceString,
    IN BOOLEAN  AllocateDestinationString
    );

Parameters

DestinationString
Pointer to an ANSI_STRING structure to hold the converted ANSI string. If AllocateDestinationString is TRUE, the routine allocates a new buffer to hold the string data, and updates the Buffer member of DestinationString to point to the new buffer. Otherwise, the routine uses the currently-specified buffer to hold the string.
SourceString
Points to the Unicode source string to be converted to ANSI.
AllocateDestinationString
TRUE if this routine is to allocate the buffer space for the DestinationString. If it does, the buffer must be deallocated by calling RtlFreeAnsiString.

Include

wdm.h or ntddk.h

Return Value

If the conversion succeeds, RtlUnicodeStringToAnsiString returns STATUS_SUCCESS. Otherwise, no storage was allocated, and no conversion was done.

Comments

The translation is done in accord with the current system-locale information.

Callers of RtUnicodeStringToAnsiString must be running at IRQL PASSIVE_LEVEL.

See Also

ANSI_STRING, UNICODE_STRING, RtlAnsiStringToUnicodeString, RtlFreeAnsiString


RtlUnicodeStringToInteger

RtlUnicodeStringToInteger converts a Unicode string representation of an integer into its integer equivalent.

NTSTATUS
  RtlUnicodeStringToInteger(
    IN PUNICODE_STRING  String,
    IN ULONG  Base  OPTIONAL,
    OUT PULONG  Value
    );

Parameters

String
Points to the Unicode string to be converted to its integer equivalent.
Base
An optional argument that indicates the base of the number expressed as a Unicode string.
Value
Points to caller supplied storage of type ULONG. RtlUnicodeStringToInteger returns the integer conversion results in Value.

Include

wdm.h or ntddk.h

Return Value

If the conversion is successful, RtlUnicodeStringToInteger returns STATUS_SUCCESS and Value is set to the integer equivalent of the Unicode string. Otherwise, the Value is set to 0, and RtlUnicodeStringToInteger returns STATUS_INVALID_PARAMETER.

Comments

If the first character of the string is a "–", the sign of the output Value is negative, otherwise if the first character is a "+" or there is no sign character, the sign of Value is positive.

If no Base is supplied, RtlUnicodeStringToInteger checks for a leading character to indicate the base of the number. An "x" indicates the string is to be converted as a hexidecimal integer; an "o" indicates the string is to be converted as an octal integer; a "b" indicates the string is to be converted as a binary integer. Otherwise RtlUnicodeStringToInteger assumes the number is to be converted as a base 10 integer.

Callers of RtlUnicodeStringToInteger must be running at IRQL PASSIVE_LEVEL.

See Also

RtlIntegerToUnicodeString


RtlUpcaseUnicodeChar

RtlUpcaseUnicodeChar converts the specified Unicode character to uppercase.

WCHAR
  RtlUpcaseUnicodeChar(
    IN WCHAR  SourceCharacter
    );

Parameters

SourceCharacter
Specifies the character to convert.

Include

ntddk.h

Return Value

RtlUpcaseUnicodeChar returns the uppercase version of the specified Unicode character.

Comments

Callers of RtlUpcaseUnicodeChar must be running at IRQL PASSIVE_LEVEL.

See Also

RtlUpcaseUnicodeString, RtlUpperChar


RtlUpcaseUnicodeString

RtlUpcaseUnicodeString converts a copy of the source string to upper case and writes the converted string in the destination buffer.

NTSTATUS
  RtlUpcaseUnicodeString(
    IN OUT PUNICODE_STRING  DestinationString  OPTIONAL,
    IN PCUNICODE_STRING  SourceString,
    IN BOOLEAN  AllocateDestinationString
    );

Parameters

DestinationString
Points to a caller-allocated buffer for the converted Unicode string or is NULL if AllocateDestinationString is set to TRUE.
SourceString
Points to the source Unicode string to be converted to upper case.
AllocateDestinationString
TRUE if RtlUpcaseUnicodeString is to allocate the buffer space for the DestinationString. If it does, the buffer must be deallocated by calling RtlFreeUnicodeString.

Include

ntddk.h

Return Value

If the operation succeeds, RtlUpcaseUnicodeString returns STATUS_SUCCESS. Otherwise, no storage was allocated, and no conversion was done.

Comments

Callers of RtlUpcaseUnicodeString must be running at IRQL PASSIVE_LEVEL.

See Also

RtlFreeUnicodeString, RtlUpcaseUnicodeChar


RtlUpperChar

RtlUpperChar converts the specified character to uppercase.

CHAR
  RtlUpperChar(
    IN CHAR Character
    );

Parameters

Character
Specifies the character to convert.

Include

ntddk.h

Return Value

RtlUpperChar returns the uppercase version of the specified character or returns the value specified by the caller for Character if the specified character cannot be converted.

Comments

RtlUpperChar returns the input Character unconverted if it is the lead byte of a multibyte character or if the uppercase equivalent of Character is a double-byte character. To convert such characters, use RtlUpcaseUnicodeChar.

Callers of RtlUpperChar must be running at IRQL PASSIVE_LEVEL.

See Also

RtlUpcaseUnicodeChar, RtlUpperString


RtlUpperString

RtlUpperString copies the given SourceString to the DestinationString buffer, converting it to uppercase.

VOID
  RtlUpperString(
    IN OUT PSTRING  DestinationString,
    IN PSTRING  SourceString
    );

Parameters

DestinationString
Points to the buffer for the converted destination string.
SourceString
Points to the source string to be converted to uppercase.

Include

ntddk.h

Comments

The MaximumLength and Buffer fields of DestinationString are not modified by this routine.

The number of bytes copied from SourceString is either the Length of SourceString or the MaximumLength of DestinationString, whichever is smaller.

Callers of RtlUpperString must be running at IRQL PASSIVE_LEVEL.

See Also

RtlUpperChar


RtlUshortByteSwap

RtlUshortByteSwap converts a USHORT from little-endian to big-endian, and vice versa.

USHORT
  RtlUshortByteSwap(
    IN USHORT  Source
    );

Parameters

Source
USHORT to convert.

Include

wdm.h or ntddk.h

Return Value

The converted USHORT value.

Comments

This routine is not supported on Windows 98 or Windows ME.

See Also

RtlUlongByteSwap, RtlUlonglongByteSwap


RtlValidSecurityDescriptor

RtlValidSecurityDescriptor checks a given security descriptor's validity.

BOOLEAN
  RtlValidSecurityDescriptor(
    IN PSECURITY_DESCRIPTOR  SecurityDescriptor
    );

Parameters

SecurityDescriptor
Points to the SECURITY_DESCRIPTOR to be checked.

Include

ntddk.h

Return Value

RtlValidSecurityDescriptor returns TRUE if the given descriptor is valid.

Comments

Callers of RtlValidSecurityDescriptor must be running at IRQL PASSIVE_LEVEL.

See Also

RtlCreateSecurityDescriptor, RtlLengthSecurityDescriptor, RtlSetDaclSecurityDescriptor, SECURITY_DESCRIPTOR


RtlVerifyVersionInfo

RtlVerifyVersionInfo compares a specified set of operating system version requirements to the corresponding attributes of the currently running version of the operating system.

NTSTATUS
  RtlVerifyVersionInfo(
    IN PRTL_OSVERSIONINFOEXW  VersionInfo,
    IN ULONG  TypeMask,
    IN ULONGLONG  ConditionMask
    );

Parameters

VersionInfo
Pointer to an RTL_OSVERSIONINFOEXW structure that specifies the operating system version requirements to compare to the corresponding attributes of the currently running version of the operating system.
TypeMask
Specifies which members of VersionInfo to compare with the corresponding attributes of the currently running version of the operating system. TypeMask is set to a logical OR of one or more of the following values:
Value | Corresponding Member
VER_BUILDNUMBER | dwBuildNumber
VER_MAJORVERSION | dwMajorVersion
VER_MINORVERSION | dwMinorVersion
VER_PLATFORMID | dwPlatformId
VER_SERVICEPACKMAJOR | wServicePackMajor
VER_SERVICEPACKMINOR | wServicePackMinor
VER_SUITENAME | wSuiteMask
VER_PRODUCT_TYPE | wProductType

ConditionMask
Specifies how to compare each VersionInfo member. To set the value of ConditionMask, a caller should use the VER_SET_CONDITION macro:
VER_SET_CONDITION (
        IN OUT  ULONGLONG  ConditionMask,
        IN  ULONG   TypeBitMask,
        IN  UCHAR   ComparisonType
        );

The value of ConditionMask is created in the following way:

  • Initialize the value of ConditionMask to zero.
  • Call VER_SET_CONDITION once for each VersionInfo member specified by TypeMask.
  • Set the TypeBitMask and ComparisonType parameters for each call to VER_SET_CONDITION as follows:
TypeBitMask
Indicates the VersionInfo member for which the comparison type is set. TypeBitMask can be one of the following values:
Value | Corresponding Member
VER_BUILDNUMBER | dwBuildNumber
VER_MAJORVERSION | dwMajorVersion
VER_MINORVERSION | dwMinorVersion
VER_PLATFORMID | dwPlatformId
VER_SERVICEPACKMAJOR | wServicePackMajor
VER_SERVICEPACKMINOR | wServicePackMinor
VER_SUITENAME | wSuiteMask
VER_PRODUCT_TYPE | wProductType
ComparisonType
Specifies the comparison type that RtlVerifyVersionInfo uses to compare the VersionInfo member specified by TypeBitMask with the corresponding attribute of the currently running operating system.

For all values of TypeBitMask other than VER_SUITENAME, ComparsionType is set to one of the following values:
Value | Meaning
VER_EQUAL | The current value must be equal to the specified value.
VER_GREATER | The current value must be greater than the specified value.
VER_GREATER_EQUAL | The current value must be greater than or equal to the specified value.
VER_LESS | The current value must be less than the specified value.
VER_LESS_EQUAL | The current value must be less than or equal to the specified value.

If TypeBitMask is set to VER_SUITENAME, ComparisonType is set to of one the following values:
Value | Meaning
VER_AND | All product suites specified in the wSuiteMask member must be present in the current system.
VER_OR | At least one of the specified product suites must be present in the current system.

Include

ntddk.h

Return Value

RtlVerifyVersionInfo returns one of the following status values:

STATUS_SUCCESS
STATUS_INVALID_PARAMETER
The input parameters are not valid.
STATUS_REVISION_MISMATCH
The specified version does not match the currently running version of the operating system.

Comments

This routine is supported on Windows XP and later operating system versions.

RtlVerifyVersionInfo enables a driver to easily verify the presence of a required set of operating system attributes. RtlVerifyVersionInfo is the kernel-mode equivalent of the user-mode VerifyVersionInfo function in the Platform SDK. See the example in the Platform SDK that shows how to verify the system version.

Typically, RtlVerifyVersionInfo returns STATUS_SUCCESS only if all comparisons succeed. However, the major version, minor version, and service pack version are tested in a sequential manner in the following way:

  • If the major version exceeds the minimum required, then the minor version and service pack version are not tested. For example, if the current major version is 6.0, a test for a system greater than or equal to version 5.1 service pack 1 succeeds. The minor version and service pack version are not tested.
  • If the minor version exceeds the minimum required, then the service pack version is not tested. For example, if the current major version is 5.2, a test for a system version greater than or equal to version 5.1 service pack 1 succeeds. The service pack version is not tested.
  • If the major service pack version exceeds the minimum required, then the minor service pack version is not tested.

To verify a range of system versions, a driver can call RtlVerifyVersionInfo twice, once to verify a lower-bound on the system version and once to verify an upper-bound on the system version.

See Also

RtlGetVersion, RTL_OSVERSIONINFOW, RTL_OSVERSIONINFOEXW


RtlVolumeDeviceToDosName

This routine is obsolete for Windows® XP and later. Use IoVolumeDeviceToDosName instead.

RtlVolumeDeviceToDosName returns the MS-DOS® path for a specified device object that represents a file system volume.

NTSTATUS
  RtlVolumeDeviceToDosName(
    IN  PVOID  VolumeDeviceObject,
    OUT PUNICODE_STRING  DosName
    );

Parameters

VolumeDeviceObject
Pointer to a device object that represents a file system volume.
DosName
Pointer to a Unicode string containing the MS-DOS path of the volume device object specified by VolumeDeviceObject.

Include

ntddk.h

Return Value

RtlVolumeDeviceToDosName returns STATUS_SUCCESS or an appropriate error status.

Comments

RtlVolumeDeviceToDosName allocates the Unicode string buffer for the MS-DOS path from the memory pool. After the buffer is no longer required, a caller of this routine should use ExFreePool to free it.

Drivers that must work on older NT-based operating systems may use this routine. Drivers written for Windows XP and later must use IoVolumeDeviceToDosName instead.


RtlWriteRegistryValue

RtlWriteRegistryValue writes caller-supplied data into the registry along the specified relative path at the given value name.

NTSTATUS
  RtlWriteRegistryValue(
    IN ULONG  RelativeTo,
    IN PCWSTR  Path,
    IN PCWSTR  ValueName,
    IN ULONG  ValueType,
    IN PVOID  ValueData,
    IN ULONG  ValueLength
    );

Parameters

RelativeTo
Specifies whether Path is an absolute registry path or is relative to a predefined path as one of the following:
Value Meaning
RTL_REGISTRY_ABSOLUTE
Path is an absolute registry path.
RTL_REGISTRY_SERVICES
Path is relative to \Registry\Machine\System\CurrentControlSet\Services.
RTL_REGISTRY_CONTROL
Path is relative to \Registry\Machine\System\CurrentControlSet\Control.
RTL_REGISTRY_WINDOWS_NT
Path is relative to \Registry\Machine\Software\Microsoft\
Windows NT\CurrentVersion.
RTL_REGISTRY_DEVICEMAP
Path is relative to \Registry\Machine\Hardware\DeviceMap.
RTL_REGISTRY_USER
Path is relative to \Registry\User\CurrentUser.
RTL_REGISTRY_OPTIONAL
Specifies that the key referenced by this parameter and the Path parameter are optional.
RTL_REGISTRY_HANDLE
Specifies that the Path parameter is actually a registry handle to use. This value is optional.

Path
Points to either an absolute registry path or a path relative to the known location specified by the RelativeTo parameter. If the RTL_REGISTRY_HANDLE flag is specified, this parameter is a registry handle for an already opened key to be used directly.
ValueName
Points to the name of a subkey or value entry to be written into the registry.
ValueType
Points to the type of value, identified by the ValueName parameter, to be placed in the registry.
ValueData
Points to the name of a subkey or values for its value entries (or both) to be written into the registry.
ValueLength
Specifies the number of bytes of ValueData to be written into the registry.

Include

wdm.h or ntddk.h

Return Value

RtlWriteRegistryValue returns the status of the operation, either STATUS_SUCCESS or an error status.

Comments

Callers of RtlWriteRegistryValue must be running at IRQL PASSIVE_LEVEL.

See Also

RtlCheckRegistryKey, RtlCreateRegistryKey, RtlDeleteRegistryValue, RtlQueryRegistryValues, ZwOpenKey


RtlxUnicodeStringToAnsiSize

RtlxUnicodeStringToAnsiSize returns the number of bytes required for a NULL-terminated ANSI string that is equivalent to a specified Unicode string.

ULONG
  RtlxUnicodeStringToAnsiSize(
    PUNICODE_STRING  UnicodeString
    );

Parameters

UnicodeString
Pointer to the Unicode string for which to compute the number of bytes required for an equivalent NULL-terminated ANSI string.

Include

wdm.h

Return Value

If the Unicode string can be translated into an ANSI string using the current system locale information, RtlxUnicodeStringToAnsiSize returns the number of bytes required for an equivalent NULL-terminated ANSI string. Otherwise, it returns zero.

Comments

The Unicode string is interpreted for the current system locale.

RtlxUnicodeStringToAnsiSize runs at IRQL PASSIVE_LEVEL.

See Also

RtlUnicodeStringToAnsiSize


RtlZeroBytes

RtlZeroBytes fills a block of memory with zeros, given a pointer to the block and the length, in bytes, to be filled and is obsolete. For better performance, use RtlZeroMemory.

VOID
  RtlZeroBytes(
    PVOID  Destination,
    SIZE_T  Length
    );


RtlZeroMemory

RtlZeroMemory fills a block of memory with zeros, given a pointer to the block and the length, in bytes, to be filled.

VOID
  RtlZeroMemory(
    IN VOID UNALIGNED  *Destination,
    IN SIZE_T  Length
    );

Parameters

Destination
Points to the memory to be filled with zeros.
Length
Specifies the number of bytes to be zeroed.

Include

wdm.h or ntddk.h

Comments

Callers of RtlZeroMemory can be running at any IRQL if the Destination block is in nonpaged pool. Otherwise, the caller must be running at IRQL < DISPATCH_LEVEL.

See Also

RtlFillMemory


Security Reference Monitor Routines

Generally, higher-level drivers, particularly network drivers, call these routines.

References for the Se Xxx routines are in alphabetical order. For an overview of the functionality of these routines, see Summary of Kernel-Mode Support Routines.


SeAccessCheck

SeAccessCheck determines whether the requested access rights can be granted to an object protected by a security descriptor and an object owner.

BOOLEAN
  SeAccessCheck(
    IN PSECURITY_DESCRIPTOR  SecurityDescriptor,
    IN PSECURITY_SUBJECT_CONTEXT  SubjectSecurityContext,
    IN BOOLEAN  SubjectContextLocked,
    IN ACCESS_MASK  DesiredAccess,
    IN ACCESS_MASK  PreviouslyGrantedAccess,
    OUT PPRIVILEGE_SET  *Privileges  OPTIONAL,
    IN PGENERIC_MAPPING  GenericMapping,
    IN KPROCESSOR_MODE  AccessMode,
    OUT PACCESS_MASK  GrantedAccess,
    OUT PNTSTATUS  AccessStatus
    );

Parameters

SecurityDescriptor
Pointer to the SECURITY_DESCRIPTOR structure that describes the security descriptor protecting the object being accessed.
SubjectSecurityContext,
Pointer to the SECURITY_SUBJECT_CONTEXT structure that specifies the subject's captured security context.
SubjectContextLocked
Indicates whether the user's subject context is locked, so that it does not have to be locked again.
DesiredAccess
Specifies the ACCESS_MASK bitmask for the access rights that the caller is attempting to acquire. If the caller sets the MAXIMUM_ALLOWED bit, the routine performs all DACL checks. However, the routine does not do any privilege checks, unless the caller specifically requests them by setting the ACCESS_SYSTEM_SECURITY or WRITE_OWNER bits.
PreviouslyGrantedAccess
Specifies the ACCESS_MASK bitmask of access rights already granted, such as access rights granted as a result of holding a privilege.
Privileges
Pointer to a caller-supplied variable to be set to the address of the PRIVILEGE_SET structure that will be used as part of the access validation, or this parameter can be NULL. The returned buffer, if any, must be released by the caller with ExFreePool.
GenericMapping
Pointer to the GENERIC_MAPPING structure associated with this object type. This value specifies the specific access rights implied by each GENERIC_XXX access right.
AccessMode
Specifies the access mode to be used in the check, either UserMode or KernelMode.
GrantedAccess
Pointer to a returned access mask indicating the granted access. If the caller specifies MAXIMUM_ALLOWED, and the DACL in SecurityDescriptor is NULL, then the routine returns GENERIC_ALL plus any additional access the caller explicitly requests.
AccessStatus
Pointer to the status value indicating why access was denied.

Return Value

If access is allowed, SeAccessCheck returns TRUE.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

SeAccessCheck might perform privilege tests for SeTakeOwnershipPrivilege and SeSecurityPrivilege, depending on the accesses being requested. It might perform additional privilege testing in future releases of the operating system.

This routine also might check whether the caller is the owner of the object in order to grant WRITE_DAC or READ_CONTROL access.

If this routine returns FALSE, the caller should use the returned AccessStatus as its return value. That is, the caller should avoid hardcoding a return value of STATUS_ACCESS_DENIED or any other specific STATUS_XXX value.

Callers of this routine must be running at IRQL = PASSIVE_LEVEL.

See Also

ExFreePool, IoGetFileObjectGenericMapping, SeValidSecurityDescriptor, ACCESS_MASK, GENERIC_MAPPING, PRIVILEGE_SET, SECURITY_DESCRIPTOR, SECURITY_SUBJECT_CONTEXT


SeAssignSecurity

SeAssignSecurity builds a self-relative security descriptor for a new object, given the security descriptor of its parent directory and any originally requested security for the object.

NTSTATUS
  SeAssignSecurity(
    IN PSECURITY_DESCRIPTOR  ParentDescriptor  OPTIONAL,
    IN PSECURITY_DESCRIPTOR  ExplicitDescriptor  OPTIONAL,
    OUT PSECURITY_DESCRIPTOR  *NewDescriptor,
    IN BOOLEAN  IsDirectoryObject,
    IN PSECURITY_SUBJECT_CONTEXT  SubjectContext,
    IN PGENERIC_MAPPING  GenericMapping,
    IN POOL_TYPE  PoolType
    );

Parameters

ParentDescriptor
Pointer to a buffer containing the SECURITY_DESCRIPTOR for the parent directory, if any, containing the new object being created. ParentDescriptor can be NULL, or have a NULL system access control list (SACL) or a NULL discretionary access control list (DACL).
ExplicitDescriptor
Pointer to a buffer containing the SECURITY_DESCRIPTOR specified by the user that is applied to the new object. ExplicitDescriptor can be NULL, or have a NULL SACL or a NULL DACL.
NewDescriptor
Receives a pointer to the returned SECURITY_DESCRIPTOR. SeAssignSecurity allocates the buffer from the paged memory pool.
IsDirectoryObject
Specifies whether the new object is a directory object. TRUE indicates the object contains other objects.
SubjectContext
Pointer to a buffer containing the security context of the subject creating the object. This is used to retrieve default security information for the new object, such as the default owner, the primary group, and discretionary access control.
GenericMapping
Pointer to the GENERIC_MAPPING structure that describes the mapping from each generic right to the implied nongeneric rights.
PoolType
This parameter is unused. The buffer to hold the new security descriptor is always allocated from paged pool.

Return Value

SeAssignSecurity can return one of the following:

STATUS_SUCCESS
The assignment was successful.
STATUS_INVALID_OWNER
The SID provided for the owner of the target security descriptor is not one the caller is authorized to assign as the owner of an object.
STATUS_PRIVILEGE_NOT_HELD
The caller does not have the privilege (SeSecurityPrivilege) necessary to explicitly assign the specified system ACL.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

The final security descriptor returned to the caller may contain a mix of information, some explicitly provided from the new object's parent.

SeAssignSecurity assumes privilege checking has not been performed. This routine performs privilege checking.

The assignment of system and discretionary ACLs is governed by the logic illustrated in the following table:

 | Explicit (nondefault) ACL specified | Explicit default ACL specified | No ACL specified
Inheritable ACL from parent | Assign specified ACL | Assign inherited ACL | Assign inherited ACL
No inheritable ACL from parent | Assign specified ACL | Assign default ACL | Assign no ACL

An explicitly specified ACL, whether a default ACL or not, can be empty or null. The caller must be a kernel-mode client or be appropriately privileged to explicitly assign a default or nondefault system ACL.

The assignment of the new object's owner and group is governed by the following logic:

  • If the passed security descriptor includes an owner, it is assigned as the new object's owner. Otherwise, the caller's token is considered to determine the owner. Within the token, the default owner, if any, is assigned. Otherwise, the caller's user ID is assigned.
  • If the passed security descriptor includes a group, it is assigned as the new object's group. Otherwise, the caller's token is considered to determine the group. Within the token, the default group, if any, is assigned. Otherwise, the caller's primary group ID is assigned.

Callers of SeAssignSecurity must be running at IRQL PASSIVE_LEVEL.

See Also

IoGetFileObjectGenericMapping, SeDeassignSecurity, GENERIC_MAPPING, SECURITY_DESCRIPTOR


SeAssignSecurityEx

SeAssignSecurityEx builds a self-relative security descriptor for a new object given the following optional parameters: a security descriptor of the object's parent directory, an explicit security descriptor for the object, and the object type.

NTSTATUS
  SeAssignSecurityEx (
    IN PSECURITY_DESCRIPTOR  ParentDescriptor  OPTIONAL,
    IN PSECURITY_DESCRIPTOR  ExplicitDescriptor  OPTIONAL,
    OUT PSECURITY_DESCRIPTOR  *NewDescriptor,
    IN GUID  *ObjectType  OPTIONAL,
    IN BOOLEAN  IsDirectoryObject,
    IN ULONG  AutoInheritFlags,
    IN PSECURITY_SUBJECT_CONTEXT  SubjectContext,
    IN PGENERIC_MAPPING  GenericMapping,
    IN POOL_TYPE  PoolType
    );

Parameters

ParentDescriptor
Pointer to the SECURITY_DESCRIPTOR of the parent object that contains the new object being created. ParentDescriptor can be NULL, or have a NULL system access control list (SACL) or a NULL discretionary access control list (DACL).
ExplicitDescriptor
Pointer to an explicit SECURITY_DESCRIPTOR that is applied to the new object. ExplicitDescriptor can be NULL, or have a NULL SACL or a NULL DACL.
NewDescriptor
Receives a pointer to the returned SECURITY_DESCRIPTOR. SeAssignSecurityEx allocates the buffer from the paged memory pool.
ObjectType
Pointer to a GUID for the type of object being created. If the object does not have a GUID, ObjectType must be set to NULL.
IsDirectoryObject
Specifies whether the new object is a directory object. If IsDirectoryObject is set to TRUE, the new object is a directory object, otherwise the new object is not a directory object.
AutoInheritFlags
Specifies the type of automatic inheritance that is applied to access control entries (ACE) in the access control lists (ACL) specified by ParentDescriptor. AutoInheritFlags also controls privilege checking, owner checking, and setting a default owner and group for NewDescriptor. AutoInheritFlags must be set to a logical OR of one or more of the following values:
Value | Meaning
SEF_DACL_AUTO_INHERIT | ACEs in the DACL of ParentDescriptor are inherited by NewDescriptor, in addition to explicit ACEs specified by ExplicitDescriptor.
SEF_SACL_AUTO_INHERIT | ACEs in the SACL of ParentDescriptor are inherited by NewDescriptor, in addition to explicit ACEs specified by ExplicitDescriptor.
SEF_DEFAULT_DESCRIPTOR_FOR_OBJECT | ExplicitDescriptor is the default descriptor for the object type specified by ObjectType. ExplicitDescriptor is not used if ACEs are inherited from ParentDescriptor.
SEF_AVOID_PRIVILEGE_CHECK | Privilege checking is not done. This flag is useful with automatic inheritance because it avoids privilege checking on each child that needs to be updated.
SEF_AVOID_OWNER_CHECK | Owner checking is not done.
SEF_DEFAULT_OWNER_FROM_PARENT If an owner is specified by ExplicitDescriptor, this flag is not used, and the owner of NewDescriptor is set to the owner specified by ExplictDescriptor.

If an owner is not specified by ExplicitDescriptor, this flag is used in the following way: If the flag is set, the owner of NewDescriptor is set to the owner of ParentDescriptor. Otherwise, the owner of NewDescriptor is set to the owner specified by the SubjectContext.
SEF_DEFAULT_GROUP_FROM_PARENT If a group is specified by ExplicitDescriptor, this flag is not used, and the group of NewDescriptor is set to the group specified by ExplictDescriptor.

If a group is not specified by ExplicitDescriptor, this flag is used in the following way: If the flag is set, the group of NewDescriptor is set to the group of ParentDescriptor. Otherwise, the group of NewDescriptor is set to the group specified by the SubjectContext.

The assignment of system and discretionary ACLs is described in the following table:
Non-default explicit descriptor(1) | Default explicit descriptor(2) | NULL Explicit descriptor
ACL is inherited from parent descriptor(3). | Assign both inherited and explicit ACLs(5)(6). | Assign inherited ACL. | Assign inherited ACL.
ACL is not inherited from parent descriptor(4). | Assign non-default ACL. | Assign default ACL. | Assign no ACL.

Assignment Notes

  1. The SEF_DEFAULT_DESCRIPTOR_FOR_OBJECT flag is not specified.
  2. The SEF_DEFAULT_DESCRIPTOR_FOR_OBJECT flag is specified.
  3. The auto inherit flag for an ACL is specified (SEF_DACL_AUTO_INHERIT or SEF_SACL_AUTO_INHERIT).
  4. The automatic inherit flag for an ACL is not specified.
  5. ACEs with the INHERITED_ACE bit set in their AceFlags member are not copied to the assigned security descriptor.
  6. ACEs that are inherited from the parent descriptor are appended after the ACEs specified by the explicit descriptor.
SubjectContext
Pointer to a security context of the subject that is creating the object. SubjectContext is used to retrieve default security information for the new object, including the default owner, the primary group, and discretionary access control.
GenericMapping
Pointer to an array of access mask values that specify the mapping between each generic rights to object-specific rights.
PoolType
This parameter is unused. The buffer to hold the new security descriptor is always allocated from paged pool.

Return Value

SeAssignSecurityEx returns one of the following values:

STATUS_SUCCESS
The assignment was successful.
STATUS_INVALID_OWNER
The SID provided as the owner of the new security descriptor is not a SID that the caller is authorized to assign as the owner of an object.
STATUS_PRIVILEGE_NOT_HELD
The caller does not have the privilege (SeSecurityPrivilege) necessary to explicitly assign the specified SACL.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

SeAssignSecurityEx extends the basic operation of SeAssignSecurity in the following ways:

  • ObjectType optionally specifies an object type. Object-specific inheritance is controlled by the following members of an object-specific ACE: Flags, InheritedObjectType, and Header.AceFlags.
  • AutoInheritFlags specifies the type of automatic inheritance of ACEs that is used. AutoInheritFlags also controls privilege checking, owner checking, and setting a default owner and group for NewDescriptor.

For more information on security and access control, see the documentation on these topics in the Platform SDK.

SeAssignSecurityEx runs at IRQL PASSIVE_LEVEL.

See Also

SeAssignSecurity, SeDeassignSecurity, GENERIC_MAPPING, SECURITY_DESCRIPTOR


SeDeassignSecurity

SeDeassignSecurity deallocates the memory associated with a security descriptor that was assigned using SeAssignSecurity.

NTSTATUS
  SeDeassignSecurity(
    IN OUT PSECURITY_DESCRIPTOR  *SecurityDescriptor
    );

Parameters

SecurityDescriptor
Pointer to the buffered SECURITY_DESCRIPTOR being released.

Return Value

If the deallocation succeeds, SeDeassignSecurity returns STATUS_SUCCESS.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

Callers of SeDeassignSecurity must be running at IRQL PASSIVE_LEVEL.

See Also

SeAssignSecurity, SECURITY_DESCRIPTOR


SeSinglePrivilegeCheck

SeSinglePrivilegeCheck checks for the passed privilege value in the context of the current thread.

BOOLEAN
  SeSinglePrivilegeCheck(
    LUID  PrivilegeValue,
    KPROCESSOR_MODE  PreviousMode
    );

Parameters

PrivilegeValue
Specifies the LUID value of the privilege being checked.
PreviousMode
Specifies the previous execution mode, one of UserMode or KernelMode.

Return Value

SeSinglePrivilegeCheck returns TRUE if the current subject has the required privilege.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

If PreviousMode is KernelMode, the privilege check always succeeds. Otherwise, this routine uses the token of the user-mode thread to determine whether the current (user-mode) thread has been granted the given privilege.

Callers of SeSinglePrivilegeCheck must be running at IRQL PASSIVE_LEVEL.

See Also

RtlConvertLongToLuid, RtlConvertUlongToLuid, RtlEqualLuid, SeValidSecurityDescriptor, LUID


SeValidSecurityDescriptor

SeValidSecurityDescriptor returns whether a given security descriptor is structurally valid.

BOOLEAN
  SeValidSecurityDescriptor(
    IN ULONG  Length,
    IN PSECURITY_DESCRIPTOR  SecurityDescriptor
    );

Parameters

Length
Specifies the size in bytes of the given security descriptor.
SecurityDescriptor
Pointer to the self-relative SECURITY_DESCRIPTOR, which must be buffered somewhere in system space.

Return Value

SeValidSecurityDescriptor returns TRUE if the buffered security descriptor is structurally valid.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

SeValidSecurityDescriptor does not enforce policy. It simply checks that the given security descriptor data is formatted correctly. In particular, it checks the revision information, self relativity, owner, alignment, and, if available, SID, group, DACL, ACL, and/or SACL do not overflow the given Length. Consequently, callers of SeValidSecurityDescriptor cannot assume that a returned TRUE implies that the given security descriptor necessarily has valid contents.

If SeValidSecurityDescriptor returns TRUE, the given security descriptor can be passed on to another kernel-mode component because it is structurally valid. Otherwise, passing a structurally invalid security descriptor to be manipulated by another kernel-mode component can cause undefined results or even a system bugcheck.

To validate a security descriptor that was passed in from user mode, call RtlValidSecurityDescriptor rather than SeValidSecurityDescriptor.

Callers of SeValidSecurityDescriptor must be running at IRQL PASSIVE_LEVEL.

See Also

RtlValidSecurityDescriptor, SECURITY_DESCRIPTOR


ZwXxx Routines

The Zw Xxx routines provide a set of system entry points parallel to some of the executive's system services. A call to a Zw Xxx routine from kernel-mode code results in a call to the corresponding system service.

The caller's access rights are not checked for validity by the system, and the call does not cause the previous mode to be set to user mode. It is the responsibility of kernel-mode code to check all user-supplied arguments for validity before calling a Zw Xxx routine.

The Zw Xxx routines are in alphabetical order.

For an overview of the functionality of these routines, see Summary of Kernel-Mode Support Routines.


ZwClose

ZwClose closes object handles.

NTSTATUS
  ZwClose(
    IN HANDLE  Handle
    );

Parameters

Handle
Is a valid handle for an open object.

Include

wdm.h or ntddk.h

Return Value

ZwClose can return one of the following:

STATUS_SUCCESS
STATUS_OBJECT_TYPE_MISMATCH
STATUS_ACCESS_DENIED
STATUS_INVALID_HANDLE

Comments

ZwClose is a generic routine that operates on any type of object.

Closing an open handle for an object causes that handle to become invalid. The reference count for the object handle is decremented and object retention checks are performed.

A named object is not actually deleted until all of its valid handles are closed and no referenced pointers remain.

Any handle obtained from one of the ZwCreate Xxx routines should eventually be released by calling ZwClose. Each such handle is created on a process-specific basis, so a driver must use each handle it creates in the context of a thread running in the appropriate process. For example, a handle returned by ZwCreateKey to a DriverEntry routine, which executes in a system process, cannot be subsequently used by the same driver's dispatch routines, which usually execute either in the context of the thread issuing the current I/O request or, for lower-level drivers, in an arbitrary thread context.

Callers of ZwClose must be running at IRQL PASSIVE_LEVEL.

See Also

ZwCreateDirectoryObject, ZwCreateFile, ZwCreateKey, ZwOpenKey, ZwOpenSection


ZwCreateDirectoryObject

ZwCreateDirectoryObject creates or opens a directory object, which is a container for other objects.

NTSTATUS
  ZwCreateDirectoryObject(
    OUT PHANDLE  DirectoryHandle,
    IN ACCESS_MASK  DesiredAccess,
    IN POBJECT_ATTRIBUTES  ObjectAttributes
    );

Parameters

DirectoryHandle
Points to a variable that receives the directory object handle if the call is successful.
DesiredAccess
Specifies the ACCESS_MASK value that expresses type of access that the caller requires to the directory object. This value is compared with the granted access on an existing directory object. A caller can specify one or a combination of the following:
DesiredAccess Flags | Meaning
DIRECTORY_QUERY | Query access to the directory object
DIRECTORY_TRAVERSE | Name-lookup access to the directory object
DIRECTORY_CREATE_OBJECT | Name-creation access to the directory object
DIRECTORY_CREATE_SUBDIRECTORY | Subdirectory-creation access to the directory object
DIRECTORY_ALL_ACCESS | All of the preceding

ObjectAttributes
Points to a structure that specifies the object's attributes, which has already been initialized with InitializeObjectAttributes. If the caller is not running in the system process context, it must set the OBJ_KERNEL_HANDLE attribute for ObjectAttributes.

Include

wdm.h or ntddk.h

Return Value

ZwCreateDirectoryObject can return one of the following values:

STATUS_SUCCESS
STATUS_ACCESS_DENIED
STATUS_ACCESS_VIOLATION
STATUS_DATATYPE_MISALIGNMENT

Comments

A directory object is a container for other objects. Note that file system directories are not represented by directory objects, but rather by file objects.

Directory objects are an integral part of the system's object management and are manipulated indirectly as a result of other operations. For example, when a device object is created, its name is inserted in a directory object and the pointer counts of both the directory object and the named device object are incremented. Any named object's header contains a pointer to the directory object containing that object's name.

Drivers that create a set of device objects might set up a directory object when they initialize. For example, a disk driver might use this technique to group the device object representing a physical disk and the device objects representing partitions on that disk in a driver-created directory object.

Before the DriverEntry routine returns control, such a driver calls ZwMakeTemporaryObject if its directory object was initialized with the permanent attribute, and ZwClose to release the directory object created to hold such a group of related device objects.

If a directory object was initialized as temporary and its handle count becomes zero, the directory object's name is deleted. Name deletion occurs for a temporary object when the last handle to the object has been closed. A driver also can delete a directory object it creates when the object is no longer needed by using this technique.

Driver routines that run in a process context other than that of the system process must set the OBJ_KERNEL_HANDLE attribute for the ObjectAttributes parameter of ZwCreateDirectoryObject. This restricts the use of the handle returned by ZwCreateDirectoryObject to processes running only in kernel mode. Otherwise, the thread handle can be accessed by the process in whose context the driver is running. Drivers can call InitializeObjectAttributes to set the OBJ_KERNEL_HANDLE attribute as follows.

InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);

Callers of ZwCreateDirectoryObject must be running at IRQL PASSIVE_LEVEL.

See Also

ACCESS_MASK, InitializeObjectAttributes, ObDereferenceObject, ZwClose, ZwMakeTemporaryObject


ZwCreateFile

ZwCreateFile either causes a new file or directory to be created, or it opens an existing file, device, directory, or volume, giving the caller a handle for the file object.

NTSTATUS
  ZwCreateFile(
    OUT PHANDLE  FileHandle,
    IN ACCESS_MASK  DesiredAccess,
    IN POBJECT_ATTRIBUTES  ObjectAttributes,
    OUT PIO_STATUS_BLOCK  IoStatusBlock,
    IN PLARGE_INTEGER  AllocationSize  OPTIONAL,
    IN ULONG  FileAttributes,
    IN ULONG  ShareAccess,
    IN ULONG  CreateDisposition,
    IN ULONG  CreateOptions,
    IN PVOID  EaBuffer  OPTIONAL,
    IN ULONG  EaLength
    );

Parameters

FileHandle
Points to a variable that receives the file handle if the call is successful.
DesiredAccess
Specifies the ACCESS_MASK value that expresses the type of access that the caller requires to the file or directory. The set of system-defined DesiredAccess flags determines the following specific access rights for file objects:
DesiredAccess Flags | Meaning
DELETE | The file can be deleted.
FILE_READ_DATA | Data can be read from the file.
FILE_READ_ATTRIBUTES | FileAttributes flags, described later, can be read.
FILE_READ_EA | Extended attributes associated with the file can be read. This flag is irrelevant to device and intermediate drivers.
READ_CONTROL | The access control list (ACL) and ownership information associated with the file can be read.
FILE_WRITE_DATA | Data can be written to the file.
FILE_WRITE_ATTRIBUTES | FileAttributes flags can be written.
FILE_WRITE_EA | Extended attributes (EAs) associated with the file can be written. This flag is irrelevant to device and intermediate drivers.
FILE_APPEND_DATA | Data can be appended to the file.
WRITE_DAC | The discretionary access control list (DACL) associated with the file can be written.
WRITE_OWNER | Ownership information associated with the file can be written.
SYNCHRONIZE | The returned FileHandle can be waited on to synchronize with the completion of an I/O operation.
FILE_EXECUTE | Data can be read into memory from the file using system paging I/O. This flag is irrelevant to device and intermediate drivers.

Callers of ZwCreateFile can specify one or a combination of the following, possibly ORed with additional compatible flags from the preceding DesiredAccess Flags list, for any file object that does not represent a directory file:
DesiredAccess to File Values | Maps to DesiredAccess Flags
GENERIC_READ | STANDARD_RIGHTS_READ, FILE_READ_DATA, FILE_READ_ATTRIBUTES, and FILE_READ_EA
GENERIC_WRITE | STANDARD_RIGHTS_WRITE, FILE_WRITE_DATA, FILE_WRITE_ATTRIBUTES, FILE_WRITE_EA, and FILE_APPEND_DATA
GENERIC_EXECUTE | STANDARD_RIGHTS_EXECUTE, SYNCHRONIZE, and FILE_EXECUTE. This value is irrelevant to device and intermediate drivers.

The STANDARD_RIGHTS_XXX are predefined system values used to enforce security on system objects.

To open or create a directory file, as also indicated with the CreateOptions parameter, callers of ZwCreateFile can specify one or a combination of the following, possibly ORed with one or more compatible flags from the preceding DesiredAccess Flags list:
DesiredAccess to Directory Values | Meaning
FILE_LIST_DIRECTORY | Files in the directory can be listed.
FILE_TRAVERSE | The directory can be traversed: that is, it can be part of the pathname of a file.

The FILE_READ_DATA, FILE_WRITE_DATA, FILE_EXECUTE, and FILE_APPEND_DATA DesiredAccess flags are incompatible with creating or opening a directory file.

ObjectAttributes
Points to a structure already initialized with InitializeObjectAttributes. Members of this structure for a file object include the following:
Member Value
ULONG Length
Specifies the number of bytes of ObjectAttributes data supplied. This value must be at least sizeof(OBJECT_ATTRIBUTES).
PUNICODE_STRING ObjectName
Points to a buffered Unicode string naming the file to be created or opened. This value must be a fully qualified file specification or the name of a device object, unless it is the name of a file relative to the directory specified by RootDirectory. For example, \Device\Floppy1\myfile.dat or \??\B:\myfile.dat could be the fully qualified file specification, provided that the floppy driver and overlying file system are already loaded. (Note: \?? replaces \DosDevices as the name of the Win32® object namespace. \DosDevices will still work, but \?? is translated faster by the object manager.)
HANDLE RootDirectory
Optionally specifies a handle to a directory obtained by a preceding call to ZwCreateFile. If this value is NULL, the ObjectName member must be a fully qualified file specification that includes the full path to the target file. If this value is nonNULL, the ObjectName member specifies a file name relative to this directory.
PSECURITY_DESCRIPTOR SecurityDescriptor
Optionally specifies a security descriptor to be applied to a file. ACLs specified by such a security descriptor are only applied to the file when it is created. If the value is NULL when a file is created, the ACL placed on the file is file-system-dependent; most file systems propagate some part of such an ACL from the parent directory file combined with the caller's default ACL. Device and intermediate drivers can set this member to NULL.
PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService
Specifies the access rights a server should be given to the client's security context. This value is nonNULL only when a connection to a protected server is established, allowing the caller to control which parts of the caller's security context are made available to the server and whether the server is allowed to impersonate the caller. Device and intermediate drivers usually set this member to NULL.
ULONG Attributes
Is a set of flags that controls the file object attributes. This value can be zero or OBJ_CASE_INSENSITIVE, which indicates that name-lookup code should ignore the case of ObjectName rather than performing an exact-match search. The value OBJ_INHERIT is irrelevant to device and intermediate drivers.

If the caller is not running in the system process context, it must set the OBJ_KERNEL_HANDLE attribute for ObjectAttributes.

IoStatusBlock
Points to a variable that receives the final completion status and information about the requested operation. On return from ZwCreateFile, the Information member contains one of the following values:

FILE_CREATED
FILE_OPENED
FILE_OVERWRITTEN
FILE_SUPERSEDED
FILE_EXISTS
FILE_DOES_NOT_EXIST

AllocationSize
Optionally specifies the initial allocation size in bytes for the file. A nonzero value has no effect unless the file is being created, overwritten, or superseded.
FileAttributes
Explicitly specified attributes are applied only when the file is created, superseded, or, in some cases, overwritten. By default, this value is FILE_ATTRIBUTE_NORMAL, which can be overridden by an ORed combination of one or more FILE_ATTRIBUTE_xxxx flags, which are defined in wdm.h and ntddk.h. For a list of flags that can be used with ZwCreateFile, see CreateFile in the Platform SDK documentation.
ShareAccess
Specifies the type of share access that the caller would like to the file, as zero, or as one or a combination of the following:
ShareAccess Flags | Meaning
FILE_SHARE_READ | The file can be opened for read access by other threads' calls to ZwCreateFile.
FILE_SHARE_WRITE | The file can be opened for write access by other threads' calls to ZwCreateFile.
FILE_SHARE_DELETE | The file can be opened for delete access by other threads' calls to ZwCreateFile.

Device and intermediate drivers usually set ShareAccess to zero, which gives the caller exclusive access to the open file.

CreateDisposition
Specifies what to do, depending on whether the file already exists, as one of the following:
CreateDisposition Values | Meaning
FILE_SUPERSEDE | If the file already exists, replace it with the given file. If it does not, create the given file.
FILE_CREATE | If the file already exists, fail the request and do not create or open the given file. If it does not, create the given file.
FILE_OPEN | If the file already exists, open it instead of creating a new file. If it does not, fail the request and do not create a new file.
FILE_OPEN_IF | If the file already exists, open it. If it does not, create the given file.
FILE_OVERWRITE | If the file already exists, open it and overwrite it. If it does not, fail the request.
FILE_OVERWRITE_IF | If the file already exists, open it and overwrite it. If it does not, create the given file.

CreateOptions
Specifies the options to be applied when creating or opening the file, as a compatible combination of the following flags:
CreateOptions Flags | Meaning
FILE_DIRECTORY_FILE The file being created or opened is a directory file. With this flag, the CreateDisposition parameter must be set to one of FILE_CREATE, FILE_OPEN, or FILE_OPEN_IF. With this flag, other compatible CreateOptions flags include only the following: FILE_SYNCHRONOUS_IO_ALERT, FILE_SYNCHRONOUS_IO
_NONALERT, FILE_WRITE_THROUGH, FILE_OPEN_FOR_BACKUP_INTENT, and FILE_OPEN_BY_FILE_ID.
FILE_NON_DIRECTORY_FILE | The file being opened must not be a directory file or this call will fail. The file object being opened can represent a data file, a logical, virtual, or physical device, or a volume.
FILE_WRITE_THROUGH System services, FSDs, and drivers that write data to the file must actually transfer the data into the file before any requested write operation is considered complete. This flag is automatically set if the CreateOptions flag FILE_NO_INTERMEDIATE
_BUFFERING is set.
FILE_SEQUENTIAL_ONLY | All accesses to the file will be sequential.
FILE_RANDOM_ACCESS | Accesses to the file can be random, so no sequential read-ahead operations should be performed on the file by FSDs or the system.
FILE_NO_INTERMEDIATE_BUFFERING | The file cannot be cached or buffered in a driver's internal buffers. This flag is incompatible with the DesiredAccess FILE_APPEND_DATA flag.
FILE_SYNCHRONOUS_IO_ALERT | All operations on the file are performed synchronously. Any wait on behalf of the caller is subject to premature termination from alerts. This flag also causes the I/O system to maintain the file position context. If this flag is set, the DesiredAccess SYNCHRONIZE flag also must be set.
FILE_SYNCHRONOUS_IO_NONALERT | All operations on the file are performed synchronously. Waits in the system to synchronize I/O queuing and completion are not subject to alerts. This flag also causes the I/O system to maintain the file position context. If this flag is set, the DesiredAccess SYNCHRONIZE flag also must be set.
FILE_CREATE_TREE_CONNECTION | Create a tree connection for this file in order to open it over the network. This flag is irrelevant to device and intermediate drivers.
FILE_COMPLETE_IF_OPLOCKED | Complete this operation immediately with an alternate success code if the target file is oplocked, rather than blocking the caller's thread. If the file is oplocked, another caller already has access to the file over the network. This flag is irrelevant to device and intermediate drivers.
FILE_NO_EA_KNOWLEDGE | If the extended attributes on an existing file being opened indicate that the caller must understand EAs to properly interpret the file, fail this request because the caller does not understand how to deal with EAs. Device and intermediate drivers can ignore this flag.
FILE_DELETE_ON_CLOSE | Delete the file when the last handle to it is is passed to ZwClose.
FILE_OPEN_BY_FILE_ID | The file name contains the name of a device and a 64-bit ID to be used to open the file. This flag is irrelevant to device and intermediate drivers.
FILE_OPEN_FOR_BACKUP_INTENT | The file is being opened for backup intent, hence, the system should check for certain access rights and grant the caller the appropriate accesses to the file before checking the input DesiredAccess against the file's security descriptor. This flag is irrelevant to device and intermediate drivers.

EaBuffer
For device and intermediate drivers, this parameter must be a NULL pointer.
EaLength
For device and intermediate drivers, this parameter must be zero.

Include

wdm.h or ntddk.h

Return Value

ZwCreateFile either returns STATUS_SUCCESS or an appropriate error status. If it returns an error status, the caller can find more information about the cause of the failure by checking the IoStatusBlock.

Comments

The handle, given by ZwCreateFile, can be used by subsequent calls to manipulate data within the file or the file object's state or attributes. For example, a driver might call this routine during initialization to open a file of microcode for its device.

There are two alternate ways to specify the name of the file to be created or opened with ZwCreateFile:

  1. As a fully qualified pathname, supplied in the ObjectName member of the input ObjectAttributes
  2. As pathname relative to the directory file represented by the handle in the RootDirectory member of the input ObjectAttributes

Certain DesiredAccess flags and combinations of flags have the following effects:

  • For a caller to synchronize an I/O completion by waiting on the returned FileHandle, the SYNCHRONIZE flag must be set. Otherwise, a caller that is a device or intermediate driver must synchronize an I/O completion by using an event object.
  • If only the FILE_APPEND_DATA and SYNCHRONIZE flags are set, the caller can write only to the end of the file, and any offset information on writes to the file is ignored. However, the file will automatically be extended as necessary for this type of write operation.
  • Setting the FILE_WRITE_DATA flag for a file also allows writes beyond the end of the file to occur. The file is automatically extended for this type of write, as well.
  • If only the FILE_EXECUTE and SYNCHRONIZE flags are set, the caller cannot directly read or write any data in the file using the returned FileHandle: that is, all operations on the file occur through the system pager in response to instruction and data accesses. Device and intermediate drivers should not set the FILE_EXECUTE flag in DesiredAccess.

The ShareAccess parameter determines whether separate threads can access the same file, possibly simultaneously. Provided that both file openers have the privilege to access a file in the specified manner, the file can be successfully opened and shared. If the original caller of ZwCreateFile does not specify FILE_SHARE_READ, FILE_SHARE_WRITE, or FILE_SHARE_DELETE, no other open operations can be performed on the file: that is, the original caller is given exclusive access to the file.

In order for a shared file to be successfully opened, the requested DesiredAccess to the file must be compatible with both the DesiredAccess and ShareAccess specifications of all preceding opens that have not yet been released with ZwClose. That is, the DesiredAccess specified to ZwCreateFile for a given file must not conflict with the accesses that other openers of the file have disallowed.

The CreateDisposition value FILE_SUPERSEDE requires that the caller have DELETE access to a existing file object. If so, a successful call to ZwCreateFile with FILE_SUPERSEDE on an existing file effectively deletes that file, and then recreates it. This implies that, if the file has already been opened by another thread, it opened the file by specifying a ShareAccess parameter with the FILE_SHARE_DELETE flag set. Note that this type of disposition is consistent with the POSIX style of overwriting files.

The CreateDisposition values FILE_OVERWRITE_IF and FILE_SUPERSEDE are similar. If ZwCreateFile is called with a existing file and either of these CreateDisposition values, the file will be replaced.

Overwriting a file is semantically equivalent to a supersede operation, except for the following:

  • The caller must have write access to the file, rather than delete access. This implies that, if the file has already been opened by another thread, it opened the file with the FILE_SHARE_WRITE flag set in the input ShareAccess.
  • The specified file attributes are logically ORed with those already on the file. This implies that, if the file has already been opened by another thread, a subsequent caller of ZwCreateFile cannot disable existing FileAttributes flags but can enable additional flags for the same file. Note that this style of overwriting files is consistent with MS-DOS®, Windows® 3.1, and with OS/2.

The CreateOptions FILE_DIRECTORY_FILE value specifies that the file to be created or opened is a directory file. When a directory file is created, the file system creates an appropriate structure on the disk to represent an empty directory for that particular file system's on-disk structure. If this option was specified and the given file to be opened is not a directory file, or if the caller specified an inconsistent CreateOptions or CreateDisposition value, the call to ZwCreateFile will fail.

The CreateOptions FILE_NO_INTERMEDIATE_BUFFERING flag prevents the file system from performing any intermediate buffering on behalf of the caller. Specifying this value places certain restrictions on the caller's parameters to other Zw..File routines, including the following:

  • Any optional ByteOffset passed to ZwReadFile or ZwWriteFile must be an integral of the sector size.
  • The Length passed to ZwReadFile or ZwWriteFile, must be an integral of the sector size. Note that specifying a read operation to a buffer whose length is exactly the sector size might result in a lesser number of significant bytes being transferred to that buffer if the end of the file was reached during the transfer.
  • Buffers must be aligned in accordance with the alignment requirement of the underlying device. This information can be obtained by calling ZwCreateFile to get a handle for the file object that represents the physical device, and, then, calling ZwQueryInformationFile with that handle. For a list of the system FILE_XXX_ALIGNMENT values, see DEVICE_OBJECT.
  • Calls to ZwSetInformationFile with the FileInformationClass parameter set to FilePositionInformation must specify an offset that is an integral of the sector size.

The CreateOptions FILE_SYNCHRONOUS_IO_ALERT and FILE_SYNCHRONOUS_IO_NONALERT, which are mutually exclusive as their names suggest, specify that all I/O operations on the file are to be synchronous as long as they occur through the file object referred to by the returned FileHandle. All I/O on such a file is serialized across all threads using the returned handle. With either of these CreateOptions, the DesiredAccess SYNCHRONIZE flag must be set so that the I/O Manager will use the file object as a synchronization object. With either of these CreateOptions set, the I/O Manager maintains the "file position context" for the file object, an internal, current file position offset. This offset can be used in calls to ZwReadFile and ZwWriteFile. Its position also can be queried or set with ZwQueryInformationFile and ZwSetInformationFile.

Driver routines that run in a process context other than that of the system process must set the OBJ_KERNEL_HANDLE attribute for the ObjectAttributes parameter of ZwCreateFile. This restricts the use of the handle returned by ZwCreateFile to processes running only in kernel mode. Otherwise, the thread handle can be accessed by the process in whose context the driver is running. Drivers can call InitializeObjectAttributes to set the OBJ_KERNEL_HANDLE attribute as follows.

InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);

Callers of ZwCreateFile must be running at IRQL PASSIVE_LEVEL.

See Also

ACCESS_MASK, DEVICE_OBJECT, IO_STATUS_BLOCK, InitializeObjectAttributes, ZwOpenFile, ZwClose, ZwReadFile, ZwQueryInformationFile, ZwSetInformationFile, ZwWriteFile


ZwCreateKey

ZwCreateKey opens an existing key or creates a new key in the registry.

NTSTATUS
  ZwCreateKey(
    OUT PHANDLE  KeyHandle,
    IN ACCESS_MASK  DesiredAccess,
    IN POBJECT_ATTRIBUTES  ObjectAttributes,
    IN ULONG  TitleIndex,
    IN PUNICODE_STRING  Class  OPTIONAL,
    IN ULONG  CreateOptions,
    OUT PULONG  Disposition  OPTIONAL
    );

Parameters

KeyHandle
Points to a returned handle for a newly created or existing key if this call is successful.
DesiredAccess
Specifies the ACCESS_MASK value that expresses the type of access that the caller requires to the key. The set of system-defined DesiredAccess flags determines the following specific access rights for key objects:
DesiredAccess Flags | Meaning
KEY_QUERY_VALUES | Value entries for the key can be read.
KEY_SET_VALUE | Value entries for the key can be written.
KEY_CREATE_SUB_KEY | Subkeys for the key can be created.
KEY_ENUMERATE_SUB_KEYS | All subkeys for the key can be read.
KEY_NOTIFY | This flag is irrelevant to device and intermediate drivers, and to other kernel-mode code.
KEY_CREATE_LINK | A symbolic link to the key can be created. This flag is irrelvant to device and intermediate drivers.

Callers of ZwCreateKey can specify one or a compatible combination of the following for any key object:
DesiredAccess to Key Values | Maps to DesiredAccess Flags
KEY_READ | STANDARD_RIGHTS_READ, KEY_QUERY_VALUES, KEY_ENUMERATE_SUB_KEYS, and KEY_NOTIFY
KEY_WRITE | STANDARD_RIGHTS_WRITE, KEY_SET_VALUE, and KEY_CREATE_SUBKEY
KEY_EXECUTE | KEY_READ. This value is irrelevant to device and intermediate drivers.
KEY_ALL_ACCESS | STANDARD_RIGHTS_ALL, KEY_QUERY_VALUES, KEY_SET_VALUE, KEY_CREATE_SUB_KEY, KEY_ENUMERATE_SUBKEY, KEY_NOTIFY and KEY_CREATE_LINK

The STANDARD_RIGHTS_XXX are predefined system values used to enforce security on system objects.

ObjectAttributes
Points to the initialized object attributes of the key being opened or created. An ObjectName string for the key must be specified. If a RootDirectory handle also is supplied, the given name is relative to the key represented by the handle. Any given name must be within the object name space allocated to the registry, meaning that all names must begin with \Registry. RootHandle, if present, must be a handle to the root directory object, to \Registry, or to a key under \Registry. If the caller is not running in the system process context, it must set the OBJ_KERNEL_HANDLE attribute for ObjectAttributes. See InitializeObjectAttributes for details.
TitleIndex
Device and intermediate drivers should set this parameter to zero.
Class
Points to the object class of the key. To the Configuration Manager, this is just a Unicode string.
CreateOptions
Specifies options to be applied when creating a key, as a compatible combination of the following:
Value | Meaning
REG_OPTION_VOLATILE | Key is not to be stored across boots.
REG_OPTION_NON_VOLATILE | Key is preserved when the system is rebooted.
REG_OPTION_CREATE_LINK | The created key is a symbolic link. This value is irrelevant to device and intermediate drivers.
REG_OPTION_BACKUP_RESTORE | Key is being opened or created with special privileges allowing backup/restore operations. This value is irrelevant to device and intermediate drivers.

Disposition
Points to a variable that receives a value indicating whether a new key was created in the \Registry tree or an existing one opened:
Value | Meaning
REG_CREATED_NEW_KEY | A new key object was created.
REG_OPENED_EXISTING_KEY | An existing key object was opened.

Include

wdm.h or ntddk.h

Return Value

ZwCreateKey returns STATUS_SUCCESS if the given key was created or opened.

Comments

If the key specified by ObjectAttributes does not exist, an attempt is made to create it. For this attempt to succeed, the new key must be a direct subkey of the key referred to by KeyHandle, and the given KeyHandle must have been opened for KEY_CREATE_SUB_KEY access.

If the specified key already exists, it is opened and its value is not affected in any way.

The security attributes specified by ObjectAttributes when a key is created determine whether the specified DesiredAccess is granted on subsequent calls to ZwCreateKey and ZwOpenKey.

Driver routines that run in a process context other than that of the system process must set the OBJ_KERNEL_HANDLE attribute for the ObjectAttributes parameter of ZwCreateKey. This restricts the use of the handle returned by ZwCreateKey to processes running only in kernel mode. Otherwise, the thread handle can be accessed by the process in whose context the driver is running. Drivers can call InitializeObjectAttributes to set the OBJ_KERNEL_HANDLE attribute as follows.

InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);

Callers of ZwCreateKey must be running at IRQL PASSIVE_LEVEL.

See Also

ACCESS_MASK, InitializeObjectAttributes, ZwClose, ZwDeleteKey, ZwEnumerateKey, ZwEnumerateValueKey, ZwFlushKey, ZwOpenKey, ZwQueryValueKey, ZwSetValueKey


ZwDeleteKey

ZwDeleteKey deletes an open key from the registry.

NTSTATUS
  ZwDeleteKey(
    IN HANDLE  KeyHandle
    );

Parameters

KeyHandle
Is a handle returned by a successful call to ZwCreateKey or ZwOpenKey.

Include

wdm.h or ntddk.h

Return Value

ZwDeleteKey can return one of the following values:

STATUS_SUCCESS
STATUS_ACCESS_DENIED
STATUS_INVALID_HANDLE

Comments

The key must have been opened for DELETE access for a deletion to succeed; the DesiredAccess value KEY_ALL_ACCESS includes DELETE access. The actual storage for the key is deleted when the last handle to the key is closed.

A call to ZwDeleteKey causes the KeyHandle to become invalid.

Callers of ZwDeleteKey must be running at IRQL PASSIVE_LEVEL.

See Also

ZwClose, ZwCreateKey, ZwOpenKey


ZwEnumerateKey

ZwEnumerateKey returns information about the subkeys of an open key.

NTSTATUS
  ZwEnumerateKey(
    IN HANDLE  KeyHandle,
    IN ULONG  Index,
    IN KEY_INFORMATION_CLASS  KeyInformationClass,
    OUT PVOID  KeyInformation,
    IN ULONG  Length,
    OUT PULONG  ResultLength
    );

Parameters

KeyHandle
Is the handle, returned by a successful call to ZwCreateKey or ZwOpenKey, of the key whose subkeys are to be enumerated.
Index
Specifies the zero-based index of the subkey for which the information is requested.
KeyInformationClass
Specifies the type of information returned in the KeyInformation buffer as one of the following system-defined values:

KeyBasicInformation
KeyNodeInformation
KeyFullInformation

KeyInformation
Points to a caller-allocated buffer to receive the requested data.
Length
Is the size in bytes of the KeyInformation buffer, which the caller should set according to the given KeyInformationClass.
ResultLength
Points to the number of bytes actually returned to KeyInformation or, if the input Length is too small, points to the number of bytes required for the available information.

Include

wdm.h or ntddk.h

Return Value

ZwEnumerateKey returns STATUS_SUCCESS, together with the name of the Index subkey to the given KeyInformation buffer. Otherwise, ZwEnumerateKey can return one of the following:

STATUS_NO_MORE_ENTRIES
STATUS_BUFFER_OVERFLOW
STATUS_BUFFER_TOO_SMALL

Comments

The KeyHandle passed to ZwEnumerateKey must have been opened with the KEY_ENUMERATE_SUB_KEYS DesiredAccess flag set for this call to succeed. See ZwCreateKey for a description of possible values for DesiredAccess.

The Index parameter is simply a way to select among subkeys of the key referred to by the KeyHandle. Two calls to ZwEnumerateKey with the same Index are not guaranteed to return the same result.

Note that callers of the Rtl..Registry routines are required to provide the name of the key. Drivers can call ZwEnumerateKey to get unknown names of the subkeys for a key with a known name.

Callers of ZwEnumerateKey must be running at IRQL PASSIVE_LEVEL.

See Also

KEY_BASIC_INFORMATION, KEY_FULL_INFORMATION, KEY_NODE_INFORMATION, RtlCheckRegistryKey, RtlCreateRegistryKey, RtlDeleteRegistryValue, RtlQueryRegistryValues, RtlWriteRegistryValue, ZwCreateKey, ZwEnumerateValueKey, ZwOpenKey


ZwEnumerateValueKey

ZwEnumerateValueKey returns information about the value entries of an open key.

NTSTATUS
  ZwEnumerateValueKey(
    IN HANDLE  KeyHandle,
    IN ULONG  Index,
    IN KEY_VALUE_INFORMATION_CLASS  KeyValueInformationClass,
    OUT PVOID  KeyValueInformation,
    IN ULONG  Length,
    OUT PULONG  ResultLength
    );

Parameters

KeyHandle
Is the handle, returned by a successful call to ZwCreateKey or ZwOpenKey, of the key whose value entries are to be enumerated.
Index
Specifies the zero-based index of a subkey for which the value information is requested.
KeyValueInformationClass
Specifies the type of information returned in the KeyValueInformation buffer as one of the following:

KeyValueBasicInformation
KeyValueFullInformation
KeyValuePartialInformation

KeyValueInformation
Points to a caller-allocated buffer to receive the requested data.
Length
Is the size in bytes of the KeyValueInformation buffer, which the caller should set according to the given KeyValueInformationClass.
ResultLength
Points to number of bytes actually returned to KeyValueInformation or, if the input Length is too small, points to the number of bytes required for the available information.

Include

wdm.h or ntddk.h

Return Value

ZwEnumerateValueKey returns STATUS_SUCCESS, together with the name of the Index subkey to the given KeyValueInformation buffer. Otherwise, ZwEnumerateValueKey returns an error status value, including the following:

STATUS_NO_MORE_ENTRIES
STATUS_BUFFER_TOO_SMALL
STATUS_BUFFER_OVERFLOW
STATUS_INVALID_PARAMETER

Comments

The KeyHandle passed to ZwEnumerateValueKey must have been opened with the KEY_QUERY_VALUES DesiredAccess flag set for this call to succeed. See ZwCreateKey for a description of possible values for DesiredAccess.

The Index is simply a way to select among subkeys with value entries. Two calls to ZwEnumerateValueKey with the same Index are not guaranteed to return the same results.

Callers of ZwEnumerateValueKey must be running at IRQL PASSIVE_LEVEL.

See Also

ZwClose, ZwCreateKey, ZwOpenKey, ZwQueryValueKey


ZwFlushKey

ZwFlushKey forces a registry key to be committed to disk.

NTSTATUS
  ZwFlushKey(
    IN HANDLE  KeyHandle
    );

Parameters

KeyHandle
Is the handle, returned by a successful call to ZwCreateKey or ZwOpenKey, of the key to be flushed.

Include

ntddk.h

Return Value

ZwFlushKey returns STATUS_SUCCESS if the key information was transferred to disk.

Comments

Changes made by ZwCreateKey or ZwSetValueKey can be flushed to disk with ZwFlushKey. This routine does not return to its caller until any changed data associated with the given KeyHandle has been written to permanent store.

Note This routine can flush the entire registry. Accordingly, it can generate a great deal of I/O. Since the system automatically flushes key changes every few seconds, it is seldom necessary to call ZwFlushKey.

Callers of ZwFlushKey must be running at = IRQL PASSIVE_LEVEL.

See Also

ZwCreateKey, ZwOpenKey, ZwSetValueKey


ZwMakeTemporaryObject

ZwMakeTemporaryObject changes the attributes of an object to make it temporary.

NTSTATUS
  ZwMakeTemporaryObject(
    IN HANDLE  Handle
    );

Parameters

Handle
Specifies an open handle for an object.

Include

wdm.h or ntddk.h

Return Value

ZwMakeTemporaryObject can return one of the following:

STATUS_SUCCESS
STATUS_ACCESS_DENIED
STATUS_INVALID_HANDLE

Comments

ZwMakeTemporaryObject is a generic routine that operates on any type of object.

Making an object temporary causes the permanent flag of the associated object to be cleared. A temporary object has a name only as long as its handle count is greater than zero. When the handle count reaches zero, the system deletes the object name and adjusts the pointer count for the object appropriately.

Callers of ZwMakeTemporaryObject must be running at IRQL = PASSIVE_LEVEL.

See Also

InitializeObjectAttributes, ZwClose, ZwCreateDirectoryObject, ZwCreateFile


ZwMapViewOfSection

ZwMapViewOfSection maps a view of a section into the virtual address space of a subject process.

NTSTATUS
  ZwMapViewOfSection(
    IN HANDLE  SectionHandle,
    IN HANDLE  ProcessHandle,
    IN OUT PVOID  *BaseAddress,
    IN ULONG  ZeroBits,
    IN ULONG  CommitSize,
    IN OUT PLARGE_INTEGER  SectionOffset  OPTIONAL,
    IN OUT PSIZE_T  ViewSize,
    IN SECTION_INHERIT  InheritDisposition,
    IN ULONG  AllocationType,
    IN ULONG  Protect
    );

Parameters

SectionHandle
Is the handle returned by a successful call to ZwOpenSection.
ProcessHandle
Is the handle of an opened process object, representing the process for which the view should be mapped. Use the NtCurrentProcess() macro to specify the current process. The handle must have PROCESS_VM_OPERATION access to the process (described in Platform SDK documentation).
BaseAddress
Points to a variable that will receive the base address of the view. If the initial value of this argument is nonNULL, the view is allocated starting at the specified virtual address rounded down to the next 64-kilobyte address boundary.
ZeroBits
Specifies the number of high-order address bits that must be zero in the base address of the section view. The value of this argument must be less than 21 and is used only when the operating system determines where to allocate the view, as when BaseAddress is NULL.
CommitSize
Specifies the size, in bytes, of the initially committed region of the view. CommitSize is only meaningful for page-file backed sections. For mapped sections, both data and image are always committed at section creation time. This parameter is ignored for mapped files. This value is rounded up to the next host-page-size boundary.
SectionOffset
Points to the offset, in bytes, from the beginning of the section to the view. If this pointer is nonNULL, the given value is rounded down to the next allocation granularity size boundary.
ViewSize
Points to a variable that will receive the actual size, in bytes, of the view. If the value of this parameter is zero, a view of the section will be mapped starting at the specified section offset and continuing to the end of the section. Otherwise, the initial value of this argument specifies the size of the view, in bytes, and is rounded up to the next host page-size boundary.
InheritDisposition
Specifies how the view is to be shared by a child process created with a create process operation. Device and intermediate drivers should set this parameter to zero.
AllocationType
A set of flags that describes the type of allocation to be performed for the specified region of pages.
Protect
Specifies the protection for the region of initially committed pages. Device and intermediate drivers should set this value to PAGE_READWRITE.

Include

wdm.h or ntddk.h

Return Value

ZwMapViewOfSection can return one of the following:

STATUS_SUCCESS
STATUS_ACCESS_DENIED
STATUS_INVALID_HANDLE

Comments

Several different views of a section can be concurrently mapped into the virtual address space of a process. Likewise, several different views of a section can be concurrently mapped into the virtual address space of several processes.

If the specified section does not exist or the access requested is not allowed, ZwMapViewOfSection returns an error.

Callers of ZwMapViewOfSection must be running at IRQL PASSIVE_LEVEL.

See Also

ZwOpenSection, ZwUnmapViewOfSection


ZwOpenFile

ZwOpenFile opens an existing file, device, directory, or volume, and returns a handle for the file object.

NTSTATUS
  ZwOpenFile(
    OUT PHANDLE  FileHandle,
    IN ACCESS_MASK  DesiredAccess,
    IN POBJECT_ATTRIBUTES  ObjectAttributes,
    OUT PIO_STATUS_BLOCK  IoStatusBlock,
    IN ULONG  ShareAccess,
    IN ULONG  OpenOptions
    );

Parameters

FileHandle
Pointer to a handle for the opened file.
DesiredAccess
Specifies the ACCESS_MASK value that expresses the types of file access desired by the caller. For information about the types of access that can be specified, see ZwCreateFile.
ObjectAttributes
Pointer to a structure that a caller initializes with InitializeObjectAttributes. If the caller is not running in the system process context, it must set the OBJ_KERNEL_HANDLE attribute for ObjectAttributes. For more information about specifying object attributes, see ZwCreateFile.
IoStatusBlock
Pointer to a structure that contains information about the requested operation and the final completion status.
ShareAccess
Specifies the type of share access for the file. For more information, see ZwCreateFile.
OpenOptions
Specifies the options to be applied when opening the file. For more information, see ZwCreateFile.

Include

ntddk.h

Return value

ZwOpenFile either returns STATUS_SUCCESS or an appropriate error status. If it returns an error status, the caller can get more information about the error by checking status information returned in IoStatusBlock.

Comments

Driver routines that run in a process context other than that of the system process must set the OBJ_KERNEL_HANDLE attribute for the ObjectAttributes parameter of ZwOpenFile. This restricts the use of the handle returned by ZwOpenFile to processes running only in kernel mode. Otherwise, the thread handle can be accessed by the process in whose context the driver is running. Drivers can call InitializeObjectAttributes to set the OBJ_KERNEL_HANDLE attribute as follows.

InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);

ZwOpenFile provides a subset of the functionality provided by ZwCreateFile.

See Also

ACCESS_MASK, InitializeObjectAttributes, ZwCreateFile


ZwOpenKey

ZwOpenKey opens an existing key in the registry.

NTSTATUS
  ZwOpenKey(
    OUT PHANDLE  KeyHandle,
    IN ACCESS_MASK  DesiredAccess,
    IN POBJECT_ATTRIBUTES  ObjectAttributes
    );

Parameters

KeyHandle
Points to a returned handle for the key specified in ObjectAttributes if this call is successful.
DesiredAccess
Specifies the ACCESS_MASK value that expresses access rights to the key desired. If the caller is not running in the system process context, it must set the OBJ_KERNEL_HANDLE attribute for ObjectAttributes. See ZwCreateKey for a description of possible values for this parameter.
ObjectAttributes
Points to the initialized object attributes of the key being opened. See the description of ZwCreateKey for more information.

Include

wdm.h or ntddk.h

Return Value

ZwOpenKey returns STATUS_SUCCESS if the given key was opened. Otherwise, it can return an error status, including the following:

STATUS_INVALID_HANDLE
STATUS_ACCESS_DENIED

Comments

ZwOpenKey or ZwCreateKey must be called before any of the Zw...Key routines that require an input KeyHandle.

If the specified key does not exist or the DesiredAccess requested is not allowed, ZwOpenKey returns an error status, and the KeyHandle remains invalid.

ZwOpenKey ignores the security information in the input ObjectAttributes. Access rights for a key object can be set only when the key is created.

Driver routines that run in a process context other than that of the system process must set the OBJ_KERNEL_HANDLE attribute for the ObjectAttributes parameter of ZwOpenFile. This restricts the use of the handle returned by ZwOpenFile to processes running only in kernel mode. Otherwise, the thread handle can be accessed by the process in whose context the driver is running. Drivers can call InitializeObjectAttributes to set the OBJ_KERNEL_HANDLE attribute as follows.

InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);

Callers of ZwOpenKey must be running at IRQL PASSIVE_LEVEL.

See Also

ACCESS_MASK, InitializeObjectAttributes, ZwCreateKey, ZwDeleteKey, ZwEnumerateKey, ZwEnumerateValueKey, ZwFlushKey, ZwQueryKey, ZwQueryValueKey, ZwSetValueKey


ZwOpenSection

ZwOpenSection opens a handle for an existing section object.

NTSTATUS
  ZwOpenSection(
    OUT PHANDLE  SectionHandle,
    IN ACCESS_MASK  DesiredAccess,
    IN POBJECT_ATTRIBUTES  ObjectAttributes
    );

Parameters

SectionHandle
Points to a variable that will receive the section object handle if this call is successful.
DesiredAccess
Specifies an ACCESS_MASK value representing the requested access to the object. The set of system-defined DesiredAccess flags relevant to device and intermediate drivers are the following:
DesiredAccess Flags | Meaning
SECTION_MAP_WRITE | A mapped view can be written.
SECTION_MAP_READ | A mapped view can be read.

A caller can specify SECTION_ALL_ACCESS, which sets all of the defined flags ORed with the system-defined STANDARD_RIGHTS_REQUIRED.

ObjectAttributes
Points to the initialized object attributes of the section to be opened. If the caller is not running in the system process context, it must set the OBJ_KERNEL_HANDLE attribute for ObjectAttributes. For details, see InitializeObjectAttributes.

Include

wdm.h or ntddk.h

Return Value

ZwOpenSection can return one of the following:

STATUS_SUCCESS
STATUS_ACCESS_DENIED
STATUS_INVALID_HANDLE

Comments

If the specified section does not exist or the access requested is not allowed, the operation fails.

Driver routines that run in a process context other than that of the system process must set the OBJ_KERNEL_HANDLE attribute for the ObjectAttributes parameter of ZwOpenSection. This restricts the use of the handle returned by ZwOpenSection to processes running only in kernel mode. Otherwise, the thread handle can be accessed by the process in whose context the driver is running. Drivers can call InitializeObjectAttributes to set the OBJ_KERNEL_HANDLE attribute as follows.

InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);

Callers of ZwOpenSection must be running at PASSIVE_LEVEL.

See Also

ACCESS_MASK, InitializeObjectAttributes, ZwMapViewOfSection, ZwUnmapViewOfSection


ZwOpenSymbolicLinkObject

ZwOpenSymbolicLinkObject returns a handle to an existing symbolic link.

NTSTATUS
  ZwOpenSymbolicLinkObject(
    OUT PHANDLE  LinkHandle,
    IN ACCESS_MASK  DesiredAccess,
    IN POBJECT_ATTRIBUTES  ObjectAttributes
    );

Parameters

LinkHandle
Points to a returned handle for the symbolic link object specified in ObjectAttributes if the call was successful.
DesiredAccess
Specifies the ACCESS_MASK value that represents the type of access that the caller requires to the symbolic link object. This is most commonly GENERIC_READ access such that the returned handle can be used with ZwQuerySymbolicLinkObject.
ObjectAttributes
Points to the initialized object attributes for the symbolic link being opened. An ObjectName string for the symbolic link must be specified. If the caller is not running in the system process context, it must set the OBJ_KERNEL_HANDLE attribute for ObjectAttributes. For details, see InitializeObjectAttributes.

Include

ntddk.h

Return Value

ZwOpenSymbolicLinkObject returns STATUS_SUCCESS if the symbolic link was opened.

Comments

Driver routines that run in a process context other than that of the system process must set the OBJ_KERNEL_HANDLE attribute for the ObjectAttributes parameter of ZwOpenSymbolicLinkObject. This restricts the use of the handle returned by ZwOpenSymbolicLinkObject to processes running only in kernel mode. Otherwise, the thread handle can be accessed by the process in whose context the driver is running. Drivers can call InitializeObjectAttributes to set the OBJ_KERNEL_HANDLE attribute as follows.

InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);

Callers of this routine must be running at IRQL PASSIVE_LEVEL.

See Also

ACCESS_MASK, InitializeObjectAttributes, ZwQuerySymbolicLinkObject


ZwQueryInformationFile

ZwQueryInformationFile returns various kinds of information about a given file object.

NTSTATUS
  ZwQueryInformationFile(
    IN HANDLE  FileHandle,
    OUT PIO_STATUS_BLOCK  IoStatusBlock,
    OUT PVOID  FileInformation,
    IN ULONG  Length,
    IN FILE_INFORMATION_CLASS  FileInformationClass
    );

Parameters

FileHandle
Is the handle returned by a successful call to ZwCreateFile.
IoStatusBlock
Points to a variable that receives the final completion status and information about the operation.
FileInformation
Points to a caller-allocated buffer or variable that receives the desired information about the file. The contents of FileInformation are defined by the FileInformationClass parameter, described later.
Length
Specifies the size in bytes of FileInformation, which the caller should set according to the given FileInformationClass.
FileInformationClass
Specifies the type of information to be returned about the file, in the buffer specified by FileInformation. Device and intermediate drivers, can specify any of the following:
FileInformationClass Value | Meaning
FileBasicInformation | Return a FILE_BASIC_INFORMATION structure. The caller must have opened the file with the DesiredAccess FILE_READ_ATTRIBUTES flag set.
FileStandardInformation | Return a FILE_STANDARD_INFORMATION structure. The caller can query this information as long as the file is open, without any particular requirements for DesiredAccess.
FilePositionInformation | Return a FILE_POSITION_INFORMATION structure. The caller must have opened the file with the DesiredAccess FILE_READ_DATA or FILE_WRITE_DATA flag set and with either of the CreateOptions FILE_SYNCHRONOUS_IO_ALERT or FILE_SYNCHRONOUS_IO_NONALERT.
FileAlignmentInformation | Return a FILE_ALIGNMENT_INFORMATION structure. The caller can query this information as long as the file is open, without any particular requirements for DesiredAccess. This information is useful if the file was opened with the CreateOptions FILE_NO_INTERMEDIATE_BUFFERING flag set.
FileNameInformation Return a FILE_NAME_INFORMATION structure. This might include the full file path or only a portion of the path.
See the comments below for details on the file name syntax.

Include

wdm.h or ntddk.h

Return Value

ZwQueryInformationFile returns STATUS_SUCCESS or an appropriate error status. It also returns the number of bytes actually written to the given FileInformation buffer in the Information member of IoStatusBlock.

Comments

ZwQueryInformationFile returns information about the given file. Note that it returns zero in any member of a FILE_XXX_INFORMATION structure that is not supported by a particular device or file system. For example, the FAT file system does not support file-creation times, so ZwQueryInformationFile sets the CreationTime member of returned FILE_BASIC_INFORMATION to zero for files on a FAT partition.

Callers of ZwQueryInformationFile must be running at IRQL PASSIVE_LEVEL.

When FileInformationClass equals FileNameInformation, the file name is returned in the FILE_NAME_INFORMATION structure. The precise syntax of the file name depends on a number of factors:

If the file was opened by submitting a full path and file name to ZwCreateFile, then ZwQueryInformationFile returns that full path and file name.

If the ObjectAttributes->RootDirectory handle was opened by name in a call to ZwCreateFile, and subsequently the file was opened by ZwCreateFile relative to this root directory handle, then the full path and file name are returned.

If the ObjectAttributes->RootDirectory handle was opened by file ID (using the FILE_OPEN_BY_FILE_ID flag) in a call to ZwCreateFile, and subsequently the file was opened by ZwCreateFile relative to this root directory handle, then only the relative path will be returned.

However, if the user has SeChangeNotifyPrivilege (described in Platform SDK documentation), the full path and file name will be returned in all cases.

If only the relative path is returned, the file name string will not begin with a backslash.

If the full path and file name are returned, the string will begin with a single backslash, regardless of its location. Thus the file C:\dir1\dir2\filename.ext will appear as \dir1\dir2\filename.ext, while the file \\server\share\dir1\dir2\filename.ext will appear as \server\share\dir1\dir2\filename.ext.

See Also

FILE_ALIGNMENT_INFORMATION, FILE_BASIC_INFORMATION, FILE_NAME_INFORMATION, FILE_POSITION_INFORMATION, FILE_STANDARD_INFORMATION, ZwCreateFile, ZwSetInformationFile


ZwQueryKey

ZwQueryKey provides data about the class of a key, and the number and sizes of its subkeys.

NTSTATUS
  ZwQueryKey(
    IN HANDLE  KeyHandle,
    IN KEY_INFORMATION_CLASS  KeyInformationClass,
    OUT PVOID  KeyInformation,
    IN ULONG  Length,
    OUT PULONG  ResultLength
    );

Parameters

KeyHandle
Is the handle, returned by a successful call to ZwCreateKey or ZwOpenKey, of the key to be queried.
KeyInformationClass
Specifies the type of information returned in the buffer as one of the following:

KeyBasicInformation
KeyFullInformation
KeyNodeInformation

KeyInformation
Points to a caller-allocated buffer to receive the requested data.
Length
Is the size in bytes of the KeyInformation buffer, which the caller should set according to the given KeyInformationClass.
ResultLength
Points to number of bytes actually returned to KeyInformation or, if the input Length is too small, points to the number of bytes required for the available information.

Include

wdm.h or ntddk.h

Return Value

ZwQueryKey returns STATUS_SUCCESS if it returned the requested information in the KeyInformation buffer. Otherwise, ZwQueryKey can return one of the following:

STATUS_BUFFER_TOO_SMALL
STATUS_BUFFER_OVERFLOW
STATUS_INVALID_PARAMETER

Comments

The KeyHandle passed to ZwQueryKey must have been opened with the KEY_QUERY_KEY DesiredAccess flag set for this call to succeed. See ZwCreateKey for a description of possible values for DesiredAccess.

ZwQueryKey returns information about the size of the value entries, the number of subkeys, the length of their names, and the size of their value entries that its caller can use to allocate buffers for registry data.

For example, a successful caller of ZwQueryKey might allocate a buffer for a subkey, call ZwEnumerateKey to get the name of the subkey, and pass that name to an Rtl..Registry routine.

Callers of ZwQueryKey must be running at IRQL = PASSIVE_LEVEL.

See Also

KEY_BASIC_INFORMATION, KEY_FULL_INFORMATION, KEY_NODE_INFORMATION, ZwClose, ZwEnumerateKey, ZwOpenKey


ZwQuerySymbolicLinkObject

ZwQuerySymbolicLinkObject returns a Unicode string containing the target of the symbolic link.

NTSTATUS
  ZwQuerySymbolicLinkObject(
    IN HANDLE LinkHandle,
    IN OUT PUNICODE_STRING LinkTarget,
    OUT PULONG ReturnedLength OPTIONAL
    );

Parameters

LinkHandle
Specifies a valid handle to an open symbolic link object obtained by calling ZwOpenSymbolicLinkObject.
LinkTarget
Points to an initialized Unicode string that contains the target of the symbolic link, specified by LinkHandle, if the call was successful.
ReturnedLength
Optionally, points to a unsigned long integer that on input contains the maximum number of bytes to copy into the Unicode string at LinkTarget. On output, the unsigned long integer contains the length of the Unicode string naming the target of the symbolic link.

Include

ntddk.h

Return Value

ZwOpenSymbolicLinkObject returns either STATUS_SUCCESS to indicate the routine completed without error or STATUS_BUFFER_TOO_SMALL if the Unicode string provided at LinkTarget is too small to hold the returned string.

Comments

Before calling this routine, driver writers must ensure that the Unicode string at LinkTarget has been properly initialized and a buffer for the string has been allocated. The MaximumLength and Buffer members of the Unicode string must be set before calling ZwQuerySymbolicLinkObject or the call will fail.

If ZwQuerySymbolicLinkObject returns STATUS_BUFFER_TOO_SMALL drivers should examine the value returned at ReturnedLength. The number returned in this variable indicates the maximum length that the Unicode string for the target of the symbolic link.

Callers of this routine must be running at IRQL PASSIVE_LEVEL.

See Also

ZwOpenSymbolicLinkObject


ZwQueryValueKey

ZwQueryValueKey returns the value entries for an open registry key.

NTSTATUS
  ZwQueryValueKey(
    IN HANDLE  KeyHandle,
    IN PUNICODE_STRING  ValueName,
    IN KEY_VALUE_INFORMATION_CLASS  KeyValueInformationClass,
    OUT PVOID  KeyValueInformation,
    IN ULONG  Length,
    OUT PULONG  ResultLength
    );

Parameters

KeyHandle
Is the handle, returned by a successful call to ZwCreateKey or ZwOpenKey, of key for which value entries are to be read.
ValueName
Points to the name of the value entry for which the data is requested.
KeyValueInformationClass
Specifies the type of information requested as one of the following:

KeyValueBasicInformation
KeyValueFullInformation
KeyValuePartialInformation

KeyValueInformation
Points to a caller-allocated buffer to receive the requested data.
Length
Is the size in bytes of the KeyValueInformation buffer, which the caller should set according to the given KeyValueInformationClass.
ResultLength
Points to number of bytes actually returned to KeyValueInformation or, if the input Length is too small, points to the number of bytes required for the available information.

Include

wdm.h or ntddk.h

Return Value

ZwQueryValueKey returns STATUS_SUCCESS if it returned the requested information in the KeyValueInformation buffer. Otherwise, ZwQueryValueKey can return one of the following:

STATUS_BUFFER_OVERFLOW
STATUS_BUFFER_TOO_SMALL
STATUS_INVALID_PARAMETER
STATUS_OBJECT_NAME_NOT_FOUND

Warning: If KeyValueBasicInformation is specified, Windows 98/Me returns STATUS_SUCCESS even if the specified registry key or value name does not exist.

Comments

The KeyHandle passed to ZwQueryValueKey must have been opened with the KEY_QUERY_VALUES DesiredAccess flag set for this call to succeed. See ZwCreateKey for a description of possible values for DesiredAccess.

Callers of ZwQueryValueKey must be running at IRQL PASSIVE_LEVEL.

See Also

KEY_VALUE_BASIC_INFORMATION, KEY_VALUE_FULL_INFORMATION, KEY_VALUE_PARTIAL_INFORMATION, ZwCreateKey, ZwEnumerateValueKey, ZwOpenKey


ZwReadFile

ZwReadFile is used to read data from an open file.

NTSTATUS
  ZwReadFile(
    IN HANDLE  FileHandle,
    IN HANDLE  Event  OPTIONAL,
    IN PIO_APC_ROUTINE  ApcRoutine  OPTIONAL,
    IN PVOID  ApcContext  OPTIONAL,
    OUT PIO_STATUS_BLOCK  IoStatusBlock,
    OUT PVOID  Buffer,
    IN ULONG  Length,
    IN PLARGE_INTEGER  ByteOffset  OPTIONAL,
    IN PULONG  Key  OPTIONAL
    );

Parameters

FileHandle
Specifies the handle returned by a successful call to ZwCreateFile.
Event
Specifies an optional handle for an event to be set to the signaled state after the read operation completes. Device and intermediate drivers should set this parameter to NULL.
ApcRoutine
Device and intermediate drivers should set this pointer to NULL.
ApcContext
Device and intermediate drivers should set this pointer to NULL.
IoStatusBlock
Pointer to an IO_STATUS_BLOCK structure that receives the final completion status and information about the requested read operation.
Buffer
Pointer to a caller-allocated buffer that receives the data read from the file.
Length
Specifies the size in bytes of the given Buffer. A successful call to ZwReadFile returns the given number of bytes from the file, unless this routine reaches the end of file first.
ByteOffset
Pointer to a variable that specifies the starting byte offset in the file where the read operation will begin. If an attempt is made to read beyond the end of the file, ZwReadFile returns an error.

If the call to ZwCreateFile set either of the CreateOptions flags FILE_SYNCHRONOUS_IO_ALERT or FILE_SYNCHRONOUS_IO_NONALERT, the I/O Manager maintains the current file position. If so, the caller of ZwReadFile can specify that the current file position offset be used instead of an explicit ByteOffset value. This specification can be made by using one of the following methods:

  • Specify the system-defined value FILE_USE_FILE_POINTER_POSITION.
  • Pass a NULL pointer for ByteOffset.

ZwReadFile updates the current file position by adding the number of bytes read when it completes the read operation, if it is using the current file position maintained by the I/O Manager.

Even when the I/O Manager is maintaining the current file position, the caller can reset this position by passing an explicit ByteOffset value to ZwReadFile. Doing this automatically changes the current file position to that ByteOffset value, performs the read operation, and then updates the position according to the number of bytes actually read. This technique gives the caller atomic seek-and-read service.

Key
Device and intermediate drivers should set this pointer to NULL.

Include

wdm.h or ntddk.h

Return Value

ZwReadFile either returns STATUS_SUCCESS or the appropriate error status. The number of bytes actually read from the file is returned in the Information member of the IoStatusBlock.

Comments

Callers of ZwReadFile must have already called ZwCreateFile with the DesiredAccess flag FILE_READ_DATA set, either explicitly or by setting this flag using GENERIC_READ.

If the preceding call to ZwCreateFile set the CreateOptions flag FILE_NO_INTERMEDIATE_BUFFERING, the Length and ByteOffset parameters to ZwReadFile must be an integral of the sector size. For more information, see ZwCreateFile.

ZwReadFile begins reading from the given ByteOffset or the current file position into the given Buffer. It terminates the read operation under one of the following conditions:

  • The buffer is full because the number of bytes specified by the Length parameter has been read. Therefore, no more data can be placed into the buffer without an overflow.
  • The end of file is reached during the read operation, so there is no more data in the file to be transferred into the buffer.

If the caller opened the file with the DesiredAccess SYNCHRONIZE flag set, the caller can wait for this routine to set the given FileHandle to the signaled state.

Drivers should call ZwReadFile in the context of the system process in three cases:

  1. The driver creates the file handle that it passes to ZwReadFile.
  2. ZwReadFile notifies the driver of I/O completion by means of an event created by the driver.
  3. ZwReadFile notifies the driver of I/O completion by means of an APC callback routine that the driver passes to ZwReadFile.

File and event handles are only valid in the process context where the handles are created. Therefore, to avoid security holes, the driver should create any file or event handle that it passes to ZwReadFile in the context of the system process instead of the process context that the driver is in.

Likewise, ZwReadFile should be called in the context of the system process if it notifies the driver of I/O completion by means of an APC, because APCs are always fired in the context of the thread issuing the I/O request. If the driver calls ZwReadFile in the context of a process other than the system process, the APC could be delayed indefinitely, or it might not fire at all.

Callers of ZwReadFile must be running at IRQL PASSIVE_LEVEL.

See Also

KeInitializeEvent, ZwCreateFile, ZwQueryInformationFile, ZwSetInformationFile, ZwWriteFile


ZwSetInformationFile

ZwSetInformationFile changes various kinds of information about a given file object.

NTSTATUS
  ZwSetInformationFile(
    IN HANDLE  FileHandle,
    OUT PIO_STATUS_BLOCK  IoStatusBlock,
    IN PVOID  FileInformation,
    IN ULONG  Length,
    IN FILE_INFORMATION_CLASS  FileInformationClass
    );

Parameters

FileHandle
Is the handle returned by a successful call to ZwCreateFile.
IoStatusBlock
Points to a variable that receives the final completion status and information about the operation.
FileInformation
Points to a buffer or variable containing the information to be set for the file. The contents of FileInformation are defined by the FileInformationClass parameter, described later. Setting any member of the structure in this buffer or variable to zero tells ZwSetInformationFile to leave the current information about the file for that member unchanged.
Length
Specifies the size in bytes of FileInformation, which the caller should set according to the given FileInformationClass.
FileInformationClass
Specifies the type of information, supplied in the buffer specified by FileInformation, to be reset for the file. Device and intermediate drivers, can specify any of the following:
FileInformationClass Value | Meaning
FileBasicInformation | Change information supplied in a FILE_BASIC_INFORMATION structure. The caller must have opened the file with the DesiredAccess FILE_WRITE_ATTRIBUTES flag set.
FileDispositionInformation | Usually, sets DeleteFile in FILE_DISPOSITION_INFORMATION to TRUE, so the file can be deleted when ZwClose is called to release the last open handle for the file object. The caller must have opened the file with the DesiredAccess DELETE flag set.
FilePositionInformation | Change the current position information, supplied in a FILE_POSITION_INFORMATION structure, for the file. The caller must have opened the file with the DesiredAccess FILE_READ_DATA or FILE_WRITE_DATA flag set and with either of the CreateOptions FILE_SYNCHRONOUS_IO_ALERT or FILE_SYNCHRONOUS_IO_NONALERT.
FileEndOfFileInformation | Change the current end-of-file information, supplied in a FILE_END_OF_FILE_INFORMATION structure, for the file: Either truncate or extend the amount of valid data in the file by moving the current end-of-file position. The caller must have opened the file with the DesiredAccess FILE_WRITE_DATA flag set.

Include

ntddk.h

Return Value

ZwSetInformationFile returns STATUS_SUCCESS or an appropriate error status. It also returns the number of bytes set on the file in the Information member of IoStatusBlock.

Comments

ZwSetInformationFile changes information about a file. It ignores any member of a FILE_XXX_INFORMATION structure that is not supported by a particular device or file system. For example, the FAT file system does not support file-creation times, so ZwSetInformationFile ignores the CreationTime member of the FILE_BASIC_INFORMATION structure when it is called to change basic file information for files on a FAT partition.

A caller that sets FileInformationClass to FileDispositionInformation can pass the FileHandle subsequently to ZwClose but to no other Zw..File routine. On return from ZwSetInformationFile, the file has been marked for deletion. It is a programming error to attempt any subsequent operation on the open file except closing it.

If the caller sets FileInformationClass to FilePositionInformation and the preceding call to ZwCreateFile set the CreateOptions flag FILE_NO_INTERMEDIATE_BUFFERING, certain restrictions on the input FILE_POSITION_INFORMATION CurrentByteOffset are enforced. See ZwCreateFile for specifics.

If the caller sets FileInformationClass to FileEndOfFileInformation and the EndOfFile member of FILE_END_OF_FILE_INFORMATION specifies an offset beyond the current end-of-file mark, ZwSetInformationFile extends the file and writes pad bytes of zeroes between the old and new end-of-file marks.

Callers of ZwSetInformationFile must be running at IRQL PASSIVE_LEVEL.

See Also

FILE_BASIC_INFORMATION, FILE_DISPOSITION_INFORMATION, FILE_END_OF_FILE_INFORMATION, FILE_POSITION_INFORMATION, ZwCreateFile, ZwQueryInformationFile


ZwSetInformationThread

ZwSetInformationThread can be called to set the priority of a thread for which the caller has a handle.

NTSTATUS
  ZwSetInformationThread(
    IN HANDLE  ThreadHandle,
    IN THREADINFOCLASS  ThreadInformationClass,
    IN PVOID  ThreadInformation,
    IN ULONG  ThreadInformationLength
    );

Parameters

ThreadHandle
Is the open handle for a thread. Use the NtCurrentThread() macro to specify the current thread.
ThreadInformationClass
Is one of the system-defined values ThreadPriority or ThreadBasePriority.
ThreadInformation
Points to a variable specifying the information to be set. If ThreadInformationClass is ThreadPriority, this value must be > LOW_PRIORITY and <= HIGH_PRIORITY. If ThreadInformationClass is ThreadBasePriority, this value must fall within the system's valid base priority range and the original priority class for the given thread: that is, if a thread's priority class is variable, that thread's base priority cannot be reset to a real-time priority value and vice versa.
ThreadInformationLength
Is the size in bytes of ThreadInformation, which must be at least sizeof(KPRIORITY).

Include

ntddk.h

Return Value

ZwSetInformationThread returns STATUS_SUCCESS or an error status, such as STATUS_INFO_LENGTH_MISMATCH or STATUS_INVALID_PARAMETER.

Comments

ZwSetInformationThread can be called by higher-level drivers to set the priority of a thread for which they have a handle.

The caller must have THREAD_SET_INFORMATION access rights for the given thread in order to call this routine.

Usually, device and intermediate drivers that set up driver-created threads call KeSetBasePriorityThread or KeSetPriorityThread from their driver-created threads, rather than ZwSetInformationThread. However, a driver can call ZwSetInformationThread to raise the priority of a driver-created thread before that thread is run.

Callers of ZwSetInformationThread must be running at IRQL PASSIVE_LEVEL.

See Also

KeSetBasePriorityThread, KeSetPriorityThread, PsCreateSystemThread


ZwSetValueKey

ZwSetValueKey replaces or creates a value entry for a key in the registry.

NTSTATUS
  ZwSetValueKey(
    IN HANDLE  KeyHandle,
    IN PUNICODE_STRING  ValueName,
    IN ULONG  TitleIndex  OPTIONAL,
    IN ULONG  Type,
    IN PVOID  Data,
    IN ULONG  DataSize
    );

Parameters

KeyHandle
Is the handle, returned by a successful call to ZwCreateKey or ZwOpenKey, of key for which a value entry is to be written in the registry.
ValueName
Points to the name of the value entry for which the data is to be written. This parameter can be a NULL pointer if the value entry has no name. If a name string is specified and the given name is not unique relative to its containing key, the data for an existing value entry is replaced.
TitleIndex
Device and intermediate drivers should set this parameter to zero.
Type
Specifies the type of the data to be written for ValueName. System-defined types include the following:
REG_XXX Type | Value
REG_BINARY | Binary data in any form
REG_DWORD | A 4-byte numerical value
REG_DWORD_LITTLE_ENDIAN | A 4-byte numerical value whose least significant byte is at the lowest address, which is identical to type REG_DWORD
REG_DWORD_BIG_ENDIAN | A 4-byte numerical value whose least significant byte is at the highest address
REG_EXPAND_SZ | A zero-terminated Unicode string, containing unexpanded references to environment variables, such as "%PATH%"
REG_LINK | A Unicode string naming a symbolic link; this type is irrelevant to device and intermediate drivers.
REG_MULTI_SZ | An array of zero-terminated strings, terminated by another zero
REG_NONE | Data with no particular type
REG_SZ | A zero-terminated Unicode string
REG_RESOURCE_LIST | A device driver's list of hardware resources, used by the driver or one of the physical devices it controls, in the \ResourceMap tree
REG_RESOURCE_REQUIREMENTS_LIST | A device driver's list of possible hardware resources it or one of the physical devices it controls can use, from which the system writes a subset into the \ResourceMap tree
REG_FULL_RESOURCE_DESCRIPTOR | A list of hardware resources that a physical device is using, detected and written into the \HardwareDescription tree by the system

Device drivers need not, and should not attempt to, call ZwSetValueKey directly to write value entries in a subkey of the \Registry..\ResourceMap key. Only the system can write value entries to the \Registry..\HardwareDescription tree.

Data
Points to a caller-allocated buffer containing the data for the value entry.
DataSize
Specifies the size in bytes of the Data buffer. If Type is any of the REG_XXX_SZ, this value must include the terminating zero(s).

Include

wdm.h or ntddk.h

Return Value

ZwSetValueKey can return one of the following:

STATUS_SUCCESS
STATUS_ACCESS_DENIED
STATUS_INVALID_HANDLE

Comments

The KeyHandle passed to ZwSetValueKey must have been opened with the KEY_SET_VALUE DesiredAccess flag set for this call to succeed. See ZwCreateKey for a description of possible values for DesiredAccess.

If the given key has no existing value entry with a name matching the given ValueName, ZwSetValueKey creates a new value entry with the given name. If a matching value entry name exists, this routine overwrites the original value entry for the given ValueName. Thus, ZwSetValueKey preserves a unique name for each value entry of any particular key. While each value entry name must be unique to its containing key, many different keys in the registry can have value entries with the same names.

Callers of ZwSetValueKey must be running at IRQL PASSIVE_LEVEL.

See Also

HalAssignSlotResources, IoAssignResources, IoQueryDeviceDescription, IoReportResourceUsage, ZwClose, ZwCreateKey, ZwFlushKey, ZwOpenKey


ZwUnmapViewOfSection

ZwUnmapViewOfSection unmaps a view of a section from the virtual address space of a subject process.

NTSTATUS
  ZwUnmapViewOfSection(
    IN HANDLE  ProcessHandle,
    IN PVOID  BaseAddress
    );

Parameters

ProcessHandle
Specifies an open process handle, previously passed to ZwMapViewOfSection.
BaseAddress
Points to the base virtual address of the view that is to be unmapped. This value can be any virtual address within the view.

Include

wdm.h or ntddk.h

Return Value

ZwUnmapViewOfSection can return one of the following:

STATUS_NORMAL
STATUS_INVALID_PARAMETER
STATUS_NO_ACCESS

Comments

The entire view of the section specified by the BaseAddress parameter is unmapped from the virtual address space of the specified process.

The virtual address region occupied by the view is no longer reserved and is available to map other views or private pages. If the view was also the last reference to the underlying section, then all committed pages in the section are decommitted and the section is deleted.

Callers of ZwUnmapViewOfSection must be running at IRQL PASSIVE_LEVEL.

See Also

ZwMapViewOfSection, ZwOpenSection


ZwWriteFile

ZwWriteFile is used to write data to an open.

NTSTATUS
  ZwWriteFile(
    IN HANDLE  FileHandle,
    IN HANDLE  Event  OPTIONAL,
    IN PIO_APC_ROUTINE  ApcRoutine  OPTIONAL,
    IN PVOID  ApcContext  OPTIONAL,
    OUT PIO_STATUS_BLOCK  IoStatusBlock,
    IN PVOID  Buffer,
    IN ULONG  Length,
    IN PLARGE_INTEGER  ByteOffset  OPTIONAL,
    IN PULONG  Key  OPTIONAL
    );

Parameters

FileHandle
Specifies the handle returned by a successful call to ZwCreateFile.
Event
Specifies an optional handle for an event to be set to the signaled state after the write operation completes. Device and intermediate drivers should set this parameter to NULL.
ApcRoutine
Device and intermediate drivers should set this pointer to NULL.
ApcContext
Device and intermediate drivers should set this pointer to NULL.
IoStatusBlock
Pointer to a variable that receives the final completion status and information about the requested write operation.
Buffer
Pointer to a caller-allocated buffer containing the data to be written to the file.
Length
Specifies the size in bytes of the given Buffer. A successful call to ZwWriteFile transfers the given number of bytes to the file. If necessary, the length of the file is extended.
ByteOffset
Pointer to a variable that specifies the starting byte offset in the file where the write operation will begin. If a given Length and ByteOffset specify a write operation past the current end-of-file mark, ZwWriteFile automatically extends the file and updates the end-of-file mark; any bytes that are not explicitly written between such old and new end-of-file marks are defined to be zero.

If the call to ZwCreateFile set only the DesiredAccess flag FILE_APPEND_DATA, ByteOffset is ignored. Data in the given Buffer, for Length bytes, is written starting at the current end of file.

If the call to ZwCreateFile set either of the CreateOptions flags, FILE_SYNCHRONOUS_IO_ALERT or FILE_SYNCHRONOUS_IO_NONALERT, the I/O Manager maintains the current file position. If so, the caller of ZwWriteFile can specify that the current file position offset be used instead of an explicit ByteOffset value. This specification can be made by using one of the following methods:

  • Specify the system-defined value FILE_USE_FILE_POINTER_POSITION.
  • Pass a NULL pointer for ByteOffset.

ZwWriteFile updates the current file position by adding the number of bytes written when it completes the write operation, if it is using the current file position maintained by the I/O Manager.

Even when the I/O Manager is maintaining the current file position, the caller can reset this position by passing an explicit ByteOffset value to ZwWriteFile. Doing this automatically changes the current file position to that ByteOffset value, performs the write operation, and then updates the position according to the number of bytes actually written. This technique gives the caller atomic seek-and-write service.

It is also possible to cause a write operation to start at the current end of file by specifying FILE_WRITE_TO_END_OF_FILE for the ByteOffset parameter even if the I/O Manager is not maintaining the current file position.

Key
Device and intermediate drivers should set this pointer to NULL.

Include

wdm.h or ntddk.h

Return Value

ZwWriteFile either returns STATUS_SUCCESS or an appropriate error status. The number of bytes actually written to the file is returned in the Information member of IoStatusBlock.

Comments

Callers of ZwWriteFile must have already called ZwCreateFile with the DesiredAccess flags FILE_WRITE_DATA and/or FILE_APPEND_DATA set, either explicitly or by setting these flags with GENERIC_WRITE. Note that having only FILE_APPEND_DATA access to a file does not allow the caller to write anywhere in the file except at the current end-of-file mark, while having FILE_WRITE_DATA access to a file does not preclude the caller from writing to or beyond the end of a file.

If the preceding call to ZwCreateFile set the CreateOptions flag FILE_NO_INTERMEDIATE_BUFFERING, the Length and ByteOffset parameters to ZwWriteFile must be an integral of the sector size. For more information, see ZwCreateFile.

ZwWriteFile begins writing data from the given Buffer at the given ByteOffset in the file, at the current file position within the file, or at the end-of-file mark. It terminates the write operation when it has written Length bytes to the file, extending the length of the file if necessary, and resetting the end-of-file mark.

If the caller opened the file with the DesiredAccess SYNCHRONIZE flag set, the caller can wait for this routine to set the given FileHandle to the signaled state.

Drivers should call ZwWriteFile in the context of the system process in three cases:

  1. The driver creates the file handle that it passes to ZwWriteFile.
  2. ZwWriteFile notifies the driver of I/O completion by means of an event created by the driver.
  3. ZwWriteFile notifies the driver of I/O completion by means of an APC callback routine that the driver passes to ZwWriteFile.

File and event handles are only valid in the process context where the handles are created. Therefore, to avoid security holes, the driver should create any file or event handle that it passes to ZwWriteFile in the context of the system process instead of the process context that the driver is in.

Likewise, ZwWriteFile should be called in the context of the system process if it notifies the driver of I/O completion by means of an APC, because APCs are always fired in the context of the thread issuing the I/O request. If the driver calls ZwWriteFile in the context of a process other than the system process, the APC could be delayed indefinitely, or it might not fire at all.

Callers of ZwWriteFile must be running at IRQL = PASSIVE_LEVEL.

See Also

KeInitializeEvent, ZwCreateFile, ZwQueryInformationFile, ZwReadFile, ZwSetInformationFile


Power Management Support Routines

All drivers that support power management call PoXxx routines. These routines are declared in the ntddk.h and wdm.h header files.

This section describes the following power management routines in alphabetical order:

PoCallDriver

PoRegisterDeviceForIdleDetection

PoRegisterSystemState

PoRequestPowerIrp

PoSetDeviceBusy

PoSetPowerState

PoSetSystemState

PoStartNextPowerIrp

PoUnregisterSystemState


PoCallDriver

PoCallDriver passes a power IRP to the next-lower driver in the device stack.

NTSTATUS
  PoCallDriver(
    IN PDEVICE_OBJECT  DeviceObject,
    IN OUT PIRP  Irp
    );

Parameters

DeviceObject
Pointer to the driver-created device object to which the IRP is to be routed.
Irp
Pointer to an IRP.

Return Value

PoCallDriver returns STATUS_SUCCESS to indicate success. It returns STATUS_PENDING if it has queued the IRP.

Headers

ntddk.h or wdm.h

Comments

Drivers call PoCallDriver — not IoCallDriver — to pass a power IRP to the next-lower driver. Drivers must call PoStartNextPowerIrp before calling PoCallDriver.

A driver that requires a new IRP should call PoRequestPowerIrp. A driver must not allocate its own power IRP.

When passing a power IRP down to the next-lower driver, the caller should use IoSkipCurrentIrpStackLocation or IoCopyCurrentIrpStackLocationToNext to set the IRP stack location, then call PoCallDriver. Use IoCopyCurrentIrpStackLocationToNext if processing the IRP requires setting an IoCompletion routine, or IoSkipCurrentStackLocation if no IoCompletion routine is required.

When a device is powering up, its drivers must set IoCompletion routines to perform start-up tasks (initializing the device, restoring context, and so on) after the bus driver has set the device in the working state. Set IoCompletion routines before calling PoCallDriver.

When a device is powering down, its drivers must perform necessary power-down tasks before passing the IRP to the next lower driver. After the IRP has reached the bus driver, the device will be powered off and its drivers will no longer have access to it. An IoCompletion routine associated with a power-down IRP should simply call PoStartNextPowerIrp.

Only one inrush IRP can be active in the system at a time. When passing a power-up IRP for a device that requires inrush current (in other words, the DO_POWER_INRUSH flag is set in the device object), PoCallDriver checks whether another inrush IRP is already active. If so, PoCallDriver queues the current IRP for handling after the previous IRP completes, and then returns STATUS_PENDING. For more information on inrush IRPs, see Setting Device Object Flags for Power Management.

If an IRP_MN_SET_POWER or IRP_MN_QUERY_POWER request is already active for DeviceObject, PoCallDriver queues this IRP and returns STATUS_PENDING.

On Windows® 2000 and later systems, drivers that are not in the paging path (that is, the DO_POWER_PAGABLE flag is set in the device object) should call PoCallDriver at IRQL PASSIVE_LEVEL. Drivers that are in the paging path (DO_POWER_PAGABLE is not set in the device object) or require inrush current (DO_POWER_INRUSH is set in the device object) can call PoCallDriver at IRQL PASSIVE_LEVEL or DISPATCH_LEVEL.

On Windows 98/Me, all drivers call PoCallDriver at IRQL PASSIVE_LEVEL.

See Also

PoRequestPowerIrp


PoRegisterDeviceForIdleDetection

PoRegisterDeviceForIdleDetection enables or cancels idle detection and sets idle time-out values for a device.

PULONG
  PoRegisterDeviceForIdleDetection(
    IN PDEVICE_OBJECT  DeviceObject,
    IN ULONG  ConservationIdleTime,
    IN ULONG  PerformanceIdleTime,
    IN DEVICE_POWER_STATE  State
    );

Parameters

DeviceObject
Pointer to the driver-created device object for the device. On Windows 2000 and later systems, this parameter can point to a PDO or FDO. On Windows 98/Me, this parameter must point to the PDO of the underlying device.
ConservationIdleTime
Sets the time-out value (in seconds) to apply when the system power policy optimizes for energy conservation. Specify zero to disable idle detection when conservation policy is in effect.
PerformanceIdleTime
Sets the time-out value (in seconds) to apply when the system power policy optimizes for performance. Specify zero to disable idle detection when performance policy is in effect.
State
Specifies the device power state to be requested in an IRP_MN_SET_POWER request when either ConservationIdleTime or PerformanceIdleTime has been met. Possible values are PowerDeviceD0, PowerDeviceD1, PowerDeviceD2, and PowerDeviceD3.

Return Value

PoRegisterDeviceForIdleDetection returns a pointer to the idle counter to indicate that idle detection has been enabled. It returns NULL to indicate that idle detection has been disabled, that an idle counter could not be allocated, or that one or both of the time-out values were invalid.

Headers

ntddk.h or wdm.h

Comments

PoRegisterDeviceForIdleDetection enables drivers to use the Power Manager's idle detection mechanism. Drivers call PoRegisterDeviceForIdleDetection for any of the following reasons:

  • To enable idle detection for the device and set initial idle time-out values
  • To change the idle time-out values for a device
  • To disable idle detection for a device

After enabling its device for idle detection, the driver calls PoSetDeviceBusy whenever its device is in use, passing the idle pointer returned by PoRegisterDeviceForIdleDetection.

Whenever the device satisfies the current idle time-out value, the Power Manager sends an IRP_MN_SET_POWER request to the top of the device stack, specifying device power state State. In response to the IRP, each driver performs any device-specific tasks required before the power state transition, then passes the IRP to the next-lower driver. When the IRP reaches the bus driver, that driver puts the device in the requested lower power state and completes the IRP.

PoRegisterDeviceForIdleDetection sets time-out values for both conservation and performance. The ConservationIdleTime value applies when the system power policy optimizes for conservation; the PerformanceIdleTime value applies when the system power policy optimizes for performance. Typically, the applicable policy depends upon the power source: when running with AC power, the system optimizes for performance, and when running off a battery, the system optimizes for conservation. Certain devices can specify time-out values of -1 to use the standard power policy time-outs for their device class. The standard time-out values provide for better system integration for supported standard device classes. At present, WDM supports this feature for devices of type FILE_DEVICE_DISK and FILE_DEVICE_MASS_STORAGE. PoRegisterDeviceForIdleDetection returns NULL if -1 is specified for a device of an unsupported type.

Only one idle detection can be set per device. Subsequent calls to PoRegisterDeviceForIdleDetection change the idle detection values.

If both ConservationIdleTime and PerformanceIdleTime are zero, this routine cancels all idle detection for the device and returns NULL.

PoRegisterDeviceForIdleDetection can free a driver from the need to perform its own idle detection. However, drivers can also implement their own idle detection.

Callers of PoRegisterDeviceForIdleDetection must be running at IRQL<DISPATCH_LEVEL.

See Also

PoSetDeviceBusy


PoRegisterSystemState

PoRegisterSystemState registers the system as busy due to certain activity.

PVOID
  PoRegisterSystemState(
    IN PVOID  StateHandle,
    IN EXECUTION_STATE  Flags
    );

Parameters

StateHandle
Pointer to a caller-supplied memory location that can contain a registration state handle. If NULL, this is a new registration. If non-NULL, this parameter points to a handle that was returned by a previous call to PoRegisterSystemState.
Flags
Indicates the type of activity. Possible values are one or more of the following:
ES_SYSTEM_REQUIRED
The system is not idle, regardless of apparent load.
ES_DISPLAY_REQUIRED
Use of the display is required.
ES_USER_PRESENT
A user is present.
ES_CONTINUOUS
The settings are continuous and should remain in effect until explicitly changed.

Return Value

PoRegisterSystemState returns a handle to be used later to change or unregister the system busy state. It returns NULL if the handle could not be allocated.

Headers

ntddk.h or wdm.h

Comments

PoRegisterSystemState registers the system busy state as indicated by the flags. The registration persists until the caller explicitly changes it with another call to PoRegisterSystemState or cancels it with a call to PoUnregisterSystemState.

The Flags parameter specifies the type of activity in progress. Drivers can specify any combination of the flags.

Setting ES_CONTINUOUS makes the busy state persist until a driver explicitly changes or cancels it by calling PoRegisterSystemState or PoUnregisterSystemState.

A driver can set the system busy state to request that the Power Manager avoid system power state transitions out of the system working state (S0) while driver activity is occurring. Note, however, that under some circumstances (such as a critically low battery) the Power Manager may override this request and put the system to sleep anyway.

Callers of PoRegisterSystemState must be running at IRQL<DISPATCH_LEVEL.

See Also

PoSetSystemState, PoUnregisterSystemState


PoRequestPowerIrp

PoRequestPowerIrp allocates a power IRP and sends it to the top driver in the device stack for the specified device.

NTSTATUS
  PoRequestPowerIrp(
    IN PDEVICE_OBJECT  DeviceObject,
    IN UCHAR  MinorFunction,
    IN POWER_STATE  PowerState,
    IN PREQUEST_POWER_COMPLETE  CompletionFunction,
    IN PVOID  Context,
    OUT PIRP  *Irp OPTIONAL
    );

Parameters

DeviceObject
Pointer to the target device object for the IRP. On Windows 2000 and later systems, this parameter can point to a PDO or FDO. On Windows 98/Me, this parameter must point to the PDO of the underlying device.
MinorFunction
Specifies one of the following minor power IRP codes: IRP_MN_QUERY_POWER, IRP_MN_SET_POWER, or IRP_MN_WAIT_WAKE.
PowerState
Specifies a power state to pass in the IRP. For IRP_MN_SET_POWER and IRP_MN_QUERY_POWER, specify the requested new device power state. Possible values are enumerators of the DEVICE_POWER_STATE type.

For IRP_MN_WAIT_WAKE, specify the lowest (least-powered) system power state from which the device should be allowed to wake the system Possible values are enumerators of the SYSTEM_POWER_STATE type.

CompletionFunction
Pointer to the caller's PowerCompletion callback to be called when the IRP has completed. The callback is declared as follows:
VOID
(*PREQUEST_POWER_COMPLETE) (
    IN PDEVICE_OBJECT DeviceObject,
    IN UCHAR MinorFunction,
    IN POWER_STATE PowerState,
    IN PVOID Context,
    IN PIO_STATUS_BLOCK IoStatus
    );

The callback parameters are as follows:

DeviceObject
Pointer to the target device object for the completed power IRP.
MinorFunction
Specifies the minor function code in the power IRP.
PowerState
Specifies the device power state passed to PoRequestPowerIrp.
Context
Pointer to the context passed to PoRequestPowerIrp.
IoStatus
Pointer to the IoStatus block in the completed IRP.
Context
Pointer to a caller-supplied context to be passed through to the PowerCompletion callback. When the caller requests a device set-power IRP in response to a system set-power IRP, the Context should contain the system set-power IRP that triggered the request.
Irp
Pointer to a caller-supplied variable in which this routine returns a pointer to the IRP it allocates. This parameter can be NULL.

Return Value

PoRequestPowerIrp returns one of the following:

STATUS_PENDING
The IRP has been sent.
STATUS_INSUFFICIENT_RESOURCES
The routine could not allocate the IRP.
STATUS_INVALID_PARAMETER_2
MinorFunction does not signify a valid minor power IRP code.

Headers

ntddk.h or wdm.h

Comments

A driver calls PoRequestPowerIrp — not IoAllocateIrp — to allocate and send a power IRP that has minor IRP code IRP_MN_SET_POWER, IRP_MN_QUERY_POWER, or IRP_MN_WAIT_WAKE. (A driver must call IoAllocateIrp to send a power IRP with minor IRP code IRP_MN_POWER_SEQUENCE.)

A device power policy owner calls this routine to send a wait/wake, query, or set-power IRP.

PoRequestPowerIrp allocates a device power IRP and sends it to the top of the device stack for the device. After the bus driver and all other drivers have completed the IRP, and the I/O Manager has called all IoCompletion routines set by drivers as they passed the IRP down the device stack, the CompletionFunction is called with the given Context.

The CompletionFunction performs any additional tasks the sender of the IRP requires after all other drivers have completed the IRP. It need not free the IRP; the Power Manager does that. On Windows 98/Me, the CompletionFunction is always called at IRQL PASSIVE_LEVEL, and drivers must complete IRPs at IRQL PASSIVE_LEVEL. On Windows 2000 and later systems, the CompletionFunction can be called at IRQL PASSIVE_LEVEL or DISPATCH_LEVEL.

A device power policy owner calls PoRequestPowerIrp to send a device query- or set-power IRP when it receives a system query- or set-power IRP. The driver should set an IoCompletion routine in the system IRP and pass the system IRP to the next lower driver. The IoCompletion routine calls PoRequestPowerIrp to send the device IRP, passing the system IRP in the Context parameter. The Context parameter is subsequently passed to the CompletionFunction for the device IRP. In the CompletionFunction, the driver can complete the system IRP. For more information, see Sending IRP_MN_QUERY_POWER or IRP_MN_SET_POWER for Device Power States and Wait/Wake Callback Routines.

Drivers can use the returned Irp to cancel an IRP_MN_WAIT_WAKE IRP. Drivers requesting other power IRPs can pass NULL for this parameter.

Callers of PoRequestPowerIrp must be running at IRQL <= DISPATCH_LEVEL.

See Also

PoStartNextPowerIrp, IRP_MN_SET_POWER, IRP_MN_QUERY_POWER, IRP_MN_WAIT_WAKE


PoSetDeviceBusy

PoSetDeviceBusy notifies the Power Manager that the device associated with IdlePointer is busy.

VOID
  PoSetDeviceBusy(
    PULONG  IdlePointer
    );

Parameters

IdlePointer
Specifies an idle pointer that was previously returned by PoRegisterDeviceForIdleDetection.

Headers

ntddk.h or wdm.h

Comments

A driver uses PoSetDeviceBusy along with PoRegisterDeviceForIdleDetection to enable system idle detection for its device. If a device that is registered for idle detection becomes idle, the Power Manager sends an IRP_MN_SET_POWER IRP to put the device in a requested sleep state.

PoSetDeviceBusy reports that the device is busy, so that the Power Manager can restart its idle countdown. If the device is not powered up, PoSetDeviceBusy does not change its state. That is, it does not cause the system to send a power-on request.

A driver should call PoSetDeviceBusy on every I/O request.

PoSetDeviceBusy can be called from any IRQL.

See Also

PoRegisterDeviceForIdleDetection


PoSetPowerState

PoSetPowerState notifies the system of a device's power state.

POWER_STATE
  PoSetPowerState(
    IN PDEVICE_OBJECT  DeviceObject,
    IN POWER_STATE_TYPE  Type,
    IN POWER_STATE  State
    );

Parameters

DeviceObject
Pointer to the target device object.
Type
Indicates whether to set a system or a device power state. Drivers must specify DevicePowerState.
State
Specifies the power state to be set. Drivers must specify an enumerator of DEVICE_POWER_STATE: PowerDeviceD0, PowerDeviceD1, PowerDeviceD2, or PowerDeviceD3.

Return Value

On Windows 2000 and later versions of the operating system, PoSetPowerState returns the previous power state. On Windows 98/Me, PoSetPowerState returns the state passed in State.

Headers

ntddk.h or wdm.h

Comments

PoSetPowerState notifies the Power Manager of the new power state for a device. A driver should call PoSetPowerState every time its device changes power state.

A driver calls this routine after receiving a device set-power IRP and before calling PoStartNextPowerIrp. When starting a device (that is, when handling a PnP IRP_MN_START_DEVICE request), the driver should call PoSetPowerState to notify the Power Manager that the device is in the D0 state.

If the device is powering down, the driver must call PoSetPowerState before leaving the D0 state. In addition, the driver must be able to process client requests before PoSetPowerState returns.

If the device is powering up, the driver must call PoSetPowerState after the device is successfully put into the D0 state.

Callers of PoSetPowerState must be running at IRQL<DISPATCH_LEVEL except when setting state to D0. When setting state to D0, callers can be running at IRQL<=DISPATCH_LEVEL.

See Also

PoStartNextPowerIrp


PoSetSystemState

Drivers call PoSetSystemState to indicate that the system is active.

VOID
  PoSetSystemState(
    IN EXECUTION_STATE  Flags
    );

Parameters

Flags
Specifies the system activity. Possible values are one or more of the following:
ES_SYSTEM_REQUIRED
The system is not idle, regardless of apparent load.
ES_DISPLAY_REQUIRED
Use of the display is required.
ES_USER_PRESENT
A user is present.

Headers

ntddk.h or wdm.h

Comments

A driver calls PoSetSystemState to set flags indicating that system activity is occurring. Unlike PoRegisterSystemState, this routine does not allow the driver to set a persistent busy state.

The Flags parameter specifies the type of activity occurring. Drivers can specify any combination of the flags.

Drivers can set the system busy state to request that the system avoid leaving of the working state while driver activity is occurring. Note, however, that under some circumstances (such as a critically low battery) the Power Manager may override this request and put the system to sleep anyway.

Callers of PoSetSystemState must be running at IRQL <= DISPATCH_LEVEL.

See Also

PoRegisterSystemState, PoUnregisterSystemState


PoStartNextPowerIrp

PoStartNextPowerIrp informs the Power Manager that the driver is ready to handle the next power IRP.

VOID
  PoStartNextPowerIrp(
    IN PIRP  Irp
    );

Parameters

Irp
Pointer to an IRP in which the major function code is IRP_MJ_POWER.

Headers

ntddk.h or wdm.h

Comments

PoStartNextPowerIrp must be called by every driver in the device stack.

Calling this routine indicates that the driver is finished with the previous power IRP, if any, and is ready to handle the next power IRP. It must be called once by each driver for every IRP_MN_QUERY_POWER or IRP_MN_SET_POWER request.

Although power IRPs are completed only once, typically by the bus driver for a device, each driver in the device stack must call PoStartNextPowerIrp as the IRP travels down or back up the stack. Even if a driver fails the IRP, it must nevertheless call PoStartNextPowerIrp to inform the Power Manager that it is ready to handle another power IRP.

The driver must call PoStartNextPowerIrp while the current IRP stack location points to the current driver. Therefore, this routine must be called before IoCompleteRequest, IoSkipCurrentIrpStackLocation, and PoCallDriver. As a general rule, a driver should call PoStartNextPowerIrp from its IoCompletion routine associated with the IRP or from the callback routine it passed to PoRequestPowerIrp.

Bus drivers must call PoStartNextPowerIrp before completing each IRP.

Callers of PoStartNextPowerIrp must be running at IRQL<=DISPATCH_LEVEL.

See Also

PoCallDriver, PoStartNextPowerIRP


PoUnregisterSystemState

PoUnregisterSystemState cancels a system state registration created by PoRegisterSystemState.

VOID
  PoUnregisterSystemState(
    IN PVOID  StateHandle
    );

Parameters

StateHandle
Specifies a handle previously returned by PoRegisterSystemState.

Headers

ntddk.h or wdm.h

Comments

This routine cancels a system busy state registration established by PoRegisterSystemState and frees the associated StateHandle.

Callers of PoUnregisterSystemState must be running at IRQL<DISPATCH_LEVEL.

See Also

PoRegisterSystemState


WMI Library Support Routines

This section describes the WMI library support routines that a driver can call to handle WMI IRPs and access WMI support for tracing driver operation.

For information about WMI library callback routines, see WMI Library Callback Routines.


WmiCompleteRequest

The WmiCompleteRequest routine indicates that a driver has finished processing a WMI request in a DpWmiXxx routine.

NTSTATUS
  WmiCompleteRequest(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp,
    IN NTSTATUS  Status,
    IN ULONG  BufferUsed,
    IN CCHAR  PriorityBoost
    );

Parameters

DeviceObject
Points to the driver's device object.
Irp
Points to the IRP.
Status
Specifies the status to return for the IRP.
BufferUsed
Specifies the number of bytes needed in the buffer passed to the driver's DpWmiXxx routine. If the buffer is too small, the driver sets Status to STATUS_BUFFER_TOO_SMALL and sets BufferUsed to the number of bytes needed for the data to be returned. If the buffer passed is large enough, the driver sets BufferUsed to the number of bytes actually used.
PriorityBoost
Specifies a system-defined constant by which to increment the runtime priority of the original thread that requested the operation. WMI calls IoCompleteRequest with PriorityBoost when it completes the IRP.

Return Value

WmiCompleteRequest returns the value that was passed to it in the Status parameter unless Status was set to STATUS_BUFFER_TOO_SMALL.. If the driver set Status equal to STATUS_BUFFER_TOO_SMALL, WmiCompleteRequest builds a WNODE_TOO_SMALL structure and returns STATUS_SUCCESS. The return value from WmiCompleteRequest should be returned by the driver in its DpWmiXxx routine.

Comments

A driver calls WmiCompleteRequest from a DpWmiXxx routine after it finishes all other processing in that routine, or after the driver finishes all processing for a pending IRP. WmiCompleteRequest fills in a WNODE_XXX with any data returned by the driver and calls IoCompleteRequest to complete the IRP.

A driver should always return the return value from WmiCompleteRequest in its DpWmiXxx routine.

A driver must not call WmiCompleteRequest from its DpWmiQueryRegInfo routine.

Callers of WmiCompleteRequest must be running at IRQL <= DISPATCH_LEVEL.

See Also

DpWmiExecuteMethod, DpWmiFunctionControl, DpWmiQueryDataBlock, DpWmiQueryReginfo, DpWmiSetDataBlock, DpWmiSetDataItem, IoCompleteRequest, WmiSystemControl


WmiFireEvent

The WmiFireEvent routine sends an event to WMI for delivery to data consumers that have requested notification of the event.

NTSTATUS
  WmiFireEvent(
    IN PDEVICE_OBJECT  DeviceObject,
    IN LPGUID  Guid,
    IN ULONG  InstanceIndex,
    IN ULONG  EventDataSize,
    IN PVOID  EventData
    );

Parameters

DeviceObject
Points to the driver's device object.
Guid
Points to the GUID that represents the event block.
InstanceIndex
If the event block has multiple instances, specifies the index of the instance.
EventDataSize
Specifies the number of bytes of data at EventData. If no data is generated for an event, EventData must be zero.
EventData
Points to a driver-allocated nonpaged buffer containing data generated by the driver for the event. If no data is generated for an event, EventData must be NULL. WMI frees the buffer without further intervention by the driver.

Return Value

WmiFireEvent propagates the status returned by IoWmiWriteEvent, or returns STATUS_INSUFFICIENT_RESOURCES if it could not allocate memory for the event.

Comments

A driver calls WmiFireEvent to send an event to WMI for delivery to all data consumers that have requested notification of the event. All parameters passed to WmiFireEvent must be allocated from nonpaged pool.

The driver sends an event only if it has been previously enabled by the driver's DpWmiFunctionControl routine, which WMI calls to process an IRP_MN_ENABLE_EVENT request.

The driver writes any data associated with the event to the buffer at EventData. WMI fills in a WNODE_SINGLE_INSTANCE structure with the data and calls IoWmiWriteEvent to deliver the event.

For more information about event tracing, see WMI Support for Tracing Driver Operation.

Callers of WmiFireEvent must be running at IRQL <= DISPATCH_LEVEL.

See Also

DpWmiFunctionControl, IRP_MN_ENABLE_EVENTS, WmiSystemControl


WmiQueryTraceInformation

The WmiQueryTraceInformation routine returns information about an event trace.

NTKERNELAPI
NTSTATUS
  WmiQueryTraceInformation(
    IN TRACE_INFORMATION_CLASS  TraceInformationClass,
    OUT PVOID  TraceInformation,
    IN ULONG  TraceInformationLength,
    OUT PULONG  RequiredLength OPTIONAL,
    IN PVOID  Buffer OPTIONAL
    );

Parameters

TraceInformationClass
Specifies a TRACE_INFORMATION_CLASS enumerator that indicates the type of information to return about an event trace.
TraceInformation
Pointer to a caller-allocated output buffer where the routine returns the event trace information specified by TraceInformationClass.
TraceInformationLength
Specifies the size, in bytes, of the TraceInformation buffer.
RequiredLength
Pointer to the value returned by the routine that specifies the required size, in bytes, of the TraceInformation buffer. The caller should set RequiredLength to NULL if it does not use the required length information.
Buffer
Pointer to the query-specific input information that a caller supplies. If caller-supplied information is not required, the caller should set Buffer to NULL.

Return Value

NTSTATUS Value | Description
STATUS_SUCCESS | Success
STATUS_INFO_LENGTH_MISMATCH | The size of the TraceInformation buffer is not equal to the required size for the specified event trace information.
STATUS_INVALID_HANDLE | The trace handle specified by the HistoricalContext member of the (PWNODE_HEADER)Buffer is not valid.
STATUS_INVALID_INFO_CLASS | The specified type of event trace information is not valid.
STATUS_INVALID_PARAMETER | The name of the event trace, supplied with a query to return a trace handle given its name, is not valid.
STATUS_INVALID_PARAMETER_MIX | The caller did not supply the information required for the specified event trace information.
STATUS_MORE_ENTRIES | The TraceInformation buffer is not large enough to hold an array of all the valid event trace handles.
STATUS_NOT_FOUND | A global logger was not found.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

For each type of event trace information specified by TraceInformationClass, the following table provides:

  • Input requirements
  • Information that WmiQueryTraceInformation returns in the TraceInformation buffer
Value of TraceClassInformation | Input Requirements | Information Returned
TraceIdClass | TraceInformationLength is equal to the value of sizeof(ULONG). The size, in bytes of the TraceInformation buffer is greater than or equal to the value of sizeof(ULONG). The HistoricalContext member of (PWNODE_HEADER)Buffer specifies an event trace handle. | *(PULONG) TraceInformation is set to the logger ID of the event trace handle.
TraceHandleClass | TraceInformationLength is equal to the value of sizeof(TRACEHANDLE). The size, in bytes of the TraceInformation buffer must be greater than or equal to the value of sizeof(TRACEHANDLE). *(PULONG)Buffer is set to a logger ID. | *(PTRACEHANDLE)TraceInformation is set to an event trace handle for the specified logger. If the specified logger ID is zero, an event trace handle for the kernel logger is returned.
TraceEnableFlagsClass | TraceInformationLength is greater than or equal to the value of sizeof(ULONG). The size, in bytes of the TraceInformation buffer must be greater than or equal to the value of sizeof(ULONG). The HistoricalContext member of (PWNODE_HEADER)Buffer specifies an event trace handle. | *(PULONG) TraceInformation is set to the enable flags that are set for the specified event trace handle.
TraceEnableLevelClass | TraceInformationLength is set greater than or equal to the value of sizeof(ULONG). The size, in bytes of the TraceInformation buffer must be greater than or equal to the value of sizeof(ULONG). The HistoricalContext member of (PWNODE_HEADER)Buffer specifies an event trace handle. | *(PULONG) TraceInformation is set to the level for the specified event trace handle.
GlobalLoggerHandleClass | TraceInformationLength is equal to the value of sizeof(TRACEHANDLE). The size, in bytes of the TraceInformation buffer must be greater than or equal to the value of sizeof(TRACEHANDLE). | *(PTRACEHANDLE)TraceInformation is set to an event trace handle for the global logger.
EventLoggerHandleClass | For internal use only. | For internal use only.
AllLoggerHandlesClass | TraceInformationLength is set to the size, bytes, of an array of m TRACEHANDLE values. The size, in bytes of the TraceInformation buffer must be greater than or equal to the value of (m*sizeof(TRACEHANDLE)). | The TraceInformation buffer contains an array of n trace handles, where n is the minimum of m, the number of caller-supplied event trace handles, and the number of valid event trace handles. The routine returns a status of STATUS_MORE_ENTRIES if the TraceInformation buffer is too small to hold all trace handles.
TraceHandleByNameClass | TraceInformationLength is set to the value of sizeof(TRACEHANDLE). The size, in bytes, of the TraceInformation buffer must be greater than or equal to the value of sizeof(TRACEHANDLE). (PUNICODE_STRING)Buffer specifies a friendly trace name in UNICODE format. | *(PTRACEHANDLE)TraceInformatio) is set to the event trace handle associated with the specified friendly name.

If the caller supplies a nonNULL RequiredLength pointer, WmiQueryTraceInformation also returns the required length for the specified event trace information.

WmiQueryTraceInformation runs at the IRQL of the caller.

For more information about event tracing, see WMI Support for Tracing Driver Operation.

See Also

IoWmiWriteEvent, TRACE_INFORMATION_CLASS, WmiFireEvent, WmiTraceMessage, WmiTraceMessageVa


WmiSystemControl

The WmiSystemControl routine is a dispatch routine for drivers that use WMI library support routines to handle WMI IRPs.

NTSTATUS
  WmiSystemControl(
    IN PWMILIB_CONTEXT  WmiLibInfo,
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp,
    OUT PSYSCTL_IRP_DISPOSITION  IrpDisposition
    );

Parameters

WmiLibInfo
Points to a WMILIB_CONTEXT structure that contains registration information for a driver's data blocks and event blocks and defines entry points for the driver's WMI library callback routines.
DeviceObject
Points to the driver's device object.
Irp
Points to the IRP.
IrpDisposition
After WmiSystemControl returns, IrpDisposition indicates how the IRP was handled:
IrpProcessed
The IRP was processed and possibly completed. If the driver's DpWmiXxx routine called by WmiSystemControl did not complete the IRP, the driver must call WmiCompleteRequest to complete the IRP after WmiSystemControl returns.
IrpNotCompleted
The IRP was processed but not completed, either because WMI detected an error and set up the IRP with an appropriate error code, or processed an IRP_MN_REGINFO or IRP_MN_REGINFO_EX request. The driver must complete the IRP by calling IoCompleteRequest.
IrpNotWmi
The IRP is not a WMI request (that is, WMI does not recognize the IRP's minor code). If the driver handles IRP_MJ_SYSTEM_CONTROL requests with this IRP_MN_XXX, it should handle the IRP; otherwise the driver should forward the IRP to the next lower driver.
IrpForward
The IRP is targeted to another device object (that is, the device object pointer at Parameters.WMI.ProviderId in the IRP does not match the pointer passed by the driver in its call to IoWMIRegistrationControl). The driver must forward the IRP to the next lower driver.

Return Value

WmiSystemControl returns STATUS_SUCCESS or one of the following error codes:

STATUS_INVALID_DEVICE_REQUEST

STATUS_WMI_GUID_NOT_FOUND

STATUS_WMI_INSTANCE_NOT_FOUND

Comments

When a driver receives an IRP_MJ_SYSTEM_CONTROL request with a WMI IRP minor code, it calls WmiSystemControl with a pointer to the driver's WMILIB_CONTEXT structure, a pointer to its device object, and a pointer to the IRP. The WMILIB_CONTEXT structure contains registration information for the driver's data blocks and event blocks and defines entry points for its WMI library callback routines.

WmiSystemControl confirms that the IRP is a WMI request and determines whether the block specified by the request is valid for the driver. If so, it processes the IRP by calling the appropriate DpWmiXxx entry point in the driver's WMILIB_CONTEXT structure. WMI is running at IRQL PASSIVE_LEVEL when it calls the driver's DpWmiXxx routine.

Callers of WmiSystemControl must be running at IRQL PASSIVE_LEVEL.

A driver must be running at IRQL PASSIVE_LEVEL when it forwards an IRP_MJ_SYSTEM_CONTROL request to the next-lower driver.

See Also

DpWmiExecuteMethod, DpWmiFunctionControl, DpWmiQueryDataBlock, DpWmiQueryReginfo, DpWmiSetDataBlock, DpWmiSetDataItem, WMILIB_CONTEXT


WmiTraceMessage

The WmiTraceMessage routine adds a message to the output log of a WPP software tracing session.

NTKERNELAPI
NTSTATUS
  WmiTraceMessage(
    IN TRACEHANDLE  LoggerHandle,
    IN ULONG  MessageFlags,
    IN LPGUID  MessageGuid,
    IN USHORT  MessageNumber,
    IN ...
    );

Parameters

LoggerHandle
Specifies a trace handle for a software tracing session.
MessageFlags
Specifies a bitwise OR of one or more message flags. See the Comments section for details.
MessageGuid
Specifies a GUID that identifies the class of software trace messages.
MessageNumber
Identifies the message subtype. The meaning of subtypes is specific to the software trace class and the provider.
...
Provides a required list of message parameters that specify a set of message parts. The parameters are organized as a sequence of parameter pairs, where each pair specifies one part of the complete message. Each parameter pair consists of a PVOID pointer to data, followed immediately by a ULONG value that specifies the length of the data. The parameter list must be terminated by a NULL PVOID pointer followed by a ULONG(0).

Return Value

WmiTraceMessage returns one of the following values:

NTSTATUS Value | Description
STATUS_SUCCESS | The operation completed successfully.
STATUS_INVALID_HANDLE | LoggerHandle is not a valid software trace handle.
STATUS_NO_MEMORY | There is insufficient buffer memory to log the message. See the Comments section.
Other NTSTATUS value | An internal error occurred.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

A caller can use WmiTraceMessage or WmiTraceMessageVa to add a message to the output log of a WPP software tracing session. WmiTraceMessage simplifies a caller's code by handling the variable list mechanism before calling WmiTraceMessageVa.

A caller can set the following message flags:

Flag | Description
TRACE_MESSAGE_SEQUENCE | Include a sequence number in the message. Message sequencing can only be used if it is set for the software tracing session specified by LoggerHandle.
TRACE_MESSAGE_GUID | MessageGuid specifies a GUID that identifies a software trace class. This flag must be set.
TRACE_MESSAGE_TIMESTAMP | Include a time stamp in the message.
TRACE_MESSAGE_PERFORMANCE_TIMESTAMP | The time stamp is the performance counter (not the system clock). This flag is valid only if TRACE_MESSAGE_TIMESTAMP is also specified.
TRACE_MESSAGE_SYSTEMINFO | Include the thread identifier (TID) and process identifier (PID) in the message.

A message will not be logged if one of the following is true:

  • The total size, in bytes, of the message data and the message header is greater than the size of individual message buffers allocated for a software tracing session. (The maximum message header size is 48 bytes.)
  • All message buffers allocated to software tracing session are full.

WmiTraceMessage runs at the IRQL of the caller.

For more information about software tracing, see WMI Support for Tracing Driver Operation.

See Also

IoWmiWriteEvent, TRACE_INFORMATION_CLASS, WmiFireEvent, WmiQueryTraceInformation, WmiTraceMessageVa


WmiTraceMessageVa

The WmiTraceMessageVa routine adds a message to the output log of a WPP software tracing session.

NTKERNELAPI
NTSTATUS
  WmiTraceMessageVa(
    IN TRACEHANDLE  LoggerHandle,
    IN ULONG  MessageFlags,
    IN LPGUID  MessageGuid,
    IN USHORT  MessageNumber,
    IN va_list  MessageArgList
    );

Parameters

LoggerHandle
Specifies a trace handle for a software tracing session.
MessageFlags
Specifies a bitwise OR of one or more message flags. See the Comments section for details.
MessageGuid
Specifies a GUID that identifies a software trace class.
MessageNumber
Identifies the message subtype. The meaning of subtypes is specific to the software trace class and the provider.
MessageArgList
Provides a required list of message parameters that specify a set of message parts. The parameters are organized as a sequence of parameter pairs, where each pair specifies one part of the complete message. Each parameter pair consists of a PVOID pointer to data, followed immediately by a ULONG value that specifies the length of the data. The parameter list must be terminated by a NULL PVOID pointer followed by a ULONG(0).

Return Value

WmiTraceMessageVa returns one of the following values:

NTSTATUS Value | Description
STATUS_SUCCESS | The operation completed successfully.
STATUS_INVALID_HANDLE | LoggerHandle is not a valid software trace handle.
STATUS_NO_MEMORY | There is insufficient buffer memory to log the message. See the Comments section for more information.
Other NTSTATUS value | An internal error occurred.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

A caller can use WmiTraceMessage or WmiTraceMessageVa to add a message to the output log of a WPP software tracing session. WmiTraceMessage simplifies a caller's code by handling the variable list mechanism before calling WmiTraceMessageVa.

A caller can set the following message flags:

Flag | Description
TRACE_MESSAGE_SEQUENCE | Include a sequence number in the message. Message sequencing can only be used if it is enabled for the software tracing session specified by LoggerHandle.
TRACE_MESSAGE_GUID | MessageGuid specifies a GUID that identifies a software trace class. This flag must be set.
TRACE_MESSAGE_TIMESTAMP | Include a time stamp in the message.
TRACE_MESSAGE_PERFORMANCE_TIMESTAMP | The time stamp is the performance counter (not the system clock). This flag is valid only if TRACE_MESSAGE_TIMESTAMP is also specified.
TRACE_MESSAGE_SYSTEMINFO | Include the thread identifier (TID) and process identifier (PID) in the message.

WmiTraceMessageVa does not log the message if one of the following is true:

  • The total size, in bytes, of the message data and the message header is greater than the size of individual message buffers allocated for a software tracing session. (The maximum message header size is 48 bytes.)
  • All message buffers allocated to software tracing session are full.

WmiTraceMessageVa runs at the IRQL of the caller.

For more information about software tracing, see WMI Support for Tracing Driver Operation.

See Also

IoWmiWriteEvent, TRACE_INFORMATION_CLASS, WmiFireEvent, WmiQueryTraceInformation, WmiTraceMessage


WMI Library Callback Routines

This describes required and optional routines that a driver must implement to handle WMI IRPs by calling WMI library support routines. A driver sets entry points to its DpWmiXxx routines in the WMILIB_CONTEXT structure the driver passes to WmiSystemControl.

The driver's DpWmiXxx routines can have any names chosen by the driver writer.

For information about WMI library support routines, see WMI Library Support Routines.


DpWmiExecuteMethod

DpWmiExecuteMethod executes a method associated with a data block. This routine is optional.

NTSTATUS
  DpWmiExecuteMethod(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp,
    IN ULONG  GuidIndex,
    IN ULONG  InstanceIndex,
    IN ULONG  MethodId,
    IN ULONG  InBufferSize,
    IN ULONG  OutBufferSize,
    IN OUT PUCHAR  Buffer
    );

Parameters

DeviceObject
Points to the driver's device object.
Irp
Points to the IRP.
GuidIndex
Specifies the data block by its index into the list of GUIDs provided by the driver in the WMILIB_CONTEXT structure it passed to WmiSystemControl.
InstanceIndex
If the block specified by GuidIndex has multiple instances, InstanceIndex specifies the instance.
MethodId
Specifies the ID of the method to execute. The driver defines the method ID as an item in a data block.
InBufferSize
Indicates the size in bytes of the input data. If there is no input data, InBufferSize is zero.
OutBufferSize
Indicates the number of bytes available in the buffer for output data.
Buffer
Points to a buffer that holds the input data and receives the output data, if any, from the method. If the buffer is too small to receive all of the output, the driver returns STATUS_BUFFER_TOO_SMALL and calls WmiCompleteRequest with the size required.

Return Value

DpWmiExecuteMethod returns STATUS_SUCCESS or an appropriate error code such as the following:

STATUS_BUFFER_TOO_SMALL

STATUS_INVALID_DEVICE_REQUEST

STATUS_WMI_INSTANCE_NOT_FOUND

STATUS_WMI_ITEM_ID_NOT_FOUND

Comments

WMI calls a driver's DpWmiExecuteMethod routine after the driver calls WmiSystemControl in response to an IRP_MN_EXECUTE_METHOD request.

If a driver does not implement a DpWmiExecuteMethod routine, it must set ExecuteWmiMethod to NULL in the WMILIB_CONTEXT the driver passes to WmiSystemControl. In this case, WMI returns STATUS_INVALID_DEVICE_REQUEST to the caller in response to any IRP_MN_EXECUTE_METHOD request.

If the method generates output, the driver should check the size of the output buffer in OutBufferSize before performing any operation that might have side effects or that should not be performed twice. For example, if a method returns the values of a group of counters and then resets the counters, the driver should check the buffer size (and possibly return STATUS_BUFFER_TOO_SMALL) before resetting the counters. This ensures that WMI can safely re-send the request with a larger buffer.

After executing the method and writing output, if any, to the buffer, the driver calls WmiCompleteRequest to complete the request.

This routine can be pageable.

See Also

IRP_MN_EXECUTE_METHOD, WMILIB_CONTEXT, WmiCompleteRequest, WmiSystemControl


DpWmiFunctionControl

DpWmiFunctionControl enables or disables notification of events, and enables or disables data collection for data blocks that the driver registered as expensive to collect. This routine is optional.

NTSTATUS
  DpWmiFunctionControl(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp,
    IN ULONG  GuidIndex,
    IN WMIENABLEDISABLECONTROL  Function,
    IN BOOLEAN  Enable
    );

Parameters

DeviceObject
Points to the driver's device object.
Irp
Points to the IRP.
GuidIndex
Specifies the block by its index into the list of GUIDs provided by the driver in the WMILIB_CONTEXT structure it passed to WmiSystemControl.
Function
Specifies what to enable or disable. WmiEventControl indicates an event, and WmiDataBlockControl indicates data collection for a block that was registered as expensive to collect (that is, a block for which the driver set WMIREG_FLAG_EXPENSIVE in Flags of the WMIGUIDREGINFO structure used to register the block).
Enable
Specifies TRUE to enable the event or data collection, or FALSE to disable it.

Return Value

DpWmiFunctionControl returns STATUS_SUCCESS or an appropriate error status such as:

STATUS_WMI_GUID_NOT_FOUND

STATUS_INVALID_DEVICE_REQUEST

Comments

WMI calls a driver's DpWmiFunctionControl routine after the driver calls WmiSystemControl in response to one of the following requests:

IRP_MN_ENABLE_COLLECTION

IRP_MN_DISABLE_COLLECTION

IRP_MN_ENABLE_EVENTS

IRP_MN_DISABLE_EVENTS

If a driver does not implement a DpWmiFunctionControl routine, it must set WmiFunctionControl to NULL in the WMILIB_CONTEXT the driver passes to WmiSystemControl. WMI returns STATUS_SUCCESS to the caller.

It is unnecessary for the driver to check whether events or data collection are already enabled for a block because WMI sends a single enable request when the first data consumer enables the block, and sends a single disable request when the last data consumer disables the block. WMI will not call DpWmiFunctionControl to enable a block without an intervening call to disable it.

After enabling or disabling the event or data collection for the block, the driver calls WmiCompleteRequest to complete the request.

This routine can be pageable.

See Also

IRP_MN_ENABLE_COLLECTION, IRP_MN_DISABLE_COLLECTION, IRP_MN_ENABLE_EVENTS, IRP_MN_DISABLE_EVENTS, WMILIB_CONTEXT, WmiSystemControl


DpWmiQueryDataBlock

DpWmiQueryDataBlock returns either a single instance or all instances of a data block. This routine is required.

NTSTATUS
  DpWmiQueryDataBlock(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp,
    IN ULONG  GuidIndex,
    IN ULONG  InstanceIndex,
    IN ULONG  InstanceCount,
    IN OUT PULONG  InstanceLengthArray,
    IN ULONG  BufferAvail,
    OUT PUCHAR  Buffer
    );

Parameters

DeviceObject
Points to the driver's device object.
Irp
Points to the IRP.
GuidIndex
Specifies the data block by its index into the list of GUIDs provided by the driver in the WMILIB_CONTEXT structure it passed to WmiSystemControl.
InstanceIndex
If DpWmiQueryDataBlock is called in response to an IRP_MN_QUERY_SINGLE_INSTANCE request, InstanceIndex specifies the instance to be queried. If DpWmiQueryDataBlock is called in response to an IRP_MN_QUERY_ALL_DATA request, InstanceIndex is zero.
InstanceCount
If DpWmiQueryDataBlock is called in response to an IRP_MN_QUERY_SINGLE_INSTANCE request, InstanceCount is 1. If DpWmiQueryDataBlock is called in response to an IRP_MN_QUERY_ALL_DATA request, InstanceCount is the number of instances to be returned.
InstanceLengthArray
Points to an array of ULONGs that indicate the length of each instance to be returned. If the buffer at Buffer is too small to receive all of the data, the driver sets InstanceLengthArray to NULL.
BufferAvail
Specifies the maximum number of bytes available to receive data in the buffer at Buffer.
Buffer
Points to the buffer to receive instance data. If the buffer is large enough to receive all of the data, the driver writes instance data to the buffer with each instance aligned on an 8-byte boundary. If the buffer is too small to receive all of the data, the driver calls WmiCompleteRequest with BufferUsed set to the size required.

Return Value

DpWmiQueryDataBlock returns STATUS_SUCCESS or an error status such as the following:

STATUS_BUFFER_TOO_SMALL

STATUS_WMI_GUID_NOT_FOUND

STATUS_WMI_INSTANCE_NOT_FOUND

If the driver cannot complete the request immediately, it can return STATUS_PENDING.

Comments

WMI calls a driver's DpWmiQueryDataBlock routine after the driver calls WmiSystemControl in response to an IRP_MN_QUERY_SINGLE_INSTANCE or IRP_MN_QUERY_ALL_DATA request.

After writing instance data to the buffer, the driver calls WmiCompleteRequest to complete the request.

This routine can be pageable.

See Also

IRP_MN_QUERY_ALL_DATA, IRP_MN_QUERY_SINGLE_INSTANCE, WMILIB_CONTEXT, WmiCompleteRequest, WmiSystemControl


DpWmiQueryReginfo

DpWmiQueryReginfo provides information about the data blocks and event blocks to be registered by a driver. This routine is required.

NTSTATUS
  DpWmiQueryReginfo(
    IN PDEVICE_OBJECT  DeviceObject,
    OUT PULONG  RegFlags,
    OUT PUNICODE_STRING  InstanceName,
    OUT PUNICODE_STRING  *RegistryPath,
    OUT PUNICODE_STRING  MofResourceName,
    OUT PDEVICE_OBJECT  *Pdo
    );

Parameters

DeviceObject
Points to the driver's device object.
RegFlags
Indicates common characteristics of all blocks being registered. Any flag set in RegFlags is applied to all blocks. A driver can supplement RegFlags for a given block by setting Flags in the block's WMIGUIDREGINFO structure. For example, a driver might clear WMIREG_FLAG_EXPENSIVE in RegFlags, but set it in Flags to register a given block as expensive to collect.

The driver sets one of the following flags in RegFlags:

WMIREG_FLAG_INSTANCE_BASENAME
Requests WMI to generate static instance names from a base name provided by the driver at the InstanceName. WMI generates instance names by appending a counter to the base name.
WMIREG_FLAG_INSTANCE_PDO
Requests WMI to generate static instance names from the device instance ID for the PDO. If the driver sets this flag, it must also set Pdo to the PDO passed to the driver's AddDevice routine. WMI generates instance names from the device instance path of the PDO. Using the device instance path as a base for static instance names is efficient because such names are guaranteed to be unique. WMI automatically supplies a "friendly" name for the instance as an item in a data block that can be queried by data consumers.

A driver might also set one or more of the following flags in RegFlags, but more typically would set them in Flags of a block's WMIGUIDREGINFO structure:

WMIREG_FLAG_EVENT_ONLY_GUID
The blocks can be enabled or disabled as events only, and cannot be queried or set. If this flag is clear, the blocks can also be queried or set.
WMIREG_FLAG_EXPENSIVE
Requests WMI to send an IRP_MN_ENABLE_COLLECTION request the first time a data consumer opens a data block and an IRP_MN_DISABLE_COLLECTION request when the last data consumer closes the data block. This is recommended if collecting such data affects performance, because a driver need not collect the data until a data consumer explicitly requests it by opening the block.
WMIREG_FLAG_REMOVE_GUID
Requests WMI to remove support for the blocks. This flag is valid only in response to a request to update registration information (IRP_MN_REGINFO or IRP_MN_REGINFO_EX with Parameters.WMI.DataPath set to WMIUPDATE).
InstanceName
Points to a single counted Unicode string that serves as the base name for all instances of all blocks to be registered by the driver. WMI frees the string with ExFreePool. If WMIREG_FLAG_INSTANCE_BASENAME is clear, InstanceName is ignored.
RegistryPath
Points to a counted Unicode string that specifies the registry path passed to the driver's DriverEntry routine.
MofResourceName
Points to a single counted Unicode string that indicates the name of the MOF resource attached to the driver's binary image file. Typically this string would be a static defined by the driver. WMI makes a copy of this string after the driver returns from this routine. This string can be dynamically allocated by the driver. In the case of an allocated string, the driver is responsible for freeing the string which should be done after WmiSystemControl returns. If the driver does not have a MOF resource attached, it can leave MofResourceName unchanged.
Pdo
Points to the physical device object (PDO) passed to the driver's AddDevice routine. If WMIREG_FLAG_INSTANCE_PDO is set, WMI uses the device instance path of this PDO as a base from which to generate static instance names. If WMIREG_FLAG_INSTANCE_PDO is clear, WMI ignores Pdo.

Return Value

DpWmiQueryReginfo always returns STATUS_SUCCESS

Comments

WMI calls a driver's DpWmiQueryReginfo after the driver calls WmiSystemControl in response to an IRP_MN_REGINFO or IRP_MN_REGINFO_EX request. WMI sends this IRP after a driver calls KRlwith WMIREG_ACTION_REGISTER, WMIREG_ACTION_REREGISTER, or WMIREG_ACTION_UPDATE. WMI transparently handles the differences between IRP_MN_REGINFO and IRP_MN_REGINFO_EX on behalf of the driver.

WMI does not send an IRP_MN_REGINFO or IRP_MN_REGINFO_EX request after a driver calls IoWMIRegistrationControl with WMIREG_ACTION_DEREGISTER, because WMI requires no further information from the driver. A driver typically deregisters its blocks in response to an IRP_MN_REMOVE_DEVICE request.

The driver provides new or updated registration information about individual blocks, or indicates blocks to remove, in the WMILIB_CONTEXT structure it passes to WmiSystemControl. After the initial call, which establishes the driver's registry path and MOF resource name, a driver's DpWmiQueryReginfo routine can change flags common to all of a driver's blocks, provide a different base name string used to generate instance names, or change the basis for instance names from a string to the device instance path of the PDO.

The driver must not return STATUS_PENDING or block the request. The driver must not complete the request by calling WmiCompleteRequest from its DpWmiQueryReginfo routine or by calling IoCompleteRequest after WmiSystemControl returns.

This routine can be pageable.

See Also

IoWMIRegistrationControl, IRP_MN_REGINFO_EX, WMILIB_CONTEXT, WMIGUIDREGINFO, WmiSystemControl


DpWmiSetDataBlock

DpWmiSetDataBlock changes all data items in a single instance of a data block. This routine is optional.

NTSTATUS
  DpWmiSetDataBlock(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp,
    IN ULONG  GuidIndex,
    IN ULONG  InstanceIndex,
    IN ULONG  BufferSize,
    IN PUCHAR  Buffer
    );

Parameters

DeviceObject
Points to the driver's device object.
Irp
Points to the IRP.
GuidIndex
Specifies the data block by its index into the list of GUIDs provided by the driver in the WMILIB_CONTEXT structure it passed to WmiSystemControl.
InstanceIndex
If the block specified by GuidIndex has multiple instances, InstanceIndex specifies the instance.
BufferSize
Specifies the size in bytes of the buffer at Buffer.
Buffer
Points to a buffer that contains new values for the instance.

Return Value

DpWmiSetDataBlock returns STATUS_SUCCESS or an appropriate error status such as the following:

STATUS_WMI_INSTANCE_NOT_FOUND

STATUS_WMI_GUID_NOT_FOUND

STATUS_WMI_READ_ONLY

STATUS_WMI_SET_FAILURE

If the driver cannot complete the request immediately, it can return STATUS_PENDING.

Comments

WMI calls a driver's DpWmiSetDataBlock routine after the driver calls WmiSystemControl in response to an IRP_MN_CHANGE_SINGLE_INSTANCE request.

If a driver does not implement a DpWmiSetDataBlock routine, it must set SetWmiDataBlock to NULL in the WMILIB_CONTEXT the driver passes to WmiSystemControl. WMI returns STATUS_READ_ONLY to the caller.

This routine can be pageable.

See Also

IRP_MN_CHANGE_SINGLE_INSTANCE, WMILIB_CONTEXT, WmiSystemControl


DpWmiSetDataItem

DpWmiSetDataItem changes a single data item in an instance of a data block. This routine is optional.

NTSTATUS
  DpWmiSetDataItem(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp,
    IN ULONG  GuidIndex,
    IN ULONG  InstanceIndex,
    IN ULONG  DataItemId,
    IN ULONG  BufferSize,
    IN PUCHAR  Buffer
    );

Parameters

DeviceObject
Points to the driver's device object.
Irp
Points to the IRP.
GuidIndex
Specifies the data block by its index into the list of GUIDs provided by the driver in the WMILIB_CONTEXT structure it passed to WmiSystemControl.
InstanceIndex
If the block specified by GuidIndex has multiple instances, InstanceIndex specifies the instance.
DataItemId
Specifies the ID of the data item to set.
BufferSize
Specifies the size in bytes of the buffer at Buffer.
Buffer
Points to a buffer that contains the new value for the data item.

Return Value

DpWmiSetDataItem returns STATUS_SUCCESS or an appropriate error code such as the following:

STATUS_WMI_INSTANCE_NOT_FOUND

STATUS_WMI_INSTANCE_ID_NOT_FOUND

STATUS_WMI_GUID_NOT_FOUND

STATUS_WMI_READ_ONLY

STATUS_WMI_SET_FAILURE

Comments

WMI calls a driver's DpWmiSetDataItem routine after the driver calls WmiSystemControl in response to an IRP_MN_CHANGE_SINGLE_ITEM request.

If a driver does not implement a DpWmiSetDataItem routine, it must set SetWmiDataItem to NULL in the WMILIB_CONTEXT the driver passes to WmiSystemControl. WMI returns STATUS_READ_ONLY to the caller.

This routine can be pageable.

See Also

IRP_MN_CHANGE_SINGLE_ITEM, WMILIB_CONTEXT, WmiSystemControl


System Structures

This chapter describes system structures and objects that are parameters to system support routines or standard driver routines. It also describes some bus-type-specific and device-type-specific configuration structures that the system defines for the convenience of driver writers.


ACCESS_MASK

A bitmask that specifies a set of access rights.

See ZwCreateFile for a description of the access rights applicable to a file or device. See ZwCreateDirectoryObject for a description of the access rights applicable to a directory. See ZwCreateKey for a description of the access rights applicable to a registry key. See ZwOpenSection for a description of the access rights applicable to a section object. See IoWMIOpenBlock for a description of the access rights applicable to a WMI data block.

For more information about access rights, see the ACCESS_MASK reference page in the Platform SDK documentation.

See Also

IoWMIOpenBlock, ZwCreateDirectoryObject, ZwCreateFile, ZwCreateKey, ZwOpenSection


ANSI_STRING

The STRING structure defines a counted string used for ANSI strings.

typedef struct _STRING {
  USHORT  Length;
  USHORT  MaximumLength;
  PCHAR  Buffer;
} STRING *PANSI_STRING;

Members

Length
The length in bytes of the string stored in Buffer.
MaximumLength
The maximum length in bytes of Buffer.
Buffer
Points to a buffer used to contain a string of characters.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

The STRING structure is used to pass ANSI strings.

If the string is NULL terminated, Length does not include the trailing NULL.

The MaximumLength is used to indicate the length of Buffer so that if the string is passed to a conversion routine such as RtlUnicodeStringToAnsiString the returned string does not exceed the buffer size.

See Also

OEM_STRING, UNICODE_STRING, RtlAnsiStringToUnicodeSize, RtlAnsiStringToUnicodeString, RtlFreeAnsiString, RtlInitAnsiString, RtlUnicodeStringToAnsiString


BOOTDISK_INFORMATION

The BOOTDISK_INFORMATION structure contains basic information describing the boot and system disks.

typedef struct _BOOTDISK_INFORMATION {
  LONGLONG  BootPartitionOffset;
  LONGLONG  SystemPartitionOffset;
  ULONG  BootDeviceSignature;
  ULONG  SystemDeviceSignature;
} BOOTDISK_INFORMATION, *PBOOTDISK_INFORMATION;

Members

BootPartitionOffset
Specifies the offset, in bytes, on the boot disk where the boot partition begins.
SystemPartitionOffset
Specifies the offset, in bytes, on the system disk where the system partition begins.
BootDeviceSignature
If the boot disk is formatted with an MBR partition table, this specifies the signature for the disk's MBR partition table. Otherwise, this member is unused.
SystemDeviceSignature
If the system disk is formatted with an MBR partition table, this specifies the signature for the disk's MBR partition table. Otherwise, this member is unused.

Comments

IoGetBootDiskInformation returns this structure to describe the boot and system disks. Drivers on Windows XP and later should use the BOOTDISK_INFORMATION_EX structure instead.

See Also

IoGetBootDiskInformation, BOOTDISK_INFORMATION_EX


BOOTDISK_INFORMATION_EX

The BOOTDISK_INFORMATION_EX structure contains extended information describing the boot and system disks.

typedef struct _BOOTDISK_INFORMATION_EX {
  LONGLONG  BootPartitionOffset;
  LONGLONG  SystemPartitionOffset;
  ULONG  BootDeviceSignature;
  ULONG  SystemDeviceSignature;
  GUID  BootDeviceGuid;
  GUID  SystemDeviceGuid;
  BOOLEAN  BootDeviceIsGpt;
  BOOLEAN  SystemDeviceIsGpt;
} BOOTDISK_INFORMATION_EX, *PBOOTDISK_INFORMATION_EX;

Members

BootPartitionOffset
Specifies the offset, in bytes, on the boot disk where the boot partition begins.
SystemPartitionOffset
Specifies the offset, in bytes, on the system disk where the system partition begins.
BootDeviceSignature
If the BootDeviceIsGpt member is FALSE, this specifies the signature for the disk's MBR partition table. Otherwise, this member is unused.
SystemDeviceSignature
If the SystemDeviceIsGpt member is FALSE, this specifies the signature for the disk's MBR partition table. Otherwise, this member is unused.
BootDeviceGuid
If the BootDeviceIsGpt member is TRUE, this specifies the GUID for the boot disk. Otherwise, this member is unused.
SystemDeviceGuid
If the SystemDeviceIsGpt member is TRUE, this specifies the GUID for the boot disk. Otherwise, this member is unused.
BootDeviceIsGpt
TRUE if the boot disk is formatted with the GPT partition table type.
SystemDeviceIsGpt
TRUE if the system disk is formatted with the GPT partition table type.

Comments

On Windows XP and later, IoGetBootDiskInformation returns this structure to describe the boot and system disks.

See Also

IoGetBootDiskInformation, BOOTDISK_INFORMATION


CM_EISA_FUNCTION_INFORMATION

CM_EISA_FUNCTION_INFORMATION defines detailed EISA configuration information returned by HalGetBusData for the input BusDataType EisaConfiguration, or by HalGetBusDataByOffset for the input BusDataType EisaConfiguration and the Offset zero, assuming the caller-allocated Buffer is of sufficient Length.

typedef struct _CM_EISA_FUNCTION_INFORMATION {
  ULONG  CompressedId;
  UCHAR  IdSlotFlags1;
  UCHAR  IdSlotFlags2;
  UCHAR  MinorRevision;
  UCHAR  MajorRevision;
  UCHAR  Selections[26];
  UCHAR  FunctionFlags;
  UCHAR  TypeString[80];
  EISA_MEMORY_CONFIGURATION  EisaMemory[9];
  EISA_IRQ_CONFIGURATION  EisaIrq[7];
  EISA_DMA_CONFIGURATION  EisaDma[4];
  EISA_PORT_CONFIGURATION  EisaPort[20];
  UCHAR  InitializationData[60];
} CM_EISA_FUNCTION_INFORMATION, *PCM_EISA_FUNCTION_INFORMATION;

Members

CompressedId
The EISA compressed identification of the device at this slot. The value is identical to the CompressedId member of the CM_EISA_SLOT_INFORMATION structure.
IdSlotFlags1
The EISA slot identification flags.
IdSlotFlags2
The EISA slot identification flags.
MinorRevision
Information supplied by the manufacturer.
MajorRevision
Information supplied by the manufacturer.
Selections[26]
The EISA selections for the device.
FunctionFlags
Indicates which of the members has available information. Callers can use the following system-defined masks to determine whether a particular type of configuration information can be or has been returned by HalGetBusData or HalGetBusDataByOffset:

EISA_FUNCTION_ENABLED
EISA_FREE_FORM_DATA
EISA_HAS_PORT_INIT_ENTRY
EISA_HAS_PORT_RANGE
EISA_HAS_DMA_ENTRY
EISA_HAS_IRQ_ENTRY
EISA_HAS_MEMORY_ENTRY
EISA_HAS_TYPE_ENTRY
EISA_HAS_INFORMATION

The EISA_HAS_INFORMATION mask is a combination of the following:

EISA_HAS_PORT_RANGE
EISA_HAS_DMA_ENTRY
EISA_HAS_IRQ_ENTRY
EISA_HAS_MEMORY_ENTRY
EISA_HAS_TYPE_ENTRY

TypeString[80]
Specifies the type of device.
EisaMemory[9]
Describes the EISA device memory configuration information, defined as follows:
typedef struct _EISA_MEMORY_CONFIGURATION {
    EISA_MEMORY_TYPE ConfigurationByte;
    UCHAR DataSize;
    USHORT AddressLowWord;
    UCHAR AddressHighByte;
    USHORT MemorySize;
} EISA_MEMORY_CONFIGURATION, *PEISA_MEMORY_CONFIGURATION;
EisaIrq[7]
Describes the EISA interrupt configuration information, defined as follows:
typedef struct _EISA_IRQ_CONFIGURATION {
    EISA_IRQ_DESCRIPTOR ConfigurationByte;
    UCHAR Reserved;
} EISA_IRQ_CONFIGURATION, *PEISA_IRQ_CONFIGURATION;
EisaDma[4]
Describes the EISA DMA configuration information, defined as follows:
typedef struct _EISA_DMA_CONFIGURATION {
    DMA_CONFIGURATION_BYTE0 ConfigurationByte0;
    DMA_CONFIGURATION_BYTE1 ConfigurationByte1;
} EISA_DMA_CONFIGURATION, *PEISA_DMA_CONFIGURATION;
EisaPort[20]
Describes the EISA device port configuration information, defined as follows:
typedef struct _EISA_PORT_CONFIGURATION {
    EISA_PORT_DESCRIPTOR Configuration;
    USHORT PortAddress;
} EISA_PORT_CONFIGURATION, *PEISA_PORT_CONFIGURATION;
InitializationData[60]
Vendor-supplied, device-specific initialization data, if any.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

The information returned by HalGetBusData or HalGetBusDataByOffset in CM_EISA_FUNCTION_INFORMATION and/or in the CM_EISA_SLOT_INFORMATION header immediately preceding it is read-only.

See Also

CM_EISA_SLOT_INFORMATION, HalGetBusData, HalGetBusDataByOffset


CM_EISA_SLOT_INFORMATION

CM_EISA_SLOT_INFORMATION defines EISA configuration header information returned by HalGetBusData for the input BusDataType EisaConfiguration, or by HalGetBusDataByOffset for the input BusDataType EisaConfiguration and the Offset zero, assuming the caller-allocated Buffer is of sufficient Length.

typedef struct _CM_EISA_SLOT_INFORMATION {
  UCHAR  ReturnCode;
  UCHAR  ReturnFlags;
  UCHAR  MajorRevision;
  UCHAR  MinorRevision;
  USHORT  Checksum;
  UCHAR  NumberFunctions;
  UCHAR  FunctionInformation;
  ULONG  CompressedId;
} CM_EISA_SLOT_INFORMATION, *PCM_EISA_SLOT_INFORMATION;

Members

ReturnCode
Contains a status code if an error occurs when the EISA BIOS is queried. Possible status codes include the following:

EISA_INVALID_SLOT
EISA_INVALID_FUNCTION
EISA_INVALID_CONFIGURATION
EISA_EMPTY_SLOT
EISA_INVALID_BIOS_CALL

ReturnFlags
The return flags.
MajorRevision
Information supplied by the manufacturer.
MinorRevision
Information supplied by the manufacturer.
Checksum
The checksum value, allowing validation of the configuration data.
NumberFunctions
The number at this slot.
FunctionInformation
Whether there is available CM_EISA_FUNCTION_INFORMATION for this slot.
CompressedId
The EISA compressed identification of the device at this slot. This value is identical to the CompressedId member of the CM_EISA_FUNCTION_INFORMATION structure. This member can be read to determine whether the caller should call HalGetBusData or HalGetBusDataByOffset again with sufficient buffer space to get more detailed CM_EISA_FUNCTION_INFORMATION for a device it supports.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

The information returned by HalGetBusData or HalGetBusDataByOffset in CM_EISA_SLOT_INFORMATION and in CM_EISA_FUNCTION_INFORMATION immediately following it is read-only.

The driver of an EISA device might call HalGetBusData or HalGetBusDataByOffset for each slot on each EISA bus in the system, requesting only CM_EISA_SLOT_INFORMATION in order to find the device(s) it supports by examining the returned CompressedId values. Then, such a driver could allocate sufficient buffer space to call HalGetBusData(ByOffset) again for CM_EISA_SLOT_INFORMATION and CM_EISA_FUNCTION_INFORMATION at slots where its device(s) can be found.

See Also

CM_EISA_FUNCTION_INFORMATION, HalGetBusData, HalGetBusDataByOffset


CM_FLOPPY_DEVICE_DATA

CM_FLOPPY_DEVICE_DATA defines a device-type-specific data record that is stored in the \\Registry\Machine\Hardware\Description tree for a floppy controller if the system can collect this information during the boot process.

typedef struct _CM_FLOPPY_DEVICE_DATA {
  USHORT  Version;
  USHORT  Revision;
  CHAR  Size[8];
  ULONG  MaxDensity;
  ULONG  MountDensity;
  //
  // New data fields for version >= 2.0
  //
  UCHAR  StepRateHeadUnloadTime;
  UCHAR  HeadLoadTime;
  UCHAR  MotorOffTime;
  UCHAR  SectorLengthCode;
  UCHAR  SectorPerTrack;
  UCHAR  ReadWriteGapLength;
  UCHAR  DataTransferLength;
  UCHAR  FormatGapLength;
  UCHAR  FormatFillCharacter;
  UCHAR  HeadSettleTime;
  UCHAR  MotorSettleTime;
  UCHAR  MaximumTrackValue;
  UCHAR  DataTransferRate;
} CM_FLOPPY_DEVICE_DATA, *PCM_FLOPPY_DEVICE_DATA;

Members

Version
The version number of this structure.
Revision
The revision of this structure.
Size[8]
The floppy disk density size.
MaxDensity
The maximum density.
MountDensity
The mount density.
StepRateHeadUnloadTime
The step rate head unload time in milliseconds.
HeadLoadTime
The head load time in milliseconds.
MotorOffTime
The motor off time in seconds.
SectorLengthCode
Indicates the sector size as an exponent in the formula ((2**code) * 128).
SectorPerTrack
The number of sectors per track.
ReadWriteGapLength
The read/write gap length, in bytes.
DataTransferLength
The data transfer length, in bytes, not including the synchronization field.
FormatGapLength
The format gap length, in bytes.
FormatFillCharacter
The format fill character.
HeadSettleTime
The head settle time in milliseconds.
MotorSettleTime
The motor settle time in milliseconds.
MaximumTrackValue
The maximum track number on the media. Track numbers are zero-based values.
DataTransferRate
The value written to the Datarate register before accessing the media.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

See Also

IoQueryDeviceDescription, IoReportResourceUsage, CM_PARTIAL_RESOURCE_DESCRIPTOR


CM_FULL_RESOURCE_DESCRIPTOR

A CM_FULL_RESOURCE_DESCRIPTOR structure specifies a set of system hardware resources of various types, assigned to a device that is connected to a specific bus. This structure is contained within a CM_RESOURCE_LIST structure.

typedef struct _CM_FULL_RESOURCE_DESCRIPTOR {
  INTERFACE_TYPE  InterfaceType;
  ULONG  BusNumber;
  CM_PARTIAL_RESOURCE_LIST  PartialResourceList;
} CM_FULL_RESOURCE_DESCRIPTOR, *PCM_FULL_RESOURCE_DESCRIPTOR;

Members

InterfaceType
Specifies the type of bus to which the device is connected. This must be one of the types defined by INTERFACE_TYPE, in wdm.h or ntddk.h. (Not used by WDM drivers.)
BusNumber
The system-assigned, driver-supplied, zero-based number of the bus to which the device is connected. (Not used by WDM drivers.)
PartialResourceList
A CM_PARTIAL_RESOURCE_LIST structure.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

See Also

CM_RESOURCE_LIST, CM_PARTIAL_RESOURCE_LIST


CM_INT13_DRIVE_PARAMETER

CM_INT13_DRIVE_PARAMETER defines a device-type-specific data record that is stored in the \\Registry\Machine\Hardware\Description tree for a disk controller if the system can collect this information during the boot process.

typedef struct _CM_INT13_DRIVE_PARAMETER {
  USHORT  DriveSelect;
  ULONG  MaxCylinders;
  USHORT  SectorsPerTrack;
  USHORT  MaxHeads;
  USHORT  NumberDrives;
} CM_INT13_DRIVE_PARAMETER, *PCM_INT13_DRIVE_PARAMETER;

Members

DriveSelect
The drive selected value.
MaxCylinders
The maximum number of cylinders.
SectorsPerTrack
The number of sectors per track.
MaxHeads
The maximum number of heads.
NumberDrives
The number of drives.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

See Also

IoQueryDeviceDescription, IoReportResourceUsage


CM_KEYBOARD_DEVICE_DATA

CM_KEYBOARD_DEVICE_DATA defines a device-type-specific data record that is stored in the \\Registry\Machine\Hardware\Description tree for a keyboard peripheral if the system can collect this information during the boot process.

typedef struct _CM_KEYBOARD_DEVICE_DATA {
  USHORT  Version;
  USHORT  Revision;
  UCHAR  Type;
  UCHAR  Subtype;
  USHORT  KeyboardFlags;
} CM_KEYBOARD_DEVICE_DATA, *PCM_KEYBOARD_DEVICE_DATA;

Members

Version
The version number of this structure.
Revision
The revision of this structure.
Type
The type of the keyboard.
Subtype
The subtype of the keyboard.
KeyboardFlags
Defined by x86 BIOS INT 16h, function 02 as:
Bit | Defined As
7 | Insert on.
6 | Caps Lock on.
5 | Num Lock on.
4 | Scroll Lock on.
3 | Alt Key is down.
2 | Ctrl Key is down.
1 | Left shift key is down.
0 | Right shift key is down.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

See Also

IoQueryDeviceDescription, IoReportResourceUsage, CM_PARTIAL_RESOURCE_DESCRIPTOR


CM_MCA_POS_DATA

CM_MCA_POS_DATA defines IBM-compatible MCA POS configuration information for a slot.

typedef struct _CM_MCA_POS_DATA {
  USHORT  AdapterId;
  UCHAR  PosData1;
  UCHAR  PosData2;
  UCHAR  PosData3;
  UCHAR  PosData4;
} CM_MCA_POS_DATA, *PCM_MCA_POS_DATA;

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

See Also

HalGetBusData, HalGetBusDataByOffset


CM_PARTIAL_RESOURCE_DESCRIPTOR

The CM_PARTIAL_RESOURCE_DESCRIPTOR structure specifies one or more system hardware resources, of a single type, assigned to a device. This structure is used to create an array within a CM_PARTIAL_RESOURCE_LIST structure.

typedef struct _CM_PARTIAL_RESOURCE_DESCRIPTOR {
    UCHAR Type;
    UCHAR ShareDisposition;
    USHORT Flags;
    union {
        struct {
            PHYSICAL_ADDRESS Start;
            ULONG Length;
        } Generic;
        struct {
            PHYSICAL_ADDRESS Start;
            ULONG Length;
        } Port;
        struct {
            ULONG Level;
            ULONG Vector;
            ULONG Affinity;
        } Interrupt;
        struct {
            PHYSICAL_ADDRESS Start;
            ULONG Length;
        } Memory;
        struct {
            ULONG Channel;
            ULONG Port;
            ULONG Reserved1;
        } Dma;
        struct {
            ULONG Data[3];
        } DevicePrivate;
        struct {
            ULONG Start;
            ULONG Length;
            ULONG Reserved;
        } BusNumber;
        struct {
            ULONG DataSize;
            ULONG Reserved1;
            ULONG Reserved2;
        } DeviceSpecificData;
    } u;
} CM_PARTIAL_RESOURCE_DESCRIPTOR, *PCM_PARTIAL_RESOURCE_DESCRIPTOR;

Members

Type
Identifies the resource type. The constant value specified for Type indicates which structure within the u union is valid, as indicated in the following table. (These flags are used within both CM_PARTIAL_RESOURCE_DESCRIPTOR and IO_RESOURCE_DESCRIPTOR structures, except where noted.)
Type Value | u Member Substructure
CmResourceTypePort | u.Port
CmResourceTypeInterrupt | u.Interrupt
CmResourceTypeMemory | u.Memory
CmResourceTypeDma | u.Dma
CmResourceTypeDevicePrivate | u.DevicePrivate
CmResourceTypeBusNumber | u.BusNumber
CmResourceTypeDeviceSpecific | u.DeviceSpecificData (Not used within IO_RESOURCE_DESCRIPTOR.)
CmResourceTypePcCardConfig | u.DevicePrivate
CmResourceTypeMfCardConfig | u.DevicePrivate
CmResourceTypeConfigData | Reserved for system use.
CmResourceTypeNonArbitrated | Not used.

ShareDisposition
Indicates whether the described resource can be shared. Valid constant values are listed in the following table.
Value | Definition
CmResourceShareDeviceExclusive | The device requires exclusive use of the resource.
CmResourceShareDriverExclusive | The driver requires exclusive use of the resource. (Not supported for WDM drivers.)
CmResourceShareShared | The resource can be shared without restriction.

Flags
Contains bit flags that are specific to the resource type, as indicated in the following table. Flags can be OR'ed together as appropriate.
Resource
Type
Flag
Definition
CmResourceTypePort
CM_RESOURCE_PORT_MEMORY | The device is accessed in memory address space.
CM_RESOURCE_PORT_IO | The device is accessed in IO address space.
CM_RESOURCE_PORT_10_BIT_DECODE | The device decodes 10 bits of the port address.
CM_RESOURCE_PORT_12_BIT_DECODE | The device decodes 12 bits of the port address.
CM_RESOURCE_PORT_16_BIT_DECODE | The device decodes 16 bits of the port address.
CM_RESOURCE_PORT_POSITIVE_DECODE | The device uses "positive decode" instead of "subtractive decode". (In general, PCI devices use positive decode and ISA buses use subtractive decode.)
CM_RESOURCE_PORT_PASSIVE_DECODE | The device decodes the port but the driver does not use it.
CM_RESOURCE_PORT_WINDOW_DECODE | Reserved for system use.
CmResourceTypeInterrupt
CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE | The IRQ line is level-triggered. (These IRQs are usually shareable.)
CM_RESOURCE_INTERRUPT_LATCHED | The IRQ line is edge-triggered.
CmResourceTypeMemory
CM_RESOURCE_MEMORY_READ_WRITE | The memory range is readable and writable.
CM_RESOURCE_MEMORY_READ_ONLY | The memory range is read-only.
CM_RESOURCE_MEMORY_WRITE_ONLY | The memory range is write-only.
CM_RESOURCE_MEMORY_PREFETCHABLE | The memory range is pre-fetchable.
CM_RESOURCE_MEMORY_COMBINEDWRITE | Combined-write caching is allowed.
CM_RESOURCE_MEMORY_24 | The device uses 24-bit addressing.
CM_RESOURCE_MEMORY_CACHEABLE | The memory range is cacheable.
CmResourceTypeDma
CM_RESOURCE_DMA_8 | 8-bit DMA channel
CM_RESOURCE_DMA_16 | 16-bit DMA channel
CM_RESOURCE_DMA_32 | 32-bit DMA channel
CM_RESOURCE_DMA_8_AND_16 | 8-bit and 16-bit DMA channel
CM_RESOURCE_DMA_BUS_MASTER | The device supports bus master DMA transfers.
CM_RESOURCE_DMA_TYPE_A | Type A DMA
CM_RESOURCE_DMA_TYPE_B | Type B DMA
CM_RESOURCE_DMA_TYPE_F | Type F DMA

u.Generic
Not used.
u.Port
Specifies a range of I/O port addresses, using the following members:
Start
For raw resources: Bus-relative physical address of the lowest of a range of contiguous I/O port addresses allocated to the device.

For translated resources: System physical address of the lowest of a range of contiguous I/O port addresses allocated to the device.

Length
The length, in bytes, of the range of allocated I/O port addresses.
u.Interrupt
Specifies an interrupt vector and level, using the following members:
Level
For raw resources: The device's bus-specific IRQL (if appropriate for the platform and bus).

For translated resources: The DIRQL assigned to the device.

Vector
For raw resources: The device's bus-specific interrupt vector (if appropriate for the platform and bus).

For translated resources: The global system vector assigned to the device.

Affinity
A bit mask value indicating the set of processors the device can interrupt. If the device can interrupt any processor, set this to -1.
u.Memory
Specifies a range of memory addresses, using the following members:
Start
For raw resources: Bus-relative physical address of the lowest of a range of contiguous memory addresses allocated to the device.

For translated resources: System physical address of the lowest of a range of contiguous memory addresses allocated to the device.

Length
The length, in bytes, of the range of allocated memory addresses.
u.Dma
Specifies a DMA setting, using one of the following members:
Channel
The number of the DMA channel on a system DMA controller that the device can use.
Port
The number of the DMA port that an MCA-type device can use.
Reserved1
Not used.
u.DevicePrivate
Reserved for system use.
u.BusNumber
Specifies bus numbers, using the following members:
Start
The lowest-numbered of a range of contiguous buses allocated to the device.
Length
The number of buses allocated to the device.
Reserved
Not used.
u.DeviceSpecificData
Specifies the size of a device-specific, private structure that is appended to the end of the CM_PARTIAL_RESOURCE_DESCRIPTOR structure. If u.DeviceSpecificData is used, the CM_PARTIAL_RESOURCE_DESCRIPTOR structure must be the last one in the CM_PARTIAL_RESOURCE_LIST array.
DataSize
The number of bytes appended to the end of the CM_PARTIAL_RESOURCE_DESCRIPTOR structure.
Reserved1
Not used.
Reserved2
Not used.

Examples of device-specific structures include:
CM_FLOPPY_DEVICE_DATA,
CM_KEYBOARD_DEVICE_DATA,
CM_SCSI_DEVICE_DATA,
CM_SERIAL_DEVICE_DATA

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

A CM_PARTIAL_RESOURCE_DESCRIPTOR structure can describe either a raw (bus-relative) resource or a translated (system physical) resource, depending on the routine or IRP with which it is being used (see See Also).

See Also

CM_RESOURCE_LIST,
CM_FULL_RESOURCE_DESCRIPTOR,
CM_PARTIAL_RESOURCE_LIST,
CM_FLOPPY_DEVICE_DATA,
CM_KEYBOARD_DEVICE_DATA,
CM_SCSI_DEVICE_DATA,
CM_SERIAL_DEVICE_DATA,
IoConnectInterrupt,
IoGetDeviceProperty,
IoReportResourceForDetection,
IO_RESOURCE_DESCRIPTOR,
IRP_MN_START_DEVICE


CM_PARTIAL_RESOURCE_LIST

The CM_PARTIAL_RESOURCE_LIST structure specifies a set of system hardware resources, of various types, assigned to a device. This structure is contained within a CM_FULL_RESOURCE_DESCRIPTOR structure.

typedef struct _CM_PARTIAL_RESOURCE_LIST {
  USHORT  Version;
  USHORT  Revision;
  ULONG  Count;
  CM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptors[1];
} CM_PARTIAL_RESOURCE_LIST, *PCM_PARTIAL_RESOURCE_LIST;

Members

Version
The version number of this structure. This value should be 1.
Revision
The revision of this structure. This value should be 1.
Count
The number of elements contained in the PartialDescriptors array. For WDM drivers, this value is always 1.
PartialDescriptors
An array of CM_PARTIAL_RESOURCE_DESCRIPTOR structures.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

See Also

CM_FULL_RESOURCE_DESCRIPTOR, CM_PARTIAL_RESOURCE_DESCRIPTOR


CM_POWER_DATA

(Windows XP and later.)

The CM_POWER_DATA structure contains information about a device's power management state and capabilities.

typedef struct CM_Power_Data_s {
    ULONG               PD_Size;
    DEVICE_POWER_STATE  PD_MostRecentPowerState;
    ULONG               PD_Capabilities;
    ULONG               PD_D1Latency;
    ULONG               PD_D2Latency;
    ULONG               PD_D3Latency;
    DEVICE_POWER_STATE  PD_PowerStateMapping[PowerSystemMaximum];
} CM_POWER_DATA, *PCM_POWER_DATA;

Members

PD_Size
The size, in bytes, of this structure.
PD_MostRecentPowerState
A DEVICE_POWER_STATE value representing the device's most recent power state.
PD_Capabilities
The device's power capabilities, represented by a combination of the following bit flags:

PDCAP_D0_SUPPORTED

PDCAP_D1_SUPPORTED

PDCAP_D2_SUPPORTED

PDCAP_D3_SUPPORTED

PDCAP_WAKE_FROM_D0_SUPPORTED

PDCAP_WAKE_FROM_D1_SUPPORTED

PDCAP_WAKE_FROM_D2_SUPPORTED

PDCAP_WAKE_FROM_D3_SUPPORTED

PDCAP_WARM_EJECT_SUPPORTED

PD_D1Latency
The device's latency when returning the D0 state from the D1 state. For more information, see the D1Latency member of DEVICE_CAPABILITIES.
PD_D2Latency
The device's latency when returning the D0 state from the D2 state. For more information, see the D2Latency member of DEVICE_CAPABILITIES.
PD_D3Latency
The device's latency when returning the D0 state from the D3 state. For more information, see the D3Latency member of DEVICE_CAPABILITIES.
PD_PowerStateMapping
An array of DEVICE_POWER_STATE values representing the maximum device power state achievable for each system power state. For more information, see the DeviceState member of DEVICE_CAPABILITIES.

Headers

Defined in ntddk.h. Include ntddk.h.

See Also

SetupDiGetDeviceRegistryProperty


CM_RESOURCE_LIST

The CM_RESOURCE_LIST structure specifies all of the system hardware resources assigned to a device.

typedef struct _CM_RESOURCE_LIST {
  ULONG  Count;
  CM_FULL_RESOURCE_DESCRIPTOR  List[1];
} CM_RESOURCE_LIST, *PCM_RESOURCE_LIST;

Members

Count
The number of elements contained in the List array. For WDM drivers, this value is always 1.
List
An array of CM_FULL_RESOURCE_DESCRIPTOR structures.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

The CM_RESOURCE_LIST structure defines the format used to store device resource lists in the registry. For more information about hardware resource allocation, see Hardware Resources.

See Also

CM_RESOURCE_LIST,
CM_FULL_RESOURCE_DESCRIPTOR,
CM_PARTIAL_RESOURCE_LIST,
CM_FLOPPY_DEVICE_DATA,
CM_KEYBOARD_DEVICE_DATA,
CM_SCSI_DEVICE_DATA,
CM_SERIAL_DEVICE_DATA,
IoConnectInterrupt,
IoGetDeviceProperty,
IoReportResourceForDetection,
IRP_MN_START_DEVICE


CM_SCSI_DEVICE_DATA

CM_SCSI_DEVICE_DATA defines a device-type-specific data record that is stored in the \\Registry\Machine\Hardware\Description tree for a SCSI HBA if the system can collect this information during the boot process.

typedef struct _CM_SCSI_DEVICE_DATA {
  USHORT  Version;
  USHORT  Revision;
  UCHAR  HostIdentifier;
} CM_SCSI_DEVICE_DATA, *PCM_SCSI_DEVICE_DATA;

Members

Version
The version number of this structure.
Revision
The revision for this structure.
HostIdentifier
The SCSI bus identifier used by the ARC firmware.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

See Also

IoQueryDeviceDescription, IoReportResourceUsage, CM_PARTIAL_RESOURCE_DESCRIPTOR


CM_SERIAL_DEVICE_DATA

CM_SERIAL_DEVICE_DATA defines a device-type-specific data record that is stored in the \\Registry\Machine\Hardware\Description tree for a serial controller if the system can collect this information during the boot process.

typedef struct _CM_SERIAL_DEVICE_DATA {
  USHORT  Version;
  USHORT  Revision;
  ULONG  BaudClock;
} CM_SERIAL_DEVICE_DATA, *PCM_SERIAL_DEVICE_DATA;

Members

Version
The version number of this structure.
Revision
The revision of this structure.
BaudClock
The clock baud rate, in MHz, at which data is transferred.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

See Also

IoQueryDeviceDescription, IoReportResourceUsage, CM_PARTIAL_RESOURCE_DESCRIPTOR


CONTROLLER_OBJECT

A controller object represents a hardware adapter or controller with homogenous devices that are the actual targets for I/O requests. A controller object can be used to synchronize a device driver's I/O to the target devices through its hardware adapter/controller.

A controller object is partially opaque. Driver writers must know about a certain field associated with the controller object because their drivers access this field through the controller object pointer returned by IoCreateController. The following field in a controller object is accessible to the creating driver.

Accessible Fields

PVOID ControllerExtension
Points to the controller extension. The structure and contents of the controller extension are driver-defined. The size is driver-determined, specified in the driver's call to IoCreateController. Usually, drivers maintain common state about I/O operations in the controller extension and device-specific state about I/O for a target device in the corresponding device extension.

Headers

ntddk.h

Comments

Most driver routines that process IRPs are given a pointer to the target device object. Consequently, device drivers that use controller objects frequently store the controller object pointer returned by IoCreateController in each device extension.

Note that a controller object has no name so it cannot be the target of an I/O request, and higher-level drivers cannot connnect or attach their device objects to a device driver's controller object.

Undocumented fields within a controller object should be considered inaccessible. Drivers with dependencies on object field locations or access to undocumented fields might not remain portable and interoperable with other drivers over time.

See Also

IoCreateController


DEVICE_DESCRIPTION

DEVICE_DESCRIPTION describes the attributes of the physical device for which a driver is requesting a DMA object.

typedef struct _DEVICE_DESCRIPTION {
  ULONG  Version;
  BOOLEAN  Master;
  BOOLEAN  ScatterGather;
  BOOLEAN  DemandMode;
  BOOLEAN  AutoInitialize;
  BOOLEAN  Dma32BitAddresses;
  BOOLEAN  IgnoreCount;
  BOOLEAN  Reserved1;
  BOOLEAN  Dma64BitAddresses;
  ULONG  BusNumber;
  ULONG  DmaChannel;
  INTERFACE_TYPE  InterfaceType;
  DMA_WIDTH  DmaWidth;
  DMA_SPEED  DmaSpeed;
  ULONG  MaximumLength;
  ULONG  DmaPort;
} DEVICE_DESCRIPTION, *PDEVICE_DESCRIPTION;

Members

Version
Specifies the version of this structure. The possible values are:
DEVICE_DESCRIPTION_VERSION
When DEVICE_DESCRIPTION is passed to IoGetDmaAdapter, the routine ignores the IgnoreCount member, and returns version 1 of the DMA_ADAPTER structure.
DEVICE_DESCRIPTION_VERSION1
When DEVICE_DESCRIPTION is passed to IoGetDmaAdapter, the IgnoreCount member is valid, and returns version 1 of the DMA_ADAPTER structure.
DEVICE_DESCRIPTION_VERSION2
When DEVICE_DESCRIPTION is passed to IoGetDmaAdapter, the IgnoreCount member is valid, and returns version 2 of the DMA_ADAPTER structure. Version 2 is available on Windows XP and later.
Master
Indicates whether the device runs as a busmaster adapter (TRUE) or a slave DMA device (FALSE).
ScatterGather
Indicates whether the device supports scatter/gather DMA.
DemandMode
Indicates whether to use the system DMA controller's demand mode. Not used for busmaster DMA.
AutoInitialize
Indicates whether to use the system DMA controller's autoinitialize mode. Not used for busmaster DMA.
Dma32BitAddresses
Specifies the use of 32-bit addresses for DMA operations.
IgnoreCount
Indicates whether to ignore the DMA controller's transfer counter. Set to TRUE if the DMA controller in this platform does not maintain an accurate transfer counter, and therefore requires a workaround. If the Version member is DEVICE_DESCRIPTION_VERSION, the value of IgnoreCount is ignored.
Reserved1
Reserved for system use. Must be FALSE.
Dma64BitAddresses
Specifies the use of 64-bit addresses for DMA operations.
BusNumber
Specifies the system-assigned value for the I/O bus. Not used by WDM drivers.
DmaChannel
Specifies the channel number to which a slave device is attached.
InterfaceType
Specifies the type of I/O bus involved in the DMA operation.
DmaWidth
Specifies the DMA data size for system DMA. Possible values are Width8Bits, Width16Bits, and Width32Bits. Not used for busmaster DMA.
DmaSpeed
Specifies one of the following speeds for system DMA: Compatible, TypeA, TypeB, TypeC, or TypeF. Not used for busmaster DMA.
MaximumLength
Specifies the maximum number of bytes the device can handle in each DMA operation.
DmaPort
Specifies the Microchannel-type bus port number. This parameter is obsolete, but is retained in the structure for compatibility with legacy drivers.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Drivers of devices that use DMA to transfer data use this structure to pass device information when requesting a DMA object. A driver should first zero-initialize the structure, then fill in the information for its device.

The InterfaceType specifies the bus interface. At present, its value can be one of the following: Internal, Isa, Eisa, or PCIBus. Additional types of buses will be supported in future versions of the operating system. The upper bound on the types of buses supported is always MaximumInterfaceType.

Setting Version to DEVICE_DESCRIPTION_VERSION1 or DEVICE_DESCRIPTION_VERSION2 and IgnoreCount to TRUE indicates that the current platform's DMA controller cannot be relied on to maintain an accurate transfer counter. In platforms with such a DMA controller, the system ignores the DMA counter but must take extra precautions to maintain data integrity during transfer operations. Using this workaround to compensate for a deficient DMA controller degrades the speed of DMA transfers.

A driver should specify TypeF as the DmaSpeed value only if the machine's ACPI BIOS supports it.

See Also

IoGetDmaAdapter


DEVICE_OBJECT

A device object represents a logical, virtual, or physical device for which a driver handles I/O requests. Every kernel-mode driver must create device objects by calling IoCreateDevice one or more times from its AddDevice routine.

Accessible Fields

PDRIVER_OBJECT DriverObject
Pointer to the driver object, representing the driver's loaded image, that was input to the DriverEntry and AddDevice routines.
PDEVICE_OBJECT NextDevice
Pointer to the next device object, if any, created by the same driver. The I/O Manager updates this list at each successful call to IoCreateDevice. A driver that is being unloaded must walk the list of its device objects and delete them. A driver that recreates its device objects dynamically also uses this field.
PIRP CurrentIrp
Pointer to the current IRP if the driver has a StartIo routine whose entry point was set in the driver object and if the driver is currently processing IRP(s). Otherwise, this field is NULL.
ULONG Flags
Device drivers OR this field in their newly created device objects with one or more of the following system-defined values:
DO_BUFFERED_IO or DO_DIRECT_IO | Higher-level drivers OR the field with the same value as the next-lower driver, except possibly for highest-level drivers.
DO_BUS_ENUMERATED_DEVICE | Bus drivers set this flag in the PDO of each device they enumerate. This flag pertains only to the PDO; it must not be set in an FDO or filter DO. Therefore, higher-level drivers layered over a bus driver must not propagate this value up the device stack.
DO_DEVICE_INITIALIZING The I/O Manager sets this flag when it creates the device object.

A device function or filter driver clears the flag in its AddDevice routine, after attaching the device object to the device stack, establishing the device power state, and ORing the field with one of the power flags (if necessary). The PnP Manager checks that the flag is clear after return from AddDevice.
DO_POWER_INRUSH | Drivers of devices that require inrush current when powering on must set this flag. A driver cannot set both this flag and DO_POWER_PAGABLE.
DO_POWER_PAGABLE Windows® 2000 and later drivers that are pageable, are not part of the paging path, and do not require inrush current must set this flag. The system calls such drivers at IRQL PASSIVE_LEVEL. Drivers cannot set both this flag and DO_POWER_INRUSH.

All WDM, Windows 98, and Windows Me drivers must set DO_POWER_PAGABLE.

DO_VERIFY_VOLUME | Removable-media drivers set this flag while processing transfer requests. Such drivers should also check for this flag in the target for a transfer request before transferring any data. See the Supporting Removable Media for details.

ULONG Characteristics
Set when a driver calls IoCreateDevice with one of the following values, as appropriate: FILE_REMOVABLE_MEDIA, FILE_READ_ONLY_DEVICE, FILE_FLOPPY_DISKETTE, FILE_WRITE_ONCE_MEDIA, FILE_DEVICE_SECURE_OPEN (Windows NT® 4.0 SP5 and later).
PVOID DeviceExtension
Points to the device extension. The structure and contents of the device extension are driver-defined. The size is driver-determined, specified in the driver's call to IoCreateDevice. Most driver routines that process IRPs are given a pointer to the device object so the device extension is usually every driver's primary global storage area and frequently a driver's only global storage area for objects, resources, and any state the driver maintains about the I/O requests it handles.
DEVICE_TYPE DeviceType
Set by IoCreateDevice, using the value specified for that routine's DeviceType parameter. For more information, see Specifying Device Types.
CCHAR StackSize
Specifies the minimum number of stack locations in IRPs to be sent to this driver. IoCreateDevice sets this field to one in newly created device objects; lowest-level drivers can therefore ignore this field. The I/O manager automatically sets the StackSize field in a higher-level driver's device object to the appropriate value if the driver calls IoAttachDevice or IoAttachDeviceToDeviceStack. Only a higher-level driver that chains itself over another driver with IoGetDeviceObjectPointer must explicitly set the value of StackSize in its own device object(s) to (1 + the StackSize value of the next-lower driver's device object).
ULONG AlignmentRequirement
Some higher-level drivers, such as a class driver layered over a corresponding port driver, that call IoGetDeviceObjectPointer reset this field in their device objects to the value of the next-lower driver's device object. Other higher-level drivers set this field at the discretion of the driver designer or leave it as set by the I/O Manager. Each device driver sets this field in its newly created device object(s) to the greater of (the alignment requirement of the device –1) or (the initialized value of this field), which can be one of the following system-defined values:

FILE_BYTE_ALIGNMENT
FILE_WORD_ALIGNMENT
FILE_LONG_ALIGNMENT
FILE_QUAD_ALIGNMENT
FILE_OCTA_ALIGNMENT
FILE_32_BYTE_ALIGNMENT
FILE_64_BYTE_ALIGNMENT
FILE_128_BYTE_ALIGNMENT
FILE_512_BYTE_ALIGNMENT

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

A device object is partially opaque. Driver writers must know about certain fields and system-defined symbolic constants associated with device objects because their drivers must access these fields through the device object pointer returned by IoCreateDevice and passed to most standard driver routines. The following fields in device objects are accessible to drivers.

The DeviceType range 0 to 32767 is reserved for use by Microsoft®.

Undocumented fields within a device object should be considered inaccessible. Drivers with dependencies on object field locations or access to undocumented fields might not remain portable and interoperable with other drivers over time.

The system-supplied video port driver sets up the fields of the device objects it creates on behalf of video miniport drivers.

The system-supplied SCSI port driver sets up the fields of the device objects it creates on behalf of SCSI miniport drivers.

The system-supplied NDIS library sets up the fields of the device objects it creates on behalf of NDIS NIC miniport drivers.

See Also

DRIVER_OBJECT, IoAttachDevice, IoAttachDeviceToDeviceStack, IoCreateDevice, IoDeleteDevice, IoGetDeviceObjectPointer


DMA_ADAPTER

DMA_ADAPTER describes a system-defined interface to a DMA controller for a given device. A driver calls IoGetDmaAdapter to obtain this structure.

typedef struct _DMA_ADAPTER {
  USHORT  Version;
  USHORT  Size;
  PDMA_OPERATIONS  DmaOperations;
  .
  .
} DMA_ADAPTER, *PDMA_ADAPTER;

Members

Version
Specifies the version of this structure.
Size
Specifies the size, in bytes, of this structure.
DmaOperations
Points to a DMA_OPERATIONS structure that contains pointers to DMA adapter functions. The Version parameter determines the version of the DMA_OPERATIONS structure returned.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Drivers for devices that use DMA to transfer data use this structure to obtain the addresses of functions that enable use of a DMA controller.

See Also

IoGetDmaAdapter, DMA_OPERATIONS


DMA_OPERATIONS

DMA_OPERATIONS provides a table of pointers to functions that control the operation of a DMA controller.

typedef struct _DMA_OPERATIONS {
  ULONG  Size;
  PPUT_DMA_ADAPTER  PutDmaAdapter;
  PALLOCATE_COMMON_BUFFER  AllocateCommonBuffer;
  PFREE_COMMON_BUFFER  FreeCommonBuffer;
  PALLOCATE_ADAPTER_CHANNEL  AllocateAdapterChannel;
  PFLUSH_ADAPTER_BUFFERS  FlushAdapterBuffers;
  PFREE_ADAPTER_CHANNEL  FreeAdapterChannel;
  PFREE_MAP_REGISTERS  FreeMapRegisters;
  PMAP_TRANSFER  MapTransfer;
  PGET_DMA_ALIGNMENT  GetDmaAlignment;
  PREAD_DMA_COUNTER  ReadDmaCounter;
  PGET_SCATTER_GATHER_LIST  GetScatterGatherList;
  PPUT_SCATTER_GATHER_LIST  PutScatterGatherList;

  // version 2 operations
  PCALCULATE_SCATTER_GATHER_LIST_SIZE  CalculateScatterGatherList;
  PBUILD_SCATTER_GATHER_LIST  BuildScatterGatherList;
  PBUILD_MDL_FROM_SCATTER_GATHER_LIST  BuildMdlFromScatterGatherList;
} DMA_OPERATIONS, *PDMA_OPERATIONS ;

Members

Size
Specifies the size, in bytes, of the DMA_OPERATIONS structure.
PutDmaAdapter
Points to a system-defined routine to free a DMA_ADAPTER structure. See PutDmaAdapter for further information.
AllocateCommonBuffer
Points to a system-defined routine to allocate a physically contiguous DMA buffer. See AllocateCommonBuffer for further information.
FreeCommonBuffer
Points to a system-defined routine to free a physically contiguous DMA buffer previously allocated by AllocateCommonBuffer. See FreeCommonBuffer for further information.
AllocateAdapterChannel
Points to a system-defined routine to allocate a channel for DMA operations. See AllocateAdapterChannel for further information.
FlushAdapterBuffers
Points to a system-defined routine to flush data from the system or busmaster adapter's internal cache after a DMA operation. See FlushAdapterBuffers for further information
FreeAdapterChannel
Points to a system-defined routine to free a channel previously allocated for DMA operations by AllocateAdapterChannel. See FreeAdapterChannel for further information.
FreeMapRegisters
Points to a system-defined routine to free map registers allocated for DMA operations. See FreeMapRegisters for further information.
MapTransfer
Points to a system-defined routine to begin a DMA operation. See MapTransfer for further information.
GetDmaAlignment
Points to a system-defined routine to obtain the DMA alignment requirements of the controller. See GetDmaAlignment for further information.
ReadDmaCounter
Points to a system-defined routine to obtain the current transfer count for a DMA operation. See ReadDmaCounter for further information.
GetScatterGatherList
Points to a system-defined routine that allocates map registers and creates a scatter/gather list for DMA. On Windows 98 and Windows ME, this value is NULL. See GetScatterGatherList for further information.
PutScatterGatherList
Points to a system-defined routine that frees map registers and a scatter/gather list after a DMA operation is complete. On Windows 98 and Windows ME, this value is NULL. See PutScatterGatherList for further information.
CalculateScatterGatherList
Pointer to a system-defined routine that determines the buffer size needed to hold a scatter/gather list for a given buffer. This member is only available in version 2 of DMA_OPERATIONS. See CalculateScatterGatherListSize for more information.
BuildScatterGatherList
Pointer to a system-defined routine that allocates map registers and creates a scatter/gather list for DMA in a driver-supplied buffer. This member is only available in version 2 of DMA_OPERATIONS. See BuildScatterGatherList for more information.
BuildMdlFromScatterGatherList
Pointer to a system-defined routine that builds an MDL corresponding to a scatter/gather list. This member is only available in version 2 of DMA_OPERATIONS. See BuildMdlFromScatterGatherList for more information.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

All members of this structure, with the exception of Size, are pointers to functions that drivers use to undertake DMA operations for their device. Drivers obtain these pointers by calling IoGetDmaAdapter. The version of DMA_OPERATIONS returned depends on the Version member of the DEVICE_DESCRIPTION structure passed to IoGetDmaAdapter. If Version is DEVICE_DESCRPTION_VERSION or DEVICE_DESCRIPTION_VERSION1, then version 1 of this structure is returned. If Version is DEVICE_DESCRIPTION_VERSION2, then version 2 of this structure is returned. Version 2 of DMA_OPERATIONS is available only on Windows XP and later.

See Also

AllocateAdapterChannel, AllocateCommonBuffer, FreeAdapterChannel, FreeCommonBuffer, FreeMapRegisters, FlushAdapterBuffers, GetDmaAlignment, GetScatterGatherList, IoGetDmaAdapter, MapTransfer, PutDmaAdapter, PutScatterGatherList, ReadDmaCounter


DRIVER_OBJECT

Each driver object represents the image of a loaded kernel-mode driver. A pointer to the driver object is an input parameter to a driver's DriverEntry, AddDevice, and optional Reinitialize routines and to its Unload routine, if any.

A driver object is partially opaque. Driver writers must know about certain fields of a driver object to initialize a driver and to unload it if the driver is unloadable. The following fields in the driver object are accessible to drivers.

Accessible Fields

PDEVICE_OBJECT DeviceObject
Pointer to the device object(s) created by the driver. This field is automatically updated when the driver calls IoCreateDevice successfully. A driver can use this field and the NextDevice field of DEVICE_OBJECT to step through a list of all the device objects that the driver created.
PUNICODE_STRING HardwareDatabase
Pointer to the \Registry\Machine\Hardware path to the hardware configuration information in the registry.
PFAST_IO_DISPATCH FastIoDispatch
Pointer to a structure defining the driver's fast I/O entry points. This field is used only by FSDs and network transport drivers.
PDRIVER_INITIALIZE DriverInit
Is the entry point for the DriverEntry routine, which is set up by the I/O Manager.
PDRIVER_STARTIO DriverStartIo
Is the entry point for the driver's StartIo routine, if any, which is set by the DriverEntry routine when the driver initializes. If a driver has no StartIo routine, this field is NULL.
PDRIVER_UNLOAD DriverUnload
Is the entry point for the driver's Unload routine, if any, which is set by the DriverEntry routine when the driver initializes. If a driver has no Unload routine, this field is NULL.
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION+1]
Is an array of one or more entry points for the driver's DispatchXxx routines. Each driver must set at least one DispatchXxx entry point in this array for the IRP_MJ_XXX requests that the driver handles. Any driver can set as many separate DispatchXxx entry points as the IRP_MJ_XXX codes that the driver handles. Each DispatchXxx routine is declared as follows:
NTSTATUS
(*PDRIVER_DISPATCH) (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    );

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Each kernel-mode driver's initialization routine should be named DriverEntry so the system will load the driver automatically. If this routine's name is something else, the driver writer must define the name of the initialization routine for the linker; otherwise, the OS loader or I/O Manager cannot find the driver's transfer address. The names of other standard driver routines can be chosen at the discretion of the driver writer.

A driver must set its DispatchXxx entry point(s) in the driver object that is passed in to the DriverEntry routine when the driver is loaded. A device driver must set one or more DispatchXxx entry points for the IRP_MJ_XXX that any driver of the same type of device is required to handle. A higher-level driver must set one or more DispatchXxx entry points for all the IRP_MJ_XXX that it must pass on to the underlying device driver. Otherwise, a driver is not sent IRPs for any IRP_MJ_XXX for which it does not set up a DispatchXxx routine in the driver object. For more information about the set of IRP_MJ_XXX that drivers for different types of underlying devices are required to handle, see IRP Function Codes and IOCTLS.

The DriverEntry routine also sets the driver's StartIo and/or Unload entry points, if any, in the driver object.

The HardwareDatabase string can be used by device drivers to get hardware configuration information from the registry when the driver is loaded. A driver is given read-only access to this string.

The RegistryPath input to the DriverEntry routine points to the \Registry\Machine\System\CurrentControlSet\Services\DriverName key, where the value entry of DriverName identifies the driver. As for the HardwareDatabase in the input driver object, a driver is given read-only access to this string.

Undocumented fields within a driver object should be considered inaccessible. Drivers with dependencies on object field locations or access to undocumented fields might not remain portable and interoperable with other drivers over time.

See Also

DriverEntry , IoCreateDevice, IoDeleteDevice, StartIo, Unload


FILE_ALIGNMENT_INFORMATION

The FILE_ALIGNMENT_INFORMATION structure is used as an argument to the ZwQueryInformationFile routine.

typedef struct _FILE_ALIGNMENT_INFORMATION {
  ULONG  AlignmentRequirement;
} FILE_ALIGNMENT_INFORMATION;

Members

AlignmentRequirement
The buffer alignment required by the underlying device. For a list of system-defined values, see DEVICE_OBJECT.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

See Also

DEVICE_OBJECT, ZwQueryInformationFile, ZwSetInformationFile


FILE_BASIC_INFORMATION

The FILE_BASIC_INFORMATION structure is used as an argument to routines that query or set file information.

typedef struct FILE_BASIC_INFORMATION {
  LARGE_INTEGER  CreationTime;
  LARGE_INTEGER  LastAccessTime;
  LARGE_INTEGER  LastWriteTime;
  LARGE_INTEGER  ChangeTime;
  ULONG  FileAttributes;
} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;

Members

CreationTime
The time that the file was created.
LastAccessTime
The last time that the file was accessed.
LastWriteTime
The last time that the file was written to.
ChangeTime
The last time the file was changed.
FileAttributes
The file attributes, which are specified using the FILE_ATTRIBUTE_xxxx bit flags defined in wdm.h and ntddk.h. For descriptions of these flags, see GetFileAttributes in the Platform SDK documentation.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

FILE_ATTRIBUTE_NORMAL can neither be set nor returned in combination with any other attributes. All other FileAttributes values override this attribute.

All dates and times are in system-time format. Absolute system time is the number of 100-nanosecond intervals since the start of 1601.

See Also

KeQuerySystemTime, ZwCreateFile, ZwQueryInformationFile, ZwSetInformationFile


FILE_DISPOSITION_INFORMATION

The FILE_DISPOSITION_INFORMATION structure is used as an argument to the ZwSetInformationFile routine.

typedef struct _FILE_DISPOSITION_INFORMATION {
  BOOLEAN  DeleteFile;
} FILE_DISPOSITION_INFORMATION;

Members

DeleteFile
If set to TRUE, delete the file when it is closed.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

The caller must have DELETE access to a given file in order to call ZwSetInformationFile with DeleteFile set to TRUE in this structure. Subsequently, the only legal operation by such a caller is to close the open file handle.

A file marked for deletion is not actually deleted until all open handles for the file object have been closed and the link count for the file is zero.

See Also

ZwClose, ZwSetInformationFile


FILE_END_OF_FILE_INFORMATION

The FILE_END_OF_FILE_INFORMATION structure is used as an argument to the ZwSetInformationFile routine.

typedef struct _FILE_END_OF_FILE_INFORMATION {
  LARGE_INTEGER  EndOfFile;
} FILE_END_OF_FILE_INFORMATION;

Members

EndOfFile
The absolute new end of file position as a byte offset from the start of the file.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

EndOfFile specifies the byte offset to the end of the file. Because this value is zero-based, it actually refers to the first free byte in the file: that is, it is the offset to the byte immediately following the last valid byte in the file.

See Also

ZwQueryInformationFile, ZwSetInformationFile


FILE_FS_DEVICE_INFORMATION

FILE_FS_DEVICE_INFORMATION provides file system device information about the type of device object associated with a file object.

typedef struct _FILE_FS_DEVICE_INFORMATION {
  DEVICE_TYPE  DeviceType;
  ULONG  Characteristics;
} FILE_FS_DEVICE_INFORMATION, *PFILE_FS_DEVICE_INFORMATION;

Members

DeviceType
Set when a driver calls IoCreateDevice as appropriate for the type of underlying device. For more information, see Specifying Device Types.
Characteristics
The device characteristics. For a description of relevant values, see DEVICE_OBJECT.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

See Also

DEVICE_OBJECT


FILE_FULL_EA_INFORMATION

FILE_FULL_EA_INFORMATION provides extended attribute (EA) information. This structure is used primarily by network drivers.

typedef struct _FILE_FULL_EA_INFORMATION {
  ULONG  NextEntryOffset;
  UCHAR  Flags;
  UCHAR  EaNameLength;
  USHORT  EaValueLength;
  CHAR  EaName[1];
} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION;

Members

NextEntryOffset
The offset of the next FILE_FULL_EA_INFORMATION-type entry. This member is zero if no other entries follow this one.
Flags
Can be zero or can be set with FILE_NEED_EA, indicating that the file to which the EA belongs cannot be interpreted without understanding the associated extended attributes.
EaNameLength
The length in bytes of the EaName array. This value does not include a zero-terminator to EaName.
EaValueLength
The length in bytes of each EA value in the array.
EaName
An array of characters naming the EA for this entry.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

This structure is longword-aligned. If a set of FILE_FULL_EA_INFORMATION entries is buffered, NextEntryOffset value in each entry, except the last, falls on a longword boundary.

The value(s) associated with each entry follows the EaName array. That is, an EA's values are located at EaName + (EaNameLength + 1).

See Also

ZwCreateFile


FILE_NAME_INFORMATION

FILE_NAME_INFORMATION provides file system device information about the name of a file object.

typedef struct _FILE_NAME_INFORMATION {
  ULONG  FileNameLength;
  WCHAR  FileName[1];
} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;

Members

FileNameLength
Specifies the length, in bytes, of the file name string.
FileName
Specifies the first character of the file name string. This is followed in memory by the remainder of the string. (See ZwQueryInformationFile for details on the syntax of this file name string.)

Headers

ntddk.h

See Also

ZwQueryInformationFile


FILE_OBJECT

To user-mode protected subsystems, a file object represents an open instance of a file, device, directory, or volume. To device and intermediate drivers, a file object usually represents a device object.

A file object is partially opaque. Certain types of drivers, such as FSDs and network transport drivers, use some of the fields of file objects. The following fields in file objects are accessible to drivers.

Accessible Fields

PDEVICE_OBJECT DeviceObject
Points to the device object on which the file is opened.
PVOID FsContext
Points to whatever optional state a driver maintains about the file object; otherwise, NULL.
PVOID FsContext2
Points to whatever additional state a driver maintains about the file object; otherwise, NULL.
UNICODE_STRING FileName
Is the name of the file opened on the device, or the Length of the string is zero if the device represented by DeviceObject is being opened.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Drivers can use the FsContext fields to maintain driver-determined state about an open file object. A driver cannot use these fields of a file object unless it is accessible in the driver's I/O stack location of an IRP.

The remaining fields in a file object are opaque. They are reserved for use by the I/O Manager and file systems.

Undocumented fields within a file object should be considered inaccessible. Drivers with dependencies on object field locations or access to undocumented fields might not remain portable and interoperable with other drivers over time.

A higher-level driver that successfully calls IoGetDeviceObjectPointer during initialization is given a pointer to the file object that represents the next-lower driver's device object in user mode. Such a higher-level driver should save the returned file object pointer. To release its reference to this file object, for example when the driver is being unloaded, the driver must call ObDereferenceObject with this file object pointer.

See Also

DEVICE_OBJECT, IoGetDeviceObjectPointer, ObDereferenceObject


FILE_POSITION_INFORMATION

The FILE_POSITION_INFORMATION structure is used as an argument to routines that query or set file information.

typedef struct FILE_POSITION_INFORMATION {
  LARGE_INTEGER  CurrentByteOffset;
} FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION;

Members

CurrentByteOffset
The byte offset of the current file pointer.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

FILE_READ_DATA or FILE_WRITE_DATA access to the file is required to change this information about the file, and the file must be opened for synchronous I/O.

If the file was opened or created with the FILE_NO_INTERMEDIATE_BUFFERING option, the value of CurrentByteOffset must be an integral multiple of the sector size of the underlying device.

See Also

ZwCreateFile, ZwSetInformationFile


FILE_STANDARD_INFORMATION

The FILE_STANDARD_INFORMATION structure is used as an argument to routines that query or set file information.

typedef struct FILE_STANDARD_INFORMATION {
  LARGE_INTEGER  AllocationSize;
  LARGE_INTEGER  EndOfFile;
  ULONG  NumberOfLinks;
  BOOLEAN  DeletePending;
  BOOLEAN  Directory;
} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION;

Members

AllocationSize
The file allocation size in bytes. Usually, this value is a multiple of the sector or cluster size of the underlying physical device.
EndOfFile
The end of file location as a byte offset.
NumberOfLinks
The number of hard links to the file.
DeletePending
The delete pending status. TRUE indicates that a file deletion has been requested.
Directory
The file directory status. TRUE indicates the file object represents a directory.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

EndOfFile specifies the byte offset to the end of the file. Because this value is zero-based, it actually refers to the first free byte in the file; that is, it is the offset to the byte immediately following the last valid byte in the file.

See Also

ZwCreateFile, ZwQueryInformationFile, ZwSetInformationFile


GENERIC_MAPPING

The GENERIC_MAPPING structure describes the ACCESS_MASK value of specific access rights associated with each type of generic access right.

typedef struct _GENERIC_MAPPING {
    ACCESS_MASK GenericRead;
    ACCESS_MASK GenericWrite;
    ACCESS_MASK GenericExecute;
    ACCESS_MASK GenericAll;
} GENERIC_MAPPING, *PGENERIC_MAPPING;

Members

GenericRead
Describes the specific access rights corresponding to the GENERIC_READ access right.
GenericWrite
Describes the specific access rights corresponding to the GENERIC_WRITE access right.
GenericExecute
Describes the specific access rights corresponding to the GENERIC_EXECUTE access right.
GenericAll
Describes the specific access rights corresponding to the GENERIC_ALL access right.

Comments

Use the IoGetFileObjectGenericMapping routine to get the specific access rights corresponding to generic access rights for a given file object. Use RtlMapGenericMask to subtract off the access rights within an ACCESS_MASK that do not derive from generic access rights.

See the reference page for GENERIC_MAPPING in the Platform SDK documentation for more information about generic access rights.

See Also

ACCESS_MASK, IoGetFileObjectGenericMapping, RtlMapGenericMask


IO_CSQ

This structure is only available on Windows XP and later.

IO_CSQ is an opaque structure used to specify the driver's cancel-safe IRP queue routines. Do not set the members of this structure directly. Use IoCsqInitialize to initialize this structure.

See Also

IoCsqInitialize, IoCsqInsertIrp, IoCsqRemoveIrp, IoCsqRemoveNextIrp


IO_CSQ_IRP_CONTEXT

This structure is only available on Windows XP and later.

IO_CSQ_IRP_CONTEXT is an opaque data structure used to specify the IRP context for an IRP in the driver's cancel-safe IRP queue. It is used as a key by the IoCsqInsertIrp and IoCsqRemoveIrp routines to identify particular IRPs in the queue.

See Also

IoCsqInsertIrp, IoCsqRemoveIrp


IO_RESOURCE_DESCRIPTOR

An IO_RESOURCE_DESCRIPTOR structure describes a range of raw hardware resources, of one type, that can be used by a device. An array of IO_RESOURCE_DESCRIPTOR structures is contained within each IO_RESOURCE_LIST structure.

typedef struct _IO_RESOURCE_DESCRIPTOR {
  UCHAR Option;
  UCHAR Type;
  UCHAR ShareDisposition;
  UCHAR Spare1;
  USHORT Flags;
  USHORT Spare2;
  union {
    struct {
      ULONG Length;
      ULONG Alignment;
      PHYSICAL_ADDRESS MinimumAddress;
      PHYSICAL_ADDRESS MaximumAddress;
    } Port;
    struct {
      ULONG Length;
      ULONG Alignment;
      PHYSICAL_ADDRESS MinimumAddress;
      PHYSICAL_ADDRESS MaximumAddress;
    } Memory;
    struct {
      ULONG MinimumVector;
      ULONG MaximumVector;
    } Interrupt;
    struct {
      ULONG MinimumChannel;
      ULONG MaximumChannel;
    } Dma;
    struct {
      ULONG Length;
      ULONG Alignment;
      PHYSICAL_ADDRESS MinimumAddress;
      PHYSICAL_ADDRESS MaximumAddress;
    } Generic;
    struct {
      ULONG Data[3];
    } DevicePrivate;
    struct {
      ULONG Length;
      ULONG MinBusNumber;
      ULONG MaxBusNumber;
      ULONG Reserved;
    } BusNumber;
    struct {
      ULONG Priority;
      ULONG Reserved1;
      ULONG Reserved2;
    } ConfigData;
  } u;
} IO_RESOURCE_DESCRIPTOR, *PIO_RESOURCE_DESCRIPTOR;

Members

Option
Specifies whether this resource description is required, preferred, or alternative. One of the following values must be used:
Value Definition
0
The specified resource range is required, unless alternative ranges are also specified.
IO_RESOURCE_PREFERRED
The specified resource range is preferred to any alternative ranges.
IO_RESOURCE_ALTERNATIVE
The specified resource range is an alternative to the range preceding it. For example, if one IO_RESOURCE_DESCRIPTOR structure specifies IRQ 5, with IO_RESOURCE_PREFERRED set, and the next structure specifies IRQ 3, with IO_RESOURCE_ALTERNATIVE set, the PnP Manager assigns IRQ 3 to the device only if IRQ 5 is unavailable. (Multiple alternatives can be specified for each resource. Both IO_RESOURCE_ALTERNATIVE and IO_RESOURCE_PREFERRED can be set, indicating a preferred alternative.)
IO_RESOURCE_DEFAULT
Not used.

Type
Identifies the resource type. For a list of valid values, see the Type member of the CM_PARTIAL_RESOURCE_DESCRIPTOR structure.
ShareDisposition
Indicates whether the described resource can be shared. For a list of valid values, see the ShareDisposition member of the CM_PARTIAL_RESOURCE_DESCRIPTOR structure.
Flags
Contains bit flags that are specific to the resource type. For a list of valid flags, see the Flags member of the CM_PARTIAL_RESOURCE_DESCRIPTOR structure.
u.Port
Specifies a range of I/O port addresses, using the following members:
Length
The length, in bytes, of the range of assignable I/O port addresses.
Alignment
The alignment, in bytes, that the assigned starting address must adhere to. The assigned starting address must be devisable by Alignment.
MinimumAddress
The minimum bus-relative I/O port address that can be assigned to the device
MaximumAddress
The maximum bus-relative I/O port address that can be assigned to the device
u.Memory
Specifies a range of memory addresses, using the following members:
Length
The length, in bytes, of the range of assignable memory addresses.
Alignment
The alignment, in bytes, that the assigned starting address must adhere to. The assigned starting address must be devisable by Alignment.
MinimumAddress
The minimum bus-relative memory address that can be assigned to the device
MaximumAddress
The maximum bus-relative memory address that can be assigned to the device
u.Interrupt
Specifies an interrupt vector range, using the following members:
MinimumVector
The minimum bus-relative vector that can be assigned to the device.
MaximumVector
The maximum bus-relative vector that can be assigned to the device.
u.Dma
Specifies a DMA setting, using one of the following members:
MinimumChannel
The minimum bus-relative DMA channel that can be assigned to the device.
MaximumChannel
The maximum bus-relative DMA channel that can be assigned to the device.
u.Generic
Not used.
u.DevicePrivate
Reserved for system use.
u.BusNumber
Specifies bus numbers, using the following members:
Length
The number of bus numbers required.
MinBusNumber
The minimum bus-relative bus number that can be assigned to the device.
MaxBusNumber
The maximum bus-relative bus number that can be assigned to the device.
Reserved
Not used.
u.ConfigData
Reserved for system use.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

See Also

CM_PARTIAL_RESOURCE_DESCRIPTOR,
IO_RESOURCE_LIST,
IO_RESOURCE_REQUIREMENTS_LIST,
IoConnectInterrupt


IO_RESOURCE_LIST

An IO_RESOURCE_LIST structure describes a range of raw hardware resources, of various types, that can be used by a device. The resources specified represent a single, acceptable resource configuration for a device. An array of IO_RESOURCE_LIST structures is contained within each IO_RESOURCE_REQUIREMENTS_LIST structure.

typedef struct _IO_RESOURCE_LIST {
  USHORT  Version;
  USHORT  Revision;
  ULONG  Count;
  IO_RESOURCE_DESCRIPTOR  Descriptors[1];
} IO_RESOURCE_LIST, *PIO_RESOURCE_LIST;

Members

Version
The version number of this structure. This value should be 1.
Revision
The revision of this structure. This value should be 1.
Count
The number of elements in the Descriptors array.
Descriptors
An array of IO_RESOURCE_DESCRIPTOR structures.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

See Also

IO_RESOURCE_DESCRIPTOR,
IO_RESOURCE_REQUIREMENTS_LIST


IO_RESOURCE_REQUIREMENTS_LIST

An IO_RESOURCE_REQUIREMENTS_LIST structure describes sets of resource configurations that can be used by a device. Each configuration represents a range of raw resources, of various types, that can be used by a device.

typedef struct _IO_RESOURCE_REQUIREMENTS_LIST {
  ULONG  ListSize;
  INTERFACE_TYPE  InterfaceType; // unused for WDM
  ULONG  BusNumber; // unused for WDM
  ULONG  SlotNumber;
  ULONG  Reserved[3];
  ULONG  AlternativeLists;
  IO_RESOURCE_LIST  List[1];
} IO_RESOURCE_REQUIREMENTS_LIST, *PIO_RESOURCE_REQUIREMENTS_LIST;

Members

ListSize
The total number of bytes that constitute the IO_RESOURCE_REQUIREMENTS_LIST structure, its IO_RESOURCE_LIST array, and the latter's IO_RESOURCE_DESCRIPTOR array.
InterfaceType
Specifies an interface type. This must be one of the types defined by INTERFACE_TYPE, in wdm.h or ntddk.h. (Not used by WDM drivers.)
BusNumber
A system-assigned, zero-based bus number. (Not used by WDM drivers.)
SlotNumber
A system slot number. (Not used by WDM drivers.)
Reserved
Not used.
AlternativeLists
The number of elements in the List array.
List
An array of IO_RESOURCE_LIST structures.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

See Also

IO_RESOURCE_DESCRIPTOR,
IO_RESOURCE_LIST,
IRP_MN_FILTER_RESOURCE_REQUIREMENTS,
IRP_MN_QUERY_RESOURCE_REQUIREMENTS


IO_STACK_LOCATION

Each I/O stack location in a given IRP has some common members and some request-type-specific members. The following summarizes the general structure of every stack location.

typedef struct _IO_STACK_LOCATION {
  UCHAR  MajorFunction;
  UCHAR  MinorFunction;
  UCHAR  Flags;
  UCHAR  Control;
  //
  // The following parameters depend on the IRP_MJ_XXX that is set
  // in MajorFunction. This declaration shows examples for IRP_MJ_READ,
  // IRP_MJ_WRITE, and IRP_MJ_DEVICE_CONTROL or, possibly,
  // IRP_MJ_INTERNAL_DEVICE_CONTROL requests, as well as for IRP_MJ_SCSI,
  // which is equivalent to IRP_MJ_INTERNAL_DEVICE_CONTROL.
  // For other IRP_MJ_XXX, see the structure definition.
  //
  union {
    .
    .
    struct {
      ULONG  Length;
      ULONG  Key;
      LARGE_INTEGER  ByteOffset;
    } Read;

    struct {
      ULONG  Length;
      ULONG  Key;
      LARGE_INTEGER  ByteOffset;
    } Write;
    .
    .
    struct {
      ULONG  OutputBufferLength;
      ULONG  InputBufferLength;
      ULONG  IoControlCode;         // IOCTL_XXX
      PVOID  Type3InputBuffer;
    } DeviceIoControl;
    .
    .
    struct {
      struct _SCSI_REQUEST_BLOCK  *Srb;
    } Scsi;
    .
    .
  } Parameters;
  PDEVICE_OBJECT  DeviceObject;
  PFILE_OBJECT  FileObject;
  .
  .
} IO_STACK_LOCATION, *PIO_STACK_LOCATION;

Members

MajorFunction
Is the IRP_MJ_XXX telling the driver what I/O operation is requested.
MinorFunction
Is a subfunction code for MajorFunction. The PnP Manager, the Power Manager, file system drivers, and SCSI class drivers set this member for some requests.
Flags
Is set with request-type-specific values and used almost exclusively by file system drivers. However, removable-media device drivers check whether this member is set with SL_OVERRIDE_VERIFY_VOLUME for read requests to determine whether to continue the read operation even if the device object's Flags is set with DO_VERIFY_VOLUME. Intermediate drivers layered over a removable-media device driver must copy this member into the I/O stack location of the next-lower driver in all incoming IRP_MJ_READ requests.
Control
Drivers can check this member to determine whether it is set with SL_PENDING_RETURNED. Drivers have read-only access to this member.
Parameters
A union that depends on the value of MajorFunction. For more detailed information about which IRP_MJ_XXX different types of drivers must handle, and for the Parameters.Xxx for each IRP_MJ_XXX, see IRP Function Codes and IOCTLs.
DeviceObject
Is a pointer to the driver-created device object representing the target physical, logical, or virtual device for which this driver is to handle the IRP.
FileObject
Is a pointer to the file object, if any, associated with DeviceObject.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Every higher-level driver is responsible for setting up the I/O stack location for the next-lower driver in each IRP.

In some cases, a higher-level driver layered over a mass-storage device driver is responsible for splitting up large transfer requests for the underlying device driver. In particular, SCSI class drivers must check the Parameters.Read.Length and Parameters.Write.Length, determine whether the size of the requested transfer exceeds the underlying HBA's transfer capabilities, and, if so, split the Length of the original request into a sequence of partial transfers to satisfy the original IRP.

A higher-level driver's call to IoCallDriver sets up the DeviceObject pointer to the next-lower-level driver's target device object in the I/O stack location of the lower driver. The I/O Manager passes each higher-level driver's IoCompletion routine a pointer to its own DeviceObject when or if the IoCompletion routine is called on completion of the IRP.

If a higher-level driver allocates IRPs to make requests of its own, its IoCompletion routine is passed a NULL DeviceObject pointer if that driver neither allocates a stack location for itself nor sets up the DeviceObject pointer in its own stack location of the newly allocated IRP.

See Also

IoCallDriver, IoGetCurrentIrpStackLocation, IoGetNextIrpStackLocation, IoSetCompletionRoutine, IoSetNextIrpStackLocation, IO_STATUS_BLOCK, IRP


IO_STATUS_BLOCK

The I/O status block in the IRP is set to indicate the final status of a given request before a driver calls IoCompleteRequest with the IRP.

typedef struct _IO_STATUS_BLOCK {
  NTSTATUS  Status;
  ULONG  Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;

Members

Status
This is the completion status, either STATUS_SUCCESS if the requested operation was completed successfully or an informational, warning, or error STATUS_XXX value.
Information
This is set to a request-dependent value. For example, on successful completion of a transfer request, this is set to the number of bytes transferred. If a transfer request is completed with another STATUS_XXX, this member is set to zero.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Unless a driver completes an IRP with an error from its Dispatch routine for that IRP_MJ_XXX, the lowest-level driver in the chain frequently sets the I/O status block in an IRP to the values that are returned to the original requester of the I/O operation.

The IoCompletion routine(s) of higher-level drivers usually check the I/O status block in IRPs completed by lower drivers. By design, the I/O status block in an IRP is the only information passed back from the underlying device driver to all higher-level drivers' IoCompletion routines.

See Also

IO_STACK_LOCATION, IoCompleteRequest, IoSetCompletionRoutine, IRP


IRP

In addition to the request-specific parameters in each driver's I/O stack location in an IRP, drivers also can use the following members of the IRP structure for various purposes.

typedef struct _IRP {
  .
  .
  PMDL  MdlAddress;
  ULONG  Flags;
  union {
    struct _IRP  *MasterIrp;
    .
    .
    PVOID  SystemBuffer;
  } AssociatedIrp;
  .
  .
  IO_STATUS_BLOCK  IoStatus;
  KPROCESSOR_MODE  RequestorMode;
  BOOLEAN PendingReturned;
  .
  .
  BOOLEAN  Cancel;
  KIRQL  CancelIrql;
  .
  .
  PDRIVER_CANCEL  CancelRoutine;
  PVOID UserBuffer;
  union {
    struct {
    .
    .
    union {
      KDEVICE_QUEUE_ENTRY DeviceQueueEntry;
      struct {
        PVOID  DriverContext[4];
      };
    };
    .
    .
    PETHREAD  Thread;
    .
    .
    LIST_ENTRY  ListEntry;
    .
    .
    } Overlay;
  .
  .
  } Tail;
} IRP, *PIRP;

Members

MdlAddress
Points to an MDL describing a user buffer for an IRP_MJ_READ or IRP_MJ_WRITE request if the driver set up its device object(s) for direct I/O. Drivers that handle IRP_MJ_INTERNAL_DEVICE_CONTROL requests also use this field if the I/O control code was defined with METHOD_DIRECT. For more information about IOCTLs, see IRP Function Codes and IOCTLs.
Flags
File system drivers use this field, which is read-only for all drivers. Network and, possibly, highest-level device drivers also might read this field, which can be set with one or more of the following system-defined masks:

IRP_NOCACHE
IRP_PAGING_IO
IRP_MOUNT_COMPLETION
IRP_SYNCHRONOUS_API
IRP_ASSOCIATED_IRP
IRP_BUFFERED_IO
IRP_DEALLOCATE_BUFFER
IRP_INPUT_OPERATION
IRP_SYNCHRONOUS_PAGING_IO
IRP_CREATE_OPERATION
IRP_READ_OPERATION
IRP_WRITE_OPERATION
IRP_CLOSE_OPERATION
IRP_DEFER_IO_COMPLETION

AssociatedIrp.MasterIrp
Points to the master IRP in an IRP that was created by a highest-level driver's call to IoMakeAssociatedIrp.
AssociatedIrp.SystemBuffer
Points to a system-space buffer for one of the following: (1) a transfer request to a driver that set up its device object(s) requesting buffered I/O; (2) an IRP_MJ_DEVICE_CONTROL request, (3) an IRP_MJ_INTERNAL_DEVICE_CONTROL request with an I/O control code that was defined with METHOD_BUFFERED. In any case, the underlying device driver usually transfers data to or from this buffer.
IoStatus
Is the I/O status block in which a driver stores status and information before calling IoCompleteRequest.
RequestorMode
Indicates the execution mode of the original requester of the operation, one of UserMode or KernelMode.
PendingReturned
If set to TRUE, a driver has marked the IRP pending. Each IoCompletion routine should check the value of this flag. If the flag is TRUE, and if the IoCompletion routine will not return STATUS_MORE_PROCESSING_REQUIRED, the routine should call IoMarkIrpPending to propagate the pending status to drivers above it in the device stack.
Cancel
If set to TRUE, the IRP either is or should be cancelled.
CancelIrql
Is the IRQL at which a driver is running when IoAcquireCancelSpinLock is called.
CancelRoutine
Is the entry point for a driver-supplied Cancel routine to be called if the IRP is cancelled. NULL indicates that the IRP is not currently cancelable.
UserBuffer
Contains the address of an output buffer if the major function code in the I/O stack location is IRP_MJ_INTERNAL_DEVICE_CONTROL and the I/O control code was defined with METHOD_NEITHER.
Tail.Overlay.DeviceQueueEntry
If IRPs are queued in the device queue associated with the driver's device object, this field links IRPs in the device queue. These links can be used only while the driver is processing the IRP.
Tail.Overlay.DriverContext
If IRPs are not queued in the device queue associated with the driver's device object, this field can be used by the driver to store up to four pointers. This field can be used only while the driver owns the IRP.
Tail.Overlay.Thread
Is a pointer to the caller's thread control block. Higher-level drivers that allocate IRPs for lower-level removable-media drivers must set this field in the IRPs they allocate. Otherwise, the FSD cannot determine which thread to notify if the underlying device driver indicates that the media requires verification.
Tail.Overlay.ListEntry
If a driver manages its own internal queue(s) of IRPs, it uses this field to link one IRP to the next. These links can be used only while the driver is holding the IRP in its queue or is processing the IRP.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Undocumented members of the IRP are reserved, used only by the I/O Manager or, in some cases, by FSDs.

Each IRP also has one or more I/O stack locations for the driver(s) that process the request. A driver must call IoGetCurrentIrpStackLocation to get a pointer to its own stack location in each IRP. Higher-level drivers must call IoGetNextIrpStackLocation to get a pointer to the next-lower driver's stack location so the higher-level driver can set it up before calling IoCallDriver with the IRP.

While a higher-level driver might check the value of the Cancel Boolean in an IRP, that driver cannot assume the IRP will be completed with STATUS_CANCELLED by a lower-level driver even if the value is TRUE.

See Also

IoCreateDevice, IoGetCurrentIrpStackLocation, IoGetNextIrpStackLocation, IoSetCancelRoutine, IoSetNextIrpStackLocation, IO_STACK_LOCATION, IO_STATUS_BLOCK


KEY_BASIC_INFORMATION

KEY_BASIC_INFORMATION defines a subset of the full information available for a registry key.

typedef struct _KEY_BASIC_INFORMATION {
  LARGE_INTEGER LastWriteTime;
  ULONG  TitleIndex;
  ULONG  NameLength;
  WCHAR  Name[1];  //  Variable-length string
} KEY_BASIC_INFORMATION, *PKEY_BASIC_INFORMATION;

Members

LastWriteTime
The last time the key or any of its values changed.
TitleIndex
Device and intermediate drivers should ignore this member.
NameLength
Specifies the size in bytes of the following name.
Name
A string of Unicode characters naming the key. The string is not null-terminated.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

See Also

ZwEnumerateKey, ZwQueryKey


KEY_FULL_INFORMATION

KEY_FULL_INFORMATION defines the information available for a registry key, including information about its subkeys and the maximum length for their names and value entries. This information can be used to size buffers to get the names of subkeys and their value entries.

typedef _KEY_FULL_INFORMATION {
  LARGE_INTEGER  LastWriteTime;
  ULONG  TitleIndex;
  ULONG  ClassOffset;
  ULONG  ClassLength;
  ULONG  SubKeys;
  ULONG  MaxNameLen;
  ULONG  MaxClassLen;
  ULONG  Values;
  ULONG  MaxValueNameLen;
  ULONG  MaxValueDataLen;
  WCHAR  Class[1];
} KEY_FULL_INFORMATION; PKEY_FULL_INFORMATION

Members

LastWriteTime
Specifies the last time the key or any of its values changed.
TitleIndex
Device and intermediate drivers should ignore this member.
ClassOffset
Specifies the offset from the start of this structure to the Class member.
ClassLength
Specifies the number of bytes in the Class name.
SubKeys
Specifies the number of subkeys for the key.
MaxNameLen
Specifies the maximum length in bytes of any name for a subkey.
MaxClassLen
Specifies the maximum length in bytes for a Class name.
Values
Specifies the number of value entries.
MaxValueNameLen
Specifies the maximum length in bytes of any value entry name.
MaxValueDataLen
Specifies the maximum length in bytes of any value entry data field.
Class[1]
A string of Unicode characters naming the class of the key.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

See Also

ZwEnumerateKey, ZwQueryKey


KEY_NODE_INFORMATION

KEY_NODE_INFORMATION defines basic information available for a registry (sub)key.

typedef struct _KEY_NODE_INFORMATION {
  LARGE_INTEGER LastWriteTime;
  ULONG  TitleIndex;
  ULONG  ClassOffset;
  ULONG  ClassLength;
  ULONG  NameLength;
  WCHAR  Name[1];  //  Variable-length string
} KEY_NODE_INFORMATION, *PKEY_NODE_INFORMATION;

Members

LastWriteTime
Specifies the last time the key or any of its values changed.
TitleIndex
Device and intermediate drivers should ignore this member.
ClassOffset
Specifies the offset from the start of this structure to the class name string, which is located immediately following the Name string.
ClassLength
Specifies the number of bytes in the class name string.
NameLength
Specifies the size in bytes of the following name.
Name
A string of Unicode characters naming the key.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

See Also

ZwEnumerateKey, ZwQueryKey


KEY_VALUE_BASIC_INFORMATION

KEY_VALUE_BASIC_INFORMATION defines a subset of the full information available for a value entry of a registry key.

typedef struct _KEY_VALUE_BASIC_INFORMATION {
  ULONG  TitleIndex;
  ULONG    Type;
  ULONG    NameLength;
  WCHAR  Name[1];  //  Variable size
} KEY_VALUE_BASIC_INFORMATION, *PKEY_VALUE_BASIC_INFORMATION;

Members

TitleIndex
Device and intermediate drivers should ignore this member.
Type
Specifies the system-defined type for the registry value in the Data member, which is one of the following:
REG_XXX Type | Value
REG_BINARY | Binary data in any form
REG_DWORD | A 4-byte numerical value
REG_DWORD_LITTLE_ENDIAN | A 4-byte numerical value whose least significant byte is at the lowest address
REG_DWORD_BIG_ENDIAN | A 4-byte numerical value whose least significant byte is at the highest address
REG_EXPAND_SZ | A zero-terminated Unicode string, containing unexpanded references to environment variables, such as "%PATH%"
REG_LINK | A Unicode string naming a symbolic link. This type is irrelevant to device and intermediate drivers
REG_MULTI_SZ | An array of zero-terminated strings, terminated by another zero
REG_NONE | Data with no particular type
REG_SZ | A zero-terminated Unicode string
REG_RESOURCE_LIST | A device driver's list of hardware resources, used by the driver or one of the physical devices it controls, in the \ResourceMap tree
REG_RESOURCE
_REQUIREMENTS_LIST 		A device driver's list of possible hardware resources it or one of the physical devices it controls can use, from which the system writes a subset into the \ResourceMap tree
REG_FULL_RESOURCE
_DESCRIPTOR 		A list of hardware resources that a physical device is using, detected and written into the \HardwareDescription tree by the system

NameLength
Specifies the size in bytes of the following value entry name.
Name
A string of Unicode characters naming a value entry of the key.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

See Also

ZwEnumerateValueKey, ZwQueryValueKey


KEY_VALUE_FULL_INFORMATION

KEY_VALUE_FULL_INFORMATION defines information available for a value entry of a registry key.

typedef struct _KEY_VALUE_FULL_INFORMATION {
  ULONG  TitleIndex;
  ULONG  Type;
  ULONG  DataOffset;
  ULONG  DataLength;
  ULONG  NameLength;
  WCHAR  Name[1];  //  Variable size
} KEY_VALUE_FULL_INFORMATION, *PKEY_VALUE_FULL_INFORMATION;

Members

TitleIndex
Device and intermediate drivers should ignore this member.
Type
Specifies the system-defined type for the registry value(s) following the Name member. For a summary of these types, see KEY_VALUE_BASIC_INFORMATION.
DataOffset
Specifies the offset from the start of this structure to the data immediately following the Name string.
DataLength
Specifies the number of bytes of registry information for the value entry identified by Name.
NameLength
Specifies the size in bytes of the following value entry name.
Name
A string of Unicode characters naming a value entry of the key.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

See Also

KEY_VALUE_BASIC_INFORMATION, ZwEnumerateValueKey, ZwQueryValueKey


KEY_VALUE_PARTIAL_INFORMATION

KEY_VALUE_PARTIAL_INFORMATION defines a subset of the value information available for a value entry of a registry key.

typedef struct _KEY_VALUE_PARTIAL_INFORMATION {
  ULONG  TitleIndex;
  ULONG  Type;
  ULONG  DataLength;
  UCHAR  Data[1];  //  Variable size
} KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION;

Members

TitleIndex
Device and intermediate drivers should ignore this member.
Type
Specifies the system-defined type for the registry value in the Data member. For a summary of these types, see KEY_VALUE_BASIC_INFORMATION.
DataLength
The size in bytes of the Data member.
Data
A value entry of the key.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

See Also

KEY_VALUE_BASIC_INFORMATION, ZwEnumerateValueKey, ZwQueryValueKey


KLOCK_QUEUE_HANDLE

KLOCK_QUEUE_HANDLE is an opaque structure that describes a queued spin lock. The driver allocates the KLOCK_QUEUE_HANDLE structure, and passes it to KeAcquireInStackQueuedSpinLock and KeAcquireInStackQueuedSpinLockAtDpcLevel to acquire the queued spin lock. Those routines initialize the structure to represent the queued spin lock. The driver passes the structure to KeReleaseInStackQueuedSpinLock and KeReleaseInStackQueuedSpinLockFromDpcLevel when releasing the spin lock.

See Also

KeAcquireInStackQueuedSpinLock, KeAcquireInStackQueuedSpinLockAtDpcLevel, KeReleaseInStackQueuedSpinLock, KeReleaseInStackQueuedSpinLock


LUID

LUID is an opaque structure that specifies an identifier that is guaranteed to be unique on the local machine. For more information, see the reference page for LUID in the Platform SDK documentation.

See Also

RtlConvertLongToLuid, RtlConvertUlongToLuid, RtlEqualLuid, RtlIsZeroLuid


OEM_STRING

The STRING structure defines a counted string used for OEM strings.

typedef struct _STRING {
  USHORT  Length;
  USHORT  MaximumLength;
  PCHAR  Buffer;
} STRING *POEM_STRING;

Members

Length
Specifies the length in bytes of the string stored in Buffer.
MaximumLength
Specifies the maximum length in bytes of Buffer.
Buffer
Points to a buffer used to contain a string of characters.

Headers

ntddk.h

Comments

The STRING structure is used to pass OEM strings.

If the string is NULL terminated, Length does not include the trailing NULL.

See Also

ANSI_STRING, UNICODE_STRING, RtlAnsiStringToUnicodeSize, RtlAnsiStringToUnicodeString, RtlFreeAnsiString, RtlInitAnsiString, RtlUnicodeStringToAnsiString


PCI_COMMON_CONFIG

PCI_COMMON_CONFIG defines standard PCI configuration information returned by HalGetBusData or HalGetBusDataByOffset for the input BusDataType PCIConfiguration, assuming the caller-allocated Buffer is of sufficient Length.

typedef struct _PCI_COMMON_CONFIG {
  USHORT  VendorID;
  USHORT  DeviceID;
  USHORT  Command;
  USHORT  Status;
  UCHAR  RevisionID;
  UCHAR  ProgIf;
  UCHAR  SubClass;
  UCHAR  BaseClass;
  UCHAR  CacheLineSize;
  UCHAR  LatencyTimer;
  UCHAR  HeaderType;
  UCHAR  BIST;

  union {
     struct _PCI_HEADER_TYPE_0 {
       ULONG  BaseAddresses[PCI_TYPE0_ADDRESSES];
       ULONG  Reserved1[2];
       ULONG  ROMBaseAddress;
       ULONG  Reserved2[2];
       UCHAR  InterruptLine;
       UCHAR  InterruptPin;
       UCHAR  MinimumGrant;
       UCHAR  MaximumLatency;
     } type0;
   } u;
   UCHAR  DeviceSpecific[192];
} PCI_COMMON_CONFIG, *PPCI_COMMON_CONFIG;

Members

VendorID
Identifies the manufacturer of the device. This must be a value allocated by the PCI SIG.
DeviceID
Identifies the particular device. This value is assigned by the manufacturer.
Command
Accesses the PCI device's control register. Writing a zero to this register renders the device logically disconnected from the PCI bus except for configuration access. Otherwise, the functionality of the register is device-dependent. Possible system-defined bit encodings for this member include:

PCI_ENABLE_IO_SPACE
PCI_ENABLE_MEMORY_SPACE
PCI_ENABLE_BUS_MASTER
PCI_ENABLE_SPECIAL_CYCLES
PCI_ENABLE_WRITE_AND_VALIDATE
PCI_ENABLE_VGA_COMPATIBLE_PALETTE
PCI_ENABLE_PARITY
PCI_ENABLE_WAIT_CYCLE
PCI_ENABLE_SERR
PCI_ENABLE_FAST_BACK_TO_BACK

Status
Accesses the PCI device's status register. The functionality of this register is device-dependent. Possible system-defined bit encodings for this member include:

PCI_STATUS_FAST_BACK_TO_BACK // read-only
PCI_STATUS_DATA_PARITY_DETECTED
PCI_STATUS_DEVSEL // 2 bits wide
PCI_STATUS_SIGNALED_TARGET_ABORT
PCI_STATUS_RECEIVED_TARGET_ABORT
PCI_STATUS_RECEIVED_MASTER_ABORT
PCI_STATUS_SIGNALED_SYSTEM_ERROR
PCI_STATUS_DETECTED_PARITY_ERROR

RevisionID
Specifies the revision level of the device described by the DeviceID member. This value is assigned by the manufacturer.
ProgIf
Identifies the register-level programming interface, if any, for the device, according to the PCI classification scheme.
SubClass
Identifies the subtype, if any, of the device, according to the PCI classification scheme.
BaseClass
Identifies type of the device, according to the PCI classification scheme.
CacheLineSize
Contains the system cache line size in 32-bit units. This member is relevant only for PCI busmaster devices. The system determines this value during the boot process.
LatencyTimer
Contains the value of the latency timer in units of PCI bus clocks. This member is relevant only for PCI busmaster devices. The system determines this value during the boot process.
HeaderType
The system ORs the value of this member with PCI_MULTIFUNCTION, if appropriate to the device. The value of this member indicates the PCI_HEADER_TYPE_0 layout that follows.
BIST
Zero indicates that the device does not support built-in self test. Otherwise, the device supports built-in self test according to the PCI standard.
u.type0
Drivers call HalAssignSlotResources to configure these values and to get back the bus-relative values passed to other configuration routines.
DeviceSpecific
Contains any device-specific initialization information that is available.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Certain members of this structure have read-only values, so attempts to reset them are ignored. These members include the following: VendorID, DeviceID, RevisionID, ProgIf, SubClass, BaseClass, HeaderType, InterruptPin, MinimumGrant, and MaximumLatency.

Other members are provisionally read-only: that is, the system initializes them to their correct values, so drivers can safely treat them as read-only. However, they can be reset if a busmaster driver finds it necessary. These members include the following: CacheLineSize and LatencyTimer.

See Also

HalAssignSlotResources, HalGetBusData, HalGetBusDataByOffset, HalSetBusData, HalSetBusDataByOffset


PCI_SLOT_NUMBER

PCI_SLOT_NUMBER defines the format of the Slot parameter to the Hal..BusData routines when they are called with the BusDataType value PCIConfiguration.

typedef struct _PCI_SLOT_NUMBER {
  union {
    struct {
      ULONG  DeviceNumber:5;
      ULONG  FunctionNumber:3;
      ULONG  Reserved:24;
    } bits;
    ULONG  AsULONG;
  } u;
} PCI_SLOT_NUMBER, *PPCI_SLOT_NUMBER;

Members

u.bits
Specifies the particular device on a multifunction adapter at the given slot that is being configured. The DeviceNumber indicates the logical slot number for the adapter; the FunctionNumber indicates the particular device on that adapter.
u.AsULONG
Species the logical slot number of the device being configured.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Drivers of PCI devices can call HalGetBusData or HalGetBusDataByOffset more than once for the same slot number to get the configuration information for their device(s).

For example, a driver might search for devices it supports on all PCI buses in the machine first, and then call HalGetBusData(ByOffset) again to request more configuration information about devices of interest. Such a driver could code a loop that calls HalGetBusData(ByOffset) with an input Buffer of sufficient Length only to contain enough of the PCI_COMMON_CONFIG to determine the VendorID and DeviceID of each PCI device. After finding the Slot numbers for any promising PCI devices, the driver would call HalGetBusData or HalGetBusDataByOffset one or more times with additional buffer space to get the information needed to configure its device(s).

See Also

HalAssignSlotResources, HalGetBusData, HalGetBusDataByOffset, HalSetBusData, HalSetBusDataByOffset, PCI_COMMON_CONFIG


POOL_TYPE

The POOL_TYPE enumeration type specifies the type of system memory to allocate.

typedef enum _POOL_TYPE {
  NonPagedPool,
  PagedPool,
  NonPagedPoolMustSucceed,
  DontUseThisType,
  NonPagedPoolCacheAligned,
  PagedPoolCacheAligned,
  NonPagedPoolCacheAlignedMustS
} POOL_TYPE;

Enumerators

PagedPool
Paged pool, which is pageable system memory. Paged pool can only be allocated and accessed at IRQL < DISPATCH_LEVEL.
PagedPoolCacheAligned
Paged pool, aligned on processor cache boundaries.
NonPagedPool
Nonpaged pool, which is nonpageable system memory. Nonpaged pool can be accessed from any IRQL, but it is a scarce resource and drivers should allocate it only when necessary.

The system can only allocate buffers larger than PAGE_SIZE from nonpaged pool in multiples of PAGE_SIZE. Requests for buffers larger than PAGE_SIZE, but not a PAGE_SIZE multiple, waste nonpageable memory.

NonPagedPoolMustSucceed
This value is for internal use only, and is only allowed during system startup. Otherwise, drivers must not specify this value, because a "must succeed" request crashes the system if the requested memory size is unavailable.
NonPagedPoolCacheAligned
Nonpaged pool, aligned on processor cache boundaries.
NonPagedPoolCacheAlignedMustS
This value is for internal use only, and is only allowed during system startup. It is the cache-aligned equivalent of NonPagedPoolMustSucceed.

Comments

When the system allocates a buffer from pool memory bigger than PAGE_SIZE, it aligns the buffer on a page boundary. Memory requests smaller than or equal to PAGE_SIZE are not necessarily aligned on page boundaries, but always fit within a single page, and are aligned on an 8-byte boundary.

See Also

ExAllocatePool, ExAllocatePoolWithTag, ExAllocatePoolWithQuota, ExAllocatePoolWithQuotaTag, ExAllocatePoolWithTagPriority


PRIVILEGE_SET

The PRIVILEGE_SET structure specifies a set of security privileges. For more information, see the reference page for PRIVILEGE_SET in the Platform SDK documentation.

See Also

SeAccessCheck


RTL_OSVERSIONINFOW

The RTL_OSVERSIONINFOW structure contains operating system version information. The information includes major and minor version numbers, a build number, a platform identifier, and descriptive text about the operating system. The RTL_OSVERSIONINFOW structure is used with RtlGetVersion.

typedef struct _OSVERSIONINFOW {
  ULONG dwOSVersionInfoSize;
  ULONG dwMajorVersion;
  ULONG dwMinorVersion;
  ULONG dwBuildNumber;
  ULONG dwPlatformId;
  WCHAR  szCSDVersion[ 128 ];     // Maintenance string for PSS usage
} RTL_OSVERSIONINFOW;

Members

dwOSVersionInfoSize
Specifies the size in bytes of an RTL_OSVERSIONINFOW structure. This member must be set before the structure is used with RtlGetVersion.
dwMajorVersion
Identifies the major version number of the operating system. For example, for Windows NT version 4.0 the major version number is four, and for Windows 2000 the major version number is five.
dwMinorVersion
Identifies the minor version number of the operating system. For example, for Windows 2000 the minor version number is zero.
dwBuildNumber
Identifies the build number of the operating system.
dwPlatformId
Identifies the operating system platform. For Microsoft® Win32® on NT-based operating systems, RtlGetVersion returns the value VER_PLATFORM_WIN32_NT.
szCSDVersion
Contains a null-terminated string, such as "Service Pack 3", which indicates the latest Service Pack installed on the system. If no Service Pack has been installed, the string is empty.

Headers

ntddk.h

See Also

RTL_OSVERSIONINFOEXW, RtlGetVersion, RtlVerifyVersionInfo


RTL_OSVERSIONINFOEXW

The RTL_OSVERSIONINFOEXW structure contains operating system version information. The information includes major and minor version numbers, a build number, a platform identifier, and information about product suites and the latest Service Pack installed on the system. This structure is used with RtlGetVersion and RtlVerifyVersionInfo.

typedef struct _OSVERSIONINFOEXW {
  ULONG  dwOSVersionInfoSize;
  ULONG  dwMajorVersion;
  ULONG  dwMinorVersion;
  ULONG  dwBuildNumber;
  ULONG  dwPlatformId;
  WCHAR  szCSDVersion[ 128 ];     // Maintenance string for PSS usage
  USHORT  wServicePackMajor;
  USHORT  wServicePackMinor;
  USHORT  wSuiteMask;
  UCHAR  wProductType;
  UCHAR  wReserved;
} RTL_OSVERSIONINFOEXW;

Members

dwOSVersionInfoSize
Specifies the size in bytes of an RTL_OSVERSIONINFOEXW structure. This member must be set before the structure is used with RtlGetVersion.
dwMajorVersion
Identifies the major version number of the operating system. For example, for Windows 2000, the major version number is five.
dwMinorVersion
Identifies the minor version number of the operating system. For example, for Windows 2000, the minor version number is zero.
dwBuildNumber
Identifies the build number of the operating system.
dwPlatformId
Identifies the operating system platform. For Win32 on NT-based operating systems, RtlGetVersion returns the value VER_PLATFORM_WIN32_NT.
szCSDVersion
Contains a null-terminated string, such as "Service Pack 3", which indicates the latest Service Pack installed on the system. If no Service Pack has been installed, the string is empty.
wServicePackMajor
Identifies the major version number of the latest Service Pack installed on the system. For example, for Service Pack 3, the major version number is three. If no Service Pack has been installed, the value is zero.
wServicePackMinor
Identifies the minor version number of the latest Service Pack installed on the system. For example, for Service Pack 3, the minor version number is zero.
wSuiteMask
Identifies the product suites available on the system. This member is a logical OR of zero or more of the following values:
Value | Meaning
VER_SUITE_BACKOFFICE | Microsoft BackOffice® components are installed.
VER_SUITE_DATACENTER | Windows 2000 or later Datacenter Server is installed.
VER_SUITE_ENTERPRISE | Windows 2000 or later Advanced Server is installed.
VER_SUITE_SMALLBUSINESS | Microsoft Small Business Server is installed.
VER_SUITE_SMALLBUSINESS_RESTRICTED | Microsoft Small Business Server is installed with the restrictive client license in force.
VER_SUITE_TERMINAL | Terminal Services are installed.

wProductType
Indicates additional information about the system. This member can be one of the following values:
Value | Meaning
VER_NT_WORKSTATION | Windows 2000 or later Professional
VER_NT_DOMAIN_CONTROLLER | Windows 2000 or later domain controller
VER_NT_SERVER | Windows 2000 or later Server

wReserved
Reserved for future use.

Headers

ntddk.h

See Also

RTL_OSVERSIONINFOW, RtlGetVersion, RtlVerifyVersionInfo


SCATTER_GATHER_LIST

The SCATTER_GATHER_LIST structure describes a scatter/gather list for DMA.

typedef struct _SCATTER_GATHER_LIST {
  ULONG  NumberOfElements;
  ULONG_PTR  Reserved;
  SCATTER_GATHER_ELEMENT  Elements[];
} SCATTER_GATHER_LIST, *PSCATTER_GATHER_LIST;

Members

NumberOfElements
Specifies the number of elements in the Elements array.
Reserved
Reserved for future use.
Elements[ ]
Specifies an array of scatter/gather elements that comprise a scatter/gather list. Each element is of type SCATTER_GATHER_ELEMENT, defined as follows:
typedef struct _SCATTER_GATHER_ELEMENT {
    PHYSICAL_ADDRESS Address;
    ULONG Length;
    ULONG_PTR Reserved;
} SCATTER_GATHER_ELEMENT, *PSCATTER_GATHER_ELEMENT;

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

For drivers that perform scatter/gather I/O, the GetScatterGatherList routine creates a SCATTER_GATHER_LIST structure and passes this structure to the driver's AdapterControl routine.

Each entry in the Elements array consists of the length of a physically contiguous scatter/gather region and its starting physical address.

See Also

GetScatterGatherList, PutScatterGatherList


SECURITY_DESCRIPTOR

The SECURITY_DESCRIPTOR structure specifies the security information associated with an object. For more information, see the reference page for SECURITY_DESCRIPTOR in the Platform SDK documentation.

See Also

ObGetObjectSecurity, ObReleaseObjectSecurity, RtlCreateSecurityDescriptor, RtlLengthSecurityDescriptor, RtlSetDaclSecurityDescriptor, RtlValidSecurityDescriptor, SeAccessCheck, SeAssignSecurity, SeDeassignSecurity


SECURITY_SUBJECT_CONTEXT

SECURITY_SUBJECT_CONTEXT is an opaque structure that represents the security context within which a particular operation is taking place.

See Also

SeAccessCheck, SeAssignSecurity, SeAssignSecurityEx


Plug and Play Structures

This chapter describes the structures that are parameters to more than one PnP routine or IRP. Structures that are used by only one routine are described in the documentation for that routine or IRP.

See Plug and Play for background and task-oriented information on supporting PnP in drivers.


BUS_INTERFACE_STANDARD

The BUS_INTERFACE_STANDARD interface structure allows device drivers to make direct calls to parent bus driver routines.

typedef struct _BUS_INTERFACE_STANDARD {
  // generic interface header
  USHORT Size;
  USHORT Version;
  PVOID Context;
  PINTERFACE_REFERENCE InterfaceReference;
  PINTERFACE_DEREFERENCE InterfaceDereference;
  // standard bus interface
  PTRANSLATE_BUS_ADDRESS TranslateBusAddress;
  PGET_DMA_ADAPTER GetDmaAdapter;
  PGET_SET_DEVICE_DATA SetBusData;
  PGET_SET_DEVICE_DATA GetBusData;
} BUS_INTERFACE_STANDARD, *PBUS_INTERFACE_STANDARD;

typedef BOOLEAN (*PTRANSLATE_BUS_ADDRESS)(
  IN PVOID  Context,
  IN PHYSICAL_ADDRESS  BusAddress,
  IN ULONG  Length,
  IN OUT PULONG  AddressSpace,
  OUT PPHYSICAL_ADDRESS TranslatedAddress
  );
typedef struct _DMA_ADAPTER *(*PGET_DMA_ADAPTER)(
  IN PVOID  Context,
  IN struct DEVICE_DESCRIPTION *DeviceDescriptor,
  OUT PULONG NumberOfMapRegisters
  );
typedef ULONG (*PGET_SET_DEVICE_DATA)(
  IN PVOID  Context,
  IN ULONG  DataType,
  IN PVOID Buffer,
  IN ULONG Offset,
  IN ULONG Length
  );

Members

Size
Size, in bytes, of this structure.
Version
Driver-defined interface version.
Context
Pointer to interface-specific context information.
InterfaceReference
Pointer to a routine that increments the interface's reference count.
InterfaceDereference
Pointer to a routine that decrements the interface's reference count.
TranslateBusAddress
Pointer to a routine that translates addresses on the parent bus to logical addresses.
GetDmaAdapter
Pointer to a routine that returns a DMA adapter structure (DMA_ADAPTER) for the target device.
SetBusData
Pointer to a routine that writes data to the device's configuration space.
GetBusData
Pointer to a routine that reads data from the device's configuration space.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

BUS_INTERFACE_STANDARD is an extension of the INTERFACE structure. For a description of the function prototypes of members InterfaceReference and InterfaceDereference, see the reference page for the INTERFACE structure.

Some operations on a device are reserved for the device's parent bus driver. Such operations might include accessing the device-specific configuration space of some buses, or programming a DMA controller.

To read and write to the device-specific configuration space, a device driver must rely on the agency of the bus driver in either of two ways:

  • By sending I/O request packets (IRP) IRP_MN_READ_CONFIG and IRP_MN_WRITE_CONFIG.
  • By obtaining an interface from the bus driver that allows the device driver to make direct calls to bus driver routines that access the device's configuration space. BUS_INTERFACE_STANDARD is such an interface, and its member routines GetBusData and SetBusData may be used to read from and write to a device's configuration space respectively.

For more information, see Accessing Device Configuration Space.

Likewise, some devices, such as bus-mastering storage devices, have on-board DMA controllers, but the device drivers for these devices can not program these DMA controllers directly, but instead must rely on routines provided by the parent bus driver. For a device driver to program the DMA controller for its device, it must first request an adapter object from the parent bus driver. The adapter object contains the routines supplied by the bus driver that can be used to program the device's DMA controller.

Drivers executing at IRQL = PASSIVE_LEVEL should obtain a device's DMA adapter object by calling IoGetDmaAdapter. IoGetDmaAdapter detects whether the bus driver supports the BUS_INTERFACE_STANDARD interface, and if it does, calls the routine pointed to by the GetDmaAdapter member of the interface to obtain the adapter object. Otherwise, it calls an equivalent legacy routine.

However, if a driver must obtain an adapter object while running at IRQL = DISPATCH_LEVEL or higher, it cannot do so with IoGetDmaAdapter. In such a case, the driver must query for the BUS_INTERFACE_STANDARD interface while still at IRQL = PASSIVE_LEVEL using IRP_MN_QUERY_INTERFACE. The driver can then call the interface routine GetDmaAdapter directly while running at IRQL = DISPATCH_LEVEL or higher.

See Also

IoGetDmaAdapter, DEVICE_DESCRIPTION, DMA_ADAPTER, IRP_MN_QUERY_INTERFACE, INTERFACE, IRP_MN_READ_CONFIG, IRP_MN_WRITE_CONFIG


DEVICE_CAPABILITIES

A DEVICE_CAPABILITIES structure describes PnP and power capabilities of a device. This structure is returned in response to an IRP_MN_QUERY_CAPABILITIES IRP.

typedef struct _DEVICE_CAPABILITIES {
  USHORT  Size;
  USHORT  Version;
  ULONG  DeviceD1:1;
  ULONG  DeviceD2:1;
  ULONG  LockSupported:1;
  ULONG  EjectSupported:1;
  ULONG  Removable:1;
  ULONG  DockDevice:1;
  ULONG  UniqueID:1;
  ULONG  SilentInstall:1;
  ULONG  RawDeviceOK:1;
  ULONG  SurpriseRemovalOK:1;
  ULONG  WakeFromD0:1;
  ULONG  WakeFromD1:1;
  ULONG  WakeFromD2:1;
  ULONG  WakeFromD3:1;
  ULONG  HardwareDisabled:1;
  ULONG  NonDynamic:1;
  ULONG  WarmEjectSupported:1;
  ULONG  NoDisplayInUI:1;
  ULONG  Reserved:14;
  ULONG  Address;
  ULONG  UINumber;
  DEVICE_POWER_STATE  DeviceState[PowerSystemMaximum];
  SYSTEM_POWER_STATE  SystemWake;
  DEVICE_POWER_STATE  DeviceWake;
  ULONG  D1Latency;
  ULONG  D2Latency;
  ULONG  D3Latency;
} DEVICE_CAPABILITIES, *PDEVICE_CAPABILITIES;

Members

Size
Specifies the size of the structure, in bytes. This field is set by the component that sends the IRP_MN_QUERY_CAPABILITIES request.
Version
Specifies the version of the structure, currently version 1. This field is set by the component that sends the IRP_MN_QUERY_CAPABILITIES request.
DeviceD1
Specifies whether the device hardware supports the D1 power state. Drivers should not change this value.
DeviceD2
Specifies whether the device hardware supports the D2 power state. Drivers should not change this value.
LockSupported
Specifies whether the device supports physical-device locking that prevents device ejection. This member pertains to ejecting the device from its slot, rather than ejecting a piece of removable media from the device.
EjectSupported
Specifies whether the device supports software-controlled device ejection while the system is in the PowerSystemWorking state. This member pertains to ejecting the device from its slot, rather than ejecting a piece of removable media from the device.
Removable
Specifies whether the device can be dynamically removed from the system. If TRUE, the device is displayed in the Unplug or Eject Hardware applet, unless SurpriseRemovalOK is also set to TRUE.
DockDevice
Specifies whether the device is a docking peripheral.
UniqueID
Specifies whether the device supports system-wide unique IDs (that is, the concatenation of its DeviceID and its InstanceID is unique system-wide). This bit is clear if the IDs that the device supports are unique only within the scope of the bus.
SilentInstall
Specifies whether the Device Manager should suppress all installation pop-ups; except required pop-ups such as "no compatible drivers found."
RawDeviceOK
Specifies whether the driver for the underlying bus can drive the device if there is no function driver (for example, SCSI devices in pass-through mode). This mode of operation is called raw mode.
SurpriseRemovalOK
Specifies whether the device can be safely removed without use of the Unplug or Eject Hardware applet. If both Removable and SurpriseRemovalOK are set, the device can be removed without using the applet.

(Note for Windows 2000 systems only: drivers for USB devices that support surprise removal must set this to TRUE only when the IRP is being passed back up the driver stack.)

WakeFromD0
Specifies whether the device can respond to an external wake signal while in the D0 state. Drivers should not change this value.
WakeFromD1
Specifies whether the device can respond to an external wake signal while in the D1 state. Drivers should not change this value.
WakeFromD2
Specifies whether the device can respond to an external wake signal while in the D2 state. Drivers should not change this value.
WakeFromD3
Specifies whether the device can respond to an external wake signal while in the D3 state. Drivers should not change this value.
HardwareDisabled
When set, this flag specifies that the device's hardware is disabled.

A device's parent bus driver or a bus filter driver sets this flag when such a driver determines that the device hardware is disabled.

The PnP Manager sends one IRP_MN_QUERY_CAPABILITIES IRP right after a device is enumerated and sends another after the device has been started. The PnP Manager only checks this bit right after the device is enumerated. Once the device is started, this bit is ignored.

NonDynamic
Reserved for future use.
WarmEjectSupported
Reserved for future use.
NoDisplayInUI
Don't display the device in the user interface. If this bit is set, the device is never displayed in the user interface, even if the device is present but fails to start. Only bus drivers and associated bus filter drivers should set this bit. (Also see the PNP_DEVICE_DONT_DISPLAY_IN_UI flag in the PNP_DEVICE_STATE structure.)
Reserved
Reserved for system use.
Address
Specifies an address indicating where the device is located on its underlying bus.

The interpretation of this number is bus-specific. If the address is unknown or the bus driver does not support an address, the bus driver leaves this member at its default value of 0xFFFFFFFF.

The following list describes the information certain bus drivers store in the Address field for their child devices:

1394
Does not supply an address because the addresses are volatile. Defaults to 0xFFFFFFFF.
EISA
Slot Number (0-F).
IDE
For an IDE device, the address contains the target ID and LUN. For an IDE channel, the address is zero or one (0 = primary channel and 1 = secondary channel).
ISApnp
Does not supply an address. Defaults to 0xFFFFFFFF.
PC Card (PCMCIA)
The socket number (typically 0x00 or 0x40).
PCI
The device number in the high word and the function number in the low word.
SCSI
The target ID.
USB
The port number.
UINumber
Specifies a number associated with the device that can be displayed in the user interface.

This number is typically a user-perceived slot number, such as a number printed next to the slot on the board, or some other number that makes locating the physical device easier for the user. For buses with no such convention, or when the UINumber is unknown, the bus driver leaves this member at its default value of 0xFFFFFFFF.

DeviceState
An array of values indicating the most-powered device power state that the device can maintain for each system power state. The DeviceState[PowerSystemWorking] element of the array corresponds to the S0 system state. The entry for PowerSystemUnspecified is reserved for system use.

The entries in this array are based on the capabilities of the parent devnode. As a general rule, a driver should not change these values. However, if necessary, a driver can lower the value, for example, from PowerDeviceD1 to PowerDeviceD2.

If the bus driver is unable to determine the appropriate device power state for a root-enumerated device, it sets DeviceState[PowerSystemWorking] to PowerDeviceD0 and all other entries to PowerDeviceD3.

SystemWake
Specifies the least-powered system power state from which the device can signal a wake event. A value of PowerSystemUndefined indicates that the device cannot wake the system.

A bus driver can get this information from its parent devnode.

In general, a driver should not change this value. If necessary, however, a driver can raise the power state, for example, from PowerSystemHibernate to PowerSystemS1, to indicate that its device cannot wake the system from a hibernation state but can from a higher-powered sleep state.

DeviceWake
Specifies the least-powered device power state from which the device can signal a wake event. A value of PowerDeviceUndefined indicates that the device cannot signal a wake event.
D1Latency
Specifies the device's approximate worst-case latency, in 100-microsecond units, for returning the device to the PowerDeviceD0 state from the PowerDeviceD1 state. Set to zero if the device does not support the D1 state.
D2Latency
Specifies the device's approximate worst-case latency, in 100-microsecond units, for returning the device to the PowerDeviceD0 state from the PowerDeviceD2 state. Set to zero if the device does not support the D2 state.
D3Latency
Specifies the device's approximate worst-case latency, in 100-microsecond units, for returning the device to the PowerDeviceD0 state from the PowerDeviceD3 state. Set to zero if the device does not support the D3 state.

Include

wdm.h or ntddk.h

Comments

Bus drivers set the appropriate values in this structure in response to an IRP_MN_QUERY_CAPABILITIES IRP. Bus filter drivers, function drivers, and filter drivers might alter the capabilities set by the bus driver.

Drivers that send an IRP_MN_QUERY_CAPABILITIES request must initialize the Size, Version, Address, and UINumber members of this structure before sending the IRP.

See Also

IRP_MN_QUERY_CAPABILITIES


DEVICE_INTERFACE_CHANGE_NOTIFICATION

A device-interface-change notification structure describes a device interface that has been enabled (arrived) or disabled (removed). The PnP Manager sends this structure to a driver that registered a callback routine for notification of EventCategoryDeviceInterfaceChange events.

typedef struct _DEVICE_INTERFACE_CHANGE_NOTIFICATION {
  USHORT  Version;
  USHORT  Size;
  GUID  Event;
  //
  // Event-specific data
  //
  GUID  InterfaceClassGuid;
  PUNICODE_STRING  SymbolicLinkName;
} DEVICE_INTERFACE_CHANGE_NOTIFICATION, *PDEVICE_INTERFACE_CHANGE_NOTIFICATION;

Members

Version
Specifies the version of the data structure, currently 1.
Size
Specifies the size of the structure, in bytes, including the size of the standard first three members plus the event-specific data.
Event
Specifies a GUID identifying the event: GUID_DEVICE_INTERFACE_ARRIVAL or GUID_DEVICE_INTERFACE_REMOVAL. The GUIDs are defined in wdmguid.h.
InterfaceClassGuid
Specifies the class of the device interface that has just been enabled or disabled.
SymbolicLinkName
Points to a Unicode string that contains the name of the symbolic link for the device interface.

Include

wdm.h or ntddk.h

Comments

This structure is allocated from paged memory.

See Also

HWPROFILE_CHANGE_NOTIFICATION, IoRegisterPlugPlayNotification, PLUGPLAY_NOTIFICATION_HEADER, TARGET_DEVICE_REMOVAL_NOTIFICATION


HWPROFILE_CHANGE_NOTIFICATION

A hardware-profile-change notification structure describes an event related to a hardware profile configuration change. The PnP Manager sends this structure to a driver that registered a callback routine for notification of EventCategoryHardwareProfileChange events.

typedef struct _HWPROFILE_CHANGE_NOTIFICATION {
  USHORT  Version;
  USHORT  Size;
  GUID  Event;
  //
  // (No event-specific data)
  //
} HWPROFILE_CHANGE_NOTIFICATION, *PHWPROFILE_CHANGE_NOTIFICATION;

Members

Version
Specifies the version of the data structure, currently 1.
Size
Specifies the size of the structure, in bytes including the size of the standard first three members plus the event-specific data.
Event
Specifies a GUID identifying the event: GUID_HWPROFILE_QUERY_CHANGE, GUID_HWPROFILE_CHANGE_COMPLETE, or GUID_HWPROFILE_CHANGE_CANCELLED. The GUIDs are defined in wdmguid.h.

Include

wdm.h or ntddk.h

Comments

There is no event-specific data for a hardware-profile-change event.

See Also

DEVICE_INTERFACE_CHANGE_NOTIFICATION, IoRegisterPlugPlayNotification, PLUGPLAY_NOTIFICATION_HEADER, TARGET_DEVICE_REMOVAL_NOTIFICATION


INTERFACE

The INTERFACE structure describes an interface that is exported by a driver for use by other drivers.

typedef STRUCT _INTERFACE {
    USHORT Size;
    USHORT Version;
    PVOID Context;
    PINTERFACE_REFERENCE InterfaceReference;
    PINTERFACE_DEREFERENCE InterfaceDereference;
    // interface-specific entries go here
} INTERFACE, *PINTERFACE;
typedef VOID (*PINTERFACE_REFERENCE)(PVOID Context);
typedef VOID (*PINTERFACE_DEREFERENCE)(PVOID Context);

Members

Size
Size, in bytes, of a structure defining a driver interface, including this structure and interface-specific members.
Version
Driver-defined interface version.
Context
Pointer to interface-specific context information.
InterfaceReference
Points to a driver-supplied routine that increments the interface's reference count.
InterfaceDereference
Points to a driver-supplied routine that decrements the interface's reference count.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

The INTERFACE structure must be included as the first member of all structures that describe interfaces returned by drivers in response to an IRP_MN_QUERY_INTERFACE request.

The InterfaceReference routine must be called by the driver that exports the interface, each time the driver supplies that interface in response to IRP_MN_QUERY_INTERFACE. Likewise, if the driver that requests the interface subsequently passes it to another driver, the driver that passes the interface must call InterfaceReference on behalf of the driver that receives it.

Each driver that imports the interface (whether by sending IRP_MN_QUERY_INTERFACE or by receiving the interface from another driver) must call the InterfaceDereference routine after it has finished using the interface. After calling the InterfaceDereference routine, a driver cannot use the interface again without first re-obtaining it.


LPGUID

An LPGUID is a long pointer to a GUID.

typedef struct _GUID {
  ULONG  Data1;
  USHORT  Data2;
  USHORT  Data3;
  UCHAR  Data4[8];
} GUID

typedef GUID *LPGUID;

Include

wdm.h or ntddk.h

Comments

A GUID is a 128-bit unique identifier.


PLUGPLAY_NOTIFICATION_HEADER

A PnP notification header is included at the beginning of each PnP notification structure, such as a DEVICE_INTERFACE_CHANGE_NOTIFICATION structure.

typedef struct _PLUGPLAY_NOTIFICATION_HEADER {
  USHORT  Version;
  USHORT  Size;
  GUID Event;
} PLUGPLAY_NOTIFICATION_HEADER, *PPLUGPLAY_NOTIFICATION_HEADER;

Members

Version
Specifies the version of the data structure, currently set to 1.
Size
Specifies the size of the structure, in bytes.
Event
Specifies a GUID identifying the event.

Include

wdm.h or ntddk.h

Comments

Drivers can cast a PnP notification structure to this type to access the Event field and identify the exact type of the structure.

See Also

DEVICE_INTERFACE_CHANGE_NOTIFICATION, HWPROFILE_CHANGE_NOTIFICATION, IoRegisterPlugPlayNotification, TARGET_DEVICE_CUSTOM_NOTIFICATION, TARGET_DEVICE_REMOVAL_NOTIFICATION


PNP_DEVICE_STATE

typedef ULONG PNP_DEVICE_STATE, *PPNP_DEVICE_STATE;

PNP_DEVICE_STATE is a bitmask of flags describing the PnP state of a device. Drivers return this structure in response to an IRP_MN_QUERY_PNP_DEVICE_STATE IRP.

Flags

PNP_DEVICE_DISABLED
The device is physically present but is disabled in hardware.
PNP_DEVICE_DONT_DISPLAY_IN_UI
Don't display the device in the user interface. Set for a device that is physically present but not usable in the current configuration, such as a game port on a laptop that is not usable when the laptop is undocked. (Also see the NodisplayInUI flag in the DEVICE_CAPABILITIES structure.)
PNP_DEVICE_FAILED
The device is present but not functioning properly.

When both this flag and PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED are set, the device must be stopped before the PnP Manager assigns new hardware resources (non-stop rebalance is not supported for the device).

PNP_DEVICE_NOT_DISABLEABLE
The device must not be disabled.

A driver sets this bit for a device that is required for proper system operation. For example, if a driver receives notification that a device is in the paging path (IRP_MN_DEVICE_USAGE_NOTIFICATION for DeviceUsageTypePaging), the driver calls IoInvalidateDeviceState and sets this flag in the resulting IRP_MN_QUERY_PNP_DEVICE_STATE IRP.

If this bit is set for a device, the PnP Manager propagates this setting to the device's parent device, its parent's parent device, and so forth.

If this bit is set for a non-enumerable device, the device cannot be disabled or uninstalled.

PNP_DEVICE_REMOVED
The device has been physically removed.
PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
The resource requirements for the device have changed.

Typically, a bus driver sets this flag when it has determined that it must expand its resource requirements in order to enumerate a new child device.

Include

wdm.h or ntddk.h

Comments

The PnP Manager queries a device's PNP_DEVICE_STATE right after starting the device by sending an IRP_MN_QUERY_PNP_DEVICE_STATE request to the device stack. In response to this IRP, the drivers for the device set the appropriate flags in PNP_DEVICE_STATE.

If any of the state characteristics change after the initial query, a driver notifies the PnP Manager by calling IoInvalidateDeviceState. In response to a call to IoInvalidateDeviceState, the PnP Manager queries the device's PNP_DEVICE_STATE again.

If a device is marked PNP_DEVICE_NOT_DISABLEABLE, the debugger displays a DNUF_NOT_DISABLEABLE user flag for the devnode. The debugger also displays a DisableableDepends value that counts the number of reasons why the device cannot be disabled. This value is the sum of X+Y, where X is one if the device cannot be disabled and Y is the count of the device's child devices that cannot be disabled.

See Also

IoInvalidateDeviceState, IRP_MN_QUERY_PNP_DEVICE_STATE


TARGET_DEVICE_CUSTOM_NOTIFICATION

A TARGET_DEVICE_CUSTOM_NOTIFICATION structure describes a custom device event.

typedef struct _TARGET_DEVICE_CUSTOM_NOTIFICATION {
  USHORT  Version;
  USHORT  Size;
  GUID  Event;
  //
  // Event-specific data
  //
  PFILE_OBJECT  FileObject;
  LONG  NameBufferOffset;
  UCHAR  CustomDataBuffer[1];
} TARGET_DEVICE_CUSTOM_NOTIFICATION, *PTARGET_DEVICE_CUSTOM_NOTIFICATION;

Members

Version
Specifies the version of the data structure, currently 1.
Size
Specifies the size of the structure, in bytes, including the first three standard members plus the event-specific data.
Event
Specifies a GUID identifying the event. GUIDs for custom event notification are defined by the components that use this mechanism.
FileObject
Points to a file object for the device.
NameBufferOffset
Specifies the offset, in bytes, from beginning of CustomDataBuffer where text begins. A value of -1 indicates that there is no text.
CustomDataBuffer
A variable-length buffer, optionally containing binary data at the start of the buffer, followed by an optional text buffer (word-aligned).

Include

wdm.h or ntddk.h

Comments

Kernel-mode components use this structure for custom event notification: to signal a custom event (IoReportTargetDeviceChange[Asynchronous]) and when handling a custom event (in a notification callback routine).

This structure accommodates both a variable-length binary data buffer and a variable-length Unicode text buffer. The NameBufferOffset must indicate where the text buffer begins, so the data can be delivered in the appropriate format (ANSI or Unicode) to user-mode applications that registered for handle-based notification with RegisterDeviceNotification. See the Platform SDK documentation for information on RegisterDeviceNotification.

See Also

IoRegisterPlugPlayNotification, IoReportTargetDeviceChange, IoReportTargetDeviceChangeAsynchronous


TARGET_DEVICE_REMOVAL_NOTIFICATION

A TARGET_DEVICE_REMOVAL_NOTIFICATION structure describes a device-removal event. The PnP Manager sends this structure to a driver that registered a callback routine for notification of EventCategoryTargetDeviceChange events.

typedef struct _TARGET_DEVICE_REMOVAL_NOTIFICATION {
  USHORT  Version;
  USHORT  Size;
  GUID  Event;
  //
  // Event-specific data
  //
  PFILE_OBJECT FileObject;
} TARGET_DEVICE_REMOVAL_NOTIFICATION, *PTARGET_DEVICE_REMOVAL_NOTIFICATION;

Members

Version
Specifies the version of the data structure, currently set to 1.
Size
Specifies the size of the structure, in bytes, including the size of the standard first three members plus the event-specific data.
Event
Specifies a GUID identifying the event: GUID_TARGET_DEVICE_QUERY_REMOVE, GUID_TARGET_DEVICE_REMOVE_COMPLETE, or GUID_TARGET_DEVICE_REMOVE_CANCELLED. These GUIDs are defined in wdmguid.h.
FileObject
Points to a file object for the device.

Include

wdm.h or ntddk.h

See Also

DEVICE_INTERFACE_CHANGE_NOTIFICATION, HWPROFILE_CHANGE_NOTIFICATION, IoRegisterPlugPlayNotification, TARGET_DEVICE_CUSTOM_NOTIFICATION


WMI Structures

This describes, in alphabetic order, the structures that are used to pass WMI information between WMI and kernel-mode drivers.


EVENT_TRACE_HEADER

An EVENT_TRACE_HEADER structure is used to pass a WMI event to the WMI event logger. It is overlaid on the WNODE_HEADER portion of the WNODE_EVENT_ITEM passed to IoWMIWriteEvent. Information contained in the EVENT_TRACE_HEADER is written to the WMI log file.

typedef struct _EVENT_TRACE_HEADER {
  USHORT           Size;
  UCHAR            HeaderType;
  UCHAR            MarkerFlags;
  union {
    ULONG         Version;
    struct {
      UCHAR     Type;
      UCHAR     Level;
      USHORT    Version;
    } Class;
  };
  ULONGLONG        ThreadId;
  LARGE_INTEGER    TimeStamp;
  union {
    GUID          Guid;
    ULONGULONG    GuidPtr;
  };
  union {
    struct {
      ULONG     ClientContext;
      ULONG     Flags;
    };
    struct {
      ULONG     KernelTime;
      ULONG     UserTime;
    };
  ULONG64          ProcessorTime;
} EVENT_TRACE_HEADER; *PEVENT_TRACE_HEADER;

Members

Size
Specifies the size in bytes of this structure. This value should be set to - sizeof(EVENT_TRACE_HEADER) plus the size of any driver data appended to the end of this structure. (Note: The sizeof this member is smaller than the sizeof the Size member of the WNODE_HEADER structure on which this structure is overlaid.)
HeaderType
Reserved for internal use.
MarkerFlags
Reserved for internal use.
Version
Drivers can use this member to store version information. This information is not interpreted by the event logger.
Class
Type
Trace event type. This can be one of the predefined EVENT_TRACE_TYPE_Xxx values contained in evntrace.h or can be a driver defined value. Callers are free to define private event types with values greater than the reserved values in evntrace.h.
Level
Trace instrumentation level. A driver defined value meant to represent the degree of detail of the trace instrumentation. Drivers are free to give this value meaning. This value should be 0 by default. More information on how consumers can request different levels of trace information will be provided in a future version of the documentation.
Version
Version of trace record. Version information that can be used by the driver to track different event formats.
ThreadId
Reserved for internal use.
TimeStamp
Indicates the time the driver event occurred. This time is indicated in units of 100 nanoseconds since 1/1/1601. If the WNODE_FLAG_USE_TIMESTAMP is set in Flags, the system logger will leave the value of TimeStamp unchanged. Otherwise, the system logger will set the value of TimeStamp at the time it receives the event. A driver can call KeQuerySystemTime to set the value of TimeStamp.
Guid
Indicates the GUID that identifies the data block for the event.
GuidPtr
If the WNODE_FLAG_USE_GUID_PTR is set in Flags, GuidPtr points to the GUID that identifies the data block for the event.
ClientContext
Reserved for internal use.
Flags
Provides information about the contents of this structure. For information on EVENT_TRACE_HEADER Flags values, see the Flags description in WNODE_HEADER.
KernelTime
Reserved for internal use.
UserTime
Reserved.
ProcessorTime
Reserved for internal use.

Comments

A driver which supports trace events will use this structure to report events to the WMI event logger. Trace events should not be reported until the driver receives a request to enable events and the control GUID is one the driver supports. The driver should initialize an EVENT_TRACE_HEADER structure, fill in any user defined event data at the end and pass a pointer to the EVENT_TRACE_HEADER to IoWmiWriteEvent. The driver should continue reporting trace events until it receives a request to disable the control GUID for the trace events.

See Also

WNODE_HEADER, WNODE_EVENT_ITEM, IoWMIWriteEvent


TRACE_INFORMATION_CLASS

The TRACE_INFORMATION_CLASS enumeration type is used to indicate types of event trace information.

typedef enum _TRACE_INFORMATION_CLASS {
  TraceIdClass,
  TraceHandleClass,
  TraceEnableFlagsClass,
  TraceEnableLevelClass,
  GlobalLoggerHandleClass,
  EventLoggerHandleClass,
  AllLoggerHandlesClass,
  TraceHandleByNameClass
} TRACE_INFORMATION_CLASS;

Enumerators

TraceIdClass
Indicates the logger ID of an event tracing session.
TraceHandleClass
Indicates a trace handle for an event tracing session.
TraceEnableFlagsClass
Indicates the enable flags set on an event trace handle.
TraceEnableLevelClass
Indicates the enable level set on an event trace handle.
GlobalLoggerHandleClass
Indicates an event trace handle for the global logger.
EventLoggerHandleClass
For internal use only.
AllLoggerHandlesClass
Indicates an array of event trace handles for all valid loggers.
TraceHandleByNameClass
Indicates an event trace handle identified by a friendly name.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

TRACE_INFORMATION_CLASS is provided primarily for use with the WmiQueryTraceInformation routine, which returns information about an event tracing session.

For more information about event tracing sessions, see WMI Support for Tracing Driver Operation.

See Also

WmiFireEvent, WmiQueryTraceInformation, WmiTraceMessage, WmiTraceMessageVa


WMILIB_CONTEXT

A WMILIB_CONTEXT structure provides registration information for a driver's data blocks and event blocks and defines entry points for the driver's WMI library callback routines.

typedef struct _WMILIB_CONTEXT {
  ULONG  GuidCount;
  PWMIGUIDREGINFO  GuidList;
  PWMI_QUERY_REGINFO  QueryWmiRegInfo;
  PWMI_QUERY_DATABLOCK  QueryWmiDataBlock;
  PWMI_SET_DATABLOCK  SetWmiDataBlock;
  PWMI_SET_DATAITEM  SetWmiDataItem;
  PWMI_EXECUTE_METHOD  ExecuteWmiMethod;
  PWMI_FUNCTION_CONTROL  WmiFunctionControl;
} WMILIB_CONTEXT, *PWMILIB_CONTEXT;

Members

GuidCount
Specifies the number of blocks registered by the driver.
GuidList
Points to an array of GuidCount WMIGUIDREGINFO structures that contain registration information for each block.
QueryWmiRegInfo
Points to the driver's DpWmiQueryReginfo routine, which is a required entry point for drivers that call WMI library support routines.
QueryWmiDataBlock
Points to the driver's DpWmiQueryDataBlock routine, which is a required entry point for drivers that call WMI library support routines.
SetWmiDataBlock
Points to the driver's DpWmiSetDataBlock routine, which is an optional entry point for drivers that call WMI library support routines. If the driver does not implement this routine, it must set this member to NULL. In this case, WMI returns STATUS_WMI_READ_ONLY to the caller in response to any IRP_MN_CHANGE_SINGLE_INSTANCE request.
SetWmiDataItem
Points to the driver's DpWmiSetDataItem routine, which is an optional entry point for drivers that call WMI library support routines. If the driver does not implement this routine, it must set this member to NULL. In this case, WMI returns STATUS_WMI_READ_ONLY to the caller in response to any IRP_MN_CHANGE_SINGLE_ITEM request.
ExecuteWmiMethod
Points to the driver's DpWmiExecuteMethod routine, which is an optional entry point for drivers that call WMI library support routines. If the driver does not implement this routine, it must set this member to NULL. In this case, WMI returns STATUS_INVALID_DEVICE_REQUEST to the caller in response to any IRP_MN_EXECUTE_METHOD request.
WmiFunctionControl
Points to the driver's DpWmiFunctionControl routine, which is an optional entry point for drivers that call WMI library support routines. If the driver does not implement this routine, it must set this member to NULL. In this case, WMI returns STATUS_SUCCESS to the caller in response to any IRP_MN_ENABLE_XXX or IRP_MN_DISABLE_XXX request.

Comments

A driver that handles WMI IRPs by calling WMI library support routines stores an initialized WMILIB_CONTEXT structure (or a pointer to such a structure) in its device extension. A driver can use the same WMILIB_CONTEXT structure for multiple device objects if each device object supplies the same set of data blocks.

When the driver receives an IRP_MJ_SYSTEM_CONTROL request, it calls WmiSystemControl with a pointer to its WMILIB_CONTEXT structure, a pointer to its device object, and a pointer to the IRP. WmiSystemControl determines whether the IRP contains a WMI request and, if so, handles the request by calling the driver's appropriate DpWmiXxx routine.

Memory for this structure can be allocated from paged pool.

See Also

DpWmiExecuteMethod, DpWmiFunctionControl, DpWmiQueryReginfo, DpWmiQueryDataBlock, DpWmiSetDataBlock, DpWmiSetDataItem, WMIGUIDREGINFO, WmiSystemControl


WMIGUIDREGINFO

A WMIGUIDREGINFO structure contains registration information for a given data block or event block exposed by a driver that uses the WMI library support routines.

typedef struct {
  LPCGUID  Guid;
  ULONG  InstanceCount;
  ULONG  Flags;
} WMIGUIDREGINFO, *PWMIGUIDREGINFO;

Members

Guid
Points to the GUID that identifies the block. The memory that contains the GUID can be paged unless it is also used to call WmiFireEvent.
InstanceCount
Specifies the number of instances defined for the block.
Flags
Indicates characteristics of the block. WMI ORs Flags with the flags set by the driver in the RegFlags parameter of its DpWmiQueryReginfo routine, which apply to all of the data blocks and event blocks registered by the driver. Flags therefore supplements the driver's default settings for a given block.

A driver might set the following flag in Flags:

WMIREG_FLAG_INSTANCE_PDO
Requests WMI to generate static instance names from the device instance ID for the PDO. If this flag is set, the Pdo parameter of the driver's DpWmiQueryReginfo routine points to the PDO passed to the driver's AddDevice routine. WMI generates instance names from the device instance path of the PDO. Using the device instance path as a base for static instance names is efficient because such names are guaranteed to be unique. WMI automatically supplies a "friendly" name for the instance as an item in a data block that can be queried by data consumers.

A driver might also set one or more of the following flags:

WMIREG_FLAG_EVENT_ONLY_GUID
The block can be enabled or disabled as an event only, and cannot be queried or set. If this flag is clear, the block can also be queried or set.
WMIREG_FLAG_EXPENSIVE
Requests WMI to send an IRP_MN_ENABLE_COLLECTION request the first time a data consumer opens the data block and an IRP_MN_DISABLE_COLLECTION request when the last data consumer closes the data block. This is recommended if collecting such data affects performance, because a driver need not collect the data until a data consumer explicitly requests it by opening the block.
WMIREG_FLAG_REMOVE_GUID
Requests WMI to remove support for this block. This flag is valid only in response to a request to update registration information (IRP_MN_REGINFO or IRP_MN_REGINFO_EX with Parameters.WMI.DataPath set to WMIUPDATE).

Comments

A driver that handles WMI IRPs by calling WMI library support routines builds An array of WMIGUIDREGINFO structures, one for each data block and event block to be registered. The driver sets the GuidList member of its WMILIB_CONTEXT structure to point to the first WMIGUIDREGINFO in the series.

Memory for this structure can be allocated from paged pool.

See Also

DpWmiQueryReginfo, IRP_MN_DISABLE_COLLECTION, IRP_MN_ENABLE_COLLECTION, IRP_MN_REGINFO, IRP_MN_REGINFO_EX, WmiFireEvent, WMILIB_CONTEXT


WMIREGGUID

A WMIREGGUID contains new or updated registration information for a data block or event block.

typedef struct {
  GUID  Guid;
  ULONG  Flags;
  ULONG  InstanceCount;
  union {
    ULONG  InstanceNameList;
    ULONG  BaseNameOffset;
    ULONG_PTR  Pdo;
    ULONG_PTR  InstanceInfo;
  };
} WMIREGGUID, *PWMIREGGUID

Members

Guid
Specifies the GUID that represents the block to register or update.
Flags
Indicates characteristics of the block to register or update.

If a block is being registered with static instance names, a driver sets one of the following flags:

WMIREG_FLAG_INSTANCE_LIST
Indicates that the driver provides static instance names for this block in a static list following the WMIREGINFO structure in the buffer at IrpStack->Parameters.WMI.Buffer. If this flag is set, InstanceNameList is the offset in bytes from the beginning of the WMIREGINFO structure that contains this WMIREGGUID to a contiguous series of InstanceCount counted UNICODE strings.
WMIREG_FLAG_INSTANCE_BASENAME
Requests WMI to generate static instance names from a base name provided by the driver following the WMIREGINFO structure in the buffer at IrpStack->Parameters.WMI.Buffer. WMI generates instance names by appending a counter to the base name. If this flag is set, BaseNameOffset is the offset in bytes from the beginning of the WMIREGINFO structure that contains this WMIREGGUID to a single counted UNICODE string that serves as the base name.
WMIREG_FLAG_INSTANCE_PDO
Requests WMI to generate static instance names from the device instance ID for the PDO. If this flag is set, InstanceInfo points to the PDO passed to the driver's AddDevice routine. WMI generates instance names from the device instance path of the PDO. Using the device instance path as a base for static instance names is efficient because such names are guaranteed to be unique. WMI automatically supplies a "friendly" name for the instance as an item in a data block that can be queried by data consumers.

If a block is being registered with dynamic instance names, WMIREG_FLAG_INSTANCE_LIST, WMIREG_FLAG_INSTANCE_BASENAME, and WMIREG_FLAG_INSTANCE_PDO must be clear.

A driver might also set one or more of the following flags:

WMIREG_FLAG_EVENT_ONLY_GUID
The block can be enabled or disabled as an event only, and cannot be queried or set. If this flag is clear, the block can also be queried or set.
WMIREG_FLAG_EXPENSIVE
Requests WMI to send an IRP_MN_ENABLE_COLLECTION request the first time a data consumer opens the data block and an IRP_MN_DISABLE_COLLECTION request when the last data consumer closes the data block. This is recommended if collecting such data affects performance, because a driver need not collect the data until a data consumer explicitly requests it by opening the block.
WMIREG_FLAG_REMOVE_GUID
Requests WMI to remove support for this block. This flag is valid only in response to a request to update registration information (IRP_MN_REGINFO or IRP_MN_REGINFO_EX with Parameters.WMI.DataPath set to WMIUPDATE).
WMIREG_FLAG_TRACED_GUID
The block can be written only to a log file and can be accessed only through user-mode routines declared in evntrace.h. Only NT kernel-mode data providers set this flag.
WMIREG_FLAG_TRACE_CONTROL_GUID
The GUID acts as the control GUID for enabling or disabling the trace GUIDs associated with it in the MOF file. This flag is valid only if WMIREG_FLAG_TRACED_GUID is also set. Only NT kernel-mode data providers set this flag.
InstanceCount
Specifies the number of static instance names to be defined for this block. If the block is being registered with dynamic instance names, WMI ignores InstanceCount.
InstanceNameList
Indicates the offset in bytes from the beginning of the WMIREGINFO structure that contains this WMIREGGUID to a contiguous series of InstanceCount counted Unicode strings. This member is valid only if WMIREG_FLAG_INSTANCE_LIST is set in Flags. If the block is being registered with dynamic instance names, WMI ignores InstanceNameList.
BaseNameOffset
Indicates the offset in bytes from the beginning of the WMIREGINFO structure that contains this WMIREGGUID to a single counted UNICODE string that serves as a base for WMI to generate static instance names. This member is valid only if WMIREG_FLAG_INSTANCE_BASENAME is set in Flags. If the block is being registered with dynamic instance names, WMI ignores BaseNameOffset.
Pdo
Points to the physical device object (PDO) passed to the driver's AddDevice routine. WMI uses the device instance path of this PDO as a base from which to generate static instance names. This member is valid only if WMIREG_FLAG_INSTANCE_PDO is set in Flags. If the block is being registered with dynamic instance names, WMI ignores Pdo.
InstanceInfo
Reserved for use by WMI.

Comments

A driver builds one or more WMIREGGUID structures in response to an IRP_MN_REGINFO or IRP_MN_REGINFO_EX request to register or update its blocks. The driver passes an array of such structures at the WmiRegGuid member of a WMIREGINFO structure, which the driver writes to the buffer at IrpStack->Parameters.WMI.Buffer.

A driver can register or update a block with either static or dynamic instance names. Static instance names provide best performance; however, dynamic instance names are preferred for data blocks if the number of instances or instance names change frequently. For more information about instance names, see Defining WMI Instance Names.

See Also

IRP_MN_REGINFO, IRP_MN_REGINFO_EX, WMIREGINFO


WMIREGINFO

A WMIREGINFO structure contains information provided by a driver to register or update its data blocks and event blocks.

typedef struct {
  ULONG  BufferSize;
  ULONG  NextWmiRegInfo;
  ULONG  RegistryPath;
  ULONG  MofResourceName;
  ULONG  GuidCount;
  WMIREGGUIDW  WmiRegGuid[];
} WMIREGINFO, *PWMIREGINFO;

Members

BufferSize
Indicates the total size of the WMI registration data associated with this WMIREGINFO structure, calculated as follows: (sizeof(WMIREGINFO) + (GuidCount * sizeof(WMIREGGUID) + additionaldata). Additional data might include items such as the MOF resource name, registry path, and static instance names for blocks.
NextWmiRegInfo
If a driver handles WMI requests on behalf of another driver, as a class driver might on behalf of a miniclass driver, NextWmiRegInfo indicates the offset in bytes from the beginning of this WMIREGINFO to the next WMIREGINFO structure that contains WMI registration information for the other driver. Otherwise, NextWmiRegInfo is zero.
RegistryPath
Indicates the offset in bytes from the beginning of this structure to a counted Unicode string that specifies the registry path passed to the driver's DriverEntry routine. The string must be aligned on a USHORT boundary. This member should be set only in response to a WMI registration request (IRP_MN_REGINFO or IRP_MN_REGINFO_EX with Parameters.WMI.DataPath set to WMIREGISTER).
MofResourceName
Indicates the offset in bytes from the beginning of this structure to a counted Unicode string that specifies the name of the MOF resource in the driver's image file. The string must be aligned on a USHORT boundary. This member should be set only in response to a WMI registration request (IRP_MN_REGINFO or IRP_MN_REGINFO_EX with Parameters.WMI.DataPath set to WMIREGISTER).
GuidCount
Indicates the number of WMIREGGUID structures in the array at WmiRegGuid.
WmiRegGuid
Is an array of GuidCount WMIREGGUID structures.

Comments

In response to a registration request (IRP_MN_REGINFO or IRP_MN_REGINFO_EX with Parameters.WMI.DataPath set to WMIREGISTER), a driver builds at least one WMIREGINFO structure and writes the WMIREGINFO structure to the buffer at IrpStack->Parameters.WMI.Buffer. The WMIREGINFO structure contains an array of WMIREGGUID structures, one for each data block or event block exposed by the driver.

If the driver handles WMI requests on behalf of another driver, it builds another WMIREGINFO containing an array of WMIREGGUID structures for each block exposed by the other driver, sets the NextWmiRegInfo member of the first WMIREGINFO to an offset in bytes from the beginning of the first WMIREGINFO to the beginning of the next WMIREGINFO in the buffer, and writes both structures to the buffer. The driver indicates the total size of both WMIREGINFO structures and associated data when calls IoCompleteRequest to complete the IRP.

A driver can use the same WMIREGINFO structure(s) to remove or update blocks in response to an update request (IRP_MN_REGINFO or IRP_MN_REGINFO_EX with Parameters.WMI.DataPath set to WMIUPDATE). If WMIREG_FLAG_REMOVE_GUID is set in the Flags member of a WMIREGGUID, WMI removes that block from the list of blocks previously registered by the driver. If WMIREG_FLAG_REMOVE_GUID is clear, WMI updates registration information for that block only if other WMIREGGUID members have changed — otherwise, WMI does not change to its registration information for that block.

See Also

IoCompleteRequest, IRP_MN_REGINFO, IRP_MN_REGINFO_EX, WMIREGGUID


WNODE_ALL_DATA

A WNODE_ALL_DATA structure contains data for all instances of a data block or event block.

typedef struct tagWNODE_ALL_DATA {
  struct _WNODE_HEADER  WnodeHeader;
  ULONG  DataBlockOffset;
  ULONG  InstanceCount;
  ULONG  OffsetInstanceNameOffsets;
  union {
    ULONG  FixedInstanceSize;
    OFFSETINSTANCEDATAANDLENGTH  OffsetInstanceDataAndLength[];
  };
} WNODE_ALL_DATA, *PWNODE_ALL_DATA;

Members

WnodeHeader
Is a WNODE_HEADER structure that contains information common to all WNODE_XXX structures, such as the buffer size, the GUID that represents a data block associated with a request, and flags that provide information about the WNODE_XXX data being passed or returned.
DataBlockOffset
Indicates the offset in bytes from the beginning of the WNODE_ALL_DATA structure to the beginning of data for the first instance.
InstanceCount
Indicates the number of instances whose data follows the fixed members of the WNODE_ALL_DATA in the buffer at IrpStack->Parameters.WMI.Buffer.
OffsetInstanceNameOffsets
Indicates the offset in bytes from the beginning of the WNODE_ALL_DATA to an array of offsets to dynamic instance names. Each instance name must be aligned on a USHORT boundary. If all instances to be returned have static instance names, WMI ignores OffsetInstanceNameOffsets.
FixedInstanceSize
Indicates the size of each instance to be returned if all such instances are the same size. This member is valid only if the driver sets WNODE_FLAG_FIXED_INSTANCE_SIZE in WnodeHeader.Flags.
OffsetInstanceDataAndLength
If instances to be returned vary in size, OffsetInstanceDataAndLength is an array of InstanceCount OFFSETINSTANCEDATAANDLENGTH structures that specify the offset in bytes from the beginning of the WNODE_ALL_DATA to the beginning of each instance and its length. OFFSETINSTANCEDATAANDLENGTH is defined as follows:
typedef struct {
    ULONG OffsetInstanceData;
    ULONG LengthInstanceData;
} OFFSETINSTANCEDATAANDLENGTH, *POFFSETINSTANCEDATAANDLENGTH
OffsetInstanceData
Indicates the offset in bytes from the beginning of the WNODE_ALL_DATA to the instance data.
LengthInstanceData
Indicates the length in bytes of the instance data.

Each instance must be aligned on a USHORT boundary. The OffsetInstanceDataAndLength member is valid only if the driver clears WNODE_FLAG_FIXED_INSTANCE_SIZE in WnodeHeader.Flags.

Comments

A driver fills in a WNODE_ALL_DATA structure in response to an IRP_MN_QUERY_ALL_DATA request. A driver might also generate a WNODE_ALL_DATA as an event.

After filling in the fixed members of the structure, a driver writes instance data and dynamic instance names (if any) at DataBlockOffset and OffsetInstanceNameOffsets, respectively, in the buffer at IrpStack->Parameters.WMI.Buffer. If WNODE_FLAG_FIXED_INSTANCE_SIZE is clear, the first offset follows the last element of the OffsetInstanceDataAndLength array, plus padding so the data begins on an 8-byte boundary.

Instance names must be USHORT aligned. Instance data must be QUADWORD aligned.

See Also

IRP_MN_QUERY_ALL_DATA, WNODE_EVENT_ITEM, WNODE_HEADER


WNODE_EVENT_ITEM

A WNODE_EVENT_ITEM contains data generated by a driver for an event.

typedef struct tagWNODE_EVENT_ITEM {
  struct _WNODE_HEADER    WnodeHeader;
                          // Rest of WNODE data indicated by
                          // flags in WnodeHeader
} WNODE_EVENT_ITEM, *PWNODE_EVENT_ITEM;
WnodeHeader
Is a WNODE_HEADER structure that contains information common to all WNODE_XXX structures, such as the buffer size, the GUID that represents a data block associated with a request, and flags that provide information about the WNODE_XXX data being passed or returned.

Comments

A WNODE_EVENT_ITEM contains whatever data the driver determines is appropriate for an event, in a WNODE_XXX structure that is appropriate for that data.

The ProviderId member of the WNODE_HEADER structure for use in a WNODE_EVENT_ITEM structure should be initialized using IoWMIDeviceObjectToProviderId.

A driver generates only events that it has previously enabled in response to an IRP_MN_ENABLE_EVENTS request. To generate an event, a driver calls IoWMIWriteEvent and passes a pointer to the WNODE_EVENT_ITEM. WMI queues the event for delivery to all data consumers registered for that event.

For best performance, events should be small in size. However, if the amount of data for an event exceeds the maximum size defined in the registry, a driver can pass a WNODE_EVENT_REFERENCE, which WMI uses to query for the related WNODE_EVENT_ITEM. For more information about defining and generating WMI events, see Windows Management Instrumentation.

See Also

IoWMIWriteEvent, IoWMIDeviceObjectToProviderId, IRP_MN_ENABLE_EVENTS, WNODE_ALL_DATA, WNODE_EVENT_REFERENCE, WNODE_HEADER, WNODE_SINGLE_INSTANCE, WNODE_SINGLE_ITEM


WNODE_EVENT_REFERENCE

A WNODE_EVENT_REFERENCE contains information that WMI can use to query for an event that exceeds the event size limit set in the registry.

typedef struct tagWNODE_EVENT_REFERENCE {
  struct _WNODE_HEADER    WnodeHeader;
  GUID                    TargetGuid;
  ULONG                   TargetDataBlockSize;
  union
  {
    ULONG    TargetInstanceIndex;
    WCHAR    TargetInstanceName[];
  };
} WNODE_EVENT_REFERENCE, *PWNODE_EVENT_REFERENCE;

Members

WnodeHeader
Is a WNODE_HEADER structure that contains information common to all WNODE_XXX structures, such as the buffer size, the Provider Id, the GUID that represents a data block associated with a request, and flags that provide information about the WNODE_XXX data being passed or returned.
TargetGuid
Indicates the GUID that represents the event to query.
TargetDataBlockSize
Indicates the size of the event.
TargetInstanceIndex
Indicates the index into the driver's list of static instance names for the event. This member is valid only if the event block was registered with static instance names and WNODE_FLAGS_STATIC_INSTANCE_NAMES is set in WnodeHeader.Flags.
TargetInstanceName
Indicates the dynamic instance name of the event as a counted Unicode string. This member is valid only if WNODE_FLAGS_STATIC_INSTANCE_NAMES is clear in WnodeHeader.Flags and the event block was registered with dynamic instance names.

Comments

If the amount of data for an event exceeds the maximum size set in the registry, a driver can generate a WNODE_EVENT_REFERENCE that specifies a WNODE_EVENT_ITEM that WMI can query to obtain the event. For more information about defining and generating WMI events, see the Kernel-mode Drivers Design.

The ProviderId member of the WNODE_HEADER structure for use in a WNODE_EVENT_REFERENCE structure should be initialized using IoWMIDeviceObjectToProviderId.

See Also

WNODE_EVENT_ITEM, WNODE_HEADER, IoWMIDeviceObjectToProviderId


WNODE_HEADER

A WNODE_HEADER is the first member of all other WNODE_XXX structures. It contains information common to all such structures.

typedef struct _WNODE_HEADER {
  ULONG       BufferSize;
  UINT_PTR    ProviderId;
  union {
    ULONG64    HistoricalContext;
    struct {
      ULONG    Version;
      ULONG    Linkage;
    };
  };
  union {
    HANDLE           KernelHandle;
    LARGE_INTEGER    TimeStamp;
  };
  GUID        Guid;
  ULONG       ClientContext;
  ULONG       Flags;
} WNODE_HEADER, *PWNODE_HEADER;

Members

BufferSize
Specifies the size in bytes of the nonpaged buffer to receive any WNODE_XXX data to be returned, including this WNODE_HEADER, additional members of a WNODE_XXX structure of the type indicated by Flags, and any WMI- or driver-determined data that accompanies that structure.
ProviderId
If Flags is set to WNODE_FLAG_EVENT_ITEM or WNODE_FLAG_EVENT_REFERENCE then ProviderId should contain the Id of the WMI Provider associated with the device object. The ProviderId value can be gotten by calling IoWMIDeviceObjectToProviderId. If Flags is set to any other value, then this member is reserved.
HistoricalContext
Reserved for WMI.
Version
Reserved for WMI.
Linkage
Reserved for WMI.
KernelHandle
Reserved for WMI.
TimeStamp
Indicates the system time a driver collected the WNODE_XXX data, in units of 100 nanoseconds since 1/1/1601. A driver can call KeQuerySystemTime to obtain this value. If the block is to be written to a log file (WNODE_FLAG_LOG_WNODE), an NT driver might also set WNODE_FLAG_USE_TIMESTAMP in Flags to request the system logger to leave the value of TimeStamp unchanged.
Guid
Indicates the GUID that represents the data block associated with the WNODE_XXX to be returned.
ClientContext
Reserved for WMI.
Flags
Indicates the type of WNODE_XXX structure that contains the WNODE_HEADER:
WNODE_FLAG_ALL_DATA
The rest of a WNODE_ALL_DATA structure follows the WNODE_HEADER in the buffer.

WMI sets this flag in the WNODE_HEADER it passes with an IRP_MN_QUERY_ALL_DATA request.

A driver sets this flag in the WNODE_HEADER of an event that consists of all instances of a data block. If the data block size is identical for all instances, a driver also sets WNODE_FLAG_FIXED_INSTANCE_SIZE.

WNODE_FLAG_EVENT_ITEM
A driver sets this flag to indicate that the WNODE_XXX structure was generated as an event. This flag is valid only if WNODE_FLAG_ALL_DATA, WNODE_FLAG_SINGLE_INSTANCE, or WNODE_FLAG_SINGLE_ITEM is also set.
WNODE_FLAG_EVENT_REFERENCE
The rest of a WNODE_EVENT_REFERENCE structure follows the WNODE_HEADER in the buffer.

A driver sets this flag when it generates an event that is larger than the maximum size specified in the registry for an event. WMI uses the information in the WNODE_EVENT_REFERENCE to request the event data and schedules such a request according to the value of WNODE_FLAG_SEVERITY_MASK.

WNODE_FLAG_METHOD_ITEM
The rest of a WNODE_METHOD_ITEM structure follows the WNODE_HEADER in the buffer.

WMI sets this flag in the WNODE_HEADER it passes with an IRP_MN_EXECUTE_METHOD request.

WNODE_FLAG_SINGLE_INSTANCE
The rest of a WNODE_SINGLE_INSTANCE structure follows the WNODE_HEADER in the buffer.

WMI sets this flag in the WNODE_HEADER it passes with a request to query or change an instance.

A driver sets this flag in the WNODE_HEADER of an event that consists of a single instance of a data block.

WNODE_FLAG_SINGLE_ITEM
The rest of a WNODE_SINGLE_ITEM structure follows the WNODE_HEADER in the buffer.

WMI sets this flag in the WNODE_HEADER it passes with a request to change an item.

A driver sets this flag in the WNODE_HEADER of an event that consists of a single data item.

WNODE_FLAG_TOO_SMALL
The rest of a WNODE_TOO_SMALL structure follows the WNODE_HEADER in the buffer.

A driver sets this flag when it passes a WNODE_TOO_SMALL, indicating that the buffer is too small for all of the WNODE_XXX data to be returned.

In addition, Flags might be set with one or more of the following flags that provide additional information about the WNODE_XXX:

WNODE_FLAG_FIXED_INSTANCE_SIZE
All instances of a data block are the same size. This flag is valid only if WNODE_FLAG_ALL_DATA is also set.
WNODE_FLAG_INSTANCES_SAME
The number of instances and the dynamic instance names in a WNODE_ALL_DATA to be returned are identical to those returned from the previous WNODE_ALL_DATA query. This flag is valid only if WNODE_FLAG_ALL_DATA is also set. This flag is ignored for data blocks registered with static instance names.

For optimized performance, a driver should set this flag if it can track changes to the number or names of its data blocks. WMI can then skip the processing required to detect and update dynamic instance names.

WNODE_FLAG_STATIC_INSTANCE_NAMES
The WNODE_XXX data to be returned does not include instance names.

WMI sets this flag before requesting WNODE_XXX data for data blocks registered with static instance names. After receiving the returned WNODE_XXX from the driver, WMI fills in the static instance names specified at registration before passing the returned WNODE_XXX to a data consumer.

WNODE_FLAG_PDO_INSTANCE_NAMES
Static instance names are based on the device instance ID of the PDO for the device. A driver requests such names by setting WMIREG_FLAG_INSTANCE_PDO in the WMIREGGUID it uses to register the block.

WMI sets this flag before requesting WNODE_XXX data for data blocks registered with PDO-based instance names.

WNODE_FLAG_SEVERITY_MASK
The driver-determined severity level of the event associated with a returned WNODE_EVENT_REFERENCE, with 0x00 indicating the least severe and 0xff indicating the most severe level.

WMI uses the value of this flag to prioritize its requests for the event data.

WNODE_FLAG_USE_TIMESTAMP
The system logger should not modify the value of TimeStamp set by the driver.

An NT driver might also set Flags to one or more of the following values for event blocks to be written to a system log file:

WNODE_FLAG_LOG_WNODE
An event block is to be sent to the system logger. The event header is a standard WNODE_HEADER structure. If the driver clears WNODE_FLAG_TRACED_GUID, the block will also be sent to WMI for delivery to any data consumers that have enabled the event. The driver must allocate the WNODE_XXX from pool memory. WMI frees the memory after delivering the event to data consumers.
WNODE_FLAG_TRACED_GUID
An event block is to be sent only to the system logger. It does not get sent to WMI data consumers. The event header is an EVENT_TRACE_HEADER structure, declared in evntrace.h, instead of a WNODE_HEADER. The driver must allocate memory for the WNODE_XXX and free it after IoWMIWriteEvent returns. The driver can allocate such memory either from the stack or, to minimize the overhead of allocating and freeing the memory, from the driver's thread local storage if the driver creates and maintains its own thread pool.
WNODE_FLAG_USE_GUID_PTR
The Guid member points to a GUID in memory, rather than containing the GUID itself. The system logger dereferences the pointer before passing the data to the consumer. This flag is valid only if WNODE_FLAG_LOG_WNODE or WNODE_FLAG_TRACED_GUID are also set.
WNODE_FLAG_USE_MOF_PTR
Data that follows the fixed members of a WNODE_XXX structure consists of an array of MOF_FIELD structures, defined in evntrace.h, that contain pointers to data and sizes rather than the data itself. The array can contain up to MAX_MOF_FIELD elements. The system logger dereferences the pointers before passing the data to the consumer This flag is valid only for blocks registered with WMIREG_FLAG_TRACED_GUID.

Comments

In an IRP_MN_CHANGE_XXX or IRP_MN_EXECUTE_METHOD request, BufferSize in the IRP indicates the maximum size in bytes of the output buffer, while BufferSize in the input WNODE_HEADER for such a request indicates the size in bytes of the input data in the buffer.

See Also

IoWMIWriteEvent,IoWMIDeviceObjectToProviderId, KeQuerySystemTime, WNODE_ALL_DATA, WNODE_EVENT_ITEM, WNODE_EVENT_REFERENCE, WNODE_METHOD_ITEM, WNODE_SINGLE_INSTANCE, WNODE_SINGLE_ITEM, WNODE_TOO_SMALL


WNODE_METHOD_ITEM

A WNODE_METHOD_ITEM indicates a method associated with an instance of a data block and contains any input data for the method.

typedef struct tagWNODE_METHOD_ITEM {
  struct _WNODE_HEADER    WnodeHeader;
  ULONG  OffsetInstanceName;
  ULONG  InstanceIndex;
  ULONG  MethodId;
  ULONG  DataBlockOffset;
  ULONG  SizeDataBlock;
  UCHAR  VariableData[];
} WNODE_METHOD_ITEM, *PWNODE_METHOD_ITEM;

Members

WnodeHeader
Is a WNODE_HEADER structure that contains information common to all WNODE_XXX structures, such as the buffer size, the GUID that represents a data block associated with a request, and flags that provide information about the WNODE_XXX data being passed or returned.
OffsetInstanceName
Indicates the offset in bytes from the beginning of this structure to the dynamic instance name of this instance, aligned on a USHORT boundary. This member is valid only if WNODE_FLAG_STATIC_INSTANCE_NAMES is clear in WnodeHeader.Flags. If the data block was registered with static instance names, WMI ignores OffsetInstanceName.
InstanceIndex
Indicates the index of this instance into the driver's list of static instance names for this data block. This member is valid only if the data block was registered with static instance names and WNODE_FLAG_STATIC_INSTANCE_NAME is set in WnodeHeader.Flags. If the data block was registered with dynamic instance names, WMI ignores InstanceIndex.
MethodId
Specifies the ID of the method to execute.
DataBlockOffset
Indicates the offset from the beginning of an input WNODE_METHOD_ITEM to input data for the method, or the offset from the beginning of an output WNODE_METHOD_ITEM to output data from the method.
SizeDataBlock
Indicates the size of the input data in an input WNODE_METHOD_ITEM, or zero if there is no input. In an output WNODE_METHOD_ITEM, SizeDataBlock indicates the size of the output data, or zero if there is no output.
VariableData
Contains additional data, including the dynamic instance name if any, and the input for or output from the method aligned on an 8-byte boundary.

Comments

WMI passes a WNODE_METHOD_ITEM with an IRP_MN_EXECUTE_METHOD request to specify a method to execute in an instance of a data block, plus any input data required by the method.

If a method generates output, a driver overwrites the input data with the output at DataBlockOffset in the buffer at IrpStack->Parameters.WMI.Buffer, and sets SizeDataBlock in the WNODE_METHOD_ITEM to specify the size of the output data.

See Also

WNODE_HEADER


WNODE_SINGLE_INSTANCE

A WNODE_SINGLE_INSTANCE contains values for all data items in one instance of a data block.

typedef struct tagWNODE_SINGLE_INSTANCE {
  struct _WNODE_HEADER    WnodeHeader;
  ULONG  OffsetInstanceName;
  ULONG  InstanceIndex;
  ULONG  DataBlockOffset;
  ULONG  SizeDataBlock;
  UCHAR  VariableData[];
} WNODE_SINGLE_INSTANCE, *PWNODE_SINGLE_INSTANCE;

Members

WnodeHeader
Is a WNODE_HEADER structure that contains information common to all WNODE_XXX structures, such as the buffer size, the GUID that represents a data block associated with a request, and flags that provide information about the WNODE_XXX data being passed or returned.
OffsetInstanceName
Indicates the offset from the beginning of this structure to the dynamic instance name of this instance, aligned on a USHORT boundary. This member is valid only if WNODE_FLAG_STATIC_INSTANCE_NAMES is clear in WnodeHeader.Flags. If the data block was registered with static instance names, WMI ignores OffsetInstanceName.
InstanceIndex
Indicates the index of an instance registered with static instance names. This member is valid only if WNODE_FLAG_STATIC_INSTANCE_NAME is set in WnodeHeader.Flags. If the data block was registered with dynamic instance names, WMI ignores InstanceIndex.
DataBlockOffset
Indicates the offset from the beginning of this structure to the beginning of the instance.
SizeDataBlock
Indicates the size of the data block for this instance.
VariableData
Contains additional data, including the dynamic instance name if any, padding so the instance begins on an 8-byte boundary, and the instance of the data block to be returned.

Comments

WMI passes a WNODE_SINGLE_INSTANCE with an IRP_MN_CHANGE_SINGLE_INSTANCE request to set read-write data items in an instance of a data block. A driver can ignore values passed for read-only data items in the instance.

A driver fills in a WNODE_SINGLE_INSTANCE in response to an IRP_MN_QUERY_SINGLE_INSTANCE request or to generate an event that consists of a single instance.

See Also

WNODE_EVENT_ITEM, WNODE_HEADER


WNODE_TOO_SMALL

A WNODE_TOO_SMALL indicates the size of the buffer needed to receive output from a request.

typedef struct tagWNODE_TOO_SMALL {
  struct _WNODE_HEADER  WnodeHeader;
  ULONG  SizeNeeded;
} WNODE_TOO_SMALL, *PWNODE_TOO_SMALL;

Members

WnodeHeader
Is a WNODE_HEADER structure that contains information common to all WNODE_XXX structures, such as the buffer size, the GUID that represents a data block associated with a request, and flags that provide information about the WNODE_XXX data being passed or returned.
SizeNeeded
Specifies the size of the buffer needed to receive all of the WNODE_XXX data to be returned.

Comments

When the buffer for a WMI request is too small to receive all of the data to be returned, a driver fills in a WNODE_TOO_SMALL structure to indicate the required buffer size. WMI can then increase the buffer to the recommended size and issue the request again. A driver is responsible for managing any side effects caused by handling the same request more than once.

See Also

WNODE_HEADER


System Types

This section describes system-defined types used by kernel-mode drivers.


IO_ALLOCATION_ACTION

The IO_ALLOCATION_ACTION enumerated type is used to specify return values for AdapterControl and ControllerControl routines.

typedef enum _IO_ALLOCATION_ACTION {
    KeepObject = 1,
    DeallocateObject,
    DeallocateObjectKeepRegisters
} IO_ALLOCATION_ACTION, *PIO_ALLOCATION_ACTION;

Enumerators

KeepObject
Indicates that you want the driver to retain ownership of the adapter or controller object.
DeallocateObject
Indicates that you do not want the driver to retain ownership of the adapter or controller object.
DeallocateObjectKeepRegisters
For adapter objects only. Indicates that you do not want the driver to retain ownership of the adapter object, but you do want the driver to retain ownership of the allocated map registers.

Comments

If an AdapterControl or ControllerControl routine completes an IRP, or if it can set up an operation (such as a disk seek) for a target device object that could be overlapped with an operation for another device object, it should return DeallocateObject.

If a driver uses packet-based bus master DMA, its AdapterControl routine should return DeallocateObjectKeepRegisters.

Otherwise, the driver should return KeepObject.


IRP Function Codes and IOCTLs

Each driver-specific I/O stack location in every IRP has a major function code (IRP_MJ_XXX) that tells the driver what operation it or the underlying device driver should carry out to satisfy the I/O request. Each kernel-mode driver must set up one or more Dispatch entry points for a required subset of system-defined major function codes that are set in the I/O stack location(s) of IRPs.

The subset of major function codes that a driver must handle depends on the nature of its device. That is, the IRP_MJ_XXX requests sent to a keyboard driver are necessarily somewhat different from those sent to a disk driver.

Every higher-level driver must set up the appropriate I/O stack location in IRPs for the next-lower-level driver and call IoCallDriver either with each input IRP or with a driver-created IRP if the higher-level driver holds on to the input IRP. Consequently, every intermediate driver must supply a Dispatch entry point for each major function code that the underlying device driver handles. Otherwise, a new intermediate driver will "break the chain" whenever an application or still higher-level driver attempts to send an I/O request, which is valid but unsupported by the new intermediate driver, down to the underlying device driver.

File system drivers also handle a required subset of system-defined IRP_MJ_XXX function codes, some with subordinate IRP_MN_XXX function codes.

This section contains the following topics:

IRP Major Function Codes

Device Type-specific I/O Requests

Defining I/O Control Codes


IRP Major Function Codes

Drivers handle IRPs set with some or all of the following major function codes:

IRP_MJ_CREATE

IRP_MJ_PNP

IRP_MJ_POWER

IRP_MJ_READ

IRP_MJ_WRITE

IRP_MJ_FLUSH_BUFFERS

IRP_MJ_QUERY_INFORMATION

IRP_MJ_SET_INFORMATION

IRP_MJ_DEVICE_CONTROL

IRP_MJ_INTERNAL_DEVICE_CONTROL

IRP_MJ_SYSTEM_CONTROL

IRP_MJ_CLEANUP

IRP_MJ_CLOSE

IRP_MJ_SHUTDOWN

As a general rule, an intermediate driver must handle at least the same IRP_MJ_XXX code as the next-lower driver. That is, an intermediate driver must provide a dispatch routine for every IRP_MJ_XXX code that the I/O Manager or a higher-level driver might send to the underlying device.

The specific operations a driver carries out for a given IRP_MJ_XXX code depends somewhat on the underlying device, particularly for IRP_MJ_DEVICE_CONTROL and IRP_MJ_INTERNAL_DEVICE_CONTROL requests. However, the I/O Manager defines the parameters and I/O stack location contents for each major function code that it sets in IRPs.

The rest of this section summarizes request-specific information about parameters for the IRP_MJ_XXX codes that device and intermediate drivers handle, as well as general information about the kinds of drivers that must handle each type of request and how they satisfy each type of request. See also System Structures for more information about the IRP, I/O stack location, and I/O status block structures.

The input and output parameters described in this section are the function-specific parameters in the IRP.


IRP_MJ_CLEANUP

Drivers that have Cancel routines also must handle cleanup requests.

When Sent

Receipt of this request indicates that the handle for the file object, representing the target device object, is being released.

Input Parameters

None

Output Parameters

None

Operation

If the driver's device objects were set up as exclusive, thereby allowing only a single thread to use the device at any given time, the driver completes every IRP currently queued to the target device object with STATUS_CANCELLED set in each IRP's I/O status block. Otherwise, the driver must cancel and complete any currently queued IRPs for the holder of the file object handle that is being released. After cancelling outstanding IRPs in the queue, the driver completes the cleanup IRP with STATUS_SUCCESS set in its I/O status block.


IRP_MJ_CLOSE

Every driver must handle close requests, with the possible exception of a driver whose device cannot be disabled or removed from the machine without bringing down the system. A disk driver whose device holds the system page file is an example of such a driver. Note that the driver of such a device also cannot be unloaded dynamically.

When Sent

Receipt of this request indicates that the handle of the file object that represents the target device object has been released.

Input Parameters

None

Output Parameters

None

Operation

Many device and intermediate drivers merely set STATUS_SUCCESS in the I/O status block of the IRP and complete the close request. However, what a given driver does on receipt of a close request depends on the driver's design. In general, a driver should undo whatever actions it takes on receipt of the create request. Device drivers whose device objects are exclusive, such as a serial driver, also can reset the hardware on receipt of a close request.


IRP_MJ_CREATE

Every kernel-mode driver must handle create requests.

When Sent

Receipt of this request indicates that a user-mode protected subsystem, possibly on behalf of an application, has requested a handle for the file object that represents the target device object, or that a higher-level driver is connecting or attaching its device object to the target device object.

Input Parameters

None

Output Parameters

None

Operation

Many device and intermediate drivers merely set STATUS_SUCCESS in the I/O status block of the IRP and complete the create request. However, what a given driver does on receipt of a create request depends on the driver's design. For example, a driver with pageable-image sections, like the system serial driver, maps in its paged-out code and allocates any resources necessary to handle subsequent I/O requests for the user-mode thread that is attempting to open the device for I/O.


IRP_MJ_DEVICE_CONTROL

Every driver whose device objects are of a given device type (see Specifying Device Types) is required to support this request, if a set of system-defined I/O control codes (IOCTLs) exists for the type. Higher-level drivers usually pass these requests on to an underlying device driver. Each device driver of the given device type is assumed to support this request, along with a set of device type-specific, system-defined (also called public) I/O control codes (IOCTL_XXX).

When Sent

Any time following the successful completion of a create request.

Input Parameters

Depending on the I/O control code at Parameters.DeviceIoControl.IoControlCode in the driver's I/O stack location of the IRP, can be one of the following:

  • Caller-supplied data in the buffer at Irp->AssociatedIrp.SystemBuffer, together with the buffer's size in the I/O stack location at Parameters.DeviceIoControl.InputBufferLength and/or a pointer to an additional input buffer in the I/O stack location at Parameters.DeviceIoControl.Type3InputBuffer
  • Caller-supplied data in the buffer described by the MDL at Irp->MdlAddress, with the buffer's size in the I/O stack location at Parameters.DeviceIoControl.InputBufferLength if the lowest-level driver's device uses DMA or PIO and if the requested operation requires the transfer of a large amount of data quickly
  • Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the buffer into which the driver transfers data

Output Parameters

Also determined by the I/O control code in the I/O stack location of the IRP.

Data can be written into the buffer at Irp->AssociatedIrp.SystemBuffer or, using DMA or PIO, into the buffer described by the MDL at Irp->MdlAddress, as long as the transfer does not exceed the buffer's size.

Operation

A driver receives this I/O control code because user-mode thread has called the Microsoft® Win32® DeviceIoControl function, or a higher-level kernel-mode driver has set up the request. Possibly, a user-mode driver has called DeviceIoControl, passing in a driver-defined (also called private) I/O control code, to request device- or driver-specific support from a closely coupled, kernel-mode device driver.

On receipt of a device I/O control request, a higher-level driver usually passes the IRP on to the next-lower driver. However, there are some exceptions to this practice. For example, a class driver that has stored configuration information obtained from the underlying port driver might complete certain IOCTL_XXX requests without passing the IRP down to the corresponding port driver.

On receipt of a device I/O control request, a device driver examines the I/O control code to determine how to satisfy the request. For most public I/O control codes, device drivers transfer a small amount of data to or from the buffer at Irp->AssociatedIrp.SystemBuffer.


IRP_MJ_FLUSH_BUFFERS

Drivers of devices with internal caches for data and drivers that maintain internal buffers for data must handle this request.

When Sent

Receipt of a flush request indicates that the driver should flush the device's cache or its internal buffer, or, possibly, should discard the data in its internal buffer.

Input Parameters

None

Output Parameters

None

Operation

The driver transfers any data currently cached in the device or held in the driver's internal buffers before completing the flush request. The driver of an input-only device that buffers data internally might simply discard the currently buffered device data before completing the flush IRP, depending on the nature of its device.


IRP_MJ_INTERNAL_DEVICE_CONTROL

In general, any replacement for an existing driver that supports internal device control requests should handle this request. Such a driver also should support at least the same set of internal I/O control codes as the driver it replaces. Otherwise, existing higher-level drivers might not work with the new driver.

Drivers that replace certain lower-level system drivers are required to handle this request. For example, a replacement for the system parallel port driver must continue to support existing parallel class drivers. Note that certain system drivers that handle this request cannot be replaced, in particular, the system-supplied SCSI and video port drivers.

When Sent

Any time after the successful completion of a create request.

Input Parameters

Depending on the I/O control code at Parameters.DeviceIoControl.IoControlCode in the I/O stack location of the IRP, can be one of the following:

  • Caller-supplied data in the buffer at Irp->AssociatedIrp.SystemBuffer, together with the buffer's size in the I/O stack location at Parameters.DeviceIoControl.InputBufferLength and/or a pointer to an additional input buffer in the I/O stack location at Parameters.DeviceIoControl.Type3InputBuffer
  • Caller-supplied data in the buffer described by the MDL at Irp->MdlAddress, with the buffer's size in the I/O stack location at Parameters.DeviceIoControl.InputBufferLength if the lowest-level driver's device uses DMA or PIO and if the requested operation requires the transfer of a large amount of data quickly
  • Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the buffer into which the driver transfers data

Output Parameters

Also determined by the I/O control code in the I/O stack location of the IRP.

Data can be written into the buffer at Irp->AssociatedIrp.SystemBuffer or, using DMA or PIO, into the buffer described by the MDL at Irp->MdlAddress, as long as the transfer does not exceed the buffer's size.

Operation

This I/O control code has been defined for communication between paired and layered kernel-mode drivers, such as one or more class drivers layered over a port driver. The higher-level driver sets up IRPs with device- or driver-specific I/O control codes, requesting support from the next-lower driver.

The requested operation is device- or driver-specific.

For general information about I/O control codes for IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL requests, see Defining I/O Control Codes. See also Device Type-specific I/O Requests.


IRP_MJ_PNP

All drivers must be prepared to receive IRP_MJ_PNP requests.

When Sent

The PnP Manager sends IRP_MJ_PNP requests during enumeration, resource rebalancing, and any other time plug-and-play activity occurs on the system. Drivers can also send certain IRP_MJ_PNP requests, depending on the minor function code.

Input Parameters

Depends on the value at MinorFunction in the current I/O stack location of the IRP. Every IRP_MJ_PNP request specifies a minor function code that identifies the requested PnP action.

Output Parameters

Depends on the value at MinorFunction in the current I/O stack location of the IRP.

Operation

See Plug and Play IRPs for detailed information about IRP_MJ_PNP requests.


IRP_MJ_POWER

All drivers must be prepared to receive IRP_MJ_POWER requests.

When Sent

The Power Manager or a driver can send IRP_MJ_POWER requests at any time the operating system is running.

Input Parameters

Depends on the value at MinorFunction in the current I/O stack location of the IRP. Every IRP_MJ_POWER request specifies a minor function code that identifies the requested power action.

Output Parameters

Depends on the value at MinorFunction in the current I/O stack location of the IRP.

Operation

See Power Management IRPs for detailed information about IRP_MJ_POWER requests.


IRP_MJ_QUERY_INFORMATION

For information about this IRP, see IRP_MJ_QUERY_INFORMATION for serial port devices.


IRP_MJ_READ

Every device driver that transfers data from its device to the system must handle read requests, as must any higher-level driver layered over such a device driver.

When Sent

Any time following the successful completion of a create request.

Possibly, a user-mode application or Win32® component with a handle for the file object representing the target device object has requested a data transfer from the device. Possibly, a higher-level driver has created and set up the read IRP.

Input Parameters

The driver's I/O stack location in the IRP indicates how many bytes to transfer at Parameters.Read.Length.

Some drivers use the value at Parameters.Read.Key to sort incoming read requests into a driver-determined order in the device queue or in a driver-managed internal queue of IRPs. Certain types of drivers also use the value at Parameters.Read.ByteOffset, which indicates the starting offset for the transfer operation.

Output Parameters

Depending on whether the underlying device driver sets up the target device object's Flags with DO_BUFFERED_IO or with DO_DIRECT_IO, data is transferred into one of the following:

  • The buffer at Irp->AssociatedIrp.SystemBuffer if the driver uses buffered I/O
  • The buffer described by the MDL at Irp->MdlAddress if the underlying device driver uses direct I/O (DMA or PIO)

Operation

On receipt of a read request, a higher-level driver sets up the I/O stack location in the IRP for the next-lower driver, or it creates and sets up additional IRPs for one or more lower drivers. It can set up its IoCompletion routine, which is optional for the input IRP but required for driver-created IRPs, by calling IoSetCompletionRoutine. Then, the driver passes the request on to the next-lower driver with IoCallDriver.

On receipt of a read request, a device driver transfers data from its device to system memory. The device driver sets the Information field of the I/O status block to the number of bytes transferred when it completes the IRP.


IRP_MJ_SET_INFORMATION

For information about this IRP, see IRP_MJ_SET_INFORMATION for serial port devices.


IRP_MJ_SHUTDOWN

Drivers of mass-storage devices that have internal caches for data must handle this request. Drivers of mass-storage devices and intermediate drivers layered over them also must handle this request if an underlying driver maintains internal buffers for data.

When Sent

Receipt of a shutdown request indicates that a file system driver is sending notice that the system is being shut down.

One or more file system drivers can send such a lower-level driver more than one shutdown request when a user logs off or when the system is being shut down for some other reason.

Input Parameters

None

Output Parameters

None

Operation

The driver must complete the transfer of any data currently cached in the device or held in the driver's internal buffers before completing the shutdown request.


IRP_MJ_SYSTEM_CONTROL

All drivers must be prepared to receive IRP_MJ_SYSTEM_CONTROL requests, which are sent by the kernel-mode component of Windows Management Instrumentation (WMI).

When Sent

The WMI kernel-mode component can send an IRP_MJ_SYSTEM_CONTROL request any time following a driver's successful registration as a supplier of WMI data. WMI IRPs typically are sent when a user-mode data consumer has requested WMI data.

Input Parameters

Depends on the value at MinorFunction in the current I/O stack location of the IRP. Every IRP_MJ_SYSTEM_CONTROL request specifies a minor function code that identifies the requested WMI action.

Output Parameters

Depends on the value at MinorFunction in the current I/O stack location of the IRP.

Operation

All drivers must support IRP_MJ_SYSTEM_CONTROL requests by supplying a DispatchSystemControl routine.

Drivers that support Windows Management Instrumentation (WMI) must handle IRP_MJ_SYSTEM_CONTROL requests by processing the minor function codes associated with this major function code. For information about the WMI minor function codes, see WMI IRPs.

Drivers that do not support WMI by registering as a WMI data provider must pass IRP_MJ_SYSTEM_CONTROL requests to the next lower driver.


IRP_MJ_WRITE

Every device driver that transfers data from the system to its device must handle write requests, as must any higher-level driver layered over such a device driver.

When Sent

Any time following the successful completion of a create request.

Possibly, a user-mode application or Win32 component with a handle for the file object representing the target device object has requested a data transfer to the device. Possibly, a higher-level driver has created and set up the write IRP.

Input Parameters

The driver's I/O stack location in the IRP indicates how many bytes to transfer at Parameters.Write.Length.

Some drivers use the value at Parameters.Write.Key to sort incoming write requests into a driver-determined order in the device queue or in a driver-managed internal queue of IRPs. Certain types of drivers also use the value at Parameters.Write.ByteOffset, which indicates the starting offset for the transfer operation.

Depending on whether the underlying device driver sets up the target device object's Flags with DO_BUFFERED_IO or with DO_DIRECT_IO, data is transferred from one of the following:

  • The buffer at Irp->AssociatedIrp.SystemBuffer, if the driver uses buffered I/O
  • The buffer described by the MDL at Irp->MdlAddress, if the underlying device driver uses direct I/O (DMA or PIO)

Output Parameters

None

Operation

On receipt of a write request, a higher-level driver sets up the I/O stack location in the IRP for the next-lower driver, or it creates and sets up additional IRPs for one or more lower drivers. It can set up its IoCompletion routine, which is optional for the input IRP but required for driver-created IRPs, by calling IoSetCompletionRoutine. Then, the driver passes the request on to the next-lower driver with IoCallDriver.

On receipt of a write request, a device driver transfers data from system memory to its device. The device driver sets the Information field of the I/O status block to the number of bytes transferred when it completes the IRP.


Device Type-specific I/O Requests

Device-specific sections of this DDK provide information about device type-specific I/O requests handled by the system-supplied drivers for the most common kinds of devices.

A new kernel-mode driver must handle the same set of I/O requests as a system-supplied driver if the new driver meets any of the following conditions:

  • The new driver replaces a system driver for the same type of device.
  • The new driver supports another device of a type already in the system.
  • The new driver is an intermediate (filter) driver, layered between two system-supplied drivers.

Such a new driver must handle every IRP_MJ_XXX request that the system-supplied drivers handle. In most cases, a new device driver should also handle the same set of IOCTL_XXX codes for IRP_MJ_DEVICE_CONTROL requests, even if the new driver must emulate the behavior of the corresponding system-supplied driver. Otherwise, the new driver might break user-mode applications that expect these kinds of requests to be honored.

For tips about the NTSTATUS values that drivers can set in the I/O status block of IRPs, in an error log packet, and as the return value for specific requests, see Logging Errors. These tips for selecting request-specific NTSTATUS values do not include STATUS_PENDING, which any driver can return for an IRP it has marked as pending (IoMarkIrpPending) and not yet completed. Use this information to decide on the appropriate status values to be returned by new drivers for similar types of devices, or as an aid in determining the appropriate status values to be returned by the driver for a new type of device.

For more information about various kinds of drivers and the requests that each is required to support, see the following:

Serial Devices and Drivers

System-Supplied Parallel Drivers

Storage Drivers

Windows Input Architecture

I/O Requests for USB Client Drivers

The IEEE 1394 Driver Stack

Access Attribute Memory of a PCMCIA Device

System Management Bus Driver Clients

For all other types of drivers, consult the documentation for the appropriate driver type.


Defining I/O Control Codes

All system-defined I/O control codes for IRP_MJ_DEVICE_CONTROL requests can be considered public, because they are exported to one or more user-mode protected subsystems that run on top of the NT executive. As public device I/O control codes, some are also assumed to be exported to user-mode applications native to a protected subsystem, particularly to Win32 applications.

For a new kind of device, the driver's designer can define a public set of I/O control codes for IRP_MJ_DEVICE_CONTROL requests. However, since such a set of codes should be generally useful to other drivers of similar devices in the future, public I/O control codes must have the approval of and must be built into the system by Microsoft Corporation.

For new devices or for common kinds of devices with special features, driver designers also can define a set of I/O control codes for IRP_MJ_INTERNAL_DEVICE_CONTROL requests. Such a set of internal I/O control codes can be used by paired kernel-mode drivers to control the underlying device.

For example, kernel-mode drivers designed to the class/port model might use such a set of internal I/O control codes to take advantage of the special features of a particular device or type of device. The system-defined SCSI class/port interface uses this technique to define a SCSI-specific set of requests that class drivers send down to the system SCSI port driver, which transforms them into OS-independent SCSI requests for HBA-specific miniport drivers.

When it is sent a device control request, a class driver sets up the next-lower port driver's I/O stack location for the IRP and passes the request on to the underlying device driver, like any other higher-level driver.

A class driver also can allocate IRPs for I/O control requests and send them to the underlying port driver as follows:

  1. Call IoBuildDeviceIoControlRequest to allocate an IRP with the major function code IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL.
  2. Set up the port driver's I/O stack location for the IRP with the IOCTL_XXX code and appropriate parameters.
  3. Call IoSetCompletionRoutine with the IRP, as necessary, so that the class driver can determine how the corresponding port driver handled a given request, reuse the IRP to send another request, or dispose of a driver-created IRP when the port driver completes a requested operation.
  4. Call IoCallDriver to pass the request on to the port driver.

To avoid synchronization problems and possible access violations, parameters for I/O control codes rarely include embedded pointers. With the exception of certain SCSI requests, the buffers at Irp->AssociatedIrp.SystemBuffer, at Irp->MdlAddress, and at Parameters.DeviceIoControl.Type3InputBuffer in a driver's I/O stack location do not contain pointers to other data buffers, nor do they contain structures with such pointers, for system-defined I/O control codes (public or internal).

Nevertheless, a pair of class/port drivers that define internal I/O control codes can pass an embedded pointer to driver-allocated memory from the higher-level driver to the lower-level driver. Such a pair of class/port drivers is responsible for ensuring that:

  • Only one driver at a time can access the data.
  • Private data buffers are accessible in an arbitrary thread context by the port driver.

Display drivers can call the GDI function EngDeviceIoControl to send privately defined, device-specific I/O control requests, as well as system-defined public I/O control requests, through the system video port driver down to the corresponding adapter-specific video miniport driver.

A user-mode VDD can call DeviceIoControl to send I/O control requests to a corresponding kernel-mode driver for an MS-DOS®-application-dedicated device.

The following figure illustrates the layout of I/O control codes.

I/O Control Code Layout

Designers of drivers for a new FILE_DEVICE_XXX type of device must set the Common flag at bit 31 in the private I/O control codes they define. Those who define a private set of I/O control codes for IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL requests also must set the Custom flag at bit 13 in the I/O control codes they define.

All system-defined I/O control codes have both these C flags cleared.

Driver writers can use the system-supplied macro CTL_CODE to set up new I/O control codes. To define an I/O control code, follow these guidelines for using CTL_CODE:

  • Choose a descriptive constant name of the form IOCTL_Device_Function, where Device indicates the type of device and Function indicates the operation.
  • Supply the following parameters to the CTL_CODE macro in the following order:
    1. DeviceType matches the value set in the DeviceType member of the driver's DEVICE_OBJECT structure. (see Specifying Device Types).
    2. FunctionCode is in the range 0x800 to 0xfff for private I/O control codes defined by customers of Microsoft. Values in the range 0x000 to 0x7ff are reserved by Microsoft for public I/O control codes. The CTL_CODE macro automatically sets the Custom flag at bit 13 for values in the range 0x800 to 0xfff.
    3. TransferType indicates how data is passed to the driver as one of the following system-defined constants:
    • METHOD_BUFFERED, if the driver transfers small amounts of data for the request

      With this method, IRPs containing the I/O control code will supply a pointer to the buffer into which or from which to transfer data at Irp->AssociatedIrp.SystemBuffer. Most I/O control codes for device and intermediate drivers use this TransferType value.

    • METHOD_IN_DIRECT, if the underlying device driver will read a large amount of data for the request using DMA or PIO and must transfer the data quickly

      With this method, IRPs containing the I/O control code will supply a pointer to an MDL, describing the output buffer at Irp->MdlAddress.

    • METHOD_OUT_DIRECT, if the underlying device driver will write a large amount of data to the device for the request using DMA or PIO and must transfer the data quickly

      With this method, IRPs containing the I/O control code will supply a pointer to an MDL, describing the data buffer, at Irp->MdlAddress.

    • METHOD_NEITHER, if the driver can be sent such a request only while it is running in the context of the thread that originates the I/O control request

      Only a highest-level kernel-mode driver is guaranteed to meet this condition, so this value is seldom used for the I/O control codes passed to device drivers. With this method, the highest-level driver must determine whether to set up buffered or direct access to user data on receipt of the request, possibly must lock down the user buffer, and must wrap its access to the user buffer in a structured exception handler. Otherwise, the originating user-mode caller might change the buffered data out from under the driver or the caller could be swapped out just as the driver is accessing the user buffer.

    4. RequiredAccess indicates the type of access that must be requested when the caller opens the file object representing the device (see IRP_MJ_CREATE). In other words, the I/O Manager will create IRPs and call the driver with a given I/O control code only if the caller has requested the necessary access rights for the driver to perform the requested operation. RequiredAccess can be one of the following system-defined constants:
    • FILE_ANY_ACCESS, if the driver can carry out the requested operation for any caller that has a handle for the file object representing the target device object
    • FILE_READ_DATA, if the driver can carry out the requested operation only for a caller with read access rights

      With this required access, the underlying device driver transfers data from the device to system memory.

    • FILE_WRITE_DATA, if the driver can carry out the requested operation only for a caller with write access rights

      With this required access, the underlying device driver transfers data from system memory to its device.

    • (FILE_READ_DATA | FILE_WRITE_DATA), if the caller must have both read and write access rights

      With this required access, the underlying device driver transfers data between system memory and the device

Most public I/O control requests sent to device drivers are assigned FILE_ANY_ACCESS as their RequiredAccess value, particularly those sent to drivers of exclusive devices and those that are buffered by the I/O Manager or a higher-level driver. Many internal I/O control requests for system-supplied drivers also specify this type of RequiredAccess.

However, for certain types of devices, the public I/O control codes require the caller to have read access rights, write access rights, or both.

For example, the definition of the public I/O control code IOCTL_DISK_SET_PARTITION_INFO shows that this I/O request can be sent to a disk driver and to all drivers layered above the disk driver only if the caller has both read and write access rights, as shown by the following definition:

#define IOCTL_DISK_SET_PARTITION_INFO\
   CTL_CODE(IOCTL_DISK_BASE, 0x008, METHOD_BUFFERED,\
         FILE_READ_DATA | FILE_WRITE_DATA)

Driver designers who want to define a set of public control codes must consult with Microsoft Corporation to have new codes added to the system header files. Private I/O control codes should be defined in the driver(s)' device-specific header files.


Plug and Play IRPs

This chapter describes the PnP IRPs that are sent to drivers. All PnP IRPs have the major function code IRP_MJ_PNP and a minor function code indicating the particular PnP request.

This chapter provides reference information for the individual IRPs. See Plug and Play for a description of the order in which the IRPs are sent, a discussion of how to handle IRPs in DispatchPnp routines, and a general discussion of PnP concepts and terminology.

For each IRP and each kind of driver, a driver is either required to handle the IRP, can optionally handle the IRP, or must not handle the IRP. Consult the table below to identify which IRPs your driver will handle and then consult the reference pages for information on the individual IRPs. The IRPs are listed in functional order in the table and in alphabetical order in the IRP reference pages.

If an IRP is marked "No" in the table for a particular driver, that driver must not handle the IRP. The driver must pass the IRP to the next driver in the device stack as described in the reference page for the IRP.

The PnP Manager sends these IRPs. PnP drivers can send some of these IRPs, but only those so noted in this chapter.

The following are the minor function codes for PnP IRPs, and the driver types that handle them:

PnP IRP Minor Function Code | Function or Filter Driver for Nonbus Device | Function Driver for Bus Device (for bus FDO) | Bus Driver or Bus Filter Driver (for child PDOs)
IRP_MN_START_DEVICE | Required | Required | Required
IRP_MN_QUERY_STOP_DEVICE | Required | Required | Required
IRP_MN_STOP_DEVICE | Required | Required | Required
IRP_MN_CANCEL_STOP_DEVICE | Required | Required | Required
IRP_MN_QUERY_REMOVE_DEVICE | Required | Required | Required
IRP_MN_REMOVE_DEVICE | Required | Required | Required
IRP_MN_CANCEL_REMOVE_DEVICE | Required | Required | Required
IRP_MN_SURPRISE_REMOVAL | Required | Required | Required
IRP_MN_QUERY_CAPABILITIES | Optional | Optional | Required
IRP_MN_QUERY_PNP_DEVICE_STATE | Optional | Optional | Optional
IRP_MN_FILTER_RESOURCE_REQUIREMENTS | Optional (1) | Optional (1) | No
IRP_MN_DEVICE_USAGE_NOTIFICATION | Required (1) | Required (1) | Required (1)
IRP_MN_QUERY_DEVICE_RELATIONS |  |  |
BusRelations | Optional (1) | Required | No (2)
EjectionRelations | No | No | Optional
RemovalRelations | Optional | Optional | No
TargetDeviceRelation | No | No | Required
IRP_MN_QUERY_RESOURCES | No | No | Required (1)
IRP_MN_QUERY_RESOURCE_REQUIREMENTS | No | No | Required (1)
IRP_MN_QUERY_ID |  |  |
BusQueryDeviceID | No | No | Required
BusQueryHardwareIDs | No | No | Optional
BusQueryCompatibleIDs | No | No | Optional
BusQueryInstanceID | No | No | Optional
IRP_MN_QUERY_DEVICE_TEXT | No | No | Required (1)
IRP_MN_QUERY_BUS_INFORMATION | No | No | Required (1)
IRP_MN_QUERY_INTERFACE | Optional | Optional | Required (1)
IRP_MN_READ_CONFIG | No | No | Required (1)
IRP_MN_WRITE_CONFIG | No | No | Required (1)
IRP_MN_EJECT | No | No | Required (1)
IRP_MN_SET_LOCK | No | No | Required (1)
(1) Required or Optional in certain situations. See the reference page for the IRP for more details. (2) Bus filter drivers might handle a query for BusRelations.


IRP_MN_CANCEL_REMOVE_DEVICE

All PnP drivers must handle this IRP.

When Sent

The PnP Manager sends this IRP to inform the drivers for a device that the device will not be removed.

The PnP Manager sends this IRP at IRQL PASSIVE_LEVEL in the context of a system thread.

Input

None

Output

None

I/O Status Block

A driver must set Irp->IoStatus.Status to STATUS_SUCCESS for this IRP. If a driver fails this IRP, the device is left in an inconsistent state.

Operation

This IRP must be handled first by the parent bus driver for a device and then by each higher driver in the device stack.

In response to this IRP, drivers return the device to the state it was in prior to receiving the IRP_MN_QUERY_REMOVE_DEVICE request.

If the device is already started when the driver receives this IRP, the driver simply sets status to success and passes the IRP to the next driver (or completes the IRP if the driver is a bus driver). For such a cancel-remove IRP, a function or filter driver need not set a completion routine. The device may not be in the remove-pending state, because, for example, the driver failed the previous IRP_MN_QUERY_REMOVE_DEVICE.

The PnP Manager calls any EventCategoryTargetDeviceChange notification callbacks with GUID_TARGET_DEVICE_REMOVE_CANCELLED after the IRP_MN_CANCEL_REMOVE_DEVICE request completes. Such callbacks were registered on the device by calling IoRegisterPlugPlayNotification. The PnP Manager also calls any user-mode components that registered for notification on the device by calling RegisterDeviceNotification.

If a file system is mounted on the device, it must undo any operations it did in response to the query-remove notification.

See Plug and Play for detailed information on handling remove IRPs and for the general rules for handling all Plug and Play IRPs.

Sending This IRP

Reserved for system use. Drivers must not send this IRP.

See Also

IoRegisterPlugPlayNotification, IRP_MN_QUERY_REMOVE_DEVICE


IRP_MN_CANCEL_STOP_DEVICE

All PnP drivers must handle this IRP.

When Sent

The PnP Manager sends this IRP, at some point after an IRP_MN_QUERY_STOP_DEVICE, to inform the drivers for a device that the device will not be disabled (Windows 98/Me only) or stopped for resource reconfiguration.

The PnP Manager sends this IRP at IRQL PASSIVE_LEVEL in the context of a system thread.

Input

None

Output

None

I/O Status Block

A driver must set Irp->IoStatus.Status to STATUS_SUCCESS for this IRP. If a driver fails this IRP, the device is left in an inconsistent state.

Operation

This IRP must be handled first by the parent bus driver for a device and then by each higher driver in the device stack.

In response to this IRP, drivers return the device to the started state. Drivers start any IRPs that were held while the device was in the stop-pending state.

If the device is already in an active state when the driver receives this IRP, a function or filter driver simply sets status to success and passes the IRP to the next driver. The parent bus driver completes the IRP. For such a cancel-stop IRP, a function or filter driver need not set a completion routine.

See Plug and Play for detailed information on handling stop IRPs and for the general rules for handling all Plug and Play IRPs.

Sending This IRP

Reserved for system use. Drivers must not send this IRP.

See Also

IRP_MN_QUERY_STOP_DEVICE


IRP_MN_DEVICE_USAGE_NOTIFICATION

System components send this IRP to ask the drivers for a device whether the device can support a special file. If all the drivers for the device succeed the IRP, the system creates the special file. The system also sends this IRP to inform drivers that a special file has been removed from the device. The special files can be a paging file, a crash dump file, or a hibernation file.

Function drivers must handle this IRP if their device can contain a paging file, dump file, or hibernation file. Filter drivers must handle this IRP if the function driver they are filtering handles the IRP. Bus drivers must handle this IRP for their adapter or controller (bus FDO) and for their child devices (child PDOs).

When Sent

The system sends this IRP when it is creating or deleting a paging file, dump file, or hibernation file. A driver can send this IRP to propagate device usage information to another device stack.

System components and drivers send this IRP at IRQL PASSIVE_LEVEL in an arbitrary thread context.

Input

The Parameters.UsageNotification.InPath member of the IO_STACK_LOCATION structure is a BOOLEAN. When this parameter is TRUE, the system is creating a paging, crash dump, or hibernation file on the device. When InPath is FALSE, such a file has been removed from the device.

Parameters.UsageNotification.Type is an enum indicating the kind of file. This parameter has one of the following values: DeviceUsageTypePaging, DeviceUsageTypeDumpFile, or DeviceUsageTypeHibernation.

Output

None

I/O Status Block

Drivers set Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status.

Drivers do not modify the Irp->IoStatus.Information field; it remains at zero as set by the component sending the IRP.

Operation

A driver handles this IRP on the IRP's way down the device stack and on the IRP's way back up the stack.

A driver responds to this IRP with a procedure like the following:

  • If Parameters.UsageNotification.InPath is TRUE, determine whether the device supports the special file.

    A driver should test for the specific Parameters.UsageNotification.Type(s) that the driver can support. Additional notification types might be added in the future.

    See further information below describing the actions required to support each notification type.

    If Parameters.UsageNotification.InPath is TRUE and the driver cannot support the special file on the device, the driver must complete the IRP with a failure status.

  • If the device supports the special file:
    1. Take appropriate actions to reflect that the device now contains, or no longer contains, a special file.

      A driver typically increments or decrements a counter. For example, if Parameters.UsageNotification.Type is DeviceUsageTypePaging and Parameters.UsageNotification.InPath is TRUE, increment a count of the number of paging files on the device. Certain driver dispatch routines must check the counter(s).

      A device that contains a special file should not be disabled. A driver can call IoInvalidateDeviceState, requesting the PnP Manager to re-query for the device's PnP device state information. In response to the resulting IRP_MN_QUERY_PNP_DEVICE_STATE IRP, the driver should set the PNP_DEVICE_NOT_DISABLEABLE flag.

      If InPath is FALSE, a driver sets the DO_POWER_PAGABLE bit in its device object for the device.

    2. Propagate the device usage information to any related devices that require the information.

      As part of its handling of an IRP_MN_DEVICE_USAGE_NOTIFICATION IRP, a driver might be required to pass the information to one or more other device stacks. Such a driver creates new IRP_MN_DEVICE_USAGE_NOTIFICATION IRP(s) and sends them to the appropriate device stack(s). The driver must wait for completion of any device-usage-notification IRP(s) it sends before the driver finishes processing the device-usage IRP it received.

      How to identify the related devices is device- and driver-specific. Typically, a driver sends the IRP to other drivers to which it would send I/O requests for the file. When a bus driver handles this request for a child device, it must send a usage notification IRP to the device stack for the device's parent.

      For example, when ftdisk is running a five-disk stripe set, it propagates paging, hibernate, and crash dump notifications to each of those five disks, since each of those devices can be required to handle paging, hibernate, or crash dump file operations.

    3. In a function or filter driver, set an IoCompletion routine.
    4. In a function or filter driver, set Irp->IoStatus.Status to STATUS_SUCCESS, set up the next stack location, and pass the IRP to the next lower driver with IoCallDriver. Do not complete the IRP.

      In a bus driver that is handling the IRP for a child PDO: set Irp->IoStatus.Status and complete the IRP (IoCompleteRequest).

    5. During IRP completion processing:

      If an IoCompletion routine detects that a lower driver has failed the IRP, the function or filter driver must undo any operations it performed in response to the IRP and propagate the error. If the function or filter driver propagated the usage information to any other device stacks, the driver must send another usage IRP to those stacks to notify them of the failure.

      If status is STATUS_SUCCESS and InPath is TRUE, clear the DO_POWER_PAGABLE bit.

See Plug and Play for the general rules for handling Plug and Play IRPs.

Supporting Paging, Crash Dump, and Hibernation Files on a Device

When any of a driver's special file counts is nonzero, the driver must support the presence of the special file(s) on its device (or a descendant device).

For a DeviceUsageTypePaging file created on its device, a driver must do the following:

  • Lock code in memory for its DispatchRead, DispatchWrite, DispatchDeviceControl, and DispatchPower routines.
  • Clear the DO_POWER_PAGABLE bit in its device object for the device (on the IRP's way up the device stack).
  • Fail IRP_MN_QUERY_STOP_DEVICE and IRP_MN_QUERY_REMOVE_DEVICE requests for the device.

For a DeviceUsageTypeDumpFile file on its device, a driver must do the following:

  • Lock code in memory for its DispatchRead, DispatchWrite, DispatchDeviceControl, and DispatchPower routines.
  • Do not take the device out of the D0 state.

    Do not register the device for idle detection (PoRegisterDeviceForIdleDetection). If the device is already registered, cancel the registration. If the driver performs its own idle detection for the device, suspend such detection.

  • Clear the DO_POWER_PAGABLE bit in its device object for the device (on the IRP's way up the device stack).
  • Fail IRP_MN_QUERY_STOP_DEVICE and IRP_MN_QUERY_REMOVE_DEVICE requests for the device.

For a DeviceUsageTypeHibernation file on its device, a driver must do the following:

  • Lock code in memory for its DispatchRead, DispatchWrite, DispatchDeviceControl, and DispatchPower routines.
  • Ensure the device is in the D0 state when the driver receives an S4 system power IRP indicating that the system is about to hibernate.
  • Do not power down the device in response to a D3 set-power IRP that is part of an S4 hibernate action. See System Power Actions for more information.

    Upon receipt of such a D3 set-power IRP, perform all tasks required to put the device in the D3 state except for powering off the device and notifying the Power Manager (PoSetPowerState). The device must retain power until the hibernation file has been written.

  • Clear the DO_POWER_PAGABLE bit in its device object for the device (on the IRP's way up the device stack).
  • Fail IRP_MN_QUERY_STOP_DEVICE and IRP_MN_QUERY_REMOVE_DEVICE requests for the device.

See Power Management for more information about device power states, power IRPs, and supporting power management in drivers.

Sending This IRP

A driver can send an IRP_MN_DEVICE_USAGE_INFORMATION IRP, but only to propagate device usage information to another device stack. A driver is never the initial source of device usage information.

See Also

IoAdjustPagingPathCount, IRP_MN_QUERY_REMOVE_DEVICE, IRP_MN_QUERY_STOP_DEVICE


IRP_MN_EJECT

Bus drivers typically handle this request for their child devices (child PDOs) that support device ejection. Function and filter drivers do not receive this request.

When Sent

The PnP Manager sends this IRP to direct the appropriate driver or drivers to eject the device from its slot.

The PnP Manager sends this IRP at IRQL PASSIVE_LEVEL in an arbitrary thread context.

Input

None

Output

None

I/O Status Block

A bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status.

On success, a bus driver sets Irp->IoStatus.Information to zero.

If a bus driver does not handle this IRP, it leaves Irp->IoStatus.Status as is and completes the IRP.

Operation

For the device to be ejected, the device must be in the D3 device power state (off) and must be unlocked (if the device supports locking).

Any driver that returns success for this IRP must wait until the device has been ejected before completing the IRP.

See Plug and Play for the general rules for handling Plug and Play IRPs.

Sending This IRP

Reserved for system use. Drivers must not send this IRP.

Instead, see the reference page for the IoRequestDeviceEject routine.

See Also

IoRequestDeviceEject


IRP_MN_FILTER_RESOURCE_REQUIREMENTS

The PnP Manager sends this IRP to a device stack so the function driver can adjust the resources required by the device, if appropriate.

The function driver typically handles this IRP.

The parent bus driver (and bus filter drivers) should not handle this request for a child PDO; instead, such a driver should report resource requirements in response to an IRP_MN_QUERY_RESOURCE_REQUIREMENTS request.

Upper and lower filter drivers do not handle this IRP.

When Sent

The PnP Manager sends this IRP when it is preparing to allocate resource(s) to a device.

The PnP Manager sends this IRP at IRQL PASSIVE_LEVEL in the context of an arbitrary thread.

Input

Irp->IoStatus.Information points to an IO_RESOURCE_REQUIREMENTS_LIST containing the hardware resource requirements for the device. The pointer is NULL if the device consumes no hardware resources.

Parameters.FilterResourceRequirements.IoResourceRequirementList also points to an IO_RESOURCE_REQUIREMENTS_LIST, but the function driver should use the list in the IoStatus block.

Output

Returned in the I/O status block.

I/O Status Block

If a function driver handles this IRP, it handles it on the IRP's way back up the stack. If the function driver handles the IRP successfully, it sets Irp->IoStatus.Status to STATUS_SUCCESS and sets Irp->IoStatus.Information to a pointer to an IO_RESOURCE_REQUIREMENTS_LIST containing the filtered resource requirements. See the Operation section below for further information on setting the filtered resource list. If a function driver encounters an error when handling this IRP, it sets the error in Irp->IoStatus.Status. If a function driver does not handle this IRP, it uses IoSkipCurrentIrpStackLocation to pass the IRP down the stack unchanged.

Upper and lower-filter drivers do not handle this IRP. Such a driver calls IoSkipCurrentIrpStackLocation, passes the IRP down to the next driver, must not modify Irp->IoStatus, and must not complete the IRP.

The parent bus driver does not handle this IRP. It leaves Irp->IoStatus as is and completes the IRP.

Operation

The PnP Manager sends an IRP_MN_QUERY_RESOURCE_REQUIREMENTS request to the parent bus driver for the device, before the function driver has attached its device object to the device stack. To give the function driver an opportunity to modify the device's resource requirements, if appropriate, the PnP Manager later sends an IRP_MN_FILTER_RESOURCE_REQUIREMENTS request to the full device stack. The PnP Manager sends this IRP before it allocates hardware resources to the device during initial device configuration. The PnP Manager might also send this IRP during resource rebalancing.

When the PnP Manager sends this IRP, it supplies the driver stack with a resource requirements list, which drivers can modify and return. The PnP Manager supplies one of the following types of resource requirements list (listed in order of priority):

  • Forced configuration (modified from a resource list to a resource requirements list)
  • Override configuration
  • Basic configuration
  • Boot configuration (modified from a resource list to a resource requirements list)

If a function driver handles this IRP, it must set a completion routine and handle the IRP on its way back up the device stack. See Plug and Play for information on handling a PnP IRP on its way back up the device stack.

If the function driver is not changing the size of the current list pointed to by Irp->IoStatus.Information, the driver can modify the list in place. If the driver needs to change the size of the requirements list, the driver must allocate a new IO_RESOURCE_REQUIREMENTS_LIST list from paged memory and free the previous list. The PnP Manager frees the returned structure when it is no longer needed.

A function driver must preserve the order of resources in the list pointed to by Irp->IoStatus.Information and must not alter resource tags that it does not handle. The driver must take care to adjust the requirements list in a way that the device's parent bus supports. If a function driver adds a new resource to the requirements list, and that resource is assigned to the device, the function driver should filter that resource out of the IRP_MN_START_DEVICE before passing the start IRP down to the bus driver.

If the function driver for the device does not handle this IRP, the PnP Manager uses the resource requirements as specified by the parent bus driver in response to the IRP_MN_QUERY_RESOURCE_REQUIREMENTS request.

A function driver must be prepared to handle this IRP for a device at any time after the driver's AddDevice routine has been called for the device.

See Plug and Play for the general rules for handling Plug and Play IRPs.

Sending This IRP

Reserved for system use. Drivers must not send this IRP.

See Also

ExAllocatePoolWithTag, ExFreePool, IO_RESOURCE_REQUIREMENTS_LIST, IRP_MN_START_DEVICE


IRP_MN_QUERY_BUS_INFORMATION

The PnP Manager uses this IRP to request the type and instance number of a device's parent bus.

Bus drivers should handle this request for their child devices (PDOs). Function and filter drivers do not handle this IRP.

When Sent

The PnP Manager sends this IRP when a device is enumerated.

The PnP Manager sends this IRP at IRQL PASSIVE_LEVEL in an arbitrary thread context.

Input

None

Output

Returned in the I/O status block.

I/O Status Block

A bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status.

On success, a bus driver sets Irp->IoStatus.Information to a pointer to a completed PNP_BUS_INFORMATION structure. (See the Operation section for more information.) On an error, the bus driver sets Irp->IoStatus.Information to zero.

Function and filter drivers do not handle this IRP.

Operation

The information returned in response to this IRP is available to the function and filter drivers for devices on the bus. Function and filter drivers can call IoGetDeviceProperty to request a DevicePropertyBusTypeGuid, DevicePropertyLegacyBusType, or DevicePropertyBusNumber. Function and filter drivers that support devices on more than one bus can use this information to determine on which bus a particular device resides.

If a bus driver returns information in response to this IRP, it allocates a PNP_BUS_INFORMATION structure from paged memory. The PnP Manager frees the structure when it is no longer needed.

A PNP_BUS_INFORMATION structure has the following format:

typedef struct _PNP_BUS_INFORMATION {
    GUID BusTypeGuid;
    INTERFACE_TYPE LegacyBusType;
    ULONG BusNumber;
} PNP_BUS_INFORMATION, *PPNP_BUS_INFORMATION;

The members of the structure are defined as follows:

BusTypeGuid
A bus driver sets BusTypeGuid to the GUID for the type of the bus on which the device resides. GUIDs for standard bus types are listed in wdmguid.h. Driver writers should generate GUIDs for other bus types using uuidgen.
LegacyBusType
A PnP bus driver sets LegacyBusType to the INTERFACE_TYPE of the parent bus. The interface types are defined in wdm.h. Some buses have a specific INTERFACE_TYPE value, such as PCMCIABus, PCIBus, or PNPISABus. For other buses, especially newer buses like USB, the bus driver sets this member to PNPBus.

The LegacyBusType specifies the interface used to communicate with the device. This may or may not correspond to the type of the parent bus. For example, the interface for a CardBus card that is plugged into a PCI CardBus controller is PCIBus. However, the interface for a PCMCIA card on a PCI CardBus controller is PCMCIABus.

BusNumber
A bus driver sets BusNumber to a number distinguishing the bus from other buses of the same type on the machine. The bus-numbering scheme is bus-specific. Bus numbers may be virtual, but must match any numbering used by legacy interfaces such as IoReportResourceUsage.

See Plug and Play for the general rules for handling Plug and Play IRPs.

Sending This IRP

Reserved for system use. Drivers must not send this IRP.

Call IoGetDeviceProperty to get information about the bus to which a device is attached.

See Also

IoGetDeviceProperty


IRP_MN_QUERY_CAPABILITIES

The PnP Manager sends this IRP to get the capabilities of a device, such as whether the device can be locked or ejected.

Function and filter drivers can handle this request if they alter the capabilities supported by the bus driver. Bus drivers must handle this request for their child devices.

When Sent

The PnP Manager sends this IRP to the bus driver for a device immediately after the device is enumerated. The PnP Manager sends this IRP again after all the drivers for a device have started the device. A driver can send this IRP to get the capabilities for a device.

The PnP Manager and drivers send this IRP at IRQL PASSIVE_LEVEL in an arbitrary thread context.

Input

The Parameters.DeviceCapabilities.Capabilities member of the IO_STACK_LOCATION structure points to a DEVICE_CAPABILITIES structure containing information about the capabilities of the device.

Output

Parameters.DeviceCapabilities.Capabilities points to the DEVICE_CAPABILITIES structure that reflects any modifications made by the drivers that handle the IRP.

I/O Status Block

A driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status such as STATUS_UNSUCCESSFUL.

If a function or filter driver does not handle this IRP, it calls IoSkipCurrentIrpStackLocation and passes the IRP down to the next driver. Such a driver must not modify Irp->IoStatus.Status and must not complete the IRP.

A bus driver sets Irp->IoStatus.Status and completes the IRP.

Operation

When a device is enumerated, but before the function and filter drivers are loaded for the device, the PnP Manager sends an IRP_MN_QUERY_CAPABILITIES request to the parent bus driver for the device. The bus driver must set any relevant values in the DEVICE_CAPABILITIES structure and return it to the PnP Manager.

After the device stack is built and drivers have started the device, the PnP Manager sends this IRP again to be handled first by the driver at the top of the device stack and then by each lower driver in the stack. Function and filter drivers can set an IoCompletion routine and handle this IRP on its way back up the device stack.

Drivers should add capabilities before they pass the IRP to the next lower driver.

Drivers should remove capabilities after all lower drivers have finished with the IRP. A driver does not typically remove capabilities that have been set by other drivers, but it might do so if it has special information about the capabilities of the device in a certain configuration. See Plug and Play for information on postponing IRP processing until lower drivers have finished.

After a device is enumerated and its drivers are loaded, its capabilities should not change. A device's capabilities might change if the device is removed and re-enumerated.

When handling an IRP_MN_QUERY_CAPABILITIES IRP, the driver that is the power policy manager for the device should set an IoCompletion routine and copy the device power capabilities, such as the S-to-D power state mappings, on the IRP's way back up the device stack. To determine the power capabilities of a child device, the parent bus driver creates another query-capabilities IRP and sends the IRP to its parent driver. See Reporting Device Power Capabilities for more information.

If a driver handles this IRP, it should check the DEVICE_CAPABILITIES Version value. If that value is not a version that the driver supports, the driver should fail the IRP. If the version is supported, the driver should check the Size field. A driver should set only those fields that are within the bounds of the capabilities structure that it received as input.

Drivers that handle this IRP can set some DEVICE_CAPABILITIES fields but must not set the Size and Version fields. These fields are only set by the component that sent the IRP.

See Plug and Play for the general rules for handling Plug and Play IRPs.

Sending This IRP

A bus driver sends this IRP to the parent device stack when it handles an IRP_MN_QUERY_CAPABILITIES request for one of its child devices. Also, a driver might send this IRP to get the device capabilities for one of its devices. A single driver in the stack has only part of the capabilities information for the device; sending an IRP to the device stack enables it to gather the full picture, including modifications by any filter drivers, and so forth.

See Handling IRPs for information on sending IRPs. The following steps apply specifically to this IRP:

  • Allocate a DEVICE_CAPABILITIES structure from paged pool, and initialize it to zeros by calling RtlZeroMemory. Initialize the Size to sizeof(DEVICE_CAPABILITIES), the Version to 1, and Address and UINumber to -1.
  • Set the values in the next I/O stack location of the IRP: set MajorFunction to IRP_MJ_PNP, set MinorFunction to IRP_MN_QUERY_CAPABILITIES, and set Parameters.DeviceCapabilities to a pointer to the allocated DEVICE_CAPABILITIES structure.
  • Initialize IoStatus.Status to STATUS_NOT_SUPPORTED.
  • Deallocate the IRP and the DEVICE_CAPABILITIES structure when they are no longer needed.

See Also

DEVICE_CAPABILITIES


IRP_MN_QUERY_DEVICE_RELATIONS

Bus drivers must handle this request for BusRelations for their adapter or controller (bus FDO). Filter drivers might handle this request for BusRelations. Bus drivers must handle this request for TargetDeviceRelation for their child devices (child PDOs). Function and filter drivers might handle this request for RemovalRelations. Bus drivers might handle this request for EjectionRelations for their child devices (child PDOs).

When Sent

The PnP Manager sends this IRP to gather information about devices with a relationship to the specified device.

The PnP Manager queries a device's BusRelations (child devices) when the device is enumerated and at other times while the device is active, such as when a driver calls IoInvalidateDeviceRelations to indicate that a child device has arrived or departed.

The PnP Manager queries a device's RemovalRelations before it removes a device's drivers or ejects the device and it queries for EjectionRelations before it ejects a device.

The PnP Manager queries a device's TargetDeviceRelation when a driver or user-mode application registers for PnP notification of an EventCategoryTargetDeviceChange on the device. The PnP Manager queries for the device that is associated with a particular file object. This is the only PnP IRP that has a valid file object parameter. A driver can query a device stack for TargetDeviceRelation.

The PnP Manager sends this IRP at IRQL PASSIVE_LEVEL in an arbitrary thread context.

Input

The Parameters.QueryDeviceRelations.Type member of the IO_STACK_LOCATION structure specifies the type of relations being queried. Possible values include BusRelations, EjectionRelations, RemovalRelations, and TargetDeviceRelation. PowerRelations is not used.

Irp->FileObject points to a valid file object only if Parameters.QueryDeviceRelations.Type is TargetDeviceRelation.

Output

Returned in the I/O status block.

I/O Status Block

A driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to a failure status such as STATUS_INSUFFICIENT_RESOURCES.

On success, a driver sets Irp->IoStatus.Information to a PDEVICE_RELATIONS pointer that points to the requested relations information. The DEVICE_RELATIONS structure is defined as follows:

typedef struct _DEVICE_RELATIONS {
    ULONG Count;
    PDEVICE_OBJECT Objects[1];  // variable length
} DEVICE_RELATIONS, *PDEVICE_RELATIONS;

Operation

If a driver returns relations in response to this IRP, it allocates a DEVICE_RELATIONS structure from paged memory containing a count and the appropriate number of device object pointers. The PnP Manager frees the structure when it is no longer needed. If a driver replaces a DEVICE_RELATIONS structure allocated by another driver, it must free the previous structure.

A driver must reference the PDO of any device that it reports in this IRP (ObReferenceObject). The PnP Manager removes the reference when appropriate.

A function or filter driver should be prepared to handle this IRP for a device any time after its AddDevice routine has completed for the device. Bus drivers should be prepared to handle a query for BusRelations immediately after a device is enumerated.

See Plug and Play for the general rules for handling Plug and Play IRPs.

The following subsections describe the specific actions for handling the various queries.

BusRelations

When the PnP Manager queries for the bus relations (child devices) of an adapter or controller, the bus driver must return a list of pointers to the PDOs of any devices physically present on the bus. The bus driver reports all devices, regardless of whether they have been started. The bus driver might need to power up its bus device to determine which children are present.

The bus driver that responds to this IRP is the function driver for the bus adapter or controller, not the parent bus driver for the bus that the adapter or controller is connected to. Function drivers for non-bus devices do not handle this query. Such drivers just pass the IRP to the next lower driver. (See the following figure.) Filter drivers typically do not handle this query.

Drivers Handling a Query For Bus Relations

In the example shown in the figure, the PnP Manager sends an IRP_MN_QUERY_DEVICE_RELATIONS for BusRelations to the drivers for the USB hub device. The PnP Manager is requesting a list of the hub device's children.

  1. As with all PnP IRPs, the PnP Manager sends the IRP to the top driver in the device stack for the device.
  2. An optional filter driver might be the top driver in the stack. A filter driver typically does not handle this IRP; it passes the IRP down the stack. A filter driver might handle this IRP, for example, if the driver exposes a non-enumerable device on the bus.
  3. The USB hub bus driver handles the IRP.

    The USB hub bus driver:

    • Creates a PDO for any child device that does not already have one.
    • Marks the PDO inactive for any device that is no longer present on the bus. The bus driver does not delete such PDOs. See Removing a Device for information on when to delete the PDOs.
    • Reports any child devices that are present on the bus.

      For each child device, the bus driver references the PDO and puts a pointer to the PDO in the DEVICE_RELATIONS structure.

      There are two PDOs in this example, one for the joystick device and one for the keyboard device.

      The bus driver should check whether another driver already created a DEVICE_RELATIONS structure for this IRP. If so, the bus driver must add to the existing information.

      If there is no child device present on the bus, the driver sets the count to zero in the DEVICE_RELATIONS structure and returns success.

    • Sets the appropriate values in the I/O status block and passes the IRP to the next lower driver. The bus driver for the adapter or controller does not complete the IRP.
  4. An optional lower filter, if present, typically does not handle this IRP. Such a filter driver passes the IRP down the stack. If a lower-filter driver handles this IRP, it can add PDO(s) to the list of child devices but it must not delete any PDOs created by other drivers.
  5. The parent bus driver does not handle this IRP, unless it is the only driver in the device stack (the device is in raw mode). As with all PnP IRPs, the parent bus driver completes the IRP with IoCompleteRequest.

    If there are one or more bus filter drivers in the device stack, such drivers might handle the IRP on its way down to the bus driver and/or on the IRP's way back up the device stack (if there are IoCompletion routines). According to the PnP IRP rules, such a driver can add PDOs to the IRP on its way down the stack and/or modify the relations list on the IRP's way back up the stack (in IoCompletion routines).

EjectionRelations

A driver returns pointers to PDOs of any devices that might be physically removed from the system when the specified device is ejected. Do not report the PDOs of children of the device; the PnP Manager always requests that child devices be removed before their parent device.

The PnP Manager sends an IRP_MN_EJECT IRP to a device being ejected. The driver for such a device also receive a remove IRP. The device's ejection relations receive an IRP_MN_REMOVE_DEVICE IRP (not an IRP_MN_EJECT IRP).

Only a parent bus driver can respond to an EjectionRelations query for one of its child devices. Function and filter drivers must pass it to the next lower driver in the device stack. If a bus driver receives this IRP as the function driver for its adapter or controller, the bus driver is performing the tasks of a function driver and must pass the IRP to the next lower driver.

PowerRelations

Reserved.

RemovalRelations

A driver returns pointers to PDOs of any devices whose drivers must be removed when the drivers for the specified device are removed. Do not report the PDOs of children of the device; the PnP Manager already requests removal of child devices before removing a device.

The order in which removal relations are removed is undefined. Removal relations at the same level in the device tree can be removed in any order.

Any driver in the device stack can handle this type of relations query. A function or filter driver handles the IRP before passing it to the next lower driver. A bus driver handles the IRP and then completes it.

TargetDeviceRelation

A parent bus driver must handle this type of relations query for its child devices. The bus driver references the child device's PDO with ObReferenceObject and returns a pointer to the PDO in the DEVICE_RELATIONS structure. There is only one PDO pointer in the structure for this relation type. The PnP Manager removes the reference to the PDO when the driver or application unregisters for notification on the device.

Only a parent bus driver responds to a TargetDeviceRelation query. Function and filter drivers must pass it to the next lower driver in the device stack. If a bus driver receives this IRP as the function driver for its adapter or controller, the bus driver is performing the tasks of a function driver and must pass the IRP to the next lower driver.

If a driver is not in a PDO-based stack, the driver sends a new target-device-relation query IRP to the device object associated with the file handle on which the driver performs I/O.

Sending This IRP

Drivers must not send this IRP to request BusRelations. Drivers are not restricted from sending this IRP for RemovalRelations or EjectionRelations, but it is not likely that a driver would do so.

Drivers can query a device stack for TargetDeviceRelation. See Handling IRPs for information on sending IRPs. The following steps apply specifically to this IRP:

  • Set the values in the next I/O stack location of the IRP: set MajorFunction to IRP_MJ_PNP, set MinorFunction to IRP_MN_QUERY_DEVICE_RELATIONS, set Parameters.QueryDeviceRelations.Type to TargetDeviceRelation, and set Irp->FileObject to a valid file object.
  • Initialize IoStatus.Status to STATUS_NOT_SUPPORTED.

If a driver sent this IRP to get the PDO to report in response to an IRP_MN_QUERY_DEVICE_RELATIONS for TargetDeviceRelation that the driver received, then the driver reports the PDO and frees the returned relations structure when the IRP completes. If a driver initiated this IRP for another reason, the driver frees the relations structure when the IRP completes and dereferences the PDO when it is no longer needed.

See Also

IoInvalidateDeviceRelations, IRP_MN_EJECT, IRP_MN_REMOVE_DEVICE, IoRegisterPlugPlayNotification, ObReferenceObject


IRP_MN_QUERY_DEVICE_TEXT

The PnP Manager uses this IRP to get a device's description or location information.

Bus drivers must handle this request for their child devices if the bus supports this information. Function and filter drivers do not handle this IRP.

When Sent

The PnP Manager sends two of these IRPs when a device is enumerated: one to query the device description and one to query the location information.

The PnP Manager sends this IRP at IRQL PASSIVE_LEVEL in an arbitrary thread context.

Input

The Parameters.QueryDeviceText.DeviceTextType member of the IO_STACK_LOCATION structure is a DEVICE_TEXT_TYPE value specifying which string is requested. Possible values for DEVICE_TEXT_TYPE include DeviceTextDescription and DeviceTextLocationInformation.

Parameters.QueryDeviceText.LocaleId is an LCID specifying the locale for the requested text.

Output

Returned in the I/O status block.

I/O Status Block

A driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status.

On success, a bus driver sets Irp->IoStatus.Information to a pointer to a driver-allocated block of memory containing a WCHAR buffer with the requested information. On an error, the bus driver sets Irp->IoStatus.Information to zero.

Operation

Bus drivers are strongly encouraged to return device descriptions for their child devices. This string is displayed in the "found new hardware" pop-up window if no INF match is found for the device.

Bus drivers are also encouraged to return LocationInformation for their child devices, but this information is optional. The format of this string depends on the bus. The Device Manager displays this string in the general properties tab for the device. Vendors should choose a string that conveys useful information to users and support personnel. For example, for PCI, the string contains the bus, device, and function. For PC Card, the string contains the slot.

If a bus driver returns information in response to this IRP, it allocates a NULL-terminated Unicode string from paged memory. The PnP Manager frees the string when it is no longer needed.

If a device does not provide description or location information, the device's parent bus driver completes the IRP (IoCompleteRequest) without modifying Irp->IoStatus.Status or Irp->IoStatus.Information.

Function and filter drivers do not handle this IRP; they pass it to the next lower driver with no changes to Irp->IoStatus.

Drivers for buses that support different text strings for different locales should be able to handle a request for a language that is not explicitly supported by the device. In such a situation, the bus driver should return the closest match for the locale or should fallback and return some appropriate supported locale string.

See Plug and Play for the general rules for handling Plug and Play IRPs.

Sending This IRP

Reserved for system use. Drivers must not send this IRP.


IRP_MN_QUERY_ID

Bus drivers must handle requests for BusQueryDeviceID for their child devices (child PDOs). Bus drivers can handle requests for BusQueryHardwareIDs, BusQueryCompatibleIDs, and BusQueryInstanceID for their child devices. Function and filter drivers do not handle this IRP.

When Sent

The PnP Manager sends this IRP when a device is enumerated. A driver might send this IRP to retrieve the instance ID for one of its devices.

The PnP Manager and drivers send this IRP at IRQL PASSIVE_LEVEL in an arbitrary thread context.

Input

The Parameters.QueryId.IdType member of the IO_STACK_LOCATION structure specifies the kind of ID(s) requested. Possible values include BusQueryDeviceID, BusQueryHardwareIDs, BusQueryComptibleIDs, and BusQueryInstanceID. The following ID type is reserved: BusQueryDeviceSerialNumber.

Output

Returned in the I/O status block.

I/O Status Block

A driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status.

On success, a driver sets Irp->IoStatus.Information to a WCHAR pointer that points to the requested information. On error, a driver sets Irp->IoStatus.Information to zero.

Operation

If a driver returns ID(s) in response to this IRP, it allocates a WCHAR structure from paged pool to contain the ID(s). The PnP Manager frees the structure when it is no longer needed.

A driver returns a single string in response to a BusQueryDeviceID or a BusQueryInstanceID request, and a MULTI_SZ string in response to a BusQueryHardwareIDs or a BusQueryComptibleIDs request.

If a driver returns an ID with an illegal character, the system will bugcheck. Characters with the following values are illegal in an ID for this IRP:

Less than 0x20 (' ')
Greater than 0x7F
Equal to 0x2C (',')

A driver must conform to the following length restrictions for IDs:

  • Each hardware ID or compatible ID that a driver returns in this IRP must be less than MAX_DEVICE_ID_LEN characters long. This constant currently has a value of 200 as defined in sdk\inc\cfgmgr32.h.
  • If a bus driver supplies globally unique instance IDs for its child devices (that is, the driver sets DEVICE_CAPABILITIES.UniqueID for the devices), then the combination of device ID plus instance ID must be less than (MAX_DEVICE_ID_LEN - 1) characters. The OS requires the additional character for a path separator.
  • If a bus driver does not supply globally unique instance IDs for its child devices, then the combination of device ID plus instance ID must be less than (MAX_DEVICE_ID_LEN - 28). The value of this equation is currently 172.

Bus drivers should be prepared to handle this IRP for a child device immediately after the device is enumerated.

Specifying BusQueryDeviceID and BusQueryInstanceID

The values a bus driver supplies for BusQueryDeviceID and BusQueryInstanceID allow the OS to differentiate a device from other devices on the machine. The OS uses the device ID, instance ID, and the unique ID field returned in the IRP_MN_QUERY_DEVICE_CAPABILITIES IRP to locate registry information for device.

For BusQueryDeviceID, a bus driver supplies the device's device ID. A device ID should contain the most-specific description of the device possible, incorporating the name of the enumerator and strings identifying the manufacturer, device, revision, packager, and packaged product, where possible. For example, the PCI bus driver responds with device IDs of the form PCI\VEN_xxxx&DEV_xxxx&SUBSYS_xxxxxxxx&REV_xx, encoding all five of the items mentioned above. However, a device ID should not contain enough information to differentiate between two identical devices. This information should be encoded in the instance ID.

For BusQueryInstanceID, a bus driver should supply a string that contains the instance ID for the device. Setup and bus drivers use the instance ID, with other information, to differentiate between two identical devices on the machine. The instance ID is either unique across the whole machine or just unique on the device's parent bus.

If an instance ID is only unique on the bus, the bus driver specifies that string for BusQueryInstanceID but also specifies a UniqueID value of FALSE in response to an IRP_MN_QUERY_CAPABILITIES request for the device. If UniqueID is FALSE, the PnP Manager enhances the instance ID by adding information about the device's parent and thus makes the ID unique on the machine. In this case the bus driver should not take extra steps to make its devices' instance IDs globally unique; just return the appropriate capabilities information and the OS takes care of it.

If a bus driver can supply a globally unique ID for each child device, such as a serial number, the bus driver specifies those strings for BusQueryInstanceID and specifies a UniqueID value of TRUE in response to an IRP_MN_QUERY_CAPABILITIES request for each device.

Specifying BusQueryHardwareIDs and BusQueryCompatibleIDs

The values a bus driver supplies for BusQueryHardwareIDs and BusQueryCompatibleIDs allow Setup to locate the appropriate drivers for the bus's child device.

A bus driver responds to each of these requests with a list of IDs that describe the device. When returning more than one hardware ID and/or more than one compatible ID, a bus driver should list the IDs in the order of most-specific to most-general to facilitate choosing the best driver match for the device. The first entry in the hardware IDs list is the most-specific description of the device and, as such, it is usually identical to the device ID.

Setup checks the IDs against the IDs listed in INF files for possible matches. Setup first scans the hardware IDs list, then the compatible IDs list. Earlier entries are treated as more specific descriptions of the device, and later entries as more general (and thus less optimal) matches for the device. If no match is found in the list of hardware IDs, Setup might prompt the user for installation media before moving on to the list of compatible IDs.

See Plug and Play for the general rules for handling Plug and Play IRPs.

Sending This IRP

Typically, only the PnP Manager sends this IRP.

To get the hardware IDs or compatible IDs for a device, call IoGetDeviceProperty instead of sending this IRP.

A driver might send this IRP to retrieve the instance ID for one of its devices. For example, consider a multifunction PnP ISA device whose functions do not operate independently. The PnP Manager enumerates the functions as separate devices, but the driver for such a device might be required to associate one or more of the functions. Because PnP ISA guarantees a unique instance ID, the driver for such a multifunction device can use the instance IDs to locate functions that reside on the same device. The driver for such a device must also get the device's enumerator name by calling IoGetDeviceProperty, to confirm that the device is a PnP ISA device.

See Handling IRPs for information on sending IRPs. The following steps apply specifically to this IRP:

  • Set the values in the next I/O stack location of the IRP: set MajorFunction to IRP_MJ_PNP, set MinorFunction to IRP_MN_QUERY_ID, and set Parameters.QueryId.IdType to BusQueryInstanceID.
  • Set IoStatus.Status to STATUS_NOT_SUPPORTED.

In addition to sending the query ID IRP, the driver must call IoGetDeviceProperty to get the DevicePropertyEnumeratorName for the device.

After the IRP completes and the driver is finished with the ID, the driver must free the ID structure returned by the driver(s) that handled the query IRP.

See Also

IoGetDeviceProperty


IRP_MN_QUERY_INTERFACE

The IRP_MN_QUERY_INTERFACE request enables a driver to export a direct-call interface to other drivers.

A bus driver that exports an interface must handle this request for its child devices (child PDOs). Function and filter can optionally handle this request.

An "interface" in this context consists of one or more routines, and possibly data, exported by a driver or set of drivers. An interface has a structure that describes its contents and a GUID that identifies its type.

For example, the PCMCIA bus driver exports an interface of type GUID_PCMCIA_INTERFACE_STANDARD that contains routines for operations such as getting the write-protect condition of a PCMCIA memory card. The function driver for such a memory card can send an IRP_MN_QUERY_INTERFACE request to the parent PCMCIA bus driver to get pointers to the PCMCIA interface routines.

This section describes the query-interface IRP as a general mechanism. Drivers that expose an interface should provide additional information about their specific interface.

When Sent

A driver or system component sends this IRP to get information about an interface exported by a driver for a device.

A driver or system component sends this IRP at IRQL PASSIVE_LEVEL in an arbitrary thread context.

A driver can receive this IRP at any time after the driver's AddDevice routine has been called for the device. The device may or may not be started when this IRP is sent (the driver cannot assume that it has successfully completed an IRP_MN_START_DEVICE request for the device).

Input

The Parameters.QueryInterface member of the IO_STACK_LOCATION structure is itself a structure, which describes the interface being requested. The structure contains the following information:

CONST GUID *InterfaceType;
USHORT Size;
USHORT Version;
PINTERFACE Interface;
PVOID InterfaceSpecificData

The members of the structure are defined as follows:

InterfaceType
Points to a GUID that identifies the interface being requested. The GUID can be for a system-defined interface, such as GUID_BUS_INTERFACE_STANDARD, or a custom interface. The GUIDs for system-defined interfaces are listed in wdmguid.h. GUIDs for custom interfaces should be generated with uuidgen.
Size
Specifies the size of the interface being requested. Drivers that handle this IRP must not return an INTERFACE structure larger than Size bytes.
Version
Specifies the version of the interface being requested.

If a driver supports more than one version of an interface, the driver returns the closest supported version without exceeding the requested version. The component that sent the IRP should examine the returned Interface.Version field and determine what to do based on that value.

Interface
Points to a structure in which to return the requested interface. This structure must contain an INTERFACE structure as its first member. The component sending the IRP allocates this structure from paged memory.

A driver that exports an interface defines a new structure type containing the INTERFACE structure, plus members for routines and/or data in the interface. (The driver also defines a GUID for the interface, as described in the InterfaceType member, above.)

A driver that exports an interface defines the execution environment for each routine in the interface, including the IRQL at which the routine can be called, and so forth.

InterfaceSpecificData
Specifies additional information about the interface being requested.

For some interfaces, the component sending the IRP specifies additional information in this field. Typically, this field is NULL and the InterfaceType and Version are sufficient to identify the interface being requested.

Output

On success, a driver fills in the members of the Parameters.QueryInterface.Interface structure.

I/O Status Block

A driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status.

On success, a bus driver sets Irp->IoStatus.Information to zero.

If a function or filter driver does not handle this IRP, it calls IoSkipCurrentIrpStackLocation and passes the IRP down to the next driver. Such a driver must not modify Irp->IoStatus.Status and must not complete the IRP.

If a bus driver does not export the requested interface and therefore does not handle this IRP for a child PDO, the bus driver leaves Irp->IoStatus.Status as is and completes the IRP.

Operation

A driver handles this IRP if the parameters specify an interface the driver supports.

A driver must not queue this IRP if the IRP requests an interface that the driver does not support. A driver must check Parameters.QueryInterface.InterfaceType in its IO_STACK_LOCATION structure. If the interface is not one the driver supports, the driver must pass the IRP to the next lower driver in the device stack without blocking.

Each interface must provide InterfaceReference and InterfaceDeference routines, and the driver that exports the interface must supply the addresses of these routines in the INTERFACE structure. Before a driver returns an interface in response to the IRP, it must increment the interface's reference count by calling its InterfaceReference routine. When the driver that requested the interface has finished using it, that driver must decrement the reference count by calling the interface's InterfaceDereference routine.

If the driver that sends the IRP (driver x) later passes the interface to another driver (driver y) then driver x must increment the interface's reference count and driver y must decrement it.

A driver that handles this IRP should avoid passing the IRP to another device stack to get the requested interface. Such a design would create dependencies between the device stacks that are difficult to manage. For example, the device represented by the second device stack cannot be removed until the appropriate driver in the first stack dereferences the interface.

Interfaces can be bus-specific or bus-independent. Bus-specific interfaces are defined in the header files for those buses. The system defines a bus-independent interface, BUS_INTERFACE_STANDARD, for exporting standard bus interfaces.

See Plug and Play for the general rules for handling Plug and Play IRPs.

This IRP is used specifically to communicate routine entry points between layered drivers for a device. A device interface is a separate mechanism, primarily for exposing a path to a device for use by user-mode components or other kernel components. Call IoGetDeviceInterfaces to get a list of device interfaces of a particular device interface class, such as all the devices on the system that support a HID interface.

Sending This IRP

See Handling IRPs for information on sending IRPs. The following steps apply specifically to this IRP:

  • Allocate an INTERFACE structure from paged pool and initialize it to zeros.
  • Set the values in the next I/O stack location of the IRP: set MajorFunction to IRP_MJ_PNP, set MinorFunction to IRP_MN_QUERY_INTERFACE, and set the appropriate values in Parameters.QueryInterface.
  • Initialize IoStatus.Status to STATUS_NOT_SUPPORTED.
  • Deallocate the IRP and the INTERFACE structure when they are no longer needed.
  • Use the interface routines and context parameter as described in the specification for the interface.
  • Decrement the reference count using the InterfaceDereference routine when the interface is no longer needed. Do not call any interface routines after dereferencing the interface.

A driver typically sends this IRP to the top of the device stack in which the driver is attached. If a driver sends this IRP to a different device stack, the driver must register for target device notification on the other device if the other device is not an ancestor of the device that the driver is servicing. Such a driver calls IoRegisterPlugPlayNotification with an EventCategory of EventCategoryTargetDeviceChange. When the driver receives notification of type GUID_TARGET_DEVICE_QUERY_REMOVE, the driver must dereference the interface. The driver can requery for the interface if it receives a subsequent GUID_TARGET_DEVICE_REMOVE_CANCELLED notification.

See Also

IoGetDeviceInterfaces, IoRegisterPlugPlayNotification


IRP_MN_QUERY_LEGACY_BUS_INFORMATION

This IRP is reserved for system use.


IRP_MN_QUERY_PNP_DEVICE_STATE

Function, filter, and bus drivers can handle this request.

When Sent

The PnP Manager sends this IRP after the drivers for a device return success from the IRP_MN_START_DEVICE request sent when a device is first started. This IRP is not sent on a start after a stop for resource rebalancing. The PnP Manager also sends this IRP when a driver for the device calls IoInvalidateDeviceState.

The PnP Manager sends this IRP at IRQL PASSIVE_LEVEL in the context of an arbitrary thread.

Input

None

Output

Returned in I/O status block.

I/O Status Block

A driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status such as STATUS_UNSUCCESSFUL.

On success, a driver sets Irp->IoStatus.Information to a PNP_DEVICE_STATE bitmask.

If a function or filter driver does not handle this IRP, it calls IoSkipCurrentIrpStackLocation, does not set an IoCompletion routine, and passes the IRP down to the next driver. Such a driver must not modify Irp->IoStatus and must not complete the IRP.

If a bus driver does not handle this IRP, it leaves Irp->IoStatus.Status as is and completes the IRP.

Operation

This IRP is handled first by the driver at the top of the device stack and then by each next lower driver in the stack.

A driver handles this IRP if it has information about the PnP state of a device. A driver can set or clear the flags in the PNP_DEVICE_STATE bitmask. If another driver has set a PNP_DEVICE_STATE in Irp->IoStatus.Information, a driver must take care to modify the flags in that bitmask rather than overwrite the whole structure.

See Plug and Play for the general rules for handling Plug and Play IRPs.

Sending This IRP

Reserved for system use. Drivers must not send this IRP.

See Also

IoInvalidateDeviceState, PNP_DEVICE_STATE


IRP_MN_QUERY_REMOVE_DEVICE

All PnP drivers must handle this IRP.

When Sent

The PnP Manager sends this IRP to inform drivers that a device is about to be removed from the machine and to query whether the device can be removed without disrupting the machine. The PnP Manager also sends this IRP if a user requests to update driver(s) for the device.

The PnP Manager sends this IRP at IRQL PASSIVE_LEVEL in the context of a system thread.

Input

None

Output

None

I/O Status Block

A driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status such as STATUS_UNSUCCESSFUL.

Operation

This IRP is handled first by the driver at the top of the device stack and then passed down to each lower driver in the stack.

In response to this IRP, drivers indicate whether the device can be removed without disrupting the machine.

See Plug and Play detailed information on handling remove IRPs and for general rules for handling all Plug and Play IRPs.

Sending This IRP

Reserved for system use. Drivers must not send this IRP.

See Also

IRP_MN_CANCEL_REMOVE_DEVICE, IRP_MN_DEVICE_USAGE_NOTIFICATION, IRP_MN_REMOVE_DEVICE


IRP_MN_QUERY_RESOURCE_REQUIREMENTS

The PnP Manager uses this IRP to get a device's resource requirements list.

Bus drivers must handle this request for their child devices that require hardware resources. Bus filter drivers can handle this request. Function and filter drivers do not handle this IRP.

When Sent

The PnP Manager sends this IRP when a device is enumerated, prior to allocating resources to a device, and when a driver reports that its device's resource requirements have changed.

The PnP Manager sends this IRP at IRQL PASSIVE_LEVEL in an arbitrary thread context.

Input

None

Output

Returned in the I/O status block.

I/O Status Block

A driver that handles this IRP sets Irp->IoStatus.Status to STATUS_SUCCESS or an appropriate error status.

On success, a driver sets Irp->IoStatus.Information to a pointer to an IO_RESOURCE_REQUIREMENTS_LIST that contains the requested information. On an error, the driver sets Irp->IoStatus.Information to zero.

Operation

If a bus driver returns a resource requirements list in response to this IRP, it allocates an IO_RESOURCE_REQUIREMENTS_LIST from paged memory. The PnP Manager frees the buffer when it is no longer needed.

If a device requires no hardware resources, the device's bus driver completes the IRP (IoCompleteRequest) without modifying Irp->IoStatus.Status or Irp->IoStatus.Information.

If a bus filter driver handles this IRP, it modifies the resource requirements list created by the bus driver. A bus filter driver modifies the list on the IRP's way back up the device stack. A bus filter driver must preserve the order of resources in the resource requirements list and must not alter resource tags that it does not handle. If a bus filter driver changes the size of the resource requirements list, the driver must allocate a new structure from paged memory and free the previous structure. If a bus filter driver adds a new resource requirement to the list and the resource is assigned to the device, the driver must filter the new resource out of the IRP_MN_START_DEVICE IRP so it is not passed to the bus driver.

Function and non-bus filter drivers do not handle this IRP; they pass it to the next lower driver with no changes to Irp->IoStatus.

See Plug and Play for the general rules for handling Plug and Play IRPs.

Sending This IRP

Reserved for system use. Drivers must not send this IRP.

See Also

IO_RESOURCE_REQUIREMENTS_LIST


IRP_MN_QUERY_RESOURCES

The PnP Manager uses this IRP to get a device's boot configuration resources.

Bus drivers must handle this request for their child devices that require hardware resources. Function and filter drivers do not handle this IRP.

When Sent

The PnP Manager sends this IRP when a device is enumerated.

The PnP Manager sends this IRP at IRQL PASSIVE_LEVEL in an arbitrary thread context.

Input

None

Output

Returned in the I/O status block.

I/O Status Block

A bus driver that handles this IRP sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status.

On success, a bus driver sets Irp->IoStatus.Information to a pointer to a CM_RESOURCE_LIST that contains the requested information. On an error, the bus driver sets Irp->IoStatus.Information to zero.

Operation

If a bus driver returns a resource list in response to this IRP, it allocates a CM_RESOURCE_LIST from paged memory. The PnP Manager frees the buffer when it is no longer needed.

If a device requires no hardware resources, the device's parent bus driver completes the IRP (IoCompleteRequest) without modifying Irp->IoStatus.Status or Irp->IoStatus.Information.

Function and filter drivers do not receive this IRP.

See Plug and Play for the general rules for handling Plug and Play IRPs.

Sending This IRP

Reserved for system use. Drivers must not send this IRP.

Drivers can call IoGetDeviceProperty to get the boot configuration for a device, in both raw and translated forms.

See Also

CM_RESOURCE_LIST, IoGetDeviceProperty


IRP_MN_QUERY_STOP_DEVICE

All PnP drivers must handle this IRP.

When Sent

The PnP Manager sends this IRP to query whether a device can be stopped to rebalance resources.

On Windows 98/Me, the PnP Manager also sends this IRP when a device is being disabled.

The PnP Manager sends this IRP at IRQL PASSIVE_LEVEL in the context of a system thread.

Input

None

Output

None

I/O Status Block

A driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status. If a driver cannot stop the device, the driver sets Irp->IoStatus.Status to STATUS_UNSUCCESSFUL.

A bus driver can set Irp->IoStatus.Status to STATUS_RESOURCE_REQUIREMENTS_CHANGED to indicate success for the IRP but also to request that the PnP Manager requery the resource requirements for the device before sending the stop IRP.

Operation

This IRP is handled first by the driver at the top of the device stack and then passed down to each lower driver in the stack.

In response to this IRP, Windows 2000 and later drivers indicate whether it is safe to stop the device for resource rebalancing.

On Windows 98/Me, this IRP is sent not only during resource rebalancing, but also when a device is being disabled. Because a driver cannot distinguish these two situations, it should proceed as if the device were being disabled. If there are any open handles to the device, the driver should fail this IRP. If no handles are open, the driver should proceed as described in Handling an IRP_MN_QUERY_STOP_DEVICE Request (Windows 98/Me).

See Plug and Play for detailed information on handling stop IRPs and for general rules for handling all Plug and Play IRPs.

Sending This IRP

Reserved for system use. Drivers must not send this IRP.

See Also

IRP_MN_CANCEL_STOP_DEVICE, IRP_MN_DEVICE_USAGE_NOTIFICATION, IRP_MN_START_DEVICE, IRP_MN_STOP_DEVICE


IRP_MN_READ_CONFIG

Bus drivers for buses with configuration space must handle this request for their child devices (child PDOs). Filter and function drivers do not handle this request.

When Sent

A driver or other system component sends this IRP to read the configuration space of a device's parent bus.

A driver or other system component sends this IRP at IRQL < DISPATCH_LEVEL in an arbitrary thread context.

Input

The Parameters.ReadWriteConfig member of the IO_STACK_LOCATION structure is itself a structure containing the following information:

ULONG WhichSpace;
PVOID Buffer;
ULONG Offset;
ULONG Length

The members of the structure can be interpreted differently by different bus drivers, but the members are typically defined as follows:

WhichSpace
Specifies the configuration space.
Buffer
Points to a buffer in which to return the requested information. The component sending the IRP allocates this structure from paged memory. The format of the buffer is bus-specific.
Offset
Specifies an offset into the configuration space.
Length
Specifies the number of bytes to read.

Output

On success, a bus driver fills the buffer at Parameters.ReadWriteConfig.Buffer with the requested data.

I/O Status Block

A bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status such as STATUS_INVALID_PARAMETER_n, STATUS_NO_SUCH_DEVICE, or STATUS_DEVICE_NOT_READY.

On success, a bus driver sets Irp->IoStatus.Information to the number of bytes returned.

If a bus driver is unable to complete this request immediately it can mark the IRP pending, return STATUS_PENDING, and complete the IRP at a later time.

Operation

A bus driver handles this IRP for its child devices (child PDOs).

Function and filter drivers do not handle this IRP; they pass it to the next lower driver with no changes to Irp->IoStatus.Status and do not set an IoCompletion routine.

A bus driver that handles this request should check the WhichSpace parameter to ensure that it contains a value that the driver supports.

See Plug and Play for the general rules for handling Plug and Play IRPs.

Sending This IRP

Typically, a function driver sends this IRP to the top driver in the device stack to which it is attached and the IRP is handled by the parent bus driver.

See Handling IRPs for information on sending IRPs. The following steps apply specifically to this IRP:

  • Allocate a buffer from paged pool and initialize it to zeros.
  • Set the values in the next I/O stack location of the IRP: set MajorFunction to IRP_MJ_PNP, set MinorFunction to IRP_MN_READ_CONFIG, and set the appropriate values in Parameters.ReadWriteConfig.
  • Initialize IoStatus.Status to STATUS_NOT_SUPPORTED.
  • Deallocate the IRP and the buffer when they are no longer needed.

Drivers must send this IRP from IRQL < DISPATCH_LEVEL.

A driver can access a bus's configuration space at DISPATCH_LEVEL through a bus interface routine, if the parent bus driver supports such an interface. To get a bus interface, a driver sends an IRP_MN_QUERY_INTERFACE request to the device stack in which the driver is attached. The driver then calls the appropriate routine returned in the interface.

For example, to read configuration space from DISPATCH_LEVEL a driver can call IRP_MN_QUERY_INTERFACE during driver initialization to get the BUS_INTERFACE_STANDARD interface from the parent bus driver. The driver sends the query IRP from IRQL PASSIVE_LEVEL. Later, from code at IRQL DISPATCH_LEVEL, the driver calls the appropriate routine returned in the interface, such as the Interface.GetBusData routine.

See Also

IRP_MN_QUERY_INTERFACE, IRP_MN_WRITE_CONFIG


IRP_MN_REMOVE_DEVICE

All PnP drivers must handle this IRP.

When Sent

The PnP Manager uses this IRP to direct drivers to remove a device's software representation (device objects, and so forth). The PnP Manager sends this IRP when a device has been removed in an orderly fashion (for example, initiated by a user in the Unplug or Eject Hardware applet), by surprise (a user pulls the device from its slot without prior warning), or when the user requests to update driver(s).

On Windows 2000 and later systems, the PnP Manager also sends this IRP if one of the drivers in the device stack fails an IRP_MN_START_DEVICE request for the device.

For an orderly device removal, the PnP Manager sends an IRP_MN_QUERY_REMOVE_DEVICE prior to the remove IRP. In this case, the device is in the remove-pending state when the remove IRP arrives. For a surprise device removal on Microsoft® Windows® 2000 or later, the PnP Manager sends an IRP_MN_SURPRISE_REMOVAL prior to the remove IRP. In this case, the device is in the surprise-removed state when the remove IRP arrives. Drivers can also receive a remove IRP before a device is started. In this case, the device is in the non-started state when the IRP arrives.

The PnP Manager sends this IRP at IRQL PASSIVE_LEVEL in the context of a system thread.

Input

None

Output

None

I/O Status Block

A driver must set Irp->IoStatus.Status to STATUS_SUCCESS. Drivers must not fail this IRP.

Operation

This IRP is handled first by the driver at the top of the device stack and then by each lower driver in the stack.

In response to this IRP, drivers perform such tasks as powering down the device, removing the device's software representation (device objects, and so forth), and releasing any resources for the device. See Removing a Device for detailed information on handling remove IRPs in function, filter, and bus drivers.

Also see Plug and Play for the general rules for handling all Plug and Play IRPs.

Sending This IRP

Reserved for system use. Drivers must not send this IRP.

If a bus driver detects that one (or more) of its child devices (child PDOs) has been physically removed from the machine, the bus driver calls IoInvalidateDeviceRelations to report the change to the PnP Manager. The PnP Manager then sends remove IRPs for any devices that have disappeared.

See Also

IoInvalidateDeviceRelations, IoRegisterPlugPlayNotification, IRP_MN_CANCEL_REMOVE_DEVICE, IRP_MN_QUERY_REMOVE_DEVICE, IRP_MN_SURPRISE_REMOVAL


IRP_MN_SET_LOCK

Bus drivers must handle this IRP for their child devices (child PDOs) that support device locking. Function and filter drivers do not handle this request.

When Sent

The PnP Manager sends this IRP to direct driver(s) to lock the device and prevent device eject, or to unlock the device.

The PnP Manager sends this IRP at IRQL PASSIVE_LEVEL in an arbitrary thread context.

Input

The Parameters.SetLock.Lock member of the IO_STACK_LOCATION structure is a BOOLEAN value specifying whether to lock (TRUE) or unlock (FALSE) the device.

Output

None

I/O Status Block

A bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status.

On success, a driver sets Irp->IoStatus.Information to zero.

If a bus driver does not handle this IRP, it leaves Irp->IoStatus.Status as is and completes the IRP.

Function and filter drivers do not handle this IRP. Such drivers call IoSkipCurrentIrpStackLocation and pass the IRP down to the next driver. Function and filter drivers do not set an IoCompletion routine, do not modify Irp->IoStatus, and must not complete the IRP.

Operation

If a driver returns success for this IRP, it ensures that the device has been locked or unlocked before completing the IRP.

See Plug and Play for the general rules for handling Plug and Play IRPs.

Sending This IRP

Reserved for system use. Drivers must not send this IRP.


IRP_MN_START_DEVICE

All PnP drivers must handle this IRP.

When Sent

The PnP Manager sends this IRP after it has assigned hardware resources, if any, to the device. The device may have been recently enumerated and is being started for the first time, or the device may be restarting after being stopped for resource rebalancing.

Sometimes the PnP Manager sends an IRP_MN_START_DEVICE to a device that is already started, supplying a different set of resources than the device is currently using. A driver initiates this action by calling IoInvalidateDeviceState and responding to the subsequent IRP_MN_QUERY_PNP_DEVICE_STATE request with the PNP_RESOURCE_REQUIREMENTS_CHANGED flag set. A bus driver might use this mechanism, for example, to open a new aperture on a PCI-to-PCI bridge.

The PnP Manager sends this IRP at IRQL PASSIVE_LEVEL in the context of a system thread.

Input

The Parameters.StartDevice.AllocatedResources member of the IO_STACK_LOCATION structure points to a CM_RESOURCE_LIST describing the hardware resources that the PnP Manager assigned to the device. This list contains the resources in raw form. Use the raw resources to program the device.

Parameters.StartDevice.AllocatedResourcesTranslated points to a CM_RESOURCE_LIST describing the hardware resources that the PnP Manager assigned to the device. This list contains the resources in translated form. Use the translated resources to connect the interrupt vector, map I/O space, and map memory.

Output

None

I/O Status Block

A driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status such as STATUS_UNSUCCESSFUL or STATUS_INSUFFICIENT_RESOURCES.

If a driver requires some time to execute its start operations for a device, it can mark the IRP pending and return STATUS_PENDING.

Operation

This IRP must be handled first by the parent bus driver for a device and then by each higher driver in the device stack.

In response to this IRP, drivers start a device for the first time or restart a device that was stopped. The exact operations required to start a device vary from device to device, but can include powering on the device, performing device-specific initialization, and connecting the interrupt.

A driver can typically handle this IRP in the same way whether it is starting a device for the first time or restarting a device after an IRP_MN_STOP_DEVICE, except if a driver needs to restore device state on a restart after a stop.

See Plug and Play for detailed information on handling a start IRP and for general rules for handling all Plug and Play IRPs.

Sending This IRP

Reserved for system use. Drivers must not send this IRP.

See Also

IRP_MN_STOP_DEVICE


IRP_MN_STOP_DEVICE

All PnP drivers must handle this IRP.

When Sent

The PnP Manager sends this IRP to stop a device so it can reconfigure the device's hardware resources.

On Windows 2000 and later systems, the PnP Manager sends this IRP only if a prior IRP_MN_QUERY_STOP_DEVICE completed successfully.

On Windows 98/Me, the PnP Manager also sends this IRP when a device is being disabled and when a device stack has failed an IRP_MN_START_DEVICE request. In cases of failed start, the PnP Manager sends this IRP without a preceding IRP_MN_QUERY_STOP_DEVICE request.

The PnP Manager sends this IRP at IRQL PASSIVE_LEVEL in the context of a system thread.

Input

None

Output

None

I/O Status Block

A driver must set Irp->IoStatus.Status to STATUS_SUCCESS.

Operation

This IRP is handled first by the driver at the top of the device stack and then passed down to each lower driver in the stack.

In response to this IRP, Windows 2000 and later drivers stop the device and release any hardware resources being used by the device, such as I/O ports and interrupts.

On Windows 2000 and later, a stop IRP is used solely to free a device's hardware resources so they can be reconfigured. Once the resources are reconfigured, the device is restarted. A stop IRP is not a precursor to a remove IRP. See Plug and Play for more information about the order in which PnP IRPs are sent to devices.

On Windows 98/Me, a stop IRP is also used after a failed start and when a device is being disabled. WDM drivers that run on these operating systems should stop the device, fail any incoming I/O, and disable and deregister any user-mode interfaces.

A driver must not fail this IRP. If a driver cannot release the device's hardware resources, it must fail the preceding query-stop IRP.

See Stopping a Device for detailed information on handling stop IRPs.

Sending This IRP

Reserved for system use. Drivers must not send this IRP.

See Also

IRP_MN_QUERY_STOP_DEVICE, IRP_MN_START_DEVICE, IoSetDeviceInterfaceState, IoRegisterDeviceInterface


IRP_MN_SURPRISE_REMOVAL

All PnP drivers must handle this IRP.

When Sent

The PnP Manager sends this IRP to notify the drivers for a device that the device has been unexpectedly removed from the machine and is no longer available for I/O. This IRP is sent on Windows 2000 and later systems only.

The PnP Manager sends this IRP before notifying user-mode applications or other kernel-mode components. After this IRP completes, the PnP Manager notifies registered applications and drivers that the device has been removed.

The device can be in any PnP state when the PnP Manager sends this IRP.

On Windows 98/Windows Me, the PnP Manager does not send this IRP.

The PnP Manager sends this IRP at IRQL PASSIVE_LEVEL in the context of a system thread.

Input

None

Output

None

I/O Status Block

A driver must set Irp->IoStatus.Status to STATUS_SUCCESS. A driver must not fail this IRP.

Operation

This IRP is handled first by the driver at the top of the device stack and then passed down to each lower driver in the stack.

This IRP indicates that a user removed a hot-plug device, either on purpose or by accident, without first using the user interface that manages removal of the device, or that a driver for the device failed a start IRP after a successful stop IRP.

Because the device is no longer present on the machine, drivers must immediately stop all access to the device. A driver releases any resources associated with the device, but leaves its device object attached to the device stack until the PnP Manager sends a subsequent IRP_MN_REMOVE_DEVICE request. Drivers fail any outstanding I/O to the device.

See Removing a Device for detailed information on handling this IRP and for the general rules for handling all Plug and Play IRPs.

Sending This IRP

Reserved for system use. Drivers must not send this IRP.

See Also

IRP_MN_REMOVE_DEVICE


IRP_MN_WRITE_CONFIG

Bus drivers for buses with configuration space must handle this request for their child devices (child PDOs). Function and filter drivers do not handle this request.

When Sent

A driver or other system component sends this IRP to write data to the configuration space of a device's parent bus.

A driver or other system component sends this IRP at IRQL < DISPATCH_LEVEL in an arbitrary thread context.

Input

Parameters.ReadWriteConfig is a structure containing the following information:

ULONG WhichSpace;
PVOID Buffer;
ULONG Offset;
ULONG Length

The members of the structure can be interpreted differently by different bus drivers, but the members are typically defined as follows:

WhichSpace
Specifies the configuration space.
Buffer
Points to a buffer that contains the data to be written. The format of the buffer is bus-specific.
Offset
Specifies an offset into the configuration space.
Length
Specifies the number of bytes to be written.

Output

Returned in the I/O status block.

I/O Status Block

A bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status such as STATUS_INVALID_PARAMETER_n, STATUS_NO_SUCH_DEVICE, or STATUS_DEVICE_NOT_READY.

On success, a bus driver sets Irp->IoStatus.Information to the number of bytes written.

If a bus driver is unable to complete this request immediately, it can mark the IRP pending, return STATUS_PENDING, and complete the IRP at a later time.

Operation

A bus driver handles this IRP for its child devices (child PDOs).

Function and filter drivers do not handle this IRP; they pass it to the next lower driver with no changes to Irp->IoStatus.Status and do not set an IoCompletion routine.

See Plug and Play for the general rules for handling Plug and Play IRPs.

Sending This IRP

Typically, a function driver sends this IRP to the device stack to which it is attached and the IRP is handled by the parent bus driver.

See Handling IRPs for information on sending IRPs. The following steps apply specifically to this IRP:

  • Allocate a buffer from paged pool and initialize it with the data to be written.
  • Set the values in the next I/O stack location of the IRP: set MajorFunction to IRP_MJ_PNP, set MinorFunction to IRP_MN_WRITE_CONFIG, and set the appropriate values in Parameters.ReadWriteConfig.
  • Initialize IoStatus.Status to STATUS_NOT_SUPPORTED.
  • Deallocate the IRP and the buffer when they are no longer needed.

Drivers must send this IRP from IRQL < DISPATCH_LEVEL.

A driver can access a bus's configuration space at DISPATCH_LEVEL through a bus interface routine, if the parent bus driver exports such an interface. To get a bus interface, a driver sends an IRP_MN_QUERY_INTERFACE request to its parent bus driver. The driver then calls the appropriate routine returned in the interface.

For example, to write configuration space from DISPATCH_LEVEL a driver can call IRP_MN_QUERY_INTERFACE during driver initialization to get the BUS_INTERFACE_STANDARD interface from the parent bus driver. The driver sends the query IRP from IRQL PASSIVE_LEVEL. Later, from code at IRQL DISPATCH_LEVEL, the driver calls the appropriate routine returned in the interface, such as the Interface.SetBusData routine.

See Also

IRP_MN_QUERY_INTERFACE, IRP_MN_READ_CONFIG


Power Management IRPs

All power IRPs have the major code IRP_MJ_POWER and one of the following minor codes, indicating a specific power management request:

IRP_MN_SET_POWER

IRP_MN_QUERY_POWER

IRP_MN_WAIT_WAKE

IRP_MN_POWER_SEQUENCE

This section provides reference information for the individual IRPs in alphabetical order. For more information about when the IRPs are sent and how drivers should handle them, see Power Management . The Power Management section also includes a general introduction to power management and terminology.


IRP_MN_POWER_SEQUENCE

When Sent

A driver sends this IRP as an optimization to determine whether its device actually entered a specific power state. Support for this IRP is optional.

To send this IRP, a driver must call IoAllocateIrp to allocate the IRP, specifying the major IRP code IRP_MJ_POWER and minor IRP code IRP_MN_POWER_SEQUENCE, and then call PoCallDriver to pass the IRP to the next lower driver. The Power Manager cannot send this IRP.

Senders of this IRP must be running at IRQL <= DISPATCH_LEVEL.

Input

None.

Output

Parameters.PowerSequence points to a POWER_SEQUENCE structure with the following members:

SequenceD1
Number of times the device has been in power state D1 or lower.
SequenceD2
Number of times the device has been in power state D2 or lower.
SequenceD3
Number of times the device has been in power state D3.

The sequence values track the minimum number of times a device has been in the corresponding power state or a lower power state.

The bus driver increments the values in SequenceD1, SequenceD2, and SequenceD3 at least each time the device enters in the corresponding power state or a lower power state.

I/O Status Block

A driver sets Irp->IoStatus.Status to STATUS_SUCCESS to indicate that it has returned the requested information, or to STATUS_NOT_IMPLEMENTED to indicate that it does not support this IRP.

Operation

This IRP returns the power sequence values for a device. Bus drivers can optionally handle it; function and filter drivers can optionally send it.

For a device that takes a long time to change state, this IRP provides a useful optimization. Every time the device changes its power state, its bus driver increments the sequence value for that power state. The bus driver initializes the sequence values at boot time and continually increments them thereafter; they need not be reset to zero.

A device policy owner can send this IRP once to get the sequence values before shutting off the device and once again to get new values when restoring power to the device. By comparing the two sets of values, the driver can determine whether the device actually entered the lower-powered state. If the device did not lose power, the driver can avoid a time-consuming reinitialization when the device returns to the D0 state.

For example, if the device takes a long time to restore power upon reaching the D2 state, the driver can store the SequenceD2 value before it sets the device state to D2 or lower. Later, when power is being restored to the device, the driver can compare the new SequenceD2 value with its stored value to determine whether the device state actually dropped below D2. If the values match, the device did not actually enter power state D2 or a lower state, and the driver can avoid reinitializing the device.


IRP_MN_QUERY_POWER

When Sent

The Power Manager or a device power policy owner sends this IRP to determine whether it can change the system or device power state, typically to go to sleep. A driver must call PoRequestPowerIrp to allocate and send this IRP.

The Power Manager sends this IRP at IRQL PASSIVE_LEVEL to device stacks that set the DO_POWER_PAGABLE flag in the PDO.

The Power Manager can send the IRP at IRQL DISPATCH_LEVEL if the DO_POWER_INRUSH flag is set. Such drivers cannot directly or indirectly access any paged code or data.

Input

Parameters.Power.Type specifies the type of power state being set, either SystemPowerState or DevicePowerState.

Parameters.Power.State specifies the power state itself, as follows:

  • If Parameters.Power.Type is SystemPowerState, the value is an enumerator of the SYSTEM_POWER_STATE type.
  • If Parameters.Power.Type is DevicePowerState, the value is an enumerator of the DEVICE_POWER_STATE type.

Parameters.Power.ShutdownType specifies additional information about the requested transition. Possible values are enumerators of the POWER_ACTION type.

Output

None.

I/O Status Block

A driver sets Irp->IoStatus.Status to STATUS_SUCCESS to indicate that the device can enter the requested state. A driver sets any appropriate failure status to indicate that it cannot enter the requested state.

Operation

The parameters for IRP_MN_QUERY_POWER are identical to those for IRP_MN_SET_POWER. Rather than notifying drivers of an irrevocable change to the power state, however, IRP_MN_QUERY_POWER queries whether the system or a device can enter a particular power state.

A driver must not change the power state of its device in response to an IRP_MN_QUERY_POWER request.

For each IRP_MN_QUERY_POWER request a driver receives, it must call PoStartNextPowerIrp, as described in Calling PoStartNextPowerIrp.

IRP_MN_QUERY_POWER for a System Power State

The Power Manager sends this IRP to ensure that it can change the system power state without disrupting work, such as dropping network connections.

Whenever possible, the Power Manager queries before sending IRP_MN_SET_POWER to request a system sleep state. However, under some conditions (such as the user pressing the Power Off button or a battery expiring), the Power Manager might issue an IRP_MN_SET_POWER request without first querying. The Power Manager queries only for sleep states; it never queries before returning to the working state.

When a driver receives a system power query IRP, it should fail the IRP if it cannot support any of the device states that are valid for the queried system state. For more information, see DeviceState. Otherwise, the driver should pass the IRP to the next lower driver. The bus driver completes the IRP.

When a device power policy owner receives a system power query IRP, it should set an IoCompletion routine in the IRP before passing it down. In the IoCompletion routine, it should send an IRP_MN_QUERY_POWER for a device state that is valid for the queried system state. For more information, see Handling a System Query Power IRP in a Device Power Policy Owner.

When the IRP specifies PowerSystemShutdown (S5), the value at Parameters.Power.ShutdownType provides a reason for the shutdown. The ShutdownType tells the driver whether the system is resetting (PowerActionShutdownReset) or powering off indefinitely to reboot later (PowerActionShutdownOff). For drivers of most devices, the difference is inconsequential. However, for certain devices, such as a video streaming device that performs DMA, a driver might opt to power down its device when the system is resetting, thus stopping any ongoing I/O.

On Microsoft® Windows® 2000 and later systems, the value at ShutdownType can also be PowerActionShutdown. In this case, the driver cannot tell what type of shutdown is requested and should therefore proceed as for a reset.

If a driver fails an IRP_MN_QUERY_POWER request for a system power state, the Power Manager typically responds by issuing an IRP_MN_SET_POWER IRP. Usually, this IRP will reaffirm the current system state. However, it is possible that drivers might receive an IRP_MN_SET_POWER to the queried state or to some other intermediate state. Drivers should be prepared to handle these situations.

IRP_MN_QUERY_POWER for a Device Power State

A device power policy owner sends this IRP to its stack in response to a system IRP_MN_QUERY_POWER request.

If a driver can put its device in the requested device state, it sets IoStatus.Status to STATUS_SUCCESS and passes the IRP down to the next lower driver, and so forth until the IRP reaches the bus driver. If any driver in the stack must fail the IRP, that driver should complete the IRP immediately by calling IoCompleteRequest and returning a failure status. Drivers that fail the IRP do not pass it further down the stack.

By returning STATUS_SUCCESS, the driver guarantees that it will not start any operation that would change its ability to set the requested power state. The driver should queue any IRPs that require such operations until it completes a set-power IRP that returns the device to an acceptable power state.

On Windows 2000 and later systems, when the IRP specifies PowerDeviceD1, PowerDeviceD2, or PowerDeviceD3, the value at Parameters.Power.ShutdownType provides information about the current system power IRP, if a system power IRP is active. In this case, the value at ShutdownType indicates the currently requested system power state, or PowerActionNone if a system request is not outstanding. On Windows 98/Me, this field always contains PowerActionNone when the IRP requests a device power state.

See Also

IRP_MN_SET_POWER, PoRequestPowerIrp


IRP_MN_SET_POWER

When Sent

Either the system Power Manager or a device power policy owner can send this IRP.

The Power Manager sends this IRP to notify drivers of a change to the system power state. If a driver has registered its device for idle detection, the Power Manager sends this IRP to change the power state of an idle device.

A driver that owns power policy sends this IRP to set the device power state for its device. A driver must call PoRequestPowerIrp to send this IRP.

The Power Manager sends this IRP at IRQL PASSIVE_LEVEL to device stacks that set the DO_POWER_PAGABLE flag in the PDO. Drivers in such stacks can touch paged code or data to complete the request.

The Power Manager can send the IRP at IRQL DISPATCH_LEVEL if the DO_POWER_INRUSH flag is set. Such drivers cannot directly or indirectly access any paged code or data.

Input

Parameters.Power.Type specifies the type of power state being set, either SystemPowerState or DevicePowerState.

Parameters.Power.State specifies the power state itself, as follows:

  • If Parameters.Power.Type is SystemPowerState, the value is an enumerator of the SYSTEM_POWER_STATE type.
  • If Parameters.Power.Type is DevicePowerState, the value is an enumerator of the DEVICE_POWER_STATE type.

Parameters.Power.ShutdownType specifies additional information about the requested transition. Possible values are enumerators of the POWER_ACTION type.

Output

Parameters.Power.SystemContext is reserved for system use.

I/O Status Block

A driver sets Irp->IoStatus.Status to STATUS_SUCCESS to indicate that the device has entered the requested state.

A driver must not fail this IRP.

Operation

The Power Manager or a driver can request an IRP_MN_SET_POWER IRP. The Power Manager sends this IRP for one of the following reasons:

  • To notify drivers of a change to the system power state
  • To change the power state of a device for which the Power Manager is performing idle detection

A driver that owns device power policy sends IRP_MN_SET_POWER to change the power state of its device.

At any given time, the system allows only one such IRP to be active for each device object.

Each driver must pass each power IRP down to the next-lower driver using the PoCallDriver routine. The PoCallDriver interface is similar to that of IoCallDriver, except that the power management subsystem might delay the IRP before passing it on to the next driver. For example, delays can occur on a PowerDeviceD0 request if the device requires inrush current and therefore must be powered up serially with another such device.

For each IRP_MN_SET_POWER request a driver receives, it must call PoStartNextPowerIrp, as described in Calling PoStartNextPowerIrp.

IRP_MN_SET_POWER for System Power States

Only the Power Manager can send a system set-power IRP.

Whenever possible, the Power Manager sends IRP_MN_QUERY_POWER before sending IRP_MN_SET_POWER to request a system sleep state. However, under some conditions (such as the user pressing the Power Off button or a battery expiring), the Power Manager might issue IRP_MN_SET_POWER without first querying. The Power Manager queries only for sleep states; it never queries before powering up.

The IRP_MN_SET_POWER request is sent to the top driver in the device stack for a device. The top driver passes the IRP down to the next lower driver and so forth until the IRP reaches the bus driver, which must complete the IRP.

A filter driver typically does not need to act on a system set-power IRP, other than to pass it on.

The device power policy owner, however, sets an IoCompletion routine before passing down the IRP. In the IoCompletion routine, it sends an IRP_MN_SET_POWER request for a device power IRP. For more information, see Handling a System Set-Power IRP in a Device Power Policy Owner.

A system set-power IRP informs drivers that a change to the system power state is imminent and the drivers must prepare for it. However, a driver should not change the power state of its device until it receives an IRP_MN_SET_POWER for a device power state.

The value at Parameters.Power.ShutdownType provides additional information about the pending actions. When the IRP specifies PowerSystemShutdown (S5), a driver can determine whether the system is resetting (PowerActionShutdownReset) or powering off indefinitely to reboot later (PowerActionShutdownOff). For drivers of most devices, the difference is inconsequential. However, for certain devices, such as video streaming devices, a driver might power off the device in order to stop I/O when the system is resetting.

On Windows 2000 and later versions of the operating system, the value at ShutdownType can also be PowerActionShutdown. In this case, the driver cannot tell what type of shutdown is requested and should therefore proceed as for a reset.

Device Power States

A driver must set the device into the requested state before completing the IRP.

When the IRP requests a transition to a lower power state, drivers must handle the IRP as it travels down the device stack, saving any context the driver will need to restore the device to the working state. When the bus driver receives the IRP, it does the same, then sets the device into the requested power state, calls PoSetPowerState to notify the Power Manager, starts the next power IRP (PoStartNextPowerIrp), and completes the device power IRP.

The driver must complete this IRP in a timely manner. In general, drivers should avoid any delay that a typical user would find noticeably slow. For example, a driver could delay a system state change to flush cached disk or network data, but should not keep a network connection alive or format a tape. For more information, see Passing Power IRPs.

On Windows 2000 and later versions of the operating system, if the IRP specifies PowerDeviceD1, PowerDeviceD2, or PowerDeviceD3, and a system set-power IRP is active, the value at Parameters.Power.ShutdownType provides information about the system IRP.

Drivers of devices on the hibernate path should inspect this value. If the IRP requests PowerDeviceD3 and ShutdownType is PowerActionHibernate, such a driver should save any context required to restore the device, but should not power down the device; the device will enter the D3 state when the machine loses power.

On Windows 2000 and later versions of the operating system, drivers should not rely on the value at ShutdownType if the requested power state is PowerDeviceD0.

On Windows 98/Me, if the IRP requests a device power state, the ShutdownType is always PowerActionNone.

The driver that determines when to power down a device varies depending on the device class.

The driver that determines when to power up a device is almost always a driver that accesses the device registers. The driver must verify that the device is in the D0 state before accessing the device's hardware registers. If the device is not in the D0 state, the driver must call PoRequestPowerIrp to send an IRP to power up the device. A driver cannot access its device unless the device is in the D0 state.

When a driver receives a set-power IRP for device state D0, it sets an IoCompletion routine and passes the IRP to the next lower driver.

When the IRP reaches the bus driver, that driver applies (or resets) power to the device, calls PoStartNextPowerIrp, completes the IRP, and calls PoSetPowerState to inform the Power Manager of the new power state for the device.

After the bus driver completes the power-up IRP, function and filter drivers handle the IRP in their IoCompletion routines as it travels back up the device stack. In the IoCompletion routine, each driver restores or reinitializes its device context and performs any other required start-up tasks.

For more information, see Handling IRP_MN_SET_POWER for Device Power States.

See Also

PoCallDriver, PoStartNextPowerIrp, PoSetPowerState, PoRequestPowerIrp, PoRegisterDeviceForIdleDetection


IRP_MN_WAIT_WAKE

When Sent

A driver that owns power policy targets this IRP to its PDO to enable its device to awaken in response to an external event, such as an incoming phone call. A driver must call PoRequestPowerIrp to send this IRP.

As a general rule, a driver should send this IRP as soon as it determines that its device should be enabled for wake-up. Consequently, drivers for most such devices send this IRP after powering on their devices and before completing the IRP_MN_START_DEVICE request.

However, a driver can send the IRP any time the device is in the working state (PowerDeviceD0). The device stack must not be in transition; that is, a driver should not send an IRP_MN_WAIT_WAKE while any other power IRP is active in its device stack.

A wait/wake IRP does not change the power state of the device or of the system. It simply enables a wake-up signal from the device. When the wake-up signal arrives, the policy owner must call PoRequestPowerIrp to send a set-power IRP to return its device to D0.

The driver must be running at IRQL PASSIVE_LEVEL to send this IRP. However, the IRP can be completed at IRQL DISPATCH_LEVEL.

Input

Parameters.WaitWake.SystemWake contains the lowest (least-powered) system power state from which the device should be allowed to awaken the system.

Output

None.

I/O Status Block

A driver sets Irp->IoStatus.Status to one of the following:

STATUS_PENDING
The driver received the IRP and is waiting for the device to signal wake-up.
STATUS_INVALID_DEVICE_STATE
The device is in a less-powered state than the DeviceWake state specified in the DEVICE_CAPABILITIES structure for the device, or the device cannot awaken the system from the SystemWake state passed in the IRP.
STATUS_NOT_SUPPORTED
The device does not support wake-up.
STATUS_DEVICE_BUSY
An IRP_MN_WAIT_WAKE request is already pending and must be completed or canceled before another IRP_MN_WAIT_WAKE request can be issued.
STATUS_SUCCESS
The device has signaled a wake event.
STATUS_CANCELLED
The IRP has been canceled.

If a driver must fail this IRP, it completes the IRP immediately and does not pass the IRP to the next-lower driver.

Operation

A driver sends IRP_MN_WAIT_WAKE for either of two reasons:

  1. To enable its device to awaken a sleeping system in response to an external wake-up signal.
  2. To enable its device to awaken from a device sleep state in response to an external wake-up signal.

The IRP must be passed down the device stack to the bus driver for the device, which calls IoMarkIrpPending and returns STATUS_PENDING from its DispatchPower routine. The IRP remains pending until a wake-up signal occurs or until the driver that sent the IRP cancels it.

Only one wait/wake IRP can be held pending for a PDO at any given time. If a driver already holds a wait/wake IRP for a PDO, it must fail any additional such IRPs with STATUS_DEVICE_BUSY. A driver that enumerates more than one child PDO can have a wait/wake IRP pending for each such PDO.

Each driver sets an IoCompletion routine as the IRP travels down the device stack. When the device signals a wake-up event, the bus driver services the wake-up signal and completes the IRP, returning STATUS_SUCCESS. The I/O Manager then calls the IoCompletion routine of the next higher driver, and so on up the device stack.

When a driver sends a wait/wake IRP, it should specify a callback routine in the PoRequestPowerIrp call. In the callback routine, the driver typically services the device. For example, the power policy owner for the device must call PoRequestPowerIrp to send an IRP_MN_SET_POWER for device state D0.

A driver that acts as the bus driver for one device and the policy owner for a parent device requests an IRP_MN_WAIT_WAKE IRP for the parent's device stack when it receives a IRP_MN_WAIT_WAKE request from a child PDO. If the driver enumerates more than one child PDO, it should request only one wait/wake IRP for the parent's device stack no matter how many child PDOs send wait/wake requests. Instead, such a driver should keep an internal count of wait/wake IRPs, incrementing the count each time it receives a request and decrementing the count each time it completes a request. If the count is nonzero after it has completed a wait/wake IRP, the driver should send another wait/wake IRP to its device stack to "rearm" itself for wake-up. For more information, see Understanding the Path of Wait/Wake IRPs Through a Device Tree.

To cancel an IRP_MN_WAIT_WAKE, a driver calls IoCancelIrp. Only the driver that originated the IRP can cancel it. A driver cancels a pending IRP_MN_WAIT_WAKE when any of the following occurs:

  • The driver receives a PnP IRP that stops or removes the device.
  • The system is going to sleep and the device wake signal must not awaken it.

See Also

PoRequestPowerIrp


WMI IRPs

This chapter describes the Windows Management Instrumentation IRPs that are part of the WMI extensions to WDM. All WMI IRPs use the major code IRP_MJ_SYSTEM_CONTROL and a minor code that indicates the specific WMI request. The WMI kernel-mode component can send WMI IRPs any time following a driver's successful registration as a supplier of WMI data. WMI IRPs typically get sent when a user-mode data consumer has requested WMI data.

All drivers must set a dispatch table entry point that can be used by a DispatchSystemControl routine to handle WMI requests. If a driver registers as a WMI data provider by calling IoWMIRegistrationControl, it must handle such requests in one of the following ways:

  • Call the kernel-mode WMI library routines declared in the wmilib.h header file. Drivers can use these routines only if they base static instance names on a single base name string or the device instance ID of a PDO. Drivers that use dynamic instance names can not use the WMI library routines.
  • Process and complete any request that was tagged with a pointer to the driver's device object. Such a request is passed by the driver in its call to IoWMIRegistrationControl. Other IRP_MJ_SYSTEM_CONTROL requests must be forwarded to the next-lower driver.

The WMI library routines simplify the handling of WMI requests. Instead of processing each WMI request, a driver calls WmiSystemControl with a pointer to its device object, the IRP, and a WMILIB_CONTEXT structure. This WMILIB_CONTEXT structure contains pointers to a set of DpWmiXXX callback routines that are defined by the driver. The WMI library validates the IRP parameters and calls the driver provided DpWmiXXX routine for driver-specific processing. WMI library then packages any output in an appropriate WNODE_XXX structure. The output and status are returned to the caller. Drivers that use dynamic instance names must handle WMI requests by filling in the WNODE_XXX structure directly.

Drivers that do not register as WMI data providers must forward all WMI requests to the next-lower driver.

For information about registering as a WMI data provider, handling WMI IRPs, and using the WMI kernel-mode library routines, see Windows Management Instrumentation.


IRP_MN_CHANGE_SINGLE_INSTANCE

All drivers that support WMI must handle this IRP.

When Sent

WMI sends this IRP to change all data items in a single instance of a data block.

WMI sends this IRP at IRQL PASSIVE_LEVEL in an arbitrary thread context.

Input

Parameters.WMI.ProviderId points to the device object of the driver that should respond to the request. This pointer is found in the driver's I/O stack location in the IRP.

Parameters.WMI.DataPath points to a GUID that identifies the data block associated with the instance to be changed.

Parameters.WMI.BufferSize indicates the size of the nonpaged buffer at Parameters.WMI.Buffer.

Parameters.WMI.Buffer points to a WNODE_SINGLE_INSTANCE structure that identifies the instance and specifies new data values.

Output

None.

I/O Status Block

If the driver handles the IRP by calling WmiSystemControl, WMI sets Irp->IoStatus.Status and Irp->IoStatus.Information in the I/O status block.

Otherwise, the driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status such as the following:

STATUS_WMI_INSTANCE_NOT_FOUND

STATUS_WMI_GUID_NOT_FOUND

STATUS_WMI_READ_ONLY

STATUS_WMI_SET_FAILURE

On success, the driver sets Irp->IoStatus.Information to zero.

Operation

A driver that handles WMI IRPs by calling WMI library support routines calls WmiSystemControl with a pointer to its WMILIB_CONTEXT structure, a pointer to its device object, and a pointer to the IRP. WmiSystemControl calls the driver's DpWmiSetDataBlock routine, or returns STATUS_WMI_READ_ONLY to the caller if the driver does not define an entry point for such a routine.

A driver that handles an IRP_MN_CHANGE_SINGLE_INSTANCE request does so only if the device object pointer at Parameters.WMI.ProviderId matches the pointer passed by the driver in its call to IoWMIRegistrationControl. Otherwise, the driver forwards the request to the next-lower driver.

If the driver handles the request, it first checks the GUID at Parameters.WMI.DataPath to determine whether it identifies a data block supported by the driver. If not, the driver fails the IRP and returns STATUS_WMI_GUID_NOT_FOUND.

If the driver supports the data block, it checks the input WNODE_SINGLE_INSTANCE at Parameters.WMI.Buffer for the instance name, as follows:

  • If WNODE_FLAG_STATIC_INSTANCE_NAMES is set in WnodeHeader.Flags, the driver uses InstanceIndex as an index into the driver's list of static instance names for that block. WMI obtains the index from registration data provided by the driver when it registered the block.
  • If WNODE_FLAG_STATIC_INSTANCE_NAMES is clear in WnodeHeader.Flags, the driver uses the offset at OffsetInstanceName to locate the instance name string in the input WNODE_SINGLE_INSTANCE. OffsetInstanceName is the offset in bytes from the beginning of the structure to a USHORT which is the length of the instance name string in bytes (not characters), including the NUL terminator if present, followed by the instance name string in Unicode.

If the driver cannot locate the specified instance, it must fail the IRP and return a STATUS_WMI_INSTANCE_NOT_FOUND. In the case of an instance that has a dynamic instance name, this status indicates that the driver does not "own" the instance. WMI can therefore continue to query other data providers and return an appropriate error to the data consumer if another provider finds the instance but cannot handle the request for some other reason.

If the driver locates the instance and can handle the request, it sets the read/write data items in the instance to the values in the WNODE_SINGLE_INSTANCE, leaving any read-only items unchanged. If the entire data block is read-only, the driver should fail the IRP and return STATUS_WMI_READ_ONLY.

If the instance is valid but the driver cannot handle the request, it can return any appropriate error status.

See Also

DpWmiSetDataBlock, IoWMIRegistrationControl, WMILIB_CONTEXT, WmiSystemControl, WNODE_SINGLE_INSTANCE


IRP_MN_CHANGE_SINGLE_ITEM

All drivers that support WMI must handle this IRP.

When Sent

WMI sends this IRP to change a single data item in a single instance of a data block.

WMI sends this IRP at IRQL PASSIVE_LEVEL in an arbitrary thread context.

Input

Parameters.WMI.ProviderId points to the device object of the driver that should respond to the request. This pointer is located in the driver's I/O stack location in the IRP.

Parameters.WMI.DataPath points to a GUID that identifies the data block to be set.

Parameters.WMI.BufferSize indicates the size of the nonpaged buffer at Parameters.WMI.Buffer.

Parameters.WMI.Buffer, points to a WNODE_SINGLE_ITEM structure that identifies the instance of the data block, the ID of the item to set, and a new data value.

Output

None.

I/O Status Block

If the driver handles the IRP by calling WmiSystemControl, WMI sets Irp->IoStatus.Status and Irp->IoStatus.Information in the I/O status block.

Otherwise, the driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status such as the following:

STATUS_WMI_INSTANCE_NOT_FOUND

STATUS_WMI_INSTANCE_ID_NOT_FOUND

STATUS_WMI_GUID_NOT_FOUND

STATUS_WMI_READ_ONLY

STATUS_WMI_SET_FAILURE

On success, a driver sets Irp->IoStatus.Information to zero.

Operation

A driver that handles WMI IRPS by calling WMI library support routines calls WmiSystemControl with a pointer to its WMILIB_CONTEXT structure, a pointer to its device object, and a pointer to the IRP. WmiSystemControl calls the driver's DpWmiSetDataItem routine, or returns STATUS_WMI_READ_ONLY to the caller if the driver does not define an entry point for such a routine.

A driver should handles an IRP_MN_CHANGE_SINGLE_ITEM request only if Parameters.WMI.ProviderId points to the same device object as the pointer that the driver passed to IoWMIRegistrationControl. Otherwise, the driver forwards the request to the next-lower driver.

Before handling a request, the driver determines whether Parameters.WMI.DataPath points to a GUID that the driver supports. If it does not, the driver fails the IRP and returns STATUS_WMI_GUID_NOT_FOUND.

If the driver supports the data block, it checks the input WNODE_SINGLE_ITEM structure that Parameters.WMI.Buffer points to for the instance name, as follows:

  • If WNODE_FLAG_STATIC_INSTANCE_NAMES is set in WnodeHeader.Flags, the driver uses InstanceIndex as an index into the driver's list of static instance names for that block. WMI obtains the index from registration data provided by the driver when it registered the block.
  • If WNODE_FLAG_STATIC_INSTANCE_NAMES is clear in WnodeHeader.Flags, the driver uses the offset at OffsetInstanceName to locate the instance name string in the input WNODE_SINGLE_ITEM. OffsetInstanceName is the offset in bytes from the beginning of the structure to a USHORT which is the length of the instance name string in bytes (not characters). This length includes the NUL terminator if present, followed by the instance name string in Unicode.

If the driver cannot locate the specified instance, it must fail the IRP and return STATUS_WMI_INSTANCE_NOT_FOUND. In the case of an instance with a dynamic instance name, this status indicates that the driver does not "own" the instance. WMI can therefore continue to query other data providers and return an appropriate error to the data consumer if another provider finds the instance but cannot handle the request for some other reason.

If the driver locates the instance and can handle the request, it sets the data item in the instance to the value in the WNODE_SINGLE_ITEM. If the data item is read-only, the driver leaves the item unchanged, fails the IRP and returns STATUS_WMI_READ_ONLY.

If the instance is valid but the driver cannot handle the request, it can return any appropriate error status.

See Also

DpWmiSetDataItem, IoWMIRegistrationControl, WMILIB_CONTEXT, WmiSystemControl, WNODE_SINGLE_ITEM


IRP_MN_DISABLE_COLLECTION

Any WMI driver that registers one or more of its data blocks as expensive to collect must handle this IRP.

When Sent

WMI sends this IRP to request the driver to stop accumulating data for a data block that the driver registered as expensive to collect and for which data collection has been enabled.

WMI sends this IRP at IRQL PASSIVE_LEVEL in an arbitrary thread context.

Input

Parameters.WMI.ProviderId points to the device object of the driver that should respond to the request. This pointer is located in the driver's I/O stack location in the IRP.

Parameters.WMI.DataPath points to a GUID that identifies the data block for which data accumulation should be stopped.

Output

None.

I/O Status Block

If the driver handles the IRP by calling WmiSystemControl, WMI sets Irp->IoStatus.Status and Irp->IoStatus.Information in the I/O status block.

Otherwise, the driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status such as the following:

STATUS_WMI_GUID_NOT_FOUND

STATUS_INVALID_DEVICE_REQUEST

On success, a driver sets Irp->IoStatus.Information to zero.

Operation

A driver registers a data block as expensive to collect by setting WMIREG_FLAG_EXPENSIVE in the Flags member of the WMIREGGUID or WMIGUIDREGINFO structure that the driver passes to WMI when it registers or updates the data block. A driver need not accumulate data for such a block until it receives an explicit request to enable collection.

A driver that handles WMI IRPs by calling WMI library support routines calls WmiSystemControl with a pointer to its WMILIB_CONTEXT structure, a pointer to its device object, and a pointer to the IRP. WmiSystemControl calls the driver's DpWmiFunctionControl routine, or simply returns STATUS_SUCCESS to the caller if the driver does not define an entry point for such a routine.

A driver handles an IRP_MN_DISABLE_COLLECTION request only if Parameters.WMI.ProviderId points to the same device object as the pointer that the driver passed to IoWMIRegistrationControl. Otherwise, the driver forwards the request to the next-lower driver.

Before handling the request, the driver determines whether Parameters.WMI.DataPath points to a GUID that the driver supports. If not, the driver fails the IRP and returns STATUS_WMI_GUID_NOT_FOUND. If the data block is valid but was not registered with WMIREG_FLAG_EXPENSIVE, the driver can return STATUS_SUCCESS and take no further action.

It is unnecessary for the driver to check whether data collection is already disabled because WMI sends a single disable request for the data block when the last data consumer disables collection for that block. WMI will not send another disable request without an intervening request to enable.

See Also

DpWmiFunctionControl, IoWMIRegistrationControl, IRP_MN_ENABLE_COLLECTION, WMILIB_CONTEXT, WMIREGGUID, WMIGUIDREGINFO, WmiSystemControl


IRP_MN_DISABLE_EVENTS

Any WMI driver that registers one or more event blocks must handle this IRP.

When Sent

WMI sends this IRP to inform the driver that a data consumer has requested no further notification of an event.

WMI sends this IRP at IRQL PASSIVE_LEVEL in an arbitrary thread context.

Input

Parameters.WMI.ProviderId points to the device object of the driver that should respond to the request. This pointer is located in the driver's I/O stack location in the IRP.

Parameters.WMI.DataPath points to a GUID that identifies the event block to disable.

Output

None.

I/O Status Block

If the driver handles the IRP by calling WmiSystemControl, WMI sets Irp->IoStatus.Status and Irp->IoStatus.Information in the I/O status block.

Otherwise, the driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status such as the following:

STATUS_WMI_GUID_NOT_FOUND

STATUS_INVALID_DEVICE_REQUEST

On success, a driver sets Irp->IoStatus.Information to zero.

Operation

A driver that handles WMI IRPs by calling WMI library support routines calls WmiSystemControl with a pointer to its WMILIB_CONTEXT structure, a pointer to its device object, and a pointer to the IRP. WmiSystemControl calls the driver's DpWmiFunctionControl routine, or simply returns STATUS_SUCCESS to the caller if the driver does not define an entry point for such a routine.

A driver handles an IRP_MN_DISABLE_EVENTS request only if Parameters.WMI.ProviderId points to the same device object as the pointer that the driver passed to IoWMIRegistrationControl. Otherwise, the driver forwards the request to the next-lower driver.

Before handling a request, the driver determines whether Parameters.WMI.DataPath points to a GUID the driver supports. If not, the driver fails the IRP and returns STATUS_WMI_GUID_NOT_FOUND.

If the driver supports the event block, it disables the event for all instances of that block.

It is unnecessary for the driver to check whether events are already disabled for the event block because WMI sends a single disable request for that event block when the last data consumer disables the event. WMI will not send another disable request without an intervening request to enable.

For details about defining event blocks, see Designing WMI Data and Event Blocks.

See Also

DpWmiFunctionControl, IoWMIRegistrationControl, IRP_MN_ENABLE_EVENTS, WMILIB_CONTEXT, WmiSystemControl


IRP_MN_ENABLE_COLLECTION

Any WMI driver that registers one or more of its data blocks as expensive to collect must handle this IRP.

When Sent

WMI sends this IRP to request the driver to start accumulating data for a data block that the driver registered as expensive to collect.

WMI sends this IRP at IRQL PASSIVE_LEVEL in an arbitrary thread context.

Input

Parameters.WMI.ProviderId points to the device object of the driver that should respond to the request. This pointer is located in the driver's I/O stack location in the IRP.

Parameters.WMI.DataPath points to a GUID that identifies the data block for which data is accumulated.

Output

None.

I/O Status Block

If the driver handles the IRP by calling WmiSystemControl, WMI sets Irp->IoStatus.Status and Irp->IoStatus.Information in the I/O status block.

Otherwise, the driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status such as the following:

STATUS_WMI_GUID_NOT_FOUND

STATUS_INVALID_DEVICE_REQUEST

On success, a driver sets Irp->IoStatus.Information to zero.

Operation

A driver registers a data block as expensive to collect by setting WMIREG_FLAG_EXPENSIVE in the Flags member of the WMIREGGUID or WMIGUIDREGINFO structure. The driver passes these structures to WMI when it registers or updates the data block. A driver need not accumulate data for such a block until it receives an explicit request to start data collection.

A driver that handles WMI IRPs by calling WMI library support routines calls WmiSystemControl with a pointer to its WMILIB_CONTEXT structure, a pointer to its device object, and a pointer to the IRP. WmiSystemControl calls the driver's DpWmiFunctionControl routine, or simply returns STATUS_SUCCESS to the caller if the driver does not define an entry point for such a routine.

A driver handles an IRP_MN_ENABLE_COLLECTION request only if Parameters.WMI.ProviderId points to the same device object as the pointer that the driver passed to IoWMIRegistrationControl. Otherwise, the driver forwards the request to the next-lower driver.

Before handling a request, the driver should make sure that Parameters.WMI.DataPath points to a GUID that the driver supports. If it does not, the driver should fails the IRP and return STATUS_WMI_GUID_NOT_FOUND. If the data block is valid but was not registered with WMIREG_FLAG_EXPENSIVE, the driver can return STATUS_SUCCESS and take no further action.

If the block is valid and was registered with WMIREG_FLAG_EXPENSIVE, the driver enables data collection for all instances of that data block.

It is unnecessary for the driver to check whether data collection is already enabled for the data block. WMI sends only a single request to enable a data block after the first data consumer enables the block. WMI will not send another request to enable without an intervening disable request.

See Also

DpWmiFunctionControl, IoWMIRegistrationControl, IRP_MN_DISABLE_COLLECTION, WMILIB_CONTEXT, WMIREGGUID, WmiSystemControl


IRP_MN_ENABLE_EVENTS

Any WMI driver that registers one or more event blocks must handle this IRP.

When Sent

WMI sends this IRP to inform the driver that a data consumer has requested notification of an event.

WMI sends this IRP at IRQL PASSIVE_LEVEL in an arbitrary thread context.

Input

Parameters.WMI.ProviderId points to the device object of the driver that should respond to the request. This pointer is located in the driver's I/O stack location in the IRP.

Parameters.WMI.DataPath points to a GUID that identifies the event block to enable.

Parameters.WMI.BufferSize indicates the size of the nonpaged buffer at Parameters.WMI.Buffer, which must be greater than or equal to the sizeof(WNODE_HEADER). A driver that does not register trace blocks (WMIREG_FLAG_TRACED_GUID) can ignore this parameter.

Parameters.WMI.Buffer points to a WNODE_HEADER that indicates whether the event should be traced (WMI_FLAGS_TRACED_GUID) and provides a handle to the system logger. A driver that does not register trace blocks (WMIREG_FLAG_TRACED_GUID) can ignore this parameter.

Output

None.

I/O Status Block

If the driver handles the IRP by calling WmiSystemControl, WMI sets Irp->IoStatus.Status and Irp->IoStatus.Information in the I/O status block.

Otherwise, the driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status such as the following:

STATUS_WMI_GUID_NOT_FOUND

STATUS_INVALID_DEVICE_REQUEST

On success, a driver sets Irp->IoStatus.Information to zero.

Operation

A driver that handles WMI IRPs by calling WMI library support routines calls WmiSystemControl with a pointer to its WMILIB_CONTEXT structure, a pointer to its device object, and a pointer to the IRP. WmiSystemControl calls the driver's DpWmiFunctionControl routine, or simply returns STATUS_SUCCESS to the caller if the driver does not define an entry point for such a routine.

A driver handles an IRP_MN_ENABLE_EVENTS request only if Parameters.WMI.ProviderId points to the same device object as the pointer that the driver passed to IoWMIRegistrationControl. Otherwise, the driver forwards the request to the next-lower driver.

Before the driver handles the request, it should determine whether Parameters.WMI.DataPath points to a GUID that the driver supports. If not, the driver fails the IRP and returns STATUS_WMI_GUID_NOT_FOUND.

If the driver supports the event block, it enables the event for all instances of that data block.

It is unnecessary for the driver to check whether events are already enabled for the event block because WMI sends a single request to enable for the event block when the first data consumer enables the event. WMI will not send another request to enable without an intervening disable request.

A driver that registers trace blocks (WMIREG_FLAG_TRACED_GUID) must also determine whether to send the event to WMI or to the system logger for tracing. If tracing is requested, Parameters.WMI.Buffer points to a WNODE_HEADER structure in which Flags is set with WNODE_FLAG_TRACED_GUID and HistoricalContext contains a handle to the logger.

For details about defining event blocks, sending events, and tracing, see Windows Management Instrumentation.

See Also

DpWmiFunctionControl, IoWMIRegistrationControl, IRP_MN_DISABLE_EVENTS, WMILIB_CONTEXT, WmiSystemControl, WNODE_EVENT_ITEM, WNODE_HEADER


IRP_MN_EXECUTE_METHOD

All drivers that support methods within data blocks must handle this IRP.

When Sent

WMI sends this IRP to execute a method associated with a data block.

WMI sends this IRP at IRQL PASSIVE_LEVEL in an arbitrary thread context.

WMI will send an IRP_MN_QUERY_SINGLE_INSTANCE prior to sending an IRP_MN_EXECUTE_METHOD. If a driver supports IRP_MN_EXECUTE_METHOD it must have a IRP_MN_QUERY_SINGLE_INSTANCE handler for the same data block whose method is being executed.

Input

Parameters.WMI.ProviderId points to the device object of the driver that should respond to the request. This pointer is located in the driver's I/O stack location in the IRP.

Parameters.WMI.DataPath points to a GUID that identifies the data block associated with the method to execute.

Parameters.WMI.BufferSize indicates the size of the nonpaged buffer at Parameters.WMI.Buffer which must be >= sizeof(WNODE_METHOD_ITEM) plus the size of any output data for the method.

Parameters.WMI.Buffer points to a WNODE_METHOD_ITEM structure in which MethodID indicates the identifier of the method to execute and DataBlockOffset indicates the offset in bytes from the beginning of the structure to the first byte of input data, if any. Parameters.WMI.Buffer->SizeDataBlock indicates the size in bytes of the input WNODE_METHOD_ITEM including input data, or zero if there is no input.

Output

If the driver handles WMI IRPs by calling WmiSystemControl, WMI fills in the WNODE_METHOD_ITEM with data returned by the driver's DpWmiExecuteMethod routine.

Otherwise, the driver fills in the WNODE_METHOD_ITEM structure that Parameters.WMI.Buffer points to as follows:

  • Updates WnodeHeader.BufferSize with the size of the output WNODE_METHOD_ITEM, including any output data.
  • Updates SizeDataBlock with the size of the output data, or zero if there is no output data.
  • Checks Parameters.WMI.Buffersize to determine whether the buffer is large enough to receive the output WNODE_METHOD_ITEM including any output data. If the buffer is not large enough, the driver fills in the needed size in a WNODE_TOO_SMALL structure pointed to by Parameters.WMI.Buffer. If the buffer is smaller than sizeof(WNODE_TOO_SMALL), the driver fails the IRP and returns STATUS_BUFFER_TOO_SMALL.
  • Writes output data, if any, over input data starting at DataBlockOffset. The driver must not change the input value of DataBlockOffset.

I/O Status Block

If the driver handles the IRP by calling WmiSystemControl, WMI sets Irp->IoStatus.Status and Irp->IoStatus.Information in the I/O status block.

Otherwise, the driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status such as the following:

STATUS_BUFFER_TOO_SMALL

STATUS_WMI_GUID_NOT_FOUND

STATUS_WMI_INSTANCE_NOT_FOUND

STATUS_WMI_ITEM_ID_NOT_FOUND

On success, a driver sets Irp->IoStatus.Information to the number of bytes written to the buffer at Parameters.WMI.Buffer.

Operation

A driver that handles WMI IRPs by calling WMI library support routines calls WmiSystemControl with a pointer to its WMILIB_CONTEXT structure, a pointer to its device object, and a pointer to the IRP. WmiSystemControl calls the driver's DpWmiExecuteMethod routine, or returns STATUS_INVALID_DEVICE_REQUEST to the caller if the driver does not define an entry point for such a routine.

A driver handles an IRP_MN_EXECUTE_METHOD request only if Parameters.WMI.ProviderId points to the same device object as the pointer that the driver passed to IoWMIRegistrationControl. Otherwise, the driver forwards the request to the next-lower driver.

Before handling the request, the driver determines whether Parameters.WMI.DataPath points to a GUID supported by the driver. If not, the driver fails the IRP and returns STATUS_WMI_GUID_NOT_FOUND.

If the driver supports the data block, it checks the input WNODE_METHOD_ITEM at Parameters.WMI.Buffer for the instance name, as follows:

  • If WNODE_FLAG_STATIC_INSTANCE_NAMES is set in WnodeHeader.Flags, the driver uses InstanceIndex as an index into the driver's list of static instance names for that block. WMI obtains the index from registration data that was provided by the driver when it registered the block.
  • If WNODE_FLAG_STATIC_INSTANCE_NAMES is clear in WnodeHeader.Flags, the driver uses the offset at OffsetInstanceName to locate the instance name string in the input WNODE_METHOD_ITEM. OffsetInstanceName is the offset in bytes from the beginning of the structure to a USHORT which is the length of the instance name string in bytes (not characters), including the NUL terminator if present, followed by the instance name string in Unicode.

If the driver cannot locate the specified instance, it must fail the IRP and return STATUS_WMI_INSTANCE_NOT_FOUND. In the case of a driver with a dynamic instance name, this status indicates that the driver does not "own" the instance. WMI can therefore continue to query other data providers and return an appropriate error to the data consumer if another provider finds the instance but cannot handle the request for some other reason.

The driver then checks the method ID in the input WNODE_METHOD_ITEM to determine whether it is a valid method for that data block. If not, the driver fails the IRP and returns STATUS_WMI_ITEM_ID_NOT_FOUND.

If the method generates output, the driver should check the size of the output buffer in Parameters.WMI.BufferSize before performing any operation that might have side effects or that should not be performed twice. For example, if a method returns the values of a group of counters and then resets the counters, the driver should check the buffer size (and fail the IRP if the buffer is too small) before resetting the counters. This ensures that WMI can safely resend the request with a larger buffer.

If the instance and method ID are valid and the buffer is adequate in size, the driver executes the method. If SizeDataBlock in the input WNODE_METHOD_ITEM is non-zero, the driver uses the data starting at DataBlockOffset as input for the method.

If the method generates output, the driver writes the output data to the buffer starting at DataBlockOffset and sets SizeDataBlock in the output WNODE_METHOD_ITEM to the number of bytes of output data. If the method has no output data, the driver sets SizeDataBlock to zero. The driver must not change the input value of DataBlockOffset.

If the instance is valid but the driver cannot handle the request, it can return any appropriate error status.

See Also

DpWmiExecuteMethod, IoWMIRegistrationControl, WMILIB_CONTEXT, WmiSystemControl, WNODE_METHOD_ITEM


IRP_MN_QUERY_ALL_DATA

All drivers that support WMI must handle this IRP.

When Sent

WMI sends this IRP to query for all instances of a given data block.

WMI sends this IRP at IRQL PASSIVE_LEVEL in an arbitrary thread context.

Input

Parameters.WMI.ProviderId in the driver's I/O stack location in the IRP points to the device object of the driver that should respond to the request.

Parameters.WMI.DataPath points to a GUID that identifies the data block.

Parameters.WMI.BufferSize indicates the maximum size of the nonpaged buffer at Parameters.WMI.Buffer, which receives output data from the request. The buffer size must be greater than or equal to sizeof(WNODE_ALL_DATA) plus the sizes of instance names and data for all instances to be returned.

Output

If the driver handles WMI IRPs by calling WmiSystemControl, WMI fills in a WNODE_ALL_DATA by calling the driver's DpWmiQueryDataBlock routine once for each block registered by the driver.

Otherwise, the driver fills in a WNODE_ALL_DATA structure at Parameters.WMI.Buffer as follows:

  • Sets WnodeHeader.BufferSize to the number of bytes of the entire WNODE_ALL_DATA to be returned, sets WnodeHeader.Timestamp to the value returned by KeQuerySystemTime, and sets WnodeHeader.Flags as appropriate for the data to be returned.
  • Sets InstanceCount to the number of instances to be returned.
  • If the block uses dynamic instance names, sets OffsetInstanceNameOffsets to the offset in bytes from the beginning of the WNODE_ALL_DATA to an array of offsets to dynamic instance names.
  • If all instances are the same size:
    • Sets WNODE_FLAG_FIXED_INSTANCE_SIZE in WnodeHeader.Flags and sets FixedInstanceSize to that size, in bytes.
    • Writes instance data starting at DataBlockOffset, with padding so that each instance is aligned to an 8-byte boundary. For example, if FixedInstanceSize is 6, the driver adds 2 bytes of padding between instances.
  • If instances vary in size:
    • Clears WNODE_FLAG_FIXED_INSTANCE_SIZE in WnodeHeader.Flags and writes an array of InstanceCount OFFSETINSTANCEDATAANDLENGTH structures starting at OffsetInstanceDataAndLength. Each OFFSETINSTANCEDATAANDLENGTH structure specifies the offset in bytes from the beginning of the WNODE_ALL_DATA structure to the beginning of the data for each instance, and the length of the data. DataBlockOffset is not used.
    • Writes instance data following the last element of the OffsetInstanceDataAndLength array, plus padding so that each instance is aligned to an 8-byte boundary.
  • If the block uses dynamic instance names, writes the instance names at the offsets specified in the array at OffsetInstanceNameOffsets, with each dynamic name string aligned to a USHORT boundary.

If the buffer at Parameters.WMI.Buffer is too small to receive all of the data, a driver fills in the needed size in a WNODE_TOO_SMALL structure at Parameters.WMI.Buffer. If the buffer is smaller than sizeof(WNODE_TOO_SMALL), the driver fails the IRP and returns STATUS_BUFFER_TOO_SMALL.

I/O Status Block

If the driver handles the IRP by calling WmiSystemControl, WMI sets Irp->IoStatus.Status and Irp->IoStatus.Information in the I/O status block.

Otherwise, the driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status such as the following:

STATUS_BUFFER_TOO_SMALL

STATUS_WMI_GUID_NOT_FOUND

On success, a driver sets Irp->IoStatus.Information to the number of bytes written to the buffer at Parameters.WMI.Buffer.

Operation

A driver that handles WMI IRPs by calling WMI library support routines calls WmiSystemControl with a pointer to its WMILIB_CONTEXT structure, a pointer to its device object, and a pointer to the IRP. WmiSystemControl calls the driver's DpWmiQueryDataBlock routine.

A driver handles an IRP_MN_QUERY_ALL_DATA request only if Parameters.WMI.ProviderId points to the same device object that the driver passed to IoWMIRegistrationControl. Otherwise, the driver forwards the request to the next-lower driver.

Before handling the request, the driver determines whether Parameters.WMI.DataPath points to a GUID that the driver supports. If not, the driver fails the IRP and returns STATUS_WMI_GUID_NOT_FOUND.

If the driver supports the data block, it fills in a WNODE_ALL_DATA structure at Parameters.WMI.Buffer with data for all instances of that data block.

See Also

DpWmiQueryDataBlock, IoWMIRegistrationControl, KeQuerySystemTime, WMILIB_CONTEXT, WmiSystemControl, WNODE_ALL_DATA


IRP_MN_QUERY_SINGLE_INSTANCE

All drivers that support WMI must handle this IRP.

When Sent

WMI sends this IRP to query for a single instance of a given data block.

WMI will send an IRP_MN_QUERY_SINGLE_INSTANCE prior to sending an IRP_MN_EXECUTE_METHOD. If a driver supports IRP_MN_EXECUTE_METHOD it must have a IRP_MN_QUERY_SINGLE_INSTANCE handler-for the same data block whose method is being executed.

WMI sends this IRP at IRQL PASSIVE_LEVEL in an arbitrary thread context.

Input

Parameters.WMI.ProviderId points to the device object of the driver that should respond to the request. This pointer is located in the driver's I/O stack location in the IRP.

Parameters.WMI.DataPath points to a GUID that identifies the data block to query.

Parameters.WMI.BufferSize indicates the maximum size of the nonpaged buffer at Parameters.WMI.Buffer, which points to a WNODE_SINGLE_INSTANCE structure that identifies the instance to query.

Output

If the driver handles WMI IRPs by calling WmiSystemControl, WMI fills in a WNODE_SINGLE_INSTANCE structure with data provided by the driver's DpWmiQueryDataBlock routine.

Otherwise, the driver fills in the WNODE_SINGLE_INSTANCE structure at Parameters.WMI.Buffer as follows:

  • Updates WnodeHeader.BufferSize with the size in bytes of the output WNODE_SINGLE_INSTANCE, including instance data.
  • Sets SizeDataBlock to the size in bytes of the instance data.
  • Writes the instance data to Parameters.WMI.Buffer starting at DataBlockOffset. The driver must not change the input value of DataBlockOffset.

If the buffer at Parameters.WMI.Buffer is too small to receive all of the data, the driver fills in the needed size in a WNODE_TOO_SMALL structure at Parameters.WMI.Buffer. If the buffer is smaller than sizeof(WNODE_TOO_SMALL), the driver fails the IRP and returns STATUS_BUFFER_TOO_SMALL.

I/O Status Block

If the driver handles the IRP by calling WmiSystemControl, WMI sets Irp->IoStatus.Status and Irp->IoStatus.Information in the I/O status block.

Otherwise, the driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status such as the following:

STATUS_BUFFER_TOO_SMALL

STATUS_WMI_GUID_NOT_FOUND

STATUS_WMI_INSTANCE_NOT_FOUND

On success, a driver sets Irp->IoStatus.Information to the number of bytes written to the buffer at Parameters.WMI.Buffer.

Operation

A driver that handles WMI IRPs by calling WMI library support routines calls WmiSystemControl with a pointer to its WMILIB_CONTEXT structure, a pointer to its device object, and a pointer to the IRP. WmiSystemControl calls the driver's DpWmiQueryDataBlock routine.

A driver handles an IRP_MN_QUERY_SINGLE_INSTANCE request only if Parameters.WMI.ProviderId points to the same device object as the pointer that the driver passed in its call to IoWMIRegistrationControl. Otherwise, the driver forwards the request to the next-lower driver.

Before handling the request, the driver determines whether Parameters.WMI.DataPath points to a GUID that the driver supports. If not, the driver fails the IRP and returns STATUS_WMI_GUID_NOT_FOUND.

If the driver supports the data block, it checks the input WNODE_SINGLE_INSTANCE at Parameters.WMI.Buffer for the instance name, as follows:

  • If WNODE_FLAG_STATIC_INSTANCE_NAMES is set in WnodeHeader.Flags, the driver uses InstanceIndex as an index into the driver's list of static instance names for that block. WMI obtains the index from registration data provided by the driver when it registered the block.
  • If WNODE_FLAG_STATIC_INSTANCE_NAMES is clear in WnodeHeader.Flags, the driver uses the offset at OffsetInstanceName to locate the instance name string in the input WNODE_SINGLE_INSTANCE. OffsetInstanceName is the offset in bytes from the beginning of the structure to a USHORT which is the length of the instance name string in bytes (not characters), including the NUL terminator if present, followed by the instance name string in Unicode.

If the driver cannot locate the specified instance, it must fail the IRP and return STATUS_WMI_INSTANCE_NOT_FOUND. In the case of an instance with a dynamic instance name, this status indicates that the driver does not "own" the instance. WMI can therefore continue to query other data providers and return an appropriate error to the data consumer if another provider finds the instance but cannot handle the request for some other reason.

If the driver locates the instance and can handle the request, it fills in the WNODE_SINGLE_INSTANCE structure at Parameters.WMI.Buffer with data for the instance.

If the instance is valid but the driver cannot handle the request, it can return any appropriate error status.

See Also

DpWmiQueryDataBlock, IoWMIRegistrationControl, WMILIB_CONTEXT, WmiSystemControl, WNODE_SINGLE_INSTANCE


IRP_MN_REGINFO

Drivers that support WMI on Windows® 98 and Windows 2000 must handle this IRP. (Drivers that support Windows XP as well must also handle the IRP_MN_REGINFO_EX IRP.)

When Sent

On Windows 98 and Windows 2000, WMI sends this IRP to query or update a driver's registration information after the driver has called IoWMIRegistrationControl. On Windows XP and later, WMI sends the IRP_MN_REGINFO_EX request instead.

WMI sends this IRP at IRQL PASSIVE_LEVEL in the context of a system thread.

Input

Parameters.WMI.ProviderId points to the device object of the driver that should respond to the request. This pointer is located in the driver's I/O stack location in the IRP.

Parameters.WMI.DataPath is set to WMIREGISTER to query registration information or WMIUPDATE to update it.

Parameters.WMI.BufferSize indicates the maximum size of the nonpaged buffer at Parameters.WMI.Buffer. The size must be greater than or equal to the total of (sizeof(WMIREGINFO) + (GuidCount * sizeof(WMIREGGUID)), where GuidCount is the number of data blocks and event blocks being registered by the driver, plus space for static instance names, if any.

Output

If the driver handles WMI IRPs by calling WmiSystemControl, WMI gets registration information for a driver's data blocks by calling its DpWmiQueryReginfo routine.

Otherwise, the driver fills in a WMIREGINFO structure at Parameters.WMI.Buffer as follows:

  • Sets BufferSize to the size in bytes of the WMIREGINFO structure plus associated registration data.
  • If the driver handles WMI requests on behalf of another driver, sets NextWmiRegInfo to the offset in bytes from the beginning of this WMIREGINFO to the beginning of another WMIREGINFO structure that contains registration information from the other driver.
  • Sets RegistryPath to the registry path that was passed to the driver's DriverEntry routine.
  • If Parameters.WMI.Datapath is set to WMIREGISTER, sets MofResourceName to the offset from the beginning of this WMIREGINFO to a counted Unicode string that contains the name of the driver's MOF resource in its image file.
  • Sets GuidCount to the number of data blocks and event blocks to register or update.
  • Writes an array of WMIREGGUID structures, one for each data block or event block exposed by the driver, at WmiRegGuid.

The driver fills in each WMIREGGUID structure as follows:

  • Sets Guid to the GUID that identifies the block.
  • Sets Flags to provide information about instance names and other characteristics of the block. For example, if a block is being registered with static instance names, the driver sets Flags with the appropriate WMIREG_FLAG_INSTANCE_XXX flag.

If the block is being registered with static instance names, the driver:

  • Sets InstanceCount to the number of instances.
  • Sets one of the following members to an offset in bytes to static instance name data for the block:
    • If the driver sets Flags with WMIREG_FLAG_INSTANCE_LIST, it sets InstanceNameList to an offset to a list of static instance name strings. WMI specifies instances in subsequent requests by index into this list.
    • If the driver sets Flags with WMIREG_FLAG_INSTANCE_BASENAME, it sets BaseNameOffset to an offset to a base name string. WMI uses this string to generate static instance names for the block.
    • If the driver sets Flags with WMIREG_FLAG_INSTANCE_PDO, it sets Pdo to an offset to a pointer to the PDO passed to the driver's AddDevice routine. WMI uses the device instance path of the PDO to generate static instance names for the block.
  • Writes the instance name strings, the base name string, or a pointer to the PDO at the offset indicated by InstanceNameList, BaseName, or Pdo, respectively.

If the driver handles WMI registration on behalf of another driver (such as a miniclass or miniport driver), it fills in another WMIREGINFO structure with the other driver's registration information and writes it at NextWmiRegInfo in the previous structure.

If the buffer at Parameters.WMI.Buffer is too small to receive all of the data, a driver writes the needed size in bytes as a ULONG to Parameters.WMI.Buffer and fails the IRP and returns STATUS_BUFFER_TOO_SMALL.

I/O Status Block

If the driver handles the IRP by calling WmiSystemControl, WMI sets Irp->IoStatus.Status and Irp->IoStatus.Information in the I/O status block.

Otherwise, the driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status such as the following:

STATUS_BUFFER_TOO_SMALL

On success, a driver sets Irp->IoStatus.Information to the number of bytes written to the buffer at Parameters.WMI.Buffer.

Operation

A driver that handles WMI IRPs by calling WMI library support routines calls WmiSystemControl with a pointer to its WMILIB_CONTEXT structure, a pointer to its device object, and a pointer to the IRP. WmiSystemControl calls the driver's DpWmiQueryReginfo routine.

A driver handles an IRP_MN_REGINFO request only if Parameters.WMI.ProviderId points to the same device object as the pointer that the driver passed to IoWMIRegistrationControl. Otherwise, the driver forwards the request to the next-lower driver.

Before handling the request, the driver checks Parameters.WMI.DataPath to determine whether WMI is querying registration information (WMIREGISTER) or requesting an update (WMIUPDATE).

WMI sends this IRP with WMIREGISTER after a driver calls IoWMIRegistrationControl with WMIREG_ACTION_REGISTER or WMIREG_ACTION_REREGISTER. In response, a driver should fill in the buffer at Parameters.WMI.Buffer with the following:

  • A WMIREGINFO structure that indicates the driver's registry path, the name of its MOF resource, and the number of blocks to register.
  • One WMIREGGUID structure for each block to register. If a block is to be registered with static instance names, the driver sets the appropriate WMIREG_FLAG_INSTANCE_XXX flag in the WMIREGGUID structure for that block.
  • Any strings WMI needs to generate static instance names.

WMI sends this IRP with WMIUPDATE after a driver calls IoWmiRegistrationControl with WMIREG_ACTION_UPDATE_GUID. In response, a driver should fill in the buffer at Parameters.WMI.Buffer with a WMIREGINFO structure as follows:

  • To remove a block, the driver sets WMIREG_FLAG_REMOVE_GUID in its WMIREGGUID structure.
  • To add or update a block (for example, to change its static instance names), the driver clears WMIREG_FLAG_REMOVE_GUID and provides new or updated registration values for the block.
  • To register a new or existing block with static instance names, the driver sets the appropriate WMIREG_FLAG_INSTANCE_XXX and supplies any strings WMI needs to generate static instance names.

A driver can use the same WMIREGINFO structures to remove, add, or update blocks as it used initially to register all of its blocks, changing only the flags and data for the blocks to be updated. If a WMIREGGUID in such a WMIREGINFO structure matches exactly the WMIREGGUID passed by the driver when it first registered that block, WMI skips the processing involved in updating the block.

WMI does not send an IRP_MN_REGINFO request after a driver calls IoWMIRegistrationControl with WMIREG_ACTION_DEREGISTER, because WMI requires no further information from the driver. A driver typically deregisters its blocks in response to an IRP_MN_REMOVE_DEVICE request.

See Also

DpWmiQueryReginfo, IoWMIRegistrationControl, WMILIB_CONTEXT, WMIREGGUID, WMIREGINFO, WmiSystemControl, IRP_MN_REGINFO_EX


IRP_MN_REGINFO_EX

On Windows XP and later, drivers that support WMI must handle this IRP. (Drivers that support Windows 98 and Windows 2000 as well must also handle the IRP_MN_REGINFO IRP).

When Sent

On Windows XP and later, WMI sends this IRP to query or update a driver's registration information after the driver has called IoWMIRegistrationControl. On Windows 98 and Windows 2000, WMI sends the IRP_MN_REGINFO request instead.

WMI sends this IRP at IRQL PASSIVE_LEVEL in the context of a system thread.

Input

Parameters.WMI.ProviderId points to the device object of the driver that should respond to the request. This pointer is located in the driver's I/O stack location in the IRP.

Parameters.WMI.DataPath is set to WMIREGISTER to query registration information or WMIUPDATE to update it.

Parameters.WMI.BufferSize indicates the maximum size of the nonpaged buffer at Parameters.WMI.Buffer. The size must be greater than or equal to the total of (sizeof(WMIREGINFO) + (GuidCount * sizeof(WMIREGGUID)), where GuidCount is the number of data blocks and event blocks being registered by the driver, plus space for static instance names, if any.

Output

If the driver handles WMI IRPs by calling WmiSystemControl, WMI gets registration information for a driver's data blocks by calling its DpWmiQueryReginfo routine.

Otherwise, the driver fills in a WMIREGINFO structure at Parameters.WMI.Buffer as follows:

  • Sets BufferSize to the size in bytes of the WMIREGINFO structure plus associated registration data.
  • If the driver handles WMI requests on behalf of another driver, sets NextWmiRegInfo to the offset in bytes from the beginning of this WMIREGINFO to the beginning of another WMIREGINFO structure that contains registration information from the other driver.
  • Sets RegistryPath to the registry path that was passed to the driver's DriverEntry routine.
  • If Parameters.WMI.Datapath is set to WMIREGISTER, sets MofResourceName to the offset from the beginning of this WMIREGINFO to a counted Unicode string that contains the name of the driver's MOF resource in its image file.
  • Sets GuidCount to the number of data blocks and event blocks to register or update.
  • Writes an array of WMIREGGUID structures, one for each data block or event block exposed by the driver, at WmiRegGuid.

The driver fills in each WMIREGGUID structure as follows:

  • Sets Guid to the GUID that identifies the block.
  • Sets Flags to provide information about instance names and other characteristics of the block. For example, if a block is being registered with static instance names, the driver sets Flags with the appropriate WMIREG_FLAG_INSTANCE_XXX flag.

If the block is being registered with static instance names, the driver:

  • Sets InstanceCount to the number of instances.
  • Sets one of the following members to an offset in bytes to static instance name data for the block:
    • If the driver sets Flags with WMIREG_FLAG_INSTANCE_LIST, it sets InstanceNameList to an offset to a list of static instance name strings. WMI specifies instances in subsequent requests by index into this list.
    • If the driver sets Flags with WMIREG_FLAG_INSTANCE_BASENAME, it sets BaseNameOffset to an offset to a base name string. WMI uses this string to generate static instance names for the block.
    • If the driver sets Flags with WMIREG_FLAG_INSTANCE_PDO, it sets Pdo to an offset to a pointer to the PDO passed to the driver's AddDevice routine. WMI uses the device instance path of the PDO to generate static instance names for the block. Drivers must call ObReferenceObject on the physical device object passed in Pdo. (Drivers that use WmiSystemControl to handle IRPs do not need to do so. WMI automatically does so before calling the driver's DpWmiQueryReginfo routine.)
  • Writes the instance name strings, the base name string, or a pointer to the PDO at the offset indicated by InstanceNameList, BaseName, or Pdo, respectively.

If the driver handles WMI registration on behalf of another driver (such as a miniclass or miniport driver), it fills in another WMIREGINFO structure with the other driver's registration information and writes it at NextWmiRegInfo in the previous structure.

If the buffer at Parameters.WMI.Buffer is too small to receive all of the data, a driver writes the needed size in bytes as a ULONG to Parameters.WMI.Buffer and fails the IRP and returns STATUS_BUFFER_TOO_SMALL.

I/O Status Block

If the driver handles the IRP by calling WmiSystemControl, WMI sets Irp->IoStatus.Status and Irp->IoStatus.Information in the I/O status block.

Otherwise, the driver sets Irp->IoStatus.Status to STATUS_SUCCESS or to an appropriate error status such as the following:

STATUS_BUFFER_TOO_SMALL

On success, a driver sets Irp->IoStatus.Information to the number of bytes written to the buffer at Parameters.WMI.Buffer.

Operation

A driver that handles WMI IRPs by calling WMI library support routines calls WmiSystemControl with a pointer to its WMILIB_CONTEXT structure, a pointer to its device object, and a pointer to the IRP. WmiSystemControl calls the driver's DpWmiQueryReginfo routine.

A driver handles an IRP_MN_REGINFO_EX request only if Parameters.WMI.ProviderId points to the same device object as the pointer that the driver passed to IoWMIRegistrationControl. Otherwise, the driver forwards the request to the next-lower driver.

Before handling the request, the driver checks Parameters.WMI.DataPath to determine whether WMI is querying registration information (WMIREGISTER) or requesting an update (WMIUPDATE).

WMI sends this IRP with WMIREGISTER after a driver calls IoWMIRegistrationControl with WMIREG_ACTION_REGISTER or WMIREG_ACTION_REREGISTER. In response, a driver should fill in the buffer at Parameters.WMI.Buffer with the following:

  • A WMIREGINFO structure that indicates the driver's registry path, the name of its MOF resource, and the number of blocks to register.
  • One WMIREGGUID structure for each block to register. If a block is to be registered with static instance names, the driver sets the appropriate WMIREG_FLAG_INSTANCE_XXX flag in the WMIREGGUID structure for that block.
  • Any strings WMI needs to generate static instance names.

WMI sends this IRP with WMIUPDATE after a driver calls IoWmiRegistrationControl with WMIREG_ACTION_UPDATE_GUID. In response, a driver should fill in the buffer at Parameters.WMI.Buffer with a WMIREGINFO structure as follows:

  • To remove a block, the driver sets WMIREG_FLAG_REMOVE_GUID in its WMIREGGUID structure.
  • To add or update a block (for example, to change its static instance names), the driver clears WMIREG_FLAG_REMOVE_GUID and provides new or updated registration values for the block.
  • To register a new or existing block with static instance names, the driver sets the appropriate WMIREG_FLAG_INSTANCE_XXX and supplies any strings WMI needs to generate static instance names.

A driver can use the same WMIREGINFO structures to remove, add, or update blocks as it used initially to register all of its blocks, changing only the flags and data for the blocks to be updated. If a WMIREGGUID in such a WMIREGINFO structure matches exactly the WMIREGGUID passed by the driver when it first registered that block, WMI skips the processing involved in updating the block.

WMI does not send an IRP_MN_REGINFO_EX request after a driver calls IoWMIRegistrationControl with WMIREG_ACTION_DEREGISTER, because WMI requires no further information from the driver. A driver typically deregisters its blocks in response to an IRP_MN_REMOVE_DEVICE request.

See Also

DpWmiQueryReginfo, IoWMIRegistrationControl, WMILIB_CONTEXT, WMIREGGUID, WMIREGINFO, WmiSystemControl, IRP_MN_REGINFO


Device Installation Overview

Before reading this section, see Providing an Installation Package for an introduction to the concepts and requirements you'll need to know concerning device installation.

Setup works with other system-supplied components and with vendor-supplied components to install devices. Setup installs devices when the system boots and at any time after boot when a user plugs in a Plug and Play (PnP) device (or manually installs a non-PnP device).

In support of PnP, Setup proceeds with device installation based on the devices in the system, rather than structuring installation around the drivers. For example, rather than loading a set of drivers and having those drivers detect the devices that they support, Setup determines the devices that are present in the system and loads and calls the drivers for each device. Drivers such as the ACPI driver and other PnP bus drivers help Setup determine which devices are present.

This section includes:

Device Installation Components

Device Installation Files

Device Installation Types

System Setup Phases

Sample PnP Device Installation

How Setup Selects Drivers

Installing Devices on 64-Bit Systems

Driver Information in the Registry

RunOnce Registry Entries


Device Installation Components

The following figure shows the software components involved in installing a device.

Device Installation Setup Components

The shaded boxes in the figure represent components that can be provided by independent hardware vendors (IHV) and original equipment manufacturers (OEM). The other device installation components are supplied by Microsoft.

The following list describes the roles that the various components play in device installation:

Kernel-Mode PnP Manager
The kernel-mode PnP Manager notifies the user-mode PnP Manager that a new device is present on the system and needs to be installed. The kernel-mode PnP Manager also calls the DriverEntry and AddDevice routines of a device's drivers and sends the IRP_MN_START_DEVICE request to start the device.

The PnP Manager has two parts: one runs in user-mode and the other runs in kernel mode. The kernel-mode PnP Manager reports PnP events to the user-mode PnP Manager, and the user-mode PnP Manager sends control requests to the kernel-mode PnP Manager.

Drivers
PnP drivers perform device-installation operations as directed by the PnP Manager. For example:
  • When the PnP Manager sends the driver an IRP_MN_QUERY_DEVICE_RELATIONS request for BusRelations, a PnP bus driver returns a list of its child devices.
  • The PnP Manager calls each PnP driver's DriverEntry and AddDevice routines.
  • The PnP Manager also send such additional requests as IRP_MN_QUERY_CAPABILITIES, IRP_MN_START_DEVICE, and IRP_MN_REMOVE_DEVICE.

PnP drivers can also detect nonPnP devices and report them to the PnP Manager using IoReportDetectedDevice.

User-Mode PnP Manager
The user-mode PnP Manager receives device installation requests from the kernel-mode PnP Manager, calls other user-mode Setup components to initiate device-installation tasks, and sends control requests (such as "start the device") to the kernel-mode PnP Manager.

The user-mode PnP Manager and the kernel-mode PnP Manager together maintain the device tree.

The user-mode PnP Manager tries to install a device in a trusted process context without requiring user responses to dialog boxes (a server-side installation). This automatic installation provides a better user experience. If the PnP Manager is unable to complete a trusted installation because, for example, an installer supplies custom Finish pages, the PnP Manager terminates the trusted installation. In this case, when a user with administrative privileges logs in, the PnP Manager restarts the device installation by launching the Found New Hardware wizard in the New Device DLL (a client-side installation).

Setup API
The Setup API includes the general Setup functions (Setup Xxx) and the device installation functions (SetupDi Xxx). These functions perform many device installation tasks such as searching for INF files, building a potential list of drivers for a device, copying driver files, writing information to the registry, registering device co-installers, and so forth. Most other Setup components call these functions.

The SetupDi Xxx functions are also sometimes referred to as the device installer. This term can be confusing, however, because more than one component is involved in installing a device.

For more information, see General Setup Functions and Device Installation Functions.

CfgMgr API
The Configuration Manager API provides basic installation and configuration operations that are not provided by Setup API. The Configuration Manager Functions perform low-level tasks such as getting the status of a devnode and managing resource descriptors. These functions are primarily called by Setup API but can also be called by other Setup components.
Co-installers and Class Installers
A class installer performs installation operations that apply to devices in a particular device setup class. For example, the ports class installer is responsible for assigning a COM port name to a device in the ports setup class. If the devices in a particular setup class do not require any special installation operations, a class installer is not required for that setup class.

Microsoft provides class installers for most of the system-defined device setup classes. For more information, see Writing a Class Installer. IHVs and OEMs can provide class installers, but they typically provide co-installers.

A co-installer performs installation operations that are specific to a particular device or to a setup class of devices. For more information, see Writing a Co-installer.

INF Files and Catalog files
INF files and catalog files provide information about devices and drivers to be installed. For more information, see Creating an INF File.
Device Manager
The Device Manager allows a user to view and manage the devices on a system. For example, a user can view device status and set device properties. If a user requests to update a driver, the Device Manager calls the Hardware Update wizard in the New Device DLL.

For more information, see Using the Device Manager. Also see the Device Manager's online help.

Add Hardware Wizard
The Add Hardware Wizard allows a user to add, remove, unplug, and troubleshoot devices.
New Device DLL
The New Device DLL contains the Found New Hardware wizard, the Hardware Update wizard, and the UpdateDriverForPlugAndPlayDevices function.

The user-mode PnP Manager calls the Found New Hardware wizard to initiate a client-side installation of a new device in the context of a user with the appropriate privileges. The Device Manager calls the Hardware Update wizard when a user clicks the Update Driver button on a device's Driver property page. The Found New Hardware and Hardware Update wizards call Setup APIs and Configuration Manager APIs to accomplish their tasks.

Custom Device Installation Application
An IHV or OEM can provide a custom device installation application. For more information, see Writing a Device Installation Application.


Device Installation Files

The software required to support a particular device depends on the kind of device and the ways in which the device is used. Typically, a vendor provides the following software in a driver package to support a device:

  • A device setup information file (INF file).

    An INF file contains information that the system Setup components use to install support for the device. Setup copies this file to the %windir%\inf directory when it installs the driver. This file is required.

    For more information, see Creating an INF file.

  • One or more drivers for the device.

    A .sys file is the driver's image file. Setup copies this file to the %windir%\system32\drivers directory when the driver is installed. Drivers are required for most devices. For more information, see Determining Device-Specific Driver Requirements.

  • Digital signatures for the driver package (a driver catalog file).

    A driver catalog file contains digital signatures. All driver packages should be signed.

    A vendor gets digital signatures by submitting its driver package to the Windows Hardware Quality Lab (WHQL) for testing and signing. WHQL returns the package with a catalog file (.cat file). For more information, see Driver Signing.

  • One or more co-installers.

    A co-installer is a Win32® DLL that assists in device installation. For example, an IHV might provide a co-installer to write device-specific information to the registry that cannot be handled by the INF. Co-installers are optional. For more information, see Writing a Co-installer.

  • Other files.

    A driver package can contain other files, such as a Custom Device Installation Application, a device icon, a driver library file (for example, for video drivers), and so forth. For more information, see:

    Writing a Device Installation Application
    Providing Device Property Pages
    Drivers with Special Installation Requirements

    Also, see the device type-specific documentation in this DDK.


Device Installation Types

Windows defines two types of device installations: those that occur on the "server side" and those that occur on the "client side". Because they do not require user intervention by an administrator, server-side installations are more desirable than client-side installations.

Server-side Installations

A server-side installation is a device installation that can be handled entirely by the system's user-mode and kernel-mode PnP Manager components. A server-side installation can occur only if:

  • The device can be detected by a bus driver, which then must notify the PnP Manager.
  • The PnP Manager can find an INF file containing a hardware ID that matches that of the device.
  • The device's INF file and drivers are signed (see Driver Signing).
  • SetupAPI can locate all of the device's drivers without prompting the user for media locations. (This means the drivers are included "in-box" with the operating system, a vendor-supplied driver was previously installed, or vendor-supplied driver files have been "pre-installed" so SetupAPI can locate them during the actual installation (see Pre-installing Driver Files).
  • The device's class installer and co-installers do not display property pages at the end of the installation operation.
  • The device's INF file has not marked the device as requiring an interactive installation (by specifying InteractiveInstall in an INF ControlFlags section).
  • RunOnce registry entries consist only of calls to rundll32.exe.

Server-side installations do not display any user interface and do not require an administrator to be logged on. (The term "server-side" is used because installation can be accomplished by the system's PnP Manager without a user-mode "client" making calls into the PnP Manager.)

Client-side Installations

A client-side installation is a device installation that requires communication with a user. A client-side installation occurs if any of the following are true:

  • The PnP Manager cannot find an INF file containing a hardware ID that matches that of the device.
  • The PnP Manager cannot locate all the required driver files.
  • The device's INF or driver files are not signed.
  • SetupAPI has to display any form of user interface, such as prompting the user for media locations.
  • A class installer or co-installer displays property pages at the end of the installation operation.
  • The device, bus, or bus driver does not support Plug and Play.

Client-side installations require use of installation "client" software, such as the Add Hardware wizard, the New Device DLL, or a vendor-supplied device installation application. This client software installs the device by making calls to SetupAPI, which in turn calls the PnP Manager when necessary. (The PnP Manager is considered to be the installation operation's "server side.")


System Setup Phases

For most devices, you should design your device and supporting files so that Setup can install the device at an appropriate time during system startup, or dynamically at any time after startup while the system is running. Certain devices, however, must be installed during a particular phase of system startup. To assist vendors of such devices, this section provides some background information on the system setup phases as they relate to device installation.

Installations During Text-Mode Setup

When Windows® boots on a system, the initial phase of the Setup program installs only the minimum number of devices needed for Windows to run, such as the keyboard, mouse, video adapter, SCSI/Disk, and Machine/HAL. This phase of the Setup program is known as text-mode setup.

For a user to install your device during text-mode setup, your distribution disk must include a text file named txtsetup.oem. For more information, see Installing a Boot Driver.

Installations During GUI-Mode Setup

After text-mode setup has completed, the Setup program boots Windows and proceeds with the GUI-mode setup phase of the installation. Setup installs most devices during GUI-mode setup.

Devices that are not installed during GUI-mode setup include those that require user interaction to be installed. For example, if this is the first time a device is being configured on the system and a co-installer for the device supplies one or more custom Finish pages, Setup must display the pages to the user. Setup performs such a device installation when a user with administrative privileges logs on.

Installations After the System is Running

Once a system is up and running, a user can install new devices:

  • To install a new PnP device, plug the device into the system.

    If the device and the bus support hot-plug notification, device installation is initiated automatically.

    If the user needs to power down the system and open the system box to plug in the device, the device will be recognized and configured when the system boots.

    If the device can be plugged in while the system is running and the device and the bus do not support hot-plug notification, use the Add Hardware Wizard to initiate device configuration. (Select Install.)

  • To install a nonPnP device, use the Add Hardware Wizard.

If Setup can install the device in the trusted context of a system process, the user does not need administrative privileges to install the device. If Setup needs to prompt the user for information, it requires the process context of an administrative user to install the device.

To update a driver for an installed device, use the Device Manager or the Hardware tab of the appropriate control panel applet. (Clicking the Properties button in the Hardware tab of a Control Panel applet brings up the Device Manager properties for the device.)


Sample PnP Device Installation

To illustrate the interaction of the components involved in device installation, this section steps through the installation of a hot-plug PnP device with an accompanying CD of supporting files.

The following figure shows the software components that participate in installing the PnP device. The shaded components are items that a device vendor might supply.

Sample PnP Device Installation

The following notes correspond to the circled numbers in the figure:

  1. The user plugs the device into the computer.

    If the device and the bus support hot-plug notification, the user can plug in a new device while the system is running.

  2. The device is enumerated.

    The bus driver, with support from the bus, receives hot-plug notification of the new device. The bus driver notifies the kernel-mode PnP Manager that the list of devices on the bus has changed by calling IoInvalidateDeviceRelations. In this case, the change is a new device on the bus.

    The kernel-mode PnP Manager queries the bus driver for a list of devices present on the bus by sending an IRP_MJ_PNP with IRP_MN_QUERY_DEVICE_RELATIONS for BusRelations. The bus driver responds to the IRP with current list of devices on the bus. The kernel-mode PnP Manager compares the new list against the previous list and, in this case, determines that there is one new device on the bus.

    The kernel-mode PnP Manager sends IRPs to the bus driver to gather information about the new device, such as the device's hardware IDs, compatible IDs, and device capabilities. The IRPs include IRP_MN_QUERY_ID and IRP_MN_QUERY_CAPABILITIES. For more information on the enumeration activities of the kernel-mode PnP Manager, see Adding a PnP Device to a Running System.

  3. The kernel-mode PnP Manager notifies the user-mode PnP Manager that there is a device to be installed.

    The user-mode PnP Manager tries to perform a trusted installation (a server-side installation), but it cannot in this example because it needs to display a UI to ask the user for an installation disk for the device.

  4. The user-mode PnP Manager creates a new process using rundll32.exe and launches newdev.dll to install the device.
  5. The New Device DLL calls device installation functions (Setup API)and PnP Configuration Manager functions (CfgMgr API) to carry out its installation tasks.

    The New Device DLL calls SetupDiBuildDriverInfoList to build the list of possible drivers for the device. In this example, none of the INFs on the system matches the new device, so the returned driver list is empty. The New Device DLL displays the Found New Device wizard. The user supplies the location of the drivers (floppy disk, CD, or Windows® Update). In this example, the driver files are on a CD, so the user loads the CD and clicks Next in the wizard. The New Device DLL calls SetupDiBuildDriverInfoList again with the new location and receives a list that contains the drivers from the CD.

    For more information on driver selection, see How Setup Selects Drivers.

    (Note that for this example, in which the device's drivers are not included with the operating system, the sequence described is valid only if the user plugs in the new device after the operating system has been installed. If a device without "in box" drivers is plugged in before the operating system is installed, the Device Manager will show the device as "unknown".)

  6. The class installer and co-installers, if any, can participate in the installation by handling DIF requests.

    For example, the New Device DLL calls SetupDiCallClassInstaller to send the DIF_SELECTBESTCOMPATDRV installation request. SetupDiCallClassInstaller sends the DIF request to any class co-installers that are registered for the device and to the class installer for the device, if there is one.

    The New Device DLL sends a series of DIF codes, including DIF_SELECTBESTCOMPATDRV, DIF_ALLOW_INSTALL, DIF_INSTALLDEVICEFILES, DIF_REGISTER_COINSTALLERS, DIF_INSTALLINTERFACES, and DIF_INSTALLDEVICE. The class installer and co-installers can participate in servicing these DIF codes.

    Setup uses the Class and ClassGUID entries in the device's INF Version section to determine the device setup class. The setup class determines the class installer and the class co-installers for the device, if any. Device-specific co-installers are listed in the INF DDInstall.Coinstallers section. For more information on installers, see Writing a Co-installer and Writing a Class Installer.

  7. Setup transfers control to kernel mode to load drivers and start the device.

    Once Setup has selected the best driver for the device, copied the appropriate driver files, registered any device-specific co-installers, registered any device interfaces, and so forth, it transfers control to kernel mode to load the drivers and start the device. The appropriate CfgMgr function sends a request to the user-mode PnP Manager, which passes it to the kernel-mode PnP Manager.

  8. The PnP Manager loads the appropriate function driver and any optional filter drivers for the device.

    The PnP Manager calls the DriverEntry routine for any required driver that is not yet loaded. The PnP Manager then calls the AddDevice routine for each driver, starting with lower filter drivers, then the function driver, and, lastly, any upper filter drivers. The PnP Manager assigns resources to the device, if required, and sends an IRP_MN_START_DEVICE to the device's drivers.

  9. Installers can supply wizard pages to change device settings.

    Setup sends a DIF_NEWDEVICEWIZARD_FINISHINSTALL request before it displays the standard Finish page. This is an opportunity for installers to add custom pages to change device settings, if necessary.


How Setup Selects Drivers

Setup selects a driver for each device, unless the device is being used in raw mode. This section describes how Setup makes that selection.

Setup's concept of a driver is really a driver node, which includes all the support for a device, such as any services, device-specific co-installers, registry entries, and so forth. The services for a device can include a set of PnP drivers (a function driver and any upper and lower filter drivers).

Some devices require a vendor-supplied driver that is designed specifically for that device. Other devices can be driven by a vendor-supplied driver that is designed to support a family of devices. Still other devices can be driven by a system-supplied driver that supports all the devices of a given device setup class. To choose a driver for a device, Setup prefers a driver that is a specific match for the device. If it does not find such a driver, it chooses from successively more general drivers.

To locate a driver match, Setup compares the device's hardware IDs and compatible IDs, as reported by the device's parent bus driver, to the hardware IDs and compatible IDs listed in the INF files on the system. Setup creates a list of possible drivers for the device; that is, drivers whose INF Models section entries contain an ID that matches one of the device's IDs. (For more information about hardware IDs and compatible IDs, see Device Identification Strings.)

If Setup does not find a match in any of the installed INF files it starts up the Found New Hardware wizard, which prompts the user for a driver.

Setup assigns a "rank" to each possible driver. The rank indicates how well the driver matches the device. The lower the rank number, the better a match the driver is for the device. A rank of zero represents the best match.

For Windows 2000 (and for Windows Me), if more than one driver has the same lowest rank, Setup chooses the driver with the most recent date. A driver's date is specified by an INF DriverVer directive. If two drivers have the same rank and the same date, Setup can choose either one, with the following exceptions:

  • For Windows 2000 only, Setup sets the date to 00/00/0000 if the driver is not digitally signed (see Driver Signing).
  • For some device setup classes, Windows Me might block installation of an unsigned driver if a signed driver is already installed for the device.

For Windows XP and later, some driver packages are considered to be "trusted" while others are "untrusted". All signed driver packages are trusted, and all unsigned driver packages are untrusted.

Note that a driver that is signed for a particular operating system version might not be considered to be signed for another operating system version.

For NT®-based systems, Setup assigns ranks to trusted drivers as follows:

Trusted Driver Rank | Description
0x0-0xFFF | Matched a device's hardware ID with the hardware ID in an INF Models section. A rank N match means that the device's N+1 hardware ID matched the INF hardware ID.
0x1000-0x1FFF | Matched one of the device's hardware IDs with a compatible ID in an INF Models section.
0x2000-0x2FFF | Matched one of the device's compatible IDs with the hardware ID in an INF Models section.
0x3000-0x3FFF | Matched one of the device's compatible IDs with a compatible ID in an INF Models section.

Driver ranks in the range 0x0-0xFFF are called "hardware ID matches" because they match hardware ID to hardware ID. These are the best matches. All other ranks are called "compatible ID matches" because the match involves at least one compatible ID. If Setup determines that a driver package for an NT-based system is untrusted, it raises the driver package's rank to a value within the appropriate untrusted rank range.

Setup assigns ranks to untrusted drivers as follows:

Untrusted Driver Rank | Description
0x8000-0x8FFF | Hardware IDs that match unsigned drivers through decorated INF sections.
0x9000-0xBFFF | Compatible IDs that match unsigned drivers through decorated INF sections.
0xC000-0xCFFF | Hardware IDs that match unsigned drivers through undecorated INF sections. Probably a Windows 9x/Me-only driver.
0xD000-0xFFFE | Compatible IDs that match unsigned drivers through undecorated INF sections. Probably a Windows 9x/Me-only driver.
0xFFFF | Worst-case match. This is a special value used by components such as co-installers.

When Setup installs a device in the context of an administrative user process (a client-side installation), it starts the Found New Hardware wizard if the driver rank is only a compatible ID match or if its rank is within the untrusted ranges. The wizard asks the user whether he or she has a better driver for the device.

For example, consider a device with two hardware IDs and two compatible IDs. The syntax of the IDs is defined in the glossary. This discussion refers to the IDs using the following shorthand names:

HwID_1, HwID_2, CID_1, and CID_2

The first hardware ID in a list of hardware IDs is the most precise identification for the device. In this example, that is HwID_1.

For this example, assume there is a signed INF file with a Models section that has an entry like the following:

DeviceDesc1 = InstallSection1, INF_HWID_1, INF_CID_1

Again, the INF_XXX_N names are shorthand for the hardware IDs and compatible IDs listed in the INF Models section.

The following table lists the ranks for the possible matches that Setup can make when comparing the sample device's IDs against the IDs in the INF files:

Device's IDs | IDs in INF Models Section
 | INF_HwID_1 | INF_CID_1
HwID_1 | Rank 0 | Rank 1000-1FFF
HwID_2 | Rank 1 | Rank 1000-1FFF
CID_1 | Rank 2000-2FFF | Rank 3000-3FFF
CID_2 | Rank 2000-2FFF | Rank 3000-3FFF

In this example, Setup starts by comparing the device's first hardware ID, HwID_1, with the IDs in the INF files on the system. If Setup matches the HwID_1 string with the first hardware ID listed in an INF Models section, it adds that driver node to its list of potential drivers and ranks that match as a "rank 0" match. If Setup matches any other INF Models entries with HwID_1, it ranks those matches and adds them to its list of potential drivers.

Next, Setup compares the device's additional hardware IDs, if any, with the IDs in the INF files. If it finds any matches, it ranks them and adds them to its list of potential drivers for this device. Then, it follows the same process for the device's compatible IDs, if any.

After Setup builds its complete list of potential drivers, it selects the best driver for the device (the driver with the lowest rank). If more than one driver has the lowest rank, Setup uses the driver's date, contained in the INF file's DriverVer directive, to choose among those drivers.

  • For Windows® XP and later (and Windows Me), Setup chooses the driver with the most recent date.
  • For Windows 2000, Setup chooses the driver with the most recent date only if the driver packages are signed. Otherwise, Setup ignores DriverVer entries and uses a default date of 00/00/0000.

If two drivers have the same rank and the same date, Setup can choose either one.

Class installers and co-installers can participate in driver selection by handling the DIF_SELECTBESTCOMPATDRV request (or the DIF_SELECTDEVICE request for a manually installed device). Setup sends this DIF codes after it builds its list of potential drivers but before it selects the best driver. When handling these DIF codes, a class installer or co-installer can set the DNF_BAD_DRIVER flag on a potential driver if the installer is able to determine that the driver does not support the device. If DNF_BAD_DRIVER is set on a potential driver node, Setup ignores the driver when making its selection.

An installer can also participate in driver selection by changing the rank of a potential driver when the installer handles the DIF_SELECTBESTCOMPATDRV (or DIF_SELECTDEVICE) request. However, the only way an installer should modify driver rank is by setting the rank to 0xFFFF. This rank value indicates that the driver can be used for the device, but only as a last choice option. Installers must not set intermediate values for driver rank because they might interfere with proper driver selection and because the rank ranges are subject to change.

Instead of modifying the driver selection process, a class installer or co-installer can override Setup's entire selection process and directly choose the driver for a device. (See DIF_SELECTBESTCOMPATDRV and DIF_SELECTDEVICE for more information.) However, this is not recommended because Setup's selection algorithms might be enhanced in a future release. When an installer directly selects a driver, Setup's selection operations are terminated.

To illustrate driver selection, consider a sample video device that matches three driver nodes in the INF files on the system. The device's parent bus driver (pci.sys) reports the following device IDs:

The device's hardware IDs:
PCI\VEN_FFFF&DEV_493D&SUBSYS_001C105D&REV_00
PCI\VEN_FFFF&DEV_493D&SUBSYS_001C105D
PCI\VEN_FFFF&DEV_493D&CC_030000
PCI\VEN_FFFF&DEV_493D&CC_0300
The device's compatible IDs:
PCI\VEN_FFFF&DEV_493D&REV_00
PCI\VEN_FFFF&DEV_493D
PCI\VEN_FFFF&CC_030000
PCI\VEN_FFFF&CC_0300
PCI\VEN_FFFF
PCI\CC_030000
PCI\CC_0300

In this example, Setup finds three driver nodes in the INF files that match the device's IDs. The first driver node in the Models section of an INF that matches is the following:

%Sample1%  = Sample1.DDInstall, PCI\VEN_FFFF&DEV_493D&CC_0300

The device's fourth hardware ID matches the hardware ID in this INF entry, so this is a "rank 3" driver match. Setup adds this driver to its list of potential drivers for the device. This driver supports any video device of this type (a video device with any subsystem vendor ID and any hardware revision number).

The second INF entry that Setup matches for the device has the following driver node in its Models section:

%Sample2%  = Sample2.DDInstall, \
    PCI\VEN_FFFF&DEV_493D&SUBSYS_001C105D

The device's second hardware ID matches the hardware ID in this INF entry, so this is a "rank 1" driver match. Setup adds this driver to its list of potential drivers for the device. This driver supports devices with this specific subsystem vendor ID and with any hardware revision number.

The third INF entry that Setup matches for the device has the following driver node in its Models section:

%Sample3%  = vga, PCI\CC_0300

The device's last compatible ID matches the hardware ID in this INF entry, so this driver match has a rank in the range 2000-2FFF. Setup adds this driver to its list of potential drivers for the device. This driver is a generic driver (the VGA driver) that supports any PCI video device.

For this example, if the co-installers and class installer do not modify the ranks that Setup assigned to the driver matches, Setup chooses the rank 1 driver, %Sample2%.


Device Installations Requiring a Reboot

Device installations should not force the user to reboot the system unless absolutely necessary. The following circumstances are the only ones for which a system reboot should be necessary:

  • Installing or removing a non-Plug and Play device.

    For these legacy devices, a user typically must shut down the system before physically adding or removing the device. After the power is turned back on, the system reboots. Note that the device's setup files should not initiate a reboot, regardless of whether the user installs the drivers before or after plugging in the hardware.

  • Updating a driver for a system boot device.

    If a device can potentially hold the system's paging, hibernation, or crash dump file, its drivers must service IRP_MN_DEVICE_USAGE_NOTIFICATION requests. The system sends this request before placing one of these files on the disk. If the drivers succeed the request, they must fail any subsequent IRP_MN_QUERY_REMOVE_DEVICE requests. When a driver for the device fails an IRP_MN_QUERY_REMOVE_DEVICE request, the system prompts the user to reboot. Note that the device's setup files should not initiate a reboot.

  • Installing a non-WDM filter driver.

    If a filter driver is added to a non-WDM driver stack, the system must be rebooted. In this case, the driver's installer or co-installer should request a reboot (see Initiating System Reboots During Device Installations). Note that adding a filter driver to a WDM driver stack does not require a reboot, unless an underlying device is a system boot device.

Avoiding System Reboots During Device Installations

To avoid system reboots during device installations, use the following rules:

  • Never use Reboot or Restart entries in INF DDInstall sections, except for installations specific to Windows 9x/Me.
  • Do not use COPYFLG_FORCE_FILE_IN_USE, or COPYFLG_REPLACE_BOOT_FILE flags with INF CopyFiles directives, unless absolutely necessary.
  • Assign a new file name to each new version of a class installer or co-installer, or a service DLL. This avoids the necessity of a reboot if an older version is in use. (In fact, if a new file name is not used for an updated class installer or class co-installer, these new files will not be used for the installation.)
  • To update a device's drivers, follow the rules listed under Updating Driver Files.

Initiating System Reboots During Device Installations

In the rare cases in which it is necessary for the system to be rebooted to complete a device installation, use the following rules:

  • During initial installations, a device's installer or co-installer can request a system reboot by setting DI_NEEDREBOOT in the SP_DEVINSTALL_PARAMS structure, which is received along with device installation function codes. (This should not be done unless absolutely necessary.)
  • During update installations, a device's installation application can call UpdateDriverForPlugandPlayDevices, which determines whether a reboot is necessary.


Installing Devices on 64-Bit Systems

If your device will be installed on both 32-bit platforms and 64-bit platforms, you must use the following steps when creating an installation package:

  • Provide both 32-bit and 64-bit compilations of all kernel-mode drivers, device installation applications, device installers, class installers, and co-installers. For more information, see Porting Your Driver to 64-Bit Windows.
  • Provide one or more cross-platform INF files that use decorated INF sections to control platform-specific installation behavior.

If you are writing a device installation application, the 32-bit version must be the default version. That is, the 32-bit version should be invoked by Autorun (described in Platform SDK documentation), so that it starts automatically when a user inserts your distribution disk.

The 32-bit version of the application must check the value returned by UpdateDriverForPlugAndPlayDevices. If the return value is ERROR_IN_WOW64, the 32-bit application is executing on a 64-bit platform and cannot update "in-box" drivers. Instead, it must call CreateProcess (described in Platform SDK documentation) to start the 64-bit version of the application. The 64-bit version can then call UpdateDriverForPlugAndPlayDevices, specifying a FullInfPath parameter that identifies the location of the 64-bit versions of all files.


Driver Information in the Registry

The operating system and the drivers store information about drivers and devices in the registry. In general, drivers should use the registry to store data that must be maintained across reboots of the system. In addition, drivers can access the registry to obtain information stored by the system or by other programs or drivers. For more information about the registry in general, see the Platform SDK documentation.

The following trees in the registry are of particular interest to driver writers (where HKLM represents HKEY_LOCAL_MACHINE):

  • HKLM\SYSTEM\CurrentControlSet\Services
  • HKLM\SYSTEM\CurrentControlSet\Control
  • HKLM\SYSTEM\CurrentControlSet\Enum
  • HKLM\SYSTEM\CurrentControlSet\HardwareProfiles

Drivers and user-mode setup components must access Plug and Play (PnP) keys in the registry using system routines such as IoGetDeviceProperty and SetupDiGetDeviceRegistryProperty. Drivers must not access these keys directly. The following discussion of registry information is solely for debugging a device installation or configuration problem.

The keys under HKLM\SYSTEM\CurrentControlSet are a safe place to preserve data that is vital to your driver because the data is stored in the system hive. The system takes extra precautions to protect the system hive (for example, keeping multiple copies).

The HKLM\SYSTEM\CurrentControlSet\Services Tree

The HKLM\SYSTEM\CurrentControlSet\Services registry tree stores information about each service on the system. Each driver has a key of the form HKLM\SYSTEM\CurrentControlSet\Services\DriverName. The PnP Manager passes this path to a driver in the RegistryPath parameter when it calls the driver's DriverEntry routine. A driver can store global driver-defined data under its key in the Services tree. Information stored under this key is available to the driver during its initialization.

The following keys and value entries are of particular interest:

ImagePath
A value entry that specifies the fully qualified path of the driver's image file. Setup creates this value using the required ServiceBinary entry in the driver's INF file. This entry is in the service-install-section referenced by the driver's INF AddService directive. A typical value for this path is %windir%\system32\Drivers\DriverName.sys, where DriverName is the name of the driver's Services key.
Parameters
A key used to store driver-specific data. For some types of drivers, the system expects to find specific value entries. You can add value entries to this subkey using AddReg entries in the driver's INF file.
Performance
A key that specifies information for optional performance monitoring. The values under this key specify the name of the driver's performance DLL and the names of certain exported functions in that DLL. You can add value entries to this subkey using AddReg entries in the driver's INF file.

The HKLM\SYSTEM\CurrentControlSet\Control Tree

The HKLM\SYSTEM\CurrentControlSet\Control registry tree contains information for controlling system startup and some aspects of device configuration. The following subkeys are of particular interest:

Class
Contains information about the device setup classes on the system. There is a subkey for each class, named using the GUID of the setup class. Each subkey contains information about a setup class, such as the class installer (if there is one), registered class upper-filter drivers, registered class lower-filter drivers, and so forth. Each class subkey contains other subkeys known as software keys (or, driver keys) for each device instance of that class installed in the system.
CoDeviceInstallers
Contains information about the class-specific co-installers that are registered on the system.
DeviceClasses
Contains information about the device interfaces on the system. There is a subkey for each device interface class and entries under those subkeys for each instance of an interface that is registered for the device interface class.

The HKLM\SYSTEM\CurrentControlSet\Enum Tree

The HKLM\SYSTEM\CurrentControlSet\Enum registry tree contains information about the devices on the system. The PnP Manager creates a subkey for each device, with a name in the form of HKLM\SYSTEM\CurrentControlSet\Enum\enumerator\deviceID. Under each of these keys is a subkey for each device instance present on the system. This subkey, which is known as the device's hardware key, has information such as the device description, hardware IDs, compatible IDs, resource requirements, and so forth.

The Enum tree is reserved for use by operating system components, and its layout is subject to change. Drivers and user-mode Setup components must use system-supplied functions, such as IoGetDeviceProperty and SetupDiGetDeviceRegistryProperty, to extract information from this tree. Drivers and Setup applications must not access the Enum tree directly. You can view the Enum tree directly using the registry editor when debugging drivers.

The HKLM\SYSTEM\CurrentControlSet\HardwareProfiles Tree

The HKLM\SYSTEM\CurrentControlSet\HardwareProfiles registry tree contains information about the hardware profiles on the system.


RunOnce Registry Entries

The system supports a registry key, RunOnce, that can be used to place commands that the system will execute one time and then delete. Each time the system boots, it executes any commands stored under the RunOnce key, then removes them. However, this is not the only time RunOnce commands can be executed, so if you place a command under the RunOnce key, you cannot predict when it will execute.

For device installations, RunOnce registry entries can be created using add-registry-sections, which are referenced by INF AddReg directives. The registry root and subkey values are as follows:

HKLM,"Software\Microsoft\Windows\CurrentVersion\RunOnce"

Following is an example add-registry-section entry that stores a command under the RunOnce key:

;; WDMAud swenum install

HKLM,%RunOnce%,"WDM_WDMAUD",,\
"rundll32.exe streamci.dll,StreamingDeviceSetup %WDM_WDMAUD.DeviceId%,%KSNAME_Filter%,%KSCATEGORY_WDMAUD%,%17%\WDMAUDIO.inf,WDM_WDMAUD.Interface.Install"

[Strings]
RunOnce = "SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce"
WDM_WDMAUD.DeviceId = "{CD171DE3-69E5-11D2-B56D-0000F8754380}"
KSNAME_Filter = "{9B365890-165F-11D0-A195-0020AFD156E4}"
KSCATEGORY_WDMAUD = "{3E227E76-690D-11D2-8161-0000F8775BF1}"

Immediately after a device has been installed, Setup executes all commands stored under the RunOnce registry key.

The following rules apply to the use of RunOnce entries for device installations:

  • RunOnce registry entries should only be used for installations of software-only devices that are enumerated by SWENUM, the software device enumerator.
  • RunOnce entries must consist only of calls to rundll32.exe, or else Microsoft will not digitally sign the driver package.


Creating an INF File

Microsoft® Windows drivers must have an INF file in order to be installed. An INF file is a text file that contains all the necessary information about the device(s) and file(s) to be installed, such as driver images, registry information, version information, and so on, to be used by the Setup components.

Windows INF files do not contain installation scripts. The installation procedures are part of a Microsoft Win32® installer application, such as the New Device Wizard and the Add Hardware Wizard, with each INF file acting as a resource.

This chapter contains the following information:

General Guidelines for INF Files

Specifying the Source and Target Locations for Device Files

Creating INF Files for Multiple Platforms and Operating Systems

Creating International INF Files

Specifying Driver Load Order

Tightening File-Open Security in a Device INF File

Accessing INF Files From a Setup Application

See INF File Sections and Directives for a complete description of INF file format.


General Guidelines for INF Files

INF files have some common parts and follow a single set of syntax rules, but they are also as different as the variety of devices that are supported on a Microsoft® Windows® machine. When writing an INF file, you should consult the following sources of information:

  • This chapter and the INF Files Sections and Directives reference material.
  • The documentation for your class of device.

    For example, if your device is a printer, see Installing and Configuring Printer Drivers.

  • DDK tools for INF files.

    The DDK provides some tools to assist with writing INF files. See the DDK's \tools subdirectory for information on tools such as GenINF and ChkINF.

  • Sample INF files and INF files for similar devices.

    The DDK includes INF files for its sample drivers. Peruse the sample drivers to see if there are INF files for devices similar to your device.

You can create or modify an INF file using any text editor in which you can control the insertion of line breaks. If your INF contains non-ASCII characters, save the file as a Unicode file.

An INF file that ships with the operating system must have a file name of xxxxxxxx.inf, where "xxxxxxxx" is no longer than eight characters. The name of an INF file that ships separately from the operating system is not limited to eight characters.


Specifying the Source and Target Locations for Device Files

When Setup processes copy, rename, and delete file statements in an INF file, it determines the source and target locations for the files. To determine these locations, it assesses whether the driver ships with the operating system or separately and examines various INF file sections and entries, including SourceDisksNames, SourceDisksFiles, LayoutFile, Include, Needs, and DestinationDirs.

This section describes how Setup determines source and target locations, and provides guidelines to help you correctly specify these locations, and describes how to copy INF files from one location to another. It contains the following topics:

Source Media for INFs

Target Media for INFs

Copying INFs


Source Media for INFs

The methods you should use to specify source media for device files depend on whether your INFs ship separately from the operating system or are included with the operating system.

Source Media for INFs that Ship Separately from the Operating System

INFs for drivers that are delivered separately from the operating system specify where the files are located using SourceDisksNames and SourceDisksFiles sections. If such an INF contains Include and Needs entries in the DDInstall section, those entries specify additional possible source locations.

If an INF has SourceDisksNames and SourceDisksFiles sections and no Include entries, the SourceDisksNames and SourceDisksFiles sections must list all the source media and source files in the kit except for the catalog and INF files. (Microsoft® Windows® 98 requires that catalog files be listed in the SourceDisksFiles section; Windows 2000 and later versions ignore catalog file entries.)

Catalog files must be in the same location as the INF file. Catalog files must not be compressed. If the installation media includes multiple disks, then a separate copy of the INF and catalog files must be included on every disk. This is because the INF and catalog files must continue to be accessible throughout the entire installation.

Source Media for INFs that Ship with the Operating System

If the files to support the device are included with the operating system, the INF must specify a LayoutFile entry in the Version section of the file. Such an entry specifies where the files reside on the operating system media. An INF that specifies a LayoutFile entry must not include SourceDisksNames and SourceDisksFiles sections.

Only system-supplied INFs should reference layout.inf directly. OEM and IHV INF files that ship with the operating system can reference a common install section in a system-supplied INF (such as mf.inf), and the system-supplied INF references the layout.inf file.

Source Media and INFs that Contain Include and Needs Entries

If an INF has SourceDisksNames and SourceDisksFiles sections and Include and Needs entries, Setup uses the main INF file plus any of the included INF files to locate source media. It is especially important with included files to be as precise as possible when specifying source media and source file locations.

Consider the hierarchy of included INFs shown in the following figure.

Sample Hierarchy of Included INF Files

The figure shows an INF for a multifunction device, named MyMfDevice.inf, which includes the system-supplied mf.inf file. In turn, the system-supplied mf.inf includes the system-supplied layout.inf file. When Setup searches for source media from which to copy a file referenced in MyMfDevice.inf, it looks for a SourceDisksFiles section in MyMfDevice.inf and in any included INF files that reference the file to be copied. Setup searches MyMfDevice.inf first, but it does not guarantee the order in which it searches the included INFs.

Decorated SourceDisksFiles sections take precedence over undecorated sections, even if the decorated INF section is in an included file. For example, for the INFs shown in the previous figure, if layout.inf contains a [SourceDisksFiles.x86] section and MyMfDevice.inf contains only an undecorated [SourceDisksFiles] section, Setup uses the decorated section from layout.inf first when installing on an x86 machine. Therefore, an INF that includes other INFs should contain section names that use platform extensions.

Typically, a vendor-supplied INF should specify the location of the files in its driver package and should not cause Setup to search included INFs for file locations. In other words, a vendor INF that copies files should specify both a SourceDisksNames and a SourceDisksFiles section, those sections should be decorated with platform extensions, and those sections should contain information for all the files directly copied by the INF.

It is helpful if the vendor file names are as vendor-specific as possible, unless the installation is explicitly replacing a vendor-supplied file that shipped with the operating system.

Note the following rules when using Includes and Needs entries:

  • Includes and Needs entries can only be used to specify system-supplied INF files.
  • Needs entries cannot be nested. That is, a section identified by a Needs entry cannot itself contain a Needs entry.

An INF file that makes use of a section in another INF file by means of the Include and Needs entries might have to make use of an accompanying section to maintain consistency. For instance, if an INF file references the installation section (DDInstall) of another INF file in order to install the driver, it must reference an INF DDInstall.Services section to install the accompanying service. Such an INF file might have the following sections:

[DDInstall]
Include = AnotherINFFile.inf
Needs = AnotherINFFileDDInstall

[DDInstall.Services]
Include = AnotherINFFile.inf
Needs = AnotherINFFileDDInstall.Services


Target Media for INFs

An INF file specifies the target location for device files with a DestinationDirs section. This section should always be specified in the same INF file as the section with the copy, rename, or delete statements.

A DestinationDirs section should include a DefaultDestDir entry.

If an INF has copy, rename, or delete sections but no DestinationDirs section and the INF includes other INFs, Setup searches the included INFs for target location information. However, the order in which Setup searches the included files is not predictable. Therefore, there is a risk that Setup will, for example, copy files to a location not intended by the INF writer. To avoid such confusion, always specify a DestinationDirs section in an INF that contains copy, rename, or delete sections. The DestinationDirs section should include at least a DefaultDestDir entry and can list sections in the INF that copy, rename, or delete files.


Copying INFs

It is sometimes necessary to copy INF files during device installation, so that Setup can find them without repetitively displaying user prompts. For example, the base INF file for a multifunction device might copy the INF files for the device's individual functions, so that Setup can find these INF files without prompting the user each time it installs one of the device's functions.

To copy INF files, you can use either of the following techniques:

  • A co-installer or setup application can call SetupCopyOEMInf (described in Platform SDK documentation). This DDK includes source code for a co-installer, cocpyinf.dll, which uses this technique. The source code resides under the DDK's /src directory.
  • (Windows XP and later.) An INF file can include the INF CopyINF directive.

    (Note that this DDK also includes a redistributable, compiled version of cocpyinf.dll. If you use this co-installer for your device, the CopyINF directive can then be used on Windows 2000. The redistributable version of copyinf.dll resides under the DDK's \tools directory.)

Both of these methods will:

  • Install the appropriate catalog file, if it exists, along with the INF file.
  • Give the INF file a unique name so that it does not overwrite any other INF files, and will not be overwritten by other INF files.
  • Retain the path to the source medium from which device files are to be copied.
  • Ensure compatibility with future versions of Windows.

On Windows 2000 and later, installation software must never copy INF files directly into a system's %windir%/inf directory. Copying INF files by using techniques not described in this section will invalidate a driver's digital signature.


Creating INF Files for Multiple Platforms and Operating Systems

By using system-defined extensions to INF file sections and directives, you can create a single INF file for cross-platform installations and/or for dual-OS installations. The extensions enable you to create decorated section names. For INF DDInstall sections and related directives, these decorations (.ntx86, .ntia64, or .nt) specify which sections and directives are relevant to each platform and operating system. You can create an INF file that installs a device only on x86 platforms, only on ia64 platforms, on all platforms supported by Windows NT4.0 and later, on all platforms supported by Windows 9x/Me, or on all platforms for all operating systems.

For example, if your device supports Windows 2000 and later platforms, and Windows 9x/Me platforms, you would create an INF file with two or more "parallel" DDInstall sections that have the following extensions to control what is installed on each platform and/or for each operating system:

  • The [install-section-name.ntx86] extension contains instructions for installing the device or set of device-compatible models on all Windows NT4.0 and later x86-based platforms.
  • The [install-section-name.ntia64] extension contains instructions for installing the device or set of device-compatible models on all ia64-based platforms.
  • The [install-section-name.nt] extension contains instructions for installing the device or set of device-compatible models on all Windows NT4.0 and later platforms.
  • The [install-section-name] extension contains Windows 9x/Me-specific instructions.

    Undecorated sections are also fallback sections for Windows NT4.0 and later platforms. Setup uses undecorated sections on Windows NT4.0 and later platforms if it cannot locate the appropriate decorated sections. However, to prevent these sections from being used on Windows 9x/Me by mistake, you should decorate any Windows NT4.0-specific or later DDInstall and related sections with the .ntx86, .ntia64, or .nt extensions.

Windows Setup processes these DDInstall sections as follows:

  • On Windows 9x/Me, Setup processes the undecorated section and ignores any sections with .nt* platform extensions.
  • On Windows NT4.0 and later:
    1. Setup checks for install sections with the platform-specific extensions, such as .ntx86. If one is present, Setup processes the section appropriate for the current platform. Setup checks for platform-specific install sections in the INF being processed and in any included INF files (that is, any INFs included with Include entries).
    2. If there are no specific platform extensions, Setup checks for a install-section-name.nt section in the INF or any included INFs. If one is present, Setup processes the install-section-name.nt section.
    3. If there is no install-section-name.nt section, Setup processes the undecorated section.

An INF file containing INF DDInstall sections with platform extensions can also contain additional per-device sections,such as the required DDInstall.Services and optional DDInstall.HW, DDInstall.CoInstallers, DDInstall.LogConfigOverride, and/or DDInstall.Interfaces sections. In dual-OS and/or cross-platform INF files, you should specify the appropriate extension immediately following the INF-writer-defined section name as, for example, install-section-name.ntx86.HW.

If a dual-OS INF file contains decorated install-section-name.nt, install-section-name.ntx86, or install-section-name.ntia64 sections, it must also have additional parallel decorated and undecorated per-device sections. That is, if the INF file has both install-section-name and install-section-name.nt sections and it has a DDInstall.HW section, it also must have a parallel install-section-name.nt.HW section (if the device or driver requires a .HW section for Windows NT4.0 and later).

The INF File Sections and Directives documentation shows these extensions as part of the formal syntax statements in the appropriate section references as, for example:

[install-section-name.HW] |
[install-section-name.nt.HW] |
[install-section-name.ntx86.HW] |
[install-section-name.ntia64.HW]

Such a formal syntax statement indicates that these extensions are valid alternatives to the basic section. It does not indicate that any INF with a install-section-name.nt.HW section must also have every other platform-specific install-section-name.nt xxx.HW section. You can use any subset of these extensions to specify the decorated sections required for a particular cross-platform or dual-OS installation.

INF files that contain install-section-name platform extensions can also include platform extensions with their INF SourceDisksNames section and INF SourceDisksFiles section entries, to specify installation file locations in a platform-specific manner.

For Windows XP and later, you can supply INF Models sections that are specific to various versions of the operating system. These version-specific Models sections are identified using the TargetOSVersion decoration in an INF Manufacturer section.


Creating International INF Files

Creating installations for international markets requires providing locale-specific INF files and, possibly, locale-specific driver files.

An INF file that will be used in an international market should use %strkey% tokens for all user-viewable text. The strings are defined in an INF Strings section, which is typically at the end of the INF file.

Locale-Specific INF Files

You can create a single INF file that supports several locales, or you can create a separate INF file for each locale.

  • To create a single international INF file, you should include a set of locale-specific Strings.LanguageID sections, as described in the reference page for the INF Strings section. Use this technique if you intend to supply a single installation medium for all international markets.

    For installations on NT-based operating systems, this is the recommended method for supporting international markets.

  • To create a separate INF file for each locale, start with a main INF file containing all the necessary sections and entries, except for the Strings section. Then create a second set of files, where each file contains just the Strings section for a supported locale. Concatenate the main file with each strings file to generate the locale-specific INF files.

    For installations on Windows 9x/Me, this is the recommended method for supporting international markets, because Windows 9x/Me does not support Strings.LanguageID sections.

    For installations on NT-based operating systems, use this technique only if you intend to supply a separate installation medium for each international market. You cannot provide multiple versions of an INF file, for a particular NT-based OS version, on a single installation medium because Setup cannot determine which INF file to use.

Locale-Specific Versions of Driver Files

If you need to provide locale-specific versions of driver files for NT-based operating systems, place the files in separate, locale-specific subdirectories of the distribution medium, such as /English and /German. In your INF file, do the following:

  • Within the INF SourceDisksFiles section, specify locale-specific subdirectories using a string key token such as %LocaleSubDir%.
  • Provide separate INF Strings sections for each language, and define the appropriate subdirectory name string in each section, as follows:
    [Strings]              ; No language ID implies English
LocaleSubDir="English"
[Strings.0407]         ; 0407 is the language ID for German
LocaleSubDir="German"

Creating Unicode INF Files

If an INF contains characters outside the ASCII range (that is, outside the range of 0-127), the INF should be in Unicode format. One way to create a Unicode INF file is to save it in Unicode format from an application such as Notepad. If the INF is not in Unicode format, Setup uses the current locale to translate characters. If the INF is in Unicode format, Setup uses the full Unicode character set. (Windows 9x/Me Setup ignores Unicode-formatted INF files.)


Specifying Driver Load Order

For most devices, the physical hierarchy of the devices on a machine determines the order in which Setup and the PnP Manager load drivers. Setup and the PnP Manager configure devices starting with the system root device, and then they configure the child devices of the root device (for example, a PCI adapter), the children of those devices, and so on. The PnP Manager loads the drivers for each device as the device is configured, if the drivers were not previously loaded for another device.

Settings in the INF file can influence driver load order. This topic describes the relevant values that vendors should specify in the service-install-section referenced by a driver's INF AddService directive. Specifically, this topic discusses the StartType, LoadOrderGroup, and Dependencies entries.

Drivers should follow these rules for specifying StartType:

  • PnP driver

    A PnP driver should have a start type of SERVICE_DEMAND_START (0x3), specifying that the PnP Manager can load the driver whenever the PnP Manager finds a device that the driver services.

  • Driver for a device required to boot the machine

    If a device is required to boot the machine, the drivers for the device should have a start type of SERVICE_BOOT_START (0x0).

  • Non-boot driver that detects device(s) that are not PnP-enumerable

    For a device that is not PnP-enumerable, a driver reports the device to the PnP Manager by calling IoReportDetectedDevice. Such a driver should have the start type SERVICE_SYSTEM_START (0x01) so Setup will load the driver during system initialization.

    Only drivers that report nonPnP hardware should set this start type. If a driver services both PnP and nonPnP devices, it should set this start type.

  • NonPnP driver that must be started by the Service Control Manager

    Such a driver should have the start type SERVICE_AUTO_START (0x02). PnP drivers must not set this start type.

A PnP driver should be written so that it can be loaded whenever Setup configures a device that the driver services. Conversely, a driver should be able to be unloaded any time the PnP Manager determines that there are no longer devices present that the driver services. The only driver load orderings that PnP drivers should depend on are the following:

  1. The drivers for a child device can depend on the fact that the drivers for the parent device have been loaded.
  2. A driver in the device stack can depend on the fact that any drivers below it have been loaded. For example, the function driver can be certain that any lower-filter drivers have been loaded.

    Note, however, that a driver in the device stack cannot depend on being loaded sequentially after a device's lower drivers, because the driver might have been loaded previously when another device was configured.

Filter drivers within a filter group cannot predict their load ordering. For example, if a device has three registered upper-filter drivers, those three drivers will all be loaded after the function driver but could be loaded in any order within their upper-filter group.

If a driver has an explicit load-order dependency on another driver, that dependency should be implemented through a parent/child relationship. A driver for a child device can depend on the drivers for the parent device being loaded before the child drivers are loaded.

To reinforce the importance of setting the correct StartType value, the following list describes how Setup and the PnP Manager use the StartType entries in INF files:

  1. On system boot, the operating system loader loads drivers of type SERVICE_BOOT_START before it transfers control to the kernel. These drivers are in memory when the kernel gets control.

    Boot-start drivers can use INF LoadOrderGroup entries to order their loading. (Boot-start drivers are loaded before most of the devices are configured, so their load order cannot be determined by device hierarchy.) The operating system ignores INF Dependencies entries for boot-start drivers.

  2. The PnP Manager calls the DriverEntry routines of the SERVICE_BOOT_START drivers so the drivers can service the boot devices.

    If a boot device has child devices, those devices are enumerated. The child devices are configured and started if their drivers are also boot-start drivers. If a device's drivers are not all boot-start drivers, the PnP Manager creates a devnode for the device but does not start the device yet.

  3. After all the boot drivers have loaded and the boot devices are started, the PnP Manager configures the rest of the PnP devices and loads their drivers.

    The PnP Manager walks the device tree and loads the drivers for the devnodes that are not yet started (that is, any nonstarted devnodes from the previous step). As each device starts, the PnP Manager enumerates the children of the device, if any.

    As it configures these devices, the PnP Manager loads the drivers for the devices, regardless of the drivers' StartType values, and starts the devices. Many of these drivers are SERVICE_DEMAND_START drivers, but they can have any StartType.

    The PnP Manager ignores registry entries that were created as a result of INF Dependencies entries and LoadOrderGroup entries for drivers that it loads in this step. The load ordering is based on the physical device hierarchy.

    At the end of this step, all of the devices have been configured, except devices that are not PnP-enumerable and the descendants of those devices. (The descendants might or might not be PnP-enumerable.)

  4. The PnP Manager loads drivers of StartType SERVICE_SYSTEM_START that are not yet loaded.

    These drivers detect and report their nonPnP devices. The PnP Manager processes registry entries that are the result of INF LoadOrderGroup entries for these drivers. It ignores registry entries that were created as a result of INF Dependencies entries for these drivers.

  5. The Service Control Manager loads drivers of StartType SERVICE_AUTO_START that are not yet loaded.

    The Service Control Manager processes the service database information with respect to the services' DependOnGroup and DependOnServices. This information is from Dependencies entries in INF AddService entries. Note that the Dependencies information is only processed for nonPnP drivers because any necessary PnP drivers were loaded in an earlier step of system startup. The Service Control Manager ignores INF LoadOrderGroup information.

    See the Platform SDK documentation for more information on the Service Control Manager.


Tightening File-Open Security in a Device INF File

For Microsoft® Windows® 2000 and later, Microsoft tightened file-open security in the class installer INFs for certain device classes, including CDROM, DiskDrive, FDC, FloppyDisk, HDC, and SCSIAdapter.

If you are unsure whether the class installer for your device has tightened security on file opens, you should tighten security by using the device's INF file to assign a value to the DeviceCharacteristics value name in the registry. Do this within an add-registry-section, which is specified using the INF AddReg directive. The add-registry-section is referenced in an INF DDInstall section and has the following syntax:

[DDInstall]
...
AddReg = Xxx_AddReg
...

[Xxx_AddReg]
...
HKR,,DeviceCharacteristics,0x10001,characteristics

The characteristics value is the numeric value of the characteristics to assign to the device. This value is the result of ORing one or more FILE_* file characteristics values as defined in wdm.h or ntddk.h. Setting the FILE_DEVICE_SECURE_OPEN characteristic, which has a numeric value of 0x100, directs the I/O Manager to perform security checks on all open requests for the device. The FILE_DEVICE_SECURE_OPEN characteristic is supported on Windows 2000 and later platforms but not on Win9x/Me platforms.

A characteristics value of zero directs Setup to ignore the class-wide device characteristics, if any, that were specified in the associated class installer INF.

During device installation, the Plug and Play Manager determines the device characteristics for a device object as follows:

  1. It retrieves the characteristics settings for the device's class, if any, as specified in the class-installer INF.
  2. It retrieves the characteristics for the device, if any, as specified in the device INF. Device-specific settings override class settings.
  3. It ORs the resulting INF-specified settings with those set in the device object by the driver, either directly or through IoCreateDevice.
  4. It ORs the device characteristics settings of the FDO and any filter DOs and propagates these settings to the FDO and filter DOs. If the device is in raw mode, and therefore has no FDO, the Plug and Play Manager propagates the device characteristics across the PDO and any filter DOs.

The above steps ensure, for example, that if one driver for a device sets FILE_DEVICE_SECURE_OPEN, that characteristic is propagated to all the device objects for drivers servicing the device.

The Plug and Play Manager ORs and propagates these characteristics after it has called the AddDevice routines for the device's drivers and after the drivers have created their device objects and attached them to the device stack, but before the Plug and Play Manager sends the IRP_MN_START_DEVICE request.

The Plug and Play Manager also propagates the following device characteristics when it propagates FILE_DEVICE_SECURE_OPEN: FILE_REMOVABLE_MEDIA, FILE_READ_ONLY_DEVICE, and FILE_FLOPPY_DISKETTE.

An INF file that has a ClassInstall32 section can set the FILE_DEVICE_SECURE_OPEN characteristic for a setup class of devices. See Tightening File-Open Security in a Class Installer INF File.


Accessing INF Files From a Setup Application

Most INF files are used by system class installers and other setup applications. This section describes common operations that vendor-supplied setup applications can be carry out on INF files, using the general Setup functions. For complete information on how to use these functions, see the Platform SDK documentation.

This section contains the following topics:

Opening and Closing an INF File

Retrieving Information from an INF File


Opening and Closing an INF File

Before an application can access the information in an INF file, it must open the file by calling SetupOpenInfFile. This function returns a handle to the INF file.

If you do not know the name of the INF file that you need to open, use SetupGetInfFileList to obtain a list of all the INF files in a directory.

Once an application opens an INF file, it can append additional INF files to the opened file using SetupOpenAppendInfFile. When subsequent Setup functions reference an open INF file, they will also be able to access any information stored in any appended files.

If no INF file is specified when calling SetupOpenAppendInfFile, this function appends the file specified by the LayoutFile entry in the INF Version section of the INF file opened during the call to SetupOpenInfFile.

When the information in the INF file is no longer needed, the application should call SetupCloseInfFile to release resources allocated during the call to SetupOpenInfFile.


Retrieving Information from an INF File

Once you have a handle to an INF file, you can retrieve information from it in a variety of ways. Functions such as SetupGetInfInformation, SetupQueryInfFileInformation, and SetupQueryInfVersionInformation retrieve information about the specified INF file.

Other functions, such as SetupGetSourceInfo and SetupGetTargetPath, acquire information about the source files and target directories.

Functions such as SetupGetLineText and SetupGetStringField enable you to directly access information stored in a line or field of an INF file. These functions are used internally by the higher-level Setup functions but are available if you need to directly access information at the line or field level.


Writing a Co-installer

A co-installer is a Microsoft® Win32® DLL that assists in device installation. Co-installers are called by Setup API as "helpers" for Class Installers. For example, a vendor can provide a co-installer to write device-specific information to the registry that cannot be handled by the INF file.

This section describes:

Co-installer Operation

Co-installer Interface

Co-installer Functionality

Handling DIF Codes

Registering a Co-installer


Co-installer Operation

Co-installers are called by Setup API as shown in the following figure.

Co-installers Participate in Device Installation

The shaded boxes represent components that IHVs and OEMs can provide. The other components are supplied by the OS. See Device Installation Overview for more information on Setup components.

Co-installers can be device-specific or class-specific. Setup API calls a device-specific co-installer only when installing the device for which the co-installer is registered. The OS and vendors can register zero or more device-specific co-installers for a device. Setup API calls a class co-installer when installing any device of the device setup class for which the co-installer is registered. The OS and vendors can register one or more class co-installers for a device setup class. In addition, a class co-installer can be registered for one or more setup classes.

GUI-mode Setup, the New Device DLL, and Custom Device Installation Applications install devices by calling SetupDiCallClassInstaller with device installation function codes (DIF codes). For each DIF request, SetupDiCallClassInstaller calls any class co-installers registered for the device's setup class, any device co-installers registered for the specific device, and then the Class Installer supplied by the system for the device's setup class, if there is one.

Custom device installation applications must call SetupDiCallClassInstaller rather than calling a co-installer or class installer directly. This function ensures that all registered co-installers are called appropriately.

Class co-installers are typically registered prior to device installation, and device-specific co-installers are registered as part of the device's installation. Class co-installers are therefore typically added to the co-installer list when it is first built and are called for all DIF requests during device installation.

Device-specific co-installers are added to the co-installer list after a DIF_REGISTER_COINSTALLERS request has been completed for the device (or SetupDiRegisterCoDeviceInstallers has been called). Device-specific co-installers do not participate in the following DIF requests:

DIF_ALLOW_INSTALL
DIF_INSTALLDEVICEFILES
DIF_SELECTBESTCOMPATDRV

Only a class co-installer (not a device-specific co-installer) can respond to the following DIF requests:

DIF_DETECT
DIF_FIRSTTIMESETUP
DIF_NEWDEVICEWIZARD_PRESELECT
DIF_NEWDEVICEWIZARD_SELECT
DIF_NEWDEVICEWIZARD_PREANALYZE
DIF_NEWDEVICEWIZARD_POSTANALYZE

A device co-installer is not appropriate in these contexts, either because a particular device has not yet been identified or at this early stage of installation the device co-installers have not yet been registered.

The following figure shows the order in which SetupDiCallClassInstaller calls co-installers and a Class Installer after any device-specific co-installers have been registered.

Example of Calling Co-installers for DIF Request Processing and PostProcessing

In the example illustrated by the previous figure, two class co-installers are registered for this device's setup class and one device-specific co-installer is registered for the device. The following steps correspond to the circled numbers in the previous figure:

  1. SetupDiCallClassInstaller calls the first class co-installer, specifying a DIF code that indicates the install request being processed (DIF_INSTALLDEVICE, in this example). The co-installer has the option of participating in the install request. In this example, the first registered class co-installer returns NO_ERROR.
  2. SetupDiCallClassInstaller, in turn, calls any additional registered class co-installers. In this example, the second class co-installer returns ERROR_DI_POSTPROCESSING_REQUIRED, which requests that the co-installer be called later for postprocessing.
  3. SetupDiCallClassInstaller calls any registered device-specific co-installers.
  4. After all registered co-installers have been called, SetupDiCallClassInstaller calls the system-supplied Class Installer, if there is one for the device's setup class. In this example, the class installer returns ERROR_DI_DO_DEFAULT, which is a typical return value for class installers.
  5. SetupDiCallClassInstaller calls the default handler for the installation request, if there is one. DIF_INSTALLDEVICE has a default handler, SetupDiInstallDevice, which is part of Setup API.
  6. SetupDiCallClassInstaller calls any co-installers that requested postprocessing. In this example, the second class co-installer requested postprocessing.

Co-installer post-processing is similar to driver IoCompletion routines, except that the co-installer is called a second time at its single entry point. When SetupDiCallClassInstaller calls a co-installer for post-processing, it sets PostProcessing to TRUE and InstallResult to the appropriate value in the Context parameter. In this example, Context.InstallResult is NO_ERROR because the default handler executed successfully.

For postprocessing, SetupDiCallClassInstaller calls co-installers in reverse order. If all the co-installers in the previous figure had returned ERROR_DI_POSTPROCESSING_REQUIRED, SetupDiCallClassInstaller would call Device_Coinstaller_1 first for postprocessing, followed by Class_Coinstaller_2, and then Class_Coinstaller_1. Class Installers do not request postprocessing; only co-installers do.

A co-installer that requests postprocessing is called even if a previous co-installer failed the install request.


Co-installer Interface

A co-installer's interface consists of an exported entry point function and an associated data structure.

Co-installer Entry Point

A co-installer must export an entry point function that has the following prototype:

typedef
DWORD
(CALLBACK* COINSTALLER_PROC) (
    IN DI_FUNCTION  InstallFunction,
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData  OPTIONAL,
    IN OUT PCOINSTALLER_CONTEXT_DATA  Context
    );

InstallFunction specifies the device installation request being processed, in which the co-installer has the option of participating. For example, DIF_INSTALLDEVICE. See Device Installation Function Codes for documentation on DIF codes.

DeviceInfoSet supplies a handle to a device information set.

DeviceInfoData optionally identifies a device that is the target of the device installation request. If this parameter is non-NULL, it identifies a device information element in the device information set. DeviceInfoData is non-NULL when SetupDiCallClassInstaller calls a device-specific co-installer. A class-specific co-installer can be called with a DIF request that has a NULL DeviceInfoData, such as DIF_DETECT or DIF_FIRSTTIMESETUP.

Context points to a COINSTALLER_CONTEXT_DATA structure, described below.

A device co-installer returns one of the following values:

NO_ERROR
The co-installer performed the appropriate actions for the specified InstallFunction, or the co-installer determined that it didn't need to perform any actions for the request.
ERROR_DI_POSTPROCESSING_REQUIRED
The co-installer performed any appropriate actions for the specified InstallFunction and is requesting to be called again after the Class Installer has processed the request.
A Win32 error
The co-installer encountered an error.

A co-installer does not set a return status of ERROR_DI_DO_DEFAULT. This status can be used only by a Class Installer. If a co-installer returns this status, SetupDiCallClassInstaller will not process the DIF_Xxx request properly. A co-installer might propagate a return status of ERROR_DI_DO_DEFAULT in its postprocessing pass, but it never sets this value.

COINSTALLER_CONTEXT_DATA

COINSTALLER_CONTEXT_DATA is a co-installer-specific context structure describing an installation request. The format of the structure is:

    typedef struct
    _COINSTALLER_CONTEXT_DATA {
        BOOLEAN  PostProcessing;
        DWORD  InstallResult;
        PVOID  PrivateData;
    } COINSTALLER_CONTEXT_DATA, *PCOINSTALLER_CONTEXT_DATA;

PostProcessing is TRUE when a co-installer is called after the appropriate Class Installer, if any, has processed the InstallFunction. PostProcessing is read-only to the co-installer.

If PostProcessing is FALSE, InstallResult is not relevant. If PostProcessing is TRUE, InstallResult is the current status of the install request. This value is NO_ERROR or an error status returned by the previous component called for this install request. A co-installer can propagate the status by returning this value for its function return, or it can return another status. InstallResult is read-only to the co-installer.

PrivateData points to a co-installer-allocated buffer. If a co-installer sets this pointer and requests postprocessing, SetupDiCallClassInstaller passes the pointer to the co-installer when it calls the co-installer for postprocessing.


Co-installer Functionality

A co-installer is a user-mode Win32 DLL that typically writes additional configuration information to the registry, or performs other installation tasks requiring information that is not available when an INF is written.

A co-installer might do some or all of the following:

  • Handle one or more of the device installation function codes (DIF codes) received by the co-installer entry point function.
  • Perform operations before the associated class or device installer is called, after the class or device installer is called, or both, as described in Co-installer Operation.
  • Provide "finish install" pages (in response to DIF_NEWDEVICEWIZARD_FINISHINSTALL) to obtain device parameters that are required so the device can operate, or to ask if device-specific applications should be installed.
  • Provide device property pages, which are displayed by the Device Manager so users can modify device parameters.

When called for post-processing, a co-installer must check the InstallResult member of the COINSTALLER_CONTEXT_DATA structure. If its value is not NO_ERROR, the co-installer must do any necessary clean up operations and return an appropriate value for InstallResult.

Co-installers are sometimes used to obtain information from the user. Such information might include additional device parameters (such as a modem's dialing properties), or whether the user wants device-specific applications installed. Co-installers can create user interfaces by providing "finish install" pages and by providing device property pages. No other form of user interface is allowed. Setup displays "finish install" pages at the end of the installation (within the Found New Hardware, Hardware Update, or Add Hardware Wizard, which require administrator privilege). The Device Manager displays property pages, and allows users with administrator privilege to modify parameters displayed on these pages.


Handling DIF Codes

Setup applications send device installation function codes (DIF codes) to installers by calling SetupDiCallClassInstaller. This function, in turn, calls the installer's entry point function. For a description of installer entry points, see:

Co-installer Interface

Class Installer Interface

The reference page for each DIF code contains the following sections:

When Sent
Describes the typical times when, and reasons why, a Setup application sends this DIF request.
Who Handles
Specifies which installers are allowed to handle this request. The installers include class installers, class co-installers (setup-class-wide co-installers), and device co-installers (device-specific co-installers).
Installer Input
Besides the DIF code, SetupDiCallClassInstaller supplies additional information relevant to the particular request. See the reference page for each DIF code for details on the information that is supplied with each request. The following list contains a general description of the additional input parameters, and lists the device installation functions (SetupDi Xxx functions) that installers can call to handle the parameters:
DeviceInfoSet
Supplies a handle to the device information set.

The handle is opaque. Use the handle, for example, to identify the device information set in calls to SetupDi Xxx functions.

The DeviceInfoSet might have an associated device setup class. If so, call SetupDiGetDeviceInfoListClass to get the class GUID.

DeviceInfoData
Optionally supplies a pointer to an SP_DEVINFO_DATA structure that identifies a device in the device information set.
Device Installation Parameters
These indirect parameters supply information for the device installation in an SP_DEVINSTALL_PARAMS structure. If DeviceInfoData is not NULL, there are device installation parameters associated with the DeviceInfoData. If DeviceInfoData is NULL, the device installation parameters are associated with the DeviceInfoSet.

Call SetupDiGetDeviceInstallParams to get the device installation parameters.

Class Installation Parameters
The optional indirect parameters are specific to the particular DIF request. These are essentially "DIF request parameters." For example, the class installation parameters for a DIF_REMOVE installation request are contained in an SP_REMOVEDEVICE_PARAMS structure.

Each SP_XXX_PARAMS structure starts with a fixed-sized SP_CLASSINSTALL_HEADER.

Call SetupDiGetClassInstallParams to get the class installation parameters.

If a DIF request has class installation parameters, there is a set of parameters associated with the DeviceInfoSet and another set of parameters associated with the DeviceInfoData (if the DIF request specifies DeviceInfoData). SetupDiGetClassInstallParams returns the most specific parameters available.

Context
Co-installers have an optional context parameter.
Installer Output
Describes the output expected for this DIF code.

If an installer modifies the device installation parameters, the installer must call SetupDiSetDeviceInstallParams to apply the changes before returning. Similarly, if an installer modifies the class installation parameters for the DIF code, the installer must call SetupDiSetClassInstallParams.

Installer Return Value
Specifies the appropriate return value(s) for the DIF code. See the following figure for more information about return values.
Default DIF Code Handler
Specifies the SetupDi function that carries out system-defined operations for the DIF code. Not all DIF codes have a default handler. Unless a co-installer or class installer takes steps to prevent the default handler from being called, SetupDiCallClassInstaller calls the default handler for a DIF code after it calls the class installer (but before it calls any co-installers that registered for post-processing).

Co-installers should not call default DIF code handlers.

Installer Operation
Describes typical tasks that an installer might do to handle the DIF request.
See Also
Lists sources of related information.

The following figure shows the sequence of events in SetupDiCallClassInstaller for processing a DIF code.

Flow of DIF Code Processing in SetupDiCallClassInstaller

The OS performs some operations for each DIF code. Vendor-supplied co-installers and class installers can participate in the installation activities. Note that SetupDiCallClassInstaller calls co-installers that registered for postprocessing even if the DIF code fails.


Registering a Co-installer

A co-installer can be registered for a single device or for all the devices in a particular setup class. A device-specific co-installer is registered dynamically through the INF file when one of its devices is installed. Class co-installers are registered manually or by a Custom Device Installation Application and an INF.

For more information, see

Registering a Device-Specific Co-installer

Registering a Class Co-installer

To update a co-installer, each new version of the DLL should have a new filename because the DLL is typically in use when the user clicks the Update Driver button on the device property page.


Registering a Device-Specific Co-installer

To register a device-specific co-installer, add the following sections to the device's INF file:

;  :
;  :
[DestinationDirs]
XxxCopyFilesSection = 11                \\DIRID_SYSTEM
                                        \\ Xxx = driver or dev. prefix
;  :
;  :
[XxxInstall.OS-platform.CoInstallers]   \\ OS-platform is optional
CopyFiles = XxxCopyFilesSection
AddReg = Xxx.OS-platform.CoInstallers_AddReg

[XxxCopyFilesSection]
XxxCoInstall.dll

[Xxx.OS-platform.CoInstallers_AddReg]
HKR,,CoInstallers32,0x00010000,"XxxCoInstall.dll, \
    XxxCoInstallEntryPoint"

The entry in the DestinationDirs section specifies that files listed in the XxxCopyFilesSection will be copied to the system directory. The Xxx prefix identifies the driver, the device, or a group of devices (for example, cdrom_CopyFilesSection). The Xxx prefix should be unique.

The co-installer install section name can be decorated with an optional OS/architecture extension (for example, cdrom_install.NTx86.CoInstallers).

The entry in the Xxx_AddReg section creates a CoInstallers32 value entry in the device's driver key. The entry contains the co-installer DLL and, optionally, a specific entry point. If you omit the entry point, the default is CoDeviceInstall. The hexadecimal flags parameter (0x00010000) specifies that this is a REG_MULTI_SZ value entry.

To register more than one device-specific co-installer for a device, copy the files for each co-installer and include more than one string in the registry entry. For example, to register two co-installers, create INF sections like the following:

;   :
;   :
[DestinationDirs]
XxxCopyFilesSection = 11                \\DIRID_SYSTEM
                                        \\ Xxx = driver or dev. prefix
;   :
;   :
[XxxInstall.OS-platform.CoInstallers]   \\ OS-platform is optional
CopyFiles = XxxCopyFilesSection
AddReg = Xxx.OS-platform.CoInstallers_AddReg

[XxxCopyFilesSection]
XxxCoInstall.dll                         \\ copy 1st coinst. file
YyyCoInstall.dll                         \\ copy 2nd coinst. file

[Xxx.OS-platform.CoInstallers_AddReg]
HKR,,CoInstallers32,0x00010000,                 \
    "XxxCoInstall.dll, XxxCoInstallEntryPoint", \
    "YyyCoInstall.dll, YyyCoInstallEntryPoint"
                                         \\ add both to registry

Device-specific co-installers are registered during the process of installing a device, when the Coinstallers INF section is processed. Setup API then calls the co-installers at each subsequent step of the installation process. If more than one co-installer is registered for a device, Setup API calls them in the order in which they are listed in the registry.


Registering a Class Co-installer

To register a co-installer for every device of a particular setup class, create a registry entry like the following under the HKLM\System\CurrentControlSet\Control\CoDeviceInstallers subkey:

{setup-class-GUID}: REG_MULTI_SZ : "XyzCoInstall.dll,XyzCoInstallEntryPoint\0\0"

The system creates the CoDeviceInstallers key. Setup-class-GUID specifies the GUID for the device setup class. If the co-installer applies to more than one class of devices, create a separate value entry for each setup class.

You must not overwrite other co-installers that have been previously written to the setup-class-GUID key. Read the key, append your co-installer string to the REG_MULTI_SZ list, and write the key back to the registry.

If you omit the CoInstallEntryPoint, the default is CoDeviceInstall.

The co-installer DLL must also be copied to the system directory.

The class co-installer is available to be called for relevant devices and services once the file has been copied and the registry entry is made.

Rather than manually creating the registry entry to register a class co-installer, you can register it using an INF file like the following:

[version]
signature = "$Windows NT$"

[DestinationDirs]
DefaultDestDir = 11    // DIRID_SYSTEM

[DefaultInstall]
CopyFiles = @classXcoinst.dll
AddReg = CoInstaller_AddReg

[CoInstaller_AddReg]
HKLM,System\CurrentControlSet\Control\CoDeviceInstallers, \
 {setup-class-GUID},0x00010008, "classXcoinst.dll,classXCoInstaller"
; above line uses the line continuation character (\)

This sample INF copies the file classXcoinst.dll to the system directory and makes an entry for the setup-class-GUID class under the CoDeviceInstallers key. The entry in the Xxx_AddReg section specifies two flags: the "00010000" flag specifies that the entry is a REG_MULTI_SZ, and the "00000008" flag specifies that the new value is to be appended to any existing value (if the new value is not already present in the string).

Such an INF that registers a class co-installer can be activated by a right-click install or through an application that calls SetupInstallFromInfSection.


Writing a Class Installer

A class installer DLL performs installation operations that apply to devices in a particular device setup class. For example, the ports class installer is responsible for assigning a COM port name to a device in the ports setup class. If the devices in a particular setup class do not require any special installation operations, a class installer is not required for that setup class.

Microsoft provides class installers for the system-defined device setup classes that require a class installer. An IHV or OEM can provide a co-installer to perform any necessary setup operations. (See Writing a Co-installer.)

If you define a new device setup class for your device, you might need to write a class installer. However, you rarely need to define a new device setup class because almost all devices can be associated with one of the system-supplied device setup classes. For example, the maker of a digital camera might think that it needs a new setup class. However, cameras fall under the image class.

This chapter contains the following information:

Class Installer Interface

Device Installation Functions Summary

Registering a Class Installer

Tightening File-Open Security in a Class Installer INF File

See also the chapter on Writing a Co-installer for general information on processing DIF codes.


Class Installer Interface

Every class installer exports a class installer function. The default name for the function is ClassInstall. Setup API calls this function whenever it needs the class installer to carry out a specific installation task for a device of its setup class.

The prototype for the installer function is as follows:

typedef DWORD  (CALLBACK* CLASS_INSTALL_PROC) (
    IN DI_FUNCTION       InstallFunction,
    IN HDEVINFO          DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData  /* optional */
    );

The class installer function receives two or three arguments:

  • a device installation function code, which identifies the installation request to perform
  • a handle to a device information set
  • optionally, a pointer to an SP_DEVINFO_DATA structure that contains information about the device to install

A class installer returns one of the following values:

ERROR_DI_DO_DEFAULT
A class installer typically returns ERROR_DI_DO_DEFAULT, which instructs Setup to perform the default action for the DIF request.

This return status is not really an error, just a valid return value. ERROR_DI_DO_DEFAULT indicates that the class installer possibly performed some actions that filter or augment the installation action, but the class installer's actions do not replace the default action.

For example, a class installer might set some flags in response to a DIF_INSTALLDEVICE request and return ERROR_DI_DO_DEFAULT. In response to this return value, Setup performs the default action for DIF_INSTALLDEVICE (calls SetupDiInstallDevice) and then calls any co-installers that requested post processing.

If you know that a given DIF request has no default action, you should still return ERROR_DI_DO_DEFAULT. The DIF request might have a default action in a future release of the operating system.

A Win32 error
A class installer can return an appropriate Win32® error.
NO_ERROR
A class installer only returns NO_ERROR if it determines that it has fully completed the device installation task, including calling any default handler or superseding the default operation.

A class installer might call the default handler if, for example, the installer needs to perform certain actions after the default handler has run. If a class installer calls the default handler, the installer must not return ERROR_DI_DO_DEFAULT; it must return NO_ERROR or a Win32 error.


Device Installation Functions Summary

Installers can use the device installation functions provided by Setup API to carry out installation operations. The device installation functions allow installers to search INF files for compatible drivers, display driver choices to the user through selection dialog boxes, and perform the actual driver installation.

Most of the device installation functions rely on information in the SP_DEVINFO_DATA structure to carry out installation tasks. Each device has an SP_DEVINFO_DATA structure associated with it. You can retrieve a handle (HDEVINFO) to a device information set that contains all installed devices in a particular class by using the SetupDiGetClassDevs function. You can use the SetupDiCreateDeviceInfo function to add a new device to a device information set. You can free all SP_DEVINFO_DATA structures in a device information set by using the SetupDiDestroyDeviceInfoList function. This function also frees any compatible device and class device lists that might have been added to the structure.

By using the SetupDiBuildDriverInfoList function, you can generate a list from which the installer or the user can choose the driver or device to install. SetupDiBuildDriverInfoList creates a list of compatible drivers or a list of all devices of a particular class.

Once you have a list of compatible drivers, you can prompt the user to select from the list by using the SetupDiSelectDevice function. This function displays a dialog box that contains information about each device in the device information set. You can install a selected driver by using the SetupDiInstallDevice function. This function uses information in the driver's INF file to create to any new registry entries required, set the configuration of the device hardware, and copy the driver files to the appropriate directories.

An installer might need to examine and set values under the registry key for a device that is about to be installed. You can open the hardware or driver key for a device by using the SetupDiCreateDevRegKey or SetupDiOpenDevRegKey function.

You can install a new class of device by using the SetupDiInstallClass function. This function installs the new class of device from an INF file that contains a ClassInstall32 section.

You can remove a device from the system by using the SetupDiRemoveDevice function. This function deletes the device's registry entries and stops the device if possible. If the device cannot be dynamically stopped, the function sets flags that eventually cause the user to be prompted to shut down the system.


Registering a Class Installer

To register a class installer, add Installer32 and Icon entries to the registry for the class. Microsoft® Windows® 2000 and later maintains a System\CurrentControlSet\Control\Class branch under HKEY_LOCAL_MACHINE for information about each class. (Windows 9x/Me maintains a System\CurrentControlSet\Services\Class branch under HKEY_LOCAL_MACHINE for information about each class.) The value of the key contains the localized description of the class.

You can specify the Installer32 and Icon registry entries in an INF file, by including an AddReg section referenced by an INF ClassInstall32 section.


Tightening File-Open Security in a Class Installer INF File

For Windows 2000 and later, you can tighten the file-open security for a class of devices, by assigning a value to the DeviceCharacteristics value name in the registry.

Do this using the INF file that installs the class installer, within an add-registry-section, which is specified using the INF AddReg directive. The add-registry-section is referenced in an INF ClassInstall32 section and has the following syntax:

[ClassInstall32] |
[ClassInstall32.ntx86] |
[ClassInstall32.ntia64]
...
AddReg = Xxx_AddReg
...

[Xxx_AddReg]
...
HKR,,DeviceCharacteristics,0x10001,characteristics     ; new

The characteristics value is the numeric value of the characteristics to assign to the device. This value is the result of ORing one or more FILE_* file characteristics values as defined in wdm.h or ntddk.h. Setting the FILE_DEVICE_SECURE_OPEN characteristic, which has a numeric value of 0x100, directs the I/O Manager to perform security checks on all open requests for devices of the setup class. The FILE_DEVICE_SECURE_OPEN characteristic is supported on Windows 2000 and later platforms but not on Win9x/Me platforms.

An individual device in the class can override the characteristics set by the class installer, if appropriate, by specifying a DeviceCharacteristics entry in its device INF file. See Tightening File-Open Security in a Device INF File for more information.


Writing a Device Installation Application

If your installation 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 installation package must handle two situations:

  1. The user plugs in your hardware before inserting your distribution medium.
  2. The user inserts your distribution medium before plugging in your hardware.

User Plugs in Hardware Before Inserting Distribution Medium

If the user plugs in new hardware before inserting your distribution medium into a drive, there are two scenarios to deal with:

  1. System-supplied in-box drivers support the device.

    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.

  2. System-supplied in-box drivers do not support the device.

    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 system installed the device using in-box drivers, the device installation application can re-install the device using drivers and INF files supplied on the distribution medium, using UpdateDriverForPlugAndPlayDevices. (This function can be called only if the device has already been installed.)
  • If the distribution medium contains device-specific applications, and a co-installer didn't install those applications in response to a DIF_NEWDEVICEWIZARD_FINISHINSTALL function code, the device installation application can use Microsoft® Installer to install them. (Microsoft Installer is described in Platform SDK documentation.)

User Inserts Distribution Medium Before Plugging in Hardware

If the user inserts your distribution medium before plugging in the hardware, an Autorun-invoked device installation application on the medium can:

  • Check for in-progress installations, and stop executing if other installation activities are in progress.
  • "Pre-install" driver files and INFs (see Pre-installing Driver Files).
  • Use Microsoft Installer to install device-specific applications.
  • If the device is "hot-pluggable," tell the user to plug it in. (If the bus doesn't provide hot-plug notification, initiate re-enumeration by calling CM_Reenumerate_DevNode.)
  • If the device is not hot-pluggable, tell the user to turn the system off, plug in the device, and turn the system back on.

Determining if the Device Is Plugged In

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 must call device installation functions to retrieve a list of devices and to examine each device, to determine if it is one the application can install.

Pre-installing Driver Files

To pre-install driver files, your device installation application should follow these steps:

  1. On the target system, create a directory for the driver files. If your device installation application installs an application, the driver files should be stored in a subdirectory of the application directory.
  2. Copy all files in the driver package from the distribution media to the directory created in Step 1. The driver package includes the driver or drivers, the INF file, the catalog file, and so forth.
  3. Call SetupCopyOEMInf (described in Platform SDK documentation), specifying the INF file in the directory created in Step 1. Specify SPOST_PATH for the OEMSourceMediaType parameter and specify NULL for the OEMSourceMediaLocation parameter. SetupCopyOEMInf copies the INF file for the driver package into the %windir%\Inf directory on the target system and directs SetupAPI to store the source location of the INF file in its list of preprocessed INF files. SetupCopyOEMInf also processes the catalog file, so the PnP Manager will install the driver the next time it recognizes a device listed in the INF file.

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.)

Installing Device-Specific Applications

If your distribution medium includes device-specific applications, the medium should include two methods for installing those applications:

  1. A device-specific co-installer that installs the device-specific applications when it receives the DIF_NEWDEVICEWIZARD_FINISHINSTALL function code.

    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.

  2. A device installation application that uses Windows Installer to install the device-specific applications.

    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.

Checking for In-Progress Installations

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;
    }
}

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.

Guidelines for Writing Device Installation Applications

Device installation applications must do the following:

  • Support removal ("uninstall") of all device-specific applications that it installs. As part of that uninstall process, the device installation application should check to see if any associated devices are still present on the system and, if so, warn the user.
  • Follow the guidelines for installing devices on 64-bit systems.
  • List all installed applications in Add/Remove Programs, using Microsoft® Windows® Installer (MSI), so the user can uninstall them if desired.
  • Follow the guidelines for Microsoft® Windows® applications. See the MSDN® web site for more information (http://msdn.microsoft.com).

(Submit device-specific applications to the appropriate Windows Logo program for software. See the MSDN web site for more information.)

Device installation applications must not do the following:

  • Do not instruct the user to copy or overwrite any files, especially .inf and .sys files.
  • Do not delete the installed driver files from the system during the uninstall operation, even if the hardware has been removed.
  • Do not force any unnecessary system reboots. Reboots are generally not required for installing PnP devices or software applications. The UpdateDriverForPlugAndPlayDevices function's bRebootRequired parameter indicates the need for a reboot.
  • Do not use "RunOnce" registry entries to spawn device installation applications, because this requires a system reboot.
  • Do not use a device or class co-installer, or a class installer, to spawn a device installation application, because the state of the system during device installation cannot be guaranteed to be safe for installing software applications. Specifically, if the device installation application runs on the server side, the system will hang. (However, device installation applications can be spawned from within finish-install wizard pages supplied by class installers or co-installers.)
  • Do not use the Startup Group to spawn device installation applications.
  • Do not use win.ini entries to spawn device installation applications.
  • Do not force the user to install any device-specific applications, unless the device will not operate without the application. Examples might include utilities for setting configurable keyboard keys or for setting a modem's country/region code, if an in-box application does not support such a capability.


Required Support for Device Property Pages

A provider of custom property pages must do the following:

  • Handle DIF_ADDPROPERTYPAGE_ADVANCED requests.
  • Supply a callback that handles PSPCB_CREATE and PSPCB_RELEASE messages if additional storage must be allocated and released for a property page.
  • Supply a dialog box procedure that handles Windows messages for each custom property page.

The following figure shows a sample custom properties page.

A Sample Custom Properties Page

In the previous figure, an installer supplies a property page named Properties. By default, the system supplies the General and Driver tabs shown in the figure. When appropriate, the system also provides Resources and Power tabs.

A setup component can define more than one property page for its device or class. Each tab should have a name that succinctly describes the purpose of the page. The system does not check to ensure that the names are unique.


Handling DIF_ADDPROPERTYPAGE_ADVANCED Requests

An installer that supplies one or more custom property pages must handle the DIF_ADDPROPERTYPAGE_ADVANCED device installation function code. The Device Manager, through Setupapi.dll, sends this request when a user clicks on Properties for a device in the Device Manager or in a Control Panel applet.

In response to this request, the installer provides information about each of its custom property pages, creates the pages, and adds the created pages to the list of dynamic property pages for the device.

The installer should take the following steps:

  1. Call SetupDiGetClassInstallParams to get the current class install parameters for the device. For example:
    SP_ADDPROPERTYPAGE_DATA AddPropertyPageData;
:
ZeroMemory(&AddPropertyPageData, sizeof(SP_ADDPROPERTYPAGE_DATA));
AddPropertyPageData.ClassInstallHeader.cbSize =
     sizeof(SP_CLASSINSTALL_HEADER);
if (SetupDiGetClassInstallParams(DeviceInfoSet, DeviceInfoData,
     (PSP_CLASSINSTALL_HEADER)&AddPropertyPageData,
     sizeof(SP_ADDPROPERTYPAGE_DATA), NULL )) {
…

    The example zero-initializes the structure in which the class install parameters will be returned and sets the size of the class install header in the cbSize field as required by SetupDiGetClassInstallParams. The class install header is the first member of each class install parameters structure.

    When a DIF_ADDPROPERTYPAGE_ADVANCED request is active, this function returns an SP_ADDPROPERTYPAGE_DATA structure at ClassInstallParams. Therefore, the call to the SetupDi function can cast the returned ClassInstallParams to a structure of this type.

  2. Ensure that the maximum number of dynamic pages for the device has not yet been met, with a statement like the following:
    if (AddPropertyPageData.NumDynamicPages <
    MAX_INSTALLWIZARD_DYNAPAGES)
 …

    If the test fails, do not initialize or create the page. Simply return NO_ERROR.

  3. Allocate memory in which to save any device-specific data that will be needed later in the dialog box procedure and initialize this area with the data. This data must include the DeviceInfoSet and DeviceInfoData passed with the request.

    For example, a property page provider can define and use a structure as follows:

    typedef struct _TEST_PROP_PAGE_DATA {
    HDEVINFO DeviceInfoSet;
    PSP_DEVINFO_DATA DeviceInfoData;
} TEST_PROP_PAGE_DATA, *PTEST_PROP_PAGE_DATA;
…
PTEST_PROP_PAGE_DATA     pMyPropPageData;
…
pMyPropPageData = HeapAlloc(GetProcessHeap(), 0,
     sizeof(TESTPROP_PAGE_DATA));
  4. Initialize a PROPSHEETPAGE structure with information about the custom property page:
    • In dwFlags, set the PSP_USECALLBACK flag and any other flags required for the custom property page. The PSP_USECALLBACK flag indicates that a callback function has been supplied.
    • In pfnCallback, set a pointer to the callback function for the property page.
    • In pfnDlgProc, set a pointer to the dialog box procedure for the property page.
    • In lParam, pass a pointer to the memory area allocated and initialized in step 3.
    • Set other members as appropriate for the custom property page. See the Platform SDK documentation for more information on the PROPSHEETPAGE structure.
  5. Call CreatePropertySheetPage to create the new page.
  6. Add the new page to the list of dynamic property pages in the DynamicPages member of the class install parameters and increment the NumDynamicPages member.
  7. Repeat steps 2 through 6 for each additional custom property page.
  8. Call SetupDiSetClassInstallParams to set the new class install parameters, which include the updated property page structure.
  9. Return NO_ERROR.

Setup adds the newly created property pages to the property sheet for the device, and the Device Manager makes Win32 API calls to create the sheet. When the property page is displayed, the system calls the dialog box procedure specified in the PROPSHEETPAGE structure.


Property Page Callback Function

When an installer sets up a property page for its device or device class, it supplies a pointer to a callback function. The callback function is called once when the property page is created and again when it is about to be destroyed.

The callback is a PropSheetPageProc function, which is described in the Platform SDK documentation. It must be able to handle the PSPCB_CREATE and PSPCB_RELEASE actions.

The callback is called with a PSPCB_CREATE message when a property page is being created. In response to this message, the callback can allocate memory for data associated with the page. The function should return TRUE to continue creating the page or FALSE if for some reason the page should not be created.

Property pages for a device are destroyed when the user clicks OK or Cancel on the page's dialog box or clicks Uninstall on the Drivers tab.

When a property page is being destroyed, the callback is called with a PSPCB_RELEASE message. The function should free any data allocated when the property page was created. Typically, this involves freeing the data at lParam in the PROPSHEETPAGE structure. The return value is ignored when the page is being destroyed.


Handling Windows Messages for Property Pages

When an installer that supplies property pages handles a DIF_ADDPROPERTYPAGE_ADVANCED request, it sets the address of a dialog box procedure for the property page. The dialog box procedure must initialize the property page when it gets a WM_INITDIALOG message, and it must be prepared to handle changes to device properties when it gets a WM_NOTIFY message. The procedure can also handle any other such messages it may require, as described in the Platform SDK documentation.

In response to a WM_INITDIALOG message, the dialog box procedure initializes information in the property page. Such information might include an icon that represents the device, the friendly name of the device, and its PnP device description.

SetupDiLoadClassIcon loads the icons for a specified device class and returns a handle to the loaded large icon that can be used in a subsequent call to SendDlgItemMessage. For example:

if (SetupDiLoadClassIcon(
        &pTestPropPageData->DeviceInfoData->ClassGuid, &ClassIcon,
        NULL)) {
    OldIcon = (HICON)SendDlgItemMessage(hDlg, IDC_TEST_ICON,
        STM_SETICON, (WPARAM)ClassIcon, 0);
    if (OldIcon) {
                DestroyIcon(OldIcon);
    }
}

The handle returned in ClassIcon can be cast to the WPARAM required by the SendDlgItemMessage function. In the example, IDC_TEST_ICON identifies the control in the dialog box that receives the STM_SETICON message. The value of IDC_TEST_ICON must be defined in the installer. See Device Installation Functions for additional SetupDi functions that manipulate icons and bitmaps, and see the Platform SDK documentation for more information on SendDlgItemMessage, DestroyIcon, and using icons in dialog boxes.

In addition to an icon representing the device, a typical device property page includes a description or "friendly name" of the device and shows the current settings of device properties. The PnP Manager stores the PnP properties of each device in the registry. A property page provider can call SetupDiGetDeviceRegistryProperty to get the value of any such property. If device- or class-specific configuration information has also been stored in the registry as part of the installation process, a property page provider can use other SetupDi functions to extract that information for display. See Device Installation Functions for details.

When certain types of changes occur on the page, the property sheet sends a WM_NOTIFY message to the dialog box procedure. The dialog box procedure should be prepared to extract the notification code from the message parameters and respond appropriately.

The PSN_APPLY notification is of particular interest to an installer. The property sheet sends this message when the user clicks OK or Apply. In response, the installer should validate the changes and set the DI_FLAGSEX_PROPCHANGE_PENDING flag in the device install parameters, as follows:

  1. If it has not already done so, get a pointer to the device install parameters (SP_DEVINSTALL_PARAMS structure) for the device. This structure is available by calling SetupDiGetDeviceInstallParams, passing the saved DeviceInfoSet and DeviceInfoData that were passed in the area at lParam.
  2. Ensure that the user's changes are valid.
  3. Set the DI_FLAGSEX_PROPCHANGE_PENDING flag in the FlagsEx field of the returned SP_DEVINSTALL_PARAMS structure. However, if the installer can be absolutely certain that the changes do not require the device's drivers to be stopped and then restarted, it need not set this flag.
  4. Call SetupDiSetDeviceInstallParams with the changed SP_DEVINSTALL_PARAMS structure to set the new parameters.

After the installer sets the new parameters, Setup or the Device Manager sends a DIF_PROPERTYCHANGE request.

The property sheet sends a PSN_RESET notification message when the user clicks Cancel. In response to this message, the dialog box procedure should discard any changes made by the user.

See the Platform SDK documentation for more information on the other notifications that such a procedure might encounter and how it should handle them.


Troubleshooting Device Installation

To verify that your device installed properly, you should do the following:

  • Use the Device Manager to view system information about the device.
  • Use SetupAPI Logging to identify installation errors.
  • Run test programs to exercise the device, including the testing and debugging tools supplied with this DDK.

Additionally, a co-installer or class installer can provide a troubleshooter that helps users troubleshoot problems with your device. See DIF_TROUBLESHOOTER for more information.


Using the Device Manager

To start the Device Manager, right-click on the My Computer icon, select Manage from the menu, and select Device Manager from the System Tools listed in the resulting display. The Device Manager displays information about each device, including the device type, device status, manufacturer, device-specific properties, and information about the driver for the device. See the online help in the Device Manager for more information.

If your device is a boot device, a problem with your device installation can prevent the machine from booting. In such cases, you will need to use the kernel debugger to troubleshoot your device installation. For more information, see the online documentation supplied with the Microsoft debuggers.

If your device is not required to boot the machine, you will typically notice a problem with your device installation because your device is not working properly and the Device Manager marks your device with a yellow exclamation point. The Device Manager also provides an error message. See Device Manager Error Messages.

When you are testing the installation of a new PnP device, it can be useful to have Device Manager list hidden devices. For more information, see Viewing Hidden Devices.

For Windows XP and later, the Device Manager provides a Details tab containing information that can be useful when debugging drivers. For more information, see Device Manager Details Tab.


Device Manager Error Messages

When the Device Manager marks a device with a yellow exclamation point, it also provides an error message. The following table lists the errors reported by the Device Manager. (Error codes are defined in cfg.h.)

Error Code | Problem Name
Code 1 | CM_PROB_NOT_CONFIGURED
Code 2 | CM_PROB_DEVLOADER_FAILED
Code 3 | CM_PROB_OUT_OF_MEMORY
Code 4 | CM_PROB_ENTRY_IS_WRONG_TYPE
Code 5 | CM_PROB_LACKED_ARBITRATOR
Code 6 | CM_PROB_BOOT_CONFIG_CONFLICT
Code 7 | CM_PROB_FAILED_FILTER
Code 8 | CM_PROB_DEVLOADER_NOT_FOUND
Code 9 | CM_PROB_INVALID_DATA
Code 10 | CM_PROB_FAILED_START
Code 11 | CM_PROB_LIAR
Code 12 | CM_PROB_NORMAL_CONFLICT
Code 13 | CM_PROB_NOT_VERIFIED
Code 14 | CM_PROB_NEED_RESTART
Code 15 | CM_PROB_REENUMERATION
Code 16 | CM_PROB_PARTIAL_LOG_CONF
Code 17 | CM_PROB_UNKNOWN_RESOURCE
Code 18 | CM_PROB_REINSTALL
Code 19 | CM_PROB_REGISTRY
Code 20 | CM_PROB_VXDLDR
Code 21 | CM_PROB_WILL_BE_REMOVED
Code 22 | CM_PROB_DISABLED
Code 23 | CM_PROB_DEVLOADER_NOT_READY
Code 24 | CM_PROB_DEVICE_NOT_THERE
Code 25 | CM_PROB_MOVED
Code 26 | CM_PROB_TOO_EARLY
Code 27 | CM_PROB_NO_VALID_LOG_CONF
Code 28 | CM_PROB_FAILED_INSTALL
Code 29 | CM_PROB_HARDWARE_DISABLED
Code 30 | CM_PROB_CANT_SHARE_IRQ
Code 31 | CM_PROB_FAILED_ADD
Code 32 | CM_PROB_DISABLED_SERVICE
Code 33 | CM_PROB_TRANSLATION_FAILED
Code 34 | CM_PROB_NO_SOFTCONFIG
Code 35 | CM_PROB_BIOS_TABLE
Code 36 | CM_PROB_IRQ_TRANSLATION_FAILED
Code 37 | CM_PROB_FAILED_DRIVER_ENTRY
Code 38 | CM_PROB_DRIVER_FAILED_PRIOR_UNLOAD
Code 39 | CM_PROB_DRIVER_FAILED_LOAD
Code 40 | CM_PROB_DRIVER_SERVICE_KEY_INVALID
Code 41 | CM_PROB_LEGACY_SERVICE_NO_DEVICES
Code 42 | CM_PROB_DUPLICATE_DEVICE
Code 43 | CM_PROB_FAILED_POST_START
Code 44 | CM_PROB_HALTED
Code 45 | CM_PROB_PHANTOM
Code 46 | CM_PROB_SYSTEM_SHUTDOWN
Code 47 | CM_PROB_HELD_FOR_EJECT
Code 48 | CM_PROB_DRIVER_BLOCKED
Code 49 | IDS_PROB_REGISTRY_TOO_LARGE


CM_PROB_NOT_CONFIGURED

There is a device on the system for which there is no ConfigFlags registry entry, meaning no driver is installed. Typically this means an INF file could not be found.

Error Code

1

Display Message – NT-based Systems

"This device is not configured correctly. (Code 1)"

"To Update the drivers for this device, click Update Driver. If that doesn't work, see your hardware documentation for more information."

Recommended Resolution – NT-based Systems

Select Update Driver, which starts the Update Driver wizard.

Display Message – Windows 98/Me

"This device is not configured correctly. (Code 1)"

"To Update the drivers for this device, click Update Driver. If that doesn't work, see your hardware documentation for more information."

Recommended Resolution – Windows 98/Me

Select Update Driver, which starts the Update Driver wizard.


CM_PROB_DEVLOADER_FAILED

Device loader failed to load drivers.

Error Code

2

Display Message – NT-based Systems

Not used.

Recommended Resolution – NT-based Systems

Not used.

Display Message – Windows 98/Me

  1. If this is a Root bus device loader:

    "Windows could not load the driver for this device because the computer is reporting two <bustype> bus types. (Code 2)"

    "Contact your computer manufacturer to get an updated BIOS for your computer."

  2. If this is not a Root bus device loader:

    "The <device-loader-names> device loader(s) for this device could not load the device driver. (Code 2)"

    "To fix this, click Update Driver to update the device driver."

Recommended Resolution – Windows 98/Me

Solution for (1): Update BIOS.

Solution for (2): Select Update Driver, which starts the Update Driver wizard.


CM_PROB_OUT_OF_MEMORY

Running out of memory – the system is probably running low on system memory.

Error Code

3

Display Message – NT-based Systems

"The driver for this device might be corrupted, or your system may be running low on memory or other resources. (Code 3)"

Recommended Resolution – NT-based Systems

Select Update Driver, which starts the Update Driver wizard.

Display Message – Windows 98/Me

"The driver for this device may be bad, or your system may be running low on memory or other resources. (Code 3)"

"To Update the drivers for this device, click Update Driver. To check your computer's memory and system resources, right-click My Computer on your desktop, click Properties, and then click the Performance tab."

Recommended Resolution – Windows 98/Me

Select Update Driver, which starts the Update Driver wizard.


CM_PROB_ENTRY_IS_WRONG_TYPE

Registry entries are incorrect.

Error Code

4

Display Message – NT-based Systems

Not used.

Recommended Resolution – NT-based Systems

Not used.

Display Message – Windows 98/Me

"This device is not working properly because one of its drivers may be bad, or your registry may be bad. (Code 4)"

To Update the drivers for this device, click Update Driver. If that doesn't work, run Scanregw.exe (click Start, click Run, type Scanregw.exe, and then click OK) to check your registry."

Recommended Resolution – Windows 98/Me

Select Update Driver, which starts the Update Driver wizard, or run scanregw.exe.


CM_PROB_LACKED_ARBITRATOR

The system lacks a resource arbitrator to resolve resource conflicts.

Error Code

5

Display Message – NT-based Systems

Not used.

Recommended Resolution – NT-based Systems

Not used.

Display Message – Windows 98/Me

"The driver for this device requested a resource that Windows does not know how to handle. (Code 5)"

"To fix this, click Update Driver to update the driver for this device."

Recommended Resolution – Windows 98/Me

Select Update Driver, which starts the Update Driver wizard.


CM_PROB_BOOT_CONFIG_CONFLICT

The boot configuration contains resource conflicts.

Error Code

6

Display Message – NT-based Systems

Not used.

Recommended Resolution – NT-based Systems

Not used.

Display Message – Windows 98/Me

"Another device is using the resources this device needs. (Code 6)"

"To fix this, shut down your computer, turn it off, and then change the resources for this device. When you have finished, start Device Manager and change the resource settings for this device."

Recommended Resolution – Windows 98/Me

Select Hardware Troubleshooter, which will launch the hardware troubleshooter wizard.


CM_PROB_FAILED_FILTER

Filtering failed.

Error Code

7

Display Message – NT-based Systems

Not used.

Recommended Resolution – NT-based Systems

Not used.

Display Message – Windows 98/Me

If the device's hardware key contains a "FailReasonString" value, the value string is displayed as the error message. (A driver or enumerator supplies this registry string value.) If the hardware key does not contain a "FailReasonString" value, the following generic error message is displayed:

"The drivers for this device need to be reinstalled. (Code 7)"

"To reinstall the drivers for this device, click Reinstall Driver."

Recommended Resolution – Windows 98/Me

Select Reinstall Driver, which starts the Update Driver wizard and reinstalls the current driver.


CM_PROB_DEVLOADER_NOT_FOUND

A device loader was not found.

Error Code

8

Display Message – NT-based Systems

Not used.

Recommended Resolution – NT-based Systems

Not used.

Display Message – Windows 98/Me

  1. If the device loader is a system device loader (that is, it begins with a "*", meaning it is part of VMM32) then the following text is displayed:

    "This device is not working properly because Windows cannot load the file (device-loader-filename) that loads the drivers for the device. (Code 8)"

    "To fix this problem, run Windows Setup again using your Windows CD-ROM."

  2. If this is not a system devloader and the devloader cannot be found (the file is missing), the following text is displayed:

    "This device is not working properly because Windows cannot load the file (device-loader-filename) that loads the drivers for the device. (Code 8)"

    "To fix this problem, click Reinstall Device to reinstall this device."

  3. If this is not a system devloader and it can be found on the disk (the file does exist) the following text is displayed:

    "This device is not working properly because the file (device-loader-filename) that loads the drivers for this device is bad. (Code 8)

    "To fix this problem, click Update Driver to update the drivers for this device."

  4. If the device's software key does not contain a "devloader" entry, or if the entry does not have a value assigned to it, the following text is displayed:

    "Device failure: Try changing the driver for this device. If that doesn't work, see your hardware documentation. (Code 8)"

Recommended Resolution – Windows 98/Me

Solution for (1) : Run Windows Setup again using your Windows CD-ROM.

Solution for (2): Select Reinstall Driver, which starts the Update Driver wizard and reinstalls the current driver.

Solution for (3): Select Update Driver, which starts the Update Driver wizard.

Solution for (4): Select Update Driver, which starts the Update Driver wizard.


CM_PROB_INVALID_DATA

Invalid data has been detected in the registry.

Error Code

9

Display Message – NT-based Systems

Not used.

Recommended Resolution – NT-based Systems

Not used.

Display Message – Windows 98/Me

  1. If the device is enumerated by the BIOS or ACPI, the following text is displayed:

    "This device is not working properly because the BIOS in your computer is reporting the resources for the device incorrectly. (Code 9)"

    "Contact your computer manufacturer to get an updated BIOS for your computer."

  2. If the device is not enumerated by the BIOS or ACPI (that is, it is an add-in card or a device that was plugged into the computer), the following text is displayed:

    "This device is not working properly because the BIOS in the device is reporting the resources for the device incorrectly. (Code 9)"

    "Contact the device manufacturer to get an updated BIOS for your "device.

Recommended Resolution – Windows 98/Me

Solution for (1): Update the BIOS.

Solution for (2): Update the BIOS.


CM_PROB_FAILED_START

The device failed to start.

Error Code

10

Display Message – NT-based Systems

If the device's hardware key contains a "FailReasonString" value, the value string is displayed as the error message. (A driver or enumerator supplies this registry string value.) If the hardware key does not contain a "FailReasonString" value, the following generic error message is displayed:

"This device cannot start. (Code 10)"

"Try upgrading the device drivers for this device."

Recommended Resolution – NT-based Systems

Select Update Driver, which starts the Update Driver wizard.

This error code is set when one of the drivers in the device's driver stack fails IRP_MN_START_DEVICE. If there are many drivers in the stack, it can be difficult to determine the one that failed.

Display Message – Windows 98/Me

If the device's hardware key contains a "FailReasonString" value, the value string is displayed as the error message. (A driver or enumerator supplies this registry string value.) If the hardware key does not contain a "FailReasonString" value, the following generic error message is displayed:

"This device is either not present, not working properly, or does not have all the drivers installed. (Code 10)"

"Try upgrading the device drivers for this device."

Recommended Resolution – Windows 98/Me

Select Update Driver, which starts the Update Driver wizard.


CM_PROB_LIAR

Automatic Skip Driver Agent (ASD) error.

Error Code

11

Display Message– NT-based Systems

Not used.

Recommended Resolution – NT-based Systems

Not used.

Display Message – Windows 98/Me

"Windows stopped responding while attempting to start this device, and therefore will never attempt to start this device again. (Code 11)"

"For more information, look up ASD in Windows Help."

"Try upgrading the device drivers for this device."

Recommended Resolution – Windows 98/Me

Select Update Driver, which starts the Update Driver wizard.


CM_PROB_NORMAL_CONFLICT

Two devices have been assigned the same I/O ports, the same interrupt, or the same DMA channel (either by the BIOS, the operating system, or a combination of the two).

Error Code

12

Display Message – NT-based Systems

"This device cannot find enough free resources that it can use. (Code 12)

"If you want to use this device, you will need to disable one of the other devices on this system."

Recommended Resolution – NT-based Systems

Select Hardware Troubleshooter, which starts the hardware troubleshooter.

This error message can also appear if the BIOS did not give a device enough resources (for example, if a USB controller doesn't get an interrupt from the BIOS because of a bad MPS table).

Display Message – Windows 98/Me

"This device cannot find any free <resource-type> resources to use. (Code 12)"

"If you want to use this device, you must disable another device that is using the resources this device needs. To do this, click Hardware Troubleshooter and follow the instructions in the wizard."

Recommended Resolution – Windows 98/Me

Select Hardware Troubleshooter, which starts the hardware troubleshooter.


CM_PROB_NOT_VERIFIED

The device could not be verified.

Error Code

13

Display Message – NT-based Systems

Not used.

Recommended Resolution – NT-based Systems

Not used.

Display Message – Windows 98/Me

"This device is either not present, not working properly, or does not have all the drivers installed. (Code 13)"

"To have Windows detect whether this device is present or not, click Detect Hardware."

Recommended Resolution – Windows 98/Me

Select Detect Hardware, which starts the legacy detection wizard.


CM_PROB_NEED_RESTART

The system must be restarted.

Error Code

14

Display Message – NT-based Systems

"This device cannot work properly until you restart your computer. (Code 14)

"To restart your computer now, click Restart Computer."

Recommended Resolution – NT-based Systems

Select Restart Computer, which restarts your computer.

Display Message – Windows 98/Me

"This device cannot work properly until you restart your computer. (Code 14)"

"To restart your computer now, click Restart Computer."

Recommended Resolution – Windows 98/Me

Select Restart Computer, which restarts your computer.


CM_PROB_REENUMERATION

The device is causing a resource conflict.

Error Code

15

Display Message – NT-based Systems

Not used.

Recommended Resolution – NT-based Systems

Not used.

Display Message – Windows 98/Me

"This device is causing a resource conflict. (Code 15)"

"To resolve the conflict, click Hardware Troubleshooter and follow the instructions in the wizard."

Recommended Resolution – Windows 98/Me

Select Hardware Troubleshooter, which starts the hardware troubleshooter.


CM_PROB_PARTIAL_LOG_CONF

The device is only partially configured.

Error Code

16

Display Message – NT-based Systems

"Windows cannot identify all the resources this device uses. (Code 16)

"To specify additional resources for this device, click the Resources tab and fill in the missing settings. Check your hardware documentation to find out what settings to use."

Recommended Resolution – NT-based Systems

Use the Resources tab to supply additional resources.

Display Message – Windows 98/Me

"Windows could not identify all the resources this device uses. (Code 16)"

"To specify additional resources for this device, click the Resources tab and fill in the missing settings. Check your hardware documentation to find out what settings to use."

Recommended Resolution – Windows 98/Me

Use the Resources tab to supply additional resources.


CM_PROB_UNKNOWN_RESOURCE

An unknown resource was specified in an INF file.

Error Code

17

Display Message – NT-based Systems

Not used.

Recommended Resolution – NT-based Systems

Not used.

Display Message – Windows 98/Me

"The driver information file (INF-file-name) is telling this child device to use a resource that the parent device does not have or recognize. (Code 17)"

"To fix this, click Update Driver to update the drivers for this device."

Recommended Resolution – Windows 98/Me

Select Update Driver to update the device's drivers.


CM_PROB_REINSTALL

Drivers must be reinstalled.

Error Code

18

Display Message – NT-based Systems

"Reinstall the drivers for this device. (Code 18)"

Recommended Resolution – NT-based Systems

Windows XP starts the Hardware Update wizard.

Display Message – Windows 98/Me

"The drivers for this device need to be reinstalled. (Code 18)"

"To reinstall the drivers for this device, click Reinstall Driver."

Recommended Resolution – Windows 98/Me

Select Reinstall Driver, which will reinstall the drivers.


CM_PROB_REGISTRY

A registry problem was detected.

Error Code

19

Display Message – NT-based Systems

"Windows cannot start this hardware device because its configuration information (in the registry) is incomplete or damaged. (Code 19)"

Recommended Resolution – NT-based Systems

This can be set if more than one service is defined for a device, there is a failure opening the service key, or the driver name can't be obtained from the service key.

Display Message – Windows 98/Me

"Your registry may be bad. (Code 19)"

"To check your registry, click Check Registry. If the registry is bad, Windows will restart your system and go back to a previous registry that is good."

Recommended Resolution – Windows 98/Me

Select Check Registry, which will start the registry checker utility.


CM_PROB_VXDLDR

VxDLdr returned an unknown result.

Error Code

20

Display Message – NT-based Systems

Not used.

Recommended Resolution – NT-based Systems

Not used.

Display Message – Windows 98/Me

"Windows could not load one of the drivers for this device. (Code 20)"

"To fix this, click Update Driver to update the drivers for this device."

Recommended Resolution – Windows 98/Me

Select Update Driver, which starts the Update Driver wizard.


CM_PROB_WILL_BE_REMOVED

The system will remove the device.

Error Code

21

Display Message – NT-based Systems

"Windows is removing this device. (Code 21)"

"Close this dialog box, and then wait a few seconds. If this problem continues, restart your computer."

Recommended Resolution – NT-based Systems

Select Restart Computer, which will restart the computer.

Display Message – Windows 98/Me

"Windows is removing this device. (Code 21)"

"Close this dialog box, and then wait a few seconds. If this problem continues, restart your computer."

Recommended Resolution – Windows 98/Me

Select Restart Computer, which will restart the computer.


CM_PROB_DISABLED

The device is disabled.

Error Code

22

Display Message – NT-based Systems

"This device is disabled. (Code 22)"

Recommended Resolution – NT-based Systems

The device is disabled because the user disabled it using Device Manager. Select Enable Device, which will enable the device.

Display Message – Windows 98/Me

  1. If this device is disabled because the user disabled it using Device Manager, the following text is displayed:

    "This device is disabled. (Code 22)"

    "Click Enable Device to enable this device."

  2. If the device is not started, the following text is displayed:

    "This device is not started. (Code 22)"

    "Click Start Device to start this device."

  3. If the device is disabled by a driver or software program, the following text is displayed:

    "This device is disabled. (Code 22)"

    "You can't enable this device because it has been disabled by a Windows driver."

Recommended Resolution – Windows 98/Me

Solution for (1): Select Enable Device, which will enable the device.

Solution for (2): Select Start Device, which will start the device.

Solution for (3): None.


CM_PROB_DEVLOADER_NOT_READY

The device loader was not ready.

Error Code

23

Display Message – NT-based Systems

Not used.

Recommended Resolution – NT-based Systems

Not used.

Display Message – Windows 98/Me

  1. If this device is a secondary display adapter and the primary display adapter was located, the following text is displayed:

    "This display adapter is functioning correctly. (Code 23)"

    "The problem is with the main display adapter. To view the properties for the main display adapter, click Properties."

  2. If this device is a secondary display adapter and the primary display adapter cannot be located, the following text is displayed:

    "This display adapter is functioning correctly. (Code 23)"

    "The problem is with the main display adapter. Fix the main display adapter, and then this display adapter will work."

  3. If this device is not a display adapter, the following text is displayed:

    "The loaders for this device cannot load the required drivers. (Code 23)"

    "To update the device drivers, click Update Driver."

Recommended Resolution – Windows 98/Me

Solution for (1): Select Properties, which will display the property page for the primary display adapter.

Solution for (2): Fix the main display adapter.

Solution for (3): Select Update Driver, which starts the Update Driver wizard.


CM_PROB_DEVICE_NOT_THERE

The device doesn't appear to be present.

Error Code

24

Display Message – NT-based Systems

"This device is not present, is not working properly, or does not have all its drivers installed. (Code 24)"

Recommended Resolution – NT-based Systems

The problem could be bad hardware, or a new driver might be needed. Devices stay in this state if they have been prepared for removal. This error code can be set if a driver's DriverEntry routine detects a device but the DriverEntry routine later fails. (For Windows XP and later, DriverEntry problems have separate error codes.)

Display Message – Windows 98/Me

  1. If this device is a legacy (root detected) device then the following text will be displayed:

    "This device is either not present, not working properly, or does not have all the drivers installed. (Code 24)"

    "To have Windows detect whether this device is present or not, click Detect Hardware."

  2. If this is a Plug and Play device then the following text is displayed:

    "This device is either not present, not working properly, or does not have all the drivers installed. (Code 24)"

    "Try upgrading the device drivers for this device."

Recommended Resolution – Windows 98/Me

Solution for (1): Select Detect Hardware, which starts the legacy detection wizard.

Solution for (2): Select Update Driver, which starts the Update Driver wizard.


CM_PROB_MOVED

The device has been moved.

Error Code

25

Display Message – NT-based Systems

Not used.

Recommended Resolution – NT-based Systems

Not used.

Display Message – Windows 98/Me

"Windows is in the process of setting up this device. (Code 25)"

"To complete the setup, click Restart Computer to restart you computer."

Recommended Resolution – Windows 98/Me

Select Restart Computer, which will restart the computer.


CM_PROB_TOO_EARLY

Too early.

Error Code

26

Display Message – NT-based Systems

Not used.

Recommended Resolution – NT-based Systems

Not used.

Display Message – Windows 98/Me

"Windows is in the process of setting up this device. (Code 26)"

"To complete the setup, click Restart Computer to restart you computer."

Recommended Resolution – Windows 98/Me

Select Restart Computer, which will restart the computer.


CM_PROB_NO_VALID_LOG_CONF

A valid logical configuration does not exist.

Error Code

27

Display Message – NT-based Systems

Not used.

Recommended Resolution – NT-based Systems

Not used.

Display Message – Windows 98/Me

"Windows can't specify the resources for this device. (Code 27)"

"Click the Resources tab, and then select the basic configuration for the resources this device uses. To see which resources this device uses, see the documentation for this device."

Recommended Resolution – Windows 98/Me

Select resources for the device.


CM_PROB_FAILED_INSTALL

The device's drivers are not installed.

Error Code

28

Display Message – NT-based Systems

"The drivers for this device are not installed. (Code 28)"

Recommended Resolution – NT-based Systems

Reinstall the device's drivers.

Display Message – Windows 98/Me

"The drivers for this device are not installed (Code 28)."

"To reinstall the drivers for this device, click Reinstall Driver."

Recommended Resolution – Windows 98/Me

Select Reinstall Driver, which reinstalls the device's drivers.


CM_PROB_HARDWARE_DISABLED

The device is disabled.

Error Code

29

Display Message – NT-based Systems

"This device is disabled because the firmware of the device did not give it the required resources. (Code 29)"

Recommended Resolution – NT-based Systems

Enable the device in the BIOS.

Display Message – Windows 98/Me

"This device is disabled because the BIOS for the device did not give it any resources. (Code 29)"

"You must enable the device in the BIOS. See your hardware documentation for details, or contact your computer manufacturer to get an updated BIOS."

Recommended Resolution – Windows 98/Me

Enable the device in the BIOS.


CM_PROB_CANT_SHARE_IRQ

The IRQ cannot be shared.

Error Code

30

Display Message – NT-based Systems

Not used.

Recommended Resolution – NT-based Systems

Not used.

Display Message – Windows 98/Me

"This device is using an Interrupt Request (IRQ) resource that is in use by another device and cannot be shared. You must change the conflicting setting or remove the real-mode driver causing the conflict. (Code 30)"

Recommended Resolution – Windows 98/Me

Change the device's resources or remove the other device.


CM_PROB_FAILED_ADD

A driver's attempt to add a device failed.

Error Code

31

Display Message – NT-based Systems

"This device is not working properly because Windows cannot load the drivers required for this device. (Code 31)"

Recommended Resolution – NT-based Systems

CM_PROB_FAILED_ADD can occur if the service key is corrupted, the driver's image could not be loaded from the disk, its DriverEntry routine failed, it couldn't unload due to a leaked reference, it was a legacy driver that created no device objects, or its AddDevice routine failed.

For Windows XP and later, CM_PROB_FAILED_ADD only occurs if the driver's AddDevice routine fails. All the other failures have separate problem codes.

Display Message – Windows 98/Me

"This device is not working properly because <dependent-device-name> is not working properly. (Code 31)"

"To view the properties for <dependent-device-name> and see why it is not working, click Properties."

Recommended Resolution – Windows 98/Me

Select Properties to bring up the property page for the dependent device that has the problem.


CM_PROB_DISABLED_SERVICE

The driver has been disabled (NT-based systems).

The installation media is not ready (Windows 98/Me).

Error Code

32

Display Message – NT-based Systems

"A driver (service) for this device has been disabled. An alternate driver may be providing this functionality. (Code 32)"

Recommended Resolution – NT-based Systems

The start type for this service is set to Disabled in the registry. If the driver really is required, change the start type.

Display Message – Windows 98/Me

"Windows cannot install the drivers for this device because it cannot access the drive or network location that has the setup files on it. (Code 32)"

"To fix this problem, click Restart Computer to restart your computer. If that doesn't work copy all the setup files onto your local hard disk, and run setup from there."

Recommended Resolution – Windows 98/Me

Select Restart Computer, which will restart the computer. If that doesn't work, copy setup files to your hard disk.


CM_PROB_TRANSLATION_FAILED

Translator failed. (NT-based systems)

Hardware malfunction (Windows 98/Me)

Error Code

33

Display Message – NT-based Systems

"Windows cannot determine which resources are required for this device. (Code 33)"

Recommended Resolution – NT-based Systems

Configure, repair, or replace hardware.

Display Message – Windows 98/Me

If the device's hardware key contains a "FailReasonString" value, the value string is displayed as the error message. (A driver or enumerator supplies this registry string value.) If the hardware key does not contain a "FailReasonString" value, the following generic error message is displayed:

"This device isn't responding to its driver. (Code 33)"

"For more information, contact your hardware vendor."

Recommended Resolution – Windows 98/Me

Configure, repair, or replace hardware.


CM_PROB_NO_SOFTCONFIG

The device requires a forced configuration.

Error Code

34

Display Message – NT-based Systems

"Windows cannot determine the settings for this device. Consult the documentation that came with this device and use the Resource tab to set the configuration. (Code 34)"

Recommended Resolution – NT-based Systems

Change the HW settings (by setting jumpers or running a vendor-supplied utility) and then use the Device Manager's Resources tab to set the forced configuration.

Display Message – Windows 98/Me

Not used.

Recommended Resolution – Windows 98/Me

Not used.


CM_PROB_BIOS_TABLE

The MPS table is bad and needs to be updated.

Error Code

35

Display Message – NT-based Systems

"Your computer's system firmware does not include enough information to properly configure and use this device. To use this device, contact your computer manufacturer to obtain a firmware or BIOS update. (Code 35)"

Recommended Resolution – NT-based Systems

Obtain a new BIOS from the system vendor.

Display Message – Windows 98/Me

Not used.

Recommended Resolution – Windows 98/Me

Not used.


CM_PROB_IRQ_TRANSLATION_FAILED

IRQ translation failed.

Error Code

36

Display Message – NT-based Systems

"This device is requesting a PCI interrupt but is configured for an ISA interrupt (or vice versa). Please use the computer's system setup program to reconfigure the interrupt for this device. (Code 36)"

Recommended Resolution – NT-based Systems

Try using the BIOS setup utility to change settings for IRQ reservations, if such an option exists. (The BIOS might have options to reserve certain IRQs for PCI or ISA devices.)

Display Message – Windows 98/Me

Not used.

Recommended Resolution – Windows 98/Me

Not used.


CM_PROB_FAILED_DRIVER_ENTRY

The driver returned failure from its DriverEntry routine.

Error Code

37

Display Message – NT-based Systems

"Windows cannot initialize the device driver for this hardware. (Code 37)"

Recommended Resolution – NT-based Systems

Reinstall or obtain a new driver.

(Note that if DriverEntry returns STATUS_INSUFFICIENT_RESOURCES, the error code is CM_PROB_OUT_OF_MEMORY.)

Display Message – Windows 98/Me

Not used.

Recommended Resolution – Windows 98/Me

Not used.


CM_PROB_DRIVER_FAILED_PRIOR_UNLOAD

The driver could not be loaded because a previous instance is still loaded.

Error Code

38

Display Message – NT-based Systems

"Windows cannot load the device driver for this hardware because a previous instance of the device driver is still in memory. (Code 38)"

Recommended Resolution – NT-based Systems

A previous driver instance can still be loaded due to an improper reference count or a race between load and unload operations. Additionally, this message can appear if a driver is referenced by multiple INF AddService directives in one ore more INF files.

Select Restart Computer, which will restart the computer.

Display Message – Windows 98/Me

Not used.

Recommended Resolution – Windows 98/Me

Not used.


CM_PROB_DRIVER_FAILED_LOAD

The driver could not be loaded.

Error Code

39

Display Message – NT-based Systems

"Windows cannot load the device driver for this hardware. The driver may be corrupted or missing. (Code 39)"

Recommended Resolution – NT-based Systems

Reinstall or obtain a new driver.

Reasons for this error include a driver that is not present, a binary file that is corrupted, a file I/O problem, or a driver that references an entry point in another binary that could not be loaded.

Display Message – Windows 98/Me

Not used.

Recommended Resolution – Windows 98/Me

Not used.


CM_PROB_DRIVER_SERVICE_KEY_INVALID

Information in the registry's service key for the driver is invalid.

Error Code

40

Display Message – NT-based Systems

"Windows cannot access this hardware because its service key information in the registry is missing or recorded incorrectly. (Code 40)"

Recommended Resolution – NT-based Systems

Reinstall the driver.

Display Message – Windows 98/Me

Not used.

Recommended Resolution – Windows 98/Me

Not used.


CM_PROB_LEGACY_SERVICE_NO_DEVICES

A driver was loaded but Windows cannot find the device.

Error Code

41

Display Message – NT-based Systems

"Windows successfully loaded the device driver for this hardware but cannot find the hardware device. (Code 41)"

Recommended Resolution – NT-based Systems

Reinstall the device.

This is a legacy root service that didn't create a device object.

Display Message – Windows 98/Me

Not used.

Recommended Resolution – Windows 98/Me

Not used.


CM_PROB_DUPLICATE_DEVICE

A duplicate device was detected.

Error Code

42

Display Message – NT-based Systems

"Windows cannot load the device driver for this hardware because there is a duplicate device already running in the system. (Code 42)"

Recommended Resolution – NT-based Systems

Select Restart Computer, which will restart the computer.

This error occurs when a bus driver erroneously creates two identically named children, or when a device with a serial number is discovered in a new location before it is noticed missing from the old location.

Display Message – Windows 98/Me

Not used.

Recommended Resolution – Windows 98/Me

Not used.


CM_PROB_FAILED_POST_START

A driver has reported a device failure.

Error Code

43

Display Message – NT-based Systems

"Windows has stopped this device because it has reported problems. (Code 43)"

Recommended Resolution – NT-based Systems

Uninstall and reinstall the device.

One of the drivers controlling the device told the OS the device failed in some manner in response to IRP_MN_QUERY_PNP_DEVICE_STATE.

Display Message – Windows 98/Me

Not used.

Recommended Resolution – Windows 98/Me

Not used.


CM_PROB_HALTED

The device has been stopped.

Error Code

44

Display Message – NT-based Systems

"An application or service has shut down this hardware device. (Code 44)"

Recommended Resolution – NT-based Systems

Solution is to reboot.

Display Message – Windows 98/Me

Not used.

Recommended Resolution – Windows 98/Me

Not used.


CM_PROB_PHANTOM

The device is not present.

Error Code

45

Display Message – NT-based Systems

"Currently, this hardware device is not connected to the computer. (Code 45)"

"To fix this problem, reconnect this hardware device to the computer."

Recommended Resolution – NT-based Systems

None. This problem code should only appear when the SHOW_NONPRESENT_DEVICES environment variable is set.

Display Message – Windows 98/Me

Not used.

Recommended Resolution – Windows 98/Me

Not used.


CM_PROB_SYSTEM_SHUTDOWN

The device is not available because the system is shutting down.

Error Code

46

Display Message – NT-based Systems

"Windows cannot gain access to this hardware device because the operating system is in the process of shutting down. (Code 46)

"The hardware device should work correctly next time you start your computer."

Recommended Resolution – NT-based Systems

None. This error code is only set when Driver Verifier is enabled and all applications have already been shut down.

Display Message – Windows 98/Me

Not used.

Recommended Resolution – Windows 98/Me

Not used.


CM_PROB_HELD_FOR_EJECT

The device has been prepared for ejection.

Error Code

47

Display Message – NT-based Systems

"Windows cannot use this hardware device because it has been prepared for 'safe removal', but it has not been removed from the computer. (Code 47)"

"To fix this problem, unplug this device from your computer and then plug it in again."

Recommended Resolution – NT-based Systems

Unplug the device and plug it in again. Alternately, selecting Restart Computer will restart the computer and make the device available.

This error should occur only if the user invoked the hotplug applet to prepare the device for removal (which calls CM_Request_Device_Eject), or pressed a physical eject button (which calls IoRequestDeviceEject). It is possible that the user prepared a device that is currently not removable, such as a CD-ROM trapped between the laptop and the docking station tray.

Display Message – Windows 98/Me

Not used.

Recommended Resolution – Windows 98/Me

Not used.


CM_PROB_DRIVER_BLOCKED

The system will not load the driver because it is listed in the defective drivers database supplied by Windows Update .

Error Code

48

Display Message – NT-based Systems

"The software for this device has been blocked from starting because it is known to have problems with Windows. Contact the hardware vendor for a new driver. (Code 48)"

Recommended Resolution – NT-based Systems

Obtain a new driver from the hardware vendor.

Display Message – Windows 98/Me

Not used.

Recommended Resolution – Windows 98/Me

Not used.


IDS_PROB_REGISTRY_TOO_LARGE

Error Code

49

Display Message – NT-based Systems

"Windows cannot start new hardware devices because the system hive is too large (exceeds the Registry Size Limit). (Code 49)"

Recommended Resolution – NT-based Systems

Set the environment variable DEVMGR_SHOW_NONPRESENT_DEVICES to 1, which causes the Device Manager to display installed devices that are not currently present. Use the Device Manager to remove these devices. If the registry is still too large, reinstall Windows.

Display Message – Windows 98/Me

Not used.

Recommended Resolution – Windows 98/Me

Not used.


Device Manager Details Tab

For Windows XP and later, the Device Manager provides a Details tab for each device. This tab displays lots of information useful to driver developers and testers, and aids Microsoft Product Support Services (PSS) in diagnosing customer problems. The tab's page displays device identification strings, along with device and driver configuration information that can be useful when debugging drivers.

Viewing a Device's Details Tab

The Details tab is disabled by default. To enable it, open a Command Prompt window and type the following command:

set DEVMGR_SHOW_DETAILS=1

After you have issued this command, a device's Details tab will be available when you select the device in the Device Manager.

Providing Firmware Revision Numbers for the Details Tab

The Device Manager's Details tab can display a device's firmware revision number, if available. A driver can supply a firmware revision number by responding to a WMI request. Specifically, the driver's DpWmiQueryDataBlock routine should support MSDeviceUI_FirmwareRevision_GUID by returning a DEVICE_UI_FIRMWARE_REVISION structure (defined in wmidata.h). The structure must contain the firmware revision number as a NULL-terminated WCHAR string, preceded by a USHORT value that contains the string length (including the NULL).


Viewing Hidden Devices

The Device Manager lists the devices that are installed on the machine. By default, certain devices are not shown in the list. These "hidden" devices include devices that have the devnode status bit DN_NO_SHOW_IN_DM set and devices that are part of a setup class that is marked as a NoDisplayClass in the registry (for example, printers and non-PnP drivers).

To include hidden devices in the Device Manager display, click View and select Show Hidden Devices.

Another category of devices, not shown in the Device Manager by default, includes devices that have been physically removed from the machine but whose registry entries have not been deleted. These devices can be considered "nonpresent" devices. Users should never need to view such devices because a nonpresent device should not need their attention and should not cause any problems. If a user needs to view your device when it is not present, there is likely a problem with your driver design.

During testing, however, you might need to view such devices. To view nonpresent devices, open a Command Prompt window and type the following command:

set DEVMGR_SHOW_NONPRESENT_DEVICES=1

(You can also set this value in a permanent environment value using the Advanced tab of the system property sheet.) After you set this value, run the Device Manager and select Show Hidden Devices.


Using SetupAPI Logging

The Windows Setup and Device Installer Services, also known as SetupAPI, include the Windows functions that control Setup and device installation. As Setup proceeds, the general Setup functions (Setup Xxx functions) and device installation functions (SetupDi Xxx functions) create a log file that provides useful information for troubleshooting device installation problems.

SetupAPI logs to the file %systemroot%\setupapi.log. The log file is a plain text file. To reset the log, rename or delete the file.

This section includes the following information:

Setting SetupAPI Logging Levels

Interpreting a Sample SetupAPI Log File


Setting SetupAPI Logging Levels

You can control the amount of information that is written to the SetupAPI log, either for all Setup applications or for individual Setup applications.

To change the level of information written to the SetupAPI log for all Setup applications, create (or modify) the following registry value:

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Setup\LogLevel
‹ ›

By setting this value (using the values listed in the tables below) you can choose the level of errors that are logged, modify the verbosity of logging, or turn off logging. You can also log information to a debugger as well as to the log file.

To specify logging levels for individual Setup applications, create a registry entry under the following key:

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Setup\AppLogLevels

Under this key, create a value name representing the application's executable file name, and assign the desired logging level to that name (using the values listed in the tables below), such as service.exe=LoggingLevel.

The logging level is a DWORD value. If this value is not specified or is zero, SetupAPI uses a default behavior, as indicated in the tables below.

The DWORD value is made up of three parts, formatted as 0xSSSSDDGG. The low eight bits, represented by the mask 0x000000FF, set the logging level for general Setup operations. The next-higher eight bits, represented by the mask 0x0000FF00, set the logging level for device installation operations. The highest bits are special flags.

The following tables contain the general logging levels, device installation logging levels, and special logging flags for Windows 2000 and later.

General Logging Levels | Meaning
0x00000000 | Use default settings (currently 0x20).
0x00000001 | Off (no Setup logging).
0x00000010 | Log errors.
0x00000020 | Log errors and warnings.
0x00000030 | Log errors, warnings and other information.
0x00000040 | Log errors, warnings and other information in verbose mode.
0x00000050 | Log errors, warnings and other information in verbose mode, plus time-stamped entries.
0x00000060 | Log errors, warnings and other information in verbose mode, plus time entries. Additionally, all entries are time-stamped.
0x00000070 | Log errors, warnings and other information in verbose mode, plus time messages. All entries are time-stamped. Additional messages that can slow down the system, such as cache hits, are included.
0x000000FF | Specifies the most verbose logging available.

Device Logging Levels | Meaning
0x00000000 | Use default settings (currently 0x3000).
0x00000100 | Off (no Setup logging).
0x00001000 | Log errors.
0x00002000 | Log errors and warnings.
0x00003000 | Log errors, warnings and other information.
0x00004000 | Log errors, warnings and other information in verbose mode.
0x00005000 | Log errors, warnings and other information in verbose mode, plus time-stamped entries.
0x00006000 | Log errors, warnings and other information in verbose mode, plus time entries. Additionally, all entries are time-stamped.
0x00007000 | Log errors, warnings and other information in verbose mode, plus time messages. All entries are time-stamped. Additional messages that can slow down the system, such as cache hits, are included.
0x0000FF00 | Specifies the most verbose logging available.

Special Flags | Meaning
0x08000000 | (Windows XP and later) Add a time stamp to all log entries.
0x20000000 | (Windows XP and later) Don't flush logging information to disk after each entry is written. (Logging is faster, but information could be lost if the system crashes.)
0x40000000 | Write log entries chronologically instead of grouping entries.
0x80000000 | Send the output to the debugger as well as to the log file.

For example, SetupAPI interprets some sample LoggingFlags values as follows:

0x00000000 means default logging
0x0000FFFF means verbose logging
0x8000FF00 means log verbose device installation information
to both the log file and the debugger

To modify the default SetupAPI logging levels during a clean installation, edit the registry during the period between text-mode Setup and GUI-mode Setup. The following steps describe the procedure. These steps assume that you are installing to D:\Winnt and have a working build of the same version of Windows on another partition. Change the SetupAPI logging levels as follows:

  1. Start the installation of the clean build you are testing.
  2. Stop the setup process during the first boot after text-mode Setup (that is, before GUI-mode Setup).
  3. Boot into the working build by selecting it from the boot menu, and log on as Administrator.
  4. Find the registry hives (files) in D:\Winnt\System32\config. In this case, you need to modify the registry hive in Software.sav.
  5. On Windows 2000, run Regedt32, select the "HKEY_LOCAL_MACHINE on Local Machine" window, and select the HKEY_LOCAL_MACHINE key. Then click on the Registry menu and select Load Hive.

    On Windows XP and later, run RegEdit. Highlight HKEY_LOCAL_MACHINE, click on the File menu and select Load Hive.

  6. Browse the files and select D:\Winnt\System32\config\software.sav. When prompted for key name, enter "_sw.sav "
  7. Open the _sw.sav key under HKEY_LOCAL_MACHINE and highlight the following key:
    HKEY_LOCAL_MACHINE\_sw.sav\Microsoft\Windows\CurrentVersion\Setup

    On Windows 2000, click on the Security menu, select Permissions, and grant full control to Administrator.

    On Windows XP and later, click on the Edit menu, select Permissions, and grant full control to Administrator.

  8. On Windows 2000, add the necessary registry values under this key using clicking on Edit and selecting Add Value.

    On Windows XP and later, click on Edit and select New DWORD Value.

    Enter the value. For example, add "0xFFFF" to enable full verbose logging.

  9. Select HKEY_LOCAL_MACHINE\_sw.sav, and unload the hive (using the Registry menu on Windows 2000, or the File menu on Windows XP and later)The _sw.sav key should disappear.
  10. Copy D:\Winnt\System32\config\software.sav to D:\Winnt\System32\config\software.
  11. Reboot and continue into Setup.
  12. To verify this change, press SHIFT+F10 in GUI-mode Setup, then run regedit.exe and check the logging level.


Interpreting a Sample SetupAPI Log File

The sample logs below illustrate the information that is contained in a SetupAPI log file.

In general, all parts of an installation appear together in the log file. An installation section in the log starts with an entry of the format [year/month/day time process-id.instance description] where instance is a number that ensures that two sections instantiated at the same time for the same process are unique.

This topic includes:

Sample Windows 2000 SetupAPI Log File

Sample Windows XP SetupAPI Log File

Sample Windows 2000 SetupAPI Log File

In the following sample Windows 2000 log file, the indented sections are explanatory annotations. The sample log was generated with LogLevel=0xFFFF for verbose output:

[1999/10/15 15:14:25 376.1560 Driver Install]

SetupAPI lists the hardware and compatible IDs of the device being
installed. The first ID listed is the most exact match. Lines without a time
stamp provide context for time-stamped entries.

Searching for hardware ID(s): acpi\pnp0200,*pnp0200
Enumerating files E:\WINNT\inf\*.inf
@ 15:14:25.637 : Opened PNF of "E:\WINNT\inf\1394.inf".

PNFs are preprocessed INF files.
:
Searching other INFs...
:

@ 15:14:26.688 : Opened PNF of "E:\WINNT\inf\machine.inf".

Setup found a match here, so it logs the INF in which it found
the match, what hardware ID it matched on, descriptive information,
and the install section.

@ 15:14:26.698 : Found *PNP0200 in E:\WINNT\inf\machine.inf; Device:
Direct memory access controller; Driver: Direct memory access
controller; Provider: Microsoft; Mfg: (Standard system devices);
Section: NO_DRV_X
@ 15:14:26.698 : Decorated section name: NO_DRV_X

:
Setup searches other INFs.
:

@ 15:14:31.575 : Opened PNF of "E:\WINNT\inf\wordpad.inf".

Setup has finished searching INFs. Next, it loads class
co-installers and class installers that are registered for
this device's setup class.

Loading co-installer modules for Direct memory access controller.
@ 15:14:31.615 : Verifying file: E:\WINNT\System32\SysSetup.Dll using
key: SysSetup.Dll in catalog: -.
@ 15:14:31.695 : Obtained module "E:\WINNT\System32\SysSetup.Dll"
procedure "CriticalDeviceCoInstaller" for use.

:
Setup performs various device installation operations
before it sends a DIF_INSTALLDEVICEFILES request.
:

@ 15:14:32.026 : Device install function: DIF_INSTALLDEVICEFILES.

Setup logs each device installation function code.
Co-installers are numbered in the order that they are loaded.

@ 15:14:32.026 : Executing co-installer 1 of 1.
@ 15:14:32.036 : Completed co-installer 1 of 1.

In this example, there is no class installer for the
device's setup class. You can tell this because there is
no entry for "Executing class-installer."

@ 15:14:32.046 : Completed class-installer.

Now Setup calls the default handler for this DIF request.
If "Executing default installer" is listed before the class
installer completes, that means the class installer called
the default handler function directly.

@ 15:14:32.046 : Executing default installer.
@ 15:14:32.056 : Install Device: Begin.

Setup lists the devnode here.

@ 15:14:32.066 : Doing copy-only install of ACPI\PNP0200\4&12BA42B2&0.

Setup lists the INF and decorated INF section being used.

@ 15:14:32.136 : Installing section NO_DRV_X from e:\winnt\inf\machine.inf.
@ 15:14:32.146 : Install Device: Queueing files from INF(s).
@ 15:14:32.156 : Install Device: Queueing co-installer files from
INF(s).
Processing co-installer registration section NO_DRV_X.CoInstallers.
@ 15:14:32.236 : Verifying file: E:\WINNT\INF\certclas.inf using key:
certclas.inf in catalog: -.
@ 15:14:32.346 : Co-Installers Registered.
@ 15:14:32.356 : Installing section NO_DRV_X.Interfaces from
e:\winnt\inf\machine.inf.
@ 15:14:32.366 : Interfaces installed.
@ 15:14:32.376 : Device install finished successfully
(ACPI\PNP0200\4&12BA42B2&0).
@ 15:14:32.386 : Install Device: End.
@ 15:14:32.396 : Completed default installer.

The installation pass for copying files has finished successfully.
Now carry on with the rest of the installation operations for this
device.

@ 15:14:32.457 : Verifying file: e:\winnt\inf\machine.inf using key:
machine.inf in catalog: -.
@ 15:14:32.497 : Verifying file: e:\winnt\inf\layout.inf using key:
layout.inf in catalog: -.
@ 15:14:32.557 : Pruning Files: Verifying catalogs/infs.
@ 15:14:32.567 : Pruning Files: Verifying catalogs/infs completed.

:
Setup performs various other device installation
functions before sending DIF_INSTALLDEVICE.
:

@ 15:14:33.498 : Device install function: DIF_INSTALLDEVICE.
@ 15:14:33.498 : Executing co-installer 1 of 1.
@ 15:14:33.518 : Completed co-installer 1 of 1.
@ 15:14:33.528 : Completed class-installer.
@ 15:14:33.538 : Executing default installer.
@ 15:14:33.538 : Install Device: Begin.

@ 15:14:33.548 : Doing full install of ACPI\PNP0200\4&12BA42B2&0.
@ 15:14:33.628 : Install Device: Changing registry settings specified
by INF(s).
@ 15:14:33.638 : Install Device: Writing driver specific registry
settings.
@ 15:14:33.668 : Install Device: Installing required Windows services.
@ 15:14:33.678 : Install Device: Writing drive descriptive registry
settings.
@ 15:14:33.708 : Install Device: Restarting device.
@ 15:14:33.768 : Install Device: Restarting device completed.
@ 15:14:33.788 : Device install finished successfully
(ACPI\PNP0200\4&12BA42B2&0).
@ 15:14:33.798 : Install Device: End.
@ 15:14:33.798 : Completed default installer.
@ 15:14:33.808 : Executing co-installer (Post Processing).
@ 15:14:33.838 : Completed co-installer 1 (Post Processing).

:
Setup performs various device installation functions
after sending DIF_INSTALLDEVICE.
:

Sample Windows XP SetupAPI Log File

For Windows XP, each log entry includes a message identifier consisting of a letter or dash (-) followed by a number. The following table describes the format for message identifiers.

Message ID | Message Type
#Ennn | Error message.
#Wnnn | Warning message.
#Innn | Informational message.
#Tnnn | Timing message.
#Vnnn | Verbose message.
#-nnn | Status message.

Following are a couple of segments from a Windows XP error log:

[2001/02/27 20:14:30 1148.173]
#-198 Command line processed: C:\WINDOWS\system32\mmc.exe "C:\WINDOWS\system32\devmgmt.msc"
#-147 Loading class installer module for "Communications Port".
@ 20:14:33.381 #V132 File "C:\WINDOWS\INF\certclas.inf" (key "certclas.inf") is signed in catalog "C:\WINDOWS\System32\CatRoot\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}\NT5INF.CAT".
@ 20:14:33.810 #V132 File "C:\WINDOWS\System32\MsPorts.Dll" (key "MsPorts.Dll") is signed in catalog "C:\WINDOWS\System32\CatRoot\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}\NT5.CAT".
@ 20:14:33.873 #V146 Using exported function "PortsClassInstaller" in module "C:\WINDOWS\System32\MsPorts.Dll".
@ 20:14:33.873 #V166 Device install function: DIF_UPDATEDRIVER_UI.
@ 20:14:33.873 #T152 Executing class installer.
@ 20:14:33.873 #V153 Completed class installer.
@ 20:14:33.889 #V155 Executing default installer.
@ 20:14:33.889 #V156 Completed default installer.
@ 20:14:36.302 #I060 Set selected driver.
#-019 Searching for hardware ID(s): *pnp0501
@ 20:14:36.318 #V017 Enumerating files "C:\WINDOWS\inf".
(following #V lines are logged only if driver bits of log level >= 0x7000)
@ 20:14:36.556 #V392 Using INF cache "C:\WINDOWS\inf\INFCACHE.1".
@ 20:14:36.731 #V073 Cache: Excluding INF "accessor.inf".
@ 20:14:36.731 #V073 Cache: Excluding INF "agtinst.inf".
:
:
@ 20:14:37.318 #T075 Enumerating files: Directory pass completed.
@ 20:14:37.398 #V005 Opened the PNF file of "C:\WINDOWS\inf\msports.inf" (Languge = 0409).
@ 20:14:37.413 #I022 Found "*PNP0501" in C:\WINDOWS\inf\msports.inf; Device: "Communications Port"; Driver: "Communications Port"; Provider: "Microsoft"; Mfg: "(Standard port types)"; Section name: "ComPort".
(rank of 0 is absolute best match)
@ 20:14:37.413 #I023 Actual install section: [ComPort.NT]. Rank: 0x00001000. Effective driver date: 02/14/2001.
@ 20:14:37.413 #I022 Found "*PNP0501" in C:\WINDOWS\inf\msports.inf; Device: "Communications Port"; Driver: "Communications Port"; Provider: "Microsoft"; Mfg: "(Standard port types)"; Section name: "ComPort".
@ 20:14:37.413 #I023 Actual install section: [ComPort.NT]. Rank: 0x00000000. Effective driver date: 02/14/2001.
@ 20:14:37.413 #T076 Enumerating files: Cache pass completed.
@ 20:15:01.383 #V166 Device install function: DIF_SELECTBESTCOMPATDRV.
@ 20:15:01.383 #T152 Executing class installer.
@ 20:15:01.383 #V153 Completed class installer.
@ 20:15:01.399 #V155 Executing default installer.
@ 20:15:01.399 #I063 Selected driver installs from section [ComPort] in "c:\windows\inf\msports.inf".
@ 20:15:01.526 #I320 Class GUID of device remains {4D36E978-E325-11CE-BFC1-08002BE10318}.
@ 20:15:01.526 #I060 Set selected driver.
@ 20:15:01.526 #I058 Selected best compatible driver.
@ 20:15:01.526 #V156 Completed default installer.
@ 20:15:02.447 #V166 Device install function: DIF_ALLOW_INSTALL.
@ 20:15:02.447 #T152 Executing class installer.
@ 20:15:02.447 #V153 Completed class installer.
@ 20:15:02.447 #V155 Executing default installer.
@ 20:15:02.447 #V156 Completed default installer.
@ 20:15:02.463 #V166 Device install function: DIF_INSTALLDEVICEFILES.
@ 20:15:02.463 #T152 Executing class installer.
@ 20:15:02.463 #V153 Completed class installer.
@ 20:15:02.463 #V155 Executing default installer.
@ 20:15:02.463 #T200 Install Device: Begin.
@ 20:15:02.478 #V124 Doing copy-only install of "ROOT\*PNP0501\PNPBIOS_17".
@ 20:15:02.478 #V005 Opened the PNF file of "c:\windows\inf\msports.inf" (Languge = 0409).
@ 20:15:02.478 #V005 Opened the PNF file of "c:\windows\inf\layout.inf" (Languge = 0409).
@ 20:15:02.494 #V011 Installing section [ComPort.NT] from "c:\windows\inf\msports.inf".
@ 20:15:02.494 #T203 Install Device: Queuing files from INF(s).
@ 20:15:02.510 #V005 Opened the PNF file of "C:\WINDOWS\INF\drvindex.inf" (Languge = 0409).
@ 20:15:02.590 #V094 Queued copy from section [ComPort.NT.Copy] in "c:\windows\inf\msports.inf": "serial.sys" to "serial.sys" with flags 0x80000024, target directory is "C:\WINDOWS\System32\DRIVERS".
@ 20:15:02.590 #V096 Source in section [sourcedisksfiles] in "c:\windows\inf\layout.inf"; Media=1 Description="Windows XP Professional CD-ROM" Tag="\win51ip.b2" Path="\i386". Driver cache will be used.
@ 20:15:02.605 #V132 File "C:\WINDOWS\INF\certclas.inf" (key "certclas.inf") is signed in catalog "C:\WINDOWS\System32\CatRoot\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}\NT5INF.CAT".
@ 20:15:02.605 #V005 Opened the PNF file of "C:\WINDOWS\INF\certclas.inf" (Languge = 0409).
@ 20:15:02.685 #V094 Queued copy from section [ComPort.NT.Copy] in "c:\windows\inf\msports.inf": "serenum.sys" to "serenum.sys" with flags 0x80000024, target directory is "C:\WINDOWS\System32\DRIVERS".
@ 20:15:02.685 #V096 Source in section [sourcedisksfiles] in "c:\windows\inf\layout.inf"; Media=1 Description="Windows XP Professional CD-ROM" Tag="\win51ip.b2" Path="\i386". Driver cache will be used.
@ 20:15:02.685 #T204 Install Device: Queuing coinstaller files from INF(s).
@ 20:15:02.685 #V005 Opened the PNF file of "c:\windows\inf\msports.inf" (Languge = 0409).
@ 20:15:02.701 #V005 Opened the PNF file of "c:\windows\inf\layout.inf" (Languge = 0409).
#-046 Processing Coinstaller registration section [ComPort.NT.CoInstallers].
@ 20:15:02.701 #V056 Coinstallers registered.
@ 20:15:02.717 #V011 Installing section [ComPort.NT.Interfaces] from "c:\windows\inf\msports.inf".
@ 20:15:02.732 #V054 Interfaces installed.
@ 20:15:02.732 #V121 Device install of "ROOT\*PNP0501\PNPBIOS_17" finished successfully.
@ 20:15:02.732 #T201 Install Device: End.
@ 20:15:02.748 #V156 Completed default installer.
@ 20:15:02.748 #T185 Pruning Files: Verifying catalogs/infs.
@ 20:15:02.764 #V132 File "c:\windows\inf\msports.inf" (key "msports.inf") is signed in catalog "C:\WINDOWS\System32\CatRoot\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}\NT5INF.CAT".
@ 20:15:02.812 #V132 File "c:\windows\inf\layout.inf" (key "layout.inf") is signed in catalog "C:\WINDOWS\System32\CatRoot\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}\NT5INF.CAT".
@ 20:15:02.812 #T186 Pruning Files: Verifying catalogs/infs completed.
@ 20:15:02.859 #V132 File "C:\WINDOWS\System32\DRIVERS\serial.sys" (key "serial.sys") is signed in catalog "C:\WINDOWS\System32\CatRoot\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}\NT5.CAT".
@ 20:15:02.875 #V191 File "C:\WINDOWS\System32\DRIVERS\serial.sys" pruned from copy.
@ 20:15:02.875 #V132 File "C:\WINDOWS\System32\DRIVERS\serenum.sys" (key "serenum.sys") is signed in catalog "C:\WINDOWS\System32\CatRoot\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}\NT5.CAT".
@ 20:15:02.875 #V191 File "C:\WINDOWS\System32\DRIVERS\serenum.sys" pruned from copy.
@ 20:15:02.875 #V166 Device install function: DIF_REGISTER_COINSTALLERS.
@ 20:15:02.923 #T152 Executing class installer.
@ 20:15:02.939 #V153 Completed class installer.
@ 20:15:02.939 #V155 Executing default installer.
@ 20:15:02.939 #V005 Opened the PNF file of "c:\windows\inf\msports.inf" (Languge = 0409).
@ 20:15:02.939 #I056 Coinstallers registered.
@ 20:15:02.955 #V156 Completed default installer.
@ 20:15:02.955 #V166 Device install function: DIF_INSTALLINTERFACES.
@ 20:15:02.955 #T152 Executing class installer.
@ 20:15:02.955 #V153 Completed class installer.
@ 20:15:02.955 #V155 Executing default installer.
@ 20:15:02.971 #V005 Opened the PNF file of "c:\windows\inf\msports.inf" (Languge = 0409).
@ 20:15:02.971 #V011 Installing section [ComPort.NT.Interfaces] from "c:\windows\inf\msports.inf".
@ 20:15:02.986 #I054 Interfaces installed.
@ 20:15:02.986 #V156 Completed default installer.
@ 20:15:02.986 #V166 Device install function: DIF_INSTALLDEVICE.
@ 20:15:03.002 #T152 Executing class installer.
@ 20:15:03.002 #V005 Opened the PNF file of "c:\windows\inf\msports.inf" (Languge = 0409).
@ 20:15:03.018 #T200 Install Device: Begin.
@ 20:15:03.018 #I123 Doing full install of "ROOT\*PNP0501\PNPBIOS_17".
@ 20:15:03.018 #V005 Opened the PNF file of "c:\windows\inf\msports.inf" (Languge = 0409).
@ 20:15:03.018 #T211 Install Device: Changing registry settings as specified by the INF(s).
@ 20:15:03.034 #T212 Install Device: Writing driver specific registry settings.
@ 20:15:03.050 #T213 Install Device: Installing required Windows services.
#-035 Processing service Add/Delete section [ComPort.NT.Services].
@ 20:15:03.320 #V282 Add Service: Modified existing service "Serial".
@ 20:15:03.653 #V282 Add Service: Modified existing service "Serenum".
@ 20:15:03.669 #T214 Install Device: Writing drive descriptive registry settings.
@ 20:15:03.669 #T216 Install Device: Restarting device.
@ 20:15:06.399 #T217 Install Device: Restarting device completed.
@ 20:15:06.399 #W114 Device "ROOT\*PNP0501\PNPBIOS_17" required reboot: Device has problem: 0x0c: CM_PROB_NORMAL_CONFLICT.
@ 20:15:06.399 #T222 Install Device: Calling RunOnce/GrpConv items.
@ 20:15:06.415 #I138 Executing RunOnce to process 5 RunOnce entries.
@ 20:15:07.241 #I121 Device install of "ROOT\*PNP0501\PNPBIOS_17" finished successfully.
@ 20:15:07.272 #T201 Install Device: End.
@ 20:15:07.336 #V153 Completed class installer.
@ 20:15:07.368 #V166 Device install function: DIF_NEWDEVICEWIZARD_FINISHINSTALL.
@ 20:15:07.368 #T152 Executing class installer.
@ 20:15:07.495 #V153 Completed class installer.
@ 20:15:07.495 #V155 Executing default installer.
@ 20:15:07.495 #V156 Completed default installer.
@ 20:15:42.100 #V166 Device install function: DIF_DESTROYPRIVATEDATA.
@ 20:15:42.100 #T152 Executing class installer.
@ 20:15:42.100 #V153 Completed class installer.
@ 20:15:42.116 #V155 Executing default installer.
@ 20:15:42.116 #V156 Completed default installer.


Updating Driver Files

Drivers are updated when a user runs the Hardware Update Wizard. Following is a set of guidelines to follow when writing installation software and INF files that update existing drivers.

  • Installation software can call UpdateDriverForPlugAndPlayDevices, supplying an INF file and a hardware ID, to update drivers for devices that match the hardware ID. For more information, see Writing a Device Installation Application.
  • When upgrading a driver, class installers and co-installers should not supply finish-install pages in response to DIF_NEWDEVICEWIZARD_FINISHINSTALL unless absolutely necessary. If possible, obtain finish-install information from the settings of the previous installation.
  • To the extent possible, class installers and co-installers should avoid basing behavior on whether they are providing an initial installation or are updating drivers for an already-installed device.
  • For Windows XP and later, the registry values CoInstallers32 and EnumPropPages32 are deleted prior to delivery of DIF_REGISTER_COINSTALLERS. INF files for earlier OS versions must explicitly either delete these values or perform a non-appending modify operation on them.
  • For Windows XP and later, the registry values UpperFilters and LowerFilters are deleted prior to delivery of DIF_INSTALLDEVICE. INF files for earlier OS versions must explicitly either delete these values or perform a non-appending modify operation on them.
  • Do not use INF DelFiles directives or INF RenFiles directives when updating drivers. Setup cannot guarantee that a particular file is not being used by another device. (Class installers and co-installers can delete or rename files, if they can reliably determine that no devices are using the files.)
  • Use the INF DelReg directive to remove old device-specific registry entries from a previous installation of the device, if the entries are no longer needed. (Do not remove global registry entries.)
  • Do not use the INF DelService directive in an INF DDInstall.Services section to remove previously installed device/driver services from the target machine. Setup cannot guarantee that a particular service is not being used by another device. (Class installers and co-installers can delete services, if they can reliably determine that no devices are using the services.)
  • When updating a class installer, class co-installer, or service DLL, you must give the new version a new file name.


Drivers with Special Installation Requirements

This chapter describes how to install boot, filter, and "null" drivers. It contains the following sections:

Installing a Boot Driver

Installing a Filter Driver

Installing a Null Driver


Installing a Boot Driver

During the text-mode setup phase of Windows installation, the Setup program installs drivers for devices that are required to boot the machine. Most of these drivers are included with the operating system.

A user can install an additional third-party driver during text-mode setup by pressing the appropriate key and inserting a floppy disk from the third-party vendor. A third-party vendor provides a txtsetup.oem file on a floppy disk to enable a user to install such a driver during text-mode setup.

To install a device that is required to boot the machine, a user installs the device hardware, turns on the machine, and installs the device's driver (if it is not included with the operating system), in the following manner:

  • During the beginning of the text-mode setup phase of booting, the system displays a message indicating that the user can press a key to install custom drivers.
  • At this point, the user presses an F n key to install a driver for a third-party device, then inserts the vendor's floppy disk.

Certain error messages displayed when a machine fails to boot can indicate that a boot driver is missing. For example:

  • If a machine fails to boot and displays the message "Inaccessible boot device," it might be because the boot disk is a third-party mass-storage device that requires a driver not included with the operating system.
  • If a machine fails to boot and displays the message "Setup could not determine your machine type," it could be because a new HAL driver is required. This error does not occur on most machines, but it might occur on a high-end server.

Note that this procedure is for installing a driver that is not included "in-the-box" with the operating system. Do not use this procedure to replace or update a driver included with the operating system. Instead, wait until the system boots and use the Device Manager to perform an "update driver" operation on the device.

If a vendor distributes a driver for a device required during boot and intends for the user to install it during text-mode setup, the following rules apply:

  • Driver file names must not exceed eight characters, and extensions must not exceed three characters.
  • The vendor's distribution disk must include a file named txtsetup.oem in addition to the other driver files.

A txtsetup.oem file is a text file that contains a list of hardware components, a list of files to be copied, and a list of registry keys and vaules to be created. For details about the contents of a txtsetup.oem file, see The txtsetup.oem File Format.

A single distribution disk with a single txtsetup.oem file can support multiple hardware devices. Such a file would contain a single Defaults section with an entry specifying the default choice for each hardware type. The file would also contain a HwComponent entry for each hardware type and the appropriate associated Files.HwComponent.ID and Config.DriverKey sections.

A sample txtsetup.oem file is provided with this DDK, under the installed DDK's \src directory.


Installing a Filter Driver

A PnP filter driver can support a specific device or all devices in a setup class and can attach below a device's function driver (a lower filter) or above a device's function driver (an upper filter). See Types of WDM Drivers for more information on PnP driver layers.

Installing a Device-Specific Filter Driver

To register a device-specific filter driver, create a registry entry through an AddReg entry in the DDInstall.HW section of the device's INF file. For a device-specific upper filter, create an entry named UpperFilters. For a device-specific lower filter, create an entry named LowerFilters. For example, the following INF excerpt installs cdaudio as an upper filter on the cdrom driver:

:
; Installation section for cdaudio. Sets cdrom as the service
; and adds cdaudio as a PnP upper filter driver.
;
[cdaudio_install]
CopyFiles=cdaudio_copyfiles, cdrom_copyfiles

[cdaudio_install.HW]
AddReg=cdaudio_addreg

[cdaudio_install.Services]
AddService=cdrom,0x00000002,cdrom_ServiceInstallSection
AddService=cdaudio,,cdaudio_ServiceInstallSection
:

[cdaudio_addreg]
HKR,,"UpperFilters",0x00010000,"cdaudio" ; REG_MULTI_SZ value
:

[cdaudio_ServiceInstallSection]
DisplayName    = %cdaudio_ServiceDesc%
ServiceType    = 1     ; SERVICE_KERNEL_DRIVER
StartType      = 3     ; SERVICE_DEMAND_START
ErrorControl   = 1     ; SERVICE_ERROR_NORMAL
ServiceBinary  = %12%\cdaudio.sys
:

Installing a Class Filter Driver

To install a class-wide upper- or lower-filter for a device setup class, you can supply a device installation application that installs the necessary services. The application can then register the service as being an upper- or lower-filter for the desired device setup classes. To copy the service binaries, the application can use SetupInstallFilesFromInfSection. To install the services, the application can use SetupInstallServicesFromInfSection. To register the services as upper- and/or lower-filters for particular device setup classes, the application calls SetupInstallFromInfSection for each device setup class of interest, using the registry key handle they retrieved from SetupDiOpenClassRegKey for the RelativeKeyRoot parameter. For example, consider the following INF sections:

:

[DestinationDirs]
upperfilter_copyfiles = 12

[upperfilter_inst]
CopyFiles = upperfilter_copyfiles
AddReg = upperfilter_addreg

[upperfilter_copyfiles]
upperfilt.sys

[upperfilter_addreg]
; append this service to existing REG_MULTI_SZ list, if any
HKR,,"UpperFilters",0x00010008,"upperfilt"

[upperfilter_inst.Services]
AddService = upperfilt,,upperfilter_service

[upperfilter_service]
DisplayName   = %upperfilter_ServiceDesc%
ServiceType   = 1   ; SERVICE_KERNEL_DRIVER
StartType     = 3   ; SERVICE_DEMAND_START
ErrorControl  = 1   ; SERVICE_ERROR_NORMAL
ServiceBinary = %12%\upperfilt.sys
:

The device installation application would:

  1. Call SetupInstallFilesFromInfSection for the [upperfilter_inst] section.
  2. Call SetupInstallServicesFromInfSection for the [upperfilter_inst.Services] section.
  3. Call SetupInstallFromInfSection for the [upperfilter_inst] section, once for each class key it wants to register the upperfilt service for.

Each call would specify SPINST_REGISTRY for the Flags argument, to indicate that only registry modifications need to be performed.


Installing a Null Driver

You might install a "null driver" (that is, non-existent driver) for a device if the device is not used on the machine and should not be started. Such devices do not typically exist on a machine, but if they do, you can install a null driver by specifying entries like the following in the INF for the device:

:
[MyModels]
%MyDeviceDescription% = MyNullInstallSection, &BadDeviceHardwareID%
:

[MyNullInstallSection]
; The install section is typically empty, but can contain entries that
; copy files or modify the registry.

[MyNullInstallSection.Services]
AddService = ,2    ; no value for the service name
:

The hardware ID for the device in the Models section should identify the device specifically, using the subsystem vendor ID and whatever other information is relevant.

The operating system will create a devnode for the device, but if the device is not capable of executing in raw mode, the operating system will not start the device because a function driver has not been assigned to it. Note, however, that if the device has a boot configuration, those resources will be reserved.


Device Identification Strings

When a Plug and Play bus enumerator detects a child device, it constructs a list of device identification strings for the child. One entry in the list is a complete identification of the device. This entry is called the device ID and it becomes the name of the device's hardware key in the registry. Additional entries in the list are less specific.

The Plug and Play Manager uses all of the identifiers in the list when it tries to match a device to an INF file, but it tries to use the most specific identifier first. This allows the setup software to give preference to drivers in the order of their suitability, those drivers supplied by the vendor being at the top of the list.

For a detailed discussion of the role device identification strings play in the selection of drivers, and the proper means of locating and ordering them in a driver's INF file, see How Setup Selects Drivers.

Identifiers are divided into the following groups:

Device IDs

Hardware IDs

Compatible IDs

Instance IDs

Device instance IDs

This section deals with the first three of these types of IDs.

The most specific of the first three types of identifiers is the device ID. Each device has only one device ID, and the device ID uniquely identifies the device.

The next most specific is the hardware ID. In most cases, the device ID is just the most specific of the hardware IDs, although there are exceptions (see Identifiers for 1394 Devices). The least specific of the first three types of identifier is the compatible ID. A device can only have one device ID.

Drivers can retrieve a device's hardware IDs by calling IoGetDeviceProperty with the DeviceProperty parameter set to DevicePropertyHardwareID, or by querying the bus driver directly with an IRP of type IRP_MN_QUERY_ID whose Parameters.QueryId.IdType field is set to BusQueryHardwareIDs.

The device ID is usually the first identifier in the list of hardware IDs obtained by either of these methods, but drivers can specifically query for the device ID alone by means of an IRP of type IRP_MN_QUERY_ID whose Parameters.QueryId.IdType field is set to BusQueryDeviceID.

Drivers can retrieve a device's compatible IDs by calling IoGetDeviceProperty with the DeviceProperty parameter set to DevicePropertyCompatibleID, or by querying the bus driver directly with an IRP of type IRP_MN_QUERY_ID whose Parameters.QueryId.IdType field is set to BusQueryCompatibleIDs.

Formats for hardware and compatible IDs vary according to the enumerator. Furthermore, each enumerator has its own policy for defining which identifiers are hardware IDs and which identifiers are compatible IDs.

The following sections provide additional information about device, hardware, and compatible IDs for devices connected to some of the most important buses:

Generic Identifiers

Identifiers for PCI Devices

Identifiers for SCSI Devices

Identifiers for IDE Devices

Identifiers for PCMCIA Devices

Identifiers for ISAPNP Devices

Identifiers for 1394 Devices

Identifiers for USB Devices


Generic Identifiers

Most, but not all, identifier strings are bus-specific. The Plug and Play Manager also supports a set of generic device identifiers for devices that can appear on many different buses. These identifiers are of the form:

*PNPd(4)

where d(4) is a 4-digit, hexadecimal type identifier. In the case of the PCMCIA bus, compatible IDs are formatted in this manner (see the following discussion of the PCMCIA bus). The official list of these identifiers can be found on the Microsoft hardware developer's website at http://www.microsoft.com/hwdev. This information is also published in the Microsoft® MSDN™.


Identifiers for PCI Devices

The device ID of a PCI device has the form

PCI\VEN_v(4)&DEV_d(4)&SUBSYS_s(8)&REV_r(2)

where v(4) is the vendor identifier that the PCI Special Interest Group assigned to the manufacturer of the card, d(4) is the device identifier that the manufacturer assigned to the card, s(8) is the subsystem identifier (often zero) reported by the card, and r(2) is the revision number.

An example of how this identifier might appear for a display adapter on a laptop computer is:

PCI\VEN_102C&DEV_00E0&SUBSYS_00000000&REV_04

The PCI bus driver supplies two hardware IDs. The format of the second hardware ID is the same as the first, but without the revision information.

PCI\VEN_v(4)&DEV_d(4)&SUBSYS_s(8)

In addition to the two hardware IDs, the PCI bus driver also generates between eight and ten compatible IDs, depending on whether the system identifier is zero or not. If there is no system ID, then the two hardware IDs indicated above collapse into the format of the first two compatible IDs in the list below, and in that case, these two IDs cease to be compatible IDs and become hardware IDs:

PCI\VEN_v(4)&DEV_d(4)&REV_r(2) (compatible ID only if there is system ID, otherwise a hardware ID)

PCI\VEN_v(4)&DEV_d(4) (compatible ID only if there is system ID, otherwise a hardware ID)

PCI\VEN_v(4)&DEV_d(4)&REV_r(2)&CC_c(2)s(2)

PCI\VEN_v(4)&DEV_d(4)&CC_c(2)s(2)p(2)

PCI\VEN_v(4)&DEV_d(4)&CC_c(2)s(2)

PCI\VEN_v(4)&CC_c(2)s(2)p(2)

PCI\VEN_v(4)&CC_c(2)s(2)

PCI\VEN_v(4)

PCI\CC_c(2)s(2)p(2)

PCI\CC_c(2)s(2)

In the above list, c(2) represents the base class code from the configuration space, s(2) is the subclass code, and p(2) is the programming interface. Thus, any of the following compatible IDs for the display adapter in the previous example would have matched the information in an INF file for that adapter:

PCI\VEN_102C&DEV_00E0&REV_04

PCI\VEN_102C&DEV_00E0

PCI\VEN_102C&DEV_00E0&REV_04&CC_0300

PCI\VEN_102C&DEV_00E0&CC_030000

PCI\VEN_102C&DEV_00E0&CC_0300

PCI\VEN_102C&CC_030000

PCI\VEN_102C&CC_0300

PCI\VEN_102C

PCI\CC_030000

PCI\CC_0300


Identifiers for SCSI Devices

The device ID format for a small computer system interface (SCSI) device is:

SCSI\t*v(8)p(16)r(4)

where t* is a device type code of variable length, v(8) is an 8-character vendor identifier, p(16) is a 16-character product identifier, and r(4) is a 4-character revision level value. The bus enumerator determines the device type by indexing an internal string table, using a numerically encoded SCSI device type code, obtained by querying the device, as shown in the following table. The remaining components are just strings returned by the device, but with special characters (including space, comma, and any nonprinting graphic) replaced with an underscore.

The ScsiPort driver currently returns the following device type strings, the first nine of which correspond to standard SCSI type codes.

SCSI Type Code | Device Type | Generic Type | Peripheral ID
DIRECT_ACCESS_DEVICE (0) | Disk | GenDisk | DiskPeripheral
SEQUENTIAL_ACCESS_DEVICE (1) | Sequential |  | TapePeripheral
PRINTER_DEVICE (2) | Printer | GenPrinter | PrinterPeripheral
PROCESSOR_DEVICE (3) | Processor |  | OtherPeripheral
WRITE_ONCE_READ_MULTIPLE_DEVICE (4) | Worm | GenWorm | WormPeripheral
READ_ONLY_DIRECT_ACCESS_DEVICE (5) | CdRom | GenCdRom | CdRomPeripheral
SCANNER_DEVICE (6) | Scanner | GenScanner | ScannerPeripheral
OPTICAL_DEVICE (7) | Optical | GenOptical | OpticalDiskPeripheral
MEDIUM_CHANGER (8) | Changer | ScsiChanger | MediumChangerPeripheral
COMMUNICATION_DEVICE (9) | Net | ScsiNet | CommunicationsPeripheral
10 | ASCIT8 | ScsiASCIT8 | ASCPrePressGraphicsPeripheral
11 | ASCIT8 | ScsiASCIT8 | ASCPrePressGraphicsPeripheral
12 | Array | ScsiArray | ArrayPeripheral
13 | Enclosure | ScsiEnclosure | EnclosurePeripheral
14 | RBC | ScsiRBC | RBCPeripheral
15 | CardReader | ScsiCardReader | CardReaderPeripheral
16 | Bridge | ScsiBridge | BridgePeripheral
17 | Other | ScsiOther | OtherPeripheral

An example of a device ID for a disk drive would be:

SCSI\DiskSEAGATE_ST39102LW_______0004

There are four hardware IDs in addition to the device ID:

SCSI\t*v(8)p(16)

SCSI\t*v(8)

SCSI\v(8)p(16)r(1)

V(8)p(16)r(1)

In the third and fourth of these additional identifiers, r(1) represents just the first character of the revision identifier. These hardware IDs are illustrated by the following examples:

SCSI\DiskSEAGATE_ST39102LW_______

SCSI\DiskSEAGATE_

SCSI\DiskSEAGATE_ST39102LW_______0

SEAGATE_ST39102LW_______0

The ScsiPort driver supplies only one compatible ID, one of the variable-sized generic type codes from the preceding table.

For example, the compatible ID for a disk drive is:

GenDisk

The generic identifier is used in INF files for SCSI devices more than any other, because SCSI drivers tend to be generic. Note that ScsiPort returns no generic name at all for sequential access and "processor" devices.


Identifiers for IDE Devices

Identifiers for integrated device electronics (IDE) devices are very similar to SCSI identifiers. The device ID format is:

IDE\t*v(40)r(8)

where t* is a device-type code of variable length, v(40) is a string containing the vendor name, an underscore, vendor's product name, and enough underscores to bring the total to 40 characters; r(8) is an 8-character revision number.

There are three hardware IDs, in addition to the device ID:

IDE\v(40)r(8)

IDE\t*v(40)

V(40)r(8)

As in the SCSI case, there is only one compatible ID, a generic type name similar to the standard SCSI type names supplied by ScsiPort driver, but having only eleven entries instead of eighteen. The generic device-type names for IDE devices are as follows:

IDE Type Code | Device Type | Generic Type | Peripheral ID
DIRECT_ACCESS_DEVICE (0) | Disk | GenDisk | DiskPeripheral
SEQUENTIAL_ACCESS_DEVICE (1) | Sequential | GenSequential | TapePeripheral
PRINTER_DEVICE (2) | Printer | GenPrinter | PrinterPeripheral
PROCESSOR_DEVICE (3) | Processor | GenProcessor | OtherPeripheral
WRITE_ONCE_READ_MULTIPLE_DEVICE (4) | Worm | GenWorm | WormPeripheral
READ_ONLY_DIRECT_ACCESS_DEVICE (5) | CdRom | GenCdRom | CdRomPeripheral
SCANNER_DEVICE (6) | Scanner | GenScanner | ScannerPeripheral
OPTICAL_DEVICE (7) | Optical | GenOptical | OpticalDiskPeripheral
MEDIUM_CHANGER (8) | Changer | GenChanger | MediumChangerPeripheral
COMMUNICATION_DEVICE (9) | Net | GenNet | CommunicationsPeripheral
10 | Other | GenOther | OtherPeripheral

For IDE changer devices, the generic type name is GenChanger instead of ScsiChanger and for communication devices the generic type name is GenNet instead of ScsiNet. ScsiPort returns no generic name at all for sequential access and "processor" devices, whereas the IDE bus driver returns GenSequential and GenProcessor. Also, the IDE bus driver returns only ten generic types, whereas ScsiPort currently returns eighteen. In other respects, the generic names returned by the IDE bus driver are the same as those returned by the ScsiPort driver.

The compatible ID for an IDE tape drive is:

GenSequential

In the special case of an LS-120 device, the IDE bus driver returns the following compatible ID:

GenSFloppy

The following illustrates the sort of identifiers that can be generated for an IDE hard drive:

IDE\DiskMaxtor_91000D8_____________________SASX1B18

IDE\Maxtor_91000D8___________________________SASX1B18

IDE\DiskMaxtor_91000D8________________________

Maxtor_91000D8__________________________SASX1B18

GenDisk


Identifiers for PCMCIA Devices

For Personal Computer Memory Card International Association (PCMCIA) devices, the device ID can take a number of different forms. For devices that are not multifunctional, the device identifier is formatted as follows:

PCMCIA\Manufacturer-Product-Crc(4)

where Manufacturer is the name of the manufacturer and Product is the name of the product. The PCMCIA enumerator retrieves these strings directly from tuples on the card. Both Manufacturer and Product are variable-length strings that do not exceed 64 characters. Crc(4) is the 4-digit hexadecimal CRC (cyclic redundancy check) checksum for the card. Numbers less than four digits long have a leading zero fill. For example, the device ID for a network card might look like this:

PCMCIA\MEGAHERTZ-CC10BT/2-BF05

For a multifunction card, each individual function has an identifier of the form:

PCMCIA\Manufacturer-Product-DEVd(4)-Crc(4)

The child function number (d(4) in this example) is a decimal number without leading zeros.

If the card doesn't have a name of the manufacturer, the identifier has one of these three forms:

PCMCIA\UNKNOWN_MANUFACTURER-Crc(4)

PCMCIA\UNKNOWN_MANUFACTURER-DEVd(4)-Crc(4)

PCMCIA\MTD-MemoryType(4)

The last of these three alternatives is for a flash memory card with no manufacturer identifier on the card. MemoryType(4) is one of two 4-digit hexadecimal numbers: 0000 for SRAM cards and 0002 for ROM cards.

In addition to the various forms of device ID just described, an INF file's Model section can also contain a hardware ID composed by replacing the 4-digit hexadecimal cyclic redundancy check (CRC) with a string containing the 4-digit hexadecimal manufacturer code, a hyphen, and the 4-digit hexadecimal manufacturer information code (both from onboard tuples). For example:

PCMCIA\MEGAHERTZ-CC10BT/2-0128-0103

PCMCIA-compatible IDs correspond to the generic device IDs mentioned in the Generic Identifiers section. Currently, PCMCIA-compatible IDs are generated for only three device types:

*PNP0600

*PNP0D00

*PNPC200

an AT Attachment (ATA) disk driver, a multi-function 3.0 PC card, and a modem card respectively.


Identifiers for ISAPNP Devices

Every ISAPNP card supports a readable resource data structure that describes the resources supported and those requested by the card. This structure supports the concept of multiple functions (or "logical devices") for ISA card. A separate set of "tags" or "descriptors" are associated with each function of the card. Using this tag information, the ISAPNP enumerator constructs two hardware identifiers, formatted as:

ISAPNP\m(3)d(4)

*m(3)n(4)

where m(3)d(4) together make up an EISA-style identifier for the device — three letters to identify the manufacturer and 4 hexadecimal digits to identify the particular device.

The following pair of hardware IDs might be produced by a specific function on a multifunction card:

ISAPNP\CSC6835_DEV0000

*CSC0000

The first of the two hardware IDs is the device ID. If the device in question is one function of a multifunction card, the device ID takes this form:

ISAPNP\m(3)d(4)_DEVn(4)

where n(4) is the decimal index (with leading zeros) of the function.

The second of the two hardware identifiers is also a compatible ID. The ISAPNP enumerator generates one or more compatible IDs the first of which is always the second hardware ID. The first three characters, m(3), that follow the "*" in an ISAPNP-compatible ID are frequently "PNP." For example, the compatible ID for a serial port might look like this:

PNP0501


Identifiers for 1394 Devices

The 1394 bus driver constructs these identifiers for a device:

1394\VendorName&ModelName

1394\UnitSpecId&UnitSwVersion

where VendorName is the name of the hardware vendor, ModelName identifies the device, UnitSpecId identifies the software specification authority, and UnitSwVersion identifies the software specification. The information used to construct these identifiers comes from the device's configuration ROM.

If a device has vendor and model name strings, the 1394 bus driver uses the first identifier as both, the device ID and the hardware ID, and the second identifier as the compatible ID. If a device lacks a vendor or model name string, the bus driver uses the second identifier as both, the device ID and the compatible ID, and returns double NULL if queried for the hardware ID. Thus, the IEEE1394 bus driver, under certain circumstances, supplies a device ID but no hardware ID. This is an exception to the general rule that the device ID is one of the hardware IDs.

The device ID for a camera on a IEEE1394 might appear as follows

1394\SONY&CCM-DS250_1.08

Multifunction devices have a separate set of identifiers for each unit directory in the device's configuration ROM.

If the device's function driver sits on top of the SBP-2 port driver, then its device ID has the following format.

SBP2\VendorName&ModelName&LUNn*

where VendorName is the hardware vendor, ModelName identifies the device, and n* is a string representing the lower-order 2 bytes of the logical unit number in hexadecimal. Various functions on a multifunction device produce device IDs that are identical except for this number.

The device ID for a SBP-2 1394 hard disk might be as follows:

SBP2\VST_TECHNOLOGIESINC.&VST_FULL_HEIGHT_FIREWIRE_DRIVE&LUN0

As with the 1394 bus, the SBP2 port driver does not classify the device ID as a hardware ID. However, whereas the 1394 bus distinguishes between hardware IDs and compatible IDs, the SBP2 port driver does not. For IRP_MN_QUERY_ID IRPs of type BusQueryHardwareIDs and IRP_MN_QUERY_ID IRPs of type BusQueryCompatibleIDs SBP2 returns the same set of four identifiers:

SBP2\VendorName&ModelName&CmdSetIdn*

SBP2\Gen

Gen

SBP2\n*&d*

where n* is the Command Set ID number, Gen is one of the generic names listed in the Generic Type column of the table below, and d* is a number formed by taking the lower five bits of the upper two bytes of the logical unit number. This number is the numeric code for the generic name of the device corresponding to the string identifier Gen. The fourth ID, listed in the preceding example (SBP2\n*&d*), is unique among all of the SBP2 hardware identifiers in that both n*, the Command Set ID number and d*, the numeric code of the generic name are in decimal, not hexadecimal.

This table lists the generic device names returned by the SBP2 port driver. Most, but not all, of the generic names generated by the SBP2 port driver are a subset of those generated by ScsiPort driver.

1394 Type Code | Device Type | Generic Type
RBC_DEVICE or DIRECT_ACCESS_DEVICE (0) | Disk | GenDisk
SEQUENTIAL_ACCESS_DEVICE (1) | Sequential | GenSequential
PRINTER_DEVICE (2) | Printer | GenPrinter
WRITE_ONCE_READ_MULTIPLE_DEVICE (4) | Worm | GenWorm
READ_ONLY_DIRECT_ACCESS_DEVICE (5) | CdRom | GenCdRom
SCANNER_DEVICE (6) | Scanner | GenScanner
OPTICAL_DEVICE (7) | Optical | GenOptical
MEDIUM_CHANGER (8) | Changer | GenChanger
Default Type (all values not listed above) | Other | GenSbp2Device


Identifiers for USB Devices

The set of identifiers generated for USB devices depends on whether the device is a single-interface device or a multiple-interface device.

Single-Interface USB Devices

When a new USB device is plugged in, Microsoft® Windows® USBHUB driver composes the following device ID using information extracted from the device's device descriptor:

USB\VID_v(4)&PID_d(4)&REV_r(4)

where v(4) is the 4-digit hexadecimal vendor code that the USB committee assigns to the vendor, d(4) is the 4-digit hexadecimal product code that the vendor assigns to the device, and r(4) is the revision code. The hub driver extracts the vendor and product codes from the idVendor and idProduct fields of the device descriptor, respectively.

An INF model section can also specify the following hardware ID:

USB\VID_v(4)&PID_d(4)

and the following compatible IDs:

USB\CLASS_c(2)&SUBCLASS_s(2)&PROT_p(2)

USB\CLASS_c(2)&SUBCLASS_s(2)

USB\CLASS_c(2)

USB\COMPOSITE

where c(2) is the class code, s(2) is the subclass code, and p(2) is the protocol code. The class code, subclass code, and protocol code are determined by the bDeviceClass, bDeviceSubClass, and bDeviceProtocol fields of the device descriptor, respectively. These values are in 2-digit hexadecimal format.

Multiple-Interface USB Devices

Devices with multiple interfaces are called composite devices. When a new USB composite device is plugged into a Windows 2000 or later machine, the USB hub driver creates a PDO and notifies the operating system that its set of child devices has changed. After querying the hub driver for the hardware identifiers associated with the new PDO, the system searches the appropriate INF files to find a match for the identifiers. If it finds a match other than USB\COMPOSITE, it loads the driver indicated in the INF file. If, however, no other match is found, the operating system makes use of the compatible ID USB\COMPOSITE, for which it loads the USB Generic Parent driver. The Generic Parent driver then creates a separate PDO and generates a separate set of hardware identifiers for each interface of the composite device.

Each interface has a device ID of the following form:

USB\ VID_v(4)&PID_d(4)&MI_z(2)

where v(4) is the 4-digit hexadecimal vendor code that the USB committee assigns to the vendor, d(4) is the 4-digit hexadecimal product code that the vendor assigns to the device, and z(2) is the interface number, extracted from the bInterfaceNumber field of the interface descriptor.

An INF model section can also specify the following compatible IDs:

USB\CLASS_c(2)&SUBCLASS_s(2)&PROT_p(2)

USB\CLASS_c(2)&SUBCLASS_s(2)

USB\CLASS_c(2)

USB\COMPOSITE

where c(2) is the class code, s(2) is the subclass code, and p(2) is the protocol code. The class code, subclass code, and protocol code are determined by the bInterfaceClass, bInterfaceSubClass, and bInterfaceProtocol fields of the interface descriptor, respectively. These values are in 2-digit hexadecimal format.


Device Classes

This section provides information about two device classes used to place devices and drivers into groups whose members have similar characteristics:

Device Setup Classes
Used to group together devices that are installed and configured in a similar manner.
Device Interface Classes
Used to group together devices that provide similar capabilities.

Because of similarities in the way both types of device classes are specified and used, the section provides a topic entitled Setup Classes Versus Interface Classes.

Setup functions use device information sets to expose the members of a class to user-mode code.


Device Setup Classes

To facilitate device installation, devices that are set up and configured in the same way are grouped into a device setup class. For example, SCSI media changer devices are grouped into the MediumChanger device setup class. The device setup class defines the class installer and class co-installers that are involved in installing the device.

Microsoft defines setup classes for most devices. IHVs and OEMs can define new device setup classes, but only if none of the existing classes apply. For example, a camera vendor doesn't need to define a new setup class because cameras fall under the Image setup class. Similarly, uninterruptible power supply (UPS) devices fall under the Battery class.

There is a GUID associated with each device setup class. System-defined setup class GUIDs are defined in devguid.h and typically have symbollic names of the form GUID_DEVCLASS_Xxx.

The device setup class GUID defines the ..\CurrentControlSet\Control\Class\ClassGUID registry key under which to create a new subkey for any particular device of a standard setup class.

This section provides the following topics:

System-Supplied Device Setup Classes

Creating a New Device Setup Class


System-Supplied Device Setup Classes

This section lists the system-supplied device setup classes. In the definition for each class, the Class and ClassGuid entries correspond to the values that must be specified in the INF Version Section of a device's INF file. The GUIDs for system-supplied device setup classes are defined in devguid.h.

Supplying the appropriate class GUID value in the INF for a device, rather than or in addition to the Class=class-name entry, significantly improves the performance of system INF searching. In fact, system INFs that do not require either entry, such as those that neither install a new device class installer nor a device driver, sometimes supply ClassGuid={00000000-0000-0000-0000-000000000000} in their Version sections to cut down on the system's INF searching time.

Following are two lists of system-defined device setup classes:

System-defined device setup classes available to vendors

System-defined device setup classes reserved for system use

System-Defined Device Setup Classes Available to Vendors

Battery Devices
Class = Battery
ClassGuid = {72631e54-78a4-11d0-bcf7-00aa00b7b32a}

This class includes drivers of battery devices and UPSs.

CD-ROM Drives
Class = CDROM
ClassGuid = {4d36e965-e325-11ce-bfc1-08002be10318}

This class includes drivers of CD-ROM drives, including SCSI CD-ROM drives. By default, the system's CD-ROM class installer also installs a system-supplied CD audio driver and CD-ROM changer driver as Plug and Play filters.

Disk Drives
Class = DiskDrive
ClassGuid = {4d36e967-e325-11ce-bfc1-08002be10318}

This class includes drivers of hard disk drives. See also the HDC and SCSIAdapter classes.

Display Adapters
Class = Display
ClassGuid = {4d36e968-e325-11ce-bfc1-08002be10318}

This class includes drivers of video adapters, including display drivers and video miniports.

Floppy Disk Controllers
Class = FDC
ClassGuid = {4d36e969-e325-11ce-bfc1-08002be10318}

This class includes drivers of floppy disk drive controllers.

Floppy Disk Drives
Class= FloppyDisk
ClassGuid= {4d36e980-e325-11ce-bfc1-08002be10318}

This class includes drivers of floppy drives.

Hard Disk Controllers
Class = HDC
ClassGuid = {4d36e96a-e325-11ce-bfc1-08002be10318}

This class includes drivers of hard disk controllers, including ATA/ATAPI controllers but not SCSI and RAID disk controllers.

Human Input Devices (HID)
Class = HIDClass
ClassGuid = {745a17a0-74d3-11d0-b6fe-00a0c90f57da}

This class includes devices that export interfaces of the HID class, including HID keyboard and mouse devices, which the installed HID device drivers enumerate as their respective child devices. (See also the Keyboard or Mouse classes later in this list.)

IEEE 1284.4 Devices
Class=Dot4
ClassGuid = {48721b56-6795-11d2-b1a8-0080c72e74a2}

This class includes drivers that control the operation of multifunction IEEE 1284.4 peripheral devices.

IEEE 1284.4 Print Functions
Class = Dot4Print
ClassGuid = {49ce6ac8-6f86-11d2-ble5-0080c72e74a2}

This class includes Dot4 print functions. A Dot4 print function is a function on a Dot4 device and has a single child device, which is a member of the Printer device setup class.

IEEE 1394 Host Bus Controller
Class = 1394
ClassGuid = {6bdd1fc1-810f-11d0-bec7-08002be2092f}

This class includes system-supplied drivers of 1394 host controllers connected on a PCI bus, but not drivers of 1394 peripherals.

Imaging Device
Class = Image
ClassGuid = {6bdd1fc6-810f-11d0-bec7-08002be2092f}

This class includes drivers of still-image capture devices, digital cameras, and scanners.

IrDA Devices
Class = Infrared
ClassGuid = {6bdd1fc5-810f-11d0-bec7-08002be2092f}

This class includes Serial-IR and Fast-IR NDIS miniports, but see also the Network Adapter class for other NDIS NIC miniports.

Keyboard
Class = Keyboard
ClassGuid = {4d36e96b-e325-11ce-bfc1-08002be10318}

This class includes all keyboards. That is, it also must be specified in the (secondary) INF for an enumerated child HID keyboard device.

Media Changers
Class = MediumChanger
ClassGuid = {ce5939ae-ebde-11d0-b181-0000f8753ec4}

This class includes drivers of SCSI media changer devices.

Memory Technology Driver
Class = MTD
ClassGUID = {4d36e970-e325-11ce-bfc1-08002be10318}

This class includes drivers for memory devices, such as flash memory cards.

Modem
Class = Modem
ClassGuid = {4d36e96d-e325-11ce-bfc1-08002be10318}

This class includes modems. An INF for a device of this class installs no device driver(s), but rather specifies the features and configuration information of a particular modem and stores this information in the registry. See also the Multifunction class.

Monitor
Class = Monitor
ClassGuid = {4d36e96e-e325-11ce-bfc1-08002be10318}

This class includes display monitors. An INF for a device of this class installs no device driver(s), but rather specifies the features of a particular monitor to be stored in the registry for use by drivers of video adapters. (Monitors are enumerated as the child devices of display adapters.)

Mouse
Class = Mouse
ClassGuid = {4d36e96f-e325-11ce-bfc1-08002be10318}

This class includes all mouse devices and other kinds of pointing devices, such as trackballs. That is, this class also must be specified in the (secondary) INF for an enumerated child HID mouse device.

Multifunction Devices
Class = Multifunction
ClassGuid = {4d36e971-e325-11ce-bfc1-08002be10318}

This class includes combo cards, such as a PCMCIA modem and netcard adapter. The driver for such a Plug and Play multifunction device is installed under this class and enumerates the modem and netcard separately as its child devices.

Multimedia
Class = Media
ClassGuid = {4d36e96c-e325-11ce-bfc1-08002be10318}

This class includes Audio and DVD multimedia devices, joystick ports, and full-motion video capture devices.

Multiport Serial Adapters
Class = MultiportSerial
ClassGuid = {50906cb8-ba12-11d1-bf5d-0000f805f530}

This class includes intelligent multiport serial cards, but not peripheral devices that connect to its ports. It does not include unintelligent (16550-type) mutiport serial controllers or single-port serial controllers (see the Ports class).

Network Adapter
Class = Net
ClassGuid = {4d36e972-e325-11ce-bfc1-08002be10318}

This class includes NDIS NIC miniports excluding Fast-IR miniports, NDIS intermediate drivers (of virtual adapters), and CoNDIS MCM miniports.

Network Client
Class = NetClient
ClassGuid = {4d36e973-e325-11ce-bfc1-08002be10318}

This class includes network and/or print providers.

Network Service
Class = NetService
ClassGuid = {4d36e974-e325-11ce-bfc1-08002be10318}

This class includes network services, such as redirectors and servers.

Network Transport
Class = NetTrans
ClassGuid = {4d36e975-e325-11ce-bfc1-08002be10318}

This class includes NDIS protocols, CoNDIS stand-alone call managers, and CoNDIS clients, as well as higher level drivers in transport stacks.

PCMCIA Adapters
Class = PCMCIA
ClassGuid = {4d36e977-e325-11ce-bfc1-08002be10318}

This class includes system-supplied drivers of PCMCIA and CardBus host controllers, but not drivers of PCMCIA or CardBus peripherals.

Ports (COM & LPT ports)
Class = Ports
ClassGuid = {4d36e978-e325-11ce-bfc1-08002be10318}

This class includes drivers of serial and parallel port devices. See also the MultiportSerial class.

Printers
Class = Printer
ClassGuid = {4d36e979-e325-11ce-bfc1-08002be10318}

This class includes printer drivers.

Printers, Bus-specific class drivers
Class = PNPPrinters
ClassGuid = {4658ee7e-f050-11d1-b6bd-00c04fa372a7}

This class includes bus-specific print class drivers, which provide printer communication for a specific bus.

Processors
Class = Processor
ClassGuid = {50127dc3-0f36-415e-a6cc-4cb3be910b65}

This class includes processor types.

SCSI and RAID Controllers
Class = SCSIAdapter
ClassGuid = {4d36e97b-e325-11ce-bfc1-08002be10318}

This class includes SCSI HBA miniports and disk-array controller drivers.

Smart Card Readers
Class = SmartCardReader
ClassGuid = {50dd5230-ba8a-11d1-bf5d-0000f805f530}

This class includes drivers for smart card readers.

Storage Volumes
Class = Volume
ClassGuid = {71a27cdd-812a-11d0-bec7-08002be2092f}

This class includes storage volumes as defined by the system-supplied logical volume manager and class drivers that create device objects to represent storage volumes, such as the system disk class driver.

System Devices
Class = System
ClassGuid = {4d36e97d-e325-11ce-bfc1-08002be10318}

This class includes HALs, system bus drivers, the system ACPI driver, and the system volume manager driver. It also includes battery drivers and UPS drivers.

Tape Drives
Class = TapeDrive
ClassGuid = {6d807884-7d21-11cf-801c-08002be10318}

This class includes drivers of tape drives, including all tape miniclass drivers.

USB
Class = USB
ClassGuid = {36fc9e60-c465-11cf-8056-444553540000}

This class includes system-supplied (bus) drivers of USB host controllers and drivers of USB hubs, but not drivers of USB peripherals.

System-Defined Device Setup Classes Reserved for System Use

The following classes and GUIDs should not be used to install devices (or drivers) on Windows 2000 or later platforms:

Adapter
Class = Adapter
ClassGUID = {4d36e964-e325-11ce-bfc1-08002be10318}

This class is obsolete.

APM
Class = APMSupport
ClassGUID = {d45b1c18-c8fa-11d1-9f77-0000f805f530}

This class is reserved for system use.

Bluetooth
Class = Bluetooth
ClassGUID = {e0cbf06c-cd8b-4647-bb8a-253b43f0f974}

This class is reserved for system use.

Computer
Class = Computer
ClassGUID = {4d36e966-e325-11ce-bfc1-08002be10318}

This class is reserved for system use.

Decoders
Class = Decoder
ClassGUID = {6bdd1fc2-810f-11d0-bec7-08002be2092f}

This class is reserved for future use.

Global Positioning System
Class = GPS
ClassGUID = {6bdd1fc3-810f-11d0-bec7-08002be2092f}

This class is reserved for future use.

No driver
Class = NoDriver
ClassGUID = {4d36e976-e325-11ce-bfc1-08002be10318}

This class is obsolete.

Non-Plug and Play Drivers
Class = LegacyDriver
ClassGUID = {8ecc055d-047f-11d1-a537-0000f8753ed1}

This class is reserved for system use.

Other Devices
Class = Unknown
ClassGUID = {4d36e97e-e325-11ce-bfc1-08002be10318}

This class is reserved for system use. Enumerated devices for which the system cannot determine the type are installed under this class. Do not use this class if you're unsure in which class your device belongs. Either determine the correct device setup class or create a new class.

Printer Upgrade
Class = Printer Upgrade
ClassGUID = {4d36e97a-e325-11ce-bfc1-08002be10318}

This class is reserved for system use.

Sound
Class = Sound
ClassGUID = {4d36e97c-e325-11ce-bfc1-08002be10318}

This class is obsolete.


Creating a New Device Setup Class

You should only create a new device setup class if absolutely necessary. It is usually possible to assign your device to one of the system-supplied device setup classes.

If your device meets both of the following criteria, you should assign it to an existing device setup class:

  • Your device's installation and configuration requirements match those of an existing class.
  • Your device's capabilities match those of an existing class.

Under the either of following circumstances, you should consider providing a device co-installer:

  • Your device has installation requirements that are not supported by an existing device type-specific INF file.
  • Installation of your device requires device property pages that are not provided by an existing class.

If your device provides capabilities that are significantly different from the capabilities provided by devices that belong to existing classes, it might merit a new device setup class. However, you must never create a new setup class for a device that belongs to one of the system-supplied classes. If you do, you will bypass the system-supplied class installer and your device will not be properly integrated into the system.

If you think a new device setup class is needed, your new class should be based on new device capabilities, and not on the device's location. For instance, supporting an existing device on a new bus should not require a new setup class.

Before creating a new device setup class, contact Microsoft to find out if a new system-supplied device setup class is being planned for your device type

You can create a new device setup class using an INF file. Besides installing support for a device, an INF file can initialize a new device setup class for the device. Such an INF file has an INF ClassInstall32 section.


Device Interface Classes

Device interface classes are the means by which drivers make devices available to applications and other drivers.

This section contains the following topics:

Introduction to Device Interfaces

Registering a Device Interface Class

Enabling and Disabling a Device Interface Instance

Using a Device Interface


Introduction to Device Interfaces

Any driver of a physical, logical, or virtual device to which user-mode code can direct I/O requests must supply some sort of name for its user-mode clients. Using the name, a user-mode application (or other system component) identifies the device from which it is requesting I/O.

In Windows NT® 4.0 and earlier versions of the NT-based operating system, drivers named their device objects and then set up symbolic links in the registry between these names and a user-visible Win32® logical name.

For Windows® 2000 and later, drivers do not name device objects. Instead, they make use of device interface classes. A device interface class is a way of exporting device and driver functionality to other system components, including other drivers, as well as user-mode applications. A driver can register a device interface class, then enable an instance of the class for each device object to which user-mode I/O requests might be sent.

Each device interface class is associated with a GUID. The system defines GUIDs for common device interface classes in device-specific header files. Vendors can create additional device interface classes.

For example, three different types of mice could be members of the same device interface class, even if one connects through a USB port, a second through a serial port, and the third through an infrared port. Each driver registers its device as a member of the interface class GUID_DEVINTERFACE_MOUSE. This GUID is defined in the header file ntddmou.h.

Typically, drivers register for only one interface class. However, drivers for devices that have specialized functionality beyond that defined for their standard interface class might also register for an additional class. For example, a driver for a disk that can be mounted should register for both its disk interface class (GUID_DEVINTERFACE_DISK) and the mountable device class (MOUNTDEV_MOUNTED_DEVICE_GUID).

When a driver registers an instance of a device interface class, the I/O Manager associates the device and the device interface class GUID with a symbolic link name. The link name is stored in the registry and persists across system boots. An application that uses the interface can query for instances of the interface and receive a symbolic link name representing a device that supports the interface. The application can then use the symbolic link name as a target for I/O requests.


Registering a Device Interface Class

There are three ways to register a device interface class:

  • Kernel-mode components, such as most drivers, can call I/O Manager routines. This topic describes how to use these routines.
  • User-mode setup applications call call SetupDi Xxx functions. See Device Interface Functions for information about these functions.
  • An INF file can contain INF DDInstall.Interfaces sections.

A WDM driver does not name its device objects. Instead, when the driver calls IoCreateDevice to create a device object, it should specify a NULL string for the device name. Bus drivers should set the FILE_AUTOGENERATED_DEVICE_NAME flag. All PnP function, filter, and bus drivers should set the FILE_DEVICE_SECURE_OPEN flag. In response, the system chooses a unique device name for the PDO.

After creating the device object and attaching it to the device stack, one driver calls IoRegisterDeviceInterface to register a device interface class and to create an instance of the interface. Typically, the function driver makes this call from its AddDevice routine, but sometimes the filter driver registers the interface.

The routine returns a symbolic link name. A driver passes the link name when it enables or disables the device interface instance. Other system components cannot use a device interface instance until the driver has enabled it. See Enabling and Disabling a Device Interface Instance for details.

The driver also uses the symbolic link name to access the registry key, in which it can store information specific to the device interface. (See IoOpenDeviceInterfaceRegistryKey for more information.) Applications use the link name to open the device.

A driver can call IoRegisterDeviceInterface as many times as necessary to register instances of additional device interface classes.


Enabling and Disabling a Device Interface Instance

After successfully starting the device, the driver that registered the interface calls IoSetDeviceInterfaceState to enable an interface instance. The driver passes the symbolic link name returned by IoRegisterDeviceInterface along with the Boolean value TRUE to enable the interface instance.

If the driver can successfully start its device, it should call this routine while handling the Plug and Play (PnP) Manager's IRP_MN_START_DEVICE request.

After the IRP_MN_START_DEVICE request completes, the PnP Manager issues device interface arrival notifications to any kernel-mode or user-mode components that requested them. For more information, see Registering for Device Interface Change Notification.

To disable a device interface instance, a driver calls IoSetDeviceInterfaceState, passing the SymbolicLinkName returned by IoRegisterDeviceInterface and FALSE as the value of Enable.

A driver should disable a device's interfaces when it handles an IRP_MN_SURPRISE_REMOVAL or IRP_MN_REMOVE_DEVICE for the device. A driver should not disable the interfaces when the device is stopped (IRP_MN_STOP_DEVICE) or put in a sleep state; it should leave any device interfaces enabled and queue I/O instead.


Using a Device Interface

Device interfaces are available to both kernel-mode components and user-mode applications. User-mode code must can SetupDi Xxx functions to find out about registered, enabled device interfaces. See Device Interface Functions for details.

Before a kernel-mode component can use a specific device or file object, it must do the following:

  1. Determine whether the required device interface class is registered and enabled.

    A driver can register with the PnP Manager to be notified when an instance of a device interface is enabled or disabled. To register, the component calls IoRegisterPlugPlayNotification. This routine stores the address of a driver-supplied callback, which is called whenever an instance of a device interface instance is enabled or disabled, for a specified device class. The callback routines receives the DEVICE_INTERFACE_CHANGE_NOTIFICATION structure, which contains a Unicode string representing the interface instance's symbolic link. See Using PnP Device Interface Change Notification for more information.

    A driver or other kernel-mode component can also call IoGetDeviceInterfaces to get a list of all registered, enabled device interface instances for a specific device interface class. The returned list contains pointers to the Unicode symbolic link strings that identify the device interface instances.

  2. Get a pointer to a device or file object corresponding to an instance of the interface.

    To access a specific device object, the driver must call IoGetDeviceObjectPointer, passing the Unicode string for the required interface in the ObjectName parameter. To access a file object, the driver must call InitializeObjectAttributes, passing the Unicode string in the ObjectName parameter, and then pass the successfully initialized attribute structure in a call to ZwCreateFile.


Setup Classes Versus Interface Classes

It is important to distinguish between the two types of device classes: device interface classes and device setup classes. The two can be easily confused because in user-mode code the same set of device installation functions and the same set of data structures (device information sets) are used with both classes. Moreover, a device often belongs to both a setup class and several interface classes at the same time. Nevertheless, the two types of classes serve different purposes, make use of different areas in the registry, and rely on a different set of header files for defining class GUIDs.

Device setup classes provide a mechanism for grouping devices that are installed and configured in the same way. A setup class identifies the class installer and class co-installers that are involved in installing the devices that belong to the class. For example, all CD-ROM drives belong to the CDROM setup class and will use the same co-installer when installed.

Device interface classes provide a mechanism for grouping devices according to shared characteristics. Rather than tracking the presence in the system of an individual device, drivers and user applications can register to be notified of the arrival or removal of any device that belongs to a particular interface class.

Setup classes are defined in the system file devguid.h. This file defines a series of GUIDs for setup classes. However, the device setup classes represented in devguid.h must not be confused with device interface classes. The devguid.h file only contains GUIDs for setup classes.

Definitions of interface classes are not provided in a single file. A device interface class is always defined in a header file that belongs exclusively to a particular class of devices. For instance, ntddmou.h contains the definition of GUID_CLASS_MOUSE, the GUID representing the mouse interface class; ntddpar.h defines the interface class GUID for parallel devices; ntddpcm.h defines the standard interface class GUID for PCMCIA devices; ntddstor.h defines the interface class GUID for storage devices, and so on.

The GUIDs in header files that are specific to the device interface class should be used to register for notification of arrival of an instance of a device interface. If a driver registers for notification using a setup class GUID instead of an interface class GUID, then it will not be notified when an interface arrives.

When defining a new setup class or interface class, do not use a single GUID to identify both a setup class and an interface class.

For additional information about GUIDs, see Using GUIDs in Drivers.


Device Information Sets

In user mode, devices that belong to either device setup classes or device interface classes are managed using device information elements and device information sets. A device information set consists of device information elements for all the devices belonging to some device setup class or device interface class.

Each device information element contains a handle to the device's devnode, and a pointer to a linked list of all the device interfaces associated with the device described by that element. If a device information set describes members of a setup class, the element might not point to any device interfaces, since setup class members are not necessarily associated with an interface.

The following diagram depicts the internal structure of a device information set.

Device Information Set

Creating a Device Information Set

After creating a device information set with SetupDiCreateDeviceInfoList, device information elements can be created and added to the list one at a time using SetupDiCreateDeviceInfo. Alternatively, SetupDiGetClassDevs can be called to create a device information set composed of all devices associated with a specified device setup class or device interface class.

Enumerating Device Information

Once a device information set has been created, both the devices and the device interfaces that belong to the set can be enumerated, but different operations are required for each type of enumeration. SetupDiEnumDeviceInfo enumerates all devices that belong to the information set that meet certain criteria. Each call to SetupDiEnumDeviceInfo extracts a SP_DEVINFO_DATA structure that roughly corresponds to a device information element. SP_DEVINFO_DATA contains the GUID of the class that the device belongs to and a device instance handle that points to the devnode for the device. The principal difference between an SP_DEVINFO_DATA structure and a complete device element is that SP_DEVINFO_DATA does not contain the linked list of interfaces associated with the device. Therefore, SetupDiEnumDeviceInfo can not be used to enumerate the interfaces in the device information set.

To enumerate the device interfaces in a device information set, call SetupDiEnumDeviceInterfaces. This routine steps through all the device information elements in the device information set, extracts the interfaces in the interface list of each element, and returns one interface with each call. If SetupDiEnumDeviceInterfaces is passed an SP_DEVINFO_DATA structure as input in its second parameter, it constrains the enumeration to only those interfaces that are associated with the device indicated by SP_DEVINFO_DATA.

SetupDiEnumDeviceInterfaces returns an SP_DEVICE_INTERFACE_DATA structure. SP_DEVICE_INTERFACE_DATA contains the interface class GUID and other information about the interface, including a reserved field with encoded information that can be used to obtain the name of the interface. To get the interface name, one further step is required: SetupDiGetDeviceInterfaceDetail must be called. SetupDiGetDeviceInterfaceDetail returns a structure of type SP_DEVICE_INTERFACE_DETAIL_DATA that contains the path in the system object tree that defines the interface.


INF File Sections and Directives

This section describes the syntax of INF files. It contains the following introductory information:

General Syntax Rules for INF Files

Looking at an INF File

Summary of INF Sections

Summary of INF Directives

The following topic contains references pages for all INF sections and directives:

Sections and Directives

For additional information on creating and using INF files, see Creating an INF File.


General Syntax Rules for INF Files

An INF file is a text file organized into named sections. Some sections have system-defined names and some sections have names determined by the writer of the INF.

Each section contains section-specific entries, which are interpreted by Setup software (class installers, co-installers, SetupAPI). Some entries begin with a predefined keyword. These entries are called directives.

Some INF entries are essentially pointers from one section to another, for a specific purpose. For example, an INF AddReg directive identifies a section containing entries that instruct Setup to modify the registry. These entries sometimes include additional arguments (required or optional) for Setup to interpret during installation.

Other INF entries do not point to other sections, but simply supply information that Setup uses during installation, such as filenames, registry values, hardware configuration information, flags, and so on. For example, an INF DriverVer directive supplies driver version information.

When Setup begins an installation, it first looks for an INF Version section to verify the validity of the INF file and to determine where installation files are located. It then starts the installation by finding an INF Manufacturer section, which will contain directives to INF Models sections, which in turn provide directives leading to various INF DDInstall sections, based on the hardware ID of the device being installed.

Following are syntax rules that govern the required and optional contents of INF files, the format of section names, using string tokens, and line format, continuation, and comments.

Required and Optional Contents
  • The set of required and optional sections, entries, and directives in any particular INF depends on the type of device/driver or component (such as an application or device class installer DLL) to be installed.
  • The set of sections, section-specific entries, and directives required to install any particular device and its drivers also depends somewhat on the corresponding class installer. For more information about how the system-supplied class installers handle device-type-specific INF files, see device-type specific documentation in this DDK.
  • Within syntax definitions, optional entries are delimited by unbolded brackets ([,]). On the other hand, bolded brackets ([, ]) are required elements of the entry in which they are contained. In the following example, the brackets around Version are required, while the brackets around Class=class-name indicate this entry is optional.

    [Version]

    Signature="signature-name"
    [Class=class-name]
    ...

Section Names
  • Sections can be specified in any order. Most INF files list sections in a particular order, by convention, but Setup finds sections by name, not by location within the INF file.
  • Each section in an INF begins with the section name enclosed in brackets ([ ]). The section name can be system-defined or INF-writer-defined.

    For example, [Manufacturer] specifies the start of the system-named Manufacturer section, while [Std.Mfg] represents a particular INF-writer-defined Models section name.

    A section name has a maximum length of 255 bytes on NT-based operating systems. On Windows 98/Me, section names should be no longer than 28 characters. INF files designed to work on both platforms must adhere to the smaller limit.

    Each section ends at the beginning of a new [section-name] or at the end-of-file mark.

  • If more than one section in an INF has the same name, the system merges their entries and directives into a single section.
  • Section names, entries, and directives are case-insensitive, so version, VERSION, and Version are equally valid section-name specifications within an INF.
  • Unless it is enclosed in double quotation marks characters ("), an INF-writer-defined section name must be a unique-to-the-INF unquoted string of explicitly visible characters, excluding certain characters with INF-specific meanings. In particular, an unquoted section name referenced by a section entry or directive cannot have leading or trailing spaces, a linefeed character, a return character, or any invisible control character, and it should not contain tabs. In addition, it cannot contain either of the bracket ([ ]) characters, a single percent (%) character, a semicolon (;), or any internal double quotation marks (") characters, and it cannot have a backslash (\) as its last character.

    For example, Std.Mfg and Std_Mfg are unique and valid section names when referenced by an INF entry or directive, but Std;Mfg (with its internal semicolon) is invalid unless it is enclosed by double quotation marks (").

    Specifying an INF-writer-defined section name as a "quoted string" overrides most of the preceding restrictions on characters in referenced section names. Such a delimited section name can contain almost any explicitly or implicitly visible characters except the closing bracket (]) as long as the corresponding section in the INF matches this "quoted string" exactly.

    For example, ";; Std Mfg " is a valid section-name reference if the corresponding section declaration in the INF exactly matches the name inside the double quotation marks with respect to its space and semicolon characters as [;; Std Mfg ].

Using String Tokens
  • Many values in an INF, including INF-writer-defined section names, can be expressed as string key tokens of the form %strkey%. In the INF Strings section of the INF file, each string key must be associated with a string value consisting of a sequence of explicitly visible characters, which the setup code converts, if necessary, into Unicode.

    (See the description of the INF Strings section for more information about how to define %strkey% tokens and their respective values.)

Line Format, Continuation, and Comments
  • Each entry and directive in a section ends with a return or linefeed character. Consequently, the text editor used to create an INF file must not insert return or linefeed characters after some arbitrary, editor-determined number of characters.
  • The backslash character (\) can be used as an explicit line continuator in an entry or directive. If part of an entry or directive, such as a path, includes a backslash at the end of a line, that backslash must be delimited with double quotation marks ("\") to override its interpretation as a line continuator.
  • Comments begin with a semicolon (;) character. When parsing and interpreting an INF file, the system assumes that the following have no relevance to the installation process:

    (1) Any characters following a semicolon on the same line, unless the semicolon appears within a "quoted string" or %strkey% token

    (2) Any empty line containing nothing except a linefeed or return character

  • Commas separate the values supplied in section entries and directives.

    An INF entry or directive can omit an optional value in the middle of a list of values, but the commas must remain. INF files for NT-bases systems can omit trailing commas, but Windows 9x INF files must not. Dual-OS INF files should specify trailing commas in any sections that are used on Windows 9x machines. Dual-OS INF files can omit trailing commas in sections that are only used for NT-based systems (that is, sections whose names are decorated with .nt, .ntx86, and so forth).

    For example, consider the syntax for a SourceDisksFiles section entry:

    filename = diskid[,[subdir][,size]]

    An entry that omits the subdir value but supplies the size value must specify both delimiting internal commas, as follows:

    filename = diskid,,size

    An entry in an INF for an NT-based OS that omits the two optional values can have this format:

    filename = diskid

    An entry in a Windows9x INF that omits the two optional values must specify the trailing commas, as follows:

    filename = diskid,,

INF Size Limits
  • A Windows 9x/Me INF file cannot be larger than 64 kilobytes. There is no practical limit to the size of an INF file for NT-based systems.
  • Unless otherwise restricted in this documentation, the maximum length of any INF field is 512 characters (including a terminating NULL).


Looking at an INF File

The following example shows selected fragments from a system-supplied class installer's INF file to illustrate how any INF file is made up of sections, each containing zero or more lines, some of which are entries that reference additional INF-writer-defined sections:

[Version]
Signature="$Windows NT$"
Class=Mouse
ClassGUID={4D36E96F-E325-11CE-BFC1-08002BE10318}
Provider=%Provider% ; defined later in Strings section
LayoutFile=layout.inf ; entry used only by system installers
DriverVer=09/28/1999,5.00.2136.1

; ... some class installer sections omitted here

[DestinationDirs]
DefaultDestDir=12 ; DIRID_DRIVERS

; ... [ControlFlags] section omitted here

[Manufacturer]
%StdMfg%    =StdMfg         ; (Standard types)
%MSMfg%     =MSMfg          ; Microsoft
; ... %otherMfg% entries omitted here

[StdMfg]  ; per-Manufacturer Models section
; Std serial mouse
%*pnp0f0c.DeviceDesc%= Ser_Inst,*PNP0F0C,SERENUM\PNP0F0C,SERIAL_MOUSE
; Std InPort mouse
%*pnp0f0d.DeviceDesc%      = Inp_Inst,*PNP0F0D
     ; ... more StdMfg entries and following
     ; MSMfg and xxMfg Models sections omitted here

     ; per-Models DDInstall (Ser_Inst, Inp_Inst, etc.)
     ; sections also omitted here

[Strings]
; where INF %strkey% tokens are defined as user-visible (and
; possibly as locale-specific) strings.
Provider = "Microsoft"
; ...
StdMfg   = "(Standard mouse types)"
MSMfg    = "Microsoft"

; ...
*pnp0f0c.DeviceDesc   = "Standard Serial Mouse"
*pnp0f0d.DeviceDesc   = "InPort Adapter Mouse"
; ...
HID\Vid_045E&Pid_0009.DeviceDesc = "Microsoft USB Intellimouse"
; ...

A few sections within the preceding INF have system-defined names, such as Version, DestinationDirs, Manufacturer, and Strings. Some named sections like Version, DestinationDirs, and Strings have only simple entries. Others reference additional INF-writer-defined sections, as shown in the preceding example of the Manufacturer section.

Note the implied hierarchy of related sections for mouse device driver installations starting with the Manufacturer section in the preceding example. The following figure shows the hierarchy of some of the sections in the INF file.

Sample Hierarchy of Sections in an INF File

Note the following about the implied hierarchy of an INF file:

  • Each %xxMfg% entry in the Manufacturer section references a per-manufacturer Models section (StdMfg, MSMfg) elsewhere in the INF. (The entries in the example above use %strkey% tokens.)
  • Each Models section specifies some number of entries; in the example they are %xxx.DeviceDesc% tokens.

    Each such %xxx.DeviceDesc% token references some number of per-models DDInstall sections (Ser_Inst and Inp_Inst) for that manufacturer's product line, with each entry identifying a single device (*PNP0F0C and *PNP0F0D, hence the "DeviceDesc" shown here) or a set of compatible models of a device.

  • Each such DDInstall-type Xxx_Inst section, in turn, can have certain system-defined extensions appended and/or can contain directives that reference additional INF-writer-defined sections. For instance, the full INF shown as fragments in the preceding example also has a Ser_Inst.Services section, and its Ser_Inst section has a CopyFiles directive that references a Ser_CopyFiles section elsewhere in this INF.


Summary of INF Sections

The following summarizes the system-defined sections that can be used in INF files. System-defined section names are case-insensitive, so version, VERSION, and Version are equally valid section-names within an INF.

This chapter describes the INF sections in the same general order used in most device INF files. However, these sections actually can be specified in any arbitrary order. The Setup code finds all sections within each INF file by section name, not by sequential order, whether system-defined or INF-writer-defined.

Version Section
This is a required section for every INF file. For installation on Windows 2000 and later, and/or Windows 9x/Me platforms, this section must have a valid Signature entry.
SourceDisksNames Section
This section is required if the INF has a corresponding SourceDisksFiles section. This section is required to install IHV/OEM-supplied devices and their drivers from distribution media included in packaged products. It is also required in such an INF that installs either of the following:
  • A co-installer DLL to supplement the operations of a system-supplied device class installer or co-installers (see also DDInstall.CoInstallers later in this list)
  • A new class installer DLL to supplement the operations of the OS's device installer (see also ClassInstall32 later in this list)

This section identifies the individual source distribution disks or CD-ROM discs for the installation. By contrast, the system-supplied INF files each specify a LayoutFile entry in their Version sections and provide at least one other INF file detailing the source distribution contents and layout of all software components to be installed.

SourceDisksFiles Section
This section identifies the locations of files to be installed from the distribution media to the destinations on the target machine. An INF that has this section must also have a SourceDisksNames section.
ClassInstall32 Section
This section initializes a device setup class. It is required in any class installer INF file. INF files that install devices and their drivers under any system-defined device class do not need this section.
ClassInstall32.Services Section
INF files commonly use the ClassInstall32.Services section with at least one AddService directive to control how and when the services of a particular device class are loaded, any dependencies it might have on other services, and so forth.
DestinationDirs Section
Device/driver INF files have a DestinationDirs section to specify a default destination directory for INF-specified copies of the files supplied on the distribution media or listed in the INF layout files. This section is required unless the INF installs a device, such as a modem or display monitor, that has no files except its INF to be installed with it.
ControlFlags Section
This section controls whether the Add Hardware Wizard presents a list of INF-specified Models values from which the end user selects a particular manually installed device (or model of a device) to be installed from the INF. It also can control whether an INF is used only to transfer files from the distribution media.

In general, most INF files for device drivers and for the system class installers have this section so they can exclude at least a subset of Models entries from the list of manually installable devices to be displayed to end users. INF files that only install PnP devices suppress the display of all model-specific information.

Manufacturer Section
This section is required in INF files for devices and their drivers.

The Manufacturer section of a system device class INF is sometimes called a "Table of Contents," because each of its entries references an INF-writer-defined Models section, which, in turn, references additional INF-writer-defined sections, such as a per-models-entry DDInstall section, DDInstall.Services section, and so forth.

Models Section (per Manufacturer entry)
This section is required to identify the devices for which the INF installs drivers. It specifies a set of mappings between the generic name (string) for a device, the device ID, and the name of the DDInstall section, elsewhere in the INF, containing the installation instructions for the device.

An INF that installs one or more devices and drivers for a single provider would have only one Models section, but system INF files for device classes can have many INF-writer-defined Models sections.

DDInstall Section (per Models entry)
This section is required to actually install any devices listed in a Models section in the INF, along with the drivers for each such device. A DDInstall section can be shared by more than one Models section.
DDInstall.Services Section
This section is required as an expansion of the DDInstall section for most Windows 2000 and later kernel-mode device drivers, including any WDM drivers (exceptions are INF files for modems and display monitors). It controls how and when the services of a particular driver are started, its dependencies (if any) on underlying legacy drivers, and so forth. This section also sets up event-logging services by a device driver if it supports event logging.
DDInstall.HW Section
This optional section adds device-specific (and typically, driver-independent) information to the registry or removes such information from the registry, possibly for a multifunction device or to install one or more PnP filter drivers.
DDInstall.CoInstallers Section
This optional section registers one or more device-specific co-installers supplied on the distribution media to supplement the operations of the system's device installer or of an existing device class installer.

A co-installer is an IHV/OEM-provided Win32® DLL that typically writes additional configuration information to the registry or performs other installation tasks that require dynamically generated, machine-specific information that is not available when the device's INF is created. For more information, see Writing a Co-installer.

DDInstall.FactDef Section
This section should be included in the INF of any manually installed nonPnP device. It specifies the factory default hardware configuration settings, such as the bus-relative I/O ports, IRQ (if any), and so forth, for the card.
DDInstall.LogConfigOverride Section
This section is used to create an override configuration, which overrides the hardware resource requirements that a Plug and Play device's bus driver reports.
DDInstall.Interfaces Section
If a driver exports the functionality of a device interface class, thus creating a new instance of the interface class, such as kernel-streaming still-image capture or data decompression, its INF file can have this section.
InterfaceInstall32 Section
If a to-be-installed component, such as a new class driver, provides one or more new device interface classes to higher-level components, its INF file has this section. In effect, this section bootstraps a set of device interfaces for a new class by setting up whatever is needed to make use of the functionality that the interface class provides.
DefaultInstall Section
An INF file's DefaultInstall section will be accessed if a user selects the "Install" menu item after right-clicking on the INF file name.
DefaultInstall.Services Section
This section is equivalent to the INF DDInstall.Services section, and is used in association with an INF DefaultInstall section.
Strings Section
This section is required in every INF file to define each %strkey% token specified in the INF. By convention, the Strings section (or sections if the INF provides a set of locale-specific Strings sections) appears last in all system-supplied INF files for ease of maintenance and localization.

Some of the sections listed here, particularly those with Install in their names, can contain directives that reference additional INF-writer-defined sections. Each directive causes particular operations to be carried out on the items listed under the appropriate type of INF-writer-defined section during the installation process.

The set of valid entries and directives for any particular section in the preceding list is section-specific and shown in the formal syntax of the reference for each of these sections. Additionally, see Summary of INF Directives for a summary of the most commonly used directives.

Optional entries and directives within each such section are shown enclosed in unbolded brackets, as for example:

[Version]
...
[Provider=%INF-creator%]
...

The Provider entry in a [Version] section is optional in the sense that it is not a mandatory entry in every INF file.


Summary of INF Directives

The following list summarizes many (but not all) of the directives that can be used in INF files. INF directive names are case-insensitive, so Addreg, addReg, and AddReg are equally valid as directive specifications within an INF.

This section lists the most commonly used directives first, together with their reciprocal or related directives. The most rarely used directives are toward the end of the list.

AddReg Directive
This directive references one or more add-registry-sections, which are INF sections used to add or modify subkeys and value entries in the registry.

The particular INF section in which an AddReg (or DelReg) directive resides determines the default, relative registry location that will receive modifications specified in the referenced add-registry-section (or delete-registry-section). These default registry locations are typically device-specific or driver-specific subkeys somewhere under the HKEY_LOCAL_MACHINE registry tree. For more information, see Driver Information in the Registry.

Additional add-registry-sections can set up registry information for vendor-supplied co-installers, for system-defined device interfaces (such as kernel streaming interfaces) exported to higher level drivers, for new device interfaces exported by an installed component for a given class of devices, for driver services, or (rarely) for a new setup class of devices if the INF has a ClassInstall32 section.

DelReg Directive
This directive references one or more del-registry-sections used to remove obsolete subkeys and/or value entries from the registry. For example, such a section might appear in an INF that upgrades a previous installation.
CopyFiles Directive
This directive references one or more file-list-sections specifying transfers of model/device-specific driver images and any other necessary files from the distribution media to the destination directory for each such file. Alternatively, this directive can specify a single file to be copied from the distribution media to the default destination directory.
DelFiles Directive
This rarely used directive references one or more file-list-sections specifying files to be deleted from the target of the installation.
RenFiles Directive
This rarely used directive references one or more file-list-sections specifying INF-associated source files to be renamed on the destination.
AddService Directive
This directive references at least a service-install-section, possibly with an additional event-log-install-section.

INF files for most kinds of Windows 2000 and later devices (those that install drivers) have an INF-writer-defined service-install-section to specify any dependencies on system-supplied drivers or services, during which stage of the system initialization process the supplied drivers should be loaded, and so forth. Many INF files for device drivers also have an INF-writer-defined event-log-install-section that is referenced by the AddService directive to set up event logging by the device driver.

DelService Directive
This rarely used directive deletes a previously installed service.
AddInterface Directive
This directive references an add-interface-section in which one or more AddReg directives are specified referencing sections that set up the registry entries for the device interfaces supported by this device/driver. Optionally, such an add-interface-section can reference one or more additional sections that specify delete-registry, file-transfer, file-delete, and/or file-rename operations.
BitReg Directive
This rarely used directive references one or more bit-registry-sections specifying existing REG_BINARY-type value entries in the registry for which particular bits in the values are to be modified.
LogConfig Directive
This directive references one or more log-config-sections that specify acceptable bus-relative and device-specific hardware configurations in an INF for devices that are detected (by PnP device enumerators) or manually installed. For example, INF files for nonPnP ISA, EISA, and MCA devices, which are manually installed, use this directive. (Also see INF DDInstall.LogConfigOverride Section.)
UpdateInis Directive
This rarely used directive references one or more update-ini-sections specifying parts of a supplied INI file to be read during installation and, possibly specifying line-by-line modifications to be made in that INI file.
UpdateIniFields Directive
This rarely used directive references one or more update-inifields-sections specifying modifications to be made on fields within the lines of an INI file.
Ini2Reg Directive
This rarely used directive references one or more ini-to-registry-sections specifying lines or sections of an INI file to be written into the registry.

The sections under which any of the directives in the preceding list can be be specified is system-determined. The basic form of each directive is shown in the formal syntax of the reference for each section, as for example:

[DDInstall] | [DDInstall.HW] | [DDInstall.CoInstallers] | [ClassInstall32] | [ClassInstall32.ntx86] | [ClassInstall32.ntia64]

AddReg=add-registry-section[, add-registry-section] ...

The rest of this chapter describes the formal syntax and meaning for each system-defined named section, standard INF-writer-defined section, and directive that can be specified in an INF file.


Sections and Directives

This section describes the syntax of sections and directives that can appear in INF files.


INF Version Section

[Version]

Signature="signature-name"
[Class=class-name]
[ClassGuid={nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn}]
[Provider=%INF-creator%]
[LayoutFile=filename.inf [,filename.inf]... ]
[CatalogFile=filename.cat]
[CatalogFile.nt=unique-filename.cat]
[CatalogFile.ntx86=unique-filename.cat]
[CatalogFile.ntia64=unique-filename.cat]
DriverVer=mm/dd/yyyy[,x.y.v.z]

By convention, the Version section appears first in INF files. Every INF file must have this section.

Entries and Values

Signature="signature-name"
Must be $Windows NT$, $Windows 95$, or $Chicago$, indicating the operating systems for which this INF is valid. These signature values have the following meanings.
Signature Value | Meaning
$Windows NT$ | NT-based operating systems
$Windows 95$ | Windows 9x/Me
$Chicago$ | All Windows operating systems

The enclosing $'s are required but these strings are case-insensitive. If signature-name is none of these string values, the file is not accepted as a valid INF.

Generally, Setup does not differentiate among these signature values. One of them must be specified, but it doesn't matter which one. You should specify the appropriate value so that someone reading an INF file can determine the operating systems for which it is intended. (For Windows Me installations, Setup generally chooses drivers with $Chicago$ or $Windows 95$ signatures, and only chooses drivers with $Windows NT$ signatures if no others are available.)

Some class installers place additional requirements on how the signature value must be specified. Such requirements, if they exist, are discussed in device type-specific sections of this DDK.

An INF must supply OS-specific installation information by appending system-defined extensions to its DDInstall sections, whether the signature-name is $Windows NT$, $Chicago$, or $Windows 95$. (See Creating INF Files for Multiple Platforms and Operating Systems for a discussion of these extensions.)

Class=class-name
For any standard type of device, this specifies the class name, which is usually one of the system-defined class names like Net or Display as listed in devguid.h, for the type of device to be installed from this INF file. See System-Supplied Device Setup Classes.

If an INF specifies a Class it should also specify the corresponding system-defined GUID value for its ClassGUID entry. Specifying the matching GUID value for a device of any predefined device setup class can install the device and its drivers faster since this helps the system setup code to optimize its INF searching.

If an INF adds a new setup class of devices to the system, it should supply a unique, case-insensitive class-name value that is different from any of the system-supplied classes in devguid.h. The length of the class-name string must be 32 characters or less. The INF must specify a newly generated GUID value for the ClassGUID entry. Also see INF ClassInstall32 Section.

This entry is irrelevant to an INF that installs neither a new device driver under a predefined device setup class nor a new device setup class.

ClassGuid = {nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn}
Specifies the device-class GUID, formatted as shown here, where each n is a hexadecimal digit.

For a Windows 2000 and later (and Windows 98/Me) INF, such a GUID value determines the device setup class subkey in the registry ...\Class tree under which to write registry information for the drivers of devices installed from this INF file. This class-specific GUID value also identifies the device class installer for the type of device and class-specific property page provider, if any.

For a new device setup class, the INF must specify a newly generated ClassGUID value. For more information about creating GUIDs, Using GUIDs in Drivers. Also see Device Setup Classes.

Provider=%INF-creator%
Identifies the provider of the INF file. Typically, this is specified as an %OrganizationName% token that is expanded later in the INF's Strings section.

For example, INF files supplied with the system typically specify the INF-creator as %Msft% and define %Msft% = "Microsoft" in their Strings sections.

LayoutFile=filename.inf [,filename.inf]...
Specifies one or more additional system-supplied INF files that contain layout information on the source media required for installing the software described in this INF. All system-supplied INF files specify this entry.

INF files that are not distributed with the OS should omit this entry, if possible. Instead, such INF files should use Include and Needs entries in DDInstall sections, or they should have SourceDisksNames and SourceDisksFiles sections, or both. INF files not distributed with the OS should include a LayoutFile directive only if

  • they require OS-supplied files as part of their installation, and those files are not installable using OS-provided INF sections that can be referenced by Include and Needs entries, or
  • they are used to support Windows 9x/Me. (Windows 9x/Me doesn't automatically include the layout files referenced by INF files you specify in Include entries, so the including INF must reference the layout files itself with LayoutFile entries.)
CatalogFile=filename.cat
Specifies a catalog (.cat) file to be included on the distribution media of a device/driver. Catalog files are supplied by the Microsoft Windows Hardware Quality Lab (WHQL), after WHQL has tested, certified, and assigned digital signatures to driver files. (Contact WHQL for more information about the signing, testing, and certification of IHV and/or OEM driver packages.)

Catalog files are not listed in the SourceDisksFiles or CopyFiles sections of the INF. Setup assumes that the catalog file is in the same location as the INF file.

System-supplied INF files never have CatalogFile= entries because the OS validates the signature for such an INF against all system-supplied xxx.cat files.

[CatalogFile.nt=unique-filename.cat] |
[CatalogFile.ntx86=unique-filename.cat] |
[CatalogFile.ntia64=unique-filename.cat]
Specifies another INF-writer-determined, unique file name, with the .cat extension, of a catalog file that is specific to Windows 2000 or later.

If these optional entries are omitted from a dual-OS INF file, a given CatalogFile=filename.cat is used for validating WDM device/driver installations on all Windows 2000 and later and Windows 98/Me machines. If any decorated CatalogFile.xxx= entry exists in an INF's Version section together with an undecorated CatalogFile= entry, the undecorated entry is assumed to identify a filename.cat for validating device/driver installations only on Windows 98/Me machines.

Note that any cross-platform and/or dual-OS device/driver INF file that has CatalogFile= and CatalogFile.xxx= entries must supply a unique IHV/OEM-determined name for each such .cat file.

DriverVer=mm/dd/yyyy[,x.y.v.z]
This entry specifies version information for drivers installed by this INF. This entry is required in Windows 2000 and later INF files.

For information about how to specify this entry, see INF DriverVer Directive.

Comments

When the Microsoft Windows Hardware Quality Lab (WHQL) certifies a driver package, it returns .cat catalog files to the IHV or OEM. Each .cat file contains a digitally encrypted signature for the driver package. The IHV or OEM must list these .cat files in the INF Version section and must supply the files on the distribution media, in the same location as the INF file. The .cat files must be uncompressed.

Note that if an INF Version section does not include at least one CatalogFile or CatalogFile.nt xxx entry, the driver is treated as unsigned, and dates listed in the DriverVer directive will not be displayed in the UI. For more information, see Enforcement of Digital Signatures.

Example

The following example shows a Version section typical of a simple device-driver INF, followed by the required SourceDisksNames and SourceDisksFiles sections implied by the entries specified in this sample Version section:

[Version]
Signature="$Chicago$"
Class=SCSIAdapter
ClassGUID={4D36E97B-E325-11CE-BFC1-08002BE10318}
Provider=%INF_Provider%
CatalogFile=aha154_win98.cat
CatalogFile.ntx86=aha154_ntx86.cat
DriverVer=08/20/1999

[SourceDisksNames]
;
; diskid = description[, [tagfile] [, <unused>, subdir]]
;
1 = %Floppy_Description%,,,\Win98
2 = %Floppy_Description%,,,\WinNT

[SourceDisksFiles]
;
; filename_on_source = diskID[, [subdir][, size]]
;
aha154x.mpd = 1,,

[SourceDisksFiles.x86]
aha154x.sys = 2,\x86

; ...

[Strings]
INF_Provider="Adaptec"
Floppy_Description = "Adaptec Drivers Disk"
; ...

See Also

DDInstall, SourceDisksNames, SourceDisksFiles, Strings


INF SourceDisksNames Section

[SourceDisksNames] |
[SourceDisksNames.x86] |
[SourceDisksNames.ia64]

diskid = disk-description[,[tag-or-cab-file],[unused,path][,flags]] |
diskid = disk-description[,[tag-or-cab-file],[unused,path],[flags][,tag-file]] Windows XP and later
...

A SourceDisksNames section identifies the distribution disks or CD-ROM discs that contain the source files to be transferred to the target machine during installation.

Entry Values

diskid
Specifies a nonnegative integer that identifies a source disk. This value can be expressed in decimal or in hexadecimal notation, but it cannot require more than four bytes of storage. If there is more than one source disk for the distribution, each diskid entry in this section must have a unique value, such as 1, 2, 3,... or 0x0, 0x1, 0x2,... and so forth.
disk-description
Specifies a %strkey% token or a "quoted string" that describes the contents and/or purpose of the disk identified by diskid. The installer can display the value of this string to the end user during installation, for example, to identify a source disk to be inserted into a drive at a particular stage of the installation process.

Every %strkey% specification in this section must be defined in the INF's Strings section. Any disk-description that is not a %strkey% token is a user-visible string that must be delimited by double quotation marks characters (") if it has any leading or trailing spaces.

tag-or-cab-file
This optional value specifies the name of a tag file or cabinet file supplied on the distribution disk, either in the installation root or in the subdirectory specified by path, if any. The value should specify only the file name and extension, not any directory or subdirectory.

Setup uses a tag file to verify that the user inserted the correct installation disk. Tag files are required for removable media, and are optional for fixed media.

If Setup cannot find installation files by name on the installation medium, and if tag-or-cab-file has the extension .cab, Setup uses it as the name of a cabinet file containing the installation files.

If a .cab extension is specified, Setup treats the file as both a tag file and a cabinet file, as explained in the following Comments section.

unused
This is not used for Windows 2000 and later. This value is only used in Windows 9x/Me. See the Windows Me DDK documentation for further information.
path
This optional value specifies the path to the directory on the distribution disk containing source files. The path is relative to the installation root and is expressed as \dirname1\dirname2... and so forth. If this value is omitted from an entry, files are assumed to be in the installation root of the distribution disk.

You can use an INF SourceDisksFiles section to specify subdirectories, relative to a given path directory, that contain source files. However, tag files and cabinet files must reside either in the given path directory or in the installation root.

flags
For Windows XP and later, setting this to 0x10 forces Setup to use cab-or-tag-file as a cabinet file name, and to use tag-file as a tag file name. Otherwise, flags is for internal use only.
tag-file
For Windows XP and later, if flags is set to 0x10, this optional value specifies the name of a tag file supplied on the distribution medium, either in the installation root or in the subdirectory specified by path. The value should specify the file name and extension without path information.

Comments

A SourceDisksNames section can have any number of entries, one for each distribution disk. Any INF with a SourceDisksNames section also must have an INF SourceDisksFiles section. (By convention, SourceDisksNames and SourceDisksFiles sections follow the INF Version section.)

These sections never appear in system-supplied INF files. Instead, system-supplied INF files specify LayoutFile entries in their Version sections.

Entries in a SourceDisksNames section can have either of two formats. In the first format, the tag-or-cab-file parameter can specify either a tag file or a cabinet file. When encountering this format, Setup uses the following algorithm:

  1. Treat the tag-or-cab-file value as a tag file name and look for the file on the installation medium. If the medium is removable and the tag file is not found, prompt the user for the correct medium. If the medium is fixed and neither the tag file nor the first file to be installed can be found, prompt the user for the correct medium.
  2. Attempt to copy installation files directly from the medium.
  3. Treat the tag-or-cab-file value as a .cab file and look for the file.
  4. Attempt to copy installation files from the .cab file.
  5. Prompt the user for files not found.

For Windows XP and later, Setup also supports a second entry format, in which there can be separate entries for uniquely specifying a tag file and a .cab file. When encountering this format, Setup uses the following algorithm:

  1. If the installation medium is removable, look for a tag file that matches the file name specified by tag-file. If the file is not found, prompt the user for the correct medium. If the medium is fixed, look for either the tag file or the cabinet file. If neither file is found, prompt the user for the correct medium.
  2. Attempt to copy installation files from the .cab file specified by tag-or-cab-file.
  3. Prompt the user for files not found.

To support distribution of driver files on multiple system architectures, you can construct architecture-specific SourceDisksNames sections. During installation, Setup API functions look for architecture-specific SourceDisksNames sections before using the generic section. For example, if, during installation on an x86-based platform, an INF file references disk "2", Setup functions will look for an entry for disk "2" in SourceDisksNames.x86 before looking in SourceDisksNames.

Setup API functions use the SourceDisksNames and SourceDisksNames.architecture sections that are in the same INF file as the relevant INF SourceDisksFiles section.

Examples

In the following example, the write.exe file is the same for all Windows platforms and is located in the \common subdirectory, under the installation root, on a CD-ROM distribution disc. The cmd.exe file is a platform-specific file that is only used on x86-based platforms.

[SourceDisksNames]
1 = "Windows NT CD-ROM",file.tag,,\common

[SourceDisksNames.x86]
2 = "Windows NT CD-ROM",file.tag,,\x86

[SourceDisksFiles]
write.exe = 1
cmd.exe = 2

This next example again shows the SourceDisksNames section from the example in the reference for the INF Version section.

[SourceDisksNames]
;
; diskid = description[, [tagfile] [, <unused>, subdir]]
;
1 = %Floppy_Description%,,,\Win98
2 = %Floppy_Description%,,,\WinNT

The following example uses entries that contain separate specifications for .tag files and .cab files.

[Version]
signature = "$Windows NT$"
Provider = %Msft%

[SourceDisksNames]
1 = "Dajava","Dajava.cab",,,0x10,"Dajava.tag"
2 = "Osc","Osc.cab",,,0x10,"OSC.tag"
3 = "Win","Win.cab",,,0x10,"Win.tag"
4 = "XMLDSO","XMLDSO.cab",,,0x10,"XMLDSO.tag"

[SourceDisksFiles]
ArrayBvr.class=1
BvrCallback.class=1
BvrsToRun.class=1
choice.osc=2
custom.osc=2
login.osc=2
mwcload.exe=3
mwcloadw.exe=3
mwclw32.dll=3
Atom.class=4
DTD.class=4
Entity.class=4
Entry.class=4

[DestinationDirs]
Test = 16430,InfTest    ; %windir%\system32

[DefaultInstall]
CopyFiles = Test

[Test]
ArrayBvr.class
mwcloadw.exe
Entity.class
custom.osc
BvrCallback.class
BvrsToRun.class
choice.osc
login.osc
mwcload.exe
mwclw32.dll
Atom.class
DTD.class
Entry.class

[Strings]
Msft = "Microsoft"

See Also

DestinationDirs, SourceDisksFiles, Version


INF SourceDisksFiles Section

[SourceDisksFiles] |
[SourceDisksFiles.x86] |
[SourceDisksFiles.ia64]

filename = diskid[,[ subdir][, size]]
...

A SourceDisksFiles section names the source files used during installation, identifies the source disks (or CD-ROM discs) that contain those files, and provides the path to the subdirectories, if any, on the distribution disks containing individual files.

Entry Values

filename
Specifies the name of the file on the source disk.
diskid
Specifies the integer identifying the source disk that contains the file. This value and the initial path to the subdir(ectory), if any, containing the named file must be defined in a SourceDisksNames section of the same INF.
subdir
This optional value specifies the subdirectory (relative to the SourceDisksNames path specification, if any) on the source disk where the named file resides.

If this value is omitted from an entry, the named source file is assumed to be in the path directory that was specified in the SourceDisksNames section for the given disk or, if no path directory was specified, in the installation root.

size
This optional value specifies the uncompressed size, in bytes, of the given file.

Comments

A SourceDisksFiles section can have any number of entries, one for each file on the distribution disks. Any INF with a SourceDisksFiles section also must have an INF SourceDisksNames section. By convention, SourceDisksNames and SourceDisksFiles sections follow the Version section. (These sections are omitted from a system-supplied INF, which instead specifies a LayoutFile entry in its Version section.)

To support distribution of driver files for multiple system architectures, construct architecture-specific SourceDisksFiles sections. During installation, Setup API functions use both architecture-specific and generic SourceDisksFiles sections, but they look in the architecture-specific section before using the generic section. For example, if, during installation on an x86-based platform, Setup is copying a file named driver.sys, it will look for the file's description in SourceDisksNames.x86 before looking in SourceDisksNames.

Example

The following example shows a SourceDisksNames section and a corresponding SourceDisksFiles section.

[SourceDisksNames]
;
; diskid = description[, [tagfile] [, <unused>, subdir]]
;
1 = %Floppy_Description%,,,\Win98
2 = %Floppy_Description%,,,\WinNT
[SourceDisksFiles]
;
; filename_on_source = diskID[, [subdir][, size]]
;
aha154x.mpd = 1,, ; on distribution disk 1, in subdir \win9x

[SourceDisksFiles.x86]
aha154x.sys = 2,\x86 ; on distribution disk 2, in subdir \WinNT\x86

; ...

See Also

CopyFiles, DestinationDirs, RenFiles, SourceDisksNames, Version


INF ClassInstall32 Section

[ClassInstall32] |
[ClassInstall32.nt] |
[ClassInstall32.ntx86] |
[ClassInstall32.ntia64]

AddReg=add-registry-section[, add-registry-section] ...
[Copyfiles=@filename | file-list-section[, file-list-section] ...]
[DelReg=del-registry-section[, del-registry-section] ...]
[Delfiles=file-list section[, file-list-section] ...]
[Renfiles=file-list-section[, file-list-section] ...]
[BitReg=bit-registry-section[,bit-registry-section]...]
[UpdateInis=update-ini-section[,update-ini-section]...]
[UpdateIniFields=update-inifields-section[,update-inifields-section]...]
[Ini2Reg=ini-to-registry-section[,ini-to-registry-section]...]

A ClassInstall32 section installs a new device setup class (and possibly a class installer) for devices of the new type.

Valid Directives

AddReg=add-registry-section[, add-registry-section] ...
References one or more named sections containing class-specific value entries to be written into the registry. Typically, this is used to give the new device setup class at least a friendly name that other components can later retrieve from the registry and use to open installed devices of this new device class, to "install" any new device class installer and/or property-page provider for this device setup class, and so forth. An HKR specification in any add-registry-section designates the ..Class\{SetupClassGUID} registry key. For additional information, see the following Comments section.

For more information, see INF AddReg Directive.

Copyfiles=@filename | file-list-section[, file-list-section] ...
Either specifies one named file to be copied from the source media to the destination or references one or more named sections in which class-relevant files on the source media are specified for transfer to the destination. The DefaultDestDir entry in the DestinationDirs section of the INF specifies the destination directory for any class-specific single file to be copied.

System-supplied INF files for device setup classes (and class installers) do not use this directive in this section.

For more information, see INF CopyFiles Directive.

DelReg=del-registry-section[, del-registry-section] ...
References one or more named sections in which value entries or keys are specified to be removed from the registry during installation of the class installer.

However, if a particular {SetupClassGUID} subkey exists in the registry ..Class branch, the system setup code subsequently ignores the ClassInstall32 section of any INF that specifies the same GUID value in its Version section. Consequently, an INF cannot replace an existing class installer or modify its behavior from a ClassInstall32 section. To modify the behavior of existing class installer, use a class-specific co-installer.

For more information, see INF DelReg Directive.

Delfiles=file-list section[, file-list-section] ...
References one or more named sections in which previously installed class-relevant files on the destination are specified for deletion.

For more information, see INF DelFiles Directive.

Renfiles=file-list-section[, file-list-section] ...
References one or more named sections in which class-relevant files to be renamed on the destination are listed.

For more information, see INF RenFiles Directive.

BitReg=bit-registry-section[,bit-registry-section]...
Is valid in this section but almost never used.

For more information, see INF BitReg Directive.

UpdateInis=update-ini-section[,update-ini-section]...
Is valid in this section but almost never used.

For more information, see INF UpdateInis Directive.

UpdateIniFields=update-inifields-section[,update-inifields-section]...
Is valid in this section but almost never used.

For more information, see INF UpdateIniFields Directive.

Ini2Reg=ini-to-registry-section[,ini-to-registry-section]...
Is valid in this section but almost never used.

For more information, see INF UpdateIniFields Directive.

Comments

An INF for devices in a system-supplied device setup class should not specify a ClassInstall32 section. (You can provide class-specific or device-specific co-installers to supplement system-supplied class installers or the system's device installer. For more information, see Writing a Co-installer.)

Usually, a ClassInstall32 section will have one or more AddReg directives to add entries under a system-provided SetupClassGUID subkey in the registry. These entries can include a class-specific "friendly name," class installer path, class icon, property page provider, and so forth.

Except for AddReg and CopyFiles, the other directives shown here are very seldom used in a ClassInstall32 section.

The system processes the ClassInstall32 section of an INF for a new device setup class when a device is about to be installed but the SetupClassGUID value of that device's class is not predefined by the system. (See Device Setup Classes for a list of the system-defined setup class names and GUIDs.)

To support a multiplatform distribution of driver files, construct platform-specific ClassInstall32 sections. For example, all system setup API functions that process a ClassInstall32 section will search first for a ClassInstall32.ntx86 section on an NT-based x86 platform and only look at an undecorated ClassInstall32 section if they cannot find a ClassInstall32.ntx86 section.

Note that the ClassInstall32 section name is also used for installations on 64-bit platforms.

In the registry, every device installed on Windows 2000 and later platforms is associated with a device setup class. If the INF for a device to be installed is not associated with a new device class installer, or if its ClassGUID= specification in the Version section does not match a system-defined setup class GUID, that device's registry subkey is created under ..Class\{UnknownClassGUID}.

The INF for any device class installer typically has an AddReg directive in its ClassInstall32 section, to define at least one named section that creates a friendly name for its kind of device. The setup code automatically creates a SetupClassGUID subkey in the registry from the value supplied for the ClassGUID= entry in the INF's Version section when the first device of that (new) setup class is installed.

Under this SetupClassGUID subkey, such an INF also provides registry information for Models-specific subkeys, using additional AddReg directives in its per-manufacturer, per-models DDInstall sections. In addition, the INF can use the add-registry sections referenced in its ClassInstall32 section to specify a property-page provider and to exert control over how its class of devices is handled in the user interface.

Such a class-specific add-registry section has the following general form:

[SetupClassAddReg]

HKR,,,,%DevClassName% ; device-class friendly name
[HKR,,Installer32,,"class-installer.dll,class-entry-point"]
[HKR,,EnumPropPages32,,"prop-provider.dll,provider-entry-point"]
HKR,,Icon,,"icon-number"
[HKR,,SilentInstall,,1]
[HKR,,NoInstallClass,,1]
[HKR,,NoDisplayClass,,1]

The system uses the specified icon to represent your installer to the user.

  • If the Icon value is positive, it represents a resource identifier for a resource. The resource will be extracted from the class installer DLL, if the Installer32 key is specified, or from the property page DLL, if the EnumPropPages32 key is specified. The value "0" represents the first icon in the DLL. The value "1" is reserved.
  • If the Icon value is negative, the absolute value represents a predefined icon. See SetupDiDrawMiniIcon for a list of the predefined icons. For example, "-18" specifies the "Unknown" icon (18).

Setting the predefined SilentInstall, NoDisplayClass, and NoInstallClass Boolean value entries in a class-specific registry key has the following effects:

  • Setting SilentInstall directs installers to send no pop-ups to the user that require a response while installing devices of this class, whether specified in the DDInstall sections of the class installer's INF file or in separate INF files for subsequently installed devices that declare themselves of this class by setting the same ClassGuid={ClassGUID} specification in their respective Version sections. For example, the system class installers of CD-ROM and disk devices and the system parallel port class installer set SilentInstall in their respective registry keys.

    If a class-specific installer requires the machine to be rebooted for any device that it installs, the class-specific add-registry section in its INF cannot have this value entry.

  • Setting NoDisplayClass suppresses the user-visible display of all devices of this class by the Device Manager. For example, the system class installers for printers and for network drivers (including clients, services, and protocols) set NoDisplayClass in their respective registry keys.
  • Setting NoInstallClass indicates that no device of this type will ever require manual installation by an end user. For example, the system class installers for exclusively PnP devices set NoInstallClass in their respective registry keys.

A ClassInstall32 section can contain AddReg directives to set the DeviceType, DeviceCharacteristics, and Security for devices of its setup class. See the INF AddReg Directive for more information.

Examples

This example shows the ClassInstall32 section, along with the named section it references with the AddReg directive, of the INF for the system display class installer.

[ClassInstall32]
AddReg=display_class_addreg

[display_class_addreg]
HKR,,,,%DisplayClassName%
HKR,,Installer32,,"Desk.Cpl,DisplayClassInstaller"
HKR,,Icon,,"-1"

By contrast, this example shows the add-registry section referenced in the system CD-ROM INF's ClassInstall32 section. It sets up a class-specific property-page provider for the CD-ROM devices/drivers that it installs. This INF also sets the SilentInstall and NoInstallClass value entries in the CD-ROM class key to TRUE (1).

[cdrom_class_addreg]
HKR,,,,%CDClassName%
HKR,,EnumPropPages32,,"SysSetup.Dll,CdromPropPageProvider"
HKR,,SilentInstall,,1
HKR,,NoInstallClass,,1
HKR,,Icon,,"101"

See Also

AddReg, BitReg, CopyFiles, DDInstall, DelFiles, DelReg, Ini2Reg, Models, RenFiles, SetupDiBuildClassInfoListEx, UpdateIniFields, UpdateInis, Version


INF ClassInstall32.Services Section

[ClassInstall32.Services] |
[ClassInstall32.nt.Services] |
[ClassInstall32.ntx86.Services] |
[ClassInstall32.ntia64.Services]

AddService=ServiceName,[flags],service-install-section[,
event-log-install-section[,[EventLogType][,EventName]]]...
[DelService=ServiceName[,[flags][,[EventLogType][,EventName]]]...
[Include=filename.inf[,filename2.inf]...]
[Needs=inf-section-name[,inf-section-name]...]

Each ClassInstall32.Services section contains one or more AddService directives referencing additional INF-writer-defined sections in a Windows 2000 or later INF file.

INF files commonly use the ClassInstall32.Services section with at least one AddService directive to control how and when the services of a particular device class are loaded, any dependencies it might have on other services, and so forth. Optionally, they set up event-logging services for the device class as well.

ClassInstall32.Services sections should have the same platform and OS decorations as their related ClassInstall32 sections. For example, a ClassInstall32.ntx86 section would have a corresponding ClassInstall32.ntx86.Services section.

This section is irrelevant to exclusively Windows 9x/Me installations.

Directives and Entries

AddService=ServiceName,[flags],service-install-section[,
event-log-install-section[,[EventLogType][,EventName]]]...
This directive references an INF-writer-defined service-install-section and, possibly, an event-log-install-section elsewhere in the INF file for the drivers of the device class covered by the ClassInstall32 section. For more information, see INF AddService Directive.
DelService=ServiceName[,[flags][,[EventLogType][,EventName]]]...
This directive removes a previously installed service from the target machine. This directive is very rarely used. For more information, see INF DelService Directive.
Include=filename.inf[,filename2.inf]...
This optional entry specifies one or more additional system-suppliednamed INF files containing sections needed to install this device class. If this entry is specified, usually so is a Needs entry. (For further information on the Include entry and restrictions on its use, see Specifying the Source and Target Locations for Device Files).
Needs=inf-section-name[,inf-section-name]...
This optional entry specifies the particular named section that must be processed during the installation of this device class. Typically, such a named section is an ClassInstall32.Services section within a system-supplied INF file listed in an Include entry. However, it can be any section that is referenced within such a ClassInstall32.Services section.

Needs entries cannot be nested. (For further information on the Needs entry and restrictions on its use, see Specifying the Source and Target Locations for Device Files).

Comments

The case-insensitive .nt, .ntx86, and .ntia64 extensions can be inserted into a ClassInstall32.Services section name in dual-OS and/or cross-platform INF files, as shown in the formal syntax statement. For more information, see Creating an INF File.

See Also

ClassInstall32, AddService, DDInstall, DDInstall.HW, DelService, Models


INF DestinationDirs Section

[DestinationDirs]

[DefaultDestDir=dirid[,subdir]]
[file-list-section=dirid[,subdir]] ...

A DestinationDirs section specifies the target destination directory or directories for all copy, delete, and/or rename operations on files referenced by name elsewhere in the INF file.

This section is required in any INF that uses a CopyFiles directive or that references a file-list-section, whether with a CopyFiles, DelFiles, or RenFiles directive.

Entry Values

DefaultDestDir=dirid[,subdir]]
Specifies the default destination directory for all copy, delete, and/or rename operations on files that are not explicitly listed in a file-list-section referenced by other entries here.
file-list-section
Specifies the INF-writer-determined name of a section referenced by a CopyFiles, RenFiles, or DelFiles directive elsewhere in the INF file. Such an entry is optional if this section has a DefaultDestDir entry and all copy-file operations specified in this INF have the same target destination. However, any file-list-section referenced by a RenFiles or DelFiles directive elsewhere in the INF must be listed here.
dirid
Specifies the directory identifier of the target directory for operations on files that are referenced by name, possibly within a named file-list-section of the INF. This can be one of the following numerical values, which are shown here with the values most commonly specified by device/driver INF files toward the top of this list:
Value | Destination Directory
01 | SourceDrive:\pathname (the directory from which the INF file was installed)
10 Windows directory
This is equivalent to %windir%.
11 System directory
This is equivalent to %windir%\system32 for NT-based systems and to %windir%\system for Windows 9x/Me.
12 Drivers directory
This is equivalent to %windir%\system32\drivers on NT-based platforms and to %windir%\system\IoSubsys on Windows 9x/Me platforms.
17 | INF file directory
18 | Help directory
20 | Fonts directory
21 | Viewers directory
23 | Color (ICM) (not used for installing printer drivers)
24 Applications directory
This is the directory into which Windows and application files are installed.
25 | Shared directory
30 | Root directory of the boot drive, a.k.a. "ARC system partition" for NT-based systems (This might or might not be the same directory as the one represented by DIRID 24.)
50 | %windir%\system directory (NT-based systems only)
51 | Spool directory (not used for installing printer drivers – see Printer DIRIDs)
52 | Spool drivers directory (not used for installing printer drivers)
53 | User Profile directory
54 | Directory where ntldr.exe and osloader.exe are located (NT-based systems only)
55 | Print processors directory (not used for installing printer drivers)
-1 | Absolute path

The following dirid values are for commonly used shell "special folders":
Value | Shell Special Folder
16406 | All Users\Start Menu
16407 | All Users\Start Menu\Programs
16408 | All Users\Start Menu\Programs\Startup
16409 | All Users\Desktop
16415 | All Users\Favorites
16419 | All Users\Application Data
16422 | Program Files
16427 | Program Files\Common
16429 | All Users\Templates
16430 | All Users\Documents

Besides the values listed above that are defined in setupapi.h, you can use any of the CSIDL_Xxx values defined in shlobj.h. To define a dirid value for a folder not listed above, add 16384 (0x4000) to the CSIDL_Xxx value. For more information on CSIDL_Xxx values, see the Platform SDK documentation.

subdir
Specifies the subdirectory (and the rest of its path, if any, under the directory identified by dirid) to be the destination of the file operations in the given file-list-section.

Comments

The optional DefaultDestDir entry provides a default destination for copy, rename, and delete file operations that appear elsewhere in the INF file:

  • CopyFiles directives that use the direct copy (@filename) notation must have a DefaultDestDir entry in the DestinationDirs section of the INF in which the direct-copy entry appears.
  • CopyFiles, RenFiles, or DelFiles sections that are not directly referenced in the DestinationDirs section must have a DefaultDestDir entry in the DestinationDirs section of the INF in which the copy/rename/delete files sections appear.

Because all WDM drivers must be installed in the %windir%\system32\drivers directory, their dual-OS INF files must specify the dirid value 10 with an explicit subdir path as system32\drivers either as the DefaultDestDir entry, if any, or in the given file-list-section(s) (referenced elsewhere in the INF with the CopyFiles directive) that list the WDM driver images to be copied to the target.

Examples

This example sets the default target directory for all copy-file, delete-file, and rename-file operations. Such a simple DestinationDirs section is common to INF files for new peripheral devices, because such an INF usually just copies a set of source files into a single directory on the target machine.

[DestinationDirs]
DefaultDestDir = 12 ; dirid = \Drivers on WinNT platforms

This example shows a fragment of the DestinationDirs section of the INF for display/video drivers.

[DestinationDirs]
DefaultDestDir     = 11 ; dirid = \system32 on WinNT platforms

; ...

; list of per-Manufacturer, per-Models, per-DDInstall-section, and
; CopyFiles-referenced xxx.Miniport/xxx.Display sections omitted here
; along with several other miniport/display paired drivers
; ...
vga.Miniport     = 12
vga.Display      = 11
xga.Miniport     = 12
xga.Display      = 11

; all video miniports copied into \system32\drivers on WinNT platforms
; all paired display drivers copied into \system32

See Also

ClassInstall32, CopyFiles, DDInstall, DelFiles, RenFiles, SourceDisksFiles, SourceDisksNames, Version


INF ControlFlags Section

[ControlFlags]

ExcludeFromSelect=* |
ExcludeFromSelect=device-identification-string[,device-identification-string] ...
[ExcludeFromSelect.nt=device-identification-string[,device-identification-string] ...]
[ExcludeFromSelect.ntx86=device-identification-string[,device-identification-string] ...]
[ExcludeFromSelect.ntia64=device-identification-string[,device-identification-string] ...]
[CopyFilesOnly=device-identification-string[,device-identification-string] ...]
[InteractiveInstall=device-identification-string[,device-identification-string] ... ]

A ControlFlags section identifies devices for which Setup should take certain unique actions during installation.

Entries and Values

device-identification-string
Identifies a hardware ID or compatible ID that has been specified in a per-manufacturer INF Models section. Each string must be separated from the next with a comma (,).
ExcludeFromSelect
Removes all (if * is specified) or the specified list of devices from certain user interface displays, from which a user is expected to select a particular device for installation.

For the NT-based operating system, the specified devices will not be displayed by the Add Hardware Wizard, but will be displayed by the Found New Hardware and Hardware Update wizards.

For Windows 9x/Me, the specified devices will not be displayed by any device selection wizard.

To exclude a set of OS-incompatible or platform-incompatible devices from this display, one or more ExcludeFromSelect entries can have the following case-insensitive extensions appended:

.nt
Do not display these devices on computers running Windows 2000 or later.
.ntx86
Do not display these devices on x86-based computers running Windows 2000 or later.
.ntia64
Do not display these devices on IA-64-based computers running Windows XP or later.
CopyFilesOnly
Installs only the INF-specified files for the given devices because the device hardware is not accessible or available yet. This entry is rarely used. However, it can be used to preinstall the drivers of a device for which the card will later be seated in a particular slot that is currently in use. For example, if a device currently seated in the particular slot is necessary to transfer INF-specified files to the target, the INF would have this entry.
InteractiveInstall
Forces the specified list of devices to be installed in a user's context. Each line can specify one or more hardware IDs or compatible IDs and there can be one or more lines.

This entry is optional. The preferred way to install devices is to omit this entry and allow Setup to install the device in the context of a trusted system thread, if possible. However, if a device absolutely requires a user to be logged in when the device is installed, include this entry in the device INF. This entry is not supported on Windows 9x systems.

Comments

Typically, a ControlFlags section has one or more ExcludeFromSelect entries to identify devices that are listed in the per-manufacturer INF Models section, but which should not be displayed to the end user as options during manual installations.

The system's Add Hardware wizard builds a list of installable devices by searching through all available INF files. It extracts information about models/devices from each of these INF files and displays this information to the end user, unless an INF overrides this behavior by suppressing the display of one or more models/devices in that INF's ControlFlags section.

Listing a device's hardware ID or compatible ID in an ExcludeFromSelect entry removes it from the display shown to the end user. Specifying * (an asterisk) for the ExcludeFromSelect value removes all devices/models defined in the INF file from this user-visible list.

An INF writer should use the InteractiveInstall sparingly and only in the following situations:

  • To install drivers for devices that have corrupted or otherwise incorrectly defined hardware IDs. For example, when two or more different devices share the same Hardware ID. This case is strictly forbidden by the Plug and Play standard, but some hardware vendors have made this error in hardware.
  • To install drivers for devices that require their own driver and absolutely cannot use the generic class driver or another driver supplied with the operating system. The InteractiveInstall directive forces the Device Manager to ask the user for confirmation for compatible ID matches.

INF files that install exclusively PnP devices can have a ControlFlags section unless they set the NoInstallClass value entry in their respective SetupClassGUID registry keys to TRUE, as described in the reference for the INF ClassInstall32 section.

In the future, WHQL might not grant the Windows Logo to devices whose INF files include InteractiveInstall entries.

Example

This example of the ControlFlags section in the system mouse class installer INF suppresses the display of devices/models that cannot be installed on NT-based x86 platforms. (Some relevant fragments of the same INF were already shown in the introduction to this chapter.)

[ControlFlags]
; Exclude all bus mice and InPort mice for x86 platforms
ExcludeFromSelect.ntx86=*PNP0F0D,*PNP0F11,*PNP0F00,*PNP0F02,*PNP0F15
; Hide this entry always
ExcludeFromSelect=UNKNOWN_MOUSE

The following INF file fragment shows two devices: one that is fully PnP-capable and requires no user intervention during installation and another that requires its own driver and cannot use any other driver. Specifying InteractiveInstall for the second device forces Setup to install this device in a user's context (a user with administrative rights), including prompting the user for the location of the driver files (INF file, driver file, and so on) as required.

; ...
[Manufacturer]
%Mfg% = ModelsSection

[ModelsSection]
; Models section, with two entries
%Device1.DeviceDesc% = Device1.Install, \
  PCI\VEN_1000&DEV_0001&SUBSYS_00000000&REV_01
%Device2.Device.Desc%    = Device2.Install, \
  PCI\VEN_1000&DEV_0001&SUBSYS_00000000&REV_02

[ControlFlags]
InteractiveInstall = \
  PCI\VEN_1000&DEV_0001&SUBSYS_00000000&REV_02
; ...

See Also

ClassInstall32, Manufacturer, Models


INF Manufacturer Section

[Manufacturer]
manufacturer-identifier
[manufacturer-identifier]
[manufacturer-identifier]
...

The Manufacturer section identifies the manufacturer of one or more devices that can be installed using the INF file.

Entries and Values

manufacturer-identifier
Uniquely identifies a manufacturer and an INF section containing information that identifies a manufacturer's device models. Each manufacturer-identifier entry must exist on a separate line and use the following format:

manufacturer-name |
%strkey%=models-section-name |
%strkey%=models-section-name [,TargetOSVersion] [,TargetOSVersion] ... (Windows XP and later)

These entries are defined as follows:

manufacturer-name
Identifies the devices' manufacturer. The INF must also contain a corresponding INF Models section of the same name. (An entry specified in this manner cannot be localized.)
strkey
Specifies a token, unique within the INF, representing the name of a manufacturer. Each such %strkey% token must be defined in a Strings section of the INF file.
models-section-name
Specifies an INF-writer-defined name for the per-manufacturer INF Models section within the INF file. This value must be unique within the INF and must follow the same general rules for defining section names already described in General Syntax Rules for INF Files.
TargetOSVersion
For Windows XP and later OS versions, this specifies one or more operating system versions with which the specified INF Models section can be used. For a description of this decoration, see the following Comments section.

Comments

Any INF that installs one or more devices must have a Manufacturer section. An IHV/OEM-supplied INF typically specifies only a single entry in this section. If multiple entries are specified, each entry must be on a separate line of the INF.

Using a %strkey%=models-section-name entry simplifies the localization of the INF for the international market, as described in Creating International INF Files and the reference page for the INF Strings section.

If an INF file specifies one or more entries in the manufacturer-name format, each such entry implicitly specifies the name of the corresponding Models section elsewhere in the INF.

The Manufacturer section of a system-supplied INF for a device setup class is sometimes called a "Table of Contents", because this section sets up the installation of every manufacturer's device models of the class. Each entry in an INF's Manufacturer section specifies both an easily localizable %strkey% token for the name of a manufacturer and a unique-to-the-INF per-manufacturer Models section name.

For Windows XP and later versions of NT-based operating systems, entries in the Manufacturer section can be decorated to specify operating system versions. The specified versions indicate OS versions with which the specified INF Models sections will be used. If no versions are specified, Setup uses the specified Models section for all versions of all operating systems.

The format of TargetOSVersion, the version decoration, is as follows:

NT[Architecture][.[OSMajorVersion][.[OSMinorVersion][.[ProductType][.SuiteMask]]]]

Each field is defined as follows:

NT
Operating system version recognition is supported for Windows XP and later NT-based operating systems.
Architecture
Identifies the hardware platform. This must be x86 or ia64.
OSMajorVersion
A number representing the operating system's major version number. For Windows XP, this number is 5.
OSMinorVersion
A number representing the operating system's minor version number. For Windows XP, this number is 1.
ProductType
A number representing one of the VER_NT_xxxx flags defined in winnt.h, such as:

0x0000001 (VER_NT_WORKSTATION)
0x0000002 (VER_NT_DOMAIN_CONTROLLER)
0x0000003 (VER_NT_SERVER)

The INF will be used only if the operating system matches the specified product type. If the INF supports multiple product types for a single OS version, multiple TargetOSVersion entries are required.

SuiteMask
A number representing a combination of one or more of the VER_SUITE_xxxx flags defined in winnt.h. These flags include:

0x00000001 (VER_SUITE_SMALLBUSINESS)
0x00000002 (VER_SUITE_ENTERPRISE)
0x00000004 (VER_SUITE_BACKOFFICE)
0x00000008 (VER_SUITE_COMMUNICATIONS)
0x00000010 (VER_SUITE_TERMINAL)
0x00000020 (VER_SUITE_SMALLBUSINESS_RESTRICTED)
0x00000040 (VER_SUITE_EMBEDDEDNT)
0x00000080 (VER_SUITE_DATACENTER)
0x00000100 (VER_SUITE_SINGLEUSERTS)
0x00000200 (VER_SUITE_PERSONAL)
0x00000400 (VER_SUITE_SERVERAPPLIANCE)

The INF will be used only if the operating system matches all of the specified product suites. If the INF supports multiple product suite combinations for a single OS version, multiple TargetOSVersion entries are required.

If your INF contains Manufacturer section entries with decorations, it must also include Models sections with names that match the OS decorations. For example, if an INF contains the following Manufacturer section:

%FooCorp%=FooMfg, NT....0x80, NT

Then the INF must also contain Models sections with the following names:

[FooMfg.NT....0x08] (Valid for Windows XP and later, Data Center only)

[FooMfg.NT] (Valid for Windows XP and later, all product types and suites)

During installation, Setup will use the [FooMfg.NT....0x08] Models section if it is running on any NT-based operating system version (Windows XP or later) that includes the Data Center product suite. If Setup is running on any NT-based operating system version, Windows XP or later, that does not include the Data Center product suite, Setup will use the [FooMfg.NT] Models section.

If the INF is intended for use with NT-based OS versions earlier than Windows XP, or for use with Windows 98/Me operating systems, it must also contain an undecorated models section named [FooMfg].

If an INF supports multiple manufacturers, these rules must be followed for each manufacturer.

Following are additional examples of TargetOSVersion decorations:

"Foo Corp." = FooMfg, NTx86

For this example, the resultant Models section name is [FooMfg.NTx86], and is applicable for any x86 version of the NT-based operating system (Windows XP or later).

"Foo Corp." = FooMfg, NT.7.8

In this case, for version 7.8 and later of the NT-based OS, the resultant Models section name is [FooMfg.NT.7.8]. For earlier versions such as Windows XP, [FooMfg] is used.

Setup's selection of which Models section to use is based on the following rules:

  • If the INF contains Models sections for several major or minor OS version numbers, Setup uses the section with the highest version numbers that are not higher than the OS version on which the installation is taking place.
  • If the INF Models sections that match the OS version also include product type and/or product suite decorations, Setup selects the section that most closely matches the running OS.

Suppose, for example, Setup is executing on Windows XP (version 5.1), without the Data Center product suite, and it finds the following entry in a Manufacturer section:

%FooCorp%=FooMfg, NT, NT.5, NT.5.5, NT....0x80

In this case, Setup will look for a Models section named [FooMfg.NT.5]. (Setup will also use the [FooMfg.NT.5] section if it is executing on a DataCenter version of Windows XP, because a specific version number takes precedence over the product type and suite mask.)

If you want in INF to explicitly exclude a specific OS version, product type, or suite, create an empty Models section. For example, an empty section named [FooMfg.NT.6.0] will prohibit installation on OS versions 6.0 and higher.

Examples

This example shows a Manufacturer section typical to an INF for a single IHV.

[Manufacturer]
%LogiMfg%=LogiMfg        ; Models section == LogiMfg

; ...
[Strings]
LogiMfg = "Logitech"

The next example shows part of a Manufacturer section typical to an INF for a device-class-specific installer:

[Manufacturer]
%ADP%=ADAPTEC
; several entries omitted here for brevity
%SONY%=SONY
%ULTRASTOR%=ULTRASTORE

The following example shows a Manufacturer section that is specific to x86 platforms, Windows XP and later:

[Manufacturer]
%foo%=foosec,NTx86.5.1

[foosec.NTx86.5.1]

The following two examples show skeletal INF files with a variety of OS-specific Models sections:

Example 1:

[Manufacturer]
%MyName% = MyName,NTx86.5.1
.
.
[MyName]
%MyDev% = InstallA,hwid
.
.
[MyName.NTx86.5.1]
%MyDev% = InstallB,hwid
.
.
.
[InstallA.ntx86]   ; Windows 2000 (NT4-x86 will also try
.                  ; to parse this section, no workaround)
.
.
[InstallA]         ; Win98/WinME (Win95 will also try
.                  ; to parse this section, no workaround)
.                  ; NT4-Alpha will also try to parse this section
.                  ; unless INF has an [InstallA.ntalpha] section.
.
.
[InstallB]         ; Windows XP and later, x86 only
.
.

Example 2:

[Manufacturer]
%MyName% = MyName,NT.6.0,NTx86.5.1
.
.
[MyName.NT.6.0]    ; Empty section, so this INF does not support
.                  ; NT 6.0 and later.
.
.
[MyName.NTx86.5.1] ; Used for NT 5.1 and later
.                  ; (but not NT 6.0 due to the NT.6.0 entry)
%MyDev% = InstallB,hwid
.
.
[MyName]           ; Empty section, so this INF does not support
.                  ; Win9x/NT4/Win2000
.
.

See Also

Models, Strings


INF Models Section

[models-section-name] |
[models-section-name.TargetOSVersion] (Windows XP and later)

device-description=install-section-name,hw-id[,compatible-id...]
[device-description=install-section-name,hw-id[,compatible-id]...] ...

A per-manufacturer Models section identifies at least one device, references the DDInstall section of the INF file for that device, and specifies a unique-to-the-INF hardware identifier for that device. Any entry in the per-manufacturer Models section also can specify one or more additional device IDs for models that are compatible with the device designated by the initial hardware ID and are controlled by the same drivers.

Each models-section-name must be listed in the INF Manufacturer section of the INF file. There can be one or more entries in any per-manufacturer Models section, depending upon how many devices (and drivers) the INF file installs for a particular manufacturer. For Windows XP and later, a models section name can include a TargetOSVersion decoration. For more information, see INF Manufacturer Section.

Each entry in a Models section is sometimes called a driver node.

Entry Values

device-description
Identifies a device to be installed, expressed as any unique combination of visible characters or as a %strkey% token defined in an INF Strings section.
install-section-name
Specifies the undecorated name of the INF install sections to be used for the device (and compatible models of device, if any). For more information, see INF DDInstall section.
hw-id
Specifies a vendor-defined hardware ID string that identifies a device, which the PnP Manager uses to find an INF-file match for this device. Such a hardware ID has one of the following formats:
enumerator\enumerator-specific-device-id
Is the typical format for individual PnP devices reported to the PnP Manager by a single enumerator. For example, USB\VID_045E&PID_00B identifies the Microsoft HID keyboard device on a USB bus. Depending on the enumerator, such a specification can even include the device's hardware revision number as, for example, PCI\VEN_1011&DEV_002&SUBSYS_00000000&REV_02.
*enumerator-specific-device-id
Indicates with the asterisk (*) that the device is supported by more than one enumerator. For example, *PNP0F01 identifies the Microsoft serial mouse, which also has a compatible-id specification of SERENUM\PNP0F01.
device-class-specific-ID
Is an I/O bus-specific format, as described in the hardware specification for the bus, for the hardware IDs of all peripheral devices on that type of I/O bus.

Note that a single device can have more than one hw-id value. The PnP Manager uses each such hw-id value, which is usually provided by the underlying bus when it enumerates its child devices, to create a subkey for each such device in the registry ..Enum branch. For manually installed devices, the system's setup code uses their hw-id values as specified in their respective INF files to create each such registry subkey.

compatible-id
Specifies a vendor-defined compatible ID string identifying compatible devices. Any number of compatible-id values can be specified for an entry in the Models section, each separated from the next by a comma (,). All such compatible devices and/or device models are controlled by the same driver as the device designated by the initial hw-id.

Comments

Each install-section-name must be unique within the INF and must follow the general rules for defining section names, described in General Syntax Rules for INF Files. The DDInstall section name referenced in a per-manufacturer Models section also can have extensions appended to the given install-section-name, thus defining additional DDInstall sections for the OS-specific or platform-specific installation of the given devices. For more information about using extensions in cross-platform and dual-OS files, see also Creating an INF File.

Any specified hw-id or compatible-id value can also be specified in the INF ControlFlags section to prevent that device from being displayed to the end user by the Add Hardware Wizard during manual installations. For more information about hw-id and compatible-id values, see Device Identification Strings.

For each device and driver installed using an INF file, the device installers use the information supplied in the INF Manufacturer section and per-manufacturer Models sections to generate Device Description, Manufacturer Name, Device ID if the installation is manual, and, possibly, Compatibility List value entries in the registry.

Example

This example shows a per-manufacturer Models section with some representative entries from the system mouse class installer's INF file, defining the DDInstall sections for some devices/models.

[Manufacturer]
%StdMfg%    =StdMfg         ; (Standard types)
%MSMfg%     =MSMfg          ; Microsoft
; ... %otherMfg% omitted here

[StdMfg]  ; per-Manufacturer Models section
  ; Std serial mouse
%*pnp0f0c.DeviceDesc%= Ser_Inst,*PNP0F0C,SERENUM\PNP0F0C,SERIAL_MOUSE
  ; Std InPort mouse
%*pnp0f0d.DeviceDesc%      = Inp_Inst,*PNP0F0D
; ... more StdMfg entries

See Also

ControlFlags, DDInstall, Manufacturer, Strings


INF DDInstall Section

[install-section-name] |
[install-section-name.nt] |
[install-section-name.ntx86] |
[install-section-name.ntia64]

[DriverVer=mm/dd/yyyy[,x.y.v.z] ]
[CopyFiles=@filename | file-list-section[,file-list-section] ...]
[CopyINF=filename1.inf[,filename2.inf]...]
[AddReg=add-registry-section[,add-registry-section]...]
[Include=filename1.inf[,filename2.inf]...]
[Needs=inf-section-name[,inf-section-name]...]
[Delfiles=file-list-section[,file-list-section]...]
[Renfiles=file-list-section[,file-list-section]...]
[DelReg=del-registry-section[,del-registry-section]...]
[BitReg=bit-registry-section[,bit-registry-section]...]
[LogConfig=log-config-section[,log-config-section]...]
[ProfileItems=profile-items-section[,profile-items-section]...]
[UpdateInis=update-ini-section[,update-ini-section]...]
[UpdateIniFields=update-inifields-section[,update-inifields-section]...]
[Ini2Reg=ini-to-registry-section[,ini-to-registry-section]...]
[Ini2Reg=ini-to-registry-section[,ini-to-registry-section]...]
[RegisterDlls=register-dll-section[,register-dll-section]...]
[UnregisterDlls=unregister-dll-section[,unregister-dll-section]...]
[ExcludeID=device-identification-string[,device-identification-string]...] ...

Each per-Models DDInstall section contains an optional DriverVer directive and one or more directives referencing additional named sections in the INF file, shown here with the most commonly specified INF directives, CopyFiles and AddReg, listed first. The sections referenced by these directives contain instructions for installing driver files and writing any device-specific and/or driver-specific information into the registry.

Directives and Entries

DriverVer=mm/dd/yyyy[,x.y.v.z]
This optional entry specifies version information for the driver package.

For information about how to specify this entry, see INF DriverVer Directive.

CopyFiles=@filename | file-list-section[,file-list-section] ...
This directive either specifies one named file to be copied from the source media to the destination or references one or more INF-writer-defined sections in which device-relevant files on the source media are specified for transfer to the destination. The CopyFiles directive is optional, but is present in most DDInstall sections.

The DefaultDestDir entry in the DestinationDirs section of the INF specifies the destination for any single file to be copied. The SourceDisksNames and SourceDisksFiles sections, or an additional INF specified in the LayoutFile entry of this INF's Version section, provides the location on the distribution media of the driver files.

For more information, see INF CopyFiles Directive.

CopyINF=filename1.inf[,filename2.inf]...]
(Windows XP and later.) This directive causes specified INF files to be copied to the target system.

For more information, see INF CopyINF Directive.

AddReg=add-registry-section[,add-registry-section]...
This directive references one or more INF-writer-defined sections in which new subkeys, possibly with initial value entries, are specified to be written into the registry or in which the value entries of existing keys are modified.

An HKR specification in such an add-registry section designates the ..Class\SetupClassGUID\device-instance-id registry path to the user-accessible driver (a.k.a. "software" key).

For more information, see INF AddReg Directive.

Include=filename.inf[,filename2.inf]...
This optional entry specifies one or more additional system-supplied INF files containing sections needed to install this device and/or driver. If this entry is specified, usually so is a Needs entry.

For example, the system INF files for device drivers that depend on the system's kernel-streaming support specify this entry as
Include= ks.inf[, [kscaptur.inf,] [ksfilter.inf]].

(For further information on the Include entry and restrictions on its use, see Specifying the Source and Target Locations for Device Files).

Needs=inf-section-name[,inf-section-name]...
This optional entry specifies sections within system-supplied INF files that must be processed during the installation of this device. Typically, such a named section is a DDInstall (or DDInstall.xxx) section within one of the INF files listed in an Include entry. However, it can be any section that is referenced within such a DDInstall or DDInstall.xxx section of the included INF.

For example, the INF files for device drivers that have the preceding Include entry specify this entry as
Needs= KS.Registration[, KSCAPTUR.Registration |
KSCAPTUR.Registration.NT, MSPCLOCK.Installation]

Needs entries cannot be nested. (For further information on the Needs entry and restrictions on its use, see Specifying the Source and Target Locations for Device Files).

DelFiles=file-list-section[,file-list-section]...
This directive references one or more INF-writer-defined sections listing files on the target to be deleted.

For more information, see INF DelFiles Directive.

RenFiles=file-list-section[,file-list-section]...
This directive references one or more INF-writer-defined sections listing files to be renamed on the destination before device-relevant source files are copied to the target machine.

For more information, see INF RenFiles Directive.

DelReg=del-registry-section[,del-registry-section]...
This directive references one or more INF-writer-defined sections in which keys and/or value entries are specified to be removed from the registry during installation of the devices.

Typically, this directive is used to handle upgrades when an INF must clean up old registry entries from a previous installation of this device. An HKR specification in such a delete-registry section designates the ..Class\SetupClassGUID\device-instance-id registry path to the user-accessible driver (a.k.a. "software" key).

For more information, see INF DelReg Directive.

BitReg=bit-registry-section[,bit-registry-section]...
This directive references one or more INF-writer-defined sections in which existing registry value entries of type REG_BINARY are modified. (See also AddReg.) An HKR specification in such a bit-registry section designates the ..Class\SetupClassGUID\device-instance-id registry path to the user-accessible driver (a.k.a. "software" key).

For more information, see INF BitReg Directive.

LogConfig=log-config-section[,log-config-section]...
This directive references one or more INF-writer-defined sections within an INF for a root-enumerated device or for a manually installed device. In these named sections, the INF for such a "detected" or manually installed device specifies one or more logical configurations of bus-relative hardware resources that the device must have to be operational. The INF for such a manually installed device that is not software-configurable also should have a DDInstall.FactDef section.

The LogConfig directive is never used to install PnP devices. However, you can use an INF DDInstall.ConfigOverride section to provide an override configuration for PnP devices.

This directive is irrelevant to all higher level (nondevice) drivers and components.

For more information, see INF LogConfig Directive.

ProfileItems=profile-items-section[,profile-items-section]...
This directive references one or more INF-writer-defined sections that describe items to be added to, or removed from, the Start menu.

This directive is only supported on Windows 2000 and later platforms.

For more information, see INF ProfileItems Directive.

UpdateInis=update-ini-section[,update-ini-section]...
This rarely used directive references one or more INF-writer-defined sections, specifying a source INI file from which a particular section or line within such a section is to be read into a destination INI file of the same name during installation. Optionally, line-by-line modifications to an existing INI file on the destination from a given source INI file of the same name can be specified in the update-ini section.

For more information, see INF UpdateInis Directive.

UpdateIniFields=update-inifields-section[,update-inifields-section]...
This rarely used directive references one or more INF-writer-defined sections in which modifications within the lines of a device-specific INI file are specified.

For more information, see INF UpdateIniFields Directive.

Ini2Reg=ini-to-registry-section[,ini-to-registry-section]...
This rarely used directive references one or more INF-writer-defined sections in which sections or lines from a device-specific INI file, supplied on the source media, are to be moved into the registry.

For more information, see INF Ini2Reg Directive.

RegisterDlls=register-dll-section[,register-dll-section]...
This directive references one or more INF sections used to specify files that are OLE controls and require self-registration.

For more information, see INF RegisterDlls Directive.

UnregisterDlls=unregister-dll-section[,unregister-dll-section]...
This directive references one or more INF sections used to specify files that are OLE controls and require self-unregistration (self-removal).

For more information, see INF UnregisterDlls Directive.

[ExcludeID=device-identification-string[,device-identification-string]...
(Windows XP and later.) This directive specifies one or more device identification strings (either hardware IDs or compatible IDs). The DDInstall section will not install devices having device IDs that match any of the hardware IDs or compatible IDs listed.

Comments

Throughout DDK documentation, the term DDInstall is used to refer to an install-section-name, with or without platform extensions. Thus, "DDInstall section" means "a named section within an INF, having the format [install-section-name] or [install-section-name.nt xxx]". When you create names for DDInstall sections, you should include a device-specific prefix, such as [WDMPNPB003_Device] or [GPR400.Install.NT].

Each DDInstall section must be referenced in a device/models-specific entry under the per-manufacturer INF Models section of the INF file.

Except for devices that have no associated files to be transferred from the source media, a dual-OS INF file for a WDM driver must have at least two parallel DDInstall sections for a given device, as follows:

  1. For Windows 9x platforms, provide an undecorated DDInstall section that specifies entries for device installations. There is no DDInstall.Services section in such a dual-OS INF file, because Windows 9x/Me does not store the same information about device/driver services and dependencies in its registry as Windows 2000 and later does. Depending on the device, it can also have either or both of the optional DDInstall.HW and DDInstall.Interfaces sections to install the device/driver on Windows 9x/Me platforms. (It might also have an INF DDInstall.LogConfigOverride section.)
  2. For Windows 2000 and later:
    • Provide a install-section-name.ntx86 section that specifies the entries for device/driver installations specific to x86-based platforms.
    • Provide a install-section-name.ntia64 section that specifies the entries for device/driver installations specific to ia64-based platforms.
    • Provide a install-section-name.nt section that specifies the entries for device/driver installations that are not specific to a particular hardware platform.

    If the INF installs drivers, it must have DDInstall.Services sections to specify device/driver registry information to be stored in the registry's ...\CurrentControlSet\Services tree. Depending on the device, it can also have one or more DDInstall.HW, DDInstall.CoInstallers, DDInstall.Interfaces, and/or DDInstall.LogConfigOverride sections.

For more information about how to use the system-defined .nt, .ntx86, and .ntia64 extensions in cross-platform and dual-OS INF files, see also Creating an INF File.

Each directive in a DDInstall section can reference more than one section name, but each additional named section must be separated from the next with a comma (,). Each such section name must be unique within the INF and must follow the same general rules for defining section names already described in General Syntax Rules for INF Files.

Any AddReg directive specified in a DDInstall section is assumed to reference an add-registry section that cannot be used to store information about upper or lower filter drivers, about multifunction devices, or about driver-independent but device-specific parameters. If a device/driver INF must store this type of information in the registry, it must use an AddReg directive in its undecorated and decorated DDInstall.HW sections, if any, to reference another INF-writer-defined add-registry-section.

A DDInstall section can include a directive named Reboot or Restart. These directives are only for compatibility with Windows 9x. If one of these entries is present the OS is forced to reboot when the device is installed. These directives should never be used for PnP devices. In any case, it is best to let Setup determine whether the machine needs to be rebooted rather than specifying these directives.

Examples

This example shows the expansion of the DDInstall sections, Ser_Inst and Inp_Inst These sections are referenced in the example for the INF Models section.

[Ser_Inst]
CopyFiles=Ser_CopyFiles, mouclass_CopyFiles

[Ser_CopyFiles]
sermouse.sys

[mouclass_CopyFiles] ; section name referenced by > 1 CopyFiles
mouclass.sys

[Inp_Inst]
CopyFiles=Inp_CopyFiles, mouclass_CopyFiles

[Inp_CopyFiles]
inport.sys

The following example provides a general illustration of using platform extensions

[Manufacturer]
%MSFT% = Microsoft

[Microsoft]
%Device.DeviceDesc% = DeviceInstall, HWID

[DeviceInstall.NTx86]
;
; This section is used for installations on NT-based x86 systems.
;
...

[DeviceInstall.NTx86.Services]
;
; Services installation for NT-based x86 systems.
;
...

[DeviceInstall.NT]
;
; This section is used for installations on NT-based systems (all other architectures).
;
...

[DeviceInstall.NT.Services]
;
; Services installation for NT-based systems (all other architectures).
;
...

[DeviceInstall]
;
; This section is used for installations on non-NT-based platforms (that is, Win9x/WinME).
;
...

This example shows the DDInstall section in a dual-OS INF file, for installation of a system-supplied WDM driver for an audio device, on an NT-based system. With the exception of the DriverVer directive, this section's entries are identical to the undecorated DDInstall section for installations of the same device on Windows 9x/Me platforms. However, this install-section-name.NT section is necessary in such a dual-OS INF file to set up the install-section-name.NT.Services section that is required to install the device and driver on Windows 2000 and later platforms.

[WDMPNPB003_Device.NT]
DriverVer=01/14/1999,5.0
Include=ks.inf, wdmaudio.inf
Needs=KS.Registration, WDMAUDIO.Registration.NT
LogConfig=SB16.LC1,SB16.LC2,SB16.LC3,SB16.LC4,SB16.LC5
; a few log-config-sections omitted here for brevity
CopyFiles=MSSB16.CopyList
AddReg=WDM_SB16.AddReg

The following shows the sections referenced by the preceding Needs entry in the system-supplied ks.inf and wdmaudio.inf files specified in the Include entry. When an NT-based system's device installer and/or media class installer process this device's install-section-name.NT section, these next two sections are also processed.

[KS.Registration]
; following AddReg= is actually a single line in the ks.inf file
AddReg=ProxyRegistration,CategoryRegistration,\
  TopologyNodeRegistration,PlugInRegistration,PinNameRegistration,\
  DeviceRegistration
CopyFiles=KSProxy.Files,KSDriver.Files

[WDMAUDIO.Registration.NT]
AddReg=WDM.AddReg
CopyFiles=WDM.CopyFiles.Sys, WDM.CopyFiles.Drv
;
; INF-writer-defined add-registry and file-list sections
; referenced by preceding directives are omitted here for brevity
;

See Also

INF DDInstall.CoInstallers Section
INF DDInstall.FactDef Section
INF DDInstall.HW Section
INF DDInstall.Interfaces Section
INF DDInstall.LogConfigOverride Section
INF DDInstall.Services Section
INF DefaultInstall Section
INF DefaultInstall.Services Section


INF DDInstall.Services Section

[install-section-name.Services] |
[install-section-name.nt.Services] |
[install-section-name.ntx86.Services]
[install-section-name.ntia64.Services]

AddService=ServiceName,[flags],service-install-section[,
event-log-install-section[,[EventLogType][,EventName]]]...
[DelService=ServiceName[,[flags][,[EventLogType][,EventName]]]...
[Include=filename.inf[,filename2.inf]...]
[Needs=inf-section-name[,inf-section-name]...]

Each per-Models DDInstall.Services section contains one or more INF AddService directives referencing additional INF-writer-defined sections in a Windows 2000 or later INF file.

Windows 2000 and later INF files commonly use the DDInstall.Services section with at least one AddService directive to control how and when the services of a particular driver are loaded, any dependencies on other services or on underlying (legacy) drivers it might have, and so forth. Optionally, they set up event-logging services by the device drivers as well.

DDInstall.Services sections should have the same platform and OS decorations as their related DDInstall sections. For example, a install-section-name.ntx86 section would have a corresponding install-section-name.ntx86.Services section.

This section is irrelevant to exclusively Windows 9x/Me installations.

Directives and Entries

AddService=ServiceName,[flags],service-install-section[,
event-log-install-section[,[EventLogType][,EventName]]]...
This directive references an INF-writer-defined service-install-section and, possibly, an event-log-install-section elsewhere in the INF file for the drivers of the devices covered by this DDInstall section. For more information, see INF AddService Directive.
DelService=ServiceName[,[flags][,[EventLogType][,EventName]]]...
This directive removes a previously installed service from the target machine. This directive is very rarely used. For more information, see INF DelService Directive.
Include=filename.inf[,filename2.inf]...
This optional entry specifies one or more additional system-supplied INF files containing sections needed to install this device. If this entry is specified, usually so is a Needs entry. (For further information on the Include entry and restrictions on its use, see Specifying the Source and Target Locations for Device Files.)
Needs=inf-section-name[,inf-section-name]...
This optional entry specifies the section that must be processed during the installation of this device. Typically, the section is a DDInstall.Services section within a system-supplied INF file listed in an Include entry. However, it can be any section that is referenced within a DDInstall.Services section.

Needs entries cannot be nested. (For further information on the Needs entry and restrictions on its use, see Specifying the Source and Target Locations for Device Files.)

Comments

The given DDInstall section must be referenced in a device/models-specific entry under the per-manufacturer Models section of the INF file. The case-insensitive extensions to the install-section-name shown in the formal syntax statement can be inserted into such a DDInstall.Services section name in dual-OS and/or cross-platform INF files. For more information about how to use the system-defined .nt, .ntx86, and .ntia64 extensions in cross-platform and dual-OS INF files, see also Creating an INF File.

Examples

This example shows the DDInstall.Services section for the Ser_Inst section shown as an example for the INF DDInstall section.

[Ser_Inst.Services]
AddService=sermouse, 0x00000002, sermouse_Service_Inst,\
                sermouse_EventLog_Inst
;
; flags value in preceding entry indicates function driver of device
;
AddService = mouclass,, mouclass_Service_Inst, mouclass_EventLog_Inst

; entries in the following xxx_Inst sections omitted here for brevity,
; but fully specified as the example for the AddService directive
;
[sermouse_Service_Inst]
; ...

[sermouse_EventLog_Inst]
; ...

[mouclass_Service_Inst]
; ...

[mouclass_EventLog_Inst]
; ...

This example shows the install-section-name.NT.Services section and its service-install-sections in the INF file for the system-supplied WDM audio device/driver shown as an example for the INF DDInstall section.

[WDMPNPB003_Device.NT.Services]
AddService = wdmaud,0x00000000,wdmaud_Service_Inst
AddService = swmidi,0x00000000,swmidi_Service_Inst
AddService = sb16,  0x00000002,sndblst_Service_Inst

[wdmaud_Service_Inst]
DisplayName   = %wdmaud.SvcDesc% ; friendly name (see Strings)
ServiceType   = 1                ; SERVICE_KERNEL_DRIVER
StartType     = 1                ; SERVICE_SYSTEM_START
ErrorControl  = 1                ; SERVICE_ERROR_NORMAL
ServiceBinary = %10%\system32\drivers\wdmaud.sys

[swmidi_Service_Inst]
DisplayName   = %swmidi.SvcDesc%
ServiceType   = 1
StartType     = 1
ErrorControl  = 1
ServiceBinary = %10%\system32\drivers\swmidi.sys

[sndblst_Service_Inst]
DisplayName   = %sndblst.SvcDesc%
ServiceType   = 1
StartType     = 1
ErrorControl  = 1
ServiceBinary = %10%\system32\drivers\mssb16.sys

[Strings] ; only immediately preceding %strkey% tokens shown here
%wdmaud.SvcDesc%="Microsoft WDM Virtual Wave Driver (WDM)"
%swmidi.SvcDesc%="Microsoft Software Synthesizer (WDM)"
%sndblst.SvcDesc%="WDM Sample Driver for SB16"

The reference for the INF DDInstall.HW section has more examples of DDInstall.Services sections with some service-install-sections referenced by the AddService directive, including one for a PnP filter driver.

See Also

AddService, DDInstall, DDInstall.HW, DelService, Models


INF DDInstall.HW Section

[install-section-name.HW] |
[install-section-name.nt.HW] |
[install-section-name.ntx86.HW]
[install-section-name.ntia64.HW]

[AddReg=add-registry-section[, add-registry-section]...] ...
[Include=filename.inf[,filename2.inf]...]
[Needs=inf-section-name[,inf-section-name]...]
[DelReg=del-registry-section[, del-registry-section]...] ...
[BitReg=bit-registry-section[,bit-registry-section] ...] ...

DDInstall.HW sections are typically used for installing multifunction devices, for installing PnP filter drivers, and for setting up any user-accessible device-specific but driver-independent information in the registry, whether with explicit AddReg directives or with Include and Needs entries.

Directives and Entries

AddReg=add-registry-section[, add-registry-section]...
References one or more INF-writer-defined add-registry-sections elsewhere in the INF file for the devices covered by this DDInstall.HW section. Such an add-registry section typically installs filters and/or stores per-device information in the registry. An HKR specification in such an add-registry section designates the ..Enum\enumeratorID\device-instance-id registry path to a user-accessible per-device (a.k.a. "hardware") subkey.
Include=filename.inf[,filename2.inf]...
Specifies one or more additional system-supplied INF files containing sections needed to install this device. If this entry is specified, usually so is a Needs entry. (For further information on the Include entry and restrictions on its use, see Specifying the Source and Target Locations for Device Files).
Needs=inf-section-name[,inf-section-name]...
Specifies the named sections that must be processed during the installation of this device. Typically, such a named section is a DDInstall.HW section within a system-supplied INF file listed in an Include entry. However, it can be any section that is referenced within such a DDInstall.HW section of the included INF.

Needs entries cannot be nested. (For further information on the Needs entry and restrictions on its use, see Specifying the Source and Target Locations for Device Files).

DelReg=del-registry-section[, del-registry-section]...
References one or more INF-writer-defined delete-registry-sections elsewhere in the INF file for the drivers of the devices covered by this DDInstall section. Such a delete-registry section removes stale registry information for a previously installed device/driver from the target machine. An HKR specification in such a delete-registry section designates the same subkey as for AddReg.

This directive is rarely used, except in an INF file that upgrades a previous installation of the same devices/models listed in the per-manufacturer per-Models section that defined the name of this DDInstall section.

BitReg=bit-registry-section[,bit-registry-section]...
Is valid in this section, but almost never used. An HKR specification in a referenced bit-registry section designates the same subkey as for AddReg.

Comments

The case-insensitive extensions to the install-section-name shown in the formal syntax statement can be inserted into such a DDInstall.HW section name in cross-platform and dual-OS INF files. For more information about how to use the system-defined .nt, .ntx86, and .ntia64 extensions in cross-platform and dual-OS INF files, see also Creating an INF File.

Any DDInstall.HW section either must have an AddReg directive or must Include another INF file and reference a section in the corresponding Needs entry that sets up the necessary registry information.

Each directive in a DDInstall.HW section can reference more than one INF-writer-defined section, but each additional named section must be separated from the next with a comma (,). Each such section name must be unique within the INF and must follow the same general rules for defining section names already described in General Syntax Rules for INF Files.

For more information about installing multifunction devices, Supporting Multifunction Devices.

Example

This example shows how the CD-ROM device class installer uses DDInstall.HW sections and DDInstall.Services sections to support both CD audio and changer functionality by creating the appropriate registry sections, and setting these up as PnP upper filter drivers.

;;
;; Installation section for cdaudio. Sets cdrom as the service
;; and adds cdaudio as a PnP upper filter driver.
;;
[cdaudio_install]
CopyFiles=cdaudio_copyfiles,cdrom_copyfiles

[cdaudio_install.HW]
AddReg=nosync_addreg,cdaudio_addreg
 ; cdaudio_addreg required to register this as a PnP filter driver

[cdaudio_install.Services]
AddService=cdrom,0x00000002,cdrom_ServiceInstallSection
AddService=cdaudio,,cdaudio_ServiceInstallSection

[changer_install]
CopyFiles=changer_copyfiles,cdrom_copyfiles

[changer_install.HW]
AddReg=changer_addreg

; ... changer_install.Services section similar to cdaudio's

; ... some similar cdrom_install(.HW)/addreg sections omitted

[cdaudio_addreg] ; changer_addreg section has similar entry
HKR,,"UpperFilters",0x00010000,"cdaudio" ; REG_MULTI_SZ value

;
; Use next section to disable synchronous transfers to this device.
; Sync transfers will always be turned off by default in this INF
; for any cdrom-type device.
;
[nosync_addreg]
HKR,,"DefaultRequestFlags",0x00010001,8

[autorun_addreg]
HKLM,"System\CurrentControlSet\Services\cdrom","AutoRun",0x00010003,1
;;
;; service-install sections for cdrom, cdaudio, and changer
;;
[cdrom_ServiceInstallSection]
DisplayName    = %cdrom_ServiceDesc%
ServiceType    = 1
StartType      = 1
ErrorControl   = 1
ServiceBinary  = %12%\cdrom.sys
LoadOrderGroup = SCSI CDROM Class
AddReg         = autorun_addreg

[cdaudio_ServiceInstallSection]
DisplayName    = %cdaudio_ServiceDesc%
ServiceType    = 1
StartType      = 1
ErrorControl   = 1
ServiceBinary  = %12%\cdaudio.sys

; ... changer_ServiceInstallSection similar to cdaudio's

See Also

AddReg, BitReg, DDInstall, DDInstall.Services, DelReg


INF DDInstall.CoInstallers Section

[install-section-name.CoInstallers] |
[install-section-name.nt.CoInstallers] |
[install-section-name.ntx86.CoInstallers]
[install-section-name.ntia64.CoInstallers]

AddReg=add-registry-section[, add-registry-section]...
CopyFiles=@filename | file-list-section[,file-list-section]...
[Include=filename.inf[,filename2.inf]...]
[Needs=inf-section-name[,inf-section-name]...]
[DelFiles=file-list-section[,file-list-section]...]
[RenFiles=file-list-section[,file-list-section]...]
[DelReg=del-registry-section[, del-registry-section]...]
[BitReg=bit-registry-section[,bit-registry-section]...]
[UpdateInis=update-ini-section[,update-ini-section]...]
[UpdateIniFields=update-inifields-section[,update-inifields-section]...]
[Ini2Reg=ini-to-registry-section[,ini-to-registry-section]...]
...

This optional section registers one or more device-specific co-installers supplied on the distribution media to supplement the operations of existing device class installers.

Directives and Entries

AddReg=add-registry-section[, add-registry-section]...
References one or more INF-writer-defined add-registry-sections that store registry information about the supplied co-installers.

An HKR specified in such an add-registry section designates the ..Class\SetupClassGUID\device-instance-id registry path to the user-accessible driver (a.k.a. "software") key. Thus, for a device-specific co-installer, it writes (or modifies) a CoInstallers32 value entry in this user-accessible per-device/driver "software" subkey.

For a class-specific co-installer, it registers the new co-installers by modifying the contents of the appropriate ..CoDeviceInstallers\SetupClassGUID subkeys. The path to the appropriate registry SetupClassGUID subkeys must be explicitly specified in the referenced add-registry sections.

For more information, see INF AddReg Directive.

CopyFiles=@filename | file-list-section[,file-list-section]...
Transfers the source co-installer files to the destination on the target machine, usually by referencing one or more INF-writer-defined file-list-sections elsewhere in the INF file. Such a file-list section specifies the co-installer files to be copied from the source media to the destination directory on the target.

However, system INF files that install co-installers never use this directive in a DDInstall.CoInstallers section.

For more information, see INF CopyFiles Directive.

Include=filename.inf[,filename2.inf]...
Specifies one or more additional system-supplied INF files containing sections needed to install the co-installers for this device or device setup class. If this entry is specified, usually so is a Needs entry. (For further information on the Include entry and restrictions on its use, see Specifying the Source and Target Locations for Device Files).
Needs=inf-section-name[,inf-section-name]...
Specifies the particular sections that must be processed during the installation of this device. Typically, such a named section is a DDInstall.CoInstallers section within a system-supplied INF file listed in an Include entry. However, it can be any section that is referenced within such a DDInstall.CoInstallers section of the included INF.

Needs entries cannot be nested. (For further information on the Needs entry and restrictions on its use, see Specifying the Source and Target Locations for Device Files.)

DelFiles=file-list-section[,file-list-section]...
References a file-list section specifying files to be removed from the target. This directive is rarely used.

For more information, see INF DelFiles Directive.

RenFiles=file-list-section[,file-list-section]...
References a file-list section specifying files on the destination to be renamed before co-installer source files are copied to the target.This directive also is rarely used.

For more information, see INF RenFiles Directive.

DelReg=del-registry-section[, del-registry-section]...
References one or more INF-writer-define delete-registry-sections. Such a section specifies stale registry information about the co-installers for a previous installation of the same devices that should be removed from the registry. An HKR specified in such a delete-registry section designates the same registry subkey as already described for AddReg. This directive is very rarely used in a DDInstall.CoInstallers section.

For more information, see INF DelReg Directive.

BitReg=bit-registry-section[,bit-registry-section]...
Is valid in this section but almost never used. An HKR specified in such a bit-registry section designates the same registry subkey as already described for AddReg.

For more information, see INF BitReg Directive.

UpdateInis=update-ini-section[,update-ini-section]...
Is valid in this section but almost never used.

For more information, see INF UpdateInis Directive.

UpdateIniFields=update-inifields-section[,update-inifields-section]...
Is valid in this section but almost never used.

For more information, see INF UpdateIniFields Directive.

Ini2Reg=ini-to-registry-section[,ini-to-registry-section]...
Is valid in this section but almost never used.

For more information, see INF Ini2Reg Directive.

Comments

The given DDInstall section must be referenced in a device/models-specific entry under the per-manufacturer Models section of the INF file.

If an INF includes a DDInstall.Coinstallers section, there must be one for each platform-decorated and undecorated DDInstall section. For example, if an INF contains an [install-section-name.ntx86] section and an [install-section-name] section and it registers device-specific co-installers, then the INF must include both an [install-section-name.ntx86.Coinstallers] section and an [install-section-name.Coinstallers] section. For more information about how to use the system-defined .nt, .ntx86, and .ntia64 extensions in cross-platform and dual-OS INF files, see also Creating an INF File. Co-installers are not supported on Windows 9x platforms.

Each directive in a DDInstall.CoInstallers section can reference more than one INF-writer-defined section name, but each additional named section must be separated from the next with a comma (,). Each directive-created section name must be unique within the INF and must follow the same general rules for defining section names already described in General Syntax Rules for INF Files.

A co-installer is a Win32 DLL that typically writes additional configuration information to the registry or performs other installation tasks that require dynamically generated, machine-specific information that is not available when an INF is created. A device-specific co-installer supplements the installation operations either of the OS's device installer or of the appropriate class installer when that device is installed.

For more information about writing and using co-installers, Writing a Co-Installer.

Installing Co-installer Images

All co-installer files must be copied into the %windir%\system32 directory. Like any INF CopyFiles operation, the destination is controlled explicitly for a named file-list-section in the DestinationDirs section of the INF file by the dirid value 11 or by supplying this dirid value for the DefaultDestDir entry.

Registering Device-Specific Co-installers

Registering one or more device-specific co-installers requires adding a REG_MULTI_SZ-typed value entry to the registry. Specify an add-registry-section referenced by the AddReg directive, using the following general form:

[DDInstall.CoInstallers_DeviceAddReg]

HKR,,CoInstallers32,0x00010000,"DevSpecificCoInstall.dll
[,DevSpecificEntryPoint]"[,"DevSpecific2CoInstall.dll
[,DevSpecific2EntryPoint]"...]

The HKR entry appears as a single line within the INF file, and each supplied device-specific co-installer DLL must have a unique name. After the listed co-installers have been registered, the system's device installer calls them at each subsequent step of the installation process for that device.

If the optional DevSpecificEntryPoint is omitted, the default CoDeviceInstall routine name is used as the entry point of the co-installer DLL.

For additional information, see Registering a Device-Specific Co-Installer.

Registering Device-Class Co-installers

To add a value entry (and setup-class subkey, if it does not exist already) for one or more device-class co-installers to the registry, an add-registry-section referenced by the AddReg directive has the following general form:

[DDInstall.CoInstallers_ClassAddReg]

HKLM,System\CurrentControlSet\Control
\CoDeviceInstallers,{SetupClassGUID},
0x00010008,"DevClssCoInst.dll[,DevClssEntryPoint]"
...

Each entry in such an add-registry section appears as a single line within the INF file, and each supplied class co-installer DLL must have a unique name. If the supplied co-installers should be used for more than one class of devices, this add-registry section can have more than one entry, each with the appropriate SetupClassGUID value. (The reference for the Version section earlier in this chapter contains a summary of the system-defined device classes and their respective setup ClassGUID values.)

Such a supplemental device-class co-installer must not replace any already registered co-installers for an existing class installer, so it must have a unique name and the REG_MULTI_SZ-type value supplied must be appended (as indicated by the 8 in the flags value 0x0010008) to the class-specific co-installer entries, if any, already present in the {SetupClassGUID} subkey. However, the OS setup functions will never append a duplicate DevClssCoInstall.dll to a value entry if a co-installer of the same name is already registered.

The INF for a supplemental device-class co-installer can be activated by a right-click install or through a custom setup application's call to SetupInstallFromInfSection.

Example

This example shows the DDInstall.CoInstallers section for IrDA serial network cards. The system-supplied INF for these IrDA (serial) NICs supplies a co-installer to the system IrDA class installer.

; DDInstall section
[PNP.NT]
AddReg=ISIR.reg, Generic.reg, Serial.reg
PromptForPort=0     ; This is handled by IRCLASS.DLL
LowerFilters=SERIAL ; This is handled by IRCLASS.DLL
BusType=14
Characteristics=0x4 ; NCF_PHYSICAL

; ... PNP.NT.Services section omitted here
[PNP.NT.CoInstallers]
AddReg = ISIR.CoInstallers.reg
; ...
[IRSIR.reg]
HKR, Ndi, HelpText, 0, %IRSIR.Help%
HKR, Ndi, Service, 0, "IRSIR"
HKR, Ndi\Interfaces, DefUpper, 0, "ndisirda"
HKR, Ndi\Interfaces, DefLower, 0, "nolower"
HKR, Ndi\Interfaces, UpperRange, 0, "ndisirda"
HKR, Ndi\Interfaces, LowerRange, 0, "nolower"

[Generic.reg]
HKR,,InfraredTransceiverType,0,"0"

[Serial.reg]
HKR,,SerialBased,0, "0"

[ISIR.CoInstallers.reg]
HKR,,CoInstallers32,0x00010000,"IRCLASS.dll,IrSIRClassCoInstaller"

; ... Services and Event Log registry sections omitted here
[Strings]
; ...
IRSIR.Help = "An IrDA serial infrared device is a built-in COM port or
external transceiver which transmits infrared pulses. This NDIS
miniport driver installs as a network adapter and binds to the FastIR
protocol."

The preceding PNP.NT.CoInstallers section only referenced a co-installer-specific add-registry section. It has no CopyFiles directive because this system-supplied INF installs a set of IrDA network devices and, like all system INF files, uses the LayoutFile entry in its Version section to transfer the co-installer file to the destination. However, any DDInstall.CoInstallers section in an INF supplied by an IHV or OEM also would have a CopyFiles directive, along with SourceDisksNames and SourceDisksFiles sections.

See Also

AddReg, BitReg, CopyFiles, DDInstall, DelFiles, DelReg, DestinationDirs, Ini2Reg, RenFiles, SourceDisksFiles, SourceDisksNames, UpdateIniFields, UpdateInis, Version


INF DDInstall.FactDef Section

[install-section-name.FactDef] |
[install-section-name.nt.FactDef] |
[install-section-name.ntx86.FactDef]
[install-section-name.ntia64.FactDef]

ConfigPriority=Priority_Value
[DMAConfig=[DMAattrs:]DMANum]
[IOConfig=io-range]
[MemConfig=mem-range]
[IRQConfig=[IRQattrs:]IRQNum
...

This section should be used in an INF for any manually installed nonPnP device that an end user might install with the Add Hardware wizard. This section specifies the factory-default hardware configuration settings, such as the bus-relative I/O ports, IRQ (if any), and so forth, for such a card.

Section Entries and Values

ConfigPriority=Priority_Value
Specifies the priority value for this factory-default logical configuration, as HARDRECONFIG, indicating a jumper change is required to reset this logical configuration.
DMAConfig=[DMAattrs:]DMANum
Specifies the bus-relative DMA channel as a decimal number. DMAattrs is optional if the device is connected on a bus that has only 8-bit DMA channels and the device uses standard system DMA. Otherwise, it can be one of the letters D for 32-bit DMA, W for 16-bit DMA, and N for 8-bit DMA, with M if the device uses busmaster DMA and with one of the following (mutually exclusive) letters indicating the type of DMA channel used: A, B, or F. If none of A, B, or F is specified, a standard DMA channel is assumed.
IOConfig=io-range
Specifies the I/O port range for the device in the following form:

start-end[([decode-mask][:alias-offset][:attr])]
where:

start specifies the (bus-relative) starting address of the I/O port range as a 64-bit hexadecimal value.

end specifies the ending address of the I/O port range, also as an 64-bit hexadecimal value.

decode-mask defines the alias type and can be any of the following:

Mask Value | Meaning | IOR_Alias =
3ff | 10-bit decode | 0x04
fff | 12-bit decode | 0x10
ffff | 16-bit decode | 0x00
0 | positive decode | 0xFF

alias-offset is ignored.

attr specifies the letter M if the given range is in system memory. If omitted, the given range is in I/O port space.

MemConfig=mem-range
Specifies the memory range for the device in the following form:

start-end[(attr)]
where:

start specifies the starting (bus-relative) address of the device memory range as a 64-bit hexadecimal value.

end specifies the ending address of the memory range, also as a 64-bit hexadecimal value.

attr specifies the attributes of the memory range as one or more of the following letters: R (read-only), W (write-only), RW (read/write), C (combined write allowed), H (cacheable), F (prefetchable), and D (card decode addressing is 32-bit, instead of 24-bit) If both R and W are specified or if neither is specified, read/write is assumed.

IRQConfig=[IRQattrs:]IRQNum
Specifies the bus-relative IRQ that the device uses as a decimal number. IRQattrs is omitted if the device uses a bus-relative, edge-triggered IRQ. Otherwise, specify L to indicate a level-triggered IRQ and LS if the device can share the IRQ line listed in this entry.

Comments

The given DDInstall section must be referenced in a device-specific entry under the per-manufacturer Models section of the INF file. The case-insensitive extensions to the install-section-name shown in the formal syntax statement can be inserted into such a DDInstall.FactDef section name in cross-OS and/or cross-platform INF files. For more information about these system-defined extensions, see Creating an INF File.

This section must contain complete factory-default information for installing one device. The INF should specify this set of entries in the order best suited to how the driver initializes its device. If necessary, it can have more than one of any particular kind of entry. For example, the INF for a device that used two DMA channels would have two DMAConfig= lines in its DDInstall.FactDef section. From this section, the Add Hardware wizard builds binary logical configuration records and stores them in the registry.

The INF files of manually installed devices for which the factory-default logical configuration settings can be changed also should use the LogConfig directive in their DDInstall sections. In general, such an INF should specify the entries in each of its log-config sections and in its DDInstall.FactDef section in the same order.

Examples

This IOConfig= entry specifies an I/O port region, eight bytes in size, which can start at 2F8.

IOConfig=2F8-2FF

This MemConfig= entry specifies a memory region of 32K bytes that can start at D0000.

MemConfig=D0000-D7FFF

See Also

DDInstall, LogConfig


INF DDInstall.LogConfigOverride Section

[install-section-name.LogConfigOverride]
[install-section-name.nt.LogConfigOverride]
[install-section-name.ntx86.LogConfigOverride]
[install-section-name.ntia64.LogConfigOverride]

LogConfig=log-config-section[,log-config-section]...]

DDInstall.LogConfigOverride sections are used to create an override configuration, which overrides the hardware resource requirements that a Plug and Play device's bus driver reports.

Section Entries and Values

The section entries and values used with DDInstall.LogConfigOverride sections are specified within log-config-sections referenced by INF LogConfig directives.

Example

[XYZDevice.LogConfigOverride]
LogConfig = XYZDevice.Override0

[XYZDevice.Override0]
IOConfig=2f8-2ff
IOConfig=20@100-FFFF%FFE0
IRQConfig=3,4,5,7,9,10,11
MemConfig=4000@0-FFFFFFFF%FFFFC000
PcCardConfig=41:100000(W)


INF DDInstall.Interfaces Section

[install-section-name.Interfaces] |
[install-section-name.nt.Interfaces] |
[install-section-name.ntx86.Interfaces]
[install-section-name.ntia64.Interfaces]

AddInterface={InterfaceClassGUID} [, [reference string] [,[add-interface-section] [,flags]]] ...
[Include=filename.inf[,filename2.inf]...]
[Needs=inf-section-name[,inf-section-name]...]

Each per-Models DDInstall.Interfaces section can have one or more AddInterface directives, depending on how many device interfaces a particular device/driver supports.

To support existing device interfaces, such as any of the system's predefined kernel-streaming interfaces, specify the appropriate InterfaceClassGUID values in this section.

To install a component, such as a class driver, that exports a new class of device interfaces, an INF also must have an INF InterfaceInstall32 section.

For more information about device interfaces, see Device Interface Classes.

Directives and Entries

AddInterface={InterfaceClassGUID} [, [reference string] [,[add-interface-section] [,flags]]] ...
This directive installs support for a device interface class, designated by the given InterfaceClassGUID value, that the driver exports to higher level components. Usually, it also references an INF-writer-defined add-interface-section elsewhere in the INF file. For detailed information about specifying this directive, see INF AddInterface Directive.
Include=filename.inf[,filename2.inf]...
This optional entry specifies one or more additional system-supplied INF files containing sections needed to register the interface classes supported by this device/driver. If this entry is specified, usually so is a Needs entry. (For further information on the Include entry and restrictions on its use, see Specifying the Source and Target Locations for Device Files.)
Needs=inf-section-name[,inf-section-name]...
This optional entry specifies the particular sections that must be processed during the installation of this device. Typically, such a named section is a DDInstall.Interfaces section within a system-supplied INF file listed in an Include entry. However, it can be any section that is referenced within such a DDInstall.Interfaces section of the included INF.

Needs entries cannot be nested. (For further information on the Needs entry and restrictions on its use, see Specifying the Source and Target Locations for Device Files.)

Comments

The DDInstall section name must be referenced by a device/models-specific entry under the per-manufacturer Models section of the INF file. For information about using the system-defined .nt, .ntx86, and .ntia64 extensions in cross-platform and dual-OS INF files, see Creating INF Files for Multiple Platforms and Operating Systems.

If a given {InterfaceClassGUID} is not installed already, the operating system's setup code installs that device interface class in the system. If an INF file installs one or more new device interface classes, it also has an [InterfaceInstall32] section identifying the GUID for the new class..

For more information about how to create a GUID, see Using GUIDs in Drivers. For the system-defined interface class GUIDs, see the appropriate system-supplied header, such as ks.h for the kernel-streaming interface class GUIDS.

When a driver is loaded, it must call IoSetDeviceInterfaceState once foreach {InterfaceClassGUID} value specified in the INF's DDInstall.Interfaces section that the driver supports on the underlying device, to enable the interface for runtime use by higher level components. Instead of registering support for a device interface in an INF, a device driver can call IoRegisterDeviceInterface before making its initial call to IoSetDeviceInterfaceState. Usually, a PnP function or filter driver makes this call from its AddDevice routine.

Example

This example shows the DDInstall.NT.Interfaces section in the dual-OS INF file for the system-supplied WDM audio device/driver shown as examples for the INF DDInstall section and the INF DDInstall.Services section.

;
; following AddInterface= are all single lines (without
; backslash line continuators) in the system-supplied INF file
;
[WDMPNPB003_Device.NT.Interfaces]
AddInterface=%KSCATEGORY_AUDIO%,%KSNAME_Wave%,\
  WDM_SB16.Interface.Wave
AddInterface=%KSCATEGORY_AUDIO%,%KSNAME_Topology%,\
  WDM_SB16.Interface.Topology
AddInterface=%KSCATEGORY_AUDIO%,%KSNAME_UART%,\
  WDM_SB16.Interface.UART
AddInterface=%KSCATEGORY_AUDIO%,%KSNAME_FMSynth%,\
  WDM_SB16.Interface.FMSynth
; ...

[Strings] ; only immediately preceding %strkey% tokens shown here
%KSCATEGORY_AUDIO% = "{6994ad04-93ef-11d0-a3cc-00a0c9223196}"
KSNAME_Wave = "Wave"
KSNAME_UART = "UART"
KSNAME_FMSynth = "FMSynth"
KSNAME_Topology = "Topology"
; ...

See Also

AddInterface, DDInstall, InterfaceInstall32, IoRegisterDeviceInterface, IoSetDeviceInterfaceState


INF InterfaceInstall32 Section

[InterfaceInstall32]

{InterfaceClassGUID}=install-interface-section[,flags]
...

This section sets up one or more new device interface classes. In effect, this section bootstraps a new device interface class, so that subsequently installed devices/drivers can be registered to support the new device interface class by using INF DDInstall.Interfaces sections in their respective INF files, or by calling IoRegisterDeviceInterface.

Entry Values

InterfaceClassGUID
Specifies a GUID value identifying the newly exported device interface class.

To register an instance of the interface class, a given GUID value in this section must be referenced by an INF AddInterface directive in an INF DDInstall.Interfaces section, or else the newly installed device's driver must call IoRegisterDeviceInterface with this GUID.

For more information about how to create a GUID, see Using GUIDs in Drivers. For the system-defined interface class GUIDS, see the appropriate headers, such as ks.h for the kernel-streaming interfaces.

install-interface-section
References an INF-writer-defined section, possibly with any of the system-defined extensions, elsewhere in this INF.
flags
If specified, must be zero.

Comments

When a given InterfaceClassGUID is not already installed in the system, that interface class is installed as the corresponding DDInstall.Interfaces section is processed by the system setup functions during device installation or when that device's driver makes the initial call to IoRegisterDeviceInterface.

Each INF-writer-created interface-install-section name must be unique within the INF and must follow the same general rules for defining section names already described in General Syntax Rules for INF Files.

Any given interface-install-section has the following general form:

[interface-install-section] |
[interface-install-section.nt] |
[interface-install-section.ntx86] |
[interface-install-section.ntia64]

AddReg=add-registry-section[, add-registry-section] ...
[Copyfiles=@filename | file-list-section[, file-list-section] ...]
[DelReg=del-registry-section[, del-registry-section] ...]
[BitReg=bit-registry-section[,bit-registry-section]...]
[Delfiles=file-list section[, file-list-section] ...]
[Renfiles=file-list-section[, file-list-section] ...]
[UpdateInis=update-ini-section[,update-ini-section]...]
[UpdateIniFields=update-inifields-section[,update-inifields-section]...]
[Ini2Reg=ini-to-registry-section[,ini-to-registry-section]...]
...

As shown here, an interface-install section must have at least one AddReg directive that references one or more add-registry sections to set up device-interface-specific information in the registry during installation of this interface. An HKR specified in such an add-registry section designates the ..DeviceClasses\{InterfaceClassGUID} key.

The registry information about this interface class should include at least a friendly name for the new device interface class and whatever information the higher level components that open and use this interface will need.

In addition, such an interface-install-section might use any of the optional directives shown here to specify interface-specific installation operations.

See Also

AddReg, BitReg, ClassInstall32, CopyFiles, DDInstall, DDInstall.Interfaces, DelFiles, DelReg, Ini2Reg, IoRegisterDeviceInterface, RenFiles, UpdateIniFields, UpdateInis


INF DefaultInstall Section

[DefaultInstall] |
[DefaultInstall.nt] |
[DefaultInstall.ntx86] |
[DefaultInstall.ntia64]

[CopyFiles=@filename | file-list-section[,file-list-section] ...]
[CopyINF=filename1.inf[,filename2.inf]...]
[AddReg=add-registry-section[,add-registry-section]...]
[Include=filename1.inf[,filename2.inf]...]
[Needs=inf-section-name[,inf-section-name]...]
[Delfiles=file-list-section[,file-list-section]...]
[Renfiles=file-list-section[,file-list-section]...]
[DelReg=del-registry-section[,del-registry-section]...]
[BitReg=bit-registry-section[,bit-registry-section]...]
[ProfileItems=profile-items-section[,profile-items-section]...]
[UpdateInis=update-ini-section[,update-ini-section]...]
[UpdateIniFields=update-inifields-section[,update-inifields-section]...]
[Ini2Reg=ini-to-registry-section[,ini-to-registry-section]...]
[Ini2Reg=ini-to-registry-section[,ini-to-registry-section]...]
[RegisterDlls=register-dll-section[,register-dll-section]...]
[UnregisterDlls=unregister-dll-section[,unregister-dll-section]...] ...

An INF file's DefaultInstall section will be accessed if a user selects the "Install" menu item after right-clicking on the INF file name.

Directives and Entries

CopyFiles=@filename | file-list-section[,file-list-section] ...
This optional directive either specifies one named file to be copied from the source medium to the destination, or references one or more INF-writer-defined sections that specify files to be transferred from the source media to the destination.

The DefaultDestDir entry in the DestinationDirs section of the INF specifies the destination for any single file to be copied. The SourceDisksNames and SourceDisksFiles sections, or an additional INF specified in the LayoutFile entry of this INF's Version section, provides the location on the distribution media of the driver files.

For more information, see INF CopyFiles Directive.

CopyINF=filename1.inf[,filename2.inf]...]
(Windows XP and later.) This directive causes specified INF files to be copied to the target system.

For more information, see INF CopyINF Directive.

AddReg=add-registry-section[,add-registry-section]...
This directive references one or more INF-writer-defined sections in which new subkeys, possibly with initial value entries, are specified to be written into the registry or in which the value entries of existing keys are modified.

For more information, see INF AddReg Directive.

Include=filename.inf[,filename2.inf]...
This optional entry specifies one or more additional system-supplied INF files containing sections needed to install this device and/or driver. If this entry is specified, usually so is a Needs entry.

For example, the system INF files for device drivers that depend on the system's kernel-streaming support specify this entry as
Include= ks.inf[, [kscaptur.inf,] [ksfilter.inf]].

(For further information on the Include entry and restrictions on its use, see Specifying the Source and Target Locations for Device Files).

Needs=inf-section-name[,inf-section-name]...
This optional entry specifies sections within system-supplied INF files that must be processed during the installation of this device. Typically, such a named section is a DDInstall (or DDInstall.xxx) section within one of the INF files listed in an Include entry. However, it can be any section that is referenced within such a DDInstall or DDInstall.xxx section of the included INF.

For example, the INF files for device drivers that have the preceding Include entry specify this entry as
Needs= KS.Registration[, KSCAPTUR.Registration |
KSCAPTUR.Registration.NT, MSPCLOCK.Installation]

Needs entries cannot be nested. (For further information on the Needs entry and restrictions on its use, see Specifying the Source and Target Locations for Device Files).

DelFiles=file-list-section[,file-list-section]...
This directive references one or more INF-writer-defined sections listing files on the target to be deleted.

For more information, see INF DelFiles Directive.

RenFiles=file-list-section[,file-list-section]...
This directive references one or more INF-writer-defined sections listing files to be renamed on the destination before device-relevant source files are copied to the target machine.

For more information, see INF RenFiles Directive.

DelReg=del-registry-section[,del-registry-section]...
This directive references one or more INF-writer-defined sections in which keys and/or value entries are specified to be removed from the registry during installation of the devices.

Typically, this directive is used to handle upgrades when an INF must clean up old registry entries from a previous installation of this device. An HKR specification in such a delete-registry section designates the ..Class\SetupClassGUID\device-instance-id registry path to the user-accessible driver (a.k.a. "software" key).

For more information, see INF DelReg Directive.

BitReg=bit-registry-section[,bit-registry-section]...
This directive references one or more INF-writer-defined sections in which existing registry value entries of type REG_BINARY are modified. (See also AddReg.) An HKR specification in such a bit-registry section designates the ..Class\SetupClassGUID\device-instance-id registry path to the user-accessible driver (a.k.a. "software" key).

For more information, see INF BitReg Directive.

ProfileItems=profile-items-section[,profile-items-section]...
This directive references one or more INF-writer-defined sections that describe items to be added to, or removed from, the Start menu.

This directive is only supported on Windows 2000 and later platforms.

For more information, see INF ProfileItems Directive.

UpdateInis=update-ini-section[,update-ini-section]...
This rarely used directive references one or more INF-writer-defined sections, specifying a source INI file from which a particular section or line within such a section is to be read into a destination INI file of the same name during installation. Optionally, line-by-line modifications to an existing INI file on the destination from a given source INI file of the same name can be specified in the update-ini section.

For more information, see INF UpdateInis Directive.

UpdateIniFields=update-inifields-section[,update-inifields-section]...
This rarely used directive references one or more INF-writer-defined sections in which modifications within the lines of a device-specific INI file are specified.

For more information, see INF UpdateIniFields Directive.

Ini2Reg=ini-to-registry-section[,ini-to-registry-section]...
This rarely used directive references one or more INF-writer-defined sections in which sections or lines from a device-specific INI file, supplied on the source media, are to be moved into the registry.

For more information, see INF Ini2Reg Directive.

RegisterDlls=register-dll-section[,register-dll-section]...
This directive references one or more INF sections used to specify files that are OLE controls and require self-registration.

For more information, see INF RegisterDlls Directive.

UnregisterDlls=unregister-dll-section[,unregister-dll-section]...
This directive references one or more INF sections used to specify files that are OLE controls and require self-unregistration (self-removal).

For more information, see INF UnregisterDlls Directive.

Comments

DefaultInstall sections are not generally used for device installations. More typically, they are used for the installation of class filter drivers, class co-installers, file system filters, and kernel driver services that are not associated with a device node.

The following example shows a typical DefaultInstall section:

[DefaultInstall]
CopyFiles=MyAppWinFiles, MyAppSysFiles, @SRSutil.exe
AddReg=MyAppRegEntries

In this example, the DefaultInstall section will be executed if a user selects "Install" after right-clicking on the INF file name.

Note that unlike a DDInstall section, a DefaultInstall section cannot contain DriverVer or LogConfig directives.

Providing a DefaultInstall section is optional. If an INF file does not include a DefaultInstall section, selecting "Install" after right-clicking on the file name causes an error message to be displayed.

To install a DefaultInstall section from a setup application, use the following call to InstallHinfSection (described in Platform SDK documentation):

InstallHinfSection(NULL,NULL,TEXT("DefaultInstall 132 path-to-inf\infname.inf"),0);


INF DefaultInstall.Services Section

[DefaultInstall.Services] |
[DefaultInstall.nt.Services] |
[DefaultInstall.ntx86.Services]
[DefaultInstall.ntia64.Services]

AddService=ServiceName,[flags],service-install-section[,
event-log-install-section[,[EventLogType][,EventName]]]...
[DelService=ServiceName[,[flags][,[EventLogType][,EventName]]]...
[Include=filename.inf[,filename2.inf]...]
[Needs=inf-section-name[,inf-section-name]...]

A DefaultInstall.Services section contains one or more AddService directives referencing additional INF-writer-defined sections in a Windows 2000 or later INF file. This section is equivalent to the INF DDInstall.Services section, and is used in association with an INF DefaultInstall section.

Directives and Entries

AddService=ServiceName,[flags],service-install-section[,
event-log-install-section[,[EventLogType][,EventName]]]...
This directive references an INF-writer-defined service-install-section and, possibly, an event-log-install-section elsewhere in the INF file for the drivers of the devices covered by this DefaultInstall section. For more information, see INF AddService Directive.
DelService=ServiceName[,[flags][,[EventLogType][,EventName]]]...
This directive removes a previously installed service from the target machine. This directive is very rarely used. For more information, see INF DelService Directive.
Include=filename.inf[,filename2.inf]...
This optional entry specifies one or more additional system-supplied INF files containing sections needed to install this device. If this entry is specified, usually so is a Needs entry. (For further information on the Include entry and restrictions on its use, see Specifying the Source and Target Locations for Device Files).
Needs=inf-section-name[,inf-section-name]...
This optional entry specifies the particular named section that must be processed during the installation of this device. Typically, such a named section is a DDInstall.Services section within a system-supplied INF file listed in an Include entry. However, it can be any section that is referenced within such a DDInstall.Services section.

Needs entries cannot be nested. (For further information on the Needs entry and restrictions on its use, see Specifying the Source and Target Locations for Device Files).

Comments

INF files use the DefaultInstall.Services section only if they also use an INF DefaultInstall section. Otherwise, they use INF DDInstall.Services sections in conjunction with INF DDInstall sections. The INF AddService directive controls how and when the services of a particular driver are loaded, any dependencies on other services or on underlying (legacy) drivers it might have, and so forth. Optionally, it sets up event-logging services for the device drivers as well.

DefaultInstall.Services sections should have the same platform and OS decorations as their related DefaultInstall sections. For example, a DefaultInstall.ntx86 section would have a corresponding DefaultInstall.ntx86.Services section.

This section is irrelevant to exclusively Windows 9x/Me installations.

Examples

See the examples provided for the INF DDInstall.Services section.


INF Strings Section

[Strings] | [Strings.LanguageID] ...

strkey1= ["]some string["]
strkey2 = " string-with-leading-or-trailing-whitespace " |
"very-long-multiline-string " |
"string-with-semicolon" | "string-ending-in-backslash" |
 ""double-quoted-string-value""
...

An INF file must have at least one Strings section to define every %strkey% token specified elsewhere in that INF.

Entry Values

strkey1, strkey2, ...
Each string key in an INF file must specify a unique name consisting of letters, digits, and/or other explicitly visible characters. A % character within such a strkey token can be expressed as %%.
some string | "some string"
Specifies a string, optionally delimited with double quotation marks characters ("), that contains letters, digits, punctuation, and possibly even certain implicitly visible characters, in particular, internal space and/or tab characters. However, an unquoted string cannot contain an internal double quotation marks ("), semicolon (;), linefeed, return, or any invisible control characters, and it cannot have a backslash (\) as its final character.
" string-with-leading-or-trailing-whitespace " |
"very-long-multiline-string" |
"string-with-semicolon" | "string-ending-in-backslash" |
""double-quoted-string-value""
The value specified for a %strkey% token must be enclosed in double quotation marks, if it meets any of the following criteria:
  • If a given string has leading or trailing whitespace that must be retained as part of its value, that string must be enclosed in double quotation marks characters to prevent its leading and/or trailing whitespaces from being discarded by the INF parser.
  • If a long string might contain any internal linefeed or return characters due to linewrapping in the text editor, it also should be enclosed in double quotation marks to prevent truncation of the string at the initial internal linefeed or return character.
  • If such a string contains a semicolon, it must be enclosed in double quotation marks to prevent the string from being truncated at the semicolon. (As already mentioned in General Syntax Rules for INF Files, the semicolon character begins each comment in INF files.)
  • If such a string ends in a backslash, it must be enclosed in double quotation marks to prevent the string from being concatenated with the next entry. (As already mentioned in General Syntax Rules for INF Files, the backslash character (\) is used as the line continuator in INF files.)
  • Like an unquoted string specification, such a "quoted string" cannot contain internal double quotation marks characters. However, it can be specified as an explicitly double-quoted string value by using one or more additional pairs of double quotation marks characters (for example, ""some string"").

    The INF parser not only discards the outermost pair of enclosing double quotation marks for any "quoted string" in this section, but also condenses each subsequent sequential pair of double quotation marks into a single double quotation marks character. That is, """some string""" also becomes "some string" when it has been parsed.

To summarize, any string containing leading or trailing whitespace, that is so long it linewraps, that contains a semicolon or a final backslash character, or that is itself a quoted string, must be enclosed in a pair of double quotation marks characters ("). The system INF parser discards the outermost enclosing pair of double quotation marks characters delimiting such a string, along with any leading or trailing whitespace characters outside the double quotation marks string delimiters.

Comments

Because the system INF parser strips the outermost pair of enclosing double quotation marks from any "quoted string" defining a %strkey% token, many of the system INF files define all their %strkey% tokens as "quoted string"s to avoid the inadvertent loss of leading and trailing whitespaces during INF parsing, to ensure that particularly long string values that wrap across lines cannot be truncated, and to ensure that strings with ending backslashes cannot be concatenated to the next line in the INF file.

To create a single international INF file, an INF for NT-based installations can have a set of locale-specific Strings.LanguageID sections, as shown in the formal syntax statement. The LanguageID extension is a hexadecimal value defined as follows:

  • The lower 10 bits contain the primary language ID and the next 6 bits contain the sub-language ID, as specified by the MAKELANGID macro defined in winnt.h.
  • The language and sub-language IDs must match the system-defined values of the Win32 LANG_XXX and SUBLANG_XXX constants defined in winnt.h.

For example, a LanguageID value of 0407 represents a primary language ID of LANG_GERMAN (07) with a sub-language ID of SUBLANG_GERMAN (01).

An INF file can contain only one [Strings] section, along with one [Strings.LanguageID] section for each LanguageID value. (Windows 9x/Me Setup does not support [Strings.LanguageID] sections.)

Depending on the current locale of a particular machine, the system setup functions process each such of these sections as follows:

  1. First, look for the .LanguageID values in the INF that match the current locale assigned to the machine. If an exact match is found, use that Strings.LanguageID INF section to translate %strkey% tokens for this installation.
  2. Otherwise, look next for a match to the LANG_XXX value with the value of SUBLANG_NEUTRAL as the SUBLANG_XXX. If such a match is found, use that INF section to translate %strkey% tokens.
  3. Otherwise, look next for a match to the LANG_XXX value and any valid SUBLANG_XXX for the same LANG_XXX family. If such a partial match is found, use that Strings.LanguageID INF section to translate %strkey% tokens.
  4. Otherwise, use the undecorated Strings section to translate %strkey% tokens for this installation.

By convention, and for convenience in creating a set of INF files for the international market, the Strings sections are the last within all system INF files. Using %strkey% tokens for all user-visible string values within an INF, and placing them in per-locale Strings sections, simplifies the translation of such strings. For additional information about locale-specific INF files, see Creating International INF Files.

Although the Strings sections are usually the last section in every INF file, any given %strkey% token defined in a Strings section can be used repeatedly elsewhere in the INF, in particular, wherever the translated value of that token is required. The system setup functions expand each %strkey% token to the specified string and then use that expanded value for further INF processing.

The use of %strkey% tokens within INF files is not restricted to user-visible string values. These tokens can be used in any manner convenient to the INF writer, as long as each token is defined within a Strings section. For example, when writing an INF file that requires the specification of several GUIDs, it might be convenient to create a %strkey% token for each GUID, using a meaningful name as a substitute for each such GUID value. Specifying a set of %strkey% = "{GUID}" values in the INF file's Strings section requires you to type each explicit GUID values only once, and it can help to provide more readable internal INF documentation than using explicit GUID values throughout the INF file.

All %strkey% tokens must be defined within the INF file in which they are referenced. Thus, for any INF file that has Include= and Needs= entries, an included INF must have its own Strings section to define all %strkey% tokens referenced in that INF.

The maximum length of any single string specified in an INF Strings section is 512 characters, including the terminating NULL. The maximum length of any concatenated string created from one or more %strkey% tokens is 4096 characters.

Examples

The following example shows a fragment of a Strings section from a system-supplied locale-specific dvd.inf for installations in English-speaking countries/regions.

[Strings]
Msft="Microsoft"
MfgToshiba="Toshiba"
Tosh404.DeviceDesc="Toshiba DVD decoder card"
; ...

The following example illustrates string concatenation.

[OEM Windows System Component Verification]
OID = 1.3.6.1.4.1.311.10.3.7    ; WHQL OEM OID
Notice = "%A% %B% %C% %D% %E%"

[Strings]
A="This certificate is used to sign untested drivers that have not passed the Windows Hardware Quality Labs (WHQL) testing process."
B = "This certificate and drivers signed with this certificate are intended for use in test environments only, and are not intended for use in any other context."
C = "Vendors who distribute this certificate or drivers signed with this certificate outside a test environment may be in violation of their driver signing agreement."
D = "Vendors who have their drivers signed with this certificate do so at their own risk."
E = "In particular, Microsoft assumes no liability for any damages that may result from the distribution of this certificate or drivers signed with this certificate outside the test environment described in a vendor's driver signing agreement."

See Also

DDInstall, DDInstall.CoInstallers, DDInstall.HW, DDInstall.Interfaces, DDInstall.Services, Manufacturer, InterfaceInstall32, Models, SourceDisksNames, Version


INF AddReg Directive

[DDInstall] |
[DDInstall.HW] |
[DDInstall.CoInstallers] |
[ClassInstall32] |
[ClassInstall32.ntx86] |
[ClassInstall32.ntia64]

AddReg=add-registry-section[, add-registry-section] ...

An AddReg directive references one or more INF-writer-defined sections used to modify or create registry information. Each such add-registry section can have entries to do the following:

  • Add new keys, possibly with initial value entries, to the registry.
  • Add new value entries to existing registry keys.
  • Modify existing value entries of particular keys in the registry.

An AddReg directive can be specified under any of the sections shown in the formal syntax statement above. This directive also can be specified under any of the following INF-writer-defined sections:

  • A service-install-section or event-log-install section referenced by the AddService directive in a DDInstall.Services section
  • An add-interface-section referenced by the AddInterface directive in a DDInstall.Interfaces section
  • An install-interface-section referenced in an InterfaceInstall32 section

Comments

Each add-registery-section name must be unique to the INF file, but it can be referenced by AddReg directives in other sections of the same INF. Each section name must follow the general rules for defining section names described in General Syntax Rules for INF Files. For more information about how to use the system-defined .nt, .ntx86, and .ntia64 extensions, see Creating an INF File.

Each named section referenced by an AddReg directive has the following form:

[add-registry-section]
reg-root, [subkey], [value-entry-name], [flags], [value]
reg-root, [subkey], [value-entry-name], [flags], [value]
...
[[add-registry-section.security]
"security-descriptor-string"]

An add-registy-section can have any number of entries, each on a separate line. An INF can also contain one or more optional add-registry-section.security sections, each specifying a security descriptor that will be applied to all registry values described within a named add-registry-section.

add-registry-section Entries

reg-root
Identifies the root of the registry tree for other values supplied in this entry. The value can be one of the following:
HKCR
Abbreviation for HKEY_CLASSES_ROOT
HKCU
Abbreviation for HKEY_CURRENT_USER
HKLM
Abbreviation for HKEY_LOCAL_MACHINE
HKU
Abbreviation for HKEY_USERS
HKR
Relative root – that is, keys specified using this abbreviation are relative to the registry key associated with the INF section in which this AddReg directive appears, as indicated in the following table.
INF Section Containing AddReg Directive | Registry Key Referenced by HKR
INF DDInstall section | The device's software key
INF DDInstall.HW section | The device's hardware key
INF DDInstall.Services section | The Services key

For more information about a device's software and hardware keys, see SetupDiOpenDevRegKey.

Note that HKR cannot be used in an add-registry-section referenced from an INF DefaultInstall section.

For more information about driver information stored under the HKEY_LOCAL_MACHINE root, see Driver Information in the Registry.

subkey
This optional value, formed either as a %strkey% token defined in a Strings section of the INF or as a registry path under the given reg-root (key1\key2\key3...), specifies one of the following:
  • A new subkey to be added to the registry at the end of the given registry path
  • An existing subkey in which the additional values specified in this entry will be written (possibly replacing the value of an existing named value entry of the given subkey)
  • Both a new subkey to be added to the registry together with its initial value entry
value-entry-name
This optional value either names an existing value entry in the given (existing) subkey or creates the name of a new value entry to be added in the specified subkey, whether it already exists or is a new key to be added to the registry. This value can be expressed either as "quoted string" or as a %strkey% token that is defined in the INF's Strings section. (If this is omitted for a string-type value, the value-entry-name is the default "unnamed" value entry for this key.)

The OS supports some system-defined special value-entry-name keywords. See the end of this Comments section for more information.

flags
This optional hexadecimal value, expressed as an ORed bitmask of system-defined low word and high word flag values, defines the data type for a value entry and/or controls the add-registry operation. Bitmask values for each of these flags are as follows:
0x00000001 (FLG_ADDREG_BINVALUETYPE)
The given value is "raw" data. (This value is identical to the FLG_ADDREG_TYPE_BINARY.)
0x00000002 (FLG_ADDREG_NOCLOBBER)
Prevent a given value from replacing the value of an existing value entry.
0x00000004 (FLG_ADDREG_DELVAL)
Delete the given subkey from the registry, or delete the specified value-entry-name from the specified registry subkey.
0x00000008 (FLG_ADDREG_APPEND)
Append a given value to that of an existing named value entry. This flag is valid only if FLG_ADDREG_TYPE_MULTI_SZ is also set. The specified string value is not appended if it already exists.
0x00000010 (FLG_ADDREG_KEYONLY)
Create the given subkey, but ignore any supplied value-entry-name and/or value.
0x00000020 (FLG_ADDREG_OVERWRITEONLY)
Reset to the supplied value only if the specified value-entry-name already exists in the given subkey.
0x00001000 (FLG_ADDREG_64BITKEY)
(Windows XP and later.) Make the specified change in the 64-bit registry. If not specified, the change is made to the native registry.
0x00002000 (FLG_ADDREG_KEYONLY_COMMON)
(Windows XP and later.) This is the same as FLG_ADDREG_KEYONLY but also works in a del-registry-section (see INF DelReg Directive ).
0x00004000 (FLG_ADDREG_32BITKEY)
(Windows XP and later.) Make the specified change in the 32-bit registry. If not specified, the change is made to the native registry.
0x00000000 (FLG_ADDREG_TYPE_SZ)
The given value entry and/or value is of type REG_SZ. Note that this is the default type for a specified value entry, so the flags value can be omitted from any reg-root= line in an add-registry section that operates on a value entry of this type.
0x00010000 (FLG_ADDREG_TYPE_MULTI_SZ)
The given value entry and/or value is of the registry type REG_MULTI_SZ. This specification does not require any NULL terminator for a given string value.
0x00020000 (FLG_ADDREG_TYPE_EXPAND_SZ)
The given value entry and/or value is of the registry type REG_EXPAND_SZ.
0x00010001 (FLG_ADDREG_TYPE_DWORD)
The given value entry and/or value is of the registry type REG_DWORD.
0x00020001 (FLG_ADDREG_TYPE_NONE)
The given value entry and/or value is of the Windows 2000 registry type REG_NONE.
value
This optionally specifies a new value for the specified value-entry-name to be added to the given registry key. Such a value can be a "replacement" value for an existing named value entry in an existing key, a value to be appended (flag value 0x00010008) to an existing named REG_MULTI_SZ-type value entry in an existing key, a new value entry to be written into an existing key, or the initial value entry for a new subkey to be added to the registry.

The expression of such a value depends on the registry type specified for the flag, as follows:

  • A registry string-type value can be expressed either as a "quoted string" or as a %strkey% token defined in a Strings section of the INF file. Such an INF-specified value need not include a NULL terminator at the end of each string.
  • A registry numerical-type value can be expressed as a hexadecimal (using 0x notation) or decimal number.
security-descriptor-string
Specifies a security descriptor, to be applied to all registry entries created by the named add-register-section. The security-descriptor-string is a string with tokens to indicate the DACL (D:) security component. See Platform SDK documentation for information about the format of security descriptor strings.

Note that the lower-order bit of the low word in a flag value distinguishes between character and binary data. Consequently, a Windows 95 installer interprets all registry data types as either REG_SZ or REG_BINARY.

To represent a number of a registry type other than one of the predefined REG_XXX types, specify a new type number in the high word of the flag ORed with FLG_ADDREG_BINVALUETYPE in its low word. The data for such a value must be specified in binary format as a sequence of bytes separated by commas. For example, to store 16 bytes of data of a new registry data type, such as 0x38, as a value entry, the add-registry section entry would be something like the following:

HKR,,MYValue,0x00380001,1,0,2,3,4,5,6,7,8,9,A,B,C,D,E,F

This technique can be used to define new registry types for numerical values, but not for values of type REG_EXPAND_SZ, REG_MULTI_SZ, REG_NONE, or REG_SZ.

Special value-entry-name Keywords

Special keywords are defined for use in the HKR AddReg entries:

[ClassInstall32] | [ClassInstall32.nt*] | [DDInstall.HW]
...
AddReg = Xxx_AddReg
...
[Xxx_AddReg]
...
[HKR,,DeviceCharacteristics,0x10001,characteristics]
[HKR,,DeviceType,0x10001,device-type]
[HKR,,Security,,security-descriptor-string]
[HKR,,UpperFilters,0x10000,service-name]
[HKR,,LowerFilters,0x10000,service-name]
[HKR,,Exclusive,0x10001,reserved]          ; RESERVED. Do not use.

[DDInstall]
...
AddReg = Yyy_AddReg
...
[Yyy_AddReg]
...
[HKR,,EnumPropPages32,,"prop-provider.dll,provider-entry-point"]
[HKR,,LocationInformationOverride,,"text-string"]

The special keywords are used as follows:

DeviceCharacteristics
A DeviceCharacteristics entry specifies characteristics for the device. The characteristics value is a numeric value that is the result of OR'ing one or more FILE_* file characteristics values, which are defined in wdm.h and ntddk.h. Only the following values can be specified in an INF:
#define FILE_REMOVABLE_MEDIA            0x00000001
#define FILE_READ_ONLY_DEVICE           0x00000002
#define FILE_FLOPPY_DISKETTE            0x00000004
#define FILE_WRITE_ONCE_MEDIA           0x00000008
#define FILE_DEVICE_SECURE_OPEN         0x00000100

For a description of these values, see IoCreateDevice.

The characteristics values specified using a DeviceCharacteristics entry will be OR'ed with those specified in each call to IoCreateDevice that creates a device object on the device stack. The OR operation occurs after all device objects have been added, but before the device is started.

The characteristics value (including a value of zero) overrides any class-wide device characteristics that were specified in the associated class installer INF.

DeviceType
A DeviceType entry specifies a device type for the device. The device-type is the numeric value of a FILE_DEVICE_XXX constant defined in wdm.h or ntddk.h. For more information, see Specifying Device Types. The flag value of 0x10001 specifies that the device-type value is a REG_DWORD.

A class-installer INF should specify the device type that applies to all, or almost all, of the devices in the class. For example, if the devices in the class are of type FILE_DEVICE_CD_ROM, specify a device-type of 0x02. If a device INF specifies a value for DeviceType, it overrides the value set by the class installer, if any. If the class or device INF specifies a DeviceType value, the PnP Manager applies that type to the PDO created by the device's bus driver.

Security
A Security entry specifies a security descriptor for the device. The security-descriptor-string is a string with tokens to indicate the DACL (D:) security component. See Platform SDK documentation for information about the format of security descriptor strings. A class-installer INF can specify a security descriptor for a device class. A device INF can specify a security descriptor for an individual device, overriding the security for the class. If the class and/or device INF specifies a security-descriptor-string, the PnP Manager propagates the descriptor to all the device objects for a device, including the FDO, filter DOs, and the PDO.
UpperFilters
An UpperFilters entry specifies a PnP upper-filter driver. This entry in a DDInstall.HW section defines one or more device-specific upper-filter drivers. In a ClassInstall32 section, this entry defines one or more class-wide upper-filter drivers.
LowerFilters
A LowerFilters entry specifies a PnP lower-filter driver. This entry in a DDInstall.HW section defines one or more device-specific lower-filter drivers. In a ClassInstall32 section, this entry defines one or more class-wide lower-filter drivers.
EnumPropPages32
An EnumPropPages32 entry specifies the name of a DLL file that is a device-specific property sheet provider. It also specifies the DLL's entry point.
LocationInformationOverride
A LocationInformationOverride entry can be used to specify a text string describing a device's physical location. It overrides the LocationInformation string that the device's bus driver supplies in response to an IRP_MN_QUERY_DEVICE_TEXT request.

Example

An AddReg directive referenced the (SCSI) Miniport_EventLog_AddReg section in this example, under an INF-writer-defined section referenced by the AddService directive in a DDInstall.Services section of this INF.

[Miniport_EventLog_AddReg]
HKR,,EventMessageFile,0x00020000,"%%SystemRoot%%\System32\IoLogMsg.dll"
; double quotation marks delimiters in preceding entry prevent truncation
; if line wraps

HKR,,TypesSupported,0x00010001,7

See Also

AddInterface, AddService, BitReg, ClassInstall32, DDInstall, DDInstall.CoInstallers, DDInstall.HW, DDInstall.Interfaces, DDInstall.Services, DelReg, InterfaceInstall32, Strings


INF DelReg Directive

[DDInstall] |
[DDInstall.HW] |
[DDInstall.CoInstallers] |
[ClassInstall32] |
[ClassInstall32.ntx86] |
[ClassInstall32.ntia64]

DelReg=del-registry-section[, del-registry-section] ...

A DelReg directive references one or more INF-writer-defined sections describing keys and/or value entries to be removed from the registry.

A DelReg directive can be specified under any of the sections shown in the formal syntax statement above. This directive also can be specified under any of the following INF-writer-defined sections:

  • A service—install-section or event—log-install section referenced by the AddService directive in a DDInstall.Services section
  • An add—interface-section referenced by the AddInterface directive in a DDInstall.Interfaces section
  • An install-interface-section referenced in an InterfaceInstall32 section

Comments

In general, an INF should never attempt to delete subkeys or value entries within existing subkeys that were set up by system components or by the INF files for other devices. The purpose of a delete-registry section is to clean stale registry information from a previous installation using a new INF file supplied by the same provider.

Each del-registry-section name must be unique to the INF file, but it can be referenced by DelReg directives in other sections of the same INF. Each section name must follow the general rules for defining section names described in General Syntax Rules for INF Files. For more information about how to use the system-defined .nt, .ntx86, and .ntia64 extensions, see Creating an INF File.

Each named section referenced by a DelReg directive has the following form:

[del-registry-section]
reg-root-string, subkey[, value-entry-name][, flags][, value]
reg-root-string, subkey[, value-entry-name][, flags][, value]
...

A del-registry-section can have any number of entries, each on a separate line.

DelReg-Referenced Section Entries

reg-root-string
Identifies the root of the registry tree for other values supplied in this entry. The value can be one of the following:
HKCR
Abbreviation for HKEY_CLASSES_ROOT.
HKCU
Abbreviation for HKEY_CURRENT_USER.
HKLM
Abbreviation for HKEY_LOCAL_MACHINE.
HKU
Abbreviation for HKEY_USERS.
HKR
Relative root – that is, keys specified using this abbreviation are relative to the registry key associated with the INF section in which this DelReg directive appears, as indicated in the following table.
INF Section Containing DelReg Directive | Registry Key Referenced by HKR
INF DDInstall section | The device's software key
INF DDInstall.HW section | The device's hardware key
INF DDInstall.Services section | The Services key

For more information about a device's software and hardware keys, see SetupDiOpenDevRegKey.

Note that HKR cannot be used in an del-registry-section referenced from an INF DefaultInstall section.

For more information about driver information stored under the HKEY_LOCAL_MACHINE root, see Driver Information in the Registry.

subkey
This value, formed either as a %strkey% token defined in a Strings section of the INF or as a registry path under the given reg-root (key1\key2\key3...), specifies one of the following:
  • A subkey to be deleted from the registry at the end of the given registry path
  • An existing subkey from which the given value-entry-name is to be deleted
value-entry-name
This value identifies a named value entry to be removed from the given subkey. This value and its preceding comma should be omitted if the subkey itself is being removed from the registry. (See additional information below.)
flags
(Windows XP and later.) This optional hexadecimal value, expressed as an ORed bitmask of system-defined low word and high word flag values, defines the data type for a value entry, or controls the delete-registry operation. If flags is not specified, the value-entry-name (if specified) or subkey will be deleted. Bitmask values for each of these flags are as follows:
0x00002000 (FLG_DELREG_KEYONLY_COMMON)
Delete the entire subkey.
0x00004000 (FLG_DELREG_32BITKEY)
Make the specified change in the 32-bit registry. If not specified, the change is made to the native registry.
0x00018002 (FLG_DELREG_MULTI_SZ_DELSTRING)
Within a multi-string registry entry, delete all strings matching a string value specified by value. Case is ignored.
value
(Windows XP and later.) Specifies a registry value, if flags indicates a registry value is required. For Windows XP, only the FLG_DELREG_MULTI_SZ_DELSTRING flag requires a value. Otherwise this value is omitted.

With operating system versions prior to Windows XP, the only way to delete a key is by specifying:

reg-root-string, subkey

For Windows XP and later, the following is also permitted (to specify the 32-bit registry):

reg-root-string, subkey,,0x4000

Example

This example shows how the system-supplied COM/LPT ports class installer's INF removes stale NT-specific registry information about COM ports from the registry.

[ComPort.NT]
CopyFiles=ComPort.NT.Copy
AddReg=ComPort.AddReg, ComPort.NT.AddReg
 ... ; more directives omitted here

[ComPort.NT.HW]
DelReg=ComPort.NT.HW.DelReg

[ComPort.NT.Copy]
serial.sys
serenum.sys

[Comport.NT.AddReg]
HKR,,EnumPropPages32,,"MSPorts.dll,SerialPortPropPageProvider"

[ComPort.NT.HW.DelReg]
HKR,,UpperFilters

See Also

AddReg, AddInterface, AddService, BitReg, ClassInstall32, DDInstall, DDInstall.CoInstallers, DDInstall.HW, DDInstall.Services, InterfaceInstall32, Strings


INF BitReg Directive

[DDInstall] |
[DDInstall.HW] |
[DDInstall.CoInstallers] |
[ClassInstall32] |
[ClassInstall32.ntx86] |
[ClassInstall32.ntia64]

BitReg=bit-registry-section[,bit-registry-section]...

A BitReg directive references one or more INF-writer-defined sections used to set or clear bits within an existing REG_BINARY-type value entry in the registry. However, this directive is very rarely used in device/driver INF files.

A BitReg directive can be specified under any of the sections shown in the formal syntax statement above. This directive also can be specified under any of the following INF-writer-defined sections:

  • A service—install-section or event—log-install section referenced by the AddService directive in a DDInstall.Services section
  • An add—interface-section referenced by the AddInterface directive in a DDInstall.Interfaces section
  • An install-interface-section referenced in an InterfaceInstall32 section

Comments

Eachbit-registy-section name must be unique to the INF file, but it can be referenced by BitReg directives in other sections of the same INF. Each INF-writer-created section name must be unique within the INF and must follow the same general rules for defining section names already described in General Syntax Rules for INF Files. For more information about how to use the system-defined .nt, .ntx86, and .ntia64 extensions in cross-platform and dual-OS INF files, see Creating an INF File.

Each named section referenced by an BitReg directive has the following form:

[bit-registry-section]
reg-root, [subkey], value-entry-name, [flags], byte-mask, byte-to-modify
reg-root, [subkey], value-entry-name, [flags], byte-mask, byte-to-modify
...

A bit-registry-section can have any number of entries, each on a separate line.

BitReg-Referenced Section Entries

reg-root
Identifies the root of the registry tree for other values supplied in this entry. The value can be one of the following:
HKCR
Abbreviation for HKEY_CLASSES_ROOT.
HKCU
Abbreviation for HKEY_CURRENT_USER.
HKLM
Abbreviation for HKEY_LOCAL_MACHINE.
HKU
Abbreviation for HKEY_USERS.
HKR
Relative root – that is, keys specified using this abbreviation are relative to the registry key associated with the INF section in which this BitReg directive appears, as indicated in the following table.
INF Section Containing BitReg Directive | Registry Key Referenced by HKR
INF DDInstall section | The device's software key
INF DDInstall.HW section | The device's hardware key
INF DDInstall.Services section | The Services key

For more information about a device's software and hardware keys, see SetupDiOpenDevRegKey.

Note that HKR cannot be used in an bit-registry-section referenced from an INF DefaultInstall section.

For more information about driver information stored under the HKEY_LOCAL_MACHINE root, see Driver Information in the Registry.

subkey
This optional value, expressed either as a %strkey% token defined in a Strings section of the INF or as a registry path under the given reg-root (key1\key2\key3...), specifies the key containing the value entry to be modified.
value-entry-name
Specifies the name of an existing REG_BINARY-type value entry in the (existing) subkey to be modified. It can be expressed either as "quoted string" or as a %strkey% token that is defined in the INF's Strings section.
flags
This optional hexadecimal value, expressed as an ORed bitmask of system-defined low word and high word flag values, specifieswhether to clear or set the bits specified in the given byte-mask. Its default value is zero, meaning clear the bits in the 64-bit section of the registry. Specify one to set the bits. Bitmask values for each of these flags are as follows:
0x00000000 (FLG_BITREG_CLEARBITS)
Clear the bits specified by byte-mask.
0x00000001 (FLG_BITREG_SETBITS)
Set the bits specified by byte-mask.
0x00004000 (FLG_BITREG_32BITKEY)
(Windows XP and later.) Make the specified change in the 32-bit registry. If not specified, the change is made to the native registry.
byte-mask
This byte-sized mask, expressed in hexadecimal notation, specifies which bits to clear or set in the current value of the given value-entry-name.
byte-to-modify
This byte-sized value, expressed in decimal, specifies the zero-based index of the byte within the REG_BINARY-type value to be modified.

Comments

The value of an existing REG_BINARY-type value entry also can be modified by simply overwriting its current value within an add-registry section elsewhere in the INF file. For more information about add-registry sections, see the reference for the AddReg directive.

Using a BitReg directive requires the definition of another INF file section. However, the value of an existing REG_BINARY-type value entry can be modified bit-by-bit in such a section, thereby preserving the values of all remaining bits.

Examples

These examples show a bit-registry section for a fictional application.

[AppX_BitReg]
; set first bit of byte 0 in ProgramData value entry
HKLM,Software\AppX,ProgramData,1,0x01,0
; preceding would change value 30,00,10 to 31,00,10

; clear high bit of byte 2 in ProgramData value entry
HKLM,Software\AppX,ProgramData,,0x80,2
; preceding would change value 30,00,f0 to 30,00,70

; set second and third bits of byte 1 in ProgramData value entry
HKLM,Software\AppX,ProgramData,1,0x06,1
; preceding would change value 30,00,f0 to 30,06,f0

See Also

AddInterface, AddReg, AddService, ClassInstall32, DDInstall, DDInstall.CoInstallers, DDInstall.HW, InterfaceInstall32


INF CopyFiles Directive

[DDInstall] |
[DDInstall.CoInstallers] |
[ClassInstall32] |
[ClassInstall32.ntx86] |
[ClassInstall32.ntia64]

CopyFiles=@filename | file-list-section[, file-list-section]...

A CopyFiles directive can do either of the following:

  • Cause a single file to be copied from the source media to the default destination directory.
  • Reference one or more INF-writer-defined sections in the INF that each specify a list of files to be copied from the source media to the destination.

Do not use CopyFiles directives to copy INF files. See Copying INFs.

A CopyFiles directive can be specified within any of the sections shown in the formal syntax statement. This directive also can be specified within any of the following INF-writer-defined sections:

  • An add-interface-section referenced by the AddInterface directive in a DDInstall.Interfaces section
  • An install-interface-section referenced in an InterfaceInstall32 section

Comments

Any file-list-section name must be unique to the INF file, but it can be referenced by CopyFiles, DelFiles, or RenFiles directives elsewhere in the same INF. Such an INF-writer-defined section name must follow the same general rules for defining section names already described in General Syntax Rules for INF Files. For more information about how to use the system-defined .nt, .ntx86, and .ntia64 extensions in cross-platform and dual-OS INF files, see also Creating an INF File.

Each named section referenced by a CopyFiles directive has one or more entries of the following form:

[file-list-section]
destination-file-name[,source-file-name][,temporary-file-name][,flag]
...

An INF-writer-defined file-list-section can have any number of entries, each on a separate line.

CopyFiles-Referenced Section Entries

destination-file-name
Specifies the name of the destination file. If no source-file-name is given, this specification is also the name of the source file.
source-file-name
Specifies the name of the source file. If the source and destination file names for the file copy operation are the same, source-file-name can be omitted.
temporary-file-name
Specifies the name of a temporary file to be created in the copy operation if a file of the same name on the destination is open or currently in use. Only used on Windows 9x/Me platforms. The NT-based OS automatically generates temporary file names when necessary and renames the copied source files the next time the OS is started.
flag
These optional flags, expressed in hexadecimal notation or as a decimal value in a section entry, can be used to control how (or whether) a particular source file is copied to the destination. One or more (ORed) values for the following system-defined flags can be specified, but some of these flags are mutually exclusive:
0x00000400 (COPYFLG_REPLACEONLY)
Copy the source file to the destination directory only if the file is already present in the destination directory.
0x00000800 (COPYFLG_NODECOMP)
Copy the source file to the destination directory without decompressing the source file if it is compressed.
0x00000008 (COPYFLG_FORCE_FILE_IN_USE)
Force file-in-use behavior: do not copy over an existing file of the same name if it is currently open. Instead, copy the given source file with a temporary name so that it can be renamed and used when the next reboot occurs.
0x00000010 (COPYFLG_NO_OVERWRITE)
Do not replace an existing file in the destination directory with a source file of the same name. This flag cannot be combined with any other flags.
0x00001000 (COPYFLG_REPLACE_BOOT_FILE)
This file is required by the system loader. The system will prompt the user to reboot the system.
0x00002000 (COPYFLG_NOPRUNE)
Do not delete this operation as a result of optimization.

For example, Setup might determine that the file copy operation is not necessary because the file already exists. However, the writer of the INF knows that the operation is required and directs Setup to override its optimization and perform the file operation. (This flag can be used to ensure that files are copied if they are also specified in an INF DelFiles directive or an INF RenFiles directive.)

0x00000020 (COPYFLG_NO_VERSION_DIALOG)
Do not write over a file in the destination directory with the source file if the existing file is newer than the source file.

This flag is irrelevant to digitally signed INF files. If a driver package is digitally signed, Setup installs the package as a whole and does not selectively omit files in the package based on other versions already present on the machine.

0x00000004 (COPYFLG_NOVERSIONCHECK)
Ignore file versions and write over existing files in the destination directory. This flag and the next two are mutually exclusive. This flag is irrelevant to digitally signed INF files.
0x00000040 (COPYFLG_OVERWRITE_OLDER_ONLY)
Copy the source file to the destination directory only if the file on the destination will be superseded by a newer version. This flag is irrelevant to digitally signed INF files.
0x00000001 (COPYFLG_WARN_IF_SKIP)
Send a warning if the user elects to not copy a file. This flag and the next are mutually exclusive, and both are irrelevant to INF files that are digitally signed.
0x00000002 (COPYFLG_NOSKIP)
Do not allow the user to skip copying a file. This flag is implied if the driver package is signed.

The DestinationDirs section of an INF file controls the destination for all file-copy operations, whatever the section containing a particular CopyFiles directive, as follows:

  • If a named section referenced by a CopyFiles directive has a corresponding entry in the DestinationDirs section of the same INF, that entry explicitly specifies the target destination directory into which all files listed in the named section will be copied. If the named section is not listed in the DestinationDirs section, Setup uses the DefaultDestDir in the INF.
  • If a CopyFiles directive uses the @filename syntax, Setup uses the DefaultDestDir entry in the DestinationDirs section of the INF.

The INF also supplies path specifications to files copied from source media in either of the following ways:

  • In IHV/OEM-supplied INF files, by using the SourceDisksNames and, possibly, SourceDisksFiles sections of this INF to explicitly specify the full path to each named source file that is not in the root directory (or directories) on the distribution media
  • In system-supplied INF files, by supplying one or more additional INF files, identified by name in the LayoutFile entry of the INF's Version section

Example

This example shows how the SourceDisksNames, SourceDisksFiles, and DestinationDirs sections specify the paths for copy-file (and delete-file) operations that occur in processing a simple device-driver INF. (The same INF was also used previously as examples of Version, SourceDisksNames, and SourceDisksFiles sections.)

[SourceDisksNames]
1 = %Floppy_Description%,,,\Win98 ; path to Win98 source files
2 = %Floppy_Description%,,,\WinNT

[SourceDisksFiles]
aha154x.mpd = 1,, ; on distribution disk 1, in subdir \win98

[SourceDisksFiles.x86]
aha154x.sys = 2,\x86 ; on distribution disk 2, in subdir \WinNT\x86

[DestinationDirs]
ASPIDEV = 11  ; Win98-specific del-file section
              ; delete existing files from DIRID_SYSTEM
DefaultDestDir = 12  ; DIRID_DRIVERS
                     ; == \System32\Drivers on Windows NT platforms
                     ; == \System\IoSubsys on Win9x platforms

; ... Manufacturer and Models sections omitted here

; Win9x-specific DDInstall, given [AHA154X.NTx86] in this INF
[AHA154X]
CopyFiles=@AHA154x.MPD
DelFiles=ASPIDEV ; defines a delete-files section not shown here
; ... some other directives and sections omitted here

[AHA154X.NTx86]
CopyFiles=@AHA154x.SYS
; ... some other directives and sections omitted here
; ...

This example shows how a CopyFiles directive can be used in a DDInstall.CoInstallers section of an INF for a device driver that provides two device-specific co-installers to supplement the INF processing of the system device-type-specific class installer.

[DestinationDirs]
XxDev_Coinstallers_CopyFiles = 11  ; DIRID_SYSTEM
; ... other file-list entries and DefaultDestDirs omitted here

; ... Manufacturer, Models, and DDInstall sections omitted here

[XxDev_Install.CoInstallers]
CopyFiles=XxDev_Coinstallers_CopyFiles
; ... AddReg omitted here

[XxDev_Coinstallers_CopyFiles]
XxPreInst.dll   ; dev-specific co-installer run before class installer
XxPostInst.dll  ; run after class installer (post processing)

As the preceding example suggests, the names of new device-specific co-installers can be constructed from the name of the provider (shown here as Xx) and the intended use for each such co-installer DLL (shown here as PreInst and PostInst).

See Also

AddInterface, ClassInstall32, DDInstall, DDInstall.CoInstallers, DDInstall.Interfaces, DelFiles, DestinationDirs, InterfaceInstall32, RenFiles, SourceDisksFiles, SourceDisksNames, Version


INF CopyINF Directive

Windows XP and later

[DDInstall]

CopyINF=filename1.inf[,filename2.inf]...

A CopyINF directive causes specified INF files to be copied to the target system.

Comments

This directive is typically used when installing multifunction devices. If the installation of a multifunction device requires multiple INF files (for multiple functions belonging to multiple setup classes), then using this directive insures that Setup will find the INF files when installing the functions. Use the following rules:

  • If the functions supplied by a multifunction device are enumerated as children of a parent device (such as an IEEE 1284.4 device), the INF file for the parent device should have a CopyINF directive to copy the INF files for the device's individual functions.
  • If all functions supplied by a multifunction device (such as a PCI card) are enumerated as peers of each other, the INF file for each function should have a CopyINF directive to copy the INF files for all peer functions.

If you follow these rules, Setup can install drivers for each function without prompting the user for an installation disk for each function.

Setup copies the specified INF files as part of the default processing for DIF_INSTALLDEVICE (see SetupDiInstallDevice), after the device has been successfully installed.

The locations of INF files specified in the CopyINF directive are relative to the source location of the INF file containing the CopyINF directive.

Setup copies the specified INF files into a system directory path that it will search during device installations.

You must include all INF files on each disk of a multi-disk installation.

System support for the CopyINF directive is available in Windows XP and later OS versions. You can also use the directive with Windows 2000 if you install and register the cocpyinf co-installer, which is supplied with this DDK in the /tools directory.

For additional information about copying INF files, see Copying INFs.

Example

[MyMfDevice.NTx86]
CopyINF = Sound.INF


INF DelFiles Directive

[DDInstall] |
[DDInstall.CoInstallers] |
[ClassInstall32] |
[ClassInstall32.ntx86] |
[ClassInstall32.ntia64]

Delfiles=file-list-section[, file-list-section]...

A DelFiles directive references an INF-writer-defined section elsewhere in the INF file, causing that list of files to be deleted in the context of operations on the section in which the referring DelFiles directive is specified.

A DelFiles directive can be specified within any of the sections shown in the formal syntax statement. This directive also can be specified within any of the following INF-writer-defined sections:

  • An add-interface-section referenced by the AddInterface directive in a DDInstall.Interfaces section
  • An install-interface-section referenced in an InterfaceInstall32 section

Comments

This directive is rarely used. The only files that can be safely deleted are those that were used only in earlier versions of the operating system, and are thus never used for the currently installed version. (For Windows XP and later, you can use the TargetOSVersion decoration to control version-specific installation behavior. See INF Manufacturer Section.)

Any file-list-section name must be unique to the INF file, but it can be referenced by CopyFiles, DelFiles, or RenFiles directives elsewhere in the same INF. Such an INF-writer-defined section name must follow the same general rules for defining section names already described in General Syntax Rules for INF Files. For more information about how to use the system-defined .nt, .ntx86, and .ntia64 extensions in cross-platform and dual-OS INF files, see also Creating an INF File.

Each named section referenced by a DelFiles directive has one or more entries of the following form:

[file-list-section]

destination-file-name[,,,flag]
...

A file-list-section can have any number of entries, each on a separate line.

DelFiles-Referenced Section Entries

destination-file-name
Specifies the name of the file to be deleted from the destination.

Do not specify a file that is listed in a CopyFiles directive. If a file is listed in both a CopyFiles-referenced and a DelFiles-referenced section, and the file is currently present on the system with a valid signature, the OS might optimize away the copy operation but perform the delete operation. This is very likely not what the INF writer intended.

flag
This optional value can be one of the following, expressed in hexadecimal notation as shown here or as a decimal value:
0x00000001 (DELFLG_IN_USE)
Delete the named file, possibly after it has been used during the installation process.

Setting this flag value in an INF queues the file-deletion operation until the system has restarted if the given file cannot be deleted because it is in use while this INF is being processed. Otherwise, such a file will not be deleted.

0x00010000 (DELFLG_IN_USE1)
This flag is a high-word version of the DELFLG_IN_USE flag, and it has the same purpose and effect. This flag should be used in only for installations on NT-based systems.

Setting this flag value in an INF prevents conflicts with the COPYFLG_WARN_IF_SKIP flag in an INF with both DelFiles and CopyFiles directives that reference the same file-list-section.

The DestinationDirs section of the INF file controls the destination for all file-deletion operations, whatever the section containing a particular DelFiles directive, as follows:

  • If a named section referenced by a DelFiles directive has a corresponding entry in the DestinationDirs section of the same INF, that entry explicitly specifies the target destination directory from which all files listed in the named section will be deleted. If the named section is not listed in the DestinationDirs section, Setup uses the DefaultDestDir entry in the INF.

Example

This example shows how the DestinationDirs section specifies the path for a delete-file operation that occurs in processing a simple device-driver INF. (The same INF was also used previously as an example of the CopyFiles directive.)

[DestinationDirs]
ASPIDEV = 11  ; name of Win9x-specific delete-file section
              ; delete existing files from DIRID_SYSTEM
DefaultDestDir = 12  ; DIRID_DRIVERS

; ...

[AHA154X] ; Win9x-specific DDInstall section
CopyFiles=@AHA154x.MPD
DelFiles=ASPIDEV ; defines delete-files section name
; ... some other directives and sections omitted here

[ASPIDEV]
VASPID.VXD ; name of file to be deleted, if it exists on target
; ...

See Also

AddInterface, ClassInstall32, CopyFiles, DDInstall, DDInstall.CoInstallers, DestinationDirs, InterfaceInstall32, RenFiles


INF RenFiles Directive

[DDInstall] |
[DDInstall.CoInstallers] |
[ClassInstall32] |
[ClassInstall32.ntx86] |
[ClassInstall32.ntia64]

Renfiles=file-list-section[, file-list-section]...

A RenFiles directive references an INF-writer-defined section elsewhere in the INF file, causing that list of files to be renamed in the context of operations on the section in which the referring RenFiles directive is specified.

A RenFiles directive can be specified within any of the sections shown in the formal syntax statement. This directive also can be specified within any of the following INF-writer-defined sections:

  • An add-interface-section referenced by the AddInterface directive in a DDInstall.Interfaces section
  • An install-interface-section referenced in an InterfaceInstall32 section

Comments

This directive is rarely used. The only files that can be safely renamed are those that were used only in earlier versions of the operating system, and are thus never used for the currently installed version. (For Windows XP and later, you can use the TargetOSVersion decoration to control version-specific installation behavior. See INF Manufacturer Section.)

Any file-list-section name must be unique to the INF file, but it can be referenced by CopyFiles, DelFiles, or RenFiles directives elsewhere in the same INF. Such an INF-writer-defined section name must follow the same general rules for defining section names already described in General Syntax Rules for INF Files. For more information about how to use the system-defined .nt, .ntx86, and .ntia64 extensions in cross-platform and dual-OS INF files, see also Creating an INF File.

Each named section referenced by a RenFiles directive has one or more entries of the following form:

[file-list-section]

new-dest-file-name,old-source-file-name
...

A file-list-section can have any number of entries, each on a separate line.

RenFiles-Referenced Section Entries

new-dest-file-name
Specifies the new name to be given to the file on the destination.
old-source-file-name
Specifies the old name of the file.

The DestinationDirs section of the INF file controls the destination for all file-rename operations, whatever the section containing a particular RenFiles directive, as follows:

  • If a named section referenced by a RenFiles directive has a corresponding entry in the DestinationDirs section in the same INF, that entry explicitly specifies the target destination directory in which all files listed in the named section will be renamed on the destination before these source files are copied. If the section is not listed in the DestinationDirs section, Setup uses the DefaultDestDir entry in the INF.

Example

This example shows a section referenced by a RenFiles directive.

[RenameOldFilesSec]
devfile41.sav, devfile41.sys

See Also

AddInterface, ClassInstall32, CopyFiles, DDInstall, DDInstall.CoInstallers, DelFiles, DestinationDirs, InterfaceInstall32, SourceDisksFiles, SourceDisksNames, Version


INF AddService Directive

[DDInstall.Services]

AddService=ServiceName,[flags],service-install-section[,
event-log-install-section[,[EventLogType][,EventName]]]
...

An AddService directive is used to control how (and when) the services of particular Windows 2000 or later device's drivers are loaded, any dependencies on other underlying legacy drivers or services, and so forth. Optionally, this directive sets up event-logging services by the devices/drivers as well.

This directive is irrelevant to exclusively Windows 9x INF files. It also is not used in INF files that install devices, such as modems or display monitors, that do not require any drivers.

Entry Values

ServiceName
Specifies the name of the service to be installed. For a device, this value is usually a generic name for its driver, such as "sermouse," or some such name.
flags
Specifies one or more (ORed) of the following system-defined flags, defined in setupapi.h, expressed as a hexadecimal value:
0x00000002 (SPSVCINST_ASSOCSERVICE)
Assign the named service as the PnP function driver (or legacy driver) for the device being installed by this INF file. Do not specify this flag when installing filter drivers or other driver components not directly associated with a device. Set this flag for only one driver for each INF DDIinstall.Services section.
0x00000008 (SPSVCINST_NOCLOBBER_DISPLAYNAME)
Do not overwrite the given service's (optional) friendly name if this service already exists in the system.
0x00000100 (SPSVCINST_NOCLOBBER_DESCRIPTION)
Do not overwrite the given service's (optional) description if this service already exists in the system.
0x00000010 (SPSVCINST_NOCLOBBER_STARTTYPE)
Do not overwrite the given service's start type if this named service already exists in the system.
0x00000020 (SPSVCINST_NOCLOBBER_ERRORCONTROL)
Do not overwrite the given service's error-control value if this named service already exists in the system.
0x00000040 (SPSVCINST_NOCLOBBER_LOADORDERGROUP)
Do not overwrite the given service's load-order-group value if this named service already exists in the system. INF files that install exclusively PnP devices and devices with WDM drivers should not set this flag.
0x00000080 (SPSVCINST_NOCLOBBER_DEPENDENCIES)
Do not overwrite the given service's dependencies list if this named service already exists in the system. INF files that install exclusively PnP devices and devices with WDM drivers should not set this flag.
0x00000001 (SPSVCINST_TAGTOFRONT)
Move the named service's tag to the front of its group order list, thereby ensuring that it is loaded first within that group (unless a subsequently installed device with this INF specification displaces it). INF files that install exclusively PnP devices and devices with WDM drivers should not set this flag.
service-install-section
References an INF-writer-defined section that contains information for installing the named service for this device (or devices).
event-log-install-section
Optionally references an INF-writer-defined section in which event-logging services for this device (or devices) are set up.
EventLogType
Optionally specifies one of System, Security, or Application. If omitted, this defaults to System, which is almost always the appropriate value for the installation of device drivers. For example, an INF would specify Security only if the to-be-installed driver provides its own security support.
EventName
Optionally specifies a name to use for the event log. If omitted, this defaults to the given ServiceName.

Comments

The system-defined and case-insensitive extensions can be inserted into a DDInstall.Services section containing an AddService directive in cross-OS and/or cross-platform INF files to specify platform-specific or OS-specific installations. For more information about how to use the system-defined .nt, .ntx86, and .ntia64 extensions in cross-platform and dual-OS INF files, see also Creating an INF File.

Each INF-writer-created section name must be unique within the INF and must follow the same general rules for defining section names already described in General Syntax Rules for INF Files.

An AddService directive must reference a named service-install-section elsewhere in the INF file. Each such named section has the following form:

[service-install-section]

[DisplayName=name]
[Description=description-string]
ServiceType=type-code
StartType=start-code
ErrorControl=error-control-level
ServiceBinary=path-to-service
[StartName=driver-object-name]
[AddReg=add-registry-section[, add-registry-section] ...]
[DelReg=del-registry-section[, del-registry-section] ...]
[BitReg=bit-registry-section[,bit-registry-section] ...]
[LoadOrderGroup=load-order-group-name]
[Dependencies=depend-on-item-name[,depend-on-item-name]...]

Any service-install-section must have at least the ServiceType, StartType, ErrorControl, and ServiceBinary entries as shown here, but the remaining entries are optional.

Service-Install Section Entries and Values

DisplayName=name
Specifies a friendly name for the service/driver, usually, for ease of localization, expressed as a %strkey% token defined in a Strings section of the INF file.
Description=description-string
Optionally specifies a string that describes the service, usually expressed as a %strkey% token defined in a Strings section of the INF file.

This string gives the user more information about the service than the DisplayName. For example, the DisplayName might be something like "DHCP Client" and the Description might be something like "Manages network configuration by registering and updating IP addresses and DNS names".

The description-string should be long enough to be descriptive but not so long as to be awkward. If a description-string contains any %strkey% tokens, each token can represent a maximum of 511 characters. The total string, after any string token substitutions, should be no longer than 1024 characters. Most strings will be shorter.

ServiceType=type-code
In any INF that installs support for one or more devices, the type-code specification must be 1 or 0x00000001 (that is, equivalent to SERVICE_KERNEL_DRIVER).

A device-dedicated application supplied when installing the device would be classified as either of SERVICE_WIN32_OWN_PROCESS (specified as 10 or 0x00000010 in the INF) or SERVICE_WIN32_SHARE_PROCESS (specified as 20 or 0x00000020 in the INF).

A highest level network driver, such as a redirector, or a file system would be classified as SERVICE_FILE_SYSTEM_DRIVER by specifying 2 or 0x00000002 in its INF.

The SERVICE_xxxx constants are defined in wdm.h and ntddk.h.

StartType=start-code
Specifies when to start the driver as one of the following numerical values, expressed either in decimal or, as shown here, in hexadecimal notation.
0x0 (SERVICE_BOOT_START)
Indicates a driver started by the operating system loader.

This value must be used for drivers of devices required for loading the operating system.

0x1 (SERVICE_SYSTEM_START)
Indicates a driver started during OS initialization.

This value should be used by PnP drivers that do device detection during initialization but are not required to load the system.

For example, a PnP driver that also can detect a legacy device should specify this value in its INF so that its DriverEntry routine will be called to find the legacy device, even if that device cannot be enumerated by the PnP Manager.

0x2 (SERVICE_AUTO_START)
Indicates a driver started by the Service Control Manager during system startup.

This value should never be used in the INF files for WDM or PnP device drivers.

0x3 (SERVICE_DEMAND_START)
Indicates a driver started on demand, either by the PnP Manager when the corresponding device is enumerated or possibly by the Service Control Manager in response to an explicit user demand for a nonPnP device.

This value should be used in the INF files for all WDM drivers of devices that are not required to load the system and for all PnP device drivers that are neither required to load the system nor engaged in device detection.

0x4 (SERVICE_DISABLED)
Indicates a driver that cannot be started.

This value can be used to temporarily disable the driver services for a device, but a device/driver cannot be installed if this value is specified in the service-install section of its INF file.

For additional information about StartType, see Specifying Driver Load Order.

ErrorControl=error-control-level
Specifies the level of error control as one of the following numerical values, expressed either in decimal or, as shown here, in hexadecimal notation.
0x0 (SERVICE_ERROR_IGNORE)
If the driver fails to load or initialize, proceed with system startup and do not display a warning to the user.
0x1 (SERVICE_ERROR_NORMAL)
If the driver fails to load or initialize its device, system startup should proceed but display a warning to the user.
0x2 (SERVICE_ERROR_SEVERE)
If the driver fails to load, system startup should switch to the registry's LastKnownGood control set and continue system startup, even if the driver again indicates a loading or device/driver initialization error.
0x3 (SERVICE_ERROR_CRITICAL)
If the driver fails to load and system startup is not using the registry's LastKnownGood control set, switch to LastKnownGood and try again. If startup still fails when using LastKnownGood, run a bug-check routine. (Only devices/drivers necessary for the system to boot specify this value in their INF files.)
ServiceBinary=path-to-service
Specifies the path to the binary for the service, expressed as %dirid%\filename.

The dirid number is one of the system-defined directory identifiers already described in the reference for the DestinationDirs section. The given filename specifies a file already transferred (see the INF CopyFiles directive) from the source distribution media to that directory on the target machine.

StartName=driver-object-name
This optional entry specifies the name of the driver object representing this device/driver. If type-code specifies 1 or 2 (SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER), this name is the driver object name that the I/O Manager uses to load the driver.
AddReg=add-registry-section[, add-registry-section] ...
References one or more INF-writer-defined add-registry-sections in which any registry information pertinent to the newly installed services is set up. This directive is rarely used in a service-install-section. An HKR specification in such an add-registry-section designates the HKLM\System\CurrentControlSet\Services\ServiceName registry key. For more information, see INF AddReg Directive.
DelReg=del-registry-section[, del-registry-section] ...
References one or more INF-writer-defined del-registry-sections in which pertinent registry information for an already installed services is removed. An HKR specification in such a del-registry-section designates the HKLM\System\CurrentControlSet\Services\ServiceName registry key. This directive is almost never used in a service-install-section, but it might be used in an INF that "updates" the registry for a previous installation of the same device/driver services. For more information see INF DelReg Directive.
BitReg=bit-registry-section[,bit-registry-section] ...
Is valid in a service-install-section but almost never used. An HKR specification in such a bit-registry-section also designates the HKLM\System\CurrentControlSet\Services\ServiceName registry key.
LoadOrderGroup=load-order-group-name
This optional entry identifies the load order group of which this driver is a member. It can be one of the "standard" load order groups, such as SCSI class or NDIS, defined by previous versions of Windows NT®.

In general, this entry is unnecessary for devices with WDM drivers or for exclusively PnP devices, unless there are legacy dependencies on such a group. However, this entry can be useful if device detection is supported by loading a group of drivers in a particular order.

For additional information about LoadOrderGroup, see Specifying Driver Load Order.

Dependencies=depend-on-item-name[,depend-on-item-name]...
Each depend-on-item-name in a dependencies list specifies the name of a service or load-order group on which the device/driver depends.

If the depend-on-item-name specifies a service, the service that must be running before this driver is started. For example, the INF for the system-supplied Win32 TCP/IP print services depends on the support of the underlying (kernel-mode) TCP/IP transport stack. Consequently, the INF for the TCP/IP print services specifies this entry as Dependencies =TCPIP.

A depend-on-item-name can specify a load order group on which this device/driver depends. Such a driver is started only if at least one member of the specified group has been started. Preceed the group name with a plus sign (+). For example, the system RAS services INF might have an entry like Dependencies = +NetBIOSGroup,RpcSS, which lists both a load-order group and a service.

The OS loads drivers according to the service-install section start-code specifications of their INF files, as follows:

  1. During the system boot start phase, the OS loads all 0x0 (SERVICE_BOOT_START) drivers.
  2. During the system start phase, the OS first loads all WDM and PnP drivers for which the PnP Manager finds devnodes in the registry ..\Enum tree (whether their INF files say 0x01 for SERVICE_SYSTEM_START or 0x03 for SERVICE_DEMAND_START).Then the OS loads all remaining SERVICE_SYSTEM_START drivers.
  3. During the system auto-start phase, the OS loads all remaining SERVICE_AUTO_START drivers.

    For additional information about Dependencies, see Specifying Driver Load Order.

Registering for Event Logging

An AddService directive also can reference an INF-writer-defined event-log-install-section elsewhere in the INF file. Each such named section referenced by an AddService directive has the following form:

[event-log-install-section]

AddReg=add-registry-section[, add-registry-section]...
[DelReg=del-registry-section[, del-registry-section]...]
[BitReg=bit-registry-section[,bit-registry-section]...]
...

For a typical device/driver INF, the event-log-install-section uses only the AddReg directive to set up an event-logging message file for the driver. An HKR specification in an add-registry-section designates the HKLM\System\CurrentControlSet\Services\
EventLog\EventLogType\EventName registry key. This event-logging add-registry-section has the following general form:

[drivername_EventLog_AddReg]
HKR,,EventMessageFile,0x00020000,"path\IoLogMsg.dll;path\driver.sys"
HKR,,TypesSupported,0x00010001,7

In particular, the section adds two value entries in the registry subkey created for the device/driver, as follows:

  • The value entry named EventMessageFile is of type REG_EXPAND_SZ, as specified by the FLG_ADDREG_TYPE_EXPAND_SZ value 0x00020000. Its value, enclosed in double quotation marks ("), associates the system-supplied IoLogMsg.dll (but it could associate another logging DLL) with the driver binary file. Usually, the paths to each of these files is expressed as follows:

    %%SystemRoot%%\System32\IoLogMsg.dll, and %%SystemRoot%%\System32\drivers\driver.sys, unless the driver binary was copied into another subdirectory on the target machine, as specified in the INF DestinationDirs section or in a section referenced by an INF CopyFiles directive.

  • The value entry named TypesSupported is of type REG_DWORD, as specified by the FLG_ADDREG_TYPE_DWORD value 0x00010001. For drivers, this value should be 7 (equivalent to the OR of EVENTLOG_SUCCESS, EVENTLOG_ERROR_TYPE, EVENTLOG_WARNING_TYPE, and EVENTLOG_INFORMATION_TYPE, without setting the EVENTLOG_AUDIT_XXX bits).

An event-log-install-section also can use the DelReg directive to remove a previously installed event-log message file, by explicitly deleting the existing EventMessageFile and TypesSupported value entries, if a driver binary is being superseded by a newly installed driver. (See also INF DelService directive.) While a BitReg directive also is valid within an INF-writer-defined event-log-install-section, it is almost never used, because the standard value entries for device driver event logging are not bitmasks.

Example

This example shows the service-install and event-log-install sections referenced by the AddService directive as already shown earlier in the example for DDInstall.Services.

[sermouse_Service_Inst]
DisplayName    = %sermouse.SvcDesc%
ServiceType    = 1                   ; = SERVICE_KERNEL_DRIVER
StartType      = 3                   ; = SERVICE_DEMAND_START
ErrorControl   = 1                   ; = SERVICE_ERROR_NORMAL
ServiceBinary  = %12%\sermouse.sys
LoadOrderGroup = Pointer Port

[sermouse_EventLog_Inst]
AddReg = sermouse_EventLog_AddReg

[sermouse_EventLog_AddReg]
HKR,,EventMessageFile,0x00020000,"%%SystemRoot%%\System32\IoLogMsg.dll;
       %%SystemRoot%%\System32\drivers\sermouse.sys"
;
; Preceding entry on single line in INF file. Enclosing quotation marks
; prevent the semicolon from being interpreted as a comment.
;
HKR,,TypesSupported,0x00010001,7

[mouclass_Service_Inst]
DisplayName    = %mouclass.SvcDesc%
ServiceType    = 1                   ; = SERVICE_KERNEL_DRIVER
StartType      = 1                   ; = SERVICE_SYSTEM_START
ErrorControl   = 1                   ; = SERVICE_ERROR_NORMAL
ServiceBinary  = %12%\mouclass.sys
LoadOrderGroup = Pointer Class

[mouclass_EventLog_Inst]
AddReg = mouclass_EventLog_AddReg

[mouclass_EventLog_AddReg]
HKR,,EventMessageFile,0x0002000,"%%SystemRoot%%\System32\IoLogMsg.dll;
       %%SystemRoot%%\System32\drivers\mouclass.sys"
HKR,,TypesSupported,0x00010001,7
; ...
[Strings]
; ...
sermouse.SvcDesc = "Serial Mouse Driver"
mouclass.SvcDesc = "Mouse Class Driver"

The example in the reference for the DDInstall.HW section, described earlier, also shows some service-install sections referenced by the AddService directive to set up PnP upper-filter drivers.

See Also

AddReg, BitReg, CopyFiles, DDInstall.HW, DDInstall.Services, DelReg, DelService, DestinationDirs, Strings


INF DelService Directive

[DDInstall.Services]

DelService=ServiceName[,[flags][,[EventLogType][,EventName]]]
...

A DelService directive is used in a DDInstall.Services section to remove one or more previously installed device/driver services from the target machine.

Entry Values

ServiceName
Specifies the name of the service to be removed.

For a device, this value is usually a generic name for its driver, such as "sermouse," or some such name.

flags
This optional value is specifies one or more of the following flags, defined in setupapi.h, expressed as a hexadecimal value:
0x00000004 (SPSVCINST_DELETEEVENTLOGENTRY)
An event-log entry (or entries) associated with the given ServiceName should also be removed from the system.
0x00000200 (SPSVCINST_STOPSERVICE)
Stop the service before deleting it.
EventLogType
Optionally specifies one of System, Security, or Application. This can be omitted if the event log to be removed is of type System.
EventName
Optionally specifies the name for the event log. This can be omitted if it is identical to the given ServiceName.

Comments

This directive is rarely used. The only services that can be safely deleted are those that were used only in earlier versions of the operating system, and are thus never used for the currently installed version. (For Windows XP and later, you can use the TargetOSVersion decoration to control version-specific installation behavior. See INF Manufacturer Section.)

However, by default, event-log information supplied by a particular device driver is not removed from the system on deinstallation, unless the INF for the device/driver explicitly requests the removal (flags or EventName) of the event log along with the removal of the driver services.

See Also

AddService, DDInstall.Services, DelReg


INF AddInterface Directive

[DDInstall.Interfaces]
AddInterface={InterfaceClassGUID} [, [reference string] [,[add-interface-section] [,flags]]]

One or more AddInterface directives can be specified within an INF DDInstall.Interfaces section to install support for device interface classes exported to higher level components, such as other drivers or applications, and to reference the add-interface-section typically used for setting up registry information about the device/driver support of each instance of device interface class.

An exported device interface class can be one of the system-defined device interface classes, such as those defined by kernel streaming, or a new device interface class specified by an INF InterfaceInstall32 section.

Entry Values

InterfaceClassGUID
Specifies the GUID value that identifies the device interface class. This can be expressed as an explicit GUID value of the form {nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn} or as a %strkey% token defined to "{nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn}" in a Strings section of the INF file.

For more information about how to create a GUID, see Using GUIDs in Drivers. For the system-defined interface class GUIDS, see the appropriate header, such as ks.h for the kernel-streaming interface GUIDs.

reference string
This optional value associated, with the device-specific instance of the specified interface class, can be expressed either as a "quoted string" or as a %strkey% token defined in an INF Strings section.

PnP function and filter drivers usually omit this value from the AddInterface= entries in their INF files.A reference string is used by the swenum driver, as a placeholder for software devices that are created on demand, using multiple instances of a single interface class. The same InterfaceClassGUID value can be specified in INF entries with two or more unique reference strings. Because the I/O Manager passes the reference string value as a path component of the interface instance's name whenever it is opened, the installed driver can discriminate between interface instances of the same class for a single device.

add-interface-section
References the name of a section elsewhere in the INF file, which typically contains an INF AddReg directive to set up the registry entries exporting the driver's support of this device interface class. For more information, see the following Comments section.
flags
If specified, must be zero.

Comments

If the device interface class identified by a given {InterfaceClassGUID} is not installed already, the system setup code installs that class in the system. Any INF that installs a new class also has an INF InterfaceInstall32 section containing the specified {InterfaceClassGUID} and referencing an interface-install-section that sets up interface-specific installation operations for that class.

To enable an instance of a device interface class for runtime use by higher level components, the driver must make a call IoSetDeviceInterfaceState with each {InterfaceClassGUID} value identifying a device interface class that the driver supports on the underlying device. As an alternative to registering its support for a device interface class in its INF, a device driver can call IoRegisterDeviceInterface before making its initial call to IoSetDeviceInterfaceState. Usually, a PnP function or filter driver makes this call from its AddDevice routine.

Each AddInterface directive in an INF DDInstall.Interfaces section can reference an INF-writer-defined add-interface-section elsewhere in the INF file. Each INF-writer-defined section name must be unique within the INF and must follow the same general rules for defining section names already described in General Syntax Rules for INF Files.

An add-interface-section referenced by the AddInterface directive has the following form:

[add-interface-section]

AddReg=add-registry-section[, add-registry-section]...
[DelReg=del-registry-section[, del-registry-section] ...]
[BitReg=bit-registry-section[,bit-registry-section] ...]
[CopyFiles=@filename | file-list-section[,file-list-section]...]
[DelFiles=file-list-section[,file-list-section]...]
[RenFiles=file-list-section[,file-list-section]...]
[UpdateInis=update-ini-section[, update-ini-section] ...]
[UpdateIniFields=update-inifields-section[, update-inifields-section] ...]
[Ini2Reg=ini-to-registry-section[, ini-to-registry-section] ...]

Typically, an add-interface-section contains only an INF AddReg directive that, in turn, references a single add-registry-section. The add-registry-section is used to store information in the registry about the interfaces supported by the device driver for subsequent use by still higher level drivers and applications.

An add-registry-section referenced within an add-interface-section is both device/driver-specific and interface instance-specific in nature. It might have a value entry defining a friendly name for the exported device interface instance so that still higher level components can refer to that interface by its friendly name in the user interface. An HKR specified in such an add-registry-section section designates the user-mode-accessible device-interface subkey of the ..DeviceClasses\{InterfaceClassGUID}\ branch. In the registry, DeviceClasses is a subkey of the ..CurrentControlSet\Control key.

Example

This example shows some of the expansion of the DDInstall.Interfaces section for a particular audio device that supports system-defined kernel-streaming interfaces.

; ...
[ESS6881.Device.Interfaces]
AddInterface=%KSCATEGORY_AUDIO%,%KSNAME_Wave%,ESSAud.Interface.Wave
AddInterface=%KSCATEGORY_RENDER%,%KSNAME_Wave%,ESSAud.Interface.Wave
AddInterface=%KSCATEGORY_CAPTURE%,%KSNAME_Wave%,ESSAud.Interface.Wave
AddInterface=%KSCATEGORY_AUDIO%,%KSNAME_Topology%,\
ESSAud.Interface.Topology
AddInterface=%KSCATEGORY_AUDIO%,%KSNAME_UART%,WDM.Interface.UART
AddInterface=%KSCATEGORY_RENDER%,%KSNAME_UART%,WDM.Interface.UART
AddInterface=%KSCATEGORY_CAPTURE%,%KSNAME_UART%,WDM.Interface.UART
AddInterface=%KSCATEGORY_AUDIO%,%KSNAME_FMSynth%,WDM.Interface.FMSynth
AddInterface=%KSCATEGORY_RENDER%,%KSNAME_FMSynth%,\
WDM.Interface.FMSynth

[ESSAud.Interface.Wave]
AddReg=ESSAud.Interface.Wave.AddReg

[ESSAud.Interface.Wave.AddReg]
HKR,,CLSID,,%Proxy.CLSID%
HKR,,FriendlyName,,%ESSAud.Wave.szPname%
; ...
[WDM.Interface.UART]
AddReg=WDM.Interface.UART.AddReg

[WDM.Interface.UART.AddReg]
HKR,,CLSID,,%Proxy.CLSID%
HKR,,FriendlyName,,%WDM.UART.szPname%
; ...
[Strings]
KSCATEGORY_AUDIO="{6994ad04-93ef-11d0-a3cc-00a0c9223196}"
KSCATEGORY_RENDER="{65e8773e-8f56-11d0-a3b9-00a0c9223196}"
KSCATEGORY_CAPTURE="{65e8773d-8f56-11d0-a3b9-00a0c9223196}"
; ...
KSNAME_WAVE="Wave"
KSNAME_UART="UART"
; ...
Proxy.CLSID="{17cca71b-ecd7-11d0-b908-00a0c9223196}"
; ...
ESSAud.Wave.szPname="ESS AudioDrive"
; ...

See Also

AddReg, BitReg, CopyFiles, DDInstall.Interfaces, DelFiles, DelReg, Ini2Reg, InterfaceInstall32, IoRegisterDeviceInterface, IoSetDeviceInterfaceState, RenFiles, UpdateIniFields, UpdateInis


INF LogConfig Directive

[DDInstall] |
[DDInstall.LogConfigOverride]

LogConfig=log-config-section[,log-config-section]...

A LogConfig directive references one or more INF-writer-defined sections, each of which specifies a logical configuration of hardware resources – the interrupt request lines, memory ranges, I/O ports, and DMA channels that can be used by the device. Each log-config-section specifies an alternative set of bus-relative hardware resources that can be used by the device.

INF files for non-PnP devices use this directive to create basic configurations.

INF files for PnP devices use this directive only to create override configurations.

Comments

A LogConfig directive can be specified under any per-manufacturer, per-models INF DDInstall section or INF DDInstall.LogConfigOverride section.

An INF for a non-PnP device that supports several alternate logical configurations typically defines a set of log-config sections under a DDInstall section. Each log-config section specifies a discrete set of logical configuration resources. It also includes a ConfigPriority entry, which ranks each logical configuration according to its effects on device and driver performance, ease of initialization, and so forth.

For PnP devices, the PnP Manager assigns a set of logical hardware resources to each PnP device. That is, the PnP Manager queries the system bus drivers, receives their reports of per-device I/O bus configuration resources in use, and assigns per-device sets of logical hardware resources to achieve the best system-wide balance in the usage of all such resources.

For PnP devices, the LogConfig directive under a DDInstall section is ignored. To override the resources reported by the bus for a PnP device, include the LogConfig directive under a DDInstall.LogConfigOverride section. In this case, the resources specified in the log-config-section will be used instead of those reported by the bus. For more information, see INF DDInstall.LogConfigOverride Section.

Platform extensions can be added to a DDInstall section containing a LogConfig directive, or to a DDInstall.LogConfigOverride section, to specify platform-specific or OS-specific logical configurations. For more information, see Creating an INF File.

A given log-config-section name must be unique to the INF file, but it can be referenced by LogConfig directives in other INF DDInstall sections for the same devices. Each INF-writer-created section name must be unique within the INF and must follow the same general rules for defining section names already described in General Syntax Rules for INF Files.

Each named section referenced by a LogConfig directive has the following form:

[log-config-section]

ConfigPriority=Priority_Value[,Config_Type]
[DMAConfig=[DMAattrs:]DMANum[,DMANum]...]
[IOConfig=io-range[,io-range]...]
[MemConfig=mem-range[,mem-range]...]
[IRQConfig=[IRQattrs:]IRQNum[,IRQNum]...]
[PcCardConfig=ConfigIndex[:[MemoryCardBase1][:MemoryCardBase2]][(attrs)]]
[MfCardConfig=ConfigRegBase:ConfigOptions[:IoResourceIndex][(attrs)]...]
...

Only one ConfigPriority entry can be used in each log-config-section. There can be more than one of each of the other entries, depending on the hardware resource requirements of the device.

One or more MfCardConfig= entries can appear only in a log-config-section that is referenced by a LogConfig directive in the DDInstall.LogConfigOverride section of an INF for a multifunction device. For more information about INF files for multifunction devices, see Supporting Multifunction Devices.

LogConfig-Referenced Section Entries and Values

ConfigPriority=Priority_Value[,Config_Type]
Specifies the priority value for this logical configuration, as one of the following:
DESIRED
Soft configured, most optimal.
NORMAL
Soft configured, less optimal than DESIRED. This is the typical setting.

NORMAL should be specified if the log-config section was defined in a DDInstall.LogConfigOverride section, and no Config_Type value can be specified.

SUBOPTIMAL
Soft configured, less optimal than NORMAL.
HARDRECONFIG
Requires a jumper change to reconfigure.
HARDWIRED
Cannot be changed.
RESTART
Requires restart to take effect.
REBOOT
For Windows 2000 and later, this is the same as RESTART.
POWEROFF
Requires power cycle to take effect.
DISABLED
Hardware/device is disabled.

Config_Type is obsolete in Windows 2000 and later INF files.

DMAConfig=[DMAattrs:]DMANum[,DMANum]...]
DMAattrs is optional if the device is connected on a bus that has only 8-bit DMA channels and the device uses standard system DMA. Otherwise, it can be one of the letters D for 32-bit DMA, W for 16-bit DMA, and N for 8-bit DMA, with M if the device uses busmaster DMA and with one of the following (mutually exclusive) letters, indicating the type of DMA channel used: A, B, or F. If none of A, B, or F is specified, a standard DMA channel is assumed.

DMANum specifies one or more bus-relative DMA channels as decimal numbers, each separated from the next by a comma (,).

IOConfig=io-range[,io-range]...
Specifies one or more I/O port ranges for the device, in either of the following forms:

start-end[([decode-mask][:alias-offset][:attr])]
(Type 1 I/O range) where:

start specifies the starting address of the I/O port range as a 64-bit hexadecimal address.

end specifies the ending address of the I/O port range, also as a 64-bit hexadecimal address.

decode-mask defines the alias type and can be any of the following:

Mask Value | Meaning | IOR_Alias =
3ff | 10-bit decode | 0x04
fff | 12-bit decode | 0x10
ffff | 16-bit decode | 0x00
0 | positive decode | 0xFF

alias-offset is ignored.

attr specifies the letter M if the given range is in system memory. If omitted, the given range is in I/O port space.

size@min-max[%align-mask][([decode-mask][:alias-offset][:attr])]
(Type 2 I/O range) where:

size specifies the number of bytes required for the I/O port range as a 32-bit hexadecimal value.

min specifies the lowest possible starting address of the I/O port range as a 64-bit hexadecimal address.

max specifies the highest possible ending address of the I/O port range as a 64-bit hexadecimal address.

align-mask optionally specifies a 64-bit mask that is used in an AND operation to align the start of the I/O port range on an integral (usually 32-bit or 64-bit) address boundary.

decode-mask defines the alias type and can be any of the following:

Mask Value | Meaning | IOR_Alias =
3ff | 10-bit decode | 0x04
fff | 12-bit decode | 0x10
ffff | 16-bit decode | 0x00
0 | positive decode | 0xFF

alias-offset is ignored.

attr specifies the letter M if the given range is in system memory. If omitted, the given range is in I/O port space.

MemConfig=mem-range[,mem-range]...
Specifies one or more memory ranges for the device in either of the following forms:

start-end[(attr)] | size@min-max[%align-mask][(attr)]
where:

start specifies the starting (bus-relative) physical address of the device memory range as a 64-bit hexadecimal value.

end specifies the ending physical address of the memory range, also as a 64-bit hexadecimal value.

attr specifies the attributes of the memory range as one or more of the following letters: R (read-only), W (write-only), RW (read/write), C (combined write allowed), H (cacheable), F (prefetchable), and D (card decode addressing is 32-bit, instead of 24-bit). If both R and W are specified or if neither is specified, read/write is assumed.

size specifies the number of bytes required in the memory range as a 32-bit hexadecimal value.

min specifies the lowest possible starting address of the device memory range as a 64-bit hexadecimal value.

max specifies the highest possible ending address of the memory range as a 64-bit hexadecimal value.

align-mask optionally specifies a 64-bit mask that is used in an AND operation to align the start of the device memory range on an integral (usually 64-bit) address boundary. If align-mask is omitted, the default memory alignment is on a 4K boundary (FFFFF000).

IRQConfig=[IRQattrs:]IRQNum[,IRQNum]...
IRQattrs is omitted if the device uses a bus-relative, edge-triggered IRQ. Otherwise, specify L to indicate a level-triggered IRQ and LS if the device can share the IRQ lines listed in this entry.

IRQNum specifies one or more bus-relative IRQs the device can use as decimal numbers, each separated from the next by a comma (,).

PcCardConfig=ConfigIndex[:[MemoryCardBase1][:MemoryCardBase2]][(attrs)]
Configures PCMCIA card registers and/or creates up to two permanent memory windows that map to the attribute space of the device. A driver can use the memory windows to access the attribute space from an ISR. Specify all numeric values in hexadecimal format.

The elements of a PcCardConfig entry are as follows:

ConfigIndex
Specifies the 8-bit PCMCIA configuration index for a device on a PCMCIA bus.
MemoryCardBase1
Optionally specifies a 32-bit base address for a first memory window.
MemoryCardBase2
Optionally specifies a 32-bit base address for a second memory window.
attrs
Optionally specifies one or more attributes for the device, separated by spaces. An invalid attribute specifier invalidates the whole PcCardConfig entry. If more than one specifier for a particular attribute is provided, the attributes are applied to individual I/O or memory windows for the device. If only one specifier is provided, then that attribute is applied to all windows (see the following example).

Specifically, if multiple specifiers are provided, the first specifier found reading from left to right will be applied to the first window, and the next specifier applied to the second window. A maximum of two I/O windows and two memory windows may be controlled by a single PcCardConfig directive. If the device has more than two memory windows, then a second PcCardConfig directive must be included.

The attributes include:
Attribute | Description
W | 16-bit I/O data path. The default is 8-bit if the INF specifies a LogConfig. If there is no LogConfig, the driver uses 16-bit I/O.
S n | ~IOCS16 source. If n is 0, ~IOCS16 is based on the value of the datasize bit. If n is 1, ~IOCS16 is based on the ~IOIS16 signal from the device. The default is S1.
Z n | I/O 8-bit, zero wait state. If n is 1, 8-bit I/O accesses occur with zero additional wait states. If n is 0, access will occur with additional wait states. This flag has no meaning for 16-bit I/O. The default is Z0.
XI n | I/O wait states. If n is 1, 16-bit system accesses occur with one additional wait state. The default is X1.
M | 16-bit memory data path. The default is 8-bit.
M8 | 8-bit memory data path.
XM n | Memory wait states, where n can be 0, 1, 2 or 3. This value determines the number of additional wait states for 16-bit accesses to a memory window. The default is XM3.
A | Memory range to be mapped as Attribute memory
C | Memory range to be mapped as Common Memory (default)

For example, an attrs value of (WB CA M XM1 XI0) translates to:

1st I/O window is 16-bit
2nd I/O window 8-bit
1st memory window is common
2nd memory window is attribute
memory 16-bit
one wait state on memory windows
zero wait states on I/O windows

MfCardConfig=ConfigRegBase:ConfigOptions[:IoResourceIndex][(attrs)]...
Specifies the attribute-memory location of the set of configuration registers for one function of a multifunction device, as follows:

ConfigRegBase specifies the attribute offset of the configuration registers for this function of the multifunction device.

ConfigOptions specifies the 8-bit PCMCIA configuration option register.

IoResourceIndex specifies the index to the IOConfig entry for the bus driver to use in programming the configuration I/O base and limit registers. This index is zero-based, that is, zero designates the initial IOConfig entry in this log-config section.

attrs can be A if the PCMCIA bus driver should turn on audio enable in the configuration and status registers.

Each MfCardConfig entry supplies information about a single function of the multifunction device. When a set of LogConfig directives each reference a discrete log-config section in the INF's DDInstall.LogConfigOverride section, each such log-config section must have its entries, including MfCardConfig entries, listed in the same order.

From a log-config-section, the system installer builds binary logical configuration records and stores them in the registry.

An INF file can contain any number of per-device log-config sections. However, each such section must contain complete information for installing one device. In general, the INF should specify the entries in each of its log-config sections in the same order. The INF should specify each set of entries in the order best suited to how the driver initializes its device.

If more than one log-config-section is present for a given device, only one of these INF sections will be used during installation. Such an INF file partially controls which such section is used with the ConfigPriority value it supplies in each such log-config section. That is, the system installers attempt to honor any configurationpriorities in an INF file, but might choose a lower ranked logical configuration if a conflict with an already installed device is found.

During installation, one and only one resource from each entry in a given log-config-section is selected and assigned to a particular device. If a particular device needs more than one resource of the same type, a set of entries of that type must be used in its log-config-sections. For example, to ensure two I/O port ranges for a particular device, two IOConfig= entries must be specified in the log-config-section for that device. On the other hand, if a device requires no IRQ, its INF can simply omit the IRQConfig entry from the log-config-sections.

Examples

This example shows some valid PcCardConfig entries for a PCMCIA device.

PcCardConfig=0:E0000:F0000(W)
PcCardConfig=0:E0000(M)
PcCardConfig=0::(W)
PcCardConfig=0(W)

This example shows a Type 1 I/O range specification in an IOConfig entry. It specifies an I/O port region, eight bytes in size, which can start at 1F8, 2F8, or 3F8.

IOConfig=1F8-1FF, 2F8-2FF, 3F8-3FF

By contrast, this example shows a Type 2 I/O range specification in an IOConfig entry. It specifies an I/O port region, eight bytes in size, which can start at 300, 308, 310, 318, 320, or 328.

IOConfig=8@300-32F%FF8

This example shows a set of IOConfig= entries for a four-port device, each specifying an I/O port range that is offset by 0x400 bytes from the next.

IoConfig=0x200-0x21f
IoConfig=0x600-0x61f
IoConfig=0xA00-0xA1f
IoConfig=0xE00-0xE1f

The next two examples show typical MemConfig entries.

This example specifies a memory region of 32K bytes that can start at either C0000 or D0000.

MemConfig=C0000-C7FFF, D0000-D7FFF

This example specifies a memory region of 32k bytes starting on 64K boundaries.

MemConfig=8000@C0000-D7FFF%F0000

This example shows how the system HDC class INF file sets up a number of log-config sections for generic ESDI hard disk controllers and uses a DDInstall.LogConfigOverride section for a particular IDE controller.

[MS_HDC] ; per-manufacturer Models section
%FujitsuIdePccard.DeviceDesc% =
          atapi_fujitsu_Inst, PCMCIA\FUJITSU-IDE-PC_CARD-DDF2
%*PNP0600.DeviceDesc% = atapi_Inst, *PNP0600 ; generic ESDI HDCs
%PCI\CC_0101.DeviceDesc% = pciide_Inst,,PCI\CC_0101

; ... other manufacturers' Models sections omitted

[atapi_Inst]
CopyFiles = @atapi.sys
LogConfig = esdilc1, esdilc2, esdilc3, esdilc4

; ... [atapi_Inst.Services] + service/EventLog-install omitted here

[esdilc1]
ConfigPriority=HARDWIRED
IOConfig=1f0-1f7(3ff::)
IoConfig=3f6-3f6(3ff::)
IRQConfig=14

[esdilc2]
ConfigPriority=HARDWIRED
IOConfig=170-177(3ff::)
IoConfig=376-376(3ff::)
IRQConfig=15

[esdilc3]
ConfigPriority=HARDWIRED
IOConfig=1e8-1ef(3ff::)
IoConfig=3ee-3ee(3ff::)
IRQConfig=11

[esdilc4]
; ...

[atapi_fujitsu_Inst.LogConfigOverride]
LogConfig = fujitsu.LogConfig0

[fujitsu.LogConfig0]
ConfigPriority=NORMAL
IOConfig=10@100-400%fff0
IRQConfig=14,15,5,7,9,11,12,3
PcCardConfig=1:0:0(W)

For some examples of how MfCardConfig entries are used, see Supporting PC Cards That Have Incomplete Configuration Register Addresses.

See Also

DDInstall, DDInstall.FactDef


INF ProfileItems Directive

[DDInstall]

ProfileItems=profile-items-section[,profile-items-section]...
...

A ProfileItems directive is used in an INF DDInstall section to list one or more profile-items-sections that contain items or groups to be added to, or removed from, the Start menu.

This directive is only supported on Windows 2000 and later.

Comments

A given profile-items-section name must be unique to the INF file.

Each INF-writer-defined section name must be unique within the INF and must follow the same general rules for defining section names described in General Syntax Rules for INF Files.

Each named section referenced by a ProfileItems directive has the following form:

[profile-items-section]

Name=link-name[,name-attributes]
CmdLine=dirid,[subdir],filename
[SubDir=path]
[WorkingDir=wd-dirid,wd-subdir]
[IconPath=icon-dirid,[icon-subdir],icon-filename]
[IconIndex=index-value]
[HotKey=hotkey-value]
[Infotip=info-tip]
[DisplayResource="ResDllPath\ResDll",ResID] (Windows XP and later)

Each profile-items-section contains detailed information for creating or removing one Start menu item or group. To manipulate more than one menu item or group from an INF, create more than one profile-items-section and list the sections in the ProfileItems directive.

Any of the string parameters specified in the profile-items-section entries can be specified using a %strkey% token, as described at the beginning of this chapter (General Syntax Rules for INF Files).

ProfileItems-Referenced Section Entries and Values

Name=link-name[,name-attributes]
The link-name specifies the name of the link for the menu item or group, without the .lnk extension. This value can be a string or a %strkey% token that is defined in a Strings section of the INF file. If DisplayResource is not specified, link-name is also the display string.

The optional name-attributes value specifies one or more flags that affect the operation on the menu item. This value is expressed as an ORed bitmask of system-defined flag values. Possible flags include the following:

0x00000001 (FLG_PROFITEM_CURRENTUSER)
Directs Setup to create or delete a Start menu item in the current user's profile. If this flag is not specified, Setup processes the item for all users.
0x00000002 (FLG_PROFITEM_DELETE)
Directs Setup to delete the menu item. If this flag is not specified, the item is created.
0x00000004 (FLG_PROFITEM_GROUP)
Directs Setup to create or delete a Start menu group under Start\Programs. If this flag is not specified, Setup creates or deletes a menu item, not a menu group.

If no flag is specified, Setup creates a menu item for all users.

CmdLine=dirid,[subdir],filename
The dirid specifies a value that identifies the directory in which the command program resides. For example, a dirid of 11 indicates the system directory. The possible dirid values are listed in the description of the dirid value in the DestinationDirs section.

If a subdir string is present, the command program is in a subdirectory of the directory referenced by dirid. The subdir specifies the subdirectory. If no subdir is specified, the program resides in the directory referenced by dirid.

The filename specifies the name of the program associated with the menu item.

SubDir=path
This optional entry specifies a subdirectory (submenu) under Start\Programs in which the menu item resides. If this entry is omitted, the path defaults to Start\Programs.

For example, if the profile-items-section has the entry "Subdir=Accessories\Games", then the menu item is being created or deleted in the Start\Programs\Accessories\Games submenu.

If FLG_PROFITEM_GROUP is specified for name-attributes, SubDir is ignored.

WorkingDir=wd-dirid[,wd-subdir]
This optional entry specifies a working directory for the command program. If this entry is omitted, the working directory defaults to the directory in which the command program resides.

The wd-dirid value identifies the working directory. The possible dirid values are listed in the description of the dirid value in the DestinationDirs section.

The wd-subdir string, if present, specifies a subdirectory of wd-dirid to be the working directory. Use this parameter to specify a directory that doesn't have a system-defined dirid. If this parameter is omitted, the wd-dirid value alone specifies the working directory.

IconPath=icon-dirid,[icon-subdir],icon-filename
This optional entry specifies the location of a file that contains an icon for the menu item.

The icon-dirid string identifies the directory for the DLL that contains the icon. The possible icon-dirid values are listed in the description of the dirid value in the DestinationDirs section.

The icon-subdir value, if present, indicates that the DLL is in a subdirectory of icon-dirid. The icon-subdir value specifies the subdirectory.

The icon-filename value specifies the DLL that contains the icon.

If this entry is omitted, Setup looks for an icon in the file specified in the CmdLine entry.

IconIndex=index-value
This optional entry specifies which icon in a DLL to use for the menu item. For information on indexing the icons in a DLL, see the Platform SDK documentation.

If an IconPath entry is specified, the index-value indexes into that DLL. Otherwise, this value indexes into the file specified in the CmdLine entry.

HotKey=hotkey-value
This optional entry specifies a keyboard accelerator for the menu item. See the Platform SDK documentation for more information on hot keys.
Infotip=info-tip
This optional entry specifies an informational tip for the menu item.

This value can be a string or a %strkey% token that is defined in a Strings section of the INF file.

For Windows XP and later, the Infotip value can also be specified as "@ResDllPath\ResDll,-ResID", where ResDllPath and ResDll specify the path and filename of a resource DLL, and -resID is a negative value representing a resource ID. Use this format to support Windows Multilanguage User Interface (MUI). An example is:

InfoTip = "@%11%\shell32.dll,-22531"
DisplayResource="ResDllPath\ResDll",ResID
(Windows XP and later.) This optional entry specifies a string resource that identifies a localizable string, to be used in the Start menu as the display name for shortcut or group. ResDllPath and ResDll specify the path and filename of a resource DLL, and resID is a positive value representing a resource ID. An example is:
DisplayResource="%11%\shell32.dll",22019

Use this entry to support Windows Multilanguage User Interface (MUI). If this entry is not used, the string specified by the Name entry is displayed.

Examples

The following INF file excerpt illustrates how to use profile-items-sections to add Calculator to the Start Menu.

[CalcInstallItems]
Name = %Calc_DESC%
CmdLine = 11,, calc.exe
SubDir = %Access_GROUP%
WorkingDir = 11
InfoTip = "%Calc_InfoTip"
:
:
[Strings]
Calc_DESC = "Calculator"
Calc_TIP = "Performs basic arithmetic tasks with an on-screen calculator"

The following INF file excerpt illustrates how to install the same software using the DisplayResource entry to create localized menu items.

[CalcInstallItems]
Name = %Calc_DESC%
CmdLine = 11,, calc.exe
SubDir = %Access_GROUP%
WorkingDir = 11
InfoTip = "@%11%\shell32.dll,-22531"
DisplayResource="%11%\shell32.dll",22019
:
:
[Strings]
Calc_DESC = "Calculator"

See Also

DDInstall


INF UpdateInis Directive

[DDInstall] |
[DDInstall.CoInstallers] |
[ClassInstall32] |
[ClassInstall32.nt] |
[ClassInstall32.ntx86] |
[ClassInstall32.ntia64]

UpdateInis=update-ini-section[, update-ini-section] ...

An UpdateInis directive references one or more named sections, specifying an INI file from which a particular section or lineis to be read and applied to an existing INI file of the same name on the target machine. Optionally, line-by-line modifications from and to such INI files can be specified in the update-ini-section.

This directive is almost never specified in INF files for installation on NT-based systems, due to the lack of necessity for INI files. However, the UpdateInis directive is valid in any of the sections shown in the formal syntax statement, as well as in INF-writer-defined sections referenced by an AddInterface directive or referenced in an InterfaceInstall32 section.

Comments

A given update-ini-section name must be unique to the INF file.

Each INF-writer-created section name must be unique within the INF and must follow the same general rules for defining section names already described in General Syntax Rules for INF Files. For more information about how to use the system-defined .nt, .ntx86, and .ntia64 extensions in cross-platform and dual-OS INF files, see also Creating an INF File.

Each named section referenced by an UpdateInis directive has the following form:

[update-ini-section]

ini-file,ini-section[,old-ini-entry][,new-ini-entry][,flags]
...

An update-ini-section can have any INF-writer-determined number of entries, each on a separate line.

UpdateInis-Referenced Section Entries

ini-file
Specifies the name of an INI file supplied on the source media and, implicitly, that of the INI file to be updated on the target machine. This value can be expressed as a filename or as a %strkey% token that is defined in a Strings section of the INF file.
ini-section
Specifies the name of the section within the given INI file. If the next two values are specified, this section contains an entry to be changed. If an old-ini-entry is omitted but a new-ini-entry is provided, the new entry is to be added as this section is read.
old-ini-entry
This optional value specifies the name of an entry in the given ini-section, usually expressed in the form "key=value". Either or both of key and value can be expressed as %strkey% tokens defined in a Strings section of the INF file. The asterisk (*) can be specified as a wild-card for either the key or the value.
new-ini-entry
This optional value specifies either a change to a given old-ini-entry or the addition of a new entry. This value can be expressed in the same manner as old-ini-entry.
flags
This optional value controls the interpretation of the given old-ini-entry and/or new-ini-entry. The flags can be one of the following numerical values:
Value | Meaning
0 This is the default value for the flags if it is omitted.

If the given old-ini-entry key is present in the INI files, replace that key=value with the given new-ini-entry. Only the keys in the INI files must match; the corresponding value of each such key is ignored.

To add a new-ini-entry to the destination INI file unconditionally, omit the old-ini-entry value from the entry in the update-ini section of the INF. To delete an old-ini-entry from the destination INI file unconditionally, omit the new-ini-entry value.
1 | If the given old-ini-entry (key=value) exists in the INI files, replace it in the destination INI file with the given new-ini-entry. Both the key and value of the given old-ini-entry must match those in the INI files for such a replacement to be made, not just their keys as for the preceding flags value.
2 If the key specified for old-ini-entry cannot be found in the destination INI file, do nothing. Otherwise, the changes made depend on matches found in the INI files for the given keys of old-ini-entry and new-ini-entry, as follows:

If the key of the old-ini-entry exists in the INI files but so does the key of the new-ini-entry, replace the old-ini-entry with the new-ini-entry in the destination INI file and, then, remove the superfluous new-ini-entry from that INI file.

If the key of the old-ini-entry exists in the INI files but the key of the new-ini-entry does not, replace the old-ini-entry key with that of the new-ini-entry in the destination INI file but leave the value of the old-ini-entry unchanged.
3 If the key and value specified for old-ini-entry cannot be found in the INI files, do nothing. Otherwise, the changes made depend on matches found in the INI files for the given keys and values of old-ini-entry and new-ini-entry, as follows:

If the key=value of the old-ini-entry exists in the INI files but so does the key=value of the new-ini-entry, replace the old-ini-entry with the new-ini-entry in the destination INI file and, then, remove the superfluous new-ini-entry from that INI file.

If the key=value of the old-ini-entry exists in the INI files but the new-ini-entry does not, replace the old-ini-entry with the new-ini-entry in the destination INI file but leave the value of the old-ini-entry unchanged.

The INF provides the full path to the given ini-file on the distribution media in one of the following ways:

  • In IHV/OEM-supplied INF files, by using the SourceDisksNames and SourceDisksFiles sections of this INF to explicitly specify the full path to each named source file that is not in the root directory (or directories) on the distribution media
  • In system-supplied INF files, by supplying one or more additional INF files, identified in the LayoutFile entry in the Version section of the INF file

Any filename specified within an old-ini-entry or new-ini-entry should designate the destination directory containing that file. Such a destination directory path to a filename in an update-ini-section entry must be specified as the value of a DIRID_XXX, enclosed in % (per cent) characters and followed by a \ (back slash). That is, such a DIRID_XXX specification in an update-ini section entry has the form %dirid%\ where dirid is one of the predefined directory identifiers or is a user-defined value created by a call to the SetupSetDirectoryId function. The backslash separates the %dirid% from the given filename, as in any full path specification to a file. For example, %11%\card.ini can be used to reference card.ini in the system32 directory. The installer replaces such a specification with the full destination path to such a file during installation.

For a summary of the predefined dirid values, see the reference for the DestinationDirs section.

See Also

AddInterface, ClassInstall32, DDInstall, DDInstall.CoInstallers, DestinationDirs, Ini2Reg, InterfaceInstall32, ProfileItems, SourceDisksFiles, SourceDisksNames, Strings, UpdateIniFields, Version


INF UpdateIniFields Directive

[DDInstall] |
[DDInstall.CoInstallers] |
[ClassInstall32] |
[ClassInstall32.ntx86] |
[ClassInstall32.ntia64]

UpdateIniFields=update-inifields-section[, update-inifields-section] ...

An UpdateIniFields directive references one or more named sections in which fine-grained modifications within the lines of an INI file can be specified.

This directive is almost never specified in INF files for installations on NT-based systems, due to the lack of necessity for INI files on their distribution media. However, the UpdateIniFields directive is valid in any of the sections shown in the formal syntax statement, as well as in INF-writer-defined sections referenced by an AddInterface directive or referenced in an InterfaceInstall32 section.

Comments

A given update-inifields-section name must be unique to the INF file. Each INF-writer-created section name must be unique within the INF and must follow the same general rules for defining section names already described in General Syntax Rules for INF Files. For more information about how to use the system-defined .nt, .ntx86, and .ntia64 extensions in cross-platform and dual-OS INF files, see also Creating an INF File.

Each named section referenced by an UpdateIniFields directive has the following form:

[update-inifields-section]

ini-file,ini-section,profile-name[,old-field][,new-field][,flags]
...

An update-inifields-section can have any INF-writer-determined number of entries, each on a separate line.

By contrast with a section referenced by the UpdateInis directive, a section referenced by UpdateIniFields replaces, adds, or deletes portions of a line in an existing INI file line rather than affecting the whole value of a particular line. At least one of the old-field and/or new-field values must be specified in each section entry.

UpdateIniFields-Referenced Section Entries

ini-file
Specifies the name of an INI file supplied on the source media and, implicitly, that of a to-be-updated INI file on the target machine. This value can be expressed as a filename or as a %strkey% token that is defined in a Strings section of the INF file.
ini-section
Specifies the name of the section within the given INI files containing the line to be modified.
profile-name
Specifies the name of the line to be modified within the given INI section. At least one of the old-field and/or new-field must be specified to effect a modification of this line.
old-field
Specifies an existing field within the given line. If new-field is omitted from this section entry, this field will be deleted from the given line. Otherwise, the given new-field value should replace this field.
new-field
Specifies a replacement for a given old-field or, if old-field is omitted, an addition to the given line.
flags
Specifies (in bit 0) how to interpret given old-field and/or new-field if either or both contain an asterisk (*), and/or (in bit 1) which separator character to use when appending a given new-field to the given line, as follows:
Bit zero = 0
Interpret any asterisk (*) in the given old-field and/or new-field literally, not as a wild-card character, when searching for a match in the given line of the INI file. This is the default value.
Bit zero = 1
Interpret any asterisk (*) in the given old-field and/or new-field as a wild-card character when searching for a match in the given line of the INI file.
Bit one = 0
Use a space character as a separator when adding the given new-field to the given line of the INI file. This is the default value.
Bit one = 1
Use a comma (,) as a separator when adding the given new-field to the given line of the INI file.

Any comments in a to-be-modified INI file line are removed because they might not be applicable after changes made according to this section. When looking for fields in the line in the INI files, spaces, tabs, and commas are interpreted as field delimiters. However, a space character is used as the default separator when a new field is appended to a line.

The INF provides the full path to the given ini-file on the distribution media in one of the following ways:

  • In IHV/OEM-supplied INF files, by using the SourceDisksNames and SourceDisksFiles sections of this INF to explicitly specify the full path to each named source file that is not in the root directory (or directories) on the distribution media
  • In system-supplied INF files, by supplying one or more additional INF files, identified in the LayoutFile entry in the Version section of the INF file

See Also

AddInterface, ClassInstall32, DDInstall, DDInstall.CoInstallers, Ini2Reg, InterfaceInstall32, SourceDisksFiles, SourceDisksNames, Strings, UpdateInis, Version


INF Ini2Reg Directive

[DDInstall] |
[DDInstall.CoInstallers] |
[ClassInstall32] |
[ClassInstall32.ntx86] |
[ClassInstall32.ntia64]

Ini2Reg=ini-to-registry-section[, ini-to-registry-section] ...

An Ini2Reg directive references one or more named sections in which lines or sections from a supplied INI file are moved into the registry, thereby creating or replacing one or more value entries under a specified key.

This directive is almost never specified in INF files for installations on NT-based systems, due to the lack of necessity for INI files on their distribution media. However, the Ini2Reg directive is valid in any of the sections shown in the formal syntax statement, as well as in INF-writer-defined sections referenced by an AddInterface directive or referenced in an InterfaceInstall32 section.

Comments

A given ini-to-registry-section name must be unique to the INF file. Each INF-writer-created section name must be unique within the INF and must follow the same general rules for defining section names already described in General Syntax Rules for INF Files. For more information about how to use the system-defined .nt, .ntx86, and .ntia64 extensions in cross-platform and dual-OS INF files, see also Creating an INF File.

Each named section referenced by an Ini2Reg directive has the following form:

[ini-to-registry-section]

ini-file,ini-section,[ini-key],reg-root,subkey[,flags]
...

An ini-to-registry-section can have any INF-writer-determined number of entries, each on a separate line.

Ini2Reg-Referenced Section Entries

ini-file
Specifies the name of an INI file supplied on the source media. This value can be expressed as a filename or as a %strkey% token that is defined in a Strings section of the INF file.
ini-section
Specifies the name of the section within the given INI file containing the registry information to be copied.
ini-key
Specifies the name of the key in the INI file to copy to the registry. If this value is omitted, the whole ini-section is to be transferred to the specified registry subkey.
reg-root
Identifies the root of the registry tree for other values supplied in this entry. For specifics, see the reference for the AddReg directive.
subkey
Identifies the subkey to receive the value, expressed either as a %strkey% token defined in a Strings section of the INF or as an explicit registry path (key1\key2\key3...) from the given reg-root.
flags
Specifies (in bit 0) how to handle the INI file after transferring the given information to the registry and/or (in bit 1) whether to overwrite existing registry information, as follows:
Bit zero = 0
Do not remove the given information from the INI file after copying it into the registry. This is the default.
Bit zero = 1
Delete the given information from the INI file after moving it into the registry.
Bit one = 0
If the specified subkey already exists in the registry, do not transfer the INI-supplied information into this subkey. Otherwise, create the given subkey in the registry with this INI-supplied information as its value entry. This is the default.
Bit one = 1
If the specified subkey already exists in the registry, replace its value entry with the INI-supplied information.

The INF provides the full path to the given ini-file on the distribution media in one of the following ways:

  • In IHV/OEM-supplied INF files, by using the SourceDisksNames and, possibly, SourceDisksFiles sections of this INF to explicitly specify the full path to each named source file that is not in the root directory (or directories) on the distribution media
  • In system-supplied INF files, by supplying one or more additional INF files, identified in the LayoutFile entry in the Version section of the INF file

See Also

AddInterface, AddReg, ClassInstall32, DDInstall, DDInstall.CoInstallers, InterfaceInstall32, SourceDisksFiles, SourceDisksNames, Strings, UpdateIniFields, UpdateInis, Version


INF RegisterDlls Directive

[DDInstall]

RegisterDlls=register-dll-section[,register-dll-section]...

A RegisterDlls directive references one or more INF sections used to specify files that are OLE controls and require self-registration.

Comments

This directive is supported on Windows 2000 and later. OLE controls and self-registration are described in Platform SDK documentation.

Each register-dll-section name must be unique to the INF file and must follow the same general rules for defining section names, described in General Syntax Rules for INF Files.

Each INF section referenced by a RegisterDlls directive must have the following entry format:

[register-dll-section]

dirid, subdir, filename, registration flags[, [optional timeout][, argument]]

A register-dll-section can have any number of entries, each on a separate line.

RegisterDlls-Referenced Section Entries

dirid
Specifies the destination directory ID of the file to be registered.
subdir
Optional. Specifies the directory path, relative to the current directory, to the file to be registered. If not specified, the file is in the current directory.
filename
Identifies the file name of the OLE control to be registered.
registration flags
Indicates the registration operations to perform on the OLE control. One or both of the following flags must be specified.
Value Meaning
FLG_REGSVR_DLLREGISTER
(0x00000001) 		Call the DllRegisterServer function (described in Platform SDK documentation).
FLG_REGSVR_DLLINSTALL
(0x00000002) 		Call the DllInstall function (described in Platform SDK documentation).

timeout
Optional. Specifies the timeout, in seconds, for an OLE Control to complete the specified registration calls. The default timeout is 60 seconds.
argument
Optional. If the control is an executable file, this is a command string passed to the executable. The default argument is /RegServer.

If the control is not an executable file, this specifies the command line argument to pass to the DllInstall function.

Example

[Dialer]
RegisterDlls = DialerRegSvr

[DialerUninstall]
UnregisterDlls = DialerRegSvr

[DialerRegSvr]
11,,avtapi.dll, 1

See Also

INF UnregisterDlls Directive


INF UnregisterDlls Directive

[DDInstall]

UnregisterDlls=unregister-dll-section[,unregister-dll-section]...

An UnregisterDlls directive references one or more INF sections used to specify files that are OLE controls and require self-unregistration (self-removal).

Comments

This directive is supported on Windows 2000 and later. OLE controls and self-unregistration are described in Platform SDK documentation.

Each unregister-dll-section name must be unique to the INF file and must follow the same general rules for defining section names, described in General Syntax Rules for INF Files.

Each INF section referenced by an UnregisterDlls directive must have the following entry format:

[unregister-dll-section]

dirid, subdir, filename, registration flags[, [optional timeout][, argument]]

An unregister-dll-section can have any number of entries, each on a separate line.

UnregisterDlls-Referenced Section Entries

dirid
Specifies the destination directory ID of the file to be unregistered.
subdir
Optional. Specifies the directory path, relative to the current directory, to the file to be unregistered. If not specified, the file is in the current directory.
filename
Identifies the file name of the OLE control to be unregistered.
registration flags
Indicates the registration operations to perform on the OLE control. One or both of the following flags must be specified.
Value Meaning
FLG_REGSVR_DLLREGISTER
(0x00000001) 		Call the DllUnRegisterServer function (described in Platform SDK documentation).
FLG_REGSVR_DLLINSTALL
(0x00000002) 		Call the DllInstall function (described in Platform SDK documentation).

timeout
Optional. Specifies the timeout, in seconds, for an OLE Control to complete the specified unregistration calls. The default timeout is 60 seconds.
argument
Optional. If the control is an executable file, this is a command string passed to the executable. The default argument is /UnRegServer.

If the control is not an executable file, this specifies the command line argument to pass to the DllInstall function.

Example

[Dialer]
RegisterDlls = DialerRegSvr

[DialerUninstall]
UnregisterDlls = DialerRegSvr

[DialerRegSvr]
11,,avtapi.dll, 1

See Also

INF RegisterDlls Directive


INF DriverVer Directive

[Version] |
[DDInstall]

DriverVer=mm/dd/yyyy[,w.x.y.z]

A DriverVer directive specifies version information for drivers installed by this INF.

Entry Values

mm/dd/yyyy
This value specifies the date of the "driver package", which includes the driver files and the INF. This date must be the most recent date of any file in the driver package. The date must be specified in month/day/year order. The month and day must contain two digits, and the year must contain four digits. A hyphen (-) can be used as the date field separator in place of the slash (/).
w.x.y.z
This value specifies an optional version number. If a value is specified, w is required but x, y, z, and their preceding period characters are optional. If specified, w, x, y, and z must each be an integer that is greater than zero but less than 65535. The value is for display purposes only (for example, in the Device Manager). The OS does not use this value for driver selection.

Comments

INF files for Windows 2000 and later must have a DriverVer directive in their INF Version sections to provide version information for the whole INF. Additionally, individual INF DDInstall sections can contain DriverVer directives to provide version information for individual drivers. DriverVer directives in the DDInstall sections are more specific and take precedence over the global DriverVer directive in the Version section.

When the OS searches for drivers, it chooses a driver with a more recent DriverVer date over a driver with an earlier date. If an INF has no DriverVer directive or contains an invalid date specification, the OS applies the default date of 00/00/0000. For Windows 2000 only, unsigned drivers are also assigned a date of 00/00/0000.

INF files for Windows 98/Me must also contain DriverVer directives, but Windows 98/Me does not recognize a DriverVer directive in the Version section. Therefore, these INF files should have DriverVer directives in the undecorated DDInstall sections that are used by Windows 98/Me.

For additional information, see How Setup Selects Drivers.

Example

[Version]
...
DriverVer=09/28/1999,5.00.2136.1


General Setup Functions

This chapter summarizes the general Setup functions. Installation software can use these functions to:

  • Read and process INF files.
  • Determine the amount of free space required on the installation's target system.
  • Move files from installation source media to media on the installation's target system, while requesting user intervention as needed.
  • Create a log of files moved during an installation.

Installation software typically uses these functions in conjunction with device installation functions and PnP Configuration Manager functions.

The Setup functions listed in this chapter are described in detail in the Platform SDK documentation. Their purpose is to enable installation software.

This chapter contains the following topics:

INF File Processing Functions

Disk Prompting and Error Handling Functions

File Queuing Functions

Default Queue Callback Routine Functions

Cabinet File Function

Disk-Space List Functions

MRU Source List Functions

File Log Functions


INF File Processing Functions

The INF file processing functions provide setup and installation functionality that includes:

  • Opening and closing an INF file
  • Retrieving information about an INF file
  • Retrieving information about source files and target directories for copy operations
  • Performing the installation actions specified in an INF file section

The following table lists the functions used for processing INF files. For detailed function descriptions, see the Platform SDK documentation.

Function | Description
InstallHinfSection | Executes a specified section in a specified INF file.
SetupCloseInfFile | Frees resources and closes the INF handle.
SetupCopyOEMInf | Copies a file into %windir%\Inf.
SetupDecompressOrCopyFile | Copies a file and, if necessary, decompresses it.
SetupFindFirstLine | Finds a pointer to the first line in a section of an INF file or, if a key is specified, the first line that matches the key.
SetupFindNextLine | Returns a pointer to the next line in an INF file section.
SetupFindNextMatchLine | Returns a pointer to the next line in an INF file section or, if a key is specified, the next line that matches the key.
SetupGetBinaryField | Retrieves binary data from a field in a specified line, in an INF file.
SetupGetFieldCount | Returns the number of fields in a line.
SetupGetFileCompressionInfo | Retrieves file compression information from an INF file.
SetupGetInfFileList | Returns a list of the INF files in a specified directory.
SetupGetInfInformation | Returns information about an INF file.
SetupGetIntField | Obtains the integer value of a specified field in a specified line, in an INF file.
SetupGetLineByIndex | Returns a pointer to the line associated with a specified index value in a specified section.
SetupGetLineCount | Returns the number of lines in the specified section.
SetupGetLineText | Retrieves the contents of a specified line from an INF file.
SetupGetMultiSzField | Returns multiple strings, starting at a specified field in a line.
SetupGetSourceFileLocation | Returns the location of a source file listed in an INF file.
SetupGetSourceFileSize | Returns the size of a specified file or a set of files listed in a specified section of an INF file.
SetupGetSourceInfo | Retrieves the path, tag file, or description for a source.
SetupGetStringField | Retrieves string data from a field in a specified line, in an INF file.
SetupGetTargetPath | Determines the target path for the files listed in a specified INF file section.
SetupInstallFile | Installs a specified file into a specific target directory.
SetupInstallFileEx | Installs a specified file into a specific target directory. The installation is postponed if an existing version of the file is in use.
SetupInstallFilesFromInfSection | Queues the files in a specified INF file section for copying. (Same as SetupQueueCopySection.)
SetupInstallFromInfSection | Performs the directives specified in an INF DDInstall section.
SetupInstallServicesFromInfSection | Performs service installation and deletion operations as specified in an INF DDInstall.Services section.
SetupOpenAppendInfFile | Opens an INF file and appends it to an existing INF handle.
SetupOpenInfFile | Opens an INF file and returns a handle to it.
SetupOpenMasterInf | Opens the master INF file that contains file and layout information for files shipped with the operating system.
SetupQueryInfFileInformation | Returns the name of one of the constituent INF files of a specified INF file.
SetupQueryInfVersionInformation | Returns the version number of one of the constituent INF files of a specified INF file.
SetupSetDirectoryId | Assigns a directory ID (DIRID) to a specified directory.
SetupUninstallOEMInf | Uninstalls a specified INF file, and deletes the associated .pnf and .cat files, if they exist.


Disk Prompting and Error Handling Functions

You can use the Setup functions to prompt the user to insert new media, or to handle errors that arise when files are being copied, renamed, or deleted.

The following table lists functions that provide dialog boxes for requesting installation media and reporting errors. For detailed function descriptions, see the Platform SDK documentation.

Function | Description
SetupCopyError | Generates a dialog box that informs the user of a copy error.
SetupDeleteError | Generates a dialog box that informs the user of a delete error.
SetupPromptForDisk | Generates a dialog box that prompts the user for an installation medium or source file location.
SetupRenameError | Generates a dialog box that informs the user of a rename error.


File Queuing Functions

Using the Setup functions, you can queue files for various operations. File queues can be established for copying, renaming, and deleting files. Typically, an application queues all of the file operations necessary for an entire installation, then "commits" the queue so the operations are performed in a single batch.

The following table provides a summary of file queuing functions. For detailed function descriptions, see the Platform SDK documentation.

Function | Description
SetupCloseFileQueue | Destroys a file queue along with any uncommitted file operations.
SetupCommitFileQueue | Commits (performs) all queued operations.
SetupOpenFileQueue | Creates and returns a handle to a file queue.
SetupPromptReboot | Prompts the user to reboot his or her machine, if necessary.
SetupQueueCopy | Queues a specified file for copying.
SetupQueueCopyIndirect | Queues a specified file for copying, and provides file location and security information.
SetupQueueCopySection | Queues the files in a specified INF file section for copying.
SetupQueueDefaultCopy | Queues a specified file for copying, using default source and destination settings contained in the INF file.
SetupQueueDelete | Queues a specified file for deletion.
SetupQueueDeleteSection | Queues the files in an INF file section for deletion.
SetupQueueRename | Queues a specified file for renaming.
SetupQueueRenameSection | Queues the files in an INF section for renaming.
SetupScanFileQueue | Scans a file queue and performs a specified operation on each queue entry.
SetupSetPlatformPathOverride | Sets the value used for overriding the default platform-specific source path.


Default Queue Callback Routine Functions

If you associate a callback routine with a file queue, the callback routine will be called each time the system performs one of the queued file operations. Typically, you can use the default queue callback routine, SetupDefaultQueueCallback, to handle these notifications.

The following table lists functions associated with the default queue callback routine. For detailed function descriptions, and for more information about using callback routines with file queues, see the Platform SDK documentation.

Function | Description
SetupDefaultQueueCallback | Handles notifications sent by the system when queued file operations are performed.
SetupInitDefaultQueueCallback | Initializes context information needed by SetupDefaultQueueCallback.
SetupInitDefaultQueueCallbackEx | Initializes context information needed by SetupDefaultQueueCallback, and provides a separate window for displaying progress messages.
SetupTermDefaultQueueCallback | Notifies the system that the setup application will not commit any more file queue operations.


Cabinet File Function

A cabinet file is a single file, usually with a .cab extension, that contains several compressed files as a file library. Cabinet files are used to organize the installation files that will be copied to the user's system. A compressed file can be spread over several cabinet files.

The following function is used with cabinet files. For a detailed function description, see the Platform SDK documentation.

Function | Description
SetupIterateCabinet | Sends a notification to a callback function for each file stored in a cabinet file.


Disk-Space List Functions

Disk-space list functions are used to create and modify disk-space lists. These lists can be used to calculate the total disk space required to handle the files that will be copied or deleted during the installation procedure.

The following table lists the functions that can be used to manipulate disk-space lists. For detailed function descriptions, see the Platform SDK documentation.

Function | Description
SetupAddInstallSectionToDiskSpaceList | Searches for CopyFile and DelFile directives in a DDInstall section of an INF file, then adds the file operations specified in those sections to a disk-space list.
SetupAddSectionToDiskSpaceList | Adds to a disk-space list all the file copy or delete operations listed in a specified section of an INF file.
SetupAddToDiskSpaceList | Adds a single delete or copy operation to a disk-space list.
SetupCreateDiskSpaceList | Creates a disk-space list.
SetupDestroyDiskSpaceList | Destroys a disk-space list and releases the resources allocated to it.
SetupQueryDrivesInDiskSpaceList | Fills a caller-supplied buffer with a list of the drives referenced by the file operations listed in the disk-space list.
SetupQuerySpaceRequiredOnDrive | Examines a disk-space list to determine the space required to perform all the file operations listed for a particular drive.
SetupRemoveFromDiskSpaceList | Removes a file copy or delete operation from a disk-space list.
SetupRemoveInstallSectionFromDiskSpaceList | Searches for CopyFiles and DelFiles directives in a DDInstall section of an INF file, and removes the file operations specified in those sections from a disk-space list.
SetupRemoveSectionFromDiskSpaceList | Removes from a disk-space list the file copy or delete operations listed in a specified section of an INF file.


MRU Source List Functions

Most recently used (MRU) source lists are resident on the user's machine and contain information about source paths used in previous installations. This information can be used when prompting the user for a source path.

The setup application can access a user-specific source list and, if the application has administrator privilege, the system-wide source list. The setup application can also create a temporary source list that is discarded when the setup application exits. By calling SetupSetSourceList, the setup application identifies which source list it will use during the installation.

The following table lists the functions that can be used to manipulate source lists. For detailed function descriptions, see the Platform SDK documentation.

Function | Description
SetupAddToSourceList | Adds an entry to a source list.
SetupCancelTemporarySourceList | Cancels use of a temporary list.
SetupFreeSourceList | Frees resources allocated by a previous call to SetupSetSourceList.
SetupQuerySourceList | Queries the current list of installation sources.
SetupRemoveFromSourceList | Removes an entry from an installation source list.
SetupSetSourceList | Sets the installation source list to the system MRU list, the user MRU list, or a temporary list.


File Log Functions

You can use a log file to record information about the files copied to a system during an installation. The log file can be either the system log or your own installation log file.

The following table lists the functions that can be used to manipulate log files. For detailed function descriptions, see the Platform SDK documentation.

Function | Description
SetupInitializeFileLog | Initializes a log file for use.
SetupLogError | Writes an error message to a log file. (It should be used only during the installation of the operating system.)
SetupLogFile | Adds an entry to the log file.
SetupQueryFileLog | Retrieves information from a log file.
SetupRemoveFileLogEntry | Removes an entry from a log file.
SetupTerminateFileLog | Releases resources allocated to a log file.


Device Installation Functions

This section describes the Setup functions that support device installation on Windows 2000 and later versions of the NT-based operating system. (Many, but not all, of these functions were introduced with Windows NT 4.0) These functions provide high-level device installation support used by system installation and maintenance utilities. Most of these functions are not supported on Windows 9x/Me.

For the device installation operations not supported by the SetupDi-prefixed device installation functions described in this section, call the appropriate PnP Configuration Manager Functions (CM_Xxx functions).

This section lists the Setup device installation functions in alphabetical order. The following tables provide functional summaries of the functions:

Update Driver Function

Device Information Functions

Driver Information Functions

Driver Selection Functions

Device Installation Handlers

Device Installation Customization Functions

Setup Class Functions

Class Bitmap and Icon Functions

Device Interface Functions

Registry Functions

Other Functions

Update Driver Function

UpdateDriverForPlugAndPlayDevices Given an INF and a hardware ID, UpdateDriverForPlugAndPlayDevices installs updated drivers for devices that match the hardware ID.

SetupDi Device Information Functions

SetupDiCreateDeviceInfoList | Creates an empty device information set. This set can be associated with a class GUID.
SetupDiCreateDeviceInfoListEx | Creates an empty device information set. This set can be associated with a class GUID and can be for devices on a remote machine.
SetupDiCreateDeviceInfo | Creates a new device information element and adds it as a new member to the specified device information set.
SetupDiOpenDeviceInfo | Retrieves information about an existing device instance and adds it to the specified device information set.
SetupDiEnumDeviceInfo | Returns a context structure for a device information element of a device information set.
SetupDiGetDeviceInstanceId | Retrieves the device instance ID associated with a device information element.
SetupDiGetDeviceInfoListClass | Retrieves the class GUID associated with a device information set if it has an associated class.
SetupDiGetDeviceInfoListDetail | Retrieves information associated with a device information set including the class GUID, remote machine handle, and remote machine name.
SetupDiGetClassDevs | Returns a device information set that contains all devices of a specified class.
SetupDiGetClassDevsEx | Returns a device information set that contains all devices of a specified class on a local or remote machine.
SetupDiSetSelectedDevice | Sets the specified device information element to be the currently-selected member of a device information set. This function is typically used by an installation wizard.
SetupDiGetSelectedDevice | Retrieves the currently-selected device for the specified device information set.
SetupDiRegisterDeviceInfo | Registers a newly created device instance with the Plug and Play Manager.
SetupDiDeleteDeviceInfo | Deletes a member from the specified device information set. This function does not delete the actual device.
SetupDiDestroyDeviceInfoList | Destroys a device information set and frees all associated memory.

SetupDi Driver Information Functions

SetupDiBuildDriverInfoList | Builds a list of drivers associated with a specified device instance or with the device information set's global class driver list.
SetupDiEnumDriverInfo | Enumerates the members of a driver information list.
SetupDiGetDriverInfoDetail | Retrieves detailed information for a specified driver information element.
SetupDiSetSelectedDriver | Sets the specified member of a driver list as the currently selected-driver. It can also be used to reset the driver list so that there is no currently-selected driver.
SetupDiGetSelectedDriver | Retrieves the member of a driver list that has been selected as the driver to install.
SetupDiCancelDriverInfoSearch | Cancels a driver list search that is currently underway in a different thread.
SetupDiDestroyDriverInfoList | Destroys a driver information list.

SetupDi Driver Selection Functions

SetupDiAskForOEMDisk | Displays a dialog that asks the user for the path to an OEM installation disk.
SetupDiSelectOEMDrv | Selects a driver for a device using an OEM path supplied by the user.
SetupDiSelectDevice | Default handler for the DIF_SELECTDEVICE request.

SetupDi Device Installation Handlers

SetupDiCallClassInstaller | Calls the appropriate class installer, and any registered co-installers, with the specified installation request.
SetupDiChangeState | The default handler for the DIF_PROPERTYCHANGE request. It can be used to change the state of an installed device.
SetupDiRegisterCoDeviceInstallers | Registers the device-specific co-installers listed in the INF file for the specified device. This function is the default handler for DIF_REGISTER_COINSTALLERS.
SetupDiInstallDevice | The default handler for the DIF_INSTALLDEVICE request.
SetupDiInstallDriverFiles | The default handler for the DIF_INSTALLDEVICEFILES request.
SetupDiInstallDeviceInterfaces | The default handler for the DIF_INSTALLINTERFACES request. It installs the interfaces listed in a DDInstall.Interfaces section of a device INF file.
SetupDiMoveDuplicateDevice | The default handler for the DIF_MOVEDEVICE request.
SetupDiRemoveDevice | The default handler for the DIF_REMOVEDEVICE request.
SetupDiUnremoveDevice | The default handler for the DIF_UNREMOVE request.
SetupDiRegisterDeviceInfo | The default handler for the DIF_REGISTERDEVICE request.
SetupDiSelectDevice | The default handler for the DIF_SELECTDEVICE request.
SetupDiSelectBestCompatDrv | The default handler for the DIF_SELECTBESTCOMPATDRV request.

SetupDi Device Installation Customization Functions

SetupDiGetClassInstallParams | Retrieves class install parameters for a device information set or a particular device information element.
SetupDiSetClassInstallParams | Sets or clears class install parameters for a device information set or a particular device information element.
SetupDiGetDeviceInstallParams | Retrieves device install parameters for a device information set or a particular device information element.
SetupDiSetDeviceInstallParams | Sets device install parameters for a device information set or a particular device information element.
SetupDiGetDriverInstallParams | Retrieves install parameters for the specified driver.
SetupDiSetDriverInstallParams | Sets the install parameters for the specified driver.

SetupDi Setup Class Functions

SetupDiBuildClassInfoList | Returns a list of setup class GUIDs that includes every class installed on the system.
SetupDiBuildClassInfoListEx | Returns a list of setup class GUIDs that includes every class installed on the local system or a remote system.
SetupDiGetClassDescription | Retrieves the class description associated with the specified setup class GUID.
SetupDiGetClassDescriptionEx | Retrieves the description of a setup class installed on a local or remote machine.
SetupDiGetINFClass | Retrieves the class of a specified device INF file.
SetupDiClassGuidsFromName | Retrieves the GUIDs associated with the specified class name. This list is built based on what classes are currently installed on the system.
SetupDiClassGuidsFromNameEx | Retrieves the GUIDs associated with the specified class name. This resulting list contains the classes currently installed on a local or remote machine.
SetupDiClassNameFromGuid | Retrieves the class name associated with the class GUID.
SetupDiClassNameFromGuidEx | Retrieves the class name associated with a class GUID. The class can be installed on a local or remote machine.
SetupDiInstallClass | Installs the ClassInstall32 section of the specified INF file.
SetupDiInstallClassEx | Installs a class installer or an interface class.
SetupDiOpenClassRegKey | Opens the device setup class registry key or a specific class's subkey.
SetupDiOpenClassRegKeyEx | Opens the device setup class registry key, the device interface class registry key, or a specific class's subkey. This function opens the specified key on the local machine or on a remote machine.

SetupDi Class Bitmap and Icon Functions

SetupDiGetClassImageList | Builds an image list that contains bitmaps for every installed class and returns the list in a data structure.
SetupDiGetClassImageListEx | Builds an image list of bitmaps for every class installed on a local or remote machine.
SetupDiGetClassImageIndex | Retrieves the index within the class image list of a specified class.
SetupDiGetClassBitmapIndex | Retrieves the index of the mini-icon supplied for the specified class.
SetupDiDrawMiniIcon | Draws the specified mini-icon at the location requested.
SetupDiLoadClassIcon | Loads both the large and mini-icon for the specified class.
SetupDiDestroyClassImageList | Destroys a class image list.

SetupDi Device Interface Functions

SetupDiCreateDeviceInterface | Registers device functionality (a device interface) for a device.
SetupDiOpenDeviceInterface | Retrieves information about an existing device interface and adds it to the specified device information set.
SetupDiGetDeviceInterfaceAlias | Returns an alias of the specified device interface.
SetupDiGetClassDevs | Returns a device information set that contains all devices of a specified class.
SetupDiGetClassDevsEx | Returns a device information set that contains all devices of a specified class on a local or remote machine.
SetupDiEnumDeviceInterfaces | Returns a context structure for a device interface element of a device information set. Each call returns information about one device interface; the function can be called repeatedly to get information about several interfaces exposed by one or more devices.
SetupDiGetDeviceInterfaceDetail | Returns details about a particular device interface.
SetupDiCreateDeviceInterfaceRegKey | Creates a registry subkey for storing information about a device interface instance and returns a handle to the key.
SetupDiOpenDeviceInterfaceRegKey | Opens the registry subkey that is used by applications and drivers to store information specific to a device interface instance and returns a handle to the key.
SetupDiDeleteDeviceInterfaceRegKey | Deletes the registry subkey that was used by applications and drivers to store information specific to a device interface instance.
SetupDiInstallDeviceInterfaces | Is the default handler for the DIF_INSTALLINTERFACES request. It installs the interfaces listed in a DDInstall.Interfaces section of a device INF file.
SetupDiRemoveDeviceInterface | Removes a registered device interface from the system.
SetupDiDeleteDeviceInterfaceData | Deletes a device interface from a device information set.
SetupDiSetDeviceInterfaceDefault | Sets a specified device interface as the default interface for a device class.
SetupDiInstallClassEx | Installs a class installer or an interface class.
SetupDiOpenClassRegKeyEx | Opens the device setup class registry key, the device interface class registry key, or a specific class's subkey. This function opens the specified key on the local machine or on a remote machine.

SetupDi Registry Functions

SetupDiCreateDevRegKey | Creates a registry storage key for device-specific configuration information and returns a handle to the key.
SetupDiOpenDevRegKey | Opens a registry storage key for device-specific configuration information and returns a handle to the key.
SetupDiDeleteDevRegKey | Deletes the specified user-accessible registry key(s) associated with a device information element.
SetupDiOpenClassRegKey | Opens the setup class registry key or a specific class's subkey.
SetupDiOpenClassRegKeyEx | Opens the device setup class registry key, the device interface class registry key, or a specific class's subkey. This function opens the specified key on the local machine or on a remote machine.
SetupDiCreateDeviceInterfaceRegKey | Creates a non-volatile registry subkey for storing information about a device interface instance and returns a handle to the key.
SetupDiOpenDeviceInterfaceRegKey | Opens the registry subkey that is used by applications and drivers to store information specific to a device interface instance and returns a handle to the key.
SetupDiDeleteDeviceInterfaceRegKey | Deletes the registry subkey that was used by applications and drivers to store information specific to a device interface instance.
SetupDiSetDeviceRegistryProperty | Sets the specified Plug and Play device property.
SetupDiGetDeviceRegistryProperty | Retrieves the specified Plug and Play device property.
SetupDiGetClassRegistryProperty | Retrieves a specified device class property from the registry.
SetupDiSetClassRegistryProperty | Sets a specified device class property in the registry.

Other SetupDi Functions

SetupDiGetActualSectionToInstall | Finds the appropriate DDInstall section to use when installing a device from a device INF file.
SetupDiGetHwProfileFriendlyName | Retrieves the friendly name associated with a hardware profile ID.
SetupDiGetHwProfileFriendlyNameEx | Retrieves the friendly name associated with a hardware profile ID on a local or remote machine.
SetupDiGetHwProfileList | Retrieves a list of all currently defined hardware profile IDs.
SetupDiGetHwProfileListEx | Retrieves a list of all currently defined hardware profile IDs on a local or remote machine.


SetupDiAskForOEMDisk

SetupDiAskForOEMDisk displays a dialog that asks the user for the path to an OEM installation disk.

WINSETUPAPI BOOL WINAPI
  SetupDiAskForOEMDisk(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData  OPTIONAL
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set for the local machine that contains the device being installed.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure for the device being installed. If this parameter is not specified, the driver being installed is associated with the global class list of the device information set.

Return Value

The function returns TRUE if it is successful and the DriverPath field of the SP_DEVINSTALLPARAMS structure is updated to reflect the new path. If the user cancels the dialog, the function returns FALSE and a call to GetLastError returns ERROR_CANCELLED.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

This function allows the user to browse local and network drives for OEM installation files. The DeviceInfoSet must only contain elements on the local machine.

See Also

SetupDiSelectOEMDrv


SetupDiBuildClassInfoList

SetupDiBuildClassInfoList returns a list of setup class GUIDs that includes every class installed on the system.

WINSETUPAPI BOOL WINAPI
  SetupDiBuildClassInfoList(
    IN DWORD  Flags,
    OUT LPGUID  ClassGuidList,
    IN DWORD  ClassGuidListSize,
    OUT PDWORD  RequiredSize
    );

Parameters

Flags
Flags used to control exclusion of classes from the list. If no flags are specified, all setup classes are included in the list. Can be a combination of the following values:
DIBCI_NOINSTALLCLASS
Exclude a class if it has the NoInstallClass value entry in its registry key.
DIBCI_NODISPLAYCLASS
Exclude a class if it has the NoDisplayClass value entry in its registry key.
ClassGuidList
Supplies a pointer to a buffer that receives a list of setup class GUIDs.
ClassGuidListSize
Supplies the number of GUIDs in the ClassGuildList array.
RequiredSize
Supplies a pointer to a variable that receives the number of GUIDs returned. If this number is greater than the size of the ClassGuidList, the number indicates how large the ClassGuidList array must be in order to contain the list.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

To retrieve the list of setup class GUIDs installed on a remote system use SetupDiBuildClassInfoListEx.

See Also

SetupDiBuildClassInfoListEx, SetupDiGetClassDescription, SetupDiGetINFClass


SetupDiBuildClassInfoListEx

SetupDiBuildClassInfoListEx returns a list of setup class GUIDs that includes every class installed on the local system or a remote system.

WINSETUPAPI BOOL WINAPI
  SetupDiBuildClassInfoListEx(
    IN DWORD  Flags,
    OUT LPGUID  ClassGuidList,
    IN DWORD  ClassGuidListSize,
    OUT PDWORD  RequiredSize,
    IN PCTSTR  MachineName,  OPTIONAL
    IN PVOID  Reserved,
    );

Parameters

Flags
Flags used to control exclusion of classes from the list. If no flags are specified, all setup classes are included in the list. Can be a combination of the following values:
DIBCI_NOINSTALLCLASS
Exclude a class if it has the NoInstallClass value entry in its registry key.
DIBCI_NODISPLAYCLASS
Exclude a class if it has the NoDisplayClass value entry in its registry key.
ClassGuidList
Supplies a pointer to a buffer that receives a list of setup class GUIDs.
ClassGuidListSize
Supplies the number of GUIDs in the ClassGuildList array.
RequiredSize
Supplies a pointer to a variable that receives the number of GUIDs returned. If this number is greater than the size of the ClassGuidList, the number indicates how large the ClassGuidList array must be in order to contain the list.
MachineName
Optionally supplies the name of a remote machine from which to retrieve installed setup classes. If MachineName is NULL, this function builds a list of classes installed on the local machine.
Reserved
Must be NULL.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

See Also

SetupDiBuildClassInfoList, SetupDiGetClassDescriptionEx


SetupDiBuildDriverInfoList

SetupDiBuildDriverInfoList builds a list of drivers associated with a specified device instance or with the device information set's global class driver list.

WINSETUPAPI BOOL WINAPI
  SetupDiBuildDriverInfoList(
    IN HDEVINFO DeviceInfoSet,
    IN OUT PSP_DEVINFO_DATA  DeviceInfoData,  OPTIONAL
    IN DWORD  DriverType
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set to contain the driver information list (either globally for all elements or specifically for a single element). The device information set must not contain remote elements.
DeviceInfoData
Supplies a pointer to the SP_DEVINFO_DATA structure for the device information element for which to build a driver list. If this parameter is NULL, the list is associated with the device information set and not with a particular device information element. Use NULL with driver lists of type SPDIT_CLASSDRIVER only.

If the class of this device is updated as a result of building a compatible driver list, the ClassGuid field of the SP_DEVINFO_DATA structure is updated upon return.

DriverType
Specifies what type of driver list to build. Must be one of the following values:
SPDIT_CLASSDRIVER
Build a list of class drivers.
SPDIT_COMPATDRIVER
Build a list of drivers for this device. DeviceInfoData must be specified if this flag is set.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

The caller can set Flags in the SP_DEVINSTALL_PARAMS that are associated with the device information set or with a specific device (DeviceInfoData) to control how the list is built. For example, the caller can set the DI_FLAGSEX_ALLOWEXCLUDEDDRVS flag to include drivers that are marked Exclude From Select.

A driver is "Exclude From Select" if either it is marked ExcludeFromSelect in the INF file or it is a driver for a device whose whole setup class is marked NoInstallClass or NoUseClass in the class installer INF. Drivers for PnP devices are typically "Exclude From Select"; PnP devices should not be manually installed. To build a list of driver files for a PnP device a caller of SetupDiBuildDriverInfoList must set this flag.

The DriverPath in the SP_DEVINSTALL_PARAMS contains either a path to a directory containing INF files or a path to a specific INF file. If DI_ENUMSINGLEINF is set, DriverPath contains a path to a single INF file. If DriverPath is NULL, this function builds the driver list from the default INF location, %windir%\inf.

After this function has built the specified driver list, the caller can enumerate the elements of the list by calling SetupDiEnumDriverInfo.

If the driver list is associated with a device instance (that is, DeviceInfoData is specified), the resulting list is composed of drivers that have the same class as the device instance with which they are associated. If this is a global class driver list (that is, DriverType is SPDIT_CLASSDRIVER and DeviceInfoData is not specified), the class that is used when building the list is the class associated with the device information set. If the device information set has no associated class, drivers of all classes are used when building the list.

Another thread can terminate the building of a driver list by a call to SetupDiCancelDriverInfoSearch.

The DeviceInfoSet must only contain elements on the local machine. This function only searches for local drivers.

See Also

SetupDiCancelDriverInfoSearch, SetupDiDestroyDriverInfoList, SetupDiEnumDriverInfo


SetupDiCallClassInstaller

SetupDiCallClassInstaller calls the appropriate class installer, and any registered co-installers, with the specified installation request (DIF code).

WINSETUPAPI BOOL WINAPI
  SetupDiCallClassInstaller(
    IN DI_FUNCTION  InstallFunction,
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData  OPTIONAL
    );

Parameters

InstallFunction
Specifies the device installation request (DIF request) to pass to the co-installers and class installer. DIF codes have the format DIF_XXX and are defined in setupapi.h. See Device Installation Function Codes for more information.
DeviceInfoSet
Supplies a handle to a device information set for the local machine.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that specifies a device in the DeviceInfoSet. If DeviceInfoData is NULL, this function calls the installers for the setup class associated with the device information set.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

SetupDiCallClassInstaller calls the class installer and any co-installers that are registered for a device or a device setup class. This function loads the installers if they are not yet loaded. The function also calls the default handler for the DIF request, if there is a default handler and if the installers return a status indicating that the default handler should be called.

Setup applications call this function with a variety of device installation function codes (DIF codes). The function ensures that all the appropriate installers and default handlers are called, in the correct order, for a given DIF request. For more information, see Handling DIF Codes.

After SetupDiCallClassInstaller returns TRUE, the setup application must call SetupDiGetDeviceInstallParams to obtain an SP_DEVINSTALL_PARAMS structure. If the structure's DI_NEEDREBOOT or DI_NEEDRESTART flag is set, the caller must prompt the user to restart the system (by calling SetupPromptReboot, for example, which is described in Platfrom SDK documentation). Note, however, that an installation application should request a system restart one time at most. Therefore, any setup application that creates multiple calls to SetupDiCallClassInstaller and SetupDiGetDeviceInstallParams should save the DI_NEEDREBOOT and DI_NEEDRESTART flags after each call, but it should prompt the user only after the last call returns.

In response to a DIF code supplied by SetupDiCallClassInstaller, class installers and co-installers might perform operations that require the system to be rebooted. In such situations, the installer or co-installer should do the following:

  1. Call SetupDiGetDeviceInstallParams to obtain the SP_DEVINSTALL_PARAMS structure.
  2. Set the DI_NEEDREBOOT or DI_NEEDRESTART flag in the structure's Flags member.
  3. Call SetupDiSetDeviceInstallParams, supplying the updated SP_DEVINSTALL_PARAMS structure, to save the revised Flags member.

After SetupDiCallClassInstaller returns, the setup application that called it should call SetupDiGetDeviceInstallParams, check the flags, and request a reboot if necessary.

The device information set specified by DeviceInfoSet must only contain elements for devices on the local machine.

For information on the design and operation of class installers and co-installers, see Writing a Class Installer and Writing a Co-installer.

See Also

SP_DEVINFO_DATA


SetupDiCancelDriverInfoSearch

SetupDiCancelDriverInfoSearch cancels a driver list search that is currently underway in a different thread.

WINSETUPAPI BOOL WINAPI
  SetupDiCancelDriverInfoSearch(
    IN HDEVINFO DeviceInfoSet
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set for which a driver list is being built.

Return Value

If a driver list search is underway for the specified device information set when this function is called, the search is terminated. SetupDiCancelDriverInfoSearch returns TRUE when the termination is confirmed. Otherwise, it returns FALSE and a call to GetLastError returns ERROR_INVALID_HANDLE.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

SetupDiCancelDriverInfoSearch is a synchronous call; therefore, it does not return until the driver search thread responds to the termination request.

See Also

SetupDIBuildDriverInfoList


SetupDiChangeState

SetupDiChangeState is the default handler for the DIF_PROPERTYCHANGE installation request. This function changes the state of an installed device.

WINSETUPAPI BOOL WINAPI
  SetupDiChangeState(
    IN HDEVINFO  DeviceInfoSet,
    IN OUT PSP_DEVINFO_DATA  DeviceInfoData
    );

Parameters

DeviceInfoSet
Supplies a handle to a device information set for the local machine.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that specifies a device in the DeviceInfoSet. This is an IN OUT parameter because the DevInst field of the structure can be updated with a new handle value upon return.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

Co-installers should not call default DIF code handlers.

Callers of this function must specify a DICS_XXX flag in the SP_PROPCHANGE_PARAMS for the device element that indicates the type of state change to perform on the device. Callers of this function must set the appropriate fields in the SP_PROPCHANGE_PARAMS and call SetupDiSetClassInstallParams before calling this function.

If you specify the DICS_FLAG_CONFIGSPECIFIC flag in the SP_PROPCHANGE_PARAMS then you must fill in the HwProfile field. A value of zero for HwProfile indicates the current profile.

To enable/disable a device in the current hardware profile, set the DICS_FLAG_CONFIGSPECIFIC flag in the SP_PROPCHANGE_PARAMS. To enable/disable a device globally, such as in both the docked and undocked hardware profiles, set the DICS_FLAG_GLOBAL flag.

This function does the following:

DICS_ENABLE
Loads the drivers for the device and starts the device, if possible. If the function is not able to start the device, it sets the DI_NEEDREBOOT flag for the device which indicates to the initiator of the property change request that they must prompt the user to reboot the machine.
DICS_DISABLE
Disables the device. If the device is disableable but this function cannot disable the device dynamically, this function marks the device to be disabled the next time the machine reboots.
DICS_PROPCHANGE
Removes and reconfigures the device so the new properties can take effect. This flag typically indicates that a user has changed a property on a Device Manager property page for the device. The PnP Manager directs the drivers for the device to remove their device objects and then the PnP Manager reconfigures and restarts the device.

Callers of this function should not specify DICS_STOP or DICS_START in the SP_PROPCHANGE_PARAMS. Use DICS_PROPCHANGE to stop and restart a device to cause changes in the device's configuration to take effect.

If DI_DONOTCALLCONFIGMG is set for a device, you should not call SetupDiChangeState for the device but should instead set the DI_NEEDREBOOT flag.

See Also

DIF_PROPERTYCHANGE, SetupDiCallClassInstaller, SP_PROPCHANGE_PARAMS


SetupDiClassGuidsFromName

SetupDiClassGuidsFromName retrieves the GUID(s) associated with the specified class name. This list is built based on the classes currently installed on the system.

WINSETUPAPI BOOL WINAPI
  SetupDiClassGuidsFromName(
    IN PCTSTR  ClassName,
    OUT LPGUID  ClassGuidList,
    IN DWORD  ClassGuidListSize,
    OUT PDWORD  RequiredSize
    );

Parameters

ClassName
Supplies the name of the class for which to retrieve the class GUID.
ClassGuidList
Supplies a pointer to an array to receive the list of GUIDs associated with the specified class name.
ClassGuidListSize
Supplies the number of GUIDs in the ClassGuidList array.
RequiredSize
Supplies a pointer to a variable that receives the number of GUIDs associated with the class name. If this number is greater than the size of the ClassGuidList buffer, the number indicates how large the array must be in order to store all the GUIDs.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

Call SetupDiClassGuidsFromNameEx to retrieve the class GUIDs for a class on a remote machine.

See Also

SetupDiClassGuidsFromNameEx, SetupDiClassNameFromGuid


SetupDiClassGuidsFromNameEx

SetupDiClassGuidsFromNameEx retrieves the GUIDs associated with the specified class name. This resulting list contains the classes currently installed on a local or remote machine.

WINSETUPAPI BOOL WINAPI
  SetupDiClassGuidsFromNameEx(
    IN PCTSTR  ClassName,
    OUT LPGUID  ClassGuidList,
    IN DWORD  ClassGuidListSize,
    OUT PDWORD  RequiredSize,
    IN PCTSTR  MachineName,  OPTIONAL
    IN PVOID  Reserved
    );

Parameters

ClassName
Supplies the name of the class for which to retrieve the class GUIDs.
ClassGuidList
Supplies a pointer to an array to receive the list of GUIDs associated with the specified class name.
ClassGuidListSize
Supplies the number of GUIDs in the ClassGuidList array.
RequiredSize
Supplies a pointer to a variable that receives the number of GUIDs associated with the class name. If this number is greater than the size of the ClassGuidList buffer, the number indicates how large the array must be in order to store all the GUIDs.
MachineName
Optionally supplies the name of a remote machine from which to retrieve the GUIDs. If MachineName is NULL, the local machine is used.
Reserved
Must be NULL.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

Class names are not guaranteed to be unique; only GUIDs are unique. Therefore, one class name can return more than one GUID.

See Also

SetupDiClassGuidsFromName, SetupDiClassNameFromGuidEx


SetupDiClassNameFromGuid

SetupDiClassNameFromGuid retrieves the class name associated with a class GUID.

WINSETUPAPI BOOL WINAPI
  SetupDiClassNameFromGuid(
    IN LPGUID  ClassGuid,
    OUT PTSTR  ClassName,
    IN DWORD  ClassNameSize,
    OUT PDWORD  RequiredSize  OPTIONAL
    );

Parameters

ClassGuid
Supplies the class GUID of the class name to retrieve.
ClassName
Receives the name of the class for the specified GUID.
ClassNameSize
Supplies the size, in characters, of the ClassName buffer.
RequiredSize
Receives the number of characters required to store the class name (including terminating NULL). RequiredSize is always less than MAX_CLASS_NAME_LEN.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

Call SetupDiClassNameFromGuidEx to retrieve the name for a class on a remote machine.

See Also

SetupDiClassGuidsFromName, SetupDiClassNameFromGuidEx


SetupDiClassNameFromGuidEx

SetupDiClassNameFromGuidEx retrieves the class name associated with a class GUID. The class can be installed on a local or remote machine.

WINSETUPAPI BOOL WINAPI
  SetupDiClassNameFromGuidEx(
    IN LPGUID  ClassGuid,
    OUT PTSTR  ClassName,
    IN DWORD  ClassNameSize,
    OUT PDWORD  RequiredSize,  OPTIONAL
    IN PCTSTR  MachineName,  OPTIONAL
    IN PVOID  Reserved
    );

Parameters

ClassGuid
Supplies the class GUID of the class name to retrieve.
ClassName
Receives the name of the class for the specified GUID.
ClassNameSize
Supplies the size, in characters, of the ClassName buffer.
RequiredSize
Receives the number of characters required to store the class name (including terminating NULL). RequiredSize is always less than MAX_CLASS_NAME_LEN.
MachineName
Optionally supplies the name of a remote machine on which the class is installed. If MachineName is NULL, the local machine is used.
Reserved
Must be NULL.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

See Also

SetupDiClassGuidsFromNameEx, SetupDiClassNameFromGuid


SetupDiCreateDeviceInfo

SetupDiCreateDeviceInfo creates a new device information element and adds it as a new member to the specified device information set.

WINSETUPAPI BOOL WINAPI
  SetupDiCreateDeviceInfo(
    IN HDEVINFO  DeviceInfoSet,
    IN PCTSTR  DeviceName,
    IN LPGUID  ClassGuid,
    IN PCTSTR  DeviceDescription,  OPTIONAL
    IN HWND  hwndParent,  OPTIONAL
    IN DWORD  CreationFlags,
    OUT PSP_DEVINFO_DATA  DeviceInfoData  OPTIONAL
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set for the local machine.
DeviceName
Supplies either a full device instance ID (for example, Root\*PNP0500\0000) or a root-enumerated device ID without the Enum branch prefix and instance ID suffix (for example, *PNP0500). The root-enumerated device ID can be used only if the DICD_GENERATE_ID flag is specified in the CreationFlags parameter.
ClassGuid
Supplies a pointer to the GUID for this device's class. If the class is not known, this value should be GUID_NULL.
DeviceDescription
Supplies a textual description of the device.
hwndParent
Supplies the window handle of the top-level window to use for any user interface related to installing the device.
CreationFlags
Controls how the device information element is created. Can be a combination of the following values:
DICD_GENERATE_ID
If this flag is specified, DeviceName contains only a Root-enumerated device ID and the system creates a unique device instance key for it. This unique device instance key is generated as:

Enum\Root\DeviceName\InstanceID
where InstanceID is a four-digit, base-10 number that is unique among all subkeys under Enum\Root\DeviceName. Call SetupDiGetDeviceInstanceId to find out what ID was generated for this device information element.

DICD_INHERIT_CLASSDRVS
If this flag is specified, the resulting device information element inherits the class driver list, if any, associated with the device information set. In addition, if there is a selected driver for the device information set, that same driver is selected for the new device information element.
DeviceInfoData
Optionally supplies a pointer to an SP_DEVINFO_DATA structure to receive the new device information element. If this parameter is not NULL, the caller must set cbSize to sizeof(SP_DEVINFO_DATA).

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

If this device instance is being added to a set that has an associated class, the device class must be the same or the call fails. In this case, a call to GetLastError returns ERROR_CLASS_MISMATCH.

If the specified device instance is the same as an existing device instance key in the registry, the call fails. In this case, a call to GetLastError returns ERROR_DEVINST_ALREADY_EXISTS. This occurs only if the DCID_GENERATE_ID flag is not set.

If the new device information element was successfully created but the caller-supplied DeviceInfoData buffer is invalid, the function returns FALSE. In this case, a call to GetLastError returns ERROR_INVALID_USER_BUFFER. However, the device information element will have been added as a new member of the set already.

The DeviceInfoSet must only contain elements on the local machine.

See Also

SetupDiDeleteDeviceInfo, SetupDiEnumDeviceInfo, SetupDiOpenDeviceInfo, SP_DEVINFO_DATA


SetupDiCreateDeviceInfoList

SetupDiCreateDeviceInfoList creates an empty device information set. This set can be associated with a class GUID.

HDEVINFO
  SetupDiCreateDeviceInfoList(
    IN LPGUID  ClassGuid,  OPTIONAL
    IN HWND  hwndParent  OPTIONAL
    );

Parameters

ClassGuid
Optionally supplies the GUID of the setup class associated with this device information set. If this parameter is specified, only devices of this class may be included in this device information set.
hwndParent
Optionally supplies the window handle of the top-level window to use for any user interface related to non-device-specific actions (such as a select-device dialog using the global class driver list).

Return Value

The function returns a handle to an empty device information set if it is successful. Otherwise, it returns INVALID_HANDLE_VALUE. To get extended error information, call GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

The caller of this function must delete the returned device information set when it is no longer needed by calling SetupDiDestroyDeviceInfoList.

To create a device information list for a remote machine use SetupDiCreateDeviceInfoListEx.

See Also

SetupDiCreateDeviceInfoListEx, SetupDiGetClassDevs, SetupDiDestroyDeviceInfoList, SetupDiGetDeviceInfoListClass


SetupDiCreateDeviceInfoListEx

SetupDiCreateDeviceInfoListEx creates an empty device information set. This set can be associated with a class GUID and can be for devices on a remote machine.

HDEVINFO
  SetupDiCreateDeviceInfoListEx(
    IN LPGUID  ClassGuid,  OPTIONAL
    IN HWND  hwndParent,  OPTIONAL
    IN PCTSTR  MachineName,  OPTIONAL
    IN PVOID  Reserved
    );

Parameters

ClassGuid
Optionally supplies the GUID of the setup class associated with this device information set. If this parameter is specified, only devices of this class may be included in this device information set.
hwndParent
Optionally supplies the window handle of the top-level window to use for any user interface related to non-device-specific actions (such as a select-device dialog using the global class driver list).
MachineName
Optionally supplies the name of a machine on the network. If such a name is specified, only devices on that machine can be created and opened in this device information set. If MachineName is NULL, the device information set is for local devices.
Reserved
Must be NULL.

Return Value

The function returns a handle to an empty device information set if it is successful. Otherwise, it returns INVALID_HANDLE_VALUE. To get extended error information, call GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

The caller of this function must delete the returned device information set when it is no longer needed by calling SetupDiDestroyDeviceInfoList.

If the device information set is for devices on a remote machine (MachineName is not NULL), all subsequent operations on this set or any of its elements must use routines that support device information sets with remote elements. The SetupDi Xxx routines that do not provide this support, such as SetupDiCallClassInstaller, have a statement to that effect in their reference page.

See Also

SetupDiCreateDeviceInfoList, SetupDiDestroyDeviceInfoList, SetupDiGetDeviceInfoListDetail


SetupDiCreateDeviceInterface

SetupDiCreateDeviceInterface registers device functionality (a device interface) for a device.

WINSETUPAPI BOOL WINAPI
  SetupDiCreateDeviceInterface(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData,
    IN LPGUID  InterfaceClassGuid,
    IN PCTSTR  ReferenceString,  OPTIONAL
    IN DWORD  CreationFlags,
    OUT PSP_DEVICE_INTERFACE_DATA  DeviceInterfaceData  OPTIONAL
    );

Parameters

DeviceInfoSet
Points to the device information set containing the device for which an interface is being registered. This handle is typically returned by SetupDiGetClassDevs. The device information set must not contain remote elements.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that identifies the device in the device information set.
InterfaceClassGuid
Points to a class GUID that specifies the interface class for the new interface.
ReferenceString
Optionally points to a reference string; this parameter is typically NULL.

Reference strings are only used by a few bus drivers that use device interfaces as placeholders for software devices that are created on demand.

CreationFlags
Reserved. Must be zero.
DeviceInterfaceData
Optionally points to a caller-allocated SP_DEVICE_INTERFACE_DATA structure to receive information about the new device interface. The caller must set DeviceInterfaceData.cbSize to sizeof(SP_DEVICE_INTERFACE_DATA) before calling this function.

Return Value

SetupDiCreateDeviceInterface returns TRUE if the function completed without error. If the function completed with an error, it returns FALSE and the error code for the failure can be retrieved by calling GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

SetupDiCreateDeviceInterface registers an interface for a device. If a device has more than one interface, call this function once for each interface being registered.

Before a registered interface can be used by applications and other system components the interface must be enabled by the driver for the device.

This function creates a registry key for the new device interface. Callers of this function can access non-volatile storage under this key using SetupDiOpenDeviceInterfaceRegKey.

If the new device interface is successfully created and registered, but the caller-supplied DeviceInterfaceData buffer is invalid, this function returns FALSE and GetLastError returns ERROR_INVALID_USER_BUFFER. The caller's buffer error does not prevent the interface from being created and registered.

The DeviceInfoSet must only contain elements on the local machine.

See Also

SetupDiOpenDeviceInterfaceRegKey, SetupDiRemoveDeviceInterface


SetupDiCreateDeviceInterfaceRegKey

SetupDiCreateDeviceInterfaceRegKey creates a registry key for storing information about a device interface instance and returns a handle to the key.

HKEY
  SetupDiCreateDeviceInterfaceRegKey(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVICE_INTERFACE_DATA  DeviceInterfaceData,
    IN DWORD  Reserved,
    IN REGSAM  samDesired,
    IN HINF  InfHandle,  OPTIONAL
    IN PCTSTR  InfSectionName  OPTIONAL
    );

Parameters

DeviceInfoSet
Points to a device information set containing the interface and its underlying device. The device information set must not contain remote elements.
DeviceInterfaceData
Points to a SP_DEVICE_INTERFACE_DATA structure that identifies the device interface, possibly returned by SetupDiCreateDeviceInterface.
Reserved
Reserved. Must be zero.
samDesired
Specifies the registry access requested by the caller to the key being created.
InfHandle
Optionally supplies the handle of an open INF file that contains a DDInstall section to be executed for the newly-created key. If this parameter is not NULL, InfSectionName must be specified as well.
InfSectionName
Optionally points to the name of an DDInstall section in the INF file specified by InfHandle. This section is executed for the newly created key. If this parameter is not NULL, InfHandle must be specified as well.

Return Value

SetupDiCreateDeviceInterfaceRegKey returns a handle to the newly-created registry key. If the function fails, it returns INVALID_HANDLE_VALUE. Call GetLastError to get extended error information.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

SetupDiCreateDeviceInterfaceRegKey creates a non-volatile subkey of the registry key for the specified device interface. Callers of this function can store private configuration data for the device interface in this subkey. The driver for the device can access this subkey using Io Xxx routines.

Close the handle returned from this function by calling RegCloseKey.

For installations that use layout files (specified by the LayoutFile entry in an INF Version section), the layout file must be opened by a call to SetupOpenAppendInfFile (described in Platform SDK documentation) before SetupDiCreateDeviceInterfaceRegKey is called.

The device information set specified by DeviceInfoSet must only contain elements on the local machine.

See Also

SetupDiCreateDeviceInterface, SetupDiDeleteDeviceInterfaceRegKey, SetupDiOpenDeviceInterfaceRegKey


SetupDiCreateDevRegKey

SetupDiCreateDevRegKey creates a registry storage key for device-specific configuration information and returns a handle to the key.

HKEY
  SetupDiCreateDevRegKey(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData,
    IN DWORD  Scope,
    IN DWORD  HwProfile,
    IN DWORD  KeyType,
    IN HINF  InfHandle,  OPTIONAL
    IN PCTSTR  InfSectionName  OPTIONAL
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set containing information about the device instance whose registry configuration storage key is to be created. The device information set must not contain remote elements.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure indicating the device instance for which to create the registry key.
Scope
Specifies the scope of the registry key to be created. The scope determines where the information is stored. The key created can be global or hardware profile-specific. Can be one of the following values:
DICS_FLAG_GLOBAL
Create a key to store global configuration information. This information is not specific to a particular hardware profile. On NT-based operating systems this creates a key that is rooted at HKEY_LOCAL_MACHINE. The exact key opened depends on the value of the KeyType parameter.
DICS_FLAG_CONFIGSPECIFIC
Create a key to store hardware profile-specific configuration information. This key is rooted at one of the hardware-profile specific branches, instead of HKEY_LOCAL_MACHINE.
HwProfile
Specifies the hardware profile for which to create a key if HwProfileFlags is set to SPDICS_FLAG_CONFIGSPECIFIC. If HwProfile is 0, the key for the current hardware profile is created. If HwProfileFlags is SPDICS_FLAG_GLOBAL, HwProfile is ignored.
KeyType
Specifies the type of registry storage key to create. Can be one of the following values:
DIREG_DEV
Create a hardware registry key for the device. This is the key for storage of driver-independent configuration information. This key is in the DeviceInstance key of the Enum branch.
DIREG_DRV
Create a software, or driver, registry key for the device. This key is located in the Class branch.
InfHandle
Supplies the handle of an open INF file that contains an INF DDInstall section to be executed for the newly-created key. If this parameter is specified, InfSectionName must be specified as well.
InfSectionName
Supplies the name of an INF DDInstall section in the INF file specified by InfHandle. This section is executed for the newly created key. If this parameter is specified, InfHandle must be specified as well.

Return Value

If the function is successful, it returns a handle to the newly-created registry key where private configuration data pertaining to this device instance can be stored/retrieved. If the function fails, it returns INVALID_HANDLE_VALUE. Call GetLastError to get extended error information.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

Close the handle returned from this function by calling RegCloseKey.

The specified device instance must be registered before calling this function. After creating the device instance with SetupDiCreateDeviceInfo, call SetupDiRegisterDeviceInfo to register it.

For installations that use layout files (specified by the LayoutFile entry in an INF Version section), the layout file must be opened by a call to SetupOpenAppendInfFile (described in Platform SDK documentation) before SetupDiCreateDevRegKey is called.

The device information set specified by DeviceInfoSet must only contain elements on the local machine.

See Also

SetupDiCreateDeviceInfo, SetupDiGetHwProfileList, SetupDiOpenDevRegKey, SetupDiRegisterDeviceInfo


SetupDiDeleteDeviceInfo

SetupDiDeleteDeviceInfo deletes a member from the specified device information set. This function does not delete the actual device.

WINSETUPAPI BOOL WINAPI
  SetupDiDeleteDeviceInfo(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set containing the device information member to delete.
DeviceInfoData
Supplies a pointer to the SP_DEVINFO_DATA structure for the device information member to delete.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Comments

If the specified device information element is in use (for example, by a wizard page), the function fails. In this case, a call to GetLastError returns ERROR_DEVINFO_DATA_LOCKED. This happens if a handle to a wizard page is retrieved with a call to SetupDiGetWizardPage with this device information element specified and the DIWP_FLAG_USE_DEVINFO_DATA flag set. To delete this device information element, you must first close the wizard's HPROPSHEETPAGE handle.

Headers

Declared in setupapi.h. Include setupapi.h.

See Also

SetupDiCreateDeviceInfo, SetupDiEnumDeviceInfo, SetupDiGetWizardPage, SetupDiOpenDeviceInfo


SetupDiDeleteDeviceInterfaceData

SetupDiDeleteDeviceInterfaceData deletes a device interface from a device information set.

WINSETUPAPI BOOL WINAPI
  SetupDiDeleteDeviceInterfaceData(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVICE_INTERFACE_DATA  DeviceInterfaceData
    );

Parameters

DeviceInfoSet
Points to the device information set containing the interface and its underlying device. This handle is typically returned by SetupDiGetClassDevs.
DeviceInterfaceData
Points to a SP_DEVICE_INTERFACE_DATA structure that identifies the interface to be deleted. This structure is typically returned by SetupDiEnumDeviceInterfaces.

Return Value

SetupDiDeleteDeviceInterfaceData returns TRUE if the function completed without error. If the function completed with an error, it returns FALSE and the error code for the failure can be retrieved by calling GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

SetupDiDeleteDeviceInterfaceData deletes a device interface element from a device information set. This function has no effect on the device interface or the underlying device.

See Also

SetupDiEnumDeviceInterfaces, SetupDiGetClassDevs, SetupDiRemoveDeviceInterface


SetupDiDeleteDeviceInterfaceRegKey

SetupDiDeleteDeviceInterfaceRegKey deletes the registry subkey that was used by applications and drivers to store information specific to a device interface instance.

WINSETUPAPI BOOL WINAPI
  SetupDiDeleteDeviceInterfaceRegKey(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVICE_INTERFACE_DATA  DeviceInterfaceData,
    IN DWORD  Reserved
    );

Parameters

DeviceInfoSet
Points to a device information set containing the interface and its underlying device. The device information set must not contain remote elements.
DeviceInterfaceData
Points to a SP_DEVICE_INTERFACE_DATA structure that identifies the device interface, possibly returned by SetupDiCreateDeviceInterface or SetupDiEnumDeviceInterfaces.
Reserved
Reserved. Must be zero.

Return Value

SetupDiDeleteDeviceInterfaceRegKey returns TRUE if it is successful; otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

SetupDiDeleteDeviceInterfaceRegKey deletes the subkey used by drivers and applications to store information about the device interface instance. This subkey was created by SetupDiCreateDeviceInterfaceRegKey or by the driver's call to an associated I/O Manager routine. SetupDiDeleteDeviceInterfaceRegKey does not affect the main registry key for the device interface instance nor any other subkeys that may have been created.

The DeviceInfoSet must only contain elements on the local machine.

See Also

SetupDiCreateDeviceInterface, SetupDiCreateDeviceInterfaceRegKey


SetupDiDeleteDevRegKey

SetupDiDeleteDevRegKey deletes the specified user-accessible registry key(s) associated with a device information element.

WINSETUPAPI BOOL WINAPI
  SetupDiDeleteDevRegKey(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData,
    IN DWORD  Scope,
    IN DWORD  HwProfile,
    IN DWORD  KeyType
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set containing the device instance whose registry configuration storage key is to be deleted. The device information set must not contain remote elements.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure indicating the device instance for which to delete registry key(s).
Scope
Specifies the scope of the registry key to delete. The scope indicates where the information is located. The key can be global or hardware profile-specific. Can be one of the following values:
DICS_FLAG_GLOBAL
Delete the key that stores global configuration information.
DICS_FLAG_CONFIGSPECIFIC
Delete the key that stores hardware profile-specific configuration information.
HwProfile
If Scope is set to DICS_FLAG_CONFIGSPECIFIC, the HwProfile parameter specifies the hardware profile for which to delete the registry key. If HwProfile is 0, the key for the current hardware profile is deleted. If HwProfile is 0xFFFFFFFF, the registry key for all hardware profiles is deleted.
KeyType
Specifies the type of registry storage key to delete. Can be one of the following values:
DIREG_DEV
Delete the hardware registry key for the device. This is the key for storage of driver-independent configuration information. This key is in the Device Instance key of the Enum branch.
DIREG_DRV
Delete a software, or driver, registry key for the device. This key is located in the Class branch.
DIREG_BOTH
Delete both the hardware and software keys for the device.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

The DeviceInfoSet must only contain elements on the local machine.

See Also

SetupDiCreateDevRegKey, SetupDiGetHwProfileList


SetupDiDestroyClassImageList

SetupDiDestroyClassImageList destroys a class image list that was built by a call to SetupDiGetClassImageList or SetupDiGetClassImageListEx.

WINSETUPAPI BOOL WINAPI
  SetupDiDestroyClassImageList(
    IN PSP_CLASSIMAGELIST_DATA  ClassImageListData
    );

Parameters

ClassImageListData
Supplies a pointer to an SP_CLASSIMAGELIST_DATA structure that contains the class image list to destroy.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved by a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

See Also

SetupDiGetClassImageList, SetupDiGetClassImageListEx


SetupDiDestroyDeviceInfoList

SetupDiDestroyDeviceInfoList destroys a device information set and frees all associated memory.

WINSETUPAPI BOOL WINAPI
  SetupDiDestroyDeviceInfoList(
    IN HDEVINFO  DeviceInfoSet
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set to destroy.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

See Also

SetupDiCreateDeviceInfoList, SetupDiGetClassDevs


SetupDiDestroyDriverInfoList

SetupDiDestroyDriverInfoList destroys a driver information list.

WINSETUPAPI BOOL WINAPI
  SetupDiDestroyDriverInfoList(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData,  OPTIONAL
    IN DWORD  DriverType
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set that contains the driver information list to destroy.
DeviceInfoData
Supplies a pointer to the SP_DEVINFO_DATA structure associated with the driver information list to destroy. If this parameter is not specified, the global class driver list is destroyed.
DriverType
Specifies what type of driver list to destroy. Must be one of the following values:
SPDIT_CLASSDRIVER
Destroy a list of class drivers.
SPDIT_COMPATDRIVER
Destroy a list of compatible drivers for the specified device. DeviceInfoData must be specified if this flag is set.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

If the currently selected driver is a member of the list being destroyed, the selection is reset.

If a class driver list is being destroyed, the DI_FLAGSEX_DIDINFOLIST and DI_DIDCLASS flags are reset for the corresponding device information set or device information element. The DI_MULTMFGS flags is also reset.

If a compatible driver list is being destroyed, the DI_FLAGSEX_DIDCOMPATINFO and DI_DIDCOMPAT flags are reset for the corresponding device information element.

See Also

SetupDiBuildDriverInfoList


SetupDiDrawMiniIcon

SetupDiDrawMiniIcon draws the specified mini-icon at the location requested.

INT
  SetupDiDrawMiniIcon(
    IN HDC  hdc,
    IN RECT  rc,
    IN INT  MiniIconIndex,
    IN DWORD  Flags
    );

Parameters

hdc
Supplies the handle of the device context in which the mini-icon will be drawn.
rc
The rectangle in the specified device context handle to draw the mini-icon in.
MiniIconIndex
The index of the mini-icon, as retrieved from SetupDiLoadClassIcon or SetupDiGetClassBitmapIndex. The following predefined indexes for devices can be used:
Class | Index
Computer | 0
Display | 2
Mouse | 5
Keyboard | 6
FDC | 9
HDC | 9
Ports | 10
Net | 15
System | 0
Sound | 8
Printer | 14
Monitor | 2
Network Transport | 3
Network Client | 16
Network Service | 17
Unknown | 18

Flags
These flags control the drawing operation. The LOWORD contains the actual flags defined as follows:
DMI_MASK
Draw the mini-icon's mask into HDC.
DMI_BKCOLOR
Use the system color index specified in the HIWORD of Flags as the background color. If this flag is not set, COLOR_WINDOW is used.
DMI_USERECT
If set, SetupDiDrawMiniIcon uses the supplied rectangle and stretches the icon to fit.

Return Value

This function returns the offset from the left side of rc where the string should start.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

By default, the icon is centered vertically and butted against the left side of the specified rectangle.

See Also

SetupDiGetClassBitmapIndex, SetupDiLoadClassIcon


SetupDiEnumDeviceInfo

SetupDiEnumDeviceInfo returns a context structure for a device information element of a device information set. Each call returns information about one device; the function can be called repeatedly to get information about several devices.

WINSETUPAPI BOOL WINAPI
  SetupDiEnumDeviceInfo(
    IN HDEVINFO  DeviceInfoSet,
    IN DWORD  MemberIndex,
    OUT PSP_DEVINFO_DATA  DeviceInfoData
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set.
MemberIndex
Supplies the zero-based index of the device information element to retrieve.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure to receive information about this element. The caller must set cbSize to sizeof(SP_DEVINFO_DATA).

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

To enumerate device information elements, an installer should initially call SetupDiEnumDeviceInfo with the MemberIndex parameter set to 0. The installer should then increment MemberIndex and call SetupDiEnumDeviceInfo until there are no more values (the function fails and a call to GetLastError returns ERROR_NO_MORE_ITEMS).

Call SetupDiEnumDeviceInterfaces to get a context structure for a device interface element (versus a device information element).

See Also

SetupDiCreateDeviceInfo, SetupDiDeleteDeviceInfo, SetupDiEnumDeviceInterfaces, SetupDiOpenDeviceInfo, SP_DEVINFO_DATA


SetupDiEnumDeviceInterfaces

SetupDiEnumDeviceInterfaces returns a context structure for a device interface element of a device information set. Each call returns information about one device interface; the function can be called repeatedly to get information about several interfaces exposed by one or more devices.

WINSETUPAPI BOOL WINAPI
  SetupDiEnumDeviceInterfaces(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData,  OPTIONAL
    IN LPGUID  InterfaceClassGuid,
    IN DWORD  MemberIndex,
    OUT PSP_DEVICE_INTERFACE_DATA  DeviceInterfaceData
    );

Parameters

DeviceInfoSet
Points to a device information set containing the device(s) for which to return interface information. This handle is typically returned by SetupDiGetClassDevs.
DeviceInfoData
Optionally points to an SP_DEVINFO_DATA structure that constrains the search for interfaces to those of just one device in the device information set. This pointer is typically returned by SetupDiEnumDeviceInfo.
InterfaceClassGuid
Points to a GUID that specifies the device interface class for the requested interface.
MemberIndex
Specifies a zero-based index into the list of interfaces in the device information set. The caller should call this function first with MemberIndex set to zero to obtain the first interface. Then, repeatedly increment MemberIndex and retrieve an interface until this function fails and GetLastError returns ERROR_NO_MORE_ITEMS.

If DeviceInfoData specifies a particular device, the MemberIndex is relative to only the interfaces exposed by that device.

DeviceInterfaceData
Points to a caller-allocated buffer that contains, on successful return, a completed SP_DEVICE_INTERFACE_DATA structure that identifies an interface that meets the search parameters. The caller must set DeviceInterfaceData.cbSize to sizeof(SP_DEVICE_INTERFACE_DATA) before calling this function.

Return Value

SetupDiEnumDeviceInterfaces returns TRUE if the function completed without error. If the function completed with an error, FALSE is returned and the error code for the failure can be retrieved by calling GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

DeviceInterfaceData points to a structure that identifies a requested device interface. To get detailed information about an interface, call SetupDiGetDeviceInterfaceDetail. The detailed information includes the name of the device interface that can be passed to a Win32® function such as CreateFile (described in Platform SDK documentation) to get a handle to the interface.

See Also

SetupDiGetClassDevs, SetupDiEnumDeviceInfo, SetupDiGetDeviceInterfaceDetail


SetupDiEnumDriverInfo

SetupDiEnumDriverInfo enumerates the members of a driver information list.

WINSETUPAPI BOOL WINAPI
  SetupDiEnumDriverInfo(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData,  OPTIONAL
    IN DWORD  DriverType,
    IN DWORD  MemberIndex,
    OUT PSP_DRVINFO_DATA  DriverInfoData
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set containing a driver information list to enumerate.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that contains a driver information list to enumerate. If this parameter is not specified, the global driver list owned by the device information set is used (this list is of type SPDIT_CLASSDRIVER).
DriverType
Specifies what type of driver list to enumerate. Must be one of the following values:
SPDIT_CLASSDRIVER
Enumerate a class driver list.
SPDIT_COMPATDRIVER
Enumerate a list of compatible drivers for the specified device. DeviceInfoData must be specified if this flag is set.
MemberIndex
Supplies the 0-based index of the driver information member to retrieve.
DriverInfoData
Supplies a pointer to an SP_DRVINFO_DATA structure to receive information about the enumerated driver.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

To enumerate driver information set members, an installer should first call SetupDiEnumDriverInfo with the MemberIndex parameter set to 0. It should then increment MemberIndex and call SetupDiEnumDriverInfo until there are no more values. When there are no more values, the function fails and a call to GetLastError returns ERROR_NO_MORE_ITEMS.

See Also

SetupDiBuildDriverInfoList


SetupDiGetActualSectionToInstall

SetupDiGetActualSectionToInstall finds the appropriate INF DDInstall section to use when installing a device from a device INF file.

WINSETUPAPI BOOL WINAPI
  SetupDiGetActualSectionToInstall(
    IN HINF  InfHandle,
    IN PCTSTR  InfSectionName,
    OUT PTSTR  InfSectionWithExt,  OPTIONAL
    IN DWORD  InfSectionWithExtSize,
    OUT PDWORD  RequiredSize,  OPTIONAL
    OUT PTSTR  *Extension  OPTIONAL
    );

Parameters

InfHandle
Supplies the handle of the INF file that contains the DDInstall section.
InfSectionName
Supplies a pointer to the name of the DDInstall section as specified by the driver node being installed.
InfSectionWithExt
Supplies a pointer to a character buffer to receive the name of the DDInstall section that should be used for installation. If this parameter is NULL, InfSectionWithExtSize must be 0. The caller can use the NULL value to determine the required buffer size, because the function returns TRUE and RequiredSize is set to the size, in characters, necessary to store the DDInstall section name.
InfSectionWithExtSize
Supplies the size, in characters, of the InfSectionWithExt buffer.
RequiredSize
Supplies a pointer to a variable that receives the size, in characters, required to store the actual DDInstall section name, including the terminating NULL.
Extension
Supplies a pointer to a variable that receives a pointer to the extension, including ".". This parameter is NULL if an extension is not required. Extension points to the extension within the caller-supplied buffer. If the InfSectionWithExt buffer is not supplied, this variable is not filled in.

Return Value

If the function is successful, it returns TRUE. If the function fails, it returns INVALID_HANDLE_VALUE. To get extended error information, call GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

This function supports an OS/architecture-specific extension that can be used to specify multiple installation behaviors for a single device, dependent on the operating environment. An extension is appended to the INF file DDInstall section name to identify that it contains OS/architecture-specific installation instructions. SetupDiGetActualSectionToInstall searches for the different DDInstall section names in the manner described below.

Starting with the name of the INF DDInstall section as specified in the driver node (for example, InstallSec) the function attempts to find one of the following section names (the search is carried out in the order listed):

For NT-based operating systems:

  • InstallSec.NT platform
  • InstallSec.NT
  • InstallSec

For Windows 98/Me:

  • InstallSec.Win
  • InstallSec

(For Windows 95/98/Me installations that call device installation functions of setupx.dll, .Win section extensions are not used.)

The first DDInstall section located is used for the installation. This section name is also used as the base for Hardware and Services section names. For example, if the DDInstall section name found is InstallSec.NTX86, the Services section name must be named InstallSec.NTX86.Services.

The original DDInstall section name specified in the driver node is written to the driver's registry key's InfSection value entry. The extension that was found is stored in the key as the REG_SZ value InfSectionExt. For example:

InfSection       : REG_SZ :    "InstallSec"
InfSectionExt    : REG_SZ :    ".NTX86"

If a driver is not selected for the specified device information element, a NULL driver is installed. Upon return, the flags in the device's SP_DEVINSTALL_PARAMS structure indicate whether the system should be restarted or rebooted for the device to start.

The function uses information on the local machine when selecting the correct section name decoration.

See Also

INF DDInstall Section, SetupDiInstallDevice


SetupDiGetClassBitmapIndex

SetupDiGetClassBitmapIndex retrieves the index of the mini-icon supplied for the specified class.

WINSETUPAPI BOOL WINAPI
  SetupDiGetClassBitmapIndex(
    IN LPGUID  ClassGuid,  OPTIONAL
    OUT PINT  MiniIconIndex
    );

Parameters

ClassGuid
Points to the GUID of the class for which to retrieve the mini-icon.
MiniIconIndex
A pointer to a buffer to receive the index of the mini-icon for the specified class. This buffer is always filled in. It receives the index of the Unknown mini-icon if there is no mini-icon for the specified class.

Return Value

If there is a min-icon for the specified class, the function returns TRUE.

If there is no mini-icon for the specified class, the function returns FALSE and the MiniIconIndex buffer receives the index for the Unknown mini-icon.

Headers

Declared in setupapi.h. Include setupapi.h.

See Also

SetupDiDrawMiniIcon, SetupDiLoadClassIcon


SetupDiGetClassDescription

SetupDiGetClassDescription retrieves the class description associated with the specified setup class GUID.

WINSETUPAPI BOOL WINAPI
  SetupDiGetClassDescription(
    IN LPGUID  ClassGuid,
    OUT PTSTR  ClassDescription,
    IN DWORD  ClassDescriptionSize,
    OUT PDWORD  RequiredSize  OPTIONAL
    );

Parameters

ClassGuid
Supplies the GUID of the setup class whose description is to be retrieved.
ClassDescription
Supplies a pointer to a character buffer that receives the class description.
ClassDescriptionSize
Supplies the size, in characters, of the ClassDescription buffer.
RequiredSize
Receives the size, in characters, required to store the class description (including terminating NULL). RequiredSize is always less than LINE_LEN.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

Call SetupDiGetClassDescriptionEx to retrieve the description of a setup class installed on a remote machine.

See Also

SetupDiBuildClassInfoList, SetupDiGetClassDescriptionEx, SetupDiGetINFClass


SetupDiGetClassDescriptionEx

SetupDiGetClassDescriptionEx retrieves the description of a setup class installed on a local or remote machine.

WINSETUPAPI BOOL WINAPI
  SetupDiGetClassDescriptionEx(
    IN LPGUID  ClassGuid,
    OUT PTSTR  ClassDescription,
    IN DWORD  ClassDescriptionSize,
    OUT PDWORD  RequiredSize,  OPTIONAL
    IN PCTSTR  MachineName,  OPTIONAL
    IN PVOID  Reserved
    );

Parameters

ClassGuid
Supplies the GUID of the setup class whose description is to be retrieved.
ClassDescription
Supplies a pointer to a character buffer that receives the class description.
ClassDescriptionSize
Supplies the size, in characters, of the ClassDescription buffer.
RequiredSize
Receives the size, in characters, required to store the class description (including terminating NULL). RequiredSize is always less than LINE_LEN.
MachineName
Optionally supplies the name of a remote machine on which the setup class resides. A value of NULL for MachineName specifies that the class is installed on the local machine.
Reserved
Must be NULL.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

If there is a friendly name in the registry key for the class, this routine returns the friendly name. Otherwise, this routine returns the class name.

See Also

SetupDiBuildClassInfoList, SetupDiBuildClassInfoListEx, SetupDiGetDeviceInfoListDetail, SetupDiGetINFClass


SetupDiGetClassDevs

SetupDiGetClassDevs returns a device information set that contains all devices of a specified class.

HDEVINFO
  SetupDiGetClassDevs(
    IN LPGUID  ClassGuid,  OPTIONAL
    IN PCTSTR  Enumerator,  OPTIONAL
    IN HWND  hwndParent,  OPTIONAL
    IN DWORD  Flags
    );

Parameters

ClassGuid
Optionally points to a class GUID for a setup class or an interface class. If the DIGCF_DEVICEINTERFACE flag is set, ClassGuid represents an interface class; otherwise, ClassGuid represents a setup class.

If the DIGCF_ALLCLASSES flag is set, this parameter is ignored and the resulting list contains devices of all installed classes.

Enumerator
Optionally points to a string that filters the devices that are returned.

If the DIGCF_DEVICEINTERFACE flag is set, this parameter optionally points to a string representing the PnP name of a particular device. This function only examines this particular device to determine whether it exposes any interfaces of the requested interface class.

If the DIGCF_DEVICEINTERFACE flag is not set, this parameter optionally specifies the name of the PnP enumerator that enumerates the devices of interest. (The names of system-supplied enumerators appear in register.h.) This function only examines device instances of this enumerator. If this parameter is NULL, this function retrieves device information for all device instances on the system.

hwndParent
Supplies the handle of the top-level window to be used for any user interface relating to the members of this set.
Flags
Supplies control options used in building the device information set. Can be a combination of the following values:
DIGCF_ALLCLASSES
Return a list of installed devices for all classes. If this flag is set, the ClassGuid parameter is ignored.
DIGCF_DEVICEINTERFACE
Return devices that expose interfaces of the interface class specified by ClassGuid. If this flag is not set, ClassGuid specifies a setup class.
DIGCF_PRESENT
Return only devices that are currently present.
DIGCF_PROFILE
Return only devices that are a part of the current hardware profile.

Return Value

SetupDiGetClassDevs returns a handle to a device information set containing all installed devices matching the specified parameters. If the function fails, it returns INVALID_HANDLE_VALUE or another appropriate error. To get extended error information, call GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

The caller of this function must delete the returned device information set when it is no longer needed by calling SetupDiDestroyDeviceInfoList.

If DIGCF_DEVICEINTERFACE is set, ClassGuid (if used) must point to a device interface class GUID and Enumerator (if used) must point to a PnP device name. The returned device information set contains devices that expose interfaces of the requested interface class. Enumerate the interfaces of the devices using SetupDiEnumDeviceInterfaces.

If DIGCF_DEVICEINTERFACE is not set, ClassGuid (if used) must point to a setup class GUID and Enumerator (if used) must specify the name of the PnP enumerator that enumerates the devices of interest.

Call SetupDiGetClassDevsEx to retrieve the devices for a class on a remote machine.

See Also

SetupDiCreateDeviceInfoList, SetupDiDestroyDeviceInfoList, SetupDiEnumDeviceInterfaces, SetupDiGetClassDevsEx


SetupDiGetClassDevsEx

SetupDiGetClassDevsEx returns a device information set that contains all devices of a specified class on a local or remote machine.

HDEVINFO
  SetupDiGetClassDevsEx(
    IN LPGUID  ClassGuid,  OPTIONAL
    IN PCTSTR  Enumerator,  OPTIONAL
    IN HWND  hwndParent,  OPTIONAL
    IN DWORD  Flags,
    IN HDEVINFO  DeviceInfoSet,  OPTIONAL
    IN PCTSTR  MachineName,  OPTIONAL
    IN PVOID  Reserved
    );

Parameters

ClassGuid
Optionally points to a class GUID for a setup class or an interface class. If the DIGCF_DEVICEINTERFACE flag is set, ClassGuid represents an interface class; otherwise, ClassGuid represents a setup class.

If the DIGCF_ALLCLASSES flag is set, this parameter is ignored and the resulting list contains devices of all installed classes.

Enumerator
Optionally points to a string that filters the devices that are returned.

If the DIGCF_DEVICEINTERFACE flag is set, this parameter optionally points to a string representing the PnP name of a particular device. This function only examines this particular device to determine whether it exposes any interfaces of the requested interface class.

If the DIGCF_DEVICEINTERFACE flag is not set, this parameter optionally specifies the name of the PnP enumerator that enumerates the devices of interest. (The names of system-supplied enumerators appear in register.h.) This function only examines device instances of this enumerator. If this parameter is NULL, this function retrieves device information for all device instances on the system.

hwndParent
Supplies the handle of the top-level window to be used for any user interface relating to the members of this set.
Flags
Supplies control options used in building the device information set. Can be a combination of the following values:
DIGCF_ALLCLASSES
Return a list of installed devices for all classes. If this flag is set, the ClassGuid parameter is ignored.
DIGCF_DEVICEINTERFACE
Return devices that expose interfaces of the interface class specified by ClassGuid. If this flag is not set, ClassGuid specifies a setup class.
DIGCF_PRESENT
Return only devices that are currently present.
DIGCF_PROFILE
Return only devices that are a part of the current hardware profile.
DeviceInfoSet
Optionally supplies the handle of an existing device information set into which this function adds the requested device information.

If DeviceInfoSet is nonNULL, then the device information set it specifies is returned on success, with the retrieved device information added. If this parameter is NULL, this function creates a new device information set.

If DeviceInfoSet is nonNULL and ClassGuid specifies a setup class, then the associated class of DeviceInfoSet (if any) must match the ClassGuid. ClassGuid specifies a setup class if it is nonNULL and the DIGCF_DEVICEINTERFACE flag is not set.

MachineName
Optionally supplies the name of a remote machine on which the devices reside. A value of NULL for MachineName specifies that the class is installed on the local machine.
Reserved
Must be NULL.

Return Value

SetupDiGetClassDevsEx returns a handle to a device information set containing all devices matching the specified parameters. If the function fails, it returns INVALID_HANDLE_VALUE or another appropriate error. To get extended error information, call GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

The caller of this function must delete the returned device information set when it is no longer needed by calling SetupDiDestroyDeviceInfoList.

If DIGCF_DEVICEINTERFACE is set, ClassGuid (if used) must point to a device interface class GUID and Enumerator (if used) must point to a PnP device name. The returned device information set contains devices that expose interfaces of the requested interface class. Enumerate the interfaces of the devices using SetupDiEnumDeviceInterfaces.

If DIGCF_DEVICEINTERFACE is not set, ClassGuid (if used) must point to a setup class GUID and Enumerator (if used) must specify the name of the PnP enumerator that enumerates the devices of interest.

A driver can use this function to get a list of device interfaces of a particular class that are exposed by devices of a particular setup class. For example, to get a list of the device interfaces of interface class "mounted device" that are exposed by devices in the setup class "Volume":

  1. Create a device information set, by calling SetupDiCreateDeviceInfoList or SetupDiCreateDeviceInfoListEx with an associated setup class of "Volume".
  2. Call SetupDiGetClassDevsEx, specifying:
    • ClassGuid with the GUID for the interface class "mounted device".
    • Flags with DIGCF_DEVICEINTERFACE set.
    • DeviceInfoSet with the HDEVINFO returned in step (1). The associated setup class of this HDEVINFO is "Volume".

In this kind of call to SetupDiGetClassDevsEx, the device interfaces retrieved are filtered based on whether their corresponding device's setup class matches that of the device information set.

See Also

SetupDiCreateDeviceInfoListEx, SetupDiDestroyDeviceInfoList, SetupDiEnumDeviceInterfaces


SetupDiGetClassImageIndex

SetupDiGetClassImageIndex retrieves the index within the class image list of a specified class.

WINSETUPAPI BOOL WINAPI
  SetupDiGetClassImageIndex(
    IN PSP_CLASSIMAGELIST_DATA  ClassImageListData,
    IN LPGUID  ClassGuid,
    OUT PINT  ImageIndex
    );

Parameters

ClassImageListData
Supplies a pointer to an SP_CLASSIMAGELIST_DATA structure that contains the class's image.
ClassGuid
Supplies a pointer to the GUID for the class.
ImageIndex
Supplies a pointer to a variable that receives the index of the specified class's image within the class image list.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved by a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

See Also

SetupDiGetClassImageList, SetupDiGetClassImageListEx


SetupDiGetClassImageList

SetupDiGetClassImageList builds an image list that contains bitmaps for every installed class and returns the list in a data structure.

WINSETUPAPI BOOL WINAPI
  SetupDiGetClassImageList(
    OUT PSP_CLASSIMAGELIST_DATA  ClassImageListData
    );

Parameters

ClassImageListData
Supplies a pointer to an SP_CLASSIMAGELIST_DATA structure to receive information regarding the class image list, including a handle to the image list. The cbSize field of this structure must be initialized with the size of the structure, in bytes, before calling this function or it will fail.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved by a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

The image list built by this function should be destroyed by calling SetupDiDestroyClassImageList.

Call SetupDiGetClassImageListEx to retrieve the image list for classes installed on a remote machine.

See Also

SetupDiDestroyClassImageList, SetupDiGetClassImageListEx


SetupDiGetClassImageListEx

SetupDiGetClassImageListEx builds an image list of bitmaps for every class installed on a local or remote machine.

WINSETUPAPI BOOL WINAPI
  SetupDiGetClassImageListEx(
    OUT PSP_CLASSIMAGELIST_DATA  ClassImageListData,
    IN PCTSTR  MachineName,  OPTIONAL
    IN PVOID  Reserved
    );

Parameters

ClassImageListData
Supplies a pointer to an SP_CLASSIMAGELIST_DATA structure to receive information regarding the class image list, including a handle to the image list. The cbSize field of this structure must be initialized with the size of the structure, in bytes, before calling this function or it will fail.
MachineName
Optionally supplies the name of a remote machine for whose classes the bitmap list is to be built. If MachineName is NULL, this function builds the list for the local machine.
Reserved
Must be NULL.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved by a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

The image list built by this function should be destroyed by calling SetupDiDestroyClassImageList.

Note Class-specific icons on a remote machine can only be displayed if the class is also present on the local machine. Thus, if the remote machine has class X, but class X is not installed locally, then the generic (unknown) icon will be returned.

See Also

SetupDiDestroyClassImageList, SetupDiGetClassImageList


SetupDiGetClassInstallParams

SetupDiGetClassInstallParams retrieves class install parameters for a device information set or a particular device information element.

WINSETUPAPI BOOL WINAPI
  SetupDiGetClassInstallParams(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData,  OPTIONAL
    OUT PSP_CLASSINSTALL_HEADER  ClassInstallParams,  OPTIONAL
    IN DWORD  ClassInstallParamsSize,
    OUT PDWORD  RequiredSize  OPTIONAL
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set that contains the class install parameters to retrieve.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that contains the class install parameters to retrieve. If this parameter is not specified, the class install parameters retrieved are associated with the device information set for the global class driver list.
ClassInstallParams
Supplies a pointer to a buffer that contains an SP_CLASSINSTALL_HEADER structure. This structure must have its cbSize member set to sizeof(SP_CLASSINSTALL_HEADER) on input or the buffer is considered to be invalid. On output, the InstallFunction member is filled with the device installation function code for the class installation parameters being retrieved. If the buffer is large enough, it also receives the class installation parameters structure specific to the function code. If ClassInstallParams is not specified, ClassInstallParamsSize must be 0.
ClassInstallParamsSize
Supplies the size, in bytes, of the ClassInstallParams buffer. If the buffer is supplied, it must be at least as large as sizeof(SP_CLASSINSTALL_HEADER). If the buffer is not supplied, ClassInstallParamsSize must be 0.
RequiredSize
(Optional) If specified, the referenced location receives the number of bytes required to store the class install parameters.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

The class install parameters are specific to a particular device installation function code that is stored in the ClassInstallHeader field located at the beginning of the ClassInstallParams buffer.

See Also

SetupDiSetClassInstallParams


SetupDiGetClassRegistryProperty

(Windows XP and later)

SetupDiGetClassRegistryProperty retrieves a property, for a specified device setup class, from the registry.

WINSETUPAPI BOOL WINAPI
  SetupDiGetClassRegistryProperty(
    IN LPGUID  ClassGuid,
    IN DWORD  Property,
    OUT PDWORD  PropertyRegDataType,  OPTIONAL
    OUT PBYTE  PropertyBuffer,
    IN DWORD  PropertyBufferSize,
    OUT PDWORD  RequiredSize,  OPTIONAL
    IN PCTSTR  MachineName,  OPTIONAL
    IN PVOID  Reserved
    );

Parameters

ClassGuid
Caller-supplied pointer to a GUID representing the device setup class for which a property is to be retrieved.
Property
Caller-supplied value identifying the property to be retrieved. This must be one of the following values:
SPCRP_SECURITY
The function returns the device's security descriptor as a SECURITY_DESCRIPTOR structure (described in Platform SDK documentation).
SPCRP_SECURITY_SDS
The function returns the device's security descriptor, in text form.
SPCRP_DEVTYPE
The function returns the device type for the class. For more information, see Specifying Device Types.
SPCRP_EXCLUSIVE
The function returns a DWORD value indicating whether users can obtain exclusive access to devices for this class. The returned value is one if exclusive access is allowed, or zero otherwise.
SPCRP_CHARACTERISTICS
The function returns flags indicating device characteristics for the class. For a list of characteristics flags, see the DeviceCharacteristics parameter to IoCreateDevice.
PropertyRegDataType
(Optional) Caller-supplied pointer to a location that receives the property's data type as one of the REG_-prefixed registry data types. If NULL, the data type is not returned.
PropertyBuffer
Caller-supplied pointer to a buffer that receives the requested property.
PropertyBufferSize
Caller-supplied size of the buffer pointed to by PropertyBuffer.
RequiredSize
(Optional) Caller-supplied pointer to receive the required buffer size. If the buffer pointed to by PropertyBuffer is too small, and RequiredSize is not NULL, the function supplies the minimum buffer size required to receive the requested property.
MachineName
(Optional) Caller-supplied name of a remote machine from which to retrieve the specified device class property. If NULL, the property is retrieved from the local machine.
Reserved
Reserved, must be NULL.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

This function is supported by Windows XP and later operating system versions.

See Also

SetupDiSetClassRegistryProperty, SetupDiGetDeviceRegistryProperty, SetupDiSetDeviceRegistryProperty


SetupDiGetCustomDeviceProperty

(Windows XP and later)

SetupDiGetCustomDeviceProperty retrieves specified device properties from the registry.

WINSETUPAPI BOOL WINAPI
  SetupDiGetCustomDeviceProperty(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData,
    IN PCTSTR  CustomPropertyName,
    IN DWORD  Flags,
    OUT PDWORD  PropertyRegDataType,  OPTIONAL
    OUT PBYTE  PropertyBuffer,
    IN DWORD  PropertyBufferSize,
    OUT PDWORD  RequiredSize  OPTIONAL
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set to query. Installer entry points receive this handle (see Co-installer Interface and Class Installer Interface). Other setup applications can call SetupDiCreateDeviceInfoList or SetupDiGetClassDevs.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure identifying the device instance for which information is to be retrieved. Installer entry points receive this pointer (see Co-installer Interface and Class Installer Interface). Other setup applications can call SetupDiOpenDeviceInfo, SetupDiEnumDeviceInfo, and other functions.
CustomPropertyName
Supplies a registry value name representing a custom property.
Flags
Supplies optional flags that indicate how the requested information should be returned. The only flag defined is:
DICUSTOMDEVPROP_MERGE_MULTISZ
If set, the function retrieves both device instance-specific property values and hardware ID-specific property values, concatenated as a REG_MULTI_SZ-typed string. (For more information, see the Comments section on this reference page.)
PropertyRegDataType
Optional. If specified, it is a pointer to a location to receive the data type of the retrieved property. The data type is specified as one of the REG_-prefixed constants representing registry data types.
PropertyBuffer
Pointer to the address of a buffer that receives requested property information.
PropertyBufferSize
Pointer to a location containing the size, in bytes, of the buffer pointed to by PropertyBuffer.
RequiredSize
Optional. If specified, and if PropertyBufferSize is too small to receive the requested information, RequiredSize receives the minimum buffer size, in bytes, required to receive the requested information.

Return Value

If the operation succeeds, the function returns TRUE; Otherwise, it returns FALSE. To obtain additional error information, call GetLastError (described in the Platform SDK documentation). If the error is ERROR_INSUFFICIENT_BUFFER and RequiredSize is specified, the specified location receives the required buffer size.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

SetupDiGetCustomDeviceProperty retrieves device properties that are associated with a single device instance or with all devices matching a certain hardware ID.

Vendors can set properties for a device instance by using INF AddReg directives in INF DDInstall.HW sections and specifying the HKR registry root.

Only the system can set properties for hardware IDs. The system supplies an "Icon" property for some hardware IDs.

The function first checks to see if the specified property exists for the specified device instance. If so, the property's value is returned. If not, the function checks to see if the property exists for all devices matching the hardware ID of the specified device instance. If so, the property's value is returned. If DICUSTOMDEVPROP_MERGE_MULTISZ is set in Flags, the function returns the property values associated with both the device instance and the hardware ID, if they both exist.

See Also

SetupDiOpenDevRegKey, SetupDiGetClassRegistryProperty, SetupDiSetClassRegistryProperty, SetupDiGetDeviceRegistryProperty, SetupDiSetDeviceRegistryProperty


SetupDiGetDeviceInfoListClass

SetupDiGetDeviceInfoListClass retrieves the class GUID associated with a device information set if it has an associated class.

WINSETUPAPI BOOL WINAPI
  SetupDiGetDeviceInfoListClass(
    IN HDEVINFO  DeviceInfoSet,
    OUT LPGUID  ClassGuid
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set to query.
ClassGuid
Supplies a pointer to the variable that receives the GUID for the associated class.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

If the specified device information set does not have an associated class because a class GUID was not specified when the set was created with SetupDiCreateDeviceInfoList, the function fails. In this case, a call to GetLastError returns ERROR_NO_ASSOCIATED_CLASS.

If a device information set is for a remote machine, use SetupDiGetDeviceInfoListDetail to get the associated remote machine handle and machine name.

See Also

SetupDiCreateDeviceInfoList, SetupDiGetClassDevs, SetupDiGetDeviceInfoListDetail


SetupDiGetDeviceInfoListDetail

SetupDiGetDeviceInfoListDetail retrieves information associated with a device information set including the class GUID, remote machine handle, and remote machine name.

WINSETUPAPI BOOL WINAPI
  SetupDiGetDeviceInfoListDetail(
    IN HDEVINFO  DeviceInfoSet,
    OUT PSP_DEVINFO_LIST_DETAIL_DATA  DeviceInfoSetDetailData
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set to query.
DeviceInfoSetDetailData
Supplies a pointer to a caller-allocated SP_DEVINFO_LIST_DETAIL_DATA structure that receives the device information set information.

The caller must set cbSize to sizeof(SP_DEVINFO_LIST_DETAIL_DATA) or the function will fail with GetLastError returning ERROR_INVALID_USER_BUFFER.

If the function completes successfully, ClassGuid contains the class GUID associated with the device information set or GUID_NULL.

If the function completes successfully and the device information set is for a remote machine, RemoteMachineHandle contains the ConfigMgr32 machine handle for accessing the remote machine and RemoteMachineName contains the name of the remote machine. If there is a remote handle for the device information set, it must be used when calling CM_Xxx_Ex functions because the DevInst handles are relative to the remote handle.

If the device information set is for the local machine, RemoteMachineHandle is NULL and RemoteMachineName is an empty string.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

If the parameters are valid, SetupDiGetDeviceInfoListDetail sets values in the DeviceInfoSetDetailData structure (except for the cbSize field) and returns status NO_ERROR.

See Also

SetupDiCreateDeviceInfoListEx, SetupDiGetClassDevsEx, SetupDiGetDeviceInfoListClass


SetupDiGetDeviceInstallParams

SetupDiGetDeviceInstallParams retrieves device install parameters for a device information set or a particular device information element.

WINSETUPAPI BOOL WINAPI
  SetupDiGetDeviceInstallParams(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData,  OPTIONAL
    OUT PSP_DEVINSTALL_PARAMS  DeviceInstallParams
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set containing information about the device instance to retrieve.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that contains the device install parameters to retrieve. If this parameter is not specified, the install parameters retrieved are those associated with the device information set.
DeviceInstallParams
Supplies a pointer to an SP_DEVINSTALL_PARAMS structure that receives the device install parameters. The cbSize field of this structure must be set to the size, in bytes, of the structure before calling this function.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

See Also

SetupDiSetDeviceInstallParams,SP_DEVINFO_DATA,SP_DEVINSTALL_PARAMS


SetupDiGetDeviceInstanceId

SetupDiGetDeviceInstanceId retrieves the device instance ID associated with a device information element.

WINSETUPAPI BOOL WINAPI
  SetupDiGetDeviceInstanceId(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData,
    OUT PTSTR  DeviceInstanceId,
    IN DWORD  DeviceInstanceIdSize,
    OUT PDWORD  RequiredSize  OPTIONAL
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set that contains the device information element to retrieve.
DeviceInfoData
Supplies a pointer to the SP_DEVINFO_DATA structure for the device information element whose ID is to be retrieved.
DeviceInstanceId
Supplies a pointer to the character buffer that will receive the ID for the specified device information element.
DeviceInstanceIdSize
Supplies the size, in characters, of the DeviceInstanceId buffer.
RequiredSize
Supplies a pointer to the variable that receives the number of characters required to store the device instance ID.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

See Also

SetupDiCreateDeviceInfo, SetupDiCreateDevRegKey, SetupDiOpenDeviceInfo, SetupDiOpenDevRegKey, SP_DEVINFO_DATA


SetupDiGetDeviceInterfaceAlias

SetupDiGetDeviceInterfaceAlias returns an alias of the specified device interface. Device interfaces are considered aliases if they are exposed by the same underlying device and have identical reference strings, but are of different interface classes.

WINSETUPAPI BOOL WINAPI
  SetupDiGetDeviceInterfaceAlias(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVICE_INTERFACE_DATA  DeviceInterfaceData,
    IN LPGUID  AliasInterfaceClassGuid,
    OUT PSP_DEVICE_INTERFACE_DATA  AliasDeviceInterfaceData
    );

Parameters

DeviceInfoSet
Points to the device information set containing the device interface for which to retrieve an alias. This handle is typically returned by SetupDiGetClassDevs.
DeviceInterfaceData
Points to a SP_DEVICE_INTERFACE_DATA structure that identifies the device interface within the device information set. This pointer is typically returned by SetupDiEnumDeviceInterfaces.
AliasInterfaceClassGuid
Is a class GUID specifying the interface class of the alias to retrieve.
AliasDeviceInterfaceData
Points to a caller-allocated buffer that contains, on successful return, a completed SP_DEVICE_INTERFACE_DATA structure that identifies the requested alias. The caller must set AliasDeviceInterfaceData.cbSize to sizeof(SP_DEVICE_INTERFACE_DATA) before calling this function.

Return Value

SetupDiGetDeviceInterfaceAlias returns TRUE if the function completed without error. If the function completed with an error, FALSE is returned and the error code for the failure can be retrieved by calling GetLastError.

Possible errors returned by GetLastError are listed in the following table.

Error | Meaning
ERROR_INVALID_PARAMETER | Invalid DeviceInfoSet or invalid DeviceInterfaceData parameter.
ERROR_NO_SUCH_INTERFACE_DEVICE | There is no alias of class AliasInterfaceClassGuid for the specified device interface.
ERROR_INVALID_USER_BUFFER | Invalid AliasDeviceInterfaceData buffer.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

SetupDiGetDeviceInterfaceAlias can be used to locate a device that exposes more than one interface. For example, consider a disk that can be part of a fault-tolerant volume and can contain encrypted data. The function driver for the disk device could register a fault-tolerant-volume interface and an encrypted-volume interface. These interfaces are device interface aliases if the function driver registers them with identical reference strings and they refer to the same device. (The reference strings will likely be NULL and therefore are equal.)

To locate such a multi-interface device, first locate all available devices that expose one of the interfaces, such as the fault-tolerant-volume interface, using SetupDiGetClassDevs and SetupDiEnumDeviceInterfaces. Then, pass a device with the first interface (fault-tolerant-volume) to SetupDiGetDeviceInterfaceAlias and request an alias of the other interface class (encrypted-volume).

If the requested alias exists but the caller-supplied AliasDeviceInterfaceData buffer is invalid, this function successfully adds the device interface element to DevInfoSet but returns FALSE for the return value. In this case, GetLastError returns ERROR_INVALID_USER_BUFFER.

See Also

SetupDiEnumDeviceInterfaces, SetupDiGetClassDevs


SetupDiGetDeviceInterfaceDetail

SetupDiGetDeviceInterfaceDetail returns details about a particular device interface.

WINSETUPAPI BOOL WINAPI
  SetupDiGetDeviceInterfaceDetail(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVICE_INTERFACE_DATA  DeviceInterfaceData,
    OUT PSP_DEVICE_INTERFACE_DETAIL_DATA  DeviceInterfaceDetailData,  OPTIONAL
    IN DWORD  DeviceInterfaceDetailDataSize,
    OUT PDWORD  RequiredSize,  OPTIONAL
    OUT PSP_DEVINFO_DATA  DeviceInfoData  OPTIONAL
    );

Parameters

DeviceInfoSet
Points to the device information set containing the interface and its underlying device. This handle is typically returned by SetupDiGetClassDevs.
DeviceInterfaceData
Points to a SP_DEVICE_INTERFACE_DATA structure that identifies the interface, typically returned by SetupDiEnumDeviceInterfaces.
DeviceInterfaceDetailData
Optionally points to a caller-allocated SP_DEVICE_INTERFACE_DETAIL_DATA structure to receive information about the specified interface. The caller must set DeviceInterfaceDetailData.cbSize to sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) before calling this function. The cbSize field always contains the size of the fixed part of the data structure, not a size reflecting the variable-length string at the end.

This parameter must be NULL if DeviceInterfaceDetailSize is zero.

DeviceInterfaceDetailDataSize
Specifies the size of the DeviceInterfaceDetailData buffer. The buffer must be at least (offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA, DevicePath) + sizeof(TCHAR)) bytes, to contain the fixed part of the structure and a single NULL to terminate an empty MULTI_SZ string.

This parameter must be zero if DeviceInterfaceDetailData is NULL.

RequiredSize
Optionally points to a caller-allocated variable to receive the required size of the DeviceInterfaceDetailData buffer. This size includes the size of the fixed part of the structure plus the number of bytes required for the variable-length device path string.
DeviceInfoData
Optionally points to a caller-allocated buffer to receive information about the device that exposes the requested interface. The caller must set DeviceInfoData.cbSize to sizeof(SP_DEVINFO_DATA).

Return Value

SetupDiGetDeviceInterfaceDetail returns TRUE if the function completed without error. If the function completed with an error, FALSE is returned and the error code for the failure can be retrieved by calling GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

Using this function to get details about an interface is typically a two-step process:

  1. Get the required buffer size. Call SetupDiGetDeviceInterfaceDetail with a NULL DeviceInterfaceDetailData pointer, an DeviceInterfaceDetailDataSize of zero, and a valid RequiredSize variable. In response to such a call, this function returns the required buffer size at RequiredSize and fails with GetLastError returning ERROR_INSUFFICIENT_BUFFER.
  2. Allocate an appropriately sized buffer and call the function again to get the interface details.

The interface detail returned by this function consists of a device path that can be passed to Win32 functions such as CreateFile. Do not attempt to parse the device path symbolic name. The device path can be reused across system boots.

SetupDiGetDeviceInterfaceDetail can be used to get just the DeviceInfoData. If the interface exists but DeviceInterfaceDetailData is NULL, this function fails, GetLastError returns ERROR_INSUFFICIENT_BUFFER, and the DeviceInfoData structure is filled with information about the device that exposes the interface.

See Also

SetupDiEnumDeviceInterfaces, SetupDiGetClassDevs


SetupDiGetDeviceRegistryProperty

SetupDiGetDeviceRegistryProperty retrieves the specified Plug and Play device property.

WINSETUPAPI BOOL WINAPI
  SetupDiGetDeviceRegistryProperty(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData,
    IN DWORD  Property,
    OUT PDWORD  PropertyRegDataType,  OPTIONAL
    OUT PBYTE  PropertyBuffer,
    IN DWORD  PropertyBufferSize,
    OUT PDWORD  RequiredSize  OPTIONAL
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set containing information about the device instance for which to retrieve a Plug and Play property.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure indicating the device instance for which to retrieve the Plug and Play property.
Property
Supplies one of the following values, indicating the property to be retrieved:
SPDRP_ADDRESS
The function retrieves the device's address.
SPDRP_BUSNUMBER
The function retrieves the device's bus number.
SPDRP_BUSTYPEGUID
The function retrieves the GUID for the device's bus type.
SPDRP_CAPABILITIES
The function retrieves the device's Capabilities registry value, which is a DWORD containing device capability flags. These flags are represented by CM_DEVCAP_xxxx bit masks defined in cfgmgr32.h.
SPDRP_CHARACTERISTICS
The function retrieves the device's Characteristics registry value, which is a DWORD containing the device's characteristics flags. For a description of these flags, which are defined in wdm.h and ntddk.h, see the IoCreateDevice function's DeviceCharacteristics parameter.
SPDRP_CLASS
The function retrieves the device's Class registry value, which is a string respresenting the setup class for the device.
SPDRP_CLASSGUID
The function retrieves the device's ClassGUID registry value, which is a string containing the GUID that represents the device's setup class.
SPDRP_COMPATIBLEIDS
The function retrieves the device's CompatibleID registry value, which is a multi-string containing the device's compatible IDs.
SPDRP_CONFIGFLAGS
The function retrieves the device's ConfigFlags registry value, which is a DWORD value containing configuration flags. These flags are represented by CONFIGFLAG_xxxx bit masks defined in regstr.h.
SPDRP_DEVICE_POWER_DATA
(Windows XP and later) The function retrieves a CM_POWER_DATA structure containing the device's power management information.
SPDRP_DEVICEDESC
The function retrieves the device's DeviceDesc registry value, which is a string containing a description of the device.
SPDRP_DEVTYPE
The function retrieves a DWORD value representing the device's type (see Specifying Device Types).
SPDRP_DRIVER
The function retrieves the device's Driver registry value, which is a string identifying the device's software key (sometimes called the "driver key"). See Driver Information in the Registry.
SPDRP_ENUMERATOR_NAME
The function retrieves the name of the device's Enumerator registry value, which is string representing the name of the device's enumerator.
SPDRP_EXCLUSIVE
The function retrieves the value of the device's Exclusive registry value, which is a DWORD indicating whether a user can obtain exclusive use of the device. The returned value is one if exclusive use is allowed, or zero otherwise. For more information, see IoCreateDevice.
SPDRP_FRIENDLYNAME
The function retrieves the device's FriendlyName registry value, which is a string respresenting the device's displayable friendly name.
SPDRP_HARDWAREID
The function retrieves the device's HardwareID registry value, which is a multi-string containing the device's hardware IDs.
SPDRP_LEGACYBUSTYPE
The function retrieves the device's legacy bus type as an INTERFACE_TYPE value (defined in wdm.h and ntddk.h).
SPDRP_LOCATION_INFORMATION
The function retrieves the device's LocationInformation registry value, which is a string describing the device's hardware location.
SPDRP_LOWERFILTERS
The function retrieves device's LowerFilters registry value, which is a multi-string representing the names of the device's lower filter drivers.
SPDRP_MFG
The function retrieves the device's Mfg registry value, which is a string representing the device's manufacturer.
SPDRP_PHYSICAL_DEVICE_OBJECT_NAME
The function retrieves the device's PhysicalDeviceObject registry value, which is a string representing the name associated with the drivce's PDO. For more information, see IoCreateDevice.
SPDRP_REMOVAL_POLICY
(Windows XP and later) The function retrieves the device's current removal policy as a DWORD containing one of the CM_REMOVAL_POLICY_Xxxx values defined in cfgmgr32.h.
SPDRP_REMOVAL_POLICY_HW_DEFAULT
(Windows XP and later) The function retrieves the device's hardware-specified default removal policy as a DWORD containing one of the CM_REMOVAL_POLICY_Xxxx values defined in cfgmgr32.h.
SPDRP_REMOVAL_POLICY_OVERRIDE
(Windows XP and later) The function retrieves the device's override removal policy (if it exists) from the registry, as a DWORD containing one of the CM_REMOVAL_POLICY_Xxxx values defined in cfgmgr32.h.
SPDRP_SECURITY
The function retrieves the device's Security registry value as a SECURITY_DESCRIPTOR structure (described in Platform SDK documentation).
SPDRP_SECURITY_SDS
The function retrieves the device's Security registry value as a string.
SPDRP_SERVICE
The function retrieves the device's Service registry value, which is a string representing the service name.
SPDRP_UI_NUMBER
The function retrieves the device's UINumber registry value, which is a DWORD value equal to the value contained in the UINumber member of the DEVICE_CAPABILITIES structure.
SPDRP_UI_NUMBER_DESC_FORMAT
The function retrieves the device's UINumberDescFormat registry value, which contains a format string used to display the UINumber value.
SPDRP_UPPERFILTERS
The function retrieves device's UpperFilters registry value, which is a multi-string representing the names of the device's lower upper drivers.
PropertyRegDataType
Supplies a pointer to a variable to receive the data type of the property being retrieved. This is one of the standard registry data types.
PropertyBuffer
Supplies a pointer to a buffer to receive the property being retrieved. If set to NULL, with PropertyBufferSize set to zero, the function just returns a value for RequiredSize.
PropertyBufferSize
Supplies the length, in bytes, of PropertyBuffer.
RequiredSize
Optional. If not NULL, it is a caller-supplied pointer to a variable that receives the required size, in bytes, of the property buffer pointed to by PropertyBuffer, based on the property requested by Property.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

See Also

SetupDiGetClassRegistryProperty, SetupDiSetClassRegistryProperty, SetupDiSetDeviceRegistryProperty, IoGetDeviceProperty


SetupDiGetDriverInfoDetail

SetupDiGetDriverInfoDetail retrieves detailed information for a specified driver information element.

WINSETUPAPI BOOL WINAPI
  SetupDiGetDriverInfoDetail(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData,  OPTIONAL
    IN PSP_DRVINFO_DATA  DriverInfoData,
    OUT PSP_DRVINFO_DETAIL_DATA  DriverInfoDetailData,  OPTIONAL
    IN DWORD  DriverInfoDetailDataSize,
    OUT PDWORD  RequiredSize  OPTIONAL
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set that contains a driver information structure for which to retrieve details.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that contains a driver information structure for which to retrieve details. If this parameter is not specified, the driver referenced is a member of the global class driver list owned by the device information set.
DriverInfoData
Supplies a pointer to an SP_DRVINFO_DATA structure that specifies the driver for which details are to be retrieved.
DriverInfoDetailData
Supplies a pointer to an SP_DRVINFO_DETAIL_DATA structure that receives detailed information about the specified driver. If this parameter is not specified, DriverInfoDetailDataSize must be 0. If this parameter is specified, the cbSize field of this structure must be set to the size, in bytes, of the structure before calling SetupDiGetDriverInfoDetail.
DriverInfoDetailDataSize
Supplies the size, in bytes, of the DriverInfoDetailData buffer.
RequiredSize
Supplies a pointer to a variable that receives the number of bytes required to store the detailed driver information. This value includes both the size of the structure and the additional bytes required for the variable-length character buffer at the end that holds the hardware ID and the compatible IDs MULTI_SZ list.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

If the specified driver information member and the caller-supplied buffer are both valid, this function is guaranteed to fill in all static fields in the SP_DRVINFO_DETAIL_DATA structure and as many IDs as possible in the variable-length buffer at the end while still maintaining MULTI_SZ format. In this case, the function returns FALSE and a call to GetLastError returns ERROR_INSUFFICIENT_BUFFER. If specified, RequiredSize contains the total number of bytes required for the structure with all IDs.

See Also

SetupDiEnumDriverInfo, SetupDiGetSelectedDriver


SetupDiGetDriverInstallParams

SetupDiGetDriverInstallParams retrieves install parameters for the specified driver.

WINSETUPAPI BOOL WINAPI
  SetupDiGetDriverInstallParams(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData,  OPTIONAL
    IN PSP_DRVINFO_DATA  DriverInfoData,
    OUT PSP_DRVINSTALL_PARAMS  DriverInstallParams
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set containing a driver information structure for which to retrieve installation parameters.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that contains a driver information structure for which to retrieve installation parameters. If DeviceInfoData is not specified, the driver referenced is a member of the global class driver list owned by the device information set.
DriverInfoData
Supplies a pointer to an SP_DRVINFO_DATA structure that specifies the driver for which install parameters are to be retrieved.
DriverInstallParams
Supplies a pointer to an SP_DRVINSTALL_PARAMS structure to receive the install parameters for this driver. The cbSize field of this structure must be set to the size, in bytes, of the structure before calling this function.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved by a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

See Also

SetupDiSetDriverInstallParams


SetupDiGetHwProfileFriendlyName

SetupDiGetHwProfileFriendlyName retrieves the friendly name associated with a hardware profile ID.

WINSETUPAPI BOOL WINAPI
  SetupDiGetHwProfileFriendlyName(
    IN DWORD  HwProfile,
    OUT PTSTR  FriendlyName,
    IN DWORD  FriendlyNameSize,
    OUT PDWORD  RequiredSize  OPTIONAL
    );

Parameters

HwProfile
Supplies the hardware profile ID associated with the friendly name to retrieve. If this parameter is 0, the friendly name for the current hardware profile is retrieved.
FriendlyName
Supplies a pointer to a character buffer to receive the friendly name.
FriendlyNameSize
Supplies the size, in characters, of the FriendlyName buffer.
RequiredSize
Supplies a pointer to a variable to receive the number of characters required to store the friendly name (including the terminating NULL).

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

Call SetupDiGetHwProfileFriendlyNameEx to get the friendly name of a hardware profile ID on a remote machine.

See Also

SetupDiGetHwProfileFriendlyNameEx, SetupDiGetHwProfileList


SetupDiGetHwProfileFriendlyNameEx

SetupDiGetHwProfileFriendlyNameEx retrieves the friendly name associated with a hardware profile ID on a local or remote machine.

WINSETUPAPI BOOL WINAPI
  SetupDiGetHwProfileFriendlyNameEx(
    IN DWORD  HwProfile,
    OUT PTSTR  FriendlyName,
    IN DWORD  FriendlyNameSize,
    OUT PDWORD  RequiredSize,  OPTIONAL
    IN PCTSTR  MachineName,  OPTIONAL
    IN PVOID  Reserved
    );

Parameters

HwProfile
Supplies the hardware profile ID associated with the friendly name to retrieve. If this parameter is 0, the friendly name for the current hardware profile is retrieved.
FriendlyName
Supplies a pointer to a character buffer to receive the friendly name.
FriendlyNameSize
Supplies the size, in characters, of the FriendlyName buffer.
RequiredSize
Supplies a pointer to a variable to receive the number of characters required to store the friendly name (including the terminating NULL).
MachineName
Optionally supplies the name of a remote machine on which the hardware profile ID resides. If MachineName is NULL, the hardware profile ID is on the local machine.
Reserved
Must be NULL.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

See Also

SetupDiGetHwProfileFriendlyName, SetupDiGetHwProfileListEx


SetupDiGetHwProfileList

SetupDiGetHwProfileList retrieves a list of all currently defined hardware profile IDs.

WINSETUPAPI BOOL WINAPI
  SetupDiGetHwProfileList
    OUT PDWORD  HwProfileList,
    IN DWORD  HwProfileListSize,
    OUT PDWORD  RequiredSize,
    OUT PDWORD  CurrentlyActiveIndex  OPTIONAL
    );

Parameters

HwProfileList
Supplies a pointer to an array to receive the list of currently defined hardware profile IDs.
HwProfileListSize
Supplies the number of DWORDs in the HwProfileList buffer.
RequiredSize
Supplies a pointer to a variable that receives the number of hardware profiles currently defined. If the number is larger than HwProfileListSize, the list is truncated to fit the array size. The value returned in RequiredSize indicates the array size required to store the entire list of hardware profiles. In this case, the function fails and a call to GetLastError returns ERROR_INSUFFICIENT_BUFFER.
CurrentlyActiveIndex
Supplies a pointer to a variable that receives the index within the returned HwProfileList of the currently active hardware profile.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

Call SetupDiGetHwProfileListEx to retrieve the hardware profile IDs for a remote machine.

See Also

SetupDiCreateDevRegKey, SetupDiOpenDevRegKey


SetupDiGetHwProfileListEx

SetupDiGetHwProfileListEx retrieves a list of all currently defined hardware profile IDs on a local or remote machine.

WINSETUPAPI BOOL WINAPI
  SetupDiGetHwProfileListEx(
    OUT PDWORD  HwProfileList,
    IN DWORD  HwProfileListSize,
    OUT PDWORD  RequiredSize,
    OUT PDWORD  CurrentlyActiveIndex,  OPTIONAL
    IN PCTSTR  MachineName,  OPTIONAL
    IN PVOID  Reserved
    );

Parameters

HwProfileList
Supplies a pointer to an array to receive the list of currently defined hardware profile IDs.
HwProfileListSize
Supplies the number of DWORDs in the HwProfileList buffer.
RequiredSize
Supplies a pointer to a variable that receives the number of hardware profiles currently defined. If the number is larger than HwProfileListSize, the list is truncated to fit the array size. The value returned in RequiredSize indicates the array size required to store the entire list of hardware profiles. In this case, the function fails and a call to GetLastError returns ERROR_INSUFFICIENT_BUFFER.
CurrentlyActiveIndex
Supplies a pointer to a variable that receives the index within the returned HwProfileList of the currently active hardware profile.
MachineName
Optionally supplies the name of a remote machine for which to retrieve the list of hardware profile IDs. If MachineName is NULL, the list is retrieved for the local machine.
Reserved
Must be NULL.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

See Also

SetupDiGetHwProfileFriendlyNameEx


SetupDiGetINFClass

SetupDiGetINFClass returns the class of a specified device INF file.

WINSETUPAPI BOOL WINAPI
  SetupDiGetINFClass(
    IN PCTSTR  InfName,
    OUT LPGUID  ClassGuid,
    OUT PTSTR  ClassName,
    IN DWORD  ClassNameSize,
    OUT PDWORD  RequiredSize  OPTIONAL,
    );

Parameters

InfName
Supplies the name of a device INF file. This name can include a path. However, if just the filename is specified, the file is searched for in each directory listed in the DevicePath entry under the HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion subkey of the registry.
ClassGuid
Receives the class GUID for the specified INF file. If the INF file does not specify a class name, this variable is set to GUID_NULL. Call SetupDiClassGuidsFromName to determine if one or more classes with this name are already installed.
ClassName
Receives the name of the class for the specified INF file. If the INF file does not specify a class name, but does specify a GUID, this buffer receives the name retrieved by calling SetupDiClassNameFromGuid. However, if SetupDiClassNameFromGuid cannot retrieve a class name (for example, the class is not installed), it returns an empty string.
ClassNameSize
Supplies the size, in characters, of the ClassName buffer.
RequiredSize
Receives the number of characters required to store the class name (including terminating NULL). RequiredSize is always less than MAX_CLASS_NAME_LEN.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

This function works with device INF files on Windows NT 4.0 and later, and Windows 9x/Me. Do not use this function with legacy INF files.

See Also

SetupDiBuildClassInfoList, SetupDiClassGuidsFromName, SetupDiClassNameFromGuid, SetupDiGetClassDescription


SetupDiGetSelectedDevice

SetupDiGetSelectedDevice retrieves the currently-selected device for the specified device information set.

WINSETUPAPI BOOL WINAPI
  SetupDiGetSelectedDevice(
    IN HDEVINFO  DeviceInfoSet,
    OUT PSP_DEVINFO_DATA  DeviceInfoData
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set from which to retrieve the selected device.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that receives the currently-selected device. The caller must set cbSize to sizeof(SP_DEVINFO_DATA). If a device is not currently selected, the function fails and a call to GetLastError returns ERROR_NO_DEVICE_SELECTED.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

SetupDiGetSelectedDevice is usually used by an installation wizard.

See Also

SetupDiSetSelectedDevice, SP_DEVINFO_DATA


SetupDiGetSelectedDriver

SetupDiGetSelectedDriver retrieves the member of a driver list that has been selected as the driver to install.

WINSETUPAPI BOOL WINAPI
  SetupDiGetSelectedDriver(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData,  OPTIONAL
    OUT PSP_DRVINFO_DATA  DriverInfoData
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set to query.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that indicates the device instance for which to retrieve the selected driver. If this parameter is NULL, the selected class driver for the global class driver list is retrieved.
DriverInfoData
Supplies a pointer to an SP_DRVINFO_DATA structure that receives information about the selected driver.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError. If a driver has not been selected for the specified device instance, the logged error is ERROR_NO_DRIVER_SELECTED.

Headers

Declared in setupapi.h. Include setupapi.h.

See Also

SetupDiSetSelectedDriver


SetupDiGetWizardPage

This function is reserved for system use. For information on wizard pages, see the DIF_NEWDEVICEWIZARD_XXX requests such as DIF_NEWDEVICEWIZARD_FINISHINSTALL.

HPROPSHEETPAGE
  SetupDiGetWizardPage(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData,  OPTIONAL
    IN PSP_INSTALLWIZARD_DATA  InstallWizardData,
    IN DWORD  PageType,
    IN DWORD  Flags
    );


SetupDiInstallClass

SetupDiInstallClass installs the ClassInstall32 section of the specified INF file.

WINSETUPAPI BOOL WINAPI
  SetupDiInstallClass(
    IN HWND  hwndParent,  OPTIONAL
    IN PCTSTR  InfFileName,
    IN DWORD  Flags,
    IN HSPFILEQ  FileQueue  OPTIONAL
    );

Parameters

hwndParent
Supplies the handle of the parent window for any user interface used to install this class.
InfFileName
Specifies the name of the INF file containing an INF ClassInstall32 section.
Flags
These flags control the installation process. Can be a combination of the following:
DI_NOVCP
Set this flag if FileQueue is supplied. DI_NOVCP instructs the SetupInstallFromInfSection function (described in Platform SDK documentation) not to create a queue of its own and to use the caller-supplied queue instead. If this flag is set, files are not copied just queued.
DI_NOBROWSE
Set this flag to disable browsing in the event a copy operation cannot find a specified file. If the caller supplies a file queue, this flag is ignored.
DI_FORCECOPY
Set this flag to always copy files, even if they are already present on the user's machine. If the caller supplies a file queue, this flag is ignored.
DI_QUIETINSTALL
Set this flag to suppress the user interface unless absolutely necessary. For example, do not display the progress dialog. If the caller supplies a file queue, this flag is ignored.
FileQueue
If the DI_NOVCP flag is set, this parameter supplies a handle to a file queue where file operations should be queued but not committed.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

This function is called by a class installer when it installs a device of a new device class.

To install an interface class or a device class, use SetupDiInstallClassEx.

See Also

SetupDiCallClassInstaller, SetupDiInstallClassEx


SetupDiInstallClassEx

SetupDiInstallClassEx installs a class installer or an interface class.

WINSETUPAPI BOOL WINAPI
  SetupDiInstallClassEx(
    IN HWND  hwndParent,  OPTIONAL
    IN PCTSTR  InfFileName,  OPTIONAL
    IN DWORD  Flags,
    IN HSPFILEQ  FileQueue,  OPTIONAL
    IN LPGUID  InterfaceClassGuid,  OPTIONAL
    IN PVOID  Reserved1,
    IN PVOID  Reserved2
    );

Parameters

hwndParent
Optionally supplies the handle of the parent window for any user interface used to install this class.
InfFileName
Optionally specifies the name of an INF file.

If this function is being used to install a class installer, the INF file contains an INF ClassInstall32 section and this parameter must not be NULL.

If this function is being used to install an interface class, the INF file contains an INF InterfaceInstall32 section.

Flags
Specifies flags that control the installation process. Can be a combination of the following:
DI_NOVCP
Set this flag if FileQueue is supplied. DI_NOVCP instructs the SetupInstallFromInfSection function (described in Platform SDK documentation) to not create a queue of its own and to use the caller-supplied queue instead. If this flag is set, files are not copied just queued.
DI_NOBROWSE
Set this flag to disable browsing in the event a copy operation cannot find a specified file. If the caller supplies a file queue, this flag is ignored.
DI_FORCECOPY
Set this flag to always copy files, even if they are already present on the user's machine. If the caller supplies a file queue, this flag is ignored.
DI_QUIETINSTALL
Set this flag to suppress the user interface unless absolutely necessary. For example, do not display the progress dialog. If the caller supplies a file queue, this flag is ignored.
FileQueue
If the DI_NOVCP flag is set, this parameter supplies a handle to a file queue where file operations should be queued but not committed.
InterfaceClassGuid
Optionally points to a GUID specifying an interface class to be installed. If this parameter is not NULL, this function is being used to install the interface class represented by the GUID. If this parameter is NULL, this function is being used to install a class installer.
Reserved1
Reserved. Must be zero.
Reserved2
Reserved. Must be zero.

Return Value

SetupDiInstallClassEx returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

SetupDiInstallClassEx is typically called by a class installer to install a new device setup class or a new device interface class. Note that an interface class can also be installed automatically as a result of installing the device interfaces for a device instance (SetupDiInstallDeviceInterfaces).

See Also

SetupDiCallClassInstaller, SetupDiInstallDeviceInterfaces


SetupDiInstallDevice

SetupDiInstallDevice is the default handler for the DIF_INSTALLDEVICE installation request. It installs a driver for a device.

WINSETUPAPI BOOL WINAPI
  SetupDiInstallDevice(
    IN HDEVINFO  DeviceInfoSet,
    IN OUT PSP_DEVINFO_DATA  DeviceInfoData
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set for the local machine that contains the device to be installed.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that identifies the device to be installed. This is an IN OUT parameter because the DevInst field of the structure can be updated with a new handle value upon return.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

Co-installers should not call default DIF code handlers.

This function installs a driver from the INF file. SetupAPI's definition of the "driver" is really a "driver node". Therefore, when this function installs a driver, that includes installing the service(s) for the device, the driver files, any device-specific co-installers, property-page providers, and control-panel applets, and registering any device interfaces. A successful installation includes, but is not limited to, the following steps:

  • Create a driver key in the registry and write appropriate entries (such as InfPath and ProviderName).
  • Locate and process the INF DDInstall section for the device. The section might be OS/architecture-specific. The DDInstall section's AddReg and DelReg entries are directed at the device's software key. Locate and process the DDInstall.HW section whose AddReg and DelReg entries are directed at the device's hardware key. Locate and process the INF DDInstall.LogConfigOverride section, if present, to supply an override configuration for the device. Locate and process the INF DDInstall.Services section to add services for the device (and potentially remove any old services that are no longer necessary).
  • Copy the INF to the system INF directory.
  • Possibly perform the other file operations, based on flag settings in the device installation parameters.

    If the DI_NOFILECOPY flag and the DI_NOVCP flag are clear, perform any file operations specified in the DDInstall section. If the DI_NOVCP flag is set, queue any file operations. If the DI_NOFILECOPY flag is set, do not copy the files; this flag might be set if, for example, a DIF_INSTALLDEVICEFILES operation was already performed for this device installation.

  • Load the drivers for the device, including the function driver and any upper or lower filter drivers.
  • Call the drivers' AddDevice routines.
  • Start the device (send an IRP_MN_START_DEVICE).

Setup does not start the device if the DI_NEEDRESTART, DI_NEEDREBOOT, or DI_DONOTCALLCONFIGMG flag is set in the SP_DEVINSTALL_PARAMS structure.

A class installer should return ERROR_DI_DO_DEFAULT or call this function when handling a DIF_INSTALLDEVICE request. This function performs numerous tasks for device installation and that list of tasks might be expanded in future releases. If a class installer performs device installation without calling this function, the class installer might not work properly on future versions of the operating system.

When GUI-mode setup finds a devnode for which no INF match exists, it first attempts to install a null driver, sending DIF_INSTALLDEVICE with the DI_FLAGSEX_SETFAILEDINSTALL flag cleared. Installation software might succeed this request (if, for example, the device can be used in raw mode, or if it is a non-PnP device). However, if the installation software fails the request, GUI-mode setup sends the DIF_INSTALLDEVICE request again, this time with the DI_FLAGSEX_SETFAILEDINSTALL flag set. This causes the SetupDiInstallDevice function to set the FAILEDINSTALL flag in the ConfigFlags registry value for the device. Installation software must succeed this request.

See Also

DIF_INSTALLDEVICE, SetupDiCallClassInstaller, SetupDiInstallDriverFiles


SetupDiInstallDeviceInterfaces

SetupDiInstallDeviceInterfaces is the default handler for the DIF_INSTALLINTERFACES installation request. It installs the interfaces listed in an INF DDInstall.Interfaces section of a device INF file.

WINSETUPAPI BOOL WINAPI
  SetupDiInstallDeviceInterfaces(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData
    );

Parameters

DeviceInfoSet
Points to the device information set containing the device whose interfaces are to be installed. The device information set must not contain remote elements.
DeviceInfoData
Points to an SP_DEVINFO_DATA structure that identifies a device in the device information set.

Return Value

SetupDiInstallDeviceInterfaces returns TRUE if the function completed without error. If the function completed with an error, FALSE is returned and the error code for the failure can be retrieved by calling GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

Co-installers should not call default DIF code handlers.

SetupDiInstallDeviceInterfaces processes each AddInterface entry in the INF file and creates each interface using SetupDiCreateDeviceInterface.

The DeviceInfoSet must only contain elements on the local machine.

For information on INF file format, see INF File Sections and Directives.

See Also

DIF_INSTALLINTERFACES, SetupDiCreateDeviceInterface


SetupDiInstallDriverFiles

SetupDiInstallDriverFiles is the default handler for the DIF_INSTALLDEVICEFILES installation request. It is similar to the SetupDiInstallDevice function; however, it performs only the file copy commands. The SetupDiInstallDriverFiles function does not configure the device.

WINSETUPAPI BOOL WINAPI
  SetupDiInstallDriverFiles(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData  OPTIONAL
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set for which driver files are to be installed. The device information set must not contain remote elements.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure indicating a particular member for which to perform file installation.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

Co-installers should not call default DIF code handlers.

A driver must be selected for the specified device information set or element before this function is called.

This function processes the CopyFiles, Delfiles, and Renfiles entries in the selected INF.

The DeviceInfoSet must only contain elements on the local machine.

See Also

SetupDiCallClassInstaller, SetupDiInstallDevice


SetupDiLoadClassIcon

SetupDiLoadClassIcon loads both the large and mini-icon for the specified class.

WINSETUPAPI BOOL WINAPI
  SetupDiLoadClassIcon(
    IN LPGUID  ClassGuid,
    OUT HICON  *LargeIcon,  OPTIONAL
    OUT LPINT  MiniIconIndex  OPTIONAL
    );

Parameters

ClassGuid
Supplies the GUID of the class for which the icon(s) should be loaded.
LargeIcon
Supplies a pointer to a variable to receive a handle for the loaded large icon for the specified class. If this parameter is not specified, the large icon is not loaded.
MiniIconIndex
Supplies a pointer to a variable to receive the index of the mini-icon for the specified class. The mini-icon is stored in the device installer's mini-icon cache.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved by a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

The icons of the class are either predefined and loaded from the device installer's internal cache, or they are loaded directly from the class installer's executable. This function queries the registry value ICON in the specified class's section. If the ICON value is specified, it indicates which mini-icon to load.

If the ICON value is negative, the absolute value represents a predefined icon in the class's registry. See SetupDiDrawMiniIcon for a list of the predefined mini-icons.

If the ICON value is positive, it represents an icon in the class installer's executable that will be extracted. The value 1 is reserved. This function also uses the INSTALLER32 registry value and then the ENUMPROPPAGES32 registry value to determine which executable to extract the icon(s) from. For more information about these registry values, see INF ClassInstall32 Section.

See Also

SetupDiDrawMiniIcon, SetupDiGetClassBitmapIndex


SetupDiMoveDuplicateDevice

SetupDiMoveDuplicateDevice is the default handler for the DIF_MOVEDEVICE installation request. This function moves a device to a new location of the Enum branch of the registry.

WINSETUPAPI BOOL WINAPI
  SetupDiMoveDuplicateDevice(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DestinationDeviceInfoData
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set for the device which is to be moved. The device information set must not contain remote elements.
DestinationDeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure for the device instance that is the destination of the move. This device instance must contain class install parameters for DIF_MOVEDEVICE or the function fails with an error of ERROR_NO_CLASSINSTALL_PARAMS.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

Co-installers should not call default DIF code handlers.

This function is typically only used by system components and is not called by vendor device installers.

See Also

SP_MOVEDEV_PARAMS


SetupDiOpenClassRegKey

SetupDiOpenClassRegKey opens the setup class registry key or a specific class's subkey.

HKEY
  SetupDiOpenClassRegKey(
    IN LPGUID  ClassGuid,  OPTIONAL
    IN REGSAM  samDesired
    );

Parameters

ClassGuid
Optionally supplies the GUID of the setup class whose key is to be opened. If this parameter is NULL, the root of the setup class tree (HKLM\SYSTEM\CurrentControlSet\Control\Class) is opened.
samDesired
Specifies the access to the key required by the caller.

Return Value

If the function is successful, it returns a handle to an opened registry key where information pertaining to this setup class can be stored/retrieved. If the function fails, it returns INVALID_HANDLE_VALUE. To get extended error information, call GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

This function does not create a registry key if it does not already exist.

The handle returned from this function must be closed by calling RegCloseKey.

To open the interface class registry key or a specific interface class subkey, call SetupDiOpenClassRegKeyEx.

See Also

SetupDiOpenClassRegKeyEx, SetupDiOpenDevRegKey


SetupDiOpenClassRegKeyEx

SetupDiOpenClassRegKeyEx opens the device setup class registry key, the device interface class registry key, or a specific class's subkey. This function opens the specified key on the local machine or on a remote machine.

HKEY
  SetupDiOpenClassRegKeyEx(
    IN LPGUID  ClassGuid,  OPTIONAL
    IN REGSAM  samDesired,
    IN DWORD  Flags,
    IN PCTSTR  MachineName,  OPTIONAL
    IN PVOID  Reserved
    );

Parameters

ClassGuid
Optionally points to the GUID of the class for which the registry key is to be opened. If this parameter is NULL, the root of the class tree (HKLM\SYSTEM\CurrentControlSet\Control\Class) is opened.
samDesired
Specifies the access to the key required by the caller.
Flags
Specifies the kind of registry key to be opened. Can be one of the following:
DIOCR_INSTALLER
Open a setup class key. If ClassGuid is NULL, open the root key of the class installer branch.
DIOCR_INTERFACE
Open an interface class key. If ClassGuid is NULL, open the root key of the interface class branch.
MachineName
Optionally points to a string containing the name of a remote machine on which to open the specified key.
Reserved
Reserved. Must be NULL.

Return Value

SetupDiOpenClassRegKeyEx returns a handle to an opened registry key where information pertaining to this setup class can be stored/retrieved. If the function fails, it returns INVALID_HANDLE_VALUE. To get extended error information, call GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

SetupDiOpenClassRegKeyEx does not create a registry key if it does not already exist.

Callers of this function must close the handle returned from this function by calling RegCloseKey.

See Also

SetupDiCreateDeviceInterfaceRegKey, SetupDiOpenDevRegKey


SetupDiOpenDeviceInfo

SetupDiOpenDeviceInfo retrieves information about an existing device instance and adds it to the specified device information set. If a device information element already exists for this device instance, the function returns the existing element.

WINSETUPAPI BOOL WINAPI
  SetupDiOpenDeviceInfo(
    IN HDEVINFO  DeviceInfoSet,
    IN PCTSTR  DeviceInstanceId,
    IN HWND  hwndParent,  OPTIONAL
    IN DWORD  OpenFlags,
    OUT PSP_DEVINFO_DATA  DeviceInfoData  OPTIONAL
    );

Parameters

DeviceInfoSet
Supplies a handle to a device information set to which the opened device information element should be added.
DeviceInstanceId
Supplies the ID of the device instance. This is the registry path relative to the Enum path of the device instance key. For example, Root\*PNP0500\0000.
hwndParent
Supplies the window handle of the top-level window to use for any user interface related to installing the device.
OpenFlags
Controls how the device information element is opened. Can be one or more of the following:
DIOD_CANCEL_REMOVE
If this flag is specified and the device had been marked for pending removal, the OS cancels the pending removal.
DIOD_INHERIT_CLASSDRVS
If this flag is specified, the resulting device information element inherits the class driver list, if any, associated with the device information set. In addition, if there is a selected driver for the device information set, that same driver is selected for the new device information element.

If the device information element was already present, its class driver list, if any, is replaced with the inherited list.

DeviceInfoData
Supplies a pointer to a caller-initialized SP_DEVINFO_DATA structure that receives information about the newly-opened device information element. The caller must set cbSize to sizeof(SP_DEVINFO_DATA).

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

If this device instance is being added to a set that has an associated class, the device class must be the same or the call will fail. In this case, a call to GetLastError returns ERROR_CLASS_MISMATCH.

If the new device information element is successfully opened but the caller-supplied DeviceInfoData buffer is invalid, this function returns FALSE. In this case, a call to GetLastError returns ERROR_INVALID_USER_BUFFER. However, the device information element is added as a new member of the set anyway.

See Also

SetupDiCreateDeviceInfo, SetupDiDeleteDeviceInfo, SetupDiEnumDeviceInfo, SP_DEVINFO_DATA


SetupDiOpenDeviceInterface

SetupDiOpenDeviceInterface retrieves information about an existing device interface and adds it to the specified device information set. This function creates a device information element for the underlying device if one is not already present in the device information set.

WINSETUPAPI BOOL WINAPI
  SetupDiOpenDeviceInterface(
    IN HDEVINFO  DeviceInfoSet,
    IN PCTSTR  DevicePath,
    IN DWORD  OpenFlags,
    OUT PSP_DEVICE_INTERFACE_DATA  DeviceInterfaceData  OPTIONAL
    );

Parameters

DeviceInfoSet
Points to a device information set that contains, or will contain, the device that exposes the interface being opened.
DevicePath
Points to a string containing the name of the device interface to be opened. This name is a Win32 device path typcially received in a PnP notification structure or obtained by a previous call to SetupDiEnumDeviceInterfaces and its related functions.
OpenFlags
Reserved. Must be zero.
DeviceInterfaceData
Optionally points to a caller-allocated buffer to receive a completed SP_DEVICE_INTERFACE_DATA structure that identifies the interface. The caller must set DeviceInterfaceData.cbSize to sizeof(SP_DEVICE_INTERFACE_DATA) before calling this function.

Return Value

SetupDiOpenDeviceInterface returns TRUE if the function completed without error. If the function completed with an error, it returns FALSE and the error code for the failure can be retrieved by calling GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

If a device interface element for the interface already exists in DeviceInfoSet, SetupDiOpenDeviceInterface updates the flags. This function, therefore, can be used to refresh the flags for a device interface. For example, an interface might have been inactive when it was first opened, but has subsequently become active.

If the new device interface is successfully opened, but the caller-supplied DeviceInterfaceData buffer is invalid, this function returns FALSE and GetLastError returns ERROR_INVALID_USER_BUFFER. The caller's buffer error does not prevent the interface from being opened.

See Also

SetupDiEnumDeviceInterfaces


SetupDiOpenDeviceInterfaceRegKey

SetupDiOpenDeviceInterfaceRegKey opens the registry subkey that is used by applications and drivers to store information specific to a device interface instance and returns a handle to the key.

HKEY
  SetupDiOpenDeviceInterfaceRegKey(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVICE_INTERFACE_DATA  DeviceInterfaceData,
    IN DWORD  Reserved,
    IN REGSAM  samDesired
    );

Parameters

DeviceInfoSet
Points to a device information set containing the interface and its underlying device.
DeviceInterfaceData
Points to a SP_DEVICE_INTERFACE_DATA structure that identifies the device interface, possibly returned by SetupDiCreateDeviceInterface or SetupDiEnumDeviceInterfaces.
Reserved
Reserved. Must be zero.
samDesired
Specifies the access to the registry key requested by the caller.

Return Value

SetupDiOpenDeviceInterfaceRegKey returns a handle to the opened registry key. If the function fails, it returns INVALID_HANDLE_VALUE. To get extended error information, call GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

Close the handle returned from by function by calling RegCloseKey.

See Also

SetupDiCreateDeviceInterface, SetupDiCreateDeviceInterfaceRegKey, SetupDiEnumDeviceInterfaces


SetupDiOpenDevRegKey

SetupDiOpenDevRegKey opens a registry storage key for device-specific configuration information and returns a handle to the key.

HKEY
  SetupDiOpenDevRegKey(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData,
    IN DWORD  Scope,
    IN DWORD  HwProfile,
    IN DWORD  KeyType,
    IN REGSAM  samDesired
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set containing information about the device instance whose registry configuration storage key is to be opened.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure indicating the device instance for which to open the registry key.
Scope
Specifies the scope of the registry key to open. The scope determines where the information is stored. The key opened can be global or hardware profile-specific. Can be one of the following values:
DICS_FLAG_GLOBAL
Open a key to store global configuration information. This information is not specific to a particular hardware profile. For NT-based operating systems this opens a key that is rooted at HKEY_LOCAL_MACHINE. The exact key opened depends on the value of the KeyType parameter.
DICS_FLAG_CONFIGSPECIFIC
Open a key to store hardware profile-specific configuration information. This key is rooted at one of the hardware-profile specific branches, instead of HKEY_LOCAL_MACHINE. The exact key opened depends on the value of the KeyType parameter.
HwProfile
Specifies the hardware profile to open a key for, if Scope is set to SPDICS_FLAG_CONFIGSPECIFIC. If HwProfile is 0, the key for the current hardware profile is opened. If Scope is SPDICS_FLAG_GLOBAL, this parameter is ignored.
KeyType
Specifies the type of registry storage key to open. Can be one of the following values:
DIREG_DEV
Open a hardware registry key for the device. This is the key for storage of driver-independent configuration information.

This key has the form HKLM\SYSTEM\CurrentControlSet\Enum\enumerator\deviceID\device-instance\Device Parameters. Only use this function to open this key. Do not open this registry path directly. This path is only provided here to aid debugging.

DIREG_DRV
Open a software, or driver, registry key for the device.

This key has the form HKLM\SYSTEM\CurrentControlSet\Control\Class\ClassGUID\InstanceID where classGUID is the GUID representing the device's class and InstanceID is a base-10, four-digit ordinal representing this device instance within the list of device instances for this class. Only use this function to open this key. Do not open this registry path directly. This path is only provided here to aid debugging.

For more information about a device's hardware and software keys, see Driver Information in the Registry.

samDesired
Specifies the access you require for this key.

Return Value

If the function is successful, it returns a handle to an opened registry key where private configuration data pertaining to this device instance can be stored/retrieved.

If the function fails, it returns INVALID_HANDLE_VALUE. To get extended error information, call GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

Close the handle returned from this function by calling RegCloseKey.

The specified device instance must be registered before calling this function. After creating the device instance with SetupDiCreateDeviceInfo, call SetupDiRegisterDeviceInfo to register it.

See Also

SetupDiCreateDeviceInfo, SetupDiCreateDevRegKey, SetupDiGetHwProfileList, SetupDiRegisterDeviceInfo


SetupDiRegisterCoDeviceInstallers

SetupDiRegisterCoDeviceInstallers registers the device-specific co-installers listed in the INF file for the specified device. This function is the default handler for DIF_REGISTER_COINSTALLERS.

WINSETUPAPI BOOL WINAPI
  SetupDiRegisterCoDeviceInstallers(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set containing a device information element for which co-installers are to be registered. The device information set must not contain any remote elements.
DeviceInfoData
Supplies the address of a SP_DEVINFO_DATA structure identifying a device for which co-installers are to be registered.

Return Value

SetupDiRegisterCoDeviceInstallers returns TRUE if the function succeeds. If the function returns FALSE, call GetLastError for extended error information.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

Co-installers should not call default DIF code handlers.

SetupDiRegisterCoDeviceInstallers reads the INF file for the device specified by DeviceInfoData and creates registry entries to register any device-specific co-installers listed in the INF. Co-installers are listed in an INF DDInstall.CoInstallers section. This function also copies the files for the co-installers, unless the DI_NOFILECOPY flag is set.

If there is no driver selected or the device has a legacy INF file, this function does not register any co-installers.

Registering a new device-specific co-installer invalidates the Device Installer's current list of co-installers. After a successful registration, the Device Installer updates its list of co-installers.

This function only registers device-specific co-installers, not class co-installers.

For further information on writing and registering device-specific co-installers, see Writing a Co-installer.

The device information set specified by DeviceInfoSet must only contain elements on the local machine.

See Also

DIF_REGISTER_COINSTALLERS, SetupDiCallClassInstaller


SetupDiRegisterDeviceInfo

SetupDiRegisterDeviceInfo registers a newly created device instance with the Plug and Play Manager. This function is the default handler for the DIF_REGISTERDEVICE request and should only be called for nonPnP devices.

WINSETUPAPI BOOL WINAPI
  SetupDiRegisterDeviceInfo(
    IN HDEVINFO  DeviceInfoSet,
    IN OUT PSP_DEVINFO_DATA  DeviceInfoData,
    IN DWORD  Flags,
    IN PSP_DETSIG_CMPPROC  CompareProc,  OPTIONAL
    IN PVOID  CompareContext,  OPTIONAL
    OUT PSP_DEVINFO_DATA  DupDeviceInfoData  OPTIONAL
    );

Parameters

DeviceInfoSet
Supplies a handle to a device information set. The device information set must not contain any remote elements.
DeviceInfoData
Supplies a pointer to a SP_DEVINFO_DATA structure that identifies the device in the DeviceInfoSet. This is an IN OUT parameter because the DevInst field of the structure can be updated with a new handle value upon return.
Flags
Controls how the device is registered. Can be the following value:
SPRDI_FIND_DUPS
Search for a previously-existing device instance corresponding to the device information pointed to by DeviceInfoData. If this flag is not specified, the device instance is registered regardless of whether or not a device instance already exists for it.

If the caller supplies a CompareProc they must also set this flag.

CompareProc
Supplies a comparison callback function to use in duplicate detection. If specified, the function is called for each device instance that is of the same class as the device instance being registered. The prototype of the callback function is as follows:
typedef  DWORD (CALLBACK* PSP_DETSIG_CMPPROC) (
    IN HDEVINFO          DeviceInfoSet,
    IN PSP_DEVINFO_DATA  NewDeviceData,
    IN PSP_DEVINFO_DATA  ExistingDeviceData,
    IN PVOID             CompareContext       OPTIONAL
    );

The compare function must return ERROR_DUPLICATE_FOUND if it finds that the two devices are duplicates. Otherwise, it should return NO_ERROR. If some other error is encountered, the callback function should return the appropriate ERROR_* code to indicate the failure.

If CompareProc is not specified and duplication detection is requested, a default comparison behavior is used. The default is to compare the new device's detect signature with the detect signature of all other devices in the class. The detect signature is contained in the class-specific resource descriptor of the device's boot log configuration.

CompareContext
Supplies a pointer to a caller-supplied context buffer that is passed into the callback function. This parameter is ignored if CompareProc is not specified.
DupDeviceInfoData
Optionally supplies a pointer to a SP_DEVINFO_DATA structure to receive information about a duplicate device instance, if any, discovered as a result of attempting to register this device. The caller must set cbSize to sizeof(SP_DEVINFO_DATA). This will be filled in if the function returns FALSE, and GetLastError returns ERROR_DUPLICATE_FOUND. This device information element is added as a member of the specified DeviceInfoSet, if not already a member. If DupDeviceInfoData is not specified, the duplicate is not added to the device information set.

If you call this function when handling a DIF_REGISTERDEVICE request, the DupDeviceInfoData parameter must be NULL.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

Co-installers should not call default DIF code handlers.

Do not call this function for PnP devices. PnP devices are registered by the OS.

After registering a device information element, the caller should refresh any stored copies of the DevInst handle associated with this device. This is necessary because the handle value might have changed during registration. The caller need not retrieve the SP_DEVINFO_DATA structure again because the DevInst field of the structure is updated to reflect the current value of the handle.

The DeviceInfoSet must only contain elements on the local machine.

See Also

DIF_REGISTERDEVICE, SP_DEVINFO_DATA, SP_DEVINSTALL_PARAMS


SetupDiRemoveDevice

SetupDiRemoveDevice is the default handler for the DIF_REMOVE installation request. It removes a device from the system.

WINSETUPAPI BOOL WINAPI
  SetupDiRemoveDevice(
    IN HDEVINFO  DeviceInfoSet,
    IN OUT PSP_DEVINFO_DATA  DeviceInfoData
    );

Parameters

DeviceInfoSet
Supplies a handle to a device information set for the local machine.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that identifies the device in the DeviceInfoSet. This is an IN OUT parameter because the DevInst field of the structure can be updated with a new handle value upon return. If this is a global removal or the last hardware profile-specific removal, all traces of the device instance are deleted from the registry and the DeviceInfoSet handle is NULL.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved by a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

Co-installers should not call default DIF code handlers.

This function removes the device from the system. It deletes the device's hardware and software registry keys and any hardware-profile-specific registry keys (configuration-specific registry keys). This function dynamically stops the device if its DevInst is active and this is a global removal or the last configuration-specific removal. If the device cannot be dynamically stopped, flags are set in the Install Parameter block of the device information set that eventually cause the user to be prompted to shut down the system.

Device removal is either global to all hardware profiles or specific to one hardware profile as specified by the ClassInstallParams field of the structure. Configuration-specific removal is only appropriate for root-enumerated devices and should only be requested by system code.

The DeviceInfoSet must only contain elements on the local machine.

See Also

SP_DEVINFO_DATA, SP_REMOVEDEVICE_PARAMS


SetupDiRemoveDeviceInterface

SetupDiRemoveDeviceInterface removes a registered device interface from the system.

WINSETUPAPI BOOL WINAPI
  SetupDiRemoveDeviceInterface(
    IN HDEVINFO  DeviceInfoSet,
    IN OUT PSP_DEVICE_INTERFACE_DATA  DeviceInterfaceData
    );

Parameters

DeviceInfoSet
Points to the device information set containing the interface and its underlying device. This handle is typically returned by SetupDiGetClassDevs. The device information set must not contain remote elements.
DeviceInterfaceData
Points to a SP_DEVICE_INTERFACE_DATA structure that identifies the interface being removed. This information is typically returned by SetupDiEnumDeviceInterfaces.

After the interface is removed, this function sets the SPINT_REMOVED flag in DeviceInterfaceData.Flags. It also clears the SPINT_ACTIVE flag, but note that this flag should have already been cleared when this function was called.

Return Value

SetupDiRemoveDeviceInterface returns TRUE if the function completed without error. If the function completed with an erorr, it returns FALSE and the error code for the failure can be retrieved by calling GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

SetupDiRemoveDeviceInterface removes the specified device interface from the system, including deleting the associated registry key.

Call SetupDiDeleteDeviceInterfaceData to delete the interface from a device information list.

A device interface must be disabled to be removed. If the interface is enabled, this function fails and GetLastError returns ERROR_DEVICE_INTERFACE_ACTIVE. Disable an interface using whatever interface-specific mechanism is provided (for example, an IOCTL). If the caller has no way of disabling an interface and the interface must be removed, the caller must stop the underlying device using SetupDiChangeState. Stopping the device disables all the interfaces exposed by the device.

The DeviceInfoSet must only contain elements on the local machine.

See Also

SetupDiChangeState, SetupDiCreateDeviceInterface, SetupDiDeleteDeviceInterfaceData, SetupDiEnumDeviceInterfaces, SetupDiGetClassDevs


SetupDiSelectBestCompatDrv

SetupDiSelectBestCompatDrv is the default handler for the DIF_SELECTBESTCOMPATDRV installation request.

WINSETUPAPI BOOL WINAPI
  SetupDiSelectBestCompatDrv(
    IN HDEVINFO DeviceInfoSet,
    IN OUT PSP_DEVINFO_DATA DeviceInfoData
    );

Parameters

DeviceInfoSet
Supplies a handle to a device information set. The device information set must not contain any remote elements.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that indicates the member of the device information set for which a driver is to be selected.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved by a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

Co-installers should not call default DIF code handlers.

SetupDiSelectBestCompatDrv selects the best driver for the device from the device information element's compatible driver list. To get the selected driver for a device, call SetupDiGetSelectedDriver.

The best driver has the lowest "rank." A "rank zero" match is the best match. To choose between several drivers in the driver list that have the same best-rank match, this function chooses the driver with the most-recent date. A driver's date is set with an INF DriverVer directive in the driver's INF file. This function only considers the DriverVer date if the INF is digitally signed.

This function uses information on the local machine when selecting the best driver.

See Also

DIF_SELECTBESTCOMPATDRV, SP_DEVINFO_DATA


SetupDiSelectDevice

SetupDiSelectDevice is the default handler for the DIF_SELECTDEVICE request.

WINSETUPAPI BOOL WINAPI
  SetupDiSelectDevice(
    IN HDEVINFO DeviceInfoSet,
    IN OUT PSP_DEVINFO_DATA DeviceInfoData  OPTIONAL
    );

Parameters

DeviceInfoSet
Supplies a handle to a device information set for the local machine.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that indicates the member of the device information set for which a driver is to be selected. If this parameter is not specified, a driver is selected for the global class driver list associated with the device information set.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved by a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

Co-installers should not call default DIF code handlers.

The function handles the user interface that allows the user to select a driver for the device specified. By setting the Flags field of the SP_DEVINSTALL_PARAMS structure, the caller can specify special handling of the user interface such as to allow users to select a driver from an OEM installation disk.

The DeviceInfoSet must only contain elements on the local machine.

See Also

SetupDiCallClassInstaller, SP_DEVINSTALL_PARAMS


SetupDiSelectOEMDrv

SetupDiSelectOEMDrv selects a driver for a device using an OEM path supplied by the user.

WINSETUPAPI BOOL WINAPI
  SetupDiSelectOEMDrv(
    IN HWND  hwndParent,  OPTIONAL
    IN HDEVINFO  DeviceInfoSet,
    IN OUT PSP_DEVINFO_DATA  DeviceInfoData  OPTIONAL
    );

Parameters

hwndParent
Supplies a window handle that will be the parent of any dialogs created during the processing of this function. This parameter can be used to override the hwndParent field in the install parameters block of the specified device information set or element. The device information set must not contain remote elements.
DeviceInfoSet
Supplies a handle to the device information set that contains the device being installed.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure for the device being installed. If this parameter is not specified, the device being installed is associated with the global class driver list of the device information set.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved by a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

This function asks the user for the OEM path and then calls the class installer to select a driver from the OEM path.

The DeviceInfoSet must only contain elements on the local machine.

See Also

SetupDiAskForOEMDisk


SetupDiSetClassInstallParams

SetupDiSetClassInstallParams sets or clears class install parameters for a device information set or a particular device information element.

WINSETUPAPI BOOL WINAPI
  SetupDiSetClassInstallParams(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData,  OPTIONAL
    IN PSP_CLASSINSTALL_HEADER  ClassInstallParams,  OPTIONAL
    IN DWORD  ClassInstallParamsSize
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set that contains the class install parameters to set.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that contains the class install parameters to set. If DeviceInfoData is not specified, the class install parameters to set are associated with the device information set.
ClassInstallParams
Supplies a pointer to a buffer that contains the new class install parameters to use. The SP_CLASSINSTALL_HEADER structure at the beginning of this buffer must have its cbSize field set to sizeof(SP_CLASSINSTALL_HEADER) and the InstallFunction field must be set to the DI_FUNCTION code that reflects the type of parameters contained in the rest of the buffer.

If ClassInstallParams is not specified, the current class install parameters, if any, are cleared for the specified device information set or element.

ClassInstallParamsSize
Supplies the size, in bytes, of the ClassInstallParams buffer. If the buffer is not supplied (that is, the class install parameters are being cleared), ClassInstallParamsSize must be 0.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

All parameters are validated before any changes are made. Therefore, a return value of FALSE indicates that no parameters were modified.

A consequence of setting class install parameters is that the DI_CLASSINSTALLPARAMS flag is set. If the caller wants to set the parameters, but disable their use, this flag must be cleared by a call to SetupDiSetDeviceInstallParams.

If the class install parameters are cleared, the DI_CLASSINSTALLPARAMS flag is reset.

See Also

SetupDiGetClassInstallParams, SetupDiSetDeviceInstallParams


SetupDiSetClassRegistryProperty

(Windows XP and later)

SetupDiSetClassRegistryProperty sets a specified device class property in the registry.

WINSETUPAPI BOOL WINAPI
  SetupDiSetClassRegistryProperty(
    IN  LPGUID ClassGuid,
    IN  DWORD Property,
    IN CONST BYTE* PropertyBuffer,  OPTIONAL
    IN  DWORD PropertyBufferSize,
    IN  PCTSTR MachineName,         OPTIONAL
    IN  PVOID Reserved
    );

Parameters

ClassGuid
Caller-supplied pointer to a GUID representing the device class for which a property is to be set.
Property
Caller-supplied value identifying the property to be set. This must be one of the following values:
SPCRP_SECURITY
The caller supplies the device's security descriptor as a SECURITY_DESCRIPTOR structure (described in Platform SDK documentation).
SPCRP_SECURITY_SDS
The caller supplies the device's security descriptor, in text form.
SPCRP_DEVTYPE
The caller supplies the device type for the class. For more information, see Specifying Device Types.
SPCRP_EXCLUSIVE
The caller supplies a DWORD value indicating whether users can obtain exclusive access to devices for this class. The supplied value is 1 if exclusive access is allowed, or zero otherwise.
SPCRP_CHARACTERISTICS
The caller supplies flags indicating device characteristics for the class. For a list of characteristics flags, see the DeviceCharacteristics parameter to IoCreateDevice.
PropertyBuffer
Caller-supplied pointer to a buffer that supplies the specified property.
PropertyBufferSize
Caller-supplied size of the buffer pointed to by PropertyBuffer.
MachineName
Caller-supplied name of a remote machine on which to set the specified device class property. If NULL, the property is set on the local machine.
Reserved
Reserved, must be NULL.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

This function is supported in Windows XP and later operating system versions.

To determine the data type for a device class property, call SetupDiGetClassRegistryProperty.

See Also

SetupDiGetClassRegistryProperty, SetupDiGetDeviceRegistryProperty, SetupDiSetDeviceRegistryProperty


SetupDiSetDeviceInstallParams

SetupDiSetDeviceInstallParams sets device install parameters for a device information set or a particular device information element.

WINSETUPAPI BOOL WINAPI
  SetupDiSetDeviceInstallParams(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData,  OPTIONAL
    IN PSP_DEVINSTALL_PARAMS  DeviceInstallParams
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set that contains the device install parameters to set.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that contains device install parameters to set. If this parameter is not specified, the install parameters set are associated with the device information set for the global class driver list.
DeviceInstallParams
Supplies a pointer to an SP_DEVINSTALL_PARAMS structure that contains the new values of the parameters. The cbSize field of this structure must be set to the size, in bytes, of the structure before calling this function.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

All parameters are validated before any changes are made. Therefore, a return value of FALSE indicates that no parameters were modified.

See Also

SetupDiGetDeviceInstallParams


SetupDiSetDeviceInterfaceDefault

SetupDiSetDeviceInterfaceDefault sets a specified device interface as the default interface for a device class.

WINSETUPAPI BOOL WINAPI
  SetupDiSetDeviceInterfaceDefault(
    IN HDEVINFO DeviceInfoSet,
    IN OUT PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
    IN DWORD Flags,
    IN PVOID Reserved
    );

Parameters

DeviceInfoSet
Caller-supplied handle to the device information set containing the device interface to use as the default. This handle is typically obtained by calling SetupDiGetClassDevs.
DeviceInterfaceData
Caller-supplied pointer to an SP_DEVICE_INTERFACE_DATA structure that identifies the device interface that will become the default for the specified device information set. This pointer is typically obtained by calling SetupDiEnumDeviceInterfaces.
Flags
Not used, must be zero.
Reserved
Reserved for future use, must be NULL.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

If the function successfully sets the specified device interface as the default for the device class, it updates the Flags member of the supplied SP_DEVICE_INTERFACE_DATA structure.


SetupDiSetDeviceRegistryProperty

SetupDiSetDeviceRegistryProperty sets the specified Plug and Play device property.

WINSETUPAPI BOOL WINAPI
  SetupDiSetDeviceRegistryProperty(
    IN HDEVINFO  DeviceInfoSet,
    IN OUT PSP_DEVINFO_DATA  DeviceInfoData,
    IN DWORD  Property,
    IN CONST BYTE  *PropertyBuffer,
    IN DWORD  PropertyBufferSize
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set containing information about the device instance whose Plug and Play property is to be modified.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure indicating the device instance whose Plug and Play property is to be modified. If the ClassGUID property is being set, this structure is updated upon return to reflect the device's new class.
Property
Supplies one of the following ordinal values, which identifies the property to be set. For descriptions of these values, see SetupDiGetDeviceRegistryProperty.

SPDRP_CHARACTERISTICS
SPDRP_COMPATIBLEIDS
SPDRP_CONFIGFLAGS
SPDRP_DEVTYPE
SPDRP_EXCLUSIVE
SPDRP_FRIENDLYNAME
SPDRP_HARDWAREID
SPDRP_LOCATION_INFORMATION
SPDRP_LOWERFILTERS
SPDRP_REMOVAL_POLICY_OVERRIDE (Windows XP and later)
SPDRP_SECURITY
SPDRP_SECURITY_SDS
SPDRP_SERVICE
SPDRP_UI_NUMBER_DESC_FORMAT
SPDRP_UPPERFILTERS

Do not set the following values:

SPDRP_ADDRESS
SPDRP_BUSNUMBER
SPDRP_BUSTYPEGUID
SPDRP_CAPABILITIES
SPDRP_CLASS
SPDRP_CLASSGUID
SPDRP_DEVICE_POWER_DATA
SPDRP_DEVICEDESC
SPDRP_DRIVER
SPDRP_ENUMERATOR_NAME
SPDRP_LEGACYBUSTYPE
SPDRP_MFG
SPDRP_PHYSICAL_DEVICE_OBJECT_NAME
SPDRP_REMOVAL_POLICY
SPDRP_REMOVAL_POLICY_HW_DEFAULT
SPDRP_UI_NUMBER

PropertyBuffer
The address of a buffer that contains the new data for the property. If the property is being cleared, then this pointer should be NULL and PropertyBufferSize must be zero.
PropertyBufferSize
Supplies the size, in bytes, of PropertyBuffer. If PropertyBuffer is NULL, then this field must be zero.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

The class name property cannot be set because it is based on the corresponding class GUID and is automatically updated when that property is changed. When the ClassGUID property changes, SetupDiSetDeviceRegistryProperty automatically cleans up any software keys associated with the device.

See Also

SetupDiGetClassRegistryProperty
SetupDiSetClassRegistryProperty
SetupDiGetDeviceRegistryProperty


SetupDiSetDriverInstallParams

SetupDiSetDriverInstallParams establishes install parameters for the specified driver.

WINSETUPAPI BOOL WINAPI
  SetupDiSetDriverInstallParams(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData,  OPTIONAL
    IN PSP_DRVINFO_DATA  DriverInfoData,
    IN PSP_DRVINSTALL_PARAMS  DriverInstallParams
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set containing a driver information structure for which to set installation parameters.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that contains a driver information structure for which to set installation parameters. If this parameter is not specified, the driver referenced is a member of the global class driver list owned by the device information set.
DriverInfoData
Supplies a pointer to an SP_DRVINFO_DATA structure that specifies the driver for which install parameters are to be set.
DriverInstallParams
Supplies a pointer to an SP_DRVINSTALL_PARAMS structure that specifies what the new driver install parameters should be. The cbSize field of this structure must be set to the size, in bytes, of the structure before this function is called.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved by a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

See Also

SetupDiGetDriverInstallParams


SetupDiSetSelectedDevice

SetupDiSetSelectedDevice sets the specified device information element to be the currently-selected member of a device information set. This function is typically used by an installation wizard.

WINSETUPAPI BOOL WINAPI
  SetupDiSetSelectedDevice(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set for which the selected device should be set.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that specifies the device information element to select.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

See Also

SetupDiGetSelectedDevice


SetupDiSetSelectedDriver

SetupDiSetSelectedDriver sets the specified member of a driver list as the currently-selected driver. It can also be used to reset the driver list so that there is no currently-selected driver.

WINSETUPAPI BOOL WINAPI
  SetupDiSetSelectedDriver(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData,  OPTIONAL
    IN OUT PSP_DRVINFO_DATA  DriverInfoData  OPTIONAL
    );

Parameters

DeviceInfoSet
Supplies a handle to the device information set containing information about the device instance for which to set a selected driver.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that contains the device information element for which to select a driver. If this parameter is NULL, a class driver for the global class driver list is selected.
DriverInfoData
If this parameter is specified, it supplies a pointer to a driver information structure that indicates the driver to be selected. If this parameter is NULL, the driver list is reset (that is, no driver is selected).

If the Reserved field of the SP_DRVINFO_DATA structure is 0, the caller is requesting a search for a driver node with the specified parameters (DriverType, Description, and ProviderName). If a match is found, that driver node is selected. The Reserved field is updated on output to reflect the actual driver node where the match was found. If a match is not found, the function fails and a call to GetLastError returns ERROR_INVALID_PARAMETER.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

See Also

SetupDiGetSelectedDriver


SetupDiUnremoveDevice

SetupDiUnremoveDevice is the default handler for the DIF_UNREMOVE installation request. This function restores a device to a hardware profile and starts the device, if possible.

WINSETUPAPI BOOL WINAPI
  SetupDiUnremoveDevice(
    IN HDEVINFO  DeviceInfoSet,
    IN OUT PSP_DEVINFO_DATA  DeviceInfoData
    );

Parameters

DeviceInfoSet
Supplies a handle to a device information set for the local machine.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that identifies the device in the DeviceInfoSet. This is an IN OUT parameter because the DevInst field of the structure can be updated with a new handle value upon return.

Return Value

The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved by a call to GetLastError.

Headers

Declared in setupapi.h. Include setupapi.h.

Comments

Co-installers should not call default DIF code handlers.

SetupDiUnremoveDevice restores a device to a hardware profile. This function starts the device, if possible, or it sets a flag in the device install parameters that eventually causes the user to be prompted to shut down the system.

The device being restored must have class install parameters for DIF_UNREMOVE or the function fails and GetLastError returns ERROR_NO_CLASSINSTALL_PARAMS.

The DeviceInfoSet must only contain elements on the local machine.

See Also

DIF_UNREMOVE, SetupDiRemoveDevice, SP_DEVINFO_DATA


UpdateDriverForPlugAndPlayDevices

Given an INF and a hardware ID, UpdateDriverForPlugAndPlayDevices installs updated drivers for devices that match the hardware ID.

BOOL WINAPI
  UpdateDriverForPlugAndPlayDevices(
    HWND  hwndParent,
    LPCTSTR  HardwareId,
    LPCTSTR  FullInfPath,
    DWORD  InstallFlags,
    PBOOL  bRebootRequired OPTIONAL
    );

Parameters

hwndParent
A caller-supplied handle to the top-level window to use for any UI related to installing devices.
HardwareId
A caller-supplied Hardware ID to match against existing devices on the machine.
FullInfPath
A caller-supplied full path to an INF and any associated driver files. The files should be on the distribution media or in a vendor-created directory, not in a system location such as %windir%\inf. The function copies driver files to the appropriate system locations if the installation is successful.
InstallFlags
A caller-supplied value created by ORing zero or more for the following bit flags:
INSTALLFLAG_FORCE
If this flag is set and the function finds a device that matches the HardwareId value, the function installs new drivers for the device whether or not better drivers already exist on the machine. Use this flag only with extreme caution. Setting this flag can cause an older driver to be installed over a newer driver, if a user runs the vendor's application after newer drivers are available.
INSTALLFLAG_READONLY
If this flag is set, the function will not copy, rename, or delete any installation files. Use of this flag should be limited to environments in which file access is restricted or impossible, such as an "embedded" operating system.
INSTALLFLAG_NONINTERACTIVE
If this flag is set, the function will return FALSE when any attempt to display UI is detected. Set this flag only if the function will be called from a component (such as a service) that cannot display UI. Note that if this flag is set and a UI display is attempted, the device can be left in an indeterminate state.

The InstallFlags parameter is typically zero.

bRebootRequired
Optional address of a Boolean value that indicates whether a reboot is required and who should prompt for it.

If bRebootRequired is NULL, this function prompts for a reboot after installing drivers, if necessary. If bRebootRequired is a valid pointer, the function supplies a BOOLEAN value that is TRUE if the system should be rebooted, and it is then the caller's responsibility to prompt for a reboot. For more information, see Comments.

Return Value

The function returns TRUE if a device was upgraded to the specified driver.

Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError. Possible error values returned by GetLastError are included in the following table.

Error Value | Description
ERROR_FILE_NOT_FOUND | The path specified for FullInfPath does not exist.
ERROR_IN_WOW64 | The calling application is a 32-bit application attempting to execute in a 64-bit environment, which is not allowed.
ERROR_INVALID_FLAGS | The value specified for InstallFlags is invalid..
ERROR_NO_SUCH_DEVINST | The value specified for HardwareId does not match any device on the system.
NO_ERROR | The routine found a match for the HardwareId value, but the specified driver was not better than the current driver and the caller did not specify the INSTALLFLAG_FORCE flag.

Headers

Declared in newdev.h. Include newdev.h. Link to newdev.lib.

Comments

UpdateDriverForPlugAndPlayDevices scans the devices on the system and attempts to install the drivers specified by FullInfPath for any devices that match the given HardwareId value. The default behavior is to only install the specified drivers if they are better then the currently installed drivers and the specified drivers are also better than any drivers in %windir%\inf. For more information, see How Setup Selects Drivers.

UpdateDriverForPlugAndPlayDevices attempts to install the specified drivers on all hardware that matches the specified HardwareId value.

Generally, setup applications should supply NULL for bRebootRequired, so the system will initiate a reboot if necessary. An application should specify a pointer value only in the following cases:

  • The application must call UpdateDriverForPlugAndPlayDevices several times to complete an installation.
  • The application must perform other operations before the reboot (if required) occurs.
  • The application is a class installer, which should set DI_NEEDREBOOT in SP_DEVINSTALL_PARAMS if a reboot is needed.

If the application must call UpdateDriverForPlugAndPlayDevices several times, it should save any TRUE reboot status value received, then prompt for a reboot after the final call has returned.

If the function returns ERROR_IN_WOW64 in a 32-bit application, the application is executing on a 64-bit system, which is not allowed. For more information, see Installing Devices on 64-bit Systems.


Device Installation Structures

This section describes the structures that are parameters to SetupDi Xxx functions, device installation function requests (DIF requests), and other device installation operations.


SP_ADDPROPERTYPAGE_DATA

An installer uses an SP_ADDPROPERTYPAGE_DATA structure to supply custom property pages for a device when handling a DIF_ADDPROPERTYPAGE_ADVANCED request.

typedef struct _SP_ADDPROPERTYPAGE_DATA {
  SP_CLASSINSTALL_HEADER  ClassInstallHeader;
  DWORD  Flags;
  HPROPSHEETPAGE  DynamicPages[MAX_INSTALLWIZARD_DYNAPAGES];
  DWORD  NumDynamicPages;
  HWND  hwndWizardDlg;
} SP_ADDPROPERTYPAGE_DATA, *PSP_ADDPROPERTYPAGE_DATA;

Members

ClassInstallHeader
An install request header that contains the header size and the DIF code for the request.
Flags
Reserved. Must be zero.
DynamicPages
An array of property sheet page handles. An installer can add the handles of custom property pages to this array.
NumDynamicPages
The number of pages added to the DynamicPages array.

Because the array index is zero-based, this value is also the index to the next free entry in the array. For example, if there are three pages in the array, DynamicPages[3] is the next entry for an installer to use.

hwndWizardDlg
The window handle of the Device Manager top-level window.

Comments

See the Platform SDK for documentation on the PROPSHEETPAGE structure and for more information on property pages.

See Also

DIF_ADDPROPERTYPAGE_ADVANCED


SP_CLASSIMAGELIST_DATA

An SP_CLASSIMAGELIST_DATA structure describes a class image list.

typedef struct _SP_CLASSIMAGE_DATA {
  DWORD  cbSize;
  HIMAGELIST  ImageList;
  DWORD  Reserved;
} SP_CLASSIMAGE_DATA, *PSP_CLASSIMAGE_DATA;

Members

cbSize
The size, in bytes, of the SP_CLASSIMAGE_DATA structure.
ImageList
A handle to the class image list.

See Also

SetupDiDestroyClassImageList, SetupDiGetClassImageIndex, SetupDiGetClassImageList


SP_CLASSINSTALL_HEADER

An SP_CLASSINSTALL_HEADER is the first member of any class install parameters structure. It contains the device installation request code that defines the format of the rest of the install parameters structure.

typedef struct _SP_CLASSINSTALL_HEADER {
  DWORD  cbSize;
  DI_FUNCTION  InstallFunction;
} SP_CLASSINSTALL_HEADER, *PSP_CLASSINSTALL_HEADER;

Members

cbSize
The size, in bytes, of the SP_CLASSINSTALL_HEADER structure.
InstallFunction
The device installation request (DIF code) for the class install parameters structure.

DIF codes have the format DIF_XXX and are defined in setupapi.h. See Device Installation Function Codes for a complete description of DIF codes.

Comments

When a component allocates a class install parameters structure, it typically initializes the header fields of the structure. Such a component sets the InstallFunction member to the DIF code for the installation request and sets cbSize to the size of the SP_CLASSINSTALL_HEADER structure. For example:

SP_REMOVEDEVICE_PARAMS RemoveDeviceParams;
RemoveDeviceParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
RemoveDeviceParams.ClassInstallHeader.InstallFunction = DIF_REMOVE;

A component must set the InstallFunction member before passing a class install parameters structure to SetupDiSetClassInstallParams.

However, a component need not set this field when passing class install parameters to SetupDiGetClassInstallParams. This function sets the InstallFunction member in the structure it passes back to the caller. It sets InstallFunction to the DIF_XXX code for the currently active device installation request.

See Also

SetupDiCallClassInstaller, SetupDiGetClassInstallParams, SetupDiSetClassInstallParams, SP_DETECTDEVICE_PARAMS, SP_MOVEDEV_PARAMS, SP_NEWDEVICEWIZARD_DATA, SP_POWERMESSAGEWAKE_PARAMS, SP_PROPCHANGE_PARAMS, SP_REMOVEDEVICE_PARAMS, SP_SELECTDEVICE_PARAMS, SP_TROUBLESHOOTER_PARAMS, SP_UNREMOVEDEVICE_PARAMS


SP_DETECTDEVICE_PARAMS

An SP_DETECTDEVICE_PARAMS structure corresponds to a DIF_DETECT installation request.

typedef struct _SP_DETECTDEVICE_PARAMS {
  SP_CLASSINSTALL_HEADER  ClassInstallHeader;
  PDETECT_PROGRESS_NOTIFY  DetectProgressNotify;
  PVOID  ProgressNotifyParam;
} SP_DETECTDEVICE_PARAMS, *PSP_DETECTDEVICE_PARAMS;

Members

ClassInstallHeader
An install request header that contains the size of the header and the DIF code for the request. See SP_CLASSINSTALL_HEADER.
DetectProgressNotify
A callback routine that displays a progress bar for the device detection operation. The callback routine is supplied by the Setup component that sends the DIF_DETECT request. The callback has the following prototype:
typedef BOOL (CALLBACK* PDETECT_PROGRESS_NOTIFY)(
    IN PVOID ProgressNotifyParam,
    IN DWORD DetectComplete
    );

ProgressNotifyParam is an opaque "handle" that identifies the detection operation. This value is supplied by the Setup component that sent the DIF_DETECT request.

DetectComplete is a value between 0 and 100 that indicates the percent completion. The class installer increments this value at various stages of its detection activities, to notify the user of its progress.

ProgressNotifyParam
The opaque ProgressNotifyParam "handle" that the class installer passes to the progress callback routine.

See Also

DIF_DETECT, SetupDiCallClassInstaller, SP_CLASSINSTALL_HEADER


SP_DEVICE_INTERFACE_DATA

An SP_DEVICE_INTERFACE_DATA structure defines a device interface in a device information set.

typedef struct _SP_DEVICE_INTERFACE_DATA {
  DWORD  cbSize;
  GUID  InterfaceClassGuid;
  DWORD  Flags;
  ULONG_PTR  Reserved;
} SP_DEVICE_INTERFACE_DATA, *PSP_DEVICE_INTERFACE_DATA;

Members

cbSize
The size, in bytes, of the SP_DEVICE_INTERFACE_DATA structure.
InterfaceClassGuid
The GUID for the class to which the device interface belongs.
Flags
Can be one or more of the following:
SPINT_ACTIVE
The interface is active (enabled).
SPINT_DEFAULT
The interface is the default interface for the device class.
SPINT_REMOVED
The interface is removed.
Reserved
Reserved. Do not use.

See Also

SetupDiCreateDeviceInterface, SetupDiEnumDeviceInterfaces, SetupDiGetDeviceInterfaceAlias, SetupDiOpenDeviceInterface, SetupDiSetDeviceInterfaceDefault, SP_DEVICE_INTERFACE_DETAIL_DATA


SP_DEVICE_INTERFACE_DETAIL_DATA

An SP_DEVICE_INTERFACE_DETAIL_DATA structure contains the path for a device interface.

typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA {
  DWORD  cbSize;
  TCHAR  DevicePath[ANYSIZE_ARRAY];
} SP_DEVICE_INTERFACE_DETAIL_DATA, *PSP_DEVICE_INTERFACE_DETAIL_DATA;

Members

cbSize
The size, in bytes, of the fixed portion of the SP_DEVICE_INTERFACE_DETAIL_DATA structure.
DevicePath
A NULL-terminated string that contains the device interface path. This path can be passed to Win32® functions such as CreateFile.

See Also

SetupDiGetDeviceInterfaceDetail


SP_DEVINFO_DATA

An SP_DEVINFO_DATA structure defines a device instance that is a member of a device information set.

typedef struct _SP_DEVINFO_DATA {
  DWORD  cbSize;
  GUID  ClassGuid;
  DWORD  DevInst;
  ULONG_PTR  Reserved;
} SP_DEVINFO_DATA, *PSP_DEVINFO_DATA;

Members

cbSize
The size, in bytes, of the SP_DEVINFO_DATA structure.
ClassGuid
The GUID of the device's setup class.
DevInst
An opaque handle to the device instance (also known as a handle to the devnode).

Some functions, such as SetupDi Xxx functions, take the whole SP_DEVINFO_DATA structure as input to identify a device in a device information set. Other functions, such as CM_Xxx functions like Cm_Get_DevNode_Status, take this DevInst handle as input.

Comments

An SP_DEVINFO_DATA structure identifies a device in a device information set. For example, when Setup sends a DIF_INSTALLDEVICE request to a class installer and co-installers, it includes a handle to a device information set and a pointer to an SP_DEVINFO_DATA that specifies the particular device. Besides DIF requests, this structure is also used in some SetupDi Xxx functions.

See Also

SP_DEVINFO_LIST_DETAIL_DATA


SP_DEVINFO_LIST_DETAIL_DATA

An SP_DEVINFO_LIST_DETAIL_DATA structure contains information about a device information set, such as its associated setup class GUID (if it has an associated setup class).

typedef struct _SP_DEVINFO_LIST_DETAIL_DATA {
  DWORD  cbSize;
  GUID  ClassGuid;
  HANDLE  RemoteMachineHandle;
  TCHAR  RemoteMachineName[SP_MAX_MACHINENAME_LENGTH];
} SP_DEVINFO_LIST_DETAIL_DATA, *PSP_DEVINFO_LIST_DETAIL_DATA;

Members

cbSize
The size, in bytes, of the SP_DEVINFO_LIST_DETAIL_DATA structure.
ClassGuid
The setup class GUID that is associated with the device information set or GUID_NULL if there is no associated setup class.
RemoteMachineHandle
A Configuration Manager machine handle for the remote machine, if the device information set is for a remote machine. If the device information set is for the local machine, this member is NULL.

This is typically the parameter that components use to access the remote machine. The RemoteMachineName contains a string, in case the component requires the name of the remote machine.

RemoteMachineName
A NULL-terminated string that contains the name of the remote machine. If the device information set is for the local machine, this member is an empty string.

See Also

SetupDiGetDeviceInfoListDetail


SP_DEVINSTALL_PARAMS

An SP_DEVINSTALL_PARAMS structure contains device installation parameters associated with a particular device information element or associated globally with a device information set.

typedef struct _SP_DEVINSTALL_PARAMS {
  DWORD  cbSize;
  DWORD  Flags;
  DWORD  FlagsEx;
  HWND  hwndParent;
  PSP_FILE_CALLBACK  InstallMsgHandler;
  PVOID  InstallMsgHandlerContext;
  HSPFILEQ  FileQueue;
  ULONG_PTR  ClassInstallReserved;
  DWORD  Reserved;
  TCHAR  DriverPath[MAX_PATH];
} SP_DEVINSTALL_PARAMS, *PSP_DEVINSTALL_PARAMS;

Members

cbSize
The size, in bytes, of the SP_DEVINSTALL_PARAMS structure.
Flags
Flags that control installation and user interface operations. Some flags can be set prior to sending the device installation request while others are set automatically during the processing of some requests. Flags can be a combination of the following values.

The flag values are listed in groups: writable by setup applications and installers, read only (only set by the OS), reserved, and obsolete. The first group lists flags that are writable:

DI_CLASSINSTALLPARAMS
Set to use the Class Install parameters. SetupDiSetClassInstallParams sets this flag when the caller specifies parameters and clears the flag when the caller specifies a NULL parameters pointer.
DI_COMPAT_FROM_CLASS
Set to force SetupDiBuildDriverInfoList to build a device's list of compatible drivers from its class driver list instead of the INF file.
DI_DRIVERPAGE_ADDED
Set by a class installer or co-installer if the installer supplies a page that replaces the system-supplied driver properties page. If this flag is set, the OS does not display the system-supplied driver page.
DI_DONOTCALLCONFIGMG
Set if the Configuration Manager should not be called to remove or reenumerate devices during the execution of certain device installation functions (for example, SetupDiInstallDevice).

If this flag is set, Setup applications, class installers, and co-installers must not call the following functions:

CM_Reenumerate_DevNode
CM_Reenumerate_DevNode_Ex
CM_Query_And_Remove_SubTree
CM_Query_And_Remove_SubTree_Ex
CM_Setup_DevNode
CM_Setup_DevNode_Ex
CM_Set_HW_Prof_Flags
CM_Set_HW_Prof_Flags_Ex
CM_Enable_DevNode
CM_Enable_DevNode_Ex
CM_Disable_DevNode
CM_Disable_DevNode_Ex

DI_ENUMSINGLEINF
Set if installers and other Setup components should only search the INF file specified by SP_DEVINSTALL_PARAMS.DriverPath. If this flag is set, DriverPath contains the path to a single INF file instead of a path to a directory.
DI_INF_IS_SORTED
Set to indicate that the Select Device page should list drivers in the order they appear in the INF file, instead of sorting them alphabetically.
DI_INSTALLDISABLED
Set if the device should be installed in a disabled state by default. To be recognized, this flag must be set before Setup calls the default handler for the DIF_INSTALLDEVICE request.
DI_NEEDREBOOT
For NT-based operating systems, this flag is set if the device requires that the machine be rebooted after device installation or a device state change. A class installer or co-installer can set this flag at any time during device installation, if the installer determines that a reboot is necessary.
DI_NEEDRESTART
The same as DI_NEEDREBOOT.
DI_NOBROWSE
Set to disable browsing when the user is selecting an OEM disk path. A setup application sets this flag to constrain a user to only installing from the installation media location.
DI_NODI_DEFAULTACTION
Set if SetupDiCallClassInstaller should not perform any default action if the class installer returns ERR_DI_DO_DEFAULT or there is not a class installer.
DI_NOFILECOPY
Set if Setup applications and components, such as SetupDiInstallDevice, should skip file copying.
DI_NOVCP
Set to disable creation of a new copy queue. Use the caller-supplied copy queue in SP_DEVINSTALL_PARAMS.FileQueue.
DI_NOWRITE_IDS
Set to prevent SetupDiInstallDevice from writing the INF-specified hardware and compatible IDs to the device properties for the devnode. This flag should only be set for root-enumerated devices.

This flag overrides the DI_FLAGSEX_ALWAYSWRITEIDS flag.

DI_PROPERTIES_CHANGE
Set by the Device Manager if a device's properties have been changed, requiring an update of the installer's user interface.
DI_QUIETINSTALL
Set if the device installer functions must be silent and use default choices wherever possible. Class installers and co-installers must not display any UI if this flag is set.
DI_RESOURCEPAGE_ADDED
Set by a class installer or co-installer if the installer supplies a page that replaces the system-supplied resource properties page. If this flag is set, the OS does not display the system-supplied resource page.
DI_SHOWOEM
Set to allow support for OEM disks. If this flag is set, the OS presents a "Have Disk" button on the Select Device page. This flag is set, by default, in system-supplied wizards.
DI_USECI_SELECTSTRINGS
Set if a class installer or co-installer supplied strings that should be used during SetupDiSelectDevice.

The following flags are read only (only set by the OS):

DI_DIDCLASS
Set if SetupDiBuildDriverInfoList has already built a list of the drivers for this class of device. If this list has already been built, it contains all the driver information and this flag is always set. SetupDiDestroyDriverInfoList clears this flag when it deletes a list of drivers for a class.

This flag is read only. Only the OS sets this flag.

DI_DIDCOMPAT
Set if SetupDiBuildDriverInfoList has already built a list of compatible drivers for this device. If this list has already been built, it contains all the driver information and this flag is always set. SetupDiDestroyDriverInfoList clears this flag when it deletes a compatible driver list.

This flag is only set in device installation parameters that are associated with a particular device information element, not in parameters for a device information set as a whole.

This flag is read only. Only the OS sets this flag.

DI_MULTMFGS
Set by SetupDiBuildDriverInfoList if a list of drivers for a device setup class contains drivers provided by multiple manufacturers.

This flag is read only. Only the OS sets this flag.

The following flags are reserved:

DI_AUTOASSIGNRES
DI_DISABLED
DI_FORCECOPY
DI_GENERALPAGE_ADDED
DI_OVERRIDE_INFFLAGS
DI_SHOWALL
DI_SHOWCLASS
DI_SHOWCOMPAT

The following flags are obsolete:

DI_NOSELECTICONS
DI_PROPS_NOCHANGEUSAGE
FlagsEx
Additional flags that provide control over installation and user interface operations. Some flags can be set prior to calling the device installer functions while others are set automatically during the processing of some functions. FlagsEx can be a combination of the following values.

The flag values are listed in groups: writable by setup applications and installers, read only (only set by the OS), reserved, and obsolete.

The first group lists flags that are writable:

DI_FLAGSEX_ALLOWEXCLUDEDDRVS
If set, include drivers that have been marked "Exclude From Select".

For example, if this flag is set, SetupDiSelectDevice displays drivers that have the Exclude From Select state and SetupDiBuildDriverInfoList includes Exclude From Select drivers in the requested driver list.

A driver is "Exclude From Select" if either it is marked ExcludeFromSelect in the INF file or it is a driver for a device whose whole setup class is marked NoInstallClass or NoUseClass in the class installer INF. Drivers for PnP devices are typically "Exclude From Select"; PnP devices should not be manually installed. To build a list of driver files for a PnP device a caller of SetupDiBuildDriverInfoList must set this flag.

DI_FLAGSEX_ALWAYSWRITEIDS
If set and the DI_NOWRITE_IDS flag is clear, always write hardware and compatible IDs to the device properties for the devnode. This flag should only be set for root-enumerated devices.
DI_FLAGSEX_APPENDDRIVERLIST
If set, SetupDiBuildDriverInfoList appends a new driver list to an existing list. This flag is relevant when searching multiple locations.
DI_FLAGSEX_DRIVERLIST_FROM_URL
If set, build the driver list from INF(s) retrieved from the URL specified in SP_DEVINSTALL_PARAMS.DriverPath. If the DriverPath is an empty string, use the Windows Update web site.

Currently, the OS does not support URLs. Use this flag to direct SetupDiBuildDriverInfoLIst to search the Windows Update web site.

Do not set this flag if DI_QUIETINSTALL is set.

DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS
If set, do not include old Internet drivers when building a driver list. This flag should be set any time you are building a list of potential drivers for a device. You can clear this flag if you are just getting a list of drivers currently installed for a device.
DI_FLAGSEX_FILTERCLASSES
If set, SetupDiBuildClassInfoList will check for class inclusion filters. This means that a device will not be included in the class list if its class is marked as NoInstallClass.
DI_FLAGSEX_FILTERSIMILARDRIVERS
(Windows XP and later.) If set, SetupDiBuildDriverInfoList includes "similar" drivers when building a class driver list. A "similar" driver is one for which one of the hardware IDs or compatible IDs in the INF file partially (or completely) matches one of the hardware IDs or compatible IDs of the hardware.
DI_FLAGSEX_INET_DRIVER
If set, the driver was obtained from the Internet. Setup will not use the device's INF to install future devices because Setup cannot guarantee that it can retrieve the driver files again from the Internet.
DI_FLAGSEX_INSTALLEDDRIVER
(Windows XP and later.) If set, SetupDiBuildDriverInfoList includes only the currently installed driver when creating a list of class drivers or device-compatible drivers.
DI_FLAGSEX_NO_DRVREG_MODIFY
Do not process the AddReg and DelReg entries for the device's hardware and software (driver) keys. That is, the AddReg and DelReg entries in the INF file DDInstall and DDInstall.HW sections.
DI_FLAGSEX_POWERPAGE_ADDED
If set, an installer added their own page for the power properties dialog. The OS will not display the system-supplied power properties page. This flag is only relevant if the device supports power management.
DI_FLAGSEX_PROPCHANGE_PENDING
If set, the user made changes to one or more device property sheets. The property-page provider typically sets this flag.

When the user closes the device property sheet, the Device Manager checks the DI_FLAGSEX_PROPCHANGE_PENDING flag. If it is set, the Device Manager clears this flag, sets the DI_PROPERTIES_CHANGE flag, and sends a DIF_PROPERTYCHANGE request to the installers to notify them that something has changed.

DI_FLAGSEX_SETFAILEDINSTALL
If set, the SetupDiInstallDevice function sets the FAILEDINSTALL flag in the ConfigFlags registry value for the device. If DI_FLAGSEX_SETFAILEDINSTALL is set, installation software must return NO_ERROR in response to DIF_INSTALLDEVICE.
DI_FLAGSEX_USECLASSFORCOMPAT
Filter INF files on the device's setup class when building a list of compatible drivers. If a device's setup class is known, setting this flag decreases the time required to build a list of compatible drivers when searching INFs that are not precompiled. This flag is ignored if DI_COMPAT_FROM_CLASS is set.

The following flags are read only; only the OS sets these flags:

DI_FLAGSEX_CI_FAILED
Set by the OS if a class installer failed to load or start. This flag is read only.
DI_FLAGSEX_DIDCOMPATINFO
Setup has built a list of driver nodes that are compatible with the device. This flag is read only.
DI_FLAGSEX_DIDINFOLIST
Setup has built a list of driver nodes that includes all the drivers listed in the INFs of the specfied setup class. If the specified setup class is NULL because the HDEVINFO set or device has no associated class, the list includes all driver nodes from all available INFs. This flag is read only.
DI_FLAGSEX_IN_SYSTEM_SETUP
If set, installation is occurring during initial system setup. This flag is read only.

The following flags are reserved:

DI_FLAGSEX_BACKUPONREPLACE
DI_FLAGSEX_DEVICECHANGE
DI_FLAGSEX_OLDINF_IN_CLASSLIST
DI_FLAGSEX_PREINSTALLBACKUP
DI_FLAGSEX_USEOLDINFSEARCH

The following flags are obsolete:

DI_FLAGSEX_AUTOSELECTRANK0
DI_FLAGSEX_NOUIONQUERYREMOVE
hwndParent
Window handle that will own the user interface dialogs related to this device.
InstallMsgHandler
Callback used to handle events during file copying. An installer can use a callback, for example, to perform special processing when committing a file queue.
InstallMsgHandlerContext
Private data used by the InstallMsgHandler callback.
FileQueue
A handle to a caller-supplied file queue where file operations should be queued but not committed.

If you associate a file queue with a device information set (SetupDiSetDeviceInstallParams), you must disassociate the queue from the device information set before you delete the device information set. If you fail to disassociate the file queue, Setup is not able to decrement its reference count on the device information set and is unable to free the memory.

This queue is only used if the DI_NOVCP flag is set, indicating that file operations should be enqueued but not committed.

ClassInstallReserved
A pointer for class-installer data. Co-installers must not use this field.
DriverPath
This path is used by the SetupDiBuildDriverInfoList function.

See Also

SetupDiBuildClassInfoList, SetupDiBuildDriverInfoList, SetupDiCallClassInstaller, SetupDiGetDeviceInstallParams, SetupDiInstallDevice, SetupDiSelectDevice, SetupDiSetDeviceInstallParams


SP_DRVINFO_DATA

An SP_DRVINFO_DATA structure contains information about a driver. This structure is a member of a driver information list that can be associated with a particular device instance or globally with a device information set.

typedef struct _SP_DRVINFO_DATA {
  DWORD  cbSize;
  DWORD  DriverType;
  ULONG_PTR  Reserved;
  TCHAR  Description[LINE_LEN];
  TCHAR  MfgName[LINE_LEN];
  TCHAR  ProviderName[LINE_LEN];
  FILETIME  DriverDate;
  DWORDLONG  DriverVersion;
} SP_DRVINFOR_DATA, *PSP_DRVINFO_DATA;

Members

cbSize
The size, in bytes, of the SP_DRVINFO_DATA structure.
DriverType
The type of driver represented by this structure. Must be one of the following values:
SPDIT_CLASSDRIVER
This structure represents a class driver.
SPDIT_COMPATDRIVER
This structure represents a compatible driver.
Description
A NULL-terminated string that describes the device supported by this driver.
MfgName
A NULL-terminated string that contains the name of the manufacturer of the device supported by this driver.
ProviderName
A NULL-terminated string giving the provider of this driver. This is typically the name of the organization that creates the driver or INF file. ProviderName can be an empty string.
DriverDate
Date of the driver. From the DriverVer entry in the INF file. See the INF DDInstall Section for more information on the DriverVer entry.
DriverVersion
Version of the driver. From the DriverVer entry in the INF file.

Comments

In SetupAPI.h, this structure equates to either SP_DRVINFO_DATA_V1 or SP_DRVINFO_DATA_V2, based on whether you include the following line in your source code:

#define  USE_SP_DRVINFO_DATA_V1 1

Define this identifier if your component must run on Windows 98/Me, or on NT-based OS versions earlier than Windows 2000. If your component will be used only on Windows 2000 and later, do not define the identifier. If the identifier is not defined, SP_DRVINFO_DATA_V2 is used.

SP_DRVINFO_DATA_V1 does not contain DriverDate and DriverVersion members.

See Also

SetupDiEnumDriverInfo, SetupDiGetDriverInstallParams, SetupDiGetSelectedDriver, SetupDiSetDriverInstallParams, SetupDiSetSelectedDriver


SP_DRVINFO_DETAIL_DATA

An SP_DRVINFO_DETAIL_DATA structure contains detailed information about a particular driver information structure.

typedef struct _SP_DRVINFO_DETAIL_DATA {
  DWORD  cbSize;
  FILETIME  InfDate;
  DWORD  CompatIDsOffset;
  DWORD  CompatIDsLength;
  ULONG_PTR  Reserved;
  TCHAR  SectionName[LINE_LEN];
  TCHAR  InfFileName[MAX_PATH];
  TCHAR  DrvDescription[LINE_LEN];
  TCHAR  HardwareID[ANYSIZE_ARRAY];
} SP_DRVINFO_DETAIL_DATA, *PSP_DRVINFO_DETAIL_DATA;

Members

cbSize
The size, in bytes, of the SP_DRVINFO_DETAIL_DATA structure.
InfDate
Date of the INF file for this driver.
CompatIDsOffset
The offset, in characters, from the beginning of the HardwareID buffer where the CompatIDs list begins.
CompatIDsLength
The length, in characters, of the CompatIDs list starting at offset CompatIDsOffset from the beginning of the HardwareID buffer. The CompatIDs list is a list of NULL-terminated strings with an extra NULL at the end of the list.
SectionName
A NULL-terminated string that contains the name of the INF DDINstall section for this driver. This must be the basic DDInstall section name, such as InstallSec, without any OS/architecture-specific extensions.
InfFileName
A NULL-terminated string that contains the full-qualified name of the INF file for this driver.
DrvDescription
A NULL-terminated string that describes the driver.
HardwareID
A buffer that contains the Hardware ID and Compatible IDs list. This is a list of NULL-terminated strings, with an extra NULL at the end of the list.

See Also

INF DDInstall Section, SetupDiGetDriverInfoDetail


SP_DRVINSTALL_PARAMS

An SP_DRVINSTALL_PARAMS structure contains driver installation parameters associated with a particular driver information element.

typedef struct _SP_DRVINSTALL_PARAMS {
  DWORD  cbSize;
  DWORD  Rank;
  DWORD  Flags;
  DWORD_PTR  PrivateData;
  DWORD  Reserved;
} SP_DRVINSTALL_PARAMS, *PSP_DRVINSTALL_PARAMS;

Members

cbSize
The size, in bytes, of the SP_DRVINSTALL_PARAMS structure.
Rank
The rank match of this driver. Ranges from 0 to n, where 0 is the most compatible.
Flags
Flags that control functions operating on this driver. Can be a combination of the following:
DNF_BAD_DRIVER
Do not use this driver. Installers can read and write this flag.

If this flag is set, SetupDiSelectBestCompatDrv and SetupDiSelectDevice ignore this driver.

A class installer or co-installer can set this flag to prevent Setup from listing the driver in the Select Driver dialog box. An installer might set this flag when handling a DIF_SELECTDEVICE or DIF_SELECTBESTCOMPATDRV request, for example.

DNF_BASIC_DRIVER
(Windows XP and later) Reserved.
DNF_CLASS_DRIVER
This driver is a class driver. This flag is READ ONLY to installers.
DNF_COMPATIBLE_DRIVER
This driver is a compatible driver. This flag is READ ONLY to installers.
DNF_DUPDESC
There are other providers supplying drivers that have the same description as this driver. This flag is READ ONLY to installers.
DNF_DUPDRIVERVER
(Windows XP and later) There are other providers supplying drivers that have the same description and date as this driver. This flag is READ ONLY to installers.
DNF_DUPPROVIDER
There are other providers supplying drivers that have the same description as this driver. The only difference between this driver and its match is the driver date. This flag is READ ONLY to installers.

If this flag is set, Setup displays the driver date and driver version next to the driver so the user can distinguish it from its match.

DNF_EXCLUDEFROMLIST
Do not display this driver in any driver-select dialogs.
DNF_INDEXED_DRIVER
Reserved.
DNF_INET_DRIVER
This driver came from the Internet or from Windows Update. This flag is READ ONLY to installers.

If you call SetupCopyOEMInf you must specify the SPOST_URL flag so that when Setup copies this INF into the %windir%\inf directory Setup will mark it as an Internet INF. If you omit this step then Setup will attempt to use this device to install other devices. The resulting problem is that Setup does not have the source files any more and will end up prompting the user with an invalid path.

DNF_INF_IS_SIGNED
(Windows XP and later) The driver's INF file is digitally signed. This flag is READ ONLY to installers.
DNF_LEGACYINF
This driver comes from a legacy INF file. This flag is valid only for the NT-based operating system. This flag is READ ONLY to installers.
DNF_NODRIVER
Set if no physical driver is to be installed for this logical driver.
DNF_OEM_F6_INF
(Windows XP and later) Reserved.
DNF_OLD_INET_DRIVER
This driver came from the Internet, but Setup does not currently have access to its source files. This flag is READ ONLY to installers.

The system will not install a driver marked with this flag because Setup does not have the source files and would end up prompting the user with an invalid path. The INF for such a driver can be used for everything except for installing devices.

DNF_OLDDRIVER
This driver presently/previously controlled the associated device. This flag is READ ONLY to installers.
PrivateData
A field a class installer can use to store private data. Co-installers should not use this field.

See Also

SetupDiGetDriverInstallParams, SetupDiSetDriverInstallParams


SP_ENABLECLASS_PARAMS

This structure is obsolete.

typedef struct _SP_ENABLECLASS_PARAMS {
  SP_CLASSINSTALL_HEADER  ClassInstallHeader;
  GUID  ClassGuid;
  DWORD  EnableMessage;
} SP_ENABLECLASS_PARAMS, *PSP_ENABLECLASS_PARAMS;


SP_INSTALLWIZARD_DATA

This structure is obsolete.

SP_INSTALLWIZARD_DATA is a parameter to the SetupDiGetWizardPage function.

Instead of DIF_INSTALLWIZARD, Setup uses the DIF_NEWDEVICEWIZARD_XXX requests such as DIF_NEWDEVICEWIZARD_FINISHINSTALL.


SP_MOVEDEV_PARAMS

This structure and its associated DIF_MOVEDEVICE installation request are reserved for system use.

typedef struct _SP_MOVEDEV_PARAMS {
  SP_CLASSINSTALL_HEADER  ClassInstallHeader;
  SP_DEVINFO_DATA  SourceDeviceInfoData;
} SP_MOVEDEV_PARAMS, *PSP_MOVEDEV_PARAMS;


SP_NEWDEVICEWIZARD_DATA

An SP_NEWDEVICEWIZARD_DATA structure is used by installers to extend the operation of the hardware installation wizard by adding custom pages. It is used with DIF_NEWDEVICEWIZARD_XXX installation requests.

typedef struct _SP_NEWDEVICEWIZARD_DATA {
  SP_CLASSINSTALL_HEADER  ClassInstallHeader;
  DWORD  Flags;
  HPROPSHEETPAGE  DynamicPages[MAX_INSTALLWIZARD_DYNAPAGES];
  DWORD  NumDynamicPages;
  HWND  hwndWizardDlg;
} SP_NEWDEVICEWIZARD_DATA, *PSP_NEWDEVICEWIZARD_DATA;

Members

ClassInstallHeader
An install request header that contains the header size and the DIF code for the request. See SP_CLASSINSTALL_HEADER.
Flags
Reserved. Must be zero.
DynamicPages
An array of property sheet page handles. An installer can add the handles of custom wizard pages to this array.
NumDynamicPages
The number of pages added to the DynamicPages array.

Because the array index is zero-based, this value is also the index to the next free entry in the array. For example, if there are 3 pages in the array, DynamicPages[3] is the next entry for an installer to use.

hwndWizardDlg
The window handle of the hardware installation wizard top-level window.

See Also

DIF_NEWDEVICEWIZARD_FINISHINSTALL, DIF_NEWDEVICEWIZARD_POSTANALYZE, DIF_NEWDEVICEWIZARD_PREANALYZE, DIF_NEWDEVICEWIZARD_PRESELECT, DIF_NEWDEVICEWIZARD_SELECT, SP_CLASSINSTALL_HEADER


SP_POWERMESSAGEWAKE_PARAMS

An SP_POWERMESSAGEWAKE_PARAMS structure corresponds to a DIF_POWERMESSAGEWAKE installation request.

typedef struct _SP_POWERMESSAGEWAKE_PARAMS {
  SP_CLASSINSTALL_HEADER  ClassInstallHeader;
  TCHAR  PowerMessageWake[LINE_LEN];
} SP_POWERMESSAGEWAKE_PARAMS, *PSP_POWERMESSAGEWAKE_PARAMS;

Members

ClassInstallHeader
An install request header that contains the header size and the DIF code for the request. See SP_CLASSINSTALL_HEADER.
PowerMessageWake
Buffer that contains a string of custom text. Setup displays this text on the power management page of the device properties display in Device Manager.

Comments

Setup only sends the DIF_POWERMESSAGEWAKE request if the drivers for the device support power management.

See Also

DIF_POWERMESSAGEWAKE, SP_CLASSINSTALL_HEADER


SP_PROPCHANGE_PARAMS

An SP_PROPCHANGE_PARAMS structure corresponds to a DIF_PROPERTYCHANGE installation request.

typedef struct _SP_PROPCHANGE_PARAMS {
  SP_CLASSINSTALL_HEADER  ClassInstallHeader;
  DWORD  StateChange;
  DWORD  Scope;
  DWORD  HwProfile;
} SP_PROPCHANGE_PARAMS, *PSP_PROPCHANGE_PARAMS;

Members

ClassInstallHeader
An install request header that contains the header size and the DIF code for the request. See SP_CLASSINSTALL_HEADER.
StateChange
State change action. Can be one of the following values:
DICS_ENABLE
The device is being enabled.

For this state change, Setup enables the device if the DICS_FLAG_GLOBAL flag is specified.

If the DICS_FLAG_CONFIGSPECIFIC flag is specified and the current hardware profile is specified then Setup enables the device. If the DICS_FLAG_CONFIGSPECIFIC is specified and not the current hardware profile then Setup sets some flags in the registry and does not change the device's state. Setup will change the device state when the specified profile becomes the current profile.

DICS_DISABLE
The device is being disabled.

For this state change, Setup disables the device if the DICS_FLAG_GLOBAL flag is specified.

If the DICS_FLAG_CONFIGSPECIFIC flag is specified and the current hardware profile is specified then Setup disables the device. If the DICS_FLAG_CONFIGSPECIFIC is specified and not the current hardware profile then Setup sets some flags in the registry and does not change the device's state.

DICS_PROPCHANGE
The properties of the device have changed.

For this state change, Setup ignores the Scope information and stops and restarts the device.

DICS_START
The device is being started (if the request is for the currently active hardware profile).

DICS_START must be DICS_FLAG_CONFIGSPECIFIC; you cannot perform that change globally.

Setup only starts the device if the current hardware profile is specified, otherwise Setup sets a registry flag and does not change the state of the device.

DICS_STOP
The device is being stopped. The driver stack will be unloaded and the CSCONFIGFLAG_DO_NOT_START flag will be set for the device.

DICS_STOP must be DICS_FLAG_CONFIGSPECIFIC; you cannot perform that change globally.

Setup only stops the device if the current hardware profile is specified, otherwise Setup sets a registry flag and does not change the state of the device.

Components should not specify DICS_STOP or DICS_START. Instead, they should use DICS_PROPCHANGE to stop and restart a device to cause changes in the device's configuration to take effect.

Scope
Flags that specify the scope of a device property change. Can be one of the following:
DICS_FLAG_GLOBAL
Make the change in all hardware profiles.
DICS_FLAG_CONFIGSPECIFIC
Make the change in the specified profile only.

The following flag is obsolete:

DICS_FLAG_CONFIGGENERAL
HwProfile
Supplies the hardware profile ID for profile-specific changes. Zero specifies the current hardware profile.

See Also

DIF_PROPERTYCHANGE, SetupDiCallClassInstaller, SetupDiChangeState, SP_CLASSINSTALL_HEADER


SP_PROPSHEETPAGE_REQUEST

An SP_PROPSHEETPAGE_REQUEST structure can be passed as the first parameter (lpv) to the ExtensionPropSheetPageProc entry point in the Setupapi DLL. ExtensionPropSheetPageProc is used to retrieve a handle to a specified property sheet page.

For information on ExtensionPropSheetPageProc and related functions, see the Platform SDK documentation.

typedef struct _SP_PROPSHEETPAGE_REQUEST {
  DWORD  CbSize;
  DWORD  PageRequested;
  HDEVINFO  DeviceInfoSet;
  PSP_DEVINFO_DATA  DeviceInfoData;
} SP_PROPSHEETPAGE_REQUEST, *PSP_PROPSHEETPAGE_REQUEST;

Members

CbSize
The size, in bytes, of the SP_PROPSHEETPAGE_REQUEST structure.
PageRequested
The property sheet page to add to the to property sheet. Can be one of the following values:
SPPSR_SELECT_DEVICE_RESOURCES
Specifies the Resource Selection page supplied by the Setupapi DLL.
SPPSR_ENUM_BASIC_DEVICE_PROPERTIES
Specifies a page that is supplied by the device's BasicProperties32 provider. That is, an installer or other component that supplied page(s) in response to a DIF_ADDPROPERTYPAGE_BASIC installation request.
SPPSR_ENUM_ADV_DEVICE_PROPERTIES
Specifies a page that is supplied by the class and/or the device's EnumPropPages32 provider. That is, an installer or other component that supplied page(s) in response to a DIF_ADDPROPERTYPAGE_ADVANCED installation request.
DeviceInfoSet
The handle for the device information set that contains the device being installed.
DeviceInfoData
A pointer to an SP_DEVINFO_DATA structure for the device being installed.

Comments

The component that is retrieving the property pages calls Setupapi's ExtensionPropSheetPageProc function and passes in a pointer to a SP_PROPSHEETPAGE_REQUEST structure, the address of their AddPropSheetPageProc function, and some private data. The property sheet provider calls the AddPropSheetPageProc routine for each property sheet it provides.

The following code excerpt illustrates how to retrieve one page, the Setupapi's Resource Selection page:

{
    DWORD Err;
    HINSTANCE hLib;
    FARPROC PropSheetExtProc;
    HPROPSHEETPAGE hPages[2];
    .
    .
    .
        if(!(hLib = GetModuleHandle(TEXT("setupapi.dll")))) {
            return GetLastError();
        }

        if(!(PropSheetExtProc = GetProcAddress(hLib,
                 "ExtensionPropSheetPageProc"))) {
            Err = GetLastError();
            FreeLibrary(hLib);
            return Err;
        }

        PropPageRequest.cbSize = sizeof(SP_PROPSHEETPAGE_REQUEST);
        PropPageRequest.PageRequested  =
            SPPSR_SELECT_DEVICE_RESOURCES;
        PropPageRequest.DeviceInfoSet  = DeviceInfoSet;
        PropPageRequest.DeviceInfoData = DeviceInfoData;

        if(!PropSheetExtProc(&PropPageRequest,
                AddPropSheetPageProc, &hPages[1])) {
            Err = ERROR_INVALID_PARAMETER;
            FreeLibrary(hLib);
            return Err;
        }
        .
        .
        .
}

The AddPropSheetPageProc for the above excerpt would be something like the following:

BOOL
CALLBACK
AddPropSheetPageProc(
    IN HPROPSHEETPAGE hpage,
    IN LPARAM lParam
   )
{
    *((HPROPSHEETPAGE *)lParam) = hpage;
    return TRUE;
}

See Also

DIF_ADDPROPERTYPAGE_ADVANCED, DIF_ADDPROPERTYPAGE_BASIC


SP_REMOVEDEVICE_PARAMS

An SP_REMOVEDEVICE_PARAMS structure corresponds to the DIF_REMOVE installation request.

typedef struct _SP_REMOVEDEVICE_PARAMS {
  SP_CLASSINSTALL_HEADER  ClassInstallHeader;
  DWORD  Scope;
  DWORD  HwProfile;
} SP_REMOVEDEVICE_PARAMS, *PSP_REMOVEDEVICE_PARAMS;

Members

ClassInstallHeader
An install request header that contains the header size and the DIF code for the request. See SP_CLASSINSTALL_HEADER.
Scope
Flags that indicate the scope of the device removal. Can be one of the following values:
DI_REMOVEDEVICE_GLOBAL
Make this change in all hardware profiles. Remove information about the device from the registry.
DI_REMOVEDEVICE_CONFIGSPECIFIC
Make this change to only the hardware profile specified by HwProfile. this flag only applies to root-enumerated devices. When Setup removes the device from the last hardware profile in which it was configured, Setup performs a global removal.
HwProfile
The hardware profile ID for profile-specific changes. Zero specifies the current hardware profile.

See Also

DIF_REMOVE, SetupDiCallClassInstaller, SetupDiRemoveDevice, SP_CLASSINSTALL_HEADER


SP_SELECTDEVICE_PARAMS

An SP_SELECTDEVICE_PARAMS structure corresponds to a DIF_SELECTDEVICE installation request.

typedef struct _SP_SELECTDEVICE_PARAMS {
  SP_CLASSINSTALL_HEADER  ClassInstallHeader;
  TCHAR  Title[MAX_TITLE_LEN];
  TCHAR  Instructions[MAX_INSTRUCTION_LEN];
  TCHAR  ListLabel[MAX_LABEL_LEN];
  TCHAR  SubTitle[MAX_SUBTITLE_LEN];
} SP_SELECTDEVICE_PARAMS, *PSP_SELECTDEVICE_PARAMS;

Members

ClassInstallHeader
An install request header that contains the header size and the DIF code for the request. See SP_CLASSINSTALL_HEADER.
Title
Buffer that contains an installer-provided window title for driver-selection windows. Setup uses this title for the select-driver window header title in the Add Hardware Wizard or the window title for the Select Device dialogs.
Instructions
Buffer that contains an installer-provided select-device instructions.
ListLabel
Buffer that contains an installer-provided label for the list of drivers from which the user can select.
SubTitle
Buffer that contains an installer-provided subtitle used in select-device wizards. This string is not used in select dialogs.

Comments

If an installer sets fields in this structure to be used during driver selection, the installer must also set the DI_USECI_SELECTSTRINGS flag in the SP_DEVINSTALL_PARAMS.

The following figure shows a sample Select Device dialog box and identifies the strings an installer can supply.

Sample Select Device Dialog

See Also

DIF_SELECTDEVICE, SetupDiCallClassInstaller, SetupDiSelectDevice, SP_CLASSINSTALL_HEADER


SP_TROUBLESHOOTER_PARAMS

An SP_TROUBLESHOOTER_PARAMS structure corresponds to a DIF_TROUBLESHOOTER installation request.

typedef struct _SP_TROUBLESHOOTER_PARAMS {
  SP_CLASSINSTALL_HEADER  ClassInstallHeader;
  TCHAR  ChmFile[MAX_PATH];
  TCHAR  HtmlTroubleShooter[MAX_PATH];
} SP_TROUBLESHOOTER_PARAMS, *PSP_TROUBLESHOOTER_PARAMS;

Members

ClassInstallHeader
An install request header that contains the header size and the DIF code for the request. See SP_CLASSINSTALL_HEADER.
ChmFile
Optionally specifies a string buffer that contains the path to a CHM file. The CHM file contains HTML help topics with troubleshooting information. The path must be fully qualified if the file is not in default system help directory (%windir%\help).
HtmlTroubleShooter
Optionally specifies a string buffer that contains the path to a topic in the ChmFile. This parameter identifies the page of the ChmFile that Setup should display first.

Comments

An installer fills in this structure in response to a DIF_TROUBLESHOOTER request.

See Also

DIF_TROUBLESHOOTER, SetupDiCallClassInstaller, SP_CLASSINSTALL_HEADER


SP_UNREMOVEDEVICE_PARAMS

An SP_UNREMOVEDEVICE_PARAMS structure corresponds to a DIF_UNREMOVE installation request.

typedef struct _SP_UNREMOVEDEVICE_PARAMS {
  SP_CLASSINSTALL_HEADER  ClassInstallHeader;
  DWORD  Scope;
  DWORD  HwProfile;
} SP_UNREMOVEDEVICE_PARAMS, *PSP_UNREMOVEDEVICE_PARAMS;

Members

ClassInstallHeader
An install request header that contains the header size and the DIF code for the request. See SP_CLASSINSTALL_HEADER.
Scope
A flag that indicates the scope of the unremove operation. This flag must always be set to DI_UNREMOVEDEVICE_CONFIGSPECIFIC
HwProfile
The hardware profile ID for profile-specific changes. Zero specifies the current hardware profile.

See Also

DIF_UNREMOVE,SetupDiCallClassInstaller, SetupDiUnremoveDevice, SP_CLASSINSTALL_HEADER


Device Installation Function Codes

This section describes the device installation requests that Setup applications send to class installers and co-installers. Each request is represented by a device installation function code (a DIF code). The DIF code constants are defined in the setupapi.h header file.

Installers that handle these requests include class installers, class co-installers, and device co-installers. Some installers are provided by Microsoft and some are provided by OEMs and third-party vendors.

Setup applications send DIF codes to installers by calling SetupDiCallClassInstaller, which in turn calls the installer's entry point function. The DIF code is one of the parameters to the installer's entry point function; other parameters provide additional input. For more information, see Handling DIF Codes.

For information on writing installers, see Writing a Co-installer and Writing a Class Installer.


DIF_ADDPROPERTYPAGE_ADVANCED

A DIF_ADDPROPERTYPAGE_ADVANCED request allows an installer to supply one or more custom property pages for a device.

When Sent

When a user clicks on the properties for a device in the Device Manager or in a Control Panel applet.

Who Handles

Class Co-installer | Can handle
Device Co-installer | Can handle
Class Installer | Can handle

Installer Input

DeviceInfoSet
Supplies a handle to the device information set containing the device.
DeviceInfoData
Optionally supplies a pointer to an SP_DEVINFO_DATA structure that identifies the device in the device information set. If DeviceInfoSet is NULL, Setup is requesting property pages for the device setup class.
Device Installation Parameters
Device installation parameters (SP_DEVINSTALL_PARAMS) are associated with the DeviceInfoData, if specified, or with the DeviceInfoSet.
Class Installation Parameters
An SP_ADDPROPERTYPAGE_DATA structure is associated with the DeviceInfoData, if specified, or with the DeviceInfoSet.

Installer Output

Device Installation Parameters
An installer can modify the device installation parameters.
Class Installation Parameters
An installer can modify the SP_ADDPROPERTYPAGE_DATA to supply custom pages.

Installer Return Value

A co-installer can return NO_ERROR or a Win32® error. A co-installer should not return ERROR_DI_POSTPROCESSING_REQUIRED for this DIF request.

A class installer returns NO_ERROR if it successfully supplies pages. Otherwise, a class installer returns ERROR_DI_DO_DEFAULT or a Win32 error code.

Default DIF Code Handler

None

Installer Operation

In response to this DIF request an installer can supply custom property pages. Installers should handle this DIF request instead of supplying an EnumPropPages32 registry entry. The EnumPropPages32 method is supported, but handling this DIF request allows you to supply property pages from a class installer or co-installer and removes the need for a separate property-page provider.

An installer typically handles this DIF request to add a new device-specific or setup-class-specific property page. An installer can also replace the system-supplied driver property page, resource property page, or power property page for a device. If an installer replaces a system-supplied page, the installer must set the appropriate flag in the device installation parameters for the device:

DI_DRIVERPAGE_ADDED
The installer supplied a driver property page.
DI_RESOURCEPAGE_ADDED
The installer supplied a resource property page.
DI_FLAGSEX_POWERPAGE_ADDED
The installer supplied a power property page.

An installer cannot replace the system-supplied general properties page.

Setup only displays one driver page, one resource page, and one power page for a device. An installer should not supply a replacement system page if a previous installer already supplied a page of that type. This constraint does not apply to non-system-supplied property pages.

The following pseudo code shows how an installer adds a custom page to the array of pages in the class install parameters:

:
// get the class install parameters by calling
// SetupDiGetClassInstallParams

// check whether NumDynamicPages has reached the max

// for a system page, check whether a previous installer
// supplied it

// fill in the PROPSHEETPAGE structure

// add the page and increment the NumDynamicPages counter
PropPageData.DynamicPages[PropPageData.NumDynamicPages++] =
    CreatePropertySheetPage(&Page);

// apply the modified parameters by calling
// SetupDiSetClassInstallParams

// for a system page, set the appropriate flag in the devinstall
// parameters
:

If an installer adds custom property page(s), the installer should first check whether NumDynamicPages in the class install parameters has reached MAX_INSTALLWIZARD_DYNAPAGES.

A co-installer should add custom pages in its preprocessing pass.

If an installer allows a user to set a property that requires Setup to remove and restart the device, the installer must set the DI_FLAGSEX_PROPCHANGE_PENDING flag in the device installation parameters from its DialogProc routine.

For more information about DIF codes, see Handling DIF Codes.

See Also

SP_ADDPROPERTYPAGE_DATA, SP_DEVINFO_DATA, SP_DEVINSTALL_PARAMS


DIF_ALLOW_INSTALL

A DIF_ALLOW_INSTALL request asks the installers for a device whether Setup can proceed to install the device.

When Sent

After selecting a driver for the device but before installing the device.

Who Handles

Class Co-installer | Can handle
Device Co-installer | Should not handle
Class Installer | Can handle

Installer Input

DeviceInfoSet
Supplies a handle to the device information set containing the device.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that identifies the device in the device information set.
Device Installation Parameters
There are device installation parameters (SP_DEVINSTALL_PARAMS) associated with the DeviceInfoData.
Class Installation Parameters
None

Installer Output

None

Installer Return Value

A co-installer can return NO_ERROR or a Win32® error. A co-installer should not return ERROR_DI_POSTPROCESSING_REQUIRED for this DIF request.

A class installer typically returns ERROR_DI_DO_DEFAULT or a Win32 error code.

Typical Win32 error codes for this DIF request include ERROR_DI_DONT_INSTALL, ERROR_NON_WINDOWS_NT_DRIVER, and ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION.

Default DIF Code Handler

None

Installer Operation

In response to a DIF_ALLOW_INSTALL request an installer confirms whether Setup can install the device.

An installer can fail this request if it determines that the selected driver is incorrect (for example, if the driver is a Windows 9x-only driver that will not work correctly on NT-based operating systems) or if it determines that a selected driver is known to have bugs.

An installer might fail this request if the DI_QUIETINSTALL flag is set in the device installation parameters and the installer needs to display UI during device installation. This failure is rare, however, because an installer can typically supply any UI pages in response to the DIF_NEWDEVICEWIZARD_FINISHINSTALL request. In that case, UI does not prevent the installer from succeeding a DIF_ALLOW_INSTALL request for which the quiet flag is set. If, however, an installer cannot limit its UI to the finish-install case, the installer must fail this DIF request if the DI_QUIETINSTALL flag is set. An installer might have this restriction, for example, if it calls vendor-supplied code that displays UI.

If an installer fails this DIF request, Setup aborts the installation.

If an installer fails this DIF request and DI_QUIETINSTALL is not set in the device installation parameters, the installer should display a dialog box with a message that explains why the device is not being installed.

For more information about DIF codes, see Handling DIF Codes.

See Also

SP_DEVINFO_DATA, SP_DEVINSTALL_PARAMS


DIF_DESTROYPRIVATEDATA

A DIF_DESTROYPRIVATEDATA request directs a class installer to free any memory or resources it allocated and stored in the ClassInstallReserved field of the SP_DEVINSTALL_PARAMS structure.

When Sent

When Setup destroys a device information set or an SP_DEVINFO_DATA element, or when Setup discards its list of co-installers and class installer for a device.

Who Handles

Class Co-installer | Does not handle
Device Co-installer | Does not handle
Class Installer | Can handle

Installer Input

DeviceInfoSet
Supplies a handle to a device information set.
DeviceInfoData
Optionally supplies a pointer to an SP_DEVINFO_DATA structure that identifies a device in the device information set.
Device Installation Parameters
Device installation parameters (SP_DEVINSTALL_PARAMS) are associated with the DeviceInfoData, if specified, or with the DeviceInfoSet.
Class Installation Parameters
None

Installer Output

Device Installation Parameters
An installer can clear the ClassInstallReserved field in the device installation parameters (SP_DEVINSTALL_PARAMS).

Installer Return Value

A co-installer does not handle this DIF request; it simply returns NO_ERROR in its preprocessing pass.

A class installer typically returns ERROR_DI_DO_DEFAULT or a Win32 error code.

Default DIF Code Handler

None

Installer Operation

In response to a DIF_DESTROYPRIVATEDATA request a class installer frees any memory or resources it allocated and stored in the ClassInstallReserved field of the SP_DEVINSTALL_PARAMS structure.

Co-installers should not use the ClassInstallReserved field.

For more information about DIF codes, see Handling DIF Codes.

See Also

SP_DEVINFO_DATA, SP_DEVINSTALL_PARAMS


DIF_DETECT

A DIF_DETECT request directs an installer to detect non-PnP devices of a particular class and add the devices to the device information set. This request is used for non-PnP devices.

When Sent

When the Add Hardware Wizard is detecting non-PnP devices.

Who Handles

Class Co-installer | Can handle
Device Co-installer | Does not handle
Class Installer | Can handle

Installer Input

DeviceInfoSet
Supplies a handle to the device information set.
Associated Class
There is a device setup class associated with the DeviceInfoSet.
DeviceInfoData
None
Device Installation Parameters
There are device installation parameters associated with the DeviceInfoSet.
Class Installation Parameters
An SP_DETECTDEVICE_PARAMS structure is associated with the DeviceInfoSet. The parameters contain a callback routine that the class installer calls to indicate the progress of the detection operation.

Installer Output

DeviceInfoSet
An installer adds a device information element to the DeviceInfoSet for each device it detects, regardless of whether a device has been previously detected and installed.
Device Installation Parameters
An installer can modify the device installation parameters for the DeviceInfoSet or for new device information elements it creates.

Installer Return Value

If a co-installer does not detect devices, it returns NO_ERROR from its preprocessing pass. If a co-installer detects devices, it can do so during pre- or postprocessing and return NO_ERROR or a Win32 error code.

If a class installer detects devices, it returns NO_ERROR or an appropriate Win32 error code. If a class installer does not handle this DIF request, it returns ERROR_DI_DO_DEFAULT.

Default DIF Code Handler

None

Installer Operation

In response to a DIF_DETECT request an installer can detect devices of its setup class.

If an installer detects devices, it should do at least the following:

  • Call the DetectProgressNotify callback routine in the SP_DETECTDEVICE_PARAMS class installation parameters, if detection will potentially take a noticeable amount of time.
  • For each device the installer detects, it should:
    • Create a device information element (SetupDiCreateDeviceInfo).
    • Provide information for driver selection.

      The installer can manually select the driver for the device or the installer can set the device's hardware ID that Setup will use to find an INF for the device. An installer sets the hardware ID by calling SetupDiSetDeviceRegistryProperty with a Property value of SPDRP_HARDWAREID.

    • Possibly set some device installation parameters.
  • Return NO_ERROR for successful detection or return a Win32 error code.

If one or more installers detects device(s) in response to this DIF code, Setup compares the list of detected devices to its current list of devices. If the installers detected a new device, Setup attempts to install the device. If the installers omitted a device that appears in Setup's list, Setup typically removes the device.

To detect non-PnP devices during GUI-mode setup, an installer must handle the DIF_FIRSTTIMESETUP request. GUI-mode setup does not send a DIF_DETECT request.

For more information about DIF codes, see Handling DIF Codes.

See Also

DIF_FIRSTTIMESETUP, SetupDiCreateDeviceInfo, SP_DETECTDEVICE_PARAMS, SP_DEVINSTALL_PARAMS


DIF_INSTALLDEVICE

A DIF_INSTALLDEVICE request allows an installer to perform tasks before and/or after the device is installed.

When Sent

After selecting the driver, registering any device co-installers, and registering any device interfaces.

Who Handles

Class Co-installer | Can handle
Device Co-installer | Can handle
Class Installer | Can handle

Installer Input

DeviceInfoSet
Supplies a handle to the device information set containing the device to be installed.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure for the device in the device information set.
Device Installation Parameters
There are device installation parameters (SP_DEVINSTALL_PARAMS) associated with the DeviceInfoData.
Class Installation Parameters
None

Installer Output

Device Installation Parameters
An installer can modify the device installation parameters for the DeviceInfoData. For example, an installer might set the DI_NEEDREBOOT flag or it might set the DI_DONOTCALLCONFIGMG flag to prevent Setup from bringing the device online dynamically with its newly installed driver and settings.

Installer Return Value

A co-installer typically returns NO_ERROR or ERROR_DI_POSTPROCESSING_REQUIRED. A co-installer might return a Win32 error code.

A class installer typically returns ERROR_DI_DO_DEFAULT or a Win32 error code. If a class installer successfully installs the device, including superseding all the operations of the default handler, the class installer returns NO_ERROR.

Default DIF Code Handler

SetupDiInstallDevice

Installer Operation

In response to a DIF_INSTALLDEVICE request an installer typically performs any final installation operations before the default handler installs the device. For example, an installer can check, and possibly modify, the upper-filter drivers and lower-filter drivers for the device listed in the registry.

Unless the DI_NOFILECOPY flag is set in the device installation parameters, an installer that handles this DIF request should copy files required for the device, such as driver files and control panel files.

If the DI_NOFILECOPY flag is clear but the DI_NOVCP flag is set, the installer must enqueue any file operations to the supplied file queue but must not commit the queue.

A co-installer can handle this DIF request in its preprocessing pass and/or in its postprocessing pass. In its preprocessing pass, a co-installer performs any operations that must occur before Setup loads the drivers and starts the device. In its postprocessing pass, the device is up and running (unless the DI_NEEDREBOOT flag was set and thus Setup could not bring the device online dynamically).

If a class installer performs a few operations but does not replace the default handler, the class installer returns ERROR_DI_DO_DEFAULT.

If the installer returns a Win32 error code, Setup abandons the installation.

For more information about DIF codes, see Handling DIF Codes.

See Also

DIF_INSTALLDEVICEFILES, SetupDiInstallDevice, SP_DEVINFO_DATA, SP_DEVINSTALL_PARAMS


DIF_INSTALLDEVICEFILES

A DIF_INSTALLDEVICEFILES request allows an installer to participate in copying the files to support a device or to make a list of the files for a device. The device files include files for the selected driver, any device interfaces, and any co-installers.

When Sent

Setup components send this DIF request for a variety of reasons. Some Setup components send this DIF request before DIF_REGISTER_COINSTALLERS, DIF_INSTALLINTERFACES, and DIF_INSTALL_DEVICE to ensure that all the relevant files can be copied before proceeding with the installation. Some Setup components omit this DIF request and expect the files to be copied during the handling of those three DIF requests. In addition, some Setup components send this DIF request to retrieve the list of the files associated with a device.

Who Handles

Class Co-installer | Can handle
Device Co-installer | Does not handle
Class Installer | Can handle

Installer Input

DeviceInfoSet
Supplies a handle to the device information set containing the device whose supporting files are to be copied.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that identifies the device in the device information set.
Device Installation Parameters
There are device installation parameters (SP_DEVINSTALL_PARAMS) associated with the DeviceInfoData.

If the DI_NOVCP flag is set, the device installation parameters contain a valid FileQueue handle and installers that handle this DIF request add their file operations to this queue and do not commit the queue.

Class Installation Parameters
None

Installer Output

Device Installation Parameters
An installer can modify the FileQueue, if there is one.

Installer Return Value

A co-installer can return NO_ERROR, ERROR_DI_POSTPROCESSING_REQUIRED, or a Win32 error code.

A class installer typically returns ERROR_DI_DO_DEFAULT or a Win32 error code. If a class installer performs or enqueues all the necessary file operations, and thus supersedes the default handler, the class installer returns NO_ERROR.

Default DIF Code Handler

SetupDiInstallDriverFiles

Installer Operation

In response to a DIF_INSTALLDEVICEFILES request an installer specifies any necessary file operations. For example, an installer can specify an additional file to be copied that is required for device installation. If the DI_NOVCP flag is set, an installer specifies file operations by adding them to the FileQueue in the device installation parameters. See the Platform SDK for information on using file queues and for reference pages on file-queuing functions such as SetupInstallFilesFromInfSection.

If this DIF request is sent during device installation, and the installer returns a Win32 error code, Setup stops the installation.

If a Setup component sends this DIF request to retrieve a list of the files associated with a device, the component retrieves the file queue but does not commit the queue.

For more information about DIF codes, see Handling DIF Codes.

See Also

SetupDiInstallDriverFiles, SP_DEVINFO_DATA, SP_DEVINSTALL_PARAMS


DIF_INSTALLINTERFACES

A DIF_INSTALLINTERFACES request allows an installer to participate in the registration of the device interfaces for a device.

When Sent

After registering device co-installers but before completing device installation.

Who Handles

Class Co-installer | Can handle
Device Co-installer | Can handle
Class Installer | Can handle

Installer Input

DeviceInfoSet
Supplies a handle to the device information set containing the device.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that identifies the device in the device information set.
Device Installation Parameters
There are device installation parameters (SP_DEVINSTALL_PARAMS) associated with the DeviceInfoData.
Class Installation Parameters
None

Installer Output

Device Installation Parameters
An installer might modify the device installation parameters, but not usually for this DIF request.

Installer Return Value

A co-installer can return NO_ERROR, ERROR_DI_POSTPROCESSING_REQUIRED, or a Win32 error code.

A class installer typically returns ERROR_DI_DO_DEFAULT or a Win32 error code. If a class installer installs the interfaces, including calling SetupDiInstallDeviceInterfaces, the class installer returns NO_ERROR.

Default DIF Code Handler

SetupDiInstallDeviceInterfaces

Installer Operation

In response to a DIF_INSTALLINTERFACES request an installer might register a device interface programmatically instead of having the interface registered through the INF file. Typically, vendor-supplied installers don't handle this DIF request.

Unless the DI_NOFILECOPY flag is set, an installer that handles this DIF request should copy files required for the device interface(s).

If the DI_NOFILECOPY flag is clear but the DI_NOVCP flag is set, the installer must enqueue any file operations to the supplied file queue but must not commit the queue.

If an installer registers a device interface, a kernel-mode component for the device (for example, a driver) must call IoSetDeviceInterfaceState to enable the interface.

If the installer returns a Win32 error code, Setup stops the installation.

For more information about DIF codes, see Handling DIF Codes.

See Also

SetupDiInstallDeviceInterfaces, SP_DEVINFO_DATA, SP_DEVINSTALL_PARAMS


DIF_NEWDEVICEWIZARD_FINISHINSTALL

A DIF_NEWDEVICEWIZARD_FINISHINSTALL request allows an installer to supply wizard page(s) that Setup displays to the user after the device has been installed but before Setup displays the standard finish page. Setup sends this request when installing PnP devices and manually installed non-PnP devices.

When Sent

After Setup installs a device (on successful completion of DIF_INSTALLDEVICE processing) but before it displays the Finish wizard page.

Setup sends this request during "New Hardware Found" (PnP) and "Add New Hardware" (non-PnP) device installation and during GUI-mode setup.

Who Handles

Class Co-installer | Can handle
Device Co-installer | Can handle
Class Installer | Can handle

Installer Input

DeviceInfoSet
Supplies a handle to the device information set containing the device.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that identifies the device in the device information set.
Device Installation Parameters
There are device installation parameters (SP_DEVINSTALL_PARAMS) associated with the DeviceInfoData.
Class Installation Parameters
An SP_NEWDEVICEWIZARD_DATA structure is associated with the DeviceInfoData.

Installer Output

Device Installation Parameters
An installer can modify the flags in the device installation parameters.
Class Installation Parameters
An installer can modify the SP_NEWDEVICEWIZARD_DATA to supply custom page(s).

Installer Return Value

If a co-installer does not handle this DIF request it returns NO_ERROR from its preprocessing pass. If a co-installer handles this request it can return NO_ERROR, ERROR_DI_POSTPROCESSING_REQUIRED, or a Win32 error code.

A class installer returns NO_ERROR if it successfully supplies page(s). Otherwise, a class installer returns ERROR_DI_DO_DEFAULT or a Win32 error code.

Default DIF Code Handler

None

Installer Operation

A DIF_NEWDEVICEWIZARD_FINISHINSTALL request allows an installer to supply wizard pages that Setup displays to the user after the device has been installed but before Setup displays the standard Finish page. Setup sends this request when installing any kind of device, whether it is a PnP-enumerated device, a detected non-PnP device, or a manually installed non-PnP device.

An installer can handle this DIF request for any PnP device.

This DIF request is not supported when installing certain non-PnP devices such as modems, printers, and scanners. If a user manually installs a non-PnP printer, modem, or scanner using the Add Hardware Wizard, the Setup application for that device does not display any finish-install pages supplied for the device.

An installer typically uses a custom Finish page to collect additional user preference settings, such as modem line speeds or default area codes.

Class installers and co-installers should only supply finish-install pages if they absolutely require that the user answer questions before the device can operate properly. If the questions are optional, or if the questions were previously answered (for example, this is an upgrade for an existing device), then they should not supply finish-install pages. Class installers and co-installers should always supply one or more property pages in response to DIF_ADDPROPERTYPAGE_ADVANCED so the user can adjust device settings after the device is installed.

The following pseudo code shows how an installer adds a custom page to the array of pages in the class install parameters:

:
// get the class install parameters by calling
// SetupDiGetClassInstallParams

// check whether NumDynamicPages has reached the max

// fill in the PROPSHEETPAGE structure

// add the page and increment the NumDynamicPages counter
NewDevWizardData.DynamicPages[NewDevWizardData.NumDynamicPages++] =
    CreatePropertySheetPage(&Page);

// apply the modified params by calling
// SetupDiSetClassInstallParams

:

See the Platform SDK for information on the CreatePropertySheetPage function.

If an installer's custom Finish page gathers settings from the user and the device needs to be restarted to have the new settings take effect, the page dialog procedure calls SetupDiChangeState with a StateChange value of DICS_PROPCHANGE in the class installation parameters. This call to SetupDiChangeState directs the PnP Manager to query-remove and remove the device, reenumerate the device's parent, rebuild the device stack of drivers, and restart the device. If an installer determines that the device cannot be dynamically removed and restarted, the installer can set the DI_NEEDREBOOT flag in the device install parameters instead of calling SetupDiChangeState. An installer should not force a reboot, however, unless it is absolutely necessary.

Setup and the PnP Manager attempt to install PnP devices in a trusted PnP context without requiring user response to dialog boxes (a "server-side" installation). If an installer supplies custom Finish page(s), however, Setup is required to display those pages to the user. Setup aborts the trusted installation and restarts the device installation when a user with administrative privileges logs in (a "client-side" installation).

GUI-mode setup sends the DIF_NEWDEVICEWIZARD_FINISHINSTALL request for each device it installs, but GUI-mode setup cannot display installation wizard pages. If an installer supplies custom finish pages, GUI-mode setup marks the device so the user receives a "New Hardware Found" popup at first login. The network configuration component of GUI-mode setup locates any network devices, such as ISDN boards, that have finish-install wizard pages, gathers those pages, and incorporates them into the network setup wizard pages.

An installer should supply a Wizard 97 header title and a header subtitle in the PROPSHEETPAGE structure for a custom wizard page. An installer should not replace the system-supplied wizard title. See the Platform SDK for documentation of the PROPSHEETPAGE structure and for more information about property pages.

Installers should supply their finish-install wizard pages, regardless of the value of the DI_QUIETINSTALL flag. The sender of the DIF_NEWDEVICEWIZARD_FINISHINSTALL request determines whether to display the wizard pages and ensures that the pages are freed in either case.

An installer can use this DIF request to add custom wizard pages, but an installer cannot replace the system-supplied finish page.

By default, the Cancel button for finish-install wizard pages is disabled. If you want to allow the user to cancel out of your finish-install wizard pages, your installer must enable the Cancel button.

For more information about DIF codes, see Handling DIF Codes.

See Also

DIF_INSTALLDEVICE, SetupDiChangeState, SP_DEVINFO_DATA, SP_DEVINSTALL_PARAMS, SP_NEWDEVICEWIZARD_DATA


DIF_NEWDEVICEWIZARD_POSTANALYZE

A DIF_NEWDEVICEWIZARD_POSTANALYZE request allows an installer to supply wizard pages that Setup displays to the user after the devnode is registered but before Setup installs the drivers for the device. This request is only used during manual installation of non-PnP devices.

When Sent

After Setup registers the device, which makes the devnode "live", but before Setup installs the drivers for the device.

Who Handles

Class Co-installer | Can handle
Device Co-installer | Does not handle
Class Installer | Can handle

Installer Input

DeviceInfoSet
Supplies a handle to the device information set containing the device.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that identifies the device in the device information set.
Device Installation Parameters
There are device installation parameters (SP_DEVINSTALL_PARAMS) associated with the DeviceInfoData.
Class Installation Parameters
An SP_NEWDEVICEWIZARD_DATA structure is associated with the DeviceInfoData.

Installer Output

Device Installation Parameters
An installer can modify the flags in the device installation parameters. Setup does not check the flags upon completion of this DIF request, but it will check them later in the installation process.
Class Installation Parameters
An installer can modify the SP_NEWDEVICEWIZARD_DATA to supply custom page(s).

Installer Return Value

If a co-installer does not handle this DIF request it returns NO_ERROR from its preprocessing pass. If a co-installer handles this request it can return NO_ERROR, ERROR_DI_POSTPROCESSING_REQUIRED, or a Win32 error code.

A class installer returns NO_ERROR if it successfully supplies page(s). Otherwise, a class installer returns ERROR_DI_DO_DEFAULT or a Win32 error code.

Default DIF Code Handler

None

Installer Operation

A DIF_NEWDEVICEWIZARD_POSTANALYZE request allows an installer to supply wizard pages that Setup displays to the user after the devnode is registered but before Setup installs the drivers for the device. This request is only used during manual installation of non-PnP devices.

If an installer adds custom postanalyze page(s), the installer should first check whether NumDynamicPages in the class install parameters has reached MAX_INSTALLWIZARD_DYNAPAGES.

After the user clicks "Next" on a custom page, Setup installs the drivers for the device and the PnP Manager starts the device. A postanalyze wizard page is the last chance for an installer to do work before the drivers are loaded and the device is started.

An installer should supply a Wizard 97 header title and a header subtitle in the PROPSHEETPAGE structure for a custom wizard page. An installer should not replace the system-supplied wizard title. See the Platform SDK for documentation of the PROPSHEETPAGE structure and for more information about property pages.

For more information about DIF codes, see Handling DIF Codes.

See Also

DIF_NEWDEVICEWIZARD_PREANALYZE, DIF_NEWDEVICEWIZARD_PRESELECT, DIF_NEWDEVICEWIZARD_SELECT, SP_DEVINFO_DATA, SP_DEVINSTALL_PARAMS, SP_NEWDEVICEWIZARD_DATA


DIF_NEWDEVICEWIZARD_PREANALYZE

A DIF_NEWDEVICEWIZARD_PREANALYZE request allows an installer to supply wizard pages that Setup displays to the user before it displays the analyze page. This request is only used during manual installation of non-PnP devices.

When Sent

After the user has selected a driver, but before Setup registers the device that makes the devnode "live".

Who Handles

Class Co-installer | Can handle
Device Co-installer | Does not handle
Class Installer | Can handle

Installer Input

DeviceInfoSet
Supplies a handle to the device information set containing the device.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that identifies the device in the device information set.
Device Installation Parameters
There are device installation parameters (SP_DEVINSTALL_PARAMS) associated with the DeviceInfoData.
Class Installation Parameters
An SP_NEWDEVICEWIZARD_DATA structure is associated with the DeviceInfoData.

Installer Output

Device Installation Parameters
An installer can modify the flags in the device installation parameters. Setup does not check the flags upon completion of this DIF request, but it checks them later in the installation process.
Class Installation Parameters
An installer can modify the SP_NEWDEVICEWIZARD_DATA to supply custom wizard page(s).

Installer Return Value

If a co-installer does not handle this DIF request it returns NO_ERROR from its preprocessing pass. If a co-installer handles this request it can return NO_ERROR, ERROR_DI_POSTPROCESSING_REQUIRED, or a Win32 error code.

A class installer returns NO_ERROR if it successfully supplies page(s). Otherwise, a class installer returns ERROR_DI_DO_DEFAULT or a Win32 error code.

Default DIF Code Handler

None

Installer Operation

A DIF_NEWDEVICEWIZARD_PREANALYZE request allows an installer to supply wizard pages that Setup displays to the user before it displays the analyze page. These pages can be thought of as "post-select" pages. This request is only used during manual installation of non-PnP devices.

An installer might use a custom preanalyze page, for example, to choose a COM port after a modem device is selected.

If an installer adds custom preselect page(s), the installer should first check whether NumDynamicPages in the class install parameters has reached MAX_INSTALLWIZARD_DYNAPAGES.

An installer should supply a Wizard 97 header title and a header subtitle in the PROPSHEETPAGE structure for a custom wizard page. An installer should not replace the system-supplied wizard title. See the Platform SDK for documentation of the PROPSHEETPAGE structure and for more information about property pages.

For more information about DIF codes, see Handling DIF Codes.

See Also

DIF_NEWDEVICEWIZARD_PRESELECT, DIF_NEWDEVICEWIZARD_POSTANALYZE, DIF_NEWDEVICEWIZARD_SELECT, SP_DEVINFO_DATA, SP_DEVINSTALL_PARAMS, SP_NEWDEVICEWIZARD_DATA


DIF_NEWDEVICEWIZARD_PRESELECT

A DIF_NEWDEVICEWIZARD_PRESELECT request allows an installer to supply wizard pages that Setup displays to the user before it displays the select-driver page. This request is only used during manual installation of non-PnP devices.

When Sent

After the user has selected the class for the device but before Setup displays the "Select a Device Driver" page.

Who Handles

Class Co-installer | Can handle
Device Co-installer | Does not handle
Class Installer | Can handle

Installer Input

DeviceInfoSet
Supplies a handle to the device information set containing the device.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that identifies the device in the device information set.
Device Installation Parameters
There are device installation parameters (SP_DEVINSTALL_PARAMS) associated with the DeviceInfoData.
Class Installation Parameters
An SP_NEWDEVICEWIZARD_DATA structure is associated with the DeviceInfoData.

Installer Output

Device Installation Parameters
An installer can modify the flags in the device installation parameters. Setup does not check the flags upon completion of this DIF request, but it checks them later in the installation process.
Class Installation Parameters
An installer can modify the SP_NEWDEVICEWIZARD_DATA to supply custom page(s).

Installer Return Value

If a co-installer does not handle this DIF request it returns NO_ERROR from its preprocessing pass. If a co-installer handles this request it can return NO_ERROR, ERROR_DI_POSTPROCESSING_REQUIRED, or a Win32 error code.

A class installer returns NO_ERROR if it successfully supplies page(s). Otherwise, a class installer returns ERROR_DI_DO_DEFAULT or a Win32 error code.

Default DIF Code Handler

None

Installer Operation

A DIF_NEWDEVICEWIZARD_PRESELECT request allows an installer to supply wizard pages that Setup displays to the user before it displays the select-driver page. This request is only used during manual installation of non-PnP devices.

If an installer adds custom preselect page(s), the installer should first check whether NumDynamicPages in the class install parameters has reached MAX_INSTALLWIZARD_DYNAPAGES.

A co-installer can add custom pages in its preprocessing pass and/or in its postprocessing pass. If it adds page(s) in its preprocessing pass, those pages are displayed before any page(s) supplied by the class installer.

If one or more installers add custom preselect pages, Setup displays the pages before the "Select a Device Driver" page. However, if the user presses "Back" on the select-driver page, Setup skips the custom preselect pages and goes back to the "Hardware Type" class-selection page.

An installer should supply a Wizard 97 header title and a header subtitle in the PROPSHEETPAGE structure for a custom wizard page. An installer should not replace the system-supplied wizard title. See the Platform SDK for documentation of the PROPSHEETPAGE structure and for more information about property pages.

For more information about DIF codes, see Handling DIF Codes.

See Also

DIF_NEWDEVICEWIZARD_PREANALYZE, DIF_NEWDEVICEWIZARD_POSTANALYZE, DIF_NEWDEVICEWIZARD_SELECT, SP_DEVINFO_DATA, SP_DEVINSTALL_PARAMS, SP_NEWDEVICEWIZARD_DATA


DIF_NEWDEVICEWIZARD_SELECT

A DIF_NEWDEVICEWIZARD_SELECT request allows an installer to supply custom wizard page(s) that replace the standard select-driver page. This request is only used during manual installation of non-PnP devices.

When Sent

Immediately before Setup displays the "Select a Device Driver" page.

Who Handles

Class Co-installer | Can handle
Device Co-installer | Does not handle
Class Installer | Can handle

Installer Input

DeviceInfoSet
Supplies a handle to the device information set containing the device.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that identifies the device in the device information set.
Device Installation Parameters
There are device installation parameters (SP_DEVINSTALL_PARAMS) associated with the DeviceInfoData.
Class Installation Parameters
An SP_NEWDEVICEWIZARD_DATA structure is associated with the DeviceInfoData.

Installer Output

Device Installation Parameters
An installer can modify the flags in the device installation parameters. Setup does not check the flags upon completion of this DIF request, but it checks them later in the installation process.
Class Installation Parameters
An installer can modify the SP_NEWDEVICEWIZARD_DATA to supply custom page(s).

Installer Return Value

If a co-installer does not handle this DIF request it returns NO_ERROR from its preprocessing pass. If a co-installer handles this request it can return NO_ERROR, ERROR_DI_POSTPROCESSING_REQUIRED, or a Win32 error code.

A class installer returns NO_ERROR if it successfully supplies page(s). Otherwise, a class installer returns ERROR_DI_DO_DEFAULT or a Win32 error code.

Default DIF Code Handler

None

Installer Operation

A DIF_NEWDEVICEWIZARD_SELECT request allows an installer to supply custom wizard page(s) that replace the standard select-driver page. This request is only used during manual installation of non-PnP devices.

An installer responds to this DIF request to completely replace the standard select-driver wizard page. If, instead, the installer only needs to modify the standard page or modify the list of drivers from which to choose, the installer should do so in response to the DIF_SELECTDEVICE request.

A co-installer should add custom page(s) in its postprocessing pass and only if the class installer did not add custom page(s). If the class installer added page(s), the co-installer should not. Otherwise, the user might be asked to choose a driver twice.

If an installer supplies a custom select page, the installer must set the selected driver. In the installer's code that supports the wizard page, after the user clicks "Next", the installer must call SetupDiSetSelectedDriver.

An installer should supply a Wizard 97 header title and a header subtitle in the PROPSHEETPAGE structure for a custom wizard page. An installer should not replace the system-supplied wizard title. See the Platform SDK for documentation of the PROPSHEETPAGE structure and for more information about property pages.

For more information about DIF codes, see Handling DIF Codes.

See Also

DIF_NEWDEVICEWIZARD_PREANALYZE, DIF_NEWDEVICEWIZARD_PRESELECT, DIF_NEWDEVICEWIZARD_POSTANALYZE, DIF_SELECTDEVICE, SetupDiSetSelectedDevice, SetupDiSetSelectedDriver, SP_DEVINFO_DATA, SP_DEVINSTALL_PARAMS, SP_NEWDEVICEWIZARD_DATA


DIF_POWERMESSAGEWAKE

A DIF_POWERMESSAGEWAKE request allows an installer to supply custom text that Setup displays on the power management properties page of the device properties.

When Sent

When a user clicks on a menu item or tab to display the properties of a device.

Setup only sends this DIF request if the drivers for the device support power management. Otherwise, Setup does not display any power properties for the device.

Who Handles

Class Co-installer | Can handle
Device Co-installer | Can handle
Class Installer | Can handle

Installer Input

DeviceInfoSet
Supplies a handle to the device information set containing the device.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that identifies the device in the device information set.
Device Installation Parameters
There are device installation parameters (SP_DEVINSTALL_PARAMS) associated with the DeviceInfoData.
Class Installation Parameters
An SP_POWERMESSAGEWAKE_PARAMS structure is associated with the DeviceInfoData.

Installer Output

Class Installation Parameters
An installer can modify the SP_POWERMESSAGEWAKE_PARAMS to supply custom text for a device's power properties page.

Installer Return Value

A co-installer typically returns NO_ERROR, ERROR_DI_POSTPROCESSING_REQUIRED, or a Win32 error code.

A class installer returns NO_ERROR if it successfully supplies power properties text. Otherwise, a class installer returns ERROR_DI_DO_DEFAULT or a Win32 error code.

Default DIF Code Handler

None

Installer Operation

A DIF_POWERMESSAGEWAKE request allows an installer to supply text that Setup displays on the power properties page for a device.

If a co-installer supplies power-properties text, it should do so in its postprocessing phase. A co-installer should take care when overwriting any power-properties text supplied by an installer that handled the request before the co-installer.

For more information about DIF codes, see Handling DIF Codes.

See Also

SP_DEVINFO_DATA, SP_DEVINSTALL_PARAMS, SP_POWERMESSAGEWAKE_PARAMS


DIF_PROPERTYCHANGE

A DIF_PROPERTYCHANGE request notifies the installer that the device's properties are changing. The device is being enabled, disabled, started, stopped, or some item on a property page has changed. This DIF request gives the installer an opportunity to participate in the change.

When Sent

When a device is being enabled, disabled, started, stopped, or its properties have changed.

For example, Setup sends this request when a property-page provider sets the DI_FLAGSEX_PROPCHANGE_PENDING flag in the FlagsEx field of the SP_DEVINSTALL_PARAMS structure for the device.

Who Handles

Class Co-installer | Can handle
Device Co-installer | Can handle
Class Installer | Can handle

Installer Input

DeviceInfoSet
Supplies a handle to the device information set containing the device.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure for the device in the device information set.
Device Installation Parameters
There are device installation parameters (SP_DEVINSTALL_PARAMS) associated with the DeviceInfoData.
Class Installation Parameters
An SP_PROPCHANGE_PARAMS structure is associated with the DeviceInfoData.

Installer Output

None

Installer Return Value

A co-installer can return NO_ERROR, ERROR_DI_POSTPROCESSING_REQUIRED, or a Win32 error code.

A class installer typically returns ERROR_DI_DO_DEFAULT or a Win32 error code. If a class installer fully handles the property change request, including calling or superseding the default handler, the class installer returns NO_ERROR.

Default DIF Code Handler

SetupDiChangeState

Installer Operation

In response to a DIF_PROPERTYCHANGE request an installer can participate in the property-change operation. The class installation parameters (SP_PROPCHANGE_PARAMS) indicate which change is taking place.

For more information about DIF codes, see Handling DIF Codes.

See Also

SetupDiChangeState, SP_DEVINFO_DATA, SP_DEVINSTALL_PARAMS, SP_PROPCHANGE_PARAMS


DIF_REGISTER_COINSTALLERS

A DIF_REGISTER_COINSTALLERS request allows an installer to participate in the registration of device-specific co-installers for a device.

When Sent

Before completing device installation.

Who Handles

Class Co-installer | Can handle
Device Co-installer | Does not handle
Class Installer | Can handle

Installer Input

DeviceInfoSet
Supplies a handle to the device information set containing the device for which co-installers are to be registered.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that identifies the device in the device information set.
Device Installation Parameters
There are device installation parameters (SP_DEVINSTALL_PARAMS) associated with the DeviceInfoData.
Class Installation Parameters
None

Installer Output

None

Installer Return Value

A co-installer can return NO_ERROR, ERROR_DI_POSTPROCESSING_REQUIRED, or a Win32 error code.

A class installer typically returns ERROR_DI_DO_DEFAULT or a Win32 error code. If a class installer fully handles the registration request, including calling or superseding the default handler, the class installer returns NO_ERROR.

Default DIF Code Handler

SetupDiRegisterCoDeviceInstallers

Installer Operation

In response to a DIF_REGISTER_COINSTALLERS request an installer might modify the list of co-installers for the device. For example, an installer might programmatically register or remove a device-specific co-installer for the device based on analysis of the device.

Unless the DI_NOFILECOPY flag is set, an installer that handles this DIF request should copy files required for the co-installer(s).

If the DI_NOFILECOPY flag is clear but the DI_NOVCP flag is set, the installer must enqueue any file operations to the supplied file queue but must not commit the queue.

If the installer returns a Win32 error code, Setup stops the installation.

For more information about DIF codes, see Handling DIF Codes.

See Also

SetupDiRegisterCoDeviceInstallers, SP_DEVINFO_DATA, SP_DEVINSTALL_PARAMS


DIF_REGISTERDEVICE

The DIF_REGISTERDEVICE request allows an installer to participate in registering a newly created device instance with the PnP Manager. Setup sends this DIF request for non-PnP devices.

When Sent

When an installer reports a previously unknown device in response to a DIF_DETECT request or if a user manually selects a device in the Add Hardware Wizard. Setup sends this DIF request in the analyze phase of the Add Hardware Wizard before it installs the device. Setup also sends this request during non-PnP detection.

Who Handles

Class Co-installer | Can handle
Device Co-installer | Does not handle
Class Installer | Can handle

Installer Input

DeviceInfoSet
Supplies a handle to the device information set containing the device.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that identifies the device in the device information set.
Device Installation Parameters
There are device installation parameters (SP_DEVINSTALL_PARAMS) associated with the DeviceInfoData.
Class Installation Parameters
None

Installer Output

None

Installer Return Value

A co-installer can return NO_ERROR or a Win32 error code. A co-installer should not return ERROR_DI_POSTPROCESSING_REQUIRED for this DIF request.

A class installer typically returns ERROR_DI_DO_DEFAULT or a Win32 error code. If a class installer completely registers the device, including performing duplicate detection, the class installer returns NO_ERROR.

If an installer determines that the device is a duplicate it returns ERROR_DUPLICATE_FOUND.

Default DIF Code Handler

SetupDiRegisterDeviceInfo

Installer Operation

A setup application typically sends this DIF request to register a non-PnP device with the PnP Manager. Non-PnP devices must be registered before they can be installed on Windows 2000 and later OS versions.

An installer typically handles this DIF request to do duplicate detection. Such an installer typically calls the default handler (SetupDiRegisterDeviceInfo) and specifies its detection routine. If the registration is successful and the installer determines that the device is not a duplicate, the installer returns NO_ERROR.

A co-installer should perform any operations to handle this DIF request in its preprocessing pass. When the co-installer is called for postprocessing, the device instance has already been registered by either the class installer or the default handler.

If an installer returns an error for this DIF code, typically ERROR_DUPLICATE_FOUND, Setup deletes the device from the device information set.

For more information about DIF codes, see Handling DIF Codes.

See Also

DIF_DETECT, SetupDiRegisterDeviceInfo, SP_DEVINFO_DATA, SP_DEVINSTALL_PARAMS


DIF_REMOVE

A DIF_REMOVE request notifies an installer that Setup is about to remove a device and gives the installer an opportunity to prepare for the removal.

When Sent

When a user removes a device in the Device Manager or in the Add Hardware Wizard.

Who Handles

Class Co-installer | Can handle
Device Co-installer | Can handle
Class Installer | Can handle

Installer Input

DeviceInfoSet
Supplies a handle to the device information set containing the device to be removed.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure for the device in the device information set.
Device Installation Parameters
There are device installation parameters (SP_DEVINSTALL_PARAMS) associated with the DeviceInfoData.
Class Installation Parameters
An SP_REMOVEDEVICE_PARAMS structure might be associated with the DeviceInfoData.

There are no class installation parameters for the request if the DI_CLASSINSTALLPARAMS flag is clear in the SP_DEVINSTALL_PARAMS. In this case, no hardware profile is specified and the device is to be removed from the system as a whole.

Installer Output

None

Installer Return Value

A co-installer can return NO_ERROR, ERROR_DI_POSTPROCESSING_REQUIRED, or a Win32 error code.

A class installer typically returns ERROR_DI_DO_DEFAULT or a Win32 error code. If a class installer fully handles this request, including calling or superseding the default handler, the class installer returns NO_ERROR.

Default DIF Code Handler

SetupDiRemoveDevice

Installer Operation

In response to a DIF_REMOVE request, an installer typically performs some clean-up operations. In this case, a co-installer returns NO_ERROR and a class installer returns ERROR_DI_DO_DEFAULT.

If an installer determines that the device should not be removed, the installer fails the DIF request by returning a Win32 error code. If the DI_QUIETINSTALL flag is clear, the installer should display a message to the user explaining why the device is not being removed.

Co-installers must not attempt to remove the device themselves by calling SetupDiRemoveDevice. Co-installers typically handle this request in postprocessing, after the device has been successfully removed.

If a co-installer needs to delete information in the registry, for example, the co-installer should do so in postprocessing and only if the previous installers succeeded the removal request. In its preprocessing pass, the co-installer should store the registry information in its context parameter and return ERROR_DI_POSTPROCESSING_REQUIRED to request postprocessing. When Setup calls the co-installer for postprocessing of this DIF request, the co-installer should check that the DIF status is NO_ERROR and then delete the registry information. If a co-installer deletes registry information in its preprocessing pass and the class installer (or another co-installer) fails the DIF_REMOVE, the co-installer could leave the device in an unpredictable state.

Installers should not delete files when handling this DIF request, in case the files are in use by another device.

Setup sends this DIF request before it initiates PnP query-remove and remove processing.

For more information about DIF codes, see Handling DIF Codes.

See Also

SetupDiRemoveDevice, SP_DEVINFO_DATA, SP_DEVINSTALL_PARAMS, SP_REMOVEDEVICE_PARAMS


DIF_SELECTBESTCOMPATDRV

A DIF_SELECTBESTCOMPATDRV request allows an installer to select the best driver from the device information element's compatible driver list.

When Sent

When the OS is preparing to install a new PnP device or is performing a change-driver operation on a PnP device.

This DIF request is typically used during a PnP configuration. If a device is being manually installed, Setup sends a DIF_SELECTDEVICE request.

Who Handles

Class Co-installer | Can handle
Device Co-installer | Does not handle
Class Installer | Can handle

Installer Input

DeviceInfoSet
Supplies a handle to the device information set containing the device.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that identifies the device in the device information set.
Device Installation Parameters
There are device installation parameters (SP_DEVINSTALL_PARAMS) associated with the DeviceInfoData.
Class Installation Parameters
None

Installer Output

Device Installation Parameters
An installer can modify the device installation parameters, but they typically do not when handling this DIF request.
DeviceInfoData
As a side effect, an installer can modify the driver list associated with the DeviceInfoData, in particular, the SP_DRVINSTALL_PARAMS.

Installer Return Value

A co-installer can return NO_ERROR, ERROR_DI_POSTPROCESSING_REQUIRED, or a Win32 error code.

A class installer typically returns ERROR_DI_DO_DEFAULT or a Win32 error code. In some cases, a class installer returns NO_ERROR.

Default DIF Code Handler

SetupDiSelectBestCompatDrv

Installer Operation

An installer handles this DIF request to participate in selecting a driver for a PnP device. An installer typically responds to this DIF request in one of the following ways:

  • Do nothing.

    If an installer has no special selection requirements, it does nothing in response to this DIF request. A class installer returns ERROR_DI_DO_DEFAULT and a co-installer returns NO_ERROR.

  • Modify the parameters of one or more drivers in the driver list.

    For example, an installer might remove a driver from consideration for the device by marking it DNF_BAD_DRIVER. An installer modifies driver parameters with a procedure like the following:

    1. Get the information about the first driver in the list by calling SetupDiEnumDriverInfo and SetupDiGetDriverInstallParams. If appropriate, modify the driver parameters and apply the change by calling SetupDiSetDriverInstallParams.

      If a driver is a worst-case choice, set the driver's rank to 0xFFFF or higher in the driver install parameters. See How Setup Selects Drivers for more information.

    2. Repeat the previous step until you have processed all the drivers in the list. Be sure to increment the MemberIndex parameter to SetupDiEnumDriverInfo as described in the reference page for that function.

    After a class installer modifies the driver list, it returns ERROR_DI_DO_DEFAULT. If a co-installer modifies the driver list, it should do so in preprocessing and return NO_ERROR.

  • Select the best driver for the device.

    This action is less common, but an installer might choose the best driver for the device. Such an installer would examine the data for each driver, choose a driver, and call SetupDiSetSelectedDriver to set the driver. After an installer sets the selected driver, it returns NO_ERROR.

    If a co-installer selects a driver, it should do so in postprocessing.

For more information about DIF codes, see Handling DIF Codes.

See Also

SetupDiSelectBestCompatDrv, SetupDiSetSelectedDriver, SP_DEVINFO_DATA, SP_DEVINSTALL_PARAMS


DIF_SELECTDEVICE

A DIF_SELECTDEVICE request allows an installer to participate in selecting the driver for a device.

When Sent

When choosing a driver for a newly enumerated device or a new driver for an existing device (change driver). For example, when a user selects Add/Remove Hardware and selects the modem class. Or, a user inserts a PnP device and selects "Choose a Driver From a List" in the Found New Hardware Wizard.

Who Handles

Class Co-installer | Can handle
Device Co-installer | Does not handle
Class Installer | Can handle

Installer Input

DeviceInfoSet
Supplies a handle to the device information set containing the device for which a driver is to be selected.
Associated Class
There is a device setup class associated with the DeviceInfoSet.
DeviceInfoData
Optionally supplies a pointer to an SP_DEVINFO_DATA structure that identifies the device in the device information set.

If DeviceInfoData is NULL, this request is to select a driver for the device setup class associated with the DeviceInfoSet.

Device Installation Parameters
If DeviceInfoData is not NULL, there are device installation parameters (SP_DEVINSTALL_PARAMS) associated with the DeviceInfoData. If DeviceInfoData is NULL, there are device installation parameters associated with the DeviceInfoSet.

Of particular interest is the DriverPath, which contains the location of INF(s) to use when building the driver list.

Class Installation Parameters
An SP_SELECTDEVICE_PARAMS structure is associated with the DeviceInfoData if DeviceInfoData is not NULL. Otherwise, the class installation parameters are associated with the device information set as a whole.

Installer Output

Device Installation Parameters
An installer can modify the device installation parameters, but it should not modify the DriverPath field.
Class Installation Parameters
An installer can modify the SP_SELECTDEVICE_PARAMS. For example, an installer might specify a title and/or instructions for Setup to use in the dialog box that asks the user to select a driver.

If an installer sets new select-device parameters, versus modifying parameters set by a previous installer, the installer must zero the fields it does not set.

Installer Return Value

If a co-installer does nothing for this DIF code, it returns NO_ERROR from its preprocessing pass. If a co-installer handles this DIF code, it should do so in its preprocessing pass and return NO_ERROR or a Win32 error code. By the time a co-installer is called for postprocessing, the driver has already been selected.

A class installer returns ERROR_DI_DO_DEFAULT, a Win32 error code, or NO_ERROR.

If an installer builds and modifies the driver list, it returns ERROR_DI_BAD_PATH if SP_DEVINSTALL_PARAMS.DriverPath is not NULL yet there are no valid drivers at that location. This can be true if there are no drivers at that location or if there are drivers, but only ones that the installer marks DNF_BAD_DRIVER. In response to this error code, Setup displays an error to the user.

Default DIF Code Handler

SetupDiSelectDevice

Installer Operation

In response to a DIF_SELECTDEVICE request, an installer performs any selection operations required for its device or device class, besides what the default handler does. An installer typically responds to this DIF request in one of the following ways:

  • Do nothing.

    If an installer has no special selection requirements, it does nothing in response to this DIF code. A class installer returns ERROR_DI_DO_DEFAULT and a co-installer returns NO_ERROR.

  • Supply select strings that Setup will display in the selection UI.

    An installer can supply select strings in the class installation parameters (SP_SELECTDEVICE_PARAMS). For example, an installer can modify the Instructions or the window header Title.

    A class installer should not supply select strings if a co-installer already supplied select strings. The co-installer probably has more relevant information.

    If an installer modifies the SP_SELECTDEVICE_PARAMS, the installer must also set the DI_USECI_SELECTSTRINGS flag in the SP_DEVINSTALL_PARAMS.

    If an installer successfully supplies select strings, Setup still needs to call the default handler. Therefore, in this case, a co-installer returns NO_ERROR and a class installer returns ERROR_DI_DO_DEFAULT.

  • Modify the device installation parameters.

    An installer can modify the device installation parameters (SP_DEVINSTALL_PARAMS). For example, an installer might set the DI_SHOWOEM flag to have Setup display the Have Disk button.

    If a class installer successfully modifies the device installation parameters, the class installer returns ERROR_DI_DO_DEFAULT.

  • Modify the list of drivers from which the user can select.

    This action is less common, but possible. An installer that modifies the driver list might, or might not, also supply select strings.

    An installer that modifies the driver list typically marks driver(s) that are inappropriate for the device. An installer marks such drivers with the flag DNF_BAD_DRIVER. Setup omits these drivers from the list it displays to the user. An installer marks bad drivers with a procedure like the following:

    1. Build the driver list by calling SetupDiBuildDriverInfoList with a DriverType of SPDIT_CLASSDRIVER.
    2. Get the information about the first driver in the list by calling SetupDiEnumDriverInfo and SetupDiGetDriverInstallParams. If the driver is not appropriate for the device, set the DNF_BAD_DRIVER flag in the Flags field of the parameters. Apply the change to the parameters by calling SetupDiSetDriverInstallParams.
    3. Repeat the previous step until you have processed all the drivers in the list. Be sure to increment the MemberIndex parameter to SetupDiEnumDriverInfo as described in the reference page for that function.

    An installer might set the DNF_BAD_DRIVER flag for one or more drivers in the driver list, but an installer must not clear that flag.

    If one or more installers successfully modify the driver list, Setup still needs to call the default handler. Therefore, in this case, a co-installer returns NO_ERROR and a class installer returns ERROR_DI_DO_DEFAULT.

  • Display its own driver-selection user interface and set the selected driver.

    Only a class installer can display its own driver-selection user interface; co-installers must not. For example, a class installer might display pictures instead of textual lists.

    If the class installer successfully sets the selected driver, the class installer returns NO_ERROR and Setup does not call the default handler and therefore does not display the default selection interface.

    If a class installer only needs to display its own interface during the Add Hardware Wizard, the class installer should handle the DIF_NEWDEVICEWIZARD_SELECT request instead of this request.

If the DI_ENUMSINGLEINF flag is set in the device installation parameters, the DriverPath is a path to a single INF instead of a path to a directory. An installer must use only that single INF to build the driver list.

For more information about DIF codes, see Handling DIF Codes.

See Also

DIF_NEWDEVICEWIZARD_SELECT, SetupDiSelectDevice, SP_DEVINFO_DATA, SP_DEVINSTALL_PARAMS, SP_SELECTDEVICE_PARAMS


DIF_TROUBLESHOOTER

The DIF_TROUBLESHOOTER request allows an installer to launch a troubleshooter for a device or to return CHM and HTM troubleshooter files for Setup to launch.

When Sent

When a user clicks the "Troubleshooter" button for a device in the Device Manager.

Who Handles

Class Co-installer | Can handle
Device Co-installer | Can handle
Class Installer | Can handle

Installer Input

DeviceInfoSet
Supplies a handle to the device information set containing the device.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that identifies the device in the device information set.
Device Installation Parameters
There are device installation parameters (SP_DEVINSTALL_PARAMS) associated with the DeviceInfoData.
Class Installation Parameters
An SP_TROUBLESHOOTER_PARAMS structure is associated with the DeviceInfoData.

Installer Output

Class Installation Parameters
An installer might modify the SP_TROUBLESHOOTER_PARAMS, setting a CHM or HTML file.

Installer Return Value

If a co-installer does not handle this request, it returns NO_ERROR from its preprocessing pass.

If a co-installer handles this request, it does so in its postprocessing pass. If the co-installer supplies CHM and HTML files, it propagates the status it received (probably ERROR_DI_DO_DEFAULT). If the co-installer runs a troubleshooter and fixes the problem, the co-installer returns NO_ERROR. If the co-installer runs a troubleshooter but does not fix the problem, it propagates the status it received (ERROR_DI_DO_DEFAULT).

If a class installer launches its own troubleshooter and fixes the problem, the class installer returns NO_ERROR. If a class installer supplies a CHM file and an HTML file or the class installer runs a troubleshooter but does not fix the problem, the class installer returns ERROR_DI_DO_DEFAULT.

If an installer encounters an error when handling this DIF code, the installer returns an appropriate Win32 error code.

Default DIF Code Handler

None

There is no default handler for DIF_TROUBLESHOOTER, but the OS provides default troubleshooters that attempt to resolve device problems if there are no installer-supplied troubleshooters.

Installer Operation

An installer calls CM_Get_DevNode_Status to get the device status and the CM problem code. Depending on the problem, an installer might provide a troubleshooter, a help file, or nothing. A troubleshooter can possibly resolve a problem with a device. If a troubleshooter resolves the problem, it should call SetupDiCallClassInstaller to send a DIF_PROPERTYCHANGE request of type DICS_PROPCHANGE. If an installer does not supply a troubleshooter for a device, it might supply a help file of problem-solving suggestions for the user.

If no installer runs its own troubleshooter, Setup runs HTML Help to display information to the user. If an installer supplied a CHM file in the class installation parameters, Setup displays that file. Otherwise, Setup displays system-supplied troubleshooting information.

The class installation parameters contain at most one ChmFile and HtmlTroubleshooter pair. If more than one installer specifies these values, Setup uses the values set by the last installer that handled the DIF request.

For more information about DIF codes, see Handling DIF Codes.

See Also

CM_Get_DevNode_Status, SP_DEVINFO_DATA, SP_DEVINSTALL_PARAMS, SP_TROUBLESHOOTER_PARAMS


DIF_UNREMOVE

A DIF_UNREMOVE request notifies the installer that Setup is about to reinstate a device in a given hardware profile and gives the installer an opportunity to participate in the operation. Setup only sends this request for non-PnP devices.

When Sent

When a root-enumerated, non-PnP device is reinstated to a hardware profile.

Who Handles

Class Co-installer | Can handle
Device Co-installer | Can handle
Class Installer | Can handle

Installer Input

DeviceInfoSet
Supplies a handle to the device information set containing the device.
DeviceInfoData
Supplies a pointer to an SP_DEVINFO_DATA structure that identifies the device in the device information set.
Device Installation Parameters
There are device installation parameters (SP_DEVINSTALL_PARAMS) associated with the DeviceInfoData.
Class Installation Parameters
An SP_UNREMOVEDEVICE_PARAMS structure is associated with the DeviceInfoData. The Scope field must be set to DI_UNREMOVEDEVICE_CONFIGSPECIFIC and a hardware profile must be specified in the HwProfile field.

Installer Output

None

Installer Return Value

A co-installer can return NO_ERROR, ERROR_DI_POSTPROCESSING_REQUIRED, or a Win32 error code.

A class installer typically returns ERROR_DI_DO_DEFAULT or a Win32 error code. In some cases, a class installer returns NO_ERROR.

Default DIF Code Handler

SetupDiUnRemoveDevice

Installer Operation

"Unremoving" a device essentially means that Setup clears a flag that previously marked a device as "not present" in a particular hardware profile.

For more information about DIF codes, see Handling DIF Codes.

See Also

SetupDiUnRemoveDevice, SP_DEVINFO_DATA, SP_DEVINSTALL_PARAMS, SP_UNREMOVEDEVICE_PARAMS


Reserved DIF Codes

The DIF codes listed in this section are reserved for system use. Vendor-supplied installers should not handle or send these requests.


DIF_ADDPROPERTYPAGE_BASIC

This DIF request is reserved for system use. Vendor-supplied installers must not handle this request.


DIF_ASSIGNRESOURCES

This DIF request is reserved for system use. Vendor-supplied installers must not handle this request.


DIF_CALCDISKSPACE

This DIF request is reserved for system use. Vendor-supplied installers must not handle this request.


DIF_DETECTCANCEL

This DIF request is reserved for system use. Vendor-supplied installers must not handle this request.


DIF_DETECTVERIFY

This DIF request is reserved for system use. Vendor-supplied installers must not handle this request.


DIF_ENABLECLASS

This DIF request is reserved for system use. Vendor-supplied installers must not handle this request.


DIF_FIRSTTIMESETUP

A DIF_FIRSTTIMESETUP request directs an installer to carry out any class-specific installation tasks that need to be completed during the initial installation of the operating system.

This DIF request is reserved. Only system-supplied installers are allowed to handle this DIF request.

When Sent

During GUI-mode setup.

Who Handles

Class Co-installer | Can handle
Device Co-installer | Does not handle
Class Installer | Can handle

Installer Input

DeviceInfoSet
Supplies a handle to the device information set.
Associated Class
There is a device setup class associated with the DeviceInfoSet.
DeviceInfoData
None
Device Installation Parameters
There are device installation parameters (SP_DEVINSTALL_PARAMS) associated with the DeviceInfoSet.
Class Installation Parameters
None

Installer Output

DeviceInfoSet
An installer adds a device information element to the DeviceInfoSet for each detected device it wants to have installed. An installer might also build a global class driver list.
Device Installation Parameters
An installer can modify the device installation parameters for the DeviceInfoSet or for new device information elements it creates.

Installer Return Value

A class co-installer can detect devices during pre- or postprocessing. Such a co-installer returns ERROR_DI_POSTPROCESSING_REQUIRED (for postprocessing) and/or returns NO_ERROR or a Win32 error code after its detection operations. If a co-installer does not detect devices, it returns NO_ERROR from its preprocessing pass.

If a class installer detects devices, it returns NO_ERROR or an appropriate Win32 error code. If a class installer does not handle this DIF request, it returns ERROR_DI_DO_DEFAULT.

Default DIF Code Handler

None

Installer Operation

GUI-mode setup sends a DIF_FIRSTTIMESETUP request with an empty DeviceInfoSet. The installers can perform legacy detection of non-PnP devices and add them to the DeviceInfoSet. System-supplied installers can also handle this DIF request when migrating legacy device installations from Windows 9x or Windows NT® to Windows 2000 and later.

An installer detects new devices of its setup class, based on registry information, by calling into a kernel-mode detection component, or by consulting unattend.txt information stored when a migration DLL ran during an OS upgrade.

If an installer detects a non-PnP device, the installer should select a driver for the device as follows: create a device information element (SetupDiCreateDeviceInfo), set the SPDRP_HARDWAREID property by calling SetupDiSetDeviceRegistryProperty, call SetupDiBuildDriverInfoList, and then call SetupDiCallClassInstaller to send a DIF_SELECTBESTCOMPATDRV request.

If one or more installers detect device(s) in response to this DIF code, GUI-mode setup attempts to install the device(s). GUI-mode setup attempts to install all devices in the list; if an installer returns a device that was previously configured, GUI-mode setup will install the device twice.

An installer must handle this DIF request silently. That is, without displaying UI to the user.

Installers should not perform tasks when handling this DIF request that require the machine to be rebooted. For example, a class installer should not set drivers to load at the next boot for the purpose of determining which drivers succeed after the reboot.

To detect non-PnP devices during GUI-mode setup, an installer must handle this request. GUI-mode setup does not send a DIF_DETECT request.

For more information about DIF codes, see Handling DIF Codes.

See Also

DIF_SELECTBESTCOMPATDRV, SetupDiBuildDriverInfoList, SetupDiCallClassInstaller, SetupDiCreateDeviceInfo, SetupDiSetDeviceRegistryProperty, SP_DEVINFO_DATA, SP_DEVINSTALL_PARAMS


DIF_FOUNDDEVICE

This DIF request is reserved for system use. Vendor-supplied installers must not handle this request.


DIF_INSTALLCLASSDRIVERS

This DIF request is reserved for system use. Vendor-supplied installers must not handle this request.


DIF_MOVEDEVICE

This DIF request is reserved for system use. Vendor-supplied installers must not handle this request.


DIF_UPDATEDRIVER_UI

This DIF request is reserved for system use. Vendor-supplied installers must not handle this request.


Obsolete DIF Codes

The DIF codes listed in this section are obsolete. Vendor-supplied installers should not handle or send these requests.


DIF_DESTROYWIZARDDATA

This DIF code is obsolete.

Setup uses the DIF_NEWDEVICEWIZARD_XXX requests instead, such as DIF_NEWDEVICEWIZARD_FINISHINSTALL.


DIF_INSTALLWIZARD

This DIF code is obsolete.

For PnP devices, Setup uses the DIF_NEWDEVICEWIZARD_XXX requests instead, such as DIF_NEWDEVICEWIZARD_FINISHINSTALL.


DIF_PROPERTIES

This DIF code is obsolete.

To supply custom property pages for a device an installer handles the DIF_ADDPROPERTYPAGE_ADVANCED request.


DIF_SELECTCLASSDRIVERS

This DIF code is obsolete.


DIF_VALIDATECLASSDRIVERS

This DIF code is obsolete.


DIF_VALIDATEDRIVER

This DIF code is obsolete.


PnP Configuration Manager Functions

This section describes PnP Configuration Manager functions, which can be called by class installers, co-installers, and additional installation applications running under the NT-based operating system. These functions are typically used in conjunction with device installation functions. Function prototypes are defined in cfgmgr32.h. Additional definitions are in cfg.h.


CM_Add_Empty_Log_Conf

The CM_Add_Empty_Log_Conf function creates an empty logical configuration, for a specified configuration type and a specified device instance, on the local system.

CMAPI CONFIGRET WINAPI
  CM_Add_Empty_Log_Conf(
    OUT PLOG_CONF  plcLogConf,
    IN DEVINST  dnDevInst,
    IN PRIORITY  Priority,
    IN ULONG  ulFlags
    );

Parameters

plcLogConf
Address of a location to receive the handle to an empty logical configuration.
dnDevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Locate_DevNode
CM_Locate_DevNode_Ex
CM_Get_Child
CM_Get_Child_Ex
CM_Get_Parent
CM_Get_Parent_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

Priority
Caller-supplied configuration priority value. This must be one of the constant values listed in the following table. The constants are listed in order of priority, from highest to lowest. (For multiple configurations with the same ulFlags value, the system will attempt to use the one with the highest priority first.)
Priority Constant | Definition
LCPRI_FORCECONFIG | Result of a forced configuration.
LCPRI_BOOTCONFIG | Result of a boot configuration.
LCPRI_DESIRED | Preferred configuration (better performance).
LCPRI_NORMAL | Workable configuration (acceptable performance).
LCPRI_LASTBESTCONFIG | For internal use only.
LCPRI_SUBOPTIMAL | Not a desirable configuration, but it will work.
LCPRI_LASTSOFTCONFIG | For internal use only.
LCPRI_RESTART | The system must be restarted
LCPRI_REBOOT | The system must be restarted (same as LCPRI_RESTART).
LCPRI_POWEROFF | The system must be shut down and powered off.
LCPRI_HARDRECONFIG | A jumper must be changed.
LCPRI_HARDWIRED | The configuration cannot be changed.
LCPRI_IMPOSSIBLE | The configuration cannot exist.
LCPRI_DISABLED | Disabled configuration.

ulFlags
Caller-supplied flags that specify the type of the logical configuration. One of the following flags must be specified.
Configuration Type Flags | Definitions
BASIC_LOG_CONF | Resource descriptors added to this configuration will describe a basic configuration.
FILTERED_LOG_CONF | Do not use. (Only the PnP manager can create a filtered configuration.)
ALLOC_LOG_CONF | Do not use. (Only the PnP manager can create an allocated configuration.)
BOOT_LOG_CONF | Resource descriptors added to this configuration will describe a boot configuration.
FORCED_LOG_CONF | Resource descriptors added to this configuration will describe a forced configuration.
OVERRIDE_LOG_CONF | Resource descriptors added to this configuration will describe an override configuration.

One of the following bit flags can be OR'ed with the configuration type flag.
Priority Comparison Flags | Definitions
PRIORITY_EQUAL_FIRST | If multiple configurations of the same type (ulFlags) have the same priority (Priority), this configuration is placed at the head of the list.
PRIORITY_EQUAL_LAST | (Default) If multiple configurations of the same type (ulFlags) have the same priority (Priority), this configuration is placed at the tail of the list.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

Calling CM_Add_Empty_Log_Conf can cause the handles returned by CM_Get_First_Log_Conf and CM_Get_Next_Log_Conf to become invalid. Thus if you want to obtain logical configurations after calling CM_Add_Empty_Log_Conf, your code must call CM_Get_First_Log_Conf again and start at the first configuration.

To remove a logical configuration created by CM_Add_Empty_Log_Conf, call CM_Free_Log_Conf.

The handle received in plcLogConf must be explicitly freed by calling CM_Free_Log_Conf_Handle.

Callers of this function must have SeLoadDriverPrivilege. (Privileges are described in Platform SDK documentation.)

See Also

CM_Add_Empty_Log_Conf_Ex


CM_Add_Empty_Log_Conf_Ex

The CM_Add_Empty_Log_Conf_Ex function creates an empty logical configuration, for a specified configuration type and a specified device instance, on either the local or a remote system.

CMAPI CONFIGRET WINAPI
  CM_Add_Empty_Log_Conf_Ex(
    OUT PLOG_CONF  plcLogConf,
    IN DEVINST  dnDevInst,
    IN PRIORITY  Priority,
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

plcLogConf
Pointer to a location to receive the handle to an empty logical configuration.
dnDevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Locate_DevNode
CM_Locate_DevNode_Ex
CM_Get_Child
CM_Get_Child_Ex
CM_Get_Parent
CM_Get_Parent_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

Priority
Caller-supplied configuration priority value. For a list of values, see the Priority description for CM_Add_Empty_Log_Conf.
ulFlags
Caller-supplied flags that specify the type of the logical configuration. For a list of flags, see the description ulFlags description for CM_Add_Empty_Log_Conf.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine, or NULL.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

Calling CM_Add_Empty_Log_Conf_Ex can cause the handles returned by CM_Get_First_Log_Conf_Ex and CM_Get_Next_Log_Conf_Ex to become invalid. Thus if you want to obtain logical configurations after calling CM_Add_Empty_Log_Conf_Ex, your code must call CM_Get_First_Log_Conf_Ex again and start at the first configuration.

To remove a logical configuration created by CM_Add_Empty_Log_Conf_Ex, call CM_Free_Log_Conf_Ex.

The handle received in plcLogConf must be explicitly freed by calling CM_Free_Log_Conf_Handle.

Callers of this function must have SeLoadDriverPrivilege. (Privileges are described in Platform SDK documentation.)

See Also

CM_Add_Empty_Log_Conf


CM_Add_ID

The CM_Add_ID function appends a specified device ID (if not already present) to a device instance's hardware ID list or compatible ID list.

CMAPI CONFIGRET WINAPI
  CM_Add_ID(
    IN DEVINST  dnDevInst,
    IN PTSTR  pszID,
    IN ULONG  ulFlags
    );

Parameters

dnDevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Locate_DevNode
CM_Locate_DevNode_Ex
CM_Get_Child
CM_Get_Child_Ex
CM_Get_Parent
CM_Get_Parent_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

pszID
Caller-supplied pointer to a NULL-terminated device ID string.
ulFlags
Caller-supplied flag constant indicating the list onto which the supplied device ID should be appended. The following flag constants are valid.
Flag Constant | Definition
CM_ADD_ID_COMPATIBLE | The specified device ID should be appended to the specific device instance's compatible ID list.
CM_ADD_ID_HARDWARE | The specified device ID should be appended to the specific device instance's hardware ID list.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

Each appended device ID is considered less compatible than IDs already existing in the specified list.Callers of this function must have SeLoadDriverPrivilege. (Privileges are described in Platform SDK documentation.)

See Also

CM_Add_ID_Ex
SetupDiSetDeviceRegistryProperty


CM_Add_ID_Ex

The CM_Add_ID_Ex function appends a device ID (if not already present) to a device instance's hardware ID list or compatible ID list, on either the local or a remote system.

CMAPI CONFIGRET WINAPI
  CM_Add_ID(
    IN DEVINST  dnDevInst,
    IN PTSTR  pszID,
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

dnDevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Locate_DevNode
CM_Locate_DevNode_Ex
CM_Get_Child
CM_Get_Child_Ex
CM_Get_Parent
CM_Get_Parent_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

pszID
Caller-supplied pointer to a NULL-terminated device ID string.
ulFlags
Caller-supplied flag constant indicating the list onto which the supplied device ID should be appended. The following flag constants are valid.
Flag Constant | Definition
CM_ADD_ID_COMPATIBLE | The specified device ID should be appended to the specific device instance's compatible ID list.
CM_ADD_ID_HARDWARE | The specified device ID should be appended to the specific device instance's hardware ID list.

hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine, or NULL.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

Each appended device ID is considered less compatible than IDs already existing in the specified list.

Callers of this function must have SeLoadDriverPrivilege. (Privileges are described in Platform SDK documentation.)

See Also

CM_Add_ID
SetupDiSetDeviceRegistryProperty


CM_Add_Range

Do not use this function. Use device installation functions instead.


CM_Add_Res_Des

The CM_Add_Res_Des function adds a resource descriptor to a logical configuration.

CMAPI CONFIGRET WINAPI
  CM_Add_Res_Des(
    OUT PRES_DES  prdResDes,
    IN LOG_CONF  lcLogConf,
    IN RESOURCEID  ResourceID,
    IN PCVOID  ResourceData,
    IN ULONG  ResourceLen,
    IN ULONG  ulFlags
    );

Parameters

prdResDes
Pointer to a location to receive a handle to the new resource descriptor.
lcLogConf
Caller-supplied handle to the logical configuration to which the resource descriptor should be added. This handle must have been previously obtained by calling one of the following functions:

CM_Add_Empty_Log_Conf
CM_Add_Empty_Log_Conf_Ex
CM_Get_First_Log_Conf
CM_Get_First_Log_Conf_Ex
CM_Get_Next_Log_Conf
CM_Get_Next_Log_Conf_Ex

ResourceID
Caller-supplied resource type identifier, which identifies the type of structure supplied by ResourceData. This must be one of the ResType_-prefixed constants defined in cfgmgr32.h.
ResourceData
Caller-supplied pointer to one of the resource structures listed in the following table.
ResourceID Parameter | Resource Structure
ResType_BusNumber | BUSNUMBER_RESOURCE
ResType_ClassSpecific | CS_RESOURCE
ResType_DevicePrivate | DEVPRIVATE_RESOURCE
ResType_DMA | DMA_RESOURCE
ResType_IO | IO_RESOURCE
ResType_IRQ | IRQ_RESOURCE
ResType_Mem | MEM_RESOURCE
ResType_MfCardConfig | MFCARD_RESOURCE
ResType_PcCardConfig | PCCARD_RESOURCE

ResourceLen
Caller-supplied length of the structure pointed to by ResourceData.
ulFlags
Not used, must be zero.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

Callers of CM_Add_Res_Des must call CM_Free_Res_Des_Handle to deallocate the resource descriptor handle, after it is no longer needed.

Callers of this function must have SeLoadDriverPrivilege. (Privileges are described in Platform SDK documentation.)

See Also

CM_Add_Res_Des_Ex, CM_Free_Res_Des_Handle


CM_Add_Res_Des_Ex

The CM_Add_Res_Des_Ex function adds a resource descriptor to a logical configuration, on either the local or a remote system.

CMAPI CONFIGRET WINAPI
  CM_Add_Res_Des_Ex(
    OUT PRES_DES  prdResDes,
    IN LOG_CONF  lcLogConf,
    IN RESOURCEID  ResourceID,
    IN PCVOID  ResourceData,
    IN ULONG  ResourceLen,
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

prdResDes
Pointer to a location to receive a handle to the new resource descriptor.
lcLogConf
Caller-supplied handle to the logical configuration to which the resource descriptor should be added. This handle must have been previously obtained by calling one of the following functions:

CM_Add_Empty_Log_Conf
CM_Add_Empty_Log_Conf_Ex
CM_Get_First_Log_Conf
CM_Get_First_Log_Conf_Ex
CM_Get_Next_Log_Conf
CM_Get_Next_Log_Conf_Ex

ResourceID
Caller-supplied resource type identifier, which identifies the type of structure supplied by ResourceData. This must be one of the ResType_-prefixed constants defined in cfgmgr32.h.
ResourceData
Caller-supplied pointer to one of the resource structures listed in the following table.
ResourceID Parameter | Resource Structure
ResType_BusNumber | BUSNUMBER_RESOURCE
ResType_ClassSpecific | CS_RESOURCE
ResType_DevicePrivate | DEVPRIVATE_RESOURCE
ResType_DMA | DMA_RESOURCE
ResType_IO | IO_RESOURCE
ResType_IRQ | IRQ_RESOURCE
ResType_Mem | MEM_RESOURCE
ResType_MfCardConfig | MFCARD_RESOURCE
ResType_PcCardConfig | PCCARD_RESOURCE

ResourceLen
Caller-supplied length of the structure pointed to by ResourceData.
ulFlags
Not used, must be zero.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine, or NULL.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

Callers of CM_Add_Res_Des_Ex must call CM_Free_Res_Des_Handle to deallocate the resource descriptor handle, after it is no longer needed.

Callers of this function must have SeLoadDriverPrivilege. (Privileges are described in Platform SDK documentation.)

See Also

CM_Add_Res_Des, CM_Free_Res_Des_Handle


CM_Connect_Machine

The CM_Connect_Machine function creates a connection to a remote system.

CMAPI CONFIGRET WINAPI
  CM_Connect_Machine(
    IN PCTSTR  UNCServerName,
    OUT PHMACHINE  phMachine
    );

Parameters

UNCServerName
Caller-supplied pointer to a text string representing the UNC name, including the \\ prefix, of the system for which a connection will be made. If the pointer is NULL, the local system is used.
phMachine
Address of a location to receive a machine handle.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

Callers of CM_Connect_Machine must call CM_Disconnect_Machine to deallocate the machine handle, after it is no longer needed.


CM_Create_DevNode

Do not use this function. Use device installation functions instead.


CM_Create_DevNode_Ex

Do not use this function. Use device installation functions instead.


CM_Create_Range_List

Do not use this function. Use device installation functions instead.


CM_Delete_Class_Key

Do not use this function. Use device installation functions instead.


CM_Delete_Class_Key_Ex

Do not use this function. Use device installation functions instead.


CM_Delete_DevNode_Key_Ex

Do not use this function. Use device installation functions instead.


CM_Delete_Range

Do not use this function. Use device installation functions instead.


CM_Detect_Resource_Conflict

Do not use this function. Use device installation functions instead.


CM_Detect_Resource_Conflict_Ex

Do not use this function. Use device installation functions instead.


CM_Disable_Devnode

Do not use this function. Use device installation functions instead.


CM_Disable_Devnode_Ex

Do not use this function. Use device installation functions instead.


CM_Disconnect_Machine

The CM_Disconnect_Machine function removes a connection to a remote system.

CMAPI CONFIGRET WINAPI
  CM_Disconnect_Machine(
    IN HMACHINE  hMachine
    );

Parameters

hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.


CM_Enable_DevNode

Do not use this function. Use device installation functions instead.


CM_Enable_DevNode_Ex

Do not use this function. Use device installation functions instead.


CM_Enumerate_Classes

The CM_Enumerate_Classes function, when called repeatedly, enumerates the local system's installed device classes by supplying each class's GUID.

CMAPI CONFIGRET WINAPI
  CM_Enumerate_Classes(
    IN ULONG  ulClassIndex,
    OUT LPGUID  ClassGuid,
    IN ULONG  ulFlags
    );

Parameters

ulClassIndex
Caller-supplied index into the system's list of device classes. For more information, see the following Comments section.
ClassGuid
Caller-supplied address of a GUID structure (described in the Platform SDK) to receive a device class's GUID.
ulFlags
Not used, must be zero.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

To enumerate the local system's device classes, call CM_Enumerate_Classes repeatedly, starting with a ulClassIndex value of zero and incrementing the index value with each subsequent call until the function returns CR_NO_SUCH_VALUE. Some index values might represent list entries containing invalid class data, in which case the function returns CR_INVALID_DATA. This return value can be ignored.

The class GUIDs obtained from this function can be used as input to the device installation functions.

See Also

CM_Enumerate_Classes_Ex


CM_Enumerate_Classes_Ex

The CM_Enumerate_Classes_Ex function, when called repeatedly, enumerates a local or remote system's installed device classes, by supplying each class's GUID.

CMAPI CONFIGRET WINAPI
  CM_Enumerate_Classes_Ex(
    IN ULONG  ulClassIndex,
    OUT LPGUID  ClassGuid,
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

ulClassIndex
Caller-supplied index into the system's list of device classes. For more information, see the following Comments section.
ClassGuid
Caller-supplied address of a GUID structure (described in the Platform SDK) to receive a device class's GUID.
ulFlags
Not used, must be zero.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

To enumerate the local or remote system's device classes, call CM_Enumerate_Classes_Ex repeatedly, starting with a ulClassIndex index value of zero and incrementing the index value with each subsequent call until the function returns CR_NO_SUCH_VALUE. Some index values might represent list entries containing invalid class data, in which case the function returns CR_INVALID_DATA. This return value can be ignored.

The class GUIDs obtained from this function can be used as input to the device installation functions.

See Also

CM_Enumerate_Classes


CM_Enumerate_Enumerators

The CM_Enumerate_Enumerators function enumerates the local system's device enumerators by supplying each enumerator's name.

CMAPI CONFIGRET WINAPI
  CM_Enumerate_Enumerators(
    IN ULONG  ulEnumIndex,
    OUT PTCHAR  Buffer,
    IN OUT PULONG  pulLength,
    IN ULONG  ulFlags
    );

Parameters

ulEnumIndex
Caller-supplied index into the system's list of device enumerators. For more information, see the following Comments section.
Buffer
Address of a buffer to receive an enumerator name. This buffer should be MAX_DEVICE_ID_LEN-sized (or, set Buffer to zero and obtain the actual name length in the location referenced by puLength).
pulLength
Caller-supplied address of a location to hold the buffer size. The caller supplies the length of the buffer pointed to by Buffer. The function replaces this value with the actual size of the enumerator's name string. If the caller-supplied buffer length is too small, the function supplies the required buffer size and returns CR_BUFFER_SMALL.
ulFlags
Not used, must be zero.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

To enumerate the local system's device enumerators, call CM_Enumerate_Enumerators repeatedly, starting with a ulEnumIndex index value of zero. and incrementing the index value with each subsequent call until the function returns CR_NO_SUCH_VALUE.

After enumerator names have been obtained, the names can be used as input to CM_Get_Device_ID_List.

See Also

CM_Enumerate_Enumerators_Ex


CM_Enumerate_Enumerators_Ex

The CM_Enumerate_Enumerators_Ex function enumerates a local or remote system's device enumerators, by supplying each enumerator's name.

CMAPI CONFIGRET WINAPI
  CM_Enumerate_Enumerators_Ex(
    IN ULONG  ulEnumIndex,
    OUT PTCHAR  Buffer,
    IN OUT PULONG  pulLength,
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

ulEnumIndex
Caller-supplied index into the system's list of device enumerators. For more information, see the following Comments section.
Buffer
Address of a buffer to receive an enumerator name. This buffer should be MAX_DEVICE_ID_LEN-sized (or, set Buffer to zero and obtain the actual name length in the location referenced by puLength).
pulLength
Caller-supplied address of a location to hold the buffer size. The caller supplies the length of the buffer pointed to by Buffer. The function replaces this value with the actual size of the enumerator's name string. If the caller-supplied buffer length is too small, the function supplies the required buffer size and returns CR_BUFFER_SMALL.
ulFlags
Not used, must be zero.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

To enumerate the local or remote system's device enumerators, call CM_Enumerate_Enumerators_Ex repeatedly, starting with a ulEnumIndex index value of zero, and incrementing the index value with each subsequent call until the function returns CR_NO_SUCH_VALUE.

After enumerator names have been obtained, the names can be used as input to CM_Get_Device_ID_List.

See Also

CM_Enumerate_Enumerators


CM_Find_Range

Do not use this function. Use device installation functions instead.


CM_First_Range

Do not use this function. Use device installation functions instead.


CM_Free_Log_Conf

The CM_Free_Log_Conf function removes a logical configuration and all associated resource descriptors, for the local system.

CMAPI CONFIGRET WINAPI
  CM_Free_Log_Conf(
    IN LOG_CONF  lcLogConfToBeFreed,
    IN ULONG  ulFlags
    );

Parameters

lcLogConfToBeFreed
Caller-supplied handle to a logical configuration. This handle must have been previously obtained by calling one of the following functions:

CM_Add_Empty_Log_Conf
CM_Add_Empty_Log_Conf_Ex
CM_Get_First_Log_Conf
CM_Get_First_Log_Conf_Ex
CM_Get_Next_Log_Conf
CM_Get_Next_Log_Conf_Ex

ulFlags
Not used, must be zero.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

Calling CM_Free_Log_Conf can cause the handles returned by CM_Get_First_Log_Conf and CM_Get_Next_Log_Conf to become invalid. Thus if you want to obtain logical configurations after calling CM_Free_Log_Conf, your code must call CM_Get_First_Log_Conf again and start at the first configuration.

Note that calling CM_Free_Log_Conf frees the configuration, but not the configuration's handle. To free the handle, call CM_Free_Log_Conf_Handle.

Callers of this function must have SeLoadDriverPrivilege. (Privileges are described in Platform SDK documentation.)

See Also

CM_Free_Log_Conf_Ex


CM_Free_Log_Conf_Ex

The CM_Free_Log_Conf_Ex function removes a logical configuration and all associated resource descriptors, for a local or remote system.

CMAPI CONFIGRET WINAPI
  CM_Free_Log_Conf_Ex(
    IN LOG_CONF  lcLogConfToBeFreed,
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

lcLogConfToBeFreed
Caller-supplied handle to a logical configuration. This handle must have been previously obtained by calling one of the following functions:

CM_Add_Empty_Log_Conf
CM_Add_Empty_Log_Conf_Ex
CM_Get_First_Log_Conf
CM_Get_First_Log_Conf_Ex
CM_Get_Next_Log_Conf
CM_Get_Next_Log_Conf_Ex

ulFlags
Not used, must be zero.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

Calling CM_Free_Log_Conf_Ex can cause the handles returned by CM_Get_First_Log_Conf_Ex and CM_Get_Next_Log_Conf_Ex to become invalid. Thus if you want to obtain logical configurations after calling CM_Free_Log_Conf_Ex, your code must call CM_Get_First_Log_Conf_Ex again and start at the first configuration.

Note that calling CM_Free_Log_Conf_Ex frees the configuration, but not the configuration's handle. To free the handle, call CM_Free_Log_Conf_Handle_Ex.

Callers of this function must have SeLoadDriverPrivilege. (Privileges are described in Platform SDK documentation.)

See Also

CM_Free_Log_Conf


CM_Free_Log_Conf_Handle

The CM_Free_Log_Conf_Handle function invalidates a logical configuration handle and frees its associated memory allocation.

CMAPI CONFIGRET WINAPI
  CM_Free_Log_Conf_Handle(
    IN LOG_CONF  lcLogConf
    );

Parameters

lcLogConf
Caller-supplied logical configuration handle. This handle must have been previously obtained by calling one of the following functions:

CM_Add_Empty_Log_Conf
CM_Add_Empty_Log_Conf_Ex
CM_Get_First_Log_Conf
CM_Get_First_Log_Conf_Ex
CM_Get_Next_Log_Conf
CM_Get_Next_Log_Conf_Ex

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

Each time your code calls one of the functions listed under the description of lcLogConf, it must subsequently call CM_Free_Log_Conf_Handle.


CM_Free_Range_List

Do not use this function. Use device installation functions instead.


CM_Free_Res_Des

The CM_Free_Res_Des function removes a resource descriptor from a logical configuration, for the local system.

CMAPI CONFIGRET WINAPI
  CM_Free_Res_Des(
    OUT PRES_DES  prdResDes,
    IN RES_DES  rdResDes,
    IN ULONG  ulFlags
    );

Parameters

prdResDes
Caller-supplied location to receive a handle to the configuration's previous resource descriptor. This parameter can be NULL. For more information, see the following Comments section.
rdResDes
Caller-supplied handle to the resource descriptor to be removed. This handle must have been previously obtained by calling one of the following functions:

CM_Add_Res_Des
CM_Add_Res_Des_Ex
CM_Get_Next_Res_Des
CM_Get_Next_Res_Des_Ex
CM_Modify_Res_Des
CM_Modify_Res_Des_Ex

ulFlags
Not used, must be zero.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

Resource descriptors for each configuration are stored in an array. If you specify an address for prdResDes, then CM_Free_Res_Des returns a handle to the resource descriptor that was previous, in the array, to the one removed. If the handle specified by rdResDes represents the resource descriptor located first in the array, then prdResDes receives a handle to the logical configuration.

Note that calling CM_Free_Res_Des frees the resource descriptor, but not the descriptor's handle. To free the handle, call CM_Free_Res_Des_Handle.

See Also

CM_Free_Res_Des_Ex


CM_Free_Res_Des_Ex

The CM_Free_Res_Des_Ex function removes a resource descriptor from a logical configuration for a local or remote system.

CMAPI CONFIGRET WINAPI
  CM_Free_Res_Des_Ex(
    OUT PRES_DES  prdResDes,
    IN RES_DES  rdResDes,
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

prdResDes
Caller-supplied location to receive a handle to the configuration's previous resource descriptor. This parameter can be NULL. For more information, see the following Comments section.
rdResDes
Caller-supplied handle to the resource descriptor to be removed. This handle must have been previously obtained by calling one of the following functions:

CM_Add_Res_Des
CM_Add_Res_Des_Ex
CM_Get_Next_Res_Des
CM_Get_Next_Res_Des_Ex
CM_Modify_Res_Des
CM_Modify_Res_Des_Ex

ulFlags
Not used, must be zero.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

Resource descriptors for each configuration are stored in an array. If you specify an address for prdResDes, then CM_Free_Res_Des returns a handle to the resource descriptor that was previous, in the array, to the one removed. If the handle specified by rdResDes represents the resource descriptor located first in the array, then prdResDes receives a handle to the logical configuration.

Note that calling CM_Free_Res_Des_Ex frees the resource descriptor, but not the descriptor's handle. To free the handle, call CM_Free_Res_Des_Handle_Ex.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

See Also

CM_Free_Res_Des


CM_Free_Res_Des_Handle

The CM_Free_Res_Des_Handle function invalidates a resource description handle and frees its associated memory allocation.

CMAPI CONFIGRET WINAPI
  CM_Free_Res_Des_Handle(
    IN RES_DES  rdResDes
    );

Parameters

rdResDes
Caller-supplied resource descriptor handle to be freed. This handle must have been previously obtained by calling one of the following functions:

CM_Add_Res_Des
CM_Add_Res_Des_Ex
CM_Get_Next_Res_Des
CM_Get_Next_Res_Des_Ex
CM_Modify_Res_Des
CM_Modify_Res_Des_Ex

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

Each time your code calls one of the functions listed under the description of RdResDes, it must subsequently call CM_Free_Res_Des_Handle.


CM_Free_Resource_Conflict_Handle

The CM_Free_Resource_Conflict_Handle function invalidates a handle to a resource conflict list, and frees the handle's associated memory allocation.

CMAPI CONFIGRET WINAPI
  CM_Free_Resource_Conflict_Handle(
    IN CONFLICT_LIST  clConflictList
    );

Parameters

clConflictList
Caller-supplied handle to be freed. This conflict list handle must have been previously obtained by calling CM_Query_Resource_Conflict_List.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

An application must call CM_Free_Resource_Conflict_Handle after it has finished using the handle that was obtained calling CM_Query_Resource_Conflict_List.


CM_Get_Child

The CM_Get_Child function is used to obtain a device instance handle to the first child node of a specified device node, in the local system's device tree.

CMAPI CONFIGRET WINAPI
  CM_Get_Child(
    OUT PDEVINST  pdnDevInst,
    IN DEVINST  dnDevInst,
    IN ULONG  ulFlags
    );

Parameters

pdnDevInst
Caller-supplied address of a location to receive the first child's device instance handle.
dnDevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Locate_DevNode
CM_Locate_DevNode_Ex
CM_Get_Child
CM_Get_Child_Ex
CM_Get_Parent
CM_Get_Parent_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

ulFlags
Not used, must be zero.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

To enumerate all children of a device node in the local system's device tree, first call CM_Get_Child to obtain a device instance handle to the first child node, then call CM_Get_Sibling to obtain handles for the rest of the children.

See Also

CM_Get_Child_Ex


CM_Get_Child_Ex

The CM_Get_Child_Ex function is used to obtain a device instance handle to the first child node of a specified device node, in a local or remote system's device tree.

CMAPI CONFIGRET WINAPI
  CM_Get_Child_Ex(
    OUT PDEVINST  pdnDevInst,
    IN DEVINST  dnDevInst,
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

pdnDevInst
Caller-supplied address of a location to receive the first child's device instance handle.
dnDevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Locate_DevNode
CM_Locate_DevNode_Ex
CM_Get_Child
CM_Get_Child_Ex
CM_Get_Parent
CM_Get_Parent_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

ulFlags
Not used, must be zero.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

To enumerate all children of a device node in a local or remote system's device tree, first call CM_Get_Child_Ex to obtain a handle to the first child node, then call CM_Get_Sibling_Ex to obtain handles for the rest of the children.

See Also

CM_Get_Child


CM_Get_Class_Name

Do not use this function. Use device installation functions instead.


CM_Get_Class_Name_Ex

Do not use this function. Use device installation functions instead.


CM_Get_Class_Key_Name

Do not use this function. Use device installation functions instead.


CM_Get_Class_Key_Name_Ex

Do not use this function. Use device installation functions instead.


CM_Get_Class_Registry_Property

Do not use this function. Use device installation functions instead.


CM_Get_Depth

The CM_Get_Depth function is used to obtain the depth of a specified device node, within the local system's device tree.

CMAPI CONFIGRET WINAPI
  CM_Get_Depth(
    OUT PULONG  pulDepth,
    IN DEVINST  dnDevInst,
    IN ULONG  ulFlags
    );

Parameters

pulDepth
Caller-supplied address of a location to receive a depth value, where zero represents the device tree's root node, one represents the root node's children, and so on.
dnDevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Locate_DevNode
CM_Locate_DevNode_Ex
CM_Get_Child
CM_Get_Child_Ex
CM_Get_Parent
CM_Get_Parent_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

ulFlags
Not used, must be zero.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

See Also

CM_Get_Depth_EX


CM_Get_Depth_Ex

The CM_Get_Depth_Ex function is used to obtain the depth of a specified device node, within a local or remote system's device tree.

CMAPI CONFIGRET WINAPI
  CM_Get_Depth_Ex(
    OUT PULONG  pulDepth,
    IN DEVINST  dnDevInst,
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

pulDepth
Caller-supplied address of a location to receive a depth value, where zero represents the device tree's root node, one represents the root node's children, and so on.
dnDevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Locate_DevNode
CM_Locate_DevNode_Ex
CM_Get_Child
CM_Get_Child_Ex
CM_Get_Parent
CM_Get_Parent_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

ulFlags
Not used, must be zero.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

See Also

CM_Get_Depth


CM_Get_Device_ID

The CM_Get_Device_ID function is used for obtaining the device instance ID associated with a specified device instance, on the local system.

CMAPI CONFIGRET WINAPI
  CM_Get_Device_ID(
    IN DEVINST  dnDevInst,
    OUT PTCHAR  Buffer,
    IN ULONG  BufferLen,
    IN ULONG  ulFlags
    );

Parameters

dnDevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Locate_DevNode
CM_Locate_DevNode_Ex
CM_Get_Child
CM_Get_Child_Ex
CM_Get_Parent
CM_Get_Parent_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

Buffer
Address of a buffer to receive a device instance ID string. The required buffer size can be obtained by calling CM_Get_Device_ID_Size, then incrementing the received value to allow room for the string's terminating NULL.
BufferLen
Caller-supplied length, in characters, of the buffer specified by Buffer.
ulFlags
Not used, must be zero.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

The function appends a NULL terminator to the supplied device instance ID string, unless the buffer is too small to hold the string. In this case, the function supplies as much of the identifier string as will fit into the buffer, and then returns CR_BUFFER_SMALL.

See Also

CM_Get_Device_ID_Ex


CM_Get_Device_ID_Ex

The CM_Get_Device_ID_Ex function is used for obtaining the device instance ID associated with a specified device instance, on a local or remote system.

CMAPI CONFIGRET WINAPI
  CM_Get_Device_ID_Ex(
    IN DEVINST  dnDevInst,
    OUT PTCHAR  Buffer,
    IN ULONG  BufferLen,
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

dnDevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Locate_DevNode
CM_Locate_DevNode_Ex
CM_Get_Child
CM_Get_Child_Ex
CM_Get_Parent
CM_Get_Parent_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

Buffer
Address of a buffer to receive a device instance ID string. The required buffer size can be obtained by calling CM_Get_Device_ID_Size_Ex, then incrementing the received value to allow room for the string's terminating NULL.
BufferLen
Caller-supplied length, in characters, of the buffer specified by Buffer.
ulFlags
Not used, must be zero.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

The function appends a NULL terminator to the supplied device instance ID string, unless the buffer is too small to hold the string. In this case, the function supplies as much of the identifier string as will fit into the buffer, and then returns CR_BUFFER_SMALL.

See Also

CM_Get_Device_ID


CM_Get_Device_ID_List

The CM_Get_Device_ID_List function is used to obtain a list of device instance IDs associated with the local system's device instances.

CMAPI CONFIGRET WINAPI
  CM_Get_Device_ID_List(
    IN PCTSTR  pszFilter,  OPTIONAL
    OUT PTCHAR  Buffer,
    IN ULONG  BufferLen,
    IN ULONG  ulFlags
    );

Parameters

pszFilter
Caller-supplied pointer to a character string specifying a subset of the system's device instance identifiers, or NULL. See the following description of ulFlags.
Buffer
Address of a buffer to receive a set of NULL-terminated device instance identifier strings. The end of the set is terminated by an extra NULL. The required buffer size should be obtained by calling CM_Get_Device_ID_List_Size.
BufferLen
Caller-supplied length, in characters, of the buffer specified by Buffer.
ulFlags
One of the optional, caller-supplied bit flags, listed in the following table, which specify search filters. If no flags are specified, the function returns all device instance IDs for all device instances.
Flag Definition
CM_GETIDLIST_FILTER_ENUMERATOR
If this flag is set, pszFilter must specify the name of a device enumerator, optionally followed by a device identifier. The string format is EnumeratorName\<DeviceID>, such as ROOT or ROOT\*PNP0500.

If pszFilter supplies only an enumerator name, the function returns device instance IDs for the instances of each device associated with the enumerator. Enumerator names can be obtained by calling CM_Enumerate_Enumerators.

If pszFilter supplies both an enumerator and a device ID, the function returns device instance IDs only for the device instances of the specified device, associated with the enumerator.
CM_GETIDLIST_FILTER_SERVICE
If this flag is set, pszFilter must specify the name of a Windows service (typically a driver). The function returns device instance IDs for the device instances controlled by the specified service.

Note that if the device tree does not contain a device node for the specified service, this function creates one by default. To inhibit this behavior, also set CM_GETIDLIST_DONOTGENERATE.
CM_GETIDLIST_FILTER_EJECTRELATIONS
If this flag is set, pszFilter must specify a device name. The function returns device instance IDs for the ejection relations of the specified device instance.
CM_GETIDLIST_FILTER_REMOVALRELATIONS
If this flag is set, pszFilter must specify a device name. The function returns device instance IDs for the removal relations of the specified device instance.
CM_GETIDLIST_FILTER_POWERRELATIONS
Not used.
CM_GETIDLIST_FILTER_BUSRELATIONS
Not used.
CM_GETIDLIST_DONOTGENERATE
Used only with CM_GETIDLIST_FILTER_SERVICE. If set, and if the device tree does not contain a device node for the specified service, this flag prevents the function from creating a device node for the service.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.


CM_Get_Device_ID_List_Ex

The CM_Get_Device_ID_List_Ex function is used to obtain a list of device instance identifiers associated with device instances on a local or remote system.

CMAPI CONFIGRET WINAPI
  CM_Get_Device_ID_List_Ex(
    IN PCTSTR  pszFilter,  OPTIONAL
    OUT PTCHAR  Buffer,
    IN ULONG  BufferLen,
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

pszFilter
Caller-supplied pointer to a character string specifying a subset of the system's device instance identifiers, or NULL. See the following description of ulFlags.
Buffer
Address of a buffer to receive a set of NULL-terminated device instance identifier strings. The end of the set is terminated by an extra NULL. The required buffer size should be obtained by calling CM_Get_Device_ID_List_Size_Ex.
BufferLen
Caller-supplied length, in characters, of the buffer specified by Buffer.
ulFlags
One of the optional, caller-supplied bit flags that specify search filters. If no flags are specified, the function supplies all instance identifiers for all device instances. For a list of bit flags, see the ulFlags description for CM_Get_Device_ID_List.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.


CM_Get_Device_ID_List_Size

The CM_Get_Device_ID_List_Size function supplies the buffer size required to hold a list of device instance identifiers associated with the local system's device instances.

CMAPI CONFIGRET WINAPI
  CM_Get_Device_ID_List_Size(
    OUT PULONG  pulLen,
    IN PCTSTR  pszFilter,  OPTIONAL
    IN ULONG  ulFlags
    );

Parameters

pulLen
Receives a value representing the required buffer size, in characters.
pszFilter
Caller-supplied pointer to a character string specifying a subset of the system's device instance identifiers, or NULL. See the following description of ulFlags.
ulFlags
One of the optional, caller-supplied bit flags that specify search filters. If no flags are specified, the function supplies the buffer size required to hold all instance identifiers for all device instances. For a list of bit flags, see the ulFlags description for CM_Get_Device_ID_List.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

The CM_Get_Device_ID_List_Size function should be called to determine the buffer size required by CM_Get_Device_ID_List.

The size value supplied in the location pointed to by pulLen is guaranteed to represent a buffer size large enough to hold all device instance identifier strings and terminating NULLs. The supplied value might actually represent a buffer size that is larger than necessary, so don't assume the value represents the true length of the character strings that CM_Get_Device_ID_List will provide.

See Also

CM_Get_Device_ID_List_Size_Ex


CM_Get_Device_ID_List_Size_Ex

The CM_Get_Device_ID_List_Size_Ex function supplies the buffer size required to hold a list of device instance identifiers associated with a local or remote system's device instances.

CMAPI CONFIGRET WINAPI
  CM_Get_Device_ID_List_Size_Ex(
    OUT PULONG  pulLen,
    IN PCTSTR  pszFilter,  OPTIONAL
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

pulLen
Receives a value representing the required buffer size, in characters.
pszFilter
Caller-supplied pointer to a character string specifying a subset of the system's device instance identifiers, or NULL. See the following description of ulFlags.
ulFlags
One of the optional, caller-supplied bit flags that specify search filters. If no flags are specified, the function supplies the buffer size required to hold all instance identifiers for all device instances. For a list of bit flags, see the ulFlags description for CM_Get_Device_ID_List_Ex.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

The CM_Get_Device_ID_List_Size_Ex function should be called to determine the buffer size required by CM_Get_Device_ID_List_Ex.

The size value supplied in the location pointed to by pulLen is guaranteed to represent a buffer size large enough to hold all device instance identifier strings and terminating NULLs. The supplied value might actually represent a buffer size that is larger than necessary, so don't assume the value represents the true length of the character strings that CM_Get_Device_ID_List_Ex will provide.

See Also

CM_Get_Device_ID_List_Size


CM_Get_Device_ID_Size

The CM_Get_Device_ID_Size function supplies the buffer size required to hold a device instance identifier associated with a device instance on the local system.

CMAPI CONFIGRET WINAPI
  CM_Get_Device_ID_Size(
    OUT PULONG  pulLen,
    IN DEVINST  dnDevInst,
    IN ULONG  ulFlags
    );

Parameters

pulLen
Receives a value representing the required buffer size, in characters.
dnDevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Locate_DevNode
CM_Locate_DevNode_Ex
CM_Get_Child
CM_Get_Child_Ex
CM_Get_Parent
CM_Get_Parent_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

ulFlags
Not used, must be zero.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

The CM_Get_Device_ID_Size function should be called to determine the buffer size required by CM_Get_Device_ID.

The size value supplied in the location pointed to by pulLen is less than or equal to MAX_DEVICE_ID_LEN, and does not include the identifier string's terminating NULL. If the specified device instance does not exist, the function supplies a size value of zero.

See Also

CM_Get_Device_ID_Size_Ex


CM_Get_Device_ID_Size_Ex

The CM_Get_Device_ID_Size_Ex function supplies the buffer size required to hold a device instance identifier associated with a device instance on a local or remote system.

CMAPI CONFIGRET WINAPI
  CM_Get_Device_ID_Size_Ex(
    OUT PULONG  pulLen,
    IN DEVINST  dnDevInst,
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

pulLen
Receives a value representing the required buffer size, in characters.
dnDevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Locate_DevNode
CM_Locate_DevNode_Ex
CM_Get_Child
CM_Get_Child_Ex
CM_Get_Parent
CM_Get_Parent_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

ulFlags
Not used, must be zero.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

The CM_Get_Device_ID_Size_Ex function should be called to determine the buffer size required by CM_Get_Device_ID_Ex.

The size value supplied in the location pointed to by pulLen is less than or equal to MAX_DEVICE_ID_LEN, and does not include the identifier string's terminating NULL. If the specified device instance does not exist, the function supplies a size value of zero.

See Also

CM_Get_Device_ID_Size


CM_Get_Device_Interface_Alias

Do not use this function. Use device installation functions instead.


CM_Get_Device_Interface_Alias_Ex

Do not use this function. Use device installation functions instead.


CM_Get_Device_Interface_List

Do not use this function. Use device installation functions instead.


CM_Get_Device_Interface_List_Ex

Do not use this function. Use device installation functions instead.


CM_Get_Device_Interface_List_Size

Do not use this function. Use device installation functions instead.


CM_Get_Device_Interface_List_Size_Ex

Do not use this function. Use device installation functions instead.


CM_Get_DevNode_Custom_Property

Do not use this function. Use device installation functions instead.


CM_Get_DevNode_Custom_Property_Ex

Do not use this function. Use device installation functions instead.


CM_Get_DevNode_Registry_Property

Do not use this function. Use device installation functions instead.


CM_Get_DevNode_Registry_Property_Ex

Do not use this function. Use device installation functions instead.


CM_Get_DevNode_Status

The CM_Get_DevNode_Status function is used to obtain the status of a device instance from its device node, in the local system's device tree.

CMAPI CONFIGRET WINAPI
  CM_Get_DevNode_Status(
    OUT PULONG  pulStatus,
    OUT PULONG  pulProblemNumber,
    IN DEVINST  dnDevInst,
    IN ULONG  ulFlags
    );

Parameters

pulStatus
Address of a location to receive status bit flags. The function can set any combination of the DN_-prefixed bit flags defined in cfg.h.
pulProblemNumber
Address of a location to receive one of the CM_PROB_-prefixed problem values defined in cfg.h. Used only if DN_HAS_PROBLEM is set in pulStatus.
dnDevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Locate_DevNode
CM_Locate_DevNode_Ex
CM_Get_Child
CM_Get_Child_Ex
CM_Get_Parent
CM_Get_Parent_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

ulFlags
Not used, must be zero.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

See Also

CM_Get_DevNode_Status_Ex


CM_Get_DevNode_Status_Ex

The CM_Get_DevNode_Status_Ex function is used to obtain the status of a device instance from its device node, on a local or remote system's device tree.

CMAPI CONFIGRET WINAPI
  CM_Get_DevNode_Status_Ex(
    OUT PULONG  pulStatus,
    OUT PULONG  pulProblemNumber,
    IN DEVINST  dnDevInst,
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

pulStatus
Address of a location to receive status bit flags. The function can set any combination of the DN_-prefixed bit flags defined in cfg.h.
pulProblemNumber
Address of a location to receive one of the CM_PROB_-prefixed problem values defined in cfg.h. Used only if DN_HAS_PROBLEM is set in pulStatus.
dnDevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Locate_DevNode
CM_Locate_DevNode_Ex
CM_Get_Child
CM_Get_Child_Ex
CM_Get_Parent
CM_Get_Parent_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

ulFlags
Not used, must be zero.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

See Also

CM_Get_DevNode_Status


CM_Get_First_Log_Conf

The CM_Get_First_Log_Conf function is used to obtain the first logical configuration, of a specified configuration type, associated with a specified device instance on the local system.

CMAPI CONFIGRET WINAPI
  CM_Get_First_Log_Conf(
    OUT PLOG_CONF  plcLogConf,  OPTIONAL
    IN DEVINST  dnDevInst,
    IN ULONG  ulFlags
    );

Parameters

plcLogConf
Address of a location to receive the handle to a logical configuration, or NULL. (See the following Comments section.)
dnDevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Locate_DevNode
CM_Locate_DevNode_Ex
CM_Get_Child
CM_Get_Child_Ex
CM_Get_Parent
CM_Get_Parent_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

ulFlags
Caller-supplied flag value indicating the type of logical configuration being requested. One of the flags in the following table must be specified.
Configuration Type Flags | Definitions
BASIC_LOG_CONF | The caller is requesting basic configuration information.
FILTERED_LOG_CONF | the caller is requesting filtered configuration information.
ALLOC_LOG_CONF | The caller is requesting allocated configuration information.
BOOT_LOG_CONF | The caller is requesting boot configuration information.
FORCED_LOG_CONF | The caller is requesting forced configuration information.
OVERRIDE_LOG_CONF | The caller is requesting override configuration information.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

Calling CM_Add_Empty_Log_Conf or CM_Free_Log_Conf can invalidate the handle obtained from a previous call to CM_Get_First_Log_Conf. Thus if you want to obtain logical configurations after calling CM_Add_Empty_Log_Conf or CM_Free_Log_Conf, your code must call CM_Get_First_Log_Conf again and start at the first configuration.

The handle received in plcLogConf must be explicitly freed by calling CM_Free_Log_Conf_Handle.

If CM_Get_First_Log_Conf is called with plcLogConf set to NULL, no handle is returned. This allows you to use the return status to determine if a configuration exists without the need to subsequently free the handle.

See Also

CM_Get_First_Log_Conf_Ex


CM_Get_First_Log_Conf_Ex

The CM_Get_First_Log_Conf_Ex function is used to obtain the first logical configuration associated with a specified device instance, on a local or remote system.

CMAPI CONFIGRET WINAPI
  CM_Get_First_Log_Conf_Ex(
    OUT PLOG_CONF  plcLogConf,  OPTIONAL
    IN DEVINST  dnDevInst,
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

plcLogConf
Address of a location to receive the handle to a logical configuration, or NULL. (See the following Comments section.
dnDevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Locate_DevNode
CM_Locate_DevNode_Ex
CM_Get_Child
CM_Get_Child_Ex
CM_Get_Parent
CM_Get_Parent_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

ulFlags
Caller-supplied flag value indicating the type of logical configuration being requested. For a list of flags, see the ulFlags description for CM_Get_First_Log_Conf.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

Calling CM_Add_Empty_Log_Conf_Ex or CM_Free_Log_Conf_Ex can invalidate the handle obtained from a previous call to CM_Get_First_Log_Conf_Ex. Thus if you want to obtain logical configurations after calling CM_Add_Empty_Log_Conf_Ex or CM_Free_Log_Conf_Ex, your code must call CM_Get_First_Log_Conf_Ex again and start at the first configuration.

The handle received in plcLogConf must be explicitly freed by calling CM_Free_Log_Conf_Handle.

If CM_Get_First_Log_Conf_Ex is called with plcLogConf set to NULL, no handle is returned. This allows you to use the return status to determine if a configuration exists without the need to subsequently free the handle.

See Also

CM_Get_First_Log_Conf


CM_Get_Global_State

Do not use this function. Use device installation functions instead.


CM_Get_Global_State_Ex

Do not use this function. Use device installation functions instead.


CM_Get_Hardware_Profile_Info

Do not use this function. Use device installation functions instead.


CM_Get_Hardware_Profile_Info_Ex

Do not use this function. Use device installation functions instead.


CM_Get_HW_Prof_Flags

Do not use this function. Use device installation functions instead.


CM_Get_HW_Prof_Flags_Ex

Do not use this function. Use device installation functions instead.


CM_Get_Log_Conf_Priority

The CM_Get_Log_Conf_Priority function is used to obtain the configuration priority of a specified logical configuration, on the local system.

CMAPI CONFIGRET WINAPI
  CM_Get_Log_Conf_Priority(
    IN LOG_CONF  lcLogConf,
    OUT PPRIORITY  pPriority,
    IN ULONG  ulFlags
    );

Parameters

lcLogConf
Caller-supplied handle to a logical configuration. This handle must have been previously obtained by calling one of the following functions:

CM_Add_Empty_Log_Conf
CM_Add_Empty_Log_Conf_Ex
CM_Get_First_Log_Conf
CM_Get_First_Log_Conf_Ex
CM_Get_Next_Log_Conf
CM_Get_Next_Log_Conf_Ex

pPriority
Caller-supplied address of a location to receive a configuration priority value. For a list of priority values, see the description of Priority for CM_Add_Empty_Log_Conf.
ulFlags
Not used, must be zero.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

See Also

CM_Get_Log_Conf_Priority_Ex


CM_Get_Log_Conf_Priority_Ex

The CM_Get_Log_Conf_Priority_Ex function is used to obtain the configuration priority of a specified logical configuration, on a local or remote system.

CMAPI CONFIGRET WINAPI
  CM_Get_Log_Conf_Priority_Ex(
    IN LOG_CONF  lcLogConf,
    OUT PPRIORITY  pPriority,
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

lcLogConf
Caller-supplied handle to a logical configuration. This handle must have been previously obtained by calling one of the following functions:

CM_Add_Empty_Log_Conf
CM_Add_Empty_Log_Conf_Ex
CM_Get_First_Log_Conf
CM_Get_First_Log_Conf_Ex
CM_Get_Next_Log_Conf
CM_Get_Next_Log_Conf_Ex

pPriority
Caller-supplied address of a location to receive a configuration priority value. For a list of priority values, see the description of Priority for CM_Add_Empty_Log_Conf_Ex.
ulFlags
Not used, must be zero.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

See Also

CM_Get_Log_Conf_Priority


CM_Get_Next_Log_Conf

The CM_Get_Next_Log_Conf function is used to obtain the next logical configuration associated with a specific device instance, on the local system.

CMAPI CONFIGRET WINAPI
  CM_Get_Next_Log_Conf(
    OUT PLOG_CONF  plcLogConf,  OPTIONAL
    IN LOG_CONF  lcLogConf,
    IN ULONG  ulFlags
    );

Parameters

plcLogConf
Address of a location to receive the handle to a logical configuration, or NULL. (See the following Comments section.
lcLogConf
Caller-supplied handle to a logical configuration. This handle must have been previously obtained by calling one of the following functions:

CM_Get_First_Log_Conf
CM_Get_Next_Log_Conf

ulFlags
Not used, must be zero.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

To enumerate the logical configurations associated with a device instance, call CM_Get_First_Log_Conf to obtain the first logical configuration of a specified configuration type, then call CM_Get_Next_Log_Conf repeatedly until it returns CR_NO_MORE_LOG_CONF.

Calling CM_Add_Empty_Log_Conf or CM_Free_Log_Conf can invalidate the handle obtained from a previous call to CM_Get_Next_Log_Conf. Thus if you want to obtain logical configurations after calling CM_Add_Empty_Log_Conf or CM_Free_Log_Conf, your code must call CM_Get_First_Log_Conf again and start at the first configuration.

The handle received in plcLogConf must be explicitly freed by calling CM_Free_Log_Conf_Handle.

If CM_Get_Next_Log_Conf is called with plcLogConf set to NULL, no handle is returned. This allows you to use the return status to determine if a configuration exists without the need to subsequently free the handle.

See Also

CM_Get_Next_Log_Conf_Ex


CM_Get_Next_Log_Conf_Ex

The CM_Get_Next_Log_Conf_Ex function is used to obtain the next logical configuration associated with a specific device instance, on a local or remote system.

CMAPI CONFIGRET WINAPI
  CM_Get_Next_Log_Conf_Ex(
    OUT PLOG_CONF  plcLogConf,  OPTIONAL
    IN LOG_CONF  lcLogConf,
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

plcLogConf
Address of a location to receive the handle to a logical configuration, or NULL. (See the following Comments section.
lcLogConf
Caller-supplied handle to a logical configuration. This handle must have been previously obtained by calling one of the following functions:

CM_Get_First_Log_Conf_Ex
CM_Get_Next_Log_Conf_Ex

ulFlags
Not used, must be zero.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

To enumerate the logical configurations associated with a device instance, call CM_Get_First_Log_Conf_Ex to obtain the first logical configuration, then call CM_Get_Next_Log_Conf_Ex repeatedly until it returns CR_NO_MORE_LOG_CONF.

Calling CM_Add_Empty_Log_Conf_Ex or CM_Free_Log_Conf_Ex can invalidate the handle obtained from a previous call to CM_Get_Next_Log_Conf_Ex. Thus if you want to obtain logical configurations after calling CM_Add_Empty_Log_Conf_Ex or CM_Free_Log_Conf_Ex, your code must call CM_Get_First_Log_Conf_Ex again and start at the first configuration.

The handle received in plcLogConf must be explicitly freed by calling CM_Free_Log_Conf_Handle.

If CM_Get_Next_Log_Conf_Ex is called with plcLogConf set to NULL, no handle is returned. This allows you to use the return status to determine if a configuration exists without the need to subsequently free the handle.

See Also

CM_Get_Next_Log_Conf


CM_Get_Next_Res_Des

The CM_Get_Next_Res_Des function is used to obtain a handle to the next resource descriptor, of a specified resource type, for a logical configuration on the local system.

CMAPI CONFIGRET WINAPI
  CM_Get_Next_Res_Des(
    OUT PRES_DES  prdResDes,
    IN RES_DES  rdResDes,
    IN RESOURCEID  ForResource,
    OUT PRESOURCEID  pResourceID,
    IN ULONG  ulFlags
    );

Parameters

prdResDes
Pointer to a location to receive a resource descriptor handle.
rdResDes
Caller-supplied handle to either a resource descriptor or a logical configuration. For more information, see the following Comments section.
ForResource
Caller-supplied resource type identifier, indicating the type of resource descriptor being requested. This must be one of the ResType_-prefixed constants defined in cfgmgr32.h.
pResourceID
Pointer to a location to receive a resource type identifier, if ForResource specifies ResType_All. For any other ForResource value, callers should set this to NULL.
ulFlags
Not used, must be zero.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

To enumerate a logical configuration's resource descriptors, begin by calling CM_Get_Next_Res_Des with the logical configuration's handle as the argument for rdResDes. This obtains a handle to the first resource descriptor of the type specified by ForResource. Then for each subsequent call to CM_Get_Next_Res_Des, specify the most recently obtained descriptor handle as the argument for rdResDes. Repeat until the function returns CR_NO_MORE_RES_DES.

To retrieve the information stored in a resource descriptor, call CM_Get_Res_Des_Data.

To modify the information stored in a resource descriptor, call CM_Modify_Res_Des.

Callers of CM_Get_Next_Res_Des must call CM_Free_Res_Des_Handle to deallocate the resource descriptor handle, after it is no longer needed.

See Also

CM_Get_Next_Res_Des_Ex


CM_Get_Next_Res_Des_Ex

The CM_Get_Next_Res_Des_Ex function is used to obtain a handle to the next resource descriptor, of a specified resource type, for a logical configuration on a local or remote system.

CMAPI CONFIGRET WINAPI
  CM_Get_Next_Res_Des_Ex(
    OUT PRES_DES  prdResDes,
    IN RES_DES  rdResDes,
    IN RESOURCEID  ForResource,
    OUT PRESOURCEID  pResourceID,
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

prdResDes
Pointer to a location to receive a resource descriptor handle.
rdResDes
Caller-supplied handle to either a resource descriptor or a logical configuration. For more information, see the following Comments section.
ForResource
Caller-supplied resource type identifier, indicating the type of resource descriptor being requested. This must be one of the ResType_-prefixed constants defined in cfgmgr32.h.
pResourceID
Pointer to a location to receive a resource type identifier, if ForResource specifies ResType_All. For any other ForResource value, callers should set this to NULL.
ulFlags
Not used, must be zero.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

To enumerate a logical configuration's resource descriptors, begin by calling CM_Get_Next_Res_Des_Ex with the logical configuration's handle as the argument for rdResDes. This obtains a handle to the first resource descriptor of the type specified by ForResource. Then for each subsequent call to CM_Get_Next_Res_Des_Ex, specify the most recently obtained descriptor handle as the argument for rdResDes. Repeat until the function returns CR_NO_MORE_RES_DES.

To retrieve the information stored in a resource descriptor, call CM_Get_Res_Des_Data_Ex.

To modify the information stored in a resource descriptor, call CM_Modify_Res_Des_Ex.

Callers of CM_Get_Next_Res_Des_Ex must call CM_Free_Res_Des_Handle to deallocate the resource descriptor handle, after it is no longer needed.

See Also

CM_Get_Next_Res_Des


CM_Get_Parent

The CM_Get_Parent function is used to obtain a device instance handle to the parent node of a specified device node, in the local system's device tree.

CMAPI CONFIGRET WINAPI
  CM_Get_Parent(
    OUT PDEVINST  pdnDevInst,
    IN DEVINST  dnDevInst,
    IN ULONG  ulFlags
    );

Parameters

pdnDevInst
Caller-supplied address of a location to receive the first child's device instance handle.
dnDevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Locate_DevNode
CM_Locate_DevNode_Ex
CM_Get_Child
CM_Get_Child_Ex
CM_Get_Parent
CM_Get_Parent_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

ulFlags
Not used, must be zero.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

See Also

CM_Get_Parent_Ex


CM_Get_Parent_Ex

The CM_Get_Parent_Ex function is used to obtain a device instance handle to the parent node of a specified device node, in a local or remote system's device tree.

CMAPI CONFIGRET WINAPI
  CM_Get_Parent_Ex(
    OUT PDEVINST  pdnDevInst,
    IN DEVINST  dnDevInst,
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

pdnDevInst
Caller-supplied address of a location to receive the first child's device instance handle.
dnDevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Locate_DevNode
CM_Locate_DevNode_Ex
CM_Get_Child
CM_Get_Child_Ex
CM_Get_Parent
CM_Get_Parent_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

ulFlags
Not used, must be zero.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

See Also

CM_Get_Parent_Ex

Built on Wednesday, July 11, 2001


CM_Get_Res_Des_Data

The CM_Get_Res_Des_Data function is used to retrieve the information stored in a resource descriptor on the local system.

CMAPI CONFIGRET WINAPI
  CM_Get_Res_Des_Data(
    IN RES_DES  rdResDes,
    OUT PVOID  Buffer,
    IN ULONG  BufferLen,
    IN ULONG  ulFlags
    );

Parameters

rdResDes
Caller-supplied handle to a resource descriptor, obtained by a previous call to CM_Get_Next_Res_Des.
Buffer
Address of a buffer to receive the contents of a resource descriptor. The required buffer size should be obtained by calling CM_Get_Res_Des_Data_Size.
BufferLen
Caller-supplied length of the buffer specified by Buffer.
ulFlags
Not used, must be zero.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

Information returned in the buffer supplied by Buffer will be formatted as one of the resource type structures listed in the description of CM_Add_Res_Des, based on the resource type that was specified when CM_Get_Next_Res_Des was called to obtain the resource descriptor handle.

See Also

CM_Get_Res_Des_Data_Ex


CM_Get_Res_Des_Data_Ex

The CM_Get_Res_Des_Data_Ex function is used to retrieve the information stored in a resource descriptor on a local or remote system.

CMAPI CONFIGRET WINAPI
  CM_Get_Res_Des_Data_Ex(
    IN RES_DES  rdResDes,
    OUT PVOID  Buffer,
    IN ULONG  BufferLen,
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

rdResDes
Caller-supplied handle to a resource descriptor, obtained by a previous call to CM_Get_Next_Res_Des_Ex.
Buffer
Address of a buffer to receive the contents of a resource descriptor. The required buffer size should be obtained by calling CM_Get_Res_Des_Data_Size_Ex.
BufferLen
Caller-supplied length of the buffer specified by Buffer.
ulFlags
Not used, must be zero.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

Information returned in the buffer supplied by Buffer will be formatted as one of the resource type structures listed in the description of CM_Add_Res_Des_Ex, based on the resource type that was specified when CM_Get_Next_Res_Des_Ex was called to obtain the resource descriptor handle.

See Also

CM_Get_Res_Des_Data


CM_Get_Res_Des_Data_Size

The CM_Get_Res_Des_Data_Size function supplies the buffer size required to hold the information contained in a specified resource descriptor on the local system.

CMAPI CONFIGRET WINAPI
  CM_Get_Res_Des_Data_Size(
    OUT PULONG  pulSize,
    IN RES_DES  rdResDes,
    IN ULONG  ulFlags
    );

Parameters

pulSize
Caller-supplied address of a location to receive the required buffer size.
rdResDes
Caller-supplied handle to a resource descriptor, obtained by a previous call to CM_Get_Next_Res_Des.
ulFlags
Not used, must be zero.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

The returned size value represents the size of the appropriate resource structure (see CM_Add_Res_Des). If the resource descriptor resides in a resource requirements list, the returned size includes both the size of the resource structure and the space allocated for associated range arrays.

See Also

CM_Get_Res_Des_Data_Size_Ex


CM_Get_Res_Des_Data_Size_Ex

The CM_Get_Res_Des_Data_Size_Ex function supplies the buffer size required to hold the information contained in a specified resource descriptor on a local or remote system.

CMAPI CONFIGRET WINAPI
  CM_Get_Res_Des_Data_Size_Ex(
    OUT PULONG  pulSize,
    IN RES_DES  rdResDes,
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

pulSize
Caller-supplied address of a location to receive the required buffer size.
rdResDes
Caller-supplied handle to a resource descriptor, obtained by a previous call to CM_Get_Next_Res_Des_Ex.
ulFlags
Not used, must be zero.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

The returned size value represents the size of the appropriate resource structure (see CM_Add_Res_Des_Ex). If the resource descriptor resides in a resource requirements list, the returned size includes both the size of the resource structure and the space allocated for associated range arrays.

See Also

CM_Get_Res_Des_Data_Size


CM_Get_Resource_Conflict_Count

The CM_Get_Resource_Conflict_Count function supplies the number of conflicts contained in a specified resource conflict list.

CMAPI CONFIGRET WINAPI
  CM_Get_Resource_Conflict_Count(
    IN CONFLICT_LIST  clConflictList,
    OUT PULONG  pulCount
    );

Parameters

clConflictList
Caller-supplied handle to a conflict list, obtained by a previous call to CM_Query_Resource_Conflict_List.
pulCount
Caller-supplied address of a location to receive the conflict count.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

The count value obtained by calling CM_Get_Resource_Conflict_Count can be used to determine the number of times to call CM_Get_Resource_Conflict_Details, which supplies information about each conflict.

If there are no entries in the conflict list, the location supplied by pulCount will receive zero.


CM_Get_Resource_Conflict_Details

The CM_Get_Resource_Conflict_Details function supplies details about one of the resource conflicts in a conflict list.

CMAPI CONFIGRET WINAPI
  CM_Get_Resource_Conflict_Details(
    IN CONFLICT_LIST  clConflictList,
    IN ULONG  ulIndex,
    IN OUT PCONFLICT_DETAILS  pConflictDetails
    );

Parameters

clConflictList
Caller-supplied handle to a conflict list, obtained by a previous call to CM_Query_Resource_Conflict_List.
ulIndex
Caller-supplied value used as an index into the conflict list. This value can be from zero to one less than the number returned by CM_Get_Resource_Conflict_Count.
pConflictDetails
Caller-supplied address of a CONFLICT_DETAILS structure to receive conflict details. The caller must supply values for the structure's CD_ulSize and CD_ulMask structures.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

To determine conflicting resource requirements between a specified device and other devices on a system, use the following steps.

  1. Call CM_Query_Resource_Conflict_List to obtain a handle to a list of resource conflicts.
  2. Call CM_Get_Resource_Conflict_Count to determine the number of conflicts contained in the resource conflict list.
  3. Call CM_Get_Resource_Conflict_Details for each entry in the conflict list.

The following conflicts are typically not reported:

  • If there are multiple conflicts for a resource, and the owners of only some of the conflicts can be determined, the conflicts without identifiable owners are not reported.
  • Conflicts that appear to be with the specified device (that is, the device conflicts with itself) are not reported.
  • If multiple non-Plug and Play devices use the same driver, resource conflicts among these devices might not be reported.

Sometimes, resources assigned to the HAL might be reported as either conflicting with the HAL or not available.


CM_Get_Sibling

The CM_Get_Sibling function is used to obtain a device instance handle to the next sibling node of a specified device node, in the local system's device tree.

CMAPI CONFIGRET WINAPI
  CM_Get_Sibling(
    OUT PDEVINST  pdnDevInst,
    IN DEVINST  DevInst,
    IN ULONG  ulFlags
    );

Parameters

pdnDevInst
Caller-supplied address of a location to receive the sibling's device instance handle.
DevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Get_Child
CM_Get_Child_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

ulFlags
Not used, must be zero.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

To enumerate all children of a device node in the local system's device tree, first call CM_Get_Child to obtain a handle to the first child node, then call CM_Get_Sibling to obtain handles for the rest of the children.

See Also

CM_Get_Sibling_Ex


CM_Get_Sibling_Ex

The CM_Get_Sibling_Ex function is used to obtain a device instance handle to the next sibling node of a specified device node, in a local or remote system's device tree.

CMAPI CONFIGRET WINAPI
  CM_Get_Sibling_Ex(
    OUT PDEVINST  pdnDevInst,
    IN DEVINST  DevInst,
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

pdnDevInst
Caller-supplied address of a location to receive the sibling's device instance handle.
DevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Get_Child
CM_Get_Child_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

ulFlags
Not used, must be zero.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

To enumerate all children of a device node in the local system's device tree, first call CM_Get_Child_Ex to obtain a handle to the first child node, then call CM_Get_Sibling_Ex to obtain handles for the rest of the children.

See Also

CM_Get_Sibling


CM_Get_Version

The CM_Get_Version function returns the version number of cfgmgr32.dll residing on the local system.

CMAPI WORD WINAPI
  CM_Get_Version(
    VOID
    );

Return Value

The major revision number is returned in the high byte and the minor revision number is returned in the low byte. For example, version 4.0 is returned as 0x0400.

See Also

CM_Get_Version_Ex


CM_Get_Version_Ex

The CM_Get_Version function returns the version number of cfgmgr32.dll residing on a local or remote system.

CMAPI WORD WINAPI
  CM_Get_Version_Ex(
    IN HMACHINE  hMachine
    );

Parameters

hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

The major revision number is returned in the high byte and the minor revision number is returned in the low byte. For example, version 4.0 is returned as 0x0400.

See Also

CM_Get_Version


CM_Intersect_Range_List

Do not use this function. Use device installation functions instead.


CM_Invert_Range_List

Do not use this function. Use device installation functions instead.


CM_Is_Dock_Station_Present

Do not use this function. Use device installation functions instead.


CM_Is_Dock_Station_Present_Ex

Do not use this function. Use device installation functions instead.


CM_Locate_DevNode

The CM_Locate_DevNode function supplies a device instance handle to the device node that is associated with a specified device instance identifier, on the local system.

CMAPI CONFIGRET WINAPI
  CM_Locate_DevNode(
    OUT PDEVINST  pdnDevInst,
    IN DEVINSTID  pDeviceID,  OPTIONAL
    IN ULONG  ulFlags
    );

Parameters

pdnDevInst
Caller-supplied address of a location to receive a device instance handle.
pDeviceID
Caller-supplied pointer to a NULL-terminated string representing a device instance identifier. If this value is NULL, or if it points to a zero-length string, the function supplies a device instance handle to the device node at the top of the device tree.
ulFlags
One of the caller-supplied bit flags listed in the following table.
Flag Definition
CM_LOCATE_DEVNODE_NORMAL
(Default.) The function only searches for device nodes representing devices that are currently plugged into the system.
CM_LOCATE_DEVNODE_PHANTOM
The function searches both for device nodes representing devices that are currently plugged into the system, and for device nodes representing devices that are not currently plugged in (but were previously).
CM_LOCATE_DEVNODE_CANCELREMOVE
Not used.
CM_LOCATE_DEVNODE_NOVALIDATION
Not used.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

See Also

CM_Locate_DevNode_Ex


CM_Locate_DevNode_Ex

The CM_Locate_DevNode_Ex function supplies a device instance handle to the device node that is associated with a specified device instance identifier, on a local or remote system.

CMAPI CONFIGRET WINAPI
  CM_Locate_DevNode_Ex(
    OUT PDEVINST  pdnDevInst,
    IN DEVINSTID  pDeviceID,  OPTIONAL
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

pdnDevInst
Caller-supplied address of a location to receive a device instance handle.
pDeviceID
Caller-supplied pointer to a NULL-terminated string representing a device instance identifier. If this value is NULL, or if it points to a zero-length string, the function supplies a device instance handle to the device node at the top of the device tree.
ulFlags
One of the caller-supplied bit flags listed in the following table.
Flag Definition
CM_LOCATE_DEVNODE_NORMAL
(Default.) The function only searches for device nodes representing devices that are currently plugged into the system.
CM_LOCATE_DEVNODE_PHANTOM
The function searches both for device nodes representing devices that are currently plugged into the system, and for device nodes representing devices that are not currently plugged in (but were previously).
CM_LOCATE_DEVNODE_CANCELREMOVE
Not used.
CM_LOCATE_DEVNODE_NOVALIDATION
Not used.

hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

See Also

CM_Locate_DevNode


CM_Merge_Range_List

Do not use this function. Use device installation functions instead.


CM_Modify_Res_Des

The CM_Modify_Res_Des function modifies a specified resource descriptor on the local system.

CMAPI CONFIGRET WINAPI
  CM_Modify_Res_Des(
    OUT PRES_DES  prdResDes,
    IN RES_DES  rdResDes,
    IN RESOURCEID  ResourceID,
    IN PCVOID  ResourceData,
    IN ULONG  ResourceLen,
    IN ULONG  ulFlags
    );

Parameters

prdResDes
Pointer to a location to receive a handle to the modified resource descriptor.
rdResDes
Caller-supplied handle to the resource descriptor to be modified. This handle must have been previously obtained by calling one of the following functions:

CM_Add_Res_Des
CM_Add_Res_Des_Ex
CM_Get_Next_Res_Des
CM_Get_Next_Res_Des_Ex
CM_Modify_Res_Des
CM_Modify_Res_Des_Ex

ResourceID
Caller-supplied resource type identifier. This must be one of the ResType_-prefixed constants defined in cfgmgr32.h.
ResourceData
Caller-supplied pointer to a resource descriptor, which can be one of the structures listed under the CM_Add_Res_Des function's description of ResourceData.
ResourceLen
Caller-supplied length of the structure pointed to by ResourceData.
ulFlags
Not used, must be zero.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

The caller-supplied resource descriptor data replaces the existing data. The values specified for ResourceID and ResourceLen do not have to match the existing resource descriptor.

If the value specified for ResourceID is ResType_ClassSpecific, then the specified resource descriptor must be the last one associated with the logical configuration.

Callers of CM_Modify_Res_Des must call CM_Free_Res_Des_Handle to deallocate the resource descriptor handle, after it is no longer needed.

Callers of this function must have SeLoadDriverPrivilege. (Privileges are described in Platform SDK documentation.)

See Also

CM_Modify_Res_Des_Ex


CM_Modify_Res_Des_Ex

The CM_Modify_Res_Des_Ex function modifies a specified resource descriptor on a local or remote system.

CMAPI CONFIGRET WINAPI
  CM_Modify_Res_Des_Ex(
    OUT PRES_DES  prdResDes,
    IN RES_DES  rdResDes,
    IN RESOURCEID  ResourceID,
    IN PCVOID  ResourceData,
    IN ULONG  ResourceLen,
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

prdResDes
Pointer to a location to receive a handle to the modified resource descriptor.
rdResDes
Caller-supplied handle to the resource descriptor to be modified. This handle must have been previously obtained by calling one of the following functions:

CM_Add_Res_Des
CM_Add_Res_Des_Ex
CM_Get_Next_Res_Des
CM_Get_Next_Res_Des_Ex
CM_Modify_Res_Des
CM_Modify_Res_Des_Ex

ResourceID
Caller-supplied resource type identifier. This must be one of the ResType_-prefixed constants defined in cfgmgr32.h.
ResourceData
Caller-supplied pointer to a resource descriptor, which can be one of the structures listed under the CM_Add_Res_Des_Ex function's description of ResourceData.
ResourceLen
Caller-supplied length of the structure pointed to by ResourceData.
ulFlags
Not used, must be zero.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

The caller-supplied resource descriptor data replaces the existing data. The values specified for ResourceID and ResourceLen do not have to match the existing resource descriptor.

If the value specified for ResourceID is ResType_ClassSpecific, then the specified resource descriptor must be the last one associated with the logical configuration.

Callers of CM_Modify_Res_Des_Ex must call CM_Free_Res_Des_Handle to deallocate the resource descriptor handle, after it is no longer needed.

Callers of this function must have SeLoadDriverPrivilege. (Privileges are described in Platform SDK documentation.)

See Also

CM_Modify_Res_Des


CM_Move_DevNode

Do not use this function. Use device installation functions instead.


CM_Move_DevNode_Ex

Do not use this function. Use device installation functions instead.


CM_Next_Range

Do not use this function. Use device installation functions instead.


CM_Open_Class_Key

Do not use this function. Use device installation functions instead.


CM_Open_Class_Key_Ex

Do not use this function. Use device installation functions instead.


CM_Open_DevNode_Key

Do not use this function. Use device installation functions instead.


CM_Open_DevNode_Key_Ex

Do not use this function. Use device installation functions instead.


CM_Query_And_Remove_SubTree

The CM_Query_And_Remove_SubTree function checks whether a device instance and its children can be removed and, if so, it removes them.

CMAPI CONFIGRET WINAPI
  CM_Query_And_Remove_SubTree(
    IN  DEVINST dnAncestor,
    OUT PPNP_VETO_TYPE pVetoType,
    OUT LPTSTR pszVetoName,
    IN  ULONG ulNameLength,
    IN  ULONG ulFlags
    );

Parameters

dnAncestor
Caller-supplied handle of the device at the root of the subtree to be removed.
pVetoType
(Optional.) If not NULL, this points to a location that, if the removal request fails, receives a PNP_VETO_TYPE-typed value indicating the reason for the failure.
pszVetoName
(Optional.) If not NULL, this is a caller-supplied pointer to a string buffer that receives a text string. The type of information this string provides is dependent on the value received by pVetoType. For information about these strings, see PNP_VETO_TYPE.
ulNameLength
(Optional.) Caller-supplied value representing the length (number of characters) of the string buffer supplied by pszVetoName. This should be set to MAX_PATH.
ulFlags
Caller-supplied flag values. The following flags are defined.
Flag | Meaning
CM_REMOVE_UI_OK | Not used.
CM_REMOVE_UI_NOT_OK | Not used.
CM_REMOVE_NO_RESTART | System restart is required.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

The purpose of the CM_Query_And_Remove_SubTree function is to allow an application to prepare a device for safe removal from the local system. Use this function to remove devices only if a driver has not set the SurpriseRemovalOK member of DEVICE_CAPABILITIES. If a driver has set SurpriseRemovalOK, the application should call CM_Request_Device_Eject instead of CM_Query_And_Remove_SubTree.

See Also

CM_Query_And_Remove_SubTree_Ex
CM_Request_Device_Eject
CM_Request_Device_Eject_Ex


CM_Query_And_Remove_SubTree_Ex

The CM_Query_And_Remove_SubTree_Ex function checks whether a device instance and its children can be removed and, if so, it removes them.

CMAPI CONFIGRET WINAPI
  CM_Query_And_Remove_SubTree_Ex(
    IN  DEVINST dnAncestor,
    OUT PPNP_VETO_TYPE pVetoType,
    OUT LPTSTR pszVetoName,
    IN  ULONG ulNameLength,
    IN  ULONG ulFlags
    IN  HMACHINE hMachine
    );

Parameters

dnAncestor
Caller-supplied handle of the device at the root of the subtree to be removed.
pVetoType
(Optional.) If not NULL, this points to a location that, if the removal request fails, receives a PNP_VETO_TYPE-typed value indicating the reason for the failure.
pszVetoName
(Optional.) If not NULL, this is a caller-supplied pointer to a string buffer that receives a text string. The type of information this string provides is dependent on the value received by pVetoType. For information about these strings, see PNP_VETO_TYPE.
ulNameLength
(Optional.) Caller-supplied value representing the length (number of characters) of the string buffer supplied by pszVetoName. This should be set to MAX_PATH.
ulFlags
Caller-supplied flag values. The following flags are defined.
Flag | Meaning
CM_REMOVE_UI_OK | Not used.
CM_REMOVE_UI_NOT_OK | Not used.
CM_REMOVE_NO_RESTART | System restart is required.

hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

The purpose of the CM_Query_And_Remove_SubTree_Ex function is to allow an application to prepare a device for safe removal from a remote system. Use this function to remove devices only if a driver has not set the SurpriseRemovalOK member of DEVICE_CAPABILITIES. If a driver has set SurpriseRemovalOK, the application should call CM_Request_Device_Eject_Ex instead of CM_Query_And_Remove_SubTree_Ex.

See Also

CM_Query_And_Remove_SubTree
CM_Request_Device_Eject
CM_Request_Device_Eject_Ex


CM_Query_Arbitrator_Free_Data

Do not use this function. Use device installation functions instead.


CM_Query_Arbitrator_Free_Data_Ex

Do not use this function. Use device installation functions instead.


CM_Query_Arbitrator_Free_Size

Do not use this function. Use device installation functions instead.


CM_Query_Arbitrator_Free_Size_Ex

Do not use this function. Use device installation functions instead.


CM_Query_Remove_SubTree

Do not use this function. Use device installation functions instead.


CM_Query_Remove_SubTree_Ex

Do not use this function. Use device installation functions instead.


CM_Query_Resource_Conflict_List

The CM_Query_Resource_Conflict_List function identifies device instances having resource requirements that conflict with a specified device instance's resource description.

CMAPI CONFIGRET WINAPI
  CM_Query_Resource_Conflict_List(
    OUT PCONFLICT_LIST  pclConflictList,
    IN DEVINST  dnDevInst,
    IN RESOURCEID  ResourceID,
    IN PCVOID  ResourceData,
    IN ULONG  ResourceLen,
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

pclConflictList
Caller-supplied address of a location to receive a handle to a conflict list.
dnDevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Locate_DevNode
CM_Locate_DevNode_Ex
CM_Get_Child
CM_Get_Child_Ex
CM_Get_Parent
CM_Get_Parent_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

ResourceID
Caller-supplied resource type identifier. This must be one of the ResType_-prefixed constants defined in cfgmgr32.h.
ResourceData
Caller-supplied pointer to a resource descriptor, which can be one of the structures listed under the CM_Add_Res_Des function's description of ResourceData.
ResourceLen
Caller-supplied length of the structure pointed to by ResourceData.
ulFlags
Not used, must be zero.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

When calling CM_Query_Resource_Conflict_List, specify a device instance handle and resource descriptor. (Resource descriptors for existing device nodes can be obtained by calling CM_Get_Res_Des_Data.) These parameters indicate the specific resources you'd like a specific device to use. The resulting conflict list identifies devices that use the same resources, along with resources reserved by the system.

After calling CM_Query_Resource_Conflict_List, an application can call CM_Get_Resource_Conflict_Count to determine the number of conflicts contained in the resource conflict list. (The number of conflicts can be zero.) Then the application can call CM_Get_Resource_Conflict_Details for each entry in the conflict list.

After an application has finished using the handle received for pclConflictList, it must call CM_Free_Resource_Conflict_handle.


CM_Reenumerate_DevNode

The CM_Reenumerate_DevNode function enumerates the devices identified by a specified device node and all of its children.

CMAPI CONFIGRET WINAPI
  CM_Reenumerate_DevNode(
    IN DEVINST  dnDevInst,
    IN ULONG  ulFlags
    );

Parameters

dnDevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Locate_DevNode
CM_Locate_DevNode_Ex
CM_Get_Child
CM_Get_Child_Ex
CM_Get_Parent
CM_Get_Parent_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

ulFlags
Not used, must be zero.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

If the specified device node represents a hardware or software bus device, the PnP Manager queries the device's drivers for a list of children, then attempts to configure and start any child devices that were not previously configured. The PnP Manager also initiates surprise-removal of devices that are no longer present (see IRP_MN_SURPRISE_REMOVAL).

Callers of this function must have SeLoadDriverPrivilege. (Privileges are described in Platform SDK documentation.)

See Also

CM_Reenumerate_DevNode_Ex


CM_Reenumerate_DevNode_Ex

The CM_Reenumerate_DevNode_Ex function enumerates the devices identified by a specified device node and all of its children.

CMAPI CONFIGRET WINAPI
  CM_Reenumerate_DevNode_Ex(
    IN DEVINST  dnDevInst,
    IN ULONG  ulFlags,
    IN HMACHINE  hMachine
    );

Parameters

dnDevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Locate_DevNode
CM_Locate_DevNode_Ex
CM_Get_Child
CM_Get_Child_Ex
CM_Get_Parent
CM_Get_Parent_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

ulFlags
Not used, must be zero.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

If the specified device node represents a hardware or software bus device, the PnP Manager queries the device's drivers for a list of children, then attempts to configure and start any child devices that were not previously configured. The PnP Manager also initiates surprise-removal of devices that are no longer present (see IRP_MN_SURPRISE_REMOVAL).

Callers of this function must have SeLoadDriverPrivilege. (Privileges are described in Platform SDK documentation.)

See Also

CM_Reenumerate_DevNode


CM_Register_Device_Driver

Do not use this function. Use device installation functions instead.


CM_Register_Device_Driver_Ex

Do not use this function. Use device installation functions instead.


CM_Register_Device_Interface

Do not use this function. Use device installation functions instead.


CM_Register_Device_Interface_Ex

Do not use this function. Use device installation functions instead.


CM_Remove_SubTree

Do not use this function. Use device installation functions instead.


CM_Remove_SubTree_Ex

Do not use this function. Use device installation functions instead.


CM_Request_Device_Eject

The CM_Request_Device_Eject function prepares a local device instance for safe removal, if the device is removable. If the device can be physically ejected, it will be.

CMAPI CONFIGRET WINAPI
  CM_Request_Device_Eject(
    IN DEVINST  dnDevInst,
    OUT PPNP_VETO_TYPE  pVetoType,
    OUT LPTSTR  pszVetoName,
    IN ULONG  ulNameLength,
    IN ULONG  ulFlags
    );

Parameters

dnDevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Locate_DevNode
CM_Locate_DevNode_Ex
CM_Get_Child
CM_Get_Child_Ex
CM_Get_Parent
CM_Get_Parent_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

pVetoType
(Optional.) If not NULL, this points to a location that, if the removal request fails, receives a PNP_VETO_TYPE-typed value indicating the reason for the failure.
pszVetoName
(Optional.) If not NULL, this is a caller-supplied pointer to a string buffer that receives a text string. The type of information this string provides is dependent on the value received by pVetoType. For information about these strings, see PNP_VETO_TYPE.
ulNameLength
(Optional.) Caller-supplied value representing the length of the string buffer supplied by pszVetoName. This should be set to MAX_PATH.
ulFlags
Not used.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

If pszVetoName is NULL, the PnP Manager displays a message to the user indicating the device was removed or, if the request failed, identifying the reason for the failure. If pszVetoName is not NULL, the PnP Manager does not display a message. (Note, however, that for Windows 2000 only, the PnP Manager displays a message even if pszVetoName is not NULL, if the device's CM_DEVCAP_DOCKDEVICE capability is set.)

Callers of CM_Request_Eject sometimes require SeUndockPrivilege or SeLoadDriverPrivilege, as follows:

  • If the device's CM_DEVCAP_DOCKDEVICE capability is set, callers must have SeUndockPrivilege. (SeLoadDriverPrivilege is not required.)
  • If the device's CM_DEVCAP_DOCKDEVICE capability is not set, and if the calling process is not interactive or is running in a multi-user environment in a session not attached to the physical console (such as a remote Terminal Services session) callers of this function must have SeLoadDriverPrivilege.

(Privileges are described in Platform SDK documentation.)

See Also

CM_Request_Device_Eject_Ex
CM_Query_And_Remove_SubTree
CM_Query_And_Remove_SubTree_Ex


CM_Request_Device_Eject_Ex

The CM_Request_Device_Eject function prepares a local or remote device instance for safe removal, if the device is removable. If the device can be physically ejected, it will be.

CMAPI CONFIGRET WINAPI
  CM_Request_Device_Eject_Ex(
    IN DEVINST  dnDevInst,
    OUT PPNP_VETO_TYPE  pVetoType,
    OUT LPTSTR  pszVetoName,
    IN ULONG  ulNameLength,
    IN ULONG  ulFlags
    IN HMACHINE  hMachine
    );

Parameters

dnDevInst
Caller-supplied device instance handle, obtained from the SP_DEVINFO_DATA structure that is used with the device installation functions.

Device instance handles can also be obtained by calling the following functions:

CM_Locate_DevNode
CM_Locate_DevNode_Ex
CM_Get_Child
CM_Get_Child_Ex
CM_Get_Parent
CM_Get_Parent_Ex
CM_Get_Sibling
CM_Get_Sibling_Ex

pVetoType
(Optional.) If not NULL, this points to a location that, if the removal request fails, receives a PNP_VETO_TYPE-typed value indicating the reason for the failure.
pszVetoName
(Optional.) If not NULL, this is a caller-supplied pointer to a string buffer that receives a text string. The type of information this string provides is dependent on the value received by pVetoType. For information about these strings, see PNP_VETO_TYPE.
ulNameLength
(Optional.) Caller-supplied value representing the length of the string buffer supplied by pszVetoName. This should be set to MAX_PATH.
ulFlags
Not used.
hMachine
Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.

Return Value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h.

Headers

Declared in cfgmgr32.h. Include cfgmgr32.h.

Comments

If pszVetoName is NULL, the PnP Manager displays a message to the user indicating the device was removed or, if the request failed, identifying the reason for the failure. If pszVetoName is not NULL, the PnP Manager does not display a message. (Note, however, that for Windows 2000 only, the PnP Manager displays a message even if pszVetoName is not NULL, if the device's CM_DEVCAP_DOCKDEVICE capability is set.)

For remote systems, this function only works for "dock" device instances. That is, the function can only be used remotely to undock a system. In that case, the caller must have SeUndockPrivilege.

Callers of CM_Request_Eject sometimes require SeUndockPrivilege or SeLoadDriverPrivilege, as follows:

  • If the device's CM_DEVCAP_DOCKDEVICE capability is set, callers must have SeUndockPrivilege. (SeLoadDriverPrivilege is not required.)
  • If the device's CM_DEVCAP_DOCKDEVICE capability is not set, and if the calling process is not interactive or is running in a multi-user environment in a session not attached to the physical console (such as a remote Terminal Services session) callers of this function must have SeLoadDriverPrivilege.

(Privileges are described in Platform SDK documentation.)

See Also

CM_Request_Device_Eject
CM_Query_And_Remove_SubTree
CM_Query_And_Remove_SubTree_Ex


CM_Request_Eject_PC

Do not use this function. Use device installation functions instead.


CM_Request_Eject_PC_Ex

Do not use this function. Use device installation functions instead.


CM_Run_Detection

Do not use this function. Use device installation functions instead.


CM_Run_Detection_Ex

Do not use this function. Use device installation functions instead.


CM_Set_Class_Registry_Property

Do not use this function. Use device installation functions instead.


CM_Set_DevNode_Problem

Do not use this function. Use device installation functions instead.


CM_Set_DevNode_Problem_Ex

Do not use this function. Use device installation functions instead.


CM_Set_DevNode_Registry_Property

Do not use this function. Use device installation functions instead.


CM_Set_DevNode_Registry_Property_Ex

Do not use this function. Use device installation functions instead.


CM_Set_HW_Prof

Do not use this function. Use device installation functions instead.


CM_Set_HW_Prof_Ex

Do not use this function. Use device installation functions instead.


CM_Set_HW_Prof_Flags

Do not use this function. Use device installation functions instead.


CM_Set_HW_Prof_Flags_Ex

Do not use this function. Use device installation functions instead.


CM_Setup_DevNode

Do not use this function. Use device installation functions instead.


CM_Setup_DevNode_Ex

Do not use this function. Use device installation functions instead.


CM_Test_Range_Available

Do not use this function. Use device installation functions instead.


CM_Uninstall_DevNode

Do not use this function. Use device installation functions instead.


CM_Uninstall_DevNode_Ex

Do not use this function. Use device installation functions instead.


CM_Unregister_Device_Interface

Do not use this function. Use device installation functions instead.


CM_Unregister_Device_Interface_Ex

Do not use this function. Use device installation functions instead.


CM_WaitNoPendingInstallEvents

CM_WaitNoPendingInstallEvents is defined in cfgmgr32.h as follows:

#define CM_WaitNoPendingInstallEvents CMP_WaitNoPendingInstallEvents

In other words, CM_WaitNoPendingInstallEvents is simply another name for CMP_WaitNoPendingInstallEvents. Since there is no actual function named CM_WaitNoPendingInstallEvents, GetProcAddress will return NULL.


CMP_WaitNoPendingInstallEvents

The CMP_WaitNoPendingInstallEvents function waits until there are no pending device installation activities for the PnP Manager to perform.

DWORD WINAPI
CMP_WaitNoPendingInstallEvents(
    IN DWORD dwTimeout
    );

Parameters

dwTimeout
Specifies a time-out interval, in milliseconds.
  • If dwTimeout is set to zero, the function tests whether there are pending installation events and returns immediately.
  • If dwTimeout is set to INFINITE (defined in winbase.h), the function's time-out interval never elapses.
  • For all other dwTimeout values, the function returns when the specified interval elapses, even if there are still pending installation events.

Return Value

The function returns one of the following values (defined in winbase.h):

WAIT_OBJECT_0
There are no pending installation activities.
WAIT_TIMEOUT
The time-out interval elapsed, and installation activities are still pending.
WAIT_FAILED
The function failed. Call GetLastError for additional error information.

Headers

Defined in cfgmgr32.h. Include cfgmgr32.h. Link with cfgmgr32.dll.

Comments

The function waits for an internal event object, which the PnP Manager sets when it determines that no installation activities are pending.

If a non-zero time-out value is specified, then CMP_WaitNoPendingInstallEvents will return either when no installation events are pending or when the time-out period has expired, whichever comes first. This routine is intended to be called only after a user has logged on.

New installation events can occur at any time. This function just indicates that there are no pending installation activities at the moment it is called.

This function is typically used by device installation applications. For more information, see Writing a Device Installation Application.

This function is not available on Windows 95/98/Me.

See Also

CM_WaitNoPendingInstallEvents


PnP Configuration Manager Structures and Types

This section describes the structures and types used with PnP Configuration Manager functions.


Resource Descriptor Structures

This section describes the structures used to specify resource descriptors.


BUSNUMBER_DES

The BUSNUMBER_DES structure is used for specifying either a resource list or a resource requirements list that describes bus number usage for a device instance.

typedef struct BusNumber_Des_s {
  DWORD  BUSD_Count;
  DWORD  BUSD_Type;
  DWORD  BUSD_Flags;
  ULONG  BUSD_Alloc_Base;
  ULONG  BUSD_Alloc_End;
} BUSNUMBER_DES, *PBUSNUMBER_DES;

Members

BUSD_Count
For a resource list:
Zero.
For a resource requirements list:
The number of elements in the BUSNUMBER_RANGE array that is included in the BUSNUMBER_RESOURCE structure.
BUSD_Type
Must be set to the constant value BusNumberType_Range.
BUSD_Flags
Not used.
BUSD_Alloc_Base
For a resource list:
The lowest-numbered of a range of contiguous bus numbers allocated to the device.
For a resource requirements list:
Zero.
BUSD_Alloc_End
For a resource list:
The highest-numbered of a range of contiguous bus numbers allocated to the device.
For a resource requirements list:
Zero.

Comments

The BUSNUMBER_DES structure is included as a member of the BUSNUMBER_RESOURCE structure.


BUSNUMBER_RANGE

The BUSNUMBER_RANGE structure specifies a resource requirements list that describes bus number usage for a device instance.

typedef struct BusNumber_Range_s {
  ULONG  BUSR_Min;
  ULONG  BUSR_Max;
  ULONG  BUSR_nBusNumbers;
  ULONG  BUSR_Flags;
} BUSNUMBER_RANGE, *PBUSNUMBER_RANGE;

Members

BUSR_Min
The lowest-numbered of a range of contiguous bus numbers that can be allocated to the device.
BUSR_Max
The highest-numbered of a range of contiguous bus numbers that can be allocated to the device.
BUSR_nBusNumbers
The number of contiguous bus numbers required by the device.
BUSR_Flags
Not used.

Comments

The BUSNUMBER_RANGE structure is included as a member of the BUSNUMBER_RESOURCE structure.


BUSNUMBER_RESOURCE

The BUSNUMBER_RESOURCE structure specifies either a resource list or a resource requirements list that describes bus number usage for a device instance.

typedef struct BusNumber_Resource_s {
  BUSNUMBER_DES  BusNumber_Header;
  BUSNUMBER_RANGE  BusNumber_Data[ANYSIZE_ARRAY];
} BUSNUMBER_RESOURCE, *PBUSNUMBER_RESOURCE;

Members

BusNumber_Header
A BUSNUMBER_DES structure.
BusNumber_Data
For a resource list:
Zero.
For a resource requirements list:
A BUSNUMBER_RANGE array.


CS_DES

The CS_DES structure is used for specifying a resource list that describes device class-specific resource usage for a device instance.

typedef struct CS_Des_s {
  DWORD  CSD_SignatureLength;
  DWORD  CSD_LegacyDataOffset;
  DWORD  CSD_LegacyDataSize;
  DWORD  CSD_Flags;
  GUID  CSD_ClassGuid;
  BYTE  CSD_Signature[ANYSIZE_ARRAY];
} CS_DES, *PCS_DES;

Members

CSD_SignatureLength
The number of elements in the byte array specified by CSD_Signature.
CSD_LegacyDataOffset
Offset, in bytes, from the beginning of the CSD_Signature array to the beginning of a block of data. For example, if the data block follows the signature array, and if the signature array length is 16 bytes, then the value for CSD_LegacyDataOffset should be 16.
CSD_LegacyDataSize
Length, in bytes, of the data block whose offset is specified by CSD_LegacyDataOffset.
CSD_Flags
Not used.
CSD_ClassGuid
A globally unique identifier (GUID) identifying a device setup class. If both CSD_SignatureLength and CSD_LegacyDataSize are zero, the GUID is null.
CSD_Signature
A byte array containing a class-specific signature.

Comments

The data block identified by CSD_LegacyDataSize and CSD_LegacyDataOffset can contain legacy, class-specific data, as stored in the DeviceSpecificData member of a CM_PARTIAL_RESOURCE_DESCRIPTOR structure, if the structure's Type member is CmResourceTypeDeviceSpecific.

The class-specific signature identified by CSD_SignatureLength and CSD_Signature can contain additional class-specific device identification information.


CS_RESOURCE

The CS_RESOURCE structure is used for specifying a resource list that describes device class-specific resource usage for a device instance.

typedef struct CS_Resource_s {
   CS_DES  CS_Header;
} CS_RESOURCE, *PCS_RESOURCE;

Members

CS_Header
A CS_DES structure.


DEVPRIVATE_DES

The DEVPRIVATE_DES structure is used for specifying either a resource list or a resource requirements list that describes private device-specific resource usage for a device instance. This structure is for internal use only.

typedef struct DevPrivate_Des_s {
  DWORD  PD_Count;
  DWORD  PD_Type;
  DWORD  PD_Data1;
  DWORD  PD_Data2;
  DWORD  PD_Data3;
  DWORD  PD_Flags;
} DEVPRIVATE_DES, *PDEVPRIVATE_DES;


DEVPRIVATE_RANGE

The DEVPRIVATE_RANGE structure specifies a resource requirements list that describes private device-specific resource usage for a device instance. This structure is for internal use only.

typedef struct DevPrivate_Range_s {
   DWORD  PR_Data1;  // mask for base alignment
   DWORD  PR_Data2;  // number of bytes
   DWORD  PR_Data3;  // minimum address
} DEVPRIVATE_RANGE, *PDEVPRIVATE_RANGE;


DEVPRIVATE_RESOURCE

The DEVPRIVATE_RESOURCE structure is used for specifying either a resource list or a resource requirements list that describes private device-specific resource usage for a device instance. This structure is for internal use only.

typedef struct DevPrivate_Resource_s {
  DEVPRIVATE_DES  PRV_Header;
  DEVPRIVATE_RANGE  PRV_Data[ANYSIZE_ARRAY];
} DEVPRIVATE_RESOURCE, *PDEVPRIVATE_RESOURCE;


DMA_DES

The DMA_DES structure is used for specifying either a resource list or a resource requirements list that describes direct memory access (DMA) channel usage for a device instance.

typedef struct DMA_Des_s {
  DWORD  DD_Count;
  DWORD  DD_Type;
  DWORD  DD_Flags;
  ULONG  DD_Alloc_Chan;
} DMA_DES, *PDMA_DES;

Members

DD_Count
For a resource list:
Zero.
For a resource requirements list:
The number of elements in the DMA_RANGE array that is included in the DMA_RESOURCE structure.
DD_Type
Must be set to the constant value DType_Range.
DD_Flags
One bit flag from each of the flag sets described in the following table.
Flag | Definition
Channel Width Flags
fDD_BYTE | 8-bit DMA channel.
fDD_WORD | 16-bit DMA channel.
fDD_DWORD | 32-bit DMA channel.
fDD_BYTE_AND_WORD | 8-bit and 16-bit DMA channel.
mDD_Width | Bit mask for the bits within DD_Flags that specify the channel width value.
Bus Mastering Flags
fDD_NoBusMaster | No bus mastering.
fDD_BusMaster | Bus mastering.
mDD_BusMaster | Bit mask for the bits within DD_Flags that specify the bus mastering value.
DMA Type Flags
fDD_TypeStandard | Standard DMA.
fDD_TypeA | Type A DMA.
fDD_TypeB | Type B DMA.
fDD_TypeF | Type F DMA.
mDD_Type | Bit mask for the bits within DD_Flags that specify the DMA type value.

DD_Alloc_Chan
For a resource list:
The DMA channel allocated to the device.
For a resource requirements list:
Not used.


DMA_RANGE

The DMA_RANGE structure specifies a resource requirements list that describes DMA channel usage for a device instance.

typedef struct DMA_Range_s {
  ULONG  DR_Min;
  ULONG  DR_Max;
  ULONG  DR_Flags;
} DMA_RANGE, *PDMA_RANGE;

Members

DR_Min
The lowest-numbered DMA channel that can be allocated to the device.
DR_Max
The highest-numbered DMA channel that can be allocated to the device.
DR_Flags
One bit flag from each of the flag sets described in the table included with the description of the DR_Flags member of the DMA_DES structure.


DMA_RESOURCE

The DMA_RESOURCE structure is used for specifying either a resource list or a resource requirements list that describes DMA channel usage for a device instance.

typedef struct DMA_Resource_s {
  DMA_DES  DMA_Header;
  DMA_RANGE  DMA_Data[ANYSIZE_ARRAY];
} DMA_RESOURCE, *PDMA_RESOURCE;

Members

DMA_Header
A DMA_DES structure.
DMA_Data
For a resource list:
Zero.
For a resource requirements list:
A DMA_RANGE array.


IO_DES

The IO_DES structure is used for specifying either a resource list or a resource requirements list that describes I/O port usage for a device instance.

typedef struct IO_Des_s {
  DWORD  IOD_Count;
  DWORD  IOD_Type;
  DWORDLONG  IOD_Alloc_Base;
  DWORDLONG  IOD_Alloc_End;
  DWORD  IOD_DesFlags;
} IO_DES, *PIO_DES;

Members

IOD_Count
For a resource list:
Zero.
For a resource requirements list:
The number of elements in the IO_RANGE array that is included in the IO_RESOURCE structure.
IOD_Type
Must be set to the constant value IOType_Range.
IOD_Alloc_Base
For a resource list:
The lowest-numbered of a range of contiguous I/O port addresses allocated to the device.
For a resource requirements list:
Zero.
IOD_Alloc_End
For a resource list:
The highest-numbered of a range of contiguous I/O port addresses allocated to the device.
For a resource requirements list:
Zero.
IOD_DesFlags
One bit flag from each of the flag sets described in the following table.
Flag | Definition
Port Type Flags
fIOD_IO | The device is accessed in I/O address space.
fIOD_Memory | The device is accessed in memory address space.
fIOD_PortType | Bit mask for the bits within IOD_DesFlags that specify the port type value.
Decode Flags
fIOD_10_BIT_DECODE | The device decodes 10 bits of the port address.
fIOD_12_BIT_DECODE | The device decodes 12 bits of the port address.
fIOD_16_BIT_DECODE | The device decodes 16 bits of the port address.
fIOD_POSITIVE_DECODE | The device uses "positive decode" instead of "subtractive decode."
fIOD_DECODE | Bit mask for the bits within IOD_DesFlags that specify the decode value.


IO_RANGE

The IO_RANGE structure specifies a resource requirements list that describes I/O port usage for a device instance.

typedef struct IO_Range_s {
  DWORDLONG  IOR_Align;
  DWORD  IOR_nPorts;
  DWORDLONG  IOR_Min;
  DWORDLONG  IOR_Max;
  DWORD  IOR_RangeFlags;
  DWORDLONG  IOR_Alias;
} IO_RANGE, *PIO_RANGE;

Members

IOR_Align
Mask used to specify the port address boundary on which the first allocated I/O port address must be aligned.
IOR_nPorts
The number of I/O port addresses required by the device.
IOR_Min
The lowest-numbered of a range of contiguous I/O port addresses that can be allocated to the device.
IOR_Max
The highest-numbered of a range of contiguous I/O port addresses that can be allocated to the device.
IOR_RangeFlags
One bit flag from each of the flag sets described in the table included with the description of the IOD_DesFlags member of the IO_DES structure. For more information, see the following Comments section.
IOR_Alias
One of the bit flags described in the following table.
Flag | Definition
IO_ALIAS_10_BIT_DECODE | The device decodes 10 bits of the port address.
IO_ALIAS_12_BIT_DECODE | The device decodes 12 bits of the port address.
IO_ALIAS_16_BIT_DECODE | The device decodes 16 bits of the port address.
IO_ALIAS_POSITIVE_DECODE | The device uses "positive decode" instead of "subtractive decode."

For more information, see the following Comments section.

Comments

The flags specified for IOR_Alias have the same interpretation as the address decoding flags specified for IOD_DesFlags. (However, the two sets of flags are not equivalent in assigned values and cannot be used interchangeably.) A resource requirements list can be specified using either set of flags, but using decode flags in IOD_DesFlags is recommended. If address decoding flags are specified using both IOD_DesFlags and IOR_Alias, contents of the latter overrides the former.


IO_RESOURCE

The IO_RESOURCE structure is used for specifying either a resource list or a resource requirements list that describes I/O port usage for a device instance.

typedef struct IO_Resource_s {
  IO_DES  IO_Header;
  IO_RANGE  IO_Data[ANYSIZE_ARRAY];
} IO_RESOURCE, *PIO_RESOURCE;

Members

IO_Header
An IO_DES structure.
IO_Data
For a resource list:
Zero.
For a resource requirements list:
An IO_RANGE array.


IRQ_DES

The IRQ_DES structure is used for specifying either a resource list or a resource requirements list that describes IRQ line usage for a device instance.

typedef struct IRQ_Des_s {
  DWORD  IRQD_Count;
  DWORD  IRQD_Type;
  DWORD  IRQD_Flags;
  ULONG  IRQD_Alloc_Num;
  ULONG  IRQD_Affinity;
} IRQ_DES, *PIRQ_DES;

Members

IRQD_Count
For a resource list:
Zero.
For a resource requirements list:
The number of elements in the IRQ_RANGE array that is included in the IRQ_RESOURCE structure.
IRQD_Type
Must be set to the constant value IRQType_Range.
IRQD_Flags
One bit flag from each of the flag sets described in the following table.
Flag | Definition
Sharing Flags
fIRQD_Exclusive | The IRQ line cannot be shared.
fIRQD_Share | The IRQ line can be shared.
mIRQD_Share | Bit mask for the bits within IRQD_Flags that specify the sharing value.
Triggering Flags
fIRQD_Level | The IRQ line is level-triggered.
fIRQD_Edge | The IRQ line is edge-triggered.
mIRQD_Edge_Level | Bit mask for the bits within IRQD_Flags that specify the triggering value.

IRQD_Alloc_Num
For a resource list:
The number of the IRQ line that is allocated to the device.
For a resource requirements list:
Not used.
IRQD_Affinity
For a resource list:
A bit mask representing the processor affinity of the IRQ line that is allocated to the device. Bit zero represents the first processor, bit two the second, and so on. Set this value to -1 to represent all processors.
For a resource requirements list:
Not used.


IRQ_RANGE

The IRQ_RANGE structure specifies a resource requirements list that describes IRQ line usage for a device instance.

typedef struct IRQ_Range_s {
  ULONG  IRQR_Min;  // minimum IRQ in the range
  ULONG  IRQR_Max;  // maximum IRQ in the range
  ULONG  IRQR_Flags;  // flags describing the range (fIRQD flags)
} IRQ_RANGE, *PIRQ_RANGE;

Members

IRQR_Min
The lowest-numbered of a range of contiguous IRQ lines that can be allocated to the device.
IRQR_Max
The highest-numbered of a range of contiguous IRQ lines that can be allocated to the device.
IRQR_Flags
One bit flag from each of the flag sets described in the table included with the description of the IRQD_Flags member of the IRQ_DES structure.


IRQ_RESOURCE

The IRQ_RESOURCE structure is used for specifying either a resource list or a resource requirements list that describes IRQ line usage for a device instance.

typedef struct IRQ_Resource_s {
  IRQ_DES  IRQ_Header;
  IRQ_RANGE  IRQ_Data[ANYSIZE_ARRAY];
} IRQ_RESOURCE, *PIRQ_RESOURCE;

Members

IO_Header
An IRQ_DES structure.
IO_Data
For a resource list:
Zero.
For a resource requirements list:
An IRQ_RANGE array.


MEM_DES

The MEM_DES structure is used for specifying either a resource list or a resource requirements list that describes memory usage for a device instance.

typedef struct Mem_Des_s {
  DWORD  MD_Count;
  DWORD  MD_Type;
  DWORDLONG  MD_Alloc_Base;
  DWORDLONG  MD_Alloc_End;
  DWORD  MD_Flags;
  DWORD  MD_Reserved;
} MEM_DES, *PMEM_DES;

Members

MD_Count
For a resource list:
Zero.
For a resource requirements list:
The number of elements in the MEM_RANGE array that is included in the MEM_RESOURCE structure.
MD_Type
Must be set to the constant value MType_Range.
MD_Alloc_Base
For a resource list:
The lowest-numbered of a range of contiguous physical memory addresses allocated to the device.
For a resource requirements list:
Zero.
MD_Alloc_End
For a resource list:
The highest-numbered of a range of contiguous physical memory addresses allocated to the device.
For a resource requirements list:
Zero.
MD_Flags
One bit flag from each of the flag sets described in the following table.
Flag | Definition
Read-Only Flags
fMD_ROM | The specified memory range is read-only.
fMD_RAM | The specified memory range is not read-only.
mMD_MemoryType | Bit mask for the bit within MD_Flags that specifies the read-only attribute.
Write-Only Flags
fMD_ReadDisallowed | The specified memory range is write-only.
fMD_ReadAllowed | The specified memory range is not write-only.
mMD_Readable | Bit mask for the bit within MD_Flags that specifies the write-only attribute.
Address Size Flags
fMD_24 | 24-bit addressing (not used).
fMD_32 | 32-bit addressing.
mMD_32_24 | Bit mask for the bit within MD_Flags that specifies the address size.
Pre-Fetch Flags
fMD_PrefetchAllowed | The specified memory range can be prefetched.
fMD_PrefetchDisallowed | The specified memory range cannot be prefetched.
mMD_Prefetchable | Bit mask for the bit within MD_Flags that specifies the prefetch ability.
Caching Flags
fMD_Cacheable | The specified memory range can be cached.
fMD_NonCacheable | The specified memory range cannot be cached.
mMD_Cacheable | Bit mask for the bit within MD_Flags that specifies the caching ability.
Combined-Write Caching Flags
fMD_CombinedWriteAllowed | Combined-write caching is allowed.
fMD_CombinedWriteDisallowed | Combined-write caching is not allowed.
mMD_CombinedWrite | Bit mask for the bit within MD_Flags that specifies the combine-write caching ability.

MD_Reserved
For internal use only.


MEM_RANGE

The MEM_RANGE structure specifies a resource requirements list that describes memory usage for a device instance.

typedef struct Mem_Range_s {
  DWORDLONG  MR_Align;
  ULONG  MR_nBytes;
  DWORDLONG  MR_Min;
  DWORDLONG  MR_Max;
  DWORD  MR_Flags;
  DWORD  MR_Reserved;
} MEM_RANGE, *PMEM_RANGE;

Members

MR_Align
Mask used to specify the memory address boundary on which the first allocated memory address must be aligned.
MR_nBytes
The number of bytes of memory required by the device.
MR_Min
The lowest-numbered of a range of contiguous memory addresses that can be allocated to the device.
MR_Max
The highest-numbered of a range of contiguous memory addresses that can be allocated to the device.
MR_Flags
One bit flag from each of the flag sets described in the table included with the description of the MD_Flags member of the MEM_DES structure.
MR_Reserved
For internal use only.


MEM_RESOURCE

The MEM_RESOURCE structure is used for specifying either a resource list or a resource requirements list that describes memory usage for a device instance.

typedef struct Mem_Resource_s {
  MEM_DES  MEM_Header;
  MEM_RANGE  MEM_Data[ANYSIZE_ARRAY];
} MEM_RESOURCE, *PMEM_RESOURCE;

Members

MEM_Header
A MEM_DES structure.
MEM_Data
For a resource list:
Zero.
For a resource requirements list:
A MEM_RANGE array.


MFCARD_DES

The MFCARD_DES structure is used for specifying either a resource list or a resource requirements list that describes resource usage by one of the hardware functions provided by an instance of a multifunction device.

typedef struct MfCard_Des_s {
  DWORD  PMF_Count;
  DWORD  PMF_Type;
  DWORD  PMF_Flags;
  BYTE  PMF_ConfigOptions;
  BYTE  PMF_IoResourceIndex;
  BYTE  PMF_Reserved[2];
  DWORD  PMF_ConfigRegisterBase;
} MFCARD_DES, *PMFCARD_DES;

Members

PMF_Count
Must be 1.
PMF_Type
Not used.
PMF_Flags
One bit flag is defined, as described in the following table.
Flag | Definition
fPMF_AUDIO_ENABLE | If set, audio is enabled.

PMF_ConfigOptions
Contents of the 8-bit PCMCIA Configuration Option Register.
PMF_IoResourceIndex
Zero-based index indicating the IO_RESOURCE structure that describes the I/O resources for the hardware function being described by this MFCARD_DES structure.
PMF_Reserved
Not used.
PMF_ConfigRegisterBase
Offset from the beginning of the card's attribute memory space to the base configuration register address.


MFCARD_RESOURCE

The MFCARD_RESOURCE structure is used for specifying either a resource list or a resource requirements list that describes resource usage by one of the hardware functions provided by an instance of a multifunction device.

typedef struct MfCard_Resource_s {
  MFCARD_DES  MfCard_Header;
} MFCARD_RESOURCE, *PMFCARD_RESOURCE;

Members

MfCard_Header
A MFCARD_DES structure.


PCCARD_DES

The PCCARD_DES structure is used for specifying either a resource list or a resource requirements list that describes resource usage by a PCMCIA card instance.

typedef struct PcCard_Des_s {
  DWORD  PCD_Count;
  DWORD  PCD_Type;
  DWORD  PCD_Flags;
  BYTE  PCD_ConfigIndex;
  BYTE  PCD_Reserved[3];
  DWORD  PCD_MemoryCardBase1;
  DWORD  PCD_MemoryCardBase2;
} PCCARD_DES, *PPCCARD_DES;

Members

PCD_Count
Must be 1.
PCD_Type
Not used.
PCD_Flags
One bit flag from each of the flag sets described in the following table.
Flag | Definition
I/O Addressing Flags
fPCD_IO_8 | The device uses 8-bit I/O addressing.
fPCD_IO_16 | The device uses 16-bit I/O addressing.
mPCD_IO_8_16 | Bit mask for the bit within PCD_Flags that specifies 8-bit or 16-bit I/O addressing.
Memory Addressing Flags
fPCD_MEM_8 | The device uses 8-bit memory addressing.
fPCD_MEM_16 | The device uses 16-bit memory addressing.
mPCD_MEM_8_16 | Bit mask for the bit within PCD_Flags that specifies 8-bit or 16-bit memory addressing.

PCD_ConfigIndex
The 8-bit index value used to locate the device's configuration.
PCD_Reserved[3]
Not used.
PCD_MemoryCardBase1
Optional, card base address of the first memory window.
PCD_MemoryCardBase2
Optional, card base address of the second memory window.


PCCARD_RESOURCE

The PCCARD_RESOURCE structure is used for specifying either a resource list or a resource requirements list that describes resource usage by a PCMCIA card instance.

typedef struct PcCard_Resource_s {
   PCCARD_DES  PcCard_Header;
} PCCARD_RESOURCE, *PPCCARD_RESOURCE;

Members

PcCard_Header
A PCCARD_DES structure.


Other Structures

This sections describes additional PnP Configuration Manager structures.


CONFLICT_DETAILS

The CONFLICT_DETAILS structure is used as a parameter to the CM_Get_Resource_Conflict_Details function.

typedef struct _CONFLICT_DETAILS_W {
  ULONG  CD_ulSize;
  ULONG  CD_ulMask;
  DEVINST  CD_dnDevInst;
  RES_DES  CD_rdResDes;
  ULONG  CD_ulFlags;
  WCHAR  CD_szDescription[MAX_PATH];
} CONFLICT_DETAILS_W , *PCONFLICT_DETAILS_W;

Members

CD_ulSize
Size, in bytes, of the CONFLICT_DETAILS structure.
CD_ulMask
One or more bit flags supplied by the caller of CM_Get_Resource_Conflict_Details. The bit flags are described in the following table.
Flag | Description
CM_CDMASK_DEVINST | If set, CM_Get_Resource_Conflict_Details supplies a value for the CD_dnDevInst member.
CM_CDMASK_RESDES | Not used.
CM_CDMASK_FLAGS | If set, CM_Get_Resource_Conflict_Details supplies a value for the CD_ulFlags member.
CM_CDMASK_DESCRIPTION | If set, CM_Get_Resource_Conflict_Details supplies a value for the CD_szDescription member.

CD_dnDevInst
If CM_CDMASK_DEVINST is set in CD_ulMask, this member will receive a handle to a device instance that has conflicting resources. If a handle is not obtainable, the member receives -1.
CD_rdResDes
Not used.
CD_ulFlags
If CM_CDMASK_FLAGS is set in CD_ulMask, this member can receive bit flags listed in the following table.
Flag | Description
CM_CDFLAGS_DRIVER | If set, the string contained in the CD_szDescription member represents a driver name instead of a device name, and CD_dnDevInst is -1.
CM_CDFLAGS_ROOT_OWNED | If set, the conflicting resources are owned by the root device (that is, the HAL), and CD_dnDevInst is -1.
CM_CDFLAGS_RESERVED | If set, the owner of the conflicting resources cannot be determined, and CD_dnDevInst is -1.

CD_szDescription
If CM_CDMASK_DESCRIPTION is set in CD_ulMask, this member will receive a NULL-terminated text string representing a description of the device that owns the resources. If CM_CDFLAGS_DRIVER is set in CD_ulFlags, this string represents a driver name. If CM_CDFLAGS_ROOT_OWNED or CM_CDFLAGS_RESERVED is set, the string value is NULL.


PnP Configuration Manager Types

This section describes PnP Configuration Manager data types.


PNP_VETO_TYPE

If the PnP Manager rejects a request to perform an operation, the PNP_VETO_TYPE enumeration is used for identifying the reason for the rejection.

typedef enum _PNP_VETO_TYPE {
  PNP_VetoTypeUnknown,
  PNP_VetoLegacyDevice,
  PNP_VetoPendingClose,
  PNP_VetoWindowsApp,
  PNP_VetoWindowsService,
  PNP_VetoOutstandingOpen,
  PNP_VetoDevice,
  PNP_VetoDriver,
  PNP_VetoIllegalDeviceRequest,
  PNP_VetoInsufficientPower,
  PNP_VetoNonDisableable,
  PNP_VetoLegacyDriver,
}   PNP_VETO_TYPE, *PPNP_VETO_TYPE;

Enumerators

PNP_VetoTypeUnknown
The specified operation was rejected for an unknown reason.
PNP_VetoLegacyDevice
The device does not support the specified PnP operation.
PNP_VetoPendingClose
The specified operation cannot be completed because of a pending close operation.
PNP_VetoWindowsApp
A Microsoft® Win32® application vetoed the specified operation.
PNP_VetoWindowsService
A Win32 service vetoed the specified operation.
PNP_VetoOutstandingOpen
The requested operation was rejected because of outstanding open handles.
PNP_VetoDevice
The device supports the specified operation, but the device rejected the operation.
PNP_VetoDriver
The driver supports the specified operation, but the driver rejected the operation.
PNP_VetoIllegalDeviceRequest
The device does not support the specified operation.
PNP_VetoInsufficientPower
There is insufficient power to perform the requested operation.
PNP_VetoNonDisableable
The device cannot be disabled.
PNP_VetoLegacyDriver
The driver does not support the specified PnP operation.

Comments

Text strings are associated with most of the veto types, and a function that receives a veto type enumerator can typically request to also receive the enumerator's associated text string. The following table identifies the text string associated with each enumerator.

pVetoType | Text String
PNP_VetoTypeUnknown | None.
PNP_VetoLegacyDevice | A device instance path.
PNP_VetoPendingClose | A device instance path.
PNP_VetoWindowsApp | An application module name.
PNP_VetoWindowsService | A Windows service name.
PNP_VetoOutstandingOpen | A device instance path.
PNP_VetoDevice | A device instance path.
PNP_VetoDriver | A driver name.
PNP_VetoIllegalDeviceRequest | A device instance path.
PNP_VetoInsufficientPower | None.
PNP_VetoNonDisableable | A device instance path.
PNP_VetoLegacyDriver | A Windows service name.


The txtsetup.oem File Format

During the text-mode setup phase of operating system installation, the Setup program installs drivers for devices that are required to boot the machine. Most of these drivers are included with the operating system. A vendor can enable users to install an additional driver during text-mode setup by supplying a txtsetup.oem file on a floppy disk.

A txtsetup.oem file is a text file that contains the following information:

  • A list of the hardware components supported by the txtsetup.oem file
  • A list of the files to copy from the distribution disk for each component
  • A list of the registry keys and values to create for each component

This chapter describes the format of a txtsetup.oem file. For additional information, see Installing a Boot Driver.

A txtsetup.oem file consists of several sections that use the following general format:

[SectionName]
entry = value1,value2,...

The name of the section is enclosed in square brackets ([ ]). A pound sign (#) or semicolon character (;) at the beginning of a line indicates a comment. Strings with embedded spaces, commas, or hashes must be enclosed in double quotes (" ").

A txtsetup.oem file must include the following sections:

  • A Disks section

    See Disks Section of a txtsetup.oem File for further information.

  • A Defaults section

    See Defaults Section of a txtsetup.oem File for further information.

  • One or more HwComponent sections

    See HwComponent Section of a txtsetup.oem File for further information.

  • One or more Files.HwComponent.ID sections

    See Files.HwComponent.ID Section of a txtsetup.oem File for further information.

  • One or more Config.DriverKey sections

    See Config.DriverKey Section of a txtsetup.oem File for further information.

A txtsetup.oem file for a PnP mass storage device must also include the following section:

  • A HardwareIds.scsi.Service section

    See HardwareIds.scsi.Service Section of a txtsetup.oem File for further information.

A sample txtsetup.oem file is provided with this DDK, under the installed DDK's /src directory.


Disks Section of a txtsetup.oem File

The Disks section identifies the disks in the device installation kit. This section has the following format:

[Disks]
diskN = "description",tagfile,directory
...

diskN
Specifies a key that can be used in subsequent sections to identify the disk.
description
Specifies a string containing the name of the disk. Setup uses the description to prompt the user to insert the disk.
tagfile
Specifies the name of a verification file on the disk. The filename must be specified as a full path from the root and must not specify a drive. Setup checks for this file to ensure that the user inserted the correct disk.
directory
Specifies the directory on the disk where the installation files are located. The directory must be specified as a full path from the root and must not specify a drive.

The following example shows a Disks section for an installation kit with two disks:

[Disks]
disk1 = "OEM SCSI driver disk 1",\disk1.tag,\
disk2 = "OEM SCSI driver disk 2",\disk2.tag,\
; ...


Defaults Section of a txtsetup.oem File

The Defaults section lists the default driver(s) for each hardware component supported by this file. Setup highlights the default selection when it presents a list of drivers to the user.

[Defaults]
component = ID
...

component
Specifies a hardware component supported by this file. The component must be one of the following system-defined values: computer or scsi.
ID
Specifies a string that identifies the default option. This string matches an ID specified in the corresponding HwComponent section.

If a txtsetup.oem file fails to define a default driver for a supported component, Setup uses the first entry in the HwComponent section.

The following example shows a Defaults section (and the HwComponent section) for a txtsetup.oem file that supports one component (scsi):

; ...
[Defaults]
SCSI = oemscsi

[SCSI]                  ; HwComponent section
oemscsi = "OEM Fast SCSI Controller"
oemscsi2 = "OEM Fast SCSI Controller 2"

; ...


HwComponent Section of a txtsetup.oem File

A HwComponent section lists the drivers available for a particular component. There is a HwComponent section for each type of component supported by the file.

[HwComponent]
ID = description
...

HwComponent
The name of the section must be one of the following system-defined values: computer or scsi.
ID
Specifies a string, unique within this section, that identifies the option.

For each entry in this section, there must be a corresponding Files.HwComponent.ID section in the file.

For the computer component, the last three characters of the string determine which kernel Setup copies. If this string ends in "_up", Setup copies the uniprocessor kernel. If this string ends in "_mp", Setup copies the multiprocessor kernel. If the string does not end in "_Xp", Setup copies one or the other kernel, but does not guarantee which one.

description
Specifies a string that Setup presents to the user in the menu of driver choices.

The following example shows a HwComponent section for a txtsetup.oem file that supports one component (scsi) and offers two options:

; ...
[SCSI]                  ; HwComponent section
oemscsi = "OEM Fast SCSI Controller"
oemscsi2 = "OEM Fast SCSI Controller 2"

; ...


Files.HwComponent.ID Section of a txtsetup.oem File

A Files.HwComponent.ID section lists the files to be copied if the user selects a particular component option. One of these sections must be present for each option listed in each HwComponent section.

[Files.HwComponent.ID]
filetype = diskN,filename[,DriverKey]
...

Files.HwComponent.ID
HwComponent corresponds to the name of a HwComponent section in the file. ID corresponds to an ID entry in that HwComponent section.
filetype
Identifies the type of the file to be copied. One of these entries is present for each file to be copied for this HwComponent.ID.

The filetype is one of the following system-defined values:

driver
Valid for all components. Setup copies the file to %systemroot%\system32\drivers.
dll
Valid for all components. Useful for the GDI portion of a display driver. Setup copies the file to %systemroot%\system32.
hal
Valid only for the computer component. Setup copies the file to %systemroot%\system32\hal.dll (for x86) or to \os\winnt\hal.dll on the system partition (for non-x86).
inf
Valid for all components. Specifies the regular INF file for the device. This file is used during GUI-mode setup and for other device maintenance operations. The file is copied to %systemroot%\system32.
catalog
Valid for drivers. Specifies a catalog file for the device. Not required for any component. For example, catalog = d1, mydriver.cat. See the WHQL guidelines for more information on catalog files.
detect
Valid for the computer component (x86 only). If specified, replaces the standard x86 hardware recognizer. Setup copies the file to c:\ntdetect.com.
diskN
Identifies the disk from which to copy the file. This value must match an entry in the Disks section.
filename
Specifies the name of the file, not including the directory path or drive. To form the full file name, Setup appends the filename to the directory specified for the disk in the Disks section.
DriverKey
Specifies the name of the key to be created in the registry services tree for this file, if the file is of type driver. This value is used to form Config.DriverKey section names. This value is required for components of type scsi.

The following example shows a Files.HwComponent.ID section in a txtsetup.oem file:

; ...
[Files.SCSI.oemscsi]
driver = d1,oemfs2.sys,OEMSCSI
inf = d1,oemsetup.inf
dll = d1, oemdrv.dll
catalog = d1, oemdrv.cat
; ...


Config.DriverKey Section of a txtsetup.oem File

A Config.DriverKey section specifies values to be set in the registry for particular component options. Setup automatically creates the required values in the Services\DriverKey key. Use this section to specify additional keys to be created under Services\DriverKey and values under Services\DriverKey and Services\DriverKey\subkey_name.

[Config.DriverKey]
value = subkey_name,value_name,value_type,value
...

subkey_name
Specifies the name of a key under the Services\DriverKey tree where Setup places the specified value. Setup creates the key if it does not exist.

If subkey_name is the empty string (""), the value is placed under the Services\DriverKey.

The subkey_name can specify more than one level of subkey, such as "subkey1\subkey2\subkey3".

value_name
Specifies the name of the value to be set.
value_type
Specifes the type of the registry entry. The value_type can be one of the following:
REG_DWORD
One value is allowed; it must be a string of 1-8 hex digits.

For example:

value = parameters,NumberOfButtons,REG_DWORD,0X2
REG_SZ or REG_EXPAND_SZ
One value is allowed; it is interpreted as the zero-terminated string to be stored.

For example:

value = parameters,Description,REG_SZ,"This is a text string"
REG_BINARY
One value is allowed; it is a string of hex digits, each pair of which is interpreted as a byte value.

For example (stores the byte stream 00,34,ec,4d,04,5a):

value = parameters,Data,REG_BINARY,0034eC4D045a
REG_MULTI_SZ
Multiple value arguments are allowed; each is interpreted as a component of the MULTI_SZ string.

For example:

value = parameters,Strings,REG_MULTI_SZ,String1,"String 2",string3
value
Specifies the value; its format depends on value_type.

The following example shows a Config.DriverKey section:

; ...
[Config.OEMSCSI]
value = parameters\PnpInterface,5,REG_DWORD,1
; ...


HardwareIds.scsi.Service Section of a txtsetup.oem File

A HardwareIds.scsi.Service section specifies the hardware IDs of the devices that a particular mass-storage driver supports.

[HardwareIds.scsi.Service]
id = "deviceID","service"
...

HardwareIds.scsi.Service
Service specifies the service to be installed.
deviceId
Specifies the device ID for a mass-storage device.
service
Specifies the service to be installed for the device.

The following example excerpt shows a HardwareIds.scsi.Service section for a disk device:

; ...
[HardwareIds.scsi.oemscsi]
id = "PCI\VEN_9004&DEV_8111","oemscsi"

; ...


The boot.ini File

The boot.ini file is used for all NT-based Microsoft® Windows® operating systems running on x86 processors. It controls the boot options, the debug options, and other features.

This section includes:

Contents of the boot.ini File

Parameters for the boot.ini File

Sample boot.ini Files

Editing the boot.ini File


Contents of the boot.ini File

A typical boot.ini file looks something like this:

[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINNT
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINNT="Microsoft Windows 2000 Professional" /fastdetect
multi(0)disk(0)rdisk(0)partition(3)\WINDOWS="Microsoft Windows 98"

Under the [operating systems] section, each operating system in your boot options menu is listed. The parameters following each operating system describe the special features that this Microsoft® Windows® version will be started with.

To identify which operating system corresponds to which line, you will have to examine the partition number and the operating system starting directory.

During the boot process, all these operating systems are displayed. If the user does not select one system after a certain amount of time, the default choice is automatically selected. The default choice is listed after the word default=, and the time limit (in seconds) is listed after the word timeout=.

Note The default operating system listing only includes the root directory, not the additional parameters. After the timeout, the boot process will locate the first line in the [operating systems] section that matches this directory, and launch that operating system.

Possible ways to change this file include:

  • Changing the parameters for one of the operating systems listed.
  • Duplicating the line for one of the operating systems, and changing the parameters on one of the resulting lines.
  • Changing the quoted string (this string is displayed in the OS loader options during boot, unless there is only one operating system listed).
  • Changing the default operating system.
  • Changing the timeout value.

If you wish to debug the computer by using a null-modem cable, the parameters /debugport and /baudrate are most useful. In Windows XP and later versions, you can use a 1394 cable instead. In this case, the /debugport and /channel parameters are required.

If you wish to install a partial checked build, the /kernel and /hal parameters are most useful.

See Parameters for the boot.ini File for a full list of available parameters.

Loss of Reserved Port

If kernel debugging is enabled through a COM port, Windows removes this port from the system device list. The Control Panel utilities will either not list this port at all, or will show "Not enough resources to use this port." This does not represent any malfunction.

As a result, if you wish to test the null-modem connection using Hyperterminal or another communication program, you must do so after connecting the cable but before enabling debugging through the boot.ini file.


Parameters for the boot.ini File

The following table lists the parameters that can be used in the boot.ini file.

Parameter | Description
/nodebug | Disables kernel debugging, even if a bug check occurs. This is the default. If you specify nodebug, then the boot loader will ignore any use of debugport, baudrate, or crashdebug.
/debug | Allows the computer to be debugged. If a kernel debugger attaches to this computer, it will be given control over its execution. If a bug check occurs, or if a kernel-mode program attempts to communicate with a debugger, the computer will pause and wait for a response from a kernel debugger.
/debugport=Port | Specifies the serial port to be used by the kernel debugger. If you are using a debug cable, Port can be COM1, COM2, or any other valid COM port. If you are using 1394 debugging, Port should be 1394. If this parameter is omitted, the debugger defaults to COM2.
/channel=Channel | Specifies the 1394 channel number to be used. Valid channel numbers are 1 through 62. Channel must match the channel number used during host computer setup, but does not depend on the physical 1394 port chosen on the adapter.
/crashdebug | Causes the code that communicates with a kernel debugger to be loaded during boot but swapped out to the paging file after boot. As a result, a kernel debugger cannot break into this computer unless a bug check occurs.
/baudrate=BaudRate | Sets the speed that the kernel debugger uses, in bits per second (bps). Baud rates of 9600, 19200, 38400, 57600, and 115200 are supported. Your hardware will determine how fast your connection can run, but in most cases there should not be any communication problems at 57600 bps. The default rate is 19,200 bps.
/kernel | Specifies the Windows kernel file to use. The default is %SystemRoot%\system32\ntoskrnle.exe for systems with less than 4 GB of memory, or ntkrnlpa.exe for systems with more than 4 GB of memory. This parameter should only be changed if you have deliberately installed a different kernel. (This can be useful if you are testing a kernel patch, or if you have made a partial checked build installation.)
/hal | Specifies the hardware abstraction layer (HAL) file to use. The default is %SystemRoot%\system32\hal.dll. This parameter should only be changed if you have deliberately installed a different HAL. (This can be useful if you are testing a HAL patch, or if you have made a partial checked build installation.)
/maxmem=SizeInMB | Specifies the amount of memory to be made available to the system. For example, you can restrict a 16 MB computer to 10 MB.
/PAE | Allows the operating system to support Physical Address Extension (PAE).
/basevideo | Causes the system to use VGA video mode.
/sos | Causes the system loader to display the names of the drivers as they load while Windows is booting.

When you use the /debugport or /baudrate parameters, the /debug parameter is automatically assumed and does not need to be specifically included. You will usually not want to select these parameters on a computer that is not actually being debugged, because this will tie up a COM port unnecessarily.


Sample boot.ini Files

The following boot.ini file can be used to debug the computer with a null-modem cable connection:

[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINNT
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINNT="Microsoft Windows 2000 Professional" /fastdetect /debugport=com1 /baudrate=57600

The following boot.ini file can be used to debug the computer with a 1394 cable connection. Here, there has been a triple-boot option created. Microsoft® Windows® 2000 is installed on partition one. Windows XP is installed on partition three; it can be selected in debug mode or in standard mode. The default option specifies partition three. Since there are two operating system specifications for this partition, the first of these two lines becomes the default setting (in this case, the standard mode):

[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(3)\WINNT
[operating systems]
multi(0)disk(0)rdisk(0)partition(3)\WINNT="Microsoft Windows XP Professional" /fastdetect
multi(0)disk(0)rdisk(0)partition(3)\WINNT="Microsoft Windows XP Professional" /fastdetect /debugport=1394 /channel=44
multi(0)disk(0)rdisk(0)partition(1)\WINNT="Microsoft Windows 2000 Professional" /fastdetect

The following boot.ini file will boot Windows NT® 4.0 in a simulated 10 MB environment, with kernel debugging enabled on COM1, and communicating at 19200 baud:

[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINNT
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\NT="Windows NT" /maxmem=10 /debugport=COM1 /baudrate=19200

The following file can be used if you have created a partial checked build. Two operating system lines appear; the first boots the free build, and the second boots the partial checked build. The display string for the checked option has been edited so that the difference will be clear on the OS loader options screen.

[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINNT
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINNT="Microsoft Windows 2000 Professional" /fastdetect
multi(0)disk(0)rdisk(0)partition(1)\WINNT="Windows 2000 Checked" /fastdetect /kernel=ntoskrnl.chk /hal=halacpi.chk

The file names used with the /kernel and /hal parameters should match those used when you created the partial checked build. For details, see Installing Just the Checked Operating System and HAL.


Editing the boot.ini File

To configure the target computer, edit the boot.ini file by adding the appropriate debugger options to notify Microsoft® Windows® to load the kernel debugger.

To edit the boot.ini file in Notepad

  1. Start Windows Explorer. Go to Tools | Folder Options | View. Make sure that Show Hidden Files and Folders is selected, and Hide File Extension for Known File Types is cleared.
  2. Go to the root directory of the boot volume of your computer (on single-boot machines, usually C:\). Right-click on boot.ini. Select Properties, and remove the read-only attribute of this file. Click OK.
  3. Double-click the file icon to start Notepad with boot.ini loaded.
  4. If you are using an MS-DOS® Command Prompt window, use the following commands instead of steps 1, 2, and 3:
    c:
cd \
attrib -s -h -r boot.ini
notepad boot.ini
  5. Edit the file. (For a description of the boot.ini syntax, see Contents of the boot.ini File.)
  6. Save the boot.ini file and quit Notepad. (You do not have to restore the original file attributes.)
  7. Shut down the computer and restart Windows.


The Checked Build of Windows

This section describes how the Microsoft® Windows® checked build (also known as debug build) of the NT-based operating systems differs from the free build (also known as retail build) of this operating system. It describes how the unique features of the checked build can be used to assist in driver development and debugging on x86 platforms. Finally, it lists several alternatives for installing and utilizing the checked build in driver development and debugging environments.

This section includes:

Checked and Free Build Differences

Using the Checked Build

Installing the Checked Build

Checked Build Breakpoints and Messages

Checked Build ASSERTs

This section does not cover IA-64 (Itanium) systems, nor does it cover Windows 98/Me.

For Windows 98/Me, commonly-used checked files are part of this DDK. If necessary, you can request additional checked files through DDK Developer Support at support.microsoft.com.


Checked and Free Build Differences

Two distinct builds of the NT-based operating systems are available:

The free build (or retail build)
This is the typical build of Microsoft® Windows® that is used in production environments. The free build of the operating system is built with full compiler optimizations. When Windows discovers correctable problems, the free build of the operating system continues to run. Distribution media containing the free build of the operating system do not have any special designation — in other words, the CD containing the free build will just be labeled with the Windows version name, and no reference to the type of build.
The checked build (or debug build)
This build of the operating system is created specifically to make identifying and diagnosing operating-system-level problems easier. For example, the checked build of the operating system has many compiler optimizations (such as stack frame elimination) disabled. Disabling such optimizations makes it easier to understand disassembled machine instructions, and therefore easier to trace the cause of problems in system software. The checked build also enables a large number of debugging cross-checks in the operating system code and system-provided drivers. This helps the checked build identify internal inconsistencies and problems as soon as they occur. Distribution media containing the checked build are clearly labeled "Debug/Checked Build." For information on obtaining this build, see Obtaining the Checked Build.

The checked build distribution contains the checked version of the operating system itself, checked HALs, checked drivers, checked versions of the file systems, and even checked (debug) builds of many of the user-mode components.

Because the checked build contains fewer optimizations and more debugging checks than the free build, the checked build is both larger in size and slower in execution than the free build. As a result, the checked build is not suitable for use in production environments (except when attempting to identify serious problems).


Using the Checked Build

This section includes:

What the Checked Build Checks

How the Checked Build Indicates a Problem

Side-Effects of Using the Checked Build

The Checked Build and the Debugger

The Checked Build and Driver Verifier


What the Checked Build Checks

The checked build includes a significant number of debugging "cross-checks" that are normally not present in the system. These checks include:

  • Parameter validation checks

    Great care has been taken to ensure that the Windows operating system code ordinarily executes with as little overhead as possible. As a result, the NT-based operating systems implement the policy that all components running in kernel-mode, including drivers, implicitly "trust" each other. Thus, parameters that are passed from one kernel-mode component to another (such as parameters passed on function calls) are typically subject to minimal validation. The checked build of the operating system enables many additional parameter validation checks.

  • Internal checks for operating system correctness and consistency

    These checks typically verify the correctness of key algorithms and data structures in the operating system. Checks of this type may also be inserted by one of the Windows developers during the operating system debugging process to help isolate difficult problems.

  • Informational checks and tracing output

    These checks, and the resulting output that is displayed in the debugger, are designed to assist debugging of drivers or other system-level components. Often, these types of checks must be individually enabled by setting debug flags — typically using the debugger — internally in the component of interest. The existence of such checks and their debug output may vary from release to release of the operating system. When such checks exist, they are often documented in Microsoft Knowledge Base articles.

It is important to remember that most of the checks performed by the checked build are checks for "reasonableness." That is, most of the checks that appear in the checked build are tests to see if values in parameters or data structures are within what the developer anticipates as being a typical range. During operation of the system, it might be possible, under certain rare circumstances, for a given parameter or value to fall outside the normally anticipated range.

Thus, even when one of the checks in the checked build fails, it does not necessarily mean that a catastrophic failure has occurred. In fact, a check in the checked build failing doesn't even necessarily mean that something has gone wrong at all! It merely means that a particular check has failed and the reason for that failure needs to be fully explored and identified.

It is just as big a mistake to ignore problems identified by the checked build as it is to assume that a given problem means that your driver has done something invalid. The key to using the checked build most profitably for driver debugging is to be sure you explain the reason for any failures that the checked build turns up.


How the Checked Build Indicates a Problem

The checked build uses a variety of methods to notify you of problems that it finds. All of these methods result in output in the kernel debugger. Therefore, to be useful, the checked build of the operating system must be run with a kernel-mode debugger (such as WinDbg or KD) attached. See Debugging Tools for NT-Based Operating Systems for details on debugging.

ASSERT Failures

Most of the checks performed by the checked build are implemented as ASSERT statements. When the expression being asserted evaluates to FALSE, a message is displayed in the debugger showing:

  • The text of the expression that failed
  • The source code path, file name, and line number of the failed ASSERT routine

Here is an example of the output displayed in the debugger as a result of an assert failing in the I/O Manager:

*** Assertion failed: Irp->IoStatus.Status != 0xffffffff
***   Source File: D:\nt\private\ntos\io\iosubs.c, line 3305

0:Break, Ignore, Terminate Process or Terminate Thread (bipt)? b
0:Execute '!cxr BD94B918' to dump context
Break instruction exception - code 80000003 (first chance)
ntkrnlmp!DbgBreakPoint:
804a3ce4 cc               int     3

In the debugger output shown here, you can see that the user was asked whether to "Break, Ignore, Terminate Process or Terminate Thread". The user answered by entering "b", and thereby requested the debugger to stop system execution with a breakpoint. With the system stopped in this way in the debugger, the user can now continue to debug the problem that was discovered.

How a failed assert affects the system when a debugger is not attached depends on whether or not the system was started with debugging support enabled. If debugging is enabled for the operating system during the system startup process, but a debugger is not attached when an assert fails, the system will hang on encountering a failed assert. If debugging is not enabled (and therefore a debugger is not attached) when an assert fails, the system will crash. This will result in a Bug Check 0x1E with a Parameter 1 value of 0x80000003.

Some ASSERT failures are preceded by additional DbgPrint output. One very common example of this type of assert is the PAGED_CODE macro, which is defined in ntddk.h and wdm.h for use in the checked build of drivers as follows:

#define PAGED_CODE() \
    if (KeGetCurrentIrql() > APC_LEVEL) { \
KdPrint(( "EX: Pageable code called at IRQL %d\n", KeGetCurrentIrql() )); \
        ASSERT(FALSE); \
        }

This macro is frequently used within the operating system to validate that pageable functions are only called at appropriate IRQLs.

You can usually determine the cause of an assert by examining the text of the failing expression. You need to consider what your driver was doing when the ASSERT occurred, and what functions had been called. The KB (Display Stack Trace) debugger command is crucial to this analysis.

See Checked Build ASSERTs for a list of the more common ASSERT calls.

Breakpoints

Another method by which the checked build will indicate that a problem has been encountered is by taking a breakpoint. Breakpoints are often preceded by DbgPrint statements, which cause the debugger to display information about the problem that has been encountered. If a debugger is not attached to the system when a breakpoint occurs, the system crashes, and any explanatory messages are lost.

Some of the most common messages that precede breakpoints encountered by driver writers in the checked build are listed in Checked Build Breakpoints and Messages.

Here is an example of how a DbgPrint call and breakpoint appear in the debugger:

*** DPC routine > 1 sec --- This is not a break in KeUpdateSystemTime
Break instruction exception - code 80000003 (first chance)
NTOSKRNL!DbgBreakPoint:
804a3ce4 cc               int     3

This example shows a message displayed in the debugger indicating that a single deferred procedure call (DPC) was executing for longer than one second. This serves as a good illustration of the type of checks implemented in the checked build. This breakpoint means that a driver has spent an unusually long time in a DPC routine. This could be a symptom of a serious driver problem. On the other hand, this breakpoint can also be caused by the driver generating a large amount of debug output in its DPC routine, thereby extending the length of time required for the DPC to execute. Examining what the DPC routine is doing, and continuing past the breakpoint once or twice will usually result in discovering the underlying cause of the problem.

In the rare situation when a breakpoint is encountered but no message is displayed, it is important to examine the kernel stack trace (using the KB debugger command) to determine where the breakpoint was encountered. Often, this will give a strong clue as to the reason for the breakpoint.

Here is an example of a breakpoint that has been seen by many Windows driver developers, along with a stack trace:

Break instruction exception - code 80000003 (first chance)
ntkrnlmp!SpinLockSpinningForTooLong:
8069aafd cc               int     3
1: kd> kb
ChildEBP RetAddr  Args to Child
f9f77c4c 80103a6c f9f77c84 00000005 fa20e7df ntkrnlmp!SpinLockSpinningForTooLong
f9f77c58 fa20e7df 81b34930 e1558bd0 00180016 halmps!KfAcquireSpinLock+0x3c
f9f77c7c 80742683 000000ff 81ba6000 00000000 nothing+0x7df
f9f77d54 80742893 0000046c 81ba6000 f9f77d80 ntkrnlmp!IopLoadDriver+0x785
f9f77d78 805f8d2d 00000000 00000000 81fa88b8 ntkrnlmp!IopLoadUnloadDriver+0x75
f9f77dac 807cd14f f7d59ce8 00000000 00000000 ntkrnlmp!ExpWorkerThread+0x129
f9f77ddc 8069bece 805f8c04 00000001 00000000 ntkrnlmp!PspSystemThreadStartup+0x4d
00000000 00000000 00000000 00000000 00000000 ntkrnlmp!KiThreadStartup+0x16

As you can see from this stack trace, the breakpoint was taken as a result of calling KfAcquireSpinLock. Examining wdm.h, you can see that this is the actual name of the function referred to by drivers as KeAcquireSpinLock. Even though no message was displayed prior to the breakpoint being taken, you can see the location of the breakpoint at the top of the stack (ntkrnlmp!SpinLockSpinningForTooLong). This location indicates the reason for the breakpoint: A spin lock has been spinning, pending acquisition, for an unusually long time.

Debugger Messages

The final way that the checked build identifies that an error has occurred (or sometimes just provides additional information) is through message output in the debugger. Errors that originate from nonkernel and non-HAL components, or from checked (debug) user-mode programs, are the most common source of debugger output error messages. The amount of output varies with the operating system release.

Here is an example of the output that might be displayed by an installation of the full checked build. This output was generated by a prerelease version of Windows XP, and thus is even more voluminous than is usually seen on a fully checked build:

0:Attempting to load winsock
0:Checking for presence of ws2_32
0:Looking in ws2_32 for getaddrinfo
0:AudioSrv: 1:CreateSessionUserSid: GetCurrentUserTokenW failed, LastError=1245
1:AudioSrv: RegOpenConsoleUser: no console sid
0:(s: 0 0xc4.d0 winlogon.exe) USRK-[Wrn=170] CloseDesktop: Desktop 0X81CEAF78 still in use by thread 0XE16F3EA0
0:GetWinStationUserToken: Error 1702 getting UserToken LogonId 0
1:AudioSrv: InitializeForNewConsoleUser: User SID S-1-5-21-329068152-1292428093-1547161642-500
1:(s: 0 0x240.3a8 spoolsv.exe) USRK-[Wrn=1400] ValidateHwnd: Invalid hwnd (0X0000FFFF)
0:(s: 0 0x240.3a8 spoolsv.exe) USRK-[Wrn=1400] ValidateHwnd: Invalid hwnd (0X0000FFFF)
0:bReadUserSystemEUDCRegistry():fail NtStatus - c0000000
0:GDI: GDISRV:Fail to read system wide eudc
0:
1:TERMSRV : Not Personal Workstation
0:(s: 0 0x260.3c4 Explorer.EXE) USER-[Wrn=1400] HMValidateHandle: Invalid:00000000 Type:0x1
0:(s: 0 0x260.3c4 Explorer.EXE) USER-[Wrn=1400] HMValidateHandle: Invalid:00000000 Type:0x1
0:(s: 0 0x260.3c4 Explorer.EXE) USER-[Wrn=1400] HMValidateHandle: Invalid:00000000 Type:0x1

Some of the most common messages that can be displayed by the checked build during driver debugging are listed in Checked Build Breakpoints and Messages.

Debugger messages without subsequent breakpoints or ASSERT failures can also result from enabling additional trace or informational messages in various system components.


Side-Effects of Using the Checked Build

Checked components of the operating system contain fewer optimizations and more debugging cross-checks than otherwise identical free components. This results in checked components running substantially slower than their free counterparts.

Perhaps of even more significance to driver writers, however, is that this slower execution results in changes in the timing relationships among code-paths. This can obscure timing problems (such as race conditions or deadlocks) that otherwise might be revealed in the free build. Thus, it is absolutely vital that driver developers test their drivers on both the free build and the checked build of the operating system before release.


The Checked Build and the Debugger

The typical setup for debugging kernel-mode drivers in an NT-based operating system utilizes two systems connected by a null modem cable (or, optionally for Windows XP and later, by a 1394 connection). For details, see Hardware Requirements for Debugging.

The host computer should be a stable system, since it is the system on which the debugger is run. Therefore, the host computer should always run the free build of the operating system. The debugger running on the host computer controls the target computer through the attached null modem cable or 1394 debugging cable.

The target computer can run either the free build or the checked build. For more incisive debugging, the checked build is preferred.


The Checked Build and Driver Verifier

While the checked build and Driver Verifier provide some checks that overlap, it's best to think of them as providing complementary levels of checking. Testing your driver with the checked build is not a substitute for testing with Driver Verifier. Similarly, testing with Driver Verifier does not provide precisely the same level of test coverage as using the checked build.

When Driver Verifier runs on the checked build, it often displays additional information in the debugger when a problem is detected. In addition, when a debugger is attached, in many cases Driver Verifier will execute a breakpoint prior to halting the system with a bug check. This break point gives you a chance to examine the state of the system and debug your driver prior to the Driver-Verifier-invoked system crash.


Installing the Checked Build

This section includes:

Obtaining the Checked Build

Installing the Complete Checked Build

Installing Just the Checked Operating System and HAL


Obtaining the Checked Build

The checked build is available on CD through subscription to the Microsoft Developer's Network (MSDN®).

The checked build is also available to MSDN subscribers through the MSDN Web site at msdn.microsoft.com.


Installing the Complete Checked Build

Probably the easiest way to utilize the checked build in driver debugging is to install the complete checked build on your computer. This can be accomplished by simply performing an installation on your computer using the checked build distribution. This results in the installation of all available checked components on your computer.

This installation will result in maximum debugging cross-checks because checked versions of all components are installed. However, this also results in the system running considerably slower than the free build of the operating system.


Installing Just the Checked Operating System and HAL

An alternative to installing the complete checked build on your computer is to install the free build of the system, and then manually install only the checked versions of the operating system image and HAL. This procedure will result in an additional boot option that lets you start the system using just the checked operating system image and HAL, but the free versions of all other system components.

One advantage to this approach, as opposed to installing the complete checked build, is that drivers get the benefit of the operating-system and HAL debug cross-checks while the performance impact on the entire system is minimized (due to the fact that free versions of system components other than the operating system and HAL are being used).

Another advantage of installing only the checked operating system image and HAL is that this allows a single installation (and thus one system directory, one set of executable components, and one set of registry parameters) to utilize either the checked or the free versions of the operating system image and HAL as determined at boot time.

Installing the checked versions of the operating system image and HAL involves copying the appropriate files from the checked distribution kit to new, unique, file names in the %SystemRoot%\system32 directory and instructing the system to offer an option to use these files during system startup. There are a few important guidelines to keep in mind when installing checked operating system and HAL images on an otherwise free installation:

  • The operating system image and HAL must be kept in synch at all times. Therefore, if a checked version of the operating system image is used, the checked version of the HAL must be also be used (and vice versa). Failure to keep the operating system image and HAL coordinated can result in rendering the system on which they are installed unbootable.
  • Take special care not to overwrite the free versions of the operating system image and the HAL that are installed by default in the installation of the free build. Overwriting the free versions of the operating system image and HAL can result in the system becoming unbootable, and can make it difficult to recover from errors. Therefore, always be careful to copy the checked versions of the operating system and HAL to unique files names in the %SystemRoot%\system32 directory.
  • Make sure the checked distribution you use is the same Service Pack number as that of the free system. For example, if you are installing the checked operating system image and HAL onto a free build system with Service Pack 2 installed, make certain that the checked distribution you are using is also Service Pack 2.

As long as you keep these guidelines in mind (and edit carefully!) installing the checked versions of the operating system and HAL is easy.

Follow the following steps to install a partial checked build.

Step 1: Identifying the Files To Install

Your first step in installing a partial checked build is to identify which version of the operating system image and HAL files were used during the installation of the free build on your system.

There are several different versions of the operating system and HAL images supplied as part of the NT-based operating system distribution kit. These different versions exist to properly support specific combinations of processor and system hardware. When the operating system software is installed, the installation procedure automatically identifies which operating system image and HAL image to use, and copies the appropriate files from the distribution medium to the %SystemRoot%\system32 directory of the system being installed.

The original names of the operating system image files on the distribution media depend on whether one or multiple processors are to be supported, and on whether Physical Address Extension (PAE) is supported. (PAE is active on systems with more than 4 GB of physical memory.). The original file names are as follows:

ntoskrnl.exe
Uniprocessor x86 architecture systems with 4 GB of physical memory or less.
ntkrnlpa.exe
Uniprocessor x86 architecture systems with PAE support.
ntkrnlmp.exe
Multiprocessor x86 architecture systems with 4 GB of physical memory or less.
ntkrpamp.exe
Multiprocessor x86 architecture systems with PAE support.

Likewise, there are several different original names for the HAL.

During system installation, the installation procedure determines the appropriate operating system image and HAL to install on your system. The selected files are copied to fixed, well-known, names in the %SystemRoot%\system32 directory during installation. The use of these fixed names makes it easy for the loader to locate these files at boot time. The well-known names for these files are:

ntoskrnl.exe
Operating system image for x86 systems with 4 GB or less of physical memory.
ntkrnlpa.exe
Operating system image for x86 systems with more than 4 GB of physical memory.
hal.dll
Loadable HAL image.

Note that in some cases, depending on the system's hardware configuration, one or more of the files may be renamed to the appropriate fixed name. In other cases, the original file name is the same as the required fixed file name.

Your first step in installing the checked operating system image and HAL is to determine the original names of the images that were copied to your system during system installation. You do this by examining the file %SystemRoot%\repair\setup.log. This is a hidden file, so you will have to change its attributes before it can be displayed by the MS-DOS® dir command.

The setup.log file is used during the system installation process to copy files from the distribution medium to the %SystemRoot%\system32 directory. Here is an example of a setup.log file:

[Paths]
TargetDirectory = "\WINNT"
TargetDevice = "\Device\Harddisk0\Partition1"
SystemPartitionDirectory = "\"
SystemPartition = "\Device\Harddisk0\Partition1"
[Signature]
Version = "WinNt5.1"
[Files.SystemPartition]
NTDETECT.COM = "NTDETECT.COM","f41f"
ntldr = "ntldr","3e8b5"
arcsetup.exe = "arcsetup.exe","379db"
arcldr.exe = "arcldr.exe","2eca9"
[Files.WinNt]
\WINNT\system32\drivers\kbdclass.sys = "kbdclass.sys","e259"
\WINNT\system32\drivers\mouclass.sys = "mouclass.sys","7e78"
\WINNT\system32\drivers\uhcd.sys = "uhcd.sys","10217"
\WINNT\system32\drivers\usbd.sys = "usbd.sys","5465"
(…several similar lines omitted…)
\WINNT\system32\framebuf.dll = "framebuf.dll","10c84"
\WINNT\system32\hal.dll = "halmacpi.dll","2bedf"
\WINNT\system32\ntkrnlpa.exe = "ntkrpamp.exe","1d66a6"
\WINNT\system32\ntoskrnl.exe = "ntkrnlmp.exe","1ce5c5"
\WINNT\inf\mdmrpci.inf = "mdmrpci.inf","96a3"

You can identify which operating system image and HAL files were installed on your system by searching setup.log for the fixed operating system image file names. Make a note of the original file names used on your system, because you will need to copy the checked versions of these same files from the checked distribution kit. You will find the standard, well-known, file name on the left of the equal sign. Its original name from the distribution medium will be immediately to the right of the equal sign on the same line.

In the sample setup.log file shown above, you can see that two operating system image files were copied to the \winnt\system32 directory (which is %SystemRoot%\system32) during installation. The file ntkrpamp.exe is copied from the distribution medium to ntkrnlpa.exe and the file ntkrnlmp.exe is copied from the distribution medium to ntoskrnl.exe. From this sample, you can also see that the HAL file (with the fixed name hal.dll in the %SystemRoot%\system32 directory) was originally named halmacpi.dll.

Warning Some HAL files have deceptively similar names. For example, halacpi.dll and halapic.dll are two commonly used HALs. Be careful to use the correct version of the HAL for your system. Selecting the wrong HAL will result in a system that is not bootable.

Step 2: Copying the Checked Files

Now that you know the names of the files that were used in your system installation, you can copy the checked versions of these files to unique file names in the %SystemRoot%\system32 directory. Find the files you have identified in the checked distribution kit. Then copy these files to the %SystemRoot%\system32 directory of your system, giving them new, unique, file names. The copies of these files may be named just about anything you like, however the file names must adhere to the 8.3 naming convention. One way to ensure unique, 8.3-compliant file names is to rename the file types from their original file types (.dll or .exe) to .chk when they are copied. Thus, using the example started in Step 1, you would copy files from the checked distribution kit as follows:

If the original file name in the checked distribution is: | Copy it to the following file name in %SystemRoot%\system32:
ntkrnlmp.exe | ntkrnlmp.chk
ntkrpamp.exe | ntkrpamp.chk
halmapic.dll | halmapic.chk

Some files in the checked distribution are provided in compressed form. These files are indicated with an underscore character as the last character in their file type. For example, if you look for the file halapic.dll in the checked build distribution kit, but you find the file halapic.dl_, you have found the correct file, but in compressed form.

To decompress compressed files from the checked distribution, use the Expand utility (%SystemRoot%\system32\expand.exe). For example, to expand halapic.dl_ and name the expanded file halapic.chk, you can use the following command from an MS-DOS Command Prompt window:

> expand halapic.dl_ halapic.chk

Step 3: Editing boot.ini

Once you have copied the checked files to the %SystemRoot%\system32 directory, you will need to create a boot-time option that allows the system to be started using these checked files. You do this by editing the file boot.ini.

For general instructions, see Editing the boot.ini File.

In this specific case, you need to create a new boot-time option that allows you to start the system with the checked version of the operating system image and HAL that you have installed.

Locate the line in the [operating systems] section of boot.ini that refers to your Windows installation. Make a second copy of it, and add to the end of the copied line the following parameters:

/kernel=KernelFile /hal=HalFile

where KernelFile is the name of the checked version of the operating system image file that you previously copied from the checked distribution kit, and HalFile is the name of the checked version of the HAL that you previously copied from the checked distribution kit.

If the line that describes your operating system contains the /PAE parameter, be sure to utilize the checked version of the operating system image that supports Physical Address Extension. If the line that describes your operating system does not have the /PAE parameter, utilize the checked version of the operating system image that you copied without PAE support.

You should also change the quoted text on the new line, so that you will be able to identify which line is the free build and which line is the partial checked build.

Here is an example of such a boot.ini file:

[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINNT
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINNT="Microsoft Windows 2000 Professional" /fastdetect
multi(0)disk(0)rdisk(0)partition(1)\WINNT="Windows 2000 Checked" /fastdetect /kernel=ntoskrnl.chk /hal=halacpi.chk

If you will be using the checked build with a kernel debugger, you should also add the proper debugging-related parameters. (The /kernel and /hal parameters do not enable debugging automatically.) See Editing the boot.ini File for details.

Once you have made your changes, save the changes and exit from the editor. The next time you boot this system, a new operating system boot option will be displayed that allows you to select your checked operating system image and HAL.

Installing Additional Checked Files

Once you have the checked operating system and HAL installed, you have the option to install additional checked components. You may do this by replacing the installed free versions of a few key components with their checked counterparts form the checked distribution. This can be helpful, for example, when you are writing a driver that exists within a stack of other devices. By replacing the free versions of the drivers that are above your driver and below your driver in the stack, you will enable additional error checking in these components. This could help you identify problems in your driver more quickly and easily.

When you replace free drivers with their checked counterparts you will need to overwrite the free versions of these components. Unlike the operating system and the HAL, there is no option to conveniently provide alternate images for system-supplied driver components. Thus, when you replace free drivers with checked drivers on your system, the checked drivers will be used when both the free and checked versions of the operating system image and HAL are started. Therefore, you might want to rename (or copy) the original free versions of any drivers that you replace with their checked counterparts, so that you can restore the free drivers later.

Finally, note that any time you change one of the standard files that exist in one of the system directories (such as %SystemRoot%\system32) Windows File Protection (WFP) will restore that file to its original state unless it is first disabled. Assuming you have a debugger attached to the system, you can temporarily disable Windows File Protection by changing the following registry value:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon
SFCDisable:REG_DWORD:2

Setting SFCDisable to a value of 2 disables WFP for the next boot (only). A value of 0 (the default) enables WFP. For a description of the features of WFP, see the Platform SDK. For more information on the WFP registry settings, search for Knowledge Base article Q222473 at http://support.microsoft.com/directory.


Checked Build Breakpoints and Messages

This topic contains a list and explanation of some of the common breakpoints and DbgPrint messages that a driver might encounter in the checked build.

*** DPC routine > 1 sec --- This is not a break in KeUpdateSystemTime
This message appears just before a breakpoint is issued. It indicates that the active driver spent more than one second in a DPC routine.
*** ISR at 0xnnnnnnnn took over .5 second
This message appears just before a breakpoint is issued. It indicates that the interrupt service routine with entry point 0xnnnnnnnn executed for more than 500ms.
IOINIT: Built-in driver xxxxxx failed to initialize – 0xnnnnnnnn
The boot start driver named xxxxxx returned a failure status 0xnnnnnnnn from its DriverEntry entry point.
IOINIT: Built-in driver xxxxxx took y.zs to initialize
The boot start driver named xxxxxx executed for y.z seconds (which is longer than the expected maximum time of 5 seconds) in its DriverEntry entry point.
IOINIT: Built-in driver xxxxxx took y.zs to fail initialization
The boot start driver named xxxxxx executed for y.z seconds (which is longer than the expected maximum time of 5 seconds) in its DriverEntry entry point.
IOLOAD: Driver xxxxxx took y.zs to initialize
The driver named xxxxxx executed for y.z seconds (which is longer than the expected maximum time of 5 seconds) in its DriverEntry entry point.
IOLOAD: Driver xxxxxx took y.zs to fail initialization
The driver named xxxxxx executed for y.z seconds (which is longer than the expected maximum time of 5 seconds) in its DriverEntry entry point.
IopLoadDriver: A PnP driver xxxxxx does not support DriverUnload routine
The driver named xxxxxx supports IRP_MJ_PNP, but did not specify an unload routine in DriverEntry.
DO_DEVICE_INITIALIZING flag not cleared on DO 0xnnnnnnnn
The device object at address 0xnnnnnnnn was created outside of DriverEntry, but the DO_DEVICE_INITIALIZING bit was not cleared before returning to the system.


Checked Build ASSERTs

This topic contains a list of common ASSERTs encountered by driver writers.

See How the Checked Build Indicates a Problem for some tips on how to handle these asserts (and others not listed).

The function listed in the Function Called column is the most common function that driver writers would call to provoke this error. Keep in mind that calling some other function from your driver might result in the called function internally calling one of the listed functions, which could in turn issue the ASSERT.

Function Called | ASSERT text | Meaning
IoAllocateMdl | ASSERT(Length) | The length of the user buffer being described was zero
IoAttachDeviceToDeviceStack | ASSERT( sourceExtension->AttachedTo == NULL ) | The device object that is being attached (the source device) is already attached to another device object
IoCallDriver | ASSERT( Irp->Type == IO_TYPE_IRP ) | The PIRP argument does not point to an IRP
IoCancelIrp | ASSERT( Irp->Type == IO_TYPE_IRP ) | The PIRP argument does not point to an IRP
IoCompleteRequest | ASSERT( Irp->Type == IO_TYPE_IRP ) | The PIRP argument does not point to an IRP
IoCompleteRequest | ASSERT( !Irp->CancelRoutine ) | There is a cancel routine present in the IRP
IoCompleteRequest | ASSERT( Irp->IoStatus.Status != STATUS_PENDING ) | Attempt to complete an IRP with STATUS_PENDING
IoCompleteRequest | ASSERT( Irp->IoStatus.Status != 0xffffffff ) | Attempt to complete an IRP with an invalid status code
IoCompleteRequest | ASSERT( Irp->Tail.Overlay.AuxiliaryBuffer != NULL ) | An IRP is being completed with STATUS_REPARSE, IO_REPARSE_TAG_MOUNT_POINT, and the aux buffer is non NULL
IoCreateDevice | ASSERT((DriverObject->Flags & DRVO_UNLOAD_INVOKED) == 0) | A device object has been created, but the driver creating it is marked for unload
IoFreeIrp | ASSERT( Irp->Type == IO_TYPE_IRP ) | The PIRP doesn't point to an IRP
IoFreeIrp | ASSERT(IsListEmpty(&(Irp)->ThreadListEntry)) | The IRP being freed is still on a thread's IRP list, and therefore still in use
IoFreeIrp | ASSERT( Irp->CurrentLocation >= Irp->StackCount ) | An IRP is being freed, but I/O completion has not yet finished for all drivers that processed this IRP
IoReuseIrp | ASSERT(Irp->CancelRoutine == NULL) | There is a cancel routine remaining in the IRP that's been requested to reuse
IoReuseIrp | ASSERT(IsListEmpty(&Irp->ThreadListEntry)) | The IRP being reused is still on a thread's IRP list, and therefore still in use
IoSetHardErrorOrVerifyDevice | ASSERT( Irp->Tail.Overlay.Thread != NULL ) | The IRP is not on any thread's IRP list
IopLoadDriver | ASSERT(driverObject->MajorFunction[i] != NULL) | The driver set a dispatch entry point to NULL in its DriverEntry routine
IopCompleteRequest | ASSERT( irp->IoStatus.Status != 0xffffffff) | An IRP was completed with an obviously invalid status
IopCompleteRequest | ASSERT(reparseBuffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) | An IRP was completed with Status == STATUS_REPARSE and Information == IO_REPARSE_TAG_MOUNT_POINT, but the ReparseTag is not for a MOUNT_POINT
IopCompleteRequest | ASSERT(reparseBuffer->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE) | An IRP was completed with Status == STATUS_REPARSE and Information == IO_REPARSE_TAG_MOUNT_POINT, but the returned tag has an invalid length
IopCompleteRequest | ASSERT(reparseBuffer->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE) | An IRP was completed with Status == STATUS_REPARSE and Information == IO_REPARSE_TAG_MOUNT_POINT, but the returned tag has an invalid length
IopSynchronousServiceTail | ASSERT( !Irp->PendingReturned ) | An IRP was marked pending, but synchronously dispatch routine returned with a status != STATUS_PENDING
MmProbeAndLockPages | ASSERT (MemoryDescriptorList->ByteCount != 0) | The byte count in the passed-in MDL is zero
MmProbeAndLockPages | ASSERT (((ULONG)MemoryDescriptorList->ByteOffset & ~(PAGE_SIZE - 1)) == 0) | The offset into the first page in the MDL is >= PAGE_SIZE; the MDL is incorrectly formed
MmProbeAndLockPages | ASSERT (((ULONG_PTR)MemoryDescriptorList->StartVa & (PAGE_SIZE - 1)) == 0) | The starting VA in the MDL is not page aligned; the MDL is incorrectly formed
MmProbeAndLockPages | ASSERT ((MemoryDescriptorList->MdlFlags & ( MDL_PAGES_LOCKED | MDL_MAPPED_TO_SYSTEM_VA | MDL_SOURCE_IS_NONPAGED_POOL | MDL_PARTIAL | MDL_IO_SPACE)) == 0) | The MDL is not in proper state for this function call
MmProbeAndLockPages | ASSERT (NumberOfPagesToLock != 0) | The MDL describes a range of pages with zero pages to lock
MmProbeAndLockPages | ASSERT (FALSE) | A page in the buffer described by the MDL has been locked into memory an unusually high number of times
MmUnlockPages | ASSERT ((MemoryDescriptorList->MdlFlags & MDL_PAGES_LOCKED) != 0) | The pages that comprise the buffer described by this MDL have not been locked
MmUnlockPages | ASSERT ((MemoryDescriptorList->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) == 0) | The MDL describes a buffer from non-paged pool
MmUnlockPages | ASSERT ((MemoryDescriptorList->MdlFlags & MDL_PARTIAL) == 0) | The MDL was built by calling IoBuildPartialMdl
MmUnlockPages | ASSERT (MemoryDescriptorList->ByteCount != 0) | The MDL describes a buffer that is zero bytes long
MmUnlockPages | ASSERT (NumberOfPages != 0) | The MDL does not contain any pages
MmUnlockPages | ASSERT ((SPFN_NUMBER)Process->NumberOfLockedPages >= 0) | The process associated with the MDL does not have any pages locked
MmUnlockPages | ASSERT (*Page <= MmHighestPhysicalPage) | A page frame pointer in the MDL is not valid
MmBuildMdlForNonPagedPool | ASSERT (MemoryDescriptorList->ByteCount != 0) | The buffer described by the MDL is zero bytes long
MmBuildMdlForNonPagedPool | ASSERT ((MemoryDescriptorList->MdlFlags & (MDL_PAGES_LOCKED | MDL_MAPPED_TO_SYSTEM_VA | MDL_SOURCE_IS_NONPAGED_POOL | MDL_PARTIAL)) == 0) | The MDL is not in a proper state for this function call
MmBuildMdlForNonPagedPool | ASSERT (NumberOfPages != 0) | The MDL describes a buffer with zero pages
MmMapLockedPagesSpecifyCache | ASSERT (MemoryDescriptorList->ByteCount != 0) | The MDL has zero length
MmMapLockedPagesSpecifyCache | ASSERT ((MemoryDescriptorList->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) == 0) | The buffer described by this MDL is already mapped into kernel virtual address space
MmMapLockedPagesSpecifyCache | ASSERT ((MemoryDescriptorList->MdlFlags & ( MDL_MAPPED_TO_SYSTEM_VA | MDL_SOURCE_IS_NONPAGED_POOL | MDL_PARTIAL_HAS_BEEN_MAPPED)) == 0) | The MDL is not in a proper state for this for this function call
MmMapLockedPagesSpecifyCache | ASSERT ((MemoryDescriptorList->MdlFlags & ( MDL_PAGES_LOCKED | MDL_PARTIAL)) != 0) | The MDL is not in a proper state for this operation
MmMapLockedPagesSpecifyCache | ASSERT (PointerPte->u.Hard.Valid == 0) | The buffer described by the MDL contains a page that is not resident in memory
MmMapLockedPagesSpecifyCache | ASSERT (Pfn2->u3.e2.ReferenceCount != 0) | The buffer described by the MDL contains a page that is not locked in memory
MmUnmapLockedPages | ASSERT (MemoryDescriptorList->ByteCount != 0) | The MDL describes a buffer that is zero bytes long
MmUnmapLockedPages | ASSERT ((MemoryDescriptorList->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) != 0) | The parameter passed to this function to specify the base address indicated an address in kernel virtual address space, but the MDL was this does not agree with the buffer description in the MDL
MmUnmapLockedPages | ASSERT (PointerPte->u.Hard.Valid == 1) | A page in the buffer described by the MDL is not resident in memory
MmUnmapLockedPages | ASSERT (*Page == MI_GET_PAGE_FRAME_FROM_PTE (PointerPte)) | A page frame pointer in the MDL is not valid
MmUnmapLockedPages | ASSERT (Pfn3->u3.e2.ReferenceCount != 0) | The buffer described by the MDL contains a page that is not locked in memory
MmMapIoSpace | ASSERT (PhysicalAddress.HighPart == 0) | This is running on an x86 system with no more than 4 GB of physical memory, but the parameter passed to this function to specify the high 32 bits of the I/O space address is non-zero
MmMapIoSpace | ASSERT (NumberOfBytes != 0) | The parameter passed to this function to specify the number of bytes to map is zero
MmMapIoSpace | ASSERT (PointerPte->u.Hard.Valid == 0) | A page in the address rage is not in I/O space
MmUnmapIoSpace | ASSERT (NumberOfBytes != 0) | The parameter passed to this function to specify the number of bytes to unmap is zero
MmAllocateContiguous | ASSERT (NumberOfBytes != 0) | The parameter passed to this function to specify the number of bytes to allocate is zero
MemorySpecifyCache | ASSERT (NumberOfBytes != 0) | The parameter passed to this function to specify the number of bytes to allocate is zero
MmAllocateNonCachedMemory | ASSERT (NumberOfBytes != 0) | The parameter passed to this function to specify the number of bytes to allocate is zero
MmFreeNonCachedMemory | ASSERT (NumberOfBytes != 0) | The parameter passed to this function to specify the number of bytes to free is zero
MmFreeNonCachedMemory | ASSERT (PAGE_ALIGN (BaseAddress) == BaseAddress) | The parameter passed to this function to specify the base address is not valid


Bug Check Codes

When a fatal kernel error occurs on an NT-based operating system, Windows will halt the system and attempt to locate a kernel debugger. If no debugger is currently attached, a blue text screen appears with information about the error.

This halting of the system is known as a bug check. It is also sometimes referred to as a Stop error, a kernel error, a system crash, or a blue screen.

The first line on the blue screen includes the word "STOP," followed by a hexadecimal number. This number is called the bug check code (or the Stop code). It is followed by some additional numbers and text.

This reference section contains descriptions of a number of different bug checks.

Each reference page lists the bug check code, the text string, and the four additional parameters which are displayed with each bug check. It also describes how you can diagnose the fault that led to the bug check, and possible ways to deal with the error.

For a full list of bug check codes, see the bugcodes.h file. This file can be found in the inc directory of the Microsoft® Windows® DDK.

You can also view bug check information by using the !analyzebugcheck extension from NTSD, CDB, KD, or WinDbg. For information on how to install these debuggers, see Debuggers.


Bug Check 0xA: IRQL_NOT_LESS_OR_EQUAL

The IRQL_NOT_LESS_OR_EQUAL bug check has value 0x0000000A. This signals that the driver accessed paged memory at DISPATCH_LEVEL or above.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory referenced
2 | IRQL at time of reference
3 | 0: Read 1: Write
4 | Address which referenced memory

Cause

This bug check is issued if paged memory (or invalid memory) is accessed when the IRQL is too high.

The error that generates this bug check usually occurs after the installation of a bug-ridden device driver, system service, or BIOS.

If you encounter bug check 0xA while upgrading to a later version of Microsoft® Windows®, this error might be caused by a device driver, a system service, a virus scanner, or a backup tool that is incompatible with the new version.

Resolving the Problem

If a kernel debugger is available, obtain a stack trace.

To resolve an error caused by a bug-ridden device driver, system service, or BIOS:

  1. Restart your computer.
  2. Press F8 at the character-based menu that displays the operating system choices.
  3. Select the Last Known Good Configuration option from the Windows Advanced Options menu. This option is most effective when only one driver or service is added at a time.

To resolve an error caused by an incompatible device driver, system service, virus scanner, or backup tool:

  1. Check the System Log in Event Viewer for error messages that might identify the device or driver that caused the error.
  2. Try disabling memory caching of the BIOS.
  3. Run the hardware diagnostics supplied by the system manufacturer, especially the memory scanner. For details on these procedures, see the owner's manual for your computer.
  4. Make sure the latest Service Pack is installed.
  5. If your system has small computer system interface (SCSI) adapters, contact the adapter manufacturer to obtain updated Windows drivers. Try disabling sync negotiation in the SCSI BIOS, checking the cabling and the SCSI IDs of each device, and confirming proper termination.
  6. For integrated device electronics (IDE) devices, define the onboard IDE port as Primary only. Also, check each IDE device for the proper master/slave/stand-alone setting. Try removing all IDE devices except for hard disks.

If the message appears during an installation of Windows, make sure that the computer and all installed peripherals are listed on the Microsoft Windows Hardware Compatibility List (HCL).

Here is a debugging example:

kd> .bugcheck       [Lists bugcheck data.]
Bugcheck code 0000000a
Arguments 00000000 0000001c 00000000 00000000

kd> kb       [Lists the stack trace.]
ChildEBP RetAddr  Args to Child
8013ed5c 801263ba 00000000 00000000 e12ab000 NT!_DbgBreakPoint
8013eecc 801389ee 0000000a 00000000 0000001c NT!_KeBugCheckEx+0x194
8013eecc 00000000 0000000a 00000000 0000001c NT!_KiTrap0E+0x256
8013ed5c 801263ba 00000000 00000000 e12ab000
8013ef64 00000246 fe551aa1 ff690268 00000002 NT!_KeBugCheckEx+0x194

kd> kv       [Lists the trap frames.]
ChildEBP RetAddr  Args to Child
8013ed5c 801263ba 00000000 00000000 e12ab000 NT!_DbgBreakPoint (FPO: [0,0,0])
8013eecc 801389ee 0000000a 00000000 0000001c NT!_KeBugCheckEx+0x194
8013eecc 00000000 0000000a 00000000 0000001c NT!_KiTrap0E+0x256 (FPO: [0,0] TrapFrame @ 8013eee8)
8013ed5c 801263ba 00000000 00000000 e12ab000
8013ef64 00000246 fe551aa1 ff690268 00000002 NT!_KeBugCheckEx+0x194

kd> .trap 8013eee8       [Gets the registers for the trap frame at the time of the fault.]
eax=dec80201 ebx=ffdff420 ecx=8013c71c edx=000003f8 esi=00000000 edi=87038e10
eip=00000000 esp=8013ef5c ebp=8013ef64 iopl=0         nv up ei pl nz na pe nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010202
ErrCode = 00000000
00000000 ???????????????       [The current instruction pointer is NULL.]

kd> kb       [Gives the stack trace before the fault.]
ChildEBP RetAddr  Args to Child
8013ef68 fe551aa1 ff690268 00000002 fe5620d2 NT!_DbgBreakPoint
8013ef74 fe5620d2 fe5620da ff690268 80404690
NDIS!_EthFilterIndicateReceiveComplete+0x31
8013ef64 00000246 fe551aa1 ff690268 00000002 elnkii!_ElnkiiRcvInterruptDpc+0x1d0

Comments

Before upgrading to a new version of Windows, remove all third-party device drivers and system services, and disable any virus scanners. Contact the software manufacturers to obtain updates of these third-party tools.


Bug Check 0x1E: KMODE_EXCEPTION_NOT_HANDLED

The KMODE_EXCEPTION_NOT_HANDLED bug check has value 0x0000001E. This signals that a kernel-mode program generated an exception which the error handler did not catch.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Exception code that was not handled
2 | Address at which exception occurred
3 | Parameter 0 of exception
4 | Parameter 1 of exception

Cause

To interpret this error message, it is necessary to identify which exception was generated.

Common exception codes include:

  • 0x80000002: STATUS_DATATYPE_MISALIGNMENT

    An unaligned data reference was encountered.

  • 0x80000003: STATUS_BREAKPOINT

    A breakpoint or ASSERT was encountered when no kernel debugger was attached to the system.

  • 0xC0000005: STATUS_ACCESS_VIOLATION

    A memory access violation occurred. (Parameter 4 of the bug check is the address, which the driver attempted to access.)

For a complete list of exception codes, see the ntstatus.h file located in the inc directory of the Windows DDK.

Resolving the Problem

As this bug check often does not display full stack information, obtaining a stack trace can be difficult. The exception address should pinpoint the driver or function that caused this problem.

If exception code 0x80000003 occurs, this indicates that a hard-coded breakpoint or assertion was hit, but the system was started with the /NODEBUG switch. This problem should rarely occur. If it occurs repeatedly, make sure a kernel debugger is connected and the system is started with the /DEBUG switch.

If exception code 0x80000002 occurs, the trap frame will supply additional information.

If the specific cause of the exception is unknown, the following should be considered:

Hardware incompatibility. First, make sure that any new hardware installed is listed on the Microsoft Windows Hardware Compatibility List (HCL).

Buggy device driver or system service. In addition, a bug-ridden device driver or system service might be responsible for this error. Hardware issues, such as BIOS incompatibilities, memory conflicts, and IRQ conflicts can also generate this error.

If a driver is listed by name within the bug check message, disable or remove that driver. Disable or remove any drivers or services that were recently added. If the error occurs during the startup sequence and the system partition is formatted with NTFS file system, you might be able to use Safe Mode to rename or delete the faulty driver. If the driver is used as part of the system startup process in Safe Mode, you need to start the computer by using the Recovery Console to access the file.

If the problem is associated with Win32k.sys, the source of the error might be a third-party remote control program. If such software is installed, the service can be removed by starting the system using the Recovery Console and deleting the offending system service file.

Check the System Log in Event Viewer for additional error messages that might help pinpoint the device or driver that is causing bug check 0x1E. Disabling memory caching of the BIOS might also resolve the error. You should also run hardware diagnostics, especially the memory scanner, supplied by the system manufacturer. For details on these procedures, see the owner's manual for your computer.

The error that generates this message can occur after the first restart during Windows Setup, or after Setup is finished. A possible cause of the error is lack of disk space for installation and system BIOS incompatibilities. For problems during Windows installation that are associated with lack of disk space, reduce the number of files on the target hard disk. Check for and delete any unneeded temporary files, Internet cache files, application backup files, and .chk files containing saved file fragments from disk scans. You can also use another hard disk with more free space for the installation. BIOS problems can be resolved by upgrading the system BIOS version.

To get a stack trace if the normal stack tracing procedures fail:

  1. Use the KB (Display Stack Backtrace) debugger command to display parameters in the stack trace to locate the first parameter to NT!PspUnhandledExceptionInSystemThread. (This will not work on an Alpha processor, since function parameters are passed in registers a0 - a5 on such systems. See the debugger documentation for details.)
  2. The first parameter to NT!PspUnhandledExceptionInSystemThread is a pointer to a structure, which contains pointers to an except statement:
    typedef struct _EXCEPTION_POINTERS {
    PEXCEPTION_RECORD ExceptionRecord;
    PCONTEXT ContextRecord;
} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;

ULONG
PspUnhandledExceptionInSystemThread(
    IN PEXCEPTION_POINTERS ExceptionPointers
    )

    Use the DD (Display Memory) debugger command on that address to display the necessary data.

  3. The first retrieved value is an exception record and the second is a context record. Use the .exr debugger command to display the exception record, and use the .cxr debugger command to display the context record.
  4. After the .cxr command executes, use the KB (Display Stack Backtrace) debugger command to display a stack trace that is based on the context record information. This stack trace indicates the calling stack where the unhandled exception occurred.

Here is an example of bug check 0x1E on an x86 processor:

kd> .bugcheck                 get the bugcheck data
Bugcheck code 0000001e
Arguments c0000005 8013cd0a 00000000 0362cffff

kd> kb                        start with a stack trace
FramePtr  RetAddr   Param1   Param2   Param3   Function Name
8013ed5c  801263ba  00000000 00000000 fe40cb00 NT!_DbgBreakPoint
8013eecc  8013313c  0000001e c0000005 8013cd0a NT!_KeBugCheckEx+0x194
fe40cad0  8013318e  fe40caf8 801359ff fe40cb00 NT!PspUnhandledExceptionInSystemThread+0x18
fe40cad8  801359ff  fe40cb00 00000000 fe40cb00 NT!PspSystemThreadStartup+0x4a
fe40cf7c  8013cb8e  fe43a44c ff6ce388 00000000 NT!_except_handler3+0x47
00000000  00000000  00000000 00000000 00000000 NT!KiThreadStartup+0xe

kd> dd fe40caf8 L2            dump EXCEPTION_POINTERS structure
0xFE40CAF8  fe40cd88 fe40cbc4                   ..@...@.

kd> .exr fe40cd88             first DWORD is the exception record
Exception Record @ FE40CD88:
   ExceptionCode: c0000005
  ExceptionFlags: 00000000
  Chained Record: 00000000
ExceptionAddress: 8013cd0a
NumberParameters: 00000002
   Parameter[0]: 00000000
   Parameter[1]: 0362cfff

kd> .cxr fe40cbc4             second DWORD is the context record
CtxFlags: 00010017
eax=00087000 ebx=00000000 ecx=03ff0000 edx=ff63d000 esi=0362cfff edi=036b3fff
eip=8013cd0a esp=fe40ce50 ebp=fe40cef8 iopl=0         nv dn ei pl nz ac po cy
vip=0    vif=0
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010617
0x8013cd0a  f3a4             rep movsb

kd> kb                        kb gives stack for context record
ChildEBP RetAddr  Args to Child
fe40ce54 80402e09 ff6c4000 ff63d000 03ff0000 NT!_RtlMoveMemory@12+0x3e
fe40ce68 80403c18 ffbc0c28 ff6ce008 ff6c4000 HAL!_HalpCopyBufferMap@20+0x49
fe40ce9c fe43b1e4 ff6cef90 ffbc0c28 ff6ce009 HAL!_IoFlushAdapterBuffers@24+0x148
fe40ceb8 fe4385b4 ff6ce388 6cd00800 ffbc0c28 QIC117!_kdi_FlushDMABuffers@20+0x28
fe40cef8 fe439894 ff6cd008 ffb6c820 fe40cf4c QIC117!_cqd_CmdReadWrite@8+0x26e
fe40cf18 fe437d92 ff6cd008 ffb6c820 ff6e4e50 QIC117!_cqd_DispatchFRB@8+0x210
fe40cf30 fe43a4f5 ff6cd008 ffb6c820 00000000 QIC117!_cqd_ProcessFRB@8+0x134
fe40cf4c 80133184 ff6ce388 00000000 00000000 QIC117!_kdi_ThreadRun@4+0xa9
fe40cf7c 8013cb8e fe43a44c ff6ce388 00000000 NT!_PspSystemThreadStartup@8+0x40


Bug Check 0x24: NTFS_FILE_SYSTEM

The NTFS_FILE_SYSTEM bug check has value 0x00000024. This indicates a problem occurred in ntfs.sys, the driver file that allows the system to read and write to NTFS drives.

Parameters

The error message includes the following four parameters in order of appearance:

Parameter | Description
1 | Source file and line number
2 | Address of the exception record (optional)
3 | Address of the context record (optional)
4 | Address where the original exception occurred (optional)

All bug checks due to problems with the file system have encoded in their first parameter the source file and the line number within the source file that generated the bug check. The high 16 bits (the first four hexadecimal digits after the 0x) identify the source file number, while the lower 16 bits (the last four hexadecimal digits of the parameter) identify the source line in the file where the bug check occurred.

Cause

One possible cause of this bug check is disk corruption. Corruption in the NTFS file system or bad blocks (sectors) on the hard disk can induce this error. Corrupted SCSI and IDE drivers can also adversely affect the system's ability to read and write to disk, thus causing the error.

Another possible cause is depletion of nonpaged pool memory. If the nonpaged pool memory is completely depleted, this error can stop the system. However, during the indexing process, if the amount of available nonpaged pool memory is very low, another kernel-mode driver requiring nonpaged pool memory can also trigger this error.

Resolving the Problem

Resolving a disk corruption problem: Check Event Viewer for error messages from SCSI and FASTFAT (System Log) or Autochk (Application Log) that might help pinpoint the device or driver that is causing the error. Try disabling any virus scanners, backup programs, or disk defragmenter tools that continually monitor the system. You should also run hardware diagnostics supplied by the system manufacturer. For details on these procedures, see the owner's manual for your computer. Run Chkdsk /f /r to detect and resolve any file system structural corruption. You must restart the system before the disk scan begins on a system partition.

Resolving a nonpaged pool memory depletion problem: Either increase the amount of installed random access memory (RAM), which increases the quantity of nonpaged pool memory available to the kernel, or reduce the number of files on the SFM volume.


Bug Check 0x2E: DATA_BUS_ERROR

The DATA_BUS_ERROR bug check has value 0x0000002E. This typically indicates that a parity error in system memory has been detected. This error is almost always caused by a hardware problem — a configuration issue, defective hardware, or incompatible hardware. The exception is when a device driver has accessed an address in the 0x8xxxxxxx range that does not exist (does not have a physical address mapping).

Parameters

The four parameters listed in the message are defined in order of appearance as follows:

Parameter | Description
1 | Virtual address that caused the fault
2 | Physical address that caused the fault
3 | Processor status register (PSR)
4 | Faulting instruction register (FIR)

Cause

The most common cause of this error is a hardware problem, usually related to defective RAM, Level 2 (L2) RAM cache, or video RAM. Bug check 0x2E usually occurs after the installation of faulty hardware or when existing hardware fails.

Hard disk corruption could also cause this error.

Resolving the Problem

Resolving a hardware problem: If hardware has recently been added to the system, remove it to see if the error recurs.

If existing hardware has failed, remove or replace the faulty component. You should run hardware diagnostics supplied by the system manufacturer to determine which hardware component has failed. For details on these procedures, see the owner's manual for your computer. Check that all adapter cards in the computer are properly seated. Use an ink eraser or an electrical contact treatment, available at electronics supply stores, to ensure that adapter card contacts are clean.

If the problem occurs on a newly installed system, check the availability of updates for the following items: firmware on reduced instruction set computing (RISC) systems, BIOS revisions on the motherboard, the SCSI controller or network cards. Updates of this kind are typically available on the web site or the bulletin board system (BBS) of the hardware manufacturer.

If the error occurs after installing a new or updated device driver, the driver should be removed or replaced. If, under this circumstance, the error occurs during startup and the system partition is formatted with NTFS, you might be able to use Safe Mode to rename or delete the faulty driver.

If the driver is used as part of the system startup process in Safe Mode, you need to start the computer using the Recovery Console in order to access the file.

For additional error messages that might help pinpoint the device or driver that is causing the error, check the System Log in Event Viewer. Disabling memory caching of the BIOS might also resolve this error. In addition, check the system for viruses, using any up-to-date commercial virus scanning software that examines the Master Boot Record of the hard disk. All Windows file systems can be infected by viruses.

Resolving a hard disk corruption problem: Run Chkdsk /f /r on the system partition. You must restart the system before the disk scan begins. If you cannot start the system due to the error, use the Recovery Console and run Chkdsk /r.

Warning If your system partition is formatted with the file allocation table (FAT) file system, the long filenames used by Windows can be damaged if Scandisk or another MS-DOS–based hard disk tool is used to verify the integrity of your hard disk from an MS-DOS prompt. (An MS-DOS prompt is typically derived from an MS-DOS startup disk or from starting MS-DOS on a multiboot system.) Always use the version of Chkdsk that matches your Windows version.

If you have the wrong revision of the CPU module on an Alpha computer, you might also encounter this error This error has been observed on an Alpha XL 266 using a revision of B02 or earlier. To resolve the error, update your system to a CPU module with a higher revision than B02.


Bug Check 0x35: NO_MORE_IRP_STACK_LOCATIONS

The NO_MORE_IRP_STACK_LOCATIONS bug check has value 0x00000035. This signifies that the IoCallDriver packet has no more stack locations remaining.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Address of the IRP
2 | Reserved
3 | Reserved
4 | Reserved

Cause

A higher-level driver has attempted to call a lower-level driver through the IoCallDriver interface, but there are no more stack locations in the packet. This will prevent the lower-level driver from accessing its parameters.

This is a disastrous situation, since the higher level driver is proceeding as if it has filled in the parameters for the lower level driver (as required). But since there is no stack location for the latter driver, the former has actually written off the end of the packet. This means that some other memory has been corrupted as well.


Bug Check 0x3F: NO_MORE_SYSTEM_PTES

The NO_MORE_SYSTEM_PTES bug check has value 0x0000003F. This is the result of a system which has performed too many I/O actions. This has resulted in fragmented system page table entries (PTE).

Parameters

None

Cause

The system is not actually out of PTEs. Rather, a driver has requested a large block of memory, but there is no contiguous block of sufficient size to satisfy this request.

Often video drivers will allocate large amounts of kernel memory that must succeed. Some backup programs do the same.

Resolving the Problem

Modify the registry to increase the total number of system PTEs.


Bug Check 0x50: PAGE_FAULT_IN_NONPAGED_AREA

The PAGE_FAULT_IN_NONPAGED_AREA bug check has value 0x00000050. This signals that invalid system memory has been referenced.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory address referenced
2 | 0: Read 1: Write
3 | Address that referenced memory (if known)
4 | Reserved

If the guilty driver can be identified, its name is printed on the blue screen and stored in PUNICODE_STRING parameter of KiBugCheckDriver.

Cause

Bug check 0x50 usually occurs after the installation of faulty hardware or in the event of failure of installed hardware (usually related to defective RAM, be it main memory, L2 RAM cache, or video RAM).

Another common cause is the installation of a bug-ridden system service.

Antivirus software can also trigger this error, as can a corrupted NTFS volume.

Resolving the Problem

Resolving a faulty hardware problem: If hardware has been added to the system recently, remove it to see if the error recurs. If existing hardware has failed, remove or replace the faulty component. You should run hardware diagnostics supplied by the system manufacturer. For details on these procedures, see the owner's manual for your computer.

Resolving a bug-ridden system service problem: Disable the service and confirm that this resolves the error. If so, contact the manufacturer of the system service about a possible update. If the error occurs during system startup, restart your computer, and press F8 at the character-mode menu that displays the operating system choices. At the resulting Windows Advanced Options menu, choose the Last Known Good Configuration option. This option is most effective when only one driver or service is added at a time.

Resolving an antivirus software problem: Disable the program and confirm that this resolves the error. If it does, contact the manufacturer of the program about a possible update.

Resolving a corrupted NTFS volume problem: Run Chkdsk /f /r to detect and repair disk errors. You must restart the system before the disk scan begins on a system partition. If the hard disk is SCSI, check for problems between the SCSI controller and the disk.

Finally, check the System Log in Event Viewer for additional error messages that might help pinpoint the device or driver that is causing the error. Disabling memory caching of the BIOS might also resolve it.

Comments

Typically, this address is in freed memory or is simply invalid.

This cannot be protected by try - except; it can only be protected by a probe.


Bug Check 0x58: FTDISK_INTERNAL_ERROR

The FTDISK_INTERNAL_ERROR bug check has value 0x00000058. This is issued if the system is booted from the wrong copy of a mirrored partition.

Parameters

None.

Cause

This often occurs if the primary partition was revived. The mirror appears to support a boot, but it does not.

Resolving the Problem

Reboot the system from the shadow partition.


Bug Check 0x76: PROCESS_HAS_LOCKED_PAGES

The PROCESS_HAS_LOCKED_PAGES bug check has value 0x00000076. This signifies that a driver failed to release locked pages after an I/O operation.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | 0 (zero)
2 | Process address
3 | Number of locked pages
4 | 0 (zero), or pointer to driver stacks

Cause

Some driver failed to release pages that it locked.

Resolving the Problem

The guilty driver can be detected by editing the registry. In the \\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management registry path, set a TrackLockedPages key equal to DWORD 1, then reboot. The system will then save stack traces, and if the driver commits the same error, the system will issue bug check 0xCB, DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS. This will identify the guilty driver.

See Also

Bug Check 0xCB


Bug Check 0x77: KERNEL_STACK_INPAGE_ERROR

The KERNEL_STACK_INPAGE_ERROR bug check has value 0x00000077. This indicates that the requested page of kernel data from the paging file could not be read into memory.

Parameters

The four parameters listed in the message can have two possible meanings. If the first and third parameters are zero, the following definitions should be used:

Parameter | Description
1 | 0
2 | Value found in stack where signature should be
3 | 0
4 | Address of signature on kernel stack

Otherwise, use the following definitions:

Parameter | Description
1 | Status code
2 | I/O status code
3 | Page file number
4 | Offset into page file

Cause

Frequently, the cause of this error can be determined from the second parameter, the I/O status code. Some common status codes are:

  • 0xC000009A, or STATUS_INSUFFICIENT_RESOURCES, is caused by lack of nonpaged pool resources.
  • 0xC000009C, or STATUS_DEVICE_DATA_ERROR, is typically due to bad blocks (sectors) on the hard disk.
  • 0xC000009D, or STATUS_DEVICE_NOT_CONNECTED, indicates defective or loose cabling, termination, or the controller not seeing the hard disk.
  • 0xC000016A, or STATUS_DISK_OPERATION_FAILED, is also caused by bad blocks (sectors) on the hard disk.
  • 0xC0000185, or STATUS_IO_DEVICE_ERROR, is caused by improper termination or defective cabling on SCSI devices, or two devices attempting to use the same IRQ.

These codes are the most common ones for which specific causes have been determined. For information about other possible status codes that can be returned, see the file ntstatus.h in the Windows DDK.

If the first and third parameters are zero, the stack signature in the kernel stack was not found. This error is caused by defective hardware.

Another common cause of this error message is failing RAM.

This bug check can also be caused by a virus infection.

Resolving the Problem

Resolving a bad block problem: An I/O status code of 0xC000009C or 0xC000016A normally indicates that the data could not be read from the disk due to a bad block (sector). If you can restart the system after the error, Autochk runs automatically and attempts to map the bad sector to prevent it's further use.

If Autochk does not scan the hard disk for errors, you can manually launch the disk scanner. Run Chkdsk /f /r on the system partition. You must restart the system before the disk scan begins. If you cannot start the system due to the error, use the Recovery Console and run Chkdsk /r.

Warning If your system partition is formatted with the FAT file system, the long filenames used by Windows can be damaged if Scandisk or another MS-DOS–based hard disk tool is used to verify the integrity of your hard disk from an MS-DOS prompt. (An MS-DOS prompt is typically derived from an MS-DOS startup disk or from starting MS-DOS on a multiboot system.) Always use the version of Chkdsk that matches your Windows version.

Resolving a defective hardware problem: If the I/O status is C0000185 and the paging file is on an SCSI disk, the disk cabling and SCSI termination should be checked for problems.

Resolving a failing RAM problem: Run the hardware diagnostics supplied by the system manufacturer, especially the memory scanner. For details on these procedures, see the owner's manual for your computer.

Check that all the adapter cards in the computer are properly seated. Use an ink eraser or an electrical contact treatment, available at electronics supply stores, to ensure adapter card contacts are clean.

Check the System Log in Event Viewer for additional error messages that might help pinpoint the device that is causing the error. Disabling memory caching of the BIOS might also resolve this error.

Make sure that the latest Windows Service Pack is installed.

If the preceding steps fail to resolve the error, take the system motherboard to a repair facility for diagnostic testing. A crack, a scratched trace, or a defective component on the motherboard can cause this error.

Resolving a virus infection: You should check your computer for viruses using any up-to-date, commercial virus scanning software that examines the Master Boot Record of the hard disk. All Windows file systems can be infected by viruses.


Bug Check 0x79: MISMATCHED_HAL

The MISMATCHED_HAL bug check has value 0x00000079. This signifies that the Hardware Abstraction Layer (HAL) revision level or configuration does not match that of the kernel or the machine.

Parameters

The following parameters are displayed on the blue screen. Parameter 1 indicates the type of mismatch.

Parameter 1 | Parameter 2 | Parameter 3 | Description
1 | Release level of ntoskrnl.exe | Release level of hal.dll | PRCB release level mismatch
2 | Build type of ntoskrnl.exe | Build type of hal.dll | Build type mismatch
3 | Machine type detected during boot | Machine type supported by HAL | Micro Channel mismatch

When Parameter 1 equals two, the following build type codes are used:

  • 0: Multiprocessor-enabled free build
  • 1: Multiprocessor-enabled checked build
  • 2: Single-processor free build

When Parameter 1 equals three, there is an Micro Channel Architecture (MCA) mismatch between the machine and the HAL. (Micro Channel computers require a Micro Channel-specific HAL.) A machine type of "2" indicates MCA.

Cause

This error often results from the user manually updating either ntoskrnl.exe or hal.dll.

Bug check 0x79 can occur if either the ntoskrnl.exe or hal.dll files have been manually updated. The error can also indicate that one of those two files is out of date (for example, the HAL might be designed for Microsoft Windows NT® 4.0 while the kernel is designed for Windows 2000). Additionally, the machine might erroneously have a multiprocessor HAL and a single-processor kernel installed, or vice versa.

The kernel file ntoskrnl.exe is for single-processor systems and ntkrnlmp.exe is for multiprocessor systems. However, these filenames correspond to the files on the installation media; after Windows has been installed, the file is renamed to ntoskrnl.exe, regardless of the source file used. The HAL file also uses the name hal.dll after installation, but there are several possible HAL files on the installation media.

Resolving the Problem

Restart the computer using either the product CD or the Windows Setup disks. At the Welcome screen, press F10 to start the Recovery Console. Use the Copy command to copy either the correct HAL or kernel file from the original CD into the appropriate folder on the hard disk. The Copy command detects whether the file to be copied is in the Microsoft compressed file format. If so, it automatically expands the file copied on the target drive.


Bug Check 0x7A: KERNEL_DATA_INPAGE_ERROR

The KERNEL_DATA_INPAGE_ERROR bug check has value 0x0000007A. This indicates that the requested page of kernel data from the paging file could not be read into memory.

Parameters

The four parameters listed in the message can have two possible meanings. If the first parameter is one, two, or three, the following definitions should be used:

Parameter | Description
1 | Lock type that was held
2 | I/O status code
3 | If Lock Type is 1 or 2: current process If Lock Type is 3: virtual address
4 | Virtual address that could not be paged into memory

Otherwise, use the following definitions:

Parameter | Description
1 | Page Table Entry (PTE) address
2 | I/O status code
3 | Virtual address
4 | Virtual address that could not be paged into memory

Cause

Frequently, the cause of this error can be determined from the second parameter, the I/O status code. Some common status codes are:

  • 0xC000009A, or STATUS_INSUFFICIENT_RESOURCES, is caused by lack of nonpaged pool resources.
  • 0xC000009C, or STATUS_DEVICE_DATA_ERROR, is typically due to bad blocks (sectors) on the hard disk.
  • 0xC000009D, or STATUS_DEVICE_NOT_CONNECTED, indicates defective or loose cabling, termination, or the controller not seeing the hard disk.
  • 0xC000016A, or STATUS_DISK_OPERATION_FAILED, is also caused by bad blocks (sectors) on the hard disk.
  • 0xC0000185, or STATUS_IO_DEVICE_ERROR, is caused by improper termination or defective cabling on SCSI devices, or two devices attempting to use the same IRQ.

These codes are the most common ones for which specific causes have been determined. For information about other possible status codes that can be returned, see the file ntstatus.h in the Windows DDK.

Another common cause of this error message is defective hardware or failing RAM.

This bug check can also be caused by a virus infection.

Resolving the Problem

Resolving a bad block problem: An I/O status code of 0xC000009C or 0xC000016A normally indicates that the data could not be read from the disk due to a bad block (sector). If you can restart the system after the error, Autochk runs automatically and attempts to map the bad sector to prevent it's further use.

If Autochk does not scan the hard disk for errors, you can manually launch the disk scanner. Run Chkdsk /f /r on the system partition. You must restart the system before the disk scan begins. If you cannot start the system due to the error, use the Recovery Console and run Chkdsk /r.

Warning If your system partition is formatted with the FAT file system, the long filenames used by an NT-based operating system can be damaged if Scandisk or another MS-DOS-based hard disk tool is used to verify the integrity of your hard disk from an MS-DOS prompt. (An MS-DOS prompt is typically derived from an MS-DOS startup disk or from starting MS-DOS on a multiboot system.) Always use the version of Chkdsk that matches your Windows version.

Resolving a defective hardware problem: If the I/O status is C0000185 and the paging file is on an SCSI disk, the disk cabling and SCSI termination should be checked for problems.

Resolving a failing RAM problem: Run the hardware diagnostics supplied by the system manufacturer, especially the memory scanner. For details on these procedures, see the owner's manual for your computer.

Check that all the adapter cards in the computer are properly seated. Use an ink eraser or an electrical contact treatment, available at electronics supply stores, to ensure adapter card contacts are clean.

Check the System Log in Event Viewer for additional error messages that might help pinpoint the device that is causing the error. Disabling memory caching of the BIOS might also resolve this error.

Make sure that the latest Windows Service Pack is installed.

If the preceding steps fail to resolve the error, take the system motherboard to a repair facility for diagnostic testing. A crack, a scratched trace, or a defective component on the motherboard can cause this error.

Resolving a virus infection: You should check your computer for viruses using any up-to-date, commercial virus scanning software that examines the Master Boot Record of the hard disk. All Windows file systems can be infected by viruses.


Bug Check 0x7B: INACCESSIBLE_BOOT_DEVICE

The INACCESSIBLE_BOOT_DEVICE bug check has value 0x0000007B. This indicates that Windows has lost access to the system partition during startup. This error always occurs while the system is starting and cannot be debugged because it generally occurs before the operating system has loaded the debugger.

Parameters

The four parameters listed in the message are defined, in order of appearance, as follows:

Parameter | Description
1 | Address of a Unicode string data structure representing the Advanced RISC Computing (ARC) specification name of the device from which the startup was being attempted
2 | Pointer to ARC name string in memory
3 | 0
4 | 0

The first parameter typically contains two separate pieces of data. For example, if the parameter is 0x00800020, 0x0020 is the actual length of the Unicode string and 0x0080 is the maximum name string length. The next parameter contains the address of the buffer. This address is in system space, so the high-order bit is set.

If the file system that is supposed to read the boot device failed to initialize or simply did not recognize the data on the boot device as a file system structure, the following parameter definition applies:

Parameter | Description
1 | Address of the device object that could not be mounted
2 | 0
3 | 0
4 | 0

The value of the first argument determines whether the argument is a pointer to an ARC name string (ARC names are a generic method of identifying devices within the ARC environment) or a device object, because a Unicode string never has an odd number of bytes, and a device object always has a Type code of 0003.

Cause

This error often results from a boot device failure. During I/O system initialization, the boot device driver might have failed to initialize the boot device (typically a hard disk). File system initialization might have failed because it did not recognize the data on the boot device. Also, repartitioning the system partition or installing a new SCSI adapter or disk controller might induce this error.

This error can also result from incompatible disk hardware. If the error occurred at the initial setup of the system, the system might have been installed on an unsupported disk or SCSI controller. Some controllers are supported only by drivers that are in the Windows Driver Library (WDL), which requires the user to do a custom installation.

Resolving the Problem

Resolving a failed boot device problem: If this happens on x86 systems, the boot.ini file must be edited; on Alpha systems, system Setup must be run.

Resolving an incompatible disk hardware problem: If Setup autodetected the controller, you might need to skip detection and use a specific manufacturer's diskette to load the driver. Also, check the availability of updates for the system BIOS and SCSI controller firmware. Updates of this kind are typically available on the web site or BBS of the hardware manufacturer.

Remove any recently added hardware, especially hard disks or controllers, to see if the error is resolved. If the offending piece of hardware was a hard disk, the disk firmware version might be incompatible with your version of Windows. Contact the manufacturer for updates. If the removal of another piece of hardware resolved the error, IRQ or I/O port conflicts likely exist. Reconfigure the new device according to the manufacturer's instructions.

Confirm that all hard disks, hard disk controllers, and SCSI adapters are listed on the Microsoft Windows Hardware Compatibility List (HCL).

If a driver was recently added, restart your computer, and press F8 at the character-based menu that displays the operating system choices. At the resulting Windows Advanced Options menu, choose the Last Known Good Configuration option. This option is most effective when only one driver or service is added at a time.

In addition, check your computer for viruses using any up-to-date, commercial virus scanning software that examines the Master Boot Record of the hard disk. All Windows file systems can be infected by viruses.

This error can also be a result of hard disk corruption. Run Chkdsk /f /r on the system partition. You must restart the system before the disk scan begins. If you cannot start the system due to the error, use the Recovery Console and run Chkdsk /r.

Warning If your system partition is formatted with the FAT file system, the long filenames used by all NT-based operating systems can be damaged if Scandisk or another MS-DOS®–based hard disk tool is used to verify the integrity of your hard disk from an MS-DOS prompt. (An MS-DOS prompt is typically derived from an MS-DOS startup disk or from starting MS-DOS on a multiboot system.) Always use the version of Chkdsk that matches your Windows version.

If your system has SCSI adapters, contact the adapter manufacturer to obtain updated Windows drivers. Try disabling sync negotiation in the SCSI BIOS, checking the cabling and the SCSI IDs of each device, and confirming proper termination. For IDE devices, define the onboard IDE port as Primary only. Also check each IDE device for the proper master/slave/stand alone setting. Try removing all IDE devices except for hard disks. Finally, check the System Log in Event Viewer for additional error messages that might help pinpoint the device or driver that is causing the error.

To analyze this error: Execute an LM command on the debugger. Verify that the following drivers were loaded: disk, classpnp, ftdisk, partmgr, and either FAT or NTFS.

You'll probably need pci or isapnp loaded. Also make sure your controller drivers were loaded — atapi.sys with the channel drivers (pciide and pciidex or intelid) or scsiport.sys with the appropriate miniport driver.

It's always helpful to know as much as possible about the boot device Windows was installed on. Useful ways to investigate include:

  • Find out what type of controller the boot device is connected to (SCSI, IDE, 1394, etc). Try to find out the manufacturer of non-IDE controllers (Adaptec, Symbios, and so on).
  • Note the SCSI ID of the boot device if you're using SCSI.
  • Indicate if other devices are attached to the same controller the boot device is on (CD-ROMs, zip drives, and so on).
  • Note the file system used on the drive.

If you know how to read through !devnode debugger extension output, and you know what your boot devices are, you can get further. Usually Plug and Play couldn't assign resources to the boot device. You can verify this by finding an entry for the service. If the status flags include DNF_INSUFFICIENT_RESOURCES and/or don't include DNF_STARTED or DNF_ENUMERATED, then you've confirmed the problem. Try !devnode 0 1 scsi or !devnode 0 1 atapi to save some time instead of dumping the whole device tree.

kd> lm            //  Displays loaded modules

start    end        module name
80001000 80016000   hal          (deferred)
80016000 80018c40   bootvid      (deferred)
80019000 8001dfc0   pciidex      (deferred)
8001e000 8001ff60   dmload       (deferred)
80086000 80086980   pciide       (deferred)
802c1000 802cc000   pci          (deferred)
802cc000 802d39a0   isapnp       (deferred)
802d4000 802ed000   ftdisk       (deferred)
802ed000 802f3820   mountmgr     (deferred)
802f4000 802fad40   fdc          (deferred)
802fb000 802fdc20   partmgr      (deferred)
802fe000 802fef00   wmilib       (deferred)
8039b000 803b8000   dmio         (deferred)
803b8000 803cb000   atapi        (deferred)
803cb000 803d1560   disk         (deferred)
803d2000 803d8e80   classpnp     (deferred)
803d9000 803fa000   fastfat      (deferred)
80400000 80540000   nt           (pdb symbols)   \\ntstress\symbols\x86\1915\symbols\exe\ntoskrnl.dbg
80540000 80546f20   ksecdd       (deferred)
80547000 80554620   cnss         (deferred)
80555000 80579000   ndis         (deferred)


Bug Check 0x7F: UNEXPECTED_KERNEL_MODE_TRAP

The UNEXPECTED_KERNEL_MODE_TRAP bug check has value 0x0000007F. This signifies that a trap was generated by the Intel CPU which the kernel did not catch.

This could be either a bound trap (a trap the kernel is not permitted to catch) or a double fault (a fault that occurred while processing an earlier fault, which always results in a system crash).

Parameters

The first parameter displayed on the blue screen specifies the trap number.

Here are some of the most common trap codes:

  • 0x00000000, or Divide by Zero Error, is caused when a DIV instruction is executed and the divisor is zero. Memory corruption, other hardware problems, or software failures can cause this error.
  • 0x00000004, or Overflow, occurs when the processor executes a call to an interrupt handler when the overflow (OF) flag is set.
  • 0x00000005, or Bounds Check Fault, is generated when the processor, while executing a BOUND instruction, finds the operand exceeds the specified limits. A BOUND instruction is used to ensure that a signed array index is within a certain range.
  • 0x00000006, or Invalid Opcode, is generated when the processor attempts to execute an invalid instruction. This is generally caused when the instruction pointer has become corrupted and is pointing to the wrong location. The most common cause of this is hardware memory corruption.
  • 0x00000008, or Double Fault, is when an exception occurs while trying to call the handler for a prior exception. Normally, the two exceptions can be handled serially. However, there are several exceptions that cannot be handled serially, and in this situation the processor signals a double fault. This is almost always caused by hardware problems.

The less-common trap codes include:

  • 0x00000001—A system-debugger call
  • 0x00000003—A debugger breakpoint
  • 0x00000007—A hardware coprocessor instruction with no coprocessor present
  • 0x0000000A—A corrupted Task State Segment
  • 0x0000000B—An access to a memory segment that was not present
  • 0x0000000C—An access to memory beyond the limits of a stack
  • 0x0000000D—An exception not covered by some other exception; a protection fault that pertains to access violations for applications

For other trap numbers, consult an Intel architecture manual.

Cause

Bug check 0x7F usually occurs after the installation of faulty or mismatched hardware (especially memory) or in the event that installed hardware fails.

Resolving the Problem

To debug this problem, use the KB (Display Stack Backtrace) debugger command to find the trap frame address. Use the .trap debugger command to format the frame. (On Intel platforms, this frame is associated with the procedure NT!KiTrap.)

If hardware was recently added to the system, remove it to see if the error recurs. If existing hardware has failed, remove or replace the faulty component. Run hardware diagnostics supplied by the system manufacturer, especially the memory scanner, to determine which hardware component has failed. For details on these procedures, see the owner's manual for your computer. Check that all adapter cards in the computer are properly seated. Use an ink eraser or an electrical contact treatment, available at electronics supply stores, to ensure adapter card contacts are clean.

If the error appears on a newly installed system, check the availability of updates for the following items: firmware on RISC systems and BIOS revisions on the motherboard, the SCSI controller or network cards. Updates of this kind are typically available on the web site or BBS of the hardware manufacturer.

Confirm that all hard disks, hard disk controllers, and SCSI adapters are listed on the Microsoft Windows Hardware Compatibility List (HCL).

If the error occurred after the installation of a new or updated device driver, the driver should be removed or replaced. If, under this circumstance, the error occurs during the startup sequence and the system partition is formatted with NTFS, you might be able to use Safe Mode to rename or delete the faulty driver. If the driver is used as part of the system startup process in Safe Mode, you need to start the computer using the Recovery Console in order to access the file. Also try restarting your computer, and press F8 at the character-based menu that displays the operating system choices. At the resulting Windows Advanced Options menu, choose the Last Known Good Configuration option. This option is most effective when only one driver or service is added at a time.

Overclocking (setting the CPU to run at speeds above the rated specification) can cause this error. If this has been done to the computer experiencing the error, return the CPU to the default clock speed setting.

Check the System Log in Event Viewer for additional error messages that might help pinpoint the device or driver that is causing the error. Disabling memory caching of the BIOS might also resolve it.

If you encountered this error while upgrading to a new version of Windows, it might be caused by a device driver, a system service, a virus scanner, or a backup tool that is incompatible with the new version. If possible, remove all third-party device drivers and system services and disable any virus scanners prior to upgrading. Contact the software manufacturer to obtain updates of these tools. Also make sure that you have installed the latest Windows Service Pack.

Finally, if all the above steps fail to resolve the error, take the system motherboard to a repair facility for diagnostic testing. A crack, a scratched trace, or a defective component on the motherboard can also cause this error.


Bug Check 0x9F: DRIVER_POWER_STATE_FAILURE

The DRIVER_POWER_STATE_FAILURE bug check has value 0x0000009F. This signifies that the driver is in an inconsistent or invalid power state.

Parameters

The following parameters are displayed on the blue screen. Parameter 1 indicates the type of violation.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Description
1 | Pointer to the device object | Reserved | Reserved | The device object being freed still has an outstanding power request which it has not completed
2 | Pointer to the target device object | Pointer to the device object | Reserved | The device object completed the IRP for the system power state request, but failed to call PoStartNextPowerIrp
3 | Pointer to the target device object | Pointer to the device object | The IRP | The device driver did not properly set the IRP as "pending" or complete the IRP
100 | Pointer to the nonpaged device object | Pointer to the target device object | Pointer to the device object to notify | The device objects in the devnode were inconsistent in their use of DO_POWER_PAGABLE
101 | Child device object (FDO) | Child device object (PDO) | Parent device object | A parent device object has detected that a child device has not set the DO_POWER_PAGABLE bit


Bug Check 0xBE: ATTEMPTED_WRITE_TO_READONLY_MEMORY

The ATTEMPTED_WRITE_TO_READONLY_MEMORY bug check has value 0x000000BE. This is issued if a driver attempts to write to a read-only memory segment.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Virtual address of attempted write
2 | PTE contents
3 | Reserved
4 | Reserved

If the driver responsible for the error can be identified, its name is printed on the blue screen and stored in PUNICODE_STRING parameter of KiBugCheckDriver.


Bug Check 0xC1: SPECIAL_POOL_DETECTED_MEMORY_CORRUPTION

The SPECIAL_POOL_DETECTED_MEMORY_CORRUPTION bug check has value 0x000000C1. This signals that the driver wrote to an invalid section of the special memory pool.

Parameters

The following parameters are displayed on the blue screen. Parameter 4 indicates the type of violation.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Description
Address that the driver tried to free | Reserved | 0 | 0x20 | Attempt to free pool which was not allocated
Address that the driver tried to free | Bytes requested | Bytes calculated | 0x21, 0x22 | Attempt to free a bad address
Address that the driver tried to free | Address where bits are corrupted | Reserved | 0x23 | Freeing an address when nearby bytes on same page have been corrupted
Address that the driver tried to free | Address where bits are corrupted | Reserved | 0x24 | Freeing an address when bytes after end of allocation have been overwritten
Current IRQL | Pool type | Number of bytes | 0x30 | Attempt to allocate pool at incorrect IRQL
Current IRQL | Pool type | Address that the driver tried to free | 0x31 | Attempt to free pool at incorrect IRQL

The _POOL_TYPE codes are enumerated in ntddk.h. In particular, zero indicates nonpaged pool and one indicates paged pool.

Cause

A driver has written to an invalid section of the special memory pool.

Resolving the Problem

Obtain a backtrace of the current thread. This backtrace will usually reveal the source of the error.

For information about the special pool, consult the Driver Verifier section of the Windows DDK.


Bug Check 0xC2: BAD_POOL_CALLER

The BAD_POOL_CALLER bug check has value 0x000000C2. This signifies that the current thread is making a bad pool request.

Parameters

The following parameters are displayed on the blue screen. Parameter 1 indicates the type of violation.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Description
0x01, 0x02, or 0x04 | Pointer to pool header | First part of pool header contents | 0 | Pool header has been corrupted
0x06 | Reserved | Pointer to pool header | Pool header contents | Attempt to free pool which was already freed
0x07 | Reserved | Pointer to pool header | 0 | Attempt to free pool which was already freed
0x08 | Current IRQL | Pool type | Size of allocation | Attempt to allocate pool at an invalid IRQL
0x09 | Current IRQL | Pool type | Address of pool | Attempt to free pool at an invalid IRQL
0x40 | Starting address | Start of system address space | 0 | Attempt to free kernel pool at user-mode address
0x41 | Starting address | Physical page frame | Highest physical page frame | Attempt to free a nonallocated nonpaged pool address
0x50 | Starting address | Start offset in pages from beginning of paged pool | Size of paged pool, in bytes | Attempt to free a nonallocated paged pool address
0x99 | Address being freed | 0 | 0 | Attempt to free pool with invalid address (or corruption in pool header)
0x9A | Pool type | Number of bytes requested | Pool tag | Allocation request was marked MUST_SUCCEED (this is never permitted)

The _POOL_TYPE codes are enumerated in ntddk.h. In particular, zero indicates nonpaged pool and one indicates paged pool.

Cause

A bad pool request has been made by the current thread.

Resolving the Problem

Activate the Driver Verifier to obtain more information about these errors. For details, consult the Driver Verifier section of the Windows DDK.


Bug Check 0xC4: DRIVER_VERIFIER_DETECTED_VIOLATION

The DRIVER_VERIFIER_DETECTED_VIOLATION bug check has value 0x000000C4. This is the general bug check code for fatal errors found by Driver Verifier.

Parameters

The four bug check parameters are displayed on the blue screen. Parameter 1 identifies the type of violation.

The following parameters are general Driver Verifier violation codes:

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Description
0x00 | Current IRQL | Pool type | 0 | Call to allocate zero bytes (minimum allocation one byte)
0x01 | Current IRQL | Pool type | Number of bytes | Attempt to allocate paged memory at an IRQL above APC_LEVEL
0x02 | Current IRQL | Pool type | Number of bytes | Attempt to allocate nonpaged memory at an IRQL above DISPATCH_LEVEL
0x10 | Bad Address | 0 | 0 | Trying to free an address that was not returned from an allocate call
0x11 | Current IRQL | Pool type | Address of pool | Attempt to free paged pool at an IRQL above APC_LEVEL
0x12 | Current IRQL | Pool type | Address of pool | Attempt to free nonpaged pool at an IRQL above DISPATCH_LEVEL
0x13 or 0x14 | Reserved | Pointer to pool header | Pool header contents | Attempt to free memory pool which was already freed
0x15 | Timer entry | Pool type (-1 for special pool) | Pool address being freed | Attempt to free pool which contains an active timer
0x16 | Reserved | Pool address | 0 | Attempt to free pool at bad address, or passing invalid parameters to memory routine
0x17 | Resource entry | Pool type (-1 for special pool) | Pool address being freed | Attempt to free pool which contains an active ERESOURCE
0x18 | Timer entry | -1 | DLL base address | Attempt to unload a driver whose DLL contains an active timer
0x19 | Resource entry | -1 | DLL base address | Attempt to unload a driver whose DLL contains an active ERESOURCE
0x30 | Current IRQL | Requested IRQL | 0 | Passing an invalid parameter to KeRaiseIrql (either a value lower than the current IRQL, or a value higher than HIGH_LEVEL) — this may result from using an uninitialized parameter
0x31 | Current IRQL | Requested IRQL | 0 | Passing an invalid parameter to KeLowerIrql (either a value higher than the current IRQL, or a value higher than HIGH_LEVEL) — this may result from using an uninitialized parameter
0x32 | Current IRQL | Spin lock address | 0 | Call to KeReleaseSpinLock at an IRQL other than DISPATCH_LEVEL (perhaps due to double-release of spin lock)
0x33 | Current IRQL | Fast mutex address | 0 | Attempt to acquire fast mutex at an IRQL above APC_LEVEL
0x34 | Current IRQL | Fast mutex address | 0 | Attempt to release fast mutex at an IRQL other than APC_LEVEL
0x35 | Current IRQL | Spin lock address | Old IRQL | Kernel is releasing a spin lock when not at DISPATCH_LEVEL
0x36 | Current IRQL | Spin lock number | Old IRQL | Kernel is releasing a queued spin lock when not at DISPATCH_LEVEL
0x37 | Current IRQL | Thread APC disable count | Resource | A resource is being acquired, but APCs are not disabled
0x38 | Current IRQL | Thread APC disable count | Resource | A resource is being released, but APCs are not disabled
0x39 | Current IRQL | Thread APC disable count | Mutex | A mutex is being acquired "unsafe", but IRQL is not APC_LEVEL on entry
0x3A | Current IRQL | Thread APC disable count | Mutex | A mutex is being released "unsafe", but IRQL is not APC_LEVEL on entry
0x3B | Current IRQL | Object to wait on | Timeout parameter | Call to KeWaitXxx at an IRQL of DISPATCH_LEVEL or higher
0x3C | Handle passed to routine | Object type | 0 | Call to ObReferenceObjectByHandle with a bad handle
0x40 | Current IRQL | Spin lock address | 0 | Call to KeAcquireSpinLockAtDpcLevel at an IRQL other than DISPATCH_LEVEL
0x41 | Current IRQL | Spin lock address | 0 | Call to KeReleaseSpinLockFromDpcLevel at an IRQL other than DISPATCH_LEVEL
0x42 | Current IRQL | Spin lock address | 0 | Call to KeAcquireSpinLock at an IRQL above DISPATCH_LEVEL
0x6F | MDL address | Physical page being locked | Highest physical page in the system | Page passed to MmProbeAndLockPages was not in PFN database (this often results from a driver that attempts to lock its own private dualport RAM; such behavior can corrupt memory on machines with noncontiguous physical RAM)
0x70 | Current IRQL | MDL address | Access mode | Call to MmProbeAndLockPages at an IRQL above DISPATCH_LEVEL
0x71 | Current IRQL | MDL address | Process address | Call to MmProbeAndLockProcessPages at an IRQL above DISPATCH_LEVEL
0x72 | Current IRQL | MDL address | Process address | Call to MmProbeAndLockSelectedPages at an IRQL above DISPATCH_LEVEL
0x73 | Current IRQL | Low 32 bits of the physical address (all 64 bits in Win64) | Number of bytes | Call to MmMapIoSpace at an IRQL above DISPATCH_LEVEL
0x74 | Current IRQL | MDL address | Access mode | Call to MmMapLockedPages in kernel mode at an IRQL above DISPATCH_LEVEL
0x75 | Current IRQL | MDL address | Access mode | Call to MmMapLockedPages in user mode at an IRQL above APC_LEVEL
0x76 | Current IRQL | MDL address | Access mode | Call to MmMapLockedPagesSpecifyCache in kernel mode at an IRQL above DISPATCH_LEVEL
0x77 | Current IRQL | MDL address | Access mode | Call to MmMapLockedPagesSpecifyCache in user mode at an IRQL above APC_LEVEL
0x78 | Current IRQL | MDL address | 0 | Call to MmUnlockPages at an IRQL above DISPATCH_LEVEL
0x79 | Current IRQL | Virtual address being unmapped | MDL address | Call to MmUnmapLockedPages in kernel mode at an IRQL above DISPATCH_LEVEL
0x7A | Current IRQL | Virtual address being unmapped | MDL address | Call to MmUnmapLockedPages in user mode at an IRQL above APC_LEVEL
0x7B | Current IRQL | Virtual address being unmapped | Number of bytes | Call to MmUnmapIoSpace at an IRQL above APC_LEVEL
0x7C | MDL address | MDL flags | 0 | Call to MmUnlockPages passed an MDL whose pages were never successfully locked
0x7D | MDL address | MDL flags | 0 | Call to MmUnlockPages passed an MDL whose pages are from nonpaged pool (these should never be unlocked)
0x80 | Current IRQL | Event address | 0 | Call to KeSetEvent at an IRQL above DISPATCH_LEVEL
0x81 | MDL address | MDL flags | 0 | Call to MmMapLockedPages without MDL_MAPPING_CAN_FAIL
0x82 | MDL address | MDL flags | 0 | Call to MmMapLockedPagesSpecifyCache without MDL_MAPPING_CAN_FAIL
0x83 | Start of physical address range to map | Number of bytes to map | First page frame number that isn't locked down | Call to MmMapIoSpace, but the caller has not locked down the MDL pages
0x84 | Start of physical address range to map | Number of bytes to map | First page frame number that is on the free list | Call to MmMapIoSpace, but the caller has not locked down the MDL pages
0x85 | MDL address | Number of pages to map | First page frame number that isn't locked down | Call to MmMapLockedPages, but the caller has not locked down the MDL pages
0x86 | MDL address | Number of pages to map | First page frame number that is on the free list | Call to MmMapLockedPages, but the caller has not locked down the MDL pages
0x90 | Reserved | Reserved | Reserved | A driver switched stacks, and the current stack is neither a thread stack nor a DPC stack. (Typically, the driver doing this should be on the stack obtained by the KB debugger command.)

The following parameters are used only when the Memory Pool Allocation Tracking option of Driver Verifier is active.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Description
0x51 | Base address of allocation | Corrupt address | Number of charged bytes | Driver is trying to free memory after having written past the end of the allocation
0x52 | Base address of allocation | Reserved | Number of charged bytes | Driver is trying to free memory after having written past the end of the allocation
0x53, 0x54, or 0x59 | Base address of allocation | Reserved | Reserved | Driver is trying to free memory after having written past the end of the allocation
0x60 | Bytes allocated from paged pool | Bytes allocated from nonpaged pool | Total number of unfreed allocations | Driver did not free all memory pools prior to unload
0x61 | Bytes allocated from paged pool | Bytes allocated from nonpaged pool | Total number of unfreed allocations | Driver is allocating pool (in another thread) at the same time as it is unloading

The following parameters are used only when the Deadlock Detection option of Driver Verifier is active. This option is only available in Windows XP and later.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Description
0x1000 | Address of the resource | Reserved | Reserved | Self-deadlock: The current thread has tried to recursively acquire a resource
0x1001 | Address of the resource that was the final cause of the deadlock | Reserved | Reserved | Deadlock: A lock hierarchy violation has been found; use the !deadlock extension for further information
0x1002 | Address of the resource | Reserved | Reserved | Uninitialized resource: A resource has been acquired without having been initialized first
0x1003 | Address of the resource that is being released deadlocked | Address of the resource which should have been released first | Reserved | Unexpected release: A resource has been released out of the proper order
0x1004 | Address of the resource | Address of the thread that acquired the resource | Address of the current thread | Unexpected thread: The wrong thread is releasing a resource
0x1005 | Address of the resource | Reserved | Reserved | Multiple initialization: A resource is being initialized more than once
0x1006 | Address of the thread being deleted | Address of the resource owned by the thread | Reserved | Thread holds resources: A thread is being deleted without first releasing its resources
0x1007 | Address of the resource | Reserved | Reserved | Unacquired resource: A resource is being released without having first been acquired

The _POOL_TYPE codes are enumerated in ntddk.h. In particular, zero indicates nonpaged pool and one indicates paged pool.

Cause

See the description of each code in the Parameters section for a description of the cause.

Resolving the Problem

If you are a system administrator, you should unload the driver if the problem persists. Turning Driver Verifier off will also stop these codes from occurring.

If you are the driver writer, use the information obtained through this bug check to fix the bugs in your code.

After a Memory Allocation Tracking bug check, use the following command in the kernel debugger:

kd> dc ViBadDriver l1; dc @$p+4 l1; du @$p

This will return the name of the driver causing the error.

Then use the !verifier extension:

kd> !verifier 3 drivername.sys

This will return information about the leaked memory allocations.

For full details on Driver Verifier, consult the Windows DDK.


Bug Check 0xC5: DRIVER_CORRUPTED_EXPOOL

The DRIVER_CORRUPTED_EXPOOL bug check has value 0x000000C5. This signifies that the system attempted to access invalid memory at a process IRQL that was too high.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory referenced
2 | IRQL at time of reference
3 | 0: Read 1: Write
4 | Address that referenced memory

Cause

A driver has probably corrupted the system pool. This code is usually issued when the corruption was in a small allocation (less than PAGE_SIZE).

Resolving the Problem

To deal with this bug, use the special pool option of Driver Verifier. If this fails to reveal the guilty driver, use the Global Flags utility to enable the special pool by pool tag.

For information about the special pool, consult the Driver Verifier section of the Windows DDK.

See Also

Bug Check 0xD0


Bug Check 0xC6: DRIVER_CAUGHT_MODIFYING_FREED_POOL

The DRIVER_CAUGHT_MODIFYING_FREED_POOL bug check has value 0x000000C6. This signifies that the driver attempted to access a freed memory pool.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory referenced
2 | Zero: Read One: Write
3 | Zero: Kernel mode One: User mode
4 | Four

Comments

The faulty component will be displayed in the current kernel stack.


Bug Check 0xC7: TIMER_OR_DPC_INVALID

The TIMER_OR_DPC_INVALID bug check has value 0x000000C7. This is issued if a kernel timer or delayed procedure call (DPC) is found somewhere in memory where it is not permitted.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | 0: Timer object 1: DPC object 2: DPC routine
2 | Address of object
3 | Beginning of memory range checked
4 | End of memory range checked

Cause

This condition is usually caused by a driver failing to cancel a timer or DPC before freeing the memory where it resides. When Driver Verifier is active, it will catch such errors and issue this bug check.

Resolving the Problem

If you are the driver writer, use the information obtained through this bug check to fix the bugs in your code.

If you are a system administrator, you should unload the driver if the problem persists.

For full details on Driver Verifier, consult the Windows DDK.


Bug Check 0xC9: DRIVER_VERIFIER_IOMANAGER_VIOLATION

The DRIVER_VERIFIER_IOMANAGER_VIOLATION bug check has value 0x000000C9. This is the bug check code for all Driver Verifier I/O Verification violations.

Parameters

When Driver Verifier is active and I/O Verification is selected, various I/O violations will cause this bug check to be issued. The following parameters will be displayed on the blue screen. Parameter 1 identifies the type of violation.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Description
0x01 | Address of IRP being freed | 0 | 0 | Attempt to free object whose type is not IO_TYPE_IRP
0x02 | Address of IRP being freed | 0 | 0 | Attempt to free IRP still associated with a thread
0x03 | Address of IRP being sent | 0 | 0 | Call to IoCallDriver with IRP Type not equal to IRP_TYPE
0x04 | Address of DeviceObject | 0 | 0 | Invalid device object passed to IoCallDriver
0x05 | Address of DeviceObject associated with offending driver | IRQL before IoCallDriver | IRQL after IoCallDriver | IRQL not preserved across call to driver dispatch routine
0x06 | IRP status | Address of IRP being completed | 0 | IoCompleteRequest called with status marked as pending or equal to -1
0x07 | Address of cancel routine | Address of IRP being completed | 0 | IoCompleteRequest called with cancel routine still set
0x08 | Address of DeviceObject | IRP major function code | Exception code | Invalid buffer passed to IoBuildAsynchronousFsdRequest
0x09 | Address of DeviceObject | I/O control code | Exception code | Invalid buffer passed to IoBuildDeviceIoControlRequest
0x0A | Address of DeviceObject | 0 | 0 | Device object with an already-initialized timer passed to IoInitializeTimer
0x0C | Address of IO status block | 0 | 0 | I/O status block passed to IRP is allocated on stack which has already unwound past that point
0x0D | Address of user event object | 0 | 0 | Event passed to IRP is allocated on stack which has already unwound past that point
0x0E | Current IRQL | Address of IRP | 0 | Call to IoCompleteRequest with IRQL above DPC

In addition to the errors mentioned in the previous table, there are a number of I/O Verification errors that will cause Driver Verifier to halt the system, but which are not actually bug checks.

These errors cause messages to be displayed on the blue screen, in a crash dump file, and in a kernel debugger. These messages will appear differently in each of these locations. When these errors occur, the hexadecimal bug check code 0xC9 and the bug check string DRIVER_VERIFIER_IOMANAGER_VIOLATION do not appear on the blue screen or in the debugger, although they will appear in a crash dump file.

On the blue screen, the following data will be displayed:

  • The message IO SYSTEM VERIFICATION ERROR.
  • The name of the driver which caused the error, along with the address in the driver's code where the error was detected.
  • The message WDM DRIVER ERROR XXX, where XXX is a hexadecimal code representing the specific error. (See the table below for a list of the I/O error codes and their meanings.)

If a kernel-mode crash dump has been enabled, the following information will appear in the crash dump file:

  • The message BugCheck 0xC9 (DRIVER_VERIFIER_IOMANAGER_VIOLATION).
  • The hexadecimal I/O error code. (See the table below for a list of the I/O error codes and their meanings.)
  • The address in the driver's code where the error was detected.
  • A pointer to the IRP.
  • A pointer to the DeviceObject.

If a kernel debugger is attached to the system which has caused this violation, the following information will be sent to the debugger:

  • The message WDM DRIVER ERROR, along with an assessment of the severity of the error.
  • The name of the driver which caused the error.
  • A descriptive string which explains the cause of this error. Often additional information is passed along, such as a pointer to the IRP. (See the table below for a list of these descriptive strings and what additional information is specified.)
  • A query for further action. Possible responses are b (break), i (ignore), z (zap), r (remove), or d (disable). Instructing the operating system to continue allows you to see what would happen "down the line" if this error had not occurred. Of course, this often will lead to additional bug checks. The "zap" option will actually remove the breakpoint that caused this error to be discovered.

Note No other bug checks can be ignored in this manner. Only this kind of I/O Verification errors can be ignored, and even these errors can only be ignored if a kernel debugger is attached.

The following table lists those I/O Verification errors that can appear in Windows 2000 and later. In Windows 2000, these errors will only be displayed if I/O Verification is set to Level 2.

I/O Error Code | Severity | Description
0x200 | Unknown | This code covers all unknown I/O Verification errors.
0x201 | Fatal error | A device is deleting itself while there is another device beneath it in the driver stack. This may be because the caller has forgotten to call IoDetachDevice first, or the lower driver may have incorrectly deleted itself.
0x202 | Fatal error | Driver has attempted to detach from device object (specified), which is not attached to anything. This may occur if detach was called twice on the same device object.
0x203 | Fatal error | A driver has called IoCallDriver without setting the CancelRoutine in the IRP to NULL. (IRP specified.)
0x204 | Fatal error | Caller has passed in NULL as a DeviceObject. This is fatal. (IRP specified.)
0x205 | Fatal error | Caller is forwarding an IRP that is currently queued beneath it. The code handling IRPs returning STATUS_PENDING in this driver appears to be broken. (IRP specified.)
0x206 | Fatal error | Caller has incorrectly forwarded an IRP (control field not zeroed). The driver should use IoCopyCurrentIrpStackLocationToNext or IoSkipCurrentIrpStackLocation. (IRP specified.)
0x207 | Fatal error | Caller has manually copied the stack and has inadvertently copied the upper layer's completion routine. Please use IoCopyCurrentIrpStackLocationToNext. (IRP specified.)
0x208 | Fatal error | This IRP is about to run out of stack locations. Someone may have forwarded this IRP from another stack. (IRP specified.)
0x209 | Fatal error | Caller is completing an IRP that is currently queued beneath it. The code handling IRPs returning STATUS_PENDING in this driver appears to be broken. (IRP specified.)
0x20A | Fatal error | Caller of IoFreeIrp is freeing an IRP that is still in use. (Original IRP and IRP in use specified.)
0x20B | Fatal error | Caller of IoFreeIrp is freeing an IRP that is still in use. (IRP specified.)
0x20C | Fatal error | Caller of IoFreeIrp is freeing an IRP that is still queued against a thread. (IRP specified.)
0x20D | Fatal error | Caller of IoInitializeIrp has passed an IRP that was allocated with IoAllocateIrp. This is illegal and unnecessary, and has caused a quota leak. Check the documentation for IoReuseIrp if this IRP is being recycled.
0x20E | Non-fatal error | Any PNP IRP must have status initialized to STATUS_NOT_SUPPORTED. (IRP specified.)
0x20F | Non-fatal error | Any Power IRP must have status initialized to STATUS_NOT_SUPPORTED. (IRP specified.)
0x210 | Non-fatal error | Any WMI IRP must have status initialized to STATUS_NOT_SUPPORTED. (IRP specified.)
0x211 | Non-fatal error | Caller has forwarded an IRP while skipping a device object in the stack. The caller is probably sending IRPs to the PDO instead of to the device returned by IoAttachDeviceToDeviceStack. (IRP specified.)
0x212 | Non-fatal error | Caller has trashed or has not properly copied the IRP's stack. (IRP specified.)
0x213 | Non-fatal error | Caller has changed the status field of an IRP it does not understand. (IRP specified.)
0x214 | Non-fatal error | Caller has changed the information field of an IRP it does not understand. (IRP specified.)
0x215 | Non-fatal error | Non-successful non-STATUS_NOT_SUPPORTED IRP status for IRP_MJ_PNP is being passed down stack. (IRP specified.) Failed PNP IRPs must be completed.
0x216 | Non-fatal error | Previously set IRP_MJ_PNP status has been converted to STATUS_NOT_SUPPORTED. (IRP specified.)
0x217 | Non-fatal error | FDO caller has not handled a required IRP. The FDO must either fail the IRP or set the IRP's status if it is not going change the IRP's status using a completion routine. (IRP specified.)
0x218 | Non-fatal error | FDO caller has responded to an IRP that is reserved for PDO use only. (IRP specified.)
0x219 | Non-fatal error | Non-successful non-STATUS_NOT_SUPPORTED IRP status for IRP_MJ_POWER is being passed down stack. (IRP specified.) Failed POWER IRPs must be completed.
0x21A | Non-fatal error | Previously set IRP_MJ_POWER status has been converted to STATUS_NOT_SUPPORTED. (IRP specified.)
0x21B | Non-fatal error | Driver has returned a suspicious status. This is probably due to an uninitialized variable bug in the driver. (IRP specified.)
0x21C | Warning | Caller has copied the IRP stack but not set a completion routine. This is inefficient -- use IoSkipCurrentIrpStackLocation instead. (IRP specified.)
0x21D | Fatal error | An IRP dispatch handler has not properly detached from the stack below it upon receiving a remove IRP. (DeviceObject, Dispatch Routine, and IRP specified.)
0x21E | Fatal error | An IRP dispatch handler has not properly deleted its device object upon receiving a remove IRP. (DeviceObject, Dispatch Routine, and IRP specified.)
0x21F | Non-fatal error | This driver has not filled out a dispatch routine for a required IRP major function. (IRP specified.)
0x220 | Non-fatal error | IRP_MJ_SYSTEM_CONTROL has been completed by someone other than the ProviderId. This IRP should either have been completed earlier or should have been passed down. (IRP specified, along with the DeviceObject where it was targeted.)
0x221 | Fatal error | An IRP dispatch handler for a PDO has deleted its device object, but the hardware has not been reported as missing in a bus relations query. (DeviceObject, Dispatch Routine, and IRP specified.)
0x222 | Fatal error | A Bus Filter's IRP dispatch handler has detached upon receiving a remove IRP when the PDO is still alive. Bus Filters must clean up in FastIoDetach callbacks. (DeviceObject, Dispatch Routine, and IRP specified.)
0x223 | Fatal error | An IRP dispatch handler for a bus filter has deleted its device object, but the PDO is still present. Bus filters must clean up in FastIoDetach callbacks. (DeviceObject, Dispatch Routine, and IRP specified.)
0x224 | Fatal error | An IRP dispatch handler has returned a status that is inconsistent with the IRP's IoStatus.Status field. (Dispatch handler routine, IRP, IRP's IoStatus.Status, and returned Status specified.)
0x225 | Non-fatal error | An IRP dispatch handler has returned a status that is illegal (0xFFFFFFFF). This is probably due to an uninitialized stack variable. To debug this, execute an LN command on the specified address.
0x226 | Fatal error | An IRP dispatch handler has returned without passing down or completing this IRP, or someone forgot to return STATUS_PENDING. (IRP specified.)
0x227 | Fatal error | IRP completion routines must be in nonpagable code, and this one is not. (Routine and IRP specified.)
0x228 | Non-fatal error | A driver's completion routine has not marked the IRP pending if the PendingReturned field was set in the IRP passed to it. This may cause the OS to hang, especially if an error is returned by the stack. (Routine and IRP specified.)
0x229 | Fatal error | A cancel routine has been set for an IRP that is currently being processed by drivers lower in the stack, possibly stomping their cancel routine. (Routine and IRP specified.)
0x22A | Non-fatal error | PDO has not responded to a required IRP. (IRP specified.)
0x22B | Non-fatal error | PDO has forgotten to fill out the device relation list with the PDO for the TargetDeviceRelation query. (IRP specified.)
0x22C | Fatal error | The code implementing the TargetDeviceRelation query has not called ObReferenceObject on the PDO. (IRP specified.)
0x22D | Non-fatal error | Caller has completed a IRP_MJ_PNP it didn't understand instead of passing it down. (IRP specified.)
0x22E | Non-fatal error | Caller has completed successful IRP_MJ_PNP instead of passing it down. (IRP specified.)
0x22F | Non-fatal error | Caller has completed untouched IRP_MJ_PNP (instead of passing the IRP down), or non-PDO has failed the IRP using illegal value of STATUS_NOT_SUPPORTED. (IRP specified.)
0x230 | Non-fatal error | Caller has completed a IRP_MJ_POWER it didn't understand instead of passing it down. (IRP specified.)
0x231 | Fatal error | Caller has completed successful IRP_MJ_POWER instead of passing it down. (IRP specified.)
0x232 | Non-fatal error | Caller has completed untouched IRP_MJ_POWER (instead of passing the IRP down) or non-PDO has failed the IRP using illegal value of STATUS_NOT_SUPPORTED. (IRP specified.)
0x233 | Fatal error | The version field of the query capabilities structure in a query capabilities IRP was not properly initialized. (IRP specified.)
0x234 | Fatal error | The size field of the query capabilities structure in a query capabilities IRP was not properly initialized. (IRP specified.)
0x235 | Non-fatal error | The address field of the query capabilities structure in a query capabilities IRP was not properly initialized to -1. (IRP specified.)
0x236 | Non-fatal error | The UI Number field of the query capabilities structure in a query capabilities IRP was not properly initialized to -1. (IRP specified.)
0x237 | Fatal error | A driver has sent an IRP that is restricted for system use only. (IRP specified.)
0x238 | Warning | Caller of IoInitializeIrp has passed an IRP that was allocated with IoAllocateIrp. This is illegal, unnecessary, and negatively impacts performance in normal use. Check the documentation for IoReuseIrp if this IRP is being recycled.
0x239 | Warning | The caller of IoCompleteRequest is completing an IRP that has never been forwarded via a call to IoCallDriver or PoCallDriver. This may be a bug. (IRP specified.)
0x23A | Fatal error | A driver has forwarded an IRP at an IRQL that is illegal for this major code. (IRP specified.)
0x23B | Fatal error | Caller has changed the status field of an IRP it does not understand. (IRP specified.)

The following table lists additional I/O Verification errors that can appear in Windows XP and later. Some of these errors will only be revealed if Enhanced I/O Verification is activated.

I/O Error Code | Severity | Description
0x23C | Fatal error | A driver has completed an IRP without setting the cancel routine in the IRP to NULL. (IRP specified.)
0x23D | Fatal error | A driver has returned STATUS_PENDING but did not mark the IRP pending via a call to IoMarkIrpPending. (IRP specified.)
0x23E | Fatal error | A driver has marked an IRP pending but didn't return STATUS_PENDING. (IRP specified.)
0x23F | Fatal error | A driver has not inherited the DO_POWER_PAGABLE bit from the stack it has attached to. (DeviceObject specified.)
0x240 | Fatal error | A driver is attempting to delete a device object that has already been deleted via a prior call to IoDeleteDevice.
0x241 | Fatal error | A driver has detached its device object during a surprise remove IRP. (IRP and DeviceObject specified.)
0x242 | Fatal error | A driver has deleted its device object during a surprise remove IRP. (IRP and DeviceObject specified.)
0x243 | Fatal error | A driver has failed to clear the DO_DEVICE_INITIALIZING flag at the end of AddDevice. (DeviceObject specified.)
0x244 | Fatal error | A driver has not copied either the DO_BUFFERED_IO or the DO_DIRECT_IO flag from the device object it is attaching to. (DeviceObject specified.)
0x245 | Fatal error | A driver has set both the DO_BUFFERED_IO and the DO_DIRECT_IO flags. These flags are mutually exclusive. (DeviceObject specified.)
0x246 | Fatal error | A driver has failed to copy the DeviceType field from the device object it is attaching to. (DeviceObject specified.)
0x247 | Fatal error | A driver has failed an IRP that cannot legally be failed. (IRP specified.)
0x248 | Fatal error | A driver has added a device object that is not a PDO to a device relations query. (IRP and DeviceObject specified.)
0x249 | Fatal error | A driver has enumerated two child PDOs that returned identical Device IDs. (Both DeviceObjects specified.)
0x24A | Fatal error | A driver has mistakenly called a file I/O function at an IRQL other than PASSIVE_LEVEL.

Cause

See the description of each code in the Parameters section for a description of the cause.

Resolving the Problem

If you are the driver writer, use the information obtained through this bug check to fix the bugs in your code.

If you are a system administrator, you should unload the driver if the problem persists.

For full details on Driver Verifier, consult the Windows DDK.


Bug Check 0xCA: PNP_DETECTED_FATAL_ERROR

The PNP_DETECTED_FATAL_ERROR bug check has value 0x000000CA. This signifies that the Plug and Play Manager encountered a severe error, probably as a result of a flawed Plug and Play driver.

Parameters

The following parameters are displayed on the blue screen. Parameter 1 identifies the type of violation.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Description
0x01 | Address of newly reported PDO | Address of older PDO which has been duplicated | Reserved | Duplicate PDO. A specific instance of a driver has enumerated multiple PDOs with identical device ID and unique IDs.
0x02 | Address of purported PDO | Reserved | Reserved | Invalid PDO. An API which requires a PDO has been called with one of the following: random memory, an FDO, or a PDO which hasn't been initialized (that is, it has not been returned to Plug and Play by QueryDeviceRelation or QueryBusRelations).
0x03 | Address of PDO whose IDs were queried | Address of ID buffer | 1: DeviceID 2: UniqueID 3: HardwareIDs 4: CompatibleIDs | Invalid ID. An enumerator has returned an ID which contains illegal characters or isn't properly terminated. (IDs must contain only characters in the ranges 0x20 - 0x2B and 0x2D - 0x7F.)
0x04 | Address of PDO with DOE_DELETE_PENDING set | Reserved | Reserved | Invalid enumeration of deleted PDO. An enumerator has returned a PDO which it had previously deleted using IoDeleteDevice.
0x05 | Address of PDO | Reserved | Reserved | PDO freed while linked in devnode tree. The object manager reference count on a PDO dropped to zero while the devnode was still linked in the tree. (This usually indicates that the driver is not adding a reference when returning the PDO in a query IRP.)


Bug Check 0xCB: DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS

The DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS bug check has value 0x000000CB. This signifies that a driver failed to release locked pages after an I/O operation.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Calling address in driver that locked the pages
2 | Caller of the calling address in driver that locked the pages
3 | Pointer to MDL containing the locked pages
4 | Guilty driver's name (pointer to Unicode string)

If the guilty driver can be identified, its name is printed on the blue screen and stored in PUNICODE_STRING parameter of KiBugCheckDriver and in Parameter 4.

Comments

This bug check is issued only if the registry key \\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\TrackLockedPages is equal to DWORD 1. If this key is not set, the system will issue the less-informative bug check 0x76, PROCESS_HAS_LOCKED_PAGES.

See Also

Bug Check 0x76


Bug Check 0xCC: PAGE_FAULT_IN_FREED_SPECIAL_POOL

The PAGE_FAULT_IN_FREED_SPECIAL_POOL bug check has value 0x000000CC. This signals that the system has referenced memory which was earlier freed.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory address referenced
2 | 0: Read 1: Write
3 | Address that referenced memory (if known)
4 | Reserved

If the guilty driver can be identified, its name is printed on the blue screen and stored in PUNICODE_STRING parameter of KiBugCheckDriver.

Cause

The system has accessed memory in the special pool which was already freed by a driver. This usually indicates a system-driver synchronization problem.

For information about the special pool, consult the Driver Verifier section of the Windows DDK.

Comments

This cannot be protected by try - except; it can only be protected by a probe.


Bug Check 0xCD: PAGE_FAULT_BEYOND_END_OF_ALLOCATION

The PAGE_FAULT_BEYOND_END_OF_ALLOCATION bug check has value 0x000000CD. This signals that the system accessed memory beyond the end of some driver's pool allocation.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory address referenced
2 | 0: Read 1: Write
3 | Address that referenced memory (if known)
4 | Reserved

If the guilty driver can be identified, its name is printed on the blue screen and stored in PUNICODE_STRING parameter of KiBugCheckDriver.

Cause

The driver allocated n bytes of memory from the special pool. Subsequently, the system referenced more than n bytes from this pool. This usually indicates a system-driver synchronization problem.

For information about the special pool, consult the Driver Verifier section of the Windows DDK.

Comments

This cannot be protected by try - except; it can only be protected by a probe.


Bug Check 0xCE: DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS

The DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS bug check has value 0x000000CE. This signals that a driver failed to cancel pending operations before unloading.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory address referenced
2 | 0: Read 1: Write
3 | Address that referenced memory (if known)
4 | Reserved

If the guilty driver can be identified, its name is printed on the blue screen and stored in PUNICODE_STRING parameter of KiBugCheckDriver.

Cause

This driver failed to cancel lookaside lists, DPCs, worker threads, or other such items before unload.


Bug Check 0xCF: TERMINAL_SERVER_DRIVER_MADE_INCORRECT_MEMORY_REFERENCE

The TERMINAL_SERVER_DRIVER_MADE_INCORRECT_MEMORY_REFERENCE bug check has value 0x000000CF. This signals that a driver has been incorrectly ported to the terminal server.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory address referenced
2 | 0: Read 1: Write
3 | Address that referenced memory (if known)
4 | Reserved

If the guilty driver can be identified, its name is printed on the blue screen and stored in PUNICODE_STRING parameter of KiBugCheckDriver.

Cause

The driver is referencing session space addresses from the system process context.

The driver probably queued an item to a system worker thread.


Bug Check 0xD0: DRIVER_CORRUPTED_MMPOOL

The DRIVER_CORRUPTED_MMPOOL bug check has value 0x000000D0. This signifies that the system attempted to access invalid memory at a process IRQL that was too high.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory referenced
2 | IRQL at time of reference
3 | 0: Read 1: Write
4 | Address that referenced memory

Cause

A driver has probably corrupted the system pool. This code is usually issued when the corruption was in a large allocation (PAGE_SIZE or larger).

Resolving the Problem

To deal with this bug, use the special pool option of Driver Verifier. If this fails to reveal the guilty driver, use the Global Flags utility to enable the special pool by pool tag.

For information about the special pool, consult the Driver Verifier section of the Windows DDK.

An alternate method is to set the \\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\ProtectNonPagedPool registry key equal to DWORD 1 and reboot. Then the system will unmap all freed nonpaged pool. This will prevent drivers from corrupting the pool. (This does not protect the pool from DMA hardware, however.)

See Also

Bug Check 0xC5


Bug Check 0xD1: DRIVER_IRQL_NOT_LESS_OR_EQUAL

The DRIVER_IRQL_NOT_LESS_OR_EQUAL bug check has value 0x000000D1. This signifies that the system attempted to access pageable memory at a process IRQL that was too high.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory referenced
2 | IRQL at time of reference
3 | 0: Read 1: Write
4 | Address that referenced memory

Cause

This bug check is usually caused by drivers that have used improper addresses.

Resolving the Problem

To deal with this bug, use a kernel debugger to get a stack trace.


Bug Check 0xD3: DRIVER_PORTION_MUST_BE_NONPAGED

The DRIVER_PORTION_MUST_BE_NONPAGED bug check has value 0x000000D3. This signifies that the system attempted to access pageable memory at a process IRQL that was too high.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory referenced
2 | IRQL at time of reference
3 | 0: Read 1: Write
4 | Address that referenced memory

If the guilty driver can be identified, its name is printed on the blue screen and stored in PUNICODE_STRING parameter of KiBugCheckDriver.

Cause

This bug check is usually caused by drivers that have incorrectly marked code or data as pageable.

Resolving the Problem

To deal with this bug, use a kernel debugger to get a stack trace.


Bug Check 0xD4: SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD

The SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD bug check has value 0x000000D4. This signifies that a driver did not cancel pending operations before unloading.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory referenced
2 | IRQL at time of reference
3 | 0: Read 1: Write
4 | Address that referenced memory

If the guilty driver can be identified, its name is printed on the blue screen and stored in PUNICODE_STRING parameter of KiBugCheckDriver.

Cause

This driver failed to cancel lookaside lists, DPCs, worker threads, or other such items before unload. Subsequently, the system attempted to access the driver's former location at a raised IRQL.

Resolving the Problem

To deal with this bug, use a kernel debugger to get a stack trace. If the guilty driver has been identified, activate Driver Verifier and attempt to replicate this bug.

For full details on Driver Verifier, consult the Windows DDK.


Bug Check 0xD5: DRIVER_PAGE_FAULT_IN_FREED_SPECIAL_POOL

The DRIVER_PAGE_FAULT_IN_FREED_SPECIAL_POOL bug check has value 0x000000D5. This signals that a driver has referenced memory which was earlier freed.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory address referenced
2 | 0: Read 1: Write
3 | Address that referenced memory (if known)
4 | Reserved

If the guilty driver can be identified, its name is printed on the blue screen and stored in PUNICODE_STRING parameter of KiBugCheckDriver.

Cause

The Driver Verifier Special Memory Pool option has caught the driver accessing memory which was earlier freed.

For information about the special pool, consult the Driver Verifier section of the Windows DDK.

Comments

This cannot be protected by try - except; it can only be protected by a probe.


Bug Check 0xD6: DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION

The DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION bug check has value 0x000000D6. This signals the driver accessed memory beyond the end of its pool allocation.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory address referenced
2 | 0: Read 1: Write
3 | Address that referenced memory (if known)
4 | Reserved

If the guilty driver can be identified, its name is printed on the blue screen and stored in PUNICODE_STRING parameter of KiBugCheckDriver.

Cause

The driver allocated n bytes of memory and then referenced more than n bytes. The Driver Verifier Special Memory Pool option detected this violation.

For information about the special pool, consult the Driver Verifier section of the Windows DDK.

Comments

This cannot be protected by try - except; it can only be protected by a probe.


Bug Check 0xD7: DRIVER_UNMAPPING_INVALID_VIEW

The DRIVER_UNMAPPING_INVALID_VIEW bug check has value 0x000000D7. This signifies a driver is trying to unmap an address that was not mapped.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Virtual address to unmap
2 | 0: system is not Terminal Server 1: system is Terminal Server
3 | 0
4 | 0

Comments

The guilty driver can be determined from the stack trace.


Bug Check 0xD8: DRIVER_USED_EXCESSIVE_PTES

The DRIVER_USED_EXCESSIVE_PTES bug check has value 0x000000D8. This signifies that there are no more system page table entries (PTE) remaining.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Pointer to the guilty driver's name (Unicode string), or zero
2 | Number of PTEs used by the guilty driver (if Parameter 1 is nonzero)
3 | Total free system PTEs
4 | Total system PTEs

If the guilty driver can be identified, its name is printed on the blue screen and stored in PUNICODE_STRING parameter of KiBugCheckDriver.

Cause

This is usually caused by a driver not cleaning up properly. Parameter 1 shows the driver which has consumed the most PTEs. The call stack will reveal which driver actually caused the bug check.

Resolving the Problem

Both drivers may need to be fixed. The total number of system PTEs may also need to be increased.


Bug Check 0xDB: DRIVER_CORRUPTED_SYSPTES

The DRIVER_CORRUPTED_SYSPTES bug check has value 0x000000DB. This signifies that an attempt was made to touch memory at an invalid IRQL, probably due to corruption of system PTEs.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Memory referenced
2 | IRQL
3 | 0: read 1: write
4 | Address in code which referenced memory

Cause

This bug check is almost always caused by drivers that have corrupted system PTEs.

Resolving the Problem

If this bug check occurs, the culprit can be detected by editing the registry. In the \\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\ registry path, set a TrackPtes key equal to DWORD 1, then reboot. The system will then save stack traces, and if the driver commits the same error, the system will issue bug check 0xDA, SYSTEM_PTE_MISUSE. Then the stack trace will identify the guilty driver.


Bug Check 0xDC: DRIVER_INVALID_STACK_ACCESS

The DRIVER_INVALID_STACK_ACCESS bug check has value 0x000000DC. This signifies that a driver accessed a stack address that lies below the stack pointer of the stack's thread.

Parameters

None.


Bug Check 0xE1: WORKER_THREAD_RETURNED_AT_BAD_IRQL

The WORKER_THREAD_RETURNED_AT_BAD_IRQL bug check has value 0x000000E1. This signifies that a worker thread completed and returned at IRQL DISPATCH_LEVEL or above.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Address of the worker routine
2 | IRQL (ought to have been zero)
3 | Work item parameter
4 | Work item address

Cause

A worker thread completed and returned at IRQL DISPATCH_LEVEL or above.

Resolving the Problem

To find the guilty driver, use the following kernel debugger command:

kd> ln address

where address is the worker routine address given in Parameter 1.


Bug Check 0xE2: MANUALLY_INITIATED_CRASH

The MANUALLY_INITIATED_CRASH bug check has value 0x000000E2. This signifies that the user deliberately initiated a crash dump from either the kernel debugger or the keyboard.

Parameters

None.

Comments

For details on manually-initiated crash dumps, see the debugger documentation.


Bug Check 0xE3: RESOURCE_NOT_OWNED

The RESOURCE_NOT_OWNED bug check has value 0x000000E3. This signifies that a thread tried to release a resouce it did not own.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Address of resource
2 | Address of thread
3 | Address of owner table (if it exists)
4 | Reserved


Bug Check 0xE4: WORKER_INVALID

The WORKER_INVALID bug check has value 0x000000E4. This signifies that an executive worker item was found in memory which must not contain such items.

Parameters

The following parameters are displayed on the blue screen.

Parameter | Description
1 | Code position indicator
2 | Address of worker item
3 | Start of pool block
4 | End of pool block

Cause

This is usually caused by a driver freeing memory which still contains an executive worker item.


Bug Check 0xE6: DRIVER_VERIFIER_DMA_VIOLATION

The DRIVER_VERIFIER_DMA_VIOLATION bug check has value 0x000000E6. This is the bug check code for all Driver Verifier DMA Verification violations.

Parameters

The following parameters are displayed on the blue screen. Parameter 1 is the only parameter of interest; this identifies the exact violation.

Parameter 1 | Description
0x03 | The driver freed the same DMA common buffer twice.
0x04 | The driver freed the same DMA adapter channel twice.
0x05 | The driver freed the same DMA map register twice.
0x06 | The driver freed the same DMA scatter-gather list twice.
0x0E | The driver attempted a DMA transfer without locking the buffer. The buffer in question was in paged memory.
0x0F | The driver or the hardware wrote past the end of its allocated DMA buffer.
0x18 | The driver attempted a DMA operation using an adapter that was already released and no longer exists.
0x19 | The driver passed a null DMA_ADAPTER value to a HAL routine.
0x1B | The driver passed an address and MDL to a HAL routine, but this address is not contained in this MDL.
0x1D | The driver attempted to map an address that was already mapped.

Cause

See the description of each code in the Parameters section for a description of the cause.

Resolving the Problem

If you are the driver writer, use the information obtained through this bug check to fix the bugs in your code.

If you are a system administrator, you should unload the driver if the problem persists.

The Driver Verifier DMA Verification option is only available in Windows XP and later. For full details on Driver Verifier, consult the Windows DDK.


Bug Check 0xF1: SCSI_VERIFIER_DETECTED_VIOLATION

The SCSI_VERIFIER_DETECTED_VIOLATION bug check has value 0x000000F1. This is the bug check code for all Driver Verifier SCSI Verification violations.

Parameters

The four bug check parameters are displayed on the blue screen. Parameter 1 identifies the type of violation.

Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Description
0x1000 | First argument passed | Second argument passed | Reserved | Miniport passed bad arguments to ScsiPortInitialize.
0x1001 | Delay, in microseconds | Reserved | Reserved | Miniport called ScsiPortStallExecution and specified a delay greater than 0.1 second, stalling the processor too long.
0x1002 | Address of routine that took too long | Address of miniport's HW_DEVICE_EXTENSION | Duration of the routine, in microseconds | Miniport routine called by the port driver took longer than 0.5 second to execute. (The HwInitialize routine is allowed 5 seconds, and the FindAdapter routine is exempt.)
0x1003 | Address of miniport's HW_DEVICE_EXTENSION | Address of the SRB | Reserved | Miniport completed a request more than once.
0x1004 | Address of the SRB | Address of miniport's HW_DEVICE_EXTENSION | Reserved | Miniport completed a request with an invalid SRB status.
0x1005 | Address of miniport's HW_DEVICE_EXTENSION | Address of LOGICAL_UNIT_EXTENSION | Reserved | Miniport called ScsiPortNotification to ask for NextLuRequest, but an untagged request is still active.
0x1006 | Address of miniport's HW_DEVICE_EXTENSION | Invalid virtual address | Reserved | Miniport passed an invalid virtual address to ScsiPortGetPhysicalAddress. (This usually means the address supplied doesn't map to the common buffer area.)
0x1007 | Address of ADAPTER_EXTENSION | Address of miniport's HW_DEVICE_EXTENSION | Reserved | The reset hold period for the bus ended, but miniport still has outstanding requests.

Cause

See the description of each code in the Parameters section for an explanation of the cause.

Resolving the Problem

If you are the driver writer, use the information obtained through this bug check to fix the bugs in your code.

If you are a system administrator, you should unload the driver if the problem persists.

The Driver Verifier SCSI Verification option is only available in Windows XP and later. For full details on Driver Verifier, consult the Windows DDK.


Bug Check 0xC000021A: STATUS_SYSTEM_PROCESS_TERMINATED

The STATUS_SYSTEM_PROCESS_TERMINATED bug check has value 0xC000021A. This means that an error has occurred in a crucial user-mode subsystem.

Parameters

The error message includes the following three parameters, in order of appearance:

Parameter | Description
1 | Status code
2 | 0
3 | 0

For information about all possible status codes that might be returned, see the file ntstatus.h in the Windows DDK.

Cause

This error occurs when a user-mode subsystem, such as WinLogon or the Client Server Runtime Subsystem (CSRSS), has been fatally compromised and security can no longer be guaranteed. In response, the operating system switches to kernel mode. Microsoft Windows cannot run without WinLogon or CSRSS. Therefore, this is one of the few cases where the failure of a user-mode service can shut down the system.

Mismatched system files can also cause this error. This can occur if you have restored your hard disk from a backup. Some backup programs might skip restoring system files that they determine are in use.

Resolving the Problem

Running the kernel debugger is not useful in this situation because the actual error occurred in a user-mode process.

Resolving an error in a user-mode device driver, system service, or third-party application: Because bug check 0xC000021A occurs in a user-mode process, the most common culprits are third-party applications. If the error occurred after the installation of a new or updated device driver, system service, or third-party application, the new software should be removed or disabled. Contact the manufacturer of the software about a possible update.

If the error occurs during system startup, restart your computer, and press F8 at the character-based menu that displays the operating system choices. At the resulting Windows Advanced Options menu, choose the Last Known Good Configuration option. This option is most effective when only one driver or service is added at a time. If this does not resolve the error, try manually removing the offending software. If the system partition is formatted with file allocation table (FAT), use a Microsoft MS-DOS® startup disk to gain access to the computer's hard disk. If the system partition is formatted with NTFS file system, you might be able to use Safe Mode to rename or delete the faulty software. If the faulty software is used as part of the system startup process in Safe Mode, you need to start the computer using the Recovery Console in order to access the file. If a newly installed piece if hardware is suspected, remove it to see if this resolves the issue.

Try running the Emergency Recovery Disk (ERD) and allow the system to repair any errors that it detects.

Resolving a mismatched system file problem: If you have recently restored your hard disk from a backup, check if there is an updated version of the Backup/Restore program available from the manufacturer. Make sure the latest Windows Service Pack is installed.


Bug Check 0xC0000221: STATUS_IMAGE_CHECKSUM_MISMATCH

The STATUS_IMAGE_CHECKSUM_MISMATCH bug check has value 0xC0000221. This indicates that a driver or a system DLL has been corrupted.

Parameters

This bug check will display a descriptive text message.

Typically, the name of the damaged file is displayed as part of the message.

Cause

This bug check results from a serious error in a driver or other system file.

This can also be caused by a disk error, faulty RAM, or a corrupted page file.

Resolving the Problem

To remedy this error, run the Emergency Recovery Disk (ERD) and allow the system to repair or replace the missing or damaged driver file on the system partition.

You can also run an in-place upgrade over the existing copy of Windows. This preserves all registry settings and configuration information, but replaces all system files. If any Service Packs and/or hotfixes had previously been applied, you need to reinstall them afterward in the appropriate order (latest Service Pack, then any post-Service Pack hotfixes in the order in which they were originally installed, if applicable).

If a specific file was identified in the bug check message as being corrupted, you can try replacing that individual file manually. If the system partition is formatted with FAT, start from an MS-DOS startup disk and copy the file from the original source onto the hard disk. If the partition is NTFS, you need to restart the system, press F8 at the operating system Loader menu, and choose Safe Mode with Command Prompt. From there, copy a fresh version of the file from the original source onto the hard disk. If the file is used as part of the system startup process in Safe Mode, you need to start the computer using the Recovery Console in order to access the file. If these methods fail, try reinstalling Windows and then restoring the system from a backup.

Note If the original file from the product CD has a filename extension ending in an _ (underscore), the file needs to be uncompressed before it can be used. The Recovery Console's Copy command automatically detects compressed files and expands them as they are copied to the target location. If you are using Safe Mode to access a drive, use the Expand command to uncompress and copy the file to the target folder. You can use the Expand command in the command line environment of Safe Mode.

Resolving a disk error problem: Disk errors can be a source of file corruption. Run Chkdsk /f /r to detect and resolve any file system structural corruption. You must restart the system before the disk scan begins on a system partition.

Resolving a RAM problem: If the error occurred immediately after RAM was added to the system, the paging file might be corrupted or the new RAM itself might be either faulty or incompatible.

To determine if newly added RAM is causing a bug check

  1. Return the system to the original RAM configuration.
  2. Use the Recovery Console to access the partition containing the paging file and delete the file pagefile.sys.
  3. While still in the Recovery Console, run Chkdsk /r on the partition that contained the paging file.
  4. Restart the system.
  5. Set the paging file to an optimal level for the amount of RAM added.
  6. Shutdown the system and add your RAM.

    The new RAM must meet the system manufacturer's specifications for speed, parity, and type (that is, fast page-mode (FPM) versus extended data out (EDO) versus synchronous dynamic random access memory (SDRAM)). Try to match the new RAM to the existing installed RAM as closely as possible. RAM can come in many different capacities, and more importantly, in different formats (single inline memory modules — SIMM — or dual inline memory modules — DIMM). The electrical contacts can be either gold or tin and it is not wise to mix these contact types.

If you experience the same error message after reinstalling the new RAM, run hardware diagnostics supplied by the system manufacturer, especially the memory scanner. For details on these procedures, see the owner's manual for your computer.

When you can log on to the system again, check the System Log in Event Viewer for additional error messages that might help pinpoint the device or driver that is causing the error.

Disabling memory caching of the BIOS might also resolve this error.


The Build Utility

The Build utility is used to build the samples, drivers, and associated software components that are supplied in the Microsoft® Windows® DDK. The Build utility helps you maintain target-dependent information, such as source file names and paths to header files and output directories, in a single file. The utility automatically sets the compiler and linker switches which are required to create output files for specific platforms that you specify.

This section includes:

Using the Build Utility

Build Utility Reference


Using the Build Utility

This section describes the use of the Build utility. This information is presented in the following topics:

Overview of the Build Utility

How to Use the Build Utility

Build Utility Techniques

Debugging Build Utility Products

Build Utility Limitations and Rules


Overview of the Build Utility

This section provides an overview of the Build utility. This overview includes the following topics:

Build Utility Features

Why You Should Use the Build Utility

How to Get the Build Utility


Build Utility Features

The Build utility:

  • Automatically establishes file dependencies.
  • Provides tools to build products for multiple hardware platforms without specifying any target-specific information.
  • Shields you from the detailed inputs and outputs of the various compilers and machine architectures.
  • Is multiprocessor aware for speedier compilation.
  • Provides detailed information about the build process.
  • Provides feedback during compilation, including information about:
    • when the build will complete
    • the number of code lines being compiled
    • how fast the Build utility is compiling the lines
    • the number of files you must link
    • the number of targets you are creating


Why You Should Use the Build Utility

The Build utility provides numerous advantages over manually creating your own make or NMAKE files. The benefits of using the Build utility include:

  • The Build utility isolates all target-dependent information in a centralized location (including header and library include paths, compiler names and switches, and linker switches).
  • You can build products for multiple hardware platforms without specifying target-specific information.
  • The Build utility ensures a consistent build with unchanging characteristics. This is important when you have multiple files to build, when numerous .exe files will be generated, and when multiple developers work on a single project.


How to Get the Build Utility

The Build utility is included in the Windows DDK as a tool for writers of device drivers. The x86 version runs on Windows® 95/98/Me, as well as on all NT-based operating systems.

Note The use of Build utility macros for Windows 2000 and later operating systems varies from Windows NT® 4.0. For a list of valid environment variables and macros, see Build Utility Environment Variables and Build Utility Macros.


How to Use the Build Utility

This section describes how to use the Build utility. This information is provided in the following topics:

Setting Up the Build Environment

Running the Build Utility

Using Macros and Environment Variables

Specifying Libraries

Using Precompiled Headers

Specifying the Location of Created Files

Using Log Files

Note The term build product denotes one or more binary files created by the Build utility. In the Microsoft® Windows® DDK, the build product is typically a driver. However, the Build utility can be used to compile and build any kind of Windows binary. Indeed, Microsoft uses the Build utility to create the binary files for its NT-based operating systems.


Setting Up the Build Environment

Before you run the Build utility, you must prepare the build environment.

To prepare the build environment, install the following software in the order listed

  1. The latest service pack for Visual C++®
  2. The Windows DDK

When you install the DDK, it defines Start menu shortcuts for the free and checked build environments, for each target operating system for which you've installed DDK support. Before using the Build utility, you must select a build environment by choosing one of the environment shortcuts located in Start | Programs | Development Kits | Windows DDK version | Build Environments.

The following build environments are available:

  • Free Build Environment
  • Checked Build Environment
  • Free 64 Bit Build Environment
  • Checked 64 Bit Build Environment
  • Win 2K Free Build Environment
  • Win 2K Checked Build Environment
  • Win ME Free Build Environment
  • Win ME Checked Build Environment

Selecting a build environment causes a special MS-DOS® Command prompt window to appear. Each build environment uses a batch file named setenv.bat to determine the initial settings for numerous environment variables. For more information about environment variables, see Using Macros and Environment Variables.

The Build utility provides environments that allow you to create both free and checked products. In the free environment, the Build utility generates a build product that is optimized for release, similar to a retail build created with Microsoft Visual Studio®. In the checked environment, the Build utility does not optimize the code it creates; checked products typically have extra tests in the code to catch errors.

The DBG preprocessor symbol enables code to compiled into either a free or checked version. For more information, see Kernel-Mode Debugging Routines.

All drivers should first be compiled and tested in the checked environment. Builds can be recompiled and retested in the free environment after they are complete and have been demonstrated to work.

Note The free and checked build environments are not related to the free and checked builds of the Windows operating system. For information about the free and checked builds of the Windows operating system, see The Checked Build of Windows.


Running the Build Utility

When you open a build environment window, the directory in the window is set to the default directory for the Windows DDK. For more information about how to set up the build environment, see Setting Up the Build Environment.

Before running the Build utility, you must first create a number of data files. The Build utility requires the files that are described in the following table to build a driver.

File | Location
Source files | Typically reside in a subdirectory of the DDK install directory, but can be anywhere.
sources File | Required in each directory that contains source files. The sources file lists the source files to be compiled and linked, and specifies values for certain macros.
makefile File | Required in each directory that contains a sources file. The makefile file specifies dependency relationships, compiler and linker options, and various other build-related settings.
dirs File | Optional file used to compile source code in multiple subdirectories automatically. This contains macros called DIRS and OPTIONAL_DIRS that specify the directories to open recursively and the order in which they should be opened.

Build Utility Command-Line

The Build utility (build.exe) is invoked from the command line of your build environment window.

For a description of the command-line syntax, see Build Utility Command-Line Options. You can also use the command build -? to display the command-line syntax.

The Build Utility's Algorithm

The Build utility searches the dirs file for the macros DIRS and OPTIONAL_DIRS. It then recurses to each directory listed in the dirs file, searching for another dirs file or a sources file. Each additional dirs file indicates another directory to recurse into. Each sources file indicates a job to be built.

If sources files are found, the Build utility searches for the macros, SOURCES, INCLUDES, TARGETNAME, and TARGETPATH. The values assigned to these macros are parsed to determine the dependencies, the list of files to build, and the end result. Normally, this information is then stored by the Build utility in a file called build.dat for future reference.

Depending on the options you pass to it, the Build utility performs the appropriate actions and then calls a make program. This program will be NMAKE, unless a different make program has been specified in BUILD_MAKE_PROGRAM.

Warning Specifying any other make program besides NMAKE is not recommended.

NMAKE uses the makefile files to generate dependency and command lists. A standard makefile located in the source code directory of every sample driver directs NMAKE to the master macro definition file, makefile.def (which is included in the Windows DDK). The makefile you supply for your own source code should do the same.

After locating the relevant make files, the Build utility might search for other files (makefile0 and makefile.inc); this occurs only on a clean build, or if NTTARGETFILES is specified in the sources file.

After the NMAKE utility evaluates the macros in all the relevant make files, it spawns the C compiler (cl.exe) with the proper switches. Once compilation is complete, the Build utility again spawns NMAKE, this time to link the compiled object files.

When the entire directory tree is built, the Build utility halts.


Using Macros and Environment Variables

The Build utility uses numerous environment variables and macros:

  • Environment variables are set by the setenv.bat batch file when you open a DDK build environment window.
  • Macros are specified in the sources files. These files must exist in each source code subdirectory. Each sources file contains a series of macro definitions in the following format:
    MACRONAME=MacroValue

Here, MacroValue represents a text string that the Build utility uses to replace MACRONAME in its internal scripts. To specify a MacroValue string that is longer than one line, end each line except the last with a backslash (\) character.

The distinction between environment variables and macros is weak, because most environment variables can be referenced or changed within sources files, and many macros can be defined as environment variables in the build environment window. However, some environment variables are meant for internal use by the Build utility and cannot be used in sources files.

Controlling Environment Variables and Macros

To see the value of all Build utility environment variables, type set in a build environment command window. The set command can also be used to change a variable's value.

To reference an environment variable or macro in a sources file, use the following syntax:

$(VariableName)

where VariableName is the name of the environment variable or macro. An example is as follows:

TARGETLIBS=$(SDK_LIB_PATH)\kernel32.lib \
           $(SDK_LIB_PATH)\advapi32.lib \
           $(SDK_LIB_PATH)\user32.lib   \
           $(SDK_LIB_PATH)\spoolss.lib

For a complete list of the required and optional environment variables and macros, see Build Utility Environment Variables and Build Utility Macros.

Note Except for the DIRS and OPTIONAL_DIRS macros, which are used by the Build utility, these macros are all used by NMAKE. All that the Build utility does is open all the files, figure out the dependencies, and then call NMAKE. The other macros used in the build process are all used by NMAKE. For information on the DIRS and OPTIONAL_DIRS macros, see the dirs file.


Specifying Libraries

Unlike some other environments that use the LIB environment variable, the Build utility always requires the full path. The purpose of this is to eliminate any ambiguities in the build process.

For instance, some build processes rely on the linker to "figure out" the correct libraries by using paths stored in the LIB environment variable in combination with a list of default libraries stored in the objects. However, this approach has the inherent (and undesirable) side-effect of making it difficult to either know, or control, which libraries are used in your build process.

On the other hand, the Build utility requires that you specify the full path to each library you use. It will disable any default library lookup that the linker might attempt to use. Additionally, when specifying the libraries, you should try to abstract any absolute dependencies that might exist in the path. The build process provides an asterisk to take the place of the platform. You can use the BASEDIR macro to take the place of the root of the source tree. You can use DDK_LIB_PATH to refer to libraries that ship as part of the Windows DDK.

Additionally, you should use an asterisk to indicate the target platform in the path. For example, assume you are building a typical Win32® Windows .exe file. Normally, this would require you to link against kernel32.lib, user32.lib, gdi32.lib, and maybe your own component library, mylib.lib. Here's what the TARGETLIBS macro would look like:

TARGETLIBS = \
# Note: SDK_LIB_PATH already ends in "\*" so you should no include it when using
# the macro.
$(SDK_LIB_PATH)\kernel32.lib \
$(SDK_LIB_PATH)\user32.lib \
$(SDK_LIB_PATH)\gdi32.lib \
..\mylib\obj\*\mylib.lib

When building on x86, this would mean the same as:

TARGETLIBS = \
$(BASEDIR)\lib\i386\kernel32.lib \
$(BASEDIR)\lib\i386\user32.lib \
$(BASEDIR)\lib\i386\gdi32.lib \
..\mylib\obj\i386\mylib.lib

To build a particular set of build products, change to a directory that contains either a dirs file or a sources file. Run the Build utility. The utility will automatically build the products specified in the sources file of each subdirectory.

For example, if a sources file describes a library called "mylib", using the following command line will build the library:

build -386

If the sources file contains a UMAPPL macro that identifies an executable named "myexe", this command line will also build "myexe". On the other hand, if "myexe" is identified using a UMTEST macro instead of a UMAPPL macro, the following command line must be used to include "myexe" in the build operation:

build -386 myexe

Library creation is not required for programs that consist of a single source file. In such a situation, define the sources file as follows:

  1. Set TARGETNAME and TARGETPATH as if you were going to generate a library.
  2. Set TARGETTYPE to be UMAPPL_NOLIB.
  3. Set SOURCES to nothing.
  4. Do not include the TARGETNAME library in UMLIBS.
  5. Specify the source file name using UMAPPL or UMTEST.
  6. Invoke the Build utility (specifying the file name, if listed using UMTEST).

The Build utility will generate the executable file.


Using Precompiled Headers

The easiest way to use precompiled headers is to include the following statement in your sources file:

PRECOMPILED_INCLUDE=some_header_file_that_every_source_file_includes

If you are building C++ code, include the statement:

PRECOMPILED_CXX=1

Nothing else is required.

Precompiled headers are put into the directory specified by the O macro. Their default location will be the obj\platform subdirectory. Therefore, they should not collide during simultaneous compilations.

See Also

PRECOMPILED_CXX, PRECOMPILED_INCLUDE, PRECOMPILED_OBJ, PRECOMPILED_TARGET


Specifying the Location of Created Files

When the Build utility creates output files, it generates a directory name by taking the value of the TARGETPATH macro and appending the value of the BUILD_ALT_DIR environment variable. Under this directory, the utility creates a subdirectory with a name based on the target machine architecture.

By default, BUILD_ALT_DIR is either "fre" (in the free build environment) or "chk" (in the checked build environment). The processor architecture string is either "i386" for x86 systems, or "ia64" for Itanium systems.

The Build utility combines these values as follows to create output directory names:

\$(TARGETPATH)$(BUILD_ALT_DIR)\platform

Consequently, the Build utility by default puts output files in the following locations:

 | Free Build | Checked Build
Object Modules | objfre\i386 objfre\ia64 | objchk\i386 objchk\ia64
Libraries | libfre\i386 libfre\ia64 | libchk\i386 libchk\ia64
Log Files | buildfre.log buildfre.err buildfre.wrn | buildchk.log buildchk.err buildchk.wrn

Because output files are placed in subdirectories that are specific to the build environment, you can keep your source files in a single directory tree and maintain both free and checked build products under this tree.

You can change the defaults by resetting the environment variables in a sources file. If you set TARGETPATH to point to a particular directory, the created objects will be placed in that directory, and neither BUILD_ALT_DIR nor the hardware platform will be added to the directory name.

When building a DLL, you create not only the DLL itself, but also an import library that other images can use to reference functions that the DLL exports. In this situation, you might want to place the .obj files created for the DLL into a different directory from the .lib and .exp files. The macro TARGETPATHLIB specifies a location for .lib and .exp files created for DLLs. If you set TARGETPATHLIB to a different directory than TARGETPATH, you can put the DLL binary in one directory, and place the .lib and .exp files in a different directory, where they will be available to other components. TARGETPATHLIB has no effect on binaries that are not DLLs.


Using Log Files

The Build utility generates files that provide useful information about build product status. These files include the following:

Consequently, the Build utility by default puts output files in the following locations:

File name in the free build environment | File name in the checked build environment | Contents
buildfre.log | buildchk.log | A log of the commands invoked by NMAKE.
buildfre.wrn | buildchk.wrn | A list of warnings generated during the build.
buildfre.err | buildchk.err | A list of errors generated during the build.

Normally, BUILD_ALT_DIR is equal to "fre" in the free build environment, and equal to "chk" in the checked build environment. If this has been changed, the corresponding part of these filenames will be changed.

Log file writing can be controlled by using the -e, -E, or -j command-line options.

Note The Build utility filters some compiler and linker warnings. Filtered warnings do not appear in the statistics that the Build utility reports; however, they do appear in the build*.log and build*.wrn files.


Build Utility Techniques

This section describes how to complete some common tasks using the Build utility. These tasks are described in the following topics:

Building Multiple Targets from One Subdirectory

Building on a Multiprocessor Computer

Utilizing a sources File Template

Building a Sample Driver

Building a New Driver


Building Multiple Targets from One Subdirectory

If your driver must run on more than one Microsoft® Windows® operating system, or support more than one hardware architecture, you can organize your builds in any of the following ways:

  • Use a single set of source files and create a single binary.
  • Use a single set of source files and create more than one binary.
  • Use more than one set of source files and create more than one binary.

In the simplest scenario, you can use a single source directory with a single makefile to build a single executable or driver.

However, the Build utility allows you to have a single subdirectory where you can build multiple executable output files.

It is easiest to use a single set of source files, regardless of the number of binaries to be created. If at all possible, avoid using more than one set of sources. Instead, use preprocessor symbols to isolate system-specific and architecture-specific code, and conditionally compile. Maintenance and debugging are vastly simplified when you use a single set of sources.

Building Multiple Drivers from a Single Set of Source Files

To develop a driver that will run on multiple Windows operating systems, use a single set of source files and create a single binary. However, sometimes it is not possible to generate a single binary that supports all target operating systems. Nevertheless, in such a case you should use the same source code and build the drivers as follows:

  1. Surround any system-dependent features with conditional compilation directives.
  2. Put all source files in one directory; for example, mydriver.
  3. Create a subdirectory for each target operating system. For example:

    mydriver\Windows2000
    mydriver\WindowsMe
    mydriver\XP

  4. In each system-specific subdirectory, put the makefile, makefile.inc, and other system-dependent build files:

    mydriver\Windows2000\makefile
    mydriver\Windows2000\makefile.inc

    mydriver\WindowsMe\makefile
    mydriver\WindowsMe\makefile.inc

    mydriver\XP\makefile
    mydriver\XP\makefile.inc

  5. In each system-specific subdirectory, create a sources file that refers to the source files in the parent directory, as in the following example:
    TARGETNAME=MYDRIVER
TARGETTYPE=DRIVER
DRIVERTYPE=WDM

C_DEFINES=-DDRIVER

INCLUDES=..\..\inc;

SOURCES= \
        ..\main.c \
        ..\vars.c \

    This sources file creates a WDM driver named MYDRIVER, using source files from the parent directory and header files from an inc directory at the same level as the parent directory. The build output files will be placed in the objfre\<platform> or objchk\<platform> subdirectory of the system-specific directory. The log files will be placed in the system-specific subdirectories.

Note To do this in Visual Studio®, you must create a project file (.dsp) for each target operating system. Each project file should specify the preprocessor options that are required to build the driver on the target operating system. In addition, create a subdirectory for each target operating system. Direct the output object (.obj) and dynamic-link library (.dll) files for each target system to the corresponding subdirectory.

Building Libraries

The Build utility supports a library-linked-to-main model. This model enables you to have one subdirectory build multiple targets that are very similar. This eliminates the need to move recursively through 10 different subdirectories to build 10 different .exe files whose sources are identical except for a single file.

In a single subdirectory you can have a number of files that share some common subset of code. Each of them will have a single source file that will have the unique code for that product. If your build product consists of several source files, you can specify all but the main source file as components of a library. The Build utility links this library with the file containing main.

This model is especially useful if you are building a set of tools that will have some common interfaces. For example, you might build some Unix-emulating tools that share file I/O code, memory code, and registry code. Each tool will have a small "wrapper" around this basic code that implements a specific action. The Build utility enables you to set up a target type of library in that subdirectory and to use the remote applications macro (UMAPPL) to specify the target names.

Consider, for example, the simple UNIX commands tar, cat and grep. These can be built by using the UMAPPL macro:

UMAPPL=tar*cat*grep

All the common source files would be listed in the SOURCES macro. The Build utility will compile all of those into a library, then compile each one of the individual source files for tar.c, cat.c, and grep.c, and finally link each of those against the common library that you built to produce tar.exe, cat.exe, and grep.exe.


Building on a Multiprocessor Computer

When the Build utility is run on a multiprocessor computer, different Build utility threads may be running on different processors. Therefore, you should be careful that your products are built in the correct order.

The following macros can be used in your sources files to control the order of the build:

  • SYNCHRONIZE_BLOCK instructs the Build utility to build a certain subdirectory first. When the Build utility finds this macro in a sources file, will stop building all other directories until this directory is built.
  • SYNCHRONIZE_DRAIN instructs the Build utility to build a certain subdirectory last. A directory whose sources file contains this macro will not be built until all other subdirectories have been built.

Use SYNCHRONIZE_BLOCK when you have a subdirectory that other subdirectories require the results from in order to build (for example, a global precompiled header). List the precompiled directory first in the dirs file, and add SYNCHRONIZE_BLOCK=1 to the sources file. This assures that the subsequent directories that use the precompiled header will not be built until the header is created.

Use SYNCHRONIZE_DRAIN when you have a subdirectory that needs the results from a prior subdirectory on the same pass. For example, when building a DLL, you may have several subdirectories with TARGETTYPE=LIBRARY, where each builds some component. You may have another subdirectory with TARGETTYPE=DYNLINK, where the Build utility will build a DLL that exports functions from the component libraries. In such a case, you should set LINKLIBS to the component libraries, make sure the DLL subdirectory is the last in the parent dirs file, and add SYNCHRONIZE_DRAIN=1 to the sources file for the DLL.

Misuse of These Macros

You should use these directives very sparingly, because they completely stall a multiprocessor build when they are encountered. In most cases, the problem is not with the multiprocessor nature of the build, but rather the macros used in the sources file.

A common mistake is using LINKLIBS to specify import libraries when building a DLL. You almost never want to do this. LINKLIBS must exist during pass 1 because the libraries it specifies are used to build the import library for the DLL. However, TARGETLIBS does not need to exist until pass 2, because the libraries it specifies are only used to link the image.

Therefore you should use LINKLIBS for component libraries only, and use TARGETLIBS for import libraries.


Utilizing a sources File Template

This topic contains an actual sources file template. This template specifies the target component to be built and the list of sources files needed to build it. It also specifies optional compiler switches and libraries that are unique for the component being built. Follow the instructions in this topic to copy and edit this template so you can use it to run the Build utility.

Using this sources template

  1. Copy the contents of this topic to the Clipboard.
  2. Paste this topic into a file using a text editor.
  3. Replace the xxxxx in the TARGETNAME macro with your target name, for example:
    TARGETNAME=myprogram
  4. Edit the TARGETPATH and TARGETTYPE macros to specify the location and type of the target.
  5. Edit the INCLUDES macro if you have a private include directory to search.
  6. Carefully edit the SOURCES macro so that it defines all the source files for the component that you are building.
  7. Remove these instructions and all comments.
  8. Save this file under the name "sources" (not "source.txt"), and quit the text editor.
  9. Run the Build utility from the command line by typing "build" and pressing Enter.
  10. After you have completed these steps, you can run either the Build utility or NMAKE to build the component.
#
# The developer defines the TARGETNAME variable. It is the name of
# the target (component) that is being built by this makefile.
# It should not include any path or filename extension.
#
TARGETNAME=xxxxx
#
# The developer defines the TARGETPATH and TARGETTYPE variables.
# The first variable specifies where the target will be built. The second specifies
# the type of target (either PROGRAM, DYNLINK, LIBRARY, UMAPPL_NOLIB or
# BOOTPGM). Use UMAPPL_NOLIB when you are only building user-mode
# programs and do not need to build a library.
#
TARGETPATH=obj
# Select one of the following, and delete the others:
TARGETTYPE=PROGRAM
TARGETTYPE=DYNLINK
TARGETTYPE=LIBRARY
TARGETTYPE=UMAPPL_NOLIB
TARGETTYPE=BOOTPGM
TARGETTYPE=DRIVER
TARGETTYPE=DRIVER_LIBRARY
TARGETTYPE=EXPORT_DRIVER
TARGETTYPE=GDI_DRIVER
TARGETTYPE=MINIPORT
TARGETTYPE=NOTARGET
TARGETTYPE=PROGLIB#
# If your TARGETTYPE is DRIVER, you can optionally specify DRIVERTYPE.
# If you are building a WDM Driver, use DRIVERTYPE=WDM, if you are building
# a VxD use DRIVERTYPE=VXD. Otherwise, delete the following two lines.
#
DRIVERTYPE=WDM
DRIVERTYPE=VXD
#
# The TARGETLIBS macro specifies additional libraries to link against your target
# image. Each library path specification should contain an asterisk (*)
# where the machine-specific subdirectory name should go.
#
TARGETLIBS=
#
# The INCLUDES variable specifies any include paths that are specific to
# this source directory. Separate multiple paths with single
# semicolons. Relative path specifications are okay.
#
INCLUDES=..\inc
#
# The developer defines the SOURCES macro. It contains a list of all the
# source files for this component. Specify each source file on a separate
# line using the line-continuation character. This minimizes merge
# conflicts if two developers are adding source files to the same component.
#
SOURCES=source1.c \
source2.c \
source3.c \
source4.c
i386_SOURCES=i386\source1.asm
IA64_SOURCES=ia64\source1.s
#
# Next, specify options for the compiler using C_DEFINES.
# All parameters specified here will be passed to both the C
# compiler and the resource compiler.
C_DEFINES=
#
# Next, specify one or more user-mode test programs and their type.
# Use UMTEST for optional test programs. Use UMAPPL for
# programs that are always built when the directory is built. See also
# UMTYPE, UMBASE, and UMLIBS. If you are building a driver, the next
# 5 lines should be deleted.
#
UMTYPE=nt
UMTEST=bunny*baz
UMAPPL=bunny*baz
UMBASE=0x1000000
UMLIBS=obj\*\bunny.lib
#
# Defining either (or both) the variables NTTARGETFILE0 and/or NTTARGETFILES
# causes makefile.def to include .\makefile.inc immediately after it
# specifies the top level targets (all, clean and loc) and their dependencies.
# The makefile.def file expands NTTARGETFILE0 as the first dependent for the
# "all" target and NTTARGETFILES as the last dependent for the "all" target.
# This is useful for specifying additional targets and dependencies that do not fit the
# general case covered by makefile.def.
#
# NTTARGETFILE0=
# NTTARGETFILES=

The following environment variables and macros enable you to specify alternate object directories: BINPLACE_PLACEFILE, COFFBASE_TXT_FILE, COMPILER_WARNINGS, MASTER_VERSION_FILE, DDK_INC_PATH, DDK_LIB_PATH, WDM_INC_PATH, SDK_INC_PATH, SDK_LIB_PATH, CRT_INC_PATH, CRT_LIB_PATH, OAK_INC_PATH.


Building a Sample Driver

Each sample driver supplied with the Windows DDK has its own source directory and sources files.

To build all samples at once

  1. Set your directory to the src subdirectory of the DDK installation directory.
  2. Invoke the Build utility with the -cZ options, as in the following example:
    E:\NTDDK>cd src
E:\NTDDK\src>build -cZ

This command creates a "clean build" of the samples (by deleting all pre-existing .obj files). It also inhibits the dependency checking of source and header files.


Building a New Driver

To build a driver, open a build environment, then use the cd command to set your default directory to one containing a sources file or a dirs file.

After setting the directory, invoke the Build utility with the -cZ option as in the following example:

E:\NTDDK>cd mydriver\src
E:\NTDDK\mydriver\src>build -cZ

Running build -cZ compiles and links your driver. It creates a "clean build" (by deleting all pre-existing .obj files) and inhibits dependency checking of source and header files.

Output files are placed in a subdirectory named either \objfre or \objchk, depending on whether you are using the free or checked build environment.

For more information, see How to Use the Build Utility.

Building a WDM Driver

To build a WDM driver, use the DRIVERTYPE macro in your sources file:

DRIVERTYPE=WDM

When this macro is set, the Build utility sets the path for include files equal to the value of WDM_INC_PATH instead of DDK_INC_PATH. This means that the WDM-only header files will be used in your driver.

For information about creating drivers that will run on multiple versions of WDM, see Determining the WDM Version and Differences in WDM Versions.


Debugging Build Utility Products

In the build environment for the Microsoft® Windows® DDK, you can always debug what you build. No matter how you build using the Build utility, symbol files that are used for debugging will be created.

You can control the type and amount of symbolic information with the NTDEBUG environment variable, and the NTDEBUGTYPE and MSC_OPTIMIZATION macros.

For example, the following settings will allow you to perform source debugging or assembly debugging on your code:

NTDEBUG=ntsd
NTDEBUGTYPE=both
MSC_OPTIMIZATION=/Odi

If you are building a driver for Windows 98/Me, you should also use the USE_MAPSYM macro.

For more information, see Debugging a Driver.

Note Most other build programs do not automatically generate symbol files. In the Visual Studio® build environment, you can choose between a "debug" build and a "retail" build; only the debug build includes symbol files.


Build Utility Limitations and Rules

There are a number of limitations and rules associated with the Build utility.

  • Only one DLL or library may be built in a given source directory. The equivalent of an import library is generated automatically when you build a DLL. The equivalent import library and export file are also generated.
  • Any number of .exe files can be generated, as long as each one consists of a single source file (containing main) that will be linked to the library or DLL being generated.
  • When you build a DLL, the LIBRARY statement in your .def file must be identical to the TARGETNAME statement in the sources file. The comparison is case sensitive.
  • If your DLL must link with other libraries, these libraries must be specified in your sources file with a TARGETLIBS statement. (For a description of the proper "*" notation, see the TARGETLIBS page.)
  • The Build utility does not process NMAKE macros or conditional syntax. Consequently, the value of a Build utility macro in a sources file must be textual; it cannot contain references to NMAKE macros.
  • Only files in the current directory, its parent directory, and the platform subdirectory can be listed in the SOURCES macro.
  • No blank spaces can appear between a Build utility macro and the equal sign. For example, the following line is valid:
    SOURCES= file.c

    while the following line is invalid:

    SOURCES = file.c


Build Utility Reference

This section provides reference material associated with the Build utility. This material includes information about the command-line options, files, environment variables, and macros that the Build utility uses. This information is described in the following topics:

Build Utility Command-Line Options

Build Utility Files

Build Utility Environment Variables

Build Utility Macros


Build Utility Command-Line Options

The following is a complete list of command-line options for the Build utility. These switches should all be preceded with a hyphen (-):

Option | Effect
-# | Forces _objects.mac to be regenerated.
-0 | Pass-zero generation only; do not compile or link.
-2 | Same as old -Z (only do a two-pass build — no pass zero).
-3 | Same as -Z.
-a | Allows synchronized blocks and drains during link pass.
-b | Displays full error message text without truncating anything.
-c | Deletes all object files.
-C | Deletes all .lib files only.
-clean | Equivalent to "-nmake clean".
-D | Check dependencies before building.
-e | Generates the log, error, and warning files. (For more information, see Using Log Files.)
-E | Always keep the log files.
-f | Forces rescan of all source and include files.
-F | When displaying errors/warnings to stdout, print the full path.
-G | Enables target-specific dirs files if and only if there is just one target.
-i | Ignores extraneous compiler warning messages.
-I | Do not display thread index if multiprocessor build.
-j filename | Use filename as the name for log files. The j switch changes the first field, so it produces filename.log, filename.wrn, and filename.err. This can be used to set up a single machine with a shared source drive, which is connected with an x86 machine and with an Itanium machine. On each of these machines, you can set the j switch so you can build all those machines at the same time across the net and produce the log, warning and error files for each platform's build.
-jpath pathname | Use pathname as the path for log files instead of ".".
-k | Keep out-of-date targets (do not delete them).
-l | Link only, no compiles.
-L | Compile only, no link phase.
-M [N] | Multiprocessor build.
-m | Background mode; run the Build utility in the idle priority class.
-nmake arg | Argument to pass to NMAKE.
-o | Display out-of-date files.
-O | Generate obj\_objects.mac file for current directory.
-p | Pause before compile and link phases.
-P | Print elapsed time after every directory.
-q | Query only; do not run NMAKE.
-r dirpath | Restarts clean build at specified path.
-s | Display status line at top of display.
-S | Display status line with include file line counts.
-t | Display the first level of the dependency tree.
-T | Display the complete dependency tree.
-u | Display unused BUILD_OPTIONS.
-$ | Display the complete dependency tree hierarchically.
-v | Enable include file version checking.
-w | Show warnings on screen.
-why | List reasons for building targets.
-x filename | Exclude include file from dependency checks.
-y | Show files scanned.
-z | No dependency checking or scanning of source files; one pass compile and link.
-Z | No dependency checking or scanning of source files; three passes.
-386 | Build targets for i386.
-x86 | Same as -386.
-ia64 | Build targets for Itanium.
-? | Display help text with these command-line options.

Parameters not preceded with a hyphen will be understood as additional source directories to be built. Parameters preceded with a tilde (~) specify directories that are not to be built. These directories must be listed in the dirs file.

An asterisk (*) as a parameter means that the Build utility should build all optional source directories.


Build Utility Files

This section describes the files that the Build utility uses. These files are described in the following topics:

_objects.mac File

dirs File

makefile File

makefile.def File

makefile.plt File

makefile.tpl File

makefile.inc File

makefile0 File

(platform)mk.inc File

sources File

verrc.tpl File


_objects.mac File

The Build utility puts a file in the obj subdirectory called _objects.mac which contains the object dependencies for each platform.

A typical _objects.mac file looks like this:

386_OBJECTS= \
    $(_OBJ_DIR)\i386\x.obj \
    $(_OBJ_DIR)\i386\y.obj

PASS0_386_OBJECTS=

IA64_OBJECTS= \
    $(_OBJ_DIR)\ia64\x.obj \
    $(_OBJ_DIR)\ia64\y.obj

PASS0_IA64_OBJECTS=

This file is created by the Build utility. You do not need to edit it.. Every time the sources file gets updated, this file is regenerated.


dirs File

You can instruct the Build utility to recursively build an entire source tree by using the dirs file.

The dirs file resides in a directory that contains subdirectories (that is, at the root of a source code tree or subtree). Each subdirectory can be a source directory or another source tree. A dirs file should exist at the root of each source code subtree, and a sources file should exist in each "leaf" directory (that is, the directories that contain actual source code).

You should define the following macros in your dirs file:

DIRS | This macro contains a list of subdirectories that the Build utility will build every time it runs.
OPTIONAL_DIRS | This macro contains a list of subdirectories that the Build utility will build only if specified on the build.exe command line.

Entries in these lists must be separated by spaces or tabs. Each subdirectory name is relative to the directory containing the dirs file.

When you build a product, all subdirectories listed as DIRS arguments are scanned. Subdirectories listed as OPTIONAL_DIRS arguments are scanned only if they are specifically listed as Build utility command arguments, or if they are assigned to the BUILD_OPTIONS environment variable.

If you follow a distinct pattern in naming your directories, it is trivial to use dirs files to build multiple versions of a product. List the current version in the DIRS macro, and the new or previous versions in the OPTIONAL_DIRS macro. Once you set this up, your build machine will be able to build whichever version you request..

Example

DIRS=dir1 dir2 dir3
OPTIONAL_DIRS=dir4 dir5

The <currentdir>\dir1, <currentdir>\dir2, and <currentdir>\dir3 directories will be built in this order every time. The <currentdir>\dir4 and <currentdir>\dir5 directories will only be built if you so specify on the Build utility command line or by using the BUILD_OPTIONS environment variable.

The Build utility supports a 'not' switch (~) that removes a directory from the default build. Using the above example,

build -cZ ~dir1 ~dir3 dir4

would build only dir2 and dir4.

An asterisk (*) as a parameter means that the Build utility should build all optional source directories.

DDK Installation and dirs Files

Each time you reinstall or partially uninstall the DDK, new dirs files are created dynamically and existing dirs files are deleted. If you need to create dirs files for additional subdirectories, run the Makedirs utility (included with the DDK), specifying the drive and starting path. For example:

makedirs d:\winddk\mydriver

The example creates dirs files in mydriver and any other parent directories subordinate to it.


makefile File

NMAKE uses makefile files to generate dependency and command lists. A standard makefile file in every sample driver's source code directory directs NMAKE to the master macro definition file, makefile.def. The makefile you supply for your own source code should do the same. The makefile.def file is included with the DDK.


makefile.def File

The Build utility makes use of a generic make file called makefile.def, which contains the macro definitions that the sources file uses.

Makefile.def specifies the flags that are passed to the compiler and linker. These settings are tailored to the DDK build environment, and you should therefore use makefile.def to build your drivers. Using this file simplifies the creation of platform-independent driver projects. The file is similar to the ntwin32.mak file, which is supplied with the Platform SDK and is used to build Win32® applications.

Using the Build utility in combination with the makefile.def file removes the guesswork about which compiler switches are required, which arguments the linker requires, and so on. By adding appropriate macro definitions to the sources file, you can control build options in a platform-independent fashion.

The Build utility will look at the makefile file; this file should always redirect it to makefile.def. This file, in turn, sets the appropriate header and library include paths, compiler names and switches, and linker switches that are defined in makefile.def, and invokes NMAKE (nmake.exe).

The current version of makefile.def resides on %ddkroot%\bin.

Warning Do not change makefile.def or any of the other files in the DDK's \bin directory. If you have driver-specific make file requirements, put them in makefile.inc instead.


makefile.plt File

The platform-specific information for the make files is contained in makefile.plt. You can include makefile.plt in your own make files to select the build target and set platform-specific variables. For an example of this, see makefile.def.

The latest version of makefile.plt is stored on %ddkroot%\bin.

This file contains three macros that are very useful: TARGET_DIRECTORY, FREEBUILD, and TARGET_CPP.


makefile.tpl File

This is the template make file. Nothing has to be in makefile.tpl except:

!include $(NTMAKEENV)\makefile.def

The complete text of makefile.tpl is as follows:

#
# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
# file to this component. This file merely indirects to the real makefile
# that is shared by all the components of the DDK.
#
!INCLUDE $(NTMAKEENV)\makefile.def


makefile.inc File

This is a make file that you can create. It should exist in the same subdirectory as a dirs file. It is typically used to build header files that are required in the subdirectories.

It can be used to generate any custom targets that are required by a module.

The Build utility will spawn NMAKE to execute this file before traversing the directory list in the dirs file.


makefile0 File

This is a make file that you can create. It should exist in the same subdirectory as a dirs file. It is typically used to build header files that are required in the subdirectories.

The Build utility will spawn NMAKE to execute this file before traversing the directory list in the dirs file.


(platform)mk.inc File

For each platform, there is a special make file:

  • i386mk.inc
  • ia64mk.inc

The current versions of these files reside on %ddkroot%\bin. In these files, there are optimization rules or assembler instructions that are specific for that target. There may also be extra link flags, resource compiler flags, or C preprocessor rules that are required. The makefile.inc files are not something you would usually edit because there are macros to override all the settings in makefile.inc in your sources file. If you want to change the optimization, use MSC_OPTIMIZATION. If you want to change linker flags, use LINKER_FLAGS.


sources File

You describe Build utility products in a file named "sources" that resides in each source code subdirectory.

The sources file contains a series of macro definitions that are recognized by the Build utility. For more information, see Using Macros and Environment Variables.


verrc.tpl File

Use this template file to add a version resource to an image. The final name would be something like "myimage.rc".

The following is the complete text of verrc.tpl:

/*
** Template for version resources. Place this in your .rc file,
** editing the values for VER_FILETYPE, VER_FILESUBTYPE,
** VER_FILEDESCRIPTION_STR and VER_INTERNALNAME_STR as needed.
** See winver.h for possible values.
**
** Ntverp.h defines several global values that do not need to be
** changed except for official releases such as betas, SDK updates, etc.
**
** Common.ver has the actual version resource structure that all these
** #defines eventually initialize.
*/
/* #include <windows.h> needed if this will be the .rc file */
#include <ntverp.h>
/*-----------------------------------------------*/
/* the following lines are specific to this file */
/*-----------------------------------------------*/
/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
* and VER_INTERNALNAME_STR must be defined before including COMMON.VER
* The strings do not need a '\0', because common.ver has them.
*/
#defineVER_FILETYPEVFT_DLL
/* possible values:VFT_UNKNOWN
VFT_APP
VFT_DLL
VFT_DRV
VFT_FONT
VFT_VXD
VFT_STATIC_LIB
*/
#defineVER_FILESUBTYPEVFT2_UNKNOWN
/* possible valuesVFT2_UNKNOWN
VFT2_DRV_PRINTER
VFT2_DRV_KEYBOARD
VFT2_DRV_LANGUAGE
VFT2_DRV_DISPLAY
VFT2_DRV_MOUSE
VFT2_DRV_NETWORK
VFT2_DRV_SYSTEM
VFT2_DRV_INSTALLABLE
VFT2_DRV_SOUND
VFT2_DRV_COMM
*/
#define VER_FILEDESCRIPTION_STR "Version Checking and File Installation Libraries"
#define VER_INTERNALNAME_STR "VERSION.DLL"
#define VER_ORIGINALFILENAME_STR "VERSION.DLL"
#include "common.ver"


Build Utility Environment Variables

The values of the following environment variables are set in the build environment window. Some of these enviroment variables can also be set in the sources files. For an overview of how these macros are used, see Using Macros and Environment Variables.

The environment variables initialized when the build environment is created are described in the following topics:

BASEDIR

BUILD_ALT_DIR

BUILD_DEFAULT

BUILD_DEFAULT_TARGETS

BUILD_MAKE_PROGRAM

C_DEFINES

CRT_INC_PATH

CRT_LIB_PATH

DDK_INC_PATH

DDK_LIB_DEST

DDK_LIB_PATH

NTDEBUG

O

OAK_INC_PATH

SDK_INC_PATH

SDK_LIB_DEST

SDK_LIB_PATH

WDM_INC_PATH

The environment variable described in the following topic is not automatically created, but can be created by using the set command:

BUILD_OPTIONS


BASEDIR

The BASEDIR environment variable specifies the base of the build product's source tree. By default, this is set to the root directory where the DDK is installed.


BUILD_ALT_DIR

Use the BUILD_ALT_DIR environment variable to specify an alternate object directory name. It must be ten characters or less and contain no spaces. The value is added to the end of the .obj name and (if no -j switch is used for build.exe) the logfile name, for example:

c:\> set BUILD_ALT_DIR=Debug
c:\> build -386 -e

Would generate objects in the objDebug\i386 subdirectory and logfiles named buildDebug.log, buildDebug.wrn, and buildDebug.err.

Use this environment variable when you want to build the same source in different windows using different language, optimizations, or debugging information. By default, the Microsoft® Windows® DDK sets BUILD_ALT_DIR to "fre" or "chk" depending on whether you open a Free or Checked Build Environment window, respectively.

The value of BUILD_ALT_DIR will be appended to TARGETPATH to generate the directory names for the location of output files.

The only limitations on the BUILD_ALT_DIR environment variable are that its value be less than 10 characters and not contain embedded spaces or dots.


BUILD_DEFAULT

The BUILD_DEFAULT environment variable lists default parameters to pass to the Build utility command line.

For example, this:

c:\> build -eswM -nmake -i

means the same as:

c:\> set BUILD_DEFAULT=-eswM -nmake -i
c:\> build


BUILD_DEFAULT_TARGETS

Use the BUILD_DEFAULT_TARGETS environment variable to specify the default target platform for which you are building. Assuming that cross compilers existed, you could set it to -386 on an Itanium and build x86 binaries.

Usually, you can just set it to the platform on which you are hosted. For example:

c:\> build -386

means the same as:

c:\> set BUILD_DEFAULT_TARGETS=-386
c:\> build


BUILD_MAKE_PROGRAM

Use the BUILD_MAKE_PROGRAM environment variable to specify the make program to execute.

The default is NMAKE. However, you can set this value to any make program you wish (set it equal to the full path and file name).

Warning Microsoft does not support the use of an alternate make program. It is highly recommended that you not change the value of this variable.


BUILD_OPTIONS

Use the BUILD_OPTIONS environment value to specify optional subdirectories (identified by OPTIONAL_DIRS in a dirs file) that should be scanned during a build operation.

For example:

// DIRS file:
DIRS=dir1 dir2 dir3
OPTIONAL_DIRS=OptDir1 OptDir2 OptDir3
c:\> build OptDir1 OptDir2 OptDir3

means the same as:

c:\> set BUILD_OPTIONS=OptDir1 OptDir2 OptDir3
c:\> build


C_DEFINES

Use the C_DEFINES environment variable to specify the switches you want passed to the C compiler and to the Microsoft interface description language compiler (MIDL).

Typically, these switches are compiler #define directives.

For example, to define DEBUG_BUILD to the compiler, you would specify:

C_DEFINES = /DDEBUG_BUILD

Within a sources file, you can add text to the C_DEFINES variable without losing its original content. For example, to define UNICODE to the compiler in addition to any existing C_DEFINES switches, you could specify:

C_DEFINES = $(C_DEFINES) /DUNICODE

There's no limit to what this #define can be, except that C_DEFINES gets passed to the compiler and it also gets passed to the resource compiler. Therefore, you cannot put compiler optimization or other machine-specific or tool-specific switches in the C_DEFINES environment variable. Instead, use one of the following macros for this:

  • MSC_OPTIMIZATION
  • MSC_WARNING_LEVEL
  • USER_C_FLAGS.


CRT_INC_PATH

Use the CRT_INC_PATH environment variable to specify the path to the C run-time headers. The default is:

%ddkroot%\inc\crt


CRT_LIB_PATH

Use the CRT_LIB_PATH environment variable to specify the path to the C run-time import libraries. The default is:

%ddkroot%\lib\*


DDK_INC_PATH

Use the DDK_INC_PATH environment variable to specify the path to the Windows DDK headers. The default is:

%ddkroot%\inc\ddk\wxp


DDK_LIB_DEST

Use the DDK_LIB_DEST environment variable to specify the directory where import libraries created by the Build utility will be placed. The default is:

%ddkroot%\lib


DDK_LIB_PATH

Use the DDK_LIB_PATH environment variable to specify the path to the Windows DDK libraries. The default is:

%ddkroot%\lib\*


NTDEBUG

Use the NTDEBUG environment variable to specify what type of symbolic information you want the Build utility to place in the symbol files it creates.

This environment variable is rarely used in the sources file. Instead, it is set in the environment by the Windows DDK.

To indicate a checked (or debug) build, specify:

NTDEBUG=ntsd

To indicate a free (or retail) build, specify:

NTDEBUG= ntsdnodbg

The only difference between the two of them is that specifying "ntsd" causes the Build utility to define DBG=1, while specifying "ntsdnodbg" causes it to define DBG=0.

The DBG variable is tested by a number of debugging-related driver routines; for more information, see Kernel-Mode Debugging Routines. You can also use #if DBG statements in your source code to conditionally-compile free and checked versions of your driver.


O

Use the O environment variable to specify the subdirectory into which final objects will be placed. Define this environment variable in your sources file or in your makefile.inc file to be certain something goes into the object subdirectory.

The benefit of using $(O) is that any files that you have built and placed in the objects subdirectory will be deleted on the next clean build. This guarantees that no collisions will occur between two builds running on the same machine at the same time. They will never override each other's files if you follow the convention that everything you build goes in $(O).


OAK_INC_PATH

Use the OAK_INC_PATH environment variable to specify the path to the OEM Adapter Kit headers. The default is:

%ddkroot%\inc\wxp


SDK_INC_PATH

Use the SDK_INC_PATH environment variable to specify the path to the Platform SDK headers. The default is:

%ddkroot%\inc\wxp


SDK_LIB_DEST

Use the SDK_LIB_DEST environment variable to specify the directory where import libraries created by the Build utility will be placed. The default is:

%ddkroot%\lib


SDK_LIB_PATH

Use the SDK_LIB_PATH environment variable to specify the path to the Platform SDK libraries. The default is:

%ddkroot%\lib\*


WDM_INC_PATH

Use the WDM_INC_PATH environment variable to specify the path to the WDM headers. The default is:

%ddkroot%\inc\ddk\wdm\wxp

If the DRIVERTYPE macro in your sources file has been set to "WDM", the Build utility will use WDM_INC_PATH instead of DDK_INC_PATH.


Build Utility Macros

You set the values of all Build utility macros in the sources files. Some of these macros can also be set in a build environment window. For an overview of how these macros are used, see Using Macros and Environment Variables.

The macros that are required in each sources file are described in the following topics:

SOURCES

TARGETLIBS

TARGETNAME

TARGETPATH

TARGETTYPE

The optional macros that you might want to define in your sources file are described in the following topics:

_OBJ_ROOT

386_OPTIMIZATION

386_WARNING_LEVEL

BINPLACE_FLAGS

BINPLACE_PLACEFILE

COFFBASE

COFFBASE_TXT_FILE

COMPILER_WARNINGS

DEBUG_CRTS

DLLBASE

DLLDEF

DLLENTRY

DLLLIBOBJECTS

DLLORDER

DRIVERBASE

DRIVERTYPE

EXEPROFILEINPUT

FREEBUILD

GPSIZE

HALBASE

IA64_OPTIMIZATION

IA64_WARNING_LEVEL

IDL_RULES

IDL_TYPE

INCLUDES

LANGUAGE

LINKER_FLAGS

LINKER_NOREF

LINKLIBS

MAKEDLL

MASTER_VERSION_FILE

MFC_FLAGS

MFC_INC_PATH

MFC_INCLUDES

MFC_LIB_PATH

MFC_LIBS

MFC_VER

MIDL_OPTIMIZATION

MIDL_UUIDDIR

MSC_OPTIMIZATION

MSC_WARNING_LEVEL

NOLINK

NO_NTDLL

NOT_LEAN_AND_MEAN

NT_UP

NTDEBUGTYPE

NTKEEPRESOURCETMPFILES

NTNOPCH

NTPROFILEINPUT

NTTARGETFILE0

NTTARGETFILE1

NTTARGETFILES

PASS0_CLIENTDIR

PASS0_HEADERDIR

PASS0_SERVERDIR

PASS0_SOURCEDIR

PRECOMPILED_CXX

PRECOMPILED_INCLUDE

PRECOMPILED_OBJ

PRECOMPILED_TARGET

RC_COMPILER

RC_DEFINES

RCCODEPAGE

RCOPTIONS

SOURCES_USED

SYNCHRONIZE_BLOCK

SYNCHRONIZE_DRAIN

TARGET_CPP

TARGET_DIRECTORY

TARGETEXT

TARGETPATHLIB

UMAPPL

UMAPPLEXT

UMBASE

UMENTRY

UMENTRYABS

UMLIBS

UMTEST

UMTYPE

USE_CRTDLL

USE_INCREMENTAL_LINKING

USE_LIBCMT

USE_LIBCNTPR

USE_MAPSYM

USE_MFC

USE_MFCUNICODE

USE_MSVCRT

USE_NATIVE_EH

USE_NOLIBS

USE_NTDLL

USE_PDB

USE_STATIC_MFC

USECXX_FLAG

USER_C_FLAGS

USER_INCLUDES

Note For information on the DIRS and OPTIONAL_DIRS macros, see the dirs file.


_OBJ_ROOT

Use the _OBJ_ROOT macro to specify the root directory for the objects subdirectory (specified by the O environment variable). By using _OBJ_ROOT, you alter the default to allow you to build into a completely different directory tree. There are many advantages in doing this, including the ability to separate objects from your source tree and building onto a different hard drive.

For example, if you were to build out of d:\nt\private\foo, normally the objects tree would look something like d:\nt\private\foo\obj\i386. By setting _OBJ_ROOT=f:\build, you would cause the objects tree to appear as f:\build\foo\obj\i386.

The object path is determined by concatenating _OBJ_ROOT with a subset of the current directory. This subset is determined by taking the current directory and parsing out the drive, and BASEDIR, if it exists.


386_OPTIMIZATION

See MSC_OPTIMIZATION.


386_WARNING_LEVEL

See MSC_WARNING_LEVEL.


BINPLACE_FLAGS

The BINPLACE_FLAGS macro is not supported for use in the Windows DDK.


BINPLACE_PLACEFILE

The BINPLACE_PLACEFILE macro is not supported for use in the Windows DDK.


COFFBASE

Use the COFFBASE macro to specify the name to look up in COFFBASE_TXT_FILE.

If you do not specify a name, it defaults to the value of TARGETNAME (if building a DYNLINK) or to "usermode" (if you are building a UMAPPL, PROGLIB, or PROGRAM).

To specify an absolute base address for your image without using a global file for all, see DLLBASE or UMBASE.


COFFBASE_TXT_FILE

The COFFBASE_TXT_FILE macro specifies the name of the file that contains the base addresses for the images you build. By default, this is %ddkroot%\bin\coffbase.txt. If a different file is specified in this macro, the contents of this file will be passed to the linker

The file should have three columns. The first is the name of the image. The second is the starting address for the image. The last is the maximum size of the image. There should also be an entry with the name "usermode" that is the default value. Here is an example:

usermode0x600000000x20000000
MyDll10x700000000x00010000
MyDll20x700100000x00010000


COMPILER_WARNINGS

The COMPILER_WARNINGS macro specifies the name of the file that contains warning information. By default, this is $(SDK_INC_PATH)\warning.h. If a different file is specified in this macro, the name of this file will be passed to the compiler with the /FI switch.

The file contains a list of compiler pragmas used to disable, enable, or promote warnings for the entire build.


DEBUG_CRTS

The DEBUG_CRTS macro specifies which set of C runtime libraries should be used.

Whether you build a checked or free product, the Build utility always links against the retail run-time libraries and the retail MFC.

If you want to link against the debug MFC and the debug run-time libraries, specify the following in your sources file or set it in your environment variables before you build:

DEBUG_CRTS=1


DLLBASE

The DLLBASE macro is used to set the base address for the DLL image that you are creating. You only need to use this macro when you are building a DLL (that is, when your TARGETTYPE macro is set to DYNLINK).

You can override the default address by specifying an address with the DLLBASE macro (for example, 0x04000000). You can set DLLBASE to be the hard-coded base address or a hex address.

If DLLBASE is omitted or left blank, the Build utility will assume that the target name in coffbase.txt is the name of your image. It will take the value of COFFBASE, if defined, as a key; otherwise, it will take TARGETNAME as a key. The target name in coffbase.txt plus this key will be used to choose the base address.


DLLDEF

Use the DLLDEF macro to specify the name of the .def file that the Build utility will pass to the librarian when building the export and import files.

If you do not set this value, the Build utility will assume it is the same name as the image you are building (in other words, equal to $(TARGETNAME).def).

The most common usage is:

DLLDEF=mydll.def

Additionally, there is a standard inference rule that will run the C preprocessor over the .def or .src file in the current directory to create build-specific .def files in the object subdirectory. The same compiler define directives that you key off of in your source code can be used in the root .def or .src file to create the export list. To enable it, use something like:

DLLDEF=$O\mydll.def

Here is an example of what mydll.src might look like:

; mydll.src
LIBRARY mydll
EXPORTS
#if defined(_X86_)
X86Routine
#elseif defined(_IA64_)
IA64Routine
#else
#error Unknown platform
#endif
// Grab some other exports from another file
#include "master.src"


DLLENTRY

Use the DLLENTRY macro to specify the DLL entry point. By default, no entry point is assumed.

For example, when you bring over programs that were built in the Visual C++® build environment or that use the C run time, you will probably set:

DLLENTRY=_DllMainCRTStartup

Refer to the documentation about the "DLL entry point" in the Win32® SDK to determine what values to use.


DLLLIBOBJECTS

Use the DLLLIBOBJECTS macro to specify extra objects to add to an import library.

Usually, when the TARGETTYPE is DYNLINK, the end result is a DLL and an import library. If you want to have different LIB objects for each platform, you can override this value to create different platform-specific DLL LIB objects. DLLLIBOBJECTS enables you to specify additional objects to add to the import library.

For example, you might have an OLE custom control (with GUIDs used to identify this control) that also exports a non-OLE C interface from an import library. Rather than build two separate libraries (for example, mydll.lib and myuuid.lib), you can list the GUID data object(s) in DLLLIBOBJECTS. The result is a single library that your users will link against.


DLLORDER

When you are building a DLL, you can use the DLLORDER macro to specify an order file that will be passed to the linker.

The order file lists the functions and the order in which they should be linked together. By default, the Build utility passes the name of the DLL as the name of the order file. For example, if you are building kernel32.dll, the Build utility expects kernel32.prf as the order file.

You can use the DLLORDER macro to specify another name. The Build utility will use whatever name you give it. It can be in a different subdirectory, have a different name, or a different an extension. You can set DLLORDER to whatever you want it to be, and you can give it a fully qualified path name.

This macro can be used instead of NTPROFILEINPUT.


DRIVERBASE

Use the DRIVERBASE macro to specify the base address for a driver. This macro is similar to the DLLBASE and UMBASE macros.

It is not generally necessary to set this value, because it will be relocated at run time.


DRIVERTYPE

Use the DRIVERTYPE macro to optionally specify a DRIVERTYPE value. (This macro is required for WDM drivers.)

Use this macro only if your TARGETTYPE value is DRIVER. Values assigned to DRIVERTYPE are case-sensitive.

If you are building a VxD driver, set DRIVERTYPE=VXD.

If you are building a WDM Driver, set DRIVERTYPE=WDM.

If you are building an IFS Kit Driver, set DRIVERTYPE=FS.

For more information, see Building a New Driver.


EXEPROFILEINPUT

The EXEPROFILEINPUT macro has been changed. Its function is now identical to that of the NTPROFILEINPUT macro.


FREEBUILD

Use the FREEBUILD macro to specify whether your build is checked (debug) or free (retail).

This macro can be used in statements of the form:

If $FREEBUILD (do things for a retail build)


GPSIZE

Specify a value for the GPSIZE macro in your sources file to control the GPSIZE switch to the linker.

The GPSIZE is an optimization that is used on RISC platforms.


HALBASE

Use the HALBASE macro to specify the base address for a HAL. This macro is similar to the DLLBASE and UMBASE macros.

It is generally not necessary to set this value because it will be relocated at run time.


IA64_WARNING_LEVEL

See MSC_WARNING_LEVEL.


IDL_RULES

The IDL_RULE macro is only used for OLE builds.


IDL_TYPE

When you specify an interface description language (IDL) file in your sources rule, you have to specify whether this is an OLE IDL or an RPC IDL file, because their syntax differs. Based on the syntax, the Build utility passes different commands to the Microsoft IDL Compiler (MIDL). The default value of IDL_TYPE is OLE.

Both of the following lines specify OLE:

IDL-TYPE=" "
IDL_TYPE=ole

The following line specifies RPC:

IDL_TYPE=rpc


INCLUDES

Use the INCLUDES macro to indicate the location of the headers to be included in your build. This macro should be invoked from within your sources file.

This macro should be set to a list of the paths to be searched for include files during compilation. Separate the entries in this list using a semicolon. Path names can be absolute, or relative to the directory in which the sources file resides.

For example:

INCLUDES=bunny;inc
INCLUDES=.\
INCLUDES=.\inc

The INCLUDES macro is read by the Build utility. It looks at the INCLUDES variable that you specify in your sources file to determine the location of the header files that you are including in your source code so that it can build the dependency tree.

Paths specified in the INCLUDES macro will be searched before the default paths. The list of default paths is determined by the values of TARGETTYPE and DRIVERTYPE. Depending on the values of these macros, the default paths can include the values of any of the following macros: CRT_INC_PATH, DDK_INC_PATH, WDM_INC_PATH, SDK_INC_PATH, OAK_INC_PATH, or MFC_INC_PATH.

You will usually use the INCLUDES macro in your sources file to indicate to the Build utility the location of the headers to be included in your build. However, there are times when some header files may not exist (for example, if they are built as part of the build process). Such headers should be specified in the USER_INCLUDES macro.


LANGUAGE

Use the LANGUAGE macro to specify the language when you set up dependencies so that you can include country/region-specific parts in your build. If you are building a product for the USA, you might want to include a USA icon, but if you are building for Korea, you would want to use a Korean icon.

The default is LANGUAGE=USA.


LINKER_FLAGS

Use the LINKER_FLAGS macro to override any default linker switch that will be passed to the linker.

Type link-? to view a list of all the linker switches. This macro provides a way to pass in flags that you cannot pass in another way.


LINKER_NOREF

Use the LINKER_NOREF macro to turn off switches to the linker.

By default, the Build utility turns some switches on. One of them is the OPTICAL_AND_REF switch, which instructs the Build utility to dispose of everything that is not referenced in the current module. This default helps to keep your modules small, but can have the disadvantage of causing your to lose, for example, debug routines that you might want to call from the debugger.

To avoid such problems, set the LINKER_NOREF value in your environment, rebuild your product, load it up in the debugger, and then run those functions that are only used in the debug scenario.


LINKLIBS

Use the LINKLIBS macro to specify the libraries that you need to link against.

The only difference between TARGETLIBS and LINKLIBS is the ordering on the command line. LINKLIBS usually gets passed first; TARGETLIBS gets passed second. If you order them correctly in your TARGETLIBS macro, that should not be a problem, except when you are building a DLL.

When you are building a DLL, you could be using objects that you have built in combination with libraries from which you would like to export certain features. For example, perhaps you compile a number of objects into a library in subdirectory one. In subdirectory two, you compile other objects into a library. And in subdirectory three, you build the DLL. However, this DLL must export functions that are defined in library one or library two. In such a case, you must put those libraries in your LINKLIBS macro.

This operation must be carefully done. The LINKLIBS macro requires that the library must be located in pass one of the build, because the Build utility builds the import libraries during pass one. You must structure your build in such a manner that the libraries are guaranteed to exist during pass one. You should never specify an import library in your LINKLIBS macro, primarily because you could end up exporting something that you imported from somebody else instead of what you actually had (perhaps with syntax errors or other problems). Problems resulting from such a mishap can be undetectable for some time.

As a result, It is almost always better to use TARGETLIBS. Use LINKLIBS only for cases that meet the following conditions:

  • You are building a dynamic link.
  • You are exporting something that is defined in some other component library that you also build.
  • In your dirs file in the previous subdirectory, you have ordered it so that the component libraries are around before you build the dynamic link.

There is a similar macro called UMLIBS that you can use if you are building UMAPPLs.


MAKEDLL

The MAKEDLL macro controls whether any actual linking occurs.

Normally, the build process is a two-pass build. In the first pass, the Build utility compiles all the source files, and creates import libraries and component libraries. In the second pass, it links everything against those libraries. The default, which directs the Build utility to make the second pass, is as follows:

MAKEDLL=1

Typically, you do not set this value. You might do a test in your make file to instruct the Build utility::

IF MAKEDLL=1
do things that you want to do on the second pass of the build

A more frequent use of this macro is to run NMAKE from the command line to run the compile and to link without running the Build utility:

nmake MAKEDLL=1

The Build utility will complete the compile operation and the link in one step without running the Build utility. This works because the Build utility is only required to determine the dependencies and call NMAKE. This method works when:

  • you know the dependencies
  • the source file has changed and you do not care about the header file dependency generation
  • tou are in a leaf node subdirectory

See Also

NOLINK


MASTER_VERSION_FILE

The MASTER_VERSION_FILE macro specifies the file name of a master version file.

Every binary created by the Build utility has a version number on it. These are usually based on version resources created by Microsoft when products built for NT-based operating systems are created.

You can use Windows Explorer or filever.exe to view properties and see which version resource the Setup program uses when it copies that image onto a new system. The system checks whether or not the version resource is newer than the one already on the system. If it is, the resource is copied onto the system, otherwise it is not.

There is a master version file for NT-based operating systems, from which all version resources are built. The Master Version File for NT-based operating systems is called ntverp and it is located in %ddkroot%\inc\wxp.

If you do not wish to use the version specified in ntverp, you can specify a different master version file by setting MASTER_VERSION_FILE to the correct file name.

If you look on the very last line of makefile.def, you will see the one place where MASTER_VERSION_FILE is used as a dependency for the resources. The TARGET_DIRECTORY macro is always dependent on the master version file to determine the name of the resource for your image.


MFC_FLAGS

The MFC_FLAGS macro specifies MFC compiler command-line options.

If you have extra command line options that you want to pass to the compiler, you can put them in MFC_FLAGS. They will only affect programs that use MFC. That can be useful if you have a global project.

For example, you could set MFC_FLAGS equal to some macro name or compiler #define instruction that you want to add. Alternatively, you can use the C_DEFINES macro.


MFC_INC_PATH

Use the MFC_INC_PATH macro to specify the path to the MFC headers.


MFC_INCLUDES

Use the MFC_INCLUDES macro to optionally specify the location of MFC headers on your system.

This should be used if you are supplying your own MFC headers.


MFC_LIB_PATH

Use the MFC_LIB_PATH macro to specify the path to the MFC libraries.


MFC_LIBS

Use the MFC_LIBS macro to provide explicit MFC library names and override the default names that the Build utility uses.


MFC_VER

Use the MFC_VER macro to specify the version of MFC to use in the build process.

By default, this value is set to 0x0600. This value should not be changed.


MIDL_OPTIMIZATION

Use the MIDL_OPTIMIZATION macro to override the default optimization that is passed to the Microsoft IDL Compiler (MIDL). The default is OI2.


MIDL_UUIDDIR

Use the MIDL_UUIDDIR macro to specify where the GUID file is placed when you generate an OLE interface description language (IDL) file. (UUIDs and GUIDs are the same thing.)

By default everything built in pass zero is placed in the location that you defined as the TARGETPATH subdirectory. Use this macro to override that default.

To create the GUIDs in the current subdirectory, set MIDL_UUIDDIR to be dot ("."):

MIDL_UUIDDIR=.

It does not matter where you put the GUIDs so long as you set your #include directives to retrieve them from this location. Otherwise, the tools later used by the Build utility will not be able to find the GUIDs.


MSC_OPTIMIZATION

Use the MSC_OPTIMIZATION macro to override the default optimization that the Build utility uses on the compiler. By default, everything is optimized. If you want to turn off optimization in order to step through your code, you can set the MSC_OPTIMIZATION value to whatever is appropriate for your compiler.

When building in the Checked Windows DDK environment, this value is set to /Od /Oi, which avoids all optimization. All of these flags also have platform-specific variants.

If MSC_OPTIMIZATION is not specified, the default is 0xs, which fully-optimizes the binaries, with a preference for smaller rather than faster binaries.

If you do not prefer these settings, you can always override the generic MSC_OPTIMIZATION macro with platform-specific macros. Available macros include I386_OPTIMIZATION for Intel x86, and IA64_OPTIMIZATION for Intel Itanium.

Note Platform specific settings (386_OPTIMIZATION, for example) will override the generic setting (MSC_OPTIMIZATION) if both are defined.

See Also

MSC_WARNING_LEVEL


MSC_WARNING_LEVEL

Use the MSC_WARNING_LEVEL macro to set the warning level to use on the compiler. The default is /W3.

After your code builds without errors, you might want to change MSC_WARNING_LEVEL to /W3/WX. Setting this value causes warnings to show as errors.

MSC_WARNING_LEVEL is generic to all platforms. Platform-specific variants include 386_WARNING_LEVEL for Intel x86, and IA64_WARNING_LEVEL for Intel Itanium.

Note Platform-specific settings (386_WARNING_LEVEL, for example) will override the generic setting (MSC_WARNING_LEVEL) if both are defined.

See Also

MSC_OPTIMIZATION


NOLINK

The NOLINK and MAKEDLL macros are primarily used in the master make file (makefile.def) to indicate which rules to enable or disable when the Build utility goes through two tools.

NOLINK=1 indicates that a link is not supposed to occur — most likely because this is pass one and the Build utility cannot guarantee that the libraries needed are built yet.

MAKEDLL=1 indicates that a link should occur and is used in pass two after the libraries are built. If you run a one-pass build (by specifying -z on the command line to the Build utility), only MAKEDLL=1 is specified.

You can test for this macro in your make file. For example, if NOLINK=1, you are in pass one; if MAKEDLL=1, you are in pass two.


NO_NTDLL

Use the NO_NTDLL macro to indicate that ntdll.lib should not be automatically added to the library list.


NOT_LEAN_AND_MEAN

The NOT_LEAN_AND_MEAN macro causes the Build utility to use a much greater number of header files.

Normally, Visual Studio® compilations use the windows.h file. This file tests to see whether a variable named WIN32_LEAN_AND_MEAN is defined. When WIN32_LEAN_AND_MEAN is defined, a large number of header files are deliberately excluded by windows.h; only the actual Windows headers are used. The equivalent Build utility procedure is to leave the NOT_LEAN_AND_MEAN macro undefined (or equal to zero). This is the default setting of the Build utility.

If the WIN32_LEAN_AND_MEAN variable is undefined in a Visual Studio build, or if NOT_LEAN_AND_MEAN=1 in a Build utility build, all header files are used. This is a much larger comilation — in addition to the Windows headers, it includes the OLE, RPC, and network headers. This is the default setting for Visual Studio.

If you wish to emulate the default Visual Studio behavior, define the following in your sources file:

NOT_LEAN_AND_MEAN=1

The best practice is to review your code and remove unnecessary header files. However, this is sometimes a much more difficult process.


NT_UP

Use the NT_UP macro to indicate whether your driver will run on a uniprocessor machine or multiprocessor machine. The default is a uniprocessor machine, as follows:

NT_UP=1

To specify multiprocessor, set

NT_UP=0

The Windows DDK environment automatically sets this value to NT_UP=0, which should be used for all Windows XP drivers.


NTDEBUGTYPE

Use the NTDEBUGTYPE macro to specify the method of linking and the kind of symbols that are used.

If you specify

NTDEBUGTYPE=ntsd

this will produce COFF symbol information. These symbols are useful only for debugging with NTSD, CDB, or KD.

If you specify

NTDEBUGTYPE=windbg

this will produce CodeView symbol information. All debuggers can understand these symbols.

To produce both COFF and CodeView symbol information, you should use

NTDEBUGTYPE=both

Note If you want to generate a program database (.pdb file) for the CV information, you must also set USE_PDB equal to one. (This is the default in the Windows XP build environment.)


NTKEEPRESOURCETMPFILES

The NTKEEPRESOURCETMPFILES macro delays the conversion of Resouce Compiler (RC) binaries.

The RC generates a binary file, but this file cannot be linked into a final image because it is not in the right format. Normally, the Build utility converts it to the right format as soon as the RC creates it (unlike other build programs, which usually convert the file during the linking process).

Converting the file immediately has the advantage that if you build a file once, it can be linked as many times as you want and it will never need to be reconverted. But it has the disadvantage that tools that understand the RC output cannot be used.

If you wish the RC output format to be preserved, set:

NTKEEPRESOURCETMPFILES=1

This delays the conversion until the linking is done. Every time you link the file, the Build utility will convert it. This makes your links a little slower, but means you can use other tools, such as the Visual C++® Resource Editor, to modify it before you link it.


NTNOPCH

Use the NTNOPCH macro to turn off the precompiled headers option for a single source file.

If you have precompiled headers on a subdirectory, the Build utility expects you to build that subdirectory and to make subsequent changes as you go along. Whenever you change one of the source files, you must rebuild that file. The Build utility detects the use of precompiled headers and compiles that single source file without them.

If you set

NTNOPCH=1

this enables you to build everything, and then to change a definition in a header file (for example, a #define something to something else). Then you can change the source file to use that new definition. Of course, you do not want to regenerate the precompiled header and rebuild everything else; it is preferable to rebuild that one source file, without using the old precompiled header. This macro tells the Build utility to turn off precompiled headers for this source file.

The Build utility will reread all the headers and use the new header information. This also requires using the -Z or -z command-line options, so that the Build utility will not scan dependencies and therefore will not regenerate the precompiled header.


NTPROFILEINPUT

The NTPROFILEINPUT macro lets you specify a profile file, which is a list of all the functions or symbols in your image and the order you want them exported in the final image.

To use a profile file, specify the following in your sources file:

NTPROFILEINPUT=1

When this is set, the Build utility will search the current subdirectory for a file whose name is the same as your build product (the name specified by TARGETNAME), and whose extension is .prf. The Build utility uses this file to order the final image that it builds.

You can optimize page usage by listing the functions in the order in which they should be exported in the final image.


NTTARGETFILE0

You can define the NTTARGETFILE0 and/or NTTARGETFILES macros to cause makefile.def to include makefile.inc immediately after it specifies the top level targets (all, clean and loc) and their dependencies.

The makefile.def file expands NTTARGETFILE0 as the first dependent for the all target, and NTTARGETFILES as the last dependent for the all target. Use this macro to specify additional targets and dependencies that do not fit the general case covered by makefile.def.

NTTARGETFILE0=

The fact that NTTARGETFILE0 exists, even if it is defined and empty, causes the Build utility to open makefile.inc in the same subdirectory as the sources file.

If you set NTTARGETFILE0 to equal a file name, the Build utility will not only include makefile.inc, but will also build the executable that the macro defines. Thus, if you set:

NTTARGETFILE0=myfile.a

the Build utility builds myfile.a as part of pass zero.

If you do not set NTTARGETFILE0, the Build utility locates the specified subdirectory on pass zero, includes the makefile.inc in that subdirectory, and follows any default rules that this file contains.

See Also

NTTARGETFILE1


NTTARGETFILE1

The NTTARGETFILE1 macro is exactly like NTTARGETFILE0, except that it occurs later in the build process. NTTARGETFILE0 occurs on pass zero; NTTARGETFILE1 occurs on pass two.

Both of these macros cause the Build utility to change directories to a specified subdirectory and to run NMAKE on pass zero or pass two in a case where it ordinarily probably would not do so.


NTTARGETFILES

If you have unique rules in your subdirectory, you can use the NTTARGETFILES macro to signal to the Build utility that you have a makefile.inc file in addition to the sources file in the subdirectory.

The makefile.inc file will provide additional information about the build process, including dependencies, command line rules, and other build rules.

See Also

NTTARGETFILE0, NTTARGETFILE1


PASS0_CLIENTDIR

The PASS0_CLIENTDIR, PASS0_HEADERDIR, and PASS0_SERVERDIR macros are used when you have a SOURCES macro in your sources file. That macro can contain the following types of files:

  • C
  • C++
  • RC
  • MC
  • IDL

Use the PASS0_CLIENTDIR, PASS0_HEADERDIR, and PASS0_SERVERDIR macros to specify a directory location for the output from the MC and the Microsoft® IDL Compiler (MIDL).

If you run MIDL over sources that include interface description language (IDL) files, the Build utility generates a server part, a client part, a header, and a default source. Use the PASS0_SERVERDIR and PASS0_CLIENTDIR macros to specify their output location.

Running MC causes the generation of a header file and a source file.. Use the PASS0_HEADERDIR and PASS0_SOURCEDIR macros to specify their output location.

When you are building a MIDL stub, it's RPC, so you have what runs on the client side and what runs on the server side. There are stub programs that communicate in RPC to each other. You can override those by default.


PASS0_HEADERDIR

Use the PASS0_HEADERDIR macro to specify the output location of the headers generated by MC and the Microsoft IDL Compiler (MIDL). By default, everything built in pass zero is output to the TARGETPATH subdirectory. Use this macro to change that default.

To create the headers in the current subdirectory, set PASS0_HEADERDIR to dot ("."):

PASS0_HEADERDIR=.

Headers can be output to any location. If your #include directives do not specify the correct location, however, the tools later used by the Build utility will not be able to find the headers.

See Also

PASS0_CLIENTDIR


PASS0_SERVERDIR

Use the PASS0_SERVERDIR macro to specify an output location for the server part that the Microsoft IDL Compiler (MIDL) generates. By default, the results of pass zero are output to the TARGETPATH subdirectory. Use this macro to change that default.

To create the server part in the current subdirectory, set PASS0_SERVERDIR to dot ("."):

PASS0_SERVERDIR=.

Headers can be output to any location. If your #include directives do not specify the correct location, however, the tools later used by the Build utility will not be able to find the headers.

See Also

PASS0_CLIENTDIR


PASS0_SOURCEDIR

Use the PASS0_SOURCEDIR macro to specify the output location for the source code generated by the Microsoft IDL Compiler (MIDL) and maketype.lib file. By default, the results of pass zero are output to the TARGETPATH subdirectory. Use this macro to change that default.

To create the source code generated by MIDL and maketype.lib in the current subdirectory, set PASS0_SOURCEDIR to dot ("."):

PASS0_SOURCEDIR=.

Your source code and maketype.lib file can be output to any location. If your #include directives do not specify the correct location, however, the tools later used by the Build utility will not be able to find the correct files.

See Also

PASS0_CLIENTDIR


PRECOMPILED_CXX

Use the PRECOMPILED_CXX macro to indicate whether the precompiled header you are building will be used with files written in C or C++.

The default is to use precompiled headers with files written in C. Therefore, you should not set PRECOMPILED_CXX if your project will use the precompiled header with files written in C.

To use the precompiled header with C++ files, specify

PRECOMPILED_CXX=1

See Also

Using Precompiled Headers


PRECOMPILED_INCLUDE

Use the PRECOMPILED_INCLUDE macro to specify the name of the precompiled header. For example, if you have precompiled headers that are a.c, b.c, and c.c as your source files, and all of them include precomp.h, specify:

PRECOMPILED_INCLUDE=precomp.h

If you omit this instruction, you will not be able to use precompiled headers. PRECOMPILED_INCLUDE sets the build process use precompiled headers.

See Also

Using Precompiled Headers


PRECOMPILED_OBJ

Use the PRECOMPILED_OBJ macro to override the default name given to the precompiled object.

By default, the Build utility takes the precompiled header with the precompiled #include directive that you specify (for example, precomp.h). The Build utility generates precomp.obj for the precompiled object and precomp.pch for the precompiled target.

You can override those names by setting the PRECOMPILED_OBJ and PRECOMPILED_TARGET macros.

See Also

Using Precompiled Headers


PRECOMPILED_TARGET

Use the PRECOMPILED_OBJ macro to override the default name given to the precompiled target.

By default, the Build utility uses the precompiled header with the precompiled #include setting that you specify (for example, precomp.h). The Build utility uses the precompiled header to create precomp.obj for the precompiled object and precomp.pch for the precompiled target.

You can override those names by setting the PRECOMPILED_OBJ and PRECOMPILED_TARGET macros.

See Also

Using Precompiled Headers


RC_COMPILER

The RC_COMPILER macro is statically defined and cannot be overridden.

See Also

RC_DEFINES, RCCODEPAGE, RCOPTIONS


RC_DEFINES

The RCOPTIONS macro contains a string to be passed to the Resource Compiler (RC). It is equivalent to the RCOPTIONS macro.

See Also

RC_COMPILER, RCCODEPAGE


RCCODEPAGE

The RCCODEPAGE macro is used to set the code pages that are associated with your build.

The value of RCCODEPAGE is passed to the Resource Compiler (RC) as the argument of its -C parameter.

This can be useful if you wish to control the code pages used (for instance, when building products for different language markets).

See Also

RC_COMPILER, RC_DEFINES, RCOPTIONS


RCOPTIONS

The RCOPTIONS macro contains a string to be passed to the Resource Compiler (RC).

See Also

RC_COMPILER, RC_DEFINES, RCCODEPAGE


SOURCES

The SOURCES macro specifies the files to be compiled. The SOURCES macro is required by the Build utility. This macro must be placed in your sources file. All files specified by this macro must reside in the directory containing the sources file.

The Build utility examines these files and generates a dependency list. If any of those dependencies change, the Build utility rebuilds this source file.

Use this macro to list your source file names. Include the file name extension, and separate the entries in this list with spaces or tabs.

If you supply one or more source files that contain a main function, these files must be listed using the UMAPPL or UMTEST macro. They are not listed using SOURCES.


SOURCES_USED

Use the SOURCES_USED macro to indicate that there is another sources file or make file elsewhere in the tree. Use this macro if that additional file contains build dependencies.

When you specify:

SOURCES_USED=filename_someplace_else

NMAKE regenerates the objects file when changes occur in the sources file that resides in the specified directory. NMAKE will also regenerate the objects file when changes occur in any sources file or make file that you specified in the SOURCES_USED macro.

For example, a sources file typically includes some other file. Just beneath that directive you could specify:

SOURCES_USED=that_filename

This instruction establishes a link between that file and the sources file. When that other file changes, NMAKE regenerates the _objects.mac file.


SYNCHRONIZE_BLOCK

The SYNCHRONIZE_BLOCK macro instructs the Build utility to build a certain subdirectory first.

When the Build utility finds this macro in a sources file, will stop building all other directories until this directory is built. To use this macro, specify the following in your sources file:

SYNCHRONIZE_BLOCK=1

Use SYNCHRONIZE_BLOCK when you have a subdirectory that other subdirectories require the results from in order to build (for example, a global precompiled header). List the precompiled directory first in the dirs file, and add SYNCHRONIZE_BLOCK=1 to the sources file. This assures that the subsequent directories that use the precompiled header will not be built until the header is created.

See Also

Building on a Multiprocessor Computer


SYNCHRONIZE_DRAIN

The SYNCHRONIZE_DRAIN macro instructs the Build utility to build a certain subdirectory last.

A directory whose sources file contains this macro will not be built until all other subdirectories have been built. To use this macro, specify the following in your sources file:

SYNCHRONIZE_DRAIN=1

Use SYNCHRONIZE_DRAIN when you have a subdirectory that needs the results from a prior subdirectory on the same pass. For example, when building a DLL, you may have several subdirectories with TARGETTYPE=LIBRARY, where each builds some component. You may have another subdirectory with TARGETTYPE=DYNLINK, where the Build utility will build a DLL that exports functions from the component libraries. In such a case, you should set LINKLIBS to the component libraries, make sure the DLL subdirectory is the last in the parent dirs file file, and add SYNCHRONIZE_DRAIN=1 to the sources file for the DLL.

See Also

Building on a Multiprocessor Computer


TARGET_CPP

Use the TARGET_CPP macro to specify name of the compiler.

The default value is cl.exe.

Warning Microsoft does not support the use of an alternate compiler. It is highly recommended that you not change the value of this variable.


TARGET_DIRECTORY

Use the TARGET_DIRECTORY macro as follows to specify the target directory, if you want some dependency file to always end up in the obj subdirectory:

TARGET_DIRECTORY=some_sourcefile:some_dependency_file

This instruction enables you to draw upon resources contained in a single source tree to complete multiple platform-specific builds without conflicts. You do not have to hard-code the name of the platform.

For example, if you have a special Build utility rule for some feature in your code, or if you want to build a particular object from a particular C file, you can use the following line in a sources file:

obj\$(TARGET_DIRECTORY)\filename.obj; filename.c

Using the TARGET_DIRECTORY macro ensures that the specified file will be placed in the appropriate subdirectory. For example, \obj\i386subdirectory\obj\.

There are some default targets. One of them is .cod. If you issue the following instruction from a subdirectory containing source files:

nmake SOURCE_FILE_NAME=.cod

it will create an assembler listing that you can review to determine the location of the compiler error.

There is another default target called .pp file, a preprocessed listing. Preprocessing adds line numbers. You can use these line numbers to determine whether the Build utility retrieved headers from the correct location, and which #define directives and structures it added.

If you issue the following instruction from a subdirectory containing source files:

nmake SOURCE_FILE_NAME=.pp

the Build utility will preprocess the file.

The .cod and .pp files are very useful for tracking bugs in the build process.


TARGETEXT

Use the TARGETTEXT macro to specify the file extension (such as .cpl) for your DLL files.

If this macro is not defined, the .dll extension will be used.

If you specify something unexpected, the Build utility will display the message, "Unexpected Target Ext".


TARGETLIBS

Use the TARGETLIBS macro to specify other libraries that you want to link against when building your image. This macro should be the primary method you use to specify the libraries or objects that you want to link against to build your image.

TARGETLIBS Paths

Paths specified in TARGETLIBS must be absolute. Separate the entries in this list with spaces or tabs.

Here is an example:

TARGETLIBS=$(SDK_LIB_PATH)\kernel32.lib \
           $(SDK_LIB_PATH)\advapi32.lib \
           $(SDK_LIB_PATH)\user32.lib   \
           $(SDK_LIB_PATH)\spoolss.lib

The TARGETLIBS path names must be defined in a special way. Because the Build utility can create build products for several hardware platforms, the destination path for build products is constructed as follows:

%TARGETPATH%\<cpu_type>\

where TARGETPATH is defined in the sources file, and cpu_type specifies the platform for which the products were built.

For example, if TARGETPATH is defined as LIB and a build request is made for an x86 processor, the build products will be directed to the following subdirectory:

lib\i386\

Because of this convention, TARGETLIBS entries must specify library names in the following form:

<targetpath>\*\<library_name>

where targetpath is identical to the value assigned to TARGETPATH in the sources file, and library_name is the full file name of the library to be linked to the executable file. The Build utility replaces the asterisk (*) with the target platform type.

LINKLIBS and UMLIBS

You can also use the LINKLIBS macro to specify the libraries that you need to link against. This macro is needed for some DLL builds, but it must be used carefully. For more information, see its reference page.

There is a similar macro called UMLIBS that you can use if you are building UMAPPLs.


TARGETNAME

Use the TARGETNAME macro to specify the name of the library to be built. Do not include the file name extension.

You must have this macro in your sources file unless you set TARGETTYPE equal to NOTARGET.


TARGETPATH

Use the TARGETPATH macro to specify the destination directory for all build products. You must have this macro in your sources file.

All build products (such as .exe, .dll, and .lib files) will be placed in this directory. Object files will be placed in the \obj subdirectory of this directory.

For example:

TARGETPATH=obj

The value of BUILD_ALT_DIR will be appended to the value of TARGETPATH to produce the directory name.

See Also

Specifying Libraries


TARGETPATHLIB

In the process of building a DLL, the Build utility also creates an import library to be used by other images that must use your DLL.

Use the TARGETPATHLIB macro to specify the target directory for this import library.

If TARGETPATHLIB is not specified, import libraries are placed in the same subdirectory as other build product files (that is, a subdirectory under TARGETPATH).


TARGETTYPE

Use the TARGETTYPE macro to specify the type of product being built. TARGETTYPE gives the Build utility clues about some of the input files that it should expect. You must include this macro in your sources file.

When building a DLL, TARGETTYPE is typically LIBRARY or DYNLINK.

The full list of possible values is as follows:

Value | Definition | Product Extension
PROGRAM | User-mode program that does not export anything. | .exe
PROGLIB | Executable program that also exports functions for other programs. | .exe
DYNLINK | Dynamic link library (DLL). This could be a control panel applet or anything that can be dynamically loaded or that people can import from that has to have when its linked. The DLL switch is passed to the linker to indicate it's not a stand-alone .exe. When you build a dynamic link, you might also need to set the TARGETEXT macro. | .dll
LIBRARY | Import library containing code that will be linked with other code. This is a library of objects, not an import library. (An import library is built as a side effect of building a dynamic link. Anytime you build a dynamic link, you get a .lib file and a .dll file. When you build a library, you just get a .lib file.) | .lib
DRIVER | Kernel-mode driver. | .sys
DRIVER_LIBRARY | Import library for a driver. The only difference between LIBRARY and DRIVER_LIBRARY is the default path for included header files. | .lib
EXPORT_DRIVER | Kernel-mode driver that also exports functions for other drivers. | .sys
HAL | Hardware Abstraction Layer. | .dll
BOOTPGM | Kernel-mode driver. | .exe
MINIPORT | Kernel-mode driver that does not link with ntoskrnl.lib or hal.lib. | .sys
GDI_DRIVER | Kernel-mode graphics driver that links with win32k.sys. | .dll
NOTARGET | Specifies that no target should actually be created. Use this if you have a directory that needs some processing but you do not wish a binary to be generated. |


UMAPPL

The UMAPPL macro enables you to build multiple targets from a single subdirectory.

If you use UMAPPL, the Build utility will automatically build executable files. Listing the names of executables in the Build utility command line is unnecessary.

To use this macro, specify a list of source file names containing a main function. Specify these file names without file name extensions and separate them with an asterisk. For example:

UMAPPL=a*b*c*d

The Build utility will compile and link each file in this list after the main target in the sources file is built. The only restriction is that there can only be one source file and you must use the UMLIBS macro to specify any files to which it should be linked.

The Build utility links against whatever things you list in the UMLIBS macro. These things could include a .res file if you have a common resource, a library that you just built in a subdirectory, or a library or object from another subdirectory. There is no limit to the files that can be listed in UMLIBS.

The difference between UMAPPL and UMTEST is that if you use the UMTEST macro, you must specify the executable names to be built on the command line of the Build utility. If you use UMAPPL, you need not specify anything on the command line, and the Build utility will automatically build all the program files.


UMAPPLEXT

Use the UMAPPLEXT macro to specify the file extensions for image files built from a single source file.

The default is .exe. Use UMAPPLEXT when you want the extension to be something other than .exe. (for example, .com or .scr).

If you want the file extension to be .exe, use UMAPPL. If you have questions about using UMAPPLEXT, see the makefile.def file.


UMBASE

The UMBASE macro can be used to set the base address for a program that you are creating.

If UMBASE is omitted or left blank, the Build utility will assume that the target name in coffbase.txt is the name of your image. It will take the value of COFFBASE, if defined, as a key; otherwise, it will take "usermode" as the key.The target name in coffbase.txt plus this key will be used to choose the base address.

When neither UMBASE nor COFFBASE is defined, the default base address of 0x01000000 will be used. It is very unlikely that your program would need a different base address than the default.

If you are building a DLL, you should use the DLLBASE macro instead.


UMENTRY

Use the UMENTRY macro to override the default entry point and specify a different entry point.

The UMENTRY macro can only be used if UMTYPE is either windows or console. If UMTYPE is something else, you can only change the default entry point by setting the absolute entry point with UMENTRYABS.

The only entry points that will be correctly understood when linking to the C runtime libraries are main and winmain, and their Unicode variants wmain and wwinmain. You should not specify any other entry points with UMENTRY.

If UMENTRY is not used, the default entry points depend on the value of UMTYPE and the character set (specified by the USE_MFCUNICODE macro).The following table lists the default entry points:

UMTYPE | Character set | Default entry point
windows | ASCII | winmain
windows | Unicode | wwinmain
console | ASCII | main
console | Unicode | wmain


UMENTRYABS

Use the UMENTRYABS macro to specify an absolute entry point.

The entry point in your source code does not, in general, match the absolute entry point in your binary. By default, the entry points and absolute entry points used by the Build utility depend on the type of product being built (specified by the UMTYPE macro) and on whether ASCII or Unicode is being used as the character set (specified by the USE_MFCUNICODE macro).

The following table lists the standard values of the entry points and the absolute entry points:

UMTYPE | Entry Point | Absolute Entry Point
windows (ASCII) | winmain | WinMainCRTStartup
windows (Unicode) | wwinmain | wWinMainCRTStartup
console (ASCII) | main | mainCRTStartup
console (Unicode) | wmain | wmainCRTStartup
nt |  | NtProcessStartup
ntss |  | NtProcessStartup
os2 |  | NtProcessStartup
posix |  | __PosixProcessStartup

Use the UMENTRYABS macro to override the absolute entry point. For example, you might want the absolute entry point to be main rather than mainCRTStartup. In this case, you would use the following setting:

UMENTRYABS=main


UMLIBS

Use the UMLIBS macro to specify a list of library path names to be linked to the files that are specified in UMTEST or in UMAPPL. Include the library that is generated by the sources file.

The specified paths must be absolute. Separate the entries in this list with spaces or tabs.

The UMLIBS path names must be defined in a special way. Because the Build utility can create build products for several hardware platforms, the destination path for build products is constructed as follows:

%TARGETPATH%\<cpu_type>\

where TARGETPATH is defined in the sources file, and cpu_type specifies the platform for which the products were built.

For example, if TARGETPATH is defined as LIB and a build request is made for an x86 processor, the build products will be directed to the following subdirectory:

lib\i386\

Because of this convention, UMLIBS entries must specify library names in the following form:

<targetpath>\*\<library_name>

where targetpath is identical to the value assigned to TARGETPATH in the sources file, and library_name is the full file name of the library to be linked to the executable file. The Build utility replaces the asterisk (*) with the target platform type.


UMTEST

Use the UMTEST macro to list the source file names that contain a main function. Type these file names without extensions and separate them with an asterisk. For example:

UMTEST=a*b*c*d

The Build utility will compile and link each file in this list after the main target in the sources file is built. The only restriction is that there can be only one source file and you must use the UMLIBS macro to specify the files to which it should link.

If you use UMTEST, you must identify the names of files you want built by listing them in the Build utility command line. Only files listed in this manner will be build. Use UMAPPL to avoid this requirement.


UMTYPE

Use the UMTYPE macro to specify the type of product being built:

Set UMTYPE to This: | To Specify This:
windows | A user-mode Win32® program (this is the default)
console | A Microsoft MS-DOS® Command window program (a Win32 console program, not a 16-bit DOS application)
nt | A kernel-mode program for an NT-based operating system
ntss | A subsystem for an NT-based operating system
os2 | An OS/2 program
posix | A POSIX program


USE_CRTDLL

The USE_CRTDLL, USE_MSVCRT, USE_LIBCMT, USE_LIBCNTPR, USE_NTDLL, and USE_NOLIBS macros indicate which run-time libraries the Build utility should use.

You should define exactly one of these macros equal to one in your sources file. The other ones should not be defined at all (you may not define them equal to zero or equal to "").

The different libraries specified by these macros are as follows:

Macro | Effect
USE_CRTDLL | Use the multi-threaded run-time libraries in a DLL. In the free build environment, this means msvcrt.lib. In the checked build environment, this means msvcrtd.lib.
USE_MSVCRT | (Same as USE_CRTDLL,)
USE_LIBCMT | Use the multi-threaded static libraries.
USE_LIBCNTPR | Use the kernel run-time libraries.
USE_NTDLL | Use ntdll.dll (the DLL for NT-based operating systems).
USE_NOLIBS | Do not use any run-time libraries.

If none of these macros are defined, the default behavior is to statically link to the single-threaded run-time libraries. In the free build environment, this means libc.lib. In the checked build environment, this means libcd.lib.


USE_INCREMENTAL_LINKING

Use the USE_INCREMENTAL_LINKING macro to direct the Build utility to use incremental linking.

USE_INCREMENTAL_LINKING=1

Using incremental linking can speed up builds on slower hardware.

See Also

USE_PDB


USE_LIBCMT

See USE_CRTDLL.


USE_LIBCNTPR

See USE_CRTDLL.


USE_MAPSYM

Use the USE_MAPSYM macro if you wish to generate .sym symbol files in addition to the .pdb symbol files.

This macro is required if you are building a Windows 98/Me product and you need debugging symbols. Use the following syntax:

USE_MAPSYM=1


USE_MFC

Use the USE_MFC macro in your sources file to indicate that you are using MFC. The following instruction will establish the correct build environment for a program using MFC.

USE_MFC=1


USE_MFCUNICODE

Use the USE_MFCUNICODE macro in your sources file to indicate that you are using Unicode MFC. The following instruction will establish the correct build environment for a program that uses Unicode MFC.

USE_MFCUNICODE=1

The Build utility supports either MFC3 or MFC4.


USE_MSVCRT

See USE_CRTDLL.


USE_NATIVE_EH

Use the US_NATIVE_EH macro if you are using standard C++ exception handling (try, catch, and throw). Specify the following in your sources file:

USE_NATIVE_EH=1

This instruction directs the Build utility to turn on some needed switches to the compiler.


USE_NOLIBS

See USE_CRTDLL.


USE_NTDLL

See USE_CRTDLL.


USE_PDB

Use the USE_PDB macro if your debug symbolic files will use a VC4 PDB. This is the default in the Windows XP build environment.

To use this macro, specify the following in your sources files:

USE_PDB=1

See Also

NTDEBUGTYPE


USE_STATIC_MFC

Use the USE_STATIC_MFC macro to statically link MFC into your program.

This macro is only necessary in cases when the standard MFC DLL is not available. In this case, specify USE_STATIC_MFC in your sources file. The Build utility will link MFC into your program statically instead of dynamically loading it from a DLL. This will make your binary much larger.

You should also use USE_STATIC_MFC if you wish to redefine or change the MFC code. This allows you to change whatever you wish, and retain everything else.

When using this macro, you cannot override classes. You cannot add new members. You cannot change arguments.

It is highly unlikely that you will need to use this macro.


USECXX_FLAG

The USECXX_FLAG macro enables you to go to a subdirectory that has all C files and compile them with the C++ compiler rather than the C compiler. (You might want to do this if you have decided to switch to C++.)

Rather than manually change all your file names to a.cpp, b.cpp, you can specify:

USECXX_FLAG=/Tp

This switch directs the compiler to use the C++ compiler rather than the C compiler to compile the specified subdirectory.


USER_C_FLAGS

Use the USER_C_FLAGS macro to specify flags that should only be sent to the C/C++ compiler.

Unlike C_DEFINES, USER_C_FLAGS is not sent to the RC compiler.


USER_INCLUDES

Use the USER_INCLUDES macro to specify header files that are created during the build process.

Normally, you use the INCLUDES macro in your sources file to indicate the location of your build headers.

There are times, however, when this macro will not be useful because some header files might not exist. For example, some header files are built as part of the build process.

Use the USER_INCLUDES macro to specify header files that are created during the build process. The Build utility will search for these header files, will not consider it an error if the files are not found and will not perform dependency checking on them.


Debugging Routines for Drivers

This section includes:

Overview of Debugging Routines

Kernel-Mode Debugging Routine Reference


Overview of Debugging Routines

Special debugging routines are available for both user-mode and kernel-mode drivers. By using these routines in your driver code, you can send messages to the debugger and set breakpoints to aid in debugging.

You should conditionally compile the debugging code in your driver by testing the DBG preprocessor flag. If you create your driver by running the Build utility from the Checked Build Environment or Checked 64-Bit Build Environment window, the DBG flag will equal 1. If you create your driver by running the Build utility from the Free Build Environment window, DBG will equal 0 (or will be undefined if neither wdm.h nor ntddk.h is included).

The following sections summarize the debugging routines:

User-Mode Debugging Routines

Kernel-Mode Debugging Routines

The Platform SDK provides complete information on the user-mode routines. See Kernel-Mode Debugging Routine Reference for complete information on the kernel-mode routines.


User-Mode Debugging Routines

User-mode drivers that include the windows.h header can use the debugging routines described below. For complete documentation of user-mode routines useful for debugging, see the Platform SDK.

Sending Output to the Debugger

OutputDebugString sends a null-terminated string to the debugger of the calling process. In a user-mode driver, OutputDebugString displays the string in the Debugger Command window. If a debugger is not running, this routine has no effect. OutputDebugString does not support the variable arguments of a printf formatted string.

The prototype for this routine is as follows:

VOID OutputDebugString(
   LPCTSTR lpOutputString
   );

Breaking Into the Debugger

A break routine causes an exception to occur in the current process, so that the calling thread can signal the debugger associated with the calling process. If no debugger is running, this usually results in the termination of the calling process.

When a user-mode program breaks into the debugger, execution pauses and the debugger is alerted.

To break into a debugger from a user-mode program, use the DebugBreak routine. Its prototype is as follows:

VOID DebugBreak(VOID);


Kernel-Mode Debugging Routines

Kernel-mode drivers can use the debugging routines summarized in this section. See Kernel-Mode Debugging Routines for complete documentation of the individual routines.

Routines named DbgXxx are kernel-mode routines that can be used in either free or checked drivers. Routines named KdXxx are kernel-mode macros that are defined only if the DBG flag is set. Therefore, the KdXxx routines are active only in a checked build of a driver. For more information on the build environments that allow you to create free and checked builds of a driver, see Setting Up the Build Environment.

Sending Output to the Debugger

DbgPrint displays output in the debugger window. This routine supports the basic printf format parameters. Only kernel-mode drivers can call DbgPrint.

DbgPrintEx is similar to DbgPrint, but it allows you to "tag" your messages. When running the debugger, you can let only messages with certain tags through. This allows you to view only those messages that you are interested in.

KdPrint and KdPrintEx are the checked versions of DbgPrint and DbgPrintEx.

Breaking Into the Debugger

When a kernel-mode program breaks into the debugger, the entire operating system freezes until the kernel debugger allows execution to resume. If no kernel debugger is present, this is treated as a bug check.

The DbgBreakPoint routine works in kernel-mode code, but otherwise is similar to the DebugBreak user-mode routine.

DbgBreakPointWithStatus also causes a break, but it additionally sends a 32-bit status code to the debugger.

KdBreakPoint and KdBreakPointWithStatus are the checked versions of these routines.

Conditionally Breaking Into the Debugger

Two conditional break routines are available for kernel-mode drivers. These routines test a logical expression. If the expression is false, execution halts and the debugger becomes active.

The ASSERT macro causes the debugger to display the failed expression and its location in the program. The ASSERTMSG macro is similar, but allows an additional message to be sent to the debugger.

These two macros take effect only if the code is compiled in the checked build environment and the resulting driver is then run on a checked Windows build. For more information on the build environments, see Setting Up the Build Environment. For more information on free and checked Windows builds, see The Checked Build of Windows.


Kernel-Mode Debugging Routine Reference

This section details routines used in kernel-mode debugging.

For a general summary of user-mode and kernel-mode debugging routines, see Overview of Debugging Routines.


DbgBreakPoint

DbgBreakPoint breaks into the kernel debugger.

VOID
NTAPI
  DbgBreakPoint(
    VOID
    );

Headers

Defined in ntddk.h and wdm.h. Include ntddk.h or wdm.h.

Comments

This routine can only be used in Windows 2000 and later.

The DbgBreakPoint routine is the kernel-mode equivalent of DebugBreak.

This routine raises an exception that is handled by the kernel debugger if one is installed; otherwise it is handled by the debug system. If no debugger is connected to the system, the exception can be handled in the standard way.

In kernel mode, a break exception that is not handled will cause a blue screen (bug check) to result. You can, however, connect a kernel-mode debugger to a hung target computer that has kernel debugging enabled. For more information, see the documentation in the Debugging Tools for Windows package.

See Also

DbgBreakPointWithStatus, KdBreakPoint, KdBreakPointWithStatus


DbgBreakPointWithStatus

DbgBreakPointWithStatus breaks into the kernel debugger and sends the value of Status to the debugger.

NTSYSAPI
VOID
NTAPI
  DbgBreakPointWithStatus(
    IN ULONG  Status
    );

Parameters

Status
Specifies a ULONG to be sent to the debugger (a status code, an address, etc.)

Headers

Defined in ntddk.h. Include ntddk.h.

Comments

This routine can only be used in Windows 2000 and later.

DbgBreakPointWithStatus is identical to DbgBreakPoint, except for the Status message.

On x86 machines, the Status parameter is stored in the eax register. On machines that have register calling conventions, Status is stored in the first argument register.

This routine raises an exception that is handled by the kernel debugger if one is installed; otherwise it is handled by the debug system. If no debugger is connected to the system, the exception can be handled in the standard way.

In kernel mode, a break exception that is not handled will cause a blue screen (bug check) to result. You can, however, connect a kernel-mode debugger to a hung target computer that has kernel debugging enabled. For more information, see the documentation in the Debugging Tools for Windows package.

See Also

DbgBreakPoint, KdBreakPoint, KdBreakPointWithStatus


DbgPrint

DbgPrint sends a string to the kernel debugger.

ULONG
  DbgPrint(
    IN PCHAR  Format,
    . . . .  [arguments]
    );

Parameters

Format
Pointer to the format string to print, as in printf. The Format string supports the printf-style formatting codes. However, the unicode format codes (%wc and %ws) can only be used at IRQL PASSIVE_LEVEL.
arguments
Specifies arguments for the format string, as in printf.

Return Value

If successful, DbgPrint returns the NTSTATUS code STATUS_SUCCESS; otherwise it returns the appropriate error code.

Headers

Defined in ntddk.h, wdm.h, and ndis.h. Include ntddk.h, wdm.h, or ndis.h.

Comments

This routine can only be used in Windows 2000 and later.

Only kernel-mode drivers can call the DbgPrint routine.

The formatted string is sent to the DbgPrint Buffer. The contents of this buffer are displayed immediately in the Debugger Command window, unless this display has been disabled by using the Global Flags Editor (gflags.exe).

If this display has been disabled, the contents of the DbgPrint Buffer can only be viewed by using the !dbgprint extension command. For details on debugger extensions, see the documentation in the Debugging Tools for Windows package.

The DbgPrint buffer can only hold 512 bytes of information.

See Also

DbgPrintEx, KdPrint, KdPrintEx


DbgPrintEx

DbgPrintEx sends a string to the kernel debugger if certain conditions are met.

ULONG
  DbgPrintEx(
    IN ULONG  ComponentId,
    IN ULONG  Level,
    IN PCHAR  Format,
    . . . .  [arguments]
    );

Parameters

ComponentId
Specifies the component calling this routine. This must be one of the component name filter IDs defined in the DDK header ntddk.h and the SDK header ntrtl.h. To avoid mixing your driver's output with the output of Windows components, you should use only the following values for ComponentId:

DPFLTR_IHVDRIVER_ID

DPFLTR_IHVVIDEO_ID

DPFLTR_IHVAUDIO_ID

DPFLTR_IHVNETWORK_ID

DPFLTR_IHVSTREAMING_ID

DPFLTR_IHVBUS_ID

Level
Specifies the severity of the message being sent. This can be any 32-bit integer. Values between 0 and 31 (inclusive) are treated differently than values between 32 and 0xFFFFFFFF. For details, see the Comments section following.
Format
Pointer to the format string to print, as in printf. The Format string supports the printf-style formatting codes. However, the Unicode format codes (%wc and %ws) can only be used at IRQL = PASSIVE_LEVEL.
arguments
Specifies arguments for the format string, as in printf.

Return Value

If successful, DbgPrintEx returns the NTSTATUS code STATUS_SUCCESS; otherwise, it returns the appropriate error code.

Headers

Routine defined in ntddk.h and ndis.h; component filter IDs defined in ntddk.h. Include ntddk.h.

Comments

This routine can only be used in Windows XP and later.

Only kernel-mode drivers can call the DbgPrintEx routine.

DbgPrintEx will either pass the specified string to the kernel debugger or do nothing at all, depending on the values of ComponentId, Level, and the corresponding component filter masks.

Each component has a separate filter mask. The components which are of interest to driver writers are IHVDRIVER, IHVVIDEO, IHVAUDIO, IHVNETWORK, IHVSTREAMING, and IHVBUS.

There are two ways to set a component filter mask:

  • Create or open the registry key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Debug Print Filter. Under this key, create a value with the name of one of these components, in uppercase. Set it equal to the DWORD value that you wish to use as the component filter mask.
  • From the kernel debugger, enter the desired component filter mask as the value of the symbol Kd_XXXX_Mask, where XXXX is the component name. This can be done using the ed command in WinDbg or KD.

Filter masks stored in the registry take effect during boot. Filter masks created by the debugger take effect immediately, and last until Windows is rebooted. A value set in the registry can be overridden by the debugger, but the component filter mask will return to the value specified in the registry if the system is rebooted.

Here is an example of how component filter masks can be set. Suppose that before the last boot, you created two values in the Debug Print Filter key: IHVVIDEO, with a value equal to DWORD 0x2, and IHVBUS, equal to DWORD 0x7FF. Now you issue the following commands in the kernel debugger:

kd> ed Kd_IHVVIDEO_Mask 0x8
kd> ed Kd_IHVAUDIO_Mask 0x7

At this point, the IHVVIDEO component has a filter mask of 0x8, the IHVAUDIO component has a filter mask of 0x7, and the IHVBUS component has a filter mask of 0x7FF.

There is also a system-wide mask called WIN2000. This is equal to one by default, though it can be changed through the registry or the debugger like all other components. When filtering is performed, each component filter mask is first ORed with the WIN2000 mask. So in this example, the IHVVIDEO mask is effectively equal to 0x9, and components whose filter masks have not been set at all (for instance, IHVSTREAMING) will have a filter mask of one.

When DbgPrintEx is called in kernel-mode code, Windows compares the message importance specified by Level with the filter mask of the component specified by ComponentId. This comparison is performed as follows:

  • If Level is equal to a number between 0 and 31, inclusive, it is interpreted as a bit shift. If this bit is set in the component filter mask, the message is sent to the debugger.
  • If Level is a number between 32 and 0xFFFFFFFF inclusive, it is treated as an actual DWORD value. Level is ANDed with the component filter mask; if this result is nonzero, the message is sent to the debugger.

The following constants can be useful for setting the value of Level. They are defined in the DDK header ntddk.h and the SDK header ntrtl.h:

#define   DPFLTR_ERROR_LEVEL     0
#define   DPFLTR_WARNING_LEVEL   1
#define   DPFLTR_TRACE_LEVEL     2
#define   DPFLTR_INFO_LEVEL      3
#define   DPFLTR_MASK    0x8000000

To make your driver compatible with the way Windows uses message levels, you should only set Level equal to DPFLTR_ERROR_LEVEL when a serious error occurs. (Since the WIN2000 system-wide filter is usually equal to one, these messages will be seen by anyone performing kernel debugging.) The warning, trace, and information levels should be used in the appropriate situations. Other bits can be freely used for any purposes that you find useful This allows you to have a wide variety of message types that can be selectively seen or hidden.

Continuing the example from the beginning of this section, suppose that the following function calls occur in your driver:

DbgPrintEx( DPFLTR_IHVVIDEO_ID,  DPFLTR_INFO_LEVEL,   "First message.\n");
DbgPrintEx( DPFLTR_IHVAUDIO_ID,  7,                   "Second message.\n");
DbgPrintEx( DPFLTR_IHVBUS_ID,    DPFLTR_MASK & 0x10,  "Third message.\n");

The first message will be transmitted, because DPFLTR_INFO_LEVEL is equal to 3; it is therefore treated as a bit shift, resulting in 0x8. This value is then ANDed with the effective IHVVIDEO component filter mask of 0x9, giving a nonzero result.

The second message will not be transmitted, because the Level value of 7 is treated as a bit shift, resulting in 0x80. This is then ANDed with the IHVAUDIO component filter mask of 0x7, giving a result of zero.

The third message will be transmitted, because DPFLTR_MASK & 0x10 is greater than 31, and is therefore treated as the literal DWORD 0x80000010. This is then ANDed with the IHVBUS component filter mask of 0x7FF, giving a nonzero result.

When the filter allows a message to be transmitted, the formatted string is sent to the DbgPrint Buffer. The contents of this buffer are displayed immediately in the Debugger Command window, unless this display has been disabled by using the Global Flags Editor (gflags.exe).

If this display has been disabled, the contents of the DbgPrint Buffer can only be viewed by using the !dbgprint extension command. For details on debugger extensions, see the documentation in the Debugging Tools for Windows package.

The DbgPrint buffer can only hold 512 bytes of information.

See Also

DbgPrint, KdPrint, KdPrintEx


KdBreakPoint

KdBreakPoint breaks into the kernel debugger.

VOID
NTAPI
  KdBreakPoint(
    VOID
    );

Headers

Defined in ntddk.h and wdm.h. Include ntddk.h or wdm.h.

Comments

This routine can only be used in Windows 2000 and later.

The KdBreakPoint routine is the kernel-mode equivalent of DebugBreak. KdBreakPoint is identical to DbgBreakPoint in code that is compiled in a checked build environment. It has no effect if compiled in a free build environment.

This routine raises an exception that is handled by the kernel debugger if one is installed; otherwise it is handled by the debug system. If no debugger is connected to the system, the exception can be handled in the standard way.

In kernel mode, a break exception that is not handled will cause a blue screen (bug check) to result. You can, however, connect a kernel-mode debugger to a hung target computer that has kernel debugging enabled. For more information, see the documentation in the Debugging Tools for Windows package.

See Also

DbgBreakPoint, DbgBreakPointWithStatus, KdBreakPointWithStatus


KdBreakPointWithStatus

KdBreakPointWithStatus breaks into the kernel debugger and sends the value of Status to the debugger.

NTSYSAPI
VOID
NTAPI
  KdBreakPointWithStatus(
    IN ULONG  Status
    );

Parameters

Status
Specifies a ULONG to be sent to the debugger (a status code, an address, etc.).

Headers

Defined in ntddk.h. Include ntddk.h.

Comments

This routine can only be used in Windows 2000 and later.

The KdBreakPointWithStatus routine is identical to DbgBreakPointWithStatus in code that is compiled in a checked build environment. This routine has no effect if compiled in a free build environment.

On x86 machines, the Status parameter is stored in the eax register. On machines that have register calling conventions, Status is stored in the first argument register.

This routine raises an exception that is handled by the kernel debugger if one is installed; otherwise it is handled by the debug system. If no debugger is connected to the system, the exception can be handled in the standard way.

In kernel mode, a break exception that is not handled will cause a blue screen (bug check) to result. You can, however, connect a kernel-mode debugger to a hung target computer that has kernel debugging enabled. For more information, see the documentation in the Debugging Tools for Windows package.

See Also

DbgBreakPoint, DbgBreakPointWithStatus, KdBreakPoint


KdPrint

KdPrint sends a string to the kernel debugger.

ULONG
  KdPrint ( (
    IN PCHAR  Format,
    . . . .  [arguments]
    ) ) ;

Parameters

Format
Pointer to the format string to print, as in printf. The Format string supports the printf-style formatting codes. However, the unicode format codes (%wc and %ws) can only be used at IRQL PASSIVE_LEVEL.
arguments
Specifies arguments for the format string, as in printf.

Return Value

If successful, KdPrint returns the NTSTATUS code STATUS_SUCCESS; otherwise it returns the appropriate error code.

Headers

Defined in ntddk.h, wdm.h, and ndis.h. Include ntddk.h, wdm.h, or ndis.h.

Comments

This routine can only be used in Windows 2000 and later.

The KdPrint routine is identical to DbgPrint in code that is compiled in a checked build environment. This routine has no effect if compiled in a free build environment. Only kernel-mode drivers can call the KdPrint routine.

A call to this macro requires double parentheses.

The formatted string is sent to the DbgPrint Buffer. The contents of this buffer are displayed immediately in the Debugger Command window, unless this display has been disabled by using the Global Flags Editor (gflags.exe).

If this display has been disabled, the contents of the DbgPrint Buffer can only be viewed by using the !dbgprint extension command. For details on debugger extensions, see the documentation in the Debugging Tools for Windows package.

The DbgPrint buffer can only hold 512 bytes of information.

See Also

DbgPrint, DbgPrintEx, KdPrintEx


KdPrintEx

KdPrintEx sends a string to the kernel debugger if certain conditions are met.

ULONG
  KdPrintEx ( (
    IN ULONG  ComponentId,
    IN ULONG  Level,
    IN PCHAR  Format,
    . . . .  [arguments]
    ) ) ;

Parameters

ComponentId
Specifies the component calling this routine. This must be one of the component name filter IDs defined in the DDK header ntddk.h and the SDK header ntrtl.h. To avoid mixing your driver's output with the output of Windows components, you should use only the following values for ComponentId:

DPFLTR_IHVDRIVER_ID

DPFLTR_IHVVIDEO_ID

DPFLTR_IHVAUDIO_ID

DPFLTR_IHVNETWORK_ID

DPFLTR_IHVSTREAMING_ID

DPFLTR_IHVBUS_ID

Level
Specifies the severity of this message. This can be any 32-bit integer. Values between 0 and 31 (inclusive) are treated differently than values between 32 and 0xFFFFFFFF. For details, see the Comments section following.
Format
Pointer to the format string to print, as in printf. The Format string supports the printf-style formatting codes. However, the Unicode format codes (%wc and %ws) can only be used at IRQL = PASSIVE_LEVEL.
arguments
Specifies arguments for the format string, as in printf.

Return Value

If successful, KdPrintEx returns the NTSTATUS code STATUS_SUCCESS; otherwise, it returns the appropriate error code.

Headers

Routine defined in ntddk.h and ndis.h; component filter IDs defined in ntddk.h. Include ntddk.h.

Comments

This routine can only be used in Windows XP and later.

The KdPrintEx routine is identical to DbgPrintEx in code that is compiled in a checked build environment. This routine has no effect if compiled in a free build environment. Only kernel-mode drivers can call the KdPrintEx routine.

A call to this macro requires double parentheses.

KdPrintEx will either pass the specified string to the kernel debugger or do nothing at all, depending on the values of ComponentId, Level, and the corresponding component filter masks.

Each component has a separate filter mask. The components which are of interest to driver writers are IHVDRIVER, IHVVIDEO, IHVAUDIO, IHVNETWORK, IHVSTREAMING, and IHVBUS.

There are two ways to set a component filter mask:

  • Create or open the registry key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Debug Print Filter. Under this key, create a value with the name of one of these components, in uppercase. Set it equal to the DWORD value that you wish to use as the component filter mask.
  • From the kernel debugger, enter the desired component filter mask as the value of the symbol Kd_XXXX_Mask, where XXXX is the component name. This can be done using the ed command in WinDbg or KD.

Filter masks stored in the registry take effect during boot. Filter masks created by the debugger take effect immediately, and last until Windows is rebooted. A value set in the registry can be overridden by the debugger, but the component filter mask will return to the value specified in the registry if the system is rebooted.

Here is an example of how component filter masks can be set. Suppose that before the last boot, you created two values in the Debug Print Filter key: IHVVIDEO, with a value equal to DWORD 0x2, and IHVBUS, equal to DWORD 0x7FF. Now you issue the following commands in the kernel debugger:

kd> ed Kd_IHVVIDEO_Mask 0x8
kd> ed Kd_IHVAUDIO_Mask 0x7

At this point, the IHVVIDEO component has a filter mask of 0x8, the IHVAUDIO component has a filter mask of 0x7, and the IHVBUS component has a filter mask of 0x7FF.

There is also a system-wide mask called WIN2000. This is equal to one by default, though it can be changed through the registry or the debugger like all other components. When filtering is performed, each component filter mask is first ORed with the WIN2000 mask. So in this example, the IHVVIDEO mask is effectively equal to 0x9, and components whose filter mask have not been set at all (for instance, IHVSTREAMING) will have a filter mask of one.

When KdPrintEx is called in kernel-mode code, Windows compares the message importance specified by Level with the filter mask of the component specified by ComponentId. This comparison is performed as follows:

  • If Level is equal to a number between 0 and 31, inclusive, it is interpreted as a bit shift. If this bit is set in the component filter mask, the message is sent to the debugger.
  • If Level is a number between 32 and 0xFFFFFFFF, inclusive, it is treated as an actual DWORD value. Level is ANDed with the component filter mask; if this result is nonzero, the message is sent to the debugger.

The following constants can be useful for setting the value of Level. They are defined in the DDK header ntddk.h and the SDK header ntrtl.h:

#define   DPFLTR_ERROR_LEVEL     0
#define   DPFLTR_WARNING_LEVEL   1
#define   DPFLTR_TRACE_LEVEL     2
#define   DPFLTR_INFO_LEVEL      3
#define   DPFLTR_MASK    0x8000000

To make your driver compatible with the way Windows uses message levels, you should only set Level equal to DPFLTR_ERROR_LEVEL when a serious error occurs. (Since the WIN2000 system-wide filter is usually equal to one, these messages will be seen by anyone performing kernel debugging.) The warning, trace, and information levels should be used in the appropriate situations. Other bits can be freely used for any purposes which you find useful; this allows you to have a wide variety of message types which can be selectively seen or hidden.

Continuing the example from above, suppose that the following function calls occur in your driver:

KdPrintEx( DPFLTR_IHVVIDEO_ID,  DPFLTR_INFO_LEVEL,   "First message.\n");
KdPrintEx( DPFLTR_IHVAUDIO_ID,  7,                   "Second message.\n");
KdPrintEx( DPFLTR_IHVBUS_ID,    DPFLTR_MASK & 0x10,  "Third message.\n");

The first message will be transmitted, because DPFLTR_INFO_LEVEL is equal to 3. It is therefore treated as a bit shift, resulting in 0x8. This value is then ANDed with the effective IHVVIDEO component filter mask of 0x9, giving a nonzero result.

The second message will not be transmitted, because the Level value of 7 is treated as a bit shift, resulting in 0x80. This is then ANDed with the IHVAUDIO component filter mask of 0x7, giving a result of zero.

The third message will be transmitted, because DPFLTR_MASK & 0x10 is greater than 31, and is therefore treated as the literal DWORD 0x80000010. This is then ANDed with the IHVBUS component filter mask of 0x7FF, giving a nonzero result.

When the filter allows a message to be transmitted, the formatted string is sent to the DbgPrint Buffer. The contents of this buffer are displayed immediately in the Debugger Command window, unless this display has been disabled by using the Global Flags Editor (gflags.exe).

If this display has been disabled, the contents of the DbgPrint Buffer can only be viewed by using the !dbgprint extension command. For details on debugger extensions, see the documentation in the Debugging Tools for Windows package.

The DbgPrint buffer can only hold 512 bytes of information.

See Also

DbgPrint, DbgPrintEx, KdPrint


ASSERT

ASSERT tests an expression. If the expression is false, it breaks into the kernel debugger.

VOID
  ASSERT(
    Expression
    );

Parameters

Expression
Specifies any logical expression.

Headers

Defined in ntddk.h and wdm.h. Include ntddk.h or wdm.h.

Comments

This routine can only be used in Windows 2000 and later.

This macro will only be included in your binary if your code is compiled in a checked build environment. The resulting binaries will only execute this ASSERT if they are run on the checked build of Windows.

If Expression evaluates to TRUE, this routine has no effect.

If Expression evaluates to FALSE, a message will be displayed in the Debugger Command window. The message contains the source-code string of Expression, as well as the path of the source-code file and the line number in that file of the instruction that called the macro. In this event, ASSERT can be ignored and the process or thread in which ASSERT occurred can be terminated. Alternatively, the debugger can be used to analyze the situation or to edit memory. If ASSERT is ignored, execution continues as if the g command was entered.

See Also

ASSERTMSG


ASSERTMSG

ASSERTMSG tests an expression. If the expression is false, it breaks into the kernel debugger and sends it the specified message.

VOID
  ASSERTMSG(
    IN PCHAR  Message,
    Expression
    );

Parameters

Message
Specifies the null-delimited string to be displayed by the debugger.
Expression
Specifies any logical expression.

Headers

Defined in ntddk.h and wdm.h. Include ntddk.h or wdm.h.

Comments

This routine can only be used in Windows 2000 and later.

The ASSERTMSG routine is identical to ASSERT, except that it sends an additional message to the debugger.

This macro will only be included in your binary if your code is compiled in a checked build environment. The resulting binaries will only execute this ASSERT if they are run on the checked build of Windows.

If Expression evaluates to TRUE, this routine has no effect.

If Expression evaluates to FALSE, a message will be displayed in the Debugger Command window. The message contains the source-code string of Expression, as well as the path of the source-code file and the line number in that file of the instruction that called the macro. In this event, ASSERTMSG can be ignored and the process or thread in which ASSERTMSG occurred can be terminated. Alternatively, the debugger can be used to analyze the situation or to edit memory. If ASSERTMSG is ignored, execution continues as if the g command was entered.

See Also

ASSERT


Testing and Debugging Tools

This section includes:

Driver Verifier

Debuggers

DevCtl

Disabler


Driver Verifier

Driver Verifier is a tool that can monitor kernel-mode drivers and graphics drivers to verify that they are not making illegal function calls or causing system corruption. It can perform a large number of checks on these drivers, as well as subject them to a variety of stresses and tests to flush out improper behavior.

Driver Verifier can be used on any number of drivers simultaneously, or on one driver at a time. It has various options that can be enabled or disabled. This allows you to put a driver through heavy stresses or through a more streamlined test.

The following sections explain the workings of Driver Verifier:

  • Driver Verifier Options describes each of the actions of Driver Verifier in detail. This section applies to all kernel-mode drivers other than graphics drivers.
  • Driver Verifier Options for Graphics Drivers describes the actions of Driver Verifier on kernel-mode graphics drivers that use the Graphics Driver Interface (GDI).
  • Activating and Monitoring Driver Verifier explains how to start Driver Verifier, how to choose which actions will be used, and how to choose which drivers will be verified. It also explains how to use the Driver Verifier Manager graphical interface to monitor the behavior of drivers being verified.

Driver Verifier works on both the free and checked builds of Microsoft® Windows®. It is available in Windows 2000 and later, but not in Windows 98/Me.


Driver Verifier Options

The following sections describe the different powers of Driver Verifier:

  • Automatic Checks

    These checks are always performed on a driver that is being verified, regardless of which options have been selected. If the driver uses memory at an improper IRQL, improperly calls or releases spin locks and memory allocations, improperly switches stacks, or frees memory pool without first removing timers, Driver Verifier will detect this behavior. When the driver is unloaded, Driver Verifier will check to see that it has properly released its resources.

  • Special Memory Pool

    When this option is active, Driver Verifier allocates most of the driver's memory requests from a special pool. This special pool is monitored for memory overruns, memory underruns, and memory that is accessed after it is freed.

  • Forcing IRQL Checking

    When this option is active, Driver Verifier places extreme memory pressure on the driver by invalidating pageable code. If the driver attempts to access paged memory at the wrong IRQL or while holding a spin lock, Driver Verifier detects this behavior.

  • Low Resources Simulation

    When this option is active, Driver Verifier randomly fails pool allocation requests and other resource requests. By injecting these allocation faults into the system, Driver Verifier tests the driver's ability to cope with a low-resource situation.

  • Memory Pool Tracking

    When this option is active, Driver Verifier checks to see if the driver has freed all its memory allocations when it is unloaded. This reveals memory leaks.

  • I/O Verification

    When this option is active, Driver Verifier allocates the driver's IRPs from a special pool, and monitors the driver's I/O handling. This detects illegal or inconsistent use of I/O routines.

  • DMA Verification

    (Microsoft® Windows® XP only) When this option is active, Driver Verifier monitors the driver's use of DMA routines. This detects improper use of DMA buffers, adapters, and map registers.

  • Deadlock Detection

    (Windows XP only) When this option is active, Driver Verifier monitors the driver's use of spin locks, mutexes, and fast mutexes. This will detect if the driver's code has the potential for causing a deadlock at some point.

  • SCSI Verification

    (Windows XP only) When this option is active, Driver Verifier will monitor a SCSI miniport driver for improper use of exported SCSI port routines, excessive delays, and improper handling of SCSI requests.

Driver Verifier can verify any number of drivers. However, the Special Memory Pool and I/O Verification options will be more effective when used on one driver at a time.


Automatic Checks

Driver Verifier performs the following actions whenever it is verifying one or more drivers. These actions are not affected by enabling or disabling any of Driver Verifier's options.

Monitoring IRQL and Memory Routines

Driver Verifier monitors the selected driver for the following forbidden actions:

  • Raising IRQL by calling KeLowerIrql
  • Lowering IRQL by calling KeRaiseIrql
  • Requesting a size zero memory allocation
  • Allocating or freeing paged pool at an IRQL above APC_LEVEL
  • Allocating or freeing nonpaged pool at an IRQL above DISPATCH_LEVEL
  • Trying to free an address that was not returned from a previous allocation
  • Trying to free an address that was already freed
  • Acquiring or releasing a fast mutex at an IRQL above APC_LEVEL
  • Acquiring or releasing a spin lock at an IRQL other than DISPATCH_LEVEL
  • Double-releasing a spin lock.
  • Specifying an illegal or random (uninitialized) parameter to any one of several APIs.
  • Marking an allocation request MUST_SUCCEED. No such requests are ever permissible.

If Driver Verifier is not active, these violations might not cause an immediate system crash in all cases. Driver Verifier monitors the driver's behavior and issues bug check 0xC4 if any of these violations occur. See Bug Check 0xC4 for a list of the bug check parameters.

Monitoring Stack Switching

Driver Verifier monitors stack usage by the driver being verified. If the driver switches its stack, and the new stack is neither a thread stack nor a DPC stack, then a bug check is issued. (This will be bug check 0xC4 with the first parameter equal to 0x90.) The stack displayed by the KB debugger command will usually reveal the driver that performed this operation.

Checking Freed Pool for Timers

Driver Verifier examines all memory pool freed by the driver being verified. If any timers remain in this pool, bug check 0xC7 is issued. (Forgotten timers can eventually lead to system crashes that are notoriously difficult to account for.)

Checking on Driver Unload

After a driver that is being verified unloads, Driver Verifier performs several checks to make sure that the driver has cleaned up.

In particular, Driver Verifier looks for:

  • Undeleted timers
  • Pending deferred procedure calls (DPCs)
  • Undeleted lookaside lists
  • Undeleted worker threads
  • Undeleted queues
  • Other similar resources

Problems such as these can potentially cause system bug checks to be issued a while after the driver unloads, and the cause of these bug checks can be hard to determine. When Driver Verifier is active, such violations will result in bug check 0xC7 being issued immediately after the driver is unloaded. See Bug Check 0xC7 for a list of the bug check parameters.

Graphics Drivers

These automatic checks are not performed when verifying a graphics driver.


Special Memory Pool

Memory corruption is a common driver problem. Driver errors can result in crashes long after the errors are made. The most common of these errors is accessing memory that has already been freed, and allocating n bytes and then accessing n+1 bytes.

To detect memory corruption, Driver Verifier can allocate driver memory from a special pool and monitor that pool for incorrect access.

Two alignments of the special pool are available. The Verify End alignment is better at detecting access overruns, and the Verify Start alignment is better at detecting access underruns. (Note that the vast majority of memory corruptions are due to overruns, not underruns.)

When Special Memory Pool is active and Verify End has been selected, each memory allocation requested by the driver is placed on a separate page. The highest possible address that allows the allocation to fit on the page is returned, so that the memory is aligned with the end of the page. The previous portion of the page is written with special patterns. The previous page and the next page are marked inaccessible.

If the driver attempts to access memory after the end of the allocation, Driver Verifier will detect this immediately, and will issue bug check 0xCD. If the driver writes in the memory prior to the beginning of the buffer, this will (presumably) alter the patterns. When the buffer is freed, Driver Verifier will detect the alteration and issue bug check 0xC1.

If the driver reads or writes to the buffer after freeing it, Driver Verifier will issue bug check 0xCC.

When Verify Start is selected, the memory buffer is aligned with the beginning of the page. With this setting, underruns cause an immediate bug check and overruns cause a bug check when the memory is freed. This option is otherwise identical to the Verify End option.

Verify End is the default alignment, as overrun errors are much more common in drivers than underrun errors.

An individual memory allocation can override these settings and choose its alignment by calling ExAllocatePoolWithTagPriority with the Priority parameter set to XxxSpecialPoolOverrun or XxxSpecialPoolUnderrun. (This routine cannot activate or deactivate the special pool, or request the special pool for a memory allocation, which would otherwise be allocated from normal pool. Only the alignment can be controlled from this routine.)

Pool Tags

Driver Verifier will assign the special pool to the drivers that have been selected for verification.

Another way to use the special pool is to assign it to memory pools that have been marked with a specific pool tag. This is done by using the Global Flags utility rather than the Verifier utility.

It is permissible to request special pools though Driver Verifier and the Global Flags Utility at the same time. If this is done, Windows will attempt to use the special pool for all pools that have the specified tags and all pool allocation requests from the specified drivers.

Special Pool Efficiency

Each allocation from the special pool uses one page of nonpageable memory and two pages of virtual address space. If the pool is exhausted, memory is allocated in the standard way until the special pool becomes available again. Thus, it is not recommended that multiple drivers be verified at the same time if Special Memory Pool is in effect.

A single driver that makes a large number of small memory requests can also deplete this pool. If this is occurring, it may be preferable to assign pool tags to the driver's memory allocations and dedicate the special pool to one pool tag at a time.

The size of the special pool increases with the amount of physical memory on the system; ideally this should be at least 1 Gigabyte (GB). On x86 machines, booting without the /3GB switch is also preferred, as virtual (in addition to physical) space is consumed. Increasing the pagefile minimum/maximum quantities (by a factor of two or three) is also a good idea.

To be sure that all of a driver's allocations are being tested, stressing the driver over long periods of time is recommended.

Monitoring the Special Pool

Statistics relating to pool allocations can be monitored. These can be displayed by the Driver Verifier Manager graphical interface, the verifier.exe command line, or in a log file. See Monitoring Global Counters for details.

If the Pool Allocations Succeeded in Special Pool counter is equal to the Pool Allocations Succeeded counter, then the special pool has been sufficient to cover all memory allocations. If the former counter is lower than the latter, then the special pool has been exhausted at least once.

These counters do not track allocations whose size is one page or larger, since the special pool is not applicable to them.

If Special Memory Pool is enabled, but less than 95% of all pool allocations have been assigned from the special pool, a warning will appear in the Driver Verifier Manager graphical interface. In Windows 2000, this warning will appear on the Driver Status screen. In Windows XP, this warning will appear on the Global Counters screen. If this occurs, you should verify a shorter list of drivers, verify individual pools by pool tag, or add more physical memory to your system.

The kernel debugger extension !verifier can also be used to monitor special pool use. It presents similar information to that of Driver Verifier Manager. For information about debugger extensions, see the documentation in the Debugging Tools for Windows package.

Activating This Option

The Special Memory Pool option can be activated for one or more drivers by using the Driver Verifier Manager graphical interface or the verifier.exe command line. This activation will take effect after the next boot. See Selecting Driver Verifier Options for details.

This option can also be turned on and off without an intervening reboot. See Using Volatile Settings for details.

Activating the Special Memory Pool for tagged memory pools is done by using the Global Flags utility. This utility is also used to set the Verify Start and Verify End alignments, regardless of whether the special pool is being used for drivers or for pool tags.

Graphics Drivers

See Special Memory Pool for Graphics Drivers for details on how this option affects display drivers and kernel-mode printer drivers.


Forcing IRQL Checking

Although kernel-mode drivers are forbidden to access pageable memory at a high IRQL or while holding a spin lock, such an action might not be noticed if the page has not actually been trimmed.

When Forcing IRQL Checking is enabled, Driver Verifier will provide extreme memory pressure on the selected driver. Whenever a driver being verified requests a spin lock, calls KeSynchronizeExecution, or raises the IRQL to DISPATCH_LEVEL or higher, all of the driver's pageable code and data (as well as system pageable pool, code, and data) are marked as trimmed. If the driver attempts to access any of this memory, Driver Verifier issues a bug check.

This memory pressure will not directly affect drivers that are not selected for verification, since other drivers' IRQL raises will not cause this action. However, when a driver that is being verified raises the IRQL, Driver Verifier trims pages that can be used by drivers that are not being verified. Thus errors by drivers that are not being verified might occasionally be caught when this option is active.

Monitoring IRQL Raises and Spin Locks

The number of IRQL raises, spin locks, and calls to KeSynchronizeExecution made by drivers being verified can be monitored. The number of pageable memory trims forced by Driver Verifier can also be monitored. These statistics can be displayed by the Driver Verifier Manager graphical interface, the verifier.exe command line, or in a log file. See Monitoring Global Counters for details.

The kernel debugger extension !verifier can also be used to monitor these statistics. It presents similar information to that of Driver Verifier Manager. In addition, in Windows XP, the !verifier 0x8 extension will display a log of recent IRQL changes made by drivers being verified. For information about debugger extensions, see the documentation in the Debugging Tools for Windows package.

Activating This Option

The Forcing IRQL Checking option can be activated by using the Driver Verifier Manager graphical interface or the verifier.exe command line. This activation will take effect after the next boot. See Selecting Driver Verifier Options for details.

This option can also be turned on and off without an intervening reboot. See Using Volatile Settings for details.

Graphics Drivers

The Forcing IRQL Checking option is not used for graphics drivers. If selected, it has no effect.


Low Resources Simulation

When Low Resources Simulation is enabled, Driver Verifier will cause a random selection of the driver's memory allocations to fail. This tests the driver's ability to react properly to low-memory and other low-resource conditions.

To accurately simulate a low-memory condition, these allocation faults are not injected until seven minutes after system startup. Therefore, any driver errors that are exposed by this action should be treated as legitimate run-time problems, not as unrealistic scenarios.

Driver Verifier can verify selected drivers or all drivers at the same time.

Monitoring the Low Resources Simulation

The number of times Driver Verifier deliberately fails resource allocations can be monitored. This statistic can be displayed by the Driver Verifier Manager graphical interface, the verifier.exe command line, or in a log file. See Monitoring Global Counters for details.

The kernel debugger extension !verifier can also be used to monitor this statistic. It presents similar information to that of Driver Verifier Manager. In addition, in Windows XP, the !verifier 0x4 extension will display a log of faults injected by Driver Verifier. For information about debugger extensions, see the documentation in the Debugging Tools for Windows package.

Activating This Option

The Low Resources Simulation option can be activated by using the Driver Verifier Manager graphical interface or the verifier.exe command line. This activation will take effect after the next boot. See Selecting Driver Verifier Options for details.

This option can also be turned on and off without an intervening reboot. See Using Volatile Settings for details.

Graphics Drivers

See Low Resources Simulation for Graphics Drivers for details on how this option affects display drivers and kernel-mode printer drivers.


Memory Pool Tracking

Memory Pool Tracking monitors the memory allocations made by the driver. At the time that the driver is unloaded, Driver Verifier ensures that all allocations made by the driver have been freed.

Unfreed memory allocations (also called memory leaks) are a common cause of lowered operating system performance. These can fragment the system pools and eventually cause system crashes.

When this option is active, Driver Verifier will issue bug check 0xC4 (with Parameter 1 equal to 0x60) if a driver unloads without freeing all its allocations.

If Driver Verifier issues this bug check with Parameter 1 equal to 0x51, 0x52, 0x53, 0x54, or 0x59, the driver has written to memory outside of its allocations. In this case, you should enable Special Memory Pool to locate the source of the error.

See Bug Check 0xC4 for a list of the bug check parameters.

Monitoring Memory Pool Tracking

Memory pool allocation statistics can be monitored separately for each driver being verified. These statistics can be displayed by the Driver Verifier Manager graphical interface, the verifier.exe command line, or in a log file. See Monitoring Individual Counters for details.

The kernel debugger extension !verifier 0x3 can be used to locate outstanding memory allocations after the driver is unloaded, or to track the current allocations while the driver is running. This extension also shows the pool tag, the size of the pool, and the address of the allocator for each allocation. For information about debugger extensions, see the documentation in the Debugging Tools for Windows package.

Activating This Option

The Memory Pool Tracking option can be activated by using the Driver Verifier Manager graphical interface or the verifier.exe command line. This activation will take effect after the next boot. See Selecting Driver Verifier Options for details.

Graphics Drivers

The Memory Pool Tracking option is not used for graphics drivers. If selected, it has no effect.


I/O Verification

Driver Verifier has three levels of I/O Verification:

  • Level 1 I/O Verification is always active whenever I/O Verification is selected in Windows 2000 or in Windows XP.
  • Level 2 I/O Verification is always active whenever I/O Verification is selected in Windows XP. In Windows 2000, I/O Verification can be configured to include both levels, or just the Level 1 tests.
  • Enhanced I/O Verification can be activated separately from the basic two I/O Verification levels in Windows XP. It is not available in Windows 2000.

The effects of each level will be described separately.

Level 1 I/O Verification

When Level 1 I/O Verification is enabled, all IRPs obtained through IoAllocateIrp are allocated from a special pool and their use is tracked.

Additionally, Driver Verifier checks for invalid I/O calls, including:

  • Attempts to free an IRP whose type is not IO_TYPE_IRP
  • Passes of invalid device objects to IoCallDriver
  • Passes of an IRP to IoCompleteRequest that contains invalid status or that still has a cancel routine set
  • Changes to the IRQL across a call to the driver dispatch routine
  • Attempts to free an IRP that remains associated with a thread
  • Passes of a device object to IoInitializeTimer that already contains an initialized timer
  • Passes of an invalid buffer to IoBuildAsynchronousFsdRequest or IoBuildDeviceIoControlRequest
  • Passes of an I/O status block to an IRP, when this I/O status block is allocated on a stack that has unwound too far
  • Passes of an event object to an IRP, when this event object is allocated on a stack that has unwound too far

Because the special IRP pool is of limited size, I/O Verification is most effective when it is only used on one driver at a time.

I/O Verification Level 1 failures cause bug check 0xC9 to be issued. The first parameter of this bug check indicates what violation has occurred. See Bug Check 0xC9 for a full parameter listing.

Level 2 I/O Verification

I/O Verification Level 2 errors are displayed in different ways: on the blue screen, in a crash dump file, and in a kernel debugger.

On the blue screen, these errors are noted by the message IO SYSTEM VERIFICATION ERROR and the string WDM DRIVER ERROR XXX, where XXX is an I/O error code.

In a crash dump file, these errors are noted by the message BugCheck 0xC9 (DRIVER_VERIFIER_IOMANAGER_VIOLATION), along with the I/O error code. In this case, the I/O error code appears as the first parameter of the bug check 0xC9.

In a kernel debugger (KD or WinDbg), these errors are noted by the message WDM DRIVER ERROR and a descriptive text string. When the kernel debugger is active, it is possible to ignore the Level 2 errors and resume system operation. (This is not possible with any other bug checks.)

The blue screen, the crash dump file, and the kernel debugger each display additional information as well. For a full description of all I/O Verification Level 2 error messages, see Bug Check 0xC9 .

Enhanced I/O Verification

This option is only available in Windows XP and later versions.

The Enhanced I/O Verification option includes some new parameter verifications, as well as some new stresses and tests.

New parameter verifications include:

  • Monitoring all IRPs for correct use of IoMarkPending. (Drivers should return STATUS_PENDING if and only if they have called IoMarkPending.)
  • Monitoring the use of IoDeleteDevice, to catch double-deletions and inappropriate detaching and deleting of device objects.
  • Unwinding all IoSkipCurrentIrpStackLocation calls.

New stresses and tests include:

  • Scrambling the order of enumerated devices, to ensure that Plug and Play (PnP) drivers don't make assumptions about the device start order.
  • Adjusting the status of PnP and Power IRPs when they complete, to catch drivers that return an incorrect status from their dispatch routines.
  • Sending bogus Power IRPs to test for driver code path bugs.
  • Sending bogus WMI IRPs to test for driver code path bugs.
  • Inserting a fake filter into every WDM stack.

Driver errors caught by Enhanced I/O Verification are displayed in the same manner as those caught by Level 2 I/O Verification.

Activating This Option

The I/O Verification option can be activated by using the Driver Verifier Manager graphical interface or the verifier.exe command line. This activation will take effect after the next boot.

When you activate I/O Verification in Windows 2000, you can choose between Level 1 and Level 2; if you choose the latter, both levels of tests are activated.

In Windows XP, choosing I/O Verification enables both Level 1 and Level 2 tests. You can activate Enhanced I/O Verification in addition to (or instead of) the standard I/O Verification.

See Selecting Driver Verifier Options for details.

Graphics Drivers

The I/O Verification option is not used for graphics drivers. If selected, it has no effect.


DMA Verification

DMA Verification monitors the use of Direct Memory Access (DMA). Since the DMA routines have changed as Windows has developed, many drivers make incorrect use of DMA calls. Moreover, some driver writers attempt to bypass the HAL DMA subsystem altogether. This practice can introduce insidious bugs into the driver.

The DMA Verification option of Driver Verifier attempts to catch common DMA errors. Along with the !dma kernel debugger extension, it can be used to verify that a driver is using DMA in a proper manner.

This Driver Verifier option is also called HAL Verification. Some error messages produced by Driver Verifier may use this term.

This Driver Verifier option is only available in Windows XP and later versions.

Different Types of DMA

DMA is a mechanism through which a hardware device can transfer data to or from memory without using the processor. The processor is required to set up the transfer, and the device will signal the processor when it has completed the transfer. The advantage of this system is that the processor can perform other tasks while the DMA transfer is being performed.

There are several types of DMA used in Windows 2000 and later versions:

Common-buffer DMA
Common-buffer DMA is performed when the system can allocate a single buffer that is accessible by both the hardware and the software. The driver is responsible for synchronizing accesses to the buffer. The memory is not cached, making this synchronization easier for the driver. After setting up a common buffer, both the driver and the hardware can write directly to the addresses in the buffer without any intervention from the HAL.
Packet DMA
Packet DMA is performed when there is a single existing buffer that must be mapped for use by the hardware. An example of using packet DMA is the transfer of a file from memory to a disk. Using common-buffer DMA in this situation would be wasteful, because the file would have to be transferred to the common buffer before the hardware could transfer it to the disk. Instead, the HAL is consulted; it gives the driver the information it needs to help the hardware find the actual buffer in memory. This operation is complicated by the need for the routines involved to work across different architectures.
Scatter-Gather DMA
Scatter-gather DMA is a shortcut method that sets up several packet DMA transfers at once. If you are transferring a packet over the network, for example, each part of the network stack adds its own header (TCP, IP, Ethernet, and so forth). These headers are all allocated from different places in memory. In this case, the scatter-gather DMA saves time by issuing a batch request to the HAL to map each header plus the data segment for access by the hardware. Instead of having to call the packet DMA routines on each part of the packet, this method calls each routine once, and lets the HAL be responsible for mapping each one individually.
System DMA
System DMA is performed by programming the system DMA controller on the motherboard to do the transfer directly. Only ISA cards can use system DMA.

Note Scatter-gather capability does not mean that the device can use the scatter-gather routines. Scatter-gather capability refers to a flag in the device description that indicates that the device is able to read or write from any area in memory, instead of just a certain range.

Effects of DMA Verification

When DMA Verification is active, the following common misuses of the DMA routines are detected:

  • Overrunning the DMA memory buffer (these overruns can be made by the hardware or the driver)
  • Attempting to use an adapter that was already freed and no longer exists
  • Double-freeing a common buffer, adapter channel, map register, or scatter-gather list
  • Leaking memory by not freeing common buffers, adapter channels, map registers, scatter-gather lists, or adapters
  • Having more than one adapter channel present for an adapter at one time
  • Allocating too many map registers
  • Not flushing adapter buffers
  • Double-mapping of map registers
  • Performing DMA on a pageable buffer (all buffers should be locked before DMA transfer begins)
  • Performing DMA on an MDL with mangled flags
  • Calling DMA routines at an improper IRQL

Driver Verifier monitors the driver's behavior and issues bug check 0xE6 if any of these violations occur. See Bug Check 0xE6 for a list of the bug check parameters.

When is DMA Verification Useful?

All drivers that use DMA directly (by calling the HAL DMA routines) should be tested with DMA Verification.

In addition, miniport drivers should also be tested, since they often use DMA indirectly (by calling port drivers that use DMA).

DMA Verification can also be an effective way to detect memory corruptions, since it can spot when either a driver or a hardware device overruns a DMA buffer.

Monitoring DMA Verification

The kernel debugger extension !dma can be used to display a wealth of DMA information. It can display various details about the behavior of each DMA adapter. For information about debugger extensions, see the documentation in the Debugging Tools for Windows package.

Activating This Option

The DMA Verification option can be activated by using the Driver Verifier Manager graphical interface or the verifier.exe command line. This activation will take effect after the next boot. See Selecting Driver Verifier Options for details.

Graphics Drivers

The DMA Verification option is not used for graphics drivers. If selected, it has no effect.


Deadlock Detection

Deadlock Detection monitors the driver's use of resources which need to be locked — spin locks, mutexes, and fast mutexes. This Driver Verifier option will detect code logic that has the potential to cause a deadlock at some future point.

The Deadlock Detection option of Driver Verifier, along with the !deadlock kernel debugger extension, is an effective tool for making sure your code avoids poor use of these resources.

This Driver Verifier option is only available in Windows XP and later versions.

Causes of Deadlocks

A deadlock is caused when two or more threads come into conflict over some resource, in such a way that no execution is possible.

The most common form of deadlock occurs when two or more threads wait for a resource that is owned by the other thread. This is illustrated as follows:

Thread 1 | Thread 2
Takes Lock A | Takes Lock B
Requests Lock B | Requests Lock A

If both sequences happen at the same time, Thread 1 will never get Lock B because it is owned by Thread 2, and Thread 2 will never get Lock A because it is owned by Thread 1. At best this causes the threads involved to halt, and at worst causes the system to stop responding.

Deadlocks are not limited to two threads and two resources. Three-way deadlocks between three threads and three locks are common — and even five-part or six-part deadlocks occur occasionally. These deadlocks require a certain degree of "bad luck" since they rely on a number of things happening simultaneously. However, the farther apart the lock acquisitions are, the more likely these become.

Single-thread deadlocks can occur when a thread attempts to take a lock that it already owns.

The common denominator among all deadlocks is that lock hierarchy is not respected. Whenever it is necessary to have more than one lock acquired at a time, each lock should have a clear precedence. If A is taken before B at one point and B before C at another, the hierarchy is A-B-C. This means that A must never be acquired after B or C, and B must not be acquired after A.

Lock hierarchy should be followed even when there is no possibility of a deadlock, since in the process of maintaining the code it will be easy for a deadlock to be accidentally introduced.

Resources That Can Cause Deadlocks

The most unambiguous deadlocks are the result of owned resources. These include spin locks, mutexes, fast mutexes, and ERESOURCEs.

Resources that are signaled rather than acquired (such as events and LPC ports) tend to cause much more ambiguous deadlocks. It is of course possible, and all too common, for code to misuse these resources in such a way that two threads will end up waiting on each other indefinitely. However, since these resources are not actually owned by any one thread, it is not possible to identify the delinquent thread with any degree of certainty.

The Deadlock Detection option of Driver Verifier looks for potential deadlocks involving spin locks, mutexes, and fast mutexes. It does not monitor the use of ERESOURCEs, nor does it monitor the use of non-owned resources.

Effects of Deadlock Detection

Driver Verifier's Deadlock Detection routines find lock hierarchy violations that are not necessarily simultaneous. Most of the time, these violations identify code paths that will deadlock when given the chance.

To find potential deadlocks, Driver Verifier builds a graph of resource acquisition order and checks for loops. If you were to create a node for each resource, and draw an arrow any time one lock is acquired before another, then path loops would represent lock hierarchy violations.

Driver Verifier will issue a bug check when one of these violations is discovered. This will happen before any actual deadlocks occur.

Note Even if the conflicting code paths can never happen simultaneously, they should still be rewritten if they involve lock hierarchy violations. Such code is a "deadlock waiting to happen" that could cause real deadlocks if the code is rewritten slightly.

When Deadlock Detection finds a violation, it will issue bug check 0xC4. The first parameter of this bug check will indicate the exact violation. Possible violations include:

  • Two or more threads involved in a lock hierarchy violation
  • A resource that is released out of sequence
  • A thread that tries to acquire the same resource twice (a self-deadlock)
  • A resource that is released without having been acquired first
  • A resource that is released by a different thread than the one that acquired it
  • A resource that is initialized more than once, or not initialized at all
  • A thread that is deleted while still owning resources

See Bug Check 0xC4 for a complete list of the bug check parameters.

Monitoring Deadlock Detection

Once Deadlock Detection finds a violation, the !deadlock kernel debugger extension can be used to investigate exactly what has occurred. It can display the lock hierarchy topology as well as the call stacks for each thread at the time the locks were originally acquired.

For best results, the driver in question should be running on a checked build of Windows, since that allows the kernel to obtain more complete run-time stack traces.

For a detailed example of the use of the !deadlock extension, as well as general information about debugger extensions, see the documentation in the Debugging Tools for Windows package.

Activating This Option

The Deadlock Detection option can be activated by using the Driver Verifier Manager graphical interface or the verifier.exe command line. This activation will take effect after the next boot. See Selecting Driver Verifier Options for details.

Graphics Drivers

The Deadlock Detection option is not used for graphics drivers, since display drivers and kernel-mode printer drivers cannot directly own resources. If selected, it has no effect.


SCSI Verification

The SCSI Verification option of Driver Verifier monitors the interaction between a SCSI miniport driver and the port driver. If the miniport driver misuses a routine, responds incorrectly to a request from the port driver, or takes an excessive amount of time to respond to a request, a bug check is issued.

This Driver Verifier option is only available in Windows XP and later versions.

Violations Detected by SCSI Verification

The SCSI Verification option can detect several misuses of SCSI routines. It is also possible to individually disable certain of these checks.

When a SCSI miniport driver commits one of the following violations, Driver Verifier will issue bug check 0xF1.

  • The miniport passes a bad argument to ScsiPortInitialize.
  • The miniport calls ScsiPortStallExecution and specifies a delay longer than 0.1 second, stalling the processor for an excessive length of time.
  • The port driver calls a miniport routine, and the miniport takes longer than 0.5 second to execute it. (The FindAdapter routine is exempt, and the HwInitialize routine is allowed 5 seconds.)
  • The miniport completes a request more than once.
  • The miniport completes a routine with an invalid SRB status.
  • The miniport calls ScsiPortNotification to ask for NextLuRequest, but an untagged request is still active.
  • The miniport passes an invalid virtual address to ScsiPortGetPhysicalAddress. (This usually means the address supplied doesn't map to the common buffer area.)
  • The bus reset hold period ends, but the miniport still has outstanding requests.

See Bug Check 0xF1 for a complete list of the bug check parameters.

In addition to these violations, SCSI Verification also monitors the miniport driver's memory access for improper use. Two common memory violations made by miniport drivers are accessing an SRB extension after a request completes, and accessing an SRB's DataBuffer when the miniport has not specified MapBuffers.

Memory violations of this sort will usually result in Bug Check 0xD1 being issued.

Activating This Option

The SCSI Verification option is enabled in a different manner from other Driver Verifier options.

To activate SCSI Verification

  1. Using the Driver Verifier Manager graphical interface or the verifier.exe command line, request verification of the desired miniport driver. SCSI Verification will not be available as an option, but you must select at least one other Driver Verifier option. See Selecting Driver Verifier Options and Selecting Drivers to be Verified for details.
  2. Open the registy using regedit.exe. In the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\ScsiPort key, add a subkey named Verifier. Within that key, add a REG_DWORD entry named VerifyLevel. The value assigned to this entry will determine which SCSI Verification tests will be active. The value 0x1 will give maximum verification.
  3. Reboot the computer.

If the VerifyLevel value does not exist, or is equal to 0xFFFFFFFF, SCSI Verification will be disabled.

The individual bits in the VerifyLevel value can be used to control exactly which tests will be performed. Bit zero (0x1) enables certain tests; bits 28, 29, 30, and 31 disable certain tests. Therefore, maximum verification can be obtained by using the value 0x00000001.

The effects of each bit are as follows:

Bit | Value | Effect
0 | 0x1 | Driver Verifier will monitor the miniport driver's memory access and check for improper use of memory buffers.
28 | 0x10000000 | Driver Verifier will not issue a bug check when the HwAdapterControl routine takes more than 0.5 second to complete.
29 | 0x20000000 | Driver Verifier will not issue a bug check when a reset hold period ends and there are still outstanding requests on a logical unit.
30 | 0x40000000 | Driver Verifier will not issue a bug check when the miniport calls ScsiPortNotification with NextLuRequest while an untagged request is still active.
31 | 0x80000000 | Driver Verifier will not issue a bug check when the HwInitialize routine takes more than 5 seconds to complete.

Graphics Drivers

The SCSI Verification option is not used for graphics drivers. If selected, it has no effect.


Driver Verifier Options for Graphics Drivers

Microsoft® Windows® kernel-mode graphics drivers do not allocate pool directly. Instead, these drivers use Graphics Driver Interface (GDI) service routines exported by win32k.sys.

Because of this difference, Driver Verifier treats graphics drivers differently than it treats other kernel-mode drivers.

The following sections describe Driver Verifier's actions on display drivers and kernel-mode printer drivers.

  • Special Memory Pool for Graphics Drivers

    When this option is active, Driver Verifier allocates most of the driver's memory requests from a special pool. This special pool is monitored for memory overruns, memory underruns, and memory that is accessed after it is freed.

  • Low Resources Simulation for Graphics Drivers

    When this option is active, Driver Verifier randomly fails memory requests and other resource requests. By injecting these allocation faults into the system, Driver Verifier tests the driver's ability to cope with a low-resource situation.

Inapplicable Options for Graphics Drivers

The Automatic Checks, Forcing IRQL Checking, Memory Pool Tracking, I/O Verification, DMA Verification, Deadlock Detection, and SCSI Verification options are not used for graphics drivers. If selected, these options have no effect.

Note Driver Verifier can be set to verify win32k.sys itself. However, this has the effect of verifying all graphics drivers simultaneously. To obtain more specific information about a graphics driver, Driver Verifier should be set to verify only the driver under investigation.


Special Memory Pool for Graphics Drivers

Memory corruption is a common driver problem. Driver errors can result in crashes long after they are made. The most common of these errors are accessing memory that has already been freed, and allocating n bytes and then accessing n+1.

When the Special Memory Pool action is used on graphics drivers, memory allocated by the EngAllocMem routine will be taken from a special memory pool. Driver Verifier will monitor that pool for any incorrect usage.

Two alignments of the special pool are available. The Verify End alignment is better at detecting access overruns, and the Verify Start alignment is better at detecting access underruns. (Note that the vast majority of memory corruptions are due to overruns, not underruns.)

When Special Memory Pool is active and Verify End has been selected, each memory allocation requested by the driver is placed on a separate page. The highest possible address that allows the allocation to fit on the page is returned, so that the memory is aligned with the end of the page. The previous portion of the page is written with special patterns. The previous page and the next page are marked inaccessible.

If the driver attempts to access memory after the end of the allocation, Driver Verifier will detect this immediately, and issue bug check 0xCD. If the driver writes in the memory prior to the beginning of the buffer, this will (presumably) alter the patterns. When the buffer is freed, Driver Verifier will detect the alteration and issue bug check 0xC1.

If the driver reads or writes to the buffer after freeing it, Driver Verifier will issue bug check 0xCC.

When Verify Start is selected, the memory buffer is aligned with the beginning of the page. With this setting, underruns cause an immediate bug check and overruns cause a bug check when the memory is freed. This option is otherwise identical to the Verify End option.

Verify End is the default alignment, as overrun errors are much more common in drivers than underrun errors.

Pool Tags

Driver Verifier will assign the special pool to the drivers that have been selected for verification.

Another way to use the special pool is to assign it to memory pools that have been marked with a specific pool tag. This is done by using the Global Flags utility rather than the Verifier utility.

It is permissible to request special pools though Driver Verifier and the Global Flags Utility at the same time. If this is done, Windows will attempt to use the special pool for all pools that have the specified tags and all pool allocation requests from the specified drivers.

Special Pool Efficiency

Each allocation from the special pool uses one page of nonpageable memory and two pages of virtual address space. If the pool is exhausted, memory is allocated in the standard way until the special pool becomes available again. Thus it is not recommended that multiple drivers be verified at the same time if Special Memory Pool is in effect.

A single driver that makes a large number of small memory requests can also deplete this pool. If this is occurring, it may be preferable to assign pool tags to the driver's memory allocations and dedicate the special pool to one pool tag at a time.

The size of the special pool increases with the amount of physical memory on the system; ideally this should be at least 1 GB. On x86 machines, booting without the /3GB switch is also preferred, as virtual (in addition to physical) space is consumed. Increasing the pagefile minimum/maximum quantities (by a factor of two or three) is also a good idea.

To be sure that all of a driver's allocations are being tested, stressing the driver over long periods of time is recommended.

Activating This Option

The Special Memory Pool option can be activated for one or more drivers by using the Driver Verifier Manager graphical interface or the verifier.exe command line. This activation will take effect after the next boot. See Selecting Driver Verifier Options for details.

This option can also be turned on and off without an intervening reboot. See Using Volatile Settings for details.

Activating the Special Memory Pool for tagged memory pools is done by using the Global Flags utility. This utility is also used to set the Verify Start and Verify End alignments, regardless of whether the special pool is being used for drivers or for pool tags. See Using the Global Flags Utility for details.

Non-Graphics Drivers

See Special Memory Pool for details on how this option affects other kernel-mode drivers.


Low Resources Simulation for Graphics Drivers

When Low Resources Simulation is enabled, Driver Verifier will cause a random selection of the driver's memory allocations to fail. This tests the driver's ability to react properly to low-memory and other low-resource conditions.

The following GDI callback functions are subject to this random failure:

EngAllocMem

EngAllocUserMem

EngCreateBitmap

EngCreateDeviceSurface

EngCreateDeviceBitmap

EngCreatePalette

EngCreateClip

EngCreatePath

EngCreateWnd

EngCreateDriverObj

BRUSHOBJ_pvAllocRbrush

CLIPOBJ_ppoGetPath

To accurately simulate a low-memory condition, these allocation faults are not injected until seven minutes after system startup. Therefore, any driver errors that are exposed by this action should be treated as legitimate run-time problems, not as unrealistic scenarios.

These allocation failures may cause rendering errors, resulting in incorrect images and other output errors. Therefore, this Driver Verifier option should only be used for robustness testing of a graphics driver, and should not be active when testing for correct implementation.

The Low Resources Simulation option may cause corruption in the shell's icon cache. If this happens, the icon cache must be manually deleted from the disk.

Monitoring Low Resources Simulation

(Windows XP only) The kernel debugger extension !gdikdx.verifier -s can be used to display a count of how many times each of the GDI callback functions, mentioned in the beginning of this section, was called, and how many times Driver Verifier caused these functions to fail. For information about debugger extensions, see the documentation in the Debugging Tools for Windows package.

Activating This Option

The Low Resources Simulation option can be activated by using the Driver Verifier Manager graphical interface or the verifier.exe command line. This activation will take effect after the next boot. See Selecting Driver Verifier Options for details.

This option can also be turned on and off without an intervening reboot. See Using Volatile Settings for details.

Non-Graphics Drivers

See Low Resources Simulation for details on how this option affects other kernel-mode drivers.


Activating and Monitoring Driver Verifier

Driver Verifier can be activated, configured, and monitored through the Verifier utility. This utility contains both a command-line interface and a graphical interface.

This section includes:

The Verifier Utility

Controlling Driver Verifier

Monitoring Driver Verifier


The Verifier Utility

The verifier.exe utility can be used to activate and monitor Driver Verifier. This utility is located in the %windir%\system32 directory of Windows®.

There are two ways to use the Verifier utility. The executable name verifier can be typed in an MS-DOS® Command Prompt window, followed by at least one command-line parameter. Any output generated will be displayed in the same window.

Alternately, the command verifier can be entered at a Command Prompt with no parameters, or you can double-click on the icon associated with verifier.exe. This causes a graphical interface named Driver Verifier Manager to appear. This graphical interface has a somewhat different arrangement in Windows 2000 and in Windows XP.

This section includes:

Verifier Command Line

Driver Verifier Manager (Windows 2000)

Driver Verifier Manager (Windows XP)


Verifier Command Line

The following syntax is used when running the Verifier utility from an MS-DOS® Command Prompt window.

It is possible to put several options on a single line. For example:

verifier /flags 7 /driver beep.sys flpydisk.sys

Verifier Command-Line Syntax

Windows 2000 Syntax

verifier /flags Options [ /iolevel Level ]
verifier { /driver DriverList | /all }
verifier /volatile /flags VolatileOptions
verifier /reset
verifier /query
verifier /log LogFileName [/interval Seconds]
verifier /?

Windows XP Syntax

verifier { /flags Options | /standard }
verifier { /driver DriverList | /all }
verifier /volatile /flags VolatileOptions
verifier /volatile /adddriver VolatileDriverList
verifier /volatile /removedriver VolatileDriverList
verifier /reset
verifier /querysettings
verifier /query
verifier /log LogFileName [/interval Seconds]
verifier /?

Parameters

/flags Options
Specifies the Driver Verifier options that will be active after the next boot. In Windows 2000, this number must be entered in decimal format. In Windows XP, this number can be entered in decimal or in hexadecimal (with an 0x prefix) format. Any combination of the following values is allowed.
Decimal | Hexadecimal | Option
1 | 0x1 (Bit 0) | Special Memory Pool
2 | 0x2 (Bit 1) | Forcing IRQL Checking
4 | 0x4 (Bit 2) | Low Resources Simulation
8 | 0x8 (Bit 3) | Memory Pool Tracking
16 | 0x10 (Bit 4) | I/O Verification
32 | 0x20 (Bit 5) | (Windows XP only) Deadlock Detection
64 | 0x40 (Bit 6) | (Windows XP only) Enhanced I/O Verification
128 | 0x80 (Bit 7) | (Windows XP only) DMA Verification

The SCSI Verification option is not enabled through this method. See SCSI Verification for details.

/standard
(Windows XP only) Specifies that the "standard" Driver Verifier options will be active after the next boot. The standard options are Special Memory Pool, Forcing IRQL Checking, Memory Pool Tracking, I/O Verification (but not the enhanced version), Deadlock Detection, and DMA Verification. This is equivalent to /flags 0xBB.
/iolevel Level
(Windows 2000 only) Specifies the level of I/O Verification. This can be 1 or 2, and is ignored unless I/O Verification has been enabled by using the /flags parameter. If this is omitted or equal to 1, only the Level 1 I/O Verification tests will be enabled. If this is equal to 2, both the Level 1 and Level 2 tests will be enabled. (In Windows XP, both levels are always active as long as I/O Verification is enabled.) See I/O Verification for details.
/driver DriverList
Causes the specified drivers to be verified after the next boot. Multiple drivers can be specified by listing their names, separated by spaces. Wildcard values, such as n*.sys, are not supported.
/all
Causes Driver Verifier to verify all installed drivers after the next boot.
/volatile
Causes changes to be made to Driver Verifier's volatile settings. Volatile settings take effect immediately, rather than after a reboot. See Using Volatile Settings for details.
/flags VolatileOptions
Specifies the Driver Verifier options that will be changed in a volatile manner. In Windows 2000, this number must be entered in decimal format. In Windows XP, this number can be entered in decimal or in hexadecimal (with an 0x prefix) format. Any combination of the following values is allowed.
Decimal | Hexadecimal | Option
1 | 0x1 (Bit 0) | Special Memory Pool
2 | 0x2 (Bit 1) | Forcing IRQL Checking
4 | 0x4 (Bit 2) | Low Resources Simulation

/adddriver VolatileDriverList
(Windows XP only) Causes the specified drivers to be added to the volatile settings. Multiple drivers can be specified by listing their names, separated by spaces. Wildcard values, such as n*.sys, are not supported. See Using Volatile Settings for details.
/removedriver VolatileDriverList
(Windows XP only) Causes the specified drivers to be removed from the volatile settings. Multiple drivers can be specified by listing their names, separated by spaces. Wildcard values, such as n*.sys, are not supported. See Using Volatile Settings for details.
/reset
Clears all Driver Verifier settings. After the next boot, no drivers will be verified.
/querysettings
(Windows XP only) Displays a summary of the non-volatile Driver Verifier settings — the options selected and the drivers selected for verification. These are the settings that will be active after the next boot. For other ways to view these settings, see Viewing Driver Verifier Settings.
/query
Causes a summary of Driver Verifier's current activity to be displayed on the screen. See Monitoring Global Counters and Monitoring Individual Counters for explanations of each statistic.
/log LogFileName
Creates a log file with name LogFileName. At regular intervals, Driver Verifier statistics will be written to this file. See Creating Log Files for details. If this command is launched from an MS-DOS® Command Prompt Window, this command will not return a new prompt. To close the log file and return a prompt, use the CTRL+C key. After a reboot, this command must be used again if a new log file is desired.
/interval Seconds
Specifies the interval between log file updates. The default is 30 seconds.
/?
Causes command-line help information to be displayed.

For more information on the use of these commands, see Controlling Driver Verifier and Monitoring Driver Verifier.


Driver Verifier Manager (Windows 2000)

The Microsoft Windows 2000 version of Driver Verifier Manager has five separate panels:

  1. The Driver Status screen displays which drivers are loaded and are being verified, and which Driver Verifier options are active. See Viewing Driver Verifier Settings for details.
  2. The Global Counters screen displays statistics related to Driver Verifier's actions. Although some of these statistics are related to certain Driver Verifier options, these statistics will be displayed regardless of which options are active. See Monitoring Global Counters for details.
  3. The Pool Tracking screen displays information on pool allocations. See Monitoring Individual Counters for details.
  4. The Settings screen is used to activate and configure Driver Verifier's actions. Changes made from this screen take effect after the next boot. See Selecting Driver Verifier Options and Selecting Drivers to be Verified for details.
  5. The Volatile Settings screen is used to alter Driver Verifier's volatile actions. Changes made from this screen take effect immediately. See Using Volatile Settings for details.

Several screens have a Refresh Frequency section on them. This is used to control how often the information displayed on that screen is updated. Low, Medium, and High instruct Driver Verifier to refresh the screen every 1, 5, or 10 seconds, respectively. Manual disables automatic updating. The Refresh Now button causes the screen to be refreshed immediately.

To exit Driver Verifier Manager, use the Exit button. If you have made any changes and have not pressed the corresponding Apply button, you will be asked if you wish to save your changes.


Driver Verifier Manager (Windows XP)

The Microsoft Windows XP version of Driver Verifier Manager begins with a screen which allows you to select one of five tasks. Whichever task you choose, you will be shown a series of screens that can be navigated by using the Back and Next buttons.

When this sequence is complete, use the Finish button to save any changes you have made and exit Driver Verifier Manager. If you wish to discard your changes, use the Cancel button.

The following tasks can be chosen from the first screen of Driver Verifier Manager:

Create standard settings
This will select a standard set of Driver Verifier options, and then allow you to choose which drivers will be verified. These settings will take effect after the next boot. See Selecting Driver Verifier Options and Selecting Drivers to be Verified for details.
Create custom settings
This allows you to activate any of Driver Verifier's actions and choose which drivers will be verified. These settings will take effect after the next boot. See Selecting Driver Verifier Options and Selecting Drivers to be Verified for details.
Delete existing settings
This will cause all of Driver Verifier's options to be deactivated and delete the list of drivers being verified. This takes effect after the next boot.
Display existing settings
This will display the non-volatile Driver Verifier settings — the options selected and the drivers selected for verification. These are the settings that will be active after the next boot. See Viewing Driver Verifier Settings for details.
Display information about the currently-verified drivers
This will display statistics related to Driver Verifier's actions. See Monitoring Global Counters and Monitoring Individual Counters for details. It will also allow you to view and alter Driver Verifier's volatile actions. See Using Volatile Settings.


Controlling Driver Verifier

This section includes:

Selecting Driver Verifier Options

Selecting Drivers to be Verified

Viewing Driver Verifier Settings

Using Volatile Settings

Using the Global Flags Utility


Selecting Driver Verifier Options

Driver Verifier options can be selected by using the Verifier Command Line, or by using the Driver Verifier Manager graphical interface, which is different in Windows 2000 and Windows XP.

Verifier Command Line

To activate or deactivate individual options, specify the desired options after the /flags parameter. In Windows 2000 you may also need to use the /iolevel parameter.

(Windows XP only) To turn on the standard options — Special Memory Pool, Forcing IRQL Checking, Memory Pool Tracking, I/O Verification, DMA Verification, and Deadlock Detection — use the /standard parameter.

To deactivate all options and clear the verified driver list, use the /reset parameter.

See Verifier Command Line for details.

Windows 2000 Driver Verifier Manager

To activate or deactivate individual options, select the Settings tab. Driver Verifier's options are listed in the Verification Type section (Special Memory Pool, Forcing IRQL Checking, Low Resources Simulation, Memory Pool Tracking, and I/O Verification). Check whichever options you wish to activate, and clear those you wish to deactivate. If I/O Verification is selected, you can choose between Level 1 and Level 2 (choosing Level 2 enables both Level 1 and Level 2 tests). To choose which drivers you wish to verify, see Selecting Drivers to be Verified.

To turn on the standard options — Special Memory Pool, Forcing IRQL Checking, Memory Pool Tracking, and I/O Verification Level 2 — select the Settings tab. Press the Preferred Settings button. This button also selects the Verify All Drivers option button. If you wish to now change the list of drivers verified, see Selecting Drivers to be Verified; otherwise, press Apply.

To deactivate all options and clear the verified driver list, select the Settings tab. Press the Reset All button. Then press Apply.

Windows XP Driver Verifier Manager

To activate individual options, select the Create custom settings task, and press Next. On the next screen, select Select individual settings from a full list, and press Next. The next screen lists all of Driver Verifier's options (Special Memory Pool, Memory Pool Tracking, Forcing IRQL Checking, I/O Verification, Enhanced I/O Verification, Deadlock Detection, DMA Verification, and Low Resources Simulation). Check whichever options you wish to activate. Then press Next. See Selecting Drivers to be Verified for the next step.

To turn on the standard options — Special Memory Pool, Forcing IRQL Checking, Memory Pool Tracking, I/O Verification, DMA Verification, and Deadlock Detection — select the Create standard settings task. Then press Next. See Selecting Drivers to be Verified for the next step.

To deactivate all options and clear the verified driver list, select the Delete existing settings task. Then press Finish.

Reboot Required

Activation and deactivation of Driver Verifier options will not take effect until after the next boot.

There is a way to change certain options without rebooting. See Using Volatile Settings for details.

Additional Information

See Driver Verifier Options and Driver Verifier Options for Graphics Drivers for descriptions of each option.


Selecting Drivers to be Verified

Drivers can be selected for verification by using the Verifier Command Line, or by using the Driver Verifier Manager graphical interface, which is different in Windows 2000 and Windows XP.

Verifier Command Line

To verify all drivers, use the /all parameter.

To verify a list of drivers, use the /driver parameter.

See Verifier Command Line for details.

Windows 2000 Driver Verifier Manager

To verify all drivers, select the Settings tab. Select Verify all drivers. Then press Apply.

To verify a list of drivers, select the Settings tab. Select Verify selected drivers. You will see a list of all drivers that were loaded in the system during the most recent boot.

The Verification Status column gives the current status for each driver. Possible Verification Status values are:

Enabled
The driver is currently being verified and will continue to be verified after reboot.
Disabled
The driver is not currently being verified, and will not be verified after reboot.
Enabled (Reboot Needed)
The driver is not currently being verified, but the user has requested verification of this driver. This driver will be verified after reboot.
Disabled (Reboot Needed)
The driver is currently being verified, but the user has requested an end to this verification. After reboot, this driver will no longer be verified.

You can select one or more drivers from this list and click the Verify or Don't Verify button. You can also right-click on the driver's name and control verification from the popup menu.

The Verify These Additional Drivers After Next Reboot text box allows you to enter the names of drivers not currently loaded on the system. Multiple names must be separated with spaces.

Once you have selected the drivers to verify, press Apply.

To deactivate all options and clear the verified driver list, select the Settings tab. Press the Reset All button. Then press Apply.

Windows XP Driver Verifier Manager

In the Windows XP Driver Verifier Manager, selection of drivers must be done after selection of options. See Selecting Driver Verifier Options for a description of this step. When this step is complete, you will see the Select what drivers to verify panel.

To verify all drivers, select Automatically select all drivers installed on this computer. Then press Finish.

To verify a list of drivers, select Select driver names from a list and then press Next. You will see a list of all drivers that are currently loaded. (In Windows XP, the current verification status of each driver will not be indicated.) Check the box next to each driver that you wish to verify. To select drivers that are not on the list, press Add currently not loaded driver(s) to the list. This allows you to browse the system for the desired driver's file. Press Open to add that driver to the top of the list. You must then check the box next to this driver to select it for verification. Once you have selected the drivers to verify, press Finish.

To verify unsigned drivers, select Automatically select unsigned drivers. A list of these drivers will be displayed. (If no such drivers exist, an error message will appear.) Then press Finish.

To verify drivers built for earlier versions of Windows, select Automatically select drivers built for older versions of Windows. A list of these drivers will be displayed. (If no such drivers exist, an error message will appear.) Then press Finish.

To deactivate all options and clear the verified driver list, start Driver Verifier Manager and select Delete existing settings from the first screen. Then press Finish.

Reboot Required

Changes made to the list of verified drivers will not take effect until after the next boot.

In Windows XP, it is possible to change the list of drivers being verified without rebooting, if certain conditions are met. See Using Volatile Settings for details.


Viewing Driver Verifier Settings

The current Driver Verifier settings can be displayed by using the Driver Verifier Manager graphical interface, which is different in Windows 2000 and Windows XP. In Windows XP, they can also be displayed by using the Verifier Command Line.

The following methods will display the settings that will take effect after the next boot. These will include a list of the Driver Verifier options that have been selected as well as a list of the drivers to be verified.

Verifier Command Line

(Windows XP only) To display the Driver Verifier settings, use the verifier /querysettings command.

Windows 2000 Driver Verifier Manager

To display the Driver Verifier settings, select the Settings tab.

Press Exit to stop viewing these settings.

Windows XP Driver Verifier Manager

To display the Driver Verifier settings, start Driver Verifier Manager and select the Display Existing Settings task. Then press Next.

Press Finish to stop viewing these settings.

Viewing the Currently-Active Features

If you wish to view the Driver Verifier features that are currently active, rather than the settings that will take effect after the next boot, see Using Volatile Settings.


Using Volatile Settings

Most changes to Driver Verifier's status (activating, deactivating, changing options, or changing the list of drivers being verified) take effect on reboot.

However, some options can be activated and deactivated without a reboot intervening. These are referred to as volatile settings. These settings take place immediately, and will last until the next boot, or until they are changed again.

Only the Special Memory Pool, Forcing IRQL Checking, and Low Resources Simulation options can be activated or deactivated in a volatile manner.

In Windows XP, the list of drivers being verified can also be changed in a volatile manner. However, a driver can only be added or removed from the volatile settings if it is not currently loaded.

Note For volatile settings to be enabled, at least one Driver Verifier option must have been selected during the last boot, and at least one driver must have been selected to be verified. If Driver Verifier was completely inactive during the last boot, it cannot be activated through volatile settings alone.

Volatile settings can be set by using the Verifier Command Line, or by using the Driver Verifier Manager graphical interface, which is different in Windows 2000 and Windows XP.

Verifier Command Line

To add or delete volatile options, use the /volatile /flags parameter.

(Windows XP only) To add or remove a driver from the volatile list, use the /volatile /adddriver or /volatile /removedriver parameters.

See Verifier Command Line for details.

Windows 2000 Driver Verifier Manager

To view the Driver Verifier features that are currently active, select either the Driver Status or the Volatile Settings tab.

To change the volatile settings, select the Volatile Settings tab.

The display on each of these screens shows the Driver Verifier options currently in effect, including volatile settings, but not including changes to permanent settings that are scheduled to take effect after the next boot. Each driver will have its status listed.

If you wish to make changes, select or unselect the desired options, then press Apply.

Windows XP Driver Verifier Manager

To view the Driver Verifier features that are currently active, or to change the volatile settings, start Driver Verifier Manager and select the Display information about the currently verified drivers task. Then press Next.

The display on this screen shows the Driver Verifier options currently in effect, including volatile settings, but not including changes to permanent settings that are scheduled to take effect after the next boot. Each driver will have its status listed.

To change the active options, press Change. Select or deselect the desired options, and then press OK.

To verify a new driver, press Add. This opens a popup window that allows you to browse the system for the desired driver file. After locating the correct driver, press Open to add it to the list of verified drivers.

To remove a driver from the list, select that driver's name and press Remove.

Then press Next, Next again, and Finish.

Driver Status Values

There are three possible status values for drivers shown on this screen. They are as follows:

Loaded
The driver is currently loaded and is being verified.
Unloaded
The driver was loaded and verified at least once since the last boot, but is currently not loaded.
Never Loaded
Driver Verifier was instructed to verify this driver, but the driver has not been loaded since this request. This can indicate that the driver is loaded on demand and has not yet been required in this session. It might also indicate that a nonexistent driver was requested for verification, or that a driver image file has been corrupted.


Using the Global Flags Utility

The Global Flags (gflags.exe) utility provides a simple method of setting certain keys within the system registry, adjusting the kernel settings of the running system, and altering the settings for image files. You can set these keys by using a graphical or command-line interface.

This utility can be found in the Windows Support Tools package and in the Debugging Tools for Windows package.

The Global Flags utility can also be used to configure the Special Memory Pool option of Driver Verifier, or to use the special pool for individual memory allocations.

To alter the Special Memory Pool settings, first start the Global Flags utility and select the System Registry option button in the Destination section.

The Kernel Special Pool Tag dialog box allows certain special pool options to be set.

If a pool tag is entered, the special pool will be used for all pool allocations with the specified tag. If the Special Memory Pool is active through Driver Verifier at the same time, all pools with the specified tag and all pools allocated from drivers being verified will be allocated from the special pool (subject to pool availability).

The Verify Start option button causes the special pool alignment to focus on underrun detection. The Verify End option is used to focus on overrun detection. These buttons control the alignment of special pool assignments made by pool tag or by Driver Verifier.

See Special Memory Pool and Special Memory Pool for Graphics Drivers for full details on the use of the special pool.


Monitoring Driver Verifier

The Verifier utility has several ways to monitor the actions of Driver Verifier and of the drivers being verified.

However, the Verifier utility does not monitor the actions of Driver Verifier with regard to graphics drivers.

The kernel debugger extension !verifier can also be used to monitor and report on a number of statistics related to Driver Verifier's activities. When verifying graphics drivers, the !gdikdx.verifier extension should be used instead. For information about debugger extensions, see the documentation in the Debugging Tools for Windows package.

This section includes:

Monitoring Global Counters

Monitoring Individual Counters

Creating Log Files


Monitoring Global Counters

Global counters are statistics that monitor some of the actions that Driver Verifier performs on drivers. These statistics are drawn from all drivers being verified, except for graphics drivers.

Global counters can be viewed by using the Verifier Command Line, or by using the Driver Verifier Manager graphical interface, which is different in Windows 2000 and Windows XP.

Verifier Command Line

To view global counters, use the verifier /query command. This will show both global counters and individual counters.

Global counters are also included in Driver Verifier log files.

Windows 2000 Driver Verifier Manager

To view global counters, select the Global Counters tab. This tab includes almost all of the global counters. (However, the Not Tracked Allocations counter is on the Pool Tracking screen, and the 95% special pool alert is on the Driver Status screen, as described immediately below.)

Windows XP Driver Verifier Manager

To view global counters, start Driver Verifier Manager and select the Display information about the currently verified drivers task. Then press Next twice.

Explanation of Global Counters

The following global counters monitor statistics related to the Forcing IRQL Checking option. These counters include actions performed since the last boot by all kernel-mode drivers that are currently being verified.

IRQL Raises
The number of times verified drivers raised the IRQL.
Spinlocks Acquired
The number of times verified drivers acquired spin locks.
Executions Synchronized
The number of times verified drivers synchronized the execution of a given routine with the ISR associated with a given interrupt object pointer.
Trims
The number of times Driver Verifier trimmed all pageable memory.

The following global counter monitors a statistic related to the Low Resources Simulation option.

Faults Injected
The total number of resource allocations failed deliberately by Driver Verifier since the last boot. (This only applies to kernel-mode drivers, not to graphics drivers.)

The following global counters monitor statistics related to the Special Memory Pool option. These counters always reflect the allocations attempted since the last boot by all kernel-mode drivers that are currently being verified. Graphics drivers are not included in these totals.

Pool Allocations Attempted
The total number of memory allocations attempted by these drivers.
Pool Allocations Succeeded
The number of allocation attempts that succeeded.
Pool Allocations Succeeded in Special Pool
The number of allocation attempts that succeeded, and were assigned from the special pool.
Pool Allocations Without Tag
The number of times these drivers requested memory allocations but did not supply a pool tag. (Pool tags are always recommended for every allocation.)
Pool Allocations Failed
The number of allocation attempts that failed, due to lack of memory.

If Special Memory Pool is enabled, but less than 95% of all pool allocations have been assigned from the special pool, a warning will appear. In Windows XP, this warning will appear in a popup window on the Global Counters screen. In Windows 2000, this warning will appear on the Driver Status screen.

The following global counter monitors a statistic related to the Special Memory Pool and Memory Pool Tracking options. It will always be zero if Memory Pool Tracking is not active.

Pool Allocations Not Tracked
The number of untracked allocations from all drivers currently being verified. Allocations whose size is one page or larger are not tracked by Memory Pool Tracking and cannot be allocated from the special pool. The individual counters do not reflect these allocations. (In Windows 2000, this counter can be found on the Pool Tracking screen under the title Not Tracked Allocations.)


Monitoring Individual Counters

Individual counters are statistics which monitor some of the actions that Driver Verifier performs on drivers. These statistics are kept separately for each driver being verified.

Individual counters can be viewed by using the Verifier Command Line, or by using the Driver Verifier Manager graphical interface, which is different in Windows 2000 and Windows XP.

Verifier Command Line

To view individual counters, use the verifier /query command. This will show both individual counters and global counters.

Individual counters are also included in Driver Verifier log files.

Windows 2000 Driver Verifier Manager

To view individual counters, select the Pool Tracking tab. Then select the desired driver from the drop-down box.

Windows XP Driver Verifier Manager

To view individual counters, start Driver Verifier Manager and select the Display information about the currently verified drivers task. Then press Next three times.

Finally, select the desired driver from the drop-down box.

Explanation of Individual Counters

Individual counters monitor statistics related to the Memory Pool Tracking option. They will all be zero if this option is not active.

These statistics are divided into two sections: Paged Pool and Nonpaged Pool. For each type of memory pool, the following four counters are shown:

Current Number of Allocations
The current number of individual allocations made by the specified driver from this type of memory pool.
Peak Number of Allocations
The greatest number of individual allocations made at any single time since the last boot by the specified driver from this type of memory pool.
Current Bytes Allocated
The current number of bytes allocated to the specified driver from this type of memory pool.
Peak Bytes Allocated
The greatest number of bytes allocated at any single time since the last boot to the specified driver from this type of memory pool.

Allocations whose size is one page or larger are not tracked by Memory Pool Tracking and cannot be allocated from the special pool. These individual counters do not reflect these large allocations. A count of all such allocations can be seen in the global counters.


Creating Log Files

Driver Verifier can create log files. These files will contain periodic updates on a number of statistics related to Driver Verifier's actions and the actions of the drivers being verified.

Log files are created from the Verifier utility by using the /log parameter. The frequency of the log record can be specified as well. See Verifier Command Line for details.

Each entry will contain both global counters and individual counters, just as with the verifier /query command.

For an explanation of these statistics, see Monitoring Global Counters and Monitoring Individual Counters.


Debuggers

This section includes:

Debugging Tools for NT-Based Operating Systems

Debugging Tools for Windows 98/Me

Hardware Requirements for Debugging


Debugging Tools for Windows 98/Me

For debugging on Windows® 98/Me, you should use the Windows System Debugger (debugger.exe, wdeb386.exe, wdeb98.exe).

Several other tools, such as the AMLI Debugger, are also available for use on Windows 98/Me. See Windows Me Debugger and Other Tools for full details on these tools.

In addition, the Microsoft Visual Studio® debugger can be used to debug user-mode programs on all Windows operating systems. See the Visual Studio documentation for details on this debugger.


Hardware Requirements for Debugging

User-mode drivers can be debugged with a single computer and either the free or checked build of the operating system. Debugging a kernel-mode driver, however, requires two machines, a target computer and a host computer. The target computer runs the driver or another kernel-mode application. The host computer runs the debugger.

Hardware Requirements for Debugging an NT-Based Operating System

The NT-based operating systems are available in two versions: the free build and the checked build. The checked build has many additional features that make it very useful to run on a computer being debugged. For full details, see The Checked Build of Windows.

Kernel debugging does not require specific combinations of the free or checked builds. You can debug a free build product from a free or checked system or debug a checked build product from a free or checked system. However, it is often better to debug a driver on a checked build to look for bugs, and to test it on a free build to check its performance.

The following figure shows the typical setup for debugging a kernel-mode driver. Windows 2000 will only support a null modem connection, but Windows XP and later will also support a 1394 connection.

Typical NT-Based Debugging Setup

For full details on hardware and software requirements for debugging, see the documentation accompanying the Debugging Tools for Windows package.

Testing on Multiple Target Computers

All drivers that will run on the NT-based operating system should be debugged and tested on both single-processor and multiprocessor computers. In addition, it's a good idea to test on the various operating system product suites, such as Personal, Professional, Server, and Advanced Server.


DevCtl

The Device Path Exerciser, or DevCtl, is a program designed to crash drivers by calling them through various user-mode I/O interfaces. It does not test the functionality, but rather the robustness of drivers. Drivers should be resilient to bad data from user mode in exactly the same way that kernel entry points have to be. If they are not resilient then they open up denial of service attacks and in some cases a mechanism to bypass system security. This program identifies drivers that do not handle the following calls properly:

  • Unexpected entry points into the driver, such as file system query functions directed to a sound card
  • Query functions with buffers that are too small to contain all the data to be returned
  • IOCTL/FSCTL functions with missing buffers, buffers that are too small, or buffers that contain meaningless information
  • IOCTL/FSCTL with direct I/O or type3 buffers with data changing asynchronously
  • IOCTL/FSCTL with bad pointers for type3 requests
  • IOCTL/FSCTL and fast path query functions where the user buffer mapping may change asynchronously, causing pages to become unreadable at arbitrary execution points
  • Relative opens with strange file names or opens to strange device objects like the direct device open or file system devices
  • Issues requests both synchronously and asynchronously to the device

DevCtl checks to make sure that the above calls are handled properly, and do not result in any of the following events:

  • System crash occurred.
  • System memory pools are corrupt.
  • Memory has leaked.
  • IRPs are not completed correctly.

While DevCtl runs, it writes lines to the file crashn.log. After each line is written, this log file is flushed. As a result, if a crash occurs, the offending operation is easy to determine even if the system proves difficult to debug. The flush operation is expensive so in some places only one portion of a block of operations is logged. For example, only logs for IOCTL for a particular function value are logged rather than each IOCTL. When the DevCtl program is restarted, it takes the last line from crashn.log and places it in the file crash.log. The DevCtl program assumes the operation in line to be a failed operation. Operations within crash.log are not performed again, by default.

After each operation is performed, the program performs a check on consumed system memory. DevCtl queries the pool tag database and look-aside information. If this operation caused either one of these memory sources to be depleted, the operation is repeated. Note that this increase in memory consumption may have had nothing to do with the request that was just performed. Typically, the second call does not see an increase and the program continues. Real memory leaks arise as a vast number of repeated calls, and the tag in question being raised to the top of the poolmon display sorted by difference (d).

For calls that would typically be buffered I/O operations, the program tracks the number of exceptions the operating system has dispatched. If the number of exceptions increases, the operation is also repeated. Although buffered I/O operations may also reference the user's address space, this is rare. Note that exception dispatching may signal an internal error that is being handled by an exception handler. Such a situation may hide a TRUE parameter or handle a validation problem. DevCtl can run with the bottom hardware page mapped so that NULL pointer dereferences do not raise exceptions, but rather return meaningless information.

Candidates for pool leaks and exceptions are logged to a file, diags.txt, which may be useful in the event that the leak does not crash the system or the many repeated calls are missed by the user. The program's basic execution passes are:

  • Issue synchronous, asynchronous, direct, and relative opens, using various file names. These catch drivers are unaware of the relative open semantics and the fact that they have to perform their own security checks. This also shows us drivers that may have word integer overflow problems manipulating file names.
  • Issue queries for possible items the driver might understand.
  • Issue miscellaneous functions with file handles like: flush, create section, read, and write (for asynchronous handles only). Reads and writes for obscure file offsets are performed. These include: append writes where the file offset is a 2^64-1, and reads and writes where the offset is an unsigned 63-bit quantity that wraps to a signed 64-bit value when the length is added on. These catch read and write paths that do not recognize the full semantics of file offsets or have overflow problems in their validation.
  • Issue miscellaneous handleless functions such as NtDeletefile, NtQueryFullAttributesFile, and so on. These functions exercise some of the fast open paths used for network queries and so on.
  • Issue an IOCTL and FSCTL pass with zero length input and output buffers. This pass detects the most common driver error of not checking buffer length properly.
  • Issue random IOCTL and FSCTL calls with random size buffers. For buffered I/O requests, the buffers are valid but contain random data. For direct I/O requests, the buffers are valid, contain random data that changes asynchronously with this thread execution, and are butted to the ends of H/W pages to make it more likely for references beyond buffer end to fail.
  • For type 3 buffers, the pointers are random.

After IOCTL passes, DevCtl issues a cancel request to the driver as part of a "miscellaneous function calls pass". IRPs that were lost (never completed by calling IoCompleteRequest or passed to other drivers but finished by the device) will cause the process to hang. Some execution paths may lead to dialog boxes appearing from the I/O manager warning that IRPs did not cancel within an allotted time. These lost IRPs are easily debugged by issuing "!process 0 0" from the debugger. Select the DevCtl process via a "!process xxx" where xxx is the Client ID (CID). The IRP (possibly more than one) will show up queued to one of the DevCtl's threads. Use "!irp xxx" where xxx is the IRP address to determine what IRP was lost. Occasionally IOCTL or FSCTL requests will pass parameter validation by a driver and will be pending for a synchronous request (for instance, some type of notify request to a driver). Pressing CTRL+C will cause the program to terminate in this case, but not in a lost IRP case.

The basic syntax for the program is:

devctl [/i] [/l] [/il nn] [/iu mm] [devnam]

Use / or + to enable an option. Use - to disable an option.

/a
Examine all devices in system. Don't prompt for yes/no.
/al
Alert the main thread periodically.
/c
Enable or disable skipping operations that aborted or crashed.
/dd
Enable or disable the direct device open paths.
/dl nn
Sets maximum limit for device type portion of IOCTL/FSCTL code, default zero.
/du nn
Sets minimum limit for device type portion of IOCTL/FSCTL code, default 200.
/e
Enable or disable zero length EA's, needed on checked builds.
/f
Enable or disable all FSCTL paths.
/fi
Enable or disable turning on failure injection in the driver verifier.
/fn
Enable or disable FSCTL paths with null buffers.
/fr
Enable or disable FSCTL paths with random buffers.
/fl nn
Sets maximum limit for function portion of IOCTL and FSCTL code, default zero.
/fu nn
Sets minimum limit for function portion of IOCTL and FSCTL code, default 200.
/g c h
Grabs a handle from another process.
/h /?
Prints this message.
/i
Enable or disable all IOCTL paths.
/if
Enable or disable all FSCTL and IOCTL paths.
/in
Enable or disable IOCTL paths with null buffers.
/il nnn
Set lower input buffer size.
/iu nnn
Set upper input buffer size.
/im
Enable or disable the impersonation of a non-admin during the test.
/ir
Enable or disable IOCTL paths with random buffers.
/j
Enable or disable relative stream opens for file systems.
/k
Enable or disable synchronous handles.
/l
Enable or disable logging and skipping failing functions.
/m
Enable or disable miscellaneous functions.
/n
Map zero page so that NULL pointer dereferences do not raise.
/ol nnn
Set lower output buffer size.
/ou nnn
Set upper output buffer size.
/p
Enable or disable the checks on pool usage through tags and look-aside lists.
/pd
Print out device objects and symbolic links and exit.
/pr
Enable or disable protection change tests.
/ps sss
Set prefix string for use with /pd.
/q
Enable or disable the normal handle query functions.
/r
Enable or disable skipping operations that are already logged as done.
/rd
Select a random device object or symbolic link for testing.
/s
Enable or disable the sub or relative opens to obtain handles.
/sd
Enable or disable the query and set security functions.
/sl
Enable or disable the opening of symbolic links.
/se nnn
Set session ID to "nnn."
/t nn
Set maximum limit for IOCTL/FSCTL calls made with random buffers, default 100000.
/tt nn
Set maximum limit for tailored calls made for discovered IOCTLs/FSCTLs, default 10000.
/v
Enable or disable the printing of error status values for calls.
/w
Enable or disable the Winsock TransmitFile test.
/y
Enable or disable touching disk devices.

The default settings are:

devctl -a -al +c +dd +dl 0 +du 200 +e +fn +fr +fl 0 fu 200 +im +il 0 +in +iu 512 +ir -j -k +l +m -n +ol 0 +ou 512 +p -pr +q +s +sd +sl +t 100000 +tt 10000 -v -w +y

Devnam is the device to open to issue requests. It must be in native object tree format like '\device\null'. If this is omitted the program prompts for each device in turn. You can skip to a particular device by typing '/prefix' where prefix is the first few characters of the device you want to match. Here is a typical run:

E:\devctl>obj\i386\devctl \device\null
Listen socket on port 1192 address 172.31.236.194
Trying to open device \device\null synchronous
Opened crashn.log for reading
Lookaside: PooL, size 128 up 2
Pool: Mdl , Paged up 0, NonPaged up 128
\device\null Open synchronous
Opened file \device\null with access 1f03ff
Pool: File, Paged up 0, NonPaged up 192
Pool: CcBc, Paged up 0, NonPaged up 160
\device\null NtQueryObject ObjectNameInformation
NtQueryObject failed c0000004
NtQueryObject failed c0000004
Lookaside: Pool, size 128 up 1
NtQueryObject failed c0000004
\device\null NtQueryInformationFile FileBasicInformation
\device\null NtQueryInformationFile FileStandardInformation
\device\null NtQueryInformationFile FileInternalInformation
… …E:\devctl>obj\i386\devctl
Listen socket on port 1194 address 172.31.236.194
Open device Cdfs? /null
Matching "null" against "Cdfs"
Matching "null" against "000126"
Matching "null" against "ASYNCMAC"
Matching "null" against "Afd"
Matching "null" against "Beep"
Matching "null" against "CdRom0"
Matching "null" against "DmLoader"
Matching "null" against "Floppy0"
Matching "null" against "FloppyPDO0"
Matching "null" against "FsWrap"
Matching "null" against "FtControl"
Matching "null" against "Gpc"
Matching "null" against "Hal Pci 0"
Matching "null" against "IdeDeviceP0T0L0"
Matching "null" against "IdeDeviceP1T1L0"
Matching "null" against "IdeFdo809a1288Channel0"
Matching "null" against "IdeFdo809a1288Channel1"
Matching "null" against "IdePort0"
Matching "null" against "IdePort1"
Matching "null" against "Ip"
Matching "null" against "KeyboardClass0"
Matching "null" against "KsecDD"
Matching "null" against "LanmanDatagramReceiver"
Matching "null" against "LanmanRedirector"
Matching "null" against "LanmanServer"
Matching "null" against "Mailslot"
Matching "null" against "MountPointManager"
Matching "null" against "Mup"
Matching "null" against "NTPNP_PCI0000"
Matching "null" against "NamedPipe"
Matching "null" against "Ndis"
Matching "null" against "Null"
Open device Null? y
Trying to open device Null synchronous
Opened crashn.log for reading
Lookaside: Pool, size 32 up 4
Pool: AfdC, Paged up 0, NonPaged up 192
\Device\Null Open synchronous
Opened file Null with access 1f03ff
Pool: File, Paged up 0, NonPaged up 192
\Device\Null NtQueryObject ObjectNameInformation
NtQueryObject failed c0000004
NtQueryObject failed c0000004
Lookaside: Pool, size 128 up 1
Lookaside: Pool, size 192 up 1
NtQueryObject failed c0000004
\Device\Null NtQueryInformationFile FileBasicInformation
\Device\Null NtQueryInformationFile FileStandardInformation
\Device\Null NtQueryInformationFile FileInternalInformation
\Device\Null NtQueryInformationFile FileEaInformation
\Device\Null NtQueryInformationFile FileAccessInformation
\Device\Null NtQueryInformationFile FileNameInformation
\Device\Null NtQueryInformationFile FileModeInformation
\Device\Null NtQueryInformationFile FileAlignmentInformation
Lookaside: PooL, size 128 up 1
Pool: Sect, Paged up 128, NonPaged up 0
Pool: CcSc, Paged up 0, NonPaged up 320
\Device\Null NtQueryInformationFile FileAllInformation
\Device\Null NtQueryInformationFile FileStreamInformation
Pool: VadS, Paged up 0, NonPaged up 32
\Device\Null NtQueryInformationFile FilePipeInformation
\Device\Null NtQueryInformationFile FilePipeLocalInformation
\Device\Null NtQueryInformationFile FilePipeRemoteInformation
E:\devctl>

Here is a sample leak:

C:\>g:\nt\nttest\security\tiger\devctl\obj\i386\devctl -if
…
Open device \Device\000167? /dfs
…
Open device \Dfs? y
…
\Dfs Open synchronous
Opened file Dfs with access 1f03ff
…
\Dfs NtQueryVolumeInformationFile FileFsVolumeInformation
Pool: Mup , Paged up 0, NonPaged up 131136
Lookaside: Scs$, size 64 up 2
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Hal , Paged up 0, NonPaged up 288
Pool: Irp , Paged up 0, NonPaged up 384
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Lookaside: Ntfi, size 264 up 1
Pool: Mup , Paged up 0, NonPaged up 130944
Lookaside: Ntfi, size 264 up 2
Lookaside: Scs$, size 64 up 1
Pool: Mup , Paged up 0, NonPaged up 131008
Pool: Mup , Paged up 0, NonPaged up 129536
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131008
Lookaside: Ntfi, size 264 up 1
Lookaside: Scs$, size 64 up 1
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 130752
Pool: Mup , Paged up 0, NonPaged up 130944
Pool: Mup , Paged up 0, NonPaged up 131008
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Lookaside: PooL, size 256 up 1
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Lookaside: Scs$, size 64 up 2
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Hal , Paged up 0, NonPaged up 288
Pool: Irp , Paged up 0, NonPaged up 768
^C

Memory: 65080K Avail: 3424K PageFlts: 0 InRam Krnl: 4632K P: 1916K
Commit: 52972K Limit: 666632K Peak: 108844K Pool N: 6312K P:10324K
Tag Type Allocs Frees Diff Bytes Per Alloc

Mup Nonp 84551 ( 0) 9870 ( 0) 74681 4779584 ( 0) 64
SYSA Paged 2227 ( 0) 750 ( 0) 1477 67136 ( 0) 45
CM Paged 6542 ( 0) 5854 ( 0) 688 8877504 ( 0) 12903
Vad Nonp 1460 ( 0) 1000 ( 0) 460 29440 ( 0) 64
File Nonp 3434 ( 0) 3137 ( 0) 297 57024 ( 0) 192

C:\>type diags.txt
\Dfs NtQueryVolumeInformationFile FileFsAttributeInformation Pool: Mup , Paged up 0, NonPaged up 65600

Note that the IOCTL and FSCTL passes take a very long time since the space is huge. You can get much quicker coverage if you know the range of IOCTLs that the driver accepts. Here is the procedure with IPNAT:

//
// NAT-supported IOCTL constant declarations
//
#define IOCTL_IP_NAT_SET_GLOBAL_INFO \
_IP_NAT_CTL_CODE(0, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_IP_NAT_CREATE_INTERFACE \
_IP_NAT_CTL_CODE(2, METHOD_BUFFERED, FILE_WRITE_ACCESS)
… … #define IOCTL_IP_NAT_DELETE_REDIRECT \
_IP_NAT_CTL_CODE(13, METHOD_BUFFERED, FILE_WRITE_ACCESS)

The first number in this macro is the function number. You can limit DevCtl to just cover this range with a command like devctl +fl 0 +fu 13. This limits both the IOCTL and FSCTL zero-length and random buffer calls. This will run very quickly; consider increasing the number of random buffers that the program gives the driver by +t nnnn, for instance.


Disabler

Disabler, or disabler.exe, is a command-line tool that repeatedly disables and re-enables (or, optionally, removes/refreshes) a Device Manager object for use in testing how that driver responds to many load/unload events. This test works on both Microsoft® Windows® 2000 and Microsoft Windows 98.

Note WHQL is currently using this tool for some of their programs.

Implementation

The core of the program revolves around a CM_DisableDevNode() and CM_Enable_DevNode() loop. The test first looks for all the devices it can test. Certain classes of devices are not testable in this fashion; for example, devices whose classes are SYSTEM will not be tested. Excluded classes include SYSTEM, VOLUME, LEGACYDRIVER, DISPLAY, MONITOR, CDROM, FDC, and FLOPPYDISK.

The core algorithm of the test is as follows.

  • Get information on the device being tested (status and problem code, and so on).
  • Get information about the device's children (again, status and problem code, and so on).
  • Disable that device, or remove this device.
  • Wait (this delay time is settable).
  • Enable this device or refresh its parent.
  • Wait (allow for the device's children to re-enumerate and restart).
  • Check that all the children came back and are working by checking the problem code, status code, and so on.
  • Check that the device node came back and is working by checking the problem code, status code, and so on.
  • (Optional) Launch a child test and record its log file (see the following Usage section).
  • Repeat (the number of repetitions is programmable; see the following Usage section).

Usage

This test can take either command-line arguments or a path to an .ini file as arguments.

Here are a list of command-line arguments the test will take. Note, you can get a list of command line arguments by running with /?.

/?
Display this Help message.
/cl:
Test only the class specified.
/et:
Specify an external test.
/el:
Specify an external test log file.
/lf:
Specify the log file name.
/dc:
Specify the number of times to disable each device.
/dl:
Specify the delay time between CM actions (in milliseconds).
/rm
Specify the disable method to be REMOVE.
/dis
Specify the disable method to be DISABLE.

If there are no arguments, it will prompt the user for test parameters, which include the device name, device class, number of repetitions (the number of times to disable and enable these devices), test method (remove or disable), and delay time (count of milliseconds to wait between disabling and re-enabling the device).

Note To start the test using an .ini file, you can use the full path of the .ini file (C:\Foo\Inifile.ini), or you can drag the file to the test icon. See Sample.ini for details.

The selections are as follows:

RepetitionCount=10
The number of times to iterate through the test.
Delay=3000
Delay time (in milliseconds) between disable and enable.
ClassToTest=USB
This test will test all devices of class USB.
ExternalTest=
If there is an entry, will run this test between every start/stop iteration. For example, when testing net cards, you can create a .bat file to ping some server and pipe the results to a file.
ExternLogFileName=
If there is an entry, will report on the results of the external test by adding this log file to the test log.
LogFileName=c:\windows\desktop\dis-samp.log
The log file name and location.

Results

Reading the results of a test can be rather cryptic sometimes.

The test will fail if:

  • The machine bug checks. This is the most common form of failure. For more information, see Bug Check Codes.
  • The device's children failed to re-appear after a stop/start operation (that is, you are testing a USB HUB, and before the test there was a USB mouse plugged into the hub, and afterward, Device Manager cannot find the mouse).
  • The device or one of its children failed to restart properly. In this situation, the Device Manager shows an error code. Error codes are enumerated in Cfg.h.
  • There is a change in the status code of the device or one of its children — that is, if DN_LIAR gets set after a start/stop operation. Status codes are enumerated in Cfg.h.
  • The device cannot be disabled. Sometimes this is normal if the device is in use, so make sure no one's using that device while it's being tested.

Note Watch for memory leaks. Drivers can allocate memory, and not freeing memory on shutdown can cause a machine to leak a lot of memory in a very short time. Try using Poolmon for detection of memory leaks.


INF File Tools

This section includes:

ChkINF

GenINF


ChkINF

The INF File Syntax Checker, or ChkINF, is a Perl script that checks the structure and syntax of Microsoft® Windows® 2000 and Windows XP driver .inf files. Results are presented in HTML format, and include a list of the errors and warnings detected in each .inf file, with each error and warning shown next to the errant .inf file entry. Note that ChkINF does not support Windows 98 or Windows Me .inf files.

The ChkINF tool includes support for all .inf sections and directives that apply to all classes of devices.

In addition, ChkINF includes specific device class support for the following device classes:

  • 1394 Host Bus Controllers (class = 1394)
  • 1394 Devices that support the 61883 protocol (class = 61883)
  • 1394 Devices that support the AVC protocol (class = AVC)
  • Battery Devices (class = Battery)
  • CD-ROM Drivers (class = CDROM)
  • Disk Drives (class = DiskDrive)
  • Display Adapters (class = Display)
  • Dot4 Devices (class = Dot4)
  • Dot4 Printers (class = Dot4Print)
  • Floppy Disk Controllers (class = FDC)
  • Floppy Disk Drives (class = FloppyDisk)
  • Hard Disk Controllers (class = HDC)
  • Human Input Devices (class = HIDClass)
  • Imaging Devices (class = Image)
  • IrDA Devices (class = Infrared)
  • Keyboards (class = Keyboard)
  • Medium Changers (class = MediumChanger)
  • Memory Technology Drivers (class = MTD)
  • Mice (class = Mouse)
  • Modems (class = Modem)
  • Monitors (class = Monitor)
  • Multifunction Devices (class = Multifunction)
  • Multimedia (class = Media)
  • Multi-port Serial Adapters (class = MultiportSerial)
  • Network Adapters (class = Net)
  • Network Clients (class = NetClient)
  • Network Service (class = NetService)
  • Network Transport (class = NetTrans)
  • PCMCIA Adapters (class = PCMCIA)
  • PnP Printers (class = PnPPrinters)
  • Ports (both COM and LPT ports) (class = Ports)
  • Printers (class = Printer)
  • Processors (class = Processor)
  • 1394 Devices that support the SBP2 protocol (class = SBP2)
  • SCSI and RAID Controllers (class = SCSIAdapter)
  • Smart Card Readers (class = SmartCardReader)
  • Storage Volumes (class = Volume)
  • System Devices (class = System)
  • Tape Drives (class = TapeDrive)
  • USB (class = USB)
  • Windows CE USB Active Sync Devices (class = WCEUSBS)

ChkINF now includes checking for .inf files used for installing file system filter drivers. ChkINF includes specific class support for the following classes of file system filter drivers:

  • Activity Monitor File System Filters
  • Anti-Virus File System Filters
  • CFS Meta Data Server File System Filters
  • Compression File System Filters
  • Content Screener File System Filters
  • Continuous Backup File System Filters
  • Copy Protection File System Filters
  • Encryption File System Filters
  • File System Filters
  • HSM File System Filters
  • Open File Backup File System Filters
  • Physical Quota Management File System Filters
  • Quota Management File System Filters
  • Replication File System Filters
  • Security Enhancer File System Filters
  • Undelete File System Filters

For more information on file system filter drivers, see the Installable File System (IFS) Kit.

ChkINF has not been extensively tested. Review your results carefully.

Running the Tool

Because ChkINF is a Perl script, in order to use the tool you will need to obtain a Perl interpreter. ChkINF requires a Perl interpreter that is Version 5.003_07 or greater. ChkINF should work with any version of Perl 5.0 or greater, but has not been tested with any versions previous to 5.003_07.

ChkINF has been tested with the following Perl interpreters:

  • GNU Perl 5.005_02 compiled for Win32®
  • GNU Perl 5.6.0 compiled for Win32
  • Perl for Win32 5.003_07 from ActiveWare Internet Corp.

Microsoft neither endorses nor recommends any specific Perl interpreters.

ChkINF is located in the %DDKRoot%\Tools\Chkinf subdirectory, and should be executed from an MS-DOS® Command prompt.

A batch file, ChkINF.bat, is provided for smooth execution. This batch file can be executed by using the following syntax:

chkinf FileList [/L LogFile] [/B] [/LO] [/DC Options]

Parameters

FileList
Specifies the files to be used. This can be the name of a single .inf file or a directory name. If a directory is specified, ChkINF will look for all .inf files in this directory. Wildcards may be used (for example, net*.inf). ChkINF will first expand all wildcards, and then process all applicable .inf files.
/L LogFile
Specifies the name of the log file to be created.
/B
Causes the default browser to be launched. ChkINF results will be displayed in this browser.
/LO
Causes ChkINF to compare all copied files (CopyFiles) with Layout.inf.
/DC Options
Specifies the device class-specific options that ChkINF should use when checking .inf files. At present, the only supported option is NOFAX, which instructs ChkINF not to check any Fax keys present in modem .inf files.

Output

ChkINF produces three types of files at the end of the checking process.

  • Summary.htm. This is a single HTML file that lists all of the .inf files that were checked, along with the number of errors and warnings detected in each one. The name of each .inf file is linked to the respective .htm file described in the File Manifest section.
  • Individual .htm results files. For each checked .inf file, a file with the same name and an .htm extension is created. This includes a log of the results for that .inf file.
  • A log file. This will be created if the /L option is used on the ChkINF command line.

The individual .htm results files include the following sections:

Errors
A list of the errors found in the .inf file, along with the error message and the line in the .inf file where it was detected. Each error includes a link to its location in the Annotated INF section.
Warnings
A list of the warnings detected in the .inf file, along with the warning message and the line in the .inf file where it was detected. Each warning includes a link to its location in the Annotated INF section.
Sections included from other infs
A list of the sections included from other .inf files. Each section listed includes a link to its location in the Sections included from other infs section. This item is omitted if the .inf being checked did not include any sections from other .inf files.
Annotated INF
The complete source for the .inf file, with the warning and error messages displayed adjacent to the line where the warning or error was detected.
Sections included from other infs
The complete source for the included sections, with warning and error messages displayed adjacent to the line where the warning or error was detected. This section is omitted if the .inf file being checked did not include any sections from other .inf files.

These files are saved into the subdirectory htm, located off the directory from which ChkINF is invoked.

Limitations

ChkINF does not support Windows 98 or Windows Me .inf files. ChkINF will not accurately check .inf structure and syntax that is specific to Windows 98/Me .inf files.

The tool does not perform device-class-specific testing, with the exception of the device classes listed in the beginning of this topic.

ChkINF has been tested with the following Perl interpreters:

  • GNU Perl 5.005_02 compiled for Win32®
  • GNU Perl 5.6.0 compiled for Win32
  • Perl for Win32 5.003_07 from ActiveWare Internet Corp.

ChkINF now includes limited support for .inf files saved in Unicode format (including Unicode Big Endian and UTF8), but there are some existing problems with the support for extended characters. If problems are encountered with .inf files in Unicode format, save the file as an ASCII text file and then run the tool.

ChkINF must be executed on the target platform in order to accurately check sections included from other .inf files via Include and Needs directives.

ChkINF issues warnings for any sections that are not referenced by a directive elsewhere in the .inf file. This is a change from previous versions of the tool, which reported errors for un-referenced sections.

ChkINF does not check for all relevant Registry keys set by an .inf file. An .inf file that passes with no errors may not function correctly.

ChkINF incorrectly reports an error if a single named service uses different binary names on the x86 and IA-64 platforms.

File Manifest

Here is a description of the files used by ChkINF.

ChkInf.bat
Batch file for smooth execution. (See Running the Tool for the syntax used.)
ChkInf.htm
ChkINF readme (identical to this documentation).
ChkInf.pm
Main module.
InfFile.pm
ChkINF internal support module.
Infrastructure.pm
ChkINF internal support module.
InfSection.pm
ChkINF internal support module.
SmartGlob.pm
ChkINF internal support module.
1394.pm
1394 Host Bus Controllers device class specific module.
61883.pm
1394 devices that support the 61883 protocol device class specific module.
AVC.pm
1394 devices that support the AVC protocol device class specific module.
Battery.pm
Battery device class specific module.
CDROM.pm
CD-ROM device class specific module.
DiskDrive.pm
Disk Drive device class specific module.
Display.pm
Display device class specific module.
Dot4.pm
Dot4 device class specific module.
Dot4Print.pm
Dot4 printer device class specific module.
FaxReg.pm
Modem device class specific sub-module.
FDC.pm
Floppy Disk Controller device class specific module.
FloppyDisk.pm
Floppy Disk Drives device class specific module.
Generic.pm
"Generic" module for devices for which a device class specific module does not yet exist.
HDC.pm
Hard Disk Controllers device class specific module.
HIDClass.pm
Human Input Device device class specific module.
Image.pm
Image device class specific module.
Infrared.pm
Infrared (IrDA) device class specific module.
Keyboard.pm
Keyboard device class specific module.
Media.pm
Multimedia device class specific module.
MediumChanger.pm
Medium Changers device class specific module.
Modem.pm
Modem device class specific module.
Monitor.pm
Monitor device class specific module.
Mouse.pm
Mouse device class specific module.
MTD.pm
Memory Technology Driver device class specific module.
Multifunction.pm
Multifunction Devices device class specific module.
MultiportSerial.pm
Multi-port Serial Adapter device class specific module.
Net.pm
Net (network adapter) device class specific module.
NetClient.pm
Network Client device class specific module.
NetService.pm
Network Service device class specific module.
NetTrans.pm
Network Transport device class specific module.
PCMCIA.pm
PCMCIA Adapter device class specific module.
PnPPrinters.pm
PnP Printers device class specific module.
Ports.pm
Ports device class specific module.
Printer.pm
Printer device class specific module.
Processor.pm
Processor device class specific module.
SBP2.pm
1394 devices that support the SBP2 protocol device class specific module.
SCSIAdapter.pm
SCSI and RAID Controllers device class specific module.
SmartCardReader.pm
Smart Card Readers device class specific module.
System.pm
System device class specific module.
TapeDrive.pm
Tape Drives device class specific module.
USB.pm
USB device class specific module.
Volume.pm
Storage Volumes device class specific module.
WCEUSBS.pm
Windows CE USB Active Sync device class specific module.
ActivityMonitor.pm
Activity Monitor file system filter module.
AntiVirus.pm
Anti-Virus file system filter module.
CFSMetaDataSErver.pm
CFS Meta Data Server file system filter module.
Compression.pm
Compression file system filter module.
ContentScreener.pm
Content Screener file system filter module.
ContinuousBackup.pm
Continuous Backup file system filter module.
CopyProtection.pm
Copy Protection file system filter module.
Encryption.pm
Encryption file system filter module.
FSFilterSystem.pm
File System Filters module.
HSM.pm
HSM file system filter module.
OpenFileBackup.pm
Open File Backup file system filter module.
PhysicalQuotaManagement.pm
Physical Quota Management file system filter module.
QuotaManagement.pm
Quota Management file system filter module.
Replication.pm
Replication file system filter module.
SecurityEnhancer.pm
Security Enhancer file system filter module.
Undelete.pm
Undelete file system filter module.


GenINF

The INF File Creation Wizard, or GenINF, is a GUI-based tool that guides the user through the process of creating Microsoft® Windows® 2000 and Windows XP device driver INF files. Please note the Limitations section. GenINF does not generate fully valid INF files. However, the skeleton INF files it generates should help developers complete their device driver INF files.

GenINF supports all device classes, but includes specific support for only certain device classes. For a list of these classes, see the geninf.htm file that is located in the Tools\geninf subdirectory of the DDK.

The tool has not been extensively tested. Carefully review all INF files created by GenINF.

Running the Tool

GenINF is located in the \Tools subdirectory of the DDK installation directory. Because it is GUI-based, it can be executed from within the Windows® 2000 User Interface, or from the command prompt. GenINF takes no arguments.

Limitations

GenINF supports the creation of INF files for Windows® 2000 only. It does not create INF files for Microsoft Windows 95, Windows 98, or Windows NT 4.0.

GenINF creates single architecture INF files only. Multi-architecture INF files are not supported.

GenINF does not always create complete and fully functional INF files. Users should review all INF files created by GenINF, and modify as required. Users should expect to add additional INF directives, especially any directives that are device-class-specific or that contain device-class-specific information.

File Manifest

Here is a description of the files.

Geninf.exe
The executable file.
Geninf.htm
The documentation for this tool.


Writing Battery Miniclass Drivers

A battery typically has a pair of drivers: the generic battery class driver that Microsoft provides, and a miniclass driver written specifically for that individual type of battery.

The class driver defines the overall functionality of the batteries in the system and interacts with the Power Manager.

The miniclass driver handles device-specific functions such as adding and removing a battery, and keeping track of its capacity and charge. The miniclass driver exports routines that the class driver calls to get information about the devices it controls.

Information on writing battery class drivers is organized as follows:

Overview of System Battery Management

Interaction of Battery Class and Miniclass Drivers

Supplying Required Battery Miniclass Driver Functionality

DriverEntry Routine of Battery Miniclass Driver

AddDevice Routine of Battery Miniclass Driver

DispatchDeviceControl Routine of Battery Miniclass Driver

DispatchSystemControl Routine of Battery Miniclass Driver

Responding to Battery Class Driver Queries

Supplying Battery Device Notification

Unload Routine of Battery Miniclass Driver

Installing a Battery Driver


Overview of System Battery Management

Battery management involves the following system components:

  • The battery GUI, which presents status information to users and allows them to set battery options
  • The Power Manager
  • The composite battery driver, a kernel-mode driver supplied by Microsoft
  • The battery class driver, a kernel-mode driver supplied by Microsoft
  • Battery miniclass drivers for individual battery devices
  • Devices, including batteries and some Uninterruptible Power Supplies (UPS)

Components of Battery Management

Devices controlled by battery miniclass drivers include batteries and some UPS devices. Batteries can be primary (nonrechargeable) or secondary (rechargeable) cells. A UPS is, in essence, a system battery with a much larger capacity and a different alert threshold than a laptop battery. (For UPS units connected to COM ports, writing a UPS minidriver is preferable to writing a battery miniclass driver.)

As shown in the preceding figure, the role of each component in battery operations is as follows:

  • A bus driver and one or more optional filter drivers, such as an ACPI filter, might be layered between the device and its miniclass driver.
  • A battery miniclass driver is the function driver for a specific type of battery or UPS device. A system can have as many battery miniclass drivers as it has different types of batteries.
  • The composite battery driver keeps track of the status of all the batteries in the system and acts as an intermediary between the Power Manager and the battery class/miniclass drivers. The composite battery driver receives IRPs from the Power Manager and notifies the Power Manager when the battery status changes (for example, when system battery power becomes critically low). The composite battery driver interacts with the battery class driver in much the same way that a battery miniclass driver does, but it is transparent to other miniclass drivers. The system has one composite battery driver, supplied by Microsoft.
  • The battery class driver supports all the battery miniclass drivers and the composite battery driver. The system has one battery class driver, supplied by Microsoft.
  • The Power Manager sends power and Plug and Play (PnP) IRPs to battery device stacks through the composite battery driver. The Power Manager does not interact directly with the battery class or miniclass drivers; all IRPs are sent through the composite battery driver.
  • The battery GUI gets system battery status from the composite battery driver through the Power Manager and presents the information to the user. The GUI also sends IRPs to the battery miniclass drivers for device-specific information. The system has one battery GUI, supplied by the hardware vendor.


Interaction of Battery Class and Miniclass Drivers

Together, the battery class driver and the miniclass driver manage the computer's use of a battery. The following figure shows how these two drivers interact.

Interaction of Battery Class and Miniclass Drivers

The miniclass driver is the primary function driver for the devices it controls. It receives IRPs from the Power Manager through the composite battery driver and calls support routines in the battery class driver to register its devices, to report status, and to handle certain system-defined battery IOCTLs.

The class driver receives information and status from all the miniclass drivers and reports it to the Power Manager through the composite battery driver. In response to battery IOCTLs, the class driver calls battery miniclass driver routines (BatteryMiniXxx routines) in the miniclass drivers to perform specific device control operations. Additionally, applications such as the power meter can send IRP_MJ_DEVICE_CONTROL requests to a miniclass driver to get information about a specific battery.

The class driver is designed to handle the superset of possible battery information and conditions, including temperature, changes in capacity, and so forth; individual batteries vary in their ability to detect and report all these conditions. Each miniclass driver should be designed to manage its specific battery type and must respond appropriately to the class driver when asked for any information that the battery does not support.


Battery Class Driver Functionality

The kernel-mode battery class driver, battc.sys, provides device-independent battery support and exports support routines for use by all device-specific battery miniclass drivers.

The battery class driver takes care of the following tasks for miniclass drivers:

  • Performing a large part of miniclass driver initialization, including allocating system resources and space for the miniclass driver's class data
  • Handling device control IRPs (IRP_MJ_DEVICE_CONTROL) that specify battery class IOCTLs. (See the Platform SDK for information on these IOCTLs.)
  • Serializing requests to the battery device
  • Administering DC power policy for the operating system
  • Freeing system resources if the miniclass driver is unloaded
  • Handling certain standard battery WMI classes

See Battery Miniclass Driver Routines for descriptions of the routines that the battery class driver exports to battery miniclass drivers.


Battery Miniclass Driver Functionality

A battery miniclass driver is responsible for the following:

  • Creating an FDO for its devices and storing device-specific information in the associated device extension
  • Assigning and maintaining the battery tag for the current battery
  • Keeping track of battery capacity, charge, and power state
  • Responding to requests from the class driver for battery status information
  • Notifying the battery class driver when the power state of the battery changes
  • Charging or discharging a specific battery when requested

A battery miniclass driver calls the battery class driver's support routines for other operations, such as handling IOCTLs, as described in Battery Class Driver Functionality.

Every battery miniclass driver provides a set of BatteryMiniXxx routines. The battery class driver calls these routines to request that the miniclass driver perform device-specific tasks. In addition, the miniclass driver must have other routines, as described in Supplying Required Battery Miniclass Driver Functionality.


Supplying Required Battery Miniclass Driver Functionality

In addition to the routines required to support Plug and Play, a battery miniclass driver must have the following routines:

DriverEntry

AddDevice

DispatchDeviceControl

DispatchSystemControl

BatteryMiniQueryTag

BatteryMiniQueryStatus

BatteryMiniQueryInformation

BatteryMiniSetInformation

BatteryMiniSetStatusNotify

BatteryMiniDisableStatusNotify

Unload

DriverEntry, Unload, DispatchDeviceControl, and AddDevice are standard driver routines. The name DriverEntry is required, so that the operating system can call it upon starting the driver. You can choose names for the other driver routines at your discretion, as long as their addresses are loaded properly in the appropriate data structures.

The BatteryMiniXxx routines are supplied by the miniclass driver and called by the battery class driver. When writing a miniclass driver, you can choose not to implement the functionality of any of these routines; however, an entry point for the routine must nevertheless be provided, and the routine must return STATUS_NOT_SUPPORTED. Prototypes for these routines appear in batclass.h.

Battery miniclass drivers must include the following header files:

  • batclass.h
  • ntddk.h or wdm.h


DriverEntry Routine of Battery Miniclass Driver

The DriverEntry routine initializes the miniclass driver.

The miniclass driver's DriverEntry routine sets up the following driver-specific entry points:

  • The Unload routine in DriverObject->DriverUnload
  • The driver's AddDevice routine in DriverObject->DriverExtension->AddDevice
  • The DispatchPower routine in DriverObject->MajorFunction[IRP_MJ_POWER]
  • The DispatchPnP routine in DriverObject->MajorFunction[IRP_MJ_PNP]
  • The DispatchCreate routine in DriverObject->MajorFunction[IRP_MJ_CREATE]
  • The DispatchClose routine in DriverObject->MajorFunction[IRP_MJ_CLOSE]
  • The DispatchDeviceControl routine in DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]
  • The DispatchSystemControl routine in DriverObject->MajorFunction[IRP_MN_SYSTEM_CONTROL].

The following sample code initializes these entry points for a hypothetical NewBatt miniclass driver:

DriverObject->DriverUnload = NewBattUnload;
DriverObject->DriverExtension->AddDevice = NewBattAddDevice;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NewBattDispatchDeviceControl;
DriverObject->MajorFunction[IRP_MJ_CREATE] = NewBattDispatchCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = NewBattDispatchClose;
DriverObject->MajorFunction[IRP_MJ_PNP] = NewBattDispatchPnp;
DriverObject->MajorFunction[IRP_MJ_POWER] = NewBattDispatchPower;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = NewBattSystemControl;

Because battery-specific state information is not known until the PnP Manager calls the miniclass driver's AddDevice routine, the DriverEntry routine does not initialize any such state. Device-specific initialization is performed in the AddDevice routine.

For additional routine-specific requirements, see the following topics:

AddDevice Routine of Battery Miniclass Driver

DispatchDeviceControl Routine of Battery Miniclass Driver

DispatchSystemControl Routine of Battery Miniclass Driver

Unload Routine of Battery Miniclass Driver

DispatchPower

DispatchPnP

DispatchCreate

DispatchClose


AddDevice Routine of Battery Miniclass Driver

Every battery miniclass driver must have an AddDevice routine, which initializes battery-specific state. The PnP Manager calls the AddDevice routine for each battery device controlled by this miniclass driver.

In addition to the tasks required of a PnP AddDevice routine, the AddDevice routine for a battery miniclass driver must also do the following:

  1. Create an FDO for the battery and attach the FDO to the device stack for the controller.
  2. Initialize the BATTERY_MINIPORT_INFO structure and call BatteryClassInitializeDevice to register the miniclass driver with the battery class driver.
  3. Perform any other initialization required for the device.


Creating an FDO in the Battery Miniclass Driver

The miniclass driver should create an FDO and attach it to the device stack for the device, as follows:

  1. Call IoCreateDevice to create an FDO for the current device, as follows:
    Status = IoCreateDevice(
         DriverObject,
         sizeof (DeviceExtension),
         NULL,
         FILE_DEVICE_BATTERY,
         0,
         FALSE,
         &Fdo
         );

    The input parameters to IoCreateDevice are a pointer to the driver object that was passed to the AddDevice routine, the size of the device extension, NULL in place of a device name, and the system-defined device type (FILE_DEVICE_BATTERY). Battery miniclass drivers can specify zero for the DeviceCharacteristics parameter, which is irrelevant to these drivers. More than one thread can send I/O requests to the battery, so the miniclass driver passes FALSE as the Exclusive parameter. IoCreateDevice returns a pointer to the created FDO.

  2. In the returned FDO, set flags and the stack size. For example:
    Fdo->Flags |= DO_BUFFERED_IO;
Fdo->Flags |= DO_POWER_PAGABLE;
Fdo->StackSize = Pdo->StackSize + 2;

    Setting the DO_BUFFERED_IO flag allows the miniclass driver to use buffered I/O for IRPs. Setting the DO_POWER_PAGABLE flag indicates that the driver is pageable and prevents it from getting power IRPs at IRQL >= DISPATCH_LEVEL. Finally, because battery IRPs require an additional stack location, miniclass drivers should set StackSize to the PDO stack size plus two, so that the driver can pass the IRP down to the PDO.

  3. Store the pointer to the device's PDO, the pointer to the FDO, the device type, the device name, and any other necessary state in the device extension. For example:
    NewBatt = (PNEW_BATT) Fdo->DeviceExtension;
NewBatt->Type = NEW_BATTERY_TYPE;
NewBatt->Fdo = Fdo;
NewBatt->Pdo = Pdo;
NewBatt->IsCacheValid = FALSE;

    The example stores the pointers to the FDO and PDO in the device extension. (The PnP Manager supplied a pointer to the PDO as the PhysicalDeviceObject pointer input to AddDevice.) In addition, the example above keeps track of its own battery type (NEW_BATTERY_TYPE, defined elsewhere in this hypothetical miniclass driver) and whether any cached information is valid.

    You determine the information stored in the device extension. For example, a smart battery driver might retain the number of batteries, a Boolean value indicating whether a battery selector is present, and, optionally, information about that battery selector.

  4. Call IoAttachDeviceToDeviceStack to attach the FDO to the device stack, then store the returned pointer, as follows:
    NewBatt->LowerDO = IoAttachDeviceToDeviceStack(Fdo,Pdo);

    The call returns a pointer to the next-lower device object, which this example stores in the device extension.

  5. Clear the DO_DEVICE_INITIALIZING flag in the FDO, as follows:
    Fdo->Flags &= ~DO_DEVICE_INITIALIZING;

    Clearing the DO_DEVICE_INITIALIZING flag allows the device object to be opened subsequently by components higher in the device stack.


Initializing the Battery Class Device

The AddDevice routine must initialize the battery class device and register the miniclass driver with the class driver. To do so, the miniclass driver calls the BatteryClassInitializeDevice routine. This call registers the miniclass driver with the class driver, so that the two drivers can use each other's support routines. This call also registers the battery device with the system so that it can be seen by the composite battery and the power meter.

BatteryClassInitializeDevice requires a pointer to a BATTERY_MINIPORT_INFO structure that contains the following information:

  • In MajorVersion and MinorVersion, the major and minor version numbers of the class driver that this miniclass driver supports.

    The version numbers are defined in batclass.h as BATTERY_CLASS_MAJOR_VERSION and BATTERY_CLASS_MINOR_VERSION, respectively.

  • In QueryTag, the entry point of the miniclass driver's BatteryMiniQueryTag routine.
  • In QueryInformation, the entry point of the miniclass driver's BatteryMiniQueryInformation routine.
  • In SetInformation, the entry point of the miniclass driver's BatteryMiniSetInformation routine.
  • In SetStatusNotify, the entry point of the miniclass driver's BatteryMiniSetStatusNotify routine.
  • In DisableStatusNotify, the entry point of the miniclass driver's BatteryMiniDisableStatusNotify routine.
  • In Context, a pointer to the miniclass driver's context information.

    The context information is typically a pointer to the FDO device extension, which is passed back to the miniclass driver each time the class driver calls a BatteryMiniXxx routine.

  • In Pdo, a pointer to the PDO for the device.
  • In DeviceName, a NULL parameter; PnP devices should not have names.

After setting up this structure, the miniclass driver attaches itself to the battery class driver by calling BatteryClassInitializeDevice, and passing a pointer to the BATTERY_MINIPORT_INFO structure. In return, it receives a handle to be used in subsequent calls to battery class driver support routines. The miniclass driver should store the returned class handle in nonpaged memory.

After calling BatteryClassInitializeDevice, the AddDevice routine might also need to initialize other device-specific data.


DispatchDeviceControl Routine of Battery Miniclass Driver

The Power Manager sends device control IRPs (IRP_MJ_DEVICE_CONTROL) to the miniclass drivers through the composite battery driver. The DispatchDeviceControl routine in the battery miniclass driver handles IRPs that contain battery IOCTLs.

In DispatchDeviceControl, the miniclass driver can call the class driver's BatteryClassIoctl routine to perform any system-defined device control tasks; BatteryClassIoctl handles device control IOCTLs for batteries.

The DispatchDeviceControl routine should do the following:

  1. If the miniclass driver defines any private IOCTLs, determine whether the current IOCTL is among them. If so, perform the requested operation, complete the IRP, specifying IO_NO_INCREMENT, and go to step 4.
  2. If the IOCTL is not a private IOCTL defined by the miniclass driver, call BatteryClassIoctl, passing the IRP and the class handle returned by BatteryClassInitializeDevice. For example:
    Status = BatteryClassIoctl (NewBattNP->ClassHandle, Irp);

    The class driver's BatteryClassIoctl routine determines whether the IOCTL is intended for the specified battery. If so, it calls the corresponding BatteryMiniXxx routine to satisfy the request and then completes the IRP, returning STATUS_SUCCESS. Otherwise, it returns STATUS_NOT_SUPPORTED.

  3. If BatteryClassIoctl returns STATUS_NOT_SUPPORTED, indicating that this is not a battery IRP, pass the IRP to the next-lower driver.
  4. Pass the returned status as its own function return value.


DispatchSystemControl Routine of Battery Miniclass Driver

Battery miniclass drivers must support Windows Management Instrumentation (WMI) by supplying a DispatchSystemControl routine to handle the IRP_MJ_SYSTEM_CONTROL IRP. WMI provides a uniform way for drivers to expose measurement and instrumentation data.

Battery miniclass drivers use the BatteryClassSystemControl routine to do initial processing. BatteryClassSystemControl takes a WmiLibContext parameter, which specifies a dispatch table of functions. The routine uses the MinorFunction member of IRP_MJ_SYSTEM_CONTROL to determine which dispatch function it calls.

There are certain WMI queries that all drivers for battery devices must handle. Battery miniclass drivers do not need to support these WMI queries directly, but instead forward them to the battery class driver to handle. To handle WMI queries, the miniclass driver provides a pointer to a DpWmiQueryDataBlock routine in the QueryWmiDataBlock member of WMILIB_CONTEXT. The miniclass driver is not required to handle any other type of WMI request. If it does not, the driver sets the other members of WMILIB_CONTEXT to zero.

Inside its DpWmiQueryDataBlock routine, the miniclass driver calls the BatteryClassQueryWmiDataBlock routine to allow the battery class driver to handle the WMI query request if it can. If the battery class driver handles that WMI class GUID, it completes the IRP. Otherwise, BatteryClassQueryWmiDataBlock returns a value of STATUS_WMI_GUID_NOT_FOUND. Then, the miniclass driver can do its driver-specific processing, and use WmiCompleteRequest to complete the request.

Battery miniclass drivers are not required to do any WMI IRP processing beyond calling BatteryClassQueryWmiDataBlock. In a minimal implementation of WMI handling for a battery miniclass driver, if BatteryClassQueryWmiDataBlock returns STATUS_WMI_GUID_NOT_FOUND, the miniclass driver simply calls WmiCompleteRequest with a status value of STATUS_WMI_GUID_NOT_FOUND.

The src\wdm\acpi\smbbatt\smbbatt directory of the DDK contains a sample of a battery miniclass driver that handles the IRP_MJ_SYSTEM_CONTROL request. In particular, the SmbBattQueryWmiDataBlock routine in the sample demonstrates a minimal implementation of a DpWmiQueryDataBlock routine.


Responding to Battery Class Driver Queries

The miniclass driver must provide the following three BatteryMiniXxx routines, which report battery status:

  • BatteryMiniQueryTag
  • BatteryMiniQueryInformation
  • BatteryMiniQueryStatus

The BatteryClassIoctl routine in the class driver calls these miniclass driver routines when it receives IOCTLs requesting information about the batteries.


Responding to Battery Tag Queries

The battery tag is a ULONG counter initialized and incremented by the miniclass driver. The battery class driver calls BatteryMiniQueryTag to request the current value of the tag.

This miniclass driver routine is declared as follows:

typedef
NTSTATUS
(*BCLASS_QUERY_TAG)(
    IN PVOID Context,
    OUT PULONG BatteryTag
    );

The Context parameter is a pointer to the context area that is allocated by the miniclass driver and passed to the class driver in the BATTERY_MINIPORT_INFO structure at device initialization (BatteryClassInitializeDevice). The BatteryTag value is created and maintained by the miniclass driver.

Each time a battery is inserted, the miniclass driver must increment the value of the tag, regardless of whether this is a new battery or the same battery that was previously present.

If no battery is present, or if the miniclass driver cannot determine whether a battery is present, the miniclass driver should return STATUS_NO_SUCH_DEVICE and set the value of the tag to BATTERY_TAG_INVALID.

The class driver uses the battery tag internally and in calls to the miniclass driver to identify a specific instance of a battery. The miniclass driver should check the value of the battery tag that is passed to each of its standard routines to ensure that it corresponds to the current battery. If the tag is incorrect, the miniclass driver should return STATUS_NO_SUCH_DEVICE.


Responding to Battery Information Queries

The battery class driver calls the BatteryMiniQueryInformation routine to get a variety of information about the current battery. This routine is declared as follows:

typedef
NTSTATUS
(*BCLASS_QUERY_INFORMATION)(
    IN PVOID Context,
    IN ULONG BatteryTag,
    IN BATTERY_QUERY_INFORMATION_LEVEL Level,
    IN LONG AtRate OPTIONAL,
    OUT PVOID Buffer,
    IN ULONG BufferLength,
    OUT PULONG ReturnedLength
    );

The Context parameter is a pointer to the context area that is allocated by the miniclass driver and passed to the class driver in the BATTERY_MINIPORT_INFO structure at device initialization. The BatteryTag parameter is a value previously returned by BatteryMiniQueryTag.

The Level parameter specifies the kind of information requested. The miniclass driver formats the information as a BATTERY_INFORMATION structure and returns it at the address supplied by Buffer, with a pointer to its length in ReturnedLength.

A miniclass driver should be prepared to handle requests for the following:

  • Battery capabilities, chemistry, capacity, low-capacity alert levels, and reserve charge
  • Temperature, in tenths of a degree Kelvin
  • Estimated remaining run time, in minutes
  • Device name
  • Manufacturer's battery model name
  • Date of manufacture
  • Unique ID
  • Serial number

Some batteries are not capable of reporting all this information. A miniclass driver should return STATUS_INVALID_DEVICE_REQUEST for any information that its device cannot supply.


Responding to Battery Status Queries

The battery class driver calls the miniclass driver's BatteryMiniQueryStatus routine to get the power state, capacity, voltage, and discharge rate of a battery. The following is the prototype for this routine:

typedef
NTSTATUS
(*BCLASS_QUERY_STATUS)(
    IN PVOID Context,
    IN ULONG BatteryTag,
    OUT PBATTERY_STATUS BatteryStatus
    );

The Context parameter is a pointer to the context area that is allocated by the miniclass driver and passed to the class driver in the BATTERY_MINIPORT_INFO structure at device initialization. The BatteryTag parameter is a value previously returned by BatteryMiniQueryTag.

In the buffered BATTERY_STATUS structure, the miniclass driver reports the battery's voltage, capacity, and charge/discharge rate to the extent that the miniclass driver can determine them. The miniclass driver also reports one or more of the following constants that describe the battery's power condition:

  • BATTERY_CHARGING
  • BATTERY_DISCHARGING
  • BATTERY_POWER_ON_LINE
  • BATTERY_CRITICAL

The miniclass driver should not report a critically low, discharging battery (BATTERY_CRITICAL and BATTERY_DISCHARGING) until it has ascertained that the condition is not merely a transitory fluctuation and has exhausted all other means of remedying the situation. Such remedies might include switching to AC power or to another battery, if the miniclass driver can do so.

When the miniclass driver reports a critically low, discharging battery, the Power Manager assumes that battery failure is imminent. If the battery supplies system power or is a secondary (rechargeable) cell, the system carries out the DC power policy for a critical battery. The details of the power policy vary from system to system, depending on hardware capabilities, application settings, and user preferences. Typically, the system attempts to enter a sleeping state or powers off the computer. For more information, see System Power Policy.

The class driver's BatteryClassStatusNotify routine and the miniclass driver's BatteryMiniQueryStatus, BatteryMiniSetStatusNotify, and BatteryMiniDisableStatusNotify routines are used in sequence by the two drivers to provide timely status information. For details, see Interaction of Battery Status and Notification Routines.


Supplying Battery Device Notification

The miniclass driver is responsible for monitoring the status of the batteries it supports and notifying the class driver when important changes occur.

In addition to the BatteryMiniQueryStatus routine, the miniclass driver also supplies the BatteryMiniSetStatusNotify and BatteryMiniDisableStatusNotify routines. The class driver uses the BatteryMiniSetStatusNotify and BatteryMiniDisableStatusNotify routines to request and cancel notification of specific battery states. These routines interact with the class and miniclass driver status routines as described in the next section. For more information on these two miniclass routines, see Setting and Canceling Battery Notification.


Interaction of Battery Status and Notification Routines

The class driver can request and receive battery status — and the miniclass driver can provide battery status — in several ways.

If the miniclass driver provides a BatteryMiniSetStatusNotify routine, the class driver can register to be notified when the battery's capacity exceeds or drops below a specified range, or when its power state changes. When any of the registered conditions occurs, the miniclass driver calls BatteryClassStatusNotify.

Note that BatteryClassStatusNotify does not supply status information; its only parameter is the context of the battery that triggered the notification. It merely informs the class driver that the battery's status has changed. In turn, the class driver calls BatteryMiniQueryStatus if it requires details.

If the miniclass driver does not support BatteryMiniSetStatusNotify, the class driver polls for status by calling the BatteryMiniQueryStatus routine at regular but infrequent intervals.

Independent of any notification requests, a miniclass driver must call BatteryClassStatusNotify whenever any of the following occurs:

  • The battery goes on line or off line.
  • The capacity of the battery becomes critically low.
  • The power state of the battery changes: it starts charging, starts discharging, stops charging, or stops discharging.

Before reporting a critically low, discharging battery, the miniclass driver should attempt to solve the problem, as described previously in Responding to Battery Status Queries.


Setting and Canceling Battery Notification

A miniclass driver provides a BatteryMiniSetStatusNotify routine so that the class driver can request notification of specific conditions. The routine is declared as follows:

typedef
NTSTATUS
(*BCLASS_SET_STATUS_NOTIFY)(
    IN PVOID Context,
    IN ULONG BatteryTag,
    IN PBATTERY_NOTIFY BatteryNotify
    );

The Context parameter is a pointer to the context area that is allocated by the miniclass driver and passed to the class driver in the BATTERY_MINIPORT_INFO structure at device initialization. The BatteryTag parameter is a value previously returned by BatteryMiniQueryTag.

The BatteryNotify parameter contains a set of flags indicating the battery power condition, and a pair of ULONG values that define a range of acceptable battery capacities. When the battery no longer satisfies the specified power conditions or its capacity goes above or below the specified range, the miniclass driver should call BatteryClassStatusNotify.

BatteryMiniSetStatusNotify should return STATUS_NOT_SUPPORTED for any conditions or trigger values that cannot be determined for this battery.

The class driver calls the BatteryMiniDisableStatusNotify routine to cancel notification of battery status changes previously requested by BatteryMiniSetStatusNotify. This routine is declared as follows:

typedef
NTSTATUS
(*BCLASS_DISABLE_STATUS_NOTIFY)(
    IN PVOID Context
    );

The Context parameter is a pointer to the context area allocated by the miniclass driver and passed to the class driver in the BATTERY_MINIPORT_INFO structure at device initialization.

Miniclass drivers can omit functionality for both routines and return STATUS_NOT_SUPPORTED. However, a miniclass driver that provides a BatteryMiniSetStatusNotify routine must provide a corresponding BatteryMiniDisableStatusNotify routine, and vice versa.


Unload Routine of Battery Miniclass Driver

The Unload routine for a battery miniclass driver ensures that all the driver's devices have been removed and frees any resources the miniclass driver has allocated.

The Unload routine should first check to ensure that all its devices have been removed and, if not, do the following for each remaining device:

  1. Call BatteryClassUnload to inform the class driver that the miniclass driver is unloading the device.
  2. Disable any device notifications from lower drivers, such as the ACPI driver, using that driver's interface.
  3. Delete the device object for the device by calling IoDeleteDevice, as follows:
        IoDeleteDevice (NewBatt->DeviceObject);

After all the miniclass driver's devices are unloaded, the Unload routine should free any resources allocated by the miniclass driver.

The miniclass driver's Unload routine can be called at any time after all the driver's devices have been removed. The PnP Manager calls the Unload routine in the context of a system thread at IRQL = PASSIVE_LEVEL.


Installing a Battery Driver

A battery driver's INF file specifies information about the driver and the devices it controls. All battery devices are members of the Battery class and the battery class installer installs the driver.

This section describes battery-specific entries in the INF file. For more information on creating and distributing INF files and installing drivers, see Creating an INF File and INF File Sections and Directives.

A battery driver's INF file includes the sections described below.

Version

A battery driver's INF file specifies the Battery class and its GUID, using the INF Version section, as shown in the following example:

[Version]
Signature="$WINDOWS NT$"
Class=Battery
ClassGuid={72631e54-78a4-11d0-bcf7-00aa00b7b32a}
Provider=%MyCo%

Note that %MyCo% must be defined in an INF Strings section (not shown).

DestinationDirs

In the INF DestinationDirs section, a battery driver's INF specifies the Drivers directory (12) as the default for all files.

[DestinationDirs]
DefaultDestDir = 12

Manufacturer

The INF Manufacturer section defines the manufacturer of the device.

[Manufacturer]
%MyCo%=MyCompany

Models

The INF Models section specifies the PnP hardware ID of the battery (shown as pnpid in the example). If the device is enumerated through ACPI, this section must also specify the EISA-style ID (shown as acpidevnum). For information on creating these IDs, see the Microsoft Web site.

[MyCompany]
%pnpid.DeviceDesc% = NewBatt_Inst,pnpid
%ACPI\acpidevnum.DeviceDesc% = NewBatt_Inst,ACPI\acpidevnum

DDInstall

In the INF DDInstall section (named NewBatt_Inst in the example), an INF CopyFiles directive copies the battery class driver (Battc.sys) and the new miniclass driver (NewBatt.sys) to the destination specified in the DestinationDirs directive.

[NewBatt_Inst]
CopyFiles = @NewBatt.sys
CopyFiles = @battc.sys

DDInstall.Services

The INF DDInstall.Services section includes an INF AddService directive that specifies additional information about the battery driver. A battery driver's INF file should indicate that the driver is a kernel driver that uses normal error handling and starts during initialization of the operating system. Battery drivers specify the load order group Extended Base.

[NewBatt_Inst.Services]
AddService = NewBatt,2,NewBatt_Service_Inst    ; function driver for the device

[NewBatt_Service_Inst]
DisplayName    = %NewBatt.SvcDesc%
ServiceType    = 1 ;    SERVICE_KERNEL_DRIVER
StartType      = 3 ;    SERVICE_DEMAND_START
ErrorControl   = 1 ;    SERVICE_ERROR_NORMAL%
ServiceBinary  = %12%\NewBatt.sys


Writing UPS Minidrivers

If an uninterruptible power supply (UPS) is connected to a Windows 2000 or later system, the UPS tab for Power Options in Control Panel provides information about the UPS. A system-supplied UPS service provides support for UPS units that are connected to COM ports and that support "simple signaling," which provides very limited control capabilities and status information.

If your UPS model supports "smart signaling," which provides enhanced control capabilities and status information, you should provide a UPS minidriver. This minidriver, which is a user-mode DLL called by the system's UPS service, has the following responsibilities:

  • Initializing the communication path to the UPS.
  • Updating registry entries that Power Options uses to obtain model-specific information to display.
  • Turning off the UPS power upon request.
  • Monitoring the UPS unit for state changes.

This section provides the following topics:

UPS Minidriver Functionality

UPS Registry Entries

Sample UPS Minidriver

Installing UPS Minidrivers


UPS Minidriver Functionality

A UPS minidriver must export the following set of functions, which are called by the system-supplied UPS service:

  • UPSInit
  • UPSGetState
  • UPSWaitForStateChange
  • UPSCancelWait
  • UPSTurnOff
  • UPSStop

Additionally, the minidriver must export a DLLMain function, as described in Platform SDK documentation.

Besides exporting these functions, the minidriver must provide initial values for UPS registry entries and then modify the values as necessary to reflect UPS state changes.

Typically, a UPS minidriver communicates with a UPS unit through a COM port by calling the CreateFile, ReadFile, and WriteFile functions (described in Platform SDK documentation). The minidriver is responsible for implementing whatever communication protocol the UPS unit supports.


UPS Registry Entries

UPS registry entries provide model-specific information about a system's UPS. A vendor-supplied UPS minidriver is responsible for supplying values for some of these registry entries, which are stored under the UPS service's tree.

The following registry key is the root of the UPS service tree:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\UPS

The UPS registry entries are organized under the following four keys:

  • UPS — Service Control Manager entries, and entries used by the Windows NT® 4.0 UPS service

    These entries are for system use only. Vendors must not modify these entries.

  • UPS\Config — Information pertaining to the configuration of the UPS service.

    These entries are for system use only. Vendors must not modify these entries.

  • UPS\Status Registry Entries — Status information.

    These entries are for vendor and system use. If vendors create and modify these entries as appropriate, Power Options displays them.

  • UPS\ServiceProviders Registry Entries — Entries for different vendor and model UPS devices.

    These entries are for vendor and system use. Vendors should create these entries while installing UPS minidrivers. The system's UPS service copies UPS model-specific values to other, system-controlled registry locations after an administrator has selected the UPS model for use.


UPS\Status Registry Entries

The following registry entries, under the UPS\Status key, must be set by UPS minidrivers.

BatteryCapacity

Value Name:
BatteryCapacity
Value Type:
REG_DWORD
Value:
The percent of battery capacity remaining in the UPS, represented as a value in the range of 0 through 100. (The displayed value is rounded to the nearest integer.)
Default Value:
0

BatteryStatus

Value Name:
BatteryStatus
Value Type:
REG_DWORD
Value:
The current status of the UPS batteries. Values are listed in the following table.
Value | Meaning
0 | The battery status is unknown.
1 | The batteries are OK.
2 | The batteries need to be replaced.

Default Value:
0

CommStatus

Value Name:
CommStatus
Value Type:
REG_DWORD
Value:
The status of the communication path to the UPS. Values are listed in the following table.
Value | Meaning
0 | The communication path to the UPS has failed.
1 | The communication path to the UPS is OK.

Default Value:
1

FirmwareRev

Value Name:
FirmwareRev
Value Type:
REG_SZ
Value:
Reports the UPS firmware revision as a displayable string.
Default Value:
""

SerialNumber

Value Name:
SerialNumber
Value Type:
REG_SZ
Value:
Reports the UPS serial number as a displayable string.
Default Value:
""

TotalUPSRuntime

Value Name:
TotalUPSRuntime
Value Type:
REG_DWORD
Value:
The amount of remaining UPS run time, in minutes.
Default Value:
0

UtilityPowerStatus

Value Name:
UtilityPowerStatus
Value Type:
REG_DWORD
Value:
Reports the status of utility-supplied power into the UPS. Values are listed in the following table.
Value | Meaning
0 | The status of utility-supplied power is unknown.
1 | Utility-supplied power is OK.
2 | A power failure has occurred.

Default Value:
0


UPS\ServiceProviders Registry Entries

Under the UPS\ServiceProviders registry key, a UPS vendor should create a vendor-specific subkey. Under this subkey, the vendor should create an entry for each UPS model. Vendors must create these registry entries while installing UPS minidrivers.

Each model-specific entry consists of a value name and a value. The value name should be the name of the UPS model. The value associated with this name is a string consisting of two parts:

  • The first part of the value string represents a hexadecimal bit mask identifying the model's capabilities. Bit values are defined in the following table.
    Bit Value | Description
    0x00000001 | The UPS is installed.
    0x00000002 | The UPS supports power failure notification.
    0x00000004 | The UPS supports notification of low battery power.
    0x00000008 | The UPS can be turned off using the serial port.
    0x00000010 | Power failure notification is indicated by a positive signal.
    0x00000020 | Low battery notification is indicated by a positive signal.
    0x00000040 | The UPS is turned off by a positive signal.
    0x00000080 | Reserved. Do not use.

  • The second part of the string is optional. It represents the path and name of the UPS minidriver. If this path and name is supplied, it must be preceded by a semicolon (;). If only the name is supplied, a default path of %SystemRoot%\system32 is used.

After a UPS minidriver has been installed, and after a system administrator has enabled the UPS using Power Options, the system's UPS service copies model-specific UPS\ServiceProviders values to other, system-controlled registry locations.

Following is an example of one vendor subkey, with value names and values for two UPS models, under UPS\ServiceProviders:

UPS\ServiceProviders

American Power Conversion

Back-UPS "0x7f"

Smart-UPS "0x1;apcups.dll"


Sample UPS Minidriver

TBS


Installing UPS Minidrivers

UPS minidrivers are user-mode DLLs that can be installed using Microsoft® Windows® Installer (described in Platform SDK documentation) or an INF file (see Creating an INF File).

One responsibility of the installation operation is to create UPS\ServiceProviders registry entries.


Battery Class Driver Routines

The battery class driver exports the following routines for use by miniclass drivers:

BatteryClassInitializeDevice

BatteryClassIoctl

BatteryClassQueryWmiDataBlock

BatteryClassStatusNotify

BatteryClassSystemControl

BatteryClassUnload

These routines are declared in batclass.h.


BatteryClassInitializeDevice

BatteryClassInitializeDevice initializes a new battery device for the class driver.

NTSTATUS
  BatteryClassInitializeDevice (
    IN PBATTERY_MINIPORT_INFO  MiniportInfo,
    IN PVOID  *ClassData
    );

Parameters

MiniportInfo
Pointer to a BATTERY_MINIPORT_INFO structure.
ClassData
Pointer to a location at which BatteryClassInitializeDevice returns a handle to be used in subsequent calls to BatteryClassXxx routines.

Return Value

BatteryClassInitializeDevice returns STATUS_SUCCESS or, possibly, STATUS_INSUFFICIENT_RESOURCES if not enough memory is available to store the battery miniclass data.

Headers

Declared in battclass.h. Include battclass.h.

Comments

Battery miniclass drivers must call BatteryClassInitializeDevice to register each battery device and to pass data about the device and the miniclass driver to the battery class driver.

This routine should be called as part of the device initialization, typically from the miniclass driver's AddDevice routine.

The Context member of the BATTERY_MINIPORT_INFO structure points to an area where the class and miniclass drivers maintain information about the battery device and its drivers. The context area typically contains the pageable device extension from the FDO and can also include other information at the discretion of the driver writer.

The class driver passes a pointer to the context area in calls to battery miniclass driver routines (BatteryMiniXxx routines). In their BatteryMiniXxx routines, miniclass drivers should read and write the device extension data through the passed-in pointer.

Miniclass drivers must use the BATTERY_MINIPORT_INFO structure to supply entry points for all the BatteryMiniXxx routines.

See Also

BatteryMiniDisableStatusNotify, BatteryMiniQueryInformation, BatteryMiniQueryStatus, BatteryMiniQueryTag, BatteryMiniSetInformation, BatteryMiniSetStatusNotify


BatteryClassIoctl

BatteryClassIoctl handles system-defined battery IOCTLs.

NTSTATUS
  BatteryClassIoctl (
    IN PVOID  ClassData,
    IN PIRP  Irp
    );

Parameters

ClassData
Pointer to a battery class handle that was previously returned by BatteryClassInitializeDevice.
Irp
Pointer to the IRP containing the IOCTL to be handled.

Return Value

BatteryClassIoctl returns STATUS_SUCCESS when it satisfies the request and completes the IRP. It returns STATUS_NOT_SUPPORTED for all IRPs other than device control IRPs that specify battery IOCTLs.

Headers

Declared in battclass.h. Include battclass.h.

Comments

BatteryClassIoctl handles and completes device control IRPs intended for the battery. Such IRPs have one of the following I/O control codes:

  • IOCTL_BATTERY_QUERY_INFORMATION
  • IOCTL_BATTERY_QUERY_STATUS
  • IOCTL_BATTERY_QUERY_TAG
  • IOCTL_BATTERY_SET_INFORMATION

The standard battery IOCTLs correspond to battery miniclass driver routines (BatteryMiniXxx routines).

When the miniclass driver is called with an IRP_MJ_DEVICE_CONTROL request, it should determine whether the IRP contains any private IOCTL defined by the miniclass driver. If so, the miniclass driver should satisfy the request, complete the IRP, and return.

If the IRP contains a public IOCTL, the driver should pass the IRP to the class driver's BatteryClassIoctl routine. This routine examines the IRP, determines whether it applies to the caller's battery device, and if so, calls the appropriate BatteryMiniXxx routine to perform the requested operation.

If BatteryClassIoctl returns STATUS_NOT_SUPPORTED for the IRP, the miniclass driver must either complete the IRP or forward it to the next-lower driver.

See Also

BatteryMiniQueryInformation, BatteryMiniQueryStatus, BatteryMiniQueryTag, BatteryMiniSetInformation


BatteryClassQueryWmiDataBlock

The BatteryClassQueryWmiDataBlock routine is used by battery miniclass drivers inside their DpWmiQueryDataBlock routines to allow the battery class driver to process the WMI data block query requests it handles on behalf of the driver.

NTSTATUS
BATTERYCLASSAPI
BatteryClassQueryWmiDataBlock(
    IN PVOID  ClassData,
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp,
    IN ULONG  GuidIndex,
    IN OUT PULONG  InstanceLengthArray,
    IN ULONG  OutBufferSize,
    OUT PUCHAR  Buffer
    );

Parameters

ClassData
Pointer to a battery class handle that was previously received from BatteryClassInitializeDevice.
DeviceObject
Pointer to the driver's device object. The battery miniclass driver can pass the matching parameter it receives inside its DpWmiQueryDataBlock routine.
Irp
Pointer to the WMI query data block request. The battery miniclass driver can pass the matching parameter it receives inside its DpWmiQueryDataBlock routine.
GuidIndex
Specifies the WMI class by its index. The battery miniclass driver can pass the matching parameter it receives inside its DpWmiQueryDataBlock routine.
InstanceLengthArray
Pointer to an array of ULONG values that indicate the length of each instance to be returned. The battery miniclass driver can pass the matching parameter it receives inside its DpWmiQueryDataBlock routine.
OutBufferSize
Specifies the maximum number of bytes available to receive data in the buffer specified by the Buffer parameter. The battery miniclass driver can pass the value of the BufferAvail parameter it receives inside its DpWmiQueryDataBlock routine.
Buffer
Pointer to the buffer to receive the instance data. If the buffer is too small to hold the data, BatteryClassQueryWmiDataBlock returns a status value of STATUS_BUFFER_TOO_SMALL. The battery miniclass driver can pass the matching parameter it receives inside its DpWmiQueryDataBlock routine.

Return Value

BatteryClassQueryWmiDataBlock returns an NT status code. Possible return values include:

STATUS_SUCCESS
The battery class driver successfully handled the request.
STATUS_BUFFER_TOO_SMALL
The battery class driver cannot handle the request because the buffer specified by the Buffer parameter is too small.
STATUS_WMI_GUID_NOT_FOUND
The battery class driver does not handle this WMI class.

Headers

Declared in batclass.h. Include batclass.h.

Comments

A battery miniclass driver should call this routine inside its DpWmiQueryDataBlock routine, before attempting to process the request. If the battery class driver returns any status other than STATUS_WMI_GUID_NOT_FOUND, it has handled the request on behalf of the miniclass driver. In that case, the class driver has already called WmiCompleteRequest, and miniclass driver must not call it again.

See Also

BatteryClassSystemControl, WmiCompleteRequest, DpWmiQueryDataBlock


BatteryClassStatusNotify

BatteryClassStatusNotify notifies the battery class driver of changes in battery status.

NTSTATUS
  BatteryClassStatusNotify (
    IN PVOID  ClassData
    );

Parameters

ClassData
Pointer to a battery class handle previously returned by BatteryClassInitializeDevice.

Return Value

BatteryClassStatusNotify returns STATUS_SUCCESS.

Headers

Declared in battclass.h. Include battclass.h.

Comments

Battery miniclass drivers must call BatteryClassStatusNotify whenever any of the following occur:

  • The battery goes on-line or off-line.
  • The battery's capacity becomes critically low.
  • The battery's power state changes; that is, the battery starts or stops charging or discharging.
  • The battery's capacity or power state deviates from the criteria set by a previous call to BatteryMiniSetStatusNotify.

The battery class driver queues status requests internally. If any such requests are pending when the miniclass driver calls BatteryClassStatusNotify, the class driver immediately calls the miniclass driver's BatteryMiniQueryStatus routine.

See Also

BatteryMiniQueryStatus, BatteryMiniSetStatusNotify


BatteryClassSystemControl

The BatteryClassSystemControl routine processes WMI IRPs on behalf of a battery miniclass driver.

NTSTATUS
BATTERYCLASSAPI
BatteryClassSystemControl (
    IN  PVOID  ClassData,
    IN  PWMILIB_CONTEXT  WmiLibContext,
    IN  PDEVICE_OBJECT  DeviceObject,
    IN  PIRP  Irp,
    OUT PSYSCTL_IRP_DISPOSITION  Disposition
    );

Parameters

ClassData
Pointer to a battery class handle that was previously received from BatteryClassInitializeDevice.
WmiLibContext
Pointer to a WMILIB_CONTEXT structure. The structure provides WMI registration information, and dispatch routines for driver-specific WMI request processing.
DeviceObject
Pointer to the driver's device object.
Irp
Pointer to the IRP that contains the WMI request.
Disposition
Pointer to a memory location that the routine uses to return information on how it handled the IRP. See WmiSystemControl for a description of the possible values returned.

Return Value

BatteryClassSystemControl returns STATUS_SUCCESS on success, and the appropriate error code on failure.

Headers

Declared in batclass.h. Include batclass.h.

Comments

Battery miniclass drivers must call this routine instead of WmiSystemControl. It provides the same functionality as WmiSystemControl, but it also ensures that the driver registers the WMI classes that the battery class driver handles on behalf of the miniclass driver.

A battery miniclass driver's DpWmiQueryDataBlock routine, which is specified by the QueryWmiDataBlock member of WMILIB_CONTEXT, must call the BatteryClassQueryWmiDataBlock routine to allow the battery class driver to process the query for the WMI classes it handles on behalf of the miniclass driver.

See Also

BatteryClassQueryWmiDataBlock, DpWmiQueryDataBlock, WMILIB_CONTEXT


BatteryClassUnload

BatteryClassUnload frees resources for a battery device that is no longer in use.

NTSTATUS
  BatteryClassUnload (
    IN PVOID  ClassData
    );

Parameters

ClassData
Pointer to a battery class handle previously returned by BatteryClassInitializeDevice.

Return Value

BatteryClassUnload returns STATUS_SUCCESS.

Headers

Declared in battclass.h. Include battclass.h.

Comments

BatteryClassUnload frees the battery class handle and unloads the battery device. In essence, it undoes the registration and initialization performed by BatteryClassInitializeDevice.

A miniclass driver should call this routine when its battery device is no longer available for use. Typically, the driver might make such a call from its Unload routine or when handling a PnP IRP_MN_REMOVE_DEVICE request.


Battery Miniclass Driver Routines

Battery miniclass drivers must include routines to support Plug and Play (PnP) and to support battery management and monitoring. Entry points for the following routines are required to support standard operating system and PnP Manager functionality:

DriverEntry

AddDevice

DispatchDeviceControl

DispatchPnP

DispatchPower

Unload

For details on a battery minidriver's support for any of the above routines, see Writing Battery Miniclass Drivers.

Entry points for the following routines, described in this section, are required in all battery miniclass drivers:

BatteryMiniDisableStatusNotify

BatteryMiniQueryInformation

BatteryMiniQueryStatus

BatteryMiniQueryTag

BatteryMiniSetInformation

BatteryMiniSetStatusNotify

The battery class driver calls BatteryMiniXxx routines to get and set information about a specific battery device. Battery miniclass drivers must supply entry points for these routines. The BatteryMiniXxx routines can have any name chosen by the driver writer. Prototypes appear in the batclass.h header file.


BatteryMiniDisableStatusNotify

BatteryMiniDisableStatusNotify disables status notification for a battery device.

NTSTATUS
  BatteryMiniDisableStatusNotify(
    IN PVOID  Context
    );

Parameters

Context
Pointer to the context area allocated by the miniclass driver for the battery device.

Return Value

BatteryMiniDisableStatusNotify returns one of the following:

STATUS_SUCCESS
A battery is currently installed and status notification has been disabled.
STATUS_NO_SUCH_DEVICE
No battery is present.
STATUS_NOT_SUPPORTED
No functionality is provided for this routine.

Headers

Defined in batclass.h. Include batclass.h.

Comments

The battery class driver calls BatteryMiniDisableStatusNotify when it no longer requires notification of battery conditions set in an earlier call to BatteryMiniSetStatusNotify.

Miniclass drivers that supply a fully functional BatteryMiniDisableStatusNotify routine must also supply a fully functional BatteryMiniSetStatusNotify routine, and vice versa.

The battery class driver calls this routine at IRQL PASSIVE_LEVEL.

See Also

BatteryMiniSetStatusNotify, BatteryClassStatusNotify


BatteryMiniQueryInformation

BatteryMiniQueryInformation returns information about the given battery device.

NTSTATUS
  BatteryMiniQueryInformation(
    IN PVOID  Context,
    IN ULONG  BatteryTag,
    IN BATTERY_QUERY_INFORMATION_LEVEL  Level,
    IN LONG  AtRate  OPTIONAL,
    OUT PVOID  Buffer,
    IN ULONG  BufferLength,
    OUT PULONG  ReturnedLength
    );

Parameters

Context
Pointer to the context area allocated by the miniclass driver for the battery device.
BatteryTag
Pointer to a battery tag previously returned by BatteryMiniQueryTag.
Level
Specifies the type of battery information to be returned. Possible values are:

BatteryInformation
BatteryGranularityInformation
BatteryTemperature
BatteryEstimatedTime
BatteryDeviceName
BatteryManufactureDate
BatteryManufactureName
BatteryUniqueID
BatterySerialNumber

AtRate
Specifies the rate of drain, in negative milliwatts, used to calculate the time to discharge the battery. This parameter is meaningful only when Level is BatteryEstimatedTime; this parameter is ignored for all other values of Level.
Buffer
Pointer to a buffer allocated by the miniclass driver. The buffer is used to return the requested information. Miniclass drivers format the contents of the buffer depending upon the value of Level, as follows:
BatteryInformation
Return information formatted as a BATTERY_INFORMATION structure.
BatteryGranularityInformation
Return a variable-length array of type BATTERY_REPORTING_SCALE that contains the reporting granularity of the remaining capacity. The number of entries returned depends upon the size of the returned buffer, to a maximum of four entries per battery.
BatteryTemperature
Return a ULONG value giving the current temperature of the battery, in tenths of a degree Kelvin.
BatteryEstimatedTime
Return a ULONG value estimating the number of seconds of run time remaining on the battery, based on the rate of drain specified in AtRate. If AtRate is negative or zero, the miniclass driver should calculate the run time based on the current rate of drain. However, if the driver cannot make an estimate (for example, AtRate is zero and the battery is not discharging), it should return BATTERY_UNKNOWN_TIME.
BatteryDeviceName
Return a UNICODE string specifying the name of the battery. For example, DR202 identifies a Duracell smart battery.
BatteryManufactureDate
Return a BATTERY_MANUFACTURE_DATE structure specifying the date the battery was manufactured.
BatteryManufactureName
Return a UNICODE string specifying the model name given to the battery by its manufacturer.
BatteryUniqueID
Return a UNICODE string that uniquely identifies the battery, typically a concatenation of the battery's manufacturer, date, and serial number.
BatterySerialNumber
Return a UNICODE string that contains the battery's serial number.
BufferLength
Specifies the length in bytes of the buffer pointed to by Buffer.
ReturnedLength
Specifies the number of bytes returned in the buffer pointed to by Buffer.

Return Value

BatteryMiniQueryInformation returns one of the following:

STATUS_SUCCESS
The battery designated by BatteryTag is currently installed and the requested information has been returned.
STATUS_NO_SUCH_DEVICE
The battery designated by BatteryTag is not present.
STATUS_INVALID_DEVICE_REQUEST
The Level parameter specifies information that this battery does not support.
STATUS_INVALID_PARAMETER
The Level parameter is not one of the enumerators listed.

Headers

Defined in batclass.h. Include batclass.h.

Comments

The battery class driver calls a miniclass driver's BatteryMiniQueryInformation routine to get various types of information about the battery. The information returned depends upon the Level parameter. Not all batteries support all the possible types of information that the class driver might request. Miniclass drivers should return STATUS_INVALID_DEVICE_REQUEST for any such requests.

If Level specifies BatteryInformation, the miniclass driver must return a BATTERY_INFORMATION structure in the buffer pointed to by Buffer. This structure contains status information about the battery, including its capabilities, technology (whether the battery is rechargeable), and chemistry; theoretical and actual full-charged capacity; critical bias; number of charge/discharge cycles; and the capacity levels at which warning alerts occur.

If Level specifies BatteryGranularityInformation, the miniclass driver can return an array of one to four elements, formatted as BATTERY_REPORTING_SCALE structures. Each element of the array consists of a granularity value and a remaining capacity value, in milliwatt-hours. The granularity indicates the precision of measurement and thus is an indicator of the accuracy of the capacity.

Most types of batteries report capacity on a single scale. Miniclass drivers for these batteries return only one entry, giving the remaining capacity and the precision of the scale. Some batteries, however, have two scales: a gross scale that measures whether capacity is greater or less than fifty percent, and a finer scale that applies as capacity approaches zero. Miniclass drivers for such batteries should return two entries describing the two scales.

If Level specifies BatteryEstimatedTime, the miniclass driver must use the optional AtRate parameter to estimate the amount of time remaining to use the battery. The AtRate parameter specifies a drain rate, in negative milliwatts.

If Level specifies BatteryUniqueId, the miniclass driver must return a string that uniquely identifies this particular battery. For control method and smart batteries, the unique ID is the concatenation of the manufacture name, the device name, the manufacture date, and the ASCII representation of the battery's serial number. This value is not meant to be displayed.

The battery class driver calls this routine at IRQL = PASSIVE_LEVEL.

See Also

BATTERY_INFORMATION, BATTERY_MANUFACTURE_DATE, BATTERY_REPORTING_SCALE


BatteryMiniQueryStatus

BatteryMiniQueryStatus returns status information about the given battery device.

NTSTATUS
  BatteryMiniQueryStatus(
    IN PVOID  Context,
    IN ULONG  BatteryTag,
    OUT PBATTERY_STATUS  BatteryStatus
    );

Parameters

Context
Pointer to the context area allocated by the miniclass driver for the battery device.
BatteryTag
Specifies a battery tag previously returned by BatteryMiniQueryTag.
BatteryStatus
Pointer to a BATTERY_STATUS structure in which the miniclass driver returns information.

Return Value

BatteryMiniQueryStatus returns one of the following:

STATUS_SUCCESS
The battery designated by BatteryTag is currently installed.
STATUS_NO_SUCH_DEVICE
The battery designated by BatteryTag is not present.

Headers

Defined in batclass.h. Include batclass.h.

Comments

The battery class driver calls BatteryMiniQueryStatus to get status information about the battery. The status information includes the battery's power state, capacity, voltage, and the amount of current flowing at the time of the request.

If the miniclass driver does not supply fully functional BatteryMiniSetStatusNotify and BatteryMiniDisableStatusNotify routines, the battery class driver calls BatteryMiniQueryStatus at regular but infrequent intervals to poll the battery's status. Otherwise, the class driver calls this routine after the miniclass driver has notified it of a change in battery status.

Before reporting a critically low, discharging battery (BATTERY_DISCHARGING and BATTERY_CRITICAL), the miniclass driver should ensure that the problem is legitimate (rather than a transitory state) and if so, should attempt to solve the problem. Possible solutions might include switching to AC power or to another battery. When the miniclass driver reports that a battery is critical and discharging, the system assumes that battery failure is imminent and prepares to shut down.

The battery class driver calls this routine at IRQL PASSIVE_LEVEL.

See Also

BatteryClassStatusNotify, BatteryMiniDisableStatusNotify, BatteryMiniSetStatusNotify


BatteryMiniQueryTag

BatteryMiniQueryTag returns the current battery tag.

NTSTATUS
  BatteryMiniQueryTag(
    IN PVOID  Context,
    OUT PULONG  BatteryTag
    );

Parameters

Context
Pointer to the context area allocated by the miniclass driver for the battery device.
BatteryTag
Pointer to a caller-allocated variable in which the miniclass driver returns the battery tag.

Return Value

BatteryMiniQueryTag returns one of the following:

STATUS_SUCCESS
A battery is currently installed.
STATUS_NO_SUCH_DEVICE
No battery is present.

Headers

Defined in batclass.h. Include batclass.h.

Comments

The battery class driver calls BatteryMiniQueryTag to get the value of the current battery tag. If a battery is present, BatteryMiniQueryTag should return the tag in BatteryTag and return STATUS_SUCCESS.

Each time a battery is inserted, the miniclass driver must increment the value of the tag, regardless of whether this is a new battery or the same battery that was previously present.

If no battery is present, or if the miniclass driver cannot determine whether a battery is present, it should return STATUS_NO_SUCH_DEVICE and set the value of the tag to BATTERY_TAG_INVALID.

The battery class driver calls this routine at IRQL PASSIVE_LEVEL.


BatteryMiniSetInformation

BatteryMiniSetInformation requests that a battery enter the charging or discharging state, or sets a critical bias value for the battery.

NTSTATUS
  BatteryMiniSetInformation(
    IN PVOID  Context,
    IN ULONG  BatteryTag,
    IN BATTERY_SET_INFORMATION_LEVEL  Level,
    IN PVOID  Buffer  OPTIONAL
    );

Parameters

Context
Pointer to the context area allocated by the miniclass driver for the battery device.
BatteryTag
Specifies a battery tag previously returned by BatteryMiniQueryTag.
Level
Specifies one of the following values: BatteryCriticalBias, BatteryCharge, or BatteryDischarge.
Buffer
Specifies the critical bias adjustment in milliwatts if Level is BatteryCriticalBias. Not used for other values of Level.

Return Value

BatteryMiniSetInformation returns one of the following:

STATUS_SUCCESS
The operation succeeded.
STATUS_NO_SUCH_DEVICE
No battery is present.
STATUS_NOT_SUPPORTED
The specified battery does not support the requested operation.
STATUS_UNSUCCESSFUL
The operation failed.

Headers

Defined in batclass.h. Include batclass.h.

Comments

The battery class driver calls BatteryMiniSetInformation to request that a battery start to charge or discharge. It can also call this routine to set a critical bias value.

With a smart battery charger/selector, the class driver specifies BatteryCharge to select a battery to charge, possibly discontinuing the charging of another battery.

The class driver specifies BatteryDischarge to indicate which battery should power the system.

The critical bias adjustment is analogous to the reserve capacity of the gas tank in an automobile. It represents the remaining charge when the battery capacity is reported as zero. Although the class driver does not change the critical bias value in normal use, this field is provided in the interface as a maintenance feature. Not all batteries can maintain a critical bias setting. Miniclass drivers for such batteries should return STATUS_NOT_SUPPORTED.

The battery class driver calls this routine at IRQL PASSIVE_LEVEL.


BatteryMiniSetStatusNotify

BatteryMiniSetStatusNotify sets the battery capacity and power state levels at which the class driver requires notification.

NTSTATUS
  BatteryMiniSetStatusNotify(
    IN PVOID  Context,
    IN ULONG  BatteryTag,
    IN PBATTERY_NOTIFY  BatteryNotify
    );

Parameters

Context
Pointer to the context area allocated by the miniclass driver for the battery device.
BatteryTag
Specifies a battery tag previously returned by BatteryMiniQueryTag.
BatteryNotify
Pointer to a BATTERY_NOTIFY structure.

Return Value

BatteryMiniSetStatusNotify returns one of the following:

STATUS_SUCCESS
A battery is currently installed.
STATUS_NO_SUCH_DEVICE
No battery is present or the given battery tag is invalid.
STATUS_NOT_SUPPORTED
The miniclass driver cannot distinguish the target condition.

Headers

Defined in batclass.h. Include batclass.h.

Comments

The battery class driver calls a miniclass driver's BatteryMiniSetStatusNotify routine to set criteria for an acceptable range of battery conditions. When the battery's capacity or power state deviates from these criteria, the miniclass driver must call BatteryClassStatusNotify to notify the class driver.

In the PowerState member of the BATTERY_NOTIFY structure, the class driver specifies one or more battery power states. Any time the battery enters a power state that is not in PowerState, the miniclass driver must notify the class driver.

In the LowCapacity and HighCapacity members of BATTERY_NOTIFY, the class driver specifies a range of capacity. When the capacity falls above or below this range, the miniclass driver must notify the class driver.

Some batteries might be unable to distinguish the precise capacities requested by the battery class driver. When possible, miniclass drivers for these batteries should attempt to correct for the error so that the user can be informed when the battery approaches a critical state. Otherwise, such drivers should return STATUS_NOT_SUPPORTED.

The battery class driver calls this routine at IRQL PASSIVE_LEVEL.

See Also

BatteryClassStatusNotify, BatteryMiniDisableStatusNotify


Battery Class/Miniclass Driver Structures

This section describes the following structures used by battery class and miniclass drivers:

BATTERY_INFORMATION

BATTERY_MANUFACTURE_DATE

BATTERY_MINIPORT_INFO

BATTERY_NOTIFY

BATTERY_REPORTING_SCALE

BATTERY_STATUS


BATTERY_INFORMATION

Battery miniclass drivers fill in this structure in response to certain BatteryMiniQueryInformation requests.

typedef struct _BATTERY_INFORMATION {
  ULONG  Capabilities;
  UCHAR  Technology;
  UCHAR  Reserved[3];
  UCHAR  Chemistry[4];
  ULONG  DesignedCapacity;
  ULONG  FullChargedCapacity;
  ULONG  DefaultAlert1;
  ULONG  DefaultAlert2;
  ULONG  CriticalBias;
  ULONG  CycleCount;
} BATTERY_INFORMATION, *PBATTERY_INFORMATION;

Members

Capabilities
Specify battery capabilities as a ULONG value encoded with one or more of the following flags:
BATTERY_SYSTEM_BATTERY
Set this flag if the battery can provide general power to run the system.
BATTERY_CAPACITY_RELATIVE
Set this flag if the miniclass driver will report battery capacity and rate as a percentage of total capacity and rate rather than as absolute values. Otherwise, the miniclass driver should report capacity in milliwatt-hours and rate in milliwatts.
BATTERY_IS_SHORT_TERM
Set this flag if the battery is a UPS, intended for short-term, failsafe use. Clear the flag for any other type of device.
BATTERY_SET_CHARGE_SUPPORTED
Set this flag if the miniclass driver supports the BatteryCharge setting in calls to BatteryMiniSetInformation.
BATTERY_SET_DISCHARGE_SUPPORTED
Set this flag if the miniclass driver supports the BatteryDischarge setting in calls to BatteryMiniSetInformation.
Technology
Specify zero for a primary, nonrechargeable battery, or one for a secondary, rechargeable battery.
Reserved
Reserved for system use.
Chemistry
Specify a four-character string indicating the type of chemistry used in the battery. Possible values include PbAc (Lead Acid), LION (Lithium Ion), NiCd (Nickel Cadmium), NiMH (Nickel Metal Hydride), NiZn (Nickel Zinc), and RAM (Rechargeable Alkaline-Manganese). Additional values might be returned as additional battery types become available.
DesignedCapacity
Specify the theoretical capacity of the battery when new, in milliwatt-hours. If BATTERY_CAPACITY_RELATIVE is set, the units are undefined.
FullChargedCapacity
Specify the battery's current fully charged capacity, in milliwatt-hours. If BATTERY_CAPACITY_RELATIVE is set, the units are undefined.
DefaultAlert1
Specify the capacity (in milliwatt-hours) at which a low battery alert should occur.
DefaultAlert2
Specify the capacity (in milliwatt-hours) at which a warning battery alert should occur.
CriticalBias
Specify the amount (in milliwatt-hours) of any small reserved charge that remains when the critical battery level shows zero. Miniclass drivers should subtract this value from the battery's FullChargedCapacity and remaining capacity (reported in BATTERY_STATUS) before reporting those values.
CycleCount
Specify the number of charge/discharge cycles the battery has experienced, or zero if the battery does not support a cycle counter.

Headers

Defined in batclass.h. Include batclass.h.

See Also

BatteryMiniQueryInformation, BatteryMiniQueryStatus


BATTERY_MANUFACTURE_DATE

Battery miniclass drivers fill in this structure in response to certain BatteryMiniQueryInformation requests.

typedef struct _BATTERY_MANUFACTURE_DATE {
  UCHAR  Day;
  UCHAR  Month;
  USHORT Year;
} BATTERY_MANUFACTURE_DATE, *PBATTERY_MANUFACTURE_DATE;

Members

Day
Specifies a value in the range 1 to 31, inclusive.
Month
Specifies a value in the range 1 to 12, inclusive.
Year
Specifies a value >= 1996.

Headers

Defined in batclass.h. Include batclass.h.

See Also

BatteryMiniQueryInformation


BATTERY_MINIPORT_INFO

Battery miniclass drivers fill in this structure before calling the battery class driver's BatteryClassInitializeDevice routine.

typedef struct {
    USHORT  MajorVersion;
    USHORT  MinorVersion;
    PVOID  Context;
    BCLASS_QUERY_TAG  QueryTag;
    BCLASS_QUERY_INFORMATION  QueryInformation;
    BCLASS_SET_INFORMATION  SetInformation;
    BCLASS_QUERY_STATUS  QueryStatus;
    BCLASS_SET_STATUS_NOTIFY  SetStatusNotify;
    BCLASS_DISABLE_STATUS_NOTIFY  DisableStatusNotify;
    PDEVICE_OBJECT  Pdo;
    PUNICODE_STRING  DeviceName;
} BATTERY_MINIPORT_INFO, *PBATTERY_MINIPORT_INFO;

Members

MajorVersion
Specifies the major version number of the battery class driver. Miniclass drivers should specify BATTERY_CLASS_MAJOR_VERSION.
MinorVersion
Specifies the minor version number of the battery class driver. Miniclass drivers should specify BATTERY_CLASS_MINOR_VERSION.
Context
Pointer to the context area allocated by the miniclass driver.
QueryTag
Specifies the entry point of the miniclass driver's BatteryMiniQueryTag routine.
QueryInformation
Specifies the entry point of the miniclass driver's BatteryMiniQueryInformation routine.
SetInformation
Specifies the entry point of the miniclass driver's BatteryMiniSetInformation routine.
QueryStatus
Specifies the entry point of the miniclass driver's BatteryMiniQueryStatus routine.
SetStatusNotify
Specifies the entry point of the miniclass driver's BatteryMiniSetStatusNotify routine.
DisableStatusNotify
Specifies the entry point of the miniclass driver's BatteryMiniDisableStatusNotify routine.
Pdo
Pointer to the PDO for the battery device.
DeviceName
Pointer to a UNICODE string; should be NULL.

Headers

Defined in batclass.h. Include batclass.h.

See Also

BatteryClassInitializeDevice


BATTERY_NOTIFY

A battery miniclass driver receives a BATTERY_NOTIFY structure when its BatteryMiniSetStatusNotify routine is called.

typedef struct {
    ULONG    PowerState;
    ULONG    LowCapacity;
    ULONG    HighCapacity;
} BATTERY_NOTIFY, *PBATTERY_NOTIFY;

Members

PowerState
Contains one or more of the following flags to specify a battery power state: BATTERY_POWER_ON_LINE, BATTERY_DISCHARGING, BATTERY_CHARGING, BATTERY_CRITICAL.
LowCapacity
Specifies a ULONG value indicating the battery capacity below which the class driver requires notification.
HighCapacity
Specifies a ULONG value indicating the battery capacity above which the class driver requires notification.

Headers

Defined in batclass.h. Include batclass.h.

See Also

BatteryMiniSetStatusNotify


BATTERY_REPORTING_SCALE

Battery miniclass drivers fill in this structure in response to certain BatteryMiniQueryInformation requests.

typedef struct {
  ULONG  Granularity;
  ULONG  Capacity;
} BATTERY_REPORTING_SCALE;

Members

Granularity
Specify the granularity of the Capacity value, in milliwatt-hours. For most batteries, this value describes a monotonically increasing scale of capacity. For lithium-ion batteries, this value describes one of two possible scales: a gross measure of battery capacity, with a large granularity, or a finer measure as the capacity approaches zero.
Capacity
Specify the battery capacity described by the corresponding granularity, in milliwatt-hours.

Headers

Defined in batclass.h. Include batclass.h.

See Also

BatteryMiniQueryInformation


BATTERY_STATUS

The BATTERY_STATUS structure is used by battery miniclass drivers to return status information in response to a call to BatteryMiniQueryStatus.

typedef struct _BATTERY_STATUS {
    ULONG    PowerState;
    ULONG    Capacity;
    ULONG    Voltage;
    LONG     Rate;
} BATTERY_STATUS, *PBATTERY_STATUS;

Members

PowerState
Specifies a battery power state as one or more of the following flags, ORed together: BATTERY_POWER_ON_LINE, BATTERY_DISCHARGING, BATTERY_CHARGING, and BATTERY_CRITICAL.
Capacity
Specifies the capacity of the given battery, in milliwatt-hours, or BATTERY_UNKNOWN_CAPACITY if the capacity cannot be determined.
Voltage
Specifies the voltage, in millivolts, across the terminals of the given battery, or BATTERY_UNKNOWN_VOLTAGE if the voltage cannot be determined.
Rate
Specifies the current rate of battery usage in milliwatts or, if the driver reports relative capacity, in units per hour. . A positive value means that the battery is charging; a negative value means the battery is discharging. If the driver cannot determine the rate, it should return BATTERY_UNKNOWN_RATE.

Headers

Defined in batclass.h. Include batclass.h.

See Also

BatteryMiniQueryStatus


UPS Minidriver Functions

This section describes the following functions, which are exported by UPS minidrivers:

  • UPSCancelWait
  • UPSGetState
  • UPSInit
  • UPSStop
  • UPSTurnOff
  • UPSWaitForStateChange

These functions are called by the system-supplied UPS service. For more information, see Writing UPS Minidrivers.


UPSCancelWait

The UPSCancelWait function cancels all waits initiated by calls to UPSWaitForStateChange.

void
  UPSCancelWait(void);

Parameters

None

Return Value

None

Headers

Declared in upssvc.h. Include upssvc.h.

Comments

The call returns immediately.

See Also

UPSWaitForStateChange


UPSGetState

The UPSGetState function returns the operational state of the UPS.

DWORD
  UPSGetState(void);

Parameters

None

Return Value

The UPSGetState function returns one of the following DWORD values:

UPS_ONLINE
Utility-supplied power is normal.
UPS_ONBATTERY
Utility-supplied power is inadequate, and the UPS batteries are discharging.
UPS_LOWBATTERY
Utility-supplied power is inadequate, and the UPS batteries are critically low.
UPS_NOCOMM
Communication with the UPS is not currently established.

Headers

Declared in upssvc.h. Include upssvc.h.

Comments

This is a non-blocking call.


UPSInit

The UPSInit function initializes a UPS minidriver, opens communication to the UPS unit, updates the registry, and causes the minidriver to start monitoring the UPS unit.

DWORD
  UPSInit(void);

Parameters

None

Return Value

The UPSInit function returns one of the following DWORD values:

UPS_INITOK
No errors were encountered during initialization.
UPS_INITREGISTRYERROR
An error occurred while accessing the registry.
UPS_INITCOMMOPENERROR
An error occurred while opening the COM port.
UPS_INITCOMMSETUPERROR
An error occurred while setting up the COM port.
UPS_INITUNKNOWNERROR
An unidentified error occurred.

Headers

Declared in upssvc.h. Include upssvc.h.

Comments

The UPSInit function is the first function exported by a UPS minidriver that is called by the UPS service. The function must complete all initialization operations for the minidriver, including the following:

  • Opening a communication path to the UPS unit
  • Determining the initial state of the UPS unit
  • Updating UPS registry entries
  • Beginning the monitoring of the UPS unit

If the UPSInit function returns a value other than UPS_INITOK, the UPS service immediately calls the UPSStop function.

See Also

UPSStop


UPSStop

The UPSStop function causes a UPS minidriver to stop monitoring its UPS unit.

void
  UPSStop(void);

Parameters

None

Return Value

None

Headers

Declared in upssvc.h. Include upssvc.h.

Comments

The UPSStop function must:

  • Cancel all waiting calls to UPSWaitForStateChange.
  • Stop monitoring the UPS unit.
  • Close and release the UPS unit's COM port.

After UPSStop returns, the only function the UPS service can call is UPSInit.

See Also

UPSInit


UPSTurnOff

The UPSTurnOff function turns off the UPS unit's power outlets, after a specified delay time.

void
  UPSTurnOff(
    DWORD  aTurnOffDelay
    );

Parameters

aTurnOffDelay
Specifies the minimum amount of time, in milliseconds, to wait before turning off the UPS unit's power outlets.

Return Value

None

Headers

Declared in upssvc.h. Include upssvc.h.

Comments

The actual delay time should not be less than that specified by aTurnOffDelay, to ensure adequate time for the operating system to shut down.

The function must not postpone the request to turn off the power. Doing so could result in the operating system unloading the UPS service and the UPS minidriver.

On the other hand, the function must not turn off power from a UPS system that does not have an internal turnoff delay. Doing so will result in a premature loss of power to the computer, which can cause system corruption.


UPSWaitForStateChange

The UPSWaitForStateChange function waits until a specified UPS state changes, or until a time-out interval elapses.

void
  UPSWaitForStateChange(
    DWORD  aCurrentState,
    DWORD  anInterval
    );

Parameters

aCurrentState
Specifies the UPS state on which to wait. When the state of the UPS system changes from the specified state to any other state, the function returns. The specified value can be one of the following:
UPS_ONLINE
Utility-supplied power is normal.
UPS_ONBATTERY
Utility-supplied power is inadequate, and the UPS batteries are discharging.
UPS_LOWBATTERY
Utility-supplied power is inadequate, and the UPS batteries are critically low.
UPS_NOCOMM
Communication with the UPS is not currently established.
anInterval
Specifies a time-out interval, in milliseconds, for the function. If the UPS state has not changed from the specified state when the interval elapses, the function returns. A value of INFINITE means the interval never elapses.

Return Value

None

Headers

Declared in upssvc.h. Include upssvc.h.

Comments

The UPSWaitForStateChange function must wait until either the state of the UPS changes from the value specified by aCurrentState, or until the time specified by aTimeout has elapsed, whichever occurs first.

A call to UPSCancelWait interrupts UPSWaitForStateChange and causes it to return.

See Also

UPSCancelWait


Graphics System Overview

Microsoft® NT-based operating systems provide a robust graphics architecture in which third-party graphics hardware companies can easily integrate their video displays and printing devices. This section provides design guidelines for writing effective graphics drivers. It is broken down as follows:

  • Graphics Drivers

    This section describes the Graphics Driver Interface (GDI) and Graphics Device Driver Interface (Graphics DDI). Design and implementation details that are common to both display and printing drivers are discussed.

  • Display and Video Drivers

    This section describes the video display environment in NT-based operating systems, and provides design and implementation details for display and video miniport driver writers.

  • Printer Drivers and Spooler Components

    This section describes the drivers and print spooler that make up the printing environment in NT-based operating systems. Sections within this part of the DDK specify how to provide customized driver and spooler components, so that new printer hardware and network configurations can be supported.


GDI Support for Graphics Drivers

This section describes the Microsoft® NT-based operating system graphics device interface (GDI). It then details the support that GDI provides to graphics drivers.

References to GDI in this section are implicit references to kernel-mode GDI; Microsoft® Win32® GDI will be explicitly identified. Kernel-mode GDI is also known as the Graphics Engine.

GDI function and structure references are documented in the Windows DDK Graphics Driver Reference. Most of the GDI function declarations and structure definitions can be found in winddi.h. For display drivers, the DirectDraw heap manager functions are declared in dmemmgr.h. Both files are shipped with the Windows DDK.


GDI from the Driver's Perspective

GDI is the intermediary support between a Windows® NT-based graphics driver and an application. Applications call Win32® GDI functions to make graphics output requests. These requests are routed to kernel-mode GDI. Kernel-mode GDI then sends these requests to the appropriate graphics driver, such as a display driver or printer driver. Kernel-mode GDI is a system-supplied module that cannot be replaced.

GDI communicates with the graphics driver through a set of graphics device driver interface (graphics DDI) functions. These functions are identified by their Drv prefix. Information is passed between GDI and the driver through the input/output parameters of these entry points. The driver must support certain Drv Xxx functions for GDI to call. The driver supports GDI's requests by performing the appropriate operations on its associated hardware before returning to GDI.

GDI includes many graphics output capabilities in itself, eliminating the need for the driver to support these capabilities and thereby making it possible to reduce the size of the driver. GDI also exports service functions that the driver can call, further reducing the amount of support the driver must provide. GDI service functions are identified by their Eng prefix, and functions that provide access to GDI-maintained structures have names in the form Xxx OBJ_Xxx.

The following figure shows this flow of communication.

Graphics Driver and GDI Interaction


GDI as a Graphics Language for Applications

Both the Win32 GDI and the graphics engine are completely device-independent. Consequently, applications do not need to access the hardware directly. Based on an application graphics request, GDI works in conjunction with device-dependent graphics drivers to provide high quality graphics output for an array of graphics devices. The same GDI code paths are used for both printing and display devices.


GDI as a Rendering Engine

For rendering operations, the driver must first enable a surface for each PDEV structure that is enabled. A PDEV is a logical representation of a physical device. If the hardware can be set up as a GDI standard-format bitmap, GDI can be used to do some or all of the drawing to the bitmap surface. GDI can also handle advanced halftoning.

For information on enabling PDEVs and surfaces, refer to the DrvEnablePDEV and DrvEnableSurface functions.


GDI-Managed Bitmaps

GDI manages bitmaps in all DIB formats including 1, 4, 8, 16, 24, and 32 bits-per-pixel. GDI can do all line drawing, filling, text output, and bit block transfer (bitblt) operations on these bitmaps. This makes it possible for the driver to either have GDI do all graphics rendering, or to implement functions for which its hardware offers special support.

If the device has a frame buffer in a DIB format, GDI can perform any or all graphics output directly to the frame buffer, thereby reducing the size of the driver. If the device uses a nonstandard-format frame buffer, then the driver must implement all required drawing functions. GDI can still simulate most drawing functions, although a performance cost is incurred: the pixels must be copied into a standard format bitmap before they can be operated on by GDI, and then be copied back to the original format after drawing is complete.


GDI-Managed Lines and Curves

GDI offers improved definitions of lines and curves. Lines are not required to have integer endpoints in DEVICE coordinates, as was true for Windows 3.x. This allows the driver to transform graphics objects without gross rounding. The fundamental curve in GDI is a Bezier curve (cubic spline) rather than an ellipse. All GDI internal operations are handled with Bezier curves, which are supported by most high-end devices. For devices that do not handle Bezier curves, GDI breaks curves down into line segments before calling the driver to draw them.

GDI can download regions to be filled in the form of paths, as well as rectangles. Drivers can decompose paths into trapezoids or spans for filling.


GDI-Managed Attributes: Brushes

GDI also manages all attributes. GDI passes attributes to the driver as brushes; the driver realizes these brushes by converting them to a useful internal form. GDI maintains this converted information for the driver. GDI also maintains all states of the brushes, including bounds, correlation, current position, and line style. The driver can cache information but is not assumed to maintain any state. Except for initialization and brush realization, GDI calls the driver only to draw on the device. GDI takes care of transformations, region locking, and pointer exclusion before it calls the driver.

Whenever a driver needs to use a brush not yet realized, it calls back to GDI. GDI allocates memory for the brush and calls the driver to realize it and, if necessary, dither it.


GDI Halftoning Capabilities

GDI halftoning produces a quality dither or color-halftone image for printing devices or display devices that do not already have such capabilities built-in. Color halftoning provides:

  • Highest quality color and gray-scale reproduction possible on a given device.
  • Increased visual resolution with a limited set of intensity levels.
  • Improved color correlation between the different output devices.

Traditional analog halftoning is a cellular process that uses a halftoning screen. The halftoning screen is composed of cells of equal sizes, with fixed-cell spacing center-to-center. The fixed-cell spacing accommodates the thickness of the ink, while the size of a dot within each cell can vary to produce the impression of a continuous tone.

On a computer, most printing or screen shading also uses a fixed-cell pixel size. To simulate the variable dot size, a combination of cluster pixels simulates the halftone screen. In Windows NT-based operating systems, GDI includes halftoning default parameters that provide a good first approximation. Additional device-specific information can be added to the system to improve output.


Using GDI 8-Bit-Per-Pixel CMY Mask Modes

Beginning with Windows XP, there are significant changes in the implementation of GDI's HT_Get8BPPMaskPalette function.

In Microsoft® Windows® XP and later, HT_Get8BPPMaskPalette uses its pPaletteEntry to return either a normal CMY palette or an inverted-index CMY palette when the Use8BPPMaskPal parameter is set to TRUE. The type of palette returned depends on the value stored in pPaletteEntry[0] when HT_Get8BPPMaskPalette is called. If pPaletteEntry[0] is set to 'RGB0', an inverted-index palette will be returned. If pPaletteEntry[0] is set to 0, a normal CMY palette will be returned.

The reason for this change in behavior of HT_Get8BPPMaskPalette is that when Windows GDI uses ROPs, which are based on the indexes in a palette and not on the palette colors, it assumes that index 0 of the palette is always black and that the last index is always white. GDI does not check the palette entries. This change in HT_Get8BPPMaskPalette ensures correct ROP output, instead of a result that is inverted.

To correct the GDI ROP behavior, GDI in Windows XP and later supports a special CMY palette composition format in which the CMY mask palette entries start at index 255 (white) and work down to index 0 (black), instead of starting at index 0 (white) and working up to index 255 (black). The CMY inverted modes also move all CMY mask color entries to the middle of a full 256-entry palette, with the beginning and end of the palette padded with equal numbers of black and white entries.

Note In the discussion that follows, the term CMY mode refers to a mode supported in the previous implementation of HT_Get8BPPMaskPalette. The term CMY_INVERTED mode refers to modes supported only on Windows XP and later GDI, in which this function inverts bitmask indexes when pPalleteEntry[0] is set to 'RGB0'.

The following steps are required for all Windows XP and later drivers that use Windows GDI halftone 8-bit-per-pixel CMY mask modes.

  1. Set the flHTFlags member of the GDIINFO structure to HT_FLAG_INVERT_8BPP_BITMASK_IDX so GDI will render images in one of the CMY_INVERTED modes.
  2. Set pPaleteEntry[0] as follows prior to a call to HT_Get8BPPMaskPalette:
    pPaletteEntry[0].peRed   = 'R';
pPaletteEntry[0].peGreen = 'G';
pPaletteEntry[0].peBlue  = 'B';
pPaletteEntry[0].peFlags = '0';

    To do this, a caller should use the HT_SET_BITMASKPAL2RGB macro (defined in winddi.h). Here is an example showing the use of this macro:

    HT_SET_BITMASKPAL2RGB(pPaletteEntry)

    Here pPaletteEntry is the pointer to the PALETTEENTRY that was passed in the call to the HT_Get8BPPMaskPalette function. When this macro completes execution, pPaletteEntry[0] will contain the string 'RGB0'.

  3. Check the pPaletteEntry parameter returned from the call to HT_Get8BPPMaskPalette using the HT_IS_BITMASKPALRGB macro, which is defined in winddi.h. Here is an example showing the use of this macro.
    InvCMYSupported = HT_IS_BITMASKPALRGB(pPaletteEntry)

    In this expression, pPaletteEntry is the pointer to the PALETTEENTRY that was passed to the HT_GET8BPPMaskPalette function. If this macro returns TRUE, then GDI does support the inverted CMY 8-bit-per-pixel bitmask modes. The caller must use a translation table to convert the palette indexes to ink levels. See Translating 8-Bit-Per-Pixel Halftone Indexes to Ink Levels for an example of a function that generates this translation table.

    If this macro returns FALSE, then the current version of GDI does not support the inverted CMY 8-bit-per-pixel bitmask modes. In that case, GDI supports only the older CMY non-inverted modes.

For GDI versions that support the 8-bit-per-pixel CMY_INVERTED modes, the meaning of the CMYMask parameter value passed to the HT_GET8BPPMaskPalette function has been changed. The following table summarizes the changes:

CMYMask
Value 		CMY Mode Indexes
(pPaletteEntry[0] != 'RGB0') 		CMY_INVERTED Mode Indexes
(pPaletteEntry[0] == 'RGB0')
0 0: White
1 to 254: Light Gray --> Dark Gray
255: Black 		0 - Black
1 to 254: Dark Gray --> Light Gray
255: White
1 0: White
1 to 123: 123 5x5x5 colors
124 to 255: Black 		0 to 65: Black
66 to 189: 123 5x5x5 colors plus one duplicate. The entry at index 127 is copied to index 128.
190 to 255: White

The values at indexes 127 and 128 are duplicated to ensure that the XOR ROP works correctly.
2 0: White
1 to 214: 214 6x6x6 colors
215 to 255: Black 		0 to 20: Black
21 to 234: 214 6x6x6 colors
235 to 255: White
3 to 255 0: White
1 to 254: CxMxY color bitmask
255: Black

In the product above, C, M, and Y represent the number of levels of cyan, magenta, and yellow, respectively.

Note: For these modes, a valid combination must not have any of the cyan, magenta, or yellow ink levels equal to zero. For such a combination, HT_Get8BPPMaskPalette indicates an error condition by returning a zero-count palette in its pPaletteEntry parameter.

 0: Black
1 to 254: Centered CxMxY colors padded with black at the beginning and white at the end
If CxMxY is an odd number, then the entry at index 128 is a duplicate of the one at index 127.
255: White

In the product above, C, M, and Y represent the number of levels of cyan, magenta, and yellow, respectively.

Note: The (C x M x Y) indexes are centered in the 256-entry palette. That is, there are equal numbers of black entries padding the low end of the palette and white entries padding the high end.

Note: For these modes, a valid combination must not have any of the cyan, magenta, or yellow ink levels equal to zero. For such a combination, HT_Get8BPPMaskPalette indicates an error condition by returning a zero-count palette in its pPaletteEntry parameter.

  • For a value of CMYMask of 0 (Gray scale), the caller can process either the CMY mode or the CMY_INVERTED mode. Note, however, that GDI ROPs are correctly processed only in the CMY_INVERTED mode.

    CMY Mode: Indexes 0 to 255 represent a gray scale from white to black.

    CMY_INVERTED Mode: Indexes 0 to 255 represent a gray scale ranging from black to white.

  • For any valid value of CMYMask from 1 to 255, the caller should use the example function shown in Translating 8-Bit-Per-Pixel Halftone Indexes to Ink Levels to translate indexes to ink levels.
  • For any valid value of CMYMask from 1 to 255, the CMY_INVERTED modes pad the palettes with black entries at the beginning of the array, and an equal number of white entries at the end of the array. The middle of the array is filled with the other colors. This ensures that all 256 of the color palette entries are symmetrically distributed so that GDI ROPs, which are index-based, not color-based, work correctly. The colors are symmetrically distributed when the color at index N is the inverse of the color at index (256 - N). When a color and its inverse are printed together, the result is black. In other words, for a given color and its inverse, the two cyan ink levels add to the maximum cyan ink level, as do the two magenta ink levels, and the two yellow ink levels. The resulting ink levels correspond to black.

    For example; a CMY palette with three levels each of cyan, magenta, and yellow has a total of 27 (3 x 3 x 3) indexes for colors, including black and white. Because 27 is an odd number, and because GDI requires that a CMY_INVERTED mode palette be padded with equal numbers of black and white entries, GDI duplicates the entry at the middle index (index 13 of the 27 colors). With the entries at indexes 13 and 14 now the same, palette will now have 28 colors. To fill the palette, GDI places 114 black entries at the beginning of the palette (indexes 0 to 113), places the 28 colors at indexes 114 (black) through 141 (white), and fills the remaining 114 entries with white (indexes 142 through 255). This makes a total of 256 entries (114 + 28 + 114 = 256 entries). This layout of the indexes ensures that all ROPs will be correctly rendered. The example function in Translating 8-Bit-Per-Pixel Halftone Indexes to Ink Levels shows how to generate the ink levels as well as a Windows 2000 CMY332 index translation table.

    The following table lists the cyan, magenta, and yellow levels for the 3 x 3 x 3 palette discussed in the previous paragraph. The 28 colors (27 original palette colors plus one duplicate) are embedded in the middle of the 256-color palette, with equal amounts of black padding at the beginning and white padding at the end. The palette is symmetric, meaning that if the ink levels at index N are added to those at index (256 - N), the result will be black (cyan, magenta, and yellow levels = 2).

Palette Index (3x3x3 Index) | Cyan Level 0 to 2 | Magenta Level 0 to 2 | Yellow Level 0 to 2
0 to 113 Black | 2 | 2 | 2
114 (0) Black | 2 | 2 | 2
115 (1) | 2 | 2 | 1
116 (2) | 2 | 2 | 0
117 (3) | 2 | 1 | 2
118 (4) | 2 | 1 | 1
119 (5) | 2 | 1 | 0
120 (6) | 2 | 0 | 2
121 (7) | 2 | 0 | 1
122 (8) | 2 | 0 | 0
123 (9) | 1 | 2 | 2
124 (10) | 1 | 2 | 1
125 (11) | 1 | 2 | 0
126 (12) | 1 | 1 | 2
127 (13) Copied to index 128 | 1 | 1 | 1
128 (14) Duplicate of entry at index 127 | 1 | 1 | 1
129 (15) | 1 | 1 | 0
130 (16) | 1 | 0 | 2
131 (17) | 1 | 0 | 1
132 (18) | 1 | 0 | 0
133 (19) | 0 | 2 | 2
134 (20) | 0 | 2 | 1
135 (21) | 0 | 2 | 0
136 (22) | 0 | 1 | 2
137 (23) | 0 | 1 | 1
138 (24) | 0 | 1 | 0
139 (25) | 0 | 0 | 2
140 (26) | 0 | 0 | 1
141 (27) White | 0 | 0 | 0
142 to 255 White | 0 | 0 | 0

  • If the requested palette is a CMY mode palette (not a CMY_INVERTED mode palette), then for values of CMYMask from 3 to 255, the rendered 8-bit-per-pixel byte index bits have the following meaning. In this case, the bit patterns represent ink levels that can be used directly without translation. This also applies when a CMY_INVERTED mode byte index is mapped to CMY mode using a translation table's CMY332Idx member. See Translating 8-Bit-Per-Pixel Halftone Indexes to Ink Levels for more information.
      Bit     7 6 5 4 3 2 1 0
          |   | |   | | |
          +---+ +---+ +-+
            |     |    |
            |     |    +-- Yellow 0-3 (Max. 4 levels)
            |     |
            |     +-- Magenta 0-7 (Max. 8 levels)
            |
            +-- Cyan 0-7 (Max. 8 levels)


Translating 8-Bit-Per-Pixel Halftone Indexes to Ink Levels

The GenerateInkLevels function shown here provides an example of how to translate 8-bit-per-pixel halftone indexes to ink levels. These indexes are contained in CMY mode and CMY_INVERTED mode palettes that GDI's HT_Get8BPPMaskPalette function returns in its pPaletteEntry parameter. GenerateInkLevels generates a 256-element array of INKLEVELS structures.

This function can be used to generate either a Windows 2000 CMY mode or a post-Windows 2000 CMY_INVERTED mode translation table. This function can also be used to generate a Windows 2000 CMY mode CMY332 reverse-mapping index table. (CMY332 uses three bits each for cyan and magenta, and two bits for yellow.) When CMYMask value is in the range 3 to 255, the function's caller can use this table to map post-Windows 2000 CMY_INVERTED indexes to Windows 2000 CMY indexes for currently existing drivers.

INKLEVELS Structure

typedef struct _INKLEVELS {
   BYTE  Cyan;          // Cyan level from 0 to max
   BYTE  Magenta;       // Magenta level from 0 to max
   BYTE  Yellow;        // Yellow level from 0 to max
   BYTE  CMY332Idx;     // Original windows 2000 CMY332 Index
} INKLEVELS, *PINKLEVELS;

Example GenerateInkLevels Function

The GenerateInkLevels function computes an 8-bit-per-pixel translation table of INKLEVELS structures, based on the values in the CMYMask and CMYInverted parameters. This function generates an INKLEVELS translation table for a valid CMYMask value in the range 0 to 255.

When this function is called, the pInkLevels parameter must point to a valid memory location of 256 INKLEVELS entries. If the function returns TRUE, then pInkLevels can be used to translate 8-bit-per-pixel indexes to ink levels, or to map to the older CMY332 indexes. If the function is called with CMYMask set to an invalid value (a value from 3 to 255 in which any of the cyan, magenta, or yellow levels is zero), the function returns FALSE.

BOOL
GenerateInkLevels(
    PINKLEVELS  pInkLevels,  // Pointer to 256 INKLEVELS table
    BYTE        CMYMask,     // CMYMask mode
    BOOL        CMYInverted  // TRUE for CMY_INVERTED mode
    )

{
    PINKLEVELS  pILDup;
    PINKLEVELS  pILEnd;
    INKLEVELS   InkLevels;
    INT         Count;
    INT         IdxInc;
    INT         cC;  // Number of Cyan levels
    INT         cM;  // Number of Magenta levels
    INT         cY;  // Number of Yellow levels
    INT         xC;  // Max. number Cyan levels
    INT         xM;  // Max. number Magenta levels
    INT         xY;  // Max. number Yellow levels
    INT         iC;
    INT         iM;
    INT         iY;
    INT         mC;
    INT         mM;

    switch (CMYMask) {

    case 0:

        cC =
        cM =
        xC =
        xM = 0;
        cY =
        xY = 255;
        break;

    case 1:
    case 2:

        cC =
        cM =
        cY =
        xC =
        xM =
        xY = 3 + (INT)CMYMask;
        break;

    default:

        cC = (INT)((CMYMask >> 5) & 0x07);
        cM = (INT)((CMYMask >> 2) & 0x07);
        cY = (INT)( CMYMask       & 0x03);
        xC = 7;
        xM = 7;
        xY = 3;
        break;
    }   // end switch statement

    Count = (cC + 1) * (cM + 1) * (cY + 1);

    if ((Count < 1) || (Count > 256)) {
        return(FALSE);
    }

    InkLevels.Cyan      =
    InkLevels.Magenta   =
    InkLevels.Yellow    =
    InkLevels.CMY332Idx = 0;
    mC                  = (xM + 1) * (xY + 1);
    mM                  = xY + 1;
    pILDup              = NULL;
    if (CMYInverted) {

        //
        // Move the pInkLevels to the first entry following
        // the centered embedded entries.
        // Skipped entries are set to white (zero). Because this
        // is a CMY_INVERTED mode, entries start from back of the
        // table and move toward the beginning of the table.
        //

        pILEnd      = pInkLevels - 1;
        IdxInc      = ((256 - Count - (Count & 0x01)) / 2);
        pInkLevels += 255;

        while (IdxInc--) {

            *pInkLevels-- = InkLevels;
        }

        if (Count & 0x01) {

            //
            // If we have an odd number of entries, we need to
            // duplicate the center one for the XOR ROP to
            // operate correctly. pILDup will always be index
            // 127, and the duplicates are at indexes 127 and 128.
            //
            pILDup = pInkLevels - (Count / 2) - 1;
        }

        //
        // We are running from the end of table to the beginning,
        // because in CMY_INVERTED mode, index 0 is black and
        // index 255 is white. Since we generate only Count
        // white, black, and colored indexes, and place them at
        // the center, we will change xC, xM, xY max. indexes
        // to the same as cC, cM and cY
        // so we only compute cC*cM*cY entries.
        //

        IdxInc = -1;
        xC     = cC;
        xM     = cM;
        xY     = cY;

    } else {
        IdxInc = 1;
        pILEnd = pInkLevels + 256;
    }

    //
    // In the following composition of ink levels, the index
    // always runs from 0 ink level (white) to maximum ink
    // levels (black).  With CMY_INVERTED mode, we compose ink
    // levels from index 255 to index 0 rather than from index
    // 0 to 255.
    //

    if (CMYMask) {

        INT Idx332C;
        INT Idx332M;

        for (iC = 0, Idx332C = -mC; iC <= xC; iC++) {

            if (iC <= cC) {

                InkLevels.Cyan  = (BYTE)iC;
                Idx332C        += mC;
            }

            for (iM = 0, Idx332M = -mM; iM <= xM; iM++) {

                if (iM <= cM) {

                    InkLevels.Magenta  = (BYTE)iM;
                    Idx332M           += mM;
                }

                for (iY = 0; iY <= xY; iY++) {

                    if (iY <= cY) {

                        InkLevels.Yellow = (BYTE)iY;
                    }

                    InkLevels.CMY332Idx = (BYTE)(Idx332C +
                                          Idx332M) +
                                          InkLevels.Yellow;
                    *pInkLevels         = InkLevels;

                    if ((pInkLevels += IdxInc) == pILDup) {

                        *pInkLevels  = InkLevels;
                        pInkLevels  += IdxInc;
                    }
                }
            }
        }

        //
        // Now, if we need to pad black at the other end of the
        // translation table, then do it here. Notice that
        // InkLevels are at cC, cM and cY here and CMY332Idx
        // is at black.
        //

        while (pInkLevels != pILEnd) {

            *pInkLevels  = InkLevels;
            pInkLevels  += IdxInc;
        }

    } else {

        //
        // Gray Scale case
        //

        for (iC = 0; iC < 256; iC++, pInkLevels += IdxInc) {

            pInkLevels->Cyan      =
            pInkLevels->Magenta   =
            pInkLevels->Yellow    =
            pInkLevels->CMY332Idx = (BYTE)iC;
        }
    }

    return(TRUE);
}


GDI/Driver Division of Labor

To understand graphics driver design, it is important to understand the roles of GDI and the driver, and how they negotiate. GDI, with its enhanced capabilities, can handle many operations that previously required a graphics driver. GDI also has the responsibility of managing data structures critical to graphics operations, such as surfaces, although each graphics driver must have access to them.


GDI Communication with the Driver

The driver exports only one function to GDI: DrvEnableDriver. All other driver-supported functions, including the DrvDisableDriver function, are exposed to GDI through an array of pointers. A GDI call to DrvEnableDriver initializes the driver and passes back the list of driver-supported graphics DDI functions. While there are some functions a driver must support, GDI will handle those operations not included in the function list received from the driver's DrvEnableDriver routine. GDI calls DrvDisableDriver when the driver is to be unloaded. Graphics DDI functions are discussed in depth in Using the Graphics DDI.

GDI makes a large number of objects and services available to the driver. These fall into two categories: user objects and service routines.


GDI User Objects

GDI maintains important internal data structures, but gives the driver access to the public fields of these structures by passing them down as user objects. User objects are intermediate data structures that provide an interface between GDI data structures and the drivers that need access to the information within these structures. The driver can pass the pointer to a user object back to GDI to query for information or to ask for various services. User objects with public fields provide the following advantages:

  • They eliminate problems associated with direct access to internal GDI data structures.
  • They provide a place to hold GDI data for the driver. For example, a PATHOBJ structure can hold all the extra data required to enumerate a complex object like a path.

The following user objects are available:

Object | Description
BRUSHOBJ | Defines the brush objects for graphic functions that output lines, text, or fills. Drivers can call BRUSHOBJ services to realize brushes or to find realizations previously cached by GDI.
CLIPOBJ | Provides the driver with access to a clip region for drawing or filling. This region can be enumerated as a series of rectangles.
FLOATOBJ | Allows graphics drivers to emulate floating point operations. Floating point operations are disabled for all other kernel-mode drivers.
FONTOBJ | Gives the driver access to information about a particular instance (or realization) of a font.
PALOBJ | A structure containing RGB palette colors; accessible via the PALOBJ_cGetColors and DrvSetPalette functions. The PALOBJ structure contains no public members.
PATHOBJ | Defines a path that specifies what is to be drawn (lines or Bezier curves). A PATHOBJ structure is passed to the driver to describe a set of lines and Bezier curves that are to be stroked or filled.
STROBJ | Enumerates for the driver a list of glyph handles and positions that describe how a text string is to be drawn.
SURFOBJ | Identifies a surface, which can be a GDI bitmap, a device-dependent bitmap, or a device-managed surface. See Surface Types for more information.
XFORMOBJ | Describes an arbitrary linear two-dimensional transform, such as for geometric wide lines.
XLATEOBJ | Defines the translations needed to convert pixels from the source surface format to the destination surface format.


GDI Service Routines

GDI exports many service routines, whose names have the form Eng Xxx. The driver dynamically links to win32k.sys to directly access these routines. GDI service routines include surface management, rendering simulations, and path, palette, font, and text services. These services are discussed in detail in GDI Support Services.


PDEV Negotiation

One of the primary responsibilities of any graphics driver is to enable a PDEV during driver initialization. A PDEV is a logical representation of the physical device. This representation is defined by the driver and is typically a private data structure. Refer to DrvEnablePDEV for more information on enabling PDEVs.

Through the DrvEnablePDEV function, the driver must provide information to GDI that describes the requested device and its capabilities. One piece of important information that the driver gives GDI is the set of graphics capability flags (GCAPS_Xxx and GCAPS2_Xxx flags) in the flGraphicsCaps and flGraphicsCaps2 members of the DEVINFO structure.

The capability flags allow GDI to determine which operations the PDEV supports. For example, GDI tests the capability flags that indicate whether the PDEV can handle Bezier curves and geometric wide lines before GDI attempts to call the DrvStrokePath function to draw paths with these primitive types. If the capability flags indicate that the PDEV cannot handle these primitive types, GDI will break down the lines or curves so it can make simpler calls to the driver.

From the driver's side, whenever the driver gets an advanced path-related call from GDI, it can return FALSE if the path or clipping is too complex for the device to process.

The driver cannot return FALSE from DrvStrokePath when handling a cosmetic line because the driver must handle any complex clipping or styling for cosmetic lines. However, DrvStrokePath can return FALSE if the path has Bezier curves or geometric lines. When this occurs, GDI breaks the call down to simpler calls, just as it does if the capability bits are not set. For example, if DrvStrokePath returns FALSE when it is sent a geometric line, GDI simplifies the line and calls the DrvFillPath function.

If DrvStrokePath is to report an error, it must return DDI_ERROR.

This kind of negotiation between GDI and the driver, for functions that depend on the PDEV, permits GDI and the driver to produce high quality output without excess communication.


Surface Negotiation

Drawing and text output require a surface on which to draw. This surface is created by the DrvEnableSurface function and is referred to as the primary surface. This surface is also known as the on-screen surface, because it appears in the video display. There is only one primary surface enabled per PDEV although a driver can support several PDEVs. Drivers that support the DrvCreateDeviceBitmap function can create and use additional surfaces. These bitmap surfaces are referred to as secondary surfaces or off-screen surfaces. For either type of surface, the driver is responsible for determining the type of drawing operations it supports.


Surface Coordinates

A device surface is a subset of an array of 228 by 228 pixels. These pixels are addressed by pairs of 28-bit signed numbers, the upper-leftmost pixel of the device surface is given the coordinates (0,0). The device surface lies in the lower right quadrant of this coordinate space, where both coordinates are nonnegative.


DC Origin

Application programs are required to keep their graphics within an array of 227 by 227 pixels. The device space has additional size at the graphics DDI level because the Window Manager may offset the application's coordinate system by one signed 27-bit coordinate, the DC origin. The DC origin is not visible to the driver and the driver identifies the graphics coordinates only after the offset is applied.


FIX Coordinates

Graphics DDIs use fractional coordinates that can specify a location on the device surface within one-sixteenth of a pixel. (On vector devices, the fractional coordinates are sixteen times more accurate than the device resolution.) The fractional coordinates are represented as 32-bit numbers in signed 28.4 bit FIX notation. In this notation, the highest-order 28 bits represent the integer part of the coordinate, and the lowest 4 bits represent the fractional part. For example, 0x0000003C equals +3.7500, and 0xFFFFFFE8 equals -1.5000.

FIX coordinates represent control points for lines and Bezier curves. For certain objects, such as rectangular clip regions, GDI uses signed 32-bit integers to represent coordinates. Because coordinates are 28-bit quantities, the highest 5 bits of an integer coordinate are either all cleared or all set.


Surface Types

Surface types can be viewed in context of how they are handled. These types are as follows:

  • Engine-managed surfaces
  • Device-managed surfaces (standard-format bitmaps)
  • Device-managed surfaces (nonstandard surfaces)

Engine-Managed Surfaces

An engine-managed surface:

  • is created and managed by GDI.
  • is created as a device-independent bitmap (or DIB) in one of the standard DIB formats: top-down, in which the origin is at the upper-left corner, or bottom-up, in which the origin is at the lower-left corner.
  • is of type STYPE_BITMAP.
  • does not have a corresponding device handle to a surface.

A standard-format bitmap is a single-plane, packed-pixel (where the data for each pixel is stored in a contiguous manner) format bitmap. Each scan line of the bitmap is aligned on a four-byte boundary.

Bitmaps created in the EngCreateBitmap function are in DIB format. A bitmap must be in DIB format in order for the engine to manage it.

Device-Managed Surfaces (Standard-Format Bitmaps)

A device-managed surface:

  • is created by a call to the device driver's DrvCreateDeviceBitmap function.
  • has an associated device handle to a surface (DHSURF — see SURFOBJ).
  • can be either opaque or non-opaque.

An opaque device-managed surface is one for which GDI has neither any information about the bitmap format nor a reference to the bits in the bitmap. For these reasons, the driver must support, at minimum, the DrvBitBlt, DrvTextOut, and DrvStrokePath functions. The type of such a surface is STYPE_DEVBITMAP.

A non-opaque device-managed surface is one for which GDI has information about the bitmap format and knows the location of the bits within the bitmap. Because of this, the driver does not need to implement any drawing operations, deferring all of them to GDI. The type of such a surface is SYTPE_BITMAP.

In order for a driver to convert a device-managed opaque bitmap to one that is non-opaque, it must call the EngModifySurface function. By doing this, the driver is informing GDI of the bitmap format and location of the bitmap in memory.

Having a device-managed DIB surface allows the driver to call back to GDI to have GDI draw on the surface. A driver that is managing its own surfaces, but is using a DIB, can still refer calls back to GDI by wrapping a DIB (created with the EngCreateBitmap function) around its surface.

Device-Managed Surfaces (Nonstandard-Format Bitmaps)

A driver can enable a device-managed nonDIB surface by calling the function EngCreateDeviceSurface to have GDI create the surface and return a handle to it. GDI relies on the driver to access, to control drawing to, and to read from a device-managed surface.

A device-dependent bitmap (DDB), sometimes called a device-format bitmap, is another type of nonDIB, device-managed surface. The DDB is supported to allow certain drivers, such as the VGA driver, to implement faster bitmap-to-screen block transfers. The DDB also allows drivers to draw to banked or nonDIB bitmaps in offscreen display memory. If a DDB is required, the driver can support the DrvCreateDeviceBitmap function and call the EngCreateDeviceBitmap function to have the engine return a handle to the bitmap.


GDI Color Space Conversions

GDI uses three RGB color spaces for its bitmap representations. In each of these color spaces, three bitfields, or color channels, are used to specify the number of bits used for red, green, and blue, respectively, in a given color. To be able to match GDI's capabilities with bitmaps, video drivers must be able to convert from one RGB color space to another.

GDI recognizes the following RGB color spaces:

  • 5,5,5 RGB: five-bit color channels for red, green, and blue
  • 5,6,5 RGB: a five-bit color channel for red, a six-bit color channel for green, and a five-bit color channel for blue
  • 8,8,8 RGB: eight-bit color channels for red, green, and blue

In general, when converting from a color channel with more bits to one with fewer bits, GDI discards the lower-order bits. When the conversion goes from a color channel with fewer bits to one with more bits, all of the bits of the smaller channel are copied to the larger channel. To fill out the remaining bits of the larger channel, some of the bits of the smaller channel are copied again to the larger channel. The following table summarizes the rules that GDI uses to convert from one RGB color space to another. In this table, color channels whose values change in the conversion are shown in bold font style.

GDI Color Space Conversion Rules

From | To | Rule | Example
5,5,5 | 5,6,5 | The most-significant bit (MSB) of the source's green channel is appended to the low-order end of the target's green channel. | (0x15, 0x19, 0x1D) becomes (0x15, 0x33, 0x1D) Note that only the green channel changes. The 5-bit channel value of the source is 1 1001, in binary, which is converted to a 6-bit value, 11 0011.
5,5,5 | 8,8,8 | For each channel, the three MSBs of the source channel are appended to the lower-order end of the target channel. | (0x15, 0x19, 0x1D) becomes (0xAD, 0xCE, 0xEF) In the red channel, 1 0101 becomes 1010 1101. Similar changes occur in the green and blue channels.
5,6,5 | 5,5,5 | Discard the least-significant bit (LSB) of the source's green channel. | (0x15, 0x33, 0x1D) becomes (0x15, 0x19, 0x1D) Note that only the green channel changes. Discard the lowest bit of 11 0011 to get 1 1001.
5,6,5 | 8,8,8 | For the 5-bit (red and blue) channels of the source, copy the three MSBs from the source and append them to the lower-order end of the target. For the 6-bit green channel, copy the two MSBs from the source and append them to the lower-order end of the target. | (0x15, 0x33, 0x1D) becomes (0xAD, 0xCF, 0xEF) In the red channel, 1 0101 becomes 1010 1101. In the green channel,11 0011 becomes 1100 1111. The transformation in the blue channel is similar to that of the red channel.
8,8,8 | 5,5,5 | Discard the three LSBs from each channel of the source. | (0xAB, 0xCD, 0xEF) becomes (0x15, 0x19, 0x1D) In the red channel, 1010 1011 becomes 1 0101. Similar transformations occur in the other two channels.
8,8,8 | 5,6,5 | Discard the three LSBs from the red and blue channels. Discard the two LSBs from the green channel. | (0xAB, 0xCD, 0xEF) becomes (0x15, 0x33, 0x1D) In the green channel, 1100 1101 becomes 11 0011. The changes in the red and blue channels are identical to those of the previously-listed transformation.


Hooking Versus Punting

The terms hooking and punting refer to driver decisions on whether it provides standard bitmap drawing operations, or relies on GDI to provide them. If the driver implements engine-managed surfaces, GDI can handle all drawing operations. A driver can, however, provide one or more of the drawing functions if its hardware can accelerate those operations. It does this by implementing, or hooking, a Drv Xxx function.

A driver writer may wish to implement only a subset of the drawing operations a particular graphics DDI entry point implements. For any operations the driver does not support, it can call the appropriate GDI functions to carry them out. This is referred to as punting to GDI. There are some situations in which the operation must be implemented in the driver. For example, if the driver implements a device-managed surface, certain drawing functions must be implemented in the display driver.

Hooking

By default, when a drawing surface is an engine-managed surface, GDI handles the drawing (rendering) operation. For a driver to take advantage of hardware that offers acceleration for some or all of these drawing functions for a given surface, or to make use of special block transfer hardware, it can hook these functions. To hook calls, the driver specifies the hooks as flags of the flHook parameter of the EngAssociateSurface and EngModifySurface functions.

If the driver specifies the hook flag of a function, it must provide that function in its list of supported graphics DDI entry points. The driver can optimize the operation where there is hardware support. Such a driver might handle only certain cases on a hooked call. For example, if complicated graphics are requested on a call that is hooked, it may still be more efficient to punt the call back to GDI, allowing GDI to handle the operation.

Here is another example of a driver that chooses whether or not to handle a hooked call. Consider a driver that supports hardware capable of handling bit-block-transfer calls with certain ROPs. Even though this driver can carry out many operations on its own, it is otherwise just a frame buffer. Such a driver will return a handle to the bitmap surface for the frame buffer as the surface for its PDEV, but it will hook the DrvBitBlt call for itself. When GDI calls DrvBitBlt, the driver can check the ROP to see if it is one of those supported by the hardware. If not, the driver can pass the operation back to GDI with a call to the EngBitBlt function.

Drivers that support device-managed surfaces must hook out some of the drawing functions; namely DrvCopyBits, DrvTextOut, and DrvStrokePath. Although GDI simulations can handle other drawing functions, it is recommended for performance reasons that drivers of this type hook out other functions, such as the DrvBitBlt and DrvRealizeBrush functions, because simulation requires drawing from and to the surface.

Punting

Punting the call back to GDI means to put in a call to the corresponding GDI simulation. In general, for every Drv Xxx graphics call, there is a corresponding GDI Eng Xxx simulation call that takes the same arguments. As long as the driver has made the bitmap non-opaque, all parameters can be passed without change to a GDI simulation. For each call the driver punts back to GDI, the size of the driver is reduced (since the code for that functionality can be omitted). However, because the engine owns the call, the driver does not have control over the execution speed. For some complicated cases, there may be no real advantage to providing support in the driver.

Hookable GDI Graphics Output Functions

The graphics output functions that the driver can hook and the corresponding GDI simulations are listed in the following table.

Driver Graphics Output Function | Corresponding GDI Simulation
DrvBitBlt | EngBitBlt
DrvPlgBlt | EngPlgBlt
DrvStretchBlt | EngStretchBlt
DrvStretchBltROP | EngStretchBltROP
DrvTextOut | EngTextOut
DrvStrokePath | EngStrokePath
DrvFillPath | EngFillPath
DrvStrokeAndFillPath | EngStrokeAndFillPath
DrvLineTo | EngLineTo
DrvCopyBits | EngCopyBits
DrvAlphaBlend | EngAlphaBlend
DrvGradientFill | EngGradientFill
DrvTransparentBlt | EngTransparentBlt


GDI Support Services

GDI exports many service routines that can simplify driver design. The driver can call these routines directly. The names of routines that are general graphics engine services whose names begin with Eng. Service routines related to a particular object always start with the name of the object; for example, CLIPOBJ_cEnumStart is a CLIPOBJ service.

Note The service routines in which the first argument is a pointer to a user object are methods on that user object, and are called using the usual C++ conventions. Therefore, drivers written in C++ can access the service routines as methods.

These service routines fall into the following categories:

Surface management

Palette services

Path services

Window services

Rendering services

Font and text services

Memory services

Event services

File, Module, and Process services

Semaphore services

Printer services

Driver-related services

Information services

Utility services

Floating point services

Halftone services

Using the Graphics DDI describes the graphics DDI entry points and also explains where many of these service routines can be used to help the driver implement the entry points. For detailed descriptions of each of the service functions, see Graphics Driver Functions (DDI).


GDI Support for Surfaces

For each PDEV, a driver must support the DrvEnableSurface function. DrvEnableSurface sets up the surface to be drawn on and associates it with the PDEV. The driver must also support the DrvDisableSurface function to disable created surfaces. Because GDI creates and maintains the surface, the driver relies on several GDI service functions, listed in the following table, to implement the enabling and disabling of surfaces.

Function Name | Purpose
EngAssociateSurface | Associates a surface with a PDEV and defines the drawing operations the driver writer wants to hook out for that surface. It uses the PDEV's default palette and style steps. The driver must make this call for the primary surface during the execution of DrvEnableSurface. The driver must also make this call when it enables a secondary surface before locking the surface to write on it.
EngCheckAbort | (Printers only) Enables a printer driver to determine whether its printer job has been terminated.
EngCreateBitmap | Creates a standard format DIB bitmap. GDI can perform all drawing operations on this type of surface.
EngCreateDeviceBitmap | Creates a device-dependent bitmap which the driver is responsible for drawing on (although it can be created as a DIB, in which case the driver can call back to have GDI draw on it).
EngCreateDeviceSurface | Creates a device-managed surface. The driver is responsible for managing certain drawing operations for this surface. The function returns a handle that the driver manages.
EngCreateWnd | Create a WNDOBJ structure on a specified surface.
EngDeleteSurface | Deletes a surface (DIB, device-dependent bitmap, or device-managed surface).
EngDeleteWnd | Deletes a WNDOBJ structure.
EngEraseSurface | Fills a specified rectangle on a surface with a given color, effectively erasing it. This function should be called only to erase the surface of a GDI bitmap.
EngLockDirectDrawSurface | Locks the kernel-mode handle of a DirectDraw® surface.
EngLockSurface | Gives the driver access to a created surface by creating a user object (SURFOBJ) for that surface. (The primary surface is not locked.)
EngMarkBandingSurface | (Printers only) Marks a surface as a banding surface.
EngModifySurface | Notifies GDI about the attributes of a surface that was created by the driver.
EngUnlockDirectDrawSurface | Releases the lock on a given DirectDraw® specified surface.
EngUnlockSurface | Unlocks a surface when the driver has finished a drawing operation (to be called when disabling a secondary surface).


GDI Support for Palettes

GDI can do most of the work with regard to palette management. When GDI calls the DrvEnablePDEV function, the driver returns its default palette to GDI as part of the DEVINFO structure. The driver must create this palette with the EngCreatePalette function.

A palette effectively maps 32-bit color indexes into 24-bit RGB color values, which is the way GDI uses palettes. A driver specifies its palette so GDI can determine how different color indexes are to appear on the device.

The driver need not deal with most palette operations and calculations as long as it uses the XLATEOBJ provided by GDI.

If the device supports a modifiable palette, it should implement the function DrvSetPalette. GDI calls DrvSetPalette when an application changes the palette for a device and passes the resulting new palette to the driver. The driver should set its internal hardware palette to match the new palette as closely as possible.

A palette can be defined for GDI in either of the two different formats listed in the following table.

Palette Format | Description
Indexed | A color index is an index into an array of RGB values. The array can be small, containing, for example, 16 color indexes, or large, containing, for example, 4096 color indexes or more.
Bit Fields | Bit fields in the color index specify colors in terms of the amounts of R, G, and B in each color. For example, 5 bits could be used for each, providing a value between 0 and 31 for each color. The 5-bit value would be scaled up to cover a range of 0 to 255 for each component when converting to RGB. (The usual RGB representation itself is defined by bit fields.)

GDI typically uses the palette mapping in reverse. That is, an application specifies an RGB color for drawing and GDI must locate the color index that causes the device to display that color. As indicated in the next table, GDI provides two primary palette service functions for creating and deleting the palette, as well as some service functions related to the PALOBJ and the XLATEOBJ used to translate color indexes between two palettes.

Function | Description
EngCreatePalette | Creates a palette. The driver associates the palette with a device by returning a handle to the palette in the DEVINFO structure.
EngDeletePalette | Deletes the given palette.
EngDitherColor | Returns a standard 8x8 dither that approximates the specified RGB color.
EngQueryPalette | Queries a palette for its attributes.
PALOBJ_cGetColors | Allows a driver to download RGB colors from an indexed palette. Called by the display driver in the DrvSetPalette function.
XLATEOBJ_cGetPalette | Retrieves the 24-bit RGB colors or the bitfield format for the colors in an indexed source palette. The driver can use this function to obtain information from the palette to perform color blending.
XLATEOBJ_hGetColorTransform | Returns the color transform for the specified translation object.
XLATEOBJ_iXlate | Translates a single source color index to a destination color index.
XLATEOBJ_piVector | Retrieves a translation vector from an indexed source palette. The driver can use this vector to perform its own translation of the source indexes to destination indexes.


GDI Services for Paths

To assist vector devices in filling complex areas, their drivers can call the engine functions, listed in the following table, that create, modify, and enumerate a path. The driver has access to paths through the PATHOBJ structure.

GDI Path Service Function | Description
EngCreatePath | Allocates a path for the driver's temporary use. The driver should delete this path before returning to GDI from its current drawing call.
EngDeletePath | Deletes a path allocated by the EngCreatePath function.
PATHOBJ_bCloseFigure | Closes a path (for filling) by drawing a line back to the starting point.
PATHOBJ_bEnum | Retrieves the next PATHDATA record from a path. Each record describes all or part of a subpath.
PATHOBJ_bEnumClipLines | Enumerates clipped line segments from a path.
PATHOBJ_bMoveTo | Changes the current position in a PATHOBJ-defined path.
PATHOBJ_bPolyBezierTo | Draws Bezier curves (cubic splines) in a PATHOBJ-defined path.
PATHOBJ_bPolyLineTo | Draws lines in a PATHOBJ-defined path.
PATHOBJ_vEnumStart | Notifies a PATHOBJ that the driver will begin calling PATHOBJ_bEnum to enumerate the curves in the specified path. This function must be called in case of an enumeration restart.
PATHOBJ_vEnumStartClipLines | Allows the driver to ask for lines to be clipped against a CLIPOBJ. This is useful when the clip region is more complex than a single rectangle.
PATHOBJ_vGetBounds | Returns a bounding rectangle for the path.


GDI Support for Window Objects

GDI provides support for window creation and deletion, and for the enumeration of rectangles in a window.

Function | Description
EngCreateWnd | Create a WNDOBJ structure on a specified surface.
EngDeleteWnd | Deletes a WNDOBJ structure.
WNDOBJ_bEnum | Gets a collection of rectangles from the visible region of a window.
WNDOBJ_cEnumStart | Sets parameters for enumeration of rectangles in the visible region of a window.
WNDOBJ_vSetConsumer | Sets a driver-defined value in the pvConsumer member of the specified WNDOBJ structure.


GDI Drawing and Related Services

To support the CLIPOBJ, BRUSHOBJ, and XFORMOBJ structures, GDI offers several drawing services, listed in the following table.

GDI Drawing Service Function | Description
BRUSHOBJ_hGetColorTransform | Retrieves the color transform for the specified brush.
BRUSHOBJ_pvAllocRbrush | Allocates memory for the driver's realization of a brush.
BRUSHOBJ_pvGetRbrush | Returns a pointer to the driver's realization of the brush. Realizes the brush if it has not yet been realized.
BRUSHOBJ_ulGetBrushColor | Returns the RGB color of the specified solid brush.
CLIPOBJ_bEnum | Retrieves a batch of rectangles from the clip region.
CLIPOBJ_cEnumStart | Sets parameters for enumeration of the rectangles in all or part of the clipped region. (The region can be enumerated once without calling this function, but subsequent enumerations require this function's use).
CLIPOBJ_ppoGetPath | Is used to retrieve complicated regions as a path.
EngAlphaBlend | Provides bit-block transfer capabilities with alpha blending. This is the GDI simulation for the DrvAlphaBlend function.
EngBitBlt | Provides general bit-block transfer capabilities either between device-managed surfaces, or between a device-managed surface and a GDI-managed standard format bitmap. This is the GDI simulation for the DrvBitBlt function.
EngControlSprites | Tears down or redraws sprites on the specified WNDOBJ area.
EngCopyBits | Translates between device-managed raster surfaces and GDI standard-format bitmaps. This is the GDI simulation for the DrvCopyBits function.
EngCreateClip | Allocates a CLIPOBJ for the driver's temporary use. The driver should call the EngDeleteClip function to delete it when it is no longer needed.
EngDeleteClip | Deletes a CLIPOBJ allocated with the EngCreateClip function.
EngDeviceIoControl | Sends a control code to the specified video miniport driver, causing the device to perform the specified operation.
EngFillPath | Fills (paints) a specified path. This is the GDI simulation for the DrvFillPath function.
EngGradientFill | Shades the specified graphics primitives. This is the GDI simulation for the DrvGradientFill function.
EngLineTo | Draws a single, solid, integer-only cosmetic line. This is the GDI simulation for the DrvLineTo function.
EngMovePointer | Moves the engine-managed pointer on the device. This is the GDI simulation for the DrvMovePointer function.
EngPaint | Paints a specified region. This is the GDI simulation for the obsolete DrvPaint function.
EngPlgBlt | Performs a rotate bit-block transfer. This is the GDI simulation for the DrvPlgBlt function.
EngSetPointerShape | Sets the shape of the pointer.
EngSetPointerTag | Creates a shape that is ORed with the application's pointer shape on DrvSetPointerShape calls to other associated drivers in a mirrored system.
EngStretchBlt | Performs a stretching bit-block transfer. This is the GDI simulation for the DrvStretchBlt function.
EngStretchBltROP | Performs a stretching bit-block transfer using a ROP. This is the GDI simulation for the DrvStretchBltROP function.
EngStrokeAndFillPath | Strokes (draws) a path and fills it at the same time. This is the GDI simulation for the DrvStrokeAndFillPath function.
EngStrokePath | Strokes (draws) a path. This is the GDI simulation for the DrvStrokePath function.
EngTransparentBlt | This is the GDI simulation for the DrvTransparentBlt function.
XFORMOBJ_bApplyXform | Applies the given transform or its inverse to the given array of points.
XFORMOBJ_iGetFloatObjXform | Downloads a FLOATOBJ transform to the driver.
XFORMOBJ_iGetXform | Downloads a transform to the driver.


GDI Font and Text Services

GDI provides support for font management and text output. The FONTOBJ structure and related functions give a driver access to a particular instance of a font. To support text output, the driver has access to the STROBJ structure and related functions. The following table lists FONTOBJ- and STROBJ-related functions.

Function | Description
EngComputeGlyphSet | Computes the glyph set supported on a device.
EngFntCacheAlloc | Allocates memory for a cached font file.
EngFntCacheFault | Reports an error to the font engine if the font driver encountered an error reading from or writing to a font data cache.
EngFntCacheLookUp | Retrieves a pointer to cached font file data.
EngGetCurrentCodePage | Returns the system's default OEM and ANSI code pages.
EngGetType1FontList | Retrieves a list of PostScript Type 1 fonts that are installed both locally and remotely.
EngTextOut | This is the GDI simulation for the DrvTextOut function.
FONTOBJ_cGetAllGlyphHandles | Allows the driver to retrieve every glyph handle of a GDI font. The driver uses this service to download an entire font.
FONTOBJ_cGetGlyphs | Translates glyph handles into pointers to the associated glyph data for the font consumer. These pointers are valid until the next call to FONTOBJ_cGetGlyphs.
FONTOBJ_pfdg | Retrieves the pointer to the FD_GLYPHSET structure associated with the specified font.
FONTOBJ_pifi | Retrieves the pointer to the IFIMETRICS structure that describes the associated font.
FONTOBJ_pjOpenTypeTablePointer | Returns a pointer to a view of an OpenType™ table.
FONTOBJ_pQueryGlyphAttrs | Returns information about a font's glyphs.
FONTOBJ_pvTrueTypeFontFile | Retrieves a pointer to the ROM-mapped TrueType file that is associated with a TrueType font.
FONTOBJ_pwszFontFilePaths | Retrieves the file path(s) associated with a font.
FONTOBJ_pxoGetXform | Retrieves the Notional-to-Device transform for the associated font. This transform is required for a driver to realize a driver-supplied font.
FONTOBJ_vGetInfo | Returns information that describes the associated font.
STROBJ_bEnum | Enumerates glyph identities and positions in the specified STROBJ.
STROBJ_bEnumPositionsOnly | Enumerates glyph identities and positions for a specified text string, but does not create cached glyph bitmaps.
STROBJ_bGetAdvanceWidths | Returns vectors specifying the probable widths of glyphs making up a specified string.
STROBJ_dwGetCodePage | Returns the code page associated with the specified STROBJ.
STROBJ_fxBreakExtra | Retrieves the amount of extra space to be added to each space character in a string when displaying and/or printing justified text.
STROBJ_vEnumStart | Restarts the enumeration of the GLYPHPOS array for the specified STROBJ. This function should be called by the driver prior to subsequent enumerations.


GDI Memory Services

GDI provides several memory-related services to driver writers, including the ability to allocate and deallocate system memory, user memory, private user memory, and video memory, as well as the ability to lock and unlock a range of memory. The following table lists the GDI memory services.

Function | Description
EngAllocMem | Allocates a block of memory from the system's paged pool, and inserts a caller-supplied tag before the allocation.
EngAllocPrivateUserMem | Allocates a block of private user memory from the address space of a specified process, and inserts a caller-supplied tag before the allocation.
EngAllocUserMem | Allocates a block of memory from the address space of the current process, and inserts a caller-supplied tag before the allocation.
EngFreeMem | Deallocates a block of system memory allocated by EngAllocMem.
EngFreePrivateUserMem | Deallocates a block of private user memory allocated by EngAllocPrivateUserMem.
EngFreeUserMem | Deallocates a block of user memory allocated by EngAllocUserMem.
EngSecureMem | Locks down the specified address range in memory.
EngUnsecureMem | Unlocks a memory address range that is locked down.
HeapVidMemAllocAligned | Allocates off-screen memory for a display driver by using the DirectDraw video memory heap manager.
VidMemFree | Frees off-screen memory allocated for a display driver by HeapVidMemAllocAligned.


GDI Event Services

GDI provides several services related to events. Drivers using these services can create and delete events, map and unmap events, and read, set and clear events.

Function | Description
EngClearEvent | Sets a specified event object to the nonsignaled state.
EngCreateEvent | Creates a synchronization event object that can be used to synchronize hardware access between a display driver and the video miniport driver.
EngDeleteEvent | Deletes the specified event object.
EngMapEvent | Maps a user-mode event object to kernel mode.
EngReadStateEvent | Returns the current state of the specified event object: signaled or nonsignaled.
EngSetEvent | Sets the specified event object to the signaled state, and returns the event object's previous state.
EngUnmapEvent | Cleans up the kernel-mode resources allocated for a mapped user-mode event.
EngWaitForSingleObject | Puts the current thread of the display driver into a wait state until the specified event object is set to the signaled state, or until the wait times out.


GDI File, Module, and Process Services

GDI provides a variety of services for file, module, and process manipulation.

Function | Description
EngDeleteFile | Deletes a file.
EngFindImageProcAddress | Returns the address of a function within an executable module.
EngFindResource | Determines the location of a resource in a module.
EngFreeModule | Unmaps a file from system memory.
EngGetCurrentProcessId | Gets the ID of the current process.
EngGetCurrentThreadId | Gets the ID of the current thread.
EngGetFileChangeTime | Returns the time a file was last written to.
EngGetFilePath | Determines the file path associated with the specified font file.
EngGetProcessHandle | Retrieves a handle to the current client process.
EngLoadImage | Loads the specified executable image into kernel-mode memory.
EngLoadModule | Loads the specified data module into system memory for reading.
EngLoadModuleForWrite | Loads the specified executable module into system memory for writing.
EngMapFile | Creates or opens a file and maps it into system space.
EngMapFontFile | Obsolete. See EngMapFontFileFD.
EngMapFontFileFD | Maps a font file into system memory, if necessary, and returns a pointer to the base location of the font data in the file.
EngMapModule | Returns the address and size of an executable file that was loaded by EngLoadModule.
EngQueryFileTimeStamp | Returns the time stamp of a file.
EngUnloadImage | Unloads an image loaded by EngLoadModule.
EngUnmapFile | Unmaps the view of a file from system space.
EngUnmapFontFile | Obsolete. See EngUnmapFontFileFD.
EngUnmapFontFileFD | Unmaps the specified font file from system memory.


GDI Semaphore Services

GDI provides a selection of services related to semaphores and safe semaphores. A driver can use these services to create or delete a semaphore, and acquire or release a semaphore.

Function | Description
EngAcquireSemaphore | Acquires the resource associated with the semaphore for exclusive access by the calling thread.
EngCreateSemaphore | Creates a semaphore object.
EngDeleteSafeSemaphore | Removes a reference to the specified safe semaphore.
EngDeleteSemaphore | Deletes a semaphore object from the system's resource list.
EngInitializeSafeSemaphore | Initializes the specified safe semaphore.
EngIsSemaphoreOwned | Determines whether any thread holds the specified semaphore.
EngIsSemaphoreOwnedByCurrentThread | Determines whether the currently executing thread holds the specified semaphore.
EngReleaseSemaphore | Releases the specified semaphore.


GDI Printer Services

GDI provides a number of services that are of interest to printer driver writers. The following table lists these services.

Function | Description
EngEnumForms | Enumerates the forms supported by the specified printer.
EngGetForm | Gets the FORM_INFO_1 details for the specified form.
EngGetPrinter | Retrieves information about the specified printer.
EngGetPrinterData | Retrieves configuration data for the specified printer.
EngGetPrinterDataFileName | Retrieves the string name of the printer's data file.
EngGetPrinterDriver | Retrieves driver data for the specified printer.
EngMapFontFile | Obsolete. See EngMapFontFileFD.
EngMapFontFileFD | Maps a font file into system memory, if necessary, and returns a pointer to the base location of the font data in the file.
EngMarkBandingSurface | Marks the specified printer surface as a banding surface.
EngSetPrinterData | Sets the configuration data for the specified printer.
EngUnmapFontFile | Obsolete. See EngUnmapFontFileFD.
EngUnmapFontFileFD | Unmaps the specified font file from system memory.
EngWritePrinter | Allows printer graphics DLLs to send a data stream to printer hardware.


GDI Driver-Related Services

Driver writers can use the GDI driver-related services listed in the following table to create or delete driver objects, obtain the name of the driver's DLL, and lock or unlock a driver object.

Function | Description
EngCreateDriverObj | Creates a DRIVEROBJ structure. This structure is used to track a device-managed resource that must be released if the resource-allocating process terminates without first cleaning it up.
EngDeleteDriverObj | Frees the handle used for tracking a device-managed resource.
EngGetDriverName | Returns the name of the driver's DLL.
EngLockDriverObj | Creates an exclusive lock on a driver object for the calling thread.
EngUnlockDriverObj | Unlocks the driver object.


GDI Information Services

GDI provides several services a driver can use to query the system about device and system attributes, a file's time stamp, and the performance counter. These services are listed in the following table.

Function | Description
EngQueryDeviceAttribute | Allows the driver to query the system about particular attributes of the device.
EngQueryFileTimeStamp | Returns the time stamp of a file.
EngQueryLocalTime | Queries the local time.
EngQueryPerformanceCounter | Queries the performance counter.
EngQueryPerformanceFrequency | Queries the frequency of the performance counter.
EngQuerySystemAttribute | Queries processor or system-specific capabilities.


GDI Utility Services

The following table lists the miscellaneous GDI utility services. These services include debugging support, getting and setting the last error, several conversion services that convert from one character encoding type to another, a sort routine, and others.

Function | Description
EngDebugBreak | Causes a breakpoint in the current process to occur.
EngDebugPrint | Prints the specified debug message to the kernel debugger.
EngGetLastError | Returns the last error code logged by GDI for the calling thread.
EngHangNotification | Notifies the system that a specified device is inoperable or unresponsive.
EngLpkInstalled | Determines whether the language pack is installed on the system.
EngMulDiv | Multiplies two 32-bit values and then divides the 64-bit result by a third 32-bit value. The return value is rounded up or down to the nearest integer.
EngMultibyteToUnicodeN | Converts the specified ANSI source string into a Unicode string using the current ANSI code page.
EngMultibyteToWideChar | Converts an ANSI source string into a wide character string using the specified code page.
EngProbeForRead | Probes a structure for read accessibility.
EngProbeForReadAndWrite | Probes a structure for read and write accessibility.
EngSetLastError | Causes GDI to report an error code, which can be retrieved by an application.
EngSort | Performs a quick-sort on the specified list.
EngUnicodeToMultibyteN | Converts the specified Unicode string into an ANSI string using the current ANSI code page.
EngWideCharToMultibyte | Converts a wide character string into an ANSI source string using the specified code page.


GDI Floating Point Services

Kernel-mode graphics drivers must do all floating point operations between calls to the GDI-supplied EngSaveFloatingPointState and EngRestoreFloatingPointState routines.

If the hardware has a floating point processor, the driver can do floating point operations directly. Otherwise, the driver can use the GDI FLOATOBJ services shown in the following table to emulate floating point operations. Regardless of processor type, the driver should use the FLOATL data type when declaring floating point values.

Function | Description
EngRestoreFloatingPointState | Restores the Windows 2000 and later kernel floating point state after the driver uses any floating point or MMX hardware instructions.
EngSaveFloatingPointState | Saves the current Windows 2000 and later kernel floating point state.
FLOATOBJ_Add | Adds two FLOATOBJs.
FLOATOBJ_AddFloat | Adds a FLOATOBJ and a FLOATL.
FLOATOBJ_AddLong | Adds a FLOATOBJ and a LONG.
FLOATOBJ_Div | Divides one FLOATOBJ by another.
FLOATOBJ_DivFloat | Divides a FLOATOBJ by a FLOATL.
FLOATOBJ_DivLong | Divides a FLOATOBJ by a LONG.
FLOATOBJ_Equal | Determines whether two FLOATOBJs are equal.
FLOATOBJ_EqualLong | Determines whether a FLOATOBJ and a LONG are equal.
FLOATOBJ_GetFloat | Calculate and return the FLOAT-equivalent value of a FLOATOBJ.
FLOATOBJ_GetLong | Calculate and return the LONG-equivalent value of a FLOATOBJ.
FLOATOBJ_GreaterThan | Determines whether one FLOATOBJ is larger than another.
FLOATOBJ_GreaterThanLong | Determines whether a FLOATOBJ is larger than a LONG.
FLOATOBJ_LessThan | Determines whether one FLOATOBJ is less than another.
FLOATOBJ_LessThanLong | Determines whether a FLOATOBJ is less than a LONG.
FLOATOBJ_Mul | Multiplies two FLOATOBJ values.
FLOATOBJ_MulFloat | Multiplies a FLOATOBJ by a FLOATL.
FLOATOBJ_MulLong | Multiplies a FLOATOBJ by a LONG.
FLOATOBJ_Neg | Changes the sign of a FLOATOBJ.
FLOATOBJ_SetFloat | Sets a FLOATOBJ to a particular FLOATL value.
FLOATOBJ_SetLong | Sets a FLOATOBJ to a particular LONG value.
FLOATOBJ_Sub | Subtracts one FLOATOBJ from another.
FLOATOBJ_SubFloat | Subtracts a FLOATL from a FLOATOBJ.
FLOATOBJ_SubLong | Subtracts a LONG from a FLOATOBJ.


GDI Halftone Services

GDI Halftone support includes the services listed in the following table.

Function | Description
HT_ComputeRGBGammaTable | Causes GDI to compute device red, green, and blue intensities based on gamma numbers.
HT_Get8BPPFormatPalette | Returns a halftone palette for use on standard 8-bits per pixel device types.
HT_Get8BPPMaskPalette | Returns a mask palette for an 8-bits per pixel device type.
HTUI_DeviceColorAdjustment | Displays a dialog box that allows a user to adjust a device's halftoning properties.


GDI Data Types

The data types defined in the following table appear in the device driver interface. Several of the listed data types have already been described in GDI User Objects. Data types that are pointers are marked with an asterisk (*).

Graphics DDI Data Type | Variable Name Prefix | Definition
BOOL | b | A 32-bit value that can be either TRUE or FALSE.
BYTE | j | An 8-bit unsigned integer.
BRUSHOBJ* | pbo | A pointer to a brush object.
CLIPLINE | cl | A clipline object.
CLIPOBJ* | pco | A pointer to a clipping object.
DHPDEV | dhpdev | A 32-bit handle, defined by the device driver, that identifies a physical device.
DHSURF | dhsurf | A 32-bit handle, defined by the device driver, that identifies a device-managed surface.
FIX | fix | A fixed point number.
FLOATL | e | A floating point number.
FLOAT_LONG | el | A 32-bit overloaded value that is interpreted as either a LONG or FLOATL, depending on context.
FLONG | fl | A set of 32-bit flags.
FONTOBJ* | pfo | A pointer to a font object.
FSHORT | fs | A set of 16-bit flags.
FWORD | fw | A 16-bit signed integer.
HBM | hbm | A 32-bit handle, defined by GDI, that identifies a bitmap.
HPAL | hpal | A 32-bit handle, defined by GDI, that identifies a palette.
HSURF | hsurf | A 32-bit handle, defined by GDI, that identifies a surface.
LONG | l | A 32-bit signed integer.
MIX | mix | A 32-bit quantity, whose lower 16 bits define foreground and background mix modes.
PALOBJ* | ppalo | A pointer to a palette object.
PATHOBJ* | ppo | A pointer to a path object.
POINTE | pte | A point structure that consists of {FLOATL x, y;}.
POINTFIX | ptfx | A point structure that consists of {FIX x, y;}.
POINTL | ptl | A point structure that consists of {LONG x, y;}.
POINTQF | ptq | A point structure that consists of {LARGE_INTEGER x, y;}. Each member of this structure is a 64-bit coordinate in 28.36 format.
PWSZ | pwsz | A pointer to a zero-terminated Unicode string.
PVOID | pv | A pointer to a VOID, an undefined data type.
RECTL | rcl | A rectangle structure that consists of {LONG xLeft, yTop, xRight, yBottom;}.
RECTFX | rcfx | A rectangle structure that consists of {FIX xLeft, yTop, xRight, yBottom;}.
ROP4 | rop4 | A 32-bit value that specifies how source, destination, pattern, and mask pixels are to be mixed.
SHORT | s | A 16-bit signed integer.
SIZEL | sizl | A two-dimensional structure that consists of {ULONG cx, cy;}.
STROBJ* | pstro | A pointer to a text string object.
SURFOBJ* | pso | A pointer to a surface object.
ULONG | ul | A 32-bit unsigned integer.
USHORT | us | A 16-bit unsigned integer.
XFORMOBJ* | pxo | A pointer to a coordinate transform object.
XLATEOBJ* | pxlo | A pointer to a color translation object.

The parameter prefixes listed in the next table are used to modify variable name prefixes in accordance with their usage.

Prefix | Parameter Usage
i | An enumerated index
c | A count
p | A pointer


Using the Graphics DDI

In response to device-independent application calls routed through the Graphics Device Interface (GDI), a graphics driver must ensure that its graphics device produces the required output. A graphics driver controls graphics output by implementing as much of the graphics Device Driver Interface (DDI) as is necessary.

Graphics DDI function names are in the Drv Xxx form. GDI calls these Drv Xxx functions to pass data to the driver. When an application makes a request of GDI, and GDI determines that the driver supports the relevant function, GDI calls that function. It is the responsibility of the driver to provide the function and return to GDI upon the function's completion.

This section describes the graphics DDI functions that writers of display and printer drivers must be aware of. Graphics DDI function declarations, structure definitions, and constants can be found in winddi.h. For more information about the graphics DDI functions, see Graphics Driver Functions (DDI).

The topics contained in this section are as follows:

Graphics Driver Functions

Supporting Initialization and Termination Functions

Creating Device-Dependent Bitmaps

Supporting Graphics Output

Supporting Graphics DDI Color and Pattern Functions

Supporting Graphics DDI Font and Text Functions

The DEVMODEW Structure


Graphics Driver Functions

The topics that follow describe the driver entry point functions, categorizing them as required, required under certain circumstances, and optional.

Required Graphics Driver Functions

Conditionally Required Graphics Driver Functions

Optional Graphics Driver Functions

When a device driver returns an error, it should typically call the GDI EngSetLastError function to report an extended error code. The application program can then retrieve the error code.


Required Graphics Driver Functions

All graphics drivers must support the entry points that GDI calls to enable and disable the driver, the PDEV structure, and the surface associated with each PDEV. The following table lists the needed functions in the order in which they are typically called.

Entry Point | Description
DrvEnableDriver | As the initial driver entry point, this function provides GDI with the driver version number and entry points of optional functions supported.
DrvGetModes | Lists the modes supported by a specified video hardware device. (This function is required of display drivers only.)
DrvEnablePDEV | Enables a PDEV.
DrvCompletePDEV | Informs the driver upon completion of device installation.
DrvEnableSurface | Creates a surface for a specified hardware device.
DrvDisableSurface | Informs the driver that the surface created for the current device is no longer needed.
DrvDisablePDEV | When the hardware is no longer needed, frees memory and resources used by the device and any surface created, but not yet deleted.
DrvDisableDriver | Frees all allocated resources for the driver and returns the device to its initial state.
DrvAssertMode | Resets the video mode for a specified hardware device. (This function is required of display drivers only.)
DrvResetDevice | Resets the device when it has become inoperable or unresponsive.


Conditionally Required Graphics Driver Functions

Besides the functions that are always required, certain other functions may be required, depending on how a driver is implemented. The conditionally-required functions are listed in the following table. If the driver manages its own primary surface (using the EngCreateDeviceSurface function to get a handle to the surface), or its own offscreen bitmaps, the driver must also support several drawing functions. Drivers writing to standard format DIBs usually allow GDI to manage most or all of these operations. Displays that support settable palettes must also support the DrvSetPalette function.

It is more common for a printer driver than a display driver to define or draw fonts. A display driver is not required to handle fonts. If the hardware has a resident font, the driver must supply information to GDI about this font. This information includes font metrics, mappings from Unicode to individual glyph identities, individual glyph attributes, and kerning tables.

Entry Point | When Required | Description
DrvCopyBits | Device-managed surfaces | Translates between device-managed raster surfaces and GDI standard-format bitmaps.
DrvDescribePixelFormat | Displays that support windows with different pixel formats on a single surface | Describes a PDEV's pixel format.
DrvGetTrueTypeFile | TrueType font drivers | Gives GDI access to a memory-mapped TrueType font file.
DrvLoadFontFile | Font drivers | Specifies file to use for font realizations.
DrvQueryFont | Printer drivers | Retrieves a GDI structure for a given font.
DrvQueryFontCaps | Font drivers | Asks driver for font driver capabilities.
DrvQueryFontData | Printer drivers | Retrieves information about a realized font.
DrvQueryFontFile | Font drivers | Asks driver for font file information.
DrvQueryFontTree | Printer drivers | Queries a tree structure defining one of three types of font mapping.
DrvQueryTrueTypeOutline | TrueType font drivers | Returns TrueType glyph handles to GDI.
DrvQueryTrueTypeTable | TrueType font drivers | Gives GDI access to TrueType font files.
DrvResetPDEV | Devices that allow mode changes in documents | Transfers driver state from old PDEV to new PDEV.
DrvSetPalette | Displays that support settable palettes | Realizes the palette for a specified device.
DrvSetPixelFormat | Displays that support windows with different pixel formats on a single surface | Sets a window's pixel format.
DrvStrokePath | Device-managed surfaces | Renders a path on the display.
DrvSwapBuffers | Drivers that support a pixel format with double buffering | Displays contents of a surface's hidden buffer.
DrvTextOut | Device-managed surfaces or drivers that define fonts | Renders a set of character images (glyphs) at specified positions.
DrvUnloadFontFile | Font drivers | Informs driver that a font file is not needed.


Optional Graphics Driver Functions

In the interests of reducing driver size, driver writers usually add only those optional functions that are well-supported in hardware. For example, a driver for hardware that supports Image Color Management (ICM) can implement the DrvIcm Xxx functions. The following tables list the functions that a graphics driver can optionally implement.

Display and Printer Driver Functions

Entry Point | Description
DrvAlphaBlend | Provides bit block transfer capabilities with alpha blending.
DrvBitBlt | Executes general bit block transfers to and from surfaces.
DrvCreateDeviceBitmap | Creates and manages a bitmap with a driver-defined format.
DrvDeleteDeviceBitmap | Deletes a device-managed bitmap.
DrvDitherColor | Requests a device to create a brush dithered against a device palette.
DrvFillPath | Paints a closed path for a device-managed surface.
DrvGradientFill | Shades the specified primitives.
DrvIcmCheckBitmapBits | Checks whether the pixels in the specified bitmap lie within the device gamut of the specified transform.
DrvIcmCreateColorTransform | Creates an ICM color transform.
DrvIcmDeleteColorTransform | Deletes the specified ICM color transform.
DrvIcmSetDeviceGammaRamp | Sets the hardware gamma ramp of the specified display device.
DrvLineTo | Draws a single solid integer-only cosmetic line.
DrvPlgBlt | Provides rotate bit block transfer capabilities between combinations of device-managed and GDI-managed surfaces.
DrvRealizeBrush | Realizes a specified brush for a defined surface.
DrvStretchBlt | Allows stretching block transfers among device-managed and GDI-managed surfaces.
DrvStretchBltROP | Performs a stretching bit block transfer using a ROP.
DrvStrokeAndFillPath | Simultaneously fills and strokes a path.
DrvSynchronize | Coordinates drawing operations between GDI and a display driver-supported coprocessor device; for engine-managed surfaces only.
DrvSynchronizeSurface | Coordinates drawing operations between GDI and a display driver-supported coprocessor device; for engine-managed surfaces only. If a driver provides both DrvSynchronize and DrvSynchronizeSurface, GDI will only call DrvSynchronizeSurface.
DrvTransparentBlt | Provides bit block transfer capabilities with transparency.

Display-Driver Only Functions

Entry Point | Description
DrvMovePointer | Moves a pointer to a new position, and redraws it.
DrvSaveScreenBits | Saves or restores a specified rectangle of the screen (display driver only).
DrvSetPointerShape | Removes the pointer from the screen, if the driver has drawn it, and then sets a new pointer shape.

Functions Used Primarily by Printer Drivers

Entry Point | Description
DrvDestroyFont | Notifies driver that a font realization is no longer needed; driver can free allocated data structures.
DrvDrawEscape | Implements draw-type escape functions.
DrvEscape | Queries information from a device not available in a device-independent DDI.
DrvFree | Frees font storage associated with an indicated data structure.

Printer-Driver Only Functions

Entry Point | Description
DrvEndDoc | Sends end-of-document information.
DrvFontManagement | Allows access to printer functionality not directly available through GDI.
DrvGetGlyphMode | Returns type of font information to be stored for a particular font.
DrvNextBand | Realizes the contents of a surface's just-drawn band.
DrvQueryPerBandInfo | Returns banding information for the specified banded printer surface.
DrvSendPage | Sends raw bits from a surface to the printer.
DrvStartBanding | Prepares the driver for banding.
DrvStartDoc | Sends start-of-document control information.
DrvStartPage | Sends start-of-page control information.

Font Driver Function

Entry Point | Description
DrvQueryAdvanceWidths | Supplies character advance widths for a specified set of glyphs.


Supporting Initialization and Termination Functions

A graphics driver can support multiple devices and multiple concurrent use of each device. Therefore, initialization and termination occur in three distinct layers, with each layer having its own timing. Initialization occurs in the following order:

  1. Driver initialization
  2. PDEV initialization
  3. Surface initialization

Termination occurs in the reverse order.


Driver Initialization and Cleanup

While the device driver may implement several or many functions, it exports only DrvEnableDriver to GDI. The driver exposes its other supported functions through a function table. The first call GDI makes to a device driver is to the DrvEnableDriver function. Within this function, the driver fills in the passed-in DRVENABLEDATA structure so that GDI can determine which other Drv Xxx functions are supported and where they are located. The driver supplies the following information in DRVENABLEDATA:

  • The iDriverVersion member contains the graphics DDI version number for a particular Windows operating system version. The winddi.h header defines the following constants:
Constant | Operating System Version
DDI_DRIVER_VERSION_NT4 | Windows NT 4.0
DDI_DRIVER_VERSION_NT5 | Windows 2000
DDI_DRIVER_VERSION_NT5_01 | Windows XP

For more information about how these constants are used, see DRVENABLEDATA.

  • The c member contains the number of DRVFN structures in the array.
  • The pdrvfn member points to an array of DRVFN structures that lists the supported functions and their indexes.

For GDI to call a function other than the driver's enable and disable functions, the driver must make the function's name and location available to GDI.

While DrvEnableDriver can also perform one-time initializations, such as the allocation of semaphores, a driver should not actually enable the hardware during DrvEnableDriver. Hardware initialization should occur in a driver's DrvEnablePDEV function. Likewise, a driver should enable the surface in the DrvEnableSurface function.

GDI calls the DrvDisableDriver function to notify the driver that it is about to be unloaded. In response to this call, the driver should free all resources and memory still allocated by the driver at this point.

If the hardware needs to be reset, GDI calls the driver's DrvAssertMode function.


PDEV Initialization and Cleanup

Each kernel-mode graphics driver represents a single logical device managed by GDI. In turn, a driver can manage one or more PDEV structures. A PDEV is a logical representation of the physical device. It is characterized by the type of hardware, logical address, and surfaces that can be supported:

  • Type of Hardware – As an example of a driver supporting a PDEV characterized by the type of hardware, one driver could support the LaserWhiz, LaserWhiz II, and LaserWhiz Super printers. The device name passed by GDI specifies which logical device is requested from the total set of driver-supported devices.
  • Logical Address – A single driver can support printers attached to LPT1, COM2, and a server named \\SERVER1\PSLASER, for example. In addition, a display driver that can support more than one VGA display simultaneously might differentiate between them by port numbers, such as 0x3CE, 0x2CE, and so on. The logical address for printers and other hard copy output devices is determined by GDI; the EngWritePrinter function directs the output to the proper destination. Displays can either determine their own logical address implicitly or retrieve the address from the private section of DEVMODEW.

    The DEVMODEW structure provides the driver with required environment settings, such as the name of the device and other information specific to either printer or display drivers.

  • Surfaces – Each PDEV requires a unique surface. For example, if a printer driver is to work on two print jobs simultaneously, each requiring a different page format such as the landscape and portrait formats, each print job requires a different PDEV. Similarly, a display driver might support two desktops on the same display, each desktop requiring a different PDEV and surface. For each surface required, there is a call to the DrvEnablePDEV function to create a different PDEV for that surface.

In response to a call to DrvEnablePDEV, the driver returns information about the capabilities of the hardware device to GDI through several structures.

The GDIINFO structure is zero-filled before GDI calls DrvEnablePDEV. The driver fills in GDIINFO to communicate the following information to GDI:

  • Driver version number
  • Basic device technology (raster versus vector)
  • Size and resolution of printable page
  • Color palette and gray scale information
  • Font and text capabilities
  • Halftoning support
  • Style step numbers

The driver should fill only the fields it supports and ignore the rest.

The driver fills in the DEVINFO structure with flags that describe the graphics capabilities of this PDEV. In nearly all cases, the information from DEVINFO tells GDI the level of graphics support the driver can provide. For example, if a drawing of a treble clef is needed, information within DEVINFO tells GDI whether the driver can handle Bezier curves or whether GDI must send multiple line segments instead. The driver should fill in as many fields as it supports and leave the others untouched.

Another important piece of information the driver must provide is a pointer (phsurfPatterns) to a buffer filled with handles for surfaces representing the standard fill patterns. Besides the standard fill patterns, phsurfPatterns can contain a null, which causes GDI to create the pattern surface automatically according to the device resolution and the pixel size. When GDI is called on to realize a brush with a standard pattern, it calls the DrvRealizeBrush function to realize the brush defined for the requested pattern.

GDI passes DrvEnablePDEV a handle, hDriver, for the kernel driver that supports the device. For a printer driver, hDriver provides the handle to the printer and is used in calls, such as EngWritePrinter, to the spooler.

Whenever GDI calls DrvEnablePDEV, the driver must allocate the memory required to support the PDEV that is created, even if DrvEnablePDEV is called to create other PDEV structures for different modes. (A driver can have several active PDEVs, although only one can be enabled at a time.) However, an actual surface is not supported until GDI calls DrvEnableSurface.

If a device surface requires the allocation of a bitmap, the allocation is not necessary until the surface is enabled (usually within the DrvEnableSurface function). Although applications often request device information before actually writing to the device, waiting to allocate a large bitmap can save valuable resources and improve driver performance during system initialization.

When the installation of the PDEV is complete, GDI calls the DrvCompletePDEV function to inform the driver that installation of the physical device is complete. This function also provides the driver with GDI's logical handle to the PDEV, which the driver uses in calls to GDI functions.

A call to the driver's DrvDisablePDEV function indicates that the given physical device is no longer needed. In this function, the driver should free any memory and resources used by the physical device.

Refer also to Enabling and Disabling the Surface.


Enabling and Disabling the Surface

As the final initialization stage, GDI calls DrvEnableSurface to have the driver enable a surface for an existing PDEV. DrvEnableSurface must specify the type of surface by calling the appropriate GDI service to create it. As described in GDI Support for Surfaces, and depending on the device and circumstances, the driver can call the appropriate GDI services from within DrvEnableSurface to create the surfaces:

  • For a device-managed surface, the driver should call the EngCreateDeviceSurface function to get a handle for the surface.
  • To create a standard-format (DIB) bitmap that GDI can manage completely, including the performance of all drawing operations, the driver should call the EngCreateBitmap function. The driver can hook out any drawing operations it can optimize. The driver can either have GDI allocate the space for the pixels or can provide the space itself, although the latter option is usually used only by printer and frame buffer drivers.

DrvEnableSurface returns a valid surface handle as a return value.

Following the creation of the surface, the driver must associate that surface with a PDEV by calling the GDI service EngAssociateSurface. This call also tells GDI which drawing function a driver has hooked for that surface.

GDI calls the DrvDisableSurface function to inform the driver that the current surface created for the PDEV by DrvEnableSurface is no longer required. The driver must deallocate any memory and resources allocated during the execution of DrvEnableSurface. DrvDisableSurface is always called before DrvDisablePDEV, if the PDEV has an enabled surface.

Once created, a surface must be deleted when it is no longer in use. Failure to properly match surface creation with deletion can cause stray objects to accumulate and degrade system performance.


Creating Device-Dependent Bitmaps

When an application requests the creation of a bitmap, a driver can create and manage a DDB by supporting the DrvCreateDeviceBitmap function. When such a driver creates the bitmap, it can store the bitmap in any format. The driver examines the passed parameters and provides a bitmap with at least as many bits-per-pixel as requested.

Note Graphics drivers can improve performance by supporting bitmaps in off-screen memory and by drawing bitmaps using hardware. For an example of this, see the Permedia display driver sample.

Within DrvCreateDeviceBitmap, the driver calls the GDI service EngCreateDeviceBitmap to have GDI create a handle for the device bitmap.

If the driver supports DrvCreateDeviceBitmap, it creates a DDB, defines its format, and returns a handle to it. The driver controls where the bitmap is stored, and in what format. The driver should support the color format that matches its device surface most closely.

The contents of the bitmap are undefined after creation. If the driver returns NULL, it does not create and manage the bitmap; instead, GDI performs these tasks.

If the driver creates bitmaps, it must also be able to delete them by implementing the DrvDeleteDeviceBitmap function.


Supporting Graphics Output

The particular graphics operations that a driver handles depend upon the drawing surface and the capabilities of the hardware. If the surface is a standard-format DIB, GDI will handle all rendering operations not supported by the driver. The driver can hook out any of the drawing functions and implement them to take advantage of hardware support.

For a device-managed surface, a driver must, at a minimum, support the graphics output functions DrvCopyBits, DrvTextOut, and DrvStrokePath. It can optionally support any of the other graphics output functions. Supporting DrvBitBlt, for example, can enhance performance. Some functions require a certain level of capability while others allow the device to indicate its capability by setting the appropriate GCAPS flags in the DEVINFO structure.

All drawing calls to the driver are always single threaded, regardless of the surface type.

The topics that follow describe how a driver can implement the following operations:

Drawing lines and curves

Drawing and filling paths

Copying bitmaps

Halftoning

Image Color Management


Drawing Lines and Curves

The types of lines and curves included in graphic output are geometric lines, cosmetic lines, and Bezier curves.

For line and curve output, a driver can support the DrvStrokePath, DrvFillPath, and DrvStrokeAndFillPath functions. The driver must support DrvStrokePath for drawing lines if the surface is device-managed; drivers are not required to support curves.

When GDI draws a line or curve with any set of attributes, GDI can call DrvStrokePath. At a minimum, the DrvStrokePath function must support the drawing of solid and styled cosmetic lines with a solid color brush and arbitrary clipping. The GDI PATHOBJ_Xxx and CLIPOBJ_Xxx service functions make this possible by breaking down the lines into a set of lines one pixel wide with precomputed clipping. DrvStrokePath provides a pointer, plineattrs, to the LINEATTRS structure that defines the various line attributes.

When the path or clipping is too complex for the driver to process on the device, the driver can punt the call back to GDI by calling the EngStrokePath function. In this case, GDI can break the DrvStrokePath call into a set of lines one pixel wide with precomputed clipping.

By calling the CLIPOBJ_Xxx services from GDI, a driver can have GDI enumerate all the lines in the path and perform all of the line clipping calculations. In addition, a driver can use the PATHOBJ_Xxx, CLIPOBJ_Xxx, or XFORMOBJ_Xxx services to simplify the graphics operations. For example, a driver can use CLIPOBJ_cEnumStart and CLIPOBJ_bEnum to enumerate the rectangles in a clip region, send this region down to the printer, and clip to it. The driver can also use PATHOBJ_vEnumStart and PATHOBJ_bEnum to enumerate lines or curves in the path. It can then send the path to the device, and stroke it.


Cosmetic Lines

A cosmetic line is always one pixel wide and is drawn using a solid color brush. It is rendered according to the Grid Intersection Quantization (GIQ) diamond convention, which determines which pixels should be turned on to render the cosmetic line.

The figure below shows a line superimposed on a rectangular grid, in which the pixels are located at the grid intersection points. To determine which pixels should be illuminated, imagine a diamond, centered on the line, and sliding along it. The diamond's width and height are exactly equal to the distance between adjacent pixel centers. As the diamond moves along the line, any pixel whose center is completely covered by the diamond is turned on. If a line passes through a point halfway between two adjacent pixels, the pixel to be turned on depends on the slope of the line and how the adjacent pixels are oriented: horizontally (side by side), or vertically (one above the other).

The following table summarizes these cases.

Slope of line (absolute value) | Adjacent pixels are oriented: | Result
Slope < 1 or Slope > 1 | Horizontally | Light the pixel at diamond's left vertex.
Slope < 1 or Slope > 1 | Vertically | Light the pixel at diamond's top vertex.
Slope = 1 | Horizontally | Light the pixel at diamond's top vertex.
Slope = 1 | Vertically | Light the pixel at diamond's right vertex.

The diamond convention lights one pixel in each column for lines with slopes between -1 and 1, and one pixel in each row for lines with slope greater than 1 in absolute value. This way, a cosmetic line is rendered with no gaps.

Start and end pixels of a cosmetic line are also determined by the diamond convention. A cosmetic line is first-pixel-inclusive and last-pixel-exclusive; that is, if the line starts inside the diamond for a pixel, that pixel is illuminated. Similarly, if the line ends inside the diamond for a pixel, that pixel is not illuminated.

Diamond Convention for Cosmetic Line

For rendering cosmetic lines, the DrvStrokePath function follows the GIQ diamond convention. The DrvLineTo function is an optional entry point that a driver can supply as an optimization for application calls to the Microsoft® Win32 LineTo function. DrvLineTo is simpler than DrvStrokePath because it supports only integer end-points and solid cosmetic lines.

For raster devices that support the R2_NOT mix mode, a binary raster operation that changes the destination color to its inverse, the driver must use exact rendering. Rendering should also be exact for devices that require rendering by both GDI and the driver. This includes devices for which GDI draws on some bitmaps and the driver draws on other surfaces (unless the pixels are too small to make any visible difference). This also includes devices that request GDI to handle complex clipping.


Geometric Wide Lines

The shape of a geometric line is determined by the width, join style, and end-cap style of the brush, and the current world-to-device transform in the XFORMOBJ structure. The line can be drawn using either a solid or a nonsolid brush.

Drivers for more advanced hardware may support geometric wide lines in the DrvStrokePath function. GDI determines whether a driver can draw a path containing a geometric line by testing the GCAPS_GEOMETRICWIDE capability flag in the DEVINFO structure returned in the call to DrvEnablePDEV. If the driver does not have the capability, or if the function fails to handle an operation because the path or clipping is too complex for the device, GDI automatically transforms the call to the simpler DrvFillPath function.

A geometric wide line has a specific meaning to a display driver graphics function. A path containing device coordinates is transformed to world coordinates using the inverse of the current transform. A geometric construction with the specified width then obtains a widened version of the path, taking into account joins and end caps. This path is transformed to device coordinates again and filled with the specified brush.

Styling of a geometric wide line is specified by an array of floating-point values. The array has a finite length, but is used as though it repeats indefinitely. The first array entry specifies the length, in world coordinates, of the first dash; the next entry specifies the length of the first gap. After this, lengths of dashes and gaps alternate. For example, the style array {3.0,1.0,1.0,1.0} causes a line to be drawn with alternating long and short dashes.

Styling can be thought of as the driver moving along a path before widening, "erasing" the parts of the path corresponding to the gaps. This breaks the path into many subpaths. The broken path is then widened as if it had no line style, applying end caps and joins as usual. Style arrays can be of odd length. For example, the style array {1.0} causes the driver to draw a line with alternating dashes. The style state (defined as the current distance into the styling array) is provided for the beginning of the first subpath in a path. It is considered to be reset to 0.0 at the beginning of each subsequent subpath, which occurs after any Win32 MoveToEx operation.


Styled Cosmetic Lines

The DrvStrokePath function must support the drawing of cosmetic lines with arbitrary clipping using a solid-color brush. The driver can make a call to the GDI service PATHOBJ_vEnumStartClipLines to precompute the clipping.

Styling of a cosmetic line is similar to that of a geometric wide line because it is specified by a repeating array. For a styled cosmetic line, the array entries are LONG values that contain the lengths in style steps. The relation between style steps and pixels is defined by the xStyleStep, yStyleStep, and denStyleStep fields in the GDIINFO structure returned by the DrvEnablePDEV function.

When the driver calls PATHOBJ_bEnumClipLines, to handle styled cosmetic lines through complex clipping, GDI modifies the value of the CLIPLINE structure's iStyleState member to represent the style state. The style state is the offset back to the first pixel of the line segment; that is, the first pixel that would be rendered if the line were not clipped. The style state consists of two 16-bit values packed into a ULONG value. If HIGH and LOW are the high-order and the low-order 16 bits of the style state, a fractional version of the style state, referred to as style position, can be computed as:

    style position = HIGH + LOW/denStyleStep

For example, if the values in iStyleState are 1 and 2, and denStyleStep is 3, then style position is 5/3. To determine exactly where the drawing of the style begins in the style array, take the product:

    style position * denStyleStep

In this example, with a denStyleStep value of 3, the drawing position is calculated to exclude the first five (5/3 * 3) pixels of the style array. That is, drawing begins at the sixth pixel in the style array of this clipped line.

There are y-styled cosmetic lines and x-styled cosmetic lines. If a line extends dx device units in the x direction and dy units in the y direction, the line is y-styled when the following is true:

    (dy * yStyleStep)  ≥  (dx * xStyleStep)

In this case, the style position is advanced by yStyleStep/denStyleStep for each pixel advanced in the y direction.

Conversely, a line is x-styled and the style position is advanced by xStyleStep/denStyleStep for each pixel advanced in the x direction when the following is true:

    (dx * xStyleStep)  >  (dy * yStyleStep)

When the style position advances to a new integer, the style step advances one unit in the style array.

The following figure shows several cosmetic styled lines having different slopes. In this illustration, the pixel grid shown is not square, but is shown as it would be for an EGA display in which four pixels in the x direction represent the same distance as three pixels in the y direction. The style steps in the GDIINFO structure ensure that styled lines appear the same at any slope on displays whose pixels are not square. In this illustration, the styling array (defined by the pstyle member of the LINEATTRS structure) is {1,1}, which is a broken line having equal-sized dots and gaps. The driver's value of xStyleStep is 3, yStyleStep is 4, and denStyleStep is 12.

Styled Cosmetic Line Examples

To illustrate further, suppose a dot matrix printer has a 144-dpi horizontal resolution and a 72-dpi vertical resolution. In addition, suppose the dot length of the minimum dot is 1/24-inch. To support this printer, select the smallest numbers for xStyleStep and yStyleStep that can compensate for the printer's aspect ratio, such as 1 for xStyleStep and 2 (144/72) for yStyleStep, and 6 (144/24) for denStyleStep.

If the LA_ALTERNATE bit is set in the flag in the LINEATTRS structure, a special style is used for a cosmetic line. In this case, every other pixel is on, regardless of direction or aspect ratio. Style state is returned as if the style array is {1,1} and xStyleStep, yStyleStep, and denStyleStep are all one. In other words, if lStyleState is zero, the first pixel is on; if lStyleState is one, the first pixel is off.

If the LA_STARTGAP bit is set in the LINEATTRS flag, the sense of the elements in the style array is inverted. The first array entry specifies the length of the first gap, the second entry specifies the length of the first dash, and so forth.


Bezier Curves

Some advanced hardware devices can draw paths containing Bezier curves (cubic splines), which are general-purpose curve primitives. If so, the driver can include support for these curves in the DrvStrokePath function.

When GDI must draw a Bezier curve path on a device-managed surface, it will test the GCAPS_BEZIERS flag (in the DEVINFO structure) to determine if it should call DrvStrokePath. If called, this function either performs the requested operation or decides not to handle it, just as it does for geometric wide lines. In the latter case, GDI breaks the request down into simpler operations, for example, by converting curves to line approximations.


Drawing and Filling Paths

The graphics driver considers a path to be a sequence of lines, and/or curves, defined by a path object (PATHOBJ structure). To handle the filling of closed paths, the driver supports the function DrvFillPath.

GDI can call DrvFillPath to fill a path on a device-managed surface. GDI compares the requirements of the fill with the DEVINFO structure's flags GCAPS_BEZIERS, GCAPS_ALTERNATEFILL, and GCAPS_WINDINGFILL, to decide whether to call the driver. If GDI does call the driver, the driver either performs the operation or returns, informing GDI that the path or clipping requested is too complex to be handled by the device. In the latter case, GDI breaks the request down into several simpler operations.

A driver can also support the optional DrvStrokeAndFillPath function to fulfill requests for path fills. This function fills and strokes a path at the same time. Many GDI primitives require this functionality. If a wide line is used for stroking, the filled area must be reduced to compensate for the increased width of the bounding path.

When the driver returns FALSE from either the DrvFillPath or DrvStrokeAndFillPath functions, GDI converts the fill-path request to a set of simpler operations and calls the driver function again. If the device returns FALSE again on the second call to DrvFillPath, GDI converts the path to a clip object and then calls EngFillPath. For a FALSE return when DrvStrokeAndFillPath is recalled, GDI can convert the call into separate calls to DrvStrokePath and DrvFillPath.


Path Fill Modes

The two fill modes defined for paths are alternate and winding. Both fill modes use an even-odd rule to determine how to fill a closed path.

FP_ALTERNATEMODE applies the even-odd rule as follows: draw a line from any arbitrary start point in the closed path to some point obviously outside of the closed path. If the line crosses an odd number of path segments, the start point is inside the closed region and is therefore part of the fill area. An even number of crossings means that the point is not in an area to be filled.

FP_WINDINGMODE considers not only the number of times that the vector crosses segments of the path, but also considers the direction of each segment. The path is considered to be drawn from start to finish, with each segment's direction implied by the order of its specified points: the first vertex of a segment is the "from" point, and the second vertex is the "to" point. Now draw the same arbitrary line described in alternate mode. Starting from zero, add one for every "forward" direction segment that the line crosses, and subtract one for every "reverse" direction segment crossed. (Forward and reverse are based on the dot product of the segment and the arbitrary line.) If the count result is nonzero, then the start point is inside the fill area; a zero count means the point is outside the fill area.

The following figure shows how to apply both rules to the more complex situation of a self-intersecting path. In alternate fill mode, point A is inside because ray 1 passes through an odd number of line segments, while points B and C are outside, because rays 2 and 3 pass through an even number of segments. In winding-fill mode, points A and C are inside, because the sum of the forward (positive) and reverse (negative) line segments crossed by their rays, 1 and 3 respectively, is not zero, while point B is outside, because the sum of the forward and reverse line segments that ray 2 crosses is zero.

Alternate and Winding Mode Fills


Filling Areas (Closed Paths)

As in line drawing, pixels for filling are considered to be at integer coordinates. Each scan line in a region is bordered on the left and right by a segment of the path. Pixels that fall between the left and right borders are considered inside the fill region. Pixels that are exactly on the left border are also inside, but those exactly on the right border are excluded. If a top border is exactly horizontal, any pixels exactly on the border are inside while pixels exactly on the lower border are excluded.

The following figure shows how the pixels included in the fill region are determined relative to left and right borders of the region. Stated mathematically, the region is considered to be "closed" on the left and top, and "open" on the right and bottom.

Determining the Pixels Included in a Fill Region

The convention described above for the x-axis of the fill region also applies to the y-axis by substituting the left border with the top border and the right border with the bottom border.


Copying Bitmaps

Bit block transfer (BitBlt) functions implemented by drivers must copy blocks of bits from one surface to another. These functions include:

DrvBitBlt

DrvStretchBlt

DrvCopyBits

There is also a display-driver-specific BitBlt function named DrvSaveScreenBits.

If the surface being drawn on is a device-managed surface or bitmap, the driver must support a minimum level of bit block transfer functions. If the surface is a GDI-managed standard format bitmap, GDI handles only those operations not hooked by the driver.

The DrvBitBlt function provides general bit block transfer capabilities. If a driver supports a device-managed surface or bitmap, the driver must implement the DrvCopyBits function. At a minimum, the driver must do the following when DrvCopyBits is called:

  • Perform a block transfer to and from a bitmap, in the device's preferred format, and to the device surface.
  • Perform the transfer with the SRCCOPY (0xCCCC) ROP.
  • Allow arbitrary clipping.

The driver can use the GDI CLIPOBJ enumeration services to reduce the clipping to a series of clip rectangles. GDI passes down a translation vector, the XLATEOBJ structure, to assist in color index translation between source and destination surfaces.

If the surface of a device is organized as a standard-format DIB, the driver can support only simple transfers. If a call comes in with a complicated ROP, the driver can punt the block transfer request back to GDI with a call to the EngCopyBits function. This allows GDI to break up the call into simpler functions the driver can perform.

If a source is used, DrvBitBlt maps a geometric source rectangle exactly onto a geometric destination rectangle. If there is no source, DrvBitBlt ignores its pptlSrc parameter. The destination rectangle is the surface to be modified and it is defined by two integer points, upper left and lower right. The rectangle is lower right exclusive; the lower and right edges of the rectangle are not part of the block transfer. DrvBitBlt cannot be called with an empty destination rectangle. The two points of the rectangle are always well ordered; that is, both coordinates of the lower right point are greater than their counterparts in the upper left point.

DrvBitBlt deals with different ROPs and can perform some optimizations, depending on the device. In some cases, if the ROP is a solid color, a fill rather than a BitBlt can be done. For devices that do not support all ROPs, true WYSIWYG is not always possible. The PostScript driver, for example, supports no ROPs.

Optionally, a block transfer handled by DrvBitBlt can be masked and involve color index translation. A translation vector assists in color index translation for palettes. The transfer might need to be arbitrarily clipped by a display driver, using a series of clip rectangles. The required region and information are furnished by GDI.

Implementing DrvBitBlt represents a significant portion of the work involved in writing a driver for a raster display driver that does not have a standard-format frame buffer. The Microsoft VGA driver furnished with the Windows DDK provides example code that completely supports the basic function for a planar device. Implementing DrvBitBlt for other devices may be less complex.

A driver can optionally provide the DrvStretchBlt function, even drivers that support device-managed surfaces. This function provides capabilities for stretching block transfers between device-managed and GDI-managed surfaces. DrvStretchBlt supports only certain types of stretching, such as stretching by integer multiples.

DrvStretchBlt also allows a driver to write on GDI bitmaps, especially when the driver can do halftoning. The function also permits the same halftoning algorithm to be applied to GDI bitmaps and device surfaces.

DrvStretchBlt maps a geometric source rectangle exactly onto a geometric destination rectangle. The source is a rectangle with corners displaced by (-0.5,-0.5) from the given integer coordinates. The points specified in the function parameters lie on integer coordinates that correspond to pixel centers. A rectangle defined by two such points is considered to be geometric, with two vertices whose coordinates are the given points, but with 0.5 subtracted from each coordinate. (GDI POINTL structures use a shorthand notation for specifying these fractional coordinate vertices.) Note that the edges of any such rectangle never intersect a pixel, but go around a set of pixels. The pixels inside the rectangle are normal pixels for a bottom right-exclusive rectangle.

The points defining the corners of the source rectangle are well-ordered. DrvStretchBlt cannot be given an empty source rectangle. Unlike DrvBitBlt, DrvStretchBlt can be called with a single clipping rectangle to prevent round-off errors in clipping the output.

The destination rectangle is defined by two integer points. These points are not well ordered, which means that the coordinates of the second point are not necessarily larger than those of the first. The source rectangle these points describe does not include the lower and right edges. Because the rectangle is not well ordered, DrvStretchBlt must sometimes perform inversions in the two x coordinates and/or the two y coordinates. (The driver must not attempt to read pixels that do not lie on the source surface). DrvStretchBlt cannot be called with an empty destination rectangle.

For color translation, DrvStretchBlt provides a pointer, pxlo, to the XLATEOBJ structure, that is used to translate between the source and destination surfaces. The XLATEOBJ structure can be queried to find the destination index for any source index. For a high-quality stretching block transfer, DrvStretchBlt is required to interpolate colors in some cases. DrvStretchBlt also uses the COLORADJUSTMENT structure to define the color adjustment values that are to be applied to the source bitmap before the bits are stretched.

DrvStretchBlt uses the iMode parameter to define how the source pixels are to be combined for output. In particular, iMode provides the HALFTONE option that permits the driver to use groups of pixels in the output surface to best approximate the color or grey level of the output. Changes to the COLORADJUSTMENT structure are passed to the driver after the next DrvStretchBlt call with an iMode of HALFTONE. In addition, if the driver requires GDI to handle halftoning for GDI bitmaps, the driver can hook out DrvStretchBlt, set the iMode parameter to HALFTONE, and return it in EngStretchBlt.

If DrvStretchBlt has hooked a call to the EngStretchBlt function and is asked to do something it does not support, it returns the request to GDI so that the appropriate function can handle it.

The DrvCopyBits function is called by GDI from its simulation operations to translate between a device-managed raster surface and a GDI standard-format bitmap. DrvCopyBits provides a fast path for SRCCOPY (0xCCCC) ROP bit block transfers.

Required for a graphics driver with device-managed bitmaps or raster surfaces, this function must translate driver surfaces to and from any standard-format bitmap. DrvCopyBits is never called with an empty destination rectangle, and the two points of the destination rectangle are always well ordered. This call has the same requirements as DrvBitBlt.

DrvCopyBits is also called with RLE bitmaps (see the Platform SDK documentation) and DDBs. The bitmaps are provided to this function as a result of application program calls to several Win32 GDI routines. The optional DDB is supported only by a few specialized drivers.


Halftoning

Traditional analog halftoning uses a halftoning screen, composed of cells of equal sizes, with fixed-cell spacing center-to-center. The fixed-cell spacing accommodates the thickness of the ink, while the size of a dot within each cell can vary to produce the impression of a continuous tone.

On a computer, most printing or screen shading also uses a fixed-cell pixel size. To simulate the variable dot size, a combination of cluster pixels simulates the halftone screen. GDI includes halftoning default parameters that provide a good first approximation. Additional device-specific information can be added to the system to improve output.

The driver sends GDI the device-related specifications that GDI needs to do halftoning through the GDIINFO structure returned by the DrvEnablePDEV function. The driver specifies the pattern size with the ulHTPatternSize member of GDIINFO, which defines the preferred output format for halftoning. For specific devices, halftoning relates to the halftone pattern sizes. GDI provides numerous predefined pattern sizes from 2 x 2 through 16 x 16.

For each standard pattern size, there is also a modified version. It is identified by the suffix "_M" on the standard pattern size's name. For example, the defined name of the standard 6-by-6 pattern is HT_PATSIZE_6x6, while the name of the modified 6-by-6 pattern is HT_PATSIZE_6x6_M). The modified version gives more color resolution, but can produce a side effect of horizontal or vertical noise. In addition, because each of these pattern sizes is device resolution-dependent, the appropriate pattern size depends upon the specific device.

The tradeoff between pattern size (spatial resolution) and color resolution is determined by the pattern size. A larger halftone pattern produces better color resolution, while a smaller pattern results in the best spatial resolution. Determining the best pattern size is frequently a matter of trial and error. For more information, refer to GDIINFO in the Graphics Driver Reference.

Another of the GDIINFO structure members affecting halftoning is flHTFlags, which contains flags that describe the device resolution needed for halftoning.

GDI handles color adjustment requests from the application and passes the information down to driver functions through the graphics DDI. If the application selects halftoning and the surface is a standard format DIB, GDI processes the bitmap using its halftoning capabilities, after which, the bitmap is sent to the device. In the PostScript driver, the EngStretchBlt function can send the bitmap to the printer using either the DrvCopyBits or DrvBitBlt (in the SRCCOPY mode) functions.

Letting GDI perform the halftoning instead of the PostScript printer, for example, provides a faster output with better WYSIWYG quality. An interface to the PostScript driver allows the user to adjust the halftoning and provides a checkbox to turn off GDI halftoning if the printer's built-in halftoning capabilities are preferred.

The DrvDitherColor function can return the DCR_HALFTONE value, which requests that GDI approximate a color using the existing device (halftone) palette. DCR_HALFTONE can be used with a display driver only when the device contains a device (halftone) palette, such as a VGA-16 adapter card, because it has a standard fixed palette. Monochrome drivers, including most raster printers, can use the iMode parameter in DrvDitherColor to obtain good gray-scale effects.

Note Windows 2000 and later do not support halftoning on 24-bit (or higher) devices.


Image Color Management

An image displayed on a computer monitor often appears differently when it is printed on a color printer. In recognition of this problem, Windows 2000 and later incorporates Image Color Management (ICM) to perform color correction on images so that their appearance is consistent across a variety of output devices.

To find out more about Image Color Management and a particular class of output device, follow the appropriate link:

Color Management for Displays

Color Management for Printers

Color Management for Still Image Devices

For a general discussion about Image Color Management, see the Platform SDK documentation.


Supporting Graphics DDI Color and Pattern Functions

Graphics DDI color and pattern functions include palette management and brush realization functions.


Managing Palettes

As described in GDI Support for Graphics Drivers, GDI handles much of the palette management work. The driver must supply its default palette to GDI in the DEVINFO structure when GDI calls the function DrvEnablePDEV. At this time, the driver should create the default palette with a call to the GDI service function EngCreatePalette.

Drivers that support settable palettes also must support the DrvSetPalette function. This function is used exclusively by display drivers.


Realizing Brushes

Graphics functions that output lines, text or fills take at least one brush as an argument. The brush defines the pattern to be used to draw the graphics object on the specified surface. Each output function that takes a brush requires a brush origin. The brush origin provides the coordinates of a pixel on the device surface to be aligned with the upper left pixel of the brush's pattern. The brush pattern is repeated (tiled) to cover the whole device surface.

The driver can support the following functions to define brushes:

DrvRealizeBrush

DrvDitherColor

A brush is always used with a mix mode that defines how the pattern should be mixed with the data already on the device surface. The MIX data type consists of two ROP2 values packed into a single ULONG value. The foreground ROP is in the lowest-order byte. The next byte contains the background ROP. For more information, see the Platform SDK documentation.

GDI keeps track of all logical brushes that an application has requested for use. Before asking a driver to draw something, GDI first issues a call to the driver function DrvRealizeBrush. This allows the driver to compute the optimal representation of the required pattern for its own drawing code.

DrvRealizeBrush is called to realize the brush defined by psoPattern (pattern for the brush) and by psoTarget (surface for the realized brush). A realized brush contains information and accelerators a driver needs to fill an area with a pattern. This information is defined and used only by the driver. Driver realization of a brush is written into a buffer that the driver can cause to be allocated by calling the GDI service function BRUSHOBJ_pvAllocRBrush from within DrvRealizeBrush. GDI caches all realized brushes; consequently, they seldom need to be recomputed.

In DrvRealizeBrush, the BRUSHOBJ user object represents the brush. The surface for which the brush is to be realized can be the physical surface for the device, a DDB, or a standard-format bitmap. For a raster device, the surface describing the brush pattern represents a bitmap; and for a vector device, it is always one of the pattern surfaces returned by the DrvEnablePDEV function. The transparency mask used for the brush is a one-bit-per-pixel bitmap with the same extent as the pattern. A mask bit of zero means that the pixel is considered to be a background pixel for the brush; that is, the target pixel is unaffected by that particular pattern pixel. DrvRealizeBrush uses an XLATEOBJ structure to translate the colors in the brush pattern to the device color indexes.

The driver should call the GDI service function BRUSHOBJ_pvGetRbrush when the value of the iSolidColor member of the BRUSHOBJ structure is 0xFFFFFFFF and the pvRbrush member is NULL. BRUSHOBJ_pvGetRbrush retrieves a pointer to the driver's realization of a specified brush. If the brush has not been realized when the driver calls this function, GDI automatically calls DrvRealizeBrush for the driver's realization of the brush.

Dithering

If necessary, GDI can request the assistance of the driver when trying to create a brush with a solid color that cannot be represented exactly on the hardware. GDI calls the driver function DrvDitherColor to request the driver to dither a brush against the reserved portion of the device palette.

Dithering uses a pattern of several colors to approximate the chosen color, and its result is an array of device color indexes. A brush created using these colors for its pattern is usually a good approximation of the given color. DrvDitherColor can also represent a color that cannot be specified exactly by a device. To do this, DrvDitherColor requests a pattern of several colors and creates a brush that approximates the given solid color.

The function DrvDitherColor is optional and is called only if the GCAPS_COLOR_DITHER or GCAPS_MONO_DITHER capability flags are set in the flGraphicsCaps member of the DEVINFO structure. DrvDitherColor can return the values listed in the following table.

Value | Meaning
DCR_DRIVER | Indicates that the dither values have been calculated by the driver. The handle to a cxDither by cyDither array of device color indexes is passed back in this case.
DCR_HALFTONE | Indicates that GDI should approximate a color using the existing device (halftone) palette. For example, GDI can use the typical palette for a printer that contains only three or four colors. DCR_HALFTONE can be used with a display driver only when the device contains a device (halftone) palette, such as VGA-16 adapter card, which has a standard fixed palette.
DCR_SOLID | Indicates that GDI should map the requested color to the nearest color value in the existing device palette (many to one).

Monochrome drivers should support DrvDitherColor in order for GDI to obtain good gray-level patterns.


Supporting Graphics DDI Font and Text Functions

For many devices, GDI can handle all font functions. Some drivers, however, can draw their own fonts, or their device's own fonts, on device surfaces. Other drivers are font drivers, which can provide glyph bitmaps and/or outlines, as well as glyph metrics to GDI. In these cases, the driver must support some of the available font functions.

Text output is a more general function. If the surface is a standard-format bitmap, GDI can handle all text output, unless the driver hooks out the call to enhance performance. For a device-managed surface, the driver must support text output.

The following topics provide information with regard to the support of font and text management functions.

Managing and Optimizing Fonts

Drawing Text


Managing and Optimizing Fonts

A producer is a driver that can generate fonts. It produces glyph information as output, including glyph metrics, bitmaps, and outlines. A consumer is a driver that uses fonts. It accepts glyph information as input for generating text output, and must draw its own fonts or those of the hardware on a device-managed surface. A driver can be both a producer and a consumer. For example, a printer driver can act as a producer while servicing a DrvQueryFontData call to provide glyph metrics and later act as a consumer while processing a DrvTextOut call.

A driver is required to handle fonts only when it is a font producer or a font consumer. If the hardware has a resident font, the driver must supply information to GDI about this font, including the font metrics in the IFIMETRICS structure, mappings from Unicode to individual glyph identities, individual glyph attributes, and kerning tables. There are also functions the driver must support. Some functions are required both by font drivers and drivers that use driver-specific or device-specific fonts. Others are required only by font drivers.

The support of font functions depends on the driver's abilities. The general types are:

Metrics functions

Glyph functions

TrueType functions


Font Metric Functions

When a driver must support fonts, it must supply font information to GDI through the IFIMETRICS structure. There is a separate IFIMETRICS structure for each font. Most of the fields are expressed in terms of FWORDs, each a signed 16-bit quantity, in the design space. If the font is a raster font, the design space and device space are the same and a font unit is equivalent to the distance between pixels.

Basically, the IFIMETRICS structure is the graphics DDI version of a text-metric structure. All distances refer to the notional coordinate system of the font designer. The notional space coordinate system is a right-handed Cartesian coordinate system in which the y-coordinate increases towards the top and the x-coordinate increases towards the right.

The IFIMETRICS structure is designed to be of variable length. No restriction is placed on the length of the character strings associated with the font. It is common practice to store the strings immediately following the last field of the IFIMETRICS structure.

Any driver that provides fonts must support the DrvQueryFont function. The driver also can include the function DrvQueryFontData to retrieve information about a realized font. In a call to DrvQueryFontData, GDI provides a pointer to an array of glyphs or kerning handles. The driver returns information about associated glyphs in GDI GLYPHDATA structures. If DrvQueryFontData has been given kerning handles, it returns information about kerning pairs in the form of Win32 POINTL structures. The following table lists the font metric functions.

Function | Description
DrvDestroyFont | Notifies the driver that a font realization is no longer needed so the driver can free any data structures that it allocated. GDI calls this function once for the font producer and once for the font consumer. Optional—should be supported only if the driver must free allocated resources.
DrvFree | Informs the driver that the indicated data structure is no longer needed. Optional—should be implemented only if the driver's memory management requires this information.
DrvQueryFont | Returns a pointer to the IFIMETRICS structure for a font. Required by all drivers that deal with fonts.
DrvQueryFontData | Returns information about a realized font. Required (for selected iMode values) by all drivers that deal with fonts.
DrvQueryFontTree | Returns pointers to structures that define either the mapping from Unicode to glyph handles or the mapping of kerning pairs to kerning handles. Required by all drivers that deal with fonts.

The function DrvQueryFontTree allows GDI to obtain pointers to tree structures that define one of the following:

  • Mapping from Unicode to glyph handles, including glyph variants (GDI FD_GLYPHSET structure)
  • Mapping of kerning pairs to kerning handles (FD_KERNINGPAIR structure)

DrvQueryFontTree requires effort to generate the needed structures, so the driver should precompute these files if possible. The structures can be stored in a resource or in a file. If the structures are stored in a file, the ideal method for loading or reading them is to call the EngMapFontFile function, which maps a file to the memory. Because the file does not get added to the swap file, the memory can be made available if needed, which is more efficient than opening and reading in a file.

In particular, the driver returns an identifier in the pid parameter. GDI passes it to the DrvFree function, with the returned pointer, when the FD_GLYPHSET structure or an array of FD_KERNINGPAIR structures is no longer needed. Depending on how memory is managed in the driver, pid can identify the structure, identify how the structure was allocated, or do nothing at all.

DrvFree and DrvDestroyFont are both optional functions. GDI calls DrvFree to inform the driver that the specified data structure is no longer needed. The driver does not need to implement it unless it allocates memory for the structure and needs to be informed when the corresponding data structure can be released. For example, if the data is associated with the FONTOBJ structure, the deletion could be deferred until a call to DrvDestroyFont, so it would not be necessary to implement DrvFree.

DrvDestroyFont notifies the driver that a font realization is no longer needed so the driver can free any data structures it allocated. GDI calls this function once for the font producer and once for the font consumer. It should be implemented only if the driver must free allocated resources when the font instance is destroyed.


Font Driver Functions

In addition to the functions described in the previous topics, the following table lists several other functions that font drivers should support.

Function | Description
DrvLoadFontFile | Specifies a file to be used for creating font realizations; the driver must prepare the file for use. Required for font drivers.
DrvQueryAdvanceWidths | Asks the driver to send GDI character advance widths for a specified set of glyphs.
DrvQueryFontCaps | Copies an array of bits that defines the capabilities of a font driver, to a specified buffer.
DrvQueryFontFile | Depending on the mode of the query, returns the number of font faces in a font file or in a descriptive string. Required for font drivers.
DrvQueryGlyphAttrs | Returns information about a font's glyphs.
DrvUnloadFontFile | Informs driver that a font file is no longer needed so driver can do necessary cleanup. Required for font drivers.

GDI calls the DrvLoadFontFile function with a particular file to be used for creating font realizations. This function is required only of font drivers. When the function DrvLoadFontFile is called, the driver performs the conversions necessary to prepare the file for use.

DrvLoadFontFile returns a unique identifier that allows GDI to request the correct font using a GDI-maintained font usage table. Once a font is loaded, GDI does not call for the same font to be loaded again.

GDI calls DrvUnloadFontFile when the specified font file is no longer needed. The DrvUnloadFontFile function is required only in font drivers. DrvUnloadFontFile causes all scratch files to be deleted and all allocated system resources to be freed.

GDI calls the DrvQueryFontFile function to return information about a font file that was loaded by the driver. DrvQueryFontFile is required only in font drivers. The type of information to be returned is specified by iMode. If iMode is QFF_DESCRIPTION, the function returns a string that Microsoft® NT-based operating systems use to describe the font file. If iMode is QFF_NUMFACES, the function returns the number of faces in the font file. The faces are identified by an index from the range 1 to number of faces.


TrueType Font Driver Functions

TrueType font drivers must support the functions listed in the following table.

Function | Description
DrvGetTrueTypeFile | Gives GDI efficient access to the memory-mapped TrueType font file.
DrvQueryTrueTypeOutline | Returns glyph handles in native TrueType format.
DrvQueryTrueTypeTable | Gives GDI access to specific files in the TrueType font file format.

All these functions provide GDI with information about TrueType font files. DrvQueryTrueTypeTable should give GDI access to specific tables in the TrueType font-file format. DrvQueryTrueTypeOutline must send GDI glyph outlines in native TrueType format. DrvGetTrueTypeFile returns to GDI the TrueType driver's private entry point that allows GDI efficient access to the memory mapped TrueType font file.


Drawing Text

The text output functions are called only for a device-managed surface (a device bitmap or surface), or for a GDI-managed surface if the driver has hooked the call in the EngAssociateSurface function. The graphic output primitives for text are the functions:

DrvTextOut

DrvGetGlyphMode

GDI calls DrvTextOut to render the pixels for a set of glyphs at specified positions for text output. Many of the DrvTextOut capabilities are defined with the GCAPS bits of the DEVINFO structure returned by the DrvEnablePDEV function.

The input parameters for DrvTextOut define two sets of pixels, foreground and opaque. The driver renders the surface to provide the following results:

  1. The opaque pixels are rendered first, with the opaque brush.
  2. The foreground pixels are then rendered with the foreground brush.

Each of these rendering operations is performed in a clip region. The pixels outside the clip region cannot be affected.

The driver must render the surface so opaque pixels are calculated and drawn on the surface first with an opaque brush. Then foreground pixels are calculated and rendered with a foreground brush. Each of these operations is limited by clipping.

Foreground and opaque pixels make up a mask through which color is brushed onto the surface. The glyphs of a font do not, in themselves, have color. The foreground set of pixels is defined as the union of the glyphs' pixels and the pixels of certain extra rectangles used to simulate strikethrough or underline. Opaque pixels are defined by opaque rectangles.

DrvTextOut selects the specified font using a pointer, pfo, to query the current FONTOBJ structure. This process can include downloading a soft font or a font substitution, or any other font optimizations necessary for the device.

If a driver has scalable fonts, it should call the FONTOBJ_pxoGetXform function for the current FONTOBJ structure, to return the notional-to-device transform for the associated font. This is required for a driver-supplied font. Notional space is the design space of the device font. For example, PostScript fonts are defined in 1000-by-1000 unit character cells. Most of the metrics returned in the IFIMETRICS structure are converted to notional space, which is why the notional-to-device transform is necessary.

The graphics engine queries the driver by calling the function DrvGetGlyphMode to find out how it should internally cache its font information. It can cache individual glyphs as bitmaps, outlines, or neither (the proper choice for device fonts).


The DEVMODEW Structure

The DEVMODEW structure is the Unicode version of the DEVMODE structure, which is described in the Platform SDK documentation. (The 'W' suffix on DEVMODEW stands for "wide", or Unicode characters.) While applications can use either structure, drivers are required to use the DEVMODEW structure rather than the DEVMODE structure.

Public and Private Members

Immediately following a DEVMODEW structure's defined members (often referred to as its public DEVMODEW members), there can be a set of driver-defined members (its private DEVMODEW members). The following figure shows the public section (the actual DEVMODEW structure itself) and the private section Normally, the private members are used only by printer drivers. The driver supplies the size, in bytes, of this private area in the dmDriverExtra member. Driver-defined private members are for exclusive use by the driver.

The DEVMODEW Structure, Public and Private Sections

For printer drivers, the DEVMODEW structure is used to specify user choices for a print document. It is also used to specify default values of these choices for printers, such as the number of copies to print, paper size, and other attributes. For display devices, the DEVMODEW structure specifies display attributes such as the number of bits per pixel, pixel dimensions, and display frequency.

Initializing a DEVMODEW Structure

Depending on whether it is to be used by a display driver or by a printer driver, a DEVMODEW structure is initialized in two different ways.

  • Display driver DEVMODEW initialization

    A display driver's DrvGetModes entry point initializes all members of the DEVMODEW structure to zero. DrvGetModes then copies the name of the display driver DLL to the dmDeviceName member, fills in the dmSpecVersion and dmDriverVersion members with the version of the DEVMODEW structure, and copies display attribute information to the appropriate members.

  • Printer driver DEVMODEW initialization

    When an application makes a call to either DocumentProperties (a printer interface DLL function that is described in the Platform SDK documentation) or DrvDocumentPropertySheets (an NT-based operating system graphics DDI), a DEVMODEW structure is created with default values. An application is then free to modify any of the public DEVMODEW members. After any changes, the application should then make a second call to the same function it called before, in order to merge the changed members with those of the driver's internal DEVMODEW structure. The second call is necessary since some changes may not work correctly; the printer driver must be called to correct the DEVMODEW structure. When the document is about to be printed, the application passes the merged DEVMODEW structure to CreateDC (described in the Platform SDK documentation), which passes it on to the DrvEnablePDEV DDI. At that time, the driver's rendering DLL validates the DEVMODEW structure and makes repairs, if necessary, before carrying out the print job.

Using a DEVMODEW Structure

Several APIs and graphics DDIs use the information in the DEVMODEW structure for such purposes as printing, querying device capabilities, showing user interface, and others. For example, DrvConvertDevMode is a print spooler graphics DDI that translates the DEVMODEW structure from one operating system version to another. This might be necessary if a printer driver gets a DEVMODEW structure from another machine that is running on a different operating system version.

Modifying a DEVMODEW Structure

Applications and drivers are free to ask for a DEVMODEW structure and modify its public part directly. Only drivers, however, are permitted to modify the private DEVMODEW structure members.

In order to modify private DEVMODEW structure members, a driver must first determine the offset of the beginning of the private data. Given a pointer to the beginning of this structure, and the dmSize member, which holds the size of the public portion of the structure, the beginning of the private portion can be found. The following example shows how to initialize a pointer to the beginning of the private section. In this example, pdm points to the beginning of the DEVMODEW structure.

PVOID pvDriverData = (PVOID)  (((BYTE *) pdm) + (pdm -> dmSize));

Printer Driver/Display Driver DEVMODEW Differences

The DEVMODEW structure members fall into three categories:

  • Members used only by printer drivers
  • Members used only by display drivers
  • Members used by both printer and display drivers

The following table lists several public DEVMODEW members that are used only by printer drivers:

DEVMODEW Members Used Only by Printer Drivers | Purpose
dmScale | Specifies the percentage by which the image is to be scaled for printing.
dmCopies | Specifies the number of copies to be printed.
dmColor | Specifies whether a color printer should print color or monochrome.
dmOrientation | Specifies the orientation of the paper, either portrait or landscape.

The next table lists several public DEVMODEW members that are used only by display drivers:

DEVMODEW Members Used Only by Display Drivers | Purpose
dmFields | Specifies bit flags identifying which of the DEVMODEW members that follow it are in use. For example, the DM_BITSPERPEL flag is set when the dmBitsPerPel member contains valid data.
dmBitsPerPel | Specifies the color resolution, in bits per pixel, of the display device.
dmPelsWidth | Specifies the width, in pixels, of the visible device surface.
dmPelsHeight | Specifies the height, in pixels, of the visible device surface.
dmDisplayFlags | Specifies the display mode - color versus monochrome, interlaced versus noninterlaced.
dmDisplayFrequency | Specifies, in hertz, the display's refresh rate.

The third table lists several public DEVMODEW members that are used by both printer and display drivers:

DEVMODEW Members Used by Printer and Display Drivers | Purpose
dmDeviceName | For displays, specifies the display driver's DLL. For printers, specifies the "friendly name" of the printer.
dmSize | Specifies the size, in bytes, of the public portion of the DEVMODEW structure.
dmDriverExtra | Specifies the number of bytes of private driver data following the public structure members. For display drivers, this is usually zero.


Introduction to Display

Graphics adapters that run on NT-based operating systems require a paired display driver and video miniport driver. This section introduces these drivers and provides the following information that is relevant to both:

Display Architecture

Types of Graphics Adapters

General Design and Implementation Strategies

Accessing the Graphics Adapter

Creating Graphics INF Files

Compatibility Testing Requirements for Display and Video Miniport Drivers

The Microsoft® Windows® DDK provides sample display and video miniport drivers that support standard graphics cards.


Display Architecture

The following figure shows the components required to display on Windows 2000 and later.

Windows 2000 and Later Display Subsystem

The shaded elements in the preceding figure represent services that are supplied with Windows 2000 and later. The unshaded elements indicate that a third-party display driver and video miniport driver are required in order for a graphics adapter to display in the Windows 2000 and later systems.

For every type of graphics card that can be used with an NT-based operating system, there must be both a display driver and a corresponding video miniport driver. The miniport driver is written specifically for one graphics adapter (or family of adapters). The display driver can be written for any number of adapters that share a common drawing interface; for example, the VGA display driver can be used with either the VGA or ET4000 miniport driver. This is because the display driver draws, while the miniport driver performs operations such as mode sets and provides information about the hardware to the driver. It is also possible for more than one display driver to work with a particular miniport driver; for example, the 16- and 256-color SVGA display drivers can use the same miniport driver.

The following sections describe the key responsibilities of display and video miniport drivers. The breakdown in responsibilities is not hard and fast; the balance between modularity and performance is the key. For example, the hardware pointer code for the VGA driver resides in the miniport driver. This promotes modularity, so the same display driver can handle both the Video Seven VRAM, which has a hardware pointer, and the ET4000, which does not.


Display Driver Responsibilities

A display driver is a DLL whose primary responsibility is rendering. When an application calls a Win32 function with device-independent graphics requests, the Graphics Device Interface (GDI) interprets these instructions and calls the display driver. The display driver then translates these requests into commands for the video hardware to draw graphics on the screen.

The display driver can access the hardware directly. This is because there is a wide variety in graphics hardware capabilities, and because display is one of the most time-critical parts of any system. This accessibility and the wide scope of capabilities within GDI provide considerable flexibility when implementing a display driver.

  • By default, GDI handles drawing operations on standard format bitmaps, such as on hardware that includes a frame buffer. A display driver can hook and implement any of the drawing functions for which the hardware offers special support. For less time-critical operations and more complex operations not supported by the graphics adapter, the driver can punt functions back to GDI and allow GDI to do the work. See Hooking Versus Punting for details.
  • For especially time-critical operations, the display driver has direct access to video hardware registers. For example, the VGA display driver for x86 systems uses optimized assembly code to implement direct access to hardware registers for some drawing and text operations.

    Note The video miniport driver must manage all resources (for example, memory resources) shared between the video miniport driver and the display driver. The system does not guarantee that resources acquired in the display driver will always be accessible to the video miniport driver.

The display driver is discussed in detail in Display Drivers.


Video Miniport Responsibilities

The video miniport driver generally handles operations that must interact with other NT kernel components. For example, operations such as hardware initialization and memory mapping require action by the NT I/O subsystem. Video miniport driver responsibilities include resource management, such as hardware configuration, and physical device memory mapping. The video miniport driver must be specific to the video hardware.

The display driver uses the video miniport driver for operations that are not frequently requested; for example, to manage resources, perform physical device memory mapping, ensure that register outputs occur in close proximity, or respond to interrupts.

Note The video miniport driver must manage all resources (for example, memory resources) shared between the video miniport driver and the display driver. The system does not guarantee that resources acquired in the display driver will always be accessible to the video miniport driver.

The video miniport driver also handles:

  • Mode set interaction with the graphics card.
  • Multiple hardware types, minimizing hardware-type dependency in the display driver.
  • Mapping the video register into the display driver's address space. I/O ports are directly addressable.

The video miniport driver is discussed in detail in Video Miniport Drivers.


Types of Graphics Adapters

There are four general types of graphics adapters:

Frame buffers

Accelerators

Coprocessors

VGA


Frame Buffers

A frame buffer is the dedicated memory on a graphics adapter. Simple graphics adapters can have a frame buffer but no accelerator. If the hardware is linearly addressable and it can support standard format bitmaps (DIB format), GDI can handle the rendering operations and write directly to the frame buffer. This can reduce the size of the display driver because the driver can let GDI do all or most of the drawing. Most frame buffers are linearly addressable, or "flat".

Among the sample display drivers is a frame buffer driver in the directory named src\video\displays\framebuf. Because this driver supports linearly addressable frame buffer hardware, it allows GDI to do most of the work, and is therefore quite small and relatively simple.


Accelerators

An accelerator contains onboard circuitry that enhances the speed of graphics operations for specific rendering operations such as line drawing and filling, or bit-block transfers. The hardware may provide support for a pointer, which is usually much faster for the driver to use than the pointer support provided by GDI.

The 3Dlabs Permedia2 and Permedia3 sample drivers shipped with the Windows DDK are sophisticated and fairly complicated accelerators. The display and miniport drivers can be found in the src\video\displays\3dlabs\perm2 and src\video\displays\3dlabs\perm3 source example folders. The 3Dlabs Permedia2 and Permedia3 drivers are coded entirely in C so that they are portable across systems.


Coprocessors

A graphics adapter that includes a coprocessor offers another way to accelerate graphics display functions. A coprocessor is essentially an accelerator with additional programmable command logic. Because coprocessors are programmable, they support multiprocessing, which enables the coprocessor to handle some time-consuming operations while other operations are occurring elsewhere.


VGA

The standard graphics card for x86-based computers is VGA. This hardware can operate in both text and graphics modes. A number of accelerators are built on top of VGA-compatible hardware.


General Design and Implementation Strategies

To design an effective Windows® 2000 and later display driver and video miniport driver, consider the following strategies:

  • Modify an existing DDK sample driver that was designed for a similar type of graphics adapter to reduce driver design time.
  • Use C to write as much of the driver as possible to maximize portability, using assembly language only when necessary for time-critical operations that are not well supported by the hardware. Although coding in assembly increases the potential for optimization, time and portability issues outweigh its benefits.
  • Use video miniport drivers for operations that manage resources, perform physical device memory mapping, ensure that register outputs occur in close proximity, or respond to interrupts. Miniport drivers are predominately used for handling variations within a hardware family and for minimizing display driver hardware-type dependencies.

For additional information of interest to display driver writers, see Graphics DDI Functions for Display Drivers. This topic and the subtopics following it discuss the graphics DDI functions that are required, conditionally required, and optional for a display driver. Video Miniport Driver Interface and its subtopics contain similar information aimed at video miniport driver writers.

You should also consider the following facts:

  • The display driver and video miniport driver operate in the same privileged kernel-mode address space as the rest of the NT Executive. A fault in either driver will cause the rest of the system to fault.
  • Display drivers and video miniport drivers can be preempted at any time.
  • The code and data sections of a display driver are both entirely pageable.
  • Exported functions must execute the standard NT-based operating system prolog on entry and the epilog on exit. For more information, see the Platform SDK documentation.

For information that is specific to display drivers, see Graphics DDI Functions for Display Drivers. That section contains information about required, conditionally required, and optionally required graphics DDI functions.


Accessing the Graphics Adapter

To ensure display performance, display drivers can access the graphics card in the following ways:

  • Indirectly—by sending IOCTLs to the video miniport driver of the graphics adapter. See Communicating IOCTLs to the Video Miniport Driver.
  • Directly—by reading and writing to video memory (the frame buffer) or hardware registers. See Accessing the Frame Buffer and Hardware Registers.


Communicating IOCTLs to the Video Miniport Driver

The following figure shows how the display driver communicates with the video miniport driver using IOCTLs.

Display Driver/Video Miniport Driver Communication

The display driver calls EngDeviceIoControl with an IOCTL to send a synchronous request to the video miniport driver. GDI uses a single buffer for both input and output to pass the request to the I/O subsystem. The I/O subsystem routes the request to the video port, which processes the request with the video miniport driver.

Some IOCTL requests require the miniport driver to access video registers, and others store or retrieve information from the miniport driver's data structures. Generally, no requests require the video miniport driver to perform actual drawing operations.

In general, and unless modularity dictates otherwise, the display driver handles drawing and other time-critical operations. Sending an IOCTL to the miniport driver to perform a time-critical function can degrade system performance.

See Video I/O Control Codes for descriptions of system-defined video IOCTLs. You can extend the interface between the display driver and the video miniport driver by adding a private IOCTL, which must be formatted as described in the Kernel-Mode Drivers Reference. If you need to write a new IOCTL, you should first contact Microsoft Technical Support.


Accessing the Frame Buffer and Hardware Registers

There are several ways to reduce display driver size. For example, you can implement only those functions that the display driver can perform faster than GDI, and then specify GDI to perform all other operations. GDI often performs a substantial amount of the drawing to linear frame buffers to reduce the size of the driver. GDI cannot access banked memory directly; therefore, when the frame buffer is not linearly addressable, the display driver must divide the frame buffer into a series of banks and provide a means for GDI to perform its draw operations to the appropriate bank. See Supporting Banked Frame Buffers for details.

The display driver has direct access to I/O-mapped and memory-mapped video registers. This access allows a display driver to achieve high performance. For example, the driver might need to access video hardware registers to send line-drawing commands at high throughput.

Similarly, for graphics cards, such as the S3, many of the innermost loops in the graphics engine code require reads and writes of several video controller ports (for example, text output in graphics mode, bit block transfers, and line drawing). Rather than requiring the display driver to send an IOCTL to the miniport driver for each request, the display driver is permitted to access the video hardware directly.


Fast User Switching

Fast User Switching, a feature of Windows XP and later, enables multiple users to be logged onto the same machine. A particular user's desktop and any running applications persist from that user's logon session to his or her next.

Fast User Switching works by allowing multiple virtual display drivers to run at the same time. (Each virtual display driver is associated with a particular PDEV.) The video miniport driver, however, exists as a single instance. When one of the virtual display drivers calls a video miniport driver callback, serious problems ensue if the miniport driver attempts to access a passed-in memory address in the context of the display driver when that display driver instance is no longer the active kernel thread. A tenet of the display driver/video miniport driver architecture is that information should flow in one direction only: from the display driver to the video miniport driver.


Creating Graphics INF Files

NT-based operating system display and video miniport drivers must be installed using an INF file. The Windows DDK provides a tool called geninf.exe that lets you generate an INF file for your display and video miniport drivers. When geninf.exe is run, it displays a number of dialogs that prompt you for information, such as the company name and the names of the display drivers and video miniport driver. Geninf.exe then generates an INF file from this information.

Note The file generated by geninf.exe might not be a fully valid INF file. Geninf.exe produces an INF file that will likely need custom registry settings added for each device described in the INF file.

If your miniport driver's calls to VideoPortGetAccessRanges or VideoPortVerifyAccessRanges consistently fail, you can manually edit the INF file to include the section and appropriate entries described in INF GeneralConfigData Section.

When you run geninf.exe, select "Display" when prompted to choose the device class. An INF file marked as Class=Display will be interpreted by the system-supplied display class installer during driver installation. This ensures that all registry entries associated with a video driver are properly initialized.

An INF file of the class Display can install only the following files on the system:

  • A single miniport driver
  • A single display driver
  • Control panel extension DLLs

No other types of driver or application files can be installed from an INF file of class Display.

Limitations of geninf.exe

You cannot use geninf.exe to generate:

  • An INF file that supports more than one architecture.
  • An INF file that supports Windows 95/98/Me or Windows NT version 4.0 or previous.
  • A mirror driver INF file. Use the INF file provided with the mirror sample driver as a template. See Mirror Driver INF File for more details.
  • A monitor INF file. Use the INF named monsamp.inf as a template. See Monitor INF File Sections for more details.

These sample INF files are both shipped with the Windows DDK.

See Creating an INF File and INF File Sections and Directives for detailed information when updating a sample INF file.


INF GeneralConfigData Section

If your miniport driver's calls to VideoPortGetAccessRanges or VideoPortVerifyAccessRanges consistently fail, you can edit the INF file generated by geninf.exe to modify the appropriate entries in the GeneralConfigData section.

[GeneralConfigData]

[MaximumDeviceMemoryConfiguration = n]
[MaximumNumberOfDevices = n]

The following are GeneralConfigData entries and values:

MaximumDeviceMemoryConfiguration=n
Specifies the maximum number of megabytes of physical address space that the miniport driver's device will attempt to map. For this entry to take effect, a reboot may be needed. You can determine whether a reboot is necessary by checking the status of your device in DeviceManager.
MaximumNumberOfDevices=n
Specifies the maximum number of adapters a miniport driver can support at one time. Specify this entry if you have also specified the MaximumDeviceMemoryConfiguration key and if the miniport driver can be for the secondary adapter in a multiple monitor system. For this entry to take effect, a reboot may be needed. You can determine whether a reboot is necessary by checking the status of your device in DeviceManager.

This entry is also be used for miniport drivers that support DualView. See Supporting DualView for more information.


Display INF File Sections

The following information applies only to graphics adapter installation. For more general information about INF files, see INF File Sections and Directives.

DDInstall.SoftwareSettings Section

A [DDInstall.SoftwareSettings] section contains AddReg and/or DelReg directives. Each of these directives points to a separate INF writer-defined section containing registry entries to be added or deleted.

In the following example, the AddReg directive points to an INF writer-defined add-registry section named ACME-1234_SoftwareDeviceSettings. The DelReg directive points to another INF writer-defined delete-registry section named ACME-1234_DeleteSWSettings.

[ACME-1234.SoftwareSettings]
AddReg=ACME-1234_SoftwareDeviceSettings
DelReg=ACME-1234_DeleteSWSettings

In the add-registry section, the value name InstalledDisplayDrivers is added to the registry and is set to the name of the display driver. The OverRideMonitorPower value name is added and is set to 0 (FALSE). This key should be used only by OEM system vendors to control the monitor device (LCD, CRT, TV, etc.) power behavior. When set to 1, it limits the possible power states of the monitor device to just D0 and D3. The MultiFunctionSupported value name must be set to 1 (TRUE) for an adapter that supports multiple PCI functions. The VideoDebugLevel value name controls the global debug level that is used in debug messages in checked builds. This value ranges from 0 (no debug messages) to 3 (most verbose messages). See VideoDebugPrint for more information.

The last value name added is CapabilityOverride, which is driver-specific and has no special meaning to the system. It is included as an example of how a driver-specific value name can be added to the registry. Unlike CapabilityOverride, the OverrideMonitorPower, MultiFunctionSupported, and VideoDebugLevel value names are used by video port system module, videoprt.sys.

[ACME-1234_SoftwareDeviceSettings]
HKR,, InstalledDisplayDrivers, %REG_MULTI_SZ%, Acme1
HKR,, OverRideMonitorPower, %REG_DWORD%, 0
HKR,, MultiFunctionSupported, %REG_DWORD%, 1
HKR,, VideoDebugLevel, %REG_DWORD%, 2
HKR,, CapabilityOverride, %REG_DWORD%, 0

The delete-registry section shows two keys being deleted from the registry: GraphicsClocking and MemClocking.

[ACME-1234_DeleteSWSettings]
HKR,, "GraphicsClocking"
HKR,, "MemClocking"

Disabling AGP Transfer Rates and Sideband Addressing

If necessary, you can modify the INF file for your display adapter to disable certain AGP transfer rates or sideband addressing. Note that a minidriver can change AGP transfer rates when it calls AgpSetRate, but such calls are not allowed to change to transfer rates that are disabled in an INF file.

The header regstr.h, which ships with the DDK, defines a set of flags.

Flag | Value | Meaning
AGP_FLAG_NO_1X_RATE | 0x00000001L | Disable single speed (66 MHz) transfer rate.
AGP_FLAG_NO_2X_RATE | 0x00000002L | Disable two times single speed transfer rate.
AGP_FLAG_NO_4X_RATE | 0x00000004L | Disable four times single speed transfer rate.
AGP_FLAG_NO_8X_RATE | 0x00000008L | Disable eight times single speed transfer rate.
AGP_FLAG_NO_SBA_ENABLE | 0x00000100L | Disable sideband addressing (SBA).

There are two types of settings: global, and platform-specific. The global entries are in the registry at the following location: HKLM,"SYSTEM\CurrentControlSet\Control\AGP".

The platform-specific entries can be found under Parameters in the filter driver service key. For example, for the (hypothetical) AcmeAGP adapter, the platform-specific entries would be found in this location in the registry: HKLM,"SYSTEM\CurrentControlSet\Services\AcmeAGP\Parameters".

To disable sideband addressing for a device with a DeviceID of 0x012A (Nuclear3D) and a VendorID of 0x1AD0 on VIA platforms, add a Nuclear3D_Install.HW section (see INF_DDInstall.HW Section) to your INF file. In this section, add an AddReg directive as in the following:

[Nuclear3D_Install.HW]
AddReg = Nuclear3D_Reg

Next, create the following Nuclear3D_Reg section pointed to by the AddReg directive:

[Nuclear3D_Reg]
HKLM,"SYSTEM\CurrentControlSet\Services\viaagp\Parameters","1AD0012A",0x00030003,00,01,00,00,00,00,00,00

This entry indicates that the subkey identified in the string following HKLM is to be added to the registry, under the HKEY_LOCAL_MACHINE root. The string "1AD0012A" is the value-entry name, of which the first four characters are the DeviceID, and the last four are the VendorID for this part. The hexadecimal number following the value-entry name is a set of flags, indicating the data type for the value entry (see INF AddReg Directive for details). The last part is the value entry itself, which effectively disables sideband addressing (see AGP_FLAG_NO_SBA_ENABLE in the preceding table).

Note The bytes in the value entry are in the opposite order from those of the AGP_FLAG_NO_SBA_ENABLE flag's definition in the preceding table.

Now suppose you decide that AGP 4X is broken on every chipset for this same device. To indicate this, add a second entry to the Nuclear3D_Reg section:

[Nuclear3D_Reg]
HKLM,"SYSTEM\CurrentControlSet\Services\viaagp\Parameters","1AD0012A",0x00030003,00,01,00,00,00,00,00,00
HKLM,"SYSTEM\CurrentControlSet\Control\AGP","1AD0012A",0x00030003,04,00,00,00,00,00,00,00

The second entry indicates that the subkey identified in the string following HKLM is to be added to the registry under the HKEY_LOCAL_MACHINE root. The value name associated with this subkey is the same as in the previous entry, a string made up of the device's DeviceID and VendorID. The flag value is also the same. The value entry is AGP_FLAG_NO_4X_RATE, which disables the AGP 4X transfer rate. Notice that, as before, the bytes in this value entry are in the opposite order as those in this flag's value in the preceding table.


Monitor INF File Sections

Monitors must be installed in NT-based operating systems using an INF file. The Windows DDK provides a sample monitor INF file, monsamp.inf, that you should use as a template to generate an INF file for your monitor. You cannot use the geninf.exe tool described in Creating Graphics INF Files to generate a monitor INF.

The rest of this topic comments on some of the sections in monsamp.inf that are of specific interest to monitor INF writers. For more general information about INF files, see INF File Sections and Directives.

SourceDisksFiles Section

Files that must be copied during monitor installation should be placed in the [SourceDisksFiles] section. The following example identifies an .icm file that is on distribution disk 1.

[SourceDisksFiles]
profile1.icm=1

For more general information, see INF SourceDisksFiles Section. See Monitor Profiles for more information about color management and profiles.

Models Section

Information about each model that is supported by a given manufacturer should be placed in the Models section. The following example identifies two models manufactured by ACME:

[ACME]
%ACME-1234%=ACME-1234.Install, Monitor\MON12AB
%ACME-5678%=ACME-5678.Install, Monitor\MON34CD

Each model is represented by a single line. Each line contains three elements:

  • Model name — for example, %ACME-1234% is a token that represents the actual model name (which would appear in the Strings section).
  • Link to a subsequent DDInstall section — for example, ACME-1234.Install is a link to the subsequent [ACME-1234.Install] section.
  • Hardware identification — for example, the expression Monitor\MON12AB combines the device class (Monitor) and the device identification (MON12AB) as it appears in the device's EDID.

For more general information, see INF Models Section.

DDInstall Section

The DDInstall section provides information to the driver about the operations to be performed when it installs the specified device. Each line in this section provides a link or links to different INF writer-defined sections that appear later in the INF file. The following example shows the DDInstall section for the ACME-1234 model:

[ACME-1234.Install]
DelReg=DEL_CURRENT_REG
AddReg=ACME-1234.AddReg, 1280, DPMS
CopyFiles=ACME-1234.CopyFiles
  • DelReg directive—provides a link to the DEL_CURRENT_REG section, which details the registry keys to be deleted.
  • AddReg directive—provides links to three sections in which registry keys to be added are detailed. These sections are ACME-1234.AddReg, 1280, and DPMS.
  • CopyFiles directive—provides a link to the ACME-1234.CopyFiles section, which specifies the files to be copied from the distribution disk or disks.

For more general information, see INF DDInstall Section.

INF Writer-Defined Sections

An INF writer-defined section can have any name, provided it is unique within the INF file. These sections are pointed to by directives in other sections. The following bullet items discuss some of the INF writer-defined sections from monsamp.inf:

  • DEL_CURRENT_REG section — identifies four registry keys whose values will be deleted: MODES, MaxResolution, DPMS, and ICMProfile. These keys will be updated appropriately with new values in subsequent sections.
    [DEL_CURRENT_REG]
HKR,MODES
HKR,,MaxResolution
HKR,,DPMS
HKR,,ICMProfile
  • 1280 section — updates the MaxResolution registry key to the string value shown.
    [1280]
HKR,,MaxResolution,,"1280, 1024"
  • DPMS section — updates the DPMS registry key to 1 (TRUE). For a monitor that does not support power management, the following line should instead set the DPMS key value to 0 (FALSE).
    [DPMS]
HKR,,DPMS,,1
  • AddReg section — the first line of the following sets the "MODES\1280,1024" subkey to the string value shown. The same line also identifies a value name for this subkey, Mode1. Note that this value establishes new Mode1 timing values which override those listed in the EDID. The first pair of numbers in the string following the Mode1 subkey specifies the range of horizontal synchronization frequencies, in KHz. The next pair of numbers in this string specifies the range of vertical synchronization frequencies, in Hz. In the second line, the PreferredMode registry key is set to the values shown in the accompanying string. The values in the string are used to set both the horizontal and the vertical resolution, in pixels, and the screen refresh rate, in hertz (Hz), for the preferred screen mode. The third line sets the ICMProfile key to the string value "profile1.icm".
    [ACME-1234.AddReg]
HKR,"MODES\1280,1024",Mode1,,"27.0-106.0,55.0-160.0,+,+"
HKR,,PreferredMode,,"1024,768,70"
HKR,,ICMProfile,0,"profile1.icm"

    For a monitor that meets the sRGB specification, which is preferred, no monitor profile is needed.


Compatibility Testing Requirements for Display and Video Miniport Drivers

This section lists some of the requirements for NT-based operating system graphics drivers and associated components to meet the Windows Hardware Quality Lab (WHQL) test criteria. The drivers that meet or exceed these tests are authorized to display the Microsoft® Windows® Logo. For more information, go to http://www.microsoft.com/hwdev.

INF and Installation Requirements

Video Miniport Driver and Display Driver Requirements

Control Panel Requirements


INF and Installation Requirements

NT-based operating system display and video miniport drivers must be installed using an INF file. To ensure that all registry entries associated with a video driver are properly initialized, this INF must be interpreted by the system-supplied display class installer and marked as Class=Display.

The Windows DDK provides a tool named geninf.exe that lets you easily generate an INF file for your display and video miniport driver. See Creating Graphics INF Files for details.


Video Miniport Driver and Display Driver Requirements

This section provides links to other sections that contain information about requirements for video miniport drivers and for display drivers.

Video Miniport Driver Requirements

Display Driver Requirements


Control Panel Requirements

The following are requirements for extensions to the display Control Panel:

  • Existing property pages must remain unchanged. Any Microsoft-provided property page (including Settings) must not be disabled, modified, removed, or replaced.
  • Custom property pages can be added only under Advanced Properties. The features exposed at the top level are commonly accessed features that are included in every Windows system. Because Windows 2000 and later operating system versions support multiple displays, custom property pages cannot be added to the top-level property page set in the Display Control Panel.
  • Control Panel extensions must be able to operate with existing Windows Control Panel elements.
  • Custom property pages must be labeled with an icon in addition to the text name. In order to prevent conflicts with future operating system or shell releases, third-party tabs must contain, in addition to the page label, either an icon (with the company's logo) or text with the name of the vendor. For example, "Acme Video Controls" is acceptable; "Video Controls" is not.
  • Control panel extensions must not initialize if the necessary hardware/driver combination is not present. If the display hardware that ships with the custom Control Panel extensions is not present, the extensions should not load. Likewise, if a custom property page has features that are dependent on proprietary driver extensions (for example, extensions that are not guaranteed to be present in every other display driver), those features must disable themselves, or the property page must not load when the necessary driver is not installed.
  • The Control Panel extension must respect the Hide modes that this monitor cannot display checkbox in the Monitor tab. If the checkbox option is checked, then the Control Panel extension must not display any modes that are not enumerated by EnumDisplaySettings (described in the Platform SDK documentation).
  • Control panel state must be stored in the registry. No .ini files are allowed. Any state that is maintained by your Control Panel extension must be stored in the SOFTWARE key in the registry, accessible through HKR in the INF file.


Display Drivers

Microsoft® NT-based operating system display driver writers are concerned with two core software interfaces:

  • Graphics DDI interface — The set of functions that the display driver implements. GDI can call the graphics DDI interface to process graphics commands.
  • GDI interface — System-supplied helper routines called by display drivers to simplify driver implementation.

This section describes key concepts associated with NT-based operating system display drivers as well as some implementation information. See GDI Support for Graphics Drivers and Using the Graphics DDI for graphics driver design details that are common to both printer drivers and display drivers, such as driver initialization and termination, and graphics output.

Display driver writers can also implement the following DDIs:

  • DirectDraw DDI — Graphics interface that allows vendors to provide hardware accelerations for DirectDraw. See DirectDraw DDI for details.
  • Direct3D DDI — 3D graphics interface that allows vendors to provide hardware accelerations for Direct3D. See Direct3D DDI for details.

For complete descriptions of the graphics DDI entry points and structures, as well as GDI service functions and objects, see Graphics Driver Functions (DDI).


Graphics DDI Functions for Display Drivers

A Microsoft® NT-based operating system display driver must implement several graphics DDI functions. Although writing a driver that capitalizes on existing GDI capabilities would be smaller and simpler to write, you should make sure that your driver also implements those operations it can perform more efficiently than GDI.

The display driver graphics DDI functions fall into three groups, each of which is discussed in following topics:

  1. Graphics DDI functions required by every display driver.
  2. Graphics DDI functions required under certain conditions.
  3. Graphics DDI functions that are optional.


Required Display Driver Functions

At a minimum, every display driver must:

  1. Enable and disable the graphics hardware.
  2. Supply GDI with information about hardware capabilities.
  3. Enable the drawing surface.

The following table lists the functions that all display drivers must implement. Following DrvEnableDriver, the remaining functions are listed alphabetically.

Function | Description
DrvEnableDriver | As the initial driver entry point, provides GDI with the driver version number and entry points of optional functions supported.
DrvAssertMode | Resets the video mode for a specified video hardware device.
DrvCompletePDEV | Informs the driver about the completion of device installation.
DrvDisableDriver | Frees all allocated resources for the driver and returns the device to its initially loaded state.
DrvDisablePDEV | When the hardware is no longer needed, frees memory and resources used by the device and any surface created, but not yet deleted.
DrvDisableSurface | Informs the driver that the surface created for the current device is no longer needed.
DrvEnablePDEV | Enables a PDEV.
DrvEnableSurface | Creates a surface for a specified hardware device.
DrvGetModes | Lists the modes supported by a specified video hardware device.

A list of required functions for all graphics drivers appears in Required Graphics Driver Functions.


Conditionally Required Display Driver Functions

Depending on how a driver is implemented and on the features of the underlying adapter, other graphics DDI functions may be required. For example, if a driver manages its own surface (using EngCreateDeviceSurface to get a handle to the surface), that driver must also, at a minimum, support the following drawing functions:

Function | Description
DrvCopyBits | Translates between device-managed raster surfaces and GDI standard-format bitmaps.
DrvStrokePath | Draws a path (curve or line) when called by GDI.
DrvTextOut | Renders a set of glyphs at specified positions.

Note Driver calls are serialized for any given surface.

Drivers that write to standard-format DIBs usually allow GDI to manage most or all of these operations. Displays that support settable palettes must support the DrvSetPalette function.

Function | Description
DrvSetPalette | Requests that the driver realize the palette for a specified device. The driver sets the hardware palette to match the entries in the given palette as closely as possible.

A list of conditionally required functions for all graphics drivers appears in Conditionally Required Graphics Driver Functions.


Optional Display Driver Functions

In order to reduce driver size, display driver writers usually add only those optional functions that are well supported in video hardware. The display driver can implement the functions listed in the following tables. These functions are sorted into the following categories:

Bitmap Management Functions

Drawing Functions

Image Color Management Functions

Pointer and Window Management Functions

Miscellaneous Functions

Bitmap Management Functions

Function | Description
DrvCreateDeviceBitmap | Creates and manages a bitmap with a driver-defined format.
DrvDeleteDeviceBitmap | Deletes a device-managed bitmap.

Drawing Functions

Function | Description
DrvAlphaBlend | Provides bit-block transfer capabilities with alpha blending.
DrvBitBlt | Provides general bit-block transfer capabilities between device-managed surfaces, between GDI-managed standard-format bitmaps, or between a device-managed surface and a GDI-managed standard-format bitmap.
DrvDitherColor | Requests a device to create a brush dithered against a device palette.
DrvFillPath | Paints a closed path for a device-managed surface.
DrvGradientFill | Shades the specified primitives.
DrvLineTo | Draws a single, solid, integer-only cosmetic line.
DrvPlgBlt | Provides rotate bit-block transfer capabilities between combinations of device-managed and GDI-managed surfaces.
DrvRealizeBrush | Realizes a specified brush for a defined surface.
DrvStretchBlt | Allows stretching block transfers among device-managed and GDI-managed surfaces.
DrvStretchBltROP | Performs a stretching bit-block transfer using a ROP.
DrvStrokeAndFillPath | Simultaneously strokes and fills a path.
DrvTransparentBlt | Provides bit-block transfer capabilities with transparency.

Image Color Management Functions

Function | Description
DrvIcmCheckBitmapBits | Checks whether the pixels in the specified bitmap lie within the device gamut of the specified transform.
DrvIcmCreateColorTransform | Creates an ICM color transform.
DrvIcmDeleteColorTransform | Deletes the specified ICM color transform.
DrvIcmSetDeviceGammaRamp | Sets the hardware gamma ramp of the specified display device.

Pointer and Window Management Functions

Function | Description
DrvDescribePixelFormat | Describes the pixel format for a device-specified PDEV by writing a pixel format description to a PIXELFORMATDESCRIPTOR structure.
DrvMovePointer | Moves a pointer to a new position and redraws it.
DrvSaveScreenBits | Saves or restores a specified rectangle of the screen.
DrvSetPixelFormat | Sets the pixel format of a window.
DrvSetPointerShape | Removes the pointer from the screen if the driver has drawn it, and then sets a new pointer shape.

Miscellaneous Functions

Function | Description
DrvDestroyFont | Notifies driver that a font realization is no longer needed; driver can free allocated data structures.
DrvDrawEscape | Implements draw-type escape functions.
DrvEscape | Queries information from a device not available in a device-independent graphics DDI.
DrvFree | Frees storage associated with an indicated data structure.
DrvNotify | Allows a display driver to be notified about certain information by GDI.
DrvSynchronize | Coordinates drawing operations between GDI and a display driver-supported coprocessor device; for engine-managed surfaces only.
DrvSynchronizeSurface | Allows drawing operations performed by a device's coprocessor to be coordinated with GDI.

Display drivers can also optionally implement the Microsoft® DirectDraw® and/or Direct3D® interfaces. See the following sections for details:

DirectDraw DDI

Direct3D DDI

A list of optional functions for all graphics drivers appears in Optional Graphics Driver Functions.


Display Driver Requirements

An NT-based operating system display driver must meet the requirements specified in the PC 99 Design Guide. If the driver is to be submitted for Windows Hardware Quality Lab (WHQL) testing, it must meet WHQL requirements as well.


Display Driver Initialization

Display driver initialization is similar to graphics driver initialization, as described in Supporting Initialization and Termination Functions. This section provides initialization details that are specific to display drivers.

Video miniport and display driver initialization occur after the NT executive and the Win32 subsystem are loaded and initialized. The system loads the video miniport driver or drivers that are enabled in the registry, and then determines which video miniport driver and display driver pair to use. During this process, GDI opens all necessary display drivers, based on the information provided by Window Manager.

The basic display driver initialization procedure, in which the desktop is created, is shown in the following figure.

Display Driver Initialization

  1. When GDI is called to create the first device context (DC) for the video hardware, GDI calls the display driver function DrvEnableDriver. Upon return, DrvEnableDriver provides GDI with a DRVENABLEDATA structure that holds both the driver's graphics DDI version number and the entry points of all callable graphics DDI functions that are implemented by the driver (other than DrvEnableDriver).
  2. GDI then calls the driver's DrvEnablePDEV function to request a description of the driver's physical device's characteristics. In the call, GDI passes in a DEVMODEW structure, which identifies the mode that GDI wants to set. If GDI requests a mode that the display or underlying miniport driver does not support, then the display driver must fail this call.
  3. The display driver represents a logical device controlled by GDI. As shown in the following figure, a single logical device can manage several physical devices, each characterized by type of hardware, logical address, and surfaces supported. The display driver allocates the memory to support the device it creates. A display driver may be called upon to manage more than one PDEV for the same physical device, although only one PDEV can be enabled at a time for a given physical device. Each PDEV is created in a separate GDI call to DrvEnablePDEV, and each call creates another PDEV that is used with a different surface.

    Because a driver must support more than one PDEV, it should not use global variables.

Logical versus Physical Devices

  4. When installation of the physical device is complete, GDI calls DrvCompletePDEV. This function provides the driver with a GDI-generated physical device handle to use when requesting GDI functions for the device.
  5. In the final stage of initialization, a surface is created for the video hardware by a GDI call to DrvEnableSurface, which enables graphics output to the hardware. Depending on the device and the environment, the display driver enables a surface in one of two ways:

    • The driver manages its own surface by calling the GDI function EngCreateDeviceSurface to obtain a handle for the surface. The device-managed surface method is required for hardware that does not support a standard-format bitmap and is optional for hardware that does.

    • GDI can manage the surface completely as an engine-managed surface if the hardware device has a surface organized as a standard-format bitmap. A driver can call EngModifySurface to convert the device-managed primary bitmap to one that is engine-managed. The driver can still hook any drawing operations.

Any existing GDI bitmap handle is a valid surface handle. A driver can call EngModifySurface to convert the device-managed primary bitmap to an engine-managed bitmap. If the surface is engine-managed, GDI can handle any or all drawing operations. If the surface is device-managed, at a minimum, the driver must handle DrvTextOut, DrvStrokePath, and DrvBitBlt.

GDI automatically enables DirectDraw after calling DrvEnableSurface. After DirectDraw is initialized, the driver can use DirectDraw's heap manager to perform off-screen memory management. See DirectDraw and GDI for details.

A display driver must implement DrvNotify in order to receive notification events, particularly the DN_DRAWING_BEGIN event. GDI sends this event immediately before it begins drawing, so it can be used to determine when caches can be initialized.

See the Plug and Play section for more information about the boot process.


Desktop Management

A display driver must implement DrvAssertMode and DrvGetModes to manage desktops.

If the display driver is palette-managed, it will also receive a call to DrvSetPalette to reset its palette to the correct state.

GDI's mechanism for handling dynamic mode changes has changed significantly in Windows 2000 and later operating system versions. The GDI HDEV assigned to a driver during initialization may differ from the HDEV assigned after the mode change is complete. Display drivers will generally be unaffected by this change for the following reasons:

  • Drivers have always assigned ppdev->hdevEng = hdev in their DrvCompletePDEV implementations.
  • Drivers have always referenced ppdev->hdevEng in any callbacks that require an HDEV.


Switching Desktops: Responding to DrvAssertMode

When switching between desktops on a display, the Window Manager ensures that the desktops are properly redrawn and that a mouse pointer is enabled and displayed in the correct position. The display driver receives a call to DrvAssertMode only when there is a desktop switch.

When this function is called, the driver ensures that the indicated PDEV is either in the mode specified when the PDEV was created, or in text mode. The Window Manager then selects the correct pointer shape and moves it to the current position. GDI, not the driver, is responsible for maintaining the mouse pointer state.

GDI calls DrvAssertMode to set the mode of a specified hardware device. This function selects either the mode specified when the display driver-defined PDEV structure was created or the default mode of the hardware. The driver should keep a record of the current mode of the PDEV.

GDI also calls DrvAssertMode, with the enable parameter set to FALSE, when the user switches from a windowed application to a full-screen application in x86 applications, or when the user switches desktops (on all platforms). The display driver must restore the video hardware to a default mode by sending IOCTL_VIDEO_RESET_DEVICE in an EngDeviceIoControl call to the video miniport driver.


Returning Display Modes: DrvGetModes

The display driver must also support DrvGetModes. This function gives GDI a pointer to an array of DEVMODEW structures. The structures define the attributes of the display for the various modes that it supports, including the dimension (in both pixels and millimeters), number of planes, bits per plane, color information, and so on.


Supporting Multiple PDEVs

This section shows how an application can create a new PDEV while the current PDEV is still loaded. The Control Panel's Display applet requires that a display driver support the enabling of additional PDEVs, because it is possible for an application to create a new PDEV with a new desktop. Specifically, from the Display applet, the end user can run a test on changes to such elements as the size, number of colors, and refresh rate of the screen. The Display applet creates a new desktop dynamically to test the display's mode changes.

GDI performs the following steps when the user requests a mode change through the Display applet. These steps assume that no active Direct3D, WNDOBJ, or DRIVEROBJ objects are owned by the current driver instance.

  1. Temporarily disable the current PDEV
    • Call DrvAssertMode (old PDEV instance). Call is made using FALSE if miniport driver is to assume control, and with TRUE if PDEV should be used.
  2. Load new driver (if required by new PDEV instance)
    • Call DrvEnableDriver (new driver instance).
  3. Create new PDEV
    • Call DrvEnablePDEV (new PDEV instance).
    • Call DrvCompletePDEV (new PDEV instance).
    • Call DrvEnableSurface (new PDEV instance).
  4. Get DirectDraw information (if DirectDraw is hooked by driver). Second call to DrvGetDirectDrawInfo is made only if the first call succeeds.
    • Call DrvGetDirectDrawInfo (new PDEV instance).
    • Call DrvGetDirectDrawInfo (new PDEV instance).
  5. Enable DirectDraw (if hooked by driver and previous call to DrvGetDirectDrawInfo succeeded).
    • Call DrvEnableDirectDraw (new PDEV instance).
  6. Copy old PDEV state to new PDEV instance (if both instances use same driver, and DirectDraw is hooked by driver).
    • Call DrvResetPDEV.
  7. Notify each driver instance of its new HDEV association. The first call to DrvCompletePDEV notifies the new driver instance; the second call notifies the old driver instance.
    • Call DrvCompletePDEV (new PDEV instance).
    • Call DrvCompletePDEV (old PDEV instance).

    The driver should use the new HDEV value in any callbacks to GDI that require an HDEV.

  8. Disable DirectDraw (if hooked by the driver and DirectDraw is active).
    • Call DrvDisableDirectDraw (old PDEV instance).
  9. Disable surface.
    • Call DrvDisableSurface (old PDEV instance).
  10. Disable PDEV.
    • Call DrvDisablePDEV (old PDEV instance).

In this example, GDI temporarily disables the current PDEV when the user clicks Apply, and then creates a second PDEV that matches the display mode selections in the dialog box. After the user views a bitmap on the display screen under the test mode, the second PDEV is destroyed and the Display applet restores the original PDEV for the desktop. Note that without the ability to revert back to the original display settings, the system would become unusable if the settings were incompatible with the hardware and driver.

If the current instance of the driver owns a Direct3D, WNDOBJ, or DRIVEROBJ object, the driver's view of the previous mode change sequence changes as follows (note that in Windows 2000 and later, DirectDraw is always enabled as soon as the driver is initialized):

  • Destruction of the owning driver instance will be deferred. Specifically, the second call to DrvCompletePDEV in step 7, step 8, and step 9 will not occur at the time of the mode change. As a result, the old driver instance is disabled due to the call to DrvAssertMode(FALSE) in step 1, and is retained until either the system does a mode change back to the original mode, or until all the objects that reference the instance are destroyed.
  • If the system reverts back to the original mode before the referencing objects are destroyed, the original driver instance will be resurrected. That is, steps 2 through 5 do not occur, and the original driver instance is re-enabled by a call to DrvAssertMode(TRUE) (see step 1).
  • If the system does not revert back to the original mode before all the referencing objects are destroyed, then the driver instance will be destroyed when the final referencing object is destroyed. That is, the second call to DrvCompletePDEV in step 7, step 8, and step 9 will occur at the time the final referencing object is destroyed (for example, when all the owning processes are terminated).

An implication of this is that Direct3D or OpenGL drivers can be called to destroy an inactive driver instance at any time. These drivers can be called even if another instance of the driver is currently active, or if the driver is in full-screen DOS mode, or if another driver owns the hardware entirely (such as the VGA driver). Consequently, the DrvDisableDirectDraw, DrvDisableSurface, and DrvDisablePDEV routines (see steps 8-10) of a driver cannot assume that the device is in graphics mode and that they own exclusive access. As a general rule, drivers should not manipulate their video hardware in their DrvDisable Xxx routines unless they know that their instance is currently active (by remembering the state from the last DrvAssertMode call).

Note A PDEV is private to a driver and contains all the information and data that represents the associated physical device. To create multiple PDEVs, the graphics driver must meet both of the following requirements:

  1. The driver must not use global variables instead of dereferencing members of a PDEV structure. If global variables are used, they might contain or point to random data when a new PDEV is created, or an old one restored. All state information must be saved in the PDEV. The PDEV is always passed to any graphics operation and is therefore used to get or set global data.
  2. The DrvDisableSurface, DrvDisablePDEV, and DrvDisableDriver routines must be implemented in the graphics driver so that an application can create and destroy additional PDEVs, and in some cases load more than one driver.

Note If the driver's version number is 1.0, GDI will not call the driver to create a second PDEV. The version number of the driver is returned in DRVENABLEDATA.

Note Occasionally, the Display applet's test bitmap will be displayed using a different driver than the currently-loaded driver. For example, if a system is running in 16-color mode with the VGA driver and testing a 64K-color mode with the VGA64K display driver, the VGA64K driver will be loaded dynamically and unloaded when the test is complete.


Pointer Control

Every application must be able to control a pointer that moves around a windowed display in response to a pointing device, such as a mouse. The display driver, GDI, or the video miniport driver can draw the pointer. Refer also to Controlling the Pointer and Moving the Pointer.

GDI can directly handle all pointer drawing for a display that uses a linearly addressable buffer. For a device that is not a linear frame buffer, GDI uses DrvCopyBits for pointer drawing. However, pointer code supported by hardware and implemented in the display driver is much faster.

Display drivers can sometimes choose which kinds of pointers they will draw and which kind they will allow GDI to handle. For example, a device might support monochrome pointers in hardware but fail the color pointer calls, allowing GDI to handle them instead.

The display driver can control the pointer in situations for which the processor does not have to be owned exclusively and the pointer does not have to be drawn off an interrupt, such as the vertical synchronization interrupt. In these special cases, the miniport driver must draw and control the pointer because certain kernel-mode callbacks (which are only available in the video miniport driver) are required. This can adversely affect performance because it requires IOCTLs to communicate with the miniport driver for each pointer operation.

To write a display driver and miniport driver pair, you must include IOCTLs for passing pointer information between the two drivers, and to allow the miniport driver to assume the drawing of any or all pointers, if necessary. The permedia and framebuf sample drivers use this approach to pointer handling. See Video I/O Control Codes for video pointer IOCTL definitions.


Pointer Drawing

GDI supports both color pointers and monochrome pointers. The shape of a monochrome pointer is defined by a single bitmap. The width of the bitmap is the same as the width of the pointer on the display, but the bitmap has twice the vertical extent as appears on the display, allowing it to contain two masks.

Calls to the pointer functions are serialized by GDI. This means two different threads in the driver cannot execute the pointer functions simultaneously. There are two possible pointer functions: DrvSetPointerShape and DrvMovePointer.


Drawing Monochrome Pointers

A monochrome bitmap is comprised of two parts: the first defines the AND mask for the pointer; the second defines the XOR mask. Together these masks provide two bits of information for each pixel of the pointer image. The following table describes the result that is displayed for the indicated values in the AND and XOR masks.

AND mask value | XOR mask value | Result displayed
0 | 0 | Pixel is black
0 | 1 | Pixel is white
1 | 0 | Pixel is unchanged (transparent)
1 | 1 | Pixel color is inverted

This bitmap definition and usage supplies a black-and-white image, while providing support for transparency and inversion of the pixels that make up the pointer.


Drawing Color Pointers

Defining the color pointer in the same way as the monochrome pointer (that is, as a bitmap that includes an AND portion and an XOR portion — see Pointer Drawing and Drawing Monochrome Pointers) also supports transparency and inversion.

  • If the color bitmap is black (index 0) and the AND mask value is 1, then the result is transparency.
  • If the color bitmap is white and the AND mask value is 1, then the result is inversion.
  • If the device cannot display color, then a pointer can be drawn as black and white.

These conventions allow applications to use a single pointer definition for both color and monochrome displays.


Controlling the Pointer: DrvSetPointerShape

If a display driver controls the pointer, then the driver must support DrvSetPointerShape to allow the pointer shape to be changed. A call to DrvSetPointerShape produces the following results:

  1. The function removes any existing pointer that the driver has drawn on the display.
  2. The function sets the new requested shape, unless it is unable to handle the shape.
  3. The new pointer is displayed at the position indicated by the parameters of the call.

The driver can call EngSetPointerShape to have GDI manage a software cursor.


Moving the Pointer: DrvMovePointer

If DrvSetPointerShape is included in the driver, then DrvMovePointer must also be supported. This function moves a driver-managed pointer to a new position. Because GDI serializes calls to pointer functions, DrvMovePointer is not be called while any thread is drawing in the display driver, unless the GCAPS_ASYNCMOVE flag has been set in the DEVINFO structure.

The driver should call EngMovePointer to have GDI move an engine-managed pointer on the device. The driver requests that GDI manage the cursor by calling EngSetPointerShape.


Managing Display Palettes

If the video hardware supports colors that can be set, it maintains a color lookup table called a palette. GDI takes each RGB value and translates it into a device color index so that it can be displayed. GDI uses precalculated and cached tables for the translation. These tables are accessible to drivers as the user object XLATEOBJ. Therefore, every GDI graphics function that takes source colors and moves them to a destination device uses a XLATEOBJ structure to translate the colors. For more information on palettes and how GDI handles them, see GDI Support for Palettes.

If the video hardware supports palettes that can be set, GDI calls the DrvSetPalette function in the display driver when it has finished mapping colors into the device palette requested by the application. GDI passes the new palette to the display driver, and the driver queries the PALOBJ to set its internal hardware palette to match the palette changes for the video hardware. This is known as palette realization.

The DrvSetPalette function supplies a handle to a PDEV to the driver, and requests the driver to realize the palette for that device. The driver should set the hardware palette to match the entries in the given palette as closely as possible.

This entry point is required if the device supports a palette that can be set, and should not be provided otherwise. A display driver specifies that its device has a settable palette by setting the GCAPS_PALMANAGED bit in the flGraphicsCaps field of the DEVINFO structure returned in DrvEnablePDEV.

The service routine PALOBJ_cGetColors is available to display drivers. This function downloads RGB colors from an indexed palette, and should be called from within the implementation of DrvSetPalette.


Bitmaps in Display Drivers

Certain devices, such as the 16-color VGA display, can more rapidly perform bit-block transfers from nonstandard bitmaps. To support this, a driver can hook DrvCreateDeviceBitmap which allows the driver to create a bitmap that a driver manages completely. When a driver creates such a bitmap, the driver can store it in any format. The driver examines the passed parameters and provides a bitmap with at least as many bits-per-pixel as requested. The contents of the bitmap are undefined after creation. If the application requests a device-managed bitmap, GDI calls the driver for drawing functions after DrvCreateDeviceBitmap returns control. If the driver returns FALSE, the driver-managed bitmap is not created, so GDI can handle drawing operations on an engine-managed surface.

The DrvSaveScreenBits function is also related to bit-block transfers in display drivers. Some display drivers can move data to or from off-screen device memory more rapidly than an area can be redrawn or copied from a DIB. These drivers can hook DrvSaveScreenBits, which lets the driver be called to save or restore a specified rectangle of a displayed image more quickly when a menu or dialog box appears.

Note For bit-block transfer calls, GDI (not the driver) handles pointer exclusion and clip region locking.

Drivers that implement device bitmaps in off-screen memory can significantly improve system performance. Off-screen device bitmaps improve system performance by:

  • Using accelerator hardware in place of GDI to draw.
  • Improving the speed of bitmap-to-screen bit-block transfers.
  • Reducing demands on main memory (a bitmap stored in off-screen memory isn't taking up space in main memory).
  • Leveraging hardware to perform operations that support OpenGL, such as mask bit-block transfers and double-buffering.

Drivers should implement device bitmaps in off-screen memory through DrvCreateDeviceBitmap. The sample permedia driver implements device bitmaps in off-screen memory and should be referred to for a complete example.


Asynchronous Rendering

A display driver that handles one or more graphics DDI drawing operations asynchronously and provides GDI access to its bitmaps through the use of EngModifySurface must implement a synchronization routine. The driver must also provide a synchronization routine in order to avoid drawing errors if it batches graphics DDI drawing operations.

Such a driver has the option of implementing one of DrvSynchronizeSurface or DrvSynchronize as the synchronization routine. GDI calls one of these routines only when the driver has hooked them in EngAssociateSurface. GDI will call only DrvSynchronizeSurface in drivers that hook both of these synchronization routines.

DrvSynchronizeSurface provides additional information to the driver regarding synchronization events and why they occur. This enables the driver to reduce performance lag due to synchronization. For example, drivers that track which device bitmaps are in the accelerator's queue might be able to return immediately from DrvSynchronizeSurface if the specified surface is not currently in the queue.

In addition to providing a synchronization routine, a driver can also activate a time-based or programmatic flush mechanism by setting the following flags in the flGraphicsCaps2 field of the DEVINFO structure:

  • GCAPS2_SYNCTIMER — Setting this flag causes the driver's synchronization routine to be called periodically. Drivers that batch graphics DDI calls must specify this flag. By doing so, these drivers avoid problems such as lag in a software cursor's movement or in drawing that is performed in bursts.

    GDI passes the DSS_TIMER_EVENT flag to DrvSynchronizeSurface when this synchronization routine is called due to a periodic event.

  • GCAPS2_SYNCFLUSH — Setting this flag causes the driver's synchronization routine to be called whenever the Microsoft® Win32® GdiFlush API is called. Drivers that perform asynchronous rendering must specify this flag and provide a synchronization routine.

    GDI passes the DSS_FLUSH_EVENT flag to DrvSynchronizeSurface when this synchronization routine is called due to a flush-based event. See the Platform SDK documentation for more information about GdiFlush.

Limitations on Batching DirectDraw Drawing Calls

The driver must never batch DirectDraw drawing calls when the destination surface is the visible screen. Such a situation occurs in a windowed DirectX® application where the completed frame is updated to the screen via DdBlt and should thus be displayed immediately. This restriction also applies to DirectDraw® video port surfaces, which might be flipped asynchronously.


Transparency in Display Drivers

If the display hardware supports transparency, the display driver should implement DrvTransparentBlt.

To reduce the cost of reading from video memory, drivers should implement this function when both the source and destination surfaces are in video memory. Drivers should let GDI process transparent bit-block transfers from system memory to video memory, and let GDI handle stretched bit-block transfers as well.

For example code, refer to the permedia sample driver.


Special Effects in Display Drivers

Windows® 2000 and later operating system versions support the following special effects:

  • If the display hardware supports alpha blending, the display driver can implement DrvAlphaBlend.
  • If the display hardware supports gradient fills, the display driver should implement DrvGradientFill.

Alpha Blending

The Windows 2000 (and later) Shell uses alpha blending extensively to perform operations such as blend-in and blend-out animations and alpha cursors. Because alpha blend operations require reading from both the source and destination surfaces, it is very slow to punt to GDI when either the source or destination is in video memory. Consequently, hardware accelerations in the driver will yield visibly smoother animations and improve overall system performance.

Drivers should implement DrvAlphaBlend for bit-block transfers from compatible bitmaps using a constant alpha, and from 32 bpp BGRA system-memory surfaces with per-pixel alpha values. DrvAlphaBlend can be implemented using triangle texture fills, provided that no seam is ever visible.

The worst-case error produced by DrvAlphaBlend should not exceed one (1) per color channel. When stretching is involved, the source should be COLORONCOLOR-stretched (see the Platform SDK documentation) prior to blending; the worst-case error should not exceed one (1) per color channel combined with the worst-case stretching error.

In cases where alpha blending is combined with stretching, the Hardware Compatibility Test (HCT) tests a display driver's implementation of DrvAlphaBlend in the following way:

  1. The HCT calls the display driver's DrvAlphaBlend, producing an alpha-blended and stretched rectangle.
  2. The HCT generates a destination rectangle, using the same source rectangle as was used in the call to DrvAlphaBlend.
  3. For each pixel P in the destination rectangle of step 2, the HCT simulates a reverse stretch to determine the corresponding pixel in the source rectangle, before stretching. The HCT applies a tolerance value to the reverse stretch to accommodate the varying stretch implementations by drivers. The HCT then calculates the alpha blend that should be applied to that pixel.

    Because any of four possible pixels (the corners of the 3 X 3 pixel square centered on pixel P) in the source rectangle could be stretched to produce pixel P in the destination rectangle, the HCT must compare the color value of each corner pixel with that of the pixel at the corresponding position in the rectangle produced by DrvAlphaBlend.

The worst-case stretching error is the largest difference in color value between any pair of corresponding corner pixels, where one of them is on the DrvAlphaBlend-produced rectangle, and the other is on the HCT-produced source rectangle.

Gradient Fills

The Windows 2000 (and later) Shell uses gradient fills on all caption bars.

The results produced by DrvGradientFill depend on the number of bits per pixel, and must satisfy the following guidelines:

24-bpp or 32-bpp surfaces

  • Values must increase or decrease monotonically in all gradated directions.
  • For rectangular gradients:

    When ulMode == GRADIENT_FILL_RECT_H, each vertical bar must be a single color.

    When ulMode == GRADIENT_FILL_RECT_V, each horizontal bar must be a single color.

  • The worst-case error in any channel must not exceed
    ±[1 + (GradientSize + 255)/512]

    In this expression GradientSize is one of the following:

    dX when ulMode == GRADIENT_FILL_RECT_H

    dY when ulMode == GRADIENT_FILL_RECT_V

    max(dX, dY) when ulMode == GRADIENT_FILL_TRIANGLE

    In the foregoing, dX is the width of the region (prclExtents->right - prclExtents->left), and dY is the height of the region (prclExtents->bottom - prclExtents->top).

  • The endpoints of the region must be exact matches.

15-bpp or 16-bpp surfaces

The worst-case error in any channel cannot exceed ±15.

1-bpp to 8-bpp surfaces

No error is permitted in gradient fills for any of these surfaces. For an 8-bpp surface, GDI does not call the driver's DrvGradientFill function.

Note that, in all surfaces, clipping does not affect results.


Color Management for Displays

GDI supports Image Color Management (ICM) version 2.0. Display drivers can use ICM without implementing any special code.

If the display hardware supports a gamma ramp, the display driver should implement DrvIcmSetDeviceGammaRamp. Color-calibrating applications that require color exactness use this capability. DirectDraw also uses this function to allow DirectX applications — such as a game that performs palette animation in RGB modes — to control the gamma ramp. For example code, refer to the permedia sample driver.


Monitor Profiles

A monitor profile is a type of device profile used for color management. This profile contains information about how to convert colors in a monitor's color space and color gamut into colors in a device-independent color space. Any user-mode application, such as a setup program or a word processor with graphics capabilities, can use a monitor profile, provided that ICM has been enabled, and that the application has knowledge of the profile's format.

Although you can create custom monitor profiles using third-party tools, you may be able to use one of the monitor profiles shipped with Windows 2000 and later operating system versions. These profiles are described in the following table.

Profile | Monitor Characteristics
mnB22G15.icm | B22 phosphor, gamma 1.5
mnB22G18.icm | B22 phosphor, gamma 1.8
mnB22G21.icm | B22 phosphor, gamma 2.1.
mnEBUG15.icm | EBU phosphor, gamma 1.5
mnEBUG18.icm | EBU phosphor, gamma 1.8
mnEBUB21.icm | EBU phosphor, gamma 2.1
mnP22G15.icm | P22 phosphor, gamma 1.5
mnP22G18.icm | P22 phosphor, gamma 1.8
mnP22G21.icm | P22 phosphor, gamma 2.1
Diamond Compatible 9300K G2.2.icm | 9300° Kelvin white point, gamma 2.2
Hitachi Compatible 9300K G2.2.icm | 9300° Kelvin white point, gamma 2.2
NEC Compatible 9300K G2.2.icm | 9300° Kelvin white point, gamma 2.2
Trinitron Compatible 9300K G2.2.icm | 9300° Kelvin white point, gamma 2.2

Installing a Monitor Profile

A user can install a monitor profile in three different ways:

  1. In the Windows Explorer, select the profile, right-click on the name, and then click Install Profile.
  2. Refer to the profile in a monitor INF file.
  3. Hard-code the profile's path and file name in an application.

Because the default directory for monitor profiles is subject to change, hard-coding the profile's path and file name is not recommended.

Using a Monitor Profile

A monitor profile, unlike a printer profile, supports very little communication between the output device and an application. For example, if a user changes the gamma ramp in the video buffer, the monitor profile is not notified that such a change has occurred. In this case, with ICM enabled, two color corrections are applied to the image before it is displayed, as shown in the following sequence of steps.

  1. The application opens and then manipulates the image.
  2. The application enables ICM by a call to a Win32 GDI ICM function, such as SetICMMode. (See the Platform SDK for more information.)
  3. The application sends the image to Win32 GDI.
  4. If ICM is enabled, Win32 GDI uses the monitor profile to translate the colors in the image.
  5. Win32 GDI sends the image to kernel-mode GDI.
  6. Kernel-mode GDI formats the image for the display driver, based on such device characteristics of the DC as bit depth, resolution, and halftoning.
  7. The display driver (or video hardware) performs gamma correction to the image.


DirectDraw and GDI

GDI automatically enables DirectDraw when the display driver is initialized. To provide better interaction between DirectDraw and the graphics DDI portion of the driver, a driver that also supports the DirectDraw DDI can implement or call the following functions:

DrvDeriveSurface
A driver-implemented function that wraps a GDI driver surface around a DirectDraw driver surface, allowing any GDI drawing to DirectDraw video memory or AGP surfaces to be hardware accelerated (rather than being drawn in software via the DIB engine). Typically, if the driver already supports off-screen device bitmaps, this function should require only a few additional lines of code.

DrvDeriveSurface improves the performance of DirectDraw applications that also use GDI, and it also eliminates cursor flicker when a software cursor is used with DirectDraw or Direct3D applications.

See the permedia driver source for a sample driver implementation.

HeapVidMemAllocAligned and VidMemFree
Driver-called functions that use the DirectDraw heap manager for all off-screen memory management. DrvCreateDeviceBitmap should call HeapVidMemAllocAligned to request DirectDraw to allocate space for GDI bitmaps; DrvDeleteDeviceBitmap should call VidMemFree to free this allocation.

DirectDraw has priority over the graphics DDI portion of the driver for off-screen memory allocation. The driver should hook the DirectDraw DdFreeDriverMemory callback, which allows the driver to remove GDI surfaces from off-screen memory to make space for higher priority DirectDraw surface allocations.

Both HeapVidMemAllocAligned and VidMemFree are declared in dmemmgr.h, which ships with the Windows DDK. A driver might have to define __NTDDKCOMP__ before including this header file.

See the permedia driver source for a sample driver implementation.


Tracking Window Changes

Changes to a window, including one in a multiple-monitor system, can be tracked by a device driver through a WNDOBJ. A WNDOBJ is a driver-level window object that contains information about the position, size, and the visible client region of a window. That is, by creating a WNDOBJ that corresponds to an application window, the driver can track the size, position, and client region changes in that window.

An application uses the Win32 API to access the WNDOBJ_SETUP functionality implemented by the device driver. Access is gained through the Win32 ExtEscape function. GDI passes this escape call to the device driver with DrvEscape, implemented by the device driver with WNDOBJ_SETUP for the value of iEsc.

An application calls ExtEscape(hdc, WNDOBJ_SETUP,...) and passes a handle to the application-created window (created by CreateWindow or some equivalent Win32 function) through the input buffer to the driver. If the driver is to keep track of the window, it calls EngCreateWnd, within the context of the ExtEscape call, to create a WNDOBJ structure for the given window. From that point on, any changes to that window will pass down to the driver.

The driver should handle the ExtEscape call in a manner similar to the following:

ULONG DrvEscape(
  SURFOBJ *pso,
  ULONG    iEsc,
  ULONG    cjIn,
  PVOID    pvIn,
  ULONG    cjOut,
  PVOID    pvOut)
{
    WNDOBJ *pwo;
    WNDDATA *pwd;

    if (iEsc == WNDOBJ_SETUP)
    {
        pwo = EngCreateWnd(pso,*((HWND *)pvIn),&DrvVideo,
                           WO_RGN_CLIENT, 0);

    // Allocate space for caching client rects. Remember the pointer
    // in the pvConsumer field.

        pwd = EngAllocMem(0, sizeof(WNDDATA), DRIVER_TAG);
        WNDOBJ_vSetConsumer(pwo,pwd);

    // Update the rectangle list for this wndobj.

        vUpdateRects(pwo);
        return(1);
    }

}

Creating a window object involves locking special window resources, therefore EngCreateWnd should be called only in the context of the WNDOBJ_SETUP escape in DrvEscape or DrvSetPixelFormat.

The EngCreateWnd function supports window tracking by multiple drivers. Through EngCreateWnd, each driver identifies its own callback routine that GDI is to call for changes to the corresponding window. This feature allows, for example, a live video driver to track changes to live video windows while an OpenGL driver is tracking changes to OpenGL windows.

GDI will call back to the driver with the most recent window states if a new WNDOBJ is created in DrvSetPixelFormat or ExtEscape. GDI will also call back to the driver when a window referenced by a WNDOBJ is destroyed.

As an accelerator, the driver may access public members of the WNDOBJ structure.

Tracking window changes involves the use of three callback functions provided to support the WNDOBJ structure. The visible client region may be enumerated by calling the WNDOBJ_cEnumStart and WNDOBJ_bEnum callback functions. A driver may associate its own data with a WNDOBJ by calling the WNDOBJ_vSetConsumer callback function.


Supporting the DitherOnRealize Flag

In earlier versions of GDI and the graphics DDI, two calls by GDI to display driver functions were required to dither a specified color and then realize a brush for that color. For example, when an application requests that a rectangle be filled with a dithered color, GDI typically calls DrvBitBlt, passing the extents of the rectangle and the brush object to use. The display driver then checks the brush, finds that it has not been realized, and calls back to GDI with BRUSHOBJ_pvGetRbrush for GDI's realization of the brush. Because the display driver, not GDI, performs the dithering of a brush, GDI passes the RGB that the application originally supplied for dithering in a DrvDitherColor callback to the display driver.

DrvDitherColor returns a pointer to an array of color indexes that describe the dither information for the supplied color back to GDI. GDI immediately passes this dither information back to the display driver in a call to DrvRealizeBrush. With the BRUSHOBJ realized, control returns back to GDI and subsequently back to the original DrvBitBlt function.

To accomplish dithering using the above technique, GDI has to call DrvDitherColor, followed immediately by a call to DrvRealizeBrush; two separate function calls. Setting a GCAPS_DITHERONREALIZE flag in the DEVINFO structure and modifying DrvRealizeBrush to effectively combine these two functions eliminates the need for the separate call to DrvDitherColor and also saves some memory allocation. Under this scheme, if the display driver sets GCAPS_DITHERONREALIZE, GDI calls DrvRealizeBrush with the RGB to be dithered and with the RB_DITHERCOLOR flag set in iHatch. The RB_DITHERCOLOR flag is set in the high byte of iHatch, while the RGB color to be dithered is contained in the three low-order bytes. The need to call DrvDitherColor is eliminated in this situation because the functionality of both calls is put into one.

For example code, refer to the permedia sample driver.


Supporting Banked Frame Buffers

Most of today's accelerators have frame buffers that can be mapped linearly into CPU address space. The display drivers of such devices do not have to support banked frame buffers.

GDI cannot directly access banked memory associated with a banked frame buffer. Consequently, the display driver of a device with such a frame buffer must divide the frame buffer into a series of contiguous banks and provide a means for GDI to perform its draw operations to the appropriate frame buffer banks. That is, GDI is made to write data to one bank of the frame buffer before being moved to subsequent banks, as necessary, to complete the draw operation through a mechanism referred to as banked callbacks.

The permedia sample driver shipped with the Windows DDK provides sample code for implementing banked frame buffer support.

The following figure shows a sample accelerator's frame buffer, a 1024-by-768 VGA display buffer, divided into several banks. This figure is provided for the purpose of illustration only. The display driver does not specifically use the physical address A000 but uses a logical address passed to it by the miniport driver.

Example of Mapping Video Memory to a Banked Frame Buffer

In this example, the video memory contents are written to the accelerator through a series of draw operations that address contiguous banks of the frame buffer. As far as GDI is concerned, each of its draw operations appear to be to the standard frame buffer and not to different banks of the accelerator's frame buffer. The device driver for the accelerator handles the banking operations that cause GDI to draw to the accelerator's frame buffer on a bank-by-bank basis.

The frame buffer is a device-managed surface when an accelerator employs a banked frame buffer, so the display driver hooks the draw function calls. When the display driver hooks a call, such as draw path, fill path, or bit-block transfer, it determines which banks in the frame buffer are affected by the draw function that was called.

If the driver elects to have GDI perform the draw function, the driver calls the appropriate Eng Xxx function. However, before making the call, the display driver must modify the clip and surface objects it received in the hooked call and pass these modified objects in the call back to GDI. The clip and surface objects are modified to prevent GDI from drawing beyond the extents of the bank. That is, if GDI is called to draw a path that exists partially in the next bank, and if there is no modification of the clip and surface objects, GDI will write to memory beyond the extents of the current bank. If GDI attempts to draw outside the extents of the bank, the resulting access violations can be difficult to track.

The example banked frame buffer in the following figure shows how an elliptical object drawn on the display spans two banks of the banked frame buffer, BANK_1 and BANK_2.

Drawn Objects Span Multiple Banks in the Frame Buffer

To draw this object, GDI must first draw the top portion of the ellipse (in BANK_1) to the standard frame buffer, and then draw the lower portion of the ellipse to the same standard buffer. The display driver must then map these two successive writes by GDI to BANK_1 and BANK_2 of the banked frame buffer to display, and also to prevent GDI from writing beyond the limits of each bank.

When performing banked frame buffering, the display driver can determine the bounds of the object (the size of the destination rectangle) by checking the parameters of the call or by calling back to GDI. From the bounds of the object, the driver can determine how many banks are spanned by the object. For every bank that the bounding rectangle touches, the display driver calls back to the appropriate GDI draw function, changing values for each call.

The driver changes the CLIPOBJ members originally passed by GDI to correspond to changes in the bounds of the bank. The top and bottom scan values are redefined so that GDI does not attempt to draw beyond the limits of the bank. The bank manager takes the original CLIPOBJ data obtained from GDI and retains the values for later restoration. Then it changes the bounds to provide new rclBounds.top and rclBounds.bottom values that describe the extent of the bank being drawn to. During banking, GDI must perform clipping to a size that prevents drawing the entire path and overwriting the limits of the current bank.

If the original CLIPOBJ passed by GDI was defined as NULL or DC_TRIVIAL, then the display driver passes a substitute CLIPOBJ, created through EngCreateClip. This substitute CLIPOBJ is modified to define a clip window so that GDI will clip to the extents of a single bank. If the CLIPOBJ is complex, such as a triangular-shaped clip object on an ellipse as shown in the preceding figure, the display driver modifies the complex CLIPOBJ with the rclBounds.top and rclBounds.bottom values to produce an additive effect between the two clip objects. As a result, GDI is prevented from writing off the end of the bank. The driver must also restore the original bounds of the CLIPOBJ data previously obtained from GDI.

In addition to altering the bounds values, the display driver sets the OC_BANK_CLIP flag in the clip object to inform GDI that this is a banked callback .

GDI must also be made to draw with reference to the beginning of the standard frame buffer. When called to draw, GDI simply gets a pointer to a SURFOBJ, which includes the pvScan0, lDelta, and iBitmapFormat members. GDI calculates where to draw on the surface by using these values as follows:

start_draw_point = pvScan0 + (y*lDelta) + (x*PixelSize(iBitmapFormat))

where x and y are coordinates at which drawing is to begin, and start_draw_point is the address at which the address of the first pixel is to be drawn. GDI performs this calculation on every drawing call and always references the SURFOBJ for pvScan0, which is the logical address for the start of the standard frame buffer.

For example, if GDI needs to draw the entire contents of an 8 bits-per-pixel 64K frame buffer, beginning at a logical address of pvScan0 = 0x100000, it would end the draw operation at 0x10FFFF (0x100000 + (63*1024)+(1023)), where y is 63, lDelta is 1024, and x is 1023 (the position of the last pixel in the last scan line).

The next time the display driver calls GDI to draw that part of the object that falls within the next bank of the banked frame buffer, GDI interprets the value of y as 64. With a value of 0x100000 for pvScan0 and 64 for y, GDI would attempt to begin to write data at 0x110000. However, 0x110000 is beyond the 0x10FFFF extent of the 64K frame buffer and must not be written to by GDI during this operation.

Consequently, when the display driver requests GDI to write the data that is to appear in the second and subsequent banks of the frame buffer, the driver must decrement the value of pvScan0 so that GDI calculates a starting point that is still referenced to the example address of 0x100000. Continuing in the example, this means decrementing the value of pvScan0 to a value of 0x090000 when drawing to the second bank of the frame buffer. As a result of this change to pvScan0, GDI still draws with a reference to address 0x100000. That is, 0x090000 + (64*1024) + 0 is equal to 0x100000, where GDI must begin to draw in order for the data to be mapped into the second bank of the frame buffer.


Unloading Video Hardware

When a surface is no longer required, a GDI call to DrvDisableSurface informs the display driver that the surface created for the current hardware device by DrvEnableSurface can be disabled. The driver must also free any resources the surface was using.

After the surface is disabled, GDI calls DrvDisablePDEV to inform the driver that the hardware device is no longer needed. The driver then frees any memory and resources that were allocated during the processing of DrvEnablePDEV.

Finally, GDI disables the display driver by calling DrvDisableDriver. The driver must free any resources allocated during DrvEnableDriver and restore the video hardware to its default state. After the driver returns from the DrvDisableDriver function, GDI frees the memory it has allocated for the driver and removes driver code and data from memory.

The following figure shows GDI's calling sequence for disabling the video hardware.

Disabling the Video Hardware


Using Events in Display Drivers

GDI provides support for events, a type of kernel dispatcher object that can be used to synchronize two threads running below DPC level. A display driver can use events to synchronize access to the video hardware:

  • By the display driver and the video miniport driver
  • By the display or video miniport driver and another component, such as an OpenGL driver or an applet extension.

The following table lists the GDI event-related functions.

Function | Description
EngClearEvent | Sets a given event object to the nonsignaled state.
EngCreateEvent | Creates a synchronization event object.
EngDeleteEvent | Deletes the specified event object.
EngMapEvent | Maps a user-mode event object to kernel mode.
EngReadStateEvent | Returns the current state of a given event object: signaled or nonsignaled.
EngSetEvent | Sets an event object to the signaled state if it was not already in that state, and returns the event object's previous state.
EngUnmapEvent | Cleans up the kernel-mode resources allocated for a mapped user-mode event.
EngWaitForSingleObject | Puts the current thread into a wait state until the given dispatch object is set to the signaled state, or (optionally) until the wait times out.

The video port driver also provides support for events to video miniport drivers. See Using Events in Video Miniport Drivers for more information.

For a broader perspective on events, see Event Objects.


Multiple-Monitor Support in the Display Driver

Multiple-monitor support is provided by Windows 2000 and later; therefore, display driver writers must not implement any special code to provide this support.

Display drivers must be implemented without using global variables. All state must exist in the PDEV for a particular display driver. GDI will call DrvEnablePDEV for every hardware device extension that is created by the video miniport driver.

To track window changes in a multiple-monitor system, a driver can request GDI to create WNDOBJ objects with desktop coordinates. The driver does this by calling EngCreateWnd using the flag WO_RGN_DESKTOP_COORD. See Tracking Window Changes for more information.

In a multiple-monitor system, GDI stores the device's desktop position in the dmPosition member of the DEVMODEW structure.


Mirror Drivers

A mirror driver is a display driver for a virtual device that mirrors the drawing operations of one or more additional physical display devices. It is implemented and behaves much like any other display driver; however, its paired video miniport driver is minimal in comparison to a typical miniport driver. See Mirror Driver Support in the Miniport for more information about miniport drivers in mirroring systems. The Windows DDK contains a sample mirror driver which includes component source files that are contained in three directories.

Directory | Contains Source Files For
video\displays\mirror\dll | The mirror driver.
video\miniport\mirror | The miniport driver.
video\displays\mirror\app | The user-mode service. Also contains mirror.inf.

GDI supports a virtual desktop and provides the ability to replicate a portion of the virtual desktop on a mirror device. GDI implements the virtual desktop as a graphics layer above the physical display driver layer. All drawing operations start in this virtual desktop space; GDI clips and renders them on the appropriate physical display devices that exist in the virtual desktop.

A mirror device can specify an arbitrary clip region in the virtual desktop, including one that spans more than one physical display device. GDI then sends the mirror device all drawing operations that intersect that driver's clip region. A mirror device can set a clip region that exactly matches a particular physical device; therefore, it can effectively mirror that device.

Note In Windows 2000 and later, the mirror driver's clip region must include the primary display device.

The mirror driver code sample illustrates how to implement a mirror driver. For more information that will help you understand the sample:

  • Use the sample INF file, mirror.inf, as a template. See Mirror Driver INF File for details.
  • See the mirror.exe application, which demonstrates how the mirror driver is attached to the virtual desktop. See Mirror Driver Installation for details.
  • Refer to the Platform SDK documentation for information about using the Win32 EnumDisplayDevices function. You use this function to determine the \\.\Display# name associated with your mirrored display device. This number is required to change the settings for your mirrored device. For multiple instances, # is a different number for each instance; therefore you must determine this number by iterating through the available display devices.

To attach the mirrored device to the global desktop

  1. Add the REG_DWORD registry entry Attach.ToDesktop to your driver's services keys.
  2. Set this key's entry to 1 (one).

To disable the mirror driver, set this entry to 0 (zero).

As mentioned previously, the driver is installed and operates in a drawing layer that resides above the device layer. Because the mirror driver's coordinate space is the desktop coordinate space, it can span more than one device. If the mirror driver is intended to mirror the primary display, its display coordinates should coincide with the primary display's desktop coordinates.

  • After the mirror driver is installed, it will be called for all rendering operations that intersect the driver's display region. On a multiple-monitor system, this might not include all drawing operations if the mirror driver overlaps only the primary display device.
  • It is recommended that a user mode service be used to maintain the mirror driver's settings. This application can ensure that the driver is loaded correctly at boot time and it can respond appropriately to changes to the desktop by getting notifications of display changes via the WM_DISPLAYCHANGE message.
  • GDI calls the mirror driver for any 2D graphics DDI drawing operation that intersects the driver's bounding rectangle. Note that GDI does not perform a bounding rectangle check if the surface is a device format bitmap; that is, if the SURFOBJ has an iType of STYPE_DEVBITMAP.
  • As always, the mirror driver must be implemented without the use of global variables. All state must exist in the PDEV for that particular driver. GDI will call DrvEnablePDEV for every hardware device extension created by the video miniport driver.
  • The mirror driver should not support DirectDraw.
  • A mirror driver must set the GCAPS_LAYERED flag to TRUE in the flGraphicsCaps member of the DEVINFO structure.
  • A mirror driver can optionally support brush realizations by implementing DrvRealizeBrush.

GDI allows the same driver to run on both a single and multiple-monitor system. A driver in a multiple-monitor system need only be aware of its position within the global desktop. GDI provides this position to the driver whenever a Win32 ChangeDisplaySettings call occurs, such as when a user dynamically changes the monitor's position in the desktop through the Control Panel's Display applet. GDI will update dmPosition member of the DEVMODEW structure accordingly when such a change occurs. A driver can receive notification of such a change by implementing DrvNotify. See Mirror Driver Installation for more information.

Note Mirror drivers are not required to render with pixel-perfect accuracy when rendering on the client side with such accuracy may be difficult. For example, the adapter/monitor receiving the mirrored image is not required to render Grid Intersect Quantization (GIQ) line drawing and polygon fills with the same precision as the adapter/monitor being mirrored.


Mirror Driver INF File

Use the mirror.inf sample mirror driver INF file as a template for constructing your own mirror driver INF file.

Note You cannot use the geninf.exe tool shipped with the Windows DDK to create the mirror driver INF file.

For more information, see Installing a Boot Driver and INF File Sections and Directives.


Mirror Driver Installation

The system installs a mirror driver in response to a Win32 ChangeDisplaySettings or ChangeDisplaySettingsEx call. You should implement a user-mode service to make one of these calls to install your mirror driver and maintain its settings. Use this application to:

  • Ensure that the mirror driver is loaded correctly at boot time. The application should specify the CDS_UPDATEREGISTRY flag to save the settings to the registry, so that the driver will automatically be loaded on subsequent boots with the same DEVMODEW information described below.
  • Respond appropriately to desktop changes by getting display change notifications through the WM_DISPLAYCHANGE message.

The sample mirror.exe, which you can build from the source code files that ship with the Windows DDK, implements a subset of the operations a user-mode service should provide to load a mirror driver.

Before the mirror driver is installed, the user-mode application should fill in a DEVMODEW structure that specifies the following display attributes:

  • Position (dmPosition)
  • Size (dmPelsWidth and dmPelsHeight)
  • Format of the mirrored display (dmBitsPerPel)

The user-mode application must also set dmFields appropriately, by including a flag for each of these structure members to be changed. The mirrored display's position coordinates must be specified in desktop coordinates; as such, they can span more than one device. To directly mirror the primary display, the mirror driver should specify its location to coincide with the primary display's desktop coordinates.

After the DEVMODEW structure members have been set, change the mirrored display settings by passing this structure in a call to the Win32 ChangeDisplaySettingsEx function.

After the mirror driver is installed, it will be called by GDI for all rendering operations that intersect the driver's display region. GDI might not send all drawing operations to the mirror driver if the mirror driver overlaps only the primary display in a multiple-monitor system.

See the Platform SDK documentation for more information about the ChangeDisplaySettings and ChangeDisplaySettingsEx functions, and display change desktop notifications.


Display Driver Testing Tools

In addition to providing a debugger, Windows® 2000 and later operating system versions provide the following tools for testing and debugging your display driver:

  • newdisp — lets you dynamically reload your driver without rebooting the system. See NewDisp: Dynamic Reload of a Display Driver for details.
  • Slider control in the Control Panel's Display program — lets you dynamically change the accelerations that GDI will call in your driver. See Dynamic Change of Permitted Driver Accelerations for details.


NewDisp: Dynamic Reload of a Display Driver

The Windows DDK provides a tool that allows a display driver to be dynamically reloaded without rebooting. This tool, called newdisp.exe, accelerates display driver testing during development by making reboots less necessary when updating display driver code.

To run newdisp.exe

  1. Close all Direct3D® and OpenGL applications.
  2. Copy your updated display driver's DLL into the \system32 directory.
  3. Run newdisp (without any arguments).

Each time newdisp is invoked, it reloads the display driver. Assuming that no driver references exist at the time of invocation, newdisp accomplishes the dynamic reload by:

  • Calling ChangeDisplaySettings with 640x480x16 colors, which causes the system to load and run the 16 color VGA display driver DLL, and at the same causes the old display driver DLL to be unloaded from memory.
  • Immediately performing another ChangeDisplaySettings callback to the original mode, which causes the new display driver DLL to be loaded from \system32 directory, and the 16 color VGA display driver DLL to be unloaded.

A reference to the driver instance exists if the driver has active Direct3D, WNDOBJ, or DRIVEROBJ objects. When newdisp is run while a reference to the driver instance exists, the old display driver DLL will never be unloaded, and correspondingly the new display driver DLL will never be loaded.

Newdisp relies on dynamic driver loading functionality that has been added to Windows 2000 and later to reload the driver without rebooting; consequently, it does not work on Windows NT® 4.0 and previous operating system versions. It also does not work if the VGA driver cannot be loaded on the graphics device, or if the native display driver supports a mode of 640x480x16 colors instead of letting that mode be handled by the VGA driver.

Note that newdisp does not currently cause the video miniport driver to be reloaded. If the miniport driver is changed, the system must be rebooted to install and test it.


Dynamic Change of Permitted Driver Accelerations

The driver's acceleration level can be changed through the user interface by using the slider included in the Control Panel's Display applet. Depending on the value set with this slider, GDI allows the following levels of driver accelerations listed in the following table.

Value | Description
0 | All display driver accelerations are permitted.
1 | DrvSetPointerShape and DrvCreateDeviceBitmap are disabled.
2 | In addition to 1, more sophisticated display driver accelerations are disallowed, including DrvStretchBlt, DrvFillPath, DrvGradientFill, DrvLineTo, DrvAlphaBlend, and DrvTransparentBlt.
3 | In addition to 2, all DirectDraw and Direct3D accelerations are disallowed.
4 | In addition to 3, almost all display driver accelerations are disallowed, except for solid color fills, DrvCopyBits, DrvTextOut, and DrvStrokePath. DrvEscape is disabled.
5 | No hardware accelerations are allowed. The driver will only be called to do bit-block transfers from a system memory surface to the screen.

A display driver can determine the current acceleration level by:

  • Receiving notification of a change to the acceleration level from GDI by implementing DrvNotify.
  • Calling EngQueryDeviceAttribute to query the current acceleration level.


DirectDraw DDI

The Microsoft® DirectDraw® DDI is a graphics interface that allows vendors to provide hardware acceleration for DirectDraw. It can be an integral part of the display driver or a separate dynamic-link library (DLL) that communicates with the display driver through a private interface defined by the driver's creator. On Microsoft® Windows® 2000 and later, a DirectDraw driver must be a 32-bit implementation.

This section describes the DirectDraw architecture and interface, and provides implementation guidelines for DirectDraw driver writers. The guidelines are specifically written for Windows 2000 and later. However, where possible, the differences for Windows 98/Me implementations have been pointed out. The reader should be familiar with the DirectDraw APIs, and have a firm grasp of the Windows 2000 display driver model. For more information about DirectDraw, see the Platform SDK.


DirectDraw Driver Header Files, Sample Code, and References

Microsoft® Windows® 2000 and later DirectDraw® driver writers use the following header files:

  • ddrawint.h contains the basic types, constants, and structures for DirectDraw drivers.
  • ddraw.h contains the basic types, constants, and structures used by both applications and drivers.
  • dvp.h is used when the driver supports the DirectDraw video port extensions (VPE).
  • dxmini.h is used when the driver includes miniport support for kernel-mode video transport.
  • ddkmapi.h is used when the driver wants to access the kernel-mode DirectDraw support for the DxApi function.
  • dmemmgr.h is used when the driver wants to perform its own memory management instead of relying on the DirectDraw run-time.
  • ddkernel.h is used when the driver includes kernel-mode support.
  • dx95type.h allows driver writers to easily port existing Windows 98/Me drivers to Windows 2000 and later. This header file maps names that are different on the two platforms.

With the exception of ddraw.h, all other header files are shipped with the Windows DDK. The ddraw.h header file is shipped with the Platform SDK.

The Windows DDK also provides sample code for a DirectDraw driver in the p3samp video display directory.

Reference pages for DirectDraw driver functions, callbacks, and structures can be found in DirectDraw Driver Functions and DirectDraw Driver Structures.

SDK-related aspects of the DirectDraw interface are covered in the Platform SDK.

DirectDraw driver writers can send questions and comments by e-mail to directx@microsoft.com.


DirectDraw Architectural Overview

Microsoft® DirectDraw® includes the following components:

  • User-mode DirectDraw (ddraw.dll) is a system-supplied dynamic-link library (DLL) that is loaded and called by DirectDraw applications. This component provides hardware emulation, manages the various DirectDraw objects, and provides display memory and display hardware management services.
  • Kernel-mode DirectDraw is an integral part of win32k.sys, which is the system-supplied graphics engine that is loaded by a kernel-mode display driver. This portion of DirectDraw performs parameter validation for the driver, making it easier to implement more robust drivers. This is a critical design goal since display drivers are trusted components of the Windows® 2000 and later operating systems. Kernel-mode DirectDraw also handles synchronization with GDI and all cross-process state.
  • The DirectDraw portion of the display driver, along with the rest of the display driver, is implemented by graphics hardware vendors. This component is referred to as the DirectDraw driver in this document. Other portions of the display driver handle GDI and other non-DirectDraw related calls.

This document generically refers to both of the system-supplied components as DirectDraw.

The following figure shows a block diagram of the DirectDraw driver architecture.

DirectDraw Driver Architecture

As shown in the preceding figure, an application accesses the display card through GDI (user and kernel-mode portions) and the display driver. The display driver will always support GDI calls and usually DirectDraw and Direct3D calls. The device independent bitmap (DIB) engine portion of GDI emulates functionality when it is not supported by the display driver.

When DirectDraw is invoked, it accesses the graphics card directly through the DirectDraw driver. Unlike GDI, DirectDraw is informed of the capabilities of a DirectDraw enabled driver. DirectDraw calls the DirectDraw driver for supported hardware functions, or the hardware emulation layer (HEL) for functions that must be emulated in software. Rather than calling the driver for requests it can't support, as GDI does, DirectDraw calls the driver for hardware supported requests and the DirectDraw HEL for requests that are not hardware supported. GDI calls, on the other hand, are sent to the driver, which must then call back into the DIB engine if the call is unsupported.

Note If the DirectDraw driver fails an operation, DirectDraw does not pass the operation to the DirectDraw HEL, but instead passes the DirectDraw driver's error code back to the application.

At initialization time and during mode changes, the display driver returns capability (caps) bits to DirectDraw. This enables DirectDraw to access information about the available driver functions, their addresses, and the capabilities of the display card and driver (such as stretching, transparent blits, display pitch, and other advanced characteristics). Once DirectDraw has this information, it can use the DirectDraw driver to access the display card directly, without making GDI calls or using the GDI specific portions of the display driver.


About DirectDraw

Microsoft DirectDraw is the display component of DirectX® that allows software designers to directly manipulate display memory, hardware blitters, hardware overlays, and flipping surfaces. DirectDraw provides a device-independent way for games and Windows subsystem software, such as 3D graphics packages and digital video codecs, to gain access to the features of specific display devices.

DirectDraw provides device-independent access to the device-specific display functionality in a direct 32-bit path. It accesses important functions in a driver that accesses the card directly, without the intervention of the Windows graphics device interface (GDI) or the device-independent bitmap (DIB) engine.

By taking advantage of this direct path, games and other display-intensive applications run faster and avoid tearing. A tear is a screen flicker caused by an image displayed and written to at the same time. Direct access often allows game performance to be limited solely by display card performance. DirectDraw also uses page flipping to provide smooth animation.

The rapid motion and ever-changing screens of many games and multimedia applications put a heavy burden on the display process and tend to exacerbate tearing. Although GDI is very fast at drawing spreadsheets, graphs, TrueType font rendering, and so on, it is not meant to be a real-time graphics API. DirectDraw augments GDI by handling the device-dependent hardware accelerator functions in a 32-bit driver.


DirectDraw Drivers

DirectDraw provides device independence through the DirectDraw driver. The DirectDraw driver is a device-specific interface usually provided by the display hardware manufacturer. DirectDraw exposes methods to the application and uses the DirectDraw portion of the display driver to work directly with the hardware. Applications never call the display driver directly.

Under Windows 2000 and later, the DirectDraw driver is always implemented as 32-bit code. The DirectDraw driver can be part of the display driver or a separate DLL that communicates with the display driver through a private interface defined by the driver writer. On Windows 2000 and later, the DirectDraw driver is assumed to be part of the display driver.

Note for Windows 98/Me When the DirectDraw driver is a separate DLL, it is loaded by ddhelp.exe. This occurs when DirectDraw is invoked.

DirectDraw still uses the non-DirectDraw specific portions of the Windows 98/Me display driver for BIOS calls (which must be 16-bit) and mode changes (which are not time-critical). DirectDraw hooks into the mode-changing process to update itself and to provide support for modes that GDI cannot support. For example, GDI does not operate well in modes below 640 X 480.

The DirectDraw driver contains only device-dependent code and performs no emulation. If a function is not performed by the hardware, the DirectDraw driver does not report it as a hardware capability. Additionally, the DirectDraw driver does not validate parameters because the DirectDraw run-time does this before the driver is invoked.


First Steps For DirectDraw Drivers

A good way to begin implementing DirectDraw functionality is to modify an existing driver. If no driver is available, start with the sample code in the DirectDraw portion of the DDK and get driver initialization, lock, and flip working. This will get a driver up and running as quickly as possible. From that base functionality, more powerful functionality can be added that will continue to improve display performance.

The DirectX Software Development Kit (SDK), which can be found in the Platform SDK, includes useful help and readme files, sample code, and tools such as DirectDraw Test that allows monitoring and testing of driver capabilities during the development process. A remote terminal in conjunction with the kernel debugger and debug printf statements are indispensable tools for verifying each action the driver takes.

Microsoft has tried to make developing a DirectDraw-enabled driver as easy as possible. However, as in all things made simple for the end user, the complexity is hidden under the hood. Because it is impossible to anticipate all the myriad hardware innovations and competing standards that will continue to emerge, a degree of complexity must be left to driver writers, who must adapt the technology to their unique hardware.

The minimum driver functionality DirectDraw requires is the ability to lock, unlock, and flip a surface. Assuming the hardware supports the related operations, driver support should also be added for blts (including transparent blts, which are important for speed in games), stretching, and overlays (critical for video playback).


Creating Device Drivers for Windows 98/Me that Work with DirectX

Microsoft® DirectX® is the high-performance game and multimedia API. The DirectX subsystem includes a new set of audio and display drivers that have been extended to support DirectX.

This topic contains important instructions on how OEMs and IHVs can install newer versions of these drivers and ensure a correct version number for the drivers. For the most up-to-date information, please see http://microsoft.com/hwdev/devdes/dll_dx5.htm.

Important The new release of DirectX 6.0 is the only vehicle that should be used by hardware vendors who ship DirectX components to their customers. The methods summarized in this article for ensuring correct version numbers and installing drivers must be followed to ensure a good experience for end users.


Overview

This topic applies only to Windows 98/Me.

The following procedure summarizes what the vendor must do to ensure that a DirectX driver is registered and will work correctly with DirectX DLLs.

To ensure a DirectX driver will work correctly with DirectX DLLs

  1. Ensure that all file names provided with the device driver are unique to the vendor, as described in Naming Windows 98/Me Device Drivers.
  2. Ensure that the device driver version number is correct for the Microsoft Windows®version and DirectX version, as described in the section Ensuring Correct Version Numbers for Windows 98/Me Drivers.
  3. Ensure that your DirectX driver is registered by completing Windows Hardware Quality Labs (WHQL) testing and acceptance, as described in Testing DirectX Device Drivers.

DirectX Setup will not recognize an installed driver as newer unless it is registered and versioned as a DirectX driver.

Note A "registered" driver is one for which the driver has been tested and accepted by WHQL with additional testing for DirectX compatibility. An "unregistered" driver is one that has not been tested and accepted by WHQL for DirectX compatibility. A registered DirectX driver is one that is provided by Microsoft or that has successfully passed WHQL testing, including validation that the driver correctly provides a version number as described in this topic.


Data Type Mapping between Windows 2000/XP and Windows 9x/98/ME

With DirectX, different functions, structures and enumerations may be required depending on whether you are writing a Windows 9x/98/Me or a Windows 2000/XP device driver. The dx95type.h file provides the correct mapping between operating systems. Tables in this section list these differences.

The following table lists the equivalent data structures:

Windows 2000/XP | Windows 9x/98/ME
D3DNTHALDEVICEDESC_V1 | D3DDEVICEDESC_V1
PDD_SURFACE_LOCAL | LPDDRAWI_DDRAWSURFACE_LCL
PDD_SURFACE_MORE | LPDDRAWI_DDRAWSURFACE_MORE
PDD_SURFACE_GLOBAL | LPDDRAWI_DDRAWSURFACE_GBL
PDD_DIRECTDRAW_GLOBAL | LPDDRAWI_DIRECTDRAW_GBL
PDD_ATTACHLIST | LPATTACHLIST
DDNTCORECAPS | DDCORECAPS
PDDNTCORECAPS | LPDDCORECAPS
DD_HALINFO | DDHALINFO
PDD_HALINFO | LPDDHALINFO
DD_MORECAPS | DDMORECAPS
PDD_MORECAPS | LPDDMORECAPS

The following table lists the equivalent HAL data structures:

Windows 2000/XP | Windows 9x/98/ME
PDD_CREATEPALETTEDATA | LPDDHAL_CREATEPALETTEDATA
PDD_CREATESURFACEDATA | LPDDHAL_CREATESURFACEDATA
PDD_CREATESURFACEEXDATA | LPDDHAL_CREATESURFACEEXDATA
PDD_CANCREATESURFACEDATA | LPDDHAL_CANCREATESURFACEDATA
PDD_WAITFORVERTICALBLANKDATA | LPDDHAL_WAITFORVERTICALBLANKDATA
PDD_DESTROYDRIVERDATA | LPDDHAL_DESTROYDRIVERDATA
PDD_SETMODEDATA | LPDDHAL_SETMODEDATA
PDD_DRVSETCOLORKEYDATA | LPDDHAL_DRVSETCOLORKEYDATA
PDD_GETSCANLINEDATA | LPDDHAL_GETSCANLINEDATA
PDD_MAPMEMORYDATA | LPDDHAL_MAPMEMORYDATA
PDD_SETEXCLUSIVEMODEDATA | LPDDHAL_SETEXCLUSIVEMODEDATA
PDD_FLIPTOGDISURFACEDATA | LPDDHAL_FLIPTOGDISURFACEDATA
PDD_UPDATENONLOCALHEAPDATA | LPDDHAL_UPDATENONLOCALHEAPDATA
PDD_GETHEAPALIGNMENTDATA | LPDDHAL_GETHEAPALIGNMENTDATA
DD_CREATEPALETTEDATA | DDHAL_CREATEPALETTEDATA
DD_CREATESURFACEDATA | DDHAL_CREATESURFACEDATA
DD_CREATESURFACEEXDATA | DDHAL_CREATESURFACEEXDATA
DD_CANCREATESURFACEDATA | DDHAL_CANCREATESURFACEDATA
DD_WAITFORVERTICALBLANKDATA | DDHAL_WAITFORVERTICALBLANKDATA
DD_DRVSETCOLORKEYDATA | DDHAL_DRVSETCOLORKEYDATA
DD_GETSCANLINEDATA | DDHAL_GETSCANLINEDATA
DD_MAPMEMORYDATA | DDHAL_MAPMEMORYDATA
DD_SETEXCLUSIVEMODEDATA | DDHAL_SETEXCLUSIVEMODEDATA
DD_FLIPTOGDISURFACEDATA | DDHAL_FLIPTOGDISURFACEDATA
DD_UPDATENONLOCALHEAPDATA | DDHAL_UPDATENONLOCALHEAPDATA
PDD_DESTROYPALETTEDATA | LPDDHAL_DESTROYPALETTEDATA
PDD_SETENTRIESDATA | LPDDHAL_SETENTRIESDATA
DD_DESTROYPALETTEDATA | DDHAL_DESTROYPALETTEDATA
DD_SETENTRIESDATA | DDHAL_SETENTRIESDATA
PDD_BLTDATA | LPDDHAL_BLTDATA
PDD_LOCKDATA | LPDDHAL_LOCKDATA
PDD_UNLOCKDATA | LPDDHAL_UNLOCKDATA
PDD_UPDATEOVERLAYDATA | LPDDHAL_UPDATEOVERLAYDATA
PDD_SETOVERLAYPOSITIONDATA | LPDDHAL_SETOVERLAYPOSITIONDATA
PDD_SETPALETTEDATA | LPDDHAL_SETPALETTEDATA
PDD_FLIPDATA | LPDDHAL_FLIPDATA
PDD_DESTROYSURFACEDATA | LPDDHAL_DESTROYSURFACEDATA
PDD_SETCLIPLISTDATA | LPDDHAL_SETCLIPLISTDATA
PDD_ADDATTACHEDSURFACEDATA | LPDDHAL_ADDATTACHEDSURFACEDATA
PDD_SETCOLORKEYDATA | LPDDHAL_SETCOLORKEYDATA
PDD_GETBLTSTATUSDATA | LPDDHAL_GETBLTSTATUSDATA
PDD_GETFLIPSTATUSDATA | LPDDHAL_GETFLIPSTATUSDATA
PDD_GETAVAILDRIVERMEMORYDATA | LPDDHAL_GETAVAILDRIVERMEMORYDATA
PDD_GETDRIVERINFODATA | LPDDHAL_GETDRIVERINFODATA
PDD_GETDRIVERSTATEDATA | LPDDHAL_GETDRIVERSTATEDATA
PDD_DESTROYDDLOCALDATA | LPDDHAL_DESTROYDDLOCALDATA
DD_BLTDATA | DDHAL_BLTDATA
DD_LOCKDATA | DDHAL_LOCKDATA
DD_UNLOCKDATA | DDHAL_UNLOCKDATA
DD_UPDATEOVERLAYDATA | DDHAL_UPDATEOVERLAYDATA
DD_SETOVERLAYPOSITIONDATA | DDHAL_SETOVERLAYPOSITIONDATA
DD_SETPALETTEDATA | DDHAL_SETPALETTEDATA
DD_FLIPDATA | DDHAL_FLIPDATA
DD_DESTROYSURFACEDATA | DDHAL_DESTROYSURFACEDATA
DD_SETCLIPLISTDATA | DDHAL_SETCLIPLISTDATA
DD_ADDATTACHEDSURFACEDATA | DDHAL_ADDATTACHEDSURFACEDATA
DD_SETCOLORKEYDATA | DDHAL_SETCOLORKEYDATA
DD_GETBLTSTATUSDATA | DDHAL_GETBLTSTATUSDATA
DD_GETFLIPSTATUSDATA | DDHAL_GETFLIPSTATUSDATA
DD_GETAVAILDRIVERMEMORYDATA | DDHAL_GETAVAILDRIVERMEMORYDATA
DD_GETDRIVERINFODATA | DDHAL_GETDRIVERINFODATA
DD_GETDRIVERSTATEDATA | DDHAL_GETDRIVERSTATEDATA
DD_DESTROYDDLOCALDATA | DDHAL_DESTROYDDLOCALDATA
PDD_CANCREATEVPORTDATA | LPDDHAL_CANCREATEVPORTDATA
PDD_CREATEVPORTDATA | LPDDHAL_CREATEVPORTDATA
PDD_FLIPVPORTDATA | LPDDHAL_FLIPVPORTDATA
PDD_GETVPORTCONNECTDATA | LPDDHAL_GETVPORTCONNECTDATA
PDD_GETVPORTBANDWIDTHDATA | LPDDHAL_GETVPORTBANDWIDTHDATA
PDD_GETVPORTINPUTFORMATDATA | LPDDHAL_GETVPORTINPUTFORMATDATA
PDD_GETVPORTOUTPUTFORMATDATA | LPDDHAL_GETVPORTOUTPUTFORMATDATA
PDD_GETVPORTFIELDDATA | LPDDHAL_GETVPORTFIELDDATA
PDD_GETVPORTLINEDATA | LPDDHAL_GETVPORTLINEDATA
PDD_DESTROYVPORTDATA | LPDDHAL_DESTROYVPORTDATA
PDD_GETVPORTFLIPSTATUSDATA | LPDDHAL_GETVPORTFLIPSTATUSDATA
PDD_UPDATEVPORTDATA | LPDDHAL_UPDATEVPORTDATA
PDD_WAITFORVPORTSYNCDATA | LPDDHAL_WAITFORVPORTSYNCDATA
PDD_GETVPORTSIGNALDATA | LPDDHAL_GETVPORTSIGNALDATA
PDD_VPORTCOLORDATA | LPDDHAL_VPORTCOLORDATA
DD_CANCREATEVPORTDATA | DDHAL_CANCREATEVPORTDATA
DD_CREATEVPORTDATA | DDHAL_CREATEVPORTDATA
DD_FLIPVPORTDATA | DDHAL_FLIPVPORTDATA
DD_GETVPORTCONNECTDATA | DDHAL_GETVPORTCONNECTDATA
DD_GETVPORTBANDWIDTHDATA | DDHAL_GETVPORTBANDWIDTHDATA
DD_GETVPORTINPUTFORMATDATA | DDHAL_GETVPORTINPUTFORMATDATA
DD_GETVPORTOUTPUTFORMATDATA | DDHAL_GETVPORTOUTPUTFORMATDATA
DD_GETVPORTFIELDDATA | DDHAL_GETVPORTFIELDDATA
DD_GETVPORTLINEDATA | DDHAL_GETVPORTLINEDATA
DD_DESTROYVPORTDATA | DDHAL_DESTROYVPORTDATA
DD_GETVPORTFLIPSTATUSDATA | DDHAL_GETVPORTFLIPSTATUSDATA
DD_UPDATEVPORTDATA | DDHAL_UPDATEVPORTDATA
DD_WAITFORVPORTSYNCDATA | DDHAL_WAITFORVPORTSYNCDATA
DD_GETVPORTSIGNALDATA | DDHAL_GETVPORTSIGNALDATA
DD_VPORTCOLORDATA | DDHAL_VPORTCOLORDATA
PDD_COLORCONTROLDATA | LPDDHAL_COLORCONTROLDATA
DD_COLORCONTROLDATA | DDHAL_COLORCONTROLDATA
PDD_SYNCSURFACEDATA | LPDDHAL_SYNCSURFACEDATA
PDD_SYNCVIDEOPORTDATA | LPDDHAL_SYNCVIDEOPORTDATA
DD_SYNCSURFACEDATA | DDHAL_SYNCSURFACEDATA
DD_SYNCVIDEOPORTDATA | DDHAL_SYNCVIDEOPORTDATA
PDD_GETMOCOMPGUIDSDATA | LPDDHAL_GETMOCOMPGUIDSDATA
PDD_GETMOCOMPFORMATSDATA | LPDDHAL_GETMOCOMPFORMATSDATA
PDD_CREATEMOCOMPDATA | LPDDHAL_CREATEMOCOMPDATA
PDD_GETMOCOMPCOMPBUFFDATA | LPDDHAL_GETMOCOMPCOMPBUFFDATA
PDD_GETINTERNALMOCOMPDATA | LPDDHAL_GETINTERNALMOCOMPDATA
PDD_BEGINMOCOMPFRAMEDATA | LPDDHAL_BEGINMOCOMPFRAMEDATA
PDD_ENDMOCOMPFRAMEDATA | LPDDHAL_ENDMOCOMPFRAMEDATA
PDD_RENDERMOCOMPDATA | LPDDHAL_RENDERMOCOMPDATA
PDD_QUERYMOCOMPSTATUSDATA | LPDDHAL_QUERYMOCOMPSTATUSDATA
PDD_DESTROYMOCOMPDATA | LPDDHAL_DESTROYMOCOMPDATA
DD_GETMOCOMPGUIDSDATA | DDHAL_GETMOCOMPGUIDSDATA
DD_GETMOCOMPFORMATSDATA | DDHAL_GETMOCOMPFORMATSDATA
DD_CREATEMOCOMPDATA | DDHAL_CREATEMOCOMPDATA
DD_GETMOCOMPCOMPBUFFDATA | DDHAL_GETMOCOMPCOMPBUFFDATA
DD_GETINTERNALMOCOMPDATA | DDHAL_GETINTERNALMOCOMPDATA
DD_BEGINMOCOMPFRAMEDATA | DDHAL_BEGINMOCOMPFRAMEDATA
DD_ENDMOCOMPFRAMEDATA | DDHAL_ENDMOCOMPFRAMEDATA
DD_RENDERMOCOMPDATA | DDHAL_RENDERMOCOMPDATA
DD_QUERYMOCOMPSTATUSDATA | DDHAL_QUERYMOCOMPSTATUSDATA
DD_DESTROYMOCOMPDATA | DDHAL_DESTROYMOCOMPDATA

The following table lists the equivalent Win 9x DirectDraw HAL callback function data structures:

Windows 2000/XP | Windows 9x/98/ME
PDD_SETCOLORKEY | LPDDHAL_SETCOLORKEY
PDD_CANCREATESURFACE | LPDDHAL_CANCREATESURFACE
PDD_WAITFORVERTICALBLANK | LPDDHAL_WAITFORVERTICALBLANK
PDD_CREATESURFACE | LPDDHAL_CREATESURFACE
PDD_DESTROYDRIVER | LPDDHAL_DESTROYDRIVER
PDD_SETMODE | LPDDHAL_SETMODE
PDD_CREATEPALETTE | LPDDHAL_CREATEPALETTE
PDD_GETSCANLINE | LPDDHAL_GETSCANLINE
PDD_MAPMEMORY | LPDDHAL_MAPMEMORY
PDD_GETAVAILDRIVERMEMORY | LPDDHAL_GETAVAILDRIVERMEMORY
PDD_GETDRIVERINFODATA | LPDDHAL_GETDRIVERINFODATA
PDD_SYNCSURFACEDATA | LPDDHAL_SYNCSURFACEDATA
PDD_SYNCVIDEOPORTDATA | LPDDHAL_SYNCVIDEOPORTDATA
PDD_SETEXCLUSIVEMODE | LPDDHAL_SETEXCLUSIVEMODE
PDD_FLIPTOGDISURFACE | LPDDHAL_FLIPTOGDISURFACE
PDD_ALPHABLT | LPDDHAL_ALPHABLT
PDD_CREATESURFACEEX | LPDDHAL_CREATESURFACEEX
PDD_GETDRIVERSTATE | LPDDHAL_GETDRIVERSTATE
PDD_PALCB_DESTROYPALETTE | LPDDHALPALCB_DESTROYPALETTE
PDD_PALCB_SETENTRIES | LPDDHALPALCB_SETENTRIES
PDD_SURFCB_LOCK | LPDDHALSURFCB_LOCK
PDD_SURFCB_UNLOCK | LPDDHALSURFCB_UNLOCK
PDD_SURFCB_BLT | LPDDHALSURFCB_BLT
PDD_SURFCB_UPDATEOVERLAY | LPDDHALSURFCB_UPDATEOVERLAY
PDD_SURFCB_SETOVERLAYPOSITION | LPDDHALSURFCB_SETOVERLAYPOSITION
PDD_SURFCB_SETPALETTE | LPDDHALSURFCB_SETPALETTE
PDD_SURFCB_FLIP | LPDDHALSURFCB_FLIP
PDD_SURFCB_DESTROYSURFACE | LPDDHALSURFCB_DESTROYSURFACE
PDD_SURFCB_SETCLIPLIST | LPDDHALSURFCB_SETCLIPLIST
PDD_SURFCB_ADDATTACHEDSURFACE | LPDDHALSURFCB_ADDATTACHEDSURFACE
PDD_SURFCB_SETCOLORKEY | LPDDHALSURFCB_SETCOLORKEY
PDD_SURFCB_GETBLTSTATUS | LPDDHALSURFCB_GETBLTSTATUS
PDD_SURFCB_GETFLIPSTATUS | LPDDHALSURFCB_GETFLIPSTATUS
PDD_VPORTCB_CANCREATEVIDEOPORT | LPDDHALVPORTCB_CANCREATEVIDEOPORT
PDD_VPORTCB_CREATEVIDEOPORT | LPDDHALVPORTCB_CREATEVIDEOPORT
PDD_VPORTCB_FLIP | LPDDHALVPORTCB_FLIP
PDD_VPORTCB_GETBANDWIDTH | LPDDHALVPORTCB_GETBANDWIDTH
PDD_VPORTCB_GETINPUTFORMATS | LPDDHALVPORTCB_GETINPUTFORMATS
PDD_VPORTCB_GETOUTPUTFORMATS | LPDDHALVPORTCB_GETOUTPUTFORMATS
PDD_VPORTCB_GETFIELD | LPDDHALVPORTCB_GETFIELD
PDD_VPORTCB_GETLINE | LPDDHALVPORTCB_GETLINE
PDD_VPORTCB_GETVPORTCONNECT | LPDDHALVPORTCB_GETVPORTCONNECT
PDD_VPORTCB_DESTROYVPORT | LPDDHALVPORTCB_DESTROYVPORT
PDD_VPORTCB_GETFLIPSTATUS | LPDDHALVPORTCB_GETFLIPSTATUS
PDD_VPORTCB_UPDATE | LPDDHALVPORTCB_UPDATE
PDD_VPORTCB_WAITFORSYNC | LPDDHALVPORTCB_WAITFORSYNC
PDD_VPORTCB_GETSIGNALSTATUS | LPDDHALVPORTCB_GETSIGNALSTATUS
PDD_VPORTCB_COLORCONTROL | LPDDHALVPORTCB_COLORCONTROL
PDD_MOCOMPCB_GETGUIDS | LPDDHALMOCOMPCB_GETGUIDS
PDD_MOCOMPCB_GETFORMATS | LPDDHALMOCOMPCB_GETFORMATS
PDD_MOCOMPCB_CREATE | LPDDHALMOCOMPCB_CREATE
PDD_MOCOMPCB_GETCOMPBUFFINFO | LPDDHALMOCOMPCB_GETCOMPBUFFINFO
PDD_MOCOMPCB_GETINTERNALINFO | LPDDHALMOCOMPCB_GETINTERNALINFO
PDD_MOCOMPCB_BEGINFRAME | LPDDHALMOCOMPCB_BEGINFRAME
PDD_MOCOMPCB_ENDFRAME | LPDDHALMOCOMPCB_ENDFRAME
PDD_MOCOMPCB_RENDER | LPDDHALMOCOMPCB_RENDER
PDD_MOCOMPCB_QUERYSTATUS | LPDDHALMOCOMPCB_QUERYSTATUS
PDD_MOCOMPCB_DESTROY | PDDHALMOCOMPCB_DESTROY
DD_CALLBACKS | DDHAL_DDCALLBACKS
DD_PALETTECALLBACKS | DDHAL_DDPALETTECALLBACKS
DD_SURFACECALLBACKS | DDHAL_DDSURFACECALLBACKS
DD_VIDEOPORTCALLBACKS | DDHAL_DDVIDEOPORTCALLBACKS
DD_COLORCONTROLCALLBACKS | DDHAL_DDCOLORCONTROLCALLBACKS
DD_KERNELCALLBACKS | DDHAL_DDKERNELCALLBACKS
DD_MOTIONCOMPCALLBACKS | DDHAL_DDMOTIONCOMPCALLBACKS
DD_MISCELLANEOUS2CALLBACKS | DDHAL_DDMISCELLANEOUS2CALLBACKS
DD_D3DBUFCALLBACKS | DDHAL_D3DBUFCALLBACKS
DD_NTCALLBACKS | DDHAL_DDNTCALLBACKS
PDD_CALLBACKS | LPDDHAL_DDCALLBACKS
PDD_PALETTECALLBACKS | LPDDHAL_DDPALETTECALLBACKS
PDD_SURFACECALLBACKS | LPDDHAL_DDSURFACECALLBACKS
PDD_VIDEOPORTCALLBACKS | LPDDHAL_DDVIDEOPORTCALLBACKS
PDD_COLORCONTROLCALLBACKS | LPDDHAL_DDCOLORCONTROLCALLBACKS
PDD_KERNELCALLBACKS | LPDDHAL_DDKERNELCALLBACKS
PDD_MOTIONCOMPCALLBACKS | LPDDHAL_DDMOTIONCOMPCALLBACKS
PDD_MISCELLANEOUS2CALLBACKS | LPDDHAL_DDMISCELLANEOUS2CALLBACKS
PDD_D3DBUFCALLBACKS | LPDDHAL_D3DBUFCALLBACKS
PDD_NTCALLBACKS | LPDDHAL_DDNTCALLBACKS

The following table lists the equivalent Win 9x Direct3D HAL callback functions:

Windows 2000/XP | Windows 9x/98/ME
D3DNTHAL_CALLBACKS | D3DHAL_CALLBACKS
D3DNTHAL_GLOBALDRIVERDATA | D3DHAL_GLOBALDRIVERDATA
D3DNTHAL_CONTEXTCREATEDATA | D3DHAL_CONTEXTCREATEDATA
D3DNTHAL_CONTEXTDESTROYDATA | D3DHAL_CONTEXTDESTROYDATA
D3DNTHAL_CONTEXTDESTROYALLDATA | D3DHAL_CONTEXTDESTROYALLDATA
D3DNTHAL_SCENECAPTUREDATA | D3DHAL_SCENECAPTUREDATA
D3DNTHAL_TEXTURECREATEDATA | D3DHAL_TEXTURECREATEDATA
D3DNTHAL_TEXTUREDESTROYDATA | D3DHAL_TEXTUREDESTROYDATA
D3DNTHAL_TEXTURESWAPDATA | D3DHAL_TEXTURESWAPDATA
D3DNTHAL_TEXTUREGETSURFDATA | D3DHAL_TEXTUREGETSURFDATA
D3DNTHAL_CALLBACKS2 | D3DHAL_CALLBACKS2
D3DNTHAL_SETRENDERTARGETDATA | D3DHAL_SETRENDERTARGETDATA
D3DNTHAL_CALLBACKS3 | D3DHAL_CALLBACKS3
D3DNTHAL_CLEAR2DATA | D3DHAL_CLEAR2DATA
D3DNTHAL_VALIDATETEXTURESTAGESTATEDATA | D3DHAL_VALIDATETEXTURESTAGESTATEDATA
D3DNTHAL_CB32_DRAWPRIMITIVES2 | D3DHAL3_CB32_DRAWPRIMITIVES2
D3DNTHAL_DRAWPRIMITIVES2DATA | D3DHAL_DRAWPRIMITIVES2DATA
D3DNTHAL_D3DEXTENDEDCAPS | D3DHAL_D3DEXTENDEDCAPS
LPD3DNTHAL_CALLBACKS | LPD3DHAL_CALLBACKS
LPD3DNTHAL_GLOBALDRIVERDATA | LPD3DHAL_GLOBALDRIVERDATA
LPD3DNTHAL_CONTEXTCREATEDATA | LPD3DHAL_CONTEXTCREATEDATA
LPD3DNTHAL_CONTEXTDESTROYDATA | LPD3DHAL_CONTEXTDESTROYDATA
LPD3DNTHAL_CONTEXTDESTROYALLDATA | LPD3DHAL_CONTEXTDESTROYALLDATA
LPD3DNTHAL_SCENECAPTUREDATA | LPD3DHAL_SCENECAPTUREDATA
LPD3DNTHAL_TEXTURECREATEDATA | LPD3DHAL_TEXTURECREATEDATA
LPD3DNTHAL_TEXTUREDESTROYDATA | LPD3DHAL_TEXTUREDESTROYDATA
LPD3DNTHAL_TEXTURESWAPDATA | LPD3DHAL_TEXTURESWAPDATA
LPD3DNTHAL_TEXTUREGETSURFDATA | LPD3DHAL_TEXTUREGETSURFDATA
LPD3DNTHAL_CALLBACKS2 | LPD3DHAL_CALLBACKS2
LPD3DNTHAL_SETRENDERTARGETDATA | LPD3DHAL_SETRENDERTARGETDATA
LPD3DNTHAL_CALLBACKS3 | LPD3DHAL_CALLBACKS3
LPD3DNTHAL_CLEAR2DATA | LPD3DHAL_CLEAR2DATA
LPD3DNTHAL_VALIDATETEXTURESTAGESTATEDATA | LPD3DHAL_VALIDATETEXTURESTAGESTATEDATA
LPD3DNTHAL_DRAWPRIMITIVES2DATA | LPD3DHAL_DRAWPRIMITIVES2DATA
LPD3DNTHAL_D3DEXTENDEDCAPS | LPD3DHAL_D3DEXTENDEDCAPS
D3DHAL2_CB32_SETRENDERTARGET | D3DNTHAL2_CB32_SETRENDERTARGET

The following table lists the equivalent Win 9x Direct3D enumerations:

Windows 2000/XP | Windows 9x/98/ME
D3DNTHAL_CONTEXT_BAD | D3DHAL_CONTEXT_BAD
D3DNTHAL_OUTOFCONTEXTS | D3DHAL_OUTOFCONTEXTS
D3DNTHALSTATE_GET_RENDER | D3DHALSTATE_GET_RENDER
D3DNTHAL_SCENE_CAPTURE_START | D3DHAL_SCENE_CAPTURE_START
D3DNTHAL_SCENE_CAPTURE_END | D3DHAL_SCENE_CAPTURE_END
D3DNTHAL_CB32_CLEAR2 | D3DHAL3_CB32_CLEAR2
D3DNTHAL_CB32_RESERVED | D3DHAL3_CB32_RESERVED
D3DNTHAL_CB32_VALIDATETEXTURESTAGESTATE | D3DHAL3_CB32_VALIDATETEXTURESTAGESTATE

The following table lists the equivalent command buffer Win 9x Direct3D:

Windows 2000/XP | Windows 9x/98/ME
D3DNTHAL_DP2COMMAND | D3DHAL_DP2COMMAND
LPDNT3DHAL_DP2COMMAND | LPD3DHAL_DP2COMMAND
D3DNTHAL_DP2OPERATION | D3DHAL_DP2OPERATION
D3DNTHAL_DP2POINTS | D3DHAL_DP2POINTS
D3DNTHAL_DP2LINELIST | D3DHAL_DP2LINELIST
D3DNTHAL_DP2INDEXEDLINELIST | D3DHAL_DP2INDEXEDLINELIST
D3DNTHAL_DP2LINESTRIP | D3DHAL_DP2LINESTRIP
D3DNTHAL_DP2INDEXEDLINESTRIP | D3DHAL_DP2INDEXEDLINESTRIP
D3DNTHAL_DP2TRIANGLELIST | D3DHAL_DP2TRIANGLELIST
D3DNTHAL_DP2INDEXEDTRIANGLELIST | D3DHAL_DP2INDEXEDTRIANGLELIST
D3DNTHAL_DP2INDEXEDTRIANGLELIST2 | D3DHAL_DP2INDEXEDTRIANGLELIST2
D3DNTHAL_DP2TRIANGLESTRIP | D3DHAL_DP2TRIANGLESTRIP
D3DNTHAL_DP2INDEXEDTRIANGLESTRIP | D3DHAL_DP2INDEXEDTRIANGLESTRIP
D3DNTHAL_DP2TRIANGLEFAN | D3DHAL_DP2TRIANGLEFAN
D3DNTHAL_DP2INDEXEDTRIANGLEFAN | D3DHAL_DP2INDEXEDTRIANGLEFAN
D3DNTHAL_DP2RENDERSTATE | D3DHAL_DP2RENDERSTATE
D3DNTHAL_DP2TEXTURESTAGESTATE | D3DHAL_DP2TEXTURESTAGESTATE
D3DNTHAL_DP2TRIANGLEFAN_IMM | D3DHAL_DP2TRIANGLEFAN_IMM
D3DNTHAL_DP2STARTVERTEX | D3DHAL_DP2STARTVERTEX
D3DNTHAL_DP2VIEWPORTINFO | D3DHAL_DP2VIEWPORTINFO
D3DNTHAL_DP2WINFO | D3DHAL_DP2WINFO
D3DNTHAL_DP2SETPALETTE | D3DHAL_DP2SETPALETTE
D3DNTHAL_DP2UPDATEPALETTE | D3DHAL_DP2UPDATEPALETTE
D3DNTHAL_DP2ZRANGE | D3DHAL_DP2ZRANGE
D3DNTHAL_DP2SETMATERIAL | D3DHAL_DP2SETMATERIAL
D3DNTHAL_DP2SETLIGHT | D3DHAL_DP2SETLIGHT
D3DNTHAL_DP2SETCLIPPLANE | D3DHAL_DP2SETCLIPPLANE
D3DNTHAL_DP2CREATELIGHT | D3DHAL_DP2CREATELIGHT
D3DNTHAL_DP2SETTRANSFORM | D3DHAL_DP2SETTRANSFORM
D3DNTHAL_DP2EXT | D3DHAL_DP2EXT
D3DNTHAL_DP2TEXBLT | D3DHAL_DP2TEXBLT
D3DNTHAL_DP2STATESET | D3DHAL_DP2STATESET
D3DNTHAL_DP2SETPRIORITY | D3DHAL_DP2SETPRIORITY
D3DNTHAL_DP2SETRENDERTARGET | D3DHAL_DP2SETRENDERTARGET
D3DNTHAL_DP2CLEAR | D3DHAL_DP2CLEAR
D3DNTHAL_DP2SETTEXLOD | D3DHAL_DP2SETTEXLOD

The following table lists the equivalent Win 9x Direct3D enumerations:

Windows 2000/XP | Windows 9x/98/ME
D3DNTDP2OP_POINTS | D3DDP2OP_POINTS
D3DNTDP2OP_INDEXEDLINELIST | D3DDP2OP_INDEXEDLINELIST
D3DNTDP2OP_INDEXEDLINELIST2 | D3DDP2OP_INDEXEDLINELIST2
D3DNTDP2OP_INDEXEDTRIANGLELIST | D3DDP2OP_INDEXEDTRIANGLELIST
D3DNTDP2OP_INDEXEDTRIANGLELIST2 | D3DDP2OP_INDEXEDTRIANGLELIST2
D3DNTDP2OP_RENDERSTATE | D3DDP2OP_RENDERSTATE
D3DNTDP2OP_LINELIST | D3DDP2OP_LINELIST
D3DNTDP2OP_LINESTRIP | D3DDP2OP_LINESTRIP
D3DNTDP2OP_INDEXEDLINESTRIP | D3DDP2OP_INDEXEDLINESTRIP
D3DNTDP2OP_TRIANGLELIST | D3DDP2OP_TRIANGLELIST
D3DNTDP2OP_TRIANGLESTRIP | D3DDP2OP_TRIANGLESTRIP
D3DNTDP2OP_INDEXEDTRIANGLESTRIP | D3DDP2OP_INDEXEDTRIANGLESTRIP
D3DNTDP2OP_TRIANGLEFAN | D3DDP2OP_TRIANGLEFAN
D3DNTDP2OP_INDEXEDTRIANGLEFAN | D3DDP2OP_INDEXEDTRIANGLEFAN
D3DNTDP2OP_TRIANGLEFAN_IMM | D3DDP2OP_TRIANGLEFAN_IMM
D3DNTDP2OP_LINELIST_IMM | D3DDP2OP_LINELIST_IMM
D3DNTDP2OP_TEXTURESTAGESTATE | D3DDP2OP_TEXTURESTAGESTATE
D3DNTDP2OP_VIEWPORTINFO | D3DDP2OP_VIEWPORTINFO
D3DNTDP2OP_WINFO | D3DDP2OP_WINFO
D3DNTDP2OP_SETPALETTE | D3DDP2OP_SETPALETTE
D3DNTDP2OP_UPDATEPALETTE | D3DDP2OP_UPDATEPALETTE
D3DNTDP2OP_ZRANGE | D3DDP2OP_ZRANGE
D3DNTDP2OP_SETMATERIAL | D3DDP2OP_SETMATERIAL
D3DNTDP2OP_SETLIGHT | D3DDP2OP_SETLIGHT
D3DNTDP2OP_CREATELIGHT | D3DDP2OP_CREATELIGHT
D3DNTDP2OP_SETTRANSFORM | D3DDP2OP_SETTRANSFORM
D3DNTDP2OP_EXT | D3DDP2OP_EXT
D3DNTDP2OP_TEXBLT | D3DDP2OP_TEXBLT
D3DNTDP2OP_STATESET | D3DDP2OP_STATESET
D3DNTDP2OP_SETPRIORITY | D3DDP2OP_SETPRIORITY
D3DNTDP2OP_SETRENDERTARGET | D3DDP2OP_SETRENDERTARGET
D3DNTDP2OP_CLEAR | D3DDP2OP_CLEAR
D3DNTDP2OP_SETTEXLOD | D3DDP2OP_SETTEXLOD
D3DNTDP2OP_SETCLIPPLANE | D3DDP2OP_SETCLIPPLANE

The following table lists the equivalent Win 9x Direct3D flags:

Windows 2000/XP | Windows 9x/98/ME
D3DNTERR_COMMAND_UNPARSED | D3DERR_COMMAND_UNPARSED
D3DNTHALDP2_USERMEMVERTICES | D3DHALDP2_USERMEMVERTICES
D3DNTHALDP2_EXECUTEBUFFER | D3DHALDP2_EXECUTEBUFFER
D3DNTHALDP2_SWAPVERTEXBUFFER | D3DHALDP2_SWAPVERTEXBUFFER
D3DNTHALDP2_SWAPCOMMANDBUFFER | D3DHALDP2_SWAPCOMMANDBUFFER
D3DNTHALDP2_REQVERTEXBUFSIZE | D3DHALDP2_REQVERTEXBUFSIZE
D3DNTHALDP2_REQCOMMANDBUFSIZE | D3DHALDP2_REQCOMMANDBUFSIZE
D3DNTHALDP2_VIDMEMVERTEXBUF | D3DHALDP2_VIDMEMVERTEXBUF
D3DNTHALDP2_VIDMEMCOMMANDBUF | D3DHALDP2_VIDMEMCOMMANDBUF

The following table lists the equivalent Win 9x Direct3D enumerations:

Windows 2000/XP | Windows 9x/98/ME
PFND3DNTPARSEUNKNOWNCOMMAND | PFND3DPARSEUNKNOWNCOMMAND
D3DNTDP2OP_CREATEVERTEXSHADER | D3DDP2OP_CREATEVERTEXSHADER
D3DNTDP2OP_DELETEVERTEXSHADER | D3DDP2OP_DELETEVERTEXSHADER
D3DNTDP2OP_SETVERTEXSHADER | D3DDP2OP_SETVERTEXSHADER
D3DNTDP2OP_SETVERTEXSHADERCONST | D3DDP2OP_SETVERTEXSHADERCONST
D3DNTDP2OP_SETSTREAMSOURCE | D3DDP2OP_SETSTREAMSOURCE
D3DNTDP2OP_SETSTREAMSOURCEUM | D3DDP2OP_SETSTREAMSOURCEUM
D3DNTDP2OP_SETINDICES | D3DDP2OP_SETINDICES
D3DNTDP2OP_DRAWPRIMITIVE | D3DDP2OP_DRAWPRIMITIVE
D3DNTDP2OP_DRAWINDEXEDPRIMITIVE | D3DDP2OP_DRAWINDEXEDPRIMITIVE
D3DNTDP2OP_CREATEPIXELSHADER | D3DDP2OP_CREATEPIXELSHADER
D3DNTDP2OP_DELETEPIXELSHADER | D3DDP2OP_DELETEPIXELSHADER
D3DNTDP2OP_SETPIXELSHADER | D3DDP2OP_SETPIXELSHADER
D3DNTDP2OP_SETPIXELSHADERCONST | D3DDP2OP_SETPIXELSHADERCONST
D3DNTDP2OP_CLIPPEDTRIANGLEFAN | D3DDP2OP_CLIPPEDTRIANGLEFAN
D3DNTDP2OP_DRAWPRIMITIVE2 | D3DDP2OP_DRAWPRIMITIVE2
D3DNTDP2OP_DRAWINDEXEDPRIMITIVE2 | D3DDP2OP_DRAWINDEXEDPRIMITIVE2
D3DNTDP2OP_DRAWRECTPATCH | D3DDP2OP_DRAWRECTPATCH
D3DNTDP2OP_DRAWTRIPATCH | D3DDP2OP_DRAWTRIPATCH
D3DNTDP2OP_VOLUMEBLT | D3DDP2OP_VOLUMEBLT
D3DNTDP2OP_BUFFERBLT | D3DDP2OP_BUFFERBLT
D3DNTDP2OP_MULTIPLYTRANSFORM | D3DDP2OP_MULTIPLYTRANSFORM
D3DNTDP2OP_ADDDIRTYRECT | D3DDP2OP_ADDDIRTYRECT
D3DNTDP2OP_ADDDIRTYBOX | D3DDP2OP_ADDDIRTYBOX
D3DNTHAL_STATESETCREATE | D3DHAL_STATESETCREATE
D3DNTCLEAR_COMPUTERECTS | D3DCLEAR_COMPUTERECTS

The following table lists the equivalent Win 9x Direct3D command buffer structures:

Windows 2000/XP | Windows 9x/98/ME
D3DNTHAL_DP2MULTIPLYTRANSFORM | D3DHAL_DP2MULTIPLYTRANSFORM
LPD3DNTHAL_DP2MULTIPLYTRANSFORM | LPD3DHAL_DP2MULTIPLYTRANSFORM
D3DNTHAL_DP2VERTEXSHADER | D3DHAL_DP2VERTEXSHADER
LPD3DNTHAL_DP2VERTEXSHADER | LPD3DHAL_DP2VERTEXSHADER
D3DNTHAL_DP2CREATEVERTEXSHADER | D3DHAL_DP2CREATEVERTEXSHADER
LPD3DNTHAL_DP2CREATEVERTEXSHADER | LPD3DHAL_DP2CREATEVERTEXSHADER
D3DNTHAL_DP2SETVERTEXSHADERCONST | D3DHAL_DP2SETVERTEXSHADERCONST
LPD3DNTHAL_DP2SETVERTEXSHADERCONST | LPD3DHAL_DP2SETVERTEXSHADERCONST
D3DNTHAL_DP2SETSTREAMSOURCE | D3DHAL_DP2SETSTREAMSOURCE
LPD3DNTHAL_DP2SETSTREAMSOURCE | LPD3DHAL_DP2SETSTREAMSOURCE
D3DNTHAL_DP2SETSTREAMSOURCEUM | D3DHAL_DP2SETSTREAMSOURCEUM
LPD3DNTHAL_DP2SETSTREAMSOURCEUM | LPD3DHAL_DP2SETSTREAMSOURCEUM
D3DNTHAL_DP2SETINDICES | D3DHAL_DP2SETINDICES
LPD3DNTHAL_DP2SETINDICES | LPD3DHAL_DP2SETINDICES
D3DNTHAL_DP2DRAWPRIMITIVE | D3DHAL_DP2DRAWPRIMITIVE
LPD3DNTHAL_DP2DRAWPRIMITIVE | LPD3DHAL_DP2DRAWPRIMITIVE
D3DNTHAL_DP2DRAWINDEXEDPRIMITIVE | D3DHAL_DP2DRAWINDEXEDPRIMITIVE
LPD3DNTHAL_DP2DRAWINDEXEDPRIMITIVE | LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE
D3DNTHAL_CLIPPEDTRIANGLEFAN | D3DHAL_CLIPPEDTRIANGLEFAN
LPD3DNTHAL_CLIPPEDTRIANGLEFAN | LPD3DHAL_CLIPPEDTRIANGLEFAN
D3DNTHAL_DP2DRAWPRIMITIVE2 | D3DHAL_DP2DRAWPRIMITIVE2
LPD3DNTHAL_DP2DRAWPRIMITIVE2 | LPD3DHAL_DP2DRAWPRIMITIVE2
D3DNTHAL_DP2DRAWINDEXEDPRIMITIVE2 | D3DHAL_DP2DRAWINDEXEDPRIMITIVE2
LPD3DNTHAL_DP2DRAWINDEXEDPRIMITIVE2 | LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE2
D3DNTHAL_DP2PIXELSHADER | D3DHAL_DP2PIXELSHADER
LPD3DNTHAL_DP2PIXELSHADER | LPD3DHAL_DP2PIXELSHADER
D3DNTHAL_DP2CREATEPIXELSHADER | D3DHAL_DP2CREATEPIXELSHADER
LPD3DNTHAL_DP2CREATEPIXELSHADER | LPD3DHAL_DP2CREATEPIXELSHADER
D3DNTHAL_DP2SETPIXELSHADERCONST | D3DHAL_DP2SETPIXELSHADERCONST
LPD3DNTHAL_DP2SETPIXELSHADERCONST | LPD3DHAL_DP2SETPIXELSHADERCONST
D3DNTHAL_DP2DRAWRECTPATCH | D3DHAL_DP2DRAWRECTPATCH
LPD3DNTHAL_DP2DRAWRECTPATCH | LPD3DHAL_DP2DRAWRECTPATCH
D3DNTHAL_DP2DRAWTRIPATCH | D3DHAL_DP2DRAWTRIPATCH
LPD3DNTHAL_DP2DRAWTRIPATCH | LPD3DHAL_DP2DRAWTRIPATCH
D3DNTHAL_DP2VOLUMEBLT | D3DHAL_DP2VOLUMEBLT
LPD3DNTHAL_DP2VOLUMEBLT | LPD3DHAL_DP2VOLUMEBLT
D3DNTHAL_DP2BUFFERBLT | D3DHAL_DP2BUFFERBLT
LPD3DNTHAL_DP2BUFFERBLT | LPD3DHAL_DP2BUFFERBLT
D3DNTHAL_DP2ADDDIRTYRECT | D3DHAL_DP2ADDDIRTYRECT
LPD3DNTHAL_DP2ADDDIRTYRECT | LPD3DHAL_DP2ADDDIRTYRECT
D3DNTHAL_DP2ADDDIRTYBOX | D3DHAL_DP2ADDDIRTYBOX
LPD3DNTHAL_DP2ADDDIRTYBOX | LPD3DHAL_DP2ADDDIRTYBOX
DDNT_GETDRIVERINFO2DATA | DD_GETDRIVERINFO2DATA
DDNT_GETFORMATCOUNTDATA | DD_GETFORMATCOUNTDATA
DDNT_GETFORMATDATA | DD_GETFORMATDATA
DDNT_DXVERSION | DD_DXVERSION
D3DHAL_TSS_MAXSTAGES | D3DNTHAL_TSS_MAXSTAGES
PDD_DIRECTDRAW_LOCAL | LPDDRAWI_DIRECTDRAW_LCL


Naming Windows 98/Me Device Drivers

This topic applies only to Windows 98/Me.

Microsoft has reserved certain file names for its default device driver suite. Device drivers from other vendors must not use these reserved file names. Vendors should use unique file names for all files that make up their driver, even if some of the components of the driver are identical to the components shipped by Microsoft.

Providing unique names for components ensures that end users can easily switch between device drivers from different manufacturers for a specific device. This ensures that no permanent loss of functionality occurs, regardless of version numbers, when a DirectX application installs its device drivers or when an upgrade of Windows is installed.

The current list of reserved driver filenames is available on the Microsoft Hardware Development web site at http://microsoft.com/hwdev.


Installing DirectX Drivers

This topic applies only to Windows 98/Me.

Creating Installation Files for Driver-Only Installation

In this scenario, the hardware vendor will provide in the distribution package all the driver files that make up the device driver, including the device's INF file.

DirectX does not provide a method for hardware vendors to distribute the runtime. For information about IHV redistribution, please send e-mail to directx@microsoft.com.

Using DirectX Setup

During the end-user installation process, DirectX Setup is executed to install the DirectX subsystem. DirectX Setup installs the entire DirectX subsystem, consisting of Microsoft DirectDraw®, DirectSound®, DirectPlay®, Direct3D®, and DirectInput®; there is no option for partial installation. When redistributed by ISVs and on the web, DirectX Setup will also upgrade drivers if necessary. The IHV redistribution (available by sending e-mail to directx@microsoft.com) installs only the runtime components.

DirectX Setup for DirectX uses version numbering and detection of registered drivers to decide whether a driver will be updated. To determine a driver's version number, DirectX Setup examines the version numbers of all files composing the device driver and uses the highest as the version number for the entire driver.

In DirectX, the Setup application backs up any driver that is replaced during installation, and also installs dxsetup.exe as a part of the DirectX subsystem. In addition, the capability for uninstalling DirectX drivers is registered with Add/Remove Programs in Control Panel.


Testing DirectX Device Drivers

This topic applies only to Windows 98/Me.

Device drivers should be registered with Microsoft through testing and acceptance by WHQL, because by default DirectX Setup will replace registered drivers only with other registered drivers that have higher version numbers. Unregistered drivers can be replaced during application installation at the discretion of the end user or application. Note that if all of the rules in this article are followed, because none of the files will have been overwritten, the end user can easily switch back to previously used device drivers using Device Manager.

To become a registered DirectX driver, the device driver must first pass the standard WHQL tests for Windows 98/Me, and then pass an additional set of DirectX-specific tests. If the driver passes all of these tests, WHQL will link the code into the new device driver that allows DirectX to determine whether the driver is registered, and a registered version number is also assigned. The registered binary version of the driver is then returned to the vendor.


Troubleshooting with Dxsetup.exe

This topic applies only to Windows 98/Me.

Dxsetup.exe, which is installed in the \Program Files\DirectX\Setup directory by DirectX Setup, has these functions:

  • Dxsetup.exe can be used to determine the version of the DirectX components installed, including whether the device drivers support DirectX and whether they are registered.
  • Dxsetup.exe can restore previously installed drivers.

Caution When using dxsetup.exe for troubleshooting, always run the utility from the user's hard disk rather than from the DirectX distribution disk. Running dxsetup.exe from the DirectX distribution disk under or later 2000 will cause the system to stall.

When dxsetup.exe is run, it presents the current status of all of the DirectX components, including device drivers, plus three options: Quit, Restore Audio Drivers, and Restore Display Drivers. Unless the user selects Quit, dxsetup.exe forces a reboot after it has performed the requested function.


References

This topic applies only to Windows 98/Me.

  • To obtain a copy of the license agreement and DirectX binaries, please send e-mail to directx@microsoft.com with Request DirectX in the Subject line.
  • If you have questions about DirectX, please contact directx@microsoft.com.
  • For information about WHQL and testing, please go to http://microsoft.com/hwtest.
  • Microsoft DirectX DDK and SDK (next-generation cross-platform multimedia support for Windows 98/Me and Windows 2000 and later): http://msdn.microsoft.com/directx, the Microsoft DirectX Multimedia Expo.
  • For the most up-to-date information on creating Windows 98/Me device drivers that work with DirectX, see http://microsoft.com/hwdev/devdes/dll_dx5.htm.
  • The current list of reserved driver filenames is available on the Microsoft Hardware Development web site, at http://microsoft.com/hwdev.


Hardware Emulation Layer

The DirectDraw driver does not do emulation. Therefore, any DirectDraw functionality not handled by the driver is handled by the DirectDraw hardware emulation layer (HEL). The HEL (written by Microsoft as part of DirectDraw) emulates the driver in software and does whatever DirectDraw needs that is not handled by the DirectDraw driver. This emulation is done in user mode.

For instance, if the DirectDraw driver has capability (caps) bits set for blts but not for transparent blts, the DirectDraw driver is called for blts and the HEL for transparent blts. In the case of a transparent blt, the HEL is passed a display memory pointer and it compares each byte from a backing surface to the color key. If the byte does not match the color key, the HEL copies it to the destination surface using the CPU. Emulation also occurs for other unsupported operations or if the card is out of display memory.

It is important to note that DirectDraw does not pass failed DirectDraw driver operations to the HEL. Instead, it returns the DirectDraw driver's error code to the application. DirectDraw determines which component to call based on the capability bits. If either the HEL or the DirectDraw driver fails a particular operation, an error code is returned to the application.

Note for Windows 98/Me On a small number of low-end cards that don't have DirectDraw-capable drivers, DirectDraw can access the card using the generic frame buffer (Framebuf) display driver. This driver can only lock, unlock, and flip. If there is no DirectDraw driver, and Framebuf does not work on the card, DirectDraw uses the HEL for everything, which is still much faster than running all operations through the GDI and the DIB engine. The HEL can also use the display control interface (DCI) support in the driver to access the primary surface in the absence of DirectDraw support.


DirectDraw Driver Fundamentals

This section contains general information about the design of display drivers for DirectDraw. Information is organized in the following groups:

DirectDraw Surfaces

Display Memory

Memory Configuration Examples

Flipping

Blitting

Drivers That Assume State Information

Turning On a Display Card and Changing Modes on Windows 98/Me


DirectDraw Surfaces

The Microsoft® DirectDraw® Surface is the basic image unit in Microsoft DirectX® graphics. It is either a rectangular collection of pixels of a particular width, height, and pixel format; or a buffer containing commands or vertices for Microsoft Direct3D®. Surfaces have bits associated with them that denote their behavior and usage. These bits are called surface capability bits (or caps bits for short). Caps bits denote intended usages such as holding texels for rendering (the DDSCAPS_TEXTURE caps bit), being the target for 3D rendering (DDSCAPS_3DDEVICE), and many others. See the reference section under the DDSCAPS structure for more information on surface caps bits.

The primary surface is the surface that is currently being scanned out to the monitor by the display card. Much more will be said about the primary surface throughout this document.


Complex Surfaces and Attachments

Surfaces can also be complex, which means that they are part of a larger collection of associated surfaces. Examples of complex surfaces include the front buffer and associated back buffers, the various levels of a MIP map, and the various faces of a cube map.

The DirectDraw run-time uses a concept known as surface attachments to manage the linking of different simple surfaces into complex surfaces. Surfaces can be attached implicitly, as when the application makes one call to IDirectDraw7::CreateSurface to build a flipping chain (front buffer and back buffers with possible Z-buffer); or explicitly, as when the application associates a Z-buffer with a render target by calling IDirectDrawSurface7::AddAttachedSurface.


Creating and Destroying DirectDraw Surfaces

Direct Draw surfaces are created in a four-stage process. These stages are:

  1. DdCanCreateSurface. The run-time calls the driver's DdCanCreateSurface to see if the driver will allow the creation of surface of this type, size, and format. The driver can return a failure code that will be propagated to the application.
  2. DdCreateSurface. The driver creates the surface in question, potentially allocating memory for the contents of the surface. Complex surfaces can be created all at once, with one call to DdCreateSurface. Thus the driver may be required to create many surfaces in one call.
  3. Memory Allocation. The DirectDraw run-time will allocate memory for any surface not allocated by the driver in response to the DdCreateSurface call. This process is covered in more detail in the following sections.
  4. D3dCreateSurfaceEx. This call is new for the DirectX 7.0 DDI. This function associates a handle with the surface in question for later use in the Direct3D D3dDrawPrimitives2 token stream. The driver also creates its own copy of the surface structure maintained by DirectDraw at this time. See the Direct3D DDK documentation for more information regarding D3dCreateSurfaceEx.

Surfaces are destroyed by a single call to the driver's DdDestroySurface entry point.

Surfaces persist only as long as the mode in which they are created persists. Where there is a mode change, all the surfaces under the driver's control are destroyed, as far as the driver is concerned. There are also other events that can cause all surfaces to be destroyed in this way. It is not necessary for the driver to determine the cause of a DdDestroySurface call.


Lost Surfaces and Atomic Restoration

Surface object lifetimes are longer for the run-time's surface objects than they are for the driver's surface objects. In a few situations, most notably mode changes, surfaces become lost. This means that the driver's surface object is destroyed when DdDestroySurface is called, but the run-time's surface object is merely placed into a suspended state, called "lost." Later, the run-time object can be restored, which corresponds to a DdCreateSurface call at the driver level.

Normally, drivers do not have to be aware of this intermediate lost state. However, there are some cases where an understanding of this process will help the driver writer.

Before the release of the DirectX 7.0 DDI, surfaces were always restored one at a time, even if they were originally created in a group as part of a complex creation. As of the DirectX 7.0 DDI, driver writers can elect to handle complex surface restoration in one atomic call. At surface restoration time, the DirectDraw run-time examines the driver's D3dCreateSurfaceEx entry point. If this entry point is defined, then the DirectDraw run-time will restore all complex surfaces in one call to DdCreateSurface. The driver will most likely not be able to differentiate between the original creation and the creation caused by restoring a surface.


Losing Driver-Managed Textures

Driver-managed surfaces also need the ability to be placed in a suspended state (lost), since they also consume video memory, which is a scarce resource. Since the driver controls the allocation of video memory for driver-managed surfaces, a method is required to notify the driver when such surfaces need to be lost. This notification has been added to the DirectX 7.0 DDI through an extension to the DdDestroySurface call.

When a driver-managed surface (marked with the DDSCAPS2_TEXTUREMANAGE flag) is lost, the driver will receive a special DdDestroySurface call with DDRAWISURF_INVALID specified in the dwFlags member of the surface structure. The driver should free video memory associated with the managed surface, but should not free any other private surface information including the backing surface copy. There will be no new DdCreateSurface call to restore the lost driver-managed surfaces since they are not really lost from the driver's point of view. For the most part, this special DdDestroySurface call is used specifically to inform the driver that it should evict its video memory copy.


Display Memory

Using a back buffer that can be flipped with a front buffer is the best way to take advantage of DirectDraw. Page flipping is essential for smooth, tear-free animation in games and video playback. In general, allocating as much display memory as possible to DirectDraw increases display performance and allows games and other DirectDraw applications to run faster, with a better quality visual image.

Note for Windows 98/Me When DirectDraw is initiated, the non-DirectDraw specific portion of the display driver must be informed which memory is being used by DirectDraw, so it can avoid writing to that memory while DirectDraw is in use. This is required for DirectDraw compatibility, and is done in the non-DirectDraw specific portion of the display driver.

When allocating memory for DirectDraw use, the virtual display driver (VDD) memory must be preserved to shell out to MS-DOS®. Caches for Windows pens, fonts, brushes, and so on can also be preserved. By going through the non-DirectDraw specific portions of the display driver code to see where VDD memory is allocated, you can determine what memory can be used. It is best to give Windows 98/Me a little extra memory, for example 32 KB, and make sure the memory is aligned on a four-byte boundary. That resulting address is used for the display pointer to the scratch area (the fpStart member of the VIDEOMEMORY structure in the sample code).

Usually, display cards will have the pitch set to the width of the display so that no memory is wasted to the right (conceptually) of the front buffer. This leaves one scratch area at the conceptual bottom that can be used for other surfaces. Memory access is very straightforward in this case because one pointer can reference the entire area of accessible display memory.

If the pitch is greater than the width of the primary surface, memory to the conceptual right of the front buffer is wasted. This has to be reclaimed as a separate rectangular heap, regardless of whether the memory on the card is linear or rectangular. (Even if the memory is linear, some display drivers fix the pitch to speed up the blitter. Rather than rewrite the driver, the memory can simply be reclaimed as a separate heap.)


Memory Heap Allocation

To allocate a surface, DirectDraw scans through the display memory heaps, in the order they were specified by the drivers. Heaps are specified in an array of VIDEOMEMORY structures. DirectDraw visits the heaps in the order of the VIDEOMEMORY structures in the array. The VIDEOMEMORY structure sets up certain metrics of the heap, such as: the starting and ending memory addresses, flags describing the heap access and what types of usage are restricted for the surface placed in this heap. DirectDraw manages the heap by suballocating and deallocating memory, that is, by creating and destroying surfaces under each heap's jurisdiction. Physical limits determine how to set up these attributes.

DirectDraw's heap manager makes two passes through the VIDEOMEMORY structures when attempting to allocate memory in response to a surface creation or restoration. The ddsCaps member of the VIDEOMEMORY structure informs DirectDraw what the memory in the heap cannot be used for on the first pass. For example, if the heap is just big enough for a back buffer, sprites can be excluded from being allocated on the first pass by setting the DDSCAPS_OFFSCREENPLAIN flag. That way, other heaps fill up with off-screen plain surfaces, while preserving the back buffer for page flipping.

The ddsCapsAlt member of the VIDEOMEMORY structure can be set to allow sprites on the second pass. That way, the heap in question can allow sprites, but only if the sprite could not be created in any other heap. Do not specify the DDSCAPS_OFFSCREENPLAIN flag in ddsCapsAlt. This allows heaps to be used preferentially for their highest and best use, without ruling out alternative uses.

Display memory heaps can be either linear or rectangular, depending on the blitter or the needs of an existing display driver. The dwFlags member of the VIDEOMEMORY structure are used to specify the memory allocation type. Linear heaps describe regions of memory where the pitch of each surface can be different. Rectangular heaps describe regions of memory where the pitch of each surface is fixed. These heaps can be mixed and matched within the same display card, if necessary (see Memory Configuration Examples for more information).

Pixel depth varies depending on the display mode. Pitch (sometimes known as stride or offset) is the number of bytes added to get from one column of display memory to the same column on the row below it (as shown as shown in the following figure). With 8-bit pixels there is one byte per pixel across the entire horizontal length of memory.

Pitch

As shown in the preceding figure, pitch is the entire horizontal stretch of display memory in bytes. In linear memory it is the same as the width of the front buffer, modulo word alignment restrictions. In rectangular memory, it is the width of the front buffer, plus whatever memory is left over to the conceptual right of the front buffer. In either case, pitch is the number of bytes added to the beginning address of one scan line to reach the beginning address of the next scan line below it.


Memory Configuration Examples

The following sections contain three different types of memory configurations: linear, rectangular, and mixed display memory allocation. Each example includes sample code that can be modified to fit the physical characteristics of the card, and can be added to the HAL to allocate display memory heaps.


Linear Memory Allocation

Display memory is considered linear whenever the pitch can be changed to match the surface width, modulo word alignment restrictions (as shown in the following figure). For example, if the blitter can only hit 8-byte strides, and a 31-pixel sprite is used, each line of display needs to be adjusted by one to align the next line on an 8-byte boundary.

Word alignment restrictions can apply to any of the three types of memory configuration. Linear memory is generally used more efficiently by the application than rectangular memory because the rows are stored sequentially. Any location can be accessed easily by moving forward or backward along this linear range.

The pitch is determined by the pixel depth and surface width, modulo word alignment restrictions. If the display is 640 8-bit pixels across, then the pitch is 640. If the pixels are 16-bit and there is a 640 X 480 screen, then the pitch is 1280. Likewise 640 wide, 32-bit pixel screens have a pitch of 2560 in linear display memory.

Linear Memory Heap Allocation

The preceding figure shows an example of a linear memory heap allocation with one primary surface and one scratch area. The pointer to the start of the primary surface is fpPrimary, a member of the VIDEOMEMORYINFO structure. The size of the primary surface and the various Windows caches are added to this to give a pointer to the beginning of the scratch area, indicated by the fpStart member of the VIDEOMEMORY structure. The end point, indicated by the fpEnd member of the VIDEOMEMORY structure, is calculated by adding the size of the remaining memory minus one.

The VIDEOMEMORY structure holds the information that manages the display memory heap(s). This sample has only one element in the array of VIDEOMEMORY structures because there is only one heap. VIDMEM_ISLINEAR is a flag in the dwFlags member of the VIDEOMEMORY structure, that denotes this as linear memory.

The following pseudo code shows how a VIDEOMEMORY structure is set up for linear memory:

/*
 * video memory pool usage
 */
static VIDEOMEMORY vidMem [] = {
    { VIDMEM_ISLINEAR, 0x00000000, 0x00000000,
           { 0 }, { 0 } },
};/*

The following pseudo code shows how linear memory heaps are set up:

/*
 * video memory pool information
 */

/* Calculate the number of video memory heaps */
    ddHALInfo.vmiData.dwNumHeaps = sizeof ( vidMem ) / sizeof ( vidMem [ 0 ] );

/* set up the pointer to the first available video memory after the primary surface */
    ddHALInfo.vmiData.pvmList     = vidMem;

/*
 * remainder of screen memory
 */

    VideoHeapBase = ddHALInfo.vmiData.fpPrimary + dwPrimarySurfaceSize + dwCacheSize;
    VideoHeapEnd = VideoHeapBase + dwDDOffScreenSize - 1;

    vidMem[ 0 ].fpStart = VideoHeapBase;
    vidMem[ 0 ].fpEnd = VideoHeapEnd;

The beginning of the first available scratch area is calculated by adding the beginning of the GDI primary surface to the size of the primary surface and the size of the Windows brush, pen, and VDD caches. The result is used to set the starting point in the first element of the VIDEOMEMORY structure to the beginning of the scratch area.

The end of the scratch area is found by adding the beginning of the scratch area to the size of the scratch area and subtracting one to make it inclusive. The result is used to set the end point of the first (and, in this case, only) element of the VIDEOMEMORY structure to the end of the scratch area. If there is more than one heap, the end point is set to the end of this heap and the next heap starts where this one leaves off.


Rectangular Memory Allocation

Display memory is considered rectangular whenever the pitch is fixed to a particular size for all the surfaces within a given heap.

With rectangular display memory, the layout is two-dimensional, with a finite width and height. This width is not always the same as the width of the screen. Because display memory must account for different display resolutions and design considerations, the actual horizontal width might span a much larger region than what is currently displayed on the monitor.

For example, even though a screen might be displaying 640 pixels across, if the rectangular display memory is 1280 bytes across, the pitch is 1280 (not 640). The pitch across a 1280-pixel horizontal stretch of memory with 16-bit pixels is 2560 (remember, the pitch is based on the number of bytes to add to get from the beginning of one scan line to the next). The pitch for 32-bit pixels is quadruple what it is for 8-bit pixels, so if the display is 1280 32-bit pixels across, the pitch is 5120.

The main problem with rectangular memory is that it rarely mimics the size of the auxiliary data that an application wants to store in it. Therefore, it may waste display memory and should be avoided wherever possible. DirectDraw allows this space to be accessed on a first-come, first-served basis. The use of these regions is sometimes limited by their awkward shape and size. Left over areas of rectangular memory are often only useful as space in which to store small sprites.

A rectangular heap can be as large as a contiguous region of available memory, but it can't be L-shaped since its size is measured in X by Y coordinates. If the rectangular heap is not tall enough and wide enough to hold a primary surface, then it cannot be a back buffer. If the pitch of the primary surface is not equal to the display width of the primary surface, a rectangular block of memory to the conceptual right of the display is left over (Heap 1 in the following figure). This block is as wide as the pitch minus the width of the display. Leftover memory to the right can also happen in linear cards if the existing display driver assumes a fixed pitch. Rectangular or linear memory may also be left over below the primary surface (but not in this example).

Rectangular Memory Allocation

In the preceding figure, the starting point (indicated by the fpStart member of the VIDEOMEMORY structure) of the rectangular heap is calculated by adding the width of the primary surface to the starting address of the primary surface. The width and height are also calculated to give the dimensions of the rectangular heap. A heap could also be created below the Windows caches, if memory is leftover there.

The following pseudo code shows how a VIDEOMEMORY structure is set up for rectangular memory:

/*
 * video memory pool usage
 */
static VIDEOMEMORY vidMem [] = {
    { VIDMEM_ISRECTANGULAR, 0x00000000, 0x00000000,
           { 0 }, { 0 } },
};

The only difference between the code for rectangular memory and its linear counterpart is the VIDMEM_ISRECTANGULAR flag, which indicates that this is rectangular memory

The following pseudo code shows how rectangular memory heaps are set up:

/*
 * video memory pool information
 */

/* set up the pointer to the first available video memory after the primary surface */
    ddHALInfo.vmiData.pvmList      = vidMem;

/* this is set to zero because there may only be one heap depending on the pitch
    ddHALInfo.vmiData.dwNumHeaps      = 0;

/*
 *  Compute the Pitch here ...
 */

    vidMem[0].fpStart  = ddHALInfo.vmiData.fpPrimary + dwPrimarySurfaceWidth;
    vidMem[0].dwWidth  = dwPitch - dwPrimarySurfaceWidth;
    vidMem[0].dwHeight = dwPrimarySurfaceHeight;
    vidMem[0].ddsCaps.dwCaps = 0;      // surface has no use restrictions

The memory heap starting point is set to the starting address of the primary surface plus the width of the primary surface. The width is determined by the pitch minus the width of the primary surface. The height is set to the height of the primary surface. The surface capabilities are set to zero to indicate that there are no imposed surface use restrictions (therefore, the surface can be used for sprites or any other type of surface).


Mixed Memory Allocation

Linear and rectangular memory heaps can be mixed and matched in any fashion, provided the hardware allows it. For instance, if a front buffer has a fixed pitch, the DirectDraw-capable driver can allocate a rectangular heap to the right of it. As shown in the following figure, if memory is also left over below the primary surface, this area can be made into a linear heap that can be used for a back buffer (that is, if it is large enough).

Mixed Memory Allocation

The preceding figure shows a linear piece of memory below the primary surface (Heap 1) and a rectangular piece of memory that is reclaimed by DirectDraw to the right of the primary surface (Heap 2).

The following pseudo code shows how a VIDEOMEMORY structure is set up for a mix of linear and rectangular memory:

/*
 * video memory pool usage
 */
static VIDEOMEMORY vidMem [] =
{
  { VIDMEM_ISRECTANGULAR, 0x00000000, 0x00000000,
            { 0 }, { 0 } },
  { VIDMEM_ISLINEAR, 0x00000000, 0x00000000,
            { 0 }, { 0 } },
};

Two areas of display memory can be allocated in this instance. The area to the conceptual right of the primary surface is necessarily rectangular, and is indicated by the VIDMEM_ISRECTANGULAR flag. The area conceptually below the primary surface can be linear, and is indicated by the VIDMEM_ISLINEAR flag.

The following pseudo code shows how a mix of rectangular and linear memory heaps are set up:

/*
 * video memory pool information
 */

/* set up the pointer to the first available video memory after the primary surface */
    ddHALInfo.vmiData.pvmList       = vidMem;

/* how many heaps are there
     ddHALInfo.vmiData.dwNumHeaps       = 2;

/* The linear piece:  */

/*
 * remainder of screen memory
 */

    VideoHeapBase = ddHALInfo.vmiData.fpPrimary + dwPrimarySurfaceSize
                    + dwCacheSize;
    VideoHeapEnd = VideoHeapBase + dwDDOffScreenSize - 1;
    vidMem[0].fpStart = VideoHeapBase;
    vidMem[0].fpEnd = VideoHeapEnd;

/* The rectangular piece:  */

/* set up the pointer to the next available video memory */
    ddHALInfo.vmiData.pvmList     = vidMem[1];

/*
 *  Compute the Pitch here ...
 */

    vidMem[1].fpStart  = ddHALInfo.vmiData.fpPrimary +
                        dwPrimarySurfaceWidth;
    vidMem[1].dwWidth  = dwPitch - dwPrimarySurfaceWidth;
    vidMem[1].dwHeight = dwPrimarySurfaceHeight;
    vidMem[1].ddsCaps.dwCaps = 0;  // surface has no use restrictions

A linear memory heap is set up by determining the start and end points of the scratch area below the primary surface, indicated by the fpStart and fpEnd members of the linear VIDEOMEMORY structure (vidMem[0]). The rectangular piece is set up using the starting point, indicated by the fpStart member of the rectangular VIDEOMEMORY structure (vidMem[1]), width, indicated by the dwWidth member, and height, indicated by the dwHeight member, of the primary surface. The pitch (the dwPitch member) must be calculated before the rectangular piece can be set up. This is the same as in the previous rectangular example, except in this case the pitch is the second element of the VIDEOMEMORY structure instead of the first. Each new heap requires a new VIDEOMEMORY structure.

In some cases, the flip register can handle only 256 KB boundaries. In these instances, a small heap can use up the space between the bottom of the caches and the start of the back buffer, allowing the back buffer to begin on a 256 KB boundary. This example is not shown, but it could be implemented by adding another element to the VIDEOMEMORY structure and setting the starting point just beyond the caches and the ending point just before the 256 KB boundary. Such a heap should be flagged with DDSCAPS_BACKBUFFER so that it can be skipped over when the heap manager looks for a back buffer. This back buffer heap (the one aligned) would also be marked with DDSCAPS_OFFSCREENPLAIN to keep sprites and textures from using this heap until no other memory is available in other heaps for off-screen plain surfaces.


Bank-Switched Memory Addressing on Windows 98/Me

Windows 2000 and later drivers do not need to support bank-switched memory. This section applies only to Windows 98/Me drivers.

If linear memory addressing is supported, use it. If the hardware or driver can only use bank switching, then you must use the virtual flat-frame buffer device VflatD.

VflatD helps manage the frame buffer for a display driver. To overcome the problem of addressing more than 64 KB of display memory, VflatD virtualizes the buffer for display cards that use bank-switching techniques. It does this by mapping display memory to a smaller block of memory addresses. Thereafter, whenever a page fault occurs during a drawing operation, VflatD calls the bank-switch procedure, directing it to map a block of display data into the physical frame buffer.

If bank switching is used, DirectDraw gets this information from the display driver and sets the DDCAPS_BANKSWITCHED flag. This indicates that display memory is presented to the hardware through a memory window. The memory is made to appear flat with VflatD.

With bank-switched memory, only a small window of memory (usually 64 KB) is visible to the application at any given time. When the application reaches the end of the window, a page fault is generated. VflatD traps the page fault and moves the memory pointer so a new window is visible to the application, as shown in the following figure.

Bank Switched Memory

As illustrated in the preceding figure, bank-switched memory exposes one 64K window of visible memory at a time. Make sure that heap start addresses are at least DWORD aligned because not doing so may slow performance, and can even cause system crashes. VflatD hangs the system if a bank switch occurs within a chunk of memory that is not DWORD aligned. This is because the processor instruction being executed cannot be broken into smaller pieces. For instance, the instruction might be to read in 4-byte increments of memory. Only one page of memory is in the window at a time, so a 4-byte chunk of an instruction that straddles a page boundary will cause the fault handler to endlessly bank switch back and forth between the two memory windows. Also, standard copy operations are up to three times faster when the data is properly aligned.

Writing aligned data means that the destination address is 4-byte aligned (PTR==PTR & 0xFFFFFFFC).

Word alignment restrictions can be handled with a simple adjustment, as shown in the following pseudo code:

 /*
  * required alignments of the scan lines for each kind of memory
  */
    ddHALInfo.vmiData.dwOffscreenAlign = AlignTbl[ wBpp >> 2 ];
    ddHALInfo.vmiData.dwOverlayAlign = AlignTbl[ wBpp >> 2 ];
    ddHALInfo.vmiData.dwTextureAlign = AlignTbl[ wBpp >> 2 ];
    ddHALInfo.vmiData.dwAlphaAlign = AlignTbl[ wBpp >> 2 ];
    ddHALInfo.vmiData.dwZBufferAlign = AlignTbl[ wBpp >> 2 ];

Note The preceding sample shows pitch alignments only; these alignments do not control the alignment of the start of surface memory.


Using VflatD

This topic applies only to Windows 98/Me.

VflatD is a page-switching DLL that changes an internal pointer when a bank boundary is crossed. VflatD is not necessary unless the memory on your graphics card is bank-switched. When a bank boundary is crossed, a page fault triggers a fault handler that causes VflatD to carry a bank switch, which exposes a new page of memory. Even though a new bank has been shifted to, the memory appears to the applications as linear addressable space. Memory simply continues from a new origin that is tracked by the VflatD memory manager. Normally this happens in the background, without error.

To use VflatD, the driver must

  1. Call VflatD_Query, which verifies that the correct version of VflatD has been loaded.
  2. Call VflatD_Create_Virtual_Frame_Buffer, which registers the driver, returns a selector identifying the logical frame buffer, and specifies a bank-switch procedure to VflatD.
  3. Call VflatD_Begin_Linear_Access, which provides access to a linear addressable frame buffer. This function should be used when initializing DirectDraw with DDCreateDriverObject.
  4. Call VflatD_End_Linear_Access. Use this function when exiting DirectDraw with HALDestroyDriver.

The bank-switch procedure must be written using 32-bit code and must be no more than 100 bytes in length. When the procedure is called, the EAX register identifies the new bank to be swapped into the physical frame buffer. The procedure must save all registers except EAX and EDX and must not return a value (that is, EAX and EDX must be the same on exit as they were on entry).

VflatD_Begin_Linear_Access starts linear access to the frame buffer. The frame buffer can be accessed through its linear address (by default the frame buffer must be accessed with the default selector). The frame buffer will remain in linear access mode until VflatD_End_Linear_Access is called. This call can be nested.

VflatD returns the access count in EAX and clears the carry flag if successful. The access count is incremented each time VflatD_Begin_Linear_Access is called, and is decremented with each call to VflatD_End_Linear_Access. Linear access mode is turned off when the access count is zero.

For more information about VflatD and the VflatD functions, see the reference section of the Windows DDK documentation.


Flipping

The primary surface is the area of memory which is being read from to draw the screen that is currently being displayed. If a primary surface has one or more attached back buffers, it is a flippable surface.

Flipping structures are used to page flip in DirectDraw. Conceptually, they can be thought of as linked lists made of surfaces. The front buffer is the "visible" buffer. The back buffer and all attached flippable surfaces must be the same size and pixel depth as the front buffer. Most modern graphics cards have enough memory for flippable front and back buffers in high resolution modes.

All types of surfaces can be flipped in DirectDraw; page flipping is the common special case. For instance, flipping is not limited to the primary surface on cards that support overlays, or on 3D capable display cards that have texture memory. In these cases, overlays and textures can be flipped in the same way as the primary surface, with the same driver entry point.

Surfaces which are not used for flipping can have any dimension and can store non-flippable objects such as image data. Image data may also be stored in system memory, but in that case DirectDraw may use the hardware emulation layer (HEL) because hardware blitters cannot normally reach system memory to blit the image data. Some cards allow hardware blitters to have direct memory access (DMA) to system memory, so DirectDraw performs a check for DMA.

The following figure illustrates the relationship between two flippable surfaces.

Flipping

If a front buffer has one or more back buffers attached, it is a flippable surface, as shown in the preceding figure. The back buffer and all attached flippable surfaces must be the same size and pixel depth as the front buffer. A back buffer surface becomes the primary surface using a flip. A flip simply changes a pointer so it points to a different flippable surface, thereby displaying the new surface . The front buffer (which is no longer the primary surface) then becomes accessible, and can have new data written to it.

Done properly, flipping solves most screen flicker problems. The ability to render to a surface that is not being displayed allows smooth, tear-free animation for game play and video playback.


Tearing

As discussed in the Flipping section, a flip essentially changes a memory pointer so that it points to a new region of display memory (see the Permedia2 sample code for example). The surface being flipped away from must be finished being displayed before the application can lock, blt, or alter that memory, or a tear may result (as shown in the following figure). A tear may also occur if the surface being flipped to is having data written to it during the flip. Tearing is universal and may happen any time an image is being drawn and displayed at the same time. Faster frame rates do not solve this problem. Since primary surfaces, overlays, and textures are all DirectDraw surfaces, they can all be flipped the same way to prevent tearing.

Tearing

A tear will occur when a page flip or blt happens at the wrong time. If a page flips while the monitor scan line is in the middle of displaying a surface, as represented by the dashed line in the preceding figure, a tear will occur. The tear can be avoided by timing the flip to occur only after the entire surface has been displayed (as in the lower example of the figure). A tear can also occur when blitting to a surface that is in the process of being displayed.


Timing a Flip

Timing a flip is very easy if a flip register is available and the scan line is known. Simply check the flip register to see whether the last flip has occurred, then make sure the scan line is not in the vertical blank before doing the flip. If the scan line and flip register are not available, however, you will have to use one or more of the algorithms described in the following paragraphs.

  • If the hardware does not have a bit for checking whether the scan line has been through a refresh cycle, more than one method should be used to time the flip. The alternative method is based on elapsed time. It is okay to flip if adequate time for drawing the entire surface has elapsed since the last flip. This amount of time is determined empirically (unless the monitor refresh rate is known) at driver initialization and on mode changes by polling until the display is in vertical sync, and then polling until it is not in vertical sync. This is done for 20 iterations, with the thread execution priority set to maximum. The result is divided by 20 to give display duration. This is the maximum time to wait before allowing access to the back buffer. (If the display duration is already known, it does not need to be calculated.) In most cases, a much shorter period is required before doing a flip, but display duration is used as a fallback because it is completely reliable.
  • If only the line number of the scan line is available, the fastest method is to record the time and scan line. Then, when the scan line is less than it was before, it has been through a refresh cycle. For instance, if the scan line is at line 300 the first time it is polled and at line 50 the next time, then the entire surface has been displayed at least once. However, the scan line is not completely reliable on all display cards. In some cases a register can be read from and written to at the same time, giving half of two different numbers. In these cases, the register needs to be read twice to verify that it isn't reporting an incorrect number. In some cases the scan line may be inaccurate as it passes through the horizontal sync. The flag that indicates whether the scan line is currently in display often returns a false negative result while the scan line is in horizontal blank.
  • If the line number of the scan line is not available, it may be possible to verify that the scan line has passed from display through vertical blank and back into display. By tracking when the scan line passes into and out of display, you can determine when an entire refresh cycle has been completed. The ability to check whether the scan line is in display or in vertical blank should be available on all display cards, but the scan line may not be. (In either case, display duration is still the fallback.)

A few adjustments may be required to get the last bit of flicker out of the display, such as making sure no calculations are occurring after the address is read (that is, shifting right two places to get the true address because the address is on a DWORD boundary, etc.). To avoid tearing, make sure the scan line is not in vertical blank, and just above the vertical sync. In the case of one driver, this problem caused a tear once every seven minutes, so be careful here. These problems are easily remedied by making sure the scan line is in display before writing to the flip register.

Although display cards are based on the original IBM video graphics card (VGA) specifications, super VGAs vary considerably (see Programmer's Guide to the EGA, VGA, and Super VGA Cards by Richard F. Ferraro - Addison-Wesley, 1990). Some cards provide no straightforward way of determining whether the scan line is in vertical blank, or if it is even in display. These deficiencies will become more important as the competition to meet the demand for advanced display capabilities increases. In the meantime, driver writers must use creativity to compensate for these deficiencies.

Once it is okay to flip, the reference to the surface to display next is loaded in the flip register. Nothing happens until the scan line gets past the vertical sync and is back into the display area. Then the flip register is read once. If something else is stored in the flip register before that time, or if the surface is being written to at the same time it is being read, a tear will occur. Once the register is read, the surface should not be locked or written to while it is still being drawn.

Checking whether the register has been read is just a matter of checking a flag in most newer cards. In older cards, however, a hardware interrupt was often used for this purpose. When a certain point was crossed that read in the flip register, whatever function was hooked to that interrupt would be called. The problem is that this interrupt may be used for other purposes in some newer hardware.


Flip Intervals

Beginning with DirectX 6.0, DirectDraw adds the ability for an application to determine when a flip command is performed. Support for these new features can be added to an existing driver, depending on the hardware capabilities.

The following terms are used when describing the timing related to the application's call to Flip:

Posted
The time at which the application calls Flip and DirectDraw calls the driver's DdFlip entry point.
Retired
The time at which the hardware begins displaying from the new surface.

In previous versions of DirectDraw, flips were always retired on or near the vertical sync following when they were posted. With DirectX 6.0 and later versions, applications can specify that the flip be retired immediately, that is, exactly when posted, or at some set number of vertical syncs after the flip is posted. DirectX 6.0 specified two new capability bits (DDCAPS2_FLIPNOVSYNC and DDCAPS2_FLIPINTERVAL in the DDCORECAPS structure) and four new flags (DDFLIP_NOVSYNC, DDFLIP_INTERVAL2, DDFLIP_INTERVAL3, and DDFLIP_INTERVAL4 in the DD_FLIPDATA structure) to enable these features.

If your driver sets DDCAPS2_FLIPNOVSYNC, it will receive the DDFLIP_NOVSYNC flag in the dwFlags member of the DD_FLIPDATA structure. The DDCSAPS2_FLIPNOVSYNC flag indicates that the flip should be retired as soon as it is posted. However, in this case, your hardware must be able to switch buffers on at least a per-scan line basis. It is not considered legal for the driver to accept or advertise support for DDCAPS2_FLIPNOVSYNC if the display does not actually retire the flip until the next vertical sync, even if the driver returns immediately.

The number at the end of the DDFLIP_INTERVAL2, DDFLIP_INTERVAL3, and DDFLIP_INTERVAL4 flags denotes how many vertical syncs the hardware should wait before retiring a posted flip. For example, DDFLIP_INTERVAL2 means that the hardware should count two vertical syncs, then retire the flip on or near the second vertical sync.

If your driver exposes DDCAPS2_FLIPINTERVAL, then DirectDraw places the number of vertical syncs to delay a flip by, into the most significant byte of the dwFlags member of the DD_FLIPDATA structure. Since the DDFLIP_INTERVAL2, DDFLIP_INTERVAL3, and DDFLIP_INTERVAL4 flags are defined to make this true, the driver should not treat these three flags as bit flags. Additionally, if the driver exposes DDCAPS2_FLIPINTERVAL, DirectDraw ensures that the most significant byte of the dwFlags member is set accordingly when the DDFLIP_INTERVAL2, DDFLIP_INTERVAL3, and DDFLIP_INTERVAL4 flags are not set. DDFLIP_NOVSYNC will cause a zero to be placed in the most significant byte, and the default value of the most significant byte becomes one since the default behavior of a flip call is to retire the flip on or near the first vertical sync after it is posted.

Since DirectX 1.0, drivers have been required to return DDERR_WASSTILLDRAWING whenever a flip was pending (that is, when the flip had been posted but not yet retired). This requirement is extended for flip intervals. Since DDFLIP_NOVSYNC flips are retired when they are posted, the driver should never return DDERR_WASSTILLDRAWING as a result of such a flip (since it will never be pending). Conversely, using one of the DDFLIP_INTERVAL2, DDFLIP_INTERVAL3, or DDFLIP_INTERVAL4 flags means that the driver needs to return DDERR_WASSTILLDRAWING for a long period of time, since the period between posting and retiring a flip is extended.

DirectDraw does not preclude the use of these flags with overlay surfaces, but drivers are not required to respect them, even if they do set the DDCAPS2_FLIPINTERVAL or DDCAPS2_FLIPNOVSYNC capability bits. Drivers may choose to respect these flags for overlays if they have the capability, but applications are unlikely to exploit this feature.

Note The DDFLIP_INTERVAL2, DDFLIP_INTERVAL3, and DDFLIP_INTERVAL4 flags are intended to exploit hardware capabilities. Drivers should not attempt to emulate these flags by looping in the driver until the flip can be retired as requested. Since important operating system mutexes are held while calling a DirectDraw driver, such an implementation can have serious deleterious effects on system performance.


Overlay support

DirectDraw also supports overlays. An overlay surface is one that can be displayed on top of the primary surface without altering the physical bits in the surface underneath it. With an overlay, registers are set that define a rectangle on the primary surface that will contain the overlay surface. The digital-to-analog converter (DAC) changes the location of the rectangles. The scan line reads data in primary surface memory until it reaches the rectangle that is set aside for the overlay. It reads from the overlay surface until that line in the overlay is finished, then continues with the original primary surface image. This switching from primary surface to the overlay and back happens on every pass of the scan line and continues until the overlay is completely displayed.

The overlay surface can have a different pixel depth than the primary surface. For example, while 8 bits per pixel (bpp) may look fine for the primary surface, a video clip may need 16 bpp to display acceptably. The pixel depth switches seamlessly between the primary surface and the overlay. For more information about overlays with DirectDraw, see the Video Port Extensions to DirectX section.

Overlays flip in exactly the same way as the primary surface. The DirectDraw surface objects swap pointers so that the new overlay surface is read when the scan line reaches the rectangle bounding the overlay. The same flipping algorithm described in Timing a Flip prevents tearing.


Texture support

A texture in 3D space flips the same way as any other surface. A texture is just a flat image that has bits set to specify that it can be transformed (texture mapped) onto a 3D surface. A texture can be mapped onto a 3D surface and the motion can be rendered smoothly by page flipping the texture. Flip waits for the renderer to finish reading (like waiting for the scan line). If the flipping driver supports textures, it must be able to recognize and handle them appropriately. See Direct3D Texture Management in the Direct3D DDK documentation for more detail on textures.


Blitting

If a blt is happening within one surface and the source and destination areas overlap, the proper direction must be determined to avoid overwriting part of the source before it is copied. This can be accomplished with just two potential starting points at opposite corners of the surface. All the blt engine needs are the location and dimensions for each image.

Everything possible should be done to speed up the actual blt. Duplicating sections of code to avoid an IF statement may make the driver go faster, for example. Perhaps the best implementation of this technique would be to put the code in a macro and use that in different places rather than making function calls. This is absolutely the right place to optimize for speed. See DdBlt in the reference section.


Transparent Blt

In a transparent blt, a color key normally specifies the color(s) that will not be moved. The source color key is analogous to the blue screen used in motion pictures. The color is compared to each pixel and if they match, the pixel is not copied. If they do not match, the pixel is copied. DirectDraw also supports color keys that are ranges.

In some cases, a transparent blt may be only partially supported by the hardware. This is probably still faster than doing it in software. The DDCAPS_COLORKEYHWASSIST flag should be set in these cases.

An example of a partially supported transparent blt is a display card that requires a bit mask, instead of just using a color key. In this case, rather than comparing each pixel with the color key to determine whether to copy it, a monochrome mask is built. That is, all of the pixels are compared with the color key and the entire surface is converted to a bit mask (usually one bit per byte, depending on color depth). When using DirectDraw, this is done when the surface is unlocked.

Once the alpha mask is built, it is compared to the source surface. Everything that is not set on the alpha mask is copied to the destination surface. This accomplishes the same effect as a source color key, but requires a mask to be built first, rather than comparing and copying at the same time. The mask must be rebuilt any time the color key is set. It also must be checked whenever a blt occurs because a color key override can be specified at that time. When the application's Blt function is called, check that the color key override (the only color key passed to the blt) is the same as the color key that is set on the surface. If they are the same, it is not really an override and the mask does not need to be rebuilt. If they are different, then the mask does need to be rebuilt. (The driver's DdBlt function always sees the color key as an override.)


Clip Lists

Clipped blts are never passed to the driver on Microsoft Windows 2000 and later. The IsClipped member of DD_BLTDATA will always be FALSE, and the clipped list will always be NULL.

Note for Windows 98/Me On Windows 98/ Me, DirectDraw supports passing an entire clip list to the driver (if the driver supports this) rather than calling the driver multiple times, once for each rectangle in the clip list. If the driver can take a list of rectangles and blt them all in a FOR loop, then the driver should set the DDCAPS_CANCLIPSTRETCHED and DDCAPS_CANCLIP flags in the DDCORECAPS structure.

In DdBlt, if a clipper is attached to the destination surface and the clipper indicates that the destination rectangle is occluded, DirectDraw will break the blt into a list of simple unoccluded rectangles. If the driver sets the DDCAPS_CANCLIPSTRETCHED and DDCAPS_CANCLIP flags, DirectDraw calls the driver once, only expecting it to run through the list of rectangles described in the DD_BLTDATA structure. If the driver doesn't set these flags, then DirectDraw calls the driver once for each unoccluded rectangle, setting the DD_BLTDATA so it contains only one rectangle at a time.


Color Fills and Pattern Fills

A color fill, as described by a rectangle, fills an area of the screen with a particular color. On most cards, the address of display memory, the dimensions of the rectangle, and the color are all that is needed. Some cards require beginning and ending X and Y coordinates. Be aware that Windows automatically drops the last line of these coordinates. For example, when they are numbered from 0 to 640, Windows drops line 640.

Some cards use a pattern fill, which can accomplish the same thing as a color fill. An 8 × 8 region of pixels (the pattern) makes up the desired color, and that pattern is used to fill the specified area. The pattern is set to equal the color desired and filled in the same as a color fill. A pattern fill takes four separate colors which can be blended, reducing the number of necessary instructions.


DirectDraw and Color Space Conversion

DirectDraw allows surfaces to be created and stored in YUV formats. Four Character Codes (FourCC) denote what color space conversions are being used. Then, during the overlay process, the image is converted to 16-bit RGB. YUV 4:2:2 is effectively the same density as 16 bits per pixel (bpp), but the color fidelity is better. The image can be written in as YUV and go into display memory as RGB, but normally the translation is done as it is read out of display memory so that the compression is maintained. This saves display memory and speeds up playback. For Windows 2000 and later, some YUV formats (UYVY and YUY2 – both types of 4:2:2) are emulated, but only when used as textures. Note that unsupported YUV format surfaces cannot be created in system memory.

Three common YUV color spaces (of which there are many types) are:

  • 4:2:2 (standard television is of this type)
  • 4:1:1 (more compressed)
  • 4:4:4 (similar to RGB)

There are many varieties of these color spaces and many other YUV formats in use today. Summarizing these is beyond the scope of this document, but an excellent resource for FOURCC information can be found at http://www.webartz.com/fourcc.


Drivers That Assume State Information

Most display drivers set up the state of the blitter when they do an operation. However, some display drivers expect the blitter to be in a known state. For example, some display drivers assume that the origin is set to do a standard blt rather than a transparent blt, and so on. In these cases, the state has to be reset after DirectDraw uses it.

For example, blts between two surfaces can be accomplished either with a fixed origin or with a separate origin for source and destination surfaces. If the display driver expects the origin to remain constant and DirectDraw changes it to access a secondary surface, the old pointer must be saved and restored when the operation is finished.

If this forces DirectDraw to wait while operations are being done so it can restore registers to their previous state, performance will suffer. This is because DirectDraw's speed comes from being asynchronous.

Care must be taken in these cases to minimize the changes being made to the display state. Moving the origin in this scenario also wastes room on the stack that could otherwise be used for passing parameters.


Turning On a Display Card and Changing Modes on Windows 98/Me

The following functions are used to turn on the display card, and also to change the mode of the display card on Windows 98/Me:

Enable

ReEnable


Enable

UINT FAR PASCAL _loadds Enable(
  LPVOID  lpDevice,
  UINT  style,
  LPSTR  lpDeviceType,
  LPSTR  lpOutput,
  LPVOID  lpStuff
  );

Enable is called to turn the display card on, or can be called through ReEnable to change the display mode. Enable is a function in the 16-bit portion of the display driver.


ReEnable

UINT FAR PASCAL _loadds ReEnable(
  DIBENGINE FAR  *lpPDevice,
  GDIINFO FAR  *lpGDIInfo
  )
{
    DPF("ReEnable");

    if (Enable(lpPDevice, EnableDevice, NULL, NULL, NULL))
    {
        Enable(lpGDIInfo, InquireInfo, NULL, NULL, NULL);
        return TRUE;
    }

    return FALSE;
}

ReEnable is called every time the display mode changes. In turn, ReEnable calls Enable with parameters to reinitialize the driver object. Enable can either turn the display card on, or it can change the display mode depending on the parameters sent to it when it is called. So, when Enable is called through ReEnable (which is about all that ReEnable does), the mode is changed, but no other object structure is created. DDCreateDriverObject is called in Enable, but the bReset parameter is set to one, which just resets the mode.

ReEnable returns TRUE if successful, or FALSE otherwise.


DirectDraw Driver Initialization

This section provides information about the driver initialization process, as it relates to Windows 98/Me, as well as to Windows 2000 and later.

Windows 2000 Driver Initialization

Windows 98/Me Driver Initialization


Windows 2000 Driver Initialization

On Microsoft® Windows® 98/Me, and on Windows® 2000 and later, driver information is only retrieved when requested by an application. In other words, in response to a DirectDraw® application's request to create an instance of a DirectDraw object, the graphics engine calls the driver functions to initialize a DirectDraw driver.

Starting with Windows 2000, this sequence is done at boot time and after each mode change. This has a side effect. On Windows 98/Me, drivers typically have two modes of operation – GDI mode and DirectDraw mode. If DirectDraw is running, it won't let GDI cache bitmaps, and so on - instead giving all of the memory to DirectDraw (and visa versa when in GDI mode). This behavior caused windowed applications (such as web pages that use DirectX) to suffer. Therefore, on Windows 2000 and later, GDI and DirectDraw are required to cooperate about how memory is used. The Permedia3 sample driver that ships with the Windows DDK has excellent examples of how to do this.

The driver initialization sequence is achieved by calling the following functions:

  • DrvGetDirectDrawInfo to retrieve information about the hardware's capabilities. GDI calls this function twice:
    • The first call determines the size of the display memory heap and the number of FOURCCs that the driver supports. GDI passes NULL for both pvmList and pdwFourCC parameters. The driver should initialize and return pdwNumHeaps and pdwNumFourCC parameters only.
    • The second call is made after GDI allocates display memory and FOURCC memory based on the values returned from the first call in pdwNumHeaps and pdwNumFourCC parameters. In the second call, the driver should initialize and return pdwNumHeaps, pvmList, pdwNumFourCC, and pdwFourCC parameters.

    GDI allocates and zero-initializes the DD_HALINFO structure to which pHalInfo points. DrvGetDirectDrawInfo function should fill in the pertinent members of the DD_HALINFO structure with driver-specific information:

    • The driver should initialize the appropriate members of the VIDEOMEMORYINFO structures to describe the general format of the display's memory. See Display Memory.
    • The driver should initialize the appropriate members of the DDCORECAPS structure to describe the driver's core capabilities to DirectDraw.
    • If the driver supports any of the DirectX features that are queried by sending a GUID to the driver's DdGetDriverInfo callback, the driver must initialize the GetDriverInfo member to point to the driver's DdGetDriverInfo callback and set the DDHALINFO_GETDRIVERINFOSET bit in dwFlags.
    • The driver must set dwSize to the size, in bytes, of the DD_HALINFO structure.
  • DrvEnableDirectDraw is used by the run-time to enable the DirectDraw hardware and determine some of the driver's callback support. GDI allocates and zero-initializes the DD_CALLBACKS, DD_SURFACECALLBACKS, and DD_PALETTECALLBACKS parameter structures. The driver should do the following for each of these callbacks that it implements:
    • Set the corresponding member of the appropriate structure to point to the callback.
    • Set the corresponding DDHAL_XXX_XXX bit in the dwFlags member of the appropriate structure.

    A driver's DrvEnableDirectDraw implementation can also dedicate hardware resources such as display memory for use by DirectDraw only.

    If it is not NULL, the GetDriverInfo callback is returned in the DD_HALINFO structure by the driver's DrvGetDirectDrawInfo. GDI allocates and initializes the DD_GETDRIVERINFODATA structure and calls DdGetDriverInfo for each of the GUIDs described in the DdGetDriverInfo reference section. All GUIDs are defined in ddrawint.h.

Locking the surface memory (whether the whole surface or part of a surface) ensures that an application and the hardware cannot obtain access to the surface memory at the same time. This prevents errors from occurring while an application is writing to surface memory. In addition, an application cannot page flip until the surface memory is unlocked.


Windows 98/Me Driver Initialization

This section describes how to modify your Windows 98/Me display miniport driver to include the DirectDraw initialization process. The following topics are discussed in this section:

DirectDraw Driver Initialization Components

Initialization Procedure

Calling the HAL Function

Updating Information About the Driver


DirectDraw Driver Initialization Components

This topic applies only to Windows 98/Me.

Ddraw.dll, ddraw16.dll, and ddhelp.exe are all components of DirectDraw involved in DirectDraw driver initialization:

  • Ddraw.dll is the 32-bit DirectDraw component that contains the DirectDraw code.
  • Ddraw16.dll is the 16-bit DirectDraw component that handles thunking to the DirectDraw portion of the GDI driver, receiving mode information from the GDI driver, dynamic color changing, and ModeX information.
  • Ddhelp.exe is a helper process that loads the ddraw.dll and the 32-bit DirectDraw driver DLL into its process space. This ensures that ddraw.dll and the 32-bit DLL always remain loaded. Ddhelp.exe has a thread blocked on all processes that enables ddraw.dll and dsound.dll to do cleanup when a process is killed or exits.


Initialization Procedure

This topic applies only to Windows 98/Me.

This section describes the code required for your driver to properly initialize for DirectDraw support. The functions are described in the order they participate in the initialization process. Consequently, the discussion begins with the defines and the Control function. The Control function calls your 32-bit HAL entry point in your driver (DriverInit in the sample), which in turn calls the functions that fill in the DDHALINFO structure with the information about your driver (buildDDHALInfo32, DDCreateDriverObject, and buildDDHALInfo16 in the sample).

Note For clarity, the sample initialization functions in this section are written in C++. For an example of an optimized version of the initialization procedure, see the sample code included in the DirectX DDK (in \src\video\miniport\p3samp).

The following topics explain the initialization procedure in detail:

Querying DCICOMMAND Support

Getting the DirectDraw Version Information

Getting the 32-bit Enhanced Driver Name

Getting the 16-bit Entry Points

Getting the DirectDraw Data


Querying DCICOMMAND Support

This topic applies only to Windows 98/Me.

DirectDraw driver initialization occurs the first time the application's DirectDrawCreate function is called (see the reference section of the DirectX Software Development Kit (SDK) for more information on DirectDrawCreate). DirectDraw handles initialization communication using the standard GDI Escape function mechanism. Escape 3075 (the old DCICOMMAND escape) is used, with the dwVersion member of the DCICMD structure set to 0x200 to indicate DCI version 2.0. (The DCICMD structure is used for backward compatibility.)

The display miniport driver for Windows 98/Me begins the DirectDraw initialization as soon as DirectDraw sends a QUERYESCSUPPORT escape to the 16-bit driver Control function. The miniport driver's Control function then checks for the DCICOMMAND escape, which is also sent by DirectDraw. If the DCICOMMAND escape was sent, the miniport driver responds with DD_HAL_VERSION (the DirectDraw HAL version supported). If DD_HAL_VERSION is not returned, DirectDraw assumes that extended DirectDraw HAL functionality is not available and will use the HEL for all DirectDraw functions. This initialization process is shown as a conceptual diagram in the following figure. IHV-provided parts in this diagram are shown shaded.

Starting DirectDraw Initialization

The following sample code shows how QUERYESCSUPPORT can be handled by your Control function:

/***********************************************************************
 *
 * Control
 *
 * This is what GDI calls when an app calls Escape or ExtEscape.
 * If you don't handle an escape make sure to pass it to the DIBENG.
 ************************************************************************/

LONG FAR PASCAL _loadds Control(
    DIBENGINE FAR * lpDevice,
    UINT            function,
    LPVOID          lpInput,
    LPVOID          lpOutput)
{
    DCICMD FAR *pdci;

    DPF("Control");  // debug message to show we are in control function

    switch (function)
    {
        case QUERYESCSUPPORT:
            //
            // QUERYESCSUPPORT is sent to ask
            // "do you support this?" lpInput points
            // to the function code to query
            //
            switch (*(UINT FAR *)lpInput)
            {
                case DCICOMMAND:
                    return DD_HAL_VERSION;
            }
            break;
        case MOUSETRAILS:
            //
            // Keep track of state of mouse trails.
            // We need to know if mouse trails are on
            // so we can turn off our hardware cursor.
            //
            if (lpInput && *(UINT FAR *)lpInput > 1)
                DriverData.fMouseTrailsOn = TRUE;
            else
                DriverData.fMouseTrailsOn = FALSE;
            break;
        case DCICOMMAND:
            pdci = (DCICMD FAR *)lpInput;
            if (pdci == NULL || pdci->dwVersion != DD_VERSION)
            {
                break;
            }


Getting the DirectDraw Version Information

This topic applies only to Windows 98/Me.

The DDVERSIONINFO escape is sent next. As of DirectDraw 5.0, the DDVERSIONINFO escape call was added to allow DirectDraw to tell the driver which DirectDraw version is currently being run. This is useful for the HAL to know because sometimes it may want to report capabilities — such as AGP, video ports, and so on — that are not supported in older versions of DirectDraw. This also allows the HAL to tell DirectDraw which version of ddrawi.h was used to compile the driver.

Most older HALs fail if the DirectDraw version (DD_VERSION in ddrawi.h) does not match the version they are expecting. Therefore, DD_VERSION cannot change if DirectX 5.0 and above are to run on DirectX 2.0 or DirectX 3.0 HALs. For this reason, a new version call was added that allows the HAL to know the real version of DirectDraw, which is equal to DD_RUNTIME_VERSION (also in ddrawi.h). However, DD_RUNTIME_VERSION is for informational purposes only. HALs should not fail DirectDraw if they receive an unknown DirectDraw run time.

HALs should check this version before accessing members of the internal DirectDraw structures (DDRAWI_DIRECTDRAW_GBL, DDRAWI_DIRECTDRAW_LCL, DDRAWI_DDRAWSURFACE_LCL, DDRAWI_DDRAWSURFACE_GBL, DDRAWI_DDVIDEOPORT_LCL, and so on) that have been added after DirectX 3.0 because nothing guarantees that the driver will run only on DirectDraw versions greater than or equal to the version with which it was compiled. For example, it may run fine on DirectX 3.0 but cause severe problems when accessing a structure member added for DirectX 5.0.

The following sample shows how the Control function in a display miniport driver for Windows 98/Me should use the version information:

else if( pcmd->dwCommand == DDVERSIONINFO )
{
    LPDDVERSIONDATA pddver;

    dwDirectDrawVersion = pcmd->dwParam;
    pddver = (LPDDVERSIONDATA) pout;
    if( !pddver )
        return 0;
    pddver->dwHALVersion = DD_RUNTIME_VERSION;
}


Getting the 32-bit Enhanced Driver Name

This topic applies only to Windows 98/Me.

The DDGET32BITDRIVENAME escape is sent after getting the DirectDraw version information. The code you add to the Windows 98/Me display miniport driver returns the name of your 32-bit driver DLL (szName), the name of the entry point (szEntryPoint, which is set to "DriverInit" in the sample code), and a pointer to a region of shared data between the 16- and 32-bit address space (dwContext). Once DirectDraw has this information, it loads the 32-bit DLL (indicated by szName), calls DriverInit (as indicated by szEntryPoint), and passes dwContext (containing a memory block shared between the 16- and 32-bit side of the driver) to it. These steps are shown in the following sample code (once again, a continuation of the Control function):

/*
* return information about our 32-bit DLL
*
* we pass a pointer to our shared global Data
* to the 32-bit driver so we can talk to each
* other by reading each others mind.
*/
else if (pdci->dwCommand == DDGET32BITDRIVERNAME)
{
    LPDD32BITDRIVERDATA p32dd = (LPDD32BITDRIVERDATA)lpOutput;

    DPF("DDGET32BITDRIVERNAME");
    lstrcpy(p32dd->szName, DIRECTDRAW_DLLNAME);
    lstrcpy(p32dd->szEntryPoint, "DriverInit");
    p32dd->dwContext = (DWORD)(LPVOID)&DriverData;

    return TRUE;
}

DriverInit (which was loaded in szEntryPoint) uses the standard Windows function MapSLFix to convert the dwContext 16-bit pointers to a 32-bit pointer, which is accessed like this:

      pDriverData = MapSLFix(dwDriverData);

The entry point indicated by szEntryPoint (DriverInit in the sample) is called only once when the DLL is loaded.

In the sample functions documented here, the buildDDHALInfo32 function is called by DriverInit to modify the structures in the shared 16- and 32-bit memory window (contained in the DDHALINFO structure). This is the unchanging data passed to DirectDraw and includes the main driver callback functions, surface callbacks, and palette callbacks. It also fills out FourCCs supported, the DLL instance handle, the physical device pointer, capabilities supported, raster operations (ROPs) supported, and the required alignments of the scan lines for each kind of memory.

The 32-bit DLL must be in shared address space. That is, it must reside above the 2 gigabyte address space so that memory can be shared with the 16-bit components. The base 0xb00b0000 is used as a linker option. DirectDraw invokes ddhelp.exe to load the 32-bit DLL and to call the entry point with the shared data pointer. The 32-bit DLL fills in shared data such as the addresses of all the 32-bit HAL functions.

The following figure shows the process for querying the 32-bit enhanced driver name and loading the 32-bit HAL function addresses to the shared 16- and 32-bit address space:

Querying the 32-bit Enhanced Driver Name and Loading the 32-bit HAL Function Addresses


Getting the 16-bit Entry Points

This topic applies only to Windows 98/Me.

The DDNEWCALLBACKFNS escape is sent next (this name is a misnomer and exists only for historical reasons). This escape gives the driver the addresses of key helper functions for use on the 16-bit side. These include the DDHAL_SetInfo, DDHAL_VidMemAlloc, and DDHAL_VidMemFree functions. However, DDHAL_SetInfo is usually the only one needed by your Windows 98/Me display miniport driver.

The lpSetInfo member of the DDHALDDRAWFNS structure is the 16-bit entry point to the DDHAL_SetInfo function in ddraw16.dll. Calling the DDHAL_SetInfo function tells DirectDraw that the shared memory region between 16- and 32-bit address space has new data in it regarding a mode change or initialization. Again, the 16-bit code is necessary because of the existing 16-bit display driver. For more information about using DDHAL_SetInfo, see Updating Information About the Driver.

Calling SetInfo for Initialization or Mode Change

The following code shows how to use the DDNEWCALLBACKFNS escape (which is included as a continuation of the Control function in a display miniport driver for Windows 98/Me):

/*
* this request gives us our DirectDraw routines to call
*/
if (pdci->dwCommand == DDNEWCALLBACKFNS)
{
    DPF("DDNEWCALLBACKFNS");
    DriverData.HALCallbacks = *((LPDDHALDDRAWFNS)pdci->dwParam1);
    return TRUE;
}

The following code from the ddrawi.h header shows the ddraw16.dll entry points and the DDHALDDRAWFNS structure:

/*
 * DDRAW16.DLL entry points
 */
typedef BOOL (DDAPI *LPDDHAL_SETINFO)( LPDDHALINFO lpDDHalInfo, BOOL reset );
typedef FLATPTR (DDAPI *LPDDHAL_VIDMEMALLOC)( LPDDRAWI_DIRECTDRAW_GBL lpDD, int heap, DWORD dwWidth, DWORD dwHeight );
typedef void (DDAPI *LPDDHAL_VIDMEMFREE)( LPDDRAWI_DIRECTDRAW_GBL lpDD, int heap, FLATPTR fpMem );

extern BOOL DDAPI DDHAL_SetInfo( LPDDHALINFO lpDDHALInfo, BOOL reset );
extern FLATPTR DDAPI DDHAL_VidMemAlloc( LPDDRAWI_DIRECTDRAW_GBL lpDD, int heap, DWORD dwWidth, DWORD dwHeight );
extern void DDAPI DDHAL_VidMemFree( LPDDRAWI_DIRECTDRAW_GBL lpDD, int heap, FLATPTR fpMem );

typedef struct
{
    DWORD                  dwSize;
    LPDDHAL_SETINFO        lpSetInfo;
    LPDDHAL_VIDMEMALLOC    lpVidMemAlloc;
    LPDDHAL_VIDMEMFREE     lpVidMemFree;
} DDHALDDRAWFNS;
typedef DDHALDDRAWFNS FAR *LPDDHALDDRAWFNS;


Getting the DirectDraw Data

This topic applies only to Windows 98/Me.

The DDCREATEDRIVEROBJECT escape is sent after the DDGET32BITDRIVENAME escape has been sent. The DDCREATEDRIVEROBJECT escape calls the same internal function that reinitializes DirectDraw in the Enable and ReEnable calls (DDCreateDriverObject). If bank switching is necessary, DDCreateDriverObject invokes VflatD. Then it calls buildDDHALInfo16, which fills out the 16-bit information that goes into the DDHALINFO structure. This includes mode change information and any data required to communicate with the 16-bit display driver, such as the mode table, current display mode, primary surface address, pixel format, display heap information, and any 16-bit callback functions (there is typically only one, HALDestroyDriver). (Since DriverInit — which calls buildDDHALInfo32 — has already been called, the 32-bit information is already present.) The driver then calls the DDHAL_SetInfo function with DDHALINFO. DirectDraw thunks to the 16-bit side to retrieve the DDHALINFO structure. Ddhelp.exe is instructed to create a thread and to block on a special shared event. This event is signaled by ddraw16.dll at some point.

Getting DirectDraw Information from the Driver

The following code sample shows how to use the DDCREATEDRIVEROBJECT escape. (Note that any escape codes that are not handled in the Control function are passed on to the DIB engine.)

            /*
             * handle the request to create a driver
             * NOTE we must return our HINSTANCE in *lpOutput
            */
            else if (pdci->dwCommand == DDCREATEDRIVEROBJECT)
            {
                DPF("DDCREATEDRIVEROBJECT");
                DDCreateDriverObject(FALSE);
                *(DWORD FAR *)lpOutput = DriverData.HALInfo.hInstance;
                return TRUE;
            }

            break;
    }

    return DIB_Control(lpDevice,function,lpInput,lpOutput);
}


Calling the HAL Function

This topic applies only to Windows 98/Me.

When a HAL function is invoked, DirectDraw tests to determine whether the function is 16- or 32-bit. If the HAL function is 32-bit, the 32-bit DirectDraw driver DLL (ddraw.dll) is called directly. If the HAL function is 16-bit, the pointers are aliased, ddraw16.dll is thunked to, and ddraw16.dll calls the 16-bit function. After that occurs, the pointer aliases are freed.

Calling the HAL Function

Built on Wednesday, July 11, 2001


Updating Information About the Driver

This topic applies only to Windows 98/Me.

Every time the GDI driver needs to update information about the driver, DDHAL_SetInfo must be called. This is done in response to DDCreateDriverObject, Enable, ReEnable, and ResetHiResMode (in DirectDraw for DirectX 3.0 and above). (Information about ResetHiResMode can be found in the Windows 95 DDK documentation.) The driver fills in a DDHALINFO structure and calls DDHAL_SetInfo (the driver saves the DDHAL_SetInfo callback address at DDNEWCALLBACKFNS escape time). In response to DDHAL_SetInfo, ddraw16.dll triggers an event. A real-time priority thread in ddhelp.exe is blocked on the event. Ddhelp.exe calls a special entry point in ddraw.dll, which then thunks to ddraw16.dll and retrieves information. If this is a mode set, all surfaces are marked as lost. Mode setting is summarized in the following figure.

Updating Driver Information


Surface Structure Members Reserved for Drivers

This topic applies only to Windows 98/Me.

DirectDraw provides two members in its surface structures in which drivers can store any data they want. These fields are the dwReserved1 member in the surface global structure (DDRAWI_DDRAWSURFACE_GBL) and the dwDriverReserved member in the surface global more structure (DDRAWI_DDRAWSURFACE_GBL_MORE). Given a local surface pointer (lpddSurfLcl, for example), the first field can be accessed as in the following expression:

lpddSurfLcl->lpGbl->dwReserved1

Accessing the second field is more complex, so the GET_LPDDRAWSURFACE_GBL_MORE macro from ddrawi.h should be used as follows:

GET_LPDDRAWSURFACE_GBL_MORE(lpddsurfLcl->lpGbl)->dwDriverReserved

The dwReserved1 member is available for driver use for display memory surfaces only. The driver should not read from or write to this field if the surface is in system memory. This is not normally an issue because system memory surfaces are not normally seen by the driver. However, Direct3D drivers see system memory texture surfaces and DirectDraw drivers capable of system-to-display memory transfers can also be passed system memory surfaces. If a driver needs to store information with a surface regardless of whether it is in system or display memory, it should use the new dwDriverReserved member. Note that a driver is not notified of the creation or destruction of system memory surfaces, so dynamically allocated resources should not be referenced by the dwDriverReserved member. The exception to this is system memory texture surfaces in Direct3D drivers. A Direct3D driver will get create and destroy texture calls in its HAL for system memory surfaces, and can therefore use these entry points to dynamically allocate and free resources.


An Example of Different Hardware Versions Using the Same Driver

This topic applies only to Windows 98/Me.

Generally your driver will work on a family of cards. Because each card has different capabilities that must be supported, query the type of card you are using to determine which features you can access. Each subsequent card adds new functionality, which could be supported by adding more cases to a switch statement like the example shown below. (This is not meant to be working code and should not be included as-is in your driver.)

switch( lpSData->ChipType )
{
    case CARD_VERSION_1:
       ddHALInfo.ddCaps.dwCaps =  0;
       ddHALInfo.ddCaps.dwCKeyCaps = 0;
       break;
    case CARD_VERSION_2
       ddHALInfo.ddCaps.dwCaps = DDCAPS_BLT | DDCAPS_BLTCOLORFILL;
       ddHALInfo.ddCaps.dwCKeyCaps = 0;
       break;
    case CARD_VERSION_3
       ddHALInfo.ddCaps.dwCaps = DDCAPS_BLT | DDCAPS_BLTCOLORFILL |
                        DDCAPS_COLORKEY | DDCAPS_COLORKEYHWASSIST;
       ddHALInfo.ddCaps.dwCKeyCaps =  DDCKEYCAPS_SRCBLT;
       break;
    default:
       ddHALInfo.ddCaps.dwCaps         =  0;
       ddHALInfo.ddCaps.ddsCaps.dwCaps =  0;
       ddHALInfo.ddCaps.dwCKeyCaps     = 0;
       break;
}


Using GetDriverInfo

This topic applies only to Windows 98/Me.

Beginning with DirectX 5.0, the GetDriverInfo callback function gave device drivers a new mechanism for providing driver-specific information, such as pointers to driver callbacks, to the DirectDraw runtime. To preserve compatibility with Windows 2000 and later, there are no plans to furnish this mechanism at the application level. GetDriverInfo is provided to help minimize changes to HAL-related DirectDraw structures in the future.

The pointer to this callback replaces the hWndListBox member that was part of the DDHALINFO structure (although it was never used) in versions of DirectDraw earlier than 5.0. This structure member has been renamed GetDriverInfo and points to a callback function with the following prototype:

DWORD __stdcall GetDriverInfo(LPDDHAL_GETDRIVERINFODATA lpData);

To inform DirectDraw that the GetDriverInfo member has been set correctly, the driver must also set the DDHALINFO_GETDRIVERINFOSET bit of dwFlags in the DDHALINFO structure.

Drivers must use the GetDriverInfo callback if any of the following DirectX features are implemented:

DirectDraw functionality:

  • Video port extensions
  • Color control
  • Windows 98/Me and Windows 2000 and later kernel-mode
  • Advance graphics port (AGP)

Direct3D functionality:

  • SetRenderTarget
  • D3dDrawPrimitives2 functions

The prototype to GetDriverInfo is similar to those of all DirectDraw callbacks. For now, the function should always set the ddRVal member of the input structure and return DDHAL_DRIVER_HANDLED, because there is no way to emulate its functionality.

The input for this callback function specifies a globally unique identifier (GUID) that determines what information DirectDraw wants. The behavior of this function is determined by which GUID is specified. The GUID points to a GUID instance defined in ddrawi.h that typically corresponds to a callback structure. The amount of data expected by DirectDraw depends on the value of this GUID. DirectDraw informs the driver of the expected amount of data in the dwExpectedSize member of the DDHAL_GETDRIVERINFODATA structure. The driver must not fill in more data than dwExpectedSize bytes. The driver should also fill in the dwActualSize member of the structure with the number of bytes known by the driver.

This flexible handshaking procedure is important for forward and backward compatibility with DirectX versions. Assuming that callback structures will get bigger with future versions of DirectX, the following scenarios apply if there is a mismatch between the callback structure sizes expected by the DirectX runtime and the sizes implemented by the Driver:

  • Under versions earlier than DirectX 5.0, DirectDraw does not attempt to call GetDriverInfo. The driver functionality is not exploited because it is not supported by these versions of DirectDraw.

    Otherwise, DirectDraw asks for a smaller callback structure than the driver wants to provide. The driver copies only the callbacks expected by DirectDraw and reports the size it expects (which is higher). It is possible but unlikely that DirectDraw will take into account that it is running on a driver designed for a more recent version.

  • If the driver is written for any release of DirectX earlier than version 5.0, it will not set the DDHALINFO_GETDRIVERINFOSET bit, and DirectX will not attempt to call GetDriverInfo.

    Otherwise, the driver implements a callback structure that is smaller than what DirectDraw expects. In this case, the driver copies its complete callback structure into the buffer provided by DirectDraw and reports the buffer size in dwActualSize. DirectDraw then knows how many callbacks are implemented by the driver and might implement different policies for the legacy driver than it would if the driver reported the entire callback structure.

To avoid problems using GetDriverInfo:

  • Do not implement dependencies based on the order in which GetDriverInfo is called. For example, avoid hooking driver initialization steps into GetDriverInfo.
  • Do not try to ascertain the DirectDraw version based on calls to GetDriverInfo.
  • Do not assume anything about the number of times DirectDraw will call the driver, or the number of times DirectDraw will query a given GUID. It is possible that DirectDraw will probe the driver repeatedly with the same GUID. Implementing assumptions about this in the driver hampers its compatibility with future runtimes.

To help avoid these problems, use the sample driver source code as a base for your implementation. The sample 32-bit callback function is defined as follows:

DWORD __stdcall GetDriverInfo32(LPDDHAL_GETDRIVERINFODATA lpData)
{
    lpData->ddRVal = DDERR_CURRENTLYNOTAVAIL;

    if (IsEqualIID(&(lpData->guidInfo),
        &GUID_MiscellaneousCallbacks) )
    {
    }
    if (IsEqualIID(&(lpData->guidInfo),
        &GUID_VideoPortCallbacks) )
    {
        DDHAL_DDVIDEOPORTCALLBACKS vpCB;
        DWORD dwSize = lpData->dwExpectedSize;
        if ( sizeof(vpCB) < dwSize )
            dwSize = sizeof(vpCB);
        lpData->dwActualSize = sizeof(vpCB);
        memcpy(lpData->lpvData, &vpCB, dwSize );
        lpData->ddRVal = DD_OK;
    }
    if (IsEqualIID(&(lpData->guidInfo),
        &GUID_ColorControlCallbacks) )
    {
        DDHAL_DDCOLORCONTROLCALLBACKS ccCB;
        DWORD dwSize = lpData->dwExpectedSize;
        if ( sizeof(ccCB) < dwSize )
            dwSize = sizeof(ccCB);
        lpData->dwActualSize = sizeof(ccCB);
        memcpy(lpData->lpvData, &ccCB, dwSize );
        lpData->ddRVal = DD_OK;
    }
    if (IsEqualIID(&(lpData->guidInfo), &GUID_VideoPortCaps) )
    {
        if (lpData->dwExpectedSize != sizeof(VideoPortCaps) )
            return DDHAL_DRIVER_HANDLED;
        lpData->dwActualSize = sizeof(VideoPortCaps);
        memcpy(lpData->lpvData, VideoPortCaps,
            sizeof(VideoPortCaps) );
        lpData->ddRVal = DD_OK;
    }
    if (IsEqualIID(&(lpData->guidInfo), &GUID_KernelCallbacks) )
    {
        DDHAL_DDKERNELCALLBACKS kCB;
        DWORD dwSize = lpData->dwExpectedSize;
        if ( sizeof(kCB) < dwSize )
            dwSize = sizeof(kCB);
        lpData->dwActualSize = sizeof(kCB);
        memcpy(lpData->lpvData, &kCB, dwSize );
        lpData->ddRVal = DD_OK;
    }
    if (IsEqualIID(&(lpData->guidInfo), &GUID_KernelCaps) )
    {
        if (lpData->dwExpectedSize != sizeof(DDKERNELCAPS) )
            return DDHAL_DRIVER_HANDLED;
        lpData->dwActualSize = sizeof(DDKERNELCAPS);
        memcpy(lpData->lpvData, &KernelCaps,
            sizeof(DDKERNELCAPS) );
        lpData->ddRVal = DD_OK;
    }
    return DDHAL_DRIVER_HANDLED;
}


Windows Drop-down Menus

This topic applies only to Windows 98/Me.

When Windows 98/Me uses a drop-down menu, it saves the area under it in a special part of display memory so that it can restore it quickly. A flag described in the Windows Device Driver Kit (the RC_SAVEBITMAP bit in the flRaster member of the GDIINFO structure) must be set to stop Windows 98/Me from saving the area under the menu. The area also can be stored elsewhere while the game is running, and restored to its original condition before Windows 98/Me takes control of the screen again, but this is not mandatory.


Asynchronous DMA Support in DirectDraw

This topic applies only to Windows 98/Me.

Versions of DirectDraw before DirectX 5.0 did not support asynchronous direct memory access (DMA) operations. This was due to the lack of a mechanism whereby the DirectDraw runtime and the driver could maintain consistent knowledge about the status of a given DMA operation. As of DirectX 5.0, DirectDraw offers such a mechanism using the GetSysmemBltStatus HAL callback.


Overview of DMA Operations

This topic applies only to Windows 98/Me.

When DirectDraw receives a blt request, it consults the blt capabilities of the device to see if it can perform the required blt. In cases involving at least one system memory surface, DirectDraw checks the DDCAPS_CANBLTSYSMEM flag and, if it is set, further consults the appropriate caps fields in the driver's DDCORECAPS structure. To review, these fields are as follows (as extracted from the DDCORECAPS structure definition in ddrawi.h):

DWORD    dwSVBCaps;
DWORD    dwSVBCKeyCaps;
DWORD    dwSVBFXCaps;
DWORD    dwSVBRops[DD_ROP_SPACE];
DWORD    dwVSBCaps;
DWORD    dwVSBCKeyCaps;
DWORD    dwVSBFXCaps;
DWORD    dwVSBRops[DD_ROP_SPACE];
DWORD    dwSSBCaps;
DWORD    dwSSBCKeyCaps;
DWORD    dwSSBFXCaps;
DWORD    dwSSBRops[DD_ROP_SPACE];

Once the driver has received the DMA blt request, it can set up the DMA operation and immediately return to DirectDraw. DirectDraw then decides if the DMA operation can be completed asynchronously by checking whether the driver has exposed the new GetSysmemBltStatus HAL callback. If the driver offers this function, DirectDraw tags the system memory surfaces to indicate that they have taken part in a DMA operation and returns immediately to the caller, typically before the DMA transfer has completed. If the driver does not offer this callback, then DirectDraw does not return to the caller until the driver reports through GetBltStatus that the destination surface is no longer involved in a blt. This behavior is required to ensure backwards compatibility with pre-DirectX 5.0 drivers.

Additionally, DirectDraw does not allow asynchronous DMA (that is, DirectDraw spins on GetBltStatus after setting up a blt) if any involved system memory surface has not been page locked by the application. A driver that does not require page locks to perform a transfer involving system memory surfaces can set the DDCAPS2_NOPAGELOCKREQUIRED flag. DirectDraw ignores the page lock status of system memory surfaces if this flag is set.

Because DirectDraw tags system memory surfaces that have taken part in a DMA operation, it knows to check with the driver before allowing any access or changes to such surfaces. If DirectDraw is asked to Lock, Blt, GetDC, PageUnlock, or Release a system memory surface, it first calls the driver's GetSysmemBltStatus function to determine whether the prior DMA operation has been completed. If the operation has not been completed, DirectDraw repeatedly calls GetSysmemBltStatus until the driver reports that the DMA operation has finished. The application-requested operation is then allowed to begin.


Responsibilities of DMA Drivers

This topic applies only to Windows 98/Me.

Drivers must expose GetSysmemBltStatus to enable asynchronous DMA. If drivers do not expose this callback, then, as explained in the previous section, DirectDraw repeatedly calls GetBltStatus until the operation is completed, even though DMA operations may still be scheduled. This fails to exploit the parallelism offered by using the processor and the DMA controller to do useful work at the same time.

DirectDraw does not call the HAL prior to scheduling a second DMA request on the same surface. This is the one scenario in which DirectDraw does not call GetSysmemBltStatus to ensure that DMA operations have been completed before allowing further requests to proceed. This design choice aims to reduce the number of DirectDraw-to-driver transitions required on a blt, but requires that the driver's Blt routine check for existing pending DMA operations on system memory surfaces before scheduling further operations.

Driver writers should also take care to ensure that any interdependencies between their accelerators and DMA controllers are reflected in their driver's behavior with respect to scheduling new blts. If an asynchronous DMA operation is scheduled, for instance, and a second video-to-video blt is requested, the driver should check that the DMA operation and the Blt operation do not intersect. In such a case the driver returns DDERR_WASSTILLDRAWING.

For more information, see the GetSysmemBltStatus callback and the DDHAL_GETBLTSTATUSDATA structure in the DirectDraw Driver Reference section. In addition, the following members of the DDRAWI_DDRAWSURFACE_GBL_MORE structure are of interest to writers of drivers of DMA-capable hardware:

dwPhysicalPageTable
Is a physical pointer to the page table. The format of the physical page table is made up of one DWORD per page. Each DWORD holds the physical address of the page. The first DWORD may not point to the beginning of a page, but each subsequent DWORD holds a pointer that is aligned on a 4K page boundary.
pPageTable
Is a linear pointer to the page table.
fpPhysicalVidMem
Is a physical pointer to the surface contents.
cPages
Specifies the number of entries in the page table.
cPageUnlocks
Is incremented on every page unlock. A driver can cache page table information and only update its cache if the cPageUnlocks value has changed since the page table was cached.

Note DirectDraw insulates the driver from the need to know about an application's nested PageLock/PageUnlock calls by referring to the dwPageLockCount value. This value is incremented whenever the application calls PageLock and decremented whenever it calls PageUnlock. Only the transitions to and from zero cause an actual page lock/page unlock operation to be performed.

Since all these fields reside in the DDRAWI_DDRAWSURFACE_GBL_MORE structure, driver writers should use the GET_LPDDRAWSURFACE_GBL_MORE macro from ddrawi.h to traverse from a pointer in a DDRAWI_DDRAWSURFACE_GBL structure to a DDRAWI_DDRAWSURFACE_GBL_MORE structure.


Surface and Palette Access Counts

This topic applies only to Windows 98/Me.

Under DirectX 5.0 and later, DirectDraw has the ability to inform your driver whether the original surface has been updated if the driver creates a copy of the surface in a local display memory cache. This lets you determine whether to update the cached surface. Whenever DirectDraw determines that a particular surface has been updated, it increments the access count in the dwContentsStamp member of the DDRAWI_DDRAWSURFACE_GBL_MORE structure. Your driver can check the dwContentsStamp member at any time; if the access count has been incremented, you should update your cache.

DirectDraw also has the ability to inform your driver whether the palette for a particular surface has changed, using the dwContentsStamp member of the DDRAWI_DDRAWPALETTE_GBL structure. This member is incremented each time the palette changes.

Additionally, the count in the dwContentsStamp members may also be set to zero. In this case, DirectDraw is unable to determine the contents of the surface. This value is set for DDSCAPS_VIDEOPORT, DDSCAPS_OWNDC, and surfaces whose display memory pointer has been changed by SetSurfaceDesc. If this is the case, you should not cache the contents of that surface.

DirectDraw increments the dwContentsStamp member of the DDRAWI_DDRAWSURFACE_GBL_MORE structure when:

  • An application calls Unlock.
  • An application calls ReleaseDC.
  • An application calls Blt.
  • An application calls Flip.
  • An application calls SetPalette.
  • An application calls SetSurfaceDesc, but the display memory pointer doesn't change.
  • Surfaces are lost.

DirectDraw increments the dwContentsStamp member of the DDRAWI_DDRAWPALETTE_GBL structure when an application calls SetEntries.

The following sample shows how to check whether a cached surface needs updating:

/*
 * Given a surface local pointer, is my private cache of the surface out of date?
 *
 * I cache a pointer to my private surface data inside the surface global more's
 * dwDriverReserved field. I keep a private copy of the surface access count in there,
 * and compare it against the incoming access count. If they are different or the
 * access counter is zero, then my cache is stale.
 * I also check the palette and update if necessary.
 */

if (ddVersion >= 0x500) //Check DDraw runtime version as passed in at initialization time
{
    LPDDRAWI_DDRAWSURFACE_GBL_MORE  lpSurfMore = GET_LPDDRAWSURFACE_GBL_MORE(lpSurfGbl);
    LPMYPRIVATEPALETTEEDATA  lpMyPerPaletteData;
    LPMYPRIVATESURFACEDATA   lpMyPerSurfaceData  = (LPMYPRIVATESURFACEDATA)lpSurfMore->dwDriverReserved;

    if( lpSurfMore->dwContentsStamp == 0 ||
            lpSurfMore->dwContentsStamp != lpMyPerSurfaceData->dwContentsStamp)
    {
        /*
         * My surface cache is stale. Update it.
         */
        lpMyPerSurfaceData->dwContentsStamp = lpSurfMore->dwContentsStamp;

        UpdateMyCache(lpSurfLcl); //copy surface to my cache.
    }

    /*
     * If there is a palette associated with the surface, did it change?
     */
    if ( lpSurfLcl->lpDDPalette )
    {
        /*
         * There is a palette associated with this surface
         */
        LPDDRAWI_DDRAWPALETTE_GBL lpPaletteGbl = lpSurfLcl->lpDDPalette->lpLcl->lpGbl;

        lpMyPerPaletteData = (LPMYPRIVATEPALETTEEDATA) lpPaletteGbl->dwDriverReserved;

        if (lpPaletteGbl->dwContentsStamp == 0 ||
            lpMyPerPaletteData->dwContentsStamp != lpPaletteGbl->dwContentsStamp )
        {
            /*
             * Palette has changed
             */
            lpMyPerPaletteData->dwContentsStamp = lpPaletteGbl->dwContentsStamp;

            UpdateMyPaletteForThisSurface(lpSurfLcl); //Update my palette table
        }
    }
}
else
{
    /*
     * Runtime less than 5.0 means I can't cache
     */
    UpdateMyCache(lpSurfLcl); //copy surface to my cache.
    UpdateMyPaletteForThisSurface(lpSurfLcl); //Update my palette table
}


Video Port Extensions to DirectX

Driver developers for devices with a hardware video port should implement the video port extensions (VPE) to Microsoft® DirectX®. The hardware video port on a VGA graphics controller provides a fast mechanism for getting data to the frame buffer. The hardware video port is a dedicated connection between video devices, typically between a hardware Moving Pictures Experts Group (MPEG) device or National Television Standards Committee (NTSC) decoder and the video card. This dedicated connection carries horizontal sync (H-sync) and vertical sync (V-sync) information with the video data. The hardware video port and overlay can use this sync information to flip automatically between multiple buffers, writing to one surface while the overlay displays another. This allows tear-free video without burdening the application.

VPE allows the client — typically Microsoft DirectShow® — to negotiate the connection between the MPEG or NTSC decoder and the hardware video port. VPE also allows the client to control effects in the video stream, including cropping, scaling, and so on. A VPE implementation should do only what is requested of it by the client; for example, it should crop only when the client requests cropping.

Microsoft DirectDraw® VPE objects do not control the video decoder, because it provides services of its own, nor does DirectDraw control the video source; it is beyond the scope of VPE. Rather, a DirectDraw VPE object represents the hardware video port itself. It monitors the incoming signal and passes image data to the frame buffer, using parameters set though its interface methods to modify the image, perform flipping, or carry out other services.

The video port extensions (VPE) are not associated with the Microsoft Windows® 2000 and later video port system module, videoprt.sys.


Video Port Extensions Background

The video port extensions (VPE) technology is a DirectDraw extension that supports direct hardware connections from a video decoder and autoflipping in the graphics frame buffer.

When video data is placed in the frame buffer, a video overlay can be used to display it. The video overlay in the graphics system tells the digital-to-analog converter (DAC) to show data in regions it would not ordinarily show. The use of overlays is efficient because blitting is not required to make the data visible, and because the video data can be viewed in a higher color depth than the visible frame buffer.

The hardware video port is a video stream delivery option that can be used instead of the PCI or AGP bus. For applications that are expected to run concurrently with other applications that require PCI bandwidth, it is advantageous to use the hardware video port to ensure low-latency video transmission between the decoder and the VGA graphics controller. This route is not as flexible as a PCI bus solution, because it ties the decoder to a particular graphics chip set, but it yields an opportunity to bypass the PCI bus if necessary.

The kernel-mode video transport capabilities, described in the Kernel-Mode Video Transport section, also provide support for VPE to ensure enhanced video playback quality and enhanced video capture support. The driver must support Kernel-Mode Video Transport in order to support VPE under Windows 2000 and later.

Note for Windows 98/Me Kernel-Mode Video Transport functionality is optional under Windows 98/Me, but is not supported under Windows 95. This is because it requires operating system support for the Microsoft Win32® Driver Model.

VPE supports only hardware-based data connections. Kernel-Mode Video Transport supports direct access for data transfer.

VPE is not a WDM technology. Under Windows 98/Me and Windows 2000 and later, WDM is used for other peripherals, but not for the display driver.

Because VPE support is part of DirectX 5.0 and later versions, and because it is supported in both operating systems, an application can take advantage of these capabilities with the assurance that the solution works on any graphics card that supports VPE under Windows 2000 and later, or Windows 98/Me.


Display Problems for Video

For the following two scenarios, interlaced video must be integrated for playback under Windows 2000 and later, or Windows 98/Me:

  • Interlaced content that is authored for display on an interlaced television and a computer with an interlaced monitor (NTSC/PAL).
  • Existing interlaced content that is authored for display on an interlaced television, which also needs to be displayed with the best-possible quality on a progressive scan (proscan) computer monitor.


NTSC and Interlaced Data

The National Television Systems Committee (NTSC) standard provides a series of 59.94 interlaced fields per second, each separated by 1/59.94 of a second. The scan lines of the even-numbered fields fall spatially halfway between the scan lines of the odd-numbered fields. However, because of the phosphor persistence of the television monitor, two fields are never displayed on a television screen at the same time. The viewer always sees either an even field or an odd field, but never at both.

A frame in NTSC is an arbitrary grouping of two sequential fields which are completely unrelated. That is, the first field in a frame is no more related to the second field in the same frame than it is to the second field in the previous frame. The Phase Alternation Line (PAL) format and the Sequential Color with Memory (SECAM) standard work identically at about 50 fields per second.

If the video contains high-motion content, the data in the odd field could be different from that in the even field. This does not cause a problem on a television monitor because you are never looking at both fields at the same time and the eye does a good job integrating the data. On a computer, however, this interlaced data is often interleaved into a single buffer and then displayed using progressive scan. This means that both fields are visible at the same time, with a high potential for motion artifacts.

The process of putting video onto a digital video disc (DVD) and then replaying it is complex. Typically, the source material being put on the disk was created for television, so each frame has two fields that are interlaced. Film shot at 24 frames per second (fps), however, must be converted to 59.94 fields per second to be compatible with a television display.


NTSC/PAL Conversion

Conversion from NTSC to PAL is done by simply playing the film a little too fast — at 25 fps. Two sequential fields are created from the same frame and displayed 1/50th of a second apart. Conversion from PAL to NTSC is done by repeating every fifth video field with a process called 3:2 pulldown. A first film frame is used to create two video fields, and then a second film frame is used to create three video fields. This process is repeated so that odd and even fields are sent in the order Ao Ae Ao Be Bo Ce Co Ce.

Therefore, an interlaced video created from a film contains pairs of fields. But unlike a standard television signal where each field is 1/60th or 1/50th of a second apart; many of these field pairs contain data from the same frame of film. Displaying these field pairs at the same time does not cause any artifacts and provides better results than television monitors can provide. However, any field pairs not from the same frame will be 1/24 of a second apart and could potentially cause greater artifacts.

When the interlaced video is encoded, a flag is set to indicate how the stream should be decoded. In a perfect world, this would be enough information to decode and optimally display the decoded pictures because the output of an MPEG-2 or NTSC decoder for DVD or DSS is theoretically always 50 or 60 interlaced fields per second. However, older films and some newer films often have a break in the flag cadence, especially at film reel changeover points. This requires a method for identifying such progressive content in order to select the proper method for displaying the information on a frame-by-frame basis.


MPEG and Progressive Content

MPEG-2 syntax provides the information necessary to identify progressive content and 3:2 pulldown. This information is stored in the header for each frame in the following 1-bit flags:

  • PROGRESSIVE_FRAME: When TRUE, this indicates that the two fields (of the frame) are actually from the same time instant (progressive film). When FALSE, this indicates that the fields might be one-half of a frame time apart (interlaced video).
  • TOP_FIELD_FIRST: Indicates which field comes first in time.
  • REPEAT_FIRST_FIELD: Indicates whether a field should be repeated for 3:2 pulldown.

With VPE and DirectDraw under DirectX 5.0 or later versions, video can always be displayed with the best-possible quality if these flags or a signal derived from these flags can be conveyed to the system on a per-field basis. Interlaced video can also be supported by DirectShow, with new flags in the media sample to indicate whether an uncompressed video media sample is either a full frame or a field, plus any other information. As described in the following sections, DirectShow can be instructed to switch between display modes on a per-frame basis by using either frame-based media samples or field-based media samples.


Progressive Scan Monitors and Interleaved Data

On a proscan monitor, the lines are displayed as a frame — that is, line 1 is displayed, then line 2, then line 3, and so on. The typical television set displays a 2:1 raster — that is, it displays the first field of a frame on the odd lines, and then it displays the second field of the frame on the even lines. Any material meant to be played on a television must be processed before being displayed on a proscan monitor.


Displaying Interleaved Video with VPE: Bob and Weave

Many expensive and imperfect methods exist for deinterlacing. Professional television producers use devices such as line doublers when deinterlacing for large-size rear-projection display, and effects systems with motion-adaptive filters when creating zooms and slow-motion sequences.

Two simple methods are available for displaying interlace on a progressive computer monitor: bob and weave. These terms are used here for simplicity, since computer and television industry terms are different.


Bob Method

The bob method of displaying data shows each field individually (similar to a television) using an overlay. The resulting image is half the normal height, so it must be zoomed 200 percent in the vertical direction using an interpolated overlay stretch. However, if this were all the bob algorithm did, the resulting image would jitter up and down because the odd field and the even field are offset by one line. Adding one line to the overlay start address on the odd fields solves this problem, as long as the vertical stretch is performed using an interpolator.

The bob method produces 60 (NTSC) progressive frames per second and retains all temporal information from an interlaced source. If a video was created with a video camera and the image contains motion, bob is the best low-cost display process for a progressive monitor. The bob method works for all sources of interlaced video data, but the weave method produces a crisper image.

By default, DirectShow uses the bob method for correcting interlaced display.


Weave Method

The weave method displays data using the hardware video port to interleave the interlaced fields into an overlay surface and then shows both fields at the same time. If this were all the weave algorithm did, however, motion artifacts would appear. The weave algorithm also relies on the MPEG driver to recognize the 3:2 pattern and then undoes it using functions in the kernel-mode video transport. The kernel-mode video transport may cause the hardware video port to discard the repeat fields, causing all field pairs to come from the same frame. The result is full-framed video displayed at 24 frames per second, just as it was originally sampled using film.

Each source-film frame is represented in the NTSC signal by two or three fields. This can be looked at as two A fields that make up the A frame. Each sequence of four film frames is converted to five television frames. Film frames A, B, C, and D become five television frames with the field pattern AA, BB, BC, CD, and DD. When the REPEAT_FIELD flag is used to encode this pattern in an MPEG stream, the MPEG data payload contains only four frames, but the field order of all five television frames is preserved.

The weave method produces 24 progressive frames per second and retains the full vertical resolution from an interlaced source. If a video was created from film using a 3:2 pulldown, or if it contains no motion, weave is the best affordable display process for a progressive monitor.


Mode Indicator and Anamorphic Format

Good driver design calls for a combination of bob, weave, and edge-adaptive filtering. Motion-detection circuitry can dynamically control the degree to which each technique is used on a pixel-by-pixel basis. Unfortunately, display logic to accomplish this is difficult to implement unless some additional data is made available. With the increasing availability of large computer-grade displays, the operating system needs this additional data to assure that basic graphics circuitry can reliably deliver an optimal picture.

In the world of DVD, it can be expected that many formats will be combined on one disk. There might be 24-frames per second film edited to 525/60 video, and then edited to 30-frames per second film. Each time such an edit takes place, it potentially changes how the data is best displayed. The current DVD specification does not ensure good performance for handling this mix of formats in a display system.

Another possible scenario is the display of a film where the REPEAT_FIELD flag is irregular or absent because of an error. When the encoder tries to interpret an irregular 3:2 pattern, it attempts to reacquire synchronization, but this can be messy. It is entirely possible for a display that follows the REPEAT_FIELD flag to change from weave mode to bob mode, or vice versa, literally in the middle of a shot. This would look very bad to the viewer.

A good way to display a film that has an occasional 3:2 pattern irregularity is to switch from weave mode to bob mode and back at the shot cuts that surround the irregularity. In other cases, it may be best to specifically identify the first field pair of a new pattern and maintain weave mode.

One can imagine many content scenarios. Some automatic display schemes work better than others depending on the particular content involved. It is likely that only some content providers will see a need to guarantee optimal results on the widest range of playback platforms. DirectShow gives these content authors a method for judging the impact of display mode on their titles and transmits their preferences.


VPE Functions in DirectDraw API and Driver

The video port extensions in DirectX 5.0 and later versions are low-level extensions to the DirectDraw API. VPE allows the client — usually DirectShow — to negotiate the connection between the MPEG or NTSC decoder and the hardware video port. VPE also allows the client to control effects in the video stream, including cropping, scaling, and so on.

VPE is not a high-level API designed for broad use by applications. Applications should use DirectShow, which provides free support for VPE. The following figure shows a simple view of the VPE and kernel-mode architecture; for more information, see the Kernel-mode Video Transport section.

Video Port Extensions and Kernel-Mode Architecture

The preceding figure shows VPE in relation to other components of DirectDraw architecture. DirectShow uses VPE to negotiate the connection, which provides information about how data and V-sync and H-sync information are transferred. This information can be an APIC connection (ITU 656), external data lines with extra pins, or proprietary data streams such as those implemented by Brooktree and Philips.

In the negotiation for the connection, the VGA hardware indicates what connections can be supported, and the MPEG or NTSC decoder indicates its preferences. DirectShow negotiates the best connection between the two. The connection is described as a globally unique identifier (GUID), with flags to describe other parameters, such as double clocking, video active, and so on.


DirectX VPE Initialization

To enable VPE functionality, the driver must do the following:

  • When DrvGetDirectDrawInfo is called, initialize the following members of the DDCORECAPS structure embedded in the DD_HALINFO structure to which the pHalInfo parameter points:
    • Set the DDCAPS2_VIDEOPORT flag in dwCaps2 to indicate that the display hardware contains a hardware video port. The driver should also set any other hardware video-port-related DDCAPS2_Xxx flags to describe the VPE support that the device is capable of.
    • Set dwMaxVideoPorts to the number of hardware video ports supported by the device.
    • Initialize dwCurrVideoPorts to zero.
  • Implement a DdGetDriverInfo function and set the GetDriverInfo member of the DD_HALINFO structure to point to this function when DrvGetDirectDrawInfo is called. The driver's DdGetDriverInfo function must parse the GUID_VideoPortCallbacks and GUID_VideoPortCaps GUIDs.
  • When DdGetDriverInfo is called with the GUID_VideoPortCallbacks GUID, fill in a DD_VIDEOPORTCALLBACKS structure with the appropriate driver callbacks and flags set. The driver must then copy this initialized structure into the DirectDraw-allocated buffer to which the lpvData member of the DD_GETDRIVERINFODATA structure points, and return the number of bytes written into the buffer in dwActualSize.
  • When DdGetDriverInfo is called with the GUID_VideoPortCaps GUID, fill in the array of DDVIDEOPORTCAPS structures with the capabilities of each hardware video port. Each hardware video port has an entry in the array, with hardware video port zero specified first, hardware video port one specified next, and so on. If the device supports only one hardware video port, there will only be one DDVIDEOPORTCAPS structure in the array. The driver must then copy this data to the DirectDraw-allocated buffer to which the lpvData member of the DD_GETDRIVERINFODATA structure points and return the number of bytes written into the buffer in dwActualSize.


DirectDraw Interfaces for Kernel-Mode Video Transport Support

The kernel-mode video transport must keep track of surface information for each surface it uses, and for each VPE object. This information must be updated every time DdUpdateOverlay or DdVideoPortUpdate is called for the surface or hardware video port. Before DirectDraw sends this information to the kernel mode video transport, it calls one of two driver functions: DdSyncSurfaceData or DdSyncVideoPortData. These functions allow the driver to fill in or modify some of the structure information and to use four dwDriverReserved N members of the DD_SYNCSURFACEDATA or three dwDriverReserved N members of the DD_SYNCVIDEOPORTDATA structure for its own purposes. These driver functions are required for the kernel-mode video transport support to work correctly.

A good example of how a driver can use these dwDriverReserved N members is to set a flag indicating which physical overlay an overlay surface is using if the hardware supports more than one physical overlay.


Color Control Initialization

DdControlColor, was added for Microsoft® DirectX® 5.0 to control the luminance/brightness controls of an overlay and/or primary surface. To enable color control functionality, the Microsoft DirectDraw® HAL must do the following at initialization time:

  • If the overlay and/or primary surface contains color controls, set the DDCAPS2_COLORCONTROLOVERLAY and/or DDCAPS2_COLORCONTROLPRIMAY flags in the dwCaps2 member of the DDCORECAPS structure that is embedded in the DD_HALINFO structure.
  • The driver must specify a function in the DD_HALINFO structure that DirectDraw can call to get additional information. This is described in DdGetDriverInfo.
  • The DdGetDriverInfo callback must be called with the GUID_ColorControlCallbacks GUID specified. The driver must fill in a DD_COLORCONTROLCALLBACKS structure with the appropriate driver callbacks and flags set, then copy this structure to the lpvData member of the input structure.


AGP Support

Microsoft® DirectDraw® treats advanced graphics port (AGP) memory as a subclass of display memory. This memory type is referred to as nonlocal display memory. The terms AGP memory and nonlocal display memory are synonymous from the perspective of DirectDraw and DirectDraw drivers.

AGP memory is considered a pure subclass of display memory. That is, if a driver indicates it supports AGP memory, in most cases it must have the same functional capabilities for local and nonlocal display memory, although performance differences are permitted. The exception is if the DDCAPS2_NONLOCALVIDMEMCAPS flag is set, in which case the blt capabilities for nonlocal display memory can differ from local display memory.

For example, if a driver states that it can texture from display memory, it must be able to texture from both local and nonlocal display memory. Blitting is treated similarly. A driver that exports the source color key blt capability must be able to do a source color keyed blt both to and from nonlocal display memory. The one exception to this rule is that it is possible to preclude certain surface types from ever being allocated in nonlocal display memory. For example, it is possible to use heaps to prevent overlay surfaces from ever being allocated in AGP memory.

Because AGP memory is treated as a subclass of display memory, DirectDraw has no separate set of display driver entry points for AGP memory. The existing display driver calls are used for both AGP surfaces and local display memory surfaces. An AGP-compatible driver must check incoming surfaces to see if they are in nonlocal or local display memory, and take the appropriate action. Blts from system to AGP (and vice versa) go through DirectDraw emulation layer as normal, unless a driver supports system-to-display memory blts (in which case it must support system-to-AGP transfers as well).

Drivers should set the DDCAPS2_TEXMANINNONLOCALVIDMEM flag as much as possible since the Direct3D texture manager will keep its backing surface in AGP memory when this is the case.

The remainder of this section discusses the steps necessary to modify your existing driver to support AGP memory using DirectDraw nonlocal display memory features.


Flagging Support for Nonlocal Display Memory

A driver must inform DirectDraw (and hence DirectDraw applications) that it is AGP-compatible. This is accomplished by specifying the capability bit DDCAPS2_NONLOCALVIDMEM in the dwCaps2 member of the DDCORECAPS structure, which is part of the DD_HALINFO structure passed to DirectDraw.

If running on an operating system that does not support AGP services, DirectDraw turns off the DDCAPS2_NONLOCALVIDMEM capability bit and all associated nonlocal heaps.


Specifying Nonlocal Display Memory Heaps

A DirectDraw driver controls how much AGP memory is available and to which surfaces by returning heaps in the DD_HALINFO structure that is passed back to DirectDraw. The driver identifies nonlocal heaps by specifying the VIDMEM_ISNONLOCAL flag in the dwFlags member of the VIDEOMEMORY data structure that describes the heap. Furthermore, a driver can choose to enable combining of memory writes on a nonlocal heap by specifying the VIDMEM_ISWC flag in addition to VIDMEM_ISNONLOCAL (however, the VIDMEM_ISWC flag is not currently implemented in DirectDraw).

It is the responsibility of an AGP-compatible DirectDraw driver to describe to DirectDraw the size (linear or rectangular), attributes (write combining), and surface types the heap should not and cannot be used for. However, it is not the driver's responsibility to actually reserve address space for the heap or commit memory to it. This is handled by DirectDraw on the driver's behalf. DirectDraw hides the details of managing AGP memory from the driver.

When specifying a nonlocal display memory heap, the start address specified by the driver has no meaning. The start address, both graphic address remapping table (GART) linear and physical, of a nonlocal heap is determined by the operating system when DirectDraw requests that a heap be created. Therefore, the driver can return any value for the start address. For a rectangular heap, this start address is ignored by DirectDraw. The specified width and height are all DirectDraw needs to determine memory requirements. For a linear heap, the start address has a meaning, but only to the extent that it is used to compute the size of the heap.

DirectDraw determines the size of a linear heap by (fpEnd - fpStart) + 1 (note that the specified end address is the last byte in the heap, not the first byte after the end of the heap). As such, any start address can be specified as long as when DirectDraw subtracts that address from the end address and adds 1, the result is the maximum size of the heap.

Although physical memory is only committed to the AGP heap when it is needed (that is, as surfaces are allocated), it is important not to specify very large nonlocal heaps. Such heaps consume shared address space and other important resources even before physical memory is committed.

It is also important to note that DirectDraw and the Windows® operating system impose policy limits on the amount of AGP memory that can be committed at any given time. This is necessary to prevent resource starvation for the rest of the system. Therefore, it is quite possible for a request for a nonlocal display memory surface to fail even though the nonlocal heaps are not fully committed.

When DirectDraw has determined the correct addresses (linear and physical) of the heap, it stores them in its heap descriptors. DirectDraw also provides a mechanism to notify a driver at initialization time of these addresses. How this is done is platform specific:

  • On Microsoft® Windows® 2000 and later, this is done with a DdGetDriverInfo call with the GUID_UpdateNonLocalHeap. When this GUID is passed to DDGetDriverInfo the UpdateNonLocalHeap data is passed in the data structure.
  • On Windows 98/Me this is done with DD_MISCELLANEOUSCALLBACKS.UpdateNonLocalHeap. The DD_MISCELLANEOUSCALLBACKS structure is retrieved from the driver with the DDGetDriverInfo call. At initialization time, the DirectDraw run-time goes through a FOR loop, calling the callback specified by the UpdateNonLocalHeap member. DirectDraw then invokes the driver-supplied function for each heap and passes the function a heap number and the linear and high physical address of the start of the heap.


Notification of Actual Heap Base Addresses

A driver might need to know the linear and physical address of the base of the heap at DirectDraw initialization time (for example, during mode changes) rather than waiting for a surface creation request and looking at the heaps in the global DirectDraw surface object. To support this, DirectDraw calls the driver-supplied DdGetDriverInfo callback function with a globally unique identifier (GUID) that identifies the information to be returned by the driver. If the driver recognizes the GUID and has information to return, it copies this information into the supplied data structure and passes it back to DirectDraw.

The driver uses two GUIDs to gather and offer further information regarding Direct Draw heaps:

  • GUID_GetHeapAlignment
  • GUID_UpdateNonLocalHeap

GUID_GetHeapAlignment signals to the driver to gather heap alignment information about any DirectDraw heaps that are passed to it. The heap information is passed to the driver using the DD_GETHEAPALIGNMENTDATA structure. GUID_GetHeapAlignment is defined as:

DEFINE_GUID( GUID_GetHeapAlignment,
    0x42e02f16, 0x7b41, 0x11d2, 0x8b, 0xff, 0x0, 0xa0, 0xc9, 0x83, 0xea, 0xf6);

GUID_UpdateNonLocalHeap signals the driver to update its internal state with the heap information with the nonlocal heap structures supplied by DirectDraw. This information is contained in the DD_UPDATENONLOCALHEAPDATA structure. GUID_UpdateNonLocalHeap is defined as:

DEFINE_GUID( GUID_UpdateNonLocalHeap,
           0x42e02f17, 0x7b41, 0x11d2, 0x8b, 0xff, 0x0, 0xa0, 0xc9, 0x83, 0xea, 0xf6);

If the driver must allocate memory for AGP surfaces by itself, but has exposed heaps to DirectDraw, then HeapVidMemAllocAligned is exposed as an Eng function for this purpose. HeapVidMemAllocAligned only deals with heap addresses so it returns an offset. The driver must do whatever memory mapping work it needs to do to turn the information returned from HeapVidMemAllocAligned into a virtual address.


Callback Handling Of Nonlocal Display Memory Surfaces

Nonlocal display memory surfaces are treated in exactly the same way as local display memory surfaces in terms of driver callbacks. For example, a driver's DdCanCreateSurface callback is invoked when attempting to create nonlocal (as well as local) display memory surfaces, DdBlt is called when blitting between local and nonlocal display memory surfaces, and DdDestroySurface is called when the surface memory is being discarded.

Since the same driver functions are used for both local and nonlocal display memory surfaces, drivers must explicitly check the memory type of incoming surfaces. The memory type can be identified by checking the ddsCaps.dwCaps member of the local surface object DD_SURFACE_LOCAL passed to the driver against the capability bits DDSCAPS_LOCALVIDMEM and DDSCAPS_NONLOCALVIDMEM.

Applications and AGP hardware access the bits of a DirectDraw surface using two different addresses. Applications use a virtual address that is translated through the operating system's page table to a portion of physical address space. This physical address space is mapped by the GART hardware to appear contiguous. Hardware accesses this physical linear address (again remapped to real, discontinuous pages of memory by the GART). The fpVidMem member of the DD_SURFACE_GLOBAL structure holds the virtual linear address useful to applications (and, potentially some driver operations). The device-side physical address can be found from:

fpStartOffset = pSurface->fpHeapOffset - pSurface->lpVidMemHeap->fpStart;

This offset is then added to the device's GART physical base address (contained in the liPhysAGPBase member of the VMEMHEAP structure).

In all other respects, nonlocal display memory surfaces behave exactly like local display memory surfaces. The driver receives lock requests when an application is trying to access the surface data of nonlocal display memory surfaces. Operations such as blts between nonlocal display memory and local display memory can be asynchronous, just as they can be between local display memory surfaces. Attempts to lock nonlocal display memory surfaces when operations involving those surfaces are still pending should be failed by the driver with DDERR_WASSTILLDRAWING error code in the usual way.

Furthermore, although DirectDraw manages the allocation and freeing of nonlocal display memory surfaces on behalf of the driver, the driver is still notified of the creation and destruction of surfaces in nonlocal display memory. When a nonlocal display memory surface is destroyed, the driver should not return until the surface is no longer in use.

Nonlocal display memory is lost in exactly the same way as local display memory, that is, when a mode switch occurs or when exclusive mode changes, all local and nonlocal display memory surfaces are lost and the DdDestroySurface driver callback is invoked for each surface. However, DirectDraw does not guarantee that the actual reserved address ranges and committed memory will be preserved. DirectDraw may choose to discard all committed memory and the reserved address ranges, or it may choose to de-commit memory but preserve the address range. It may also preserve both and simply mark the surfaces as lost. A driver should not make assumptions based on any one of these scenarios.


Reordering Textures In Nonlocal Display Memory

There are special cases where the driver writer might want to re-order textures in AGP memory to allow more efficient texture management. The DDCAPS2_SYSTONONLOCAL_AS_SYSTOLOCAL flag signals that the driver can support blts from backing surfaces to nonlocal video memory using all the same caps that were specified for backing surface memory to local video memory blts.

The DDCAPS2_SYSTONONLOCAL_AS_SYSTOLOCAL flag is valid only if the DDCAPS2_NONLOCALVIDMEMCAPS flag is set. If DDCAPS2_SYSTONONLOCAL_AS_SYSTOLOCAL is set, then the DDCAPS_CANBLTSYSMEM flag must be set by the driver and all the associated backing surface blt caps must be correct. DDCAPS2_SYSTONONLOCAL_AS_SYSTOLOCAL signifies that the backing surface to video memory DDCAPS blt caps also apply to backing surface to nonlocal video memory blts. For example, the dwSVBCaps, dwSVBCKeyCaps, dwSVBFXCaps, and dwSVBRops members of the DDCORECAPS structure are assumed to be filled in correctly. Any blt from a backing surface to nonlocal memory that matches these caps bits will be passed to the driver.

Note This feature is intended to enable the driver itself to do efficient reordering of textures. This is not meant to imply that hardware can write into AGP memory. Hardware writing directly into AGP memory is not currently supported.


Handling DMA-style AGP

An AGP-compatible display card can use AGP memory in one of two ways: using the execute model or the direct memory access (DMA) model.

  • In the execute model, if there is a texture in nonlocal video memory, the card accesses AGP memory directly. That is, if a card is textured from AGP memory it reads texel data directly from a backing surface.
  • In the DMA model, the contents of the surfaces must be explicitly moved to local display memory on the card before a texturing operation can be performed.

It is important to note that the model refers to how a client of the display card sees the transfer. For example, a display card may automatically move texel data from a backing surface to a small local display memory cache when texturing. This may seem like the DMA model. However, because the client application has no information about this transfer taking place, the display card is, in fact, exposing an execute model. Only when the client application has to take explicit action to move the contents of a backing surface to local display memory is the display card considered to be exposing the DMA model.

The previous sections that dealt with AGP memory described how a driver can enable and expose the execute model of AGP usage. This section describes the additional steps a driver must take to expose use of DMA model AGP to the application. Note that the driver writer must decide whether to expose the execute model or the DMA model when writing the driver. The driver should expose one model or the other, but not both.

Before exposing the DMA model from a driver, it is important to consider the implications of the DMA model to the application writer. If a driver exposes execute model AGP support, DirectDraw assumes that surfaces in AGP (nonlocal display memory) and local display memory are functionally identical. Thus the display card can texture either from nonlocal or local display memory without any additional actions by the application. When setting a render state, an application can specify the handle to a texture surface directly, regardless of whether the surface is in nonlocal or local display memory.

However, if a driver exposes the DMA model, surfaces in nonlocal display memory may have different capabilities from those in local display memory. Therefore, before attempting to texture from a nonlocal display memory surface, the application must check whether the hardware is capable of texture from nonlocal display memory. This is accomplished by examining the capabilities exposed by the driver. The same is true for blitting.

An application explicitly requests AGP memory by specifying DDSCAPS_VIDEOMEMORY ORed with DDSCAPS_NONLOCALVIDMEM. If an application does not specify a memory type or only specifies DDSCAPS_VIDEOMEMORY, nonlocal display memory is not considered. Also, if the call does not specify local or nonlocal display memory, the surface is a texture, and the device sets the D3DDEVCAPS_TEXTURENONLOCALVIDEOMEMORY flag, then the surface can be allocated in AGP memory.

This means that if a driver exposes the DMA model, surfaces are not allocated from AGP memory. This is in contrast to a driver that exposes execute model, in which AGP memory is allocated even if the application does not explicitly request it. Drivers that expose the execute model are therefore much simpler for applications to use. Furthermore, an execute model driver allows a legacy application to gain the benefits of AGP, whereas a DMA model driver only accelerates new applications written explicitly for AGP. This should be considered when deciding whether to expose the execute or DMA models.


Flagging Support for DMA Model Nonlocal Display Memory

In addition to specifying the DDCAPS2_NONLOCALVIDMEM flag to report AGP support, a DMA model driver must export the capability flag DDCAPS2_NONLOCALVIDMEMCAPS. This flag indicates that nonlocal (AGP) memory has different capabilities than local display memory.


Reporting DirectDraw Capabilities for DMA Model Nonlocal Display Memory

A DMA model driver has different capabilities for nonlocal display memory than for local display memory. For example, a display card may be able to stretch blit local display memory surfaces but not nonlocal display memory surfaces. If the driver specifies the DDCAPS2_NONLOCALVIDMEMCAPS flag, the driver is probed for the DirectDraw capabilities of nonlocal display memory surface by the DdGetDriverInfo driver entry point. The GUID that identifies this probe is GUID_NonLocalVidMemCaps.

It is important to note that for this release of DirectDraw, a driver can only specify the capabilities for blts from nonlocal display memory to local display memory. Transfers from local display memory to nonlocal display memory, and from nonlocal display memory to nonlocal display memory, are always emulated by the DirectDraw HEL. This restriction may be relaxed in a future release.


Reporting Direct3D Capabilities for DMA Model Nonlocal Display Memory

A DMA model driver must also export the Direct3D® capabilities for nonlocal display memory surfaces. This is significantly simpler than reporting DirectDraw capabilities. The only capability affected is D3DDEVCAPS_TEXTURENONLOCALVIDEOMEMORY. If a display card exporting the DMA model can texture directly from nonlocal display memory, it should set this capability in its Direct3D device description. If it cannot, and the application must explicitly load or blt the nonlocal display memory surface to a local display memory surface before performing texturing, it should not set this capability. For completeness, an execute model driver should always set this capability bit.


Kernel-Mode Video Transport

This topic describes kernel-mode video transport as it exists on the Windows 98/Me and Windows 2000 and later operating systems.

Windows 98/Me

Kernel-mode video transport refers to a new DirectDraw component in ring 0 (kernel mode) that enhances video functionality. The HAL for this interface is added to the virtual display miniport driver (miniVDD) in Windows 98/Me, and to the miniport driver under Windows 2000 and later.

A primary role of this new functionality is to hook an IRQ generated by the video port when V-sync occurs, and then to call the miniVDD to tell it to perform video port and overlay flips. This capability can support up to ten buffers without encountering hardware limitations, as long as the video port supports the V-sync IRQ. This capability is used automatically by the versions of DirectDraw supplied with DirectX 5.0 and above when autoflipping is specified by the client and the hardware cannot autoflip.

The need for this capability stems in part from the current limitations on hardware solutions, which typically support only two buffers, with no support for the new bob and weave quality algorithms tied to the video port IRQ. If the video port supports a V-sync IRQ, then this new DirectX capability can emulate autoflipping and field skipping, greatly enhancing the quality of video needed to support DVD and other video playback requirements.

The kernel-mode video transport also ensures enhanced capture support. Under Windows 98/Me and Windows 2000 and later, the WDM-based video capture driver runs in kernel mode, with direct access to the frame buffer. The capture driver can "manually" flip overlays. The kernel-mode video transport HAL can provide V-sync notification from the video port or display; it can also get field polarities, which can be useful when capturing vertical blanking interval (VBI) data.

Although the primary purpose of the kernel-mode HAL is to enhance VPE autoflipping capabilities, it also supports video bus masters, which can write data while in kernel mode. The bus master can be notified before losing the surface because of a mode change, or because a full-screen MS-DOS instance is launched. Because the new HAL support allows a bus master to be called before the changes occur, the bus master can shut off without causing a problem.

Windows 2000 and Later

Kernel-mode video transport refers to a Microsoft® DirectDraw® component that a client, such as Microsoft DirectShow®, can use to enhance video functionality. A primary role of this functionality is to call the miniport driver to tell it to perform hardware video port and overlay flips when V-sync occurs. This capability can support up to ten buffers without encountering hardware limitations, as long as the hardware video port supports the V-sync interrupt request (IRQ). This capability is used automatically by the versions of DirectDraw supplied with Microsoft DirectX® 5.0 and later versions when autoflipping is specified by the client and the hardware cannot autoflip.

The kernel-mode video transport also ensures enhanced capture support. Under Microsoft Windows® 98/Me and Microsoft Windows® 2000 and later, the WDM-based video capture driver runs in kernel mode, with direct access to the frame buffer. The capture driver can "manually" flip overlays. The Windows 2000 and later miniport video transport driver can provide V-sync notification from the hardware video port or display; it can also get field polarities, which can be useful when capturing vertical blanking interval (VBI) data.

Although the primary purpose of the kernel-mode driver is to enhance hardware video port autoflipping capabilities, it also supports video bus masters, which can write data while in kernel mode. The bus master can be notified before losing the surface because of a mode change, or because a full-screen Command Prompt instance is launched. Because the new driver support allows a bus master to be called before the changes occur, the bus master can shut off without causing a problem.


VPE and Kernel-Mode Video Transport Architecture

This section provides some details about the Windows 98/Me and Windows 2000 and later architectures for the video port extensions (VPE) and kernel-mode video transport in DirectX 5.0 and later versions. The architecture for kernel-mode video transport is the same under Windows 98/Me and Windows 2000 and later, based on new functions that Microsoft added as device-independent code. Kernel-mode video transport consists of a DxApi function that is supplied as part of DirectDraw, the DxApi callbacks supplied in the miniport by the driver, and the COM interface methods supplied as part of DirectDraw.

Windows 98/Me

In Windows 98/Me, the DxApi callbacks are added to the miniVDD, which contains the device-specific code for the graphics device.

In Windows 98/Me, as shown in the following figure, the kernel-mode device support is added to the miniVDD, which contains the device-specific code for the graphics device. In Windows 2000 and later, the kernel-mode video transport (HAL) portion is part of the Windows 2000 miniport driver.

Windows 98/Me Kernel-mode Video Transport Architecture

Note This architecture also supports using the PCI bus for data flow between the MPEG device and VGA device; however, using PCI never results in high-quality output.

In this architecture, DirectShow (or another ring 3 client) calls the new DirectDraw interfaces to get handles to the DirectDraw object and surface objects. The client passes these handles to the kernel-mode driver. These handles are specified in the calls to the kernel-mode video transport. The following figure shows a simple version of this.

Handle Passing in Windows 98/Me Video Transport

Windows 2000 and Later

In Windows 2000 and later, as shown in the following figure, the DxApi callbacks are part of the Windows 2000 miniport. For more information about the DxApi callbacks, see DxApi Miniport Functions for Windows 2000.

Windows 2000 Kernel-Mode Video Transport Architecture

The preceding figure shows the kernel-mode video transport architecture in relation to other kernel-mode and user-mode components (the dashed line denotes the kernel transition). In this architecture, DirectShow (or another user mode client) calls the IDirectDrawKernel and IDirectDrawSurfaceKernel DirectDraw COM interfaces to get handles to the DirectDraw object and surface objects.

Note This architecture also supports using the PCI bus for data flow between the MPEG device and VGA device.

In Windows 2000 and later, the client then passes these handles to the miniport driver. These handles are specified in the calls to the kernel-mode video transport. The following figure shows a simple version of how the handles are passed.

Handle Passing in Windows 2000 Video Transport

The preceding figure shows how handles are passed in user- and kernel-mode video transport.


Using Kernel-Mode Video Transport

This information presented in this topic is separated into two parts: the first part is intended for those developing Windows 98/Me drivers; the second part is intended for those developing Windows 2000 and later drivers.

Windows 98/Me

The kernel-mode video transport provides helper functions that allow Windows 2000/WDM-style kernel-mode drivers to take advantage of VGA capabilities. These include various video port related features, the ability to reliably access the VGA frame buffer, and the ability to flip an overlay. This functionality is accessed by the kernel-mode driver linking with dxapi.lib, which allows it to later call dxapi.sys. This functionality is available only when DirectDraw is loaded.

The DxApi function is the single entry point that accepts a function identifier, an input buffer and size, and an output buffer and size. The behavior of this function and the size and format of the input and output buffers depend on the specified function identifier.

To use the DxApi interface, the kernel-mode driver must receive ring 3 handles for each DirectDraw object, surface, and video port that it needs to use. For the capture and MPEG models, these handles are passed down using their existing APIs. If a driver wants to use this functionality but it has not been passed these handles already, a ring 3 component can retrieve the handles and pass them down to the driver.

Windows 2000 and Later

Kernel-mode video transport functionality is accessed by the miniport driver linking with dxapi.lib, which allows it to later call dxapi.sys. This functionality is available only when DirectDraw is loaded.

A hardware decoder uses the DxApi function supplied with kernel-mode DirectDraw to access the DxApi miniport callback functions. The DxApi function is a single entry point that accepts a function identifier, an input buffer and size, and an output buffer and size. The behavior of this function and the size and format of the input and output buffers depend on the specified function identifier. The DxApi function and its function identifiers are defined in ddkmapi.h.

DirectShow or another client accesses the DxApi miniport callback functions supplied by the driver through DirectDraw. The DxApi miniport functions are defined in dxmini.h.

To use the kernel-mode video transport interface, the miniport driver must first receive user-mode handles for each DirectDraw object, surface, and VPE object that it needs to use. For the capture and MPEG models, these handles are passed down using their existing APIs. If a driver requires this functionality but is not a stream-class driver, a user-mode component can retrieve the handles using the IDirectDrawKernel and IDirectDrawSurfaceKernel COM interfaces and pass them down to the driver. The COM interfaces and their methods are identified in ddkernel.h.


Getting the User-Mode Handles

The following procedures show how to obtain the user-mode (ring 3) handles. These procedures apply to drivers for the Windows 98/Me and Windows 2000 and later operating systems.

To get the DirectDraw handle

  1. Call QueryInterface( lpDD, &IID_IDirectDrawKernel, &pNewInterface) on the DirectDraw interface.
  2. Call the IDirectDrawKernel::GetKernelHandle method on the new interface.

The IDirectDrawKernel::GetKernelHandle method returns a kernel-mode handle for the DirectDraw driver. To release the handle, use the IDirectDrawKernel::ReleaseKernelHandle method.

Code Sample

ddRVal = IDirectDraw_QueryInterface( lpDD, &IID_IDirectDrawKernel, &pDDK );
if( ( ddRVal == DD_OK ) && ( pDDK != NULL ) )
{
    dwDirectDrawHandle = 0;
    IDirectDrawKernel_GetKernelHandle( pDDK, dwDirectDrawHandle );
    if( dwDirectDrawHandle == 0 )
    {
        // error
    }
}

To get the DirectDrawSurface handle

  1. Call QueryInterface( lpSurface, &IID_IDirectDrawSurfaceKernel, &pDDSK) on the DirectDrawSurface interface.
  2. Call the IDirectDrawSurfaceKernel::GetKernelHandle method on the new interface.

The IDirectDrawSurfaceKernel::GetKernelHandle method returns a kernel-mode handle for the DirectDrawSurface driver. To release the handle, use the IDirectDrawSurfaceKernel::ReleaseKernelHandle method.

Code Sample

ddRVal = IDirectDraw_QueryInterface( lpSurface,
             &IID_IDirectDrawSurfaceKernel, &pDDSK );
if( ( ddRVal == DD_OK ) && ( pDDK != NULL ) )
{
    dwSurfaceHandle = 0;
    IDirectDrawSurfaceKernel_GetKernelHandle( pDDSK, dwSurfaceHandle );
    if( dwSurfaceHandle == 0 )
    {
        // error
    }
}


DxApi Miniport Functions For Windows 2000

DxApi miniport driver support is only available using Windows 2000 and later because it requires changes to the operating system.

DxApi miniport driver support is very useful for the following applications:

  • Autoflipping using an IRQ for devices that do not support hardware autoflipping or that have limitations that make it undependable. This allows DirectDraw to always revert to software autoflipping when hardware autoflipping is unavailable.
  • Field skipping using an IRQ to support MPEG drivers that can undo the 3:2 pulldown of MPEG data originally sampled from film.
  • Busmastering for devices that want to continuously busmaster data without having to call DdLock / DdUnlock every frame. This is especially useful in the miniport since the drivers for these devices are WDM drivers.
  • Video and VBI capture. In the miniport driver it is easy to capture video based on a hardware video port IRQ or graphics IRQ.

Support for this API is added into the Windows 2000 miniport driver.


DxApi Miniport Initialization

To enable DxApi miniport driver functionality, the DirectDraw driver must perform the following tasks at initialization time:

  1. The driver must specify a DdGetDriverInfo function in the DD_HALINFO structure that DirectDraw can call to get additional information.
  2. The DdGetDriverInfo callback is called with the GUID_KernelCallbacks GUID specified. The driver must fill in a DD_KERNELCALLBACKS structure with the appropriate callbacks and flags set. The driver then copies this structure to the lpvData member of the DD_GETDRIVERINFODATA structure.
  3. The DdGetDriverInfo callback is called with GUID_KernelCaps GUID specified. The driver must fill in a DDKERNELCAPS structure. The driver then copies this structure to the lpvData member of the DD_GETDRIVERINFODATA structure.
  4. The kernel calls the miniport driver IOCTL handler with MajorFunction = IRP_MJ_PNP, MinorFunction = IRP_MN_QUERY_INTERFACE, and InterfaceType = GUID_DxApi. This allows the miniport driver to fill in the DXAPI_INTERFACE structure with pointers to miniport driver functions that DirectDraw can call.

The miniport driver can specify a value in the Context member of the DXAPI_INTERFACE structure that will be passed to the miniport driver each time one of these functions is called.


Video VBI Capture

DirectX 5.2 introduced two DirectDraw driver functions for video vertical blanking interval (VBI) capture. These functions are DxTransfer and DxGetTransferStatus.

The DxTransfer function facilitates video and VBI capture. Since this function is called at IRQ time, the driver must call DxTransfer and return as quickly as possible. If the display hardware is not ready to do a busmaster at the time DxTransfer is called, then the driver should keep an internal queue of a number of bus masters (the actual number of bus masters saved in the queue is up to the driver developer). This allows the hardware to perform the busmaster when the hardware is ready. In other words, the driver should not poll and wait for the bus master to complete.

When DirectDraw calls the DxTransfer function, it returns a transfer ID in the dwTransferID member of the DDTRANSFERININFO structure. The driver can then use this identification when calling the DxGetTransferStatus function.

When the bus master completes, the driver must generate an IRQ. The driver must then call the IRQCallback function specified in DxEnableIRQ and specify the DDIRQ_BUSMASTER flag. DirectDraw then calls the DxGetTransferStatus function to determine which busmaster completed. The driver must return the transfer ID (dwTransferID) that DirectDraw passed to the driver earlier. In this way, if the driver has five busmasters in the queue, DirectDraw can determine which one completed most recently.


Kernel-mode API Support (Windows 98/Me)

Note Kernel-mode support is only available using Windows 98/Me because it requires changes to the Main VDD.

Kernel-mode support is very useful for the following applications:

  • Autoflipping using an IRQ for devices that do not support hardware autoflipping or that have limitations that make it undependable. This allows DirectDraw to always revert to software autoflipping when hardware autoflipping is unavailable.
  • Field skipping using an IRQ to support MPEG drivers that can undo the 3:2 pulldown of MPEG data originally sampled from film.
  • Busmastering for devices that want to continuously busmaster data without having to call Lock / Unlock on every frame. This is especially useful in kernel mode since the drivers for these devices exist in kernel mode in WDM.
  • Video and VBI capture. In kernel mode it is easy to capture video based on a video port IRQ or graphics IRQ.

Support for this API is added into the miniVDD.


Kernel-mode Initialization

This topic applies only to Windows 98/Me.

To enable kernel-mode functionality, the DirectDraw HAL must do the following at initialization time:

  1. The HAL must specify a 32-bit function in the DDHALINFO structure that DirectDraw can call to get additional information. This is described in GetDriverInfo.
  2. The 32-bit GetDriverInfo callback is called with the GUID_KernelCallbacks GUID specified. The HAL must fill in a DDHAL_DDKERNELCALLBACKS structure with the appropriate 32-bit HAL callbacks and flags set, then copy this structure to the lpvData member of the input structure.
  3. The 32-bit GetDriverInfo callback is called with the GUID_KernelCaps GUID specified. The HAL must fill in a DDKERNELCAPS structure, then copy this structure to the lpvData member of the input structure.
  4. The miniVDD must support an input/output control (IOCTL) interface. This is done by adding the following code to the control procedure:
    Begin_Control_Dispatch  MiniVDD
    Control_Dispatch W32_DEVICEIOCONTROL, ctrlDeviceIoControl
End_Control_Dispatch MiniVDD

;**************************************************************
;
;   ctrlDeviceIoControl
;
;   DESCRIPTION: This function called to perform Device IO
; for a 32 bit process that has opened this device with
; CreateFile.
;
;   ENTRY:
;        ESI    Ptr to DIOCParams
;        ESI+8  Io control code
;
;   EXIT:
;        EAX    As determined by function or 1 for an
; invalid IOCTL
;
;**************************************************************
public  ctrlDeviceIoControl
BeginProc ctrlDeviceIoControl, RARE

    mov    ecx, [esi+0Ch]
    cmp    ecx, VDD_IOCTL_GET_DDHAL
    jnz    @F
    call   GetDDHAL
@@:
    sub    eax, eax
    ret

EndProc ctrlDeviceIoControl
  5. When DirectDraw is initialized, it sends a VDD_IOCTL_GET_DDHAL IOCTL to the miniVDD. This allows the miniVDD to fill in the provided function table with pointers to functions that kernel-mode DirectDraw can call. The following structure is passed to the miniVDD, which fills it in:
    typedef struct _DDMINIVDDTABLE
{
    DWORD       dwMiniVDDContext;
    MINIPROC    vddGetIRQInfo;
    MINIPROC    vddIsOurIRQ;
    MINIPROC    vddEnableIRQ;
    MINIPROC    vddSkipNextField;
    MINIPROC    vddBobNextField;
    MINIPROC    vddSetState;
    MINIPROC    vddLock;
    MINIPROC    vddFlipOverlay;
    MINIPROC    vddFlipVideoPort;
    MINIPROC    vddGetPolarity;
    MINIPROC    vddSetSkipPattern;
    MINIPROC    vddGetCurrentAutoflip;
    MINIPROC    vddGetPreviousAutoflip;
    MINIPROC    vddTransfer;
    MINIPROC    vddGetTransferStatus;
} DDMINIVDDTABLE;

    The miniVDD can specify a value in the dwMiniVDDContext member that will be passed to the miniVDD each time one of these functions is called. For some miniVDDs, this is useful for multiple monitor support. The following code example could be used to fill in this structure:

    ;************************************************************
;
;   GetDDHAL
;
;   DESCRIPTION: This function fills in the function
;     table supplied by DDRAW with functions that their VxD
;     can call for kernel mode DirectDraw support.  The
;     MiniVDD can fill in the dwMiniVDDContext field with a
;     value that will always be passed back when called.
;
;   ENTRY:
;      ESI      Ptr to DIOCParams
;      ESI+18h  Ptr to output buffer
;      ESI+1Ch  Size of output buffer
;      ESI+20h  Amount of data we write into output buffer
;
;   EXIT:
;      EAX      0 = success
;
;***********************************************************

BeginProc GetDDHAL, RARE

    mov    eax, SIZE _DDMINIVDDTABLE
    cmp    eax, [esi+1Ch]
    jg     GetDDHAL_Error

    mov    ebx, [esi+18h]
    mov    eax, 27h
    mov    [ebx._DDMINIVDDTABLE.dwMiniVDDContext], eax
    mov    eax, OFFSET32 DDGetIRQInfo
    mov    [ebx._DDMINIVDDTABLE.vddGetIRQInfo], eax
    mov    eax, OFFSET32 DDIsOurIRQ
    mov    [ebx._DDMINIVDDTABLE.vddIsOurIRQ], eax
    mov    eax, OFFSET32 DDEnableIRQ
    mov    [ebx._DDMINIVDDTABLE.vddEnableIRQ], eax
    mov    eax, OFFSET32 DDSkipNextField
    mov    [ebx._DDMINIVDDTABLE.vddSkipNextField], eax
    mov    eax, OFFSET32 DDBobNextField
    mov    [ebx._DDMINIVDDTABLE.vddBobNextField], eax
    mov    eax, OFFSET32 DDSetState
    mov    [ebx._DDMINIVDDTABLE.vddSetState], eax
    mov    eax, OFFSET32 DDLock
    mov    [ebx._DDMINIVDDTABLE.vddLock], eax
    mov    eax, OFFSET32 DDFlipOverlay
    mov    [ebx._DDMINIVDDTABLE.vddFlipOverlay], eax
    mov    eax, OFFSET32 DDFlipVideoPort
    mov    [ebx._DDMINIVDDTABLE.vddFlipVideoPort], eax
    mov    eax, OFFSET32 DDGetFieldPolarity
    mov    [ebx._DDMINIVDDTABLE.vddGetPolarity], eax
    mov    eax, OFFSET32 DDSetSkipPattern
    mov    [ebx._DDMINIVDDTABLE.vddSetSkipPattern], eax
    mov    eax, OFFSET32 DDGetCurrentAutolfip
    mov    [ebx._DDMINIVDDTABLE.vddGetCurrentAutoflip], eax
    mov    eax, OFFSET32 DDGetPreviousAutoflip
    mov    [ebx._DDMINIVDDTABLE.vddGetPreviousAutoflip], eax
    mov    eax, OFFSET32 DDTransfer
    mov    [ebx._DDMINIVDDTABLE.vddTransfer], eax
    mov    eax, OFFSET32 DDGetTransferStatus
    mov    [ebx._DDMINIVDDTABLE.vddGetTransferStatus], eax

    mov    ebx, [esi+20h]
    mov    eax, SIZE _DDMINIVDDTABLE
    mov    [ebx], eax

    sub    eax, eax
    ret

GetDDHAL_Error:
    mov    eax, 1
    ret

EndProc GetDDHAL

For reference information on the kernel-mode DirectDraw functions, see Kernel-Mode MiniVDD Functions.


Windows 98/Me Video VBI Capture

This topic applies only to Windows 98/Me.

Beginning with DirectX 5.2, DirectDraw contains two new HAL functions for Windows 98/Me in the miniVDD for video vertical blanking interval (VBI) capture: vddTransfer and vddGetTransferStatus.

The vddTransfer function facilitates video and VBI capture. Because this function is called at IRQ time, the driver must call vddTransfer and return as quickly as possible. If the display hardware is not ready to do a bus master at the time vddTransfer is called, then the driver should keep an internal queue of a number of bus masters (the actual number of bus masters saved in the queue is up to the driver developer). This allows the hardware to perform the bus master when the hardware is ready. In other words, the driver should not poll and wait for the bus master to complete.

When DirectDraw calls the vddTransfer function, it returns a transfer ID in the dwTransferID member of the DDTRANSFERININFO structure. The driver can then use this identification when calling the vddGetTransferStatus function.

When the bus master completes, the driver must generate an IRQ. DirectDraw then calls an IRQ handler that calls the vddIsOurIRQ function. The driver must then return a DDIRQ_BUSMASTER flag. This indicates that it is indeed the driver's IRQ and it is a bus master completion IRQ. DirectDraw then calls the vddGetTransferStatus function to determine which bus master completed. The driver must return the transfer ID (dwTransferID) that DirectDraw passed to the driver earlier. In this way, if the driver has five bus masters in the queue, DirectDraw can determine which one completed most recently.


Extended Surface Alignment

Microsoft® DirectDraw® supports surface alignment requirements on a per-heap basis. This support was introduced in Microsoft DirectX® 5.0. The driver can specify X and Y alignments for rectangular heaps, and pitch and start-offset alignments for linear heaps. These alignments can vary for different surface types.

Some display hardware cannot set its start-of-display offset in an atomic operation. At the beginning of a display period, it is possible for such hardware to latch a new start-of-display offset when the driver is only halfway through setting the value. DirectDraw now allows the driver to specify alignment requirements for visible back buffers. Some hardware may be able to express alignment requirements for potentially visible back buffers that force the start-of-display offset to be a value that requires only one register write. This technique can help avoid the occasional flicker that would otherwise be visible when the primary surface is flipped at a high frequency.


Review of the Older Alignment Method

Versions of DirectDraw before DirectX 5.0 allowed the driver to express pitch alignment requirements for linear heaps. For the purposes of this discussion, use of these alignment requirements by DirectDraw can be seen in three steps:

  1. Create the surface and fill in an aligned lPitch member based on the driver's global alignment requirements (as returned in the VIDEOMEMORYINFO structure) and the surface's ddsCaps member. This pitch is increased until it is a multiple of the appropriate alignment requirement.
  2. Call the driver's DdCreateSurface callback, if defined. The driver can modify the lPitch value, but this change will be ignored by Microsoft® Windows® 2000 and later.
  3. If the driver call is not handled, or if it requests allocation, allocate display memory for the surface from one of the driver's heaps. The width of the allocated surface is taken to be the aligned pitch determined in step 1, unless modified by the driver in step 2.

If a driver implemented the DdCreateSurface callback, it could be assured that any incoming surface would have its lPitch member set to an aligned value. For backward-compatibility, this behavior still exists. Step three maintains exactly the same behavior, unless the driver has exposed a GetHeapAlignment entry point. If, and only if, this entry point is defined, the previously calculated lPitch alignment is discarded, and all surface alignment conforms to the requirements reported using GUID_GetHeapAlignment. Drivers can keep their VIDEOMEMORYINFO structure alignment requirements as they are, and expect the same alignment behavior when run on older DirectDraw run-times. This alignment behavior has been completely replaced for new (DirectX 5.0 and later versions) DirectDraw run-times. It should be noted that exposing GetHeapAlignment turns off this legacy alignment procedure for all heaps, not just those for which GUID_GetHeapAlignment reports alignment requirements.


Using Extended Surface Alignment

To enable the extended surface alignment functionality, the DirectDraw driver must perform the following tasks at initialization time:

  • The driver must specify a DdGetDriverInfo function in the DD_HALINFO structure that DirectDraw can call to get additional information.
  • The DdGetDriverInfo callback is called with the GUID_GetHeapAlignment GUID specified. The driver must fill in a DD_GETHEAPALIGNMENTDATA structure, then copy this structure to the lpvData member of the DD_GETDRIVERINFODATA structure.

The driver should fill in the DDSCAPS structure pointed to in the HEAPALIGNMENT structure with the logical OR of the DDSCAPS_xxxx flags for any type of surface that requires alignment in this heap. If a bit in DDSCAPS is set, then DirectDraw will abide by the alignment restrictions expressed in the appropriate SURFACEALIGNMENT structure member. The DDSCAPS_FLIP bit and the FlipTarget member apply to surfaces that are back buffers in the primary flipping chain, that is, a potentially primary (visible) surface. The following list shows the currently allowed set of surface capabilities for which alignment can be specified:

  • DDSCAPS_OFFSCREENPLAIN
  • DDSCAPS_EXECUTEBUFFER
  • DDSCAPS_OVERLAY
  • DDSCAPS_TEXTURE
  • DDSCAPS_ZBUFFER
  • DDSCAPS_ALPHA
  • DDSCAPS_FLIP

Note DirectDraw compares a new surface's capabilities against the entries in the HEAPALIGNMENT structure in the order in which they are specified. For example, a surface with DDSCAPS_MIPMAP | DDSCAPS_TEXTURE | DDSCAPS_FLIP set is aligned according to the Texture member of the HEAPALIGNMENT structure, since this is the first applicable capabilities bit for which an alignment is specified (that is, Texture appears before FlipTarget in the HEAPALIGNMENT structure). The FlipTarget member is not considered in this example. Since back buffers in a primary flipping chain are marked with DDSCAPS_FLIP and no other bit for which an alignment can be specified, such surfaces are aligned according to the FlipTarget member. Surfaces that could potentially become members of a primary flipping chain (those with the same pixel format and size as the primary surface) are also aligned according to the FlipTarget member.


Extended Surface Capabilities

Beginning with Microsoft® DirectX® 6.0, Microsoft DirectDraw® contains surface capabilities beyond those found in previous versions. These extended capabilities require the addition of several new structures, specifically the DDSCAPS2 and DD_MORESURFACECAPS structures. The DDSCAPS2 structure contains the dwCaps member originally found in the DDSCAPS structure, but also contains three new members: dwCaps2, dwCaps3, and dwCaps4. Only dwCaps2 is used in DirectDraw for DirectX 6.0. The last three members of the DDSCAPS2 structure are also identically arranged in the DDSCAPSEX structure.


New Surface Capabilities

The new surface capabilities added to DirectDraw in DirectX 6.0 and above are made visible to the driver when the application sets the appropriate flags in the dwCaps2 member of the DDSCAPS2 structure.

Applications can only set the DDSCAPS2_HARDWAREDEINTERLACE flag in conjunction with the DDSCAPS_OVERLAY flag. If a driver sees this flag set at CreateSurface time, it means that DirectDraw expects that the driver will do whatever is necessary to match the hardware video port frame rate with the device frame rate.

The DDSCAPS2_HINTDYNAMIC, DDSCAPS2_HINTSTATIC, and DDSCAPS2_OPAQUE flags are hints set by the application at CreateSurface time that inform the driver what the application plans to do with the surface. The DDSCAPS2_HINTDYNAMIC flag means that the application will be updating the surface frequently. The DDSCAPS2_HINTSTATIC flag means that the application will be updating the surface rarely, but still requires access. This means the driver must be able to allow locks on the surface, which may involve some hidden decompression and compression steps. The DDSCAPS2_OPAQUE flag means that the application will never lock, blt, or update the surface for the rest of that surface's lifetime. The driver is free to compress or reorder the surface without having to ever decompress it.

Note The driver does not need to set these flags to enable them. DirectDraw merely passes these bits to the driver when DdCreateSurface is called.

Driver writers might want to use the extended heap restriction features (described in Extended Heap Restrictions) of DirectDraw to automatically place DDSCAPS2_OPAQUE textures in optimized heaps. This is entirely up to the driver developer.

The DDSCAPS2_HINTDYNAMIC, DDSCAPS2_HINTSTATIC, and DDSCAPS2_OPAQUE flags are described in more detail in the Microsoft Direct3D® DDK documentation.

The DDSCAPS2_TEXTUREMANAGE flag is not relevant to drivers. This flag informs the Direct3D run-time that it is responsible for moving the surface from a backing surface to display memory, as appropriate, to enable accelerated 3D texturing.


Exposing the Extended Surface Capabilities

The DDCORECAPS structure contains a DDSCAPS field which drivers fill in to indicate what types of surfaces they support. When these caps are reported to the application, a slightly different structure, DDCAPS, is returned. This DDCAPS structure is built from the driver's DDCORECAPS and other structures which are queried using the DdGetDriverInfo interface. For DirectX 6.0, the application-visible DDCAPS contains a DDSCAPS2 member. This DDCAPS2 member is constructed from the DDSCAPS member in the DDCORECAPS structure, and the ddsCapsMore member of the DD_MORESURFACECAPS structure.

The DD_MORESURFACECAPS structure is queried from the driver at driver initialization time using the DdGetDriverInfo call. The appropriate GUID, as defined in ddrawint.h, is GUID_DDMoreSurfaceCaps.

Responding to the GUID_DDMoreSurfaceCaps query is entirely optional. It is intended to allow drivers to do two distinct things:

  • Expose new surface capabilities that the driver can create in display memory.
  • Express to DirectDraw new heap restrictions for these new surface capabilities.

The first item has been covered in the previous section and is fairly self-explanatory. The second item is more complex, and readers should be familiar with the significance of the ddsCaps and ddsCapsAlt members of the VIDEOMEMORY structure, described in Memory Heap Allocation, before reading the next section.


Extended Heap Restrictions

The DD_MORESURFACECAPS structure is of variable size. It always has a ddsCapsMore member, but it may have zero or more ddsExtendedHeapRestrictions entries. If the driver responds to the GUID_DDMoreSurfaceCaps query, it should return a DD_MORESURFACECAPS structure that contains as many ddsExtendedHeapRestrictions entries as it returned display memory heaps in the DD_HALINFO structure (DirectDraw guarantees that the GUID_DDMoreSurfaceCaps query is made after the driver reports DD_HALINFO.)

The driver should also fill in an appropriate dwSize value in the DD_MORESURFACECAPS structure. The value of dwSize is calculated in this way:

DDMORESURFACECAPS.dwSize =
          (DWORD) (sizeof(DDMORESURFACECAPS)
        + (((signed int)DDHALINFO.vmiData.dwNumHeaps) - 1)
        * sizeof(DDSCAPSEX)*2 );

Note that subtracting 1 from the value of dwNumHeaps is necessary to account for the fact that the DD_MORESURFACECAPS structure has a ddsExtendedHeapRestrictions member that is a one-element array. Only those array elements after the first (that is, from ddsExtendedHeapRestrictions[1] on) should be counted in calculating the total size of the DD_MORESURFACECAPS structure.

The ddsCapsEx and ddsCapsExAlt members are exactly analogous to the ddsCaps and ddsCapsAlt members of the array of VIDEOMEMORY structures returned in the pvmList member of the VIDEOMEMORYINFO structure, which is contained as a member of the DD_HALINFO structure. Any bit set in ddsCapsEx means that surface with that bit set must not be placed in that heap. Any bit set in the ddsCapsExAlt member means that the surface cannot be placed in that heap. When allocating surfaces, DirectDraw first passes through all heaps, and if it finds any heap for which no capability bits in the ddsCaps member of the VIDEOMEMORY structure match with the DDSCAPS bits of the surface, it will allocate the surface in that heap. If this pass finds no such heaps, then DirectDraw will make the same pass but check the ddsCapsEx field. If this pass fails to find any heaps, then the surface cannot be created in any heap.


Extended Surface Description Structure

The extended DirectDraw surface description structure, DDSURFACEDESC2, is identical to the DDSURFACEDESC structure, except that the pointer to the DDSCAPS structure at the end of the structure has been replaced with a pointer to a DDSCAPS2 structure.

The data blocks for the DdCreateSurface and DdCanCreateSurface driver calls each contain a pointer to a DDSURFACEDESC structure. As of DirectX 6.0, these pointers might actually point to a DDSURFACEDESC2 structure, even though the pointers remain typed as LPDDSURFACEDESC. If a driver chooses, it can examine the dwSize member of the DDSURFACEDESC pointer, and thereby decide if the pointer actually points to a DDSURFACEDESC2 structure. If your driver must run on pre-DirectX 6.0 installations, it must make this check.

If the size returned is sizeof(DDSURFACEDESC2), the driver can then examine the dwCaps2, dwCaps3, and dwCaps4 members of the DDSCAPS2 structure.


Compressed Texture Surfaces

A surface can contain a bitmap to be used for texturing 3D objects. To reduce the amount of memory consumed by textures, Microsoft® DirectDraw® supports the compression of texture surfaces.

Note No new callbacks have been added to support compressed texture surfaces. DirectDraw passes information about compressed texture surfaces to the driver through the existing driver callbacks.

FOURCC | Description | Alpha premultiplied?
DXT1 | Opaque / one-bit alpha | N/A
DXT2 | Explicit alpha | Yes
DXT3 | Explicit alpha | No
DXT4 | Interpolated alpha | Yes
DXT5 | Interpolated alpha | No

The preceding shows the five types of compressed textures that drivers should support.

For more information on the format of compressed textures, see the heading, Compressed Texture Formats, in the DirectDraw SDK documentation.


Enumerating DXT Formats

In Microsoft DirectX®, there are two ways for your driver to enumerate pixel formats. The first method enumerates formats that can be used for textures. This method is implemented using the lpTextureFormats member of the D3DHAL_GLOBALDRIVERDATA structure. The second method enumerates formats that can be used for either DDSCAPS_OVERLAY surfaces or DDSCAPS_OFFSCREENPLAIN surfaces. The second method uses the dwNumFourCCCodes member of the DDCORECAPS structure included in the DD_HALINFO structure and the lpdwFourCC array that is also included in the DD_HALINFO structure.

Since DXT formats are primarily intended to be used as textures, your driver will enumerate DXT formats only through the first method. There is no need to add DXT formats to the lpdwFourCC array.


Creating the Compressed Texture Surface

Whenever DirectDraw requests the driver to create a surface, the driver must determine whether it is being asked to create a compressed texture surface. To determine this, the driver must check for information that has previously been set by DirectDraw in the DDSURFACEDESC2 structure for the surface being created. Your driver must include the following verification steps (as with any surface):

  • Check for the DDSCAPS_TEXTURE flag in the dwFlags member of the DDSCAPS structure.
  • Check for the DDPF_FOURCC flag in the dwFlags member of the DDPIXELFORMAT structure for the surface being created. This check should before the following dwFourCC check.
  • Check for one of the DXT codes in the dwFourCC member of the DDPIXELFORMAT structure for the surface being created.
  • Check the width and height members (dwWidth and dwHeight) of the DDSURFACEDESC2 structure. DirectDraw sets these members to multiples of 4 pixels.


Using Compressed Texture Surfaces

DirectDraw will only call the driver to do a blt between two surfaces of the same DXT type if the DDCAPS2_COPYFOURCC flag is set in the dwCaps2 member of the DDCORECAPS structure. If this flag is not set, the DirectDraw HEL will perform the blt. This is most important for backing surface-to-display copy blts, since this is the mechanism whereby textures are downloaded from backing surfaces to display memory. Thus, exposing DXT texture surfaces effectively requires your driver to support the DDCAPS2_COPYFOURCC flag.

The DDCAPS2_COPYFOURCC flag has some additional implications. Your driver must be able to execute a blt between FourCC formats having at least these attributes:

  • The source and destination formats are the same FourCC format.
  • The source and destination surfaces are different.
  • The source and destination rectangles both make up the entire surface (that is, there is no stretching, and there are no sub-rectangles).
  • Both surfaces are in display memory.
  • The driver must be able to perform these blts for every FourCC format it supports in display memory.

Note Microsoft® DirectShow® uses the DDCAPS2_COPYFOURCC flag to accelerate some video functionality, hence the requirement for this flag implies that all FourCC formats can be copied.

If a blt operation requires compression to a DXT format, the DirectDraw HEL always performs the blt. This means that DirectDraw will never request the driver to perform a blt for which:

  • The destination surface has a DXT format.
  • The formats for the source and destination surfaces are not the same.

The semantics of the DirectDraw DDCAPS_CANBLTSYSMEM capability bit imply that the display driver will be called for all blts from system memory to display memory. Consequently, the driver may be called for such blts from DXT surfaces to non-DXT surfaces. The only requirement in this case is that the driver return DDHAL_DRIVER_NOTHANDLED if it cannot perform the decompression. This will cause DirectDraw to propagate a DDERR_UNSUPPORTED error code to the application. It is acceptable to implement decompression for blts from system memory to display memory in your driver, but this is not required for DirectX 6.0.

DirectDraw display memory allocation routines do not handle pixel format considerations. HeapVidMemAllocAligned, for instance, expects a count of bytes as its input parameter. Likewise, DDHAL_PLEASEALLOC_BLOCKSIZE (see the fpVidMem member of the DD_SURFACE_GLOBAL structure) signifies that the dwBlockSizeX and dwBlockSizeY members of the DD_SURFACE_GLOBAL structure are counts of bytes and lines, respectively. Consequently, if your driver uses either of these mechanisms to allocate display memory through DirectDraw allocators, your driver needs to be able to calculate the memory consumption, in bytes, of a DXT surface by itself. The following sample shows one way to perform this calculation:

DWORD dx, dy;
DWORD blksize, surfsize;
LPVOID pmem;

/*
 * Determine how much memory to allocate for the FourCC format.
 */
switch ((int)pDDPF->dwFourCC)
{
  case MAKEFOURCC('D','X','T','1'):
    blksize = 8; // The size of a DXT1 4x4 pixel block.
    break;
  case MAKEFOURCC('D','X','T','2'):    // premultiplied alpha
  case MAKEFOURCC('D','X','T','3'):    // non-premultiplied alpha
    blksize = 16; //The size of a DXT2,3 4x4 pixel block
    break;
  case MAKEFOURCC('D','X','T','4'):    // premultiplied alpha
  case MAKEFOURCC('D','X','T','5'):    // non-premultiplied alpha
    blksize = 16; //The size of a DXT4,5 4x4 pixel block.
    break;

  default:
    DDASSERT(0);
}

/*
 * Calculate the number of blocks in the x and y dimensions.
 */
dx = (nWidth  + 3) >> 2;
dy = (nHeight + 3) >> 2;
surfsize = dx * dy * blksize;

When the application calls the IDirect3DVertexBuffer7::Lock or IDirectDrawSurface7::GetSurfaceDesc methods (described in the Direct3D and DirectDraw SDK documentation sets, respectively) on a compressed surface, the driver must set the DDSD_LINEARSIZE flag in the dwFlags member of the DDSURFACEDESC2 structure. In addition, the driver must set the number of bytes allocated to contain the compressed surface data in the dwLinearSize member of the same structure. (The dwLinearSize member resides in a union with the lPitch member, so these members are mutually exclusive, as are the DDSD_LINEARSIZE and DDSD_PITCH flags.)

Your hardware or driver can convert and store the compressed texture in any format you choose (typically a reordering into a more hardware-efficient layout). However, your hardware or driver must be able to convert the compressed texture back to its original DXT code format whenever DirectDraw requires it; that is, whenever the application calls the IDirect3DVertexBuffer7::Lock method.

Windows® 2000 Note

Under Windows 2000, system memory DXT surfaces will have had some of their fields mapped for memory allocation purposes. The mapping is:

wWidth = lPitch = dx * blksize;
wHeight         = dy;
dwRGBBitCount   = 8;

When the driver encounters a system memory DXT surface, for example in D3dCreateSurfaceEx, it must map the fields back before making use of them. The back mapping is:

realWidth        = (wWidth  << 2) / blksize;
realHeight       =  wHeight << 2;
realLinearSize   = dwLinearSize * wHeight;
realRGBBitCount  = 0

RefRast Notes

In the past there has been some disagreement between the reference rasterizer (RefRast) and this documentation. This has shown up in three areas:

  1. The DXT4 and DXT5 formats in the RefRast ramped the Alpha values in the opposite order as shown in the documentation. Note that the section entitled 3-Bit Linear Alpha Interpolation (DXT4 and DXT5 format) in the DirectDraw SDK documentation is correct.
  2. The RefRast did not have the following logic guarding the color comparison logic. This was an error in RefRast.
    if ((color_0 > color_1) OR !DXT1) {
/*  color comparison logic */
}
  3. The RefRast added rounding to the calculations in order to better approximate the original value. Since then, several hardware implementations have performed the rounding in slightly different ways. Since this was not previously clarified, testing should allow for slight variations in the color and alpha values obtained from the decompression logic.

Unaltering Compressed Texture Surfaces

[This is preliminary documentation and subject to change.]

The width and height of a compressed-texture surface are altered by the user-mode runtime to force the kernel-mode runtime to allocate the appropriate amount of video memory space. The display driver must reverse this alteration.

Whenever the DirectDraw runtime calls the driver's D3dCreateSurfaceEx function to create a compressed-texture surface, the driver must recompute the width and height of the surface and restore them to their unaltered state. If the driver does not perform this restoration, subsequent operations that are performed on these surfaces could fail.

So we need to document that for DXT surfaces, the display driver needs to recompute everything in the CreateSurfaceEx call for sysmem surfaces. Here is the relevant data. When CreateSurfaceEx is called:

Width and pitch contain the number of 4x4 blocks in a row multipled by the block size.

Height contains the number of 4x4 blocks in the column.

So, the driver needs to do the following calculation:

RealHeight = Height * 4;

RealWidth = (Width / Block size) * 4

I'd put it in the "Compressed Texture Surfaces" part. Please include a note that it's an NT-only issue. This munging doesn't happen on win9x systems.

Also, it should be clear in the docs that the driver should fix up the kernel's surface structure (the DD_SURFACE struct) with the re-calculated width and height. This prevents the kernel-mode ddraw part from rejecting DXT texture download blts because the rects won't match (i.e. if the driver leaves the DD_SURFACE with the broken size, kernel will reject a blt from that broken sysmem surface to the vidmem surface because the source rect (which is in un-broken coordinates) will seem to be "outside" the broken DD_SURFACE size)


DirectX Compressed VolumeTexture Formats

Volume textures maps are digitized images that are generated periodically through a true 3D region of space. For example, a ball of fire may be sampled and the "amount" of flame within a slice can be accounted for. In this sense, the amount of flame would mean a set of values for the Alpha, Red, Green and Blue components at each pixel in the image. The entire flame would be represented by a series of these slices.

Before going into details of DirectX volume rendering, it is important to clarify some terminology. It should be noted that there are two common methods used in computer graphics to represent volume data sets. One is to sample the image at each location and store the appropriate ARGB values. For example, data for the flame could be stored as a 256 X 256 X 256 three-dimensional array. This would require about 64MB to store a 32 bit value at each location in the array. (Some applications, such as medical imaging, may require this amount of data!) However, "slicing" the flame into 4 or 8 slabs can make a very good approximation. Each slab would store 256X256 elements, where each element would represent a region of data within the slab. If we assume an array of size 256 X 256 X 4 is reasonable, then storing a 32-bit value at each location would require only 1MB of storage (less if the data is compressed). The reason to talk about these two different methods is that if you want anything in your image that is behind the flame to be hidden, then the data value stored at each location would be different. In the full 256 X 256 X 256 data set, any one element may contribute about 1/256 of the final alpha and color. In the slicing method, an element could contribute anywhere from 0 up to the final alpha and color used for that pixel. The problem is that sometimes the term "voxel" is used to describe both types of sampling. Care should be taken to realize that starting with DirectX 8, the slicing method, often called "Volume Texturing" is the only method supported. The idea is to reduce the volume data set to a reasonable size. With some minor modifications to the texturing hardware, the DirectX graphics API can expose high-performance volumetric rendering.

Up to this point, most of this section has focused on DXTN compressed surface formats. These formats work well for 2D textures. They are inefficient, however, when you are working with a volume data set. The inefficiency is due to the fact that volume data sets would be stored in separate surfaces that would require extra hardware cycles to access. To address this issue, DirectX 8 supports a set of Volume surface formats.

The idea is to take the volume slices and compress then using DXTN. Then, instead of storing the completed surfaces sequentially in memory, the DXTN data blocks are reordered. The reordering is done so that the small 4X4 texel blocks form data cubes. They can be 4X4X1, 4X4X2, 4X4X3, or 4X4X4. Note that the 4X4X1 ordering is exactly the same as that used in DXT1 through DXT5. The important point is:

Volume surfaces are slices of data that are compressed using DXTN and then reordered to account for the 3D locality of data. These reordered data structures are referred to by the FOURCC codes of DXV1,..., DXV5 (or just DXVN to describe the general case). Note that a DXV1 data structure would hold a set of reordered DXT1 surfaces, DXV2 would hold a set of DXT2 surfaces, and so on.

DXVN Details

A DXVN surface stored in the 1-deep arrangement contains one set of 4x4 DXTN subblocks (in effect it is just a DXTN surface). The DXVN 4x4x2 block format structure contains two 4x4 DXTN subblocks, one taken from each of two adjacent data slices. Using this method it is obvious that a DXVN 4x4x4 block format structure contains four 4x4 DXTN subblocks taken from 4 data slices. Note that in all cases the N in DXVN is used to match it to the corresponding DXTN type used for compression. (Note that DXTN blocks can be stored as 64 bits (color and 1-bit alpha, or 128 bits with additional alpha information.) So the DXVN subblocks will have the same possible sizes based on the type N. (That is, DXT1 and DXV1 use 64 bit subblocks, while DXT2,..,DXT5 and DXV2,..,DXV5 use 128 bit subblocks.)

Given a texel coordinate (u, v, p) where u {0,1,…,width-1}, v {0, 1, …, height-1}, and p {0, 1, …, depth-1}, the following can be used to compute the corresponding address of the compressed block and subblock in memory containing that texel. As mentioned above, the subblock format matches the existing DXTN format;

subblock_size = 8 (for DXT1)
subblock_size = 16 (for DXT2,...,DXT5)
block_size = MIN(p, 4) * subblock_size
horiz_stride = (width + 3) >> 2
planar_stride = ( (height + 3) >> 2) * horiz_stride
block_byte_address = block_size *
    ( (p >> 2) * planar_stride + (v >> 2) * horiz_stride + (u >> 2) )
subblock_byte_address = block_byte_address + ((p & 3) * subblock_size)


Motion Compensation

Motion compensation is the term for an important stage of the decoding process for compressed digital video. Many graphic accelerator devices provide some type of acceleration capability for supporting compressed video decoding. Because the motion compensation process is the most frequently supported part of video decoding, the device driver interface that supports compressed video decoding is called the motion compensation DDI. In addition to motion compensation, some devices can perform IDCT (Inverse Discrete Cosine Transformation) and other hardware functions that a software video decoder can use to accelerate the decoding process. The motion compensation DDI is flexible enough to handle devices that provide these other capabilities as well.

The input data to a software MPEG decoder is well defined. If the decoder is designed for MPEG-2, the input is in MPEG-2 format. The output of the decoder is also well defined. It is an uncompressed frame in a variety of formats. However, the interim formats between the software decoders and the display devices are not well defined, with many devices requiring their own proprietary data formats. Therefore, the motion compensation device driver interface is flexible and the interim formats are described as GUIDs. The display driver reports the GUIDs that represent the capabilities it supports, and the software decoder chooses the GUID which best matches its requirements.

To enable motion compensation functionality, the driver must perform the following steps:

  • Implement a DdGetDriverInfo function and set the GetDriverInfo member of the DD_HALINFO structure to point to this function when DrvGetDirectDrawInfo is called. The driver's DdGetDriverInfo function must parse the GUID_MotionCompCallbacks GUID.
  • Fill in a DD_MOTIONCOMPCALLBACKS structure with the appropriate driver callback pointers and callback type flags set when the DdGetDriverInfo function is called with the GUID_MotionCompCallbacks GUID. The driver must then copy this initialized structure into the Microsoft® DirectDraw®-allocated buffer to which the lpvData member of the DD_GETDRIVERINFODATA structure points, and return the number of bytes written into the buffer in dwActualSize.


DirectX Video Acceleration

DirectX Video Acceleration is a technology that aids in the acceleration of digital video decoding processing. Please see DirectX Video Acceleration for more details about accelerating digital video decoding processing.

DirectX Video Acceleration makes use of the following Motion Compensation callback functions provided in DirectDraw drivers for acceleration of digital video decoding processing, with support of alpha blending for such purposes as DVD subpicture support:

Callback Function | Purpose
DdMoCompBeginFrame | Starts decoding a new frame.
DdMoCompCreate | Notifies the driver that a software decoder will start using motion compensation with the specified GUID.
DdMoCompDestroy | Notifies the driver that this motion compensation object will no longer be used. The driver now needs to perform any necessary cleanup.
DdMoCompEndFrame | Completes a decoded frame.
DDMoCompGetBuffInfo | Allows the driver to specify how many interim surfaces are required to support the specified GUID, and the size, location, and format of each of these surfaces.
DdMoCompGetFormats | Indicates the uncompressed formats to which the hardware can decode the data.
DdMoCompGetGuids | Retrieves the number of GUIDs the driver supports.
DdMoCompGetInternalInfo | Allows the driver to report that it internally allocates display memory to perform motion compensation.
DdMoCompQueryStatus | Queries the status of the most recent rendering operation to the specified surface.
DdMoCompRender | Specifies the surfaces containing the macroblocks, the offsets in each surface where the macroblocks exist, and the size of the macroblock data to be rendered.

This section contains a description of the Motion Compensation device driver side of the DirectX VA interface. The following steps show how entries are accessed through the DD_MOTIONCOMPCALLBACKS structure:

  1. At the start of the relevant processing, the device driver's DdMoCompCreate notifies the driver that the software decoder will start using a video acceleration object.
  2. GUIDs received from IAMVideoAccelerator::GetVideoAcceleratorGUIDs originate from the device driver's DdMoCompGetGUIDs.
  3. A call to the downstream input pin's IAMVideoAccelerator::GetUncompFormatsSupported returns data from the device driver's DdMoCompGetFormats.
  4. The DXVA_ConnectMode data structure from the decoder's IAMVideoAcceleratorNotify::GetCreateVideoAcceleratorData is passed to the device driver's DdMoCompCreate.
  5. Data returned from IAMVideoAccelerator::GetCompBufferInfo originates from the device driver's DdMoCompGetBuffInfo.
  6. Buffers sent using IAMVideoAccelerator::Execute are received by the device driver's DdMoCompRender.
  7. Use of IAMVideoAccelerator::QueryRenderStatus invokes the device driver's DdMoCompQueryStatus. A return code of DDERR_WASSTILLDRAWING from DdMoCompQueryStatus will be seen by the host decoder as a return code of E_PENDING from IAMVideoAccelerator::QueryRenderStatus.
  8. Data sent to IAMVideoAccelerator::BeginFrame are received by the device driver's DdMoCompBeginFrame. A return code of E_PENDING is needed from DdMoCompBeginFrame in order for E_PENDING to be seen by the host decoder in response to IAMVideoAccelerator::BeginFrame.
  9. Data sent to IAMVideoAccelerator::EndFrame are received by the device driver's DdMoCompEndFrame.
  10. At the end of the relevant processing, the device driver's DdMocompDestroy is used to notify the driver that the current video acceleration object will no longer be used, so that the driver can perform any necessary cleanup.


Gamma Control

Beginning with DirectX 6.0, DirectDraw offers applications a way of specifying gamma tables that are applied to the DirectDraw device. Gamma ramp support was added to Windows 98/Me so that applications can modify the device color mapping in HiColor and TrueColor modes. Driver writers are encouraged to add this facility to their drivers, because it can be used by both DirectDraw and advanced gamma-correcting software.

Note Gamma ramp capabilities are implemented as part of the GDI display driver, not the 32-bit HAL. In addition, the information provided here applies only to Windows 98/Me, but not to Windows 2000 and later.

DirectDraw calls the driver through the SetDeviceGammaRamp SDK function. If the call is successful, DirectDraw sets the DDCAPS2_PRIMARYGAMMA flag in the dwCaps2 member of the DDCORECAPS structure.

Your display driver needs to perform the following steps:

  1. Set the C1_GAMMA_RAMP flag in the dpCaps1 member of the GDIINFO structure. C1_GAMMA_RAMP and GDIINFO are both defined in the Windows DDK, in file \winddk\inc\win_me\inc16\gdidefs.inc.
  2. Write an OEMGammaRamp function, which is prototyped as follows (you do not need to call it OEMGammaRamp; this is a pseudoname used in this documentation):
cProc   OEMGammaRamp,<FAR,PUBLIC,WIN,PASCAL>,<es,si,di>
        parmD   lpDev
        parmW   fGetSet          ;determine get/set flag
        parmD   lpGammaRamp      ;pointer to a set of three arrays

The lpDev parameter is used in all other exports and is documented elsewhere.

The fGetSet parameter determines whether you should return the current gamma ramp or set a new one. If fGetSet == 0, then set the gamma ramp specified in lpGammaRamp; otherwise, return the current gamma ramp in lpGammaRamp.

The lpGammaRamp parameter is a pointer to an array of 768 16-bit WORDs containing the new gamma ramp values, or a buffer to return the current values (depending on the value of fGetSet). The first 256 entries define the red gamma values, the next 256 define the green gamma values, and the last 256 entries define the blue gamma values. The gamma values range between 0 and 65535.

  3. Export the OEMGammaRamp function as ordinal 32 in the display driver .DEF file.

The OEMGammaRamp function returns a WORD containing either 1 for success or 0 for an error. This value is returned directly to the application. The function cannot return -1 for simulation; there is no simulation.

Note DIBENG does not implement this function, so do not try to pass it on.

Your driver must ensure that this device driver interface is safe to call between BeginScene and EndScene calls. Do not let the system stall waiting for the 3-D hardware. If necessary, fail the call.

DirectX 6.0 handles saving and restoring the gamma values for full-screen applications; your driver should not do this. However, your driver (and miniVDD) needs to restore the gamma ramp values when an MS-DOS box is deactivated (ResetHiResMode). Your driver also needs to restore the gamma values to appropriate defaults when a full-screen VM gets the focus.

Your driver does not need to set the DDCAPS2_PRIMARYGAMMA flag. DirectDraw will detect your driver's support for OEMGammaRamp and set this flag automatically.

The DDCAPS2_CANCALIBRATEGAMMA flag is not directly relevant to display drivers. This bit means that DirectDraw can modify gamma ramp tables to account for the physical responses of the display subsystem. The driver may see modified gamma ramps, but it needs to take no special action (and in fact will not have any way to know that these ramps have been modified).


Implementing Gamma Ramp Support in a Microsoft Windows Display Driver

OEMs and IHVs who write display drivers can provide a more accurate and positive end-user experience by incorporating support for downloadable gamma ramps. Reasons to support downloadable gamma ramps include:

  • User enjoyment ISVs who create games want the user to have a consistent visual experience regardless of the system being used. Without color management and downloadable gamma ramps, the user is forced to tweak brightness settings, contrast settings, or color adjustments, while hoping to find settings that provide an appealing color environment. Top-tier game ISVs have asked for programmable gamma ramps so their games can appear as intended, including flare effects in games such as the red flash that occurs when the player gets hit in Quake.
  • Accurate online color representation With the strong growth of e-commerce, companies making products available through online catalogs will require color management capabilities so that online customers can see a product's true colors, minimizing losses due to returns.
  • Color consistency across devices Users want the output of their color images to look very similar to the image on the monitor. Graphics boards with downloadable gamma ramps are a much-needed component of a good color management system.

To improve the customer's color experience on the PC, downloadable gamma ramp support is a requirement for the Microsoft® Windows® Logo Program for hardware. (See the guidelines in PC 98:14.11, "Adapter supports downloadable RAMDAC entries for image color matching.") Both graphics board drivers and the graphics adapters are required to support downloadable gamma ramps, so the original level of red, green, and blue color components for all pixels in a frame buffer can be replaced with calibrated values.

As systems evolve and need to use both 2D and 3D graphics for applications, they will require multiple gamma ramps to provide an enjoyable and repeatable experience. Traditional 3D has a gamma of 1.0, while most images have a range of gammas from 1.8, for Macintosh and Adobe PhotoShop, to 2.2, for standard red, green, blue, (sRGB). When these are mixed on the multimedia desktop, at least two gammas are needed. Microsoft encourages vendors to support multiple programmable gamma ramps.


DirectDraw Support for Gamma Ramps

To allow easier software support for downloadable gamma ramps on the Microsoft Windows 98/Me and Windows 2000 and later operating systems, a gamma interface called IDirectDrawGammaControl has been added to Microsoft DirectDraw®. Available in Microsoft DirectX® 6.0 and later versions, this interface enables game developers to manipulate gamma ramp levels and to tell the system what the perceived gamma on the primary surface in full screen exclusive mode should be. As a result, applications can quickly change the red, green, and blue color components of pixels before they are sent to the digital-to-analog converter (DAC) for display.

You can use either the Microsoft Win32® application programming interface (API) or the IDirectDrawGammaControl interface. There are three significant differences between SetDeviceGammaRamp and the DirectDraw API:

  • SetDeviceGammaRamp does not allow all gamma ramps. It checks the gamma ramp; if it is too complex, such as the red flash when the player is shot in Quake, it rejects the gamma ramp.
  • SetDeviceGammaRamp will not currently make use of a gamma calibrator. This may change in future versions of Image Color Management (ICM), but for Windows 2000, only the DirectDraw API supports the gamma calibrators.
  • The gamma ramp set by DirectDraw is guaranteed to clean up correctly when the application is closed. If an application calls SetDeviceGammaRamp and does not restore the old gamma ramp, it is not automatically cleaned up.

The existing gamma entry points are already used by GetDeviceGammaRamp and SetDeviceGammaRamp. Therefore, the display driver doesn't need to do anything special to support this new interface, as long as it already supports the Win32 Get/SetDeviceGammaRamp functions.

In addition to getting and setting gamma ramps, the new DirectDraw interface allows the new gamma ramp to be calibrated, provided that a gamma calibrator is installed. The mechanism that DirectDraw uses to register and communicate with the gamma calibrator is an interim mechanism that will be changed in future releases.

DirectDraw looks for an installed software calibrator and passes the gamma value to the software calibrator; the software calibrator in turn adjusts the gamma ramp according to the measured response of the monitor. The calibrator passes the gamma ramp back to DirectDraw, which passes it to the SetDeviceGammaRamp device driver interface (DDI). The result is that the game looks as intended.

For DirectDraw to use the gamma calibrator, the calibrator must register itself with DirectDraw using a registry key; DirectDraw will call it if the application wants the gamma ramp to be calibrated.

In the future, both the method by which DirectDraw communicates with the gamma calibrator, through the DDI, and the method gamma calibrators use to register themselves in the registry will change. But every part of the DirectDraw API is permanent.

ICM is the color management system in Windows; all system level color management should be handled by ICM. For this reason, downloadable gamma ramp support will be rolled into ICM in the future, making current solutions for gamma calibrators obsolete. Until such time, we have provided a method by which applications can take advantage of the installed base of software calibrators and graphics adapters that support downloadable gamma ramps.


Using Gamma Controls

To determine whether a specific graphics card and monitor support gamma calibration, call IDirectDraw7::GetCaps and examine the dwCaps2 member of the associated DDCAPS structure. If the DDCAPS2_CANCALIBRATEGAMMA capability flag is present, then gamma calibration is supported.

You can retrieve the IDirectDrawGammaControl interface by querying the surface with the IID_IDirectDrawGammaControl reference identifier. The IDirectDrawGammaControl::GetGammaRamp method retrieves the red, green, and blue gamma ramps for the primary surface.


Setting and Retrieving Gamma Ramp Levels

Gamma ramp levels are effectively lookup tables that DirectDraw uses to map the frame buffer color components to new levels that will be displayed. You set and retrieve ramp levels for the primary surface by calling the IDirectDrawGammaControl::SetGammaRamp and IDirectDrawGammaControl::GetGammaRamp methods.

The first parameter is the pointer to the IDIRECTDRAWGAMMACONTROL structure. The next parameter specifies the flags, which for the IDirectDrawGammaControl::GetGammaRamp call must be 0. For the IDirectDrawGammaControl::SetGammaRamp call, this parameter may be DDSGR_CALIBRATE. If this flag is set, then DirectDraw calibrates the gamma ramp; otherwise, it sets the gamma ramp without calibrating it. The last parameter is the pointer to the DDGAMMARAMP structure that contains three 256-element arrays of WORDs, one array each to contain the red, green, and blue gamma ramps.

Games that use this function should always provide values ranging between 0 and 0xFFFF. DACs vary in resolution; DACs that support fewer than 16 bits will ignore the least significant bits of the gamma ramp entries.

The gamma ramp values that the application calls should range between 0 and 0xFFFF, just as in the SetDeviceGammaRamp and GetDeviceGammaRamp calls. The driver may need to perform some additional converting. For all, the covered range is the same with only a difference in accuracy.


DDIs and APIs Related to Gamma Ramp Support

To add gamma ramp support to your Windows 98/Me driver:

  1. Export DDIGammaRamp as ordinal 32.
  2. Set the C1_GAMMA_RAMP bit in dpCaps1.
  3. Implement DDIGammaRamp.

The functions, methods, and structure in the following list play roles in gamma ramp support.

DDIGammaRamp

GetDeviceGammaRamp

SetDeviceGammaRamp

IDirectDrawGammaControl::GetGammaRamp

IDirectDrawGammaControl::SetGammaRamp

DDGAMMARAMP


DDIGammaRamp

DDIGammaRamp sets the gamma ramp on direct color display boards. The export ordinal for this function is 32.

BOOL
  DDIGammaRamp(
    LPDEVICE  lpDev,
    BOOL  fGetSet,
    LPARAM  lpGammaRamp
    );

Parameters

lpDev
Points to the physical device.
fGetSet
Specifies whether the gamma ramp will be read from or written to. A value of TRUE denotes that the gamma ramp will be written to; a value of FALSE denotes it will be read from.
lpGammaRamp
Points to a set of three arrays, each consisting of 256 WORD (16 bit) elements. These arrays are the mapping between RGB values in the frame buffer and DAC values. The first array holds the red values, the second holds the green values, and the third holds the blue values.

Return Value

DDIGammaRamp returns TRUE if the function is successful. Otherwise, it returns NULL.

Comments

For display adapters that only have 8-bit DACs, the high byte of a given WORD is to be loaded. For adapters that have 12-bit DACs, the high-order 12 bits are used. For 16-bit DACs, the entire WORD is loaded.

Direct color display modes do not use color lookup tables to translate between pixel values and colors, the pixel value is fed directly to the DACs. The direct color modes are usually 16, 24, or 32 bits deep. The display adapter must have hardware to support loadable gamma ramps for the driver to support this function. If the driver does support this function, it must also set the C1_GAMMA_RAMP bit in dpCaps1.

The setting of the display gamma ramp acts globally across all tasks. The gamma ramp is not maintained on a per-application basis. Once set, the gamma ramp does not change until the next set call made by an application. It is expected that users will run a calibration utility to set the gamma ramps when they boot Windows. Arbitrary applications must not set it independently of each other.


GetDeviceGammaRamp

The GetDeviceGammaRamp function gets the gamma ramp on direct color display boards whose drivers support downloadable gamma ramps in hardware.

BOOL WINAPI
  GetDeviceGammaRamp(
    IN HDC  hDC,
    OUT LPVOID  lpRamp
    );

Parameters

hDC
Specifies the device context of the direct color display board in question.
lpRamp
Points to a buffer where the function can place the current gamma ramp of the color display board. The gamma ramp is specified in three arrays of 256 WORD elements each, which contain the mapping between RGB values in the frame buffer and digital-analog-converter (DAC) values. The sequence of the arrays is red, green, blue.

Return Value

GetDeviceGammaRamp returns TRUE if it succeeds, and FALSE otherwise.

Comments

Direct color display modes do not use color lookup tables and are usually 16-, 24-, or 32-bit. Not all direct color video boards support loadable gamma ramps. GetDeviceGammaRamp succeeds only for devices with drivers that support downloadable gamma ramps in hardware.


SetDeviceGammaRamp

SetDeviceGammaRamp sets the gamma ramp on direct color display boards whose drivers support downloadable gamma ramps in hardware.

BOOL WINAPI
  SetDeviceGammaRamp(
    IN HDC  hDC,
    IN LPVOID  lpRamp
    );

Parameters

hDC
Specifies the device context of the direct color display board in question.
lpRamp
Points to a set of three arrays, each consisting of 256 WORD (16 bit) elements. These arrays are the mapping between RGB values in the frame buffer and DAC values. The first array holds the red values, the second holds the green values, and the third holds the blue values.

Return Value

SetDeviceGammaRamp returns TRUE if it succeeds, and FALSE otherwise.

Comments

Direct color display modes do not use color lookup tables and are usually 16-, 24-, or 32-bit. Not all direct color video boards support loadable gamma ramps. SetDeviceGammaRamp succeeds only for devices with drivers that support downloadable gamma ramps in hardware.


IDirectDrawGammaControl::GetGammaRamp

The IDirectDrawGammaControl::GetGammaRamp method retrieves the red, green, and blue gamma ramps for the primary surface.

HRESULT
  IDirectDrawGammaControl::GetGammaRamp(
    THIS_
    DWORD  dwFlags,
    LPDDGAMMARAMP  lpRampData
    ) PURE;

Parameters

dwFlags
Is not currently used and is set to 0.
lpRampData
Address of a DDGAMMARAMP structure to be filled with the new red, green, and blue gamma ramp entries. Each array maps color values in the frame buffer to the color values that will be passed to the DAC.

Return Value

IDirectDrawGammaControl::GetGammaRamp returns DD_OK if it succeeds in retrieving the gamma ramp. If this method fails, it returns one of the following values:

  • DDERR_EXCEPTION
  • DDERR_INVALIDOBJECT
  • DDERR_INVALIDPARAMS


IDirectDrawGammaControl::SetGammaRamp

The IDirectDrawGammaControl::SetGammaRamp method sets the red, green, and blue gamma ramps for the primary surface.

HRESULT
  IDirectDrawGammaControl::SetGammaRamp(
    THIS_
    DWORD  dwFlags,
    LPDDGAMMARAMP  lpRampData
    ) PURE;

Parameters

dwFlags
Indicates whether gamma calibration is desired. Set this parameter to DDSGR_CALIBRATE to request that the calibrator adjust the gamma ramp according to the physical properties of the display, making the result identical on all systems. If calibration is not needed, set this parameter to 0.
lpRampData
Address of a DDGAMMARAMP structure that contains the new red, green, and blue gamma ramp entries. Each array maps color values in the frame buffer to the color values that will be passed to the DAC.

Return Value

IDirectDrawGammaControl::SetGammaRamp returns DD_OK if it succeeds in setting the gamma ramp. If this method fails, it returns one of the following values:

  • DDERR_EXCEPTION
  • DDERR_INVALIDOBJECT
  • DDERR_INVALIDPARAMS
  • DDERR_OUTOFMEMORY

Comments

IDirectDrawGammaControl::SetGammaRamp is a DirectX 6.0 API.

Not all systems support gamma calibration. To determine whether gamma calibration is supported, call IDirectDraw7::GetCaps, and examine the dwCaps2 member of the associated DDCAPS structure after the method returns. If the DDCAPS2_CANCALIBRATEGAMMA capability flag is present, then gamma calibration is supported.

Calibrating gamma ramps incurs some processing overhead and should not be used frequently.

Including the DDSGR_CALIBRATE flag in the dwFlags parameter when running on systems that do not support gamma calibration will not cause this method to fail. The method succeeds, setting new gamma ramp values without calibration.


DDGAMMARAMP

The DDGAMMARAMP structure contains red, green, and blue ramp data for the IDirectDrawGammaControl::GetGammaRamp and IDirectDrawGammaControl::SetGammaRamp methods.

typedef struct _DDGAMMARAMP {
  WORD  red[256];
  WORD  green[256];
  WORD  blue[256];
} DDGAMMARAMP, FAR * LPDDGAMMARAMP;

Members

red
Array of 256 WORD elements that describe the red gamma.
green
Array of 256 WORD elements that describe the green gamma.
blue
Array of 256 WORD elements that describe the blue gamma.


Mapping Gamma Ramp Values to RAMDACs

The RAMDAC uses the buffer (or gamma ramp) as a lookup table before mapping gamma ramp data into the most significant bits of the words. The gamma ramp always expects values in the range 0x0000 to 0xFFFF.

ICM 3.0: The Long-term Solution

As a long-term solution for gamma ramp support, Microsoft plans to add the functionality of the DirectDraw call into the next version of ICM, version 3.0. DirectDraw will continue to support this feature, but when the next version of ICM is complete, ICM will be used for this function instead of the current method of loading the gamma calibrator. Applications won't be affected, but gamma calibrators will.

ICM will be able to control the gamma ramp process without allowing other applications to intercept the gamma ramp adjustment; this will make it easier to display accurate gamma ramps.


Windows Millennium Hibernate Feature

In the process of developing the Windows® Millennium (Windows Me) hibernate feature, Microsoft found that many display adapters did not correctly support the D3 state. Some display adapters had problems in the BIOS, others had drivers that did not correctly restore register set, and others relied on Vaux current to maintain the state.

To distinguish newer display adapter drivers and devices that have been modified and tested to support hibernation, Windows Me has added a new flag to Get_Adapter_Power_State_Caps and Set_Adapter_Power_State calls. If a system's display adapter drivers do not export these calls or do not implement the new flag, the system will not be placed in S4 (hibernate) state, and the hibernation feature UI will be disabled.

Shortly after the display driver is loaded, Windows Me tests to determine whether the driver has exported the Get_Adapter_Power_State_Caps function. If this function is exported, Windows Me will call this function and examine its return value to determine the power states that the device supports. Drivers indicate supported power states by ORing one or more of the following flags and returning this value in the Get_Adapter_Power_State_Caps call.

Flag | Value (hexadecimal)
CM_POWERSTATE_D0 | 0x00000001
CM_POWERSTATE_D1 | 0x00000002
CM_POWERSTATE_D2 | 0x00000004
CM_POWERSTATE_D3 | 0x00000008
CM_POWERSTATE_HIBERNATE | 0x00000010

Note This implementation is required for drivers to accurately indicate supported power states.

Do not indicate support of CM_POWERSTATE_D3 unless your device has been thoroughly tested on a bus that loses both Vcc and Vaux power when the system is placed in S3. Likewise, do not set the CM_POWERSTATE_HIBERNATE flag unless your device has undergone thorough hibernation testing.

If the display driver does not export the Get_Adapter_Power_State_Caps call or does not set the CM_POWERSTATE_HIBERNATE bit in the return value, Windows Me will disable the hibernation feature. Because older Windows 98 display drivers did not implement the CM_POWERSTATE_HIBERNATE flag, Windows Me will disable hibernation for these older devices and drivers.

Windows Me also uses the same bits for the Set_Adapter_Power_State call. Before placing the system in a new power state, Windows Me calls the driver's Set_Adapter_Power_State function with the appropriate CM_POWERSTATE_HIBERNATE flag. Before returning from this call, drivers must perform any necessary actions to prepare their device to enter the new power state.

For example, if Set_Adapter_Power_State is called with either CM_POWERSTATE_D3 or CM_POWERSTATE_HIBERNATE flags, the driver must save its device's register values to prepare for power loss. Subsequently, when power is restored, Windows Me will call Set_Adapter_Power_State with CM_POWERSTATE_D0. In response, the driver must restore its device's registers so the device is returned to the same state it was in before the sleep or hibernate request.

In addition, drivers must be designed to handle the Set_Adapter_Power_State CM_POWERSTATE_D0 command while resuming even though the BIOS might have initiated a re-POST or other display activity. A device must not enable its IRQ until the Set_Adapter_Power_State CM_POWERSTATE_D0 command is received. In other words, do not allow a display device to generate interrupts before its driver receives the Set_Adapter_Power_State CM_POWERSTATE_D0 command. Although the system can reflect display adapter interrupts to real mode while booting, interrupts cannot be reflected to real mode while resuming because Plug and Play might have changed the interrupt.

Likewise, regardless of what the BIOS does to the display adapter during resume, the driver is responsible for putting the device back into the same state it was in before it received the Set_Adapter_Power_State CM_POWERSTATE_D3 command.

Windows Millennium Power Management Configuration


SET_ADAPTER_POWER_STATE

This topic applies only to Windows Me.

The SET_ADAPTER_POWER_STATE function saves and restores whatever state is necessary to place the device into the power state specified in the PowerState parameter.

DWORD
  __cdecl SetAdapterPowerState(
    DEVNODE  devnode,
    DWORD  PowerState
    );

Parameters

devnode
Specifies the device node for the device.
PowerState
Specifies the power state into which to place the device. This parameter can be one those shown in the following table. Note that the CM_POWERSTATE_HIBERNATE flag is new, and is used to indicate support for the Hibernate feature.
State | Value (hexadecimal)
CM_POWERSTATE_D0 | 0x00000001
CM_POWERSTATE_D1 | 0x00000002
CM_POWERSTATE_D2 | 0x00000004
CM_POWERSTATE_D3 | 0x00000008
CM_POWERSTATE_HIBERNATE | 0x00000010

Return Value

SET_ADAPTER_POWER_STATE returns one of the following values:

Value | Description
CR_DEFAULT | Operating system should perform its default action for the power state transition. (That is, re-POST for D3 to D0. Otherwise, it should do nothing.) This should also be returned if PowerState is something other than one of the four CM_POWERSTATE_DN values.
CR_SUCCESS | Power state was changed successfully. No further action needs to be taken by the operating system.

Comments

The driver remains in memory at all times. Display memory contents do not need to be saved because the operating system resets the display mode during a return to the D0 state.

The default action defined by CR_DEFAULT is to re-POST the device if it is going from D3 to D0. Any other state transition results in no action. If the display driver is capable of initializing the device from a power-off without a POST, then this function returns CR_SUCCESS during the D3 to D0 transition.

SET_ADAPTER_POWER_STATE

Entry | Meaning
ESP+4 | Device node.
ESP+8 | Power state to set. One of: CM_POWERSTATE_D0 CM_POWERSTATE_D1 CM_POWERSTATE_D2 CM_POWERSTATE_D3 CM_POWERSTATE_HIBERNATE

Exit | Meaning
EAX | CR_DEFAULT Routine did nothing. CR_SUCCESS Routine set the appropriate power state for the adapter/display chip set.


GET_ADAPTER_POWER_STATE_CAPS

This topic applies only to Windows Me.

The GET_ADAPTER_POWER_STATE_CAPS function should return the power states supported by the display adapter.

DWORD
  cdecl GetAdapterPowerStateCaps(
    DEVNODE  devnode
    );

Parameters

devnode
Specifies the device node for the device.

Return Value

GET_ADAPTER_POWER_STATE_CAPS returns a bitmask containing an ORed combination of the following flags. Note that the CM_POWERSTATE_HIBERNATE flag is a new flag that is used to indicate support for the Hibernate feature.

Flag | Value (hexadecimal)
CM_POWERSTATE_D0 | 0x00000001
CM_POWERSTATE_D1 | 0x00000002
CM_POWERSTATE_D2 | 0x00000004
CM_POWERSTATE_D3 | 0x00000008
CM_POWERSTATE_HIBERNATE | 0x00000010


Writing a Windows MiniVDD for a Secondary Display

This topic applies only to Windows Me.

The main job of a miniVDD is VGA virtualization. Secondary displays are not VGA devices, however, so most miniVDD code is not needed for a secondary display. You should use a secondary miniVDD only if you really need it.

The miniVDD for a secondary display is stored in the registry as Minivdd2. When a secondary miniVDD is used, the operating system does not load cardVDD2. Only a single copy of the VxD is used.

The driver should implement PNP_NEW_DEVNODE and should use CM_Set_Driver_Private_DWORD for instance data. A user-mode (ring 3) driver must use VDD_REGISTER_DISPLAY_DRIVER_INFO to communicate with the miniVDD.

VDD_Get_DisplayINFO gets the device node handle and uses the device node to get its resource assignment. On secondary devices, DEVICE_IS_NOT_VGA is set in diInfoFlags.

Do not hook VGA functions on non-VGA devices. Only the following miniVDD calls, listed in alphabetic order, should be hooked:

  • DISPLAY_DRIVER_DISABLING
  • GET_ADAPTER_POWER_STATE_CAPS
  • GET_MONITOR_POWER_STATE_CAPS
  • GET_NUM_UNITS
  • GET_TOTAL_VRAM_SIZE
  • MAKE_HARDWARE_NOT_BUSY
  • POST_CRTC_MODE_CHANGE
  • PRE_CRTC_MODE_CHANGE
  • PRE_INT_10_MODE_SET
  • REGISTER_DISPLAY_DRIVER
  • SET_MONITOR_POWER_STATE
  • TURN_VGA_OFF
  • TURN_VGA_ON
  • VESA_CALL_POST_PROCESSING
  • VESA_SUPPORT


Interface Between BaseVDD/MiniVDD/Display Drivers

This topic applies only to Windows Me.

The following table indicates the functions that must be supported by each display driver/miniVDD for the primary and secondary display adapters or usable services.

MiniVDD Functions

baseVDD —> miniVDD

No. | Function |  | Pri | Sec | Notes
1 | REGISTER_DISPLAY_DRIVER | Interface between miniVDD and driver | 2 | 2 |
2 | PRE_HIRES_TO_VGA | Switch to core graph | 1 | 3 |
3 | SAVE_REGISTERS | Save registers | 2 | 3 |
4 | RESTORE_REGISTERS | Restore registers | 2 | 3 |
5 | ENABLE_TRAPS | Enable I/O traps | 2 | 3 |
6 | DISABLE_TRAPS | Disable I/O traps | 2 | 3 |
7 | DISPLAY_DRIVER_DISABLING | Disable display | 1 | 1 |
8 | ENABLE_ACCELERATER | Enable display | 1 | 3 |
9 | DISABLE_ACCELERATER |  | 3 | 3 | Not Used
10 | CHECK_UPDATE |  | 3 | 3 | Not Used
11 | CHECK_WINDOWED |  | 3 | 3 | Not Used
12 | ACC_VBE_PM | VBE/PM | 2 | 2 |
13 | ACC_VBE_DDC | VBE/DDC | 2 | 2 |
14 | ACC_INT_10 | ESA BIOS (VGA BIOS) | 4 | 3 |
15 | ACC_GET_CAPABILITIES | Accelerator BIOS | 4 | 3 |
16 | ACC_GET_EXT_MODE_INFO | Accelerator BIOS | 4 | 3 |
17 | ACC_GET_FLAT_SELECTOR | Accelerator BIOS | 4 | 3 |
18 | ACC_ENABLE_BIOS | Accelerator BIOS | 4 | 3 |
19 | ACC_DISABLE_BIOS | Accelerator BIOS | 4 | 3 |
20 | ACC_SET_PALETTE | Accelerator BIOS | 4 | 3 |
21 | ACC_GET_PALETTE | Accelerator BIOS | 4 | 3 |
22 | ACC_SET_CURSOR | Accelerator BIOS | 4 | 3 |
23 | ACC_SHOW_CURSOR | Accelerator BIOS | 4 | 3 |
24 | ACC_HIDE_CURSOR | Accelerator BIOS | 4 | 3 |
26 | ACC_GET_CURSOR_POS | Accelerator BIOS | 4 | 3 |
27 | GET_NUM_UNITS | Obtain number of monitor units available for connection | 2 | 2 | New Feature (not yet supported)
28 | SET_ADAPTER_POWER_STATE |  | 2 | 2 | New Feature (not yet supported)
29 | GET_ADAPTER_POWER_ STATE_CAPS |  | 2 | 2 | New Feature
30 | SET_MONITOR_POWER_STATE |  | 2 | 2 | New Feature
31 | GET_MONITOR_POWER_ STATE_CAPS |  | 2 | 2 | New Feature
32 | ET_MONITOR_INFO |  | 2 | 2 | New Feature
33 | I2C_OPEN |  | 2 | 2 | New Feature
34 | I2C_ACCESS |  | 2 | 2 | New Feature
35 | GPIO_OPEN |  | 2 | 2 | New Feature
36 | GPIO_ACCESS |  | 2 | 2 | New Feature
37 | COPYPROTECTION_ACCESS |  | 2 | 2 | New Feature
1: Support is necessary 2: Support may be necessary 3: Support is unnecessary (not in use) 4: Necessary for accelerator BIOS support (this function may not be supported in the future)

Protected Mode API Functions

Display driver (Windows kernel) —> baseVDD

The following miniVDD-related protected mode API call interface will be changed partially.

Display drivers to be created in the future must follow these guidelines.

Multimonitor support does not function — even if a candidate for the secondary display adapter exists — if a display driver that does not meet the following calling guidelines is set as the primary. (nor can it be used as a secondary.

No | Function |  | Pri | Sec | Notes
1 | VDD_DRIVER_REGISTER | Register VDD driver | 1 | 1 |
2 | VDD_DRIVER_UNREGISTER | Unregister VDD driver | 1 | 1 |
3 | VDD_SAVE_DRIVER_STATE |  | 3 | 3 | Not Used
4 | VDD_REGISTER_DISPLAY_ DRIVER_INFO | Interface between miniVDD and driver | 2 | 2 |
5 | VDD_REGISTER_SSB_FLAGS |  | 3 | 3 | Not Used
6 | VDD_GET_DISPLAY_CONFIG | Obtain display settings | 2 | 2 |
7 | VDD_PRE_MODE_CHANGE |  | 3 | 3 | Not Used
8 | VDD_POST_MODE_CHANGE |  | 3 | 3 | Not Used
9 | VDD_SET_USER_FLAGS |  | 3 | 3 | Not Used
10 | VDD_SET_BUSY_FLAG_ADDR |  | 3 | 3 | Not Used
11 | VDD_VBE_PM | Power management (—> ACC_VBE_PM) | 2 | 2 |
12 | VDD_ENABLE | Resource control | 3 | 3 | New Feature
13 | VDD_GETMEMBASE | Obtain memory address | 3 | 3 | New Feature
14 | VDD_OPEN | Open device | 2 | 2 | New Feature
15 | VDD_CLOSE | Close device | 2 | 2 | New Feature
16 | VDD_OPEN_KEY | Open settings key | 2 | 2 | New Feature
17 | VDD_SET_POWER_STATE | Power management (—> ACC_VBE_PM) | 2 | 2 | New Feature
1: Support is necessary 2: Can be used 3: Cannot be used

VDD Service Functions

miniVDD —> baseVDD

No | Function | Pri | Sec | Notes | Notes
1 | VDD_Get_Special_VM_IDs | Obtain Message VM ID | 1 | 1 |
2 | VDD_Register_Mini_VDD | Register miniVDD | 1 | 1 | Modified
3 | VDD_Install_IO_Handler | I/O trap | 3 |  |
4 | VDD_Install_Mult_IO_Handlers | I/O trap | 3 |  |
5 | VDD_Enable_Local_Trapping | I/O trap | 3 |  |
6 | VDD_Disable_Local_Trapping | I/O trap | 3 |  |
7 | Test_Vid_VM_Handle | Display owner VM check | 1 | 1 |
8 | VDD_Trap_Suspend | Interrupt process | 1 | 1 |
9 | VDD_Map_VRAM | Accelerator BIOS | 3 | 2 |
1: Can be used 2: Cannot be used 3: Cannot be used due to possible discontinuation of support in the future (supported in Windows 98 for compatibility with current drivers)


32-bit Code Samples

This section applies only to Windows 98/Me.

This section provides samples of 32-bit code, including 32-bit functions, 32-bit callback routines, and 32-bit structures.

32-bit Function Samples

32-bit Callback Samples

32-bit Structure Samples


32-bit Function Samples

This topic applies only to Windows 98/Me.

The following helper functions should be implemented in the 32-bit portion of the HAL:

buildDDHALInfo32

DllMain

DPF

DriverInit

getDisplayDuration

updateFlipStatus


buildDDHALInfo32

This topic applies only to Windows 98/Me.

The buildDDHALInfo32 function sample shows how to collect the information about the 32-bit HAL for DirectDraw in the shared memory window with the 16-bit portion of the HAL.

The 16-bit analog to buildDDHALInfo32 is buildDDHALInfo16. The 16-bit version shows how to fill in information that is specific to the HAL table but can only be obtained from the 16-bit side, such as from the mode table.

The sample buildDDHALInfo32 function included here shows how to fill in the function names, capabilities, and pointers needed by DirectDraw to drive the display card. These are filled in both at initialization time and during mode changes. The buildDDHALInfo32 function is called to modify the structures in the shared 16- and 32-bit memory window (DDHALINFO) that resides above the 2 gigabyte boundary and is accessible from 16- and 32-bit pointers. All of the HAL information is stored in the DDHALINFO structure so it can be accessed easily by DirectDraw. Delete any HAL entries you don't need, and instead put NULL in the entry table.

In this sample, the main driver, surface, and palette callback function names are filled in with aliases of their respective structures (cbDDCallbacks, cbDDSurfaceCallbacks, and cbDDPaletteCallbacks). The DirectDraw callbacks used in this sample are WaitForVerticalBlank32 and GetScanLine32. Flags are set in the dwFlags member of the cbDDCallbacks structure alias to indicate that they are implemented in 32-bit code. For example, the DDHAL_CB32_WAITFORVERTICALBLANK flag indicates that a WaitForVerticalBlank callback is implemented in 32-bit code. If it were implemented in 16-bit code, the name of the 16-bit function would be filled in by buildDDHALInfo16 and the flag that specified it as 32-bit implementation would be left out.

This buildDDHALInfo32 sample also fills in the DirectDrawSurface callbacks with the following functions: Blt32, Flip32, Lock32, GetBltStatus32, and GetFlipStatus32. As with WaitForVerticalBlank and GetScanLine32 in the previous paragraph, each of these functions is flagged as a 32-bit implementation in the dwFlags member. If, for some reason, one or more of these was implemented in 16-bit code, the 32-bit flag would be left out for that function and the buildDDHALInfo16 function would fill in the name of the 16-bit function.

In this sample, there are no DirectDrawPalette callbacks to fill in, but the size of the structure is still filled in and the dwFlags member is explicitly set to 0. Then the DDHALINFO structure is filled in with all information of the above callback structures.

The FourCC codes (four character codes for color space conversions) are filled out in the order of preference. The one with the highest quality for your device should go first, and so on (see DirectDraw and Color Space Conversion for a description of common FourCC code formats). The driver instance (hInstance) is filled in with the instance of the 32-bit DLL. The pdevice parameter is the pointer to the device structure for the display miniport driver.

All of the capabilities supported by this HAL are filled in the dwCaps member of the DDCORECAPS structure included in the DDHALINFO structure. In this sample, DDCAPS_BLT indicates there is a blitter so the HAL can blt, DDCAPS_BLTQUEUE indicates the HAL is capable of queuing up blts, DDCAPS_BLTCOLORFILL indicates the HAL can do color fills, and DDCAPS_COLORKEY means the HAL can do transparent blts. (For a list of the capabilities flags, see the DDCORECAPS structure.)

As far as surface capabilities go, the sample indicates the driver can support flipping, off screen plain, and primary surfaces (DDSCAPS_FLIP, DDSCAPS_OFFSCREENPLAIN, DDSCAPS_PRIMARYSURFACE). The color key capabilities include source blt and destination blt.

The supported raster operations (ROPs) are filled in (see the Win32 SDK for a list of standard raster operations) and the display mode (indicated by the dwModeIndex parameter of the DDHALINFO structure) is temporarily set to DDUNSUPPORTEDMODE (buildDDHALInfo16 fills this in for real). The required alignments of the scan lines (specified in terms of bits) for each kind of memory are filled in.

/*
 * buildDDHALInfo32
 *
 * Build a DDHALInfo structure
 */
static BOOL buildDDHALInfo32()
{
    /*
     * Modify the structures in our shared window with the 16-bit driver
     */
    #define cbDDCallbacks        pDriverData->DDCallbacks
    #define cbDDSurfaceCallbacks pDriverData->DDSurfaceCallbacks
    #define cbDDPaletteCallbacks pDriverData->DDPaletteCallbacks
    #define ddHALInfo            pDriverData->HALInfo

    /*
     * Fill in the main driver callbacks
     */
    memset(&cbDDCallbacks, 0, sizeof(DDHAL_DDCALLBACKS));
    cbDDCallbacks.dwSize                = sizeof(DDHAL_DDCALLBACKS);
    cbDDCallbacks.WaitForVerticalBlank  = WaitForVerticalBlank32;
    cbDDCallbacks.GetScanLine           = GetScanLine32;
    cbDDCallbacks.dwFlags               =
                        DDHAL_CB32_WAITFORVERTICALBLANK |
                        DDHAL_CB32_GETSCANLINE;

    /*
     * Fill in the surface callbacks
     */
    memset(&cbDDSurfaceCallbacks, 0, sizeof(DDHAL_DDSURFACECALLBACKS));
    cbDDSurfaceCallbacks.dwSize         =
                  sizeof(DDHAL_DDSURFACECALLBACKS);
    cbDDSurfaceCallbacks.Blt            = Blt32;
    cbDDSurfaceCallbacks.Flip           = Flip32;
    cbDDSurfaceCallbacks.Lock           = Lock32;
    cbDDSurfaceCallbacks.GetBltStatus   = GetBltStatus32;
    cbDDSurfaceCallbacks.GetFlipStatus  = GetFlipStatus32;
    cbDDSurfaceCallbacks.dwFlags        = DDHAL_SURFCB32_BLT |
                                          DDHAL_SURFCB32_FLIP |
                                          DDHAL_SURFCB32_LOCK |
                                          DDHAL_SURFCB32_GETBLTSTATUS |
                                          DDHAL_SURFCB32_GETFLIPSTATUS;

    /*
     * Fill in the palette callbacks
     */
    memset(&cbDDPaletteCallbacks, 0, sizeof(DDHAL_DDPALETTECALLBACKS));
    cbDDPaletteCallbacks.dwSize  = sizeof(DDHAL_DDPALETTECALLBACKS);
    cbDDPaletteCallbacks.dwFlags = 0;

    /*
     * Fill in the HALINFO
     */
    memset(&ddHALInfo, 0, sizeof(DDHALINFO));
    ddHALInfo.dwSize = sizeof(DDHALINFO);

    /*
     * Callback functions
     */
    ddHALInfo.lpDDCallbacks        = &cbDDCallbacks;
    ddHALInfo.lpDDSurfaceCallbacks = &cbDDSurfaceCallbacks;
    ddHALInfo.lpDDPaletteCallbacks = &cbDDPaletteCallbacks;

    /*
     *  FOURCCs supported
     */
    ddHALInfo.ddCaps.dwNumFourCCCodes = 0;
    ddHALInfo.lpdwFourCC = NULL;

    /*
     * Return our HINSTANCE
     */
    ddHALInfo.hInstance = (DWORD)hInstance;

    /*
     * PDevice
     */
    ddHALInfo.lpPDevice = (LPVOID)pDriverData->lpPDevice;

    /*
     * Capabilities supported
     */
    ddHALInfo.ddCaps.dwCaps = DDCAPS_BLT |
                              DDCAPS_BLTQUEUE |
                              DDCAPS_BLTCOLORFILL |
                              DDCAPS_COLORKEY;

    ddHALInfo.ddCaps.ddsCaps.dwCaps = DDSCAPS_FLIP |
                                      DDSCAPS_OFFSCREENPLAIN |
                                      DDSCAPS_PRIMARYSURFACE;

    ddHALInfo.ddCaps.dwCKeyCaps = DDCKEYCAPS_SRCBLT |
                                  DDCKEYCAPS_DESTBLT;

    ddHALInfo.ddCaps.dwFXCaps = 0x00000000;

    /*
     * Fill in ROPs supported
     */
    ddHALInfo.ddCaps.dwRops[0] =0x00000001;
            // BLACKNESS - 0x00 / 32 = 0 + 0 remainder - DWORD 0, bit 0
    ddHALInfo.ddCaps.dwRops[1] =0x00000000;
    ddHALInfo.ddCaps.dwRops[2] =0x00000000;
    ddHALInfo.ddCaps.dwRops[3] =0x00000000;
    ddHALInfo.ddCaps.dwRops[4] =0x00000000;
    ddHALInfo.ddCaps.dwRops[5] =0x00000000;
    ddHALInfo.ddCaps.dwRops[6] =0x00001000;
            // WHITENESS - 0xff / 32 = 7 + 31 remainder - DWORD 7,bit 31
    ddHALInfo.ddCaps.dwRops[7] =0x80000000;
            // SRCCOPY   - 0xcc / 32 = 6 + 12 remainder - DWORD 6,bit 12

    /*
     * Current video mode, the 16-bit driver will fill this out for real.
     */
    ddHALInfo.dwModeIndex = DDUNSUPPORTEDMODE;

    /*
     *  Required alignments of the scan lines for each kind of memory
     *  (specified in terms of bits - DWORD alignment is used in this
     *  driver)
     */
    ddHALInfo.vmiData.dwOffscreenAlign = 32;
    ddHALInfo.vmiData.dwOverlayAlign   = 32;
    ddHALInfo.vmiData.dwTextureAlign   = 32;
    ddHALInfo.vmiData.dwAlphaAlign     = 32;
    ddHALInfo.vmiData.dwZBufferAlign   = 32;

    return TRUE;

} /* buildDDHALInfo32 */


DllMain

This topic applies only to Windows 98/Me.

The DllMain function is called when the driver DLL first starts up and must be replicated exactly.

This function starts by setting hInstance to hModule, which is the instance of the driver DLL. Then it begins a switch statement on the input parameter dwReason. If dwReason is DLL_PROCESS_ATTACH, the DLL is being mapped into the process's address space and the DisableThreadLibraryCalls Win32 function is called with hModule as the parameter. This tells the system that the DLL_THREAD_ATTACH and DLL_THREAD_DETACH modifications should not be sent to the specified DLL's DllMain function. If the case is DLL_PROCESS_DETACH, the DLL is being unmapped from the process's address space. If it is DLL_THREAD_ATTACH, a thread is being created; if it is DLL_THREAD_DETACH, a thread is exiting cleanly.

Parameters

hModule
Specifies the instance of this DLL.
dwReason
Specifies the reason for calling this DLL. One of the following values can be selected:
Flag | Meaning
DLL_PROCESS_ATTACH | A new process is attempting to access the DLL; one thread is assumed.
DLL_PROCESS_DETACH | A process is detaching from the DLL.
DLL_THREAD_ATTACH | A new thread of an existing process is attempting to access the DLL; this call is made beginning with the second thread of a process attaching to the DLL.
DLL_THREAD_DETACH | One of the additional threads (not the first thread) of a process is detaching from the DLL.

lpvReserved
Is unused.

Return Value

DllMain always returns TRUE.

/*
 * DllMain
 */
BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason,
                        LPVOID lpvReserved)
{
    hInstance = hModule;

    switch( dwReason ) {

    case DLL_PROCESS_ATTACH:  // The DLL is being mapped into the
                              // process's address space
        DisableThreadLibraryCalls( hModule );
                              // This tells the system we don't want
                              // DLL_THREAD_ATTACH and DLL_THREAD_DETACH
                              // modifications sent to the specified
                              // DLL's DllMain function
  break;

    case DLL_PROCESS_DETACH:  // The DLL is being unmapped from the
                              // process address space
        break;

    case DLL_THREAD_ATTACH:  // A thread is being created
        break;

    case DLL_THREAD_DETACH:  // A thread is exiting cleanly
        break;

    default:
        break;
    }

    return TRUE;

} /* DllMain */


DPF

This topic applies only to Windows 98/Me.

The DPF function sends messages to a debug terminal.

This function is simply a way to send messages to a remote debug terminal using the Win32 OutputDebugString function. Whenever a debug printf statement is inserted into the code, it calls this function. This can be duplicated in each file or be made into an include statement. Some developers have a version that allows different priority levels to be set for each message. It is called with a string to be displayed and mimics the function of a printf statement, except that the output is to the debug terminal.(In this sample, each string will begin with "DDDRV32:" and end with a carriage return.)

/*
 * DPF debug stuff
 */
#ifdef DEBUG

#define START_STR       "DDDRV32: "
#define END_STR         "\r\n"

/*
 * DPF
 */
void __cdecl DPF(LPSTR szFormat, ...)
{
    char str[256];

    lstrcpy(str, START_STR);
    wvsprintf(str+lstrlen(str), szFormat, (LPVOID)(&szFormat+1));
    lstrcat(str, END_STR);
    OutputDebugString(str);    // Sends message to debug terminal
}
#endif


DriverInit

This topic applies only to Windows 98/Me.

The DriverInit function is a sample entry point called by DirectDraw to initialize the 32-bit driver. The entry point is called after your Control function receives QUERYESCAPESUPPORT with DDGET32BITDRIVERNAME escapes and returns the entry point (szEntryPoint). (For this sample, the entry point is named DriverInit.) DriverInit is called only once during driver initialization; it is not called on mode changes.

The dwDriverData parameter in the DriverInit sample code points to a region of shared data between the 16- and 32-bit address space. It is aliased through MapSLFix (a standard Windows driver routine), which converts it to a 32-bit pointer, pDriverData. MapSLFix creates a 32-bit pointer for a 16-bit selector, so you can use what it returns from the 16-bit side. A 16:16 pointer is used to point to the needed 32-bit objects, so a 64 KB block of memory is shared between 16- and 32-bit sides. Since only 64 KB of linear address space is accessible with a 16:16 pointer, any objects larger than 64 KB require two 16:16 pointers tiled together (most objects should be smaller than 64 KB). The pointer is used to set the fReset flag to TRUE because the display parameters are being reset. The buildDDHALInfo32 sample function is called from this function to fill out all of the 32-bit function names and driver information.

Parameters

dwDriverData
Points to a shared memory region between 16- and 32-bit address space.

Return Value

DriverInit always returns 1.

/*
 * DriverInit
 *
 * This is the entry point called by DirectDraw
 * to initialize the 32-bit driver.
 */
DWORD _stdcall DriverInit( DWORD dwDriverData )
{
    extern LPVOID _stdcall MapSLFix( DWORD );      // 16:16->0:32
    pDriverData = MapSLFix( dwDriverData );
    buildDDHALInfo32();
    pDriverData->fReset = TRUE;
    return 1;

} /* DriverInit */


getDisplayDuration

This topic applies only to Windows 98/Me.

The getDisplayDuration sample function obtains the length of a refresh cycle, measured in performance ticks.

This function does not need to be called if the monitor refresh rate is known (or you can modify this sample to use that information). If the monitor refresh rate is known, the performance ticks (thousandths of a second) can be calculated based on the known frequency in hertz. That number can then be put in the dwFlipDuration member of the FLIPRECORD sample structure, rather than running this function (unless you modify this sample to use that information). The method described in this paragraph should be more accurate than the empirical method employed by getDisplayDuration.

Assuming the monitor refresh rate is not known, getDisplayDuration should be called on every mode change. This will not affect performance because the monitor is synching at this time. First, getDisplayDuration takes control of the CPU with the Win32 SetPriorityClass function. When the CRT is freshly in display after being in vertical blank, the counter is started. The counter keeps track of the elapsed time, measured in ticks, through 20 display cycles. This elapsed time is divided by 20 to give the average number of ticks per display cycle and the result is stored in the dwFlipDuration member of the FLIPRECORD structure. It is a good idea to check the result with a debug statement, as in the sample shown here. The macros IN_VBLANK and IN_DISPLAY included in this sample can be written to test whether the CRT is in vertical blank or in display, respectively (for more information, see 32-bit Macros).

This function has no parameters and does not return a value.

/*
 * getDisplayDuration
 *
 * Get the length (in ticks) of a refresh cycle
 */
static void getDisplayDuration( void )
{
    int         I;            // Counter
    __int64     start, end;   // 64 bit pointer to hold ticks counted
    DWORD       oldclass;     // Variable to save our priority class
    HANDLE      hprocess;     // Our process handle

    memset( &flipRecord, 0, sizeof( flipRecord ) );
                  // Set memory to size of flipRecord structure
    hprocess = GetCurrentProcess();
                  // Get our current process
    oldclass = GetPriorityClass( hprocess );
                  // Save our old priority class
    SetPriorityClass( hprocess, REALTIME_PRIORITY_CLASS );
                  // Keeps out interruptions as we measure display time
    while(IN_VBLANK);  // Uses macro to wait until out of vertical blank
    while(IN_DISPLAY); // Uses macro to wait until no longer in display
    QueryPerformanceCounter((LARGE_INTEGER*)&start);  // Start counter
    #define LOOP_CNT    20  // We want 20 iterations
    for( i=0;i<LOOP_CNT;i++ )
    {
        while(IN_VBLANK);
        while(IN_DISPLAY);
    }
    QueryPerformanceCounter((LARGE_INTEGER*)&end);
                  // Read counter at the end of 20 cycles
    SetPriorityClass( hprocess, oldclass );
                  // Restore our old priority class
    flipRecord.dwFlipDuration = ((DWORD)(end-start) +
                  LOOP_CNT/2)/LOOP_CNT;
                  // Calculate flip duration
#ifdef DEBUG
    QueryPerformanceFrequency((LARGE_INTEGER*)&start);

    DPF( "Duration = %d ticks, %dms, %dHz",
        flipRecord.dwFlipDuration,
        flipRecord.dwFlipDuration * 1000 / (DWORD)start,
        (DWORD)start / flipRecord.dwFlipDuration);
#endif

} /* getDisplayDuration */


updateFlipStatus

This topic applies only to Windows 98/Me.

The updateFlipStatus sample function determines whether the most recent flip has occurred. This sample function should be modified to match the characteristics of your particular card.

The sample code for updateFlipStatus represents a good default implementation of the flipping algorithm. Care should be exercised in making alterations to this routine, but such alterations may be necessary, nonetheless (see Timing a Flip for other useful algorithms). In addition to modifying the flipping algorithm in some cases, the sample code needs to be modified if the driver is to support flipping overlays. The code must be able to scan through a chain of FLIPRECORD structures to find the correct fpVidMem pointer; therefore, multiple FLIPRECORD structures can be used in that case.

If the input parameter, fpVidMem, is set to zero then updateFlipStatus checks to see whether a flip is being processed on any surface (for a description of a flip being processed, see Flipping and Flip32). If fpVidMem points to a surface, then updateFlipStatus determines whether that surface is being flipped from. If fpVidMem does point to a surface that is being flipped from, it determines whether that surface has been completely displayed. If the display device is in the vertical blank, the time is checked to see whether enough time has passed to complete a flip. (This is because many cards cannot report the scan line while the gun is in the vertical blank.) If not enough time has passed, DDERR_WASSTILLDRAWING is returned. If enough time has passed, the bFlipFlag member of the FLIPRECORD structure is set to FALSE and DD_OK is returned, indicating the surface is available.

If display isn't in vertical blank, the scan line can be used to determine whether the entire screen has been displayed. If the scan line is above where it was previously, the flip flag is set to FALSE (meaning that the flip is not pending on that surface) and DD_OK is returned to indicate that it is okay to proceed with operations on that surface. If the scan line is not above the previous measurement, the time is checked again to see whether it is greater than the display duration. If not enough time has elapsed, DDERR_WASSTILLDRAWING is returned to indicate that the surface is not yet available.

The IN_VBLANK and CURRENT_VLINE macros can be written to test whether the CRT is in vertical blank and to read the current scan line, respectively (for more information, see 32-bit Macros).

Parameters

fpVidMem
Points to the beginning of a particular surface in display memory. Declared in ddrawi.h.

Return Value

updateFlipStatus returns DD_OK if the flip has occurred and DDERR_WASSTILLDRAWING if not.

/*
 * updateFlipStatus
 *
 * Checks to see if the most recent flip has occurred
 */
static __inline HRESULT updateFlipStatus( FLATPTR fpVidMem )
{
    /*
     * See if a flip has happened recently
     */
    if( flipRecord.bFlipFlag && ((fpVidMem == 0)||
                        (fpVidMem == flipRecord.fpFlipFrom) ) )
    {
        __int64 ttime;        //64 bit pointer - measures time in ticks

        /*
         * If we aren't in the vertical blank, we can use the scan line
         * to help decide on what to do
         */
        if(!(IN_VBLANK))
        {
            if( (CURRENT_VLINE >= flipRecord.wFlipScanLine) )
            {
                QueryPerformanceCounter((LARGE_INTEGER*)&ttime);
                if( (DWORD)(ttime-flipRecord.liFlipTime) <=
                  flipRecord.dwFlipDuration )
                {
                    return DDERR_WASSTILLDRAWING;  // Not done flipping
                }
            }
        }
        /*
         * In the vertical blank, scan line is useless
         */
        else
        {
            QueryPerformanceCounter((LARGE_INTEGER*)&ttime);
            if( ((DWORD)(ttime-flipRecord.liFlipTime) <=
                        flipRecord.dwFlipDuration) )
            {
                return DDERR_WASSTILLDRAWING;     // Not done flipping
            }
        }
        flipRecord.bFlipFlag = FALSE;
                        // A flip is not pending on this surface
    }
    return DD_OK;       // OK to do a flip or blt on this surface
} /* updateFlipStatus */


32-bit Callback Samples

This section applies only to Windows 98/Me.

Callback routines should be implemented in the 32-bit portion of the HAL. If, for some reason, a particular callback cannot be implemented in 32-bit, it can be written in 16-bit instead. If it is written in 16-bit, do not set the bit in the callback table that specifies it is a 32-bit callback function. This way, the callback is called from the 16-bit side by default (it still must be listed in the DDHALINFO structure). When that is done, ddraw16.dll calls the callback function rather than ddraw.dll, and the callback function is run on the 16-bit side.

The following sample 32-bit HAL callbacks are discussed in this section:

Blt32

Flip32

GetBltStatus32

GetFlipStatus32

GetScanLine32

Lock32

WaitForVerticalBlank32


Blt32

This topic applies only to Windows 98/Me.

Blt32 is called for every DirectDraw blt operation. Blts to surfaces that are being flipped from must not happen until the flip is completed. If a blt happens on the same surface that is being displayed, a tear can occur. This type of tear looks like the screen jerked upwards briefly.

This callback should be optimized for the following three operations: source copy, transparent blt, and color fill. The optimization should include making a single test to determine whether the operation is a source copy, followed by a single test to see whether it is a transparent blt, followed by a single test to see whether it is a color fill, followed by code that handles any other permutations the driver supports. The first three are most critical to display performance because they are used most often (and are all that is covered in this sample). Obviously, handling more cases is preferable, but make sure the code to handle these cases does not interfere with the speed of the execution of source copy, transparent blt, and color fill.

Local surface objects are passed in to Blt32. You must retrieve the pointer to the global surface object by referencing the surface object's lpGbl pointer. This happens in the first part of Blt32 because the global surface pointer is what actually points to display memory. The DirectDraw object thinks the local surface pointer is the display memory pointer. However, because multiple DirectDraw objects may exist, this DirectDraw object is not guaranteed to have the input focus. The global surface pointer is guaranteed to correspond to the DirectDraw object that has the input focus.

Before blitting to a flippable surface, call updateFlipStatus with a pointer to the display memory of the destination surface to see if that surface is involved in a flip. The blt cannot be done on a surface that is flipping because this will cause a tear. The updateFlipStatus function is called with the fpVidMem member of the DDRAWI_DDRAWSURFACE_GBL structure (representing the destination surface) passed as a parameter to specify the surface of interest. If the return value is not DD_OK, then the ddRVal member of the DDHAL_BLTDATA structure is set to the value of the ddrval parameter and DDHAL_DRIVER_HANDLED is returned. This gives up control to DirectDraw and passes it the return value, that is, DDERR_WASSTILLDRAWING. If the return value is DD_OK, the dwFlags parameter is set equal to the dwFlags member of the DDHAL_BLTDATA structure (the latter half of this sample contains the code for the flags that are used), which specifies what kind of blt to do. If the dwFlags parameter is DDBLT_ASYNC, and there is enough FIFO memory to do a blt, the blt is done asynchronously through the FIFO, in the order received. If there is not enough FIFO memory, a message is sent out for debugging purposes to indicate that the asynchronous blt failed, the ddRVal member of the DDHAL_BLTDATA structure is set to DDERR_WASSTILLDRAWING, and DDHAL_DRIVER_HANDLED is returned.

All of the information needed to do a blt is contained in the bltFX member of the DDHAL_BLTDATA structure. The dwFlags member of the DDHAL_BLTDATA structure determines what kind of blt is being done (see the latter half of the sample code for these flags). The color key always comes in the DDBLTFX structure; it does not have to be looked up in the surface.

If the dwFlags member is DDBLT_ASYNC, the sample checks to see whether the FIFO has enough room for a blt. If there is not enough room, return immediately. Otherwise, get the offset, width, and height for the blt, and check dwFlags to determine whether it is a raster operation (DDBLT_ROP). If it is a raster operation and the dwROP member of the DDBLTFX structure pointed to by the bltFX member of the DDHAL_BLTDATA structure is SRCCOPY, then the operation is a standard copy operation (for more information, see the DDBLTFX structure). The destination offset, source data, source offset, source width, source height, and color key (if one exists) are then determined in the sample. There may be a color key override (DDBLT_KEYSRCOVERRIDE) if it is a transparent blt. If no color key exists, the same information is set up without the color key. This double checks how the blt is set up.

When performing a color fill instead of a raster operation (dwFlags == DDBLT_COLORFILL), the dwFillColor parameter in the sample is set equal to the dwFillColor member of the DDBLTFX structure pointed to by the bltFX member of the DDHAL_BLTDATA structure. A debug message is sent out to verify that the correct fill color, destination height, and width have been selected. If this is not a raster operation or color fill (or other implemented function), then return DDHAL_DRIVER_NOTHANDLED so this unsupported request can be passed on to the DIB engine. Otherwise the ddRVal member of the DDHAL_BLTDATA structure is set to DD_OK and DDHAL_DRIVER_HANDLED is returned.

/*
 * Blt32
 *
 * 32-bit blt routine.
 */
DWORD __stdcall Blt32( LPDDHAL_BLTDATA pbd )
{
    HRESULT     ddrval;     // DirectDraw return value
    DWORD       dwFlags;    // For specifying the type of blt

    DWORD dwFillColor;      // Used to specify the RGB color to fill with
    DWORD dwColorKey;       // Holds our color key for a transparent blt

    DWORD dwDstOffset;      // Offset to beginning of destination surface
    DWORD dwDstWidth;       // Width of destination surface (in pixels)
    DWORD dwDstHeight;      // Height of destination surface (in rows)

    DWORD dwSrcOffset;      // Offset to the beginning of source surface
    DWORD dwSrcWidth;       // Width of source surface (in pixels)
    DWORD dwSrcHeight;      // Height of source surface (in rows)

    LPDDRAWI_DDRAWSURFACE_LCL  srcx;
                            // Local pointer to source surface
    LPDDRAWI_DDRAWSURFACE_LCL  dstx;
                            // Local pointer to destination surface
    LPDDRAWI_DDRAWSURFACE_GBL  src;
                            // Global pointer to source surface
    LPDDRAWI_DDRAWSURFACE_GBL  dst;
                            // Global pointer to destination surface
    dstx = pbd->lpDDDestSurface;      // Destination surface
    dst = dstx->lpData;               // Destination data

    /*
     * NOTES:
     *
     * Everything you need is in pdb->bltFX.
     * Look at pdb->dwFlags to determine what kind of blt you are doing,
     * DDBLT_xxxx are the flags.
     *
     * COLORKEY NOTES:
     *
     * ColorKey ALWAY comes in BLTFX. You don't have to look it up in
     * the surface.
     */

    /*
     * Is a flip pending on our destination surface?  If so, pass
     * ddrval return value and exit
     */
    ddrval = updateFlipStatus(dst->fpVidMem);
    if( ddrval != DD_OK )
    {
        pbd->ddRVal = ddrval;          // Pass the return value
        return DDHAL_DRIVER_HANDLED;   // Can't blt now, exit function
    }

    /*
     * If async, then only work if blitter isn't busy
     * This should probably be a little more specific to each call, but
     * this is pretty close
     */
    dwFlags = pbd->dwFlags;
    if( dwFlags & DDBLT_ASYNC )
    {
        if( !ENOUGH_FIFO_FOR_BLT )
        {
            DPF("ASYNC FAILED");
            pbd->ddRVal = DDERR_WASSTILLDRAWING;// Pass the return value
            return DDHAL_DRIVER_HANDLED;        // Not enough FIFO, exit
        }
    }

    /*
     * Get offset, width, and height for destination
     */
    dwDstOffset = dst->fpVidMem     - pDriverData->ScreenAddress;
    dwDstWidth  = pbd->rDest.right  - pbd->rDest.left;
    dwDstHeight = pbd->rDest.bottom - pbd->rDest.top;

    /*
     * Handle ROPs such as copy, transparent blts and color fills
     */
    if (dwFlags & DDBLT_ROP)
    {
        if (pbd->bltFX.dwROP == SRCCOPY)
        {
            srcx = pbd->lpDDDestSurface;
            src = srcx->lpData;

            dwSrcOffset = src->fpVidMem    - pDriverData->ScreenAddress;
            dwSrcWidth  = pbd->rSrc.right  - pbd->rSrc.left;
            dwSrcHeight = pbd->rSrc.bottom - pbd->rSrc.top;
            dwColorKey  =
                pbd->bltFX.ddckSrcColorkey.dwColorSpaceLowValue;

            if (dwFlags & DDBLT_KEYSRCOVERRIDE)
                DPF("Blt32: TransBlt from %08X %dx%d -> %08X %dx%d
                    key=%08X", dwSrcOffset, dwSrcWidth, dwSrcHeight,
                    dwDstOffset, dwDstWidth, dwDstHeight, dwColorKey);
            else
                DPF("Blt32: Blt from %08X %dx%d -> %08X %dx%d",
                    dwSrcOffset, dwSrcWidth, dwSrcHeight, dwDstOffset,
                    dwDstWidth, dwDstHeight);
        }
    }
    else if (dwFlags & DDBLT_COLORFILL)
    {
        dwFillColor = pbd->bltFX.dwFillColor;
        DPF("Blt32: fill %08X %08X %dx%d", dwFillColor, dwDstWidth,
            dwDstHeight);
    }
    else
    {
                     // This is where you would handle extra ROPs
   return DDHAL_DRIVER_NOTHANDLED;
                     // We couldn't handle the blt, pass it on to HEL
    }

    pbd->ddRVal = DD_OK;         // Pass the return value
    return DDHAL_DRIVER_HANDLED; // Blt successful, exit function

} /* Blt32 */


Flip32

This topic applies only to Windows 98/Me.

The Flip32 callback handles flipping of surfaces, including primary surfaces, overlays and textures.

When a flip occurs in DirectDraw, the front buffer object remains the front buffer object; only the surface memory to which it points changes. The key issue is to eliminate tearing. The surface being displayed is indicated by the lpSurfCurr member of the DDHAL_FLIPDATA structure and the surface that should be displayed next is indicated by the lpSurfTarg member of the same structure. Don't flip while any flips involving this surface chain are pending (typically if a flip is pending, updateFlipStatus code handles this). In addition, don't flip if the blitter is busy; if it is blitting to the target surface this could result in a tear (the macro in this sample, DRAW_ENGINE_BUSY, handles this test). The DRAW_ENGINE_BUSY macro in this sample can be written to test whether your blitter is busy (for more information, see 32-bit Macros).

When the hardware registers are pointed at the new surface, the surface that was flipped away from needs to be tracked. One possible method of tracking the surface is by using a FLIPRECORD structure. If the user tries to lock the surface, it is possible to verify whether it has finished being displayed. The FLIPRECORD structure itself is not mandatory, but you need a way to keep track of the surface. If you can have multiple flips (that is, flipping overlays and flipping textures), you need to have more than one FLIPRECORD structure (or an analog to it).

Flip32 sends out a debug message to verify the current and target surfaces and the fpVidMem pointers that correspond to each. (Of course, the debug messages in the sample code are merely suggestions and are purely up to the discretion of the driver writer.) The updateFlipStatus function is called with a 0 parameter to see whether a flip is pending.

If the return value from updateFlipStatus is not equal to DD_OK, a flip cannot happen at this time. The return value is passed by setting the ddRVal member of the DDHAL_FLIPDATA structure to the value returned from the updateFlipStatus function (ddrval), and DDHAL_DRIVER_HANDLED is returned from Flip32 because the request has been processed.

If the return value is equal to DD_OK, and the blit engine is not busy, it is okay to flip. (You may want to write a macro called SET_FLIP_REGISTER or just add the code that sets the register, which is read when the next surface is to be displayed.) If the blitter is busy, the flip can't be done at this time, DDERR_WASSTILLDRAWING is passed in the ddRVal member of the DDHAL_FLIPDATA structure, and DDHAL_DRIVER_HANDLED is returned. The updateFlipStatus function does not work unless one or more FLIPRECORD structures are maintained properly.

If all of the conditions for allowing a flip are met, you can check the bit that tells whether the flip has occurred (assuming the hardware has such a bit). If your hardware does not have such a bit, the QueryPerformanceCounter Win32 function is called to set the beginning flip time. This can be polled later to see whether enough time has elapsed to go through an entire refresh cycle. The bFlipFlag member of the FLIPRECORD structure is set to TRUE to indicate a pending flip. Then the fpFlipFrom member of the same structure is set to the value of the fpVidMem member of the DDRAWI_DDRAWSURFACE_GBL structure that is contained in the DDRAWI_DDRAWSURFACE_LCL structure (lpGbl) that is pointed to by the lpSurfCurr member of the DDHAL_FLIPDATA structure. In addition, the bHaveEverCrossedVBlank member of the FLIPRECORD structure is reset to FALSE (to verify whether the surface has been completely displayed—for more information, see Timing a Flip).

If the scan line is in vertical blank, the dwFlipScanLine member of the FLIPRECORD structure is set to 0 and the bWasEverInDisplay member is set to FALSE. If you have a multiregister flip (that is, more than one register must be changed to do a flip), do not do this when the scan line is in the vertical blank. In that case, if the DDFLIP_WAIT flag is not set, return out of Flip32 with the DDERR_WASSTILLDRAWING error, and avoid doing the flip while in vertical blank. If the DDFLIP_WAIT flag is set, wait until the scan line is out of vertical blank and then do the flip. That is the only way to be sure not to tear when you have multiregister flips. Otherwise the dwFlipScanLine member is set to the result of the CURRENT_VLINE (an implementation-specific macro that determines the scan line), and the bWasEverInDisplay member of the FLIPRECORD structure is set to TRUE. Again, this is to keep track of where you are in the display cycle. DD_OK is passed as the return value in the ddRVal member of the DDHAL_FLIPDATA structure, and DDHAL_DRIVER_HANDLED is returned after a successful flip.

/*
 * Flip32
 */
DWORD __stdcall Flip32( LPDDHAL_FLIPDATA pfd )
{
    HRESULT     ddrval;       // DirectDraw return value

    /*
     * NOTES:
     *
     * This callback is invoked whenever we are about to flip from
     * one surface to another. pfd->lpSurfCurr is the surface we were
     * at; pfd->lpSurfTarg is the one we are flipping to.
     *
     * You should point the hardware registers at the new surface, and
     * also keep track of the surface that was flipped away from, so
     * that if the user tries to lock it, you can be sure that it is
     * done being displayed.
     */
    DPF( "Flip32: curr=%08lx, targ=%08lx", pfd->lpSurfCurr,
                              pfd->lpSurfTarg );
    DPF( "        vidmem ptrs change: %08lx->%08lx",
                        pfd->lpSurfCurr->lpGbl->fpVidMem,
                        pfd->lpSurfTarg->lpGbl->fpVidMem );

    ddrval = updateFlipStatus(0);   // Are there any flips pending?

    if (ddrval != DD_OK)
    {
        pfd->ddRVal = ddrval;       // Pass the return value
        return DDHAL_DRIVER_HANDLED;// Exit function without flipping
    }

    /*
     * Is the blitter busy right now?
     */
    if (DRAW_ENGINE_BUSY)
    {
        pfd->ddRVal = DDERR_WASSTILLDRAWING; // Pass the return value
        return DDHAL_DRIVER_HANDLED;    // Draw engine busy, exit
    }

    /*
     *  Everything is OK, do the flip here. Suggest writing a
     *  SET_FLIP_REGISTER macro to use here.
     */

    /*
     * Remember where/when we were when we did the flip
     * (Only required if we have a piece of hardware that doesn't have
     * a bit that is set when a flip occurs.)
     */
    QueryPerformanceCounter((LARGE_INTEGER*)&flipRecord.liFlipTime);
    flipRecord.bFlipFlag = TRUE;
    flipRecord.fpFlipFrom = pfd->lpSurfCurr->lpGbl->fpVidMem;
    flipRecord.bHaveEverCrossedVBlank = FALSE;

    /*
     * Update flipRecord structure so updateFlipStatus can determine
     * whether we have been through a complete
     * display cycle later
     */
    if (IN_VBLANK)
    {
        flipRecord.dwFlipScanLine = 0;
        flipRecord.bWasEverInDisplay = FALSE;
    }
    else
    {
        flipRecord.dwFlipScanLine = CURRENT_VLINE;
        flipRecord.bWasEverInDisplay = TRUE;
    }

    pfd->ddRVal = DD_OK;
    return DDHAL_DRIVER_HANDLED;

} /* Flip32 */


GetBltStatus32

This topic applies only to Windows 98/Me.

The GetBltStatus32 callback checks whether the blitter queue has room for more blts and whether the blitter is busy.

GetBltStatus32 first checks the dwFlags member of the DDHAL_GETBLTSTATUSDATA structure to see whether blts are supported. If they are, it makes sure any flips away from the destination surface have been completed. If no flip is pending, GetBltStatus32 checks to see whether there is room in the FIFO or if the FIFO is as empty as it can be. If there is not enough room for the blt parameters, the return value (the ddRVal member of the DDHAL_GETBLTSTATUSDATA structure) is set to DDERR_WASSTILLDRAWING. If there is enough FIFO to do a blt, the return value is set to DD_OK. If a blt cannot be added, the draw engine is checked and the return value is set to DDERR_WASSTILLDRAWING if it is busy or DD_OK if not. In either case, DDHAL_DRIVER_HANDLED is returned. This simply means the call has been dealt with successfully, not that any specific action has been performed.

The ENOUGH_FIFO_FOR_BLT and DRAW_ENGINE_BUSY macros in this sample can be written to test whether the hardware FIFO has enough room for a blt and whether the blitter is busy, respectively. These macros are implementation-specific (for more information, see 32-bit Macros).

/*
 * GetBltStatus32
 */
DWORD __stdcall GetBltStatus32(
        LPDDHAL_GETBLTSTATUSDATA lpGetBltStatus )
{
    /*
     * CANBLT: can we add a blt?
     */
    if( lpGetBltStatus->dwFlags == DDGBS_CANBLT )
    {
        /*
         * Make sure that we've flipped away from the destination
         * surface
         */
        lpGetBltStatus->ddRVal = updateFlipStatus(
                        lpGetBltStatus->lpDDSurface->lpGbl->fpVidMem );
        if( lpGetBltStatus->ddRVal == DD_OK )
        {
            /*
             * There was no flip going on. Is there room in the FIFO
             * to add a blt?
             */
            if( !ENOUGH_FIFO_FOR_BLT )
            {
                lpGetBltStatus->ddRVal = DDERR_WASSTILLDRAWING;
            }

else
            {
                lpGetBltStatus->ddRVal = DD_OK;
            }
        }
    }
    /*
     * DONEBLT: Is a blt in progress?
     */
    else
    {
        if( DRAW_ENGINE_BUSY )
        {
            lpGetBltStatus->ddRVal = DDERR_WASSTILLDRAWING;
        }
        else
        {
            lpGetBltStatus->ddRVal = DD_OK;
        }
    }
    return DDHAL_DRIVER_HANDLED;

} /* GetBltStatus32 */


GetFlipStatus32

This topic applies only to Windows 98/Me.

The GetFlipStatus32 callback determines whether a previously requested flip has occurred and whether it is okay to do a flip.

To perform a flip, the previous flip must be completed and the blitter cannot be busy. If the display has been through one refresh cycle since the previous flip, DD_OK is returned. If it has not been through a refresh cycle, DDERR_WASSTILLDRAWING is returned to indicate that this surface is still busy "drawing" the flipped page. DDERR_WASSTILLDRAWING is also returned if the blitter is busy and the caller is asking whether it is okay to flip.

GetFlipStatus32 first checks to see whether a flip is pending by calling updateFlipStatus. If no flip is pending, it checks the blt engine to make sure that a blt is not being processed on the surface to which it is being flipped. Since it is not known for certain which surface is being targeted, the flip cannot occur until the blt engine is done. If a flip is pending, GetFlipStatus32 sets the ddRVal member of the DDHAL_GETFLIPSTATUSDATA structure to the return value of updateFlipStatus . The value 0 is passed to updateFlipStatus to find out if a flip is pending on any surface. If the dwFlags member of the DDHAL_GETFLIPSTATUSDATA structure is set to DDGFS_CANFLIP and the ddRVal member (of the same structure) is DD_OK, then check to see whether the blt engine is busy, by using the DRAW_ENGINE_BUSY macro. If it is, the ddRVal member is changed to DDERR_WASSTILLDRAWING. Once these return values are set, DDHAL_DRIVER_HANDLED is returned because the request has been dealt with successfully. If the blitter is not busy, it continues with DDGFS_CANFLIP and returns DDHAL_DRIVER_HANDLED.

The DRAW_ENGINE_BUSY macro in this sample can be written to test whether your blitter is busy. This is implementation-specific (for more information, see 32-bit Macros).

/*
 * GetFlipStatus32
 *
 * If the display has gone through one refresh cycle since the flip
 * occurred we return DD_OK. If it has not been through one refresh
 * cycle we return DDERR_WASSTILLDRAWING to indicate that this surface
 * is still busy "drawing" the flipped page. We also return
 * DDERR_WASSTILLDRAWING if the blitter is busy and the caller wanted
 * to know if a flip could be performed.
 */
DWORD __stdcall GetFlipStatus32(
        LPDDHAL_GETFLIPSTATUSDATA lpGetFlipStatus )
{
    lpGetFlipStatus->ddRVal = updateFlipStatus( 0 );
                              // Is a flip happening on any surface?

    /*
     * Check to see whether the blitter is busy, if someone wants to
     * know if a flip can be performed
     */
    if( lpGetFlipStatus->dwFlags == DDGFS_CANFLIP )
    {
        if( (lpGetFlipStatus->ddRVal == DD_OK) && DRAW_ENGINE_BUSY )
        {
            lpGetFlipStatus->ddRVal = DDERR_WASSTILLDRAWING;
        }
    }
    return DDHAL_DRIVER_HANDLED;

} /* GetFlipStatus32 */


GetScanLine32

This topic applies only to Windows 98/Me.

The GetScanLine32 callback returns the physical scan line, if it can be determined. If the hardware does not have the ability to read the scan line, then put NULL in this function's entry point in buildDDHALInfo32.

If a vertical blank is in progress, the scan line is indeterminate; therefore the ddRVal member of the DDHAL_GETSCANLINEDATA structure is set to DDERR_VERTICALBLANKINPROGRESS and DDHAL_DRIVER_HANDLED is returned. If the scan line is not in vertical blank, it is read into the dwScanLine member of the DDHAL_GETSCANLINEDATA structure with the CURRENT_VLINE macro. CURRENT_VLINE is an implementation-specific macro that reads the scan line register(s) and reports the scan line (see 32-bit Macros for more information). The DD_OK return value is passed in the ddRVal member of the DDHAL_GETSCANLINEDATA structure and DDHAL_DRIVER_HANDLED is returned.

/*
 * GetScanLine32
 */
DWORD __stdcall GetScanLine32(
        LPDDHAL_GETSCANLINEDATA lpGetScanLine )
{
    /*
     * If a vertical blank is in progress, the scan line is
     * indeterminate. If the scan line is indeterminate we return
     * the error code DDERR_VERTICALBLANKINPROGRESS.
     * Otherwise we return the scan line and a success code.
     */
    if( IN_VBLANK )
    {
        lpGetScanLine->ddRVal = DDERR_VERTICALBLANKINPROGRESS;
                        // Can't get the scan line
    }
    else
    {
        lpGetScanLine->dwScanLine = CURRENT_VLINE;
                        // Read current scan line
        lpGetScanLine->ddRVal = DD_OK;
                        // We got the scan line successfully
    }
    return DDHAL_DRIVER_HANDLED; // We dealt with the call

} /* GetScanLine32 */


Lock32

This topic applies only to Windows 98/Me.

The Lock32 callback locks a surface so that only the user can access it. It is invoked whenever a surface is about to be directly accessed by the host CPU.

The sole purpose of Lock32 is to provide a display memory pointer to DirectDraw. If Lock32 returns DDHAL_DRIVER_NOTHANDLED, DirectDraw gets that pointer from the surface structure. If you want to use a pointer other than the one DirectDraw uses to point to the surface memory (passed in by the lpSurface member of the DDHAL_LOCKDATA structure), return that pointer in the lpSurfData member of the DDHAL_LOCKDATA structure, and specify DDHAL_DRIVER_HANDLED.

Before allowing a lock, it must be verified that a surface can be safely accessed by the user. If the memory cannot be accessed while in accelerator mode, the card should be taken out of accelerator mode or the driver should return DDERR_SURFACEBUSY. If the surface being accessed was just flipped away from, it must finish displaying before it can be locked. If a mode reset has occurred (pDriverData->fReset is set to TRUE), getDisplayDuration is called and pDriverData->fReset is set to FALSE (pDriverData->fReset is TRUE when the display duration for this mode hasn't been calculated yet). This is because the display duration is different in different modes. The getDisplayDuration function only needs to be called if the monitor refresh rate is not known, otherwise it can be calculated by converting the frequency (in hertz) to performance ticks (thousandths of a second) and filled into the dwFlipDuration member of the FLIPRECORD structure. This should be more accurate than the sampling method that getDisplayDuration uses in the following sample code. Another method is to alter getDisplayDuration to do this anyway (provided the refresh rate is known).

Before an actual lock can occur, any pending physical flip must have been processed. This is checked by calling updateFlipStatus with the pointer to the fpVidmem member of the DDRAWI_DDRAWSURFACE_GBL structure that is contained in the DDRAWI_DDRAWSURFACE_LCL structure (lpGbl) that is pointed to by the lpDDSurface member of the DDHAL_LOCKDATA structure as the input parameter. If the return value is not equal to DD_OK, the ddRVal member of the DDHAL_LOCKDATA structure is set to DDERR_WASSTILLDRAWING (because the lock cannot be done) and DDHAL_DRIVER_HANDLED is returned.

If a lock cannot be done while a blt is in progress (this depends on the hardware requirements), check whether the draw engine is busy doing a blt. If it is, set the ddRVal member of the DDHAL_LOCKDATA structure to DDERR_WASSTILLDRAWING (because the surface can't be locked right now) and return DDHAL_DRIVER_HANDLED. Otherwise, returning DDHAL_DRIVER_NOTHANDLED effectively locks the surface.

/*
 * Lock32
 */
DWORD __stdcall Lock32( LPDDHAL_LOCKDATA lpLockData )
{
    HRESULT     ddrval;             // DirectDraw return value

    /*
     * NOTES:
     *
     * This callback is invoked whenever a surface is about to be
     * directly accessed by the user. This is where you need to make
     * sure that a surface can be safely accessed by the user.
     *
     * If your memory cannot be accessed while in accelerator mode, you
     * should take either take the card out of accelerator mode or else
     * return DDERR_SURFACEBUSY
     *
     * If someone is accessing a surface that was just flipped away
     * from, make sure that the old surface (what was the primary) has
     * finished being displayed.
     */

    /*
     * Get the monitor frequency after a mode reset
     */
    if( pDriverData->fReset )
    {
        getDisplayDuration();
        pDriverData->fReset = FALSE;
    }

    /*
     * Check to see if any pending physical flip has occurred
     */
    ddrval = updateFlipStatus(lpLockData->
                              lpDDSurface->lpGbl->fpVidMem);
    if( ddrval != DD_OK )
    {
        lpLockData->ddRVal = DDERR_WASSTILLDRAWING;   // Can't lock
        return DDHAL_DRIVER_HANDLED;      // We dealt with the request
    }

    /*
     * Don't allow a lock if a blt is in progress (only do this if your
     * hardware requires it)
     */
    if(DRAW_ENGINE_BUSY)
    {
        lpLockData->ddRVal = DDERR_WASSTILLDRAWING;
                        // Can't lock during a blt
        return DDHAL_DRIVER_HANDLED;
                        // Request handled
    }

    return DDHAL_DRIVER_NOTHANDLED;
                        // Request not handled, let the lock proceed

} /* Lock32 */


WaitForVerticalBlank32

This topic applies only to Windows 98/Me.

The WaitForVerticalBlank32 callback handles requests for vertical blank status. If WaitForVerticalBlank32 does not return DDHAL_DRIVER_HANDLED, DirectDraw returns an error to the application because DirectDraw cannot emulate this function.

WaitForVerticalBlank32 determines why the function was called based on which flag it was passed. The three options are: DDWAITVB_I_TESTVB, DDWAITVB_BLOCKBEGIN, and DDWAITVB_BLOCKEND.

  • The DDWAITVB_I_TESTVB flag means the vertical blank status is all that is wanted. The status of the vertical blank in this sample is tested with the IN_VBLANK macro and the bIsInVB member of the DDHAL_WAITFORVERTICALBLANKDATA structure is set accordingly. The function then returns DDHAL_DRIVER_HANDLED.
  • If the case is DDWAITVB_BLOCKBEGIN, the WaitForVerticalBlank32 sample looks for the beginning of the vertical blank. To do this, the IN_VBLANK macro is used to wait until the scan line leaves the vertical blank and the IN_DISPLAY macro is used to wait until the scan line pops out of display. This indicates that the scan line is at the very start of vertical blank. At this time, the ddRVal member of the DDHAL_WAITFORVERTICALBLANKDATA structure is set to DD_OK and DDHAL_DRIVER_HANDLED is returned.
  • If the case is DDWAITVB_BLOCKEND, the WaitForVerticalBlank32 sample looks for the end of the vertical blank interval. If the scan line is currently in vertical blank, the IN_VBLANK macro is used to wait until the scan line is no longer in vertical blank. Then the bFlipFlag member of the FLIPRECORD structure is set to FALSE (since a display cycle has been completed), the ddRVal member of the DDHAL_WAITFORVERTICALBLANKDATA structure is set to DD_OK and DDHAL_DRIVER_HANDLED is returned. If the scan line is not currently in vertical blank, the IN_DISPLAY macro is used to wait until the scan line is no longer in display. Then, as before, the IN_VBLANK macro is used to wait until the scan line is no longer in vertical blank. The bFlipFlag member of the FLIPRECORD structure is set to FALSE, the ddRVal member of the DDHAL_WAITFORVERTICALBLANKDATA structure is set to DD_OK, and DDHAL_DRIVER_HANDLED is returned.

If none of the preceding cases occurs, WaitForVerticalBlank32 returns DDHAL_DRIVER_NOTHANDLED because the request cannot be processed correctly, and DirectDraw returns an error to the application.

IN_VBLANK is an implementation-specific macro that reads hardware register(s) to determine whether the scan line is in vertical blank. It returns immediately with a positive value if the scan line is in vertical blank and with zero if not. Likewise, IN_DISPLAY returns a positive value if the scan line is in display and returns zero if it is not. These macros must be defined before WaitForVerticalBlank32 can work correctly (see 32-bit Macros for more information).

/*
 * WaitForVerticalBlank32
 */
DWORD __stdcall WaitForVerticalBlank32(
        LPDDHAL_WAITFORVERTICALBLANKDATA lpWaitForVerticalBlank )
{

    switch( lpWaitForVerticalBlank->dwFlags )
    {
    case DDWAITVB_I_TESTVB:
        /*
         * If testvb is just a request for the current vertical blank
         * status
         */
        lpWaitForVerticalBlank->ddRVal = DD_OK;
                                   // We got the vertical blank status
        lpWaitForVerticalBlank->bIsInVB = IN_VBLANK;
                                   // Are we in vertical blank?
        return DDHAL_DRIVER_HANDLED;// Request dealt with

    case DDWAITVB_BLOCKBEGIN:
        /*
         * If blockbegin is requested we wait until the vertical blank
         * is over, and then wait for the display period to end.
         */
        while(IN_VBLANK);     // Wait until we are not in vertical blank
        while(IN_DISPLAY);    // Wait until we leave display
        lpWaitForVerticalBlank->ddRVal = DD_OK;
                              //We got waited until block begin
        return DDHAL_DRIVER_HANDLED;
                              // Request dealt with

    case DDWAITVB_BLOCKEND:
        /*
         * If blockend is requested we wait for the vblank interval to
         * end.
         */
        if( IN_VBLANK )
        {
            while( IN_VBLANK );//Wait until we are not in vertical blank
        }
        else
        {
            while(IN_DISPLAY); // Wait until we are not in display
            while(IN_VBLANK);  // Wait until we leave vertical blank
        }
        flipRecord.bFlipFlag = FALSE;
                               // No longer need to wait for flip
        lpWaitForVerticalBlank->ddRVal = DD_OK;
                               // We successfully reached blockend
        return DDHAL_DRIVER_HANDLED;// Request handled
    }

    return DDHAL_DRIVER_NOTHANDLED; // Unable to handle request

} /* WaitForVerticalBlank32 */


32-bit Structure Samples

This section applies only to Windows 98/Me.

The following structure can be implemented in the 32-bit HAL as a means of keeping track of the surface after a flip has occurred:

  • FLIPRECORD


FLIPRECORD

This topic applies only to Windows 98/Me.

The FLIPRECORD structure sample keeps track of all the information pertinent to managing a surface after a flip has occurred. It is not defined by DirectDraw and its use is not strictly required. However, it contains all the information needed to perform a flip. It is used in the sample code by updateFlipStatus, getDisplayDuration, Flip32, and WaitForVerticalBlank32.

typedef struct
{
  FLATPTR  fpFlipFrom;
  __int64  liFlipTime;
  DWORD  dwFlipDuration;
  BOOL  bFlipFlag;
  BOOL  bHaveEverCrossedVBlank;
  BOOL  bWasEverInDisplay;
  UINT  dwFlipScanLine;
} FLIPRECORD;

Members

fpFlipFrom
Points to the surface being flipped from.
liFlipTime
Is a 64-bit pointer to the hold time, in milliseconds.
dwFlipDuration
Indicates how long a flip takes in milliseconds (measured during initialization).
bFlipFlag
Indicates whether the driver has been asked to do a flip.
bHaveEverCrossedVBlank
Indicates whether the driver has ever crossed vertical blank.
bWasEverInDisplay
Indicates whether the driver has ever been in display.
dwFlipScanLine
Indicates the scan line being displayed.

Comments

FLIPRECORD keeps track of when it is all right to let an operation proceed against a back buffer. When an operation is requested against the surface specified by the fpFlipFrom member, you need to check the rest of the structure. The liFlipTime member is not needed if a bit exists to tell you when the refresh has occurred. The duration of a flip, in performance ticks, (dwFlipDuration) is not needed in this case either. If liFlipTime is needed, is set with the Win32 QueryPerformanceCounter function, which sets the beginning flip time and the future comparisons which determine the time elapsed. Likewise, if dwFlipDuration is needed, it is set when getDisplayDuration is called at mode change.

The bFlipFlag member keeps track of when a flip has been requested on a surface (setting this flag to TRUE indicates a pending flip). It is changed in updateFlipStatus and WaitForVerticalBlank32, based on the algorithm that determines whether a surface being flipped to has finished being displayed. If the flip has been requested, but the surface has not yet been through a refresh cycle, bFlipFlag is set to TRUE. The bHaveEverCrossedVBlank (filled in by the IN_VBLANK macro), bWasEverInDisplay (filled in by the IN_DISPLAY macro), and dwFlipScanLine (filled in by the CURRENT_VLINE macro) members are all involved in the algorithm that times a flip to avoid tearing (as explained in the updateFlipStatus reference section). The macros just mentioned are implementation-specific (for more information about implementing macros, see 32-bit Macros).


16-bit DirectDraw HAL Samples

This section contains general information about implementing a 16-bit DirectDraw HAL extension to the display miniport driver for Windows 98/Me.

The following functions are the only ones that may need to be included in the 16-bit HAL (depending on the capabilities of your display hardware):

buildDDHALInfo16

DDCreateDriverObject

HALDestroyDriver

Note Although any of the callback functions of the 32-bit DirectDraw HAL can be implemented in 16-bit code, in the interest of speed — and, potentially, forward compatibility — it is wisest to leave them in the 32-bit HAL.


buildDDHALInfo16

This topic applies only to Windows 98/Me.

The buildDDHALInfo16 function collects information about the 16-bit HAL for DirectDraw in the DDHALINFO structure.

Most of the DDHALINFO structure is filled out by the 32-bit HAL. The buildDDHALInfo16 function only fills out 16-bit information and information that changes during a mode switch. This includes the mode table, current display mode, primary surface address, pixel format, display heap information (see Memory Heap Allocation for more detail), and any 16-bit callback functions (typically there is only one, HALDestroyDriver).

/***********************************************************************
 *
 * buildDDHALInfo16
 *
 * Fills in the 16-bit side of the HALINFO structure. Most of the
 * structure has been filled in by our 32-bit driver.
 *
 * This function fills in only 16-bit-specific stuff, or things that
 * change on every mode switch.
 *
 ***************************************************************************/

BOOL buildDDHALInfo16()
{
    int                 i;
    LPDDHALMODEINFO     lpMode;

    /*
     * Modify the structures in our shared window with the 32-bit driver
     */
    #define cbDDCallbacks        DriverData.DDCallbacks
    #define cbDDSurfaceCallbacks DriverData.DDSurfaceCallbacks
    #define cbDDPaletteCallbacks DriverData.DDPaletteCallbacks
    #define ddHALInfo            DriverData.HALInfo

    /*
     * Count the number of modes in the mode table. The table lives in
     * Setmode.c, not this file.
     */
    for (i=0; ModeList[i].dwWidth != 0; i++)
        ;

    ddHALInfo.dwNumModes = i;
    ddHALInfo.lpModeInfo = ModeList;

    /*
     * Current video mode
     */
    ddHALInfo.dwModeIndex = DriverData.ModeNumber;
    lpMode = &ModeList[ddHALInfo.dwModeIndex];

    /*
     * Current primary surface attributes
     */
    ddHALInfo.vmiData.fpPrimary = DriverData.ScreenAddress;

    /*
     * Fill in the pixel format
     */
    ddHALInfo.vmiData.ddpfDisplay.dwSize  = sizeof (DDPIXELFORMAT);
    ddHALInfo.vmiData.ddpfDisplay.dwFlags = DDPF_RGB;
    ddHALInfo.vmiData.ddpfDisplay.dwRGBBitCount = lpMode->dwBPP;

    ddHALInfo.vmiData.dwDisplayWidth  = lpMode->dwWidth;
    ddHALInfo.vmiData.dwDisplayHeight = lpMode->dwHeight;
    ddHALInfo.vmiData.lDisplayPitch   = lpMode->lPitch;

    if (lpMode->dwFlags & DDMODEINFO_PALETTIZED )
    {
        ddHALInfo.vmiData.ddpfDisplay.dwFlags |= DDPF_PALETTEINDEXED8;
    }

    ddHALInfo.vmiData.ddpfDisplay.dwRBitMask = lpMode->dwRBitMask;
    ddHALInfo.vmiData.ddpfDisplay.dwGBitMask = lpMode->dwGBitMask;
    ddHALInfo.vmiData.ddpfDisplay.dwBBitMask = lpMode->dwBBitMask;
    ddHALInfo.vmiData.ddpfDisplay.dwRGBAlphaBitMask = lpMode->dwAlphaBitMask;

    /*
     * figure out where to put the video heap:
     *
     *  ScreenAddress ----> +----------------+
     *                      |                |
     *                      |                |
     *                      |                |
     *                      |   visible      |
     *                      |   screen       |
     *                      +----------------+
     *                      | non visible    |
     *                      | "scratch" area |
     *                      +----------------+
     *  VideoHeapBase ----> |                |
     *                      |   extra video  |
     *                      |   memory       |
     *                      |                |
     *                      |                |
     *                      ~~~~~~~~~~~~~~~~~~
     *                      ~~~~~~~~~~~~~~~~~~
     *                      |                |
     *                      |                |
     *                      +----------------+
     */
#define WORK_AREA_SIZE   0

    DriverData.VideoHeapBase  = DriverData.ScreenAddress;
    DriverData.VideoHeapBase += lpMode->dwHeight * lpMode->lPitch;
    DriverData.VideoHeapBase += WORK_AREA_SIZE;
    DriverData.VideoHeapEnd   = DriverData.ScreenAddress + DriverData.TotalVRAM;

    ddHALInfo.vmiData.dwNumHeaps = sizeof(DriverData.vidMem) / sizeof(DriverData.vidMem[0]);
    ddHALInfo.vmiData.pvmList    = DriverData.vidMem;

    DriverData.vidMem[0].dwFlags = VIDMEM_ISLINEAR;
    DriverData.vidMem[0].ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
    DriverData.vidMem[0].fpStart = DriverData.VideoHeapBase;
    DriverData.vidMem[0].fpEnd   = DriverData.VideoHeapEnd;

    DPF("TotalVRAM     = %08lX", DriverData.TotalVRAM);
    DPF("ScreenAddress = %08lX", DriverData.ScreenAddress);
    DPF("ScreenSize    = %08lX", lpMode->dwHeight * lpMode->lPitch);
    DPF("VideoHeapBase = %08lX", DriverData.VideoHeapBase);
    DPF("VideoHeapEnd  = %08lX", DriverData.VideoHeapEnd);
    DPF("VideoHeapSize = %08lX", DriverData.VideoHeapEnd - DriverData.VideoHeapBase);

    /*
     * callback functions (give DDRAW 16:16 pointers)
     */
    ddHALInfo.lpDDCallbacks        = &cbDDCallbacks;
    ddHALInfo.lpDDSurfaceCallbacks = &cbDDSurfaceCallbacks;
    ddHALInfo.lpDDPaletteCallbacks = &cbDDPaletteCallbacks;

    /*
     * This is the only 16-bit callback, all the others are either
     * undefined or 32-bit.
     */
    cbDDCallbacks.DestroyDriver = HALDestroyDriver;

    return TRUE;

} /* buildDDHALInfo16 */


DDCreateDriverObject

This topic applies only to Windows 98/Me.

The DDCreateDriverObject function creates a driver object and registers it with DirectDraw. If the driver object is created during a mode change, this function re-registers the driver and driver capabilities with DirectDraw.

During initialization (see Driver Initialization), DirectDraw issues a GDI escape call asking this function to create a driver object and register it with DirectDraw. In this case it is called with bReset set to 0. When this function is called from Enable or ReEnable, bReset is set to 1 to indicate a mode change. When this happens, DDCreateDriverObject has to reregister the mode and driver capabilities with DirectDraw. In both cases the driver object has to be registered with DirectDraw. The function called to register with DirectDraw comes from the DDNEWCALLBACKFNS escape (see the buildDDHALInfo32 description). If this escape has not been received, it cannot register.

If the HAL is using VflatD, DDCreateDriverObject starts VflatD. Otherwise it sets up for linear memory access (for more information, see VflatD). DDCreateDriverObject also calls buildDDHALInfo16, which fills in the rest of the DDHALINFO structure (most of DDHALINFO has already been filled in by the 32-bit counterpart to this function, buildDDHALInfo32).

/*
 * DDCreateDriverObject
 *
 * DDCREATEDRIVEROBJECT handler.
 *
 * Called at ESCAPE time or when the mode is set.
 *
 * When called from ESCAPE,
 * DirectDraw issues a GDI Escape call asking us to create a driver
 * object and register it with DirectDraw.
 *
 *     bReset           will be 0
 *
 * When called from Enable,
 * the display driver calls this function internally, every time the
 * display mode has changed. In this case we need to reregister
 * the mode and driver caps with DirectDraw.
 *
 *     bReset           will be 1
 *
 * In both cases we need to call DirectDraw to register our driver
 * object. The function we need to call to register with DirectDraw is
 * given to us with the DDNEWCALLBACKFNS escape (see DDNewCallbackFns).
 * If we have not received this escape we should not register.
 *
 */
BOOL DDCreateDriverObject(BOOL bReset)
{
    DPF("DDCreateDriverObject(%d)", bReset);

    /*
     * Do we have the function we need to call to register ourself?
     */
    if (DriverData.HALCallbacks.lpSetInfo == NULL)
    {
        DPF("DDCreateDriverObject: failing because lpSetInfo == NULL");
        return FALSE;
    }

    /*
     * If we have not connected with our 32-bit alter ego, don't
     * register.
     */
    if (DriverData.HALInfo.dwSize != sizeof(DDHALINFO))
    {
        DPF("DDCreateDriverObject: failing because 32-bit driver did not fill in stuff");
        return FALSE;
    }

    /*
     * Do we need VflatD for access to the frame buffer?
     */
#ifdef VFLATD
    if (!bReset && DriverData.ScreenAddress == 0 &&
        DriverData.ScreenSel == VFDQuerySel())
    {
        if (VFDBeginLinearAccess())
        {
            DriverData.RealScreenAddress = VFDQueryBase();
            DPF( "Using VFLATD, addr=%08lx", DriverData.RealScreenAddress);
        }
    }
    else
    {
        DriverData.RealScreenAddress = DriverData.ScreenAddress;
        DPF( "RealScreenAddress=%08lx", DriverData.RealScreenAddress);
    }
#endif

    /*
     * Set up 16-bit HAL info
     */
    buildDDHALInfo16();

    /*
     * Call DirectDraw to register our driver object.
     */
    return DriverData.HALCallbacks.lpSetInfo(&DriverData.HALInfo, bReset);

} /* DDCreateDriverObject */


HALDestroyDriver

This topic applies only to Windows 98/Me.

The HALDestroyDriver function destroys the DirectDraw driver object. This frees up shared resources and turns off VflatD (if bank switching is enabled).

/***************************************************************************
 * HALDestroyDriver
 ***************************************************************************/

DWORD __loadds CALLBACK HALDestroyDriver(LPDDHAL_DESTROYDRIVERDATA p)
{
    DPF("DDHALDestroyDriver");

    DriverData.HALCallbacks.lpSetInfo = 0; // Makes this function
                               // unavailable

    //
    // If we are using VflatD, turn off linear mode.
    //
#ifdef VFLATD
    if (DriverData.ScreenAddress == 0)
    {
        DPF("Done using VflatD");
        DriverData.RealScreenAddress = 0;
        VFDEndLinearAccess();
    }
#endif

    p->ddRVal = DD_OK;
    return DDHAL_DRIVER_HANDLED;

} /* HALDestroyDriver */


Return Values for DirectDraw and Direct3D

Errors are represented by negative values and cannot be combined. The following lists some values that can be returned by the Microsoft® DirectDraw® and Direct3D® functions that are described in the Windows® DDK documentation. For a list of the error codes that each function can return, see the function descriptions in the reference section. Refer to DirectDraw header file ddraw.h for a complete listing of error codes and return values.

A DirectDraw driver must return one of the two return codes: DDHAL_DRIVER_HANDLED or DDHAL_DRIVER_NOTHANDLED. If the driver returns DDHAL_DRIVER_HANDLED, then it must also return either DD_OK or one of the error codes listed in ddraw.h.

Return Code | Meaning
DD_OK | The request completed successfully.
DDHAL_DRIVER_HANDLED | The driver has performed the operation and returned a valid return code for that operation in the ddrval member of the structure passed to the driver's callback. If this code is DD_OK, DirectDraw or Direct3D proceeds with the function. Otherwise, DirectDraw or Direct3D returns the error code provided by the driver and aborts the function.
DDHAL_DRIVER_NOCKEYHW | The display driver couldn't handle the call because it ran out of color key hardware resources.
DDHAL_DRIVER_NOTHANDLED | The driver has no comment on the requested operation. If the driver is required to have implemented a particular callback, DirectDraw or Direct3D reports an error condition. Otherwise, DirectDraw or Direct3D handles the operation as if the driver callback had not been defined by executing the DirectDraw or Direct3D device-independent implementation. DirectDraw and Direct3D typically ignore any value returned in the ddrval member of that callback's parameter structure.
DDERR_UNSUPPORTED | The operation is not supported.
DXERR_GENERIC | There is an undefined error condition.
DXERR_OUTOFCAPS | The hardware needed for the requested operation has already been allocated.
DXERR_UNSUPPORTED | The operation is not supported.


DirectX Video Acceleration Overview

Microsoft® DirectX® Video Acceleration (DirectX VA) provides an application programming interface (API) and a corresponding device driver interface (DDI) for acceleration of digital video decoding. The API supports alpha blending for purposes such as DVD subpicture support. Encryption support is provided for applications that might require it.

The video acceleration DDI establishes a common interface that provides access to hardware acceleration capabilities. This interface also provides cross-vendor compatibility between user-mode software applications and acceleration capabilities. It supports the decoding of video in formats including the H.26x series from the ITU-T, and the MPEG-x series from ISO/IEC JTC1. In particular, this interface provides support for the following motion-compensated video codec standards:

  • MPEG-2 "main profile" video (formally ITU-T Recommendation H.262 or ISO/IEC 13818-2)
  • ITU-T Recommendation H.261 video
  • ITU-T Recommendation H.263 video
  • MPEG-1 video (formally ISO/IEC 11172-2)
  • A subset of MPEG-4 video (formally ISO/IEC 14496-2)

The API and DDI permit one or more stages of the video decoding process to be divided between the host CPU and the video hardware accelerator. The accelerator executes the motion-compensated prediction (MCP), and may also execute the inverse discrete-cosine transform (IDCT) and the variable-length decoding (VLD) stages of the decoding process.

Video processing operations that are frequently-executed and simple are offloaded onto an accelerator. By confining common video processing operations to the accelerator, video acceleration can be obtained with minimal standard-specific customization to the accelerator. User-mode implementations can leave complex, less frequently-executed operations, such as bitstream parsing and variable-length decoding (VLD), to the host CPU.

The information presented here is applicable to both device driver (DDK) and (SDK) developers. The format specified defines how information is exchanged between the user-mode host decoder and the kernel-mode device driver. In most cases, the data is transferred from the host to the device driver but, in some cases, data is sent in the other direction.

This section includes the following topics:

IAMVideoAccelerator Interface

DirectX VA Data Flow Management

DirectX VA Operations

Restricted Modes


IAMVideoAccelerator Interface

The IAMVideoAccelerator interface enables a video decoder filter to access the functionality of a video accelerator. Operation of the IAMVideoAccelerator interface results in use of the motion compensation device driver interface, which is accessed through the DD_MOTIONCOMPCALLBACKS structure. For more information on the IAMVideoAccelerator interface, see the Microsoft Platform SDK.


Video Decoding

The DirectX VA API decodes a single video stream. No support is provided to support multiple video streams. Support of multiple video streams therefore requires a separate DirectX VA session for each video stream (for example, a separate pair of output and input pins for the video decoder and acceleration driver to use in filter graph operation).


Decoder Stages

The decoder stages that are depicted in the following figure show the operation of the MCP and IDCT parts of an accelerator.

Decoder Stages

Built on Wednesday, July 11, 2001


Frame Buffer Organization

All picture buffers are assumed to have frame-organized buffers as described in the MPEG-2 video specification. Address units are given in frame coordinates unless otherwise specified.

It is possible to use an implementation-specific translation layer to losslessly convert prediction blocks that are described in frame coordinates to field coordinates. For example, a single frame motion prediction can be broken into two separate, top and bottom macroblock-portion predictions.

Three video component channels {Y, Cb, Cr} are decoded using interfaces defined for DirectX VA. Motion vectors for the two chrominance components are derived from those sent for luminance components. The accelerator is responsible for converting any of these motion vectors to different coordinate systems that may be used.

The following figure shows how video data buffering is implemented in the host and accelerator

Video Data Buffering in Host and Accelerator Systems


Implementation of Current Standards

The basic operations of H.261, MPEG-1, MPEG-2 (H.262), H.263, and MPEG-4 are listed in the following topics:

ITU-T H.261

MPEG-1

MPEG-2 (H.262)

ITU-T H.263

MPEG-4


ITU-T H.261

This standard is formally titled "Video Codec for Audiovisual Services at px64 kbit/s," ITU-T Recommendation H.261. Recommendation H.261 contains the same basic design later used in other video codec standards. This standard uses 8-bit samples with Y, Cb, and Cr components, 4:2:0 sampling, 16x16 "macroblock"-based motion compensation, 8x8 IDCT, zig-zag inverse scanning of coefficients, scalar quantization, and variable-length coding of coefficients based on a combination of zero-valued run-lengths and quantization index values.

All H.261 prediction blocks use forward-only prediction from the previous picture. H.261 does not have half-sample accurate prediction filters, but instead uses a type of low-pass filter called the "loop filter" (Section 3.2.3 of the H.261 specification) that can be turned off or on during motion compensation prediction for each macroblock.

Annex D Graphics

Recommendation H.261 Annex D Graphic Transfer mode can be supported by reading four decoded pictures from the accelerator back onto the host and interleaving them there for display as a higher-resolution graphic picture.


MPEG-1

The MPEG-1 video standard is formally titled ISO/IEC 11172-2. This standard was developed not long after H.261 and borrowed significantly from it. The MPEG-1 standard does not have a loop filter; instead it uses a simple half-sample filter that attempts to resolve subpixel movement between frames. Two additional prediction modes, bidirectional and backward prediction, were added. These prediction modes require one additional reference frame to be buffered. The bidirectional prediction mode averages forward-predicted and backward-predicted prediction blocks. The arithmetic for averaging forward and backward prediction blocks is similar to that for creating a half-sampled "interpolated" prediction block. The basic structure is otherwise the same as H.261.


MPEG-2 (H.262)

The MPEG-2 standard is formally titled "Information Technology – Generic Coding of Moving Pictures and Associated Audio Information: Video," ITU-T Recommendation H.262 | ISO/IEC 13818-2. This standard added only a basic 16x8 shape to the existing tools of MPEG-1 (from a very low layer perspective). From a slightly higher-layer perspective, MPEG-2 added many additional ways to combine predictions referenced from multiple fields in order to deal with interlaced video characteristics.


ITU-T H.263

ITU-T Recommendation H.263 is formally titled "Video Coding for Low Bit Rate Communication." Recommendation H.263 is a more recent video codec standard that offers improved compression performance relative to H.261, MPEG-1, and MPEG-2. This standard contains a "baseline" mode of operation that supports only the most basic form of H.263. It also contains a large number of optional enhanced modes of operation that can be used for various purposes. Baseline H.263 prediction operates in this interface using a subset of the MPEG-1 features. The baseline mode contains no bidirectional prediction – only forward prediction.

Rounding Control: Several H.263 optional modes require rounding control. This feature is supported by the bRcontrol member of DXVA_PictureParameters.

Motion vectors over picture boundaries: Several H.263 optional modes allow motion vectors that address locations outside the boundaries of a picture, as defined in H.263 Annex D. This functionality is supported by the bPicExtrapolation member of DXVA_PictureParameters, which indicates whether the accelerator needs to support such motion. There are two basic ways of supporting such motion:

  • Clip the value of the address on each sample fetch to ensure that it stays within picture boundaries.
  • Pad the picture by duplicated samples to widen the actual memory area used by one macroblock width and height across each border of the picture.

The accelerator can use either method; the result is the same.

Bidirectional motion prediction: The bidirectional motion prediction used in some optional H.263 prediction operations uses a different rounding operator than MPEG-1. (It uses downward-rounding of half integer values as opposed to upward-rounding.) This is supported by the bBidirectionalAveragingMode member of the DXVA_PictureParameters structure.

Four-MV motion compensation (4MV): Although each macroblock in H.263 is 16x16 in size, some optional modes (for example, Annex F and Annex J of H.263) allow four motion vectors to be sent for a single macroblock, with one macroblock for each 8x8 luminance block within the macroblock. The corresponding 8x8 chrominance area uses a single derived motion vector.

Overlapped Block Motion Compensation (OBMC): H.263 Annex F contains Overlapped Block Motion Compensation (OBMC) for luminance samples in addition to 4MV support. OBMC prediction is supported by allowing twelve motion vectors to be sent for forward prediction of a macroblock.

OBMC prediction blocks can be realized in hardware as a combination of predictions organized into three planes: a current plane (with a plane index of zero), an upper/lower plane (with a plane index of one), and a left/right plane (with a plane index of two). The three planes can serve as temporary storage for the blocks q(x,y), r(x,y), and s(x,y) defined in H.263 Section F.3. After each of the three planes have been filled out for all four blocks, they would then be combined according to the formula in H.263 Section F.3, and weighted by their respective H matrices given in H.263 Annex F.

As an example, an OBMC luminance macroblock prediction may be comprised of eight top/bottom prediction blocks of 8x4 shape, eight left/right blocks of 4x8 shape, and four current blocks of 8x8 shape. If all four of the motion vectors for the plane with index 0 have the same motion vector (that is, when not in a 4MV macroblock), a single 16x16 macroblock prediction can be used to fill the entire 16x16 plane.

In terms of the representation of the OBMC process, ten motion vectors are sent for the macroblock. The first four are for the Y0, Y1, Y2, and Y3 blocks in the current macroblock. Remote vectors are then sent in the following order:

  1. the left and right halves of the top of the macroblock
  2. the top and bottom halves of the left side of the macroblock
  3. the top and bottom halves of the right side of the macroblock

(H.263 does not use distinct remote vectors for the left and right halves of the bottom of the macroblock – it instead reuses the vectors for the current macroblock.)

H.263 Registration of One 8x8 Block in the OBMC Prediction Planes

PB frames (Annex G and M): In this mode, macroblocks for a P-frame and a pseudo B-frame are multiplexed together into the unique "PB-frame" picture coding type. The B-frame portion of each macroblock borrows from information encoded for the P-frame portion of the macroblock: The B-frame forward and backward motion vectors are scaled from the P-frame vector, and the reconstructed P-frame macroblock serves as backward reference for the B-frame portion. The PB-frame includes only a pseudo B-frame since the backward macroblock can only refer to the reconstructed P macroblock that is contained within the same PB macroblock. However, as with traditional B-frame semantics, a B macroblock within a PB-frame can refer to any location within the forward-reference frame.

The limitation of the backward reference creates smaller size backward prediction block shapes as described in H.263 and depicted in the preceding figure. PB-frames are labeled as a distinct macroblock type that has two motion vectors.

Deblocking Filter (Annex J): Special commands are defined to accelerate deblocking filters, whether used in the loop as with Annex J, or outside the loop as is the case when deblocking H.261 pictures or H.263 baseline pictures. The host CPU must create deblocking commands that observe GOB or slice segments if necessary.

Reference Picture Selection (Annexes N and U): Multiple reference frames are supported by the accelerator using the picture index selection field of each prediction block.

Scalability (Annex O): H.263 Spatial scalability B-frames are very similar in this interface to MPEG-1 B-frames. Spatial scalability requires upsampling the lower-layer reference picture and then using the upsampled picture as the reference (in all other aspects, it is essentially the same as signal-to-noise ratio and temporal scalability). The appropriate bidirectional averaging rounding control should be set to downward-biased averaging for H.263. (MPEG-1 and MPEG-2 use upward-biased averaging, and H.263 uses downward-biased averaging.)

Reference Picture Resampling (Annex P): The simple form of this annex is supported by reference buffer resampling. For advanced forms of Annex P resampling, the reconstructed frames that serve as reference frames must be resampled by external means and stored as reference frame buffers that are addressable by the accelerator.

Reduced-Resolution Update mode (Annex Q): The H.263 reduced-resolution update mode is not currently supported, as it has unusual residual upsampling requirements, a different form of deblocking filter, and a different form of advanced prediction OBMC. However, reduced-resolution update-mode operation may be supported in this interface with host-based IDCT processing when the deblocking filter mode is active and the advanced prediction mode is inactive.

Independent Segment Decoding (Annex R): There is no low-level or accelerator awareness of independent segment borders. Some forms of Annex R can be supported without any special handling (for example, baseline plus Annex R). Forms of Annex R that require picture segment extrapolation can be supported by decoding each segment as a picture and then constructing the complete output picture from these smaller pictures.

Specific IDCT (Annex W): This interface supports the IDCT specified in Annex W of H.263.

Other H.263 Optional Features: Other optional features of H.263 can be supported without any impact on the accelerator interface. For example, Annexes I, K, S, and T can be easily handled by altering the host side of the processing operation without any impact on the accelerator.


MPEG-4

MPEG-4 was based heavily on H.263 for progressive-scan coding, and on MPEG-2 for support of interlace and color sampling formats other than 4:2:0. The features that support H.263 and MPEG-2 can be used to support MPEG-4.

MPEG-4 can support a sample accuracy of more than eight bits. DirectX VA includes a mechanism to support more than eight bits per pixel using the bBPPminus1 member of DXVA_PictureParameters.

Note The features most unique to MPEG-4, such as shape coding, object orientation, face modeling, mesh objects, and sprites, are not supported in DirectX VA.


Prediction Principles

Block motion-compensated prediction (MCP) is the basic tool that gives MPEG and the H.26x family of codecs the advantage over pure still-frame coding methods such as JPEG. Generic instances of prediction exist at many stages of the codec, but MCP is the most processing intensive.

Motion vectors, DCT coefficients, and other data that is not directly part of the MCP process also employ prediction to make the transmitted form of the data more compact. These instances of prediction are considered to be executed on the host CPU processor or bitstream parser/variable-length-decoding unit.

In a generic prediction coding scheme, previously transmitted and decoded data serves as the prediction for current data, and differences between the prediction and the actual current data values are sent as prediction error. The transmitted difference information updates the prediction to the correct value, or, in the case of MCP, to a value that is a close enough approximation to a desired value. Previously decoded frames are used to predict or "guess" what future frames should look like. The difference data (known as prediction error) then corrects the guess, attempting to bring the combined prediction + prediction error (reconstructed) image as close to the original (before compression) future frame as possible. Reconstructed elements are stored and used as prediction for future elements.

This recursive loop is occasionally broken by various types of resets that are specific to the element being predicted. The resets are described by the semantics of the decoding process. For example, motion vectors and DC coefficient predictions are reset at slices, while the whole temporal frame prediction chain is reset by an intra-refresh frame. The temporal basic prediction loop fits this description, but works with modified data taken from whole frames that serve as prediction. Data from the reference frames that serve as prediction are modified in order to account for movement or other types of change that occur over time.

The following figure shows the signal flow for motion-compensated prediction.

Generic MCP Signal Flow


Stages of Prediction

Previous Next

Macroblock Prediction

The formation of a macroblock prediction (through MCP) must be done as a series of discrete phases as shown below.

Signal Flow of Motion Compensation Prediction Blocks


Uncompressed Picture Formats

For applications to use the uncompressed decoded pictures produced through DirectX VA, pictures must be produced in a known format. The list of uncompressed picture formats supported by any DirectX VA accelerator must contain at least one member of the pixel formats described in 4:2:2 Video Pixel Formats or 4:2:0 Video Pixel Formats.


4:2:2 Video Pixel Formats

To decode compressed 4:2:2 video, use one of the following uncompressed pixel formats.

Pixel Format | Description
YUY2 | Data can be treated as an array of unsigned char in which the first byte contains the first sample of Y, the second byte contains the first sample of Cb, the third byte contains the second sample of Y, the fourth byte contains the first sample of Cr; and so on (such that if addressed as an array of two little-endian WORD type variables, the first WORD contains Y0 in the LSBs and Cb in the MSBs, and the second WORD contains Y1 in the LSBs and Cr in the MSBs)..
UYVY | The same as "YUY2", except for swapping the byte order in each word (such that if addressed as an array of two little-endian WORD type variables, the first WORD contains Cb in the LSBs and Y0 in the MSBs, and the second WORD contains Cr in the LSBs and Y1 in the MSB).


4:2:0 Video Pixel Formats

To decode compressed 4:2:0 video, use one of the following uncompressed pixel formats:

Pixel Format | Description
YUY2 | As described in 4:2:2 Video Pixel Formats, except that two lines of output Cb and Cr samples are produced for each actual line of 4:2:0 Cb and Cr samples, the second of each pair of such two lines being either a duplicate of the first or an average of the first and third.
UYVY | As described in 4:2:2 Video Pixel Formats, except that two lines of output Cb and Cr samples are produced for each actual line of 4:2:0 Cb and Cr samples, the second of each pair of such two lines being either a duplicate of the first or an average of the first and third.
YV12 | All Y samples are found first in memory as an array of unsigned char (possibly with a larger stride for memory alignment), followed immediately by all Cr samples (with half the stride of the Y lines, and half the number of lines), then followed immediately by all Cb samples in a similar fashion.
IYUV | The same as YV12, except for swapping the order of the Cb and Cr planes.
NV12 | A format in which all Y samples are found first in memory as an array of unsigned char with an even number of lines (possibly with a larger stride for memory alignment), followed immediately by an array of unsigned char containing interleaved Cb and Cr samples (such that if addressed as a little-endian WORD type, Cb would be in the LSBs and Cr would be in the MSBs) with the same total stride as the Y samples. This is the preferred 4:2:0 pixel format.
NV21 | As in NV12, except that Cb and Cr samples are swapped so that the chroma array of unsigned char would have Cr followed by Cb for each sample (such that if addressed as a little-endian WORD type, Cr would be in the LSBs and Cb would be in the MSBs).
IMC1 | As in YV12, except that the stride of the Cb and Cr planes is the same as the stride in the Y plane. The Cb and Cr planes are also restricted to fall on memory boundaries that are a multiple of 16 lines (a restriction that has no effect on usage for the standard formats, since the standards all use 16×16 macroblocks).
IMC2 | As in IMC1, except that Cb and Cr lines are interleaved at half-stride boundaries. In other words, each full-stride line in the chrominance area starts with a line of Cr, followed by a line of Cb that starts at the next half-stride boundary. (This is a more address-space-efficient format than IMC1, cutting the chrominance address space in half, and thus cutting the total address space by 25%.) This runs a close second in preference relative to NV12, but NV12 appears to be more popular.
IMC3 | As in IMC1, except for swapping Cb and Cr.
IMC4 | As in IMC2, except for swapping Cb and Cr.


Accelerator Sequentiality Requirements

The host software decoder (not the hardware accelerator) ensures that race conditions do not cause undesirable behavior in the operation of the interface. However, it is the hardware accelerator that reports, when queried, whether the display of an uncompressed surface is pending or in progress and if requested operations have been completed.


Software Decoder Sequentiality Requirements

Requirements must be observed to assure the proper operation of sequential operations in the decoding process and to avoid tearing artifacts on the display. These concern the handling of uncompressed surfaces for decoding and display. The guiding principle is: Don't write over what you need for referencing or display, and avoid race conditions. This principle can be decomposed into two rules:

  1. Do not overwrite any picture that has been submitted for display unless it has already been shown on the display and also removed from the display.
  2. Do not overwrite any picture that is needed as a reference for the creation of other pictures that have not yet been created.

The software decoder must query the status of the accelerator to avoid race conditions. The decoder must also use a sufficient number of uncompressed picture surfaces to ensure that space is available for all necessary operations. This results in a need for at least four uncompressed picture surfaces for decoding video streams consisting of I, B, and P pictures (more surfaces are generally encouraged and are necessary for some operations such as the use of front-end alpha blending). Using extra surfaces can greatly reduce the need to wait for operational dependencies to be resolved.

Examples that show the decoding of conventional I-, B-, and P-structured video frames (without using a deblocking filter) are provided in Using Four Uncompressed Surfaces for Decoding and Using Five or More Uncompressed Surfaces for Decoding.

Note For compressed buffers, as well as for uncompressed surfaces, it is generally better to cycle through the allocated and available buffers rather than to keep reusing the same buffer or the same subset of allocated buffers. This can reduce the possibility of bottlenecks that require delays to be added to wait on unnecessary dependencies. In some cases, the allocation of multiple buffers by a driver may be taken as an indication that cycling through these buffers for double or triple buffering is the proper way to operate and to avoid artifacts such as temporary picture freezes. (This applies to alpha-blend data loading in particular.)


Using Four Uncompressed Surfaces for Decoding

The following table shows a hypothetical case of a video decoder that requires one frame time to decode each picture. It decodes a bitstream consisting of a steadily-increasing number of B pictures starting from zero B pictures after an initial I picture. The bitstream of B pictures occurs between pairs of P pictures. In this table, a letter shows the type of each picture (I, B, or P), a subscript shows the frame display index (the temporal display order of each picture), and a superscript shows the number of the buffer containing the picture.

Decoding Process | I00 | P11 | P23 | B32 | P06 | B14
Display Process |  |  | I00 | P11 | B32 | P23
Frames Decoded (at start of interval) | 0 | 1 | 2 | 3 | 4 | 5
Decoding Process | B35 | P210 | B17 | B38 | B19 | P015
Display Process | B14 | B35 | P06 | B17 | B38 | B19
Frames Decoded (at start of interval) | 6 | 7 | 8 | 9 | 10 | 11
Decoding Process | B311 | B112 | B313 | B114 | P221 | B316
Display Process | P210 | B311 | B112 | B313 | B114 | P221
Frames Decoded (at start of interval) | 12 | 13 | 14 | 15 | 16 | 17
Decoding Process | B117 | B318 | B119 | B320 | P028 |
Display Process | B316 | B117 | B318 | B119 | B320 |
Frames Decoded (at start of interval) | 18 | 19 | 20 | 21 | 22 |

Each B picture in the preceding table requires two prior pictures in bitstream order until it can be decoded. As a consequence, the decoder cannot begin displaying pictures with their proper timing until after the second picture has been decoded—that is, until during the third time slice of decoding. Somewhere during this time slice, the display of pictures with their proper timing can begin.

The initiation of the display of a picture may not perfectly coincide with the picture that appears on the display. Instead, the display may continue to show a picture prior to the one that was sent for display until the proper time arrives to switch to the new picture. For optimal performance, surface 0 (which holds the first I picture) should not be overwritten for use by the B picture that arrives three frame times later, even though the I picture is not needed by that B picture for referencing. Instead, a fourth surface (surface 3) should be used to hold that B picture. This eliminates the need to check whether the display period of the first I picture has been completed before decoding the B picture.

Application of the two rules described in Software Decoder Sequentiality Requirements imply that the first three decoded pictures must be placed in different surfaces, because none of them has been displayed until some time during the third period (period 2). Then the fourth decoded picture ideally should be placed in a fourth surface because the display of the first displayed picture may not yet be over until some time during the fourth period (period 3).

A significant bottleneck in the decoding process occurs as a result of having more than two B pictures in succession. This occurs in the preceding table upon encountering the tenth decoded picture (B19). When the third or subsequent B picture in a contiguous series is encountered, the time lag tolerance between the display of one B picture and the use of a surface to hold the next decoded B picture is eliminated. The host decoder must check the display status of the B picture that was displayed in the previous period (B17) to ensure that it has been removed from the display (waiting for this to happen if necessary), then it must immediately use the same surface for the next B picture to be decoded (surface 1 used for B19). The decoder cannot decode the new B picture into either of the surfaces being used to hold its reference I or P pictures (in this case, surfaces 0 and 2 used for P06 and P210), and cannot decode the new B picture into the surface being displayed during the same interval of time (in this case, surface 3 used for B38). So it must use the surface that was displayed in the immediately preceding period (in this case, surface 1).


Using Five or More Uncompressed Surfaces for Decoding

More than four buffers can be used for decoding, allowing the time lag between the start of the display of a buffer and new write operations to that buffer, to increase from a minimum of one display period to two or more. This technique can provide more of an allowance for jitter in the timing of the decoding process. This technique can also enable output processing on the decoded pictures to perform a three-field deinterlace operation as part of the display process. This is because not only is the current picture available for display, but the previous picture is alsoavailable and can provide context and/or allow a one-field delay in the actual display process.

Although a minimum of four buffers is required for effective use of DirectX VA with B pictures, the use of five or more buffers is encouraged – particularly in scenarios that do not require a very low delay. DirectX VA decoders for I, B, P-structured video decoding are therefore expected to set their minimum and maximum requested uncompressed surface allocation counts to at least four and five, respectively, when allocating uncompressed surfaces. Using one or more extra uncompressed surfaces can be a good way to achieve smooth, reliable, tear-free operation.


DirectX VA Data Flow Management

This section describes how data flow is managed in the DirectX Video Acceleration DDI and API. This information is provided in the following topics:

Encryption Support

Setting Up DirectX VA Decoding

bDXVA_Func Variable

Probing and Locking of Configurations

Buffer Description List


Encryption Support

The security needs of some applications can require the encryption of data used in video decoding. DirectX VA data can be encrypted for the following structures and types of data:

  • macroblock control command structures
  • residual difference block structures
  • bitstream buffer contents

In order for the host decoder to use encryption, it must determine what types of encryption the accelerator supports. The information about the types of encryption that are supported by an accelerator is contained in a list of encryption-type GUIDs that are supplied to the host as video-accelerator-type GUIDs. (The "no encryption" GUID DXVA_NoEncrypt must not be sent in this list because support for it is required and therefore implicit.) All accelerators must be capable of operation without encryption in use.

The host chooses the type of encryption protocol to apply and indicates this choice by sending a GUID to the accelerator. In a typical encryption scenario, two more steps must take place before encrypted data can be successfully transferred:

  1. The host decoder may require verification that the accelerator is authorized to receive the data. This verification can be provided by having the accelerator pass a signed structure to the host to prove that it holds an authorized public/private key pair.
  2. The host decoder then sends an encrypted "content key" to the accelerator.

The precise number of steps for initializing the encryption protocol may depend on the particular type of encryption to be used.

Each data set that is exchanged between the host and accelerator to initialize the encryption process must be prefixed by the encryption protocol type GUID in order to distinguish data for one type of encryption from data for another. This is necessary because one type of encryption could be used for one DirectX VA buffer, and another type of encryption could be used for another DirectX VA buffer.

The DXVA_EncryptProtocolHeader structure is used to indicate that an encryption protocol is being used, as well as the type of encryption that is in use.


Setting Up DirectX VA Decoding

In order for a decoder to operate correctly with an accelerator, the decoder and the accelerator must be properly set up for two distinct aspects of operation:

  1. The type of video data format to be decoded. This is codified using the DXVA_ConnectMode structure.
  2. The API configuration for intermediate data formats used and for establishing which processing resides on the host and which on the accelerator. This intermediate data configuration is established by the negotiation of a connection configuration for each DXVA function to be used.


bDXVA_Func Variable

The bDXVA_Func variable is an 8-bit value used to

  • probe and lock a configuration for a specific DirectX VA function
  • specify the function relevant to a configuration structure passed with a probe and lock command
  • signal an actual operation to be performed

When used to probe and lock a configuration for a specific DirectX VA function, bDXVA_Func is placed in the eight LSBs of the DXVA_ConfigQueryorReplyFunc variable and DXVA_ConfigQueryorReplyFunc is conveyed to the accelerator as specified in the Platform SDK.

When used to specify the function relevant to a configuration structure that is passed with a probe and lock command, bDXVA_Func is placed in the eight LSBs of the DXVA_ConfigQueryorReplyFunc variable and in the dwFunction DWORD of the configuration structure used. The relevant configuration structures are as follows:

DXVA_ConfigPictureDecode for compressed picture decoding.

DXVA_ConfigAlphaLoad for alpha-blending data loading.

DXVA_ConfigAlphaCombine for alpha-blending combination.

When used to signal an actual operation to be performed, the bDXVA_Func variable is conveyed to the accelerator as specified in the Platform SDK.


Probing and Locking of Configurations

The process of establishing the configuration for each DirectX VA function (a specific value of bDXVA_Func) that needs configuration is performed by

  1. probing (if needed) to determine whether a configuration is accepted by the accelerator
  2. locking in a specific configuration if it is supported

To determine the support for a specific configuration, send a probing command to the accelerator for the particular bDXVA_Func to be probed with a configuration. Along with the probing command a configuration structure (specific to the bDXVA_Func value) is sent that describes the configuration being probed to determine support. The accelerator then returns an S_OK or S_FALSE indication for whether the specified configuration is supported by the accelerator or not. The accelerator may also return a suggested alternative configuration.

To lock in specific configuration, send a locking command to the accelerator for the particular bDXVA_Func to be locked. Along with the locking command a configuration structure (specific to the bDXVA_Func value) is sent that describes the configuration to be locked in if supported. The accelerator then returns anS_OK or S_FALSE indication for whether the specified configuration is supported by the accelerator. If the indication is S_OK, the specified configuration is locked in for use. If the indication is S_FALSE, a suggested alternative configuration is returned.

The decoder may send a locking command without first sending a probing command for the specified configuration. If the accelerator has returned an S_OK in a probing command for a specific configuration, it returns an S_OK to a locking command for that same configuration, unless otherwise noted.

Once a locking command has been sent and acknowledged for use with a returned S_OK, the specified configuration is locked in, and no further probing or locking commands are sent by the decoder for the same value of bDXVA_Func.

In order to ensure that all DirectX VA software decoders are capable of operation with all DirectX VA accelerators, a minimal interoperability configuration set is defined as a set of configurations that must be supported by any software decoder that uses a particular bDXVA_Func. At least one member of that minimal interoperability configuration set must be supported by every accelerator that indicates support for the bDXVA_Func variable by exposing an associated video accelerator GUID. In some cases, an additional encouraged configuration set also may be defined.


DXVA_ConfigQueryOrReplyFunc Variable

The first 24 bits (MSBs) of the DXVA_ConfigQueryOrReplyFunc DWORD variable contains the QueryOrReplyFlag variable. The definitions for this variable are listed in the following configuration structure definitions:

DXVA_ConfigPictureDecode for compressed picture decoding.

DXVA_ConfigAlphaLoad for alpha blending data loading.

DXVA_ConfigAlphaCombine for alpha blending combination.


Buffer Description List

DirectX VA operates primarily by passing buffers of data from the host to the accelerator. An array of DXVA_BufferDescription structures is referred to as a buffer description list. When a set of buffers is sent from the host decoder to the hardware accelerator, a buffer description list is sent to describe the buffers. The buffer description list contains one DXVA_BufferDescription structure for each buffer in this set. The buffer description list starts with a DXVA_BufferDescription structure for the first buffer of the first type, followed by a DXVA_BufferDescription structure for the next buffer of the same type, and so on. The buffer description list continues with a DXVA_BufferDescription structure for the first buffer of the next type, and so on.

The value in the dwTypeIndex member of the DXVA_BufferDescription structure specifies what type of buffer is used to pass data from the host to the accelerator.

dwTypeIndex | Description
1 | Picture decoding parameter buffer
2 | Macroblock control command buffer (closely associated with and having a 1:1 correspondence with residual difference block data buffers)
3 | Residual difference block data buffer
4 | Deblocking filter control command buffer (with or without a restriction on the effect of the filter)
5 | Inverse quantization matrix buffer (only used with off-host VLD processing)
6 | Slice-control buffer (closely associated with and having a 1:1 correspondence with bitstream data buffers)
7 | Bitstream data buffer
8 | AYUV alpha blending sample buffer
9 | IA44/AI44 alpha blending surface buffer
10 | DPXD alpha-blending surface buffer
11 | Highlight data buffer
12 | DCCMD data buffer
13 | Alpha-blend combination buffer
14 | Picture resampling control buffer
15 | Read-back command buffer. These buffers contain commands to read macroblocks of the resulting picture back to the host.


DirectX VA Operations

This section reviews the following four operations defined for values of the bDXVA_Func variable:

Compressed Picture Decoding (bDXVA_Func=1)

Alpha-Blend Data Loading (bDXVA_Func=2)

Alpha-Blend Combination (bDXVA_Func=3)

Picture Resampling Control (bDXVA_Func=4)


Compressed Picture Decoding (bDXVA_Func=1)

The DXVA_ConfigPictureDecode structure contains the DirectX VA connection configuration data for compressed picture decoding.


Minimal Interoperability Configuration Set (bDXVA_Func=1)

All DirectX VA decoders must interoperate with all DirectX VA accelerators. Every decoder must be capable of operation with any member of a set of connection configurations as specified in the DXVA_ConfigPictureDecode structure, and every DirectX VA accelerator must be capable of operation with at least one connection configuration member of that set. That minimal interoperability set is defined in terms of the members of the DXVA_ConfigPictureDecode structure as follows:

  1. All members of this most basic set have the following aspects in common:
    • guidConfigBitstreamEncryption equals DXVA_NoEncrypt
    • guidConfigMBcontrolEncryption equals DXVA_NoEncrypt
    • guidConfigResidDiffEncryption equals DXVA_NoEncrypt
    • bConfigBitstreamRaw equals zero
    • bConfigHostInverseScan equals zero
    • bConfigSpecificIDCT equals zero
  2. The first two members of this set (among which accelerators are encouraged to support the variation with bConfigSpatialHost8or9Clipping equals zero) are defined by:
    • bConfigMBcontrolRasterOrder equals 1
    • bConfigResidDiffHost equals 1
    • bConfigSpatialResid8 equals zero
    • bConfigResid8Subtraction equals zero
    • bConfigSpatialHost8or9Clipping equals zero or 1
    • bConfigSpatialResidInterleaved equals zero
    • bConfigIntraResidUnsigned equals zero
    • bConfigResidDiffAccelerator equals zero
  3. The third member of the set (not particularly encouraged for accelerator implementation) is defined by:
    • bConfigMBcontrolRasterOrder equals one
    • bConfigResidDiffHost equals 1
    • bConfigSpatialResid8 equals 1
    • bConfigResid8Subtraction equals zero
    • bConfigSpatialHost8or9Clipping equals zero
    • bConfigSpatialResidInterleaved equals 1
    • bConfigIntraResidUnsigned equals zero
    • bConfigResidDiffAccelerator equals zero
  4. The fourth member of this set (not particularly encouraged for accelerator implementation) is defined by:
    • bConfigMBcontrolRasterOrder equals 1
    • bConfigResidDiffHost equals 1
    • bConfigSpatialResid8 equals zero
    • bConfigResid8Subtraction equals zero
    • bConfigSpatialHost8or9Clipping equals 1
    • bConfigSpatialResidInterleaved equals zero
    • bConfigIntraResidUnsigned equals 1
    • bConfigResidDiffAccelerator equals zero
  5. Two additional members of this set (among which accelerators are encouraged to support the variation with bConfigResid8Subtraction = 1) are defined by:
    • bConfigMBcontrolRasterOrder equals one
    • bConfigResidDiffHost equals 1
    • bConfigSpatialResid8 equals 1
    • bConfigResid8Subtraction equals zero or 1
    • bConfigSpatialHost8or9Clipping equals zero
    • bConfigSpatialResidInterleaved equals zero
    • bConfigIntraResidUnsigned equals zero
    • bConfigResidDiffAccelerator equals zero
  6. One additional member of this set is defined only for the MPEG2_C and MPEG2_D restricted mode profiles and indicated in the DXVA_ConnectMode structure. No other profiles include this configuration in their minimal interoperability set. This additional member is defined by:
    • bConfigMBcontrolRasterOrder equals one
    • bConfigResidDiffHost equals zero
    • bConfigResidDiffAccelerator equals 1
    • bConfigHostInverseScan equals zero
    • bConfig4GroupedCoefs equals 1


Additional Encouraged Configuration Set

Some additional configurations are encouraged to be implemented in software decoders, as these configurations may exist in hardware and can provide a significant performance benefit relative to those in the minimal configuration set. As specified by members of DXVA_ConfigPictureDecode, the additional configuration set is defined as follows:

  1. All members of this set have the following aspects in common:
    • guidConfigBitstreamEncryption equals DXVA_NoEncrypt
    • guidConfigMBcontrolEncryption equals DXVA_NoEncrypt
    • guidConfigResidDiffEncryption equals DXVA_NoEncrypt
    • bConfigMBcontrolRasterOrder equals zero
    • bConfigResidDiffHost equals zero
    • bConfigSpatialResid8 equals zero
    • bConfigResid8Subtraction equals zero
    • bConfigSpatialHost8or9Clipping equals zero
    • bConfigSpatialResidInterleaved equals zero
    • bConfigSpecificIDCT equals zero
  2. For good support of off-host bitstream processing acceleration, the first member of this set is defined by:
    • bConfigBitstreamRaw equals 1
    • bConfigResidDiffAccelerator equals zero
    • bConfigHostInverseScan equals zero
    • bConfig4GroupedCoefs equals zero
  3. For good support of off-host IDCT acceleration, the second member of this set is defined by:
    • bConfigBitstreamRaw equals zero
    • bConfigResidDiffAccelerator equals 1
    • bConfigHostInverseScan equals 1
    • bConfig4GroupedCoefs equals zero
  4. For support of off-host IDCT as expected to be found in some implementations, the third member of this set (not particularly encouraged for accelerators relative to the second set member) is defined by:
    • bConfigBitstreamRaw equals zero
    • bConfigResidDiffAccelerator equals 1
    • bConfigHostInverseScan equals zero
    • bConfig4GroupedCoefs equals 1

Accelerators that implement the first member of this set (as specified in item 2 above) are also encouraged to support the second member of the set (as specified in item 3 above). Implementing both members provides flexibility in the manner in which their acceleration capabilities can be used.


Compressed Picture Parameters

The parameters that need to be sent once for each picture to be decoded are specified in the DXVA_PictureParameters structure.


Macroblock-Oriented Picture Decoding

A decoded picture contains one or more macroblock control command buffers if it does not contain bitstream data buffers. The decoding process for every macroblock is addressed (only once) in a buffer of each type that is used. For every macroblock control command buffer, there is a corresponding residual difference block data buffer containing the same set of macroblocks. If one or more deblocking filter control buffers are sent, the set of macroblocks in each deblocking filter control buffer is the same as the set of macroblocks in corresponding macroblock control and residual difference block data buffers.

The processing of the picture requires that the motion prediction for each macroblock must precede the addition of the residual difference data. This can be accomplished either by processing the motion prediction commands first and then reading this data back in from the destination picture buffer while processing the residual difference data buffer, or by processing these two buffers in a coordinated fashion – adding the residual data to the prediction before writing the result to the destination picture buffer. The motion prediction command and residual difference data for each macroblock affect only the rectangular region within that macroblock.

A deblocking filter command for a macroblock may require access to read the reconstructed values of two rows and two columns of samples neighboring the current macroblock at the top and left as well as reconstructed values within the current macroblock. It can result in modification of one row and one column of samples neighboring the current macroblock at the top and left as well as up to three rows and three columns within the current macroblock. The filtering process for a given macroblock could therefore require the prior reconstruction of other macroblocks.

The two different types of deblocking filter buffers are:

  • a buffer type that requires access and modification of the value of reconstructed samples for macroblocks outside the current buffer when the bPicDeblockConfined member of DXVA_PictureParameters is zero), and
  • a buffer type that does not (when bPicDeblockConfined is 1).

To process the first of these two types of deblocking command buffers, the accelerator must ensure that the reconstruction has been completed for all buffers that affect macroblocks to the left and top of the macroblocks in the current buffer before processing the deblocking commands in the current buffer. Processing the second of these two types requires only prior reconstruction values within the current buffer.

The deblocking post-processing can be conducted either by processing the motion prediction and residual difference data for the entire buffer or frame first, followed by reading back in the values of some of the samples and modifying them as a result of the deblocking filter operations, or by processing the deblocking command buffer in a coordinated fashion with the residual difference data buffer—performing the deblocking before writing the final output values to the destination picture buffer.

Note that the destination picture buffer for the deblocked picture could differ from that of the reconstructed picture prior to deblocking, in order to support "outside the loop" deblocking as a post-processing operation that does not affect the sample values used for prediction of the next picture.


Macroblock Control Commands

The generation of each decoded macroblock during compressed picture decoding is governed by a macroblock control command data structure. There are four variations of macroblock control command structures defined in the dxva.h header file, depending on the type of picture to be decoded and the configuration of the decoding process:

  • DXVA_MBctrl_I_HostResidDiff_1: A structure used for intra pictures (when the bPicIntra member of the DXVA_PictureParameters structure is 1) with host-based residual difference decoding (when the bConfigResidDiffHost member of the DXVA_ConfigPictureDecode structure is one).
  • DXVA_MBctrl_I_OffHostIDCT_1: A structure used for intra pictures (when the bPicIntra member of the DXVA_PictureParameters structure is one) with 4:2:0 sampling (when the bChromaFormat member of the DXVA_PictureParameters structure is 1) with off-host residual difference decoding (when the bConfigResidDiffHost member of DXVA_ConfigPictureDecode is zero).
  • DXVA_MBctrl_P_HostResidDiff_1: A structure used for P and B pictures (when the bPicIntra member of DXVA_PictureParameters is zero) with host-based residual difference decoding (when the bConfigResidDiffHost member of DXVA_ConfigPictureDecode is 1) with OBMC not in use (when bPicOBMC is zero) without use of four motion vectors per macroblock for the B part of a PB picture (when at least one of the bPicBinPB or bPic4Mvallowed members of DXVA_PictureParameters is zero) and without use of motion vector reference picture selection (when the bMV_RPS member of DXVA_PictureParameters is zero).
  • DXVA_MBctrl_P_OffHostIDCT_1: A structure used for P and B pictures (when the bPicIntra member of DXVA_PictureParameters is zero) with 4:2:0 sampling (when the bChromaFormat member of DXVA_PictureParameters is 1) with off-host residual difference decoding (when the bConfigResidDiffHost member of DXVA_ConfigPictureDecode is zero) with OBMC not in use (when bPicOBMC is zero) without use of four motion vectors per macroblock for the B part of a PB picture (when at least one of the bPicBinPB or bPic4Mvallowed members of DXVA_PictureParameters is zero) and without use of motion vector reference picture selection (when the bMV_RPS member of the DXVA_PictureParameters structure is zero).

If the picture is not an intra picture (when the bPicIntra member of DXVA_PictureParameters is zero), motion vectors are included in the macroblock control command structure. The number of motion vectors that are included depends upon the type of picture. Additionally, if macroblock-based reference-picture selection is in use, then a reference-picture selection index for each motion vector is also included in the macroblock control-command structure. The space reserved for motion vectors in each macroblock control command is normally the amount needed for four motion vectors. These normal cases include the two non-intra cases described above. The remaining cases (not explicitly defined in the dxva.h header file) are as follows:

  • If OBMC is in use (when the bPicOBMC member of the DXVA_PictureParameters structure is 1) and the picture is not the B part of a PB picture (when the bPicBinPB member of the DXVA_PictureParameters structure is zero), space for ten motion vectors plus any additional space needed to align to a 16-byte boundary is included.
  • If OBMC is in use (when the bPicOBMC member of the DXVA_PictureParameters structure is 1) and the picture is the B part of a PB picture (when the bPicBinPB member of the DXVA_PictureParameters structure is 1), space for eleven motion vectors plus any additional space needed to align to a 16-byte boundary is included.
  • If OBMC is not in use (when the bPicOBMC member of the DXVA_PictureParameters structure is zero) and the picture is the B part of a PB picture (when the bPicBinPB member of the DXVA_PictureParameters structure is 1) and four motion vectors per macroblock are allowed (when the bPic4Mvallowed member of the DXVA_PictureParameters structure is 1), space for five motion vectors plus any additional space needed to align to a sixteen-byte boundary is included.


Low-Level IDCT Processing Elements

The interface supports three low-level methods of handling inverse discrete-cosine transform (IDCT). In all cases, the basic inverse-quantization process, pre-IDCT range saturation, MPEG-2 mismatch control (if necessary), and intra-DC offset (if necessary) are performed on the host, and the final picture reconstruction and reconstruction clipping is done on the accelerator. The first method is to pass macroblocks of transform coefficients to the accelerator for external IDCT, picture reconstruction, and reconstruction clipping. The second and third involve performing an IDCT on the host and passing blocks of spatial-domain results for external picture reconstruction and reconstruction clipping.

The inverse quantization, pre-IDCT saturation, mismatch control, intra-DC offset, IDCT, picture reconstruction, and reconstruction clipping processes are defined in the following steps: (The values of BPP, WT, and HT should be assumed to be equal to 8, unless otherwise specified by the DXVA_PictureParameters structure.)

  1. Perform inverse quantization as necessary (including application of any inverse-quantization weighting matrices) to create a set of IDCT coefficient values F"(u,v) from entropy-coded quantization indices (performed by the host).
  2. Saturate each reconstructed coefficient value F"(u,v) of the transform coefficient block to obtain a value F'(u,v) within the restricted allowable range (performed by the host):

  3. Perform mismatch control (as needed for MPEG-2 only, and performed by the host) by adding up the saturated values of all coefficients in the macroblock (equivalent to XORing their LSBs). If the sum is even, then the saturated value of the last coefficient F'(WT-1,HT-1) is modified by subtracting one if F'(WT-1,HT-1) is odd and adding one if F'(WT-1,HT-1) is even (equivalent to toggling its LSB). (If the sum is odd, the saturated value of F'(WT-1,HT-1) is used without alteration.) The coefficient values subsequent to the saturation and mismatch control are then denoted herein as F(u,v).

    Note MPEG-1 has a different form of mismatch control that consists of altering the value by plus or minus 1 for each coefficient that would otherwise be an even value after inverse quantization. H.263 does not require mismatch control in the sense described in this reference. In any case, where applicable, mismatch control is the host's responsibility.

  4. Add an intra-DC offset if necessary (performed by the host) so that all intra blocks correspond to adding a difference to a spatial reference prediction value of 2(BPP-1). Such an offset is necessary for all of the referenced video-coding standards (H.261, H.263, MPEG-1, MPEG-2, and MPEG-4) except when HostResidDiff is 1 and the bConfigIntraResidUnsigned member of DXVA_ConfigPictureDecode is 1. The intra DC offset has the value (2(BPP-1))WTHT . This value is 1024 in all cases except MPEG-4, which allows BPP to be greater than 8.
  5. Perform the unitary separable transformation (either on the host or the accelerator):

where:

C(u) = 1 for u = 0, otherwise 2,

C(v) = 1 for v = 0, otherwise 2,

x and y are the horizontal and vertical spatial coordinates in the pixel domain,

u and v are the transform-domain horizontal and vertical frequency coordinates, and

WT and HT are the width and height of the transform block (normally both are eight).

The accuracy of this IDCT process must conform to that required in the H.261&3 and MPEG-1&2&4 video-coding standards (all have very similar requirements).

  6. Add the spatial-domain residual information to the motion-compensated prediction value for non-intra blocks or to the constant reference value for intra blocks (this constant being 2(BPP-1) except when HostResidDiff (bit 10 of the wMBtype member of DXVA_MBctrl_P_HostResidDiff_1) is 1 and the bConfigIntraResidUnsigned member of DXVA_ConfigPictureDecode is 1, in which case it is zero) to perform picture reconstruction (on the accelerator).
  7. Clip the picture reconstruction to a range of [0, (2BPP)-1] to store the final resulting picture sample values on the accelerator.


Off-Host IDCT

The transfer of macroblock inverse discrete-cosine transform (IDCT) coefficient data for off-host IDCT processing consists of a buffer of index and value information. Index information is sent as 16-bit words (although only 6-bit quantities are really needed for 8x8 transform blocks), and transform coefficient value information is sent as signed 16-bit words (although only twelve bits are needed for the usual case of 8x8 transform blocks and BPP equal to 8).

Transform coefficients are sent in either DXVA_TCoefSingle or DXVA_TCoef4Group structures. If the bConfig4GroupedCoefs member of the DXVA_ConfigPictureDecode structure is zero, coefficients are sent individually using DXVA_TCoefSingle structures. If bConfig4GroupedCoefs is 1, coefficients are sent in groups of four using DXVA_TCoef4Group structures.


Host Based IDCT

Previous Next

Host-Based IDCT

IDCT may be performed on the host, with the result passed through the API. There are two supported schemes for sending the results – the 16-bit method and the 8-8 overflow method. An indication of which is used is sent in the bConfigSpatialResid8 member of DXVA_ConfigPictureDecode.

16-bit Method

When sending data using the 16-bit method, blocks of 16-bit data are sent sequentially. Each block of spatial-domain data consists of 64 16-bit integers.

If BPP, as derived from the DXVA_PictureParameters structure, is greater than 8, only the 16-bit method is allowed. If the bPicIntra member of DXVA_PictureParameters is 1 and BPP is 8, the 16-bit method is not allowed. If IntraMacroblock is zero, the 16-bit samples are sent as signed quantities relative to the motion-compensated prediction values. If IntraMacroblock is 1, the 16-bit samples are sent as follows:

  • If the bConfigIntraResidUnsigned member of DXVA_ConfigPictureDecode is 1, the samples are sent as unsigned quantities relative to the constant reference value of zero,
  • If the bConfigIntraResidUnsigned member of DXVA_ConfigPictureDecode is zero, the samples are sent as signed quantities relative to the constant reference value of 2(BPP-1).

Blocks of data are sent sequentially, in the order specified by scanning the wPatternCode member of the macroblock control structure for bits with values of 1 from the MSB to LSB. These macroblock control structures are defined in the DXVA_MBctrl_I_HostResidDiff_1 and DXVA_MBctrl_P_HostResidDiff_1 structures.

Note No clipping of these values can be assumed to have been performed on the host, unless the bConfigSpatialHost8or9Clipping member of DXVA_ConfigPictureDecode is 1. Although only a BPP+1 bit range is needed to adequately represent the spatial-domain difference data, the output of some IDCTs will produce numbers beyond this range unless they are clipped.

The accelerator must work with at least a 15-bit range of values. Although video-coding standards typically specify clipping of a difference value prior to adding it to a prediction value (that is, 9-bit clipping in 8-bit-per-sample video), this clipping stage is actually unnecessary since it has no effect on the resulting decoded output picture. It is not assumed that this clipping occurs unless necessary for the accelerator hardware as indicated by the bConfigSpatialHost8or9Clipping member of DXVA_ConfigPictureDecode being set to 1.

The 8-8 Overflow Method

If the BPP parameter derived from DXVA_PictureParameters is 8, the 8-bit difference method may be used. Its use is required if bPicIntra is 1 and BPP is 8. In this case, each spatial-domain difference value is represented using only eight bits. When sending data using the 8-bit method, blocks of 8-bit data are sent sequentially. Each block of 8-bit spatial-domain residual difference data consists of 64 values of DXVA_Sample8.

The macroblock control commands used with host residual difference decoding are defined in the DXVA_MBctrl_I_HostResidDiff_1 and the DXVA_MBctrl_P_HostResidDiff_1 structures.

If IntraMacroblock in the macroblock control command is zero, the 8-bit samples are signed differences to be added or subtracted (as determined from the bConfigResid8Subtraction member of the DXVA_ConfigPictureDecode structure and whether the sample is in a first pass block or overflow block) relative to a motion compensation prediction.

If IntraMacroblock in the macroblock control command is zero, and the difference to be represented for some pixel in a block is too large to represent using only eight bits, a second "overflow" block of samples can be sent.

If IntraMacroblock in the macroblock control command is 1, the 8-bit samples are set as follows:

  • If the bConfigIntraResidUnsigned member of DXVA_ConfigPictureDecode is one, the 8-bit samples are sent as unsigned quantities relative to the constant reference value of zero,
  • If the bConfigIntraResidUnsigned member of DXVA_ConfigPictureDecode is zero, the 8-bit samples are sent as signed quantities relative to the constant reference value of 2(BPP-1).

Overflow blocks are not sent if IntraMacroblock is 1.

Blocks of data are sent sequentially, in the order specified by scanning the wPatternCode member of the macroblock control command for bits with values of 1 from MSB to LSB, and then all necessary 8-bit overflow blocks are sent as specified by the wPC_Overflow member of the macroblock control command. Such overflow blocks are subtracted rather than added if the bConfigResid8Subtraction member of DXVA_ConfigPictureDecode is 1. The first pass of 8-bit differences for each non-intra macroblock is added. If the bPicOverflowBlocks member of DXVA_PictureParameters is zero or the IntraMacroblock member of the macroblock control command is 1, there is no second pass. If bPicOverflowBlocks is 1, IntraMacroblock is zero, and bConfigResid8Subtraction is 1, the second pass of 8-bit differences for each non-intra macroblock is subtracted. If bPicOverflowBlocks is 1, IntraMacroblock is zero, and bConfigResid8Subtraction is zero, the second pass of 8-bit differences for each non-intra macroblock is added.

If any sample is nonzero in both an original 8-bit block and in a corresponding 8-bit overflow block, then:

  • If bConfigResid8Subtraction is zero, the sign of the sample must be the same in both blocks.
  • If bConfigResid8Subtraction is 1, the sign of the sample in the original 8-bit block must be the same as the sign of minus one times the value of the sample in the corresponding overflow block.

This allows the sample to be added to the prediction picture with 8-bit clipping of the result after each of the two passes.

Note The 8+8 method (using 8-bit differences with overflow blocks with bConfigResid8Subtraction equal to zerozero) cannot represent a residual difference value of +255 if IntraMacroblock is zero, which makes it not strictly compliant with video-coding standards. However, this format is supported because it is used in some existing implementations, more efficient than 16-bit sample use in terms of the amount of data needed to represent a picture, and does not normally result in any meaningful degradation of video quality.


Deblocking Filter Control

Deblocking filter-control commands, if present, are sent for each luminance block in a macroblock and are sent once for each pair of chrominance blocks. The commands are sent in raster-scan order within the macroblock, with all blocks for luminance sent before any blocks for chrominance, then one chrominance 4:2:0 command, then one chrominance 4:2:2 command if needed, then two chrominance 4:4:4 commands if needed (the same filtering is applied to both chrominance components).

The filtering for each block is specified by specification of the deblocking to occur across its top edge, followed by specification of the deblocking to occur across its left edge. Deblocking is specified for chrominance only once—and the same deblocking commands are used for both the Cb and Cr components. For example, deblocking of a 16x16 macroblock that contains 4:2:0 data using 8x8 blocks is specified by sending four sets of two (top and left) edge-filtering commands for the luminance blocks, followed by one set of two edge-filtering commands for the chrominance.


Off-Host VLD Bitstream Decoding Operation

When variable-length decoding of raw bitstream data is performed on the accelerator, the data sent by the host for the decoding of the picture is divided into the following buffer types:

Buffer Type | Description
Inverse-quantization matrix | Provides information about how to perform inverse-quantization of the bitstream data.
Slice control | Provides information about the location of start codes and data within a corresponding bitstream data buffer.
Bitstream data | Contains raw streams of data encoded according to a particular video coding specification.

Inverse-Quantization Matrix Buffers

An inverse-quantization matrix buffer is sent to initialize inverse-quantization matrices for off-host bitstream decoding. Inverse-quantization matrix buffers provide information about how to decode all current and subsequent video in the bitstream, until a new inverse-quantization matrix buffer is provided. (Thus, inverse-quantization matrices are persistent.) No more than one inverse-quantization matrix buffer can be sent from the host to the accelerator at a time. The DXVA_QmatrixData structure loads quantization matrix data for compressed video-picture decoding.


Slice-Control Buffers

Slice-control buffers guide the operation of off-host VLD bitstream processing. The host software decoder determines the location of "slice-level" resynchronization points in the bitstream. A slice is defined to be a multi-macroblock layer that includes a resynchronization point in the bitstream data. In H.261 bitstreams, an H.261 GOB is considered a slice. In H.263 bitstreams, a sequence of one or more H.263 GOBs starting with a GOB start code and containing no additional GOB start codes is considered a slice. The slice-control buffer contains an array of DXVA_SliceInfo slice-control structures, which apply to the contents of a corresponding bitstream data buffer.

Bitstream Data Buffer Contents

If a bitstream buffer is used, the buffer simply contains raw bytes from a video bitstream to support off-host decoding including low-level bitstream parsing with variable-length decoding.

Certain restrictions are imposed on the contents of bitstream data buffers, in order to ensure that they are used in a manner consistent with the intended design:

  1. Except for MPEG-1 and MPEG-2, the first bitstream data buffer for each picture must start with all data if any (subsequent to the end of all data for any prior picture) that precedes the first slice for the current picture in the bitstream (for example, the sequence header or picture header).
  2. For MPEG-1 and MPEG-2, the first bitstream data buffer for each picture must start with the slice start code of the first slice of the picture (for example, no sequence header or picture header, because all relevant data is provided in other parameters).
  3. If the start of a slice of bitstream data is located within a particular bitstream data buffer, the end of that slice must also be located within that same data buffer unless the buffer that contains the start of the slice has reached its allocated size.

The decoder should manage the filling of the bitstream data buffers to avoid straddling the slices across different buffers.


Alpha-Blend Data Loading (bDXVA_Func=2)

The second type of DirectX VA function is the loading of information for specifying an alpha-blending surface to be blended with video data. The DXVA_ConfigAlphaLoad structure is used for alpha-blend data loading.


Minimal Interoperability Configuration Set (bDXVA_Func=2)

It is a design requirement for all DirectX VA decoders to interoperate with all DirectX VA accelerators. This requires that every DirectX VA decoder be capable of operation with any member of a set of connection configurations, and that every DirectX VA accelerator be capable of operation with at least one connection configuration member of that set. The minimal interoperability configuration set for alpha-blend data loading consists of all defined values of the bConfigDataType member of DXVA_ConfigAlphaLoad.


Loading an AYUV Alpha Blending Surface

An AYUV alpha-blending surface is defined as an array of samples of 32 bits each in the DXVA_AYUVsample2 structure. This surface can be used as the source for blending a graphic with decoded video pictures.

The width and height of the AYUV alpha-blending surface are specified in the associated buffer description list.

Loading a 16-entry YUV Palette

A 16-entry YUV palette is defined as an array of sixteen DXVA_AYUVsample2 structures. Such a palette is used along with an IA44 or AI44 alpha-blending surface. The palette array is sent to the accelerator in an AYUV alpha-blending sample buffer (buffer type 8). In this case, the bSampleAlpha8 member of DXVA_AYUVsample2 for each sample has no meaning and must be zero.

The YUV palette can be used to create the source for blending a graphic with decoded video pictures. This palette can be used to create the graphic source along with either

•    an IA44/AI44 alpha blending surface, or

•    a DPXD alpha blending surface, a highlight buffer, and DCCMD data

Loading an AYUV Surface

Rather than loading just a sixteen-entry palette, an entire image graphic can simply be loaded directly as an AYUV image to specify the graphic content. In this case, the AYUV graphic is sent to the accelerator in an AYUV alpha-blending sample buffer (buffer type 8).

Loading an IA44/AI44 Alpha Blending Surface

An index-alpha 4-4 (IA44) alpha-blending surface is defined as an array of 8-bit samples, each of which is structured as a byte referred to as a DXVA_IA44sample byte. The four MSBs of this byte contain an index referred to as SampleIndex4, and the four LSBs of this byte contain an alpha value referred to as SampleAlpha4.

An alpha-index 4-4 (AI44) alpha-blending surface is defined as an array of 8-bit samples, each of which is structured as a byte referred to as a DXVA_AI44sample byte. The four MSBs of this byte contain an alpha value referred to as SampleAlpha4 and the four LSBs of this byte contain an index referred to as SampleIndex4.

The SampleIndex4 field contains the index into the sixteen-entry palette for the sample.

The SampleAlpha4 field contains the opacity of the sample, and is interpreted as follows:

  • The value zero indicates that the sample is transparent (so that the palette entry for SampleIndex4 has no effect on the resulting blended picture). For a zero value of SampleAlpha4, the blend specified is to use the picture value without alteration.
  • The value fifteen indicates that the sample is opaque (so that the palette entry for SampleIndex4 completely determines the resulting blended picture).
  • For nonzero values of SampleAlpha4, the blend specified is to add (SampleAlpha4+1) times the graphic value to (15-SampleAlpha4) times the picture value and to the constant 8, and right-shift the result by four places.

The width and height of the IA44 alpha-blending surface are specified in the associated buffer description list.


Loading a DPXD Alpha Blending Surface

A decoded PXD (DPXD) alpha-blending surface is defined as a packed frame-structured array of two-bit samples, each of which is used as an index into a four-color table determined by highlight and DCCMD data. The result of the combination of DPXD, highlight, and DCCMD is equivalent to an IA44 surface, and is used with a sixteen-entry YUV palette for blending. If treated as an array of bytes, the index of the first two-bit sample is placed in the MSBs of the first byte of DPXD data, the next sample in the next two bits, the third sample in the next two bits, the fourth sample in the LSBs, the fifth sample in the MSBs of the next byte, and so on.

The DPXD alpha-blending surface may be created from the PXD information on a DVD, which is in a run-length encoded format. The creation of DPXD from PXD on a DVD requires the host to perform the run-length decoding of the raw data from the disk.

The stride of the surface must be interpreted as the stride in bytes, not in two-bit sample units. However, the width and height must be in two-bit sample units.

Note The PXD on a DVD is in a field-structured interlaced format. The DPXD alpha-blending surface defined herein is not. The host is therefore responsible for interleaving the data from the two fields if forming DPXD from DVD PXD data.

For further clarification of DVD subpicture definition and data field interpretation, see DVD Specifications for Read-Only Disk: Part 3 - Video Specification (v. 1.11, May '99).


Loading Highlight Data

The DXVA_Highlight structure specifies a highlighted rectangular area of a subpicture, and is used along with DCCMD data and a DPXD surface to create an alpha-blending surface. The highlight data is formatted in a manner compatible with the DVD ROM specification. For further clarification of DVD subpicture definition and data field interpretation, see DVD Specifications for Read-Only Disk: Part 3 - Video Specification (v. 1.11, May '99).


Loading DCCMD Data

The DCCMD (display control command) data is formatted in a manner compatible with the DVD ROM specification, and is to be applied along with highlight data to a DPXD surface to create an alpha-blending surface. The DCCMD data buffer contents must consist of data formatted as a list of DVD DCCMDs. For further clarification of DVD subpicture definition and data field interpretation, see DVD Specifications for Read-Only Disk: Part 3 - Video Specification (v. 1.11, May '99).


Alpha-Blend Combination (bDXVA_Func=3)

When the bDXVA_Func variable is equal to three the operation specified is an alpha-blend combination. An alpha-blend combination takes the last loaded alpha-blend source information and combines it with a reference picture to create a blended picture for display. It uses an alpha-blend combination data buffer to control this process.

The DXVA_ConfigAlphaCombine structure establishes the configuration for how alpha blend combination operations are performed.


Minimal Interoperability Configuration Set (bDXVA_Func=3)

It is a design requirement for all DirectX VA decoders to interoperate with all DirectX VA accelerators. This requires that every decoder be capable of operation with any member of a set of connection configurations, and that every accelerator be capable of operation with at least one connection configuration member of that set. The minimal interoperability configuration set for alpha-blend data loading consists of the bConfigBlendType member of DXVA_ConfigAlphaCombine having a choice of values as determined by the restricted mode profile.


Alpha-Blend Combination Buffers

An alpha-blend combination buffer governs the generation of a blended picture from a source picture and a graphic image with accompanying alpha-blending information. In the event that the source and destination pictures are not in 4:4:4 format, every second sample of the graphic blending information (for example, the first, third, fifth, and so on) must be applied to the subsampled source chrominance information in the vertical or horizontal direction as applicable to produce the blended result.

The contents of an alpha-blend combination buffer consist of a DXVA_BlendCombination structure.


MPEG-2 Pan-Scan Operation

If the PictureSourceRect16thPel member of DXVA_BlendCombination is used to select an area specified by MPEG-2 video pan-scan parameters, the PictureSourceRect16thPel parameters can be computed as follows (provided that the values computed do not violate the restrictions above for alpha-blend combination buffers, as could be the case with some MPEG-2 pan-scan parameters and in particular can be the case with some MPEG-2 DVD content):

left = 8 X (horizontal_size - display_horizontal_size) – frame_centre_horizontal_offset

top = 8 X·(vertical_size - display_vertical_size) - frame_centre_vertical_offset

right = left + (16 X display_horizontal_size)

bottom = top + (16 X display_vertical_size)

And the PictureDestinationRect member of DXVA_BlendCombination would normally then be created as:

  • left = 0 or 8 (as in the DVD 704-Wide Non-Pan-Scan Picture Operation section)
  • top = 0
  • right = left + display_horizontal_size
  • bottom = top + display_vertical_size


DVD 4:3 Pan-Scan Within 16:9 Pictures

In DVD's use of MPEG-2 for 4:3 pan-scan within 16:9 pictures, the pan-scan parameters are restricted such that they will not violate the restrictions specified in the DXVA_BlendCombination structure, and also must maintain the following restrictions required by the DVD specification:

  • horizontal_size = 720 or 704
  • vertical_size = 480 or 576
  • display_horizontal_size = 540
  • display_vertical_size = vertical_size
  • frame_centre_vertical_offset = 0
  • frame_centre_horizontal_offset has an absolute value that is less than or equal to 1440 for horizontal_size = 720 and less than or equal to 1312 for horizontal_size = 704

The formulation described in MPEG-2 Pan-Scan Operation can then be applied directly in this case.


DVD 704-Wide Non-Pan-Scan Picture Operation

The use of MPEG-2 on DVD for 704-wide pictures specifies a source rectangle if using MPEG-2 pan-scan operation that exceeds the boundaries of the decoded picture (it specifies a display_horizontal_size of 720 that exceeds the decoded picture's horizontal_size of 704). In this case, the host software decoder is responsible for cropping the source rectangle to keep it from reaching outside the allocated source area and for managing the destination rectangle to adjust for the cropping. There are two basic alternatives, both of which involve specifying a picture source rectangle (in 1/16th sample resolution) with the following values:

  • left = 0
  • right = 16 X (left + horizontal_size) = 11264.

The two alternatives are:

  • A picture destination rectangle set as:
    • left = (display_horizontal_size – horizontal_size) / 2 = 8
    • right = left + horizontal_size = 712

    with the graphic used in a straightforward fashion, or

The picture destination rectangle set as:

  • left = 0
  • right = left + horizontal_size = 704

    with the graphic destination rectangle being displaced to the left by eight samples to compensate for the shifted picture destination.

The second of these two alternatives is presumably the preferred one as it creates only the destination area that will be used for the display.


DVD 352-Wide Picture Operation

DVD can use 352-wide pictures, which can be stretched to a width of 704 by use of a picture-source rectangle (in 1/16th sample resolution) having:

  • left = 0
  • right = 16 X (left + horizontal_size) = 5632

and a picture destination rectangle having two alternative formulations:

  1. The picture destination rectangle can be set as:
    • left = 8
    • right = left + (2 X horizontal_size) = 712

      with the graphic used in a straightforward fashion, or

  2. the picture destination rectangle can be set as:
    • left = 0
    • right = left + (2 X horizontal_size) = 704

      with the graphic destination rectangle being displaced to the left by eight to compensate for the shifted picture destination

The second of these two alternatives is presumably the preferred one as it creates only the destination area that will be used for the display.


DVD 720-Wide Picture Operation

A rather trivial example is the use of MPEG-2 on DVD with 720-wide pictures, in which case the picture source rectangle (in 1/16th sample resolution) would have:

  • left = 0
  • right = left + (16 X horizontal_size) = 11520

and the destination rectangle would normally have:

  • left = 0
  • right = left + horizontal_size = 720


DVD 16:9 Letterbox Height in 4:3 Picture Operation

Another example is DVD's use of 16:9 video for 4:3 displays with letterbox framing. This can be supported by using a picture-source rectangle having:

  • top = 0
  • bottom = top + (16 X vertical_size) = 7680 or 9216 and a picture-destination rectangle having top = vertical_size / 8 = 60 or 72 and bottom = 7 X vertical_size / 8 = 420 or 504.


Picture Resampling Control (bDXVA_Func=4)

The picture resampling function is specified for such purposes as spatial scaleable video coding, reference picture resampling, or resampling for use as an upsampled or display picture.

The resampling is performed as specified for H.263 Annex O Spatial Scalability or for H.263 Annex P with "clipping" at the picture edges, which is the same as in some forms of Spatial Scalability in MPEG-2 and MPEG-4. This uses simple two-tap separable filtering.

Note that picture resampling control does not require a connection configuration. Its operation requires only support of the appropriate restricted mode GUID. As no connection configuration is needed for picture resampling control, no minimal interoperability set must be defined for its operation.

A single buffer type defined in the DXVA_PicResample structure controls the resampling process.


Restricted Modes

Restricted mode profiles indicate the capabilities of an accelerator.

Some restricted-mode profiles are defined as subsets of the capabilities of other restricted-mode profiles (for example, the MPEG2_A profile is a subset of the capabilities of the MPEG2_B profile). In order to enforce a logical structure to the accelerator capability determination, it is a requirement that accelerators that support some particular restricted-mode profile also expose support of all other restricted mode profiles that are subsets of the capabilities of the particular profile in question. For example, the MPEG2_A profile is a subset of the capabilities of the MPEG2_B profile; therefore, accelerators that support the MPEG2_B profile must also support the MPEG2_A profile.

The following restricted-mode profiles are defined in anticipation of combinations of features likely to find widespread support. These profiles establish a set of video coding "tools" necessary for decoding and also determining whether a given video data format can be decoded in some fashion using the API.


Non-Restricted Operation

If DirectX VA is used without strict conformance to the restricted-mode profiles described in this section, the wRestrictedMode member of DXVA_ConnectMode must be set to a specific value to indicate this lack of restriction.

Connection mode and functions for non-restricted operation are as follows:

  • wRestrictedMode equals 0xFFFF.
  • All defined values of the bDXVA_Func variable are allowed.


H261_A Restricted Profile

The H261_A restricted profile contains the set of features required for minimal support of ITU-T Rec. H.261 without acceleration support for H.261 Annex D graphics. Support of this profile is currently encouraged but not required. This set of features is defined by the following restrictions:

  • DXVA_ConnectMode connection and functions:
    • wRestrictedMode equals 1
    • bDXVA_Func equals 1
  • Picture decoding (bDXVA_Func = 1):

    Restrictions on the DXVA_PictureParameters structure:

    • bBPPMinus1 equals 7
    • bSecondField equals zero
    • (bMacroblockWidthMinus1, bMacroblockHeightMinus1) = (15, 15)
    • (bBlockWidthMinus1, bBlockHeightMinus1) = (7, 7)
    • bChromaFormat equals 1 (4:2:0)
    • bPicStructure equals 3 (frame structured)
    • bMVprecisionAndChromaRelation is equal to 2 (H.261 integer-sample motion)
    • bPicExtrapolation equals zero
    • bPicDeblocked equals zero
    • bPic4MVallowed equals zero
    • bPicOBMC equals zero
    • bMV_RPS equals zero
    • bPicScanFixed equals 1

    Restrictions on DXVA_MBctrl_I_HostResidDiff_1, DXVA_MBctrl_I_OffHostIDCT_1, DXVA_MBctrl_P_HostResidDiff_1, and DXVA_MBctrl_P_OffHostIDCT_1:

    • MotionType is equal to a value of 2 (frame motion) if MotionForward equal to 1
    • MBscanMethod is equal to a value of zero (zig-zag) if the bConfigHostInverseScan member of DXVA_ConfigPictureDecode equals zero
    • FieldResidual equals zero (frame residual)
    • MotionBackward equals zero (no backward prediction)

    Restrictions on bitstream buffers:

    • The contents of any bitstream buffers must contain data in the H.261 video format.


H261_B Restricted Profile

The H261_B restricted profile contains the set of features required for support of ITU-T Rec. H.261 without acceleration support for H.261 Annex D graphics but with deblocking filter post-processing support. Support of this profile is currently encouraged but not required. This set of features is defined by the restrictions listed above for the H261_A restricted profile, except for the following:

  • DXVA_ConnectMode connection mode and functions:
    • wRestrictedMode equals 2
  • Picture decoding (bDXVA_Func = 1):

    Restrictions on the DXVA_PictureParameters structure:

    • bPicDeblocked may be either zero or 1.
    • wDeblockedPictureIndex must not be equal to wDecodedPictureIndex when bPicDeblocked is 1.


H263_A Restricted Profile

The H263_A restricted profile contains the set of features required for support of ITU-T Rec. H.263 and a small specific set of enhanced optional capabilities. Support of this profile is currently encouraged but not required. This set of features is defined by the following set of restrictions:

  • DXVA_ConnectMode connection mode and functions:
    • wRestrictedMode equals 3
    • bDXVA_Func equals 1
  • Picture decoding (bDXVA_Func = 1):

    Restrictions on the DXVA_PictureParameters structure:

    • BPP equals 8
    • bSecondField equals zero
    • (MacroblockWidth, MacroblockHeight) = (16, 16)
    • (WT, HT) = (8, 8)
    • bChromaFormat equals 1 (4:2:0)
    • bPicStructure equals 3 (frame structured)
    • bRcontrol equals zero
    • bMVprecisionAndChromaRelation equals one (H.263 half-sample motion)
    • bPicExtrapolation equals zero
    • bPicDeblocked equals zero
    • bPic4MVallowed equals zero
    • bPicOBMC equals zero
    • bMV_RPS equals zero
    • bPicScanFixed equals 1

    Restrictions on DXVA_MBctrl_I_HostResidDiff_1, DXVA_MBctrl_I_OffHostIDCT_1, DXVA_MBctrl_P_HostResidDiff_1, and DXVA_MBctrl_P_OffHostIDCT_1:

    • MotionType equals 2 (frame motion) if MotionForward is equal to one.
    • MBscanMethod equals zero (zig-zag) if bConfigHostInverseScan equals zero
    • FieldResidual equals zero (frame residual)
    • H261LoopFilter equals zero (no H.261 loop filter)
    • MotionBackward equals zero (no backward or bidirectional motion)

    Restrictions on bitstream buffers:

    • The contents of any bitstream buffer must contain data in the H.263 video format in "baseline" mode (no options, no PLUSPTYPE) or with Annex L information (to be ignored).


H263_B Restricted Profile

The H263_B restricted profile contains the set of features required for support of ITU-T Rec. H.263 and a specific set of enhanced optional capabilities. Support of this profile is currently encouraged but not required. This set of features is specified by the restrictions listed above for the H263_A restricted profile, except for the following additional restrictions:

  • DXVA_ConnectMode connection mode and functions:
    • wRestrictedMode = 4
  • Picture decoding (bDXVA_Func = 1):

    Restrictions on the DXVA_PictureParameters structure:

    • bRcontrol may equal either zero or 1
    • bPicExtrapolation may equal either zero or 1
    • Pic4MV may equal either zero or 1
    • Motion4MV may equal either zero or 1
    • bPicScanFixed may equal either zero or 1

    Restrictions on DXVA_MBctrl_I_HostResidDiff_1, DXVA_MBctrl_I_OffHostIDCT_1, DXVA_MBctrl_P_HostResidDiff_1, and DXVA_MBctrl_P_OffHostIDCT_1:

    • MBscanMethod may be a value of zero (zig-zag), a value of 1 (alternate vertical) or a value of 2 (alternate horizontal) if bConfigHostInverseScan is equal to zero.

    Restrictions on bitstream buffers:

    • The contents of any bitstream buffers may also contain data in the H.263 video format with any subset of CPCF, CPFMT and Annexes D, I, N (single forward reference picture per output picture), and T.


H263_C Restricted Profile

The H263_C restricted profile contains the set of features required for support of ITU-T Rec. H.263 and a specific set of enhanced optional capabilities. Support of this profile is currently encouraged but not required. This set of features is specified by the restrictions listed above for the H263_B restricted profile, except for the following additional restrictions:

  • DXVA_ConnectMode connection mode and functions:
    • wRestrictedMode equals 5
  • Picture decoding (bDXVA_Func = 1):

    Restrictions on the DXVA_PictureParameters structure:

    • bPicDeblocked may be 1
    • wDeblockedPictureIndex may or may not be equal to wDecodedPictureIndex when bPicDeblocked is equal to 1

    Restrictions on bitstream buffers:

    • The contents of any bitstream buffers may also contain data in the H.263 video format with any subset of CPCF, CPFMT and Annexes D, I, J, N (single forward-reference picture per output picture), and T.


H263_D Restricted Profile

The H263_D restricted profile contains the set of features required for support of ITU-T Rec. H.263 and a specific set of enhanced optional capabilities. Support of this profile is currently encouraged but not required. This set of features is specified by the restrictions listed above for the H263_C restricted profile, except for the following:

  • DXVA_ConnectMode connection mode and functions:
    • wRestrictedMode equals 6
    • bDXVA_Func may be either 1 (picture decoding) or 4 (picture resampling)
  • Picture decoding (bDXVA_Func = 1):

    Restrictions on the DXVA_PictureParameters structure:

    • bBidirectionalAveragingMode member of DXVA_PictureParameters equals 1 (H.263 bidirectional averaging) or zero (MPEG-2 bidirectional averaging)
    • bMV_RPS member of DXVA_PictureParameters may be either zero or 1

      Restrictions on DXVA_MBctrl_I_HostResidDiff_1, DXVA_MBctrl_I_OffHostIDCT_1, DXVA_MBctrl_P_HostResidDiff_1, and DXVA_MBctrl_P_OffHostIDCT_1:

    • MotionBackward may be either zero or 1

    Restrictions on bitstream buffers:

    • The contents of any bitstream buffers may also contain data in the H.263 video format with any subset of Annexes K, O, P (factor-of-two resizing with clipping only in one or both dimensions), S, and U.
  • Picture resampling (bDXVA_Func = 4):
    • PicResampleSourceWidth and PicResampleDestWidth must be equal or related by a multiplicative factor of 2 (or 1/2).
    • PicResampleSourceHeight and PicResampleDestHeight must be equal or related by a multiplicative factor of 2 (or 1/2).
    • If PicResampleSourceHeight and PicResampleDestHeight are equal, PicResampleSourceWidth and PicResampleDestWidth must be related by a multiplicative factor of 2 (or 1/2). If PicResampleSourceHeight and PicResampleDestHeight indicate an upsampling operation, PicResampleSourceWidth and PicResampleDestWidth must not indicate a downsampling operation, and vice versa.

    Note Although H.263 requires only support of the bBidirectionalAveragingMode member of DXVA_PictureParameters equal to 1 when MotionForward is 1 and MotionBackward is 1, the H263_D restricted profile also allows bBidirectionalAveragingMode to be zero. This is intended to allow the H263_D restricted profile to support MPEG-4 video as well as H.263 video—and MPEG-4 uses the MPEG-1/MPEG-2 style of bidirectional averaging.


H263_E Restricted Profile

The H263_D restricted profile contains the set of features required for support of ITU-T Rec. H.263 and a specific set of enhanced optional capabilities. Support of this profile is currently encouraged but not required. This set of features is specified by the restrictions listed above for the H263_D restricted profile, except:

  • DXVA_ConnectMode connection mode and functions:
    • wRestrictedMode equals 7
  • Picture decoding (bDXVA_Func = 1):

    Restrictions on the DXVA_PictureParameters structure:

    • bPicOBMC may be either zero or 1

    Restrictions on DXVA_MBctrl_I_HostResidDiff_1, DXVA_MBctrl_I_OffHostIDCT_1, DXVA_MBctrl_P_HostResidDiff_1, and DXVA_MBctrl_P_OffHostIDCT_1:

    • if bPicOBMC is 1 and Motion4MV is 1, MotionBackward must be zero.

    Restrictions on bitstream buffers:

    • The contents of any bitstream buffer may also contain data in the H.263 video format with Annex F.


H263_F Restricted Profile

The H263_E restricted profile contains the set of features required for support of ITU-T Rec. H.263 and a specific set of enhanced optional capabilities. Support of this profile is currently encouraged but not required. This set of features is specified by the restrictions listed above for the H263_E restricted profile, except for the following additional restrictions:

  • DXVA_ConnectMode connection mode and functions:
    • wRestrictedMode equals 8
  • Picture decoding restrictions (bDXVA_Func = 1):

    Restrictions on the DXVA_PictureParameters structure:

    • bPicBinPB may be either zero or 1

    Restrictions on bitstream buffers:

    • The contents of any bitstream buffer may also contain data in the H.263 video format with any subset of Annexes G, M, V and W.


MPEG1_A Restricted Profile

The MPEG1_A restricted profile contains a set of features required for support of MPEG-1 video. Support of this profile is required for windows video accelerator drivers that provide hardware video acceleration capabilities. This set of features is defined by the following set of restrictions:

  • DXVA_ConnectMode connection mode and functions:
    • wRestrictedMode equals 9
    • bDXVA_Func equals 1
  • Picture decoding (bDXVA_Func = 1):

    Restrictions on the DXVA_PictureParameters structure:

    • BPP equals 8
    • bSecondField equals zero
    • (MacroblockWidth, MacroblockHeight) = (16, 16)
    • (WT, HT) = (8, 8)
    • bChromaFormat equals 1 (4:2:0)
    • bPicStructure equals 3 (frame structured)
    • bRcontrol equals zero
    • bBidirectionalAveragingMode equals zero (MPEG-2 bidirectional averaging)
    • bMVprecisionAndChromaRelation equals zero (MPEG-2 half-sample motion)
    • bPicExtrapolation equals zero
    • bPicDeblocked equals zero
    • bPic4MVallowed equals zero
    • bPicOBMC equals zero
    • bMV_RPS member of DXVA_PictureParameters equals zero
    • SpecificIDCT equals zero
    • bPicScanFixed equals one

    Restrictions on DXVA_MBctrl_I_HostResidDiff_1, DXVA_MBctrl_I_OffHostIDCT_1, DXVA_MBctrl_P_HostResidDiff_1, and DXVA_MBctrl_P_OffHost IDCT_1:

    • MotionType equals 2 (frame motion)
    • MBscanMethod equals zero (zig-zag) if bConfigHostInverseScan equals zero
    • FieldResidual equals zero (frame residual)
    • H261LoopFilter equals zero (no H.261 loop filter)

    Restrictions on bitstream buffers:

    • The contents of any bitstream buffer must contain data in the MPEG-1 main profile video format.


MPEG2_A Restricted Profile

The MPEG2_A restricted profile contains a set of features required for support of MPEG-2 video Main Profile. Support of this profile is required for windows video accelerator drivers that provide hardware video acceleration capabilities. This set of features is defined by the following set of restrictions:

  • DXVA_ConnectMode connection mode and functions:
    • wRestrictedMode = 0x0A
    • bDXVA_Func equals 1
  • Picture decoding (bDXVA_Func = 1):

    Restrictions on the DXVA_PictureParameters structure:

    • wRestrictedMode = 0x0A
    • BPP equals 8
    • (MacroblockWidth, MacroblockHeight) = (16, 16)
    • (WT, HT) = (8, 8)
    • bChromaFormat is equal to 1 (4:2:0)
    • bRcontrol equals zero
    • bBidirectionalAveragingMode equals zero (MPEG-2 bidirectional averaging)
    • bMVprecisionAndChromaRelation equals zero (MPEG-2 half-sample motion)
    • bPicExtrapolation equals zero
    • bPicDeblocked equals zero
    • bPic4MVallowed equals zero
    • bPicOBMC equals zero
    • bMV_RPS member of DXVA_PictureParameters equals zero
    • SpecificIDCT equals zero
    • bPicScanFixed equals one

      Restrictions on DXVA_MBctrl_I_HostResidDiff_1, DXVA_MBctrl_I_OffHostIDCT_1, DXVA_MBctrl_P_HostResidDiff_1, and DXVA_MBctrl_P_OffHostIDCT_1:

    • MBscanMethod may be a value of zero (zig-zag) or a value of 1 (alternate vertical) if bConfigHostInverseScan is equal to zero
    • H261LoopFilter equals zero

    Restrictions on bitstream buffers:

    • The contents of any bitstream buffer must contain data in the MPEG-2 main profile video format.
    • bNewQmatrix[i] equals zero, for i = 2 and 3


MPEG2_B Restricted Profile

The MPEG2_B restricted profile contains a set of features required for support of MPEG-2 video Main Profile and an associated DVD subpicture using front-end buffer-to-buffer sub-picture blending. Support of this profile is currently encouraged but not required. This set of features is defined by the restrictions listed for the MPEG2_A restricted profile, except for the following additional restrictions:

  • DXVA_ConnectMode connection mode and functions:
  • wRestrictedMode = 0x0B
  • bDXVA_Func = 1 (picture decoding), or 2 (alpha blend data loading) or 3 (alpha blend combination) (all of these values must be supported)
  • bConfigBlendType = 0 (front-end buffer-to-buffer blending)
  • bConfigDataType = 0, 1, or 3 (at the accelerator's discretion)
  • Alpha-blending source and destination surfaces are supported with width and height of at least 720 and 576, respectively.

Because the MPEG2_A restricted profile is defined by a relaxation of the accelerator requirements of the MPEG2_B profile, all accelerators that support the MPEG2_B profile must support the MPEG2_A profile.


MPEG2_C Restricted Profile

The MPEG2_C restricted profile contains a set of features required for support of MPEG-2 video Main Profile. Support of this profile is required for Windows video accelerator drivers that provide hardware video acceleration capabilities. This set of features is defined by the restrictions listed previously for the MPEG2_A restricted profile, except for the following additional connection mode and function restrictions:

  • wRestrictedMode is equal to 0x0C.
  • One additional member having bConfigResidDiffHost equal to zero and bConfigResidDiffAccelerator equal to 1 is added to the minimal interoperability set as described in Minimal Interoperability Configuration Set (bDXVA_Func=1).

Because the MPEG2_C restricted profile is defined by a relaxation of the accelerator requirements of the MPEG2_A profile (by allowing an accelerator to not support any of the members of the minimal interoperability set for MPEG2_A), all accelerators that support the MPEG2_A profile must support the MPEG2_C profile. Similarly, all accelerators that support the MPEG2_D profile must support the MPEG2_C profile.


MPEG2_D Restricted Profile

The MPEG2_D restricted profile contains a set of features required for support of MPEG-2 video Main Profile and an associated DVD subpicture using back-end hardware sub-picture blending. This set of features is defined by the restrictions listed previously for the MPEG2_B restricted profile, except for the following additional DXVA_ConnectMode connection mode and function restrictions:

  • wRestrictedMode = 0x0D
  • one additional member having bConfigResidDiffHost equal to zero and bConfigResidDiffAccelerator equal to 1 is added to the minimal interoperability set as described in Minimal Interoperability Configuration Set (bDXVA_Func=1).
  • bConfigBlendType may be either zero or 1 (at the accelerator's discretion)
  • bConfigDataType may support any value (at the accelerator's discretion)

Since the MPEG2_D restricted profile is defined by a relaxation of the accelerator requirements of the MPEG2_B profile (by allowing an accelerator to not support any of the members of the minimal interoperability set for MPEG2_B), all drivers that support the MPEG2_B profile must support the MPEG2_D profile.


Direct3D DDI

The Microsoft® Direct3D® device driver interface (DDI) is a graphics interface that allows vendors to provide hardware acceleration for Direct3D. The interface is flexible, allowing vendors to provide Direct3D acceleration according to hardware capabilities. Driver writers implement the Direct3D DDI as an integral part of the display driver.

This section describes the Direct3D architecture and interface, and provides implementation guidelines for Direct3D driver writers. It is assumed that the reader is familiar with the Direct3D and Microsoft DirectDraw® APIs, and that the reader has a firm grasp of the Windows® 2000 display driver model, including the DirectDraw DDI.

All Direct3D drivers for Windows 2000 and later must conform to the Microsoft DirectX® 7.0 or later Direct3D driver model. The DirectX 8.0 driver model will be supported in the released version of Microsoft® Windows® XP.


Direct3D DDI Header Files, Sample Code, and References

Microsoft® Windows® 2000 and later driver writers should reference the following header files when developing a Microsoft Direct3D® driver:

d3dnthal.h
Contains prototypes for callbacks that are implemented by the driver and definitions for driver-level structures. The D3DHAL_DP2OPERATION enumerated type is defined in this file. This header is included in winddi.h, which must be included in all Windows 2000 and later display drivers.
d3dtypes.h
Contains Direct3D type definitions used by both applications and drivers. Except for D3DHAL_DP2OPERATION, all other Direct3D enumerated types are defined in this header.
d3dcaps.h
Contains structures and definitions that describe capabilities of various aspects of Direct3D drivers.
dx95type.h
Allows driver developers to write driver code that is portable between Windows 2000 and later and Windows 98/Me.
ddrawint.h
This header file is required to develop the Microsoft DirectDraw® portion of a display driver. This header is included in winddi.h.

All of these header files are shipped with the Windows DDK. The Windows DDK also provides sample code for a Direct3D driver in the perm3 video display directory.

Reference pages for Direct3D DDI functions, structures, and enumerations can be found in Direct3D Driver Functions, Direct3D Driver Structures, and Direct3D Driver Enumerations.

The primary reference for SDK-related aspects of the Direct3D interface is the Platform SDK documentation.

Less-experienced graphics programmers might find Computer Graphics: Principles and Practice by Foley, van Dam, Feiner, and Hughes published by Addison-Wesley 1990, to be a useful general graphics reference.


Cross Platform Direct3D Driver Development

The Microsoft® Windows® 2000 and later and Windows 98/Me Direct3D® DDI types are not directly compatible when compiling, due to naming differences and some type changes of members. Logically however, all members serve the same purpose.

A utility file, dx95type.h, is provided with the Windows DDK to assist with writing code intended to be portable between Windows 2000 and later and Windows 98/Me. It contains a set of type definitions and macros that map some naming differences that occur between the Windows 98/Me and Windows 2000 and later platforms, enabling some common driver code to be used between them.


Direct3D Implementation Requirements

The purpose of this section and the following subsections is to provide detailed descriptions of the requirements for hardware certification with respect to exposed features. This section does not specifically require features; rather it defines how features that are exposed (via the capabilities) must be implemented in order to conform to the standard (or, reference) implementation. This section includes, but is not limited to, detailed descriptions of features that are present in the PC2001 Design Guide. As always, the reference rasterizer is the final authority on what is and is not a compliant image. Ultimately, a compliant feature is one that behaves as the reference rasterizer does.

For each of the following features, if it is implemented, it must conform to the reference as described below. Compliance is generally assured by comparing a scene rasterized by the hardware to an identical scene rasterized by the reference rasterizer. Some features also list additional requirements beyond simple reference comparisons.

Render Target Requirements

Point, Line, and Triangle Filling Requirements

Shading Requirements

Texturing Requirements


Render Target Requirements

This section lists requirements for color buffers and depth buffers.

Color Buffers

If the hardware is unable to support a render target that is also to be used as a texture (that is, the device cannot "render to a texture"), the device must fail calls to the IDirect3DDevice7::SetRenderTarget and IDirect3D7::CreateDevice methods on such surfaces. These methods are described in the Direct3D SDK documentation. The fact that a render target is to be used as a texture is signified by the presence of the DDSCAPS_TEXTURE flag in the surface description (see the dwCaps member of the DDSCAPS structure).

Depth Buffers

If the hardware is unable to support a particular combination of render target and depth-buffers, then the device must fail any API calls that would cause this invalid scenario to occur, and where this mismatch can be detected, such as in calls to the IDirect3D7::CreateDevice and IDirectDrawSurface7::AddAttachedSurface methods. These methods are described in the Direct3D and DirectDraw SDK documentation sets, respectively. An example of such a mismatch might be when the render target and depth buffer are of different bit depths. It is not acceptable to transparently alter the format of either the render target or the depth-buffer to cause an invalid combination to work properly.

It is acceptable to silently increase the precision of the depth buffer.


Point, Line, and Triangle Filling Requirements

This section lists requirements for filling points, lines, and triangles.

Points

The point fill and rasterization rules are identical to the triangle fill rules. All flags and capabilities that apply to triangles also apply to points, and vice-versa. The reference implementation expands a point into a rectangle and applies the triangle fill rules to the result.

Given a point with coordinates P0(x,y), generate four new points P1, P2, P3, and P4 as follows:

P1(x,y) = (x – 0.5, y – 0.5)
P2(x,y) = (x – 0.5, y + 0.5)
P3(x,y) = (x + 0.5, y + 0.5)
P4(x,y) = (x + 0.5, y – 0.5)

The rectangle is then generated as two triangles, such as (P1, P2, P3) and (P1, P3, P4). You may also examine the reference rasterizer implementation in the source files setup.cpp and scancnv.cpp.

Lines

Line fill rules are documented in the DirectX DDK in the reference rasterizer source files setup.cpp and scancnv.cpp.

Triangles

Triangle fill rules are documented in the DirectX DDK in the reference rasterizer source files setup.cpp and scancnv.cpp.

Hardware should supply the culling caps and properly implement the three culling modes. The following code fragment determines whether to cull the current triangle:

if (CurrentCullMode != D3DCULL_NONE) {
    int ccw = (((v[0]->sx - v[2]->sx) *
                (v[1]->sy - v[2]->sy)) <
               ((v[1]->sx - v[2]->sx) *
                (v[0]->sy - v[2]->sy)));
if ((CurrentCullMode == D3DCULL_CW && (ccw == 0)) ||
        (CurrentCullMode == D3DCULL_CCW && (ccw != 0))) {
        // Current triangle is culled, move onto
        // next triangle.
    }
}
// Current triangle is not culled, render it

The preceding code sample tests to determine which way the triangle is facing. The triangle is defined 0,1,2 and tested for being counter-clockwise in screen space. If it is not, and there is clockwise culling, then that triangle is not drawn because the vertices go in clockwise order.


Shading Requirements

This section lists requirements for flat shading, Gouraud shading, specular highlighting, alpha blending, dithering, and color-key.

Flat Shading

The D3DPSHADECAPS_COLORFLATRGB bit in the dwShadeCap member of the D3DPRIMCAPS structure must be set for the appropriate primitive type (line or triangle) in order to indicate that flat shading is supported for that primitive type.

For all primitive types except triangle fans, the color, specular (if supported) and alpha data come from the first vertex of each primitive. For triangle fans, the second vertex is used. These colors remain constant across the entire triangle (that is, they are not interpolated).

Gouraud Shading

The dwShadeCaps member of the D3DPRIMCAPS structure must have the D3DPSHADECAPS_COLORGOURAUDRGB bit set for the appropriate primitive type (line or triangle) to indicate that Gouraud interpolation of colors is supported. The color and specular components are both linearly interpolated between vertices.

For all primitives, the color data must use linear interpolation between the vertices of the primitive, and must conform to an image generated by the reference rasterizer. Furthermore, all color and alpha components must be interpolated in the same fashion if they are present. For example, it is not valid to use Gouraud interpolation of the RGB components of a color while using flat shading for the alpha component. An exception is the special case of the fog component transmitted via the alpha component of the specular color, which should never be flat shaded.

Perspective correction of iterated color components is encouraged. Note that the reference rasterizer in DirectX 7.0 already does perspective correction of color components. This is taken into account in current testing procedures.

Specular Highlighting

If specular highlighting support is to be exposed, then one or both of the following flags must be set in the dwShadeCaps member of the D3DPRIMCAPS structure for the appropriate primitive type (line or triangle):

  • D3DPSHADECAPS_SPECULARFLATRGB must be set if flat shading is supported.
  • D3DPSHADECAPS_SPECULARGOURAUDRGB must be set if Gouraud shading is supported.

If specular highlighting is supported, then it must be possible to enable or disable it by setting the appropriate value of the D3DRENDERSTATE_SPECULARENABLE render state.

Specular highlighting must be full color, and must be capable of producing the full range of colors available for the render target, per the reference rasterizer. Monochromatic specular highlighting is not sufficient to meet this requirement.

The D3DPSHADECAPS_SPECULARFLATMONO and D3DPSHADECAPS_SPECULARGOURAUDMONO flags are not to be used to indicate monochromatic specular highlighting. They indicate only that specular highlighting is supported in RAMP mode. There is no cap that can indicate that an adapter supports only monochromatic specular highlights in RGB mode. If your adapter supports only monochromatic specular highlights in RGB mode, you should not set the SPECULARFLATRGB or SPECULARGOURAUDRGB caps. With the mono modes, the hardware should just interpolate the blue channel of the specular components as a white intensity. This is controlled by the D3DRENDERSTATE_MONOENABLE render state.

To properly implement specular highlights, a second set of interpolants is required. However, hardware parts that support z-buffering and blending can often emulate specular highlights by doing a second blending pass over the triangle with the z comparison function set to D3DCMP_EQUAL (see the D3DCMPFUNC enumerated type in the DirectX SDK documentation). This second pass would do a blend to add the interpolated specular component to the pixel written during the first pass; values that exceed the maximum should saturate to white.

Alpha Blending

To expose support for alpha blending, the following flags must be set in the dwShadeCaps member of the D3DPRIMCAPS structure for the appropriate primitive type (line or triangle):

  • D3DPSHADECAPS_ALPHAFLATBLEND must be set if flat shading is supported with alpha.
  • D3DPSHADECAPS_ALPHAGOURAUDBLEND must be set if Gouraud shading is supported with alpha.

If alpha blending is supported, it must be possible to enable or disable it by setting the appropriate value of the D3DRENDERSTATE_ALPHABLENDENABLE render state.

Alpha blending, or true transparency (from the 3D space), is the process of modulating incoming color by the value of the data that is already located in the frame buffer. This render state has modes that can be set by the D3DRENDERSTATE_SRCBLEND and D3DRENDERSTATE_DESTBLEND render states.

When the alpha value for a blending operation is not available, it must be assumed to be 1.0 (opaque). An example of when this is possible is blending with textures that have no alpha channel.

If the target to which the resultant pixel is written contains an alpha channel, the alpha value resulting from any alpha blending operation must be written to that channel, allowing proper accumulation of transparency.

Dithering

If dithering is supported on a particular primitive type (line or triangle), the dwRasterCaps member of the D3DPRIMCAPS structure must have the D3DPRASTERCAPS_DITHER flag set. The feature must be controllable by means of the D3DRENDERSTATE_DITHERENABLE render state.

If dithering is supported, it may not default to always off or always on.

Color-key

Color-key is related to texture transparency and the D3DPTEXTURECAPS_TRANSPARENCY cap (see the dwTextureCaps member of the D3DPRIMCAPS structure).

Color-key transparency (used to create 2D sprites) replaces some colors of an object with the colors that are beneath them in the frame buffer. The driver should make it possible for an application to enable color-key for an entire scene, but only use the color-key on certain surfaces with the attached color-key values (instead of turning the color-key on and off for each surface).

Color-key is enabled with the AND of the render state enable and the DDRAWISURF_HASCKEYSRCBLT bit in the surface. (See the dwFlags member of the DD_SURFACE_LOCAL structure for more information.) Applications create a texture surface that uses DDSD_CKSRCBLT and then call the IDirect3DDevice7::SetRenderState method (described in the Direct3D SDK documentation) with D3DRENDERSTATE_COLORKEYENABLE and TRUE. Both of these must be true for color-key to occur, and applications must be permitted to leave the render state TRUE all the time and still selectively use color-key for a subset of a frame's textures (that is, those that have the DDRAWISURF_HASCKEYSRCBLT bit set). It is up to the driver to correctly handle this behavior.


Texturing Requirements

This section lists requirements for texture sizes and texture filtering. There are also texture-related requirements for the IDirect3DDevice7::ValidateDevice method.

Texture Sizes

The following are requirements for texture sizes.

  1. The driver must expose its minimum and maximum texture dimensions through the dwMinTextureWidth, dwMinTextureHeight, dwMaxTextureWidth, and dwMaxTextureHeight members of the D3DDEVICEDESC7 structure. This structure is defined in the Direct3D SDK documentation.
  2. If the hardware has an aspect ratio restriction on its textures, that ratio must be present in the dwMaxTextureAspectRatio member of the D3DDEVICEDESC7 structure.
  3. If the device supports only texture dimensions that are powers of two, then it must set the dwTextureCaps member of the D3DPRIMCAPS structure to contain the D3DPTEXTURECAPS_POW2 flag for the appropriate primitive type (line or triangle).
  4. If the device can support textures of an arbitrary size when the texture addressing mode for the texture stage is set to D3DTADDRESS_CLAMP, and the texture wrapping for the texture stage is disabled (D3DRENDERSTATE_WRAPn set to 0), and MIP mapping is not in use, then it must set the D3DPTEXTURECAPS_NONPOW2CONDITIONAL flag.
  5. If the device only supports textures whose dimensions are equal, then it must set the dwTextureCaps member of the D3DPRIMCAPS structure to contain the D3DPTEXTURECAPS_SQUAREONLY flag for the appropriate primitive type (line or triangle).

If the device supports textures of an arbitrary size without restrictions other than those described in the first and second requirement, then it must not set any of the flags described in third, fourth, and fifth requirements.

Texture Filtering

Texture magnification and minification filters must be enabled and disabled through the D3DTSS_MAGFILTER and D3DTSS_MINFILTER texture stage states. (See the D3DTEXTURESTAGESTATETYPE enumerated type in the Direct3D SDK documentation for more information about the D3DTSS_Xxx texture stage states.) This filtering must not be performed automatically when these states are disabled.

Texture MIP mapping must be enabled and disabled through the D3DTSS_MIPFILTER texture stage state. If this state is disabled, but the texture was created as a MIP map, the device must use only the top level of the MIP map. MIP mapped filtering must not be performed when this state is disabled.

If the device supports anisotropic filtering, the maximum anisotropy level must be exported through the value of the dwMaxAnisotropy member of the D3DDEVICEDESC7 structure (defined in the Direct3D SDK documentation) value. Furthermore, the device must accept any setting from 1 through dwMaxAnisotropy in the D3DTSS_MAXANISOTROPY texture stage state.

The device must be able to apply all supported filter modes to textures of any supported format. For example, if MIP mapping is supported with other texture formats, MIP map filtering of YUV textures should be able to be performed.

IDirect3DDevice7::ValidateDevice

If a device supports a particular combination of texture stage state blending operations and operands in a single pass, then the device must return DD_OK from a call to the IDirect3DDevice7::ValidateDevice method (described in the Direct3D SDK documentation) for each such combination.

If a device does not support a particular combination of texture stage state blending operations in a single pass, or does not support one or more of the blending operations or operands, then it must return one of the error codes allowable for the IDirect3DDevice7::ValidateDevice method. Invalid blending operations cannot silently fail the IDirect3DDevice7::ValidateDevice method.


Direct3D Driver Callbacks and Functions

The following subsections list the callbacks that comprise the Windows® 2000 and later Direct3D® DDI. Some callbacks are required, while others are optional and their inclusion in a Direct3D driver depends on the hardware capabilities.

The Direct3D DDI callbacks are prototyped as follows:

typedef DWORD (APIENTRY *LPD3DHAL_MYFUNCTIONCB) (LPD3DHAL_MYFUNCTIONDATA);

where:

  • LPD3DHAL_MYFUNCTIONCB points to a driver-implemented callback that can be called MyFunction. All callback names are pseudo-names decided upon by the display driver writer.
  • LPD3DHAL_MYFUNCTIONDATA is a pointer to a D3DHAL_MYFUNCTIONDATA structure being passed to the callback. Callback parameter structures are characterized as follows:
    • The first member of every structure, dwhContext, is the context handle that describes the 3D context in which the callback should operate. The only exception to this rule is the D3DHAL_CONTEXTCREATEDATA structure.
    • The last member of every structure is ddrval. This member is used to pass the callback's return value back to Direct3D so it can be returned to the calling application.

See Direct3D Driver Initialization to determine how to initialize Direct3D callbacks.


Required Direct3D Driver Callbacks and Functions

The following table lists the Direct3D callback functions that must be implemented in a Direct3D driver.

Required Callback | Description
D3dContextCreate | Creates a context.
D3dContextDestroy | Destroys a context.
D3dCreateSurfaceEx | Creates an association between a texture handle and a surface.
D3dDestroyDDLocal | Destroys all the Direct3D surfaces previously created by D3dCreateSurfaceEx that belong to the same given local DirectDraw object.
D3dDrawPrimitives2 | Renders primitives and returns updated state to Direct3D.
D3dGetDriverState | Returns state information about the driver to DirectDraw and Direct3D run-times.
D3dValidateTextureStageState | Performs texture stage state validation which is required for all drivers that support texturing.

In order to support Direct3D, a driver must minimally support Microsoft DirectDraw® and must also implement certain DirectDraw DDI functions and callbacks. Those pertinent to Direct3D support are listed in the following table:

DDI Function | Description
DrvGetDirectDrawInfo | This function retrieves the capabilities of the graphics hardware. In this initialization function the driver indicates that it supports Direct3D.
DdGetDriverInfo | The run-time queries this callback with GUIDs for additional information about the driver. Several GUIDs pertain specifically to the driver's Direct3D support.

DirectDraw function and callback implementation details are discussed in DirectDraw DDI.


Operation Code Handling

In order to support the Microsoft® DirectX® 7.0 Direct3D driver model, driver writers need to make their drivers respond to a number of new operation codes in their implementation of D3dDrawPrimitives2. Some of these operation codes replace callbacks that were formerly required or conditionally required, and others provide new functionality. The most important new operation codes are summarized in the following table, beginning with those that replace callbacks:

Operation Code | Condition/Description
D3DDP2OP_SETRENDERTARGET | Always required. Maps a new rendering target surface and depth buffer in the current context. Replaces D3dSetRenderTarget.
D3DDP2OP_CLEAR | Always required. Used to clear the context's render target, Z-buffer. Replaces D3dClear2. Also used to clear hardware stencil buffers, and depth buffers that cannot be cleared properly by a depth fill bit-block transfer.
D3DDP2OP_SETPALETTE | Used to map an association between a palette handle and a surface handle, and specify the characteristics of the palette. Only needed for drivers that support paletted textures; otherwise this should be a NOP.
D3DDP2OP_UPDATEPALETTE | Used to make alterations to a texture palette, for drivers that support paletted textures. Otherwise, this should be a NOP.
D3DDP2OP_TEXBLT | Specifies a blt operation from a source texture to a destination texture.

Other useful operation codes are summarized in the D3DHAL_DP2OPERATION description in the reference section.


Return Codes for Direct3D Driver Callbacks

The return value for all driver callbacks must always be one of the following values.

Value | Meaning
D3DHAL_CONTEXT_BAD | The context that was passed in was not valid.
DDHAL_DRIVER_HANDLED | The driver has performed the operation and returned a valid return code for that operation in the ddrval member of the structure passed to the driver's callback. If this code is DD_OK, Direct3D proceeds with the function. Otherwise, Direct3D returns the error code provided by the driver and aborts the function.
DDHAL_DRIVER_NOTHANDLED | The driver has no comment on the requested operation. If the driver is required to have implemented a particular callback, Direct3D reports an error condition. Otherwise, Direct3D handles the operation as if the driver callback had not been defined by executing the Direct3D device-independent implementation. Direct3D typically ignores any value returned in the ddrval member of that callback's parameter structure.
D3DHAL_OUTOFCONTEXTS | There are no more contexts are left in this process.


Direct3D Driver Initialization

When the driver's DrvGetDirectDrawInfo function is called by the Microsoft® DirectDraw® run-time to initialize DirectDraw support, the driver must do the following to indicate its Microsoft® Direct3D® capabilities:

  • Set the DDCAPS_3D flag in the ddCaps.dwCaps member of the DD_HALINFO structure to indicate that the driver's hardware has 3D acceleration.
  • Set any of the following DDSCAPS_Xxx flags in the ddCaps.ddsCaps member of the DD_HALINFO structure that describe the 3D capabilities of a driver's video memory surface:
Flag | Meaning
DDSCAPS_3DDEVICE | Indicates that a driver's surface can be used as a destination for 3D rendering.
DDSCAPS_TEXTURE | Indicates that a driver's surface can be used for 3D texture mapping.
DDSCAPS_ZBUFFER | Indicates that a driver's surface can be used as a Z-buffer.

  • Set the GetDriverInfo member of the DD_HALINFO structure to point to the driver's DdGetDriverInfo callback. The driver must also set the DDHALINFO_GETDRIVERINFOSET flag in the dwFlags member of the DD_HALINFO structure to indicate that it has implemented the DdGetDriverInfo callback.
  • Allocate and initialize the members of the D3DHAL_CALLBACKS structure and return this structure in the lpD3DHALCallbacks member of the DD_HALINFO structure.
  • Allocate and initialize the members of the D3DHAL_GLOBALDRIVERDATA structure and return this structure in the lpD3DGlobalDriverData member of the DD_HALINFO structure.

To indicate that the driver is capable of working with Microsoft DirectX® 7.0 it should do the following:

  • Include the D3DDEVCAPS_DRAWPRIMITIVES2EX flag in the devCaps member of the D3DDEVICEDESC_V1 structure that is reported during Microsoft Direct3D® driver initialization.
  • Respond to the GUID_Miscellaneous2Callbacks GUID in DdGetDriverInfo callback by setting the GetDriverState, CreateSurfaceEx, and DestroyDDLocal members of the DD_MISCELLANEOUS2CALLBACKS structure. These are set to point to the appropriate callbacks for the Direct3D driver and OR'd in the dwFlags member with the DDHAL_MISC2CB32_CREATESURFACEEX, DDHAL_MISC2CB32_GETDRIVERSTATE and DDHAL_MISC2CB32_DESTROYDDLOCAL bits, respectively.

After DrvGetDirectDrawInfo returns, GDI calls the driver's DdGetDriverInfo callback several times for different GUIDs to complete the driver's initialization. The DdGetDriverInfo callback must respond to the following GUIDs to support Direct3D:

GUID_D3DCallbacks3
The driver should allocate and initialize the members of the D3DHAL_CALLBACKS3 structure and return this structure in the lpvData member of the DD_GETDRIVERINFODATA structure.
GUID_Miscellaneous2Callbacks
The driver should allocate and initialize the members of the DD_MISCELLANEOUS2CALLBACKS structure and return this structure in the lpvData member of the DD_GETDRIVERINFODATA structure.
GUID_D3DExtendedCaps
The driver should allocate and initialize the appropriate members of the D3DHAL_D3DEXTENDEDCAPS structure and return this structure in the lpvData member of the DD_GETDRIVERINFODATA structure.
GUID_ZPixelFormats
The driver should allocate and initialize the appropriate members of a DDPIXELFORMAT structure for every Z-buffer format that the driver supports and return these structure(s) in the lpvData member of the DD_GETDRIVERINFODATA structure. The driver must respond to this GUID if it supports the D3DDP2OP_CLEAR operation code in its implementation of D3dDrawPrimitives2.
GUID_D3DParseUnknownCommandCallback
The driver should store the pointer to the Direct3D run-time's D3DParseUnknownCommand callback. The pointer is passed to the driver in the lpvData member of the DD_GETDRIVERINFODATA structure. The driver's D3dDrawPrimitives2 callback calls the D3DParseUnknownCommand callback to parse commands that the driver does not recognize.

See DirectDraw Driver Initialization for details on initializing a DirectDraw driver.


Direct3D Context Management

A context encapsulates all the state information for an application-created Microsoft® Direct3D® hardware abstraction layer (HAL) device; that is, a context describes how the driver should draw. State includes information such as the surface being rendered to, the depth surface, shading information, and texture information.

A Direct3D driver is responsible for creating and managing its own rendering contexts.


Creating a Context

A driver must create and initialize a device-specific context that encapsulates all of the state information it requires to perform rendering. State is not shared between contexts; so the driver must maintain full state information for each context that it creates.

To create a context, the driver should do the following:

  • Allocate the device-specific context and zero-initialize it.
  • See D3DContextCreate for additional steps to be done within that callback. The D3dContextCreate callback is invoked when an application creates a Direct3D HAL device. The driver must implement this callback.

The driver must be able to reference all texture handles created by D3dCreateSurfaceEx within a created context. This enables the driver to clean up all driver-specific data related to textures created within this context when a call to D3dContextDestroy is made.


Deleting a Context

Direct3D calls the D3dContextDestroy callback when an application requests that a Direct3D HAL device be destroyed. The driver should free all resources it allocated to the specified context.


Maintaining State Within a Context

A driver updates its internal state associated with a context when its D3dDrawPrimitives2 callback is called. This callback must also return the updated context's public state to Direct3D. See D3dDrawPrimitives2 for more information about processing and updating state.


Overview of Direct3D Surface Handles

The Microsoft® DirectX® 7.0 device driver interface (DDI) is designed to promote a model whereby the Direct3D run-time components parse as little of the command stream as possible before handing the commands to the driver. Additionally, the command stream should be formatted so that it can be directly consumed by future hardware.

One important change directed towards these goals is the movement of all surface-related data out of intermediate structures owned by the Direct3D/DirectDraw® run-time into structures owned, updated, and formatted by the driver.

Surfaces are referred to by handles embedded in the command stream. In these high-frequency operations, the driver can look up its own representation of a surface from the handle, without resorting to locking a surface via helper functions such as EngLockDirectDrawSurface.

The mechanism for assigning these handles is a new driver entry point called D3dCreateSurfaceEx. This entry point is called directly after calls to the existing DdCanCreateSurface and DdCreateSurface entry points, and after a video memory address and handle have been assigned to a surface. At D3dCreateSurfaceEx time, the driver can copy all pertinent information out of the DirectDraw run-time's copy of the surface structure and into its own surface structure. Surface data such as size, format, and fpVidMem (a member of the DD_SURFACE_GLOBAL structure) are obvious candidates for which driver-side copies would be required.

Handles are guaranteed by the run-time to be unique per device and per process. Handles are not guaranteed to be unique per context, and this has some implications for drivers that are discussed in greater detail in Creating Driver-Side Surface Structures.

There is no corresponding DestroySurfaceEx call, so driver-side surface structures are destroyed at DdDestroySurface time.


Creating Driver-Side Surface Structures

The DirectDraw run-time calls the driver's D3dCreateSurfaceEx entry point after it has called the DdCreateSurface entry point and allocated memory for the surface. The run-time calls D3dCreateSurfaceEx only for those surfaces tagged with DDSCAPS_TEXTURE, DDSCAPS_EXECUTEBUFFER, DDSCAPS_3DDEVICE, or DDSCAPS_ZBUFFER flags.

Before calling D3dCreateSurfaceEx, the run-time assigns an integer value as a handle to the surface. This value is stored in the dwSurfaceHandle member of the DDRAWI_DDSURFACE_MORE structure (as pointed to by the lpSurfMore member of the DDRAWI_DDSURFACE_LCL structure). See DD_SURFACE_MORE and DD_SURFACE_LOCAL, which are aliases for the DDRAWI_DDSURFACE_MORE and DDRAWI_DDSURFACE_LCL structures.

These integer values start at one and are kept as small as possible. (Zero is a guaranteed invalid value for a surface handle.) The intention is that a driver can keep an array of pointers into its own structures. As soon as it receives a handle (when D3dCreateSurfaceEx is called) that is beyond the end of the array, it can reallocate the array and continue. The Direct3D run-time passes no handle value to the driver before that handle is shown to the driver via D3dCreateSurfaceEx. However, the driver should be robust enough to handle values that are out-of-range, or that refer to a slot in the handle table that has been freed (that is a handle for which DdDestroySurface has been called). Note that since zero is a guaranteed invalid value, the zero entry in the handle table can be reused for other purposes. The perm3 sample driver uses the zero entry to store the current length of the array.


Pointers to DirectDraw Surfaces

Driver writers might be tempted to keep just a pointer to the DirectDrawSurface data structures inside their private driver-side surface structures. This practice will not succeed on Microsoft® Windows® 2000 and later, because access to DirectDraw's kernel-side data structures is mediated through a management scheme that insulates these structures from user mode and from drivers. This is why EngLockDirectDrawSurface exists: it provides a pointer to the structure that is valid for a brief time; until the EngUnlockDirectDrawSurface routine is called.

Outside of this lock/unlock pair, the structure is not guaranteed to reside at the same location, nor even to exist. Additionally, these lock/unlock pairs impede performance. If the driver keeps its own copies of the surface structures, then the locks are not needed. Updates to data within the driver-side surface structures are made during low-frequency calls like D3dCreateSurfaceEx. The result is that less code must be executed during high-frequency calls like D3dDrawPrimitives2.


D3dCreateSurfaceEx Handles

Certain situations can cause D3dCreateSurfaceEx to be called for an invalid, destroyed surface. Drivers can robustly handle this case by simply ignoring any D3dCreateSurfaceEx call for a video memory surface that has an fpVidMem (a member of the DD_SURFACE_GLOBAL structure) of zero. However, a driver can get a D3dCreateSurfaceEx call with a system memory surface that has an fpVidMem value of zero, which means that the system memory surface is in the process of being destroyed. The driver should then free any existing driver-side data related to this surface.


D3dCreateSurfaceEx and Backing Surfaces

D3dCreateSurfaceEx is also called for backing surfaces. This allows the driver to allocate a driver-side structure for the surface and thus respond to the D3DDP2OP_TEXBLT token for a system to video texture download.

It is very important that the driver not fail D3dCreateSurfaceEx for backing surface formats for which it does not support the pixel format. Such surfaces may be created for use with the software rasterizer. The driver should simply ignore backing surfaces it does not support. (Alternatively, the driver can create a driver-side structure, but the corresponding handle is never subsequently sent to the driver.) Failing D3dCreateSurfaceEx for these surfaces causes a failure code to be propagated to the application and the driver can potentially affect an emulation-only application. A driver's response to such situations can be tested by running the ddtest.exe application on the DirectX 7.0 SDK. Run the program and try to create a backing surface texture of a format unsupported by the driver, but supported by the DirectDraw emulation layer (a list of these formats can be found in the DirectDraw SDK documentation).


D3dCreateSurfaceEx and Complex Surfaces

As explained in Creating and Destroying DirectDraw Surfaces in the DirectDraw DDK documentation, creation of a complex surface causes an array of surfaces to be passed to DdCreateSurface. However, even in complex cases, only a pointer to the root surface is passed to D3dCreateSurfaceEx. It is necessary for the driver to go through the attachment lists of the root surface and create driver-side copies for all attached surfaces. This can be a tricky operation if the driver is attempting to handle creations for cube maps, MIP maps, and so on.

There are two types of DirectDraw surface attachments, implicit and explicit. An implicit attachment is formed during a complex surface creation. For example, when creating a primary flipping chain, the primary and back buffer are created by a single CreateSurface API call and they are attached to one another implicitly by the CreateSurface call. Another example is a MIP map chain where a series of MIP maps are created by a single CreateSurface API call. An explicit attachment is formed when surfaces created from different CreateSurface calls are attached explicitly by AddAttachedSurface.

The style of attachment has an implication for D3dCreateSurfaceEx processing. When two surfaces are explicitly attached, then both of those surfaces were created by separate calls to CreateSurface and each surface will have resulted in a call to D3dCreateSurfaceEx before the surface attachment was made. However, in the case of an implicitly attached surface, only a single CreateSurface and D3dCreateSurfaceEx call is made for the entire chain of surfaces. Therefore, when processing a D3dCreateSurfaceEx call a driver must run the attached list of surfaces to identify handles, and create driver side data structures for each attached surface. However, the attached surface list may contain a mixture of implicitly and explicitly attached surfaces. The driver will already have been notified of explicitly attached surfaces by D3dCreateSurfaceEx and probably will not want to process such surfaces again.

The driver can distinguish between implicit and explicit attachments by means of the DDAL_IMPLICIT flag stored in the dwFlags field of the DD_ATTACHLIST data structure. If DDAL_IMPLICIT is set in the dwFlags field, the attachment is implicit and no separate D3dCreateSurfaceEx call is seen for the attached surface. If this flag is not set, the attachment is explicit and the attached surface results in its own D3dCreateSurfaceEx call. By examining this flag, the driver can determine whether it needs to process an attached surface as part of the parent surface's D3dCreateSurfaceEx call or whether a separate D3dCreateSurfaceEx call will have been made for the attached surface.

For more information, see the section on surface attachments in DirectDraw Driver Fundamentals, and see the sample code included in D3dCreateSurfaceEx.


D3dCreateSurfaceEx and MIP Maps

Each level in a MIP map is associated with a different handle value. There is no guarantee that these handles are consecutive, however. The Direct3D DDI is designed so that only the top-level surface's handle is passed as an argument in the IDirect3DDevice7::SetTexture API method (described in the Direct3D SDK documentation), and then the current level-of-detail is specified by a texture stage state (D3DTSS_MAXMIPLEVEL). The most natural way to work with MIP maps is to build one driver-side structure that represents the entire MIP map.


D3dCreateSurfaceEx Handles and Flip

DirectDraw's surface structures are designed to represent conceptual surfaces, not necessarily specific locations in video memory. The main usage of this abstraction is in a primary flipping chain, where the application uses one constant surface object to represent the back buffer, even though the back buffer may be moving around in video memory as a result of the DdFlip operation.

The DdFlip method takes a ring of surfaces, and rotates (sequentially reassigns) their video memory pointers around this ring. In the particular case of two surface objects, the process is reduced to trading their video memory pointers. In addition, the DirectDraw run-time also rotates the D3dCreateSurfaceEx handles associated with each surface, and the driver-owned contents of the dwReserved1 members of each surface. This behavior has some interesting consequences for a DirectX 7.0 driver, and effectively rules out the embedding of pointers to DirectDraw's surface structures inside the driver's own surface structures.

Consider two surface objects A and B that have associated handles HA and HB, and fpVidMem (a member of the DD_SURFACE_GLOBAL structure) values of FA and FB. Further, suppose that the application is using surface structure A to refer to the back buffer of a flipping chain. At DdFlip time, the handles and both fpVidmem values are swapped, so that surface A has HB and FB, and surface B has HA and FA. The application now tries to draw to the back buffer, surface A, which should represent the video memory at FB (because the application called DdFlip).

A drawing command is issued to the driver, which looks up the handle associated with that surface (which is now HB, not HA). What would happen if the driver merely stored a pointer to the DirectDraw surface structure? The driver would look up HB, then follow the stored pointer to surface B, which now has an fpVidMem value of FA. Drawing would begin on the video memory at FA. This is not what the application is expecting. If, on the other hand, the driver were to store surface data in its own structures, rather than following a pointer to DirectDraw's surface structure, then HB would still resolve to FB, and drawing would occur on the correct surface. This latter case is the way the current DDI is implemented.


D3dCreateSurfaceEx Handles and DirectDraw DDIs

Handles do not completely insulate a DirectX 7.0 driver from the DirectDraw-managed DDRAWI_DDSURFACE_MORE and DDRAWI_DDSURFACE_LCL structures. These structure names are essentially aliases for the structures DD_SURFACE_MORE and DD_SURFACE_LOCAL. In DirectDraw DDIs, such as DdBlt, DdFlip, the driver is still passed surface structure pointers, and still must be able to use these structures instead of its private representations.


Points to Consider when Restoring Complex Flipping Chains

When a complex primary surface is created, it might or might not have an attached Z-buffer. When a surface is restored, it is possible that the application has added an attachment to a Z-buffer. Driver writers should be mindful of these different scenarios when going through surface attachment lists in D3dCreateSurfaceEx. A typical technique, presented in the perm3 sample driver, is to mark a surface's dwReserved1 field when D3dCreateSurfaceEx is called for that surface. The driver only marks the surface if fpVidMem (a member of the DD_SURFACE_GLOBAL structure) is not equal to zero. This is because fpVidMem could be zero because the application restored a primary surface that had a back buffer with an explicitly attached Z-buffer, but the Z-buffer had not yet been restored. At some later time, the application restores the Z-buffer, and the driver then marks it. Note that if the application restores the Z-buffer before restoring the primary chain, the driver may receive the Z-buffer, already marked, attached to the back buffer when D3dCreateSurfaceEx is called.


Lost Surfaces, Surface Handles, and Contexts

The concept of lost surfaces was introduced in the DirectDraw SDK documentation. Lost surfaces have some implications in the DirectX 7.0 DDI model. See Lost Surfaces and Atomic Restoration for more details.

It is necessary for some surfaces to be referred to in a context (such as the render target, Z-buffer, or a texture), typically by storing the handles for those surfaces in the driver's context. These surfaces may become lost, which means destroyed, as far as the driver is concerned. The context itself may survive, but may now have "stale" (invalid) handles to destroyed surfaces. The run-time guarantees that no rendering commands are passed to the context while it is in this state, but there is still the problem of how to re-associate the context with restored surfaces before rendering can begin again. The run-time guarantees that the handles for lost surfaces do not change. This in turn guarantees that if a context keeps handles to its surfaces (render target, Z, and textures), then it need not worry that the surface objects referred to by these handles have been destroyed. These surfaces are always recreated (restored) with the same handle values before rendering can resume on this context.

Some driver writers may wish to optimize the state of a context by storing surface data directly in the context, rather than doing the work of dereferencing the handles on every D3dDrawPrimitives2 call. Since the cost of this dereference is likely to be very small compared to the cost of executing a batch of D3dDrawPrimitives2 tokens, this optimization is not encouraged. However, if driver writers wish to do so, then they must be aware that surfaces may move when they are restored. This means that while the handle may be the same, there is no guarantee that a surface is restored with the same fpVidMem (a member of the DD_SURFACE_GLOBAL structure) pointer with which it was created. Contexts that are optimized in this way may end up with "stale" (invalid) video memory pointers, and have no information that the surface has moved. Dealing with this can be fairly tricky, but several methods are possible. One method to deal with this is that the driver may tag any surface when it is associated with a context (as render target, Z-buffer, or texture). Then at D3dCreateSurfaceEx time, it can search for any context that refers to this surface and then update that context.

It is not recommended that a surface keep a pointer to a context, since one surface may be associated with more than one context.


Direct3D Texture Management

Although texture support is optional, most of today's drivers are capable of supporting it. Drivers that support texture mapping must respond to all of the texture-related operation codes in the Microsoft® Direct3D® DDI.

Drivers must also validate the texture stage states with the D3dValidateTextureStageState callback.


Multitexturing

Direct3D drivers can support the simultaneous use of multiple textures. This multiple texture support is enabled in the driver using texture stage state types (D3DTEXTURESTAGESTATETYPE, described in the DirectX SDK documentation). These allow all the properties of a texture to be defined and combined with vertex extensions that specify independent sets of texture coordinate data.

Adding multitexture support for Direct3D drivers requires setting the correct capability bits (Caps), implementing texture blending, and implementing D3dValidateTextureStageState.

To be compliant with DirectX 6.0 and later versions, a driver is required to properly parse up to eight texture coordinate sets, even if the device can only iterate and use the number or coordinates defined in dwFVFCaps (a member of the D3DHAL_D3DEXTENDEDCAPS structure). The driver uses D3DTSS_TEXCOORDINDEX(s) to get the correct coordinates to use for texturing.

Flexible vertex formats (FVF) allow multitexturing because they make it possible to pass more than one texture coordinate in the vertex structure. Multiple textures can then be blended together in an iterated process and applied to a piece of geometry.

Texture handles are no longer generated by Direct3D drivers. Instead, the texture handles are generated by the Direct3D run-time. Texture cache management is done completely by the Direct3D run-time so that, to the driver, textures always appear to come from the application itself. All texture state is sent to the driver in the D3dDrawPrimitives2 command stream.

With the addition of multitexture, the methods for blending and texture filtering have also been refined to make possible a much clearer and well-defined mechanism for blending. For more information on these blending and texture filtering mechanisms, see the Microsoft DirectX® SDK documentation.


Texture Stages

The texture stage indicates the location of the texture in the texture pipeline. The position with the highest non-NULL texture is closest to the frame buffer. Each stage is a texture blending unit that performs the operation used to combine an associated texture onto a polygon, as shown in the following figure.

A Single Texture Stage

The current texture enters the stage and is blended with another texture and a diffuse component with the result being passed forward to the next stage in the texture pipeline (or frame buffer if this is the last stage).

There are eight texture stages, numbered zero through seven, with zero being furthest to the frame buffer, and corresponding to the render state texture handle D3DRENDERSTATE_TEXTUREHANDLE, described in the DirectX SDK documentation. The driver must handle up to eight texture coordinates, even if the hardware does not support that many.

In multiple texture rendering, the lower-numbered texture stages are farther away from the frame buffer. The lowest texture stage in the cascade is picked up and filtered to get a texel, or texture element. A blending operation occurs between that texel and the next as it cascades down the texture pipeline toward the frame buffer.

For example, if two textures, Texture0 and Texture1, are blended together, the resulting texel enters the rasterization pipeline just as a single texture would using legacy texturing. With three textures, Texture0 gets blended with Texture1. The resulting texel is then blended with Texture2 according to some (programmable) weight. This means that Texture0 cannot influence Texture2 directly; it can only do so by proxy, by being blended with Texture1. This latter example is illustrated in the following figure.

A Three Stage Texture Pipeline

Each texture stage introduces no more than one texture into the pipeline. The pixel pipeline is separate and comes after multitexture operations. This may include fog application or frame buffer alpha blending.


Command Stream

At the driver level, instructions come in the form of calls to D3dDrawPrimitives2. The input structure D3DHAL_DRAWPRIMITIVES2DATA contains a pointer into a command buffer. This is a sequence of D3DHAL_DP2COMMAND structures. Each of these structures contains a bCommand member that specifies what type of data follows it in the buffer. This specification comes in the form of a D3DHAL_DP2OPERATION enumerated type, such as D3DDP2OP_INDEXEDTRIANGLESTRIP or, in the case of setting up texture states, D3DDP2OP_TEXTURESTAGESTATE. (See D3DHAL_DP2OPERATION for a complete listing of these enumerators.)

In other words, the D3DHAL_DP2OPERATION operation code simply specifies what type of structures follow it in the command buffer. The number of structures to follow is specified by either wPrimitiveCount or wStateCount, members of a union that is in turn a member of the D3DHAL_DP2COMMAND structure. The wPrimitiveCount member keeps track of the number of graphics primitives to render, while the wStateCount member keeps track of the number of state changes to process.

For example, if the operation code is D3DDP2OP_TEXTURESTAGESTATE, and the value of wStateCount is seven, then seven D3DHAL_DP2TEXTURESTAGESTATE structures will follow before the next D3DHAL_DP2COMMAND instruction is reached. To carry this example to completion, each D3DHAL_DP2TEXTURESTAGESTATE structure contains a dwStage member that specifies which stage of the texture blending pipeline needs to have a texture state change. The TSState member of the same structure specifies which state of the D3DTEXTURESTAGESTATETYPE enumerated type to set, and the dwValue member of the D3DHAL_DP2TEXTURESTAGESTATE structure contains the value to which the specified state should be set.

The process is the same for all render states, or any other type of instruction. If the bCommand member of the D3DHAL_DP2COMMAND structure is D3DDP2OP_RENDERSTATE, then the structure to follow is a D3DHAL_DP2RENDERSTATE structure and the information in that structure is used to set the render state accordingly.

Rather than using distinct Boolean-valued render states to control the coordinates, each render state value is a set of flags composed with the D3DWRAP_U and D3DWRAP_V flags (defined in d3dtypes.h). This change was made for compatibility with higher-dimensional textures.

Other useful information pertaining to multitexture implementation can be found in the DirectX SDK documentation, in the sections covering blend equations, semantics of per-texture states, color operations, and alpha operations. For more information about the texture stage state types enabled for DirectX 6.0 and later versions, see the D3DTEXTUREOP, D3DTEXTUREMAGFILTER, D3DTEXTUREMINFILTER, and D3DTEXTUREMIPFILTER enumerated types.


Texture Addressing and Filtering Operations

In Direct3D, texture addressing, filtering, and blending operations are performed by a separate logical unit called a texture stage. Addressing and filtering operations are described here because they form a logical grouping independent of the blending operations. For further information about texture operations, see the D3DTEXTUREOP enumerated type in the DirectX SDK documentation.

Although addressing and sampling operations are defined in conjunction with blending operations in DirectX 6.0 and later versions, in later releases of DirectX they are likely to be independent of the blending operations. The following texture stage states are used to set up texture addressing and filtering operations for each stage in the texture pipeline:

Operation | Description
D3DTSS_ANISOTROPY | Specifies the anisotropic filtering ratio limit. It specifies the maximum aspect ratio of anisotropic filtering to be applied during sampling of this texture.
D3DTSS_MAGFILTER | Defines the type of filter used to sample textures when they are being magnified (that is, when one texel is getting stretched onto multiple rendering surface pixels). The filters that can be used for texture magnification are enumerated in D3DTEXTUREMAGFILTER.
D3DTSS_MAXMIPLEVEL | Specifies the maximum MIP map level to be used. It indicates that this texture should never sample MIP map levels that are larger that the one indicated. Therefore, the maximum dimension is 2 MAXMIPLEVEL. Zero indicates that there is no limit.
D3DTSS_MINFILTER | Defines the type of filtering that is used to sample textures when they are being minified, that is, one texel is mapped onto less than one screen pixel. The filters that can be used for texture minification are enumerated in D3DTEXTUREMINFILTER.
D3DTSS_MIPFILTER | Defines the type of filtering that is used to sample between layers of a MIP map. The filters that can be used for this are enumerated in D3DTEXTUREMIPFILTER.
D3DTSS_MIPLEVEL | Allows application to set the MIP level when hardware cannot. This is overridden when the MIP level is determined by hardware.
D3DTSS_MIPMAPLODBIAS | Is a D3DVALUE that specifies the MIP map level of detail (LOD) bias. This bias affects the MIP map level calculation, allowing more or less blurring of textures (and more aliasing) as desired. Units are in MIP levels. Current WHQL/DCT tests require the MIP map LOD bias to operate in the range -3.0 to 3.0.
D3DTSS_TEXCOORDINDEX | Specifies the index of a texture coordinate set. This integer indicates the index of the set of texture coordinates from which the addressing unit should sample. These coordinates are listed in the incoming flexible vertex format (FVF) vertex data in numerical order, with zero being the standard DirectX set of texture coordinates, one being a second texture coordinate set, and so on. This allows textures to share sets of texture coordinates as desired.

Important To be Direct3D-compliant, drivers are required to properly parse up to eight texture coordinate sets, even if the device can only iterate and use the number of coordinates defined in dwFVFCaps. The driver must use D3DTSS_TEXCOORDINDEX(s) to grab the right coordinates to use for texturing.


Texture Stage Operations

An application performs blending operations for texture stages by calling the IDirect3DDevice7::SetTextureStageState method (described in the Direct3D SDK documentation). Multitexture blending operations are performed by a set of texture blending unit stages. Each of these can be individually programmed to carry out a variety of texture blending operations, selected by a parameter.

Direct3D does not provide a mechanism for specifying more than one texture being introduced at each blending stage. Saturation is defined to occur between texture stages in the pipeline, but it should occur as late as possible within each stage.

The set of legal operations is enumerated in D3DTEXTUREOP. These operations are required for PC98 compatibility compliance:

  • D3DTOP_DISABLE
  • D3DTOP_SELECTARG1, D3DTOP_SELECTARG2
  • D3DTOP_MODULATE
  • D3DTOP_ADD
  • D3DTOP_BLENDTEXTUREALPHA

The default values are D3DTOP_MODULATE for stage one, and D3DTOP_DISABLE for all other stages. D3DTOP_MODULATE is used for stage one for backwards compatibility, but by default all texturing should be disabled.


Texture Stage Arguments

Each of the multitexture blending operations combines two inputs. These can be selected by calling the IDirect3DDevice7::SetTextureStageState method (described in the Direct3D SDK documentation) and specifying one of the following members of the D3DTEXTURESTAGESTATETYPE enumerated type:

Enumerator | Meaning
D3DTSS_ALPHAARG1 | Controls first input to alpha operation.
D3DTSS_ALPHAARG2 | Controls second input to alpha operation.
D3DTSS_COLORARG1 | Controls first input to color operation.
D3DTSS_COLORARG2 | Controls second input to color operation.

Texture Argument Flags

At each texture stage, any of the preceding four parameters can be set using the following texture argument flags:

Flag | Meaning
D3DTA_CURRENT | The texture argument is the result of the previous blending stage. In the first texture stage (stage zero), this argument is equivalent to D3DTA_DIFFUSE. This can be thought of as the current color of the polygon as each texture is composited onto it. If the previous blending stage uses a bump-map texture (the D3DTOP_BUMPENVMAP operation), the system chooses the texture from the stage before the bump-map texture. (If s represents the current texture stage, and s - 1 contains a bump-map texture, this argument becomes the result output by texture stage s - 2.)
D3DTA_DIFFUSE | The iterated color data obtained from the Gouraud interpolators. This is often used as the ARG2 on the first texture, since there is no D3DTA_CURRENT texture color at that point.
D3DTA_TEXTURE | The texture bound to this texture stage using the IDirect3DDevice7::SetTexture(n, lpTex3) method (described in the Direct3D SDK documentation), where n is the stage number. IDirect3DDevice7::SetTexture defines which texture object to use for the texture in this stage when D3DTA_TEXTURE is one of the arguments. D3DTA_TEXTURE can only be present in D3DTSS_ALPHAARG1 and D3DTSS_COLORARG1, but not in D3DTSS_ALPHAARG1 and D3DTSS_COLORARG2.
D3DTA_TFACTOR | A value set in Direct3D with D3DRENDERSTATE_TEXTUREFACTOR. Note: Some implementations may not be able to simultaneously use both D3DTA_TFACTOR and a D3DTA_DIFFUSE color.

Modifier Flags

These two values should be combined with one of the preceding flags using the bit-wise OR operator.

Value | Meaning
D3DTA_ALPHAREPLICATE | Indicates that this argument should have its alpha channel replicated to all color channels before use in this operation. If this is a texture with only one component, it is automatically replicated to all color channels for these operations. This flag need not be specified for the ALPHA_ARGs, but using it does not produce an error.
D3DTA_COMPLEMENT | Indicates that this argument should be inverted for the operation.

Defaults

The following default values are used if a state is not filled in by the application. While these default values have been defined to make multitexture operations more convenient, robust code always fully specifies the desired state.

D3DTSS_COLORARG1 and D3DTSS_ALPHAARG1 both default to D3DTA_TEXTURE, if the corresponding texture has been set. If no texture has been set for this stage, then these both default to D3DTA_DIFFUSE.

D3DTSS_COLORARG2 and D3DTSS_ALPHAARG2 default to D3DTA_CURRENT. Note that D3DTA_CURRENT defaults to D3DTA_DIFFUSE on the first stage (except as noted in the description of D3DTA_CURRENT).

ARG2 defaults to D3DTA_DIFFUSE, but is ignored because the operation defaults to D3DTOP_SELECTARG1.

D3DTA_DIFFUSE defaults to 0xFFFFFFF if no diffuse color is specified in the flexible vertex format (FVF) data.

D3DTA_SPECULAR defaults to 0x00000000 if no specular color is specified in the FVF data.

D3DTA_CURRENT defaults to D3DTA_DIFFUSE if this is the first stage except when the previous blending stage is a D3DTOP_BUMPENVMAP or D3DTOP_BUMPENVMAPLUMINANCE color operation. In this case, the following occurs:

  • If the previous stage is D3DTOP_BUMPENVMAP or D3DTOP_BUMPENVMAPLUMINANCE, then this argument is the result of the stage before the previous stage.
  • In the second texture stage (stage one), this argument defaults to D3DTA_DIFFUSE.

D3DTA_TEXTURE is a value for a D3DTSS_COLORARG1 or D3DTSS_ALPHAARG1 state of any stage, or defaults to 0x0 if no texture is bound to this stage.


Multitexture Validation

Current hardware does not necessarily implement everything that Direct3D can express. The application determines whether a particular blending operation can be performed by first setting up the desired blending mode, and then calling the IDirect3DDevice7::ValidateDevice method (described in the Direct3D SDK documentation). The driver must accurately report its capabilities at initialization time and support D3DValidateTextureStageState to allow its capabilities to be validated. Validation also covers operations specified at the TBLEND level.

IDirect3DDevice7::ValidateDevice Return Codes

Return Code | Meaning
CONFLICTINGTEXTUREFILTER | The hardware cannot do trilinear filtering and multitexture at the same time.
TOOMANYOPERATIONS | The hardware cannot handle the specified number of options.
UNSUPPORTEDALPHAARG | The specified alpha argument is unsupported.
UNSUPPORTEDALPHAOPERATION | The specified alpha operation is unsupported.
UNSUPPORTEDCOLORARG | The specified color argument is unsupported.
UNSUPPORTEDCOLOROPERATION | The specified color operation is unsupported.
UNSUPPORTEDFACTORVALUE | The hardware cannot support D3DTA_TFACTOR greater than 1.0.
WRONGTEXTUREFORMAT | The hardware cannot support the current state in the selected texture format.


Paletted Textures

Direct3D also allows palettes to be used with textures. A palette can be attached to a texture, just as it can to any other DirectDrawSurface object. To support paletted textures, drivers must respond to the D3DDP2OP_SETPALETTE and D3DDP2OP_UPDATEPALETTE operation codes in their implementation of D3dDrawPrimitives2. These operation codes are followed by D3DHAL_DP2SETPALETTE and D3DHAL_DP2UPDATEPALETTE structures, respectively, in the command stream. D3DDP2OP_SETPALETTE creates an association between a palette handle to be used and a surface handle (already created by D3DCreateSurfaceEx). Later, D3DDP2OP_UPDATEPALETTE can be sent multiple times to set the values of the palette entries to be used for this texture.


Texture Blitting

An important change to the Direct3D DDI, which takes effect as of DirectX 7.0, is that textures are blitted - not by a direct call to DdBlt - but by embedding a new token in the D3dDrawPrimitives2 command stream. This new token is D3DDP2OP_TEXBLT, and it signals the driver that a texture has to be transferred from a backing surface into local or non-local video memory.

Also, instead of the driver being responsible for creating internal handles for textures through the legacy D3dTextureCreate and D3dTextureDestroy callbacks, the run-time now assigns a handle number to each DirectDrawSurface object that is created within the Direct3D context. The driver is signaled about this handle number through the D3dCreateSurfaceEx callback.

D3dCreateSurfaceEx is called after every hardware abstraction layer (HAL) DDCreateSurface call is finished. D3dCreateSurfaceEx is also called after every internal hardware emulation layer (HEL) CreateSurface call is finished. The HEL call usually occurs when a backing DirectDrawSurface object is created. These calls may occur before and after a Direct3D context is created with D3dContextCreate.

Also, when the application is running, a call is made to D3dDestroyDDLocal to clean up and destroy any driver data created explicitly for these surfaces. This call is also made before a Direct3D context is created. This is done to ensure that there are no dirty handles associated with any contexts that have not been cleaned up. This is simply a preventative measure that should not actually destroy anything if contexts are properly cleaned up after use.


Driver-Managed Textures

The driver can optionally manage textures that have been marked as manageable. These DirectDrawSurface objects are marked as manageable with the DDSCAPS2_TEXTUREMANAGE flag in the dwCaps2 member of the structure referred to by lpSurfMore->ddCapsEx. (lpSurfMore and ddCapsEx are members of the DD_SURFACE_LOCAL and DD_SURFACE_MORE structures, respectively.)

The driver makes explicit its support for driver-managed textures by setting the dwCaps2 member of the DDCORECAPS structure to the DDCAPS2_CANMANAGETEXTURE bit. The driver specifies this DDCORECAPS structure in the ddCaps member of a DD_HALINFO structure. DD_HALINFO is returned by DrvGetDirectDrawInfo in response to the initialization of the DirectDraw component of the driver.

The driver can then create the necessary surfaces in video or non-local memory in a "lazy" fashion. That is, the driver leaves the textures in backing surfaces until it requires them, which is just before rasterizing a primitive that makes use of the texture.

Surfaces should be evicted primarily by their priority assignment. The driver should respond to the D3DDP2OP_SETPRIORITY operation code in the D3dDrawPrimitives2 command stream. This opcode sets the priority for a given surface. As a secondary measure, it is expected that the driver uses a least-recently-used (LRU) scheme. This scheme should be used as a tie breaker, whenever the priority of two or more textures is identical in a particular scenario. Logically, any surface that is in use should not be evicted at all.

If a driver supports managed surfaces, then the driver may receive a special DdDestroySurface call for a managed surface in the case where video memory is lost, such as when a mode switch occurs. In this case the DRAWISURF_INVALID flag is set and the driver should simply evict the video memory copy of this managed surface and keep other structures intact. Otherwise, the driver should perform a regular destroy surface call.

The driver must be cautious of honoring DdBlt and DdLock calls when managing textures. This is because any change to the backing surface image must be propagated into the video memory copy of the surface before the texture is used again. The driver should determine if it is better to update just a portion of the surface or all of it.

The driver is allowed to perform texture management in order to perform optimization transformations on the textures or to decide for itself where and when to transfer textures in memory.


Driver-Managed Resources

In addition to supporting texture management as described in Driver-Managed Textures, a DirectX 8.1 driver can also manage resources in general, such as textures, volume textures, cube-map textures, vertex buffers, and index buffers.

The driver makes explicit its support for driver-managed resources by setting the dwCaps2 member of the DDCORECAPS structure to the DDCAPS2_CANMANAGERESOURCE bit. The driver specifies this DDCORECAPS structure in the ddCaps member of a DD_HALINFO structure. DD_HALINFO is returned by DrvGetDirectDrawInfo in response to the initialization of the DirectDraw component of the driver.


Primitive Drawing and State Changes

All Microsoft® Direct3D® primitives and state are passed to the D3dDrawPrimitives2 callback in command and vertex buffers. The driver is responsible for parsing these buffers and processing all drawing and state change requests.

The sections that follow discuss the layout of command and vertex buffers and describe how the driver should process them.


Command and Vertex Buffers

The D3dDrawPrimitives2 DDI uses two types of buffers: command buffers and vertex buffers. (See D3DHAL_DRAWPRIMITIVES2DATA for a description of the main input structure.) Command buffers contain instructions followed by data in a structure similar to that of execute buffers. Command buffers might contain indexed and non-indexed primitives and, occasionally, inline vertex data. Command buffers can be either API-level execute buffers or Direct3D internal command buffers.

With internal command buffers, the driver allocates the memory and may do multi-buffering. Internal command buffers are write-only. The instruction format can be seen in D3DHAL_DP2COMMAND.

If the D3DHALDP2_USERMEMVERTICES flag is set, the vertex buffer is specified by a user-memory pointer. Otherwise the vertex buffer is a DirectDrawSurface that can be an API-level execute buffer, an internal implicit vertex buffer, or an API-level vertex buffer.

The vertex buffer API can create, destroy, lock and unlock vertex buffers, and can use the IDirect3DVertexBuffer7::ProcessVertices method to process vertices from source to destination buffers. The IDirect3DDevice7::DrawPrimitiveVB and IDirect3DDevice7::DrawIndexedPrimitiveVB methods are the primary API-level calls. Vertex buffers can also be optimized, but optimized vertex buffers cannot be locked. See the Direct3D SDK documentation for descriptions of these three methods.

Note to Windows 98/Me Driver Writers

When you place a vertex buffer in video memory, it must be located in one of the heaps you reported to the DirectDraw/Direct3D runtime at initialization time. If the vertex buffer (whose pointer you return to the runtime) does not lie in one of the reported heap ranges, the runtime deallocates the vertex buffer and create a new one in system memory.

The reason for this requirement is that on Windows 98/Me, the runtime holds the Win16Lock on the vertex buffer at all times. (If the runtime constantly locked and unlocked the vertex buffer, performance would suffer.) However , to ensure that the operating system works correctly, the Win16Lock can be held only for relatively short periods of time.

The only way to avoid the runtime holding the Win16Lock for video memory surfaces is to use virtual memory aliasing of the video memory, in particular the heaps. It is these heaps that are aliased by the runtime. Therefore, only video memory that lies in one of these heaps can be locked without holding the Win16Lock. It is important to note that this check for video memory pointers that can be aliased occurs when command and vertex buffers are swapped in response to a D3dDrawPrimitives2 call to your driver, as well as at the time they are created.

This requirement does not apply to Windows 2000 and later. The Win16Lock and the video memory aliasing to avoid locking are specific to Windows 98/Me.


Command and Vertex Buffer Allocation

There are three types of buffers used in Direct3D:

  • Implicit vertex buffers (IVBs) are created for internal use only; that is, applications are unaware of IVBs. One IVB is always created after context creation. Direct3D stores vertex data in IVBs.
  • Explicit vertex buffers (EVBs) are created only in response to an application request. Direct3D then stores vertex data in EVBs.
  • Command buffers are created for internal use only; that is, applications are unaware of command buffers. Direct3D stores command data in command buffers.

Implicit vertex buffers are special vertex buffers used internally by Direct3D for batching. They are created during device initialization and can be multibuffered. They are always read/write so they should not be put in video memory (for Microsoft DirectX® 6.0 and the later versions). This type of buffer is marked by the absence of both the DDSCAPS2_VERTEXBUFFER and DDSCAPS2_COMMANDBUFFER flags.

Explicit vertex buffers are created and controlled by the application. These cannot be multibuffered and cannot be put into local or non-local video memory unless the DDSCAPS_WRITEONLY flag is set. Explicit vertex buffers are marked with DDSCAPS_VERTEXBUFFER.

Command buffers are used by Direct3D to batch commands. They can be multibuffered and are used for all APIs except for TLVERTEX or unclipped execute-buffer API calls. This type of buffer is marked by the flag DDSCAPS2_COMMANDBUFFER. They are always write-only, though no explicit flag is set and they never contain invalid instructions.

By default, the Direct3D run-time allocates all of these buffers. IVBs and command buffers are accessed through the surfaces with which they are associated. All buffers are passed to the driver's D3dDrawPrimitives2 callback.

Driver-Allocated Vertex and Command Buffers

A Direct3D driver can optionally perform the allocation of vertex and command buffers by supplying callback functions. To supply these callback functions, the Direct3D driver must fill out a DD_D3DBUFCALLBACKS structure and point the lpD3DBufCallbacks member of the DD_HALINFO structure to it. DD_HALINFO is returned by DrvGetDirectDrawInfo in response to the initialization of the DirectDraw component of the driver. The callbacks reported in the DD_D3DBUFCALLBACKS structure are:

CanCreateD3dBuffer

CreateD3dBuffer

DestroyD3dBuffer

LockD3dBuffer

UnlockD3dBuffer

Windows 98/Me Note A Direct3D driver for Windows 98/Me uses the DDHAL_DDEXEBUFCALLBACKS structure rather than DD_D3DBUFCALLBACKS to supply callback functions. The callbacks reported in the DDHAL_DDEXEBUFCALLBACKS structure are named XxxExecuteBuffer instead of XxxD3dBuffer like the preceding callback functions. However, the callback functions reported in DDHAL_DDEXEBUFCALLBACKS are used in the same way. The ddrawi.h file defines DDHAL_DDEXEBUFCALLBACKS; the ddrawint.h file defines DD_D3DBUFCALLBACKS.

A Direct3D driver's source code can contain the following definition to map DD_D3DBUFCALLBACKS to DDHAL_DDEXEBUFCALLBACKS so that such source code can be used to build a driver for either Windows 2000/XP or Windows 98/Me:
#define DDHAL_D3DBUFCALLBACKS DDHAL_DDEXEBUFFCALLBACKS
For more information, see Data Type Mapping between Windows 2000/XP and Windows 9x/98/ME.

These functions are called in the same way as the Dd Xxx Surface callbacks (such as DdCanCreateSurface) and only when the DDSCAPS_EXECUTEBUFFER flag is set. The buffer creation flags are DDSCAPS_WRITEONLY, DDSCAPS2_VERTEXBUFFER, and DDSCAPS2_COMMANDBUFFER.

Drivers determine the type of buffer being requested by checking the ddsCaps member of the DD_SURFACE_LOCAL structure passed to the CanCreateExecuteBuffer and CreateExecuteBuffer callback for the following flags:

  • DDSCAPS_VERTEXBUFFER indicates that the driver should allocate an explicit vertex buffer.
  • DDSCAPS_COMMANDBUFFER indicates that the driver should allocate a command buffer.
  • If neither flag is set, the driver should allocate an implicit vertex buffer.

Drivers can allocate vertex buffers and command buffers using existing execute buffer callbacks. The driver should expose video memory heaps, even if they do their own heap management. This can be done by exposing a "dummy heap" that reports the appropriate size. Direct3D assumes that the driver can blt with outstanding locks to video memory.

The driver can internally allocate N vertex and command buffers and cycle through these buffers. Direct3D fills a given pair while the hardware asynchronously renders from the other queued buffers. This is very useful with direct memory access (DMA).

Buffers in a multibuffering set can be in different memory types. To do this, the driver is called to create the first buffer. It can create the set immediately and return the first buffer in the set to Direct3D. For each call to D3dDrawPrimitives2, if the D3DHALDP2_SWAPVERTEXBUFFER or D3DHALDP2_SWAPCOMMANDBUFFER flag is set, the driver should return a new buffer. If the returned buffer is in video memory, the corresponding D3DHALDP2_VIDMEMVERTEXBUF or D3DHALDP2_VIDMEMCOMMANDBUF flag should be set.

Occasionally, Direct3D requests the minimum size for the next buffer. If the size is too large, the driver should allocate the buffer in a backing surface. If the size is too small, the driver is permitted to provide a larger buffer. The driver should keep track of how many buffers and what memory types they are and clean up everything on exit.


Direct3D Command Buffers

The following figure shows portions of a sample logical command buffer. The driver's D3dDrawPrimitives2 callback receives a pointer to a command buffer in the lpDDCommands member of the D3DHAL_DRAWPRIMITIVES2DATA structure. The command buffer is always processed sequentially.

Sample Command Buffer

As shown in the preceding figure, a command buffer contains an unspecified number of D3DHAL_DP2COMMAND structures, where the bCommand member of each structure identifies one of the following commands:

  • D3DDP2OP_RENDERSTATE indicates that there are wStateCount D3DHAL_DP2RENDERSTATE structures that follow in the command buffer. The driver should parse the state from each of these structures and update its private driver state accordingly. The driver should also update the appropriate state in the array to which lpdwRStates points. If the driver does not support the state requested in the command buffer, the driver should override the requested value with one that it supports.
  • D3DDP2OP_TEXTURESTAGESTATE indicates that there are wStateCount D3DHAL_DP2TEXTURESTAGESTATE structures that follow in the command buffer. The driver should parse the state from each of these structures and update the driver's texture state associated with the specified texture stage accordingly. The driver does not report texture stage state back to the Direct3D run-time.

    A driver is required to properly parse up to eight texture coordinate sets regardless of how many coordinate sets it actually uses.

  • D3DDP2OP_VIEWPORTINFO indicates that there is one D3DHAL_DP2VIEWPORTINFO structure that follows in the command buffer. The driver should parse this structure and update the viewport information stored in the driver's internal rendering context.
  • D3DDP2OP_WINFO indicates that there is one D3DHAL_DP2WINFO structure that follows in the command buffer. The driver should parse this structure and update the w-buffer information stored in the driver's internal rendering context.
  • Any of the remaining D3DDP2OP_Xxx commands indicate that there is enough data following in the command buffer to render wPrimitiveCount (a member of the D3DHAL_DP2COMMAND structure) primitives. Depending on the primitive command, the driver should parse D3DHAL_DP2Xxx structures from the command buffer and vertex-associated data from either or both the vertex buffer and command buffer. The driver must attempt to process all valid D3DDP2OP_Xxx commands; that is, the driver cannot choose to ignore certain defined primitive types. See the individual D3DHAL_DP2Xxx structure reference pages for details.

Depending on the current command, the following additional information is stored in the command buffer:

  • Index information for all D3DDP2OP_INDEXEDXxx primitive commands.
  • Vertex data for the D3DDP2OP_TRIANGLEFAN_IMM and D3DDP2OP_LINELIST_IMM primitive commands.
  • Additional operations are also defined as D3DDP2OP_Xxx opcodes in the D3DHAL_DP2OPERATION structure. These are equivalent to D3DDP2OP_Xxx commands with the same names.

The command buffer occasionally contains commands that are understood only by Direct3D. If the driver's D3dDrawPrimitives2 callback does not recognize the command, the driver should call Direct3D's D3dParseUnknownCommand callback to attempt to parse it. When D3dParseUnknownCommand returns successfully, the driver should continue parsing and processing the command buffer. If D3dParseUnknownCommand fails by returning D3DERR_COMMAND_UNPARSED, D3dDrawPrimitives2 should set the following members of the D3DHAL_DRAWPRIMITIVES2DATA structure and return:

  • In dwErrorOffset, write the offset of the first unhandled D3DHAL_DP2COMMAND structure into the buffer to which lpDDCommands points.
  • Set ddrval to D3DERR_COMMAND_UNPARSED.

See Direct3D Driver Initialization for details on how to initialize the D3dParseUnknownCommand callback.

To simplify implementation of D3dDrawPrimitives2, driver writers can copy the parsing code from the perm3 sample code and write driver-specific rendering and state update code only.

Direct3D is not always informed of the current render states. For example, execute buffers are not inspected by the run-time before they reach the driver. The driver can keep track of the render state array with the lpdwRStates member in the D3DHAL_DRAWPRIMITIVES2DATA structure. This is a pointer to the internal render states array that the driver keeps up to date as state changes occur.


Direct3D Vertex Buffers

A vertex buffer contains the vertex data associated with a command buffer's primitives in a call to D3dDrawPrimitives2. Vertices are represented using the flexible vertex format (FVF), where each vertex can have the following data associated with it:

  • Position (x,y,z, and optional w) (required)
  • Diffuse color (optional)
  • Specular color (optional)
  • Texture coordinates (optional). Direct3D can send up to a maximum of eight sets of (u,v) values.

Drivers must provide FVF support.

The actual vertices and the order in which they should be processed depends on the D3DDP2OP_Xxx primitive command just parsed from the command buffer. See the individual D3DHAL_DP2Xxx structure reference pages for details.


Accelerated State Management

Accelerated state management is a mechanism for communicating large state changes across the API and DDI in a single call. This scheme allows an application to define a collection of state-set calls as a state block defined by a single integer. Sending this integer as a render state executes all the state changes in one call.

This reduces API overhead by reducing the number of IDirect3DDevice7::SetRenderState method (described in the Direct3D SDK documentation) calls required, and can improve the efficiency of drivers by allowing them to "precompile" stage changes into their own hardware-specific format upon a state block define, instead of on execution of each state change.

Most applications render in only a handful of states, so having fine-grained state transitions is seldom important. What is more important is being able to define blocks of state that can be interchanged as the driver switches between common rendering scenarios. This is the whole point of state block management.

State-set tokens are used to record the states in the driver. A handle refers to a collection of states. The D3DHAL_DP2STATESET structure is used to inform the driver about state-set operations to perform.

If the dwOperation member of the D3DHAL_DP2STATESET structure is set to D3DHAL_STATESETBEGIN, the driver begins recording the states for the handle contained in the dwParam member. When the driver receives a dwOperation of D3DHAL_STATESETEND, it stops recording state.

If the dwOperation member is D3DHAL_STATESETDELETE, the state-set referred to by the dwParam handle should be deleted.

If the dwOperation member is D3DHAL_STATESETEXECUTE, the state block referred to by the dwParam handle should be applied in the device.

If the dwOperation member is D3DHAL_STATESETCAPTURE, the current state in the driver should be captured in a specific way, giving a snapshot of the current states defined in the state block. That is, only states that are already in the state block are captured. Thus, the state block acts as a sort of mask, only recording states that are defined in it. For example, if there is a D3DRENDERSTATE_ZENABLE render state in the state block, then the current state for D3DRENDERSTATE_ZENABLE is captured and put in the state block. If there is no D3DRENDERSTATE_ZENABLE in the state block, then that state is not captured.

Groupings of states are used to make generic state blocks that can be modified slightly for different rendering scenarios. These pre-defined groupings (enumerated in D3DSTATEBLOCKTYPE in the DirectX SDK documentation) define generic state blocks that can be subsequently modified with state changes to accommodate anticipated recurring rendering scenarios. For example, the driver might create 100 generic predefined state blocks and then modify each slightly to accommodate a different rendering scenario. The state block type is passed in the sbType member of the D3DHAL_DP2STATESET structure.

The sbType member is only valid for D3DHAL_STATESETBEGIN and D3DHAL_STATESETEND and specifies the pre-defined state block type with one of the following D3DSTATEBLOCKTYPE enumerated types: NULL for no state, D3DSBT_ALL for all state, D3DSBT_PIXELSTATE for pixel state, and D3DSBT_VERTEXSTATE for vertex state.

The driver should ignore the sbType member unless it implements render state extensions. If the driver implements extended render states; that is, render states beyond those the Direct3D run-time supplies, it can use sbType to determine what type of pre-defined render states are being used. From this information it can determine how to append the state block appropriately, to support its extensions.


FVF (Flexible Vertex Format)

The driver's D3dDrawPrimitives2 callback receives vertex data in a flexible vertex format (FVF). Because the vertex format is flexible, there is no comprehensive data structure defined for this data. Drivers must implement full FVF functionality.

Note that there was an FVF update for Microsoft® DirectX® 7.0 that included 1D, 3D, and 4D textures in addition to the usual 2D textures. See the perm3 sample driver and Platform SDK documentation for more information about these topics.


Determining the Vertex Buffer Data Format

To identify the format of the data in the vertex buffer, a driver should determine the following information:

  • The dimension of the textures (1D, 2D, 3D, or 4D)
  • The components that are present in the FVF data
  • The ordering of the components that are present

FVF Texture Dimension

The driver should determine the dimension of the textures from the D3DTEXTURETRANSFORMFLAGS texture coordinate count flags (D3DTTFF_COUNTn, described in the DirectX SDK documentation). The number of the count flag signals how many texture coordinates are present. Note that this does not necessarily equate to the dimension of the textures themselves, as explained below.

Non-Projected Textures

  • D3DTTFF_COUNT1 indicates that the rasterizer should expect 1D texture coordinates.
  • D3DTTFF_COUNT2 indicates that the rasterizer should expect 2D texture coordinates.
  • D3DTTFF_COUNT3 indicates that the rasterizer should expect 3D texture coordinates.
  • D3DTTFF_COUNT4 indicates the rasterizer should expect 4D texture coordinates.

Projected Textures

If projected textures are being used, the D3DTTFF_PROJECTED flag is set to indicate that the texture coordinates are to be divided by the last (COUNTth) element of the texture coordinate set. Thus, for a 2D projected texture, the count would be three, since the first two elements are divided by the third, resulting in two floats for a 2D texture lookup. That is, both D3DTTFF_COUNT2 and D3DTTFF_COUNT3 | D3DTTFF_PROJECTED reference a 2D texture.

FVF Vertex Data Components

The driver determines which components are present by analyzing the flags specified in the dwVertexType member of the D3DHAL_DRAWPRIMITIVES2DATA structure. Specifically, the following table indicates the possible bit fields that can be set in dwVertexType and the components that they identify:

Value | Meaning
D3DFVF_DIFFUSE | Each vertex has a diffuse color.
D3DFVF_SPECULAR | Each vertex has a specular color.
D3DFVF_TEX0 | No texture coordinates are provided with the vertex data.
D3DFVF_TEX1 | Each vertex has one set of texture coordinates.
D3DFVF_TEX2 | Each vertex has two sets of texture coordinates.
D3DFVF_TEX3 | Each vertex has three sets of texture coordinates.
D3DFVF_TEX4 | Each vertex has four sets of texture coordinates.
D3DFVF_TEX5 | Each vertex has five sets of texture coordinates.
D3DFVF_TEX6 | Each vertex has six sets of texture coordinates.
D3DFVF_TEX7 | Each vertex has seven sets of texture coordinates.
D3DFVF_TEX8 | Each vertex has eight sets of texture coordinates.
D3DFVF_XYZRHW | Each vertex has x, y, z, and w coordinates.

Only one of the D3DFVF_TEXn flags is set.

FVF Vertex Component Ordering

The components that comprise the vertex data are strictly ordered. Specifically, Microsoft Direct3D® only supplies the driver with vertex data that is ordered as shown in the following figure. Note that this diagram assumes 2D texture coordinates, although 1D, 3D, and 4D textures are also valid for DirectX 7.0 and later versions.

Flexible Vertex Format

As shown in the preceding figure, Direct3D always sends x,y,z, and w values; the remaining data is sent only as required by an application. Specifically, vertex data consists of the following components:

  1. Location (x,y,z,w) (required)

    The first vertex component is four D3DVALUEs that identify the position of the vertex. Direct3D always sets the D3DFVF_XYZRHW bit in dwVertexType.

  2. Diffuse Color (optional).

    If present, this component is a D3DCOLOR value that specifies the diffuse color for this vertex. Direct3D sets the D3DFVF_DIFFUSE bit in dwVertexType when this component is present.

  3. Specular Color (optional).

    If present, this component is a D3DCOLOR value that specifies the specular color for this vertex. Direct3D sets the D3DFVF_SPECULAR bit in dwVertexType when this component is present.

  4. Texture Data (optional).

    This part varies based on the dimension of the texture. For each dimension in the texture, a D3DVALUE specifies each of the u, v, w, or q components (see explanation of FVF Texture Dimension). For example, if 2D non-projected textures are being used, two D3DVALUEs per texture are needed to specify the vertex's u,v values for each texture up to eight textures total. The number of u,v pairs present is n, where n corresponds to the D3DFVF_TEXn flag set in dwVertexType. For example, if D3DFVF_TEX3 is set in dwVertexType, then three u,v pairs are supplied with each vertex.

FVF data is always tightly packed; that is, no memory is wasted on components that are not explicitly specified in the vertex buffer. For example, when dwVertexType is (D3DFVF_XYZRHW | D3DFVF_TEX2), and the texture dimension is 2D, each vertex in the buffer consists of eight tightly packed D3DVALUEs. These specify the location (x,y,z,w) and texture coordinates for two textures (tu0,tv0, tu1,tv1) as shown in the following figure.

Vertex Buffer

Note that in the preceding figure it is assumed that there are only two texture coordinates. The vertex data supplied to the driver is always transformed and lit. The driver never receives normals. All data in the FVF texture coordinate sets are single precision IEEE floats. See the perm3 sample driver for implementation details. See the Platform SDK documentation for more details about FVF.


Advanced Direct3D Driver Topics

This section describes Microsoft® Direct3D® specialty topics and optimizations. These features are not central to implementing core functionality in a Direct3D driver; they should be implemented later in the driver development process, after core driver functionality is completed.

The topics described in this section are:

Optimized Textures

Stencil Planes

Guard Band Clipping

Extents Adjustment

W-Buffering

Bump Mapping

Hardware Transform and Lighting


Optimized Textures

In order to increase performance, some hardware vendors have changed their texture formats from the standard Microsoft DirectDraw® surface format. One approach is to tile the pixels so they are arranged in memory with 2D locality of reference. For example, instead of arranging the pixels scan line by scan line like this:

0 | 1 | 2 | 3 | … width
width+1 | width+2 | width+3 | width+4 | …

pixels are arranged in 4x8 blocks of DWORDs:

0 | 1 | 2 | 3
4 | 5 | 6 | 7

Thus, a single contiguous 32-byte memory reference pulls in a 4x8 block of pixels for use by the rasterizer. This layout maps much better to the pattern of memory references typically generated by the rasterizer than does the standard DirectDraw layout. Such schemes are referred to as 'swizzling' or 'patching' the texture. These operations are relatively more rapid to perform, and do not affect the size of the memory surface allocated. However, there is still significant latency introduced by this operation that applications need to control.

Another approach is to compress the texture into video memory and decompress it into a local cache on the accelerator. This decreases the video memory bandwidth required to keep the rasterizer running at full speed. In DirectX 5.0, drivers could do this as well, but it is a much slower operation that affects the application's view of video memory allocation due to the resulting texture being smaller.

To accommodate hardware vendors, DirectX 6.0 and later versions enable "optimized" textures that give the driver an opportunity to translate the surface into a proprietary format when the texture is used. Once optimized, the surface cannot be locked and may be smaller or larger than the original.

Many 3D accelerator chipsets on the market have a proprietary format that cannot be described with the standard DirectDraw mechanisms. This feature is intended to cover all hardware with such surface types.

Currently applications have some textures that need to be updated frequently, and others that can be left alone for the duration of the application. These latter benefit from patching due to improved resulting fill rate. The flags shown in the Optimized Texture API section allow the application to specify this usage scenario to the driver so it can optimize performance accordingly.


Optimized Texture API

Three new capabilities indicate the level of optimization that can be applied to a DirectDrawSurface object. In DirectX 6.0 and beyond, only textures can be marked with these caps bits. The optimized surface paradigm may be extended in the future to cover other types of surfaces, although the semantics may not be the same as for textures.

To address these issues as cleanly as possible, three new flags are provided in the DirectDrawSurface7:: Create method. When none of these three flags is specified, the decision whether to patch or swizzle is left entirely up to the driver. These flags are as follows:

DDSCAPS2_HINTDYNAMIC
Indicates to the driver that this surface is locked very frequently, (for example, once per frame) for use such as streaming video or procedural textures. This cap should work for all driver-enumerated texture surface formats. The driver should avoid any transformation for these textures, especially if it requires some overhead.
DDSCAPS2_HINTSTATIC
This indicates to the driver that the surface can be reordered/retiled/swizzled in the IDirect3DDevice7::Load and IDirectDrawSurface7::Blt methods (described in the Direct3D SDK and DirectDraw SDK documentation, respectively). This operation does not change the size of the texture. It is relatively fast, and symmetrical, since the application may still lock these bits (although it takes a performance hit when doing so). Drivers are not allowed to fail locks on these surfaces and therefore cannot use lossy compression techniques. MIP map surfaces can be interleaved in this case.

This cap is not intended to force swizzling under any circumstances, especially those in which no performance benefit will arise. In particular, some texel formats may silently fail to swizzle.

DDSCAPS2_OPAQUE
This indicates to the driver that this surface will not be accessed by the application again. This flag behaves like the DDSCAPS2_HINTSTATIC flag, but with the addition of allowing actual compression using a hardware-specific compression scheme. This operation is relatively slow, but should allow simple, symmetric compression schemes (such as YUV 4:2:0, or color cell compression) to be used, providing compression ratios from 2 to 6x. Asymmetric schemes such as VQ should not be used here because they result in unacceptable benchmarks.

MIP map textures can be interleaved arbitrarily by the driver. This technique should probably only be requested outside of internal rendering loops such as when textures are loaded from disk. Heap size reports after such a texture is loaded reflect the reduced memory consumption if compression was applied. There is additional header overhead on textures and therefore compressing many small textures does not save as much memory as might be expected.

In general, there is no guarantee about texture compression ratio, or compression quality implied by this flag.

Surfaces created with this flag fail in the following cases:

Calls to the IDirectDrawSurface7::Lock method.

Calls to the IDirectDrawSurface7::GetDC method. Both methods are described in the DirectDraw SDK documentation.

Subrectangle blts to such surfaces.

All blts from such surfaces.

The only way to put data into such surfaces is with the IDirect3DDevice7::Load method (described in the Direct3D SDK documentation), or a full surface blt call.


Stencil Planes

Stencil planes enable and disable drawing on a per-pixel basis. They are typically used in multi-pass algorithms to achieve special effects, such as decals, outlining, shadows, and constructive solid geometry rendering.

Some hardware designed to accelerate Direct3D implements stencil planes. The special effects enabled by stencil planes are useful for entertainment applications.

Stencil planes are assumed to be embedded in the z-buffer data.

In DirectX 5.0, applications found the available z-buffer bit depths using the DDBD_Xx flags set in the dwDeviceZBufferBitDepth member of the D3DDEVICEDESC_V1 structure. To support z-buffers with stencil and z-buffer bit depths that cannot be represented using the existing DDBD_Xx flags, DirectX 6.0 and later versions have a new API entry point, IDirect3D7::EnumZBufferFormats (described in the Direct3D SDK documentation), which returns an array of DDPIXELFORMAT structures describing the possible z-buffer/stencil pixel formats. The DDPIXELFORMAT structure has been augmented to include three new z-buffer-related fields: dwStencilBitDepth, dwZBitMask, and dwStencilBitMask. A new flag, DDPF_STENCILBUFFER, indicates the presence of stencil bits within the z-buffer. The dwZBufferBitDepth member, which existed previously; gives the total number of z-buffer bits including the stencil bits. The new members of the DDPIXELFORMAT structure are as follows:

dwStencilBitDepth
Specifies the number of stencil bits (as an integer, not as a DDBD_Xx flag value).
dwZBitMask
Specifies which bits the z-value occupies. If nonzero, this mask means that the z-buffer is a standardized unsigned integer z-buffer format.
dwStencilBitMask
Specifies which bits the stencil value occupies.

DirectX 6.0 and later versions drivers should still set the appropriate DDBD_Xx flags in dwDeviceZBufferBitDepth for the z-only z-buffer formats they support. If stencil planes are not supported and the DDBD_Xx flags can represent all available z-buffer formats, then setting these flags is sufficient, because they are translated into DDPIXELFORMAT by IDirect3D7::EnumZBufferFormats. Otherwise, the Direct3D driver must respond to a DdGetDriverInfo query that uses the GUID_ZPixelFormats GUID by returning a buffer in which the first DWORD indicates the number of valid z-buffer DDPIXELFORMAT structures, followed by the DDPIXELFORMAT structures themselves.

See DDPIXELFORMAT in the DirectDraw DDK reference documentation for more information.

New render states associated with stencil planes are shown in the following table, which lists the render state, the type associated with the render state's value, and a description. See the DirectX SDK documentation for more details.

Render State | Type | Description
D3DRENDERSTATE_STENCILFUNC | D3DCMPFUNC | Comparison function. The test passes if the following expression is true: (ref & mask) OPERATION (stencil & mask) where ref is the reference value, stencil is the value in the stencil buffer, and mask is the value of D3DRENDERSTATE_STENCILMASK.
D3DRENDERSTATE_STENCILREF | DWORD | Reference value used in the stencil test.
D3DRENDERSTATE_STENCILMASK | DWORD | Mask value used in the stencil test.
D3DRENDERSTATE_STENCILWRITEMASK | DWORD | Write mask applied to any values written to the stencil buffer.
D3DRENDERSTATE_STENCILFAIL D3DRENDERSTATE_STENCILZFAIL D3DRENDERSTATE_STENCILPASS | D3DSTENCILOP | See the explanation in the following paragraph.

Three new render states, D3DRENDERSTATE_STENCILFAIL, D3DRENDERSTATE_STENCILZFAIL, and D3DRENDERSTATE_STENCILPASS, are defined, respectively, to inform the hardware about what to do when the stencil test fails, when the stencil test passes but the z-test fails, and when both the stencil and z-tests pass. The values of these new render states can be set to enumerators of the D3DSTENCILOP enumerated type.


Stencil Operation Codes

The D3DSTENCILOP enumerated type, described in the DirectX SDK documentation, contains members that are used to specify the desired stencil operation to be performed.


Guard Band Clipping

The driver signals that is supports guard band clipping when it fields the GUID_D3DExtendedCaps GUID in DdGetDriverInfo. A guard band is a rectangle that is potentially larger than the viewport (and even the render target), to which vertices can be clipped automatically by the driver. The Direct 3D clipping code clips to this rectangle instead of to the viewport. By allowing the driver to specify potentially large guard band rectangles, the need to generate new vertices due to clipping is reduced.

A reasonable real-world example is a hardware device that can correctly render as long as screen x and y coordinates fall in the range -2048 through 2047.

Guard band clipping is also beneficial for antialiasing hardware, because the filter area can extend outside the rendering surface extent. This reduces filtering errors that can be introduced if primitives are geometrically clipped to this extent.

To do the correct clipping, the driver is passed the viewport information. This specifies the actual viewport that the application requires the geometry to be clipped to. Driver writers who do not want to implement guard band clipping can ignore this information. It is recommended that drivers do not use this data to implement clipping through scissor or masking operations since these are likely to be slower than letting Direct3D do the clipping.


Extents Adjustment

Some hardware uses an antialiasing kernel that influences pixels outside the extents rectangle defined by the screen-space vertices. Applications that use the extents rectangle in the D3DCLIPSTATUS structure (defined in d3dtypes.h) for dirty rectangle processing might experience rendering artifacts because the extents rectangle does not cover the pixels modified by the hardware.

Direct3D addresses this problem by enabling hardware drivers to request that the extents rectangle be adjusted outward by a specified number of pixels in the dvExtentsAdjust member of the D3DHAL_D3DEXTENDEDCAPS structure. This member is filled in response to the GUID_D3DExtendedCaps GUID in DdGetDriverInfo. The extents rectangle is clipped to the extents of the render target surface for the device. The default is zero.


W-Buffering

Normally, z-buffering uses perspective-correct z for depth comparison and storage in the z-buffer, as this is the z that the rasterizer iterators must generate in order to maintain planar polygons. Some implementations can perform hidden surface elimination by filling the z-buffer with depth information expressed as w, or z relative to the eye. This is what is referred to as w-buffering in this documentation. This can be achieved by linearly interpolating the vertex 1/w term specified in the classic transformed and lit vertex structure (TLVERTEX - defined in the Direct3D SDK documentation), computing its reciprocal per pixel, and then using this w value for the depth comparison and conditionally storing it into the depth buffer.

Typically, the hardware stores a floating point value in the buffer. The following precision formats are common:

Size | Format
16 bits | 12.4
24 bits | IEEE single-precision float with no low byte of mantissa.
32 bits | Standard IEEE single-precision float.

Conventional z-buffering was developed for the technical markets that use CAD or authoring tools, in which the viewing volume/workspace is of known and limited extent. The range of depth values stored can therefore be of limited extent, allowing the ratio of far/near (the distances to the far and near clip planes) to be on the order of two to ten.

Typical hardware designed for such applications iterates perspective-correct z and stores it directly into the z-buffer. Due to the mathematics involved, this perspective-correct z is not distributed evenly within the z-buffer range. Using a far/near ratio of 100 results in 90 percent of the depth buffer range being used on the first 10 percent of the scene depth range. While this may be sufficient for tools, typical applications for entertainment or visual simulations with exterior scenes require far/near ratios of 1000 to 1 or 10000 to 1. At a ration of 1000 to 1, 98 percent of the range is used on the first two percent of the depth. This can cause hidden surface artifacts in distant objects, especially when using 16-bit depth buffers.

By contrast, when w (or eye-relative z) is used, the buffer bits can be more evenly allocated between the near and far clip planes in world space. The key benefit is that the ratio of far to near is no longer an issue, allowing applications to support a maximum range of miles, yet still get reasonably accurate depth buffering within inches of the eye point.


W-Buffering API

The D3DRENDERSTATE_ZENABLE render state supports three settings from the D3DZBUFFERTYPE enumerated type. See the DirectX SDK documentation for more details.

Value | Meaning
D3DZB_FALSE | Disables all depth buffering.
D3DZB_TRUE | Enables z-buffer using perspective correct z.
D3DZB_USEW | Disables z-buffering but enables w-buffering, which is eye-relative z.

Because the exact format used for storing w varies widely, it should be assumed to be opaque.

Surface allocations and depth-fill operations work identically when using w-buffering. All z-buffer compare modes work identically in either case.


W-Buffering DDI

The driver supports w-buffering by enabling the D3DPRASTERCAPS_WBUFFER cap in the dwRasterCaps member of the D3DPRIMCAPS structure. The D3DRENDERSTATE_ZENABLE render state is passed to the driver to enable or disable w-buffering or z-buffering.

The D3DHAL_DP2VIEWPORTINFO structure supports fields that correspond to world-space front and back clip planes (hither and yon respectively). This information can be used to adjust fog tables as well.


Bump Mapping

Bump mapping is an elegant technique that enables a surface to appear wrinkled or dimpled without the need to model these depressions geometrically.

Bump mapping in the usual sense involves perturbing the angles of the surface normals according to information given in a two-dimensional "bump map." This tricks the local reflection model, where intensity is mainly a function of the surface normal, into producing local variations on a smooth surface. This deception is evident only when silhouetted, because in that case the perturbations are no longer visible at the edges. That is, the silhouette follows the line of the model and is therefore not perturbed. This is an important technique because it appears to add texture to a surface, rather than modulating the color of a flat surface.

Because bump mapping for Direct3D is done by texturing a surface in the rendering phase without perturbing the geometry, it bypasses serious modeling problems that would otherwise occur. If the object is polygonal, the mesh has to be fine enough to receive the perturbations from the texture map. This is a serious drawback, if the texture is to be an option.

Bump mapping is perturbed environment mapping that allows an arbitrary number, shape, and color of lights to be specified. DirectDraw specifies new pixel formats for bumps: DDPF_DU and DDPF_UV. These are integrated with multitexture blending through the D3DTEXTURESTAGESTATETYPE enumerated type, described in the DirectX SDK documentation. Environment mapping can be done by the application.

Bump mapping in this case is more accurately described as per-pixel texture coordinate perturbation by rasterizers for diffuse and specular environment maps. This capability is integrated with Direct3D multitexture support. Bump mapping is performed in the local surface coordinate system (texture coordinates (u, v)).

This technique allows the lighting environment of the scene to be represented in an image environment map (either for diffuse or specular effects). It permits the lights to be of any number, shape, color, or intensity distribution that can be represented in such a map. These maps can be created in advance for static cases, or easily updated on the fly for changing light sources, using blts.

Conventional bump mapping schemes derived from Phong shading are limited to spherical light sources of constant color and fixed fall-off curve. These do not require the additional texture addressing capabilities of per-pixel environment mapping and can work well for diffuse lighting effects, but cannot produce the visually structured specular highlights required for photorealism. In the future, use of such techniques will be facilitated by the integration of environment mapping calculations directly into the Direct3D geometry pipeline.

Bump mapping is commonly provided in photorealistic renderers. It can be used to drastically increase surface detail effects, without tessellating the surface into large numbers of small triangles. When used with specular effects, bump maps can simulate reflective yet rough surfaces, such as wet stone or pavement. When supported by 3D accelerators, such effects can be performed in real time, allowing dynamic light source changes. Direct3D's support of bump mapping eliminates one of the few remaining barriers to representing surfaces and environments with photorealistic quality.

When a DirectDrawSurface object is created with a bump-map format, that texture is considered to be a bump map. This object can be bound into the Direct3D device using any of the textures bound to the texture stages. A programmed texture blending stage can be set to perform the bump map operation by setting D3DTOP_BUMPENVMAP. The texture defined for this stage is a DirectDrawSurface object with a bump-map format. It uses the texture coordinates of the flexible vertex format specified by this stage's texture coordinate identifier to position itself on the rendered objects. It also respects the specified texture stage's controlling filtering, wrapping, and so on.

The bump values in this texture perturbs the texture coordinates used by the immediately following texture, which should be considered a specular or diffuse environment map.

Emulation

This methodology can be emulated on any hardware that supports an 8-bit paletted texture mode. The restriction is that the environment map used (the texture immediately following the bump texture map) must have a resolution of exactly 16X16 texels, and no filtering. This is indicated by the D3DTEXOPCAPS_MAXBUMPENVMAP16X16 flag. Other parts will have no limits on the size of the environment map that the bump map can perturb.

More general methods for bump-mapped environment mapping will be supported in future versions of DirectX, when additional information, such as normal vector data, is provided in the DDI.

Bump mapping is enabled with the multitexture blending operations D3DTOP_BUMPENVMAP and D3DTOP_BUMPENVMAPPREMODULATE. The latter operation is a combination of bump mapping and gloss mapping that allows the specular reflection intensity to be encoded in the same surface as the bump map data.

There are now four additional texture states provided at each stage:

D3DTS_BUMPENVMAT00

D3DTS_BUMPENVMAT01

D3DTS_BUMPENVMAT10

D3DTS_BUMPENVMAT11


Hardware Transform and Lighting

Hardware acceleration of geometry operations, such as lighting and transformation, has been enabled with modifications to the D3dDrawPrimitives2 DDI for DirectX 7.0. At the API level, devices that support vertex operations in hardware will be enumerated separately from those that do rasterization only.

The existing caps structures have been extended to indicate features that may be present on a hardware-accelerated transform device. For example, the number of supported light sources is set with the dwNumLights member of the D3DLIGHTINGCAPS structure that is reported with the D3DDEVICEDESC_V1 structure.

Other flags of note are:

Flag | Meaning
D3DDEVCAPS_CANBLTSYSTONONLOCAL | The device supports a texture blt from system memory to non-local video memory.
D3DDEVCAPS_DRAWPRIMITIVES2EX | The driver is DirectX 7.0-compliant by supporting extended D3dDrawPrimitives2 capabilities.
D3DDEVCAPS_HWRASTERIZATION | The device has hardware acceleration for rasterization.
D3DDEVCAPS_HWTRANSFORMANDLIGHT | The device can support both hardware transform and lighting in hardware.
D3DDEVCAPS_SEPARATETEXTUREMEMORIES | The device is texturing from separate memory pools.
D3DTRANSFORMCAPS_CLIP | The hardware can clip while transforming.

Since the feature sets of hardware geometry accelerators may differ (such as the number of light sources supported), the caps structures indicate which subset of geometry operations this device performs. Zero is a valid value for the number of light sources supported, indicating that the hardware does transformations only.

Only vertices that include a vertex normal are properly lit; for vertices that do not contain a normal, a dot product of 0 is employed in all lighting calculations.

All the key state and data structures used by the software implementation of the geometry pipeline are made available at the DDI level. Some display cards will implement only lighting in hardware, and do transformation and clipping on the host processor.

The following render state types pertain only to devices that accelerate transform and lighting:

D3DRENDERSTATE_AMBIENT
D3DRENDERSTATE_AMBIENTMATERIALSOURCE
D3DRENDERSTATE_CLIPPING
D3DRENDERSTATE_CLIPPLANEENABLE
D3DRENDERSTATE_COLORVERTEX
D3DRENDERSTATE_DIFFUSEMATERIALSOURCE
D3DRENDERSTATE_EMISSIVEMATERIALSOURCE
D3DRENDERSTATE_EXTENTS
D3DRENDERSTATE_FOGVERTEXMODE
D3DRENDERSTATE_LIGHTING
D3DRENDERSTATE_LOCALVIEWER
D3DRENDERSTATE_NORMALIZENORMALS
D3DRENDERSTATE_SPECULARMATERIALSOURCE
D3DRENDERSTATE_VERTEXBLEND


Vertex Blending

Vertex blending operations are supported for DirectX 7.0. Vertex blending works in this way: an object from modeling space is multiplied by a 4X4 world matrix, placing the model's origin in a particular world space, relative to the origin of that world space. One part of the matrix does orientation and another part does the position. There can be up to three world matrices applied, allowing objects to be "bent" by blending the vertices with different weighting over the span of the object. A sample of a bending banana can be found in the Windows® DDK.

Next, the view matrix is applied, which effectively compresses the space relative to a particular viewpoint; much like a camera compresses the real world onto a two-dimensional picture.


Multimatrix Vertex Blending

Multimatrix vertex blending is a technique for rendering objects with smoothly blended skin joints. While this particular technique is not common in current software, some kind of smooth-skinning is currently used by most games involving animated characters.

There are a variety of geometry blending techniques. The technique described here is a form of geometry blending. This technique blends vertices across the joints of segmented articulated models, providing increased realism with reduced polygon count. As the joint changes in each frame, the geometry pipeline updates the positions of nearby vertices to smoothly blend between the segments at that joint. This capability can operate between segments that are related by joint types other than rotations, such as translations, scales, shears, or any combination that is representable by a 4X4 transformation matrix.

The general principle is to extend the typical segmented character by blending mesh vertices at joints.

Segmented models are considered to be built up from segments, or coordinate systems, each defined by a transformation matrix. Traditionally, each vertex of a mesh is considered to belong to only a single segment. This paradigm has been extended to allow vertices to have partial membership in other segments. Each vertex near the joint between two or more segments can have a skin weight Beta value, representing the proportion by which it actually belongs to the other segments.

When used in classic hierarchical modeling, the root segment gets no blending. It is always a rigid body since there is no other transform with which to blend. The skin weight Beta is defined as the proportion of the parent coordinate system that is to be used. This will be 0.0 over the entire object if it is entirely rigid-body (as is always the case for pre-DirectX 7.0 implementations).

The Beta will be 1.0 for those portions that are rigidly attached to the parent segment. This will drop as the proportion of the parent segment's contribution to the blend drops. There must be some set of points with 1.0 in them (and 0.0) in order to maintain geometric continuity between several segments.

Multimatrix vertex blending allows smooth skin blending to be performed by updating the position of each vertex, without requiring a separate 4X4 transform to be specified for each vertex. It addresses the common case of a continuous smooth surface and yet requires only one additional value —the skin weight Beta — per vertex, minimizing additional bandwidth requirements.

The specified vertex position data is transformed by all active world matrices, and the results are blended together using corresponding vertex weights.

The same steps are performed for any normal present in the vertex. This produces a single vertex (with position and normal) that is then fed into the rest of the pipeline for conventional lighting and clipping. See Multimatrix Vertex Blending Algorithm for more detail.

Characters can often contain the majority of the polygons in a scene, and are a key performance issue. Geometry pipelines that do not handle smooth-skinning well will have difficulty with a majority of the content.

Furthermore, the number of characters visible is one of the most highly variable components of the scene. This has serious impact on frame-rate leveling behavior. For interactive applications, level frame rate is more important than high average frame rate, making efficient character rendering a very critical feature.

Vertex blending must be performed after transformations. If blending is not integrated into the rendering pipeline, the transformations must be performed twice: once for skinning and once for rendering.

Integrating vertex blending into the geometry pipeline allows this case to be handled with a single traversal of the vertex data, which makes it just as fast as unblended vertices in bandwidth limited cases.


User Clip Planes

User-defined clip planes are enabled for DirectX 7.0. These work just like other clip planes but they are settable by the application. The driver must handle these planes by responding to the D3DDP2OP_SETCLIPPLANE operation code in D3dDrawPrimitives2.


Cube Environment Map Support

Multiple texture support in Direct3D allows the use of environment maps for lighting and reflections. However, single-map 360-degree solutions like circular or spherical maps aren't robust enough to be widely used in real time. The most suitable solution for real-time generation and addressing of a 360-degree environment is a cubical map, composed of six textures (faces). Each face can be generated by pointing a camera with a 90-degree field-of-view in the appropriate direction. Per-vertex vectors (normal, reflection, or refraction) are provided to the rasterization hardware that then iterates them across the polygon and calculates the intersections of the interpolated vectors with the faces of the cube map. If the application or API generates the cube environment map, the driver does not require the information about the transformation matrix or coordinate space in which the per-vertex vectors are defined. This is because the vectors are used only to address the environment map, which is logically in the same coordinate space.

Addressing of a circular map involves vector normalization; addressing of a spherical map requires the use of trigonometric functions. All types of single-map environments are nonlinear: a circular map is extremely distorted and anisotropic near its periphery, while a spherical map has large distortions near its poles. This makes it necessary to re-create the environment map every time the viewpoint changes in such a way that the central view area becomes distorted.

Cubical environment maps, formed by pointing a real or simulated camera with 90-degree field-of-view in six different directions, are free of these disadvantages. They can be generated faster but need to be updated less frequently, have fewer distortions, and can be addressed by using equations similar to the ones already used for perspective-correct texture mapping.

In general, cube maps are the best choice to provide real-time environment mapping for complex lighting and reflections. Several hardware vendors support, or have plans to support, cube maps in silicon. The most widely used approach is described in Siggraph 94 by D.Voorhies and J.Foran, pages 163-166.

The cube map enables are passed to the driver using the D3dDrawPrimitives2 render state mechanism. FVF texture coordinates are passed with FVF code 01 for that texture coordinate set.

The cube map is defined in world coordinates; that is, its world transform matrix is the identity matrix. The cube map can appear to be in a different space if texture transforms are used on the corresponding texture coordinate indexes. These texture coordinate indexes will be looking directly at face four, the +z face. Y is up by default. The origin of the (u,v) texel grid is at the upper left corner of each face, in order to allow creation of the face without any additional transformations by pointing camera from the center of the cube.

DirectDrawCreateEx (described in the DirectDraw SDK documentation) takes a flag that indicates a cube map is to be created. Some faces need not be allocated at the API level, although drivers may pad as required. The surface descriptor contains a bit field with six bits indicating the faces that the application expects to use. When faces are attained with the IDirectDrawSurface7::GetAttachedSurface method (described in the DirectDraw SDK documentation), the NULL faces will be skipped. The dimensions of each face are available from its surface descriptor, and the face bitcode field will indicate which face it is.

The pointer returned from DirectDrawCreate is actually a pointer to the first non-NULL face in the cube. The face identifier can be obtained by taking the surface's bitcode. This is the pointer that is passed to the IDirect3DDevice7::SetTexture method (described in the Direct3D SDK documentation) to make this map available in the multitexture pipeline.

If any of the surfaces are intended to be rendered to, the cube map must be created with the D3DPTEXTURECAPS_CUBEMAP cap flag set.

Any faces not created by the call are assumed to be filled with the color specified in the surface descriptor's dwEmptyFaceColor member. (See the DDSURFACEDESC2 structure.)

Current restrictions: All cube faces must be the same size and must be square. Cube face widths must be a power of two. The cube faces can be MIP mapped. No color keying is supported with cube map textures. As with other textures, alpha channels and alpha palettes are supported.


Integration of Environment Mapping with Standard Diffuse Lighting

Standard diffuse lighting calculations for Gouraud shading of diffuse components can be performed in the geometry pipeline. However, for best realism, the specular component could be generated by cube environment mapping. When both are in operation, the FVF specified by the application should contain one vector in the position for the lighting computation, and a separate 3D texture coordinate set for use as the vector into the cube map.


Vertex and Pixel Fogging

Fog has three main profile types: linear, exponential, and exponential squared. There are also two main implementation methods: vertex fog (also known as iterated or local fog) and pixel fog (also known as table or global fog).

In monochromatic (ramp) lighting mode, fog can work properly onlywhen the fog color is black. (If there is no lighting, any fog color will work since it is rendered as black.) Fog can be considered a measure of visibility — the lower the fog value, the greater the fog effect and the less visible the object will be.

The fog blending factor f is used in all fog calculations. It stands for the proportion of fog color versus object color. The final color is determined by the following formula:

Color = f * objColor + (1.0 - f) * fogColor

Therefore, a fog blending factor of 0.0 is full fog color and a fog blending factor of 1.0 is full object color. Typically, f decreases with distance.

Linear Fog

As the preceding figure shows, linear fog density increases in a linear fashion as the distance increases. This differs from exponential fog where the fog density increases exponentially. A linear fog profile might be set up as follows: the D3DRENDERSTATE_FOGSTART render state is set to ZFront and f = 1.0; the D3DRENDERSTATE_FOGEND render state is set to ZBack and f = 0.0. The D3DRENDERSTATE_FOGDENSITY render state is ignored.


Vertex Fog

Vertex fog is enabled using the D3DRENDERSTATE_FOGENABLE render state. Vertex fog can be made perspective-correct. For scenes with large polygons, vertex fog might not be the better choice, because the vertices are farther apart.

Vertex fog can be used in two ways:

  1. Make use of Direct3D lighting code using D3DVERTEX structures (described in the Direct3D SDK documentation) to define the fog blending factor.
  2. Make use of D3DLVERTEX or D3DTLVERTEX structures (both are described in the Direct3D SDK documentation). This is useful for doing custom fog effects such as layered fog, range-based fog, volume fog, and others.

When using fog with the D3DVERTEX structure, PRIMCAPS.dwRasterCaps has the D3DPRASTERCAPS_FOGVERTEX flag set. Individual calls to the IDirect3DDevice7::SetRenderState method (described in the Direct3D SDK documentation) are used to set D3DRENDERSTATE_FOGENABLE to TRUE, and D3DRENDERSTATE_FOGCOLOR to a 24-bit RGB color. For linear fog, the IDirect3DDevice7::SetRenderState method is used to set D3DRENDERSTATE_FOGSTART and D3DRENDERSTATE_FOGEND. For exponential and exponential squared fog, the D3DRENDERSTATE_FOGDENSITY render state is set with D3DLIGHTSTATETYPE, described in the Direct3D SDK documentation.

When using fog with the D3DTLVERTEX structure, the IDirect3DDevice7::SetRenderState method is used to set D3DRENDERSTATE_FOGENABLE to TRUE, set the color of the fog in D3DRENDERSTATE_FOGCOLOR, and set D3DRENDERSTATE_FOGTABLEMODE to D3DFOG_NONE (this is set in the D3DTLVERTEX structure itself). A fog blend factor f is defined at each vertex. This is the alpha component of the specular RGBA.

The following figure illustrates a sample relationship between altitude and fog density in a Layered Atmosphere Model.

Layered Atmosphere Model

The fog blending factor is calculated during the lighting phase and is placed in the alpha component of the specular color value in the vertex. This should then be interpolated according to the current shade mode set up by the D3DRENDERSTATE_SHADEMODE render state.

The fog blending factors for vertices v1, v2, and v3 are calculated by:

f1, f2, and f3 are interpolated across the triangle based on the current shade mode.

The new color, C, is obtained from the following formula:

C = (1 - f) * fog_color + f * src_color

In this formula,

  • f is the source, interpolated fog blending factor
  • fog_color is the current fog color (set by the render state D3DRENDERSTATE_FOGCOLOR)
  • src_color is the source, interpolated, textured color

If f, the fog blending factor, is 0.0, C will be set to a value identical to the fog color. If f is 1.0 there will be no fog effect.

Fog factor in a vertex is a function of the distance from the camera position to the vertex. This distance could be approximated by taking only Z value in camera space. For per-vertex fog we compute (Xc,Yc,Zc) in camera space by transforming the vertex using Mworld*Mview and then compute the distance to the vertex.

In RGB mode, fog factor f is scaled to be in the range 0 through 255, and is written to the alpha component of the specular output color.

In Ramp mode, diffuse and specular components are multiplied by the fog factor f and are clamped to be in the range 0.0 through 1.0.


Pixel Fog

Pixel fog is similar to vertex fog, but the fog blending factor, f, is calculated at rasterization time rather than at lighting time. Pixel fog is more accurate than vertex fog. The fog blending factor specified in the LVERTEX or D3DTLVERTEX structures (described in the Direct3D SDK documentation) is ignored. Pixel fog is limited to the three fog profile types (linear fog, exponential fog, and exponential squared fog). For pixel fog, the hardware does a table look-up on the depth value interpolated at each pixel. There is no need for 256 table entries if they are being interpolated linearly in-between. Future releases of DirectX may provide compensation for nonlinear z-distribution. ZFront and ZBack have values in the interval [0.0, 1.0]. Pixel fog is used by setting the PRIMCAPS.dwPRasterCaps to D3DPRASTERCAPS_FOGTABLE. The D3DDevice7::SetRenderState method sets the D3DRENDERSTATE_FOGENABLE render state to TRUE; the D3DRENDERSTATE_FOGCOLOR render state to 24-bit RGB; and the D3DRENDERSTATE_FOGTABLEMODE render state to one of D3DFOG_LINEAR, D3DFOG_EXP, or D3DFOG_EXP2. Here, the fog blending factor is calculated according to the three render states as follows:

fStart is determined by the render state D3DRENDERSTATE_FOGSTART and is in the interval [0.0, 1.0].

fEnd is determined by the render state D3DRENDERSTATE_FOGEND and is in the interval [0.0, 1.0].

fDensity is determined by the render state D3DRENDERSTATE_FOGDENSITY and is in the interval [0.0, 1.0].

The calculation of the fog blending factor f is based on z and the three fog render states just described. The actual calculation depends on the render state D3DRENDERSTATE_FOGTABLEMODE. Only D3DFOGMODE_LINEAR uses the fog start and end values.

  • D3DFOGMODE_NONE

    No pixel fog is applied.

  • D3DFOGMODE_LINEAR

    Linear fog growth.

  • D3DFOGMODE_EXP

    Exponential fog growth.

  • D3DFOGMODE_EXP2

    Exponential squared fog growth.

Typically exponential and exponential squared fog are too expensive to do directly. Instead, look-up tables are precalculated for a number of z values in the interval [0.0, 1.0] using the current fog density. The nearest table entry can then be used for the current z value, or an interpolating value between the two surrounding z values can be used to get the appropriate fog factor.

The final fogged color C is then calculated in the same manner as vertex fog as follows:

C = (1-f) * fog_color + f * src_color

In this formula,

  • f is the fog blending factor
  • fog_color is the current fog color (set by the render state D3DRENDERSTATE_FOGCOLOR)
  • src_color is the source, interpolated, textured color

If f, the fog blending factor, is 0.0, the final fogged color will be identical to the fog color. If f is 1.0, there will be no fog effect.


Range Based Fog

Fog can also be range-based. Range-based fog is useful because with normal z, or depth-based fog an object can appear at the side of the view, but then as the viewer rotates toward it, the object disappears back into the fog because its z-value changes. This is illustrated in the following figure. If fog is based on range instead of depth, it does not vary as the viewer rotates in place. This is compelling for flight simulators, tank games, and other applications where it is undesirable to have objects disappearing and reappearing in the distance as the viewer rotates. To set up fog to be range-based, D3DPRASTERCAPS_FOGRANGE and the D3DRENDERSTATE_RANGEFOGENABLE render state should be set. This render state works only with D3DVERTEX vertices. When the application specifies D3DLVERTEX or D3DTLVERTEX vertices, the F (fog) component of the RGBF fog value should already be corrected for range. The D3DVERTEX, D3DLVERTEX, and D3DTLVERTEX structures are defined in the Direct3D SDK documentation.

Range Based Fog

Note that if only fog within a specified range is visible, the viewer can rotate without objects coming in and out of the fog as with normal z or depth-based fog. That is, objects that were visible, remain visible, regardless of the rotation.


DirectX 7.0 Release Notes

The following topics contain update information for DirectX 7.0, concerning flexible vertex format (FVF), the rasterizer, and MIP Map surface creation:

FVF Update

Rasterizer Update

MIP Map Surface Creation Update


FVF Update

The FVF codes originally defined in DirectX 6.0 now support the specifications for texture coordinate sets in DirectX 7.0.

In addition to the normal 2D textures, supported in DirectX 6.0, DirectX 7.0 supports 1D, 3D, and 4D textures. In addition, the textures may be projected. The dwVertexType member of D3DHAL_DRAWPRIMITIVES2DATA can be examined when D3dDrawPrimitives2 is called, to determine the dimensionality of each texture coordinate set.

For example, if there is a vertex with five texture coordinate sets, each one of these textures can be 1D, 2D, 3D, or 4D and they may be projected textures. Each texture stage is independent, so the dimensionality can be different for each set of coordinates. The upper 16 bits of the FVF flag contained in dwVertexType can be examined to determine the dimensionality of the texture coordinates.

The texture coordinate count is a 4-bit field that can range from zero through eight. This gives the number of texture coordinate sets given in the upper 16 bits of the word. The upper 16 bits of the FVF code are allocated as two bits each for each of eight texture coordinate sets. The meaning of the texture coordinate bits is as follows:

Bit Pattern | Decimal Value | Meaning
00 | 0 | Two-dimensional texture coordinate pair, (u, v) as in DirectX 6.0
01 | 1 | Three-dimensional texture coordinate triple, (u, v, q)
10 | 2 | Four-dimensional texture coordinate quadruple, (u, v, w, q)
11 | 3 | One-dimensional texture coordinate, u

3D texture coordinate sets can be used for any of three different purposes: projected textures (signaled by D3DTTFF_PROJECTED - see D3DTEXTURETRANSFORMFLAGS in the DirectX SDK documentation), volume textures, or cube map vector textures, as determined by a set of render states analogous to the D3DRENDERSTATE_WRAP0 to D3DRENDERSTATE_WRAP7 modes that are already specified on a texture coordinate set basis.

The flags used with the D3DRENDERSTATE_WRAPn render states for 1D through 4D texture coordinates, respectively, are as follows: D3DWRAPCOORD_0 (same as D3DWRAP_U, which specifies wrapping in the u coordinate direction), D3DWRAPCOORD_1 (same as D3DWRAP_V, which specifies wrapping in the v coordinate direction), D3DWRAPCOORD_2 (specifies wrapping in the w coordinate direction), and D3DWRAPCOORD_3 (specifies wrapping in the q coordinate direction).

When projected textures are in use, they take the RHW value from the corresponding texture coordinate field, instead of from the position field. However, the position field's RHW is still used for both w-buffering and fog calculations, and therefore must be provided when either of these is in use.


Rasterizer Update

The reference rasterizer has been extracted into a separate DLL to enable additional WHQL tests to be added asynchronously of normal DirectX ship cycles (quarterly is typical). It has been updated to support any of the rasterizer-level operations added to the API either in the core or as extensions that require guaranteed consistency of implementation.

The production rasterizer may well not be updated to support these techniques, since environment mapping at the vertex level is likely to be faster than at the pixel level when running in software.

This rasterizer is likely to be upgraded in terms of performance on key cases that are identified.


MIP Map Surface Creation Update

Prior to DirectX 7.0, it was a safe assumption that the attachment chain for a MIP map consisted only of the sub-levels of that MIP map. With the advent of cubic environment maps, this is no longer the case. Each face of a cubic environment may itself be a MIP map and, as such, the attachment chain of a surface forming one face of a cubic environment map can consist of links to the other faces of the cube map as well as links to sub-levels of the MIP map. Care must therefore be taken when creating MIP map and cubic environment map surfaces.

As the attachment chain of a MIP map surface can now contain links to surfaces other than simply a lower level MIP map, a new capability bit has been introduced, DDSCAPS2_MIPMAPSUBLEVEL (see the DDSCAPS2 structure for this and the following flags). This bit is set for all but the top-level surface of a MIP map chain. Thus, given the top-level surface of a MIP map chain you can find the surface representing the next lowest level of the MIP map chain by traversing the attachment list of the top-level surface looking for a surface with the DDSCAPS2_MIPMAPSUBLEVEL capability bit set.

To determine if a surface is a face of a cubic environment map, check for the surface capability bit DDSCAPS2_CUBEMAP. If the DDSCAPS_MIPMAP capability bit is not set, the attachment list of this surface consists of the other faces of the cube map that are being created (check for the capability bits DDSCAPS2_CUBEMAP_POSITIVEX, DDSCAPS2_CUBEMAP_NEGATIVEX, DDSCAPS2_CUBEMAP_POSITIVEY, DDSCAPS2_CUBEMAP_NEGATIVEY, DDSCAPS2_CUBEMAP_POSITIVEZ, DDSCAPS2_CUBEMAP_NEGATIVEZ). If the DDSCAPS_MIPMAP capability bit is set then the attached surface list of the cube map surface consists of links to the other faces of the cube map as above but also to the next level of the MIP map for this face. The sub-level of the MIP map can be identified via the DDSCAPS2_MIPMAPSUBLEVEL bit described above.

D3DRENDERSTATE_MIPMAPLODBIAS

Although this render state is obsolete, its functionality has simply been moved into the texture stage states, that is, D3DRENDERSTATE_MIPMAPLODBIAS is exactly equivalent to the D3DTSS_MIPMAPLODBIAS enumerator in the D3DTEXTURESTAGESTATETYPE enumerated type for texture stage zero. On receiving the D3DRENDERSTATE_MIPMAPLODBIAS render state through a legacy interface, your driver should simply map this to the same code that handles D3DTSS_MIPMAPLODBIAS for texture stage zero.

The MIP map LOD bias is a floating-point value used to change the level of detail (LOD) bias. This value offsets the value of the MIP map level that is computed by trilinear texturing. It is usually in the range -1.0 to 1.0; the default value is 0.0. Current WHQL/DCT tests require the MIP map LOD bias to operate in the range -3.0 to 3.0.

Each unit bias (+/-1.0) biases the selection by exactly one MIP map level. A negative bias will cause the use of larger MIP map levels, resulting in a sharper but more aliased image. A positive bias will cause the use of smaller MIP map levels, resulting in a blurrier image. Applying a negative bias also results in the referencing of a smaller amount of texture data, which can boost performance on some systems.


DirectX 8.0 Release Notes

The following section contains update information for DirectX 8.0 and it focuses on those areas of the DDI that have been modified or extended for DirectX 8.0.


DIRECT3D_VERSION

A DirectX display driver must support legacy (DirectX 7.0 and earlier) versions of the DirectX runtime. In order to do that, it is necessary to include both old and new DirectX headers, for example d3d.h and d3d8.h. However, this can cause a problem with the definition of the preprocessor symbol DIRECT3D_VERSION. This preprocessor symbol is used in the header files to indicate which structures and functions should be included. If the DIRECT3D_VERSION has not already been defined, the DirectX header files will set the value of DIRECT3D_VERSION to the most recent version they were designed for. Thus, d3d.h sets DIRECT3D_VERSION to 0x0700 and d3d8.h sets DIRECT3D_VERSION to 0x0800. If d3d.h is included in your source before d3d8.h, new Direct3D 8.0 features will not be defined and compiler errors will result.

To avoid this, define DIRECT3D_VERSION to 0x0800 before including any header files. In order to get all the necessary symbols in header files, include d3d8.h before winddi.h or d3dnthal.h.


Minimal DirectX 8.0 DDI Support

DirectX 8.0 will provide hardware acceleration by DirectX 7.0 level drivers. However, for a driver to expose any of the new features of DirectX 8.0 such as multiple vertex streams, index buffers, or vertex and pixel shaders, it must identify itself by reporting DirectX 8.0 style capabilities and support the new D3dDrawPrimitives2 rendering tokens. In order to support the new D3dDrawPrimitives2 rendering tokens the driver is required to provide basic support for vertex streams and fixed function vertex shaders.

Reporting DirectX 8.0 style capabilities involves the following steps:

  • Handling the new GetDriverInfo2 variant of the existing DdGetDriverInfo entry point.
  • Returning a D3DCAPS8 structure containing the capabilities of the device when requested.
  • Ensuring that defined fields of that structure have certain minimum values.
  • Returning a texture format list that includes DirectX 8.0 style surface format descriptions.

These various requirements are discussed in the following sections.


Supporting GetDriverInfo2

The DirectX 8.0 DDI introduces a new mechanism for querying the driver for information. This mechanism extends the existing DdGetDriverInfo entry point to query for additional information from the driver. Currently, this mechanism is only used for querying for DX8 style D3D caps.

Note As you read the following you may be confused as to why the GetDriverInfo2 mechanism is necessary at all. It would seem preferable to simply define a new GetDriverInfo GUID that the driver would handle by returning a D3DCAP8 structure. GetDriverInfo2, introduced in the following paragraphs, is a mechanism to minimize the changes required to the Windows Operating Systems to enable DirectX 8.0 level functionality and thus make redistributing the DirectX 8.0 runtime practical.

This extension to GetDriverInfo takes the form of a DdGetDriverInfo call with GUID_GetDriverInfo2. When a DdGetDriverInfo call with that GUID is received by the driver, it must examine the data structure passed in the lpvData field of the DD_GETDRIVERINFODATA data structure to see what information is being requested. As described below, lpvData can point to either a DD_GETDRIVERINFO2DATA or DD_STEREOMODE structure.

The GUID_GetDriverInfo2 is the same GUID value as GUID_DDStereoMode. If your driver does not handle GUID_DDStereoMode, this is not an issue. However, if your DirectX 8.0 driver will handle GUID_DDStereoMode, please note that when a call to DdGetDriverInfo with the GUID_GetDriverInfo2(GUID_DDStereoMode) is made, the runtime sets the dwHeight field of the DD_STEREOMODE structure to the special value D3DGDI2_MAGIC. This field corresponds to the dwMagic field of the DD_GETDRIVERINFO2DATA structure. Therefore, by casting the lpvData pointer to either a pointer to a DD_STEREOMODE structure or a pointer to a DD_GETDRIVERINFO2DATA structure and checking the value of the corresponding field (dwHeight or dwMagic) for the value D3DGDI2_MAGIC, you can distinguish between a call to determine stereo mode capabilities or a request of Direct3D 8.0 capabilities.

Once the driver has determined that this is a call to GetDriverInfo2 it must then determine the type of information being requested by the runtime. This type is contained in the dwType field of the DD_GETDRIVERINFO2DATA data structure.

Finally, the driver copies the requested data into the supplied buffer. It is important to note that the lpvData field of the DD_GETDRIVERINFODATA data structure points to the buffer to which to copy the requested data. lpvData also points to the DD_GETDRIVERINFO2DATA structure. This means that the data returned by the driver will overwrite the DD_GETDRIVERINFO2DATA structure (and, therefore, that the DD_GETDRIVERINFO2DATA structure occupies the first few DWORDs of the buffer).

In order to be called with GetDriverInfo2, and report DirectX 8.0 capabilities, it is necessary for the driver to set the new flag DDHALINFO_GETDRIVERINFO2 in the dwFlags field of the DD_HALINFO structure returned by the driver. If this flag is not set, the runtime will not send GetDriverInfo2 calls to the driver and the driver will not be recognized as a DirectX 8.0 level driver.

The runtime uses GetDriverInfo2 with type D3DGDI2_TYPE_DXVERSION to notify the driver of the current DX runtime version being used by the application. The runtime provides a pointer to a DD_DXVERSION structure in the lpvData field of DD_GETDRIVERINFODATA.


Reporting DirectX 8.0 Style Direct3D Capabilities

In response to a GetDriverInfo2 query with type D3DGDI2_TYPE_GETD3DCAPS8, the driver should copy an initialized D3DCAPS8 structure into the lpvData field of the DD_GETDRIVERINFODATA structure. This structure is new for DirectX 8.0 and is used for both reporting capabilities from the driver to runtime and from the runtime to the application.

D3DCAPS8 has fields that describe both capabilities new to DirectX 8.0 and capabilities carried forward from DirectX 7.0. D3DCAPS8 is not a complete replacement for existing capabilities. Although this structure (along with information of supported surface formats) is a complete description of the device's capabilities from an API perspective it is not sufficient for the DDI. The runtime makes use of the DirectDraw capabilities reported by the driver for such information as supported surface capabilities (DDSCAPS) even though these are not exposed directly through the DirectX 8.0 API. Furthermore, the driver is required to continue to report legacy capability structures (such as D3DHAL_D3DEXTENDEDCAPS) as applications using legacy interfaces (DirectX 7.0 and earlier) will continue to request these capabilities. Therefore, reporting DirectX 8.0 style caps through D3DCAPS8 is an additional requirement, rather than a replacement for the existing capability reporting mechanisms. When DirectX 8.0 interfaces are used by the application the runtime will not query for extended D3D capabilities such as D3DHAL_D3DEXTENDEDCAPS if the driver reports DirectX 8.0 capabilities with D3DCAPS8.

D3DCAPS8 is described in the DirectX 8.0 SDK documentation. The driver should not initialize the DeviceType or AdapterOrdinal fields. These will be initialized to appropriate values by the runtime. The driver should simply set these fields to zero.


Minimum Capability Requirements for DirectX 8.0 Drivers

In addition to returning the D3DCAPS8 data structure in response to a GetDriverInfo2 query, the DirectX 8.0 runtime has other requirements that a driver must meet to be considered a DirectX 8.0 level driver.

A DirectX 8.0 driver must explicitly:

  • Report support for one or more vertex streams in the MaxStreams field of D3DCAPS8.
  • Report a maximum point sprite size of at least one in the MaxPointSize field of D3DCAPS8.
  • Modify its list of supported texture formats to support new style pixel format specifications.
  • Handle the new D3dDrawPrimitives2 (DP2) drawing tokens.
  • Handle D3dCreateSurfaceEx for vertex and index buffers even if your driver does not support video memory vertex buffer creation. Handles for system memory vertex and index buffers will be passed to the driver.
  • Set the new post-transformed clipping flag D3DPMISCCAPS_CLIPTLVERT if the hardware supports clipping of post-transformed vertex data.

It should be noted that a driver is not required to support any of the new features of DirectX 8.0 such as pixel or vertex shaders, volume textures, point sprites (beyond the non-zero maximum point size), multi-sampling or even multiple vertex streams (as the driver can set the maximum number of simultaneous vertex streams to one) in order to be considered a DirectX 8.0 driver.


Reporting Support for Video Memory Vertex and Index Buffers

DirectX 8.0 has added two new Direct3D capability flags that flag to the runtime whether the driver does or does not support video memory vertex and index buffers. Before these flags were created, the runtime could not determine whether the driver provided real support for video memory vertex buffers or not. Therefore, if a DirectX 8.0 exports the execute buffer (d3d buffer) creation and destruction driver entry points it should add one or both of the capability bits D3DDEVCAPS_HWVERTEXBUFFER and D3DDEVCAPS_HWINDEXBUFFER to the DevCaps field of the D3DCAPS8 structure reported via GetDriverInfo2 to the runtime. Set the flag D3DDEVCAPS_HWVERTEXBUFFER if your driver supports video or non-local video memory vertex buffers and D3DDEVCAPS_HWINDEXBUFFER if your driver supports video or non-local video memory index buffers.

The runtime masks these capability bits off before reporting capabilities to the application (they are not useful to applications only to the runtime itself). Therefore, these capabilities will not be visible to the DirectX Caps Viewer application even if your driver exports them.

Correct support for these capabilities will be part of WHQL certification testing.


The Texture Format List

Direct 8.0 introduces a new mechanism for describing pixel formats. In previous versions of DirectDraw and Direct3D pixel formats were described by a data structure (DDPIXELFORMAT) that contained information about the number of bits per color channel and bit masks for each color channel (along with flags and size field). Pixel formats in DirectX 8.0 are simple DWORDs that identify a particular pixel format and are compatible with FOURCC codes (Direct3D pixel formats are simply FOURCC codes with all but the least significant bytes being zero).

The DDPIXELFORMAT data structure is no longer exposed through API level interfaces. However, it is still used at the DDI level. Specifically, the driver still reports its supported texture formats through a texture format array that consists of surface descriptions with their embedded DDPIXELFORMAT data structures. However, the embedded pixel format structures can now be used to report new style pixel formats. To specify a new style pixel format using the DDPIXELFORMAT data structure, set the dwFlags field of the structure to the value DDPF_D3DFORMAT and store the new pixel format identifier in the dwFourCC field. In addition, certain other new fields have been added to DDPIXELFORMAT (the new fields have been added as members of unions with existing fields so the size of the data structure is the same). These fields include: dwOperations, dwPrivateFormatBitCount, and wFlipMSTypes and wBltMSTypes.

A DirectX 8.0 DDI compliant driver should continue to report DX7 style surface formats through the standard mechanisms, that is, the texture format list reported in the global driver data structure (D3DHAL_GLOBALDRIVERDATA) and the Z/Stencil list reported in response to a GUID_ZPixelFormats from DdGetDriverInfo. However, the driver should also report all of its supported surface formats through the new DirectX 8.0 DDI mechanism described below.

DirectX 8.0 DDI style surface formats are reported using GetDriverInfo2. Two GetDriverInfo2 query types are used by the runtime to query for surface formats from the driver. D3DGDI2_TYPE_GETFORMATCOUNT is used to request the number of DirectX 8.0 style surface formats supported by the driver. D3DGDI2_TYPE_GETFORMAT is used to query for a particular surface format from the driver.

To handle the D3DGDI2_TYPE_GETFORMATCOUNT, the driver must store the number of DirectX 8.0 DDI style surface formats that it supports in the dwFormatCount field of the DD_GETFORMATCOUNTDATA.

When the runtime has received the number of supported formats from the driver, it will then query for each surface format in turn with GetDriverInfo2 queries of type D3DGDI2_TYPE_GETFORMAT. The data structure pointed to by the lpvData field of the DD_GETDRIVERINFODATA data structure is, in this case, DD_GETFORMATDATA.

The DirectX 8.0 runtime scans the texture format list reported by the driver examining the dwFlags fields of each pixel format. If any of the texture formats have dwFlags set to DDPF_D3DFORMAT, then the runtime identifies this texture format list as DX8 style and filters all texture formats whose pixel format is not flagged as DDPF_D3DFORMAT. Furthermore, a DX7 runtime will filter any texture format that does have DDPF_D3DFORMAT set. Therefore, a driver supporting the DX8 DDI can return a texture format list that contains two entries for each supported format, one specified in the old style and one in the new. DX8 runtimes will use the formats specified in the new style and DX7 runtimes will use the formats specified in the old style.

All supported surface formats, such as textures, depth or stencil buffers, or render targets, should be reported through the GetDriverInfo2 mechanism. The runtime will ignore the texture and Z/Stencil formats returned through legacy mechanisms (D3DHAL_GLOBALDRIVERDATA and GUID_ZPixelFormats). No attempt will be made to map these formats to DX8 style formats for DirectX 8.0 drivers. However, legacy formats will be mapped to the new style for legacy, DirectX 7.0 or earlier drivers. Therefore, a driver must report all supported surface formats through the DirectX 8.0 DDI. Furthermore, as legacy runtimes will not map new style surface formats to old style formats it is essential that the driver continue to report DirectX 7.0 style surface and Z/Stencil formats through the legacy mechanism.


Format Operations

When reporting supported surface formats a DirectX 8.0 driver must also indicate which operations can be performed on surfaces of that format. The supported operations for a pixel format are reported through the dwOperations field of the DDPIXELFORMAT structure. The driver should set this field to the logical combination of all supported operations for surfaces of that format.


Surface Formats as FOURCC Codes

Three of the new surface formats defined by DirectX 8.0, D3DFMT_Q8W8V8U8, D3DFMT_V16U16 and D3DFMT_W11V11U10, are passed to the driver as FOURCC codes. This means the various bit depth and mask fields of the DDPIXELFORMAT data structure are not initialized and their values are undefined. Hence, a driver processing these three formats must not rely on the bit count or masks in the pixel format but must compute these as necessary. For example, when computing the pitch of a surface of one of these types the dwRGBBitCount field of the pixel format must not be used. All other formats other than YUV, DXT and IHV specific extension formats are mapped to the legacy DDPIXELFORMAT representation when passed to the driver and, hence, will have valid pixel formats and masks in the pixel format data structure.


Multiple Vertex Streams

DirectX 8.0 adds support for multiple vertex streams. Even if the driver and hardware combination does not support more than one stream of vertex data, the driver must still handle the stream binding DP2 tokens (D3DDP2OP_SETSTREAMSOURCE and D3DDP2OP_SETSTREAMSOURCEUM) and the new vertex stream based DP2 drawing tokens (see New DP2 Stream Drawing Tokens). These are the mechanisms for passing vertex data to the driver in drawing for DirectX 8.0 level drivers.


Reporting Multiple Vertex Stream Capability

A driver reports the ability to support multiple vertex streams by setting the value of the MaxStreams field of the D3DCAPS8 structure. A driver that supports multiple vertex streams should specify a value greater than one. A DX8 level driver that does not support multiple vertex streams should set MaxStreams to one. No DX8 level driver should specify a value of zero for this field. The driver should also set the MaxStreamStride field to the maximum supported stride (in bytes) between vertex elements in a vertex stream.


Stream Zero

Vertex stream zero is treated differently from the other streams (by virtue of the fact that it was the only stream supported by prior versions of Direct3D). Vertex buffers that have a flexible vertex format (FVF), where the FVF field is non-zero, can only be bound to stream zero. However, this does not imply that the vertex buffer bound to stream zero will always have a flexible vertex format.

Stream zero is also the implied vertex source when one of the special, fixed-function vertex shaders is the current vertex shader handle.


Notification of Stream / Vertex Buffer Binding

Previous Next

Notification of Stream and Vertex Buffer Binding

A driver is notified of the binding of a vertex buffer to a particular stream through a new DP2 token, D3DDP2OP_SETSTREAMSOURCE, and its associated HAL data structure, D3DHAL_DP2SETSTREAMSOURCE.


Index Buffers

DirectX 8.0 introduces the concept of index buffers. These buffers are very similar to vertex buffers but store simple 16 or 32-bit indices into vertex data rather than the vertex data itself. Index buffers extend all the benefits of vertex buffers, for example optimal download and caching, to index data.

Index buffers are created, locked, unlocked and destroyed with the same driver entry points as those used for vertex buffers. A driver can distinguish between these buffer types using the new surface capability bit DDSCAPS2_INDEXBUFFER. For index buffers, this flag will be set in the ddsCapsEx.dwCaps2 field of the surface's DD_SURFACE_MORE structure. It will be clear for vertex buffers.

Unlike many other surface types, a driver does not need to set the capability DDSCAPS2_INDEXBUFFER when reporting its capabilities to the runtime in order to receive driver calls for index buffer creation, destruction, and locking. A DirectX 8.0 driver that supports vertex buffers is assumed to support index buffers also. If the underlying hardware has no direct support for index buffers then the driver should handle index buffer creation by allocating system memory for the surface.


Reporting Support for 32-bit Indices

Prior to DirectX 8.0 vertex indices were restricted to 16-bit quantities. DirectX 8.0 adds support for 32-bit indices. A driver reports support for 32-bit indices by setting the value of the MaxVertexIndex field of D3DCAPS8 (currently also in D3DHAL_D3DEXTENDEDCAPS) to a value greater than 0xFFFF. This field also allows the driver to report that although it supports indices requiring 32-bits of storage it does not support the full range of 32-bit values.


Setting the Current Index Buffer

As with vertex data, the index buffer to be used by drawing primitives is no longer part of the data passed to the driver with the primitive, but rather is driver state. The current index buffer is set by a new DP2 token, D3DDP2OP_SETINDICES. This token established the index buffer with the given handle as the current index buffer to use when drawing indexed primitives until a new index buffer is set or the current index buffer is cleared (an index buffer handle of zero is specified in the DP2 token data).


New DP2 Stream Drawing Tokens

DirectX 8.0's support for multiple streams of vertex data requires that new DP2 drawing tokens be introduced. These new tokens are necessary because existing drawing tokens assumed that there was a single pointer to vertex data for a particular drawing instruction. With multiple streams, this is no longer the case. A drawing command may well access multiple vertex data buffers simultaneously through streams.

It is important to note that these drawing tokens replace the existing primitive type specific tokens (for example, D3DDP2OP_POINTS, D3DDP2OP_TRIANGLELIST, D3DDP2OP_TRIANGLESTRIP) for calls through the new DirectX 8.0 interfaces only. Calls made through DX7 our earlier interfaces will still be passed through the DDI as the old style drawing tokens. Therefore, a DX8 driver is required to support both old and new style drawing tokens.

The indexed and non-indexed drawing tokens have two variants. For example, non-indexed drawing is accomplished by the tokens D3DDP2OP_DRAWPRIMITIVE and D3DDP2OP_DRAWPRIMITIVE2. Similarly, indexed drawing is accomplished by the tokens D3DDP2OP_DRAWINDEXEDPRIMITIVE and D3DDP2OP_DRAWINDEXEDPRIMITIVE2.

The main distinction between the two variants is that D3DDP2OP_DRAWPRIMITIVE2 and D3DDP2OP_DRAWINDEXEDPRIMITIVE2 are used when the vertex data has been transformed by the runtime. This can be the case either because the driver/hardware combination does not support hardware vertex processing or the software vertex processing has been explicitly selected. For these tokens, only stream zero is used and it contains transformed and lit vertices.

D3DDP2OP_DRAWPRIMITIVE and D3DDP2OP_DRAWINDEXEDPRIMITIVE are used then the runtime has not processed the vertex data. Thus, these tokens can supply untransformed vertex data when the hardware supports hardware vertex processing or transformed vertex data when the application supplies transformed data direct to the runtime. In this case any number of streams (up to MaxStreams) can be active. These variants (along with the other new drawing token, D3DDP2OP_CLIPPEDTRIANGLEFAN) enable optimal code paths in the runtime and the distinctions beyond those described here are not significant to the driver.


Copying Vertex and Index Buffers in the DP2 Stream

A new DP2 token, D3DDP2OP_BUFFERBLT, has been added to support optimal copying and updating of index and vertex buffers. This token is very similar to the existing D3DDP2OP_TEXBLT that copies and updates textures but has been modified to support sub-buffer copying rather than simple rectangles.


Point Sprites

DirectX 8.0 introduces support for point sprites. A point sprite is an extension to basic point rendering that allows the size of the point to be specified, either by a render state or by a vertex component. When accelerated, the point sprites will be rendered in hardware as a screen space quadrilateral formed of two triangles, and render states such as textures and blending will be used.


Reporting Support for Point Sprites

A driver notifies the runtime of its support for point sprites by setting the MaxPointSize field of the D3DCAPS8 structure to a floating point number greater than one (reporting a value of one is part of the requirement to indicate a DX8 level HAL). This value specifies the maximum point width and height in render target pixels. Devices that do not support point sprites can set this value to 1.0.

The size of a point sprite can be specified either by a new per-vertex element or by a new render state. If the driver and hardware combination supports the interleaving of point size information with other vertex data (rather than simply through the point size render state D3DRS_POINTSIZE), it should set the D3DFVFCAPS_PSIZE flag in the FVFCaps field of the D3DCAPS8 structure.

The absence of D3DFVFCAPS_PSIZE indicates that the device does not support D3DFVF_PSIZE (per-vertex point size) for pre-transformed vertices (and thus the base point size will always come from D3DRS_POINTSIZE). D3DFVF_PSIZE is always supported for post-transformed vertices.

The implication of this is that DX8 drivers for which the D3DFVFCAPS_PSIZE bit is not set are still required to accept D3DFVF_PSIZE for post-transformed vertices. This ability will not be emulated in the DirectX 8.0 runtime; however, the DirectX 8.1 runtime can emulate this ability. The driver must always gracefully ignore any point size data passed through the FVF. Note that the D3DUSAGE_POINTS bit is required to be set for vertex buffers that are to be used for rendering point sprites, so the driver can avoid allocating these vertex buffers in memory types that are slow for reads into the CPU.

Point sprites present a challenge when user clip planes are being used. It is possible that a particular hardware implementation of point sprites will clip only the actual vertex position of the point sprite against the user clip plane, rather than the expanded quad actually rendered. If the driver and hardware combination can support clipping of point sprites by their actual computed size rather than simple vertex position then the D3DPMISCCAPS_CLIPPLANESCALEDPOINTS capability bit should be set in the PrimitiveMiscCaps field of D3DCAPS8.

DX8 drivers that perform transform and lighting (that is, offer hardware vertex processing) are entirely responsible for a correct point sprite implementation. No emulation will be performed by the DirectX 8.0 runtime. This means that even if the hardware is used with software vertex processing, point sprites are the DX8 driver's responsibility. However, in DirectX 8.1 and later, if the hardware is used with software vertex processing, the runtime can provide emulation.


Computing the Size of Point Sprites

Point sprites are rendered using the existing D3DPT_POINT primitive type. The size of point sprites can be controlled either through the new render state D3DRS_POINTSIZE or by the new FVF component D3DFVF_PSIZE.

For vertices without the D3DFVF_PSIZE vertex component the current value of the D3DRS_POINTSIZE render state should be used. Otherwise, the value specified in the vertex data should be used. In either case, the value is a floating-point number that is the size (width and height) of the rendered quad in rendering target pixels. The default value of the point size render state (1.0) is sent to the driver during initialization.

Two render states control clamping of the computed point sprite size, D3DRS_POINTSIZE_MIN and D3DRS_POINTSIZE_MAX. The computed size of the point should be clamped to be no smaller than the size given by D3DRS_POINTSIZE_MIN and no larger than the size given by D3DRS_POINTSIZE_MAX. It is the driver's responsibility to ensure that the point sprite size is clamped to the minimum and maximum sizes specified by the render states.

For drivers that support hardware vertex processing the size of point sprites may also be scaled based on the distance from the point to the eye (in eye space). Scaling of the point sprites is enabled by the new render state D3DRS_POINTSCALEENABLE. If the value of this render state is TRUE then the points are scaled according to the following formula. Note that in this case the application-specified point size is expressed in camera space units. This scaling is performed by drivers that support transform and lighting only.

Si
Input point size (either per-vertex or D3DRS_POINTSIZE)
A,B,C
Point scale factors D3DRS_POINTSCALEA/B/C
Vh
Height of viewport (dwHeight field in D3D_VIEWPORT)
Pe = (Xe, Ye, Ze)
Eye space position of point
De = sqrt (Xe2 + Ye2 + Ze2)
Distance from eye to position (eye at origin)
Ss = Vh * Si * sqrt(1/(A + B*De + C*(De2)))
Screen space point size
Smax
MaxPointSize device capability
Smin
D3DRS_POINTSIZE_MIN
Final screen-space point size S =
Smax if Ss > Smax

Smin if Ss < Smin

Ss otherwise

Note that for the application to be drawing single pixel vertices, rather than point sprites, it must have the following render states set:

SetRenderState (D3DRS_POINTSCALEENABLE, FALSE)
// All textures must be turned off.
SetTexture (0, NULL);
SetTextureStageState(1, D3DTSS_COLOROP,  D3DTOP_DISABLE);
// The point size render state must be set to any value between 0.0-1.0
SetRenderState(D3DRS_POINTSIZE, 1.0);
// D3DRS_POINTSIZE_MIN and D3DRS_POINTSIZE_MAX
// must be set appropriately to allow
// D3DRS_POINTSIZE to be set to a value between 0.0-1.0


Rendering Point Sprites

A screen space point P = (X, Y, Z, W) of screen-space size S is rasterized as a quadrilateral with the following 4 vertices:

(X–S/2, Y–S/2, Z, W)
(X+S/2, Y–S/2, Z, W)
(X–S/2, Y+S/2, Z, W)
(X+S/2, Y+S/2, Z, W)

The vertex color attributes are duplicated at each of the 4 vertices, therefore each point is always rendered with constant colors.

The assignment of texture indices is controlled by the D3DRS_POINTSPRITEENABLE setting. If D3DRS_POINTSPRITEENABLE is set to FALSE, then the texture coordinates of the vertex are duplicated at each of the 4 vertices. If no texture coordinates are present in the vertex the default values of (0.0f, 0.0f, 0.0f, 1.0f) are used for the corners of the point sprite. If the D3DRS_POINTSPRITEENABLE is set to TRUE, then the texture coordinates at the 4 vertices, starting from the top left corner and winding clockwise, are set to:

(0.0f, 0.0f)
(1.0f, 0.0f)
(0.0f, 1.0f)
(1.0f, 1.0f)

When clipping is enabled, points are clipped as follows. If the vertex is outside the view frustum in Z (either near or far), then the point is not rendered. If the point, taking into account the point size, is totally outside the viewport in x or y, then the point is not rendered. Remaining points are rendered. Note that it is possible for the point position to be outside the viewport (in x or y) and still be partially visible.

Points may or may not be correctly clipped to user-defined clip planes. If D3DDEVCAPS_CLIPPLANESCALEDPOINTS is not set, then points are clipped to user-defined clip planes based only on the vertex position, ignoring the point size. In this case, scaled points will be fully rendered when the vertex position is inside the clip planes, and discarded when the vertex position is outside a clip plane. Applications may prevent potential 'popping' artifacts by adding a border geometry to clip planes that is as large as the maximum point size.

If the D3DDEVCAPS_CLIPPLANESCALEDPOINTS bit is set, then the scaled points are correctly clipped to user-defined clip planes.

It is important to remember that point sprites should have no dependencies on the culling or fill modes. Point sprites should always be rendered regardless of the cull or fill mode.

Also it is important that in point fill mode with flat shading that the rules for flat shading a primitive are complied with. This means that the first vertex of a primitive dictates the color of that primitive and hence the color for each vertex of the primitive. This is not what occurs with the current version of the reference rasterizer or the sample driver (version 8.0) and will be fixed in later versions.


Volume Textures

DirectX 8.0 adds support for volume or 3D textures. Such textures have depth in addition to width and height.


Reporting Support for Volume Textures

DirectX 8.0 introduces two new primitive texture capabilities flags that the driver sets to indicate support for volume textures. These flags are D3DPTEXTURECAPS_VOLUMEMAP and D3DPTEXTURECAPS_MIPVOLUMEMAP. D3DPTEXTURECAPS_VOLUMEMAP should be set in the dwTextureCaps field of the D3DPRIMCAPS8 structure (part of D3DCAPS8) if the hardware has support for volume textures. D3DPTEXTURECAPS_MIPVOLUMEMAP indicates that the driver supports MIP mapped volume textures.

It is a requirement that hardware that supports volume textures supports the use of volume textures in multi-texturing scenarios (in combination with other volume textures or 2D textures). If this scenario is not supported by the hardware, the driver cannot set D3DPTEXTURECAPS_VOLUMEMAP.

The driver can indicate that it requires the dimensions of the volume texture to be a power of 2 by setting the primitive texture capability D3DPTEXTURECAPS_VOLUMEMAP_POW2.

A driver that supports volume textures is also required to specify the minimum and maximum volume texture dimensions it supports. The field MaxVolumeExtent should be set to the maximum supported dimensions of the volume texture. It is a requirement that the same constraint applies to all three dimensions of the volume texture (width, height and depth).

A driver notifies the runtime of the volume texture filtering and texture addressing modes supported by the hardware by setting the VolumeTextureFilterCaps and VolumeTextureAddressCaps to the appropriate combinations of flags.

Finally, the driver notifies the runtime about what surface formats can be used with volume textures by setting the D3DFORMAT_OP_VOLUMETEXTURE in the dwOperations field of the surface format's DDPIXELFORMAT.


Handling the Creation of Volume Textures

DirectX 8.0 introduces a new surface capability bit DDSCAPS2_VOLUME. This flag will be set in the ddsCapsEx.dwCaps2 field of the surface's DD_SURFACE_MORE structure. In the DdCreateSurface and D3dCreateSurfaceEx callbacks the depth of the volume texture can be found in the low word of the dwCaps4 field of the extended surface capabilities (ddsCapsEx) of the surface's DD_SURFACE_MORE structure. The driver should return the "slice pitch" (that is, the number of bytes to add to move from one 2D slice of the volume to the next) of the volume texture in the dwBlockSizeY field of the surface global structure.


Locking a Subvolume of a Volume Texture

DirectX 8.1 introduces a new feature that lets a driver lock just a subvolume of a volume texture. When a driver's DdLock function is called, the driver can improve system performance by locking just a subvolume instead of the whole volume texture.

To indicate support of this feature, the driver must set the D3DDEVCAPS_SUBVOLUMELOCK bit in the DevCaps member of the D3DCAPS8 structure. The driver returns a D3DCAPS8 structure in response to a GetDriverInfo2 query as described in Reporting DirectX 8.0 Style Direct3D Capabilities. Support of this query is described in Supporting GetDriverInfo2.

After support of this feature is determined, the driver can receive a DdLock call with the DDLOCK_HASVOLUMETEXTUREBOXRECT bit set in the dwFlags member of the passed DD_LOCKDATA structure. This bit informs the driver to lock down the specified subvolume texture. The driver must then obtain the front and back coordinates of the locked subvolume from the left and right members of the RECTL structure that is specified in the rArea member of DD_LOCKDATA. The driver obtains the front and back coordinates from the higher 16 bits of the left and right members respectively. The left and right coordinates of the locked subvolume are constrained to the lower 16 bits of the left and right members. The driver uses the top and bottom members of the RECTL structure in rArea unchanged to specify the top and bottom coordinates of the locked subvolume. In this way, the rArea member effectively provides three coordinate sets to specify the locked subvolume. The RECTL structure is described in the Platform SDK documentation.

The following code shows how to obtain the front and back coordinates:

"real" left = rArea.left && 0xFFFF;
"real" right = rArea.right && 0xFFFF;
front = rArea.left >> 16;
back = rArea.right >> 16;

This feature is available on Windows Me and Windows XP and later versions. This feature is also available on Windows 2000 and Windows 98 operating system versions that have the DirectX 8.1 runtime installed on them.


Presentation

DirectX 8.0 formalizes the concept of "presentation" (or making the results of rendering visible to the user) in the API. Previously, this was accomplished either by page flipping in full screen mode or by blitting in windowed mode. The new Present API abstracts the differences of fullscreen and windowed mode away. However, this abstraction is not yet exposed at the DDI level. The runtime simply maps the present API to either the DdFlip or DdBlt DDI entry points depending on the application mode.

DirectX 8.0 has added two new DirectDraw blt flags that are passed to the driver as notification of when a blt operation is actually part of a Present and therefore marks a frame boundary. These new flags are DDBLT_PRESENTATION and DDBLT_LAST_PRESENTATION. Two flags are necessary because clipping may result in a single Present call invoking multiple blt operations in the driver. In this case, all of the blts that are invoked as a result of the Present operation have the DDBLT_PRESENTATION flag set. However, only the final blt of the sequence used to perform the Present will have the DDBLT_LAST_PRESENTATION bit set. Therefore, if blt is used to implement a Present call, the driver will see zero or more blts with the DDBLT_PRESENTATION bit set followed by exactly one blt with both the DDLT_PRESENTATION and DDBLT_LAST_PRESENTATION bits set. These flags are never set by the application. Only the runtime is allowed to pass these flags to a blt. In addition, these flags will only be passed to drivers supporting the DirectX 8.0 DDI.

The driver is only permitted to queue a maximum of three frames. If the driver sees a blt call with DDBLT_PRESENTATION set and it already has three DDBLT_LAST_PRESENTATION blts queued it must fail the call with DDERR_WASSTILLDRAWING. The runtime will retry until the queue has drained sufficiently.

If the driver can't effectively determine when a DDBLT_LAST_PRESENTATION blt in the queue has been retired, then the must not queue frames at all. DDBLT_LAST_PRESENTATION should cause such drivers to return DDERR_WASSTILLDRAWING until the accelerator is completely finished, exactly as if the application had called Lock on the source surface before calling Blt.

Finally, in the case of multiple windowed applications running simultaneously, the driver should count presentation blts based on the source of each blt, rather than the primary, that is, the driver is allowed to queue three frames per window/render target. This will result in better performance in this case.


New DDSCAPS2 Flags

A new flag, DDSCAPS2_DISCARDBACKBUFFER, has been introduced to indicate that preservation of the back buffer is not required. It will be set on the primary surface and the back buffers if the application has set D3DSWAPEFFECT_DISCARD on the Present API.

DX8 runtimes now set another new flag, DDSCAPS2_NOTUSERLOCKABLE, on the primary and the back buffers if the flipping chain is not lockable, or on any render target that is not lockable. This allows drivers to do behind the scenes optimization. Note that it is still possible to lock the surfaces so the driver will need to handle these cases, but such locks will be very infrequent and are not expected to be fast.

The driver can also determine whether the depth/stencil buffer is lockable by the presence of the DDSCAPS2_NOTUSERLOCKABLE flag.


Present and GetBltStatus

For DX8 the runtime no longer calls DdGetBltStatus on blts involving system memory surfaces. This was always the behavior on Windows® 2000 and is now the behavior on Windows 98/Me also. The result is that asynchronous DMA to or from system memory surfaces is no longer possible (see Asynchronous DMA Support in DirectDraw for details). DX8 drivers should not page lock system memory surfaces by themselves, and system memory to video memory transfers should be synchronous.


Palettized Textures

Although API support for palettized textures has been completely overhauled for DirectX 8.0, this is not reflected in the DDI. The existing palette oriented DP2 tokens continue to be used to notify the driver of the binding between a palette and a texture and of updates to palettes.

It cannot be assumed that, because an association between a surface and a palette has been established with D3DDP2OP_SETPALETTE, the lpPalette field of the surface structure points to a valid palette. The association between a palette and a surface established by the DP2 stream will not be reflected in the actual surface and palette data structures.

Furthermore, DirectDraw's palette DDI entry points will not be called for these palettes. All DDI notifications of texture palette operations are done through the DP2 stream.


Cursors

DirectX 8.0 has added an API to support high update frequency cursors without requiring API level direct access to the primary surface. For DirectX 8.0, the cursor is the standard GDI cursor if capabilities permit, or else it is emulated with DirectDraw blts. To support the DirectX cursor API, the driver has to return capability information in D3DCAPS8.

The CursorCaps field should be set to D3DCURSORCAPS_MONO, D3DCURSORCAPS_COLOR, or both to indicate support for monochrome and color hardware cursors. The MaxCursorEdgeSize field should be set to the minimum of the maximum width and maximum height of the hardware cursor (or zero if no hardware cursor is supported). It is not possible to express different maximum sizes for the width and height of the cursor.


Vertex Shaders

All drivers that support the DirectX 8.0 DDI must support the new DP2 token D3DDP2OP_SETVERTEXSHADER even if programmable vertex shaders are not supported in hardware. This is because D3DDP2OP_SETVERTEXSHADER is the mechanism by which the FVF of incoming vertex data is communicated to the driver when using fixed function as well as programmable vertex processing.

D3DDP2OP_SETVERTEXSHADER can be used to notify the driver of either the handle of the current programmable vertex shader to use or the FVF of the vertex data for fixed function vertex processing due to the nature of the handle name space for vertex shaders. The vertex shader handle name space includes all vertex FVF codes. Thus, a vertex shader handle can refer either to a programmable vertex shader handle previously created by means of the D3DDP2OP_CREATEVERTEXSHADER DP2 token, or to the FVF code of a vertex format to be processed by fixed function vertex processing.

Therefore the driver for hardware that does not support programmable vertex processing should process D3DDP2OP_SETVERTEXSHADER to determine the FVF (and hence the processing to be performed) on the vertex data bound to stream zero. This is particularly important when processing user memory (UM) primitives. In this case, the only way of determining the FVF of the supplied vertex data is through the D3DDP2OP_SETVERTEXSHADER token. The test to determine whether a handle is a vertex shader handle or a legacy FVF code is simple. If the least significant bit of the handle is set (1) then the handle is vertex shader handler. If the least significant bit is clear (0) the handle is a legacy FVF code.

If the FVF code of a vertex buffer conflicts with that specified by D3DDP2OP_SETVERTEXSHADER the driver should ignore the FVF code of the vertex buffer and continue.

The DirectX runtime guarantees that only FVF codes will be passed as vertex shader handles to a driver that does not support programmable vertex processing. However, such a driver should have debug code to verify that the FVF code that is passed is supported.


Reporting Support for Programmable Vertex Processing Hardware

For a DirectX 8.0 level driver to report support for programmable vertex shader hardware it must set the VertexShaderVersion field of the D3DCAPS8 structure to a valid, non-zero vertex shader version number. The VertexShaderVersion is a DWORD where the most significant word must have the value 0xFFFE and the least significant word holds the actual version number. The least significant byte of this word holds the minor version number and the most significant byte holds the major version number. As the format of this DWORD is complex the driver must set the value of VertexShaderVersion using the macro D3DVS_VERSION defined in d3d8types.h. For example, the following code fragment sets the VertexShaderVersion to indicate support for 1.0 level functionality.

myD3DCaps8.VertexShaderVersion = D3DVS_VERSION(1, 0);

To report no support for programmable vertex shaders the following code fragment would be used:

myD3DCaps8.VertexShaderVersion = D3DVS_VERSION(0, 0);

Drivers that do not support programmable vertex processing should set VertexShaderVersion to zero.

In addition to setting the vertex shader version, the driver should report the number of constant registers it has for vertex shading. In order to support the 1.0 vertex shading specification the device must have at least 96 constant registers. The driver reports the number of constant registers in the MaxVertexShaderConst field of the D3DCAPS8 structure. For example, the following code fragment reports the minimum number of constant registers required for version 1.0 vertex shaders.

myD3DCaps8.MaxVertexShaderConst = 96;

d3d8types.h defines a symbol for the minimum number of constant registers required by version 1.0 of the vertex shader specification. This symbol is D3DVS_CONSTREG_MAX_V1_0 and it is recommended that the driver use this symbol unless it supports more than 96 constant registers.


Pixel Shaders

All drivers that support the DirectX 8.0 DDI may support the new DP2 token D3DDP2OP_SETPIXELSHADER if programmable pixel shaders are supported in hardware.

D3DDP2OP_SETPIXELSHADER can be used to notify the driver of the handle of the current programmable pixel shader to use. A pixel shader handle refers to a programmable pixel shader handle previously created by means of the D3DDP2OP_CREATEPIXELSHADER DP2 token.


Reporting Support for Programmable Pixel Processing Hardware

For a DirectX 8.0 level driver to report support for programmable pixel shader hardware it must set the PixelShaderVersion field of the D3DCAPS8 structure to a valid, non-zero pixel shader version number. The PixelShaderVersion is a DWORD where the most significant word must have the value 0xFFFF and the least significant word holds the actual version number. This least significant byte of this word holds the minor version number and the most significant byte holds the major version number. As the format of this DWORD is complex the driver must set the value of PixelShaderVersion using the macro D3DPS_VERSION defined in d3d8types.h. For example, the following code fragment sets the PixelShaderVersion to indicate support for 1.0 level functionality.

myD3DCaps8.PixelShaderVersion = D3DPS_VERSION(1, 0);

To report support for 0.5 level pixel shaders the code would be as follows:

myD3DCaps8.PixelShaderVersion = D3DPS_VERSION(0, 5);

Drivers that do not support programmable pixel processing should set PixelShaderVersion to zero.

Unlike vertex shaders, a device cannot expose more constant registers than the 1.0 specification defines. A device that implements the 1.0 pixel shader specification must expose only eight constant pixel shader registers. However, there is an additional pixel shader related capability that a driver should set, MaxPixelShaderValue. This field gives the internal range of values supported for pixel color blending operations. Implementations must allow data within the range they report to pass through pixel processing unmodified (for example unclamped). This value normally defines the limits of a signed range, that is, an absolute value. Therefore, for example, 1 indicates that the range is [-1.0 to 1.0], and 8 indicates that the range is [-8.0 to 8.0].

However, the special value 0.0 indicates that no signed range is supported, and therefore the range is [0 .. 1.0] as in DirectX 6/7.


High Order Surfaces

DirectX 8 introduces support for a class for high order surfaces. This section describes the mechanics of the DDI for these patch surfaces but it does not describe the algorithms used. Please refer to the reference rasterizer source code included with the DDK for the details of the algorithms employed.


Reporting Support for High Order Surfaces

A driver reports its support for high order surfaces using four new capability bits in the DevCaps field of the D3DCAPS8 structure. These flags are as follows:

D3DDEVCAPS_QUINTICRTPATCHES

Device supports quintic béziers and B-splines.

D3DDEVCAPS_RTPATCHES

Device supports rectangular and triangular patches.

D3DDEVCAPS_RTPATCHHANDLEZERO

When this device capability is set, the hardware architecture does not require caching of any information and that un-cached patches (handle zero) will be drawn as efficiently as cached ones. Note that D3DDEVCAPS_RPATCHHANDLERZERO does not mean that a patch with handle zero can be drawn. A handle zero patch can always be drawn whether this cap is set or not.

D3DDEVCAPS_NPATCHES

Device supports n-patches.


High Order Surface DP2 Stream Drawing Tokens

The D3DDP2OP_DRAWRECTPATCH token is sent to the driver to draw a rectangular patch. The D3DDP2OP_DRAWTRIPATCH token is sent to the driver to draw a triangular patch.


High Order Surface Render States

There are three render states that are used with high order surfaces. These render states are described below.

D3DRS_PATCHEDGESTYLE

This render state is used to control whether patch edges use discrete or continues tessellation. See the DirectX 8.0 SDK documentation for more details.

D3DRS_PATCHSEGMENTS

This render state gives the number of segments to be used for each edge of the patch. If an explicit number of segments is specified in the DP2 token those segments should override the value of this render state. See the DirectX 8.0 SDK documentation for more details.

D3DRS_DELETERTPATCH

This render state notifies the driver that a patch is to be deleted.


Multisample Rendering

DirectX 8.0 introduces support for multi-sample rendering with the number of samples per pixel under application control. The API support multi-sampling in both fullscreen and windowed modes of operation. Furthermore, there is sufficient flexibility to support hardware that performs the processing of samples into pixels at the back end (directly out of the frame buffer) or at the front end (via a special flip or blt call).


Reporting Multi-sample Support

A driver reports the multi-sample capabilities of the hardware by specifying the number of samples per pixel for each surface format it reports. DDPIXELFORMAT has been extended to include a structure called MultiSampleCaps. This structure has fields that let the driver express the number of samples per pixel for both flip (fullscreen) and blt (windowed) multi-sampling. Each of these fields is a WORD in which each bit indicates support for a given number of samples per pixel. Hence, the driver can express support for several different sample counts with a single surface format entry.


Multi-sample Support via StretchBlt

Although not the recommended mechanism for supporting multi-sampling it is possible to implement multi-sampling support in the driver by rendering to a large back buffer and performing a stretch blt to resample the large back buffer to the lower resolution primary. However, if this is the mechanism by which the driver supports multi-sampling it must set the new capability bit D3DPRASTERCAPS_STRETCHBLTMULTISAMPLE in the RasterCaps field of the D3D8CAPS structure.

It is important to note if the driver uses a stretch blt to perform a page flip in fullscreen mode the driver should specify the supported sample counts in wFlipMSTypes and not wBltMSTypes as, conceptually at least, a flip is being performed.


Handling the Creation of Multi-Sampled Surfaces

When a multi-sampled surface is being created the number of samples can be found in the ddsCapsEx.dwCaps3 of the DD_SURFACE_MORE structure. This field simply holds one of the values of the enumerated type D3DMULTISAMPLE_TYPE. It is not a bit field like wFlipMSTypes or wBltMSTypes. If a surface is not multi-sampled dwCaps3 will have the value D3DMULTISAMPLE_NONE (0).

When determining whether a creation request for a multi-sample surface can be satisfied or not the driver should not take into account the current value of the D3DRS_MULTISAMPLEANTIALIAS render state. It is not permissible for a driver to fail a request to set D3DRS_MULTISAMPLEANTIALIAS false. Therefore, any restriction that would affect the ability to perform multi-sample rendering should be enforced at context create time even if D3DRS_MULTISAMPLEANTIALIAS is FALSE at that time.

Although DirectX 8.0 reduces the applications ability to access the primary surface it does not eliminate them. This has important implications when the primary buffer itself is multi-sampled. In those cases where Direct3D does lock the primary it does not expect the surface data to be multi-sampled. Therefore, if the underlying hardware does have a multi-sampled primary it must take appropriate action when the primary is locked and unlocked. On DdLock the driver must return a buffer of data that contains the contents of the primary in a single sample-per-pixel format. On DdUnlock the driver must convert the single sample-per-pixel format back to primary's multi-sampled format. The new cursor API can also result in DdBlt calls targeting the primary. Again, if the primary is multi-sampled, the DdBlt call must handle the conversion from the single sample-per-pixel cursor data to the mutli-sampled primary.


Controlling Multi-sampling

Two render states control multi-sample rendering.

D3DRS_MULTISAMPLEANTIALIAS

A BOOL value that determines how individual samples are computed when using a multi-sample render target buffer. When set to TRUE, the multiple samples are computed so that full-scene antialiasing is performed by sampling at different sample positions for each multiple sample. When set to FALSE, the multiple samples are all written with the same sample value (sampled at the pixel center), which allows non-antialiased rendering to a multi-sample buffer. This render state has no effect when rendering to a single sample buffer. The default value is TRUE.

See the DirectX 8.0 SDK documentation for more details.

D3DRS_MULTISAMPLEMASK

Each bit in this mask, starting at the LSB, controls modification of one of the samples in a multi-sample render target. Thus, for an 8-sample render target, the low byte contains the 8 write enables for each of the 8 samples. This render state has no effect when rendering to a single sample buffer. The default value is 0xFFFFFFFF.

This render state enables use of a multi-sample buffer as an accumulation buffer, doing multi-pass rendering of geometry where each pass updates a subset of samples. See the DirectX 8.0 SDK documentation for more details.


Pure Device Support

DirectX 8.0 introduces the concept of a "pure" device. When using a pure device the runtime is somewhat more lightweight; it will not track state or state blocks or perform any software vertex processing on behalf of the hardware. Furthermore, the application cannot query back state from the runtime. The lack of state tracking, particularly when state blocks are being used, can result in a significant performance boost for the application.

Only vertex processing directly supported by the hardware is available to the application when using a pure device. For example, for cards that don't support hardware transform and lighting, only pre-transformed vertices can be passed to Direct3D. Furthermore, the API functions SetClipStatus, GetClipStatus and ProcessVertices cannot be used with the pure device.

In order to use a pure device the application must request it with the device creation flag D3DCREATE_PUREDEVICE and the driver must report its ability to act as a pure device.


Reporting Pure Device Capability

A driver reports the ability to support pure devices by setting the new device capability D3DDEVCAPS_PUREDEVICE in the DevCaps field of the D3DCAPS8 structure.


State Block Recording and Pure Devices

State block handling is different for a device operating in pure device mode. In this mode, the state block control DP2 token (D3DDP2OP_STATESET) will be sent to the driver with a new operation type (in the dwOperations field). This new operation type is D3DHAL_STATESETCREATE.


Processing the D3DDP2OP_CLEAR DP2 Token

DirectX 8.0 introduces some changes to the required processing of the D3DDP2OP_CLEAR token. Specifically a new flag D3DCLEAR_COMPUTERECTS has been added to the dwFlags field of the D3DHAL_DP2CLEAR data structure. This new flag will only be passed to the driver when a pure device type is being used (that is, D3DCREATE_PUREDEVICE was specified when creating the device and the driver exports the D3DDEVCAPS_PUREDEVICE device cap). Furthermore, this flag will never be passed to non-DirectX 8.0 drivers and it will not be specified using the legacy Clear or Clear2 driver callbacks.


Vertex Buffer Issues

The following section contains update information for vertex buffer creation and use.


Vertex Buffer Callbacks and Windows 2000

DirectX 7.0 on the initial retail release of Windows® 2000 and on Windows 2000 Service Pack 1 (SP1) suffers from a defect that prevents a driver's execute buffer (D3D buffer) callbacks from being invoked by the runtime. This prevents the driver from being notified of vertex buffer creation requests and, hence, no video memory or non-local video memory buffers can be created or used in this scenario. This defect is not present in DirectX 8.0 or in the version of DirectX 7.0 that is shipped with DirectX 8.0. Furthermore, it will be corrected in an upcoming service pack for Windows 2000 and in all future versions of Windows 2000. However, there is no workaround to enable video memory vertex buffers on Windows 2000 or Windows 2000 SP1 other than to install DirectX 8.0.


Vertex Buffer Creation Handling on Windows 2000

In DirectX 8.0 vertex (and index) buffers can be managed as textures were in DirectX 7.0. That is, a system memory copy of a vertex copy is maintained at all times and a video memory copy is only allocated when that vertex buffers is actually required. In order to make vertex management work correctly, however, it is essential that the driver fail vertex buffer creation in the correct way. If the driver does not want to allocate a vertex buffer in video memory but, instead, wishes the runtime to allocate the buffer in system memory, it should not return DDHAL_DRIVER_NOTHANDLED but rather should return DDHAL_DRIVER_HANDLED and indicate failure by setting a ddRVal of E_FAIL. If the driver returns DDHAL_DRIVER_NOTHANDLED the runtime will attempt to allocate the surface from the video memory heaps returned by the driver. This may either fail and return an error to the application or result in the surface being allocated in local or non-local video memory (which is not the intention).

Therefore, if you wish the runtime to allocate a vertex buffer in system memory on your behalf, set ddRVal to E_FAIL and return DDHAL_DRIVER_HANDLED.


Vertex Buffer Renaming

To improve parallelism between the driver and the runtime Direct3D supports the concept of vertex buffer "renaming". Essentially this is a double buffering scheme for vertex buffers. In certain circumstances a driver can, when passed a vertex buffer through a DDI call, modify the video memory pointer of the vertex buffer. In this way, the driver can continue to process the contents of the vertex buffer, while, at the same time, the application can lock and fill the vertex buffer. As far as the application is concerned it is using the same vertex buffer. The fact that the memory pointed to by that vertex buffer has been modified is hidden by the runtime and driver.

Although previous versions of DirectX supported vertex buffer renaming there have been certain changes with DirectX 8.0. In previous versions of Direct3D, renaming was primarily accomplished via the D3dDrawPrimitives2 DDI entry point. Flags specified in D3DHAL_DRAWPRIMITIVES2DATA would specify whether the driver could swap the vertex or command buffer and if so, what the required sizes of the buffers would be. However, in DirectX 8.0 vertex buffer swapping is not accomplished through D3dDrawPrimitives2 (although calls through legacy interfaces will still exploit this mechanism) but rather through the LockExecuteBuffer (LockD3DBuffer) DDI entry point.

DirectX 8.0 defines a new lock flag, D3DLOCK_DISCARD, that when passed to the driver indicates that the caller does not require the existing contents of the driver and hence they can be discarded prior to returning the pointer to the vertex buffer data. Hence, when the driver receives a vertex buffer lock call with the D3DLOCK_DISCARD flag set it can choose to rename the vertex buffer by setting the fpVidMem to a new value.

It is important to note that the D3DLOCK_DISCARD flag will not be passed to the driver by the initial retail release of Windows® 2000. The flag will be passed on Windows 2000 Service Pack 1 (SP1) and all subsequent versions of Windows 2000 and all versions of Windows 98/Me.

In DirectX 7.0 vertex buffer renaming could also be accomplished via LockExecuteBuffer using the flag DDLOCK_DISCARDCONTENTS. However, there were defects in the synchronization between runtime and driver on the original release of DirectX 7.0 that prevent this mechanism working correctly. However, the version of DirectX 7.0 released with DirectX 8.0 corrects this problem and vertex buffer renaming at lock time will be functional through DirectX 7.0 interfaces.


Handling Renaming on Windows 2000

In order to correctly perform vertex buffer renaming it is important to understand the nature of the fpVidMem pointer stored in the surface global object on Windows® 2000 and later. The interpretation of fpVidMem depends on the type of memory in which the surface is stored. For both system and non-local video memory (AGP) surfaces the fpVidMem is a pointer directly into the user mode address space of the process owning that surface.

For local video memory surfaces, fpVidMem is an offset from the start of video memory. In order to convert this to a user mode pointer it is necessary to add the base address of video memory as mapped into a user mode process. This base address can be found in the fpProcess field of the DirectDraw local object for a given process.

Although fpVidMem for a non-local video memory surface is simply a user mode pointer the means by which this user mode pointer are generated are somewhat complex. It is necessary to understand how the Windows 2000 kernel maintains AGP heaps and manages surface allocations from them. The first important point is that, for non-local heaps, the start address of the heap maintained by the kernel may not be a heap into any real address space. It is in fact, normally, a numerical offset designed to ensure that valid allocations from that heap cannot have a NULL (zero) address.

It may be helpful to think of AGP heaps as residing in a conceptual address space that does not correspond to any real address space. The fpStart field of an AGP heap is the base address of the heap in this conceptual address space. Furthermore, any surfaces allocated from an AGP heap have an fpHeapOffset that also lies in this conceptual address space. Thus, fpHeapOffset is an offset from the base of this conceptual heap and it is not an offset from the start of the heap itself. Furthermore, it is not a pointer into any real address space. In order for a user mode process to access the memory of a surface fpHeapOffset must be mapped (via pointer arithmetic) into the address space of that user mode process. When a surface is created the kernel performs this mapping according to the formula outlined below.

Given a surface (pSurface), a kernel mode AGP heap (pvmHeap) and a mapping of the heap into a particular user mode process (pMap), the following formula is used to compute the actual, user mode, fpVidMem, for a surface:

fpVidMem = pMap->pvVirtAddr +
    (pSurface->fpHeapOffset – pvmHeap->fpStart)

pvVirtAddr is the base address of the user mode mapping of the AGP heap into a given process. fpStart is the offset of the base of the AGP heap into the conceptual address space described above and fpHeapOffset is the offset of the start of the surface from the base of the same conceptual address space.

Your driver is notified of the conceptual base address of AGP heaps through the DdGetDriverInfo callback. When DdGetDriverInfo is called with GUID_UpdateNonLocalHeap the fpGARTLin field of the data structure passed is the same value as fpStart, i.e., the base address of the start of the AGP heap in the conceptual address space. Unfortunately, your driver is not notified of the value of pvVirtAddr and it is not visible to the driver through any of the data structures passed to the driver. Therefore, its value has to be computed from the fpVidMem computed by the kernel for the vertex buffer on initial creating. Given the fpVidMem computed by the kernel simply subtract the current fpHeapOffset less the heap's fpStart. Given the fpHeapOffset of the new memory to be swapped into the vertex buffer on renaming the new value of fpVidMem can be easily computed.

The following code fragment demonstrates computing a new fpVidMem for an AGP surface in a lock call.

// Get the vertex buffer's surface local and global from the
// lock data
LPDDRAWI_DDRAWSURFACE_LCL*pLcl = pLockData->lpDDSurface;
LPDDRAWI_DDRAWSURFACE_GBL*pGbl = pLcl->lpGbl;

// Get heap this vertex buffer was allocated from
LPVVIDEOMEMORY pHeap = pGbl->lpVidMemHeap;

// Get the current fpVidMem for the vertex buffer
FLATPTR fpCurrentVidMem = pGbl->fpVidMem;

// Compute the virtual base address of the mapping of this AGP
// into the process owning this vertex buffer.
FLATPTR pvVirtAddr = fpCurrentVidMem –
                     (pGbl->fpHeapOffset – pHeap->fpStart);

// Given the fpHeapOffset of the non-local video memory to be
// swapped into the new vertex buffer compute the new fpVidMem
// as follow
FLATPTR fpNewVidMem = pvVirtAddr + (fpNewHeapOffset – pHeap->fpStart);

// Now store the new fpVidMem in the surface global object and
// also in the lock data.
pGbl->fpHeapOffset = fpNewHeapOffset;
pGbl->fpVidMem = fpNewVidMem;
pLockData->lpSurfData = fpNewVidMem;

// Return success and driver handled
pLockData->ddRVal = DD_OK;
return DDHAL_DRIVER_HANDLED;

In order to make non-local video memory accessible to a user mode process it is necessary for the memory to be both committed and mapped to the user mode process. To ensure that this is done when vertex buffer renaming is being performed it is essential that the new memory for the vertex buffer be allocated using the Eng Xxx function HeapVidMemAllocAligned. This will guarantee that the memory is committed and mapped prior to use. HeapVidMemAllocAligned returns an offset into the conceptual address space of the AGP heap and, hence, this pointer can be used as an fpHeapOffset directly.

If the driver returns DDHAL_DRIVER_HANDLED for a lock of an AGP surface the kernel code will return to the runtime and application the value of lpSurfData in the DD_LOCKDATA data structure. If the driver returns DDHAL_DRIVER_NOTHANDLED the kernel simply returns the value of fpVidMem to user mode. Therefore, it is not necessary to return DDHAL_DRIVER_HANDLED as long as fpVidMem is updated to point to the new user mode pointer. However, we recommend that the driver both set fpVidMem and lpSurfData and return DDHAL_DRIVER_HANDLED.


Clipping Transformed Vertices

The Direct3D 8.0 runtime fully supports the clipping of pre-transformed vertices through both the DrawPrimitive and ProcessVertices API calls. This clipping includes user defined clipping planes as well as Z and the X and Y viewport extents. However, the runtime does not guarantee the clipping of post-transformed vertices. Post-transformed vertex data is passed directly from the application to the driver by the runtime. This does not imply that a driver is required to full clip post-transformed vertex data. A new capability flag D3DPMISCCAPS_CLIPTLVERTS has been added for DirectX 8.0. If the driver sets this flag in the PrimitiveMiscCaps field of the D3DCAPS8 structure the application can assume that the driver will fully clip post-transformed vertex data to Z and the X and Y viewport extents. Clipping to user-defined clip planes is never supported for post-transformed data. If the driver does not set this flag the application is required to performing clipping of the post-transformed data to the Z extents and to (at least) the guard band extents in X and Y.

It is important to note that the runtime does not validate that the application has correctly clipped post-transformed data. It is the driver's responsibility to ensure that a crash or hang does not occur if unclipped or incorrectly clipped data is passed when this flag is set.


Handling Compressed Texture Surfaces Created In System Memory

This topic applies only to NT-based operating systems.

The width and height of a compressed-texture surface created in system memory are altered by the user-mode runtime to force the kernel-mode runtime to allocate the appropriate amount of memory. The display driver must reverse this alteration to prevent subsequent operations that are performed on this surface from failing. Whenever the DirectDraw runtime calls the driver's D3dCreateSurfaceEx function to create a compressed-texture surface, the driver must restore the width and height of the surface to their unaltered states.

The driver's D3dCreateSurfaceEx function receives the surface's width, pitch, and height altered as follows:

  • Width and pitch contain the number of 4x4 blocks in a row multiplied by the block size.
  • Height contains the number of 4x4 blocks in the column.

The following code snippet shows the calculations that the driver must perform to restore the width and height of the surface:

RealWidth = (Width / Block size) * 4;
RealHeight = Height * 4;

The driver should assign the restored width and height values to members in the kernel's DD_SURFACE_GLOBAL surface structure. Doing so prevents the DirectDraw kernel-mode runtime from rejecting DXT texture download blts because the width and height values do not match. That is, if the driver leaves the altered sizes in the wWidth and wHeight members of DD_SURFACE_GLOBAL, the DirectDraw kernel-mode runtime will reject a blt from the altered system-memory surface to the video-memory surface because the width and height of the source, which is in unaltered coordinates, will seem to be "outside" the altered DD_SURFACE_GLOBAL size.


Enabling Alpha Channels On Full-Screen Back Buffers

It is a well established fact in the DirectDraw DDI that the creation of a primary flipping chain has no intrinsic pixel format. Consequently, surfaces in this chain take on the pixel format of the display mode. For example, a primary flipping chain created in a 32bpp mode will take on a D3DFMT_X8R8G8B8 format.

Such a chain is created for many full-screen applications. Because the back buffer of the chain has no alpha channel, the D3DRS_ALPHABLENDENABLE render state and the associated blend-render states for destination surfaces are poorly defined. DirectX 8.1 introduces a new feature that the Direct3D runtime uses to inform a driver of an application's request to create a full-screen flipping chain of surfaces with an alpha channel in the pixel formats of those surfaces.

To indicate support of this feature, the driver must set the D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD bit (defined in the d3d8caps.h file) in the Caps3 member of the D3DCAPS8 structure. The driver returns a D3DCAPS8 structure in response to a GetDriverInfo2 query as described in Reporting DirectX 8.0 Style Direct3D Capabilities. Support of this query is described in Supporting GetDriverInfo2.

After support of this feature is determined, the driver can receive DdCreateSurface calls with the DDSCAPS2_ENABLEALPHACHANNEL (defined in the ddraw.h file) bit set in the dwCaps2 member of the DDSCAPS2 structure. This bit is only set to create surfaces that are part of a primary flipping chain or that are on stand-alone back buffers.

If the driver detects this bit, the driver determines that the surfaces take on not the display mode's format, but the display mode's format plus alpha. For example, in a 32bpp mode, such surfaces should be given the D3DFMT_A8R8G8B8 format.

This feature is available on Windows XP and later versions. This feature is also available on Windows 2000 and Windows 98/Me operating system versions that have the DirectX 8.1 runtime installed on them.


Video Miniport Drivers

NT-based operating system video miniport drivers are adapter-specific, kernel-mode drivers. Each different type of graphics card that can be used with an NT-based operating system must have both a video miniport driver and a display driver.

A video miniport driver links itself with the video port driver, which is a system-supplied, kernel-mode dynamic-link library. A miniport driver calls only the video port driver's VideoPort Xxx functions to communicate with the system and with its hardware.

Windows 2000 and later miniport drivers must be implemented as Plug and Play (PnP) drivers. The Windows 2000 and later video port driver supports Windows NT 4.0 drivers as legacy drivers.

This section provides implementation details for video miniport writers and describes the miniport driver's interaction with both the display driver and the video port driver. Reference pages for all video port and miniport driver functions can be found in the Graphics Driver Reference.

Display drivers are discussed in Introduction to Display and Display Drivers.


Video Miniport Header Files, Sample Code, and References

NT-based operating system video miniport drivers include the following header files:

File Name | Contents
dderror.h | Contains the Win32® status constants that miniport drivers return to the video port driver, which are also returned to the miniport driver's corresponding kernel-mode display driver.
devioctl.h | Contains the macros and constants used to define I/O control codes.
miniport.h | Contains the basic types, constants, and structures for video (and SCSI) miniport drivers.
ntddvdeo.h | Contains the system-defined I/O control codes (IOCTLs) and corresponding structures that are sent in video request packets (VRPs) to video miniport drivers.
tvout.h | Contains the VIDEOPARAMETERS structure used to implement TV connector and copy protection support and the constants used in this structure.
video.h | Contains the VideoPort Xxx and SvgaHwIoPort Xxx video port function declarations, video-specific structures, such as the VIDEO_REQUEST_PACKET, and the HwVid Xxx video miniport function prototypes.
videoagp.h | Contains the AGP-specific structures, Agp Xxx miniport driver function prototypes, and VideoPort Xxx function declarations required to implement AGP support in a video miniport driver.

These headers are shipped with the Windows DDK. For more detailed information about the functions, structures, system-defined I/O control codes, constants, in these header files, see Graphics Driver Functions (DDI), GDI Functions for Graphics Drivers, and Graphics Driver Structures.

The Windows DDK also provides sample code for several working video miniport drivers in the video\miniport directory. The 3dlabs miniport driver samples implement a broad variety of capabilities The mirror sample contains a mirror-driver-specific miniport driver implementation.


Video Miniport Driver Requirements

The following are some of the requirements for video miniport drivers.

  • An NT-based operating system video miniport driver must be a single .sys file.

    A miniport driver consists of a single binary file. The miniport driver's main purpose is to detect, initialize, and configure one or more graphics adapters of the same type.

  • A miniport driver can only make calls exported by videoprt.sys.

    A miniport driver can call only those functions that are exported by the system-supplied video port driver. (The exported video port functions are listed on the reference pages following Video Port Functions for Miniport Drivers.) Driver writers can also use the following to determine which functions a miniport driver is calling:

    link -dump -imports my_driver.sys

    A miniport driver cannot load or install another driver on the machine using undocumented OS function calls.

  • A miniport driver can enable panning only upon receiving an end-user request.

    Panning must be disabled by default. The miniport driver should enable it only when it is requested through a Control Panel. OEMs can enable panning by default as a part of their pre-install.


Video Miniport Driver within the Graphics Architecture

The following figure shows the video miniport driver within the NT-based operating system graphics subsystem.

NT-Based Operating System Graphics Architecture

Each video miniport driver provides hardware-level support for a display driver. The display driver calls the graphics engine EngDeviceIoControl function to request support from the underlying video miniport driver. EngDeviceIoControl, in turn, calls an I/O system service to send the request through the video port driver to the miniport driver.

In most circumstances, the display driver carries out time-critical operations that are visible to the user, while the underlying miniport driver provides support for infrequently requested operations or for truly time-critical operations that cannot be preempted by an interrupt or a context switch to another process.

A display driver cannot handle device interrupts, and only the miniport driver can set up device memory and map it into a display driver's virtual address space.

The video port driver is a system-supplied module provided to support video miniport drivers. It acts as the intermediary between the display driver and video miniport drivers

For more information about NT-based operating system display drivers, see Introduction to Display and Display Drivers.


Platform-Specific Details for Video Miniports

On x86-based NT-based operating system platforms, there are two kinds of video miniport drivers: nonVGA-compatible miniport drivers and VGA-compatible miniport drivers.


NonVGA-Compatible x86-Based Miniports

Previous Next

NonVGA-Compatible, x86-Based Miniports

Most miniport drivers are nonVGA-compatible, and are consequently much simpler to implement.

NonVGA-compatible video miniport drivers rely on having the system-supplied VGA miniport driver (vga.sys) or another VGA-compatible SVGA miniport driver loaded concurrently. Such a miniport driver is set up to configure itself in the registry with VgaCompatible set to zero (FALSE) and has the following features:

  • It provides no special support for full-screen MS-DOS applications in x86-based machines. Instead, it is loaded along with a system-supplied VGA (or, possibly, with a VGA-compatible SVGA) miniport driver, which provides this support for full-screen MS-DOS applications.
  • In most cases, it either is written for an adapter that has no VGA compatibility mode or for an accelerator that works independently of the VGA.


VGA-Compatible, x86-Based Miniports

A VGA-compatible miniport driver has the following features:

  • It is based on the system-supplied VGA miniport driver, with code modified to support adapter-specific features. The system-supplied VGA display drivers use the support provided by VGA-compatible miniport drivers, so the developer of a new miniport driver for a VGA-compatible adapter need not write a new display driver.
  • It provides support for full-screen MS-DOS® applications to do I/O directly to the adapter registers. It also functions as a video validator to prevent such applications from issuing any sequence of instructions that would hang the machine.

Miniport drivers of most SVGA adapters fall in this category, but any new miniport driver for a nonSVGA adapter can provide VGA compatibility support at the discretion of the driver designer.

Self-declared "VGA-compatible" miniport drivers are set up to configure themselves in the registry with VgaCompatible set to one (TRUE).


Video Miniport Driver Interface

The following sections list the functions that comprise the video miniport driver interface. Some functions are required, while others are conditionally required or optional, and their inclusion in a miniport driver depends on the adapter's features and the driver writer.

Except for DriverEntry, this documentation uses pseudonames for standard miniport driver functions that suggest the required functionality of each. In other words, the name given to each standard miniport driver function, except DriverEntry, can be anything the miniport driver writer chooses.


Required Video Miniport Driver Functions

The following system-defined functions must be implemented in every video miniport driver. With the exception of DriverEntry, all other miniport driver functions are listed in alphabetic order:

Required Function Name | Description
DriverEntry | Initializes the video miniport driver.
HwVidFindAdapter | Gets the access ranges for devices on an enumerable bus; if necessary, determines the device type.
HwVidGetPowerState | Queries whether a device can support the requested power state.
HwVidGetVideoChildDescriptor | Enumerates the child devices attached to the specified device.
HwVidInitialize | Performs one-time initialization of the adapter for the corresponding display driver. Called in response to a request to open the adapter.
HwVidSetPowerState | Sets the power state of the specified device.
HwVidStartIO | Begins processing of the incoming VRP.


Conditionally Required Video Miniport Driver Functions

The following system-defined functions are conditionally required in a video miniport driver, depending on a given adapter's features and on the driver designer. Functions are listed in alphabetic order.

Conditionally Required Function Name | Description
HwVidInterrupt | Handles adapter-generated interrupts. This function is required if the miniport driver's adapter generates interrupts.
HwVidResetHw | Resets the adapter to character mode so the HAL can display system shutdown information in case of a controlled shutdown (crash) of the machine and initialization information on a soft reboot of the machine. Required if the adapter's registers cannot be automatically reset by an INT10.
HwVidSynchronizeExecutionCallback | Synchronizes access to data shared by HwVidInterrupt; allows critical sections of code to be run at a higher than normal software or hardware priority (IRQL, with some device and system interrupts masked off). Required if other miniport driver functions share state with HwVidInterrupt.


Optional Video Miniport Driver Functions

The following system-defined functions can be optionally implemented in video miniport drivers. Functions are listed in alphabetic order.

Optional Function Name | Description
HwVidExecuteDma | Performs a DMA operation.
HwVidLegacyResources | Returns a list of legacy resources for a particular device.
HwVidQueryDeviceCallback and/or HwVidQueryNamedValueCallback | Process configuration information stored in the registry. Optional if the miniport driver's HwVidFindAdapter function uses I/O bus-type-specific configuration information or driver-supplied defaults.
HwVidQueryInterface | Returns a miniport driver-implemented functional interface into which a child device can call.
HwVidTimer | Is called periodically at approximately one-second intervals by the video port driver.
SvgaHwIoPort Xxx functions | Validate accesses to I/O ports by full-screen MS-DOS applications in x86-based machines. These functions are for VGA-compatible SVGA miniport drivers. See VGA-Compatible Miniport's SvgaHwIoPortXxx for more information.


Video Miniport Initialization

Video miniport driver initialization occurs after the NT kernel, HAL, and core drivers, such as the PCI bus driver, are loaded and initialized. The basic system initialization sequence occurs as follows:

  • The NT kernel and HAL are loaded and initialized.
  • Core drivers such as the PCI bus driver are loaded and initialized.
  • The PCI bus driver obtains PCI resource information and the device ID and vendor ID from each of its children's PCI configuration spaces and reports this information back to the system.
  • If the PnP Manager recognizes the device and vendor IDs, the I/O Manager loads the corresponding video miniport driver and the video port driver from a known location. If the PnP Manager does not recognize the IDs, it prompts the user for the location of the miniport driver and loads it from this location.
  • The I/O manager calls the miniport driver's DriverEntry routine with two system-supplied input pointers. DriverEntry allocates and initializes a VIDEO_HW_INITIALIZATION_DATA structure with driver-specific and adapter-specific values, including pointers to the miniport driver's other entry points. DriverEntry must also claim any legacy resources, which are those resources not listed in the device's PCI configuration space but that are decoded by the device. See Claiming Legacy Resources for details.
  • The miniport driver's DriverEntry function calls VideoPortInitialize. VideoPortInitialize performs those aspects of miniport driver initialization that are common to all miniport drivers. For example, for non-PnP drivers, VideoPortInitialize verifies portions of the miniport driver-initialized VIDEO_HW_INITIALIZATION_DATA structure, initializes some of the public members of the system-created device object, allocates memory for the device extension of the device object, and collects and stores pertinent information in the device extension. See Video Miniport's Device Extension for more details about device extensions. For PnP drivers, the device object-related actions occur at a later time.
  • When VideoPortInitialize returns, DriverEntry propagates the return value of VideoPortInitialize back to the caller. Miniport driver writers should make no assumptions about the value returned by VideoPortInitialize.

At this point, the system has loaded and initialized the video miniport driver. The next step is for the PnP manager to start the device. See Starting the Device of the Video Miniport for details.


Starting the Device of the Video Miniport

The PnP manager sends an IRP to the video port driver requesting that the graphics adapter be started. The video port driver's dispatch routine calls the miniport driver's HwVidFindAdapter routine in response to this IRP. Details for some of HwVidFindAdapter's tasks are discussed in the following topics:

Setting up Video Adapter Access Ranges

Setting Hardware Information in the Registry

Changing State on the Adapter


Setting up Video Adapter Access Ranges

An array of VIDEO_ACCESS_RANGE-type elements describes one or more ranges of memory and/or I/O ports that a video adapter decodes. Each access range element in this array contains bus-relative physical address values.

The miniport driver's HwVidFindAdapter routine must claim all PCI memory and ports or ranges of ports that the adapter will respond to. Depending on the adapter and the AdapterInterfaceType value in VIDEO_PORT_CONFIG_INFO, HwVidFindAdapter can call some of the following VideoPort Xxx functions to get the necessary bus-relative configuration data:

VideoPortGetAccessRanges

VideoPortGetBusData

VideoPortGetDeviceData

VideoPortGetRegistryParameters

VideoPortVerifyAccessRanges

If HwVidFindAdapter cannot get bus-relative access ranges information by calling VideoPortGetBusData or VideoPortGetAccessRanges, or from the registry with VideoPortGetDeviceData or VideoPortGetRegistryParameters, the miniport driver should have a set of bus-relative default values for access ranges.

Every HwVidFindAdapter function must map each claimed bus-relative physical address range to a range in kernel-mode address space with VideoPortGetDeviceBase before the miniport driver attempts to communicate with an adapter. The HAL can remap bus-relative access range values to system-space logical address ranges, particularly in multiple bus machines.

With mapped logical range addresses, the driver can call the VideoPortRead Xxx and VideoPortWrite Xxx functions to read from or write to an adapter. These kernel-mode addresses also can be passed to VideoPortCompareMemory, VideoPortMoveMemory, VideoPortZeroDeviceMemory, and/or VideoPortZeroMemory. For a mapped range in I/O space, the miniport driver calls the VideoPortReadPort Xxx and VideoPortWritePort Xxx functions. For a mapped range in memory, the miniport driver calls the VideoPortReadRegister Xxx and VideoPortWriteRegister Xxx functions.

The HwVidFindAdapter function must always call VideoPortVerifyAccessRanges or VideoPortGetAccessRanges successfully before it calls VideoPortGetDeviceBase.

  • Any successful call to VideoPortVerifyAccessRanges or VideoPortGetAccessRanges establishes a miniport driver's claim on bus-specific video memory and register addresses or I/O ports for its adapter in the registry. It is critical to note, however, that any subsequent call to VideoPortVerifyAccessRanges or VideoPortGetAccessRanges will cause that driver's previously claimed resources to be erased and replaced with the ranges passed to the most recently called function. Therefore, if a driver claims ranges by separate calls to these functions, it must pass in all range arrays, including those already claimed.
  • HwVidFindAdapter can claim a small set of access ranges for an adapter, use this set to determine whether the adapter is one that the miniport driver supports, and claim a full set of access ranges for a supported adapter with another call to VideoPortGetAccessRanges or VideoPortVerifyAccessRanges. Again, each successful call to these VideoPort..AccessRanges routines for a particular adapter overwrites the caller's previous claims in the registry.
  • To claim other types of hardware resources, such as an interrupt vector, a miniport driver should set appropriate values in the VIDEO_PORT_CONFIG_INFO and call VideoPortVerifyAccessRanges, or it should call VideoPortGetAccessRanges.
  • Calling VideoPortGetAccessRanges or VideoPortVerifyAccessRanges successfully ensures that a miniport driver does not try to use register or device memory addresses already in use by another driver.
  • Claiming an adapter's bus-relative hardware resources in the registry prevents drivers that load later from attempting to use the same access ranges (and other hardware resources) for their adapters. It also prevents a subsequently loaded driver from changing the initialized state of the video adapter.

The miniport driver of hardware that decodes legacy resources must claim these resources in its DriverEntry routine, or if implemented, its HwVidLegacyResources routine. Legacy resources are those resources not listed in the device's PCI configuration space but that are decoded by the device. See Claiming Legacy Resources for details.

After a miniport driver is loaded and its HwVidInitialize function is run, the miniport driver's HwVidStartIO function is called to map any access range of video memory that the miniport driver makes visible to its corresponding display driver.


Setting Hardware Information in the Registry

HwVidFindAdapter can call the VideoPortGetRegistryParameters and VideoPortSetRegistryParameters functions to get and set configuration information in the registry. For example, HwVidFindAdapter might call VideoPortSetRegistryParameters to set up nonvolatile configuration information in the registry for the next boot. It might call VideoPortGetRegistryParameters to get adapter-specific, bus-relative configuration parameters written into the registry by an installation program.

It is recommended that miniport drivers set certain hardware information in the registry to display useful information to the user and for assistance in debugging. A miniport driver can set a chip type, DAC type, memory size (of the adapter), and a string to identify the adapter. This information is displayed by the control panel display applet.

The driver sets this information by calling VideoPortSetRegistryParameters. Typically, the driver makes the call in its HwVidFindAdapter routine.

The following table describes the information that the driver can register and provides details for the ValueName and ValueData parameters of VideoPortSetRegistryParameters:

Information for Entry | ValueName | ValueData
Chip type | HardwareInformation.ChipType | Null terminated string containing the chip name.
DAC type | HardwareInformation.DacType | Null terminated string containing the DAC name or ID.
Memory size | HardwareInformation.MemorySize | ULONG containing, in MB, the amount of video memory on the adapter.
Adapter ID | HardwareInformation.AdapterString | Null-terminated string containing the name of the adapter.
BIOS | HardwareInformation.BiosString | Null-terminated string containing information about the BIOS.


Changing State on the Adapter

The miniport driver must not permanently change the state of the adapter until its HwVidInitialize routine is called. Miniport driver routines called before HwVidInitialize, such as HwVidFindAdapter, should not change the state of any video adapter unnecessarily and must not change the state of any video adapter permanently.

While HwVidFindAdapter runs, the HAL has control of the video adapter so it can write information to the screen in the early stages of the system boot process. If HwVidFindAdapter's attempt to identify its adapter affects an adapter's state, this routine should restore the original state immediately so that on return from HwVidFindAdapter the HAL can continue to display boot-up messages.

For example, HwVidFindAdapter should defer determining the DAC type of an adapter to the HwVidInitialize function, because making this determination does not affect whether the miniport driver will be loaded but does change the state of the adapter permanently.


Claiming Legacy Resources

A video miniport driver must claim and report all legacy resources in its VIDEO_HW_INITIALIZATION_DATA structure during driver initialization. Legacy resources are those resources not listed in the device's PCI configuration space but that are decoded by the device. NT-based operating systems will disable power management and docking when they encounter legacy resources that are not reported in the manner outlined in this section.

Miniport drivers must do the following to report such legacy resources:

  • If the legacy resource list for the device is known at compile time, fill in the following two fields of the VIDEO_HW_INITIALIZATION_DATA structure that is created and initialized in the DriverEntry routine:
    Structure Member | Definition
    HwLegacyResourceList | Points to an array of VIDEO_ACCESS_RANGE structures. Each structure describes a device I/O port or memory range for the video adapter that is not listed in PCI configuration space.
    HwLegacyResourceCount | Is the number of elements in the array to which HwLegacyResourceList points.

  • If the legacy resource list for the device is not known at compile time, implement a HwVidLegacyResources function and initialize the HwGetLegacyResources member of VIDEO_HW_INITIALIZATION_DATA to point to this function. For example, a miniport driver that supports two devices with different sets of legacy resources would implement HwVidLegacyResources to report the legacy resources at run time. The video port driver will ignore the HwLegacyResourceList and HwLegacyResourceCount members of VIDEO_HW_INITIALIZATION_DATA when a miniport driver implements HwVidLegacyResources.
  • Fill in the RangePassive field for each VIDEO_ACCESS_RANGE structure defined in the miniport driver accordingly. Setting RangePassive to VIDEO_RANGE_PASSIVE_DECODE indicates that the region is decoded by the hardware but that the display and video miniport drivers will never touch it. Setting RangePassive to VIDEO_RANGE_10_BIT_DECODE indicates that the device decodes ten bits of the port address for the region.

Again, a driver should only include resources that the hardware decodes but that are not claimed by PCI. Code in a driver that needs to claim minimal legacy resources might look something like the following:

//              RangeStart        RangeLength
//              |                 |      RangeInIoSpace
//              |                 |      |  RangeVisible
//        +-----+-----+           |      |  |  RangeShareable
//       low         high         |      |  |  |  RangePassive
//        v           v           v      v  v  v  v
VIDEO_ACCESS_RANGE AccessRanges[] = {
    // [0] (0x3b0-0x3bb)
    {0x000003b0, 0x00000000, 0x0000000c, 1, 1, 1, 0},
    // [1] (0x3c0-0x3df)
    {0x000003C0, 0x00000000, 0x00000010, 1, 1, 1, 0},
    // [2] (0xa0000-0xaffff)
    {0x000A0000, 0x00000000, 0x00010000, 1, 0, 0, 0},
};

// Within the DriverEntry routine:
VIDEO_HW_INITIALIZATION_DATA hwInitData;
hwInitData.HwLegacyResourceList = AccessRanges;
hwInitData.HwLegacyResourceCount = 3;

The miniport driver can "reclaim" legacy resources again in subsequent call(s) to VideoPortVerifyAccessRanges; however, the video port driver will just ignore requests for any such previously claimed resources. Power management and docking will be disabled in the system if the miniport driver attempts to claim a legacy access range in VideoPortVerifyAccessRanges that was not previously claimed in the HwLegacyResourceList during DriverEntry or returned in the LegacyResourceList parameter of HwVidLegacyResources.


Initializing the Video Miniport for Communication with Display Driver

For each adapter found by the PnP Manager and successfully configured by the miniport driver, the miniport driver's HwVidInitialize function is called when the corresponding display driver is loaded. HwVidInitialize can initialize software state information, but it should not set up visible state on the adapter. On return from HwVidInitialize, the adapter should be set to the same state as on return from the miniport driver's HwVidResetHw routine. For more information on HwVidResetHw, see Resetting the Adapter in the Video Miniport.

If necessary, a miniport driver's HwVidInitialize function can carry out a one-time initialization operation on the adapter that was postponed by its HwVidFindAdapter function. For example, a miniport driver might postpone loading microcode on the adapter and have the HwVidInitialize function call VideoPortGetRegistryParameters.

When the HwVidInitialize function returns control, the graphics engine has a handle for the miniport driver's adapter. The corresponding display driver then can call the engine's EngDeviceIoControl function to request access to mapped video memory or to request any other operation. The video port driver sends such a request on to the miniport driver's HwVidStartIO function, as a VRP. See Processing Video Requests for details.

Usually, a display driver controls the display the end user sees, except occasionally when a full-screen MS-DOS application is run in an x86-based machine running an NT-based operating system. For more information about supporting this feature in VGA-compatible miniport drivers, see VGA-Compatible Miniport's SvgaHwIoPortXxx.

The HwVidInitialize function can call VideoPortGetRegistryParameters or VideoPortSetRegistryParameters to get and set configuration information in the registry. For example, HwVidInitialize might call VideoPortSetRegistryParameters to set up nonvolatile configuration information in the registry for the next boot. It might call VideoPortGetRegistryParameters to get adapter-specific, bus-relative configuration parameters written into the registry by an installation program.


Video Miniport's Device Extension

A device extension is each miniport driver's primary and only global storage area for adapter-specific state information.

Each miniport driver defines the size, internal structure, and contents of its device extension. The video port driver passes a pointer to the device extension as an input parameter to every system-defined miniport driver function except DriverEntry and, if implemented, the HwVidSynchronizeExecutionCallback and SvgaHwIoPort Xxx functions. Many VideoPort Xxx functions require this pointer as an argument as well.

The miniport driver must also use the device extension to maintain the state information for a single adapter. Each adapter detected by the system will have separate state information maintained in a separate device extension. The miniport driver must not use global variables to store any per-adapter state. This is especially critical in order to provide seamless multiple monitor support.


Registry Callbacks in the Video Miniport

A miniport driver's HwVidFindAdapter function can request that configuration information be retrieved from the registry by calling one of the following video port driver functions with a driver-supplied callback:

  • VideoPortGetDeviceData with the CallbackRoutine parameter set to point to a driver-supplied HwVidQueryDeviceCallback
  • VideoPortGetRegistryParameters with the CallbackRoutine parameter set to point to a driver-supplied HwVidQueryNamedValueCallback

VideoPortGetDeviceData and VideoPortGetRegistryParameters retrieve information from a different key in the registry. Consequently, each requires the miniport driver to supply a system-defined HwVid..Callback function with different formal parameters.

Neither of the HwVid..Callbacks can retrieve configuration information about display driver defaults from the registry. This is because they are typically called before any display drivers have been loaded by the system.

A miniport driver also can call VideoPortSetRegistryParameters to store information, such as information about the chip and DAC type, in the registry under the adapter key. For more information on storing hardware information in the registry, see Setting Hardware Information in the Registry. To retrieve the information from the registry later, the miniport driver calls VideoPortGetRegistryParameters.

Note that the registry information made available by calls to VideoPortGetDeviceData is volatile: it is re-created every time the system is loaded. Note also that the video port driver makes this information and the configuration information returned by VideoPortGetRegistryParameters available only to video miniport drivers. A miniport driver cannot call VideoPortSetRegistryParameters to pass configuration information to its corresponding display driver.


Processing Video Requests

All I/O requests that originate in a display driver's call to EngDeviceIoControl are mapped from IRPs to VRPs by the video port driver. The video port driver then calls the corresponding miniport driver's HwVidStartIO function with a pointer to each VIDEO_REQUEST_PACKET structure that it sets up. All VRPs sent to HwVidStartIO have the IoControlCode member set to an IOCTL_VIDEO_XXX.

The video port driver also manages the synchronization of incoming requests for all video miniport drivers by sending each miniport driver's HwVidStartIO routine only one VRP for processing at a time. HwVidStartIO owns each input VRP until the miniport driver completes the requested operation and returns control. Until a miniport driver completes the current VRP, the video port driver holds on to any outstanding IRPs that the I/O Manager sends in response to subsequent calls to EngDeviceIoControl by the corresponding display driver.

On receipt of a video request, HwVidStartIO must examine the VRP, process the video request on the adapter, set the appropriate status and other information in the VRP, and return TRUE.


System-Defined IOCTL_VIDEO_XXX Requests

Typically, most video miniport drivers support the following requests:

IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES

IOCTL_VIDEO_QUERY_AVAIL_MODES

IOCTL_VIDEO_QUERY_CURRENT_MODE

IOCTL_VIDEO_SET_CURRENT_MODE

IOCTL_VIDEO_RESET_DEVICE

IOCTL_VIDEO_MAP_VIDEO_MEMORY

IOCTL_VIDEO_UNMAP_VIDEO_MEMORY

IOCTL_VIDEO_SHARE_VIDEO_MEMORY

IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY

IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES

IOCTL_VIDEO_FREE_PUBLIC_ACCESS_RANGES

IOCTL_VIDEO_GET_POWER_MANAGEMENT

IOCTL_VIDEO_SET_POWER_MANAGEMENT

IOCTL_VIDEO_GET_CHILD_STATE

IOCTL_VIDEO_SET_CHILD_STATE_CONFIGURATION

IOCTL_VIDEO_VALIDATE_CHILD_STATE_CONFIGURATION

Depending on the adapter's features, video miniport drivers can support the following additional requests:

IOCTL_VIDEO_QUERY_COLOR_CAPABILITIES

IOCTL_VIDEO_SET_COLOR_REGISTERS (required if the device has a palette)

IOCTL_VIDEO_DISABLE_POINTER

IOCTL_VIDEO_ENABLE_POINTER

IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES

IOCTL_VIDEO_QUERY_POINTER_ATTR

IOCTL_VIDEO_SET_POINTER_ATTR

IOCTL_VIDEO_QUERY_POINTER_POSITION

IOCTL_VIDEO_SET_POINTER_POSITION

IOCTL_VIDEO_HANDLE_VIDEOPARAMETERS

IOCTL_VIDEO_SWITCH_DUALVIEW

VGA-compatible SVGA miniport drivers are required to support the following additional requests:

IOCTL_VIDEO_SAVE_HARDWARE_STATE

IOCTL_VIDEO_RESTORE_HARDWARE_STATE

IOCTL_VIDEO_DISABLE_CURSOR

IOCTL_VIDEO_ENABLE_CURSOR

IOCTL_VIDEO_QUERY_CURSOR_ATTR

IOCTL_VIDEO_SET_CURSOR_ATTR

IOCTL_VIDEO_QUERY_CURSOR_POSITION

IOCTL_VIDEO_SET_CURSOR_POSITION

IOCTL_VIDEO_GET_BANK_SELECT_CODE

IOCTL_VIDEO_SET_PALETTE_REGISTERS

IOCTL_VIDEO_LOAD_AND_SET_FONT

Details for each IOCTL can be found in Video I/O Control Codes. Miniport driver writers should not use undocumented system-defined IOCTLs.


Privately Defined Display-Miniport IOCTL_VIDEO_XXX Requests

A miniport driver can define one or more private I/O control codes for its corresponding display driver.

However, only a specific display-and-miniport driver pair can use privately defined I/O control codes. That is, a miniport driver designed to run under an existing display driver should not define private I/O control codes because the existing display driver cannot make new I/O control requests without being rewritten and, possibly, without breaking existing miniport drivers it already uses. An existing or generic display driver layered over many different models of adapters, such as SVGA adapters, also cannot rely on a privately defined I/O control code to have the same effects in every underlying miniport driver.

For more information on defining private I/O control codes, see Defining I/O Control Codes.


Handling Unsupported IOCTL_VIDEO_XXX Requests

Every HwVidStartIO function also must handle the receipt of an unsupported IOCTL_VIDEO_XXX, as follows:

  1. Set the input VRP's Status field to ERROR_INVALID_FUNCTION.
  2. Set the input VRP's Information field to zero.
  3. Return TRUE to indicate the request was processed.

See the VIDEO_REQUEST_PACKET and STATUS_BLOCK structures for more details.


Supporting Plug and Play and Power Management in a Video Miniport

All Windows® 2000 and later miniport drivers must support Plug and Play and Power Management. This includes the ability to enumerate child devices such as DDC monitors, I2C (I2C) devices, and secondary adapters.

The video port driver manages most of the PnP requirements for the miniport driver, including creating the FDO (Functional Device Object) and receiving and dispatching PnP-specific IRPs on the miniport driver's behalf.

Miniport drivers must implement the following functions to support PnP and Power Management:

HwVidSetPowerState

HwVidGetPowerState

HwVidGetVideoChildDescriptor

The graphics adapter for a legacy miniport driver cannot be removed from the system while the system is running, nor are legacy miniport drivers automatically detected when added to a running system.

See Child Devices of the Graphics Adapter for more information about detecting and communicating with an adapter's child devices. For general information about Plug and Play drivers, see Plug and Play.


Using AGP in the Video Miniport

The video port driver provides AGP (Accelerated Graphics Port) support that allows the miniport driver's device to directly access system (physical) memory.

To use AGP, a miniport driver must first query the video port driver-implemented AGP support routines by calling VideoPortQueryServices with its ServicesType parameter set to VideoPortServicesAGP, and its Interface pointer set to the address of either a VIDEO_PORT_AGP_INTERFACE or VIDEO_PORT_AGP_INTERFACE_2 structure.

The miniport driver allocates memory for each of these structures, and must initialize the Size and Version members of each prior to the call to VideoPortQueryServices. The video port returns pointers to its AGP support routines in the miniport driver-allocated VIDEO_PORT_AGP_INTERFACE structure passed to VideoPortQueryServices.

The only difference between the two structures is that the VIDEO_PORT_AGP_INTERFACE_2 structure has one additional member, AgpSetRate, a pointer to the AgpSetRate function. This function can be used to change the data transfer rate for an AGP chipset. When querying for AGP services, miniport drivers should first call VideoPortQueryServices with pInterface set to the address of a VIDEO_PORT_AGP_INTERFACE_2 structure. If that call fails, the miniport driver should call VideoPortQueryServices, this time passing the address of a VIDEO_PORT_AGP_INTERFACE structure.

A miniport driver can tailor its AGP memory usage based on the amount of physical memory in the system. This information is contained in the AgpAllocationLimit member of the VIDEO_PORT_AGP_INTERFACE and VIDEO_PORT_AGP_INTERFACE_2 structures.


Accessing System Memory through AGP

The miniport driver should call the following video port driver-supplied functions to enable its device to access main memory:

  1. Call AgpReservePhysical to reserve a range of physical addresses on the system bus to which the AGP controller can respond.
  2. Call AgpCommitPhysical to lock physical memory and have it mapped to a portion of the AGP-decodable physical address range returned by AgpReservePhysical. The miniport driver can call AgpCommitPhysical several times to do many smaller commitments rather than one large one.

Then, for an application to be able to see and use this committed AGP-controlled memory, the video miniport driver must call the following functions:

  1. Call AgpReserveVirtual to reserve a range of virtual addresses in the application's address space.
  2. Call AgpCommitVirtual to lock virtual memory and have the virtual addresses mapped to the AGP-decodable physical address range returned by AgpReservePhysical.

An application can access committed virtual memory as if it were contiguous.


Releasing Memory from AGP Use

The miniport driver is responsible for freeing and releasing all virtual and physical memory that it has reserved and committed as outlined in Accessing System Memory through AGP. It does so by calling the following video port driver AGP service routines:

  • AgpFreeVirtual unmaps virtual memory locked by a prior call to AgpCommitVirtual.
  • AgpReleaseVirtual releases a range of virtual addresses reserved by a prior call to AgpReserveVirtual.
  • AgpFreePhysical unmaps physical memory locked by a prior call to AgpCommitPhysical.
  • AgpReleasePhysical releases a range of physical addresses reserved by a prior call to AgpReservePhysical.


Child Devices of the Graphics Adapter

The following sections discuss issues that affect miniport drivers of graphics adapters with one or more child devices:

Detecting Child Devices

Communicating with the Driver of a Child Device

Using I2C to Communicate with a Child Device


Detecting Child Devices

You must implement HwVidGetVideoChildDescriptor in your miniport driver for the Plug and Play Manager to be able to detect child devices of a graphics adapter.

By default, HwVidGetVideoChildDescriptor cannot be called until after the parent device is started; that is, HwVidGetVideoChildDescriptor cannot be called until after HwVidFindAdapter has completed. To override this default, thus allowing child enumeration to occur at any time, you can set the AllowEarlyEnumeration member of VIDEO_HW_INITIALIZATION_DATA to TRUE.

Some devices generate an interrupt when new hardware is connected to the system or when existing hardware is disconnected from the system. To handle such an interrupt, the miniport driver should do the following:

  • Implement a DPC (PMINIPORT_DPC_ROUTINE) that calls VideoPortEnumerateChildren.
  • Implement an interrupt handler (HwVidInterrupt) that calls VideoPortQueueDPC to queue the DPC when an interrupt on the device occurs.

VideoPortEnumerateChildren forces the re-enumeration of the adapter's child devices by causing the miniport driver's HwVidGetVideoChildDescriptor function to be called for each of the parent device's children. The Plug and Play Manager will update the relationship between the parent device and its children accordingly.


Communicating with the Driver of a Child Device

A video miniport driver and the driver of a child device can mutually define an interface that allows the child driver to communicate with its hardware through the parent miniport driver. The child driver obtains this interface by sending an IRP_MN_QUERY_INTERFACE request to the video port driver for the parent miniport driver. Upon receiving such a request, the video port driver calls the miniport driver's HwVidQueryInterface function, if it is defined, and the miniport driver returns a pointer to the interface. The driver of the child device can then call into the miniport driver through the functions exposed by HwVidQueryInterface at any time.

If the miniport driver does not implement HwVidQueryInterface or fails the call, the video port driver passes the request to the parent of the miniport driver's device. If a child driver sends an IRP_MN_QUERY_INTERFACE to another child of the miniport driver and the other child driver does not implement HwVidQueryInterface or fails the call, the video port driver returns an error.

Because the child driver can call into the miniport driver without the video port driver's knowledge, the miniport driver must synchronize access to itself in all of the functions exposed by HwVidQueryInterface. It does this by calling VideoPortAcquireDeviceLock and VideoPortReleaseDeviceLock to grab and release the video port driver-maintained device lock, respectively.

A child device is enumerated by HwVidGetVideoChildDescriptor.


Using I2C to Communicate with a Child Device

On Microsoft® Windows® XP and later, after the Plug and Play Manager has enumerated a video adapter's child devices, the miniport driver can communicate with the adapter's child devices on an I2C bus using the I2C protocol. Communication between the miniport driver and WDM drivers for those devices on an I2C bus can occur via a software interface exposed by the miniport driver (as described in Communicating with the Driver of a Child Device). The miniport driver can initiate physical communication between those devices on the I2C bus by way of a new hardware interface exposed by the video port driver. If the miniport driver needs the I2C master device (usually the graphics chip) to read from or write to a physical child device over the I2C bus, it can use the hardware I2C interface provided by the video port driver's VideoPortQueryServices routine. Note that this communication over the I2C bus is limited strictly to hardware devices on the same I2C bus. Miniport driver writers are strongly encouraged to use these routines for all such communication.

This mode of communication is also useful in cases where a video adapter has components for which there is no WDM driver. For example, a video adapter may have a daughter board or circuit that is used to send the video image to a digital flat panel. In this case, the miniport driver can make use of the hardware I2C interface provided by VideoPortQueryServices to send commands to that circuit over the I2C bus.

Communicating with Child Devices Through the I2C Interface

The preceding figure illustrates how a miniport driver can initiate communication between two hardware devices on an I2C bus.

To take advantage of the video port's I2C routines, the miniport driver must query the video port driver for an I2C interface. In preparation for this, the miniport driver must allocate a VIDEO_PORT_I2C_INTERFACE structure, and initialize its first two members (the Size and Version members) to appropriate values. The miniport driver then calls the video port driver's VideoPortQueryServices routine, setting the servicesType parameter to VideoPortServicesI2C, and setting the pInterface parameter to the partially-initialized VIDEO_PORT_I2C_INTERFACE structure.

If the call to VideoPortQueryServices is successful, the video port driver fills in the remaining members of the VIDEO_PORT_I2C_INTERFACE structure, including the addresses of four I2C routines: I2CStart, I2CStop, I2CRead, and I2CWrite.

I2CStart and I2CStop are used, respectively, to initiate communication with the child device, and to terminate communication with it.

I2CRead reads a specified number of bytes from the child device; I2CWrite writes a specified number of bytes to it.


Interrupts in the Video Miniport

The miniport driver for an adapter that generates interrupts must implement a HwVidInterrupt routine. The miniport driver's DriverEntry routine should initialize the HwInterrupt member of the VIDEO_HW_INITIALIZATION_DATA structure to point to the interrupt handler.

The video port driver sets up an interrupt object for the miniport driver if the adapter generates interrupts. Because it is created and managed by the video port driver, a miniport driver writer needs no further information about interrupt objects.

If the miniport driver's HwVidFindAdapter function finds that the video adapter does not actually generate interrupts or that it cannot determine a valid interrupt vector/level for the adapter, HwVidFindAdapter should set both InterruptLevel and InterruptVector in the VIDEO_PORT_CONFIG_INFO structure to zero.

When HwVidFindAdapter returns control, the video port driver checks the interrupt configuration members in VIDEO_PORT_CONFIG_INFO and, if both are zero, does not connect an interrupt for the miniport driver. Explicitly setting both interrupt configuration members to zero in HwVidFindAdapter disables the HwVidInterrupt entry point, if any, that was set up by the miniport driver's DriverEntry function.

Note that HwVidInterrupt can access the miniport driver's device extension since it is nonpaged. Depending on the design of the miniport driver, it might be impossible for other driver functions to share the device extension or a particular area of the device extension with HwVidInterrupt safely.

For example, suppose the miniport driver's HwVidStartIO function is accessing the device extension when the adapter interrupts, HwVidInterrupt is run on another processor, and HwVidInterrupt also accesses the device extension. If such a situation might occur, HwVidStartIO should call VideoPortSynchronizeExecution with a driver-supplied HwVidSynchronizeExecutionCallback function.

A video miniport driver should adhere to the following two rules:

  1. Whenever the miniport driver and hardware are in any state other than D0, the hardware never generates an interrupt.
  2. Because of Rule 1, a device driver ISR should never act on an interrupt if the power state is D3 (it should return FALSE).


When to Implement a HwVidSynchronizeExecutionCallback Routine

Miniport drivers for adapters that do not generate interrupts seldom call VideoPortSynchronizeExecution with a HwVidSynchronizeExecutionCallback function.

In fact, even miniport drivers that have a HwVidInterrupt function do not necessarily have a HwVidSynchronizeExecutionCallback function. Because the video port driver does not send a request to a miniport driver's HwVidStartIO function until it completes processing of the preceding request (see Processing Video Requests for more information), miniport drivers rarely call VideoPortSynchronizeExecution.

There are two possible uses for a miniport driver's HwVidSynchronizeExecutionCallback function:

  • To access the adapter registers using the miniport driver's device extension for a driver function other than the HwVidInterrupt function.

    When the HwVidSynchronizeExecutionCallback function is given control, interrupts from the adapter are masked off so the miniport driver's HwVidInterrupt function cannot change state in the device extension while the HwVidSynchronizeExecutionCallback function is running in an SMP machine.

  • To write commands to the adapter registers or ports very quickly if the adapter requires it.

    When the HwVidSynchronizeExecutionCallback function is given control, almost all system interrupts are masked off, so the HwVidSynchronizeExecutionCallback function cannot be preempted by a device (or even, a clock) interrupt.

    An HwVidSynchronizeExecutionCallback function must return control as quickly as possible.

With the first type of HwVidSynchronizeExecutionCallback function, the miniport driver calls VideoPortSynchronizeExecution with the Priority set to VpMediumPriority. With the second type of HwVidSynchronizeExecutionCallback function, the miniport driver also makes this call with the Priority set to VpMediumPriority if the driver has no HwVidInterrupt function. Otherwise, such a miniport driver makes this call with the Priority set to VpHighPriority.

In general, a miniport driver should not call VideoPortSynchronizeExecution with the second type of HwVidSynchronizeExecutionCallback function unless the driver designer has no other alternative: that is, unless the adapter is such that it must be programmed with system interrupts masked off. Otherwise, the miniport driver should call VideoPortSynchronizeExecution with the Priority set to VpLowPriority.

A HwVidSynchronizeExecutionCallback function, like a HwVidInterrupt function, cannot be pageable and cannot call certain VideoPort Xxx functions without bringing down the system. For a summary of VideoPort Xxx functions that the HwVidSynchronizeExecutionCallback function can call safely, see HwVidInterrupt.


Timers in the Video Miniport

Any miniport driver can have an HwVidTimer function at the discretion of the driver writer. An HwVidTimer function allows the miniport driver to time out operations or to monitor state changes over a coarser-grained interval than is possible by calling VideoPortStallExecution. HwVidTimer also does not prevent other system operations from occurring as VideoPortStallExecution does.

For example, a miniport driver for an adapter that emulates VGA functionality might have an HwVidTimer function that monitors the status of its adapter's "VGA" registers periodically so the driver can emulate VGA-style graphics.

After a call to VideoPortStartTimer, the port driver calls HwVidTimer once every second until the miniport calls VideoPortStopTimer. A miniport driver can enable and disable calls to the HwVidTimer function repeatedly.

Note that an HwVidTimer function cannot disable calls to itself with VideoPortStopTimer. Another miniport driver function must control the enabling or disabling of calls to an HwVidTimer function through the use of VideoPortStartTimer and VideoPortStopTimer.


Using Spin Locks in Video Miniport Drivers

The video port driver supports multiprocessor synchronization in the video miniport driver by providing spin lock functions to protect data when one or more miniport driver threads are running at or below IRQL DISPATCH_LEVEL. The video port driver's spin lock functions enable miniport driver threads to create, acquire, release, and destroy spin locks. The video port driver provides these functions because video miniport driver writers must implement miniport drivers using functions provided exclusively by the video port driver. For a general discussion on spin locks, see Spin Locks.

Before a video miniport driver can use a spin lock, it must create the spin lock by calling VideoPortCreateSpinLock. After the spin lock has been created, a thread can attempt to acquire the spin lock by a call to either VideoPortAcquireSpinLock or VideoPortAcquireSpinLockAtDpcLevel. The first function of this pair can be used when the miniport driver's thread is at or below IRQL DISPATCH_LEVEL. The second function can be used only when the thread is running at IRQL DISPATCH_LEVEL.

When the thread that is holding the spin lock has completed its task, the miniport driver should release the spin lock. If the thread acquired the spin lock in a call to VideoPortAcquireSpinLock, it should use VideoPortReleaseSpinLock to release the spin lock. In the call to VideoPortReleaseSpinLock, the thread must pass the same value in the NewIrql parameter that it received in the OldIrql parameter of VideoPortAcquireSpinLock when that function returned. If the thread called VideoPortAcquireSpinLockAtDpcLevel, it should call VideoPortReleaseSpinLockFromDpcLevel to release the spin lock.

When the miniport driver has no further use for the spin lock, it should destroy the spin lock by a call to VideoPortDeleteSpinLock.


Resetting the Adapter in the Video Miniport

Every miniport driver must have an HwVidResetHw function if its adapter cannot be reset to an initialized state without a hard reboot of the machine.

HwVidResetHw is called by the HAL if the machine is about to crash or if the user initiates a soft reboot of the machine. HwVidResetHw resets the adapter to a specified character mode, so the HAL can display crash-dump information as it shuts down the system or initialization information during a soft reboot.

HwVidResetHw cannot call the BIOS, cannot call any pageable code, nor may it be made pageable. If possible, it should call only the VideoPortRead Xxx and VideoPortWrite Xxx functions, but it also can call any of the following:

VideoPortStallExecution

VideoPortZeroDeviceMemory

VideoPortZeroMemory


Video Port Driver Support for Busmaster DMA

Beginning with Windows XP, the operating system graphics interface supports DMA on PCI busmaster devices. Video miniport drivers of PCI busmaster devices can implement the following types of DMA support using helper functions supplied by the video port driver:

  • Packet-based DMA

    In packet-based DMA, data is transferred directly between the requestor's space and the device. Since the requestor's space might not be contiguous, packet-based DMA is more efficient on those devices with hardware scatter/gather support. Packet-based DMA is an ideal choice for moving large amounts of "dumb" data between user space and the device.

  • Common-buffer DMA

    In common-buffer DMA, a buffer is shared between (hence, common to), and used by both the host and the device for repeated DMA operations. Some drivers use common-buffer DMA to upload driver-manipulated data, such as a series of commands, to the graphics engine. The common buffer is contiguous and is always accessible to both the device and the host CPU.

    The common buffer is a precious system resource. For better overall driver and system performance, drivers should use common-buffer DMA as economically as possible.

Depending on the nature of the busmaster adapter, some miniport drivers use packet-based DMA exclusively, others use common-buffer DMA exclusively, and some use both.

Regardless of which type of DMA is used, the miniport driver should call VideoPortGetDmaAdapter to get a pointer to the VP_DMA_ADAPTER structure and use it for subsequent DMA functions calls. When there is no longer any need for continued DMA operations, the miniport driver should call VideoPortPutDmaAdapter to discard the adapter object.

The following subsections describe how to use the packet-based and common-buffer DMA support supplied by the video port driver.

Packet-Based Busmaster DMA

Common-Buffer Busmaster DMA

Points to Consider When Using DMA


Packet-Based Busmaster DMA

Ordinarily, a display driver initiates a DMA operation by sending a transfer request to the miniport driver. When a miniport driver supporting packet-based DMA operations receives such a request, it first locks the buffer involved in the data transfer. The miniport driver then initiates the transfer by calling the video port driver's VideoPortStartDma function, which in turn calls the miniport driver's HwVidExecuteDma callback routine to carry out the data transfer. This DMA operation is handled asynchronously: VideoPortStartDma does not wait for the DMA operation to complete before returning control to the miniport driver.

Depending on the size of the transfer request and the number of system resources assigned to the adapter, the driver may not be able to transfer all of the data in a single DMA operation. The miniport driver should inspect the actual transfer size returned in order to find out whether there is more data to be transferred. As soon as the DMA hardware finishes the current transfer, the miniport driver should call the video port driver's VideoPortCompleteDma function to complete the current DMA operation. If there is still data remaining to be transferred, the miniport driver repeats the process of calling the video port driver's VideoPortStartDma and VideoPortCompleteDma functions iteratively until no more data remains to be transferred. When all of the data has been transferred, the miniport driver should unlock the buffer.

The miniport driver performs the following sequence of operations to use packet-based DMA:

  1. Report hardware capabilities to the system and acquire an adapter object.

    The miniport driver calls the video port driver's VideoPortGetDmaAdapter function, which returns a pointer to a VP_DMA_ADAPTER structure. This is usually done at initialization time, typically within the miniport driver's HwVidFindAdapter routine. The miniport driver uses this pointer for subsequent DMA operations.

  2. Lock host memory.

    The miniport driver calls the video port driver's VideoPortLockBuffer function, which probes the buffer, makes those memory pages resident, and locks them.

  3. Start the DMA transfer.

    The miniport driver calls the video port driver's VideoPortStartDma function, which flushes the host processor memory caches, builds the scatter/gather list, and calls the miniport driver's HwVidExecuteDma callback routine to carry out the DMA operation asynchronously. VideoPortStartDma returns control to the miniport driver without waiting for the DMA operation to complete.

  4. Complete the DMA transfer.

    The miniport driver should call the video port driver's VideoPortCompleteDma function as soon as the hardware finishes the DMA operation. Many video adapters generate an interrupt when a DMA operation is complete. For example, a system with this type of adapter could react to the interrupt in the following way. When the hardware generates the interrupt to notify the miniport driver that the DMA operation has completed, the miniport driver's interrupt service routine (ISR) calls the video port driver's VideoPortQueueDpc function to queue a DPC routine, which in turn calls the video port driver's VideoPortCompleteDma function. The ISR cannot directly call VideoPortCompleteDma since this video port driver function must be called at or below DISPATCH level.

    VideoPortCompleteDma flushes any data remaining in the busmaster adapter's internal cache, and frees any unused resources (including the scatter/gather list built by VideoPortStartDma).

    If only part of the data has been transferred (due to limitations on the number of available map registers, for example), the miniport driver must make repeated calls to VideoPortStartDma and VideoPortCompleteDma until all of the data has been transferred.

  5. Unlock host memory.

    When all of the data has been transferred, the miniport driver should call the video port driver's VideoPortUnlockBuffer function to unlock the data buffer it acquired in the second step.

  6. Discard the adapter object.

    This step is optional. If, for some reason, the miniport driver decides that there will be no further DMA operations for the rest of its lifetime, it should discard the DMA adapter object by calling the video port driver's VideoPortPutDmaAdapter function.

For more information on the general initialization sequence of the miniport driver, see Video Miniport Initialization.


Common-Buffer Busmaster DMA

The miniport driver performs the following sequence of operations to use common-buffer DMA:

  1. Get an adapter object.

    The miniport driver calls the video port driver's VideoPortGetDmaAdapter function, usually within the miniport driver's HwVidFindAdapter routine, to get a pointer to a VP_DMA_ADAPTER structure. The miniport driver uses this pointer for subsequent DMA operations.

  2. Allocate a common buffer.

    The miniport driver calls the video port driver's VideoPortAllocateCommonBuffer function, using the pointer obtained in the previous step.

  3. Release the common buffer.

    When the miniport driver no longer requires the common buffer, it calls the video port driver's VideoPortReleaseCommonBuffer function.

  4. Discard the adapter object.

    This step is optional. If, for some reason, the miniport driver decides that there will be no further DMA operations for the rest of its lifetime, it should discard the DMA adapter object by calling the video port driver's VideoPortPutDmaAdapter function.


Points to Consider When Using DMA

This section provides some important points to consider if you plan to use DMA operations in your miniport driver.

Additional Notes on VideoPortStartDma

The display driver usually sends transfer requests to the miniport driver, which actually carries out those DMA transfers. The display driver cannot assume that just because its DMA engine is idle, all data in a transfer request has been transferred. This is because the miniport driver needs to call VideoPortStartDma and VideoPortCompleteDma multiple times for a large transfer request. The hardware's DMA engine is idle between two such DMA operations, even though there might be additional data to transfer. It is the miniport driver's responsibility to inform the display driver when the transfer request has been completely accomplished.

The Context parameter of VideoPortStartDma should point to nonpaged memory, such as memory in the hardware extension. This parameter is passed through to the miniport driver's HwVidExecuteDma callback routine, which runs at DISPATCH level.

DMA and Interrupts

For many devices, an interrupt is generated when a hardware DMA operation is complete. The video miniport driver's interrupt service routine (ISR) should queue a DPC routine for further DMA-related tasks. Do not call the video port driver's DMA functions in an ISR since they can only be called at or below DISPATCH level.

It is safe to check the size being transferred in the aforementioned DPC routine, even if the VideoPortStartDma function has not yet returned, since the variable pointed to by the pLength argument of VideoPortStartDma has already been updated at the time HwVidExecuteDma was called.

Logical Addresses Versus Physical Addresses

The video port driver's DMA implementation uses the concept of logical addresses, which are addresses used by the DMA hardware. Logical addresses can be different from physical addresses. The video port driver-provided DMA functions take into account any platform-specific memory restrictions. For this reason, it is important to use the video port driver DMA functions instead of such kernel-mode functions as MmGetPhysicalAddress. Please refer to Adapter Objects and DMA for more information about logical addresses.

Concurrent DMA

For devices that support concurrent DMA transfers, either on a DMA controller that supports simultaneous reads and writes, or on two separate DMA controllers, miniport drivers should obtain a separate DMA adapter object for each concurrent path. For example, if a device has two DMA controllers that work in parallel, the miniport driver should make two calls to VideoPortGetDmaAdapter, thereby obtaining pointers to two VP_DMA_ADAPTER structures. After that, whenever the miniport driver makes a DMA transfer request of a particular DMA controller, it should use the appropriate pointer in that request.


Using Events in Video Miniport Drivers

The video port driver provides support for events, a type of kernel dispatcher object that can be used to synchronize two threads running below DPC level. A video miniport driver can use events to synchronize access to the video hardware:

  • By the video miniport driver and the display driver
  • By the display or video miniport driver and another component, such as an OpenGL driver or an applet extension.

The following table lists the event-related functions that the video port driver supplies.

Function | Description
VideoPortClearEvent | Sets a given event object to the nonsignaled state.
VideoPortCreateEvent | Creates an event object.
VideoPortDeleteEvent | Deletes the specified event object.
VideoPortReadStateEvent | Returns the current state of a given event object: signaled or nonsignaled.
VideoPortSetEvent | Sets an event object to the signaled state if it was not already in that state, and returns the event object's previous state.
VideoPortWaitForSingleObject | Puts the current thread into a wait state until the given dispatch object is set to the signaled state, or (optionally) until the wait times out.

GDI also provides support for events to display drivers. See Using Events in Display Drivers for more information.

For a broader perspective on events, see Event Objects in the Kernel-Mode Drivers Design Guide.


Mirror Driver Support in the Miniport

Mirror driver support for video miniport drivers is provided by Windows 2000 and later, so a miniport driver must not have any special code to attempt such support. See Mirror Drivers for more information about display drivers in mirroring systems.

The requirements for a mirror driver miniport driver are minimal. The only functions which must be implemented are DriverEntry, which is exported by the miniport driver, and the following:

HwVidFindAdapter

HwVidInitialize

HwVidStartIo

Since there is no physical display device associated with a mirrored surface, all three of the functions shown in the preceding list can be empty implementations that always return success.


Supporting DualView

Many modern display adapters are able to drive two or more different display devices simultaneously. DualView, a feature of Microsoft Windows XP and later, provides system-level support for features similar to those of Multimonitor, but requires only a single display adapter. The graphics device interfaces (GDIs), and the end-user experiences, are identical for both DualView and Multimonitor.

SingleView Mode

In SingleView mode, a display adapter drives a single display device, regardless of the number of monitors. This is the usual mode for most of the display adapters that Windows 2000 and later operating system versions currently support.

DualView Mode

A computer in DualView mode can use a single display adapter (with multiple video ports) to drive multiple images on different monitors, with each display device portraying a different part of the desktop. The primary image displays the primary view; other images display secondary views.

The following subsections provide more information about DualView:

Enabling DualView

DualView Advanced Implementation Details


Enabling DualView

For a minimal DualView implementation, perform the following actions:

  • Just before the miniport driver's HwVidFindAdapter returns, call the new video port driver entry point, VideoPortCreateSecondaryDisplay, to generate a device extension for the secondary view. In the secondary device extension, add two new private members:
  1. A flag that indicates the device extension is for a secondary display
  2. A pointer that contains the address of the primary display's device extension
  • Four changes must be made in the miniport driver's HwVidStartIo callback routine, modifying the way it responds to the four IOCTL requests shown. The fourth item in the following list presents two ways of accomplishing the same outcome.
  1. In response to the IOCTL_VIDEO_MAP_VIDEO_MEMORY request, each view's frame buffer pointer and length should be properly set.
  2. The response to the IOCTL_VIDEO_SET_CURRENT_MODE request should be made specific to the secondary view.
  3. The response to the IOCTL_VIDEO_RESET_DEVICE request depends on whether the device is the primary or the secondary display. If the device is the primary display, carry out any needed operations. If the device is the secondary display, however, it is recommended that no action be taken.
  4. Change the response to the IOCTL_VIDEO_SHARE_VIDEO_MEMORY request, to get a correct map of both views. Note that for DirectDraw implementations, you can modify the DirectDraw function DdMapMemory to get the correct map of both views.
  • The display driver should take care of the adjustment between the logical frame buffer address and the physical video memory offset. This is especially important for DirectDraw implementations, because in Dualview the primary surface may start anywhere other than memory location 0. The display driver should notify DirectDraw by filling pHalInfo->vmiData.pvPrimary and pHalInfo->vmiData.fpPrimary with the appropriate video memory offsets on handling DrvGetDirectDrawInfo.

Additional Implementation Notes

  • HwVidInitialize is called only once for the primary device object. Any secondary device objects must be initialized in this call.
  • For a DrvAssertMode call in which bEnable is set to FALSE, the miniport driver should check the status of the other views. It should avoid turning off the video chip while other views are still active.
  • Never assume that drawing operations have the same drawing context (for example, color depth and stride). This is especially important for chips that use tile frame buffers.
  • GDI can only set the primary view on a built-in device. Some systems, such as laptop computers, have built-in monitor devices (LCDs), but can also be connected to external monitors. The miniport driver should mark a view as removable by passing the VIDEO_DUALVIEW_REMOVABLE flag when it calls VideoPortCreateSecondaryDisplay.
  • On laptop computers in DualView mode, hotkey switches should be disabled. On a video ACPI-enabled system, the miniport driver should reject IOCTL_VIDEO_VALIDATE_CHILD_STATE_CONFIGURATION requests.
  • For laptop computers supporting multi-child devices, the miniport driver should handle IOCTL_VIDEO_GET_CHILD_STATE requests and return logical child relationships (discussed in the following section).


DualView Advanced Implementation Details

An ideal DualView implementation should recognize when its secondary views are enabled or disabled. When the secondary views are disabled, the primary view should behave as it would without DualView enabled. This means that:

  • The primary display can access all parts of video memory.
  • On a laptop computer, the primary display can be switched to any of the child display devices.

Video Memory Arrangement

In an ideal DualView implementation, memory buffer usage is optimized so that the entire video memory is used by the primary display when the secondary display is disabled. This optimization is optional, however; the video memory allocation strategy to use is completely up to the driver writer.

When secondary views are disabled, the primary view should be able to access all parts of video memory to maximize system performance. When secondary views are enabled, however, the miniport driver should not just appropriate the primary view's memory. Instead, a miniport driver should reserve video memory for secondary views, prior to changing to DualView mode. Starting with Windows 2000 (and continuing for later operating system versions), there is a new video request, IOCTL_VIDEO_SWITCH_DUALVIEW to help driver writers handle video memory arrangement. When Windows 2000 (and later) handles a call to the ChangeDisplaySettings function (described in the Platform SDK documentation), it sends the IOCTL_VIDEO_SWITCH_DUALVIEW request to each DualView-related view before it attempts to change the mode. Drivers can use that information to make video memory arrangements in advance of their need.

Memory Arrangement with DualView Disabled

The preceding figure illustrates an arrangement of video memory with DualView disabled.

Memory Arrangement with DualView Enabled

The preceding figure illustrates a suggested arrangement of video memory with DualView enabled. Each view has its own screen buffer and offscreen heap.

Child Relationships

A typical mobile video chip has multiple child devices, such as LCD, CRT, and TV. In SingleView mode, as shown in the following figure, the primary view owns all of these child devices, while the secondary view owns none of them. A user can switch the primary view from one child device to another. Only one device can be active at a time.

SingleView Mode

In DualView mode, however, each child can be assigned to a different view; the question arises as to which view is associated with which child. The relationships between views and devices can be described in two ways: in terms of physical child relations and in terms of logical child relations.

Physical child relations reflect the relationship between the adapter's video chip and its display devices. After the system boots, the physical relationship between the video chip and the display devices never changes. In the preceding figure and the following figure, the video chip owns the LCD, CRT and TV display devices; hence, all three display devices are physical children of the video chip.

Logical child relations reflect the dynamic relationships between the views and the display devices. In the following figure, DualView has been enabled, and the situation is that the primary view (View 1) owns the LCD device, while the secondary view (View 2) owns both the CRT and TV devices. Another way to say this is that the LCD device is the logical child of the primary view, while the CRT and TV devices are the logical children of the secondary view. The miniport driver reports logical child relationships through the IOCTL_VIDEO_GET_CHILD_STATE request.

DualView Mode

One additional point remains. When DualView is enabled, the primary view may automatically switch children. In SingleView Mode, only the CRT, which is associated with the primary (and only) view, is active. All other display devices are inactive. After DualView has been enabled, the preceding figure shows the primary view has switched to display on the LCD device, while the CRT is a child of the secondary view. This switch might be necessary for a laptop computer due to the fact that the secondary view is removable, which means that the LCD device cannot be associated with that view. Whether and how to make this switch is totally under the control of miniport drivers.


TV Connector and Copy Protection Support in the Video Miniport

All video miniport drivers should handle VRPs with the IOCTL_VIDEO_HANDLE_VIDEOPARAMETERS I/O control code. This IOCTL is sent to the miniport driver to either query the capabilities and current settings of the TV connector and copy protection hardware or set the functionality of the copy protection hardware. The miniport driver determines the action to be performed by checking the dwCommand field of the VIDEOPARAMETERS structure, which is passed in the VRP's InputBuffer. The system will not allow DVD playback at all if a miniport driver does not handle this VRP.

If dwCommand is set to VP_COMMAND_GET, and the device does not support TV Out, then the miniport driver should return NO_ERROR in the Status member of the VRP's StatusBlock. It should also set the Information member of the VRP's StatusBlock to the size, in bytes, of the VIDEOPARAMETERS structure. It should either set dwFlags to zero or set dwTVStandard to VP_TV_STANDARD_WIN_VGA.

If dwCommand is set to VP_COMMAND_GET, and the device does support TV Out, the miniport driver should indicate this in the VIDEOPARAMETERS structure, by setting the dwTVStandard and dwCPStandard members. The miniport driver should also set the dwCPType member to reflect whether copy protection is supported. If copy protection is not turned on, the miniport driver will subsequently receive a call to turn it on.

The following sections provide implementation details for miniport drivers of devices that do have a TV connector:

Querying TV Connector and Copy Protection Hardware

Setting Copy Protection Hardware


Querying TV Connector and Copy Protection Hardware

The miniport driver should do the following with the VIDEOPARAMETERS structure when the dwCommand field is VP_COMMAND_GET and the device has a TV connector:

  • Verify the Guid (required).
  • Set both VP_FLAGS_TV_MODE and VP_FLAGS_TV_STANDARD in dwFlags if the hardware can change the mode and standard. The miniport driver should also set the appropriate flag bits for all other capabilities that it supports; for example, the miniport driver should set VP_FLAGS_TV_FLICKER if the device supports flicker filter.
  • Set the appropriate bit in dwMode to indicate the current display mode of the device (optional). The miniport driver sets VP_MODE_TV_PLAYBACK if the TV connector is actively displaying to a TV, sets VP_MODE_WIN_GRAPHICS if the device is displaying to a CRT only, or sets both mode bits if the device is displaying to both a TV and CRT.
  • Fill in dwAvailableModes with the playback modes that the device is capable of. All miniport drivers must set VP_MODE_WIN_GRAPHICS. If the device can turn on overscan and turn off the flicker filter, the miniport driver should also set VP_MODE_TV_PLAYBACK.
  • If the device is currently displaying through the TV connector, fill in dwTVStandard with the current world television standard being displayed (optional). If TV output is disabled, the miniport driver should just set the VP_TV_STANDARD_WIN_VGA bit.
  • Fill in dwAvailableTVStandard with all of the TV standards that the connector supports.
  • Set dwMaxUnscaledX and dwMaxUnscaledY to the largest x and y values that can be displayed on the TV without using scaling hardware (required).

If, in addition to a TV connector, the device also has copy protection hardware, the miniport driver should update the following additional fields of the VIDEOPARAMETERS structure:

  • Set VP_FLAGS_COPYPROTECT in dwFlags (as well as setting VP_FLAGS_TV_MODE and VP_FLAGS_TV_STANDARD).
  • Set dwCPType to the type(s) of copy protection supported.
  • Set dwCPStandard to the TV standards on which the copy protection works.


Setting TV Connector and Copy Protection Hardware

For any bit set by a miniport driver in VIDEOPARAMETERS' dwFlags member on a VP_COMMAND_GET, the miniport driver can perform a set on a VP_COMMAND_SET. It is the caller's responsibility to call the miniport driver to set only that functionality for which the miniport driver indicated support on a VP_COMMAND_GET. The miniport driver should respond to a VP_COMMAND_SET by setting the hardware with the value of each VIDEOPARAMETERS field for which the corresponding bit is set in dwFlags. For example:

  • If the miniport driver set the VP_FLAGS_TV_MODE bit on a VP_COMMAND_GET, then the miniport driver should change the mode from VP_MODE_WIN_GRAPHICS to VP_MODE_TV_PLAYBACK when VP_FLAGS_TV_MODE is set on a VP_COMMAND_SET.
  • If the miniport driver set the VP_FLAGS_TV_STANDARD bit on a VP_COMMAND_GET, then the miniport driver should change the TV standard to the standard indicated in dwTVStandard when VP_FLAGS_TV_STANDARD is set on a VP_COMMAND_SET.
  • If the miniport driver set the VP_FLAGS_CONTRAST bit on a VP_COMMAND_GET, then the miniport driver should set the contrast to the value in dwContrast when VP_FLAGS_CONTRAST is set on a VP_COMMAND_SET.

A VIDEOPARAMETERS field contains undefined data if the corresponding bit is not set in dwFlags.


Setting Copy Protection Hardware

Miniport drivers that returned VP_FLAGS_PROTECTED in VIDEOPARAMETERS's dwFlags member on a VP_COMMAND_GET should do the following in response to the VP_COMMAND_SET command, depending on the dwCPCommand member of the VIDEOPARAMETERS structure:

  • If dwCPCommand is VP_CP_CMD_ACTIVATE, the miniport driver should turn on copy protection and generate and return a unique copy protection key in dwCPKey.
  • If dwCPCommand is VP_CP_CMD_DEACTIVATE and the copy protection key in dwCPKey is valid, the miniport driver should turn off copy protection.
  • If dwCPCommand is VP_CP_CMD_CHANGE and the copy protection key in dwCPKey is valid, the miniport driver should change copy protection based on the data in based on the trigger data in bCP_APSTriggerBits.

Miniport drivers of devices that do not have copy protection hardware should simply return NO_ERROR in the Status field of the VRP's StatusBlock.


Multiple Session Copy Protection

The miniport driver of a device that has copy protection can optionally support multiple simultaneous copy protection sessions. To do so, the miniport driver should do the following:

  • Return a unique copy protection key in dwCPKey for each copy protection activation.
  • Keep copy protection enabled until all sessions have been temporarily turned off (through VP_CP_CMD_CHANGE) or deactivated (VP_CP_CMD_DEACTIVATE). For example, the miniport driver could increment or decrement a reference count every time copy protection is activated (VP_CP_CMD_ACTIVATE) or deactivated/turned off, disabling copy protection entirely only when the reference count is zero.


VGA-Compatible Miniport's SvgaHwIoPortXxx

VGA-compatible miniport drivers in x86-based machines replace the system-supplied VGA miniport driver. Therefore, VGA-compatible miniport drivers must have a set of SvgaHwIoPort Xxx functions to support full-screen MS-DOS applications as the system-supplied VGA miniport driver does.

The designer of a new VGA-compatible SVGA miniport driver should adapt one of the system-supplied SVGA miniport driver's SvgaHwIoPort Xxx functions to the adapter's features. As already mentioned in VGA-compatible x86 Based Miniports, miniport drivers for other types of adapters in x86-based machines can have a set of SvgaHwIoPort Xxx routines and provide the same support at the discretion of the miniport driver designer or if the miniport driver cannot be loaded while the system VGA miniport is loaded.


Windowed VDMs in x86-Based Machines

Each MS-DOS application runs as a Windows VDM, which in turn, runs as a Console Manager application in the Win32 protected subsystem.

In NT-based operating system platforms, a kernel-mode component called the V86 emulator traps I/O instructions issued by MS-DOS applications. As long as such an application runs within a window, its attempts to access video adapter ports are trapped and reflected back to the system-supplied video VDD, which emulates the behavior of the adapter for the application.

In other words, the display driver retains control of the video adapter while a VDM runs in a window.


Full-Screen VDMs in x86-based Machines

For performance reasons, when the user switches an MS-DOS application to full-screen mode in an x86-based machine, the display driver yields control of the adapter. The system VGA or a VGA-compatible miniport driver then hooks out from the V86 emulator all I/O instructions, such as application-issued IN, REP INSB/INSW/INSD, OUT, and REP OUTSB/OUTSW/OUTSD instructions, to the video I/O ports. These hooked I/O operations are forwarded to the VGA-compatible miniport driver's SvgaHwIoPort Xxx functions.

However, for faster performance, a miniport driver can call VideoPortSetTrappedEmulatorPorts to allow some I/O ports to be accessed directly by the application. The miniport driver continues to hook other I/O ports with its SvgaHwIoPort Xxx to validate the application-issued instruction stream to those ports.

To prevent a full-screen application from issuing a sequence of instructions that might hang the machine, the SvgaHwIoPort Xxx functions monitor the application instruction stream to a driver-determined set of adapter registers. A miniport driver must enable direct access only to I/O ports that are completely safe. For example, ports for the sequencer and miscellaneous output registers should always be hooked by the V86 emulator and trapped to the miniport driver-supplied SvgaHwIoPort Xxx functions for validation.

Direct access to I/O ports for the application is determined by the IOPM (named for the x86 I/O permission map) that the VGA-compatible miniport driver sets by calling VideoPortSetTrappedEmulatorPorts. Note that the miniport driver can adjust the IOPM by calling this function to have access ranges, describing I/O ports, released for direct access by the application or re-trapped to an SvgaHwIoPort Xxx function. The current IOPM determines which ports can be accessed directly by the application and which remain hooked by the V86 emulator and trapped to an SvgaHwIoPort Xxx function for validation.

By default, all I/O ports set up in such a miniport driver's emulator access ranges array are trapped to the corresponding SvgaHwIoPort Xxx function. However, VGA-compatible miniport drivers usually call VideoPortSetTrappedEmulatorPorts on receipt of an IOCTL_VIDEO_ENABLE_VDM request to reset the IOPM for the VDM to allow direct access to some of these I/O ports. Usually, such a driver allows direct access to all video adapter registers except the VGA sequencer registers and the miscellaneous output register, plus any SVGA adapter-specific registers that the driver writer has determined should always be validated by an SvgaHwIoPort Xxx function.


VGA-Compatible Miniport's HwFindAdapter

A VGA-compatible miniport driver's HwVidFindAdapter function (or registry HwVid..Callback) must set up the following in the VIDEO_PORT_CONFIG_INFO buffer:

  • NumEmulatorAccessEntries, indicating the number of entries in the EmulatorAccessEntries array
  • EmulatorAccessEntries, pointing to a static array containing the given number of EMULATOR_ACCESS_ENTRY-type elements, each describing a range of I/O ports hooked from the V86 emulator and, by default, forwarded to an SvgaHwIoPort Xxx function

    Each entry includes a starting I/O address, a range length, the size of access to be trapped (UCHAR, USHORT, or ULONG), whether the miniport driver supports input or output of string data through the I/O port(s), and the miniport driver-supplied SvgaHwIoPort Xxx function that actually validates and, possibly, transfers the data. Each SvgaHwIoPort Xxx function handles read (IN or REP INSB/INSW/INSD) and/or write (OUT or REP OUTSB/OUTSW/OUTSD) transfers of UCHAR-, USHORT-, or ULONG-sized data.

  • EmulatorAccessEntriesContext, a pointer to storage, such as an area in the miniport driver's device extension, in which the miniport driver's SvgaHwIoPort Xxx functions can batch a sequence of application-issued instructions that require validation
  • VdmPhysicalVideoMemoryAddress and VdmPhysicalVideoMemoryLength, describing a range of video memory that must be mapped into the VDM address space to support BIOS INT10 calls from full-screen MS-DOS applications

    The miniport driver can call the VideoPortInt10 function when such an application changes the video mode to one that the miniport driver's adapter can support.

  • HardwareStateSize, describing the minimum number of bytes required to store the hardware state for the adapter in response to an IOCTL_VIDEO_SAVE_HARDWARE_STATE request

    When the user switches a full-screen MS-DOS application to run in a window, the miniport driver must save the adapter state before the display driver regains control of the video adapter. Note that a VGA-compatible miniport driver also must support the reciprocal IOCTL_VIDEO_RESTORE_HARDWARE_STATE request because the user might switch the windowed application back to full-screen mode.

A VGA-compatible miniport driver's emulator access entries specify subsets of its access ranges array for the adapter. The emulator access entries can be and usually are all I/O ports in the mapped access ranges array set up by its HwVidFindAdapter function. The access ranges it passes in calls to VideoPortSetTrappedEmulatorPorts, defining the current IOPM and determining the I/O ports that are directly accessible by a full-screen MS-DOS application, specify subsets of the miniport driver's emulator access entries.


Validating Instructions in SvgaHwIoPortXxx

As already mentioned in VGA-Compatible Miniport's HwFindAdapter, the IOPM set for directly accessible I/O ports usually includes all SVGA registers except the sequencer registers and the miscellaneous output register, which the VGA-compatible miniport driver continues to monitor with its SvgaHwIoPort Xxx functions. The sequencer registers control internal chip timing on VGA-compatible video adapters. If a full-screen MS-DOS application touches other adapter registers during a synchronous reset, the machine can hang. Likewise, if the miscellaneous output register is set to select a nonexistent clock, the machine can hang.

VGA-compatible miniport drivers must ensure that full-screen MS-DOS applications do not issue instructions that cause the machine to hang. Each such miniport driver must supply SvgaHwIoPort Xxx functions that monitor application-issued instructions to the I/O ports for the adapter sequencer registers and miscellaneous output register. Each new VGA-compatible miniport driver for an adapter with special features also must monitor and continue to validate any I/O ports to which an application might send any instruction sequence that could hang the machine.

Whenever an application attempts to access the sequencer clock register, the SvgaHwIoPort Xxx function must change the IOPM in order to trap all instructions coming in during a synchronous reset. As soon as an application sends an instruction that affects the sequencer or attempts to write to the miscellaneous output register, the SvgaHwIoPort Xxx function should adjust the IOPM by calling VideoPortSetTrappedEmulatorPorts to disable direct access to all adapter registers.

The miniport driver-supplied SvgaHwIoPort Xxx functions should buffer subsequent IN (or INSB/INSW/INSD) and/or OUT (or OUTSB/OUTSW/OUTSD) instructions in the EmulatorAccessEntriesContext area it set up in the VIDEO_PORT_CONFIG_INFO (see VGA-Compatible Miniport's HwFindAdapter) until the synchronous reset is done, or until the application either restores the miscellaneous output register or resets it to a "safe" clock.

Then, the miniport driver is responsible for checking that the buffered instructions cannot hang the machine. If not, the miniport driver should process the buffered instructions, usually by calling VideoPortSynchronizeExecution with a driver-supplied HwVidSynchronizeExecutionCallback function. Otherwise, the miniport driver should discard the buffered instructions.


VGA-Compatible Miniport's HwVidStartIO

When the user switches a full-screen MS-DOS application back to running in a window, a VGA-compatible miniport driver's HwVidStartIO function is sent a VRP with the I/O control code IOCTL_VIDEO_SAVE_HARDWARE_STATE. The miniport driver must store the state of the adapter in case the user switches the application to full-screen mode again.

Note that the miniport driver's SvgaHwIoPort Xxx function might have buffered a sequence of application INs and/or OUTs, as described in Validating Instructions in SvgaHwIoPortXxx, when its HwVidStartIO routine is called to save the adapter state. In these circumstances, the miniport driver should save the current state, including the buffered instructions, so that the SvgaHwIoPort Xxx functions can resume validation operations exactly where they left off if the user switches the application to full-screen mode again.

When the miniport completes a save operation, the port driver automatically disables the current IOPM for VDMs and the miniport driver's SvgaHwIoPort Xxx functions. The video port driver restores the IOPM automatically if the application is switched to full-screen mode again. It also resumes calling the miniport driver's SvgaHwIoPort Xxx function, after it calls the miniport driver's HwVidStartIO routine with the IOCTL_VIDEO_RESTORE_HARDWARE_STATE request.


Converting a Windows NT 4.0 Miniport Driver to Windows 2000

A good Windows NT 4.0 and previous miniport driver can easily become a Windows 2000 and later miniport driver. The following are some of the updates necessary to provide Plug and Play support, which is required in Windows 2000 and later miniport drivers:

  • See Supporting Plug and Play and Power Management in a Video Miniport for a list of new functions that must be implemented. Be sure to initialize the new members of VIDEO_HW_INITIALIZATION_DATA to point to these new functions.
  • Update the call to VideoPortInitialize in your DriverEntry function. The fourth parameter (HwContext) must be NULL on Windows 2000 and later.
  • Update your HwVidFindAdapter function. For devices on an enumerable bus, HwVidFindAdapter must be changed as follows:
    • Remove most of your device detection code. This is because a call to HwVidFindAdapter on Windows 2000 means that the PnP Manager has already detected the device.
    • Call VideoPortGetAccessRanges to obtain the bus-relative physical addresses to which the device will respond. These addresses are assigned by the PnP Manager.
    • If the driver supports more than one device type, determine the type of device.
    • Ignore the Again parameter. This is because the system will call HwVidFindAdapter only once per device.

    For a device on a non-enumerable bus such as ISA, PnP still attempts to start the device, although it is the responsibility of HwVidFindAdapter to determine whether the device is actually present.

  • Update the .Mfg section of the driver's INF file to include the device and vendor ID. This is required so that the PnP Manager can associate the device with its INF file. Samples of the Windows NT 4.0 and updated Windows 2000 and later .Mfg sections follow:
    [ABC.Mfg]   ; Windows NT V4.0 INF
%ABC% ABC Graphics Accelerator A = abc
%ABC% ABC Graphics Accelerator B = abc

[ABC.Mfg]   ; Windows 2000 and later INF
%ABC% ABC Graphics Accelerator A = abc, PCI\VEN_ABCD&DEV_0123
%ABC% ABC Graphics Accelerator B = abc, PCI\VEN_ABCD&DEV_4567

    You can use the geninf.exe tool shipped with the Windows DDK to generate an INF. Keep in mind, however, that geninf.exe does not create an INF for Windows NT 4.0. You must modify the INF file produced by geninf.exe if you intend to support Windows NT 4.0 in addition to Windows 2000 and later operating system versions. See Creating Graphics INF Files for more details.

The Windows 2000 and later video port supports Windows NT 4.0 miniports as legacy drivers. The graphics adapter for a legacy miniport driver cannot be removed from the system while the system is running, nor are legacy miniports automatically detected when added to a running system.


Introduction to Printing

The Microsoft® Windows® 2000 and later printing architecture consists of a print spooler and a set of printer drivers. By calling device-independent Win32® printing and GDI functions, applications can create print jobs and send them to any of a variety of devices, including laser printers, vector plotters, raster printers, and fax machines. Printer drivers include a user interface component that allows users to control a printer's selectable options.

An application's calls to Win32 GDI functions are passed to the GDI graphics engine, which either spools the drawing instructions as an EMF file or, in conjunction with a printer driver, renders a printable image that can be sent to the spooler. Spooler components interpret EMF files, and they can insert page layout information and job control instructions into the data stream. The spooler then sends the data stream to the serial, parallel, or network port driver associated with the target printer's I/O port.

Spooler and driver components are designed to be replaceable, so hardware vendors can easily add support for new hardware. For more information about print spooler and driver components, see the following sections:

Print Spooler Architecture

Printer Driver Architecture

Support for a new printer usually requires only the creation of new data files for use with one of the Microsoft-supplied printer drivers. For more information about Microsoft's printer drivers, see the following sections:

Microsoft Universal Printer Driver

Microsoft Postscript Printer Driver

Microsoft Plotter Driver

You can customize the behavior of the Microsoft Universal Printer Driver and the Microsoft Postscript Printer Driver. For more information, see Customizing Microsoft's Printer Drivers. You can also customize the Windows 2000 and later print spooler. See Customizing Print Spooler Components.

Additional sections cover the following topics:

Internet Printing

Color Management for Printers

Installing and Configuring Printer Drivers

CPSUI (a tool for creating user interfaces based on property sheets)


Print Spooler Architecture

The Microsoft® Windows® 2000 and later print spooler is made up of a set of Microsoft-supplied and optional vendor-supplied components, with responsibilities that include:

  • Determining if a print job should be handled locally or across a network.
  • Accepting a data stream created by GDI, in conjunction with a printer driver, for output on a particular type of printer.
  • Spooling the data to a file (if spooling is enabled).
  • Selecting the first available physical printer in a logical printer queue.
  • Converting a data stream from a spooled format (such as EMF) to a format that can be sent to printer hardware (such as PCL).
  • Sending a data stream to printer hardware.
  • Maintaining a registry-based database for spooler components and printer forms.


Spooler Components

This section provides the following topics:

Introduction to Spooler Components

Print Providers


Introduction to Spooler Components

The primary components of the Microsoft® Windows® 2000 and later print spooler are illustrated in the following diagram.

Windows 2000 and Later Print Spooler Components

Application
Print application that creates a print job by calling GDI functions.
GDI
Graphics device interface (includes both user mode and kernel mode components).
Winspool.drv
This is the client interface into the spooler. It exports the functions that make up the spooler's Win32® API, and provides RPC stubs for accessing the server. (GDI is the primary client, but applications also call some of its Win32 functions.)
Spoolsv.exe
This is the spooler's API server. It is implemented as a Windows 2000 (or later) service that is started when the operating system is started. This module exports an RPC interface to the server side of the spooler's Win32 API. Clients of spoolsv.exe include winspool.drv (locally) and Win32spl.dll (remotely). The module implements some API functions, but most function calls are passed to a print provider by means of the router (spoolss.dll).
Spoolss.dll
This is the spooler's router. It determines which print provider to call, based on a printer name or handle supplied with each function call, and passes the function call to the correct provider.
Print Provider
The print provider that supports the specified print device.

If printer hardware is local to the system on which the application is running, the "client" and "server" are the same system (although this is not evident in the diagram).

All spooler components execute in user mode.


Print Providers

This section provides the following topics:

Introduction to Print Providers

Sample Print Provider

Print Provider Capabilities

Functions Defined by Print Providers

Local Print Provider


Introduction to Print Providers

Print providers are responsible for directing print jobs to local or remote print devices. They are also responsible for print queue management operations, such as starting, stopping, and enumerating a server's print queues. Print providers define a high-level, machine-independent, Operating System-independent view of a print server.

All print providers implement a common set of print provider capabilities. These capabilities are defined by a set of API functions, which are called by the spooler's router (spoolss.dll).

Most functions defined by print providers require a printer handle as input. A spooler client obtains a printer handle by calling OpenPrinter (described in the Platform SDK documentation) in winspool.drv, which calls the API server (spoolsv.exe). The spooler's router (spoolss.dll) calls each print provider's OpenPrinter function until one of them supplies a printer handle and a return value indicating the print provider recognizes the specified printer name. The router then returns its own handle to the API server. The router's handle includes both the printer handle and a provider handle. This handle is returned to the application so that subsequent calls from the application can be directed to the correct provider and printer.

Microsoft provides the following print providers with Windows 2000 and later:

localspl.dll
Local Print Provider. Handles all print jobs directed to printers that are managed from the local server.
win32spl.dll
Windows Network Print Provider. Handles print jobs directed to remote Win32 (NT-based-operating system or Windows for Workgroups) servers. When the job arrives at the remote server, it is passed to the server's local print provider.
nwprovau.dll
Novell NetWare Print Provider. Handles print jobs directed to Novell NetWare print servers.
inetpp.dll
HTTP Print Provider. Handles print jobs sent to a URL. (See Internet Printing.)

Vendors can create additional network print providers. For more information, see Writing a Network Print Provider.

The following diagram illustrates possible flow paths involving these print providers.

Print Provider Flow Paths

When viewing the diagram, you should consider the following points:

  • If the printer is managed by the client system, the print job is handled by the local print provider (localspl.dll). Printers managed by localspl.dll do not have to be physically local to the client; they can be directly connected to network cards.
  • If the printer is located on a NT-based-operating system server, the network provider (win32spl.dll) uses RPC to redirect calls from the client's router to the server's spoolsv.exe process. Because the printer is local to the server, the server's local print provider will handle the print job.
  • If the printer is located on some other type of server, it can be accessed by either the local print provider or by a network print provider that supports that server type, using data formats and network protocols supported by the server.
  • For the local print provider to access a remote printer, it must contain a port monitor that can use network protocols recognized by the remote printer or server.


Sample Print Provider

A sample print provider is included with this DDK. The sample is not a fully functioning print provider; it is a template containing skeletal implementations of the functions defined by print providers. Sample files are located in the pp subdirectory of the directory tree containing DDK samples.


Print Provider Capabilities

By supporting predefined sets of API functions, Windows 2000 and later print providers can supply the following capabilities:

  • Print Queue Management

    Adding, deleting, opening, closing, enumerating, and setting parameters for print queues. Also, providing notification of changes to a print queue's state.

  • Printer Driver Management

    Adding, deleting, enumerating, and specifying a directory for printer drivers.

  • Print Job Creation

    Starting and ending a document, starting and ending a document page, writing the job's data stream to a port, reading printer status information.

  • Print Job Scheduling

    Scheduling, enumerating, and setting parameters for a print job.

  • Forms Management

    Adding, deleting, enumerating, and setting parameters for print forms.

  • Print Processor Management

    Adding, deleting, enumerating, specifying a directory for and the data types supported by print processors.

  • Print Monitor Management

    Adding, deleting, and enumerating print monitors.

  • Port Management

    Adding, deleting, configuring, enumerating, and setting parameters for printer ports.

  • Registry Management

    Creating, deleting, and enumerating registry keys and values associated with a print provider.

  • Other Capabilities

    Displaying a message box, shutting down the print provider, reading a memory mapped spool file, providing a communication path between port monitor UI DLLs and port monitor server DLLs.

These capabilities are implemented as a set of functions defined by print providers.


Functions Defined by Print Providers

This topic lists all of the functions a print provider can supply. Most of these functions are described in the Platform SDK documentation. If the function is defined in this DDK, the function name provides a link to the associated reference page.

All print providers must supply pointers for all listed functions. However, most vendor-supplied print providers are "partial providers" which do not need to support many of the operations defined by the functions. Therefore, many of the function pointers can be NULL. For more information about partial print providers, see Writing a Network Print Provider.

In the following function lists, functions that must be supported are labeled "Required".

All print providers must export the initialization function, InitializePrintProvidor. Pointers to all the other functions must be supplied in a PRINTPROVIDOR structure. (Note that these two names are misspelled, but are consistent with the names appearing in the header file, winsplp.h.)

Functions are divided into the following groups:

Initialization Function

Print Queue Management Functions

Printer Driver Management Functions

Print Job Creation Functions

Print Job Scheduling Functions

Forms Management Functions

Print Processor Management Functions

Print Monitor Management Functions

Port Management Functions

Registry Management Functions

Other Functions

Initialization Function

Function | Description
InitializePrintProvidor (Required)
 | Initializes the print provider and returns pointers to supplied functions.

Print Queue Management Functions

Function | Description
AddPrinter
 | Adds a print queue to the list of those managed by the print provider, and associates a print processor with the print queue.
AddPrinterConnection
 | Creates a connection to the specified print queue.
ClosePrinter (Required)
 | Disables caller access to a specified print queue.
DeletePrinter
 | Deletes a print queue from the list of those managed by the print provider.
DeletePrinterConnection
 | Removes a connection to the specified print queue.
EnumPrinters (Required)
 | Enumerates the list of print queues currently managed by the print provider.
FindClosePrinterChangeNotification
 | Disables printer change notifications that were enabled by FindFirstPrinterChangeNotification.
FindFirstPrinterChangeNotification
 | Returns a handle to a wait object that the caller can use to wait for specified printer events.
GetPrinter (Required)
 | Returns current parameter values for a specified print queue.
OpenPrinter (Required)
 | Enables caller access to a specified print queue.
RefreshPrinterChangeNotification
 | Called by router if client calls FindNextPrinterChangeNotification (see the Platform SDK documentation) with the PRINTER_NOTIFY_OPTIONS_REFRESH flag set.
ResetPrinter
 | Modifies a print queue's data type or DEVMODE structure.
SetPrinter (Required)
 | Sets parameters for a specified print queue.
WaitForPrinterChange |
 | Obsolete.

Printer Driver Management Functions

Function | Description
AddPrinterDriver
 | Adds a specified printer's driver files to a specified server.
AddPrinterDriverEx
 | Same as AddPrinterDriver, with additional parameters.
DeletePrinterDriver
 | Deletes access to a specified printer's driver files, on a specified server.
DeletePrinterDriverEx
 | Same as DeletePrinterDriver, with additional parameters.
EnumPrinterDrivers
 | Returns a list of printer drivers that have been added to a specified server by calling AddPrinterDriver or AddPrinterDriverEx.
GetPrinterDriver
 | Returns information about a printer driver, which the caller can then pass to AddPrinterDriver. (The returned information is typically obtained from an .inf file.)
GetPrinterDriverEx
 | Same as GetPrinterDriver, with additional parameters.
GetPrinterDriverDirectory
 | Returns the name of the server's printer driver directory.

Print Job Creation Functions

Function | Description
AbortPrinter (Required) | Attempts to delete the current job from the specified print queue.
AddJob (Required) | Returns a job identifier and spool file path. The caller uses CreateFile and WriteFile to send data to the spool file.
EndDocPrinter (Required) | Performs job completion operations.
EndPagePrinter | Performs page completion operations.
ReadPrinter | Obtains status information from a bi-directional printer.
ScheduleJob (Required) | Informs the provider that a specified job can be scheduled. The job is specified by a job identifier previously returned by AddJob.
StartDocPrinter (Required) | Prepares the print provider to begin spooling a print job.
StartPagePrinter | Prepares the print provider to receive a print job page.
WritePrinter (Required) | Receives a portion of the print job's data stream.

Note The AddJob...ScheduleJob sequence is an alternative to the StartDocPrinter...EndDocPrinter sequence.

Print Job Scheduling Functions

Function | Description
EnumJobs (Required) | Returns a list of scheduled print jobs.
GetJob (Required) | Returns job parameters.
SetJob (Required) | Cancels, pauses, resumes, or restarts a print job, or sets job parameters.

Forms Management Functions

Function | Description
AddForm | Adds a specified form to the list of those available for a specified printer.
DeleteForm | Removes a specified form from the list of those available for a specified printer.
EnumForms | Returns a list of forms available for a specified printer.
GetForm | Returns characteristics of a specified form.
SetForm | Modifies characteristics of a specified form.

Print Processor Management Functions

Function | Description
AddPrintProcessor
 | Installs a print processor on the specified server and adds it to the list of those that the print provider can call.
DeletePrintProcessor
 | Deletes a print processor from the list of those that the print provider can call.
EnumPrintProcessorDataTypes
 | Returns a list of the data types supported by the print processors that are callable by the print provider.
EnumPrintProcessors
 | Returns the list of print processors that the print provider can call.
GetPrintProcessorDirectory
 | Returns the directory path in which print processor files must be stored.

Print Monitor Management Functions

Function | Description
AddMonitor | Adds a print monitor to the list of those that the print provider can call.
DeleteMonitor | Deletes a print monitor from the list of those that the print provider can call.
EnumMonitors | Returns the list of print monitors that the print provider can call.

Port Management Functions

Function | Description
AddPort | Adds a printer port to the list of those available, typically by calling the specified port monitor's AddPortUI function.
AddPortEx | Same as AddPort, with additional parameters.
ConfigurePort (Required) | Configures a printer port, typically by calling the specified port monitor's ConfigurePortUI function.
DeletePort (Required) | Deletes a printer port from the list of those available, typically by calling the specified port monitor's DeletePortUI function.
EnumPorts (Required) | Returns a list of available printer ports.
SetPort | Sets parameters for a specified printer port.

Registry Management Functions

Function | Description
DeletePrinterData | Deletes the value currently assigned to a specified value name, under the specified printer's PrinterDriverData key.
DeletePrinterDataEx | Same as DeletePrinterData, with additional parameters.
DeletePrinterKey | Deletes a specified key and its subkeys, if they are currently stored in the registry under the specified printer's PrinterDriverData key.
EnumPrinterData | Returns each of the value names and currently assigned values that are stored in the registry under the specified printer's PrinterDriverData key.
EnumPrinterDataEx | Same as EnumPrinterData, with additional parameters.
EnumPrinterKey | Returns a list of subkeys currently contained in the registry under a specified key name.
GetPrinterData | Returns the value currently assigned to a specified value name, which is stored in the registry under the specified printer's PrinterDriverData key.
GetPrinterDataEx | Same as GetPrinterData, with additional parameters.
SetPrinterData | Stores a specified value name and value in the registry, under the specified printer's PrinterDriverData key.
SetPrinterDataEx | Same as SetPrinterData, with additional parameters.

Other Functions

Function | Description
XcvData
 | Provides a communication path between a port monitor UI DLL and a port monitor server DLL.


Local Print Provider

The local print provider for Windows 2000 and later provides job control and printer management capabilities for all printers that are accessed through the local print provider's port monitors. (A client administrator sets up access to such printers by selecting the Local Printer option when using the Add Printer Wizard.) Such printers include those connected to the local system's serial and parallel ports. They can also include devices connected to other I/O channels, such as SCSI ports, along with printers connected to remote non-NT-based-operating system servers.

The local print provider implements the entire set of functions defined by print providers. It also supplies the following capabilities:

  • Print job spooler, with despooling of jobs directed to locally accessible print queues.
  • Support for the Windows 2000 and later printer driver architecture with calls to local printer interface DLLs.
  • Support for vendor-supplied print processors (see Writing a Print Processor).
  • Support for vendor-supplied print monitors (see Writing a Print Monitor).

The following diagram provides a (somewhat simplified) view of control flow among the local printer provider's components, when an application creates a print job.

Control Flow in Local Printer Provider

As the diagram shows, an application creates a print job by calling the Graphics Driver Interface (GDI). Regardless of whether the print job's initial output format is EMF, the local print provider's job creation API creates a spool file. Later, when the job is scheduled, the spool file is read and, if the format is EMF, the EMF print processor sends the job back to GDI for conversion to RAW format, with the help of a printer graphics DLL. The converted data stream can then be sent back through the local print provider to the printer (without being respooled).

Vendor can create partial print providers that work in conjunction with the local print provider to support custom network configurations.


Printer Driver Architecture

Print jobs are created by applications through calls to Microsoft® Win32® GDI functions. These function calls can be spooled as EMF data type records for later playback by the EMF print processor, or they can immediately render a printable image for each document page. Image rendering, whether performed immediately or during the playback of EMF records, is controlled by the GDI rendering engine. During the rendering operation, the GDI rendering engine calls the appropriate Windows® 2000 and later printer driver for assistance.

Windows 2000 and later printer drivers have the following responsibilities:

  • They assist GDI in rendering print jobs by providing printer-specific drawing capabilities that cannot be supported by GDI.
  • They send the rendered image's data stream to the print spooler.
  • They provide a user interface to the modifiable configuration parameters associated with printers and print documents, such as which input and output trays are selected, the number of copies, image resolution and orientation, and so on.

Windows 2000 and later printer drivers are made up of a set of printer driver components that divide a driver's drawing and user interface operations into separate DLLs.

While the purpose of this section is to explain how to write your own printer driver for Windows 2000 and later, it is important to keep in mind that the following three printer drivers are shipped with the operating system:

Microsoft Universal Printer Driver

Microsoft Postscript Printer Driver

Microsoft Plotter Driver

These three drivers support most printing devices on the market today. You only need to write a printer driver if your printing device is not compatible with the appropriate Microsoft-supplied driver. Most new printers can be supported by simply adding a printer data file to one of these drivers. Devices that might require a new driver include those containing hardware drawing accelerators controlled by proprietary command sequences.


Printer Driver Components

All Windows® 2000 and later printer drivers consist of the following components:

  • A printer graphics DLL that assists GDI in rendering a print job, and sends the rendered data stream to the print spooler.
  • A printer interface DLL that provides both a user interface to the driver's configuration parameters, and an interface the spooler can call to notify the driver of print-related system events.

In addition, Microsoft-supplied printer drivers make use of printer data files.


Printer Graphics DLL

This section provides the following topics:

Introduction to Printer Graphics DLLs

Functions Defined by Printer Graphics DLLs

Sample Printer Graphics DLL

Rendering a Print Job

Supporting Device Fonts

Returning Printer-Specific Information

Choosing User Mode or Kernel Mode

Building a Printer Graphics DLL


Introduction to Printer Graphics DLLs

Printer graphics DLLs implement Drv-prefixed graphics DDI functions described in Using the Graphics DDI. These DLLs have the following two responsibilities:

  • Assisting GDI in rendering a print job

    A printer graphics DLL can provide graphics DDI drawing functions to handle drawing operations that must be performed in a device-specific manner and thus cannot be handled exclusively by GDI's rendering engine.

  • Delivering a rendered data stream to the spooler

    Printer graphics DLLs typically produce an output stream in a RAW data type (including command sequences) that the spooler can send to printer hardware through print monitors.

The amount of rendering assistance that a printer graphics DLL must provide is printer type-specific, depending on the hardware's drawing capabilities, and includes the following scenarios:

  • The GDI rendering engine does all rendering, using a GDI-managed surface. The graphics DLL does not provide any DDI drawing functions.
  • The graphics DLL provides some graphics DDI drawing functions to work in conjunction with GDI's rendering engine, using a GDI-managed surface. The graphics DDI drawing functions provided by the graphics DLL can optionally call back to the GDI rendering engine's GDI support services.
  • The graphics DLL does all rendering by providing graphics DDI drawing functions and using a device-managed surface.

For example, the Microsoft Universal Printer Driver (Unidrv) uses a GDI-managed surface and provides some graphics DDI drawing functions, while the Microsoft Postscript Printer Driver uses a device-managed surface.

For more information about providing rendering assistance in graphics drivers, see Surface Types and Using the Graphics DDI.

Printer graphics DLLs are not called during EMF spooling of a print job. The appropriate graphics DLL is called when the EMF print processor plays back EMF records.

Note that printer graphics DLLs do not send rendered print jobs to hardware. Rendered data streams are returned to the spooler. The spooler sends the stream to a port monitor, which is the user-mode interface into a kernel-mode miniport driver for a local parallel port or network port.

For Windows 2000 and later, you can design a printer graphics DLL to execute in kernel mode, or you can design it to execute in user mode. For more information, see Choosing User Mode or Kernel Mode.

The following two diagrams illustrate the data flow that occurs when an application creates a print job using GDI. The first diagram pictures a user-mode printer graphics DLL.

Print Job Data Flow, Using a User-Mode Printer Graphics DLL

The second diagram pictures a kernel-mode printer graphics DLL.

Print Job Data Flow, Using a Kernel-Mode Printer Graphics DLL

Note in the diagrams that if the output format from GDI is EMF, the printer graphics DLL does not receive the job until the EMF print processor plays back EMF records. Note also that the EMF Print Processor changes Output Format to non-EMF.

The diagrams illustrate an entirely local environment. If the printer is connected to a server, EMF records are typically produced by the client's copy of the GDI rendering engine (GRE), then spooled to a local file that is sent to the server. The server's copy of the spooler reads the file and sends the records to the server's EMF print processor, and the server's copy of the GRE calls the server's printer graphics DLL.


Functions Defined by Printer Graphics DLLs

Like all graphics drivers, printer graphics DLLs are responsible for defining the following graphics DDI functions. Following DrvEnableDriver, the initial driver entry point, the remaining functions are listed in alphabetical order.

Function Name | Description
DrvEnableDriver | Allows the driver to initialize itself and return pointers to supported graphics DDI functions.
DrvCompletePDEV | Provides the driver with a GDI handle to a device instance.
DrvDisableDriver | (Optional) Allows the driver to perform cleanup operations before being unloaded.
DrvDisablePDEV | Allows the driver to remove device instance-specific information.
DrvDisableSurface | Allows the driver to remove a drawing surface.
DrvEnablePDEV | Allows the driver to provide GDI with physical device characteristics and to initialize device instance-specific information.
DrvEnableSurface | Allows the driver to create a drawing surface.
DrvQueryDeviceSupport | (Optional) Returns requested device-specific information.
DrvQueryDriverInfo | (Optional) Returns requested driver-specific information.

Printer graphics DLLs are also responsible for defining the following print-specific graphics DDI functions, which are called at certain points during the rendering of a print job.

Function | When Called
DrvEndDoc | When GDI has finished sending a document to the driver for rendering.
DrvNextBand | (Optional) When GDI has finished drawing a band for a physical page, so the driver can send the band to the printer.
DrvQueryPerBandInfo | (Optional) Before GDI begins drawing a band for a physical page, so the driver can supply GDI with band-specific information.
DrvSendPage | When GDI has finished drawing a physical page, so the driver can send the page to the printer.
DrvStartBanding | (Optional) When GDI is ready to start sending bands of a physical page to the driver for rendering.
DrvStartDoc | When GDI is ready to start sending a document to the driver for rendering.
DrvStartPage | When GDI is ready to start sending a document page to the driver for rendering.

Typically, a printer graphics DLL also defines whatever additional graphics DDI functions are necessary to accomplish print job rendering. The number and type of functions defined depends on:

  • Whether the driver supports use of GDI-managed or device-managed drawing surfaces (or both). For more information, see Surface Types.
  • The extent to which drawing operations can be handled by GDI instead of being performed by the driver itself. For more information, see Using the Graphics DDI.

All functions defined by printer graphics DLLs are called by GDI's kernel-mode graphics rendering engine (GRE).

The DrvEnableDriver and DrvQueryDriverInfo functions are exported by the graphics DLL. The address of all other supported graphics DDI functions are placed in a table that is returned by the DrvEnableDriver function.


Sample Printer Graphics DLL

Source code for plotter.dll, the printer graphics DLL for the Microsoft Plotter Driver, is provided with this DDK. The code is located in a subdirectory of the directory tree containing DDK samples.


Rendering a Print Job

Print jobs are either rendered as they are created, or they are spooled as EMF records. In the latter case, rendering takes place when the EMF print processor (winprint.dll) plays back the EMF records. Rendering consists of a series of calls to GDI's Win32 drawing functions, beginning with CreateDC.

When an application calls GDI's CreateDC function to create a printer device context, GDI checks to see if the appropriate printer graphics DLL is loaded. If it is not, GDI loads the DLL and calls its DrvEnableDriver function. The function is not called again unless the driver is reloaded.

Next, GDI calls the printer graphics DLL's DrvEnablePDEV function so the driver can create a device instance and return device characteristics. GDI uses the returned information to create an internal description of the device instance, and then calls the graphics DLL's DrvCompletePDEV function to supply a GDI handle to the device instance. The graphics DLL must use this handle as input to some of the Eng-prefixed callbacks provided by the GDI drawing engine (see GDI Support Services).

This is followed by a call to the graphics DLL's DrvEnableSurface function, so the driver can create a drawing surface for the device instance by calling EngCreateBitmap or, if the drawing surface is device-managed, by calling EngCreateDeviceSurface. If EngCreateBitmap cannot supply a bitmap large enough to contain an entire physical page, and if the driver supports page banding, EngMarkBandingSurface can be called to inform GDI that banding will be employed. Finally, the EngAssociateSurface must be called to allow GDI to associate the created surface with a specified device instance, and to let GDI know which driver-supplied graphics DDI drawing functions (if any) it should call when drawing on this particular surface.

At this point, a drawing surface has been created and rendering can begin. For each document to be rendered, GDI calls the following functions in the printer graphics DLL:

DrvStartDoc
For each physical page {
DrvStartPage
DrvStartBanding
For each banding surface {
DrvQueryPerBandInfo
Rendering operations
 DrvNextBand
}
DrvSendPage
}
DrvEndDoc

With the exception of DrvQueryPerBandInfo, these functions are intended to allow the printer graphics DLL to send control sequences to the printer hardware (by calling EngWritePrinter ), and to perform any internal operations needed to initialize or complete processing of a document, page, or band.

The printer graphics DLL is responsible for sending the rendered image (that is, the contents of the drawing surface) to the printer at appropriate times (by calling EngWritePrinter), as follows:

  • For GDI-managed or device-managed bitmap surfaces

    The drawing surface is a GDI-supplied or driver-supplied bitmap. The printer graphics DLL might hook some drawing functions (see Surface Negotiation). If page banding is in use, the DrvNextBand function should send drawing surface contents. If banding is not in use, the DrvSendPage function should send the drawing surface contents.

  • For device-managed vector surfaces

    The drawing surface is within the device. The printer graphics DLL hooks all drawing functions (see Surface Negotiation), and these functions send image data to the printer during rendering operations. Page banding is not used.

If you anticipate that any graphics DDI function provided by a printer graphics DLL could potentially take more than five seconds to execute, you should include code that calls EngCheckAbort at least every five seconds to see if the print job should be terminated.

After GDI calls DrvEndDoc to indicate that a document has been completely rendered, it calls DrvDisableSurface. If DrvEnableSurface called EngCreateBitmap, then DrvDisableSurface must call EngDeleteSurface.

GDI calls a printer graphics DLL's DrvDisablePDEV function when an application calls DeleteDC.

If an application calls GDI's ResetDC function during the printing of a document, GDI creates a new device context and calls the printer graphics DLL's DrvEnablePDEV function for the new context. Then GDI calls the DrvResetPDEV function, so the graphics DLL can update the new context with information from the old one. Next, DrvDisableSurface and DrvDisablePDEV are called for the old context, followed by DrvEnableSurface for the new context. Finally, GDI calls DrvStartDoc and rendering resumes on a new page.

GDI calls DrvDisableDriver prior to unloading the printer graphics DLL.

If printer hardware supports drawing operations that are not supported by GDI drawing functions, the printer graphics DLL can provide a DrvDrawEscape function.

A printer graphics DLL can provide a DrvEscape function if it is necessary to support drawing or non-drawing operations that are not available through GDI functions. For example, the Microsoft Postscript printer driver uses escapes to support Postscript injection points. Or, an application might need to obtain a fax machine's phone number. The DrvEscape function is also used for indicating the operations supported by the DrvDrawEscape function.


Supporting Device Fonts

If a printer provides device fonts, the printer graphics DLL must define a DrvTextOut function to generate text output commands. The graphics DLL must also define the following functions:

DrvQueryAdvanceWidths
DrvQueryFont
DrvQueryFontData
DrvQueryFontTree

For more information about supporting device fonts, see Supporting Graphics DDI Font and Text Functions.


Returning Printer-Specific Information

GDI sometimes requests a printer graphics DLL to return printer-specific information in between print jobs, by calling such DrvQuery-prefixed graphics DDI functions as DrvQueryAdvanceWidths (if defined by the graphics DLL).

An example of when this might occur is the case of a word processing application that is maintaining a WYSIWYG screen display of a printable page. To correctly display the line breaks in text, the word processor must base line-fitting calculations on character widths and other font metrics from the selected printer's implementation of a font.


Choosing User Mode or Kernel Mode

Prior to version 4.0 of Windows NT®, GDI and all graphics drivers executed in user mode. With version 4.0, these components were moved to kernel mode. While this change provided performance improvements for display devices, performance gains for printing devices were not significant enough to counteract losing the advantages inherent with user-mode execution.

Therefore, for Windows® 2000 and later you can design a printer graphics DLL to execute in kernel mode, or you can design it to execute in user mode. User-mode execution of printer graphics DLLs provides the following advantages over kernel-mode execution:

  • Unlimited stack space
  • Access to Win32® APIs
  • Less potential for causing system crashes
  • Easier debugging, with user-mode debuggers
  • Better floating point capabilities, since use of graphics DDI floating point functions is not required
  • Capability of calling any customized, vendor-supplied user-mode DLLs that are not part of the described Windows 2000 and later printer driver architecture

Using the Graphics DDI in User Mode

A user-mode printer graphics DLL is not limited to calling only the GDI Support Services and other Eng-prefixed graphics DDI callback functions. However, there are some rules that must be followed:

  • Like kernel-mode graphics DLLs, user-mode graphics DLLs must call the graphics DDI's versions of functions that create or modify a drawing surface. These callback functions are the GDI Support Services, and calling Win32 equivalents of these drawing functions is not allowed.

    For user-mode DLLs, calls to these drawing callback functions are intercepted by the user-mode GDI client, which then passes the calls to GDI's kernel-mode graphics rendering engine (GRE).

  • The following list of Eng-prefixed graphics DDI functions cannot be called by user-mode DLLs.

    EngCreatePath
    EngCreateClip
    EngDeleteClip
    EngGetType1FontList
    EngMapModule
    EngDebugBreak

    All other Eng-prefixed functions available to kernel-mode printer graphics DLLs are also available in user mode. For functions that have exact Win32 equivalents, such as EngGetPrinter or EngGetPrinterDriver, the Win32 equivalent is called. Functions without exact Win32 equivalents are implemented in the GDI client.

  • User-mode printer graphics DLLs can continue to use graphics DDI functions for floating point support.

Converting an Existing Printer Graphics DLL to User Mode

If you have previously developed a printer graphics DLL that executes in kernel mode, for Windows® 2000 and later you have the following options:

  1. Do nothing. Existing kernel-mode printer graphics DLLs will continue to work in kernel mode. Microsoft might remove support for kernel-mode printer graphics DLLs in a future release of the operating system.
  2. Convert the DLL to user-mode execution. To convert, simply add a DrvQueryDriverInfo function to the DLL, then follow the rules for building a printer graphics DLL.

Creating a New Printer Graphics DLL in User Mode

When developing a new printer graphics DLL that executes in user mode, you can continue to use all the graphics DDI functions used by kernel-mode DLLs. However, you also have the following options:

  • For Eng-prefixed functions that have exact Win32 equivalents, you can call the Win32 functions. These functions consist of the following:
EngAllocMem
EngAllocUserMem
EngEnumForms
EngFreeMem
EngFreeUserMem
EngFindImageProcAddress 		EngGetForm
EngGetLastError
EngGetPrinter
EngGetPrinterData
EngGetPrinterDriver
EngLoadImage 		EngMulDiv
EngSetLastError
EngSetPrinterData
EngUnloadImage
EngWritePrinter

  • For Eng-prefixed functions that correspond to Win32 functions with similar functionality, you can call the Win32 functions. These functions consist of the following:
EngAcquireSemaphore
EngCreateSemaphore
EngDeleteSemaphore
EngFindResource
EngFreeModule 		EngGetCurrentCodePage
EngGetDriverName
EngGetPrinterDataFileName
EngLoadModule
EngMultiByteToUnicodeN 		EngMultiByteToWideChar
EngQueryLocalTime
EngReleaseSemaphore
EngUnicodeToMultiByteN
EngWideCharToMultiByte

  • For functions that create or modify a drawing service, new drivers must continue to call GDI support services and not their Win32 equivalents.
  • Instead of using graphics DDI functions for floating point support, you can use the FLOAT data type.


Building a Printer Graphics DLL

When building a printer graphics DLL, you must be aware of the following differences between DLLs intended for user-mode execution and those intended for kernel-mode execution.

Rules for Building a Printer Graphics DLL

User Mode Graphics DLL | Kernel Mode Graphics DLL
Set TARGETTYPE=DYNLINK in source file. | Set TARGETTYPE=GDI_DRIVER in source file.
Preprocessor macro USERMODE_DRIVER must be defined in source files before winddi.h is included. | Preprocessor macro USERMODE_DRIVER must not be defined.
Object modules must be linked with the umpdddi.lib and gdi32.lib import libraries. | Object modules must be linked with the win32k.lib import library.
The DrvQueryDriverInfo function must return TRUE for DRVQUERY_USERMODE. | The DrvQueryDriverInfo function must return FALSE for DRVQUERY_USERMODE. (Alternatively, the function can be omitted.)


Printer Interface DLL

This section provides the following topics:

Introduction to Printer Interface DLLs

Functions Defined by Printer Interface DLLs

Sample Printer Interface DLL

Creating Property Sheet Pages for Printers


Introduction to Printer Interface DLLs

Printers typically provide users with a large number of modifiable configuration options that can be changed for each document that is printed. Options such as paper, tray and font selection, along with image resolution, size, color, and so on, must be accessible through user interfaces that can be invoked by applications.

A printer driver's printer interface DLL, which executes in user mode, is responsible for exporting a user interface to the printer's configuration options. Providing this interface involves creating property sheet pages for printers. Applications (such as the print folder) display the interface by calling Win32 functions exported by the print spooler, and the spooler, in turn, calls functions defined by printer interface DLLs.

Providing a user interface to configuration options is not a printer interface DLL's only responsibility. The DLL also exports functions that the spooler can call to notify the driver of print-related system events, such as driver installations and upgrades, or printer additions and connections.


Functions Defined by Printer Interface DLLs

Printer interface DLLs export the functions listed in the following table.

Function | Purpose
DllEntryPoint | Initial DLL entry point, typically called DLLMain (described in the Platform SDK documentation).
DrvConvertDevMode | Converts the specified DEVMODE structure from one version to another.
DrvDeviceCapabilities | Returns requested information about a printer's capabilities.
DrvDevicePropertySheets | Calls CPSUI to create property sheet pages that describe a printer's properties.
DrvDocumentEvent | (Optional) Allows the printer interface DLL to specify which events associated with printing a document it will handle.
DrvDriverEvent | (Optional) Allows the printer interface DLL to respond to notifications from the spooler that certain driver-specific events have occurred.
DrvDocumentPropertySheets | Calls CPSUI to create property sheet pages that describe a print document's properties.
DrvPrinterEvent | Allows the printer interface DLL to respond to notifications from the spooler that certain printer-specific events have occurred.
DrvQueryColorProfile | (Optional) Allows the printer interface DLL to specify an ICC profile to use for color management.
DrvQueryJobAttributes | (Optional) Allows the printer interface DLL to specify support for such capabilities as printing multiple document pages on a physical page ("N-up" printing), printing multiple copies of each page, and collating pages.
DevQueryPrintEx | Determines if a print job can be printed using the printer's current configuration.
DrvUpgradePrinter | (Optional) Updates a printer's registry settings when a new version of the driver is added to a system.


Sample Printer Interface DLL

Source code for plotui.dll, the printer interface DLL for the Microsoft Plotter Driver, is provided with this DDK. The code is located in a subdirectory of the directory tree containing DDK samples.


Creating Property Sheet Pages for Printers

Printer interface DLLs, in conjunction with CPSUI, are responsible for creating the property sheet pages that users of Windows® 2000 and later employ to view and modify configuration parameters associated with printers and print documents. Each printer interface DLL must provide a DrvDevicePropertySheets function to create printer-specific pages, and a DrvDocumentPropertySheets function to create document-specific pages.

To understand how these functions should be designed, it is important to read the section describing CPSUI. Displaying property sheet pages involves interaction between an application, the print spooler, the printer interface DLL, and CPSUI. Execution flow is described in Using CPSUI with Printer Drivers.


Printer Data Files

Microsoft-supplied printer drivers make use of data files to describe individual printing devices. For more information, see the following:

  • Microsoft Universal Printer Driver

    Describes .gpd files.

  • Microsoft Postscript Printer Driver

    Describes .ppd files.

  • Microsoft Plotter Driver

    Describes .pcd files.


Microsoft Universal Printer Driver

This section describes the Microsoft Universal Printer Driver (Unidrv) and explains how to add minidrivers that allow Unidrv to support new printers. The following topics are covered:

Introduction to the Universal Printer Driver

Introduction to GPD Files

Printer Attributes

Printer Commands

Printer Features

Printer Options

Printer Font Descriptions

Conditional Statements

Compressing Raster Data

Filtering Raster Data

Handling Color Formats

Halftoning with Unidrv

Controlling Image Quality

Handling Installable Features and Options

Specifying Feature and Option Display Order

Describing Printer Memory Configurations

Specifying Paper Sizes

Referencing Locales

Using Unidrv Vector Graphics Capabilities

Installing a Unidrv Minidriver

Unidrv Printer Minidriver Versioning


Introduction to the Universal Printer Driver

The Universal Printer Driver (Unidrv) is the Microsoft Corporation's standard printer driver for non-Postscript printers. The following topics provide an introduction to Unidrv:

Unidrv Capabilities

Unidrv Components

Unidrv Minidrivers

Unidrv User Interface

Unidrv Renderer

Sample GPD Files

Microsoft Minidriver Development Tool


Unidrv Capabilities

The Universal Printer Driver (Unidrv) provides the following capabilities:

  • Support for all non-Postscript printers, using printer-specific Unidrv minidrivers that describe each printer's characteristics.
  • A Unidrv user interface, based on the TreeView control and property sheets, that is consistent for all printers, but is also modifiable for each printer's unique options.
  • A single Unidrv renderer that, along with the GDI graphics engine, converts Microsoft® Win32® GDI calls from applications into printer commands that can be sent to the print spooler.

To provide support for minidrivers written as GPC files for Microsoft's previous printer driver, RasDD, the Microsoft Minidriver Development Tool provides automated conversions of RasDD GPC files to Unidrv GPD files.


Unidrv Components

Unidrv components consist of DLLs, plus text and binary data files, as illustrated in the following diagram:

Unidrv Components

Components in the diagram include:

Application
A user application, such as a word processor, that provides users with printing capabilities.
gdi32.dll
User-mode DLL that exports Win32 GDI functions.
Kernel-Mode Graphics Engine
NT Executive code that implements GDI functionality.
Minidriver Text Files
Text-based Unidrv minidrivers that describe printers by using GPD file entries.
Binary Data Files
Temporary files (with a .bud extension) that Unidrv creates after parsing information contained in minidriver text files.
unidrvui.dll
Unidrv user interface DLL, providing common UI code for all Unidrv-supported printers.
User Interface Plug-In
Optional, printer-specific, user interface plug-in.
compstui.dll
CPSUI user interface for printers.
unidrv.dll
Unidrv renderer, which renders images and sends the image data stream to the print spooler.
Rendering Plug-In
Optional, printer-specific, rendering plug-in.


Unidrv Minidrivers

Unidrv minidrivers are text files that contain descriptions of printers. Each minidriver describes one printer type from one manufacturer. This text-based description is called a generic printer description (GPD), and each file is called a GPD file. Each minidriver consists of one or more GPD files.

Using GPD files to describe a printer, Unidrv supports the following capabilities:

  • Generic, standard printer features that are found on most printers.
  • Unique, customized printer features that only your printer provides.
  • Installable printer options, which can only be selected if the options are installed.
  • Option constraints, which allow you to specify incompatible options.
  • Conditional statements, which allow you to specify that some printer characteristics are dependent on others.
  • Specification of printer commands that can include current values from a large selection of standard variables. You can also perform arithmetic operations on these variables.
  • A customized help file, in addition to the standard help file provided with Unidrv, for describing customized features.

For information about creating GPD files, see Introduction to GPD Files.

A Unidrv minidriver can consist of more than one GPD file. For more information, see Using Multiple GPD Files in a Minidriver.

When a printer is installed, Unidrv's GPD parser reads all the printer's GPD files. The information in the GPD files is used to create a temporary binary file for the printer. Both the Unidrv User Interface and the Unidrv renderer reference this binary file.

Typically, a minidriver must provide resources, such as fonts, bitmaps, and localizable text strings. These resources are placed in a resource DLL. For more information, see Using Resource DLLs in a Minidriver.


Unidrv User Interface

The Unidrv user interface employs CPSUI to create the following property sheet pages:

  • The Device Settings page for the printer property sheet, which is displayed when a user selects the Properties menu item from the printer folder or a printer window. The page lists printer-specific configuration settings.
  • The Layout, Paper/Quality, and Advanced pages for the document property sheet, which are displayed when a user selects the Document Defaults menu item from the printer folder or a printer window, or when an application calls the PrinterProperties or DocumentProperties functions (described in the Platform SDK documentation). The pages list document-specific configuration settings.

These property sheet pages contain the printer features and printer options specified by a printer's Unidrv minidriver. They also allow the user to modify option values.

The Unidrv user interface is implemented as a user-mode printer interface DLL. Code within this DLL, in conjunction with CPSUI, specifies the contents of the property sheet pages. The DLL enforces constraints on which printer options can be combined, based on information in the minidriver. It also ensures that users do not select options not installed on the printer.

You can modify the Unidrv-supplied property sheet pages by providing a user interface plug-in.


Unidrv Renderer

The Unidrv renderer is implemented as a printer graphics DLL and thus exports functions defined by the Microsoft Device Driver Interface (DDI) for graphics drivers. When an application calls Graphics Device Interface (GDI) functions to send images to a printer device, the kernel-mode graphics engine calls the renderer's graphics DDI functions. These graphics DDI functions assist GDI in drawing a print job's page images.

The renderer is also responsible for sending rendered image data, along with printer command sequences, to the print spooler, which then directs the images and commands to printer hardware. The printer commands that the renderer sends are specified in the Unidrv minidrivers.

You can modify Unidrv's rendering operations by providing a rendering plug-in.


Sample GPD Files

The DDK includes a large number of sample minidrivers. The samples include GPD files, along with font and resources files, for a variety of printer types. Samples are located in the mini subdirectory of the directory tree containing DDK samples.


Microsoft Minidriver Development Tool

The Microsoft Minidriver Development Tool (Microsoft MDT), which is included with this DDK as minidev.exe, is a software tool designed for easy development of Unidrv minidrivers.

Microsoft MDT provides the following features:

  • Generic Printer Description (GPD) Editor

    Syntax-checking text editor for creating the GPD files that make up Unidrv minidrivers.

  • UniDrv Font Metrics (UFM) Editor

    Property sheet-based editor that generates Unidrv Font Metrics files.

  • Glyph Translation Table (GTT) Editor

    Property sheet-based editor that generates Glyph Translation Table files.

  • MiniDriver Workspace

    Window-based editing workspace for a Unidrv minidriver, providing access to the minidriver's GPD file, resource file, UFM file, and GTT file.

  • Minidriver Conversion Wizard

    Automatically converts binary minidrivers, used with previous versions of NT-based operating systems, into text-based minidrivers for Windows 2000 and later. When you use the Wizard, it creates a Windows 2000 (or later) minidriver by converting the files listed in the following table.
    Input files | File Contents | Output Files
    Windows GPC files | Printer capability descriptions | Windows 2000 and later GPD files
    Windows PFM files | Font descriptions | Windows 2000 and later UFM files
    Windows CTT files | Glyph translations | Windows 2000 and later GTT files

    Additionally, the conversion wizard generates resource files with the correct file names and resource identifiers.

  • INF Wizard

    Automatically creates an INF file for the converted minidriver. (See Installing a Unidrv Minidriver.)

  • String Resource Editor

    Dialog box used to modify text strings contained in a printer minidriver's resource file (.rc file).

For instructions on how to use Microsoft MDT, run the program and read its Help topics.


Introduction to GPD Files

GPD files are used for creating Unidrv minidrivers. A Unidrv minidriver consists of a text-based generic printer description (GPD), which can be contained in one or more GPD files.

GPD files use the GPD language to describe a printer. The files contain GPD file entries that use the GPD language to provide the following types of information:

  • Printer attributes that describe printer characteristics.
  • Printer commands that control printer operations.
  • Printer features describing the printer capabilities that can be controlled by Unidrv.
  • Printer options representing the states that can be assigned to printer features.
  • Printer font descriptions that specify the characteristics associated with hardware-resident and cartridge fonts.
  • Conditional statements that describe dependencies between printer attributes and a printer's configuration.

The GPD language also defines GPD file entries that control the following operations:

Compressing raster data

Handling Color Formats

Halftoning with Unidrv

Handling Installable Features and Options

Describing printer memory configurations

This introductory section also includes discussions of master units, using multiple GPD files in a minidriver, and using resource DLLs in a minidriver.


GPD File Entries

GPD files are made up of entries, using the GPD language, that describe device-specific characteristics of each raster printer. This section includes the following topics, which describe GPD file entries:

GPD File Entry Format

GPD Value Types

Line Continuation

Comments and Ignored Blocks

Macros

Preprocessor Directives

Standard Variables


GPD File Entry Format

All GPD file entries conform to the following format:

*EntryName: EntryValue {GPD_FileEntry, GPD_FileEntry, ...}

EntryName is always a predefined keyword that Unidrv's GPD parser recognizes, preceded by an asterisk.

EntryValue must be one of the GPD value types.

Each GPD_FileEntry is another GPD file entry, conforming to the format shown above. Each of these sub-entries must be valid for the specified EntryName of the entry containing it.

Some EntryName keywords do not accept braces or enclosed sub-entries.

Each GPD entry is terminated by end-of-line or a right brace ( } ).

An example of a simple GPD file entry, which does not accept sub-entries, is the following attribute entry:

*MaxCopies: 99

This entry specifies that the maximum number of copies the printer can handle is 99.

Following is a more complex example, describing a printer that can print pages in either of two page orientations (portrait or landscape). The example also specifies the commands the driver must send to select each orientation.

*Feature: Orientation
{
    *Name: "Orientation"
    *DefaultOption: Portrait
    *Option: Portrait
    {
        *Name: "Portrait"
        *Command: CmdSelect
        {
            *Order: DOC_SETUP.7
            *Cmd: "<1B>&l0O"
        }
    }
    *Option: Landscape_CC90
    {
        *Name: "Landscape"
        *Command: CmdSelect
        {
            *Order: DOC_SETUP.7
            *Cmd: "<1B>&l1O"
        }
    }
}


GPD Value Types

All GPD file entries contain a value specification. The GPD language defines the following value types:

Symbolic names

Text strings

Constants

Numeric values

Boolean values

Lists

Pairs

Rectangles


Symbolic Names

A symbolic name is a character string used as an identifier. Symbolic names have the following characteristics:

  • The first character must be an uppercase or lowercase letter.
  • After the first character, the name can consist of uppercase and lowercase letters, numbers, and the underscore character ( _ ).
  • Names are case sensitive.
  • The number of characters in a name is unlimited.

The GPD language predefines a large number of symbolic names. Predefined names exist for printer attributes, command names, standard features, standard options, and standard variables.

You can define symbolic names for customized features, customized options, and macros.


Text Strings

Text strings are strings of literal characters, delimited by quotation marks. Strings used by Unidrv minidrivers can be placed in either of two locations:

  • They can be placed in a resource file. Strings that require localization, such as user interface text, should be placed in a resource file, as described in Using Resource DLLs in a Minidriver.
  • They can be included in GPD files. Strings representing the escape sequences that make up printer commands are typically included within GPD files, because these strings do not need to be localized.

Strings must obey the following rules:

  • Strings must be delimited by quotation marks ("...").
  • Hexadecimal byte values can be placed in a string by delimiting hexadecimal digits by angle brackets (<...>), such as <03> or <1B>. Within a set of angle brackets, each pair of digits is interpreted as another hexadecimal byte value. Therefore <03><1B>, <03 1B>, and <031B> are all equivalent.
  • The percent sign (%) is used as an escape character. To include a quotation mark or left angle bracket (", <) in a string, precede it with a percent sign. To specify a string that ends with a percent sign, you must specify the hexadecimal value for %, as in "<25>".

    Additionally, to include a percent sign in a text string representing a printer command, you must precede it with another percent sign. To specify a printer command that ends with a percent sign, you must specify two hexadecimal % values, as in
    "command-string<25 25>"

An example string is the command that selects letter-sized paper for the Canon BJC-600 printer. This command, which is the byte sequence 1B 28 67 03 00 6E 01 72, can be specified as:

"<1B>(g<03 00>n<01>r"

Each ASCII character included in the string is converted to its one-byte hexadecimal equivalent.

  • Strings that are included in GPD files must obey the following additional rule:

    To extend a string beyond a single line, precede each line after the first with a line continuation character (+), and delimit the text on each line with quotation marks.

  • A string value can consist of multiple text strings. For example, the following two GPD entries are equivalent:
    *Name: "abc""def" *% Comment
+      "gh"    "ijk"

*Name: "abcdefghijk"

For additional rules pertaining to strings defined in resource files, refer to the STRINGTABLE statement description in the Platform SDK documentation.

For more information about specifying printer command escape sequences, see Command String Format.


Constants

Constants are named values that are predefined by the GPD language. Constant names typically consist of capital letters. Example GPD constants are PAGE, SERIAL, and TTY, which are values that can be assigned to the *PrinterType attribute.


Numeric Values

All numeric values that you specify as entry values or parameter values in a GPD file must be integers. Decimal points are not allowed, except within text strings.

Numeric values are assumed to be positive unless preceded by a minus sign.

Numeric values are assumed to be decimal unless preceded by 0x, in which case they are unsigned hexadecimal values.

The asterisk character (*) can be used to indicate either an infinite value or a "don't care" value, if applicable within the context of a particular GPD file entry.


Boolean Values

Boolean values are defined as being equal to either of the predefined constants TRUE or FALSE. By convention, the symbolic names of all printer attributes that accept Boolean values end with a question mark character, as the following example illustrates:

*RotateRasterData?: FALSE


Lists

To assign a set of values to an attribute, use the LIST keyword. The format is:

LIST (Value1, Value2, Value3, ..., ValueN)

where Value1, Value2, Value3, ..., ValueN represents a set of one or more values, all of the type specified for the attribute. For example, the order in which a printer's color plane data should be sent can be specified as follows:

*ColorPlaneOrder: LIST(YELLOW, MAGENTA, CYAN, BLACK)


Pairs

To assign a pair of values to an attribute, use the PAIR keyword. The format is:

PAIR (Value1, Value2)

where Value1 and Value2 are numeric values. For example, the cursor origin position can be specified in master units as follows:

*CursorOrigin: PAIR(120, 100)


Rectangles

To describe a rectangle in a GPD file, use the RECT keyword. The format is:

RECT (left, top, right, bottom)

where left, top, right, and bottom represent numeric values, in master units.


Line Continuation

GPD file entries that are too long to fit onto a single line can be continued on subsequent lines. To continue an entry, each line after the first must be preceded by a plus sign (+). The plus sign must be the first character on the line, without preceding white space, as illustrated in the following example:

*DeviceFonts:
+    LIST(
+        =RC_FONT_Courier_10pt_regular,
+        =RC_FONT_CGTimes_regular,
+        =RC_FONT_Univers_regular,
+        =RC_FONT_Univers_condensed_regular,
+        =RC_FONT_Antique_Olive_regular,
+        =RC_FONT_Albertus_Medium,
+        =RC_FONT_Albertus_Extra_Bold,
+        =RC_FONT_Courier_regular,
+        =RC_FONT_Letter_Gothic_regular,
+        =RC_FONT_Wingdings)

You do not need to use a line continuation character at the beginning of the following lines:

  • Lines that start with an asterisk.
  • Lines that start with a left brace.


Comments and Ignored Blocks

GPD files can contain comments. The format for a comment is as follows:

*% CommentString

where CommentString is any string of characters ending with a line terminator. Each line of a multi-line comment must begin with the *% character sequence. The *% sequence must be preceded by white space or a line break.

The following are examples of valid comments:

*% This section of the GPD file
*% contains macro definitions.
*Macros: HP4L
{
    *% These macros define command prefixes for the paper size feature.
    LetterCmdPrefix: "<1B>&l2a8c1E<1B>*p0x0Y"  *% Prefix for letter option.
    A4CmdPrefix: "<1B>&l26a8c1E<1B>*p0x0Y"     *% Prefix for A4 option.
    Env10CmdPrefix: "<1B>&l81a8c1E<1B>*p0x0Y"  *% Prefix for Env10 option.
}

To request the GPD parser to ignore a group of GPD entries, you can create an ignored block that contains the entries to be ignored. The format for an ignored block is as follows:

*IgnoreBlock {IgnoredEntries}

where IgnoredEntries is a set of GPD file entries, containing an equal number of left and right braces.

In the following example, the GPD parser ignores the GPD entries describing the Landscape_CC90 option.

*Feature: Orientation
{
    *Name: "Orientation"
    *DefaultOption: Portrait
    *Option: Portrait
    {
        *Name: "Portrait"
        *Command: CmdSelect
        {
            *Order: DOC_SETUP.7
            *Cmd: "<1B>&l0O"
        }
    }
*IgnoreBlock
{
    *Option: Landscape_CC90
    {
        *Name: "Landscape"
        *Command: CmdSelect
        {
            *Order: DOC_SETUP.7
            *Cmd: "<1B>&l1O"
        }
    }
}
}


Macros

The GPD language supports two types of macros:

  • Block macros, which allow you to specify a set of GPD file entries that can be inserted in its entirety anywhere in a GPD file.
  • Value macros, which allow you to specify sets of values that can be inserted individually anywhere in a GPD file.


Block Macros

A block macro is used to delimit a set of GPD file entries that you want to insert repeatedly into a GPD file. You can include any entry type in a block macro definition, such as feature and option statements, attribute specifications, and references to value macros or other block macros.

The following rules apply to the use of block macros:

  • A block macro definition within a GPD file must be located before any references to it.
  • A block macro defined at root level (that is, not inside braces) is available through the GPD file that defines it, after it is defined. Otherwise, the scope of a block macro is the set of left and right braces containing its definition.
  • A block macro definition can contain definitions of additional block macros and value macros.
  • A block macro definition can reference other previously-defined block macros and value macros, but it cannot reference itself.
  • Block macros do not accept arguments.
  • If braces are included in a macro body, they must be paired (that is, there must be an equal number of left and right braces).
  • If you create two block macros with the same name, the first definition is in effect until the GPD parser encounters the second definition. The second definition then replaces the first. If the scope of the second definition ends, the first definition is reinstated.

Block Macro Format

To define a block macro in a GPD file, use the following format:

*BlockMacro: BlockMacroName {BlockMacroBody}

where BlockMacroName is a unique name, and BlockMacroBody is a set of one or more GPD file entries. If BlockMacroBody contains braces, equal numbers of left and right braces ( {, } ) must be included.

For example, you might define a block macro named EnvelopeDefaults, which is defined as follows:

*BlockMacro: EnvelopeDefaults
{
    *PrintableArea: PAIR(4646, 6738)
    *PrintableOrigin: PAIR(150, 150)
    *RotateSize: TRUE
}

Referencing Block Macros

To reference a block macro, use the following format:

*InsertBlock: =BlockMacroName

where BlockMacroName is a unique name, previously specified in the *BlockMacro entry that defines the macro.

For example, to reference the EnvelopeDefaults macro within an option specification, you could use the following entries:

*Option: Env9
{
    *InsertBlock: =EnvelopeDefaults
}


Value Macros

A value macro is used to specify a set of one or more values that you want to insert individually and repeatedly into a GPD file. Values can be any of the GPD value types.

The following rules apply to the use of value macros:

  • A value macro definition within a GPD file must be located before any references to it.
  • A value macro defined at root level (that is, not inside braces) is available through the GPD file that defines it, after it is defined. Otherwise, the scope of a value macro is the set of left and right braces containing its definition.
  • A value macro must resolve to one of the GPD value types.
  • A value macro definition can reference other previously-defined value macros if all values are text strings, but a value macro cannot reference itself.
  • Value macros do not accept arguments.
  • If you create two value macros with the same name, the first definition is in effect until the GPD parser encounters the second definition. The second definition then replaces the first. If the scope of the second definition ends, the first definition is reinstated.

Value Macro Format

To define one or more value macros in a GPD file, use the following format:

*Macros: ValueMacroGroupName {ValueMacroBody}

where ValueMacroGroupName is a unique name, and ValueMacroBody is a set of unique value names and associated values, as follows:

ValueMacroName: MacroValue

where ValueMacroName is a unique macro name, and MacroValue represents a GPD value type. (MacroValue can include references to previously-defined value macros, as long as the resolved string represents a GPD value type.)

As an example, you might define value macros for a set of frequently used command prefixes as follows:

*Macros: HP4L
{
    LetterCmdPrefix: "<1B>&l2a8c1E<1B>*p0x0Y"
    A4CmdPrefix: "<1B>&l26a8c1E<1B>*p0x0Y"
    Env10CmdPrefix: "<1B>&l81a8c1E<1B>*p0x0Y"
}

Note that ValueMacroGroupName (HP4L in the example) is optional and treated as a comment.

Referencing Value Macros

To reference a value macro, use the following format:

=ValueMacroName

where ValueMacroName is a unique name, previously specified in the *Macros entry that defines the macro.

For example, to reference one of the HP4L macros within a command specification, you could use the following entries:

*Command: CmdSelect
{
    *Cmd: =LetterCmdPrefix "<1B>*c0t5760x7680Y"
}

The only time you can assign a value by combining macro references with non-macro values is when all macro definitions and other values represent text or command substrings, as illustrated in the example. In all other cases, the macro reference must represent the entire value to be assigned.


Preprocessor Directives

GPD files can contain preprocessor directives, which can be used to control conditional parsing of sections within the GPD file. The following table describes the preprocessor directives that can be used in GPD files.

Preprocessor Directive | Definition
*Define: SymbolName
 | Defines a symbol.
*Undefine: SymbolName
 | Removes a previously defined symbol.
*Ifdef: SymbolName
 | Indicates the beginning of a block of GPD file entries. If the specified symbol is defined, the GPD file entries between this directive and the next *Ifdef, *Elseifdef, *Else, or *Endif directive are processed by the GPD parser.
*Elseifdef: SymbolName
 | If the specified symbol is defined, and the symbol specified by the previous *Ifdef or *Elseifdef directive is undefined, the GPD file entries between this directive and the next *Ifdef, *Elseifdef, *Else, or *Endif directive are processed by the GPD parser.
*Else:
 | If the symbol specified by the previous *Ifdef or *Elseifdef directive is undefined, the GPD file entries between this directive and the next *Ifdef or *Endif directive are processed by the GPD parser.
*Endif:
 | Indicates the end of a block of GPD file entries.
*Include: "FileName"
 | Specifies the name of an additional GPD file. See Using Multiple GPD Files in a Minidriver.
*SetPPPrefix: PrefixString
 | Changes the prefix string prepended to preprocessor directives. See Changing the Preprocessor Directive Prefix.

Conditional preprocessor directives can be nested. At each nesting level, the sequence for using conditional preprocessor directives is as follows:

*Ifdef: Symbol1
 GPD file section
*Elseifdef: Symbol2
 GPD file section
*Elseifdef: Symbo3
 GPD file section
*Elseifdef: Symbol4
 GPD file section
...
*Else:
 GPD file section
*Endif:

For each *Ifdef directive used, *Endif is required. The *Elseifdef and *Else directives are optional. Each GPD file section can contain GPD file entries and, optionally, a nested sequence of conditional preprocessor directives.

All symbols defined using *Define remain defined until explicitly undefined using *Undefine.

The *Include directive allows you to specify the name of an additional GPD file. For more information, see Using Multiple GPD Files in a Minidriver.

Note that the *IgnoreBlock GPD entry does not affect preprocessor directives, because the preprocessor executes before the GPD parser.

Changing the Preprocessor Directive Prefix

The *SetPPPrefix directive allows you to change the prefix used with preprocessor directives. That is, you can use this directive to replace the asterisk (*) character that prepends the preprocessor directives with another character or string.

For example, if your GPD file contains the following directive:

*SetPPPrefix: #SpecialPrefix#

then the preprocessor stops searching for preprocessor directives that begin with * and instead looks for directives beginning with #SpecialPrefix#. The following sequence temporarily changes the preprocessor prefix to #SpecialPrefix#, then restores it to *.

*SetPPPrefix: #SpecialPrefix#
#SpecialPrefix#Ifdef: WINNT_50
#SpecialPrefix#Include: "ExtraGPD.gpd"
#SpecialPrefix#Endif:
#SpecialPrefix#SetPPPrefix: *

The primary purpose of this feature is to allow GPD files written for future operating system versions to be compatible with Windows® 2000. For example, suppose GPD files for a future version of the operating system can include GPD file entries that conflict with the asterisk-prefixed preprocessor directives supported by Windows 2000. By changing the prefix, a GPD file written for the future operating system version can also be used with Windows 2000. An example might be constructed as follows:

*Ifdef: WINNT_70
    *SetPPPrefix: #SpecialPrefix#
    *% Do special, OS-specific processing of
    *% GPD file entries that might conflict with
    *% asterisk-prefixed preprocessor directives.
    #SpecialPrefix#SetPPPrefix: *
*Endif:

Note that this technique only changes the prefix that the preprocessor looks for. Keywords recognized by the parser must always be preceded by an asterisk.

Predefined Preprocessor Symbols

Microsoft defines the following preprocessor symbols.

Symbol | Where Defined | Definition
WINNT_51 | GPD preprocessor for Windows XP | Environment is Windows XP.
WINNT_50 | GPD preprocessor for Windows XP and Windows 2000 | Environment is Windows 2000.
WINNT_40 | GPD preprocessors for Windows XP, Windows 2000, and Windows NT 4.0 | Environment is Windows NT 4.0.
PARSER_VER_1.0 | GPD preprocessors for Windows NT 4.0, Windows 2000, and Windows XP | GPD parser version 1.0

The WINNT_40, WINNT_50, and WINNT_51 symbols are useful for creating GPD files that are compatible with Windows NT® 4.0, Windows 2000, and Windows XP. If, for example, Windows XP supports a printer capability that is not supported by Windows 2000, then that capability can be specified within a GPD file section that is bounded by *Ifdef: WINNT_51 and *Endif directives.


Standard Variables

The GPD language defines a set of standard variables that can be referenced within command strings, using the command string format. The Unidrv driver assigns values to these variables. From the point of view of a GPD file, the variables are read-only.

All standard variables are stored as DWORD integers.

The following printer command entry specifies the command string that is sent to an HP LaserJet 4P when a block of raster data is ready:

*Command: CmdSendBlockData: "<1B>*b" %d{NumOfDataBytes} "W"

The following table contains all the standard variables, in alphabetic order.

Standard Variable Name
Value
Comments
BlueValue
Blue component of the current color. | Valid for use in CmdDefinePaletteEntry command strings. (Also see GreenValue, RedValue.)
CurrentFontID
Identification number of the current downloaded soft font. | Valid if current print job includes downloaded soft fonts.
CurrentPaletteIndex
Current index into the color palette. | Valid for use in CmdSelectPaletteEntry command strings. (Also see GreenValue, RedValue.)
CursorOriginX
X-coordinate of cursor origin, in master units. | Valid whenever a print job is in progress.
CursorOriginY
Y-coordinate of cursor origin, in master units. | Valid whenever a print job is in progress.
DestX
X-coordinate of cursor destination, in master units, relative to the cursor origin. | Valid for use in CmdXMoveAbsolute command strings.
DestXRel
X coordinate of cursor destination, in master units, relative to the current cursor position. | Valid for use in CmdXMoveRelLeft and CmdXMoveRelRight command strings.
DestY
Y coordinate of cursor destination, in master units, relative to the cursor origin. | Valid for use in CmdYMoveAbsolute command strings.
DestYRel
Y coordinate of cursor destination, in master units, relative to the current cursor position. | Valid for use in CmdYMoveRelUp and CmdYMoveRelDown command strings.
FontBold
Set to one if current font is bold, or zero otherwise. | Valid when a font has been specified.
FontHeight
Height, in master units, of the current font. | Valid when a font has been specified.
FontItalic
Set to one if current font is italic, or zero otherwise. | Valid when a font has been specified.
FontMaxWidth
Set to the maximum character increment of all glyphs in the font. | Valid when a font has been specified.
FontStrikeThru
Set to one if strike-through is enabled for the current font, or zero otherwise. | Valid when a font has been specified.
FontUnderLine
Set to one if current font is underlined, or zero otherwise. | Valid when a font has been specified.
FontWidth
Width, in master units, of the current font. | Valid when a font has been specified.
GraphicsXRes
Current horizontal resolution for graphics, in DPI. | Valid whenever a print job is in progress.
GraphicsYRes
Current vertical resolution for graphics, in DPI. | Valid whenever a print job is in progress.
GrayPercentage
Gray level (percentage) to use for gray fill. | Valid for use in CmdRectGrayFill command strings.
GreenValue
Green component of the current color. | Valid for use in CmdDefinePaletteEntry command strings. (Also see BlueValue, RedValue.)
LinefeedSpacing
Amount of vertical space, in master units, representing a linefeed. | Valid for use in CmdSetLineSpacing command strings.
NextFontID
Identification number of the next soft font to be downloaded. | Valid for use in CmdSetFontID command strings.
NextGlyph
The two-byte code of the next glyph to download. | Valid for use in CmdSetCharCode command strings.
NumOfCopies
Number of copies requested by the user. | Valid whenever a print job is in progress.
NumOfDataBytes
Number of bytes of raster data ready for transfer. Valid for use in any CmdSend XXX Data command string.

If data is compressed, the value is the number of bytes after compression.
PageNumber
The number of the page currently being printed. Note that this does not necessarily correspond to the application's page number, but rather the number of times DrvSendPage has been called.

This value is initialized by DrvStartDoc and is incremented by DrvSendPage.

For example, if N-up = 4 is selected, PageNumber is incremented to 2 only when the fifth page of the document is being printed.

As another example, if a document is printed in reverse order (back to front) the PageNumber standard variable still reports the first page to be printed as page 1, even though this is the last page of the document.

This behavior is needed to properly support the auto-duplexing feature.

The OEM should use PageNumber only to determine whether the current page is the front or back side.

 Valid whenever a print job is in progress.
PaletteIndexToProgram
Index into the color palette for the next entry to program. | Valid for use in CmdDefinePaletteEntry command strings. (Also see RedValue, GreenValue, BlueValue, CurrentPaletteIndex.)
PatternBrushID
Identification number of a downloaded pattern brush. | Valid for use with CmdDownloadPattern and CmdSelectPattern command strings.
PatternBrushSize
Size, in bytes, of the current pattern brush. | Valid for use with CmdDownloadPattern command string.
PatternBrushType
Type of the current pattern brush. Value can be:
2: Shading pattern
3: Cross-hatch pattern
4: User-defined pattern 		Valid for use with CmdDownloadPattern and CmdSelectPattern command strings.
PhysPaperLength
Portrait-mode length, in y-master units, of the paper currently in use. | Valid whenever a print job is in progress.
PhysPaperWidth
Portrait-mode width, in master units, of the paper currently in use. | Valid whenever a print job is in progress.
RasterDataHeightInPixels
Height, in pixels, of the image represented by current data. | Valid for use in any CmdSend XXX Data command string, and in CmdSetSrcBmpHeight command strings. Compression does not modify this value.
RasterDataWidthInBytes
Number of bytes contained in a scan line. | Valid for use in any CmdSend XXX Data command string, and in CmdSetSrcBmpWidth command strings. Compression does not modify this value.
RectXSize
Rectangle width, in x-master units. | Valid for use in CmdSetRectWidth command strings.
RectYSize
Rectangle length, in y-master units. | Valid for use in CmdSetRectHeight command strings.
RedValue
Red component of the current color. | Valid for use in CmdDefinePaletteEntry command strings. (Also see GreenValue, BlueValue.)
TextXRes
Current horizontal resolution for text, in DPI. | Valid whenever a print job is in progress.
TextYRes
Current vertical resolution for text, in DPI. | Valid whenever a print job is in progress.


Master Units

Most printers support commands with a variety of horizontal and vertical resolutions. For example, the Immediate Line Feed command for a particular printer might provide a resolution of 1/288th of an inch, while the same printer might support a vertical graphics resolution of 1/96th of an inch. Likewise, this printer might provide horizontal resolutions of 1/80th, 1/160th, and 1/320th of an inch.

Unidrv provides a single coordinate system to handle these various resolutions. The units in this coordinate system are called master units. A printer's master units are expressed as an (x, y) pair of values, where x is the master unit for the horizontal plane and y is the master unit for the vertical plane.

To determine a plane's master unit, you must calculate the least common multiple (LCM) of the denominators for the actual resolutions. Using the example printer, you would do the following:

  • Calculate the LCM of 80, 160, and 320, which is 320. Thus, the horizontal master unit is 1/320th of an inch.
  • Calculate the LCM of 288 and 96, which is 576. Thus, the vertical master unit is 1/576th of an inch.

To specify a printer's master units, you use the *MasterUnits attribute. The attribute's format is as follows:

*MasterUnits: PAIR (X_Denominator, Y_Denominator)

where X_Denominator is the LCM of the denominators for the horizontal resolutions, and Y_Denominator is the LCM of the denominators for the vertical resolutions. The following GPD entry specifies the master units for the example:

*MasterUnits: PAIR(320, 576)

Generally, position and size values used in GPD file entries must be specified in master units. For example, to specify that the maximum custom page size for our example printer is 9 inches by 12 inches, the following entry would be used, where 9x320=2880 and 12x576=6912:

*MaxSize: PAIR(2880, 6912)

When calculating master units, use only the device resolutions that you want Unidrv to support. For example, if a printer supports horizontal resolutions of 1/80th, 1/96th, 1/160th, and 1/320th of an inch, but you do not intend to specify the 1/96th of an inch resolution within your GPD file, do not include it in your LCM calculation.

If your printer supports cursor commands for moving the cursor position, then the values specified for the *XMoveUnit and *YMoveUnit cursor attributes must be included in master unit calculations. Suppose, for example, that a GPD file contains the following entries:

*XMoveUnit: 60
*YMoveUnit: 60

When calculating this printer's master units, 1/60th of an inch must be included in the horizontal and vertical master unit calculations.


Using Multiple GPD Files in a Minidriver

Unidrv minidrivers can consist of more than one GPD file. This allows you to place characteristics that are common to more than one printer in one or more GPD files, and then to include these common GPD files in a particular printer's individual GPD file.

To include additional GPD files, you use *Include directives, which are described in Preprocessor Directives. You can use multiple *Include directives, as shown in the following example:

*Include: "common1.gpd"
*Include: "common2.gpd"
*Include: "common3.gpd"

The *Include directive's filename parameter cannot be a macro reference, and it cannot include a path specificaion.

Each included file must end with a complete GPD file entry, and the file must contain equal numbers of left and right braces. Included files can also contain *Include directives.

The GPD parser treats the top-level GPD file and all included files as if they were one long file. Therefore, macros defined in one file can be referenced in subsequently included files. If a GPD file entry is duplicated, the most recently parsed entry replaces previous ones. Entries not duplicated are added to Unidrv's database.


Using Resource DLLs in a Minidriver

Typically, printer drivers require the use of such resources as externally stored fonts, icons and other bitmaps, and localizable user interface text strings. Descriptions of these items are placed in a resource DLL, as described in the Platform SDK documentation.

To use resource DLLs in a Unidrv minidriver, you must identify the resources in either of the following manners:

  • If you are using more than one resource DLL, identify them using the RESDLL feature.

    An example usage of the RESDLL feature is as follows:

    *Feature: RESDLL
{
    *Option: FirstRes
    {*Name: "MyFirstRes.dll"}
    *Option: SecondRes
    {*Name: "MySecondRes.dll"}
    *Option: ThirdRes
    {*Name: "MyThirdRes.dll"}
}

    To reference resources contained in one of these resource DLLs, use the following format:

    RESDLL.ResourceOptionName.ResourceID

    Following is an example, which uses an option name from the example feature entry:

    *rcNameID: RESDLL.SecondRes.288

    This example references the string resource that has a resource identifier of 288 and is contained in MySecondRes.dll.

  • If you are using only one resource DLL, you can identify it by assigning a value to the *ResourceDLL attribute.

    To reference a resource contained in this resource DLL, simply specify the appropriate resource identifier, as illustrated in the following example:

    *rcNameID: 288

All resource DLLs used with a minidriver must be specified in a printer INF file. See Installing a Unidrv Minidriver.

Within a GPD file, resource identifiers must be used when assigning values to any entry whose name begins with *rc, such as *rcIconID, *rcPromptMsgID, and *rcCartridgeNameID, for example.

Additionally, if your printer contains hardware-resident fonts, you must provide printer font descriptions for these fonts in the form of .ufm or .ifi files, and you must identify these files in a resource DLL, using the RC_UFM or RC_FONT resource type, respectively.

Microsoft supplies one resource DLL, unires.dll, which contains string resources for the standard features and standard options. The Microsoft-supplied GPD file, stdnames.gpd, assigns a macro symbol name to each resource indentifier. This allows you to reference these resources by their macro name, as illustrated in the following example:

*rcNameID: =LETTERSMALL_DISPLAY


Printer Attributes

Printer attributes are GPD file entries that represent printer characteristics. To set an attribute's value, you include the attribute name and the desired value in the GPD file.

The following topics describe how to specify printer attributes in GPD files:

Printer Attribute Format

Attribute Types

General Attributes


Printer Attribute Format

To specify a printer attribute entry in a GPD file, use the following format:

*AttributeName: AttributeValue

where AttributeName is a predefined name belonging to one of the attribute types, and AttributeValue is one of the GPD value types.

For example, the *ModelName attribute is used for specifying a text string that describes your printer hardware. To assign a value to this attribute, you could place the following line in your GPD file:

*ModelName: "Canon Bubble-Jet BJC-600"

All attribute names are predefined and are recognized by Unidrv's GPD parser.


Attribute Types

Several types of attributes are defined, consisting of:

  • General Attributes

    General attributes are associated with the printer device.

  • Command Attributes

    Command attributes are associated with printer commands.

  • Feature Attributes

    Feature attributes are associated with specific printer features.

  • Option Attributes

    Option attributes are associated with the options belonging to specific features.


General Attributes

General attributes represent one of the attribute types defined by the GPD language. General attributes are not associated with a particular feature or option. The general attributes are divided into the following groups:

Root-level-only attributes

General printing attributes

Text printing attributes

Raster Printing Attributes

Vector Printing Attributes

Usually, you place all general attributes in a GPD file at root level (that is, not inside braces). The root-level-only attributes must always be placed at root level.

Occasionally, the value of a general attribute (except for the root-level-only attributes) is dependent on configuration parameters. In such a case, the attribute entry might be placed within an *Option statement, or a within a *Case statement (located either at root level or contained in an *Option statement). If the attribute is not at root level (either because it is contained in an *Option statement or because it is in a non-root-level *Case statement), the attribute name must be prefixed by the EXTERN_GLOBAL symbol, as follows:

EXTERN_GLOBAL: *AttributeName: AttributeValue

For more information about specifying configuration dependencies, see Conditional Statements.


Root-Level-Only Attributes

Root-level-only attributes are general attributes that describe such driver-specific characteristics as the names of resource files, help files, or additional included GPD files, along with specifications for the driver's master units, version number, and character code page.

Additional root-level-only attributes specify such device-specific characteristics as the printer's name, type, maximum copy capacity, and number of font cartridge slots.

These attributes are called root-level-only attributes because they must always be placed in a GPD file at root level (that is, not inside braces).

The following table lists the root-level-only attributes.

Attribute Name |  | Attribute Parameter | Comments
*CodePage
 | Numeric-valued Windows code page identifier, as described in the Platform SDK documentation. |  |  | Optional. If not specified, Unicode is used. The code page is applied to all displayed strings.
*FontCartSlots
 | Numeric value representing the number of font cartridge slots provided by the printer. |  |  | Optional. If not specified, the default value is zero.
*GPDFileName
 | Quoted text string representing the GPD file name (without path). |  |  | Optional.
*GPDFileVersion
 | Quoted text string representing the current GPD file version. Recommended format is MajorVersion.MinorVersion, such as "1.0". |  |  | Optional. If specified, this string is displayed in Unidrv's About dialog box.
*GPDSpecVersion
 | Quoted text string representing the current GPD specification version. Required format is MajorVersion.MinorVersion, such as "1.0". |  |  | Required. Must be first entry in GPD file, before any comments. This value must be "1.0" for Windows 2000.
*HelpFile
 | Quoted string containing the name of a customized help file, with a .hlp extension. |  |  | Optional. If included, it can add topics or overwrite existing topics in Unidrv's help file. Help file indexes are specified by *HelpIndex attributes for features and options.
*Include
 | Quoted string containing the name of an additional GPD file. |  |  | Obsolete. This entry has been redefined as a preprocessor directive.
*InstalledOptionName
 | Quoted string that is displayed to indicate an installable feature or option is installed. Typically, this string is "Installed", but any appropriate string can be specified. |  |  | Required if *Installable? is TRUE for any features or options (see Feature Attributes), and if *rcInstalledOptionNameID is not specified.
*MasterUnits
 | PAIR representing the printer's master units. |  |  | Required. To reduce potential round-off errors, use the same values for resolution units in font metrics data that you specify for *MasterUnits. (See Unidrv Font Metrics in Customized Font Management.)
*MaxCopies
 | Numeric value representing the maximum number of copies the printer can supporrt. |  |  | Optional. If not specified, the default value is 1.
*ModelName
 | Quoted text string representing the printer model name. |  |  | Required if *rcModelNameID is not specified. String must match name in setup.inf.
*NotInstalledOptionName
 | Quoted string that is displayed to indicate an installable feature or option is not installed. Typically, this string is "Not installed", but any appropriate string can be specified. |  |  | Required if *Installable? is TRUE for any features or options (see Feature Attributes), and if *rcNotInstalledOptionNameID is not specified.
*Personality
 | Quoted string representing the printer language used by the printer. |  |  | Optional. If specified, the string is displayed by Directory Services. Also see *rcPersonalityID.
*PrinterType
 | PAGE, SERIAL, or TTY |  |  | Required.
*PrintRate
 | Numeric value representing the monochrome print rate. Units are specified by *PrintRateUnit. |  |  | Optional. If not specified, the default value is 0.
*PrintRatePPM
 | Numeric value representing the printing speed, in pages per minute. |  |  | Optional. If not specified, the default value is 0.
*PrintRateUnit
 | PPM – Pages/min. CPS – Characters/sec. LPM – Lines/min. IPM – Inches/min. (IPM is for plotters) |  |  | Required if *PrintRate is specified. The specified unit should match the printer type. For example, PPM should be specified for page printers.
*rcInstalledOptionNameID
 | Resource ID of a string resource that is displayed to indicate an installable feature or option is installed. Typically, this string is "Installed", but any appropriate string can be specified. |  |  | Required if *Installable? is TRUE for any features or options (see Feature Attributes), and if *InstalledOptionName is not specified.
*rcNotInstalledOptionNameID
 | Resource ID of a string resource that is displayed to indicate an installable feature or option is not installed. Typically, this string is "Not installed", but any appropriate string can be specified. |  |  | Required if *Installable? is TRUE for any features or options (see Feature Attributes), and if *NotInstalledOptionName is not specified.
*rcPersonalityID
 | Resource ID of a string resource representing the printer language used by the printer. |  |  | Optional. If specified, the string is displayed by Directory Services. Also see *Personality.
*rcPrinterIconID
 | Resource ID of an RC_ICON resource representing an icon associated with the printer. |  |  | Optional. If not specified, a default printer icon is displayed. It is recommended that all RC_ICON resource IDs be numbered contiguously starting with 1.
*ResourceDLL
 | Quoted string containing the name, without path information, of a resource DLL. |  |  | Optional. See Using Resource DLLs in a Minidriver.

For examples, see the sample GPD files.


General Printing Attributes

General printing attributes are general attributes used for specifying characteristics that can be associated with any type of printing. These attributes are divided into the following groups:

Printer Capability Attributes

Color Attributes

Cursor Attributes


Printer Capability Attributes

Printer capability attributes are general printing attributes that specify such printer characteristics as page margin, rotation, and text printing capabilities that affect all paper sizes and orientations.

Attribute Name |  | Attribute Parameter | Comments
*MemoryUsage
 | LIST of constants indicating the types of data that are stored in printer memory. Can be one or more of: FONT RASTER VECTOR If a data type is listed but not supported by the printer, it is ignored. |  | Optional. If not specified, the default value is LIST(FONT, RASTER, VECTOR). For more information, see Describing Printer Memory Configurations.
*OEMCustomData
 | Quoted text string to be supplied to a rendering plug-in when it calls IPrintOemDriverUni::DrvGetGPDData. |  | Required if a rendering plug-in calls IPrintOemDriverUni::DrvGetGPDData. Interpretation of text string contents is determined by the rendering plug-in. This attribute is a relocatable global attribute; it may be placed at the root level (see Root-Level-Only Attributes) to signify that it has no dependency on printer configuration, or it may appear with *Option or *Case constructs if there is some dependency.
*OutputOrderReversed?
 | TRUE or FALSE, indicating whether multipage documents are sorted from last page to first. |  | Optional. If not specified, the default value is FALSE. The EXTERN_GLOBAL symbol should not be used with *OutputOrderReversed?.
*ReselectFont
 | LIST of constants indicating operations after which Unidrv must reselect the current font. Can be on of the following: AFTER_GRXDATA – After any CmdSend xxxx Data raster data emission command. AFTER_XMOVE – After any x-movement cursor command. AFTER_FF – After the CmdFF command. |  | Optional. If not specified, Unidrv does not reselect fonts.
*ReverseBandOrderForEvenPages?
 | TRUE or FALSE, indicating whether reverse banding is enabled. This attribute is used to support printers with auto-duplex capability; that is, printers that are able to print on both sides of a sheet of paper. The section following this table contains more information. |  | The default value of this attribute is FALSE. Setting this attribute to TRUE enables reverse banding order. This attribute is a relocatable global attribute; it may be placed at the root level (see Root-Level-Only Attributes) to signify that it has no dependency on printer configuration, or it may appear with *Option or *Case constructs if there is some dependency.
*RotateCoordinate?
 | TRUE or FALSE, indicating whether the printer supports commands to rotate the coordinate system to match the page orientation. |  | Optional. If not specified, the default value is FALSE. If TRUE, *Option entries for the Orientation feature must specify printer commands. Cannot be placed in a *Case entry.
*RotateFont?
 | TRUE or FALSE, indicating whether the printer automatically rotates fonts to match the page orientation. |  | Optional. If not specified, the default value is FALSE. If TRUE, then *RotateCoordinate? must also be TRUE. Cannot be placed in a *Case entry.
*RotateRaster?
 | TRUE or FALSE, indicating whether the printer automatically rotates raster data to match the page orientation. |  | Optional. If not specified, the default value is FALSE. If TRUE, then *RotateCoordinate? must also be TRUE. Cannot be placed in a *Case entry.
*TextCaps
 | LIST of constants indicating the printer's text capabilities. Can consist of one or more of the TC_xxx flags described in the Platform SDK documentation's description of GetDeviceCaps. |  | Optional. If not specified, Unidrv assumes no text capabilities are supported.

For examples, see the sample GPD files.

Additional Information on *ReverseBandOrderForEvenPages?

A side effect of the auto-duplex capability is that the bottom edge of a page that has just been printed is fed back into the printer, to become the top edge of the next page. To maintain the orientation of the second page relative to the first, the raster image of the second page must be sent to the printer in reverse order. In other words, if the printer printed the front side by sending the top scanline first, it must print the back side bottom scanline first.

When *ReverseBandOrderForEvenPages? is TRUE and duplexing is on, Unidrv enumerates each band in reverse order for even-numbered pages (the back sides of odd-numbered pages). The OEM rendering plug-in needs to cache only one band of data before sending it to the printer. The order of the scanlines within each band is not reversed, so the plug-in must still handle that task, and it must also reverse the order of the bits within each scanline. Although this is extra work for the plug-in, the advantage is that the plug-in does not need to cache any raster data and can begin sending data to the printer immediately.

Both the value of the *ReverseBandOrderForEvenPages? attribute and the driver-simulated rotation affect the way bands are enumerated, which is shown in the following table. The band enumeration order specified in the column headed with TRUE applies when *ReverseBandOrderForEvenPages? is TRUE, and duplexing is selected, and the page to be printed is the second (or back) side. Otherwise the column headed with FALSE applies.

 | TRUE and Even Page | FALSE or Odd Page
Driver-Simulated Rotation |  |
CCW_ROTATE90 | SW_LTOR | SW_RTOL
CCW_ROTATE270 | SW_RTOL | SW_LTOR
No Rotation | SW_UP | SW_DOWN

Legend: SW_LTOR = Left To Right, SW_RTOL = Right To Left, SW_UP = Bottom To Top, SW_DOWN = Top To Bottom.

An OEM rendering plug-in can support auto-duplexing without using the *ReverseBandOrderForEvenPages? attribute. The plug-in can do so by simply caching all of the data for the entire page and sending it to the printer, beginning with the bottom scanline. That scanline, as well as all the others on that page, must be sent in reverse order.

Note: The OEM rendering plug-in is responsible for reversing the order of the bits with each scanline and the order of the scanlines with each band as it sends the data to the printer. To determine when this must be done, the value of the PageNumber standard variable can be obtained by making a call to IPrintOemDriverUni::DrvGetStandardVariable, using the index SVI_PAGENUMBER. If the page number is odd, no reversing is needed. If the number is even and duplexing is selected, reversing is needed.


Color Attributes

Color attributes are general printing attributes that specify characteristics for controlling color printing.

The following table lists the color attributes.

Attribute Name | Attribute Parameter | Comments
*ChangeColorModeOnDoc?
 | TRUE or FALSE. Indicates whether a printer's color mode can be changed between pages of a document without side effects. | Optional. If not specified, the default value is TRUE. Unidrv uses this value to optimize printing speed.
*CyanInMagentaDye
 | Numeric value, from 0 to 1000, indicating the percentage of cyan contamination in magenta dye. The value is the contamination percentage times 100. For example, 8.4% contamination is specified as 840 and 10% is 1000. | Optional. If not specified, a Unidrv-supplied default value is used.
*CyanInYellowDye
 | Numeric value, from 0 to 1000, indicating the percentage of cyan contamination in yellow dye. The value is the contamination percentage times 100. For example, 8.4% contamination is specified as 840 and 10% is 1000. | Optional. If not specified, a Unidrv-supplied default value is used.
*EnableGDIColorMapping
 | TRUE or FALSE. Indicates whether GDI should perform gamut mapping from display to printer color space. | Optional. If not specified, the default value is FALSE. If TRUE, Unidrv sets the HT_FLAG_DO_DEVCLR_XFORM flag in the GDIINFO structure.
*MagentaInCyanDye
 | Numeric value, from 0 to 1000, indicating the percentage of magenta contamination in cyan dye. The value is the contamination percentage times 100. For example, 8.4% contamination is specified as 840 and 10% is 1000. | Optional. If not specified, a Unidrv-supplied default value is used.
*MagentaInYellowDye
 | Numeric value, from 0 to 1000, indicating the percentage of magenta contamination in yellow dye. The value is the contamination percentage times 100. For example, 8.4% contamination is specified as 840 and 10% is 1000. | Optional. If not specified, a Unidrv-supplied default value is used.
*YellowInCyanDye
 | Numeric value, from 0 to 1000, indicating the percentage of yellow contamination in cyan dye. The value is the contamination percentage times 100. For example, 8.4% contamination is specified as 840 and 10% is 1000. | Optional. If not specified, a Unidrv-supplied default value is used.
*YellowInMagentaDye
 | Numeric value, from 0 to 1000, indicating the percentage of yellow contamination in magenta dye. The value is the contamination percentage times 100. For example, 8.4% contamination is specified as 840 and 10% is 1000. | Optional. If not specified, a Unidrv-supplied default value is used.

For examples, see the sample GPD files.


Cursor Attributes

Cursor attributes are general printing attributes that specify characteristics of a printer's cursor.

The following table lists the cursor attributes.

Attribute Name | Attribute Parameter | Comments
*AbsXMovesRightOnly? | TRUE or FALSE. This parameter is used to specify that a device can accept only absolute move commands that move the current position to the right. If a move to the left of the current position is required, Unidrv first sends a carriage return so that the absolute command that is sent is to the right of the new current position. | Optional. If not specified, the default value is FALSE.
*BadCursorMoveInGrxMode | LIST of values representing illegal cursor movements in raster graphics mode. Can be one or more of: X_PORTRAIT X_LANDSCAPE Y_PORTRAIT Y_LANDSCAPE | Optional. If not specified, the default is no restrictions. As an example, LIST(X_PORTRAIT) indicates x-direction movement is not allowed for portrait orientation.
*CursorXAfterCR | One of: AT_PRINTABLE_X_ORIGIN AT_CURSOR_X_ORIGIN Indicates cursor's x-position after a carriage return. | Optional. If not specified, the default value is AT_CURSOR_X_ORIGIN, which is the physical zero position.
*EjectPageWithFF? | TRUE or FALSE. Indicates whether the printer uses form-feed to eject a page. | Optional. If not specified, the default value is FALSE.
*LineSpacingMoveUnit | Positive integer value. Specifies the move units for the CmdSetLineSpacing command. Units are expressed in dots per inch. For a printer whose line spacing move unit is 1/60th of an inch, this entry should be 60. Note that the line spacing move unit must divide evenly into the master Y unit. The *MaxLineSpacing parameter is still in master units independent of whether *LineSpacingMoveUnit is specified. | Optional. The default value is 1 master unit.
*MaxLineSpacing | Numeric value representing the maximum line spacing, in y-master units. | Optional. If not specified, Unidrv assumes there is no maximum value.
*UseSpaceForXMove? | TRUE or FALSE. Indicates whether space characters can be used to perform cursor x-direction movements. | Optional. If not specified, the default value is TRUE. If TRUE, Unidrv uses spaces for coarse moves and NULLs for fine moves. If FALSE, Unidrv uses NULLs for all moves.
*XMoveThreshold | Numeric value, in x-master units, representing the movement threshold beyond which CmdXMoveAbsolute should be used instead of CmdXMoveRelLeft or CmdXMoveRelRight. | Optional. If not specified, the default value is zero, meaning CmdXMoveAbsolute should always be used. Only applicable if all three x-movement commands are specified.
*XMoveUnit | Numeric value, in dots per inch, representing the smallest horizontal movement the printer is capable of. For example, if the movement unit is 1/600th of an inch, the specified value is 600. | Required if the printer supports horizontal movement cursor commands. (If specified, include this value when calculating master units.)
*YMoveAttributes | LIST of values indicating y-movement attributes. Can be one or more of: FAV_LF (favor LF spacing) SEND_CR_FIRST | Optional. If not specified, no attributes are assumed.
*YMoveThreshold | Numeric value, in y-master units, representing the movement threshold beyond which CmdYMoveAbsolute should be used instead of CmdYMoveRelLeft or CmdYMoveRelRight. | Optional. If not specified, the default value is zero, meaning CmdYMoveAbsolute should always be used. Only applicable if all three y-movement commands are specified.
*YMoveUnit | Numeric value, in dots per inch, representing the smallest vertical movement the printer is capable of. For example, if the movement unit is 1/600th of an inch, the specified value is 600. | Required if the printer supports vertical movement cursor commands. (If specified, include this value when calculating master units.)

For examples, see the sample GPD files.


Text Printing Attributes

Text printing attributes are general attributes that specify characteristics of a printer's text printing capabilities. These attributes are divided into the following groups:

Attributes for device fonts

Attributes for downloaded fonts

Attributes for simulated fonts


Attributes for Device Fonts

The following table lists attributes describing the printer's support for device fonts.

Attribute Name | Attribute Parameter | Comments
*CharPosition | UPPERLEFT or BASELINE. Indicates the area of the character bounding box to which the print head should be positioned before printing a character. | Optional. If not specified, the default value is UPPERLEFT.
*DefaultCTT | Numeric value representing the RC_CTT resource identifier of the default character translation table. | Optional. If not specified, there is no translation table. (This attribute is provided only for backward compatibility with GPC files.)
*DefaultFont | Numeric value representing the RC_FONT or RC_UFM resource identifier of the default font. | Required if the printer supports device fonts.
*LookAheadRegion | Numeric value representing the size, in the master y-unit, of the look-ahead region. | Optional. If not specified, the default value is zero. Used only with serial printers, (e. g., HP DeskJet), for ordering text and bitmap data.
*MaxFontUsePerPage | Numeric value representing the maximum number of fonts the printer can use per page. | Optional. If not specified, there is no limit.
*TextYOffset | Numeric value representing the vertical distance, in y master units, by which resident fonts must be repositioned to align with bitmap font baselines. | Optional. If not specified, the default value is 0. (Used with some dot-matrix printers.)

For examples, see the sample GPD files.


Attributes for Downloaded Fonts

The following table lists attributes describing the printer's support for downloaded fonts.

Attribute Name | Attribute Parameter | Comments
*DLSymbolSet | Constant (PC-8, ROMAN-8, and so on) representing the symbol set to be used when downloading TrueType fonts. | Optional. If not specified, the glyph range is assumed to be contiguous within limits specified by *MinGlyphID and *MaxGlyphID.
*FontFormat | Constant value indicating the type of downloading supported. Must be one of the following: HPPCL HPPCL_RES HPPCL_OUTLINE OEM_CALLBACK | Required if the printer can download fonts. If OEM_CALLBACK is specified, font callback functions must be provided. For more information about these callbacks, see Customizing Microsoft's Printer Drivers.
*MaxFontID | Numeric value representing the maximum identifier for soft fonts. | Optional. If not specified, the default value is 65535.
*MaxGlyphID | Numeric value representing the maximum identifier for downloaded font glyphs. | Optional. If not specified and *DLSymbolSet is not specified, the default value is 255. Ignored if *DLSymbolSet is specified.
*MaxNumDownFonts | Numeric value representing the maximum number of soft fonts that can be stored in printer memory at one time. | Optional. If not specified, Unidrv assumes an unlimited number of soft fonts can be stored.
*MinFontID | Numeric value representing the minimum identifier for soft fonts. | Optional. If not specified, the default value is one.
*MinGlyphID | Numeric value representing the minimum identifier for downloaded font glyphs. | Optional. If not specified and *DLSymbolSet is not specified, the default value is 32. Ignored if *DLSymbolSet is specified.
*TextHalftoneThreshold | Numeric value that determines whether Unidrv performs text halftoning for TrueType fonts. If the driver's resolution is greater than or equal to the value specified in this attribute, Unidrv halftones text. | Optional. The default value is 0.

For examples, see the sample GPD files.


Attributes for Simulated Fonts

The following table lists attributes describing the printer's support for simulated fonts.

Attribute Name | Attribute Parameter | Comments
*DiffFontsPerByteMode? | TRUE or FALSE. For printers supporting both single-byte and double-byte modes, this indicates whether the printer maintains separate fonts and font characteristics for each mode. | Optional. If not specified, the default value is FALSE.

For examples, see the sample GPD files.


Raster Printing Attributes

Raster printing attributes are general attributes that specify characteristics of a printer's text printing capabilities. These attributes are divided into the following groups:

Raster Data Compression Attributes

Raster Data Emission Attributes


Raster Data Compression Attributes

There are no attributes associated with raster data compression.

For information about commands associated with raster data compression, see Raster Data Compression Commands.


Raster Data Emission Attributes

The following table lists attributes describing the printer's support for raster data emission.

Attribute Name | Attribute Parameter | Comments
*CursorXAfterSendBlockData | Constant value indicating the cursor's x-position after a block of raster data has been sent. Can be one of: AT_GRXDATA_END AT_GRXDATA_ORIGIN AT_CURSOR_X_ORIGIN meaning the pixel at the start of the graphics block, the pixel after the last one in the block, or the cursor origin. | Optional. If not specified, the default value is AT_GRXDATA_END.
*CursorYAfterSendBlockData | Constant value indicating the cursor's y-position after a block of raster data has been sent. Can be one of: NO_MOVE AUTO_INCREMENT | Optional. If not specified, the default value is NO_MOVE, meaning the cursor's y-position is unchanged.
*MaxMultipleRowBytes | Numeric value indicating the maximum-size raster block to use when downloading raster data on devices that set *SendMultipleRows? to TRUE. | The default value is 32 KB. The largest allowed value is 256 KB.
*MirrorRasterByte? | TRUE or FALSE, indicating whether Unidrv should mirror (reverse) each byte of image data. | Optional. If not specified, the default value is FALSE.
*MirrorRasterPage? | TRUE or FALSE, indicating whether output is to be mirrored. When TRUE, this attribute causes everything on the page to be printed as raster, and then mirrored in the opposite direction from banding. This means that portrait pages are mirrored left to right; landscape pages are mirrored top to bottom. This attribute is most useful for printing on transparencies or back-print film. | Optional. The default value is FALSE. This attribute is a relocatable global attribute. It may appear as a root-level attribute (see Root-Level-Only Attributes) when there are no configuration dependencies, or it may appear with *Option or *Case constructs on a per-media type basis.
*MoveToX0BeforeSetColor? | TRUE or FALSE, indicating whether the cursor's x-coordinate must be set to zero before an explicit color selection command can be sent. | Optional. If not specified, the default value is FALSE. Can be TRUE only if *UseExpColorSelectCmd? is also TRUE.
*OptimizeLeftBound? | TRUE or FALSE, indicating whether Unidrv should remove blanks at the left bound of each band. | Optional. If not specified, the default value is FALSE.
*OutputDataFormat | H_BYTE or V_BYTE, indicating whether the bits in a data byte are mapped to horizontal pixels or vertical pixels. | Optional. If not specified, the default value is H_BYTE.
*RasterSendAllData? | TRUE or FALSE, indicating whether Unidrv should send all raster data, including blank scanlines and blanks within scanlines. | Optional. If not specified, the default value is FALSE.
*SendMultipleRows? | TRUE or FALSE, indicating whether the command specified by CmdSendBlockData can send multiple blocks at one time. |
*StripBlanks | LIST indicating which blanks in a raster data block should be stripped. Can be one or more of: LEADING ENCLOSED TRAILING | Optional. If not specified, Unidrv does not strip any blanks. Also see *MinStripBlankPixels in Option Attributes for the Resolution Feature.
*UseExpColorSelectCmd? | TRUE or FALSE, indicating whether the printer requires explicit color selection commands, separate from color raster data. | Optional. If not specified, the default value is FALSE. Dot-matrix printers require a value of TRUE.

For information about commands associated with raster data emission, see Raster Data Emission Commands.

For examples, see the sample GPD files.


Vector Printing Attributes

Vector printing attributes are general attributes that specify characteristics of a printer's vector printing capabilities. These attributes compose a single group:

Rectangle Area Fill Attributes


Rectangle Area Fill Attributes

The following table lists attributes describing the printer's support for filling rectangle areas.

Attribute Name | Attribute Parameter | Comments
*CursorXAfterRectFill | AT_RECT_X_ORIGIN or AT_RECT_X_END, indicating where the cursor's x-coordinate is after the printer fills a rectangle area. | Optional. If not specified, the default value is AT_RECT_X_ORIGIN.
*CursorYAfterRectFill | AT_RECT_Y_ORIGIN or AT_RECT_Y_END, indicating where the cursor's y-coordinate is after the printer fills a rectangle area. | Optional. If not specified, the default value is AT_RECT_Y_ORIGIN.
*MaxGrayFill | Numeric value representing the maximum gray fill percentage allowed as an argument to the CmdRectGrayFill command. | Optional. If not specified, the default value is 100 (percent).
*MinGrayFill | Numeric value representing the minimum gray fill percentage allowed as an argument to the CmdRectGrayFill command. | Optional. If not specified, the default value is 1 (percent).

For information about commands associated with a printer's rectangle area fill capabilities, see Rectangle Area Fill Commands.

For examples, see the sample GPD files.


Printer Commands

The GPD language provides a predefined command name for each commonly used printer operation. Additionally, customized commands can be defined for device-specific printer options.

Each printer command can be implemented in either of two ways:

  • You can place a device-specific command string in a GPD file. Unidrv sends the command string to the print spooler at the appropriate time.
  • You can implement the IPrintOemUni::CommandCallback COM method, which dynamically generates a command string. Unidrv calls the method whenever it has to send the command to the spooler. For more information see Dynamically-Generated Printer Commands in Customizing Microsoft's Printer Drivers.

The following topics describe how to specify printer commands in GPD files:

Command Entry Format

Command Names

Command Attributes

Command String Format

Command Execution Order


Command Entry Format

To specify a printer command entry in a GPD file, use the following format:

*Command: CommandName {CommandAttributes}

where CommandName is one of the predefined command names, and CommandAttributes is a set of command attributes.

For example, a GPD file might contain the following specification of the CmdStartPage command, which initializes a page for printing.

*Command: CmdStartPage
{
    *Order: PAGE_SETUP.100
    *Cmd: "<0D>"
}

If, for a particular CommandName value, you only need to specify the *Cmd attribute, you can use a shortened version of the command entry format, as follows:

*Command : CommandName : CommandString

where CommandString is a text string representing a printer command escape sequence. For more information about specifying escape sequences, see Command String Format.

For example, a GPD file might contain the following specification of the CmdBoldOn command, which turns on bold text:

*Command: CmdBoldOn: "<1B>(s3B"


Command Names

The GPD language defines a unique command name for each common printer command. Additionally, it defines the CmdSelect command name for specifying commands used for selecting printer options.

The following topics list all the defined command names:

General Printing Commands

Printer Configuration Commands

Option Selection Command

Text Printing Commands

Raster Printing Commands

Vector Printing Commands


General Printing Commands

General printing commands are those that can be associated with any type of printing. These commands are divided into the following groups:

Color Commands

Cursor Commands


Color Commands

The following topics describe the color commands:

Commands for Selecting Primary Background Colors

Commands for Controlling Printer Palettes

Commands for Selecting Pattern Brushes

All commands are specified using the command entry format.

Commands for Selecting Primary Background Colors

The printer commands in the following table are used by printers that do not support programmable color palettes, such as planar color printers (for example, dot matrix printers) and some palette printers (for example, early ink jet printers).

Command | Description | Comments
CmdSelectBlackColor
 | Command to select black background color. | Optional.
CmdSelectBlueColor
 | Command to select blue background color. | Optional.
CmdSelectCyanColor
 | Command to select background cyan color. | Optional.
CmdSelectGreenColor
 | Command to select green background color. | Optional.
CmdSelectMagentaColor
 | Command to select magenta background color. | Optional.
CmdSelectRedColor
 | Command to select red background color. | Optional.
CmdSelectYellowColor
 | Command to select yellow background color. | Optional.
CmdSelectWhiteColor
 | Command to select background white color. | Optional.

For examples, see the sample GPD files.

Commands for Controlling Printer Palettes

The printer commands in the following table are used by printers that support programmable palettes for both foreground (text and vector) printing and for raster printing.

Command | Description | Comments
CmdBeginPaletteDef
 | Command to initialize a color palette definition. | Optional. If not specified, no initialization of palette definitions is needed.
CmdEndPaletteDef
 | Command to end a palette definition. | Optional. If not specified, no command is required to end a palette definition. The *Order attribute can be specified. If it isn't, the *Order attribute associated with the most recently executed option selection command for the Colormode feature is used.
CmdBeginPaletteReDef
 | Command to initialize a color palette redefinition. | Optional. If not specified, no initialization of palette redefinitions is needed.
CmdEndPaletteReDef
 | Command to end a palette redefinition. | Optional. If not specified, no command is required to end a palette redefinition.
CmdDefinePaletteEntry
 | Command to define a palette entry. | Required if the printer supports palettes. In 24 BPP mode, Unidrv allows palettes for which *PaletteSize is 1. This allows GPD developers to implement a direct RGB color selection command for their devices. To do so, set *PaletteSize to 1, and specify the selection color command in the CmdDefinePaletteEntry command. The CmdSelectPaletteEntry command must also be specified but can be defined as a NULL command.
CmdRedefinePaletteEntry
 | Command to redefine a palette entry. | Optional. If not specified, CmdDefinePaletteEntry is used to redefined palette entries.
CmdSelectPaletteEntry
 | Command to select a palette entry as the current color. | Required if the printer supports palettes.

For examples, see the sample GPD files.

Commands for Selecting Pattern Brushes

The printer commands in the following table are used by printers that support downloading and selecting pattern brushes.

Command | Description | Comments
CmdDownloadPattern
 | Command to deliver a brush pattern to the printer. | Optional. If specified, CmdSelectPattern must also be specified.
CmdSelectBlackBrush
 | Command to a solid black brush as the current brush. | Required if the printer supports brushes.
CmdSelectPattern
 | Command to select a downloaded brush pattern. | Optional. If specified, CmdDownloadPattern must also be specified.
CmdSelectWhiteBrush
 | Command to select a solid white brush as the current brush. | Optional.


Cursor Commands

The printer commands in the following table control cursor movement. All commands are specified using the command entry format.

Command | Description | Comments
CmdBackSpace
 | Command to move the cursor back over the last printed character. | Optional. Used only for overstriking.
CmdCR
 | Command to more the cursor to its left-most x-position. | Required.
CmdFF
 | Command to eject a page. | Required if *EjectPageWithFF? is set to TRUE.
CmdLF
 | Command to move the cursor to the next line. | Optional. Amount of movement is specified by CmdSetLineSpacing.
CmdPopCursor
 | Command to pop the last saved cursor position from the stack. | Required if CmdPushCursor is specified.
CmdPushCursor
 | Command to push the current cursor position onto the stack. | Optional.
CmdSetLineSpacing
 | Command to set the distance the cursor moves when a CmdLF command is issued. | Optional.
CmdUniDirectionOff
 | Command to disable unidirectional printing, thereby enabling bi-directional printing. | Optional.
CmdUniDirectionOn
 | Command to enable unidirectional printing. | Optional. If not present, print in bi-directional mode.
CmdXMoveAbsolute
 | Command to move the cursor to an absolute x-position. | Optional. The command string can include only one standard variable, which is used to specify the distance.
CmdXMoveRelLeft
 | Command to move the cursor to the left from the current x-position, by the specified amount. | Optional. The command string can include only one standard variable, which is used to specify the distance.
CmdXMoveRelRight
 | Command to move the cursor to the right from the current x-position, by the specified amount. | Optional. The command string can include only one standard variable, which is used to specify the distance.
CmdYMoveAbsolute
 | Command to move the cursor to an absolute y-position. | Optional. The command string can include only one standard variable, which is used to specify the distance.
CmdYMoveRelDown
 | Command to move the cursor down from the current y-position, by the specified amount. | Optional. The command string can include only one standard variable, which is used to specify the distance.
CmdYMoveRelUp
 | Command to move the cursor up from the current y-position, by the specified amount. | Optional. The command string can include only one standard variable, which is used to specify the distance.

For examples, see the sample GPD files.


Printer Configuration Commands

The following table lists the printer configuration commands. All commands are specified using the command entry format.

Command | Description | Comments
CmdStartJob | Command to initialize a print job. | Optional. Command execution order must be specified.
CmdStartDoc | Command to initialize a document. | Optional. Command execution order must be specified.
CmdStartPage | Command to initialize a page and set the cursor position to (0,0) in cursor coordinates. | Optional. Command execution order must be specified.
CmdEndPage | Command to finish printing a page. | Optional. Command execution order must be specified.
CmdEndDoc | Command to finish printing a document. | Optional. Command execution order must be specified.
CmdEndJob | Command to complete a print job. | Optional. Command execution order must be specified.
CmdCopies | Command to specify the number of copies to print. | Optional. Command execution order must be specified.
CmdSleepTimeOut | Command to specify the number of minutes for the printer to wait before entering power-save mode. | Optional. Command execution order must be specified.

For examples, see the sample GPD files.


Option Selection Command

The following table lists the option selection command. The command is specified using the command entry format.

Command | Description | Comments
CmdSelect | Command to select a printer option. | Required for each option. Command execution order must be specified.

For examples, see the sample GPD files.


Text Printing Commands

Text printing commands are those that are associated with printing text. These commands are divided into the following groups:

Commands for Device Fonts

Commands for Downloaded Fonts

Commands for Simulated Fonts


Commands for Device Fonts

There are no commands associated with device fonts. For information about device font attributes, see Attributes for Device Fonts.


Commands for Downloaded Fonts

The following table lists the commands for controlling downloaded fonts. All commands are specified using the command entry format.

Command | Description | Comments
CmdDeleteFont | Command to delete a soft font by specifying its identifier. | Optional. Specify this command only if a deleted font's allocated memory can be immediately reclaimed.
CmdDeselectFontID | Command to deselect the current font ID in order to make the font inactive. | Optional. If not present, the current font does not need to be deselected when a new font is selected.
CmdSelectFontHeight | Command to select the height of a downloaded font. | Optional. If not present, the printer does not support scaleable, downloadable True Type outline fonts. This command is needed for HPPCL_OUTLINE format.
CmdSelectFontID | Command to select the current font ID in order to make the font active. | Required if the printer supports downloaded fonts.
CmdSelectFontWidth | Command to select the width of a downloaded font. | Optional. If not present, the width of the downloaded font is scaled proportionally its height.
CmdSetCharCode | Command to specify the character code of the next character to be downloaded or deleted. | Required if the printer supports downloaded fonts.
CmdSetFontID | Command to set the current font ID. | Required if the printer supports downloaded fonts.

For examples, see the sample GPD files.


Commands for Simulated Fonts

The following table lists the commands for controlling simulated fonts. All commands are specified using the command entry format.

Command | Description | Comments
CmdBoldOff | Command to disable bolding. | Optional. Must be specified if CmdBoldOn is specified.
CmdBoldOn | Command to enable bolding. | Optional. If specified, Unidrv sends this command to enable bolding and sends CmdBoldOff to disable bolding.
CmdClearAllFontAttribs | Single command to disable bold, italic, and underline capabilities. | Optional. Can be specified if the printer supports bold, italic, or underlining, but supports only a single command to disable them all. Use instead of CmdBoldOff, CmdItalicOff and CmdUnderlineOff.
CmdItalicOff | Command to disable italics. | Optional. Must be specified if CmdItalicOn is specified.
CmdItalicOn | Command to enable italics. | Optional. If specified, Unidrv sends this command to enable italics and sends CmdItalicOff to disable italics.
CmdSelectDoubleByteMode | Command to enable double-byte printing. | Optional. Must be specified if CmdSelectSingleByteMode is specified.
CmdSelectSingleByteMode | Command to enable single-byte printing. | Optional. Must be specified if the printer can be switched between single-byte and double-byte modes.
CmdSetFontSim | Single command to set bold, italic, underline, and strike-through capabilities. | Optional. Must be specified if font characteristics must be set each time the font is used (for printers that do not store font characteristics).
CmdStrikeThruOff | Command to disable strike-through. | Optional. Must be specified if CmdStrikeThruOn is specified.
CmdStrikeThruOn | Command to enable strike-through. | Optional. If specified, Unidrv sends this command to enable strike-through and sends CmdStrikeThruOff to disable strike-through.
CmdUnderlineOff | Command to disable underlining. | Optional. Must be specified if CmdUnderlineOn is specified.
CmdUnderlineOn | Command to enable underlining. | Optional. If specified, Unidrv sends this command to enable underlining and sends CmdUnderlineOff to disable underlining.
CmdVerticalPrintingOff | Command to disable vertical printing. | Optional. Must be specified if CmdVerticalPrintingOn is specified.
CmdVerticalPrintingOn | Command to enable vertical printing. | Optional. Must be specified if the printer supports vertical printing.
CmdWhiteTextOff | Command to disable printing white text. | Optional. Must be specified if CmdWhiteTextOn is specified.
CmdWhiteTextOn | Command to enable printing white text. | Optional. If specified, Unidrv sends this command to enable printing white text and sends CmdWhiteTextOff to disable printing white text. (This command is provided for backwards compatibility with GPC 3.0.)

For examples, see the sample GPD files.


Raster Printing Commands

Raster printing commands are those that are associated with printing rasterized graphics. These commands are divided into the following groups:

Raster Data Compression Commands

Raster Data Emission Commands


Raster Data Compression Commands

The following table lists the raster data compression commands. All commands are specified using the command entry format.

For more information about raster data compression commands, see Compressing Raster Data.

Command | Description | Comments
CmdDisableCompression | Command to disable the printer's acceptance of all compressed data types. | Optional.
CmdEnableDRC | Command to enable the printer's acceptance of DRC-compressed data. | Optional. If not specified, Unidrv does not use Delta-Row compression.
CmdEnableFE_RLE | Command to enable the printer's acceptance of FE-RLE-compressed data. | Optional. If not specified, Unidrv does not use FE-RLE compression.
CmdEnableOEMComp | Command to enable the printer's acceptance of a customized compressed data type. | Optional. If not specified, Unidrv does not use customized data compression.
CmdEnableTIFF4 | Command to enable the printer's acceptance of TIFF 4.0-compressed data. | Optional. If not specified, Unidrv does not use TIFF4.0 compression.

For examples, see the sample GPD files.


Raster Data Emission Commands

The following table lists the raster data emission commands. All commands are specified using the command entry format.

Command | Description | Comments
CmdBeginRaster | Command to initialize a raster data transfer. | Optional. If not specified, Unidrv assumes no initialization is needed.
CmdEndRaster | Command to complete a raster data transfer. | Optional. If not specified, Unidrv assumes no transfer-completion operations are needed.
CmdSetDestBmpHeight | Command to set the height of a destination bitmap. | Optional. Applicable only if the printer supports scalable bitmaps.
CmdSetDestBmpWidth | Command to set the width of a destination bitmap. | Optional. Applicable only if the printer supports scalable bitmaps.
CmdSetSrcBmpHeight | Command to set the height of a source bitmap. | Optional. Applicable only if the printer supports scalable bitmaps.
CmdSetSrcBmpWidth | Command to set the width of a source bitmap. | Optional. Applicable only if the printer supports scalable bitmaps.
CmdSendBlockData | Command to deliver a block of data to the printer. | Required. If *OutputDataFormat is V_BYTE, a block contains the data for one physical pass of the print head. (See *PinsPerPhysPass). If *OutputDataFormat is H_BYTE, a block contains the data for one logical pass of the print head. (See *PinsPerLogPass).
CmdEndBlockData | Command to indicate the end of a block of data that was sent using the CmdSendBlockData command. | Optional. If not specified, Unidrv assumes no command is needed to indicate the end of a block. (Used by some dot-matrix printers.)
CmdSendBlackData | Command to deliver black plane data to the printer. | Required if *UseExpColorSelectCmd? attribute is FALSE.
CmdSendBlueData | Command to deliver blue plane data to the printer. | Required if *UseExpColorSelectCmd? attribute is FALSE.
CmdSendCyanData | Command to deliver cyan plane data to the printer. | Required if *UseExpColorSelectCmd? attribute is FALSE.
CmdSendGreenData | Command to deliver green plane data to the printer. | Required if *UseExpColorSelectCmd? attribute is FALSE.
CmdSendMagentaData | Command to deliver magenta plane data to the printer. | Required if *UseExpColorSelectCmd? attribute is FALSE.
CmdSendRedData | Command to deliver red plane data to the printer. | Required if *UseExpColorSelectCmd? attribute is FALSE.
CmdSendYellowData | Command to deliver yellow plane data to the printer. | Required if *UseExpColorSelectCmd? attribute is FALSE.

For examples, see the sample GPD files.


Vector Printing Commands

Vector printing commands are those that are associated with printing vector graphics. These commands compose a single group:

Rectangle Area Fill Commands


Rectangle Area Fill Commands

The following table lists the rectangle area fill commands. All commands are specified using the command entry format.

Command | Description | Comments
CmdRectBlackFill | Command to black fill a rectangle. | Optional. If not specified, Unidrv attempts black fill by specifying the CmdRectGrayFill command with a gray percentage of *MaxGrayFill.
CmdRectGrayFill | Command to gray fill a rectangle. (Does not erase the background.) | Optional. If not specified, Unidrv assumes no gray fill capability. Command string typically includes the GrayPercentage variable.
CmdRectWhiteFill | Command to white fill a rectangle. (Erases the background.) | Optional. If not specified, Unidrv assumes no erasing white fill. In that case, Unidrv returns failure if an application requests white fill, because gray fill cannot erase the background.
CmdSetRectHeight | Command to set the rectangle height. | Optional. Must be specified if CmdSetRectWidth is specified.
CmdSetRectSize | Command to set the rectangle width and height. Not supported for Windows 2000 or later. | Optional. Used for printers that set the width and height in one command.
CmdSetRectWidth | Command to set the rectangle width. | Optional. Must be specified if CmdSetRectHeight is specified.

For examples, see the sample GPD files.


Command Attributes

When specifying a printer command, you use attributes to provide Unidrv with the following information:

  • The escape sequence that causes the hardware to perform the operation, if the operation is implemented in printer hardware.
  • The callback identifier and parameters required by the IPrintOemUni::CommandCallback method, if the operation is implemented in a rendering plug-in.
  • The order in which the command should be sent, relative to other commands.

The following table lists the command attributes in alphabetic order and describes their parameters.

Attribute Name | Attribute Parameter | Comments
*CallbackID | Positive numeric value, passed to the rendering plug-in's IPrintOemUni::CommandCallback method as its dCmdCbID argument. | Required for dynamically-generated printer commands. Not valid if *Cmd is specified.
*Cmd | Text string containing a printer command escape sequence, specified using the Command String Format. | Required unless *CallbackID is specified.
*NoPageEject? | TRUE or FALSE, indicating whether executing the command causes the printer to eject the current physical page. Used only if *Order specifies the DOC_SETUP section and if DUPLEX printing is enabled. To avoid premature page ejection between duplexed document pages, Unidrv only issues commands with this attribute set to TRUE, if possible. | Optional. If not specified, the default value is FALSE, meaning the command might cause page ejection. Must not be TRUE if a command causes side effects (that is, if the command modifies printer settings outside of those controlled by commands with *NoPageEject? set to TRUE).
*Order | Section name and order number, as described in Command Execution Order. | Valid only with configuration commands and customized option commands, unless stated in the command description.
*Params | List of standard variables, passed to the rendering plug-in's IPrintOemUni::CommandCallback method in the EXTRAPARAM structure that is passed as its pdwParams argument. | Valid only if *CallbackID is also specified.

For examples, see the sample GPD files.


Command String Format

Command strings are used to specify the escape sequences that Unidrv must send to printer hardware. Command strings can be made up of the following elements:

  • Quoted text strings, which have the following format:

    "TextString"

    where TextString is a text string.

  • Command arguments, which have the following format:

    %ArgumentType{StandardVariableExpression}

    where ArgumentType is a letter representing one of the command string argument types, and StandardVariableExpression is a standard variable expression.

Any number of quoted text strings and command arguments can be combined in a command string.

As an example, a printer's command to set a rectangle's gray fill percentage might be specified as follows:

*Command: CmdRectGrayFill: "<1B>*c" %d{GrayPercentage} "g2P"

To send a percent sign (%) to a printer, include two percent sign characters (%%) in the command string. If the percent sign is at the end of the command string, you must use the hexadecimal equivalent, as in:
"string <25 25>".


Command String Argument Types

When you include arguments in command strings, you must specify each argument's type. Each argument type specification is a single letter, preceded by a percent sign.

The following table lists all the argument type specifiers.

Argument Type Specifier | Description of resulting value
%<Digits>d | ASCII string representing a decimal value, including a minus sign if negative. <Digits> is an optional number indicating the string length.
%<Digits>D | ASCII string representing decimal value, including a plus or minus sign. <Digits> is an optional number indicating the string length.
%c | Binary byte.
%C | Binary byte added to ASCII "0".
%f | Unsigned ASCII string representing a decimal value, with a decimal point inserted as the third character from the right, as in "12.25".
%g | 2 * ABS(Parameter) + IS_NEGATIVE(Parameter) as a base-64 number, least significant digit to most significant digit. The most significant digit (0-63) is represented by bytes 191 through 254. All other digits are represented by bytes 63 through 126. "IS_NEGATIVE(Parameter)" is 1 if Parameter is negative, and zero otherwise.
%l | Binary word, least significant byte first.
%m | Binary word, most significant byte first.
%n | Canon integer encoding. Binary value encoded from most significant byte to least significant byte. The 4 least significant bits are encoded as 001sbbbb , where s represents the sign (0 is negative, 1 is positive), and b represents a significant bit of the integer. The next most significant 6 bits are encoded as 01bbbbbb. For example, 254 (11111110) is represented as (01001111 00111110).
%q | ASCII string representing a QUME hexadecimal number. For Toshiba/Qume devices.
%v | NEC VFU (Vertical Format Unit) encoding. The specified variable's value is divided by 1/6 inch. The result is the number of times VFU data is sent to the printer.

You can specify a range of acceptable values for any argument. To do so, include the argument's minimum and maximum values by placing them inside a set of square brackets ( [, ] ), immediately following the argument type specifier, and separating the values by a comma. For example, the following command specifies 0 through 255 as an acceptable range for the value of LinefeedSpacing/2:

*Command:CmdSetLineSpacing{*Cmd:"<1B>3"%c[0,255]{(LinefeedSpacing/2)}}


Standard Variable Expressions

When you specify arguments in a command string, you can specify the argument value as an expression. This expression can perform operations using the current values of the standard variables. Each standard variable expression within a command string is delimited by braces ( {, } ).

A standard variable expression can consist of a combination of the following components:

  • Zero, one, or more standard variables
  • Integer numeric values
  • Expression operators

A standard variable expression cannot contain embedded macro references.

The expression operators are included in the following table.

Operator | Definitions
Val1 + Val2 | Addition.
Val1 - Val2 | Subtraction.
Val1 / Val2 | Division.
Val1 * Val2 | Multiplication.
max (Val1, Val2) | Maximum. Value is the maximum of Val1 and Val2.
max_repeat (Val1) | See Using max_repeat.
min (Val1, Val2) | Minimum. Value is the minimum of Val1 and Val2.
mod (Val1, Val2) | Modulus. Value is the remainder of dividing Val1 by Val2.
( ) | Precedence operators. If not used, C-language precedence is used.

Standard variable expressions do not modify the values assigned to the standard variables. The calculated value is placed in the escape sequence, using the format specified by the command string argument type specifier.

Using max_repeat

The use of max_repeat is best explained with an example. Suppose a GPD file contains the following entry:

*Command:CmdXMoveRelRight{*Cmd:"<1B>["%d[0,9600]{max_repeat((DestXRel/4))}"a"}

This command contains a single argument, of type %d. It also contains an argument range specification. Whenever Unidrv sends this command to the printer, it first calculates DestXRel/4 and determines if it is within the specified range. If the calculated value is greater than 9600, Unidrv sends the command repeatedly, with a maximum value of 9600, until the specified value has been sent. Thus if DestXRel/4 equals 20,000, Unidrv sends the following commands:

<1B>[9600
<1B>[9600
<1B>[800

The max_repeat operator can be used only if the following conditions are met:

  • A command string includes only a single argument.
  • The argument includes a range specification.


Command Execution Order

Printer commands must be sent to printer hardware in a meaningful order. For most of the command names defined in the GPD language, Unidrv knows when to send the command's escape sequence to the printer. There are two exceptions:

The option selection command

Printer configuration commands

For both of these command types, you must specify the order in which the commands should be executed.

Command execution order is made up of two components — a job section name and a sequence order number. The Unidrv driver divides each print job into six sections. For each section, Unidrv sends the printer the commands assigned to the section, in the specified sequence. The following sections are defined:

JOB_SETUP
Commands assigned to the JOB_SETUP section are sent once per job. They are the first commands sent when a new job begins. These commands are sent from within Unidrv's implementation of the DrvStartDoc function.
DOC_SETUP
Commands assigned to the DOC_SETUP section are sent before the first page of a document is sent. The commands are sent from within Unidrv's implementation of the DrvStartDoc function. (These commands are also sent after an application calls the Win32 ResetDC function. Commands in this section must not remove downloaded information, such as soft fonts and patterns.)
PAGE_SETUP
Commands assigned to the PAGE_SETUP section are sent at the beginning of each new page, before drawing begins. These commands are sent from within Unidrv's implementation of the DrvStartPage function.
PAGE_FINISH
Commands assigned to the PAGE_FINISH section are sent at the end of each page, after drawing is complete. These commands are sent from within Unidrv's implementation of the DrvSendPage function.
DOC_FINISH
Commands assigned to the DOC_FINISH section are sent after the last page of a document is sent. The commands are sent from within Unidrv's implementation of the DrvEndDoc function. (Commands in this section must not remove downloaded information, such as soft fonts and patterns.)
JOB_FINISH
Commands assigned to the JOB_FINISH section are sent once per job. They are the last commands sent when a job ends. These commands are sent from within Unidrv's implementation of the DrvEndDoc function.

Within each of these sections, commands are executed in the order indicated by their sequence numbers.

To specify a command's section and sequence number, use the *Order attribute, which is one of the command attributes. The format is:

*Order: SectionName.SequenceNumber

where SectionName is one of JOB_SETUP, DOC_SETUP, PAGE_SETUP, PAGE_FINISH, DOC_FINISH, or JOB_FINISH, and SequenceNumber is a numeric value.

Sequence numbers do not have to be consecutive, but each number specified within a section must be unique. Commands within a section are executed from the one with the lowest sequence number to that with the highest. For example, the following entries indicate that options for the InputBin, PaperSize, and Resolution features are assigned to the DOC_SETUP section and are sent in the specified order:

*Feature: InputBin
{
    *DefaultOption: Auto
    *Option: Auto
    {
        *Name: "Auto Tray"
        *Command: CmdSelect
        {
            *Order: DOC_SETUP.50
            *Cmd: "<1B>(1<010014>"
        }
    }
    ...
}
*Feature: PaperSize
{
    *DefaultOption: Letter
    *Option: Letter
    {
        *Name: "Letter size"
        *Command: CmdSelect
        {
            *Order: DOC_SETUP.60
            *Cmd: "<1B>(g<0300>n<01>r"
        }
    }
    ...
}
*Feature: Resolution
{
    *DefaultOption: 360dpi
    *Option: 360dpi
    {
        *Name: "360 dpi x 360dpi"
        *Command: CmdSelect
        {
            *Order: DOC_SETUP.70
            *Cmd: "<1B>(d<020001>"
        }
    }
    ...
}


Printer Features

Printer features are capabilities that can be controlled by the Unidrv driver. By listing a feature and its characteristics in a GPD file, you inform the Unidrv driver that your printer supports the feature.

Each printer feature can be assigned to one or more states, and printer options are used to define the possible states. For example, if your printer accepts both letter-sized and legal-sized pages, your GPD file should specify the PaperSize feature, along with the Letter and Legal options.

All features and their associated options are listed on either the printer property sheet or the document property sheet associated with the printer. For more information about these property sheets, see Unidrv User Interface.

This section explains GPD language support for both standard features and customized features. Additional topics in this section discuss the feature entry format, feature attributes, and feature conflict priority.


Standard Features

Standard features are printer features commonly provided by most printers. They are identified by predefined names that the GPD language recognizes. (Resource identifiers for strings representing these names are contained in stdnames.gpd, which is supplied with this DDK.) Some standard features are required and must be specified for every printer. Others are optional.

The following table lists all the standard features, in alphabetic order, and indicates whether each feature accepts standard options or customized options.

Feature Name | Description | Standard Options | Comments
Collate | Page collation | See Standard Options. Customized options are not allowed. | Optional. If not specified, Unidrv does not support page collation.
ColorMode | Color printing modes | None. All options are customized. Also see Option Attributes for the ColorMode Feature. | Optional. If not specified, Unidrv renders images in single-plane, 1-bit-per-pixel format.
Duplex | Two-sided printing | See Standard Options. Customized options are not allowed. | Optional. If not specified, Unidrv performs only single-sided printing.
Halftone | Halftoning capabilities | See Standard Options. Customized options are allowed. Also see Option Attributes for the Halftone Feature. | Optional. If not specified, Unidrv selects a GDI-supported halftoning method. Also see Halftoning with Unidrv.
InputBin | Types of input bins | See Standard Options. Customized options are allowed. Also see Option Attributes for the InputBin Feature. | Required. Customized input bin names must be 24 characters or less.
MediaType | Types of printing media | See Standard Options. Customized options are allowed. | Optional. If not specified, the printer's default medium is always used.
Memory | Printer memory configurations | All options are customized. Also see Option Attributes for the Memory Feature. | Optional. If specified, Unidrv attempts to keep track of memory usage. Default *FeatureType value is PRINTER_PROPERTY.
Orientation | Paper orientations | See Standard Options. Customized options are not allowed. | Optional. If not specified, the default orientation is PORTRAIT.
OutputBin | Types of output bins | None. All options are customized. Also see Option Attributes for the OutputBin Feature. | Optional. If not specified, Unidrv does not attempt to select an output bin.
PageProtect | Enables protection of current print page | See Standard Options. Customized options are not allowed. | Optional. If not specified, the default value is OFF. Unidrv only enables page protection if enough printer memory is available. Default *FeatureType value is PRINTER_PROPERTY. Also see *PageProtectMem.
PaperSize | Paper sizes | See Standard Options. Customized options are allowed. Also see Option Attributes for the PaperSize Feature. | Required. At least one option must be specified. The CUSTOMSIZE option allows printer users to specify a paper size.
RESDLL | Resource DLLs | All options are customized. See Using Resource DLLs in a Minidriver. | Optional. Also see *ResourceDLL.
Resolution | Printing resolutions | All options are customized. Also see Option Attributes for the Resolution Feature. | Required. At least one option must be specified.
Stapling | Stapling capabilities | All options are customized. | Optional. If specified, Directory Services indicates the printer supports stapling.

For examples, see the sample GPD files.


Customized Features

Customized features are those that are specific to your hardware. You create unique names for these features. For each customized feature, you must specify a set of customized options. For example, suppose your printer provides an economy mode of operation. Because the GPD language does not provide a feature for describing this capability, you must define a customized feature and its options. The feature's specification might appear as follows:

*Feature: EconoMode
{
    *Name: "Economy Mode"
    *FeatureType: PRINTER_PROPERTY
    *DefaultOption: EconoModeOff
    *Option: EconoModeOff
    {
        *Name: "Off"
        *Command: CmdSelect
         {
             *Order: DOC_SETUP.5
             *Cmd: "@PJL SET ECONOMODE=OFF<0A>"
         }
    }
    *Option: EconoModeOn
    {
        *Name: "On"
        *Command: CmdSelect
        {
            *Order: DOC_SETUP.5
            *Cmd: "@PJL SET ECONOMODE=ON<0A>"
        }
    }
}


Feature Entry Format

To specify a printer feature entry in a GPD file, use the following format:

*Feature: FeatureName {FeatureAttributes}

where FeatureName is the name of either one of the predefined standard features or a customized feature name, and FeatureAttributes is a set of feature attributes.

For example, a GPD file might contain the following specification of the standard InputBin feature.

*Feature: InputBin
{
    *Name: "Paper Bin"
    *DefaultOption: Upper
    *Option: Upper
    {
        *Name: "Upper Tray"
        *Command: CmdSelect
        {
            *Order: DOC_SETUP.10
            *Cmd: "<1B>&l1H"
        }
        *Constraints: PaperSize.Env10
    }
    *Option: Manual
    {
        *Name: "Manual Feed"
        *Command: CmdSelect
        {
            *Order: DOC_SETUP.10
            *Cmd: "<1B>&l2H"
        }
        *Installable?: TRUE
    }
}

If you repeat a feature specification by, for example, including two or more InputBin feature entries, then the following rules apply:

  • Attributes and options that are not duplicated are added to Unidrv's database.
  • Attributes and options that are duplicated are overwritten, and Unidrv retains only the last specification.

You can control the order in which features are displayed to the user. See Specifying Feature and Option Display Order.


Feature Attributes

When specifying a printer feature, you use attributes to provide Unidrv with the following information:

  • A text string representing the feature's display name.
  • The set of printer options associated with the feature.
  • A Boolean value indicating whether the feature is always present or is installable.
  • The feature type and priority, if the feature is customized, indicating on which property sheet the feature is displayed and its relative priority.

The following table lists the feature attributes in alphabetic order and describes their parameters.

Attribute Name | Attribute Parameter | Comments
*ConcealFromUI?
 | TRUE or FALSE, indicating whether the feature should be displayed in the user interface. Not supported for Windows 2000 or later. | Optional. If not specified the default value is FALSE, which means the feature is displayed. Should be TRUE only if a feature has only one option (for example, one resolution) and is thus not user-modifiable, or, if the feature's option selection is controlled by setting another feature's options.
*ConflictPriority
 | Numeric value representing the feature's priority, where 1 is the highest priority. | Optional. See Feature Conflict Priority.
*DefaultOption
 | Name of one of the feature's options. | Optional. If not specified, the first option listed in a *Feature entry is the default. For the PaperSize feature, the default options for Unidrv are A4 for metric locales and Letter elsewhere. If the default PaperSize does not exist, Unidrv uses the PaperSize option that is specified by the *DefaultOption keyword.
*Featuretype
 | DOC_PROPERTY JOB_PROPERTY PRINTER_PROPERTY If DOC_PROPERTY or JOB_PROPERTY, the feature is assigned to the document property sheet. If PRINTER_PROPERTY, the feature is assigned to the printer property sheet. | Required for customized features. Optional for standard features. If not specified, the default value for standard features is DOC_PROPERTY unless otherwise noted. If PRINTER_PROPERTY, the feature's option value is saved in the registry. If DOC_PROPERTY or JOB_PROPERTY, the feature's option value is saved with the document.
*HelpIndex
 | Numeric value representing an index into the help file specified by the *HelpFile root-level-only attribute. | (Also an option attribute.)
*Installable?
 | TRUE or FALSE, indicating whether the feature is installable. (FALSE means always installed.) For more information, see Handling Installable Features and Options. | Optional. If not specified, the default value is FALSE. If TRUE, all the feature's options are also installable, except for the first one specified. If FALSE, at least one of the feature's options must also always be installed. (Also an option attribute.)
*InstallableFeatureName
 | Text string that is displayed to ask the user whether an installable feature is actually installed. For more information, see Handling Installable Features and Options. | Required if *Installable? is TRUE and *rcInstallableFeatureNameID is not specified. (Also an option attribute.)
*Name
 | Text string used as the feature's display name on the printer's property sheet. | Optional. If not specified, then *rcNameID must be specified. (Also an option attribute.)
*Option
 | Option parameters, as described in Option Entry Format. | Required. Use an *Option entry for each option associated with the feature.
*rcIconID
 | Resource ID of an icon resource associated with the feature. | Optional. If not specified, Unidrv does not display an icon for the feature on the printer property sheet. (Also an option attribute.)
*rcInstallableFeatureNameID
 | Resource ID of a text string that is displayed to ask the user whether an installable feature is actually installed. For more information, see Handling Installable Features and Options. | Required if *Installable? is TRUE and *InstallableFeatureName is not specified. (Also an option attribute.)
*rcNameID
 | Resource ID of string resource representing the feature name. (Zero is not a valid resource ID.) | Optional. If not specified, then *Name must be specified. (Also an option attribute.)
*UpdateQualityMacro?
 | TRUE or FALSE, indicating whether the feature is included in a conditional statement that specifies quality settings (see Controlling Image Quality). | Optional. If not specified, the default value is FALSE. (The value is forced to TRUE if the feature is included in a conditional statement that specifies quality settings.)

For examples, see the sample GPD files.


Feature Conflict Priority

A feature's conflict priority identifies the priority that a feature should have when Unidrv's user interface code enforces option constraints.

The GPD parser assigns a conflict priority to a feature in the following order, from highest to lowest priority:

  1. Installable features that are actually installed. (See Handling Installable Features and Options.)
  2. Features with *FeatureType set to PRINTER_PROPERTY.
  3. Features with *FeatureType set to DOC_PROPERTY or JOB_PROPERTY.

Features within each feature type are assigned a relative priority based on the value specified for the feature's *ConflictPriority attribute. Thus, for example, a PRINTER_PROPERTY feature with a *ConflictPriority attribute of 1 has a higher priority than a DOC_PROPERTY feature with a *ConflictPriority attribute of 3. Features that do not have a *ConflictPriority attribute have a lower priority than those that do.

For more information about the *FeatureType and *ConflictPriority attributes, see Feature Attributes.


Printer Options

Printer options represent the states that can be assigned to printer features. For example, if a printer can use both letter-sized and legal-sized paper, then LETTER and LEGAL are specified as options for its PaperSize feature.

This section discusses GPD language support for both standard options and customized options.

Additional topics in this section discuss the option entry format, option attributes, and option constraints.


Standard Options

Standard options are those that are associated with standard features. They are identified by predefined names that the GPD language recognizes. (Resource identifiers for strings representing these names are contained in stdnames.gpd, which is supplied with this DDK.)

The following table lists the standard option names that are permitted for each standard feature. Use these names as arguments to *Option entries.

Feature Name | Standard Option Names | Customized Options Allowed?
Collate | ON, OFF | No.
ColorMode | No standard options. | Yes. Also see Handling Color Formats and Controlling Image Quality.
Duplex | HORIZONTAL, VERTICAL, NONE | No.
Halftone HT_PATSIZE_2x2
HT_PATSIZE_2x2_M
HT_PATSIZE_4x4
HT_PATSIZE_4x4_M
HT_PATSIZE_6x6
HT_PATSIZE_6x6_M
HT_PATSIZE_8x8
HT_PATSIZE_8x8_M
HT_PATSIZE_10x10
HT_PATSIZE_10x10_M
HT_PATSIZE_12x12
HT_PATSIZE_12x12_M
HT_PATSIZE_14x14
HT_PATSIZE_14x14_M
HT_PATSIZE_16x16
HT_PATSIZE_16x16_M
HT_PATSIZE_SUPERCELL
HT_PATSIZE_SUPERCELL_M
HT_PATSIZE_AUTO 		Yes. Also see Halftoning with Unidrv.
InputBin AUTO
CASSETTE
ENVFEED
ENVMANUAL
FORMSOURCE
LARGECAPACITY
LARGEFMT
LOWER
MANUAL
MIDDLE
SMALLFMT
TRACTOR
UPPER 		Yes.
MediaType GLOSSY
STANDARD
TRANSPARENCY 		Yes. Also see Controlling Image Quality.
Memory | No standard options. | Yes.
Orientation | PORTRAIT, LANDSCAPE_CC90, LANDSCAPE_CC270 | No.
PageProtect | ON, OFF | No.
PaperSize 10X11
10X14
11X17
12X11
15X11
9X11
A_PLUS
A2
A3
A3_EXTRA
A3_EXTRA_TRANSVERSE
A3_ROTATED
A3_TRANSVERSE
A4
A4_EXTRA
A4_PLUS
A4_ROTATED
A4_TRANSVERSE
A4SMALL
A5
A5_EXTRA
A5_ROTATED
A5_TRANSVERSE
A6
A6_ROTATED
B_PLUS
B4
B4_JIS_ROTATED
B5
B5_EXTRA
B5_JIS_ROTATED
B5_TRANSVERSE
B6_JIS
B6_JIS_ROTATED
CSHEET
CUSTOMSIZE
DBL_JAPANESE_POSTCARD
DBL_JAPANESE_POSTCARD_ROTATED
DSHEET
ENV_10
ENV_11
ENV_12
ENV_14
ENV_9
ENV_B4
ENV_B5
ENV_B6
ENV_C3
ENV_C4
ENV_C5
ENV_C6
ENV_C65
ENV_DL
ENV_INVITE
ENV_ITALY
ENV_MONARCH
ENV_PERSONAL
ESHEET
EXECUTIVE
FANFOLD_LGL_GERMAN
FANFOLD_STD_GERMAN
FANFOLD_US
FOLIO
ISO_B4
JAPANESE_POSTCARD
JAPANESE_POSTCARD_ROTATED
JENV_CHOU3
JENV_CHOU3_ROTATED
JENV_CHOU4
JENV_CHOU4_ROTATED
JENV_KAKU2
JENV_KAKU2_ROTATED
JENV_KAKU3
JENV_KAKU3_ROTATED
JENV_YOU4
JENV_YOU4_ROTATED
LEDGER
LEGAL
LEGAL_EXTRA
LETTER
LETTER_EXTRA
LETTER_EXTRA_TRANSVERSE
LETTER_PLUS
LETTER_ROTATED
LETTER_TRANSVERSE
LETTERSMALL
NOTE
P16K
P16K_ROTATED
P32K
P32K_ROTATED
P32KBIG
P32KBIG_ROTATED
PENV_1
PENV_1_ROTATED
PENV_10
PENV_10_ROTATED
PENV_2
PENV_2_ROTATED
PENV_3
PENV_3_ROTATED
PENV_4
PENV_4_ROTATED
PENV_5
PENV_5_ROTATED
PENV_6
PENV_6_ROTATED
PENV_7
PENV_7_ROTATED
PENV_8
PENV_8_ROTATED
PENV_9
PENV_9_ROTATED
QUARTO
STATEMENT
TABLOID
TABLOID_EXTRA 		Yes. Customized names must not exceed the length specified by CCHFORMNAME in wingdi.h.
Resolution | No standard options. | Yes.


Customized Options

Customized options are those that are not defined by predefined names in the GPD language. You must create unique names for these options.

Customized options can be associated with customized features. For an example of customized options associated with customized features, see Customized Features.

You can also specify customized options for some of the standard features. For example, if your printer provides a paper size that is not described by one of the standard options for the PaperSize feature, you can specify a customized paper size option by creating a unique name for the option.

Customized option names must be unique within a feature, but option names can be reused in different features. Also, you can use standard option names within customized features. Thus, for example, you can use the standard option names ON and OFF within several *Feature entries for customized features.


Option Entry Format

To specify a printer option entry in a GPD file, use the following format:

*Option: OptionName {OptionAttributes}

where OptionName is either the name of one of the predefined standard options or a customized option name, and OptionAttributes is a set of option attributes.

For an example of a set of *Option entries associated with a feature, see Feature Entry Format.

If you repeat an option specification, for example by specifying two or more *Option entries for the PaperSize feature's LETTER option, each duplicate option attribute within the *Option entry overwrites the previous one, and the GPD parser only retains the last one encountered. On the other hand, if the GPD parser encounters two or more *Feature entries for the PaperSize (or any other) feature, *Option entries not previously specified are added to the parser's database.

You can control the order in which options are displayed to the user. See Specifying Feature and Option Display Order.


Option Attributes

When specifying printer options, you use attributes to provide Unidrv with the following information:

  • Text strings representing an option's display name, user prompt, and help message.
  • A Boolean value indicating whether an option is always present or is installable.
  • The printer command that causes an option to be selected.
  • Various types of option-specific information.

This section contains the following topics:

Option Attributes for All Features

Option Attributes for the ColorMode Feature

Option Attributes for the Halftone Feature

Option Attributes for the InputBin Feature

Option Attributes for the Memory Feature

Option Attributes for the OutputBin Feature

Option Attributes for the PaperSize Feature

Option Attributes for the Resolution Feature


Option Attributes for All Features

The following table lists, in alphabetic order, the option attributes available for all features and describes their parameters.

Attribute Name | Attribute Parameter | Comments
*Command
 | A CmdSelect option selection command, specifying the command string that must be sent to the printer in order to select the option. | Required.
*DisabledFeatures
 | LIST of feature name strings, identifying features that should be disabled if the option is selected. | Optional. Listed features cannot have *Installable? set to TRUE. For more information, see Handling Installable Features and Options.
*HelpIndex
 | Numeric value representing an index into the help file specified by the *HelpFile root-level-only attribute. | (Also a feature attribute.) Index value cannot be zero or -1.
*Installable?
 | TRUE or FALSE, indicating whether the option is installable. (FALSE means always installed.) For more information, see Handling Installable Features and Options. | Optional. If not specified, the default value is FALSE. (Also a feature attribute.)
*InstallableFeatureName
 | Text string that is displayed to ask the user whether an installable option is actually installed. For more information, see Handling Installable Features and Options. | Required if *Installable? is TRUE and *rcInstallableFeatureNameID is not specified. (Also a feature attribute.)
*Name
 | Text string used as the option's display name on the printer's property sheet. | Optional. If not specified, then *rcNameID must be specified. (Also a feature attribute.)
*OptionID
 | Numeric value representing a unique option identifier that Unidrv stores in the printer's DEVMODE structure. For use only with the PaperSize, InputSlot, Halftoning, MediaType, and Resolution features. Value is stored in the DEVMODE structure's dmPaperSize, dmDefaultSource, dmDitherType, or dmMediaType member, respectively. | Optional. If not specified, Unidrv assigns an identifier value (>256). To avoid conflicts with Unidrv-assigned identifiers, the specified value must be greater than 512.
*PromptTime
 | UISETUP or PRTSTARTDOC, indicating when Unidrv should display the prompt message specified by *rcPromptMsgID. If UISETUP, display occurs when the user selects the option from the printer's property sheet. If PRTSTARTDOC, display occurs when the print job starts. | Required if *rcPromptMsgID is specified. If PRTSTARTDOC is specified for more than one option, the prompting messages are displayed in a single dialog box with one OK button.
*rcIconID
 | Resource ID of an icon resource associated with the option. | Optional. If not specified, Unidrv does not display an icon for the option on the printer property sheet. (Also a feature attribute.)
*rcInstallableFeatureNameID
 | Resource ID of a text string that is displayed to ask the user whether an installable option is actually installed. For more information, see Handling Installable Features and Options. | Required if *Installable? is TRUE and *InstallableFeatureName is not specified. (Also a feature attribute.)
*rcNameID
 | Resource ID of string resource representing the option name. | Optional. If not specified, then *Name must be specified. (Also a feature attribute.) For standard options of the PaperSize feature only, setting this attribute to RCID_DMPAPER_SYSTEM_NAME causes Unidrv to use a predefined option name string.
*rcPromptMsgID
 | Resource ID of string resource representing a user prompt message. | Required for the InputBin feature's MANUAL option, to specify a message Unidrv can display to request more paper. Otherwise, optional. Unidrv displays the message in a dialog box with an OK button. The *rcPromptTime attribute controls when Unidrv displays the message.

For examples, see the sample GPD files.


Option Attributes for the ColorMode Feature

The following table lists the attributes associated with the ColorMode feature. For more information about the ColorMode feature, see Standard Features.

Attribute Name | Attribute Parameter | Comments
*Color? | TRUE or FALSE, indicating whether the option produces color. | Optional. If not specified, the default value is TRUE for *DrvBPP > 1. To create gray scaling, set to FALSE with *DrvBPP > 1.
*ColorPlaneOrder | LIST indicating the order in which Unidrv should send color plane data. Examples: LIST (YELLOW, MAGENTA, CYAN, BLACK) LIST (RED, GREEN, BLUE) Colors can be repeated in the list. | Required if *DevNumOfPlanes is greater than 1. The number of colors specified must equal *DevNumOfPlanes.
*DevBPP | Numeric value indicating the number of bits per pixel of color data supported by the printer. | Optional. If not specified, the default value is 1.
*DevNumOfPlanes | Numeric value indicating the number of color planes supported by the printer. | Optional. If not specified, the default value is 1. (For color printers, a value of 1 is referred to as pixel mode.)
*DrvBPP | Numeric value indicating the number of bits per pixel that Unidrv should use for its bitmap rendering buffer. The bitmap format is a Windows DIB, and valid values are 1, 4, 8, 16, 24, or 32. | Optional. If not specified, the default value is 1. (For color printers, a value of 1 is referred to as "planar mode".) Windows DIBs always use one color plane.
*IPCallbackID | Positive numeric value, passed to the rendering plug-in's IPrintOemUni::ImageProcessing method as its IPCallbackID argument. | Required if a rendering plug-in is supplied that contains an IPrintOemUni::ImageProcessing method.
*PaletteProgrammable? | TRUE or FALSE, indicating whether the color palette is programmable. | Optional. If not specified, the default value is FALSE.
*PaletteSize | Numeric value representing the number of entries in the color palette used with the specified option. | Optional. If not specified, the default value is 2.
*RasterMode | DIRECT or INDEXED, indicating whether the raster data is sent directly to the printer or is indexed through a color palette. | Optional. If not specified, the default value is INDEXED.

For examples, see the sample GPD files.

For information about additional option attributes, see Option Attributes for All Features.

Also see Controlling Image Quality.


Option Attributes for the Halftone Feature

The following table lists the attributes associated with the Halftone feature. For more information about the Halftone feature, see Standard Features.

Attribute Name | Attribute Parameter | Comments
*HTCallbackID | Positive numeric value passed to the rendering plug-in's IPrintOemUni::HalftonePattern method as its dwCallbackID parameter. | Required if an IPrintOemUni::HalftonePattern method is provided. See Halftoning with Unidrv.
*HTNumPatterns | Numeric value representing the number of halftone patterns provided. See Halftoning with Unidrv. | Optional. Can be 1 or 3, where 3 implies separate patterns for red, green, and blue, in that order. If not specified, the default value is 1. Can be used with either *rcHTPatternID or *HTCallbackID.
*HTPatternSize | PAIR of numeric values representing the width and height, in pixels, of the pattern specified by *rcHTPatternID. | Required if *rcHTPatternID is specified. The maximum pattern size is PAIR (256, 256). Width and height, multiplied together, must be divisible by 4 for storage as DWORDs.
*rcHTPatternID | Resource identifier for an RC_HTPATTERN resource representing halftone pattern data. | Required if a halftone pattern is provided in a resource DLL. See Halftoning with Unidrv.

For examples, see the sample GPD files.

For more information about using these attributes, see Halftoning with Unidrv. These attributes are not used with minidriver-supplied halftoning.


Option Attributes for the InputBin Feature

There are no attributes associated with the InputBin feature. For more information about the InputBin feature, see Standard Features.

For information about additional option attributes, see Option Attributes for All Features.


Option Attributes for the Memory Feature

The following table lists the attributes associated with the Memory feature. For more information about the Memory feature, see Standard Features.

Attribute Name | Attribute Parameter | Comments
*MemConfigKB | PAIR of numeric values indicating the total and available printer-resident memory, in kilobytes. For example, PAIR (1024, 450) indicates 1024 kilobytes total, 450 kilobytes available, with a GPD-generated option name of "1024KB". | Optional. See Describing Printer Memory Configurations.
*MemConfigMB | PAIR of numeric values indicating the total and available printer-resident memory, in megabytes. For example, PAIR (2, 1) indicates 2 megabytes total, 1 megabyte available, with a GPD-generated option name of "2MB". | Optional. See Describing Printer Memory Configurations.
*MemoryConfigKB | PAIR of numeric values indicating the total and available printer-resident memory, in kilobytes. For example, PAIR (1024, 450) indicates 1024 kilobytes total, 450 kilobytes available. | Optional. See Describing Printer Memory Configurations.

For examples, see the sample GPD files.

For more information about using these attributes, along with examples, see Describing Printer Memory Configurations.

For information about additional option attributes, see Option Attributes for All Features.


Option Attributes for the OutputBin Feature

There are no attributes specifically associated with the OutputBin feature, although it is not uncommon to include an *OutputOrderReversed? entry for a specific output bin. For more information about the OutputBin feature, see Standard Features.

For information about additional option attributes, see Option Attributes for All Features.


Option Attributes for the PaperSize Feature

The following table lists the attributes associated with the PaperSize feature. For more information about the PaperSize feature, see Standard Features.

Note All paper size specifications for the following attributes must be expressed relative to PORTRAIT orientation, even if the attributes are being used to describe a different orientation, such as LANDSCAPE.

Attribute Name | Attribute Parameter | Comments
*BottomMargin | Numeric value representing the minimum allowable bottom margin, in x master units, for user-specified paper sizes associated with the CUSTOMSIZE option. Value is relative to the bottom of the physical page. | Optional. If not specified, the default value is 0. Used only with the CUSTOMSIZE option. Portrait orientation is assumed. See Specifying Paper Sizes.
*CenterPrintable? | TRUE or FALSE, indicating whether the value specified by *MaxPrintableWidth is centered. | Optional. If not specified, the printable area is to the right of the margin specified by *MinLeftMargin. Used only with the CUSTOMSIZE option. See Specifying Paper Sizes.
*CursorOrigin | PAIR of numeric values representing the cursor origin position, in master units, where PAIR (0, 0) is the upper left corner. Alternatively for CUSTOMSIZE, specify these values using *CustCursorOriginX and *CustCursorOriginY. | Optional. If not specified, the default value is PAIR (0, 0). Unidrv assumes the cursor origin, relative to the printer, is constant with different paper sizes.
*CustCursorOriginX | CUSTOMSIZE parameter expression, used to create a value for the x index of *CursorOrigin. | Optional. Use only with the CUSTOMSIZE option. See Specifying Paper Sizes.
*CustCursorOriginY | CUSTOMSIZE parameter expression, used to create a value for the y index of *CursorOrigin. | Optional. Use only with the CUSTOMSIZE option. See Specifying Paper Sizes.
*CustPrintableOriginX | CUSTOMSIZE parameter expression, used to create a value for the x index of *PrintableOrigin. | Optional. Use only with the CUSTOMSIZE option. See Specifying Paper Sizes.
*CustPrintableOriginY | CUSTOMSIZE parameter expression, used to create a value for the y index of *PrintableOrigin. | Optional. Use only with the CUSTOMSIZE option. See Specifying Paper Sizes.
*CustPrintableSizeX | CUSTOMSIZE parameter expression, used to create a value for the x value of *PrintableArea. | Optional. Use only with the CUSTOMSIZE option. See Specifying Paper Sizes.
*CustPrintableSizeY | CUSTOMSIZE parameter expression, used to create a value for the y value of *PrintableArea. | Optional. Use only with the CUSTOMSIZE option. See Specifying Paper Sizes.
*MaxSize | PAIR of numeric values representing maximum allowable page length (x) and height (y) values, in master units, for user-specified paper sizes associated with the CUSTOMSIZE option. | Required for the CUSTOMSIZE option. Portrait orientation is assumed. See Specifying Paper Sizes.
*MaxPrintableWidth | Numeric value representing the maximum printable width, in x master units, for user-specified paper sizes associated with the CUSTOMSIZE option. | Required for the CUSTOMSIZE option. Portrait orientation is assumed. See Specifying Paper Sizes.
*MinLeftMargin | Numeric value representing the minimum allowable left margin, in x master units, for user-specified paper sizes associated with the CUSTOMSIZE option. Value is relative to the left edge of the physical page | Optional. If not specified, the default value is 0. Used only with the CUSTOMSIZE option. Portrait orientation is assumed. See Specifying Paper Sizes.
*MinSize | PAIR of numeric values representing minimum allowable page length (x) and height (y) values, in master units, for user-specified paper sizes associated with the CUSTOMSIZE option. | Required for the CUSTOMSIZE option. Portrait orientation is assumed. See Specifying Paper Sizes.
*PageDimensions | PAIR of numeric values representing the page length (x) and height (y) values, in master units, for any customized options for the PaperSize feature. | Used only for vendor-defined paper sizes. See Specifying Paper Sizes.
*PageProtectMem | Numeric value representing the amount of printer memory, in kilobytes, required to protect a page. | Required if the PageProtect feature is specified. See Specifying Paper Sizes.
*PrintableArea | PAIR of numeric values representing the x- and y-plane lengths, in master units, of the printable page area. | Required for all PaperSize options except CUSTOMSIZE. See Specifying Paper Sizes.
*PrintableOrigin | PAIR of numeric values representing the origin of the printable area, in master units, relative to the upper left-hand corner of the paper. | Required for all PaperSize options except CUSTOMSIZE. For CUSTOMSIZE, you can specify these values using *CustPrintableOriginX and *CustPrintableOriginY.
*RotateSize? | TRUE or FALSE, indicating whether Unidrv should rotate the page dimensions because the paper (typically envelopes) is fed in sideways. | Optional. If not specified, the default value is FALSE. Can be used with any standard option for the PaperSize feature, except CUSTOMSIZE.
*TopMargin | Numeric value representing the minimum allowable top margin, in y master units, for user-specified paper sizes associated with the CUSTOMSIZE option. Value is relative to the top of the physical page. | Optional. If not specified, the default value is 0. Used only with the CUSTOMSIZE option. Portrait orientation is assumed. See Specifying Paper Sizes.

For examples, see the sample GPD files.

CUSTOMSIZE Parameter Expressions

CUSTOMIZE parameter expressions are a restricted form of the command string format. Text strings are not allowed.

Within the expression's ArgumentType segment, the following restrictions apply:

  • The only ArgumentType value allowed is %d.
  • Bracketed value ranges are not allowed.

Within the expression's StandardVariableExpression segment, the following restrictions apply:

  • Only the PhysPaperWidth and PhysPaperLength standard variables can be used.
  • The Max_Repeat operator is not allowed.

Following are example expressions:

*CustCursorOriginX: %d{((PhysPaperWidth-14040)/2)+300}
*CustCursorOriginY: %d{180}
*CustPrintableOriginX: %d{300}
*CustPrintableOriginY: %d{300}
*CustPrintableSizeX: %d{PhysPaperWidth-600}
*CustPrintableSizeY: %d{PhysPaperLength-600}


Option Attributes for the Resolution Feature

The following table lists the attributes associated with the Resolution feature. For more information about the Resolution feature, see Standard Features.

Attribute Name | Attribute Parameter | Comments
*DPI | PAIR of numeric values representing the x and y values for the printer's resolution, in dots per inch. | Required. The x and y values must equal *TextDPI x and y values, or they must be equal to *TextDPI x and y values divided by a power of two. For example, if *TextDPI is PAIR(300, 300), then *DPI values might be PAIR(300, 300), PAIR(150, 150), or PAIR(75, 75), but not PAIR(100, 100).
*MinStripBlankPixels | Numeric value representing the minimum number of blank bytes that Unidrv should encounter within a scan line before stripping enclosing blank bytes. | Optional. If not specified, the default value is zero. This attribute is relevant only if a *StripBlanks entry specifies ENCLOSED. See Raster Data Emission Attributes.
*PinsPerLogPass | Numeric value presenting the number of scan lines printed by one logical pass of the print head. Must be a multiple of *PinsPerPhysPass, since each logical pass consists of one or more physical passes. | Optional. If not specified, the default value is 1. Required if a printer performs interlacing, requiring multiple passes of the print head across a set of scan lines, to print all the scan lines.
*PinsPerPhysPass | Numeric value representing the number of scan lines printed as the print head moves across the page. Must be one, or a multiple of eight. | Optional. If not specified, the default value is 1.
*RequireUniDir? | TRUE or FALSE, indicating whether the specified resolution requires unidirectional printing to be enabled. | Optional. If not specified, the default value is FALSE.
*SpotDiameter | Numeric value representing the spot diameter size, as a percentage of the pixel size, for the resolution specified by *DPI. | Required. Examples: 100 means the spot diameter equals the pixel size. 200 means the spot diameter is twice the pixel size. 50 means the spot diameter is half the pixel size.
*TextDPI | PAIR or numeric values representing the x and y values for the printer's text resolution, in dots per inch. | Required. See *DPI comments. This resolution is used for drawing fonts and vector graphics.

For examples, see the sample GPD files.

For information about additional option attributes, see Option Attributes for All Features.

Also see Controlling Image Quality.


Option Constraints

It is sometimes necessary to constrain the ability of users to install or select certain printer options associated with printer features. The following types of option constraints can be specified:

  • You can constrain an option so that it cannot be selected if a conflicting option is already selected. These constraints are called selection constraints.
  • You can constrain an installable option so that it cannot be installed if a conflicting installable option is already installed. These constraints are called installation constraints.
  • You can constrain an option so that it cannot be selected if a conflicting installable option is already installed, or so that it cannot be selected if a required installable option is not installed. These constraints are called constraints between selections and installations.

The driver's user interface code enforces constraints when the user chooses the OK button on the printer's property sheet dialog box. If invalid combinations of options have been selected, the user is given the choice of either correcting the conflicts by modifying the property sheet page or letting the driver attempt to make corrections automatically, based on feature conflict priority.


Selection Constraints

Often, certain options for various printer features cannot be selected simultaneously. For example, if the envelope feeder is selected, then non-envelope paper sizes, such as letter-sized or A4-sized paper, cannot be selected.

To specify combinations of printer options that cannot be simultaneously selected, use *InvalidCombination or *Constraint entries. If a user attempts to select a combination of options that you have specified as being invalid, Unidrv rejects the selection.

The *InvalidCombination entry has the following format:

*InvalidCombination: LIST (FeatureName.OptionName, FeatureName.OptionName, ...)

where FeatureName is the name of a feature and OptionName is the name of an option associated with the feature.

The options listed in a single *InvalidCombination entry indicate a set of options that cannot be used in combination. For example, the following entry specifies that CMYK color mode cannot be used with plain paper and 720 DPI.

*InvalidCombination: LIST(Resolution.720dpi, MediaType.Plain, ColorMode.CMYK)

All *InvalidCombination entries must be located at the GPD file's root level (that is, not within braces). The number of options included in an entry is not limited.

If you only need to indicate an invalid combination relationship between two options, you can use a *Constraints entry. Its format is:

*Constraints: FeatureName.OptionName

where FeatureName is the name of a feature and OptionName is the name of an option associated with the feature. A *Constraints entry must be placed inside an *Option entry. For example, to indicate that letter-sized and A4-sized paper cannot be used with the envelope feeder, you can use the following entries:

*Feature: InputBin
{
    *Option: ENVFEED
    {
        *Constraints: PaperSize.Letter
        *Constraints: PaperSize.A4
    }
}

or, equivalently:

*Feature: InputBin
{
    *Option: ENVFEED
    {
        *Constraints: LIST(PaperSize.Letter, PaperSize.A4)
    }
}

These examples specify that if a user attempts to select the envelope feeder and letter-sized paper, or the envelope feeder and A4-sized paper, Unidrv rejects the selection.


Installation Constraints

Sometimes, certain installable printer options cannot be installed simultaneously. For example, it might not be possible to install both the envelope feeder and the duplexing unit.

To specify combinations of printer options that cannot be simultaneously installed, use *InvalidInstallableCombination entries.

The *InvalidInstallableCombination entry has the following format:

*InvalidInstallableCombination: LIST (FeatureName.OptionName, FeatureName.OptionName, ...)

where FeatureName is the name of a feature and OptionName is the name of an option associated with the feature. This list can include features as well as options, in which case the period and OptionName are not included.

The features and options listed in a single *InvalidInstallableCombination entry indicate a set of features and options that cannot be used in combination. For example, the following entry specifies that the envelope feeder and the duplexing unit cannot be simultaneously installed.

*InvalidInstallableCombination: LIST(InputBin.ENVFEED, Duplex)

All *InvalidInstallationCombination entries must be located at the GPD file's root level (that is, not within braces). The number of features and options included in an entry is not limited.

If a feature or option is included in an *InvalidInstallationCombination entry, the feature or option's *Installable? attribute must be set to TRUE.


Constraints between Selections and Installations

Sometimes it is necessary to specify that a certain option cannot be selected if some other option is installed, or that a certain option cannot be selected if some other option is not installed. For example, a user should not be able to select tabloid paper if a printer's large format paper tray is not installed.

To specify relationships between the selection of certain options with the installation state of other options, use *InstalledConstraints and *NotInstalledConstraints entries. Their format is:

*InstalledConstraints: FeatureName.OptionName
*NotInstalledConstraints: FeatureName.OptionName

where FeatureName is the name of a feature and OptionName is the name of an option associated with the feature. If the argument is a feature, the period and OptionName are not included.

An *InstalledConstraints or *NotInstalledConstraints entry must be placed inside a *Feature or *Option entry. For example, to indicate that a user should not be able to select tabloid paper if a printer's large format paper tray is not installed, the following entries can be used:

*Feature: InputBin
{
    *Option: LARGEFMT
    {
        Installable?: TRUE
        NotInstalledConstraints: PaperSize.TABLOID
    }
}

If a feature or option includes an *InstalledConstraints or *NotInstalledConstraints entry, the feature or option's *Installable? attribute must be set to TRUE.


Printer Font Descriptions

The GPD language provides entries for describing hardware-resident fonts, font cartridges, and font substitution of TrueType fonts for similar hardware-resident or cartridge fonts.

You can optionally provide customized code for handling soft fonts. For information about this customized code, see Customized Font Management.


Hardware-Resident Fonts

If your printer contains hardware-resident fonts, you must provide specifications of font metrics for these fonts within .ufm or .ifi files. To create a .ufm or .ifi file, use the Microsoft Minidriver Development Tool.

Each hardware resident font is described in a separate .ufm or .ifi file. To make the these files available to Unidrv, do the following:

  • In the printer's resource DLL, specify .ufm files by using the RC_UFM resource type, and specify .ifi files by using the RC_FONT resource type.
  • In the printer's GPD file, use the *ResourceDLL attribute to specify the resource DLL's name.
  • In the printer's GPD file, use a *DeviceFonts entry to specify the resource identifiers associated with the RC_UFM or RC_FONT entries in the resource DLL.

The format of the *DeviceFonts entry is as follows:

*DeviceFonts: LIST (FontResourceID, FontResourceID, ...)

where FontResourceID is the RC_UFM resource identifier associated with an .ufm file, or the RC_FONT resource identifier associated with an .ifi file.

Following is an example:

*% Assume that RC_FONT_xxx ids are references to
*% value macros defined by the GPD file creator.
*DeviceFonts: LIST(=RC_FONT_COURIER10, =RC_FONT_ARIALR,
+                  =RC_FONT_ARIALI, =RC_FONT_ARIALB,
+                  =RC_FONT_ARIALBI, =RC_FONT_TIMESNRR,
+                  =RC_FONT_TIMESNRI, =RC_FONT_TIMESNRB,
+                  =RC_FONT_TIMESNRBI)

You can include several *DeviceFonts entries in Unidrv minidrivers. The GPD parser concatenates multiple entries and makes all listed fonts available for all configurations of the printer's features. If you need to specify that some fonts are only available with certain configurations, you can include *DeviceFonts entries within conditional statements.


Font Cartridges

If your printer accepts font cartridges, cartridges can be described by *FontCartridge GPD file entries. This entry's format is:

*FontCartridge: CartridgeName {FontCartidgeAttributes}

where CartridgeName is a text string representing the name of the cartridge and FontCartridgeAttributes is a set of one or more font cartridge attributes.

Alternatively, the fonts supplied by font cartridges can be specified using Unidrv Font Format Files (.uff files). Typically, the most commonly supplied font cartridges are described in a GPD file, while less commonly-used cartridges are specified with .uff files.


Font Cartridge Attributes

The following table contains attributes that can be included in a *FontCartridge GPD entry.

Attribute Name | Attribute Parameter | Comments
*CartridgeName | Text string representing the cartridge name. | Required, unless *rcCartridgeNameID is specified.
*Fonts | LIST of RC_UFM or RC_FONT resource identifiers representing fonts contained in the cartridge that are available for both portrait and landscape orientations. | At least one of *Fonts, *PortraitFonts or *LandscapeFonts must be specified. Font resource identifiers should be numbered contiguously from 1.
*LandscapeFonts | LIST of RC_UFM or RC_FONT resource identifiers representing fonts contained in the cartridge that are available only for landscape orientation. | At least one of *Fonts, *PortraitFonts or *LandscapeFonts must be specified. Font resource identifiers should be numbered contiguously from 1.
*PortraitFonts | LIST of RC_UFM or RC_FONT resource identifiers representing fonts contained in the cartridge that are available only for portrait orientation. | At least one of *Fonts, *PortraitFonts or *LandscapeFonts must be specified. Font resource identifiers should be numbered contiguously from 1.
*rcCartridgeNameID | Resource identifier of a String resource representing the cartridge name. | Required, unless *CartridgeName is specified.


Font Substitution

For printers that provide hardware-resident or cartridge fonts, a font substitution table can be specified. By providing a font substitution table, you specify hardware-resident or cartridge fonts that can be substituted for TrueType fonts that must be downloaded. When Unidrv receives text in such a TrueType font, it first checks to see if the font substitution table contains a hardware-resident substitution for the font. If Unidrv finds a substituted resident font, and if the font metrics (such as character set, weight, italic, orientation, and so on) are compatible, the resident font is used.

You can create a default font substitution table by using a series of *TTFS entries. The format of each entry is:

*TTFS: FontName
{
*TTFontName: "TTFontNameString"
 *DevFontName: "DeviceFontNameString"
}

where FontName is a symbol specifying the entry name, TTFontNameString is a text string identifying the TrueType font to be replaced, and DeviceFontNameString is a text string identifying the hardware-resident or cartridge font to be used. Following is an example table:

*TTFS: Arial
{
    *TTFontName: "Arial"
    *DevFontName "Arial"
}
*TTFS: TNR
{
    *TTFontName: "Times New Roman"
    *DevFontName: "Times New Roman"
}
*TTFS: CurrierNew
{
    *TTFontName:  "Courier New"
    *DevFontName: "Courier New"
}

If there are duplicate *TTFS entries with the same FontName value, the last entry read by the parser supersedes the previous one.

The substitution table you specify is a default table, because Unidrv allows users to modify the substitutions.

All *TTFS entries must be located at the GPD file's root level (that is, not within braces).

To control whether or not font substitution is enabled by default, use the *TTFSEnabled? entry. This entry's format is:

*TTFSEnabled?: BooleanValue

where BooleanValue is TRUE or FALSE. If BooleanValue is TRUE, Unidrv enables font substitution. If BooleanValue is FALSE, or if you do not include a *TTFSEnabled? entry in the GPD file, Unidrv disables font substitution until it is enabled by a user.

The *TTFSEnable? entry is relocatable, but *TTFS entries are not. (For information about relocatable entries, see What to Place Inside *Switch, *Case, and *Default Statements).

Default TrueType Font Substitutions

A default table of TrueType font substitutions is provided in the file named ttfsub.gpd. To use it, add the following entry at the GPD file's root level (that is, not within braces):

*Include: "ttfsub.gpd"

Additionally, this file must be installed. For more information, see Printer INF File Install Sections.


Conditional Statements

The GPD language provides C-like conditional statements that allow you to describe dependencies that some printer attributes can have on a printer's configuration. For example, the margins and cursor origin for a page might depend on the page's orientation. The *Switch and *Case statements allow you to express such dependencies. The format of these statements is as follows:

*Switch FeatureName
{
*Case Option1_Name
{
}
*Case Option2_Name
{
}
 etc.
*Case OptionN_Name
{
}
*Default
{
}
}

FeatureName must be the name of a feature that is specified within the GPD file with a *Feature entry. The option names used must be options that are associated with the specified feature.

To express the case in which page margins and cursor origin are dependent on the page's orientation, the following entries could be used:

*Feature: Orientation
{
    *DefaultOption: Portrait
    *Option: Portrait
    {
        *Name: "Portrait"
        *rcIconID: =RC_ICON_PORTRAIT
    }
    *Option: Landscape_CC90
    {
        *Name: "Landscape"
        *rcIconID: =RC_ICON_LANDSCAPE
    }
}
*Feature: PaperSize
{
    *DefaultOption: Letter
    *Option: Letter
    {
        *Name: "Letter 8.5 x 11 inch"
        *switch: Orientation
        {
            *case: Portrait
            {
                *PrintableArea: PAIR(4800, 6324)
                *PrintableOrigin: PAIR(150, 150)
                *CursorOrigin: PAIR(150,100)
            }
            *case: Landscape_CC90
            {
                *PrintableArea: PAIR(4860, 6360)
                *PrintableOrigin: PAIR(120, 120)
                *CursorOrigin: PAIR(100,6480)
            }
        }
    }
}

In this example, options for the printer's PaperSize feature are dependent on the selected option for the printer's Orientation feature.

If you do not list all of a feature's options as *Case statement arguments, you can include a *Default statement, just as in the C language. If you do not include all options and you do not include a *Default statement, you must evaluate relevant attributes (in the example, *PrintableArea, *PrintableOrigin, and *CursorOrigin) elsewhere in the GPD file, preceding the *Switch statement.

Specifying Multiple Dependencies

You can include *Switch statements inside *Case and *Default statements. This allows you to specify multiple dependencies, as follows:

*Feature: feature1 {*Option: optionA {...} *Option: optionB {...}}
*Feature: feature2 {*Option: optionC {...} *Option: optionD {...}}
*Feature: feature3
    {*Option: optionE
        {*Switch: feature1
            {*Case: optionA
                 {*Switch: feature2
                     {*Case: optionD
                         {AttributeX: ValueX}
                      *Default
                         {AttributeX: ValueY}
                     }
                 }
             *Default
                  {AttributeX: ValueZ}
             }
         }
    *Option: optionF {...}
    }

In this example AttributeX, belonging to optionE of feature3, is dependent on both feature1 and feature2.

If the user has selected optionA for feature1, optionD for feature2, and optionE for feature3, then attributeX is set to ValueX.

If the user has selected optionA for feature1, optionC for feature2, and optionE for feature3, then attributeX is set to ValueY.

If the user has selected optionB for feature1 and optionE for feature3, then attributeX is set to ValueZ. The setting for Feature2 is irrelevant.

The following rules apply when specifying multiple dependencies:

  • Multiple dependencies must be specified within the scope of a single *Switch entry. Using the example, for instance, you cannot use a *Switch entry to indicate that feature3 is dependent on feature1 and then, in a subsequent, non-nested *Switch statement, indicate that feature3 is dependent on feature2.
  • You cannot specify the same feature more than once within each nested *Switch entry.

Where to Place a *Switch Statement

You can place a *Switch statement in the following locations within a GPD file:

  • Inside an *Option statement
  • Inside a *Feature statement
  • Inside a *Case statement
  • Inside a *Default statement
  • At the file's top level (that is, not inside a set of braces)

What to Place Inside *Switch, *Case, and *Default Statements

Within a *Switch entry, you can only place *Case entry and a *Default entry.

GPD file entries that can be placed inside *Case or *Default entries are referred to as relocatable entries. The following types of GPD entries are relocatable:

  • Most printer attributes, except for root-level-only attributes. (General attributes must be preceded by EXTERN_GLOBAL unless the *Switch entry is at root level – not within braces.)
  • Nested *Switch entries, which allow you to specify multiple dependencies.
  • *Command entries.
  • *TTFSEnabled?, which enables font substitution.

The following types of GPD entries are not relocatable:

  • Root-level-only attributes.
  • *TTFS entries for specifying substituted font.
  • *Constraints, *InvalidCombination, *InvalidInstallableCombination, *NotInstalledConstraints entries that define invalid combinations of options, as described in Option Constraints.
  • *Feature and *Option entries (although feature attributes and option attributes are relocatable).

One method for determining if entries have been placed correctly inside *Case statements is to remove all the *Switch and *Case statements. If the entries inside the *Case statements are correct, they are still correct after the *Switch and *Case statements are removed.


Compressing Raster Data

Unidrv supports raster data compression using the following three formats:

  • Tagged Image File Format (TIFF), version 4.0
  • Delta-Row Compression (DRC)
  • East Asian Run-Length Encoding (FE-RLE)

These methods are defined in the HP PCL 5 Printer Language Technical Reference.

You can include entries in a GPD file to indicate which of these compression formats your printer supports. You can also provide your own compression algorithm.

For more information about raster data compression, see the following topics:

Using Unidrv-Supported Compression

Using Customized Compression


Using Unidrv-Supported Compression

If you include a CmdEnableTIFF4 command entry in your GPD file, Unidrv uses TIFF 4.0 compression.

If you include a CmdEnableDRC command entry in your GPD file, Unidrv uses DRC compression.

If you include a CmdEnableFE_RLE command entry in your GPD file, Unidrv uses FE-RLE compression.

If your printer supports more than one of these compression methods, you can include a command entry for each supported method. For each scan line, Unidrv tries each compression algorithm and chooses the algorithm that produces the most compressed result. (You can also include a customized algorithm. See Using Customized Compression.) When Unidrv finds the best algorithm, it compresses the scan line data. Then it sends to the printer the command specified by the appropriate command entry, followed by the compressed data.

If you specify a CmdDisableCompression command entry, then regardless of the compression methods available, Unidrv temporarily disables sending compressed data when it encounters an uncompressed data block that is smaller than its compressed form.

To limit unnecessary computations, do not enable a compression method (by specifying its command entry) if the method is unlikely to produce a usable result.

For most printers, acceptance of compressed data can be enabled or disabled by sending command strings outside of data blocks. When you specify CmdEnableTIFF4, CmdEnableDRC, CmdEnableFE_RLE, and CmdDisableCompression entries for these printers, you include a command string.

For some printers (typically East Asian printers), compression selection commands are embedded in the raster data that is sent with a CmdSendBlockData command. When you specify CmdEnableTIFF4, CmdEnableDRC, or CmdEnableFE_RLE entries for these printers, do not include a command string. Instead, specify an empty quoted string to represent the command. This tells Unidrv to use compression but to not send separate commands to enable it. For these printers, only one compression algorithm can be used. A CmdDisableCompression entry is not needed because there is no way for Unidrv to turn off compression in this case.

For more information about CmdEnableTIFF4, CmdEnableDRC, CmdEnableFE_RLE, and CmdDisableCompression entries, see Raster Data Compression Commands.

For more information about CmdSendBlockData, see Raster Data Emission Commands.


Using Customized Compression

If you want to supply a customized compression algorithm, you include a CmdEnableOEMComp command entry to specify the command that enables your algorithm. If your printer can disable compression, you can optionally include a CmdDisableCompression entry to specify the command that disables compression. You must also provide a rendering plug-in that implements the IPrintOemUni::Compression method.

If you provide a customized compression algorithm, you can also enable the use of Unidrv-supported algorithms. For each scan line, Unidrv tries each compression algorithm and chooses the algorithm that produces the most compressed result. (For information about Unidrv-supported algorithms, see Using Unidrv-Supported Compression.) When Unidrv finds the best algorithm, it compresses the scan line data. Then it sends to the printer the command specified by the appropriate command entry, followed by the compressed data.

For more information about CmdEnableOEMComp and CmdDisableCompression entries, see Raster Data Compression Commands.

For more information about customized compression, see Customized Data Stream Compression.


Filtering Raster Data

If you want to provide customized post-processing of the scan line data stream before it is spooled, you can do so by implementing the IPrintOemUni::FilterGraphics method in a rendering plug-in. There are no GPD file entries associated with this Unidrv feature.

For more information, see Customized Data Stream Filtering.


Handling Color Formats

Each color format that a printer supports is specified as an option to the ColorMode feature. By using option attributes for the ColorMode feature, you can describe each color format that your printer accepts. The following table illustrates the color data formats that Unidrv can handle.

Number of Color Planes in Device (*DevNumOfPlanes) | Number of Bits per Pixel in Device (*DevBPP)
1 | 1 (Black and white)
1 | 8
1 | 24
3 | 1 (CMY and RGB)
4 | 1 (CMYK)

For these formats, Unidrv can convert DIB data into the proper format and send it to the printer. (Halftoning operations that can be performed on this data are described in Halftoning with Unidrv.)

If your printer supports color formats that are not listed in the table, you must do the following:

  • Set the *DevNumOfPlanes and *DevBPP attributes to zero. Doing this prevents Unidrv from sending DIB data to the printer.
  • Provide a rendering plug-in that implements the IPrintOemUni::ImageProcessing method.

The IPrintOemUni::ImageProcessing method must perform the following operations:

  • Convert DIB data into the printer's color format.
  • Perform halftoning operations on the data.
  • Send the data to the print spooler.

For more information about providing an IPrintOemUni::ImageProcessing function, see Customized Color Formats.

Rendering High Quality Images

For each color format, you specify both the bits per pixel that the printer hardware accepts and the bits per pixel you want Unidrv to use when creating DIBs. These values are specified with the *DevBPP and *DrvBPP attributes, respectively. Sometimes, it is desirable for images to be rendered as bitmaps having a higher number of bits per pixel than the printer can handle (in order, for example, to attempt reproducing high-quality photographs). Therefore, it is allowable to specify a *DrvBPP value that is larger than the result of multiplying the *DevBPP value by the *DevNumOfPlanes value.

For example, suppose you want to define a ColorMode option that causes images to be rendered as 24 bits/pixel bitmaps, but then you want the bitmap to be sent to the printer as CMYK data. You might define this mode as follows:

*Feature: ColorMode
{
    *Option: 24toCMYK
    {
        *Name: "Photographic Quality"
        *DrvBPP: 24
        *DevNumOfPlanes: 4
        *DevBPP: 1
        *ColorPlaneOrder: LIST(CYAN, MAGENTA, YELLOW, BLACK)
        *IPCallbackID: 1
    }
    other options
}

In this example, the *DevBPP and *DevNumOfPlanes attributes represent the four-plane, one-bit-per-plane CMYK format that Unidrv can render and then send to the printer. However, in this case, halftoning operations must be performed on the rendered image before it is printed. Minidriver-supplied halftoning must be used.


Halftoning with Unidrv

Halftoning operations can be controlled by either GDI or driver software, or by device hardware. The type that is used is dependent on the color format. The following topics discuss Unidrv's support for halftoning operations:

GDI-supplied halftoning

Minidriver-supplied halftoning

Device-supplied halftoning


GDI-Supplied Halftoning

If a specified color format is one for which the number of bits per pixel used for rendering the image (*DrvBPP) is the same as the bits per pixel supported by the printer (*DevBPP multiplied by *DevNumOfPlanes), then halftoning operations are handled by GDI. An example is a *DrvBPP value of four, with *DevBPP equal to one and *DevNumOfPlanes equal to four.

For such a situation, the only halftoning methods allowed are those that GDI provides. These halftoning methods are represented in GPD files by the standard halftoning option names, which are listed under Standard Options. To specify the GDI-supported halftoning methods that you want Unidrv to allow for your printer, specify their names in *Option entries for the Halftone feature. (The Halftone feature is one of the standard printer features.)

If you specify several halftoning methods and color modes in your GPD file, and if you want to limit which halftoning methods can be selected with which color modes, use option constraints.

Unidrv uses the standard HT_PATSIZE_AUTO option if no halftoning options are specified in the GPD file. The HT_PATSIZE_AUTO option causes Unidrv to use the standard halftoning method that is optimum for the selected resolution and color mode. This enables a user to switch among various combinations of resolution and color mode without the need to know the best halftoning option for any particular combination.

When using GDI-supplied halftoning capabilities, you can provide minidriver-supplied halftone patterns.

For more information about color formats, see Handling Color Formats.


Minidriver-Supplied Halftone Patterns

When GDI-supported halftone methods are being used, GDI allows specification of customized halftone patterns. To specify customized halftone patterns, use option attributes for the halftone feature as follows:

  • The *rcHTPatternID, *HTPatternSize and *HTNumPatterns attributes allow you to describe halftone patterns that are stored in a resource DLL. Halftone pattern resources are three-dimensional arrays of binary data, starting on a DWORD address boundary. They can be specified using the following format, which calculates the correct size and provides the required address alignment:
    BYTE HTPatternResource [HTNumPatterns][(HTPatternSize.y*HTPatternSize.x+3) & ~3];

    Within an .rc file used to create a resource DLL, the pattern might be specified as follows:

    1     RC_HTPATTERN LOADONCALL DISCARDABLE HALFTONE.BIN

    where halftone.bin is a file containing a halftone pattern.

  • The *HTCallbackID attribute allows you to indicate that you are implementing the IPrintOemUni::HalftonePattern method in a rendering plug-in. A unique *HTCallbackID value must be provided for each pattern the IPrintOemUni::HalftonePattern method supports.

You can provide halftone pattern resources, an IPrintOemUni::HalftonePattern method, or both, as follows:

  • If you provide only halftone patterns, Unidrv obtains the patterns from the resource DLL and passes them to GDI. The patterns cannot be encrypted.
  • If you provide only an IPrintOemUni::HalftonePattern method, the method must generate and return halftone patterns to Unidrv, which passes them to GDI.
  • If you want to place encrypted halftone patterns in a resource DLL, then you must also provide an IPrintOemUni::HalftonePattern method to decode the patterns and return them to Unidrv, which in turn passes them to GDI.

For more information about halftoning, see Customized Halftoning.


Minidriver-Supplied Halftoning

If a specified color format is one for which the number of bits per pixel used for rendering the image (*DrvBPP) is greater than the bits per pixel supported by the printer (*DevBPP multiplied by *DevNumOfPlanes), then you must provide customized halftoning capabilities.

To provide customized halftoning capabilities, you must do the following:

  • Provide a rendering plug-in that implements the IPrintOemUni::ImageProcessing method.
  • Include a Halftone *Feature entry in your GPD file and, for each customized halftoning method, include an *Option entry describing the halftoning method. (Do not use any of the option attributes for the halftone feature.)
  • Include a ColorMode *Feature entry in your GPD file. For each specified color formatting option, you must include an *IPCallbackID attribute if you want your IPrintOemUni::ImageProcessing method to handle halftoning for that color format.

The following example defines two color formats and four halftoning methods:

*Feature: ColorMode
{
    *Option: ColorFormat1
    {
        *Name: "Color Format 1"
        *DevBPP: 1
        *DevNumofPlanes: 4
        *ColorPlaneOrder: LIST (CYAN, MAGENTA, YELLOW, BLACK)
        *DrvBPP: 4
        *Constraints: LIST (Halftone.CustomHalftoneMethod1,
+                           Halftone.CustomHalftoneMethod2)
    }
    *Option: ColorFormat2
    {
        *Name: "Color Format 2"
        *DevBPP: 24
        *DevNumofPlanes: 1
        *DrvBPP: 8
        *IPCallbackID: 100
        *Constraints: LIST (Halftone.StandardHalftoneMethod1,
+                           Halftone.StandardHalftoneMethod2)
    }
}
*Feature: Halftone
{
    *Option: StandardHalftoneMethod1
    {
        *Name: "Standard Halftone Method 1"
    }
    *Option: StandardHalftoneMethod2
    {
        *Name: "Standard Halftone Method 2"
    }
    *Option: CustomHalftoneMethod1
    {
        *Name: "Custom Halftone Method 1"
    }
    *Option: CustomHalftoneMethod2
    {
        *Name: "Custom Halftone Method 2"
    }
}

In the example, both the ColorFormat1 and ColorFormat2 ColorMode options represent color formats that Unidrv can handle, as explained in Handling Color Formats. For ColorFormat2, an *IPCallbackID attribute has been specified. If the printer user selects ColorFormat2 as the color format, Unidrv calls the printer's IPrintOemUni::ImageProcessing COM method to handle halftoning. One of the method's parameters is a pointer to the string name representing the currently selected halftoning method.

In this example, two standard halftoning methods and two customized halftoning methods are available. The example uses option constraints to specify which halftoning methods Unidrv should allow a user to select for each color format.

For more information about halftoning, see Customized Halftoning.


Device-Supplied Halftoning

If your printer provides halftoning capabilities internally, your minidriver must specify the commands that Unidrv sends to the printer to activate these capabilities. For each halftoning option that is printer-supported, your GPD file's Halftone *Feature entry must include *Command entries for each device-supplied halftoning option, as follows:

*Feature: Halftone
{
    *Option: CustomHalftoneMethod1
    {
        *Name: "Custom Halftone Method 1"
        *Command: CmdSelect: "<printer command string>"
    }
    *Option: CustomHalftoneMethod2
    {
        *Name: "Custom Halftone Method 2"
        *Command: CmdSelect: "<printer command string>"
    }
}

ColorMode feature entries must also be specified, and they must include *DevBPP and *DevNumofPlanes entries describing the input formats expected by the printer.


Controlling Image Quality

Unidrv's user interface provides a set of three radio buttons that allow a user to select "draft", "better", or "best" image quality for a print job. Draft quality emphasizes printer speed over image resolution, while best quality does the opposite.

The purpose of these radio buttons is to allow the user to easily select the feature options required to obtain the desired quality, without the necessity of explicitly selecting the required options individually.

The options that Unidrv should select when a radio button is pressed are specified in the printer's GPD file. The GPD language defines the following three entries:

*DraftQualitySettings
*BetterQualitySettings
*BestQualitySettings

Each of these entries is associated with one of the radio buttons, and each entry accepts a list of options. When a user selects the corresponding button, Unidrv goes through the list and sets the specified options.

The format for each of the quality setting entries is as follows:

*XXXX QualitySettings: LIST(FeatureName.OptionName, FeatureName.OptionName, FeatureName.OptionName, ...)

where each FeatureName is a name associated with a *Feature entry, and OptionName is a name associated with one of the feature's *Option entries. An empty list causes the associated radio button to be grayed out.

An additional, required entry specifies the default image quality. The format is as follows:

*DefaultQuality: DefaultQuality

where DefaultQuality is either DRAFTQUALITY, BETTERQUALITY, or BESTQUALITY.

These GPD file entries can be associated with any option of the ColorMode and MediaType features. Typically, they are placed in conditional statements, as illustrated in the following example.

*switch: ColorMode {
    *case: Mono {
        *BestQualitySettings: LIST(ColorMode.Mono,
                                   Resolution.Option1,
                                   TextQuality.Option3)
        *BetterQualitySettings: LIST(ColorMode.Mono,
                                     Resolution.Option1,
                                     TextQuality.Option1)
        *DraftQualitySettings: LIST(ColorMode.Mono,
                                    Resolution.Option2,
                                    TextQuality.Option2)
        *DefaultQuality: BETTERQUALITY }
    *default: {
        *BestQualitySettings: LIST(ColorMode.24bpp,
                                   Resolution.Option2,
                                   TextQuality.Option3)
        *BetterQualitySettings: LIST(ColorMode.Color,
                                     Resolution.Option2,
                                     TextQuality.Option1)
        *DraftQualitySettings: LIST(ColorMode.Color,
                                    Resolution.Option2,
                                    TextQuality.Option2)
        *DefaultQuality: BETTERQUALITY }}

As illustrated in the example, a good strategy is to specify one *Case entry for single color mode, then use a *Default entry for all multicolor modes. This is because Unidrv's Page Setup property sheet page offers the user two choices — color or non-color printing. If you use the format in the example, Unidrv displays the quality buttons when the user selects the color printing option.

Following is a more complex example, which ties image quality to both color mode and media type:

*switch: Colormode {
    *case: Mono {
    *switch: MediaType {
        *case: CLAYCOATED {
            *DraftQualitySettings:  LIST(Option List)
            *BetterQualitySettings:  LIST(Option List)
            *BestQualitySettings:  LIST(Option List)
            *DefaultQuality:  BESTQUALITY }
        *case: GLOSSY {
            *DraftQualitySettings:  LIST(Option List)
            *BetterQualitySettings:  LIST(Option List)
            *BestQualitySettings:  LIST(Option List)
            *DefaultQuality:  BETTERQUALITY
        *default:
            *DraftQualitySettings:  LIST(Option List)
            *BetterQualitySettings:  LIST(Option List)
            *BestQualitySettings:  LIST(Option List)
            *DefaultQuality:  DRAFTQUALITY }}}
    *default: {
    *switch: MediaType {
        *case: CLAYCOATED {
            *DraftQualitySettings:  LIST(Option List)
            *BetterQualitySettings:  LIST(Option List)
            *BestQualitySettings:  LIST(Option List)
            *DefaultQuality:  BESTQUALITY }
        *case: GLOSSY {
            *DraftQualitySettings:  LIST(Option List)
            *BetterQualitySettings:  LIST(Option List)
            *BestQualitySettings:  LIST(Option List)
            *DefaultQuality:  BETTERQUALITY }
        *default: {
            *DraftQualitySettings:  LIST(Option List)
            *BetterQualitySettings:  LIST(Option List)
            *BestQualitySettings:  LIST(Option List)
            *DefaultQuality:  DRAFTQUALITY }}}
}

When using the quality setting GPD entries, the following rules must be observed:

  • You must always use all four entries. Specifying an empty option list is allowed, and causes the associated radio button to be grayed out.
  • All four entries must be specified for all ColorMode and MediaType combinations. The examples use a *Default entry within each conditional statement to achieve this.
  • Option lists within the quality setting entries must not violate any option constraints you have specified.
  • Options included in an option list should not change the selected medium type. Also, while it is acceptable, for example, to set the color mode to 24 bits/pixel for best quality, 8 bits/pixel for better quality, and 4 bits/pixel for draft quality, changing to 1 bits/pixel (single color) would not be acceptable.

If a feature is included in a conditional statement that specifies quality settings, the parser sets the feature's *UpdateQualityMacro? attribute to TRUE. (See Feature Attributes.)


Handling Installable Features and Options

Some of a printer's features or options might be installable. For example, a printer could accept an optional envelope feeder, which might or might not be currently attached. This envelope feeder must be described within a GPD file in two ways:

  • As an option for the InputBin feature.
  • As an installable "feature" (even though it is really an option), which allows the user to indicate whether it is actually installed.

First, to specify the envelope feeder, along with an automatic feeder, as options for the InputBin feature, the following GPD entries could be used.

*Feature: InputBin
{
    *Name: "Input Bin"
    *Option: AUTO
    {
        *Name: "Automatic Feeder"
        *Command: CmdSelect {Command Attributes}
    }
    *Option: ENVFEED
    {
        *Name: "Envelope Feeder"
        *Command: CmdSelect {Command Attributes}
    }
}

To make the envelope feeder installable, additional GPD entries are needed, as follows:

*InstalledOptionName: "Installed"
*NotInstalledOptionName: "Not installed"
*Feature: InputBin
{
    *Name: "Input Bin"
    *Option: AUTO
    {
        *Name: "Automatic Feeder"
        *Command: CmdSelect {Command Attributes}
    }
    *Option: ENVFEED
    {
        *Name: "Envelope Feeder"
        *Command: CmdSelect {Command Attributes}
        *Installable?: TRUE
        *InstallableFeatureName: "Optional Envelope Feeder"
    }
}

Within the *Option entry for the envelope feeder, two attributes have been added:

  • The *Installable? attribute indicates that the option is installable.
  • The *InstallableFeatureName attribute specifies a text string that Unidrv displays so that the user can indicate whether the option is actually installed.

Whenever *Installable? is set to TRUE for a feature or option, Unidrv creates an additional feature for the property sheet display. (Note that even if the installable item is a option, Unidrv creates a feature representation for it in the property sheet.) This Unidrv-synthesized feature is identified by the string supplied with *InstallableFeatureName. The feature provides two options, "Installed" and "Not installed", and allows the user to select one of these options. The strings "Installed" and "Not installed" are specified with the *InstalledOptionName and *NotInstalledOptionName attributes so that you can modify them if other text is more appropriate.

So, for our example, the property sheet would include an InputBin feature, labeled Input Bin, that includes two options, labeled Automatic Feeder and Envelope Feeder. The property sheet would also include an additional feature, labeled Optional Envelope Feeder, with two options, labeled Installed and Not installed. The user can only select Envelope Feeder under Input Bin if he or she first selects Installed under Optional Envelope Feeder.

Sometimes, it is necessary to indicate that certain installable options cannot be installed simultaneously, or that a certain non-installable option cannot be selected if some other installable option is installed. To handle these situations, use GPD entries that specify option constraints.

You cannot use the *Installable? attribute with optional features that require a *DisabledFeatures entry. For these features, you must explicitly specify the optional feature with "Installed" and "Not installed" options. For example, suppose a printer has an optional duplexing unit. The Duplex feature (see Standard Features) must be disabled if the duplexing unit is not installed. You must define an "Optional Duplexing Unit" feature, with "Installed" and "Not Installed" options. Within the "Not Installed" *Option entry, you would include a *DisabledFeatures entry for the Duplex feature. The following GPD entries can be used:

*Feature: DuplexUnit
{
    *ConflictPriority: 3   *% Make priority higher than Duplex feature
    *Name: "Optional Duplexing Unit"
    *Option: Installed
    {
        *Name: "Installed"
    }
    *Option: NotInstalled
    {
        *Name: "Not Installed"
        *DisabledFeatures: LIST(Duplex)
        *Constraints: LIST (Duplex.LongEdge, Duplex.ShortEdge)
    }
}

Be sure to also specify any relevant option constraints, as illustrated.


Specifying Feature and Option Display Order

To control the order in which features and options are displayed on Unidrv-generated property sheet pages, include empty *Feature and *Option entries in the GPD file. These entries must be placed towards the beginning of the file, before the appearance of full *Feature and *Option entries, and before any other references to feature or option names. The order in which the empty entries are listed is the order in which the features and options appear on the property sheet pages. (Note, however, that options of the PaperSize feature are always listed in alphabetical order, and this order cannot be changed.)

Following is an example of a set of empty *Feature and *Option entries:

*Feature: EconoMode
{
    *Option: Off{}
    *Option: On{}
}
*Feature: Orientation
{
    *Option: PORTRAIT{}
    *Option: LANDSCAPE_CC90{}
}
*Feature: PaperSize
{
}
*Feature: Resolution
{
    *Option: Option1{}
    *Option: Option2{}
    *Option: Option3{}
}

The example specifies the order in which the EconoMode, Orientation, PaperSize, and Resolution features are displayed. Additionally, it specifies the display order for the EconoMode, Orientation, and Resolution options. PaperSize options are displayed in alphabetical order.

If a GPD file does not include empty *Feature and *Option entries specifying the display order, the GPD parser determines the display order. While the parser generally causes features and options to be displayed in the order they appear in a GPD file, this order is not guaranteed. Additionally, by default the parser always causes the InputBin feature to be displayed first.

Including empty *Feature and *Option entries to explicitly specify display order is recommended over allowing the parser to create the order.


Describing Printer Memory Configurations

A Unidrv minidriver can contain descriptions of a printer's possible and default memory configurations, so that Unidrv can attempt to keep track of printer memory usage. Each memory configuration description includes values for both the total memory and available memory. Available memory can be used for downloading fonts, protecting pages, and other operations controlled by Unidrv.

Within a GPD file, you can use two methods to describe a printer's possible memory configurations. Both methods involve specifying attributes within a *Feature entry for the Memory feature, which is one of the standard features. The two methods are as follows:

  1. You can specify every possible configuration in a separate *Option entry within the *Feature entry. Each *Option entry must contain a *MemoryConfigKB attribute, which is described in Option Attributes for the Memory Feature.

    For example, to specify that a printer can have two memory configurations, a 1-megabyte configuration with 450 kilobytes available and a 2-megabyte configuration with 1350 kilobytes available, you can use the following GPD entries:

    *Feature: Memory
{
    *Name: "Printer Memory"
    *DefaultOption: 1MB
    *Option: 1MB
    {
        *Name: "Standard 1MB"
        *MemoryConfigKB: PAIR(1024, 450)
    }
    *Option: 2MB
    {
        *Name: "Add-On 2MB"
        *MemoryConfigKB: PAIR(2048,1350)
    }
}
  2. Alternatively, the *Feature entry can contain one or more *MemConfigKB or *MemConfigMB attributes instead of *Option entries. This is simply a way to specify memory options without including a set of *Option entries. Each *MemConfigKB or *MemConfigMB attribute represents a memory option.

    For example, to specify the same two configurations, a 1-megabyte configuration with 450 kilobytes available and a 2-megabyte configuration with 1350 kilobytes available, you can use the following GPD entries:

    *Feature: Memory
{
    *Name: "Printer Memory"
    *DefaultOption: 1024KB
    *MemConfigKB: PAIR(1024, 450)
    *MemConfigKB: PAIR(2048, 1350)
}

    The GPD parser creates a displayable option name for each configuration, based on the first entry in the PAIR statement. In the example, option names would be "1024KB" and "2048KB". The argument to the *DefaultOption attribute must match one of these names.

Both method 1 and method 2 can be used within a single *Feature entry.

If parser-generated option names are incompatible with localization requirements, use method 1 instead of method 2.

Whichever method you use, the Unidrv User Interface displays the memory feature options in the device's printer property sheet.

If your minidriver specifies memory configurations, it can also specify the types of data that can be stored in printer memory and use up its available space. The *MemoryUsage attribute is one of the printer capability attributes, and you can use it to indicate to Unidrv whether font, raster, or vector data, or a combination of the three, are stored within printer memory. For each type specified, Unidrv attempts to keep track of how much printer memory is in use.


Specifying Paper Sizes

Unidrv supports three categories of paper sizes—standard paper sizes, vendor-defined paper sizes, and user-defined paper sizes.

Standard Paper Sizes

Standard paper sizes are those that are commonly supported by most printers. The dimensions of these paper sizes are predefined. For more information, see Supporting Standard Paper Sizes.

Vendor-Defined Paper Sizes

Vendor-defined paper sizes (also called non-standard paper sizes) are defined by a printer vendor, within a printer's GPD file. For more information, see Supporting Vendor-Defined Paper Sizes.

User-Defined Paper Sizes

User-defined paper sizes (also called customized paper sizes) are defined by system administrators using the system's print folder, and thus are system-specific. For more information, see Supporting User-Defined Paper Sizes.


Supporting Standard Paper Sizes

Standard paper sizes are represented by the standard options for the PaperSize feature.

For each standard paper size that a printer supports, the GPD file's PaperSize feature must include an *Option entry whose argument is one of the standard option names (except CUSTOMSIZE). Within this entry, the following option attributes are required:

*PrintableArea
*PrintableOrigin
*rcNameID
*Command

The following option attributes can be used, but are not required:

*CursorOrigin
*RotateSize?
*PageProtectMem

For all standard paper sizes, the RCID_DMPAPER_SYSTEM_NAME resource identifier (defined in stdnames.gpd) should be used as the argument to *rcNameID.


Supporting Vendor-Defined Paper Sizes

Vendor-defined paper sizes are vendor-specific and must be fully described by each printer's GPD file. These sizes are also called non-standard paper sizes, because they are not included in the standard options for the PaperSize feature.

For each vendor-defined paper size that a printer supports, the GPD file's PaperSize feature must include an *Option entry whose argument is not one of the standard option names. Within this entry, the following option attributes are required:

*PageDimensions
*PrintableArea
*PrintableOrigin
*rcNameID or *Name
*Command

The following option attributes can be used, but are not required:

*CursorOrigin
*RotateSize?
*PageProtectMem


Supporting User-Defined Paper Sizes

User-defined paper sizes can be specific to a single print server and are typically customized for a specific application. Hence they are often called customized paper sizes. System administrators use the print folder to define customized paper sizes. If a printer can handle customized paper sizes, vendors must use the printer's GPD file to specify the acceptable range of sizes.

Two methods are provided for describing acceptable size ranges for customized paper:

  • You can specify size ranges explicitly.
  • You can specify size ranges relative to the printer's largest paper size.

Specifying Paper Size Ranges Explicitly

To use this method, your GPD file's PaperSize feature must include an *Option entry with a CUSTOMSIZE argument. This entry must contain the following option attributes:

*MinSize
*MaxSize
*MaxPrintableWidth
*MinLeftMargin
*TopMargin
*BottomMargin
*CenterPrintable?
*CursorOrigin
*Command

You can use these GPD entries to create customized paper size descriptions only for printers having the following characteristics:

  • The printer supports commands to explicitly select customized paper sizes (typically by moving the cursor origin).
  • The cursor origin remains fixed, relative to the upper left-hand corner of the paper, for all customized paper sizes. (This is typically not true for landscape mode printing, or for printers that are center-fed or right-hand-fed.)
  • The top and bottom margins are independent of paper size.
  • If the paper width is less than the sum of the values specified for *MinLeftMargin and *MaxPrintableWidth, there is no right-hand margin. That is, the printer can print to the right edge of the paper.

Command parameters (specified in *Command entries) can be calculated at print time if standard variable expressions are used, typically including the PhysPaperLength and PhysPaperWidth variables. These variables represent the actual paper size requested for the print job, as specified by an application.

Specifying Paper Size Ranges Relative to the Printer's Largest Paper Size

For printers that do not support the characteristics required for specifying customized paper size ranges explicitly, an alternate method is provided, which specifies paper sizes relative to the printer's largest paper size.

To use this method, your GPD file's PaperSize feature must include an *Option entry with a CUSTOMSIZE argument. This entry must contain the following option attributes:

*MinSize
*MaxSize
*MaxPrintableWidth
*CustCursorOriginX
*CustCursorOriginX
*CustPrintableOriginX
*CustPrintableOriginY
*CustPrintableSizeX
*CustPrintableSizeY
*Command

When specifying a size range relative to the printer's largest paper size, use the following alignment rules:

  • For left-feed printers, the top and left margins of all paper sizes must be aligned.
  • For right-feed printers, the top and right margins of all paper sizes must be aligned.
  • For center-feed printers, the top margins and top center points of all paper sizes must be aligned.

The following steps are involved:

  1. Determine the following information for the printer's largest paper size:
    • The command required to select the largest paper size.
    • Values that would be used for the largest paper size's *PageDimensions, *CursorOrigin, *PrintableOrigin, and *PrintableArea GPD entries, as if they were going to be included in the GPD file. However, you will not actually place these entries in the file.
  2. Create formulas that specify or calculate the following information for each customized paper size, relative to the printer's largest paper size.
    • The origin and size of each paper's printable area.
    • The cursor origin for each paper.

The formulas for step 2 must be CUSTOMSIZE parameter expressions, which are specified as values for the following GPD entries:

*CustCursorOriginX
*CustCursorOriginX
*CustPrintableOriginX
*CustPrintableOriginY
*CustPrintableSizeX
*CustPrintableSizeY

The CUSTOMSIZE option must also include a *Command entry which specifies the command that selects the largest printer size. This command is sent for all custom paper sizes, and the formulas specified for the printable area and cursor origin control where the printer prints on the actual paper, whatever its size.

Sample Calculations

As a simple example, assume your printer supports customized paper sizes that have margins of the same size as the largest paper size's margins. The steps involved are:

  1. Determine values for the largest paper size's *PageDimensions, *CursorOrigin, *PrintableOrigin, and *PrintableArea entries. (Don't put these entries in the GPD file.)
  2. Determine the width of each of the largest paper size's margins in terms of these values, as illustrated in the following pseudo-expressions:

    LeftMarginWidth=*PrintableOrigin.x

    RightMarginWidth=*PageDimensions.x–*PrintableArea.x–LeftMarginWidth

    TopMarginWidth=*PrintableOrigin.y

    BottomMarginWidth=*PageDimensions.y–*PrintableArea.y–TopMarginWidth

    In these pseudo-expressions, .x and .y represent the horizontal and vertical components of each entry's pair value. For landscape printing, use landscape values for *PrintableArea and *PrintableOrigin.

  3. Now create pseudo-expressions that specify or calculate the printable areas for non-standard paper sizes.

    *CustPrintableOriginX: %d{LeftMarginWidth}

    *CustPrintableOriginY: %d{TopMarginWidth}

    *CustPrintableSizeX: %d{PhysPaperWidth–LeftMarginWidth–RightMarginWidth}

    *CustPrintableSizeY: %d{PhysPaperLength–TopMarginWidth–BottomMarginWidth}

    Notice use of the two standard variables, PhysPaperWidth and PhysPaperLength. At runtime, these variables contain the length and width of the actual paper size that has been requested by an application.

    Note that these pseudo-expressions are valid whether the paper is left-fed, right-fed, or center-fed.

  4. Plug real values, determined in step 1, into these expressions to create GPD entries. Examples might be:
    *CustPrintableOriginX:  %d{300}
*CustPrintableOriginY:  %d{300}
*CustPrintableSizeX:   %d{PhysPaperWidth-600}
*CustPrintableSizeY:  %d{PhysPaperLength-600}
  5. Create pseudo-expressions that calculate the cursor origin indices. In the following pseudo-expressions, *CursorOrigin.x and *CursorOrigin.y are place holders for the horizontal and vertical components of the pair value for largest paper size's cursor origin.

    For left-fed printers:

    *CustCursorOriginX: %d{*CursorOrigin.x}

    *CustCursorOriginY: %d{*CursorOrigin.y}

    For right-fed printers:

    *CustCursorOriginX: %d{*CursorOrigin.x+PhysPaperWidth–*PageDimensions.x}

    *CustCursorOriginY: %d{*CursorOrigin.y}

    For center-fed printers:

    *CustCursorOriginX: %d{*CursorOrigin.x+(PhysPaperWidth–PageDimensions.x)/2}

    *CustCursorOriginY: %d{*CursorOrigin.y}

  6. Plug real values, determined in step 1, into these expressions to create GPD entries. Examples might be (for center-fed paper):
    *CustCursorOriginX:  %d{((PhysPaperWidth-14040)/2)+300}
*CustCursorOriginY:   %d{180}
  7. Specify values for the remaining three GPD entries—*MinSize, *MaxSize, and *MaxPrintableWidth. The value specified for *MaxPrintableWidth is not actually used for this method, but the parser requires the entry to exist, so its value can be set to 1.

A Real Example

The following example GPD file segment describes acceptable customized paper sizes for a center-fed printer. For portrait mode, all margins for all custom paper sizes are 300 master units (1/4 inch) in size. For landscape mode, top and bottom margins are 240 master units while left and right margins are 200 master units.

*Option: CUSTOMSIZE
{
  *rcNameID: =USER_DEFINED_SIZE_DISPLAY
  *MinSize: PAIR(4200,9000)
  *MaxSize: PAIR(14040, 21240)
  *MaxPrintableWidth: 14040
  *MinLeftMargin: 100
  *CenterPrintable?: FALSE
  *PageProtectMem: 1692
  *InsertBlock: =PaperConstraints
  *switch: Orientation
  {
    *case: PORTRAIT
    {
       *CustCursorOriginX:  %d{((PhysPaperWidth-14040)/2)+300}
       *CustCursorOriginY:   %d{180}
       *CustPrintableOriginX:  %d{300}
       *CustPrintableOriginY:  %d{300}
       *CustPrintableSizeX:   %d{PhysPaperWidth-600}
       *CustPrintableSizeY:  %d{PhysPaperLength-600}
       *Command: CmdSelect
       {
         *Order: DOC_SETUP.13
         *Cmd: "<1B>&l101a8c1e99F<1B>*p0x0Y<1B>*c0t8064x12528Y"
       }
    }
    *case: LANDSCAPE_CC90
    {
      *switch:  Option20
      {
      *% The 8100 rotates the landscape job 180 degrees if a stapler
      *% is attached, so the staple can be placed in the top left
      *% corner of the document. The printer always rotates the
      *% landscape job, even if stapling is not selected.
        *case: 3KStapler
        {
          *CustCursorOriginX:  %d{((PhysPaperWidth-14040)/2)+200}
          *CustCursorOriginY:   %d{PhysPaperLength}
          *CustPrintableOriginX:  %d{200}
          *CustPrintableOriginY:  %d{240}
          *CustPrintableSizeX:   %d{PhysPaperWidth-400}
          *CustPrintableSizeY:  %d{PhysPaperLength-480}
          *Command: CmdSelect
          {
            *Order: DOC_SETUP.13
            *Cmd: "<1B>&l101a8c1e63F<1B>*p0x0Y<1B>*c0t12456x8184Y"
          }
        }
        *case: MBM5S
        {
          *CustCursorOriginX:  %d{((PhysPaperWidth-14040)/2)+200}
          *CustCursorOriginY:   %d{PhysPaperLength}
          *CustPrintableOriginX:  %d{200}
          *CustPrintableOriginY:  %d{240}
          *CustPrintableSizeX:   %d{PhysPaperWidth-400}
          *CustPrintableSizeY:  %d{PhysPaperLength-480}
          *Command: CmdSelect
          {
            *Order: DOC_SETUP.13
            *Cmd: "<1B>&l101a8c1e63F<1B>*p0x0Y<1B>*c0t12456x8184Y"
          }
        }
        *default
        {
          *CustCursorOriginX:  %d{((PhysPaperWidth-14040)/2)+200}
          *CustCursorOriginY:   %d{21000}
          *CustPrintableOriginX:  %d{200}
          *CustPrintableOriginY:  %d{240}
          *CustPrintableSizeX:   %d{PhysPaperWidth-400}
          *CustPrintableSizeY:  %d{PhysPaperLength-480}
          *Command: CmdSelect
          {
            *Order: DOC_SETUP.13
            *Cmd: "<1B>&l101a8c1e63F<1B>*p0x0Y<1B>*c0t12456x8184Y"
          }
        }
      } *% switch Option20
    } *% case LANDSCAPE_CC90
  } *% switch Orientation
}


Referencing Locales

GPD files can reference a system's locale. Typically, locale identifiers are used within *Switch statements, where parameters such as default paper sizes and resource DLLs can be specified in a locale specific manner.

To reference locale information, the GPD file must contain an *Include statement that includes the file locale.gpd (supplied with this DDK) as follows:

*Include: locale.gpd

This GPD file defines a feature named "Locale", and defines options for many locales. (Refer to the file to see which locales are defined.) Following is an example usage of these locale options. The example bases the default paper size on the locale.

*Feature: PaperSize
{
...
    Option: A4
    {
    }
    ...
*switch: Locale
{
    *case: English_United_States
    {
        *DefaultOption: Letter
    }
    *case: English_United_Kingdom
    {
        *DefaultOption: A4
    }
    *default:
    {
        *DefaultOption: Letter
    }
} *% End of switch
} *% End of Feature: PaperSize

At runtime, Unidrv determines the system's default locale by calling GetSystemDefaultLCID (described in the platform SDK documentation). When a printer is installed, the GPD parser reads the printer's GPD file and uses information within the *Case statement associated with the default locale. (Note that if the system's locale is changed after the printer is installed, locale-based options are not changed.)

Here's another example, which selects a resource DLL based on the locale. The resource DLL can contain locale-specific resources, such as display strings.

*switch: Locale
{
    *case: English_United_States
    {
        *ResourceDLL: english.dll
    }
    *case: German_Standard
    {
        *ResourceDLL: german.dll
    }
    *default:
    {
        *ResourceDLL: english.dll
    }
}


Using Unidrv Vector Graphics Capabilities

On Microsoft® Windows® XP and later, Unidrv provides support for two types of vector graphics printers: HP-GL/2 monochrome (PCL-5e), or PCL XL monochrome (PCL-6). There is also pseudo-vector graphics support for graphics printers that do not have vector rendering capabilities.

HP-GL/2 Monochrome (PCL-5e) Vector Graphics Support

PCL XL Monochrome (PCL-6) Vector Graphics Support

Pseudo-Vector Graphics Support


HP-GL/2 Monochrome (PCL-5e) Vector Graphics Support

HP-GL/2 monochrome (PCL-5e) vector graphics support in Unidrv running on Windows XP and later allows the printer driver to create job data in a format that is optimal for the device: vector graphics versus raster graphics. This normally results in less system overhead, less output data to transmit, and faster print throughput.

HP-GL/2 uses most of the currently-defined GPD features for job setup, page setup, media selection, and paper size. The actual drawing commands are hard-coded in the driver.

The following topics are covered:

Enabling HP-GL/2 Vector Graphics Support (PCL-5e) in the GPD

Halftone Algorithms

HP-GL/2 Supported Fonts

HP-GL/2 Caveats


Enabling HP-GL/2 Vector Graphics Support (PCL-5e) in the GPD

To enable HP-GL/2 vector support on Windows XP, you must do two things:

  1. Set the *Personality attribute to PERSONALITY_HPGL2.
  2. Define a GraphicsMode customized feature that has an HPGL2MODE option. To provide raster graphics support as well, include a RASTERMODE option.

You can set the personality attribute in this way:

*Personality: =PERSONALITY_HPGL2

The PERSONALITY_HPGL2 constant is defined in stdnames.gpd.

The following GPD example demonstrates setting the *Personality attribute and defining a GraphicsMode customized feature with both a vector graphics mode, as well as a raster graphics mode. Note that the entire block is guarded by an *Ifdef: GPD compiler directive.

*Ifdef: WINNT_51
*Personality: =PERSONALITY_HPGL2
*Feature: GraphicsMode
{
    *rcNameID: =GRAPHICSMODE_DISPLAY
    *FeatureType: DOC_PROPERTY
    *HelpIndex: 12000
    *DefaultOption: HPGL2MODE
    *Option: HPGL2MODE
    {
        *rcNameID: =GRAPHICSMODE_HPGL2_DISPLAY
    }
    *Option: RASTERMODE
    {
        *rcNameID: =GRAPHICSMODE_RASTER_DISPLAY
    }
}
*Endif:

The WINNT_51 parameter used in the above directive applies to versions of Unidrv, rather than operating system versions. For a Windows XP Unidrv printer driver running on Windows 2000, the WINNT_51 parameter is defined and the block is compiled. For earlier Unidrv versions, regardless of operating system version, this parameter is undefined, and the block is not compiled.

A GPD file for a color printer should also define a ColorMode feature, as shown in the following generic sample. Note that specific details of your printer might require changes to certain values.

*Feature: ColorMode
{
  *rcNameID: =COLOR_PRINTING_MODE_DISPLAY
  *HelpIndex: 12004
  *DefaultOption: 24bpp
  *Option: Mono
   {
     *rcNameID: =MONO_DISPLAY
     *DevNumOfPlanes: 1
     *DevBPP: 1
     *Color?: FALSE
     *Command: CmdSelect
      {
        *Order: PAGE_SETUP.16
        *Cmd: "<1B>&b1M"
      }
   }
  *Option: 24bpp
   {
     *rcNameID: =24BPP_DISPLAY
     *DevNumOfPlanes: 1
     *DevBPP: 24
     *DrvBPP: 24
     *PaletteSize: 256
     *PaletteProgrammable?: TRUE
     *Command: CmdDefinePaletteEntry
      {
        *Cmd : "<1B>*v" %d{RedValue}"a"
+                       %d{GreenValue}"b"
+                       %d{BlueValue}"c"
+                       %d{PaletteIndexToProgram}"I"
      }
     *Command: CmdSelectPaletteEntry { *Cmd : "<1B>*v"
+                        %d{CurrentPaletteIndex}"S" }
     *Command: CmdSetSrcBmpWidth { *Cmd : "<1B>*r"
+                        %d{RasterDataWidthInBytes / 3}"S" }
     *Command: CmdSelect
      {
        *Order: PAGE_SETUP.16
        *Cmd: "<1B>*v1N<1B>*v1O<1B>*l184O<1B>*v6W<000308080808>
+              <1B>*v0a0b0c7i255a255b255c"
      }
   }
}


Halftone Algorithms

Some printer vendors prefer to use different halftone algorithms while printing different kinds of objects, such as text, vector objects, and bitmaps. The three examples that follow show what should be added to the GPD to print each of these types of objects.

The first example shows how to incorporate halftone rendering while printing text.

*Ifdef: WINNT_51
*Feature: TEXTHALFTONE
{
  *rcNameID: =TEXTHALFTONE_DISPLAY
  *DefaultOption: DETAIL
  *Option: DETAIL
   {
     *rcNameID: =DETAIL_HT_DISPLAY
     *Command: CmdSetTextHTAlgo { *Cmd : "<1B>*t0J" }
   }
  *Option: SMOOTH
   {
     *rcNameID: =SMOOTH_HT_DISPLAY
     *Name: "Smooth"
     *Command: CmdSetTextHTAlgo { *Cmd : "<1B>*t15J" }
   }
  *Option: BASIC
   {
     *rcNameID: =BASIC_HT_DISPLAY
     *Command: CmdSetTextHTAlgo { *Cmd : "<1B>*t18J" }
   }
}
*Endif:

The second example includes commands for halftone rendering while printing vector graphics.

*Ifdef:  WINNT_51
*Feature: GRAPHICSHALFTONE
{
  *rcNameID: =GRAPHICSHALFTONE_DISPLAY
  *DefaultOption: SMOOTH
  *Option: DETAIL
   {
     *rcNameID: =DETAIL_HT_DISPLAY
     *Command: CmdSetGraphicsHTAlgo { *Cmd : "<1B>*t15J" }
   }
  *Option: SMOOTH
   {
     *rcNameID: =SMOOTH_HT_DISPLAY
     *Command: CmdSetGraphicsHTAlgo { *Cmd : "<1B>*t18J" }
   }
  *Option: BASIC
   {
     *rcNameID: =BASIC_HT_DISPLAY
     *Command: CmdSetGraphicsHTAlgo { *Cmd : "<1B>*t18J" }
   }
}
*Endif:

The third example includes commands for halftone rendering while printing bitmaps.

*Ifdef: WINNT_51
*Feature: PHOTOHALFTONE
{
  *rcNameID: =PHOTOHALFTONE_DISPLAY
  *DefaultOption: SMOOTH
  *Option: DETAIL
   {
     *rcNameID: =DETAIL_HT_DISPLAY
     *Command: CmdSetPhotoHTAlgo { *Cmd : "<1B>*t15J" }
   }
  *Option: SMOOTH
   {
     *rcNameID: =SMOOTH_HT_DISPLAY
     *Command: CmdSetPhotoHTAlgo { *Cmd : "<1B>*t7J" }
   }
  *Option: BASIC
   {
     *rcNameID: =BASIC_HT_DISPLAY
     *Command: CmdSetPhotoHTAlgo { *Cmd : "<1B>*t3J" }
   }
}
*Endif:


HP-GL/2 Supported Fonts

HP-GL/2 supports the same font resources as those defined for raster mode. Device fonts that can be used by both vector and raster modes are added to the GPD and resource files.


HP-GL/2 Caveats

  1. HP-GL/2 works only for the version of Unidrv that ships with Windows XP and later operating system releases (Windows XP Unidrv refers to the set of driver files that ship with Windows XP — unidrv.dll, unidrvui.dll, unires.dll, and stdnames.gpd). It does not work on Windows 2000 Unidrv. If a Windows XP version of Unidrv is present on a machine running Windows 2000 (for example, when a Windows 2000 machine makes a point and print connection to a Windows XP server), then the driver uses HP-GL/2.
  2. Some of the rendering commands in the GPD are ignored when HP-GL/2 mode is activated. Instead, hard coded commands in the driver are used. However, those commands must be present in the GPD for the following reasons:
    1. In later versions of the operating system, the hard coding of rendering commands might be removed.
    2. An HP-GL/2 driver offers an option to switch to raster mode (that is, to not use the HP-GL/2 driver). For raster mode, all of the commands must be present in the GPD.

      A good rule of thumb is that any PCL-XL/HP-GL/2 command that is used to actually draw something (for example, CmdDownloadPattern or CmdSelectBlackBrush) is ignored. Commands such as Page setup, Document setup, and others that are not drawing commands are not ignored. For more information on these commands, see Color Commands.

      Additionally, all HP-GL/2 commands are hard-coded in the driver.

  3. Masks received in calls to DrvBitBlt and other bit-block transfer functions may not work correctly.
  4. When Windows XP Unidrv is used on Windows 2000 and HP-GL/2 is activated, some graphics rendering functions may not work correctly. For example, the output from DrvGradientFill calls has red and blue reversed.
  5. Unidrv assumes that printer hardware supports ROP commands. If a printer does not support ROP, some documents might not print correctly.
  6. Support for hatch brushes is required. If the printer does not support hatch brushes, then the output depends on how the printer hardware handles the hatch brush selection command (FT21,x SV21,x).
  7. The color of a hatch brush is ignored for monochrome printers. It is always printed as black.
  8. For color printers, HP-GL/2 supports only 24 bpp/600 dpi. For monochrome printers, HP-GL/2 supports only 600 dpi. If your printer supports other values, constrain HP-GL/2 mode to be chosen only when color depth is 24 bpp and resolution is 600 dpi. The following example shows how the GraphicsMode feature can be modified to accomplish this. In this example, the first *Constraints entry causes Unidrv to reject a mode change to HPGL2MODE if the Resolution feature's Option2 value is not 600x600 dpi. (In the example, it is assumed that the Option2 value is some lower resolution, such as 300x300 dpi.) The second *Constraints entry causes Unidrv to reject the mode change if the ColorMode feature's options are Color or 8bpp.
    *Feature: GraphicsMode
{
  *rcNameID: =GRAPHICSMODE_DISPLAY
  *FeatureType: DOC_PROPERTY
  *HelpIndex: 12000
  *DefaultOption: HPGL2MODE
  *Option: HPGL2MODE
   {
     *rcNameID: =GRAPHICSMODE_HPGL2_DISPLAY
     *Constraints: Resolution.Option2
     *Constraints: LIST(ColorMode.Color, ColorMode.8bpp)
   }
  *Option: RASTERMODE
   {
     *rcNameID: =GRAPHICSMODE_RASTER_DISPLAY
   }
}
  9. Color printers must be able to scale images on the hardware. This requirement does not exist for monochrome printers.
  10. For monochrome printers, it is assumed that:
    • The printer accepts only 1bpp information.
    • A bit set to 1 indicates a black pixel, and a bit set to 0 indicates a white pixel.
    • The printer cannot gray scale any color. (This arises naturally from the 1 bpp limitation.)
  11. The following compression methods must be supported:
    • No compression
    • TIFF
    • Delta Row
  12. HP-GL/2 does not perform system landscape rotation. When HP-GL/2 is enabled, the printer is assumed to handle the rotation of rasters, fonts, and coordinates for pages printed in landscape mode. To counter this problem, make sure that all GPD rotation parameters (the *RotateCoordinate?, *RotateFont?, and *RotateRaster? attributes) are set to TRUE. If your printer has memory overflow problems with rotation, you should consider not activating HP-GL/2, or placing constraints on memory (that is, HP-GL/2 should be activated only if memory is 4 MB or more.

    On low-memory devices (for example, a 600 dpi monochrome laser printer with 2 MB of RAM), certain pages that generate out-of-memory errors when the device is in HP-GL/2 mode might print correctly in raster mode. One solution for devices with less than a full bitmap of memory is to write the GPD so that raster mode is the default, and to let the system handle landscape rotation, rather than HP-GL/2. In addition, certain complex portrait print jobs might print correctly in raster mode, but not in HP-GL/2 mode. If that is the case, you should consider making raster mode the default.

  13. Print optimization functionality on the Advanced tab of the printer property pages is currently ignored in HP-GL/2 mode.
  14. *MirrorRasterPage? is not supported in HP-GL/2 mode.


PCL XL Monochrome (PCL-6) Vector Graphics Support

Windows XP and later.

Unidrv's support for PCL XL monochrome (PCL-6) vector graphics allows it to create job data in a format that is optimal for the device: either vector graphics or raster graphics. This support usually results in less system overhead, less output data to transmit, and faster print throughput.

PCL XL monochrome uses most of the currently-defined GPD features for job setup, page setup, media selection, and paper size. However, the actual drawing commands are hard-coded within Unidrv. Consequently, most drawing commands within GPD files are ignored. There is no need to remove these commands from the GPD file.

This section contains the following topics:

Writing a PCL XL GPD File

Specifying New Device Fonts in PCL XL Minidrivers

Using Default PCL XL Fonts

Installing a PCL XL Minidriver

PCL XL Issues


Writing a PCL XL GPD File

This section provides general information about writing a PCL XL GPD file, such as which files your GPD file should include, how to enable PCL XL in your GPD file, and how to order PCL XL commands in a PCL XL stream.

Files to Include

To write a GPD-based minidriver, use the preprocessor directive *Include to specify the following GPD files:

pclxl.gpd — contains macros for the PCL XL operators so that you can write GPD code that is easier to read and understand. For example, you can write =BeginPage instead of <43>.

p6disp.gpd — contains macros for resource strings contained in pcl5eres.dll and pclxl.dll.

p6font.gpd — contains macros for fonts contained in pclxl.dll.

pjl.gpd — contains macros for PJL commands.

In addition to the preceding files, include the standard GPD files, stdnames.gpd and ttfsub.gpd.

The following example shows how these files would be included in a GPD file.

*Include: stdnames.gpd
*Include: ttfsub.gpd
*Include: pclxl.gpd
*Include: p6disp.gpd
*Include: p6font.gpd
*Include: pjl.gpd

Enabling PCL XL Support in the GPD File

To enable PCL XL vector support, you only need to set the *Personality attribute. This is done in the following way:

*Personality: = PERSONALITY_PCLXL

The PERSONALITY_PCLXL constant is defined in stdnames.gpd.

A model-specific sample GPD file is included in the Windows DDK to help developers create new PCL XL minidrivers. Every PCL XL model-specific GPD file must include the standard PCL XL GPD file, pclxl.gpd.

PCL XL Command Ordering

The order of the commands is more critical in PCL XL than in PCL-5. A small error in the PCL stream is not likely to affect the job, but PCL XL commands are valid only at certain points in the stream so any error in PCL XL (PCL-6) causes an XL error page to be emitted. For example, you cannot send a BeginPage operator before you have sent a BeginSession operator.

A PCL XL stream has a form similar to the following. (The indentation shown is used only to emphasize the point that these operators come in pairs.)

PJL commands
BeginSession
  OpenDataSource
    BeginPage
      <page data>
    EndPage
  CloseDataSource
EndSession
PJL commands

The PCL XL stream is preceded by and followed by PJL commands. The PCL XL stream itself begins with a BeginSession operator, and ends with an EndSession operator. Within that pair of operators, there is another pair of operators: OpenDataSource and CloseDataSource. Within that operator pair come one or more BeginPage/EndPage operator pairs, one pair for each page sent to the printer. The page data, which describes how an individual page is rendered, is bracketed by a BeginPage/EndPage operator pair.

For detailed information about all PCL XL operators, refer to the PCL XL Feature Reference Protocol Class 2.0 documentation at http://www.hp-developer-solutions.com/.

Additional Information about PCL XL GPD Files

In PCL XL GPD files, the *FontFormat attribute name, which specifies the way that fonts are downloaded, is restricted to two values: HPPCL_OUTLINE and HPPCL_RES. The first value indicates that Unidrv is to download TrueType outline data. The second value indicates that Unidrv is to download bitmap soft font data.

An IHV can lessen printer memory usage by limiting the number of fonts to be downloaded, or by limiting the number of characters to be downloaded in a given font. The *MinFontID and *MaxFontID attribute names are used to inform Unidrv to download soft fonts whose IDs lie within the range specified by these values. Similarly, the *MinGlyphID and *MaxGlyphID attribute names are used to limit the number of glyphs in a given font to download to those within a specific range.

Unidrv operates under the assumption that each GPD file contains its own dither matrix. It is also recommended that each device have its own dither matrix. The dither matrix is specified in a *Feature: Dither customized feature.


Specifying New Device Fonts in PCL XL Minidrivers

If you want to support new device fonts in a PCL XL minidriver, you must create UFM files for those device fonts. To do so, use the Microsoft Minidriver Development Tool (MDT). Using this tool, you can edit all of the fields in a UFM file.

A UFM file has the following format:

A UNIFM_HDR structure, which serves as a header for the UFM file

A UNIDRVINFO structure

An IFIMETRICS structure

An EXTTEXTMETRIC structure

A character width table

A correctly formatted font selection command must be placed in the correct location in the UFM file. The font selection command consists of 16 bytes for the font selection, one byte for a space character, and as many bytes as are needed to hold the digits of the symbol set number.

Following is an example of how a font selection command would appear in a UFM file. (The numbers in the second line show the position of each character in the font selection command.)

CG Omega    BdIt 629
12345678901234567890

The font name and style, CG Omega BdIt (bold/italic) take up the first 16 bytes. After that, there is a single space character, which separates the font name from the symbol set number. The symbol set number, 629, takes up the last three bytes. Unidrv parses the font selection command in the UFM file and sends the font selection command and symbol set number separately.

To enter the font selection command into the UFM file, start the Microsoft Minidriver Development Tool, and open the UFM file. The Headers tab displays information about the UNIFM_HDR and the UNIDRVINFO structures. Double-click the SelectFont member of the UNIDRVINFO structure, and enter the font selection command as discussed previously. Make sure there is a space character separating the font name from the symbol select number.

The font name and symbol set number discussed in the previous example are two of the three attributes required for the SetFont operator, which would appear in the output data from the driver. In the following example, the FontName and SymbolSet attributes of this operator are set to the same values as in the preceding example. The third attribute, CharSize, is set to the value 100.

ubyte_array (CG Omega    BdIt) FontName
real32 100 CharSize
uint16 629 SymbolSet
SetFont

For more information about the SetFont font selection command, see the PCL XL Feature Reference Protocol Class 2.0 documentation at http://www.hp-developer-solutions.com/.


Using Default PCL XL Fonts

If you want to include the standard PCL XL fonts, you should include the standard resource DLL, pclxl.dll, that is part of the cab file. The following line, which should appear in the GPD, uses the *ResourceDLL attribute to specify the resource DLL to be used.

*ResourceDLL: "pclxl.dll"

The default PCL XL fonts that Unidrv supports are listed in the following table:

Font Name | Font File
"Albertus Medium" | ALBERTR.UFM
"Albertus Extra Bold" | ALBERTX.UFM
"Antique Olive" | AOLIVEB.UFM AOLIVEI.UFM AOLIVER.UFM
"Arial" | ARIALB.UFM ARIALI.UFM ARIALJ.UFM ARIALR.UFM
"ITC Benguiat" | BENGUATB.UFM BENGUATI.UFM BENGUATJ.UFM BENGUATR.UFM
"ITC Bookman Demi" | BOOKMANB.UFM BOOKMANJ.UFM
"ITC Bookman Light" | BOOKMANI.UFM BOOKMANR.UFM
"Brougham" | BROGHAMB.UFM BROGHAMI.UFM BROGHAMJ.UFM BROGHAMR.UFM
"CG Omega" | CGOMEGAB.UFM CGOMEGAI.UFM CGOMEGAJ.UFM CGOMEGAR.UFM
"CG Times" | CGTIMESB.UFM CGTIMESI.UFM CGTIMESJ.UFM CGTIMESR.UFM
"Clarendon Condensed" | CLARCD.UFM
"Coronet" | CORONETR.UFM
"Courier" | COURIERB.UFM COURIERI.UFM COURIERJ.UFM COURIERR.UFM
"Garamond" | GARMONDB.UFM GARMONDI.UFM GARMONDJ.UFM GARMONDR.UFM
"Letter Gothic" | LETGOTHB.UFM LETGOTHI.UFM LETGOTHR.UFM
"Marigold" | MARGOLDR.UFM
"Times New Roman" | TIMESNRB.UFM TIMESNRI.UFM TIMESNRJ.UFM TIMESNRR.UFM
"Univers Condensed" | UNIVERCB.UFM UNIVERCI.UFM UNIVERCJ.UFM UNIVERCR.UFM
"Univers" | Universa.UFM UNIVERSB.UFM Universc.UFM Universd.UFM Universe.UFM UNIVERSI.UFM UNIVERSJ.UFM UNIVERSR.UFM
"W Dingbats" | WDINGBAT.UFM
"Wingdings" | WINGDING.UFM
"Symbol" | SYMBOL.UFM


Installing a PCL XL Minidriver

In Windows XP and later, ntprint.inf has the following [PCLXL.OEM] section:

[PCLXL.OEM]
CopyFiles=PCLXL,@PCL5ERES.DLL

The INF CopyFiles directive copies all of the files listed in the [PCLXL] section, as well as pcl5eres.dll, to the default destination directory. The [PCLXL] section also appears in ntprint.inf and lists the files to be copied.

[PCLXL]
PCLXL.DLL
PCLXL.GPD
P6FONT.GPD
PJL.GPD
P6DISP.GPD

Pclxl.dll contains the PCL XL UFMs and various resource strings. The other GPDs listed in this section are the PCL XL (PCL-6) support files.

To install a PCL XL printer minidriver, an OEM should add a section similar to the following in the printer-specific INF. This INF loads before ntprint.inf does.

[P6SAMPLE.GPD]
CopyFiles=@P6SAMPLE.GPD
DataSection=UNIDRV_DATA
DataFile=P6SAMPLE.GPD
Include=NTPRINT.INF
Needs=UNIDRV.OEM,TTFSUB.OEM,PCLXL.OEM

In the preceding section, the CopyFiles directive in the first line copies the OEM's GPD file (called p6sample.gpd in this example). The entry associated with the DataSection directive in the second line (see Printer INF File Data Sections and Printer INF File Install Sections) refers to the [UNIDRV_DATA] section in ntprint.inf. The DataFile directive in the third line specifies that p6sample.gpd is the data file associated with this printer minidriver. The fourth line causes ntprint.inf to be included. The three entries in the Needs directive of the fifth line refer to the identically-named sections in ntprint.inf. This enables the INF file to gain access to the files that it loads in driver.cab.

For additional information on using the CopyFiles directive for printer installations, see Printer INF File CopyFiles Sections.


PCL XL Issues

  • Windows XP and later supports print optimization functionality on the Advanced tab of the printer property pages. If Print Optimizations are disabled, Unidrv prints PCL XL data in raster mode.
  • *MirrorRasterPage? is not supported in PCL XL mode.
  • PCL XL does not support switching between PCL XL and raster modes.
  • The GPD *TextHalftoneThreshold attribute name does not work on a PCL XL minidriver. Text in any resolution is grayscaled in PCL XL mode.


Pseudo-Vector Graphics Support

Devices that do not support true vector graphics can take advantage of the support that Unidrv provides for pseudo-vector graphics. When you use this feature, Unidrv downloads solid black rectangles and horizontal and vertical lines directly to a non-vector graphics device, reducing the overhead of rendering these figures on a raster surface. This also reduces the size of the output data, which can improve printer throughput for devices that do not handle raster data efficiently.

To benefit from this feature, a minidriver for a non-vector graphics device needs only to support the CmdRectBlackFill command. This functionality is disabled when the Print Optimization feature in the Advanced tab of the printer property pages is turned off.

The pseudo-vector graphics feature intercepts calls to DrvBitBlt, DrvStrokePath, and DrvLineTo, to determine whether a solid black rectangle or a vertical or horizontal line is to be drawn. When Unidrv recognizes the figure to be drawn as a valid rectangle (one that is solid black, has no complex clipping, and does not use a ROP using the current destination bits), it is stored in a rectangle array instead of being drawn on the surface.

The most difficult aspect of the pseudo-vector graphics feature is avoiding z-order problems caused by objects that must be drawn on top of previously-drawn objects. The objects on top might need to erase or overwrite part of a black rectangle. If the black rectangle has already been downloaded to the device, an object drawn later on the system surface may not be drawn correctly.

The solution to this problem is to temporarily store a valid rectangle, rather than drawing it immediately on the surface. When a new object is to be drawn on the surface, Unidrv checks it to see whether the object overlaps with any black rectangle. If so, the overlapped portion of the black rectangle is drawn on the surface first, before the new object is drawn, thereby maintaining the correct z-ordering. Drawing the rectangle first also takes into account the possibility that the new object to be drawn might have a ROP associated with it, including one that interacts with the destination.

In addition, it is possible that the new object to be drawn contains complex clipping so that the resulting figure is no longer a rectangle. When the band or page rendering is complete, any remaining black rectangles can be directly downloaded to the device without causing any z-order problems. Unidrv maintains a list of up to 256 rectangles per band, concatenating BitBlt rectangles where possible.

Pseudo-Vector Graphics Issues

The pseudo-vector graphics feature may alter the z-ordering in certain situations, particularly when text is downloaded directly to the device and subsequent objects with complex clipping must interact with that text.


Installing a Unidrv Minidriver

Installation of a Unidrv minidriver requires a printer INF file that identifies the minidriver's files. If a printer model is not supported by Microsoft's printer INF file, ntprint.inf, a vendor-supplied INF file is required. The INF file should reference printer INF file data sections and printer INF file install sections, which are defined in ntprint.inf. For a minidriver named abc100, the following INF file entries are typically needed, if the printer is bi-directional, supports TrueType font substitution, and uses a single resource DLL:

[Manufacturer]
"ABC Printers"

[ABC Printers]
"ABC Printer 100" = ABC100.GPD, ABC_Printer_100

[ABC100.GPD]
CopyFiles=@ABCres.dll,@ABC100.gpd  ;Resource DLL and GPD file
DataSection=UNIDRV_BIDI_DATA       ;Unidrv Data Section
DataFile=ABC100.gpd
Include=NTPRINT.INF                ;Include NTPRINT.INF.
Needs=TTFSUB.OEM,UNIDRV_BIDI.OEM   ;Install TrueType subs, Unidrv,
                                   ;    and PJL language monitor.

If you are providing a user interface plug-in or a rendering plug-in, you need to include the names of these components within your INF file. For information about installing customized code, see Installing Customized Driver Components.


Unidrv Printer Minidriver Versioning

See Specifying Printer Driver Version Numbers.


Microsoft PostScript Printer Driver

The PostScript Printer Driver (Pscript) is the Microsoft corporation standard printer driver for PostScript printers. The following topics describe Pscript:

Pscript Capabilities

Pscript Components

Pscript Minidrivers

Pscript User Interface

Pscript Renderer


Pscript Capabilities

The PostScript Printer Driver (Pscript) provides the following capabilities:

  • Support for all PostScript printers, using printer-specific PPD-based Pscript minidrivers that describe each printer's characteristics.
  • A Pscript user interface, based on the TreeView control and property sheets, that is consistent for all printers, but is also modifiable for each printer's unique options.
  • A single Pscript renderer that, along with the GDI graphics engine, converts Microsoft® Win32® GDI calls from applications into printer commands that can be sent to the print spooler.
  • Support for version 3.1 of the Document Structuring Convention, described in the PostScript Language Reference Manual published by Adobe Systems, Inc.
  • Support for printers that provide PostScript Level 1, Level 2, or Level 3 features.
  • The following types of support for fonts:
    • Incremental downloading of OpenType fonts as PostScript Type 1 or Type 2 fonts.
    • Incremental downloading of TrueType fonts as PostScript Type 1, Type 3, Type 32, Type 42, or CID-based Type 42 fonts.
    • Incremental downloading of host-resident raster fonts as PostScript Type 3 or Type 32 fonts.
    • Full downloading of host-resident PostScript Type 1 fonts.
    • Printer-resident PostScript Type 1, Type 2, and CID fonts.
    • Font substitution per glyph, for glyphs that exist in the printer's character set.
  • Support for ICM 2.0, and allowing image color management to be performed on the host system or by printer hardware.


Pscript Components

Pscript components consist of DLLs, plus text and binary data files, as illustrated in the following diagram:

Pscript Components

Components in the diagram include:

Application
A user application, such as a word processor, that provides users with printing capabilities.
gdi32.dll
User-mode DLL that exports Win32 GDI functions.
Kernel-Mode Graphics Engine
NT-based-operating system Executive code that implements GDI functionality.
Minidriver Text Files
Text-based Pscript minidrivers, created using PPD files.
Binary Data Files
Temporary files (with a .bpd extension) that Pscript creates after parsing information contained in minidriver text files.
ps5ui.dll
Pscript user interface DLL, providing common UI code for all Pscript-supported printers.
User Interface Plug-In
Optional, printer-specific, user interface plug-in.
compstui.dll
CPSUI user interface for printers.
pscript5.dll
Pscript renderer, which handles text output and renders images, then sends the text and image data to the print spooler.
Rendering Plug-In
Optional, printer-specific, rendering plug-in.


Pscript Minidrivers

Pscript minidrivers are created from .ppd files and .ntf files.

PPD Files

Text-based PostScript Printer Description files (.ppd files) describe a PostScript printer's characteristics. The Pscript driver for Microsoft® Windows® 2000 and later supports .ppd files that are compatible with version 4.3 of the PPD specification from Adobe Systems, Inc. Pscript reads a printer's .ppd file and converts the text into a binary format, stored locally as a .bpd file that is regenerated every time the .ppd file changes.

NTF Files

Windows 2000 and later font files (.ntf files) are binary files used for describing the device fonts of printers supported by Pscript.

Microsoft provides a default .ntf file, named pscript.ntf, that contains descriptions of commonly encountered US device fonts. For East Asian printers, Microsoft also provides a default .ntf file, named pscrptfe.ntf, which contains descriptions of commonly encountered East Asian device fonts.

In addition, hardware vendors can supply device font descriptions for fonts not supported by pscript.ntf. These font descriptions can be created by converting AFM files to NTF files. Customized, printer model-specific .ntf files can be installed by listing them as dependent files in a printer INF file. For more information, see Installing a Pscript Minidriver.

Pscript searches for font metrics by first checking printer model-specific .ntf files, then checking pscript.ntf, and using the first font description found.


Converting AFM Files to NTF Files

For Windows® 2000 and later, Adobe Font Metrics (AFM) files must be converted to .ntf files. A command line tool for performing this conversion, named makentf.exe, is provided with this DDK.

To convert one or more .afm files, use the following command syntax:

makentf NTF_FileName.ntf AFM_FileNames [-v] [-o]

where NTF_FileName is the name of the .ntf file to be produced, and AFM_FileNames is a set of one or more AFM files to be converted.

The following command line options are supported:

-v
Verbose. This option creates a command output stream that contains a textual display of the NTF file structures being generated.
-o
Omit standard Western glyph sets. By default, makentf includes the standard Western glyph sets when generating an .ntf file. If you are creating multiple .ntf files, you only need to include the Western glyph sets in one of the files, as long as all the files will be used together. For example, suppose you are creating one .ntf file that contains Roman font metrics and another that contains Japanese font metrics. You might use the following commands:
makentf roman.ntf roman1.afm roman2.afm roman3.afm
makentf -o jpn.ntf jpn1.afm jpn2.afm jpn3.afm

If these files are used together, Western glyph set information will always be obtained from roman.ntf, so duplicating the information in jpn.ntf is not needed and consumes extra space. On the other hand, if jpn.ntf will be used alone, -o must not be specified.

A second command syntax is also supported, as follows:

makentf filename

where filename is the name of a file to receive output text. This syntax causes makentf to create a file containing lists of PostScript glyph names and Unicode values for each code page known to makentf.

An additional file, PSFamily.dat, is provided with this DDK and must reside in the same directory that contains makentf.exe. This is a text file that supplies makentf with the display and family names for each font.

Before a standard .afm file can be converted, you must add a line similar to the following:

Comment UniqueID IDnumber

where IDnumber represents the font's unique identifier, issued by the font vendor.

When it is processing an East Asian font's .afm file, makentf requires some additional .map and .ps files, which must reside in the same directory as that of makentf and PSFamily.dat. The additional .map and .ps files, which are provided in the DDK (together with PSFamily.dat), are necessary to create a mapping table from Unicode code to CID for the font. For more information, see Converting East Asian AFM Files to NTF Files.

An .afm file that will be converted to an .ntf file can contain the FontBBox2 keyword. This keyword's arguments are similar to those for FontBBox (see the Adobe Font Metrics File Format Specification, from Adobe Systems, Inc.), except that FontBBox2 arguments describe the bounding box for glyphs used in a specific character set (such as 90ms), while FontBBox arguments describe the bounding box for the union of all characters described in the .afm file. If FontBBox2 is not found, the values specified for FontBBox are used for the bounding box.


Converting East Asian AFM Files to NTF Files

To process an East Asian font's .afm file, makentf (discussed in Converting AFM Files to NTF Files) requires .map and .ps files to create a mapping table from Unicode to CID (character ID) for the font.

The East Asian .afm file has the CID description and metrics for each glyph contained in the font. The .map file lists the Unicode codes and corresponding character codes for the font's character set. The .ps file contains a list of Unicode codes and the corresponding CIDs for the font's character set.

Starting with an East Asian .afm file, makentf determines the character set. Based on the character set, makentf finds the appropriate .map and .ps files. From the .map file, makentf lists the Unicode codes that can be used in the font. From the Unicode code list and the .ps file, makentf then creates a Unicode-to-CID mapping table for the font. Currently, the .afm file is used to verify that each CID (glyph) is actually contained in the font. If the CID is found in the .afm file, a mapping entry from the Unicode code to the CID is created in the mapping table. If the CID is not found, the mapping entry is not created.

The .map and .ps files needed to create an .ntf file for Chinese Simplified, Chinese Traditional, Japanese, and Korean are shown in the following lists. Place these files and your .afm files in the same directory.

Chinese Simplified

  • ucs2gbk.map
  • unigbh.ps
  • unigbv.ps

Chinese Traditional

  • ucs2bg5.map
  • unicnsh.ps
  • unicnsv.ps

Japanese

  • ucs283h.map
  • ucs283v.map
  • ucs2msj.map
  • uni83h.ps
  • uni83v.ps
  • unijish.ps
  • unijisv.ps

Korean

  • ucs2jhb.map
  • ucs2uhc.map
  • uniksh.ps
  • uniksv.ps


Installing a Pscript Minidriver

Installation of a Pscript minidriver requires a printer .inf file that identifies the minidriver's files. If a printer model is not supported by Microsoft's printer .inf file, ntprint.inf, a vendor-supplied .inf file is required. The .inf file should reference printer .inf file data sections and printer .inf file install sections, which are defined in ntprint.inf. For a minidriver named abc100, the following .inf file entries are typically needed:

[Manufacturer]
"ABC Printers"

[ABC Printers]
"ABC Printer 100 PS" = ABC100.PPD, ABC_Printer_100_PS

[ABC100.PPD]
CopyFiles=@ABC100.ppd       ; PPD file.
DataSection=PSCRIPT_DATA    ; PSCRIPT Data Section
DataFile=ABC100.ppd
Include=NTPRINT.INF         ; Include NTPRINT.INF.
Needs=PSCRIPT.OEM           ; Install PSCRIPT.

If you are providing a user interface plug-in or a rendering plug-in, you need to include the names of these components within your .inf file. For information about installing customized code, see Installing Customized Driver Components.


Pscript Printer Minidriver Versioning

See Specifying Printer Driver Version Numbers.


AddEuro

The Euro symbol, as shown in the following figure, is the currency symbol for the basic monetary unit used in countries/regions of the European Union.

The AddEuro feature adds this symbol to the printer's device font. When AddEuro is enabled, a Euro symbol that appears on a display device will also be printed on paper when the document is sent to a printer. If this feature is unavailable or disabled, a user who selects an unaliased device font will be able to see a Euro symbol on the screen, but will see a large circular dot on paper. With this feature enabled, a user can print the Euro symbol, whether or not it is available in the printer's device font.

AddEuro uses a private PPD keyword, *ADHasEuro, to allow printer manufacturers to set the best defaults.

Keyword and Value | Meaning
*ADHasEuro: True | The printer already has a built-in Euro symbol that does not need to be downloaded. With this value, AddEuro is disabled by default.
*ADHasEuro: False | The printer does not have a built-in Euro symbol; if called for by an application, this symbol should be downloaded. With this value, AddEuro is enabled by default, regardless of PostScript version.

If the *ADHasEuro keyword does not appear, the AddEuro feature is enabled by default for printers with PostScript version < 3011, and disabled by default for versions ≥ 3011.


TrueGray

The TrueGray feature checks RGB colors in text and vector graphics, but not in bitmaps. For colors that are gray (that is, colors whose red, green, and blue values are equal), the TrueGray feature translates the colors from the RGB color space to the color printer's gray color space before printing them. This feature is not available for monochrome printers.

The TrueGray feature uses a private PPD keyword, *ADTrueGray, to allow PScript mindriver writers to enable or disable this feature.

Keyword and Value | Meaning
*ADTrueGray: True | The TrueGray feature is enabled by default for this printer.
*ADTrueGray: False | The TrueGray feature is disabled by default for this printer.

When the user interface indicates that the TrueGray feature is enabled, the driver detects RGB colors for which R = G = B, and one of the following conditions is true:

  • When ICM processing is off
  • When ICM processing is carried out on the host and the destination color profile is RGB data and the converted color is R' = G' = B' (that is, different from the original color)
  • When ICM processing would normally be done using CIE-based color spaces and the original color is R = G = B

No attempt is made to detect gray in CMYK colors. This is the color space normally used when ICM color processing is carried out on the host.


Pscript User Interface

The Pscript user interface employs CPSUI to create the following property sheet pages:

  • The Device Settings page for the printer property sheet, which is displayed when a user selects the Properties menu item from the printer folder or a printer window. The page lists printer-specific configuration settings.
  • The Layout, Paper/Quality, and Advanced pages for the document property sheet, which are displayed when a user selects Printing Preferences menu item from the printer folder or a printer window, or when an application calls the PrinterProperties or DocumentProperties functions (described in the Platform SDK documentation). The pages list document-specific configuration settings.

These property sheet pages contain the printer features and printer options specified by a printer's Pscript minidriver. They also allow the user to modify option values.

The Pscript user interface is implemented as a user-mode printer interface DLL. Code within this DLL, in conjunction with CPSUI, specifies the contents of the property sheet pages. The DLL enforces constraints on which printer options can be combined, based on information in the minidriver. It also ensures that users do not select options not installed on the printer.

You can modify the Pscript-supplied property sheet pages by providing a user interface plug-in, which is described in the section entitled Customizing Microsoft's Printer Drivers.


Pscript Renderer

The Pscript renderer is implemented as a printer graphics DLL and thus exports functions defined by the Microsoft Device Driver Interface (DDI) for graphics drivers. When an application calls Graphics Device Interface (GDI) functions to send text and images to a printer device, the kernel-mode graphics engine calls the renderer's graphics DDI functions. These graphics DDI functions assist GDI in drawing a print job's page images.

The renderer is also responsible for sending text rendered image data, along with printer command sequences, to the print spooler, which then directs the data stream and commands to printer hardware.

You can modify Pscript's rendering operations by providing a rendering plug-in, which is described in the section entitled Customizing Microsoft's Printer Drivers.


PPD-Specific Interface

The IPrintCoreUI2 COM interface supports nine methods that a user interface plug-in can call to access information in PPD files. Six of these methods are supported in the IPrintCorePS2 COM interface. This section describes the PPD-specific behavior of these methods.

IPrintCoreUI2 Interface PPD Methods

IPrintCoreUI2::EnumConstrainedOptions

IPrintCoreUI2::EnumFeatures

IPrintCoreUI2::EnumOptions

IPrintCoreUI2::GetOptions

IPrintCoreUI2::GetFeatureAttribute

IPrintCoreUI2::GetGlobalAttribute

IPrintCoreUI2::GetOptionAttribute

IPrintCoreUI2::SetOptions

IPrintCoreUI2::WhyConstrained

IPrintCorePS2 Interface PPD Methods

IPrintCorePS2::EnumFeatures

IPrintCorePS2::EnumOptions

IPrintCorePS2::GetOptions

IPrintCorePS2::GetFeatureAttribute

IPrintCorePS2::GetGlobalAttribute

IPrintCorePS2::GetOptionAttribute

Throughout this section, a reference to any method that is a member of both interfaces applies to both methods. For example, a reference to GetOptions applies to IPrintCoreUI2::GetOptions as well as to IPrintCorePS2::GetOptions.

PPD Feature Availability

Note that in this section, the phrase "PPD feature is not currently available" means that either the printer does not support the feature, or the feature's non-None/False options are constrained by current installable option settings.

For example, "Duplex feature is not currently available" means either the PPD does not specify the *Duplex feature keyword, or the *Duplex feature keyword's non-None options are currently constrained by the fact that the Duplex Unit is not installed.


Using GetOptions and SetOptions

GetOptions can be called to retrieve the driver's current setting for features whose keywords are listed in the buffer pointed to by the pmszFeaturesRequested input parameter.

For example, in a call to GetOptions, suppose that the pmszFeaturesRequested input buffer contains this string (in MULTI_SZ format):

"PageSize\0Duplex\0Resolution\0\0"

After the GetOptions method returns, the output pmszFeatureOptionBuf could contain the following string (also in MULTI_SZ format):

"PageSize\0Letter\0Duplex\0DuplexTumble\0Resolution\0300dpi\0\0"

This example shows that GetOptions retrieved the option keywords for PageSize (Letter), Duplex (DuplexTumble), and Resolution (300dpi).

SetOptions can be called to change the driver's current setting based on the feature/option keyword pairs in the pmszFeatureOptionBuf input buffer.

There are two categories of features that are supported:

PPD Features

Driver Features


PPD Features

PPD features are defined in the PPD file within *OpenUI/*CloseUI structure keyword pairs, and in certain PPD keywords that are treated similarly by the Pscript driver. Although EnumFeatures lists the *LeadingEdge and *UseHWMargins keywords, they are not defined within PPD *OpenUI/*CloseUI structure keyword pairs. Consequently, the GetOptions and SetOptions methods ignore these keywords if they appear in the feature list. The PPD feature/option keywords are case sensitive.

SetOptions handles certain PPD features in a special way:

  • If the printer's PPD file includes the *OutputOrder feature keyword and SetOptions is called to change the option selection for this feature, then the %PageOrder driver feature setting will be changed to match the new output order. This is done in order to prevent the spooler from performing unnecessary page order simulation.
  • If the printer's PPD file includes the *OutputBin feature keyword and SetOptions is called to change the option selection for this feature, and the change causes the current setting of the %PageOrder driver feature to be the opposite of the printer's page ordering, and %MetafileSpooling is "False", then %MetafileSpooling will be reset to "True".
  • When spooler EMF spooling is enabled, and Collate is set to "True" (this can be set either directly in the public portion of the DEVMODE structure or by calling SetOptions on the PPD's *Collate feature keyword), but the Collate feature is not currently available, and %MetafileSpooling is "False", then %MetafileSpooling will be reset to "True". This is done when all requested settings in the SetOptions call are applied.
  • If Duplex is set to simplex (this can be set either directly in the public portion of the DEVMODE structure or by calling SetOptions on the PPD's *Duplex feature keyword), but %PagePerSheet is set to "Booklet", then %PagePerSheet will be changed to "2". This is done when all requested settings in the SetOptions call are applied.


Driver Features

Driver features are non-PPD features that are synthesized by the driver (for example, the %OutputFormat feature). To avoid name conflicts with PPD feature keywords, all driver feature keyword names are preceded by a "%" character. Driver feature/option keywords are also case sensitive.

To obtain a list of all driver feature keywords that the driver supports, a plug-in can call EnumFeatures, which will return the feature keyword list containing both driver features and PPD features. The plug-in can then search for feature keyword names that begin with the "%" prefix to get the driver feature list.

The following table lists the currently supported driver features. Each row in the table lists a driver feature keyword, shows the supported options, states whether the feature's options can be enumerated in a call to EnumOptions, and provides a brief description.

Driver Feature | Supported Options | EnumOptions? | Description and Comments
%AddEuro | "True" "False" | Yes | Add the Euro symbol to device fonts. This feature is supported only for Level 2+ printers. For Level 1 printers, SetOptions ignores this feature, and GetOptions always returns "False". Printer-sticky
%CtrlDAfter | "True" "False" | Yes | Send Ctrl-D after each job. Printer-sticky
%CtrlDBefore | "True" "False" | Yes | Send Ctrl-D before each job. Printer-sticky
%CustomPageSize | See Note (1) below for more information. | No | Specify PostScript custom page size parameters. Document-sticky See Note (2) below.
%GraphicsTrueGray | "True" "False" | Yes | Convert gray graphics to PostScript gray. Printer-sticky
%JobTimeout | A NULL-terminated ANSI string containing decimal digit characters that represents the unsigned integer number of seconds for the timeout, in the range 0 through 2,147,483,647. For SetOptions, extra tab or space characters before or after the decimal digits are allowed, but a sign symbol is not allowed. | No | Specify the job timeout value. Printer-sticky
%MaxFontSizeAsBitmap | A NULL-terminated ANSI string containing decimal digit characters that represents the unsigned integer number of pixels, in the range 0 through 32,767. For SetOptions, extra tab or space characters before or after the decimal digits are allowed, but a sign symbol is not allowed. | No | Specify the maximum font size to download as a bitmap. Printer-sticky
%MetafileSpooling | "True" "False" | Yes | Enable/disable advanced printing features. Document-sticky See Note (3) below.
%MinFontSizeAsOutline | A NULL-terminated ANSI string containing decimal digit characters that represents the unsigned integer number of pixels, in the range 0 through 32,767. For SetOptions, extra tab or space characters before or after the decimal digits are allowed, but a sign symbol is not allowed. | No | Specify the minimum font size to download as outline. Printer-sticky
%Mirroring | "True" "False" | Yes | Mirror output by reversing the horizontal coordinates. Document-sticky
%Negative | "True" "False" | Yes | Produce negative output by reversing values for black and white. This feature is supported only for black and white printers. For color printers, SetOptions ignores this feature, and GetOptions always returns "False". Document-sticky
%Orientation | "Portrait", "Landscape", "RotatedLandscape" | Yes | Specify the output orientation. Document-sticky
%OutputFormat | "Speed", "Portability", "EPS", "Archive" | Yes | Specify the PostScript output format. Document-sticky See Note (6) below.
%OutputProtocol | "ASCII", "BCP", "TBCP", "Binary" | Yes | Specify the protocol the printer will use for print jobs. PostScript printers are assumed to support "ASCII" and "Binary", so these options are always available. The "BCP" and "TBCP" options are available only if they are supported. (To find this out, check the global attribute "Protocols". Printer-sticky
%OutputPSLevel | "1", "2", "3" | No | Specify which PostScript language level to use for the print job. The setting will never be greater than the value specified in the "LanguageLevel" global attribute. Document-sticky
%PageOrder | "FrontToBack" "BackToFront" | Yes | Specify the order in which pages will be printed. Document-sticky See Note (4) below.
%PagePerSheet | "1", "2", "4", "6", "9", "16", "Booklet" | Yes | Specify the number of logical pages per physical sheet. This feature is also known as "N-up" printing. Document-sticky See Note (5) below.
%PSErrorHandler | "True" "False" | Yes | Send PostScript error handler. Document-sticky
%PSMemory | A NULL-terminated ANSI string containing decimal digit characters that represents the unsigned integer number of kilobytes of PostScript memory, in the range 0 through 2,147,483,647. For SetOptions, extra tab or space characters before or after the decimal digits are allowed, but a sign symbol is not allowed. | No | Specify the amount of available PostScript virtual memory. The core driver requires a certain amount of available PostScript virtual memory for its processing. If %PSMemory is set below this minimum, the minimum value will be used as the new value. Currently the minimum value is 172 KB for Level 1 printers and 249 KB for Level 2+ printers. Printer-sticky
%TextTrueGray | "True" "False" | Yes | Convert gray text to PostScript gray. Printer-sticky
%TTDownloadFormat | "Automatic", "Outline", "Bitmap", "NativeTrueType" | Yes | Specify TrueType font downloading format. "NativeTrueType" is supported only when the "TTRasterizer" global attribute indicates support for "Type42". Document-sticky
%WaitTimeout | A NULL-terminated ANSI string containing decimal digit characters that represents the unsigned integer number of seconds for the timeout, in the range 0 through 2,147,483,647. For SetOptions, extra tab or space characters before or after the decimal digits are allowed, but a sign symbol is not allowed. | No | Specify wait timeout value. Printer-sticky

Notes on Driver Feature Keywords

  1. The %CustomPageSize driver feature has five option values: x, y, WidthOffset, HeightOffset, and FeedDirection. Please refer to section 5.16 of the PostScript Printer Description File Format Specification, Version 4.3, for a detailed explanation of these parameters.

    A %CustomPageSize entry contains the %CustomPageSize keyword, together with values for the x, y, WidthOffset, HeightOffset, and FeedDirection options. The first item is the %CustomPageSize keyword, followed by a NULL character. The values for x, y, WidthOffset, and HeightOffset follow this keyword, and appear as substrings of unsigned decimal digits, each representing the number of PostScript points for the corresponding option value. Each of these numeric values is followed by one or more space or tab characters. The final item in the string is the value for FeedDirection, which is terminated by a NULL character. The options for FeedDirection are "LongEdge", "ShortEdge" (corresponding to orientations 0 and 1), and "LongEdgeFlip", "ShortEdgeFlip" (corresponding to orientations 2 and 3). Check the *LeadingEdge PPD feature keyword for supported feed directions.

    For GetOptions, the output buffer pointed to by pmszFeatureOptionBuf is as described in the previous paragraph. In the following example, the value for x is 612, the value for y is 792, the values for WidthOffset and HeightOffset are both 0, and the value for FeedDirection is "ShortEdge".

    "%CustomPageSize\0612 792 0 0 ShortEdge\0"

    For SetOptions, extra tab or space characters before or after the decimal digits are allowed, but a sign symbol is not allowed. Otherwise, the input buffer pointed to by pmszFeatureOptionBuf should be constructed as described above.

  2. The %CustomPageSize driver feature is supported only if all three of the following conditions are met:
    1. The PPD file contains the *CustomPageSize feature.
    2. The *PPD-Adobe keyword has a value greater than or equal to 4.3 OR *UseHWMargin: False is specified to indicate a roll-fed device.
    3. The *PageSize PPD feature's currently selected option is CustomPageSize.
  3. On Windows NT 4.0, the %MetafileSpooling feature is always supported. On Windows 2000 and later operating system versions, this feature is supported only when spooler EMF spooling is enabled.

    When supported, setting this feature's option to "False" causes changes to the following EMF-related features:

    1. On Windows 2000 and later operating system releases, if %PagePerSheet is "Booklet", it will be changed to "1".
    2. If Collate is set to "True" (which can be set either directly in the public portion of the DEVMODE structure or by calling SetOptions on the *Collate PPD feature), but the Collate feature is not currently available, Collate will be set to "False".
    3. On Windows 2000 and later operating system releases, if %PageOrder is the opposite of the printer's current output order setting, %PageOrder will be reversed to the printer's value.
  4. On Windows NT 4.0, the %PageOrder driver feature is not supported. On Windows 2000 and later operating system releases, this feature is supported only when spooler EMF spooling is enabled.

    When it is supported, setting this feature can cause the following to occur:

    1. If the printer's PPD file includes the *OutputOrder feature keyword, then its option selection will be changed to match the output order of the new setting for the %PageOrder feature. This is done to prevent the spooler from performing unnecessary page order simulation.
    2. If the printer's PPD file does not include the *OutputOrder feature, and the new setting for the %PageOrder driver feature is the opposite of the printer's current output order setting, and the %MetafileSpooling driver feature is "False", then %MetafileSpooling will be reset to "True".
  5. On Windows NT 4.0, the "Booklet" option is not supported for the %PagePerSheet driver feature. On Windows 2000 and later operating system releases, the "Booklet" option is supported only when spooler EMF spooling is enabled and the Duplex feature is available.

    When the "Booklet" option is supported, setting the %PagePerSheet driver feature to "Booklet" can cause the following changes:

    1. If the %MetafileSpooling driver feature is "False", it will be reset to "True".
    2. If the *Duplex PPD feature is set to None, the *Duplex feature will be reset to the first non-Simplex option defined in the PPD file.
  6. Except for "EPS" (Encapsulated PostScript), the formats specified in the %OutputFormat driver feature are categorized according to the following two characteristics:
    1. Is the output PostScript code independent of page order?
    2. Does the output PostScript code contain device control commands, (which usually use the setpagedevice operator)?
 | Page Order Independent | setpagedevice
Archive | Yes | No
Portability | Yes | Yes
Speed | No | Yes

When GetOptions is called on driver feature keywords, if a requested feature keyword is not recognized, or if the feature keyword is recognized but not supported in the current document-sticky or printer-sticky mode (see Replacing Driver-Supplied Property Sheet Pages), the feature will simply be ignored and the output buffer will not contain its feature/option keyword pair.

For example, suppose the GetOptions method is called, and the pmszFeaturesRequested input buffer contains the following string (in MULTI_SZ format):

"Resolution\0%CustomPageSize\0Unknown_Name\0%Orientation\0\0"

After GetOption returns, the pmszFeatureOptionBuf output buffer could contain this string (also in MULTI_SZ format):

"Resolution\0300dpi\0%CustomPageSize\0612 792 0 0 ShortEdge\0%Orientation\0RotatedLandscape\0\0"

Notice that the Unknown_Name feature (which does not exist) listed in the first string does not appear in the second string, since it was not recognized by the Pscript driver. The other features, Resolution, %CustomPageSize, and %Orientation, appear in the output string, together with their current options, which are "300dpi", "612 792 0 0 ShortEdge", and "RotatedLandscape", respectively. See Driver Features for an explanation of the %CustomPageSize options.

When SetOptions is called on driver feature keywords, if a requested feature keyword or its option keyword in the input buffer pointed to by pmszFeatureOptionBuf is not recognized, or the feature is recognized but not supported in the current document-sticky or printer-sticky mode (see Replacing Driver-Supplied Property Sheet Pages), or both the feature keyword and its option keyword are recognized but the option keyword is invalid for that feature (for example, trying to set %TTDownloadFormat to "NativeTrueType" on a printer that does not support Type42 TTRasterizer), then that feature/option pair will be ignored and the current option for that feature will continue to be in effect.

The order of feature/option keyword pairs in the buffer pointed to by pmszFeatureOptionBuf can affect the result of the SetOptions call. For example, the following two different orders have different results.

pmszFeatureOptionBuf | %PagePerSheet | %MetafileSpooling
"%MetafileSpooling\0False\0%PagePerSheet\0Booklet\0\0" | "Booklet" | "True"
"%PagePerSheet\0Booklet\0%MetafileSpooling\0False\0\0" | "1" | "False"

For an explanation of why these results occur, see Note 3 on %MetafileSpooling, above.


Using GetGlobalAttribute

All of the global attribute names are the same as the keyword names defined in PostScript Printer Description File Format Specification, v4.3. Refer to this specification for their semantics.

In the following table, the pdwDataType parameter takes values of the EATTRIBUTE_DATATYPE enumerated type.

Global Attribute Output Parameters
CenterRegistered *pdwDataType: kADT_BOOL

*pbData: TRUE or FALSE

*pcbNeeded: sizeof(BOOL)
ColorDevice *pdwDataType: kADT_BOOL

*pbData: TRUE or FALSE

*pcbNeeded: sizeof(BOOL)
Extensions *pdwDataType: kADT_ASCII

pbData: ASCII string (in MULTI_SZ format) containing registered values of extensionOption the printer supports.

*pcbNeeded: byte count of the ASCII string pointed to by pbData (including the last NULL character)

Note: "*FileSystem: True" is treated as if *Extensions had the "FileSystem" option. "FileSystem: False" is treated as if *Extensions did not have the "FileSystem" option.
FileVersion *pdwDataType: kADT_DWORD

*pbData: a DWORD whose high-order word contains the major version number, and whose low-order word contains the minor version number.

*pcbNeeded: sizeof(DWORD)
FreeVM *pdwDataType: kADT_DWORD

*pbData: value of *FreeVM

*pcbNeeded: sizeof(DWORD)
LandscapeOrientation *pdwDataType: kADT_ASCII

pbData: NULL-terminated ASCII string of either "Plus90" or "Minus90".

*pcbNeeded: byte count of the ASCII string pointed to by pbData (including the last NULL character)

Note: "Minus90" is returned only when the PPD contains "*LandscapeOrientation: Minus90". In all other cases, "Plus90" is returned.
LanguageEncoding *pdwDataType: kADT_ASCII

pbData: NULL-terminated ASCII string containing one of the following encodingOption values:

"ISOLatin1"

"Unicode"

"JIS83-RKSJ"

"None"

*pcbNeeded: byte count of the ASCII string pointed to by pbData (including the last NULL character)

Notes

"WindowsANSI" is treated the same as "ISOLatin1". Other encodingOption values are not supported.

If *LanguageEncoding is absent, *LanguageVersion is used to deduce the return value.
LanguageLevel *pdwDataType: kADT_DWORD

*pbData: PostScript language level supported by the printer

*pcbNeeded: sizeof(DWORD)
NickName *pdwDataType: kADT_UNICODE

pbData: NULL-terminated UNICODE string of the PPD's *ShortNickName value if *ShortNickName is present, or *NickName value if *ShortNickName is absent.

*pcbNeeded: byte count of the UNICODE string pointed to by pbData (including the last NULL character)
PPD-Adobe *pdwDataType: kADT_DWORD

*pbData: a DWORD whose high-order word contains the major version number, and whose low-order word contains the minor version number.

*pcbNeeded: sizeof(DWORD)
PrintPSErrors *pdwDataType: kADT_BOOL

*pbData: TRUE or FALSE

*pcbNeeded: sizeof(BOOL)

Note: If *PrintPSErrors is absent, it is assumed to be TRUE.
Product *pdwDataType: kADT_BINARY

pbData: the *Product value

*pcbNeeded: byte count of output binary data

Note: only the first *Product entry is returned.
Protocols *pdwDataType: kADT_ASCII

pbData: ASCII string (in MULTI_SZ format) containing registered values of protocolOption the printer supports.

*pcbNeeded: byte count of the ASCII string pointed to by pbData (including the last NULL character)
PSVersion *pdwDataType: kADT_BINARY

pbData: the *PSVersion value

*pcbNeeded: byte count of output binary data

Note: only the first *PSVersion entry is returned.
SuggestedJobTimeout *pdwDataType: kADT_DWORD

*pbData: the *SuggestedJobTimeout value. If it is absent from the PPD, returns 0 by default.

*pcbNeeded: sizeof(DWORD)
SuggestedWaitTimeout *pdwDataType: kADT_DWORD

*pbData: the *SuggestedWaitTimeout value. If it is not present in the PPD, returns 300 by default.

*pcbNeeded: sizeof(DWORD)
Throughput *pdwDataType: kADT_DWORD

*pbData: the *Throughput value. If it is not present in the PPD, returns 0 by default.

*pcbNeeded: sizeof(DWORD)
TTRasterizer *pdwDataType: kADT_ASCII

pbData: a NULL-terminated ASCII string containing one of following rasterizerOption values:

"None"

"Accept68K"

"Type42"

"TrueImage"

*pcbNeeded: byte count of the ASCII string pointed to by pbData (including the last NULL character)

Note: if the *TTRasterizer entry is absent, "None" is returned.


Using EnumFeatures

A caller can use EnumFeatures to retrieve a keyword list that contains currently supported driver features and all PPD features, in addition to the following, which Pscript treats as if they were features defined within PPD *OpenUI/*CloseUI structure keywords:

*LeadingEdge

*UseHWMargins

Pscript handles certain features in a special way. If more than one of *Resolution, *SetResolution, and *JCLResolution keyword appear in a PPD, they are merged into one standard feature. After merging, the feature's keyword name will be "JCLResolution" if *JCLResolution appears first; otherwise it will be "Resolution".

Note Some driver features (such as %Mirroring) are always supported, while other driver features are supported only under certain conditions. For example, when spooler EMF spooling is disabled on Windows 2000 and later operating system releases, the %PageOrder feature will not be supported. These unsupported driver features will not appear in the output keyword list of EnumFeatures.

For driver features, the keyword prefix "%" is included in the output. For PPD features, the keyword prefix "*" is not included in the output.


Using EnumOptions

A caller can use EnumOptions to retrieve a keyword list of options for supported driver features and any PPD features. For PPD features, EnumOptions is always supported and it returns the options defined by PPD.

For driver features, EnumOptions is supported only for features that are currently supported and have a fixed set of options. For example: %AddEuro has two options: "True" and "False", and %PageOrder has two options "FrontToBack" and "BackToFront". EnumOptions is supported for %AddEuro (if the Language level is 2 and above), as is %PageOrder (if spooler EMF spooling is enabled). But features such as %CustomPageSize, %PSMemory, and others have an unlimited number of possible options, which means that EnumOptions is not supported for them.

For driver features that are not currently supported, or for supported driver features that are not enumerable via EnumOptions, EnumOptions returns E_NOTIMPL.

Also, some options of a driver feature may not be supported under certain conditions. For example, if spooler EMF spooling is disabled on Windows 2000 and later operating system releases, then the "Booklet" option is not supported for the %PagePerSheet feature. For another example, if the printer does not have a Type42 rasterizer, then "NativeTrueType" option is not supported for %TTDownloadFormat. These unsupported options will not appear in the output keyword list of EnumOptions.

Pscript handles the following feature keywords in a special way:

  • The *CustomPageSize feature keyword is converted into an option of the *PageSize feature keyword, with "CustomPageSize" being the option keyword. Call GetOptionAttribute to obtain its PPD parameters.
  • The *ManualFeed True entry is converted into an option of the *InputSlot feature keyword, with "ManualFeed" being the option keyword name.
  • For the *InputSlot feature keyword, Pscript always adds a driver-generated option with option keyword name "*UseFormTrayTable" as the first option (the "*" prefix is used in the option keyword name to avoid possible name conflict with PPD-defined options), which is followed by options defined in the PPD. If the "*UseFormTrayTable" option is selected, Pscript will use the form-to-tray assignment table to automatically select the paper tray that supports the selected paper size.


Using GetFeatureAttribute

This function is supported only for PPD features. If a certain attribute is not available, GetFeatureAttribute returns E_INVALIDARG.

In the following table, the pdwDataType parameter takes values of the EATTRIBUTE_DATATYPE enumerated type.

Feature Attribute Output Parameters
DisplayName *pdwDataType: kADT_UNICODE

pbData: NULL terminated UNICODE string of the feature keyword name's translation string

*pcbNeeded: byte count of the UNICODE string pointed to by pbData (including the NULL terminator)

This feature attribute is available to any PPD feature EnumFeatures can return.
DefaultOption *pdwDataType: kADT_ASCII

pbData: NULL terminated ASCII string of the default option keyword name

*pcbNeeded: byte count of the ASCII string pointed to by pbData (including the NULL terminator)

This feature attribute is available to any PPD feature EnumFeatures can return.
OpenUIType *pdwDataType: kADT_ASCII

pbData: NULL terminated ASCII string containing one of following types: "PickOne", "PickMany", "Boolean".

*pcbNeeded: byte count of the ASCII string pointed to by pbData (including the NULL terminator)

This feature attribute is available to any PPD feature EnumFeatures can return.
OpenGroupType *pdwDataType: kADT_ASCII

pbData: For features defined within the PPD's "*OpenGroup: InstallableOptions … *CloseGroup: InstallableOptions" pair, a NULL terminated ASCII string of "InstallableOptions" will be returned. For other features, an empty ASCII string (which has only the NULL terminator) will be returned.

*pcbNeeded: byte count of the ASCII string pointed to by pbData (including the NULL terminator)

This feature attribute is available to any PPD feature that EnumFeatures can return.
OrderDependencyValue *pdwDataType: kADT_LONG

*pbData: the relative order specified by the PPD's *OrderDependency or *NonUIOrderDependency keyword for this feature. Notice that the first parameter of these keywords is a real number that is converted to a LONG and returned.

*pcbNeeded: sizeof(LONG)

This attribute is available only for a PPD feature that has an *OrderDependency or *NonUIOrderDependency entry in the PPD, and the entry omits optionKeyword.
OrderDependencySection *pdwDataType: kADT_ASCII

pbData: NULL terminated ASCII string containing one of following section names: "ExitServer", "Prolog", "DocumentSetup", "PageSetup", "JCLSetup", or "AnySetup".

*pcbNeeded: byte count of the ASCII string pointed to by pbData (including the NULL terminator)

This attribute is available only for a PPD feature that has an *OrderDependency or *NonUIOrderDependency entry in the PPD, and the entry omits optionKeyword.


Using GetOptionAttribute

This function is supported only for PPD features. If a certain attribute is not available, GetOptionAttribute returns E_INVALIDARG.

In the following table, the pdwDataType parameter takes values of the EATTRIBUTE_DATATYPE enumerated type.

Output Parameters for General Option Attributes

General Option Attribute Output Parameters
DisplayName *pdwDataType: kADT_UNICODE

pbData: NULL terminated UNICODE string of the option keyword name's translation string

*pcbNeeded: byte count of the UNICODE string pointed to by pbData (including the NULL terminator)

This option attribute is available to any option that EnumOptions can return on a PPD feature.
Invocation *pdwDataType: kADT_BINARY

pbData: byte array for the option's InvocationValue.

*pcbNeeded: byte count of the binary data pointed to by pbData

This option attribute is available to any option that EnumOptions can return on a PPD feature. If the option's InvocationValue is empty, the function will set pdwDataType as above, set *pcbNeeded = 0, and then return S_OK.
OrderDependencyValue *pdwDataType: kADT_LONG

*pbData: the relative order specified by the PPD's *OrderDependency or *NonUIOrderDependency keyword for this option. Notice that the first parameter of these keywords is a real number that is converted to a LONG and returned.

*pcbNeeded: sizeof(LONG)

This option attribute is available only for an option that has an *OrderDependency or *NonUIOrderDependency entry in the PPD, and the entry does not omit optionKeyword.
OrderDependencySection *pdwDataType: kADT_ASCII

pbData: NULL terminated ASCII string containing one of following section names: "ExitServer" "Prolog" "DocumentSetup" "PageSetup" "JCLSetup" "AnySetup".

*pcbNeeded: byte count of the ASCII string pointed to by pbData (including the NULL terminator)

This option attribute is available only for an option that has an *OrderDependency or *NonUIOrderDependency entry in the PPD, and the entry does not omit optionKeyword.

Output Parameters for Specific Option Attributes

In addition to the general option attributes described earlier, the option attributes listed in the following tables can have limitations on when they are available. Some attributes are available to all options of a specific PPD feature, while others are available only to specific options of their PPD feature. Any such limitations are listed for each option attribute.

Feature
Keyword 		Option Attribute Output Parameters
*InputSlot
RequiresPageRegion *pdwDataType: kADT_BOOL

*pbData: TRUE if *PageRegion invocation code must be sent with the *InputSlot invocation code, and FALSE otherwise. This is based on the PPD's *RequiresPageRegion keyword. If the keyword is omitted for this input slot option, TRUE is returned for this attribute.

*pcbNeeded: sizeof(BOOL)

This option attribute is available to any option of the "InputSlot" PPD feature, except for the driver-generated option "*UseFormTrayTable".
*OutputBin
OutputOrderReversed *pdwDataType: kADT_BOOL

*pbData: TRUE if the binOption's output order is "Reverse", and FALSE if the output order is "Normal". This is based on the PPD's *DefaultOutputOrder and *PageStackOrder keywords.

*pcbNeeded: sizeof(BOOL)

This option attribute is available to any option of the "OutputBin" PPD feature.
*PageSize
ImageableArea *pdwDataType: kADT_RECT

*pbData: a bounding box of the PageSize option's imageable area, as specified by the PPD's *ImageableArea keyword, is returned in a RECT structure (defined in the Platform SDK documentation), whose left and bottom members contain the llx and lly values, and whose right and top members contain the urx and ury values. All values are in microns. The PPD's llx, and lly values are rounded up to the nearest integer before being converted into microns. The PPD's urx and ury values are rounded down to the nearest integer before being converted into microns.

*pcbNeeded: sizeof(RECT)

This option attribute is available to any option of "PageSize" PPD feature, except the "CustomPageSize" option.
PaperDimension *pdwDataType: kADT_SIZE

*pbData: the physical dimension of the PageSize option, as specified by the PPD's *PaperDimension keyword, is returned in a SIZE structure (defined in the Platform SDK documentation), whose cx member contains the width value and whose cy member contains the height value. All values are in microns.

*pcbNeeded: sizeof(SIZE)

This option attribute is available to any option of the "PageSize" PPD feature, except the "CustomPageSize" option.
*PageSize: CustomPageSize
HWMargins *pdwDataType: kADT_RECT

*pbData: the four values specified by the PPD's *HWMargins keyword are returned in a RECT structure (defined in the Platform SDK documentation). All values are in microns.

*pcbNeeded: sizeof(RECT)

This option attribute is available only to the "CustomPageSize" option of the "PageSize" PPD feature.
MaxMediaHeight *pdwDataType: kADT_DWORD

*pbData: the value specified by the PPD's *MaxMediaHeight keyword, in microns.

*pcbNeeded: sizeof(DWORD)

This option attribute is available only to the "CustomPageSize" option of the "PageSize" PPD feature.
MaxMediaWidth *pdwDataType: kADT_DWORD

*pbData: the value specified by the PPD's *MaxMediaWidth keyword, in microns.

*pcbNeeded: sizeof(DWORD)

This option attribute is available only to the "CustomPageSize" option of the "PageSize" PPD feature.
ParamCustomPageSize *pdwDataType: kADT_CUSTOMSIZEPARAMS

pbData: an array of CUSTOMPARAM_MAX elements, where each element is a CUSTOMSIZEPARAM structure. Each element of this array stores values specified in the PPD's *ParamCustomPageSize keyword's paramOption entry. For paramOption other than "Orientation", lMinVal and lMaxVal values are in microns. For "Orientation", lMinVal and lMaxVal values are in the range of [0, 3].

*pcbNeeded: sizeof(CUSTOMSIZEPARAM) * CUSTOMPARAM_MAX

This option attribute is available only to the "CustomPageSize" option of the "PageSize" PPD feature.

See following note.
*InstalledMemory
VMOption *pdwDataType: kADT_DWORD

*pbData: the value specified by the PPD's *VMOption keyword, or 0 if the PPD does not specify the *VMOption keyword for this option.

*pcbNeeded: sizeof(DWORD)

This option attribute is available to any option of the "InstalledMemory" PPD feature.
FCacheSize *pdwDataType: kADT_DWORD

*pbData: the value specified by the PPD's *FCacheSize keyword, or 0 if the PPD does not specify the *FCacheSize keyword for this option.

*pcbNeeded: sizeof(DWORD)

This option attribute is available to any option of the "InstalledMemory" PPD feature.

Note on ParamCustomPageSize

Here is some sample code that shows how to obtain the PPD file's original order, min, and max values of the "*ParamCustomPageSize Width" entry. The CUSTOMPARAM_WIDTH constant, which is defined in printoem.h, indicates the offset of the CUSTOMSIZEPARAM structure that contains the information related to the Width entry. This structure is one of CUSTOMPARAM_MAX CUSTOMSIZEPARAM structures that form an array of such structures. The printoem.h header defines a set of constants named CUSTOMPARAM_XXX listing the offsets of the structures in this array (Width, Height, WidthOffset, HeightOffset, and Orientation).

PCUSTOMSIZEPARAM  pCSParam;

pCSParam = (PCUSTOMSIZEPARAM)pbData + CUSTOMPARAM_WIDTH;

order = pCSParam->dwOrder;
// Convert lMinVal and lMaxVal from microns to points.
//   To convert microns to inches, divide by 25400.
//   To convert inches to points, multiply by 72.
min = pCSParam->lMinVal / 25400.0 * 72.0;
max = pCSParam->lMaxVal / 25400.0 * 72.0;


Microsoft Plotter Driver

The Microsoft® Plotter Driver is the Microsoft corporation's standard printer driver for plotters that support the Hewlett-Packard Graphics Language. The following topics describe the Microsoft Plotter Driver:

Plotter Driver Capabilities

Plotter Driver Components

Plotter Driver Minidrivers

Plotter Driver User Interface

Plotter Driver Renderer


Plotter Driver Capabilities

The Microsoft Plotter Driver (MSPlot) provides the following capabilities:

  • Support for all plotters that use the HPGL/2 version of the Hewlett-Packard Graphics Language, by means of plotter model-specific plotter driver minidrivers.
  • A plotter driver user interface, based on the TreeView control and property sheets, that is consistent for all plotters.
  • A plotter driver renderer that, along with the GDI graphics engine, converts Win32® GDI calls from applications into printer commands that can be sent to the print spooler.

To provide support for a new HPGL/2-compliant device type, all you need to do is provide a minidriver that describes the device.


Plotter Driver Components

MSPlot components consist of DLLs and binary data files, as illustrated in the following diagram.

Components in the diagram include:

Application
A user application that provides users with printing capabilities.
gdi32.dll
User-mode DLL that exports Win32 GDI functions.
Kernel-Mode Graphics Engine
NT-based operating system Executive code that implements GDI functionality.
Minidrivers
MSPlot minidrivers (.pcd files).
Cached .pcd file data
Minidriver data read from .pcd files.
plotui.dll
Plotter driver user interface DLL, providing common UI code for all MSPlot-supported printers.
compstui.dll
CPSUI user interface for printers.
plotter.dll
Plotter driver renderer, which renders images and sends the image data stream to the spooler.


Sample Plotter Driver Files

This DDK includes the following MSPlot sample code:

  • Source code for the plotter driver user interface DLL (plotui.dll)
  • Source code for the plotter driver renderer (plotter.dll)
  • Source code for plotgpc.exe, which generates .pcd files.
  • A sample minidriver text file, which can be used as input to plotgpc.exe.

Samples are located in a subdirectory of the directory tree containing DDK samples. The plotter driver renderer (plotter.dll) can be compiled as either a user-mode or a kernel-mode DLL. For more information, see Choosing User Mode or Kernel Mode.


Plotter Driver Minidrivers

Model-specific minidrivers for the Microsoft Plotter Driver are vendor-supplied binary .pcd files created from text files that describe a device's characteristics.

PCD Files

To generate a .pcd file, you must first create a text file using the PCD source file format. You must then run plotgpc.exe, which is included with this DDK. This program will convert a text file into a binary .pcd file. Use the following command syntax:

plotgpc source-file-path.txt target-file-path.pcd

For both the source and destination files, you must explicitly specify file name extensions; defaults are not supported.

A sample text file that can be used as input to plotgpc.exe is included in the sample plotter driver files.


PCD Source File Format

All plotter device characteristics are specified using the following format:

keyword {value}

where keyword is one of the PCD source file keywords and value is a quoted string or numeric value. For example, the following statement specifies that the plotter supports color:

ColorCap {1}

Keywords are described in the following table.

Key- word | Value Definition | Default Value
BezierCap
 | 1=Device supports HPGL2 Beziers extension. 0=No support. | 0
ColorCap
 | 1=Color device 0=Monochrome device | 0
COLORINFO
 | Thirty DWORD-sized values representing the contents of a COLORINFO structure. | { {6810,3050,0}, // xr, yr, Yr {2260,6550,0}, // xg, yg, Yg {1810,500,0}, // xb, yb, Yb {2000,2450,0}, // xc, yc, Yc {5210,2100,0}, // xm, ym, Ym {4750,5100,0}, // xy, yy, Yy {3324,3474,10000}, // xw, yw, Yw 10000,10000,10000, // RGB gamma 1422,952, // M/C, Y/C 787,495, // C/M, Y/M 324,248 // C/Y, M/Y }
DeviceMargin
 | Four DWORD-sized values representing the left, top, right, and bottom paper margins, in 1/1000 mm units. | {5000, 5000, 5000, 36000}
DeviceName
 | Quoted string representing a displayable device name (31 characters max.) | "HPGL/2 Plotter"
DevicePelsDPI
 | One DWORD-sized value representing the device's effective DPI. For more information see the upDevicePelsDPI member of GDIINFO. | The default is zero, causing GDI to calculate a value.
DeviceSize
 | Two DWORD-sized values representing maximum paper size, in x and y coordinates of 1/1000 mm units. A y value of 25400 (1 inch) or less indicates the device accepts variable paper lengths. | {215900, 279400}
FormInfo
 | A form description for each form supported by the plotter. | None.
HTPatternSize
 | One of the HT_PATSIZE_-prefixed constants that identify standard halftoning patterns. | 0xffffffff
InitString
 | Quoted C-language string representing commands sent to the printer by the driver's DrvStartPage function. | NULL string.
MaxCopies
 | Maximum number of copies per page that the device can render. | 1
MaxPens
 | Number of pens (32 max.) | 8
MaxPolygonPts
 | Maximum number of points to define a polygon to be stroked or filled. | 128
MaxQuality
 | Number of quality levels (4 max.) | 4
MaxScale
 | Maximum scale size. 0-10000 (100 is 100%) | 100
NoBitmapFont
 | 1=Device does not support bitmap fonts. 0=Bitmap fonts are supported. | 0
PaperTrayCap
 | 1=Device has paper tray source. 0=No support. | 0
PaperTraySize
 | Two DWORD-sized values representing the paper tray width and height, in 1/1000 mm units. | {-1, -1}
PlotDPI
 | Two DWORD-sized values representing a pen plotter's x and y resolution, in dots per inch. | {1016, 1016}
PlotPenData
 | A pen description for each pen. | None.
PushPopPal
 | 1=Driver must push/pop palette when switching between RTL and HPGL2. 0=Push/pop isn't required. | 0
RasterByteAlign
 | 1=Device must receive all raster data on byte-aligned x coordinates. 0=Byte alignment isn't required. | 0
RasterCap
 | 1=Raster device 0=Pen device | 0
RasterDPI
 | Two DWORD-sized values representing x and y resolution, in dots per inch. For raster plotters, this is the raster resolution. For pen plotters, this is the ideal resolution the GDI supplies to an application. | {300, 300}
RollFeedCap
 | 1=Device has roll paper source. 0=No support. | 0
ROPLevel
 | ROP_LEVEL_0 = No RasterOp support. ROP_LEVEL_1 = Rop1 support. ROP_LEVEL_2 = Rop2 support. ROP_LEVEL_3 = Rop3 support. | ROP_LEVEL_0
RTLMonoEncode5
 | 1=HP Raster Transfer Language (RTL) Monochrome Compression Mode 5 is supported. 0=No support. | 0
RTLMonoFixPal
 | RTL Monochrome palette only. 0=White, 1=Black | 0
RTLMonoNoCID
 | 1=In RTL Mono mode, CID commands are not required. 0=In RTL Mono mode, CID commands are required. | 0
RTLNoDPIxy
 | 1=RTL DPI X,Y move commands are not supported. 0=These commands are supported. | 0
TransparentCap
 | 1=Device supports transparent mode. 0=No support. | 0
WindingFillCap
 | 1=Device supports winding fills. 0=No support. | 0

Pen Descriptions

Each pen description must have the following format:

PlotPenData {Pen Number, Color}

where Pen Number identifies the pen's slot number and Color is a PC_IDX_-prefixed color identifier. Following are example pen descriptions:

PlotPenData {1, PC_IDX_WHITE}
PlotPenData {2, PC_IDX_BLACK}
PlotPenData {3, PC_IDX_RED}

Form Descriptions

Each form description must have the following format:

FormInfo {"Form Description", Width, Length, Left Margin, Top Margin, Right Margin, Bottom Margin}

where Form Description is a string describing the form, Width and Length specify the form size in 1/1000 mm units, and the margins are also specified in 1/1000 mm units. Following are three examples:

FormInfo {"Roll Paper 24 in",    609600,      0, 0, 0, 0, 0}
FormInfo {"ANSI A 8.5 x 11 in",  215900, 279400, 0, 0, 0, 0}
FormInfo {"ISO A4 210 x 297 mm", 210000, 297000, 0, 0, 0, 0}


Plotter Driver User Interface

The plotter user interface employs CPSUI to create the following two property sheet pages:

  • The Device Settings page for the printer property sheet, which is displayed when a user selects the Properties menu item from the printer folder or a printer window. This page lists printer-specific configuration settings.
  • The Layout, Paper/Quality, and Advanced pages for the document property sheet, which are displayed when a user selects the Document Defaults menu item from the printer folder or a printer window, or when an application calls the PrinterProperties or DocumentProperties functions (described in the Platform SDK documentation). This page lists document-specific configuration settings.

These property sheets contain the plotter features and options specified by a plotter's minidriver. They also allow the user to modify option values.

The plotter's user interface is implemented as a user-mode printer interface DLL. Code within this DLL, in conjunction with CPSUI, specifies the contents of the property sheet pages. The DLL enforces constraints on which plotter options can be combined, based on information in the minidriver. It also ensures that users do not select options not installed on the plotter.


Plotter Driver Renderer

The plotter driver renderer is implemented as a printer graphics DLL and thus exports functions defined by the Microsoft Device Driver Interface (DDI) for graphics drivers. When an application calls Graphics Device Interface (GDI) functions to send images to a plotter, the kernel-mode graphics engine calls the renderer's graphics DDI functions. These graphics DDI functions assist GDI in drawing a print job's page images.

The renderer is also responsible for sending rendered image data, along with plotter command sequences, to the print spooler, which then directs the images and commands to plotter hardware.


Customizing Microsoft's Printer Drivers

The designs of the Microsoft Universal Printer Driver (Unidrv) and the Microsoft Postscript Printer Driver (Pscript) are based on the NT-based operating system printer driver architecture. Therefore, each is composed of two components — a printer interface DLL and a printer graphics DLL. This section explains how to customize these components.

To customize the printer interface DLL provided for Unidrv or Pscript, you must provide one or more user interface plug-ins. You can use these plug-ins to modify the driver's user interface and to provide extra processing for certain printer events.

To customize the printer graphics DLL provided for Unidrv or Pscript, you must provide one or more rendering plug-ins. You can use these plug-ins to modify the data that is sent to the print spooler within a print job's data stream.

This section also explains how to implement printer driver COM interfaces, which are used by plug-ins to communicate with the printer drivers, and how to install customized driver components.


User Interface Plug-Ins

This section contains the following topics that explain how to develop a user interface plug-in:

Introduction to User Interface Plug-Ins

Sample UI Plug-In

COM Interfaces for UI Plug-Ins

Providing DEVMODE Structure Additions

Accessing Driver Settings from UI Plug-Ins

Modifying a Driver-Supplied Property Sheet Page

Replacing Driver-Supplied Property Sheet Pages

Adding New Property Sheet Pages

Customizing Other Printer Interface Operations


Introduction to User Interface Plug-Ins

When you add support for a new printer device to either the Microsoft Universal Printer Driver (Unidrv) or the Microsoft Postscript Printer Driver (Pscript), you can customize the driver's user interface by modifying the printer property sheet or the document property sheet for your printer.

You accomplish this customization by providing a user-mode DLL. This DLL is referred to as a user interface plug-in, or just UI plug-in.

A UI plug-in can modify the printer property sheet by adding, removing, or replacing options within the property sheet's Device Settings page. It can also add a new page. Likewise, the plug-in can modify the document property sheet by adding, removing, or replacing options within the property sheet's Layout, Paper/Quality, and Advanced pages, or it can add a new page.

UI plug-ins are called by the printer interface DLL for Unidrv or Pscript, using a set of COM interfaces. Printer interface DLLs are implemented by using CPSUI, and a UI plug-in interacts indirectly with CPSUI through the driver's printer interface DLL. Therefore, it is useful to read the CPSUI section before developing a UI plug-in.

In addition to modifying the printer driver's user interface, a UI plug-in can perform other operations, such as processing certain printer events and reporting supported capabilities. For more information, see Customizing Other Printer Interface Operations.


Sample UI Plug-In

Source code for a sample user interface plug-in is provided with this DDK. Code is contained in the src\print\oemdll\oemui source code sub-directory and creates a plug-in that can be used with either Unidrv or Pscript5.


COM Interfaces for UI Plug-Ins

The following COM interfaces are defined for communication between Microsoft's printer drivers and UI plug-ins:

  • IPrintOemUI COM Interface – Allows the printer interface DLL for Unidrv or Pscript5 to call UI plug-ins.
  • IPrintOemUI2 COM Interface — Extends the IPrintOemUI COM Interface.
  • IPrintOemDriverUI COM Interface — Supplies utility operations to UI plug-ins.
  • IPrintCoreUI2 COM Interface — Provides helper methods for minidriver UI plug-ins.


IPrintOemUI COM Interface

The IPrintOemUI COM interface is the means by which the printer interface DLL for Unidrv or Pscript5 communicates with a UI plug-in. The IPrintOemUI interface is implemented by each UI plug-in.

The following table lists and describes all of the methods supplied by the IPrintOemUI interface. UI plug-ins must define all listed methods. If a method is not needed it can simply return E_NOTIMPL.

Method | Description
IPrintOemUI::CommonUIProp
 | Allows a user interface plug-in to modify an existing printer property sheet page or document property sheet page.
IPrintOemUI::DeviceCapabilities
 | Allows a user interface plug-in to specify customized device capabilities.
IPrintOemUI::DevicePropertySheets
 | Allows a user interface plug-in to add a new page to a printer device's printer property sheet.
IPrintOemUI::DevMode
 | Performs operations on a user interface plug-in's private DEVMODE members.
IPrintOemUI::DevQueryPrintEx
 | Allows a user interface plug-in to help determine if a print job is printable.
IPrintOemUI::DocumentPropertySheets
 | Allows a user interface plug-in to add a new page to a printer device's document property sheet.
IPrintOemUI::DriverEvent
 | Called by the print spooler when processing driver-specific events that might require action by the printer driver.
IPrintOemUI::FontInstallerDlgProc
 | Replaces the Unidrv font installer's user interface.
IPrintOemUI::GetInfo
 | (Implementation required.) Returns a user interface plug-in's identification information.
IPrintOemUI::PrinterEvent
 | Allows a user interface plug-in to process printer events.
IPrintOemUI::PublishDriverInterface
 | (Implementation required.) Supplies a pointer to the Unidrv or Pscript5 driver's IPrintOemDriverUI COM interface.
IPrintOemUI::QueryColorProfile
 | Allows a printer interface DLL to specify an ICC profile to use for color management.
IPrintOemUI::UpdateExternalFonts
 | Allows a printer interface DLL to update a printer's Unidrv Font Format file (.uff file).
IPrintOemUI::UpgradePrinter
 | Allows a user interface plug-in to upgrade device option values that are stored in the registry.

For more information, see Implementing Printer Driver COM Interfaces.


IPrintOemUI2 COM Interface

The IPrintOemUI2 COM interface extends the IPrintOemUI COM interface. In addition to all of the methods in the IPrintOemUI interface, the IPrintOemUI2 interface provides the following methods. Except for the IPrintOemUI2::HideStandardUI method, these methods can be implemented in Unidrv or Pscript5 plug-ins running on Microsoft® Windows® XP and later.

Method | Description
IPrintOemUI2::DocumentEvent
 | Allows a UI plug-in to replace the core driver UI module's default implementation of the DrvDocumentEvent DDI.
IPrintOemUI2::HideStandardUI
 | Allows a Pscript5 UI plug-in to specify whether the standard property sheets should be displayed or hidden.
IPrintOemUI2::QueryJobAttributes
 | Allows a UI plug-in to post-process the core driver's results after a call to the DrvQueryJobAttributes DDI.


IPrintOemDriverUI COM Interface

The IPrintOemDriverUI COM interface allows a UI plug-in to view and modify information managed by the printer interface DLL for Unidrv or Pscript.

The following table lists and describes all of the methods defined by the IPrintOemDriverUI interface.

Method | Description
IPrintOemDriverUI::DrvGetDriverSetting
 | Allows a user interface plug-in to obtain the current status of printer features and other internal information.
IPrintOemDriverUI::DrvUpdateUISetting
 | Allows a user interface plug-in to notify the driver of a modified user interface option.
IPrintOemDriverUI::DrvUpgradeRegistrySetting
 | Allows a user interface plug-in to update device settings stored in the registry.

For more information, see Implementing Printer Driver COM Interfaces.


IPrintCoreUI2 COM Interface

The IPrintCoreUI2 COM interface extends the IPrintOemDriverUI COM interface. The Windows XP and later Pscript5 driver provides the IPrintCoreUI2 COM interface; the methods in this interface are for use only by Pscript5 user interface plug-ins.

Method | Description
IPrintCoreUI2::DrvGetDriverSetting
 | Enables a user interface plug-in to obtain the current status of printer features and other internal information.
IPrintCoreUI2::DrvUpdateUISetting
 | Enables a user interface plug-in to notify the driver of a modified user interface option.
IPrintCoreUI2::DrvUpgradeRegistrySetting
 | Allows OEM plug-ins to upgrade private registry settings.
IPrintCoreUI2::EnumConstrainedOptions
 | Determines which options of a feature are constrained.
IPrintCoreUI2::EnumFeatures
 | Enumerates a printer's available features.
IPrintCoreUI2::EnumOptions
 | Enumerates the available options of a specific feature.
IPrintCoreUI2::GetFeatureAttribute
 | Retrieves the feature attribute list or the value of a specific feature attribute.
IPrintCoreUI2::GetGlobalAttribute
 | Retrieves the global attribute list or the value of a specific global attribute.
IPrintCoreUI2::GetOptionAttribute
 | Retrieves the option attribute list or the value of a specific option attribute.
IPrintCoreUI2::GetOptions
 | Retrieves the driver's current feature settings in the format of a list of feature/option keyword pairs.
IPrintCoreUI2::QuerySimulationSupport
 | Retrieves a spooler simulation capability structure, which indicates the kinds of simulation the spooler supports.
IPrintCoreUI2::SetOptions
 | Sets the driver's feature settings.
IPrintCoreUI2::WhyConstrained
 | Determines why the specified feature/option selection is constrained.


Providing DEVMODE Structure Additions

Your user interface plug-in can add additional, private members to the DEVMODE structure, as illustrated in the following figure.

Public and Private DEVMODE Sections

A UI plug-in can use these private DEVMODE members for storing values associated with customized printer options. The plug-in makes these options available to the user by modifying a driver-supplied property sheet page or by adding new property sheet pages.

If your UI plug-in adds private DEVMODE members, the added members must be prefixed by the OEM_DMEXTRAHEADER structure.

You are not required to add members to the DEVMODE structure, but if you do, your plug-in must implement the IPrintOemUI::DevMode method. This method's purpose, depending on input arguments, is to return the size of, initialize, convert, or validate the additional DEVMODE members.


Accessing Driver Settings from UI Plug-Ins

A user interface plug-in can obtain the current status of printer features and other internal information. The IPrintOemDriverUI::DrvGetDriverSetting COM interface method is implemented within the printer interface DLL for Microsoft's printer drivers and can be called by UI plug-ins.

Additionally, the following methods allow UI plug-ins to modify driver information.

  • IPrintOemDriverUI::DrvUpdateUISetting allows a UI plug-in to notify the driver when a user has modified driver settings.
  • IPrintOemDriverUI::DrvUpgradeRegistrySetting allows a UI plug-in to modify device settings in the registry, so that registry settings used by older driver versions can be updated.


Modifying a Driver-Supplied Property Sheet Page

A UI plug-in can modify Unidrv-supplied or Pscript5-supplied property sheet pages by implementing the IPrintOemUI::CommonUIProp method and a callback function.

The IPrintOemUI::CommonUIProp method is used by the UI plug-in to specify a set of option items that CPSUI can add, remove, or replace within either the printer property sheet's Device Settings page or the document property sheet's Layout, Paper/Quality, and Advanced pages.

The callback function, of type OEMCUIPCALLBACK, is used to process user modifications to customized option items.

Adding Option Items

Your UI plug-in must describe new option items by placing them in an array of OPTITEM structures supplied by the driver. The driver's printer interface DLL calls the UI plug-in's IPrintOemUI::CommonUIProp method twice. The first time the method is called, it should return the number of OPTITEM structures required. The driver allocates space for an OPTITEM array and describes the array in an OEMCUIPPARAM structure. The driver calls IPrintOemUI::CommonUIProp again, supplying the address of the OEMCUIPPARAM structure, so the method can load the OPTITEM structures with option descriptions.

Removing Option Items

To remove an option from a property sheet page that is supplied by Unidrv or Pscript5, your UI plug-in's IPrintOemUI::CommonUIProp method can traverse the array of OPTITEM structures pointed to by the OEMCUIPPARAM structure. For each option that you'd like to remove from the property sheet, you can set the OPTITEM structure's OPTIF_HIDE flag. (Note that this does not actually remove the option; it hides the option from the user so that its default value cannot be changed.)

Replacing Option Items

To replace an option in a property sheet page that is supplied by Unidrv or Pscript, you should follow the instructions under Removing Option Items to remove the existing option item, then follow the instructions under Adding Option Items to create a new option item to replace the old one.

Handling Modifications to Customized Option Values

In order to process user modifications to customized option items, you must provide at least one callback function. You can either specify a single callback function that handles options for both the document property sheet and the printer property sheet, or you can specify a separate function for each. These callbacks are of type OEMCUIPCALLBACK.

A callback function is specified by placing its address in an OEMCUIPPARAM structure. The UI plug-in receives the address of this structure as input to its IPrintOemUI::CommonUIProp method.

When a user opens the printer property sheet or document property sheet and modifies options, CPSUI calls the printer driver's printer interface DLL. This DLL processes option values contained in its own OPTITEM structures. Then for each UI plug-in, the printer interface DLL calls the OEMCUIPCALLBACK-typed callback function that was previously specified by IPrintOemUI::CommonUIProp.


Replacing Driver-Supplied Property Sheet Pages

The IPrintCoreUI2 COM interface provides four methods that a Pscript5 UI plug-in running on Windows XP and later must use when it intends to fully replace the core driver's standard UI pages. (The term core driver refers to either the Unidrv or Pscript5 printer driver.) These methods are

  • IPrintCoreUI2::EnumConstrainedOptions
  • IPrintCoreUI2::GetOptions
  • IPrintCoreUI2::SetOptions
  • IPrintCoreUI2::WhyConstrained

These methods are supported only while the UI plug-in's IPrintOemUI::DocumentPropertySheets and IPrintOemUI::DevicePropertySheets methods and their property sheet callback routines are executing. A UI plug-in supports these methods to display its own user interface. When not supported, these methods return E_NOTIMPL.

The core driver displays its own property sheet UI in two circumstances: for DrvDocumentPropertySheets, and for DrvDevicePropertySheets. The first method displays properties that apply only to documents (document-sticky properties), while the second method displays properties that apply to a device (device- or printer-sticky properties).

The core driver remembers which type of property sheet it is handling (and therefore, which mode — document-sticky or printer-sticky). The core driver saves that state information in a structure (the OEMUIOBJ structure) it creates for the UI instance. When the core driver calls a plug-in's interface methods, it passes a pointer to an OEMUIOBJ structure, so that when a plug-in calls back to the core driver from IPrintCoreUI2::EnumConstrainedOptions, IPrintCoreUI2::GetOptions, IPrintCoreUI2::SetOptions, or IPrintCoreUI2::WhyConstrained, these methods pass the pointer back to the core driver, which is then able to determine the mode.

For IPrintCoreUI2::EnumConstrainedOptions, IPrintCoreUI2::SetOptions, and IPrintCoreUI2::WhyConstrained, only document-sticky features are supported when IPrintOemUI::DocumentPropertySheets or its property sheet callback routine are executing, and only printer-sticky features are supported when IPrintOemUI::DevicePropertySheets or its property sheet callback routine are executing. For IPrintCoreUI2::SetOptions, any feature whose stickiness does not match the current sticky mode should be ignored. When either IPrintCoreUI2::EnumConstrainedOptions or IPrintCoreUI2::WhyConstrained is called for a feature whose stickiness does not match the current sticky mode, the method should return E_INVALIDARG.

For IPrintCoreUI2::GetOptions, both document-sticky and printer-sticky features are supported in document-sticky mode (that is, when IPrintOemUI::DocumentPropertySheets or its property sheet callback routine are running), but only printer-sticky features are supported in printer-sticky mode (when IPrintOemUI::DevicePropertySheets or its property sheet callback routine are running).


Adding New Property Sheet Pages

If you want to add new pages to the property sheets provided by the printer interface to Unidrv or Pscript5, your UI plug-in must implement the following IPrintOemUI methods:

  • IPrintOemUI::DevicePropertySheets

    Used for adding pages to the printer property sheet, which is displayed when a user selects the Properties menu item from the printer folder or a printer window, or when an application calls the PrinterProperties function (described in the Platform SDK documentation).

  • IPrintOemUI::DocumentPropertySheets

    Used for adding pages to the document property sheet, which is displayed when a user selects the Printer Preferences menu item from the printer folder or a printer window, or when an application calls the DocumentProperties or AdvancedDocumentProperties functions (described in the Platform SDK documentation).

If you implement one of these methods, you will typically also supply a _CPSUICALLBACK-typed callback function to handle user modifications. This callback function must call IPrintOemDriverUI::DrvUpdateUISetting to inform the driver when the value associated with a user interface setting has been modified, if the setting's value is stored in the driver's DEVMODE structure or registry keys.


Customizing Other Printer Interface Operations

A UI plug-in can optionally implement any of the following IPrintOemUI methods:

IPrintOemUI::DeviceCapabilities

IPrintOemUI::DevQueryPrintEx

IPrintOemUI::PrinterEvent

IPrintOemUI::UpgradePrinter

The methods are equivalent to similarly named functions exported by the user-mode printer interface DLL that is used by Unidrv and Pscript5. These customization methods do not replace the equivalent functions in the driver's printer interface DLL. In each case, the printer interface DLL function is called first, and then the driver calls the plug-in's customization method.


Rendering Plug-Ins

The following topics describe how to customize printer rendering operations:

Introduction to Rendering Plug-Ins

Sample Rendering Plug-In

COM Interfaces for Rendering Plug-Ins

Customized Graphics DDI Functions

Customized PDEV Structures

Accessing Driver Settings from Rendering Plug-Ins

Pscript-Specific Customized Rendering

Unidrv-Specific Customized Rendering


Introduction to Rendering Plug-Ins

When you add support for a new printer device to either the Microsoft Universal Printer Driver (Unidrv) or the Microsoft Postscript Printer Driver (Pscript), you can implement COM interface methods to modify the data that the driver sends to the print spooler.

You accomplish this customization by providing a user-mode DLL. This DLL is referred to as a rendering plug-in.

Two types of customization are supported:

  • Providing customized versions of some graphics DDI rendering functions.
  • Implementing Unidrv-specific or Pscript-specific COM interface methods that modify the rendered image or scan line data stream, or insert Postscript code at specific injection points, before the data stream is sent to the spooler.


Sample Rendering Plug-In

Source code for sample rendering plug-ins are provided with this DDK. Code is contained in the src\oemdll\oemuni and src\oemdll\oemps source code subdirectories. The code in the first subdirectory creates a plug-in that can be used with Unidrv. The code in the second subdirectory creates a plug-in that can be used with Pscript5.


COM Interfaces for Rendering Plug-Ins

The following COM interfaces are defined for communication between Microsoft's printer drivers and rendering plug-ins:

  • IPrintOemUni COM Interface – Allows the printer graphics DLL for Unidrv to call rendering plug-ins.
  • IPrintOemUni2 COM Interface – Extends the capabilities of the IPrintOemUni COM interface.
  • IPrintOemDriverUni COM Interface – Supplies utility operations to rendering plug-ins for Unidrv.
  • IPrintOemPS COM Interface – Allows the printer graphics DLL for Pscript5 to call rendering plug-ins.
  • IPrintOemPS2 COM Interface – Extends the capabilities of the IPrintOemPS COM interface.
  • IPrintOemDriverPS COM Interface – Supplies utility operations to rendering plug-ins for Pscript5.
  • IPrintCorePS2 COM Interface — Provides helper methods for Pscript5 minidriver render plug-ins.


IPrintOemUni COM Interface

The IPrintOemUni COM interface is the means by which the printer graphics DLL for Unidrv communicates with a rendering plug-in. The IPrintOemUni interface is implemented by each rendering plug-in.

The following table lists and describes all of the methods provided by the IPrintOemUni interface. Rendering plug-ins must define all listed methods. If a method is not needed it can simply return E_NOTIMPL.

Method | Description
IPrintOemUni::CommandCallback
 | Allows a rendering plug-in to provide dynamically generated printer commands.
IPrintOemUni::Compression
 | Allows a rendering plug-in to provide a customized bitmap compression method.
IPrintOemUni::DevMode
 | Performs operations on a rendering plug-in's private DEVMODE members.
IPrintOemUni::DisableDriver
 | Frees resources that were allocated by a rendering plug-ins IPrintOemUni::EnableDriver method.
IPrintOemUni::DisablePDEV
 | Allows a rendering plug-in to delete the private PDEV structure that was allocated by its IPrintOemUni::EnablePDEV method.
IPrintOemUni::DownloadCharGlyph
 | Allows a rendering plug-in to download a character glyph for a specified soft font to the printer.
IPrintOemUni::DownloadFontHeader
 | Allows a rendering plug-in to download a font's header information to a printer.
IPrintOemUni::DriverDMS
 | Allows a rendering plug-in to indicate that it will use a device-managed drawing surface.
IPrintOemUni::EnableDriver
 | Allows a rendering plug-in to hook out some graphics DDI functions.
IPrintOemUni::EnablePDEV
 | Allows a rendering plug-in to create its own PDEV structure.
IPrintOemUni::FilterGraphics
 | Allows a rendering plug-in to modify scan line data and send it to the spooler.
IPrintOemUni::GetImplementedMethod
 | (Implementation required.) Allows Unidrv to determine which IPrintOemUni interface methods have been implemented by a rendering plug-in.
IPrintOemUni::GetInfo
 | (Implementation required.) Returns a rendering plug-in's identification information.
IPrintOemUni::HalftonePattern
 | Allows a rendering plug-in to create or modify a halftone pattern before it is used in a halftoning operation.
IPrintOemUni::ImageProcessing
 | Allows a rendering plug-in to modify image bitmap data, in order to perform color formatting or halftoning.
IPrintOemUni::MemoryUsage
 | Allows a rendering plug-in to specify the amount of memory required for use by its IPrintOemUni::ImageProcessing method.
IPrintOemUni::OutputCharStr
 | Allows a rendering plug-in to control the printing of font glyphs.
IPrintOemUni::PublishDriverInterface
 | (Implementation required.) Supplies a pointer to the Unidrv driver's IPrintOemDriverUni COM interface.
IPrintOemUni::ResetPDEV
 | Allows a rendering plug-in to reset its PDEV structure.
IPrintOemUni::SendFontCmd
 | Allows a rendering plug-in to modify a printer's font selection command and then send it to the printer.
IPrintOemUni::TextOutAsBitmap
 | Allows a rendering plug-in to create a bitmap image of a text string.
IPrintOemUni::TTDownloadMethod
 | Allows a rendering plug-in to indicate the format that Unidrv should use for a specified TrueType font.
IPrintOemUni::TTYGetInfo
 | Allows a rendering plug-in to supply Unidrv with information relevant to text-only printers.

For more information, see Implementing Printer Driver COM Interfaces.


IPrintOemUni2 COM Interface

The IPrintOemUni2 COM interface contains all of the methods of, and extends the capabilities of the IPrintOemUni COM interface.

The following table lists and describes all of the methods provided by the IPrintOemUni2 interface. Rendering plug-ins must define all listed methods. If a method is not needed it can simply return E_NOTIMPL.

Method |  | Description
IPrintOemUni2::WritePrinter
 | Enables a plug-in to capture all output data generated by a Unidrv driver.


IPrintOemDriverUni COM Interface

The IPrintOemDriverUni COM interface provides a rendering plug-in with access to utility operations supplied by the printer graphics DLL for Unidrv. These operations include sending a data stream to the print spooler and obtaining driver-managed information.

The following table lists and describes all of the methods defined by the IPrintOemDriverUni interface.

Method | Description
IPrintOemDriverUni::DrvGetDriverSetting
 | Returns the current status of printer features and other internal information.
IPrintOemDriverUni::DrvGetGPDData
 | Enables rendering plug-ins to obtain data defined in a printer's GPD file.
IPrintOemDriverUni::DrvGetStandardVariable
 | Enables rendering plug-ins to obtain the current value of Unidrv's standard variables.
IPrintOemDriverUni::DrvUniTextOut
 | Enables a rendering plug-in using a device-managed drawing surface to easily output text strings.
IPrintOemDriverUni::DrvWriteAbortBuf
 | Enables a rendering plug-in to reset a printer after a user has terminated a print job.
IPrintOemDriverUni::DrvWriteSpoolBuf
 | Sends printer data to the spooler.
IPrintOemDriverUni::DrvXMoveTo
 | Notifies Unidrv of cursor x-position changes.
IPrintOemDriverUni::DrvYMoveTo
 | Notifies Unidrv of cursor y-position changes.

For more information, see Implementing Printer Driver COM Interfaces.


IPrintOemPS COM Interface

The IPrintOemPS COM interface is the means by which the printer graphics DLL for Pscript5 communicates with a rendering plug-in. The IPrintOemPS interface is implemented by each rendering plug-in.

The following table lists and describes all of the methods provided by the IPrintOemPS interface. Rendering plug-ins must define all listed methods. If a method is not needed it can simply return E_NOTIMPL.

Method | Description
IPrintOemPS::Command
 | Allows a rendering plug-in to insert Postscript commands into the print job's data stream.
IPrintOemPS::DevMode
 | Performs operations on a rendering plug-in's private DEVMODE members.
IPrintOemPS::DisableDriver
 | Frees resources that were allocated by a rendering plug-in's IPrintOemPS::EnableDriver method.
IPrintOemPS::DisablePDEV
 | Allows a rendering plug-in to delete the private PDEV structure that was allocated by its IPrintOemPS::EnablePDEV method.
IPrintOemPS::EnableDriver
 | Allows a rendering plug-in to hook out some graphics DDI functions.
IPrintOemPS::EnablePDEV
 | Allows a rendering plug-in to create its own PDEV structure.
IPrintOemPS::GetInfo
 | (Implementation required.) Returns rendering plug-in identification information.
IPrintOemPS::PublishDriverInterface
 | (Implementation required.) Supplies a pointer to the Pscript5 driver's IPrintOemDriverPS COM interface.
IPrintOemPS::ResetPDEV
 | Allows a rendering plug-in to reset its PDEV structure.

For more information, see Implementing Printer Driver COM Interfaces.


IPrintOemPS2 COM Interface

The IPrintOemPS2 COM interface contains all of the methods of, and extends the capabilities of the IPrintOemPS COM interface. This interface is limited to Pscript5 rendering plug-ins running on Windows XP and later.

The following table lists and describes all of the methods provided by the IPrintOemPS2 interface. Rendering plug-ins must define all listed methods. If a method is not needed it can just return E_NOTIMPL.

Method | Description
IPrintOemPS2::GetPDEVAdjustment
 |  | Enables a plug-in to override specific PDEV settings.
IPrintOemPS2::WritePrinter
 |  | Enables a plug-in to capture all output data generated by a Postscript driver.

For more information, see Implementing Printer Driver COM Interfaces.


IPrintOemDriverPS COM Interface

The IPrintOemDriverPS COM interface provides a rendering plug-in with access to utility operations supplied by the printer graphics DLL for Pscript5. These operations include sending a data stream to the print spooler and obtaining driver-managed information.

The following table lists and describes all of the methods defined by the IPrintOemDriverPS interface.

Method | Description
IPrintOemDriverPS::DrvGetDriverSetting
 | Returns the current status of printer features and other internal information.
IPrintOemDriverPS::DrvWriteSpoolBuf
 | Sends printer data to the spooler.

For more information, see Implementing Printer Driver COM Interfaces.


IPrintCorePS2 COM Interface

The IPrintCorePS2 COM interface provides a set of helper methods for Pscript5 render plug-ins. The following table lists and describes all of the methods defined by the IPrintCorePS2 interface.

Method | Description
IPrintCorePS2::DrvWriteSpoolBuf
 | Is provided by the Pscript5 driver so that rendering plug-ins can send printer data to the spooler.
IPrintCorePS2::EnumFeatures
 | Enumerates a printer's available features.
IPrintCorePS2::EnumOptions
 | Enumerates the available options of a specific feature.
IPrintCorePS2::GetFeatureAttribute
 | Retrieves the feature attribute list or the value of a specific feature attribute.
IPrintCorePS2::GetGlobalAttribute
 | Retrieves the global attribute list or the value of a specific global attribute.
IPrintCorePS2::GetOptionAttribute
 | Retrieves the option attribute list or the value of a specific option attribute.
IPrintCorePS2::GetOptions
 | Retrieves the driver's current feature settings in the format of a list of feature/option keyword pairs.


Customized Graphics DDI Functions

Printer minidriver developers can extend the capabilities of the core printer driver graphics DDIs by implementing plug-in methods. A rendering plug-in can hook out some graphics DDI functions in order to provide customized implementations of the core printer driver functions. Developers of new printer render modules should implement COM-based methods for their plug-ins. See COM Interfaces for Rendering Plug-Ins for a list of the defined COM interfaces.

Prior to the publication of the COM interfaces, IHVs could extend the capabilities of the graphics DDIs by implementing one or more OEMXxx functions for their rendering plug-ins. Although the use of these functions is still supported for compatibility reasons, writers of new render module plug-ins should use the methods in the COM interfaces.

The remainder of this section contains the following topics:

COM-Based Rendering Plug-Ins

Non-COM-Based Rendering Plug-Ins


COM-Based Rendering Plug-Ins

To provide customized hooking functions, your COM-based rendering plug-in must implement the IPrintOemUni::EnableDriver or IPrintOemPS::EnableDriver method, which fills in a DRVENABLEDATA structure with the address of each hooking function.

A COM-based rendering plug-in can hook out a graphics DDI function only if the Unidrv or Pscript5 driver defines the function. For a list of such functions, see IPrintOemUni::EnableDriver or IPrintOemPS::EnableDriver.

If you provide a particular customized hooking function, that function preempts the driver's equivalent graphics DDI function. When designing a customized hooking function, you have the following options:

  • The hooking function can completely handle the graphics DDI operation internally.
  • The hooking function can call back to the printer driver's equivalent graphics DDI function.

By calling back to the driver's graphics DDI function, the hooking function can perform pre-processing or post-processing of function arguments, but still allow the driver to actually perform the graphics DDI operation. One of the input arguments to a rendering plug-in's IPrintOemUni::EnablePDEV or IPrintOemPS::EnablePDEV method is a DRVENABLEDATA structure containing pointers to the driver's graphics DDI functions. If you want to call back to these functions, you should save this structure's contents.

It might be necessary for you to provide a customized PDEV structure. You can reference this structure from within a graphics DDI hooking function, through the SURFOBJ structure pointer that each hooking function receives as input. Specifically, the SURFOBJ structure's dhpdev member points to a DEVOBJ structure, and the DEVOBJ structure's pdevOEM member points to your customized PDEV structure.


Non-COM-Based Rendering Plug-Ins

A printer minidriver notifies the core driver of its capabilities by implementing the OEMEnableDriver function, which fills in the members of a DRVENABLEDATA structure. The pdrvfn member of this structure should be set with the address of an array of DRVFN structures. Each element of this array should be initialized with, respectively, a function index, and the address of one of the OEMXxx functions that the IHV is implementing. (For detailed descriptions of each of the OEMXxx functions, see Non-COM-Based DDI Hook-out Functions.)

When an application calls Win32® GDI to perform a rendering task, Win32® GDI in turn calls into the Unidrv or Pscript5 core driver, which usually handles the task. If a printer minidriver has indicated that it is capable of hooking out a specific rendering operation, however, the core driver passes the rendering task along to the IHV render module plug-in.

For example, suppose that an application makes a call to the Win32® LineTo API (described in the Platform SDK documentation). Ordinarily, this would result in another call to the core driver's DrvLineTo DDI to draw the line. If the printer minidriver has indicated that it intends to hook out calls to this DDI, however, DrvLineTo immediately forwards the call to the IHV's OEMLineTo function.

An IHV can implement OEMLineTo, or any of the other hook-out functions described in Non-COM-Based DDI Hook-out Functions, so that it can completely handle the rendering operation, or it can call back to have the core driver handle that operation.

OEMLineTo could be implemented as shown in the following pseudocode example:

BOOL APIENTRY
  OEMLineTo(
    SURFOBJ  *pso,
    CLIPOBJ  *pco,
    BRUSHOBJ  *pbo,
    LONG  x1,
    LONG  y1,
    LONG  x2,
    LONG  y2,
    RECTL  *prclBounds,
    MIX  mix
)
{
if ( OEM wants to handle the call ) {
  code to handle the call
}
else
// OEM calls Unidrv's DrvLineTo DDI
  bRetVal = (((PFN_DrvLineTo)(poempdev->pfnUnidrv[UD_DrvLineTo])) (
            pso,
            pco,
            pbo,
            x1,
            x2,
            y1,
            y2,
            prclBounds,
            mix,));
}

In the preceding example, the expression

poempdev->pfnUnidrv[UD_DrvLineTo]

evaluates to the address of the core driver's DrvLineTo DDI. The (PFN_DrvLineTo) expression that precedes it casts the function pointer to the appropriate type. Each of the hook-out functions listed in this section is associated with its own function pointer.

Note that when an OEMXxx DDI calls back to the Unidrv core driver and the surface involved is a device-managed surface, Unidrv can simply ignore the call by returning FALSE.


Customized PDEV Structures

Rendering plug-ins support private PDEV structures by implementing the following methods:

IPrintOemUni::EnablePDEV or IPrintOemPS::EnablePDEV
IPrintOemUni::DisablePDEV or IPrintOemPS::DisablePDEV
IPrintOemUni::ResetPDEV or IPrintOemPS::ResetPDEV

PDEV structure is a generic term. It refers to a private, locally defined structure for use by the module that defines it. Typically it is used for storing physical device characteristics. Each printer driver, and each rendering plug-in, defines its own PDEV structure. There is no globally defined structure of type "PDEV".


Accessing Driver Settings from Rendering Plug-Ins

A rendering plug-in can obtain the current status of printer features and other internal driver information. The following COM interface methods are implemented within Microsoft's printer drivers and can be called by rendering plug-ins:

Methods Implemented by Unidrv
 | IPrintOemDriverUni::DrvGetDriverSetting
 | IPrintOemDriverUni::DrvGetStandardVariable
 | IPrintOemDriverUni::DrvGetGPDData

Methods Implemented by Pscript5
IPrintOemDriverPS::DrvGetDriverSetting


Pscript-Specific Customized Rendering

Pscript5 allows device-specific customized code to inject Postscript commands into the data stream that the Pscript5 driver sends to the printer device. If you want to provide this type of customized code, you must provide a rendering plug-in that implements the IPrintOemPS::Command method.

Pscript5 calls the IPrintOemPS::Command method at a variety of points within the print job's data stream. One of the function's arguments specifies an index value representing the current point in the data stream. Each time the function is called, it can check the index value and either provide additional stream data or not.


Unidrv-Specific Customized Rendering

The following topics provide information about the types of operations that Unidrv allows rendering plug-ins to perform:

Customized Color Formats

Customized Halftoning

Customized Data Stream Compression

Customized Data Stream Filtering

Customized Font Management

Dynamically Generated Printer Commands

Handling Device-Managed Surfaces


Customized Color Formats

Unidrv supports several color formats, which are listed in Handling Color Formats in the section, Microsoft Universal Printer Driver. For these formats, Unidrv converts GDI bitmaps into the correct format before sending it to the printer. If your printer accepts formats not supported by Unidrv, you must provide a rendering plug-in that implements the IPrintOemUni::ImageProcessing method.

If you implement IPrintOemUni::ImageProcessing, and if the user has selected a color format (ColorMode option) that Unidrv cannot handle, then each time a buffer of GDI bitmap data is ready for printing, Unidrv calls the method and passes the bitmap's address as an input argument. The method must convert the bitmap to the specified format, perform customized halftoning operations if necessary, and call the IPrintOemDriverUni::DrvWriteSpoolBuf method to send the modified bitmap to the print spooler. It must also call the IPrintOemDriverUni::DrvXMoveTo and IPrintOemDriverUni::DrvYMoveTo methods to update the cursor position. For more information about these operations, see the description of IPrintOemUni::ImageProcessing.

If a rendering plug-in implements IPrintOemUni::ImageProcessing, it can also implement IPrintOemUni::MemoryUsage.


Customized Halftoning

As explained in Halftoning with Unidrv, in the section Microsoft Universal Printer Driver, Unidrv allows halftoning operations to be performed by GDI, by the printer device, or by customized driver code. This section explains how to perform halftoning operations in customized driver code.

Two types of customization are available:

  • Customized halftone patterns
  • Customized halftoning methods

Customized Halftone Patterns

Halftone patterns can be specified in a resource DLL, or they can be generated by a rendering plug-in that implements the IPrintOemUni::HalftonePattern method. As explained in Halftoning with Unidrv, in the section entitled Microsoft Universal Printer Driver, there are two reasons for implementing IPrintOemUni::HalftonePattern:

  1. Customized patterns are provided in a resource DLL, and the patterns are encrypted.
  2. Customized patterns are not provided in a resource DLL. Instead, they are generated by IPrintOemUni::HalftonePattern.

The IPrintOemUni::HalftonePattern method's purpose is to return a usable halftone pattern to Unidrv, which in turn passes it to GDI. The method can either decode a pattern that is stored in a resource DLL in an encrypted form, or it can generate a pattern during execution.

If you implement the IPrintOemUni::HalftonePattern method, your GPD file must include an *HTCallbackID attribute in each halftoning *Option entry that specifies a halftoning method for which a customized pattern is used. For more information about this attribute, see Option Attributes for the Halftone Feature in Microsoft Universal Printer Driver.

Customized Halftoning Methods

For a printer that uses Unidrv, providing code that implements customized halftoning methods requires the following steps:

  • Provide a rendering plug-in that implements the IPrintOemUni::ImageProcessing method.
  • Include a Halftone *Feature entry in the printer's GPD file, with each contained *Option entry representing a halftoning method. (Standard and customized halftoning methods can both be included.)

The IPrintOemUni::ImageProcessing method receives GDI bitmaps as input. The method must perform halftoning operations, based on the currently selected halftoning method, and return the resulting bitmap to Unidrv.

If a rendering plug-in implements IPrintOemUni::ImageProcessing, it can also implement the IPrintOemUni::MemoryUsage.

For more information about halftoning, see Halftoning with Unidrv in Microsoft Universal Printer Driver.


Customized Data Stream Compression

Unidrv allows data compression operations to be performed by customized code.

To perform customized compression operations, you must do the following:

  • Provide a rendering plug-in that implements the IPrintOemUni::Compression method.
  • Include a CmdEnableOEMComp command entry in the printer's GPD file. For more information about this command, see Raster Data Compression Commands in the section, Microsoft Universal Printer Driver.

The IPrintOemUni::Compression method receives scan line data as input. The method must compress the data and then return the result to Unidrv. The CmdEnableOEMComp command entry specifies the command that must be sent to the printer so the printer can accept the compressed data. For each scan line that is to be sent to the printer, Unidrv calls IPrintOemUni::Compression to compress the scan line data. Then, if this is the only compression method available, Unidrv sends to the printer the command specified by the CmdEnableOEMComp command entry, followed by the compressed data.

If the printer minidriver contains GPD entries that also enable Unidrv-supported compression methods, Unidrv tries each compression algorithm for each scan line and chooses the algorithm that produces the best result. For more information about Unidrv's compression capabilities, see Compressing Raster Data in Microsoft Universal Printer Driver.

Only one customized compression method can be enabled at one time.


Customized Data Stream Filtering

Unidrv allows customized code to perform final post-processing of image data before it is spooled. Such processing might consist of removing adjacent dots, or any other data filtering operation that Unidrv does not provide.

To perform final post-processing of image data, you must provide a rendering plug-in that implements the IPrintOemUni::FilterGraphics method.

The IPrintOemUni::FilterGraphics method receives scan line data as input. The method must process the data and then send it to the print spooler by calling IPrintOemDriverUni::DrvWriteSpoolBuf. If the IPrintOemUni::FilterGraphics method is implemented, Unidrv does not spool printer data. Instead, it sends every data block to the IPrintOemUni::FilterGraphics method.


Customized Font Management

Unidrv supports downloading soft fonts as bitmaps or TrueType outlines, for PCL printers. For device fonts, Unidrv supports PCL, CAPSL, and PPDS printer command formats. For other formats, customized font management code must be provided in a rendering plug-in. The following set of IPrintOemUni methods can be implemented:

IPrintOemUni::DownloadFontHeader
Used for obtaining a soft font's header information from Unidrv and then downloading the information to the printer.
IPrintOemUni::DownloadCharGlyph
Used for downloading a soft font's character glyphs to the printer.
IPrintOemUni::OutputCharStr
Used for controlling the printing of characters.
IPrintOemUni::SendFontCmd
Used for modifying a printer's device font selection command, if necessary, and then sending it to the printer.
IPrintOemUni::TextOutAsBitmap
Used for creating a bitmap image of a text string.
IPrintOemUni::TTDownloadMethod
Used for specifying the glyph format Unidrv should use when sending a specified soft font to the printer.

Unidrv provides a callback function, UNIFONTOBJ_GetInfo, that rendering plug-ins can call to obtain font or glyph information.

For device fonts, font descriptions must be provided in the form of Unidrv Font Metrics files (.ufm files) and Glyph Translation Table files (.gtt files).

For cartridge fonts, font descriptions can be provided in resource DLLs and specified using font cartridge entries in a GPD file. Font descriptions can also be provided in the form of Unidrv Font Format files (.uff files).

For downloadable PCL soft fonts, font descriptions must be provided in the form of Unidrv Font Format files (.uff files).

Unidrv Font Metrics Files

Each device font that a printer supports must be represented by a Unidrv Font Metrics file (.ufm file). A .ufm file is a binary file that is constructed using the structures described in Unidrv Font Metrics Structures in the section, Printer Driver Functions and Structures. The first structure in a .ufm file is UNIFM_HDR, which contains offsets to the file's other structures.

For more information about creating .ufm files, see the Microsoft Minidriver Development Tool.

Unidrv also supports .ifi files, the font metrics files created for Windows NT® 4.0.

Glyph Translation Table Files

Each device font that a printer supports must be represented by a Glyph Translation Table file (.gtt file). A .gtt file is a binary file that is constructed using the structures described in Unidrv Glyph Translation Table Structures in Printer Driver Functions and Structures. The first structure in a .gtt file is UNI_GLYPHSETDATA, which contains offsets to the file's other structures.

For more information about creating .gtt files, see the Microsoft Minidriver Development Tool.

Unidrv also supports glyph translation files created for Windows NT 4.0, which use RLE compression and have an .rle extension.

Unidrv Font Format Files

For cartridge fonts that are not specified using font cartridge entries in a GPD file, the fonts must be described in a Unidrv Font Format file (.uff file). Additionally, downloadable PCL soft fonts must be specified using .uff files.

A .uff file is a binary file that is constructed using the following sets of structures:

  • Unidrv Font Format Structures, which define the contents and structure of a .uff file.
  • Unidrv Font Metrics Structures, which define the metrics for each font.
  • Unidrv Glyph Translation Table Structures, which define the glyph sets used by the fonts.

Additionally, for downloadable PCL soft fonts, the binary data to be downloaded is stored in a .ufm file.

Creating .uff files is the responsibility of vendor-supplied font installation software. Unidrv reads a printer's .uff files to obtain font and glyph information. The font installer should modify .uff file contents when fonts are added or deleted. For more information about creating a font installer, see Customized Font Installers for Unidrv.

All .uff files for all printers must be stored in the %SystemRoot%\System32\Spool\Drivers\Unifont directory. To associate individual .uff files with specific printers, installation software must call the SetPrinterData function (described in the Platform SDK documentation) to create registry values under each printer's registry key. The following table lists the registry value names that must be used, and indicates the maintainer of each value.

Registry Value Name and Type | Value Definition | Maintainer
"ExternalFontFile" REG_SZ | Filename of a .uff file specifying currently installed fonts. Fonts can be downloadable or contained in a cartridge. | Font Installer.
"ExtFontCartFile" REG_SZ | Filename of a .uff file specifying all the fonts contained in all the font cartridges listed for "ExtFontCartNames". | Font Installer.
"ExtFontCartNames" REG_MULTI_SZ | Names of all the font cartridges that could possibly be installed on the printer. | Font Installer.
"FontCart" REG_MULTI_SZ | Names of all the font cartridges currently installed for the printer. | Unidrv user interface.

After adding a font cartridge to a printer, the system administrator must run the font installer, which is responsible for copying font descriptions from the .uff file specified by "ExtFontCartFile" into the .uff file specified by "ExternalFontFile". Likewise, the font installer must remove font descriptions from the .uff file specified by "ExtFontCartFile" when a cartridge is removed.


Dynamically Generated Printer Commands

Each time you specify a printer command in a GPD file for a Unidrv minidriver, you can use one of two methods:

  • Place the command string in the GPD file.

    When you place the command string in a GPD file, Unidrv sends the command to the print spooler at appropriate times. These command strings can include standard variables, which Unidrv evaluates before sending the command.

  • Provide a callback function.

    If you provide a callback function, Unidrv calls the function when it is time to send the command, and the function is responsible for sending the command to the print spooler. This enables you to include code that dynamically generates a command string and then sends it to the printer.

To place a command string in a GPD file, you need to include a *Cmd attribute within the command's *Command entry.

To provide code that dynamically generates a command string, you must do the following:

  • Provide a rendering plug-in that implements the IPrintOemUni::CommandCallback method.
  • Include a *CallbackID command attribute and, optionally, a *Params attribute, within the command's *Command entry in the GPD file.

When Unidrv is ready to issue a printer command, it checks the minidriver database to determine if the command has been specified with a *Cmd attribute or with a *CallbackID attribute. In the former case, Unidrv sends the command string to the print spooler. In the latter case, Unidrv calls the IPrintOemUni::CommandCallback method, passing the *CallbackID and *Params values as input arguments.

Printer commands are discussed in the section, Microsoft Universal Printer Driver. For more information about the *Cmd, *CallbackID, and *Params attributes, see Command Attributes.


Handling Device-Managed Surfaces

When Unidrv renders print page images, it uses GDI-managed drawing surfaces. All images are rendered as bitmaps. For devices providing capabilities that cannot be exploited by this scenario, such as the ability to draw vectors, you can provide customized driver support for a device-managed drawing surface. To support a device-managed surface, you must provide a rendering plug-in that implements the following:

  • A set of hooking functions for all the Unidrv-supported graphics DDI drawing functions. The following functions must be hooked:

    DrvAlphaBlend
    DrvBitBlt
    DrvCopyBits
    DrvDitherColor
    DrvFillPath
    DrvGradientFill
    DrvLineTo
    DrvPlgBlt
    DrvRealizeBrush
    DrvStretchBlt
    DrvStretchBltROP
    DrvStrokeAndFillPath
    DrvStrokePath
    DrvTextOut
    DrvTransparentBlt

  • The IPrintOemUni::EnableDriver method, which is used to provide Unidrv with pointers to the graphics DDI hooking functions.
  • The IPrintOemUni::DriverDMS method, which informs Unidrv that a device-managed surface is to be used, and specifies which of the defined hooking functions will be used for the surface.

The hooking functions cannot call back to GDI's Eng-prefixed support services when drawing on a device-managed surface. However, they can create a temporary bitmap surface, then pass that surface's handle to Eng-prefixed drawing functions (see Rendering a Print Job).

The IPrintOemUni::DriverDMS method is called each time a print job is about to be rendered, so the rendering plug-in can specify the type of rendering surface (GDI-managed or device-managed) for each job. Basing the surface choice on a selectable option in the user interface requires you to also provide a user interface plug-in.

Drawing Text on a Device-Managed Surface

The rendering plug-in must hook out Unidrv's DrvTextOut function (along with all other graphics DDI drawing functions). Creating text for a device-managed surface involves interaction among the following four functions:

  • Unidrv's DrvTextOut function
  • The rendering plug-in's DrvTextOut hooking function
  • Unidrv's IPrintOemDriverUni::DrvUniTextOut method
  • The rendering plug-in's IPrintOemUni::TextOutAsBitmap method

The steps involved in displaying text on a device-managed surface are as follows:

  1. GDI calls Unidrv's DrvTextOut function.
  2. Unidrv calls the rendering plug-in's DrvTextOut hooking function.
  3. The hooking function sends commands to the device to specify the text's brush, rotation, and clip region.
  4. The hooking function calls Unidrv's IPrintOemDriverUni::DrvUniTextOut method, which attempts to use downloaded fonts to output the text. This method also handles glyph-based clipping.
  5. If IPrintOemDriverUni::DrvUniTextOut cannot use a downloadable font (because the font is not available or is rotated), it calls the rendering plug-in's IPrintOemUni::TextOutAsBitmap method, which draws the text as a bitmap.
  6. After IPrintOemDriverUni::DrvUniTextOut returns, the DrvTextOut hooking function must draw underlines and strike-throughs, based on rectangles specified by the DrvTextOut function's prclExtra parameter, using vector commands (if supported).


Implementing Printer Driver COM Interfaces

This section explains how to construct a plug-in, based on DDK-supplied sample code. It also explains the calling sequences used for communication between the printer drivers and plug-ins. The following topics are provided:

Interface Identifiers for Printer Drivers

Creating the Plug-In

Accessing Plug-In Interfaces from Printer Drivers

Accessing Printer Driver Interfaces from Plug-Ins


Interface Identifiers for Printer Drivers

A set of GUIDs is defined in prcomoem.h. Each of these GUIDs is an interface identifier for one of the COM interfaces used for communication between the printer drivers (Unidrv and Pscript5) and plug-ins.

For Windows® 2000 and Windows® XP, the following GUIDs are defined:

IID_IPrintOemUI
IID_IPrintOemUI2 (Pscript5 UI plug-ins on Windows XP and later)
IID_IPrintOemDriverUI
IID_IPrintCoreUI2 (Pscript5 UI plug-ins on Windows XP and later)
IID_IPrintOemUni
IID_IPrintOemUni2 (Unidrv render plug-ins on Windows XP and later)
IID_IPrintOemDriverUni
IID_IPrintOemPS
IID_IPrintOemPS2 (Pscript5 render plug-ins on Windows XP and later)
IID_IPrintOemDriverPS
IID_IPrintCorePS2 (Pscript5 render plug-ins on Windows XP and later)

Each GUID identifies one version of one interface. If a new version of an interface is defined, a new GUID will be added to the list.

User interface plug-ins and rendering plug-ins must identify the interface versions they support. The printer driver (Unidrv or Pscript5) will call a plug-in's IUnknown::QueryInterface method (described in the Platform SDK documentation), specifying an interface identifier as input. If the plug-in supports the specified version, the method must return a pointer to the interface along with a return status of S_OK. Otherwise it must return E_NOINTERFACE. The driver starts with the interface identifier for the most recent version and continues to call QueryInterface with earlier version identifiers until the method returns S_OK or the driver exhausts the list of version identifiers.

Likewise, Unidrv and Pscript5 provide IUnknown::QueryInterface methods for the IPrintOemDriverUI, IPrintCoreUI2, IPrintOemDriverUni, IPrintOemDriverPS, or IPrintCorePS2 COM interfaces. Plug-ins should call the appropriate interface's QueryInterface method to determine the driver's supported interface version and to receive an interface pointer.


Creating the Plug-In

All printer driver plug-ins must define DllMain, DllGetClassObject, and DllCanUnloadNow functions. They must also implement the IClassFactory COM interface and one of the IPrintOemUI, IPrintOemUI2, IPrintOemUni, IPrintOemUni2, IPrintOemPS, or IPrintOemPS2 COM interfaces.

When creating either a user interface plug-in or a rendering plug-in, you should base your code on the sample UI plug-in or the sample rendering plug-in provided in this DDK.

To create either type of plug-in, you must do the following:

  1. Define a DllMain function (described in the Platform SDK documentation).

    This is the entry point for all Win32 DLLs.

  2. Define and export a DllGetClassObject function (described in the Platform SDK documentation).

    The printer driver calls this function to obtain access to the plug-in's implementation of the IClassFactory interface (described in the Platform SDK documentation). When the driver calls DllGetClassObject, it specifies one of the following class identifiers (defined in prcomoem.h):

    CLSID_OEMUI – for UI plug-ins
    CLSID_OEMRENDER – for rendering plug-ins

    The driver also specifies an interface identifier of IID_IClassFactory.

    The DllGetClassObject function must create an instance of its IClassFactory interface and return a pointer to it, as illustrated in the sample code.

  3. Implement the IClassFactory COM interface.

    The IClassFactory interface's CreateInstance method should create an instance of the plug-in's implementation of one of the following COM interfaces:

    IPrintOemUI, IPrintOemUI2, IPrintOemUni, IPrintOemUni2, IPrintOemPS, or IPrintOemPS2

    One of the CreateInstance method's inputs is an interface identifier. The driver calls CreateInstance with an interface identifier of IID_IUnknown, meaning the CreateInstance method must return a pointer to the created instance's IUnknown interface (described in the Platform SDK documentation), as illustrated in the sample code.

  4. Implement one of the IPrintOemUI, IPrintOemUI2, IPrintOemUni, IPrintOemUni2, IPrintOemPS, or IPrintOemPS2 COM interfaces, including the standard IUnknown interface, as illustrated in the sample code.

    The first of the implemented methods to be called by the driver is the IUnknown interface's QueryInterface method (described in the Platform SDK documentation). This method receives one of the interface identifiers for printer drivers as an input argument. The driver calls the method to determine which version of the interface is supported by the plug-in and to receive a pointer to the supported interface.

  5. Define and export a DllCanUnloadNow function (described in the Platform SDK documentation).

    The DllCanUnloadNow function must return S_OK if all instances of the plug-in-implemented IPrintOemUI, IPrintOemUI2, IPrintOemUni, IPrintOemUni2, IPrintOemPS, or IPrintOemPS2 COM interfaces have been released. The S_OK return indicates to the driver that the plug-in can be unloaded.


Accessing Plug-In Interfaces from Printer Drivers

If a UI plug-in or rendering plug-in has been installed, the printer driver (Unidrv or Pscript5) will use the following calling sequence to obtain access to the plug-in's IPrintOemUI, IPrintOemUI2, IPrintOemUni, IPrintOemUni2, IPrintOemPS, or IPrintOemPS2 COM interface:

  1. The driver calls LoadLibrary to load the plug-in DLL, which causes the plug-in's DllMain function to be called.
  2. The driver calls the plug-in's DllGetClassObject function, which returns a pointer to the plug-in's IClassFactory interface.
  3. The driver calls the IClassFactory interface's CreateInstance method, specifying an interface identifier of IID_IUnknown, which causes the method to create an instance of the plug-in's IPrintOemUI, IPrintOemUI2, IPrintOemUni, IPrintOemUni2, IPrintOemPS, or IPrintOemPS2 interface and return a pointer to the instance's IUnknown interface.
  4. The driver calls the IUnknown interface's QueryInterface method to determine which version of the IPrintOemUI, IPrintOemUI2, IPrintOemUni, IPrintOemUni2, IPrintOemPS, or IPrintOemPS2 interface is supported by the plug-in and to receive a pointer to the supported interface.
  5. The driver calls the plug-in interface's PublishDriverInterface method to make the driver's IPrintOemDriverUI, IPrintCoreUI2, IPrintOemDriverUni, IPrintOemDriverPS, or IPrintCorePS2 interface available to the plug-in.
  6. If the plug-in has implemented the IPrintOemUni interface, the driver calls IPrintOemUni::GetImplementedMethod to determine which interface methods have been implemented. Similarly, if the plug-in has implemented the IPrintOemUni2 interface, the driver calls IPrintOemUni2::GetImplementedMethod for the same purpose.


Accessing Printer Driver Interfaces from Plug-Ins

If a plug-in will be calling methods belonging to the driver-supplied IPrintOemDriverUI, IPrintCoreUI2, IPrintOemDriverUni, IPrintOemDriverPS, or IPrintCorePS2 interfaces, it must obtain an interface pointer from the driver as follows:

  1. The plug-in must implement the IPrintOemUI, IPrintOemUI2, IPrintOemUni, IPrintOemUni2, IPrintOemPS, or IPrintOemPS2 interface's PublishDriverInterface method.
  2. When the driver (Unidrv or Pscript5) calls the plug-in's PublishDriverInterface method, it supplies a pointer to the IPrintOemDriverUI, IPrintCoreUI2, IPrintOemDriverUni, IPrintOemDriverPS, or IPrintCorePS2 instance's IUnknown interface.
  3. The plug-in must use the IUnknown interface pointer to call IUnknown::QueryInterface, specifying the interface identifier that represents the desired version of the IPrintOemDriverUI, IPrintCoreUI2, IPrintOemDriverUni, IPrintOemDriverPS, or IPrintCorePS2 interface. (For more information, see Interface Identifiers for Printer Drivers.)
  4. If the plug-in specifies an interface identifier representing an interface version supported by the driver, QueryInterface returns a pointer to the IPrintOemDriverUI, IPrintCoreUI2, IPrintOemDriverUni, IPrintOemDriverPS, or IPrintCorePS2 interface. Note that the driver calls the interface's AddRef method (described in the Platform SDK documentation) before returning the interface pointer to the plug-in. The plug-in should save this pointer so it can be used later to call interface methods.
  5. When the IPrintOemDriverUI, IPrintCoreUI2, IPrintOemDriverUni, IPrintOemDriverPS, or IPrintCorePS2 interface pointer is no longer needed, the plug-in must call the interface's Release method (described in the Platform SDK documentation).


Installing Customized Driver Components

When you provide customized components for Microsoft's printer drivers, you must also provide an .ini file for installation of the component. (If your printer is not supported by ntprint.inf, you must also provide a printer .inf file.)

The .ini file must contain an OEMFiles section. In this section, each customized component is described by using one of the following entries:

OEMDriverFilen
Names a rendering plug-in.
OEMConfigFilen
Names a user interface plug-in.

where n specifies the order in which the installer installs the files. Numbers specified for n must be contiguous, starting with 1, for both types of plug-ins.

For example, if you are providing two rendering plug-ins and one user interface plug-in, and your printer model is XYZ, your .ini file might appear as follows:

[OEMFiles]
OEMDriverFile1=XYZDRV1.DLL
OEMConfigFile1=XYZUI1.DLL
OEMDriverFile2=XYZDRV2.DLL

Spaces are not allowed before or after the equal sign (=). File names cannot include path specifications.

In the example, two rendering plug-ins are specified. Based on the n values for OEMDriverFile n, xyzdrv1.dll is installed before xyzdrv2.dll. The Unidrv and Pscript5 drivers call plug-ins in the order they are installed, so later, when a driver needs to call graphics DDI hooking functions and COM methods supplied by these plug-ins, xyzdrv1.dll will be called before xyzdrv2.dll.

The .ini file name should reflect the printer product name. The .ini filename should be distinct from the names of .ini files for other printers to avoid name conflicts . Note that if you are back-porting a rendering plug-in or user interface plug-in to Windows NT® 4.0, your .ini file name must match your .gpd or .ppd file name. (That is, xyz.ini must be used for xyz.gpd or xyz.ppd.) This restriction does not apply to Windows® 2000 or later operating system versions.

An .ini file can contain either ANSI or UNICODE text, but UNICODE text is recommended. Within an .ini file, lines beginning with the pound sign ( # ) are comments.

For more information about .inf and .ini files, see General Guidelines for INF Files. Also see Installing a Unidrv Minidriver in Microsoft Universal Printer Driver.


Customized Font Installers for Unidrv

Vendor-supplied font installation software is required for cartridge fonts that are not described by font cartridge entries in a printer's GPD file. These fonts must be described using Unidrv Font Format Files (.uff files). Creating .uff files is the responsibility of vendor-supplied font installers.

Vendor-supplied font installers should also provide support for downloadable PCL soft fonts.

The following two techniques are provided for creating a customized font installer:

  • Supplying a user interface plug-in

    This plug-in must implement the following COM interface methods:

    IPrintOemUI::FontInstallerDlgProc
    IPrintOemUI::UpdateExternalFonts

  • Supplying a separate executable file

    During font installation, the executable file must store its name in the registry by calling SetPrinterData (described in the Platform SDK documentation) and specifying a value for the "FontInstaller" key.

Unidrv uses the following algorithm for locating a font installer:

  1. If the name of a font installer executable file has been stored in the registry, Unidrv does not allow the system administrator to select font installation operations from the printer's property sheet. Instead, the administrator must run the supplied executable file.
  2. If an installer executable file is not available, Unidrv enables selection of font installation operations Unidrv from the printer's property sheet. Unidrv determines if a user interface plug-in has been installed. If so, its font installation methods are called. If a user interface plug-in has not been installed, or if its font installation methods return E_NOTIMPL, the driver uses its own fault installer.


Customizing Print Spooler Components

This section explains how to customize print spooler components. The following topics are provided:

Writing a Print Processor

Writing a Print Monitor

Writing a Network Print Provider


Writing a Print Processor

This section provides the following topics:

Introduction to Print Processors

Sample Print Processor

Functions Defined by Print Processors

Processing a Print Job

Installing a Print Processor


Introduction to Print Processors

Print processors are user-mode DLLs that are responsible for converting a print job's spooled data into a format that can be sent to a print monitor. They are also responsible for handling application requests to pause, resume and cancel print jobs.

The print job's spooled data is contained in a spool file. The print processor reads the file, performs conversion operations on the data stream, and writes the converted data to the spooler. The spooler then sends the data stream to the appropriate print monitor.

Microsoft® Windows® 2000 and later includes the print processors listed in the following table.

Print Processor | Input Data Types | Output Data Types
winprint.dll | EMF RAW TEXT | RAW
sfmpsprt.dll | PSCRIPT1 | RAW

For information about the data types, see the following topics:

EMF Data Type

RAW Data Type

TEXT Data Type

PSCRIPT1 Data Type

You can create a customized print processor to support a data type that is not supported by Windows 2000 or later operating system version. You can also provide a customized print processor that supports one or more of the supported data types, thus allowing you to modify the capabilities provided by the supplied print processors.

Print processors are associated with printer drivers during driver installation, so multiple print processors supporting the same data type can coexist. For more information, see Installing a Print Processor.


EMF Data Type

Enhanced Metafile (EMF) data consists of instructions to call GDI functions. The print processor must call the GDI functions to render printable images. The GDI functions make calls to the printer driver's printer graphics DLL, which renders the image and sends it to the spooler as RAW data (by calling EngWritePrinter).

NT-based operating system clients send EMF data to NT-based operating system print servers. EMF data is device independent and can be sent to a server more quickly than RAW data. A print job is also spooled as EMF data when the requesting application is local to the server, allowing a quick return to the application while the EMF data is subsequently rendered by a background spooler thread.

For more information about the EMF data type, see the Windows 2000 Professional Resource Kit or the Windows 2000 Server Resource Kit. For more information about enhanced metafiles, see the Platform SDK documentation.


RAW Data Type

RAW data can be sent to a print monitor without further processing. The print processor just sends this data back to the spooler (by calling WritePrinter, described in the Platform SDK documentation), sometimes inserting form feeds. An example of a RAW data file is one consisting of PCL commands. Print jobs are sent from client to server in RAW format if either the client or the server does not support NT-based-operating system EMF, or if a server administrator has disabled EMF support. In such cases, image rendering is performed on the client before the job is sent to the server.

(Postscript commands can be considered RAW data if the target printer supports Postscript. On the other hand, the sfmpsprt.dll print processor takes Postscript input and interprets it for non-Postscript printers, so in that case the Postscript is not RAW data.)

For more information about the RAW data type, see the Windows 2000 Professional Resource Kit or the Windows 2000 Server Resource Kit.


TEXT Data Type

TEXT data consists solely of ANSI text. The print processor calls GDI to draw characters using the print device's default font, and sends the resulting RAW-formatted output to the spooler (by calling WritePrinter, described in the Platform SDK documentation). The process is equivalent to opening the input file with Notepad and then printing the file. (This format is used for printers that don't print text characters.)

For more information about the TEXT data type, see the Windows 2000 Professional Resource Kit or the Windows 2000 Server Resource Kit.


PSCRIPT1 Data Type

PSCRIPT1 data is Postscript data that is targeted for printing on a non-Postscript printer. The print processor interprets the Postscript commands and writes the resulting RAW-formatted output to a file.

For more information about the PSCRIPT1 data type, see the Windows 2000 Professional Resource Kit or the Windows 2000 Server Resource Kit.


Sample Print Processor

Source code for genprint.dll, a sample print processor that accepts EMF data, RAW data, and TEXT data as input, is included in this DDK. The code is located in the genprint subdirectory of the directory tree containing DDK samples.


Functions Defined by Print Processors

Print processors must export the functions listed in the following table.

Function Name | Description
ClosePrintProcessor | Closes the print processor.
ControlPrintProcessor | Provides control over printing a document.
EnumPrintProcessorDatatypes | Enumerates the data types supported by a print processor.
GetPrintProcessorCapabilities | Returns print processor capabilities for a specified input data type.
OpenPrintProcessor | Opens the print processor for printing.
PrintDocumentOnPrintProcessor | Prints a document on the print processor.


Processing a Print Job

When the spooler is ready to send a print job to a print processor, it calls the print processor's OpenPrintProcessor function. This function performs initialization activities and returns a handle.

The spooler can then call PrintDocumentOnPrintProcessor, which is the print processor function that converts the data stream from the input format to the output format and returns the converted stream to the spooler.

If the input format is NT-based-operating system EMF, the PrintDocumentOnPrintProcessor function can control the playback of the EMF records by using GDI functions for print processors. These functions provide an interface between the print processor and the printer driver. This interface allows print processors to control the physical layout of printer pages and thus facilitates implementing such features as printing multiple document pages per physical page ("N-up" printing), printing pages in reverse order, and printing multiple copies of each page.

A print processor's output data stream must be returned to the spooler. Typically, if the data conversion requires interaction with the printer driver's printer graphics DLL (as is the case for EMF input data), the graphics DLL returns the stream to the spooler by calling EngWritePrinter. On the other hand, if the conversion does not call the printer graphics DLL (as is the case for RAW input data), then the print processor calls WritePrinter (described in the Platform SDK documentation).

The PrintDocumentOnPrintProcessor function can be interrupted by asynchronous calls from the spooler to the print processor's ControlPrintProcessor function. This function implements an application's ability to pause, resume, or cancel a print job.

After PrintDocumentOnPrintProcessor finishes converting the data stream and returns, the spooler calls the print processor's ClosePrintProcessor function.


Using GDI Functions for Print Processors

A set of user-mode GDI functions is exported by gdi32.dll, for use by print processors that handle NT-based-operating system EMF as an input format. The following table lists the functions that are provided.

Function Name | Description
GdiDeleteSpoolFileHandle | Releases a spool file handle.
GdiEndDocEMF | Completes EMF playback operations for a print job document.
GdiEndPageEMF | Completes EMF playback operations for a physical page, and ejects the page from the printer.
GdiGetDC | Returns a handle to the printer's device context.
GdiGetDevmodeForPage | Returns a document page's DEVMODE structure.
GdiGetPageCount | Returns the number of document pages.
GdiGetPageHandle | Returns a handle to a document page.
GdiGetSpoolFileHandle | Returns a spool file handle, required as input to the other GDI functions.
GdiPlayPageEMF | Plays the EMF records associated with a document page.
GdiResetDCEMF | Resets a printer's device context.
GdiStartDocEMF | Performs initialization operations for the print job document.
GdiStartPageEMF | Performs initialization operations for a physical page.

An EMF print processor's PrintDocumentOnPrintProcessor should call GdiGetSpoolFileHandle to obtain a spool file handle and GdiGetDC to obtain the printer's device context handle. Then it can perform the following steps:

  • For each print job document, GdiStartDocEMF must be called before any EMF records are played and GdiEndDocEMF must be called after the last EMF record has been played.
  • For each physical page to be printed, GdiStartPageEMF must be called before any document pages are drawn on the page, and GdiEndPageEMF must be called after the last document page has been drawn on the physical page.
  • For each document page to be drawn on a physical page, GdiGetDevmodeForPage must be called to determine if the DEVMODE structure contents have changed since the last document page was drawn. If the DEVMODE has changed, a new physical page must be started (by calling GdiEndPageEMF and GdiStartPageEMF), and the printer's device context must be updated by calling GdiResetDCEMF. A document page is drawn on a physical page by first calling GdiGetPageHandle to obtain a document page handle, and then calling GdiPlayPageEMF to draw the page.

After the job has been completely drawn, the print processor must call GdiDeleteSpoolFileHandle.

If a print processor requires the total page count before it can begin printing pages (such as for printing pages in reverse order) it can call GdiGetPageCount, but this function doesn't return until spooling ends and thus disables the ability to print while spooling.

If a print processor uses these GDI functions, its EnumPrintProcessorDatatypes function must return "NT EMF" as a supported data type, which represents generic Windows 2000 and later EMF format. The print processor must not modify EMF records.


Installing a Print Processor

To install a print processor, an installation application must call the spooler's AddPrintProcessor function, which is described in the Platform SDK documentation.

To associate a print processor with a printer driver, its file name must be listed in an .inf file by using a PrintProcessor entry. This entry must be included for every printer driver to which the print processor is to be associated. For more information, see Printer INF Files.

When an installation application calls the spooler's AddPrinter function, specifying a PRINTER_INFO_2 structure as an input argument, it specifies the print processor name (obtained from the .inf file) as a structure member. (The AddPrinter function and PRINTER_INFO_2 structure are described in the Platform SDK documentation.)


Writing a Print Monitor

Print monitors are responsible for directing a print data stream from the print spooler to an appropriate port driver. Two types of print monitors are defined — language monitors and port monitors. This section describes both monitor types, and provides design and implementation guidelines.

The following topics are provided:

Language Monitors

Port Monitors

Language and Port Monitor Interaction

Functions Defined by Print Monitors

Initializing a Print Monitor

Opening and Closing a Port

Printing a Print Job

Managing a Port

TCPMON Xcv Interface

Converting Print Monitors for Use with Clustered Print Servers

Installing a Print Monitor


Language Monitors

Language monitors are user-mode DLLs that serve two purposes:

  • They provide a full duplex communications path between the print spooler and bi-directional printers that are capable of providing software-accessible status information.
  • They add printer control information, such as commands defined by a printer job language, to the data stream.

Microsoft provides a language monitor, pjlmon.dll, which supports Printer Job Language (PJL), and provides bi-directional communication for PJL printers. This monitor is included in the DDK as the sample language monitor.

Customized language monitors can be written to support other job control languages, for uni-directional or bi-directional printers.

Language monitors are optional and only associated with a particular printer type if included in the printer's .inf file, as described in Installing a Print Monitor.

If a language monitor is associated with a printer, the language monitor receives the printer's data stream from the print processor, modifies it, and passes it to the printer's port monitor. For more information, see Language and Port Monitor Interaction.


Sample Language Monitor

Source code for pjlmon.dll, the language monitor that supports bi-directional PJL language support, is included in this DDK. The code is located in the \pjlmon subdirectory of the directory tree containing DDK samples.


Port Monitors

Port monitors consist of user-mode DLLs. They are responsible for providing a communications path between the user-mode print spooler and the kernel-mode port drivers that access I/O port hardware. A port monitor typically uses the CreateFile, WriteFile, ReadFile, and DeviceIOControl functions, described in the Platform SDK documentation, to communicate with kernel-mode port drivers. Port monitors are also responsible for management and configuration of a server's printer ports, as described in Managing a Port.

An NT-based-operating system user's view of a "printer" is really a print queue, to which one or more physical printer devices can be connected. A port is the physical connection between the print queue and a single printer device. Each port monitor supports one or more instances of one or more types of ports. For example localmon.dll, the sample port monitor, can support all of a server's local COM and LPT ports. (The print folder assigns ports to port monitors by calling the Platform SDK documentation's AddPrinter function.)

For print queues representing multiple printer devices (through multiple ports), the spooler sends each print job to the first available port. If the port monitor indicates that a specified port is busy or has encountered an error, the spooler resubmits the job to the queue, specifying another port supported by the port monitor.

Besides localmon.dll, Windows 2000 and later provides several additional port monitors. The Windows NT Server Resource Kit describes each of these port monitors.

Customized port monitors can be written to support additional types of I/O port hardware.

For Windows 2000 and later, each port monitor is divided into two DLLs:

Port Monitor UI DLL
A port monitor's user interface DLL contains user interface functionality and executes on print client systems.

This DLL must reside in the client system's System32 sub-directory.

Port Monitor Server DLL
A port monitor's server DLL contains port communications functionality and executes on print servers. It must not display a user interface.

The UI DLL communicates with the server DLL by calling the spooler's XcvData function.

A sample port monitor is included in this DDK.


Sample Port Monitor

Source code for localmon.dll, the port monitor that supports local LPT and COM ports, is included in this DDK. The code is located in the localmon and localui subdirectories of the directory tree containing DDK samples.


Language and Port Monitor Interaction

The following illustration demonstrates the path taken by printer data from the print processor to a printer that a) has a language monitor associated with it; and b) does not have a language monitor associated with it.

Printer Data Path with a Language Monitor and without a Language Monitor

If a language monitor is associated with a printer during the printer's installation, the language monitor receives the printer's data stream from the spooler's print processor. The language monitor modifies the data stream and passes it to the printer's port monitor.

Most of the functions defined by print monitors are the same for language monitors and port monitors. Typically, if a language monitor is in the data stream path, the spooler calls the language monitor's implementation of a function and the language monitor calls the port monitor's implementation of the same function. For example, the WritePort function in the PJL language monitor (pjlmon.dll) adds PJL commands to the data stream and then calls the port monitor's WritePort to send the stream to the port driver.

If a language monitor is not installed, the spooler calls the port monitor's implementation of the function.

Because language monitors and port monitors are discrete components of the printing architecture, customized and Microsoft-supplied monitors can be used together. Thus, you can provide a customized language monitor that works in conjunction with a Microsoft-supplied port monitor, and vice versa.

You can also provide a single print monitor consisting of a combined language and port monitor.


Combined Language and Port Monitor

Specialized printer hardware can be supported by a single customized print monitor that acts as a combined language and port monitor. If such a monitor requires user interaction to obtain configuration parameters, it must be divided into a UI DLL and a server DLL, following the model for port monitors. Language-related functionality belongs in the server DLL.

A combined monitor's UI DLL must define port monitor client DLL functions. Its server DLL must define both port monitor server DLL functions and language monitor functions.


Functions Defined by Print Monitors

The following sections list the functions that must be defined within print monitor DLLs.

Language Monitor Functions

Port Monitor Client DLL Functions

Port Monitor Server DLL Functions


Language Monitor Functions

The following table lists the functions that a language monitor must define.

Function Name | Description
DllEntryPoint | DLL entry point, typically called DLLMain, which is described in the Platform SDK documentation.
ClosePort | Closes a port when there are no printers connected to it.
EndDocPort | Performs end-of-print-job tasks on a port.
GetPrinterDataFromPort | (Optional.) Polls a port for values that are stored in the registry.
InitializePrintMonitor2 | Initializes the print monitor and returns an instance handle.
OpenPortEx | Opens a port for a newly connected printer.
ReadPort | Reads data from a printer port.
StartDocPort | Performs the tasks required to start a print job on a port.
WritePort | Writes data to a printer port.


Port Monitor Client DLL Functions

The following table lists the functions that a port monitor UI DLL must define.

Function Name | Description
DllEntryPoint | DLL entry point, typically called DLLMain, which is described in the Platform SDK documentation.
AddPortUI | Creates a port and obtains configuration information by displaying a dialog box.
ConfigurePortUI | Configures a previously added port.
DeletePortUI | Deletes a port.
InitializePrintMonitorUI | Initializes the port monitor UI DLL.


Port Monitor Server DLL Functions

The following table lists the functions that a port monitor server DLL must define.

Function Name | Description
DllEntryPoint | DLL entry point, typically called DLLMain, which is described in the Platform SDK documentation.
ClosePort | Closes a port if there are no printers connected to it.
EndDocPort | Performs end-of-print-job tasks on a port.
EnumPorts | Enumerates the ports available for printing on a server.
GetPrinterDataFromPort | (Optional.) Sends an I/O control code to a port driver, and returns the result.
InitializePrintMonitor2 | Initializes the print monitor and returns an instance handle.
OpenPort | Opens a printer port.
ReadPort | Reads data from a printer port.
SetPortTimeOuts | (Optional.) Sets a time-out value on an open port.
StartDocPort | Performs the tasks required to start a print job on a port.
WritePort | Writes data to a printer port.
XcvClosePort | Closes a port after port management is complete.
XcvDataPort | Handles port management tasks.
XcvOpenPort | Opens a port for management purposes.


Initializing a Print Monitor

When the spooler calls LoadLibrary to load a print monitor DLL, the system immediately calls the DLL's DllEntryPoint function. It is generally a good idea for the entry point function to call DisableThreadLibraryCalls, described in the Platform SDK documentation, so the DLL will not be unnecessarily notified when threads are created and deleted.

Each DLL exports an initialization function, which the spooler calls after calling LoadLibrary. Language monitor DLLs and port monitor server DLLs export an InitializePrintMonitor2 function. Port monitor UI DLLs export an InitializePrintMonitorUI function.

These two initialization functions are responsible for returning pointers to the rest of the functions defined by print monitors, so the spooler can call them. The initialization functions can also perform load-time initialization operations. The monitor's InitializePrintMonitor2 function returns a monitor instance handle. The monitor should allocate local memory to store instance-specific information, and use the monitor handle as an identifier for the allocated memory.

When the spooler is first started, it loads all of the monitor DLLs that have been installed. After calling all monitor initialization functions, the spooler calls each port monitor's EnumPorts function, which enumerates the ports supported by the monitor. (A monitor supports a port if the port has been added to the monitor's database, as described in Adding a Port.) Each supported port is then opened, as described in Opening and Closing a Port.


Opening and Closing a Port

After a port has been added, as described in Adding a Port, the spooler can open it by calling the appropriate language monitor's OpenPortEx function.

The language monitor uses the OpenPortEx function to create and return a port handle. Typically, a language monitor calls its associated port monitor's OpenPort function, and the language monitor just returns the handle obtained from the port monitor's OpenPort.

If a language monitor is not associated with a port, the spooler calls the port monitor's OpenPort function directly.

The spooler does not allow more than one path to a port to be enabled at one time. Thus, after it as called OpenPortEx (or OpenPort) in a particular monitor, it will not attempt to open the same port again before closing it.

After a port has been opened, the spooler can call additional functions to print a job, as described in Printing a Print Job, using the port handle as an input argument. A monitor should be written so that, after a port has been opened, the spooler can send multiple print jobs before closing the port.

The spooler closes a port if a job must be sent through a different language monitor, if no print queues are associated with a port, or when the system shuts down. To close a port, the spooler calls a language monitor's ClosePort function. The function invalidates the handle that was created when the port was opened. A language monitor typically calls the ClosePort function defined by its associated port monitor.

If a language monitor is not associated with a port, the spooler calls the port monitor's ClosePort function directly.


Printing a Print Job

After a port has been opened, as described in Opening and Closing a Port, the spooler can send print jobs to the port.

Each print job is delimited by spooler calls to a language or port monitor's StartDocPort and EndDocPort functions. The spooler calls these functions when a print processor calls the spooler's StartDocPrinter and EndDocPrinter functions, which are described in the Platform SDK documentation. Within the scope of a set of StartDocPort and EndDocPort functions, unlimited spooler calls to a monitor's WritePort, ReadPort, and GetPrinterDataFromPort functions can occur.

Each of these functions requires the port handle returned by OpenPortEx (or OpenPort) to be specified as in input argument. Typically, a language monitor implements each of the functions by calling the like-named function in its associated port monitor.

When the spooler calls a language monitor's WritePort function to send a data stream to the port, the function generally adds language-specific information, such as PJL commands, to the received data stream before passing it to the associated port monitor's WritePort function.

The ReadPort function is used for obtaining status information from bi-directional printer hardware, which a language monitor might send to the spooler by calling SetPort, described in the Platform SDK documentation. The spooler does not call the ReadPort function.

If printing hardware is bi-directional, both its language monitor and its port monitor should support a GetPrinterDataFromPort function. A language monitor's GetPrinterDataFromPort function should accept a registry value name as input, obtain a value for that name (generally by calling associated port monitor's WritePort and ReadPort functions), and return the value to the caller. A port monitor's GetPrinterDataFromPort function should accept an I/O control code as input, call DeviceIoControl (described in the Platform SDK documentation) to pass the control code to the port driver, and return the result.


Managing a Port

Port management activities consist of adding a port, configuring a port, and deleting a port in response to requests from applications (such as the print folder). These port management activities are handled by port monitors, not language monitors, and require Administrator privilege. There are special rules for storing port configuration information.

One additional, optional management activity involves Setting Port Timeout Values.


Adding a Port

Adding a port consists of storing the port's name and user-modifiable configuration information inside the port monitor server DLL's local storage or in the registry.

When an application calls the print spooler's AddPort function (described in the Platform SDK documentation), it specifies the name of a port monitor as a function argument. The spooler calls the AddPortUI function contained in the port monitor UI DLL of the specified port monitor.

The port monitor UI DLL's AddPortUI function should perform the following operations:

  1. Call the print spooler's OpenPrinter function (described in the Platform SDK documentation), which causes the XcvOpenPort function in the port monitor server DLL to be called.
  2. Call the print spooler's XcvData function several times, to request the port monitor server DLL to add the port and to transfer configuration information between the UI DLL and the server DLL. The XcvData function calls the server DLL's XcvDataPort function. The AddPortUI function typically obtains configuration information from the user by displaying dialog boxes.
  3. Call the print spooler's ClosePrinter function (described in the Platform SDK documentation), which causes the XcvClosePort function in the port monitor server DLL to be called.

For more information about these operations, see the description of AddPortUI. Also see Storing Port Configuration Information.

A port monitor's EnumPorts function must enumerate all ports that have been added. The spooler can call each port monitor's EnumPorts function to determine the set of ports supported on a print server.


Configuring a Port

Configuring a port consists of modifying a port monitor server DLL's stored configuration information for a previously-added port.

When an application calls the print spooler's ConfigurePort function (described in the Platform SDK documentation), the ConfigurePort function calls the ConfigurePortUI function contained in the port monitor UI DLL of the appropriate port monitor.

The port monitor UI DLL's ConfigurePortUI function should perform the following operations:

  1. Call the print spooler's OpenPrinter function (described in the Platform SDK documentation), which causes the XcvOpenPort function in the port monitor server DLL to be called.
  2. Call the print spooler's XcvData function one or more times, to transfer configuration information between the UI DLL and the server DLL. The XcvData function calls the server DLL's XcvDataPort function. The ConfigurePortUI function typically obtains configuration information from the user by displaying dialog boxes.
  3. Call the print spooler's ClosePrinter function (described in the Platform SDK documentation), which causes the XcvClosePort function in the port monitor server DLL to be called.

For more information about these operations, see the description of ConfigurePortUI. Also see Storing Port Configuration Information.


Deleting a Port

Deleting a port consists of removing the port's stored name and user-modifiable configuration information from the port monitor server DLL's local storage or from the registry.

When an application calls the print spooler's DeletePort function (described in the Platform SDK documentation), the DeletePort function calls the DeletePortUI function contained in the port monitor UI DLL of the appropriate port monitor.

The port monitor UI DLL's DeletePortUI function should perform the following operations:

  1. Call the print spooler's OpenPrinter function (described in the Platform SDK documentation), which causes the XcvOpenPort function in the port monitor server DLL to be called.
  2. Call the print spooler's XcvData function one or more times, to request the port monitor server DLL to delete the port. The XcvData function calls the server DLL's XcvDataPort function.
  3. Call the print spooler's ClosePrinter function (described in the Platform SDK documentation), which causes the XcvClosePort function in the port monitor server DLL to be called.

For more information about these operations, see the description of DeletePortUI.


Setting Port Timeout Values

If you are writing a port monitor for a port that has modifiable time-out values, the time-out values should be initialized from within the monitor's OpenPort function. For example the OpenPort function in localmon.dll, the sample port monitor, calls the SetCommTimeouts function, described in the Platform SDK documentation, for this purpose.

Additionally, a port monitor can optionally provide a SetPortTimeOuts function, which can be called by language monitors. The function is called by pjlmon.dll, the sample language monitor. The print spooler does not call SetPortTimeOuts.


Storing Port Configuration Information

The Windows® 2000 and later print spooler can operate in either a clustered or non-clustered server environment. When the spooler is operating in a server cluster, print monitor configuration information must be stored in the cluster registry. On the other hand, if the spooler is operating on a single, non-clustered server system, print monitor configuration information must be stored in the server's local registry.

The print spooler defines a set of registry functions for use by print monitors. These functions direct configuration data to the appropriate registry, so the print monitor does not have to determine if the server is clustered. Print monitors must not use the Win32 registry API or the cluster registry API directly; all configuration data must be stored and accessed using the spooler's registry functions. Addresses of these functions are supplied to the print monitor in a MONITORREG structure when the spooler calls the monitor's InitializePrintMonitor2 function.

In a server cluster, multiple instances of the spooler can coexist. Specifically, each cluster node possesses its own instance, and an additional instance exists for the cluster itself. One of the input parameters of the spooler registry functions is a spooler handle. This handle is received by the monitor's InitializePrintMonitor2 function and identifies the spooler instance (node or cluster) that has opened the monitor. Using the spooler handle, the spooler registry functions maintain subkeys for each spooler instance.


TCPMON Xcv Interface

This section describes the transceive (Xcv) interface for the standard TCP/IP port monitor (TCPMON). This interface, which is implemented using XcvData and XcvDataPort function calls, enables those using it to configure a TCP/IP printer port or to obtain information about a TCP/IP printer port configuration. The Xcv interface described in this section is specific to TCP/IP ports. Other Xcv interfaces might be available for other port types.

To obtain a handle to an Xcv interface for either a local machine or a remote machine, call the OpenPrinter function (described in the Platform SDK documentation). The following code sample illustrates how to obtain an Xcv handle to a port:

HANDLE hXcv = INVALID_HANDLE_VALUE;
PRINTER_DEFAULTS Defaults = { NULL, NULL, <Required Access> };

// Handle to a local machine
if (OpenPrinter(",XcvPort <PortName>", &hXcv, &Defaults ) {
// hXvc contains an Xcv data handle to a local TCPMON port
}

// Handle to a remote machine
if (OpenPrinter("<ServerName>\\,XcvPort <PortName>", &hXcv, &Defaults ) {
// hXvc contains an Xcv data handle to a TCPMON port on <ServerName>
}

In the code samples, ServerName and PortName represent server and port name strings. Once you have obtained the handle, you can query information that is specific to the TCPMON port monitor, or you can change the port configuration. Note that the access you require for the port monitor must be specified in the DesiredAccess member of the PRINTER_DEFAULTS structure (or pass NULL if no special security is required). For certain calls to the XcvData function (such as when the AddPort and DeletePort commands are specified — see TCPMON Xcv Commands), SERVER_ACCESS_ADMINISTER privilege is required. For details about the OpenPrinter function and the access rights that may be requested in the PRINTER_DEFAULTS structure, see the Platform SDK documentation.

If the port does not yet exist, the Xcv handle can be obtained from the server by specifying the monitor name. (In the case of the standard TCP/IP port monitor port, this is "Standard TCP/IP Port".) The following code sample illustrates how to obtain an Xcv data handle to a port monitor:

HANDLE hXcv = INVALID_HANDLE_VALUE;
PRINTER_DEFAULTS Defaults = { NULL, NULL, <Required Access> };

// Handle to a local machine
if (OpenPrinter(",XcvMonitor <MonitorName>", &hXcv, &Defaults ) {
// hXcv contains an Xcv data handle to the monitor <MonitorName>
}

// Handle to a remote machine
if (OpenPrinter("<ServerName>\\,XcvMonitor <MonitorName>", &hXcv, &Defaults ) {
// hXcv contains an Xcv data handle to the monitor
// <MonitorName> on the server <ServerName>
}

In the code samples, ServerName and PortName represent server and port name strings. Once you have obtained the Xcv data handle, you can issue instructions and requests to the monitor by calling the XcvData function.

Note that the return value from the XcvData function indicates only whether the data was correctly sent to the port monitor. A return value of TRUE does not indicate that the operation was successful. To determine whether the operation was successful, inspect the value in *pdwStatus. These status values are summarized in the following table:

Status Value | Meaning
NO_ERROR | The operation was successful.
ERROR_ACCESS_DENIED | The user has insufficient privileges. The command requires SERVER_ACCESS_ADMINISTER privilege.
ERROR_INSUFFICIENT_BUFFER | An output buffer is required, but is smaller than required.
ERROR_INVALID_DATA | An input buffer is required, but the pointer to it is NULL, or the size of the input buffer is smaller than required.
ERROR_INVALID_HANDLE | The Xcv data handle is invalid.
ERROR_INVALID_LEVEL | The input or output data structure is not the correct version.
ERROR_INVALID_PARAMETER | An output buffer is required, but it is NULL, or the output required parameter is NULL and the output buffer is too small, or the standard TCP/IP port monitor does not understand the command being issued.


TCPMON Xcv Commands

This section describes the commands that can be specified in a call to the XcvData or XcvDataPort function, when it is communicating with the standard TCP/IP port monitor (TCPMON). Each command is specified by the pszDataName string in the call to these functions. Certain commands require an input buffer, or an output buffer, or both. The pInputData and pOutputData parameters of these functions hold the addresses of these buffers.

The table that appears in the description of each of the following commands lists the XcvData and XcvDataPort parameters that are used with the commands. Note that the hXcv parameter (common to both functions) is not listed, nor is the XcvData function's pdwStatus parameter.

AddPort Command

The AddPort command adds a standard TCP/IP port, which can be either an LPR port or a RAW TCP/IP port.

XcvData Parameter | Value
pszDataName | L"AddPort"
pInputData | Address of a PORT_DATA_1 structure
cbInputData | sizeof(PORT_DATA_1)
pOutputData | NULL
cbOutputData | 0
pcbOutputNeeded | NULL

XcvData returns NO_ERROR if it can add the port. In addition to the normal error codes, XcvData returns ERROR_ACCESS_DENIED if the user has insufficient privileges to create a port on the server. This command requires SERVER_ACCESS_ADMINISTER privilege. If the pInputData parameter is NULL, the function returns ERROR_INVALID_DATA. If pInputData—>dwVersion is not equal to 1, the function returns ERROR_INVALID_LEVEL.

ConfigPort Command

The ConfigPort command configures an existing standard TCP/IP port monitor port.

XcvData Parameter | Value
pszDataName | L"ConfigPort"
pInputData | Address of a PORT_DATA_1 structure
cbInputData | sizeof(PORT_DATA_1)
pOutputData | NULL
cbOutputData | 0
pcbOutputNeeded | NULL

XcvData returns NO_ERROR if it can configure the port. In addition to the normal error codes, XcvData returns ERROR_ACCESS_DENIED if the caller has insufficient privileges to perform the request. This command requires SERVER_ACCESS_ADMINISTER privilege. If the pInputData parameter is NULL, or the value in cbInputData is smaller than required, the function returns ERROR_INVALID_DATA. If pInputData—>dwVersion is not equal to 1, the function returns ERROR_INVALID_LEVEL.

DeletePort Command

The DeletePort command deletes a port from the standard TCP/IP port monitor.

XcvData Parameter | Value
pszDataName | L"DeletePort"
pInputData | Address of a DELETE_PORT_DATA_1 structure
cbInputData | sizeof(DELETE_PORT_DATA_1)
pOutputData | NULL
cbOutputData | 0
pcbOutputNeeded | NULL

XcvData returns NO_ERROR if the port is successfully deleted. In addition to the normal error codes, XcvData returns ERROR_ACCESS_DENIED if the caller has insufficient privileges on the server. This command requires SERVER_ACCESS_ADMINISTER privilege. If the pInputData parameter is NULL, or if the cbInputData parameter is smaller than required, the function returns ERROR_INVALID_DATA. If pInputData—>dwVersion is not equal to 1, the function returns ERROR_INVALID_LEVEL.

GetConfigInfo Command

The GetConfigInfo command obtains the configuration information of a particular port. In this case, the Xcv data handle must point to a particular standard TCP/IP port monitor port so that the port can be identified.

XcvData Parameter | Value
pszDataName | L"GetConfigInfo"
pInputData | Address of a CONFIG_INFO_DATA_1 structure
cbInputData | sizeof(CONFIG_INFO_DATA_1)
pOutputData | Address of a PORT_DATA_1 structure
cbOutputData | sizeof(PORT_DATA_1)
pcbOutputNeeded | Address of a DWORD containing the number of bytes needed for the buffer pointed to by pOutputData

XcvData returns NO_ERROR if it can obtain the configuration information for the port. If pInputData is NULL, or if cbInputData is smaller than required, the function returns ERROR_INVALID_DATA. If pInputData—>dwVersion is not equal to 1, the function returns ERROR_INVALID_LEVEL. If cbOutputData is smaller than required, the function returns ERROR_INVALID_PARAMETER when pcbOutputNeeded is NULL, and ERROR_INSUFFICIENT_BUFFER when pcbOutputNeeded is nonNULL.

HostAddress Command

The HostAddress command gets the name of the printer's host.

XcvData Parameter | Value
pszDataName | L"HostAddress"
pInputData | NULL
cbInputData | 0
pOutputData | Address of a buffer that will receive a string containing the printer's host name
cbOutputData | Size of the buffer pointed to by pOutputData
pcbOutputNeeded | Address of a DWORD containing the number of bytes needed for the buffer pointed to by pOutputData

XcvData returns NO_ERROR if it can obtain the name of the printer's host. If cbOutputData is smaller than required, the function returns ERROR_INVALID_PARAMETER when pcbOutputNeeded is NULL, and ERROR_INSUFFICIENT_BUFFER when pcbOutputNeeded is nonNULL. If pOutputData is NULL, the function returns ERROR_INVALID_PARAMETER.

IPAddress Command

The IPAddress command gets the printer's IP address.

XcvData Parameter | Value
pszDataName | L"IPAddress"
pInputData | NULL
cbInputData | 0
pOutputData | Address of a buffer that will receive a string containing the printer's IP address
cbOutputData | Size of the buffer pointed to by pOutputData
pcbOutputNeeded | Address of a DWORD containing the number of bytes needed for the buffer pointed to by pOutputData

XcvData returns NO_ERROR if it can obtain the printer's IP address. If cbOutputData is smaller than required, the function returns ERROR_INVALID_PARAMETER when pcbOutputNeeded is NULL, and ERROR_INSUFFICIENT_BUFFER when pcbOutputNeeded is nonNULL. If pOutputData is NULL, the function returns ERROR_INVALID_PARAMETER.

MonitorUI Command

The MonitorUI command gets the name of the port monitor UI DLL that provides an interface to TCPMON.

XcvData Parameter | Value
pszDataName | L"MonitorUI"
pInputData | NULL
cbInputData | 0
pOutputData | Address of a buffer that will receive the name of the port monitor user interface DLL
cbOutputData | Number of bytes in the string containing the name of the port monitor user interface DLL
pcbOutputNeeded | Address of a DWORD containing the number of bytes needed for the buffer pointed to by pOutputData

XcvData returns NO_ERROR if it is able to obtain the name of the user interface DLL. In addition to the normal error codes, XcvData returns ERROR_ACCESS_DENIED if the caller has insufficient privileges on the server. This command requires SERVER_ACCESS_ADMINISTER privilege. If cbOutputData is smaller than required, the function returns ERROR_INVALID_PARAMETER when pcbOutputNeeded is NULL, and ERROR_INSUFFICIENT_BUFFER when pcbOutputNeeded is nonNULL. If pOutputData is NULL, the function returns ERROR_INVALID_PARAMETER.

SNMPCommunity

The SNMPCommunity command gets the Simple Network Management Protocol (SNMP) community name for a printer.

XcvData Parameter | Value
pszDataName | L"SNMPCommunity"
pInputData | NULL
cbInputData | 0
pOutputData | Address of a buffer that will receive a string containing the printer's SNMP community
cbOutputData | Size of the buffer needed to contain the string pointed to by the pOutputData parameter
pcbOutputNeeded | Address of a DWORD containing the number of bytes needed for the buffer pointed to by pOutputData

XcvData returns NO_ERROR if it can get the printer's SNMP community name. If cbOutputData is smaller than required, the function returns ERROR_INVALID_PARAMETER when pcbOutputNeeded is NULL, and ERROR_INSUFFICIENT_BUFFER when pcbOutputNeeded is nonNULL. If pOutputData is NULL, the function returns ERROR_INVALID_PARAMETER.

SNMPDeviceIndex

The SNMPDeviceIndex command gets the Simple Network Management Protocol (SNMP) device index of the printer.

XcvData Parameter | Value
pszDataName | L"SNMPDeviceIndex"
pInputData | NULL
cbInputData | 0
pOutputData | Address of a buffer that will receive the device index
cbOutputData | sizeof(DWORD)
pcbOutputNeeded | Address of a DWORD that contains sizeof(DWORD)

XcvData returns NO_ERROR if it can get the printer's SNMP device index. If cbOutputData is smaller than required, the function returns ERROR_INVALID_PARAMETER when pcbOutputNeeded is NULL, and ERROR_INSUFFICIENT_BUFFER when pcbOutputNeeded is nonNULL. If pOutputData is NULL, the function returns ERROR_INVALID_PARAMETER.

SNMPEnabled

The SNMPEnabled command determines whether the Simple Network Management Protocol (SNMP) is enabled for the current device.

XcvData Parameter | Value
pszDataName | L"SNMPEnabled"
pInputData | NULL
cbInputData | 0
pOutputData | Address of a buffer that will receive a DWORD value
cbOutputData | sizeof(DWORD)
pcbOutputNeeded | Address of a DWORD that contains sizeof(DWORD)

XcvData returns NO_ERROR if SNMP is enabled for the device. If cbOutputData is smaller than required, the function returns ERROR_INVALID_PARAMETER when pcbOutputNeeded is NULL, and ERROR_INSUFFICIENT_BUFFER when pcbOutputNeeded is nonNULL. If pOutputData is NULL, the function returns ERROR_INVALID_PARAMETER.


Converting Print Monitors for Use with Clustered Print Servers

Clustering of print servers is a new feature of Windows® 2000. Any printer port monitor that is intended to run on Windows 2000 (or later) clusters must be modified so it can be called from multiple spooler instances (the node's spooler and a cluster spooler). The following steps must be taken:

  • The monitor's InitializePrintMonitor function must be replaced with an InitializePrintMonitor2 function. The latter function returns a monitor instance handle.
  • Globally stored variables must be moved to locally allocated memory, and this memory must be associated with the monitor handle returned by InitializePrintMonitor2.
  • Calls to the Win32 registry API must be replaced with calls to the spooler's registry functions, addresses of which are passed to the monitor in a MONITORREG structure. (See Storing Port Configuration Information.)
  • Port monitors must be divided into a port monitor UI DLL and a port monitor server DLL. The UI DLL must communicate with the server DLL by calling the spooler's XcvData function.
  • A Shutdown function must be added.

Print monitors that are not converted can be used only in a non-clustered environment. They cannot be used with clustered servers.

Once a printer port monitor running on a clustered node of a machine running Windows® 2000 or later has made a connection (either across the network or locally), the port monitor should return from calls made by the spooler within a reasonable amount of time. (The default value of the spooler resource timeout is 180 seconds. See Setting Port Timeout Values for more information.)

When a failover from one cluster node to another occurs, the spooler must wait for all current printing jobs to complete or fail. If a pending print job is held up in a port monitor for longer than the spooler resource timeout, the spooler may come back online in an incomplete state, with printers temporarily missing. This may affect users who have connections to those missing printers.


Installing a Print Monitor

This section describes the methods that can be used to install print monitors. (You can install a print monitor with the same .inf file that you use to install your printer. For more information about .inf files, see Plug and Play and Power Management.)

Installing a Language Monitor

To install a language monitor, you must list its file name in an .inf file by using a LanguageMonitor entry. This entry must be included for every printer driver that controls a printer requiring the use of the language monitor. For more information, see Printer INF Files.

The Add Driver wizard or the Add Printer wizard will read this .inf file and install language monitors associated with printer drivers.

Alternatively, custom installation applications can install language monitors by calling the spooler's AddMonitor function, to explicitly install only a specific monitor DLL.

(The AddMonitor function is described in the Platform SDK documentation.)

Installing a Port Monitor

To install a port monitor, your installation medium must include a printer INF file (that is, an INF file for which Class = Printer) that contains a PortMonitors section. The single entry in this section points to an install section containing two entries: an INF CopyFiles directive that lists all of the files that make up the port monitor, and a PortMonitorDll entry that specifies which DLL in the previous list implements the port monitor interface. The following example code illustrates these points. The PortMonitors section points to an install section named SamplePortMon. In that section, an INF CopyFiles directive copies three files that make up the port monitor. Following that, a PortMonitorDll entry identifies the DLL that implements the port monitor interface.

[PortMonitors]
"Sample Port Monitor" = SamplePortMon

[SamplePortMon]
CopyFiles = @file1.dll, @file2.dll, @file3.hlp
PortMonitorDll = file1.dll

To install a port monitor, open the Printers folder in the Control Panel. On the Printers folder's File menu, select Server Properties. On the File Server Properties dialog, click the Ports tab, and then click the Add Port... button. On the Printer Ports dialog, click the New Port Type... button. Type the path to the INF file in the text input box, and then click OK.

Alternatively, a custom installation application can install the port monitor DLL by a call to the AddMonitor function (described in the Platform SDK documentation).


Writing a Network Print Provider

Occasionally, a vendor might want to supply a print provider to support a new network architecture. One possible way to supply new print provider functionality is to create an entirely new print provider that replaces the local print provider. However in reality this is a challenging and probably unnecessary task. An alternative is to create a partial print provider that works in conjunction with the local print provider.

This section provides the following topics:

Overview of Partial Print Providers

Supporting Printer Change Notifications

Installing a Network Print Provider


Overview of Partial Print Providers

A partial provider DLL typically implements customized versions of only the provider functions that manage print queues and print jobs. The partial provider executes only on the print client system and depends on the local print provider for driver management operations and for generating printer data. Multiple partial providers can exist on a client system.

In Functions Defined by Print Providers, certain functions are identified as "required". Partial print providers must provide all required functions. Partial print providers generally do not implement any of the optional functions. Required functions belong to the following function groups:

Initialization Function

Print Queue Management Functions

Print Job Creation Functions

Print Job Scheduling Functions

Port Management Functions

For partial print providers, printer ports should be considered to be equivalent to print queues. For any function that receives a PRINTER_INFO_2 structure (described in the Platform SDK documentation), the structure's pPort member should be set to the print queue name. Thus if the print queue name is \\Server\Printer1, the port name should also be \\Server\Printer1. The partial print provider's implementation of EnumPorts (described in the Platform SDK documentation) must return a port name of \\Server\Printer1.

As described in Introduction to Print Providers, an application's call to OpenPrinter causes the spooler's router to call each print provider until one of them recognizes the specified print queue and returns a handle.

It is important to remember that a partial print provider does not replace the local provider. Once a user connection to a printer has been created, each call to a provider function is routed through the local provider, which either handles the call itself or reroutes it to a partial provider. All calls to provider functions that are identified as "required" are rerouted from the local provider to the appropriate partial provider.

Partial providers do not generate print jobs; they depend on the local provider and its print processors to create RAW data that can be sent to a printer. When a print processor calls the local provider's StartDocPrinter function (see Printing a Print Job), and the print queue is supported by a partial provider, the local provider calls the partial provider's StartDocPrinter function, supplying the RAW data (as a file). The partial provider's StartDocPrinter, WritePrinter, and EndDocPrinter functions should send the RAW data over the network to the remote print queue.


Supporting Printer Change Notifications

Applications can request notification of the occurrences of print queue events by calling the spooler's FindFirstPrinterChangeNotification, FindNextPrinterChangeNotification, and FindClosePrinterChangeNotification functions, as described in the Platform SDK documentation. If you think application writers will want to request event notification for print queues supported by your partial print provider, you must support event notification in your provider as follows:

  • Provide a FindFirstPrinterChangeNotification function.

    The spooler calls this function to supply the print provider with the following information:

    • A set of flags indicating the types of printer events for which the application has requested notification.
    • A handle to the print queue for which notifications are being requested.
    • A list of types of information the application has requested to be supplied when an event occurs.

    The function must return a flag value that indicates whether the provider should be polled to determine if changes have occurred. (Non-polled providers send signals to the client whenever changes occur. A provider that must be polled does not send signals to a client when changes occur. Instead, the spooler signals the client at regular intervals, whether changes have occurred or not.)

    (Note that at the provider level, this function has different arguments than at the Win32 level.)

  • Keep track of all print queue events that the application specified when it called FindFirstPrinterChangeNotification.

    (For a list of the types of notifications an application can request, and for a list of the types of information that can be used to describe an event, see the Platform SDK documentation's description of the Win32 FindFirstPrinterChangeNotification function. Types of events for which an application might request notification include adding or deleting a print job or form. Types of information an application might request include job or form parameters.)

    Print providers that are not polled must call PartialReplyPrinterChangeNotification or ReplyPrinterChangeNotification when changes occur, to supply the spooler with information describing the changes. The ReplyPrinterChangeNotification function must be called at some point because it causes the spooler to signal the application, while the PartialReplyPrinterChangeNotification function does not. When the application receives a signal from ReplyPrinterChangeNotification, it is supposed to call FindNextPrinterChangeNotification. This latter function supplies the application with the event information that the spooler previously received from the print provider.

    Print providers that are polled should simply keep track of changes. The spooler signals the application at regular intervals. When the application receives a signal, it is supposed to call the spooler's FindNextPrinterChangeNotification function. For polled providers, this function calls the provider's RefreshPrinterChangeNotification function.

  • Provide a RefreshPrinterChangeNotification function.

    This function must return the current state of all monitored print queue options, for the specified print queue. The spooler calls this function when an application calls FindNextPrinterChangeNotification with the PRINTER_NOTIFY_OPTIONS_REFRESH flag set, as described in the Platform SDK documentation. (Applications are supposed to set this flag if a previous call to FindNextPrinterChangeNotification returns a PRINTER_NOTIFY_INFO structure with the PRINTER_NOTIFY_INFO_DISCARDED flag set.) Both polled and non-polled providers must support RefreshPrinterChangeNotification.

  • Provide a FindClosePrinterChangeNotification function (described in the Platform SDK documentation).


Installing a Network Print Provider

To install a new network print provider, you must supply an installer that copies the provider DLL into the target system's \System32 subdirectory and then calls AddPrintProvidor (described in the Platform SDK documentation). This function creates a registry entry for the provider and adds the provider to the end of the spooler's list of installed providers. The function then loads the provider DLL and calls the provider's InitializePrintProvidor function.

To create a connection to a printer supported by a network print provider, a user invokes the Add Printer Wizard and chooses the "Network printer server" option. The user specifies a print queue using the \\Server\Printer format, and the provider's OpenPrinter function must recognize that print queue name.


Internet Printing

This section provides the following topics:

Printing to URLs from Applications

Viewing Print Web Pages

Customizing Print Web Pages

Installing Print Drivers from a Web Page


Printing to URLs from Applications

From an application's perspective, printing to a URL-identified print queue is identical to printing to a UNC-identified print queue. The application is typically unaware that the print queue is accessed by means of a URL.

By viewing print Web pages, a user can install and connect to a URL-identified print queue. When this happens, the print queue is assigned the same "friendly name" that it has on the print server, and this friendly name is listed in the user's print folder.

Applications generally refer to the print queue by its friendly name, as they do for UNC-identified print queues. Calls to OpenPrinter in the local print provider (caused, for example, by the application making GDI calls), include the friendly name. The local print provider, in turn, calls OpenPrinter in the HTTP print provider (inetpp.dll), specifying the print queue's URL.

Applications that refer to print queues by friendly names are generally unaware of whether the print queue is local or on a network, or whether the network protocol is RPC, SMB, or HTTP. However applications can, if necessary, call OpenPrinter directly, specifying a URL. When specifying a URL to OpenPrinter, the following URL format must be used:

HTTP://ServerName/Printers/ShareName/.Printer

where ServerName is the server name (either a DNS name for Internet connections, or a WINS name for Intranet connections), Printers represents a virtual directory on the server, and ShareName is the print queue's share name, as specified in its property sheet. (Virtual directories are discussed in the Platform SDK documentation.)

When a client spooler component or application calls OpenPrinter and specifies a URL, subsequent calls to spooler functions, such as StartDocPrinter, WritePrinter, and so on, are handled by the client's HTTP print provider. The HTTP print provider appends arguments to the URL and sends the resulting URL string to the print server.

For a Windows® 2000 print server to accept print requests containing URLs, it must be running either:

  • Windows 2000 Server software with the Microsoft Internet Information Server (IIS), or
  • Windows 2000 Professional software with the Microsoft Peer Web Server

For a Microsoft® Windows® XP print server to accept print requests containing URLs, it must be running either:

  • Microsoft® Windows® .NET Server software with the Microsoft Internet Information Server (IIS), or
  • Microsoft® Windows® XP® Professional software with the Microsoft Peer Web Server

Note: A Microsoft® Windows® XP® Home Edition print server cannot accept requests containing URLs.

On the print server, IIS or the Peer Web Server receives the URL string. Arguments appended to the string by inetpp.dll on the client system cause the server to call the HTTP print server, which is contained in msw3prt.dll. The HTTP print server accepts RAW-formatted printer data and sends it to the local print spooler.

Printer data is sent from client to server using the Internet Printing Protocol (IPP 1.0), defined by the Printer Working Group (PWG) of the Internet Engineering Task Force (IETF).

The following figure illustrates the path that print data takes from a client application to a print server spooler, if the client prints to a URL-identified print queue.

Printing to an URL-Identified Print Queue

If both the client and server are Windows 2000 or later systems, as illustrated, RPC protocol is typically (but not always) used for client-server communication. (For more information, see Installing Print Drivers from a Web Page) If the client and server are not both Windows 2000 or later systems, HTTP is used. HTTP is also used for printers that contain internal network cards and support IPP 1.0, and are therefore not connected to a server.

Print server security is provided by IIS, which executes on the print server. Security mechanisms supported by IIS are described in the IIS Resource Guide, which is contained in the Microsoft Windows 2000 Server Resource Kit. Additionally, the resource kit describes specifically how system administrators can control security methods associated with printing to URLs.


Viewing Print Web Pages

With any Internet browser executing on any type of client platform, users can view Web pages that display the status of a Windows® 2000 or later print server and its connected printers. Microsoft provides a set of server-resident HTML files that generate these Web pages. Web pages for the print server and for each server-installed printer can be referenced by a client browser using URLs. Additional pages can be referenced by links from these pages.

For a Windows 2000 print server to support Web pages, it must be running either Windows 2000 Server software with the Microsoft Internet Information Server (IIS), or Windows 2000 Professional software with the Microsoft Peer Web Server.

For a Windows® XP® print server to support Web pages, it must be running either Windows .NET Server software with the Microsoft Internet Information Server (IIS), or Windows XP Professional software with the Microsoft Peer Web Server. Note that the print server in Windows XP Home Edition does not support Web pages.

To view a print server page, a user specifies the following URL format:

HTTP://ServerName/Printers

where ServerName is the server name (either a DNS name for Internet connections, or a WINS name for Intranet connections). The URL points to an HTML file that generates the print server's page.

The server page provides a link to a print queue page for each print queue available on the server. Shared print queues can be accessed by all users. A user can also reference the print queue pages for shared printers by specifying a URL with the following format:

HTTP://ServerName/ShareName

where ShareName is the print queue's share name, as specified in its property sheet.

If a user selects a printer's link within the print folder, Microsoft Internet Explorer is automatically started and the print queue page's URL is accessed. Alternately, as already described, a user can view a print server page or a print queue page by specifying the page's URL to any HTML browser.

Print Web pages are generated from template files that can be interpreted by Microsoft Active Server Pages (ASP). These templates (called ASP files) contain standard HTML tags and ASP script tags (<% and %>).

When the Active Server Pages interpreter encounters text within ASP script tags, it calls an appropriate scripting language interpreter (such as JScript® or VBScript) to process the text. The resulting HTML data stream is then sent to the client browser.

Microsoft Active Server Pages is described in the Platform SDK documentation.

A set of COM-based ActiveX objects for print Web pages, with associated Automation interfaces, is provided (in oleprn.dll) for obtaining printer properties and SNMP information.

When a user wants to view the Web page of a particular server or printer, the following steps occur:

  1. The user employs a browser to specify an appropriate URL. The URL points to one of the template files on the specified print server.
  2. The server-resident Active Server Pages interpreter, which is part of IIS, searches for ASP script tags, invokes the appropriate scripting language interpreter to interpret the script text, and places the returned results in the HTML data stream.
  3. The ASP interpreter, on the server, sends the resulting HTML stream to the client's browser.

The following picture illustrates the process by which a printer URL is sent from a client to a print server, and how its associated HTML stream is returned to the client.

Sending a Print URL from the Client to the Print Server


Customizing Print Web Pages

This section provides the following topics:

ASP Files for Print Web Pages

Customizing the Printer Details Web Page

Installing Customized Print Web Pages


ASP Files for Print Web Pages

Print Web pages are created by using ASP files. Microsoft provides ASP files that create the following print Web pages:

  • A print server page that is referenced by the URL HTTP://ServerName/printers, where ServerName represents the DNS or WINS name for a print server. This page contains links to a page for every printer installed on the server.
  • A print queue page for each of the server's print queues. These pages are accessible by links in the print server page, or they can be referenced directly from a browser using the URL HTTP://ServerName/ShareName.
  • Additional pages for queued documents, printer properties, and printer-specific details. These pages are displayed within a frame of the print queue page.

The printer-specific details page can be customized by replacing its ASP file. For more information, see Customizing the Printer Details Web Page.


Sample ASP Files

Sample ASP files are provided in this DDK. The samples are located in the QueueASP sub-directory of the directory tree containing DDK samples.


Customizing the Printer Details Web Page

If you want to replace the printer details page provided by Microsoft, you can provide one or more customized ASP files. If you replace the default page, you can also provide links to additional customized pages installed on the server, plus links to any other pages on the Web.

If Microsoft's standard TCP/IP port monitor (tcpmon.dll) is used with your printer, customized ASP files can be used to replace the default printer details pages on a per-printer type or per-manufacturer basis. If customized ASP files have not been installed, the default printer details page is used.

Customized ASP files can also be used to replace the default printer details pages for printers using other port monitors, but per-printer type and per-manufacturer replacements are not allowed.

The method used for installing customized ASP files determines whether the customized files replace the default files for a printer type, a manufacturer, or a port monitor. For more information, see Installing Customized Print Web Pages.

The following topics provide more information about creating print Web pages:

Replacing the Default Printer Details Page

Which Printer Details Page is Displayed?

ASP Variables for Print Web Pages

ActiveX Objects for Print Web Pages

Updating Web Page Information


Replacing the Default Printer Details Page

You can replace the default printer details page with a customized page by using the following steps:

  1. Provide a customized ASP file for the page.
  2. Follow the installation procedures described in Installing Customized Print Web Pages.

A customized printer detail page can provide links to additional customized pages, or any other URLs. ASP files for additional customized pages must be installed as indicated in Installing Customized Print Web Pages. For information about specifying links, refer to ASP documentation in the Platform SDK documentation.

Customized print Web pages can use the following technologies

ASP Variables for Print Web Pages

ActiveX Objects for Print Web Pages

Customized COM objects

For information about creating and using COM objects, see the Platform SDK documentation.

Notes All print Web pages created using ASP files are generated from a single ASP application.

You must not modify the file named globals.asp, which is contained in the Printers subdirectory of the system disk.

Microsoft reserves the right to modify its print Web pages without notice. Therefore, customized ASP files must not depend on the content of Microsoft-supplied ASP files.


Which Printer Details Page is Displayed?

When a user attempts to view a printer's details page, the server uses the following algorithm to determine which ASP file to read.

  • If the Standard TCP/IP Port Monitor is used with the printer:
    1. The server first checks to see if a set of printer type-specific ASP files has been installed. If so, they are used.
    2. If printer type-specific ASP files are not available, the server checks to see if a set of manufacturer-specific ASP files have been installed. If so, they are used.
    3. If manufacturer-specific ASP files are not available, and if the Printer MIB (RFC 1759) for SNMP is supported for the printer, Microsoft's default ASP files are used.
    4. If SNMP is not supported, a printer details page is not provided.
  • If the Standard TCP/IP Port Monitor is not used with the printer, the server checks to see if a set of monitor-specific ASP files have been installed. If so, they are used. If not, a printer details page is not provided.

For more information, see Installing Customized Print Web Pages.


ASP Variables for Print Web Pages

Microsoft provides a set of ASP session variables for use by customized print Web pages. The following table lists the session variables. Customized ASP files must not modify these variables. As indicated, some variables are only valid if Microsoft's TCP/IP port monitor is being used for the printer.

Some variables are passed in as session variables, while others are passed in using URL decoration. Session variables can be accessed by using Session("VariableName"). Parameters passed in by URL decoration can be accessed by using Request("VariableName"). If you wish to automatically refresh the status page, you might find it necessary to redecorate the URL with the variables your page requires. Since Request variables must be passed in the URL, they may require encoding and decoding to translate from ANSI to Unicode representation. A helper object, whose COM ProgID is "OlePrn.OleCvt", has been provided to enable encoding and decoding between the ANSI used in the URL and Unicode. Two methods on this object, EncodeUnicodeName, and DecodeUnicodeName, can be used to translate from ANSI to Unicode, and from Unicode to ANSI, respectively. This conversion does not need to be performed for Session variables.

Variable | Value | TCP/IP Port Monitor Only? | Variable Type | Encoded?
MS_ASP1 | Directory path to the initial Web page used for describing printer-specific details. | No | Request | No
MS_Community | The print server's SNMP community name. | Yes | Request | No
MS_Computer | The print server's computer name. | No | Session | No
MS_DefaultPage | The default ASP file for printer-specific details. | No | Session | No
MS_Device | The printer's SNMP device index. | Yes | Request | No
MS_DHTMLEnabled | TRUE if the client supports dynamic HTML; otherwise FALSE. | No | Session | No
MS_IPAddress | The printer's IP address. | Yes | Request | No
MS_LocalServer | The print server's identifier. This might be either an IP address or a computer name. | No | Session | No
MS_Model | The name of the printer driver. | No | Request | Yes
MS_Portname | The printer's port name. | No | Request | Yes
MS_Printer | The printer's name. | No | Request | Yes
MS_SNMP | TRUE if SNMP is being used with a printer, otherwise FALSE. | Yes | Request | No
MS_URLPrinter | The printer's name, in encoded URL format. | No | Request | Yes

The session variables specify properties of the "current" printer, that is, the printer for which an ASP page was invoked. To obtain additional printer properties for the current printer, or to obtain properties of a different printer, see ActiveX Objects for Print Web Pages.


ActiveX Objects for Print Web Pages

Three ActiveX® objects, IAspHelp, ISNMP, and IOleCvt, are provided for print Web pages. ASP files can access each object through an Automation interface, using any scripting language, such as VBScript. The objects and interfaces are supplied in oleprn.dll.

  • The IAspHelp Automation Interface allows you to obtain properties associated with a specified printer.

    This interface provides access to information that isn't available from ASP session variables, and allows an ASP page to obtain information about printers other than the one for which the page was invoked.

  • The ISNMP Automation Interface allows you to set and retrieve values associated with SNMP OIDs, if RFC 1759 is supported for a printer.

    The ISNMP interface can only be used with printers that use Microsoft's TCIP/IP port monitor. This interface is essentially an OLE automation wrapper for SNMP Management API functions, described in the Platform SDK documentation.

    Object IDs (OIDs) can be specified using numeric strings, and by including text name strings for the Management Information Base (MIB) specified by RFC 1759. Additional MIB names can be used if you define, compile, and install customized MIBs, as described in the Platform SDK documentation.

  • The IOleCvt Automation Interface allows you to convert strings from ANSI to Unicode, and vice-versa, to convert strings to UTF8 format, and to convert Unicode strings using a different code page.

For information about ActiveX and Automation, see the Platform SDK documentation.


Updating Web Page Information

The print server does not support server push for updating information on a print server Web page. Client pull operations are supported (assuming the user's browser recognizes HTML-specified "refresh" parameters) and can be included in customized pages. (For more information about client pull, refer to appropriate HTML documentation.)


Installing Customized Print Web Pages

The methods used for installing customized print Web pages depend on whether you are installing pages that are specific to a printer type, specific to a manufacturer, or specific to a port monitor. See the following topics:

Installing Pages for a Printer Type

Installing Pages for a Manufacturer

Installing Pages for a Port Monitor


Installing Pages for a Printer Type

If the Standard TCP/IP Port Monitor is used with your printer, you can install a printer details page that is specific to the printer type. To do so, include the page's ASP file, along with all subordinate files (such as .gif files or ASP files for linked pages), in the printer INF file for the printer type. Following is a sample section of a printer INF file.

[Manufacturer]
"ACME"

[ACME]
"ACME Mega Laser" = ACML01.PPD

[ACML01.PPD]
CopyFiles=@ACML01.PPD,PSCRIPT,ACML1WEB
DataSection=PSCRIPT_DATA

[ACML1WEB]
PAGE1.ASP, ACML1.ASP ;ACML1.ASP renamed to PAGE1.ASP during installation
ACML2.ASP
ACGF001.GIF

[DestinationDirs]
DefaultDestiDir=66000
ACML1WEB=66004

When the printer class installer encounters this INF file section, it will perform the following operations:

  • Create a directory formatted as <Root>\<Manufacturer>\<Printer Type>. For the example, the following sub-directory would be created:

    ..\ACME\ACME Mega Laser

    The sub-directory is specified in the INF file using a printer DIRID value of 66004.

  • Copy acml1.asp, asml2.asp, and acgf001.gif into the sub-directory.
  • Rename acml1.asp to Page1.asp (caused by the first statement in the ACML1WEB section).

Note that you must identify the first ASP file to be viewed by preceding it by the Page1.asp filename, as shown in the example. The installer renames this file to Page1.asp in the target directory.

All ASP filenames with a format of PageN.asp, where N is 1, 2, 3, and so on, are reserved by Microsoft.

A sample INF file is provided with the sample ASP files.


Installing Pages for a Manufacturer

You can install a printer details page that is manufacturer-specific, for all the manufacturer's printer types that use the Standard TCP/IP Port Monitor. To do so, place the page's ASP file, along with all subordinate files (such as .gif files or ASP files for linked pages), in the manufacturer's sub-directory (\%windir%\web\printers\<Manufacturer>). A customized setup program must be provided to accomplish this.

The page's initial ASP file must be named Page1.asp. All ASP filenames with a format of PageN.asp, where N is 1, 2, 3, and so on, are reserved by Microsoft.

The manufacturer-specific page will be used for all of the manufacturer's printer types that use the Standard TCP/IP Port Monitor and do not have printer type-specific pages.

The system determines a printer's manufacturer by reading the printer's INF file at installation time. When a user attempts to view a printer details page, the system first checks to see if a file named Page1.asp exists in <Root>\<Manufacturer>\<Printer Type>. If a file is not found, the system checks <Root>\<Manufacturer>.


Installing Pages for a Port Monitor

You can provide a customized printer details page for use with printers that do not use the Standard TCP/IP Port Monitor. Place the page's ASP file, along with all subordinate files (such as .gif files or ASP files for linked pages), in the monitor's sub-directory (<Root>\<Monitor>, where Monitor matches the monitor name returned in a PORT_INFO_2 structure – see the Platform SDK documentation). Your monitor's installer program must perform this task.

The page's initial ASP file must be named Page1.asp. All ASP filenames with a format of PageN.asp, where N is 1, 2, 3, and so on, are reserved by Microsoft.


Installing Print Drivers from a Web Page

Before a user can send a job to a print queue that is visible by means of print Web pages, driver files must be sent from the print server and installed on the user's system. This installation operation occurs when a user views a print queue's web page and then selects its installation page. (The installation page cannot be replaced with a customized page.)

If the client can connect to the server using RPC, which is likely for intranet connections, the printer is installed in the usual, non-HTTP manner. Otherwise the installation page calls the HTTP print server, which creates a cabinet file (described in the Platform SDK documentation) containing the printer's .inf file and all required installation files. The server sends the cabinet file to the client, where it is expanded. It starts the client's Add Printer Wizard, which completes the installation and adds the printer to the user's print folder.

As an alternative to selecting a print queue's installation page, a user can install a URL-identified printer by running the Add Printer Wizard explicitly. When a user specifies a URL to the Add Printer Wizard, the client always connects to the server using HTTP. This installation method must be used when installing printers that contain their own network cards and are therefore not connected to a server.

The installation process is not customizable beyond specifying the contents of the printer .inf file, which is the same .inf file used to install the printer on the print server.


Installing and Configuring Printer Drivers

This section describes installation and configuration of printer drivers. The following topics are provided:

Plug and Play for Printers

Printer INF Files

Directory Services for Printers

Supporting Point and Print

Specifying Printer Driver Version Numbers


Plug and Play for Printers

This section describes the design of Plug and Play for printers in Microsoft® Windows® 2000 and later. Printing Plug and Play design is similar to the Windows 95 design. Windows 2000 and later operating system versions support Plug and Play for printers attached to LPT ports, USB ports, infrared ports, and parallel ports.

There are three system components responsible for Plug and Play printer installation:

  1. Printer Installation and the Plug and Play Manager
  2. Plug and Play Bus Enumerators
  3. Printer Class Installer

The final topic in this section provides information about custom-built Plug and Play drivers.

Installing a Custom Plug and Play Printer Driver


Printer Installation and the Plug and Play Manager

The Plug and Play manager handles all Plug and Play events for the machine, and is generic to all devices. The Plug and Play manager is documented in Plug and Play. Introduction to Plug and Play gives an overview of Plug and Play installation, and of how the various kernel-mode and user-mode components interact.

Printer Installation Differences between Windows 98/Me and Windows 2000 and Later

The Plug and Play architecture on Windows 2000 and later differs from that on Windows 95/98/Me. The most significant differences are:

  • The drivers included with Windows 2000 and later are contained in a file, driver.cab, that is installed when the operating system is installed. This file contains all of the Plug and Play in-box drivers for all types of devices, so the user normally does not need the original installation media to install a driver.
  • Little or no user intervention is required to install a particular driver. If a Windows 2000 or later driver that is digitally signed by Microsoft is in driver.cab or already installed on the machine, Plug and Play verifies the driver's signature and installs the driver with no user intervention. This type of installation is called server-side installation. If the driver is not available on the system, or it is not signed, or the driver installation requires interaction with the user (through user interface elements), Plug and Play reverts to a client-side installation. For more information about each type of installation, see the discussion of the user-mode PnP manager in Device Installation Components. In most cases, when a machine is booted with a new Plug and Play device connected to it, the device is installed and ready to use by the time the user logs on.

If the user must be able to choose which driver to install, you can use an InteractiveInstall directive in the INF ControlFlags section. This directive can be used only in the following two circumstances:

  1. To install devices that have incorrectly defined hardware IDs. This can occur when a hardware device has a corrupted hardware ID, or when a hardware vendor assigns the same hardware ID to two different devices, which is an error in hardware design.
  2. To install a driver for a device that cannot use the generic class installer or a driver supplied with the operating system.

If hardware IDs or compatible IDs are listed with the InteractiveInstall directive, Setup defers installation of printers matching those IDs to the client side, so the installation is delayed until an administrator logs on. The administrator is prompted to install the correct driver files. This is useful if two printer drivers share the same device ID, but require different drivers.

In contrast to Windows 2000 and later, Windows 95/98/Me Plug and Play installs devices without user intervention only if there is a hardware ID (rank-0) match. When there is a compatible ID (rank-1) match for the driver of a Plug and Play device, but no hardware ID match, the user is prompted to select the correct driver from the installation media. (This means that the user must have the installation media in order to install the driver.)

Also on Windows 95/98/Me, when a driver is written for multiple devices (or for similar devices on multiple buses), the user is always prompted for installation if only the compatible ID was listed, unless every possible hardware ID is listed with a duplicate driver entry in the INF file.

Duplicate Installation Detection

When Setup calls the printer class installer to install a printer, the class installer determines whether the printer has already been manually installed. It does this by looking for exact matches between the driver and port names of currently installed printers and those listed in the INF file. If the class installer finds an installed print queue whose driver and port names match these two parameters, it does not install a second print queue, but instead associates it with the devnode entry. This prevents creating a second print queue for the same device.

A number of popular printer models share the same hardware ID (the HP DeskJet series, for example). On Windows 95/98/Me, if a user manually installs a DeskJet model that is subsequently detected by Plug and Play, a second print queue is installed if the user selects the appropriate driver. If the user does not select a driver, then he or she is prompted to do so every time the computer reboots.

Windows 2000 and later avoids this behavior by listing all printers with both a hardware ID and compatible ID match. When multiple matches are found, the class installer checks to see whether there is already a print queue with the same hardware ID match. If there is, the Plug and Play manager does not install a second queue. If not, the hardware ID match is downgraded to a compatible ID match. If these hardware IDs are also listed in the InteractiveInstall entry (see INF ControlFlags section) of the INF file, the user is prompted to select a driver.


Plug and Play Bus Enumerators

The following sections provide information about Plug and Play bus enumeration on each of the following types of port:

Printer Connected to an LPT Port

Printer Connected to a USB Port

Printer Connected to an Infrared Port


Printer Connected to an LPT Port

The LPT enumerator is an example of a bus driver. The LPT enumerator is capable of obtaining identification information from LPT port hardware that conforms to the IEEE 1284 Extended Capabilities Port Protocol and ISA Interface Standard.

When a Windows 2000 or later system starts, the configuration manager calls the LPT enumerator to enumerate the IEEE 1284-compatible devices connected to LPT ports. For each device found, the configuration manager calls the printer class installer. The printer class installer calls SetupDi-prefixed device installation functions, which obtain information from printer INF files.

For a parallel-connected printer, the parallel enumerator creates a devnode with a unique hardware ID generated from the 1284 string it receives from the printer.

An example 1284 string is:

"MANUFACTURER:Hewlett-Packard;COMMAND SET:PJL,MLC,PCL,POSTSCRIPT;MODEL:HP Color LaserJet 550;CLASS:PRINTER;COMMENT:HP LaserJet;"

From this 1284 string the parallel enumerator produces the following hardware ID:

LPTENUM\Hewlett-PackardHP_Co3115

The hardware ID is made up of the enumerator prefix, followed by the Manufacturer Name, the Model name, and a cyclic redundancy check (CRC) code. The CRC code, which is the last four digits of the hardware ID, is generated from the manufacturer and model strings. Spaces in the string are replaced with underscores.

To read the 1284 ID string from the device, send IOCTL_PAR_QUERY_DEVICE_ID. Note that the spooler redirects the LPTx symbolic link (where x is the LPT number 1, 2, or 3) to the spooler's named pipe, which means that if the spooler is running, then parport never sees the IOCTLs sent to LPTx.

The devnode for a parallel-connected Plug and Play printer is placed under HKLM\SYSTEM\CurrentControlSet\Enum\LPTENUM and has a single hardware ID of the form:

LPTENUM\Company_NameModelNam1234

The driver stack appears in the figure following the next code sample.

The INF code that will correctly "plug and play" a hardware ID of the form LPTENUM\Company_NameModelNam1234 is shown in the following example. Notice that the "Model Name XYZ" device description appears twice in the INF Manufacturer section. The hardware ID in the first line includes the bus enumerator, while the hardware ID in the second line does not. The two lines guarantee a rank-0 hardware ID match regardless of the type of bus on which the printer is installed. See Installing a Custom Plug and Play Printer Driver for more information.

[Manufacturer]
%Company_Name%=Company_Name

; Section name for all drivers for Company_Name
[Company_Name]
"Model Name XYZ" = Install_Section_XYZ, LPTENUM\Company_NameModelNam1234 ; plus any compatible IDs
"Model Name XYZ" = Install_Section_XYZ, Company_NameModelNam1234 ; plus any compatible IDs

; The install section for the XYZ model
[Install_Section_XYZ]

[Strings]
Company_Name="Company Name"

Plug and Play for Parallel Port Printers

For a printer that shares its device ID with other models, the INF should be similar to the following:

[Manufacturer]
%Company_Name%=Company_Name

; The section for all drivers for Company_Name
[Company_Name]
"Model Name XYA" = Install_Section_XYA, LPTENUM\Company_NameModelNam1234, Company_NameModelNam1234 ; plus any other compatible IDs
"Model Name XYA" = Install_Section_XYA, Company_NameModelNam1234, Company_NameModelNam1234 ; plus any other compatible IDs
"Model Name XYB" = Install_Section_XYB, LPTENUM\Company_NameModelNam1234, Company_NameModelNam1234; plus any other compatible IDs
"Model Name XYB" = Install_Section_XYB, Company_NameModelNam1234, Company_NameModelNam1234 ; plus any other compatible IDs

; The install sections
[Install_Section_XYA]

[Install_Section_XYB]

[ControlFlags]
InteractiveInstall = LPTENUM\Company_NameModelNam1234, Company_NameModelNam1234

[Strings]
Company_Name = "Company Name"

Just as in the previous example, each model in the INF Manufacturer section is represented by a pair of nearly identical lines. For a given model, one line in the pair includes the bus enumerator; the other does not. The two lines guarantee a rank-0 hardware ID match regardless of the type of bus on which the printer is installed. See Installing a Custom Plug and Play Printer Driver for more information.


Printer Connected to a USB Port

When a Universal Serial Bus (USB) printer is connected over a USB port, the USB bus driver creates a functional device object (FDO) with a hardware ID of the form VIDvvPIDpp, and compatible ID Class_7. The devnode for this is created under Enum\USB\ ...Class_7 and identifies a printer device connected over a USB port. Plug and Play loads usbprint.sys using a compatible ID match on Class_7 from usbprint.inf.

The entry from usbprint.inf that is used to load usbprint.sys for any USB printer device is:

[Microsoft]
%USBPRINT.DeviceDesc% = USBPRINT_Inst,USB\Class_07,GENERIC_USB_PRINTER

Usbprint.sys queries the Plug and Play printer to get the 1284 string, and generates a hardware ID that is compatible with the parallel bus enumerator. (For more information, see USBPRINT Interface.) It creates a physical device object (PDO) whose devnode is under Enum\USBPRINT, and with two hardware IDs in the following form:

USBPRINT\Company_NameModelNam1234

The following figure shows the driver stack for a printer connected over a USB port.

Plug and Play for USB Printers

The following example shows the entries in an INF Manufacturer section that can be used to install a USB or other bus-type printer driver. The first line guarantees a rank-0 hardware ID match if the printer is installed on a USB bus. The second line guarantees a rank-0 hardware ID match if the printer is installed on another bus. For more information, see Installing a Custom Plug and Play Printer Driver.

"Model Name XYZ" = Install_Section_XYZ, USBPRINT\Company_NameModelNam1234, Company_NameModelNam1234 ; plus any other compatible IDs
"Model Name XYZ" = Install_Section_XYZ, Company_NameModelNam1234, Company_NameModelNam1234 ; plus any other compatible IDs


Printer Connected to an Infrared Port

Printers connected over an infrared (IR) port do not support Plug and Play using the 1284 device string. For a computer with an IR port, a service constantly polls for devices. When an IR Plug and Play printer is brought within range, a PDO is created under Enum\Root\ with a device ID of the form HWPnnnn. The hardware ID of the devnode has a single entry of the form HWPnnnn.

The INF Manufacturer section entries for a printer that supports Plug and Play over LPT and IR ports should appear similar to the following:

"Model Name XYZ" = Install_Section_XYZ, LPTENUM\Company_NameModelNam1234, Company_NameModelNam1234, Model_Name_XYZ
"Model Name XYZ" = Install_Section_XYZ, HWP9876, Model_Name_XYZ


Printer Class Installer

The printer class is one of the built-in device setup classes in Windows 2000 and later. The printer class installer, ntprint.dll, installs printer driver files by calling the AddPrinterDriverEx function. This class installer makes printers available on the server by calling AddPrinter. Both functions are described in the Platform SDK documentation.


Installing a Custom Plug and Play Printer Driver

On Windows XP, the Plug and Play manager loads drivers in this order (listed from highest to lowest preference):

  1. signed IHV drivers
  2. "in-box" drivers
  3. unsigned IHV drivers

On Windows 2000, there is no difference between in-box and signed IHV drivers: either type of driver is loaded in preference to an unsigned IHV driver. To learn more about applications designed to install drivers and INF files that replace "in-box" drivers, see Writing a Device Installation Application.

If you are developing a driver that replaces a Windows 2000 in-box driver, make sure that the hardware IDs in the INF Models section of your INF file include the appropriate port enumerator. The Windows 2000 version of ntprint.inf includes port enumerators in its entries in the INF Models section. If the same entries in your INF file omit port enumerators, Plug and Play selects the in-box Windows 2000 driver in preference to yours. If your driver replaces a Windows XP in-box driver, you do not have to include the port enumerator in a hardware ID.

An IHV can avoid a popup asking for user interaction in client-side installations by providing two lines in the INF Models section for each model, as in the following example.

; Models section

[OEM Company Name]
"XYZ PScript Printer" = OEMXYZ.PPD, LPTENUM\OEM_Company_NameXYZ_F84F, XYZ_PScript_Printer
"XYZ PScript Printer" = OEMXYZ.PPD, OEM_Company_NameXYZ_F84F, XYZ_PScript_Printer
.
.
.

In this example, the two lines are nearly identical, differing only by the inclusion of the bus enumerator (LPTENUM) in the hardware ID in the first line. In each line, the second and third entry values are the hardware ID and compatible ID, respectively. For a printer that is installed over a specific bus (the parallel port in this case), the hardware ID in the first line produces a hardware ID match, which is the best possible match. For a printer installed over any other bus, the hardware ID in the second line also produces a hardware ID match.

In either case, Setup does not require a response from the user on whether to install the driver, so does not display a popup asking for a response. Note, however, that if the match is not a hardware ID match, but rather a compatible ID match, and installation occurs on the client side, Setup displays a popup asking for user interaction.


Printer INF Files

An extensive discussion of .inf files is provided in General Guidelines for INF Files.

The following topics provide specific information about .inf files for printers:

Printer DIRIDs

Printer INF File Entries

Printer INF File Data Sections

Printer INF File Install Sections

Printer INF File CopyFiles Sections

Sample Printer INF Files

For additional information about printer .inf files, see the following topics:

Installing a Unidrv Minidriver

Installing a Pscript Minidriver

Installing Customized Driver Components

Also see the installation topics in the following section:

Customizing Print Spooler Components


Printer DIRIDs

When specifying target directories within .inf files, directory identifiers (DIRIDs) should be used. See INF DestinationDirs Section for more information about DIRIDs.

The following table lists printer-specific DIRIDs and the purpose of each.

DIRID | Purpose | Directory Contents
66000 | Represents the directory path returned by the GetPrinterDriverDirectory function. | Driver files and dependent files.
66001 | Represents the directory path returned by the GetPrintProcessorDirectory function. | Print processor files.
66002 | Represents the directory path to additional files to be copied to \System32 of the local system. See the paragraph following this table. | Print monitor files and other dependent files.
66003 | Represents the directory path returned by the GetColorDirectory function. | ICM color profile files.
66004 | Represents the directory path to which printer type-specific ASP files are copied. | ASP files and associated files. (See Internet Printing.)

Files in the directory assigned to the DIRID of 66002 are copied to the System32 subdirectory when printer drivers for the native architecture are being installed on the local system, such as when x86 drivers are installed locally on a x86 system. Files in this directory are ignored if a driver is being installed to a remote system.

A printer driver is installed when the printer class installer calls the spooler's AddPrinterDriverEx function. This function requires all driver files to be located in the directory that is returned by the GetPrinterDriverDirectory function.


Printer INF File Entries

For an installation application to install a printer on a print server, it must call the spooler's AddPrinterDriverEx function to load driver files and then call the spooler's AddPrinter function to make the printer available on the server.

The AddPrinterDriverEx function requires a DRIVER_INFO_3 structure as input, and the AddPrinter function requires a PRINTER_INFO_2 structure as input. The default Windows 2000 or later printer class installer, ntprint.dll, reads printer .inf files to obtain string values that must be placed in these structures before the functions are called.

The AddPrinterDriverEx and AddPrinter functions, along with the DRIVER_INFO_3 and PRINTER_INFO_2 structures, are described in the Platform SDK documentation.

A set of .inf file entries for printer drivers that ntprint.dll recognizes has been defined. These entries have the following format:

EntryName=Value

where EntryName is a string identifying the entry and Value is a string value assigned to the entry.

The following table lists .inf file entries that should be included in printer .inf files. For each entry, the table includes the following:

  • The value that should be assigned to the entry.
  • The default value that ntprint.dll uses if the entry is not defined.
  • The structure member into which ntprint.dll places a pointer to the entry value.
INF File Entry | Value | Default Value (if entry not specified) | Structure Member
ConfigFile | The name of the driver's printer interface DLL. | Value specified for DriverFile. | pConfigFile member of the DRIVER_INFO_3 structure (described in the Platform SDK documentation)
DataFile | The name of a driver's associated data file, such as a .ppd file. | Driver's section name within the .inf file. | pDataFile member of the DRIVER_INFO_3 structure
DefaultDataType | Not used with NT-based-operating systems. |  |
DriverFile | The name of the driver's printer graphics DLL. | Driver's section name within the .inf file. | pDriverPath member of the DRIVER_INFO_3 structure
ExcludeFromSelect | See Note 1, following this table. | None | None
HelpFile | The name of the interface DLL's help file. | None. A help file is not specified. | pHelpFile member of the DRIVER_INFO_3 structure
LanguageMonitor | The name of a language monitor to be associated with the printer driver. See LanguageMonitor Value Format. | None. A language monitor is not specified. | pMonitorName member of the DRIVER_INFO_3 structure
PrintProcessor | The name of a print processor to be associated with the printer driver. See PrintProcessor Value Format. | None. A print processor is not specified. | pPrintProcessor member of the DRIVER_INFO_2 structure (described in the Platform SDK documentation)
VendorSetup | The name of a function within a vendor-supplied DLL, that handles customized printer setup operations. | None. See Note 2, following this table. | None

Note 1 (ExcludeFromSelect): The device ID of a device that should not be shown in the Select Device dialog or in the Add Printer Wizard. For printers, this includes all PnP entries of devices that have duplicate device descriptions in the INF file; for example, devices that have multiple entries for infrared and parallel enumeration or for another bus. The ExcludeFromSelect entry, unlike all others in this table, must appear in the Control Flags section of the INF file. See INF ControlFlags Section for more information.

Note 2 (VendorSetup): Customized setup operations are not performed. In particular, no user interface is permitted during print processor, print monitor, or printer driver installation, except through the use of the VendorSetup INF entry.

Printer .inf file entries are typically specified within printer .inf file data sections. For examples, see the sample printer .inf files.

LanguageMonitor Value Format

When a LanguageMonitor entry is included in a printer .inf file, the value format is as follows:

LanguageMonitor="MonitorName, MonitorDLLName"

where MonitorName is a text string representing the monitor's displayed name, and MonitorDLLName is the filename of the monitor DLL.

PrintProcessor Value Format

When a PrintProcessor entry is included in a printer .inf file, the value format is as follows:

PrintProcessor="PrintProcessorName, PrintProcessorDLLName"

where PrintProcessorName is a text string representing the print processor's displayed name, and PrintProcessorDLLName is the filename of the DLL.

Dependent Files

For Windows 2000 and later, a dependent file is a printer driver file that is included in a printer .inf file install section with a printer DIRID of 66000 or 66002, but not assigned to the DriverFile, DataFile, ConfigFile, or HelpFile entries.

A maximum of 64 dependent files can be specified for each printer model.


Customized Printer Setup Operations

To provide customized printer setup operations for printers that are installed using ntprint.dll, the default Windows 2000 and later printer class installer, you can include a VendorSetup INF entry in the printer's .inf file.

Note If you plan to display user interface elements during the installation of a print processor, a print monitor, or a printer driver, you must use the VendorSetup INF entry.

The format for the VendorSetup entry is as follows:

VendorSetup=FileName, FunctionName

where FileName is the name of a DLL containing a setup function, and FunctionName is the name of the function.

The function specified by FunctionName must match the following prototype:

VOID WINAPI FunctionName (HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, UINT nCmdShow);

where FunctionName is the name of the setup function. The function's parameters and their descriptions are shown in the following table:

Parameter | Description
hWnd | Specifies the handle of the parent window.
hInstance | Specifies the instance handle of the calling process.
lpszCmdLine | Specifies an ANSI string containing the name of the printer that was just installed. This string is parsed by FunctionName.
nCmdShow | Specifies how the window is to be shown. The flags that control how the window is shown are defined in winuser.h.

The printer class installer calls the function as one of the final steps in the installation operation.


Printer INF File Data Sections

The default Windows 2000 and later printer class installer, ntprint.dll, allows printer .inf files to contain data sections. Data sections are specified using the following format:

DataSection=SectionName

where SectionName is an .inf file section name.

Data sections are used for specifying sets of printer .inf file entries that are common to multiple printers. By grouping the common entries in a list under the named section, and then referencing that section with a DataSection statement for each printer that uses the entries, the entry list has to be included only once in the .inf file.

Microsoft's printer .inf file, ntprint.inf, defines the following data sections:

  • [PSCRIPT_DATA]

    Assigns values to the DriverFile, ConfigFile, and HelpFile entries for the Microsoft Postscript Printer Driver.

  • [UNIDRV_DATA]

    Assigns values to the DriverFile, ConfigFile, and HelpFile entries for the Microsoft Universal Printer Driver.

  • [UNIDRV_BIDI_DATA]

    Assigns values to the DriverFile, ConfigFile, HelpFile, and LanguageMonitor entries for the Microsoft Universal Printer Driver, for bi-directional printers.

These data sections should be referenced from within vendor-supplied .inf files. For examples, see Installing a Unidrv Minidriver and Installing a Pscript Minidriver.

"Previous Names" Section

The Windows 2000 and later printer class installer recognizes a special data section called "Previous Names". One of these sections is permitted in each .inf file. Entries in the section identify drivers for which the printer name is different for Windows 2000 and later than it is for Windows 95/98/Me. Specifying such name differences allows Point and Print to be supported for Windows 95/98/Me clients connecting to Windows 2000 and later servers.

The format for each entry in this section is:

"Windows 2000 or later Printer Name" = "Windows 95/98/Me Printer Name"

The following are sample entries:

[Previous Names]
"HP Color LaserJet" = "HP Color LaserJet (MS)"
"HP DeskJet 1200C" = "HP DeskJet 1200C (MS)"
"HP DeskJet 310" = "HP DeskJet 310 Printer"


Printer INF File Install Sections

For Windows NT® 4.0 and previous, vendors who supplied minidrivers to customers also supplied the customer with a copy of the appropriate Microsoft printer driver, obtained from Microsoft.

For Windows® 2000 and later, vendors do not distribute Microsoft's printer drivers along with their minidrivers. Instead, each vendor supplies an .inf file that installs the vendor's files and then invokes Microsoft's printer .inf file, ntprint.inf, which in turn installs the appropriate printer driver components.

Microsoft's printer .inf file, ntprint.inf, contains the following INF DDInstall sections that can be referenced by vendor .inf files:

  • [PSCRIPT.OEM]

    Installs the Microsoft Postscript Printer Driver (Pscript).

  • [UNIDRV.OEM]

    Installs the Microsoft Universal Printer Driver (Unidrv).

  • [UNIDRV_BIDI.OEM]

    Installs the Microsoft Universal Printer Driver and pjlmon.dll, the language monitor that supports Printer Job Language (PJL) and provides bi-directional communication for PJL printers.

  • [TTFSUB.OEM]

    Installs ttfsub.gpd, which is included with this DDK and contains a set of *TTFS entries for common TrueType font substitutions that can be used with Unidrv-supported printers.

  • [sRGBPROFILE.OEM]

    Installs the system's sRGB color profile.

  • [LOCALE.OEM]

    Installs locale.gpd, which contains locale identifiers. (See Referencing Locales.)

To reference these Install sections from your .inf file, the file must use the Include and Needs directives, as illustrated in the following example:

[Manufacturer]
"ABC Printers"

[ABC Printers]
"ABC Printer 100ex" = ABC100EX.GPD, ABC_Printer_100ex

[ABC100EX.GPD]
CopyFiles=@ABCres.dll,@ABC100EX.gpd
DataSection=UNIDRV_BIDI_DATA      ; Unidrv Bi-Directional Data Section
DataFile=ABC100EX.gpd
Include=NTPRINT.INF               ; Include NTPRINT.INF.
Needs=TTFSUB.OEM,UNIDRV_BIDI.OEM  ; Install Unidrv, TrueType subs,
                                  ;    and PJL language monitor.


Printer INF File CopyFiles Sections

When a printer INF file contains a file list section that is referenced by an INF CopyFiles directive, each file in the file list must be specified using the following format:

[file-list-section]
destination-file-name[,,flag]
destination-file-name[,,flag]
destination-file-name[,,flag]
...

The destination-file-name field is required, and the flag field is optional. File specifications must not include the optional source-file-name or temporary-file-name fields that are defined for file list sections used with the INF CopyFiles directive. This restriction is required for installing print drivers from a Web page.


Sample Printer INF Files

A sample printer .inf file is supplied with this DDK. The sample is located in a subdirectory of the directory tree containing DDK samples.


Directory Services for Printers

When a user installs a network-shared printer, the Windows® 2000 and later print folder, by default, also publishes the printer to the Windows 2000 (or later) Directory Services. Publication is accomplished by calling the spooler's SetPrinter function with an input structure of PRINTER_INFO_7, as described in the Platform SDK documentation.

Publishing a print queue makes it visible to users through the Search option on the task bar's Start menu.

The following topics provide more information about printer support for Directory Services:

Print Spooler Support for Printer Directory Services

Printer Driver Support for Printer Directory Services


Print Spooler Support for Printer Directory Services

Windows 2000 and later print spooler support for Directory Services consists of:

  • Publishing print queues.
  • Maintaining three registry keys.
  • Allowing access to spooler-maintained registry keys.
  • Returning a print queue's publication state.

Publishing Print Queues

The SetPrinter function, described in the Platform SDK documentation, allows callers to publish, unpublish, or update a print queue object. For these purposes, the SetPrinter function must be called with an input structure of PRINTER_INFO_7.

A print queue object can be published only if it is associated with the computer object describing the print server to which the user is connected. A user's ability to publish a print queue is determined by his or her access rights, as contained in the user's client security context. You can publish a print queue if you have Manage Printers permission on the print queue.

Maintaining Three Registry Keys

Three registry keys contain copies of all information published in the print queue object. The three keys are referenced using the following identifiers, defined in winspool.h:

Key | Definition
SPLDS_DRIVER_KEY | For storing driver-specific information, which can be supplied by the spooler or the driver.
SPLDS_SPOOLER_KEY | For storing spooler-supplied, spooler-specific information.
SPLDS_USER_KEY | For storing application-supplied, user-specific information.

The spooler uses SPLDS_DRIVER_KEY to store driver capabilities that can be obtained by calling the Platform SDK DeviceCapabilities function. The driver is responsible for storing driver capabilities that the spooler cannot obtain, as described in Printer Driver Support for Printer Directory Services. Values stored under these keys must be identified by SPLDS_-prefixed constants, defined in winspool.h.

The spooler keeps track of which values under these keys have been modified since the last time the print queue object was updated. Each time the spooler publishes or updates the print queue object, it copies all modified values into the object.

Allowing Access to Spooler-Maintained Registry Keys

The spooler allows printer drivers to access the three spooler-maintained registry keys by calling the SetPrinterDataEx, GetPrinterDataEx and EnumPrinterDataEx functions, which are described in the Platform SDK documentation. The SetPrinterDataEx function sets values under the keys, while GetPrinterDataEx and EnumPrinterDataEx return current values. (Drivers should not set values under the SPLDS_SPOOLER_KEY key.) Callers of these functions do not specify a complete registry path; the functions automatically determine the path to the specified print queue's registry entries.

Returning a Print Queue's Publication State

The GetPrinter function, described in the Platform SDK documentation, allows callers to determine if a print queue is currently published. For this purpose, the GetPrinter function must be called with an input structure of PRINTER_INFO_7. The function returns the print queue's publication state (published or unpublished) and object identifier.

All the previously mentioned functions are described in the Platform SDK documentation. The functions are not used exclusively for DS-related operations.


Printer Driver Support for Printer Directory Services

Printer drivers are not responsible for publishing a print queue to Directory Services. The Windows 2000 and later print folder creates a print queue object (by calling the spooler's SetPrinter function) during the process of installing the printer. (See Publishing Print Queues.)

Print queue properties are published so that a user can search for printers with particular properties by using the Search option on the task bar's Start menu. The print folder publishes some, but not all, of the printer capabilities that are available to it from DriverCapabilities. Only capabilities that are considered useful for browsing purposes are published.

Printer drivers can add or modify a print queue object's property information. The print queue properties that can be published are identified by SPLDS_-prefixed constants, defined in winspool.h. To add or modify printer properties, your driver must use these predefined property name identifiers.

To add or modify a print queue object's property information, carry out the following steps:

  1. Add property names and values to the registry, under the SPLDS_DRIVER_KEY, by calling the spooler's SetPrinterDataEx function.
  2. Call the spooler's SetPrinter function, with an input structure of PRINTER_INFO_7 (described in the Platform SDK documentation) and an action of DSPRINT_UPDATE, to inform the spooler that it should update the published print queue object. (Drivers should not specify an action of DSPRINT_PUBLISH.)

These steps should be implemented within the printer driver's DrvPrinterEvent function, when the function receives a PRINTER_EVENT_INITIALIZE event.

If a driver must obtain the current values for a printer's published properties, it should call GetPrinterDataEx or EnumPrinterDataEx to obtain the information from the registry, which is spooler-maintained and always up to date. An alternative way is to call GetPrinter to obtain the print queue's object identifier and then to call ADSI functions to obtain the values of the published properties. This technique is not recommended, both because it is more resource intensive and because returned data might not always be current.


Supporting Point and Print

This section provides the following topics that describe Windows® 2000 and later Point and Print technology:

Introduction to Point and Print

Supporting Point and Print During Printer Installations

Supporting Point and Print During Printer Connections


Introduction to Point and Print

Point and Print is a term that refers to the capability of allowing a user on a Windows 2000 and later client to create a connection to a remote printer without providing disks or other installation media. All necessary files and configuration information are automatically downloaded from the print server to the client.

Point and Print technology provides two methods by which you can specify files that should be sent from the print server to the client machine:

  • Files can be associated with a printer driver. These files are associated with every print queue that uses the driver.
  • Files can be associated with individual print queues.

For more information, see Supporting Point and Print During Printer Installations.

When a user application calls the AddPrinterConnection function (described in the Platform SDK documentation) to make a printer connection, the following operations are performed:

  • Driver-associated and queue-associated files are downloaded from the print server to the client.
  • Current values of the printer's configuration parameters, which are stored in the server's registry under the printer's key, are downloaded to the client.

For more information, see Supporting Point and Print During Printer Connections.


Supporting Point and Print During Printer Installations

To support Point and Print technology, it is necessary to indicate which driver-specific and queue-specific files need to be sent to a client when the client user connects to a print server. The following topics are provided:

Installing Driver-Specific Files

Installing Queue-Specific Files

Point and Print DLLs


Installing Driver-Specific Files

Files are associated with a printer driver by including them in the printer's .inf file. For more information, see Printer INF Files.

To provide Point and Print support for Windows 95/98/98 clients connected to Windows 2000 and later servers, see the description of the "Previous Names" data section in Printer INF File Data Sections.


Installing Queue-Specific Files

At printer installation time, a vendor-supplied installation application can specify a set of files, of any type, to be associated with a particular print queue. The files are downloaded to each client that connects to the print server. The installation application specifies the files by placing values in the registry, as illustrated in the following table.

Value Name | Value Type | Value
Directory | REG_SZ | Directory path to the files specified by Files. Used as both the source path on the server and the destination path on the client. This path is relative to the PRINT$ environment variable.
Files | REG_MULTI_SZ | Filenames of the files to be copied to a client when the client connects to the print server. Files can be DLLs, data files, or any other type of file.
Module | REG_SZ | Filename of an optional Point and Print DLL.

The application should create these values by calling the print spooler's SetPrinterDataEx function. The registry key specified with this call should be formatted as:

CopyFiles\ComponentName

where ComponentName is the name of the software component with which the files are associated. For example, files associated with Microsoft Image Color Management (ICM) are specified under the CopyFiles\ICM key. You specify the registry key name as an argument to the SetPrinterDataEx function, and the function creates the key as a subkey of the print queue's key on the print server.

Installation Example

As an example, suppose that an HP Color LaserJet printer is installed on a print server and is assigned the print queue name of "HpColor". Also suppose that Microsoft ICM requires the following two files to be associated with the print queue:

  • A color profile named hpclrlsr.icm, located in PRINT$\Color on the server.
  • A DLL named mscms.dll, located in PRINT$\Color on the server.

An installation application would call the ICM API function AssociateColorProfileWithDevice, which in turn calls SetPrinterDataEx to create the following server registry entries:

CopyFiles\ICM\Directory: Color
CopyFiles\ICM\Files: hpclrsr.icm
CopyFiles\ICM\Module: mscms.dll

The mscms.dll module is a Point and Print DLL that exports GenerateCopyFilePaths and SpoolerCopyFileEvent functions.


Point and Print DLLs

You can optionally supply a special Point and Print DLL by associating its name with the Module registry value. This DLL must export the following two functions:

GenerateCopyFilePaths
This function, which is called by both the server's spooler and the client's spooler, can be used to modify the directory path specified by the Directory registry value. Either the source path (on the server) or the destination path (on the client), or both, can be modified.
SpoolerCopyFileEvent
This function, also called by both the server's spooler and the client's spooler, receives an event code indicating the occurrence of certain connection-related printer events.

A Point and Print DLL need not export only these functions. For example mscms.dll, which is used by Microsoft's ICM component, also exports a set of ICM API functions.

Note that you can specify other DLLs in addition to, or instead of, a Point and Print DLL that exports GenerateCopyFilePaths and SpoolerCopyFileEvent. To do so, assign the DLL file names to the Files registry key instead of the Module registry key. (See Installing Queue-Specific Files).

On the print server, the Point and Print DLL must be located in one of the load paths searched by the Platform SDK LoadLibrary function.

After the installation application has placed the DLL's name in the server's registry by calling SetPrinterDataEx, all subsequent calls to SetPrinterDataEx result in a call to the DLL's SpoolerCopyFileEvent function, with a supplied event code of COPYFILE_EVENT_SET_PRINTER_DATAEX.

Unlike the files listed under the Files registry key (see Installing Queue-Specific Files), the Point and Print DLL is not copied from the print server to the client when the client connects to a printer. Instead, the DLL is assumed to already be client-resident when a connection to the print server is made. As a result, the DLL can be used for additional purposes not related to Point and Print functionality.

When determining if the DLL named under the Module key can be found, the client spooler checks the LoadLibrary path and then checks the driver directory. One method for installing the Point and Print DLL on a client is to specify its name in a printer .inf file as a dependent file, so the file can be copied to the client's driver directory during downloading of driver-specific files.


Supporting Point and Print During Printer Connections

When a user on a client system connects to a print server, driver-specific and queue-specific files must be sent from the server to the client. The following topics are provided:

Downloading Driver-Specific Files

Downloading Queue-Specific Files


Downloading Driver-Specific Files

A client system creates a connection to a print server by calling AddPrinterConnection. This call results in a call to GetPrinterDriver on the server, which reads the printer's .inf file in order to fill in a DRIVER_INFO_3 structure, followed by a call to AddPrinterDriver, with the DRIVER_INFO_3 structure as input. The AddPrinterDriver function causes all files listed in the DRIVER_INFO_3 structure to be sent to the client.

These functions and the DRIVER_INFO_3 structure are described in the Platform SDK documentation.


Downloading Queue-Specific Files

If a user decides to create a printer connection from his or her client system to a print server, and if an installation application has created the registry entries described in Supporting Point and Print During Printer Installations, the following events occur:

  1. The user application calls AddPrinterConnection, which is described in the Platform SDK documentation.
  2. The client's remote print provider (win32spl.dll) creates a connection to the server.
  3. The server's spooler sends driver files to the client.
  4. The client's win32spl.dll calls EnumPrinterKey and EnumPrinterDataEx on the server to copy the printer's registry entries.
  5. As the server's spooler enumerates registry values during processing of EnumPrinterDataEx, it performs the following operations each time it encounters a subkey of the printer's CopyFiles key, such as CopyFiles\ICM:
    • Loads the Point and Print DLL, if specified, and calls its GenerateCopyFilePaths function, which can modify source and/or destination paths.
    • Creates SourceDir and TargetDir keys, based on source and destination paths returned by GenerateCopyFilePaths, and returns them to the client spooler as EnumPrinterDataEx data. (These keys do not really exist on the server.)
  6. The client's win32spl.dll caches printer keys received in response to EnumPrinterData and EnumPrinterDataEx calls.
  7. For each subkey of the printer's CopyFiles key, such as CopyFiles\ICM, the client's win32spl.dll performs the following operations:
    • Loads the local Point and Print DLL, if one is provided, and calls its GenerateCopyFilePaths function, which can modify source and/or destination paths. (Inputs are the SourceDir and TargetDir keys received from the server.)
    • Downloads all files associated with the Files key from the server.
    • Logs an event, indicating Point and Print files were downloaded.
    • Calls the Point and Print DLL's SpoolerCopyFileEvent function, if a DLL is provided, specifying a COPYFILE_EVENT_FILE_CHANGED event.
  8. The client spooler calls the driver's DrvPrinterEvent function, specifying a PRINTER_EVENT_CACHE_REFRESH event.
  9. The client spooler calls the driver's DrvPrinterEvent function again, specifying a PRINTER_EVENT_ADD_CONNECTION event.
  10. If a Point and Print DLL is provided, the client spooler calls its SpoolerCopyFileEvent function, specifying a COPYFILE_EVENT_ADD_PRINTER_CONNECTION event.

Connection Example

As an example, assume that an installation application has defined the server registry entries described in the installation example. Additionally, assume that the server is named NTPRINT and the client is named MyClient.

To connect to the print queue named HpColor on NTPRINT, a user application on MyClient calls AddPrinterConnection as follows:

AddPrinterConnection("\\NTPRINT\HpColor")

On the server, the spooler loads mscms.dll and calls GenerateCopyFilePaths as follows:

GenerateCopyFilePaths(
    "HpColor",
    "Color",
    &SplclientInfo1,
    1,
    \\NTPRINT\PRINT$\Color,
    &dwSourceDirSize,
    "Color",
    &dwDestDirSize,
    COPYFILE_FLAG_SERVER_SPOOLER)

Microsoft ICM's mscms.dll module does not modify the source or destination paths, so it just returns ERROR_SUCCESS.

The server spooler returns the following keys to MyClient:

SourceDir: \\NTPRINT\PRINT$\Color
TargetDir: "Color"

On the client, the value for TargetDir expands to C:\Winnt\System32\Spool\Drivers\Color.

The spooler on MyClient performs the following operations:

  • Downloads mscms.dll and calls GenerateCopyFilePaths as follows:
    GenerateCopyFilePaths(
    "\\NTPRINT\HpColor",
    "Color",
    &SplclientInfo1,
    1,
    \\NTPRINT\PRINT$\Color,
    &dwSourceDirSize,
    "C:\Winnt\System32\Spool\Drivers\Color",
    &dwDestDirSize,
    COPYFILE_FLAG_CLIENT_SPOOLER)

    Microsoft ICM's mscms.dll module does not modify the source or destination paths, so it just returns ERROR_SUCCESS.

  • Downloads hpclrlsr.icm to C:\Winnt\System32\Spool\Drivers\Color.
  • Logs an event, indicating Point and Print files were downloaded.
  • Calls the SpoolerCopyFileEvent function in mscms.dll, specifying a COPYFILE_EVENT_FILE_CHANGED event.
  • Calls the printer driver's DrvPrinterEvent function, specifying a PRINTER_EVENT_CACHE_REFRESH event.
  • Calls the printer driver's DrvPrinterEvent function again, specifying a PRINTER_EVENT_ADD_CONNECTION event.
  • Calls the SpoolerCopyFileEvent function in mscms.dll, specifying a COPYFILE_EVENT_ADD_PRINTER_CONNECTION event.


Specifying Printer Driver Version Numbers

Unidrv- and Pscript5-based printer minidrivers, as well as monolithic printer drivers (drivers developed completely by an IHV), should use printer driver versioning on Microsoft® Windows® XP and later. The Windows XP and later print spooler uses the versioning information to enable it to select the correct driver files during the installation of a new operating system version or service pack, or when a new Point and Print connection is established.

Printer driver versioning is not supported on Windows 2000 or previous NT-based operating system versions. In those operating system versions, the print spooler bases its decision on whether to replace a particular driver file solely on the file's timestamp. A newer file is always chosen in preference to an older file, even though the file with the newer date might have the old feature set. Because it is so easy to change the date of a file, this can prevent the spooler from making the correct choice in the files it chooses.

To ensure that the correct versions of your driver files are installed, simply add version numbers to those files. You can do this by making minor modifications to pdrvver.h (which ships with the DDK), and including that file in your printer driver DLL resource file. Setting up a monolithic driver, using INF-based installation, also benefits from driver versioning, because a newer DLL is not overwritten by an older DLL, even though the older DLL might have a more recent timestamp.

The pdrvver.h header consists almost exclusively of preprocessor #define directives. The first two, VER_FILETYPE and VER_FILESUBTYPE, which must not be modified, indicate that the file is a resource file for a driver, specifically a printer driver. (The constants VFT_DRV and VFT2_DRV_VERSIONED_PRINTER, which appear with VER_FILETYPE and VER_FILESUBTYPE, are described in the Platform SDK documentation for the VS_FIXEDFILEINFO structure.) The ones you need to change are the last four, which are the following:

VER_FILEVERSION
This constant should be set to a sequence of four comma-delimited WORD values. The third and fourth WORDs are used to set the high and low WORDs, respectively, of the VS_FIXEDFILEINFO structure's dwFileVersionLS member. The meaning of each of the four WORDs is described in the following table:
Value | Meaning
First WORD | Reserved. This value should be set to 0.
Second WORD | Represents the major version of the driver. For user-mode drivers, set this to 0x0003. For kernel-mode drivers, set this to 0x0002.
Third WORD | Represents the feature set number.
High byte Represents a major feature set release. A newer release is assumed to have a superset of the functionality of the previous release. Increment this value with each new major release.

For Unidrv- and Pscript5-based minidrivers running on Windows XP and later, including Windows Updates and Service Packs, this should be set to 0x05.
Low byte Represents a minor feature set release - a new release from the same code base or architecture. Increment this value with each new minor release.

For Unidrv- and Pscript5-based minidrivers running on the following operating system releases, this byte should be set as shown:

Windows XP: Set to 0x01.
First Windows XP Service Pack: Set to 0x01. (The particular bug fix number appears in the fourth WORD.)
First Windows Update: Set to 0x02.
Fourth WORD | Represents a bug fix or service pack release. Increment this value on release of a new binary, when it is a collection of bug fixes or a service pack.

Here is a monolithic driver example:

#define VER_FILEVERSION    0, 3, 0X0100, 0X0002

In order, left to right, the first WORD value is zero, which it must be. The value of the second WORD is three, indicating that this is a user-mode driver. In the third WORD, the high byte's value (0X01) denotes that this is the first major release, and the low byte of the same WORD (0x00) indicates that there are, so far, no minor releases. The fourth WORD (0x0002) indicates that this is the second bug fix or service pack release. (No distinction is made between these types of releases.)

Here are some Unidrv-/Pscript5-based minidriver examples:

#define VER_FILEVERSION    0, 3, 0X0501, 0X0001

In order, left to right, the first WORD value is zero, as before. The value of the second WORD is three, indicating that this is a user-mode driver. In the third WORD, the high byte and low byte values (0X05 and 0x01, respectively) denote that this is a release for Windows XP. The fourth WORD (0x0001) indicates that this is the first bug fix or service pack release.

#define VER_FILEVERSION    0, 3, 0X0502, 0X0000

As before, the first WORD is zero, and the second WORD indicates that this is a user-mode minidriver. The third WORD (0x0502) indicates that this is the first Windows Update version released after Windows XP. The fourth WORD (0x0000) indicates that this is neither a bug fix nor service pack release.

VER_FILEDESCRIPTION_STR
This constant should be set to a name that identifies the driver, as in the following example.
#define VER_FILEDESCRIPTION_STR    "Sample Printer Driver Resource DLL"
VER_INTERNALNAME_STR
Set this constant to a name that specifies the internal name of the file (not including the path), as in the following example. For more information, see the Platform SDK documentation.
#define VER_INTERNALNAME_STR    "SAMPLERES.DLL"
VER_ORIGINALFILENAME_STR
Set this constant to a name that specifies the original name of the file (not including the path), as in the following example. For more information, see the Platform SDK documentation.
#define VER_ORIGINALFILENAME_STR    "SAMPLERES.DLL"


CPSUI

This section describes the Common Property Sheet User Interface (CPSUI). The following topics are provided:

Introduction to CPSUI

Sample CPSUI Application

CPSUI-Supplied Functions

Application-Supplied Callback Functions

Creating Property Sheet Pages


Introduction to CPSUI

The Common Property Sheet User Interface (CPSUI) is a user-mode dynamic link library that enables developers to create property sheet pages having a common, standard appearance. Most pages created with CPSUI consist of:

  • A treeview window, with each tree node representing a selectable, user-modifiable page option.
  • A context menu for each tree node, which is used for displaying and selecting parameter values associated with the node.

Context menu items are created using a predefined set of CPSUI-supported window controls. A user selects an option in the treeview window, then selects the desired value for that option using the context menu.

While CPSUI was designed to be used by any application, its primary use is by the NT-based operating system printing subsystem. Therefore, the DDK's Design Guide and Reference focus on this use.

CPSUI provides predefined property sheet pages for printers and print documents. CPSUI-supplied pages consist of the Device Settings page for a printer, and the Layout, Paper/Quality, and Advanced pages for a document. These pages can be viewed from the print folder's Printer menu.

The print spooler, in conjunction with printer interface DLLs, use these predefined pages to create property sheets for printers and documents. For information about how the print spooler, printer interface DLLs, and CPSUI interact, see Using CPSUI with Printer Drivers.

Customized user interface code created for Microsoft's Unidrv and Pscript drivers can also use CPSUI. For more information, see User Interface Plug-ins.


Sample CPSUI Application

Source code for CPSUISAM, a sample CPSUI application, is included with this DDK. The application causes CPSUI to call into the print spooler to create property sheet pages for the system's default printer. The application then creates an additional property sheet page, in order to illustrate some of the techniques that can be employed when using CPSUI to create a new page.

Note: Printer interface DLLs should not call into the print spooler. CPSUISAM illustrates some of the capabilities of CPSUI but does not represent techniques that should be used by printer interface DLLs. Instead, these DLLs should follow the steps described in Using CPSUI with Printer Drivers.


CPSUI-Supplied Functions

CPSUI provides the following two important functions for applications:

  • CommonPropertySheetUI

    The CommonPropertySheetUI function is CPSUI's entry point. The function causes property sheet pages to be created and displayed, and then allows them to be viewed and modified by a user.

    When an application calls CommonPropertySheetUI, it supplies the address of a page creation callback that describes the pages to be created. CPSUI calls this callback to obtain the page descriptions. Then it displays the pages, allows the application user to modify values contained in the page, and delivers modified values to the application using page event callbacks. The CommonPropertySheetUI function doesn't return until the user has dismissed the property sheet by clicking on OK or Cancel.

    Note that printer interface DLLs do not call this function; it is called by the print spooler.

  • ComPropSheet

    The ComPropSheet function is the means by which applications describe property sheet pages to CPSUI, so that CPSUI can create and display them. CPSUI applications call this function from within page creation callbacks. Typically, a page description includes a pointer to a page event callback, which CPSUI will call when the application user modifies page values.

For a detailed description of when these functions are called, see Using CPSUI with Printer Drivers.

Two additional CPSUI-supplied functions, SetCPSUIUserData and GetCPSUIUserData, can be used by application-supplied dialog box procedures to store and retrieve an application-supplied value.


Application-Supplied Callback Functions

CPSUI communicates with applications by callback functions. A CPSUI application must supply two types of callbacks:

Page creation callbacks

Page event callbacks


Page Creation Callbacks

When an application makes an initial call into CPSUI's entry point function (CommonPropertySheetUI), it must include the address of a PFNPROPSHEETUI-typed callback function. This callback function is responsible for describing property sheet pages and sending these descriptions to CPSUI for creation.

CPSUI's CommonPropertySheetUI function immediately calls back to the PFNPROPSHEETUI-typed function, supplying the address of a PROPSHEETUI_INFO structure. The application can then call CPSUI's ComPropSheet function, supplying page descriptions that CPSUI can use to create the pages, as illustrated in the following diagram:

Application-CPSUI Communication

For more information, see Methods for Specifying Pages.


Page Event Callbacks

When a user interacts with a property sheet page, the operation system sends notification of such window events as a changed focus or a modified value. How a CPSUI application receives notification of a page's window events depends on how the application has defined the page:

  • If the page was defined using CPSUI-supplied pages and templates, it can supply a CPSUI message handler.
  • If the application created a customized page that is not supplied by CPSUI, it must provide a dialog box procedure. For more information, see Dialog Box Procedures and CPSUI.

A CPSUI application supplies CPSUI with the address of a page event callback when it calls the ComPropSheet function.


CPSUI Message Handler

A CPSUI message handler is a callback function that is defined using the _CPSUICALLBACK function type. This type of page event callback is recommended if you are using CPSUI-supplied pages and templates.

When a user interacts with a property sheet page and causes an event to occur, CPSUI intercepts the event and calls the _CPSUICALLBACK-typed function, supplying a CPSUICBPARAM structure that describes the reason the callback function is being called.

The callback function must handle the event, and then return a status value to CPSUI that indicates if the page needs to be redisplayed or reinitialized.


Dialog Box Procedures and CPSUI

A dialog box procedure is a callback function that handles window messages sent by the system. This type of page event callback is required if you are creating a customized property sheet page that is not supplied by CPSUI. (You can also use dialog box procedures with CPSUI-supplied pages and templates, but use of a CPSUI message handler is recommended.) For more information about dialog box procedures, see DialogProc in the Platform SDK documentation. Pointers to dialog box procedures are declared using the DLGPROC pointer type, also described in the Platform SDK documentation.

For all property sheet pages created using CPSUI, window messages are first intercepted by CPSUI before being passed to the application-supplied dialog box procedure. If the page was defined using a CPSUI-supplied template, the application-supplied dialog procedure can supply a return value indicating that CPSUI should process the message.

A dialog box procedure can use the SetCPSUIUserData and GetCPSUIUserData functions to store and retrieve an application-supplied value.

For more information about using dialog box procedures with CPSUI, see the Comments section for DLGPAGE.


Creating Property Sheet Pages

Property sheet pages created using CPSUI are made up of property sheet options, where each option represents a user-modifiable value. Dialogs for property sheet options are created using a set of CPSUI-supported window controls that let a user modify an option's value.

CPSUI-supplied window controls can be displayed within CPSUI-supplied pages and templates, or they can be used with customized pages. There are several methods for specifying pages, all of which involve calling CPSUI's ComPropSheet function.

Creating property sheet pages for printers and print documents involves using CPSUI with printer drivers and requires interaction between an application, the print spooler, a printer interface DLL, and CPSUI.


Property Sheet Options

A property sheet option is a displayable, selectable item on a property sheet page. Typically, users can modify an option's value. CPSUI helps applications create options in a standard format, using a predefined set of CPSUI-supported window controls. Applications do not have to provide resources for these controls.

Each property sheet page typically contains several options. For each property sheet option, a CPSUI application must use the following CPSUI structures:

  • One OPTITEM structure, which identifies the option's display name and other characteristics.
  • One OPTTYPE structure, which identifies the option's display dialog type (CPSUI option type).
  • One or more OPTPARAM structures, which identify the option's user-selectable parameter values.

To use these CPSUI structures to describe property sheet options, the page containing the option must be defined using a COMPROPSHEETUI structure.


CPSUI-Supported Window Controls

CPSUI supports a set of window controls that provide a consistent interface to the user. Use of these window controls is particularly important when creating property sheet pages for printer devices and documents, because users expect a consistent interface for all printers.

CPSUI-supported window controls include:

  • Boxes containing two or three radio buttons
  • Scroll and track bars
  • Edit, list, and combo boxes
  • An up/down arrow box
  • A check box

This set of window controls must always be used when specifying property sheet options. The window controls are specified by using CPSUI option types. While usually not necessary, appearance of these controls can be customized. For more information, see Customizing CPSUI-Supported Window Controls.

CPSUI also defines two special controls, called an extended check box and an extended push button. These controls, which provide capabilities beyond those of standard check boxes and push buttons, can be specified using the EXTCHKBOX and EXTPUSH structures, respectively.


Customizing CPSUI-Supported Window Controls

If you are using CPSUI-supported window controls in conjunction with CPSUI-supplied pages and templates, CPSUI provides window control resources that describe the controls in a manner that allows them to fit together. Therefore, you do not need to provide resources for the controls.

On the other hand, if you are creating a property sheet page that does not use a CPSUI-supplied page or template, you must customize the CPSUI-supported window controls that you use. To do this, you need to provide window control resources for the CPSUI option types. You must specify identifiers for these resources using the BegCtrlID member of each option's OPTTYPE structure.

If you are customizing CPSUI-supported window controls, remember that CPSUI does not display an option if the OPTIF_HIDE flag set in the OPTITEM structure. CPSUI moves the remaining controls to fill the space normally taken up by the hidden option. Therefore, if you are creating a page containing several simultaneously-displayed options, the following rules should be obeyed:

  • Each option should occupy the entire horizontal space of the property sheet page.
  • Option dialogs should not overlay each other.
  • For options represented by radio buttons that are arranged from left to right, buttons and icons should be aligned on the x axis. If the buttons are arranged from top to bottom, buttons and icons should be aligned on the y axis.
  • If several items share one group box, the group box must belong to the first OPTITEM, which is the topmost item in the group box. The group box must be large enough to contain all items associated with it.

Also, note that if radio buttons and icons are arranged top to bottom and some of these controls are hidden, CPSUI does not remove resulting white space in the y direction.


CPSUI-Supplied Pages and Templates

CPSUI supplies a set of predefined property sheet pages, along with three page templates. Predefined property sheet pages include the following:

  • A set of three pages, with tab titles of Layout, Paper/Quality, and Advanced. These pages are meant to contain document properties for printers, and can be used for creating a property sheet from within a printer interface DLL's DrvDocumentPropertySheets function.
  • A single page, with a tab title of Advanced. Again, the page is meant to contain document properties for printers, and can be used for creating a property sheet from within a printer interface DLL's DrvDocumentPropertySheets function.
  • A single page, with a tab title of Device Settings. This page is meant to contain printer properties, and can be used for creating a property sheet from within a printer interface DLL's DrvDevicePropertySheets function.
  • A single, generic treeview page with no predefined title. Any CPSUI application can use this page.

To use a predefined page, an application must identify it using the pDlgPage member of a COMPROPSHEETUI structure.

CPSUI also supplies three predefined page templates. CPSUI uses these templates for creating its predefined pages. Applications can also use them. The templates consist of the following:

  • A treeview page template, which CPSUI uses to create the predefined Advanced and Device Settings pages. This template consists of a treeview control that contains a node for each property sheet option. A context menu is associated with each node of the tree. Each node's context menu provides the means by which a user can modify the option's value. CPSUI supplies a dialog box procedure for this template, which handles Windows messages for all the CPSUI-supported window controls.
  • Two multiple control templates, which CPSUI uses to create the predefined Layout and Paper/Quality pages. CPSUI supplies a dialog box procedure for this template, which handles Windows messages for all the CPSUI-supported window controls.

To use a predefined page template, an application must identify it using the DlgTemplateID member of a DLGPAGE structure.


Methods for Specifying Pages

An application can use any of three methods to specify property sheet pages to CPSUI. Each of the following methods involves calling CPSUI's ComPropSheet function, specifying one of the ComPropSheet function codes.

  • Supplying a COMPROPSHEETUI structure

    If an application describes a property sheet page by passing a COMPROPSHEETUI structure to ComPropSheet, it can:

    • Use one of the CPSUI-supplied pages and templates to specify a predefined, standard page type that printer interface DLLs can use for printer property sheets.
    • Specify a set of user-modifiable property sheet options that will appear on the page.
    • Specify a page event callback function that CPSUI will call when a user views or modifies the page's options.
  • Supplying a PROPSHEETPAGE structure

    A PROPSHEETPAGE structure (described in the Platform SDK documentation) can be used to describe a property sheet page, if the page cannot be constructed using the common (standard) dialogs available when using a COMPROPSHEETUI structure. Printer interface DLLs typically should not need to use this method.

  • Supplying a callback function

    An application can pass ComPropSheet the address of a PFNPROPSHEETUI-typed callback function, which CPSUI immediately calls. The callback function is responsible for calling ComPropSheet itself to create property sheet pages.

    The print spooler uses this method to inform CPSUI of the existence a printer interface DLL's DrvDocumentPropertySheets and DrvDevicePropertySheets functions. Likewise, the Unidrv and Pscript drivers use the technique to inform CPSUI of the existence of IPrintOemUI::DocumentPropertySheets and IPrintOemUI::DevicePropertySheets COM methods in user interface plug-ins.

Whichever method is used for specifying new pages, the pages must be assigned to a group parent by passing a group parent handle to the ComPropSheet function.


Group Parent

Property sheet pages can be grouped together by assigning them to a single group parent. You can create a group parent by calling CPSUI's ComPropSheet function with a CPSFUNC_INSERT_PSUIPAGE function code, and specifying PSUIPAGEINSERT_GROUP_PARENT as the Type member for an INSERTPSUIPAGE_INFO structure.

When a new group parent is created, a handle is returned. The handle can then be used as the hComPropSheet parameter to ComPropSheet, when adding or deleting property sheet pages.

Additionally, a group parent handle is received as the hComPropSheet member of the PROPSHEETUI_INFO structure that is received by an application's PFNPROPSHEETUI-typed callback function. If you don't create new group parents, all property sheet pages should be assigned to this one.

You can create additional group parents under each group parent that is created. The property sheet itself is considered to be the top-level group parent. If you do not explicitly create additional group parents, all added property sheet pages are assigned to the top-level parent.


Using CPSUI with Printer Drivers

The print spooler, in conjunction with printer interface DLLs, uses CPSUI to create property sheet pages for print documents and printer devices. The following steps are involved when an application (such as Microsoft® Word) displays a property sheet for a print document:

  1. The application calls the print spooler's DocumentProperties function (described in the Platform SDK documentation), specifying the printer on which the document is to be printed.
  2. The print spooler calls CPSUI's entry point function, CommonPropertySheetUI, specifying an internal PFNPROPSHEETUI-typed callback function.
  3. CPSUI calls the spooler's PFNPROPSHEETUI-typed callback function.
  4. The spooler's PFNPROPSHEETUI-typed callback function calls CPSUI's ComPropSheet function (with a CPSFUNC_ADD_PFNPROPSHEETUI function code) to notify CPSUI of the address of the appropriate printer interface DLL's DrvDocumentPropertySheets function.
  5. CPSUI calls the printer interface DLL's DrvDocumentPropertySheets function.
  6. The printer interface DLL's DrvDocumentPropertySheets function calls CPSUI's ComPropSheet function (typically with a CPSFUNC_ADD_PCOMPROPSHEETUI function code) to provide CPSUI with property sheet page descriptions and page event callbacks.
  7. CPSUI's ComPropSheet function calls CreatePropertySheetPage (described in the Platform SDK documentation) to create the property sheet pages specified by the printer interface DLL. CPSUI then calls PropertySheet (described in the Platform SDK documentation) to display the property sheet pages.

The following diagram illustrates these steps.

Modules Involved in Displaying a Property Sheet

As the application user traverses the property sheet pages and modifies option values, the operating system notifies CPSUI of page events and CPSUI, in turn, calls the page event callback supplied by the printer interface DLL. The page event callback handles page events and stores newly selected option values internally, as necessary.

When the user dismisses the property sheet by clicking on the Ok or Cancel button, CPSUI destroys the pages and causes the CommonPropertySheetUI function to return to the print spooler, which then returns control to the application.

When an application displays a property sheet for a printer device instead of a print document, the same steps are followed, except that the application calls the spooler's PrinterProperties function and the spooler passes the address of the printer interface DLL's DrvDevicePropertySheets function to CPSUI.


Color Management for Printers

This section describes the operations that printer drivers must perform to support color management. The following topics are provided:

Enabling Color Management

Controlling Color Management

Locating ICC Profiles

Installing ICC Profiles


Enabling Color Management

Color management can be enabled by either an application or a printer driver. Applications can enable color management by either of the following two methods:

  • Calling SetICMMode (described in the Platform SDK documentation), specifying ICM_ON.

    This method enables system-controlled color management.

  • Specifying a DEVMODE structure when calling CreateDC to create a print job, and setting either DMICMMETHOD_SYSTEM, DMICMMETHOD_DRIVER, or DMICMMETHOD_DEVICE in the DEVMODE structure's dmICMMethod member.

    This method allows the application to select system-controlled, driver-controlled, or device-controlled color management (assuming the specified control type is supported).

Printer drivers can enable color management by setting either DMICMMETHOD_SYSTEM, DMICMMETHOD_DRIVER, or DMICMMETHOD_DEVICE in the dmICMMethod member of the driver's default DEVMODE structure. (An application can override the default setting if supplying a DEVMODE structure for CreateDC. Additionally, the driver is responsible for storing the user's choice for color management during execution of the driver's DrvDocumentPropertySheets function.)


Controlling Color Management

Color management for a printer can be controlled by an application, the system (GDI), the driver, or device hardware. The driver determines which component is managing color correction by examining flags within the BRUSHOBJ and XLATEOBJ structures that are passed to its implementations of graphics DDI drawing functions. The following flags are defined:

Flag | Definition
BR_DEVICE_ICM in BRUSHOBJ XO_DEVICE_ICM in XLATEOBJ | Color management is being performed by the driver or the device.
BR_HOST_ICM in BRUSHOBJ XO_HOST_ICM in XLATEOBJ | Color management is being performed by the application or the system (GDI).

The following topics describe driver support for these color management scenarios:

System Control

Driver Control and Device Control

Supporting CMYK Color Space

Color Management of JPEG and PNG Images


System Control

System-controlled color management is the default color management type. It is also the recommended type for printers. If color management is enabled, GDI corrects the colors of all DIBs, pens, and brushes before sending them to the driver's printer graphics DLL, based on the input and output color spaces and installed ICC profiles.

No ICM-specific code needs to be added to a printer driver to support system-control color management, other than indicating support for CYMK color space (if appropriate), as described in Supporting CMYK Color Space.


Driver Control and Device Control

If color management control is provided by either the driver or by printer hardware, the driver's printer graphics DLL must set the GCAPS_ICM flag in the DEVINFO structure.

The driver must indicate support for CYMK color space (if appropriate), as described in Supporting CMYK Color Space.

Printer graphics DLLs must define the following three functions:

DrvIcmCreateColorTransform
DrvIcmDeleteColorTransform
DrvIcmCheckBitmapBits

GDI calls the DrvIcmCreateColorTransform function to supply the driver with ICC profiles (described in the Platform SDK documentation) for the print job. Given these profiles, the function can create an internal color transform to use when correcting color information. A color transform is a driver-specific, internally defined mapping from one color space to another. The function returns a handle to the transform, which GDI stores.

Flags within the BRUSHOBJ and XLATEOBJ structures indicate whether color management is being performed by the system (or application) or by the driver (or device). Within each driver-implemented graphics DDI drawing function that receives either (or both) of these structures, the flags must be checked. If the system or application is currently handling color management, the driver or device must not. If driver or device color management is enabled, the graphics DDI function must call BRUSHOBJ_hGetColorTransform or XLATEOBJ_hGetColorTransform (or both) to obtain a handle to the color transform to be used. The handle will be one that the driver provided in response to a previous call to its DrvIcmCreateColorTransform function.

Handling Proprietary Color Management

For some devices, proprietary color management is performed (either by the driver or by hardware) regardless of whether ICM has been enabled. Drivers for such devices must not allow color correction to be performed if the received image data has already been corrected. Pre-corrected data can be received if:

  • An application has color-corrected the image "outside the DC" (see the Platform SDK documentation).
  • Color management is being handled by the system.

For either of these scenarios, both the BR_HOST_ICM flag in the flColorType member of BRUSHOBJ and the XO_HOST_ICM flag in the flXlate member of XLATEOBJ will be set. These flags can be set even if the dmICMMethod member of DEVMODE is DMICMMETHOD_NONE.


Supporting CMYK Color Space

Regardless of whether color management is being handled by the application, system, driver, or device, a printer graphics DLL must indicate whether it supports the CMYK color space. This is done by setting the GCAPS_CMYKCOLOR flag in the DEVINFO structure. If this flag is set and CMYK profiles are in use, then GDI sends CMYK color data, instead of RGB data, to the printer graphics DLL for bitmaps, brushes, and pens. GDI also sets the following flags:

  • The BR_CMYKCOLOR flag in the flColorType member of the BRUSHOBJ structure.
  • The XO_FROM_CMYK flag in the flXlate member of the XLATEOBJ structure.

Note that if the driver supports CMYK color space, it must also support halftoning. Thus if the driver sets the GCAPS_CMYKCOLOR flag in DEVINFO, it must also set GCAPS_HALFTONE.


Color Management of JPEG and PNG Images

For printers that provide hardware support of JPEG and PNG compressed images, color management must be handled by the driver or device and cannot be handled by GDI.

Before an application sends a JPEG or PNG compressed image to a printer, it will call ExtEscape with either the CHECKJPEGFORMAT or CHECKPNGFORMAT escape code. This results in a call to the driver's DrvQueryDeviceSupport function, with a query type of either QDS_CHECKJPEGFORMAT or QDS_CHECKPNGFORMAT and a buffer containing the compressed image.

The driver can examine the image data and determine if it can support the image. Supporting the image must include performing color transformations if either the XLATEOBJ structure's XO_DEVICE_ICM flag or XO_HOST_ICM flag is set, because GDI cannot perform color transformations on such images.

For these compressed images, color space information is typically contained within the image data. One exception is JFIF files, which are YCbCr-encoded and for which the default sRGB space is a good approximation. However, a JFIF file might contain a proprietary APPx marker that specifies a color space, in which case the driver must transform the image using the color space.

For more information about supporting JPEG and PNG compressed images, see the Comments section for DEVINFO.


Locating ICC Profiles

When color management is enabled, GDI searches for an appropriate ICC profile, using the following steps:

  1. If the driver's printer interface DLL provides a DrvQueryColorProfile function, the GDI client calls the function to give the driver an opportunity to specify a profile. If the function returns a profile, it is used.
  2. If DrvQueryColorProfile does not exist or does not return a profile, GDI searches the color directory for profiles that have been installed for the specified printer type. GDI uses the first profile it finds that matches resolution, media type, and dithering settings in the DEVMODE structure.
  3. If the color directory does not contain any profiles for the specified printer type that match the specified DEVMODE contents, GDI uses the system's default sRGB profile.

For more information, see Installing ICC Profiles. Additional information about ICC profiles can be found in the Platform SDK documentation.


Installing ICC Profiles

To install ICC profiles for a printer, the files must be listed in a printer .inf file.

Following is an example of an .inf file that causes two ICC profile files to be installed. Note that profile files are written to the color directory, which has a printer DIRID value of 66003.

[Version]
Signature="$Windows NT$"
Provider="My Company"
ClassGUID={4D36E979-E325-11CE-BFC1-08002BE10318}
Class=Printer

[My Company]
"My printer model" = MYDRIVER,My_Printer_Model

[MYDRIVER]
DriverFile=DRVR.DRV
DataFile=DRVR.DRV
CopyFiles=@DRVR.DRV,MY_COLOR_PROFILES
DataSection=MYDATA

[MYDATA]
HelpFile=DRVR.HLP
DefaultDataType=EMF

[MY_COLOR_PROFILES]
profile1.icm
profile2.icm

[DestinationDirs]
DefaultDestDir=11
MY_COLOR_PROFILES =66003


Supporting Printers on Terminal Servers

Microsoft® Windows® 2000 and later supports Terminal Services, a technology that allows multiple users to connect to a single server system. This server system is called a terminal server. For a detailed discussion of Terminal Services, see the Platform SDK documentation.

If you are developing a printer minidriver or driver for Windows 2000 or later, you do not have to do anything special to support printers connected to terminal servers. However, you must follow all design, implementation, and installation guidelines specified in this DDK. Specifically, you must use the following rules:

  • If possible, support your printer by simply providing a minidriver that works with one of the following Microsoft-supplied drivers:

    Microsoft Universal Printer Driver

    Microsoft Postscript Printer Driver

    Microsoft Plotter Driver

    Most new printers can be supported by one of these drivers.

  • If your device must be supported by a custom driver, your driver must adhere exactly to Microsoft's printer driver architecture. Specifically:
    1. You must create a printer interface DLL.
    2. You must create a printer graphics DLL. This DLL can execute in either user mode or kernel mode, but user mode is preferred.
    3. If you create kernel-mode code, you must test the code using Driver Verifier.
    4. You must provide an installation procedure based on .inf files, as described in Installing and Configuring Printer Drivers.

    All custom driver code must be re-entrant. User-mode code should employ critical section objects (described in the Platform SDK documentation). Kernel-mode code should use semaphores (see EngCreateSemaphore and related functions).

    Printer drivers and custom spooler components must access the registry only through interfaces provided specifically for these drivers and spooler components, as described in appropriate sections of this DDK.

Installation Considerations

Usually, all you need to do for installation is provide an .inf file that can be read by Microsoft's printer class installer when a user invokes the Add Printer wizard. Sometimes, custom setup code (a co-installer or class installer) is also needed. If you must create custom setup code, remember the following:

  • Either the user or the setup code must put the terminal server into installation mode. (For more information, see the Platform SDK documentation.)
  • Don't attempt to replace system files. Windows File Protection prohibits system file replacement.
  • Avoid requiring system reboots, as much as possible. Use the following guidelines:
    1. Don't replace driver files that haven't changed. For example, files shared by several devices shouldn't be updated if the most current version is already installed.
    2. If a file must be replaced, the setup code should take steps to unload the old version and then load the new version (for example, by stopping the driver service, replacing the file, then restarting the service).
    3. Requiring a user to log off, then re-log on, is preferable to requiring a system reboot.

For more information about co-installers and class installers, see Writing a Co-installer and Writing a Class Installer.

Note Before writing custom setup code, it is important to read the Terminal Services programming guidelines provided in the Platform SDK documentation.

User Interface Considerations

Custom setup code that is run by a user can display a user interface.

Almost all printer driver code runs in the spooler's execution context and therefore cannot display a user interface. User interfaces can be displayed only by printer interface DLLs, and only from within the following functions:

  • The DrvDevicePropertySheets and DrvDocumentPropertySheets functions, which create property pages.
  • The DrvPrinterEvent function, which receives event codes identifying printer events. Note that the function can display a user interface only for the PRINTER_EVENT_ADD_CONNECTION and PRINTER_EVENT_DELETE_CONNECTION event codes.

All other printer driver code executes in the spooler's context. From this context, calling MessageBox or MessageBoxEx is allowed, but you must set MB_SERVICE_NOTIFICATION. These functions are described in the Platform SDK documentation.

.


Printer Driver Testing Tools

Print Gremlin (pGremlin.exe) is a testing tool that can be used to test coverage of Unidrv and Pscript5 printer minidrivers running on Windows 2000 and later operating system releases.


Print Gremlin

Print Gremlin (pGremlin.exe) is a tool intended to provide comprehensive test coverage of Unidrv and Pscript5 printer minidrivers running on Windows 2000 and later operating system releases. It is also useful for exercising other kinds of printer minidrivers, although code coverage for these minidrivers varies and is generally not as complete as it is for the Unidrv and Pscript minidrivers. Printer vendors should use this tool to ensure that their printer drivers are robust and that they produce correct output. In the future, WHQL will be using a variant of Print Gremlin as the WHQL logo test requirement, eventually replacing WinPARTy for that purpose.

Print Gremlin was developed to reduce the reliance on pure application testing of printer minidrivers, which seldom exercises all code and data paths in a printer minidriver. Instead, Print Gremlin exercises a large majority of the core driver code, primarily in the rendering module. This coverage includes calls to all of the graphics DDIs exposed by the core drivers. For WHQL testing this is limited to just the graphics DDIs that are called by GDI and the spooler. The rationale for this is that drivers should be responsible only for those graphics DDIs that the operating system actually calls and uses.

Print Gremlin exercises some of the user interface module, but is not directly targeted at it. Vendors will still need to perform their own user interface testing, such as ensuring that the constraints are working correctly, settings are sticky, and that turning a feature on produces the expected results. (For example, setting the mode to Duplex should produce duplex output.) Print Gremlin directly creates and alters a DEVMODE structure, and uses the user interface to validate what it creates or modifies in this structure.

Usage

pGremlin  [option  [option [...]]]

Option is one of the following:

Option | Meaning
/? | Display usage information.
/InstallCoveragePrinters | Install printers used for regression and code coverage.

Note: By default, Print Gremlin prints to currently installed printers, and coverage printers are not installed.

Installing Print Gremlin

To install Print Gremlin, start the Print Gremlin Setup Wizard, and respond to the dialog boxes that it displays.

Setting Up Target Devices

The vendor installs printers that use the print driver models to be tested. For the best coverage, the vendor should install a printer instance for each desired configuration, such as Draft, Better, and Best Quality, or for each different font downloading option. This way, multiple configurations can be covered in one pass of the tool.

Analyzing Output

After you run Print Gremlin, examine the printer's output to verify that it appears as expected. Ideally, each output page should look the same as the EMF that generated it. The EMF files, which are in the same directory as pGremlin.exe, can be viewed with Image Preview. Except for differences in the way a display device and a printer display an image, the display device and printer versions should appear the same, or nearly so.

For some combinations of print device and display device, there might be significant differences. For example, dot matrix devices and pen plotters should not be expected to produce images that closely match the quality of those produced by the display device. Certain printer settings can also affect the quality of output. For example, a printer set at 3 BPP will not produce a gradient fill of the same quality as that of another printer set at 24 BPP. The first printer has at most eight colors to work with, thereby making the gradient fill appear very blocky.

Common Problems Found with Print Gremlin

The most common kinds of problems that Print Gremlin finds are:

  • Writing beyond the end of a buffer
  • Accessing a NULL pointer
  • Passing corrupt data structures to GDI
  • Using memory after it has been freed
  • Freeing memory more than once
  • Ignoring a function's return value


USBPRINT Interface

Usbprint.sys is the Microsoft®-provided kernel-mode device driver for USB printers. Usbprint.sys works with usbmon.dll to provide end-to-end connectivity between USB printers and high-level printer drivers.

Unlike some USB device classes, usbprint.sys does not "drive" the printer. Instead, usbprint.sys provides a communication conduit by which higher-level drivers can control the printer. As is true for parallel printers, USB printers require a printer driver to render print jobs, and also may require a language monitor to manage high-level communication with the printer.


Programming Considerations for USBPRINT

Usbprint.sys, together with USBMON, provides an interface very similar to that used by parallel printers. In many cases, it is possible for a single printer driver or language monitor to work correctly on both parallel and USB printers without modification. If a language monitor uses only the WritePort and ReadPort functions and the IOCTL_PAR_QUERY_DEVICE_ID request, it will be portable between USB and parallel printers.

In some cases, it might be necessary for a language monitor to make vendor-specific requests to a printer in order to take advantage of special printer features. To do this, use IOCTL_USBPRINT_VENDOR_SET_COMMAND and IOCTL_USBPRINT_VENDOR_GET_COMMAND. Note, however, that using these IOCTLs renders a language monitor incompatible with the parallel port monitor.

Language monitors normally do not have access to a device handle for the printer they are managing. Instead, they have a port name provided by the port monitor that sits between the language monitor and the bus driver (usbprint.sys in this case). See Language and Port Monitor Interaction for more information. The lack of a device handle prevents language monitors from directly calling device bus driver IOCTLs. To overcome this limitation, USBMON implements the GetPrinterDataFromPort API, which allows language monitors to issue IOCTLs through USBMON to USBPRINT.

The USB printing stack shares the following APIs and IOCTL with the parallel printing stack:

WritePort

ReadPort

IOCTL_PAR_QUERY_DEVICE_ID

The following IOCTLs are specific to the USB printing stack:

IOCTL_USBPRINT_VENDOR_SET_COMMAND

IOCTL_USBPRINT_VENDOR_GET_COMMAND

Note Usbprint.sys does not provide a mechanism for obtaining descriptors from the device, nor for directly manipulating USB pipes.


Graphics Driver Functions (DDI)

This section provides reference information for functions that are implemented by display and/or printer driver writers. Most of these functions are named with a Drv prefix. The Graphics Driver Design Guide describes which functions are required, conditionally required, or optional in a graphics driver's implementation.

Using the Graphics DDI lists the include files that contain declarations for the graphics driver functions described in this section.

The system-supplied GDI services that can be called by graphics drivers are documented in GDI Functions for Graphics Drivers.


DrvAssertMode

DrvAssertMode sets the mode of the specified physical device to either the mode specified when the PDEV was initialized or to the default mode of the hardware.

BOOL
  DrvAssertMode(
    IN DHPDEV  dhpdev,
    IN BOOL  bEnable
    );

Parameters

dhpdev
Specifies the handle to the PDEV describing the hardware mode that should be set when bEnable is TRUE.
bEnable
Specifies the mode to which the hardware is to be set. If this parameter is TRUE, the driver should set the hardware to the original mode specified by the initialized PDEV. Otherwise, the driver should set the hardware to its default mode so the video miniport driver can assume control.

Return Value

DrvAssertMode returns TRUE if it successfully changed the display mode; it returns FALSE if it was unable to change the display mode. A driver is permitted to return FALSE from a DrvAssertMode call with bEnable set to FALSE. A driver must return TRUE from a DrvAssertMode call with bEnable set to TRUE; that is, a driver can not fail enabling a mode that was previously enabled.

Headers

Declared in winddi.h. Include winddi.h.

Comments

GDI calls DrvAssertMode when it is required to switch among multiple desktops on a single display surface. To switch from one PDEV to another, GDI calls DrvAssertMode with the bEnable parameter set to FALSE for one PDEV, and TRUE for the other. To revert to the original PDEV, DrvAssertMode is called with bEnable set to FALSE, followed by another call to DrvAssertMode, with bEnable set to TRUE and dhpdev set to the original PDEV.

If the physical device is palette-managed, GDI will call DrvSetPalette to reset the device's palette. The driver does not then need to keep track of the current pointer state because the Window Manager selects the correct pointer shape and moves it to the current position. The Console Manager ensures that desktops are properly redrawn.

DrvAssertMode must be implemented in display drivers.

See Also

DrvGetModes


DrvBitBlt

DrvBitBlt provides general bit-block transfer capabilities between device-managed surfaces, between GDI-managed standard-format bitmaps, or between a device-managed surface and a GDI-managed standard-format bitmap.

BOOL
  DrvBitBlt(
    IN SURFOBJ  *psoTrg,
    IN SURFOBJ  *psoSrc,
    IN SURFOBJ  *psoMask,
    IN CLIPOBJ  *pco,
    IN XLATEOBJ  *pxlo,
    IN RECTL  *prclTrg,
    IN POINTL  *pptlSrc,
    IN POINTL  *pptlMask,
    IN BRUSHOBJ  *pbo,
    IN POINTL  *pptlBrush,
    IN ROP4  rop4
    );

Parameters

psoTrg
Points to the SURFOBJ structure that describes the surface on which to draw.
psoSrc
Points to a SURFOBJ structure that describes the source for the bit-block transfer operation, if required by the rop4 parameter.
psoMask
Points to a SURFOBJ structure that describes a surface to be used as a mask for the rop4 parameter. The mask is a bitmap with 1 bit per pixel. Typically, a mask is used to limit the area to be modified in the destination surface. Masking is selected by setting the rop4 parameter to the value 0xAACC. The destination surface is unaffected if the mask is 0x0000.

The mask will be large enough to cover the destination rectangle.

If this parameter is null and a mask is required by the rop4 parameter, the implicit mask in the brush is used.

pco
Points to a CLIPOBJ structure that limits the area to be modified. GDI services (CLIPOBJ_Xxx) that enumerate the clip region as a set of rectangles are provided. Whenever possible, GDI simplifies the clipping involved; for example, this function is never called with a single clipping rectangle. GDI clips the destination rectangle before calling this function, making additional clipping unnecessary.
pxlo
Points to an XLATEOBJ structure that specifies how color indices should be translated between the source and destination surfaces. If pxlo is NULL, no translation is needed.

If the source surface is palette-managed, its colors are represented by indices into a lookup table of RGB values. The XLATEOBJ structure can be queried for a translate vector that will allow the device driver to translate any source index into a color index for the destination.

The situation is more complicated when, for example, the source is RGB, but the destination is palette-managed. In this case, the closest match to each source RGB value must be found in the destination palette. The driver can call the XLATEOBJ_iXlate service to perform this operation.

Optionally, the device driver can match colors when the target palette is the default device palette.

prclTrg
Points to a RECTL structure that defines the area to be modified. This structure uses the coordinate system of the destination surface. The lower and right edges of this rectangle are not part of the bit-block transfer, meaning the rectangle is lower right exclusive.

DrvBitBlt is never called with an empty destination rectangle. The two points that define the rectangle are always well-ordered. However, on multimonitor systems the rectangle may define a region larger than the destination surface. Drivers should intersect this rectangle with their surface.

pptlSrc
Points to a POINTL structure that defines the upper left corner of the source rectangle, if a source exists. This parameter is ignored if there is no source.
pptlMask
Points to a POINTL structure that defines which pixel in the mask corresponds to the upper left corner of the source rectangle, if a source exists. This parameter is ignored if the psoMask parameter is null.
pbo
Points to the brush object that defines the pattern for the bit-block transfer. GDI's BRUSHOBJ_pvGetRbrush service can be used to retrieve the device's realization of the brush. This parameter is ignored if the rop4 parameter does not require a pattern.
pptlBrush
Points to a POINTL structure that defines the origin of the brush in the destination surface. The upper left pixel of the brush is aligned at this point, and the brush repeats according to its dimensions. This parameter is ignored if the rop4 parameter does not require a pattern.
rop4
Specifies a raster operation that defines how the mask, pattern, source, and destination pixels are combined to write to the destination surface.

This is a quaternary raster operation, which is an extension of the ternary Rop3 operation. A Rop4 has 16 relevant bits, which are similar to the 8 defining bits of a Rop3. The simplest way to implement a Rop4 is to consider its 2 bytes separately: The low byte specifies a Rop3 that should be calculated if the mask is one, and the high byte specifies a Rop3 that can be calculated and applied if the mask is 0.

Return Value

The return value is TRUE if the bit-block transfer operation is successful. Otherwise, it is FALSE, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

If the driver hooks DrvBitBlt, GDI will call this function when it needs to perform a BitBlt operation where one of the surfaces is a device-managed surface. If the driver implements opaque device-managed bitmaps, it must hook DrvBitBlt; otherwise, hooking DrvBitBlt is optional. If the driver can not handle the specified call it may punt the call back to the DIB engine by calling EngBitBlt.

GDI's CLIPOBJ_Xxx services allow the clipping to be reduced to a series of clipping rectangles. A translation vector assists in color index translation for palettes.

Notes Do not dereference parameter pointers unless the ROP indicates they are needed. For example, never unnecessarily dereference pbo—>iSolidColor because doing so for a ROP such as BLACKNESS can cause an access violation. (This rule also applies to any function that includes a MIX parameter.)

If the driver receives a call to this function in which the rop4 parameter is set to 0XCCAA, the driver should punt the call to EngBitBlt, exposing the device surface(s) as appropriate for the call.

For more information on raster operations, see the Platform SDK documentation.

See Also

BRUSHOBJ, BRUSHOBJ_pvGetRbrush, CLIPOBJ, DrvSynchronize, EngAssociateSurface, EngBitBlt, EngCreateBitmap, EngCreateDeviceSurface, SURFOBJ, XLATEOBJ, XLATEOBJ_iXlate


DrvCompletePDEV

DrvCompletePDEV stores the GDI handle (hdev) of the physical device in dhpdev.

VOID
  DrvCompletePDEV(
    IN DHPDEV  dhpdev,
    IN HDEV  hdev
    );

Parameters

dhpdev
Identifies the physical device by its handle, which was returned to GDI when it called DrvEnablePDEV.
hdev
Identifies the physical device that has been installed. This is the GDI handle for the physical device being created. The driver should use this handle when calling GDI functions.

Headers

Declared in winddi.h. Include winddi.h.

Comments

DrvCompletePDEV is called by GDI when its installation of the physical device is complete. It also provides the driver with a handle to the PDEV to be used when requesting GDI services for the device. This function is required for graphics drivers; when GDI calls DrvCompletePDEV, it cannot fail.


DrvCopyBits

DrvCopyBits translates between device-managed raster surfaces and GDI standard-format bitmaps.

BOOL
  DrvCopyBits(
    IN SURFOBJ  *psoDest,
    IN SURFOBJ  *psoSrc,
    IN CLIPOBJ  *pco,
    IN XLATEOBJ  *pxlo,
    IN RECTL  *prclDest,
    IN POINTL  *pptlSrc
    );

Parameters

psoDest
Points to the destination surface for the copy operation.
psoSrc
Points to the source surface for the copy operation.
pco
Points to a CLIPOBJ structure that defines a clip region on the destination surface.
pxlo
Points to an XLATEOBJ structure that defines the translation of color indices between the source and target surfaces. If pxlo is NULL, no translation is needed.
prclDest
Points to a RECTL structure that defines the area to be modified. This structure uses the coordinate system of the destination surface. The lower and right edges of this rectangle are not part of the bit-block transfer, meaning the rectangle is lower right exclusive.

DrvCopyBits is never called with an empty destination rectangle. The two points that define the rectangle are always well-ordered.

pptlSrc
Points to a POINTL structure that defines the upper-left corner of the source rectangle.

Return Value

The return value is TRUE if the source surface is successfully copied to the destination surface.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The driver may optionally hook DrvCopyBits. If so, GDI will call DrvCopyBits when it needs to copy from one surface to another and at least one of the surfaces is device-managed.

See Also

CLIPOBJ, XLATEOBJ


DrvCreateDeviceBitmap

DrvCreateDeviceBitmap creates and manages bitmaps.

HBITMAP
  DrvCreateDeviceBitmap(
    IN DHPDEV  dhpdev,
    IN SIZEL  sizl,
    IN ULONG  iFormat
    );

Parameters

dhpdev
Identifies the PDEV that describes the physical device that an application has designated as the primary target for a bitmap. The format of the bitmap must be compatible with this physical device.
sizl
Specifies the height and width of the desired bitmap, in pixels.
iFormat
Specifies the bitmap format, which indicates the required number of bits of color information per pixel, and always matches the format of the primary. This value can be one of the following:
Value | Meaning
BMF_8BPP | 8 bits per pixel.
BMF_16BPP | 16 bits per pixel.
BMF_24BPP | 24 bits per pixel.
BMF_32BPP | 32 bits per pixel.

Return Value

The return value is a handle that identifies the created bitmap if the function is successful. If the driver chooses to let GDI create and manage the bitmap, the return value is zero. If an error occurs, the return value is 0xFFFFFFFF, and GDI logs an error code.

Headers

Declared in winddi.h. Include winddi.h.

Comments

If the driver creates the bitmap, it can store it anywhere and in any format. It is assumed that the driver will take into account the specifications of the parameters and provide a bitmap with at least as many bits per pixel as requested.

The contents of the created bitmap are undefined.

This function is optional. If this function is implemented, however, DrvDeleteDeviceBitmap must also be implemented.

See Also

DrvDeleteDeviceBitmap


DrvDeleteDeviceBitmap

DrvDeleteDeviceBitmap deletes a device bitmap created by DrvCreateDeviceBitmap.

VOID
  DrvDeleteDeviceBitmap(
    IN DHSURF  dhsurf
    );

Parameters

dhsurf
Identifies the bitmap to be deleted. This handle identifies the bitmap created by DrvCreateDeviceBitmap.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A driver must implement DrvDeleteDeviceBitmap if it supplies DrvCreateDeviceBitmap.

The driver should free any resources associated with the device bitmap.


DrvDeriveSurface

DrvDeriveSurface derives a GDI surface from the specified DirectDraw surface.

HBITMAP
  DrvDeriveSurface(
    DD_DIRECTDRAW_GLOBAL  *pDirectDraw,
    DD_SURFACE_LOCAL  *pSurface
    );

Parameters

pDirectDraw
Points to a DD_DIRECTDRAW_GLOBAL structure that describes the DirectDraw object.
pSurface
Points to a DD_SURFACE_LOCAL structure that describes the DirectDraw surface around which to wrap a GDI surface.

Return Value

DrvDeriveSurface returns a handle to the derived GDI surface upon success. It returns NULL if the call fails or if the driver cannot accelerate GDI drawing to the specified DirectDraw surface.

Headers

Declared in winddi.h. Include winddi.h.

Comments

DrvDeriveSurface allows the driver to create a GDI surface wrapped around a DirectDraw video memory or AGP surface object in order to allow accelerated GDI drawing to the surface. If the driver does not hook this call, all GDI drawing to DirectDraw surfaces is done in software using the DIB engine.

GDI calls DrvDeriveSurface with RGB surfaces only.

The driver should call DrvCreateDeviceBitmap to create a GDI surface of the same size and format as that of the DirectDraw surface. Space for the actual pixels need not be allocated since it already exists.

See Also

EngCreateDeviceBitmap, EngModifySurface


DrvDescribePixelFormat

DrvDescribePixelFormat describes the pixel format for a device-specified PDEV by writing a pixel format description to a PIXELFORMATDESCRIPTOR structure.

LONG
  DrvDescribePixelFormat(
    IN DHPDEV  dhpdev,
    IN LONG  iPixelFormat,
    IN ULONG  cjpfd,
    OUT PIXELFORMATDESCRIPTOR  *ppfd
    );

Parameters

dhpdev
Identifies the device for which pixel format information is requested.
iPixelFormat
Specifies the index number of the requested pixel format.
cjpfd
Specifies the maximum number of bytes that can be written to the structure pointed to by ppfd.
ppfd
Points to a PIXELFORMATDESCRIPTOR structure that is to receive information about the pixel format. This parameter can be NULL. See the Platform SDK documentation for the definition of the PIXELFORMATDESCRIPTOR structure.

Return Value

The return value is the maximum pixel format index if the function is successful. Otherwise, it is zero, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A display driver that supports 3D graphics hardware can support windows with different pixel formats on a single display surface. The pixel format must correspond to a configuration supported by the graphics hardware.

DrvDescribePixelFormat fills in the structure pointed to by ppfd if this parameter is not null.

The returned maximum pixel format index can be used by applications that need to obtain a device context's maximum pixel format index. The pixel formats that a device supports are identified by positive one-based integer indices.

The pixel format functions are used in conjunction with the window object services functions to track and update pixel formats of windows on a display surface.


DrvDestroyFont

DrvDestroyFont notifies the driver that a font realization is no longer needed and that the driver can now free any associated data structures it has allocated.

VOID
  DrvDestroyFont(
    IN FONTOBJ  *pfo
    );

Parameters

pfo
Points to the FONTOBJ structure that identifies the font instance.

Headers

Declared in winddi.h. Include winddi.h.

Comments

If the DEVICE_FONTTYPE flag is set in the flFontType member of the FONTOBJ structure, the driver should release any resources or memory identified with both the pvConsumer and pvProducer members of FONTOBJ. Otherwise, it should release only memory and resources identified with pvConsumer.

The driver must reset the pvConsumer and pvProducer members to null if it uses them.

GDI calls DrvDestroyFont once for the font producer and once again for the font consumer.

GDI guarantees that DrvDestroyFont and DrvTextOut never overlap; consequently, the driver can rely on cached information while processing a DrvTextOut call.

This function must be implemented if the driver allocates resources when it realizes fonts.

See Also

DrvTextOut, FONTOBJ


DrvDisableDriver

DrvDisableDriver is used by GDI to notify a driver that it no longer requires the driver and is ready to unload it.

VOID
  DrvDisableDriver(
    VOID
    );

Headers

Declared in winddi.h. Include winddi.h.

Comments

The driver should free all allocated resources and return the device to the state it was in before the driver was loaded.

DrvDisableDriver is required for graphics drivers.

See Also

DrvEnableDriver


DrvDisablePDEV

DrvDisablePDEV is used by GDI to notify a driver that the specified PDEV is no longer needed.

VOID
  DrvDisablePDEV(
    IN DHPDEV  dhpdev
    );

Parameters

dhpdev
Pointer to the PDEV that describes the physical device to be disabled. This value is the handle returned by DrvEnablePDEV.

Headers

Declared in winddi.h. Include winddi.h.

Comments

If the physical device has an enabled surface, GDI calls DrvDisablePDEV after calling DrvDisableSurface. The driver should free any memory and resources used by the PDEV.

DrvDisablePDEV is required for graphics drivers.

See Also

DrvAssertMode, DrvEnablePDEV


DrvDisableSurface

DrvDisableSurface is used by GDI to notify a driver that the surface created by DrvEnableSurface for the current device is no longer needed.

VOID
  DrvDisableSurface(
    IN DHPDEV  dhpdev
    );

Parameters

dhpdev
Is a handle to the PDEV that describes the physical device whose surface is to be released.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The driver should free any memory and resources used by the surface associated with the PDEV as soon as the physical device is disabled.

If the driver has been disabled by a call to DrvAssertMode, the driver cannot access the hardware during DrvDisableSurface because another active PDEV might be in use. Any necessary hardware changes should have been performed during the call to DrvAssertMode. A driver should keep track of whether or not it has been disabled by DrvAssertMode so that it can perform proper cleanup operations in DrvDisableSurface.

If the physical device has an enabled surface, GDI calls DrvDisableSurface before calling DrvDisablePDEV.

DrvDisableSurface is required for graphics drivers.

See Also

DrvAssertMode, DrvDisableDriver, DrvDisablePDEV, DrvEnableSurface


DrvDitherColor

DrvDitherColor requests the device to create a brush dithered against a device palette.

ULONG
  DrvDitherColor(
    IN DHPDEV  dhpdev,
    IN ULONG  iMode,
    IN ULONG  rgb,
    OUT ULONG  *pul
    );

Parameters

dhpdev
Points to the PDEV that describes the physical device against whose palettes the specified color should be dithered.
iMode
Determines the palette to dither against. This parameter can be one of the following values:
Value | Meaning
DM_DEFAULT | The driver should create a dither for the native, default color space of the device. For example, if the device is running at 16bpp, the resulting dither should be in a 16bpp format.
DM_MONOCHROME | The driver should create the dither for monochrome color space; that is, the dither should be returned as a 1bpp bitmap.

rgb
Specifies the RGB color that is to be dithered.
pul
Points to the memory location in which the dithering information is to be recorded. Memory must have been allocated for a standard-format bitmap with dithered brush dimensions cxDither by cyDither. These dimensions are members of the DEVINFO structure. The bitmap format is determined by the iDitherFormat member of the DEVINFO structure.

Return Value

The return value is DCR_DRIVER if the dither values have been calculated by the driver, DCR_SOLID if the engine should use the best solid color approximation of the color, or DCR_HALFTONE if the engine should create a halftone approximation for the driver.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The result of the dither is a set of device color indices stored in pul. A brush created using these colors for its pattern should be a good approximation of the given color rgb.

DrvDitherColor is an optional function that is called only if cxDither and cyDither are nonzero. Monochrome device drivers, including most raster printers, should use the iMode parameter to tell GDI how to get good gray-scale patterns.

See Also

DEVINFO, DrvEnablePDEV


DrvDrawEscape

DrvDrawEscape is the entry point that serves more than one function call; the particular function depends on the value of the iEsc parameter.

ULONG
  DrvDrawEscape(
    IN SURFOBJ  *pso,
    IN ULONG  iEsc,
    IN CLIPOBJ  *pco,
    IN RECTL  *prcl,
    IN ULONG  cjIn,
    IN PVOID  pvIn
    );

Parameters

pso
Identifies the surface to which the call is directed.
iEsc
Specifies the operation to be performed. The meanings of the remaining parameters depend on this parameter. This parameter can be the following value.
Value | Meaning
ESC_PASSTHROUGH | Passes raw device data to the device driver. The number of bytes of raw data is indicated by cjIn. The data is pointed to by pvIn. The return value is the number of bytes written if the function is successful. Otherwise, it is zero, and an error code is logged.

pco
Points to a CLIPOBJ structure that can be queried to find the area on the surface that the caller can overwrite.
prcl
Points to a RECTL structure that defines the window rectangle on the surface. The application does not know the position of the window on the surface. GDI supplies this rectangle and holds a lock that ensures the rectangle is stable for the duration of the call. Coordinates received from the application are relative to the upper left corner of the window rectangle.
cjIn
Specifies the size, in bytes, of the buffer pointed to by pvIn.
pvIn
Points to the input data for the call. The format of the input data depends on the function specified by iEsc.

Return Value

The return value depends on the function specified by iEsc. The driver should return 0xFFFFFFFF if an unsupported function is called.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This entry point differs from DrvEscape in that a CLIPOBJ structure is provided. This allows a driver to implement its own drawing functions in a windowed environment.

The escapes that a device supports are determined by a call to DrvEscape.

For more information about the escape codes that Microsoft reserves, see DrvEscape.

DrvDrawEscape is optional for all drivers.

See Also

CLIPOBJ, DrvEnableDriver, DrvEscape


DrvEnableDriver

DrvEnableDriver is the initial driver entry point exported by the driver DLL and it fills in a DRVENABLEDATA structure with the driver's graphics DDI version number and the calling addresses of all graphics DDI functions supported by the driver.

BOOL
  DrvEnableDriver(
    IN ULONG  iEngineVersion,
    IN ULONG  cj,
    OUT DRVENABLEDATA  *pded
    );

Parameters

iEngineVersion
Identifies the version of GDI that is currently running.
cj
Is the size in bytes of the structure pointed to by pded. If the structure is larger than expected, extra members should be left unmodified.
pded
Points to a DRVENABLEDATA structure. GDI zero-initializes cj bytes before the call. The driver fills in its own data.

Return Value

The return value is TRUE if the specified driver is enabled. Otherwise, it is FALSE, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

DrvEnableDriver must be implemented in all graphics drivers.

One-time initializations, such as allocating semaphores, can also be performed by this function. The driver should wait until DrvEnablePDEV is called before enabling hardware, such as a display.

When performing version checking using the value provided in iEngineVersion, the driver should use the appropriate DDI_DRIVER_VERSION_Xxx constant (defined in winddi.h) shown in the following table. Drivers should almost never check just for equality since new versions and service pack releases for the operating system will be released in the future. For more information, see DRVENABLEDATA.

Value | Operating System Version
DDI_DRIVER_VERSION_NT4 | Windows NT 4.0
DDI_DRIVER_VERSION_SP3 | Windows NT 4.0 Service Pack 3
DDI_DRIVER_VERSION_NT5 | Windows 2000
DDI_DRIVER_VERSION_NT5_01 | Windows XP

See Also

DrvDisableDriver, DRVENABLEDATA, DrvEnablePDEV, DRVFN


DrvEnablePDEV

DrvEnablePDEV returns a description of the physical device's characteristics to GDI.

DHPDEV
  DrvEnablePDEV(
    IN DEVMODEW  *pdm,
    IN LPWSTR  pwszLogAddress,
    IN ULONG  cPat,
    OUT HSURF  *phsurfPatterns,
    IN ULONG  cjCaps,
    OUT ULONG  *pdevcaps,
    IN ULONG  cjDevInfo,
    OUT DEVINFO  *pdi,
    IN HDEV  hdev,
    IN LPWSTR  pwszDeviceName,
    IN HANDLE  hDriver
    );

Parameters

pdm
Points to a DEVMODEW structure that contains driver data.

For a driver that supports Windows NT 4.0, DrvEnablePDEV should return the default mode of the hardware when GDI calls it with the following DEVMODEW members set to zero: dmBitsPerPel, dmPelsWidth, dmPelsHeight, and dmDisplayFrequency.

pwszLogAddress
For printer drivers, points to the logical address string that is the user's name for the location to which the driver is writing. Examples include "LPT1" or "My Printer."

Display drivers should ignore this parameter.

cPat
For printer drivers, specifies the number of surface handles in the buffer pointed to by phsurfPatterns. The driver cannot access memory beyond the end of the buffer.

Display drivers should ignore this parameter.

phsurfPatterns
Display drivers should ignore this parameter.

For printer drivers, points to a buffer that the driver will fill with surface handles representing the standard fill patterns. The following patterns must be defined in order:
Pattern | Description
HS_HORIZONTAL | Horizontal hatch.
HS_VERTICAL | Vertical hatch.
HS_FDIAGONAL | 45-degree upward hatch (left to right).
HS_BDIAGONAL | 45-degree downward hatch (left to right).
HS_CROSS | Horizontal and vertical cross hatch.
HS_DIAGCROSS | 45-degree crosshatch.

Note The number of default hatch patterns that require driver support was reduced in a previous version of the DDK. Consequently, HS_DDI_MAX, typically used by drivers to declare the size of the pattern array, was reduced.

GDI calls DrvRealizeBrush with one of these surfaces to realize a brush with a standard pattern.

Each of these surfaces must be a monochrome (1 bit per pixel) GDI bitmap for raster devices. The device driver should choose patterns that will look most like standard patterns when written on the device surface.

GDI is never required to use these brushes in support routines for a vector device. Therefore, surfaces can be device-supported surfaces that DrvRealizeBrush recognizes as standard patterns.

cjCaps
Specifies the size of the buffer pointed to by pdevcaps. The driver must not access memory beyond the end of the buffer.
pdevcaps
Points to a GDIINFO structure that will be used to describe device capabilities. GDI zero-initializes this structure calling DrvEnablePDEV.
cjDevInfo
Specifies the number of bytes in the DEVINFO structure pointed to by pdi. The driver should modify no more than this number of bytes in the DEVINFO.
pdi
Points to the DEVINFO structure, which describes the driver and the physical device. The driver should only alter the members it understands. GDI fills this structure with zeros before a call to DrvEnablePDEV.
hdev
Is a GDI-supplied handle to the device. This handle must be used as input to some GDI callbacks, such as EngGetDriverName.
pwszDeviceName
Points to a zero-terminated string that is the user-readable name of the device.
hDriver
Identifies the kernel-mode driver that supports the device. For a printer driver this parameter should be used as a handle to the printer when calling the spooler.

Return Value

The return value is a handle to the PDEV that identifies the enabled device if the function is successful. That is, DrvEnablePDEV returns a handle to the private, driver-defined device instance information upon success. Otherwise, it returns NULL.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A graphics device driver might support several physical devices attached to different logical addresses. Drivers must also support simultenous use of different drawing surfaces.

The purposes of DrvEnablePDEV are: (1) to inform GDI of the physical characteristics of the device, and (2) to create a private PDEV structure describing the current device instance (based on the received DEVMODE structure and device name). When GDI subsequently calls other graphics DDI functions, it supplies the handle returned by DrvEnablePDEV as input (usually within a SURFOBJ structure) so the driver can identify the device instance.

A single logical device can manage several PDEVs that can be differentiated by the following:

  1. Type of hardware. A single device driver might support "LaserWhiz," "LaserWhiz II," and "LaserWhiz Super."
  2. Logical address. A single device driver can support printers attached to "LPT1," "COM2," "\SERVER1\PSLAZER," and so forth. A display driver that can support more than one VGA display simultaneously might differentiate them according to port numbers; for example, 0x3CE or 0x2CE.
  3. Surfaces. A printer driver can process two print jobs simultaneously. The two surfaces represent two pages that will be printed. Similarly, a display device driver might support two desktops on the same device.

When receiving a call to this function, the driver must allocate the memory to support the PDEV. However, the actual surface need not be supported until GDI calls DrvEnableSurface.

If a device surface requires a bitmap to be allocated, these allocations need not be made until needed. Although applications often request device information long before actually writing to the device, waiting to allocate resources, such as large bitmaps, can conserve memory.

GDI zero-initializes the buffer pointed to by phsurfPatterns before calling this function.

DrvEnablePDEV is required for graphics drivers.

See Also

DEVINFO, DEVMODEW, DrvEnableSurface, DrvRealizeBrush, EngCreatePalette, GDIINFO


DrvEnableSurface

DrvEnableSurface sets up a surface to be drawn on and associates it with a given PDEV.

HSURF
  DrvEnableSurface(
    IN DHPDEV  dhpdev
    );

Parameters

dhpdev
Identifies a handle to a PDEV. This value is the return value of DrvEnablePDEV. The PDEV describes the physical device for which a surface is to be created.

Return Value

The return value is a handle that identifies the newly created surface. Otherwise, it is zero, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

There are two methods for preparing a surface for use.

  1. In this method, which is recommended, the driver creates the surface by a call to EngCreateDeviceSurface. After GDI creates the surface and returns a handle to the driver, the driver calls EngModifySurface, setting the appropriate hook flags, and optionally, informing GDI of the surface's location.
  2. The second method is the one used by Windows NT 4.0 drivers. In this method, the driver calls EngCreateBitmap. After this call, the driver calls EngAssociateSurface to associate the surface with the physical display device. This GDI function allows the driver to specify which graphics output routines are supported for standard-format bitmaps. A call to this function can only be made when no surface exists for the given physical device. If a Windows 2000 or later driver is back-ported to run on Windows NT 4.0, this method must be used. If such a driver will also run on Windows 2000 or later, a separate code path in the driver should use the first method.

    For printer devices, the usual situation is for GDI to collect the graphics directly onto a GDI bitmap. The driver should call EngCreateBitmap, which allows GDI to allocate memory for the bitmap.

Any existing GDI bitmap handle is a valid surface handle.

For printer graphics DLLs that use GDI-managed surfaces, the DrvEnableSurface function should call EngCreateBitmap, specifying a surface size large enough to contain an entire physical page. If that fails, repeated calls to EngCreateBitmap should be attempted, with decreasing surface sizes, until a call succeeds. The valid size should be specified as input to EngMarkBandingSurface, which informs GDI that surface banding will be necessary.

DrvEnableSurface is required for graphics drivers.

See Also

DrvDisableSurface, DrvEnablePDEV, EngCreateBitmap, EngCreateDeviceSurface


DrvEndDoc

DrvEndDoc is called by GDI when it has finished sending a document to the driver for rendering.

BOOL
  DrvEndDoc(
    IN SURFOBJ  *pso,
    IN FLONG  fl
    );

Parameters

pso
Is a caller-supplied pointer to a SURFOBJ structure.
fl
Is a caller-supplied set of bit flags. The following flag is defined:
Flag | Definition
ED_ABORTDOC | The print job is being terminated before completion.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise, it should call SetLastError to set an error code, and then return FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A printer graphics DLL must provide a DrvEndDoc function. The function is called after the last physical page of a print job has been rendered.

Typically the function is used for sending control sequences to printer hardware, after a document has been printed, by calling GDI's EngWritePrinter function. The function can also perform internal, document-specific clean-up operations for the printer graphics DLL.

Because there is not a separate call into the printer graphics DLL when a print job is finished, the DrvEndDoc function must also send control sequences to the printer to end the job, if required by the printer. (In other words, there is one document per job.)

See Also

DrvStartDoc


DrvEscape

DrvEscape is used for retrieving information from a device that is not available in a device-independent device driver interface; the particular query depends on the value of the iEsc parameter.

ULONG
  DrvEscape(
    IN SURFOBJ  *pso,
    IN ULONG  iEsc,
    IN ULONG  cjIn,
    IN PVOID  pvIn,
    IN ULONG  cjOut,
    OUT PVOID  pvOut
    );

Parameters

pso
Points to a SURFOBJ structure that describes the surface to which the call is directed.
iEsc
Specifies a query. The meaning of the other parameters depends on this value. QUERYESCSUPPORT is the only predefined value; it queries whether the driver supports a particular escape function. In this case, pvIn points to an escape function number; cjOut and pvOut are ignored. If the specified function is supported, the return value is nonzero.
cjIn
Specifies the size, in bytes, of the buffer pointed to by pvIn.
pvIn
Points to the input data for the call. The format of the input data depends on the query specified by the iEsc parameter.
cjOut
Specifies the size, in bytes, of the buffer pointed to by pvOut.
pvOut
Points to the output buffer. The format of the output data depends on the query specified by the iEsc parameter.

Return Value

The return value is dependent on the query specified by the iEsc parameter. If the function specified in the query is not supported, the return value is zero.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Drawing on the device is not allowed in this function. DrvDrawEscape is to be used for specialized drawing support.

Microsoft reserves the range 0 to 0X10000 for its escape codes. Third-party vendors are free to choose escape codes for their own use above this range. Since driver-specific escape codes may conflict with those used in other display drivers, it is important for a display driver to validate escape parameters before processing the escape. One way to do this would be to validate the input and output block sizes and the input block parameters. For added security, drivers should also include a "magic" value which must be set appropriately in every input block to ensure that the input block is from a trusted source.

DrvEscape is optional for all drivers.

See Also

DrvDrawEscape, SURFOBJ


DrvFillPath

DrvFillPath is an optional entry point to handle the filling of closed paths.

BOOL
  DrvFillPath(
    IN SURFOBJ  *pso,
    IN PATHOBJ  *ppo,
    IN CLIPOBJ  *pco,
    IN BRUSHOBJ  *pbo,
    IN POINTL  *pptlBrushOrg,
    IN MIX  mix,
    IN FLONG  flOptions
    );

Parameters

pso
Points to a SURFOBJ structure that defines the surface on which to draw.
ppo
Points to a PATHOBJ structure that defines the path to be filled. The PATHOBJ_Xxx service routines are provided to enumerate the lines, Bezier curves, and other data that make up the path.
pco
Points to a CLIPOBJ structure. The CLIPOBJ_Xxx service routines are provided to enumerate the clip region as a set of rectangles.
pbo
Points to a BRUSHOBJ structure that defines the pattern and colors used to fill the closed path. This parameter should be dereferenced only if the fill operation specified in mix requires the use of a brush. For example, if mix is set to BLACKNESS, pbo is not defined and should not be dereferenced.
pptlBrushOrg
Points to a POINTL structure that defines the brush origin, which is used to align the brush pattern on the device.
mix
Specifies a MIX structure (defined in the Platform SDK documentation) that defines the foreground and background raster operations to use for the brush.
flOptions
Specifies either FP_WINDINGMODE, indicating that a winding mode fill should be performed, or FP_ALTERNATEMODE, indicating that an alternating mode fill should be performed. All other flags should be ignored. For more information about these modes, see Path Fill Modes.

Return Value

The return value is TRUE if the driver is able to fill the path. If the path or clipping is too complex to be handled by the driver and should be handled by GDI, the return value is FALSE, and an error code is not logged. If the driver encounters an unexpected error, such as not being able to realize the brush, the return value is DDI_ERROR, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

GDI can call DrvFillPath to fill a path on a device-managed surface. When deciding whether to call this function, GDI compares the fill requirements with the following flags in the flGraphicsCaps member of the DEVINFO structure: GCAPS_BEZIERS, GCAPS_ALTERNATEFILL, and GCAPS_WINDINGFILL.

The mix mode defines how the incoming pattern should be mixed with the data already on the device surface. The MIX data type consists of two ROP2 values packed into a single ULONG. The low-order byte defines the foreground raster operation; the high-order byte defines the background raster operation. For more information about raster operation codes, see the Platform SDK documentation.

See Also

BRUSHOBJ, CLIPOBJ, DEVINFO, DrvStrokeAndFillPath, PATHOBJ, SURFOBJ


DrvFontManagement

DrvFontManagement is an optional entry point provided for PostScript devices.

ULONG
  DrvFontManagement(
    IN SURFOBJ  *pso,
    IN FONTOBJ  *pfo,
    IN ULONG  iMode,
    IN ULONG  cjIn,
    IN PVOID  pvIn,
    IN ULONG  cjOut,
    OUT PVOID  pvOut
    );

Parameters

pso
Points to a SURFOBJ.
pfo
Points to a FONTOBJ.
iMode
Specifies the escape number to be perfomed. This must either be equal to QUERYESCSUPPORT, or in the range 0x100 through 0x3FE.
cjIn
Specifies the size, in bytes, of the buffer pointed to by pvIn.
pvIn
Points to an input buffer. If the iMode parameter is QUERYESCSUPPORT, pvIn points to a ULONG value in the range 0x100 through 0x3FE.
cjOut
Specifies the size, in bytes, of the output buffer.
pvOut
Points to the output data buffer.

Return Value

If this function is hooked by the device driver then GDI will pass calls made by an application to ExtEscape for escape numbers 0x100 through 0x3fe, or for the QUERYESCSUPPORT escape when the first DWORD pointed to by pvIn is in the range 0x100 through 0x3fe.

The return value is a value in the range 0x00000001 through 0x7FFFFFFF if the function is successful. If the escape is not implemented, the return value is zero. If the function fails, the return value is a value in the range 0x80000000 through 0xFFFFFFFF.

Headers

Declared in winddi.h. Include winddi.h.

See Also

FONTOBJ, SURFOBJ


DrvFree

DrvFree is used to notify the driver that the specified structure is no longer needed.

VOID
  DrvFree(
    IN PVOID  pv,
    IN ULONG_PTR  id
    );

Parameters

pv
Points to the structure whose memory is to be freed.
id
Points to an identifier that was returned with the structure.

Headers

Declared in winddi.h. Include winddi.h.

Comments

DrvFree is an optional function that should be supported only if the driver must be informed when memory associated with structures can be freed. For example, if a FONTOBJ structure is in use, deletion can be deferred until DrvDestroyFont has been called, eliminating the need for the driver to implement DrvFree.

A driver can use id in different ways. It can specify an object handle or it can indicate the way the structure is allocated. For example, it can differentiate between loaded resources and memory allocated from a heap. The driver can ignore this parameter if the structure pointed to by pv contains enough information.

See Also

DrvQueryFont, DrvQueryFontTree


DrvGetGlyphMode

DrvGetGlyphMode tells GDI how to cache glyph information.

ULONG
  DrvGetGlyphMode(
    IN DHPDEV  dhpdev,
    IN FONTOBJ  *pfo
    );

Parameters

dhpdev
Identifies a PDEV.
pfo
Points to a FONTOBJ structure that can be queried to find the font size, transform, and so on.

Return Value

DrvGetGlyphMode returns one of the following values:

Value | Meaning
FO_GLYPHBITS | GDI should cache all glyph data for this font.
FO_HGLYPHS | The device caches fonts on its own, so GDI should cache only glyph handles for this font.
FO_PATHOBJ | GDI should cache PATHOBJ structures for this font.

Headers

Declared in winddi.h. Include winddi.h.

Comments

GDI calls a driver's DrvGetGlyphMode routine to determine the range of font information that should be cached for a particular font; that is, DrvGetGlyphMode determines what GDI stores in its font cache. A device that caches fonts on its own should return FO_HGLYPHS to minimize the storage requirements for the font.

GDI calls DrvGetGlyphMode for each font realization. For example, a driver might want to download outlines for point sizes larger than 12 point, but raster images for smaller fonts. However, GDI reserves the right to refuse this request.

The driver must check the RASTER_FONTTYPE bit of the flFontType member of the FONTOBJ structure to determine the actual form of the glyphs. If this bit is set, GDI is sending bitmaps; otherwise it is sending PATHOBJ structures.

At the time of the call to DrvGetGlyphMode, the associated FONTOBJ is not fully functional. GDI guarantees only that the IFIMETRICS structure and the notional-to-device transform are correct.

DrvGetGlyphMode is an optional driver function. If this function is not provided, GDI will store raster fonts by default.

See Also

FONTOBJ, FONTOBJ_cGetGlyphs, GLYPHDEF, GLYPHPOS, IFIMETRICS, PATHOBJ, STROBJ


DrvGetModes

DrvGetModes lists the modes supported by a given device.

ULONG
  DrvGetModes(
    IN HANDLE  hDriver,
    IN ULONG  cjSize,
    OUT DEVMODEW  *pdm
    );

Parameters

hDriver
Specifies the handle to the driver for which the modes must be enumerated. This is the handle passed in the hDriver parameter of the DrvEnablePDEV function.
cjSize
Specifies the size in bytes of the buffer pointed to by pdm.
pdm
Points to the buffer containing DEVMODEW structure(s) for the driver to fill in, or NULL.

Return Value

The driver should return the number of bytes written to the buffer if pdm is not NULL. If pdm is NULL, the driver should return the number of bytes required to hold all mode data. The driver should return zero if an error occurs.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function must be implemented in all display drivers.

The Window Manager dynamically loads all display drivers associated with a miniport driver (based on the InstalledDisplayDrivers key in the registry). Each display driver is called to retrieve the list of modes supported by that combination of loaded drivers. For example, the VGA64K display driver only returns the 64K color modes that were returned in the list of modes obtained from the miniport driver.

DrvGetModes can be called before there is an active PDEV.

Refer to the permedia sample to see a working implementation of DrvGetModes.

See Also

DEVMODEW, DrvAssertMode, DrvEnablePDEV, EngDeviceIoControl


DrvGetTrueTypeFile

DrvGetTrueTypeFile accesses a memory-mapped TrueType font file.

PVOID
  DrvGetTrueTypeFile(
    IN ULONG_PTR  iFile,
    IN ULONG  *pcj
    );

Parameters

iFile
Identifies a driver TrueType font file.
pcj
Points to a ULONG value that specifies the size, in bytes, of the font file. This parameter cannot be NULL.

Return Value

The return value is a pointer to the memory-mapped TrueType font file if the function is successful. Otherwise, it is NULL.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This private entry point is provided by the TrueType driver to allow GDI efficient access to the memory-mapped TrueType font file.

DrvGetTrueTypeFile is required for TrueType font drivers.

See Also

DrvLoadFontFile


DrvGradientFill

DrvGradientFill shades the specified primitives.

BOOL
  DrvGradientFill(
    IN SURFOBJ  *psoDest,
    IN CLIPOBJ  *pco,
    IN XLATEOBJ  *pxlo,
    IN TRIVERTEX  *pVertex,
    IN ULONG  nVertex,
    IN PVOID  pMesh,
    IN ULONG  nMesh,
    IN RECTL  *prclExtents,
    IN POINTL  *pptlDitherOrg,
    IN ULONG  ulMode
    );

Parameters

psoDest
Points to the SURFOBJ that identifies the surface on which to draw.
pco
Points to a CLIPOBJ. The CLIPOBJ_Xxx service routines are provided to enumerate the clip region as a set of rectangles. This enumeration limits the area of the destination that is modified. Whenever possible, GDI simplifies the clipping involved.
pxlo
Should be ignored by the driver.
pVertex
Points to an array of TRIVERTEX structures, with each entry containing position and color information. TRIVERTEX is defined in the Platform SDK documentation.
nVertex
Specifies the number of TRIVERTEX structures in the array to which pVertex points.
pMesh
Points to an array of structures that define the connectivity of the TRIVERTEX elements to which pVertex points.

When rectangles are being drawn, pMesh points to an array of GRADIENT_RECT structures, each of which specifies two TRIVERTEX elements that define a rectangle. The TRIVERTEX elements can represent any diagonally-opposed pair of rectangle vertices. Rectangle drawing is lower-right exclusive. Both TRIVERTEX and GRADIENT_RECT are defined in the Platform SDK documentation.

When triangles are being drawn, pMesh points to an array of GRADIENT_TRIANGLE structures, each of which specifies the three TRIVERTEX elements that define a triangle. Triangle drawing is lower-right exclusive. GRADIENT_TRIANGLE is defined in the Platform SDK documentation.

nMesh
Specifies the number of elements in the array to which pMesh points.
prclExtents
Points to a RECTL structure that defines the area in which the gradient drawing is to occur. The points are specified in the coordinate system of the destination surface. This parameter is useful in estimating the size of the drawing operations.
pptlDitherOrg
Points to a POINTL structure that defines the origin on the surface for dithering. The upper left pixel of the dither pattern is aligned with this point.
ulMode
Specifies the current drawing mode and how to interpret the array to which pMesh points. This parameter can be one of the following values:
GRADIENT_FILL_RECT_H
The pMesh parameter points to an array of GRADIENT_RECT structures. Each rectangle is to be shaded from left to right. Specifically, the upper-left and lower-left pixels are the same color, as are the upper-right and lower-right pixels.
GRADIENT_FILL_RECT_V
The pMesh parameter points to an array of GRADIENT_RECT structures. Each rectangle is to be shaded from top to bottom. Specifically, the upper-left and upper-right pixels are the same color, as are the lower-left and lower-right pixels.
GRADIENT_FILL_TRIANGLE
The pMesh parameter points to an array of GRADIENT_TRIANGLE structures.

The gradient fill calculations for each mode are documented in the Comments section.

Return Value

DrvGradientFill returns TRUE upon success. Otherwise, it returns FALSE and reports an error by calling EngSetLastError.

Headers

Declared in winddi.h. Include winddi.h.

Comments

DrvGradientFill can be optionally implemented in graphics drivers. GDI never calls this function for palletized surfaces.

The driver hooks DrvGradientFill by setting the HOOK_GRADIENTFILL flag when it calls EngAssociateSurface or EngModifySurface. If the driver has hooked DrvGradientFill and is called to perform an operation that it does not support, the driver should have GDI handle the operation by punting the data in a call to EngGradientFill.

GDI will not call DrvGradientFill for 8bpp destination surfaces.

The formulas for computing the color value at each pixel of the primitive depend on ulMode as follows:

GRADIENT_FILL_TRIANGLE
The triangle's vertices are defined as V1, V2, and V3. Point P is inside the triangle. Draw lines from P to V1, V2, and V3 to form three sub-triangles. Let ai denote the area of the triangle opposite Vi for i=1,2,3. The color at point P is computed as:
RedP   = (RedV1 * a1 + RedV2 * a2 + RedV3 * a3) / (a1+a2+a3)
GreenP = (GreenV1 * a1 + GreenV2 * a2 + GreenV3 * a3) / (a1+a2+a3)
BlueP  = (BlueV1 * a1 + BlueV2 * a2 + BlueV3 * a3) / (a1+a2+a3)
GRADIENT_FILL_RECT_H
The rectangle's top-left point is V1 and the bottom-right point is V2. Point P is inside the rectangle. The color at point P is given by:
RedP =   (RedV2 * (Px - V1x) + RedV1 * (V2x - Px)) / (V2x-V1x)
GreenP = (GreenV2 * (Px - V1x) + GreenV1 * (V2x - Px)) / (V2x-V1x)
BlueP =  (BlueV2 * (Px - V1x) + BlueV1 * (V2x - Px)) / (V2x-V1x)
GRADIENT_FILL_RECT_V
The rectangle's top-left point is V1 and the bottom-right point is V2. Point P is inside the rectangle. The color at point P is given by:
RedP   = (RedV2 * (Py-V1y) + RedV1 * (V2y - Py)) / (V2y-V1y)
GreenP = (GreenV2 * (Py-V1y) + GreenV1 * (V2y - Py)) / (V2y-V1y)
BlueP  = (BlueV2 * (Py-V1y) + BlueV1 * (V2y - Py)) / (V2y-V1y)

The total error accumulated over all three color channels must not be more than eight (8). For more information about permissible error, see Special Effects in Display Drivers.

The driver should ignore the alpha value of the vertices, leaving the alpha channel unchanged for surfaces that support alpha.

See Also

EngAssociateSurface, EngGradientFill


DrvIcmCheckBitmapBits

DrvIcmCheckBitmapBits checks whether the pixels in the specified bitmap lie within the device gamut of the specified transform.

BOOL
  DrvIcmCheckBitmapBits(
    IN DHPDEV  dhpdev,
    IN HANDLE  hColorTransform,
    IN SURFOBJ  *pso,
    OUT PBYTE  paResults
    );

Parameters

dhpdev
Identifies the physical device by its handle.
hColorTransform
Identifies the color transform against which the bitmap is to be checked. This transform was created by the driver through a prior call to its DrvIcmCreateColorTransform routine.
pso
Points to the SURFOBJ that contains the bitmap surface to be checked.
paResults
Points to an array of bytes in which the driver returns the test results. GDI allocates this buffer to contain at least as many bytes as there are pixels in the bitmap. The driver need not perform any allocation or bound checking before writing to the array.

Return Value

DrvIcmCheckBitmapBits returns TRUE upon success. Otherwise, it reports an error and returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Each byte in the array to which paResults points corresponds with a pixel in the bitmap. For each pixel, the driver determines whether its color value is in the device gamut and then writes a value between zero and 255 in the corresponding array byte. The values have the following meanings:

Value | Meaning
Zero | The color is in the device gamut.
Nonzero | The color is outside of the gamut. A value of n+1 indicates that the color is at least as far out of the gamut as a value of n.

DrvIcmCheckBitmapBits can be optionally implemented in drivers that support ICM. A driver indicates support for ICM by setting the GCAPS_ICM flag in the flGraphicsCaps member of the DEVINFO structure.

See Also

DrvIcmCreateColorTransform


DrvIcmCreateColorTransform

DrvIcmCreateColorTransform creates an ICM color transform.

HANDLE
  DrvIcmCreateColorTransform(
    IN DHPDEV  dhpdev,
    IN LPLOGCOLORSPACEW  pLogColorSpace,
    IN PVOID  pvSourceProfile,
    IN ULONG  cjSourceProfile,
    IN PVOID  pvDestProfile,
    IN ULONG  cjDestProfile,
    IN PVOID  pvTargetProfile,
    IN ULONG  cjTargetProfile,
    IN DWORD  dwReserved
    );

Parameters

dhpdev
Identifies the physical device by its handle.
pLogColorSpace
Points to a logical color space structure. The LOGCOLORSPACEW structure is defined in the Platform SDK documentation. The driver should obtain source color space information from this structure when pvSourceProfile is NULL.
pvSourceProfile
Points to the memory map of the source profile. This parameter can be NULL.
cjSourceProfile
Specifies the size, in bytes, of the source profile memory map. If pvSourceProfile is NULL, this parameter should be set to zero.
pvDestProfile
Points to the memory map of the destination profile.
cjDestProfile
Specifies the size, in bytes, of the destination profile memory map.
pvTargetProfile
Points to the memory map of the target profile. This parameter can be NULL.
cjTargetProfile
Specifies the size, in bytes, of the target profile memory map. If pvTargetProfile is NULL, this parameter should be set to zero.
dwReserved
Reserved parameter that should be set to zero.

Return Value

DrvIcmCreateTransform returns a handle to the created transform upon success. Otherwise, it reports an error and returns NULL.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The driver creates a color transform from the profile data as follows:

  • The driver should use the source profile that pvSourceProfile points to when it is not NULL. Otherwise, the driver should use the data in the structure to which pLogColorSpace points for source color space information.
  • When the driver receives a destination profile but no target profile, it should store the data required to transform colors from the specified source color space into the specified destination color space.
  • When the driver receives both destination and target profiles, it should store the data required to transform colors from the specified source color space into the specified target color space and from the target color space back to the destination color space. In this scenario, the driver's device is the destination device on which an image can be proofed. The driver must then be able to convert the color space of the proofing image into the target device's color space.

Regardless of whether a target profile is specified, the driver's device is always the destination device.

The provided profiles adhere to version 2.10 of the ICC profile format. If the driver does not understand the specified format, it should fail the call.

The driver can safely access the entire memory map of each profile. The pvSourceProfile, pvDestProfile, and pvTargetProfile pointers are valid only during the scope of the call to DrvIcmCreateTransform.

Drivers that report ICM support should implement this function. A driver indicates support for ICM by setting the GCAPS_ICM flag in the flGraphicsCaps member of the DEVINFO structure.

See Also

DrvIcmDeleteColorTransform


DrvIcmDeleteColorTransform

DrvIcmDeleteColorTransform deletes the specified color transform.

BOOL
  DrvIcmDeleteColorTransform(
    IN DHPDEV  dhpdev,
    IN HANDLE  hcmXform
    );

Parameters

dhpdev
Identifies the physical device by its handle.
hcmXform
Identifies the color transform to be deleted. This color transform was created by the driver in a call to DrvIcmCreateColorTransform.

Return Value

DrvIcmDeleteColorTransform returns TRUE upon success. Otherwise, it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Drivers that report ICM support should implement this function. A driver indicates support for ICM by setting the GCAPS_ICM flag in the flGraphicsCaps member of the DEVINFO structure.

See Also

DrvIcmCreateColorTransform


DrvIcmSetDeviceGammaRamp

DrvIcmSetDeviceGammaRamp sets the hardware gamma ramp of the specified display device.

BOOL
  DrvIcmSetDeviceGammaRamp(
    IN DHPDEV  dhpdev,
    IN ULONG  iFormat,
    IN LPVOID  lpRamp
    );

Parameters

dhpdev
Identifies the physical device whose gamma ramp is to be set.
iFormat
Specifies the data format of the buffer to which lpRamp points. This parameter is always IGRF_RGB_256WORDS.
lpRamp
Points to the buffer containing the gamma ramp to be set on the device. The format of the data in this buffer is determined by iFormat.

When iFormat is IGRF_RGB_256WORDS, lpRamp points to a GAMMARAMP structure that defines the 256-entry ramps to be set for each of the red, blue, and green color channels. Each value is described using 16-bit precision. If the hardware has fewer bits of precision, it should downshift and use the most significant bits, without rounding.

Return Value

DrvIcmSetDeviceGammaRamp returns TRUE upon success. Otherwise, it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Drivers for display devices with loadable hardware gamma ramps should implement this function.

DrvIcmSetDeviceGammaRamp should fail if it is called with any other value besides IGRF_RGB_256WORDS in iFormat.

The driver hooks this function by setting the GCAPS2_CHANGEGAMMARAMP flag in the flGraphicsCaps2 field of the DEVINFO structure passed to DrvEnablePDEV. In general, the driver should not set this capability when running in a palettized 8bpp mode.


DrvLineTo

DrvLineTo draws a single, solid, integer-only cosmetic line.

BOOL
  DrvLineTo(
    SURFOBJ  *pso,
    CLIPOBJ  *pco,
    BRUSHOBJ  *pbo,
    LONG  x1,
    LONG  y1,
    LONG  x2,
    LONG  y2,
    RECTL  *prclBounds,
    MIX  mix
    );

Parameters

pso
Points to a SURFOBJ structure that describes the surface on which to draw.
pco
Points to a CLIPOBJ structure that defines the clip region in which the rendering must be done. No pixels can be affected outside this clip region.
pbo
Points to a BRUSHOBJ structure that specifies the brush to use when drawing the line.
x1, y1
Specify the integer x- and y-coodinates of the line's beginning point.
x2, y2
Specify the integer x- and y-coordinates of the line's end point.
prclBounds
Points to an integer rectangle that bounds the unclipped line. Drivers that support hardware line drawing can use this rectangle to quickly determine whether the line fits in a coordinate space small enough to be rendered by the hardware.
mix
Defines how the incoming pattern should be mixed with the data already on the device surface. The low-order byte defines the raster operation. For more information about raster operation codes, see the Platform SDK documentation.

Return Value

DrvLineTo returns TRUE if it succeeds; otherwise, it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

DrvLineTo is an optional entry point that a driver can supply as an optimization for application calls to the Win32 LineTo function. If the driver doesn't hook DrvLineTo, or if the driver returns FALSE from a call to this function, GDI will automatically call DrvStrokePath instead. A driver that has hooked DrvLineTo can call EngLineTo when the rendering surface is a DIB.

This function is simpler than DrvStrokePath because it supports only integer end-points and solid cosmetic lines. GDI has less overhead when calling DrvLineTo instead of DrvStrokePath; consequently, DrvLineTo is intended to be used as a simple optimization by drivers that can accelerate nominal width lines in hardware.

See Also

BRUSHOBJ, CLIPOBJ, DrvStrokePath, EngLineTo, SURFOBJ


DrvLoadFontFile

The DrvLoadFontFile function receives information from GDI relating to loading and mapping font files.

ULONG_PTR
  DrvLoadFontFile(
    ULONG  cFiles,
    ULONG_PTR  *piFile,
    PVOID  *ppvView,
    ULONG  *pcjView,
    DESIGNVECTOR  *pdv,
    ULONG  ulLangID,
    ULONG  ulFastCheckSum
    );

Parameters

cFiles
Caller-supplied value indicating the number of files associated with the font.
piFile
Caller-supplied pointer to a cFiles-sized array of file handles. Each handle represents one of the files associated with the font. The file handles can be passed individually to EngMapFontFileFD.
ppvView
Caller-supplied pointer to a cFiles-sized array containing the starting address of the memory space into which each font file has been mapped.
pcjView
Caller-supplied pointer to a cFiles-sized array containing the size of the memory space into which each font file has been mapped.
pdv
For Adobe Multiple Master fonts, this is a caller-supplied pointer to a DESIGNVECTOR structure (described in the Platform SDK documentation) identifying the Multiple Master instance. Otherwise, this parameter is NULL.
ulLangID
Caller-supplied language identifier, obtained from the registry.
ulFastCheckSum
Specifies a GDI-supplied checksum for the font. If this parameter is nonzero, the GDI font cache engine can be used in order to access a font more quickly. If this parameter is zero, the GDI font engine cannot be used.

Return Value

If the operation succeeds, it should return a driver-defined value that uniquely identifies the font. The driver will subsequently receive this value as an input parameter to such functions as DrvQueryFont, DrvQueryFontFile, DrvQueryFontTree. If an error is encountered, the function should return HFF_INVALID.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Font drivers are required to supply a DrvLoadFontFile function. The function's purpose is to allow a font driver to receive notification that a font's associated files are being loaded and mapped. The driver can store input arguments for later use.

Loading and mapping a font file entails calling EngMapFontFileFD. When an application calls AddFontResource or AddFontResourceEx (described in the Platform SDK documentation), GDI calls EngMapFontFileFD and then calls DrvLoadFontFile. The DrvLoadFontFile function's ppvView and pcjView parameters supply the location and size of each file's mapping, as returned by EngMapFontFileFD.

GDI unmaps the files when DrvLoadFontFile returns. If the driver needs to remap the files later, in response to subsequent calls from GDI, it can call EngMapFontFileFD itself if it has saved the cFiles and piFile parameters.

When the GDI font engine calls the font driver's DrvLoadFontFile DDI, it passes a checksum for the font in the ulFastCheckSum parameter. If this parameter is nonzero and the font in question has been cached, DrvLoadFontFile can obtain a pointer to the font data with a call to EngFntCacheLookUp. After the font driver obtains the pointer to the font data, it can then load the font data. If the font has not been cached, the font driver can cache the font by first allocating memory for the font cache, using a call to EngFntCacheAlloc, and then writing the font data to that memory. If the font driver encounters an error reading or writing the font data, it can notify the GDI font engine by making a call to EngFntCacheFault.

If the GDI font engine called DrvLoadFontFile and passed in a value of zero for the ulFastCheckSum parameter, this means that the GDI font engine is not in operation, and the font driver does not need to take any action.

See Also

DrvUnloadFontFile, EngFntCacheLookUp, EngFntCacheAlloc, EngFntCacheFault


DrvMovePointer

DrvMovePointer moves the pointer to a new position and ensures that GDI does not interfere with the display of the pointer.

VOID
  DrvMovePointer(
    IN SURFOBJ  *pso,
    IN LONG  x,
    IN LONG  y,
    IN RECTL  *prcl
    );

Parameters

pso
Points to a SURFOBJ structure that describes the surface of a display device.
x,y
Specify the x and y coordinates on the display where the driver should position the hot spot of the pointer.

A negative x value indicates that the driver should remove the pointer from the display because drawing is about to occur where it is presently located. If the pointer has been removed from the display and the x value is nonnegative, the driver should restore the pointer.

When the driver has set the GCAPS_PANNING flag in the DEVINFO structure, a negative y value indicates that GDI is calling this function only to notify the driver of the cursor's current position. The current position can be computed as (x, y+pso->sizlBitmap.cy). A driver that does not set the GCAPS_PANNING flag will never receive a negative y coordinate.

prcl
Points to a RECTL structure defining an area that bounds all pixels affected by the pointer on the display. GDI will not draw in this rectangle without first removing the pointer from the screen. This parameter can be null.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Drivers sometimes need to know the current position of the pointer on the screen – even when GDI is simulating the pointer (such that the driver no longer gets normal DrvMovePointer calls) – in order to handle panning virtual displays. To receive this notification, the driver should set the GCAPS_PANNING flag in the flGraphicsCaps field of the DEVINFO structure.

DrvMovePointer will not be called while any thread is drawing in the display driver unless the GCAPS_ASYNCMOVE flag is set in the flGraphicsCaps member of DEVINFO.

DrvMovePointer must be implemented in display drivers only when DrvSetPointerShape is also implemented.

If a driver has registered the specified pointer using DrvSetPointerShape, DrvMovePointer must not fail.

See Also

DEVINFO, SURFOBJ


DrvNextBand

DrvNextBand is called by GDI when it has finished drawing a band for a physical page, so the driver can send the band to the printer.

BOOL
  DrvNextBand(
    IN SURFOBJ  *pso,
    IN POINTL  *pptl
    );

Parameters

pso
Caller-supplied pointer to a SURFOBJ structure, which identifies the banding surface.
pptl
Caller-supplied pointer to a POINTL structure to receive the function-supplied origin of the next band.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise, it should call SetLastError to set an error code, and then return FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

If a printer graphics DLL uses GDI-managed surfaces, and if it supports surface banding, it must provide a DrvNextBand function. GDI calls DrvNextBand each time it has finished drawing the portion of the page's image that can be contained on the band's surface. The surface used by GDI for drawing is one that the driver previously specified by calling EngMarkBandingSurface. The function should send the image to the printer by calling EngWritePrinter, and it should return the indices of the next band's origin in the POINTL structure pointed to by pptl.

After all of a physical page's bands have been drawn, the function should return (-1, -1) in the supplied POINTL structure. GDI then calls the driver's DrvSendPage function.

See Also

DrvStartBanding, DrvEnableSurface


DrvNotify

DrvNotify allows a display driver to be notified about certain information by GDI.

VOID
  DrvNotify(
    IN SURFOBJ  *pso,
    IN ULONG  iType,
    IN PVOID  pvData
    );

Parameters

pso
Points to a SURFOBJ structure that describes the primary surface for which notification is occurring.
iType
Identifies the type of information about which GDI is notifying the driver. This parameter can be one of the following values:
DN_DEVICE_ORIGIN
Notifies the driver of the device's origin. The pvData parameter points to a POINTL structure that identifies the origin of the physical device in desktop space. This notification is useful for drivers of devices that are a part of a multi-monitor system. The value to which pvData points is always (0,0) on a single monitor system.
DN_DRAWING_BEGIN
Notifies the driver that the first drawing operation is about to occur for this instance of the PDEV that is associated with the specified surface. The pvData parameter points to NULL.
pvData
Points to notification data or NULL, depending on the value of iType.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A display driver can optionally implement DrvNotify. GDI will call DrvNotify only in display drivers that do implement it.

See Also

EngQueryDeviceAttribute


DrvOffset

DrvOffset is obsolete.

BOOL
  DrvOffset(
    IN SURFOBJ  *pso,
    IN LONG  x,
    IN LONG  y,
    IN FLONG  flReserved
    );

Headers

Declared in winddi.h. Include winddi.h.


DrvPaint

DrvPaint is obsolete, and is no longer called by GDI in Windows 2000 and later. New drivers should implement one or more of DrvFillPath, DrvStrokePath, or DrvStrokeAndFillPath.

BOOL
  DrvPaint(
    IN SURFOBJ  *pso,
    IN CLIPOBJ  *pco,
    IN BRUSHOBJ  *pbo,
    IN POINTL  *pptlBrushOrg,
    IN MIX  mix
    );

Headers

Declared in winddi.h. Include winddi.h.


DrvPlgBlt

DrvPlgBlt provides rotate bit-block transfer capabilities between combinations of device-managed and GDI-managed surfaces.

BOOL
  DrvPlgBlt(
    IN SURFOBJ  *psoTrg,
    IN SURFOBJ  *psoSrc,
    IN SURFOBJ  *psoMsk,
    IN CLIPOBJ  *pco,
    IN XLATEOBJ  *pxlo,
    IN COLORADJUSTMENT  *pca,
    IN POINTL  *pptlBrushOrg,
    IN POINTFIX  *pptfx,
    IN RECTL  *prcl,
    IN POINTL  *pptl,
    IN ULONG  iMode
    );

Parameters

psoTrg
Points to a SURFOBJ structure that describes the surface on which to draw.
psoSrc
Points to a SURFOBJ structure that describes the source for the bit-block transfer operation.
psoMsk
Points to an optional surface that represents a mask for the source. It is defined by a logic map, which is a bitmap with one bit per pixel.

This mask limits the area of the source that is copied. A mask has an implicit rop4 of 0xCCAA, which means the source should be copied wherever the mask is one, but the destination should be left alone wherever the mask is zero.

If this parameter is NULL, rop4 is implicitly 0xCCCC, which means the source should be copied everywhere in the source rectangle.

The mask is always large enough to contain the relevant source; tiling is unnecessary.

pco
Points to a CLIPOBJ structure that limits the area of the destination to be modified. GDI functions enumerate the clip region as a set of rectangles.

Whenever possible, GDI simplifies the clipping involved. Unlike the DrvBitBlt function, DrvPlgBlt can be called with a single clipping rectangle. This prevents rounding errors in clipping the output.

pxlo
Points to a XLATEOBJ structure that defines how color indices are translated between the source and target surfaces. The XLATEOBJ can also be queried to find the RGB color for any source index. If pxlo is NULL, no translation is needed.

A high quality rotate bit-block transfer is needed to interpolate colors.

pca
Points to a COLORADJUSTMENT structure that defines the color adjustment values to be applied to the source bitmap before stretching the bits. For more information about this structure, see the Platform SDK documentation.
pptlBrushOrg
Points to the origin of the halftone brush. Device drivers that use halftone brushes should align the upper left pixel of the brush's pattern with this point on the device surface.
pptfx
Points to three POINTFIX structures that define a parallelogram in the destination surface. Define pptfx[0] as A, pptfx[1] as B, and pptfx[2] as C. A, B, and C define three vertices of a parallelogram. A fourth implicit vertex is given as:
    D = B + C – A

DrvPlgBlt is never called with A, B, and C colinear.

prcl
Points to a RECTL structure that defines the area to be copied, in the coordinate system of the source surface. The points of the source rectangle are well ordered. DrvPlgBlt will never be given an empty source rectangle.
pptl
Points to a POINTL structure that specifies which pixel in the given mask corresponds to the upper-left pixel in the source rectangle. Ignore this parameter if no psoMsk is specified.
iMode
Defines how source pixels are combined to get output pixels. This value can be one of the following:
Value | Meaning
BLACKONWHITE | On a shrinking bit-block transfer, pixels should be combined with an AND operation. On a stretching bit-block transfer, pixels should be replicated.
COLORONCOLOR | On a shrinking bit-block transfer, enough pixels should be ignored so that pixels need not be combined. On a stretching bit-block transfer, pixels should be replicated.
HALFTONE | The driver can use groups of pixels in the output surface to best approximate the color or gray level of the input.
WHITEONBLACK | On a shrinking bit-block transfer, pixels should be combined with an OR operation. On a stretching bit-block transfer, pixels should be replicated.

The methods WHITEONBLACK, BLACKONWHITE, and COLORONCOLOR provide compatibility for old applications, but do not produce the best results for color surfaces.

Return Value

DrvPlgBlt returns TRUE upon success. Otherwise, it reports an error and returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Similar to DrvStretchBlt, DrvPlgBlt enables a device driver to write to GDI bitmaps, especially when the driver can do halftoning.

To transform the bitmap, this function performs bit-block transfers from a rectangle defined by prcl to any parallelogram. The parallelogram is defined by pptfx, which points to an array of three points.

The source rectangle at prcl is considered to be a geometric rectangle whose corners are displaced by (-0.5,-0.5) from the given integer coordinates. This exactly matches the source rectangle for DrvStretchBlt. The source rectangle is always well ordered.

The upper-left corner of the source rectangle is mapped to the first point, A. The upper-right corner of the source rectangle is mapped to the second point, B. The lower-left corner of the source rectangle is mapped to the third point, C. The lower right corner of the source rectangle is mapped to the implicit point in the parallelogram defined by treating the three given points as vectors and computing:

    D = B + C - A

Note that a stretch blit can be expressed exactly as a parallelogram blt, but the coordinates given for the destination will have a fractional part of 0.5.

DrvPlgBlt is optional for graphics drivers. It is provided only for certain types of rotation. The driver should call EngPlgBlt if DrvPlgBlt is called to perform operations it does not support.

See Also

DrvAlphaBlend, DrvBitBlt, DrvStretchBlt, DrvStretchBltROP, DrvTransparentBlt, EngAlphaBlend, EngBitBlt, EngPlgBlt, EngStretchBlt, EngStretchBltROP, EngTransparentBlt


DrvQueryAdvanceWidths

DrvQueryAdvanceWidths returns character advance widths for a specified set of glyphs.

BOOL
  DrvQueryAdvanceWidths(
    IN DHPDEV  dhpdev,
    IN FONTOBJ  *pfo,
    IN ULONG  iMode,
    IN HGLYPH  *phg,
    OUT PVOID  pvWidths,
    IN ULONG  cGlyphs
    );

Parameters

dhpdev
Identifies a PDEV previously returned by DrvEnablePDEV.
pfo
Points to a FONTOBJ structure that identifies the font instance.
iMode
Specifies the type of information to be provided. This parameter can be one of the following values:
Value | Meaning
QAW_GETEASYWIDTHS | The character advance widths are returned as an array of 12.4 fixed-point numbers. This mode will not be used if the widths exceed the range of the 12.4 representation. This routine should compute widths as quickly as possible. If the computation of a glyph's character advance width cannot be accomplished efficiently, the driver should write 0xFFFF into the buffer for that glyph. The function returns DDI_ERROR if an error occurs, FALSE if not all widths can be efficiently computed for this mode, or TRUE in all other cases.
QAW_GETWIDTHS | The character advance widths are recorded as an array of 12.4 fixed-point numbers. This mode will not be used if the widths exceed the range of the 12.4 representation. The function returns TRUE if successful.

phg
Points to an array of HGLYPH structures that specify the glyphs for which the driver will return character advance widths.
pvWidths
Points to a buffer where the driver will record data.
cGlyphs
Specifies the number of glyphs in the input buffer pointed to by phg.

Return Value

The return value is dependent on the value of the iMode parameter.

Headers

Declared in winddi.h. Include winddi.h.

See Also

DrvEnablePDEV, FONTOBJ


DrvQueryDeviceSupport

DrvQueryDeviceSupport returns requested device-specific information.

BOOL
  DrvQueryDeviceSupport(
    SURFOBJ  *pso,
    XLATEOBJ  *pxlo,
    XFORMOBJ  *pxo,
    ULONG  iType,
    ULONG  cjIn,
    PVOID  pvIn,
    ULONG  cjOut,
    PVOID  pvOut
    );

Parameters

pso
Caller-supplied pointer to a SURFOBJ structure.
pxlo
Caller-supplied pointer to an XLATEOBJ structure.
pxo
Caller-supplied pointer to an XFORMOBJ structure.
iType
Caller-supplied bit flag indicating the type of information being requested. One of the following flags can be specified:
Flag | Definition
QDS_CHECKJPEGFORMAT | The buffer pointed to by pvIn contains a JPEG-compressed image. The function must return TRUE if the device can print the image. Otherwise it must return FALSE.
QDS_CHECKPNGFORMAT | The buffer pointed to by pvIn contains a PNG-compressed image. The function must return TRUE if the device can print the image. Otherwise it must return FALSE.

cjIn
Caller-supplied size of the buffer pointed to by pvIn.
pvIn
Caller-supplied pointer to an input buffer.
cjOut
Caller-supplied size of the buffer pointed to by pvOut.
pvOut
Caller-supplied pointer to an output buffer.

Return Value

If the operation succeeds, the function should return TRUE; otherwise it should return FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

If the QDS_CHECKJPEGFORMAT or QDS_CHECKPNGFORMAT flag is set in iType, the following rules apply:

  • The pvIn parameter points to a buffer containing a JPEG-compressed or PNG-compressed image. The driver must return TRUE if the image can be printed, or FALSE otherwise.
  • The pxlo parameter is valid but the only information of interest is the XLATEOBJ structure's flXlate member. If either the XO_HOST_ICM or XO_DEVICE_ICM flag is set, the driver must only return TRUE if it can convert the image's color space to the printer's color space (or if the two color spaces are the same). For more information, see Color Management of JPEG and PNG Images.

For more information about supporting JPEG and PNG compressed images, see the Comments section for DEVINFO.


DrvQueryDriverInfo

DrvQueryDriverInfo returns requested driver-specific information.

BOOL
  DrvQueryDriverInfo(
    DWORD  dwMode,
    PVOID  pBuffer,
    DWORD  cbBuf,
    PDWORD  pcbNeeded
    );

Parameters

dwMode
Caller-supplied constant value, as indicated in the following table.
Value | Definition
DRVQUERY_USERMODE | The caller is querying whether the driver executes in user mode or in kernel mode.

pBuffer
Caller-supplied pointer to a buffer to receive requested information. The function must supply the following information:
dwMode Value | pBuffer Size | Value supplied by DrvQueryDriverInfo
DRVQUERY_USERMODE | 1 DWORD | TRUE if driver executes in user mode; otherwise FALSE.

cbBuf
Caller-supplied value representing the size, in bytes, of the buffer pointed to by pBuffer.
pcbNeeded
Caller-supplied pointer to a location to receive the minimum buffer size, in bytes, required to contain the requested information.

Return Value

If the operation succeeds, the function should return TRUE; otherwise it should return FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Printer graphics DLLs that execute in user mode must export a DrvQueryDriverInfo function. If the function is not exported, the local print provider assumes the graphics DLL executes in kernel mode.


DrvQueryFont

DrvQueryFont is used by GDI to get the IFIMETRICS structure for a given font.

PIFIMETRICS
  DrvQueryFont(
    IN DHPDEV  dhpdev,
    IN ULONG_PTR  iFile,
    IN ULONG  iFace,
    IN ULONG_PTR  *pid
    );

Parameters

dhpdev
Pointer to a PDEV handle that identifies a physical device. The PDEV was returned from a previous call to DrvEnablePDEV.
iFile
Identifies a driver font file. This identifier is returned by DrvLoadFontFile. This parameter is zero for device-resident fonts.
iFace
Specifies the one-based index of the driver font. GDI can query the number of fonts from the DEVINFO structure.
pid
Points to a memory location holding the address of an identifier that GDI will pass to DrvFree when the IFIMETRICS structure is no longer needed. Depending on how the driver manages memory, this identifier can identify the structure, identify the way it was allocated, or do nothing at all.

Return Value

The return value is a pointer to the IFIMETRICS structure that describes the given font if the function is successful. Otherwise, it is null, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The driver fills the IFIMETRICS structure.

The IFIMETRICS structure must remain unchanged during the scope of the associated PDEV.

If the number of fonts in DEVINFO is -1 and iFace is zero, the driver should return the number of fonts it supports.

DrvQueryFont is required for font drivers and drivers that use driver-specific or device-specific fonts.

See Also

DEVINFO, DrvEnablePDEV, DrvLoadFontFile, IFIMETRICS


DrvQueryFontCaps

DrvQueryFontCaps defines the capabilities of the font driver.

LONG
  DrvQueryFontCaps(
    IN ULONG  culCaps,
    OUT ULONG  *pulCaps
    );

Parameters

culCaps
Specifies the number of ULONG values that can be written by the font driver.
pulCaps
Points to a buffer that will receive the number of values specified in the first parameter. The elements of the array have the following meanings:
Element | Meaning
pulCaps[0] | A count of the number of ULONG values in the complete array. If culCaps is less than this value, then the caller will receive an incomplete array.
pulCaps[1] A set of flags that can be one or more of the following values:

QC_OUTLINES
If this flag is set, the font driver can return an outline description of the glyphs. Moreover, the fonts are assumed to be scalable. Bitmap fonts do not have this flag set.

QC_1BIT
Indicates that the font driver is capable of returning monochrome bitmaps of each glyph.

QC_4BIT
Indicates that the font driver is capable of returning antialiased 4-bits-per-pixel bitmaps. Each pixel in the bitmap is represented by an unsigned 4-bit value in the range 0 through 15, yielding 16 shades of gray.

Return Value

The return value is the number of ULONG values written to the destination buffer if the function is successful. Otherwise, it is FD_ERROR.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A driver might report that it supports more than one format for a font. For example, a driver could, in principle, return with both QC_1BIT and QC_4BIT set, indicating that it is capable of returning both monochrome and antialiased versions of the font. All bitmaps generated by a font driver must start and end on 32-bit boundaries. If necessary, the end of a bitmap should be "padded" to satisfy this requirement.

See Also

DrvQueryFont, DrvQueryFontTree


DrvQueryFontData

DrvQueryFontData retrieves information about a realized font.

LONG
  DrvQueryFontData(
    IN DHPDEV  dhpdev,
    IN FONTOBJ  *pfo,
    IN ULONG  iMode,
    IN HGLYPH  hg,
    IN OUT GLYPHDATA  *pgd,
    IN OUT PVOID  pv,
    IN ULONG  cjSize
    );

Parameters

dhpdev
Identifies a PDEV returned from a prior call to DrvEnablePDEV.
pfo
Points to a FONTOBJ structure that defines the font realization.
iMode
Specifies the type of information requested. This parameter can be one of the following values:
Value | Meaning
QFD_GLYPHANDBITMAP If pgd is not null, then the driver should fill in the GLYPHDATA structure with the metrics of the glyph specified by hg.

If pv is not null, a GLYPHBITS structure should be written at this address. The driver should copy the glyph bitmap corresponding to the glyph specified by hg into this structure. The size of the structure is specified by cjSize.

If glyph bitmaps are not supported by the driver, this function will only be called with pv set to null.

If the driver supports glyph bitmaps, the return value is the size, in bytes, of the glyph bitmap. Otherwise, it is zero.

This mode must be supported.
QFD_GLYPHANDOUTLINE If pgd is not null, then the driver should fill in the GLYPHDATA structure with the metrics of the glyph specified by hg.

If pv is not null, a PATHOBJ structure should be written at this address. The driver passes this PATHOBJ to the PATHOBJ_Xxx services to create the outline for the glyph specified by hg. The cjSize parameter should be ignored.

The return value is zero if the function is successful. Otherwise, it is FD_ERROR.

Only font drivers that provide glyph outlines need to support this mode.
QFD_MAXEXTENTS If pv is not null, the driver should write an FD_DEVICEMETRICS structure to the buffer pointed to by pv.

The return value is the size, in bytes, needed for the buffer if pv is null.

If pgd is nonzero, the font driver should copy an FD_REALIZEEXTRA structure to this address that corresponds to this realization of the font, as identified by the FONTOBJ.
QFD_TT_GRAY1_BITMAP | The realized font should be rendered in one bit-per-pixel of grayscale (that is, either black or white).
QFD_TT_GRAY2_BITMAP | The realized font should be rendered in two bits-per-pixel of grayscale.
QFD_TT_GRAY4_BITMAP | The realized font should be rendered in four bits-per-pixel of grayscale.
QFD_TT_GRAY8_BITMAP | The realized font should be rendered in eight bits-per-pixel of grayscale.
QFD_TT_MONO_BITMAP | Same as QFD_TT_GRAY1_BITMAP.

hg
Specifies the glyph.
pgd
Points to GLYPHDATA structure. This parameter can be null.
pv
Points to a data buffer. The type of data written to this buffer is dependent on iMode. This parameter can be null.
cjSize
Specifies the size of the buffer pointed to by pv.

Return Value

The return value depends on the value of the iMode parameter. If an error occurs, the return value is FD_ERROR, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

GDI provides a pointer to an array of glyph or kerning handles, and the driver returns information about the glyphs or kerning pairs. The driver can assume that all handles in the array are valid.

DrvQueryFontData is required for font drivers and drivers that use device-specific or driver-specific fonts.

See Also

DrvEnablePDEV, DrvQueryFontFile, FD_DEVICEMETRICS, FONTOBJ, GLYPHBITS, PATHOBJ


DrvQueryFontFile

DrvQueryFontFile provides font file information.

LONG
  DrvQueryFontFile(
    IN ULONG_PTR  iFile,
    IN ULONG  ulMode,
    IN ULONG  cjBuf,
    IN ULONG  *pulBuf
    );

Parameters

iFile
Identifies the driver font file. This identifier is returned by a prior call to DrvLoadFontFile.
ulMode
Specifies the type of information to be written. This parameter can be one of the following values:
Value | Meaning
QFF_DESCRIPTION | The function provides a string that an NT-based operating system will use to describe the font file. A zero-terminated Unicode string is written to the buffer pointed to by pulBuffer.
QFF_NUMFACES | The function returns the number of typefaces in the font file; the cjBuf and pulBuf parameters are ignored. Typefaces are identified by an index ranging from one through the number of typefaces.

cjBuf
Specifies the size, in bytes, of the return buffer.
pulBuf
Points to the return buffer.

Return Value

If ulMode is QFF_NUMFACES, then the return value is the number of faces in the font file. If pulBuf is null, it is the number of bytes of data that would be written to pulBuf; otherwise, it is the number of bytes written to pulBuf. If an error occurs, the return value is FD_ERROR.

Headers

Declared in winddi.h. Include winddi.h.

Comments

DrvQueryFontFile is required for font drivers.

See Also

DrvLoadFontFile


DrvQueryFontTree

DrvQueryFontTree provides GDI with a pointer to a structure that defines one of the following:

  • A mapping from Unicode to glyph handles, including glyph variants
  • A mapping of kerning pairs to kerning handles
PVOID
  DrvQueryFontTree(
    IN DHPDEV  dhpdev,
    IN ULONG_PTR  iFile,
    IN ULONG  iFace,
    IN ULONG  iMode,
    IN ULONG_PTR  *pid
    );

Parameters

dhpdev
Identifies a device by a handle to its PDEV, returned from a prior call to DrvEnablePDEV.
iFile
Identifies the driver font file. This value is returned by DrvLoadFontFile.
iFace
Specifies the one-based index of the driver font.
iMode
Specifies the type of information to be provided. This can be one of the following values:
Value | Meaning
QFT_GLYPHSET | GDI requests a pointer to an FD_GLYPHSET structure that defines the mappings from single Unicode characters to glyph handles.
QFT_KERNPAIRS GDI requests a pointer to a sorted, null-terminated array of FD_KERNINGPAIR structures.

The kerning pairs should be stored in increasing order. The primary key is the second Unicode character; the secondary key is the first Unicode character in the kerning pair.

pid
Points to a memory location holding the address of an identifier that GDI will pass to DrvFree, along with the returned pointer, when the FD_GLYPHSET structure or array of FD_KERNINGPAIR structures are no longer needed. Depending on how memory is managed in the driver, this identifier can identify the structure, identify the way it was allocated, or do nothing at all.

Return Value

The return value is a pointer to the requested structure if the function is successful. Otherwise, it is NULL, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The returned structure must remain unmodified until GDI calls DrvFree with the address of the structure.

DrvQueryFontTree is required for font drivers and drivers that use device-specific fonts.

See Also

DEVINFO, DrvEnablePDEV, DrvFree, DrvLoadFontFile, DrvQueryFontData, DrvQueryFontTree, FD_GLYPHSET, FD_KERNINGPAIR, IFIMETRICS


DrvQueryGlyphAttrs

DrvQueryGlyphAttrs returns information about a font's glyphs.

PFD_GLYPHATTR
  DrvQueryGlyphAttrs(
    IN FONTOBJ  *pfo,
    IN ULONG  iMode
    );

Parameters

pfo
GDI-supplied pointer to a FONTOBJ structure identifying the font for which attributes are being requested.
iMode
GDI-supplied flag indicating the type of glyph attribute being requested. The following flag is defined:
Flag | Definition
FO_ATTR_MODE_ROTATE | The function returns an array indicating which glyphs of a vertical font must be rotated.

Return Value

DrvQueryGlyphAttrs should return a pointer to an FD_GLYPHATTR structure. If an error is encountered, such as an invalid input argument, or if the font described by the FONTOBJ structure is not a vertical font, the function should return NULL.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The DrvQueryGlyphAttrs function should be supplied by font drivers. Currently, the only attribute flag defined is FO_ATTR_MODE_ROTATE, meaning the function should indicate which glyphs of a vertical font must be rotated. (For vertical fonts, DBCS glyphs must be rotated.) This information is useful to printer drivers that support printers having built-in font rasterizers.

The function should return rotation information in the FD_GLYPHATTR structure that is used as the function's return value.

GDI calls the appropriate font driver's DrvQueryGlyphAttrs function when a printer driver calls GDI's FONTOBJ_pQueryGlyphAttrs function.


DrvQueryPerBandInfo

A printer graphics DLL's DrvQueryPerBandInfo function is called by GDI before it begins drawing a band for a physical page, so the driver can supply GDI with band-specific information.

ULONG
  DrvQueryPerBandInfo(
    IN SURFOBJ  *pso,
    IN OUT PERBANDINFO  *pbi
    );

Parameters

pso
Caller-supplied pointer to a SURFOBJ structure describing the drawing surface.
pbi
Caller-supplied pointer to a PERBANDINFO structure containing default information, which the function can overwrite.

Return Value

The function must return one of the following values:

Value | Definition
Greater than zero | GDI will use the contents of the PERBANDINFO structure.
Zero | GDI will ignore the contents of the PERBANDINFO structure.
DDI_ERROR | GDI will not draw the band.

Headers

Declared in winddi.h. Include winddi.h.

Comments

If a printer graphics DLL uses GDI-managed surfaces, and if it supports surface banding, it can optionally provide a DrvQueryPerBandInfo function. GDI calls the function prior to rendering each band.

The printer graphics DLL uses the function's PERBANDINFO structure to indicate whether the previous band should be redrawn, and to specify that the band should be scaled. If a printer graphics DLL supports banding but does not provide a DrvQueryPerBandInfo function, GDI will not repeat or scale bands.

The DrvQueryPerBandInfo function is only called during playback of EMF files.

See Also

DrvNextBand, DrvStartBanding


DrvQueryTrueTypeOutline

DrvQueryTrueTypeOutline retrieves glyph outlines in native TrueType format.

LONG
  DrvQueryTrueTypeOutline(
    IN DHPDEV  dhpdev,
    IN FONTOBJ  *pfo,
    IN HGLYPH  hglyph,
    IN BOOL  bMetricsOnly,
    IN GLYPHDATA  *pgldt,
    IN ULONG  cjBuf,
    OUT TTPOLYGONHEADER  *ppoly
    );

Parameters

dhpdev
Specifies a handle to a PDEV returned from a call to DrvEnablePDEV.
pfo
Points to a FONTOBJ structure. Details of the font realization can be queried from this structure.
hglyph
Specifies the HGLYPH structure for which the outline is being queried.
bMetricsOnly
Specifies that font metrics (only) should be returned, or that TrueType outlines should be returned in cubic Bezier format, or that the TrueType outlines should be returned unhinted. This value can be one of the following:
Flag | Meaning
TTO_METRICS_ONLY | Only font metrics are to be returned. Font data (either outlines or bitmaps) will not be returned.
TTO_QUBICS | Outlines are to be returned in cubic Bezier format.
TTO_UNHINTED | Outlines are to be returned unhinted.

pgldt
Points to the buffer where the GLYPHDATA structure for this glyph should be written. If pgldt is null, this parameter is ignored.
cjBuf
Specifies the size, in bytes, of the buffer that will contain the TrueType outline.
ppoly
Points to the buffer where the TrueType outline should be written. The format of the data is in native TrueType format, stored in a TTPOLYGONHEADER structure. See the Platform SDK documentation for more information about the TTPOLYGONHEADER structure.

Return Value

The return value is the size, in bytes, required for the ppoly buffer if pgldt is null. If pgldt is not null, the return value is the number of bytes copied into the ppoly buffer. If an error occurs, the return value is FD_ERROR.

Headers

Declared in winddi.h. Include winddi.h.

Comments

DrvQueryTrueTypeOutline is required for TrueType font drivers.

See Also

DrvEnablePDEV, FONTOBJ


DrvQueryTrueTypeTable

DrvQueryTrueTypeTable accesses specific tables in a TrueType font-description file.

LONG
  DrvQueryTrueTypeTable(
    IN ULONG_PTR  iFile,
    IN ULONG  ulFont,
    IN ULONG  ulTag,
    IN PTRDIFF  dpStart,
    IN ULONG  cjBuf,
    OUT BYTE  *pjBuf,
    OUT PBYTE  *ppjTable,
    OUT ULONG *pcjTable
    );

Parameters

iFile
Identifies the driver-provided TrueType font file. This identifier is obtained from DrvLoadFontFile.
ulFont
Specifies the one-based index of the driver font.
ulTag
Specifies the table to access. If ulTag is zero, the driver should return access to the entire file.
dpStart
Specifies the offset from the beginning of the tables from which to begin access. If ulTag is zero, dpStart is the offset from the beginning of the file.
cjBuf
Is the size in bytes of the buffer to which pjBuf points, or zero.
pjBuf
If not NULL, points to the buffer into which the driver should copy the table or font data.
ppjTable
If not NULL, points to the location in which the driver should return the address of the table or font data.
pcjTable
If not NULL, is the location in which the driver should return the length in bytes of the table or font data to which ppjTable points.

Return Value

DrvQueryTrueTypeTable returns one of the following values:

  • If pjBuf is NULL, the number of bytes required for the buffer to hold the entire table (this would be the same as the value returned in pcjTable).
  • If pjBuf is not NULL, the number of bytes copied.
  • If an error occurs, FD_ERROR.

Headers

Declared in winddi.h. Include winddi.h.

Comments

DrvQueryTrueTypeTable must be implemented in TrueType font drivers.

There are two ways in which DrvQueryTrueTypeTable can be requested to return table or font data:

  • When cjBuf and pjBuf are not NULL, the driver should copy the contents of the requested table into the buffer to which pjBuf points. In this situation, ppjTable and pcjTable will be NULL and should be ignored by the driver.
  • When ppjTable and pcjTable are not NULL, the driver should return a pointer to and the length of the table in these parameters, respectively. In this situation, cjBuf and pjBuf will be NULL and should be ignored by the driver.

See Also

DrvLoadFontFile


DrvRealizeBrush

DrvRealizeBrush requests that the driver realize a specified brush for a specified surface.

BOOL
  DrvRealizeBrush(
    IN BRUSHOBJ  *pbo,
    IN SURFOBJ  *psoTarget,
    IN SURFOBJ  *psoPattern,
    IN SURFOBJ  *psoMask,
    IN XLATEOBJ  *pxlo,
    IN ULONG  iHatch
    );

Parameters

pbo
Points to the BRUSHOBJ that is to be realized. All other parameters, except for psoTarget, can be queried from this object. Parameter specifications are provided as an optimization. This parameter is best used only as a parameter for BRUSHOBJ_pvAllocRBrush, which allocates the memory for the realized brush.
psoTarget
Points to the surface for which the brush is to be realized. This surface can be the physical surface for the device, a device format bitmap, or a standard format bitmap.
psoPattern
Points to the surface that describes the pattern for the brush. For a raster device, this is a bitmap. For a vector device, this is one of the pattern surfaces provided by DrvEnablePDEV.
psoMask
Points to a transparency mask for the brush. This is a 1 bit per pixel bitmap that has the same extent as the pattern. A mask of zero means the pixel is considered a background pixel for the brush. (In transparent background mode, the background pixels are unaffected in a fill.) Plotters can ignore this parameter because they never draw background information.
pxlo
Points to a XLATEOBJ that defines the interpretration of colors in the pattern. If pxlo is NULL, no translation is needed. A XLATEOBJ_Xxx service routine can be called to translate the colors to device color indices. Vector devices should translate color zero through the XLATEOBJ to get the foreground color for the brush.
iHatch
Specifies whether psoPattern is one of the hatch brushes returned by DrvEnablePDEV. This is true if the value of this parameter is less than HS_DDI_MAX, which is defined in winddi.h.

Return Value

The return value is TRUE if the brush was successfully realized. Otherwise, it is FALSE, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

To realize a brush, the driver converts a GDI brush into a form that can be used internally. A realized brush contains device-specific information needed by the device to accelerate drawing using the brush.

The driver's realization of a brush is written into the buffer allocated by a call to BRUSHOBJ_pvAllocRBrush.

DrvRealizeBrush is required for a driver that does any drawing to any surface.

See Also

BRUSHOBJ, BRUSHOBJ_pvAllocRBrush, DrvEnablePDEV, XLATEOBJ


DrvResetDevice

DrvResetDevice resets a device that is inoperable or unresponsive.

ULONG DrvResetDevice(
  IN DHPDEV dhpdev,
  IN PVOID Reserved
  );

Parameters

dhpdev
Identifies the PDEV that describes the physical device that has hung. This is the value returned by DrvEnablePDEV.
Reserved
Is reserved and must be set to NULL.

Return Value

DrvResetDevice should return one of the following values:

Value | Meaning
DRD_ERROR | The device did not recover from the error.
DRD_SUCCESS | The device is currently in working order.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function is available in Windows XP and later.

DrvResetDevice is usually called in response to EngHangNotification. A driver should take any steps necessary to restore the device to working order, and should do so with no data loss or as little as possible.

See Also

DrvEnablePDEV, EngHangNotification


DrvResetPDEV

DrvResetPDEV allows a graphics driver to transfer the state of the driver from an old PDEV structure to a new PDEV structure when a Win32 application calls ResetDC.

BOOL
  DrvResetPDEV(
    DHPDEV  dhpdevOld,
    DHPDEV  dhpdevNew
    );

Parameters

dhpdevOld
Caller-supplied handle to the original device PDEV structure. This handle was previously provided by the driver as a return value for DrvEnablePDEV.
dhpdevNew
Caller-supplied handle to the new PDEV structure.

Return Value

This return value is TRUE if the function is successful. Otherwise it is FALSE, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A graphics driver's DrvResetPDEV function should be used for modifying the contents of a new PDEV structure, based on the contents of the old (currently in use) PDEV structure.

OpenGL display drivers that need to know about mode changes should implement DrvResetPDEV. Otherwise, all other display drivers typically do not need to implement this function.

The following information is relevant to printer graphics DLLs.

The function is called as a result of an application's call to the Win32 ResetDC function, which in turn causes GDI to call the driver's DrvEnablePDEV to obtain a new PDEV structure. Because the driver can modify a PDEV structure's contents during the rendering of a print job, the DrvResetPDEV function allows the driver to transfer these modifications from the old PDEV structure to the new one.

Examples of the types of information that a printer graphics DLL might want to add to the new PDEV structure are pointers to cached font files, or flags indicating whether page initialization should (or should not) take place the next time DrvStartDoc or DrvStartPage is called.

If ResetDC is called during the rendering of a print document, the printer graphics DLL receives the following sequence of calls:

    dhpdevNew = DrvEnablePDEV();
    DrvResetPDEV(dhpdevOld, dhpdevNew);
    DrvDisableSurface(dhpdevOld);
    DrvDisablePDEV(dhpdevOld);
    DrvEnableSurface(dhpdevNew);
    DrvStartDoc(dhpdevNew);

If ResetDC is called between documents there is no surface associated with the PDEV, so only the following sequence of calls is made:

    dhpdevNew = DrvEnablePDEV();
    DrvResetPDEV(dhpdevOld,dhpdevNew);
    DrvDisablePDEV(dhpdevOld);

See Also

DrvDisablePDEV, DrvDisableSurface, DrvEnablePDEV, DrvEnableSurface, DrvStartDoc


DrvSaveScreenBits

DrvSaveScreenBits causes a display driver to save or restore a given rectangle of the displayed image.

ULONG_PTR
  DrvSaveScreenBits(
    IN SURFOBJ  *pso,
    IN ULONG  iMode,
    IN ULONG_PTR  ident,
    IN RECTL  *prcl
    );

Parameters

pso
Points to a SURFOBJ structure that describes the surface.
iMode
Specifies the operation to perform. This parameter can be one of the following values:
SS_SAVE
The driver should save the data from the rectangle defined by prcl. The driver is responsible for managing this data in its off-screen memory. The ident parameter is ignored.

Upon success, DrvSaveScreenBits should return an identifier for the saved data. The driver can return a handle or even a pointer to its off-screen memory. This function returns zero if it fails.

SS_RESTORE
The driver should restore the data identified by ident to the rectangle prcl on the display; that is, the driver should restore the bitmap to its original position. The driver can assume that the rectangle at prcl is exactly the same size as the rectangle that was saved. The data should be discarded after this call.

DrvSaveScreenBits should return TRUE if the data has been restored to the display, or FALSE if the data cannot be restored.

SS_FREE
The data identified by ident is no longer needed and can be freed. The value of prcl is undefined and should not be used. The driver should not restore the saved rectangle to the display.

DrvSaveScreenBits should return TRUE.

ident
Specifies an identifier returned by a previous call to DrvSaveScreenBits if iMode is SS_RESTORE or SS_FREE. The driver should ignore this parameter when iMode is SS_SAVE.
prcl
Points to a RECTL structure that defines the portion of the screen to be saved or restored.

Return Value

The return value is dependent on the value of the iMode parameter.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Some display drivers might be able to move data to or from off-screen device memory much faster than the area can be redrawn. This might be useful when the window manager must display a menu or dialog box.

DrvSaveScreenBits is optional for display drivers.

See Also

SURFOBJ


DrvSendPage

A printer graphics DLL's DrvSendPage function is called by GDI when it has finished drawing a physical page, so the driver can send the page to the printer.

BOOL
  DrvSendPage(
    IN SURFOBJ  *pso
    );

Parameters

pso
Caller-supplied pointer to a SURFOBJ structure describing the drawing surface.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise, it should call SetLastError to set an error code, and then return FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

GDI calls DrvSendPage each time it has finished drawing a physical page's image on the drawing surface. The function is responsible for calling EngWritePrinter to send the image to the printer, and for performing end-of-page operations, such as ejecting the page.

Printer graphics DLLs using GDI-managed surfaces are typically implemented so that for pages that are banded, the image for each band is sent to the printer by the driver's DrvNextBand function. For those pages, the DrvSendPage function only needs to perform end-of-page operations.

Additionally, if a printer graphics DLL is using a device-managed surface, the DrvSendPage function typically only needs to perform end-of-page operations, because the image is sent to the printer as it is drawn.

If there is a potential for this function to take a long time to execute, it should call EngCheckAbort every five seconds. If EngCheckAbort returns TRUE, DrvSendPage should terminate its operation and return FALSE.

See Also

DrvStartPage


DrvSetPalette

DrvSetPalette requests that the driver realize the palette for a specified device.

BOOL
  DrvSetPalette(
    IN DHPDEV  dhpdev,
    IN PALOBJ  *ppalo,
    IN FLONG  fl,
    IN ULONG  iStart,
    IN ULONG  cColors
    );

Parameters

dhpdev
Identifies the device whose palette is to be realized. This parameter is the device handle returned to GDI by DrvEnablePDEV.
ppalo
Points to the PALOBJ from which the colors (RGB values) should be queried.
fl
A set of flags that provides hints and options. This parameter can be the following value:
Value | Meaning
SP_DEFAULT | The palette is the device's complete default palette. The PALOBJ can be ignored, but contains the correct contents.

iStart
Specifies the first palette index to overwrite.
cColors
Specifies the number of colors to change in the hardware palette. Extra colors, beyond the number available in the hardware, can be ignored. If cColors is smaller than the size of the hardware palette, set only cColor entries and leave the remaining colors as they are.

Return Value

The return value is TRUE if the function is successful. Otherwise, it is FALSE, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The driver sets the hardware palette to match the entries in the given palette as closely as possible.

Only indexed palettes are realizeable. The RC_PALETTE bit of the flRasterCaps member of the GDIINFO structure specifies whether a device has a realizeable palette.

DrvSetPalette is required for display drivers that support realizeable palettes.

See Also

DrvEnablePDEV, EngCreatePalette, EngDeletePalette


DrvSetPixelFormat

DrvSetPixelFormat sets the pixel format of a window.

BOOL
  DrvSetPixelFormat(
    IN SURFOBJ  *pso,
    IN LONG  iPixelFormat,
    IN HWND  hwnd
    );

Parameters

pso
Points to the SURFOBJ with which the window is associated.
iPixelFormat
Index that specifies the device format to which the pixel format is to be set. The pixel formats that a device supports are identified by positive one-based integer indices starting at 1.
hwnd
Identifies the window whose pixel format is to be set.

Return Value

The return value is TRUE if the function is successful. Otherwise, it is FALSE, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Setting the pixel format more than once can result in complications for the Window Manager and for multithreaded applications. Consequently, the pixel format of a window can be set only once and must remain unchanged.

See Also

DrvDescribePixelFormat, SURFOBJ


DrvSetPointerShape

DrvSetPointerShape is used to request the driver to take the pointer off the display, if the driver has drawn it there; to attempt to set a new pointer shape; and to put the new pointer on the display at a specified position.

ULONG
  DrvSetPointerShape(
    IN SURFOBJ  *pso,
    IN SURFOBJ  *psoMask,
    IN SURFOBJ  *psoColor,
    IN XLATEOBJ  *pxlo,
    IN LONG  xHot,
    IN LONG  yHot,
    IN LONG  x,
    IN LONG  y,
    IN RECTL  *prcl,
    IN FLONG  fl
    );

Parameters

pso
Points to a SURFOBJ structure that describes the surface on which to draw.
psoMask
Points to a SURFOBJ structure that defines the AND-XOR mask. (The AND-XOR mask is described in Drawing Monochrome Pointers.) The dimensions of this bitmap determine the size of the pointer. There are no implicit constraints on pointer sizes, but optimal pointer sizes are 32 x 32, 48 x 48, and 64 x 64 pixels. If this parameter is NULL, the pointer is transparent.
psoColor
Points to a SURFOBJ structure that defines the colors for a color pointer. If this parameter is NULL, the pointer is monochrome. The pointer bitmap has the same width as psoMask and half the height.
pxlo
Points to a XLATEOBJ structure that defines the colors in psoColor.
xHot, yHot
Specify the x and y positions of the pointer's hot spot relative to its upper-left pixel. The pixel indicated by the hot spot should be positioned at the new pointer position.
x, y
Specify the new pointer position.
prcl
Is the location in which the driver should write a rectangle that specifies a tight bound for the visible portion of the pointer.
fl
Specifies an extensible set of flags. The driver should decline the call if any flags are set that it does not understand. This parameter can be one or more of the following predefined values, and one or more driver-defined values:
Flag | Meaning
SPS_ALPHA | The pointer has per-pixel alpha values.
SPS_ANIMATESTART | The driver should be prepared to receive a series of similarly-sized pointer shapes that will comprise an animated pointer effect.
SPS_ANIMATEUPDATE | The driver should draw the next pointer shape in the animated series.
SPS_ASYNCCHANGE | This flag is obsolete. For legacy drivers, the driver should accept the change only if it is capable of changing the pointer shape in the hardware while other drawing is underway on the device. GDI uses this option only if the now obsolete GCAPS_ASYNCCHANGE flag is set in the flGraphicsCaps member of the DEVINFO structure.
SPS_CHANGE | The driver is requested to change the pointer shape.
SPS_FREQMASK | The driver is requested to render a mouse trail, updating the image as many times per millisecond as indicated in the expression fl & SPS_FREQMASK. A driver that is capable of rendering mouse trails must have the GCAPS2_MOUSETRAILS flag set in the flGraphicsCaps2 member of its DEVINFO structure.
SPS_LENGTHMASK | The driver is requested to render a mouse trail of length indicated by the expression fl & SPS_LENGTHMASK. (A mouse trail of length N is made up of N + 1 cursor images.) A driver that is capable of rendering mouse trails must have the GCAPS2_MOUSETRAILS flag set in the flGraphicsCaps2 member of its DEVINFO structure.

Return Value

The return value can be one of the following values:

Value | Meaning
SPS_ACCEPT_EXCLUDE | Is obsolete. GDI will disable the driver's pointer and revert to software simulation if the driver returns this value.
SPS_ACCEPT_NOEXCLUDE | The driver accepts the shape. The shape is supported in hardware and GDI is not concerned about other drawings overwriting the pointer.
SPS_DECLINE | The driver does not support the shape, so GDI must simulate it.
SPS_ERROR | The driver normally supports this shape, but failed for unusual reasons.

Headers

Declared in winddi.h. Include winddi.h.

Comments

DrvSetPointerShape is optional for display drivers. If this function is implemented, however, DrvMovePointer must also be implemented.

The iUniq members of the SURFOBJ structures to which psoMask and psoColor point are unique for unique pointers. The driver can use this information in conjunction with these structures' unique dhsurf handles as cache keys for cursor caching.

When SPS_ALPHA is set in fl, psoMask is NULL and psoColor points to a 32bpp BGRA surface. The per-pixel alpha value indicates the opacity of the corresponding pointer pixel with the desktop pixel underneath. The source alpha format is pre-multiplied; that is, each of the color channels of the source surface has already been pre-multiplied with the corresponding alpha value, thus eliminating a multiply operation at the time of the blend.

Default alpha cursors are largely black and white with a large range of alpha values; however, there is no color restriction since applications can specify arbitrary cursors themselves. Typical alpha pointer sizes are approximately 8 pixels larger in dimension than typical pointers without alpha. This accommodates the shadow effect, which is accomplished by a blurring filter that expands the resulting pointer bitmap shape. The vast majority of pointers will be 64x64 pixel bitmaps or smaller.

The driver indicates its ability to handle pointers with per-pixel alpha values by setting the GCAPS2_ALPHACURSOR flag in the flGraphicsCaps2 member of the DEVINFO structure returned by DrvEnablePDEV.

See Also

SURFOBJ, XLATEOBJ, DrvMovePointer


DrvStartBanding

DrvStartBanding is called by GDI when it is ready to start sending bands of a physical page to the driver for rendering.

BOOL
  DrvStartBanding(
    IN SURFOBJ  *pso,
    IN POINTL  *pptl
    );

Parameters

pso
Caller-supplied pointer to a SURFOBJ structure, which identifies the banding surface.
pptl
Caller-supplied pointer to a POINTL structure to receive the function-supplied origin of the first band.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise, it should call SetLastError to set an error code, and then return FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

If a printer graphics DLL uses GDI-managed surfaces, and if it supports surface banding, it must provide a DrvNextBand function. GDI calls DrvStartBanding only if the printer graphics DLL's DrvEnableSurface function previously called EngMarkBandingSurface to specify a banding surface.

The DrvStartBanding function's purpose is to allow the printer graphics DLL to perform any initializations needed before banding operations begin on a physical page, and to provide GDI with the indices of the first band's origin.

The DrvStartBanding function is called once per page. Each time GDI has finished drawing a band, it calls DrvNextBand so the driver can send the band to the printer.


DrvStartDoc

DrvStartDoc is called by GDI when it is ready to start sending a document to the driver for rendering.

BOOL
  DrvStartDoc(
    IN SURFOBJ  *pso,
    IN LPWSTR  pwszDocName,
    IN DWORD  dwJobId
    );

Parameters

pso
Caller-supplied pointer to a SURFOBJ structure.
pwszDocName
Caller-supplied pointer to a NULL-terminated Unicode string specifying the name of the document to be printed.
dwJobId
Caller-supplied print job number. This value is returned to GDI from the spooler in a call to StartDocPrinter.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise, it should call SetLastError to set an error code, and then return FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A printer graphics DLL must provide a DrvStartDoc function. Typically the function is used for sending control sequences to printer hardware, before a document is printed, by calling GDI's EngWritePrinter function. The function can also perform internal, document-specific initialization operations for the printer graphics DLL.

The DrvStartDoc function is called at the start of a print job, and whenever an application (such as a print processor) calls ResetDC (see DrvResetPDEV).

Because there is not a separate call into the printer graphics DLL when a print job is started, the DrvStartDoc function must also send control sequences to the printer to initialize the job, if required by the printer. (In other words, there is one document per job.)

See Also

DrvEndDoc


DrvStartPage

DrvStartPage is called by GDI when it is ready to start sending the contents of a physical page to the driver for rendering.

BOOL
  DrvStartPage(
    IN SURFOBJ  *pso
    );

Parameters

pso
Caller-supplied pointer to a SURFOBJ structure.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise, it should call SetLastError to set an error code, and then return FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A printer graphics DLL must provide a DrvStartPage function. The function is called before each physical page of a print job is rendered. (A physical page can contain one or more document pages.)

Typically the function is used for sending control sequences to printer hardware, before a page is printed, by calling GDI's EngWritePrinter function. The function can also perform internal, page-specific initialization operations for the printer graphics DLL.

See Also

DrvSendPage


DrvStretchBlt

DrvStretchBlt provides stretching bit-block transfer capabilities between any combination of device-managed and GDI-managed surfaces.

BOOL
  DrvStretchBlt(
    IN SURFOBJ  *psoDest,
    IN SURFOBJ  *psoSrc,
    IN SURFOBJ  *psoMask,
    IN CLIPOBJ  *pco,
    IN XLATEOBJ  *pxlo,
    IN COLORADJUSTMENT  *pca,
    IN POINTL  *pptlHTOrg,
    IN RECTL  *prclDest,
    IN RECTL  *prclSrc,
    IN POINTL  *pptlMask,
    IN ULONG  iMode
    );

Parameters

psoDest
Points to a SURFOBJ that identifies the surface on which to draw.
psoSrc
Points to a SURFOBJ that defines the source for the bit-block transfer operation.
psoMask
This optional parameter points to a surface that provides a mask for the source. The mask is defined by a logic map, which is a bitmap with 1 bit per pixel.

The mask limits the area of the source that is copied. If this parameter is specified, it has an implicit rop4 of 0xCCAA, meaning the source should be copied wherever the mask is one, but the destination should be left alone wherever the mask is zero.

When this parameter is null there is an implicit rop4 of 0xCCCC, which means that the source should be copied everywhere in the source rectangle.

The mask will always be large enough to contain the relevant source; tiling is unnecessary.

pco
Points to a CLIPOBJ that limits the area to be modified in the destination. GDI services are provided to enumerate the clip region as a set of rectangles.

Whenever possible, GDI simplifies the clipping involved. However, unlike DrvBitBlt, DrvStretchBlt can be called with a single clipping rectangle. This prevents rounding errors in clipping the output.

pxlo
Points to a XLATEOBJ that specifies how color indices are to be translated between the source and target surfaces. If pxlo is NULL, no translation is needed.

The XLATEOBJ can also be queried to find the RGB color for any source index. A high quality stretching bit-block transfer will need to interpolate colors in some cases.

pca
Points to a COLORADJUSTMENT structure that defines the color adjustment values to be applied to the source bitmap before stretching the bits. (See the Platform SDK documentation.)
pptlHTOrg
Specifies the origin of the halftone brush. Device drivers that use halftone brushes should align the upper left pixel of the brush's pattern with this point on the device surface.
prclDest
Points to a RECTL structure that defines the area to be modified in the coordinate system of the destination surface. This rectangle is defined by two points that are not necessarily well ordered, meaning the coordinates of the second point are not necessarily larger than those of the first point. The rectangle they describe does not include the lower and right edges. This function is never called with an empty destination rectangle.

DrvStretchBlt should interchange the two x values and/or the two y values when the destination rectangle is not well ordered.

prclSrc
Points to a RECTL that defines the area that will be copied in the coordinate system of the source surface. The rectangle is defined by two points, and will map onto the rectangle defined by prclDest. The points of the source rectangle are well ordered. This function is never given an empty source rectangle.

The mapping is defined by prclSrc and prclDest. The points specified in prclDest and prclSrc lie on integer coordinates, which correspond to pixel centers. A rectangle defined by two such points is considered to be a geometric rectangle with two vertices whose coordinates are the given points, but with 0.5 subtracted from each coordinate. (POINTL structures should be considered a shorthand notation for specifying these fractional coordinate vertices.)

The edges of any rectangle never intersect a pixel, but go around a set of pixels. The pixels inside the rectangle are those expected for a "bottom-right exclusive" rectangle. DrvStretchBlt will map the geometric source rectangle exactly onto the geometric destination rectangle.

pptlMask
Points to a POINTL structure that specifies which pixel in the given mask corresponds to the upper left pixel in the source rectangle. Ignore this parameter if no mask is specified.
iMode
Specifies how source pixels are combined to get output pixels. The HALFTONE mode is slower than the other modes, but produces higher quality images.
Value | Meaning
BLACKONWHITE | On a shrinking bit-block transfer, pixels should be combined with a Boolean AND operation. On a stretching bit-block transfer, pixels should be replicated.
COLORONCOLOR | On a shrinking bit-block transfer, enough pixels should be ignored so that pixels don't need to be combined. On a stretching bit-block transfer, pixels should be replicated.
HALFTONE | The driver can use groups of pixels in the output surface to best approximate the color or gray level of the input.
WHITEONBLACK | On a shrinking bit-block transfer, pixels should be combined with a Boolean OR operation. On a stretching bit-block transfer, pixels should be replicated.

Return Value

The return value is TRUE if the function is successful. Otherwise, it is FALSE, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

DrvStretchBlt enables the device driver to write to GDI bitmaps, especially when the driver can do halftoning. This function allows the same halftoning algorithm to be applied to GDI bitmaps and device surfaces.

This function can be provided to handle only certain forms of stretching, such as by integer multiples. If the driver has hooked the call and is asked to perform an operation it does not support, the driver should forward the data to EngStretchBlt for GDI to handle.

If the driver wants GDI to handle halftoning, and wants to ensure the proper iMode value, the driver can hook DrvStretchBlt, set iMode to HALFTONE, and call back to GDI with EngStretchBlt with the set iMode value.

DrvStretchBlt is optional for display drivers.

See Also

CLIPOBJ, DrvBitBlt, EngStretchBlt, SURFOBJ, XLATEOBJ


DrvStretchBltROP

DrvStretchBltROP performs a stretching bit-block transfer using a ROP.

BOOL
  DrvStretchBltROP(
    IN SURFOBJ  *psoDest,
    IN SURFOBJ  *psoSrc,
    IN SURFOBJ  *psoMask,
    IN CLIPOBJ  *pco,
    IN XLATEOBJ  *pxlo,
    IN COLORADJUSTMENT  *pca,
    IN POINTL  *pptlHTOrg,
    IN RECTL  *prclDest,
    IN RECTL  *prclSrc,
    IN POINTL  *pptlMask,
    IN ULONG  iMode,
    IN BRUSHOBJ  *pbo,
    IN DWORD  rop4
    );

Parameters

psoDest
Points to a SURFOBJ that describes the surface on which to draw.
psoSrc
Points to a SURFOBJ that describes the source surface for the bit-block transfer.
psoMask
Points to a SURFOBJ structure that defines a mask for the source. The mask is defined by a logic map, which is a bitmap with one bit per pixel. Typically, a mask limits the area to be modified in the destination surface. This mask is always the same size as the source surface.
pco
Points to a CLIPOBJ that limits the area to be modified in the destination. The CLIPOBJ_Xxx service routines are provided to enumerate the clip region as a set of rectangles.

Whenever possible, GDI simplifies the clipping involved. However, unlike DrvBitBlt, DrvStretchBltROP can be called with a single clipping rectangle. This prevents rounding errors in clipping the output.

pxlo
Points to a XLATEOBJ that specifies how color indices are to be translated between the source and target surfaces. If pxlo is NULL, no translation is needed.

This XLATEOBJ structure can also be queried to find the RGB color for any source index. A high quality stretching bit-block transfer will need to interpolate colors in some cases.

pca
Points to a COLORADJUSTMENT structure that defines the color adjustment values to be applied to the source bitmap before stretching the bits. For more information see the Platform SDK documentation.
pptlHTOrg
Points to a POINTL structure that defines the origin of the halftone brush on the destination surface. When using halftone brushes, the driver should align the upper-left pixel of the brush with this point and repeat the brush according to its dimensions. The driver should ignore this parameter if the rop4 parameter does not require a pattern.
prclDest
Points to a RECTL structure that defines the rectangular area to be modified. This rectangle is specified in the coordinate system of the destination surface and is defined by two points: upper left and lower right. The two points that define the rectangle are not always well ordered, meaning the coordinates of the second point are not necessarily larger than those of the first point. The driver should interchange the two x values and/or the two y values if the destination rectangle is not well ordered.

The rectangle is lower-right exclusive; that is, it lower and right edges are not a part of the copy.

DrvStretchBltROP is never called with an empty destination rectangle.

prclSrc
Points to a RECTL structure that defines the area to be copied. This rectangle is specified in the coordinate system of the source surface and is defined by two points: upper left and lower right. The two points that define the rectangle are always well ordered.

The rectangle is lower-right exclusive; that is, its lower and right edges are not a part of the copy.

The driver should map this rectangle to the rectangle defined by prclDest.

pptlMask
Points to a POINTL structure that defines a pixel in the mask to which prclMask points. This pixel corresponds with the upper-left pixel in the source rectangle to which prclSrc points. The driver should ignore this parameter if no mask is specified.
iMode
Specifies how source pixels are combined to get output pixels. The HALFTONE mode is slower than the other modes, but produces higher quality images. This parameter can be one of the following values:
Value | Meaning
BLACKONWHITE | On a shrinking bit-block transfer, pixels should be combined with a Boolean AND operation. On a stretching bit-block transfer, pixels should be replicated.
COLORONCOLOR | On a shrinking bit-block transfer, enough pixels should be ignored so pixels need not be combined. On a stretching bit-block transfer, pixels should be replicated.
HALFTONE | The driver can use groups of pixels in the output surface to best approximate the color or gray level of the input.
WHITEONBLACK | On a shrinking bit-block transfer, pixels should be combined with a Boolean OR operation. On a stretching bit-block transfer, pixels should be replicated.

pbo
Points to the BRUSHOBJ structure to be used to define the pattern for the bit-block transfer. GDI's BRUSHOBJ_pvGetRbrush service routine retrieves the device's realization of the brush. The driver can ignore this parameter if the rop4 parameter does not require a pattern.
rop4
Represents a raster operation that defines how the mask, pattern, source, and destination pixels are combined to write an output pixel to the destination surface.

This is a quaternary raster operation, which is a natural extension of the usual ternary Rop3 operation. A Rop4 has 16 relevant bits, which are similar to the 8 defining bits of a Rop3. (The other redundant bits of the Rop3 are ignored.) The simplest way to implement a Rop4 is to consider its 2 bytes separately. The lower byte specifies a Rop3 that should be computed wherever the mask to which psoMask points is 1. The high byte specifies a Rop3 that can be computed and applied wherever the mask is zero.

Return Value

DrvStretchBltROP should return TRUE upon success. Otherwise, it should report an error code and return FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The mapping is defined by prclSrc and prclDest. The points specified in prclDest and prclSrc lie on integer coordinates, which correspond to pixel centers. A rectangle defined by two such points is considered to be a geometric rectangle with two vertices whose coordinates are the given points, but with 0.5 subtracted from each coordinate. (POINTL structures are shorthand notation for specifying these fractional coordinate vertices.)

The driver can optionally implement DrvStretchBltROP. If the driver does hook this call, it can call EngStretchBltROP to perform those stretching blit operations that it does not support.

See Also

DrvAlphaBlend, DrvBitBlt, DrvPlgBlt, DrvStretchBlt, DrvTransparentBlt, EngAlphaBlend, EngBitBlt, EngPlgBlt, EngStretchBlt, EngStretchBltROP, EngTransparentBlt


DrvStrokeAndFillPath

DrvStrokeAndFillPath strokes and fills a path concurrently.

BOOL
  DrvStrokeAndFillPath(
    IN SURFOBJ  *pso,
    IN PATHOBJ  *ppo,
    IN CLIPOBJ  *pco,
    IN XFORMOBJ  *pxo,
    IN BRUSHOBJ  *pboStroke,
    IN LINEATTRS  *plineattrs,
    IN BRUSHOBJ  *pboFill,
    IN POINTL  *pptlBrushOrg,
    IN MIX  mixFill,
    IN FLONG  flOptions
    );

Parameters

pso
Points to a SURFOBJ structure that describes the surface on which to draw.
ppo
Points to a PATHOBJ structure that describes the path to be filled. The PATHOBJ_Xxx service routines are provided to enumerate the lines, Bezier curves, and other data that make up the path.
pco
Points to a CLIPOBJ structure. The CLIPOBJ_Xxx service routines are provided to enumerate the clip region as a set of rectangles.
pxo
Points to a XFORMOBJ structure that is required when a geometric wide line is drawn. It specifies the transform that takes world coordinates to device coordinates. This is needed because the path is provided in device coordinates but a geometric wide line is actually widened in world coordinates. The XFORMOBJ can be queried to find out what the transform is.
pboStroke
Specifies the brush to use when stroking the path.
plineattrs
Points to the LINEATTRS structure that describes the attributes of the line to be drawn.
pboFill
Specifies the brush to use when filling the path.
pptlBrushOrg
Specifies the brush origin for both brushes.
mixFill
Specifies a MIX structure (defined in the Platform SDK documentation) that defines the foreground and background raster operations to use for the brush.
flOptions
Specifies either FP_WINDINGMODE, meaning that a winding mode fill should be performed, or FP_ALTERNATEMODE, meaning that an alternating mode fill should be performed. All other flags should be ignored. For more information on these modes, see Path Fill Modes.

Return Value

The return value is TRUE if the driver can fill the path. Otherwise, if GDI should fill the path, the return value is FALSE. If an error occurs, the return value is DDI_ERROR, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

If a wide line is used for stroking, the filled area must be reduced to compensate.

The driver can return FALSE if the path or the clipping is too complex for the device to handle; in that case, GDI converts to a simpler call. For example, if the device driver has set the GCAPS_BEZIERS flag in the flGraphicsCaps member of the DEVINFO structure and then receives a path with Bezier curves, it can return FALSE; GDI will then convert the Bezier curves to lines and call DrvStrokeAndFillPath again. If the device driver returns FALSE again, GDI will further simplify the call, making calls to DrvStrokePath and DrvFillPath, or to DrvBitBlt, depending on the mix and width of the lines making up the path.

The mix mode defines how the incoming pattern should be mixed with the data already on the device surface. The MIX data type consists of two ROP2 values packed into a single ULONG. The low-order byte defines the foreground raster operation; the high-order byte defines the background raster operation. For more information about raster operation codes, see the Platform SDK documentation.

See Also

CLIPOBJ, DrvFillPath, DrvStrokePath, LINEATTRS, PATHOBJ, SURFOBJ, XFORMOBJ


DrvStrokePath

DrvStrokePath strokes a path when called by GDI.

BOOL
  DrvStrokePath(
    IN SURFOBJ  *pso,
    IN PATHOBJ  *ppo,
    IN CLIPOBJ  *pco,
    IN XFORMOBJ  *pxo,
    IN BRUSHOBJ  *pbo,
    IN POINTL  *pptlBrushOrg,
    IN LINEATTRS  *plineattrs,
    IN MIX  mix
    );

Parameters

pso
Identifies the surface on which to draw.
ppo
Points to a PATHOBJ structure. GDI PATHOBJ_Xxx service routines are provided to enumerate the lines, Bezier curves, and other data that make up the path. This indicates what is to be drawn.
pco
Points to a CLIPOBJ structure. GDI CLIPOBJ_Xxx service routines are provided to enumerate the clip region as a set of rectangles. Optionally, all the lines in the path may be enumerated preclipped by CLIPOBJ. This means that drivers can have all their line clipping calculations done for them.
pxo
Points to a XFORMOBJ structure. This is needed only when a geometric wide line is to be drawn. It specifies the transform that maps world coordinates to device coordinates. This is needed because the path is provided in device coordinates but a geometric wide line is actually widened in world coordinates.

The XFORMOBJ structure can be queried to find the transform.

pbo
Specifies the brush to be used when drawing the path.
pptlBrushOrg
Points to the brush origin used to align the brush pattern on the device.
plineattrs
Points to a LINEATTRS structure. Note that the elStyleState member of this structure must be updated as part of this function if the line is styled. Also note that the ptlLastPel member must be updated if a single pixel width cosmetic line is being drawn.
mix
Specifies a MIX structure (defined in the Platform SDK documentation) that defines the foreground and background raster operations to use for the brush.

Return Value

The return value is TRUE if the driver is able to stroke the path. If GDI should stroke the path, the return value is FALSE, and an error code is not logged. If the driver encounters an error, the return value is DDI_ERROR, and an error code is reported.

Headers

Declared in winddi.h. Include winddi.h.

Comments

If the driver has hooked the function, and if the appropriate GCAPS are set, GDI calls DrvStrokePath when GDI draws a line or curve with any set of attributes.

If a driver supports this entry point, it should also support the drawing of cosmetic wide lines with arbitrary clipping. Using the provided GDI functions, the call can be broken down into a set of single-pixel-width lines with precomputed clipping.

This function is required if any drawing is to be done on a device-managed surface.

Drivers for advanced devices can optionally receive this call to draw paths containing Bezier curves and geometric wide lines. GDI will test the GCAPS_BEZIERS and GCAPS_GEOMETRICWIDE flags of the flGraphicsCaps member of the DEVINFO structure to decide whether it should call this function. (The four combinations of the bits determine the four levels of functionality for this call.) If the driver gets an advanced call containing Bezier curves or geometric wide lines, it can decide not to handle the call, returning FALSE. This might happen if the path or clipping is too complex for the device to process. If the call does return FALSE, GDI breaks the call down into simpler calls that can be handled more easily.

For device-managed surfaces, the function must minimally support single-pixel-wide solid and styled cosmetic lines using a solid-colored brush.

The mix mode defines how the incoming pattern should be mixed with the data already on the device surface. The MIX data type consists of two ROP2 values packed into a single ULONG. The low-order byte defines the foreground raster operation; the high-order byte defines the background raster operation. For more information about raster operation codes, see the Platform SDK documentation.

See Also

CLIPOBJ, DEVINFO, DrvFillPath, LINEATTRS, PATHOBJ, XFORMOBJ


DrvSwapBuffers

DrvSwapBuffers displays the contents of the window's associated hidden buffer on the specified surface.

BOOL
  DrvSwapBuffers(
    IN SURFOBJ  *pso,
    IN WNDOBJ  *pwo
    );

Parameters

pso
Points to the target surface that will be modified for display.
pwo
Points to the window object that defines the region on the target surface with which the back buffer will be swapped.

Return Value

The return value is TRUE if the function is successful; it is FALSE upon failure.

Headers

Declared in winddi.h. Include winddi.h.

Comments

DrvSwapBuffers can affect the display only if the pixel format for the window specified by pwo is double-buffered. The content of the hidden buffer is undefined after the swap occurs.

This function is required if the driver supports a pixel format with double buffering; that is, if PFD_DOUBLEBUFFER is set in the dwFlags member of the PIXELFORMATDESCRIPTOR structure.

See Also

DrvDescribePixelFormat


DrvSynchronize

DrvSynchronize informs the driver that GDI needs to access a device-managed surface. This function allows asychronous drawing operations performed by a device's coprocessor to be coordinated with GDI accesses.

VOID
  DrvSynchronize(
    IN DHPDEV  dhpdev,
    IN RECTL  *prcl
    );

Parameters

dhpdev
Identifies the device to be synchronized with GDI. This parameter is the device handle returned to GDI by DrvEnablePDEV.
prcl
Should be ignored by the driver.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function allows asynchronous drawing operations performed by a device's coprocessor to be coordinated with GDI accesses.

DrvSynchronize can be optionally implemented in display drivers. GDI calls this function only if it is hooked by EngAssociateSurface. GDI calls DrvSynchronize just before drawing directly onto the device surface. GDI will call DrvSynchronizeSurface instead of DrvSynchronize in drivers that implement both of these functions.

This function should return only when it is safe for GDI to access any device-managed surface. That is, DrvSynchronize should delay returning from the call until all asynchronous drawing operations have been completed by the device's co-processor, thus indicating that it is safe for GDI to access any device-managed surface.

DrvSynchronize is intended to support devices that use a coprocessor for drawing. Such a device can treat some drawing operations as asychronous, returning to GDI from the operation before the drawing is complete. If this is the case, it is possible that a subsequent drawing operation will be handled by GDI. In order for GDI to safely access device-managed surfaces, it must have a means of ensuring that any asynchronous rendering being done by the device's co-processor is complete. By calling this function, GDI synchronizes access to a device-managed surface with the driver.

GDI will never call DrvSynchronize for device-managed surfaces. DrvSynchronize is not itself an output function.

See Also

DrvEnablePDEV, DrvSynchronizeSurface


DrvSynchronizeSurface

DrvSynchronizeSurface informs the driver that GDI needs to write to the specified surface. This function allows drawing operations performed by a device's coprocessor to be coordinated with GDI.

VOID
  DrvSynchronizeSurface(
    IN SURFOBJ  *pso,
    IN RECTL  *prcl,
    IN FLONG  fl
    );

Parameters

pso
Points to a SURFOBJ that identifies the surface on which the drawing synchronization is to occur.
prcl
Specifies a rectangle on the surface that GDI will draw into, or NULL. If this does not collide with the drawing operation in progress, the driver can elect to let GDI draw without waiting for the coprocessor to complete.
fl
Is a flag that specifies the event for which GDI is making the synchronization request. This parameter can be one of the following values:
DSS_TIMER_EVENT
GDI is calling this function due to a synchronization timer event. Timer events are generated for only those drivers that specify the GCAPS2_SYNCTIMER bit of the DEVINFO structure.
DSS_FLUSH_EVENT
GDI is calling this function due to a synchronization flush event. These flush events are generated for only those drivers that specify the GCAPS2_SYNCFLUSH bit of the DEVINFO structure.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function allows drawing operations performed by a device's coprocessor to be coordinated with GDI.

DrvSynchronizeSurface can be optionally implemented in display drivers. GDI calls this function only if it is hooked by EngAssociateSurface. GDI calls DrvSynchronizeSurface just before drawing directly onto the device surface.

DrvSynchronizeSurface is intended to support devices that use a coprocessor for drawing. Such a device can start a long drawing operation and return to GDI while the operation continues. If the device driver does not perform all drawing operations to the surface, it is possible that a subsequent drawing operation will be handled by GDI. In this case, it is necessary for GDI to wait for the coprocessor to complete its work before drawing on the surface.

This function should return when it is safe for GDI to draw on the surface within the rectangular region specified by prcl.

DrvSynchronizeSurface is not itself an output function.

See Also

DrvEnablePDEV, DrvSynchronize


DrvTextOut

DrvTextOut is the entry point from GDI that calls for the driver to render a set of glyphs at specified positions.

BOOL
  DrvTextOut(
    IN SURFOBJ  *pso,
    IN STROBJ  *pstro,
    IN FONTOBJ  *pfo,
    IN CLIPOBJ  *pco,
    IN RECTL  *prclExtra,
    IN RECTL  *prclOpaque,
    IN BRUSHOBJ  *pboFore,
    IN BRUSHOBJ  *pboOpaque,
    IN POINTL  *pptlOrg,
    IN MIX  mix
    );

Parameters

pso
Points to a SURFOBJ structure that describes the surface on which to write.
pstro
Points to a STROBJ structure that defines the glyphs to be rendered and the positions in which to place them.
pfo
Points to a FONTOBJ structure from which to retrieve information about the font and its glyphs.
pco
Points to a CLIPOBJ structure that defines the clip region through which all rendering must be done. The driver cannot affect any pixels outside the clip region.
prclExtra
Is NULL and should be ignored by the driver.
prclOpaque
Points to a single opaque rectangle. This rectangle is bottom-right exclusive. Pixels within this rectangle (those that are not foreground and not clipped) are to be rendered with the opaque brush. This rectangle always bounds the text to be drawn. If this parameter is null, no opaque pixels are to be rendered.
pboFore
Points to the brush object to be used for the foreground pixels. This brush will always be a solid color brush.
pboOpaque
Points to the brush object for the opaque pixels. Both the foreground and background mix modes for this brush are assumed to be R2_COPYPEN. Unless the driver sets the GCAPS_ARBRUSHOPAQUE capabilities bit in the flGraphicsCaps member of the DEVINFO structure, it will always be called with a solid color brush.
pptlOrg
Points to a POINTL structure that defines the brush origin for both brushes.
mix
Specifies foreground and background raster operations (mix modes) for pboFore. The driver will only be called with both mix modes equal to COPYPEN unless it sets the GCAPS_ARBMIXTXT capabilities bit in the flGraphicsCaps member of the DEVINFO structure.

Return Value

The return value is TRUE if the function is successful; otherwise, it is FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The input parameters to DrvTextOut define two sets of pixels: foreground and opaque. The driver must render the surface so that the result is identical to a process where the opaque pixels are rendered first with the opaque brush, and then the foreground pixels are rendered with the foreground brush. Each of these operations is limited by clipping.

The foreground and opaque pixels are regarded as a screen through which color is brushed onto the surface. The glyphs of the font do not have color in themselves.

The input parameters to DrvTextOut define the set of glyph pixels, the set of extra rectangles, the opaque rectangle, and the clip region. It is the driver's responsibility to calculate and then render the set of foreground and opaque pixels.

GDI guarantees that DrvTextOut and DrvDestroyFont never overlap; consequently, the driver can rely on cached information while processing a DrvTextOut call.

The mix mode defines how the incoming pattern should be mixed with the data already on the device surface. The MIX data type consists of two ROP2 values packed into a single ULONG. The low-order byte defines the foreground raster operation; the next byte defines the background raster operation. For more information about raster operation codes, see the Platform SDK documentation.

This is a required function.

See Also

CLIPOBJ, DEVINFO, FONTOBJ, STROBJ, SURFOBJ


DrvTransparentBlt

DrvTransparentBlt provides bit-block transfer capabilities with transparency.

BOOL
  DrvTransparentBlt(
    IN SURFOBJ  *psoDst,
    IN SURFOBJ  *psoSrc,
    IN CLIPOBJ  *pco,
    IN XLATEOBJ  *pxlo,
    IN RECTL  *prclDst,
    IN RECTL  *prclSrc,
    IN ULONG  iTransColor,
    IN ULONG  ulReserved
    );

Parameters

psoDst
Points to the SURFOBJ that identifies the target surface on which to draw.
psoSrc
Points to the SURFOBJ that identifies the source surface of the bit-block transfer.
pco
Points to a CLIPOBJ structure. The CLIPOBJ_Xxx service routines are provided to enumerate the clip region as a set of rectangles. This enumeration limits the area of the destination that is modified. Whenever possible, GDI simplifies the clipping involved.
pxlo
Points to a XLATEOBJ structure that tells how the source color indices should be translated for writing to the target surface. If pxlo is NULL, no translation is needed.
prclDst
Points to a RECTL structure that defines the rectangular area to be modified. This rectangle is specified in the coordinate system of the destination surface and is defined by two points: upper left and lower right. The rectangle is lower-right exclusive; that is, its lower and right edges are not a part of the bit-block transfer. The two points that define the rectangle are always well ordered.

DrvTransparentBlt is never called with an empty destination rectangle.

prclSrc
Points to a RECTL structure that defines the rectangular area to be copied. This rectangle is specified in the coordinate system of the source surface and is defined by two points: upper left and lower right. The two points that define the rectangle are always well ordered.

The source rectangle will never exceed the bounds of the source surface, and so will never overhang the source surface.

This rectangle is mapped to the destination rectangle defined by prclDst. DrvTransparentBlt is never called with an empty source rectangle.

iTransColor
Specifies the transparent color in the source surface format. It is a color index value that has been translated to the source surface's palette.
ulReserved
Reserved; this parameter must be set to zero.

Return Value

DrvTransparentBlt returns TRUE upon success. Otherwise, it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Bit-block transfer with transparency is supported between two device-managed surfaces or between a device-managed surface and a GDI-managed standard format bitmap. Driver writers are encouraged to support the case of blting from off-screen device bitmaps in video memory to other surfaces in video memory; all other cases can be punted to EngTransparentBlt with little performance penalty. The driver can punt calls involving device-managed surfaces to EngTransparentBlt.

The pixels on the source surface that match the transparent color specified by iTransColor are not copied.

The driver will never be called with overlapping source and destination rectangles on the same surface.

The driver should ignore any unused bits in the color key comparison, such as for the most significant bit when the bitmap format is a 5-5-5 16bpp.

The driver hooks DrvTransparentBlt by setting the HOOK_TRANSPARENTBLT flag when it calls EngAssociateSurface. If the driver has hooked DrvTransparentBlt and is called to perform an operation that it does not support, the driver should have GDI handle the operation by forwarding the data in a call to EngTransparentBlt.

See Also

DrvBitBlt, DrvPlgBlt, DrvStretchBlt, DrvStretchBltROP, EngAssociateSurface, EngBitBlt, EngPlgBlt, EngStretchBlt, EngStretchBltROP, EngTransparentBlt


DrvUnloadFontFile

DrvUnloadFontFile informs a font driver that the specified font file is no longer needed.

BOOL
  DrvUnloadFontFile(
    IN ULONG_PTR  iFile
    );

Parameters

iFile
Identifies the font file to be removed. The iFile parameter is a value returned by DrvLoadFontFile.

Return Value

The return value is TRUE if the function is successful.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The driver should delete all scratch files, unload all DLLs that were loaded, and free all allocated system resources at this time.

This function is required for font drivers.


WNDOBJCHANGEPROC

WNDOBJCHANGEPROC is a driver-defined callback function that GDI uses to notify the driver of changes to the window in question.

VOID
  (CALLBACK * WNDOBJCHANGEPROC) (
    WNDOBJ  *pwo,
    FLONG  fl
    );

Parameters

pwo
Points to a WNDOBJ structure defining the window object that is currently changing. The window object contains the new size and position of the window. If fl is WOC_CHANGED, this parameter is NULL.
fl
Is a flag that describes the change occuring to the window object. This parameter can be one of the following values:
WOC_RGN_CLIENT_DELTA
The WNDOBJ contains a delta client region. The delta region is valid for this call only.
WOC_RGN_CLIENT
The WNDOBJ contains a new client region.
WOC_RGN_SURFACE_DELTA
The WNDOBJ contains a delta surface region. The pvConsumer member of the WNDOBJ structure is zero. The delta region is valid for this call only.
WOC_RGN_SURFACE
The WNDOBJ refers to a surface region created by GDI. The pvConsumer member of the WNDOBJ structure is zero.
WOC_CHANGED
All windows have been updated. GDI always notifies the driver at the end of a desktop update.
WOC_DELETE
The WNDOBJ is being deleted as a result of the deletion of the window.
WOC_DRAWN
The windows subsystem has completed the screen-to-screen blit calls (screen-to-screen DrvCopyBits) necessary to update the screen contents to correspond with the window region changes.
WOC_SPRITE_OVERLAP
A sprite overlaps with the WNDOBJ area. This parameter is used when a sprite is first moved on top of the WNDOBJ area or immediately after the WNDOBJ is created if it overlaps with a pre-existing sprite.
WOC_SPRITE_NO_OVERLAP
Sprites no longer overlap the WNDOBJ area. This parameter is used when all sprites have been moved off the WNDOBJ area, and will be used only if the callback was previously called with WOC_SPRITE_OVERLAP.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The pfn parameter of the EngCreateWnd function points to this function.

See Also

EngCreateWnd, WNDOBJ


GDI Functions for Graphics Drivers

This section provides reference information for system-supplied GDI functions that can be called by both display and printer drivers. This includes the following function groups:

  • Eng Xxx functions. These are general graphics engine services.
  • XXXOBJ_Xxx functions. These specialized service routines are related to a particular object.

GDI Support for Graphics Drivers lists the include files that contain declarations for the graphics driver functions described in this section.

Reference material for functions that are implemented by display and/or printer driver writers can be found in Graphics Driver Functions (DDI).


BRUSHOBJ_hGetColorTransform

BRUSHOBJ_hGetColorTransform retrieves the color transform for the specified brush.

HANDLE
  BRUSHOBJ_hGetColorTransform(
    IN BRUSHOBJ  *pbo
    );

Parameters

pbo
Points to the BRUSHOBJ structure whose color transform is being queried. The color transform was created in a prior call to DrvIcmCreateColorTransform.

Return Value

BRUSHOBJ_hGetColorTransform returns a handle to the color transform for the specified BRUSHOBJ structure upon success. Otherwise, it returns NULL.

Headers

Declared in winddi.h. Include winddi.h.

Comments

BRUSHOBJ_hGetColorTransform returns NULL when ICM is disabled.

The color transform for a translation object is obtained by calling XLATEOBJ_hGetColorTransform.

See Also

BRUSHOBJ, DrvIcmCreateColorTransform, XLATEOBJ_hGetColorTransform


BRUSHOBJ_pvAllocRbrush

BRUSHOBJ_pvAllocRbrush allocates memory for the driver's realization of a specified brush.

PVOID
  BRUSHOBJ_pvAllocRbrush(
    IN BRUSHOBJ  *pbo,
    IN ULONG  cj
    );

Parameters

pbo
Points to the BRUSHOBJ structure for which the realization is to be allocated.
cj
Specifies the size, in bytes, required for the realization.

Return Value

The return value is a pointer to the allocated memory if the function is successful. Otherwise, it is null, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

BRUSHOBJ_pvAllocRbrush allocates memory for the brush realization. GDI manages the memory and discards it when the brush is no longer needed.

This function should be called only by an implementation of a brush realization following a call to DrvRealizeBrush.

See Also

BRUSHOBJ, DrvRealizeBrush


BRUSHOBJ_pvGetRbrush

BRUSHOBJ_pvGetRbrush retrieves a pointer to the driver's realization of a specified brush.

PVOID
  BRUSHOBJ_pvGetRbrush(
      IN BRUSHOBJ  *pbo
    );

Parameters

pbo
Points to the BRUSHOBJ structure whose realization is requested.

Return Value

The return value is a pointer to the realized brush if the function is successful. If the brush cannot be realized, the return value is null and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

BRUSHOBJ_pvGetRbrush is called when the brush is a pattern brush that has not yet been realized; that is, it is called when the iSolidColor member of the BRUSHOBJ structure is 0xFFFFFFFF and the pvRbrush member is null.

If the brush has not been realized when BRUSHOBJ_pvGetRbrush is called, GDI calls the driver-supplied DrvRealizeBrush function to obtain the driver's realization of the brush. As an acceleration, GDI caches this realization in the pvRbrush member of the BRUSHOBJ structure. Then, when an application reuses this brush for another drawing operation, the driver doesn't have to call BRUSHOBJ_pvGetRbrush again.

See Also

BRUSHOBJ, BRUSHOBJ_pvAllocRbrush, DrvRealizeBrush


BRUSHOBJ_ulGetBrushColor

BRUSHOBJ_ulGetBrushColor returns the RGB color of the specified solid brush.

ULONG
 BRUSHOBJ_ulGetBrushColor(
    IN BRUSHOBJ  *pbo
    );

Parameters

pbo
Points to the BRUSHOBJ structure whose color is being queried.

Return Value

BRUSHOBJ_ulGetBrushColor returns the RGB color of a solid brush. If the specified brush is not solid, this function returns -1.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The color stored in the iSolidColor member of the BRUSHOBJ structure is an index value that has been translated to the target surface's palette. BRUSHOBJ_ulGetBrushColor allows the driver to query the original RGB color value of iSolidColor.

See Also

BRUSHOBJ


CLIPOBJ_bEnum

CLIPOBJ_bEnum enumerates a batch of rectangles from a specified clip region; a prior call to CLIPOBJ_cEnumStart determines the order of enumeration.

BOOL
  CLIPOBJ_bEnum(
    IN CLIPOBJ  *pco,
    IN ULONG  cj,
    OUT ULONG  *pv
    );

Parameters

pco
Points to a CLIPOBJ structure describing the clip region that is to be enumerated.
cj
Specifies the size, in bytes, of the buffer pointed to by pv.
pv
Points to the buffer that will receive data about the clip region in an ENUMRECTS structure.

Return Value

The return value is TRUE if the driver must call this function again for more enumeration data, or FALSE if the enumeration is complete. It is possible for CLIPOBJ_bEnum to return TRUE with the number of clipping rectangles equal to zero. In such cases, the driver should call CLIPOBJ_bEnum again without taking any action.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A possible loop structure for calling this function follows:

do {
    bMore = CLIPOBJ_bEnum(pco, sizeof(buffer), &buffer.c);
    for (i = 0; i < buffer.c; i++) {
        .
        .
        .
    }
} while (bMore);

The count of objects written to the buffer is written to the buffer itself.

See Also

CLIPOBJ, CLIPOBJ_cEnumStart, ENUMRECTS


CLIPOBJ_cEnumStart

CLIPOBJ_cEnumStart sets parameters for enumerating rectangles in a specified clip region.

ULONG
  CLIPOBJ_cEnumStart(
    IN CLIPOBJ  *pco,
    IN BOOL  bAll,
    IN ULONG  iType,
    IN ULONG  iDirection,
    IN ULONG  cLimit
    );

Parameters

pco
Points to the CLIPOBJ structure that defines the clip region to be enumerated.
bAll
Specifies whether the entire region should be enumerated. This parameter is TRUE if the whole region should be enumerated. It is FALSE if only the parts relevant to the present drawing operation should be enumerated.

A driver that caches clip regions must enumerate the entire region.

iType
Specifies the data structures that are to be written by CLIPOBJ_bEnum. This parameter currently must be CT_RECTANGLES, indicating that the region is to be enumerated as a list of rectangles.
iDirection
Determines the order in which the rectangles are to be enumerated. This order can be essential if a DrvBitBlt operation is executing concurrently on the same surface. If the order is not relevant to the device driver, CD_ANY should be specified for complex regions, allowing GDI to optimize the enumeration. This value can be one of the following:
Value | Meaning
CD_ANY | Any order convenient for GDI.
CD_LEFTDOWN | Right to left, top to bottom.
CD_LEFTUP | Right to left, bottom to top.
CD_RIGHTDOWN | Left to right, top to bottom.
CD_RIGHTUP | Left to right, bottom to top.

cLimit
Specifies the maximum number of rectangles to be enumerated. If this parameter is zero, counting is omitted.

Return Value

The return value is the count of enumerated rectangles. If the count exceeds cLimit, the return value is 0xFFFFFFFF.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A region can be enumerated whether or not this function is called. By default, the driver only enumerates relevant rectangles, starting at the upper left.

The driver can restart enumeration by calling this function again.

See Also

CLIPOBJ, CLIPOBJ_bEnum, DrvBitBlt


CLIPOBJ_ppoGetPath

CLIPOBJ_ppoGetPath creates a PATHOBJ structure that contains the outline of the specified clip region.

PATHOBJ
  *CLIPOBJ_ppoGetPath(
    IN CLIPOBJ  *pco
    );

Parameters

pco
Pointer to a CLIPOBJ structure that defines the specified clip region.

Return Value

The return value is a pointer to a PATHOBJ structure if the function is successful. Otherwise, it is null, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The returned PATHOBJ structure should be deleted using EngDeletePath when the driver no longer needs it.

A driver for a device that can download a clipping path might prefer this function for defining complex regions.

See Also

CLIPOBJ, EngDeletePath, PATHOBJ


EngAcquireSemaphore

EngAcquireSemaphore acquires the resource associated with the semaphore for exclusive access by the calling thread.

VOID
  EngAcquireSemaphore(
    IN HSEMAPHORE  hsem
    );

Parameters

hsem
Handle to the semaphore associated with the resource to be acquired.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

EngAcquireSemaphore allows exclusive access to the driver resource associated with the semaphore by locking out all other threads from accessing the semaphore's resource.

A call to this routine should be followed with a call to EngReleaseSemaphore as quickly as possible.

See Also

EngCreateSemaphore, EngDeleteSemaphore, EngIsSemaphoreOwned, EngIsSemaphoreOwnedByCurrentThread, EngReleaseSemaphore


EngAllocMem

EngAllocMem allocates a block of memory from the system's paged pool, and inserts a caller-supplied tag before the allocation.

PVOID
  EngAllocMem(
    IN ULONG  Flags,
    IN ULONG  MemSize,
    IN ULONG  Tag
    );

Parameters

Flags
Specifies how to allocate memory. The FL_ZERO_MEMORY flag requests that the allocated memory's contents be zero-initialized; if this flag is not set, the memory is returned uninitialized.
MemSize
Specifies the number of bytes to allocate.
Tag
Specifies a four-byte allocation tag that uniquely identifies the driver doing the memory allocation.

Return Value

EngAllocMem returns a pointer to the allocated memory if the system has enough memory to satisfy the request; otherwise, it returns a null pointer.

Headers

Declared in winddi.h. Include winddi.h.

Comments

When the memory is no longer needed, it should be freed by a call to the EngFreeMem function. The Tag string should be specified in byte-reversed order. It is recommended that the first letter in the string (before it is reversed) be 'D' to denote a display driver; the other three bytes should be indicative of the driver name. For example, the tag string 'zyxD' appears as 'Dxyz' if pool is dumped. The tag appears in any crash dump of the system that occurs.

See Also

EngFreeMem


EngAllocPrivateUserMem

EngAllocPrivateUserMem allocates a block of private user memory from the address space of a specified process, and inserts a caller-supplied tag before the allocation.

PVOID
  EngAllocPrivateUserMem(
    IN PDD_SURFACE_LOCAL  psl,
    IN SIZE_T  cj,
    IN ULONG  tag
    );

Parameters

psl
Points to the DD_SURFACE_LOCAL structure representing the DirectDraw surface with which to associate the allocated memory.
cj
Specifies the number of bytes of memory to allocate.
tag
Specifies a four-byte allocation tag that uniquely identifies the driver doing the memory allocation.

Return Value

EngAllocPrivateUserMem returns a pointer to the allocated memory if there is enough user-mode memory to satisfy the request; otherwise, it returns a null pointer.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A DirectDraw driver may require a user-memory "scratch pad" in place of true video memory. Although this practice is discouraged due to its performance implications, it is occasionally necessary. This scratch memory is usually allocated only for a short period of time. Once the memory has been allocated, it is used for the intended graphics operations, and then deallocated.

A problem arises if the driver instance is destroyed before the surface is unlocked. A particular case occurs when the system switches to a protected desktop as a result of a user pressing CTRL+ALT+DEL. In this situation, the mode switch is performed on a system process context. If the driver has any outstanding surface locks, such as when the mode switch happens before the surface has been unlocked, the driver will be required to destroy that surface on a different process context. The driver cannot call EngFreeUserMem to deallocate the scratch area since this entry point will fail if called on a different context from that used when the memory was allocated.

EngAllocPrivateUserMem, and EngFreePrivateUserMem are provided to address this problem. These two functions are identical to EngAllocUserMem and EngFreeUserMem, except that they do the extra work required to free memory allocated on a different process context. Process context information is stored with the DirectDraw object that owns the DirectDraw surface object to which psl points.

The tag string should be specified in byte-reversed order. The reason for this is that if a crash dump of the system occurs, the contents of the tag string are displayed in the opposite order. It is recommended that the first letter in the displayed string be 'D' to denote a display driver; the other three (at most) bytes should be indicative of the driver name. For example, the tag string '3sD' will appear as 'Ds3' if pool is dumped.

See Also

DD_SURFACE_LOCAL, DD_SURFACE_GLOBAL, EngFreePrivateUserMem, EngAllocUserMem, EngFreeUserMem


EngAllocUserMem

EngAllocUserMem allocates a block of memory from the address space of the current process, and inserts a caller-supplied tag before the allocation.

PVOID
  EngAllocUserMem(
    IN SIZE_T  cj,
    IN ULONG  tag
    );

Parameters

cj
Specifies the number of bytes to allocate.
tag
Specifies a 4-byte allocation tag that uniquely identifies the driver doing the memory allocation.

Return Value

EngAllocUserMem returns a pointer to the allocated memory if there is enough user-mode memory to satisfy the request; otherwise, it returns a null pointer.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A process in an NT-based operating system has 4 GB of virtual address space. The upper 2 GB is system memory that is accessible only to kernel-mode threads; this space is identical across all processes. The lower 2 GB is user memory that is accessible to both user-mode and kernel-mode threads; this space is unique to its process. The memory allocated by EngAllocUserMem is allocated from the unique 2 GB of user memory, and is thus accessible only when the graphics driver is called in the context of the thread in which the memory was allocated. Graphics drivers always execute in the context of the caller; that is, graphics drivers cannot switch process contexts.

EngAllocUserMem is particularly useful to a printer driver with large bitmaps that will only be used by the current process. Rather than allocating from the system pool, this driver can instead allocate space from the current process's address space. Drivers need to exercise care with memory allocated by EngAllocUserMem, as it is possible for the application to step on this memory. EngAllocUserMem should only be used to allocate relatively large chunks of memory, as each allocation takes at least 64 KB of virtual address space. Sensitive data structures should never be allocated using this function. Also, user memory allocated by this function cannot be passed to EngWritePrinter by the printer driver.

The tag string should be specified in byte-reversed order. The reason for this is that if a crash dump of the system occurs, the contents of the tag string are displayed in the opposite order. It is recommended that the first letter in the displayed string be 'D' to denote a display driver; the other three (at most) bytes should be indicative of the driver name. For example, the tag string '3sD' will appear as 'Ds3' if pool is dumped.

When the memory is no longer needed, it can be freed by a call to the EngFreeUserMem function.

To allocate user memory from the address space of a different process, use EngAllocPrivateUserMem.

See Also

EngFreeUserMem, EngAllocPrivateUserMem


EngAlphaBlend

EngAlphaBlend provides bit-block transfer capabilities with alpha blending.

BOOL
  EngAlphaBlend(
    IN SURFOBJ  *psoDest,
    IN SURFOBJ  *psoSrc,
    IN CLIPOBJ  *pco,
    IN XLATEOBJ  *pxlo,
    IN RECTL  *prclDest,
    IN RECTL  *prclSrc,
    IN BLENDOBJ  *pBlendObj
    );

Parameters

psoDest
Points to a SURFOBJ structure that identifies the surface on which to draw.
psoSrc
Points to a SURFOBJ structure that identifies the source surface.
pco
Points to a CLIPOBJ structure. The CLIPOBJ_Xxx service routines are provided to enumerate the clip region as a set of rectangles. This enumeration limits the area of the destination that is modified. Whenever possible, GDI simplifies the clipping involved. However, unlike EngBitBlt, EngAlphaBlend might be called with a single rectangle in order to prevent round-off errors in clipping the output.
pxlo
Points to a XLATEOBJ structure that specifies how color indices should be translated between the source and destination surfaces.

If the source surface is palette managed, its colors are represented by indices into a lookup table of RGB color values. In this case, GDI can query the XLATEOBJ structure for a translate vector to quickly translate any source index into a color index for the destination.

The situation is more complicated when, for example, the source is RGB but the destination is palette-managed. In this case, the closest match to each source RGB value must be found in the destination palette. GDI calls the XLATEOBJ_iXlate service routine to perform this matching operation.

prclDest
Points to a RECTL structure that defines the rectangular area to be modified. This rectangle is specified in the coordinate system of the destination surface and is defined by two points: upper left and lower right. The two points that define the rectangle are always well ordered.

The rectangle is lower-right exclusive; that is, its lower and right edges are not a part of the blend.

The specified rectangle can overhang the destination surface; GDI performs the proper clipping when it does.

EngAlphaBlend must never be called with an empty destination rectangle.

prclSrc
Points to a RECTL structure that defines the area to be copied. This rectangle is specified in the coordinate system of the source surface and is defined by two points: upper left and lower right. The two points that define the rectangle are always well ordered.

The rectangle is lower-right exclusive; that is, its lower and right edges are not a part of the blend.

The source rectangle must never exceed the bounds of the source surface, and thus never overhang the source surface.

EngAlphaBlend must never be called with an empty source rectangle.

The mapping is defined by prclSrc and prclDest. The points specified in prclDest and prclSrc lie on integer coordinates, which correspond to pixel centers. A rectangle defined by two such points is considered to be a geometric rectangle with two vertices whose coordinates are the given points, but with 0.5 subtracted from each coordinate. (POINTL structures are shorthand notation for specifying these fractional coordinate vertices.)

pBlendObj
Points to a BLENDOBJ structure that describes the blending operation to perform between the source and destination surfaces. This structure is a wrapper for the BLENDFUNCTION structure, which includes necessary source and destination format information that is not available in the XLATEOBJ structure . BLENDFUNCTION is declared in the Platform SDK documentation. Its members are defined as follows:

BlendOp defines the blend operation to be performed. Currently this value must be AC_SRC_OVER, which means that the source bitmap is placed over the destination bitmap based on the alpha values of the source pixels. There are three possible cases that this blend operation should handle. These are described in the Comments section of this reference page.

BlendFlags is reserved and is currently set to zero.

SourceConstantAlpha defines the constant blend factor to apply to the entire source surface. This value is in the range of [0,255], where 0 is completely transparent and 255 is completely opaque.

AlphaFormat defines whether the surface is assumed to have an alpha channel. This member can optionally be set to the following value:

AC_SRC_ALPHA
The source surface can be assumed to be in a pre-multiplied alpha 32bpp "BGRA" format; that is, the surface type is BMF_32BPP and the palette type is BI_RGB. The alpha component is an integer in the range of [0,255], where 0 is completely transparent and 255 is completely opaque.

Return Value

EngAlphaBlend returns TRUE upon success. If an error occurs, it returns FALSE and reports an error code.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A bit-block transfer with alpha blending is supported between the following surfaces:

  • From one device-managed surface to another device-managed surface.
  • From one GDI-managed standard format bitmap to another GDI-managed standard format bitmap.
  • From one device-managed surface to a GDI-managed surface, and vice versa.

The driver should never call EngAlphaBlend with overlapping source and destination rectangles on the same surface.

The three possible cases for the AC_SRC_OVER blend function are:

  • The source bitmap has no per-pixel alpha (AC_SRC_ALPHA is not set), so the blend is applied to the pixel's color channels based on the constant source alpha value specified in SourceConstantAlpha as follows:
    Dst.Red = Round(((Src.Red * SourceConstantAlpha) +
    ((255 – SourceConstantAlpha) * Dst.Red)) / 255);
Dst.Green = Round(((Src.Green * SourceConstantAlpha) +
    ((255 – SourceConstantAlpha) * Dst.Green)) / 255);
Dst.Blue = Round(((Src.Blue * SourceConstantAlpha) +
    ((255 – SourceConstantAlpha) * Dst.Blue)) / 255);
/* Do the next computation only if the destination bitmap
    has an alpha channel. */
Dst.Alpha = Round(((Src.Alpha * SourceConstantAlpha) +
    ((255 – SourceConstantAlpha) * Dst.Alpha)) / 255);
  • The source bitmap has per-pixel alpha values (AC_SRC_ALPHA is set), and SourceConstantAlpha is not used (it is set to 255). The blend is computed as follows:
    Dst.Red = Src.Red +
    Round(((255 – Src.Alpha) * Dst.Red) / 255);
Dst.Green = Src.Green +
    Round(((255 – Src.Alpha) * Dst.Green) / 255);
Dst.Blue = Src.Blue +
    Round(((255 – Src.Alpha) * Dst.Blue) / 255);
/* Do the next computation only if the destination bitmap
    has an alpha channel. */
Dst.Alpha = Src.Alpha +
    Round(((255 – Src.Alpha) * Dst.Alpha) / 255);
  • The source bitmap has per-pixel alpha values (AC_SRC_ALPHA is set), and SourceConstantAlpha is used (it is not set to 255). The blend is computed as follows:
    Temp.Red = Round((Src.Red * SourceConstantAlpha) / 255);
Temp.Green = Round((Src.Green * SourceConstantAlpha) / 255);
Temp.Blue = Round((Src.Blue * SourceConstantAlpha) / 255);
/* The next computation must be done even if the
    destination bitmap does not have an alpha channel. */
Temp.Alpha = Round((Src.Alpha * SourceConstantAlpha) / 255);

/* Note that the following equations use the just-computed
   Temp.Alpha value: */
Dst.Red = Temp.Red +
    Round(((255 – Temp.Alpha) * Dst.Red) / 255);
Dst.Green = Temp.Green +
    Round(((255 – Temp.Alpha) * Dst.Green) / 255);
Dst.Blue = Temp.Blue +
    Round(((255 – Temp.Alpha) * Dst.Blue) / 255);
/* Do the next computation only if the destination bitmap
    has an alpha channel. */
Dst.Alpha = Temp.Alpha +
    Round(((255 – Temp.Alpha) * Dst.Alpha) / 255);

The driver should call EngAlphaBlend if it has hooked DrvAlphaBlend and it is called to do something that it does not support.

See Also

DrvAlphaBlend, DrvBitBlt, DrvPlgBlt, DrvStretchBlt, DrvStretchBltROP, DrvTransparentBlt, EngAssociateSurface, EngBitBlt, EngPlgBlt, EngStretchBlt, EngStretchBltROP, EngTransparentBlt


EngAssociateSurface

EngAssociateSurface marks a given surface as belonging to a specified device.

BOOL
  EngAssociateSurface(
    IN HSURF  hsurf,
    IN HDEV  hdev,
    IN FLONG  flHooks
    );

Parameters

hsurf
Identifies the surface or bitmap to be associated with hdev. This handle was returned by EngCreateBitmap or EngCreateDeviceBitmap.
hdev
Identifies the device with which the surface is to be associated. This is the GDI-created handle that was passed to the driver's DrvCompletePDEV function.
flHooks
Specifies the functions that the driver can hook from GDI. The driver must implement the corresponding function for every bit that it sets in flHooks. This member is a bit-wise OR of any of the following values:
Flag | Function to be hooked
HOOK_ALPHABLEND | DrvAlphaBlend
HOOK_BITBLT | DrvBitBlt
HOOK_COPYBITS | DrvCopyBits
HOOK_FILLPATH | DrvFillPath
HOOK_GRADIENTFILL | DrvGradientFill
HOOK_LINETO | DrvLineTo
HOOK_MOVEPANNING | Obsolete
HOOK_PAINT | Obsolete
HOOK_PLGBLT | DrvPlgBlt
HOOK_STRETCHBLT | DrvStretchBlt
HOOK_STRETCHBLTROP | DrvStretchBltROP
HOOK_STROKEANDFILLPATH | DrvStrokeAndFillPath
HOOK_STROKEPATH | DrvStrokePath
HOOK_SYNCHRONIZE | DrvSynchronize or DrvSynchronizeSurface (either or both)
HOOK_SYNCHRONIZEACCESS | Obsolete
HOOK_TEXTOUT | DrvTextOut
HOOK_TRANSPARENTBLT | DrvTransparentBlt

Return Value

The return value is TRUE if the function is successful. Otherwise, the driver should send the information to the GDI function it is implementing, and return GDI's return value.

Headers

Declared in winddi.h. Include winddi.h.

Comments

EngAssociateSurface can be used by printer drivers to implement "rules" or device fonts, or by display drivers to make use of special blt hardware.

If the surface identified by hsurf is a standard format bitmap, the driver can specify which output functions to the surface it will handle by setting bits in flHooks. Setting bits in flHooks causes particular output functions to be sent to the driver instead. This is referred to as hooking. If the driver does not hook a call, GDI will automatically manage the operation when a standard format bitmap is being drawn on.

When the surface is associated, it assumes the default palette and style steps of the PDEV. A surface must be associated before it is returned by DrvEnableSurface.

By default, when a driver supports device bitmaps by implementing DrvCreateDeviceBitmap/DrvDeleteDeviceBitmap, GDI does not automatically synchronize drawing calls to the device bitmap and to the primary surface. For example, GDI can call the driver's DrvBitBlt function to draw to a device bitmap, while another thread is drawing to the primary surface by executing the driver's implementation of DrvTextOut. The driver can even be called to draw to multiple device bitmaps at the same time.

See Also

DrvBitBlt, DrvCompletePDEV, DrvCopyBits, DrvCreateDeviceBitmap, DrvDeleteDeviceBitmap, DrvEnableSurface, DrvFillPath, DrvLineTo, DrvStretchBlt, DrvStrokeAndFillPath, DrvStrokePath, DrvSynchronize, DrvSynchronizeSurface, DrvTextOut, EngModifySurface


EngBitBlt

EngBitBlt provides general bit-block transfer capabilities either between device-managed surfaces, or between a device-managed surface and a GDI-managed standard format bitmap.

BOOL
  EngBitBlt(
    IN SURFOBJ  *psoTrg,
    IN SURFOBJ  *psoSrc,
    IN SURFOBJ  *psoMask,
    IN CLIPOBJ  *pco,
    IN XLATEOBJ  *pxlo,
    IN RECTL  *prclTrg,
    IN POINTL  *pptlSrc,
    IN POINTL  *pptlMask,
    IN BRUSHOBJ  *pbo,
    IN POINTL  *pptlBrush,
    IN ROP4  rop4
    );

Parameters

psoTrg
Points to the SURFOBJ structure that identifies the surface on which to draw.
psoSrc
If the rop4 requires it, points to a SURFOBJ structure that defines the source for the bit-block transfer operation.
psoMask
Points to a SURFOBJ structure that defines a surface to be used as a mask. The mask is defined as a bitmap with 1 bit per pixel. Typically, a mask limits the area that is to be modified in the destination surface. Masking is selected by a rop4 with the value 0xAACC. The destination surface is unaffected when the mask is zero.

The mask is large enough to cover the destination rectangle.

If the value of this parameter is null and a mask is required by the rop4, then the implicit mask in the brush is used. If a mask is required, then psoMask overrides the implicit mask in the brush.

pco
Points to a CLIPOBJ structure. The CLIPOBJ_Xxx service routines are provided to enumerate the clip region as a set of rectangles. This enumeration limits the area of the destination that will be modified. Whenever possible, GDI simplifies the clipping involved; for example, this function is never called with a single clipping rectangle. GDI clips the destination rectangle before calling this function, making additional clipping unnecessary.
pxlo
Points to a XLATEOBJ structure that tells how color indices should be translated between the source and target surfaces.
prclTrg
Points to a RECTL structure in the coordinate system of the destination surface that defines the area to be modified. The rectangle is defined by two points; upper left and lower right. The lower and right edges of this rectangle are not part of the bit-block transfer, meaning the rectangle is lower right exclusive.

EngBitBlt is never called with an empty destination rectangle. The two points that define the rectangle are always well ordered.

pptlSrc
Points to a POINTL structure that defines the upper left corner of the source rectangle, if a source exists. If there is no source, the driver should ignore this parameter.
pptlMask
Points to a POINTL structure that defines which pixel in the mask corresponds to the upper left corner of the destination rectangle. If no mask is specified in psoMask the driver should ignore this parameter.
pbo
Points to the brush object to be used to define the pattern for the bit-block transfer. GDI's BRUSHOBJ_pvGetRbrush service routine retrieves the device's realization of the brush. The driver can ignore this parameter if the rop4 parameter does not require a pattern.
pptlBrush
Points to a POINTL structure that defines the origin of the brush in the destination surface. The upper left pixel of the brush is aligned at this point and the brush repeats according to its dimensions. Ignore this parameter if the rop4 parameter does not require a pattern.
rop4
Represents a raster operation that defines how the mask, pattern, source, and destination pixels are combined to write an output pixel to the destination surface.

This is a quaternary raster operation, which is a natural extension of the usual ternary Rop3 operation. A Rop4 has 16 relevant bits, which are similar to the 8 defining bits of a Rop3. (The other, redundant bits of the Rop3 are ignored.) The simplest way to implement a Rop4 is to consider its 2 bytes separately. The lower byte specifies a Rop3 that should be computed wherever the mask is 1. The high byte specifies a Rop3 that can be computed and applied wherever the mask is 0.

Return Value

The return value is TRUE if the function is successful. Otherwise, it is FALSE, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

If a device's surface is organized as a standard-format bitmap, the driver can request that GDI perform the bit-block transfer by calling EngBitBlt. A driver might do this if it has special hardware to handle simple transfers quickly, but doesn't want to handle calls with complicated transfers.

See the Platform SDK documentation for more information on raster operations.

See Also

BRUSHOBJ, BRUSHOBJ_pvGetRbrush, CLIPOBJ, DrvBitBlt, EngAssociateSurface, SURFOBJ, XLATEOBJ


EngCheckAbort

GDI's EngCheckAbort function enables a printer graphics DLL to determine if a print job should be terminated.

BOOL
  EngCheckAbort(
    IN SURFOBJ  *pso
    );

Parameters

pso
Caller-supplied pointer to a SURFOBJ structure, previously received from GDI.

Return Value

If the print job should be terminated, the function returns TRUE. If the print job should not be terminated, or if pso does not point to a valid SURFOBJ structure, the function returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A printer graphics DLL should call EngCheckAbort from within any graphics DDI function that takes more than five seconds to execute. If the print job should be terminated, the printer graphics DLL should stop its current operation and return to GDI, specifying a return value of FALSE for the graphics DDI function that called EngCheckAbort.


EngClearEvent

EngClearEvent sets a specified event object to the nonsignaled state.

VOID
  EngClearEvent(
    IN PEVENT  pEvent
    );

Parameters

pEvent
Points to the event object returned by a previous call to either EngCreateEvent or EngMapEvent.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function is available in Windows XP and later.

See Also

EngCreateEvent, EngMapEvent


EngComputeGlyphSet

EngComputeGlyphSet computes the glyph set supported on a device.

FD_GLYPHSET *
  EngComputeGlyphSet(
    IN INT  nCodePage,
    IN INT  nFirstChar,
    IN INT  cChars
    );

Parameters

nCodePage
Specifies the code page supported.
nFirstChar
Character code of the first supported ANSI character.
cChars
Number of ANSI characters supported.

Return Value

If the glyph set is computed successfully, a pointer to an FD_GLYPHSET structure is returned. If an error occurs, null is returned .

Headers

Declared in winddi.h. Include winddi.h.

Comments

A driver can use EngComputeGlyphSet to compute the glyph set for a font that contains only glyphs in the code page described by nCodePage.

The driver must call EngFreeMem to free memory when it is done using the FD_GLYPHSET structure returned by EngComputeGlyphSet.

See Also

EngFreeMem


EngControlSprites

EngControlSprites tears down or redraws sprites on the specified WNDOBJ area.

BOOL
  EngControlSprites(
    IN WNDOBJ  *pwo,
    IN FLONG  fl
    );

Parameters

pwo
Points to the WNDOBJ structure on which the sprites are being built or torn down.
fl
This parameter can be one of the following values:
ECS_TEARDOWN
Requests that GDI tear down and remove any sprites that overlap the WNDOBJ area. GDI restores the area beneath the sprite by making immediate calls to DrvCopyBits.
ECS_REDRAW
Requests that GDI redraw, restoring any sprites that overlap the WNDOBJ area. GDI redraws directly to the screen by making calls to DrvCopyBits.

Return Value

EngControlSprites returns TRUE upon successfully completing the requested operation; otherwise, it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The invocation of ECS_TEARDOWN may be persistent. For example, the driver can call EngControlSprites once with ECS_TEARDOWN as soon as it has created the WNDOBJ, and no sprites will ever be drawn on top of the window.

The driver can call EngControlSprites with ECS_REDRAW numerous times without making intervening calls with ECS_TEARDOWN in order to force the repaint of a sprite at any time.

ECS_TEARDOWN always forces an immediate redraw of any sprites on top of the WNDOBJ area. GDI saves the bits beneath the sprites by calling DrvCopyBits to copy them from the screen, and then composites the sprites onto the screen by calling DrvCopyBits. This can be used to allow sprites to be composited onto a back-buffer just before a swap-buffer command is sent to the hardware (through DrvSwapBuffers or any other driver swap buffer mechanism). This permits seamless compositing of sprites, without flashing, when the window is double buffering.

ECS_TEARDOWN will never cause a WOC_SPRITE_NO_OVERLAP message to be sent, and likewise ECS_REDRAW will never cause a WOC_SPRITE_OVERLAP message to be sent.

EngControlSprites can be called even if no sprites currently overlap the WNDOBJ area.

See Also

EngCreateWnd, WNDOBJ


EngCopyBits

EngCopyBits translates between device-managed raster surfaces and GDI standard-format bitmaps.

BOOL
  EngCopyBits(
    OUT SURFOBJ  *psoDest,
    IN SURFOBJ  *psoSrc,
    IN CLIPOBJ  *pco,
    IN XLATEOBJ  *pxlo,
    IN RECTL  *prclDest,
    IN POINTL  *pptlSrc
    );

Parameters

psoDest
Points to a SURFOBJ structure that describes the destination surface for the copy operation.
psoSrc
Points to a SURFOBJ structure that describes the source surface for the copy operation.
pco
Points to a CLIPOBJ structure that restricts the area of the destination surface that will be affected. This parameter can be NULL.
pxlo
Points to a XLATEOBJ structure that defines the translation of color indices between the source and target surfaces.
prclDest
Points to a RECTL structure that defines the area in the coordinate system of the destination surface that will be modified. The rectangle is lower-right exclusive, meaning the lower and right edges of this rectangle are not part of the copy.
pptlSrc
Points to a POINTL structure that defines the upper left corner of the source rectangle.

Return Value

The return value is TRUE if the function is successful. If it is unsuccessful, it reports an error and returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Standard-format bitmaps are single-plane, packed-pixel format. Each scan line is aligned on a 4-byte boundary. These bitmaps have 1, 4, 8, 16, 24, 32, or 64 bits per pixel.

GDI calls this function from its simulations.

EngCopyBits should not be called with an empty destination rectangle, and the two points of the destination rectangle must be well-ordered; that is, the first point should represent the upper-left vertex of the rectangle, and the second should represent the lower-right vertex.

See Also

CLIPOBJ, SURFOBJ, XLATEOBJ


EngCreateBitmap

EngCreateBitmap requests that GDI create and manage a bitmap.

HBITMAP
  EngCreateBitmap(
    IN SIZEL  sizl,
    IN LONG  lWidth,
    IN ULONG  iFormat,
    IN FLONG  fl,
    IN PVOID  pvBits
    );

Parameters

sizl
Specifies the size, in pixels, of the bitmap to be created. If pvBits is nonnull, this value should represent all pixels visible on the device, allowing the device to keep off-screen memory.
lWidth
Specifies the allocation width of the bitmap, which is the number of bytes that must be added to a pointer to move down one scan line.
iFormat
Specifies the format of the bitmap in terms of the number of bits of color information per pixel that are required. This parameter can be one of the following values:
Value | Meaning
BMF_1BPP | Monochrome
BMF_4BPP | 4 bits per pixel
BMF_8BPP | 8 bits per pixel
BMF_16BPP | 16 bits per pixel
BMF_24BPP | 24 bits per pixel
BMF_32BPP | 32 bits per pixel
BMF_4RLE | 4 bits per pixel; run length encoded
BMF_8RLE | 8 bits per pixel; run length encoded

fl
Is a bitmask that specifies properties about the bitmap to be created. This parameter can be zero, or any combination of the following values:
Value | Meaning
BMF_NOZEROINIT | GDI will not zero-initialize the bitmap when allocating it. This flag is checked only when pvBits is null.
BMF_TOPDOWN | The first scan line represents the top of the bitmap. Note that standard-format bitmaps have the first scan line at the bottom by default.
BMF_USERMEM | GDI will allocate the memory for the bitmap from user memory. By default, the memory is allocated from the kernel's address space. This flag should be specified only when the bitmap being created will not be used by other processes. User memory cannot be passed to EngWritePrinter by the printer driver.

pvBits
Points to the first scan line of the bitmap that is to be created. If this parameter is null, GDI allocates the storage space for the pixels of the bitmap. If pvBits is nonnull, it is a pointer to the buffer for the bitmap.

Return Value

If the function completes successfully, the return value is a handle that identifies the created bitmap. Otherwise, it is zero, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Storage for the bitmap can optionally be provided by the driver.

The driver should associate the created bitmap as a surface by calling EngAssociateSurface before returning from DrvEnableSurface.

The bitmap should be deleted by using EngDeleteSurface when it is no longer needed.

Frame buffer display drivers should use the pvBits parameter, allowing GDI to do most drawing directly to the display.

See Also

DrvCreateDeviceBitmap, EngAllocUserMem


EngCreateClip

EngCreateClip creates a CLIPOBJ structure that the driver uses in callbacks.

CLIPOBJ
  *EngCreateClip(
    VOID
    );

Return Value

The return value is a pointer to the newly-created CLIPOBJ structure if the function succeeds. Otherwise, it is NULL.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The CLIPOBJ structure created by EngCreateClip allows GDI to directly access banked frame buffers. The structure must be initialized by the driver so that the iDComplexity member of the CLIPOBJ structure is set to DC_TRIVIAL or DC_RECT. If the iDComplexity member is set to DC_RECT, the driver can set the rclBounds member of CLIPOBJ to the extent of the frame buffer bank. The driver must delete this CLIPOBJ structure using EngDeleteClip.


EngCreateDeviceBitmap

EngCreateDeviceBitmap requests GDI to create a handle for a device bitmap.

HBITMAP
  EngCreateDeviceBitmap(
    IN DHSURF  dhsurf,
    IN SIZEL  sizl,
    IN ULONG  iFormatCompat
    );

Parameters

dhsurf
Identifies the device bitmap being created.
sizl
Specifies the size, in pixels, of the bitmap to be created.
iFormatCompat
Specifies the compatible engine format of the device surface being created. This is used by GDI if a temporary buffer is needed to simulate a complicated drawing call. The allowable values for iFormatCompat are BMF_1BPP, BMF_4BPP, BMF_8BPP, BMF_16BPP, BMF_24BPP, and BMF_32BPP.

Return Value

The return value is a handle that identifies the bitmap if the function is successful. Otherwise, it is zero, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The storage space for the bitmap can optionally be provided by the driver. The surface should be associated by using EngAssociateSurface. The bitmap should be deleted by calling EngDeleteSurface when it is no longer needed.

See Also

EngCreateBitmap


EngCreateDeviceSurface

EngCreateDeviceSurface creates and returns a handle for a device surface that the driver will manage.

HSURF
  EngCreateDeviceSurface(
    DHSURF  dhsurf,
    SIZEL  sizl,
    ULONG  iFormatCompat
    );

Parameters

dhsurf
Identifies the surface to be managed by the device. This handle is passed to the driver when a SURFOBJ structure is passed for input or output.
sizl
Specifies the size, in pixels, of the surface to be created.
iFormatCompat
Specifies the compatible engine format of the device surface being created. This is used by GDI if a temporary buffer is needed to simulate a complicated drawing call.

Return Value

The return value is a handle that identifies the surface if the function is successful. Otherwise, it is zero, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The storage space for the surface can optionally be provided by the driver. The surface should be associated by using EngAssociateSurface. The surface should be deleted when it is no longer needed by using EngDeleteSurface.

See Also

SURFOBJ


EngCreateDriverObj

EngCreateDriverObj creates a DRIVEROBJ structure.

HDRVOBJ
  EngCreateDriverObj(
    PVOID  pvObj,
    FREEOBJPROC  pFreeObjProc,
    HDEV  hdev
    );

Parameters

pvObj
Points to the driver resource that will be tracked by the DRIVEROBJ structure. The resource is associated with the current client process.
pFreeObjProc
Points to a driver-supplied callback function that frees the resource pointed to by pvObj. The callback function should be defined as follows, where pDriverObj points to the DRIVEROBJ structure:
BOOL CALLBACK DrvobjFreeObjProc(DRIVEROBJ *pDriverObj);
hdev
Identifies the physical device associated with the object. This parameter is the GDI handle received by the driver's DrvCompletePDEV function.

Return Value

The return value is a handle that identifies the newly-created DRIVEROBJ structure if the function is successful. Otherwise, it is zero.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This structure is used to track a device-managed resource that must be released if the resource-allocating process terminates without first cleaning it up.

The driver can explicitly delete the DRIVEROBJ structure by calling EngDeleteDriverObj. Otherwise, the engine frees the resource by calling the function pointed to by pFreeObjProc when the process that created the DRIVEROBJ terminates.

See Also

DRIVEROBJ


EngCreateEvent

EngCreateEvent creates a synchronization event object that can be used to synchronize hardware access between a display driver and the video miniport driver.

BOOL
  EngCreateEvent(
    OUT PEVENT  *ppEvent
    );

Parameters

ppEvent
Points to a location in which a valid event object is returned.

Return Value

EngCreateEvent returns TRUE if it is successful in creating an event object. Otherwise, it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function is available in Windows XP and later.

EngCreateEvent creates a synchronization event object, which is initialized to the nonsignaled state.

See Also

EngDeleteEvent, EngSetEvent, EngWaitForSingleObject


EngCreatePalette

EngCreatePalette sends a request to GDI to create an RGB palette.

HPALETTE
  EngCreatePalette(
    IN ULONG  iMode,
    IN ULONG  cColors,
    IN ULONG  *pulColors,
    IN FLONG  flRed,
    IN FLONG  flGreen,
    IN FLONG  flBlue
    );

Parameters

iMode
Specifies how the palette will be defined. This parameter can be one of the following values:
Value | Meaning
PAL_BITFIELDS | The palette is defined by the flRed, flGreen, and flBlue parameters.
PAL_BGR | The device accepts RGB colors directly, with B as the least significant byte.
PAL_INDEXED | An array of RGB colors is provided with cColors and pulColors.
PAL_RGB | The device accepts RGB colors directly, with R as the least significant byte.

cColors
If the iMode parameter is PAL_INDEXED, cColors specifies the number of colors provided in the array pointed to by pulColors. Otherwise, this parameter should be zero.
pulColors
Points to the beginning of an array of ULONG values if iMode is PAL_INDEXED. The low-order 3 bytes of each ULONG define the RGB colors in the palette.
flRed, flGreen, and flBlue
If the iMode parameter is PAL_BITFIELDS, these parameters are masks that show which bits correspond to red, green, and blue. Each mask must consist of contiguous bits and should not overlap other masks. All combinations of bitfields are supported by GDI.

Return Value

The return value is a handle to the new palette if the function is successful. Otherwise, it is zero, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The driver can associate the new palette with a device by returning a pointer to the palette in the DEVINFO structure.

A PAL_INDEXED palette associated with the device must have its first index entry set to black (red = 0, green = 0, blue = 0) and its last entry set to white (255, 255, 255). All other entries should be set so that entries whose indexes are one's complements of each other have colors that contrast greatly. For example, if entry 0x9 of a 16 entry palette is set to pure green (0,255,0), entry 0x6 (=~0x9) should be set to a color that contrasts well with green, such as dark purple (128,0,128). Setting entries in this way allows XOR raster operations to behave reasonably.

See Also

DEVINFO, DrvSetPalette, EngDeletePalette


EngCreatePath

EngCreatePath allocates a path for the driver's temporary use.

PATHOBJ
  *EngCreatePath(
    VOID
    );

Return Value

The return value is a pointer to a PATHOBJ structure if the function is successful. Otherwise, it is null, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The driver should delete the path, allocated by EngCreatePath, before returning to GDI from its current drawing call.

Functions that create and modify paths are provided to assist devices in clipping paths. A driver can create a path, fill it with lines and pass the path to PATHOBJ_bEnumClipLines for clipping against the complex region.

A PATHOBJ structure is a locked object, and thus should not be locked for a long time by the driver.

If the driver uses EngCreatePath to create a PATHOBJ structure, it should be deleted by using EngDeletePath as soon as the driver finishes with it.

The returned PATHOBJ structure is used in calls to PATHOBJ_bMoveTo, PATHOBJ_bPolyLineTo, PATHOBJ_vEnumStartClipLines, and PATHOBJ_bEnumClipLines

See Also

PATHOBJ, PATHOBJ_bEnumClipLines


EngCreateSemaphore

EngCreateSemaphore creates a semaphore object.

HSEMAPHORE
  EngCreateSemaphore(
    VOID
    );

Return Value

If the function succeeds, the return value is a handle to the semaphore object. A null pointer is returned if the function fails.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Graphics drivers can create and use a semaphore object for resource synchronization. For example:

  • The permedia display driver uses a semaphore when an asynchronous pointer requires access to the CRTC registers, because these registers are shared by both the asynchronous hardware pointers and the synchronous activities of the device.
  • Multiple printer drivers sharing global data, such as font data on a print server, need to synchronize access to this data.

See Also

EngAcquireSemaphore, EngDeleteSemaphore, EngIsSemaphoreOwned, EngIsSemaphoreOwnedByCurrentThread, EngReleaseSemaphore


EngCreateWnd

EngCreateWnd creates a WNDOBJ structure for the window referenced by hwnd.

WNDOBJ
  *EngCreateWnd(
    SURFOBJ  *pso,
    HWND  hwnd,
    WNDOBJCHANGEPROC  pfn,
    FLONG  fl,
    int  iPixelFormat
    );

Parameters

pso
Points to a SURFOBJ structure identifying a device surface.
hwnd
Is the handle that identifies a window created by an application's call to the Win32® CreateWindow or equivalent function.
pfn
Points to a driver-defined WNDOBJCHANGEPROC callback that GDI calls to notify the driver of changes to the window identified by hwnd. In the context of this function, the WNDOBJ values will be unchanged.
fl
Is a bitmask that specifies the type of changes GDI should track and report to the driver. This value must be consistent through all WNDOBJ requests made by the driver. This parameter can be one or more of the following bit field values:
Flag | Meaning
WO_DRAW_NOTIFY | GDI should provide the driver with WOC_DRAWN notifications.
WO_RGN_CLIENT | GDI should track changes in the client region of the window object, and notify the driver when the window's visible client region changes. The region enumerated in the callback function is the new visible client area of the window.
WO_RGN_CLIENT_DELTA | GDI should track changes in the delta client region of the window object, and notify the driver when the window's visible region changes. The region enumerated in the callback function is a non-empty delta area that is in the new region but not in the old region. The delta region is valid during the callback only.
WO_RGN_DESKTOP_COORD GDI creates a WNDOBJ structure with desktop coordinates when the system is running multiple monitors.

GDI ignores this flag and creates a WNDOBJ structure with device coordinates when the system is running a single monitor.
WO_RGN_SURFACE | GDI should track changes in the surface region of the window object, and notify the driver when the surface region changes. The surface region is the display surface area excluding all visible client regions of the windows being tracked by the driver.
WO_RGN_SURFACE_DELTA | GDI should track changes in the delta surface region of the window object, and notify the driver when the surface region changes. The region enumerated in the callback function is a non-empty delta area that is in the new surface region but not in the old surface region. The delta surface region is valid during the callback only.
WO_RGN_UPDATE_ALL | GDI should notify the driver for all windows it tracks when any of its windows' visible regions change. This flag must be used in conjunction with the WO_RGN_CLIENT flag.
WO_RGN_WINDOW | GDI should track changes in the entire region of the window object (which includes the client region of the window), and notify the driver when the window's region changes.
WO_SPRITE_NOTIFY | GDI should notify the driver for all windows it tracks when any of its windows' visible regions are overlapped or no longer overlapped by sprites.

iPixelFormat
Specifies the pixel format associated with the window object. The pixel format of a window object is fixed. This parameter can be zero if there is no associated pixel format.

Return Value

The return value is a pointer to a WNDOBJ structure if the function is successful. Otherwise, the return value is –1 if the same window is being tracked by the driver, or zero if the driver is not tracking the same window.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Because creating a window object involves locking window resources, EngCreateWnd should be called only in the context of the WNDOBJ_SETUP escape in DrvEscape.

EngCreateWnd supports window tracking by multiple drivers, where each driver is identified by a unique WNDOBJCHANGEPROC function pointer identified by pfn. For example, a live video driver can track changes to live video windows while an OpenGL driver is tracking changes to OpenGL windows.

GDI will call WNDOBJCHANGEPROC with the most recent window state if a new WNDOBJ is created by DrvEscape. GDI will also notify WNDOBJCHANGEPROC when a window described by a WNDOBJ structure is destroyed.

The WOC_SPRITE_OVERLAP and WOC_SPRITE_NO_OVERLAP notifications passed to WNDOBJCHANGEPROC allow the driver to be synchronously informed when a sprite is on top of its window, and take the appropriate action. The driver receives these notifications even if all sprites have been torn down by the ECS_TEARDOWN flag of EngControlSprites.

See Also

DrvEscape, WNDOBJ, WNDOBJCHANGEPROC


EngDebugBreak

EngDebugBreak causes a breakpoint in the current process to occur.

VOID
  EngDebugBreak(
    VOID
    );

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

EngDebugBreak is useful for debugging drivers that are under development.

See Also

EngDebugPrint


EngDebugPrint

EngDebugPrint prints the specified debug message to the kernel debugger.

VOID
  EngDebugPrint(
    IN PCHAR StandardPrefix,
    IN PCHAR DebugMessage,
    IN va_list ap
    );

Parameters

StandardPrefix
Points to a string that is prepended to DebugMessage.
DebugMessage
Points to a string containing the debug message to be printed.
ap
Specifies the variable argument list.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

EngDebugPrint is useful for debugging drivers that are under development. It prints StandardPrefix, followed by DebugMessage, to the kernel debugger.

The StandardPrefix parameter acts as a unique identifier of the driver executing the debug statement; therefore, the same string should be used for all calls to EngDebugPrint by a single driver.

The DebugMessage parameter is a variable argument ASCII C string; that is, it can contain both ordinary characters and C-style conversion specifications. The argument list contained in ap can have any number of arguments of any type in it.

An example use of EngDebugPrint follows:

#define STANDARD_DEBUG_PREFIX     "Permedia: "
LONG bank;
LONG width;
...
VOID MyDebugPrint(PCHAR DebugMessage, …)
{
    va_list ap;

    va_start(ap, DebugMessage);
    EngDebugPrint(STANDARD_DEBUG_PREFIX, DebugMessage, ap);
    va_end(ap);
}
...
MyDebugPrint("Bank: %lx; Width: %ld", bank, width);

See Also

EngDebugBreak


EngDeleteClip

EngDeleteClip deletes a CLIPOBJ structure allocated by EngCreateClip.

VOID
  EngDeleteClip(
    IN CLIPOBJ  *pco
    );

Parameters

pco
Points to the CLIPOBJ structure to delete.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.


EngDeleteDriverObj

EngDeleteDriverObj frees the handle used for tracking a device-managed resource.

BOOL
  EngDeleteDriverObj(
    IN HDRVOBJ  hdo,
    IN BOOL  bCallBack,
    IN BOOL  bLocked
    );

Parameters

hdo
Identifies the GDI handle that is to be deleted. This handle was obtained from EngCreateDriverObj.
bCallBack
Specifies whether or not the cleanup callback should be called. If TRUE, GDI will invoke the cleanup callback before removing the DRIVEROBJ from the handle manager. If the callback function returns failure, EngDeleteDriverObj will fail.
bLocked
Specifies whether the object was locked by the driver (through a call to EngLockDriverObj) before EngDeleteDriverObj was called.

Return Value

The return value is TRUE if the function is successful and the handle is freed; it is FALSE if the handle has not been freed. If the pFreeObjProc driver function specified in EngCreateDriverObj returns FALSE, then EngDeleteDriverObj will fail and the handle won't be freed. This could happen if the cleanup callback needs to lock another DRIVEROBJ structure (in order to free the current DRIVEROBJ structure ) and fails because the other DRIVEROBJ structure is in use by another thread.

Headers

Declared in winddi.h. Include winddi.h.

Comments

After the handle is freed, the associated driver resource is no longer tracked by GDI and the function pointed to by the pFreeObjProc parameter of EngCreateDriverObj will not be called upon process termination. It is the responsibility of the driver to ensure that the resource is freed.

Most drivers should be consistent in how objects are cleaned up at termination time. Consequently, they will pass TRUE for bCallback, indicating to GDI that it should call the driver's cleanup function to free this driver resource.

The bCallBack parameter indicates to GDI whether or not the callback function needs to be called. Passing TRUE for bCallBack tells GDI to call the driver's cleanup function back to free this driver resource. Passing FALSE prevents GDI from calling the cleanup function. If pFreeObjProc returns FALSE, EngDeleteDriverObj fails and the handle won't be freed. For example, this could happen if the pFreeObjProc needed to lock down another DRIVEROBJ structure to free the current DRIVEROBJ structure and failed because the structure was being used by another thread. The pFreeObjProc should never fail at cleanup time, because no threads, other than the cleanup thread, are running, so locks of other objects won't fail.

The bLocked parameter indicates to GDI that the object has already been locked once by the driver. Often, before an object is deleted, the driver might have locked it down to use first. This allows the driver to call GDI without first having to unlock the object, thus eliminating the possibility that another thread could enter the driver and lock it down before the handle is freed.

See Also

DRIVEROBJ, EngCreateDriverObj


EngDeleteEvent

EngDeleteEvent deletes the specified event object.

BOOL
  EngDeleteEvent(
    IN PEVENT  pEvent
    );

Parameters

pEvent
Points to the event object to be deleted.

Return Value

EngDeleteEvent returns TRUE if it is successful in deleting the specified event object. It returns FALSE if the caller attempts to delete a mapped user event.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function is available in Windows XP and later.

A display driver can call EngDeleteEvent only with an event object returned from the EngCreateEvent function, and must not call it to delete event objects returned from EngMapEvent.

Before calling EngDeleteEvent, the display driver must notify all holders of the specified event object that it is about to become invalid.

See Also

EngCreateEvent, EngMapEvent


EngDeleteFile

EngDeleteFile deletes a file.

BOOL
  EngDeleteFile(
    IN LPWSTR  pwszFileName
    );

Parameters

pwszFileName
Points to a null-terminated string that contains the fully qualified name of the file to delete. An example of a fully qualified file name string is L"\\??\\c:\\test.dat".

Return Value

EngDeleteFile returns TRUE upon success. Otherwise, it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

See Also

EngMapFile


EngDeletePalette

EngDeletePalette sends a request to GDI to delete the specified palette.

BOOL
  EngDeletePalette(
    IN HPALETTE  hpal
    );

Parameters

hpal
Identifies the palette to be deleted. The handle is supplied by EngCreatePalette.

Return Value

The return value is TRUE if the function is successful; otherwise, it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.


EngDeletePath

EngDeletePath deletes a path previously allocated by EngCreatePath.

VOID
  EngDeletePath(
    IN PATHOBJ  *ppo
    );

Parameters

ppo
Points to the PATHOBJ structure to be deleted.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.


EngDeleteSafeSemaphore

EngDeleteSafeSemaphore removes a reference to the specified safe semaphore.

VOID
  EngDeleteSafeSemaphore(
    IN OUT ENGSAFESEMAPHORE  *pssem
    );

Parameters

pssem
Points to the ENGSAFESEMAPHORE structure that contains the safe semaphore from which to delete a reference.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

EngDeleteSafeSemaphore deletes the semaphore only when the last reference to it has been removed.

EngInitializeSafeSemaphore and EngDeleteSafeSemaphore are thread-safe, operating under a lock and maintaining a reference count on the semaphore. This guarantees that only one semaphore is created regardless of the number of simultaneous calls to it, and that the semaphore exists until the last reference to it is released.

Every caller of EngInitializeSafeSemaphore should call EngDeleteSafeSemaphore when it no longer needs the semaphore.

See Also

EngInitializeSafeSemaphore, ENGSAFESEMAPHORE


EngDeleteSemaphore

EngDeleteSemaphore deletes a semaphore object from the system's resource list.

VOID
  EngDeleteSemaphore(
    IN OUT HSEMAPHORE  hsem
    );

Parameters

hsem
Is the handle of the semaphore to be deleted. The semaphore was created in EngCreateSemaphore.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

See Also

EngAcquireSemaphore, EngCreateSemaphore, EngReleaseSemaphore


EngDeleteSurface

EngDeleteSurface deletes the specified surface.

BOOL
  EngDeleteSurface(
    IN HSURF  hsurf
    );

Parameters

hsurf
Identifies the surface to delete. This handle can be an HSURF or HBM.

Return Value

EngDeleteSurface returns TRUE if it is successful in deleting the surface. Otherwise, it returns FALSE and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.


EngDeleteWnd

EngDeleteWnd deletes a WNDOBJ structure.

VOID
  EngDeleteWnd(
    IN WNDOBJ  *pwo
    );

Parameters

pwo
Points to the WNDOBJ structure to be deleted.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

Because deleting a window object involves locking window resources, EngDeleteWnd should be called only in the context of the WNDOBJ_SETUP escape in DrvEscape, or from an MCD or ICD escape.

A driver can call EngDeleteWnd to remove its WNDOBJ structure associated with a window regardless of whether the window continues to exist. This is useful when the driver is being dynamically unloaded by the system while the associated window still exists.

See Also

EngCreateWnd, WNDOBJ


EngDeviceIoControl

EngDeviceIoControl sends a control code to the specified video miniport driver, causing the device to perform the specified operation.

DWORD EngDeviceIoControl(
    IN HANDLE  hDevice,
    IN DWORD  dwIoControlCode,
    IN LPVOID  lpInBuffer,
    IN DWORD  nInBufferSize,
    IN OUT LPVOID  lpOutBuffer,
    IN DWORD  nOutBufferSize,
    OUT LPDWORD  lpBytesReturned
    );

Parameters

hDevice
Is a handle to the device that is to perform the operation.
dwIoControlCode
Specifies the control code for the operation. The I/O controls are listed and described in full in Video I/O Control Codes.
lpInBuffer
Points to a buffer containing data required to perform the operation. This parameter can be NULL if the control code specifies an operation that does not require input data.
nInBufferSize
Specifies the size, in bytes, of lpInBuffer.
lpOutBuffer
Points to a buffer in which the operation's output data is returned. This parameter can be NULL if the control code specifies an operation that does not produce output data.
nOutBufferSize
Specifies the size, in bytes, of lpOutBuffer.
lpBytesReturned
Points to a long word that specifies the actual size, in bytes, of the data returned in lpOutBuffer.

Return Value

The return value is a 32-bit Win32 API-defined error code.

Headers

Declared in winddi.h. Include winddi.h.

Comments

EngDeviceIoControl is used by a display driver to communicate I/O requests to its corresponding miniport driver. This function provides the only communication channel between a display and video miniport driver.


EngDitherColor

EngDitherColor returns a standard 8x8 dither that approximates the specified RGB color.

ULONG
  EngDitherColor(
    IN HDEV  hdev,
    IN ULONG  iMode,
    IN ULONG  rgb,
    OUT ULONG  *pul
    );

Parameters

hdev
Identifies the device. This is the handle that GDI passed to DrvCompletePDEV.
iMode
Determines the palette that GDI should dither against. This parameter can be one of the following values:
Value | Meaning
DM_DEFAULT | Requests that GDI create a dither for the native, default color space of the device. For example, if the device is running at 16bpp, the resulting dither is in a 16bpp format.
DM_MONOCHROME | Requests that GDI create the dither for monochrome color space; that is, the dither is returned as a 1bpp bitmap.

rgb
Specifies the RGB color that is to be dithered. GDI ignores the high byte of this ULONG.
pul
Points to the memory location in which GDI returns the dithering information. The driver must have allocated memory for a standard-format bitmap with dithered brush dimensions of 8x8. The driver must also set the cxDither and cyDither members of the DEVINFO structure to 8.

Return Value

The return value is DCR_DRIVER if the dither values have been calculated by the driver, or DCR_SOLID if the engine should use the best solid color approximation of the color.

Headers

Declared in winddi.h. Include winddi.h.

Comments

EngDitherColor can be called for bitmaps that are 8bpp or higher.

See Also

DrvRealizeBrush


EngEnumForms

EngEnumForms enumerates the forms supported by the specified printer.

BOOL
  EngEnumForms(
    IN HANDLE  hPrinter,
    IN DWORD  Level,
    OUT LPBYTE  pForm,
    IN DWORD  cbBuf,
    OUT LPDWORD  pcbNeeded,
    OUT LPDWORD  pcReturned
    );

Parameters

hPrinter
Is the PDEV handle of the printer for which the forms should be enumerated. This is the handle that is passed as the hDriver parameter of DrvEnablePDEV.
Level
Specifies the version of the structure pointed to by pForm. This value must be 1, which indicates that the enumerated forms are to be returned in FORM_1_INFO structures.
pForm
Points to an array of bytes in which the enumerated FORM_INFO_1 structures are written.
cbBuf
Specifies the size, in bytes, of lpbForms.
pcbNeeded
Is the address of the value that specifies the number of bytes copied into pForm if the copy is completed successfully. If pForm is too small to contain all the enumerated forms' data, this parameter specifies the number of bytes required.
pcReturned
Is the address of the value that specifies the number of FORM_INFO_1 structures copied into pForm.

Return Value

EngEnumForms returns TRUE if all parameters are valid and the enumerated form data is successfully copied into pForm. Otherwise, it returns FALSE and an error message is logged. To get error information, call EngGetLastError.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A printer driver can call EngEnumForms to have GDI obtain the list of forms supported by a particular printer. The enumerated information is returned as an array of FORM_INFO_1 structures (defined in the Platform SDK documentation) pointed to by pForm. If the array pointed to by pForm is not large enough to hold the enumerated data, the requisite array size is instead returned in pcbNeeded.

See Also

DrvEnablePDEV, EngGetLastError


EngEraseSurface

EngEraseSurface calls GDI to erase the surface; a given rectangle on the surface will be filled with the given color.

BOOL
  EngEraseSurface(
    IN SURFOBJ  *pso,
    IN RECTL  *prcl,
    IN ULONG  iColor
    );

Parameters

pso
Points to the surface to erase.
prcl
Points to a rectangle defining which pixels to erase on the surface. This rectangle is exclusive of the bottom and right edges.
iColor
Specifies a color index. This is an index to the value that will be written into each pixel.

Return Value

The return value is TRUE if the function is successful. Otherwise, it is FALSE, and an error code is reported.

Headers

Declared in winddi.h. Include winddi.h.


EngFillPath

EngFillPath fills a path.

BOOL
  EngFillPath(
    IN SURFOBJ  *pso,
    IN PATHOBJ  *ppo,
    IN CLIPOBJ  *pco,
    IN BRUSHOBJ  *pbo,
    IN POINTL  *pptlBrushOrg,
    IN MIX  mix,
    IN FLONG  flOptions
    );

Parameters

pso
Points to a SURFOBJ structure that describes the surface on which to draw.
ppo
Points to a PATHOBJ structure that defines the path to be filled. Use the PATHOBJ_Xxx service routines to enumerate the lines, Bezier curves, and other data that make up the path.
pco
Points to a CLIPOBJ structure. Use the CLIPOBJ_Xxx service routines to enumerate the clip region as a set of rectangles.
pbo
Points to a BRUSHOBJ structure that defines the pattern and colors with which to fill.
pptlBrushOrg
Points to a POINTL structure defining the brush origin to use to align the brush pattern on the device.
mix
Defines the foreground and background raster operations to use for the brush.
flOptions
Specifies the mode to use when filling the path. This value should be FP_WINDINGMODE or FP_ALTERNATEMODE. All other flags should be ignored. For more information about these modes, see Path Fill Modes.

Return Value

The return value is TRUE if GDI is able to fill the path. Otherwise, it is FALSE, and an error code is not logged. If an error is encountered, the return value is FALSE, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Whenever GDI fills a path on a device-managed surface, it can call this entry point depending on a comparison of the fill requirements and the following GCAPS bits: GCAPS_BEZIERS, GCAPS_ALTERNATEFILL, and GCAPS_WINDINGFILL.

See Also

BRUSHOBJ, CLIPOBJ, PATHOBJ, SURFOBJ


EngFindImageProcAddress

EngFindImageProcAddress returns the address of a function within an executable module.

PVOID
  EngFindImageProcAddress(
    IN HANDLE  hModule,
    IN LPSTR  lpProcName
    );

Parameters

hModule
Is a handle to the image in which the function can be found. This handle was obtained by calling EngLoadImage. This parameter can be NULL on Windows NT 4.0 SP3 and later versions, which includes Windows 2000 and later operating system versions.
lpProcName
Points to the string that specifies the name of the function to be located.

Return Value

EngFindImageProcAddress returns the base address of the function's executable code if it successfully locates the function. Otherwise, it returns NULL.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A driver must previously have loaded the image into kernel-mode through a call to EngLoadImage.

The function identified by lpProcName must be exported by the loaded module. This is accomplished by using the EXPORTS key in the module's .DEF file.

A driver cannot call EngFindImageProcAddress with hModule set to NULL on any version of Windows NT 4.0 prior to SP3. Consequently, the driver must do version checking to ensure that the system is running that version or Windows 2000 or later. Specifically, if the iEngineVersion value passed to the driver's DrvEnableDriver routine is greater than or equal to DDI_DRIVER_VERSION_SP3, the driver can call EngFindImageProcAddress with a NULL value for hModule.

To obtain the address of a GDI service routine that is new to Windows 2000 and later operating system versions, the driver can call EngFindImageProcAddress with the function's string name and hModule set to NULL. The lpProcName parameter can be the text string equivalent of any of the following functions when hModule is NULL:

BRUSHOBJ_hGetColorTransform | EngAlphaBlend
EngClearEvent | EngControlSprites
EngCreateEvent | EngDeleteEvent
EngDeleteFile | EngDeleteSafeSemaphore
EngDeleteWnd | EngDitherColor
EngGetPrinterDriver | EngGradientFill
EngHangNotification | EngInitializeSafeSemaphore
EngLockDirectDrawSurface | EngLpkInstalled
EngMapEvent | EngMapFile
EngMapFontFileFD | EngModifySurface
EngMovePointer | EngPlgBlt
EngQueryDeviceAttribute | EngQueryPalette
EngQuerySystemAttribute | EngReadStateEvent
EngRestoreFloatingPointState | EngSaveFloatingPointState
EngSetEvent | EngSetPointerShape
EngSetPointerTag | EngStretchBltROP
EngTransparentBlt | EngUnlockDirectDrawSurface
EngUnmapEvent | EngUnmapFile
EngUnmapFontFileFD | EngWaitForSingleObject
FONTOBJ_pfdg | FONTOBJ_pjOpenTypeTablePointer
FONTOBJ_pQueryGlyphAttrs | FONTOBJ_pwszFontFilePaths
HeapVidMemAllocAligned | HT_Get8BPPMaskPalette
STROBJ_bEnumPositionsOnly | STROBJ_bGetAdvanceWidths
STROBJ_fxBreakExtra | STROBJ_fxCharacterExtra
VidMemFree | XLATEOBJ_hGetColorTransform

See Also

DrvEnableDriver, EngLoadImage


EngFindResource

EngFindResource determines the location of a resource in a module.

PVOID
  EngFindResource(
    IN HANDLE  h,
    IN int  iName,
    IN int  iType,
    OUT PULONG  pulSize
    );

Parameters

h
Is a handle to the module that contains the resource. This handle is obtained from EngLoadModule.
iName
Is an integer identifier representing the name of the resource being looked up.
iType
Is an integer identifier representing the type of the resource being looked up.
pulSize
Points to a ULONG in which the resource's size, in bytes, is returned.

Return Value

The return value is a pointer to the address of the specified resource. NULL is returned if an error occurs.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The size of a successfully located resource is returned in pulSize.

See Also

EngLoadModule, EngMapModule


EngFntCacheAlloc

EngFntCacheAlloc allocates storage for a font that is to be stored in cached memory.

PVOID
  EngFntCacheAlloc(
    IN ULONG  FastCheckSum,
    IN ULONG  ulSize
    );

Parameters

FastCheckSum
Specifies the checksum for the font.
ulSize
Specifies the number of bytes of storage to allocate.

Return Value

On success, this function returns the address of the cache of font data. Otherwise, it returns NULL.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function is available in Windows XP and later.

When the font driver calls this function, the font engine allocates memory in which the font driver stores font data.

The font engine calls the font driver's DrvLoadFontFile entry point when a font file is first loaded. It is in this call that the font driver receives a value for FastCheckSum, which it subsequently uses when it calls this function.

See Also

EngFntCacheFault, EngFntCacheLookUp, DrvLoadFontFile


EngFntCacheFault

EngFntCacheFault reports an error to the font engine if the font driver encountered an error reading from or writing to a font data cache.

VOID
  EngFntCacheFault(
    IN ULONG  ulFastCheckSum,
    IN ULONG  iFaultMode
    );

Parameters

ulFastCheckSum
Specifies the checksum for the font.
iFaultMode
Specifies the type of error that occurred. This parameter can be one of the following values:
Value | Meaning
ENG_FNT_CACHE_READ_FAULT | An error occurred during retrieval.
ENG_FNT_CACHE_WRITE_FAULT | An error occurred during storage.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function is available in Windows XP and later.

If an error occurrs while the font driver was reading from or writing to the font data cache, it should report the error to the font engine by a call to this function.

The font engine calls the font driver's DrvLoadFontFile entry point when a font file is first loaded. It is in this call that the font driver receives a value for ulFastCheckSum, which it subsequently uses when it calls this function.

See Also

EngFntCacheAlloc, EngFntCacheLookUp, DrvLoadFontFile


EngFntCacheLookUp

EngFntCacheLookUp retrieves the address of cached font file data.

PVOID
  EngFntCacheLookUp(
    IN ULONG  FastCheckSum,
    OUT ULONG  *pulSize
    );

Parameters

FastCheckSum
Specifies the checksum for the font.
pulSize
Points to a memory location that will receive the size, in bytes, of the data.

Return Value

On success, this function returns a pointer to the cached data. Otherwise, it returns NULL.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function is available in Windows XP and later.

The font engine calls the font driver's DrvLoadFontFile entry point when a font file is first loaded. It is in this call that the font driver receives a value for FastCheckSum, which it subsequently uses when it calls this function.

See Also

EngFntCacheAlloc, EngFntCacheFault, DrvLoadFontFile


EngFreeMem

EngFreeMem deallocates a block of system memory.

VOID
  EngFreeMem(
    IN PVOID  Mem
    );

Parameters

Mem
Points to the block of paged pool memory being deallocated.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

This routine releases memory allocated by EngAllocMem. The memory block must not be accessed after it is freed.


EngFreeModule

EngFreeModule unmaps a file from system memory.

VOID
  EngFreeModule(
    IN HANDLE  h
    );

Parameters

h
Is a handle that identifies the memory-mapped file to be freed. This handle was obtained from EngLoadModule or EngLoadModuleForWrite.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

See Also

EngLoadModule, EngLoadModuleForWrite, EngMapModule


EngFreePrivateUserMem

EngFreePrivateUserMem deallocates a block of private user memory.

VOID
  EngFreePrivateUserMem(
    IN PDD_SURFACE_LOCAL  psl,
    IN PVOID  pv
    );

Parameters

psl
Points to the DD_SURFACE_LOCAL structure representing the DirectDraw surface with which the memory is associated.
pv
Points to the block of user memory being deallocated.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This routine deallocates a block of memory allocated by EngAllocPrivateUserMem.

See Also

DD_SURFACE_LOCAL, EngAllocPrivateUserMem, EngAllocUserMem, EngFreeUserMem


EngFreeUserMem

EngFreeUserMem deallocates a block of user memory.

VOID
  EngFreeUserMem(
    IN PVOID  pv
    );

Parameters

pv
Points to the block of user memory being deallocated.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

This routine releases memory allocated by EngAllocUserMem. The memory block must not be accessed after it is freed.


EngGetCurrentCodePage

EngGetCurrentCodePage returns the system's default OEM and ANSI code pages.

VOID
  EngGetCurrentCodePage(
    OUT PUSHORT  OemCodePage,
    OUT PUSHORT  AnsiCodePage
    );

Parameters

OemCodePage
Points to a USHORT in which the system's default OEM code page is returned.
AnsiCodePage
Points to a USHORT in which the system's default ANSI code page is returned.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

EngGetCurrentCodePage returns the default code pages that are used by the system to translate from ANSI to Unicode. These values are set at boot time according to locale settings.

See Also

STROBJ_dwGetCodePage


EngGetCurrentProcessId

EngGetCurrentProcessId identifies an application's current process.

HANDLE
  EngGetCurrentProcessId(
    VOID
    );

Return Value

EngGetCurrentProcessId returns the 4-byte identifier of the application's process.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function is available in Windows XP and later.

Callers of EngGetCurrentProcessId should treat the returned ID as a read-only value.

Callers of EngGetCurrentProcessId can be running at any IRQL.

See Also

EngGetCurrentThreadId, EngGetProcessHandle


EngGetDriverName

EngGetDriverName returns the name of the driver's DLL.

LPWSTR
  EngGetDriverName(
    IN HDEV  hdev
    );

Parameters

hdev
Is the GDI handle received by the driver as the hdev parameter for DrvCompletePDEV.

Return Value

EngGetDriverName returns a pointer to the null-terminated string buffer in which the name of the driver's DLL is specified. The system obtains and stores the driver's name from the DRIVER_INFO_2 structure when the driver is first installed through the Win32 AddPrinterDriver routine.

Headers

Declared in winddi.h. Include winddi.h.

See Also

EngGetPrinterDataFileName


EngGetFileChangeTime

EngGetFileChangeTime returns a file's last write time.

BOOL
  EngGetFileChangeTime(
    IN HANDLE  h,
    OUT LARGE_INTEGER  *pChangeTime
    );

Parameters

h
Is a handle that identifies the file whose change time is to be queried.
pChangeTime
Points to a LARGE_INTEGER in which the change time is returned.

Return Value

EngGetFileChangeTime returns TRUE if it succeeds in returning the timestamp; otherwise it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The time returned is specified in system-time format. Absolute system time is the number of 100-nanosecond intervals since the start of 1601.


EngGetFilePath

EngGetFilePath determines the file path associated with the specified font file.

BOOL
  EngGetFilePath(
    IN HANDLE h,
    OUT WCHAR (*pDest)[MAX_PATH+1]
    );

Parameters

h
Specifies the font file handle.
pDest
Points to a buffer that will contain the fully qualified path of the directory containing the font file. The buffer can contain at most MAX_PATH + 1 characters, including the terminating null character. The constant MAX_PATH is defined in windef.h.

Return Value

EngGetFilePath returns TRUE if it succeeds in obtaining the file path of the font file. Otherwise, EngGetFilePath returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

See Also

EngMapFontFileFD


EngGetForm

EngGetForm gets the FORM_INFO_1 details for the specified form.

BOOL
  EngGetForm(
    IN HANDLE  hPrinter,
    IN LPWSTR  pFormName,
    IN DWORD  Level,
    OUT LPBYTE  pForm,
    IN DWORD  cbBuf,
    OUT LPDWORD  pcbNeeded
    );

Parameters

hPrinter
Is a handle that identifies the printer for which the form is being specified.
pFormName
Points to a string that specifies the name of the form.
Level
Specifies the version of the form structure to which pForm points. This value must be 1, which indicates that the form information will be returned in a FORM_INFO_1 structure.
pForm
Points to an array of bytes in which the initialized FORM_INFO_1 structure will be written.
cbBuf
Specifies the size, in bytes, of pForm.
pcbNeeded
Points to a value that specifies the number of bytes copied into pForm if the function succeeds. The value is the number of bytes required to perform the copy if cbBuf is too small.

Return Value

EngGetForm returns TRUE if the form structure is successfully copied into pForm. Otherwise, it logs an error message and returns FALSE. To get the error information, call EngGetLastError.

Headers

Declared in winddi.h. Include winddi.h.

Comments

EngGetForm returns a FORM_INFO_1 structure (described in the Platfrom SDK documentation) containing the form data associated with pFormName. The written data and its size are returned to the caller via pForm and pcbNeeded, respectively. If the array pointed to by pForm is not large enough to hold the form data, the requisite array size is instead returned in pcbNeeded.

To get a list of all supported forms, the printer driver should call EngEnumForms.

See Also

EngGetLastError


EngGetLastError

EngGetLastError returns the last error code logged by GDI for the calling thread.

ULONG
  EngGetLastError(
    VOID
    );

Return Value

The return value is the last error code set by EngSetLastError.

Headers

Declared in winddi.h. Include winddi.h.

Comments

EngGetLastError facilitates communication of GDI and/or driver error conditions to an application.

See Also

EngSetLastError


EngGetPrinter

EngGetPrinter retrieves information about the specified printer.

BOOL
  EngGetPrinter(
    IN HANDLE  hPrinter,
    IN DWORD  dwLevel,
    OUT LPBYTE  pPrinter,
    IN DWORD  cbBuf,
    OUT LPDWORD  pcbNeeded
    );

Parameters

hPrinter
Identifies the printer for which data should be retrieved. This is the handle that is passed as the hDriver parameter of DrvEnablePDEV.
dwLevel
Specifies the version of the structure to which pPrinter points. This parameter can have any of the following values:
Value | Structure Returned via pPrinter
1 | PRINTER_INFO_1
2 | PRINTER_INFO_2
3 | PRINTER_INFO_3
4 | PRINTER_INFO_4
5 | PRINTER_INFO_5

pPrinter
Pointer to the data space in which the printer information structure, identified by dwLevel, is loaded.
cbBuf
Specifies the size, in bytes, of the data space pointed to by pPrinter.
pcbNeeded
Is the return address in which the number of bytes copied is returned if the function succeeds, or in which the number of required bytes is returned if cbBuf is too small.

Return Value

EngGetPrinter returns TRUE upon success; otherwise, it logs an error and returns FALSE. To get error information, call EngGetLastError.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The PRINTER_INFO_X structures are defined in the Platform SDK documentation.

See Also

DrvEnablePDEV


EngGetPrinterData

EngGetPrinterData retrieves configuration data for the specified printer.

DWORD
  EngGetPrinterData(
    IN HANDLE  hPrinter,
    IN LPWSTR  pValueName,
    OUT LPDWORD  pType,
    OUT LPBYTE  pData,
    IN DWORD  nSize,
    OUT LPDWORD  pcbNeeded
    );

Parameters

hPrinter
Is a handle that identifies the printer for which configuration data should be retrieved. This is the handle that is passed as the hDriver parameter of DrvEnablePDEV.
pValueName
Points to a null-terminated string that identifies the data to be retrieved.
pType
Points to a variable that receives the data type stored by EngSetPrinterData. This parameter can be null.
pData
Points to an array of bytes in which the configuration data will be written.
nSize
Specifies the size, in bytes, of pData.
pcbNeeded
Is an address that receives the number of bytes copied into lpbData if the function succeeds. This parameter receives the number of bytes required if nSizef is too small.

Return Value

EngGetPrinterData returns the last logged error message.

Headers

Declared in winddi.h. Include winddi.h.

See Also

DrvEnablePDEV, EngSetPrinterData


EngGetPrinterDataFileName

EngGetPrinterDataFileName retrieves the string name of the printer's data file.

LPWSTR
  EngGetPrinterDataFileName(
    IN HDEV  hdev
    );

Parameters

hdev
Is the GDI handle received by the driver as the hdev parameter for DrvCompletePDEV.

Return Value

EngGetPrinterDataFileName returns a pointer to the null-terminated string buffer in which the name of the printer's data file is specified. The system obtains and stores the printer's data file name from the DRIVER_INFO_2 structure when the driver is first installed through the Win32 AddPrinterDriver routine.

Headers

Declared in winddi.h. Include winddi.h.

See Also

EngGetDriverName


EngGetPrinterDriver

EngGetPrinterDriver retrieves driver data for the specified printer.

BOOL
  EngGetPrinterDriver(
    IN HANDLE  hPrinter,
    IN LPWSTR  pEnvironment,
    IN DWORD  dwLevel,
    OUT BYTE  *lpbDrvInfo,
    IN DWORD  cbBuf,
    OUT DWORD  *pcbNeeded
    );

Parameters

hPrinter
Identifies the printer for which the driver data should be retrieved.
pEnvironment
Points to a null-terminated string that specifies the environment. For example, "Windows NT x86" specifies an NT-based operating system running on an Intel processor. If pEnvironment is NULL, the current environment of the calling driver and client machine is used.
dwLevel
Specifies the version of the structure to which lpbDrvInfo points. This parameter must be one of the following values:
Value | Meaning
1 | GDI writes a DRIVER_INFO_1 structure in the buffer to which lpbDrvInfo points.
2 | GDI writes a DRIVER_INFO_2 structure in the buffer to which lpbDrvInfo points.
3 | GDI writes a DRIVER_INFO_3 structure in the buffer to which lpbDrvInfo points.

lpbDrvInfo
Points to a buffer in which GDI returns the requested DRIVER_INFO_X structure.
cbBuf
Specifies the size, in bytes, of the buffer to which lpbDrvInfo points.
pcbNeeded
Points to a variable in which GDI returns the number of bytes copied into the buffer to which lpbDrvInfo points upon success, or the number of bytes required if cbBuf is too small.

Return Value

EngGetPrinterDriver returns TRUE upon success; otherwise it reports an error and returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A printer driver DLL can work with multiple data files to support different printer models. The printer driver calls EngGetPrinterDriver to determine which data file to use. For example, the Unidrv renderer calls this function to determine the name of a GPD file, and the postscript driver calls this function to determine the name of a PPD file. The DRIVER_INFO_2 and DRIVER_INFO_3 structures contain a full path and filename specifying the location of the data file. The printer driver can then use the returned path and filename to load the data file by calling EngLoadModule with the path and filename as a single argument.

The DRIVER_INFO_X structures are defined in the Platform SDK documentation.

See Also

EngLoadModule


EngGetProcessHandle

EngGetProcessHandle retrieves a handle to the current client process.

HANDLE
  EngGetProcessHandle(
    VOID
    );

Return Value

In Windows 2000 and later, the EngGetProcessHandle function always returns NULL.

Headers

Declared in winddi.h. Include winddi.h.

See Also

EngGetCurrentProcessId, EngGetCurrentThreadId


EngGetType1FontList

EngGetType1FontList retrieves a list of PostScript Type 1 fonts that are installed both locally and remotely.

BOOL
  EngGetType1FontList(
    IN HDEV  hdev,
    OUT TYPE1_FONT  *pType1Buffer,
    IN ULONG  cjType1Buffer,
    OUT PULONG  pulLocalFonts,
    OUT PULONG  pulRemoteFonts,
    OUT LARGE_INTEGER  *pLastModified
    );

Parameters

hdev
Is the GDI handle received by the driver as the hdev parameter for DrvCompletePDEV.
pType1Buffer
Points to an array of TYPE1_FONT structures in which to return the Type 1 font list. This parameter can be null.
cjType1Buffer
Specifies the size, in bytes, of pType1Buffer.
pulLocalFonts
Is the address in which the number of Type 1 fonts on the local system will be written.
pulRemoteFonts
Is the address in which the number of Type 1 fonts on the remote system will be written.
pLastModified
Is the address in which the time stamp corresponding to the last time a Type 1 font was added or removed from the local system will be written.

Return Value

EngGetType1FontList returns TRUE if it succeeds; otherwise, it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

PostScript printer drivers can call EngGetType1FontList to obtain a list of Type 1 fonts available to them. These fonts can then be accessed through the handles returned in the TYPE1_FONT structure.

If pType1Buffer is null, EngGetType1FontList returns only the number of local and remote Type 1 fonts, as well as the time stamp corresponding to the last time a Type 1 font was added or removed locally from the system.

See Also

TYPE1_FONT


EngGradientFill

EngGradientFill shades the specified primitives.

BOOL
  EngGradientFill(
    IN SURFOBJ  *psoDest,
    IN CLIPOBJ  *pco,
    IN XLATEOBJ  *pxlo,
    IN TRIVERTEX  *pVertex,
    IN ULONG  nVertex,
    IN PVOID  pMesh,
    IN ULONG  nMesh,
    IN RECTL  *prclExtents,
    IN POINTL  *pptlDitherOrg,
    IN ULONG  ulMode
    );

Parameters

psoDest
Points to the SURFOBJ structure that identifies the surface on which to draw.
pco
Points to a CLIPOBJ structure. The CLIPOBJ_Xxx service routines are provided to enumerate the clip region as a set of rectangles. This enumeration limits the area of the destination that is modified. Whenever possible, GDI simplifies the clipping involved.
pxlo
Points to a XLATEOBJ structure. This structure indicates how color indices should be translated between 32 bpp RGB format and the destination. The driver is responsible for converting the input COLOR16 color values to RGB.
pVertex
Points to an array of TRIVERTEX structures, with each entry containing position and color information. The TRIVERTEX structure is defined in the Platform SDK documentation.
nVertex
Specifies the number of TRIVERTEX structures in the array to which pVertex points.
pMesh
Points to an array of structures that define the connectivity of the TRIVERTEX elements to which pVertex points.

When rectangles are being drawn, pMesh points to an array of GRADIENT_RECT structures, each of which specifies two TRIVERTEX elements that define a rectangle. The TRIVERTEX elements can represent any diagonally-opposed pair of rectangle vertices. Rectangle drawing is lower-right exclusive. Both TRIVERTEX and GRADIENT_RECT are defined in the Platform SDK documentation.

When triangles are being drawn, pMesh points to an array of GRADIENT_TRIANGLE structures, each of which specifies the three TRIVERTEX elements that define a triangle. Triangle drawing is lower-right exclusive. The GRADIENT_TRIANGLE structure is defined in the Platform SDK documentation.

nMesh
Specifies the number of elements in the array to which pMesh points.
prclExtents
Points to a RECTL structure that defines the area in which the gradient drawing is to occur. The points are specified in the coordinate system of the destination surface. This parameter is useful in estimating the size of the drawing operations.
pptlDitherOrg
Points to a POINTL structure that defines the origin on the surface for dithering. The upper-left pixel of the dither pattern is aligned with this point.
ulMode
Specifies the current drawing mode and how to interpret the array to which pMesh points. This parameter can be one of the following values:
GRADIENT_FILL_RECT_H
The pMesh parameter points to an array of GRADIENT_RECT structures. Each rectangle is to be shaded from left to right.
GRADIENT_FILL_RECT_V
The pMesh parameter points to an array of GRADIENT_RECT structures. Each rectangle is to be shaded from top to bottom.
GRADIENT_FILL_TRIANGLE
The pMesh parameter points to an array of GRADIENT_TRIANGLE structures.

Return Value

EngGradientFill returns TRUE upon success. Otherwise, it reports an error and returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The driver should call EngGradientFill if it has hooked DrvGradientFill and it is called to do something that it does not support.

The formulas used to compute the color value at each pixel depend on the value of ulMode as follows:

GRADIENT_FILL_RECT_H
The rectangle's top-left point is V1 and the bottom-right point is V2. Point P is inside the rectangle. The color at point P is given by:
RedP =   (RedV2 * (Px - V1x) + RedV1 * (V2x - Px)) / (V2x-V1x)
GreenP = (GreenV2 * (Px - V1x) + GreenV1 * (V2x - Px)) / (V2x-V1x)
BlueP =  (BlueV2 * (Px - V1x) + BlueV1 * (V2x - Px)) / (V2x-V1x)
GRADIENT_FILL_RECT_V
The rectangle's top-left point is V1 and the bottom-right point is V2. Point P is inside the rectangle. The color at point P is given by:
RedP   = (RedV2 * (Py-V1y) + RedV1 * (V2y - Py)) / (V2y-V1y)
GreenP = (GreenV2 * (Py-V1y) + GreenV1 * (V2y - Py)) / (V2y-V1y)
BlueP  = (BlueV2 * (Py-V1y) + BlueV1 * (V2y - Py)) / (V2y-V1y)
GRADIENT_FILL_TRIANGLE
The triangle's vertices are defined as V1, V2, and V3. Point P is inside the triangle. Draw lines from P to V1, V2, and V3 to form three sub-triangles. Let ai denote the area of the triangle opposite Vi for i=1,2,3. The color at point P is computed as:
RedP   = (RedV1 * a1 + RedV2 * a2 + RedV3 * a3) / (a1+a2+a3)
GreenP = (GreenV1 * a1 + GreenV2 * a2 + GreenV3 * a3) / (a1+a2+a3)
BlueP  = (BlueV1 * a1 + BlueV2 * a2 + BlueV3 * a3) / (a1+a2+a3)

GDI ignores the alpha value of the vertices, leaving the alpha channel unchanged for surfaces that support alpha.

See Also

DrvGradientFill


EngHangNotification

EngHangNotification notifies the system that a specified device is inoperable or unresponsive.

ULONG EngHangNotification(
  IN HDEV  hDev,
  IN PVOID  Reserved
  );

Parameters

hDev
Identifies the physical device that has hung. This parameter is the GDI handle received by the driver's DrvCompletePDEV entry point.
Reserved
Is reserved and must be set to NULL.

Return Value

EngHangNotification returns one of the following values:

Value | Meaning
EHN_ERROR | The device did not recover from the error.
EHN_RESTORED | The device was restored to working order.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function is available in Windows XP and later.

A driver should make this call any time it detects that the hardware is inoperable or unresponsive. If EngHangNotification returns EHN_RESTORED, the driver should retry the operation that detected the inoperable state; otherwise the driver should fail the current call as soon as possible. Any subsequent driver operations that detect a problem should again call EngHangNotification.

See Also

DrvCompletePDEV, DrvResetDevice


EngInitializeSafeSemaphore

EngInitializeSafeSemaphore initializes the specified safe semaphore.

BOOL
  EngInitializeSafeSemaphore(
    OUT ENGSAFESEMAPHORE  *pssem
    );

Parameters

pssem
Points to the driver-allocated ENGSAFESEMAPHORE structure to be initialized.

Return Value

EngInitializeSafeSemaphore returns TRUE upon success. Otherwise, it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

EngInitializeSafeSemaphore and EngDeleteSafeSemaphore are thread-safe, operating under a lock and maintaining a reference count on the semaphore. This guarantees that only one semaphore is created regardless of the number of simultaneous calls to it, and that the semaphore exists until the last reference to it is released.

Once the safe semaphore is initialized, the driver can call EngAcquireSemaphore and EngReleaseSemaphore with the hsem member of the ENGSAFESEMAPHORE structure for synchronization.

Callers of EngInitializeSafeSemaphore should call EngDeleteSafeSemaphore when they no longer need the semaphore.

See Also

EngAcquireSemaphore, EngDeleteSafeSemaphore, EngReleaseSemaphore, EngIsSemaphoreOwned, EngIsSemaphoreOwnedByCurrentThread, ENGSAFESEMAPHORE


EngIsSemaphoreOwned

EngIsSemaphoreOwned determines whether any thread holds the specified semaphore.

BOOL
  EngIsSemaphoreOwned(
    IN HSEMAPHORE  hsem
    );

Parameters

hsem
Specifies a handle to the semaphore.

Return Value

EngIsSemaphoreOwned returns TRUE if any thread holds the specified semaphore, and FALSE if no thread holds it.

Headers

Declared in winddi.h. Include winddi.h.

See Also

EngAcquireSemaphore, EngCreateSemaphore, EngReleaseSemaphore, EngIsSemaphoreOwnedByCurrentThread


EngIsSemaphoreOwnedByCurrentThread

EngIsSemaphoreOwnedByCurrentThread determines whether the currently executing thread holds the specified semaphore.

BOOL
  EngIsSemaphoreOwnedByCurrentThread(
    IN HSEMAPHORE  hsem
    );

Parameters

hsem
Specifies a handle to a semaphore.

Return Value

EngIsSemaphoreOwnedByCurrentThread returns TRUE if the currently executing thread holds the specified semaphore, and FALSE if it does not.

Headers

Declared in winddi.h. Include winddi.h.

See Also

EngAcquireSemaphore, EngCreateSemaphore, EngReleaseSemaphore, EngIsSemaphoreOwned


EngLineTo

EngLineTo draws a single, solid, integer-only cosmetic line.

BOOL
  EngLineTo(
    SURFOBJ  *pso,
    CLIPOBJ  *pco,
    BRUSHOBJ  *pbo,
    LONG  x1,
    LONG  y1,
    LONG  x2,
    LONG  y2,
    RECTL  *prclBounds,
    MIX  mix
    );

Parameters

pso
Points to a SURFOBJ structure that describes the surface on which to draw.
pco
Points to a CLIPOBJ structure that defines the clip region in which the rendering must be done. No pixels can be affected outside this clip region.
pbo
Points to a BRUSHOBJ structure that specifies the brush to use when drawing the line.
x1, y1
Specify the integer x- and y-coodinates of the line's beginning point.
x2, y2
Specify the integer x- and y-coordinates of the line's end point.
prclBounds
Points to an integer rectangle that bounds the unclipped line. Drivers that support hardware line drawing can use this rectangle to quickly determine whether the line fits in a coordinate space small enough to be rendered by the hardware.
mix
Defines how the incoming pattern should be mixed with the data already on the device surface. The low-order byte defines the raster operation. For more information about raster operation codes, see the Platform SDK documentation.

Return Value

EngLineTo returns TRUE if it succeeds; otherwise, it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The driver that has hooked DrvLineTo can call EngLineTo when the rendering surface is a device-independent bitmap (DIB).

See Also

BRUSHOBJ, CLIPOBJ, DrvLineTo, SURFOBJ


EngLoadImage

EngLoadImage loads the specified executable image into kernel-mode memory.

HANDLE
  EngLoadImage(
    IN LPWSTR  pwszDriver
    );

Parameters

pwszDriver
Points to a null-terminated string that names the file containing the executable image to be loaded.

Return Value

If EngLoadImage succeeds, the return value is a handle to the image that was loaded. Otherwise, this function returns NULL.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A driver can use EngLoadImage to map an executable image into kernel-mode memory. For example, a printer driver can call EngLoadImage to load a minidriver.

EngLoadImage requires that the image file to be loaded have a .dll suffix. The driver must include this suffix in the pwszDriver string.

To execute a section of code within the loaded image, the driver should obtain the function address from EngFindImageProcAddress.

The file identified by pwszDriver must be located in the %SystemRoot%\System32 directory or within a directory found in the directory hierarchy under %SystemRoot%\System32.

Drivers that need to load a module as data only should call EngLoadModule or EngLoadModuleForWrite instead of this function.

See Also

EngLoadModule, EngLoadModuleForWrite, EngUnloadImage


EngLoadModule

EngLoadModule loads the specified data module into system memory for reading.

HANDLE
  EngLoadModule(
    IN LPWSTR  pwsz
    );

Parameters

pwsz
Points to a null-terminated string that contains the name of the data file to be loaded.

Return Value

If EngLoadModule succeeds, the return value is a handle to the module that was loaded. Otherwise, NULL is returned.

Headers

Declared in winddi.h. Include winddi.h.

Comments

EngLoadModule loads a data file into system memory with read-only permission. To access the loaded module, the driver should call EngMapModule with the handle returned by this function.

The file identified by pwsz must be located in the %SystemRoot%\System32 directory or within a directory found in the directory hierarchy under %SystemRoot%\System32.

To load a writable module, the driver should call EngLoadModuleForWrite. Drivers that need to load an image as executable code should call EngLoadImage instead of this function.

See Also

EngFreeModule, EngLoadModuleForWrite, EngMapModule


EngLoadModuleForWrite

EngLoadModuleForWrite loads the specified executable module into system memory for writing.

HANDLE
  EngLoadModuleForWrite(
    IN LPWSTR  pwsz,
    IN ULONG  cjSizeOfModule
    );

Parameters

pwsz
Points to a null-terminated string that contains the name of the file to be loaded.
cjSizeOfModule
Specifies the size, in bytes, of the module to be loaded.

Return Value

If EngLoadModuleForWrite succeeds, the return value is a handle to the module that was loaded. Otherwise, NULL is returned.

Headers

Declared in winddi.h. Include winddi.h.

Comments

EngLoadModuleForWrite loads a data file into system memory with write permission. To access the loaded module, the driver should call EngMapModule with the handle returned by this function.

EndLoadModuleForWrite loads the file into memory that is the same size as the file when cjSizeOfModule is zero. If cjSizeOfModule is greater than zero, GDI extends or truncates the file to be exactly cjSizeOfModule bytes in size before loading it. No assumptions should be made about the contents of memory that extend beyond the file when cjSizeOfModule is greater than the file's original size.

The file identified by pwsz must be located in the %SystemRoot%\System32 directory or within a directory found in the directory hierarchy under %SystemRoot%\System32.

To load a module with read-only permissions, the driver should call EngLoadModule. Drivers that need to load an image as executable code should call EngLoadImage instead of this function.

See Also

EngFreeModule, EngLoadImage, EngLoadModule, EngMapModule


EngLockDirectDrawSurface

EngLockDirectDrawSurface locks the kernel-mode handle of a DirectDraw® surface.

PDD_SURFACE_LOCAL
  EngLockDirectDrawSurface(
    IN HANDLE  hSurface
    );

Parameters

hSurface
Specifies the handle of the surface to be locked.

Return Value

EngLockDirectDrawSurface returns a pointer to a DD_SURFACE_LOCAL structure that describes the surface information upon success. Otherwise, it returns a NULL pointer.

Headers

Declared in winddi.h. Include winddi.h.

Comments

EngLockDirectDrawSurface allows driver writers to lock DirectDraw surfaces. Locking the handle guarantees synchronized behavior and preserves the handle from being deleted by other threads in the system.

Currently, the driver receives DirectDraw surface handles only from the Direct3D® texturing interface. Consequently, only drivers that perform texturing need to lock texture surfaces.

Upon completion of texturing, the driver must release the locked handle by calling EngUnlockDirectDrawSurface.

See Also

EngUnlockDirectDrawSurface


EngLockDriverObj

EngLockDriverObj creates an exclusive lock on this object for the calling thread.

DRIVEROBJ
  *EngLockDriverObj(
    IN HDRVOBJ hdo
    );

Parameters

hdo
Is a handle to the DRIVEROBJ structure to be locked by GDI.

Return Value

EngLockDriverObj returns a DRIVEROBJ structure if the function is successful. If the operation fails, it returns NULL.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function will fail if the handle is invalid, if the object is already locked by another thread, or if the handle isn't owned by the calling process.


EngLockSurface

EngLockSurface creates a user object for a given surface. This function gives drivers access to surfaces they create.

SURFOBJ
  *EngLockSurface(
    IN HSURF  hsurf
    );

Parameters

hsurf
Is a handle that identifies the surface to lock.

Return Value

The return value is a pointer to a SURFOBJ structure if the function is successful. Otherwise, this function returns NULL.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function gives drivers access to surfaces they create.

The driver is responsible for unlocking the surface when it no longer needs it. Surfaces should be locked only for very short periods of time.

Use the EngUnlockSurface function to unlock the surface.

See Also

SURFOBJ, EngUnlockSurface


EngLpkInstalled

EngLpkInstalled determines whether the language pack is installed on the system.

BOOL
  EngLpkInstalled(
    VOID
    );

Return Value

EngLpkInstalled returns TRUE when the language pack is installed. Otherwise, it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.


EngMapEvent

EngMapEvent maps a user-mode event object to kernel mode.

PEVENT
  EngMapEvent(
    IN HDEV  hDev,
    IN HANDLE  hUserObject,
    IN PVOID  Reserved1,
    IN PVOID  Reserved2,
    IN PVOID  Reserved3
    );

Parameters

hDev
Specifies the GDI handle of the physical device associated with the event. This is the GDI handle passed as the hdev parameter to the driver's DrvCompletePDEV function.
hUserObject
Specifies the user-mode event handle to be mapped.
Reserved1
Is reserved for system use, and must be set to NULL.
Reserved2
Is reserved for system use, and must be set to NULL.
Reserved3
Is reserved for system use, and must be set to NULL.

Return Value

EngMapEvent returns a pointer to an event object on success. Otherwise, it returns NULL.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function is available in Windows XP and later.

After successfully mapping the user event, EngMapEvent automatically sets the event object to the signaled state, attempts to satisfy as many waits as possible, and then resets the event object to the nonsignaled state.

A mapped event provides a mechanism by which an application can wait for a kernel-mode graphics operation to complete. The display driver or video miniport driver signals the application when it is done using the resource for which the event was mapped, thus freeing the application to use the resource.

Display and miniport drivers cannot wait on mapped events, but can set or clear them.

The driver can also perform its own cleanup by calling EngUnmapEvent on the event object returned by EngMapEvent.

See Also

DrvCompletePDEV, EngUnmapEvent


EngMapFile

EngMapFile creates or opens a file and maps it into system space.

PVOID
  EngMapFile(
    IN LPWSTR  pwsz,
    IN ULONG  cjSize,
    OUT ULONG_PTR  *piFile
    );

Parameters

pwsz
Points to a null-terminated string that contains the fully qualified name of the file to be mapped. An example of a fully qualified file name string is L"\\??\\c:\\test.dat".
cjSize
Specifies the number of bytes of the file to map.
piFile
Points to the identifier of the mapped file. When the mapped file needs to be released, this value should be passed to EngUnmapFile.

Return Value

EngMapFile returns a pointer to the mapped view of the file if it succeeds. Otherwise, it returns NULL.

Headers

Declared in winddi.h. Include winddi.h.

Comments

If the file already exists, EngMapFile opens and maps it for read/write. If the file does not exist, EngMapFile creates and maps it for read/write.

The value of cjSize affects the mapping of the file as follows:

  • When cjSize is zero, GDI maps the file in its entirety.
  • When cjSize is greater than the size of the file, GDI expands the file to cjSize bytes in size before mapping it in system memory. No assumptions should be made about the contents of memory that extend beyond the file's original size.
  • When cjSize is less than the size of the file, GDI truncates the file to cjSize bytes in size before mapping it into system memory.

A driver can read and write to the file through the returned pointer.

See Also

EngDeleteFile, EngUnmapFile


EngMapFontFile

EngMapFontFile is obsolete. Use EngMapFontFileFD instead.

BOOL
  EngMapFontFile(
    ULONG_PTR  iFile,
    PULONG  *ppjBuf,
    ULONG  *pcjBuf
    );

Headers

Declared in winddi.h. Include winddi.h.


EngMapFontFileFD

EngMapFontFileFD maps a font file into system memory, if necessary, and returns a pointer to the base location of the font data in the file.

BOOL
  EngMapFontFileFD(
    IN ULONG_PTR  iFile,
    OUT PULONG  *ppjBuf,
    OUT ULONG  *pcjBuf
    );

Parameters

iFile
Is a caller-supplied file handle that identifies the font file to be mapped. This handle must have been received previously as input to DrvLoadFontFile.
ppjBuf
Points to a location in which the function returns the mapped file's base memory address.
pcjBuf
Points to a location in which the function returns the mapped file's size, in bytes.

Return Value

EngMapFontFileFD returns TRUE if it succeeds; otherwise, it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The EngMapFontFileFD function is provided so font drivers can map a font file into memory and access the file's data. If the font file has not yet been memory-mapped, EngMapFontFileFD loads the font data into system memory before returning ppjBuf and pcjBuf to the driver. If the file is already mapped, the function just returns the file's ppjBuf and pcjBuf values.

See Also

DrvLoadFontFile, EngUnmapFontFileFD


EngMapModule

EngMapModule returns the address and size of a file that was loaded by EngLoadModule, EngLoadModuleForWrite, EngLoadImage, or EngMapFile.

PVOID
  EngMapModule(
    IN HANDLE  h,
    OUT PULONG  pSize
    );

Parameters

h
Is a handle to the file to be memory-mapped.
pSize
Points to a memory location that will receive the size, in bytes, of the memory-mapped file.

Return Value

EngMapModule returns a pointer to the view of the file identified by h. The file's size is returned in pSize.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A driver can open and read a file using EngLoadModule and EngMapModule.

See Also

EngFreeModule, EngLoadModule, EngLoadModuleForWrite, EngLoadImage, EngMapFile


EngMarkBandingSurface

EngMarkBandingSurface marks the specified surface as a banding surface.

BOOL
  EngMarkBandingSurface(
    IN HSURF  hsurf
    );

Parameters

hsurf
Is a caller-supplied handle that identifies the surface to mark as a banding surface.

Return Value

The return value is always TRUE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

If a printer graphics DLL uses GDI-managed surfaces, it must call EngMarkBandingSurface if it cannot create a surface (by calling EngCreateBitmap) that is large enough to hold an entire physical page's bitmap. Both EngCreateBitmap and EngMarkBandingSurface should be called from within the printer graphics DLL's DrvEnableSurface function.

The handle supplied for hsurf must be a bitmap handle returned by EngCreateBitmap.

If a printer graphics DLL calls EngMarkBandingSurface, it must define DrvStartBanding and DrvNextBand functions.


EngModifySurface

EngModifySurface notifies GDI about the attributes of a surface that was created by the driver.

BOOL
  EngModifySurface(
    IN HSURF  hsurf,
    IN HDEV  hdev,
    IN FLONG  flHooks,
    IN FLONG  flSurface,
    IN DHSURF  dhsurf,
    IN VOID*  pvScan0,
    IN LONG  lDelta,
    IN VOID*  pvReserved
    );

Parameters

hsurf
Identifies the surface to be modified. This parameter is a surface handle returned by EngCreateDeviceBitmap or EngCreateDeviceSurface, or from the hsurf member of the SURFOBJ structure.
hdev
Identifies the device with which the surface is to be associated. This is the handle that GDI passed to DrvCompletePDEV.
flHooks
Is a set of flags that control the functions the driver can hook whenever GDI drawing occurs on the specified surface. This can be a bitwise OR of any of the HOOK_Xxx values listed on the EngAssociateSurface reference page.
flSurface
Is a set of flags that describe the surface's attributes. Currently, the driver should set this to be MS_NOTSYSTEMMEMORY when the surface is located in video memory.
dhsurf
Identifies the surface to the driver. The driver can set this to anything; GDI sets the dhsurf member of the resulting surface's SURFOBJ structure to this value if the function is successful.
pvScan0
Points to the virtual address of the start of the bitmap.
lDelta
Is the virtual address stride of the bitmap.
pvReserved
Is reserved and must always be set to NULL.

Return Value

EngModifySurface returns TRUE upon success; otherwise it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

EngModifySurface allows the driver to modify a device-managed surface and inform GDI of this surface's attributes. This allows drivers to convert the destination surface from being opaque to non-opaque, thus allowing GDI to draw on the surface.

The DIB engine uses pvScan0 and lDelta to draw directly to the surface. When these parameters are NULL, the surface is opaque to GDI, and GDI will revert to calling DrvCopyBits for drawing operations not hooked by the driver.

See Also

EngAssociateSurface


EngMovePointer

EngMovePointer moves the engine-managed pointer on the device.

VOID
  EngMovePointer(
    IN SURFOBJ  *pso,
    IN LONG  x,
    IN LONG  y,
    IN RECTL  *prcl
    );

Parameters

pso
Points to a SURFOBJ structure that describes the display device surface on which the pointer is to be moved.
x, y
Specify the x-and y- coordinates on the display where the hot spot of the pointer should be positioned.

A negative x value indicates that the pointer should be removed from the display because drawing is about to occur at its present location. If the pointer has been removed from the display and the x value is non-negative, the pointer should be restored.

prcl
Points to a RECTL structure defining an area that bounds all pixels affected by the pointer on the display. The driver should pass the prcl parameter received by its DrvMovePointer function. GDI will not draw in this rectangle without first removing the pointer from the screen. This parameter can be NULL.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

EngMovePointer must not be called while any thread is drawing in the display driver.

See Also

DEVINFO, DrvMovePointer, EngSetPointerShape, SURFOBJ


EngMulDiv

EngMulDiv multiplies two 32-bit values and then divides the 64-bit result by a third 32-bit value.

int
  EngMulDiv(
    IN int  a,
    IN int  b,
    IN int  c
    );

Parameters

a
Specifies the 32-bit signed multiplicand.
b
Specifies the 32-bit signed multiplier.
c
Specifies the 32-bit signed divisor by which the result of a*b is to be divided.

Return Value

EngMulDiv returns the signed 32-bit result of the multiplication and division. The return value is rounded up or down to the nearest integer.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Drivers should not pass a zero divisor to EngMulDiv.


EngMultiByteToUnicodeN

EngMultiByteToUnicodeN converts the specified ANSI source string into a Unicode string using the current ANSI code page.

VOID
  EngMultiByteToUnicodeN(
    OUT LPWSTR  UnicodeString,
    IN ULONG  MaxBytesInUnicodeString,
    OUT PULONG  BytesInUnicodeString,
    IN PCHAR  MultiByteString,
    IN ULONG  BytesInMultiByteString
    );

Parameters

UnicodeString
Points to the buffer in which the resultant Unicode string is returned.
MaxBytesInUnicodeString
Supplies the maximum number of bytes to be written to UnicodeString. If this value is too small, causing UnicodeString to be a truncated equivalent of MultiByteString, no error condition results.
BytesInUnicodeString
Points to a ULONG in which the number of bytes written to UnicodeString is returned.
MultiByteString
Points to the ANSI source string that is to be converted to Unicode.
BytesInMultiByteString
Specifies the number of bytes in MultiByteString.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

See Also

EngMultiByteToWideChar, EngUnicodeToMultiByteN


EngMultiByteToWideChar

EngMultiByteToWideChar converts an ANSI source string into a wide character string using the specified code page.

INT
  EngMultiByteToWideChar(
    IN UINT  CodePage,
    OUT LPWSTR  WideCharString,
    IN INT  BytesInWideCharString,
    IN LPSTR  MultiByteString,
    IN INT  BytesInMultiByteString
    );

Parameters

CodePage
Specifies the code page to use to perform the translation.
WideCharString
Points to the buffer into which the translated character string is copied.
BytesInWideCharString
Specifies the size, in bytes, of WideCharString. If WideCharString is not large enough to contain the translation, EngMultiByteToWideChar truncates the string, and does not report an error.
MultiByteString
Points to the buffer containing the multibyte string to be translated.
BytesInMultiByteString
Specifies the number of bytes in MultiByteString.

Return Value

The EngMultiByteToWideChar function returns the number of bytes it converted to wide character form, if successful. Otherwise, the function returns -1.

Headers

Declared in winddi.h. Include winddi.h.

See Also

EngUnicodeToMultiByteN, EngWideCharToMultiByte


EngPaint

EngPaint causes GDI to paint a specified region.

BOOL
  EngPaint(
    IN SURFOBJ  *pso,
    IN CLIPOBJ  *pco,
    IN BRUSHOBJ  *pbo,
    IN POINTL  *pptlBrushOrg,
    IN MIX  mix
    );

Parameters

pso
Points to a SURFOBJ structure that describes the surface on which to draw.
pco
Points to a CLIPOBJ structure that defines the area to be painted. The CLIPOBJ_Xxx service routines are provided to enumerate the clip region as a set of rectangles.
pbo
Points to a BRUSHOBJ structure that defines the pattern and colors with which to fill.
pptlBrushOrg
Points to a POINTL structure that defines the brush origin used to align the brush pattern on the device.
mix
Defines the foreground and background raster operations to use for the brush.

Return Value

The return value is TRUE if the function is successful. Otherwise, it is FALSE, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Vector device drivers can implement this function with the help of EngCreatePath and PATHOBJ_Xxx service routines.

The mix mode defines how the incoming pattern should be mixed with the data already on the device surface. The MIX data type consists of two ROP2 values packed into a single ULONG. The low-order byte defines the foreground raster operation; the next byte defines the background raster operation. For more information about raster operation codes, see the Platform SDK documentation.

See Also

BRUSHOBJ, CLIPOBJ, EngCreatePath, PATHOBJ, SURFOBJ


EngPlgBlt

EngPlgBlt causes GDI to perform a rotate bit-block transfer.

BOOL
  EngPlgBlt(
    IN SURFOBJ  *psoTrg,
    IN SURFOBJ  *psoSrc,
    IN SURFOBJ  *psoMsk,
    IN CLIPOBJ  *pco,
    IN XLATEOBJ  *pxlo,
    IN COLORADJUSTMENT  *pca,
    IN POINTL  *pptlBrushOrg,
    IN POINTFIX  *pptfx,
    IN RECTL  *prcl,
    IN POINTL  *pptl,
    IN ULONG  iMode
    );

Parameters

psoTrg
Points to a SURFOBJ structure that describes the surface on which to draw.
psoSrc
Points to a SURFOBJ structure that describes the source surface for the bit-block transfer operation.
psoMsk
Points to an optional surface that represents a mask for the source. It is defined by a logic map, which is a bitmap with one bit per pixel.

This mask limits the area of the source that is copied. A mask has an implicit rop4 of 0xCCAA, which means the source should be copied wherever the mask is 1, but the destination should be left alone wherever the mask is zero.

If this parameter is null, there is an implicit rop4 of 0xCCCC, which means the source should be copied everywhere in the source rectangle.

The mask will always be large enough to contain the relevant source; tiling is unnecessary.

pco
Points to a CLIPOBJ structure that limits the area of the destination to be modified. GDI functions enumerate the clip region as a set of rectangles.

Whenever possible, GDI simplifies the clipping involved. Unlike the DrvBitBlt function, EngPlgBlt may be called with a single clipping rectangle. This prevents rounding errors in clipping the output.

pxlo
Points to a XLATEOBJ structure that defines how color indices are translated between the source and target surfaces. This XLATEOBJ structure can be queried to find the RGB color for any source index.

A high quality rotate bit-block transfer is needed to interpolate colors.

pca
Points to a COLORADJUSTMENT structure that defines the color adjustment values to be applied to the source bitmap before stretching the bits. For more information, see the Platform SDK documentation.
pptlBrushOrg
Points to the origin of the halftone brush. Drivers that use halftone brushes should align the upper left pixel of the brush's pattern with this point on the device surface.
pptfx
Points to three POINTFIX structures that define a parallelogram in the destination surface. A fourth, implicit, vertex is given as: D = B + C – A.

EngPlgBlt is never called with A, B, and C colinear.

prcl
Points to a RECTL structure that defines, in the coordinate system of the source surface, the area to be copied. The points of the source rectangle are well ordered. EngPlgBlt will never be given an empty source rectangle.
pptl
Points to a POINTL structure that specifies which pixel in the given mask corresponds to the upper-left pixel in the source rectangle. Ignore this parameter if psoMsk is NULL.
iMode
Defines how source pixels are combined to get output pixels. This parameter can be one of the following values:
Value | Meaning
BLACKONWHITE | On a shrinking bit-block transfer, pixels should be combined with an AND operation. On a stretching bit-block transfer pixels should be replicated.
COLORONCOLOR | On a shrinking bit-block transfer, enough pixels should be ignored so that pixels need not be combined. On a stretching bit-block transfer, pixels should be replicated.
HALFTONE | The driver may use groups of pixels in the output surface to best approximate the color or gray level of the input.
WHITEONBLACK | On a shrinking bit-block transfer, pixels should be combined with an OR operation. On a stretching block transfers, pixels should be replicated.

The methods WHITEONBLACK, BLACKONWHITE, and COLORONCOLOR are simple and provide compatibility for old applications, but do not produce the best looking results for color surfaces.

Return Value

The return value is TRUE if the function is successful. Otherwise, it is FALSE and an error code is reported.

Headers

Declared in winddi.h. Include winddi.h.

Comments

EngPlgBlt performs only certain types of rotations.

This function performs bit-block transfers from a rectangle defined by prcl to any parallelogram. The parallelogram is defined by pptfx, which points to an array of three points.

The source rectangle at prcl is considered to be a geometric rectangle whose corners are displaced by (-0.5,-0.5) from the given integer coordinates. This exactly matches the source rectangle for EngStretchBlt. The source rectangle is always well ordered.

The upper-left corner of the source rectangle is mapped to the first point, A. The upper-right corner of the source rectangle is mapped to the second point, B. The lower-left corner of the source rectangle is mapped to the third point, C. The lower-right corner of the source rectangle is mapped to the implicit point in the parallelogram defined by treating the three given points as vectors and computing:

D = B + C - A

Note that a stretch blit can be expressed exactly as a parallelogram blit, but the coordinates given for the destination will be divisible by five.

See Also

DrvAlphaBlend, DrvBitBlt, DrvPlgBlt, DrvStretchBlt, DrvStretchBltROP, DrvTransparentBlt, EngAlphaBlend, EngBitBlt, EngStretchBlt, EngStretchBltROP, EngTransparentBlt


EngProbeForRead

EngProbeForRead probes a structure for read accessibility.

VOID
  EngProbeForRead(
    IN PVOID  Address,
    IN ULONG  Length,
    IN ULONG  Alignment
    );

Parameters

Address
Points to the structure to be probed.
Length
Specifies the length, in bytes, of the structure to be probed.
Alignment
Supplies the required alignment of the structure. This parameter is expressed as the number of bytes in the base data type. For example, an alignment of 1 specifies that Address be aligned on a character boundary, 2 specifies alignment on a short boundary, and 4 specifies alignment on a long boundary.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

EngProbeForRead causes an exception to be raised if the structure pointed to by Address:

  • Does not have a base address that begins on an alignment-byte boundary.
  • Is not read-accessible.

See Also

EngProbeForReadAndWrite


EngProbeForReadAndWrite

EngProbeForReadAndWrite probes a structure for read and write accessibility.

VOID
  EngProbeForReadAndWrite(
    IN PVOID  Address,
    IN ULONG  Length,
    IN ULONG  Alignment
    );

Parameters

Address
Points to the structure to be probed.
Length
Specifies the length, in bytes, of the structure to be probed.
Alignment
Supplies the required alignment of the structure. This parameter is expressed as the number of bytes in the base data type. For example, an alignment of 1 specifies that Address be aligned on a character boundary, 2 specifies alignment on a short boundary, and 4 specifies alignment on a long boundary.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

EngProbeForReadAndWrite causes an exception to be raised if the structure pointed to by Address:

  • Does not have a base address that begins on an alignment-byte boundary.
  • Is not both read- and write-accessible.

See Also

EngProbeForRead


EngQueryDeviceAttribute

EngQueryDeviceAttribute allows the driver to query the system about particular attributes of the device.

BOOL
  EngQueryDeviceAttribute(
    IN HDEV  hdev,
    IN ENG_DEVICE_ATTRIBUTE  devAttr,
    IN VOID  *pvIn,
    IN ULONG  ulInSize,
    OUT VOID  *pvOut,
    OUT ULONG  ulOutSize
    );

Parameters

hdev
Identifies the device for GDI. This parameter is the GDI handle received by the driver's DrvCompletePDEV function.
devAttr
Specifies the attribute for which GDI should return information. This parameter must be QDA_ACCELERATION_LEVEL, which queries the driver accelerations that GDI currently allows.
pvIn
Reserved for system use. This parameter is currently ignored by GDI.
ulInSize
Reserved for system use. This parameter is currently ignored by GDI.
pvOut
Points to a buffer of ulOutSize bytes in which GDI writes information about the attribute being queried. When devAttr is QDA_ACCELERATION_LEVEL, GDI writes in the buffer a DWORD value from 0 through 5 that enumerates the current acceleration level. See Display Driver Testing Tools for a description of the acceleration levels.
ulOutSize
Is the size in bytes of the buffer to which pvOUt points.

Return Value

EngQueryDeviceAttribute returns TRUE upon success; otherwise, it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The video card's acceleration level can be dynamically set through the Display Applet. EngQueryDeviceAttribute allows the driver to determine the acceleration level currently set.

See Also

DrvNotify


EngQueryFileTimeStamp

EngQueryFileTimeStamp returns the time stamp of a file.

LARGE_INTEGER
  EngQueryFileTimeStamp(
    IN LPWSTR  pwsz
    );

Parameters

pwsz
Points to a null-terminated string containing the name of the file to be queried.

Return Value

EngQueryFileTimeStamp returns the last time the file was written to upon success. It returns NULL if it fails.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The time returned is local system time for the current time zone, specified in system-time format. Absolute system time is the number of 100-nanosecond intervals since the start of 1601.


EngQueryLocalTime

EngQueryLocalTime queries the local time.

VOID
  EngQueryLocalTime(
    OUT PENG_TIME_FIELDS  ptf
    );

Parameters

ptf
Points to the ENG_TIME_FIELDS structure in which the local time is returned.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

EngQueryLocalTime returns the time at the current locale in the ENG_TIME_FIELDS structure.


EngQueryPalette

EngQueryPalette queries the specified palette for its attributes.

ULONG
  EngQueryPalette(
    IN HPALETTE  hPal,
    OUT ULONG  *piMode,
    IN ULONG  cColors,
    OUT ULONG  *pulColors
    );

Parameters

hPal
Specifies the handle of the palette to be queried.
piMode
Points to the location in which the palette mode, as originally specified to EngCreatePalette, is returned.
cColors
Specifies the number of entries in the buffer to which pulColors points. The return value depends on whether cColors is negative
pulColors
Points to a buffer in which the palette color information is returned. If cColors is zero, pulColors can be NULL.

Return Value

When cColors is zero, EngQueryPalette returns the number of palette entries required in the buffer to which pulColors points in order to return the palette color information. When cColors is non-zero and pulColors is not NULL, EngQueryPalette returns the number of entries written in the buffer to which pulColors points.

Headers

Declared in winddi.h. Include winddi.h.

Comments

If the palette mode is PAL_BITFIELDS, PAL_RGB, or PAL_BGR and the buffer that pulColors points to is large enough, pulColors points to three ULONG masks that represent the red, green, and blue color masks of the palette.

If the palette mode is PAL_INDEXED and the buffer that pulColors points to is large enough, pulColors contains all of the 24-bit RGB values that represent the palette colors.

A driver must test for the presence of the GCAPS_PALMANAGED flag to determine whether the colors represent a fixed or a changeable palette.

EngQueryPalette is intended for use by mirroring drivers that need to know the color format of the primary display. A mirroring driver typically calls this function in its DrvEnablePDEV routine.

See Also

EngCreatePalette


EngQueryPerformanceCounter

EngQueryPerformanceCounter queries the performance counter.

VOID
  EngQueryPerformanceCounter(
    OUT LONGLONG  *pPerformanceCount
    );

Parameters

pPerformanceCount
Points to a location in which the performance counter value, in hertz, is returned.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

EngQueryPerformanceCounter always returns a 64-bit integer that represents the number of ticks per second. The count begins accumulating when the system is booted.

A driver should call this routine sparingly. Frequent calls to EngQueryPerformanceCounter can degrade the I/O performance for the calling driver and for the system as a whole.

See Also

EngQueryPerformanceFrequency


EngQueryPerformanceFrequency

EngQueryPerformanceFrequency queries the frequency of the performance counter.

VOID
  EngQueryPerformanceFrequency(
    OUT LONGLONG  *pFrequency
    );

Parameters

pFrequency
Points to a location in which the performance counter frequency is returned.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

The resolution of the timer is 1/x, where x is the value returned in the location to which pFrequency points. For example, if the value returned in pFrequency is 2 million, each tick is 1/2 millionth of a second. Each 1/x millionth increment of the count corresponds to one second of elapsed time.

A driver should call this routine sparingly. Frequent calls to EngQueryPerformanceFrequency can degrade the I/O performance for the calling driver and for the system as a whole.

See Also

EngQueryPerformanceCounter


EngQuerySystemAttribute

EngQuerySystemAttribute queries processor or system-specific capabilities.

BOOL
  EngQuerySystemAttribute(
    IN ENG_SYSTEM_ATTRIBUTE  CapNum,
    OUT PDWORD  pCapability
    );

Parameters

CapNum
Specifies the capability being queried. This parameter can be one of the following values:
Value | Meaning
EngNumberOfProcessors | GDI returns the number of active processors in the system.
EngOptimumAvailableSystemMemory | Not available for use.
EngOptimumAvailableUserMemory | Not available for use.
EngProcessorFeature | GDI returns a bitmask of flags that describe the features of the processor. Currently, GDI sets the QSA_MMX flag when an x86 processor has MMX support. QSA_MMX is relevant only on the x86 platform.

pCapability
Points to the location in which the result of the query is returned. The value that GDI returns in this parameter depends on the enumerated value specified by CapNum.

Return Value

EngQuerySystemAttribute returns TRUE upon success. Otherwise, it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.


EngReadStateEvent

EngReadStateEvent returns the current state of the specified event object: signaled or nonsignaled.

LONG
  EngReadStateEvent(
    IN PEVENT  pEvent,
    );

Parameters

pEvent
Points to the event object returned by a previous call to EngCreateEvent or EngMapEvent.

Return Value

EngReadStateEvent returns a nonzero value if the event object is currently set to the signaled state. If the event object is set to the nonsignaled state, this function returns zero.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function is available in Windows XP and later.

See Also

EngCreateEvent, EngMapEvent


EngReleaseSemaphore

EngReleaseSemaphore releases the specified semaphore.

VOID
  EngReleaseSemaphore(
    IN HSEMAPHORE  hsem
    );

Parameters

hsem
Is a handle to the semaphore to be released.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

EngReleaseSemaphore releases the semaphore's exclusive lock on a driver's resource and re-enables the delivery of special kernel asychronous procedure calls.

The lock and asynchronous procedure call suspension were acquired in a call to EngAcquireSemaphore.

See Also

EngAcquireSemaphore, EngDeleteSemaphore, EngIsSemaphoreOwned, EngIsSemaphoreOwnedByCurrentThread


EngRestoreFloatingPointState

EngRestoreFloatingPointState restores the Windows 2000 (and later) kernel floating point state after the driver uses any floating point or MMX hardware instructions.

BOOL
  EngRestoreFloatingPointState(
    IN VOID  *pBuffer
    );

Parameters

pBuffer
Points to the buffer whose contents were filled by EngSaveFloatingPointState.

Return Value

EngRestoreFloatingPointState returns TRUE if successful. Otherwise, it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The driver must save the current kernel floating point state before using floating point hardware instructions. On Intel architecture systems, this permits the use of MMX instructions if they are supported by the processor. Drivers that do not properly use EngSaveFloatingPointState and EngRestoreFloatingPointState when using floating point or MMX hardware will cause random floating point or MMX corruption in the calling application.

On every call to the driver, the driver must call EngSaveFloatingPointState once to preserve kernel state before using floating point or MMX operations. It must also call EngRestoreFloatingPointState once after all floating point or MMX operations are complete to reset the kernel state.

GDI automatically saves the floating point state for any calls to a driver's DrvEscape routine when the escape is OPENGL_CMD, OPENGL_GETINFO, or RXFUNCS.

See Also

EngSaveFloatingPointState


EngSaveFloatingPointState

EngSaveFloatingPointState saves the current Windows 2000 (and later) kernel floating point state.

ULONG
  EngSaveFloatingPointState(
    OUT VOID  *pBuffer,
    IN ULONG  cjBufferSize
    );

Parameters

pBuffer
Points to the buffer to receive the state. This buffer must be zero-initialized, and must be in nonpaged memory.
cjBufferSize
Size in bytes of the buffer to which pBuffer points.

Return Value

If pBuffer is non-NULL, EngSaveFloatingPointState returns TRUE if the state is successfully saved. It returns FALSE if the specified buffer is too small or the state cannot be saved.

If pBuffer is NULL or cjBufferSize is zero, EngSaveFloatingPointState returns the size of the buffer needed to save the floating point state. If the return value is zero, the processor does not have hardware floating point capability. In this case, the driver must not use any floating point instructions.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The driver must save the current kernel floating point state before using floating point hardware instructions. On Intel architecture systems, this permits the use of MMX instructions if they are supported by the processor. Drivers that do not properly use EngSaveFloatingPointState and EngRestoreFloatingPointState when using floating point or MMX hardware will cause random floating point or MMX corruption in the calling application.

On every call to the driver, the driver must call EngSaveFloatingPointState once to preserve kernel state before using floating point or MMX operations. It must also call EngRestoreFloatingPointState once after all floating point or MMX operations are complete to reset the kernel state.

GDI automatically saves the floating point state for any calls to a driver's DrvEscape routine when the escape is OPENGL_CMD, OPENGL_GETINFO, or RXFUNCS.

See Also

EngRestoreFloatingPointState


EngSecureMem

EngSecureMem locks down the specified address range in memory.

HANDLE
  EngSecureMem(
    IN PVOID  Address,
    IN ULONG  Length
    );

Parameters

Address
Points to the base address of the memory to be secured.
Length
Specifies the size of the memory range to be secured.

Return Value

EngSecureMem returns a handle to the secured address range upon successful completion; otherwise, it returns NULL.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The address range locked down by EngSecureMem will not be deallocated until it is unlocked by EngUnsecureMem.


EngSetEvent

EngSetEvent sets the specified event object to the signaled state, and returns the event object's previous state.

LONG
  EngSetEvent(
    IN PEVENT  pEvent
    );

Parameters

pEvent
Points to the event object that is to be set to the signaled state. This event object was returned by a previous call to EngCreateEvent or EngMapEvent.

Return Value

EngSetEvent returns a nonzero value if the event object's previous state was signaled.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function is available in Windows XP and later.

Every event object is in either the signaled state or the nonsignaled state. Calling EngSetEvent causes the event object to be set to the signaled state.

See Also

EngCreateEvent, EngMapEvent, EngWaitForSingleObject


EngSetLastError

EngSetLastError causes GDI to report an error code, which can be retrieved by an application.

VOID
  EngSetLastError(
    IN ULONG  iError
    );

Parameters

iError
Specifies the 32-bit error code to set.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

EngSetLastError sets the last error code for the calling thread. This function allows a driver to communicate error conditions to an application. To facilitate this communication, a driver should use the Win32 application error codes defined in winerror.h.

Only the last error code to be set is retrievable; that is, consecutive calls to EngSetLastError will cause the last-error code field to be overwritten.

See Also

EngGetLastError


EngSetPointerShape

EngSetPointerShape sets the pointer shape for the calling driver.

ULONG
  EngSetPointerShape(
    IN SURFOBJ  *pso,
    IN SURFOBJ  *psoMask,
    IN SURFOBJ  *psoColor,
    IN XLATEOBJ  *pxlo,
    IN LONG  xHot,
    IN LONG  yHot,
    IN LONG  x,
    IN LONG  y,
    IN RECTL  *prcl,
    IN FLONG  fl
    );

Parameters

pso
Points to a SURFOBJ structure that describes the surface on which to draw.
psoMask
Points to a SURFOBJ structure that defines the AND-XOR mask to apply to the pointer bitmap. The top half of the bitmap specifies the monochrome AND mask and the bottom half specifies the monochrome XOR mask. The pointer is the same width and half the height of the mask to which psoMask points. There are no implicit constraints on pointer sizes, but optimal pointer sizes are 32 x 32, 48 x 48, and 64 x 64 pixels. If this parameter is NULL, the pointer is transparent.
psoColor
Points to a SURFOBJ structure that defines the colors for a color pointer. This bitmap is the same width and half the height of the bitmap to which psoMask points, and is in the same color format as the surface to which pso points. If this parameter is NULL, the pointer is monochrome.
pxlo
Points to a XLATEOBJ structure that defines the colors in psoColor.
xHot, yHot
Specify the x and y positions of the pointer's hot spot relative to its upper-left pixel. The pixel indicated by the hot spot should be positioned at the new pointer position.
x, y
Specify the new pointer position.
prcl
If non-NULL, the driver has provided a rectangle that bounds all pixels affected by the pointer on the display. GDI avoids drawing on this rectangle without first moving the pointer out of the way.
fl
Specifies a set of flags that GDI should use to process this call. This parameter can be one or more of the following predefined values:
Flag | Meaning
SPS_ANIMATESTART | GDI should be prepared to receive a series of similarly-sized pointer shapes that will comprise an animated pointer effect.
SPS_ANIMATEUPDATE | GDI should draw the next pointer shape in the animated series.
SPS_CHANGE | GDI is requested to change the pointer shape.

Return Value

EngSetPointerShape returns one of the following values:

Value | Meaning
SPS_ACCEPT_EXCLUDE | GDI accepts the shape. GDI does not read from or write to the rectangle written at prcl without first moving the pointer out of the way.
SPS_ERROR | GDI normally supports this shape, but failed for unusual reasons.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The driver can call EngSetPointerShape to have GDI manage a software cursor.

There are two parts to the monochrome bitmap to which psoMask points. The first part defines the AND mask for the pointer while the second part defines the XOR mask. Taken together, these masks provide two bits of information for each pixel of the pointer image. The following truth table determines what GDI draws on the display for different values in the AND and XOR masks:

AND value | XOR value | Resultant Pixel
0 | 0 | White.
0 | 1 | Black.
1 | 0 | Pixel is unchanged.
1 | 1 | Pixel color is inverted.

This mechanism supplies a black and white image while allowing for transparency and inversion of the pixels that make up the pointer.

See Also

DrvSetPointerShape, EngMovePointer, SURFOBJ, XLATEOBJ


EngSetPointerTag

EngSetPointerTag creates a shape that is unioned with the application's pointer shape on DrvSetPointerShape calls to other associated drivers in a mirrored system.

BOOL
  EngSetPointerTag(
    IN HDEV  hdev,
    IN SURFOBJ  *psoMask,
    IN SURFOBJ  *psoColor,
    IN XLATEOBJ  *pxlo,
    IN FLONG  fl
    );

Parameters

hdev
Is the GDI handle received by the driver as the hdev parameter for DrvCompletePDEV.
psoMask
Points to a 1bpp SURFOBJ structure that describes the monochrome components of the tag. The dimensions of this bitmap determine the size of the tag. There are no implicit constraints on tag sizes, but optimal tag sizes are 32 x 32, 48 x 48, and 64 x 64 pixels. GDI removes the current tag when this value is NULL.
psoColor
Points to a SURFOBJ structure in the same color format as the calling driver. This value can be NULL if the tag contains no color components. The color bitmap has the same width as psoInputMask and half the height.
pxlo
Reserved for system use; must be set to NULL.
fl
Reserved for system use; must be set to zero.

Return Value

EngSetPointerTag returns TRUE when it successfully applies the tag. Otherwise, it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A remote-control driver can call EngSetPointerTag to tag a pointer shape to denote control of the system. Once the remote-control driver sets a tag, GDI will automatically composite it with all pointer shapes generated by the system, until the driver removes or changes the tag.

The driver that calls EngSetPointerShape never gets its own tag applied to its own DrvSetPointerShape calls by GDI; only other drivers in the mirrored system get the tag applied.

If psoColor is NULL, psoMask points to a monochrome surface that is twice as high as it is wide. The top half contains the monochrome AND mask, and the bottom half contains the monochrome XOR mask.

If psoColor is not NULL, psoMask contains only the monochrome AND mask and psoColor contains the color XOR surface. This color surface must be in the same color format as the driver. GDI joins the shapes by anchoring the upper-left corners of each bitmap.

GDI makes copies of psoMask and psoColor, so the surfaces passed in by the driver can be deleted immediately after calling EngSetPointerTag.

The results of EngSetPointerTag take effect on the next pointer shape call generated by the system.

See Also

DrvSetPointerShape, EngSetPointerShape, SURFOBJ


EngSetPrinterData

EngSetPrinterData sets the configuration data for the specified printer.

DWORD
  EngSetPrinterData(
    IN HANDLE  hPrinter,
    IN LPWSTR  pType,
    IN DWORD  dwType,
    IN LPBYTE  lpbPrinterData,
    IN DWORD  cjPrinterData
    );

Parameters

hPrinter
Is a handle that identifies the printer for which configuration data should be set. This is the handle that is passed as the hDriver parameter of DrvEnablePDEV.
pType
Points to a null-terminated string that identifies the data to be set.
dwType
Is a flag that specifies the type of information to be set. This parameter can be one of the following values:
Value | Meaning
REG_BINARY | Binary data in any form.
REG_DWORD | A 32-bit number.
REG_DWORD_BIG_ENDIAN | A 32-bit number in big-endian format, meaning that the most significant byte of a word is the low-order byte.
REG_DWORD_LITTLE_ENDIAN | A 32-bit number in little-endian format (same as REG_DWORD), meaning that the most significant byte of a word is the high-order byte
REG_EXPAND_SZ | A null-terminated string that contains unexpanded references to environment variables (for example, "%PATH%"). It will be a UNICODE or ANSI string depending on whether UNICODE or ANSI functions are used.
REG_LINK | A UNICODE symbolic link.
REG_MULTI_SZ | An array of null-terminated strings, terminated by two null characters.
REG_NONE | No defined value type.
REG_RESOURCE_LIST | A device-driver resource list.
REG_SZ | A null-terminated string. It will be a UNICODE or ANSI string depending on whether you use the UNICODE or ANSI functions.

lpbPrinterData
Is a byte pointer to the printer configuration data that is to be set. The type of data pointed to is determined by dwType.
cjPrinterData
Specifies the size, in bytes, of lpbPrinterData.

Return Value

EngSetPrinterData returns the last logged error message.

Headers

Declared in winddi.h. Include winddi.h.

See Also

DrvEnablePDEV, EngGetPrinterData


EngSort

EngSort performs a quick-sort on the specified list.

VOID
  EngSort(
    IN OUT PBYTE  pjBuf,
    IN ULONG  c,
    IN ULONG  cjElem,
    IN SORTCOMP  pfnComp
    );

Parameters

pjBuf
Points to the data array to be sorted.
c
Specifies the size, in bytes, of each element in pjBuf.
cjElem
Specifies the number of elements in pjBuf to be sorted.
pfnComp
Points to a function that implements the element comparison to be used for the sort.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

EngSort implements a quick-sort algorithm to sort cjElem elements in pjBuf, where each element is of size c. The sorted elements are returned in pjBuf; that is, the original contents of the buffer are overwritten with the sorted results.

The basis for comparing two elements is defined in the function that pfnComp points to. This function is prototyped as follows:

int (__cdecl *SORTCOMP)(const void *pv1, const void *pv2);

where pv1 and pv2 point to the two elements to be compared. The return value is the result of the comparison defined as follows:

Return Value | Meaning
Negative integer | *pv1 < *pv2
Zero | *pv1 = *pv2
Positive integer | *pv1 > *pv2

The array is sorted in increasing order, which is defined by the pfnComp parameter.


EngStretchBlt

EngStretchBlt causes GDI to do a stretching bit-block transfer.

BOOL
  EngStretchBlt(
    IN SURFOBJ  *psoDest,
    IN SURFOBJ  *psoSrc,
    IN SURFOBJ  *psoMask,
    IN CLIPOBJ  *pco,
    IN XLATEOBJ  *pxlo,
    IN COLORADJUSTMENT  *pca,
    IN POINTL  pptlHTOrg,
    IN RECTL  *prclDest,
    IN RECTL  *prclSrc,
    IN POINTL  *pptlMask,
    IN ULONG  iMode
    );

Parameters

psoDest
Points to a SURFOBJ structure that describes the surface on which to draw.
psoSrc
Points to a SURFOBJ structure that describes the source surface for the bit-block transfer.
psoMask
Points to a SURFOBJ structure that defines a mask for the source. The mask is defined by a logic map, which is a bitmap with one bit per pixel.

The mask limits the area of the source that is copied. If this parameter is specified, it has an implicit rop4 of 0xCCAA, meaning the source should be copied wherever the mask is 1, but the destination should be left alone wherever the mask is 0.

If this parameter is null, the rop4 is implicitly 0xCCCC, which means the source should be copied everywhere in the source rectangle.

pco
Points to a CLIPOBJ structure that limits the area to be modified in the destination. GDI services are provided to enumerate the clip region as a set of rectangles.

Whenever possible, GDI simplifies the clipping involved. However, unlike DrvBitBlt, EngStretchBlt can be called with a single clipping rectangle. This prevents rounding errors in clipping the output.

pxlo
Points to a XLATEOBJ structure that specifies how color indices are to be translated between the source and target surfaces.

This XLATEOBJ structure can also be queried to find the RGB color for any source index. A high quality stretching bit-block transfer will need to interpolate colors in some cases.

pca
Points to a COLORADJUSTMENT structure that defines the color adjustment values to be applied to the source bitmap before stretching the bits. For more information see the Platform SDK documentation.
pptlHTOrg
Points to a POINTL structure that defines the origin of the halftone brush. Drivers that use halftone brushes should align the upper left pixel of the brush's pattern with this point on the device surface.
prclDest
Points to a RECTL structure that defines the area to be modified in the coordinate system of the destination surface. This rectangle is defined by two points that are not well ordered, meaning the coordinates of the second point are not necessarily larger than those of the first point. The rectangle described does not include the lower and right edges. This function is never called with an empty destination rectangle.

If the destination rectangle is not well ordered, EngStretchBlt makes it well ordered.

prclSrc
Points to a RECTL structure that defines the area to be copied, in the coordinate system of the source surface. The rectangle will map to the rectangle defined by prclDest. This function is never given an empty source rectangle, and the points of the source rectangle are always well-ordered.

The mapping is defined by prclSrc and prclDest. The points specified in prclDest and prclSrc lie on integer coordinates, which correspond to pixel centers. A rectangle defined by two such points is considered to be a geometric rectangle with two vertices whose coordinates are the given points, but with 0.5 subtracted from each coordinate. (POINTL structures are shorthand notation for specifying these fractional coordinate vertices.)

The edges of any rectangle never intersect a pixel, but go around a set of pixels. The pixels that are inside the rectangle are those expected for a bottom-right exclusive rectangle. EngStretchBlt maps the geometric source rectangle exactly onto the geometric destination rectangle.

pptlMask
Points to a POINTL structure that defines the pixel in the given mask that corresponds to the upper left pixel in the source rectangle. This parameter is ignored if no mask is specified.
iMode
Specifies how source pixels are combined to get output pixels. The HALFTONE mode is slower than the other modes, but produces higher quality images.
Value | Meaning
BLACKONWHITE | On a shrinking bit-block transfer, pixels should be combined with a Boolean AND operation. On a stretching bit-block transfer, pixels should be replicated.
COLORONCOLOR | On a shrinking bit-block transfer, enough pixels should be ignored so that pixels don't need to be combined. On a stretching bit-block transfer, pixels should be replicated.
HALFTONE | The driver can use groups of pixels in the output surface to best approximate the color or gray level of the input.
WHITEONBLACK | On a shrinking bit-block transfer, pixels should be combined with a Boolean OR operation. On a stretching bit-block transfer, pixels should be replicated.

Return Value

The return value is TRUE if the function is successful. Otherwise, it is FALSE and an error code is reported.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function allows the same halftoning algorithm to be applied to GDI bitmaps and device surfaces.

The driver should call EngStretchBlt if it has hooked DrvStretchBlt and is called to do something the driver does not support.

See Also

CLIPOBJ, DrvBitBlt, SURFOBJ, XLATEOBJ


EngStretchBltROP

EngStretchBltROP performs a stretching bit-block transfer using a ROP.

BOOL
  EngStretchBltROP(
    IN SURFOBJ  *psoDest,
    IN SURFOBJ  *psoSrc,
    IN SURFOBJ  *psoMask,
    IN CLIPOBJ  *pco,
    IN XLATEOBJ  *pxlo,
    IN COLORADJUSTMENT  *pca,
    IN POINTL  *pptlHTOrg,
    IN RECTL  *prclDest,
    IN RECTL  *prclSrc,
    IN POINTL  *pptlMask,
    IN ULONG  iMode,
    IN BRUSHOBJ  *pbo,
    IN DWORD  rop4
    );

Parameters

psoDest
Points to a SURFOBJ structure that describes the surface on which to draw.
psoSrc
Points to a SURFOBJ structure that describes the source surface for the bit-block transfer.
psoMask
Points to a SURFOBJ structure that defines a mask for the source surface. The mask is defined by a logic map, which is a bitmap with 1 bit per pixel. Typically, a mask limits the area that is to be modified in the destination surface. This mask should always be the same size as the source surface.
pco
Points to a CLIPOBJ structure that limits the area to be modified in the destination. The CLIPOBJ_Xxx service routines are provided to enumerate the clip region as a set of rectangles.

Whenever possible, GDI simplifies the clipping involved. However, unlike EngBitBlt, EngStretchBltROP can be called with a single clipping rectangle. This prevents rounding errors in clipping the output.

pxlo
Points to a XLATEOBJ structure that specifies how color indices are to be translated between the source and target surfaces.

This XLATEOBJ structure can also be queried to find the RGB color for any source index. A high quality stretching bit-block transfer will need to interpolate colors in some cases.

pca
Points to a COLORADJUSTMENT structure that defines the color adjustment values to be applied to the source bitmap before stretching the bits. For more information see the Platform SDK documentation.
pptlHTOrg
Points to a POINTL structure that defines the origin of the halftone brush on the destination surface. When using halftone brushes, GDI aligns the upper left pixel of the brush's pattern at this point and repeats the brush according to its dimensions. GDI ignores this parameter if the rop4 parameter does not require a pattern.
prclDest
Points to a RECTL structure that defines the rectangular area to be modified. This rectangle is specified in the coordinate system of the destination surface and is defined by two points: upper left and lower right. The two points that define the rectangle are not always well ordered, meaning the coordinates of the second point are not necessarily larger than those of the first point. If the destination rectangle is not well ordered, GDI makes it so.

The rectangle is lower-right exclusive; that is, its lower and right edges are not a part of the copy.

EngStretchBltROP must never be called with an empty destination rectangle.

prclSrc
Points to a RECTL structure that defines the area to be copied. This rectangle is specified in the coordinate system of the source surface and is defined by two points: upper left and lower right. The two points that define the rectangle are always well ordered.

The rectangle is lower-right exclusive; that is, its lower and right edges are not a part of the copy.

This rectangle maps to the rectangle to which prclDest points.

EngStretchBltROP must never be called with an empty source rectangle.

pptlMask
Points to a POINTL structure that defines the pixel in the mask to which prclMask points. This pixel corresponds to the upper-left pixel in the source rectangle to which prclSrc points. This parameter is ignored if no mask is specified; that is, GDI ignores pptlMask when prclMask is NULL.
iMode
Specifies how source pixels are combined to get output pixels. The HALFTONE mode is slower than the other modes, but produces higher quality images. This parameter can be one of the following values:
Value | Meaning
BLACKONWHITE | On a shrinking bit-block transfer, GDI combines pixels with a Boolean AND operation. On a stretching bit-block transfer, pixels are replicated.
COLORONCOLOR | On a shrinking bit-block transfer, GDI ignores enough pixels so that pixels need not be combined. On a stretching bit-block transfer, pixels are replicated.
HALFTONE | GDI uses groups of pixels in the output surface to best approximate the color or gray level of the input.
WHITEONBLACK | On a shrinking bit-block transfer, pixels should be combined with a Boolean OR operation. On a stretching bit-block transfer, pixels should be replicated.

pbo
Points to the BRUSHOBJ structure to be used to define the pattern for the bit-block transfer. GDI's BRUSHOBJ_pvGetRbrush service routine retrieves the device's realization of the brush. GDI ignores this parameter if the rop4 parameter does not require a pattern.
rop4
Represents a raster operation that defines how the mask, pattern, source, and destination pixels are combined to write an output pixel to the destination surface.

This is a quaternary raster operation, which is a natural extension of the usual ternary Rop3 operation. A Rop4 has 16 relevant bits, which are similar to the 8 defining bits of a Rop3. (The other redundant bits of the Rop3 are ignored.) The simplest way to implement a Rop4 is to consider its 2 bytes separately. The lower byte specifies a Rop3 that should be computed wherever the mask to which psoMask points is 1. The high byte specifies a Rop3 that can be computed and applied wherever the mask is zero.

Return Value

EngStretchBltROP returns TRUE upon success. Otherwise, it reports an error and returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The driver should call EngStretchBltROP if it has hooked DrvStretchBltROP but cannot support all operations.

The mapping is defined by prclSrc and prclDest. The points specified in prclDest and prclSrc lie on integer coordinates that correspond to pixel centers. A rectangle defined by two such points is considered to be a geometric rectangle with two vertices whose coordinates are the given points, but with 0.5 subtracted from each coordinate. (POINTL structures are shorthand notation for specifying these fractional coordinate vertices.)

See Also

DrvAlphaBlend, DrvBitBlt, DrvPlgBlt, DrvStretchBlt, DrvStretchBltROP, DrvTransparentBlt, EngAlphaBlend, EngBitBlt, EngPlgBlt, EngStretchBlt, EngTransparentBlt


EngStrokeAndFillPath

EngStrokeAndFillPath causes GDI to fill a path and stroke it at the same time.

BOOL
  EngStrokeAndFillPath(
    IN SURFOBJ  *pso,
    IN PATHOBJ  *ppo,
    IN CLIPOBJ  *pco,
    IN XFORMOBJ  *pxo,
    IN BRUSHOBJ  *pboStroke,
    IN LINEATTRS  *plineattrs,
    IN BRUSHOBJ  *pboFill,
    IN POINTL  *pptlBrushOrg,
    IN MIX  mixFill,
    IN FLONG  flOptions
    );

Parameters

pso
Points to a SURFOBJ structure that defines the drawing surface.
ppo
Points to a PATHOBJ structure that defines the path to be filled. The PATHOBJ_Xxx service routines are provided to enumerate the lines, Bezier curves, and other data that make up the path.
pco
Points to a CLIPOBJ structure. The CLIPOBJ_Xxx service routines are provided to enumerate the clip region as a set of rectangles.
pxo
Points to a XFORMOBJ structure that is only needed when a geometric wide line is to be drawn and specifies the transform that converts world coordinates to device coordinates. The path is provided in device coordinates but a geometric wide line is actually widened in world coordinates.

The driver can use the XFORMOBJ_Xxx service routines to determine the transform.

pboStroke
Points to a BRUSHOBJ structure that describes the brush to use when stroking the path.
plineattrs
Points to a LINEATTRS structure.
pboFill
Points to a BRUSHOBJ structure that describes the brush to use when filling the path.
pptlBrushOrg
Points to a POINTL structure that defines the brush origin for both brushes.
mixFill
Defines the foreground and background raster operations to use for the fill brush.
flOptions
Specifies which fill mode to use. This parameter can be FP_WINDINGMODE or FP_ALTERNATEMODE; all other bits should be ignored. For more information about these modes, see Path Fill Modes.

Return Value

The return value is TRUE if GDI fills the path. If the driver should fill the path, the return value is FALSE, and an error code is not logged. If GDI encounters an unexpected error, such as not being able to realize the brush, the return value is DDI_ERROR, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The mix mode defines how the incoming pattern should be mixed with the data already on the device surface. The MIX data type consists of two ROP2 values packed into a single ULONG. The low-order byte defines the foreground raster operation; the next byte defines the background raster operation. For more information about raster operation codes, see the Platform SDK documentation.

See Also

BRUSHOBJ, CLIPOBJ, DrvStrokeAndFillPath, LINEATTRS, PATHOBJ, SURFOBJ, XFORMOBJ


EngStrokePath

EngStrokePath requests that GDI stroke a specified path.

BOOL
  EngStrokePath(
    IN SURFOBJ  *pso,
    IN PATHOBJ  *ppo,
    IN CLIPOBJ  *pco,
    IN XFORMOBJ  *pxo,
    IN BRUSHOBJ  *pbo,
    IN POINTL  *pptlBrushOrg,
    IN LINEATTRS  *plineattrs,
    IN MIX  mix
    );

Parameters

pso
Points to a SURFOBJ structure that describes the surface on which to draw.
ppo
Points to a PATHOBJ structure. The PATHOBJ_Xxx service routines are provided to enumerate the lines, Bezier curves, and other data that make up the path. This indicates what is to be drawn.
pco
Points to a CLIPOBJ structure. The CLIPOBJ_Xxx service routines are provided to enumerate the clip region as a set of rectangles. Optionally, all the lines in the path can be enumerated preclipped by this CLIPOBJ. This means that drivers can have all their line clipping calculations done for them.
pxo
Points to a XFORMOBJ structure. This is needed only when a geometric wide line is to be drawn. It specifies the transform that converts world coordinates to device coordinates. This is needed because the path is provided in device coordinates but a geometric wide line is actually widened in world coordinates.

The driver can use the XFORMOBJ_Xxx service routines to determine the transform.

pbo
Specifies the brush to be used when drawing the path.
pptlBrushOrg
Points to the brush origin used to align the brush pattern on the device.
plineattrs
Points to a LINEATTRS structure. Note that the elStyleState member of this structure must be updated as part of this function if the line is styled. Also note the ptlLastPel member of the same structure must be updated if a single-pixel-width cosmetic line is being drawn.
mix
Specifies how to combine the brush with the destination.

Return Value

The return value is TRUE if GDI strokes the path. If the driver should stroke the path, the return value is FALSE, and no error is logged. If GDI encounters an error, the return value is DDI_ERROR, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The mix mode defines how the incoming pattern should be mixed with the data already on the device surface. The MIX data type consists of two ROP2 values packed into a single ULONG. The low-order byte defines the foreground raster operation; the next byte defines the background raster operation. For more information about raster operation codes, see the Platform SDK documentation.

See Also

CLIPOBJ, DrvStrokePath, LINEATTRS, PATHOBJ, SURFOBJ, XFORMOBJ


EngTextOut

EngTextOut causes GDI to render a set of glyphs at specified positions.

BOOL
  EngTextOut(
    IN SURFOBJ  *pso,
    IN STROBJ  *pstro,
    IN FONTOBJ  *pfo,
    IN CLIPOBJ  *pco,
    IN RECTL  *prclExtra,
    IN RECTL  *prclOpaque,
    IN BRUSHOBJ  *pboFore,
    IN BRUSHOBJ  *pboOpaque,
    IN POINTL  pptlOrg,
    IN MIX  mix
    );

Parameters

pso
Points to a SURFOBJ structure that describes the surface on which to write.
pstro
Points to a STROBJ structure that defines the glyphs to be rendered and the positions where they are to be placed.
pfo
Points to a FONTOBJ structure that is used to retrieve information about the font and its glyphs.
pco
Points to a CLIPOBJ structure that defines the clip region through which rendering must be done. No pixels can be affected outside this clip region.
prclExtra
Should always be NULL.
prclOpaque
Points to a single opaque rectangle that is bottom right exclusive. Pixels within this rectangle (those that are not foreground and not clipped) are to be rendered with the opaque brush. This rectangle always bounds the text to be drawn. If this parameter is null, no opaque pixels are to be rendered.
pboFore
Points to the brush object to be used for the foreground pixels. This brush will always be a solid color brush.
pboOpaque
Points to the brush object for the opaque pixels. Both the foreground and background mix modes for this brush are assumed to be R2_COPYPEN. Unless the driver sets the GCAPS_ARBRUSHOPAQUE capabilities bit in the flGraphicsCaps member of the DEVINFO structure, it will always be called with a solid color brush.
pptlOrg
Points to a POINTL structure that defines the brush origin for both brushes.
mix
Specifies foreground and background raster operations (mix modes) for pboFore.

Return Value

The return value is TRUE if the function is successful. Otherwise, it is FALSE, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The driver should call EngTextOut when it has hooked DrvTextOut and cannot render the glyphs.

Note The driver cannot punt to EngTextOut if it has hooked DrvTextOut for a device managed surface.

The input parameters to EngTextOut define two sets of pixels: foreground and opaque. The driver must render the surface so the result is identical to a process where the opaque pixels are rendered first with the opaque brush, and then the foreground pixels are rendered with the foreground brush. Each of these operations is limited by clipping.

The foreground and opaque pixels are regarded as a screen through which color is brushed onto the surface. The glyphs of the font do not have color in themselves.

The input parameters to EngTextOut define the set of glyph pixels, the set of extra rectangles, the opaque rectangle, and the clip region. The driver must calculate and then render the set of foreground and opaque pixels.

The mix mode defines how the incoming pattern should be mixed with the data already on the device surface. The MIX data type consists of two ROP2 values packed into a single ULONG. The low-order byte defines the foreground raster operation; the next byte defines the background raster operation. For more information about raster operation codes, see the Platform SDK documentation.

See Also

CLIPOBJ, DEVINFO, DrvTextOut, FONTOBJ, STROBJ, SURFOBJ


EngTransparentBlt

EngTransparentBlt provides bit-block transfer capabilities with transparency.

BOOL
  EngTransparentBlt(
    IN SURFOBJ  *psoDst,
    IN SURFOBJ  *psoSrc,
    IN CLIPOBJ  *pco,
    IN XLATEOBJ  *pxlo,
    IN RECTL  *prclDst,
    IN RECTL  *prclSrc,
    IN ULONG  iTransColor,
    IN ULONG  ulReserved
    );

Parameters

psoDst
Points to the SURFOBJ structure that identifies the target surface on which to draw.
psoSrc
Points to the SURFOBJ structure that identifies the source surface of the bit-block transfer.
pco
Points to a CLIPOBJ structure. The CLIPOBJ_Xxx service routines are provided to enumerate the clip region as a set of rectangles. This enumeration limits the area of the destination that is modified. Whenever possible, GDI simplifies the clipping involved.
pxlo
Points to a XLATEOBJ structure that tells how the source color indices should be translated for writing to the target surface.
prclDst
Points to a RECTL structure that defines the rectangular area to be modified. This rectangle is specified in the coordinate system of the destination surface and is defined by two points: upper left and lower right. The rectangle is lower-right exclusive; that is, its lower and right edges are not a part of the bit-block transfer. The two points that define the rectangle are always well ordered.

The driver must never call EngTransparentBlt with an empty destination rectangle.

prclSrc
Points to a RECTL structure that defines the rectangular area to be copied. This rectangle is specified in the coordinate system of the source surface and is defined by two points: upper left and lower right. The two points that define the rectangle are always well ordered.

The source rectangle will never exceed the bounds of the source surface, and so will never overhang the source surface.

This rectangle is mapped to the destination rectangle defined by prclDst. The driver must never call EngTransparentBlt with an empty source rectangle.

iTransColor
Specifies the transparent color, in the source surface's format. This is a color index value that has been translated to the source surface's palette.
ulReserved
Reserved. This parameter must be set to zero.

Return Value

EngTransparentBlt returns TRUE upon success. Otherwise, it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The driver should call EngTransparentBlt if it has hooked DrvTransparentBlt and it is called to do something that it does not support.

Bit-block transfer with transparency is supported between two device-managed surfaces or between a device-managed surface and a GDI-managed standard format bitmap. Currently, GDI supports only BMF_4BPP and BMF_8BPP source surfaces.

The pixels on the source surface that match the transparent color specified by iTransparentColor are not copied.

See Also

DrvBitBlt, DrvPlgBlt, DrvStretchBlt, DrvStretchBltROP, DrvTransparentBlt, EngBitBlt, EngPlgBlt, EngStretchBlt, EngStretchBltROP


EngUnicodeToMultiByteN

EngUnicodeToMultiByteN converts the specified Unicode string into an ANSI string using the current ANSI code page.

VOID
  EngUnicodeToMultiByteN(
    OUT PCHAR  MultiByteString,
    IN ULONG  MaxBytesInMultiByteString,
    OUT PULONG  BytesInMultiByteString,
    IN PWSTR  UnicodeString,
    IN ULONG  BytesInUnicodeString
    );

Parameters

MultiByteString
Points to the buffer in which the resultant ANSI string is returned.
MaxBytesInMultiByteString
Supplies the maximum number of bytes to be written to MultiByteString. If this value is too small, causing MultiByteString to be a truncated equivalent of UnicodeString, then no error condition results.
BytesInMultiByteString
Points to a ULONG in which the number of bytes written to MultiByteString is returned.
UnicodeString
Points to the Unicode source string that is to be converted to ANSI.
BytesInUnicodeString
Specifies the number of bytes in UnicodeString.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

See Also

EngMultiByteToUnicodeN, EngWideCharToMultiByte


EngUnloadImage

EngUnloadImage unloads an image loaded by EngLoadImage.

VOID
  EngUnloadImage(
    IN HANDLE  hModule
    );

Parameters

hModule
Is a handle of the image to be unloaded from system memory.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

See Also

EngLoadImage


EngUnlockDirectDrawSurface

EngUnlockDirectDrawSurface releases the lock on the specified surface.

BOOL
  EngUnlockDirectDrawSurface(
    IN PDD_SURFACE_LOCAL  pSurface
    );

Parameters

pSurface
Points to a DD_SURFACE_LOCAL structure that describes the surface to be unlocked.

Return Value

EngUnlockDirectDrawSurface returns TRUE when it successfully unlocks the specified surface. Otherwise, it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The surface must previously have been locked by EngLockDirectDrawSurface.

See Also

EngLockDirectDrawSurface


EngUnlockDriverObj

EngUnlockDriverObj causes GDI to unlock the driver object.

BOOL
  EngUnlockDriverObj(
    IN HDRVOBJ  hdo
    );

Parameters

hdo
Identifies the object to be unlocked.

Return Value

The return value is TRUE if the function is successful; otherwise, it is FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The specified driver object must have been previously locked by a call to EngLockDriverObj. The object is not unlockable by another thread while it is locked down.


EngUnlockSurface

EngUnlockSurface causes GDI to unlock the surface.

VOID
  EngUnlockSurface(
    IN SURFOBJ  *pso
    );

Parameters

pso
Points to a SURFOBJ structure that describes the surface to be unlocked.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

The specified surface must previously have been locked by a call to EngLockSurface. The pointer to the SURFOBJ must not be used after this call.


EngUnmapEvent

EngUnmapEvent cleans up the kernel-mode resources allocated for a mapped user-mode event.

BOOL
  EngUnmapEvent(
    IN PEVENT  pEvent
    );

Parameters

pEvent
Points to an event object returned from a previous call to EngMapEvent.

Return Value

EngUnmapEvent returns TRUE upon success. Otherwise, it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function is available in Windows XP and later.

The display driver should call EngUnmapEvent when it is notified that the process (typically EngCreateDriverObj) that created the user-mode event has terminated. The display driver can also call EngUnmapEvent to perform its own cleanup. The display and miniport drivers should not touch the event object after EngUnmapEvent has been called.

The display driver can call EngUnmapEvent only for an event object returned by EngMapEvent. It must not call this function for an event object returned by EngCreateEvent.

See Also

EngMapEvent, EngCreateEvent, EngCreateDriverObj


EngUnmapFile

EngUnmapFile unmaps the view of a file from system space.

BOOL
  EngUnmapFile(
    IN ULONG_PTR  iFile
    );

Parameters

iFile
Specifies the identifier of the mapped file. This identifier was obtained in a prior call to EngMapFile.

Return Value

EngUnmapFile returns TRUE upon success. Otherwise, it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

See Also

EngMapFile


EngUnmapFontFile

EngUnmapFontFile is obsolete. Use EngUnmapFontFileFD instead.

VOID
  EngUnmapFontFile(
  ULONG_PTR  iFile
    );

Headers

Declared in winddi.h. Include winddi.h.


EngUnmapFontFileFD

EngUnmapFontFileFD unmaps the specified font file from system memory.

VOID
  EngUnmapFontFileFD(
    IN ULONG_PTR  iFile
    );

Parameters

iFile
Identifies the font file to be unmapped. This identifier is obtained from DrvLoadFontFile.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

A font driver calls EngUnmapFontFileFD to unmap a font file that was mapped by EngMapFontFileFD.


EngUnsecureMem

EngUnsecureMem unlocks an address range that is locked down in memory.

VOID
  EngUnsecureMem(
    IN HANDLE  hSecure
    );

Parameters

hSecure
Is a handle to the address range that is locked down. This handle is returned by EngSecureMem.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.


EngWaitForSingleObject

EngWaitForSingleObject puts the current thread of the display driver into a wait state until the specified event object is set to the signaled state, or until the wait times out.

BOOL
  EngWaitForSingleObject(
    IN PEVENT  pEvent,
    IN PLARGE_INTEGER  pTimeOut
    );

Parameters

pEvent
Points to an initialized event object. This event object handle was obtained in a previous call to EngCreateEvent.
pTimeOut
(Optional) Points to a time-out value that specifies the absolute or relative time at which the wait is to be completed. A negative value specifies an interval relative to the current time. The value should be expressed in units of 100 nanoseconds. Absolute expiration times track any changes in the system time; relative expiration times are not affected by system time changes. If pTimeOut is NULL, the calling thread remains in a waiting state until the event object is signalled.

Return Value

EngWaitForSingleObject returns TRUE upon success. Otherwise, it returns FALSE. A return value of FALSE indicates that one of the parameters is invalid, or that a time-out occurred.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function is available in Windows XP and later.

EngWaitForSingleObject causes a display driver thread to be put into a wait state. The display driver thread stays in the wait state until either the event object is set to the signaled state or until the wait times out. If no time-out value is supplied, the display driver thread remains in the wait state until the event object is set to the signaled state.

A synchronization event is automatically reset to the nonsignaled state when the wait is satisfied. Thus, only one wait will be satisfied per call to EngSetEvent or VideoPortSetEvent. In contrast, a notification event will not be automatically reset.

A time-out value of zero allows the driver to test the wait condition and to conditionally perform any side effects provided that the wait can be immediately satisfied.

The display driver can synchronize drawing operations between itself and the video miniport driver by calling EngWaitForSingleObject with an event object, and waiting until the miniport driver sets the event object to the signaled state.

The driver cannot call EngWaitForSingleObject on events returned from EngMapEvent.

See Also

EngCreateEvent, EngSetEvent, VideoPortSetEvent


EngWideCharToMultiByte

EngWideCharToMultiByte converts a wide character string into an ANSI source string using the specified code page.

INT
  EngWideCharToMultiByte(
    IN UINT  CodePage,
    IN LPWSTR  WideCharString,
    IN INT  BytesInWideCharString,
    OUT LPSTR  MultiByteString,
    IN INT  BytesInMultiByteString
    );

Parameters

CodePage
Specifies the code page to use to perform the translation.
WideCharString
Points to a buffer containing the wide character string to be translated.
BytesInWideCharString
Specifies the size, in bytes, of WideCharString.
MultiByteString
Points to a buffer into which the translated character string is to be copied
BytesInMultiByteString
Specifies the number of bytes in MultiByteString. If MultiByteString is not large enough to contain the translation, EngWideCharToMultiByte truncates the string, and does not report an error.

Return Value

EngWideCharToMultiByte returns the number of bytes converted into multibyte form, if successful. Otherwise, it returns -1.

Headers

Declared in winddi.h. Include winddi.h.

See Also

EngMultiByteToWideChar, EngUnicodeToMultiByteN


EngWritePrinter

GDI's EngWritePrinter function allows printer graphics DLLs to send a data stream to printer hardware.

BOOL
  EngWritePrinter(
    IN HANDLE  hPrinter,
    IN LPVOID  pBuf,
    IN DWORD  cbBuf,
    OUT LPDWORD  pcWritten
    );

Parameters

hPrinter
Is a caller-supplied printer handle. This should be the handle received as the DrvEnablePDEV function's hDriver parameter value.
pBuf
Is a caller-supplied pointer to a buffer containing a byte stream to be sent to the printer.
cbBuf
Is a caller-supplied number of bytes contained in the buffer pointed to by pBuf.
pcWritten
Is a caller-supplied pointer to a DWORD in which the number of bytes actually written to the printer is returned.

Return Value

If the operation succeeds, the function returns TRUE; otherwise it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Printer graphics DLLs call EngWritePrinter to send data streams (either control sequences or image data) to the print spooler, which in turn sends the data to the printer hardware by calling the appropriate print monitor. The function returns after the spooler receives the data.

The buffer pointed to by pBuf cannot be in user memory; that is, pBuf cannot point to memory allocated by EngCreateBitmap with the BMF_USERMEM flag set or by EngAllocUserMem.

For additional information about calling EngWritePrinter, see Rendering a Print Job.


FLOATOBJ_Add

FLOATOBJ_Add adds the two FLOATOBJs, and returns with the result in the first parameter.

VOID
  FLOATOBJ_Add(
    IN OUT PFLOATOBJ  pf,
    IN PFLOATOBJ  pf1
    );

Parameters

pf
Points to the first FLOATOBJ operand. When the function returns, *pf will be reset to the sum of *pf and *pf1.
pf1
Points to the second FLOATOBJ operand.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

The FLOATOBJ_Xxx services allow graphics drivers to emulate floating point arithmetic. An NT-based operating system does not support kernel-mode floating point operations on some systems.

See Also

FLOATOBJ


FLOATOBJ_AddFloat

FLOATOBJ_AddFloat adds the value of type FLOATL to the FLOATOBJ, and returns with the result in the first parameter.

VOID
  FLOATOBJ_AddFloat(
    IN OUT PFLOATOBJ  pf,
    IN FLOATL  f
    );

Parameters

pf
Points to the FLOATOBJ operand. When the function returns, *pf will be reset to the sum of *pf and *f.
f
Specifies the FLOATL operand. This value is converted to a FLOATOBJ for the summation.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

The FLOATOBJ_Xxx services allow graphics drivers to emulate floating point arithmetic. An NT-based operating system does not support kernel-mode floating point operations on some systems.

See Also

FLOATOBJ


FLOATOBJ_AddLong

FLOATOBJ_AddLong adds the value of type LONG to the FLOATOBJ, and returns with the result in the first parameter.

VOID
  FLOATOBJ_AddLong(
    IN OUT PFLOATOBJ  pf,
    IN LONG  l
    );

Parameters

pf
Points to the FLOATOBJ operand. When the function returns, *pf will be reset to the sum of *pf and *f.
l
Specifies the LONG operand. This value is converted to a FLOATOBJ for the summation.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

The FLOATOBJ_Xxx services allow graphics drivers to emulate floating point arithmetic. An NT-based operating system does not support kernel-mode floating point operations on some systems.

See Also

FLOATOBJ


FLOATOBJ_Div

FLOATOBJ_Div divides the two FLOATOBJs, and returns with the result in the first parameter.

VOID
  FLOATOBJ_Div(
    IN OUT PFLOATOBJ  pf,
    IN PFLOATOBJ  pf1
    );

Parameters

pf
Points to the first FLOATOBJ operand. When the function returns, *pf will be reset to the quotient of *pf divided by *pf1.
pf1
Points to the second FLOATOBJ operand.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

The FLOATOBJ_Xxx services allow graphics drivers to emulate floating point arithmetic. An NT-based operating system does not support kernel-mode floating point operations on some systems.

See Also

FLOATOBJ


FLOATOBJ_DivFloat

FLOATOBJ_DivFloat divides the FLOATOBJ by the value of type FLOATL, and returns with the result in the first parameter.

VOID
  FLOATOBJ_DivFloat(
    IN OUT PFLOATOBJ  pf,
    IN FLOATL  f
    );

Parameters

pf
Points to the FLOATOBJ operand. When the function returns, *pf will be reset to the quotient of *pf divided by f.
f
Specifies the FLOATL operand. This value is converted to a FLOATOBJ for the division.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

The FLOATOBJ_Xxx services allow graphics drivers to emulate floating point arithmetic. An NT-based operating system does not support kernel-mode floating point operations on some systems.

See Also

FLOATOBJ


FLOATOBJ_DivLong

FLOATOBJ_DivLong divides the FLOATOBJ by the value of type LONG, and returns with the result in the first parameter.

VOID
  FLOATOBJ_DivLong(
    IN OUT PFLOATOBJ  pf,
    IN LONG  l
    );

Parameters

pf
Points to the FLOATOBJ operand. When the function returns, *pf will be reset to the quotient of *pf divided by l.
l
Specifies the LONG operand. This value is converted to a FLOATOBJ for the division.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

The FLOATOBJ_Xxx services allow graphics drivers to emulate floating point arithmetic. An NT-based operating system does not support kernel-mode floating point operations on some systems.

See Also

FLOATOBJ


FLOATOBJ_Equal

FLOATOBJ_Equal determines whether the two FLOATOBJs are equal.

BOOL
  FLOATOBJ_Equal(
    IN PFLOATOBJ  pf,
    IN PFLOATOBJ  pf1
    );

Parameters

pf
Points to the first FLOATOBJ operand.
pf1
Points to the second FLOATOBJ operand.

Return Value

FLOATOBJ_Equal returns TRUE if *pf and *pf1 are equal; otherwise it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The FLOATOBJ_Xxx services allow graphics drivers to emulate floating point arithmetic. An NT-based operating system does not support kernel-mode floating point operations on some systems.

See Also

FLOATOBJ


FLOATOBJ_EqualLong

FLOATOBJ_EqualLong determines whether the FLOATOBJ and the value of type LONG are equal.

BOOL
  FLOATOBJ_EqualLong(
    IN PFLOATOBJ  pf,
    IN LONG  l
    );

Parameters

pf
Points to the FLOATOBJ.
l
Specifies the LONG value. This value is converted to a FLOATOBJ for the comparison.

Return Value

FLOATOBJ_EqualLong returns TRUE if *pf and the FLOATOBJ-equivalent value of l are equal; otherwise it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The FLOATOBJ_Xxx services allow graphics drivers to emulate floating point arithmetic. An NT-based operating system does not support kernel-mode floating point operations on some systems.

See Also

FLOATOBJ


FLOATOBJ_GetFloat

FLOATOBJ_GetFloat calculates and returns the FLOAT-equivalent value of the specified FLOATOBJ.

LONG
  FLOATOBJ_GetFloat(
    IN PFLOATOBJ  pf
    );

Parameters

pf
Points to the FLOATOBJ to be converted to a FLOAT.

Return Value

FLOATOBJ_GetFloat returns the FLOAT-equivalent value of *pf. The return value is of type LONG, and needs to be typecast to a FLOAT by the driver.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The FLOATOBJ_Xxx services allow graphics drivers to emulate floating point arithmetic. An NT-based operating system does not support kernel-mode floating point operations on some systems.

See Also

FLOATOBJ


FLOATOBJ_GetLong

FLOATOBJ_GetLong calculates and returns the LONG-equivalent value of the specified FLOATOBJ.

LONG
  FLOATOBJ_GetLong(
    IN PFLOATOBJ  pf
    );

Parameters

pf
Points to the FLOATOBJ to be converted to a LONG.

Return Value

FLOATOBJ_GetFloat returns the LONG-equivalent value of *pf.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The FLOATOBJ_Xxx services allow graphics drivers to emulate floating point arithmetic. An NT-based operating system does not support kernel-mode floating point operations on some systems.

See Also

FLOATOBJ


FLOATOBJ_GreaterThan

FLOATOBJ_GreaterThan determines whether the first FLOATOBJ is greater than the second FLOATOBJ.

BOOL
  FLOATOBJ_GreaterThan(
    IN PFLOATOBJ  pf,
    IN PFLOATOBJ  pf1
    );

Parameters

pf
Points to the first FLOATOBJ.
pf1
Points to the second FLOATOBJ.

Return Value

FLOATOBJ_GreaterThan returns TRUE if *pf is greater than *pf1; otherwise it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The FLOATOBJ_Xxx services allow graphics drivers to emulate floating point arithmetic. An NT-based operating system does not support kernel-mode floating point operations on some systems.

See Also

FLOATOBJ


FLOATOBJ_GreaterThanLong

FLOATOBJ_GreaterThanLong determines whether the FLOATOBJ is greater than the value of type LONG.

BOOL
  FLOATOBJ_GreaterThanLong(
    IN PFLOATOBJ  pf,
    IN LONG  l
    );

Parameters

pf
Points to the FLOATOBJ.
l
Specifies the LONG value. This value is converted to a FLOATOBJ for the comparison.

Return Value

FLOATOBJ_GreaterThanLong returns TRUE if *pf is greater than the FLOATOBJ-equivalent of l; otherwise it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The FLOATOBJ_Xxx services allow graphics drivers to emulate floating point arithmetic. An NT-based operating system does not support kernel-mode floating point operations on some systems.

See Also

FLOATOBJ


FLOATOBJ_LessThan

FLOATOBJ_LessThan determines whether the first FLOATOBJ is less than the second FLOATOBJ.

BOOL
  FLOATOBJ_LessThan(
    IN PFLOATOBJ  pf,
    IN PFLOATOBJ  pf1
    );

Parameters

pf
Points to the first FLOATOBJ.
pf1
Points to the second FLOATOBJ.

Return Value

FLOATOBJ_LessThan returns TRUE if *pf is less than *pf1; otherwise it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The FLOATOBJ_Xxx services allow graphics drivers to emulate floating point arithmetic. An NT-based operating system does not support kernel-mode floating point operations on some systems.

See Also

FLOATOBJ


FLOATOBJ_LessThanLong

FLOATOBJ_LessThanLong determines whether the FLOATOBJ is less than the value of type LONG.

BOOL
  FLOATOBJ_LessThanLong(
    IN PFLOATOBJ  pf,
    IN LONG  l
    );

Parameters

pf
Points to the FLOATOBJ.
l
Specifies the LONG value. This value is converted to a FLOATOBJ for the comparison.

Return Value

FLOATOBJ_LessThanLong returns TRUE if *pf is less than the FLOATOBJ-equivalent of l; otherwise it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The FLOATOBJ_Xxx services allow graphics drivers to emulate floating point arithmetic. An NT-based operating system does not support kernel-mode floating point operations on some systems.

See Also

FLOATOBJ


FLOATOBJ_Mul

FLOATOBJ_Mul multiplies the two FLOATOBJs, and returns with the result in the first parameter.

VOID
  FLOATOBJ_Mul(
    IN OUT PFLOATOBJ  pf,
    IN PFLOATOBJ  pf1
    );

Parameters

pf
Points to the first FLOATOBJ operand. When the function returns, *pf will be reset to the value ( *pf * *pf1).
pf1
Points to the second FLOATOBJ operand.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

The FLOATOBJ_Xxx services allow graphics drivers to emulate floating point arithmetic. An NT-based operating system does not support kernel-mode floating point operations on some systems.

See Also

FLOATOBJ


FLOATOBJ_MulFloat

FLOATOBJ_MulFloat multiplies the FLOATOBJ by the value of type FLOATL, and returns with the result in the first parameter.

VOID
  FLOATOBJ_MulFloat(
    IN OUT PFLOATOBJ  pf,
    IN FLOATL  f
    );

Parameters

pf
Points to the FLOATOBJ operand. When the function returns, *pf will be reset to the value (*pf * f).
f
Specifies the FLOATL operand. This value is converted to a FLOATOBJ for the multiplication.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

The FLOATOBJ_Xxx services allow graphics drivers to emulate floating point arithmetic. An NT-based operating system does not support kernel-mode floating point operations on some systems.

See Also

FLOATOBJ


FLOATOBJ_MulLong

FLOATOBJ_MulLong multiplies the FLOATOBJ by the value of type LONG, and returns with the result in the first parameter.

VOID
  FLOATOBJ_MulLong(
    IN OUT PFLOATOBJ  pf,
    IN LONG  l
    );

Parameters

pf
Points to the FLOATOBJ operand. When the function returns, *pf will be reset to the value ( *pf * l).
l
Specifies the LONG operand. This value is converted to a FLOATOBJ for the multiplication.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

The FLOATOBJ_Xxx services allow graphics drivers to emulate floating point arithmetic. An NT-based operating system does not support kernel-mode floating point operations on some systems.

See Also

FLOATOBJ


FLOATOBJ_Neg

FLOATOBJ_Neg negates the FLOATOBJ.

VOID
  FLOATOBJ_Neg(
    IN OUT PFLOATOBJ  pf
    );

Parameters

pf
Points to the FLOATOBJ to be negated. When the function returns, *pf will contain the negated value.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

The FLOATOBJ_Xxx services allow graphics drivers to emulate floating point arithmetic. An NT-based operating system does not support kernel-mode floating point operations on some systems.

See Also

FLOATOBJ


FLOATOBJ_SetFloat

FLOATOBJ_SetFloat assigns the value of type FLOATL to the FLOATOBJ.

VOID
  FLOATOBJ_SetFloat(
    OUT PFLOATOBJ  pf,
    IN FLOATL  f
    );

Parameters

pf
Points to the FLOATOBJ that will receive the value of f.
f
Specifies the FLOATL value. This value is converted to a FLOATOBJ for the assignment.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

The FLOATOBJ_Xxx services allow graphics drivers to emulate floating point arithmetic. An NT-based operating system does not support kernel-mode floating point operations on some systems.

See Also

FLOATOBJ


FLOATOBJ_SetLong

FLOATOBJ_SetLong assigns the value of type LONG to the FLOATOBJ.

VOID
  FLOATOBJ_SetLong(
    OUT PFLOATOBJ  pf,
    IN LONG  l
    );

Parameters

pf
Points to the FLOATOBJ that will receive the value of l.
l
Specifies the LONG value. This value is converted to a FLOATOBJ for the assignment.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

The FLOATOBJ_Xxx services allow graphics drivers to emulate floating point arithmetic. An NT-based operating system does not support kernel-mode floating point operations on some systems.

See Also

FLOATOBJ


FLOATOBJ_Sub

FLOATOBJ_Sub subtracts the second FLOATOBJ from the first, and returns with the result in the first parameter.

VOID
  FLOATOBJ_Sub(
    IN OUT PFLOATOBJ  pf,
    IN PFLOATOBJ  pf1
    );

Parameters

pf
Points to the first FLOATOBJ operand. When the function returns, *pf will be reset to the value (*pf - *pf1).
pf1
Points to the second FLOATOBJ operand.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

The FLOATOBJ_Xxx services allow graphics drivers to emulate floating point arithmetic. An NT-based operating system does not support kernel-mode floating point operations on some systems.

See Also

FLOATOBJ


FLOATOBJ_SubFloat

FLOATOBJ_SubFloat subtracts the value of type FLOATL from the FLOATOBJ, and returns with the result in the first parameter.

VOID
  FLOATOBJ_SubFloat(
    IN OUT PFLOATOBJ  pf,
    IN FLOATL  f
    );

Parameters

pf
Points to the FLOATOBJ operand. When the function returns, *pf will be reset to the value (*pf - f).
f
Specifies the FLOATL operand. This value is converted to a FLOATOBJ for the subtraction.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

The FLOATOBJ_Xxx services allow graphics drivers to emulate floating point arithmetic. An NT-based operating system does not support kernel-mode floating point operations on some systems.

See Also

FLOATOBJ


FLOATOBJ_SubLong

FLOATOBJ_SubLong subtracts the value of type LONG from the FLOATOBJ, and returns with the result in the first parameter.

VOID
  FLOATOBJ_SubLong(
    IN OUT PFLOATOBJ  pf,
    IN LONG  l
    );

Parameters

pf
Points to the FLOATOBJ operand. When the function returns, *pf will be reset to the value (*pf - l).
l
Specifies the LONG operand. This value is converted to a FLOATOBJ for the subtraction.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

The FLOATOBJ_Xxx services allow graphics drivers to emulate floating point arithmetic. An NT-based operating system does not support kernel-mode floating point operations on some systems.

See Also

FLOATOBJ


FONTOBJ_cGetAllGlyphHandles

FONTOBJ_cGetAllGlyphHandles allows the device driver to find every glyph handle of a GDI font.

ULONG
  FONTOBJ_cGetAllGlyphHandles(
    IN FONTOBJ  *pfo,
    OUT HGLYPH  *phg
    );

Parameters

pfo
Points to the FONTOBJ structure that is to be downloaded.
phg
Points to a buffer large enough to hold all the glyph handles in the font. This parameter can be NULL.

Return Value

The return value is the number of glyph handles supported by the font.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A driver uses this function to download an entire font.

The driver must provide a buffer large enough to contain the output. GDI copies all glyph handles belonging to the associated font to this buffer.

The number of glyphs in the font can be determined by calling FONTOBJ_vGetInfo, or by calling FONTOBJ_cGetAllGlyphHandles with the phg parameter set to null.

See Also

FONTOBJ


FONTOBJ_cGetGlyphs

FONTOBJ_cGetGlyphs is a service to the font consumer that translates glyph handles into pointers to glyph data, which are valid until the next call to FONTOBJ_cGetGlyphs.

ULONG
  FONTOBJ_cGetGlyphs(
    IN FONTOBJ  *pfo,
    IN ULONG  iMode,
    IN ULONG  cGlyph,
    IN HGLYPH  *phg,
    OUT PVOID  **ppvGlyph
    );

Parameters

pfo
Points to a FONTOBJ structure containing the glyph handles to be translated.
iMode
Specifies whether data will be written as bitmaps or as outline objects. This parameter can be one of the following values:
Value | Meaning
FO_GLYPHBITS | Data will consist of GLYPHBITS structures that define the bitmaps of the glyphs.
FO_PATHOBJ Data will consist of PATHOBJ structures that define the outlines of the glyphs.

To determine whether the path should be filled or stroked, the font consumer should check the flInfo member of the IFIMETRICS structure. If the FM_INFO_RETURNS_STROKES flag is set, the path should be stroked; otherwise, the path should be filled.

cGlyph
Specifies the number of glyphs to be translated. The only acceptable value is 1 (the code assumes 1, regardless of the value specified).
phg
Points to an array of cGlyph HGLYPH structures supplied by the driver.
ppvGlyph
Points to a buffer that is to receive cGlyph pointers to GLYPHDEF structures, corresponding to the handles passed in by the driver.

Return Value

The return value is the count of pointers passed to the driver if the function is successful. Otherwise, it is zero, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function should be used if the driver is caching fonts.

See Also

DrvGetGlyphMode, FONTOBJ, FONTOBJ_cGetAllGlyphHandles, GLYPHBITS, IFIMETRICS, PATHOBJ


FONTOBJ_pfdg

FONTOBJ_pfdg retrieves the pointer to the FD_GLYPHSET structure associated with the specified font.

FD_GLYPHSET *
  FONTOBJ_pfdg(
    IN FONTOBJ  *pfo
    );

Parameters

pfo
Points to the FONTOBJ structure for which the associated FD_GLYPHSET structure is to be returned.

Return Value

FONTOBJ_pfdg returns a pointer to the FD_GLYPHSET structure associated with the specified font.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Printer drivers can call FONTOBJ_pfdg to determine which Unicode code points are supported in a GDI font. The printer driver can then determine whether it can optimize performance by instead using a similar printer-resident font to display a text string.

See Also

FD_GLYPHSET, FONTOBJ


FONTOBJ_pifi

FONTOBJ_pifi retrieves the pointer to the IFIMETRICS structure associated with a specified font.

IFIMETRICS *
  FONTOBJ_pifi(
    IN FONTOBJ  *pfo
    );

Parameters

pfo
Points to the FONTOBJ structure for which the associated IFIMETRICS structure is to be retrieved.

Return Value

The return value is a pointer to the IFIMETRICS structure associated with the specified font if the function is successful. Otherwise, it is NULL.

Headers

Declared in winddi.h. Include winddi.h.


FONTOBJ_pjOpenTypeTablePointer

FONTOBJ_pjOpenTypeTablePointer returns a pointer to a view of an OpenType® table.

PBYTE
  FONTOBJ_pjOpenTypeTablePointer(
    IN FONTOBJ  *pfo,
    IN ULONG  ulTag,
    OUT ULONG  *pcjTable
    );

Parameters

pfo
Points to the FONTOBJ that identifies the font whose OpenType table is being queried.
ulTag
Identifies the font table whose pointer is to be returned.
pcjTable
Points to the location in which GDI returns the size in bytes of the table being queried.

Return Value

FONTOBJ_pjOpenTypeTablePointer returns a pointer to a view of the OpenType table. A return value of NULL indicates that the requested table is not present in this font.

Headers

Declared in winddi.h. Include winddi.h.

Comments

FONTOBJ_pjOpenTypeTablePointer can be called by printer drivers that can download OpenType fonts or parts of OpenType fonts to the printer.

The pointer to a table returned by FONTOBJ_pjOpenTypeTablePointer is guaranteed to be valid only during the scope of the DrvTextOut call to which pfo is passed as a parameter.

See Also

DrvTextOut, FONTOBJ


FONTOBJ_pQueryGlyphAttrs

FONTOBJ_pQueryGlyphAttrs returns information about a font's glyphs.

PFD_GLYPHATTR APIENTRY
  FONTOBJ_pQueryGlyphAttrs(
    IN FONTOBJ  *pfo,
    IN ULONG  iMode
    );

Parameters

pfo
Is a caller-supplied pointer to a FONTOBJ structure identifying the font for which attributes are being requested.
iMode
Is a caller-supplied flag indicating the type of glyph attribute being requested. The following flag is defined:
Flag | Definition
FO_ATTR_MODE_ROTATE | The function returns an array indicating which glyphs of a vertical font must be rotated.

Return Value

FONTOBJ_pQueryGlyphAttrs returns a pointer to an FD_GLYPHATTR structure. If an error is encountered, such as an invalid input argument, or if the font described by the FONTOBJ structure is not a vertical font, the function returns NULL.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Currently, the only attribute flag defined is FO_ATTR_MODE_ROTATE. This flag is meant for use by printer drivers that support printers with built-in font rasterizers. The driver can call the FONTOBJ_pQueryGlyphAttrs function, specifying the FO_ATTR_MODE_ROTATE flag, to determine which glyphs within a vertical font must be rotated.

Vertical fonts have a font name that starts with the "@" character. To determine if the current font is a vertical font, the driver can check for the FO_VERT_FACE flag in the flFontType member of the font's FONTOBJ structure.

Rotation information is returned in the FD_GLYPHATTR structure that is used as the function's return value.

The FONTOBJ_pQueryGlyphAttrs function is supplied by GDI. When a printer driver calls FONTOBJ_pQueryGlyphAttrs, GDI calls the appropriate font driver's DrvQueryGlyphAttrs function to obtain the requested information.


FONTOBJ_pvTrueTypeFontFile

FONTOBJ_pvTrueTypeFontFile retrieves a kernel-mode pointer to a view of a TrueType, OpenType, or Type1 font file.

PVOID
  FONTOBJ_pvTrueTypeFontFile(
    IN FONTOBJ  *pfo,
    OUT ULONG  *pcjFile
    );

Parameters

pfo
Points to the FONTOBJ structure with which the TrueType, PostScript OpenType, or PostScript Type1 font is associated.
pcjFile
Points to a location in which GDI returns the size, in bytes, of the view of the font file.

Return Value

FONTOBJ_pvTrueTypeFontFile returns a pointer to a kernel-mode view of a font file upon success. If the FONTOBJ structure identifies a Type1 font, the return value is a pointer to the memory mapped image of the pfb file. Otherwise, this function returns NULL.

Headers

Declared in winddi.h. Include winddi.h.

Comments

FONTOBJ_pvTrueTypeFontFile should be called only for TrueType, OpenType, or Type1 fonts. The pointer returned by FONTOBJ_pvTrueTypeFontFile is valid only within the scope of the calling DrvTextOut function. That is, the driver should not assume that the pointer returned by this function is valid upon exiting DrvTextOut and returning control to GDI.

See Also

FONTOBJ


FONTOBJ_pwszFontFilePaths

FONTOBJ_pwszFontFilePaths retrieves the file path(s) associated with a font.

LPWSTR
  FONTOBJ_pwszFontFilePaths(
    IN FONTOBJ  *pfo,
    OUT ULONG  *pcwc
    );

Parameters

pfo
Points to the FONTOBJ structure being queried.
pcwc
Points to the location in which GDI returns the number of Unicode characters, including terminating zeros, found in all the returned font file path strings.

Return Value

FONTOBJ_pwszFontFilePaths returns a pointer to an array of font file path strings upon success. Each string is zero terminated by a single Unicode zero. This function returns NULL upon failure or when the paths are not available for the specified font; that is, when the font is a temporary font added from a memory image.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Printer drivers can call FONTOBJ_pwszFontFilePaths when they want to do their own file mapping. File mapping is performed by calling EngMapFile.

Typically, there is only one file per font. For example, a TrueType font has only one file, whereas Type 1 fonts might require two files (a .pfm and .pfb).

See Also

EngMapFile, FONTOBJ


FONTOBJ_pxoGetXform

FONTOBJ_pxoGetXform retrieves the notional-to-device transform for the specified font.

XFORMOBJ
  FONTOBJ_pxoGetXform(
    IN FONTOBJ  *pfo
    );

Parameters

pfo
Points to the FONTOBJ structure for which the transform is to be retrieved.

Return Value

The return value is a XFORMOBJ structure that can be used by the XFORMOBJ_Xxx service routines. The returned XFORMOBJ structure assumes that:

  1. The distance between the pixels is in device space units.
  2. Both notional and device space have positive values of y in the top-to-bottom direction.

If the font is a raster font, the return value is NULL.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The driver needs the notional-to-device transform to realize a driver-supplied font.

See Also

FONTOBJ, XFORMOBJ


FONTOBJ_vGetInfo

FONTOBJ_vGetInfo retrieves information about an associated font.

VOID
  FONTOBJ_vGetInfo(
    IN FONTOBJ  *pfo,
    IN ULONG  cjSize,
    OUT FONTINFO  *pfi
    );

Parameters

pfo
Points to the FONTOBJ structure to be queried.
cjSize
Specifies the size in bytes of the buffer pointed to by pfi.
pfi
Points to a buffer previously allocated by the driver. GDI writes a FONTINFO structure to this buffer.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.


HeapVidMemAllocAligned

HeapVidMemAllocAligned allocates off-screen memory for a display driver by using the DirectDraw video memory heap manager.

FLATPTR
  HeapVidMemAllocAligned(
    IN LPVIDMEM  lpVidMem,
    IN DWORD  dwWidth,
    IN DWORD  dwHeight,
    IN LPSURFACEALIGNMENT  lpAlignment,
    OUT LPLONG  lpNewPitch
    );

Parameters

lpVidMem
Points to a VIDEOMEMORY structure that represents the DirectDraw heap from which to allocate the surface.
dwWidth
Is the width in bytes of the requested surface.
dwHeight
Is the height in scanlines of the requested surface.
lpAlignment
Points to a SURFACEALIGNMENT structure that describes the alignment restrictions for the surface.
lpNewPitch
Is the location in which the resulting pitch value is written. This information is relevant only to linear (non-rectangular) off-screen heaps.

Return Value

HeapVidMemAllocAligned returns the FLATPTR offset of the resulting allocation upon success. Otherwise, it returns zero.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The driver should use the array of VIDEOMEMORY structures its DrvGetDirectDrawInfo function receives to determine the value of lpVidMem with which to call HeapVidMemAllocAligned. The driver receives this array in the pvmList parameter during the second call to DrvGetDirectDrawInfo. It is possible that DrvGetDirectDrawInfo might not be called when low memory conditions exist on the system. Consequently, the driver should always check to ensure that it has a non-NULL pointer in pvmList.

See Also

DrvGetDirectDrawInfo, SURFACEALIGNMENT, VIDEOMEMORY, VidMemFree


HT_ComputeRGBGammaTable

HT_ComputeRGBGammaTable is a halftone-related GDI service that causes GDI to compute device red, green, and blue intensities based on gamma numbers.

LONG
  HT_ComputeRGBGammaTable(
    IN USHORT  GammaTableEntries,
    IN USHORT  GammaTableType,
    IN USHORT  RedGamma,
    IN USHORT  GreenGamma,
    IN USHORT  BlueGamma,
    OUT LPBYTE  pGammaTable
    );

Parameters

GammaTableEntries
Specifies the total number of steps in the table for each of red, green, and blue intensities. This value must greater than 1 and less than or equal to 256 (that is, 2 <= GammaTableEntries <= 256). For example, a value of 256 means there are 256 red entries, 256 green entries, and 256 blue entries in the gamma table.
GammaTableType
Specifies pGammaTable's organization. Valid table types are:
GammaTableType | Meaning
0 | The gamma table's red, green, and blue values are interleaved together. Each gamma step is 3 bytes; 1 byte each for red, green, and blue.
1 | The red, green, and blue tables are packed separately; that is, the entire red table is followed by the entire green table, which is followed by the entire blue table. Individual entries are 1 byte each, making each sub-table a total of GammaTableEntries bytes in length.

RedGamma, GreenGamma, BlueGamma
Specify the red, green, and blue gamma values. These USHORT values are interpreted as real numbers whose four least-significant digits are to the right of the (implied) decimal point. For example, a gamma value of 10000 represents the real number 1.0000, and 12345 represents 1.2345. The minimum gamma value allowed is 0.0000, and the maximum allowable value is 6.5535.
pGammaTable
Points to the array of bytes in which the gamma table's red, green, and blue intensities will be written. The returned table is organized as specified by the GammaTableType parameter.

Return Value

The return value is the number of gamma entries written to pGammaTable; upon success, this value is equal to GammaTableEntries. If GammaTableEntries is less than 2 or greater than 256, the return value is 0.

The red, green, and blue intensities returned in pGammaTable range from 0 to 255.

Headers

Declared in winddi.h. Include winddi.h.

Comments

GDI halftone service routines use a special palette to do halftoning. If the device selects an 8-bit per pixel palette from a pool of 24-bit device colors for a 16-bit or 24-bit type surface, GDI assumes red, green, and blue color steps; each has equal brightness.

GDI provides this service so that the driver can query the 8-bit per pixel halftone palette used by GDI or compute gamma corrected and equalized RGB color intensities for the device.


HT_Get8BPPFormatPalette

HT_Get8BPPFormatPalette returns a halftone palette for use on standard 8-bits per pixel device types.

LONG
  HT_Get8BPPFormatPalette(
    OUT LPPALETTEENTRY  pPaletteEntry,
    IN USHORT  RedGamma,
    IN USHORT  GreenGamma,
    IN USHORT  BlueGamma
    );

Parameters

pPaletteEntry
Points to an array of PALETTEENTRY structures. When this pointer is not NULL, GDI assumes that it points to valid memory space in which GDI can place the entire 8-bits per pixel halftone palette.
RedGamma, GreenGamma, BlueGamma
Specify the red, green, and blue gamma values. These USHORT values are interpreted as real numbers whose four least-significant digits are to the right of the (implied) decimal point. For example, a gamma value of 10000 represents the real number 1.0000, and 12345 represents 1.2345. The minimum gamma value allowed is 0.0000, and the maximum allowable value is 6.5535.

Return Value

If pPaletteEntry is not NULL, the return value is the number of PALETTEENTRY structures that GDI filled in starting at the memory location pointed to by pPaletteEntry. If pPaletteEntry is NULL, the return value is the total count of PALETTEENTRY structures required to store the 8-bits per pixel halftone palette.

Headers

Declared in winddi.h. Include winddi.h.

Comments

HT_Get8BPPFormatPalette is a halftone-related GDI service that drivers can use to acquire the system's standard 8-bits per pixel halftone palette.

The PALETTEENTRY structure is documented in the Platform SDK documentation.


HT_Get8BPPMaskPalette

HT_Get8BPPMaskPalette returns a mask palette for an 8-bits-per-pixel device type.

LONG
  HT_Get8BPPMaskPalette(
    IN OUT LPPALETTEENTRY  pPaletteEntry,
    IN BOOL  Use8BPPMaskPal,
    IN BYTE  CMYMask,
    IN USHORT  RedGamma,
    IN USHORT  GreenGamma,
    IN USHORT  BlueGamma
    );

Parameters

pPaletteEntry
Points to the array of PALETTEENTRY structures (described in the Platform SDK documentation) to be filled in. GDI assumes that it points to valid memory space in which GDI can place the entire 8-bit-per-pixel halftone palette.

For drivers that run on Windows XP and later operating system versions, pPaletteEntry[0] is checked to determine how GDI will return the composed CMY palette. If pPaletteEntry[0] is set to 'RGB0', the palette will be in one of the CMY_INVERTED modes and will have its indexes inverted. That is, index 0 in the palette is black, and index 255 is white. If pPaletteEntry[0] is not set to 'RGB0', the palette is a normal CMY palette, with index 0 being white and index 255 being black. See Using GDI 8-Bit-Per-Pixel CMY Mask Modes for new requirements and details on how to use this parameter.

Use8BPPMaskPal
Indicates which type of palette should be returned. When Use8BPPMaskPal is TRUE, HT_Get8BPPMaskPalette sets the pPaletteEntry parameter with the address of a CMY palette (an array of PALETTEENTRY structures) that is described by the bit mask specified in CMYMask. When Use8BPPMaskPal is FALSE, the function sets pPaletteEntry with the address of a standard RGB 8-bit-per-pixel halftone palette.
CMYMask
Specifies information about the array of PALETTEENTRY structures pointed to by pPaletteEntry. This parameter can have one of the following values:
Value | Meaning
0 | Gray scale with 256 levels
1 | Five levels each of cyan, magenta, and yellow (each ranging from 0 to 4), for a total of 125 colors
2 | Six levels each of cyan, magenta, and yellow (each ranging from 0 to 5), for a total of 216 colors
3 to 255 | A bitmask that specifies that maximum number of levels of cyan, magenta, and yellow, respectively.

For all values of CMYMask, and for Windows XP and later operating system versions, the value in pPaletteEntry[0] determines whether the palette that follows pPaletteEntry [0] is a normal CMY palette, or one of the CMY_INVERTED mode palettes. If pPaletteEntry[0] is 'RGB0', the palette mode is CMY_INVERTED. If pPaletteEntry[0] is not 'RGB0', the palette is a normal CMY palette.

For values of CMYMask from 3 to 255, inclusive, the value is a bitmask in which groups of bits have the following meanings:

  • The three highest bits (bits 7,6,5) specify the number of levels of cyan. At most, seven levels of cyan (levels 1 to 7) are possible.
  • The middle three bits (bits 4,3,2) specify the number of levels of magenta. At most, seven levels of magenta (levels 1 to 7) are possible.
  • The two lowest bits (bits 1,0) specify the number of levels of yellow. At most, three levels of yellow (levels 1 to 3) are possible.
Palette Index Bit Number:   7   6   5   4   3   2   1   0
                            |       |   |       |   |   |
                            +---C---+   +---M---+   +-Y-+

For values of CMYMask ranging from 3 to 255, any bitmask combination in which the cyan, magenta, or yellow level bits are zero is invalid. In such cases, HT_Get8BPPMaskPalette returns a palette count of zero. See Using GDI 8-Bit-Per-Pixel CMY Mask Modes for more information.

RedGamma, GreenGamma, BlueGamma
If Use8BPPMaskPal is TRUE, the values of these parameters are not used. In that case, gamma values will be specified in the ciDevice member of the GDIINFO structure.

If Use8BPPMaskPal is FALSE, the values of these parameters specify the red, green, and blue gamma values, respectively, that GDI is to use to gamma-correct the palette. These USHORT values are interpreted as real numbers whose four least-significant digits are to the right of the decimal point. For example, a gamma value of 10000 represents the real number 1.0000, and 12345 represents 1.2345. The minimum gamma value allowed is 0.0000, and the maximum allowable value is 6.5535.

Return Value

If pPaletteEntry is not NULL, HT_Get8BPPMaskPalette returns the number of PALETTEENTRY structures that GDI filled out in the array to which pPaletteEntry points. If pPaletteEntry is NULL, the value returned is the total count of PALETTEENTRY structures required to store the halftone palette.

If an illegal value of the CMYMask parameter is used in the call to this function, HT_Get8BPPMaskPalette returns a value of zero.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The PALETTEENTRY structure is documented in the Platform SDK documentation.

Calling HT_Get8BPPMaskPalette with Use8BPPMaskPal set FALSE is equivalent to calling HT_Get8BPPFormatPalette.

See Using GDI 8-Bit-Per-Pixel CMY Mask Modes for more information about this function and how its parameters are used.

See Also

HT_Get8BPPFormatPalette


HTUI_DeviceColorAdjustment

HTUI_DeviceColorAdjustment can be used by graphics device drivers to display a dialog box that allows a user to adjust a device's halftoning properties.

LONG
  HTUI_DeviceColorAdjustment(
    IN LPSTR  pDeviceName,
    OUT PDEVHTADJDATA  pDevHTAdjData
      );

Parameters

pDeviceName
Is a caller-supplied pointer to a NULL-terminated string representing a displayable device name.
pDevHTAdjData
Is a caller-supplied pointer to a DEVHTADJDATA structure.

Return Value

The function returns the following values:

Return Value | Definition
Greater than 0 | The user chose the dialog box's OK button.
0 | The user chose the dialog box's Cancel button.
Less than 0 | An error occurred.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A graphics driver interface, such as a printer interface DLL, can call the HTUI_DeviceColorAdjustment function to display a dialog box that allows a user to view and modify the device's halftoning properties. Depending on member values specified for the DEVHTADJDATA structure, the function will either enable the dialog box for user modification or just display caller-specified default values. If user modification is allowed, the function returns the modified parameters to the caller (using the DEVHTAJDATA structure), so the driver can pass them to the device.


PALOBJ_cGetColors

PALOBJ_cGetColors copies RGB colors from an indexed palette.

ULONG
  PALOBJ_cGetColors(
    IN PALOBJ  *ppalo,
    IN ULONG  iStart,
    IN ULONG  cColors,
    OUT ULONG  *pulColors
    );

Parameters

ppalo
Points to the PALOBJ structure that contains the RGB colors to be copied.
iStart
Specifies the starting color index.
cColors
Specifies the number of colors to be written.
pulColors
Points to the buffer in which the colors are to be written.

Return Value

The return value is the number of colors written if the function is successful. Otherwise, it is zero.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A graphics driver can call this function in its implementation of DrvSetPalette.


PATHOBJ_bCloseFigure

PATHOBJ_bCloseFigure closes an open figure in a path by drawing a line from the current position to the first point of the figure.

BOOL
  PATHOBJ_bCloseFigure(
    IN PATHOBJ  *ppo
    );

Parameters

ppo
Points to a PATHOBJ structure that identifies the path to be closed.

Return Value

The return value is TRUE if the function is successful.

Headers

Declared in winddi.h. Include winddi.h.


PATHOBJ_bEnum

PATHOBJ_bEnum retrieves the next PATHDATA record from a specified path and enumerates the curves in the path.

BOOL
  PATHOBJ_bEnum(
    IN PATHOBJ  *ppo,
    OUT PATHDATA  *ppd
    );

Parameters

ppo
Points to a PATHOBJ structure whose curves and/or lines are to be enumerated.
ppd
Points to a PATHDATA structure that is to be filled.

Return Value

The return value is TRUE if the specified path contains more PATHDATA records, indicating that this service should be called again. Otherwise, if the output is the last PATHDATA record in the path, the return value is FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

PATHOBJ_bEnum can be called only after a call to PATHOBJ_vEnumStart has been made.

A PATHDATA structure describes all or part of a subpath (a connected part of a path). For example, a MoveTo call by the application within a path begins a new subpath.

See Also

PATHDATA, PATHOBJ, PATHOBJ_vEnumStart, PATHOBJ_vEnumStartClipLines


PATHOBJ_bEnumClipLines

PATHOBJ_bEnumClipLines enumerates clipped line segments from a given path.

BOOL
  PATHOBJ_bEnumClipLines(
    IN PATHOBJ  *ppo,
    IN ULONG  cb,
    OUT CLIPLINE  *pcl
    );

Parameters

ppo
Points to the path containing the clipped line segments that are to be enumerated.
cb
Specifies the size of the output buffer, in bytes. GDI does not write beyond this point in the buffer. The value of this parameter must be large enough to hold a CLIPLINE structure with at least one RUN structure. The driver should allocate space for several RUN structures.
pcl
Points to the buffer in which a CLIPLINE structure is returned. The structure contains the original unclipped control points for a line segment. (The correct pixels for the line cannot be computed without the original points.) RUN structures, which describe sets of pixels along the line that are not clipped away, are written to this buffer.

If a clip region is complex, a single line segment can be broken into many RUN structures. A segment is returned as many times as necessary to list all of its RUN structures.

The CLIPLINE structure contains the starting and ending points of the original unclipped line and the line segments, or RUN structures, of that line that are to appear on the display.

Return Value

The return value is TRUE if more line segments are to be enumerated, indicating that this service should be called again. Otherwise, it is FALSE, indicating that the returned segment is the last segment in the path.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The enumeration must be started with PATHOBJ_vEnumStartClipLines before the driver makes this call.

See Also

CLIPLINE, PATHOBJ_vEnumStartClipLines, RUN


PATHOBJ_bMoveTo

PATHOBJ_bMoveTo sets the current position in a given path.

BOOL
  PATHOBJ_bMoveTo(
    IN PATHOBJ  *ppo,
    IN POINTFIX  ptfx
    );

Parameters

ppo
Points to a PATHOBJ structure created by the driver.
ptfx
Points to a POINTFIX structure that specifies the new position.

Return Value

The return value is TRUE if the function is successful. Otherwise, it is FALSE, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function should only be called with PATHOBJ structures created by EngCreatePath.


PATHOBJ_bPolyBezierTo

PATHOBJ_bPolyBezierTo draws Bezier curves on a path.

BOOL
  PATHOBJ_bPolyBezierTo(
    IN PATHOBJ  *ppo,
    IN POINTFIX  *pptfx,
    IN ULONG  cptfx
    );

Parameters

ppo
Points to the PATHOBJ structure created by the driver.
pptfx
Points to the array of control points. Each set of three control points, along with the preceding control point, or current position, determines a Bezier curve.
cptfx
Specifies the count of points in pptfx. Must be a multiple of three.

Return Value

The return value is TRUE if the function is successful. Otherwise, it is FALSE, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

PATHOBJ_bPolyBezierTo must be called only with a PATHOBJ structure created by EngCreatePath.

See Also

PATHOBJ, PATHOBJ_bPolylineTo


PATHOBJ_bPolyLineTo

PATHOBJ_bPolyLineTo draws lines from the current position in a path through the specified points.

BOOL
  PATHOBJ_bPolyLineTo(
    IN PATHOBJ  *ppo,
    IN POINTFIX  *pptfx,
    IN ULONG  cptfx
    );

Parameters

ppo
Points to the PATHOBJ structure created by the driver.
pptfx
Points to an array of POINTFIX structures that define control points. The first line is drawn from the current position to the first point in this array; lines are then drawn to each subsequent point in the array.
cptfx
Specifies the count of points in pptfx. This is also the number of lines that will be added to the path.

Return Value

The return value is TRUE if the function is successful. Otherwise, it is FALSE, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

PATHOBJ_bPolyLineTo should only be called with PATHOBJ structures created by EngCreatePath.

See Also

PATHOBJ, PATHOBJ_bPolyBezierTo


PATHOBJ_vEnumStart

PATHOBJ_vEnumStart notifies a given PATHOBJ structure that the driver will be calling PATHOBJ_bEnum to enumerate lines and/or curves in the path.

VOID
  PATHOBJ_vEnumStart(
    IN PATHOBJ  *ppo
    );

Parameters

ppo
Points to a PATHOBJ structure whose lines and/or curves are to be enumerated.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

PATHOBJ_vEnumStart can be called at any time to restart an enumeration.


PATHOBJ_vEnumStartClipLines

PATHOBJ_vEnumStartClipLines allows the driver to request lines to be clipped against a specified clip region.

VOID
  PATHOBJ_vEnumStartClipLines(
    IN PATHOBJ  *ppo,
    IN CLIPOBJ  *pco,
    IN SURFOBJ  *pso,
    IN LINEATTRS  *pla
    );

Parameters

ppo
Points to the PATHOBJ structure that describes the specified clipping object.
pco
Points to a CLIPOBJ structure that describes the clip region.
pso
Points to a SURFOBJ structure that GDI queries to retrieve information about styling steps.
pla
Points to a LINEATTRS structure that GDI queries to retrieve line width and styling information.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function is useful when the clip region is more complex than a simple rectangle.

PATHOBJ_vEnumStartClipLines performs calculations for cosmetic wide lines. If the LINEATTRS structure needs a cosmetic wide line, the enumeration walks the given path as many times as needed to complete the widened figure.

This function should not be called for geometric wide lines or paths that contain Bezier curves.

Once begun, this enumeration process should not be restarted.

See Also

CLIPOBJ, LINEATTRS, PATHOBJ, SURFOBJ


PATHOBJ_vGetBounds

PATHOBJ_vGetBounds retrieves the bounding rectangle for the specified path.

VOID
  PATHOBJ_vGetBounds(
    IN PATHOBJ  *ppo,
    OUT PRECTFX  prectfx
    );

Parameters

ppo
Points to a PATHOBJ structure that describes the path for which a bounding rectangle is to be calculated.
prectfx
Points to the address where the RECTFX structure is to be written. The returned rectangle is exclusive of the bottom and right edges. An empty rectangle is specified by setting all four RECTFX members to zero.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.


STROBJ_bEnum

STROBJ_bEnum enumerates glyph identities and positions.

BOOL
  STROBJ_bEnum(
    IN STROBJ  *pstro,
    OUT ULONG  *pc,
    OUT PGLYPHPOS  *ppgpos
    );

Parameters

pstro
Points to the STROBJ structure containing the GLYPHPOS information.
pc
Points to the count, returned by GDI, of GLYPHPOS structures.
ppgpos
Points to the array in which GDI will write the GLYPHPOS structures.

Return Value

The return value is TRUE if more glyphs remain to be enumerated, or FALSE if the enumeration is complete. The return value is DDI_ERROR if the glyphs cannot be enumerated, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A driver should download only the glyph handles if it caches fonts itself.

The information returned depends on the driver's return value for DrvGetGlyphMode.

Bitmaps or outlines can also be obtained from FONTOBJ structures.

Printer drivers should call STROBJ_bEnumPositionsOnly instead of STROBJ_bEnum if printer hardware provides internal rendering of TrueType fonts.

See Also

FONTOBJ_cGetGlyphs, GLYPHPOS, STROBJ, STROBJ_vEnumStart


STROBJ_bEnumPositionsOnly

STROBJ_bEnumPositionsOnly enumerates glyph identities and positions for a specified text string, but does not create cached glyph bitmaps.

BOOL
  STROBJ_bEnumPositionsOnly(
    IN STROBJ  *pstro,
    OUT ULONG  *pc,
    OUT PGLYPHOS  **ppgpos
    );

Parameters

pstro
Is a caller-supplied pointer to a STROBJ structure describing a text string. This is typically the STROBJ structure received by the driver's DrvTextOut function.
pc
Is a caller-supplied address to receive the GDI-supplied number GLYPHPOS structures pointed to by ppgpos.
ppgpos
Is a caller-supplied address to receive a GDI-supplied pointer to an array of GLYPHPOS structures. (See the following Comments section.)

Return Value

The return value is TRUE if more glyphs remain to be enumerated, or FALSE if the enumeration is complete. The return value is DDI_ERROR if the glyphs cannot be enumerated, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The STROBJ_bEnumPositionsOnly function is typically called from within a driver's DrvTextOut function. It performs the same operations as STROBJ_bEnum with one important exception – GDI does not create cached bitmaps of the glyphs. The STROBJ_bEnum function assumes the driver will eventually need these bitmaps. However, many newer printers contain internal rasterizers and therefore do not need GDI to render glyphs. For such printers, eliminating the automatic rendering and caching of glyph bitmaps in server memory provides considerable savings of both processing time and memory allocation.

For printers that support internal glyph rasterization, the following rules should be followed:

  • The driver should set the GCAPS_FONT_RASTERIZER flag in its DEVINFO structure.
  • The driver's DrvTextOut function should call STROBJ_bEnumPositionsOnly instead of STROBJ_bEnum.
  • If the print job includes a font that the device cannot rasterize internally, the driver should call FONTOBJ_cGetGlyphs to obtain glyph bitmaps.
  • If a driver needs to determine the likely printer position after a text string has been printed, but does not need a font glyph, it can call STROBJ_bGetAdvanceWidths.

Because GDI does not create cached bitmaps of the glyphs, the contents of the GLYPHDEF structure within each returned GLYPHPOS structure will be NULL.


STROBJ_bGetAdvanceWidths

The STROBJ_bGetAdvanceWidths function returns vectors specifying the probable widths of glyphs making up a specified string.

BOOL
  STROBJ_bGetAdvanceWidths(
    IN STROBJ  *pso,
    IN ULONG  iFirst,
    IN ULONG  c,
    OUT POINTQF  *pptqD
      );

Parameters

pso
Is a caller-supplied pointer to a STROBJ structure describing a text string. This is typically the STROBJ structure received by the driver's DrvTextOut function.
iFirst
Is a caller-supplied, zero-based index into the text string supplied by the STROBJ structure. This index represents the first character of the string for which a width is to be returned.
c
Is a caller-supplied count of the number of contiguous characters, starting and the character specified by iFirst, for which width values are to be returned.
pptqD
Is a caller-supplied pointer to a c-sized array of POINTQF structures to receive character widths in (28.36, 28.36) format.

Return Value

If the operation succeeds, the function returns TRUE; otherwise it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The STROBJ_bGetAdvanceWidths function is useful to printer drivers that call STROBJ_bEnumPositionsOnly instead of STROBJ_bEnum. The function fills in the pptqD array with the probable widths of a string's glyphs, and can be used to calculate the printer position after a string as been rendered by the printer, if the printer's glyph rendering hardware does not return exact character widths.

Note that glyph positions returned by STROBJ_bEnumPositionsOnly do not necessarily correspond exactly to the widths returned by STROBJ_bGetAdvanceWidths.


STROBJ_dwGetCodePage

STROBJ_dwGetCodePage returns the code page associated with the specified STROBJ structure.

DWORD
  STROBJ_dwGetCodePage(
    IN STROBJ  *pstro
    );

Parameters

pstro
Points to a STROBJ structure with which the code page is associated.

Return Value

STROBJ_dwGetCodePage returns a DWORD value that identifies the code page associated with the font used in the text output call at the Win32 API level.

Headers

Declared in winddi.h. Include winddi.h.


STROBJ_fxBreakExtra

STROBJ_fxBreakExtra retrieves the amount of extra space to be added to each space character in a string when displaying and/or printing justified text.

FIX
  STROBJ_fxBreakExtra(
    IN STROBJ  *pstro
    );

Parameters

pstro
Points to the STROBJ structure of the string to be displayed.

Return Value

STROBJ_fxBreakExtra returns the amount of extra space to add to each space character in the string. A return value of zero indicates that no extra space is added to space characters in a string.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The extra space value is specified in pixel coordinates.

See Also

STROBJ, STROBJ_fxCharacterExtra


STROBJ_fxCharacterExtra

STROBJ_fxCharacterExtra retrieves the amount of extra space with which to augment each character's width in a string when displaying and/or printing it.

FIX
  STROBJ_fxCharacterExtra(
    IN STROBJ  *pstro
    );

Parameters

pstro
Points to the STROBJ structure of the string to be displayed.

Return Value

STROBJ_fxCharacterExtra returns the amount of extra space to add to every character in the string. A return value of zero indicates that the string should be laid out using the characters' unaugmented widths.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The extra space value is specified in pixel coordinates.

STROBJ_fxCharacterExtra never fails.

See Also

STROBJ, STROBJ_fxBreakExtra


STROBJ_vEnumStart

STROBJ_vEnumStart defines the form, or type, for data that will be returned from GDI in subsequent calls to STROBJ_bEnum.

VOID
  STROBJ_vEnumStart(
    IN STROBJ  *pstro
    );

Parameters

pstro
Points to the STROBJ structure whose data form is to be defined.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function also restarts the enumeration of the GLYPHPOS array.

This function should be called by the driver prior to calling STROBJ_bEnum.


VidMemFree

VidMemFree frees off-screen memory allocated for a display driver by HeapVidMemAllocAligned.

VOID
  VidMemFree(
    IN LPVMEMHEAP  pvmh,
    IN FLATPTR  ptr
    );

Parameters

pvmh
Points to a VMEMHEAP structure that represents the DirectDraw heap from which the surface was allocated. The driver obtains this value from the lpHeap member of the VIDEOMEMORY structure originally passed to HeapVidMemAllocAligned.
ptr
Is the FLATPTR offset of the allocated surface.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

See Also

HeapVidMemAllocAligned


WNDOBJ_bEnum

WNDOBJ_bEnum gets a batch of rectangles from the visible region of a window.

BOOL
  WNDOBJ_bEnum(
    IN WNDOBJ  *pwo,
    IN ULONG  cj,
    OUT ULONG  *pul
    );

Parameters

pwo
Points to a WNDOBJ structure created by a call to EngCreateWnd.
cj
Specifies the size, in bytes, of the buffer pointed to by pul. GDI will not write beyond this limit.
pul
Points to the buffer in which a structure of the following form is to be written. In this structure, c is a count of the rectangles returned, and arcl is an array of rectangles:
typedef struct _ENUMRECTS{
    ULONG c;
    RECTL arcl[]
} ENUMRECTS;

Include

winddi.h

Return Value

The return value is TRUE if there is more data to be enumerated and the driver should repeat the call. It is FALSE if the enumeration is complete.

Comments

The order of enumeration is determined by the call to WNDOBJ_cEnumStart.

A possible loop structure for calling this function follows.

do {
    bMore = WNDOBJ_bEnum(pwo, sizeof(buffer), &buffer.c);
    for (i = 0; i < buffer.c; i++) {
        //  Process the data
    }
} while (bMore);

WNDOBJ_bEnum should be called only by the callback function provided to GDI by the EngCreateWnd function, or by the graphics DDI functions that are given a WNDOBJ.

See Also

EngCreateWnd, WNDOBJ, WNDOBJ_cEnumStart


WNDOBJ_cEnumStart

WNDOBJ_cEnumStart is a callback function that sets parameters for enumeration of rectangles in the visible region of a window.

ULONG
  WNDOBJ_cEnumStart(
    IN WNDOBJ  *pwo,
    IN ULONG  iType,
    IN ULONG  iDirection,
    IN ULONG  cLimit
    );

Parameters

pwo
Points to a WNDOBJ structure created by a call to EngCreateWnd.
iType
Specifies the type of structures to be returned by WNDOBJ_bEnum. This parameter can be CT_RECTANGLES, meaning that the region is to be enumerated as a list of rectangles.
iDirection
Determines the order in which the rectangles are returned. This order can be essential when an overlapping DrvBitBlt is being performed on the same surface. If the order is not relevant to the device driver, then CD_ANY should be specified. This allows GDI to optimize its enumeration for complex regions. This parameter can be one of the following values:
Value | Meaning
CD_ANY | Any order convenient for GDI.
CD_LEFTDOWN | Right to left, top to bottom.
CD_LEFTUP | Right to left, bottom to top.
CD_LEFTWARDS | Left to right, vertical direction is not defined.
CD_RIGHTDOWN | Left to right, top to bottom.
CD_RIGHTUP | Left to right, bottom to top.
CD_UPWARDS | Bottom to top, horizontal direction is not defined.

cLimit
Is an indication of how many objects the driver is interested in caching. This is only used to decide when to stop counting rectangles while GDI is calculating the return value for this function. If cLimit is zero, counting is not done.

Return Value

The return value is a count of the number of objects that would be enumerated, provided this value is less than or equal to cLimit. If the count is greater than cLimit, the return value is 0xFFFFFFFF.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Enumeration can be restarted by calling this function again.

WNDOBJ_cEnumStart should be called only:

  • In the context of the driver callback function supplied to GDI in the EngCreateWnd function, or the graphics DDI functions where a WNDOBJ is given.
  • When the calling thread has the device lock to ensure that no client region changes occur.

See Also

DrvBitBlt, EngCreateWnd, EngLockDriverObj, WNDOBJ, WNDOBJ_bEnum


WNDOBJ_vSetConsumer

WNDOBJ_vSetConsumer sets a driver-defined value in the pvConsumer field of the specified WNDOBJ structure.

VOID
  WNDOBJ_vSetConsumer(
    IN WNDOBJ  *pwo,
    IN PVOID  pvConsumer
    );

Parameters

pwo
Points to a WNDOBJ structure created by a prior call to EngCreateWnd.
pvConsumer
A driver-defined value for identifying this particular WNDOBJ structure. This value overrides the previous value stored in the WNDOBJ structure.

Return Value

None

Headers

Declared in winddi.h. Include winddi.h.

Comments

WNDOBJ_vSetConsumer should be called only by the following functions:

  • Graphics DDI functions where a WNDOBJ structure is provided.
  • The callback provided to GDI by a driver's call to EngCreateWnd.
  • The WNDOBJ_SETUP escape defined by DrvEscape after a new WNDOBJ structure is created.

See Also

EngCreateWnd, WNDOBJ


XFORMOBJ_bApplyXform

XFORMOBJ_bApplyXform applies the given transform or its inverse to the given array of points.

BOOL
  XFORMOBJ_bApplyXform(
    IN XFORMOBJ  *pxo,
    IN ULONG  iMode,
    IN ULONG  cPoints,
    IN PVOID  pvIn,
    OUT PVOID  pvOut
    );

Parameters

pxo
Points to a XFORMOBJ structure that defines the transform to be applied to the pvIn array.
iMode
Identifies the transform and the input and output data types. This parameter can be one of the following:
Value | Meaning
XF_INV_FXTOL | Applies the inverse of the transform to POINTFIX structures to get POINTL structures.
XF_INV_LTOL | Applies the inverse of the transform to POINTL structures to get POINTL structures.
XF_LTOFX | Applies the transform to POINTL structures to get POINTFIX structures.
XF_LTOL | Applies the transform to POINTL structures to get POINTL structures.

cPoints
Specifies the count of points in pvIn to be transformed.
pvIn
Points to an array of input points. The format of the points is specified by the iMode parameter.
pvOut
Points to the buffer that is to receive the transformed points. The iMode parameter specifies the format of the points.

Return Value

The return value is TRUE if all points were transformed without overflow. FALSE is returned if pxo, pvIn, or pvOut are null, or if overflow occurs during the transformation.

Headers

Declared in winddi.h. Include winddi.h.

Comments

See GDI Data Types for descriptions of the POINTFIX and POINTL structures.

See Also

XFORMOBJ


XFORMOBJ_iGetFloatObjXform

XFORMOBJ_iGetFloatObjXform downloads a FLOATOBJ transform to the driver.

ULONG
  XFORMOBJ_iGetFloatObjXform(
    IN XFORMOBJ  *pxo,
    OUT FLOATOBJ_XFORM  *pxfo
    );

Parameters

pxo
Points to the XFORMOBJ structure that defines the transform to be downloaded.
pxfo
Points to the buffer that is to receive the FLOATOBJ_XFORM structure. This parameter can be NULL.

Return Value

If an error occurs, the return value is DDI_ERROR. Otherwise, the return value is a complexity hint about the transform object. The value of this transform characterization can be one of the following:

Return Value | Meaning
GX_GENERAL | Arbitrary 2 x 2 matrix and offset.
GX_IDENTITY | Identity matrix; no translation offset.
GX_OFFSET | Identity matrix; there is a translation offset.
GX_SCALE | Off-diagonal matrix elements are zero.

Headers

Declared in winddi.h. Include winddi.h.

Comments

If pxfo is not NULL, XFORMOBJ_iGetFloatObjXform loads a FLOATOBJ_XFORM into the memory location pxfo points to. This function allows graphics drivers to emulate floating point arithmetic. NT-based operating systems do not support kernel-mode floating point operations on some systems.

See Also

FLOATOBJ, XFORMOBJ


XFORMOBJ_iGetXform

XFORMOBJ_iGetXform downloads a transform to the driver.

ULONG
  XFORMOBJ_iGetXform(
    IN XFORMOBJ  *pxo,
    OUT XFORML  *pxform
    );

Parameters

pxo
Points to the XFORMOBJ structure that defines the transform to be downloaded to the driver.
pxform
Points to the buffer that is to receive the XFORML structure. This parameter can be NULL.

Return Value

If an error occurs, the return value is DDI_ERROR. Otherwise, the return value is a complexity hint about the transform object. The value of this transform characterization can be one of the following:

Value | Meaning
GX_GENERAL | Arbitrary 2 x 2 matrix and offset.
GX_IDENTITY | Identity matrix; no translation offset.
GX_OFFSET | Identity matrix; there is a translation offset.
GX_SCALE | Off-diagonal matrix elements are zero.

Headers

Declared in winddi.h. Include winddi.h.

See Also

XFORMOBJ, XFORMOBJ_bApplyXform


XLATEOBJ_cGetPalette

XLATEOBJ_cGetPalette retrieves RGB colors or the bitfields format from the specified palette.

ULONG
  XLATEOBJ_cGetPalette(
    IN XLATEOBJ  *pxlo,
    IN ULONG  iPal,
    IN ULONG  cPal,
    OUT ULONG  *pPal
    );

Parameters

pxlo
Points to the XLATEOBJ structure from which GDI retrieves the requested information.
iPal
Identifies the palette information to be written. This parameter can be one of the following values:
Value | Meaning
XO_DESTBITFIELDS | GDI retrieves the bitfields format of the destination palette.
XO_DESTPALETTE | GDI retrieves RGB colors from the destination palette.
XO_SRCBITFIELDS | GDI retrieves the bitfields format of the source palette.
XO_SRCPALETTE | GDI retrieves RGB colors from the source palette.

cPal
Specifies the number of entries in the buffer pointed to by pPal. This can be smaller than the total size of the palette.
pPal
Points to a buffer in which GDI writes the requested palette information. If iPal is XO_SRCPALETTE or XO_DESTPALETTE and the respective palette type is PAL_INDEXED, each entry is a 24-bit RGB value.

If iPal is XO_SRCBITFIELDS or XO_DESTBITFIELDS and the respective palette type is PAL_BITFIELDS, PAL_RGB, or PAL_BGR, pPal points to three ULONG masks that represent the red, green, and blue color masks.

Return Value

XLATEOBJ_cGetPalette returns the number of entries written if pPal is not null. A value of zero is returned if the XLATEOBJ is null or its palette is invalid. XLATEOBJ_cGetPalette will also return zero if the data pointed to by pxlo is not consistent with the value in iPal. For example, if the data pointed to is a bitfield, but iPal is set to either XO_SRCPALETTE or XO_DESTPALETTE, XLATEOBJ_cGetPalette will return zero. Similarly, if the data pointed to by pxlo is a palette, but iPal is set to either XO_SRCBITFIELDS or XO_DESTBITFIELDS, XLATEOBJ_cGetPalette also returns zero.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The driver must have information about the palette to perform some methods of color blending.

See Also

XLATEOBJ


XLATEOBJ_hGetColorTransform

XLATEOBJ_hGetColorTransform returns the color transform for the specified translation object.

HANDLE
  XLATEOBJ_hGetColorTransform(
    IN XLATEOBJ  *pxlo
    );

Parameters

pxlo
Points to the XLATEOBJ structure whose color transform is being queried. The color transform was created in a prior call to DrvIcmCreateColorTransform.

Return Value

XLATEOBJ_hGetColorTransform returns a handle to the color transform for the specified XLATEOBJ upon success. Otherwise, it returns NULL.

Headers

Declared in winddi.h. Include winddi.h.

Comments

XLATEOBJ_hGetColorTransform returns NULL when it is called in host ICM context or when ICM is disabled.

The color transform for a brush is obtained by calling BRUSHOBJ_hGetColorTransform.

See Also

BRUSHOBJ_hGetColorTransform, DrvIcmCreateColorTransform, XLATEOBJ


XLATEOBJ_iXlate

XLATEOBJ_iXlate translates a color index of the source palette to the closest index in the destination palette.

ULONG
  XLATEOBJ_iXlate(
    IN XLATEOBJ  *pxlo,
    IN ULONG  iColor
    );

Parameters

pxlo
Points to a XLATEOBJ structure that defines the source palette.
iColor
Specifies the color index to be translated.

Return Value

The return value is an index into the destination palette if the function is successful. If the function fails, -1 is returned.

Headers

Declared in winddi.h. Include winddi.h.


XLATEOBJ_piVector

XLATEOBJ_piVector retrieves a translation vector that the driver can use to translate source indices to destination indices.

ULONG
 *XLATEOBJ_piVector(
    IN XLATEOBJ  *pxlo
    );

Parameters

pxlo
Points to a XLATEOBJ structure that defines the indexed source object.

Return Value

The return value is a pointer to a vector of translation entries if the function is successful. Otherwise, it is null, and an error code is logged.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function can be used only if the source palette is an indexed palette.


Graphics Driver Structures

Both GDI and the graphics driver create and maintain several structures as a means of defining objects, passing data, storing flag settings, and so on. This section describes these structures. GDI Support for Graphics Drivers lists the include files that contain definitions of these structures.

Reference material for functions that are implemented by display and/or printer driver writers can be found in Graphics Driver Functions (DDI). The system-supplied GDI services that can be called by graphics drivers are documented in GDI Functions for Graphics Drivers.


BLENDOBJ

BLENDOBJ controls blending by specifying the blending functions for source and destination bitmaps.

typedef struct _BLENDOBJ {
  BLENDFUNCTION  BlendFunction;
} BLENDOBJ,*PBLENDOBJ;

Members

BlendFunction
Is a structure that specifies the blending operation to use, the alpha transparency for the source bitmap, and the way the source and destination bitmaps are interpreted.

Headers

Declared in winddi.h. Include winddi.h.

Comments

See the Platform SDK documentation for the definition of the BLENDFUNCTION structure.


BRUSHOBJ

BRUSHOBJ contains three public members that describe a brush object.

typedef struct _BRUSHOBJ {
  ULONG  iSolidColor;
  PVOID  pvRbrush;
  FLONG  flColorType;
} BRUSHOBJ;

Members

iSolidColor
Specifies the color index of a solid brush. This index has been translated to the target surface's palette. Drawing can proceed without realization of the brush. A value of 0xFFFFFFFF indicates that a nonsolid brush must be realized.
pvRbrush
Points to the driver's realized brush.
flColorType
Specifies flags that describe this brush object. This member can be a combination of any of the following values (only one of BR_HOST_ICM and BR_DEVICE_ICM can be set):
Value | Meaning
BR_CMYKCOLOR | When this bit is set, iSolidColor contains a 32-bit CMYK color value. Otherwise, iSolidColor contains a palette index or 0xFFFFFFFF.
BR_DEVICE_ICM | The driver performs image color management for the brush color.
BR_HOST_ICM | The driver need not perform image color management for the brush color because GDI (or the calling application) is responsible.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Drivers can call BRUSHOBJ_Xxx service routines to realize brushes or to find previously realized brushes.

If the iSolidColor member is 0xFFFFFFFF or the pvRbrush member is NULL, the driver must call the BRUSHOBJ_pvGetRbrush function to realize the brush.

If neither BR_HOST_ICM or BR_DEVICE_ICM are set, ICM is not enabled in the graphics engine or in the driver.

See Also

BRUSHOBJ_hGetColorTransform, BRUSHOBJ_pvGetRbrush, BRUSHOBJ_pvGetRbrush, BRUSHOBJ_ulGetBrushColor


CIECHROMA

CIECHROMA is used to describe the chromaticity coordinates, x and y, and the luminance, Y in CIE color space.

typedef struct _CIECHROMA {
  LDECI4  x;
  LDECI4  y;
  LDECI4  Y;
} CIECHROMA;

Members

x
Specifies the x coordinate in CIE chromaticity space.
y
Specifies the y coordinate in CIE chromaticity space.
Y
Specifies the luminance.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This structure is used by the COLORINFO structure to define colors for GDIINFO.

The LDECI4 type is used to represent real numbers to four decimal places. For example, (LDECI4) 10000 represents the real number 1.0000, and (LDECI4) -12345 represents -1.2345.

Both x and y should be in the range zero to one. The Y member should be in the range 0 to 100.

See Also

COLORINFO, DrvEnablePDEV, GDIINFO


CLIPLINE

CLIPLINE gives the driver access to a portion of a line between two clip regions used for drawing.

typedef struct _CLIPLINE {
  POINTFIX  ptfxA;
  POINTFIX  ptfxB;
  LONG   lStyleState;
  ULONG   c;
  RUN   arun[1];
} CLIPLINE, *PCLIPLINE;

Members

ptfxA
Specifies the starting point of the line.
ptfxB
Specifies the end point of the line.
lStyleState
Is a pair of 16-bit values supplied by GDI whenever the driver calls PATHOBJ_bEnumClipLines. These two values are packed into a LONG and specify the style offset back to the first pixel of the line segment. This is the first pixel that would be rendered if the line were not clipped. This value allows the styling for the remainder of the line to be computed. Refer to Styled Cosmetic Lines for additional information.
c
Specifies the number of RUN structures in the arun array.
arun
Is an array of RUN structures. The RUN structures describe the start and stop portions of the clip line.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The CLIPLINE structure is used by PATHOBJ_bEnumCliplines. The CLIPLINE structure contains the original, unclipped control points of the line segment.

See Also

CLIPOBJ, GDIINFO, RUN


CLIPOBJ

CLIPOBJ describes the clip region used when drawing.

typedef struct _CLIPOBJ {
  ULONG  iUniq;
  RECTL  rclBounds;
  BYTE  iDComplexity;
  BYTE  iFComplexity;
  BYTE  iMode;
  BYTE  fjOptions;
} CLIPOBJ;

Members

iUniq
Specifies a value that uniquely identifies the clip region. If iUniq is nonzero, the driver uses it as a cache identifier. This allows the driver to recognize a region after downloading and caching it. If the value is zero, the driver should not cache the region because the region will not be used again.
rclBounds
Specifies a rectangle that bounds the part of the region that intersects the drawing. If iDComplexity is DC_RECT, then this is the clipping rectangle to be considered.
iDComplexity
Specifies the complexity of the part of the region that intersects with the drawing. This member must be one of the following values:
Value | Meaning
DC_COMPLEX | The clip region must be enumerated.
DC_RECT | Clip to a single rectangle.
DC_TRIVIAL | Clipping need not be considered; draw the whole figure.

iFComplexity
Specifies the complexity of the whole region. This value is used by the driver in deciding whether or not to cache the region. CLIPOBJ_cEnumStart can be called to determine the exact number of rectangles in the region. This member can be one of the following values:
Value | Meaning
FC_COMPLEX | The region consists of more than four rectangles.
FC_RECT | The region is a single rectangle.
FC_RECT4 | The region consists of, at most, four rectangles.

iMode
Specifies how the region is stored by GDI. This can help the driver determine how to enumerate the region. This member can be one of the following values:
Value | Meaning
TC_PATHOBJ | The region is stored as a path.
TC_RECTANGLES | The region is stored as rectangles.

fjOptions
Specifies clipping options. This member can be the following value:
Value | Meaning
OC_BANK_CLIP | Obsolete. Indicates an engine callback for a banked device.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The region, described by CLIPOBJ, can be enumerated as a series of rectangles.

See Also

CLIPOBJ_bEnum, CLIPOBJ_cEnumStart


COLORINFO

typedef struct _COLORINFO {
  CIECHROMA  Red;
  CIECHROMA  Green;
  CIECHROMA  Blue;
  CIECHROMA  Cyan;
  CIECHROMA  Magenta;
  CIECHROMA  Yellow;
  CIECHROMA  AlignmentWhite;
  LDECI4  RedGamma;
  LDECI4  GreenGamma;
  LDECI4  BlueGamma;
  LDECI4  MagentaInCyanDye;
  LDECI4  YellowInCyanDye;
  LDECI4  CyanInMagentaDye;
  LDECI4  YellowInMagentaDye;
  LDECI4  CyanInYellowDye;
  LDECI4  MagentaInYellowDye;
} COLORINFO, *PCOLORINFO;

Members

Red, Green, Blue, Cyan, Magenta, Yellow, AlignmentWhite
CIECHROMA structures defining the x, y, and Y (luminance) coordinates of the named color.
RedGamma, GreenGamma, BlueGamma
Are the gamma corrections of display devices that permit the display device to display colors between the primary colors with accuracy. Their values should be between 0 and 6.5535, which means that the numbers actually stored in these members must be in the range 0 through 65535.
MagentaInCyanDye, YellowInCyanDye, CyanInMagentaDye, YellowInMagentaDye, CyanInYellowDye, MagentaInYellowDye
Used for printing devices to describe color purity and concentration. Values should be between zero and one, which means that the numbers actually stored in these members must be in the range 0 through 10000.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The LDECI4 type is used to represent real numbers to four decimal places. For example, (LDECI4) 10000 represents the real number 1.0000, and (LDECI4) -12345 represents -1.2345.

Any values in the COLORINFO structure that are out of the specified range default to the NTSC values.

See Also

CIECHROMA, DrvEnablePDEV, GDIINFO


DEVHTADJDATA

DEVHTADJDATA is used as input to the HTUI_DeviceColorAdjustment function.

typedef struct _DEVHTADJDATA {
  DWORD   DeviceFlags;
  DWORD   DeviceXDPI;
  DWORD   DeviceYDPI;
  PDEVHTINFO  pDefHTInfo;
  PDEVHTINFO  pAdjHTInfo;
} DEVHTADJDATA, *PDEVHTADJDATA;

Members

DeviceFlags
Is a set of flags, set by the caller, describing color mixing and color versus gray-scale output. Either, both, or neither of the following flags should be set, as appropriate:
Flag Definition
DEVHTADJF_ADDITIVE_DEVICE If set, the device uses additive color mixing.
If not set, the device uses subtractive color mixing.
DEVHTADJF_COLOR_DEVICE If set, the device produces color output.
If not set, the device produces gray-scaled output.

DeviceXDPI
Is the caller-supplied horizontal resolution, in dots per inch, for the device.
DeviceYDPI
Is the caller-supplied vertical resolution, in dots per inch, for the device.
pDefHTInfo
Is a caller-supplied pointer to a DEVHTINFO structure containing the device's default halftoning properties.
pAdjHTInfo
Is a caller-supplied pointer to a DEVHTINFO structure containing the device's current halftoning properties. Before the HTUI_DeviceColorAdjustment function returns, it modifies this structure's contents, if the user has adjusted the halftoning properties. Can be NULL (see the following Comments section).

Headers

Declared in winddi.h. Include winddi.h.

Comments

If pAdjHTInfo is NULL, or if pAdjHTInfo and pDefHTInfo point to the same buffer, the HTUI_DeviceColorAdjustment function displays the halftoning properties supplied by pDefHTInfo but does not allow the user to modify them.


DEVHTINFO

DEVHTINFO is used as input to the HTUI_DeviceColorAdjustment function.

typedef struct _DEVHTINFO {
  DWORD   HTFlags;
  DWORD   HTPatternSize;
  DWORD   DevPelsDPI;
  COLORINFO  ColorInfo;
} DEVHTINFO, *PDEVHTINFO;

Members

HTFlags
Internal flags. Do not modify.
HTPatternSize
Is a caller supplied value that must be one of the HTPAT_SIZE-prefixed constants defined in ht.h.
DevPelsDPI
For printers, specifies the number of dots per inch. See the description of the ulDevicePelsDPI member of the GDIINFO structure for more information.

For displays, this member should be set to zero.

ColorInfo
Is a caller-supplied pointer to a COLORINFO structure containing halftoning color information.

Headers

Declared in winddi.h. Include winddi.h.


DEVINFO

DEVINFO provides information about the driver and its private PDEV to the graphics engine.

typedef struct tagDEVINFO {
  FLONG   flGraphicsCaps;
  LOGFONTW  lfDefaultFont;
  LOGFONTW  lfAnsiVarFont;
  LOGFONTW  lfAnsiFixFont;
  ULONG  cFonts;
  ULONG  iDitherFormat;
  USHORT  cxDither;
  USHORT  cyDither;
  HPALETTE  hpalDefault;
  FLONG  flGraphicsCaps2;
} DEVINFO, *PDEVINFO;

Members

flGraphicsCaps
Is a set of flags that describe graphics capabilities of the graphics driver and/or its hardware. These flags are defined as follows:
Flag | Definition
GCAPS_ALTERNATEFILL | Handles alternating fills.
GCAPS_ARBRUSHOPAQUE | Supports an arbitrary brush for text opaque rectangle (background color).
GCAPS_ARBRUSHTEXT | Supports an arbitrary brush for the text foreground color.
GCAPS_ASYNCCHANGE | This flag is obsolete. In legacy drivers, this flag indicates that the driver can change the pointer shape in hardware while other drawing is occurring on the device.
GCAPS_ASYNCMOVE | The driver can move the pointer in hardware while other drawing is occurring on the device.
GCAPS_BEZIERS | Handles Bezier curves.
GCAPS_CMYKCOLOR | The driver supports the CYMK color space.
GCAPS_COLOR_DITHER | Handles color dithering to a PDEV-compatible surface.
GCAPS_DIRECTDRAW | This flag is obsolete.
GCAPS_DITHERONREALIZE | Specifies that GDI can call DrvRealizeBrush with the RGB to be dithered directly.
GCAPS_DONTJOURNAL | Disallows metafile printing to this printer driver. This is valid only for printer DCs and will generally result in slower return-to-application time when printing.
GCAPS_FONT_RASTERIZER | Device hardware can rasterize TrueType fonts.
GCAPS_FORCEDITHER | Allows dithering on all geometric pens.
GCAPS_GEOMETRICWIDE | Handles geometric widening.
GCAPS_GRAY16 | Handles antialiased text natively.
GCAPS_HALFTONE | Handles halftoning.
GCAPS_HIGHRESTEXT | Indicates that the driver is requesting glyph positions as returned by the STROBJ in FIX point coordinates.
GCAPS_HORIZSTRIKE | This flag is obsolete. In legacy drivers, this flag indicated that the driver handled horizontal strikeouts in DrvTextOut.
GCAPS_ICM | Indicates that color management operations can be performed by the driver or printer hardware.
GCAPS_LAYERED | Indicates that this is a layer or mirror driver for remoting. Printer drivers cannot be layer drivers.
GCAPS_MONO_DITHER | Handles monochrome dithering.
GCAPS_NO64BITMEMACCESS | This flag is obsolete.
GCAPS_NUP | Indicates that "N-up" printing is supported.
GCAPS_OPAQUERECT | Handles opaque rectangles in DrvTextOut.
GCAPS_PALMANAGED | Supports palette management.
GCAPS_PANNING | When GDI is simulating the pointer, it should call DrvMovePointer to notify the driver of the current cursor position. This allows the driver to handle panning virtual displays.
GCAPS_SCREENPRECISION | The rasterizer (font engine) should choose a screen (soft) font over a device font when choosing a font for which there is no exact match.
GCAPS_VECTORFONT | Handles stroking of vector fonts in DrvTextOut.
GCAPS_VERTSTRIKE | This flag is obsolete. In legacy drivers, this flag indicated that the driver handled vertical strikeouts in DrvTextOut.
GCAPS_WINDINGFILL | Handles winding mode fills. See Path Fill Modes for more information.

lfDefaultFont
Is an Extended Logical Font structure that specifies the default font for a device. For more information about this structure, see EXTLOGFONT in the Platform SDK Documentation.
lfAnsiVarFont
Is an Extended Logical Font structure that specifies the default variable-pitch font for a device. For more information about this structure, see EXTLOGFONT in the Platform SDK Documentation.
lfAnsiFixFont
Is an Extended Logical Font structure that specifies the default fixed-pitch (monospaced) font for a device. For more information about this structure, see EXTLOGFONT in the Platform SDK Documentation.
cFonts
Specifies the number of device fonts. GDI assumes that the device can draw text with this number of fonts on its own surfaces and that the driver can provide metrics information about the fonts. If the driver sets cFonts to -1, GDI will wait until fonts are needed to query the driver for the actual number of fonts it supports in a call to DrvQueryFont.
iDitherFormat
Specifies the format of the bitmap. This parameter indicates how many bits of color information per pixel are requested, and must be one of the following values:
Value | Meaning
BMF_1BPP | Monochrome
BMF_4BPP | 4 bits per pixel
BMF_8BPP | 8 bits per pixel
BMF_16BPP | 16 bits per pixel
BMF_24BPP | 24 bits per pixel
BMF_32BPP | 32 bits per pixel
BMF_4RLE | 4 bits per pixel, run length encoded
BMF_8RLE | 8 bits per pixel, run length encoded
BMF_JPEG | JPEG compressed image
BMF_PNG | PNG compressed image

cxDither and cyDither
Specify the dimensions of a dithered brush. If these members are nonzero, then the device can create a dithered brush for a given RGB color.
hpalDefault
Specifies the default palette for the device. The driver should create the palette by calling EngCreatePalette. The driver associates a palette with a device by returning this handle to GDI.
flGraphicsCaps2
Are flags that describe additional graphics capabilities of the device driver. These flags are defined as follows:
Flag | Definition
GCAPS2_ALPHACURSOR | Handles pointers with per-pixel alpha values.
GCAPS2_CHANGEGAMMARAMP | The display device has a loadable hardware gamma ramp.
GCAPS2_ICD_MULTIMON | Informs GDI that the driver intends to handle DrvSetPixelFormat, DrvDescribePixelFormat, and DrvSwapBuffers calls in a multimon environment, even when the rectangle in the operation also intersects another device. Only one device is ever given the opportunity to handle those calls. If the capability is not specified and the region involved intersects more than one device, no driver is called.
GCAPS2_JPEGSRC | Device can accept JPEG compressed images (that is, images for which BMP_JPEG is set in the SURFOBJ structure).
GCAPS2_MOUSETRAILS | Indicates that the driver supports mouse trails (a succession of cursor images showing the mouse's location during a short period of time). The driver is capable of handling the values GDI sends in the fl parameter of the DrvSetPointerShape function. The driver should use the SPS_LENGTHMASK and SPS_FREQMASK masks to obtain values for the length and frequency of the mouse trails. See DrvSetPointerShape for more information about these masks.
GCAPS2_PNGSRC | Device can accept PNG compressed images (that is, images for which BMP_PNG is set in the SURFOBJ structure).
GCAPS2_SYNCFLUSH | The driver supports a programmatic-based flush mechanism for batched graphics DDI calls. DrvSynchronizeSurface will be called whenever GDI must flush any drawing that is being batched by the driver.
GCAPS2_SYNCTIMER | The driver supports a timer-based flush mechanism for batched graphics DDI calls. DrvSynchronizeSurface will be called periodically, based on a timer interval determined by GDI.
GCAPS2_xxxx

Headers

Declared in winddi.h. Include winddi.h.

Comments

The driver's DrvEnablePDEV function fills in a DEVINFO structure; the driver should set only the members that are relevant to it. This structure is zero-initialized by GDI before DrvEnablePDEV is called. Applications do not have direct access to this structure.

If a driver sets GCAPS2_JPEGSRC or GCAPS2_PNGSRC in flGraphicsCaps2, the following rules apply:

  • The driver must provide a DrvQueryDeviceSupport function.
  • Every driver-defined graphics DDI function that receives a SURFOBJ structure as input must be able to either support the compressed format or return an error code.
  • The driver must be able to handle complex clip regions for images that use the compressed format.
  • For driver-defined graphics DDI functions that receive a ROP4 input argument, only 0xCCCC is used with JPEG and PNG formats.

See Also

DrvEnablePDEV, DrvQueryFont, DrvRealizeBrush, DrvTextOut


DEVMODEW

DEVMODEW is used for specifying characteristics of display and print devices.

typedef struct _devicemodew {
  WCHAR  dmDeviceName[CCHDEVICENAME];
  WORD   dmSpecVersion;
  WORD   dmDriverVersion;
  WORD   dmSize;
  WORD   dmDriverExtra;
  DWORD  dmFields;
  union {
    struct {
      short  dmOrientation;
      short  dmPaperSize;
      short  dmPaperLength;
      short  dmPaperWidth;
    };
    POINTL  dmPosition;
  };
  short  dmScale;
  short  dmCopies;
  short  dmDefaultSource;
  short  dmPrintQuality;
  short  dmColor;
  short  dmDuplex;
  short  dmYResolution;
  short  dmTTOption;
  short  dmCollate;
  WCHAR  dmFormName[CCHFORMNAME];
  WORD   dmLogPixels;
  DWORD  dmBitsPerPel;
  DWORD  dmPelsWidth;
  DWORD  dmPelsHeight;
  DWORD  dmDisplayFlags;
  DWORD  dmDisplayFrequency;
  DWORD  dmICMMethod;
  DWORD  dmICMIntent;
  DWORD  dmMediaType;
  DWORD  dmDitherType;
  DWORD  dmReserved1;
  DWORD  dmReserved2;
  DWORD  dmPanningWidth;
  DWORD  dmPanningHeight;
} DEVMODEW, *PDEVMODEW, *NPDEVMODEW, *LPDEVMODEW;

Members

dmDeviceName
For a display, specifies the name of the display driver's DLL; for example, "S3ViRGE" for S3's ViRGE driver.

For a printer, specifies the "friendly name"; for example, "PCL/HP LaserJet" in the case of PCL/HP LaserJet®. If the name is greater than CCHDEVICENAME characters in length, the spooler truncates it to fit in the array.

dmSpecVersion
Specifies the version number of this DEVMODEW structure. The current version number is identified by the DM_SPECVERSION constant in wingdi.h.
dmDriverVersion
For a printer, specifies the printer driver version number assigned by the printer driver developer.

Display drivers can set this member to DM_SPECVERSION.

dmSize
Specifies the size in bytes of the public DEVMODEW structure, not including any private, driver-specified members identified by the dmDriverExtra member.
dmDriverExtra
Specifies the number of bytes of private driver data that follow the public structure members. If a device driver does not provide private DEVMODEW members, this member should be set to zero.
dmFields
Specifies bit flags identifying which of the following DEVMODEW members are in use. For example, the DM_ORIENTATION flag is set when the dmOrientation member contains valid data. Flags are defined in wingdi.h.
dmOrientation
For printers, specifies the paper orientation. This member can be either DMORIENT_PORTRAIT or DMORIENT_LANDSCAPE.

This member is not used for displays.

dmPaperSize
For printers, specifies the size of the paper to be printed on. This member must be zero if the length and width of the paper are both specified by the dmPaperLength and dmPaperWidth members. Otherwise, the dmPaperSize member must be one of the DMPAPER-prefixed constants defined in wingdi.h.

This member is not used for displays.

dmPaperLength
For printers, specifies the length of the paper, in units of 1/10 of a millimeter. This value overrides the length of the paper specified by the dmPaperSize member, and is used if the paper is of a custom size, or if the device is a dot matrix printer, which can print a page of arbitrary length.

This member is not used for displays.

dmPaperWidth
For printers, specifies the width of the paper, in units of 1/10 of a millimeter. This value overrides the width of the paper specified by the dmPaperSize member. This member must be used if dmPaperLength is used.

This member is not used for displays.

dmPosition
For displays, specifies the position on the upper-left corner of the display, in desktop coordinates. This member is used to determine the relative position of monitors in a multiple monitor environment.

This member is not used for printers.

dmScale
For printers, specifies the percentage by which the image is to be scaled for printing. The image's page size is scaled to the physical page by a factor of dmScale/100. For example, a 17-inch by 22-inch image with a scale value of 100 requires 17x22-inch paper, while the same image with a scale value of 50 should print as half-sized and fit on letter-sized paper.

This member is not used for displays.

dmCopies
For printers, specifies the number of copies to be printed, if the device supports multiple copies.

This member is not used for displays.

dmDefaultSource
For printers, specifies the printer's default input bin. This must be one of the DMBIN-prefixed constants defined in wingdi.h. If the specified constant is DMBIN_FORMSOURCE, the input bin should be automatically selected.

This member is not used for displays.

dmPrintQuality
For printers, specifies the printer resolution. The following negative constant values are defined in wingdi.h:

DMRES_HIGH
DMRES_MEDIUM
DMRES_LOW
DMRES_DRAFT

If a positive value is specified, it represents the number of dots per inch (DPI) for the x resolution, and the y resolution is specified by dmYResolution.

This member is not used for displays.

dmColor
For printers, specifies whether a color printer should print color or monochrome. This member can be one of DMCOLOR_COLOR or DMCOLOR_MONOCHROME.

This member is not used for displays.

dmDuplex
For printers, specifies duplex (double-sided) printing for duplex-capable printers. This member can be one of the following values:
DMDUP_HORIZONTAL
Print double-sided, using short edge binding.
DMDUP_SIMPLEX
Print single-sided.
DMDUP_VERTICAL
Print double-sided, using long edge binding.

This member is not used for displays.

dmYResolution
For printers, specifies the y resolution of the printer, in DPI. If this member is used, the dmPrintQuality member specifies the x resolution.

This member is not used for displays.

dmTTOption
For printers, specifies how TrueType® fonts should be printed. This member must be one of the DMTT-prefixed constants defined in wingdi.h.

This member is not used for displays.

dmCollate
For printers, specifies whether multiple copies should be collated. This member can be one of the following values:
DMCOLLATE_TRUE
Collate when printing multiple copies.
DMCOLLATE_FALSE
Do not collate when printing multiple copies.

Specifying DMCOLLATE_FALSE provides faster output because the data is sent to a printer only once, no matter how many copies are required.

This member is not used for displays.

dmFormName
For printers, specifies the name of the form to use; such as "Letter" or "Legal". This must be a name that can be obtain by calling the Win32® EnumForms function (described in the Platform SDK documentation).

This member is not used for displays.

dmLogPixels
For displays, specifies the number of logical pixels per inch of a display device and should be equal to the ulLogPixels member of the GDIINFO structure.

This member is not used for printers.

dmBitsPerPel
For displays, specifies the color resolution, in bits per pixel, of a display device.

This member is not used for printers.

dmPelsWidth
For displays, specifies the width, in pixels, of the visible device surface.

This member is not used for printers.

dmPelsHeight
For displays, specifies the height, in pixels, of the visible device surface.

This member is not used for printers.

dmDisplayFlags
For displays, specifies a display device's display mode. This member can be one of the following values:
DM_GRAYSCALE
Specifies that the display is a noncolor device. If this flag is not set, color is assumed.
DM_INTERLACED
Specifies that the display mode is interlaced. If the flag is not set, noninterlaced is assumed.

This member is not used for printers.

dmDisplayFrequency
For displays, specifies the frequency, in hertz, of a display device in its current mode.

This member is not used for printers.

dmICMMethod
Specifies one of the DMICMMETHOD-prefixed constants defined in wingdi.h.
dmICMIntent
Specifies one of the DMICM-prefixed constants defined in wingdi.h.
dmMediaType
Specifies one of the DMMEDIA-prefixed constants defined in wingdi.h.
dmDitherType
Specifies one of the DMDITHER-prefixed constants defined in wingdi.h.
dmReserved1
Is reserved for system use and should be ignored by the driver.
dmReserved2
Is reserved for system use and should be ignored by the driver.
dmPanningWidth
Is reserved for system use and should be ignored by the driver.
dmPanningHeight
Is reserved for system use and should be ignored by the driver.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The DEVMODEW structure is the Unicode version of the DEVMODE structure (described in the Platform SDK documentation). While applications can use either the ANSI or Unicode version of the structure, drivers are required to use the Unicode version.

For printer drivers, the DEVMODEW structure is used for specifying printer characteristics required by a print document. It is also used for specifying a printer's default characteristics.

Immediately following a DEVMODEW structure's defined members (often referred to as its public members), there can be a set of driver-defined members (often referred to as private DEVMODEW members). The driver supplies the size, in bytes, of this private area in dmDriverExtra. Driver-defined private members are for exclusive use by the driver. The starting address for the private members can be referenced using the dmSize member as follows:

PVOID pvDriverData = (PVOID) (((BYTE *) pdm) + (pdm->dmSize));

See Also

DOCUMENTPROPERTYHEADER, DrvConvertDevMode, DrvDeviceCapabilities, DrvGetModes


DRIVEROBJ

DRIVEROBJ is used to track a resource, allocated by a driver, that requires use GDI services. A DRIVEROBJ structure allows a display driver to request the GDI service in managing per-process resources. By creating a DRIVEROBJ structure, a display driver can insure that resources will be released when an application terminates.

typedef struct _DRIVEROBJ {
  PVOID  pvObj;
  FREEOBJPROC  pFreeProc;
  HDEV  hdev;
  DHPDEV  dhpdev;
} DRIVEROBJ;

Members

pvObj
Points to the driver resource that will be tracked by the DRIVEROBJ structure. The resource is associated with the current client process.
pFreeProc
Points to a driver-supplied callback function that frees the resource pointed to by pvObj. This callback function has the following prototype:
BOOL (CALLBACK * FREEOBJPROC) (DRIVEROBJ * pDriverObj);

The callback function returns TRUE if it is able to free the resource, and FALSE otherwise.

hdev
Is the GDI handle of the physical device associated with the object.
dhpdev
Points to the driver's private instance data; that is, this member identifies the driver's PDEV.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A DRIVEROBJ structure allows a display driver to request the GDI service in managing per-process resources. By creating a DRIVEROBJ structure, a display driver can insure that resources will be released when an application terminates.

Some drivers, in their Escape support, allocate resources on behalf of applications. In such cases, the DRIVEROBJ structure provides a means for the application to notify the driver when it terminates. GDI will call the driver's cleanup function for each DRIVEROBJ structure allocated in an application's context that is not deleted before the application terminates.

This structure provides a locking mechanism for exclusive access to the associated resource.

See Also

EngCreateDriverObj, EngDeleteDriverObj, EngLockDriverObj, EngUnlockDriverObj


DRVENABLEDATA

DRVENABLEDATA contains a pointer to an array of DRVFN structures and the graphics DDI version number of the structures.

typedef struct tagDRVENABLEDATA {
  ULONG  iDriverVersion;
  ULONG  c;
  DRVFN  *pdrvfn;
} DRVENABLEDATA, *PDRVENABLEDATA;

Members

iDriverVersion
Specifies the graphics DDI version number for the NT-based operating system for which the driver is targeted. This member can be set to one of the following values:
Value | Operating System Version
DDI_DRIVER_VERSION_NT4 | Windows NT 4.0
DDI_DRIVER_VERSION_SP3 | Windows NT 4.0 Service Pack 3
DDI_DRIVER_VERSION_NT5 | Windows 2000
DDI_DRIVER_VERSION_NT5_01 | Windows XP

See the Comments section for more information.

c
Specifies the number of DRVFN structures in the buffer pointed to by the pdrvfn member.
pdrvfn
Points to a buffer containing an array of DRVFN structures.

Headers

Declared in winddi.h. Include winddi.h.

Comments

To run on these NT-based operating systems versions, the iDriverVersion member must be set as follows:

Windows Version |  | Value of iDriverVersion
Windows NT 4.0
 | iDriverVersion == DDI_DRIVER_VERSION_NT4
Windows NT 4.0 SP3
 | DDI_DRIVER_VERSION_NT4 <= iDriverVersion <= DDI_DRIVER_VERSION_SP3
Windows 2000
 | DDI_DRIVER_VERSION_NT4 <= iDriverVersion <= DDI_DRIVER_VERSION_NT5
Windows XP
 | DDI_DRIVER_VERSION_NT4 <= iDriverVersion <= DDI_DRIVER_VERSION_NT5_01

As the table shows, a driver for which iDriverVersion is set to DDI_DRIVER_VERSION_NT4 can run on any of these operating system versions, but a driver for which iDriverVersion is set to DDI_DRIVER_VERSION_NT5_01 can currently run only on Windows XP.

Note: If a driver implements a Drv Xxx graphics DDI that is not supported in all versions of Windows, the driver may not specify a DRVFN entry for that graphics DDI when running on versions of Windows that do not support it. If the driver does specify a DRVFN entry for such a graphics DDI, Windows will reject the driver. The permedia2 sample demonstrates how to specify different DRVFN structures for different versions of Windows.

See Also

DrvEnableDriver, DRVFN


DRVFN

DRVFN is used by graphics drivers to provide GDI with pointers to the graphics DDI functions defined by the driver.

typedef struct _DRVFN {
  ULONG  iFunc;
  PFN  pfn;
} DRVFN, *PDRVFN;

Members

iFunc
Is the function index that identifies a graphics DDI function implemented by the driver. The index name reflects the name of the related graphics DDI function; for example, an index value of INDEX_DrvEnablePDEV specifies the DrvEnablePDEV function. See the header file, winddi.h, for a complete list of index values.
pfn
Specifies the address of the driver-defined graphics DDI function associated with the index supplied for iFunc. This function has the following prototype:
LONG_PTR  (APIENTRY * PFN) ();

Headers

Declared in winddi.h. Include winddi.h.

Comments

A graphics driver must allocate an array of DRVFN structures, with an array element for each graphics DDI function implemented in the driver. The driver returns the array's address to GDI in the DRVENABLEDATA structure whose pointer is passed to the driver's DrvEnableDriver function during driver initialization.

Graphics DDI function addresses can be placed in the DRVFN array in any order.

See Also

DrvEnableDriver


ENGSAFESEMAPHORE

ENGSAFESEMAPHORE provides the driver with a thread-safe semaphore.

typedef struct _ENGSAFESEMAPHORE {
  HSEMAPHORE  hsem;
  LONG  lCount;
} ENGSAFESEMAPHORE;

Members

hsem
Is a handle to the semaphore.
lCount
Specifies the reference count on the semaphore.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A safe semaphore is a wrapper that contains a handle to a semaphore and a reference count on that semaphore.

The driver allocates an ENGSAFESEMAPHORE structure and passes it to EngInitializeSafeSemaphore for initialization. GDI operates the safe semaphore under a lock and maintains a reference count on it, making it suitable for multithreading.

Once the safe semaphore is initialized, the driver can call EngAcquireSemaphore and EngReleaseSemaphore with the hsem for synchronization.

See Also

EngAcquireSemaphore, EngDeleteSafeSemaphore, EngInitializeSafeSemaphore, EngReleaseSemaphore


ENG_TIME_FIELDS

ENG_TIME_FIELDS is the structure in which EngQueryLocalTime returns the local time.

typedef struct _ENG_TIME_FIELDS {
  USHORT  usYear;
  USHORT  usMonth;
  USHORT  usDay;
  USHORT  usHour;
  USHORT  usMinute;
  USHORT  usSecond;
  USHORT  usMilliseconds;
  USHORT  usWeekday;
} ENG_TIME_FIELDS, *PENG_TIME_FIELDS;

Members

usYear
Specifies the current calendar year. The range is [1601,...].
usMonth
Specifies the current calendar month. The range is [1,12].
usDay
Specifies the current calendar day. The range is [1,31].
usHour
Specifies the current hour. The range is [0,23].
usMinute
Specifies the current minute. The range is [0,59].
usSecond
Specifies the current second. The range is [0,59].
usMilliseconds
Specifies the current millisecond. The range is [0,999].
usWeekday
Specifies the current day. The range is [0,6], where 0 is Sunday and 6 is Saturday.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The driver is responsible for allocating the ENG_TIME_FIELDS structure and passing its pointer to EngQueryLocalTime.


ENUMRECTS

ENUMRECTS is used by the CLIPOBJ_cEnumStart function to provide information about rectangles in a clip region for the CLIPOBJ_bEnum function.

typedef struct _ENUMRECTS {
  ULONG  c;
  RECTL  arcl[1];
} ENUMRECTS;

Members

c
Specifies the number of RECTL structures in the arcl array.
arcl
Is an array of RECTL structures that specify the coordinates of rectangles in the clip region.

Headers

Declared in winddi.h. Include winddi.h.


FD_DEVICEMETRICS

FD_DEVICEMETRICS is used to provide device-specific font information to GDI if the iMode parameter of the driver-supplied DrvQueryFontData function is QFD_MAXEXTENTS.

typedef struct _FD_DEVICEMETRICS {
  FLONG   flRealizedType;
  POINTE  pteBase;
  POINTE  pteSide;
  LONG  lD;
  FIX  fxMaxAscender;
  FIX  fxMaxDescender;
  POINTL  ptlUnderline1;
  POINTL  ptlStrikeout;
  POINTL  ptlULThickness;
  POINTL  ptlSOThickness;
  ULONG  cxMax;
  ULONG  cyMax;
  ULONG  cjGlyphMax;
  FD_XFORM  fdxQuantized;
  LONG  lNonLinearExtLeading;
  LONG  lNonLinearIntLeading;
  LONG  lNonLinearMaxCharWidth;
  LONG  lNonLinearAvgCharWidth;
  LONG  lMinA;
  LONG  lMinC;
  LONG  lMinD;
  LONG  alReserved[1];
} FD_DEVICEMETRICS, *PFD_DEVICEMETRICS;

Members

flRealizedType
Is a set of accelerator flags. This value can be a combination of the following values:
Flag Meaning
FDM_TYPE_BM_SIDE_CONST
An accelerator for horizontal and vertical writing. If this flag is set, the font has constant height for all bitmaps. In the horizontal case, this means that the cy dimension is constant; in the vertical case, this means that the cx dimension is constant. This accelerator is not used for outlines.
FDM_TYPE_CHAR_INC_EQUAL_BM_BASE
An accelerator for horizontal and vertical writing. In the horizontal case, if this flag is set, each glyph's advance width is equal to the cx dimension of the glyph bitmap; in the vertical case, if this flag is set, each glyph's advance width is equal to the cy dimension of the glyph bitmap. This accelerator is not used for outlines.
FDM_TYPE_CONST_BEARINGS
If set, the a and c spacing is constant for all glyphs.
FDM_TYPE_MAXEXT_EQUAL_BM_SIDE
This flag can be set only if FDM_TYPE_BM_SIDE_CONST is also set. If set, the font height (as defined above for horizontal and vertical writing) is equal to the sum of max ascender and max descender. This accelerator is not used for outlines.
FDM_TYPE_ZERO_BEARINGS
If set, the a and c spacing is zero for all glyphs.

pteBase
Specifies the notional space unit vector along the font's baseline, transformed to device space and then normalized.
pteSide
Specifies a notional space unit vector perpendicular to the font's baseline in the direction of the ascender, transformed to device space and then normalized. In notional space, baseline and ascender directions must be orthogonal, but in device space, pteBase and pteSide do not have to be orthogonal, depending on the Notional to Device space transform.
lD
Specifies the advance width if the font is a fixed pitch (monospaced) font. If the font is a variable pitch font, this member should be set to zero.
fxMaxAscender
Specifies the hinted maximum ascender height for this font instance, measured along pteSide.
fxMaxDescender
Specifies the hinted maximum descender height for this font instance, measured along pteSide.
ptlUnderline1
Specifies the hinted underline position for this font instance, relative to the glyph's character origin.
ptlStrikeout
Specifies the hinted strikeout position for this font instance, relative to the glyph's character origin.
ptlULThickness
Specifies the hinted underline thickness for this font instance. This vector defines the side of the rectangle used to draw the underline. The base is implicitly defined by the baseline.
ptlSOThickness
Specifies the hinted strikeout thickness for this font instance. This vector defines the side of the rectangle used to draw the strikeout. The base is implicitly defined by the baseline.
cxMax
Specifies the hinted maximum glyph bitmap width, in pixels, for this font instance. Not used for outlines.
cyMax
Specifies the hinted maximum glyph bitmap height, in pixels, for this font instance. Not used for outlines.
cjGlyphMax
Specifies the hinted maximum size of a glyph, in pixels, for this font instance.
fdxQuantized
The font driver fills in the font transformation that is actually used in the realization of the font. This may differ from the transformation requested by GDI as defined by FONTOBJ_pxoGetXform.
lNonLinearExtLeading
Is the nonlinear external leading in 28.4 device units.
lNonLinearIntLeading
Is the nonlinear internal leading in 28.4 device units.
lNonLinearMaxCharWidth
Is the nonlinear maximum character increment in 28.4 device units.
lNonLinearAvgCharWidth
Is the nonlinear average character width in 28.4 device units.
lMinA
Is the largest negative A space for this font realization, specified as an absolute value.
lMinC
Is the largest negative C space for this font realization, specified as an absolute value.
lMinD
Is the smallest non-zero character width for this font realization.
alReserved
Is reserved and should be ignored by the font provider.

Headers

Declared in winddi.h. Include winddi.h.

Comments

On input to the font provider, GDI sets all DWORD fields to 0xFFFFFFFF. The font provider is expected to overwrite a field if the corresponding quantity does not scale linearly under realization.

See Also

DrvQueryFontData


FD_GLYPHATTR

FD_GLYPHATTR is used to specify the return value for the FONTOBJ_pQueryGlyphAttrs and DrvQueryGlyphAttrs functions.

typedef struct _FD_GLYPHATTR {
  ULONG  cjThis;
  ULONG  cGlyphs;
  ULONG  iMode;
  BYTE  aGlyphAttr[1];
} FD_GLYPHATTR, *PFD_GLYPHATTR;

Members

cjThis
Is the size in bytes of the FD_GLYPHATTR structure, including the array specified by the aGlyphAttr member.
cGlyphs
Specifies the number of glyphs in the font.
iMode
Is a flag indicating the type of information being returned. The following flag is defined:
Flag | Definition
FO_ATTR_MODE_ROTATE | The array specified by aGlyphAttr is a bit array indicating which glyphs of a vertical font must be rotated. The bit array's length is (cGlyphs+7)/8. If a glyph's bit is set, the glyph should be rotated during rasterization.

aGlyphAttr
Is an array supplying the information specified by iMode. The size of this array is (cGlyphs+7)/8 bytes.

Headers

Declared in winddi.h. Include winddi.h.

Comments

If iMode is FO_ATTR_MODE_ROTATE (the only flag currently defined), a printer driver can determine the bit that corresponds to a particular glyph index using the following code fragment, where hg is the glyph index and pga is a FD_GLYPHATTR structure pointer:

BYTE glyphBits[8] = {0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1};
(pga->aGlyphAttr[hg / 8] & (glyphBits[hg % 8])


FD_GLYPHSET

FD_GLYPHSET is used to define the mappings from Unicode characters to glyph handles.

typedef struct _FD_GLYPHSET {
  ULONG  cjThis;
  FLONG  flAccel;
  ULONG  cGlyphsSupported;
  ULONG  cRuns;
  WCRUN  awcrun[1];
} FD_GLYPHSET, *PFD_GLYPHSET;

Members

cjThis
Specifies the size, in bytes, of the structure, including the array of WCRUN structures.
flAccel
Specifies accelerator flags. This member must be the following value:
Flags | Meaning
GS_8BIT_HANDLES | All handles are 8-bit quantities.
GS_16BIT_HANDLES | All handles are 16-bit quantities.
GS_UNICODE_HANDLES | For all runs in this GLYPHSET, the handle is obtained by zero extending the Unicode code point.

cGlyphsSupported
Specifies the total number of glyphs in all runs.
cRuns
Specifies the number of RUN structures in the awcrun array.
awcrun
Is an array of WCRUN structures.

Headers

Declared in winddi.h. Include winddi.h.

See Also

DrvQueryFontTree, WCRUN


FD_KERNINGPAIR

FD_KERNINGPAIR is used to store information about kerning pairs.

typedef struct _FD_KERNINGPAIR {
  WCHAR  wcFirst;
  WCHAR  wcSecond;
  FWORD  fwdKern;
} FD_KERNINGPAIR;

Members

wcFirst
Specifies the code point of the first character in the kerning pair.
wcSecond
Specifies the code point of the second character in the kerning pair.
fwdKern
Specifies the kerning value, in font (notional) units, for the kerning pair. If this value is greater than zero, the characters will be moved apart; otherwise, the characters will be moved together.

Headers

Declared in winddi.h. Include winddi.h.

Comments

An array of FD_KERNINGPAIR structures must be zero-terminated, which means the last FD_KERNINGPAIR structure in the array has all structure members set to zero. An array of FD_KERNINGPAIR structures must be sorted in increasing order according to an unsigned 32-bit key, calculated as follows:

    wcFirst + 65536 * wcSecond.

See Also

DrvQueryFontTree


FD_XFORM

FD_XFORM describes an arbitrary two-dimensional font transform.

typedef struct _FD_XFORM {
  FLOATL  eXX;
  FLOATL  eXY;
  FLOATL  eYX;
  FLOATL  eYY;
} FD_XFORM, *PFD_XFORM;

Members

eXX, eXY, eYX, eYY
Are the four elements that comprise a 2x2 row-major matrix. eXX and eXY are the elements in the first row; eYX and eYY are the elements in the second row.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This structure is used typically to hold notional-to-device-space font transformations.


FLOATOBJ

FLOATOBJ is used to emulate a floating point number.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This structure, in conjunction with the FLOATOBJ_Xxx service routines, allows graphics drivers to emulate floating point arithmetic in the NT® kernel. Floating point arithmetic is not otherwise supported in the NT kernel code.

There are no public members in the FLOATOBJ structure.

See Also

FLOATOBJ_Add, FLOATOBJ_AddFloat, FLOATOBJ_AddLong, FLOATOBJ_Div, FLOATOBJ_DivFloat, FLOATOBJ_DivLong, FLOATOBJ_Equal, FLOATOBJ_EqualLong, FLOATOBJ_GetFloat, FLOATOBJ_GetLong, FLOATOBJ_GreaterThan, FLOATOBJ_GreaterThanLong, FLOATOBJ_LessThan, FLOATOBJ_LessThanLong, FLOATOBJ_Mul, FLOATOBJ_MulFloat, FLOATOBJ_MulLong, FLOATOBJ_Neg, FLOATOBJ_SetFloat, FLOATOBJ_SetLong, FLOATOBJ_Sub, FLOATOBJ_SubFloat, FLOATOBJ_SubLong, FLOATOBJ_XFORM, XFORMOBJ_iGetFloatObjXform


FLOATOBJ_XFORM

FLOATOBJ_XFORM describes an arbitrary linear two-dimensional transform, such as for geometric wide lines.

typedef struct {
  FLOATOBJ  eM11;
  FLOATOBJ  eM12;
  FLOATOBJ  eM21;
  FLOATOBJ  eM22;
  FLOATOBJ  eDx;
  FLOATOBJ  eDy;
} FLOATOBJ_XFORM, *PFLOATOBJ_XFORM, FAR *LPFLOATOBJ_XFORM;

Members

eM11, eM12, eM21, eM22
Are the four elements that comprise a 2x2 row-major matrix.
eDx, eDy
Are the x- and y-translation components of the transform.

Headers

Declared in winddi.h. Include winddi.h.

Comments

All elements are specified as FLOATOBJ values. The transform can be downloaded to the driver. Structure members can be operated on by the FLOATOBJ_Xxx routines.

See Also

FLOATOBJ, XFORMOBJ_iGetXform


FONTDIFF

FONTDIFF describes all of the characteristics that are different between a base font and one of its simulations.

typedef struct _FONTDIFF {
  BYTE  jReserved1;
  BYTE  jReserved2;
  BYTE  jReserved3;
  BYTE  bWeight;
  USHORT  usWinWeight;
  FSHORT  fsSelection;
  FWORD  fwdAveCharWidth;
  FWORD  fwdMaxCharInc;
  POINTL  ptlCaret;
} FONTDIFF;

Members

jReserved1, jReserved2, jReserved3
Are reserved for system use.
bWeight
Specifies the Panose weight.
usWinWeight
Specifies the weight of the font in the range 0 to 1000 (for example, 400 is normal and 700 is bold). This value is provided to the application in the lfWeight member of the Win32 LOGFONT structure.
fsSelection
Specifies a combination of the following flags:
Value | Meaning
FM_SEL_BOLD | Set if the characters of the font are bold.
FM_SEL_ITALIC | Set if the characters of the font are italic.
FM_SEL_NEGATIVE | Set if the characters of the font have the foreground and background reversed.
FM_SEL_OUTLINED | Set if the characters of the font are hollow.
FM_SEL_REGULAR | Set if the characters of the font are normal weight.
FM_SEL_STRIKEOUT | Set if the characters of the font are struck out by default; otherwise strikeouts must be simulated.
FM_SEL_UNDERSCORE | Set if all the characters of the font are underscored by default; otherwise underscoring must be simulated.

fwdAveCharWidth
Specifies the arithmetic average of the width of all of the 26 lower case letters 'a' through 'z' of the Latin alphabet and the space character. If any of the 26 lowercase letters are not present, then this member should be set equal to the weighted average of all glyphs in the font.
fwdMaxCharInc
Specifies the maximum character increment of all glyphs in the font.
ptlCaret
Specifies the direction of the ascender direction of the font. For example, the value for a non-italicized Latin font is (0,1) while an italicized Latin font might specify a value of (2,5).

Headers

Declared in winddi.h. Include winddi.h.

Comments

If a font has already been emboldened, the only possible remaining simulation is italicization, yielding a bold italic simulation. Similarly, an italicized font can only be emboldened, also yielding a bold italic simulation.

See Also

FONTSIM


FONTSIM

FONTSIM contains offsets to one or more FONTDIFF structures describing bold, italic, and bold italic font simulations.

typedef struct _FONTSIM {
  PTRDIFF  dpBold;
  PTRDIFF  dpItalic;
  PTRDIFF  dpBoldItalic;
} FONTSIM;

Members

dpBold
If nonzero, specifies the offset from the beginning of this structure to the FONTDIFF structure describing the bold simulation. If this member is zero, the font does not support bold simulation.
dpItalic
If nonzero, specifies the offset from the beginning of this structure to the FONTDIFF structure describing the italic simulation. If this member is zero, the font does not support italic simulation.
dpBoldItalic
If nonzero, specifies the offset from the beginning of this structure to the FONTDIFF structure describing the bold italic simulation. If this member is zero, the font does not support bold italic simulation.

Headers

Declared in winddi.h. Include winddi.h.

Comments

If the dpFontSim member of the IFIMETRICS structure is nonzero, it holds the offset from the beginning of that structure to the beginning of a FONTSIM structure.

See Also

FONTDIFF, IFIMETRICS


FONTINFO

FONTINFO contains information regarding a specific font.

typedef struct {
  ULONG  cjThis;
  FLONG  flCaps;
  ULONG  cGlyphsSupported;
  ULONG  cjMaxGlyph1;
  ULONG  cjMaxGlyph4;
  ULONG  cjMaxGlyph8;
  ULONG  cjMaxGlyph32;
} FONTINFO, *PFONTINFO;

Members

cjThis
Specifies the size of this FONTINFO structure in bytes.
flCaps
Is a set of capabilities flags. The allowed flags are FO_DEVICE_FONT and FO_OUTLINE_CAPABLE.
cGlyphsSupported
Specifies the number of glyphs in the font.
cjMaxGlyph1
Specifies the size of the largest glyph in 1 bit/pixel. A nonzero value implies that 1-bit-per-pixel bitmaps are supported.
cjMaxGlyph4
Specifies the size of the largest glyph in 4 bit/pixel. A nonzero value implies that 4-bit-per-pixel bitmaps are supported.
cjMaxGlyph8
Specifies the size of the largest glyph in 8 bit/pixel. A nonzero value implies that 8-bit-per-pixel bitmaps are supported.
cjMaxGlyph32
Specifies the size of the largest glyph in 32 bit/pixel. A nonzero value implies that 32-bit-per-pixel bitmaps are supported.

Headers

Declared in winddi.h. Include winddi.h.

Comments

GDI writes and returns this structure through FONTOBJ_vGetInfo.

See Also

FONTOBJ_vGetInfo


FONTOBJ

FONTOBJ is used to give a driver access to information about a particular instance of a font.

typedef struct _FONTOBJ {
  ULONG  iUniq;
  ULONG  iFace;
  ULONG  cxMax;
  FLONG  flFontType;
  ULONG_PTR  iTTUniq;
  ULONG_PTR  iFile;
  SIZE  sizLogResPpi;
  ULONG  ulStyleSize;
  PVOID  pvConsumer;
  PVOID  pvProducer;
} FONTOBJ;

Members

iUniq
Specifies a distinct realization of the font. This value can be used by the driver to identify a GDI font that it might have cached or to identify a driver's realization of its own font. If this member is zero for a GDI font, the font should not be cached.
iFace
Specifies the device index for a device font, which was registered by a call to DrvQueryFont. If the font is a GDI font, this member has meaning only to GDI, and the driver should ignore it.
cxMax
Specifies the width, in pixels, of the largest glyph in the specified font.
flFontType
Is a value specifying the type of the font. This member can be a combination of the flags listed in the following table. (Note, however, that FO_GRAY16 and FO_NOGRAY16 are mutually exclusive.)
Flag | Meaning
FO_CFF | Postscript OpenType font.
FO_DBCS_FONT | Font supports DBCS code pages.
FO_EM_HEIGHT | TrueType driver internal flag.
FO_GRAY16 | Font bitmaps are four bits-per-pixel blending (alpha) values.
FO_MULTIPLEMASTER | Multiple Master (Type1 or OpenType) font.
FO_NOGRAY16 | Indicates that the font driver cannot (or will not) grayscale a particular font realization.
FO_POSTSCRIPT | Postscript (Type1 or OpenType) font.
FO_SIM_BOLD | Driver-simulated bold font.
FO_SIM_ITALIC | Driver-simulated italic font.
FO_TYPE_DEVICE | Device-specific font.
FO_TYPE_OPENTYPE | OpenType™ font.
FO_TYPE_RASTER | Bitmap font.
FO_TYPE_TRUETYPE | TrueType font.
FO_VERT_FACE | Vertical font.

If the RASTER_FONTYPE flag is set, the glyphs written to the specified STROBJ structure are bitmaps, otherwise they are pointers to PATHOBJ structures. If the glyph images are returned in the form of PATHOBJ structures, the driver must inspect the FM_INFO_TECH_STROKE flag of the flInfo member of the associated IFIMETRICS structure. If that flag is set, the paths should be stroked, otherwise the paths must be filled using the alternating mode convention.

If the FO_GRAY16 flag is set then the font bitmaps are four bits-per-pixel blending (alpha) values A value of zero means that the resulting pixel should have the same color as the background. If the alpha value is k, then the following table describes the attributes of the resulting pixel:
Pixel Attribute | Calculation
Blending b = 0 if k = 0
b = (k + 1)/16, for k = 1, 2, ... , 15
Luminance Components d0 = gamma[c0]
d1 = gamma[c1]
where c0 is the background color, c1 is the foreground color, and gamma[] takes a color component from application space to CIE space.
Blended Luminance | d = (1 - b) * d0 + b * d1
Blended Device Voltage c = lambda[d]
where lambda takes a color from CIE space to device color space.

GDI sets the FO_GRAY16 flag when it requests that a font be grayscaled to one of 16 values. In this case GDI sets the FO_GRAY16 bit on entry to the DrvQueryFontData function. If the font driver cannot, or will not grayscale a particular font realization, then the font provider clears the FO_GRAY16 flag and sets the FO_NOGRAY16 flag to inform GDI that the grayscaling request will not be satisfied.

iTTUniq
Specifies the associated TrueType file. Two separate point size realizations of a TrueType font face will have FONTOBJ structures that share the same iTTUniq value, but will have different iUniq values. Only TrueType font types can have a nonzero iTTUniq member. For more information see flFontType.
iFile
Is the identifier returned for device fonts already loaded. If the font is a GDI font, then this member is used internally to identify the font and should be ignored.
sizLogResPpi
Specifies the resolution of the device for which this font is realized.
ulStyleSize
Specifies the style size of the font instance, in points.
pvConsumer
A consumer is a driver that accepts glyph information as input for generating text output. Only a font consumer can modify this member. The consumer of this font can store any information in the location pointed to by this member. This member should be used to store a pointer to consumer-allocated data associated with this font instance. The engine will not modify this member. The pvConsumer member is guaranteed to be null the first time a FONTOBJ structure is passed to the consumer.
pvProducer
A producer is a driver that can produce glyph information as output; this includes glyph metrics, bitmaps, and outlines. Only a font producer can modify this member. The producer of this font can store any information in the location pointed to by this member. This member should be used to store a pointer to producer-allocated data associated with this font instance. The engine will not modify this member. The pvProducer member is guaranteed to be null the first time a FONTOBJ structure is passed to the producer.

Headers

Declared in winddi.h. Include winddi.h.

Comments

As an accelerator, the driver is allowed to access the public members of the FONTOBJ structure.

A driver can be both a producer and a consumer. For example, a printer driver can act as a producer while processing a call to the driver-supplied DrvQueryFontData function to provide glyph metrics, and later act a consumer while processing a call to the driver-supplied DrvTextOut function.

See Also

DrvDestroyFont, DrvGetGlyphMode, DrvQueryFont, DrvQueryTrueTypeOutline, FONTOBJ_cGetAllGlyphHandles, FONTOBJ_cGetGlyphs, FONTOBJ_pifi, FONTOBJ_pxoGetXform, FONTOBJ_vGetInfo, IFIMETRICS


GAMMARAMP

GAMMARAMP is used by DrvIcmSetDeviceGammaRamp to set the hardware gamma ramp of a particular display device.

typedef struct _GAMMARAMP {
  WORD  Red[256];
  WORD  Green[256];
  WORD  Blue[256];
} GAMMARAMP, *PGAMMARAMP;

Members

Red
Is the 256-entry ramp for the red color channel.
Green
Is the 256-entry ramp for the green color channel.
Blue
Is the 256-entry ramp for the blue color channel.

Headers

Declared in winddi.h. Include winddi.h.


GDIINFO

GDIINFO describes the graphics capabilities of a given device.

typedef struct _GDIINFO {
  ULONG  ulVersion;
  ULONG  ulTechnology;
  ULONG  ulHorzSize;
  ULONG  ulVertSize;
  ULONG  ulHorzRes;
  ULONG  ulVertRes;
  ULONG  cBitsPixel;
  ULONG  cPlanes;
  ULONG  ulNumColors;
  ULONG  flRaster;
  ULONG  ulLogPixelsX;
  ULONG  ulLogPixelsY;
  ULONG  flTextCaps;
  ULONG  ulDACRed;
  ULONG  ulDACGreen;
  ULONG  ulDACBlue;
  ULONG  ulAspectX;
  ULONG  ulAspectY;
  ULONG  ulAspectXY;
  LONG  xStyleStep;
  LONG  yStyleStep;
  LONG  denStyleStep;
  POINTL  ptlPhysOffset;
  SIZEL  szlPhysSize;
  ULONG  ulNumPalReg;
  COLORINFO  ciDevice;
  ULONG  ulDevicePelsDPI;
  ULONG  ulPrimaryOrder;
  ULONG  ulHTPatternSize;
  ULONG  ulHTOutputFormat;
  ULONG  flHTFlags;
  ULONG  ulVRefresh;
  ULONG  ulBltAlignment;
  ULONG  ulPanningHorzRes;
  ULONG  ulPanningVertRes;
  ULONG  xPanningAlignment;
  ULONG  yPanningAlignment;
  ULONG  cxHTPat;
  ULONG  cyHTPat;
  LPBYTE  pHTPatA;
  LPBYTE  pHTPatB;
  LPBYTE  pHTPatC;
  ULONG  flShadeBlend;
  ULONG  ulPhysicalPixelCharacteristics;
  ULONG  ulPhysicalPixelGamma;
} GDIINFO, *PGDIINFO;

Members

ulVersion
Specifies the driver version number. The byte ordering of ulVersion has the following form.

The high-order 16 bits must be set to zero. Bits 8 through 15 specify the version number of the Microsoft operating system for which the driver is designed. The high-order 4 bits of this range specify the major number of the version, the low-order 4 bits contain the minor number of the version. The low-order 8 bits of ulVersion specify the version number of the display driver; this value should be incremented for each release of the display driver binary file.

The version number contained in ulVersion is displayed in the Driver Information group of the Display Type dialog box displayed by the Display applet in Control Panel.

ulTechnology
Specifies the device technology. This member can be one of the following values:
Value | Meaning
DT_CHARSTREAM | Device fonts only
DT_PLOTTER | Vector plotter
DT_RASCAMERA | Raster camera
DT_RASDISPLAY | Raster display
DT_RASPRINTER | Raster printer

ulHorzSize
Specifies the width of the physical surface. A positive value indicates that the width is in units of millimeters, while a negative value denotes that the width is in units of micrometers.
ulVertSize
Specifies the height of the physical surface. A positive value indicates that the height is in units of millimeters, while a negative value denotes that the height is in units of micrometers.
ulHorzRes
Specifies the width of the physical surface, in pixels. See also ulDesktopHorzRes.
ulVertRes
Specifies the height of the physical surface, in pixels. See also ulDesktopHorzRes.
cBitsPixel
Specifies the number of adjacent bits in each color plane. The total number of bits per pixel is the product of cBitsPixel and cPlanes.
cPlanes
Specifies the number of color planes.
ulNumColors
For palettized devices, ulNumColors specifies the number of entries in the default color palette. For non-palettized devices (which do not include printers), ulNumColors is set to -1.
flRaster
Is reserved and must be left set to zero.
ulLogPixelsX
Specifies the width resolution of the device in logical pixels per inch.

For printers, this member should be set to the printer's resolution in dpi.

For displays, this member must be set to 96.

ulLogPixelsY
Specifies the height resolution of the device in logical pixels per inch.

For printers, this member should be set to the printer's resolution in dpi.

For displays, this member must be set to 96.

flTextCaps
Specifies a flag describing Windows® 3.1 text capabilities. If the driver TC_SCROLLBLT flag is in this member, it indicates that the console should perform text scrolling by redrawing the entire screen, using the driver-supplied DrvTextOut function rather than the DrvBitBlt or DrvCopyBits functions. The driver should set this flag if screen-to-screen bit-block transfers are slow. If this flag is not set, the driver is implicitly requesting that the console perform text scrolls through DrvBitBlt/DevCopyBits.
ulDACRed, ulDACGreen, ulDACBlue
Specifies the display number of DAC bits for the specified color.
ulAspectX
Specifies the relative width of a device pixel, in the range of one to 1000.
ulAspectY
Specifies the relative height of a device pixel, in the range of one to 1000.
ulAspectXY
Specifies the square root of the sum of the squares of ulAspectX and ulAspectY.
xStyleStep
Specifies the numerator of style advance for x-major lines, dx. For additional information, refer to the following Comments section and Styled Cosmetic Lines.
yStyleStep
Specifies the numerator of style advance for y-major lines, dy. For additional information, refer to the following Comments section and Styled Cosmetic Lines.
denStyleStep
Specifies the denominator of style advance, D. For additional information, refer to the following Comments section and Styled Cosmetic Lines.
ptlPhysOffset
Specifies the size, in pixels, of the unwritable margin of a surface.
szlPhysSize
Specifies the size, in pixels, of the entire surface, including unwritable margins.
ulNumPalReg
Specifies the number of palette registers for an indexed device.
ciDevice
Is a COLORINFO structure that defines the device's colors in CIE coordinate space.
ulDevicePelsDPI
For printers, specifies the number of pixels (or dots, or nozzles) per inch if the pixels are laid out side by side without overlapping or space between. For example, if the size of a pixel is 0.001 inch, this value is equal to one-divided-by 0.001. If the member is zero, GDI halftoning calculates this number based on the assumption that all pixels are connected with no overlapping.

Because the physical dot size for most printers is larger than the measured dot size, GDI uses this value to approximate how many physical dots can be placed, based on the cell size (pattern size). A log regression is then performed to determine what is most linear; that is, where the dots should be placed for the best coverage to optimize the overlapped device pixels coverage (dot gain).

For displays, this member should be set to zero.

ulPrimaryOrder
Specifies the bit order of the device's primary colors or plane numbers for the halftone output in accordance with the color-to-bit mapping listed in the following table. For example, if your device output order is BGR (Bit 0[C], Bit 1[B], Bit 2[A]), set this member to PRIMARY_ORDER_CBA.
Bit 2(A) | Bit 1(B) | Bit 0(C)
RGB Primary Colors | R | G | B
CMY Primary Colors | C | M | Y
Plane Numbers | Plane3 | Plane2 | Plane1

This member can be one of the following values:

PRIMARY_ORDER_ABC
PRIMARY_ORDER_ACB
PRIMARY_ORDER_BAC
PRIMARY_ORDER_BCA
PRIMARY_ORDER_CBA
PRIMARY_ORDER_CAB

ulHTPatternSize
Specifies the size of the halftone pattern. The values ending with AxB_M are variations of the AxB patterns. In other words, SIZE_AxB and SIZE_AxB_M differ by which pixels are lit in an A x B pattern. This member can be one of the following values:

HT_PATSIZE_2x2
HT_PATSIZE_2x2_M
HT_PATSIZE_4x4
HT_PATSIZE_4x4_M
HT_PATSIZE_6x6
HT_PATSIZE_6x6_M
HT_PATSIZE_8x8
HT_PATSIZE_8x8_M
HT_PATSIZE_10x10
HT_PATSIZE_10x10_M
HT_PATSIZE_12x12
HT_PATSIZE_12x12_M
HT_PATSIZE_14x14
HT_PATSIZE_14x14_M
HT_PATSIZE_16x16
HT_PATSIZE_16x16_M
HT_PATSIZE_SUPERCELL
HT_PATSIZE_SUPERCELL_M
HT_PATSIZE_USER
HT_PATSIZE_MAX_INDEX
HT_PATSIZE_DEFAULT

ulHTOutputFormat
Specifies the preferred output format for halftone. HT_FORMAT_4BPP uses only 8 full intensity colors while HT_FORMATP_IRGB uses all the 16 colors including the half-intensity colors. It is assumed that a 5 x 5 x 5 format (5 bits per color) is used for HT_FORMAT_16BPP. This member can be one of the following values:

HT_FORMAT_1BPP
HT_FORMAT_4BPP
HT_FORMAT_4BPP_IRGB
HT_FORMAT_8BPP
HT_FORMAT_16BPP
HT_FORMAT_24BPP
HT_FORMAT_32BPP

flHTFlags
Specifies a combination of flags describing the device. These flags are needed for halftoning. This member can be a combination of the following values:
Flag | Meaning
HT_FLAG_8BPP_CMY332_MASK | Flag used to clear the upper eight bits of flHTFlags (bits 24 to 31). The MAKE_CMY332_MASK macro can then be used to set these bits with 8-bit-per-pixel CMY mode ink level information. See Using GDI 8-Bit-Per-Pixel CMY Mask Modes for more information.
HT_FLAG_ADDITIVE_PRIMS | Device primaries are additive.
HT_FLAG_DO_DEVCLR_XFORM | Requests GDI to perform generic color correction.
HT_FLAG_HAS_BLACK_DYE | Device has separate black dye.
HT_FLAG_HIGH_INK_ABSORPTION
HT_FLAG_HIGHER_INK_ABSORPTION
HT_FLAG_HIGHEST_INK_ABSORPTION 		Paper in device absorbs more than normal amount of ink, so GDI should render less ink to paper. These flags indicate the relative amount of ink absorption, with HT_FLAG_HIGHER_INK_ABSORPTION denoting more absorption than HT_FLAG_HIGH_INK_ABSORPTION, but less than HT_FLAG_HIGHEST_INK_ABSORPTION.
HT_FLAG_INK_ABSORPTION_IDX0
HT_FLAG_INK_ABSORPTION_IDX1
HT_FLAG_INK_ABSORPTION_IDX2
HT_FLAG_INK_ABSORPTION_IDX3 		Flags used to define HT_FLAG_HIGH/HIGHER/HIGHEST_INK_ABSORPTION and HT_FLAG_LOW/LOWER/LOWEST_INK_ABSORPTION.
HT_FLAG_INK_HIGH_ABSORPTION | Flag used to define HT_FLAG_HIGH/HIGHER/HIGHEST_INK_ABSORPTION.
HT_FLAG_INVERT_8BPP_BITMASK_IDX | GDI halftone should render 8-bit-per-pixel ask mode surface bitmap using a CMY_INVERTED mode palette. See Using GDI 8-Bit-Per-Pixel CMY Mask Modes for CMY_INVERTED mode palette description and requirements.
HT_FLAG_LOW_INK_ABSORPTION
HT_FLAG_LOWER_INK_ABSORPTION
HT_FLAG_LOWEST_INK_ABSORPTION 		Paper in device absorbs less than normal amount of ink, so GDI should render more ink to paper. These flags indicate the relative amount of ink absorption, with HT_FLAG_LOWER_INK_ABSORPTION denoting less absorption than HT_FLAG_LOW_INK_ABSORPTION, but more than HT_FLAG_LOWEST_INK_ABSORPTION.
HT_FLAG_NORMAL_INK_ABSORPTION | Paper in device absorbs normal amount of ink.
HT_FLAG_OUTPUT_CMY | Device uses CMY primaries rather than RGB primaries. This flag value applies only to 1 bpp and 4 bpp destination surfaces.
HT_FLAG_PRINT_DRAFT_MODE | Disables GDI's antialiasing code.
HT_FLAG_SQUARE_DEVICE_PEL | Device pixel is square rather than round (displays only — printers require rounded pixels).
HT_FLAG_USE_8BPP_BITMASK | Device uses monochrome printing.

ulVRefresh
The video refresh rate for the currrent display mode. This is the value returned by the miniport driver for the refresh rate for the current mode.

The refresh rate contained in ulVRefresh is displayed in the Driver Information group of the Display Type dialog box displayed by the Display applet contained in Control Panel.

ulBltAlignment
This member indicates the preferred x-alignment for bit block transfers to the device. A value of zero indicates that bit block transfers are accelerated; any other nonnegative number indicates that bit block transfers are not accelerated, and gives the preferred horizontal alignment as a pixel multiple.

This value is used by the system to determine the default alignment for window positions and is also used to set the initial full-drag default during setup. A value of zero indicates that full-drag should be on by default; any value other than zero indicates that full-drag should be off by default.

ulPanningHorzRes, ulPanningVertRes
Should be ignored by the driver and remain zero-initialized.
xPanningAlignment, yPanningAlignment
Should be ignored by the driver and remain zero-initialized.
cxHTPat, cyHTPat
Specify the width and height, respectively, in pixels, of the user-supplied halftone dither pattern. The value of cxHTPat must be in the range HT_USERPAT_CX_MIN to HT_USERPAT_CX_MAX, inclusive. The value of cyHTPat must be in the range HT_USERPAT_CY_MIN to HT_USERPAT_CY_MAX, inclusive. These constants are defined in winddi.h. See the following Comments section for more information.
pHTPatA, pHTPatB, pHTPatC
Point to the user-defined halftone dither patterns for primary colors A, B, and C, respectively, as defined by the PRIMARY_ORDER_XXX value in the ulPrimaryOrder member. Each dither pattern must be a valid two-dimensional byte array of size cxHTPat by cyHTPat. See the following Comments section for more information.
flShadeBlend
Should be ignored by the driver and remain zero-initialized.
ulPhysicalPixelCharacteristics
Specifies the way that color fragments are configured to form pixels on the display device. The color fragments on the display device can be arranged in RGB order, or in BGR order, completely independent of the RGB ordering in the frame buffer. The color fragments can be configured in horizontal stripes in which all of the fragments in one row are the same color. Alternatively, the color fragments can be configured in vertical stripes, in which all fragments in one column are the same color. Vertical striping is preferred, since it effectively provides three separate fragments in a row for each pixel, thereby giving greater horizontal subpixel resolution.

The ulPhysicalPixelCharacteristics member must be set to one of the values shown in the following table:
Value | Meaning
PPC_DEFAULT | Display device physical pixel information is unknown.
PPC_BGR_ORDER_HORIZONTAL_STRIPES | Physical color fragments on the display device are arranged, from top to bottom, in rows of blue, green, and red color fragments.
PPC_BGR_ORDER_VERTICAL_STRIPES | Physical color fragments on the display device are arranged, from left to right, in columns of blue, green, and red color fragments.
PPC_RGB_ORDER_HORIZONTAL_STRIPES | Physical color fragments on the display device are arranged, from top to bottom, in rows of red, green, and blue color fragments.
PPC_RGB_ORDER_VERTICAL_STRIPES | Physical color fragments on the display device are arranged, from left to right, in columns of red, green, and blue color fragments.
PPC_UNDEFINED Display device physical pixel information is known but cannot be expressed as one of the given enumerations. The enumerations are currently applicable to an LCD-based monitor. The driver should set ulPhysicalPixelCharacteristics to PPC_UNDEFINED when either of the following conditions is met. (This list is not comprehensive, but covers the most common conditions.)
  • The driver has knowledge that the monitor is not an LCD device.
  • The device is an LCD device but the resolution of the frame buffer is different from the native resolution of the physical display requiring scaling. That is, scaling is required because there is no longer a one-to-one correspondence between frame buffer pixels and device pixels.

ulPhysicalPixelGamma
Specifies the gamma of the display device. This member should be set to either the gamma of the physical pixel, scaled by a factor of 1000, or to one of the following values. For example, a gamma value of 2.2 would be represented as 2200.
Value | Meaning
PPG_DEFAULT | The driver has no knowledge of the gamma for the device.
PPG_SRGB | The device uses an sRGB gamma.

Headers

Declared in winddi.h. Include winddi.h.

Comments

GDI zero-initializes this structure before calling the driver-supplied DrvEnablePDEV function.

The xStyleStep, yStyleStep, and denStyleStep members define how a cosmetic line style should advance as it draws each pixel of a cosmetic line. The amount advanced along the style for each pixel is defined as a fraction that depends on whether the line is x-styled or y-styled. If the line is x-styled, the style advances by the fractional amount dx/D for each pixel moved in the x direction. Otherwise the style advances by dy/D for each pixel moved in the y direction.

The dots in the predefined line style PS_DOT are each one unit long. If the driver defines xStyleStep as one and denStyleStep as 5, then a dotted horizontal line consists of 5-pixels-on followed by 5-pixels-off, repeated.

Each of these three numbers must be less than 65536, even though the caps members are LONG values. These style steps are defined by the driver to ensure that the dots and dashes in a line are a pleasing size on the output device. The horizontal and vertical steps can be different to correct for non trivial aspect ratios. For example, on an EGA display, whose pixels are 33 percent higher than they are wide, you can set:

pdevcaps->xStyleStep   =  3;    // For an EGA
pdevcaps->yStyleStep   =  4;
pdevcaps->denStyleStep = 12;

In this case, horizontal dotted lines are 4-pixels-on, 4-pixels-off, because the style advances by 3/12 or 1/4 for each pixel. Vertical dotted lines are 3-pixels-on/3-pixels-off.

Styled lines look better if both the x and y style steps divide evenly into the style denominator, as they do in the preceding example. This gives dashes and dots that are always the same length.

GDI needs this information so that its bitmap functions can emulate exactly what the device does on its own surface. Applications can access this information to determine exactly which pixels will be turned on for styled lines. Refer also to Styled Cosmetic Lines.

The halftone-related members, cxHTPat, cyHTPat, pHTPatA, pHTPatB, and pHTPatC, can be used in an OEM Unidrv rendering plug-in to define a custom halftone pattern consisting of either one or three colors. These members are checked only if the ulHTPatternSize member is set to HT_PATSIZE_USER. In this case an OEM can use these members to define a custom halftone pattern, based on data stored in a resource file or generated by an OEM customization module. The cxHTPat and cyHTPat members define the size of each of the three two-dimensional halftone pattern arrays. The pHTPatA, pHTPatB, and pHTPatC members point to the respective pattern arrays for each color. If only one pattern array is used, pHTPatA points to it, and the other two pointers are set to NULL.

Each byte threshold at a particular location in a halftone dither pattern determines whether the pixel at the corresponding output plane location will be on or off. A zero threshold value at a particular location in the pattern array indicates that the corresponding pixel location is ignored (is black). Threshold values from 1 to 255 provide the dither pattern with 255 levels of gray; if the pixel value in the output plane is greater than or equal to the threshold value for that location, the pixel is turned on. A pixel value less than its corresponding threshold value causes its pixel to be turned off in the output plane. See Customized Halftoning in Customizing Microsoft's Printer Drivers for more information.

See Also

CIECHROMA, COLORINFO, DrvBitBlt, DrvCopyBits, DrvEnablePDEV, DrvTextOut


GLYPHBITS

GLYPHBITS is used to define a glyph bitmap.

typedef struct _GLYPHBITS {
  POINTL ptlOrigin;
  SIZEL  sizlBitmap;
  BYTE  aj[1];
} GLYPHBITS;

Members

ptlOrigin
Is a POINTL structure that defines the origin of the character in the bitmap.
sizlBitmap
Specifies the size, in bytes, of the bitmap.
aj
A variable-sized byte array containing a BYTE-aligned bitmap of the glyph. The array must include padding at the end to DWORD-align the entire structure.

GDI will make this request of drivers that have antialiased fonts (see the description of DrvQueryFontCaps). It is possible that a driver may not be able to render a font in a multilevel format. In this case, the driver fails the call and GDI will call the driver again requesting a monochrome realization.

Headers

Declared in winddi.h. Include winddi.h.

See Also

DrvGetGlyphMode, DrvQueryFontData, FONTOBJ_cGetGlyphs, GLYPHDEF


GLYPHDATA

GLYPHDATA contains information about an individual glyph.

typedef struct _GLYPHDATA {
  GLYPHDEF gdf;
  HGLYPH  hg;
  FIX  fxD;
  FIX  fxA;
  FIX  fxAB;
  FIX  fxInkTop;
  FIX  fxInkBottom;
  RECTL  rclInk;
  POINTQF  ptqD;
} GLYPHDATA;

Members

gdf
Points to either a GLYPHBITS structure or a PATHOBJ structure, depending on, respectively, whether the glyph data is in the form of a bitmap or an outline.
hg
Is the glyph handle.
fxD
Specifies the character increment amount, D = A + B + C. The character increment amount represents the sum of the prebearing, or left sidebearing amount (A), the width of the glyph (B), and the width of the right sidebearing amount (C). The two sidebearing amounts represent the (usually) empty space immediately to the left and right of the glyph. The value stored in fxD is the dot product of D and a unit vector along the baseline (in device coordinates), yielding the projection of D onto the baseline.
fxA
Specifies the prebearing, or left sidebearing amount, A. The value stored in fxA is the dot product of A and a unit vector along the baseline (in device coordinates), yielding the projection of A onto the baseline.
fxAB
Specifies the advancing edge of the character, A + B. The value stored in fxAB is the dot product of A + B and a unit vector along the baseline (in device coordinates), yielding the projection of A + B onto the baseline.
fxInkTop
Specifies the distance between the baseline and the ink box top along a unit vector in the ascent direction (in device coordinates).
fxInkBottom
Specifies the distance between the baseline and the ink box bottom along a unit vector in the ascent direction (in device coordinates).
rclInk
Specifies the ink box in which the glyph fits. The sides of the ink box are parallel to the x and y axes.
ptqD
Specifies the character increment vector, D = A + B + C. The high-order WORDs of ptqD are 28.4 device coordinates. The low-order WORDs of this member provide additional precision.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The quantities A, B, and C mentioned in the descriptions of GLYPHDATA members are simple tranforms of the notional space versions into 28.4 device coordinates. A is the left sidebearing amount, the width of the space to the left of the glyph, B is the width of the glyph, and C is the right sidebearing amount, the width of the space to the right of the glyph. For some glyphs, A and/or C can be negative, indicating that the glyph extends farther to the left and/or right than is usually the case.


GLYPHDEF

GLYPHDEF union identifies individual glyphs and provides either a pointer to a GLYPHBITS structure or a pointer to a PATHOBJ structure.

typedef union _GLYPHDEF {
  GLYPHBITS  *pgb;
  PATHOBJ  *ppo;
} GLYPHDEF;

Members

pgb
If pgb is defined, this member points to a GLYPHBITS structure. The driver can use the bitmap bits stored in this structure to form the associated glyph on its surface.
ppo
If ppo is defined, this member points to a PATHOBJ structure the driver can examine to extract the path describing the associated glyph.

Headers

Declared in winddi.h. Include winddi.h.

See Also

GLYPHBITS, PATHOBJ


GLYPHPOS

GLYPHPOS is used by GDI to provide a graphics driver with a glyph's description and position.

typedef struct _GLYPHPOS {
  HGLYPH  hg;
  GLYPHDEF  *pgdf;
  POINTL  *ptl;
} GLYPHPOS, *PGLYPHPOS;

Members

hg
Identifies the glyph.
pgdf
Pointer to a GLYPHDEF structure.
ptl
Specifies the point in device space where the character origin of the glyph should be placed. Note that if the driver had set GCAPS_HIGHRESTEXT in the flGraphicsCaps member of DEVINFO at enable time, the x and y coordinates should be interpreted as FIX point quantities; otherwise they should be interpreted as LONGs.

Headers

Declared in winddi.h. Include winddi.h.

Comments

For printer drivers:
If a printer graphics DLL is executing in user mode, and if the DLL has received the GLYPHPOS structure as input to DrvTextOut or as a result of calling STROBJ_bEnum (see STROBJ), then the pgdf member is always NULL. In such cases, the DLL can call FONTOBJ_cGetGlyphs to obtain the glyph's bitmap or outline.

See Also

STROBJ, STROBJ_bEnum, STROBJ_vEnumStart


IFIEXTRA

IFIEXTRA defines additional information for a given typeface that GDI can understand.

typedef struct _IFIEXTRA {
  ULONG  ulIdentifier;
  PTRDIFF  dpFontSig;
  ULONG  cig;
  PTRDIFF  dpDesignVector;
  PTRDIFF  dpAxesInfoW;
  ULONG  aulReserved[1];
} IFIEXTRA, *PIFIEXTRA;

Members

ulIdentifier
Should be set to zero. This member was used by GDI to identify Type1 fonts on Windows NT 4.0.
dpFontSig
Is the offset in bytes from the beginning of the IFIMETRICS structure to the FONTSIGNATURE structure. The driver should set this member to zero if it does not support multiple character sets.

The character set information in FONTSIGNATURE should be consistent with the information provided in the character sets array to which the dpCharSets member of IFIMETRICS points. The FONTSIGNATURE structure is documented in the Platform SDK documentation.

cig
Is the number of distinct glyphs in a font that supports glyph indices. The font's glyph handles are contiguous values that range from 0 to (cig-1). For OpenType fonts, this value is stored in the numGlyphs value of the maxp table.

Fonts that do not have contiguous glyph handles should set this member to zero. Note that the Platform SDK glyph index APIs will not work for fonts that set this member to zero.

dpDesignVector
Is the offset from the beginning of the IFIMETRICS structure to the DESIGNVECTOR structure for this font. The driver should set dpDesignVector only if this font is a multiple master font. The DESIGNVECTOR structure is described in the Platform SDK documentation.
dpAxesInfoW
Is the offset from the beginning of the IFIMETRICS structure to the AXESINFOW structure for this font. The driver should set dpAxesInfoW only if this font is a multiple master font. The AXESINFOW structure is described in the Platform SDK documentation.
aulReserved
Is reserved and should be ignored by the driver.

Headers

Declared in winddi.h. Include winddi.h.

Comments

When used, this structure lies below the IFIMETRICS structure in memory.

See Also

DrvQueryFont, IFIMETRICS


IFIMETRICS

IFIMETRICS defines information for a given typeface that GDI can understand.

typedef struct _IFIMETRICS {
  ULONG  cjThis;
  ULONG  cjIfiExtra;
  PTRDIFF  dpwszFamilyName;
  PTRDIFF  dpwszStyleName;
  PTRDIFF  dpwszFaceName;
  PTRDIFF  dpwszUniqueName;
  PTRDIFF  dpFontSim;
  LONG  lEmbedId;
  LONG  lItalicAngle;
  LONG  lCharBias;
  PTRDIFF  dpCharSets;
  BYTE  jWinCharSet;
  BYTE  jWinPitchAndFamily;
  USHORT  usWinWeight;
  ULONG  flInfo;
  USHORT  fsSelection;
  USHORT  fsType;
  FWORD  fwdUnitsPerEm;
  FWORD  fwdLowestPPEm;
  FWORD  fwdWinAscender;
  FWORD  fwdWinDescender;
  FWORD  fwdMacAscender;
  FWORD  fwdMacDescender;
  FWORD  fwdMacLineGap;
  FWORD  fwdTypoAscender;
  FWORD  fwdTypoDescender;
  FWORD  fwdTypoLineGap;
  FWORD  fwdAveCharWidth;
  FWORD  fwdMaxCharInc;
  FWORD  fwdCapHeight;
  FWORD  fwdXHeight;
  FWORD  fwdSubscriptXSize;
  FWORD  fwdSubscriptYSize;
  FWORD  fwdSubscriptXOffset;
  FWORD  fwdSubscriptYOffset;
  FWORD  fwdSuperscriptXSize;
  FWORD  fwdSuperscriptYSize;
  FWORD  fwdSuperscriptXOffset;
  FWORD  fwdSuperscriptYOffset;
  FWORD  fwdUnderscoreSize;
  FWORD  fwdUnderscorePosition;
  FWORD  fwdStrikeoutSize;
  FWORD  fwdStrikeoutPosition;
  BYTE  chFirstChar;
  BYTE  chLastChar;
  BYTE  chDefaultChar;
  BYTE  chBreakChar;
  WCHAR  wcFirstChar;
  WCHAR  wcLastChar;
  WCHAR  wcDefaultChar;
  WCHAR  wcBreakChar;
  POINTL  ptlBaseline;
  POINTL  ptlAspect;
  POINTL  ptlCaret;
  RECTL  rclFontBox;
  BYTE  achVendId[4];
  ULONG  cKerningPairs;
  ULONG  ulPanoseCulture;
  PANOSE  panose;
#if defined(_WIN64)
  PVOID  Align;
#endif
} IFIMETRICS, *PIFIMETRICS;

Members

cjThis
Specifies the size in bytes of this structure. The specified size includes any Unicode strings appended to the end of this structure, but does not include the optional IFIEXTRA structure.
cjIfiExtra
Specifies the size in bytes of the IFIEXTRA structure that follows this IFIMETRICS structure. A value of zero indicates that no IFIEXTRA structure is present.
dpwszFamilyName
Specifies the offset in bytes to a zero-terminated Unicode string containing the family name of the font (for example, "Times Roman"). Generally, this string immediately follows the IFIMETRICS structure. This string should be the same as the name recorded in the lfFaceName member of the Win32 LOGFONT structure.
dpwszStyleName
Specifies the offset in bytes to a zero-terminated Unicode string describing the style of the font (for example, "Bold").
dpwszFaceName
Specifies the offset in bytes to a zero-terminated Unicode string representing the unique and complete name of the font. The name contains the family and subfamily names of the font (for example, "Times New Roman Bold").
dpwszUniqueName
Specifies the offset in bytes to a zero-terminated Unicode string representing the unique identifier of the font (for example, "Monotype:Times New Roman:1990").
dpFontSim
Specifies the offset in bytes from the beginning of this IFIMETRICS structure to a FONTSIM structure that describes the simulations that the font supports. The driver should set this member to a non-zero value only if the font supports bold, italic, or bold italic simulations; otherwise, the driver should set this to zero.

Note that if a font is italic by design, the driver should not indicate font support for italic simulation although it can indicate font support for bold italic simulation. Similarly, the driver should not indicate font support for bold simulation if the font is bold by design, but can indicate font support for bold italic simulation. If the font is both bold and italic by design, it should not support any simulations.

The offsets in the FONTSIM structure are relative to the base of the FONTSIM structure.

lEmbedId
Is the Embedding ID of the font. This value is TrueType-specific and should be set to zero by all other font providers.
lItalicAngle
Specifies the italic angle of the font. This value is TrueType-specific and should be set to zero by all other font providers.
lCharBias
Specifies the character bias. This value is TrueType-specific and should be set to zero by all other font providers.
dpCharSets
Is the offset from the beginning of this IFIMETRICS structure to an array containing a list of all Windows character sets supported by this font. The array is 16 bytes in size and is always terminated with DEFAULT_CHARSET. The first value of the array should identify the Windows character set that has the best and most complete coverage in the font; this value should also be stored in jWinCharSet. For instance, if this is a Japanese font that also supports US ANSI and Cyrillic character sets, then jWinCharSet should be set to SHIFTJIS_CHARSET and the array identified by dpCharSets would contain SHIFTJIS_CHARSET, ANSI_CHARSET, RUSSIAN_CHARSET, DEFAULT_CHARSET.

If this font does not support more than one Windows character set, dpCharSets should be set to zero.

jWinCharSet
Identifies the character set best supported by this font. If the font supports only a single Windows character set, the driver should store the corresponding value in jWinCharSet. The driver should not store DEFAULT_CHARSET in this field. This member can be one of the following values:
Value | Meaning
ANSI_CHARSET | This font supports the Windows ANSI character set.
ARABIC_CHARSET | This font supports the Arabic character set.
BALTIC_CHARSET | This font supports the Baltic character set.
CHINESEBIG5_CHARSET | This font supports the traditional Chinese (Big 5) character set.
EASTEUROPE_CHARSET | This font supports the Eastern European character set.
GB2312_CHARSET | This font supports the simplified (PRC) Chinese character set.
GREEK_CHARSET | This font supports the Greek character set.
HANGEUL_CHARSET | This font supports the Korean (Hangeul) character set.
HEBREW_CHARSET | This font supports the Hebrew character set.
JOHAB_CHARSET | This font supports the Korean (Johab) character set.
OEM_CHARSET | This font supports an OEM-specific character set. The OEM character set is system dependent.
SHIFTJIS_CHARSET | This font supports the Shift-JIS (Japanese Industry Standard) character set.
SYMBOL_CHARSET | This font supports the Windows symbol character set.
RUSSIAN_CHARSET | This font supports the Cyrillic character set.
THAI_CHARSET | This font supports the Thai character set.
TURKISH_CHARSET | This font supports the Turkish character set.
VIETNAMESE_CHARSET | This font supports the Vietnamese character set.

jWinPitchAndFamily
Specifies the pitch of the font. The two low-order bits specify the pitch of the font and can be one of the following values:
Value | Meaning
FIXED_PITCH | For fixed pitch fonts
VARIABLE_PITCH | For variable pitch fonts

Bits 4 through 7 of this member specify the font family and can be one of the following values:
Value | Meaning
FF_DECORATIVE | Novelty fonts, such as Old English.
FF_DONTCARE | Don't care or unknown.
FF_MODERN | Fonts with constant stroke width (fixed-pitch), with or without serifs. Fixed-pitch fonts are usually modern, such as Pica, Elite, and Courier.
FF_ROMAN | Fonts with variable stroke width (proportionally spaced) and with serifs, such as Times Roman, Palatino, and Century Schoolbook.
FF_SCRIPT | Fonts designed to look like handwriting, such as Script and Cursive.
FF_SWISS | Fonts with variable stroke width (proportionally spaced) and without serifs, such as Helvetica and Swiss.

usWinWeight
Specifies the weight of the font in the range 0 to 1000 (for example, 400 is normal and 700 is bold). This value is provided to the application in the lfWeight member of the Win32 LOGFONT structure.
flInfo
Specifies additional information about the font. This field can be a combination of the following flag values:
Value Meaning
FM_INFO_1BPP
Indicates that a glyph bitmap has a color depth of one bit per pixel. For Windows NT 3.1, the first version of Windows NT, this flag must be set.
FM_INFO_4BPP
Indicates that a glyph bitmap has a color depth of four bits per pixel. The driver should set this if the font supports antialiased glyph bitmaps with 16 levels of gray.
FM_INFO_8BPP
Indicates that a glyph bitmap has a color depth of eight bits per pixel. The current version of GDI will ignore this setting as it does not support color fonts.
FM_INFO_16BPP
Indicates that a glyph bitmap has a color depth of 16 bits per pixel. The current version of GDI will ignore this setting as it does not support color fonts.
FM_INFO_24BPP
Indicates that a glyph bitmap has a color depth of 24 bits per pixel. The current version of GDI will ignore this setting as it does not support color fonts.
FM_INFO_32BPP
Indicates that a glyph bitmap has a color depth of 32 bits per pixel. The current version of GDI will ignore this setting as it does not support color fonts.
FM_INFO_90DEGREE_ROTATIONS
Indicates that the font can be realized in 90 degree rotations of the original notional shape. GDI requests the rotation of a font by including the rotation in the notional to device transformation passed to the driver when creating the font. This member has meaning only when the FM_INFO_ARB_XFORMS flag has not been set.
FM_INFO_ANISOTROPIC_SCALING_ONLY
Indicates that the font supports only arbitrary anisotropic scaling. That is, transforms are equivalent to a diagonal matrix multiplied by a positive real number. If this flag is set, then the FM_INFO_ARB_XFORMS and the FM_INFO_ISOTROPIC_SCALING_ONLY flags cannot be set. If the FM_INFO_90DEGREE_ROTATIONS flag is also set, the font supports transformations that are a combination of a simple anisotropic scaling followed by a rotation by a multiple of 90 degrees.
FM_INFO_ARB_XFORMS
Indicates that a font can be realized under a continuous range of two dimensional linear transformations.
FM_INFO_CONSTANT_WIDTH
Indicates that all glyphs of the font under all realizations have the same value of character increment. If this flag is set, the FM_INFO_OPTICALLY_FIXED_PITCH flag must also be set.
FM_INFO_DBCS_FIXED_PITCH
Indicates that double-byte characters for this font are fixed pitch. Nothing is implied about single byte characters. This flag is meaningful only for fonts that support a double-byte character set (DBCS), such as shift JIS. Fonts that do not support a DBCS should not set this flag.
FM_INFO_DO_NOT_ENUMERATE
Indicates that this font will not be enumerated by the Win32 EnumFontFamiliesEx, EnumFontFamilies or EnumFonts routines. Moreover, the string returned to a Win32 application call to GetTextFace will be retrieved from the string dpwszUniqueName. This flag allows the font provider to associate more than one IFIMETRICS structure with one of its fonts.
FM_INFO_DSIG
Indicates that a font is compliant with the Unicode standard.
FM_INFO_FAMILY_EQUIV
Indicates that the dpwszFamilyName offset in IFIMETRICS is actually the offset to a list of equivalent family names or aliases. The first name is the base or real name; the subsequent names are equivalents or aliases. Each name in the list is zero-terminated; the list is terminated by two zeros.
<base name> <0> <alias 1> <0>...<alias n>
    <0> <0>

The based names are used only for mapping; they are not enumerated.
FM_INFO_IGNORE_TC_RA_ABLE
Indicates that, for this font, the TC_RA_ABLE flag is ignored.
FM_INFO_INTEGER_WIDTH
Indicates that all glyphs have nonfractional advance widths. Bitmap fonts usually set this flag.
FM_INFO_INTEGRAL_SCALING
Indicates that the font can be scaled by an integral amount in both the x and y directions. If this flag is set, then the driver must be able to render glyphs in the case where the notional to device transformation is scaled by integral amounts in the x and y directions. GDI requests the integral scaling of a font by including the axial scalings in the notional to device transformation passed to the driver when creating the font. This flag is meaningful only when the FM_INFO_ARB_XFORMS flag has not been set.
FM_INFO_ISOTROPIC_SCALING_ONLY
Indicates that the font supports arbitrary isotropic scaling only. That is, transforms are equivalent to the identity matrix multiplied by a positive real number. If this flag is set, then neither the FM_INFO_ARB_XFORMS nor the FM_INFO_ANISOTROPIC_SCALING_ONLY flags can be set. If the FM_INFO_90DEGREE_ROTATIONS flag is set, the font supports transformations equivalent to an isotropic scaling followed by a rotation by a multiple of 90 degrees.
FM_INFO_OPTICALLY_FIXED_PITCH
Indicates that this font is considered typographically as fixed pitch. This is an optical quality of the font and does not necessarily indicate that all the glyphs of the font have the same character increment.
FM_INFO_NONNEGATIVE_AC
Indicates that all glyphs of this font have non-negative a and c spacing. That is, the glyph black box never extends outside the region bordered by the character origin and the character concatenation point.
FM_INFO_NOT_CONTIGUOUS
Indicates that the supported character set is not contiguous.
FM_INFO_RETURNS_BITMAPS
Indicates that the font contains a valid digital signature.
FM_INFO_RETURNS_OUTLINES
Indicates that for any glyph supported by the driver, GDI can request a PATHOBJ structure that describes the outline of that glyph. If possible, when the outline is filled using GDI's path filling conventions, the resulting bitmap should be identical to the bitmap returned by the driver. The FM_INFO_RETURNS_OUTLINES and FM_INFO_RETURNS_STOKES flags cannot be set concurrently.
FM_INFO_RETURNS_STROKES
Indicates that for any glyph supported by the drivers, GDI can request a PATHOBJ structure that describes the spline of the glyph. This path cannot be filled but can be stroked to give a representation of the glyph. The FM_INFO_RETURNS_OUTLINES and FM_INFO_RETURNS_STOKES flags cannot be set concurrently.
FM_INFO_RIGHT_HANDED
Indicates that the ascent direction of the font is 90 degrees counterclockwise from the baseline direction. The ascent direction is the direction along which height is measured and is always perpendicular to the baseline direction.
FM_INFO_TECH_BITMAP
Indicates that the font is a bitmap font.
FM_INFO_TECH_CFF
Indicates that the font is a Pscript OpenType font that contains a Compact Font Format (CFF) table.
FM_INFO_TECH_MM
Indicates that this is a Multiple Master (MM) font.
FM_INFO_TECH_OUTLINE_NOT_TRUETYPE
Indicates that the font is based on a scalable font technology that uses outline paths, but is not based on TrueType. This flag does not specify whether the paths returned for this font should be filled or stroked; the consumer should examine the FM_INFO_RETURNS_STROKES and FM_INFO_RETURNS_OUTLINES flags for this information.
FM_INFO_TECH_STROKE
Indicates that the font is based on a stroked font technology. This flag does not specify whether the paths returned for this font should be filled or stroked; the consumer should examine the FM_INFO_RETURNS_STROKES and FM_INFO_RETURNS_OUTLINES flags for this information.
FM_INFO_TECH_TRUETYPE
Indicates that the font is a TrueType font.
FM_INFO_TECH_TYPE1
Indicates that this font is a PostScript screen font (either Type1 or OpenType PostScript).

fsSelection
Specifies a combination of the following flags:
Value | Meaning
FM_SEL_BOLD | Set if the characters of the font are bold.
FM_SEL_ITALIC | Set if the characters of the font are italic.
FM_SEL_NEGATIVE | Set if the characters of the font have the foreground and background reversed.
FM_SEL_OUTLINED | Set if the characters of the font are hollow.
FM_SEL_REGULAR | Set if the characters of the font are normal weight.
FM_SEL_STRIKEOUT | Set if the characters of the font are struck out by default; otherwise strikeouts must be simulated.
FM_SEL_UNDERSCORE | Set if all the characters of the font are underscored by default; otherwise underscoring must be simulated.

fsType
This is a TrueType-specific bit field indicating certain properties for the font, such as font embedding and licensing rights for the font. Embeddable fonts can be stored in a document. When a document with embedded fonts is opened on a system that does not have the font installed (the remote system), the embedded font can be loaded for temporary (and in some cases permanent) use on that system by an embedding-aware application. Embedding licensing rights are granted by the font vendor. The following flags can be set:
Value | Meaning
FM_EDITABLE_EMBED | Set if the font can be embedded and temporarily loaded on other systems. Documents containing Editable fonts can be opened for reading and writing.
FM_READONLY_EMBED | Set if read-write embedding is not permitted; only "preview and print" encapsulation is allowed. When this bit is set, the font can be embedded and temporarily loaded on the remote system. Documents containing "preview and print" fonts must be opened "read-only;" no edits can be applied to the document.
FM_TYPE_LICENSED
FM_NO_EMBEDDING 		Set if the font is a Restricted License font. When only this bit is set, this font must not be modified, embedded, or exchanged in any manner without first obtaining permission of the legal owner. For Restricted License embedding to take effect, it must be the only level of embedding selected.

Fonts with the FM_READONLY_EMBED bit set indicate that they can be embedded within documents but must only be installed temporarily on the remote system. Any document that includes an FM_READONLY_EMBED font must be opened "read-only." That is, the application can let the user view and/or print the document, but not edit it.

Fonts with the FM_EDITABLE_EMBED bit set indicate that they can be embedded in documents, but must only be installed temporarily on the remote system. In contrast to FM_READONLY_EMBED fonts, documents containing Editable fonts can be opened "read-write;" editing is permitted, and changes can be saved.

Fonts with no fsType bits set indicate that they can be embedded and permanently installed on the remote system by an application. The user of the remote system acquires the identical rights, obligations, and licenses for that font as the original purchaser of the font, and is subject to the same end-user license agreement, copyright, design patent, and/or trademark as was the original purchaser.

Applications that implement support for font embedding, either through use of the Font Embedding DLL or through other means, must not embed fonts that are not licensed to permit embedding. Further, applications loading embedded fonts for temporary use must delete the fonts when the document containing the embedded font is closed.

If multiple embedding bits are set, the least restrictive license granted takes precedence. For example, if bits 1 and 3 are set, bit 3 takes precedence over bit 1and the font can be embedded with Editable rights. For compatibility purposes, most vendors granting Editable embedding rights also set the Preview & Print bit (0x000C). This permits an application that only supports Preview & Print embedding to detect that font embedding is allowed.

fwdUnitsPerEm
Specifies the em-height of the font.
fwdLowestPPEm
Specifies the smallest readable size of the font, in pixels. This value is ignored for bitmap fonts.
fwdWinAscender
Specifies the Windows ascender value for the font.
fwdWinDescender
Specifies the Windows descender value for the font.
fwdMacAscender
Specifies the Macintosh ascender value for the font.
fwdMacDescender
Specifies the Macintosh descender value for the font. This number is typically less than zero. It measures the signed displacement from the base line of the lowest descender in the Macintosh character set.
fwdMacLineGap
Specifies the Macintosh line gap for the font. The suggested Macintosh interline spacing is equal to fwdMacLineGap + fwdMacAscender – fwdMacDescender.
fwdTypoAscender
Specifies the typographic ascender value for the font.
fwdTypoDescender
Specifies the typographic descender value for the font. This value specifies the signed displacement of the lowest descender from the baseline.
fwdTypoLineGap
Specifies the typographic line gap for the font.
fwdAveCharWidth
Specifies the arithmetic average of the width of all of the 26 lower case letters 'a' through 'z' of the Latin alphabet and the space character. If any of the 26 lowercase letters are not present, then this member should be set equal to the weighted average of all glyphs in the font.
fwdMaxCharInc
Specifies the maximum character increment of all glyphs in the font.
fwdCapHeight
Specifies the height of the optical line describing the top of the uppercase 'H' in font units (FUnits). This might not be the same as the measured height of the uppercase 'H.' If this information does not exist, fwdCapHeight should be set to zero, which indicates that it is undefined.
fwdXHeight
Specifies the height of the optical line describing the height of the lowercase 'x' in font units. This might not be the same as the measured height of the lowercase 'x.' A value of zero indicates that this member is undefined.
fwdSubscriptXSize
Specifies the suggested character width (the size along the baseline direction) of the subscript font.
fwdSubscriptYSize
Specifies the suggested character height (the size along the ascender direction) of the subscript font.
fwdSubscriptXOffset
Specifies the suggested offset in the baseline direction of the subscript character. The offset is with respect to the character origin of the base character.
fwdSubscriptYOffset
Specifies the suggested offset in the baseline direction of the subscript character. The offset is taken from the character origin of the base character.
fwdSuperscriptXSize
Specifies the suggested character width (the size along the baseline direction) of the superscript font.
fwdSuperscriptYSize
Specifies the suggested character height (the size along the ascender direction) of the superscript font.
fwdSuperscriptXOffset
Specifies the suggested offset in the baseline direction of the superscript character. The offset is taken from the character origin of the base character.
fwdSuperscriptYOffset
Specifies the suggested offset in the baseline direction of the superscript character. The offset is taken from the character origin of the base character.
fwdUnderscoreSize
Specifies the suggested width of the underscore bar, in font units.
fwdUnderscorePosition
Specifies the suggested displacement, in font units, from the base line to the middle of the underscore bar.
fwdStrikeoutSize
Specifies the suggested width of the strike-out bar, in font coordinates.
fwdStrikeoutPosition
Specifies the suggested displacement of the middle of the strikeout bar from the baseline.
chFirstChar
Specifies the lowest supported character in the code page specified in jWinCharSet. This field is provided for Windows 3.1 compatibility.
chLastChar
Specifies the highest supported character in the code page specified in jWinCharSet. This field is provided for Windows 3.1 compatibility.
chDefaultChar
Specifies the default character in the code page specified in jWinCharSet. This field is provided for Windows 3.1 compatibility.
chBreakChar
Specifies the break character in the code page specified in jWinCharSet. This field is provided for Windows 3.1 compatibility.
wcFirstChar
Specifies the supported character with the smallest Unicode character code.
wcLastChar
Specifies the supported character with the largest Unicode character code.
wcDefaultChar
Specifies the character to be substituted when an application requests a character that is not supported by the font.
wcBreakChar
Specifies the code point of the space character or its equivalent.
ptlBaseline
Specifies the intended writing direction of this font. For example, a typical Latin font specifies a value of (1,0).
ptlAspect
Specifies the aspect ratio of the pixel centers for which the bitmap font was designed. This value is used only by bitmap fonts.
ptlCaret
Specifies the direction of the ascender direction of the font. For example, the value for a non-italicized Latin font is (0,1) while an italicized Latin font might specify a value of (2,5).
rclFontBox
Specifies the bounding box of all glyphs in the font in design space.
achVendId
Specifies a four character identifier for the font vendor. Identifiers are documented in the Microsoft TrueType specification.
cKerningPairs
Specifies the number of kerning pairs associated with this font.
ulPanoseCulture
Specifies the manner in which to interpret the panose number. This number should be set to FM_PANOSE_CULTURE_LATIN for Latin-based fonts. See the Platform SDK documentation for information about the PANOSE structure.
panose
Is an array of 10 bytes used to describe the visual characteristics of a given typeface. These characteristics are then used to associate the font with other fonts of similar appearance having different names. See the Platform SDK documentation for information about the PANOSE structure.
Align
This member is defined only if the _WIN64 constant is defined. Its only purpose is to ensure that this structure is aligned correctly under the IA64 architecture.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Additional information for a typeface can optionally be specified in the IFIEXTRA structure.

A driver's DrvQueryFont routine fills out and returns an IFIMETRICS structure to GDI.

The IFIMETRICS structure defines all the information for a typeface that GDI understands. Most of the members are FWORD values, which are signed 16-bit quantities in design space. If the font is a raster font, design space and device space are the same and a font unit is equivalent to the distance between pixels.

The coordinate system in the font/notional space is such that the y coordinate increases in an upward direction and the x coordinate increases to the right.

See Also

DrvQueryFont, IFIEXTRA, PATHOBJ


LINEATTRS

LINEATTRS is used by a driver's line-drawing functions to determine line attributes.

typedef struct _LINEATTRS {
  FLONG  fl;
  ULONG  iJoin;
  ULONG  iEndCap;
  FLOAT_LONG  elWidth;
  FLOATL  eMiterLimit;
  ULONG  cstyle;
  PFLOAT_LONG  pstyle;
  FLOAT_LONG  elStyleState;
} LINEATTRS, *PLINEATTRS;

Members

fl
Option flags. This member can be one of the following values:
Flag | Meaning
LA_ALTERNATE | A special cosmetic line style; every other pixel is on.
LA_GEOMETRIC | A geometric wide line.
LA_STARTGAP | The first entry in the style array specifies the length of the first gap.
LA_STYLED | The line is a styled line.

iJoin
Specifies join styles for geometric wide lines. This member can be one of the following values:
Join Style | Meaning
JOIN_BEVEL | The joining edges of wide lines are beveled.
JOIN_MITER | The joining edges of wide lines are mitered.
JOIN_ROUND | The joining edges of wide lines are rounded.

iEndCap
Specifies the end cap style for a geometric wide line. This member can be one of the following values:
End Cap Style | Meaning
ENDCAP_BUTT | The end cap is
ENDCAP_ROUND | The end cap is rounded.
ENDCAP_SQUARE | The end cap is square.

elWidth
Specifies the width of the line. This width is measured in FLOAT world coordinates for a geometric wide line, but in LONG device coordinates for a cosmetic wide line.
eMiterLimit
Sets the limit as a multiple of the line width that a miter join is allowed to extend from its inside corner to its outer vertex. This prevents very long spikes from occurring when lines of a path meet at very small angles. If the miter limit is exceeded, a bevel join should be used instead.

This member is used only by geometric wide lines.

cstyle
Specifies the number of entries in the style array.
pstyle
Points to the style array. If this member is null, the line style is solid.
elStyleState
A pair of 16-bit values supplied by GDI whenever the driver calls PATHOBJ_bEnumClipLines. These two values, packed into a LONG, specify where in the styling array (at which pixel) to start the first subpath. This value must be updated as part of the output routine if the line is not solid. This member applies to cosmetic lines only. Refer also to Styled Cosmetic Lines for additional information.

Headers

Declared in winddi.h. Include winddi.h.

See Also

DrvStrokeAndFillPath, DrvStrokePath, PATHOBJ_vEnumStartClipLines


PALOBJ

A PALOBJ is a user object that represents an indexed color palette.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This structure is used in conjunction with the PALOBJ_cGetColors service routine.

The PALOBJ structure has no public members.

See Also

PALOBJ_cGetColors


PATHDATA

PATHDATA describes all or part of a subpath.

typedef struct _PATHDATA {
  FLONG  flags;
  ULONG  count;
  POINTFIX  pptfx;
} PATHDATA, *PPATHDATA;

Members

flags
Flags describing the data returned are defined as follows:
Value | Meaning
PD_ALL | This flag is the ORed combination of the other flags in this table. That is, PD_ALL == PD_BEGINSUBPATH | PD_ENDSUBPATH | PD_RESETSTYLE | PD_CLOSEFIGURE | PD_BEZIERS.
PD_BEGINSUBPATH | The first point begins a new subpath. It is not connected to the previous subpath. If this flag is not set, the starting point for the first curve to be drawn from this data is the last point returned in the previous call.
PD_BEZIERS | If set, each set of three control points returned for this call describes a Bezier curve. If clear, each control point describes a line segment. A starting point for either type is either explicit at the beginning of the subpath, or implicit as the endpoint of the previous curve.
PD_CLOSEFIGURE | This bit is only defined if the record ends a subpath. If set, there is an implicit line segment connecting the last point of the subpath with the first point. If such a closed subpath is being stroked, joins are used all around the path, and there are no end caps. If this flag is not set, the subpath is considered open, even if the first and last points happen to coincide. In that case, end caps should be drawn. This flag is not relevant to filling because all subpaths are assumed closed when a path is filled.
PD_ENDSUBPATH | The last point in the array ends the subpath. This subpath can be open or closed depending on the PD_CLOSEFIGURE flag. If there is more data to be returned in the path, the next record begins a new subpath. Note that a single record might begin and end a subpath.
PD_RESETSTYLE | This bit is defined only if this record begins a new subpath. If set, it indicates the style state should be reset to zero at the beginning of the subpath. If not set, the style state is defined by the LINEATTRS structure, or continues from the previous subpath.

count
Specifies the count of POINTFIX structures pointed to by pptfx.
pptfx
Points to an array of POINTFIX structures that define the control points for the curves. These structures must not be modified.

Headers

Declared in winddi.h. Include winddi.h.

Comments

PATHDATA describes all or part of a subpath. For example, a MoveTo call by an application within a path begins a new subpath.

For a description of the POINTFIX structure, see GDI Data Types.

See Also

LINEATTRS, PATHOBJ_bEnum


PATHOBJ

PATHOBJ is used to describe a set of lines and Bezier curves that are to be stroked or filled.

typedef struct _PATHOBJ{
  FLONG  fl;
  ULONG  cCurves;
} PATHOBJ;

Members

fl
A set of hint flags that describe the path. This member can be any of the following values:
PO_ALL_INTEGERS
The vertices of the path have integer coordinates with no fractional parts. This flag is intended primarily as an accelerator so that drivers can use a simpler all-integer fast-path.

In addition, when GDI sets this flag, the driver is permitted to deviate slightly from the standard NT-based operating system GDI Grid Intersection Quantization (GIQ) convention that dictates the rasterization rules for lines. Specifically, when PO_ALL_INTEGERS is set the driver can choose its own rules for which pixel should be lit in the tie-breaker case where a line logically falls exactly between two pixels. Typically, this flag allows drivers to use hardware point-to-point line drawing capabilities even when the hardware has a different tie-breaker rule from that of GIQ.

PO_BEZIERS
The path contains Bezier curves. GDI sets only one of PO_BEZIERS or PO_ELLIPSE in the fl member.
PO_ELLIPSE
The path consists of a single ellipse inscribed in the path's bounding rectangle. GDI sets only one of PO_BEZIERS or PO_ELLIPSE in the fl member.
PO_ENUM_AS_INTEGERS
The driver can request that the vertices returned from PATHOBJ_bEnum be expressed in a 32-bit integer format rather than the standard 28.4 format. The driver makes this request by ORing PO_ENUM_AS_INTEGERS into the fl member of the given PATHOBJ before calling PATHOBJ_bEnum.

The driver can set PO_ENUM_AS_INTEGERS only when GDI has set the PO_ALL_INTEGERS flag. That is, the path must be known to contain only integer coordinates. Note that PO_ENUM_AS_INTEGERS is the only flag that the driver is permitted to modify.

When this flag is set, the driver is permitted to deviate slightly from the standard GIQ convention that dictates the rasterization rules for lines. Specifically, when PO_ENUM_ALL_INTEGERS is set the driver can choose its own rules for which pixel should be lit in the tie-breaker case where a line logically falls exactly between two pixels. Typically, this flag allows drivers to use hardware point-to-point line drawing capabilities even when the hardware has a different tie-breaker rule from that of GIQ.

cCurves
The number of lines and Bezier curves that make up the path.

Headers

Declared in winddi.h. Include winddi.h.

Comments

Functions associated with this structure allow the lines and curves to be enumerated for the driver.

The following GDI service routines are provided for PATHOBJ objects:

PATHOBJ_bCloseFigure
PATHOBJ_bEnum
PATHOBJ_bEnumClipLines
PATHOBJ_bMoveTo
PATHOBJ_bPolyBezierTo
PATHOBJ_bPolyLineTo
PATHOBJ_vEnumstart
PATHOBJ_vEnumStartClipLines
PATHOBJ_vGetBounds

See Also

DrvFillPath, DrvStrokeAndFillPath, DrvStrokePath, EngCreatePath, EngDeletePath


PERBANDINFO

PERBANDINFO is used as input to a printer graphics DLL's DrvQueryPerBandInfo function.

typedef struct _PERBANDINFO {
  BOOL  bRepeatThisBand;
  SIZEL  szlBand;
  ULONG  ulHorzRes;
  ULONG  ulVertRes;
} PERBANDINFO, *PPERBANDINFO;

Members

bRepeatThisBand
If TRUE, GDI redraws the previous band. If FALSE, GDI draws the next band.
szlBand
Specifies the size of the rectangle, in pixels, in which GDI can draw the band.
ulHorzRes
Specifies the horizontal resolution GDI should use when scaling the band.
ulVertRes
Specifies the vertical resolution GDI should use when scaling the band.

Headers

Declared in winddi.h. Include winddi.h.

Comments

If the result of ulHorzRes divided by ulVertRes is smaller than the result obtained by dividing the same members of the GDIINFO structure, the band is rendered smaller by the graphics engine. If the values are the same, no scaling is done. The resultant scale factor obtained from this structure cannot be larger than the one stored in GDIINFO.

When the band is scaled, the graphics engine anchors the smaller band to the upper-left corner of the original band.

See Also

DrvQueryPerBandInfo, GDIINFO


RUN

RUN is used to describe a linear set of pixels that is not clipped by the CLIPLINE structure.

typedef struct _RUN {
  LONG  iStart;
  LONG  iStop;
} RUN, *PRUN;

Members

iStart
Specifies the starting point for a field of pixels to be drawn. The first pixel of the unclipped line is pixel 0.
iStop
Specifies the stopping point for a field of pixels to be drawn.

Headers

Declared in winddi.h. Include winddi.h.

Comments

If the clip region is complex, a single line segment can be broken into many RUNs. The same segment is returned as many times as necessary to list all of its RUNs.

See Also

PATHOBJ_bEnumClipLines


STROBJ

STROBJ class, or text string object, contains an enumeration of glyph handles and positions for the device driver.

class _STROBJ {
  ULONG  cGlyphs;
  FLONG  flAccel;
  ULONG  ulCharInc;
  RECTL  rclBkGround;
  GLYPHPOS  *pgp;
  LPWSTR  pwszOrg;
} STROBJ;

Members

cGlyphs
Specifies the number of glyphs in the STROBJ.
flAccel
Accelerator flags. This member can be any of the following values:
Flag Meaning
SO_BREAK_EXTRA
Fixed-width spacing is added to every break character.
SO_CHARACTER_EXTRA
Fixed-width spacing is added between each pair of consecutive glyphs.
SO_CHAR_INC_EQUAL_BM_BASE
Spacing is determined by bitmap sizes. In this context, bitmap base is defined as cx for horizontal case, cy for vertical case. This bit is set means that every glyph in a font the bitmap (supplied in GLYPHBITS structure by GDI) will have a base equal to the advance width for that glyph. This does not mean that this is a fixed pitch font. (Not used for PATHOBJs.)
SO_DO_NOT_SUBSTITUTE_DEVICE_FONT
A printer driver should not substitute one of its printer fonts for GDI's font choice.
SO_DXDY
Glyphs are to be rendered at random positions.
SO_ESC_NOT_ORIENT
A glyph's orientation is different from the escapement direction. Escapement is the angle the text direction makes with the horizontal. Orientation is the angle between the glyph's baseline and the escapement direction.
SO_FLAG_DEFAULT_PLACEMENT
Default increment vectors are used to position the characters.
SO_GLYPHINDEX_TEXTOUT
pwszOrg points to an array of glyph indexes, rather than a Unicode array.
SO_HORIZONTAL
Text is horizontal; left-to-right or right-to-left, depending on SO_REVERSED. The y coordinate is only supplied for the first glyph in the string.
SO_MAXEXT_EQUAL_BM_SIDE
Bitmaps have the same widths. In this context, bitmap side is defined as cy for horizontal case and cx for vertical case. This flag guarantees that all glyphs in the font will have the same side equal to the sum of ascender and descender. However, this bit indicates more than just a constant side. For horizontal case, this bit also indicates that the vertical distance between the top of the glyph's bitmap and its character origin is equal to the ascender for all glyphs. For vertical case, this bit indicates that the horizontal distance between the glyph's origin and "top" of the glyph's bitmap (which is really right or left, depending on whether you are writing in the direction of positive or negative y axis) is equal to the ascender. In either case, the tops and bottoms of all glyph bitmaps lay on the same line in the direction of writing. (Not used for PATHOBJs.)
SO_REVERSED
Set if horizontal is right-to-left or vertical is bottom-to-top.
SO_VERTICAL
Text is vertical; top-to-bottom or bottom-to-top, depending on SO_REVERSED. The x coordinate is only supplied for the first glyph in the string.
SO_ZERO_BEARINGS
All glyphs have zero A and zero C spacing. This bit guarantees that glyph's black boxes do not overlap.

ulCharInc
Specifies whether the font is a fixed-pitch (monospace) font. If it is, this member is equal to the advance width of glyphs in pels; otherwise, it is zero. When this member is nonzero, GDI supplies a valid coordinate for only the first character in the string. All other character positions must be generated by the driver by successively adding the value of this member along the writing direction.
rclBkGround
Specifies the bounding box for the string.
pgp
Points to the GLYPHPOS array for the whole string. Can be NULL (see the following Comments section).
pwszOrg
Points to the original Unicode string or cGlyphs characters. Contrary to its name, this string is not usually zero-terminated. Also, this string is not always valid, such as in journalling with printer fonts, in which case this parameter will be null.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A driver can call STROBJ_vEnumStart and STROBJ_bEnum to obtain identities and positions of glyphs in the string. If pgp is not NULL, it points to a GLYPHPOS array describing the whole string and only a single call to STROBJ_bEnum is required. If pgp is NULL, STROBJ_bEnum will have to be called repeatedly in a loop to obtain all the string's glyph positions.

See Also

DrvGetGlyphMode , DrvTextOut


SURFACEALIGNMENT

SURFACEALIGNMENT is used by a display driver to describe the alignment restrictions for a surface being allocated by HeapVidMemAllocAligned.

typedef struct _SURFACEALIGNMENT {
  union {
     struct {
         DWORD  dwStartAlignment;
         DWORD  dwPitchAlignment;
         DWORD  dwReserved1;
         DWORD  dwReserved2;
     } Linear;
     struct {
         DWORD  dwXAlignment;
         DWORD  dwYAlignment;
         DWORD  dwReserved1;
         DWORD  dwReserved2;
     } Rectangular;
  };
} SURFACEALIGNMENT;

Members

Linear
Describes the alignment restrictions for linear heap allocations. Its members are:
dwStartAlignment
Is the start alignment multiple in bytes that DirectDraw® should respect when performing linear heap allocations. The driver should set this member to zero if no particular alignment is required.
dwPitchAlignment
Is the end alignment multiple in bytes that DirectDraw should respect when performing linear heap allocations. The driver should set this member to zero if no particular alignment is required.
dwReserved1, dwReserved2
Are reserved for system use and should be ignored by the display driver.
Rectangular
Describes the alignment restrictions for rectangular heap allocations. Its members are:
dwXAlignment
Is the X alignment multiple in bytes that DirectDraw should respect when performing rectangular heap allocations. The driver cannot specify an X alignment that is more fine-grained than one doubleword; DirectDraw will round any X alignment up to the nearest multiple of 4 bytes. The driver should set this member to zero if no particular alignment is required.
dwYAlignment
Is the Y alignment multiple in bytes that DirectDraw should respect when performing rectangular heap allocations. The driver should set this member to zero if no particular alignment is required.
dwReserved1, dwReserved2
Are reserved for system use and should be ignored by the display driver.

Headers

Declared in winddi.h. Include winddi.h.

See Also

HeapVidMemAllocAligned


SURFOBJ

SURFOBJ is the user object for a surface. A device driver usually calls methods on a surface object only when the surface object represents a GDI bitmap or a device-managed surface.

typedef struct _SURFOBJ {
  DHSURF  dhsurf;
  HSURF  hsurf;
  DHPDEV  dhpdev;
  HDEV  hdev;
  SIZEL  sizlBitmap;
  ULONG  cjBits;
  PVOID  pvBits;
  PVOID  pvScan0;
  LONG  lDelta;
  ULONG  iUniq;
  ULONG  iBitmapFormat;
  USHORT  iType;
  USHORT  fjBitmap;
} SURFOBJ;

Members

dhsurf
If the surface is a device managed surface, this member is a device handle identifying the surface. Otherwise, this member is zero.
hsurf
Identifies the surface.
dhpdev
Identifies the device's PDEV that is associated with the specified surface.
hdev
GDI's logical handle for the PDEV associated with this device.
sizlBitmap
Specifies the size of the surface, in pixels.
cjBits
Specifies the size of the buffer pointed to by pvBits.
pvBits
If the surface is a standard format bitmap, this is a pointer to the surface's pixels. For BMF_JPEG or BMF_PNG images, this is a pointer to a buffer containing the image data in a JPEG or PNG format. Otherwise, this member is NULL.
pvScan0
Points to the first scan line of the bitmap. If iBitmapFormat is BMF_JPEG or BMF_PNG, this member is NULL.
lDelta
Specifies the count of bytes required to move down one scan line in the bitmap. If iBitmapFormat is BMF_JPEG or BMF_PNG, this member is NULL.
iUniq
Specifies the current state of the specified surface. Every time the surface changes, this value is incremented. This enables drivers to cache source surfaces.

For a surface that should not be cached, iUniq is set to zero. This value is used in conjunction with the BMF_DONTCACHE flag of fjBitmap.

iBitmapFormat
Specifies the standard format most closely matching this surface. If the iType member specifies a bitmap (STYPE_BITMAP), this member specifies its format. NT-based operating systems support a set of predefined formats, although applications can also send device-specific formats by using SetDIBitsToDevice. Supported predefined formats include the following:
Value | Meaning
BMF_1BPP | 1 bit per pixel.
BMF_4BPP | 4 bits per pixel.
BMF_8BPP | 8 bits per pixel.
BMF_16BPP | 16 bits per pixel.
BMF_24BPP | 24 bits per pixel.
BMF_32BPP | 32 bits per pixel.
BMF_4RLE | 4 bits per pixel, run length encoded.
BMF_8RLE | 8 bits per pixel, run length encoded.
BMF_JPEG | JPEG compressed image.
BMF_PNG | PNG compressed image.

iType
Surface type, which is one of the following:
Type | Definition
STYPE_BITMAP | The surface is a bitmap.
STYPE_DEVBITMAP | The surface is a device format bitmap.
STYPE_DEVICE | The surface is managed by the device.

fjBitmap
If the surface is of type STYPE_BITMAP and is a standard uncompressed format bitmap, the following flags can be set. Otherwise, this member should be ignored.
Value | Meaning
BMF_DONTCACHE | The bitmap should not be cached by the driver because it is a transient bitmap, created by GDI, that the driver will never see again. If this flag is set, the iUniq member of this structure will be set to 0.
BMF_KMSECTION | Is used by GDI only and should be ignored by the driver.
BMF_NOTSYSMEM | The bitmap is not in system memory. EngModifySurface sets this flag when it moves a bitmap into video memory.
BMF_NOZEROINIT | The bitmap was not zero-initialized.
BMF_TOPDOWN | The first scan line represents the top of the bitmap.
BMF_WINDOW_BLT | GDI sets this flag to notify the driver of a window move from one screen location to another.

Headers

Declared in winddi.h. Include winddi.h.

Comments

When information about a particular surface is required by a driver, the driver must access the SURFOBJ. This structure allows quick access to the properties of the surface.

When a SURFOBJ structure represents a GDI bitmap, the driver must be able to determine the format of the bitmap and locate the bitmap bits.

When a SURFOBJ structure represents a device surface, the driver must be able to locate the device handle for the surface.

For more information about supporting JPEG and PNG compressed images, see DEVINFO.


TYPE1_FONT

TYPE1_FONT contains the information necessary for a PostScript driver to access a Type1 font through GDI.

typedef struct _TYPE1_FONT {
  HANDLE  hPFM;
  HANDLE  hPFB;
  ULONG  ulIdentifier;
} TYPE1_FONT;

Members

hPFM
Handle to the PostScript Type1 .pfm file.
hPFB
Handle to the PostScript Type1 .pfb file.
ulIdentifier
An identifier that is generated and used by GDI. The driver stores ulIdentifier in the dpCharSets field of the IFIMETRICS structure.

Headers

Declared in winddi.h. Include winddi.h.

Comments

A PostScript driver can obtain a list of installed Type1 fonts by calling EngGetType1FontList.

Each PostScript Type1 font comes with two separate files: a .pfm file and a .pfb file. The .pfm file contains font metrics information; the .pfb file contains the PostScript Type1 binary font data.

See Also

IFIMETRICS


WCRUN

WCRUN describes a run of HGLYPH structures.

typedef struct _WCRUN {
  WCHAR   wcLow;
  USHORT  cGlyphs;
  HGLYPH  *phg;
} WCRUN, *PWCRUN;

Members

wcLow
The first character in the run.
cGlyphs
A count of characters in the run.
phg
A pointer to an array of HGLYPH structures that correspond to this run. If this member is null, then all characters in this run can be converted to HGLYPH structures by a simple zero extension.

Headers

Declared in winddi.h. Include winddi.h.

Comments

GDI relies on the runs being arranged in increasing order by code points. A binary search is made through the list of runs.

See Also

DrvQueryFontTree


WNDOBJ

WNDOBJ allows the driver to keep track of the position, size, and visible client region changes of a window.

typedef struct _WNDOBJ {
  CLIPOBJ  coClient;
  PVOID  pvConsumer;
  RECTL  rclClient;
  SURFOBJ  *psoOwner;
} WNDOBJ, *PWNDOBJ;

Members

coClient
A CLIPOBJ that describes the region of the window. If iDComplexity is DC_RECT and the left edge in rclBounds is greater than or equal to the right edge, or the top edge is greater than or equal to the bottom edge, the client region is invisible.
pvConsumer
A driver-defined value for identifying this particular WNDOBJ. This value can be set by calling the WNDOBJ_vSetConsumer function.
rclClient
A lower-right exclusive rectangle of the client area of the window in screen coordinates.
psoOwner
Points to the SURFOBJ that was passed to EngCreateWnd when this WNDOBJ was created.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The visible client region can be enumerated by calling the WNDOBJ_cEnumStart and WNDOBJ_bEnum functions.

A driver can associate its own data with a WNDOBJ by calling the WNDOBJ_vSetConsumer function.

As an accelerator, the driver can access public members of the WNDOBJ. These public members are guaranteed to remain unchanged only in the context of the driver callback routine supplied to GDI in the EngCreateWnd function, or the functions where a WNDOBJ is given.

The driver should use the SURFOBJ to which psoOwner points to retrieve driver-specific state relevant to the WNDOBJ, such as the driver's PDEV handle, rather than maintain global variables.

See Also

CLIPOBJ, EngCreateWnd, WNDOBJ_bEnum, WNDOBJ_cEnumStart, WNDOBJ_vSetConsumer, WNDOBJCHANGEPROC


XFORML

XFORML describes an arbitrary, linear two-dimensional transform, such as for geometric wide lines.

typedef struct _XFORML {
  FLOATL  eM11;
  FLOATL  eM12;
  FLOATL  eM21;
  FLOATL  eM22;
  FLOATL  eDx;
  FLOATL  eDy;
} XFORML, *PXFORML;

Members

eM11, eM12, eM21, eM22
Specify the four elements that comprise a 2x2 row-major matrix.
eDx, eDy
Specify the x- and y-translation components of the transform.

Headers

Declared in winddi.h. Include winddi.h.

Comments

GDI associates such a transform with every XFORMOBJ.The driver can download this transform by calling XFORMOBJ_iGetXform.

See Also

XFORMOBJ, XFORMOBJ_iGetXform


XFORMOBJ

XFORMOBJ describes an arbitrary linear two-dimensional transform, such as for geometric wide lines.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The arbitrary two-dimensional transform can be downloaded to the driver. Functions are also provided to apply the transform to driver-supplied data.

There are no public members in the XFORMOBJ structure.

See Also

FONTOBJ_pxoGetXform, XFORMOBJ_bApplyXform, XFORMOBJ_iGetXform


XLATEOBJ

XLATEOBJ is used to translate color indexes from one palette to another.

typedef struct _XLATEOBJ {
  ULONG  iUniq;
  FLONG  flXlate;
  USHORT  iSrcType;
  USHORT  iDstType;
  ULONG  cEntries;
  ULONG  *pulXlate;
} XLATEOBJ;

Members

iUniq
A cache identifier that enables the driver to recognize an XLATEOBJ structure that it has previously cached. If this member is zero, the driver should not cache the XLATEOBJ structure.
flXlate
Flags specifying hints about the translation. This member can be any combination of the following values:
Value | Meaning
XO_DEVICE_ICM | ICM is enabled on the device. The driver should translate color according to the color transform created by DrvIcmCreateColorTransform. The driver should call XLATEOBJ_hGetColorTransform to get the color transform handle. This bit is mutually exclusive from XO_HOST_ICM.
XO_FROM_CMYK | As a result of ICM translation, source indices are translated to the 32-bit CMYK color format. When this bit is set, iSrcType, iDstType, cEntries, and pulXlate should be ignored.
XO_HOST_ICM | ICM is performed by the graphics engine, so the colors in this color table are corrected to the target surface. This bit is set by the GDI as information for the driver: no action is required by the driver. This bit is mutually exclusive from XO_DEVICE_ICM.
XO_TABLE | A table is provided to translate source indices to target indices.
XO_TO_MONO | Source indices are translated to a monochrome format with the special property that all indices map to zero, except for one. A driver can use this to accelerate a block transfer.
XO_TRIVIAL | Source indices are usable as target indices.

iSrcType
Is obsolete. Use XLATEOBJ_cGetPalette to query the source format.
iDstType
Is obsolete. Use XLATEOBJ_cGetPalette to query the destination format.
cEntries
Count of entries in pulXlate. Indexing into pulXlate with a value greater than cEntries results in a memory access violation.
pulXlate
Points to an array of translation entries.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The destination palette always belongs to the destination surface of some drawing operation. The source palette is an application-selected palette or a palette from another surface.

The XLATEOBJ structure is used to translate color indices that refer to the source palette to indices for the destination palette. The resulting index identifies a color that matches the source color as closely as possible.

See Also

XLATEOBJ_piVector


DirectDraw Driver Functions

This section provides reference pages for Microsoft® DirectDraw® driver functions, callbacks, and function-specific structures. Except for the Drv Xxx functions, all other function names are pseudonames to be decided upon by the display driver writer.

DirectDraw Driver Header Files, Sample Code, and References lists the include files containing most of the DirectDraw function prototypes and structure and constant definitions.


DdAddAttachedSurface

DdAddAttachedSurface attaches a surface to another surface.

DWORD
  (APIENTRY *PDD_SURFCB_ADDATTACHEDSURFACE)(
    PDD_ADDATTACHEDSURFACEDATA  lpAddAttachedSurface
    );

Parameters

lpAddAttachedSurface
Points to a DD_ADDATTACHEDSURFACEDATA structure that contains information required for the driver to perform the attachment.

Return Value

DdAddAttachedSurface returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DdAddAttachedSurface can be optionally implemented in DirectDraw drivers.

The driver should update any internal surface state it keeps to reflect the attachment.

DD_ADDATTACHEDSURFACEDATA

The DD_ADDATTACHEDSURFACEDATA structure contains information necessary to attach a surface to another surface.

typedef struct _DD_ADDATTACHEDSURFACEDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  PDD_SURFACE_LOCAL  lpDDSurface;
  PDD_SURFACE_LOCAL  lpSurfAttached;
  HRESULT  ddRVal;
  VOID  *AddAttachedSurface;
} DD_ADDATTACHEDSURFACEDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_GLOBAL structure that represents the driver.
lpDDSurface
Points to a DD_SURFACE_LOCAL structure that represents the surface to which another surface is being attached.
lpSurfAttached
Points to a DD_SURFACE_LOCAL structure that represents the surface to be attached.
ddRVal
Specifies the location in which the driver writes the return value of the DdAddAttachedSurface callback. A return code of DD_OK indicates success.
AddAttachedSurface
Is unused on Windows® 2000 and later.


DdBlt

DdBlt performs a bit-block transfer.

DWORD
  (APIENTRY *PDD_SURFCB_BLT)(
    PDD_BLTDATA  lpBlt
    );

Parameters

lpBlt
Points to the DD_BLTDATA structure that contains the information required for the driver to perform the blit.

Return Value

DdBlt returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DdBlt can be optionally implemented in DirectDraw drivers.

Before performing the bit block transfer, the driver should ensure that a flip involving the destination surface is not in progress. If the destination surface is involved in a flip, the driver should set ddRVal to DDERR_WASSTILLDRAWING and return DDHAL_DRIVER_HANDLED.

The driver should check dwFlags to determine the type of blit operation to perform. The driver should not check for flags that are undocumented.

When performing transparent (color keyed) blts, drivers should ignore any unused pixel bits in their comparisons. (For instance in 32bpp modes, the high byte is typically unused. This byte should not be used in the color key comparison.)

DD_BLTDATA

The DD_BLTDATA structure contains the information relevant to the driver for doing bit block transfers.

typedef struct _DD_BLTDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  PDD_SURFACE_LOCAL  lpDDDestSurface;
  RECTL  rDest;
  PDD_SURFACE_LOCAL  lpDDSrcSurface;
  RECTL  rSrc;
  DWORD  dwFlags;
  DWORD  dwROPFlags;
  DDBLTFX  bltFX;
  HRESULT  ddRVal;
  VOID  *Blt;
  BOOL  IsClipped;
  RECTL  rOrigDest;
  RECTL  rOrigSrc;
  DWORD  dwRectCnt;
  LPRECT  prDestRects;
  DWORD  dwAFlags;            // Windows 2000 and later
  DDRGBA  ddrgbaScaleFactors; // Windows 2000 and later
 } DD_BLTDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_GLOBAL structure that describes the DirectDraw object.
lpDDDestSurface
Points to the DD_SURFACE_LOCAL structure that describes the surface on which to blit.
rDest
Points to a RECTL structure that specifies the upper left and lower right points of a rectangle on the destination surface. These points define the area in which the blit should occur and its position on the destination surface.
lpDDSrcSurface
Points to a DD_SURFACE_LOCAL structure that describes the source surface.
rSrc
Points to a RECTL structure that specifies the upper left and lower right points of a rectangle on the source surface. These points define the area of the source blit data and its position on the source surface.
dwFlags
Is a set of flags that specify the type of blit operation to perform and what associated structure members have valid data that the driver should use. This member is a bit-wise OR of any of the following flags:
Flag | Meaning
DDBLT_AFLAGS | This flag is not yet used as of DirectX® 7.0. Indicates to the driver that the dwAFlags and ddrgbaScaleFactors members in this structure are valid. This flag is always set if the DD_BLTDATA structure is passed to the driver from the DdAlphaBlt callback. Otherwise this flag is zero. If this flag is set, the DDBLT_ROTATIONANGLE and DDBLT_ROP flags will be zero.
DDBLT_ASYNC | Perform this blit asynchronously through the FIFO in the order received. If no room exists in the hardware FIFO, the driver should fail the call and return immediately.
DDBLT_COLORFILL | Use the dwFillColor member in the DDBLTFX structure (defined in the DirectDraw SDK documentation) as the RGB color with which to fill the destination rectangle on the destination surface.
DDBLT_DDFX | Use the dwDDFX member in the DDBLTFX structure (defined in the DirectDraw SDK documentation) to determine the effects to use for the blit.
DDBLT_DDROPS | This flag is reserved for system use and should be ignored by the driver. The driver should also ignore the dwDDROPS member of the DDBLTFX structure.
DDBLT_KEYDESTOVERRIDE | Use the dckDestColorkey member in the DDBLTFX structure (defined in the DirectDraw SDK documentation) as the color key for the destination surface. If an override is not being set, then dckDestColorkey does not contain the color key. The driver should test the surface itself.
DDBLT_KEYSRCOVERRIDE | Use the dckSrcColorkey member in the DDBLTFX structure (defined in the DirectDraw SDK documentation) as the color key for the source surface. If an override is not being set, then dckDestColorkey does not contain the color key. The driver should test the surface itself.
DDBLT_ROP | Use the dwROP member in the DDBLTFX structure (defined in the DirectDraw SDK documentation) for the raster operation for this blit. Currently, the only ROP passed to the driver is SRCCOPY. This ROP is the same as that defined in the Win32® API. See the Platform SDK documentation for details.
DDBLT_ROTATIONANGLE | This flag is not supported on Windows 2000 and later and should be ignored by the driver.
DDBLT_WAIT | Do not return immediately with the DDERR_WASSTILLDRAWING message if the blitter is busy—wait until the blit can be set up or another error occurs.

dwROPFlags
Is unused on Windows 2000 and later and should be ignored by the driver.
bltFX
Specifies a DDBLTFX structure (defined in the DirectDraw SDK documentation) that contains override information for more complex blit operations. For example, the dwFillColor member is used for solid color fills, and the ddckSrcColorKey and ddckDestColorKey members are used for color key blits. The driver can determine which members of bltFX contain valid data by looking at the dwFlags member of the DD_BLTDATA structure. Note that the DDBLTFX_NOTEARING, DDBLTFX_MIRRORLEFTRIGHT, and DDBLTFX_MIRRORUPDOWN flags are unsupported on Windows 2000 and later and will never be passed to the driver.See the Platform SDK documentation for information about the DDBLTFX structure.
ddRVal
Specifies the location in which the driver writes the return value of the DdBlt callback. A return code of DD_OK indicates success.
Blt
Is used by the DirectDraw API and should not be filled in by the driver.
IsClipped
Indicates whether this is a clipped blit. On Windows 2000 and later, this member is always FALSE, indicating that the blit is unclipped.
rOrigDest
Is unused for Windows 2000 and later. Specifies a RECTL structure that defines the unclipped destination rectangle. This member is valid only if IsClipped is TRUE.
rOrigSrc
Is unused for Windows 2000 and later. Specifies a RECTL structure that defines the unclipped source rectangle. This member is valid only if IsClipped is TRUE.
dwRectCnt
Is unused for Windows 2000 and later. Specifies the number of destination rectangles to which prDestRects points. This member is valid only if IsClipped is TRUE.
prDestRects
Is unused for Windows 2000 and later. Points to an array of RECTL structures that describe of destination rectangles. This member is valid only if IsClipped is TRUE.
dwAFlags (Windows 2000 and later only)
Is valid only if the DDBLT_AFLAGS flag is set in the dwFlags member of this structure. This member specifies operation flags used only by the DdAlphaBlt callback (which is not yet implemented as of DirectX 7.0). This member is a bit-wise OR of any of the following flags:
Flag | Meaning
DDABLT_BILINEARFLITER | Enable bilinear filtering of the source pixels during a stretch blit. By default, no filtering is performed. Instead, a nearest-neighbor source pixel is copied to a destination pixel.
DDABLT_NOBLEND | Write the source pixel values to the destination surface without blending. The pixels are converted from the source pixel format to the destination format, but no color keying, alpha blending, or RGBA scaling are performed. In the case of a fill operation (where the lpDDSrcSurface member is NULL), the lpDDRGBAScaleFactors member of this structure points to the source alpha and color components that are to be converted to the destination pixel format and are used to fill the destination. A blit operation is performed if a valid source surface is specified, but in this case, lpDDRGBAScaleFactors must be NULL or the call will fail. This flag cannot be used in conjunction with the DDBLT_KEYSRC and DDBLT_KEYDEST flags.
DDABLT_SRCOVERDEST | If set, this flag indicates that the operation originated from the application's AlphaBlt routine. If the call was originated by the application's Blt method, this flag is not set. Drivers that have a unified DdBlt and DdAlphaBlt callback can use this flag to distinguish between the two application function calls.

ddrgbaScaleFactors (Windows 2000 and later only)
Is valid only if the DDBLT_AFLAGS flag is set in the dwFlags member of this structure. This member is a DDARGB structure (defined in ddraw.h) that contains RGBA-scaling factors. These scaling factors are used to scale the color and alpha components of each source pixel before it is composited to the destination surface.


DdCanCreateSurface

DdCanCreateSurface indicates whether the driver can create a surface of the specified surface description.

DWORD
  (APIENTRY *PDD_CANCREATESURFACE)(
    PDD_CANCREATESURFACEDATA  lpCanCreateSurface
    );

Parameters

lpCanCreateSurface
Points to the DD_CANCREATESURFACEDATA structure containing the information required for the driver to determine whether a surface can be created.

Return Value

DdCanCreateSurface returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DdCanCreateSurface should check the surface description to which lpDDSurfaceDesc points to determine if the driver can support the format and capabilities of the requested surface for the mode that the driver is currently in. The driver should return DD_OK in ddRVal if it supports the surface; otherwise, it should return the DDERR_Xxx error code that best describes why it does not support the surface.

The bIsDifferentPixelFormat member of the following structure is unreliable for z-buffers. Drivers should use bIsDifferentPixelFormat only when they have first checked that the specified surface is not a z-buffer. Drivers can perform this check by determining whether the DDSCAPS_ZBUFFER flag is set in lpDDSurfaceDesc—>ddsCaps.dwCaps.

This function must be implemented in a DirectDraw driver.

DD_CANCREATESURFACEDATA

The DD_CANCREATESURFACEDATA structure contains information necessary to indicate whether a surface can be created.

typedef struct _DD_CANCREATESURFACEDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  PDD_SURFACEDESC  lpDDSurfaceDesc;
  DWORD  bIsDifferentPixelFormat;
  HRESULT  ddRVal;
  VOID  *CanCreateSurface;
} DDHAL_CANCREATESURFACEDATA;

Members

lpDD
Points to the DD_DIRECTDRAW_GLOBAL structure representing the DirectDraw object.
lpDDSurfaceDesc
Points to a DDSURFACEDESC structure that contains a description of the surface to be created. See the Comments section for additional information about this member.
bIsDifferentPixelFormat
Indicates whether the pixel format of the surface to be created differs from that of the primary surface.
ddRVal
Specifies the location in which the driver writes the return value of the DdCanCreateSurface callback. A return code of DD_OK indicates success.
CanCreateSurface
Is used by the DirectDraw API and should not be filled in by the driver.

Comments

The DirectDraw surface description pointed to by the lpDDSurfaceDesc member is actually a DDSURFACEDESC2 structure (rather than a DDSURFACEDESC structure) for DirectDraw 6.0 and later runtimes. Therefore, if you need information at CanCreateSurface time from those members that are in the DDSURFACEDESC2 structure but not in the DDSURFACEDESC structure, you can simply cast the pointer to a DDSURFACEDESC structure to a pointer to a DDSURFACEDESC2 structure prior to use. The following example shows how the value of dwTextureStage (a member of the DDSURFACEDESC2 structure, but not also of the DDSURFACEDESC structure) can be obtained from a pointer to a DDSURFACEDESC structure.

DDSURFACEDESC2* pddsd = (DDSURFACEDESC2*)pccsd->lpDDSurfaceDesc;
DWORD dwStage = pddsd->dwTextureStage;

See Also

DdCreateSurface


DdControlColor

DdControlColor controls the luminance and brightness controls of an overlay surface.

DWORD
  (APIENTRY *PDD_COLORCB_COLORCONTROL)(
    PDD_COLORCONTROLDATA  lpColorControl
    );

Parameters

lpColorControl
Points to a DD_COLORCONTROLDATA structure that contains the color control information for a specified overlay surface.

Return Value

DdControlColor returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DdControlColor can be optionally implemented in a DirectDraw driver.

DD_COLORCONTROLDATA

The DD_COLORCONTROLDATA structure contains the color control information for the specified overlay.

typedef struct _DD_COLORCONTROLDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  PDD_SURFACE_LOCAL  lpDDSurface;
  LPDDCOLORCONTROL  lpColorData;
  DWORD  dwFlags;
  HRESULT  ddRVal;
  VOID  *ColorControl;
} DD_COLORCONTROLDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_GLOBAL structure that describes the DirectDraw API.
lpDDSurface
Points to the DD_SURFACE_LOCAL structure representing the overlay surface.
lpColorData
Points to a DDCOLORCONTROL structure. See the dwFlags member to determine how to use this member.
dwFlags
Is a set of flags that specify the color control flags. This member can be one of the following values:
Flag | Meaning
DDRAWI_GETCOLOR | The driver should return the color controls it supports for the specified overlay in the lpColorData member. The driver should set the appropriate flags in the dwFlags member of the DDCOLORCONTROL structure to indicate in which other members the driver has returned valid data.
DDRAWI_SETCOLOR | The driver should set the current color controls for the specified overlay using the values specified in the lpColorData member.

ddRVal
Specifies the location in which the driver writes the return value of the DdControlColor callback. A return code of DD_OK indicates success.
ColorControl
Is used by the DirectDraw API and should not be filled in by the driver.


DdCreatePalette

DdCreatePalette creates a DirectDrawPalette object for the specified DirectDraw object.

DWORD
  (APIENTRY *PDD_CREATEPALETTE)(
    PDD_CREATEPALETTEDATA  lpCreatePalette
    );

Parameters

lpCreatePalette
Points to a DD_CREATEPALETTEDATA structure that contains the information necessary to create the DirectDrawPalette object.

Return Value

DdCreatePalette returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

DD_CREATEPALETTEDATA

The DD_CREATEPALETTEDATA structure contains information necessary to create a DirectDrawPalette object for this DirectDraw object.

typedef struct _DD_CREATEPALETTEDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  PDD_PALETTE_GLOBAL  lpDDPalette;
  LPPALETTEENTRY  lpColorTable;
  HRESULT  ddRVal;
  VOID  *CreatePalette;
  BOOL  is_excl;
} DD_CREATEPALETTEDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_GLOBAL structure that represents the DirectDraw object.
lpDDPalette
Points to a DD_PALETTE_GLOBAL structure representing the DirectDrawPalette object.
lpColorTable
Points to an array of 2, 4, 16, or 256 PALETTEENTRY structures used to initialize the colors for this DirectDrawPalette object.
ddRVal
Specifies the location in which the driver writes the return value of the DdCreatePalette callback. A return code of DD_OK indicates success.
CreatePalette
Is used by the DirectDraw API and should not be filled in by the driver.
is_excl
Indicates whether this process has exclusive mode.

Headers

Declared in ddrawint.h. Include winddi.h.


DdCreateSurface

DdCreateSurface creates a DirectDraw surface.

DWORD
  (APIENTRY *PDD_CREATESURFACE)(
    PDD_CREATESURFACEDATA  lpCreateSurface
    );

Parameters

lpCreateSurface
Points to a DD_CREATESURFACEDATA structure that contains the information required to create a surface.

Return Value

DdCreateSurface returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

The driver can allocate the surface memory itself or can request that DirectDraw perform the memory management. If the driver performs the allocation, it must do the following:

  • Perform the allocation and write a valid pointer to the memory in the fpVidMem member of the DD_SURFACE_GLOBAL structure.
  • If the surface has a FourCC format, write the pitch in the lPitch member of the DD_SURFACE_GLOBAL and DDSURFACEDESC structures, and update the flags accordingly.

Otherwise, the driver can have DirectDraw allocate the surface by returning one of the following values in fpVidMem:

  • DDHAL_PLEASEALLOC_BLOCKSIZE, requesting that DirectDraw allocate the surface memory from offscreen memory.
  • DDHAL_PLEASEALLOC_USERMEM, requesting that DirectDraw allocate the surface memory from user memory. The driver must also return the size in bytes of the memory region in the dwUserMemSize member of DD_SURFACE_GLOBAL.

For DirectDraw to perform the allocation of a surface with a FourCC format, the driver must also return the pitch and x- and y-block sizes in the lPitch, dwBlockSizeX, and dwBlockSizeY members, respectively, of the DD_SURFACE_GLOBAL structure. The pitch must also be returned in the lPitch member of the DDSURFACEDESC structure. For linear memory, the driver should set dwBlockSizeX to the size in bytes of the memory region and set dwBlockSizeY to 1.

By default, the driver is not notified when a primary surface is created on Windows 2000 and later. However, if the driver supports GUID_NTPrivateDriverCaps and the DDHAL_PRIVATECAP_NOTIFYPRIMARYCREATION flag is set, then the driver will be notified.

DD_CREATESURFACEDATA

The DD_CREATESURFACEDATA structure contains information necessary to create a surface.

typedef struct _DD_CREATESURFACEDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  PDD_SURFACEDESC  lpDDSurfaceDesc;
  PDD_SURFACE_LOCAL  *lplpSList;
  DWORD  dwSCnt;
  HRESULT  ddRVal;
  VOID  *CreateSurface;
} DD_CREATESURFACEDATA;

Members

lpDD
Points to the DD_DIRECTDRAW_GLOBAL structure representing the driver.
lpDDSurfaceDesc
Points to the DDSURFACEDESC structure describing the surface that the driver should create.
lplpSList
Points to a list of DD_SURFACE_LOCAL structures describing the surface objects created by the driver. On Windows 2000 and later, there is usually only one entry in this array. However, if the driver supports the Windows 98/Me-style surface creation techniques using DdGetDriverInfo with GUID_NTPrivateDriverCaps, and the driver sets the DDHAL_PRIVATECAP_ATOMICSURFACECREATION flag, the member will contain a list of surfaces (usually more than one).
dwSCnt
Specifies the number of surfaces in the list to which lplpSList points. This value is usually 1 on Windows 2000 and later. However, if the driver support the Windows 98/Me-style surface creation techniques using DdGetDriverInfo with GUID_NTPrivateDriverCaps, the member will contain the actual number of surfaces in the list (usually more than one).
ddRVal
Specifies the location in which the driver writes the return value of the DdCreateSurface callback. A return code of DD_OK indicates success.
CreateSurface
Is used by the DirectDraw API and should not be filled in by the driver.


DdDestroyPalette

DdDestroyPalette destroys the specified palette.

DWORD
  (APIENTRY *PDD_PALCB_DESTROYPALETTE)(
    PDD_DESTROYPALETTEDATA  lpDestroyPalette
    );

Parameters

lpDestroyPalette
Points to a DD_DESTROYPALETTEDATA structure that contains the information needed to destroy a palette.

Return Value

DdDestroyPalette returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DD_DESTROYPALETTEDATA

The DD_DESTROYPALETTEDATA structure contains information necessary to destroy the specified palette.

typedef struct _DD_DESTROYPALETTEDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  PDD_PALETTE_GLOBAL  lpDDPalette;
  HRESULT  ddRVal;
  VOID  *DestroyPalette;
} DD_DESTROYPALETTEDATA;

Members

lpDD
Points to the DD_DIRECTDRAW_GLOBAL structure representing the DirectDraw object.
lpDDPalette
Points to the DD_PALETTE_GLOBAL structure representing the palette object to be destroyed.
ddRVal
Specifies the location in which the driver writes the return value of the DdDestroyPalette callback. A return code of DD_OK indicates success.
DestroyPalette
Is used by the DirectDraw API and should not be filled in by the driver.


DdDestroySurface

DdDestroySurface destroys a DirectDraw surface.

DWORD
  (APIENTRY *PDD_SURFCB_DESTROYSURFACE)(
    PDD_DESTROYSURFACEDATA  lpDestroySurface
    );

Parameters

lpDestroySurface
Points to a DD_DESTROYSURFACEDATA structure that contains the information needed to destroy a surface.

Return Value

DdDestroySurface returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

If DirectDraw did the memory allocation at surface creation time, DdDestroySurface should return DDHAL_DRIVER_NOTHANDLED.

If the driver is performing the surface memory management itself, DdDestroySurface should free the surface memory and perform any other cleanup, such as freeing private data stored in the dwReserved1 members of the DD_SURFACE_GLOBAL and DD_SURFACE_LOCAL structures.

DD_DESTROYSURFACEDATA

The DD_DESTROYSURFACEDATA structure contains information necessary to destroy the specified surface.

typedef struct _DD_DESTROYSURFACEDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  PDD_SURFACE_LOCAL  lpDDSurface;
  HRESULT  ddRVal;
  VOID  *DestroySurface;
} DD_DESTROYSURFACEDATA;

Members

lpDD
Points to the DD_DIRECTDRAW_GLOBAL structure that describes the DirectDraw API.
lpDDSurface
Points to the DD_SURFACE_LOCAL structure representing the surface object to be destroyed.
ddRVal
Specifies the location in which the driver writes the return value of the DdDestroySurface callback. A return code of DD_OK indicates success.
DestroySurface
Is used by the DirectDraw API and should not be filled in by the driver.


DdFlip

DdFlip causes the surface memory associated with the target surface to become the primary surface, and the current surface to become the nonprimary surface.

DWORD
  (*PDD_SURFCB_FLIP)(
    PDD_FLIPDATA  lpFlip
    );

Parameters

lpFlip
Points to a DD_FLIPDATA structure that contains the information required to perform the flip.

Return Value

DdFlip returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DdFlip allows a display driver to perform multibuffering. DirectDraw drivers must implement this function.

The driver should update its surface pointers so that the next frame will be written to the surface to which the lpSurfTarg member of the following structure points. If a previous flip request is still pending, the driver should fail the call and return DDERR_WASSTILLDRAWING. The driver should ensure that the scan line is not in the vertical blank before performing the flip. DdFlip does not affect the actual display of the video data.

If the driver's hardware supports overlays or textures, DdFlip should make any necessary checks based on the surface type before performing the flip.

DD_FLIPDATA

The DD_FLIPDATA structure contains information needed to do a flip.

typedef struct _DD_FLIPDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  PDD_SURFACE_LOCAL  lpSurfCurr;
  PDD_SURFACE_LOCAL  lpSurfTarg;
  DWORD  dwFlags;
  HRESULT  ddRVal;
  VOID  *Flip;
  PDD_SURFACE_LOCAL  lpSurfCurrLeft;
  PDD_SURFACE_LOCAL  lpSurfTargLeft;
} DD_FLIPDATA;

Members

lpDD
Points to the DD_DIRECTDRAW_GLOBAL structure that describes the DirectDraw API.
lpSurfCurr
Points to the DD_SURFACE_LOCAL structure describing the current surface.
lpSurfTarg
Points to the DD_SURFACE_LOCAL structure describing the target surface; that is, the surface to which the driver should flip.
dwFlags
Is a set of flags that provide the driver with details for the flip. This member can be a bit-wise OR of the following flags:
Flag | Meaning
DDFLIP_EVEN | The surface to which the lpSurfTarg member points contains only the even field of video data. This flag is valid only when the surface is an overlay, and is mutually exclusive of DDFLIP_ODD.
DDFLIP_ODD | The surface to which the lpSurfTarg member points contains only the odd field of video data. This flag is valid only when the surface is an overlay, and is mutually exclusive of DDFLIP_EVEN.
DDFLIP_NOVSYNC | The driver should perform the flip and return immediately. Typically, the current back buffer (which used to be the front buffer) is still visible until the next vertical retrace. Subsequent operations involving the surfaces to which the lpSurfCurr and lpSurfTarg members point will not check to see if the physical flip has finished. This allows an application to perform flips at a higher frequency than the monitor refresh rate, although it might introduce visible artifacts.
DDFLIP_INTERVAL2 | The driver should perform the flip on every other vertical sync. It should return DDERR_WASSTILLDRAWING until the second vertical retrace has occurred. This flag is mutually exclusive of DDFLIP_INTERVAL3 and DDFLIP_INTERVAL4.
DDFLIP_INTERVAL3 | The driver should perform the flip on every third vertical sync. It should return DDERR_WASSTILLDRAWING until the third vertical retrace has occurred. This flag is mutually exclusive of DDFLIP_INTERVAL2 and DDFLIP_INTERVAL4.
DDFLIP_INTERVAL4 | The driver should perform the flip on every fourth vertical sync. It should return DDERR_WASSTILLDRAWING until the fourth vertical retrace has occurred. This flag is mutually exclusive of DDFLIP_INTERVAL2 and DDFLIP_INTERVAL3.

ddRVal
Specifies the location in which the driver writes the return value of the DdFlip callback. A return code of DD_OK indicates success.
Flip
Is used by the DirectDraw API and should not be filled in by the driver.
lpSurfCurrLeft
Points to the DD_SURFACE_LOCAL structure describing the current left surface.
lpSurfTargLeft
Points to the DD_SURFACE_LOCAL structure describing the left target surface to flip to.


DdFlipToGDISurface

DdFlipToGDISurface notifies the driver when DirectDraw is flipping to or from a GDI surface.

DWORD
  (*PDD_FLIPTOGDISURFACE)(
    PDD_FLIPTOGDISURFACEDATA  lpFlipToGDISurface
    );

Parameters

lpFlipToGDISurface
Points to a DD_FLIPTOGDISURFACEDATA structure that contains the notification information.

Return Value

DdFlipToGDISurface returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DdFlipToGDISurface can be implemented in drivers with hardware that needs to be enabled or disabled, depending on whether a GDI surface is being flipped to.

DD_FLIPTOGDISURFACEDATA

The DD_FLIPTOGDISURFACEDATA structure contains the GDI surface notification information.

typedef struct _DD_FLIPTOGDISURFACEDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  DWORD  dwToGDI;
  DWORD  dwReserved;
  HRESULT  ddRVal;
  VOID  *FlipToGDISurface;
} DD_FLIPTOGDISURFACEDATA;

Members

lpDD
Points to the DD_DIRECTDRAW_GLOBAL structure that describes the DirectDraw API.
dwToGDI
Indicates that DirectDraw is flipping to a GDI surface when TRUE; indicates that DirectDraw is flipping from a GDI surface when FALSE.
dwReserved
Is reserved for system use and should be ignored by the driver.
ddRVal
Specifies the location in which the driver writes the return value of the DdFlipToGDISurface callback. A return code of DD_OK indicates success.
FlipToGDISurface
Is used by the DirectDraw API and should not be filled in by the driver.


DdFreeDriverMemory

DdFreeDriverMemory frees offscreen or nonlocal display memory to satisfy a new allocation request.

DWORD
  (APIENTRY *PDD_FREEDRIVERMEMORY)(
    PDD_FREEDRIVERMEMORYDATA  lpfdm
    );

Parameters

lpfdm
Points to a DD_FREEDRIVERMEMORYDATA structure that contains the details of the free request.

Return Value

DdFreeDriverMemory returns one of the following callback codes:

DDHAL_DRIVER_HANDLED when the driver hooks the call.

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

The driver should implement DdFreeDriverMemory when it has DirectDraw manage all offscreen display memory management, including allocations for DrvCreateDeviceBitmap. DirectDraw requests for allocations in offscreen memory should always take precedence over GDI device bitmap allocations.

DirectDraw calls DdFreeDriverMemory when it does not have enough offscreen or nonlocal display memory to allocate a surface requested by an application. The driver should move a GDI device bitmap from offscreen memory into system memory and then immediately return. Bitmap moves can be accomplished by calling EngModifySurface.

DirectDraw will continually call DdFreeDriverMemory until there is enough offscreen memory from which to allocate the requested surface or until the driver returns DDERR_OUTOFMEMORY.

DD_FREEDRIVERMEMORYDATA

The DD_FREEDRIVERMEMORYDATA structure contains the details of the free request.

typedef struct _DD_FREEDRIVERMEMORYDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  PDD_SURFACE_LOCAL  lpDDSurface;
  HRESULT  ddRVal;
  VOID  *FreeDriverMemory;
} DD_FREEDRIVERMEMORYDATA;

Members

lpDD
Points to the DD_DIRECTDRAW_GLOBAL structure that describes the DirectDraw API.
lpDDSurface
Points to the DD_SURFACE_LOCAL structure representing the surface that DirectDraw is attempting to allocate.
ddRVal
Specifies the location in which the driver writes the return value of the DdFreeDriverMemory callback. A return code of DD_OK indicates that the driver succeeded in freeing some space; otherwise, the driver should set this to be DDERR_OUTOFMEMORY.
FreeDriverMemory
Is used by the DirectDraw API and should not be filled in by the driver.

See Also

DrvCreateDeviceBitmap, EngModifySurface, HeapVidMemAllocAligned


DdGetAvailDriverMemory

DdGetAvailDriverMemory queries the amount of free memory in the driver-managed memory heap.

DWORD
  (APIENTRY *PDD_GETAVAILDRIVERMEMORY)(
    PDD_GETAVAILDRIVERMEMORYDATA  lpGetAvailDriverMemory
    );

Parameters

lpGetAvailDriverMemory
Points to a DD_GETAVAILDRIVERMEMORYDATA structure that contains the information required to perform the query.

Return Value

DdGetAvailDriverMemory returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

This function does not need to be implemented if the memory will be managed by DirectDraw.

DdGetAvailDriverMemory determines how much free memory is in the driver's private heaps for the specified surface type. The driver should check the surface capabilities specified in the DDSCaps member of the following structure against the heaps it is maintaining internally, to determine what heap size to query. For example, if DDSCAPS_NONLOCALVIDMEM is set, the driver should return only contributions from the AGP heaps.

The driver indicates its support of DdGetAvailDriverMemory by implementing a response to GUID_MiscellaneousCallbacks in DdGetDriverInfo.

DD_GETAVAILDRIVERMEMORYDATA

The DD_GETAVAILDRIVERMEMORYDATA structure contains the information needed by the driver to query and return the amount of free memory.

typedef struct _DD_GETAVAILDRIVERMEMORYDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  DDSCAPS  DDSCaps;
  DWORD  dwTotal;
  DWORD  dwFree;
  HRESULT  ddRVal;
  VOID  *GetAvailDriverMemory;
} DD_GETAVAILDRIVERMEMORYDATA;

Members

lpDD
Points to the DD_DIRECTDRAW_GLOBAL structure that describes the DirectDraw API.
DDSCaps
Points to a DDSCAPS structure that describes the type of surface for which memory availability is being queried.
dwTotal
Specifies the location in which the driver returns the number of bytes of driver-managed memory that can be used for surfaces of the type described by DDSCaps.
dwFree
Specifies the location in which the driver returns the amount of free memory, in bytes, for the surface type described by DDSCaps.
ddRVal
Specifies the location in which the driver writes the return value of the DdGetAvailDriverMemory callback. A return code of DD_OK indicates success.
GetAvailDriverMemory
Is used by the DirectDraw API and should not be filled in by the driver.


DdGetBltStatus

DdGetBltStatus queries the blit status of the specified surface.

DWORD
  (APIENTRY *PDD_SURFCB_GETBLTSTATUS)(
    PDD_GETBLTSTATUSDATA  lpGetBltStatus
    );

Parameters

lpGetBltStatus
Points to a DD_GETBLTSTATUSDATA structure that contains the information required to perform the blit status query.

Return Value

DdGetBltStatus returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

The blit status that the driver returns is based on the dwFlags member of the structure that lpGetBltStatus points to, as follows:

  • If the flag is DDGBS_CANBLT, the driver should determine whether the surface is currently involved in a flip. If a flip is not in progress and if the hardware is otherwise capable of currently accepting a blit request, the driver should return DD_OK in the ddRVal member of the following structure. If a flip is in progress or if the hardware cannot currently accept another blit request, the driver should set the ddRVal member to DDERR_WASSTILLDRAWING.
  • If the flag is DDGBS_ISBLTDONE, the driver should set ddRVal to DDERR_WASSTILLDRAWING if a blit is currently in progress; otherwise it should return DD_OK.

DD_GETBLTSTATUSDATA

The DD_GETBLTSTATUSDATA structure returns the blit status information.

typedef struct _DD_GETBLTSTATUSDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  PDD_SURFACE_LOCAL  lpDDSurface;
  DWORD  dwFlags;
  HRESULT  ddRVal;
  VOID  *GetBltStatus;
} DD_GETBLTSTATUSDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_GLOBAL structure that describes the DirectDraw API.
lpDDSurface
Points to a DD_SURFACE_LOCAL structure representing the surface whose blit status is being queried. For GetSysmemBltStatus calls, the driver is assured that this member points to a system memory surface.
dwFlags
Specifies the blit status being requested. This member can be one of the following values:
Flag | Meaning
DDGBS_CANBLT | Queries whether the driver can currently perform a blit.
DDGBS_ISBLTDONE | Queries whether the driver has completed the last blit.

ddRVal
Specifies the location in which the driver writes the return value of the DdGetBltStatus callback. A return code of DD_OK indicates success.
GetBltStatus
Is used by the DirectDraw API and should not be filled in by the driver.

See Also

DdBlt


DdGetDriverInfo

DdGetDriverInfo queries the driver for additional information about itself.

DWORD
  (APIENTRY *PDD_GETDRIVERINFO)(
    PDD_GETDRIVERINFODATA  lpGetDriverInfo
    );

Parameters

lpGetDriverInfo
Points to a DD_GETDRIVERINFODATA structure that contains the information required to perform the query.

Return Value

DdGetDriverInfo must return DDHAL_DRIVER_HANDLED.

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

Drivers must implement DdGetDriverInfo to expose driver-supported DirectDraw functionality that is not returnable through DrvEnableDirectDraw.

The driver's DrvGetDirectDrawInfo function returns a pointer to DdGetDriverInfo in the GetDriverInfo member of the DD_HALINFO structure.

To inform DirectDraw that the DdGetDriverInfo member has been set correctly, the driver must also set the DDHALINFO_GETDRIVERINFOSET bit of the dwFlags member in the DD_HALINFO structure.

DdGetDriverInfo should determine whether the driver and its hardware support the callbacks or capabilities requested by the specified GUID. For all GUIDs except GUID_D3DParseUnknownCommandCallback, if the driver does provide the requested support, it should set the following members of the DD_GETDRIVERINFODATA structure:

  • Set dwActualSize to the size in bytes of the callback or capability structure being returned by the driver.
  • In the memory that lpvData points to, initialize the members of the callback or capability structure that corresponds with the requested feature as follows:
    • Set the dwSize member to the size in bytes of the structure.
    • For callbacks, set the function pointers to point to those callbacks implemented by the driver, and set the bits in the dwFlags member to indicate what functions the driver supports.
    • For capabilities, set the appropriate members of the capability structure with values supported by the driver/device.
  • Return DD_OK in ddRVal.

If the driver does not support the feature, it should set ddRVal to DDERR_CURRENTLYNOTAVAIL and return.

DirectDraw informs the driver of the expected amount of data in the dwExpectedSize member of the DD_GETDRIVERINFODATA structure. The driver must not fill in more data than dwExpectedSize bytes.

To avoid problems using DdGetDriverInfo:

  • Do not implement dependencies based on the order in which DdGetDriverInfo is called. For example, avoid hooking driver initialization steps into DdGetDriverInfo.
  • Do not try to ascertain the DirectDraw version based on the calls to DdGetDriverInfo.
  • Do not assume anything about the number of times DirectDraw will call the driver, or the number of times DirectDraw will query a given GUID. It is possible that DirectDraw will probe the driver repeatedly with the same GUID. Implementing assumptions about this in the driver hampers its compatibility with future runtimes.

DD_GETDRIVERINFODATA

The DD_GETDRIVERINFODATA structure is used to pass data to and from the DdGetDriverInfo callback routine.

typedef struct _DD_GETDRIVERINFODATA {
  VOID  *dhpdev;        // Windows 2000 and later
  DWORD  dwSize;
  DWORD  dwFlags;
  GUID  guidInfo;
  DWORD  dwExpectedSize;
  PVOID  lpvData;
  DWORD  dwActualSize;
  HRESULT  ddRVal;
  ULONG_PTR  dwContext; // Windows 98/Me only
} DD_GETDRIVERINFODATA, *PDD_GETDRIVERINFODATA;

Members

dhpdev (Windows 2000 and later only)
Specifies a handle to the driver's PDEV.
dwSize
Specifies the size in bytes of this DD_GETDRIVERINFODATA structure.
dwFlags
Is currently unused and is set to zero.
guidInfo
Specifies the GUID of the DirectX support for which the driver is being queried. In a Windows 2000 and later DirectDraw driver, this member can be one of the following values (in alphabetic order):
GUID | Description
GUID_ColorControlCallbacks | Queries whether the driver supports DdControlColor. If the driver does support it, the driver should initialize and return a DD_COLORCONTROLCALLBACKS structure in the buffer to which lpvData points.
GUID_D3DCallbacks | Queries whether the driver supports any of the functionality specified through the D3DHAL_CALLBACKS structure. If the driver does not provide any of this support, it should initialize and return a D3DHAL_CALLBACKS structure in the buffer to which lpvData points.
GUID_D3DCallbacks2 | Obsolete.
GUID_D3DCallbacks3 | Queries whether the driver supports any of the functionality specified through the D3DHAL_CALLBACKS3 structure. If the driver does provide any of this support, it should initialize and return a D3DHAL_CALLBACKS3 structure in the buffer to which lpvData points.
GUID_D3DCaps | Obsolete.
GUID_D3DExtendedCaps | Queries whether the driver supports any of the Microsoft® Direct3D® functionality specified through the D3DHAL_D3DEXTENDEDCAPS structure. If the driver does provide any of this support, it should initialize and return a D3DHAL_D3DEXTENDEDCAPS structure in the buffer to which lpvData points.
GUID_D3DParseUnknownCommandCallback | Provides the Direct3D portion of the driver with the Direct3D runtime's D3dParseUnknownCommandCallback. The driver's D3dDrawPrimitives2 callback calls D3dParseUnknownCommandCallback to parse commands from the command buffer that the driver doesn't understand.DirectDraw passes a pointer to this function in the buffer to which lpvData points. If the driver supports this aspect of Direct3D, it should store the pointer.
GUID_GetHeapAlignment | Queries whether the driver supports surface alignment requirements on a per-heap basis. If the driver does provide this support, it should initialize and return a DD_GETHEAPALIGNMENTDATA structure in the buffer to which lpvData points.
GUID_KernelCallbacks | Queries whether the driver supports any of the functionality specified through the DD_KERNELCALLBACKS structure. If the driver does provide any of this support, it should initialize and return a DD_KERNELCALLBACKS structure in the buffer to which lpvData points.
GUID_KernelCaps | Queries whether the driver supports any of the kernel-mode capabilities specified through the DDKERNELCAPS structure. If the driver does provide any of this support, it should initialize and return a DDKERNELCAPS structure in the buffer to which lpvData points.
GUID_MiscellaneousCallbacks | Queries whether the driver supports DdGetAvailDriverMemory. If the driver does support it, the driver should initialize and return a DD_MISCELLANEOUSCALLBACKS structure in the buffer to which lpvData points.
GUID_Miscellaneous2Callbacks | Queries whether the driver supports the additional miscellaneous functionality specified in the DD_MISCELLANEOUS2CALLBACKS structure. If the driver does support any of this support, the driver should initialize and return a DD_MISCELLANEOUS2CALLBACKS structure in the buffer to which lpvData points.
GUID_MotionCompCallbacks | Queries whether the driver supports the motion compensation functionality specified through the DD_MOTIONCOMPCALLBACKS structure. If the driver does provide any of this support, is should initialize and return a DD_MOTIONCOMPCALLBACKS structure in the buffer to which lpvData points.
GUID_NonLocalVidMemCaps | Queries whether the driver supports any of the nonlocal display memory capabilities specified through the DD_NONLOCALVIDMEMCAPS structure. If the driver does provide any of this support, it should initialize and return a DD_NONLOCALVIDMEMCAPS structure in the buffer to which lpvData points.
GUID_NTCallbacks | Queries whether the driver supports any of the functionality specified through the DD_NTCALLBACKS structure. If the driver does provide any of this support, it should initialize and return a DD_NTCALLBACKS structure in the buffer to which lpvData points.
GUID_NTPrivateDriverCaps | Queries whether the driver supports the Windows 98/Me-style surface creation techniques specified through the DD_NTPRIVATEDRIVERCAPS structure. If the driver does provide any of this support, it should initialize and return a DD_NTPRIVATEDRIVERCAPS structure in the buffer to which lpvData points.
GUID_UpdateNonLocalHeap | Queries whether the driver supports retrieval of the base addresses of each nonlocal heap in turn. If the driver does provide this support, it should initialize and return a DD_UPDATENONLOCALHEAPDATA structure in the buffer to which lpvData points.
GUID_VideoPortCallbacks | Queries whether the driver supports the video port extensions (VPE). If the driver does support VPE, it should initialize and return a DD_VIDEOPORTCALLBACKS structure in the buffer to which lpvData points.
GUID_VideoPortCaps | Queries whether the driver supports any of the VPE object capabilities specified through the DDVIDEOPORTCAPS structure. If the driver does provide any of this support, it should initialize and return a DDVIDEOPORTCAPS structure in the buffer to which lpvData points.
GUID_ZPixelFormats | Queries the pixel formats supported by the depth buffer. If the driver supports Direct3D, it should allocate and initialize the appropriate members of a DDPIXELFORMAT structure for every z-buffer format that it supports and return these in the buffer to which lpvData points.

dwExpectedSize
Specifies the number of bytes of data that DirectDraw expects the driver to pass back in the buffer to which lpvData points.
lpvData
Points to a DirectDraw-allocated buffer into which the driver copies the requested data. This buffer is typically dwExpectedSize bytes in size. The driver must not write more than dwExpectedSize bytes of data in it.
dwActualSize
Specifies the location in which the driver returns the number of bytes of data it writes in lpvData.
ddRVal
Specifies the driver's return value.
dwContext (Windows 98/Me only)
Specifies context information for the driver. This member is filled in by DirectDraw. On Windows 98/Me, this is the dwReserved3 member of the DDRAWI_DIRECTDRAW_GBL structure.

Comments

The data structure passed to the driver for a DdGetDriverInfo call has minor differences between Windows 98/Me and Windows 2000 and later. On Windows 2000 and later the data structure is called DD_GETDRIVERINFODATA and on Windows 98/Me the data structure is called DDHAL_GETDRIVERINFODATA. Both data structrures include a field for driver specific context information. On Windows 2000 and later, DD_GETDRIVERINFODATA includes a field dhpdev that stores the DHPDEV of the driver being called. On Windows 98/Me, DDHAL_GETDRIVERINFODATA includes a field dwContext that is copied for the driver reserved dwReserved3 field of the DirectDraw global object.

Comments

DD_GETDRIVERSTATEDATA

typedef struct _DD_GETDRIVERSTATEDATA {
    DWORD                        dwFlags;
    union
    {
        PDD_DIRECTDRAW_GLOBAL    lpDD;
        DWORD_PTR                dwhContext;
    };
    LPDWORD                      lpdwStates;
    DWORD                        dwLength;
    HRESULT                      ddRVal;
} DD_GETDRIVERSTATEDATA;

The DD_GETDRIVERSTATEDATA structure contains the driver state information supplied by the driver.

Members

dwFlags
Flags that indicate the data required.
lpDD
Points to a DD_DIRECTDRAW_GLOBAL structure representing the driver.
dwhContext
lpdwStates
Points to the state data that is being supplied by the driver.
dwLength
ddRVal
Is the location in which the driver writes the return value of the DdGetDriverState callback. A return code of DD_OK indicates success.›


DdGetFlipStatus

DdGetFlipStatus determines whether the most recently requested flip on a surface has occurred.

DWORD
  (APIENTRY *PDD_SURFCB_GETFLIPSTATUS)(
    PDD_GETFLIPSTATUSDATA  lpGetFlipStatus
    );

Parameters

lpGetFlipStatus
Points to a DD_GETFLIPSTATUSDATA structure that contains the information required to perform the flip status query.

Return Value

DdGetFlipStatus returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

The driver should report its flip status based on the flag set in the dwFlags member of the structure that lpGetFlipStatus points to as follows:

  • If the flag is DDGFS_CANFLIP, the driver should determine whether the surface is currently involved in a flip. If a flip or a blit is not in progress and if the hardware is otherwise capable of currently accepting a flip request, the driver should return DD_OK in ddRVal. If a flip is in progress or if the hardware cannot currently accept a flip request, the driver should set ddRVal to DDERR_WASSTILLDRAWING.
  • If the flag is DDGFS_ISFLIPDONE, the driver should set ddRVal to DDERR_WASSTILLDRAWING if a flip is currently in progress; otherwise it should return DD_OK.

DD_GETFLIPSTATUSDATA

The DD_GETFLIPSTATUSDATA structure returns the flip status information.

typedef struct _DD_GETFLIPSTATUSDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  PDD_SURFACE_LOCAL  lpDDSurface;
  DWORD  dwFlags;
  HRESULT  ddRVal;
  VOID  *GetFlipStatus;
} DD_GETFLIPSTATUSDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_GLOBAL structure representing the driver.
lpDDSurface
Points to a DD_SURFACE_LOCAL structure that describes the surface whose flip status is being queried.
dwFlags
Specifies the flip status being requested. This member can be one of the following values:
Flag | Meaning
DDGFS_CANFLIP | Queries whether the driver can currently perform a flip.
DDGFS_ISFLIPDONE | Queries whether the driver has finished the last flip.

ddRVal
Specifies the location in which the driver writes the return value of the DdGetFlipStatus callback. A return code of DD_OK indicates success.
GetFlipStatus
Is used by the DirectDraw API and should not be filled in by the driver.


DdGetScanLine

DdGetScanLine returns the number of the current physical scan line.

DWORD
  (APIENTRY *PDD_GETSCANLINE)(
    PDD_GETSCANLINEDATA  pGetScanLine
    );

Parameters

pGetScanLine
Points to a DD_GETSCANLINEDATA structure in which the driver returns the number of the current scan line.

Return Value

DdGetScanLine returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

If the monitor is not in vertical blank, the driver should write the scan line value in the dwScanLine member of the following structure. The number must be in the range [0, n], where scan line 0 is the first visible scan line and scan line n is the last visible scan line on the screen. The driver should then set DD_OK in ddRVal and return DDHAL_DRIVER_HANDLED.

The scan line is indeterminate if a vertical blank is in progress. In this situation, the driver should set ddRVal to DDERR_VERTICALBLANKINPROGRESS and return DDHAL_DRIVER_HANDLED.

DD_GETSCANLINEDATA

The DD_GETSCANLINEDATA structure contains the members required to query and return the number of the current scan line.

typedef struct _DD_GETSCANLINEDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  DWORD  dwScanLine;
  HRESULT  ddRVal;
  VOID  *GetScanLine;
} DD_GETSCANLINEDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_GLOBAL structure that represents the driver.
dwScanLine
Specifies the location in which the driver returns the number of the current scan line. See the Comments section for more information.
ddRVal
Specifies the location in which the driver writes the return value of the DdGetScanLine callback. A return code of DD_OK indicates success.
GetScanLine
Is used by the DirectDraw API and should not be filled in by the driver.

Comments

The returned scan line value in dwScanLine must be greater than or equal to 0 and less than N, where N is the sum of the number of visible scan lines and the number of scan lines that occur during vblank. For example, with a display operating at a resolution of 640x480, that has 12 scan lines during vblank, the value returned to GetScanLine could range from 0 to 491.


DdLock

DdLock locks a specified area of surface memory and provides a valid pointer to a block of memory associated with a surface.

DWORD
  (APIENTRY *PDD_SURFCB_LOCK)(
    PDD_LOCKDATA  lpLock
    );

Parameters

lpLock
Points to a DD_LOCKDATA structure that contains the information required to perform the lockdown.

Return Value

DdLock returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DdLock should set the ddRVal member of the following structure to DDERR_WASSTILLDRAWING and return DDHAL_DRIVER_HANDLED if a blit or flip is in progress.

Unless otherwise specified by the dwFlags member of the following structure, the driver can return a memory pointer to the top of the surface in lpSurfData, also a member of the following structure. If the driver needs to calculate its own address for the surface, it can rely on the pointer passed in the fpProcess member of the following structure as being a per-process pointer to the user-mode mapping of its DirectDraw-accessible frame buffer.

A lock does not provide exclusive access to the requested memory block; that is, multiple threads can lock the same surface at the same time. It is the application's responsibility to synchronize access to the memory block whose pointer is being obtained.

A driver running on an NT-based operating system should not return a pointer to system memory from its DdLock function unless that driver's DdCreateSurface function previously allocated such memory with the PLEASE_ALLOC_USERMEM flag. If PLEASE_ALLOC_USERMEM was not used, applications could receive errors whenever they attempted to access such memory. See NT Kernel's Implementation of DDLOCK_NOSYSLOCK for more information.

NT Kernel's Implementation of DDLOCK_NOSYSLOCK

Applications can use DirectDraw's and Direct3D's Application Programming Interfaces (API) to obtain long-duration locks on video memory resources. Such locks are called "NOSYSLOCK" locks. These locks operate differently than typical video-memory locks as described in the following paragraphs.

After the DirectDraw runtime calls a driver's DdLock function with the DDLOCK_NOSYSLOCK flag specified in the dwFlags member of DD_LOCKDATA, the runtime examines the pointer to the surface contents returned by the driver. Instead of passing the driver-returned pointer directly to an application, the runtime creates a second user-mode mapping of video memory (both local and non-local) and calculates the equivalent virtual address within that mapping. This virtual address is known as the alias pointer to the memory lock. The runtime passes this alias-lock pointer to the application. The application uses this alias-lock pointer to read and write directly to video memory. Neither the application nor the driver is aware that it uses a different locked-memory pointer.

Later, at mode-switch time, the DirectDraw runtime notes any outstanding alias-lock pointers. Instead of waiting for the alias-lock pointers to complete—as it would for a typical video-memory lock—the runtime remaps the user-mode mapping of video memory and allows the mode switch to continue. The runtime remaps the user-mode mappings to a single dummy page; the application continues to read and write to that dummy page, otherwise unaware of any changes. The runtime must then clean up alias-lock pointers by calling the driver's DdUnlock function. The runtime can clean up alias-lock pointers because the application is no longer writing into video memory. Because this clean up occurs at mode-switch time, the next step in the sequence is to lose surfaces, which means to destroy the driver's per-surface objects. In other words, the runtime calls the driver's DdDestroySurface function for all surfaces, including surfaces that the application continues to consider as locked. In fact, the application continues to read and write to a dummy page of system memory.

This whole process only works if the memory pointer returned by DdLock is some mapping of video memory. This video-memory mapping can be either the user-mode mapping of non-local video memory performed by the DirectDraw kernel-mode runtime or the mapping provided by the driver's DdMapMemory function. If the memory pointer cannot be attributed to one of these mappings, the runtime does not remap the lock. The mode switch continues, which means that the driver's surface object is unlocked and destroyed through calls to the driver's DdUnlock and DdDestroySurface functions respectively. The driver then typically releases any system memory that the driver allocated at lock time. Because the application is still writing to this memory, an access violation occurs.

Consequently, a driver should not attempt to return system memory pointers from its DdLock function unless that driver's DdCreateSurface function previously allocated such memory with the PLEASE_ALLOC_USERMEM flag. The DirectDraw runtime owns memory allocated in this manner and can defer release of this memory until the application unlocks the memory. Therefore, the driver's DdLock function can return pointers to memory allocated in this manner without risk of crashing the application.

DD_LOCKDATA

The DD_LOCKDATA structure contains information necessary to do a lock as defined by DirectDraw's parameter structures.

typedef struct _DD_LOCKDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  PDD_SURFACE_LOCAL  lpDDSurface;
  DWORD  bHasRect;
  RECTL  rArea;
  LPVOID  lpSurfData;
  HRESULT  ddRVal;
  VOID  *Lock;
  DWORD  dwFlags;
  FLATPTR  fpProcess; // Windows 2000 and later
} DD_LOCKDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_GLOBAL structure that describes the DirectDraw API.
lpDDSurface
Points to a DD_SURFACE_LOCAL structure that describes the surface associated with the memory region to be locked down.
bHasRect
Specifies whether the area in rArea is valid.
rArea
Specifies a RECTL structure that defines the area on the surface to lock down.
lpSurfData
Specifies the location in which the driver can return a pointer to the memory region that it locked down.
ddRVal
Specifies the location in which the driver writes the return value of the DdLock callback. A return code of DD_OK indicates success.
Lock
Is used by the DirectDraw API and should not be filled in by the driver.
dwFlags
Specifies a bitmask that tells the driver how to perform the memory lockdown. This member is a bitwise-OR of any of the following values:
Flag | Meaning
DDLOCK_DISCARDCONTENTS No assumptions will be made about the contents of the surface or vertex buffer during this lock. This enables two things:
1. Direct3D or the driver may provide an alternative memory area as the vertex buffer. This is useful when one plans to clear the contents of the vertex buffer and fill in new data.
2. Drivers sometimes store surface data in a reordered format. When the application locks the surface, the driver is forced to undo this surface data reordering before allowing the application to see the surface contents.

This flag is a hint to the driver that it can skip the un-reordering process since the application plans to overwrite every single pixel in the surface or locked rectangle (and so erase any un-re-ordered pixels anyway). Applications should always set this flag when they intend to overwrite the entire surface or locked rectangle.
DDLOCK_DONOTWAIT | On IDirectDrawSurface7 and higher interfaces, the default is DDLOCK_WAIT. If you wish to override the default and use time when the accelerator is busy (as denoted by the DDERR_WASSTILLDRAWING return code) then use this flag.
DDLOCK_EVENT | Set if an event handle is being passed to Lock, which triggers the event when it can return the surface memory pointer requested.
DDLOCK_NOOVERWRITE | Used only with Direct3D vertex buffer locks. Indicates that no vertices that were referred to in IDirect3DDevice7::DrawPrimitiveVB and IDirect3DDevice7::DrawIndexedPrimitiveVB calls (described in the Direct3D SDK documentation) since the start of the frame (or the last lock without this flag) will be modified during the lock. This can be useful when one is only appending data to the vertex buffer.
DDLOCK_NOSYSLOCK Indicates that a system-wide lock should not be taken when this surface is locked. This has several advantages when locking video memory surfaces, such as cursor responsiveness, ability to call more Windows functions, and easier debugging. However, an application specifying this flag must comply with a number of conditions documented in the help file.
This flag cannot be specified when locking the primary.
DDLOCK_OKTOSWAP | Same as DDLOCK_DISCARDCONTENTS.
DDLOCK_READONLY | The surface being locked will only be read from. On Windows 2000 and later, this flag is never set.
DDLOCK_SURFACEMEMORYPTR | The driver should return a valid memory pointer to the top of the rectangle specified in rArea. If no rectangle is specified, the driver should return a pointer to the top of the surface.
DDLOCK_WAIT | Set to indicate that Lock should wait until it can obtain a valid memory pointer before returning. If this bit is set, Lock will never return DDERR_WASSTILLDRAWING.
DDLOCK_WRITEONLY | The surface being locked will only be written to. On Windows 2000 and later, this flag is never set.
DDLOCK_HASVOLUMETEXTUREBOXRECT | The driver should return a valid memory pointer to the beginning of the subvolume texture specified in the rectangle (RECTL) in rArea. The driver obtains the front and back coordinates of the subvolume from the top 16 bits of the left and right coordinates (left and right members of RECTL) respectively. The left and right coordinates are constrained to the lower 16 bits. If no rectangle is specified, the driver should return a pointer to the top of the whole volume. This value is available in DirectX 8.1 and later.

fpProcess (Windows 2000 and later only)
Specifies a pointer to a user-mode mapping of the driver's memory. The driver performs this mapping in DdMapMemory.

See Also

DdMapMemory, DdUnlock


DdMapMemory

DdMapMemory maps application-modifiable portions of the frame buffer into the user-mode address space of the specified process, or unmaps memory.

DWORD
  (APIENTRY *PDD_MAPMEMORY)(
    PDD_MAPMEMORYDATA  lpMapMemory
    );

Parameters

lpMapMemory
Points to a DD_MAPMEMORYDATA structure that contains details for the memory mapping or unmapping operation.

Return Value

DdMapMemory returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DdMapMemory is called to perform memory mapping before the first call to DdLock. The handle returned by the driver in fpProcess will be passed to every DdLock call made on the driver.

DdMapMemory is also called to unmap memory after the last DdUnLock call is made.

To prevent driver crashes, the driver must not map any portion of the frame buffer that must not be modified by an application.

DD_MAPMEMORYDATA

The DD_MAPMEMORYDATA structure contains the information necessary to perform the mapping or unmapping.

typedef struct _DD_MAPMEMORYDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  BOOL  bMap;
  HANDLE  hProcess;
  FLATPTR  fpProcess;
  HRESULT  ddRVal;
} DD_MAPMEMORYDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_GLOBAL structure that represents the driver.
bMap
Specifies the memory operation that the driver should perform. A value of TRUE indicates that the driver should map memory; FALSE means that the driver should unmap memory.
hProcess
Specifies a handle to the process whose address space is affected.
fpProcess
Specifies the location in which the driver should return the base address of the process's memory-mapped space when bMap is TRUE. When bMap is FALSE, fpProcess contains the base address of the memory to be unmapped by the driver.
ddRVal
Specifies the location in which the driver writes the return value of the DdMapMemory callback. A return code of DD_OK indicates success.


DdMoCompBeginFrame

DdMoCompBeginFrame starts decoding a new frame.

DWORD
  (APIENTRY *PDD_MOCOMPCB_BEGINFRAME)(
    PDD_BEGINMOCOMPFRAMEDATA  lpFrameData
    );

Parameters

lpFrameData
Points to a DD_BEGINMOCOMPFRAMEDATA structure that contains the information needed to start decoding a new frame.

Return Value

DdMoCompBeginFrame returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DirectDraw drivers that support motion compensation must implement DdMoCompBeginFrame.

DirectDraw ensures that begin and end frames will be properly paired.

DD_BEGINMOCOMPFRAMEDATA

The DDHAL_BEGINMOCOMPFRAMEDATA structure contains the frame information required to start decoding.

typedef struct _DD_BEGINMOCOMPFRAMEDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  PDD_MOTIONCOMP_LOCAL  lpMoComp;
  PDD_SURFACE_LOCAL  lpDestSurface;
  DWORD  dwInputDataSize;
  LPVOID  lpInputData;
  DWORD  dwOutputDataSize;
  LPVOID  lpOutputData;
  HRESULT  ddRVal;
} DD_BEGINMOCOMPFRAMEDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that describes the DirectDraw API.
lpMoComp
Points to a DD_MOTIONCOMP_LOCAL structure that contains a description of the motion compensation being requested.
lpDestSurface
Points to a DD_SURFACE_LOCAL structure representing the destination surface in which to decode this frame.
dwInputDataSize
Indicates the amount of other optional input data in lpInputData required to begin this frame.
lpInputData
Points to an optional input buffer, the contents of which are defined by the GUID. This buffer cannot contain any embedded pointers.
dwOutputDataSize
Indicates the amount of other optional output data in lpOutputData required to begin this frame.
lpOutputData
Points to an optional output buffer, the contents of which are defined by the GUID. This buffer cannot contain any embedded pointers.
ddRVal
Specifies the location in which the driver writes the return value of the DdMoCompBeginFrame callback. A return code of DD_OK indicates success.


DdMoCompCreate

DdMoCompCreate notifies the driver that a software decoder will start using motion compensation with the specified GUID.

DWORD
  (APIENTRY *PDD_MOCOMPCB_CREATE)(
    PDD_CREATEMOCOMPDATA  lpCreateData
    );

Parameters

lpCreateData
Points to a DD_CREATEMOCOMPDATA structure that contains the information required to begin using motion compensation.

Return Value

DdMoCompCreate returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DdMoCompCreate can be optionally implemented in DirectDraw drivers. It is not required for motion compensation support.

DdMoCompCreate also reports the width, height, and format of the output frame. The driver can fail this call if it cannot support motion compensation with these dimensions.

DD_CREATEMOCOMPDATA

The DD_CREATEMOCOMPDATA structure contains the data required to begin using motion compensation.

typedef struct _DD_CREATEMOCOMPDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  PDD_MOTIONCOMP_LOCAL  lpMoComp;
  GUID  *lpGuid;
  DWORD  dwUncompWidth;
  DWORD  dwUncompHeight;
  DDPIXELFORMAT  ddUncompPixelFormat;
  LPVOID  lpData;
  DWORD  dwDataSize;
  HRESULT  ddRVal;
} DD_CREATEMOCOMPDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that describes the DirectDraw API.
lpMoComp
Points to a DD_MOTIONCOMP_LOCAL structure that contains a description of the motion compensation object.
lpGuid
Points to a GUID that describes the motion compensation process being used.
dwUncompWidth
Specifies the width of the uncompressed output frame.
dwUncompHeight
Specifies the height of the uncompressed output frame.
ddUncompPixelFormat
Points to a DDPIXELFORMAT structure that contains the format of the uncompressed output frame.
lpData
Points to an optional data buffer that contains any optional information required by the GUID given in lpGuid. This buffer cannot contain any embedded pointers.
dwDataSize
Indicates the size of the data buffer contained in lpData.
ddRVal
Specifies the location in which the driver writes the return value of the DdMoCompCreate callback. A return code of DD_OK indicates success.


DdMoCompDestroy

DdMoCompDestroy notifies the driver that this motion compensation object will no longer be used. The driver now needs to perform any necessary cleanup.

DWORD
  (APIENTRY *PDD_MOCOMPCB_DESTROY)(
    PDD_DESTROYMOCOMPDATA  lpDestroyData
    );

Parameters

lpDestroyData
Points to a DD_DESTROYMOCOMPDATA structure that contains the information needed to finish motion compensation.

Return Value

DdMoCompDestroy returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DdMoCompDestroy can be optionally implemented in DirectDraw drivers. It is not required for motion compensation support.

DD_DESTROYMOCOMPDATA

The DD_DESTROYMOCOMPDATA structure contains the information required to finish performing motion compensation.

typedef struct _DD_DESTROYMOCOMPDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  PDD_MOTIONCOMP_LOCAL  lpMoComp;
  HRESULT  ddRVal;
} DD_DESTROYMOCOMPDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that describes the DirectDraw API.
lpMoComp
Points to a DD_MOTIONCOMP_LOCAL structure that contains a description of the motion compensation being requested.
ddRVal
Specifies the location in which the driver writes the return value of the DdMoCompDestroy callback. A return code of DD_OK indicates success.


DdMoCompEndFrame

DdMoCompEndFrame completes a decoded frame.

DWORD
  (APIENTRY *PDD_MOCOMPCB_ENDFRAME)(
    PDD_ENDMOCOMPFRAMEDATA  lpFrameData
    );

Parameters

lpFrameData
Points to a DD_ENDMOCOMPFRAMEDATA structure that contains the information needed to complete the decoded frame.

Return Value

DdMoCompEndFrame returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DirectDraw drivers that support motion compensation must implement DdMoCompEndFrame.

DirectDraw ensures that begin and end frames will be properly paired.

DD_ENDMOCOMPFRAMEDATA

The DD_ENDMOCOMPFRAMEDATA structure contains information required to complete a decoded frame.

typedef struct _DD_ENDMOCOMPFRAMEDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  PDD_MOTIONCOMP_LOCAL  lpMoComp;
  LPVOID  lpInputData;
  DWORD  dwInputDataSize;
  HRESULT  ddRVal;
} DD_ENDMOCOMPFRAMEDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that describes the DirectDraw API.
lpMoComp
Points to a DD_MOTIONCOMP_LOCAL structure that contains a description of the motion compensation being requested.
lpInputData
Points to an optional buffer, the contents of which are defined by the GUID. This buffer cannot contain any embedded pointers.
dwInputDataSize
Indicates the amount of data in lpInputData.
ddRVal
Specifies the location in which the driver writes the return value of the DdMoCompEndFrame callback. A return code of DD_OK indicates success.


DdMoCompGetBuffInfo

DDMoCompGetBufferInfo allows the driver to specify how many interim surfaces are required to support the specified GUID, and the size, location, and format of each of these surfaces.

DWORD
  (APIENTRY *PDD_MOCOMPCB_GETCOMPBUFFINFO)(
    PDD_GETMOCOMPCOMPBUFFDATA  lpBufferData
    );

Parameters

lpBufferData
Points to a DD_GETMOCOMPCOMPBUFFDATA structure that contains the compressed buffer information.

Return Value

DdMoCompGetBufferInfo returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DdMoCompGetBufferInfo can be optionally implemented in DirectDraw drivers. This function is required for motion compensation support.

DD_GETMOCOMPCOMPBUFFDATA

The DD_GETMOCOMPCOMPBUFFDATA structure contains the compressed buffer information.

typedef struct _DD_GETMOCOMPCOMPBUFFDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  GUID  *lpGuid;
  DWORD  dwWidth;
  DWORD  dwHeight;
  DDPIXELFORMAT  ddPixelFormat;
  DWORD  dwNumTypesCompBuffs;
  LPDDCOMPBUFFERINFO  lpCompBuffInfo;
  HRESULT  ddRVal;
} DD_GETMOCOMPCOMPBUFFDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that describes the DirectDraw API.
lpGuid
Points to a GUID for which the compressed buffer information is requested.
dwWidth
Indicates the width of the uncompressed output frame.
dwHeight
Indicates the height of the uncompressed output frame.
ddPixelFormat
Points to a DDPIXELFORMAT structure that contains the pixel format of the uncompressed output frame.
dwNumTypesCompBuffs
Indicates how many different types of surfaces the driver requires to perform motion compensation using the requested GUID.
lpCompBuffInfo
Points to a DDCOMPBUFFERINFO structure that contains the driver-supplied information for each type of required surface.
ddRVal
Specifies the location in which the driver writes the return value of the DdMoCompGetBufferInfo callback. A return code of DD_OK indicates success.


DdMoCompGetFormats

DdMoCompGetFormats indicates the uncompressed formats to which the hardware can decode the data.

DWORD
  (APIENTRY *PDD_MOCOMPCB_GETFORMATS)(
    PDD_GETMOCOMPFORMATSDATA  lpGetFormatData
    );

Parameters

lpGetFormatData
Points to a DD_GETMOCOMPFORMATSDATA structure that contains the uncompressed format information for the hardware.

Return Value

DdMoCompGetFormats returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DirectDraw drivers that support motion compensation must implement DdMoCompGetFormats.

DD_GETMOCOMPFORMATSDATA

The DD_GETMOCOMPFORMATSDATA structure contains the uncompressed format information.

typedef struct _DD_GETMOCOMPFORMATSDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  GUID  *lpGuid;
  DWORD  dwNumFormats;
  LPDDPIXELFORMAT  lpFormats;
  HRESULT  ddRVal;
} DD_GETMOCOMPFORMATSDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that describes the DirectDraw API.
lpGuid
Points to a GUID that describes the uncompressed formats being requested.
dwNumFormats
Indicates the number of uncompressed formats supported for the specified GUID.
lpFormats
Points to a DDPIXELFORMAT structure that contains the motion compensation pixel format. If this member is not NULL, the uncompressed formats are copied into the buffer pointed to by this member.
ddRVal
Specifies the location in which the driver writes the return value of the DdMoCompGetFormats callback. A return code of DD_OK indicates success.


DdMoCompGetGuids

DdMoCompGetGuids retrieves the number of GUIDs the driver supports.

DWORD
  (APIENTRY *PDD_MOCOMPCB_GETGUIDS)(
    PDD_GETMOCOMPGUIDSDATA  lpGetGuidData
    );

Parameters

lpGetGuidData
Points to a DD_GETMOCOMPGUIDSDATA structure that contains the GUID information.

Return Value

DdMoCompGetGuids returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DirectDraw drivers that support motion compensation must implement DdMoCompGetGuids.

DD_GETMOCOMPGUIDSDATA

The DD_GETMOCOMPGUIDSDATA structure contains the motion compensation GUID information.

typedef struct _DD_GETMOCOMPGUIDSDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  DWORD  dwNumGuids;
  GUID  *lpGuids;
  HRESULT  ddRVal;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that describes the DirectDraw API.
dwNumGuids
Indicates the number of motion compensation GUIDs in lpGuids.
lpGuids
Points to a list of GUIDs that describe the motion compensation processes being used. If lpGuids is NULL, the driver should set dwNumGuids to the number of GUIDs that it supports. Otherwise, it should fill lpGuids with the GUIDs that it supports and set the number in dwNumGuids.
ddRVal
Specifies the location in which the driver writes the return value of the DdMoCompGetGuids callback. A return code of DD_OK indicates success.


DdMoCompGetInternalInfo

DdMoCompGetInternalInfo allows the driver to report that it internally allocates display memory to perform motion compensation.

DWORD
  (APIENTRY *PDD_MOCOMPCB_GETINTERNALINFO)(
    PDD_GETINTERNALMOCOMPDATA  lpInternalData
    );

Parameters

lpInternalData

Points to a DD_GETINTERNALMOCOMPDATA structure that contains the internal memory requirements.

Return Value

DdMoCompGetInternalInfo returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DirectDraw drivers that support motion compensation must implement DdMoCompGetInternalInfo.

This function allows the decoder and DirectShow® to make better-informed decisions regarding what GUID to choose.

DD_GETINTERNALMOCOMPDATA

The DD_GETINTERNALMOCOMPDATA structure contains the internal memory requirements.

typedef struct _DD_GETINTERNALMOCOMPDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  GUID  *lpGuid;
  DWORD  dwWidth;
  DWORD  dwHeight;
  DDPIXELFORMAT  ddPixelFormat;
  DWORD  dwScratchMemAlloc;//..out
  HRESULT  ddRVal;
} DD_GETINTERNALMOCOMPDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that describes the DirectDraw API.
lpGuid
Points to a GUID for which the internal memory requirement is requested.
dwWidth
Indicates the width of uncompressed output frame.
dwHeight
Indicates the height of uncompressed output frame.
ddPixelFormat
Points to a DDPIXELFORMAT structure that contains the pixel format of the uncompressed output frame.
dwScratchMemAlloc
Indicates the amount of internal memory the display driver will privately reserve to perform motion compensation
ddRVal
Specifies the location in which the driver writes the return value of the DdMoCompGetInternalInfo callback. A return code of DD_OK indicates success.


DdMoCompQueryStatus

DdMoCompQueryStatus queries the status of the most recent rendering operation to the specified surface.

DWORD
  (APIENTRY *PDD_MOCOMPCB_QUERYSTATUS)(
    PDD_QUERYMOCOMPSTATUSDATA  lpStatusData
    );

Parameters

lpStatusData
Points to a DD_QUERYMOCOMPSTATUSDATA structure that contains the information needed to query the status.

Return Value

DdMoCompQueryStatus returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DirectDraw drivers that support motion compensation must implement DdMoCompQueryStatus.

DD_QUERYMOCOMPSTATUSDATA

The DD_QUERYMOCOMPSTATUSDATA structure contains information required to query the status of the previous frame.

typedef struct _DD_QUERYMOCOMPSTATUSDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  PDD_MOTIONCOMP_LOCAL  lpMoComp;
  PDD_SURFACE_LOCAL  lpSurface;
  DWORD  dwFlags;
  HRESULT  ddRVal;
} DD_QUERYMOCOMPSTATUSDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that describes the DirectDraw API.
lpMoComp
Points to a DD_MOTIONCOMP_LOCAL structure that contains a description of the motion compensation being requested.
lpSurface
Points to a DD_SURFACE_LOCAL structure that contains the surface being queried.
dwFlags
Indicates the type of surface access.
DDMCQUERY_READ
Indicates that the surface can only be tested for read or display access. If this flag is not set, the surface can be tested for write access.
ddRVal
Specifies the location in which the driver writes the return value of the DdMoCompQueryStatus callback. A return code of DD_OK indicates the hardware has finished processing the DdMoCompRender request. Otherwise the return value must be DDERR_WASSTILLDRAWING.


DdMoCompRender

DdMoCompRender tells the driver what macroblocks to render by specifying the surfaces containing the macroblocks, the offsets in each surface where the macroblocks exist, and the size of the macroblock data to be rendered.

DWORD
  (APIENTRY *PDD_MOCOMPCB_RENDER)(
    PDD_RENDERMOCOMPDATA  lpRenderData
    );

Parameters

lpRenderData
Points to a DD_RENDERMOCOMPDATA structure that contains the information needed to render a frame.

Return Value

DdMoCompRender returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DirectDraw drivers that support motion compensation must implement DdMoCompRender.

DdMoCompRender can be called multiple times between the DdMoCompBeginFrame and DdMoCompEndFrame sequence.

If a previous render operation is not yet finished, the driver should set the DirectDraw return code to DDERR_WASSTILLDRAWING.

DD_RENDERMOCOMPDATA

The DD_RENDERMOCOMPDATA structure contains the information required to render a frame.

typedef struct _DD_RENDERMOCOMPDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  PDD_MOTIONCOMP_LOCAL  lpMoComp;
  DWORD  dwNumBuffers;
  LPDDMOCOMPBUFFERINFO  lpBufferInfo;
  DWORD  dwFunction;
  LPVOID  lpInputData;
  DWORD  dwInputDataSize;
  LPVOID  lpOutputData;
  DWORD  dwOutputDataSize;
  HRESULT  ddRVal;
} DD_RENDERMOCOMPDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that describes the DirectDraw API.
lpMoComp
Points to a DD_MOTIONCOMP_LOCAL structure that contains a description of the motion compensation being requested.
dwNumBuffers
Indicates the number of entries in the lpBufferInfo member.
lpBufferInfo
Points to a DDMOCOMPBUFFERINFO structure that contains the surfaces and the locations within the surfaces from which to get the macroblock data to render.
dwFunction
Indicates a specific operation the decoder would like the driver to perform. The possible values for this member are defined by the GUID used.
lpInputData
Points to an optional input buffer, the contents of which are defined by the GUID. This buffer cannot contain any embedded pointers.
dwInputDataSize
Specifies the size of the data pointed to by lpInputData.
lpOutputData
Points to an optional output buffer, the contents of which are defined by the GUID. This buffer cannot contain any embedded pointers.
dwOutputDataSize
Specifies the size of the data pointed to by lpOutputData.
ddRVal
Specifies the location in which the driver writes the return value of the DdMoCompRender callback. A return code of DD_OK indicates success.


DdSetClipList

DdSetClipList is obsolete for use in all currently supported operating systems.

DWORD
  (APIENTRY *PDD_SURFCB_SETCLIPLIST)(
    PDD_SETCLIPLISTDATA  lpSetClipList
    );


DdSetColorKey

DdSetColorKey sets the color key value for the specified surface.

DWORD
  (APIENTRY *PDD_SURFCB_SETCOLORKEY)(
    PDD_SETCOLORKEYDATA  lpSetColorKey
    );

Parameters

lpSetColorKey
Points to a DD_SETCOLORKEYDATA structure that contains the information required to set the color key for the specified surface.

Return Value

DdSetColorKey returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

DDHAL_DRIVER_NOCKEYHW

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DdSetColorKey sets the source or destination color key for the specified surface. Typically, this callback is implemented only for drivers that support overlays with color key capabilities.

DD_SETCOLORKEYDATA

The DD_SETCOLORKEYDATA structure contains information necessary to set the color key value for the specified surface.

typedef struct _DD_SETCOLORKEYDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  PDD_SURFACE_LOCAL  lpDDSurface;
  DWORD  dwFlags;
  DDCOLORKEY  ckNew;
  HRESULT  ddRVal;
  VOID  *SetColorKey;
} DD_SETCOLORKEYDATA;

Members

lpDD
Points to the DD_DIRECTDRAW_GLOBAL structure that describes the DirectDraw API.
lpDDSurface
Points to the DD_SURFACE_LOCAL structure that describes the surface with which the color key is to be associated.
dwFlags
Specifies which color key is being requested. This member is a bit-wise OR of any of the following values:
Value | Meaning
DDCKEY_COLORSPACE | The DDCOLORKEY structure contains a color space. If this bit is not set, the structure contains a single color key.
DDCKEY_DESTBLT | The DDCOLORKEY structure specifies a color key or color space to be used as a destination color key for blt operations.
DDCKEY_DESTOVERLAY | The DDCOLORKEY structure specifies a color key or color space to be used as a destination color key for overlay operations.
DDCKEY_SRCBLT | The DDCOLORKEY structure specifies a color key or color space to be used as a source color key for blit operations.
DDCKEY_SRCOVERLAY | The DDCOLORKEY structure specifies a color key or color space to be used as a source color key for overlay operations

ckNew
Specifies a DDCOLORKEY structure that specifies the new color key values for the DirectDrawSurface object.
ddRVal
Specifies the location in which the driver writes the return value of the DdSetColorKey callback. A return code of DD_OK indicates success.
SetColorKey
This is not used on Windows 2000 and later.


DdSetEntries

DdSetEntries updates the palette entries in the specified palette.

DWORD
  (APIENTRY *PDD_PALCB_SETENTRIES)(
    PDD_SETENTRIESDATA  lpSetEntries
    );

Parameters

lpSetEntries
Points to a DD_SETENTRIESDATA structure that contains the information required to set the palette's entries.

Return Value

DdSetEntries returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DD_SETENTRIESDATA

The DD_SETENTRIESDATA structure contains information necessary to set palette entries.

typedef struct _DD_SETENTRIESDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  PDD_PALETTE_GLOBAL  lpDDPalette;
  DWORD  dwBase;
  DWORD  dwNumEntries;
  LPPALETTEENTRY  lpEntries;
  HRESULT  ddRVal;
  VOID  *SetEntries;
} DD_SETENTRIESDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_GLOBAL structure that describes the DirectDraw API.
lpDDPalette
Points to a DD_PALETTE_GLOBAL structure that represents the DirectDrawPalette object.
dwBase
Specifies an index into the color table of the first entry to be modified.
dwNumEntries

Specifies the number of palette entries that the driver should update.

lpEntries
Points to a PALETTEENTRY structure that specifies the color table.
ddRVal
Passes the DirectDraw return values.
SetEntries
Is used by the DirectDraw API and should not be filled in by the driver.


DdSetExclusiveMode

DdSetExclusiveMode notifies the driver when a DirectDraw application is switching to or from exclusive mode.

DWORD
  (APIENTRY *PDD_SETEXCLUSIVEMODE)(
    PDD_SETEXCLUSIVEMODEDATA  lpSetExclusiveMode
    );

Parameters

lpSetExclusiveMode
Points to a DD_SETEXCLUSIVEMODEDATA structure that contains the notification information.

Return Value

DdSetExclusiveMode returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DdSetExclusiveMode can be optionally implemented in display drivers. Drivers for hardware that needs to be partially enabled and/or disabled to support exclusive mode should implement this function.

DirectDraw applications can go fullscreen and take total control of the primary surface. Specifically, the application is responsible for operations such as DirectDraw mode changes and primary surface flipping when in exclusive mode.

DD_SETEXCLUSIVEMODEDATA

The DD_SETEXCLUSIVEMODEDATA structure contains the exclusive mode notification information.

typedef struct _DD_SETEXCLUSIVEMODEDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  DWORD  dwEnterExcl;
  DWORD  dwReserved;
  HRESULT  ddRVal;
  VOID  *SetExclusiveMode;
} DD_SETEXCLUSIVEMODEDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_GLOBAL structure that describes the DirectDraw API.
dwEnterExcl
Indicates that a DirectDraw application is switching into exclusive mode when TRUE; indicates that a DirectDraw application is leaving exclusive mode when FALSE.
dwReserved
This is reserved for system use and should be ignored by the driver.
ddRVal
Specifies the location in which the driver writes the return value of the DdSetExclusiveMode callback. A return code of DD_OK indicates success.
SetExclusiveMode
Is used by the DirectDraw API and should not be filled in by the driver.


DdSetOverlayPosition

DdSetOverlayPosition sets the position for an overlay.

DWORD
  (APIENTRY *PDD_SURFCB_SETOVERLAYPOSITION)(
    PDD_SETOVERLAYPOSITIONDATA  lpSetOverlayPosition
    );

Parameters

lpSetOverlayPosition
Points to a DD_SETOVERLAYPOSITIONDATA structure that contains the information required to set the overlay position.

Return Value

DdSetOverlayPosition returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

When the overlay is visible, the driver should cause the overlay to be displayed on the primary surface. The upper left corner of the overlay should be anchored at (lXPos,lYPos). For example, values of (0,0) indicates that the upper left corner of the overlay should appear in the upper left corner of the surface identified by lpDDDestSurface.

When the overlay is invisible, the driver should set DDHAL_DRIVER_HANDLED in ddRVal and return.

DD_SETOVERLAYPOSITIONDATA

The DD_SETOVERLAYPOSITIONDATA structure contains information necessary to change the display coordinates of an overlay surface.

typedef struct _DD_SETOVERLAYPOSITIONDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  PDD_SURFACE_LOCAL  lpDDSrcSurface;
  PDD_SURFACE_LOCAL  lpDDDestSurface;
  LONG  lXPos;
  LONG  lYPos;
  HRESULT  ddRVal;
  VOID  *SetOverlayPosition;
} DD_SETOVERLAYPOSITIONDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_GLOBAL structure that describes the DirectDraw API.
lpDDSrcSurface
Points to a DD_SURFACE_LOCAL structure that represents the DirectDraw overlay surface.
lpDDDestSurface
Points to a DD_SURFACE_LOCAL structure representing the surface that is being overlaid.
lXPos
Specifies the x coordinate of the upper left corner of the overlay, in pixels.
lYPos
Specifies the y coordinate of the upper left corner of the overlay, in pixels.
ddRVal
Specifies the location in which the driver writes the return value of the DdSetOverlayPosition callback. A return code of DD_OK indicates success.
SetOverlayPosition
Is used by the DirectDraw API and should not be filled in by the driver.


DdSetPalette

DdSetPalette attaches a palette to the specified surface.

DWORD
  (APIENTRY *PDD_SURFCB_SETPALETTE)(
    PDD_SETPALETTEDATA  lpSetPalette
    );

Parameters

lpSetPalette
Points to a DD_SETPALETTEDATA structure that contains the information required to set a palette to the specified surface.

Return Value

DdSetPalette returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DD_SETPALETTEDATA

The DD_SETPALETTEDATA structure contains information necessary to set a palette for a specific surface.

typedef struct _DD_SETPALETTEDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  PDD_SURFACE_LOCAL  lpDDSurface;
  PDD_PALETTE_GLOBAL  lpDDPalette;
  HRESULT  ddRVal;
  VOID  *SetPalette;
  BOOL  Attach;
} DD_SETPALETTEDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_GLOBAL structure that represents the DirectDraw object.
lpDDSurface
Points to a DD_SURFACE_LOCAL structure that represents the DirectDrawSurface object.
lpDDPalette
Points to a DD_PALETTE_GLOBAL structure that specifies the palette to set to the surface.
ddRVal
Specifies the location in which the driver writes the return value of the DdSetPalette callback. A return code of DD_OK indicates success.
SetPalette
Is used by the DirectDraw API and should not be filled in by the driver.
Attach
Indicates whether to attach this palette to the surface.


DdSyncSurfaceData

DdSyncSurfaceData sets and modifies surface data before it is passed to the miniport.

DWORD
  (APIENTRY *PDD_KERNELCB_SYNCSURFACE)(
    PDD_SYNCSURFACEDATA  lpSyncSurface
    );

Parameters

lpSyncSurface
Points to a DD_SYNCSURFACEDATA structure that contains the surface data.

Return Value

DdSyncSurfaceData returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DD_SYNCSURFACEDATA

The DD_SYNCSURFACEDATA structure contains the surface information.

typedef struct _DD_SYNCSURFACEDATA {
  DWORD  dwSize;              // Windows 98/Me only
  PDD_DIRECTDRAW_LOCAL  lpDD;
  PDD_SURFACE_LOCAL  lpDDSurface;
  DWORD  dwSurfaceOffset;
  ULONG_PTR  fpLockPtr;
  LONG  lPitch;
  DWORD  dwOverlayOffset;
  DWORD  dwOverlaySrcWidth;   // Windows 98/Me only
  DWORD  dwOverlaySrcHeight;  // Windows 98/Me only
  DWORD  dwOverlayDestWidth;  // Windows 98/Me only
  DWORD  dwOverlayDestHeight; // Windows 98/Me only
  ULONG  dwDriverReserved1;
  ULONG  dwDriverReserved2;
  ULONG  dwDriverReserved3;
  ULONG  dwDriverReserved4;   // Windows 2000 and later
  HRESULT  ddRVal;
} DD_SYNCSURFACEDATA;

Members

dwSize (Windows 98/Me only)
Specifies the size of this structure. This member must be initialized before the structure is used.
lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that describes the DirectDraw API.
lpDDSurface
Points to the DD_SURFACE_LOCAL structure that describes the surface with which to sync.
dwSurfaceOffset
Contains the byte offset from the start of the frame buffer to the start of the surface. This value is used only by the miniport. This member must contain data that is filled in by the driver.
fpLockPtr
Contains the pointer value to be returned by the DdLock call for accessing the surface. This value is used by a kernel-mode client. This member can be modified by the driver, but does not need to be.
lPitch
Contains the pitch passed to the client during a DdLock call. This member can be modified by the driver, but does not need to be.
dwOverlayOffset
Contains the byte offset from the start of the frame buffer to the start of the overlay. This value is used only by the miniport and may be different than the dwSurfaceOffset member if cropping is involved or if the overlay origin is not the top left of the surface. This member must contain data that is filled in by the driver.
dwOverlaySrcWidth (Windows 98/Me only)
Specifies the source width of the overlay. This value is used only by the miniport. This member can be modified by the driver, but does not need to be.
dwOverlaySrcHeight (Windows 98/Me only)
Specifies the source height of the overlay. This value is used only by the miniport. This member can be modified by the driver, but does not need to be.
dwOverlayDestWidth (Windows 98/Me only)
Specifies the destination width of the overlay. This value is used only by the miniport. This member can be modified by the driver, but does not need to be.
dwOverlayDestHeight (Windows 98/Me only)
Specifies the destination height of the overlay. This value is used only by the miniport. This member can be modified by the driver, but does not need to be.
dwDriverReserved1
Is reserved for use by the display driver.
dwDriverReserved2
Is reserved for use by the display driver.
dwDriverReserved3
Is reserved for use by the display driver.
dwDriverReserved4 (Windows 2000 and later only)
Is reserved for use by the display driver.
ddRVal
Specifies the location in which the driver writes the return value of the DdSyncSurfaceData callback. A return code of DD_OK indicates success.


DdSyncVideoPortData

DdSyncVideoPortData sets and modifies VPE object data before it is passed to the miniport.

DWORD
  (APIENTRY *PDD_KERNELCB_SYNCVIDEOPORT)(
    PDD_SYNCVIDEOPORTDATA  lpSyncVideoPort
    );

Parameters

lpSyncVideoPort
Points to a DD_SYNCVIDEOPORTDATA structure that contains the VPE object data.

Return Value

DdSyncVideoPortData returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DD_SYNCVIDEOPORTDATA

The DD_SYNCVIDEOPORTDATA structure contains the VPE object information.

typedef struct _DD_SYNCVIDEOPORTDATA {
  DWORD  dwSize; // Windows 98/Me only
  PDD_DIRECTDRAW_LOCAL  lpDD;
  PDD_VIDEOPORT_LOCAL  lpVideoPort;
  DWORD  dwOriginOffset;
  DWORD  dwHeight;
  DWORD  dwVBIHeight;
  ULONG  dwDriverReserved1;
  ULONG  dwDriverReserved2;
  ULONG  dwDriverReserved3;
  HRESULT  ddRVal;
} DD_SYNCVIDEOPORTDATA;

Members

dwSize (Windows 98/Me only)
Specifies the size of this structure. This member must be initialized before the structure is used.
lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that describes the DirectDraw API.
lpVideoPort
Points to a DD_VIDEOPORT_LOCAL structure that that describes the hardware video port with which to sync.
dwOriginOffset
Contains the byte offset from the top left corner of the surface to the top left corner of where the VPE object writes its data. This value is only used by the miniport. This member must contain data that is filled in by the driver.
dwHeight
Contains the height of the VPE object data. By default, this is twice the field height when interleaved, but the driver can change this if it needs to. This value is used only by the miniport. This member can be modified by the driver, but does not need to be.
dwVBIHeight
Contains the number of lines in the VBI region. This value is used only by the miniport. This member can be modified by the driver, but does not need to be.
dwDriverReserved1, dwDriverReserved2, dwDriverReserved3
Are reserved for use by the display driver.
ddRVal
Specifies the location in which the driver writes the return value of the DdSyncVideoPortData callback. A return code of DD_OK indicates success.


DdUnlock

DdUnLock releases the lock held on the specified surface.

DWORD
  (APIENTRY *PDD_SURFCB_UNLOCK)(
    PDD_UNLOCKDATA  lpUnlock
    );

Parameters

lpUnlock
Points to a DD_UNLOCKDATA structure that contains the information required to perform the lock release.

Return Value

DdUnlock returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

The driver does not need to verify that the memory was previously locked down by DdLock, because DirectDraw does parameter validation before calling this routine.

DD_UNLOCKDATA

The DD_UNLOCKDATA structure contains information necessary to do an unlock as defined by DirectDraw parameter structures.

typedef struct _DD_UNLOCKDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  PDD_SURFACE_LOCAL  lpDDSurface;
  HRESULT  ddRVal;
  VOID  *Unlock;
} DD_UNLOCKDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_GLOBAL structure that describes the DirectDraw API.
lpDDSurface
Points to a DD_SURFACE_LOCAL structure that describes the surface to be unlocked.
ddRVal
Specifies the location in which the driver writes the return value of the DdUnlock callback. A return code of DD_OK indicates success.
Unlock
Is used by the DirectDraw API and should not be filled in by the driver.

See Also

DdLock


DdVideoPortCanCreate

The DdVideoPortCanCreate callback determines whether the driver can support a DirectDraw VPE object of the specified description.

DWORD
  (APIENTRY *PDD_VPORTCB_CANCREATEVIDEOPORT)(
    PDD_CANCREATEVPORTDATA  lpCanCreateVideoPort
    );

Parameters

lpCanCreateVideoPort
Points to a DD_CANCREATEVPORTDATA structure that contains the information necessary for the driver to determine whether the specified DirectDraw VPE object can be supported.

Return Value

DdVideoPortCanCreate returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DdVideoPortCanCreate must be implemented in drivers that support VPE.

The driver should check the members of the DDVIDEOPORTDESC structure to which lpDDVideoPortDesc points to determine whether the hardware supports the specified type of VPE object.

DD_CANCREATEVPORTDATA

The DD_CANCREATEVPORTDATA structure contains the information required for the driver to determine whether a VPE object can be created.

typedef struct _DD_CANCREATEVPORTDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  LPDDVIDEOPORTDESC  lpDDVideoPortDesc;
  HRESULT  ddRVal;
  VOID  *CanCreateVideoPort;
} DD_CANCREATEVPORTDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that describes the DirectDraw API.
lpDDVideoPortDesc
Points to a DDVIDEOPORTDESC structure that contains a description of the VPE object being requested.
ddRVal
Specifies the location in which the driver writes the return value of the DdVideoPortCanCreate callback. A return code of DD_OK indicates success.
CanCreateVideoPort
Is used by the DirectDraw API and should not be filled in by the driver.

See Also

DdVideoPortCreate


DdVideoPortCreate

DdVideoPortCreate notifies the driver that DirectDraw has created a VPE object.

DWORD
  (APIENTRY *PDD_VPORTCB_CREATEVIDEOPORT)(
    PDD_CREATEVPORTDATA  lpCreateVideoPort
    );

Parameters

lpCreateVideoPort
Points to a DD_CREATEVPORTDATA structure that describes the created VPE object.

Return Value

DdVideoPortCreate returns one of the following values:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DdVideoPortCreate can be optionally implemented in DirectDraw drivers that support VPE.

DdVideoPortCreate can allocate memory for and initialize any private, VPE object-specific data. The driver can use the dwReserved1 and dwReserved2 members of the DD_VIDEOPORT_LOCAL structure to store this data. The driver cannot use or change any other members of the DD_VIDEOPORT_LOCAL structure.

If the hardware video port is implemented to use the feature connector, the driver might need to initialize the feature connector for hardware video port use.

DdVideoPortCreate should not turn the hardware video port on. This is accomplished in DdVideoPortUpdate.

DD_CREATEVPORTDATA

The DD_CREATEVPORTDATA structure contains the information necessary to describe the VPE object being created.

typedef struct _DD_CREATEVPORTDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  LPDDVIDEOPORTDESC  lpDDVideoPortDesc;
  PDD_VIDEOPORT_LOCAL  lpVideoPort;
  HRESULT  ddRVal;
  VOID  *CreateVideoPort;
} DD_CREATEVPORTDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that describes the DirectDraw API.
lpDDVideoPortDesc
Points to a DDVIDEOPORTDESC structure that describes the created VPE object.
lpVideoPort
Points to a DD_VIDEOPORT_LOCAL structure that represents the created VPE object.
ddRVal
Specifies the location in which the driver writes the return value of the DdVideoPortCreate callback. A return code of DD_OK indicates success.
CreateVideoPort
Is used by the DirectDraw API and should not be filled in by the driver.


DdVideoPortDestroy

DdVideoPortDestroy notifies the driver that DirectDraw has destroyed the specified VPE object.

DWORD
  (APIENTRY *PDD_VPORTCB_DESTROYVPORT)(
    PDD_DESTROYVPORTDATA  lpDestroyVideoPort
    );

Parameters

lpDestroyVideoPort
Points to a DD_DESTROYVPORTDATA structure that contains the information required for the driver to clean up.

Return Value

DdVideoPortDestroy returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DdVideoPortDestroy can be optionally implemented in DirectDraw drivers that support VPE.

The driver should free any memory that it allocated and associated with the specified VPE object. This includes freeing any driver-allocated memory accessed through the dwReserved1 and dwReserved2 members of the DD_VIDEOPORT_LOCAL structure.

DD_DESTROYVPORTDATA

The DD_DESTROYVPORTDATA structure contains the information necessary for the driver to clean up.

typedef struct _DD_DESTROYVPORTDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  PDD_VIDEOPORT_LOCAL  lpVideoPort;
  HRESULT  ddRVal;
  VOID  *DestroyVideoPort;
} DD_DESTROYVPORTDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that represents the DirectDraw object.
lpVideoPort
Points to a DD_VIDEOPORT_LOCAL structure that represents this VPE object.
ddRVal
Specifies the location in which the driver writes the return value of the DdVideoPortDestroy callback. A return code of DD_OK indicates success.
DestroyVideoPort
Is used by the DirectDraw API and should not be filled in by the driver.

See Also

DdVideoPortCreate


DdVideoPortFlip

DdVideoPortFlip performs a physical flip, causing the VPE object to start writing data to the new surface.

DWORD
  (APIENTRY *PDD_VPORTCB_FLIP)(
    PDD_FLIPVPORTDATA  lpFlipVideoPort
    );

Parameters

lpFlipVideoPort
Points to a DD_FLIPVPORTDATA structure that contains the information required for the driver to perform the flip.

Return Value

DdVideoPortFlip returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DdVideoPortFlip must be implemented in DirectDraw drivers that support VPE.

The driver should update its surface pointers so that the next frame of video will be written to the surface to which lpSurfTarg points. If a previous flip request is still pending, the driver should fail the call and return DDERR_WASSTILLDRAWING. DdVideoPortFlip does not affect the actual display of the video data.

A call to DdVideoPortFlip typically accompanies a call to DdFlip when an application is performing video streaming.

DD_FLIPVPORTDATA

The DD_FLIPVPORTDATA structure contains the information necessary for the VPE object to perform a flip.

typedef struct _DD_FLIPVPORTDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  PDD_VIDEOPORT_LOCAL  lpVideoPort;
  PDD_SURFACE_LOCAL  lpSurfCurr;
  PDD_SURFACE_LOCAL  lpSurfTarg;
  HRESULT  ddRVal;
  VOID  *FlipVideoPort;
} DD_FLIPVPORTDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that represents the DirectDraw object.
lpVideoPort
Points to a DD_VIDEOPORT_LOCAL structure that represents this VPE object.
lpSurfCurr
Points to the current surface; that is, the surface on which data is currently being written.
lpSurfTarg
Points to the target surface; that is, the surface to which the driver should flip.
ddRVal
Specifies the location in which the driver writes the return value of the DdVideoPortFlip callback. A return code of DD_OK indicates success.
FlipVideoPort
Is used by the DirectDraw API and should not be filled in by the driver.


DdVideoPortGetBandwidth

DdVideoPortGetBandwidth reports the bandwidth limitations of the device's frame buffer memory based the specified VPE object output format.

DWORD
  (APIENTRY *PDD_VPORTCB_GETBANDWIDTH)(
    PDD_GETVPORTBANDWIDTHDATA  lpGetVideoPortBandwidth
    );

Parameters

lpGetVideoPortBandwidth
Points to a DD_GETVPORTBANDWIDTHDATA structure that contains the information required for the driver to return the bandwidth data.

Return Value

DdVideoPortGetBandwidth returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DdVideoPortGetBandwidth must be implemented in DirectDraw drivers that support VPE.

DdVideoPortGetBandwidth informs clients of bandwidth requirements for any specified format, helping them to choose a format and better understand its limitations. The driver can supply accurate bandwidth information only after the VPE object has been created because the driver needs the information in the DDVIDEOPORTDESC structure.

DdVideoPortGetBandwidth is typically called twice to obtain the bandwidth parameters of the specified hardware video port. Depending on the dwFlags member of the DD_GETVPORTBANDWIDTHDATA structure, the driver should do the following:

  • When the flag is DDVPB_TYPE, the driver should indicate the type of device it is by setting one of the following flags in the dwCaps member of the DDVIDEOPORTBANDWIDTH structure to which lpBandwidth points:
    • DDVPBCAPS_DESTINATION indicates that the device will describe its bandwidth capabilities in terms of the overlay stretch factor; that is, that the bandwidth information returned by the driver in the next call to DdVideoPortGetBandwidth will refer to the size of the destination overlay. This flag best describes hardware that refreshes from both the primary and overlay surfaces simultaneously. As the destination video is stretched, the hardware has more time to read the pixels from the overlay surface, decreasing the required memory bandwidth.
    • DDVPBCAPS_SOURCE indicates that the device will describe its bandwidth capabilities in terms of the required source overlay size; that is, that the bandwidth information returned by the next call to DdVideoPortGetBandwidth refers to the size of the source overlay. This flag best describes hardware that pre-fetches the overlay data into a line buffer or large FIFO. Such hardware does not require extra bandwidth, but does require that the source overlay data fit entirely within the buffer/FIFO size supported by the hardware.

    The driver should also set the dwSize member of the DDVIDEOPORTBANDWIDTH structure before returning.

  • When the flag is DDVPB_VIDEOPORT, the dwWidth and dwHeight members in the DD_GETVPORTBANDWIDTHDATA structure refer to the pre-scale size of the video data that the hardware video port will write to the frame buffer as the source overlay. The driver should return an overlay stretch factor at which the device can display the overlay, multiplied by 1000, in each of the dwOverlay, dwColorkey, dwYInterpolate, and dwYInterpAndColorkey members of the DDVIDEOPORTBANDWIDTH structure. For example, a value of 2000 indicates that the device has the bandwidth to stretch the overlay to two times the source's specified size when displaying it. A value of 1000 indicates that no stretching need be done for the specified data size. A value of 500 indicates that the device has sufficient bandwidth to shrink the overlay destination in half. The driver must set a valid value in dwOverlay, but can return -1 in any of the other three members that it does not support.

    The DDVPB_VIDEOPORT flag assumes that the device is best described by the DDVPBCAPS_DESTINATION flag. If this is not the case, the driver should fail the call.

  • When the DDVPB_OVERLAY flag is set, the dwWidth and dwHeight members in the DD_GETVPORTBANDWIDTHDATA structure refer to the source overlay size. The driver should return a percentage of this overlay's size, multiplied by 1000, at which it can support displaying the overlay in each of the dwOverlay, dwColorkey, dwYInterpolate, and dwYInterpAndColorkey members of the DDVIDEOPORTBANDWIDTH structure. For example, a value of 750 indicates that the device requires the specified source overlay to be shrunk to 75% of its original size in order for the device to successfully display it. A value of 1000 indicates that no shrinking is required. Drivers for this type of device do not typically return a value greater than 1000. The driver must set a valid value in dwOverlay, but can return 0 in any of the other three members if it does not support color keying and/or Y-axis interpolation.

    The DDVPB_OVERLAY flag assumes that the device is best described using the DDVPBCAPS_SOURCE flag. If this is not the case, the driver should fail the call.

DD_GETVPORTBANDWIDTHDATA

The DD_GETVPORTBANDWIDTHDATA structure contains the bandwidth information for any specified format.

typedef struct _DD_GETVPORTBANDWIDTHDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  PDD_VIDEOPORT_LOCAL  lpVideoPort;
  LPDDPIXELFORMAT  lpddpfFormat;
  DWORD  dwWidth;
  DWORD  dwHeight;
  DWORD  dwFlags;
  LPDDVIDEOPORTBANDWIDTH  lpBandwidth;
  HRESULT  ddRVal;
  VOID  *GetVideoPortBandwidth;
} DD_GETVPORTBANDWIDTHDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that represents the DirectDraw object.
lpVideoPort
Points to a DD_VIDEOPORT_LOCAL structure that represents this VPE object.
lpddpfFormat
Points to a DDPIXELFORMAT structure that describes the output pixel format for which the driver should return bandwidth information.
dwWidth, dwHeight
Specify the dimensions of the source overlay or of the video data, in pixels, depending on the value of dwFlags. These values are calculated by the client based on the VPE object's capabilities returned in a prior call to DdVideoPortGetBandwidth.
dwFlags
Are the flags indicating how the driver should interpret the dwWidth and dwHeight members. This member can be one of the following values:
Flag | Meaning
DDVPB_OVERLAY | The dwWidth and dwHeight members specify the size in pixels of the source overlay surface. This flag indicates that the VPE object is dependent on the overlay source size.
DDVPB_TYPE | The dwWidth and dwHeight members are not set.
DDVPB_VIDEOPORT | The dwWidth and dwHeight members specify the pre-scale size of the video data that the VPE object writes to the frame buffer. This flag indicates that the VPE object is dependent on the overlay stretch factor.

lpBandwidth
Points to the DDVIDEOPORTBANDWIDTH structure in which the driver should write the bandwidth parameters.
ddRVal
Specifies the location in which the driver writes the return value of the DdVideoPortGetBandwidth callback. A return code of DD_OK indicates success.
GetVideoPortBandwidth
Is used by the DirectDraw API and should not be filled in by the driver.

See Also

DdVideoPortCreate


DdVideoPortColorControl

DdVideoPortColorControl gets or sets the VPE object color controls.

DWORD
  (APIENTRY *PDD_VPORTCB_COLORCONTROL)(
    PDD_VPORTCOLORDATA  lpColorControl
    );

Parameters

lpColorControl
Points to a DD_VPORTCOLORDATA structure that contains the information required for the driver to get the current VPE object color controls or to set new values.

Return Value

DdVideoPortColorControl returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DirectDraw drivers that set the DDVPCAPS_COLORCONTROL flag in the DDVIDEOPORTCAPS structure must implement DdVideoPortColorControl.

Depending on the value of the dwFlags member of the DD_VPORTCOLORDATA structure, the driver should do the following:

  • When dwFlags is DDRAWI_VPORTGETCOLOR, the driver should fill in each member of the DDCOLORCONTROL structure that it supports with the VPE object's current color control setting. The driver must set the corresponding bit in the dwFlags member of DDCOLORCONTROL for every color control member in which it writes data.

    DdVideoPortColorControl can be called to determine the color control capabilities of the VPE object. The driver should therefore fail the call if it does not support a requested color control capability.

  • When dwFlags is DDRAWI_VPORTSETCOLOR, the driver should set the VPE object's color control settings to the values specified in the DDCOLORCONTROL structure. The driver should check the dwFlags member of DDCOLORCONTROL to determine which structure members contain valid data.

DD_VPORTCOLORDATA

The DD_VPORTCOLORDATA structure contains the VPE object color control information.

typedef struct _DD_VPORTCOLORDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  PDD_VIDEOPORT_LOCAL  lpVideoPort;
  DWORD  dwFlags;
  LPDDCOLORCONTROL  lpColorData;
  HRESULT  ddRVal;
  VOID  *ColorControl;
} DD_VPORTCOLORDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure representing the DirectDraw object.
lpVideoPort
Points to a DD_VIDEOPORT_LOCAL structure that represents this VPE object.
dwFlags
Specifies the color control operation to be performed by the driver. This member can be one of the following values:
Flag | Meaning
DDRAWI_VPORTGETCOLOR | The driver should write the current VPE object color controls into the DDCOLORCONTROL structure to which lpColorData points.
DDRAWI_VPORTSETCOLOR | The driver should set new values for the VPE object color controls based on the contents of the DDCOLORCONTROL structure to which lpColorData points.

lpColorData
Points to a DDCOLORCONTROL structure that defines the color control associated with the VPE object to which lpVideoPort points. The value of dwFlags determines whether the driver reads from or writes to this structure.
ddRVal
Specifies the location in which the driver writes the return value of the DdVideoPortColorControl callback. A return code of DD_OK indicates success.
ColorControl
Is used by the DirectDraw API and should not be filled in by the driver.


DdVideoPortGetConnectInfo

DdVideoPortGetConnectInfo returns the connections supported by the specified VPE object.

DWORD
  (APIENTRY *PDD_VPORTCB_GETVPORTCONNECT)(
    PDD_GETVPORTCONNECTDATA  lpGetConnect
    );

Parameters

lpGetConnect
Points to a DD_GETVPORTCONNECTDATA structure that contains the information required for the driver to return the VPE object connection data.

Return Value

DdVideoPortGetConnectInfo returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DdVideoPortGetConnectInfo must be implemented in DirectDraw drivers that support VPE.

DirectDraw calls DdVideoPortGetConnectInfo to obtain the number of connections supported by the specified VPE object and the characteristics of each connection. DdVideoPortGetConnectInfo is called twice for the specified VPE object:

  • In the first call, lpConnect is NULL. The driver should write the number of connections that the VPE object supports in dwNumEntries. Upon return, DirectDraw will allocate this number of DDVIDEOPORTCONNECT structures to pass in the second call to DdVideoPortGetConnectInfo.
  • In the second call, lpConnect points to the array of allocated DDVIDEOPORTCONNECT structures. The driver should fill in each structure to describe each connection that the VPE object supports. The driver should also return the number of supported connections in dwNumEntries. Note that the driver is guaranteed that the buffer to which lpConnect points is large enough to hold the connection information being requested.

DD_GETVPORTCONNECTDATA

The DD_GETVPORTCONNECTDATA structure contains the connection combinations supported by the specified VPE object.

typedef struct _DD_GETVPORTCONNECTDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  DWORD  dwPortId;
  LPDDVIDEOPORTCONNECT  lpConnect;
  DWORD  dwNumEntries;
  HRESULT  ddRVal;
  VOID  *GetVideoPortConnectInfo;
} DD_GETVPORTCONNECTDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure representing the DirectDraw object.
dwPortId
Specifies the ID of the VPE object for which the driver is to retrieve connection information. DirectDraw obtains this ID from the dwVideoPortID member of the DDVIDEOPORTCAPS structure.
lpConnect
Points to an array of DDVIDEOPORTCONNECT structures in which the driver should return the characteristics of each connection that the VPE object supports. This member can be NULL.
dwNumEntries
Specifies the location in which the driver returns the number of connection combinations supported by the specified VPE object.
ddRVal
Specifies the location in which the driver writes the return value of the DdVideoPortGetConnectInfo callback. A return code of DD_OK indicates success.
GetVideoPortConnectInfo
Is used by the DirectDraw API and should not be filled in by the driver.


DdVideoPortGetField

DdVideoPortGetField determines whether the current field of an interlaced signal is even or odd.

DWORD
  (APIENTRY *PDD_VPORTCB_GETFIELD)(
    PDD_GETVPORTFIELDDATA  lpGetField
    );

Parameters

lpGetField
Points to a DD_GETVPORTFIELDDATA structure that contains the information required for the driver to determine whether the current field is even or odd.

Return Value

DdVideoPortGetField returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DirectDraw drivers that set the DDVPCAPS_READBACKFIELD flag in the DDVIDEOPORTCAPS structure must implement DdVideoPortGetField.

The driver should determine whether the current field is even or odd and write TRUE or FALSE in bField, accordingly. If the query cannot be performed because the hardware video port is disabled, the driver should set DDERR_VIDEONOTACTIVE in ddRVal and return DDHAL_DRIVER_HANDLED.

DD_GETVPORTFIELDDATA

The DD_GETVPORTFIELDDATA structure contains the information required for the driver to determine whether the current field of an interlaced signal is even or odd.

typedef struct _DD_GETVPORTFIELDDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  PDD_VIDEOPORT_LOCAL  lpVideoPort;
  BOOL  bField;
  HRESULT  ddRVal;
  VOID  *GetVideoPortField;
} DD_GETVPORTFIELDDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that describes the DirectDraw API.
lpVideoPort
Points to a DD_VIDEOPORT_LOCAL structure that represents this VPE object.
bField
Specifies the location in which the driver should indicate the polarity of the field. This member should be set to TRUE if the current field is the even field of an interlaced signal and to FALSE if the current field is the odd field.
ddRVal
Specifies the location in which the driver writes the return value of the DdVideoPortGetField callback. A return code of DD_OK indicates success.
GetVideoPortField
Is used by the DirectDraw API and should not be filled in by the driver.


DdVideoPortGetFlipStatus

DdVideoPortGetFlipStatus determines whether the most recently requested flip on a surface has occurred.

DWORD
  (APIENTRY *PDD_VPORTCB_GETFLIPSTATUS)(
    PDD_GETVPORTFLIPSTATUSDATA  lpGetFlipStatus
    );

Parameters

lpGetFlipStatus
Points to a DD_GETVPORTFLIPSTATUSDATA structure that contains the information required for the driver to determine a surface's flip status.

Return Value

DdVideoPortGetFlipStatus returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DirectDraw drivers that support VPE must implement DdVideoPortGetFlipStatus.

The driver should set ddRVal to DDERR_WASSTILLDRAWING if a flip is currently in progress; otherwise it should return DD_OK.

If the driver returns DDERR_WASSTILLDRAWING, DirectDraw will fail locks and blits on that surface.

DD_GETVPORTFLIPSTATUSDATA

The DD_GETVPORTFLIPSTATUSDATA structure contains the flip status information for the specified surface.

typedef struct _DD_GETVPORTFLIPSTATUSDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  FLATPTR  fpSurface;
  HRESULT  ddRVal;
  VOID  *GetVideoPortFlipStatus;
} DD_GETVPORTFLIPSTATUSDATA;

Members

lpDD
Points to the DD_DIRECTDRAW_LOCAL structure that represents the DirectDraw object.
fpSurface
Points to the surface for which the flip status information is required.
ddRVal
Specifies the location in which the driver writes the return value of the DdVideoPortGetFlipStatus callback. A return code of DD_OK indicates success.
GetVideoPortFlipStatus
Is used by the DirectDraw API and should not be filled in by the driver.


DdVideoPortGetInputFormats

DdVideoPortGetInputFormats determines the input formats that the DirectDraw VPE object can accept.

DWORD
  (APIENTRY *PDD_VPORTCB_GETINPUTFORMATS)(
    PDD_GETVPORTINPUTFORMATDATA  lpGetInputFormats
    );

Parameters

lpGetInputFormats
Points to a DD_GETVPORTINPUTFORMATDATA structure that contains the information required for the driver to return the input formats the VPE object can accept.

Return Value

DdVideoPortGetInputFormats returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DdVideoPortGetInputFormats must be implemented in DirectDraw drivers that support VPE.

DirectDraw calls DdVideoPortGetInputFormats to obtain the number of input formats supported by the specified VPE object and a description of each format. DdVideoPortGetInputFormats is called twice for the specified VPE object:

  • In the first call, lpddpfFormat is NULL. The driver should write the number of input formats that the VPE object supports in dwNumFormats. Upon return, DirectDraw will allocate this number of DDPIXELFORMAT structures to pass in the second call to DdVideoPortGetInputFormats.
  • In the second call, lpddpfFormat points to the array of allocated DDPIXELFORMAT structures. The driver should fill in each structure to describe each input format that the VPE object supports. The driver should also return the number of supported input formats in dwNumFormats. Note that the driver is guaranteed that the buffer to which lpddpfFormat points is large enough to hold the format information being requested.

If the dwFlags member of the DD_GETVPORTINPUTFORMATDATA structure is set only to DDVPFORMAT_VIDEO, the driver should return only those formats that are supported for the normal video data. If dwFlags is set only to DDVPFORMAT_VBI, the driver should return only those formats supported for the VBI data. If dwFlags is set to both flags, the driver should return all formats supported by the VPE object.

DD_GETVPORTINPUTFORMATDATA

The DD_GETVPORTINPUTFORMATDATA structure contains the information required for the driver to return the input formats that the VPE object can accept.

typedef struct _DD_GETVPORTINPUTFORMATDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  PDD_VIDEOPORT_LOCAL  lpVideoPort;
  DWORD  dwFlags;
  LPDDPIXELFORMAT  lpddpfFormat;
  DWORD  dwNumFormats;
  HRESULT  ddRVal;
  VOID  *GetVideoPortInputFormats;
} DD_GETVPORTINPUTFORMATDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that represents the DirectDraw object.
lpVideoPort
Points to a DD_VIDEOPORT_LOCAL structure that represents this VPE object.
dwFlags
Indicates the type of formats for which support is being queried. This member can be one or more of the following values:
Flag | Meaning
DDVPFORMAT_VBI | The driver should return formats for the VBI data.
DDVPFORMAT_VIDEO | The driver should return formats for the video data.

lpddpfFormat
Points to an array of DDPIXELFORMAT structures in which the driver should write the pixel formats supported by the VPE object. This member can be NULL.
dwNumFormats
Specifies the location in which the driver should write the number of formats that the VPE object supports.
ddRVal
Specifies the location in which the driver writes the return value of the DdVideoPortGetInputFormats callback. A return code of DD_OK indicates success.
GetVideoPortInputFormats
Is used by the DirectDraw API and should not be filled in by the driver.


DdVideoPortGetOutputFormats

DdVideoPortGetOutputFormats determines the output formats that the VPE object supports.

DWORD
  (APIENTRY *PDD_VPORTCB_GETOUTPUTFORMATS)(
    PDD_GETVPORTOUTPUTFORMATDATA  lpGetOutputFormats
    );

Parameters

lpGetOutputFormats
Points to a DD_GETVPORTOUTPUTFORMATDATA structure that contains the information required for the driver to return the output formats the VPE object supports.

Return Value

DdVideoPortGetOutputFormats returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DirectDraw drivers that support VPE must implement DdVideoPortGetOutputFormats.

DirectDraw calls DdVideoPortGetOutputFormats to obtain the number of output formats supported by the specified VPE object and a description of each format. DdVideoPortGetOutputFormats is called twice for the specified VPE object:

  • In the first call, lpddpfOutputFormats is NULL. The driver should write the number of output formats that the VPE object supports in dwNumFormats. Upon return, DirectDraw will allocate this number of DDPIXELFORMAT structures to pass in the second call to DdVideoPortGetOutputFormats.
  • In the second call, lpddpfOutputFormats points to the array of allocated DDPIXELFORMAT structures. The driver should fill in each structure with a description of each output format that the VPE object can write to the frame buffer. The driver should return only those output formats that it supports based on the input format of the video data. The driver should also return the number of supported output formats in dwNumFormats. Note that the driver is guaranteed that the buffer to which lpddpfOutputFormats points is large enough to hold the format information being requested.

If dwFlags is set only to DDVPFORMAT_VIDEO, the driver should return only those output formats that are supported for normal video data. If dwFlags is set only to DDVPFORMAT_VBI, the driver should return only those formats supported for VBI data. If dwFlags is set to both flags, the driver should return all formats supported by the VPE object.

DD_GETVPORTOUTPUTFORMATDATA

The DD_GETVPORTOUTPUTFORMATDATA structure contains the information required for the driver to return all of the output formats that the VPE object supports for a given input format.

typedef struct _DD_GETVPORTOUTPUTFORMATDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  PDD_VIDEOPORT_LOCAL  lpVideoPort;
  DWORD  dwFlags;
  LPDDPIXELFORMAT  lpddpfInputFormat;
  LPDDPIXELFORMAT  lpddpfOutputFormats;
  DWORD  dwNumFormats;
  HRESULT  ddRVal;
  VOID  *GetVideoPortOutputFormats;
} DD_GETVPORTOUTPUTFORMATDATA;

Members

lpDD
Points to the DD_DIRECTDRAW_LOCAL structure that represents the DirectDraw object.
lpVideoPort
Points to the DD_VIDEOPORT_LOCAL structure that represents this VPE object.
dwFlags
Indicates the type of output formats for which support is being queried. This member can be one or more of the following values:
Flag | Meaning
DDVPFORMAT_VBI | The driver should return formats for the VBI data.
DDVPFORMAT_VIDEO | The driver should return formats for the video data.

lpddpfInputFormat
Points to a DDPIXELFORMAT structure that contains an input format supported by the VPE object. This format was returned by DdVideoPortGetInputFormats.
lpddpfOutputFormats
Points to an array of DDPIXELFORMAT structures in which the driver should return the output formats that the VPE object supports for the input format specified by lpddpfInputFormat. This member can be NULL.
dwNumFormats
Specifies the location in which the driver should return the number of output formats that the VPE object supports for the specified input format.
ddRVal
Specifies the location in which the driver writes the return value of the DdVideoPortGetOutputFormats callback. A return code of DD_OK indicates success.
GetVideoPortOutputFormats
Is used by the DirectDraw API and should not be filled in by the driver.


DdVideoPortGetLine

DdVideoPortGetLine returns the current line number of the hardware video port.

DWORD
  (APIENTRY *PDD_VPORTCB_GETLINE)(
    PDD_GETVPORTLINEDATA  lpGetLine
    );

Parameters

lpGetLine
Points to a DD_GETVPORTLINEDATA structure that contains the information required for the driver to determine and return the current line number for the specified hardware video port.

Return Value

DdVideoPortGetLine returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

Drivers that set the DDVPCAPS_READBACKLINE flag in the DDVIDEOPORTCAPS structure must implement DdVideoPortGetLine.

The driver should write the number of the current video line in dwLine. The returned line number must be zero-based; that is, the first line of video is line 0, the second line of video is line 1, etc.

If the device is in a vertical blank, the driver should set DDERR_VERTICALBLANKINPROGRESS in ddRVal. If the query cannot be performed because the hardware video port is disabled, the driver should set DDERR_VIDEONOTACTIVE in ddRVal. In both of these failed cases, the driver should return DDHAL_DRIVER_HANDLED.

DD_GETVPORTLINEDATA

The DD_GETVPORTLINEDATA structure contains the current line number of the hardware video port.

typedef struct _DD_GETVPORTLINEDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  PDD_VIDEOPORT_LOCAL  lpVideoPort;
  DWORD  dwLine;
  HRESULT  ddRVal;
  VOID  *GetVideoPortLine;
} DD_GETVPORTLINEDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that represents the DirectDraw object.
lpVideoPort
Points to a DD_VIDEOPORT_LOCAL structure that represents this VPE object.
dwLine
Specifies the location in which the driver should write the current line number on the hardware video port.
ddRVal
Specifies the location in which the driver writes the return value of the DdVideoPortGetLine callback. A return code of DD_OK indicates success.
GetVideoPortLine
Is used by the DirectDraw API and should not be filled in by the driver.


DdVideoPortGetSignalStatus

DdVideoPortGetSignalStatus retrieves the status of the video signal currently being presented to the hardware video port.

DWORD
  (APIENTRY *PDD_VPORTCB_GETSIGNALSTATUS)(
    PDD_GETVPORTSIGNALDATA  lpGetSignalStatus
    );

Parameters

lpGetSignalStatus
Points to a DD_GETVPORTSIGNALDATA structure that contains the information required for the driver to retrieve the status of the video signal.

Return Value

DdVideoPortGetSignalStatus returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DirectDraw drivers that support VPE must implement DdVideoPortGetSignalStatus.

The driver should determine whether a valid signal is coming in to the hardware video port and report the result in dwStatus.

DD_GETVPORTSIGNALDATA

The DD_GETVPORTSIGNALDATA structure contains the signal status of the hardware video port.

typedef struct _DD_GETVPORTSIGNALDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  PDD_VIDEOPORT_LOCAL  lpVideoPort;
  DWORD  dwStatus;
  HRESULT  ddRVal;
  VOID  *GetVideoSignalStatus;
} DD_GETVPORTSIGNALDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that represents the DirectDraw object.
lpVideoPort
Points to a DD_VIDEOPORT_LOCAL structure that represents this VPE object.
dwStatus
Specifies the location in which the driver should write the status of the signal at the hardware video port. This member can be one of the following values:
Flag | Meaning
DDVPSQ_NOSIGNAL | No video signal is present at the hardware video port.
DDVPSQ_SIGNALOK | A valid video signal is present at the hardware video port.

ddRVal
Specifies the location in which the driver writes the return value of the DdVideoPortGetSignalStatus callback. A return code of DD_OK indicates success.
GetVideoSignalStatus
Is used by the DirectDraw API and should not be filled in by the driver.


DdVideoPortUpdate

DdVideoPortUpdate starts and stops the VPE object, and modifies the VPE object data stream.

DWORD
  (APIENTRY *PDD_VPORTCB_UPDATE)(
    PDD_UPDATEVPORTDATA  lpUpdate
    );

Parameters

lpUpdate
Points to a DD_UPDATEVPORTDATA structure that contains the information required for the driver to update the VPE object.

Return Value

DdVideoPortUpdate returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DirectDraw drivers that support VPE must implement DdVideoPortUpdate.

When dwFlags is DDRAWI_VPORTSTART or DDRAWI_VPORTUPDATE, the driver should do the following:

  • Check all flags in the dwVPFlags member of the DDVIDEOPORTINFO structure to which lpVideoInfo points. These flags describe how the driver should transfer video data to a surface (or surfaces); for example, they indicate whether the driver should perform autoflipping, crop the video or VBI data, etc.
  • Set up loops in the hardware to write video and/or VBI data to the surfaces in the order in which the surfaces are stored in the array(s). The driver should return as quickly as possible after setting up these loops.
  • If autoflipping has been requested, store the frame buffer offset for each surface in the driver's internal data structure. The surface offsets should be stored in the order in which the surfaces occur in the DD_SURFACE_INT arrays. In this way, when DdUpdateOverlay is called, the driver has a record of the flipping order of the surface chain.

If the dwVBIHeight member of the DDVIDEOPORTINFO structure is greater than zero and lplpDDVBISurface is not NULL, the driver should write dwVBIHeight lines of VBI data into each surface in the array to which lplpDDVBISurface points.

If the driver's hardware cannot support the number of surfaces specified when autoflipping is requested, DdVideoPortUpdate should fail the call by setting DDERR_UNSUPPORTED in ddRVal.

The number of surfaces in the video and VBI surface chains can be different; that is, dwNumAutoflip and dwNumVBIAutoflip can be different values.

When dwFlags is DDRAWI_VPORTSTOP, the driver should return immediately. The driver should not poll until the data stream stops.

DD_UPDATEVPORTDATA

The DD_UPDATEVPORTDATA structure contains the information required to start, stop, and change the VPE object.

typedef struct _DD_UPDATEVPORTDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  PDD_VIDEOPORT_LOCAL  lpVideoPort;
  PDD_SURFACE_INT  *lplpDDSurface;
  PDD_SURFACE_INT  *lplpDDVBISurface;
  PDD_VIDEOPORTINFO  lpVideoInfo;
  DWORD  dwFlags;
  DWORD  dwNumAutoflip;
  DWORD  dwNumVBIAutoflip;
  HRESULT  ddRVal;
  VOID  *UpdateVideoPort;
} DD_UPDATEVPORTDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that represents the DirectDraw object.
lpVideoPort
Points to a DD_VIDEOPORT_LOCAL structure that represents this VPE object.
lplpDDSurface
Points to an array of surface structure(s) that represent regular video surface(s). This member can be NULL.
lplpDDVBISurface
Points to an array of surface structure(s) that represent VBI surface(s). This member can be NULL.
lpVideoInfo
Points to a DDVIDEOPORTINFO structure that describes how the VPE object should transfer video data to a surface. This member can be NULL when dwFlags is DDRAWI_VPORTSTOP.
dwFlags
Indicates the action to be performed by the VPE object. This member must be one of the following values:
Flag | Meaning
DDRAWI_VPORTSTART | The driver should start the flow of data through the VPE object.
DDRAWI_VPORTSTOP | The driver should stop the flow of data through the VPE object.
DDRAWI_VPORTUPDATE | DdVideoPortUpdate has been called with a new set of flags in the dwVPFlags member of the DDVIDEOPORTINFO structure to which lpVideoInfo points. The driver should change the flow of data through the VPE object according to the new flags.

dwNumAutoflip
Specifies the number of surfaces in the list to which lplpDDSurface points. If this member is greater than 1, lplpDDSurface is an array of surface structures to accommodate autoflipping.
dwNumVBIAutoflip
Specifies the number of surfaces in the list to which lplpDDVBISurface points. If this member is greater than 1, lplpDDVIBSurface is an array of surface structures to accommodate autoflipping of VBI data.
ddRVal
Specifies the location in which the driver writes the return value of the DdVideoPortUpdate callback. A return code of DD_OK indicates success.
UpdateVideoPort
Is used by the DirectDraw API and should not be filled in by the driver.


DdVideoPortWaitForSync

DdVideoPortWaitForSync waits until the next vertical synch occurs.

DWORD
  (APIENTRY *PDD_VPORTCB_WAITFORSYNC)(
    PDD_WAITFORVPORTSYNCDATA  lpWaitForSync
    );

Parameters

lpWaitForSync
Points to a DD_WAITFORVPORTSYNCDATA structure that contains the information required for the driver to synchronize the VPE object.

Return Value

DdVideoPortWaitForSyncData returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

If the condition on which the driver is waiting does not occur before the number of milliseconds specified in dwTimeOut has elapsed, the driver should set ddRVal to DDERR_VIDEONOTACTIVE and return.

The driver must specify its own timeout criteria when dwTimeOut is zero.

DD_WAITFORVPORTSYNCDATA

The DD_WAITFORVPORTSYNCDATA structure contains the information required for the driver to synchronize the VPE object.

typedef struct _DD_WAITFORVPORTSYNCDATA {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  PDD_VIDEOPORT_LOCAL  lpVideoPort;
  DWORD  dwFlags;
  DWORD  dwLine;
  DWORD  dwTimeOut;
  HRESULT  ddRVal;
  VOID  *UpdateVideoPort;
  } DD_WAITFORVPORTSYNCDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that represents the DirectDraw object.
lpVideoPort
Points to a DD_VIDEOPORT_LOCAL structure that represents this VPE object.
dwFlags
Indicates the condition for which the driver should wait. This member can be one of the following values:
Flag | Meaning
DDVPWAIT_BEGIN | The driver should return at the beginning of the next V-sync.
DDVPWAIT_END | The driver should return at the end of the next/current V-sync.
DDVPWAIT_LINE | The driver should return at the beginning of the line specified in dwLine.

dwLine
Specifies the line number on which the driver should synchronize when dwFlags is DDVPWAIT_LINE. The driver should ignore this member when dwFlags is set to DDVPWAIT_BEGIN or DDVPWAIT_END.
dwTimeOut
Specifies the maximum amount of time the driver should wait, in milliseconds, before timing out.
ddRVal
Specifies the location in which the driver writes the return value of the DdVideoPortWaitForSync callback. A return code of DD_OK indicates success.
UpdateVideoPort
Is used by the DirectDraw API and should not be filled in by the driver.


DdWaitForVerticalBlank

DdWaitForVerticalBlank returns the vertical blank status of the device.

DWORD
  (APIENTRY *PDD_WAITFORVERTICALBLANK)(
    PDD_WAITFORVERTICALBLANKDATA  lpWaitForVerticalBlank
    );

Parameters

lpWaitForVerticalBlank
Points to a DD_WAITFORVERTICALBLANKDATA structure that contains the information required to obtain the vertical blank status.

Return Value

DdWaitForVerticalBlank returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

Depending on the value of dwFlags, the driver should do the following:

  • If dwFlags is DDWAITVB_I_TESTVB, the driver should query the current vertical blanking status. The driver should set bIsInVB to TRUE if the monitor is currently in a vertical blank; otherwise it should set it to FALSE.
  • If dwFlags is DDWAITVB_BLOCKBEGIN, the driver should block and wait until a vertical blank begins. If a vertical blank is in progress when the driver begins the block, the driver should wait until the next vertical blank begins before returning.
  • If dwFlags is DDWAITVB_BLOCKEND, the driver should block and wait until a vertical blank ends.

When the driver successfully handles the action specified in dwFlags, it should set DD_OK in ddRVal and return DDHAL_DRIVER_HANDLED. The driver should return DDHAL_DRIVER_NOTHANDLED for those flags that it is incapable of handling.

DdWaitForVerticalBlank allows an application to synchronize itself with the vertical blanking interval (VBI).

Note DdWaitForVerticalBlank should never enter a polling loop if the monitor power state will cause the driver to hang. For example, during a monitor power-down, an app might call WaitForVerticalBlank. The DirectDraw run-time calls the display driver's DdWaitForVerticalBlank entry point, which waits for the status to change. If the monitor is powered down, this value will never change - unless the driver writer prepares for this scenario. One solution is to include a timeout in the polling loop while waiting for a vertical blank. The sample Permedia2 driver is simply set to not poll at all if the monitor is powered down.

There is also an issue with the WHQL Display Compatibility Tests (DCTs). One of the DCTs for power management powers down the monitor and then polls the vertical blank status, waiting for it to change. If the driver always reports the same vertical blank status when the monitor is powered down, then the test app will hang waiting for the result to change. This was fixed in the Permedia2 sample driver by returning alternating results while the monitor is powered down. That is, the first time the driver's DdWaitForVerticalBlank entry point is called with the DDWAIT_I_TESTVB flag (when the monitor is powered down), it returns FALSE, the next time it returns TRUE, next time FALSE, etc.

DD_WAITFORVERTICALBLANKDATA

The DD_WAITFORVERTICALBLANKDATA structure contains information necessary to obtain the monitor's vertical blank information.

typedef struct _DDHAL_WAITFORVERTICALBLANKDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  DWORD  dwFlags;
  DWORD  bIsInVB;
  DWORD  hEvent;
  HRESULT  ddRVal;
  VOID  *WaitForVerticalBlank;
} DDHAL_WAITFORVERTICALBLANKDATA;

Members

lpDD
Points to the DirectDraw structure representing the DirectDraw object.
dwFlags
Specifies how the driver should wait for the vertical blank. This member can be one of the following values:
Flag | Meaning
DDWAITVB_BLOCKBEGIN | The driver should return when it detects the beginning of the vertical blank interval.
DDWAITVB_BLOCKBEGINEVENT | Set up an event to trigger when the vertical blank begins. This flag is not currently supported.
DDWAITVB_BLOCKEND | The driver should return when it detects the end of the vertical blank interval and display begins.
DDWAITVB_I_TESTVB | The driver should determine whether a vertical blank is currently occurring and return the status in bIsInVB.

bIsInVB
Indicates the status of the vertical blank. A value of TRUE indicates that the device is in a vertical blank; FALSE means that it is not. The driver should return the current vertical blanking status in this member when dwFlags is DDWAITVB_I_TESTVB.
hEvent
Is a handle for the event that should be triggered when the vertical blank begins. The event is triggered on an interrupt, so if your hardware is able to generate an interrupt on the vertical blank, you should pass this event handle to your ring 0 interrupt handler so that it is triggered when the interrupt fires. Is currently unsupported and should be ignored by the driver.
ddRVal
Specifies the location in which the driver writes the return value of the DdWaitForVerticalBlank callback. A return code of DD_OK indicates success.
WaitForVerticalBlank
Is used by the DirectDraw API and should not be filled in by the driver.


DrvDisableDirectDraw

DrvDisableDirectDraw disables hardware for DirectDraw use.

VOID
  DrvDisableDirectDraw(
    IN DHPDEV  dhpdev
    );

Parameters

dhpdev
Handle to the PDEV that was returned by the driver's DrvEnablePDEV routine.

Headers

Declared in winddi.h. Include winddi.h.

Comments

GDI calls DrvDisableDirectDraw when the last DirectDraw application has finished running. A driver's DrvDisableDirectDraw implementation should clean up any software resources and reclaim any hardware resources that the driver dedicated to DirectDraw in DrvEnableDirectDraw.


DrvEnableDirectDraw

DrvEnableDirectDraw enables hardware for DirectDraw use.

BOOL
  DrvEnableDirectDraw(
    IN DHPDEV  dhpdev,
    OUT DD_CALLBACKS  *pCallBacks,
    OUT DD_SURFACECALLBACKS  *pSurfaceCallBacks,
    OUT DD_PALETTECALLBACKS  *pPaletteCallBacks
    );

Parameters

dhpdev
Handle to the PDEV returned by the driver's DrvEnablePDEV routine.
pCallBacks
Points to the DD_CALLBACKS structure to be initialized by the driver.
pSurfaceCallBacks
Points to the DD_SURFACECALLBACKS structure to be initialized by the driver.
pPaletteCallBacks
Points to the DD_PALETTECALLBACKS structure to be initialized by the driver.

Return Value

DrvEnableDirectDraw returns TRUE if it succeeds; otherwise, it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

GDI calls DrvEnableDirectDraw to obtain pointers to the DirectDraw callbacks that the driver supports. The driver should set the function pointer members of DD_CALLBACKS, DD_SURFACECALLBACKS, and DD_PALETTECALLBACKS to point to those functions that it implements. A driver should also set the corresponding bit fields in the dwFlags members of these structures for all supported callbacks.

A driver's DrvEnableDirectDraw implementation can also dedicate hardware resources such as display memory for use by DirectDraw only.

See Also

DrvGetDirectDrawInfo


DrvGetDirectDrawInfo

DrvGetDirectDrawInfo returns the capabilities of the graphics hardware.

BOOL
  DrvGetDirectDrawInfo(
    IN DHPDEV  dhpdev,
    OUT DD_HALINFO  *pHalInfo,
    OUT DWORD  *pdwNumHeaps,
    OUT VIDEOMEMORY  *pvmList,
    OUT DWORD  *pdwNumFourCCCodes,
    OUT DWORD  *pdwFourCC
    );

Parameters

dhpdev
Handle to the PDEV returned by the driver's DrvEnablePDEV routine.
pHalInfo
Points to a DD_HALINFO structure in which the driver should return the hardware capabilities that it supports.
pdwNumHeaps
Points to the location in which the driver should return the number of VIDEOMEMORY structures pointed to by pvmList.
pvmList
Points to an array of VIDEOMEMORY structures in which the driver should return information about each display memory chunk that it controls. The driver should ignore this parameter when it is NULL.
pdwNumFourCC
Points to the location in which the driver should return the number of DWORDs pointed to by pdwFourCC.
pdwFourCC
Points to an array of DWORDs in which the driver should return information about each FOURCC that it supports. The driver should ignore this parameter when it is NULL.

Return Value

DrvGetDirectDrawInfo returns TRUE if it succeeds; otherwise, it returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The driver's DrvGetDirectDrawInfo routine should do the following:

  • When pvmList and pdwFourCC are NULL:
    1. Reserve offscreen display memory for DirectDraw use.
    2. Write the number of driver display memory heaps and supported FOURCCs in pdwNumHeaps and pdwNumFourCC, respectively.
  • When pvmList and pdwFourCC are not NULL:
    1. Write the number of driver display memory heaps and supported FOURCCs in pdwNumHeaps and pdwNumFourCC, respectively.
    2. For each VIDEOMEMORY structure in the list to which pvmList points, fill in the appropriate members to describe a particular chunk of display memory. The list of structures provides DirectDraw with a complete description of the driver's offscreen memory.
  • Initialize the members of the DD_HALINFO structure with driver-specific information as follows:
    1. Initialize the appropriate members of the VIDEOMEMORYINFO structure to describe the general characteristics of the display's memory.
    2. Initialize the appropriate members of the DDCORECAPS structure to describe the capabilities of the hardware.
    3. If the driver implements a DdGetDriverInfo function, set GetDriverInfo to point to it and set dwFlags to DDHALINFO_GETDRIVERINFOSET.

See Also

DD_HALINFO, DdGetDriverInfo, DrvEnableDirectDraw, VIDEOMEMORY, VIDEOMEMORYINFO


DxApi

DxApi is a single entry point in DirectDraw that accepts commands from the hardware decoder to access the DxApi miniport functions.

DWORD
  FAR PASCAL DxApi(
    IN DWORD  dwFunctionNum,
    IN LPVOID  lpvInBuffer,
    IN DWORD  cbInBuffer,
    OUT LPVOID  lpvOutBuffer,
    OUT DWORD  cbOutBuffer
    );

Parameters

dwFunctionNum
Indicates the behavior of the DxApi function (function identifier). See the comments section for the list of function identifiers.
lpvInBuffer
Points to the input buffer.
cbInBuffer
Indicates the size in bytes of the input buffer.
lpvOutBuffer
Points to the output buffer.
cbOutBuffer
Indicates the size in bytes of the output buffer.

Return Value

DxApi returns the number of bytes actually written to the output buffer.

Headers

Declared in ddkmapi.h. Include ddkmapi.h.

Comments

DxApi accepts a function identifier (dwFunctionNum), an input buffer (lpvInBuffer) and its size (cbInBuffer), and an output buffer (lpvOutBuffer) and its size (cbOutBuffer). The behavior of the function and the size and format of the input and output buffers depend on the specified function identifier. The return value is the number of actual bytes written into the output buffer.

The following function identifiers are defined for the DxApi function in the ddkmapi.h header file:

DD_DXAPI_ADDVPCAPTUREBUFFER

DD_DXAPI_CLOSEHANDLE

DD_DXAPI_FLIP_OVERLAY

DD_DXAPI_FLIP_VP

DD_DXAPI_FLUSHVPCAPTUREBUFFERS

DD_DXAPI_GET_CURRENT_VP_AUTOFLIP_SURFACE

DD_DXAPI_GET_LAST_VP_AUTOFLIP_SURFACE

DD_DXAPI_GET_POLARITY

DD_DXAPI_GET_SURFACE_STATE

DD_DXAPI_GET_VP_FIELD_NUMBER

DD_DXAPI_GETKERNELCAPS

DD_DXAPI_GETVERSIONNUMBER

DD_DXAPI_LOCK

DD_DXAPI_OPENDIRECTDRAW

DD_DXAPI_OPENSURFACE

DD_DXAPI_OPENVIDEOPORT

DD_DXAPI_OPENVPCAPTUREDEVICE

DD_DXAPI_REGISTER_CALLBACK

DD_DXAPI_SET_SURFACE_STATE

DD_DXAPI_SET_VP_FIELD_NUMBER

DD_DXAPI_SET_VP_SKIP_FIELD

DD_DXAPI_UNREGISTER_CALLBACK


DD_DXAPI_ADDVPCAPTUREBUFFER

DD_DXAPI_ADDVPCAPTUREBUFFER adds a new capture buffer to the internal video port capture queue. Each time a hardware video port V-sync occurs, the kernel-mode video transport determines whether the previous field needs to be captured and if so, initiates a bus master to the next buffer in the queue.

When this function identifier is used as the dwFunctionNum parameter of the DxApi function, the input and output buffer parameters of DxApi are defined as:

lpvInBuffer
Points to a DDADDVPCAPTUREBUFF structure that contains the information required to add a new buffer.
lpvOutBuffer
Points to a DWORD (ddRVal) that contains the DirectDraw return value.

Comments

This function identifier can be called at raised IRQL.

DDADDVPCAPTUREBUFF

The DDADDVPCAPTUREBUFF structure contains the information required to add a new buffer to the internal capture queue.

typedef struct _DDADDVPCAPTUREBUFF {
  HANDLE  hCapture;
  DWORD  dwFlags;
  PMDL  pMDL;
  PKEVENT  pKEvent;
  LPDDCAPBUFFINFO  lpBuffInfo;
} DDADDVPCAPTUREBUFF, FAR * LPDDADDVPCAPTUREBUFF;

Members

hCapture
Contains the VPE capture handle.
dwFlags
Indicates whether the destination buffer exists in regular system memory or nonlocal display memory (AGP). One of the following:
Flag | Meaning
DDADDBUFF_INVERT | The buffer is to be inverted during capture.
DDADDBUFF_NONLOCALVIDMEM | The destination buffer exists in nonlocal display memory.
DDADDBUFF_SYSTEMMEMORY | The destination buffer exists in system memory.

pMDL
Points to an MDL (defined in wdm.h) that describes the physical pages of the destination buffer.
pKEvent
Points to a KEVENT that the kernel-mode video transport sets when the destination has been filled.
lpBuffInfo
Points to a DDCAPBUFFINFO structure that the kernel-mode video transport fills in before setting the KEVENT.

DDCAPBUFFINFO

The DDCAPBUFFINFO structure contains the capture information.

typedef struct _DDCAPBUFFINFO {
  DWORD  dwFieldNumber;
  DWORD  bPolarity;
  LARGE_INTEGER  liTimeStamp;
  DWORD  ddRVal;
} DDCAPBUFFINFO, FAR * LPDDCAPBUFFINFO;

Members

dwFieldNumber
Indicates the internal field number of the field captured.
bPolarity
Specifies whether the captured field is an even or odd field.
liTimeStamp
Is used by DirectDraw and should be ignored by the driver.
ddRVal
Specifies the location in which the driver writes the return value. Contains DD_OK if the capture buffer contains valid data.


DD_DXAPI_CLOSEHANDLE

DD_DXAPI_CLOSEHANDLE closes the kernel-mode handle.

When this function identifier is used as the dwFunctionNum parameter of the DxApi function, the input and output buffer parameters of DxApi are defined as:

lpvInBuffer
Points to the DDCLOSEHANDLE structure that contains the appropriate handle.
lpvOutBuffer
Points to a DWORD (ddRVal) that contains the DirectDraw return value.

The input buffer specifies the DirectDraw object, surface, VPE object, or VPE capture handle that needs to be closed. Calling this function identifier does not cause the corresponding close routines to be called. The output from this function identifier is a DirectDraw return code. This function identifier can only be called at passive level .

DDCLOSEHANDLE

The DDCLOSEHANDLE structure contains the DirectDraw object, surface, VPE object, or VPE capture handle.

typedef struct _DDCLOSEHANDLE {
  HANDLE  hHandle;
} DDCLOSEHANDLE, FAR *LPDDCLOSEHANDLE;

Members

hHandle
Specifies the handle to be closed.


DD_DXAPI_FLIP_OVERLAY

DD_DXAPI_FLIP_OVERLAY flips the overlay to display the other surface.

When this function identifier is used as the dwFunctionNum parameter of the DxApi function, the input and output buffer parameters of DxApi are defined as:

lpvInBuffer
Points to a DDFLIPOVERLAY structure that contains the surface information required for the flip.
lpvOutBuffer
Points to a DWORD (ddRVal) that contains the DirectDraw return value.

Comments

This call does not rotate the memory pointers as does the user-mode DdFlip function, so it is up to the client to keep track of which surface is visible and which is not. The dwFlags member of the DDFLIPOVERLAY structure can contain DDFLIP_EVEN or DDFLIP_ODD to accommodate bob mode when not using a hardware video port. If the overlay is associated with a hardware video port, the hardware video port is not automatically flipped. This function identifier cannot be called while autoflipping.

This function identifier can be called at raised IRQL.

DDFLIPOVERLAY

The DDFLIPOVERLAY structure contains the surface information required for the flip.

typedef struct _DDFLIPOVERLAY {
  HANDLE  hDirectDraw;
  HANDLE  hCurrentSurface;
  HANDLE  hTargetSurface;
  DWORD   dwFlags;
} DDFLIPOVERLAY, FAR *LPDDFLIPOVERLAY;

Members

hDirectDraw
Specifies the DirectDraw handle.
hCurrentSurface
Specifies the current DirectDrawSurface handle.
hTargetSurface
Specifies the handle of the DirectDrawSurface to which the flip occurs.
dwFlags
Flags specifying flip options.
Flag | Meaning
DDFLIP_EVEN | For use only when displaying video in an overlay surface. The new surface contains data from the even field of a video signal. This flag cannot be used with the DDFLIP_ODD flag.
DDFLIP_ODD | For use only when displaying video in an overlay surface. The new surface contains data from the odd field of a video signal. This flag cannot be used with the DDFLIP_EVEN flag.


DD_DXAPI_FLIP_VP

DD_DXAPI_FLIP_VP causes the hardware video port to write data to a different surface.

When this function identifier is used as the dwFunctionNum parameter of the DxApi function, the input and output buffer parameters of DxApi are defined as:

lpvInBuffer
Points to a DDFLIPVIDEOPORT structure that contains the handle information required to flip the hardware video port.
lpvOutBuffer
Points to a DWORD (ddRVal) that contains the DirectDraw return value.

The dwFlags member of the DDFLIPVIDEOPORT structure should contain DDVPFLIP_VIDEO or DDVPFLIP_VBI to indicate whether the video or the VBI region of the video signal should be flipped. To flip both regions, this function identifier should be called twice. This function identifier cannot be called while autoflipping.

This function identifier can be called from raised IRQL.

DDFLIPVIDEOPORT

The DDFLIPVIDEOPORT structure contains the information required to flip the hardware video port.

typedef struct _DDFLIPVIDEOPORT {
  HANDLE  hDirectDraw;
  HANDLE  hVideoPort;
  HANDLE  hCurrentSurface;
  HANDLE  hTargetSurface;
  DWORD  dwFlags;
} DDFLIPVIDEOPORT, FAR *LPDDFLIPVIDEOPORT;

Members

hDirectDraw
Specifies the DirectDraw handle.
hVideoPort
Specifies the VPE object handle.
hCurrentSurface
Specifies the current DirectDrawSurface handle.
hTargetSurface
Specifies the handle of the DirectDrawSurface to which the flip occurs.
dwFlags
Indicates whether the surfaces represent VBI surfaces or regular surfaces. One of the following:
Flag | Meaning
DDVPFLIP_VBI | Flips the VBI surface.
DDVPFLIP_VIDEO | Flips the normal video surface.


DD_DXAPI_FLUSHVPCAPTUREBUFFERS

DD_DXAPI_FLUSHVPCAPTUREBUFFERS removes all buffers from the capture queue and stops video capture for that device.

When this function identifier is used as the dwFunctionNum parameter of the DxApi function, the input and output buffer parameters of DxApi are defined as:

lpvInBuffer
Contains the VPE capture handle (HANDLE hCapture;).
lpvOutBuffer
Points to a DWORD (ddRVal) that contains the DirectDraw return value.

Comments

All KEVENTs that have been registered using the DD_DXAPI_ADDVPCAPTUREBUFFER function identifier will be set. This function identifier can be called at raised IRQL.


DD_DXAPI_GET_CURRENT_VP_AUTOFLIP_SURFACE

DD_DXAPI_GET_CURRENT_VP_AUTOFLIP_SURFACE returns the surface(s) handles that are receiving the current video and VBI data from the hardware video port.

When this function identifier is used as the dwFunctionNum parameter of the DxApi function, the input and output buffer parameters of DxApi are defined as:

lpvInBuffer
Points to a DDGETAUTOFLIPIN structure that contains the required handle information.
lpvOutBuffer
Points to a DDGETAUTOFLIPOUT structure that contains the surface information and the VBI data from the hardware video port.

Comments

An error is returned if the hardware video port is not in autoflip mode. It also returns the polarity of the current field, where the bPolarity member of the DDGETAUTOFLIPOUT structure is set to TRUE if the current field is the even field of an interlaced video signal.

This function identifier can be called at raised IRQL.

DDGETAUTOFLIPIN

The DDGETAUTOFLIPIN structure contains the handle information.

typedef struct _DDGETAUTOFLIPIN {
  HANDLE  hDirectDraw;
  HANDLE  hVideoPort;
} DDGETAUTOFLIPIN, FAR *LPDDGETAUTOFLIPIN;

Members

hDirectDraw
Specifies the DirectDraw handle.
hVideoPort
Specifies the VPE object handle.

DDGETAUTOFLIPOUT

The DDGETAUTOFLIPOUT structure contains the handle and polarity information returned from the DD_DXAPI_GET_CURRENT_VP_AUTOFLIP_SURFACE and DD_DXAPI_GET_LAST_VP_AUTOFLIP_SURFACE function identifiers of the DxApi function.

typedef struct _DDGETAUTOFLIPOUT {
  DWORD   ddRVal;
  HANDLE  hVideoSurface;
  HANDLE  hVBISurface;
  BOOL  bPolarity;
} DDGETAUTOFLIPOUT, FAR *LPDDGETAUTOFLIPOUT;

Members

ddRVal
Specifies the location in which the driver writes the return value. A return code of DD_OK indicates success.
hVideoSurface
Specifies the handle for the current video surface.
hVBISurface
Specifies the handle for the current VBI data.
bPolarity
Specifies whether the field is an even or odd field of an interlaced video signal.


DD_DXAPI_GET_LAST_VP_AUTOFLIP_SURFACE

DD_DXAPI_GET_LAST_VP_AUTOFLIP_SURFACE returns the surface(s) handles that received the most recent field of data written to the frame buffer (taking field skipping into account).

When this function identifier is used as the dwFunctionNum parameter of the DxApi function, the input and output buffer parameters of DxApi are defined as:

lpvInBuffer
Points to a DDGETAUTOFLIPIN structure that contains the required handle information.
lpvOutBuffer
Points to a DDGETAUTOFLIPOUT structure that contains the surface information and the VBI data from the hardware video port.

Comments

The surfaces returned by this function identifier may be the same surfaces that are receiving the current field if the hardware video port is interleaving the data. This function identifier also returns the polarity of the field most recently written to the frame buffer, where the bPolarity member of the DDGETAUTOFLIPOUT structure is set to TRUE if the field was the even field of an interlaced video signal. An error is returned if the hardware video port is not in autoflip mode.

This function identifier can be called at raised IRQL.


DD_DXAPI_GET_POLARITY

DD_DXAPI_GET_POLARITY returns the polarity of the current hardware video port field.

When this function identifier is used as the dwFunctionNum parameter of the DxApi function, the input and output buffer parameters of DxApi are defined as:

lpvInBuffer
Points to a DDGETPOLARITYIN structure that contains the handle information.
lpvOutBuffer
Points to a DDGETPOLARITYOUT structure that contains the polarity information.

Comments

The bPolarity member of the DDGETPOLARITYOUT structure is set to TRUE if the current field is the even field of an interlaced video signal. This function identifier can be called at raised IRQL.

DDGETPOLARITYIN

The DDGETPOLARITYIN structure contains the DirectDraw and VPE object handles.

typedef struct _DDGETPOLARITYIN {
  HANDLE  hDirectDraw;
  HANDLE  hVideoPort;
} DDGETPOLARITYIN, FAR *LPDDGETPOLARITYIN;

Members

hDirectDraw
Specifies the DirectDraw handle.
hVideoPort
Specifies the VPE object handle.

DDGETPOLARITYOUT

The DDGETPOLARITYOUT structure contains the requested polarity information.

typedef struct _DDGETPOLARITYOUT {
  DWORD  ddRVal;
  BOOL  bPolarity;
} DDGETPOLARITYOUT, FAR *LPDDGETPOLARITYOUT;

Members

ddRVal
Specifies the location in which the driver writes the return value. A return code of DD_OK indicates success.
bPolarity
Specifies whether the field is an even or odd field of an interlaced video signal.


DD_DXAPI_GET_SURFACE_STATE

DD_DXAPI_GET_SURFACE_STATE indicates whether the overlay surface is in bob or weave mode and whether it can be put into bob or weave mode.

When this function identifier is used as the dwFunctionNum parameter of the DxApi function, the input and output buffer parameters of DxApi are defined as:

lpvInBuffer
Points to a DDGETSURFACESTATEIN structure that contains the surface handle.
lpvOutBuffer
Points to a DDGETSURFACESTATEOUT structure that contains the surface capabilities.

Comments

The dwStateCaps member of the DDGETSURFACESTATEOUT structure returns its capabilities, including DDSTATE_BOB and DDSTATE_WEAVE. The dwStateStatus member can return DDSTATE_BOB, DDSTATE_WEAVE, DDSTATE_SOFTWARE_AUTOFLIP (so the caller can know whether the hardware is using software or hardware autoflipping) and DDSTATE_EXPLICITLY_SET (indicating the caller is in this state due to a previous DD_DXAPI_SET_SURFACE_STATE call).

This function identifier can be called at raised IRQL.

DDGETSURFACESTATEIN

The DDGETSURFACESTATEIN structure contains the DirectDraw and DirectDraw surface handle information.

typedef struct _DDGETSURFACESTATEIN {
  HANDLE  hDirectDraw;
  HANDLE  hSurface;
} DDGETSURFACESTATEIN, FAR *LPDDGETSURFACESTATEIN;

Members

hDirectDraw
Specifies the DirectDraw handle.
hSurface
Specifies the DirectDrawSurface handle.

DDGETSURFACESTATEOUT

The DDGETSURFACESTATEOUT structure contains the capabilities and status of the specified surface.

typedef struct _DDGETSURFACESTATEOUT {
  DWORD  ddRVal;
  DWORD  dwStateCaps;
  DWORD  dwStateStatus;
} DDGETSURFACESTATEOUT, FAR *LPDDGETSURFACESTATEOUT;

Members

ddRVal
Specifies the location in which the driver writes the return value. A return code of DD_OK indicates success.
dwStateCaps
Contains the DirectDrawSurface's capabilities of the device. One or more of the following:
Flag | Meaning
DDSTATE_BOB | The device is capable of performing bob mode.
DDSTATE_WEAVE | The device is capable of performing weave mode.

dwStateStatus
Contains the status of the selected DirectDrawSurface. One or more of the following:
Flag | Meaning
DDSTATE_BOB | Bob mode is being used on this surface.
DDSTATE_EXPLICITLY_SET | This state is due to a previous DD_DXAPI_SET_SURFACE_STATE call.
DDSTATE_SKIPEVENFIELDS | Stop bob or weave mode and skip every other field instead.
DDSTATE_SOFTWARE_AUTOFLIP | Software (as opposed to hardware) autoflipping is being used.
DDSTATE_WEAVE | Weave mode is being used on this surface.


DD_DXAPI_GET_VP_FIELD_NUMBER

DD_DXAPI_GET_VP_FIELD_NUMBER returns the field number of the current hardware video port field.

When this function identifier is used as the dwFunctionNum parameter of the DxApi function, the input and output buffer parameters of DxApi are defined as:

lpvInBuffer
Points to a DDGETFIELDNUMIN structure that contains the required DirectDraw and VPE object handles.
lpvOutBuffer
Points to a DDGETFIELDNUMOUT structure that contains the field number.

Comments

This function identifier can be used when using the VPE capture functions, because they also return the field number being captured. This function identifier can be called at raised IRQL.

DDGETFIELDNUMIN

The DDGETFIELDNUMIN structure contains the DirectDraw and VPE object handle information.

typedef struct _DDGETFIELDNUMIN {
  HANDLE  hDirectDraw;
  HANDLE  hVideoPort;
} DDGETFIELDNUMIN, FAR *LPDDGETFIELDNUMIN;

Members

hDirectDraw
Specifies the DirectDraw handle.
hVideoPort
Specifies the VPE object handle.

DDGETFIELDNUMOUT

The DDGETFIELDNUMOUT structure contains the hardware video port's field number.

typedef struct _DDGETFIELDNUMOUT {
  DWORD  ddRVal;
  DWORD  dwFieldNum;
} DDGETFIELDNUMOUT, FAR *LPDDGETFIELDNUMOUT;

Members

ddRVal
Specifies the location in which the driver writes the return value. A return code of DD_OK indicates success.
dwFieldNum
Specifies the hardware video port's field number.


DD_DXAPI_GETKERNELCAPS

DD_DXAPI_GETKERNELCAPS returns the capabilities of this kernel-mode device.

When this function identifier is used as the dwFunctionNum parameter of the DxApi function, the input and output buffer parameters of DxApi are defined as:

lpvInBuffer
Contains the DirectDraw handle (HANDLE hDirectDraw;).
lpvOutBuffer
Points to a DDGETKERNELCAPSOUT structure that contains the capabilities of the specified DirectDraw object.

Comments

The hDirectDraw handle specifies the DirectDraw object for which to return the kernel-mode capabilities. The dwCaps member of the DDGETKERNELCAPSOUT structure contains the DDKERNELCAPS_XXX flags defined in ddkernel.h and the dwIRQCaps member contains the DDIRQ_XXX flags defined in ddkernel.h. This function identifier can only be called at passive level.

DDGETKERNELCAPSOUT

The DDGETKERNELCAPSOUT structure contains the capabilities of the DirectDraw object.

typedef struct _DDGETKERNELCAPSOUT {
  DWORD  ddRVal;
  DWORD  dwCaps;
  DWORD  dwIRQCaps;
} DDGETKERNELCAPSOUT, FAR *LPDDGETKERNELCAPSOUT;

Members

ddRVal
Specifies the location in which the driver writes the return value. A return code of DD_OK indicates success.
dwCaps
Can be any combination of the capabilities in the dwCaps field of DDKERNELCAPS.
dwIRQCaps
Can be a combination of the flags in the dwIRQCaps field of DDKERNELCAPS.


DD_DXAPI_GETVERSIONNUMBER

DD_DXAPI_GETVERSIONNUMBER returns the version of the kernel-mode video transport supported by this interface.

When this function identifier is used as the dwFunctionNum parameter of the DxApi function, the input and output buffer parameters of DxApi are defined as:

lpvInBuffer
NULL.
lpvOutBuffer
Points to a DDGETVERSIONNUMBER structure that contains the DirectDraw version number.

Comments

This function identifier can only be called at passive level.

DDGETVERSIONNUMBER

The DDGETVERSIONNUMBER structure contains the version number information.

typedef struct _DDGETVERSIONNUMBER {
  DWORD  ddRVal;
  DWORD  dwMajorVersion;
  DWORD  dwMinorVersion;
} DDGETVERSIONNUMBER, FAR *LPDDGETVERSIONNUMBER;

Members

ddRVal
Specifies the location in which the driver writes the return value. A return code of DD_OK indicates success.
dwMajorVersion
Specifies the DirectDraw major version number.
dwMinorVersion
Specifies the DirectDraw minor version number.


DD_DXAPI_LOCK

DD_DXAPI_LOCK allows the client to access the surface for an indefinite amount of time.

When this function identifier is used as the dwFunctionNum parameter of the DxApi function, the input and output buffer parameters of DxApi are defined as:

lpvInBuffer
Points to a DDLOCKIN structure that contains the handle information required for the lock.
lpvOutBuffer
Points to a DDLOCKOUT structure that contains the surface information from the surface that is locked.

Comments

If the surface ever becomes unusable due to a fullscreen command prompt, a resolution change, and so on, the pfnSurfaceClose callback specified in the DD_DXAPI_OPENSURFACE function identifier is called to notify the client that it should no longer access this surface.

The lpSurface member of the DDLOCKOUT structure contains the pointer that can be used to access the surface. The other members of the DDLOCKOUT structure relate closely to their counterparts in the DDSURFACEDESC structure (dwSurfWidth correlates to dwWidth, SurfaceCaps correlates to ddsCaps, dwFormatFlags correlates to ddpfPixelFormat.dwFlags, and so on).

There is no corresponding Unlock function identifier.

This function identifier can only be called from passive level.

DDLOCKIN

The DDLOCKIN structure contains the DirectDraw object and DirectDraw surface handle information.

typedef struct _DDLOCKIN {
  HANDLE  hDirectDraw;
  HANDLE  hSurface;
} DDLOCKIN, FAR *LPDDLOCKIN;

Members

hDirectDraw
Specifies the DirectDraw handle.
hSurface
Specifies the DirectDrawSurface handle.

DDLOCKOUT

The DDLOCKOUT structure contains a description of the surface.

typedef struct _DDLOCKOUT {
  DWORD  ddRVal;
  DWORD  dwSurfHeight;
  DWORD  dwSurfWidth;
  LONG   lSurfPitch;
  PVOID  lpSurface;
  DWORD  SurfaceCaps;
  DWORD  dwFormatFlags;
  DWORD  dwFormatFourCC;
  DWORD  dwFormatBitCount;
  union
  {
      DWORD  dwRBitMask;
      DWORD  dwYBitMask;
  };
  union
  {
      DWORD  dwGBitMask;
      DWORD  dwUBitMask;
  };
  union
  {
      DWORD  dwBBitMask;
      DWORD  dwVBitMask;
  };
} DDLOCKOUT, FAR *LPDDLOCKOUT;

Members

ddRVal
Specifies the location in which the driver writes the return value. A return code of DD_OK indicates success.
dwSurfHeight, dwSurfWidth
Specify the dimensions of the surface, in pixels.
lSurfPitch
Specifies the distance, in bytes, to the start of the next line.
lpSurface
Points to the surface memory.
SurfaceCaps
Is a set of flags that specify the capabilities of the surface. This member can be set to one or more of the following flags:
Flag | Meaning
DDSCAPS_3DDEVICE | This surface can be used for 3D rendering. Applications can use this flag to ensure that a device that can only render to a certain heap has offscreen surfaces allocated from the correct heap. If this flag is set for a heap, the surface is not allocated from that heap.
DDSCAPS_ALLOCONLOAD | Memory for the surface is not allocated until the surface is loaded by the application using the IDirect3DDevice7::Load method.
DDSCAPS_ALPHA | This surface contains alpha information. The pixel format must be queried to determine whether this surface contains only alpha information or alpha information interlaced with pixel color data (such as RGBA or YUVA).
DDSCAPS_BACKBUFFER | This surface is the back buffer of a surface flipping structure. Typically, this capability is set by the application's CreateSurface method when the DDSCAPS_FLIP flag is used. Only the surface that immediately precedes the DDSCAPS_FRONTBUFFER surface has this capability set. The other surfaces are identified as back buffers by the presence of the DDSCAPS_FLIP flag, their attachment order, and the absence of the DDSCAPS_FRONTBUFFER and DDSCAPS_BACKBUFFER capabilities. If this capability is sent to the application's CreateSurface method, a stand-alone back buffer is being created. After this method is called, this surface could be attached to a front buffer, another back buffer, or both to form a flipping surface structure. For more information, see the AddAttachedSurface method in the DirectX SDK documentation. DirectDraw supports an arbitrary number of surfaces in a flipping structure.
DDSCAPS_COMPLEX | A complex surface is being described. A complex surface results in the creation of more than one surface. The additional surfaces are attached to the root surface. The complex structure can be destroyed only by destroying the root.
DDSCAPS_FLIP | This surface is a part of a surface flipping structure. When this capability is passed to the application's CreateSurface method, a front buffer and one or more back buffers are created. DirectDraw sets the DDSCAPS_FRONTBUFFER bit on the front-buffer surface and the DDSCAPS_BACKBUFFER bit on the surface adjacent to the front-buffer surface. The dwBackBufferCount member of the DDSURFACEDESC structure must be set to at least 1 in order for the method call to succeed. The DDSCAPS_COMPLEX capability must always be set when creating multiple surfaces by using the CreateSurface method.
DDSCAPS_FRONTBUFFER | This surface is the front buffer of a surface flipping structure. This flag is typically set by the application's CreateSurface method when the DDSCAPS_FLIP capability is set. If this capability is sent to the CreateSurface method, a stand-alone front buffer is created. This surface will not have the DDSCAPS_FLIP capability. It can be attached to other back buffers to form a flipping structure by using the application's AddAttachedSurface method.
DDSCAPS_HWCODEC | This surface should be able to have a stream decompressed to it by the hardware.
DDSCAPS_LIVEVIDEO | This surface should be able to receive live video.
DDSCAPS_LOCALVIDMEM | This surface exists in true, local display memory rather than nonlocal display memory. If this flag is specified then DDSCAPS_VIDEOMEMORY must be specified as well. This flag cannot be used with the DDSCAPS_NONLOCALVIDMEM flag.
DDSCAPS_MIPMAP | This surface is one level of a mipmap. This surface will be attached to other DDSCAPS_MIPMAP surfaces to form the mipmap. This can be done explicitly by creating a number of surfaces and attaching them by using the application's AddAttachedSurface method, or implicitly by the application's CreateSurface method. If this capability is set, DDSCAPS_TEXTURE must also be set.
DDSCAPS_MODEX | This surface is a 320×200 or 320×240 Mode X surface.
DDSCAPS_NONLOCALVIDMEM | This surface exists in nonlocal display memory rather than true, local display memory. If this flag is specified, then DDSCAPS_VIDEOMEMORY flag must be specified as well. This cannot be used with the DDSCAPS_LOCALVIDMEM flag.
DDSCAPS_OFFSCREENPLAIN | This surface is any offscreen surface that is not an overlay, texture, z-buffer, front-buffer, back-buffer, or alpha surface. It is used to identify plain surfaces.
DDSCAPS_OPTIMIZED | Not currently implemented.
DDSCAPS_OVERLAY | This surface is an overlay. It may or may not be directly visible depending on whether it is currently being overlaid onto the primary surface. DDSCAPS_VISIBLE can be used to determine if it is being overlaid at the moment.
DDSCAPS_OWNDC | This surface will have a device context (DC) association for a long period.
DDSCAPS_PALETTE | This device driver allows unique DirectDrawPalette objects to be created and attached to this surface.
DDSCAPS_PRIMARYSURFACE | The surface is the primary surface. It represents what is visible to the user at the moment.
DDSCAPS_PRIMARYSURFACELEFT | This surface is the primary surface for the left eye. It represents what is visible to the user's left eye at the moment. When this surface is created, the surface with the DDSCAPS_PRIMARYSURFACE capability represents what is seen by the user's right eye.
DDSCAPS_STANDARDVGAMODE | This surface is a standard VGA mode surface, and not a ModeX surface. This flag cannot be used in combination with the DDSCAPS_MODEX flag.
DDSCAPS_SYSTEMMEMORY | This surface memory was allocated in system memory.
DDSCAPS_TEXTURE | This surface can be used as a 3D texture. It does not indicate whether the surface is being used for that purpose.
DDSCAPS_VIDEOMEMORY | This surface exists in display memory.
DDSCAPS_VIDEOPORT | This surface can receive data from a hardware video port.
DDSCAPS_VISIBLE | Changes made to this surface are immediately visible. It is always set for the primary surface, as well as for overlays while they are being overlaid and texture maps while they are being textured.
DDSCAPS_WRITEONLY | Only write access is permitted to the surface. Read access from the surface may generate a general protection fault (GPF), but the read results from this surface are not meaningful.
DDSCAPS_ZBUFFER | This surface is the z-buffer. The z-buffer contains information that cannot be displayed. Instead, it contains bit-depth information that is used to determine which pixels are visible and which are obscured.

dwFormatFlags
Is a set of optional control flags. This member can be set to a combination of the following flags:
Flag | Meaning
DDPF_ALPHA | The pixel format describes an alpha-only surface.
DDPF_ALPHAPIXELS | The surface has alpha channel information in the pixel format.
DDPF_ALPHAPREMULT | Reserved for system use.
DDPF_BUMPDUDV | Bump map dUdV data in the pixel format is valid.
DDPF_BUMPLUMINANCE | Luminance data in pixel format is valid. This flag is used when hanging luminance off bumpmap surfaces; the bit mask for the luminance portion of the pixel is then indicated by the dwBumpLuminanceBitCount member of the DDPIXELFORMAT structure.
DDPF_COMPRESSED | The surface accepts pixel data in the specified format and compresses it during the write operation.
DDPF_FOURCC | The FourCC code is valid.
DDPF_LUMINANCE | Luminance data in the pixel format is valid. This flag is used for luminance only or luminance plus alpha surfaces; the bit depth is then indicated by the dwLuminanceBitCount member of the DDPIXELFORMAT structure.
DDPF_PALETTEINDEXED1 | The surface is 1-bit color indexed.
DDPF_PALETTEINDEXED2 | The surface is 2-bit color indexed.
DDPF_PALETTEINDEXED4 | The surface is 4-bit color indexed.
DDPF_PALETTEINDEXED8 | The surface is 8-bit color indexed.
DDPF_PALETTEINDEXEDTO8 | The surface is 1-, 2-, or 4-bit color indexed to an 8-bit palette.
DDPF_RGB | The RGB data in the pixel format structure is valid.
DDPF_RGBTOYUV | The surface accepts RGB data and translates it during the write operation to YUV data. The format of the data to be written is contained in the pixel format structure. The DDPF_RGB flag is set.
DDPF_STENCILBUFFER | The surface contains stencil information along with the Z information.
DDPF_YUV | The YUV data in the pixel format structure is valid.
DDPF_ZBUFFER | The pixel format describes a z-buffer-only surface.
DDPF_ZPIXELS | The surface is in RGBZ format.

dwFormatFourCC
Specifies the FourCC code. For more information on FourCC codes, see the DirectX SDK documentation.
dwFormatBitCount
Specifies the number of bits per pixel (4, 8, 16, 24, or 32) of the RGB or YUV data.
dwRBitMask
Specifies the mask for red bits.
dwYBitMask
Specifies the mask for Y bits.
dwGBitMask
Specifies the mask for green bits.
dwUBitMask
Specifies the mask for U bits.
dwBBitMask
Specifies the mask for blue bits.
dwVBitMask
Specifies the mask for V bits.


DD_DXAPI_OPENDIRECTDRAW

DD_DXAPI_OPENDIRECTDRAW notifies the kernel-mode video transport that the driver wants to use a DirectDraw object.

When this function identifier is used as the dwFunctionNum parameter of the DxApi function, the input and output buffer parameters of DxApi are defined as:

lpvInBuffer
Points to a DDOPENDIRECTDRAWIN structure that contains the DirectDraw handle information.
lpvOutBuffer
Points to a DDOPENDIRECTDRAWOUT structure that contains the new DirectDraw handle information.

Comments

The object is specified by the dwDirectDrawHandle member of the DDOPENDIRECTDRAWIN structure, which is the handle passed down from user mode. The driver must also specify a callback that is called if the DirectDraw object goes away. The pContext member of the DDOPENDIRECTDRAWIN structure contains a value that is passed if the pfnDirectDrawClose callback is ever called.

If ddRVal is set to DD_OK, the output from this function identifier is a DirectDraw return code and a new DirectDraw handle. This new handle must be used on all subsequent calls that require a DirectDraw handle.

This function identifier can only be called at passive level.

DDOPENDIRECTDRAWIN

The DDOPENDIRECTDRAWIN structure contains the DirectDraw object information.

typedef struct _DDOPENDIRECTDRAWIN {
  ULONG_PTR  dwDirectDrawHandle;
  LPDD_NOTIFYCALLBACK  pfnDirectDrawClose;
  PVOID  pContext;
} DDOPENDIRECTDRAWIN, FAR *LPDDOPENDIRECTDRAWIN;

Members

dwDirectDrawHandle
Contains the DirectDraw handle that was passed down from user mode.
pfnDirectDrawClose
Points to a pfnDirectDrawClose callback function that is called if the DirectDraw object goes away.
pContext
Contains a value that is passed if the pfnDirectDrawClose callback is ever called.

DDOPENDIRECTDRAWOUT

The DDOPENDIRECTDRAWOUT structure contains a DirectDraw return code and a new DirectDraw handle for the DD_DXAPI_OPENDIRECTDRAW function identifier of the DxApi function if ddRVal is set to DD_OK. This new handle must be used on all subsequent calls that require a DirectDraw handle.

typedef struct _DDOPENDIRECTDRAWOUT {
  DWORD  ddRVal;
  HANDLE  hDirectDraw;
} DDOPENDIRECTDRAWOUT, FAR *LPDDOPENDIRECTDRAWOUT;

Members

ddRVal
Specifies the location in which the driver writes the return value. A return code of DD_OK indicates success.
hDirectDraw
Contains the new DirectDraw handle.


DD_DXAPI_OPENSURFACE

DD_DXAPI_OPENSURFACE notifies the kernel-mode video transport that the driver wants to use a surface object.

When this function identifier is used as the dwFunctionNum parameter of the DxApi function, the input and output buffer parameters of DxApi are defined as:

lpvInBuffer
Points to a DDOPENSURFACEIN structure that contains the DirectDrawSurface object information.
lpvOutBuffer
Points to a DDOPENSURFACEOUT structure that contains the new DirectDrawSurface handle information.

Comments

The object is specified by the dwSurfaceHandle member of the DDOPENSURFACEIN structure, which is the handle passed down from user mode. The hDirectDraw member specifies the DirectDraw object with which it is associated. The driver must also specify a callback that is called when the surface becomes unusable due to it being released at user mode, a fullscreen command prompt, or a mode change. The pContext member contains a value that is passed if the pfnSurfaceClose callback function is ever called.

If ddRVal is set to DD_OK, the output from this function identifier is a DirectDraw return code and a new surface handle. This new handle must be used on all subsequent calls that reference this surface.

This function identifier can only be called at passive level.

DDOPENSURFACEIN

The DDOPENSURFACEIN structure contains the DirectDrawSurface object information.

typedef struct _DDOPENSURFACEIN {
  HANDLE  hDirectDraw;
  ULONG_PTR  dwSurfaceHandle;
  LPDD_NOTIFYCALLBACK  pfnSurfaceClose;
  PVOID  pContext;
} DDOPENSURFACEIN, FAR *LPDDOPENSURFACEIN;

Members

hDirectDraw
Specifies the DirectDraw object to which the surface handle will be associated.
dwSurfaceHandle
Specifies the DirectDrawSurface handle passed down from user mode.
pfnSurfaceClose
Points to a pfnSurfaceClose callback function that is called if the DirectDraw object goes away.
pContext
Contains a value that is passed if the pfnSurfaceClose callback function is ever called.

DDOPENSURFACEOUT

The DDOPENSURFACEOUT structure contains a DirectDraw return code and a new DirectDrawSurface handle, if ddRVal is set to DD_OK. This new handle must be used on all subsequent calls that require a DirectDrawSurface handle.

typedef struct _DDOPENSURFACEOUT {
  DWORD  ddRVal;
  HANDLE  hSurface;
} DDOPENSURFACEOUT, FAR *LPDDOPENSURFACEOUT;

Members

ddRVal
Specifies the location in which the driver writes the return value. A return code of DD_OK indicates success.
hSurface
Contains the new DirectDrawSurface handle.


DD_DXAPI_OPENVIDEOPORT

DD_DXAPI_OPENVIDEOPORT notifies the kernel-mode video transport that the driver wants to use a hardware video port.

When this function identifier is used as the dwFunctionNum parameter of the DxApi function, the input and output buffer parameters of DxApi are defined as:

lpvInBuffer
Points to a DDOPENVIDEOPORTIN structure that contains the DirectDraw VPE object information.
lpvOutBuffer
Points to a DDOPENVIDEOPORTOUT structure that contains the new VPE object handle information.

Comments

The object is specified by the dwVideoPortHandle member of the DDOPENVIDEOPORTIN structure, which is the hardware video port ID specified when the VPE object was created in user mode. The hDirectDraw member specifies the DirectDraw object with which it is associated. The driver must also specify a callback that is called when the VPE object becomes unusable due to it being released at user mode. The pContext member contains a value that is passed if the pfnVideoPortClose callback function is ever called.

If ddRVal is set to DD_OK, the output from this function identifier is a DirectDraw return code and a new surface handle. This new handle must be used on all subsequent calls that reference this VPE object.

This function identifier can only be called at passive level.

DDOPENVIDEOPORTIN

The DDOPENVIDEOPORTIN structure contains the VPE object information.

typedef struct _DDOPENVIDEOPORTIN {
  HANDLE  hDirectDraw;
  ULONG  dwVideoPortHandle;
  LPDD_NOTIFYCALLBACK  pfnVideoPortClose;
  PVOID  pContext;
} DDOPENVIDEOPORTIN, FAR *LPDDOPENVIDEOPORTIN;

Members

hDirectDraw
Specifies the DirectDraw object to which the surface handle will be associated.
dwVideoPortHandle
Specifies the hardware video port ID that was passed down when the VPE object was created in user mode.
pfnVideoPortClose
Points to a pfnVideoPortClose callback function that is called if the DirectDraw object goes away.
pContext
Contains a value that is passed if the pfnVideoPortClose callback function is ever called.

DDOPENVIDEOPORTOUT

The DDOPENVIDEOPORTOUT structure contains a DirectDraw return code and a new surface handle if ddRVal is set to DD_OK. This new handle must be used on all subsequent calls that require a VPE object handle.

typedef struct _DDOPENVIDEOPORTOUT {
  DWORD  ddRVal;
  HANDLE  hVideoPort;
} DDOPENVIDEOPORTOUT, FAR *LPDDOPENVIDEOPORTOUT;

Members

ddRVal
Specifies the location in which the driver writes the return value. A return code of DD_OK indicates success.
hVideoPort
Contains the new VPE object handle.


DD_DXAPI_OPENVPCAPTUREDEVICE

DD_DXAPI_OPENVPCAPTUREDEVICE opens the device for capture.

When this function identifier is used as the dwFunctionNum parameter of the DxApi function, the input and output buffer parameters of DxApi are defined as:

lpvInBuffer
Points to a DDOPENVPCAPTUREDEVICEIN structure that contains the relevant VPE object information required for the capture.
lpvOutBuffer
Points to a DDOPENVPCAPTUREDEVICEOUT structure that contains the new capture handle.

Comments

A VPE capture device allows hardware video port data to be automatically bus mastered from the surface to a specified buffer. Opening the capture device determines which lines are to be captured. For example, for VBI the capture driver may only be interested in the first 21 lines. If the capture driver wants to capture different regions to different buffers (for example, VBI and video to separate buffers), multiple capture devices can be created.

When a capture device is created, the kernel-mode video transport creates a queue for each device. The driver can later add buffers to this queue. Each time the hardware video port V-sync occurs, the kernel-mode video transport automatically initiates the correct bus masters from the frame buffer surface most recently filled by the hardware video port to the buffer in the queue. If you don't want to capture on every field, you can indicate this by setting the dwCaptureEveryNFields member of the DDOPENVPCAPTUREDEVICEIN structure to something other than 1.

The hDirectDraw and hVideoPort members of the DDOPENVPCAPTUREDEVICEIN structure specify the DirectDraw object and VPE object from which you want to capture. The dwStartLine and dwEndLine members indicate which lines are to be captured. The dwStartLine member is relative to the start of the surface (0 is the first line) and dwEndLine is inclusive (setting dwStartLine and dwEndLine to 0 causes the first line to be captured).

The driver must also specify a callback that is called when the capture device becomes unusable due to the VPE object being released at user mode. The pContext member of the DDOPENVPCAPTUREDEVICEIN structure contains a value that is passed if the pfnCaptureClose callback function is ever called.

If ddRVal is set to DD_OK, the output from this function identifier is a DirectDraw return code and a new capture handle. This new handle must be used on all subsequent calls that reference this capture device.

This function identifier can only be called at passive level.

DDOPENVPCAPTUREDEVICEIN

The DDOPENVPCAPTUREDEVICEIN structure contains the VPE capture information.

typedef struct _DDOPENVPCAPTUREDEVICEIN {
  HANDLE  hDirectDraw;
  HANDLE  hVideoPort;
  DWORD  dwStartLine;
  DWORD  dwEndLine;
  DWORD  dwCaptureEveryNFields;
  LPDD_NOTIFYCALLBACK  pfnCaptureClose;
  PVOID  pContext;
  DWORD  dwFlags;
} DDOPENVPCAPTUREDEVICEIN, FAR * LPDDOPENVPCAPTUREDEVICEIN;

Members

hDirectDraw
Specifies the DirectDraw handle from which the capture takes place.
hVideoPort
Specifies the VPE object handle from which the capture takes place.
dwStartLine
Indicates the starting line of the capture. This member is relative to the start of the surface (0 is the first line).
dwEndLine
Indicates the last line of the capture (inclusive).
dwCaptureEveryNFields
Contains a value that is the divisor for the number of fields that are to be captured per second. A field is a region that typically contains 240 lines, in which two fields make up a frame. Fields come at a rate of approximately 60 per second. To capture all 60 fields per second, set this value to 1, to capture 30 fields per second, set this value to 2, to capture 15 fields per second, set this field to 4, and so on.
pfnCaptureClose
Points to a pfnCaptureClose callback that is called when the capture device becomes unusable due to the VPE object being released at user mode.
pContext
Contains the value that is passed if the pfnCaptureClose callback is ever called.
dwFlags
One of the following:
Flag | Meaning
DDOPENCAPTURE_VBI | Capture from the VBI stream.
DDOPENCAPTURE_VIDEO | Capture from the video stream.

DDOPENVPCAPTUREDEVICEOUT

The DDOPENVPCAPTUREDEVICEOUT structure contains the VPE capture handle.

typedef struct _DDOPENVPCAPTUREDEVICEOUT {
  DWORD  ddRVal;
  HANDLE  hCapture;
} DDOPENVPCAPTUREDEVICEOUT,
FAR * LPDDOPENVPCAPTUREDEVICEOUT;

Members

ddRVal
Specifies the location in which the driver writes the return value. A return code of DD_OK indicates success.
hCapture
Contains the new VPE capture handle.


DD_DXAPI_REGISTER_CALLBACK

DD_DXAPI_REGISTER_CALLBACK allows the client to register a callback that is called when an event occurs.

When this function identifier is used as the dwFunctionNum parameter of the DxApi function, the input and output buffer parameters of DxApi are defined as:

lpvInBuffer
Points to a DDREGISTERCALLBACK structure that contains the information required to register a callback.
lpvOutBuffer
Points to a DWORD (ddRVal) that contains the DirectDraw return value.

Comments

This function identifier can only register a single event at a time. If the client wants to be called for multiple events, it must call DD_DXAPI_REGISTER_CALLBACK multiple times.

The IRQ events are actually called at IRQ time, so the callback function must return quickly and only perform calls that are safe.

The pContext member of the DDREGISTERCALLBACK structure contains client data that is passed back to the client when the pfnDirectDrawClose callback is called.

This function identifier can only be called at passive level.

DDREGISTERCALLBACK

The DDREGISTERCALLBACK structure contains the register callback information. This structure is used by both the DD_DXAPI_REGISTER_CALLBACK and DD_DXAPI_UNREGISTER_CALLBACK function identifiers of the DxApi function.

typedef struct _DDREGISTERCALLBACK {
  HANDLE  hDirectDraw;
  ULONG  dwEvents;
  LPDD_NOTIFYCALLBACK  pfnCallback;
  ULONG_PTR  dwParam1;
  ULONG_PTR  dwParam2;
  PVOID  pContext;
} DDREGISTERCALLBACK, FAR *LPDDREGISTERCALLBACK;

Members

hDirectDraw
Specifies the DirectDraw handle.
dwEvents
Defines the event that should trigger the callback. The values in dwParam1 and dwParam2 depend on the event. The following events are defined:
Event Description dwParam1,
dwParam2
DDEVENT_DISPLAY_VSYNC Called every time a display V-sync occurs. unused,
unused
DDEVENT_POSTDOSBOX Called after returning from a full-screen MS-DOS® box. unused,
unused
DDEVENT_POSTRESCHANGE Called after a mode change occurs. unused,
unused
DDEVENT_PREDOSBOX Called before entering a full-screen MS-DOS box. unused,
unused
DDEVENT_PRERESCHANGE Called before a mode change occurs. unused,
unused
DDEVENT_VP_LINE Sets an IRQ to occur each time the hardware video port writes the specified line and then calls the callback each time the IRQ is triggered. hVideoPort,
line
DDEVENT_VP_VSYNC Called each time a hardware video port V-sync occurs. hVideoPort,
unused

pfnCallback
Points to a pfnCallback callback function that is called if the DirectDraw object goes away.
dwParam1
Is defined by the dwEvent member.
dwParam2
Is defined by the dwEvent member.
pContext
Contains client data that is passed back to the client if the pfnCallback callback function is called.


DD_DXAPI_SET_SURFACE_STATE

DD_DXAPI_SET_SURFACE_STATE allows the client to switch the overlay surface between bob and weave mode.

When this function identifier is used as the dwFunctionNum parameter of the DxApi function, the input and output buffer parameters of DxApi are defined as:

lpvInBuffer
Points to a DDSETSURFACESTATE structure that contains the requested surface state information.
lpvOutBuffer
Points to a DWORD (ddRVal) that contains the DirectDraw return value.

Comments

The dwState member of the DDSETSURFACESTATE structure contains the new state, which can be either DDSTATE_BOB or DDSTATE_WEAVE.

If the surface is associated with a hardware video port, it is possible to indicate that you would like the state change to occur at a future time. In this instance, dwStartField indicates the field on which the state change should occur. A value of 0 indicates it should occur at the start of the next field, a value of one indicates the start of the following field, and so on.

This function identifier can be called at raised IRQL.

DDSETSURFACESTATE

The DDSETSURFACESTATE structure contains the surface state information.

typedef struct _DDSETSURFACETATE {
  HANDLE  hDirectDraw;
  HANDLE  hSurface;
  DWORD  dwState;
  DWORD  dwStartField;
} DDSETSURFACESTATE, FAR *LPDDSETSURFACESTATE;

Members

hDirectDraw
Specifies the DirectDraw handle.
hSurface
Specifies the DirectDrawSurface handle.
dwState
Indicates the surface state. One of the following:
Flag | Meaning
DDSTATE_BOB | Bob mode is to be used on this surface.
DDSTATE_WEAVE | Weave mode is to be used on this surface.

dwStartField
Indicates the field on which the state change should occur. A value of 0 indicates it should occur at the start of the next field, a value of 1 indicates the start of the following field, and so on.


DD_DXAPI_SET_VP_FIELD_NUMBER

DD_DXAPI_SET_VP_FIELD_NUMBER sets the internal field number for the specified VPE object to the specified value.

When this function identifier is used as the dwFunctionNum parameter of the DxApi function, the input and output buffer parameters of DxApi are defined as:

lpvInBuffer
Pointsto a DDSETFIELDNUM structure that specifies the appropriate handles and the field number to be set.
lpvOutBuffer
Points to a DWORD (ddRVal) that contains the DirectDraw return value.

Comments

The internal field number is returned using the DD_DXAPI_GET_VP_FIELD_NUMBER function identifier and the DD_DXAPI_ADDVPCAPTUREBUFFER function identifier.

This function identifier can be called at raised IRQL.

DDSETFIELDNUM

The DDSETFIELDNUM structure contains the handles and the field number.

typedef struct _DDSETFIELDNUM {
  HANDLE  hDirectDraw;
  HANDLE  hVideoPort;
  DWORD  dwFieldNum;
} DDSETFIELDNUM, FAR *LPDDSETFIELDNUM;

Members

hDirectDraw
Specifies the DirectDraw handle.
hVideoPort
Specifies the VPE object handle.
dwFieldNum
Specifies the hardware video port's field number to be set.


DD_DXAPI_SET_VP_SKIP_FIELD

DD_DXAPI_SET_VP_SKIP_FIELD indicates that the hardware video port should not write a future field into the frame buffer. This is useful primarily for undoing the 3:2 pattern often introduced in some video content.

When this function identifier is used as the dwFunctionNum parameter of the DxApi function, the input and output buffer parameters of DxApi are defined as:

lpvInBuffer
Points to a DDSETSKIPFIELD structure that contains the VPE object information and the number of the start field.
lpvOutBuffer
Points to a DWORD (ddRVal) that contains the DirectDraw return value.

Comments

This function identifier only skips a single field and must be called explicitly for each field that needs to be skipped. If VBI data is present in the field, the VBI portion if the data is not skipped.

This function identifier can be called at raised IRQL.

DDSETSKIPFIELD

The DDSETSKIPFIELD structure contains the start field information.

typedef struct _DDSETSKIPFIELD {
  HANDLE  hDirectDraw;
  HANDLE  hVideoPort;
  DWORD  dwStartField;
} DDSETSKIPFIELD, FAR *LPDDSETSKIPFIELD;

Members

hDirectDraw
Specifies the DirectDraw handle.
hVideoPort
Specifies the VPE object handle.
dwStartField
Indicates the field that needs to be skipped and is relative to the current field. A value of 0 indicates it should skip the next field, a value of 1 indicates the field after that, and so on.


DD_DXAPI_UNREGISTER_CALLBACK

DD_DXAPI_UNREGISTER_CALLBACK allows the client to unregister a previously-registered callback. This function identifier can only unregister one event at a time.

When this function identifier is used as the dwFunctionNum parameter of the DxApi function, the input and output buffer parameters of DxApi are defined as:

lpvInBuffer
Points to a DDREGISTERCALLBACK structure that contains the information required to unregister a callback.
lpvOutBuffer
Points to a DWORD (ddRVal) that contains the DirectDraw return value.

Comments

The parameters are identical to those of the DD_DXAPI_REGISTER_CALLBACK function identifier.

This function identifier can only be called at passive level.


DxBobNextField

DxBobNextField bobs the next field of interleaved data.

DWORD
  (*PDX_BOBNEXTFIELD)(
    PVOID  HwDeviceExtension,
    PDDBOBNEXTFIELDINFO  BobNextFieldInfo,
    PVOID  lpOutput
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
BobNextFieldInfo
Points to a DDBOBNEXTFIELDINFO structure that contains the bob information for the surface.
lpOutput
Is reserved for system use.

Return Value

DxBobNextField returns DX_OK if it succeeds; otherwise, it returns one of the following error values:

DXERR_GENERIC

DXERR_OUTOFCAPS

DXERR_UNSUPPORTED

Headers

Declared in ddkmini.h. Include ddkmini.h.

Comments

When data is interleaved, DdFlip is called every other frame. This is insufficient for bob because it must be notified after every V-sync. This function is called when a V-sync does not cause a flip.

DDBOBNEXTFIELDINFO

The DDBOBNEXTFIELDINFO structure contains the bob information for the surface.

typedef struct _DDBOBNEXTFIELDINFO {
  LPDDSURFACEDATA  lpSurface;
} DDBOBNEXTFIELDINFO, *PDDBOBNEXTFIELDINFO;

Members

lpSurface
Points to a DDSURFACEDATA structure that represents the surface.


DxEnableIRQ

DxEnableIRQ indicates to the miniport which IRQs should be enabled or disabled.

DWORD
  (*PDX_ENABLEIRQ)(
    PVOID  HwDeviceExtension,
    PDDENABLEIRQINFO  EnableIrqInfo,
    PVOID  lpOutput
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
EnableIrqInfo
Points to the DDENABLEIRQINFO structure that contains the information required to enable interrupts.
lpOutput
Is reserved for system use.

Return Value

DxEnableIRQ returns DX_OK if it succeeds; otherwise, it returns one of the following error values:

DXERR_GENERIC

DXERR_OUTOFCAPS

DXERR_UNSUPPORTED

Headers

Declared in dxmini.h. Include dxmini.h.

Comments

The dwIRQSources member of the DDENABLEIRQINFO structure contains the DDIRQ_xxx flags that are set for every IRQ that should be enabled. If an IRQ is not specified in this call, it should be disabled. If the requested combination cannot be supported, this function fails.

Because the miniport must always manage its own IRQ, it needs to call the specified IRQCallback when an IRQ occurs. When calling IRQCallback, the dwIRQFlags member of the DX_IRQDATA structure passed to IRQCallback contains the DDIRQ_xxxx flags that indicate what caused the IRQ.

DDENABLEIRQINFO

The DDENABLEIRQINFO structure contains the information required to enable interrupts.

typedef struct _DDENABLEIRQINFO {
  DWORD  dwIRQSources;
  DWORD  dwLine;
  PDX_IRQCALLBACK  IRQCallback;
  PDX_IRQDATA  lpIRQData;
} DDENABLEIRQINFO, *PDDENABLEIRQINFO;

Members

dwIRQSources
Indicates the interrupts that should be enabled. One or more of the following:
Flag | Meaning
DDIRQ_DISPLAY_VSYNC | The device can generate IRQs based on the display V-sync.
DDIRQ_VPORT0_LINE | The device can generate IRQs based on a programmable line for hardware video port number 0.
DDIRQ_VPORT0_VSYNC | The device can generate V-sync IRQs for hardware video port number 0.
DDIRQ_VPORT1_LINE | The device can generate IRQs based on a programmable line for hardware video port number 1.
DDIRQ_VPORT1_VSYNC | The device can generate V-sync IRQs for hardware video port number 1.
DDIRQ_VPORT2_LINE | The device can generate IRQs based on a programmable line for hardware video port number 2.
DDIRQ_VPORT2_VSYNC | The device can generate V-sync IRQs for hardware video port number 2.
DDIRQ_VPORT3_LINE | The device can generate IRQs based on a programmable line for hardware video port number 3.
DDIRQ_VPORT3_VSYNC | The device can generate V-sync IRQs for hardware video port number 3.
DDIRQ_VPORT4_LINE | The device can generate IRQs based on a programmable line for hardware video port number 4.
DDIRQ_VPORT4_VSYNC | The device can generate V-sync IRQs for hardware video port number 4.
DDIRQ_VPORT5_LINE | The device can generate IRQs based on a programmable line for hardware video port number 5.
DDIRQ_VPORT5_VSYNC | The device can generate V-sync IRQs for hardware video port number 5.
DDIRQ_VPORT6_LINE | The device can generate IRQs based on a programmable line for hardware video port number 6.
DDIRQ_VPORT6_VSYNC | The device can generate V-sync IRQs for hardware video port number 6.
DDIRQ_VPORT7_LINE | The device can generate IRQs based on a programmable line for hardware video port number 7.
DDIRQ_VPORT7_VSYNC | The device can generate V-sync IRQs for hardware video port number 7.
DDIRQ_VPORT8_LINE | The device can generate IRQs based on a programmable line for hardware video port number 8.
DDIRQ_VPORT8_VSYNC | The device can generate V-sync IRQs for hardware video port number 8.
DDIRQ_VPORT9_LINE | The device can generate IRQs based on a programmable line for hardware video port number 9.
DDIRQ_VPORT9_VSYNC | The device can generate V-sync IRQs for hardware video port number 9.

dwLine
Indicates which line should generate the IRQ. If the hardware does not have the ability to generate an IRQ based on a programmable line, the value in this member is meaningless.
IRQCallback
Points to an IRQCallback that the miniport calls when the miniport is managing IRQs, and an IRQ occurs.
lpIRQData
Points to the data to be sent to IRQCallback when IRQCallback is called.

Comments

The dwIRQSources member of this structure does not use the DDIRQ_BUSMASTER flag. However, the DDIRQ_BUSMASTER flag can be set in the dwIrqFlags member of the DX_IRQDATA structure accessed by the IRQCallback function the driver calls when an IRQ occurs.


DxFlipOverlay

DxFlipOverlay is called when a miniport client wants to flip the overlay or when autoflipping is enabled.

DWORD
  (*PDX_FLIPOVERLAY)(
    PVOID  HwDeviceExtension,
    PDDFLIPOVERLAYINFO  FlipOverlayInfo,
    PVOID  lpOutput
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
FlipOverlayInfo
Points to the DDFLIPOVERLAYINFO structure that contains the flip information for the surface.
lpOutput
Is reserved for system use.

Return Value

DxFlipOverlay returns DX_OK if it succeeds; otherwise, it returns one of the following error values:

DXERR_GENERIC

DXERR_OUTOFCAPS

DXERR_UNSUPPORTED

Headers

Declared in dxmini.h. Include dxmini.h.

Comments

If a hardware video port is not used and the client still wants the overlay to bob the data, the dwFlags member of the DDFLIPOVERLAYINFO structure specifies the polarity of the data in the field being flipped (using the DDFLIP_EVEN or DDFLIP_ODD flags). These flags are not used when flipping a surface that is fed by a hardware video port.

DDFLIPOVERLAYINFO

The DDFLIPOVERLAYINFO structure contains the flip information for the surface.

typedef struct _DDFLIPOVERLAYINFO {
  LPDDSURFACEDATA  lpCurrentSurface;
  LPDDSURFACEDATA  lpTargetSurface;
  DWORD  dwFlags;
} DDFLIPOVERLAYINFO, *PDDFLIPOVERLAYINFO;

Members

lpCurrentSurface
Points to a DDSURFACEDATA structure that contains information about the current surface.
lpTargetSurface
Points to a DDSURFACEDATA structure that contains information about the target surface.
dwFlags
Specifies the polarity of the data in the field being flipped. One of the following flags is returned:
Flag | Meaning
DDFLIP_EVEN | The target surface contains the even field of video data.
DDFLIP_ODD | The target surface contains the odd field of video data.


DxFlipVideoPort

DxFlipVideoPort is called when a miniport client wants to flip the VPE object or when autoflipping is enabled.

DWORD
  (*PDX_FLIPVIDEOPORT)(
    PVOID  HwDeviceExtension,
    PDDFLIPVIDEOPORTINFO  FlipVideoPortInfo,
    PVOID  lpOutput
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
FlipVideoPortInfo
Points to the DDFLIPVIDEOPORTINFO structure that contains the flip information for the surface and VPE object.
lpOutput
Is reserved for system use.

Return Value

DxFlipVideoPort returns DX_OK if it succeeds; otherwise, it returns one of the following error values:

DXERR_GENERIC

DXERR_OUTOFCAPS

DXERR_UNSUPPORTED

Headers

Declared in dxmini.h. Include dxmini.h.

Comments

The dwFlipVPFlags member of the DDFLIPVIDEOPORTINFO structure uses the DDVPFLIP_VIDEO or DDVPFLIP_VBI flags to indicate whether the surfaces represent VBI surfaces or regular surfaces.

DDFLIPVIDEOPORTINFO

The DDFLIPVIDEOPORTINFO structure contains the VPE object and surface information.

typedef struct _DDFLIPVIDEOPORTINFO {
  LPDDVIDEOPORTDATA  lpVideoPortData;
  LPDDSURFACEDATA  lpCurrentSurface;
  LPDDSURFACEDATA  lpTargetSurface;
  DWORD  dwFlipVPFlags;
} DDFLIPVIDEOPORTINFO *PDDFLIPVIDEOPORTINFO;

Members

lpVideoPortData
Points to a DDVIDEOPORTDATA structure that contains the VPE object information.
lpCurrentSurface
Points to a DDSURFACEDATA structure that contains information about the current surface.
lpTargetSurface
Points to a DDSURFACEDATA structure that contains information about the target surface.
dwFlipVPFlags
Indicates whether the surfaces represent VBI surfaces or regular surfaces. One of the following:
Flag | Meaning
DDVPFLIP_VBI | Flip the VBI surface.
DDVPFLIP_VIDEO | Flip the normal video surface.


DxGetCurrentAutoflip

DxGetCurrentAutoflip is called when the device is hardware autoflipping and a miniport client wants to know which surface is receiving the current field of video data for capture purposes.

DWORD
  (*PDX_GETCURRENTAUTOFLIP)(
    PVOID HwDeviceExtension,
    PDDGETCURRENTAUTOFLIPININFO  GetCurrentAutoflipInInfo,
    PDDGETCURRENTAUTOFLIPOUTINFO  GetCurrentAutoflipOutInfo
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
GetCurrentAutoflipInInfo
Points to the DDGETCURRENTAUTOFLIPININFO structure that contains the VPE object information.
GetCurrentAutoflipOutInfo
Points to the DDGETCURRENTAUTOFLIPOUTINFO structure that contains the surface information.

Return Value

DxGetCurrentAutoflip returns DX_OK if it succeeds; otherwise, it returns one of the following error values:

DXERR_GENERIC

DXERR_OUTOFCAPS

DXERR_UNSUPPORTED

Headers

Declared in dxmini.h. Include dxmini.h.

Comments

The DxGetCurrentAutoflip function returns the current index in the autoflip chain of the current surface in the dwSurfaceIndex member of the DDGETCURRENTAUTOFLIPOUTINFO structure.

DDGETCURRENTAUTOFLIPININFO

The DDGETCURRENTAUTOFLIPININFO structure contains the VPE object information.

typedef struct _DDGETCURRENTAUTOFLIPININFO {
  LPDDVIDEOPORTDATA  lpVideoPortData;
} DDGETCURRENTAUTOFLIPININFO, *PDDGETCURRENTAUTOFLIPININFO;

Members

lpVideoPortData
Points to a DDVIDEOPORTDATA structure that contains the VPE object information.

DDGETCURRENTAUTOFLIPOUTINFO

The DDGETCURRENTAUTOFLIPOUTINFO structure provides the surface information.

typedef struct _DDGETCURRENTAUTOFLIPOUTINFO {
  DWORD  dwSurfaceIndex;
  DWORD  dwVBISurfaceIndex;
} DDGETCURRENTAUTOFLIPOUTINFO, *PDDGETCURRENTAUTOFLIPOUTINFO;

Members

dwSurfaceIndex
Specifies the current index in the autoflip chain of the current surface.
dwVBISurfaceIndex
Specifies the current index in the autoflip chain of the current VBI surface.


DxGetIRQInfo

DxGetIRQInfo indicates which interrupts the driver supports.

DWORD
  (*PDX_GETIRQINFO)(
    PVOID  HwDeviceExtension,
    PVOID  lpInput,
    PDDGETIRQINFO  GetIrqInfo
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
lpInput
Is reserved for system use.
GetIrqInfo
Points to a DDGETIRQINFO structure that contains the interrupt information.

Return Value

DxGetIrqInfo returns DX_OK if it succeeds; otherwise, it returns one of the following error values:

DXERR_GENERIC

DXERR_OUTOFCAPS

DXERR_UNSUPPORTED

Headers

Declared in dxmini.h. Include dxmini.h.

Comments

Because the miniport must always manage the IRQ, this function must always set the dwFlags member of the DDGETIRQINFO structure to IRQINFO_HANDLED. If any other flag is set, this function will fail.

DDGETIRQINFO

The DDGETIRQINFO structure contains interrupt information for the miniport.

typedef struct _DDGETIRQINFO {
  DWORD  dwFlags;
} DDGETIRQINFO, *PDDGETIRQINFO;

Members

dwFlags
Specifies the interrupt management status.
IRQINFO_HANDLED
The miniport is managing the interrupt.


DxGetPolarity

DxGetPolarity returns the polarity (even or odd) of the current field being written by the VPE object.

DWORD
  (*PDX_GETPOLARITY)(
    PVOID  HwDeviceExtension,
    PDDGETPOLARITYININFO  GetPolarityInInfo,
    PDDGETPOLARITYOUTINFO  GetPolarityOutInfo
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
GetPolarityInInfo
Points to a DDGETPOLARITYININFO structure that contains the VPE object from which to get the polarity information.
GetPolarityOutInfo
Points to a DDGETPOLARITYOUTINFO structure that contains the polarity information for the specified VPE object.

Return Value

DxGetPolarity returns DX_OK if it succeeds; otherwise, it returns one of the following error values:

DXERR_GENERIC

DXERR_OUTOFCAPS

DXERR_UNSUPPORTED

Headers

Declared in dxmini.h Include dxmini.h. Comments

The following structures contain VPE object information:

DDGETPOLARITYININFO

The DDGETPOLARITYININFO structure contains the VPE object information.

typedef struct _DDGETPOLARITYININFO {
  LPDDVIDEOPORTDATA  lpVideoPortData;
} DDGETPOLARITYININFO, *PDDGETPOLARITYININFO;

Members

lpVideoPortData
Points to a DDVIDEOPORTDATA structure that contains the VPE object information.

DDGETPOLARITYOUTINFO

The DDGETPOLARITYOUTINFO structure contains the polarity information of the VPE object.

typedef struct _DDGETPOLARITYOUTINFO {
  DWORD  bPolarity;
} DDGETPOLARITYOUTINFO, *PDDGETPOLARITYOUTINFO;

Members

bPolarity
Indicates the polarity (even or odd) of the current field being written by the VPE object.


DxGetPreviousAutoflip

DxGetPreviousAutoflip is called when the device is hardware autoflipping and a miniport client wants to know which surface received the previous field of video data for capture purposes.

DWORD
  (*PDX_GETPREVIOUSAUTOFLIP)(
    PVOID  HwDeviceExtension,
    PDDGETPREVIOUSAUTOFLIPININFO  GetPreviousAutoflipInInfo,
    PDDGETPREVIOUSAUTOFLIPOUTINFO  GetPreviousAutoflipOutInfo
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
GetPreviousAutoflipInInfo
Points to a DDGETPREVIOUSAUTOFLIPININFO structure that contains the VPE object information.
GetPreviousAutoflipOutInfo
Points to a DDGETPREVIOUSAUTOFLIPOUTINFO structure that contains the index of the autoflip chain.

Return Value

DxGetPreviousAutoflip returns DX_OK if it succeeds; otherwise, it returns one of the following error values:

DXERR_GENERIC

DXERR_OUTOFCAPS

DXERR_UNSUPPORTED

Headers

Declared in dxmini.h. Include dxmini.h.

Comments

If interleaving, the surface that received the previous field may be the same surface that is receiving the current field.

DxGetPreviousAutoflip returns the index in the autoflip chain of the correct surface in the dwSurfaceIndex member of the DDGETPREVIOUSAUTOFLIPOUTINFO structure.

DDGETPREVIOUSAUTOFLIPININFO

The DDGETPREVIOUSAUTOFLIPININFO structure provides the VPE object information.

typedef struct _DDGETPREVIOUSAUTOFLIPININFO {
  LPDDVIDEOPORTDATA  lpVideoPortData;
} DDGETPREVIOUSAUTOFLIPININFO, *PDDGETPREVIOUSAUTOFLIPININFO;

Members

lpVideoPortData
Points to a DDVIDEOPORTDATA structure that contains the VPE object information.

DDGETPREVIOUSAUTOFLIPOUTINFO

The DDGETPREVIOUSAUTOFLIPOUTINFO structure provides the surface data.

typedef struct _DDGETPREVIOUSAUTOFLIPOUTINFO {
  DWORD  dwSurfaceIndex;
  DWORD  dwVBISurfaceIndex;
} DDGETPREVIOUSAUTOFLIPOUTINFO, *PDDGETPREVIOUSAUTOFLIPOUTINFO;

Members

dwSurfaceIndex
Specifies the current index in the autoflip chain of the current surface.
dwVBISurfaceIndex
Specifies the current index in the autoflip chain of the current VBI surface.


DxGetTransferStatus

DxGetTransferStatus is used by DirectDraw to determine which hardware bus master has completed.

DWORD
  (*PDX_GETTRANSFERSTATUS)(
    PVOID  HwDeviceExtension,
    PVOID  lpInput,
    PDDGETTRANSFEROUTINFO  GetTransferOutInfo
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
lpInput
Is reserved for system use.
GetTransferOutInfo
Points to a DDGETTRANSFERSTATUSOUTINFO structure contains the transfer status information.

Return Value

DxGetTransferStatus returns DX_OK if it succeeds; otherwise, it returns one of the following error values:

DXERR_GENERIC

DXERR_OUTOFCAPS

DXERR_UNSUPPORTED

Headers

Declared in dxmini.h. Include dxmini.h.

Comments

The driver identifies the bus master by supplying the transfer ID in the DDGETTRANSFERSTATUSOUTINFO structure. The transfer ID for each bus master is originally supplied by DirectDraw in the dwTransferID member of the DDTRANSFERININFO structure.)

DDGETTRANSFERSTATUSOUTINFO

The DDGETTRANSFERSTATUSOUTINFO structure contains the transfer status information.

typedef struct _DDGETTRANSFERSTATUSOUTINFO {
  DWORD  dwTransferID;
} DDGETTRANSFERSTATUSOUTINFO, *PDDGETTRANSFEROUTINFO;

Members

dwTransferID
Contains the transfer ID of the bus master that completed. The transfer ID was originally supplied to the driver in the dwTransferID member of the DDTRANSFERININFO structure.


DxLock

DxLock is called when a miniport client wants access to the frame buffer.

DWORD
  (*PDX_GETTRANSFERSTATUS)(
    PVOID  HwDeviceExtension,
    PDDLOCKININFO  LockInInfo,
    PDDLOCKOUTINFO  LockOutInfo
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
LockInInfo
Points to a DDLOCKININFO structure that contains the surface information for the lock.
LockOutInfo
Points to a DDLOCKOUTINFO structure that contains the surface in the frame buffer.

Return Value

DxLock returns DX_OK if it succeeds; otherwise, it returns one of the following error values:

DXERR_GENERIC

DXERR_OUTOFCAPS

DXERR_UNSUPPORTED

Headers

Declared in dxmini.h. Include dxmini.h. Comments

The following structures contain surface information:

DDLOCKININFO

The DDLOCKININFO structure contains the surface information.

typedef struct _DDLOCKININFO {
  LPDDSURFACEDATA  lpSurfaceData;
} DDLOCKININFO, *PDDLOCKININFO;

Members

lpSurfaceData
Points to a DDSURFACEDATA structure that contains the surface information.

DDLOCKOUTINFO

The DDLOCKOUTINFO structure contains the surface information output from the DxLock function.

typedef struct _DDLOCKOUTINFO {
  ULONG_PTR  dwSurfacePtr;
} DDLOCKOUTINFO, *PDDLOCKOUTINFO;

Members

dwSurfacePtr
Points to the surface in the frame buffer.


DxSetState

DxSetState is called when a miniport client decides it wants to switch from bob mode to weave mode, and vice versa.

DWORD
  (*PDX_SETSTATE)(
    PVOID  HwDeviceExtension,
    PDDSETSTATEININFO  SetStateInInfo,
    PDDSETSTATEOUTINFO  SetStateOutInfo
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
SetStateInInfo
Points to a DDSETSTATEININFO structure that contains the surface and VPE object information.
SetStateOutInfo
Points to a DDSETSTATEOUTINFO structure that contains the state information for the hardware video port.

Return Value

DxSetState returns DX_OK if it succeeds; otherwise, it returns one of the following error values:

DXERR_GENERIC

DXERR_OUTOFCAPS

DXERR_UNSUPPORTED

Headers

Declared in dxmini.h. Include dxmini.h.

Comments

The surface data passed contains the new state. If the new state is not supported, the miniport should fail the call.

If the new state requires the device to revert from hardware autoflipping to software autoflipping, the miniport should set the dwSoftwareAutoflip member of the DDSTATEOUTINFO structure equal to 1 and set dwSurfaceIndex equal to the current position in the autoflip list of the surface receiving hardware video port data.

DDSETSTATEININFO

The DDSETSTATEININFO structure contains the surface and VPE object information.

typedef struct _DDSETSTATEININFO {
  LPDDSURFACEDATA  lpSurfaceData;
  LPDDVIDEOPORTDATA  lpVideoPortData;
} DDSETSTATEININFO, *PDDSETSTATEININFO;

Members

lpSurfaceData
Points to a DDSURFACEDATA structure that contains the surface information.
lpVideoPortData
Points to a DDVIDEOPORTDATA structure that contains the VPE object information.

DDSETSTATEOUTINFO

The DDSETSTATEOUTINFO structure contains the state information for the VPE object.

typedef struct _DDSETSTATEOUTINFO {
  BOOL   bSoftwareAutoflip;
  DWORD  dwSurfaceIndex;
  DWORD  dwVBISurfaceIndex;
} DDSETSTATEOUTINFO, *PDDSETSTATEOUTINFO;

Members

bSoftwareAutoflip
When set to a non-zero value, causes DirectDraw to revert to software autoflipping. Note that once software autoflipping has been initiated, you cannot revert back to hardware autoflipping until the VPE object and surface are destroyed and restarted.
dwSurfaceIndex
Indicates the index in the autoflip chain of the surface currently receiving the data from the VPE object. This field is ignored unless the miniport driver is switching from hardware autoflipping to software autoflipping.
dwVBISurfaceIndex
Indicates the index in the autoflip chain of the VBI surface currently receiving the data from the VPE object. This field is ignored unless the miniport is switching from hardware autoflipping to software autoflipping.

Comments

When asked to switch from bob to weave, the miniport may need to switch from hardware autoflipping to software autoflipping (no current hardware supports automatic field skipping, and so on). All the driver has to do is set the dwSoftwareAutoflip member to a non-zero value and DirectDraw will revert to software autoflipping.

If the miniport driver switches from hardware to software autoflipping, DirectDraw must know which surface is currently receiving data from the VPE object so it can continue without causing a glitch. Therefore, the miniport driver must set the dwSurfaceIndex member to the index in the autoflip chain of the surface currently receiving the data from the VPE object. When DdVideoPortUpdate is called, it gives an array of surfaces that you can autoflip between. You can then program these addresses into your hardware when you software autoflip.


DxSkipNextField

DxSkipNextField is called when the next field needs to be skipped or re-enabled.

DWORD
  (*PDX_SKIPNEXTFIELD)(
    PVOID  HwDeviceExtension,
    PDDSKIPNEXTFIELDINFO  SkipNextFieldInfo,
    PVOID  lpOutput
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
SkipNextFieldInfo
Points to a DDSKIPNEXTFIELDINFO structure that contains the skip information for the VPE object.
lpOutput
Is reserved for system use.

Return Value

DxSkipNextField returns DX_OK if it succeeds; otherwise, it returns one of the following error values:

DXERR_GENERIC

DXERR_OUTOFCAPS

DXERR_UNSUPPORTED

Headers

Declared in dxmini.h. Include dxmini.h.

Comments

If the dwSkipFlags member of the DDSKIPNEXTFIELDINFO structure is DDSKIP_SKIPNEXT, the following field should be skipped. If the vertical blanking interval (VBI) height is greater than zero, only the video data should be skipped (not the VBI data). If dwSkipFlags is set to DDSKIP_ENABLENEXT, the next field should be restored.

DDSKIPNEXTFIELDINFO

The DDSKIPNEXTFIELDINFO structure contains the skip information for the VPE object.

typedef struct _DDSKIPNEXTFIELDINFO {
  LPDDVIDEOPORTDATA  lpVideoPortData;
  DWORD  dwSkipFlags;
} DDSKIPNEXTFIELDINFO, *PDDSKIPNEXTFIELDINFO;

Members

lpVideoPortData
Points to a DDVIDEOPORTDATA structure that represents the VPE object.
dwSkipFlags
Indicates whether to skip the next field. One of the following:
Flag | Meaning
DDSKIP_ENABLENEXT | The next field should be restored.
DDSKIP_SKIPNEXT | The next field should be skipped.


DxTransfer

DxTransfer tells the driver to bus master data from a surface to the buffer specified in the memory descriptor list (MDL).

DWORD
  (*PDX_TRANSFER)(
    PVOID  HwDeviceExtension,
    PDDTRANSFERININFO  TransferInInfo,
    PDDTRANSFEROUTINFO  TransferOutInfo
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
TransferInInfo
Points to a DDTRANSFERININFO structure that contains the transfer information for the surface.
TransferOutInfo
Points to a DDTRANSFEROUTINFO structure that contains the polarity of the field being captured.

Return Value

DxTransfer returns DX_OK if it succeeds; otherwise, it returns one of the following error values:

DXERR_GENERIC

DXERR_OUTOFCAPS

DXERR_UNSUPPORTED

Headers

Declared in dxmini.h. Include dxmini.h.

Comments

The MDL is defined in the WDM documentation.

DxTransfer is called at hardware interrupt time. This means the driver cannot wait for a previous bus master to complete and it cannot call any functions that are not safe to call at interrupt time (that is, most of them).

In addition, the driver should not fail the call just because the hardware is currently busy. Instead, the driver should maintain an internal queue.

DDTRANSFERININFO

The DDTRANSFERININFO structure contains the transfer information for the surface

typedef struct _DDTRANSFERININFO {
  LPDDSURFACEDATA  lpSurfaceData;
  DWORD  dwStartLine;
  DWORD  dwEndLine;
  ULONG_PTR  dwTransferID;
  DWORD  dwTransferFlags;
  PMDL  lpDestMDL;
} DDTRANSFERININFO, *PDDTRANSFERININFO;

Members

lpSurfaceData
Points to a DDSURFACEDATA structure that represents the surface that contains the information to be transferred. The information in this structure is supplied by DirectDraw.
dwStartLine
Indicates the first line in the surface from which data will be transferred.
dwEndLine
Indicates the last line in the surface from which data will be transferred, inclusive.
dwTransferID
Specifies an identification for the transfer supplied by DirectDraw. This transfer ID is used by the driver in the DDGETTRANSFERSTATUSOUTINFO structure.
dwTransferFlags
Indicates the type of transfer. One of the following:
Flag | Meaning
DDTRANSFER_CANCEL | DirectDraw previously requested a transfer, but is now canceling that request.
DDTRANSFER_HALFLINES | Due to half line issues, the odd field contains an extra line of useless data at the top that the driver must account for.
DDTRANSFER_INVERT | During bus mastering, the capture driver is requesting an inversion.
DDTRANSFER_NONLOCALVIDMEM | The transfer is from display memory to AGP memory.
DDTRANSFER_SYSTEMMEMORY | The transfer is from display memory to system memory.

lpDestMDL
Points to a destination MDL structure.

DDTRANSFEROUTINFO

The DDTRANSFEROUTINFO structure returns the polarity of the field being captured.

typedef struct _DDTRANSFEROUTINFO {
  DWORD  dwBufferPolarity;
} DDTRANSFEROUTINFO, *PDDTRANSFEROUTINFO;

Members

dwBufferPolarity
Specifies the polarity of the field being captured. This value is set to true if the current video field is the even field of an interlaced video signal and false otherwise.


IRQCallback

IRQCallback points to a DirectDraw structure that is filled in by the driver with the information about the IRQ that has occurred.

VOID
  (*PDX_IRQCALLBACK) (
    PDX_IRQDATA  pIrqData
    );

Parameters

pIrqData
Points to the DX_IRQDATA structure that will be filled in with the driver's IRQ information.

DX_IRQDATA

The DX_IRQDATA structure contains the IRQ information supplied by the driver.

typedef struct _DX_IRQDATA {
  DWORD  dwIrqFlags;
} DX_IRQDATA, *PDX_IRQDATA;

Members

dwIrqFlags
Specifies the type of IRQ that has occurred. One or more of the following:
Flag | Meaning
DDIRQ_BUSMASTER | The IRQ was generated because a transfer request was completed.
DDIRQ_DISPLAY_VSYNC | The device can generate IRQs based on the display V-sync.
DDIRQ_VPORT0_LINE | The device can generate IRQs based on a programmable line for hardware video port number 0.
DDIRQ_VPORT0_VSYNC | The device can generate V-sync IRQs for hardware video port number 0.
DDIRQ_VPORT1_LINE | The device can generate IRQs based on a programmable line for hardware video port number 1.
DDIRQ_VPORT1_VSYNC | The device can generate V-sync IRQs for hardware video port number 1.
DDIRQ_VPORT2_LINE | The device can generate IRQs based on a programmable line for hardware video port number 2.
DDIRQ_VPORT2_VSYNC | The device can generate V-sync IRQs for hardware video port number 2.
DDIRQ_VPORT3_LINE | The device can generate IRQs based on a programmable line for hardware video port number 3.
DDIRQ_VPORT3_VSYNC | The device can generate V-sync IRQs for hardware video port number 3.
DDIRQ_VPORT4_LINE | The device can generate IRQs based on a programmable line for hardware video port number 4.
DDIRQ_VPORT4_VSYNC | The device can generate V-sync IRQs for hardware video port number 4.
DDIRQ_VPORT5_LINE | The device can generate IRQs based on a programmable line for hardware video port number 5.
DDIRQ_VPORT5_VSYNC | The device can generate V-sync IRQs for hardware video port number 5.
DDIRQ_VPORT6_LINE | The device can generate IRQs based on a programmable line for hardware video port number 6.
DDIRQ_VPORT6_VSYNC | The device can generate V-sync IRQs for hardware video port number 6.
DDIRQ_VPORT7_LINE | The device can generate IRQs based on a programmable line for hardware video port number 7.
DDIRQ_VPORT7_VSYNC | The device can generate V-sync IRQs for hardware video port number 7.
DDIRQ_VPORT8_LINE | The device can generate IRQs based on a programmable line for hardware video port number 8.
DDIRQ_VPORT8_VSYNC | The device can generate V-sync IRQs for hardware video port number 8.
DDIRQ_VPORT9_LINE | The device can generate IRQs based on a programmable line for hardware video port number 9.
DDIRQ_VPORT9_VSYNC | The device can generate V-sync IRQs for hardware video port number 9.

Headers

Declared in dxmini.h. Include dxmini.h.


NotifyCallback

NotifyCallback points to a DirectDraw structure that is filled in by the runtime with information about an event that has occurred.

ULONG
  (FAR PASCAL *LPDD_NOTIFYCALLBACK)(
    DWORD  dwFlags,
    PVOID  pContext,
    DWORD  dwParam1,
    DWORD  dwParam2
    );

Parameters

dwFlags
Indicates the event that caused the callback to be called. The values in dwParam1 and dwParam2 depend on the value of dwFlags. The following values are possible:
Flag | dwParam1 | dwParam2
DDNOTIFY_CLOSECAPTURE | hCapture | unused
DDNOTIFY_CLOSEDIRECTDRAW | hDirectDraw | unused
DDNOTIFY_CLOSESURFACE | hSurface | unused
DDNOTIFY_CLOSEVIDEOPORT | hVideoPort | unused
DDNOTIFY_DISPLAY_VSYNC | hDirectDraw | unused
DDNOTIFY_POSTDOSBOX | hDirectDraw | unused
DDNOTIFY_POSTRESCHANGE | hDirectDraw | unused
DDNOTIFY_PREDOSBOX | hDirectDraw | unused
DDNOTIFY_PRERESCHANGE | hDirectDraw | unused
DDNOTIFY_VP_LINE | hVideoPort | unused
DDNOTIFY_VP_VSYNC | hVideoPort | unused

pContext
Contains a value that was passed from the calling function identifier.
dwParam1, dwParam2
Contain the parameters required by the event that caused the callback.


IDirectDrawKernel

This section describes the methods defined for the IDirectDrawKernel interface. Method prototypes are defined in ddkernel.h.


IDirectDrawKernel::GetCaps

The IDirectDrawKernel::GetCaps method returns the capabilities of this kernel-mode device.

STDMETHOD
  (GetCaps) (
    THIS_
    LPDDKERNELCAPS lpCaps,
    ) PURE;

Parameters

lpCaps
Caller-supplied pointer to a DDKERNELCAPS structure into which the kernel-mode capabilities of the DirectDraw device are returned.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in ddkernal.h and ddraw.h. Include ddkernal.h and winddi.h.


IDirectDrawKernel::GetKernelHandle

The IDirectDrawKernel::GetKernelHandle method returns a kernel-mode handle to the DirectDraw object.

STDMETHOD
  (GetKernelHandle) (
    THIS_
    PULONG_PTR pulDirectDrawHandle,
    ) PURE;

Parameters

pulDirectDrawHandle
Caller-supplied pointer into which the kernel-mode handle of the DirectDraw object is returned.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in ddkernal.h. Include ddkernal.h.


IDirectDrawKernel::ReleaseKernelHandle

The IDirectDrawKernel::ReleaseKernelHandle method releases a kernel-mode handle to the DirectDraw object.

STDMETHOD
  (ReleaseKernelHandle) (
    THIS
    ) PURE;

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in ddkernal.h. Include ddkernal.h.


IDirectDrawSurfaceKernel

This section describes the methods defined for the IDirectDrawSurfaceKernel interface. Method prototypes are defined in ddkernel.h.


IDirectDrawSurfaceKernel::GetKernelHandle

The IDirectDrawSurfaceKernel::GetKernelHandle method returns a kernel-mode handle to the DirectDraw surface.

STDMETHOD
  (GetKernelHandle) (
    THIS_
    PULONG_PTR pulSurfaceHandle,
    ) PURE;

Parameters

pulSurfaceHandle
Caller-supplied pointer into which the kernel-mode handle of the DirectDraw surface is returned.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in ddkernal.h. Include ddkernal.h.


IDirectDrawSurfaceKernel::ReleaseKernelHandle

The IDirectDrawSurfaceKernel::ReleaseKernelHandle method releases a kernel-mode handle to the DirectDraw surface.

STDMETHOD
  (ReleaseKernelHandle) (
    THIS
    ) PURE;

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in ddkernal.h. Include ddkernal.h.


DirectDraw Driver Structures

This section describes the Microsoft® DirectDraw® driver structures supported on Windows®. These structures are used by display drivers that offer DirectDraw support. DirectDraw Driver Header Files, Sample Code, and References lists the include files that define the DirectDraw structures described in this section.

Although the DD_Xxx types described in this reference refer to the actual structures in the ddrawint.h header file, it is recommended that driver writers use the DDHAL_Xxx types from ddrawi.h. In cases where the structure names are different in the headers ddrawi.h and ddrawint.h, use types from the ddrawi.h file for cross-platform compatibility. The minor naming differences are aliased with typedefs in the dx95type.h header file, which is provided to help port drivers from Windows 98/Me to Windows 2000 and later.

See DirectDraw Driver Functions for function and callback reference information.

Note The memory for all DirectX® structures should be initialized to zero before the structures are used. In addition, all structures that contain a dwSize member should set this member to the size of the structure, in bytes, before use. The following example performs these tasks on a common structure, DDCORECAPS:

DDCORECAPS ddcorecaps; // Cannot use this yet.

ZeroMemory(&ddcorecaps, sizeof(ddcorecaps));
ddcorecaps.dwSize = sizeof(ddcorecaps);

// Now the structure can be used.


DD_ATTACHLIST

The DD_ATTACHLIST structure maintains a list of attached surfaces for DirectDraw.

typedef struct _DD_ATTACHLIST {
  PDD_ATTACHLIST  lpLink;
  PDD_SURFACE_LOCAL  lpAttached;
} DD_ATTACHLIST;

Members

lpLink
Points to the next attached surface.
lpAttached
Points to a DD_SURFACE_LOCAL structure that contains the attached surface local object.


DD_CALLBACKS

DD_CALLBACKS contains entry pointers to the object callbacks that a device driver supports.

typedef struct DD_CALLBACKS {
  DWORD  dwSize;
  DWORD  dwFlags;
  PDD_DESTROYDRIVER  DestroyDriver;
  PDD_CREATESURFACE  CreateSurface;
  PDD_SETCOLORKEY  SetColorKey;
  PDD_SETMODE  SetMode;
  PDD_WAITFORVERTICALBLANK  WaitForVerticalBlank;
  PDD_CANCREATESURFACE  CanCreateSurface;
  PDD_CREATEPALETTE  CreatePalette;
  PDD_GETSCANLINE  GetScanLine;
  PDD_MAPMEMORY  MapMemory;
} DD_CALLBACKS;
typedef DD_CALLBACKS *PDD_CALLBACKS;

Members

dwSize
Specifies the size in bytes of this structure.
dwFlags
Indicates what DirectDraw object callbacks the driver has implemented. For every bit set in dwFlags, the driver must initialize the corresponding function pointer member of this structure. This member can be one or more of the following flags:

DDHAL_CB32_CANCREATESURFACE
DDHAL_CB32_CREATEPALETTE
DDHAL_CB32_CREATESURFACE
DDHAL_CB32_GETSCANLINE
DDHAL_CB32_MAPMEMORY
DDHAL_CB32_SETCOLORKEY
DDHAL_CB32_SETMODE
DDHAL_CB32_WAITFORVERTICALBLANK

DestroyDriver
Is not used on Windows 2000 and later and should be ignored by the driver.
CreateSurface
Points to the driver-supplied DdCreateSurface object callback.
SetColorKey
Points to the driver-supplied DdSetColorKey object callback.
SetMode
Is not used on Windows 2000 and later and should be ignored by the driver.
WaitForVerticalBlank
Points to the driver-supplied DdWaitForVerticalBlank object callback.
CanCreateSurface
Points to the driver-supplied DdCanCreateSurface object callback.
CreatePalette
Points to the driver-supplied DdCreatePalette object callback.
GetScanLine
Points to the driver-supplied DdGetScanLine object callback.
MapMemory
Points to the driver-supplied DdMapMemory object callback.

Comments

Entries that the display driver does not use should be set to NULL.GDI allocates the memory for this structure and calls the driver's DrvEnableDirectDraw function to initialize it.

See Also

DD_COLORCONTROLCALLBACKS, DD_KERNELCALLBACKS, DD_MISCELLANEOUSCALLBACKS, DD_MOTIONCOMPCALLBACKS, DD_NTCALLBACKS, DD_PALETTECALLBACKS, DD_SURFACECALLBACKS, DD_VIDEOPORTCALLBACKS, DrvEnableDirectDraw


DD_CLIPPER_GLOBAL

DD_CLIPPER_GLOBAL contains the global DirectDrawClipper data that can be shared between object instances.

typedef struct _DD_CLIPPER_GLOBAL {
  ULONG_PTR  dwReserved1;
} DD_CLIPPER_GLOBAL;

Members

dwReserved1
Is reserved for use by the display driver.


DD_CLIPPER_LOCAL

DD_CLIPPER_LOCAL structure contains local data for each individual DirectDrawClipper object.

typedef struct _DD_CLIPPER_LOCAL {
  ULONG_PTR  dwReserved1;
} DD_CLIPPER_LOCAL;

Members

dwReserved1
Is reserved for use by the display driver.


DD_COLORCONTROLCALLBACKS

DD_COLORCONTROLCALLBACKS structure contains an entry pointer to the DirectDraw color control callback that a device driver supports.

typedef struct _DD_COLORCONTROLCALLBACKS {
  DWORD  dwSize;
  DWORD  dwFlags;
  PDD_COLORCB_COLORCONTROL  ColorControl;
} DD_COLORCONTROLCALLBACKS, *PDD_COLORCONTROLCALLBACKS;

Members

dwSize
Specifies the size in bytes of this DD_COLORCONTROLCALLBACKS structure.
dwFlags
Indicates whether the device supports the color control callback identified by ColorControl. The driver should set this member to be DDHAL_COLOR_COLORCONTROL when it implements the color control callback.
ColorControl
Points to the driver-supplied DdControlColor callback.

Comments

Entries that the display driver does not use should be set to NULL. The driver should initialize this structure when its DdGetDriverInfo function is called with the GUID_ColorControlCallbacks GUID.

See Also

DD_CALLBACKS, DD_KERNELCALLBACKS, DD_MISCELLANEOUSCALLBACKS, DD_MOTIONCOMPCALLBACKS, DD_NTCALLBACKS, DD_PALETTECALLBACKS, DD_SURFACECALLBACKS, DD_VIDEOPORTCALLBACKS, DdGetDriverInfo


DD_D3DBUFCALLBACKS

DD_D3DBUFCALLBACKS structure is used only by drivers that implement driver level allocation of command and vertex buffers.

typedef struct _DD_D3DBUFCALLBACKS {
  DWORD  dwSize;
  DWORD  dwFlags;
  PDD_CANCREATESURFACE  CanCreateD3DBuffer;
  PDD_CREATESURFACE  CreateD3DBuffer;
  PDD_SURFCB_DESTROYSURFACE  DestroyD3DBuffer;
  PDD_SURFCB_LOCK  LockD3DBuffer;
  PDD_SURFCB_UNLOCK  UnlockD3DBuffer;
} DD_D3DBUFCALLBACKS, *PDD_D3DBUFCALLBACKS;

Members

dwSize
Specifies the size in bytes of this DD_D3DBUFCALLBACKS structure.
dwFlags
CanCreateD3DBuffer
Points to the driver's CanCreateD3DBuffer callback.
CreateD3DBuffer
Points to the driver's CreateD3DBuffer callback.
DestroyD3DBuffer
Points to the driver's DestroyD3DBuffer callback.
LockD3DBuffer
Points to the driver's LockD3DBuffer callback.
UnlockD3DBuffer
Points to the driver's UnlockD3DBuffer callback.

Comments

Drivers that manage their own command and vertex buffers will need to fill out a DD_D3DBUFCALLBACKS structure and point the lpD3DBufCallbacks member of DD_HALINFO to it.

The driver must also support the callback functions reported in the DD_D3DBUFCALLBACKS structure. These Xxx D3DBuffer callbacks are each analogous to the Dd Xxx Surface callback of similar name; they have the same prototypes and are called with the same input parameters. These new callbacks are called only when the surface in question has the DDSCAPS_EXECUTEBUFFER flag set in the surface caps. The buffer creation flags are DDSCAPS_WRITEONLY, DDSCAPS2_VERTEXBUFFER and DDSCAPS2_COMMANDBUFFER.

The driver determines the type of buffer being requested by checking the ddsCaps member of the DD_SURFACE_LOCAL structure that is passed to CanCreateD3DBuffer and CreateD3DBuffer for the following flags:

  • DDSCAPS_VERTEXBUFFER

    Indicates that the driver should allocate an Explicit Vertex Buffer.

  • DDSCAPS_COMMANDBUFFER

    Indicates that the driver should allocate a Command Buffer.

  • The absence of both these flags

    Indicates that the driver should allocate an Implicit Vertex Buffer.

Implicit Vertex Buffers should not be placed in video memory since they are expected to be read/write. Only Explicit Vertex Buffers with the DDSCAPS_WRITEONLY flag set can be safely placed in video memory.


DD_DIRECTDRAW_GLOBAL

DD_DIRECTDRAW_GLOBAL contains driver information that describes the driver's device.

typedef struct _DD_DIRECTDRAW_GLOBAL {
  VOID  *dhpdev;
  ULONG_PTR  dwReserved1;
  ULONG_PTR  dwReserved2;
  LPDDVIDEOPORTCAPS  lpDDVideoPortCaps;
} DD_DIRECTDRAW_GLOBAL;

Members

dhpdev
Is a handle to the driver's private PDEV.
dwReserved1
Is reserved for use by the display driver.
dwReserved2
Is reserved for use by the display driver.
lpDDVideoPortCaps
Points to an array of one or more DDVIDEOPORTCAPS structures in which the driver should describe the DirectDraw VPE object(s) that it supports. The structure(s) are allocated by DirectDraw; the number of structure(s) is based on the value returned in the dwMaxVideoPort member of DDCORECAPS.

This member is NULL when the driver does not implement the VPE.

Comments

DirectDraw allocates memory for this structure. Only one DD_DIRECTDRAW_GLOBAL definition exists per device. In a multi-monitor system, each device will have its own unique DD_DIRECTDRAW_GLOBAL structure.

The dwReserved1 and dwReserved2 members can be used as required by the driver. For example, a driver might store pointers to internal data structures in these members.

See Also

DD_DIRECTDRAW_LOCAL


DD_DIRECTDRAW_LOCAL

DD_DIRECTDRAW_LOCAL contains driver information that is relevant to the current DirectDraw process only.

typedef struct _DD_DIRECTDRAW_LOCAL {
  PDD_DIRECTDRAW_GLOBAL  lpGbl;
} DD_DIRECTDRAW_LOCAL;

Members

lpGbl
Points to the DD_DIRECTDRAW_GLOBAL structure that describes the driver.


DD_DXVERSION

DirectX 8.0 and later versions only.

DD_GETDRIVERINFO2DATA is used by the runtime with type D3DGDI2_TYPE_DXVERSION to notify the driver of the current DX runtime version being used by the application.

//
// This data structure is used to notify drivers about the
// DirectX version number. This is the value that is denoted
// as DD_RUNTIME_VERSION in the DDK headers.
//
typedef struct _DD_DXVERSION
{
    DD_GETDRIVERINFO2DATA gdi2;        // [in/out]
                                       // GetDriverInfo2
                                       // data
    DWORD                 dwDXVersion; // [in]
                                       // The Version of DX
    DWORD                 dwReserved;  // Reserved
} DD_DXVERSION;

Members

gdi2
The GetDriverInfo2 data.
dwDXVersion
Specifies the version of DirectX. This field will be set to DD_RUNTIME_VERSION, which is 0x00000700 for DirectX 7.0 and 0x00000800 for DirectX 8.0.
dwReserved
Reserved field. Driver should not read or write.

Comments

This information is provided to a new driver (one that exposes GetDriverInfo2) for DX7 and DX8 applications.

The runtime provides a pointer to a DD_DXVERSION structure in the lpvData field of the DD_GETDRIVERINFODATA data structure.


DD_GETDRIVERINFO2DATA

DirectX 8.0 and later versions only.

DD_GETDRIVERINFO2DATA is passed in the lpvData field of the DD_GETDRIVERINFODATA structure when GUID_GetDriverInfo2 is specified.

typedef struct _DD_GETDRIVERINFO2DATA
{
  DWORD dwReserved;   // Reserved Field.
                      // Driver should not read or write.

  DWORD dwMagic;      // Magic Number. Has D3DGDI2_MAGIC
                      // if this is a GetDriverInfo2 call.
                      // Otherwise this structure is, in
                      // fact, a DD_STEREOMODE call.
                      // Driver should only read this field.

  DWORD dwType;       // Type of information requested. This
                      // field contains one of the
                      // DDGDI2_TYPE_ values listed below.
                      // Driver should only read (not write)
                      // this field.

  DWORD dwExpectedSize;   // Expected size of the
                          // information requested.
                          // Driver should only read
                          // (not write) this field.

  // The remainder of the data buffer (beyond the first
  // four DWORDs) follows here.
} DD_GETDRIVERINFO2DATA;

Members

dwReserved
Reserved field. Driver should not read or write.
dwMagic
Specifies the magic number. Has the value D3DGDI2_MAGIC if this is a GetDriverInfo2 call. Otherwise this structure is, in fact, a DD_STEREOMODE call.
dwType
Specifies the type of information requested. This field contains one of the DDGDI2_TYPE_ values listed below. Driver should only read (not write) this field.
Value | Meaning
D3DGDI2_TYPE_GETD3DCAPS8 | This type indicates that the runtime requests to receive a D3DCAPS8 structure giving the DirectX 8.0 style capabilities of the device. The driver should copy an initialized D3DCAPS8 structure into the lpvData field of the DD_GETDRIVERINFODATA structure.
D3DGDI2_TYPE_GETFORMATCOUNT | Is used to request the number of DirectX 8.0 style surface formats supported by the driver. The data structure pointed to by the lpvData field of the DD_GETDRIVERINFODATA is DD_GETFORMATCOUNTDATA.
D3DGDI2_TYPE_GETFORMAT | Is used to query for a particular surface format from the driver. The data structure pointed to by the lpvData field of the DD_GETDRIVERINFODATA data structure is DD_GETFORMATDATA.
D3DGDI2_TYPE_DXVERSION | Is used to notify the driver of the current DX runtime version being used by the application. The runtime provides a pointer to a DD_DXVERSION structure in the lpvData field of the DD_GETDRIVERINFODATA data structure.

dwExpectedSize
Specifies the expected size of the information requested. Driver should only read (not write) this field.

Comments

The dwExpectedSize field of the DD_GETDRIVERINFODATA structure is not used when a GetDriverInfo2 request is being made. Its value is undefined in this case and should be ignored. The actual expected size of the data is found in the dwExpectedSize field of the DD_GETDRIVERINFO2DATA structure.

The following code fragment demonstrates how to handle GetDriverInfo2:

D3DCAPS8 myD3DCaps8 = { … };

DWORD CALLBACK
DdGetDriverInfo(LPDDHAL_GETDRIVERINFODATA lpData)
{
  if (MATCH_GUID((lpData->guidInfo), GUID_GetDriverInfo2))
  {
    ASSERT(NULL != lpData);
    ASSERT(NULL != lpData->lpvData);

    // Is this a call to GetDriverInfo2 or DDStereoMode?
    if (((DD_GETDRIVERINFO2DATA*)(lpData->lpvData))->dwMagic
      == D3DGDI2_MAGIC)
    {
      // Yes, its a call to GetDriverInfo2, fetch the
      // DD_GETDRIVERINFO2DATA data structure.
      DD_GETDRIVERINFO2DATA* pgdi2 = lpData->lpvData;
      ASSERT(NULL != pgdi2);
      // What type of request is this?
      switch (pgdi2->dwType)
      {
        case D3DGDI2_TYPE_GETD3DCAPS8:
        {
          // The runtime is requesting the DX8 D3D caps
          // so copy them over now. It should be noted
          // that the dwExpectedSize field of
          // DD_GETDRIVERINFODATA is not used for
          // GetDriverInfo2 calls and should be ignored.
          size_t copySize = min(
            sizeof(myD3DCaps8), pgdi2->dwExpectedSize);
          memcpy(lpData->lpvData, &myD3DCaps8, copySize);
          lpData->dwActualSize = copySize;
          lpData->ddRVal       = DD_OK;
          return DDHAL_DRIVER_HANDLED;
        }
        default:
          // For any other GetDriverInfo2 types not handled
          // or understood by the driver set an ddRVal of
          // DDERR_CURRENTLYNOTAVAIL and return
          // DDHAL_DRIVER_HANDLED.
          return DDHAL_DRIVER_HANDLED;
      }
    }
    else
    {
      // It must be a call a request for stereo mode support.
      // Fetch the stereo mode data
      DD_STEREOMODE* pStereoMode = lpData->lpvData;
      ASSERT(NULL != pStereoMode);

      // Process the stereo mode request...
      lpData->dwActualSize = sizeof(DD_STEREOMODE);
      lpData->ddRVal       = DD_OK;
      return DDHAL_DRIVER_HANDLED;
    }
  }

  // Handle any other device GUIDs...

} // DdGetDriverInfo


DD_GETFORMATDATA

DirectX 8.0 and later versions only.

DD_GETFORMATDATA is the data structure pointed to by the lpvData field of DD_GETDRIVERINFODATA for DD_GETDRIVERINFO2DATA queries with the type D3DGDI2_TYPE_GETFORMAT.

typedef struct _DD_GETFORMATDATA
{
    DD_GETDRIVERINFO2DATA gdi2;          // [in/out]
                                         // GetDriverInfo2
                                         // data
    DWORD                 dwFormatIndex; // [in]
                                         // The format to
                                         // return
    DDPIXELFORMAT         format;        // [out]
                                         // The actual
                                         // format
} DD_GETFORMATDATA;

Members

gdi2
The GetDriverInfo2 data.
dwFormatIndex
Specifies the index of the pixel format to return.
format
Receives the actual pixel format.

Comments

The runtime identifies the format to be returned with an integer index whose value varies between zero and one less than the number of supported formats reported earlier by the driver. How these indices are mapped to actual formats is left to the driver. However, each index must map uniquely to one supported format. The order in which the formats are reported is not significant. When processing this GetDriverInfo2 request the driver should read the dwFormatIndex and map that to one of the supported formats (probably by using dwFormatIndex as an index into an array of DDPIXELFORMAT structures) and then copy that format into the format field of the DD_GETFORMATDATA field. The runtime guarantees that it will only pass an index to the driver that is in the range zero to one less than the number of surface formats reported by the driver. The range of the index should be validated in the debug driver build.


DD_GETFORMATCOUNTDATA

DirectX 8.0 and later versions only.

DD_GETFORMATCOUNTDATA is the data structure pointed to by the lpvData field of DD_GETDRIVERINFODATA for DD_GETDRIVERINFO2DATA queries with the type D3DGDI2_TYPE_GETFORMAT.

typedef struct _DD_GETFORMATCOUNTDATA
{
    DD_GETDRIVERINFO2DATA gdi2;          // [in/out]
                                         // GetDriverInfo2
                                         // data
    DWORD                 dwFormatCount; // [out]
                                         // Number of
                                         // supported
                                         // surface formats
    DWORD                 dwReserved;    // Reserved
} DD_GETFORMATCOUNTDATA;

Members

gdi2
The GetDriverInfo2 data.
dwFormatCount
Receives the number of supported surface formats.
dwReserved
Reserved field. Driver should not read or write.

Comments

To handle the D3DGDI2_TYPE_GETFORMATCOUNT, the driver must store the number of DirectX 8.0 DDI style surface formats that it supports in the dwFormatCount field of the DD_GETFORMATCOUNTDATA.


DD_GETHEAPALIGNMENTDATA

DD_GETHEAPALIGNMENTDATA contains data on required alignments from a particular heap.

typedef struct _DD_GETHEAPALIGNMENTDATA {
  ULONG_PTR  dwInstance;
  DWORD  dwHeap;
  HRESULT  ddRVal;
  VOID  *GetHeapAlignment;
  HEAPALIGNMENT  Alignment;
} DD_GETHEAPALIGNMENTDATA, *PDD_GETHEAPALIGNMENTDATA;

Members

dwInstance
Indicates the driver context as returned from the driver initialization routine and stored in the dhpDev member of the DD_DIRECTDRAW_GLOBAL structure.
dwHeap
Specifies the heap index passed by DirectDraw.
ddRVal
Is the location where the driver writes the return value. A return code of DD_OK indicates success.
GetHeapAlignment
Is unused on Windows 2000 and later versions of the operating system.
Alignment
Points to a HEAPALIGNMENT structure filled in by the driver.

Comments

The dwHeap member is the ordinal number of the heap for which alignment data is being requested. In other words, it is the index into the array of VIDEOMEMORY structures pointed to by the pvmList parameter of the DrvGetDirectDrawInfo driver function.


DD_HALINFO

DD_HALINFO describes the capabilities of the hardware and driver.

typedef struct _DD_HALINFO {
  DWORD  dwSize;
  VIDEOMEMORYINFO  vmiData;
  DDCORECAPS  ddCaps;
  PDD_GETDRIVERINFO  GetDriverInfo;
  DWORD  dwFlags;
  LPVOID  lpD3DGlobalDriverData;
  LPVOID  lpD3DHALCallbacks;
  PDD_D3DBUFCALLBACKS  lpD3DBufCallbacks;
} DD_HALINFO, *PDD_HALINFO;

Members

dwSize
Specifies the size in bytes of this DD_HALINFO structure.
vmiData
Is a VIDEOMEMORYINFO structure that describes the display's memory.
ddCaps
Is a DDCORECAPS structure that contains driver-specific capabilities.
GetDriverInfo
Points to the driver's DdGetDriverInfo function. This function will be called to get further DirectDraw driver information. This member can be NULL.
dwFlags
Specifies the display driver's creation flags. The driver should set this member to DDHALINFO_GETDRIVERINFOSET when it provides a function pointer in the GetDriverInfo member.
Flag | Meaning
DDHALINFO_ISPRIMARYDISPLAY | The driver is the primary display driver.
DDHALINFO_MODEXILLEGAL | This hardware does not support ModeX modes.
DDHALINFO_GETDRIVERINFOSET | The GetDriverInfo member is set.
DDHALINFO_GETDRIVERINFO2 | Driver supports GetDriverInfo2 variant of GetDriverInfo.

lpD3DGlobalDriverData
Points to a D3DHAL_GLOBALDRIVERDATA structure that describes the 3D capabilities of the driver and its device.
lpD3DHALCallbacks
Points to the driver's initialized D3DHAL_CALLBACKS structure.
lpD3DBufCallbacks
Should normally be ignored by the driver. Used only by drivers that wish to implement driver level vertex and command buffer allocation. This is usually done for performance reasons. The lpD3DBufCallbacks member is a pointer to a DD_D3DBUFCALLBACKS structure that the driver fills out with the callbacks used to support driver managed vertex and command buffers.

Comments

GDI allocates and zero-initializes the DD_HALINFO structure and passes it to the driver's DrvGetDirectDrawInfo routine to be initialized with driver-specific data.


DD_KERNELCALLBACKS

DD_KERNELCALLBACKS contains entry pointers to the DirectDraw kernel-mode callbacks that the driver supports.

typedef struct _DD_KERNELCALLBACKS {
  DWORD  dwSize;
  DWORD  dwFlags;
  PDD_KERNELCB_SYNCSURFACE  SyncSurfaceData;
  PDD_KERNELCB_SYNCVIDEOPORT  SyncVideoPortData;
} DD_KERNELCALLBACKS, *PDD_KERNELCALLBACKS;

Members

dwSize
Specifies the size in bytes of this DD_KERNELCALLBACKS structure.
dwFlags
Indicates what DirectDraw kernel callbacks the driver has implemented. For every bit set in dwFlags, the driver must initialize the corresponding function pointer member of this structure. This member can be one or more of the following flags:

DDHAL_KERNEL_SYNCSURFACEDATA
DDHAL_KERNEL_SYNCVIDEOPORTDATA

SyncSurfaceData
Points to the driver-supplied DdSyncSurfaceData object callback.
SyncVideoPortData
Points to the driver-supplied DdSyncVideoPortData object callback.

Comments

Entries that the display driver does not use should be set to NULL. The driver should initialize this structure when its DdGetDriverInfo function is called with the GUID_KernelCallbacks GUID.

See Also

DD_COLORCONTROLCALLBACKS, DD_MISCELLANEOUSCALLBACKS, DD_MOTIONCOMPCALLBACKS, DD_NTCALLBACKS, DD_PALETTECALLBACKS, DD_SURFACECALLBACKS, DD_VIDEOPORTCALLBACKS, DdGetDriverInfo


DD_MISCELLANEOUSCALLBACKS

DD_MISCELLANEOUSCALLBACKS contains an entry pointer to the memory query callback that a device driver supports.

typedef struct _DD_MISCELLANEOUSCALLBACKS {
  DWORD  dwSize;
  DWORD  dwFlags;
  PDD_GETAVAILDRIVERMEMORY  GetAvailDriverMemory;
} DD_MISCELLANEOUSCALLBACKS;

Members

dwSize
Specifies the size in bytes of this DD_MISCELLANEOUSCALLBACKS structure.
dwFlags
Indicates whether the device supports the DdGetAvailDriverMemory callback. The driver should set this member to DDHAL_MISCCB32_GETAVAILDRIVERMEMORY when it implements the callback.
GetAvailDriverMemory
Points to the driver-supplied DdGetAvailDriverMemory callback.

Comments

Entries that the display driver does not use should be set to NULL. The driver should initialize this structure when its DdGetDriverInfo function is called with the GUID_MiscellaneousCallbacks GUID.

See Also

DD_COLORCONTROLCALLBACKS, DD_KERNELCALLBACKS, DD_MOTIONCOMPCALLBACKS, DD_NTCALLBACKS, DD_PALETTECALLBACKS, DD_SURFACECALLBACKS, DD_VIDEOPORTCALLBACKS, DdGetDriverInfo


DD_MISCELLANEOUS2CALLBACKS

DD_MISCELLANEOUS2CALLBACKS is used to return the addresses of the four new callback routines for DirectX® 7.0 that are exposed through DdGetDriverInfo by responding to the GUID_Miscellaneous2Callbacks GUID.

typedef struct _DD_MISCELLANEOUS2CALLBACKS {
    DWORD                dwSize;
    DWORD                dwFlags;
    PDD_ALPHABLT         AlphaBlt;
    PDD_CREATESURFACEEX  CreateSurfaceEx;
    PDD_GETDRIVERSTATE   GetDriverState;
    PDD_DESTROYDDLOCAL   DestroyDDLocal;
} DD_MISCELLANEOUS2CALLBACKS, *PDD_MISCELLANEOUS2CALLBACKS;

Members

dwSize
The size, in bytes of this structure.
dwFlags
Specifies the callbacks supported and flag concerning their usage.
Value | Meaning
DDHAL_MISC2CB32_ALPHABLT | The AlphaBlt callback is supported.
DDHAL_MISC2CB32_CREATESURFACEEX | The CreateSurfaceEx callback is supported.
DDHAL_MISC2CB32_GETDRIVERSTATE | The GetDriverState callback is supported.
DDHAL_MISC2CB32_DESTROYDDLOCAL | The DestroyDDLocal callback is supported.

AlphaBlt
Points to the driver's AlphaBlt implementation. See the DirectDraw DDK documentation for coverage of this function.
CreateSurfaceEx
Points to the driver's D3dCreateSurfaceEx implementation. This callback creates an association between a DirectDraw® surface and a small integer handle.
GetDriverState
Points to the driver's D3dGetDriverState implementation.
DestroyDDLocal
Points to the driver's D3dDestroyDDLocal implementation. Used to destroy the local copy of the device context.


DD_MORESURFACECAPS

DD_MORESURFACECAPS defines more driver surface capabilities in addition to those described in DDCORECAPS.

typedef struct _DD_MORESURFACECAPS
{
    DWORD  dwSize;
    DDSCAPSEX  ddsCapsMore;
    struct
    {
    DDSCAPSEX  ddsCapsEx;
    DDSCAPSEX  ddsCapsExAlt;
    } ddsExtendedHeapRestrictions[1];
} DD_MORESURFACECAPS;

Members

dwSize
Specifies the size of this DD_MORESURFACECAPS structure. The DD_MORESURFACECAPS structure is of variable size. There should be exactly DD_HALINFO.vmiData.dwNumHeaps copies of the ddsExtendedHeapRestrictions structure within the array member of this structure. The total size of a DD_MORESURFACECAPS structure is thus:
dwSize =
   sizeof(DD_MORESURFACECAPS) +
   (DD_HALINFO.vmiData.dwNumHeaps - 1) * sizeof(DDSCAPSEX) * 2

This calculation accounts for the minimum size of the DD_MORESURFACECAPS structure, which includes only one ddsExtendedHeapRestrictions array element. Any additional ddsExtendedHeapRestrictions array elements must be accounted for by adding the sizes of the remaining array elements. That is, by adding the product of the number of remaining ddsExtendedHeapRestrictions structures times the size of each one.

ddsCapsMore
Specifies the extensions to ddcaps.ddsCaps that describe the types of extended surfaces the driver can create. When a DDCAPS structure is returned to the application, it will be a DDSCAPS2 structure manufactured from DDCAPS.ddsCaps and DD_MORESURFACECAPS.ddsCapsMore.
ddsExtendedHeapRestrictions
Is a structure containing two members. These members are filled in by DirectX 6.0-aware drivers (and drivers compliant with later versions of DirectX), to restrict the video memory heaps that are exposed to DirectDraw to certain sets of DDSCAPS_Xxx bits. The DirectDraw version is determined by looking at DDVERSIONINFO, which is defined in ddrawi.h. The ddsCapsEx and ddsCapsExAlt members of the DD_MORESURFACECAPS structure are exactly analogous to the ddsCaps and ddsCapsAlt members of the VIDEOMEMORY structures listed in the VIDMEMINFO.pvmList member of DD_HALINFO.vmiData.
ddsCapsEx
Specifies a DDSCAPS structure in which the driver returns the capabilities for which this chunk of memory cannot be used.
ddsCapsExAlt
Specifies a DDSCAPS structure in which the driver returns the capabilities for which this chunk of memory cannot be used for when no other memory is found on the first pass.

Comments

This structure contains the caps bits added to the DDCAPS.ddsCaps structure in DirectX 6.0. See the DirectDraw SDK documentation for a description of the DDCAPS structure.

Note for Windows 98/Me: DD_MORESURFACECAPS is the definition for Windows 2000 and later versions. Drivers that run on Windows 98/Me will use the name DDMORESURFACECAPS, which is aliased in dx95type.h.


DD_MOTIONCOMP_LOCAL

DD_MOTIONCOMP_LOCAL contains local data for each individual DirectDraw motion compensation object.

typedef struct _DD_MOTIONCOMP_LOCAL {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  GUID  guid;
  DWORD dwUncompWidth;
  DWORD  dwUncompHeight;
  DDPIXELFORMAT  ddUncompPixelFormat;
  DWORD  dwDriverReserved1;
  DWORD  dwDriverReserved2;
  DWORD  dwDriverReserved3;
  LPVOID  lpDriverReserved1;
  LPVOID  lpDriverReserved2;
  LPVOID  lpDriverReserved3;
} DD_MOTIONCOMP_LOCAL;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that describes the DirectDraw object.
guid
Is a GUID that describes the motion compensation process being used.
dwUncompWidth
Indicates the width of the uncompressed output frame.
dwUncompHeight
Indicates the height of the uncompressed output frame.
ddUncompPixelFormat
Is a DDPIXELFORMAT structure that contains the pixel format of the uncompressed output frame.
dwDriverReserved1, dwDriverReserved2, dwDriverReserved3
Are reserved for use by the display driver.
lpDriverReserved1, lpDriverReserved2, lpDriverReserved3
Are reserved for use by the display driver.


DD_MOTIONCOMPCALLBACKS

DD_MOTIONCOMPCALLBACKS contains entry pointers to the motion compensation callbacks that a device driver supports.

typedef struct _DD_MOTIONCOMPCALLBACKS {
  DWORD  dwSize;
  DWORD  dwFlags;
  PDD_MOCOMPCB_GETGUIDS  GetMoCompGuids;
  PDD_MOCOMPCB_GETFORMATS  GetMoCompFormats;
  PDD_MOCOMPCB_CREATE  CreateMoComp;
  PDD_MOCOMPCB_GETCOMPBUFFINFO  GetMoCompBuffInfo;
  PDD_MOCOMPCB_GETINTERNALINFO  GetInternalMoCompInfo;
  PDD_MOCOMPCB_BEGINFRAME  BeginMoCompFrame;
  PDD_MOCOMPCB_ENDFRAME  EndMoCompFrame;
  PDD_MOCOMPCB_RENDER  RenderMoComp;
  PDD_MOCOMPCB_QUERYSTATUS  QueryMoCompStatus;
  PDD_MOCOMPCB_DESTROY  DestroyMoComp;
} DD_MOTIONCOMPCALLBACKS, *PDD_MOTIONCOMPCALLBACKS;

Members

dwSize
Specifies the size in bytes of this DD_MOTIONCOMPCALLBACKS structure.
dwFlags
Indicates what additional DirectDraw motion compensation callbacks the driver has implemented. For every bit set in dwFlags, the driver must initialize the corresponding function pointer member of this structure. This member can be one or more of the following flags:

DDHAL_MOCOMP32_BEGINFRAME
DDHAL_MOCOMP32_CREATE
DDHAL_MOCOMP32_DESTROY
DDHAL_MOCOMP32_GETCOMPBUFFINFO
DDHAL_MOCOMP32_GETINTERNALINFO
DDHAL_MOCOMP32_ENDFRAME
DDHAL_MOCOMP32_GETFORMATS
DDHAL_MOCOMP32_GETGUIDS
DDHAL_MOCOMP32_QUERYSTATUS
DDHAL_MOCOMP32_RENDER

GetMoCompGuids
Points to the driver-supplied DdMoCompGetGuids object callback.
GetMoCompFormats
Points to the driver-supplied DdMoCompGetFormats object callback.
CreateMoComp
Points to the driver-supplied DdMoCompCreate object callback.
GetMoCompBuffInfo
Points to the driver-supplied DdMoCompGetBuffInfo object callback.
GetInternalMoCompInfo
Points to the driver-supplied DdMoCompGetInternalInfo object callback.
BeginMoCompFrame
Points to the driver-supplied DdMoCompBeginFrame object callback.
EndMoCompFrame
Points to the driver-supplied DdMoCompEndFrame object callback.
RenderMoComp
Points to the driver-supplied DdMoCompRender object callback.
QueryMoCompStatus
Points to the driver-supplied DdMoCompQueryStatus object callback.
DestroyMoComp
Points to the driver-supplied DdMoCompDestroy object callback.

Comments

Entries that the display driver does not use should be set to NULL. The driver should initialize this structure when its DdGetDriverInfo function is called with the GUID_MotionCompCallbacks GUID.

See Also

DD_COLORCONTROLCALLBACKS, DD_KERNELCALLBACKS, DD_MISCELLANEOUSCALLBACKS, DD_NTCALLBACKS, DD_PALETTECALLBACKS, DD_SURFACECALLBACKS, DD_VIDEOPORTCALLBACKS, DdGetDriverInfo


DD_NONLOCALVIDMEMCAPS

DD_NONLOCALVIDMEMCAPS contains the capabilities for nonlocal display memory.

typedef struct _DD_NONLOCALVIDMEMCAPS {
  DWORD  dwSize;
  DWORD  dwNLVBCaps;
  DWORD  dwNLVBCaps2;
  DWORD  dwNLVBCKeyCaps;
  DWORD  dwNLVBFXCaps;
  DWORD  dwNLVBRops[DD_ROP_SPACE];
} DD_NONLOCALVIDMEMCAPS, *PDD_NONLOCALVIDMEMCAPS;

Members

dwSize
Specifies the size in bytes of this DD_NONLOCALVIDMEMCAPS structure.
dwNLVBCaps
Contains the driver-specific capabilities for nonlocal-to-local display memory blits.
dwNLVBCaps2
Contains more of the driver-specific capabilities for nonlocal-to-local display memory blits.
dwNLVBCKeyCaps
Contains driver color key capabilities for nonlocal-to-local display memory blits.
dwNLVBFXCaps
Contains driver FX capabilities for nonlocal-to-local display memory blits.
dwNLVBRops
Is an array of DD_ROP_SPACE DWORDs containing the raster operations supported for nonlocal-to-local blits. The constant DD_ROP_SPACE is defined in ddraw.h.

Comments

On Windows 2000 and later versions, the data structure is called DD_NONLOCALVIDMEMCAPS and on Windows 98/Me the data structure is called DDNONLOCALVIDMEMCAPS.

Normally, the dwNLVBCaps, dwNLVBCaps2, dwNFLBCKeyCaps, dwNLVBFXCaps, and dwNLVBRops members contain a subset of the flags used in the DDCORECAPS structure that is relevant to nonlocal-to-local blitting. However, to allow flexibility for device driver writers, any of the flags in DDCORECAPS can be used.


DD_NTCALLBACKS

DD_NTCALLBACKS contains entry pointers to Windows 2000 and later DirectDraw callbacks that a device driver supports.

typedef struct _DD_NTCALLBACKS {
  DWORD  dwSize;
  DWORD  dwFlags;
  PDD_FREEDRIVERMEMORY  FreeDriverMemory;
  PDD_SETEXCLUSIVEMODE  SetExclusiveMode;
  PDD_FLIPTOGDISURFACE  FlipToGDISurface;
} DD_NTCALLBACKS, *PDD_NTCALLBACKS;

Members

dwSize
Specifies the size in bytes of this DD_NTCALLBACKS structure.
dwFlags
Indicates what Windows 2000 and later callbacks the driver has implemented. For every bit set in dwFlags, the driver must initialize the corresponding function pointer member of this structure. This member can be one or more of the following flags:

DDHAL_NTCB32_FREEDRIVERMEMORY
DDHAL_NTCB32_SETEXCLUSIVEMODE
DDHAL_NTCB32_FLIPTOGDISURFACE

FreeDriverMemory
Points to the driver-supplied DdFreeDriverMemory callback.
SetExclusiveMode
Points to the driver-supplied DdSetExclusiveMode callback.
FlipToGDISurface
Points to the driver-supplied DdFlipToGDISurface callback.

Comments

Entries that the display driver does not use should be set to NULL. The driver should initialize this structure when its DdGetDriverInfo function is called with the GUID_NTCallbacks GUID.

See Also

DD_COLORCONTROLCALLBACKS, DD_KERNELCALLBACKS, DD_MISCELLANEOUSCALLBACKS, DD_MOTIONCOMPCALLBACKS, DD_PALETTECALLBACKS, DD_SURFACECALLBACKS, DD_VIDEOPORTCALLBACKS, DdGetDriverInfo


DD_NTPRIVATEDRIVERCAPS

DD_NTPRIVATEDRIVERCAPS enables the driver to change the behavior of DirectDraw when DirectDraw is creating surfaces.

typedef struct DD_NTPRIVATEDRIVERCAPS {
  DWORD  dwSize;
  DWORD  dwPrivateCaps;
} DD_NTPRIVATEDRIVERCAPS;

Members

dwSize
Specifies the size in bytes of this DD_NTPRIVATEDRIVERCAPS structure.
dwPrivateCaps
Indicates how DirectDraw should create the surface.
DDHAL_PRIVATECAP_AUTOMICSURFACECREATION
When this flag is set, it indicates that the driver requests DdCreateSurface to be called only once when the application creates a complex flipping chain using a single CreateSurface call. In this case, the lplpSList member of the DD_CREATESURFACEDATA structure points to a list of surfaces to create (rather than a single surface) and dwSCnt contains the number of surfaces in the list.
DDHAL_PRIVATECAP_NOTIFYPRIMARYCREATION
When this flag is set, the driver's DdCreateSurface function will be called when creating a primary surface. If this flag is not set, the driver's DdCreateSurface function will not be called.

Comments

The behavior of DirectDraw emulates the surface creation techniques employed by DirectDraw when creating surfaces for Windows 98/Me.

When the DDHAL_PRIVATECAP_AUTOMICSURFACECREATION flag is not set, DirectDraw will perform surface creation using the original method, that is, it will call the driver's DdCreateSurface function once for each surface being created.

When the DDHAL_PRIVATECAP_NOTIFYPRIMARYCREATION flag is not set, DirectDraw will perform primary surface creation using the original method, that is, it will not call the driver when creating a primary surface.


DD_PALETTE_GLOBAL

DD_PALETTE_GLOBAL contains the global DirectDrawPalette data that can be shared between object instances.

typedef struct _DD_PALETTE_GLOBAL {
  ULONG_PTR  dwReserved1;
} DD_PALETTE_GLOBAL;

Members

dwReserved1
Is reserved for use by the display driver.


DD_PALETTE_LOCAL

DD_PALETTE_LOCAL contains palette-related data that is unique to an individual palette object.

typedef struct _DD_PALETTE_LOCAL {
  ULONG  dwReserved0;
  ULONG_PTR  dwReserved1;
} DD_PALETTE_LOCAL;

Members

dwReserved0
Is reserved for system use.
dwReserved1
Is reserved for use by the display driver


DD_PALETTECALLBACKS

DD_PALETTECALLBACKS contains entry pointers to the DirectDraw palette callbacks that a device driver supports.

typedef struct DD_PALETTECALLBACKS {
  DWORD  dwSize;
  DWORD  dwFlags;
  PDD_PALCB_DESTROYPALETTE  DestroyPalette;
  PDD_PALCB_SETENTRIES  SetEntries;
} DD_PALETTECALLBACKS, *PDD_PALETTECALLBACKS;

Members

dwSize
Specifies the size in bytes of this DD_PALETTECALLBACKS structure.
dwFlags
Indicates what DirectDrawPalette callbacks the driver has implemented. For every bit set in dwFlags, the driver must initialize the corresponding function pointer member of this structure. This member can be one or more of the following flags:

DDHAL_PALCB32_DESTROYPALETTE
DDHAL_PALCB32_SETENTRIES

DestroyPalette
Points to the driver-supplied DdDestroyPalette palette callback.
SetEntries
Points to the driver-supplied DdSetEntries palette callback.

Comments

Entries that the display driver does not use should be set to NULL. The driver initializes this structure in DrvEnableDirectDraw.

See Also

DD_COLORCONTROLCALLBACKS, DD_KERNELCALLBACKS, DD_MISCELLANEOUSCALLBACKS, DD_MOTIONCOMPCALLBACKS, DD_NTCALLBACKS, DD_SURFACECALLBACKS, DD_VIDEOPORTCALLBACKS, DrvEnableDirectDraw


DD_STEREOMODE

DD_STEREOMODE is used by the runtime with GUID_DDStereoMode to query whether the driver supports stereo for a given video display mode.

// The runtime checks each mode in the driver to see
// if it supports stereo. The driver returns DD_OK
// if GUID_DDStereoMode is supported.
typedef struct _DD_STEREOMODE
{
    DWORD       dwSize;         // size of DD_STEREOMODE
    DWORD       dwHeight;
    DWORD       dwWidth;
    DWORD       dwBpp;
    DWORD       dwRefreshRate;
    BOOL        bSupported;     // driver supports this mode
} DD_STEREOMODE, FAR * LPDDSTEREOMODE;} DD_DXVERSION;

Members

dwSize
Specifies the size in bytes of the DD_STEREOMODE structure.
dwHeight
Specifies the height in scanlines of the display mode. Has the value D3DGDI2_MAGIC if this structure is, in fact, a DD_GETDRIVERINFO2DATA call.
dwWidth
Specifies the width in pixels of the display mode.
dwBpp
Specifies the bits per pixel of the display mode.
dwRefreshRate
Specifies the refresh rate in hertz of the display mode.
bSupported
Driver sets to TRUE is stereo is supported with the specified display mode, or FALSE otherwise.

Comments

GUID_DDStereoMode is a way to turn OFF stereo per-mode, since it is expected that a driver that can do stereo can do stereo in any mode.

The runtime provides a pointer to a DD_STEREOMODE structure in the lpvData field of the DD_GETDRIVERINFODATA data structure.


DD_SURFACE_GLOBAL

DD_SURFACE_GLOBAL contains global surface-related data that can be shared between multiple surfaces.

typedef struct _DD_SURFACE_GLOBAL {
  DWORD  dwBlockSizeY;
  union {
  LPVIDEOMEMORY  lpVidMemHeap;
  DWORD  dwBlockSizeX;
  DWORD  dwUserMemSize;
  };
  FLATPTR  fpVidMem;
  union {
  LONG  lPitch;
  DWORD  dwLinearSize;
  };
  LONG  yHint;
  LONG  xHint;
  DWORD  wHeight;
  DWORD  wWidth;
  ULONG_PTR  dwReserved1;
  DDPIXELFORMAT  ddpfSurface;
  FLATPTR  fpHeapOffset;
  HANDLE  hCreatorProcess;
} DD_SURFACE_GLOBAL;

Members

dwBlockSizeY
Specifies the location in which the driver returns the height, in scanlines, of the offscreen memory block that DirectDraw should allocate. The driver should set this value when it returns DDHAL_PLEASEALLOC_BLOCKSIZE in the fpVidMem member.
lpVidMemHeap
Points to a VIDEOMEMORY structure from which the heap display memory was allocated.
dwBlockSizeX
Specifies the location in which the driver returns the size in bytes of the width of the offscreen memory block that DirectDraw should allocate. The driver should set this value when it returns DDHAL_PLEASEALLOC_BLOCKSIZE in the fpVidMem member.
dwUserMemSize
Specifies the location in which the driver returns the size in bytes of the memory block that DirectDraw should allocate in user-mode system memory. driver should set this value when it returns DDHAL_PLEASEALLOC_USERMEM in the fpVidMem member.
fpVidMem
If the driver allocates the memory block, it should return the offset into display memory in this member. If the driver requests DirectDraw to do the memory allocation, it can instead return one of the following values in this member from its DdCreateSurface routine:
Value | Meaning
DDHAL_PLEASEALLOC_BLOCKSIZE | DirectDraw should allocate a memory block of size dwBlockSizeX in offscreen memory.
DDHAL_PLEASEALLOC_USERMEM | DirectDraw should allocate a memory block of size dwBlockSizeX in user-mode memory.

dwLinearSize
Specifies the linear size of a non-rectangular surface.
lPitch
Specifies the pitch of the surface; that is, the distance in bytes to the start of the next line. This is also known as the stride of the surface.
yHint
Specifies the y-coordinate of the surface. This member is a 2D Cartesian coordinate specified in device space.
xHint
Specifies the x-coordinate of the surface. This member is a 2D Cartesian coordinate specified in device space.
wHeight
Specifies the height of the surface.
wWidth
Specifies the width of the surface.
dwReserved1
Is reserved for use by the display driver.
ddpfSurface
Points to the DDPIXELFORMAT structure that describes the pixel format of the surface.
fpHeapOffset
Points to the raw offset in the source heap.
hCreatorProcess
Is reserved for system use and should be ignored by the driver.

Comments

A vertex buffer, which is created by CreateD3DBuffer, holds a list of vertices used by the D3dDrawPrimitives2 callback for rendering primitives. Windows represents vertex buffers as a DirectDraw surfaces, thereby establishing a connection between vertex buffers and the DD_SURFACE_GLOBAL structure.

When a DirectX driver is working with a vertex buffer, it is important for it to be able to correctly determine the size of this buffer. DirectDraw passes the linear buffer size to the driver in the lPitch member of this structure. On Windows 2000 and later versions, but not on Windows 98/Me, the wWidth member of this structure is set to the same value. Note that both structure members should be considered to be read-only. The value that DirectDraw places in these members represents the minimum vertex buffer size. Should the need for a larger buffer arise (such as for optimization), a driver writer is free to create a buffer larger than that size. Under no circumstances, however, should the driver report the larger buffer size to DirectDraw.


DD_SURFACE_LOCAL

DD_SURFACE_LOCAL contains surface-related data that is unique to an individual surface object.

typedef struct _DD_SURFACE_LOCAL {
  PDD_SURFACE_GLOBAL  lpGbl;
  DWORD  dwFlags;
  DDSCAPS  ddsCaps;
  ULONG_PTR  dwReserved1;
  union {
  DDCOLORKEY  ddckCKSrcOverlay;
  DDCOLORKEY  ddckCKSrcBlt;
  }
  union {
  DDCOLORKEY  ddckCKDestOverlay;
  DDCOLORKEY  ddckCKDestBlt;
  }
  PDD_SURFACE_MORE  lpSurfMore;
  PDD_ATTACHLIST  lpAttachList;
  PDD_ATTACHLIST  lpAttachListFrom;
  RECT  rcOverlaySrc;
} DD_SURFACE_LOCAL;

Members

lpGbl
Points to the DD_SURFACE_GLOBAL structure containing surface data that is shared globally with multiple surfaces.
dwFlags
Is a set of surface flags.
Flag | Meaning
DDRAWISURF_BACKBUFFER | The surface was originally a back buffer.
DDRAWISURF_DRIVERMANAGED | The surface is a driver managed texture used with Direct3D.
DDRAWISURF_FRONTBUFFER | The surface was originally a front buffer.
DDRAWISURF_HASCKEYSRCBLT | The surface has source color key overlay data in the ddckCKSrcBlt member.
DDRAWISURF_HASOVERLAYDATA | The surface has overlay data.
DDRAWISURF_HASPIXELFORMAT | The surface has pixel format data.
DDRAWISURF_INVALID | The surface has been invalidated by a mode setting operation.

ddsCaps
Is a DDSCAPS structure that describes the capabilities of the surface.
dwReserved1
Is reserved for use by the display driver.
ddckCKSrcOverlay
Is a DDCOLORKEY structure (defined in the DirectDraw SDK documentation) that contains the color key information for source overlay use.
ddckCKSrcBlt
Is a DDCOLORKEY structure that describes the color key for source color key overlays.
ddckCKDestOverlay
Is a DDCOLORKEY structure (defined in the DirectDraw SDK documentation) that contains the color key information for destination overlay use.
ddckCKDestBlt
Is a DDCOLORKEY structure (defined in the DirectDraw SDK documentation) that describes the color key for destination color key overlays.
lpSurfMore
Points to a DD_SURFACE_MORE structure that contains additional local surface data.
lpAttachList
Points to a DD_ATTACHLIST structure that contains the list of surfaces to which this surface attached.
lpAttachListFrom
Points to a DD_ATTACHLIST structure that contains the list of surfaces attached to this surface.
rcOverlaySrc
Is reserved for system use and should be ignored by the driver.


DD_SURFACE_MORE

DD_SURFACE_MORE contains additional local data for each individual DirectDrawSurface object.

typedef struct _DD_SURFACE_MORE {
  DWORD  dwMipMapCount;
  PDD_VIDEOPORT_LOCAL  lpVideoPort;
  DWORD  dwOverlayFlags;
  DDSCAPSEX  ddsCapsEx;
  DWORD  dwSurfaceHandle;
} DD_SURFACE_MORE, *PDD_SURFACE_MORE;

Members

dwMipMapCount
Contains the number of mipmap levels in the chain.
lpVideoPort
Points to a DD_VIDEOPORT_LOCAL structure of the VPE object currently writing data to this surface.
dwOverlayFlags
Is a set of flags that indicate the overlay flags most recently passed to DdUpdateOverlay.
Flag | Meaning
DDOVER_ADDDIRTYRECT | Add a dirty rectangle to an emulated overlaid surface.
DDOVER_ALPHADEST | Use the alpha information in the pixel format or the alpha channel surface attached to the destination surface as the alpha channel for the destination overlay.
DDOVER_ALPHADESTCONSTOVERRIDE | Use the dwConstAlphaDest member in the DDOVERLAYFX structure (defined in the DirectDraw SDK documentation) as the destination alpha channel for this overlay.
DDOVER_ALPHADESTNEG | The NEG suffix indicates that the destination surface becomes more transparent as the alpha value increases.
DDOVER_ALPHADESTSURFACEOVERRIDE | Use the lpDDSAlphaDest member in the DDOVERLAYFX structure (defined in the DirectDraw SDK documentation) as the alpha channel destination for this overlay.
DDOVER_ALPHAEDGEBLEND | Use the dwAlphaEdgeBlend member in the DDOVERLAYFX structure as the alpha channel for the edges of the image that border the color key colors.
DDOVER_ALPHASRC | Use the alpha information in the pixel format or the alpha channel surface attached to the source surface as the source alpha channel for this overlay.
DDOVER_ALPHASRCCONSTOVERRIDE | Use the dwConstAlphaSrc member in the DDOVERLAYFX structure (defined in the DirectDraw SDK documentation) as the source alpha channel for this overlay.
DDOVER_ALPHASRCNEG | The NEG suffix indicates that the source surface becomes more transparent as the alpha value increases.
DDOVER_ALPHASRCSURFACEOVERRIDE | Use the lpDDSAlphaSrc member in the DDOVERLAYFX structure as the alpha channel source for this overlay.
DDOVER_AUTOFLIP | Autoflip the overlay whenever the VPE object autoflips.
DDOVER_BOB | Display each field of VPE object data individually without causing any jittery artifacts.
DDOVER_BOBHARDWARE | Bob is performed using hardware rather than software or emulated.
DDOVER_DDFX | Use the overlay FX flags to define special overlay FX.
DDOVER_HIDE | Turn this overlay off.
DDOVER_INTERLEAVED | Indicates that the surface memory is composed of interleaved fields.
DDOVER_KEYDEST | Use the color key associated with the destination surface.
DDOVER_KEYDESTOVERRIDE | Use the dckDestColorkey member in the DDOVERLAYFX structure (defined in the DirectDraw SDK documentation) as the color key for the destination surface.
DDOVER_KEYSRC | Use the color key associated with the source surface.
DDOVER_KEYSRCOVERRIDE | Use the dckSrcColorkey member in the DDOVERLAYFX structure as the color key for the source surface.
DDOVER_OVERRIDEBOBWEAVE | Bob and weave decisions should not be overridden by other interfaces. If this flag is set, DirectDraw will not allow a kernel-mode driver to use the kernel-mode video transport functionality to switch the hardware between bob and weave mode.
DDOVER_REFRESHALL | Redraw the entire surface on an emulated overlayed surface.
DDOVER_REFRESHDIRTYRECTS | Redraw all dirty rectangles on an emulated overlayed surface.
DDOVER_SHOW | Turn this overlay on.

ddsCapsEx
Is used to expose extended surface capabilities. For more information, see Extended Surface Capabilities in the design guide.
dwSurfaceHandle
Is a cookie for D3dCreateSurfaceEx so that it can associated a texture handle with the surface.


DD_SURFACECALLBACKS

DD_SURFACECALLBACKS contains entry pointers to the DirectDraw surface callbacks that a device driver supports.

typedef struct DD_SURFACECALLBACKS {
  DWORD  dwSize;
  DWORD  dwFlags;
  PDD_SURFCB_DESTROYSURFACE  DestroySurface;
  PDD_SURFCB_FLIP  Flip;
  PDD_SURFCB_SETCLIPLIST  SetClipList;
  PDD_SURFCB_LOCK  Lock;
  PDD_SURFCB_UNLOCK  Unlock;
  PDD_SURFCB_BLT  Blt;
  PDD_SURFCB_SETCOLORKEY  SetColorKey;
  PDD_SURFCB_ADDATTACHEDSURFACE  AddAttachedSurface;
  PDD_SURFCB_GETBLTSTATUS  GetBltStatus;
  PDD_SURFCB_GETFLIPSTATUS  GetFlipStatus;
  PDD_SURFCB_UPDATEOVERLAY  UpdateOverlay;
  PDD_SURFCB_SETOVERLAYPOSITION  SetOverlayPosition;
  LPVOID  reserved4;
  PDD_SURFCB_SETPALETTE  SetPalette;
} DD_SURFACECALLBACKS, *PDD_SURFACECALLBACKS;

Members

dwSize
Specifies the size in bytes of the DD_SURFACECALLBACKS structure. This member is unused by Windows 2000 and later versions.
dwFlags
Indicates which DirectDrawSurface callbacks the driver has implemented. For every bit set in dwFlags, the driver must initialize the corresponding function pointer member of this structure. This member can be one or more of the following flags:

DDHAL_SURFCB32_DESTROYSURFACE
DDHAL_SURFCB32_FLIP
DDHAL_SURFCB32_SETCLIPLIST
DDHAL_SURFCB32_LOCK
DDHAL_SURFCB32_UNLOCK
DDHAL_SURFCB32_BLT
DDHAL_SURFCB32_SETCOLORKEY
DDHAL_SURFCB32_ADDATTACHEDSURFACE
DDHAL_SURFCB32_GETBLTSTATUS
DDHAL_SURFCB32_GETFLIPSTATUS
DDHAL_SURFCB32_UPDATEOVERLAY
DDHAL_SURFCB32_SETOVERLAYPOSITION
DDHAL_SURFCB32_SETPALETTE

DestroySurface
Points to the driver-supplied DdDestroySurface surface callback.
Flip
Points to the driver-supplied DdFlip surface callback.
SetClipList
Points to the driver-supplied DdSetClipList surface callback.
Lock
Points to the driver-supplied DdLock surface callback.
Unlock
Points to the driver-supplied DdUnlock surface callback.
Blt
Points to the driver-supplied DdBlt surface callback.
SetColorKey
Points to the driver-supplied DdSetColorKey surface callback.
AddAttachedSurface
Points to the driver-supplied DdAddAttachedSurface surface callback.
GetBltStatus
Points to the driver-supplied DdGetBltStatus surface callback.
GetFlipStatus
Points to the driver-supplied DdGetFlipStatus surface callback.
UpdateOverlay
Points to the driver-supplied DdUpdateOverlay surface callback.
SetOverlayPosition
Points to the driver-supplied DdSetOverlayPosition surface callback.
reserved4
Is reserved for system use and should be ignored by the driver.
SetPalette
Points to the driver-supplied DdSetPalette surface callback.

Comments

Entries that the display driver does not use should be set to NULL. The driver initializes this structure in DrvEnableDirectDraw.

See Also

DD_COLORCONTROLCALLBACKS, DD_KERNELCALLBACKS, DD_MISCELLANEOUSCALLBACKS, DD_MOTIONCOMPCALLBACKS, DD_NTCALLBACKS, DD_PALETTECALLBACKS, DD_VIDEOPORTCALLBACKS, DrvEnableDirectDraw


DD_UPDATENONLOCALHEAPDATA

DD_UPDATENONLOCALHEAPDATA contains the required heap information.

typedef struct _DD_UPDATENONLOCALHEAPDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  DWORD  dwHeap;
  FLATPTR  fpGARTLin;
  FLATPTR  fpGARTDev;
  ULONG_PTR  ulPolicyMaxBytes;
  HRESULT  ddRVal;
  VOID  *UpdateNonLocalHeap;
} DD_UPDATENONLOCALHEAPDATA;

Members

lpDD
Points to the DD_DIRECTDRAW_GLOBAL structure that represents the DirectDraw object.
dwHeap
Indicates the heap index.
fpGARTLin
Points to the linear graphic address remapping table (GART) address of the start of the heap.
fpGARTDev
Points to the physical GART address of the start of the heap.
ulPolicyMaxBytes
Indicates the maximum amount of AGP memory to use.
ddRVal
Is the location in which the driver writes the return value. A return code of DD_OK indicates success.
UpdateNonLocalHeap
Is unused on Windows 2000 and later versions of the operating system.


DD_VIDEOPORT_LOCAL

DD_VIDEOPORT_LOCAL contains VPE-related data that is unique to an individual DirectDraw VPE object.

typedef struct _DD_VIDEOPORT_LOCAL {
  PDD_DIRECTDRAW_LOCAL  lpDD;
  DDVIDEOPORTDESC  ddvpDesc;
  DDVIDEOPORTINFO  ddvpInfo;
  PDD_SURFACE_INT  lpSurface;
  PDD_SURFACE_INT  lpVBISurface;
  DWORD  dwNumAutoflip;
  DWORD  dwNumVBIAutoflip;
  ULONG_PTR  dwReserved1;
  ULONG_PTR  dwReserved2;
  ULONG_PTR  dwReserved3;
} DD_VIDEOPORT_LOCAL;

Members

lpDD
Points to a DD_DIRECTDRAW_LOCAL structure that contains the DirectDraw object's data.
ddvpDesc
Is a DDVIDEOPORTDESC structure that describes the VPE object.
ddvpInfo
Is a DDVIDEOPORTINFO structure that describes the transfer of video data to a surface.
lpSurface
Points to a DD_SURFACE_INT structure for the surface receiving the video data.
lpVBISurface
Points to a DD_SURFACE_INT structure for the surface receiving the VBI data.
dwNumAutoflip
Specifies the number of current autoflip surfaces.
dwNumVBIAutoflip
Specifies the number of VBI surfaces currently being autoflipped.
dwReserved1, dwReserved2, dwReserved3
Are reserved for use by the display driver.

Comments

This structure is initialized and filled in by DirectDraw. Except for the dwReserved1, dwReserved2, and dwReserved3 members, the driver must not modify any other members of the DD_VIDEOPORT_LOCAL structure.


DD_VIDEOPORTCALLBACKS

DD_VIDEOPORTCALLBACKS contains entry pointers to DirectDraw VPE callbacks that a device driver supports.

typedef struct DD_VIDEOPORTCALLBACKS {
  DWORD  dwSize;
  DWORD  dwFlags;
  PDD_VPORTCB_CANCREATEVIDEOPORT  CanCreateVideoPort;
  PDD_VPORTCB_CREATEVIDEOPORT  CreateVideoPort;
  PDD_VPORTCB_FLIP  FlipVideoPort;
  PDD_VPORTCB_GETBANDWIDTH  GetVideoPortBandwidth;
  PDD_VPORTCB_GETINPUTFORMATS  GetVideoPortInputFormats;
  PDD_VPORTCB_GETOUTPUTFORMATS  GetVideoPortOutputFormats;
  LPVOID  lpReserved1;
  PDD_VPORTCB_GETFIELD  GetVideoPortField;
  PDD_VPORTCB_GETLINE  GetVideoPortLine;
  PDD_VPORTCB_GETVPORTCONNECT  GetVideoPortConnectInfo;
  PDD_VPORTCB_DESTROYVPORT  DestroyVideoPort;
  PDD_VPORTCB_GETFLIPSTATUS  GetVideoPortFlipStatus;
  PDD_VPORTCB_UPDATE  UpdateVideoPort;
  PDD_VPORTCB_WAITFORSYNC  WaitForVideoPortSync;
  PDD_VPORTCB_GETSIGNALSTATUS  GetVideoSignalStatus;
  PDD_VPORTCB_COLORCONTROL  ColorControl;
} DD_VIDEOPORTCALLBACKS, *PDD_VIDEOPORTCALLBACKS;

Members

dwSize
Specifies the size in bytes of this DD_VIDEOPORTCALLBACKS structure.
dwFlags
Indicates what VPE callbacks the driver has implemented. For every bit set in dwFlags, the driver must initialize the corresponding function pointer member of this structure. This member can be one or more of the following flags:

DDHAL_VPORT32_CANCREATEVIDEOPORT
DDHAL_VPORT32_CREATEVIDEOPORT
DDHAL_VPORT32_FLIP
DDHAL_VPORT32_GETBANDWIDTH
DDHAL_VPORT32_GETINPUTFORMATS
DDHAL_VPORT32_GETOUTPUTFORMATS
DDHAL_VPORT32_GETAUTOFLIPSURF
DDHAL_VPORT32_GETFIELD
DDHAL_VPORT32_GETLINE
DDHAL_VPORT32_GETCONNECT
DDHAL_VPORT32_DESTROY
DDHAL_VPORT32_GETFLIPSTATUS
DDHAL_VPORT32_UPDATE
DDHAL_VPORT32_WAITFORSYNC
DDHAL_VPORT32_GETSIGNALSTATUS
DDHAL_VPORT32_COLORCONTROL

CanCreateVideoPort
Points to the driver-supplied DdVideoPortCanCreate callback.
CreateVideoPort
Points to the driver-supplied DdVideoPortCreate callback.
FlipVideoPort
Points to the driver-supplied DdVideoPortFlip callback.
GetVideoPortBandwidth
Points to the driver-supplied DdVideoPortGetBandwidth callback.
GetVideoPortInputFormats
Points to the driver-supplied DdVideoPortGetInputFormats callback.
GetVideoPortOutputFormats
Points to the driver-supplied DdVideoPortGetOutputFormats callback.
lpReserved1
Is reserved for system use and should be ignored by the driver.
GetVideoPortField
Points to the driver-supplied DdVideoPortGetField callback.
GetVideoPortLine
Points to the driver-supplied DdVideoPortGetLine callback.
GetVideoPortConnectInfo
Points to the driver-supplied DdVideoPortGetConnectInfo callback.
DestroyVideoPort
Points to the driver-supplied DdVideoPortDestroy callback.
GetVideoPortFlipStatus
Points to the driver-supplied DdVideoPortGetFlipStatus callback.
UpdateVideoPort
Points to the driver-supplied DdVideoPortUpdate callback.
WaitForVideoPortSync
Points to the driver-supplied DdVideoPortWaitForSync callback.
GetVideoSignalStatus
Points to the driver-supplied DdVideoPortGetSignalStatus callback.
ColorControl
Points to the driver-supplied DdVideoPortColorControl callback.

Comments

Entries that the display driver does not use should be set to NULL. The driver should initialize this structure when its DdGetDriverInfo function is called with the GUID_VideoPortCallbacks GUID.

See Also

DD_COLORCONTROLCALLBACKS, DD_KERNELCALLBACKS, DD_MISCELLANEOUSCALLBACKS, DD_MOTIONCOMPCALLBACKS, DD_NTCALLBACKS, DD_PALETTECALLBACKS, DD_SURFACECALLBACKS, DdGetDriverInfo


DDCOLORCONTROL

DDCOLORCONTROL defines the color controls associated with a DirectDraw VPE object.

typedef struct _DDCOLORCONTROL {
  DWORD  dwSize;
  DWORD  dwFlags;
  LONG  lBrightness;
  LONG  lContrast;
  LONG  lHue;
  LONG  lSaturation;
  LONG  lSharpness;
  LONG  lGamma;
  LONG  lColorEnable;
  DWORD  dwReserved1;
} DDCOLORCONTROL;

Members

dwSize
Specifies the size in bytes of this DDCOLORCONTROL structure.
dwFlags
Is a set of flags that specify what structure members contain valid data. When the structure is returned by DdVideoPortColorControl, it also indicates what options are supported by the VPE object. This member can be a bitwise OR of the following values:
Flag | Meaning
DDCOLOR_BRIGHTNESS | The lBrightness member contains valid data.
DDCOLOR_CONTRAST | The lContrast member contains valid data.
DDCOLOR_COLORENABLE | The lColorEnable member contains valid data.
DDCOLOR_GAMMA | The lGamma member contains valid data.
DDCOLOR_HUE | The lHue member contains valid data.
DDCOLOR_SATURATION | The lSaturation member contains valid data.
DDCOLOR_SHARPNESS | The lSharpness member contains valid data.

lBrightness
Specifies the luminance intensity (Black Level), in IRE units*100. This member can range from 0 to 10,000, with a default value of 750 (7.5 IRE).
lContrast
Specifies the relative difference between higher and lower intensity luminance values, in IRE units*100. This member can range from 0 to 20,000, with a default value of 10,000 (100 IRE). Higher values of contrast cause darker luminance values to tend towards black, and cause lighter luminance values to tend towards white. Lower values of contrast cause all luminance values to move towards the middle luminance values.
lHue
Specifies the phase relationship of the chrominance components. Hue is specified in degrees, with a valid range of -180 to 180. The default is 0 degrees.
lSaturation
Specifies the color intensity, in IRE units*100. This member can range from 0 to 20,000, with a default value of 10,000 (100 IRE).
lSharpness
Specifies the sharpness in arbitrary units. The valid range is 0 to 10, with a default value of 5.
lGamma
Controls the amount of gamma correction applied to the luminance values. The valid range is 1 to 500 gamma units, with a default of 1.
lColorEnable
Is a flag indicating whether color is used. If this member is zero, color is not used; if it is 1, then color is used. The default value is 1.
dwReserved1
Is reserved for system use and should be ignored.


DDCOMPBUFFERINFO

DDCOMPBUFFERINFO contains driver-supplied information regarding compression buffers.

typedef struct _DDCOMPBUFFERINFO {
  DWORD  dwSize;
  DWORD  dwNumCompBuffers;
  DWORD  dwWidthToCreate;
  DWORD  dwHeightToCreate;
  DWORD  dwBytesToAllocate;
  DDSCAPS2  ddCompCaps;
  DDPIXELFORMAT  ddPixelFormat;
} DDCOMPBUFFERINFO, *LPDDCOMPBUFFERINFO;

Members

dwSize
Specifies the size in bytes of this DDCOMPBUFFERINFO structure.
dwNumCompBuffers
Indicates the number of surfaces of this type required for decompression.
dwWidthToCreate
Indicates the width of the surface of this type to create.
dwHeightToCreate
Indicates the height of the surface of this type to create.
dwBytesToAllocate
Indicates the total number of bytes used by each surface.
ddCompCaps
Points to a DDSCAPS2 structure that contains the capabilities to use when creating surfaces of this type. This allows the driver to specify the type of memory to use when creating these surfaces.
ddPixelFormat
Points to a DDPIXELFORMAT structure that contains the pixel formats to use when creating surfaces of this type.

Comments

This structure passes this information to the DD_GETMOCOMPCOMPBUFFDATA structure.


DDCORECAPS

DDCORECAPS specifies the core capabilities of the DirectDraw driver and its device, which are exposed to an application through the DirectDraw object.

typedef typedef struct _DDCORECAPS {
  DWORD  dwSize;
  DWORD  dwCaps;
  DWORD  dwCaps2;
  DWORD  dwCKeyCaps;
  DWORD  dwFXCaps;
  DWORD  dwFXAlphaCaps;
  DWORD  dwPalCaps;
  DWORD  dwSVCaps;
  DWORD  dwAlphaBltConstBitDepths;
  DWORD  dwAlphaBltPixelBitDepths;
  DWORD  dwAlphaBltSurfaceBitDepths;
  DWORD  dwAlphaOverlayConstBitDepths;
  DWORD  dwAlphaOverlayPixelBitDepths;
  DWORD  dwAlphaOverlaySurfaceBitDepths;
  DWORD  dwZBufferBitDepths;
  DWORD  dwVidMemTotal;
  DWORD  dwVidMemFree;
  DWORD  dwMaxVisibleOverlays;
  DWORD  dwCurrVisibleOverlays;
  DWORD  dwNumFourCCCodes;
  DWORD  dwAlignBoundarySrc;
  DWORD  dwAlignSizeSrc;
  DWORD  dwAlignBoundaryDest;
  DWORD  dwAlignSizeDest;
  DWORD  dwAlignStrideAlign;
  DWORD  dwRops[DD_ROP_SPACE];
  DDSCAPS  ddsCaps;
  DWORD  dwMinOverlayStretch;
  DWORD  dwMaxOverlayStretch;
  DWORD  dwMinLiveVideoStretch;
  DWORD  dwMaxLiveVideoStretch;
  DWORD  dwMinHwCodecStretch;
  DWORD  dwMaxHwCodecStretch;
  DWORD  dwReserved1;
  DWORD  dwReserved2;
  DWORD  dwReserved3;
  DWORD  dwSVBCaps;
  DWORD  dwSVBCKeyCaps;
  DWORD  dwSVBFXCaps;
  DWORD  dwSVBRops[DD_ROP_SPACE];
  DWORD  dwVSBCaps;
  DWORD  dwVSBCKeyCaps;
  DWORD  dwVSBFXCaps;
  DWORD  dwVSBRops[DD_ROP_SPACE];
  DWORD  dwSSBCaps;
  DWORD  dwSSBCKeyCaps;
  DWORD  dwSSBFXCaps;
  DWORD  dwSSBRops[DD_ROP_SPACE];
  DWORD  dwMaxVideoPorts;
  DWORD  dwCurrVideoPorts;
  DWORD  dwSVBCaps2;
} DDCORECAPS, *PDDCORECAPS;

Members

dwSize
Specifies the size in bytes of this DDCORECAPS structure.
dwCaps
Is a flag that specifies the driver's capabilities. The driver should set the appropriate DDCAPS_Xxx bit for every capability that it supports.
Flag | Meaning
DDCAPS_3D | The display hardware has 3D acceleration.
DDCAPS_ALIGNBOUNDARYDEST | DirectDraw supports only those source rectangles with the x-axis aligned to the dwAlignBoundaryDest boundaries of the surface.
DDCAPS_ALIGNBOUNDARYSRC | DirectDraw supports only those source rectangles with the x-axis aligned to the dwAlignBoundarySrc boundaries of the surface.
DDCAPS_ALIGNSIZEDEST | DirectDraw supports only those source rectangles whose x-axis sizes, in bytes, are dwAlignSizeDest multiples.
DDCAPS_ALIGNSIZESRC | DirectDraw supports only those source rectangles whose x-axis sizes, in bytes, are dwAlignSizeSrc multiples.
DDCAPS_ALIGNSTRIDE | DirectDraw creates display memory surfaces that have a stride alignment equal to the dwAlignStrideAlign value.
DDCAPS_ALPHA | The display hardware supports an alpha channel during blit operations.
DDCAPS_BANKSWITCHED | The display hardware is bank-switched and is potentially very slow at random access to display memory. If this capability bit is set by the Windows 2000 or later driver, DirectDraw will be disabled.
DDCAPS_BLT | The display hardware is capable of blit operations.
DDCAPS_BLTCOLORFILL | The display hardware is capable of color filling with a blitter.
DDCAPS_BLTDEPTHFILL | The display hardware is capable of depth filling z-buffers with a blitter.
DDCAPS_BLTFOURCC | The display hardware is capable of color-space conversions during blit operations.
DDCAPS_BLTQUEUE | The display hardware is capable of asynchronous blit operations.
DDCAPS_BLTSTRETCH | The display hardware is capable of stretching during blit operations.
DDCAPS_CANBLTSYSMEM | The display hardware is capable of blitting to or from system memory.
DDCAPS_CANCLIP | The display hardware is capable of clipping with blitting.
DDCAPS_CANCLIPSTRETCHED | The display hardware is capable of clipping while stretch-blitting.
DDCAPS_COLORKEY | Some form of color key in either overlay or blit operations is supported. More specific color key capability information can be found in the dwCKeyCaps member.
DDCAPS_COLORKEYHWASSIST | The color key is hardware assisted.
DDCAPS_GDI | The display hardware is shared with GDI. If this capability bit is set by the Windows 2000 or later driver, DirectDraw will be disabled.
DDCAPS_NOHARDWARE | No hardware support exists.
DDCAPS_OVERLAY | The display hardware supports overlays.
DDCAPS_OVERLAYCANTCLIP | The display hardware supports overlays but cannot clip them.
DDCAPS_OVERLAYFOURCC | The overlay hardware is capable of color-space conversions during overlay operations.
DDCAPS_OVERLAYSTRETCH | The overlay hardware is capable of stretching.
DDCAPS_PALETTE | DirectDraw is capable of creating and supporting DirectDrawPalette objects for more than just the primary surface. If this capability bit is set by the Windows 2000 or later driver, DirectDraw will be disabled.
DDCAPS_PALETTEVSYNC | DirectDraw is capable of updating a palette synchronized with the vertical refresh.
DDCAPS_READSCANLINE | The display hardware is capable of returning the current scan line.
DDCAPS_STEREOVIEW | The display hardware has stereo vision capabilities.
DDCAPS_VBI | The display hardware is capable of generating a vertical-blank interrupt.
DDCAPS_ZBLTS | Supports the use of z-buffers with blit operations.
DDCAPS_ZOVERLAYS | Supports the use of the application's UpdateOverlayZOrder method as a z-value for overlays to control their layering. If this capability bit is set by the Windows 2000 or later driver, DirectDraw will be disabled.

dwCaps2
Specify more of the driver's capabilities. The driver should set the appropriate DDCAPS2_Xxx bit for every capability that it supports.
Flag | Meaning
DDCAPS2_AUTOFLIPOVERLAY | The overlay can be automatically flipped to the next surface in the flip chain each time a hardware video port V-sync occurs, allowing the VPE object and the overlay to double buffer the video without CPU overhead. This option is only valid when the surface is receiving data from hardware video port. If the hardware video port data is noninterlaced or noninterleaved, it flips on every V-sync. If the data is being interleaved in memory, it flips on every other V-sync.
DDCAPS2_CANBOBHARDWARE | The overlay hardware can display each field of an interlaced video stream individually.
DDCAPS2_CANBOBINTERLEAVED | The overlay hardware can display each field of an interlaced video stream individually while it is interleaved in memory without causing any artifacts that might normally occur without special hardware support. This option is only valid when the surface is receiving data from a VPE object and is only valid when the video is zoomed at least 200 percent in the vertical direction.
DDCAPS2_CANBOBNONINTERLEAVED | The overlay hardware can display each field of an interlaced video stream individually while it is not interleaved in memory without causing any artifacts that might normally occur without special hardware support. This option is only valid when the surface is receiving data from a VPE object and is only valid when the video is zoomed at least 200 percent in the vertical direction.
DDCAPS2_CANCALIBRATEGAMMA | A calibrator is available to adjust the gamma ramp according to the physical display properties so that the result will be identical on all calibrated systems.
DDCAPS2_CANDROPZ16BIT | Sixteen-bit RGBZ values can be converted into 16-bit RGB values. (The system does not support eight-bit conversions.)
DDCAPS2_CANFLIPODDEVEN | The driver supports bob using software without using a VPE object.
DDCAPS2_CANMANAGERESOURCE | The driver supports managing resources.
DDCAPS2_CANMANAGETEXTURE | The driver supports managing textures.
DDCAPS2_CANRENDERWINDOWED | The driver can render in windowed mode.
DDCAPS2_CERTIFIED | The display hardware is certified.
DDCAPS2_COLORCONTROLOVERLAY | The overlay surface contains color controls (brightness, sharpness, and so on).
DDCAPS2_COLORCONTROLPRIMARY | The primary surface contains color controls (gamma, and so on).
DDCAPS2_COPYFOURCC | The driver supports blitting any FOURCC surface to another surface of the same FOURCC.
DDCAPS2_FLIPINTERVAL | The driver will respond to the DDFLIP_INTERVAL2, DDFLIP_INTERVAL3, and DDFLIP_INTERVAL4 flags.
DDCAPS2_FLIPNOVSYNC | The driver will respond to DDFLIP_FLIPNOVSYNC.
DDCAPS2_NO2DDURING3DSCENE | The driver cannot interleave 2D operations such as DdBlt or DdLock on any surfaces that Direct3D is using between calls to the IDirect3DDevice::BeginScene and IDirect3DDevice::EndScene methods.
DDCAPS2_NONLOCALVIDMEM | The driver supports nonlocal display memory.
DDCAPS2_NONLOCALVIDMEMCAPS | Blit capabilities for nonlocal display memory surfaces differ from local display memory surfaces. If this flag is present, the DDCAPS2_NONLOCALVIDMEM flag will also be present.
DDCAPS2_NOPAGELOCKREQUIRED | The driver should be called for blits involving system memory surfaces even if the system memory surfaces are not pagelocked.
DDCAPS2_PRIMARYGAMMA | The driver supports loadable gamma ramps for the primary surface.
DDCAPS2_VIDEOPORT | The display hardware contains a hardware video port.
DDCAPS2_WIDESURFACES | The display driver can create surfaces wider than the primary surface. Drivers that set this bit should expect to receive CreateSurface requests from applications for surfaces wider than the primary surface.

dwCKeyCaps
Specify the color key capabilities of surfaces. The driver should set the appropriate DDCKEYCAPS_Xxx bit for every capability that it supports.
Flag | Meaning
DDCKEYCAPS_DESTBLT | Supports transparent blitting with a color key that identifies the replaceable bits of the destination surface for RGB colors.
DDCKEYCAPS_DESTBLTCLRSPACE | Supports transparent blitting with a color space that identifies the replaceable bits of the destination surface for RGB colors.
DDCKEYCAPS_DESTBLTCLRSPACEYUV | Supports transparent blitting with a color space that identifies the replaceable bits of the destination surface for YUV colors.
DDCKEYCAPS_DESTBLTYUV | Supports transparent blitting with a color key that identifies the replaceable bits of the destination surface for YUV colors.
DDCKEYCAPS_DESTOVERLAY | Supports overlaying with color keying of the replaceable bits of the destination surface being overlaid for RGB colors.
DDCKEYCAPS_DESTOVERLAYCLRSPACE | Supports a color space as the color key for the destination of RGB colors.
DDCKEYCAPS_DESTOVERLAYCLRSPACEYUV | Supports a color space as the color key for the destination of YUV colors.
DDCKEYCAPS_DESTOVERLAYONEACTIVE | Supports only one active destination color key value for visible overlay surfaces.
DDCKEYCAPS_DESTOVERLAYYUV | Supports overlaying using color keying of the replaceable bits of the destination surface being overlaid for YUV colors.
DDCKEYCAPS_NOCOSTOVERLAY | Indicates that there are no bandwidth tradeoffs for using the color key with an overlay.
DDCKEYCAPS_SRCBLT | Supports transparent blitting using the color key for the source with this surface for RGB colors.
DDCKEYCAPS_SRCBLTCLRSPACE | Supports transparent blitting using a color space for the source with this surface for RGB colors.
DDCKEYCAPS_SRCBLTCLRSPACEYUV | Supports transparent blitting using a color space for the source with this surface for YUV colors.
DDCKEYCAPS_SRCBLTYUV | Supports transparent blitting using the color key for the source with this surface for YUV colors.
DDCKEYCAPS_SRCOVERLAY | Supports overlaying using the color key for the source with this overlay surface for RGB colors.
DDCKEYCAPS_SRCOVERLAYCLRSPACE | Supports overlaying using a color space as the source color key for the overlay surface for RGB colors.
DDCKEYCAPS_SRCOVERLAYCLRSPACEYUV | Supports overlaying using a color space as the source color key for the overlay surface for YUV colors.
DDCKEYCAPS_SRCOVERLAYONEACTIVE | Supports only one active source color key value for visible overlay surfaces.
DDCKEYCAPS_SRCOVERLAYYUV | Supports overlaying using the color key for the source with this overlay surface for YUV colors.

dwFXCaps
Specify the driver's stretching and effects capabilities. The driver should set the appropriate DDFXCAPS_Xxx bit for every capability that it supports.
Flag | Meaning
DDFXCAPS_BLTARITHSTRETCHY | Uses arithmetic operations, rather than pixel-doubling techniques, to stretch and shrink surfaces during a blit operation. Occurs along the y-axis (vertically).
DDFXCAPS_BLTARITHSTRETCHYN | Uses arithmetic operations, rather than pixel-doubling techniques, to stretch and shrink surfaces during a blit operation. Occurs along the y-axis (vertically), and works only for integer stretching (×1, ×2, and so on).
DDFXCAPS_BLTMIRRORLEFTRIGHT | Supports mirroring left to right in a blit operation.
DDFXCAPS_BLTMIRRORUPDOWN | Supports mirroring top to bottom in a blit operation.
DDFXCAPS_BLTROTATION | Supports arbitrary rotation in a blit operation. If this capability bit is set by the Windows 2000 or later driver, DirectDraw will be disabled.
DDFXCAPS_BLTROTATION90 | Supports 90-degree rotations in a blit operation. If this capability bit is set by the Windows 2000 or later driver, DirectDraw will be disabled.
DDFXCAPS_BLTSHRINKX | Supports arbitrary shrinking of a surface along the x-axis (horizontally). This flag is valid only for blit operations.
DDFXCAPS_BLTSHRINKXN | Supports integer shrinking (×1, ×2, and so on) of a surface along the x-axis (horizontally). This flag is valid only for blit operations.
DDFXCAPS_BLTSHRINKY | Supports arbitrary shrinking of a surface along the y-axis (vertically). This flag is valid only for blit operations.
DDFXCAPS_BLTSHRINKYN | Supports integer shrinking (×1, ×2, and so on) of a surface along the y-axis (vertically). This flag is valid only for blit operations.
DDFXCAPS_BLTSTRETCHX | Supports arbitrary stretching of a surface along the x-axis (horizontally). This flag is valid only for blit operations.
DDFXCAPS_BLTSTRETCHXN | Supports integer stretching (×1, ×2, and so on) of a surface along the x-axis (horizontally). This flag is valid only for blit operations.
DDFXCAPS_BLTSTRETCHY | Supports arbitrary stretching of a surface along the y-axis (vertically). This flag is valid only for blit operations.
DDFXCAPS_BLTSTRETCHYN | Supports integer stretching (×1, ×2, and so on) of a surface along the y-axis (vertically). This flag is valid only for blit operations.
DDFXCAPS_OVERLAYARITHSTRETCHY | Uses arithmetic operations, rather than pixel-doubling techniques, to stretch and shrink surfaces during an overlay operation. Occurs along the y-axis (vertically).
DDFXCAPS_OVERLAYARITHSTRETCHYN | Uses arithmetic operations, rather than pixel-doubling techniques, to stretch and shrink surfaces during an overlay operation. Occurs along the y-axis (vertically), and works only for integer stretching (×1, ×2, and so on).
DDFXCAPS_OVERLAYMIRRORLEFTRIGHT | Supports mirroring of overlays around the vertical axis.
DDFXCAPS_OVERLAYMIRRORUPDOWN | Supports mirroring of overlays across the horizontal axis.
DDFXCAPS_OVERLAYSHRINKX | Supports arbitrary shrinking of a surface along the x-axis (horizontally). This flag is valid only for DDSCAPS_OVERLAY surfaces. This flag indicates only the capabilities of a surface; it does not indicate that shrinking is available.
DDFXCAPS_OVERLAYSHRINKXN | Supports integer shrinking (×1, ×2, and so on) of a surface along the x-axis (horizontally). This flag is valid only for DDSCAPS_OVERLAY surfaces. This flag indicates only the capabilities of a surface; it does not indicate that shrinking is available.
DDFXCAPS_OVERLAYSHRINKY | Supports arbitrary shrinking of a surface along the y-axis (vertically). This flag is valid only for DDSCAPS_OVERLAY surfaces. This flag indicates only the capabilities of a surface; it does not indicate that shrinking is available.
DDFXCAPS_OVERLAYSHRINKYN | Supports integer shrinking (×1, ×2, and so on) of a surface along the y-axis (vertically). This flag is valid only for DDSCAPS_OVERLAY surfaces. This flag indicates only the capabilities of a surface; it does not indicate that shrinking is available.
DDFXCAPS_OVERLAYSTRETCHX | Supports arbitrary stretching of a surface along the x-axis (horizontally). This flag is valid only for DDSCAPS_OVERLAY surfaces. This flag indicates only the capabilities of a surface; it does not indicate that stretching is available.
DDFXCAPS_OVERLAYSTRETCHXN | Supports integer stretching (×1, ×2, and so on) of a surface along the x-axis (horizontally). This flag is valid only for DDSCAPS_OVERLAY surfaces. This flag indicates only the capabilities of a surface; it does not indicate that stretching is available.
DDFXCAPS_OVERLAYSTRETCHY | Supports arbitrary stretching of a surface along the y-axis (vertically). This flag is valid only for DDSCAPS_OVERLAY surfaces. This flag indicates only the capabilities of a surface; it does not indicate that stretching is available.
DDFXCAPS_OVERLAYSTRETCHYN | Supports integer stretching (×1, ×2, and so on) of a surface along the y-axis (vertically). This flag is valid only for DDSCAPS_OVERLAY surfaces. This flag indicates only the capabilities of a surface; it does not indicate that stretching is available.

dwFXAlphaCaps
This member and its flags are obsolete and should not be used by the driver.
dwPalCaps
Specify the driver's palette capabilities. The driver should set the appropriate DDPCAPS_Xxx bit for every capability that it supports. The DDPCAPS_Xxx flags are defined in ddraw.h. The DirectDraw runtime currently ignores these capabilities.
dwSVCaps
Specify the driver's stereo vision capabilities. The driver should set the appropriate DDSVCAPS_Xxx bit for every capability that it supports.
Flag | Meaning
DDSVCAPS_ENIGMA | The stereo view is accomplished using Enigma encoding.
DDSVCAPS_FLICKER | The stereo view is accomplished using high-frequency flickering.
DDSVCAPS_REDBLUE | The stereo view is accomplished when the viewer looks at the image through red and blue filters placed over the left and right eyes. All images must adapt their color spaces for this process.
DDSVCAPS_SPLIT | The stereo view is accomplished with split-screen technology.

dwAlphaBltConstBitDepths,
dwAlphaBltPixelBitDepths,
dwAlphaBltSurfaceBitDepths,
dwAlphaOverlayConstBitDepths,
dwAlphaOverlayPixelBitDepths,
dwAlphaOverlaySurfaceBitDepths,
Are reserved for system use and can be ignored by the driver.
dwZBufferBitDepths
Is a flag that specifies the Z buffer depths supported by the driver. This can be one or more of the following values:
Flag | Meaning
DDBD_8 | The driver supports an 8bpp depth buffer.
DDBD_16 | The driver supports a 16bpp depth buffer.
DDBD_24 | The driver supports a 24bpp depth buffer.
DDBD_32 | The driver supports a 32bpp depth buffer.

dwVidMemTotal
Specifies the total amount of display memory, in bytes.
dwVidMemFree
Specifies the number of bytes of free display memory. The driver sets this member once during initialization to the same value it returns in the dwVidMemTotal member. DirectDraw will update it every time the application does a memory allocation.
dwMaxVisibleOverlays
Specifies the maximum number of visible overlays.
dwCurrVisibleOverlays
Specifies the current number of visible overlays.
dwNumFourCCCodes
Specifies the number of FourCC codes that the driver supports.
dwAlignBoundarySrc
Specifies the source rectangle alignment. This member can be optionally set by the driver. If the driver sets this member, then the overlay source rectangle's top left coordinate value must be a multiple of dwAlignBoundarySrc.
dwAlignSizeSrc
Specifies the size of the source rectangle, in bytes. This member can be optionally set by the driver. If the driver sets this member, then the overlay source rectangle's width must be a multiple of dwAlignSizeSrc.
dwAlignBoundaryDest
Specifies the destination rectangle alignment. This member can be optionally set by the driver. If the driver sets this member, then the overlay destination rectangle's top left coordinate value must be a multiple of dwAlignBoundaryDest.
dwAlignSizeDest
Specifies the destination rectangle byte size. This member can be optionally set by the driver. If the driver sets this member, then the overlay destination rectangle's width must be a multiple of dwAlignSizeDest.
dwAlignStrideAlign
Is reserved for system use and should be ignored by the driver.
dwRops
Specifies an array of DD_ROP_SPACE DWORDs that together can hold flags to indicate the ROPs that the driver supports. The driver should set the bit field for every corresponding ROP that it supports. See the Platform SDK documentation for information about ROPs.
ddsCaps
Specifies a DDSCAPS structure that describes the types of surfaces the driver supports.
dwMinOverlayStretch, dwMaxOverlayStretch
Are the minimum and maximum overlay stretch factors multiplied by 1000. For example, a factor of 1.3 should be stored as 1300.
dwMinLiveVideoStretch, dwMaxLiveVideoStretch
Are the minimum and maximum live video stretch factors multiplied by 1000. For example, a factor of 1.3 should be stored as 1300.
dwMinHwCodecStretch, dwMaxHwCodecStretch
Are the minimum and maximum hardware codec stretch factors multiplied by 1000. For example, a factor of 1.3 should be stored as 1300.
dwReserved1, dwReserved2, dwReserved3
Are reserved for system use. The driver should ignore these members.
dwSVBCaps
Is a set of flags that specify the driver-specific capabilities for system-memory-to-display-memory blits. The driver should bitwise OR the appropriate DDCAPS_Xxx flags to indicate the types of blit operations it supports when blitting from system memory to display memory.
dwSVBCKeyCaps
Is a set of flags that specify driver color-key capabilities for system-memory-to-display-memory blits. The driver should bitwise OR the appropriate DDCKEYCAPS_Xxx flags to indicate the types of color key operations it supports when blitting from system memory to display memory.
dwSVBFXCaps
Is a set of flags that specify driver FX capabilities for system-memory-to-display-memory blits. The driver should bitwise OR the appropriate DDFXCAPS_Xxx flags to indicate the types of effects it supports when blitting from system memory to display memory.
dwSVBRops
Specifies an array of DD_ROP_SPACE DWORDs that together can hold flags to indicate the ROPs that the driver supports when performing system-memory-to-display-memory blits. The driver should set the bit field for every corresponding ROP that it supports. See the Platform SDK documentation for information about ROPs.
dwVSBCaps
Is a set of flags that specify driver-specific capabilities for display-memory-to-system-memory blits. The driver should bitwise OR the appropriate DDCAPS_Xxx flags to indicate the types of blit operations it supports when blitting from display memory to system memory.
dwVSBCKeyCaps
Is a set of flags that specify driver color-key capabilities for display-memory-to-system-memory blits. The driver should bitwise OR the appropriate DDCKEYCAPS_Xxx flags to indicate the types of color key operations it supports when blitting from display memory to system memory.
dwVSBFXCaps
Is a set of flags that specify driver FX capabilities for display-memory-to-system-memory blits. The driver should bitwise OR the appropriate DDFXCAPS_Xxx flags to indicate the types of effects it supports when blitting from display memory to system memory.
dwVSBRops
Specifies an array of DD_ROP_SPACE DWORDs that together can hold flags to indicate the ROPs that the driver supports when performing display-memory-to-system-memory blits. The driver should set the bit field for every corresponding ROP that it supports. See the Platform SDK documentation for information about ROPs.
dwSSBCaps
Is a set of flags that specify driver-specific capabilities for system-memory-to-system-memory blits. The driver should bitwise OR the appropriate DDCAPS_Xxx flags to indicate the types of blit operations it supports when blitting from system memory to system memory.
dwSSBCKeyCaps
Is a set of flags that specify driver color-key capabilities for system-memory-to-system-memory blits. The driver should bitwise OR the appropriate DDCKEYCAPS_Xxx flags to indicate the types of color key operations it supports when blitting from system memory to system memory.
dwSSBFXCaps
Is a set of flags that specify driver FX capabilities for system-memory-to-system-memory blits. The driver should bitwise OR the appropriate DDFXCAPS_Xxx flags to indicate the types of effects it supports when blitting from system memory to system memory.
dwSSBRops
Specifies an array of DD_ROP_SPACE DWORDs that together can hold flags to indicate the ROPs that the driver supports when performing system-memory-to-system-memory blits. The driver should set the bit field for every corresponding ROP that it supports. See the Platform SDK documention for information about ROPs.
dwMaxVideoPorts
Specifies the maximum number of useable VPE objects.
dwCurrVideoPorts
Specifies the current number of VPE objects used. The driver does not need to fill in this member because it is set by DirectDraw.
dwSVBCaps2
Specify additional driver-specific capabilities for system-memory-to-display-memory blits. Valid flags are identical to the blit-related flags used with the dwCaps2 member.

Comments

This section contains the DirectDraw driver structure whose name has the form DDCORECAPS, which is the form used on Windows 98/Me. This structure is identical to that whose name has the form DDNTCORECAPS which is the form used on Windows 2000 and later versions. The include file dx95type.h contains a type define from DDNTCORECAPS to DDCORECAPS.

This structure mirrors the first entries of the DDCAPS structure, but is of a fixed size and does not grow as DDCAPS does.

The driver initializes DDCORECAPS when it is initializing the other members of the DD_HALINFO structure in its DrvGetDirectDrawInfo structure. The DirectDraw runtime might update some members.

DirectDraw requests additional driver capabilities by calling the DdGetDriverInfo function that is also returned in the DD_HALINFO structure.


DDKERNELCAPS

DDKERNELCAPS notifies the client what support, if any, exists in the miniport driver for the kernel-mode video transport.

typedef struct _DDKERNELCAPS {
  DWORD  dwSize;
  DWORD  dwCaps;
  DWORD  dwIRQCaps;
} DDKERNELCAPS, FAR *LPDDKERNELCAPS;

Members

dwSize
Specifies the size, in bytes, of this structure. This member must be initialized before the structure is used.
dwCaps
Is a set of flags indicating the device's capabilities. This member can be any combination of the following capabilities:
Flag | Meaning
DDKERNELCAPS_AUTOFLIP | The driver supports the DxFlipVideoPort and the DxFlipOverlay callbacks, and that these callbacks can be used for autoflipping.
DDKERNELCAPS_CAPTURE_INVERTED | The device supports inverting the DIBs while capturing the data.
DDKERNELCAPS_CAPTURE_NONLOCALVIDMEM | The device supports a VPE capture interface capable of transferring data to nonlocal display memory.
DDKERNELCAPS_CAPTURE_SYSMEM | The device supports a VPE capture interface capable of transferring data to system memory.
DDKERNELCAPS_FIELDPOLARITY | The device can report the polarity (even/odd) of the current VPE object field.
DDKERNELCAPS_FLIPOVERLAY | The driver supports the DxFlipOverlay callback.
DDKERNELCAPS_FLIPVIDEOPORT | The driver supports the DxFlipVideoPort callback.
DDKERNELCAPS_LOCK | The device supports accessing the frame buffer without causing contention with blitters, and so on, and that the driver supports the DxLock callback.
DDKERNELCAPS_SETSTATE | The driver supports the DxSetState callback, allowing a client to switch between bob and weave display modes.
DDKERNELCAPS_SKIPFIELDS | The device supports field skipping, either using hardware or by supporting the DxSkipNextField callback.

dwIRQCaps
Can be a combination of the following flags:
Flag | Meaning
DDIRQ_DISPLAY_VSYNC | The device can generate IRQs based on the display VSYNC.
DDIRQ_VPORT0_LINE | The device can generate IRQs based on a programmable line for hardware video port number 0.
DDIRQ_VPORT0_VSYNC | The device can generate VSYNC IRQs for hardware video port number 0.
DDIRQ_VPORT1_LINE | The device can generate IRQs based on a programmable line for hardware video port number 1.
DDIRQ_VPORT1_VSYNC | The device can generate V-sync IRQs for hardware video port number 1
DDIRQ_VPORT2_LINE | The device can generate IRQs based on a programmable line for hardware video port number 2.
DDIRQ_VPORT2_VSYNC | The device can generate V-sync IRQs for hardware video port number 2.
DDIRQ_VPORT3_LINE | The device can generate IRQs based on a programmable line for hardware video port number 3.
DDIRQ_VPORT3_VSYNC | The device can generate V-sync IRQs for hardware video port number 3.
DDIRQ_VPORT4_LINE | The device can generate IRQs based on a programmable line for hardware video port number 4.
DDIRQ_VPORT4_VSYNC | The device can generate V-sync IRQs for hardware video port number 4.
DDIRQ_VPORT5_LINE | The device can generate IRQs based on a programmable line for hardware video port number 5.
DDIRQ_VPORT5_VSYNC | The device can generate V-sync IRQs for hardware video port number 5.
DDIRQ_VPORT6_LINE | The device can generate IRQs based on a programmable line for hardware video port number 6.
DDIRQ_VPORT6_VSYNC | The device can generate V-sync IRQs for hardware video port number 6.
DDIRQ_VPORT7_LINE | The device can generate IRQs based on a programmable line for hardware video port number 7.
DDIRQ_VPORT7_VSYNC | The device can generate V-sync IRQs for hardware video port number 7.
DDIRQ_VPORT8_LINE | The device can generate IRQs based on a programmable line for hardware video port number 8.
DDIRQ_VPORT8_VSYNC | The device can generate V-sync IRQs for hardware video port number 8.
DDIRQ_VPORT9_LINE | he device can generate IRQs based on a programmable line for hardware video port number 9.
DDIRQ_VPORT9_VSYNC | he device can generate V-sync IRQs for hardware video port number 9.


DDMOCOMPBUFFERINFO

DDMOCOMPBUFFERINFO contains the macro block information required to render a frame and passes this information to the DD_RENDERMOCOMPDATA structure.

typedef struct _DDMOCOMPBUFFERINFO {
  DWORD  dwSize;
  PDD_SURFACE_LOCAL  lpCompSurface;
  DWORD  dwDataOffset;
  DWORD  dwDataSize;
  LPVOID  lpPrivate;
} DDMOCOMPBUFFERINFO, *LPDDMOCOMPBUFFERINFO;

Members

dwSize
Specifies the size in bytes of this DDMOCOMPBUFFERINFO structure.
lpCompSurface
Points to a DD_SURFACE_LOCAL structure that contains the compressed data.
dwDataOffset
Indicates the offset to the relevant data, in bytes, from the beginning of the buffer. This value does not allow for pitch.
dwDataSize
Indicates the size of the relevant data in bytes. This value does not allow for pitch.
lpPrivate
Is used by DirectDraw and should be ignored by the driver.


DDPIXELFORMAT

DDPIXELFORMAT describes the pixel format of a DirectDrawSurface object.

typedef struct _DDPIXELFORMAT {
  DWORD  dwSize;
  DWORD  dwFlags;
  DWORD  dwFourCC;
union
{
  DWORD  dwRGBBitCount;
  DWORD  dwYUVBitCount;
  DWORD  dwZBufferBitDepth;
  DWORD  dwAlphaBitDepth;
  DWORD  dwLuminanceBitCount;
  DWORD  dwBumpBitCount;
  DWORD  dwPrivateFormatBitCount;
} ;
union
{
  DWORD  dwRBitMask;
  DWORD  dwYBitMask;
  DWORD  dwStencilBitDepth;
  DWORD  dwLuminanceBitMask;
  DWORD  dwBumpDuBitMask;
  DWORD  dwOperations;
} ;
union
{
  DWORD  dwGBitMask;
  DWORD  dwUBitMask;
  DWORD  dwZBitMask;
  DWORD  dwBumpDvBitMask;
  struct
  {
    WORD wFlipMSTypes;
    WORD wBltMSTypes;
  } MultiSampleCaps;
} ;
union
{
  DWORD  dwBBitMask;
  DWORD  dwVBitMask;
  DWORD  dwStencilBitMask;
  DWORD  dwBumpLuminanceBitMask;
} ;
union
{
  DWORD  dwRGBAlphaBitMask;
  DWORD  dwYUVAlphaBitMask;
  DWORD  dwLuminanceAlphaBitMask;
  DWORD  dwRGBZBitMask;
  DWORD  dwYUVZBitMask;
} ;
} DDPIXELFORMAT, FAR* LPDDPIXELFORMAT;

Members

dwSize
Specifies the size in bytes of the DDPIXELFORMAT structure. This member must be initialized before the structure is used.
dwFlags
Is a set of flags that specify optional control flags. This member is a bitwise-OR of any of the following values:
Flag | Meaning
DDPF_ALPHA | The pixel format describes an alpha-only surface.
DDPF_ALPHAPIXELS | The surface has alpha channel information in the pixel format.
DDPF_ALPHAPREMULT | The color components in the pixel are premultiplied by the alpha value in the pixel. If this flag is set, the DDPF_ALPHAPIXELS flag must also be set. If this flag is not set but the DDPF_ALPHAPIXELS flag is set, the color components in the pixel format are not premultiplied by alpha. In this case, the color components must be multiplied by the alpha value at the time that an alpha-blending operation is performed.
DDPF_BUMPDUDV | Bump map dUdV data in the pixel format is valid.
DDPF_BUMPHEIGHT | Bump map height data in the pixel format is valid.
DDPF_COMPRESSED | The surface accepts pixel data in the specified format and compresses it during the write operation.
DDPF_FOURCC | The FourCC code is valid.
DDPF_LUMINANCE | Luminance data in the pixel format is valid. Use this flag for luminance-only or luminance-plus-alpha surfaces; the bit depth is then specified in the dwLuminanceBitCount member.
DDPF_LUMINANCEPIXELS | Luminance data in the pixel format is valid. Use this flag when hanging luminance off, for example, bumpmap surfaces. The bit mask for the luminance portion of the pixel is then specified in the dwBumpLuminanceBitMask member.
DDPF_PALETTEINDEXED1 | The surface is 1-bit color indexed.
DDPF_PALETTEINDEXED2 | The surface is 2-bit color indexed.
DDPF_PALETTEINDEXED4 | The surface is 4-bit color indexed.
DDPF_PALETTEINDEXED8 | The surface is 8-bit color indexed.
DDPF_PALETTEINDEXEDTO8 | The surface is 1-, 2-, or 4-bit color indexed to an 8-bit palette.
DDPF_RGB | The RGB data in the pixel format structure is valid.
DDPF_RGBTOYUV | The surface accepts RGB data and translates it during the write operation to YUV data. The format of the data to be written is contained in the pixel format structure. The DDPF_RGB flag is set.
DDPF_STENCILPIXELS | The surface encodes stencil and depth information in each pixel of the z-buffer.
DDPF_YUV | The YUV data in the pixel format structure is valid.
DDPF_ZBUFFER | The pixel format describes a z-buffer-only surface.
DDPF_ZPIXELS | The surface is in RGBZ format.

dwFourCC
Specifies the FourCC code.
dwRGBBitCount
Specifies the number of RGB bits per pixel (4, 8, 16, 24, or 32).
dwYUVBitCount
Specifies the number of YUV bits per pixel.
dwZBufferBitDepth
Specifies the Z-buffer bit depth (8, 16, 24, or 32 bits).
dwAlphaBitDepth
Specifies the Alpha channel bit depth.
dwLuminanceBitCount
Specifies the number of bits per pixel.
dwBumpBitCount
Specifies the total number of bits per "bumpel" (bump-map texel).
dwPrivateFormatBitCount
Specifies the bits per pixel of a pixel format private to the driver (that is, not one of the standard ones defined by Direct3D).
dwRBitMask
Specifies the mask for red bits.
dwYBitMask
Specifies the mask for Y bits.
dwStencilBitDepth
Specifies the bit depth of the stencil buffer. This member specifies how many bits are reserved within each pixel of the z-buffer for stencil information.
dwLuminanceBitMask
Specifies the mask for luminance bits.
dwBumpDuBitMask
Specifies the mask for bump map U delta bits.
dwOperations
Specifies the intended operations that can be performed on surfaces with this pixel format, for example, whether they can be used as textures, cube maps, volume textures, or render targets. The operations that can be reported are as follows:
Operation | Meaning
D3DFORMAT_OP_TEXTURE | When this flag is specified in a pixel format it indicates that surfaces of this format can be used as MIP mapped textures.
D3DFORMAT_OP_VOLUMETEXTURE | When this flag is specified in a pixel format it indicates that surfaces of this format can be used as volume textures. Please note, that this flag is independent of D3DFORMAT_OP_TEXTURE. Thus, it is possible to specify a pixel format that can only be used for volume textures and not for conventional, MIP mapped textures.
D3DFORMAT_OP_CUBETEXTURE | When this flag is specified in a pixel format it indicates that surfaces of this format can be used as cubic environment map textures. Please note, that this flag is independent of D3DFORMAT_OP_TEXTURE. Thus, it is possible to specify a pixel format that can only be used for cubic environment map textures and not for conventional, MIP mapped textures.
D3DFORMAT_OP_OFFSCREEN_RENDERTARGET | When this flag is specified in a pixel format it indicates that surfaces of this format can be used as an offscreen render target regardless of the pixel format of the display mode (providing the pixel format of the current display mode was reported with the D3DFORMAT_OP_DISPLAYMODE and D3DFORMAT_OP_3DACCELERATION). If the pixel format of the current display mode did not have these flags set it indicates no 3D acceleration is available in this mode even if the render target is offscreen. This flag can be combined with D3DFORMAT_OP_TEXTURE to indicate that the device can render to textures of the specified pixel format.
D3DFORMAT_OP_SAME_FORMAT_RENDERTARGET | When this flag is specified in a pixel format it indicates that surfaces of this format can be used as render targets but only when the pixel format of the surface matches the pixel format of the current display mode. This flag does not only apply to offscreen render target but can be specified on the pixel formats of display modes to indicate rendering target capability. This flag can be combined with D3DFORMAT_OP_TEXTURE to indicate that the device can render to textures of the specified pixel format.
D3DFORMAT_OP_ZSTENCIL | When this flag is specified in a pixel format it indicates that surfaces of this format can be used as Z/Stencil buffers but only if the depth of the Z/Stencil surface matches the color depth of the rendering target to which the depth buffer is attached. When deciding on a match between Z/Stencil and color buffer depth, the pixel stride is used.
D3DFORMAT_OP_ZSTENCIL_WITH_ARBITRARY_COLOR_DEPTH | When this flag is specified in a pixel format it indicates that surfaces of this format can be used as Z/Stencil buffers regardless of the color depth of the render target to which the surface is attached. When specifying this flag you also should specify D3DFORMAT_OP_ZSTENCIL.
D3DFORMAT_OP_SAME_FORMAT_UP_TO_ALPHA_RENDERTARGET | When this flag is specified in a pixel format it indicates that surfaces of this format can be used as a render target if the current display mode is the same depth, if the alpha channel is ignored. For example, if the device can render to A8R8G8B8 when the display mode is X8R8G8B8, then the format operation list entry for A8R8G8B8 should have this flag set.
D3DFORMAT_OP_DISPLAYMODE | When this flag is specified it indicates that there is a display mode with this pixel format that has DirectDraw support (including Flip). This flag should not to be set on alpha formats.
D3DFORMAT_OP_3DACCELERATION | When this flag is specified the graphics accelerator can support some level of Direct3D acceleration when in a display mode with this pixel format and also implies that the driver can create a context in this mode (for some render target format). This flag must only be used when reporting display mode formats (by specifying the D3DFORMAT_OP_DISPLAYMODE). It is not required and indeed should not be set when reporting offscreen render targets formats.

dwGBitMask
Specifies the mask for green bits.
dwUBitMask
Specifies the mask for U bits.
dwZBitMask
Specifies the mask for Z bits.
dwBumpDvBitMask
Specifies the mask for bump map V delta bits.
wFlipMSTypes, wBltMSTypes
Used when specifying surfaces that can be used when performing multi-sample rendering (see Comments).
dwBBitMask
Specifies the mask for blue bits.
dwVBitMask
Specifies the mask for V bits.
dwStencilBitMask
Specifies the mask for stencil bits within each z-buffer pixel.
dwBumpLuminanceBitMask
Specifies the mask for luminance in a bump map.
dwRGBAlphaBitMask, dwYUVAlphaBitMask
Specify the masks for alpha channel.
dwLuminanceAlphaBitMask
Specifies the mask for luminance in the alpha channel.
dwRGBZBitMask, dwYUVZBitMask
Specify the masks for the z channel.

Comments

The runtime now imposes some rules on the op list. The current rules are:

  • Only one Endian-ness (big or little) for any DS format is allowed, for example D15S1 or S1D15, not both independent of other bits.
  • A list should only include D3DFORMAT_OP_DISPLAYMODE for exactly one 16bpp format (for example it should not enumerate 5:5:5 and 5:6:5).
  • A list should not contain any alpha formats with D3DFORMAT_OP_DISPLAYMODE or D3DFORMAT_OP_3DACCELLERATION set.
  • Make sure no mode has D3DFORMAT_OP_3DACCELLERATION set that does not also have D3DFORMAT_OP_DISPLAYMODE set.

If the driver supports a lockable D16, it should report D3DFMT_D16_LOCKABLE in the op list; otherwise, it should report D3DFMT_D16.

Drivers supporting multisampling must fill in the MultiSampleCaps in the Depth/Stencil formats for which multisampling can be supported. This allows the runtime to detect if a driver supports multisampling for combinations of render target and Z buffer formats. For additional information about the restrictions related to stretch blt multi-sampling, see the description of D3DPRASTERCAPS_STRETCHBLTMULTISAMPLE cap in the rastercaps contained in the D3DCAPS8 structure in the SDK documentation.

The enumerated type D3DMULTISAMPLE_TYPE defined in d3d8types.h is used when setting the bits in wFlipMSTypes and wBltMSTypes. To specify support for a specific number of samples per pixel, simply logically shift 1 by the appropriate value from the D3DMULTISAMPLE_TYPE enumerated type less 1 and OR this into the appropriate field (wFlipMSTypes and wBltMSTypes).

For example, if the driver supports both two and four samples for pixel when flipping (fullscreen mode) and four samples per pixel when blitting (windowed mode) on X8R8G8B8 surface the following entry would be reported in the surface format list.

DDPIXELFORMAT ddpf;
ZeroMemory(&ddpf, sizeof(ddpf));
ddpf.dwSize       = sizeof(DDPIXELFORMAT);
ddpf.dwFlags      = DDPF_D3DFORMAT;
ddpf.dwFourCC     = D3DFMT_X8R8G8B8;
ddpf.dwOperations = D3DFORMAT_OP_DISPLAYMODE |
                    D3DFORMAT_OP_3DACCELERATION;
ddpf.MultiSampleCaps.wFlipMSTypes = (1 << (D3DMULTISAMPLE_4_SAMPLES – 1))
                                  | (1 << (D3DMULTISAMPLE_2_SAMPLES – 1));
ddpf.MultiSampleCaps.wBltMSTypes = (1 << (D3DMULTISAMPLE_4_SAMPLES – 1));

It is not necessary to specify 1 << (D3DMULTISAMPLE_NONE - 1) when reporting formats. It is assumed that any format reported can also be used without multi-sampling. If the hardware supports multi-sample rendering with a z-buffer the z-buffer formats reported should also include the supported samples-per-pixels.


DDSCAPS

DDSCAPS defines the capabilities of a DirectDraw surface object.

typedef struct _DDSCAPS {
  DWORD  dwCaps;
} DDSCAPS, FAR* LPDDSCAPS;

Members

dwCaps
Is a set of flags that specify the capabilities of the surface. This member is a bitwise OR of any of the following flags:
Flag | Meaning
DDSCAPS_3DDEVICE | This surface can be used for 3D rendering. Applications can use this flag to ensure that a device that can only render to a certain heap has offscreen surfaces allocated from the correct heap. If this flag is set for a heap, the surface is not allocated from that heap.
DDSCAPS_ALLOCONLOAD | Memory for the surface is not allocated until the surface is loaded by the application using the IDirect3DTexture::Load method.
DDSCAPS_ALPHA | This surface contains alpha information only.
DDSCAPS_BACKBUFFER | This surface is the back buffer of a surface flipping structure. Typically, this capability is set by the application's CreateSurface method when the DDSCAPS_FLIP flag is used. Only the surface that immediately precedes the DDSCAPS_FRONTBUFFER surface has this capability set. The other surfaces are identified as back buffers by the presence of the DDSCAPS_FLIP flag, their attachment order, and the absence of the DDSCAPS_FRONTBUFFER and DDSCAPS_BACKBUFFER capabilities. If this capability is sent to the application's CreateSurface method, a stand-alone back buffer is being created. After this method is called, this surface could be attached to a front buffer, another back buffer, or both to form a flipping surface structure. For more information, see the AddAttachedSurface method in the DirectX SDK. DirectDraw supports an arbitrary number of surfaces in a flipping structure.
DDSCAPS_COMPLEX | A complex surface is being described. A complex surface results in the creation of more than one surface. The additional surfaces are attached to the root surface. The complex structure can be destroyed only by destroying the root.
DDSCAPS_FLIP | This surface is a part of a surface flipping structure. When this capability is passed to the application's CreateSurface method, a front buffer and one or more back buffers are created. DirectDraw sets the DDSCAPS_FRONTBUFFER bit on the front-buffer surface and the DDSCAPS_BACKBUFFER bit on the surface adjacent to the front-buffer surface. The dwBackBufferCount member of the DDSURFACEDESC structure must be set to at least 1 in order for the method call to succeed. The DDSCAPS_COMPLEX capability must always be set when creating multiple surfaces by using the CreateSurface method.
DDSCAPS_FRONTBUFFER | This surface is the front buffer of a surface flipping structure. This flag is typically set by the application's CreateSurface method when the DDSCAPS_FLIP capability is set. If this capability is sent to the CreateSurface method, a stand-alone front buffer is created. This surface will not have the DDSCAPS_FLIP capability. It can be attached to other back buffers to form a flipping structure by using the application's AddAttachedSurface method.
DDSCAPS_HWCODEC | This surface should be able to have a stream decompressed to it by the hardware.
DDSCAPS_LIVEVIDEO | This surface should be able to receive live video.
DDSCAPS_LOCALVIDMEM | This surface exists in true, local display memory rather than nonlocal display memory. If this flag is specified, then DDSCAPS_VIDEOMEMORY must be specified as well. This flag cannot be used with the DDSCAPS_NONLOCALVIDMEM flag.
DDSCAPS_MIPMAP | This surface is one level of a mipmap. This surface is attached to other DDSCAPS_MIPMAP surfaces to form the mipmap. This can be done explicitly by creating a number of surfaces and attaching them by using the application's AddAttachedSurface method, or implicitly by the application's CreateSurface method. If this capability is set, DDSCAPS_TEXTURE must also be set.
DDSCAPS_MODEX | This surface is a 320×200 or 320×240 Mode X surface. If this capability bit is set by the Windows 2000 or later driver, DirectDraw will be disabled.
DDSCAPS_NONLOCALVIDMEM | This surface exists in nonlocal display memory rather than true, local display memory. If this flag is specified, then DDSCAPS_VIDEOMEMORY flag must be specified as well. This cannot be used with the DDSCAPS_LOCALVIDMEM flag.
DDSCAPS_OFFSCREENPLAIN | This surface is any offscreen surface that is not an overlay, texture, z-buffer, front-buffer, back-buffer, or alpha surface. It is used to identify plain surfaces.
DDSCAPS_OVERLAY | This surface is an overlay. The visibility of this overlay depends on whether it is currently being overlaid onto the primary surface. DDSCAPS_VISIBLE can be used to determine whether it is being overlaid at the moment.
DDSCAPS_OPTIMIZED | This flag is not currently implemented.
DDSCAPS_OWNDC | This surface will have a device context (DC) association for a long period. If this capability bit is set by the Windows 2000 or later driver, DirectDraw will be disabled.
DDSCAPS_PALETTE | This device driver allows unique DirectDrawPalette objects to be created and attached to this surface.
DDSCAPS_PRIMARYSURFACE | This surface is the primary surface. It represents what is visible to the user at the moment.
DDSCAPS_PRIMARYSURFACELEFT | This surface is the primary surface for the left eye. It represents what is visible to the user's left eye at the moment. When this surface is created, the surface with the DDSCAPS_PRIMARYSURFACE capability represents what is seen by the user's right eye.
DDSCAPS_STANDARDVGAMODE | This surface is a standard VGA mode surface, and not a ModeX surface. This flag cannot be used in combination with the DDSCAPS_MODEX flag.
DDSCAPS_SYSTEMMEMORY | This surface memory was allocated from system memory. If this capability bit is set by the Windows 2000 or later driver, DirectDraw will be disabled.
DDSCAPS_TEXTURE | This surface can be used as a 3D texture. It does not indicate whether the surface is being used for that purpose.
DDSCAPS_VIDEOMEMORY | This surface exists in display memory.
DDSCAPS_VIDEOPORT | This surface can receive data from a VPE object.
DDSCAPS_VISIBLE | Changes made to this surface are immediately visible. It is always set for the primary surface, as well as for overlays while they are being overlaid and texture maps while they are being textured.
DDSCAPS_WRITEONLY | Only write access is permitted to the surface. Read access from the surface may generate a general protection fault (GPF), but the read results from this surface are not meaningful. If this capability bit is set by the Windows 2000 or later driver, DirectDraw will be disabled.
DDSCAPS_ZBUFFER | This surface is the z-buffer. It contains bit-depth information that is used to determine which pixels are visible and which are obscured. The z-buffer contains information that cannot be displayed.

Comments

This structure is used by the driver to report the types of surfaces the driver supports. It is also filled in by an application to specify the type of surface to be created.


DDSCAPS2

DDSCAPS2 defines additional capabilities of a DirectDraw surface object.

typedef struct _DDSCAPS2 {
  DWORD  dwCaps;
  DWORD  dwCaps2;
  DWORD  dwCaps3;
  DWORD  dwCaps4;
} DDSCAPS2, FAR* LPDDSCAPS2;

Members

dwCaps
Is a set of flags representing the capabilities of the surface. The flags in this member are identical to those in the corresponding member of the DDSCAPS structure.
dwCaps2
Is a set of flags that indicate additional surface capabilities. This member can contain one or more of the following capability flags. Each of these flags, except DDSCAPS2_TEXTUREMANAGE, are set by the application when the application calls its CreateSurface method.
Flag | Meaning
DDSCAPS2_COMMANDBUFFER | Marks a command buffer, used by Direct3D to batch commands.
DDSCAPS2_CUBEMAP | This surface is a cubic environment map. When using this flag, also specify the face or faces of the cubic environment map to create.
DDSCAPS2_CUBEMAP_POSITIVEX | This flag is used with the DDSCAPS2_CUBEMAP flag to create the positive X face of a cubic environment map.
DDSCAPS2_CUBEMAP_NEGATIVEX | This flag is used with the DDSCAPS2_CUBEMAP flag to create the negative X face of a cubic environment map.
DDSCAPS2_CUBEMAP_POSITIVEY | This flag is used with the DDSCAPS2_CUBEMAP flag to create the positive Y face of a cubic environment map.
DDSCAPS2_CUBEMAP_NEGATIVEY | This flag is used with the DDSCAPS2_CUBEMAP flag to create the negative Y face of a cubic environment map.
DDSCAPS2_CUBEMAP_POSITIVEZ | This flag is used with the DDSCAPS2_CUBEMAP flag to create the positive Z face of a cubic environment map.
DDSCAPS2_CUBEMAP_NEGATIVEZ | This flag is used with the DDSCAPS2_CUBEMAP flag to create the negative Z face of a cubic environment map.
DDSCAPS2_CUBEMAP_ALLFACES | This flag is used with the DDSCAPS2_CUBEMAP flag to create all six faces of a cubic environment map.
DDSCAPS2_D3DTEXTUREMANAGE | The texture is always managed by Direct3D.
DDSCAPS2_DISCARDBACKBUFFER DirectX 8.0 and later versions only.

Indicates that preservation of the back buffer is not required. It will be set on the primary surface and the back buffers if the application has set D3DSWAPEFFECT_DISCARD on the Present API.
DDSCAPS2_DONOTPERSIST | The managed surface can be safely lost.
DDSCAPS2_ENABLEALPHACHANNEL DirectX 8.1 and later versions only.

Indicates to create surfaces that are part of a primary flipping chain or that are on stand-alone back buffers. This flag turns on the alpha channel. See Enabling Alpha Channels On Full-screen Back Buffers for more information.
DDSCAPS2_HARDWAREDEINTERLACE | The driver must convert the interlaced signal to progressive frames. The DDSCAPS_VIDEOPORT and DDSCAPS_OVERLAY flags in this structure must also be set.
DDSCAPS2_HINTANTIALIASING | The application will use antialiasing. This flag is valid only if the DDSCAPS_3DDEVICE flag is also set.
DDSCAPS2_HINTDYNAMIC | The application will be updating the surface frequently. Surfaces with this flag set must also have the DDSCAPS_TEXTURE flag in this structure set. This flag cannot be used with the DDSCAPS2_HINTSTATIC or DDSCAPS2_OPAQUE flags.
DDSCAPS2_HINTSTATIC | The application will be updating the surface infrequently, but still requires access. Surfaces with this flag set must also have the DDSCAPS_TEXTURE flag in this structure set. This flag cannot be used with the DDSCAPS2_HINTDYNAMIC or DDSCAPS2_OPAQUE flags.
DDSCAPS2_INDEXBUFFER DirectX 8.0 and later versions only.

Marks an index buffer, created and controlled by the application.
DDSCAPS2_MIPMAPSUBLEVEL | It enables easier use of GetAttachedSurface, rather than EnumAttachedSurfaces, for surface constructs such as cube maps, in which there is more than one mipmap surface attached to the root surface. This should be set on all non-top-level surfaces in a mipmapped cube map so that a call to GetAttachedSurface can distinguish between top-level faces and attached mipmap levels. This capability bit is ignored by CreateSurface.
DDSCAPS2_NOTUSERLOCKABLE DirectX 8.0 and later versions only.

Set on the primary and the back buffers if the flipping chain is not lockable, or on any render target that is not lockable. This allows drivers to do behind the scenes optimization. Note that it is still possible to lock the surfaces so the driver will need to handle these cases, but such locks will be very infrequent and are not expected to be fast.
The driver can also determine whether the depth/stencil buffer is lockable by the presence of this flag.

DDSCAPS2_NPATCHES DirectX 8.0 and later versions only.

Indicates that the vertex buffer data can be used to render n-patches.
DDSCAPS2_OPAQUE | The application will never lock, blit, or update the surface for the rest of that surface's lifetime. The driver can compress or reorder the surface without ever having to decompress it. Surfaces with this flag set must also have the DDSCAPS_TEXTURE flag in this structure set. This flag cannot be used with the DDSCAPS2_HINTDYNAMIC or DDSCAPS2_HINTSTATIC flags.
DDSCAPS2_POINTS DirectX 8.0 and later versions only.

Indicates that the vertex buffer data can be used to render points and point sprites.
DDSCAPS2_RTPATCHES DirectX 8.0 and later versions only.

Indicates that the vertex buffer data can be used to render rt-patches.
DDSCAPS2_STEREOSURFACELEFT This surface is part of a stereo flipping chain. When this flag is set during a CreateSurface call, a pair of stereo surfaces are created for each buffer in the primary flipping chain. You must create a complex flipping chain (with back buffers). You cannot create a single set of stereo surfaces. The Flip method requires back buffers, so at least 4 surfaces must be created.

In addition, when this flag is set in a DDSURFACEDESC structure as the result of an EnumDisplayModes or GetDisplayMode call, it indicates support for stereo in that mode.
DDSCAPS2_TEXTUREMANAGE | The client indicates that this texture surface should be managed by the driver if possible; otherwise it is managed by Direct3D Immediate Mode. This flag can be used only for texture surfaces (DDSCAPS_TEXTURE flag set in the dwCaps member). For more information, see Automatic Texture Management in the Direct3D Immediate Mode documentation.
DDSCAPS2_VERTEXBUFFER | Marks an explicit vertex buffer, created and controlled by the application.
DDSCAPS2_VOLUME DirectX 8.0 and later versions only.

This flag will be set if the texture has depth in addition to width and height.

dwCaps3
Is the number of samples for a multi-sampled surface. This field holds one of the values of the enumerated type D3DMULTISAMPLE_TYPE. If a surface is not multi-sampled, dwCaps3 will have the value D3DMULTISAMPLE_NONE (0).
dwCaps4
The low word is the depth for a volume texture.

Comments

This structure is used by the driver to report the types of surfaces the driver supports. It is also filled in by an application to specify the type of surface to be created.


DDSURFACEDATA

DDSURFACEDATA is used by DirectDraw to represent a surface to the kernel-mode miniport driver.

typedef struct _DDSURFACEDATA {
  DWORD  ddsCaps;
  DWORD  dwSurfaceOffset;
  ULONG_PTR  fpLockPtr;
  DWORD  dwWidth;
  DWORD  dwHeight;
  LONG   lPitch;
  DWORD  dwOverlayFlags;
  DWORD  dwOverlayOffset;
  DWORD  dwOverlaySrcWidth;
  DWORD  dwOverlaySrcHeight;
  DWORD  dwOverlayDestWidth;
  DWORD  dwOverlayDestHeight;
  DWORD  dwVideoPortId;
  DWORD  dwFormatFlags;
  DWORD  dwFormatFourCC;
  DWORD  dwFormatBitCount;
  DWORD  dwRBitMask;
  DWORD  dwGBitMask;
  DWORD  dwBBitMask;
  ULONG  dwDriverReserved1;
  ULONG  dwDriverReserved2;
  ULONG  dwDriverReserved3;
  ULONG  dwDriverReserved4;
} DDSURFACEDATA, *LPDDSURFACEDATA;

Members

ddsCaps
Points to a DDSCAPS structure that contains the creation capabilities used to describe the surface.
dwSurfaceOffset
Specifies the byte offset from the beginning of the frame buffer to the start of the surface. This field is used only by the miniport driver.
fpLockPtr
Points to the start of the surface.
dwWidth
Specifies the surface width, in pixels.
dwHeight
Specifies the surface height, in pixels.
lPitch
Specifies the surface pitch.
dwOverlayFlags
Is a set of flags that specify the current user-mode DDOVER_Xxx flags set by DdUpdateOverlay.
Flag | Meaning
DDOVER_ADDDIRTYRECT | Add a dirty rectangle to an emulated overlaid surface.
DDOVER_ALPHADEST | Use either the alpha information in pixel format or the alpha channel surface attached to the destination surface as the alpha channel for this overlay.
DDOVER_ALPHADESTCONSTOVERRIDE | Use the dwAlphaDestConst member of the DDOVERLAYFX structure as the destination alpha channel for this overlay. The DDOVERLAYFX structure is defined in ddraw.h.
DDOVER_ALPHADESTNEG | The destination surface becomes more transparent as the alpha value increases (0 is opaque).
DDOVER_ALPHADESTSURFACEOVERRIDE | Use the lpDDSAlphaDest member of the DDOVERLAYFX structure (defined in the DirectDraw SDK documentation) as the alpha channel destination for this overlay.
DDOVER_ALPHAEDGEBLEND | Use the dwAlphaEdgeBlend member of the DDOVERLAYFX structure (defined in the DirectDraw SDK documentation) as the alpha channel for the edges of the image that border the color key colors.
DDOVER_ALPHASRC | Use either the alpha information in pixel format or the alpha channel surface attached to the source surface as the source alpha channel for this overlay.
DDOVER_ALPHASRCCONSTOVERRIDE | Use the dwAlphaSrcConst member of the DDOVERLAYFX structure (defined in the DirectDraw SDK documentation) as the source alpha channel for this overlay.
DDOVER_ALPHASRCNEG | The source surface becomes more transparent as the alpha value increases (0 is opaque).
DDOVER_ALPHASRCSURFACEOVERRIDE | Use the lpDDSAlphaSrc member of the DDOVERLAYFX structure (defined in the DirectDraw SDK documentation) as the alpha channel source for this overlay.
DDOVER_AUTOFLIP | Automatically flip to the next surface in the flip chain each time a hardware video port VSYNC occurs.
DDOVER_BOB | Display each field of the interlaced video stream individually without causing any artifacts.
DDOVER_BOBHARDWARE | Bob is performed using hardware rather than software or being emulated.
DDOVER_DDFX | Use the overlay FX flags to define special overlay effects.
DDOVER_HIDE | Turn this overlay off.
DDOVER_INTERLEAVED | The surface memory is composed of interleaved fields.
DDOVER_KEYDEST | Use the color key associated with the destination surface.
DDOVER_KEYDESTOVERRIDE | Use the dckDestColorkey member of the DDOVERLAYFX structure (defined in the DirectDraw SDK documentation) as the color key for the destination surface.
DDOVER_KEYSRC | Use the color key associated with the source surface.
DDOVER_KEYSRCOVERRIDE | Use the dckSrcColorkey member of the DDOVERLAYFX structure (defined in the DirectDraw SDK documentation) as the color key for the source surface.
DDOVER_OVERRIDEBOBWEAVE | Bob and weave decisions should not be overridden by other interfaces. If this flag is set, DirectDraw will not allow a kernel-mode driver to use the kernel-mode video transport functionality to switch the hardware between bob and weave mode.
DDOVER_REFRESHALL | Redraw the entire surface on an emulated overlaid surface.
DDOVER_REFRESHDIRTYRECTS | Redraw all dirty rectangles on an emulated overlaid surface.
DDOVER_SHOW | Turn this overlay on.

dwOverlayOffset
Specifies the byte offset from the beginning of the frame buffer to the start of the overlay. This field is used only by the miniport driver.
dwOverlaySrcWidth
Specifies the overlay source width. This field is used only by the miniport driver.
dwOverlaySrcHeight
Specifies the overlay source height. This field is used only by the miniport driver.
dwOverlayDestWidth
Specifies the overlay destination width. This field is used only by the miniport driver.
dwOverlayDestHeight
Specifies the overlay destination height. This field is used only by the miniport driver.
dwVideoPortId
If this surface is being fed by a VPE object, this field indicates the ID of the VPE object, an integer in the range (0 - (maximum number of hardware video ports -1 )); otherwise, this field is -1.
dwFormatFlags
Is a set of pixel-format control flags.
Flag | Meaning
DDPF_ALPHA | The pixel format describes an alpha-only surface.
DDPF_ALPHAPIXELS | The surface has alpha channel information in the pixel format.
DDPF_ALPHAPREMULT | The color components in the pixel are premultiplied by the alpha value in the pixel. If this flag is set, the DDPF_ALPHAPIXELS flag must also be set. If this flag is not set but the DDPF_ALPHAPIXELS flag is set, the color components in the pixel format are not premultiplied by alpha. In this case, the color components must be multiplied by the alpha value at the time that an alpha-blending operation is performed.
DDPF_BUMPDUDV | The bump map dUdV data in the pixel format is valid.
DDPF_BUMPLUMINANCE | The luminance data in pixel format is valid. This flag is used when hanging luminance off bumpmap surfaces. The bit mask for the luminance portion of the pixel is then indicated by the dwBumpLuminanceBitCount member of the DDPIXELFORMAT structure.
DDPF_COMPRESSED | The surface will accept pixel data in the specified format and compress it during the write operation.
DDPF_FOURCC | The FourCC code is valid.
DDPF_LUMINANCE | The luminance data in the pixel format is valid. This flag is used for luminance only or luminance plus alpha surfaces; the bit depth is then indicated by the dwLuminanceBitCount member of the DDPIXELFORMAT structure.
DDPF_PALETTEINDEXED1 | The surface is 1--bit color indexed.
DDPF_PALETTEINDEXED2 | The surface is 2--bit color indexed.
DDPF_PALETTEINDEXED4 | The surface is 4--bit color indexed.
DDPF_PALETTEINDEXED8 | The surface is 8-bit color indexed.
DDPF_PALETTEINDEXEDTO8 | The surface is 1-, 2-, or 4-bit color indexed to an 8-bit palette.
DDPF_RGB | The RGB data in the pixel format structure is valid.
DDPF_RGBTOYUV | The surface will accept RGB data and translate it during the write operation to YUV data. The format of the data to be written will be contained in the pixel format structure. The DDPF_RGB flag will be set.
DDPF_STENCILBUFFER | The surface contains stencil information along with Z information.
DDPF_YUV | The YUV data in the pixel format structure is valid.
DDPF_ZBUFFER | The pixel format describes a z-buffer-only surface.
DDPF_ZPIXELS | The surface is in RGBZ format.

dwFormatFourCC
Specifies the FourCC code.
dwFormatBitCount
Specifies the number of bits per pixel (4, 8, 16, 24, or 32).
dwRBitMask
Specifies the red bit mask.
dwGBitMask
Specifies the green bit mask.
dwBBitMask
Specifies the blue bit mask.
dwDriverReserved1, dwDriverReserved2, dwDriverReserved3, dwDriverReserved4
Are reserved for use by the miniport driver.


DDSURFACEDESC

DDSURFACEDESC contains a description of a surface to be created by the driver.

typedef struct _DDSURFACEDESC {
  DWORD  dwSize;
  DWORD  dwFlags;
  DWORD  dwHeight;
  DWORD  dwWidth;
  union
  {
  LONG  lPitch;
  DWORD  dwLinearSize;
  };
  DWORD  dwBackBufferCount;
  union
  {
  DWORD  dwMipMapCount;
  DWORD  dwZBufferBitDepth;
  DWORD  dwRefreshRate;
  };
  DWORD  dwAlphaBitDepth;
  DWORD  dwReserved;
  LPVOID  lpSurface;
  DDCOLORKEY  ddckCKDestOverlay;
  DDCOLORKEY  ddckCKDestBlt;
  DDCOLORKEY  ddckCKSrcOverlay;
  DDCOLORKEY  ddckCKSrcBlt;
  DDPIXELFORMAT  ddpfPixelFormat;
  DDSCAPS  ddsCaps;
} DDSURFACEDESC;

Members

dwSize
Specifies the size in bytes of this DDSURFACEDESC structure. This member must be initialized before the structure is used.
dwFlags
Is a set of flags that determine what members of the DDSURFACEDESC structure contain valid data. This member can be one or more of the following flags:
Flag | Meaning
DDSD_ALL | All input members contain valid data.
DDSD_ALPHABITDEPTH | The dwAlphaBitDepth member is valid.
DDSD_BACKBUFFERCOUNT | The dwBackBufferCount member is valid.
DDSD_CAPS | The ddsCaps member is valid.
DDSD_CKDESTBLT | The ddckCKDestBlt member is valid.
DDSD_CKDESTOVERLAY | The ddckCKDestOverlay member is valid.
DDSD_CKSRCBLT | The ddckCKSrcBlt member is valid.
DDSD_CKSRCOVERLAY | The ddckCKSrcOverlay member is valid.
DDSD_HEIGHT | The dwHeight member is valid.
DDSD_LINEARSIZE | The dwLinearSize member is valid.
DDSD_MIPMAPCOUNT | The dwMipMapCount member is valid.
DDSD_PITCH | The lPitch member is valid.
DDSD_PIXELFORMAT | The ddpfPixelFormat member is valid.
DDSD_REFRESHRATE | The dwRefreshRate member is valid.
DDSD_WIDTH | The dwWidth member is valid.
DDSD_ZBUFFERBITDEPTH | The dwZBufferBitDepth member is valid.

dwHeight
Specifies the height of surface in pixels.
dwWidth
Specifies the width of the surface in pixels.
lPitch
Specifies the number of bytes between the beginnings of two adjacent scan lines; that is, the number of bytes to add to the beginning address of one scan line to reach the beginning address of the next scan line below it. The driver's DdCreateSurface callback must return this value.
dwLinearSize
Specifies the size of a formless, late-allocated, optimized surface.
dwBackBufferCount
Specifies the number of back buffers associated with the surface.
dwMipMapCount
Specifies the number of mipmap levels.
dwZBufferBitDepth
Specifies the depth of z-buffer in bits per pixel.
dwRefreshRate
Specifies the refresh rate of the monitor (used when the display mode is described).
dwAlphaBitDepth
Specifies the depth of the alpha buffer in bits per pixel.
dwReserved
Is reserved and should be set to zero.
lpSurface
Specifies the address of the associated surface memory.
ddckCKDestOverlay
Specifies the color key for destination overlay use.
ddckCKDestBlt
Specifies the color key for destination blt use.
ddckCKSrcOverlay
Specifies the color key for source overlay use.
ddckCKSrcBlt
Specifies the color key for source blt use.
ddpfPixelFormat
Specifies a DDPIXELFORMAT structure that describes the pixel format of the surface.
ddsCaps
Specifies a DDSCAPS structure that contains the DirectDraw surface capabilities.

Comments

The relevant members differ for each potential type of surface. This structure is typically created and initialized by an application.


DDSURFACEDESC2

DDSURFACEDESC2 contains a description of a surface to be created by the driver.

typedef struct _DDSURFACEDESC2 {
  DWORD  dwSize;
  DWORD  dwFlags;
  DWORD  dwHeight;
  DWORD  dwWidth;
  union
  {
  LONG  lPitch;
  DWORD  dwLinearSize;
  } ;
  DWORD  dwBackBufferCount;
  union
  {
  DWORD  dwMipMapCount;
  DWORD  dwRefreshRate;
  DWORD  dwSrcVBHandle;
  } ;
  DWORD  dwAlphaBitDepth;
  DWORD  dwReserved;
  LPVOID  lpSurface;
  union
  {
  DDCOLORKEY  ddckCKDestOverlay;
  DWORD  dwEmptyFaceColor;
  } ;
  DDCOLORKEY  ddckCKDestBlt;
  DDCOLORKEY  ddckCKSrcOverlay;
  DDCOLORKEY  ddckCKSrcBlt;
  union
  {
  DDPIXELFORMAT  ddpfPixelFormat;
  DWORD  dwFVF;
  } ;
  DDSCAPS2  ddsCaps;
  DWORD  dwTextureStage;
} DDSURFACEDESC2;

Members

dwSize
Specifies the size in bytes of this DDSURFACEDESC2 structure. This member must be initialized before the structure is used.
dwFlags
Is a set of flags that determine what members of the DDSURFACEDESC2 structure contain valid data. This member can be one or more of the following flags:
Flag | Meaning
DDSD_ALL | All input members contain valid data.
DDSD_ALPHABITDEPTH | The dwAlphaBitDepth member is valid.
DDSD_BACKBUFFERCOUNT | The dwBackBufferCount member is valid.
DDSD_CAPS | The ddsCaps member is valid.
DDSD_CKDESTBLT | The ddckCKDestBlt member is valid.
DDSD_CKDESTOVERLAY | The ddckCKDestOverlay member is valid.
DDSD_CKSRCBLT | The ddckCKSrcBlt member is valid.
DDSD_CKSRCOVERLAY | The ddckCKSrcOverlay member is valid.
DDSD_FVF | The dwFVF member is valid.
DDSD_HEIGHT | The dwHeight member is valid.
DDSD_LINEARSIZE | The dwLinearSize member is valid.
DDSD_LPSURFACE | The lpSurface member is valid.
DDSD_MIPMAPCOUNT | The dwMipMapCount member is valid.
DDSD_PITCH | The lPitch member is valid.
DDSD_PIXELFORMAT | The ddpfPixelFormat member is valid.
DDSD_REFRESHRATE | The dwRefreshRate member is valid.
DDSD_SRCVBHANDLE | The dwSrcVBHandle member is valid.
DDSD_TEXTURESTAGE | The dwTextureStage member is valid.
DDSD_WIDTH | The dwWidth member is valid.
DDSD_ZBUFFERBITDEPTH | This flag is not used in DDSURFACEDESC2. It is only used in DDSURFACEDESC.

dwHeight
Specifies the height of surface in pixels.
dwWidth
Specifies the width of the surface in pixels.
lPitch
Specifies the number of bytes between the beginnings of two adjacent scan lines; that is, the number of bytes to add to the beginning address of one scan line to reach the beginning address of the next scan line below it. The driver's DdCreateSurface callback must return this value.
dwLinearSize
Specifies the size of a formless, late-allocated, optimized surface.
dwBackBufferCount
Specifies the number of back buffers associated with the surface.
dwMipMapCount
Specifies the number of mipmap levels.
dwZBufferBitDepth
Removed in DDSURFACEDESC2. Use the ddpfPixelFormat member of this structure instead.
dwRefreshRate
Specifies the refresh rate of the monitor (used when the display mode is described).
dwSrcVBHandle
Specifies the source used in IDirect3DVertexBuffer7::Optimize (described in the Direct3D SDK documentation).
dwAlphaBitDepth
Specifies the depth of the alpha buffer in bits per pixel.
dwReserved
Is reserved and should be set to zero.
lpSurface
Specifies the address of the associated surface memory.
ddckCKDestOverlay
Specifies the color key for destination overlay use.
dwEmptyFaceColor
Specifies the physical color for empty cube map faces.
ddckCKDestBlt
Specifies the color key for destination blit use.
ddckCKSrcOverlay
Specifies the color key for source overlay use.
ddckCKSrcBlt
Specifies the color key for source blit use.
ddpfPixelFormat
Specifies a DDPIXELFORMAT structure that describes the pixel format of the surface.
dwFVF
Specifies the Flexible Vertex Format (FVF) for the vertex buffers.
ddsCaps
Specifies a DDSCAPS structure that contains the DirectDraw surface capabilities.
dwTextureStage
Specifies the stage in the multitexture cascade.

Comments

The relevant members differ for each potential type of surface. This structure is typically created and initialized by an application.


DDVIDEOPORTBANDWIDTH

DDVIDEOPORTBANDWIDTH describes the bandwidth characteristics of an overlay when used with a particular VPE object/pixel format configuration.

typedef struct _DDVIDEOPORTBANDWIDTH {
  DWORD  dwSize;
  DWORD  dwCaps;
  DWORD  dwOverlay;
  DWORD  dwColorkey;
  DWORD  dwYInterpolate;
  DWORD  dwYInterpAndColorkey;
  ULONG_PTR  dwReserved1;
  ULONG_PTR  dwReserved2;
} DDVIDEOPORTBANDWIDTH;

Members

dwSize
Specifies the size in bytes of this DDVIDEOPORTBANDWIDTH structure.
dwCaps
Specifies the dependencies of the bandwidth. The driver's DdVideoPortGetBandwidth function sets this member to one of the following values:
Flag | Meaning
DDVPBCAPS_DESTINATION | The device's capabilities are described in terms of the destination overlay's minimum stretch factor. The bandwidth information set by the driver in the dwOverlay, dwColorkey, dwYInterpolate, and dwYInterpAndColorkey members refers to the destination overlay size.
DDVPBCAPS_SOURCE | The device's capabilities are described in terms of the required source overlay's rectangle size (in pixels). The bandwidth information set by the driver in the dwOverlay, dwColorkey, dwYInterpolate, and dwYInterpAndColorkey members refers to the source overlay size.

dwOverlay
Specifies the stretch factor or overlay source size at which the device can support an overlay, multiplied by 1000. The driver sets this value based on its device's type and capabilities, and on the dimensions specified in the dwWidth and dwHeight members of the DD_GETVPORTBANDWIDTHDATA structure passed to DdVideoPortGetBandwidth. For example, a stretch factor of 2 is specified as 2000, and an overlay source size of 750 indicates that the specified source overlay be shrunk to 75 percent of its original size. The driver must return a valid number in this member.
dwColorkey
Specifies the stretch factor or overlay source size at which an overlay with color keying is supported, multiplied by 1000. The driver sets this value based on its device's type and capabilities, and on the dimensions specified in the dwWidth and dwHeight members of the DD_GETVPORTBANDWIDTHDATA structure passed to DdVideoPortGetBandwidth. For example, a stretch factor of 2 is specified as 2000.
dwYInterpolate
Specifies the stretch factor or overlay source size at which an overlay with y-axis interpolation is supported, multiplied by 1000. The driver sets this value based on its device's type and capabilities, and on the dimensions specified in the dwWidth and dwHeight members of the DD_GETVPORTBANDWIDTHDATA structure passed to DdVideoPortGetBandwidth. For example, a stretch factor of 2 is specified as 2000.
dwYInterpAndColorkey
Specifies the stretch factor or overlay source size at which an overlay with y-axis interpolation and color keying is supported, multiplied by 1000. The driver sets this value based on its device's type and capabilities, and on the dimensions specified in the dwWidth and dwHeight members of the DD_GETVPORTBANDWIDTHDATA structure passed to DdVideoPortGetBandwidth. For example, a stretch factor of 2 is specified as 2000.
dwReserved1, dwReserved2
Are reserved for system use and should be ignored by the driver.


DDVIDEOPORTCAPS

DDVIDEOPORTCAPS describes the capabilities and alignment restrictions of a hardware video port.

typedef struct _DDVIDEOPORTCAPS {
  DWORD  dwSize;
  DWORD  dwFlags;
  DWORD  dwMaxWidth;
  DWORD  dwMaxVBIWidth;
  DWORD  dwMaxHeight;
  DWORD  dwVideoPortID;
  DWORD  dwCaps;
  DWORD  dwFX;
  DWORD  dwNumAutoFlipSurfaces;
  DWORD  dwAlignVideoPortBoundary;
  DWORD  dwAlignVideoPortPrescaleWidth;
  DWORD  dwAlignVideoPortCropBoundary;
  DWORD  dwAlignVideoPortCropWidth;
  DWORD  dwPreshrinkXStep;
  DWORD  dwPreshrinkYStep;
  DWORD  dwNumVBIAutoFlipSurfaces;
  DWORD  dwNumPreferredAutoflip;
  WORD  wNumFilterTapsX;
  WORD  wNumFilterTapsY;
} DDVIDEOPORTCAPS;

Members

dwSize
Specifies the size in bytes of the structure.
dwFlags
Specify what members in this structure contain valid data. This member can be a bitwise-OR of any of the following values:
Flag | Meaning
DDVPD_ALIGN All of the alignment members are valid. These include:
dwAlignVideoPortBoundary,
dwAlignVideoPortPrescaleWidth,
dwAlignVideoPortCropBoundary, and
dwAlignVideoPortCropWidth.
DDVPD_AUTOFLIP | The dwNumAutoFlipSurfaces is valid.
DDVPD_CAPS | The dwCaps member is valid.
DDVPD_FX | The dwFX member is valid.
DDVPD_HEIGHT | The dwMaxHeight member is valid.
DDVPD_ID | The dwVideoPortID member is valid.
DDVPD_WIDTH | The dwMaxWidth and dwMaxVBIWidth members are valid.

dwMaxWidth
Specifies the maximum field width supported by the hardware video port. This value is typically dictated by the number of bits in the width register.
dwMaxVBIWidth
Specifies the maximum width of VBI data supported by the hardware video port. This value can be larger than the normal field width if the hardware video port supports oversampled VBI data.
dwMaxHeight
Specifies the maximum field height supported by the hardware video port. This value is typically dictated by the number of bits in the height register.
dwVideoPortID
Specifies the hardware video port ID for this entry. This member should be the index number of this DDVIDEOPORTCAPS structure within the array to which the lpDDVideoPortCaps member of the DD_DIRECTDRAW_GLOBAL structure points. This value ranges from 0 to (dwMaxVideoPorts - 1). (dwMaxVideoPorts is a member of the DDCORECAPS structure.) If the device supports only one hardware video port, this member should be zero.
dwCaps
Is a set of flags that specify the capabilities supported by this hardware video port. This member can be a bitwise-OR of any of the following values:
Flag | Meaning
DDVPCAPS_AUTOFLIP | A flip can be performed automatically to avoid tearing.
DDVPCAPS_COLORCONTROL | The hardware video port can perform color operations on the incoming data before it is written to the frame buffer.
DDVPCAPS_INTERLACED | The hardware video port supports interlaced video.
DDVPCAPS_NONINTERLACED | The hardware video port supports noninterlaced video.
DDVPCAPS_OVERSAMPLEDVBI | The hardware video port can accept VBI data in a different width or format than the regular video data.
DDVPCAPS_READBACKFIELD | The device can return a value signifying whether the current field of an interlaced signal is even or odd.
DDVPCAPS_READBACKLINE | The device can return the number of the current line of video being written into the frame buffer.
DDVPCAPS_SHAREABLE | Is ignored by DirectDraw.
DDVPCAPS_SKIPEVENFIELDS | The hardware video port can automatically discard even fields of video.
DDVPCAPS_SKIPODDFIELDS | The hardware video port can automatically discard odd fields of video.
DDVPCAPS_SYNCMASTER | The device is capable of driving the graphics V-sync with the hardware video port driver V-sync.
DDVPCAPS_SYSTEMMEMORY | The hardware video port can write data directly to system memory.
DDVPCAPS_VBISURFACE | The data within the vertical blanking interval can be written to a different surface.

dwFX
Is a set of flags that specify the effects supported by this hardware video port. This member is a bitwise-OR of any of the following values:
Flag | Meaning
DDVPFX_CROPTOPDATA | The hardware video port supports limited cropping to crop out the vertical interval data.
DDVPFX_CROPX | The hardware video port can crop incoming data in the x direction before writing it to the surface.
DDVPFX_CROPY | The hardware video port can crop incoming data in the y direction before writing it to the surface.
DDVPFX_IGNOREVBIXCROP | The hardware video port can ignore the left and right cropping coordinates for video data when cropping oversampled VBI data.
DDVPFX_INTERLEAVE | The hardware video port supports interleaving interlaced fields in memory.
DDVPFX_MIRRORLEFTRIGHT | The hardware video port supports mirroring left to right as the video data is written into the frame buffer.
DDVPFX_MIRRORUPDOWN | The hardware video port supports mirroring top to bottom as the video data is written into the frame buffer.
DDVPFX_PRESHRINKX | Data can be arbitrarily shrunk in the x direction before it is written to the surface.
DDVPFX_PRESHRINKXB | Data can be shrunk by negative powers of 2 (1/2, 1/4, 1/8, and so on) in the x direction before it is written to the surface.
DDVPFX_PRESHRINKXS | Data can be shrunk in increments of 1/dwPreshrinkXStep in the x direction before it is written to the surface.
DDVPFX_PRESHRINKY | Data can be arbitrarily shrunk in the y direction before it is written to the surface.
DDVPFX_PRESHRINKYB | Data can be shrunk by negative powers of 2 (1/2, 1/4, 1/8, and so on) in the y direction before it is written to the surface.
DDVPFX_PRESHRINKYS | Data can be shrunk in increments of 1/dwPreshrinkYStep in the y direction before it is written to the surface.
DDVPFX_PRESTRETCHX | Data can be arbitrarily stretched in the x direction before it is written to the surface.
DDVPFX_PRESTRETCHXN | Data can be stretched by integer factors in the x direction before it is written to the surface.
DDVPFX_PRESTRETCHY | Data can be arbitrarily stretched in the y direction before it is written to the surface.
DDVPFX_PRESTRETCHYN | Data can be stretched by integer factors in the y direction before it is written to the surface.
DDVPFX_VBICONVERT | Data within the vertical blanking interval can be converted independent of the remaining video data.
DDVPFX_VBINOSCALE | Scaling can be disabled for data within the vertical blanking interval.

dwNumAutoFlipSurfaces
Specifies the maximum number of surfaces supported in the autoflip chain, if the hardware video port supports autoflipping. If the hardware video port does not support autoflipping, the driver should set this member to zero.
dwAlignVideoPortBoundary
Specifies the byte alignment restriction of where the hardware video port can be oriented relative to the origin of the surface in the x direction.
dwAlignVideoPortPrescaleWidth
Specifies the byte alignment restriction of how wide the hardware video port data can be when prescaling is performed.
dwAlignVideoPortCropBoundary
Specifies the byte alignment restriction for the left cropping coordinate.
dwAlignVideoPortCropWidth
Specifies the byte alignment restriction for the width of the cropping rectangle.
dwPreshrinkXStep
Indicates that the hardware video port can shrink the video data width in steps of 1/dwPreshrinkXStep. This member is valid only when the DDVPFX_PRESHRINKXS capability is specified.
dwPreshrinkYStep
Indicates that the hardware video port can shrink the video data height in steps of 1/dwPreshrinkYStep. This member is valid only when the DDVPFX_PRESHRINKYS capability is specified.
dwNumVBIAutoFlipSurfaces
Specifies the maximum number of surfaces supported in the autoflip chain, if the hardware video port supports autoflipping. If the hardware video port does not support autoflipping, the driver should set this member to zero. This member works the same way as dwNumAutoFlipSurfaces except that it pertains only to devices that can send the VBI data to a different surface than that to which the normal video is being written.
dwNumPreferredAutoflip
Specifies the optimal number of autoflippable surfaces supported by the hardware.
wNumFilterTapsX
Indicates the number of taps the prescaler uses in the x direction. A value of 0 indicates no prescale, a value of 1 indicates replication, and so on.
wNumFilterTapsY
Indicates the number of taps the prescaler uses in the y direction. A value of 0 indicates no prescale, a value of 1 indicates replication, and so on.

Comments

The driver reports the capabilities described by the DDVIDEOPORTCAPS structure when its DdGetDriverInfo function is called with the GUID_VideoPortCaps GUID.


DDVIDEOPORTCONNECT

DDVIDEOPORTCONNECT describes a hardware video port connection.

typedef struct _DDVIDEOPORTCONNECT {
  DWORD  dwSize;
  DWORD  dwPortWidth;
  GUID  guidTypeID;
  DWORD  dwFlags;
  ULONG_PTR  dwReserved1;
} DDVIDEOPORTCONNECT;

Members

dwSize
Specifies the size in bytes of the DDVIDEOPORTCONNECT structure.
dwPortWidth
Specifies the width of the hardware video port. This value represents the number of physical pins on the hardware video port. This member must always be filled in, even when the guidTypeID assumes a certain size.
guidTypeID
Specifies a GUID that describes the synchronization characteristics of the hardware video port. The following port types are predefined:
Port Type | Description
DDVPTYPE_E_HREFH_VREFH | External syncs where HREF is active high and VREF is active high.
DDVPTYPE_E_HREFH_VREFL | External syncs where HREF is active high and VREF is active low.
DDVPTYPE_E_HREFL_VREFH | External syncs where HREF is active low and VREF is active high.
DDVPTYPE_E_HREFL_VREFL | External syncs where HREF is active low and VREF is active low.
DDVPTYPE_BROOKTREE | Sync information is embedded in the data stream using the Brooktree definition.
DDVPTYPE_CCIR656 | Sync information is embedded in the data stream according to the CCIR656 specification.
DDVPTYPE_PHILIPS | Sync information is embedded in the data stream using the Philips definition.

dwFlags
Is a set of flags that identify the capabilities of the hardware video port connection. This member can be a bitwise OR of any of the following flags:
Flag | Meaning
DDVPCONNECT_DISCARDSVREFDATA | The device discards any data written during the VREF period, causing this data to not be written to the frame buffer. This flag should be set only by the driver.
DDVPCONNECT_DOUBLECLOCK | When set by the driver, this flag indicates that the hardware video port is capable of double clocking the data. When set by the client, it indicates that the hardware video port should double clock the data. This flag is valid only in a hardware video port with a guidTypeID that supports an external sync.
DDVPCONNECT_HALFLINE | When set by the driver, this flag indicates that the hardware video port supports writing half lines into the frame buffer, sometimes causing the data to not be displayed correctly. When set by the client, it indicates that the driver may write half lines.
DDVPCONNECT_INTERLACED | When set by the driver, this flag indicates that the hardware video port supports interlaced signals. When set by the client, it indicates that the signal is interlaced.
DDVPCONNECT_INVERTPOLARITY | When set by the driver, this flag indicates that the hardware video port is capable of inverting the field polarities; that is, treating even fields as odd and vice versa. When set by the client, it indicates that the hardware video port should invert the field polarities.
DDVPCONNECT_SHAREEVEN | This is currently an unimplemented feature and should be ignored by the driver.
DDVPCONNECT_SHAREODD | This is currently an unimplemented feature and should be ignored by the driver.
DDVPCONNECT_VACT | When set by the driver, this flag indicates that the hardware video port is capable of using an external VACT signal. When set by the client, it indicates that the hardware video port should use the external VACT signal.

dwReserved1
Is reserved for system use and should be set to zero.

Comments

The driver's DdVideoPortGetConnectInfo callback routine initializes a DDVIDEOPORTCONNECT structure for every connection that the hardware video port supports. The client can change the dwFlags member of one of the driver's DDVIDEOPORTCONNECT structures before calling the driver's DdVideoPortCanCreate callback.


DDVIDEOPORTDATA

DDVIDEOPORTDATA is used by DirectDraw to represent a VPE object to the kernel-mode miniport.

typedef struct DDVIDEOPORTDATA {
  DWORD  dwVideoPortId;
  DWORD  dwVPFlags;
  DWORD  dwOriginOffset;
  DWORD  dwHeight;
  DWORD  dwVBIHeight;
  ULONG  dwDriverReserved1;
  ULONG  dwDriverReserved2;
  ULONG  dwDriverReserved3;
} DDVIDEOPORTDATA, *LPDDVIDEOPORTDATA;

Members

dwVideoPortId
Specifies the ID of this hardware video port, an integer in the range (0 - (maximum number of hardware video ports - 1)).
dwVPFlags
Is a set of flags that specify the current user mode DDVP_Xxx flags set by DdVideoPortUpdate.
Flag | Meaning
DDVP_AUTOFLIP | Perform automatic flipping. Autoflipping is performed between the overlay surface that was attached to the hardware video port using the application's AttachSurface method, and the overlay surfaces that are attached to the surface using the application's AttachSurface method. The flip order is the order in which the overlay surfaces were attached.
DDVP_CONVERT | Perform the conversion using the target surface format.
DDVP_CROP | Perform cropping using the specified rectangle.
DDVP_HARDWAREDEINTERLACE | The hardware video port should use the deinterlacing hardware.
DDVP_IGNOREVBIXCROP | The video data should ignore the left and right cropping coordinates when cropping the VBI data.
DDVP_INTERLEAVE | Interlaced fields should be interleaved in memory.
DDVP_MIRRORLEFTRIGHT | The data should be mirrored left to right as it is written into the frame buffer.
DDVP_MIRRORUPDOWN | The data should be mirrored top to bottom as it is written into the frame buffer.
DDVP_OVERRIDEBOBWEAVE | These bob and weave decisions should not be overridden by other interfaces. If this flag is set, DirectDraw will not allow a kernel-mode driver to use the kernel-mode video transport functionality to switch the hardware between bob and weave modes.
DDVP_PRESCALE | Perform pre-scaling/zooming based on the prescale parameters.
DDVP_SKIPEVENFIELDS | Ignore input of even fields.
DDVP_SKIPODDFIELDS | Ignore input of odd fields.
DDVP_SYNCMASTER | Drive the graphics V-syncs using the hardware video port V-syncs.
DDVP_VBICONVERT | The lpddpfVBIOutputFormat member contains data that should be used to convert the data within the vertical blanking interval.
DDVP_VBINOINTERLEAVE | Interleaving can be disabled for data within the vertical blanking interval.
DDVP_VBINOSCALE | Data within the vertical blanking interval should not be scaled.

dwOriginOffset
Specifies the byte offset of the VPE object relative to the start of the surface. This value is used only by the miniport driver.
dwHeight
Specifies the height of the VPE object data. This value is used only by the miniport driver.
dwVBIHeight
Specifies the height of the VBI data. This value is used only by the miniport driver.
dwDriverReserved1, dwDriverReserved2, dwDriverReserved3
Are reserved for use by the miniport driver.


DDVIDEOPORTDESC

DDVIDEOPORTDESC describes the VPE object being created.

typedef struct _DDVIDEOPORTDESC {
  DWORD  dwSize;
  DWORD  dwFieldWidth;
  DWORD  dwVBIWidth;
  DWORD  dwFieldHeight;
  DWORD  dwMicrosecondsPerField;
  DWORD  dwMaxPixelsPerSecond;
  DWORD  dwVideoPortID;
  DWORD  dwReserved1;
  DDVIDEOPORTCONNECT  VideoPortType;
  ULONG_PTR  dwReserved2;
  ULONG_PTR  dwReserved3;
} DDVIDEOPORTDESC;

Members

dwSize
Specifies the size in bytes of the DDVIDEOPORTDESC structure.
dwFieldWidth
Specifies the width in pixels of the incoming video stream.
dwVBIWidth
Specifies the width in pixels of the VBI data in the incoming video stream.
dwFieldHeight
Specifies the field height in scan lines of the incoming video stream.
dwMicrosecondsPerField
Specifies the time interval in microseconds between live video VSYNCs. This number should be rounded up to the nearest whole microsecond.
dwMaxPixelsPerSecond
Specifies the maximum pixel rate per second.
dwVideoPortID
Specifies the ID of the hardware video port to be used. This ID should range from 0 to (dwMaxVideoPorts -1), where dwMaxVideoPorts is a member of the DDCORECAPS structure.
dwReserved1
Is reserved for system use and should be ignored by the driver.
VideoPortType
Specifies a DDVIDEOPORTCONNECT structure describing the connection characteristics of the hardware video port.
dwReserved2, dwReserved3
Are reserved for future use and should be ignored by the driver.


DDVIDEOPORTINFO

DDVIDEOPORTINFO describes how the driver should transfer video data to a surface (or to surfaces) and it is a member of the DD_VIDEOPORT_LOCAL structure.

typedef struct _DDVIDEOPORTINFO {
  DWORD  dwSize;
  DWORD  dwOriginX;
  DWORD  dwOriginY;
  DWORD  dwVPFlags;
  RECT  rCrop;
  DWORD  dwPrescaleWidth;
  DWORD  dwPrescaleHeight;
  LPDDPIXELFORMAT  lpddpfInputFormat;
  LPDDPIXELFORMAT  lpddpfVBIInputFormat;
  LPDDPIXELFORMAT  lpddpfVBIOutputFormat;
  DWORD  dwVBIHeight;
  ULONG_PTR  dwReserved1;
  ULONG_PTR  dwReserved2;
} DDVIDEOPORTINFO;

Members

dwSize
Specifies the size in bytes of the structure. This member must be initialized before the structure is used.
dwOriginX
Indicates the x placement of the video data within the surface, in pixels. This offset applies to all surfaces when autoflipping is requested.
dwOriginY
Indicates the y placement of the video data within the surface, in pixels. This offset applies to all surfaces when autoflipping is requested.
dwVPFlags
Is a set of flags that specify how the driver should transfer the video data. This member can be a bitwise OR of the following values:
Flag | Meaning
DDVP_AUTOFLIP | Perform automatic flipping. Auto-flipping is performed between the overlay surface that was attached to the hardware video port and the overlay surfaces that are attached to the surface. The flip order is the order in which the overlay surfaces were attached.
DDVP_CONVERT | The video data and target surface have different formats. The driver should convert the video data to the format of the target surface format.
DDVP_CROP | The driver should crop both the video and VBI data using the rectangle in the rCrop member.
DDVP_IGNOREVBIXCROP | The driver should ignore the left and right cropping coordinates when cropping the VBI data.
DDVP_INTERLEAVE | Interlaced fields of both video and VBI data should be interleaved in memory.
DDVP_MIRRORLEFTRIGHT | Video data should be mirrored left to right as it is written into the frame buffer.
DDVP_MIRRORUPDOWN | Video data should be mirrored top to bottom as it is written into the frame buffer.
DDVP_NOINTERLEAVE | If the DDVP_INTERLEAVE flag is set, the driver should interleave the video data only; that is, the driver should not interleave the VBI data.
DDVP_OVERRIDEBOBWEAVE | The bob and weave decisions should not be overridden by other interfaces. If this flag is set, DirectDraw will not allow a kernel-mode driver to use the kernel-mode video transport functionality to switch the hardware between bob and weave modes.
DDVP_PRESCALE | Perform prescaling/zooming based on the dwPrescaleWidth and dwPrescaleHeight members. The driver should prescale only the video data if DDVP_VBINOSCALE is set; otherwise, it should prescale both the video and VBI data.
DDVP_SKIPEVENFIELDS | Ignore input of even fields for both video and VBI data.
DDVP_SKIPODDFIELDS | Ignore input of odd fields for both video and VBI data.
DDVP_SYNCMASTER | Drive the graphics VSYNCs using the hardware video port VSYNCs.
DDVP_VBICONVERT | The DDPIXELFORMAT structure to which the lpddpfVBIOutputFormat member points contains data that should be used to convert the data within the vertical blanking interval.
DDVP_VBINOSCALE | Data within the vertical blanking interval should not be scaled.

rCrop
Specifies a RECT structure that specifies a cropping rectangle in pixels. This member contains a valid rectangle when the DDVP_CROP flag is set in the dwVPFlags member.
dwPrescaleWidth
Specifies the width in pixels to which the video and VBI data should be prescaled or zoomed. For example, if the video data is 720 pixels wide and the client requests the width cut in half, the client will specify 360 in dwPrescaleWidth. This member contains a valid width when the DDVP_PRESCALE flag is set in the dwVPFlags member.
dwPrescaleHeight
Specifies the height in pixels to which the video and VBI data should be prescaled or zoomed. For example, if the video data is 240 pixels wide and the client requests the width cut in half, the client will specify 120 in dwPrescaleHeight. This member contains a valid width when the DDVP_PRESCALE flag is set in the dwVPFlags member.
lpddpfInputFormat
Points to a DDPIXELFORMAT structure that specifies the format of the video data to be written to the VPE object. This format can be different from the target surface format if the VPE object performs a conversion.
lpddpfVBIInputFormat
Points to a DDPIXELFORMAT structure that specifies the input format of the data within the vertical blanking interval.
lpddpfVBIOutputFormat
Points to a DDPIXELFORMAT structure that specifies the output format of the data within the vertical blanking interval.
dwVBIHeight
Specifies the number of lines of data within the vertical blanking interval.
dwReserved1, dwReserved2
Are reserved for system use and should be ignored by the driver.

Comments

All members of this structure are set by the client and the driver should never change them. The client is typically the overlay mixer.


DXAPI_INTERFACE

DXAPI_INTERFACE contains the interfaces for the DxApi miniport driver functions.

typedef struct _DXAPI_INTERFACE {
  USHORT  Size;
  USHORT  Version;
  PVOID  Context;
  PVOID  InterfaceReference;
  PVOID  InterfaceDereference;
  PDX_GETIRQINFO  DxGetIrqInfo;
  PDX_ENABLEIRQ  DxEnableIrq;
  PDX_SKIPNEXTFIELD  DxSkipNextField;
  PDX_BOBNEXTFIELD  DxBobNextField;
  PDX_SETSTATE  DxSetState;
  PDX_LOCK  DxLock;
  PDX_FLIPOVERLAY  DxFlipOverlay;
  PDX_FLIPVIDEOPORT  DxFlipVideoPort;
  PDX_GETPOLARITY  DxGetPolarity;
  PDX_GETCURRENTAUTOFLIP  DxGetCurrentAutoflip;
  PDX_GETPREVIOUSAUTOFLIP  DxGetPreviousAutoflip;
  PDX_TRANSFER  DxTransfer;
  PDX_GETTRANSFERSTATUS  DxGetTransferStatus;
} DXAPI_INTERFACE, *PDXAPI_INTERFACE;

Members

Size
Specifies the size in bytes of this DXAPI_INTERFACE structure.
Version
Specifies the version of the DxApi miniport functions. This value will be passed back to the driver on subsequent DxApi miniport function calls.
Context
Points to the device extension of the device.
InterfaceReference
Is not used by the driver.
InterfaceDereference
Is not used by the driver.
DxGetIrqInfo
Points to the driver-supplied DxGetIrqInfo miniport driver callback routine.
DxEnableIrq
Points to the driver-supplied DxEnableIrq miniport driver callback routine.
DxSkipNextField
Points to the driver-supplied DxSkipNextField miniport driver callback routine.
DxBobNextField
Points to the driver-supplied DxBobNextField miniport driver callback routine.
DxSetState
Points to the driver-supplied DxSetState miniport driver callback routine.
DxLock
Points to the driver-supplied DxLock miniport driver callback routine.
DxFlipOverlay
Points to the driver-supplied DxFlipOverlay miniport driver callback routine.
DxFlipVideoPort
Points to the driver-supplied DxFlipVideoPort miniport driver callback routine.
DxGetPolarity
Points to the driver-supplied DxGetPolarity miniport driver callback routine.
DxGetCurrentAutoflip
Points to the driver-supplied DxGetCurrentAutoflip miniport driver callback routine.
DxGetPreviousAutoflip
Points to the driver-supplied DxGetPreviousAutoflip miniport driver callback routine.
DxTransfer
Points to the driver-supplied DxTransfer miniport driver callback routine.
DxGetTransferStatus
Points to the driver-supplied DxGetTransferStatus miniport driver callback routine.


HEAPALIGNMENT

HEAPALIGNMENT contains data specifying the alignment requirements for a given display memory heap.

typedef struct _HEAPALIGNMENT {
  DWORD  dwSize;
  DDSCAPS  ddsCaps;
  DWORD  dwReserved;
  SURFACEALIGNMENT  ExecuteBuffer;
  SURFACEALIGNMENT  Overlay;
  SURFACEALIGNMENT  Texture;
  SURFACEALIGNMENT  ZBuffer;
  SURFACEALIGNMENT  AlphaBuffer;
  SURFACEALIGNMENT  Offscreen;
  SURFACEALIGNMENT  FlipTarget;
} HEAPALIGNMENT, FAR *LPHEAPALIGNMENT;

Members

dwSize
Specifies the size in bytes of this HEAPALIGNMENT structure.
ddsCaps
Specifies a DDSCAPS structure that indicates what alignment fields are valid.
dwReserved
Is reserved for system use.
ExecuteBuffer
Specifies a SURFACEALIGNMENT structure that contains heap alignment requirements for surfaces tagged with DDSCAPS_EXECUTEBUFFER.
Overlay
Specifies a SURFACEALIGNMENT structure that contains heap alignment requirements for surfaces tagged with DDSCAPS_OVERLAY.
Texture
Specifies a SURFACEALIGNMENT structure that contains heap alignment requirements for surfaces tagged with DDSCAPS_TEXTURE.
ZBuffer
Specifies a SURFACEALIGNMENT structure that contains heap alignment requirements for surfaces tagged with DDSCAPS_ZBUFFER.
AlphaBuffer
Specifies a SURFACEALIGNMENT structure that contains heap alignment requirements for surfaces tagged with DDSCAPS_ALPHA.
Offscreen
Specifies a SURFACEALIGNMENT structure that contains heap alignment requirements for surfaces tagged with DDSCAPS_OFFSCREENPLAIN.
FlipTarget
Specifies a SURFACEALIGNMENT structure that contains heap alignment requirements for surfaces tagged with DDSCAPS_FLIP.

Comments

The driver should verify that the dwSize member is at least as large as sizeof(HEAPALIGNMENT). In the future, this structure may grow as additional surface types are added, but the order of the existing members will not change.


VIDEOMEMORY

VIDEOMEMORY allows the driver to manage its display memory into heaps.

typedef struct _VIDEOMEMORY {
  DWORD  dwFlags;
  FLATPTR  fpStart;
  union{
  FLATPTR  fpEnd;
  DWORD  dwWidth;
  };
  DDSCAPS  ddsCaps;
  DDSCAPS  ddsCapsAlt;
  union{
    struct _VMEMHEAP  *lpHeap;
    DWORD  dwHeight;
  };
} VIDEOMEMORY, *LPVIDEOMEMORY;

Members

dwFlags
Is a set of flags that describe this particular section of display memory. This member can be a bitwise OR of any of the following values:
Flag | Meaning
VIDMEM_ISLINEAR | The display memory is a contiguous block of memory.
VIDMEM_ISRECTANGULAR | The display memory is rectangular.
VIDMEM_ISHEAP | This flagais reserved for system use and should be ignored by the driver.
VIDMEM_ISNONLOCAL | The heap resides in nonlocal (AGP) memory.
VIDMEM_ISWC | The driver has enabled write-combining on the display memory in this heap. Write-combining is a special caching mode in Pentium™ Pro-class processors that batches writes to the same cache line so they can be transferred in a single bus clock. Write-combining does not preserve ordering of the writes, a tradeoff that is usually acceptable for frame buffers. Refer to Intel® documentation for more information on write-combining. This flag cannot be used unless the VIDMEM_ISNONLOCAL flag is also set.
VIDMEM_HEAPDISABLED | The DirectDraw run-time uses this flag to turn off a heap when the heap's initialization has failed. This will most likely occur with an AGP heap. The driver should not set this bit.

fpStart
Points to the starting address of a memory range in the heap.
fpEnd
Points to the ending address of a memory range if the heap is linear. This address is inclusive, that is, it specifies the last valid address in the range. Thus, the number of bytes specified by fpStart and fpEnd is (fpEnd - fpStart + 1).
dwWidth
Specifies the width in bytes of the section of memory pointed to by fpStart. This member should only be used to describe rectangular memory regions.
ddsCaps
Specifies a DDSCAPS structure in which the driver returns the capabilities for which this section of memory cannot be used.
ddsCapsAlt
Specifies a DDSCAPS structure in which the driver returns the capabilities for which this chunk of memory cannot be used when no other memory is found on the first pass.
lpHeap
Is reserved for system use and should be ignored by the driver.
dwHeight
Specifies the height of the chunk of memory to which fpStart points. This member should only be used to describe rectangular memory regions.

Comments

On Windows 2000 and later the data structure is called VIDEOMEMORY and on Windows 98/Me the data structure is called VIDMEM.

GDI allocates and passes an array of VIDEOMEMORY structures to the second call of the driver's DrvGetDirectDrawInfo function. The driver should fill in the appropriate members of each structure to describe each particular section of memory. The list provides a complete description of the driver's offscreen memory.

DirectDraw scans through to allocate its surfaces in the order the display memory heaps are listed. Heaps are managed in an array of VIDEOMEMORY structures. The memory allocated first will be the memory that is accessed first. The VIDEOMEMORY structure sets up certain starting points, and determines the amount of memory on the surface and what cannot be done with the surface. DirectDraw manages it by sub-allocating and deallocating memory, that is, creating and destroying surfaces under each heap's jurisdiction. Physical limits determine how to set up these attributes.

DirectDraw's heap manager makes two passes through the VIDEOMEMORY structures. The ddsCaps member indicates to DirectDraw what the memory in the heap cannot be used for on the first pass. For example, if the heap was just big enough for a back buffer, sprites could be excluded from being allocated on the first pass by setting the DSCAPS_OFFSCREENPLAIN flag in the DDSCAPS structure. That way, other surfaces would fill up with sprites, while preserving the back buffer for page flipping. The ddsCapsAlt member could be set to allow sprites on the second pass (by removing the DSCAPS_OFFSCREENPLAIN flag). This allows heaps to be used preferentially for their highest and best use, without ruling out alternative uses. By choosing the order of allocation carefully (for example, by listing the back buffer last), the need to sort by ddsCaps and ddsCapsAlt can sometimes be eliminated.


VIDEOMEMORYINFO

VIDEOMEMORYINFO describes the general format of the display's memory.

typedef struct _VIDEOMEMORYINFO {
  FLATPTR  fpPrimary;
  DWORD  dwFlags;
  DWORD  dwDisplayWidth;
  DWORD  dwDisplayHeight;
  LONG   lDisplayPitch;
  DDPIXELFORMAT  ddpfDisplay;
  DWORD  dwOffscreenAlign;
  DWORD  dwOverlayAlign;
  DWORD  dwTextureAlign;
  DWORD  dwZBufferAlign;
  DWORD  dwAlphaAlign;
  PVOID  pvPrimary;  // Windows 2000 and later
  DWORD  dwNumHeaps; // Windows 98/Me only
  LPVIDMEM  pvmList; // Windows 98/Me only
} VIDEOMEMORYINFO, *LPVIDEOMEMORYINFO;

Members

fpPrimary
Specifies the offset, in bytes, in display memory to the primary surface.
dwFlags
Is currently unused and should be set to zero.
dwDisplayWidth
Specifies the current width of the display, in pixels.
dwDisplayHeight
Specifies the current height of the display, in pixels.
lDisplayPitch
Specifies the current pitch of the display, in bytes.
ddpfDisplay
Specifies a DDPIXELFORMAT structure in which the pixel format of the display is described.
dwOffscreenAlign
Specifies the byte alignment required when allocating this memory for offscreen surfaces.
dwOverlayAlign
Specifies the byte alignment required when allocating this memory for overlay planes.
dwTextureAlign
Specifies the byte alignment required when allocating this memory for textures.
dwZBufferAlign
Specifies the byte alignment required when allocating this memory for the depth buffer.
dwAlphaAlign
Specifies the byte alignment required when allocating this memory for an alpha buffer.
pvPrimary (Windows 2000 and later only)
Specifies a kernel-mode pointer to the beginning of the primary surface.
dwNumHeaps (Windows 98/Me only)
Specifies the number of memory heaps in pvmList.
pvmList (Windows 98/Me only)
Points to the first heap in an array of heaps.

Comments

The VIDEOMEMORYINFO structure has minor differences between Windows 98/Me and Windows 2000 and later. On Windows 2000 and later the data structure is called VIDEOMEMORYINFO and on Windows 98/Me the data structure is called VIDMEMINFO. On Windows 2000 and later, VIDEOMEMORYINFO includes a field pvPrimary that stores a kernel-mode pointer to the primary surface. On Windows 98/Me, VIDMEMINFO includes the fields dwNumHeaps and pvmList that specify an array of memory heaps.

GDI allocates memory for and passes a VIDEOMEMORYINFO structure to the driver's DrvGetDirectDrawInfo function as a member of the DD_HALINFO parameter. The driver should fill in the appropriate members to describe the general characteristics of the device's memory.


VMEMHEAP

VMEMHEAP contains information about the heap.

typedef struct _VMEMHEAP {
  DWORD  dwFlags;
  DWORD  stride;
  LPVOID  freeList;
  LPVOID  allocList;
  DWORD  dwTotalSize;
  FLATPTR  fpGARTLin;
  FLATPTR  fpGARTDev;
  DWORD  dwCommitedSize;
  DWORD  dwCoalesceCount;
  HEAPALIGNMENT  Alignment;
  DDSCAPSEX  ddsCapsEx;
  DDSCAPSEX  ddsCapsExAlt;
  LARGE_INTEGER  liPhysAGPBase;
  HANDLE  hdevAGP;
  LPVOID  pvPhysRsrv;
} VMEMHEAP, FAR *LPVMEMHEAP;

Members

dwFlags
Is reserved for system use and should be ignored by the driver.
stride
Is reserved for system use and should be ignored by the driver.
freeList
Is reserved for system use and should be ignored by the driver.
allocList
Is reserved for system use and should be ignored by the driver.
dwTotalSize
Is reserved for system use and should be ignored by the driver.
fpGARTLin
Points to the linear graphic address remapping table (GART) address of the start of the heap for nonlocal display memory.
fpGARTDev
Points to the physical GART address of the start of the heap for nonlocal display memory.
dwCommitedSize
Is reserved for system use and should be ignored by the driver.
dwCoalesceCount
Is reserved for system use and should be ignored by the driver.
Alignment
Is reserved for system use and should be ignored by the driver.
ddsCapsEx
Is reserved for system use and should be ignored by the driver.
ddsCapsExAlt
Is reserved for system use and should be ignored by the driver.
liPhysAGPBase
Is reserved for system use and should be ignored by the driver.
hdevAGP
Is reserved for system use and should be ignored by the driver.
pvPhysRsrv
Is reserved for system use and should be ignored by the driver.


Windows 98/Me Structures

This section lists structures that are used by Windows® 98/Me drivers. These structures are defined in ddrawi.h.


DBLNODE

DBLNODE holds a node in a doubly-linked list of surface interfaces.

typedef struct _DBLNODE {
  struct  _DBLNODE  FAR  *next;
  struct  _DBLNODE  FAR  *prev;
  LPDDRAWI_DDRAWSURFACE_LCL  object;
  LPDDRAWI_DDRAWSURFACE_INT  object_int;
} DBLNODE, FAR *LPDBLNODE;

Members

next
Points to the next node.
prev
Points to the previous node.
object
Points to a DDRAWI_DDRAWSURFACE_LCL structure that is the link to the object.
object_int
Points to a DDRAWI_DDRAWSURFACE_INT structure containing the object interface.


DDHAL_Xxx Structures

This table contains all the DirectDraw driver structures whose names have the form DDHAL_Xxx, which is the form used on Windows 98/Me. These structures are identical to those whose names have the form DD_Xxx, which is the form used on Windows 2000 and later. The include file dx95type.h contains type defines from DD_Xxx to DDHAL_Xxx.

DDHAL_Xxx Structure | DD_Xxx Structure
DDHAL_BLTDATA | DD_BLTDATA
DDHAL_DDKERNELCALLBACKS | DD_KERNELCALLBACKS
DDHAL_GETBLTSTATUSDATA | DD_GETBLTSTATUSDATA
DDHAL_GETDRIVERINFODATA | DD_GETDRIVERINFODATA
DDHAL_GETSCANLINEDATA | DD_GETSCANLINEDATA
DDHAL_LOCKDATA | DD_LOCKDATA
DDHAL_SYNCSURFACEDATA | DD_SYNCSURFACEDATA
DDHAL_SYNCVIDEOPORTDATA | DD_SYNCVIDEOPORTDATA
DDHAL_WAITFORVERTICALBLANKDATA | DD_WAITFORVERTICALBLANKDATA


DDHALDDRAWFNS

DDHALDDRAWFNS contains pointers to ddraw16.dll entry points.

typedef struct {
  DWORD  dwSize;
  LPDDHAL_SETINFO  lpSetInfo;
  LPDDHAL_VIDMEMALLOC  lpVidMemAlloc;
  LPDDHAL_VIDMEMFREE  lpVidMemFree;
} DDHALDDRAWFNS, FAR *LPDDHALDDRAWFNS;

Members

dwSize
Specifies the size of this structure.
lpSetInfo
Points to the DDHAL_SetInfo function.
lpVidMemAlloc
Points to the DDHAL_VidMemAlloc function.
lpVidMemFree
Points to the DDHAL_VidMemFree function.

DDHAL_SetInfo

DDHAL_SetInfo provides GDI with current information about the driver.

extern BOOL DDAPI DDHAL_SetInfo(
  LPDDHALINFO  lpDDHALInfo,
  BOOL  reset
  );

Parameters

lpDDHALInfo
Points to the DDHALINFO structure.
reset
Specifies whether there has been a mode change. If set TRUE, there has been a mode change.

DDHAL_VidMemAlloc

DDHAL_VidMemAlloc allocates a block of video memory.

extern
  FLATPTR DDAPI DDHAL_VidMemAlloc(
    LPDDRAWI_DIRECTDRAW_GBL  lpDD,
    int  heap,
    DWORD  dwWidth,
    DWORD  dwHeight
    );

Parameters

lpDD
Points to a DDRAWI_DIRECTDRAW_GBL structure.
heap
Specifies the index of the DirectDraw heap from which to allocate the surface.
dwWidth
Specifies the width in bytes of the requested surface.
dwHeight
Specifies the height in scanlines of the requested surface.

DDHAL_VidMemFree

DDHAL_VidMemFree frees a block of video memory previously allocated by DDHAL_VidMemAlloc.

extern void
  DDAPI DDHAL_VidMemFree(
    LPDDRAWI_DIRECTDRAW_GBL  lpDD,
    int heap,
    FLATPTR  fpMem
    );

Parameters

lpDD
Points to a DDRAWI_DIRECTDRAW_GBL structure.
heap
Specifies the index of the DirectDraw heap from which the surface was allocated.
fpMem
Is the FLATPTR offset of the allocated surface.


DDHALINFO

DDHALINFO collects all the information needed to create an instance of a DirectDraw driver.

typedef struct _DDHALINFO {
  DWORD   dwSize;
  LPDDHAL_DDCALLBACKS  lpDDCallbacks;
  LPDDHAL_DDSURFACECALLBACKS  lpDDSurfaceCallbacks;
  LPDDHAL_DDPALETTECALLBACKS  lpDDPaletteCallbacks;
  VIDMEMINFO  vmiData;
  DDCORECAPS  ddCaps;
  DWORD  dwMonitorFrequency;
  LPDDHAL_GETDRIVERINFO  GetDriverInfo;
  DWORD  dwModeIndex;
  LPDWORD  lpdwFourCC;
  DWORD  dwNumModes;
  LPDDHALMODEINFO  lpModeInfo;
  DWORD  dwFlags;
  LPVOID  lpPDevice;
  DWORD  hInstance;
  DWORD  lpD3DGlobalDriverData;
  DWORD  lpD3DHALCallbacks;
  LPDDHAL_DDEXEBUFCALLBACKS  lpDDExeBufCallbacks;
} DDHALINFO, FAR *LPDDHALINFO;

Members

dwSize
Specifies the size of the structure. This member must be initialized before the structure is used.
lpDDCallbacks
Specifies the address of the DDHAL_DDCALLBACKS structure containing the DirectDraw object callbacks.
lpDDSurfaceCallbacks
Specifies the address of the DDHAL_DDSURFACECALLBACKS structure containing the DirectDrawSurface object callbacks.
lpDDPaletteCallbacks
Specifies the address of the DDHAL_DDPALETTECALLBACKS structure containing the DirectDrawPalette object callbacks.
vmiData
Specifies the address of a VIDEOMEMORYINFO structure that contains the display memory information.
ddCaps
Specifies the DDCORECAPS structure (defined in the DirectDraw SDK documentation) that specifies the capabilities the hardware can set.
dwMonitorFrequency
Indicates the monitor frequency in the current mode. (You can also poll for the monitor frequency using getDisplayDuration.)
GetDriverInfo
Is a callback to get an arbitrary vtable from the driver.
dwModeIndex
Specifies an ndex into a mode array that indicates the current mode.
lpdwFourCC
Indicates the FourCC codes supported in this mode only, and are listed in the order of preference of use (speed and quality).
dwNumModes
Indicates the number of modes supported.
lpModeInfo
Specifies the address of a DDHALMODEINFO structure that contains the mode information.
dwFlags
Is a set of display driver creation flags.
Flag | Meaning
DDHALINFO_GETDRIVERINFOSET | The GetDriverInfo member is set.
DDHALINFO_ISPRIMARYDISPLAY | The driver is the primary display driver.
DDHALINFO_MODEXILLEGAL | This hardware does not support ModeX modes.

lpPDevice
Indicates that the physical device pointer is the physical device in the display miniport driver.
hInstance
Is an instance handle to the 16-bit driver.
lpD3DGlobalDriverData
Points to the Direct3D global data.
lpD3DHALCallbacks
Points to the Direct3D callbacks.
lpDDExeBufCallbacks
Points to the execute buffer pseudo-object callbacks.

Comments

Windows 2000 and later use a similarly named structure, DD_HALINFO, to accomplish the same purpose.

DDHALINFO is filled out in the buildDDHALInfo16 and buildDDHALInfo32 functions of the DirectDraw HAL and contains all the unchanging function names and capabilities of the hardware and driver. The only entries of concern to the Direct3D HAL are the lpD3DGlobalDriverData, lpD3DHAL_Callbacks, and GetDriverInfo members. The other structure members relate only to the DirectDraw portion of the driver.

See Also

DD_HALINFO


DDRAWI_DDRAWCLIPPER_GBL

DDRAWI_DDRAWCLIPPER_GBL contains the global DirectDrawClipper data that can be shared between object instances.

typedef struct _DDRAWI_DDRAWCLIPPER_GBL {
  DWORD  dwRefCnt;
  DWORD  dwFlags;
  LPDDRAWI_DIRECTDRAW_GBL lpDD;
  DWORD  dwProcessId;
  ULONG_PTR  dwReserved1;
  ULONG_PTR  hWnd;
  LPRGNDATA  lpStaticClipList;
} DDRAWI_DDRAWCLIPPER_GBL;

Members

dwRefCnt
Is used by DirectDraw and should not be filled in by the driver.
dwFlags
Is a set of clip list control flags.
Flag | Meaning
DDRAWICLIP_ISINITIALIZED | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWICLIP_INMASTERSPRITELIST | The clipper is referenced in the master sprite list.
DDRAWICLIP_WATCHWINDOW | This flag is used by DirectDraw and should not be filled in by the driver.

lpDD
Is used by DirectDraw and should not be filled in by the driver.
dwProcessId
Is used by DirectDraw and should not be filled in by the driver.
dwReserved1
Is reserved for use by the display driver.
hWnd
Is the handle to the window being tracked by the clipper.
lpStaticClipList
Points to a RGNDATA structure (defined in dciddi.h) that contains the clip list set by the application.


DDRAWI_DDRAWCLIPPER_INT

DDRAWI_DDRAWCLIPPER_INT contains the DirectDrawClipper object's interface information.

typedef struct _DDRAWI_DDRAWCLIPPER_INT {
  LPVOID  lpVtbl;
  LPDDRAWI_DDRAWCLIPPER_LCL  lpLcl;
  LPDDRAWI_DDRAWCLIPPER_INT  lpLink;
  DWORD  dwIntRefCnt;
} DDRAWI_DDRAWCLIPPER_INT;

Members

lpVtbl
Is used by DirectDraw and should not be filled in by the driver.
lpLcl
Points to a DDRAWI_DDRAWCLIPPER_LCL structure that contains the local object.
lpLink
Is used by DirectDraw and should not be filled in by the driver.
dwIntRefCnt
Is used by DirectDraw and should not be filled in by the driver.


DDRAWI_DDRAWCLIPPER_LCL

DDRAWI_DDRAWCLIPPER_LCL contains local data for each individual DirectDrawClipper object.

typedef struct _DDRAWI_DDRAWCLIPPER_LCL {
  DWORD  lpClipMore;
  LPDDRAWI_DDRAWCLIPPER_GBL  lpGbl;
  LPDDRAWI_DIRECTDRAW_LCL  lpDD_lcl;
  DWORD  dwLocalRefCnt;
  IUnknown  FAR  *pUnkOuter;
  LPDDRAWI_DIRECTDRAW_INT  lpDD_int;
  ULONG_PTR  dwReserved1;
  IUnknown  *pAddrefedThisOwner;
} DDRAWI_DDRAWCLIPPER_LCL;

Members

lpClipMore
Points to additional local data. This member is for future use.
lpGbl
Points to a DDRAWI_DDRAWCLIPPER_GBL structure that contains the clip list data.
lpDD_lcl
Is used by DirectDraw and should not be filled in by the driver.
dwLocalRefCnt
Is used by DirectDraw and should not be filled in by the driver.
pUnkOuter
Is used by DirectDraw and should not be filled in by the driver.
lpDD_int
Is used by DirectDraw and should not be filled in by the driver.
dwReserved1
Is reserved for use by the display driver.
pAddrefedThisOwner
Is used by DirectDraw and should not be filled in by the driver.


DDRAWI_DDRAWPALETTE_GBL

DDRAWI_DDRAWPALETTE_GBL contains the global DirectDrawPalette data that can be shared between object instances.

typedef struct _DDRAWI_DDRAWPALETTE_GBL {
  DWORD  dwRefCnt;
  DWORD  dwFlags;
  LPDDRAWI_DIRECTDRAW_LCL  lpDD_lcl;
  DWORD  dwProcessId;
  LPPALETTEENTRY  lpColorTable;
  union
  {
     ULONG_PTR  dwReserved1;
     HPALETTE  hHELGDIPalette;
  };
  DWORD  dwDriverReserved;
  DWORD  dwContentsStamp;
  DWORD  dwSaveStamp;
  DWORD  dwHandle;
} DDRAWI_DDRAWPALETTE_GBL;

Members

dwRefCnt
Is used by DirectDraw and should not be filled in by the driver.
dwFlags
Is a set of palette control flags.
Flag | Meaning
DDRAWIPAL_2 | The palette has 2 entries.
DDRAWIPAL_4 | The palette has 4 entries.
DDRAWIPAL_16 | The palette has 16 entries.
DDRAWIPAL_256 | The palette has 256 entries.
DDRAWIPAL_ALLOW256 | The palette can be fully updated.
DDRAWIPAL_ALPHA | The entries in the palette contain alpha information.
DDRAWIPAL_DIRTY | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWIPAL_EXCLUSIVE | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWIPAL_GDI | The palette is allocated through GDI.
DDRAWIPAL_INHEL | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWIPAL_STORED_8 | The palette is stored as 8 bpp per entry.
DDRAWIPAL_STORED_8INDEX | The palette is stored as an 8-bit index into the destination palette.
DDRAWIPAL_STORED_16 | The palette is stored as 16 bpp per entry.
DDRAWIPAL_STORED_24 | The palette is stored as 24 bpp per entry.

lpDD_lcl
Is used by DirectDraw and should not be filled in by the driver.
dwProcessId
Is used by DirectDraw and should not be filled in by the driver.
lpColorTable
Specifies the address of an array of PALETTEENTRY structures that contain the RGB values that are the colors in the palette.
dwReserved1
Is reserved for use by the display driver.
hHELGDIPalette
Is used by DirectDraw and should not be filled in by the driver.
dwDriverReserved
Is reserved for use by the HAL, regardless of who created the object.
dwContentsStamp
Is incremented when the palette changes.
dwSaveStamp
Is set to dwContentsStamp when the palette is saved to a surface file.
dwHandle
Is a handle used in D3dDrawPrimitives2 palette notification.


DDRAWI_DDRAWPALETTE_INT

DDRAWI_DDRAWPALETTE_INT contains the DirectDrawPalette object's interface information.

typedef struct _DDRAWI_DDRAWPALETTE_INT {
  LPVOID  lpVtbl;
  LPDDRAWI_DDRAWPALETTE_LCL  lpLcl;
  LPDDRAWI_DDRAWPALETTE_INT  lpLink;
  DWORD  dwIntRefCnt;
} DDRAWI_DDRAWPALETTE_INT;

Members

lpVtbl
Is used by DirectDraw and should not be filled in by the driver.
lpLcl
Points to a DDRAWI_DDRAWPALETTE_LCL structure that contains the local object.
lpLink
Is used by DirectDraw and should not be filled in by the driver.
dwIntRefCnt
Is used by DirectDraw and should not be filled in by the driver.


DDRAWI_DDRAWPALETTE_LCL

DDRAWI_DDRAWPALETTE_LCL contains local data for each individual DirectDrawPalette object.

typedef struct _DDRAWI_DDRAWPALETTE_LCL {
  DWORD  lpPalMore;
  LPDDRAWI_DDRAWPALETTE_GBL  lpGbl;
  ULONG_PTR  dwUnused0;
  DWORD  dwLocalRefCnt;
  IUnknown FAR  *pUnkOuter;
  LPDDRAWI_DIRECTDRAW_LCL  lpDD_lcl;
  ULONG_PTR  dwReserved1;
  ULONG_PTR  dwDDRAWReserved1;
  ULONG_PTR  dwDDRAWReserved2;
  ULONG_PTR  dwDDRAWReserved3;
} DDRAWI_DDRAWPALETTE_LCL;

Members

lpPalMore
Specifies the address of additional local data. Reserved for system use.
lpGbl
Specifies the address of a DDRAWI_DDRAWPALETTE_GBL structure that contains the palette data.
dwUnused0
Is not currently used.
dwLocalRefCnt
Is used by DirectDraw and should not be filled in by the driver.
pUnkOuter
Is used by DirectDraw and should not be filled in by the driver.
lpDD_lcl
Is the address of the owning local driver object.
dwReserved1
Is reserved for use by the display driver.
dwDDRAWReserved1
dwDDRAWReserved2
dwDDRAWReserved3


DDRAWI_DDRAWSURFACE_GBL

DDRAWI_DDRAWSURFACE_GBL contains the global DirectDrawSurface data that can be shared between object instances.

typedef struct _DDRAWI_DDRAWSURFACE_GBL {
  DWORD  dwRefCnt;
  DWORD  dwGlobalFlags;
  union
  {
     LPACCESSRECTLIST  lpRectList;
     DWORD  dwBlockSizeY;
  };
  union
  {
     LPVMEMHEAP  lpVidMemHeap;
     DWORD  dwBlockSizeX;
  };
  union
  {
     LPDDRAWI_DIRECTDRAW_GBL lpDD;
     LPVOID   lpDDHandle;
  };
  FLATPTR   fpVidMem;
  union
  {
     LONG   lPitch;
     DWORD  dwLinearSize;
  };
  WORD    wHeight;
  WORD    wWidth;
  DWORD   dwUsageCount;
  ULONG_PTR   dwReserved1;
  DDPIXELFORMAT   ddpfSurface;
} DDRAWI_DDRAWSURFACE_GBL;

Members

dwRefCnt
Is used by DirectDraw and should not be filled in by the driver.
dwGlobalFlags
Is a set of global surface flags.
Flag | Meaning
DDRAWISURFGBL_FASTLOCKHELD | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWISURFGBL_HARDWAREOPDEST | This surface was the destination for an asynchronous hardware operation.
DDRAWISURFGBL_HARDWAREOPSOURCE | This surface was the source for an asynchronous hardware operation.
DDRAWISURFGBL_IMPLICITHANDLE | This hKernelHandle was created implicitly.
DDRAWISURFGBL_ISCLIENTMEM | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWISURFGBL_ISGDISURFACE | The surface represents what to GDI is a front buffer.
DDRAWISURFGBL_LATEALLOCATELINEAR | An optimized surface was allocate as a formless chunk. The lPitch member is invalid, but the dwLinearSize member is valid.
DDRAWISURFGBL_LOCKBROKEN | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWISURFGBL_LOCKNOTHOLDINGWIN16LOCK | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWISURFGBL_LOCKVRAMSTYLE | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWISURFGBL_MEMFREE | Video memory has been freed.
DDRAWISURFGBL_READONLYLOCKHELD | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWISURFGBL_SOFTWAREAUTOFLIP | This surface is autoflipped using software.
DDRAWISURFGBL_SYSMEMEXECUTEBUFFER | The driver sets this flag to inform DirectDraw that the surface was allocated in system memory.
DDRAWISURFGBL_SYSMEMREQUESTED | The surface is in system memory at the request of the user.
DDRAWISURFGBL_VPORTDATA | This surface received data from the video port.
DDRAWISURFGBL_VPORTINTERLEAVED | This surface contains interleaved video port data.

lpRectList
Is used by DirectDraw and should not be filled in by the driver.
dwBlockSizeY
Contains the block size of the y axis of display memory that the display driver requested.
lpVidMemHeap
Points to a VMEMHEAP structure from which the heap display memory was allocated.
dwBlockSizeX
Contains the block size of the x axis of display memory that the display driver requested.
lpDD
Points to a DDRAWI_DIRECTDRAW_GBL structure that contains information about the DirectDraw object.
lpDDHandle
Points to a handle to the DirectDraw object. This member is used by the display driver when calling functions in ddraw16.dll.
fpVidMem
Is the address of display memory.
lPitch
Specifies the distance in bytes to the start of the next line on the surface.
dwLinearSize
Specifies tthe linear size of a nonrectangular surface.
wHeight
Specifies the height of the surface in scanlines.
wWidth
Specifies the width of the surface in pixels.
dwUsageCount
Is used by DirectDraw and should not be filled in by the driver.
dwReserved1
Is reserved for use by the display driver for display memory surfaces only.
ddpfSurface
Is the address of a DDPIXELFORMAT structure that contains the pixel format information for this surface. This member is allocated only if the pixel format differs from that of the primary display; that is, it is not allocated unless the DDRAWISURF_HASPIXELFORMAT flag in the DDRAWI_DDRAWSURFACE_LCL structure is set.

Comments

Driver writers should use the GET_LPDDRAWSURFACE_GBL_MORE macro to traverse from a DDRAWI_DDRAWSURFACE_GBL address to the DDRAWI_DDRAWSURFACE_GBL_MORE structure.

The DDRAWI_DDRAWSURFACE_GBL structure is similar in purpose to the Windows 2000 and later structure, DD_SURFACE_GLOBAL.


DDRAWI_DDRAWSURFACE_GBL_MORE

DDRAWI_DDRAWSURFACE_GBL_MORE contains additional global DirectDrawSurface data that can be shared between object instances.

typedef struct _DDRAWI_DDRAWSURFACE_GBL_MORE {
  DWORD    dwSize;
  union
  {
     DWORD     dwPhysicalPageTable;
     FLATPTR   fpPhysicalVidMem;
  };
  LPDWORD  pPageTable;
  DWORD    cPages;
  ULONG_PTR    dwSavedDCContext;
  FLATPTR  fpAliasedVidMem;
  ULONG_PTR    dwDriverReserved;
  ULONG_PTR    dwHELReserved;
  DWORD    cPageUnlocks;
  ULONG_PTR    hKernelSurface;
  DWORD    dwKernelRefCnt;
  LPDDCOLORCONTROL lpColorInfo;
  FLATPTR  fpNTAlias;
  DWORD    dwContentsStamp;
  LPVOID   lpvUnswappedDriverReserved;
  LPVOID   lpDDRAWReserved2;
  DWORD    dwDDRAWReserved1;
  DWORD    dwDDRAWReserved2;
  FLATPTR  fpAliasOfVidMem;
} DDRAWI_DDRAWSURFACE_GBL_MORE;

Members

dwSize
Specifies the size of the structure. This member must be initialized before the structure is used.
dwPhysicalPageTable
Specifies the physical address of the page table (an array of physical addresses with one per 4KB page). This is the physical address of the table of physical addresses of the pages that hold the page-locked system memory surface. This table will be valid whenever the dwPageLockCount member of the DDRAWI_DDRAWSURFACE_MORE structure is non-zero.
fpPhysicalVidMem
Is the physical address of the surface (non-local display memory only).
pPageTable
Is the linear address of the page table whose physical address is given in dwPhysicalPageTable.
cPages
Specifies the count of elements in the array pointed to by dwPhysicalPageTable and pPageTable. This will be equal to the number of physical pages representing the surface.
dwSavedDCContext
Is used by the DirectDraw API and should not be filled in by the driver.
fpAliasedVidMem
Is used by DirectDraw and should not be filled in by the driver.
dwDriverReserved
Is reserved for driver use (both system and display memory surfaces).
dwHELReserved
Is used by DirectDraw and should not be filled in by the driver.
cPageUnlocks
Specifies the number of times a surface is page-unlocked. This member is incremented whenever the surface is page-unlocked. Drivers can cache the physical page table of a surface, then check this value whenever a new DMA request is received. If the value has changed, then the driver's cache of the physical page table needs to be updated. If not, the surface has remained page-locked since the last time it was passed to the driver.
hKernelSurface
Is the kernel handle for this surface.
dwKernelRefCnt
Is used by DirectDraw and should not be filled in by the driver.
lpColorInfo
Is used by DirectDraw and should not be filled in by the driver.
fpNTAlias
Is used by internally by DirectDraw and should not be filled in by the driver.
dwContentsStamp
Is a value that changes when the surface data changes. A value of 0 means no information.
lpvUnswappedDriverReserved
Is reserved for use by the display driver. It is not swapped when a Flip is called on this surface.
lpDDRAWReserved2
dwDDRAWReserved1
dwDDRAWReserved2
fpAliasOfVidMem
Is used by DirectDraw and should not be filled in by the driver.

Comments

Driver writers should use the GET_LPDDRAWSURFACE_GBL_MORE macro to traverse from a DDRAWI_DDRAWSURFACE_GBL address to the DDRAWI_DDRAWSURFACE_GBL_MORE structure.


DDRAWI_DDRAWSURFACE_INT

DDRAWI_DDRAWSURFACE_INT contains the DirectDrawSurface object's interface information.

typedef struct _DDRAWI_DDRAWSURFACE_INT {
  LPVOID  lpVtbl;
  LPDDRAWI_DDRAWSURFACE_LCL  lpLcl;
  LPDDRAWI_DDRAWSURFACE_INT  lpLink;
  DWORD   dwIntRefCnt;
} DDRAWI_DDRAWSURFACE_INT;

Members

lpVtbl
Is used by DirectDraw and should not be filled in by the driver.
lpLcl
Points to a DDRAWI_DDRAWSURFACE_LCL structure that contains the local object.
lpLink
Is used by DirectDraw and should not be filled in by the driver.
dwIntRefCnt
Is used by DirectDraw and should not be filled in by the driver.


DDRAWI_DDRAWSURFACE_LCL

DDRAWI_DDRAWSURFACE_LCL contains local data for each individual DirectDrawSurface object.

struct _DDRAWI_DDRAWSURFACE_LCL {
  LPDDRAWI_DDRAWSURFACE_MORE lpSurfMore;
  LPDDRAWI_DDRAWSURFACE_GBL  lpGbl;
  ULONG_PTR   hDDSurface;
  LPATTACHLIST  lpAttachList;
  LPATTACHLIST  lpAttachListFrom;
  DWORD  dwLocalRefCnt;
  DWORD  dwProcessId;
  DWORD  dwFlags;
  DDSCAPS  ddsCaps;
  union
  {
     LPDDRAWI_DDRAWPALETTE_INT  lpDDPalette;
     LPDDRAWI_DDRAWPALETTE_INT  lp16DDPalette;
  };
  union
  {
     LPDDRAWI_DDRAWCLIPPER_LCL  lpDDClipper;
     LPDDRAWI_DDRAWCLIPPER_INT  lp16DDClipper;
  };
  DWORD  dwModeCreatedIn;
  DWORD  dwBackBufferCount;
  DDCOLORKEY  ddckCKDestBlt;
  DDCOLORKEY  ddckCKSrcBlt;
  ULONG_PTR  hDC;
  ULONG_PTR  dwReserved1;
  DDCOLORKEY  ddckCKSrcOverlay;
  DDCOLORKEY  ddckCKDestOverlay;
  LPDDRAWI_DDRAWSURFACE_INT lpSurfaceOverlaying;
  DBLNODE  dbnOverlayNode;
  RECT  rcOverlaySrc;
  RECT  rcOverlayDest;
  DWORD  dwClrXparent;
  DWORD  dwAlpha;
  LONG  lOverlayX;
  LONG  lOverlayY;
} DDRAWI_DDRAWSURFACE_LCL;

Members

lpSurfMore
Is the address of a DDRAWI_DDRAWSURFACE_MORE structure that contains additional local data.
lpGbl
Is the address of a DDRAWI_DDRAWSURFACE_GBL structure that contains the display memory information for this surface.
hDDSurface
Is the Windows 2000 and later kernel-mode handle.
lpAttachList
Is the address of an ATTACHLIST structure that contains the list of surfaces to which this surface attached.
lpAttachListFrom
Address of an ATTACHLIST structure that contains the list of surfaces that are attached to this surface.
dwLocalRefCnt
Is used by DirectDraw and should not be filled in by the driver.
dwProcessId
Is used by DirectDraw and should not be filled in by the driver.
dwFlags
Is a set of surface control flags.
Flag | Meaning
DDRAWISURF_ATTACHED | The surface is attached to another surface.
DDRAWISURF_ATTACHED_FROM | This surface has other surfaces attached to it.
DDRAWISURF_BACKBUFFER | The surface was originally a back buffer.
DDRAWISURF_DATAISALIASED | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWISURF_DCIBUSY | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWISURF_DRIVERMANAGED | The surface is a driver-managed surface.
DDRAWISURF_FRONTBUFFER | The surface was originally a front buffer.
DDRAWISURF_GETDCNULL | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWISURF_HASCKEYDESTBLT | The surface has CKDestBlt
DDRAWISURF_HASCKEYDESTOVERLAY | The surface has CKDestOverlay.
DDRAWISURF_HASCKEYSRCBLT | The surface has CKSrcBlt.
DDRAWISURF_HASCKEYSRCOVERLAY | The surface has CKSrcOverlay.
DDRAWISURF_HASDC | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWISURF_HASOVERLAYDATA | The surface has overlay data.
DDRAWISURF_HASPIXELFORMAT | The surface has pixel format data.
DDRAWISURF_HELCB | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWISURF_HW_CKEYDESTBLT | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWISURF_HW_CKEYDESTOVERLAY | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWISURF_HW_CKEYSRCBLT | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWISURF_HW_CKEYSRCOVERLAY | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWISURF_IMPLICITCREATE | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWISURF_IMPLICITROOT | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWISURF_INMASTERSPRITELIST | The surface is referenced in the master sprite list.
DDRAWISURF_INVALID | The surface has been invalidated by a mode set.
DDRAWISURF_ISFREE | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWISURF_LOCKEXCLUDEDCURSOR | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWISURF_PARTOFPRIMARYCHAIN | The surface is part of a primary chain.
DDRAWISURF_SETGAMMA | Gamma ramp for this surface is active.
DDRAWISURF_STEREOSURFACELEFT | The surface is the left of a stereo pair.
DDRAWISURF_SW_CKEYDESTBLT | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWISURF_SW_CKEYDESTOVERLAY | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWISURF_SW_CKEYSRCBLT | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWISURF_SW_CKEYSRCOVERLAY | This flag is used by DirectDraw and should not be filled in by the driver.

ddsCaps
Specifies the address of a DDSCAPS structure that contains the capabilities of the surface.
lpDDPalette
Points to a DDRAWI_DDRAWPALETTE_INT structure that contains the palette information associated with this surface.
lp16DDPalette
Is a 16-bit pointer to a DDRAWI_DDRAWPALETTE_INT structure that contains the palette information associated with this surface.
lpDDClipper
Points to a DDRAWI_DDRAWCLIPPER_LCL structure that contains the clip list information associated with this surface.
lp16DDClipper
Is a 16-bit pointer to a DDRAWI_DDRAWCLIPPER_INT structure that contains the clip list information associated with this surface.
dwModeCreatedIn
Is used by DirectDraw and should not be filled in by the driver.
dwBackBufferCount
Indicates the number of back buffers that were created for this surface.
ddckCKDestBlt
Is a DDCOLORKEY structure (defined in the DirectDraw SDK documentation) that contains the color key information for destination blt use.
ddckCKSrcBlt
Is a DDCOLORKEY structure that contains the color key information for source blt use.
hDC
Is used by DirectDraw and should not be filled in by the driver.
dwReserved1
Is reserved for use by the display driver.
ddckCKSrcOverlay
Is a DDCOLORKEY structure (defined in the DirectDraw SDK documentation) that contains the color key information for source overlay use.
ddckCKDestOverlay
Is a DDCOLORKEY structure that contains the color key information for destination overlay use.
lpSurfaceOverlaying
Points to a DDRAWI_DDRAWSURFACE_INT structure that contains the information about the surface that is being overlaid.
dbnOverlayNode
Is a DBLNODE structure that contains the pointers to the previous and next overlays.
rcOverlaySrc
Is used by DirectDraw and should not be filled in by the driver.
rcOverlayDest
Is used by DirectDraw and should not be filled in by the driver.
dwClrXparent
Is used by DirectDraw and should not be filled in by the driver.
dwAlpha
Is used by DirectDraw and should not be filled in by the driver.
lOverlayX
Specifies the current x overlay position.
lOverlayY
Specifies the current y overlay position.

Comments

Every member of this structure following the dwReserved1 member is allocated only if the surface can be used for overlays. When this part of the structure is allocated, ddckCDSrcOverlay must not be moved from the beginning of this area.

The DDRAWI_DDRAWSURFACE_LCL structure is similar in purpose to the Windows 2000 and later structure, DD_SURFACE_LOCAL.


DDRAWI_DDRAWSURFACE_MORE

DDRAWI_DDRAWSURFACE_MORE contains additional local data for each individual DirectDrawSurface object.

typedef struct _DDRAWI_DDRAWSURFACE_MORE {
  DWORD  dwSize;
  IUNKNOWN_LIST  FAR  *lpIUnknowns;
  LPDDRAWI_DIRECTDRAW_LCL  lpDD_lcl;
  DWORD  dwPageLockCount;
  DWORD  dwBytesAllocated;
  LPDDRAWI_DIRECTDRAW_INT  lpDD_int;
  DWORD  dwMipMapCount;
  LPDDRAWI_DDRAWCLIPPER_INT  lpDDIClipper;
  //------- Fields added in Version 5.0 -------
  LPHEAPALIASINFO  lpHeapAliasInfo;
  DWORD  dwOverlayFlags;
  VOID  *rgjunc;
  LPDDRAWI_DDVIDEOPORT_LCL  lpVideoPort;
  LPDDOVERLAYFX  lpddOverlayFX;
  DDSCAPSEX  ddsCapsEx;
  DWORD  dwTextureStage;
  LPVOID  lpDDRAWReserved;
  LPVOID  lpDDRAWReserved2;
  LPVOID  lpDDrawReserved3;
  DWORD  dwDDrawReserved4;
  LPVOID  lpDDrawReserved5;
  LPDWORD  lpGammaRamp;
  LPDWORD  lpOriginalGammaRamp;
  LPVOID  lpDDrawReserved6;
#ifndef WIN95
  DISPLAYMODEINFO  dmiDDrawReserved7;
#endif
  DWORD  dwSurfaceHandle;
  DWORD  qwDDrawReserved8[2];
  LPVOID  lpDDrawReserved9;
  DWORD  cSurfaces;
  LPDDSURFACEDESC2  pCreatedDDSurfaceDesc2;
  LPDDRAWI_DDRAWSURFACE_LCL *slist;
  DWORD  dwFVF;
  PVOID  lpVB;
} DDRAWI_DDRAWSURFACE_MORE;

Members

dwSize
Specifies the size of this structure. This member must be initialized before the structure is used.
lpIUnknowns
Is used by DirectDraw and should not be filled in by the driver.
lpDD_lcl
Is used by DirectDraw and should not be filled in by the driver.
dwPageLockCount
Is used by DirectDraw and should not be filled in by the driver.
dwBytesAllocated
Is used by DirectDraw and should not be filled in by the driver.
lpDD_int
Is used by DirectDraw and should not be filled in by the driver.
dwMipMapCount
Contains the number of MIP map levels in the chain.
lpDDIClipper
Is used by DirectDraw and should not be filled in by the driver.
lpHeapAliasInfo
Is used by DirectDraw and should not be filled in by the driver.
dwOverlayFlags
Contains the overlay flags most recently passed to UpdateOverlay.
Flag | Meaning
DDOVER_ADDDIRTYRECT | Add a dirty rectangle to an emulated overlaid surface.
DDOVER_ALPHADEST | Use the alpha information in the pixel format or the alpha channel surface attached to the destination surface as the alpha channel for the destination overlay.
DDOVER_ALPHADESTCONSTOVERRIDE | Use the dwConstAlphaDest field in the DDOVERLAYFX structure (defined in the DirectDraw SDK documentation) as the destination alpha channel for this overlay.
DDOVER_ALPHADESTNEG | The NEG suffix indicates that the destination surface becomes more transparent as the alpha value increases.
DDOVER_ALPHADESTSURFACEOVERRIDE | Use the lpDDSAlphaDest field in the DDOVERLAYFX structure (defined in the DirectDraw SDK documentation) as the alpha channel destination for this overlay.
DDOVER_ALPHAEDGEBLEND | Use the dwAlphaEdgeBlend field in the DDOVERLAYFX structure (defined in the DirectDraw SDK documentation) as the alpha channel for the edges of the image that border the color key colors.
DDOVER_ALPHASRC | Use the alpha information in the pixel format or the alpha channel surface attached to the source surface as the source alpha channel for this overlay.
DDOVER_ALPHASRCCONSTOVERRIDE | Use the dwConstAlphaSrc field in the DDOVERLAYFX structure (defined in the DirectDraw SDK documentation) as the source alpha channel for this overlay.
DDOVER_ALPHASRCNEG | The NEG suffix indicates that the source surface becomes more transparent as the alpha value increases.
DDOVER_ALPHASRCSURFACEOVERRIDE | Use the lpDDSAlphaSrc field in the DDOVERLAYFX structure (defined in the DirectDraw SDK documentaion) as the alpha channel source for this overlay.
DDOVER_ARGBSCALEFACTORS | The DDOVERLAYFX structure (defined in the DirectDraw SDK documentation) contains valid ARGB scaling factors.
DDOVER_AUTOFLIP | Autoflip the overlay whenever the video port autoflips.
DDOVER_BOB | Display each field of video port data individually without causing any jittery artifacts.
DDOVER_BOBHARDWARE | Bob will be performed using hardware rather than software or emulation.
DDOVER_DDFX | Use the overlay FX flags to define special overlay FX.
DDOVER_DEGRADEARGBSCALING | ARGB scaling factors can be degraded to conform with driver capabilities.
DDOVER_HIDE | Turn this overlay off.
DDOVER_INTERLEAVED | The surface memory is composed of interleaved fields.
DDOVER_KEYDEST | Use the color key associated with the destination surface.
DDOVER_KEYDESTOVERRIDE | Use the dckDestColorkey field in the DDOVERLAYFX structure (defined in the DirectDraw SDK documentation) as the color key for the destination surface.
DDOVER_KEYSRC | Use the color key associated with the source surface.
DDOVER_KEYSRCOVERRIDE | Use the dckSrcColorkey field in the DDOVERLAYFX structure as the color key for the source surface.
DDOVER_OVERRIDEBOBWEAVE | Bob/weave decisions should not be overridden by other interfaces.
DDOVER_REFRESHALL | Redraw the entire surface on an emulated overlaid surface.
DDOVER_REFRESHDIRTYRECTS | Redraw all dirty rectangles on an emulated overlaid surface.
DDOVER_SHOW | Turn this overlay on.

rgjunc
Is used by DirectDraw and should not be filled in by the driver.
lpVideoPort
Points to a DDRAWI_DDVIDEOPORT_LCL structure of the video port currently writing data to this surface.
lpddOverlayFX
Points to a DDOVERLAYFX structure (defined in the DirectDraw SDK documentation) that contains the current overlay FX.
ddsCapsEx
dwTextureStage
Specifies the stage in a multitexture cascade.
lpDDRAWReserved
lpDDRAWReserved2
lpDDrawReserved3
dwDDrawReserved4
lpDDrawReserved5
lpGammaRamp
lpOriginalGammaRamp
lpDDrawReserved6
dmiDDrawReserved7
dwSurfaceHandle
Specifies a cookie for use with the CreateSurfaceEx DDI.
qwDDrawReserved8
lpDDrawReserved9
cSurfaces
Is used by DirectDraw and should not be filled in by the driver.
pCreatedDDSurfaceDesc2
Is used by DirectDraw and should not be filled in by the driver.
slist
Is used by DirectDraw and should not be filled in by the driver.
dwFVF
Specifies the saved FVF flags for execute buffers.
lpVB
Is used by DirectDraw and should not be filled in by the driver.

Comments

The DDRAWI_DDRAWSURFACE_MORE structure is similar in purpose to the Windows 2000 and later structure, DD_SURFACE_MORE.


DDRAWI_DDVIDEOPORT_INT

DDRAWI_DDVIDEOPORT_INT contains the DirectDraw video port object's interface information.

typedef struct _DDRAWI_DDVIDEOPORT_INT {
  LPVOID  lpVtbl;
  LPDDRAWI_DDVIDEOPORT_LCL  lpLcl;
  LPDDRAWI_DDVIDEOPORT_INT  lpLink;
  DWORD  dwIntRefCnt;
  DWORD  dwFlags;
} DDRAWI_DDVIDEOPORT_INT;

Members

lpVtbl
Is used by DirectDraw and should not be filled in by the driver.
lpLcl
Points to a DDRAWI_DDVIDEOPORT_LCL structure that contains the local object.
lpLink
Is used by DirectDraw and should not be filled in by the driver.
dwIntRefCnt
Is used by DirectDraw and should not be filled in by the driver.
dwFlags
Is used by DirectDraw and should not be filled in by the driver.


DDRAWI_DDVIDEOPORT_LCL

DDRAWI_DDVIDEOPORT_LCL contains local data for each individual DirectDraw video port object.

typedef struct _DDRAWI_DDVIDEOPORT_LCL {
  LPDDRAWI_DIRECTDRAW_LCL  lpDD;
  DDVIDEOPORTDESC  ddvpDesc;
  DDVIDEOPORTINFO  ddvpInfo;
  LPDDRAWI_DDRAWSURFACE_INT  lpSurface;
  LPDDRAWI_DDRAWSURFACE_INT  lpVBISurface;
  LPDDRAWI_DDRAWSURFACE_INT *lpFlipInts;
  DWORD  dwNumAutoflip;
  DWORD  dwProcessID;
  DWORD  dwStateFlags;
  DWORD  dwFlags;
  DWORD  dwRefCnt;
  FLATPTR  fpLastFlip;
  ULONG_PTR  dwReserved1;
  ULONG_PTR  dwReserved2;
  HANDLE  hDDVideoPort;
  DWORD  dwNumVBIAutoflip;
  LPDDVIDEOPORTDESC  lpVBIDesc;
  LPDDVIDEOPORTDESC  lpVideoDesc;
  LPDDVIDEOPORTINFO  lpVBIInfo;
  LPDDVIDEOPORTINFO  lpVideoInfo;
  DWORD  dwVBIProcessID;
} DDRAWI_DDVIDEOPORT_LCL;

Members

lpDD
Points to a DDRAWI_DIRECTDRAW_LCL structure that contains the local DirectDraw object's data.
ddvpDesc
Points to a DDVIDEOPORTDESC structure that describes the video port object.
ddvpInfo
Points to a DDVIDEOPORTINFO structure that describes the transfer of video data to a surface.
lpSurface
Points to a DDRAWI_DDRAWSURFACE_INT structure for the surface receiving the data.
lpVBISurface
Points to a DDRAWI_DDRAWSURFACE_INT structure for the surface receiving the VBI data.
lpFlipInts
Is used by DirectDraw and should not be filled in by the driver.
dwNumAutoflip
Specifies the number of current autoflip surfaces. The driver should use this member for information purposes only.
dwProcessID
Is used by DirectDraw and should not be filled in by the driver.
dwStateFlags
Is used by DirectDraw and should not be filled in by the driver.
dwFlags
Is used by DirectDraw and should not be filled in by the driver.

dwRefCnt
Is used by DirectDraw and should not be filled in by the driver.
fpLastFlip
Is used by DirectDraw and should not be filled in by the driver.
dwReserved1
Is reserved for use by the display driver.
dwReserved2
Is reserved for use by the display driver.
hDDVideoPort
Is used by DirectDraw and should not be filled in by the driver.
dwNumVBIAutoflip
Specifies the number of VBI surfaces currently being autoflipped. The driver should use this member for information purposes only.
lpVBIDesc
lpVideoDesc
lpVBIInfo
lpVideoInfo
dwVBIProcessID
Specifies the ID of the process owning this video port.

Comments

The DDRAWI_DDVIDEOPORT_LCL structure is similar in purpose to the Windows 2000 and later structure, DD_VIDEOPORT_LOCAL.


DDRAWI_DIRECTDRAW_GBL

DDRAWI_DIRECTDRAW_GBL contains the global DirectDraw data that can be shared between object instances.

typedef struct _DDRAWI_DIRECTDRAW_GBL {
  DWORD  dwRefCnt;
  DWORD  dwFlags;
  FLATPTR  fpPrimaryOrig;
  DDCORECAPS  ddCaps;
  DWORD  dwInternal1;
  DWORD  dwUnused1[9];
  LPDDHAL_CALLBACKS  lpDDCBtmp;
  LPDDRAWI_DDRAWSURFACE_INT  dsList;
  LPDDRAWI_DDRAWPALETTE_INT  palList;
  LPDDRAWI_DDRAWCLIPPER_INT  clipperList;
  LPDDRAWI_DIRECTDRAW_GBL  lp16DD;
  DWORD  dwMaxOverlays;
  DWORD  dwCurrOverlays;
  DWORD  dwMonitorFrequency;
  DDCORECAPS  ddHELCaps;
  DWORD  dwUnused2[50];
  DDCOLORKEY  ddckCKDestOverlay;
  DDCOLORKEY  ddckCKSrcOverlay;
  VIDMEMINFO  vmiData;
  LPVOID  lpDriverHandle;
  LPDDRAWI_DIRECTDRAW_LCL  lpExclusiveOwner;
  DWORD  dwModeIndex;
  DWORD  dwModeIndexOrig;
  DWORD  dwNumFourCC;
  DWORD FAR  *lpdwFourCC;
  DWORD  dwNumModes;
  LPDDHALMODEINFO  lpModeInfo;
  PROCESS_LIST  plProcessList;
  DWORD  dwSurfaceLockCount;
  DWORD  dwAliasedLockCnt;
  ULONG_PTR  dwReserved3;
  ULONG_PTR  hDD;
  char  cObsolete[12];
  DWORD  dwReserved1;
  DWORD  dwReserved2;
  DBLNODE  dbnOverlayRoot;
  volatile LPWORD  lpwPDeviceFlags;
  DWORD  dwPDevice;
  DWORD  dwWin16LockCnt;
  DWORD  dwUnused3;
  DWORD  hInstance;
  DWORD  dwEvent16;
  DWORD  dwSaveNumModes;
 //------- Fields added in Version 2.0 -------
  ULONG_PTR  lpD3DGlobalDriverData;
  ULONG_PTR  lpD3DHALCallbacks;
  DDCORECAPS  ddBothCaps;
//------- Fields added in Version 5.0 -------
  LPDDVIDEOPORTCAPS  lpDDVideoPortCaps;
  LPDDRAWI_DDVIDEOPORT_INT  dvpList;
  ULONG_PTR  lpD3DHALCallbacks2;
  RECT  rectDevice;
  DWORD  cMonitors;
  LPVOID  gpbmiSrc;
  LPVOID  gpbmiDest;
  LPHEAPALIASINFO  phaiHeapAliases;
  ULONG_PTR  hKernelHandle;
  ULONG_PTR  pfnNotifyProc;
  LPDDKERNELCAPS  lpDDKernelCaps;
  LPDDNONLOCALVIDMEMCAPS  lpddNLVCaps;
  LPDDNONLOCALVIDMEMCAPS  lpddNLVHELCaps;
  LPDDNONLOCALVIDMEMCAPS  lpddNLVBothCaps;
  ULONG_PTR  lpD3DExtendedCaps;
//--------Fields added in Version 5.0A
  DWORD  dwDOSBoxEvent;
  RECT  rectDesktop;
  char  cDriverName[MAX_DRIVER_NAME];
//------ Fields added in Version 6.0 -------
  ULONG_PTR   lpD3DHALCallbacks3;
  DWORD  dwNumZPixelFormats;
  LPDDPIXELFORMAT  lpZPixelFormats;
  LPDDRAWI_DDMOTIONCOMP_INT mcList;
  DWORD  hDDVxd;
  DDSCAPSEX  ddsCapsMore;
} DDRAWI_DIRECTDRAW_GBL;

Members

dwRefCnt
Is used by DirectDraw and should not be filled in by the driver.
dwFlags
Contains the DirectDraw object's control flags.
Flag | Meaning
DDRAWI_ATTACHEDTODESKTOP | The device is attached to the desktop.
DDRAWI_CHANGINGMODE | The display is currently in a mode change.
DDRAWI_DDRAWDATANOTFETCHED | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWI_DISPLAYDRV | The driver is the display driver.
DDRAWI_EMULATIONINITIALIZED | Emulation has been initialized.
DDRAWI_EXPLICITMONITOR | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWI_EXTENDEDALIGNMENT | At least one heap has extended alignment. Ignore the alignment specified in VIDEOMEMORYINFO.
DDRAWI_FLIPPEDTOGDI | The driver has been flipped to show the GDI surface.
DDRAWI_FULLSCREEN | The driver is in full-screen mode.
DDRAWI_GDIDRV | The driver is a GDI driver.
DDRAWI_HASCKEYDESTOVERLAY | The driver has CKDestOverlay.
DDRAWI_HASCKEYSRCOVERLAY | The driver has CKSrcOverlay.
DDRAWI_HASGDIPALETTE | A GDI palette exists on the primary surface.
DDRAWI_HASGDIPALETTE_EXCLUSIVE | The palette is in exclusive mode.
DDRAWI_MODECHANGED | The display mode has been changed.
DDRAWI_MODEX | The driver is using Mode X.
DDRAWI_MODEXILLEGAL | ModeX is not supported by this hardware.
DDRAWI_NEEDSWIN16FORVRAMLOCK | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWI_NOEMULATION | There is no emulation.
DDRAWI_NOHARDWARE | There is no hardware associated with this driver.
DDRAWI_PALETTEINIT | The GDI palette has been initialized.
DDRAWI_PDEVICEVRAMBITCLEARED | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWI_SECONDARYDRIVERLOADED | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWI_STANDARDVGA | The device is using standard VGA mode (DDRAWI_MODEX will be set).
DDRAWI_TESTINGMODES | This flag is used by DirectDraw and should not be filled in by the driver.
DDRAWI_UMODELOADED | A user-mode driver DLL is loaded.
DDRAWI_VIRTUALDESKTOP | The driver is really a multimonitor virtual desktop.

fpPrimaryOrig
Points to the memory location of the primary surface display memory.
ddCaps
Specifies a DDCORECAPS structure (defined in the DirectDraw SDK documentation) that contains the driver capabilities.
dwInternal1
Is used by DirectDraw and should not be filled in by the driver.
dwUnused1
Is not currently used.
lpDDCBtmp
Points to a DDHAL_CALLBACKS structure that contains pointers to HAL callbacks.
dsList
Is used by DirectDraw and should not be filled in by the driver.
palList
Is used by DirectDraw and should not be filled in by the driver.
clipperList
Is used by DirectDraw and should not be filled in by the driver.
lp16DD
Is used by DirectDraw and should not be filled in by the driver.
dwMaxOverlays
Specifies the maximum number of overlays.
dwCurrOverlays
Specifies the current number of overlays.
dwMonitorFrequency
Specifies the monitor frequency in the current mode.
ddHELCaps
Specifies a DDCORECAPS structure (defined in the DirectDraw SDK documentation) that contains the HEL capabilities.
dwUnused2
Is not currently used.
ddckCKDestOverlay
Is a DDCORECAPS structure used to hold the color key for destination overlay use.
ddckCKSrcOverlay
Is a DDCORECAPS structure (defined in the DirectDraw SDK documentation) used to hold the color key for source overlay use.
vmiData
Specifies a VIDEOMEMORYINFO structure that contains information about display memory.
lpDriverHandle
Is a handle for use by the display driver to call functions in ddraw16.dll.
lpExclusiveOwner
Is used by DirectDraw and should not be filled in by the driver.
dwModeIndex
Contains the current mode index.
dwModeIndexOrig
Contains the original mode index.
dwNumFourCC
Specifies the number of FourCC codes supported.
lpdwFourCC
Is used by DirectDraw and should not be filled in by the driver.
dwNumModes
Specifies the number of modes supported.
lpModeInfo
Is used by DirectDraw and should not be filled in by the driver.
plProcessList
Is used by DirectDraw and should not be filled in by the driver.
dwSurfaceLockCount
Specifies the total number of outstanding locks.
dwAliasedLockCnt
Is used by DirectDraw and should not be filled in by the driver.
dwReserved3
Is reserved for use by the display driver.
hDD
Is used by DirectDraw and should not be filled in by the driver.
cObsolete
Is an obsolete member and should not be used.
dwReserved1
Is reserved for use by the display driver.
dwReserved2
Is reserved for use by the display driver.
dbnOverlayRoot
Specifies the root node of the doubly-linked list of overlay z orders.
lpwPDeviceFlags
Points to a memory location containing a set of driver physical device flags.
dwPDevice
Points to the driver's physical device. This member is a 16:16 pointer.
dwWin16LockCnt
Specifies the count of Win16Lock holds.
dwUnused3
Is currently unused.
hInstance
Is the handle to the driver instance.
dwEvent16
Specifies an event used by the 16-bit side of the driver to tell the 32-bit side that a mode change has occurred.
dwSaveNumModes
Specifies the number of modes supported.
lpD3DGlobalDriverData
Points to global Direct3D data.
lpD3DHALCallbacks
Points to the start of a block of memory containing a list of Direct3D HAL callbacks.
ddBothCaps
Specifies a DDCORECAPS structure (defined in the DirectDraw SDK documentation) containing the logical AND of the driver and the HEL capabilities.
lpDDVideoPortCaps
Points to a DDVIDEOPORTCAPS structure containing the information returned by the HAL. This will be an array of these structures if more than one video port is in existence.
dvpList
Is used by DirectDraw and should not be filled in by the driver.
lpD3DHALCallbacks2
Points to a block of memory containing post-DirectX 3.0 HAL callbacks.
rectDevice
Specifies a rectangle, in desktop coordinates, for the device.
cMonitors
Specifies the number of monitors in the system.
gpbmiSrc
Is used by DirectDraw and should not be filled in by the driver.
gpbmiDest
Is used by DirectDraw and should not be filled in by the driver.
phaiHeapAliases
Is used by DirectDraw and should not be filled in by the driver.
hKernelHandle
This member is used by DirectDraw and should not be filled in by the driver.
pfnNotifyProc
Points to a notification process registered with the VDD. This member is used by DirectDraw and should not be filled in by the driver.
lpDDKernelCaps
Points to a DDKERNELCAPS structure that contains the capabilities of the kernel mode interface.
lpddNLVCaps
Points to a DD_NONLOCALVIDMEMCAPS structure that contains the hardware non-local to local display memory capabilities.
lpddNLVHELCaps
Points to a DD_NONLOCALVIDMEMCAPS structure that contains the emulation layer non-local to local display memory capabilities.
lpddNLVBothCaps
Points to a DD_NONLOCALVIDMEMCAPS structure that contains the logical AND of hardware and emulation non-local to local display memory capabilities.
lpD3DExtendedCaps
Points to the start of a block of memory containing a set of extended capabilities for Direct3D.
dwDOSBoxEvent
Is an event set when return from a DOS box.
rectDesktop
Specifies the rectangle in which the desktop lies.
cDriverName
Specifies the display name.
lpD3DHALCallbacks3
Points to the start of a block of memory containing DirectX 6.0 callbacks.
dwNumZPixelFormats
Specifies the number of z-buffer and stencil pixel formats.
lpZPixelFormats
Points to an array of z-buffer pixel formats.
mcList
Is used by DirectDraw and should not be filled in by the driver.
hDDVxd
Is a handle to ddraw.vxd.
ddsCapsMore
Is a DDSCAPSEX structure as queried by the GUID_DDMoreSurfaceCaps GUID.

Comments

The DDRAWI_DIRECTDRAW_GBL structure is similar in purpose to the Windows 2000 and later structure, DD_DIRECTDRAW_GLOBAL.


DDRAWI_DIRECTDRAW_LCL

DDRAWI_DIRECTDRAW_LCL contains local data for each individual DirectDraw object.

typedef struct _DDRAWI_DIRECTDRAW_LCL {
  DWORD  lpDDMore;
  LPDDRAWI_DIRECTDRAW_GBL  lpGbl;
  DWORD  dwUnused0;
  DWORD  dwLocalFlags;
  DWORD  dwLocalRefCnt;
  DWORD  dwProcessId;
  IUnknown FAR  *pUnkOuter;
  DWORD  dwObsolete1;
  ULONG_PTR  hWnd;
  ULONG_PTR  hDC;
  DWORD  dwErrorMode;
  LPDDRAWI_DDRAWSURFACE_INT  lpPrimary;
  LPDDRAWI_DDRAWSURFACE_INT  lpCB;
  DWORD   dwPreferredMode;
  //------- Fields added in Version 2.0 -------
  HINSTANCE  hD3DInstance;
  IUnknown FAR  *pD3DIUnknown;
  LPDDHAL_CALLBACKS  lpDDCB;
  ULONG_PTR  hDDVxd;
  //------- Fields added in Version 5.0 -------
  DWORD   dwAppHackFlags;
  //------- Fields added in Version 5.A -------
  ULONG_PTR    hFocusWnd;
  DWORD   dwHotTracking;
  DWORD   dwIMEState;
  //------- Fields added in Version 6.0 -------
  ULONG_PTR  hWndPopup;
  ULONG_PTR  hDD;
  ULONG_PTR  hGammaCalibrator;
  LPDDGAMMACALIBRATORPROC  lpGammaCalibrator;
} DDRAWI_DIRECTDRAW_LCL;

Members

lpDDMore
Points to additional local data.
lpGbl
Points to a DDRAWI_DIRECTDRAW_GBL structure that contains the DirectDraw global data.
dwUnused0
Is not currently used.
dwLocalFlags
Is a set of local flags.
Flag | Meaning
DDRAWILCL_ACTIVENO
DDRAWILCL_ACTIVEYES
DDRAWILCL_ALLOWMODEX | Mode X is supported.
DDRAWILCL_ATTEMPTEDD3DCONTEXT | This flag is for the use of DirectDraw only, and should not be set by the driver.
DDRAWILCL_CREATEDWINDOW
DDRAWILCL_CURSORCLIPPED
DDRAWILCL_DIRECTDRAW7
DDRAWILCL_DIRTYDC | Set on ChangeDisplaySettings, cleared when device DC is reinitialized.
DDRAWILCL_DISABLEINACTIVATE
DDRAWILCL_EXPLICITMONITOR | The device was chosen explicitly; that is,. not by a call to DirectDrawCreate(NULL).
DDRAWILCL_FPUPRESERVE | Direct3D needs to switch to single precision/exceptions disabled each time.
DDRAWILCL_FPUSETUP | Direct3D does not need to switch to single precision/exceptions disabled each time.
DDRAWILCL_HASEXCLUSIVEMODE
DDRAWILCL_HOOKEDHWND
DDRAWILCL_ISFULLSCREEN
DDRAWILCL_MODEHASBEENCHANGED
DDRAWILCL_MULTITHREADED | The application indicates that it must be multithreaded.
DDRAWILCL_POWEREDDOWN | This flag is for the use of DirectDraw only, and should not be set by the driver.
DDRAWILCL_SETCOOPCALLED
DDRAWILCL_V1SCLBEHAVIOUR

dwLocalRefCnt
Specifies the local reference count.
dwProcessId
Specifies the ID of the owning process.
pUnkOuter
Points to the outer IUnknown.
dwObsolete1
Is obsolete and should not be used.
hWnd
hDC
Is a handle to the device context.
dwErrorMode
lpPrimary
lpCB
dwPreferredMode
hD3DInstance
Is a handle to Direct3D's DLL.
pD3DIUnknown
Points to Direct3D's aggregated IUnknown.
lpDDCB
Points to a DDHAL_CALLBACKS structure containing pointers to HAL callbacks.
hDDVxd
Is a handle to ddraw.vxd.
dwAppHackFlags
Is a set of application compatibilty flags.
hFocusWnd
Is a handle to the focus window set by SetCoopLevel.
dwHotTracking
Specifies the reactive menu (and other user interface elements) setting cached while the application was fullscreen.
dwIMEState
Specifies the IME toolbar setting.
hWndPopup
Is a handle to a popup window.
hDD
Is used by DirectDraw and should not be filled in by the driver.
hGammaCalibrator
Is used by DirectDraw and should not be filled in by the driver.
lpGammaCalibrator
Is used by DirectDraw and should not be filled in by the driver.

Comments

The DDRAWI_DIRECTDRAW_LCL structure is similar in purpose to the Windows 2000 and later structure, DD_DIRECTDRAW_LOCAL.


Direct3D Driver Functions

This section provides reference pages for the callback functions and their associated structures in the Windows® Direct3D® driver interface. All callback names are pseudonames to be decided upon by the display driver writer.

Direct3D DDI Header Files, Sample Code, and References lists the include file that contains Direct3D function prototypes.

For general Direct3D data structure definitions, see Direct3D Driver Structures. Additional information for writing a Direct3D driver can be found in Direct3D DDI.

The end of this reference contains the D3DBuffer Callbacks that are used only in drivers that manage their own command and vertex buffers.


D3dContextCreate

D3dContextCreate creates a context.

DWORD
  (*APIENTRY *LPD3DHAL_CONTEXTCREATECB)(
    LPD3DHAL_CONTEXTCREATEDATA  pccd
    );

Parameters

pccd
Points to a D3DHAL_CONTEXTCREATEDATA structure that contains the information required to create a context and the data that the driver should store in the new context.

Return Value

D3dContextCreate returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Comments

D3dContextCreate must be implemented in drivers that support Direct3D. It should perform the following steps:

  • Initialize the driver's context with all information required by the driver to perform rendering. This includes associating the rendering target and depth buffer that lpDDS and lpDDSZ point to, respectively, with the context.
  • Generate a unique context ID for this new context and return it in dwhContext. Direct3D will use this context ID in every subsequent callback it makes to this Direct3D device. The driver must never create a context handle of zero.
  • Set ddrval to DD_OK upon success, and to D3DHAL_OUTOFCONTEXTS if it cannot create the context.
  • Return DDHAL_DRIVER_HANDLED upon return.

State is not shared between contexts; therefore, the driver must maintain full state information for each context. This state will be changed by any subsequent calls to D3dDrawPrimitives2.

The driver must be able to reference all texture handles that are created within the created context. This is so that the driver can clean up all driver-specific data related to textures created within this context when a D3dContextDestroy call is made.

D3DHAL_CONTEXTCREATEDATA

The D3DHAL_CONTEXTCREATEDATA structure contains all of the information that D3dContextCreate needs to create a new context.

typedef struct _D3DHAL_CONTEXTCREATEDATA {
  PDD_DIRECTDRAW_LOCAL  lpDDLcl;
  PDD_SURFACE_LOCAL  lpDDSLcl;
  PDD_SURFACE_LOCAL  lpDDSZLcl;
  DWORD  dwPID;
  ULONG_PTR  dwhContext;
  HRESULT  ddrval;
} D3DHAL_CONTEXTCREATEDATA, *LPD3DHAL_CONTEXTCREATEDATA;

Members

lpDDLcl
Points to the DirectDraw object that an application must create in order to retrieve the COM Interface to Direct3D. This allows context information to be shared between a DirectDraw application and the driver. lpDDLcl is the common and binding factor between the application's context and the driver's context. It points to a DD_DIRECTDRAW_LOCAL structure that is used to identify the surfaces that belong to a given Direct3D context and is relevant to the current DirectDraw process only. lpDDLcl is necessary because surfaces (for example, depth buffers, rendering buffers, and textures) can be created before a Direct3D context is ever created in the driver.
lpDDSLcl
Points to a DD_SURFACE_LOCAL structure that describes the DirectDraw surface to be used as the rendering target.
lpDDSZLcl
Points to a DD_SURFACE_LOCAL structure that describes the DirectDraw surface to be used as a depth buffer. If this member is NULL, no depth buffering is to be performed.
dwPID
Specifies the current process ID. This is the process ID of the Direct3D application that initiated the creation of the Direct3D device.
dwhContext
Specifies the location where the driver returns the context handle upon successfully creating the context. The driver should return a unique context ID for Direct3D to use when communicating with the driver.
ddrval
Specifies the location where the driver writes the return value of D3dContextCreate. A return code of DD_OK indicates success.

See Also

D3dContextDestroy, D3dDrawPrimitives2.


D3dContextDestroy

D3dContextDestroy deletes the specified context.

DWORD
  (APIENTRY *LPD3DHAL_CONTEXTDESTROYCB)(
    LPD3DHAL_CONTEXTDESTROYDATA  pcdd
    );

Parameters

pcdd
Points to a D3DHAL_CONTEXTDESTROYDATA structure that contains the information required for the driver to destroy the context.

Return Value

D3dContextDestroy returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Comments

All Direct3D drivers must support D3dContextDestroy.

The driver should free all resources it allocated to the context being deleted. For example, the driver should free any texture resources it associated with the context. The driver should not free the DirectDraw surface(s) associated with the context because these will be freed by DirectDraw in response to an application or Direct3D runtime request.

D3DHAL_CONTEXTDESTROYDATA

The D3DHAL_CONTEXTDESTROYDATA structure contains the information that D3dContextDestroy needs to delete a context.

typedef struct _D3DHAL_CONTEXTDESTROYDATA {
  ULONG_PTR  dwhContext;
  HRESULT  ddrval;
} D3DHAL_CONTEXTDESTROYDATA, *LPD3DHAL_CONTEXTDESTROYDATA;

Members

dwhContext
Specifies the handle to the context to be destroyed.
ddrval
Specifies the location where the driver writes the return value of D3dContextDestroy. DD_OK indicates success.

See Also

D3dContextCreate


D3dCreateSurfaceEx

D3dCreateSurfaceEx creates a Direct3D surface from a DirectDraw surface and associates a requested handle value to it.

DWORD
  (APIENTRY *PDD_CREATESURFACEEX)(
    PDD_CREATESURFACEEXDATA  pcsxd
    );

Parameters

pcsxd
Points to a DD_CREATESURFACEEXDATA structure that contains the information required for the driver to create the surface (described below).

Return Value

D3dCreateSurfaceEx returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint. Include winddi.h.

Comments

All Direct3D drivers must support D3dCreateSurfaceEx.

D3dCreateSurfaceEx creates an association between a DirectDraw surface and a small integer surface handle. By creating these associations between a handle and a DirectDraw surface, D3dCreateSurfaceEx allows a surface handle to be embedded in the Direct3D command stream. For example, when the D3DDP2OP_TEXBLT command token is sent to D3dDrawPrimitives2 to load a texture map, it uses a source handle and destination handle that were associated with a DirectDraw surface through D3dCreateSurfaceEx.

For every DirectDraw surface created under the local DirectDraw object, the runtime generates a valid handle that uniquely identifies the surface and places it in pcsxd->lpDDSLcl->lpSurfMore->dwSurfaceHandle. (See the DD_SURFACE_MORE structure for more information about its dwSurfaceHandle member.) This handle value is also used with the D3DRENDERSTATE_TEXTUREHANDLE render state to enable texturing, and with the D3DDP2OP_SETRENDERTARGET and D3DDP2OP_CLEAR commands to set and clear new rendering and depth buffers. The driver should fail the call and return DDHAL_DRIVER_HANDLED if it cannot create the Direct3D surface.

Upon the destruction of a system memory surface with a dwSurfaceHandle, the driver will be notified by a D3dCreateSurfaceEx callback. The fpVidMem pointer (a member of the DD_SURFACE_GLOBAL structure) for the system memory surface is cleared to zero. The driver should then invalidate and free any driver-private data associated to this system memory surface. It is common for a video memory surface to have fpVidMem set to zero, so drivers must check memory type before applying this special destruction notification. Upon destruction of video memory surface, however, there is no additional D3dCreateSurfaceEx callback notification because drivers always get a DdDestroySurface callback for video memory surface.

The driver should also store any surface-related information that it subsequently will need when using the surface. The driver must create a new surface table for each new lpDDLcl and implicitly enlarge the table when necessary to accommodate more surfaces. Typically this is done with an exponential growth algorithm so that you do not have to enlarge the table too often. See the perm3 sample driver that ships with the DDK for implementation details.

Direct3D calls D3dCreateSurfaceEx after the surface is created by DirectDraw by request of the Direct3D runtime or the application.

DD_CREATESURFACEEXDATA

The DD_CREATESURFACEEXDATA structure contains information required for the driver to create a surface and associate with it a supplied texture handle.

typedef struct _DD_CREATESURFACEEXDATA {
  DWORD  dwFlags;
  PDD_DIRECTDRAW_LOCAL  lpDDLcl;
  PDD_SURFACE_LOCAL  lpDDSLcl;
  HRESULT  ddRVal;
} DD_CREATESURFACEEXDATA;

Members

dwFlags
Is a set of flags for D3dCreateSurfaceEx that are currently not used and always zero.
lpDDLcl
Is a handle to the DirectDraw object created by the application. This is the scope within which the lpDDSLcl handles exist. A DD_DIRECTDRAW_LOCAL structure describes the driver.
lpDDSLcl
Is a handle to the DirectDraw surface to be created for Direct3D. These handles are unique within each different DD_DIRECTDRAW_LOCAL structure. A DD_SURFACE_LOCAL structure represents the created surface object.
ddRVal
Specifies the location where the driver writes the return value of the D3dCreateSurfaceEx callback. A return code of DD_OK indicates success.

See Also

D3dDestroyDDLocal

Sample implementation of D3dCreateSurfaceEx

LPDDRAWI_DDRAWSURFACE_LCL GetAttachedSurface(
    LPDDRAWI_DDRAWSURFACE_LCL pLcl,
    DDSCAPS2 * pddsCaps2)
{
    LPATTACHLIST pAl;

    pAl = pLcl->lpAttachList;

    while (pAl)
    {
        LPDDRAWI_DDRAWSURFACE_LCL pLclAttached = pAl->lpAttached;
        LPATTACHLIST pAlAttached = pLclAttached->lpAttachList;

        if ((pLclAttached->lpSurfMore->ddsCapsEx.dwCaps2 & pddsCaps2->dwCaps2) ||
            (pLclAttached->lpSurfMore->ddsCapsEx.dwCaps3 & pddsCaps2->dwCaps3) ||
            (pLclAttached->lpSurfMore->ddsCapsEx.dwCaps4 & pddsCaps2->dwCaps4) ||
            (pLclAttached->ddsCaps.dwCaps & pddsCaps2->dwCaps)
            )
        {
            return pLclAttached;
        }
        pAl = pAl->lpLink;
    }
    return NULL;
}

void CSExProcessPossibleMipmap(LPDDRAWI_DDRAWSURFACE_LCL pLcl)
{
    //
    // A more likely scenario would be to build a list of surfaces
    // so that the driver can create one structure that represents the
    // entire mipmap, rather than creating an object to represent each
    // level as depicted here.
    //
    DDSCAPS2 ddsCaps2 = {0,DDSCAPS2_MIPMAPSUBLEVEL,0,0};
    while (pLcl)
    {
        //Call the private driver routine that creates a driver-side surface structure
        CreateMyRepresentation(pLcl);

        pLcl = GetAttachedSurface(pLcl,&ddsCaps2);
    }
}

//
// The actual return type should reflect the fact that the only
// way this routine should fail is with DDERR_OUTOFMEMORY
//
void MyCreateSurfaceExHelper(LPDDRAWI_DDRAWSURFACE_LCL pLcl)
{
    LPATTACHLIST pAl;
    DDSCAPS2 ddsCaps2 = {0,0,0,0};
    LPDDRAWI_DDRAWSURFACE_LCL pLclAttached;
    LPDDRAWI_DDRAWSURFACE_LCL pLclStart;

    if (pLcl->lpGbl->fpVidMem == 0)
    {
        //A required check against bad surfaces
        if (pLcl->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY)
            return;

        //Else, this is a system memory surface, so we are being informed of
        // its destruction
        DestroyMyRepresentation(pLcl->lpSurfMore->dwSurfaceHandle);
        return;
    }

    CSExProcessPossibleMipmap(pLcl);

    if (pLcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_CUBEMAP)
    {
        int i;
        //
        // The root surface is always positive X, so we check for the
        // other five face types.
        //
        DWORD dw[5] = {
            DDSCAPS2_CUBEMAP_NEGATIVEX,
            DDSCAPS2_CUBEMAP_POSITIVEY,
            DDSCAPS2_CUBEMAP_NEGATIVEY,
            DDSCAPS2_CUBEMAP_POSITIVEZ,
            DDSCAPS2_CUBEMAP_NEGATIVEZ};

        for(i=0;i< sizeof(dw)/sizeof(dw[0]);i++)
        {
            ddsCaps2.dwCaps2 = dw[i];
            pLclAttached = GetAttachedSurface(pLcl, &ddsCaps2);
            if (pLclAttached)
                CSExProcessPossibleMipmap(pLclAttached);
        }

        //
        // Once we know it's a cube map, we know there can't be any other
        // attachments.
        //
        return;
    }

    //
    // At this point:
    //      If it's a cubemap, we returned above.
    //      If it's a mipmap, we handled all cases above.
    // The only other complex surface possibility is a primary flipping chain.
    // Since a primary flipping chain cannot be mipmapped, we will simply return
    // here if this surface is a mipmap.
    //

    if (pLcl->ddsCaps.dwCaps & DDSCAPS_MIPMAP)
        return;

    //
    // The only system memory surfaces we'll ever be interested in are textures (mipmaps)
    // and cube maps. Any other kind of system memory surface is not interesting to
    // us, and we return here. WE DO NOT PROPAGATE AN ERROR CODE FOR SYSTEM MEMORY
    // SURFACES WHOSE FORMAT WE DO NOT UNDERSTAND. This could cause an error code to
    // be propagated to the application when it was trying to use system memory surfaces
    // of a format we don't understand, but is valid for the reference rasterizer, for example.
    //

    if (pLcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
        return;

    //
    // Now walk around a flipping chain. A flipping chain is a ring of
    // surface attached to each other (each surface is attached to the next
    // and to the previous surface in the ring, but not to any other surface
    // in the ring).
    // We need to watch out for this circular ring and make sure we exit appropriately.
    // There is also the possibility of a z buffer attached to one of the surfaces
    // in the ring, which may or may not have been CreateSurfaceEx'ed already.
    //

    pLclStart = pLcl;

    while (pLcl && pLcl != pLclStart)
    {
        //Check for Z buffer attached to this surface in the ring.
        ddsCaps2.dwCaps = DDSCAPS_ZBUFFER;
        ddsCaps2.dwCaps2 = 0;
        pLclAttached = GetAttachedSurface(pLcl, &ddsCaps2);
        if (pLclAttached)
            CreateMyRepresentation(pLclAttached);

        //Check for stereo left surface attached to this surface in the ring
        ddsCaps2.dwCaps = 0;
        ddsCaps2.dwCaps2 = DDSCAPS2_STEREOSURFACELEFT;
        pLclAttached = GetAttachedSurface(pLcl, &ddsCaps2);
        if (pLclAttached)
            CreateMyRepresentation(pLclAttached);

        // Move to next surface in the primary flipping ring. The next surface is
        // definitely in video memory (all surfaces in an attachment structure have
        // to be in the same memory type, and we excluded system memory above).
        // The next surface in the ring is thus the attached video memory surface
        // that is NOT a z buffer NOR a stereo left surface.

        ddsCaps2.dwCaps = DDSCAPS_VIDEOMEMORY;
        ddsCaps2.dwCaps2 = 0;
        do
        {
            pLclAttached = GetAttachedSurface(pLcl, &ddsCaps2);
        }
        while (
            pLclAttached->ddsCaps.dwCaps & DDSCAPS_ZBUFFER ||
            pLclAttached->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_STEREOSURFACELEFT
            );

        pLcl = pLclAttached;

        if (pLcl != pLclStart)
            CreateMyRepresentation(pLcl);
    }
}


D3dDestroyDDLocal

D3dDestroyDDLocal destroys all the Direct3D surfaces previously created by D3DCreateSurfaceEx that belong to the same given local DirectDraw object.

DWORD
  (APIENTRY *PDD_DESTROYDDLOCAL)(
    PDD_DESTROYDDLOCALDATA  pcdddd
    );

Parameters

pcdddd
Points to a DDHAL_DESTROYDDLOCALDATA structure that contains the information required for the driver to destroy the surfaces.

Return Value

D3dDestroyDDLocal returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

All Direct3D drivers must support D3dDestroyDDLocal.

Direct3D calls D3dDestroyDDLocal when the application indicates that the Direct3D context is no longer required and it will be destroyed along with all surfaces associated to it. The association comes through the pointer to the local DirectDraw object. The driver must free any memory that the driver's D3dCreateSurfaceEx callback allocated for each surface, if necessary.

The driver should not destroy the DirectDraw surfaces associated with these Direct3D surfaces. This is the application's responsibility.

DDHAL_DESTROYDDLOCALDATA

DDHAL_DESTROYDDLOCALDATA contains the information required for the driver to destroy a set of surfaces associated to a given local DirectDraw object.

typedef struct _DDHAL_DESTROYDDLOCALDATA {
  DWORD  dwFlags;
  PDD_DIRECTDRAW_LOCAL  pDDLcl;
  HRESULT  ddrval;
} DDHAL_DESTROYDDLOCALDATA, *LPDDHAL_DESTROYDDLOCALDATA;

Members

dwFlags
Currently unused.
pDDLcl
Points to the local Direct Draw object that serves as a reference for all Direct3D surfaces that have to be destroyed.
ddrval
Specifies the location where the driver writes the return value of D3dDestroyDDLocal. A return code of DD_OK indicates success.

See Also

D3dCreateSurfaceEx


D3dDrawPrimitives2

D3dDrawPrimitives2 renders primitives and returns the updated render state.

DWORD
  (APIENTRY *LPD3DHAL_DRAWPRIMITIVES2CB)(
    LPD3DHAL_DRAWPRIMITIVES2DATA  pdp
    );

Parameters

pdp
Points to a D3DHAL_DRAWPRIMITIVES2DATA structure that contains the information required for the driver to render one or more primitives.

Return Value

D3dDrawPrimitives2 returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Comments

D3dDrawPrimitives2 must be implemented in Direct3D drivers.

The driver must do the following:

  • Ensure that the context handle specified by the dwhContext member of the D3DHAL_DRAWPRIMITIVES2DATA structure is valid.
  • Check that a flip to the drawing surface associated with the context is not in progress. If the drawing surface is involved in a flip, the driver should set the ddrval member of the following structure to DDERR_WASSTILLDRAWING and return DDHAL_DRIVER_HANDLED.
  • Determine the location where the first D3DHAL_DP2COMMAND structure is found by adding dwCommandOffset bytes to the command buffer that lpDDCommands points to. dwCommandOffset and lpDDCommands are members of the D3DHAL_DRAWPRIMITIVES2DATA structure.
  • Determine the location in the vertex buffer where the first vertex is found. This should only be done if there is data in the vertex buffer; that is, when a D3DDP2OP_Xxx command token is received (except when the token is D3DDP2OP_LINELIST_IMM or D3DDP2OP_TRIANGLEFAN_IMM). These two opcodes indicate that the vertex data is passed immediately in the command stream, rather than in a vertex buffer. So, assuming there is data in the vertex buffer, if the vertex buffer is in user memory, the first vertex is dwVertexOffset bytes into the buffer that lpVertices points to. Otherwise, the driver should apply dwVertexOffset to the memory associated with the DD_SURFACE_LOCAL structure to which lpDDVertex points. dwVertexOffset, lpVertices, and lpDDVertex are members of the following structure.
  • Check the dwVertexType member of the D3DHAL_DRAWPRIMITIVES2DATA structure to ensure that the driver supports the requested FVF. The driver should fail the call if any of the following conditions exist:
    • Vertex coordinates are not specified; that is, if D3DFVF_XYZRHW is not set.
    • Normals are specified; that is, if D3DFVF_NORMAL is set.
    • Any of the reserved D3DFVF_RESERVEDx bits are set.
  • Process all of the commands in the command buffer sequentially. For each D3DHAL_DP2COMMAND structure, the driver should do the following:
    • If the command is D3DDP2OP_RENDERSTATE, process the wStateCount D3DHAL_DP2RENDERSTATE structures that follow in the command buffer, updating the driver state for each render state structure. When the D3DHALDP2_EXECUTEBUFFER flag is set, the driver should also reflect the state change in the array that lpdwRStates points to. wStateCount and lpdwRStates are members of the D3DHAL_DRAWPRIMITIVES2DATA structure.
    • If the command is D3DDP2OP_TEXTURESTAGESTATE, process the wStateCount D3DHAL_DP2TEXTURESTAGESTATE structures that follow in the command buffer, updating the driver's texture state associated with the specified texture stage for each texture state structure.
    • If the command is D3DDP2OP_VIEWPORTINFO, process the D3DHAL_DP2VIEWPORTINFO structure that follows in the command buffer, updating the viewport information stored in the driver's internal rendering context.
    • If the command is D3DDP2OP_WINFO, process the D3DHAL_DP2WINFO structure that follows in the command buffer, updating the w-buffering information stored in the driver's internal rendering context.
    • Otherwise, process the D3DHAL_DP2Xxx primitive structures that follow the D3DDP2OP_Xxx primitive rendering command in the command buffer.
    • If the command is unknown, call the runtime's D3dParseUnknownCommand callback. The runtime provides this callback to the driver's DdGetDriverInfo callback with the GUID_D3DParseUnknownCommandCallback GUID.

The driver does not need to probe for readability the memory where the command and vertex buffers are stored. However, the driver must stay within the bounds specified by the dwCommandLength and dwVertexLength members of the D3DHAL_DRAWPRIMITIVES2DATA structure.

If the driver must fail D3dDrawPrimitives2, it should fill in the dwErrorOffset member of the D3DHAL_DRAWPRIMITIVES2DATA structure with the offset into the command buffer where the first unhandled D3DHAL_DP2COMMAND can be found.

If a DirectX 8.0 or later interface on the runtime is being used, there is no concept of current vertex buffer. Never stall upon D3dDrawPrimitives2. Otherwise, if the current vertex buffer (passed in via lpDDVertex) has only DDSCAPS_EXECUTEBUFFER set, never stall at the end of D3dDrawPrimitives2.

Note Although this is how it is supposed to work, due to a bug, it doesn't. The end-result is that if the driver doesn't always stall on vertex buffers with only DDSCAPS_EXECUTEBUFFER set (known as implicit vertex buffers), there might be some synchronization issues and resulting corruption. The workaround is to stall when transitioning between rendering user-memory primitives (identified by D3DHALDP2_USERMEMVERTICES) and rendering from an implicit vertex buffer only when D3DHALDP2_SWAPVERTEXBUFFER is not set. Here is an example of when D3dDrawPrimitives2 should stall on an implicit vertex buffer:

DrawPrimitives2(p*, D3DHALDP2_USERMEMVERTICES); // Don't stall
DrawPrimitives2(Implicit VB, 0); // STALL due to D3D bug

And here is an example of when D3dDrawPrimitives2 should not stall on an implicit vertex buffer:

DrawPrimitives2(p*, D3DHALDP2_USERMEMVERTICES); // Don't stall
DrawPrimitives2(Explicit VB, 0); // Don't stall if not locked
DrawPrimitives2(Explicit VB, D3DHALDP2_SWAPVERTEXBUFFER); // Don't stall whether or not locked
DrawPrimitives2(Implicit VB, 0); // Don't stall whether or not locked
DrawPrimitives2(Implicit VB, 0); // Don't stall whether or not locked
DrawPrimitives2(p*, D3DHALDP2_USERMEMVERTICES); // Don't stall
DrawPrimitives2(Implicit VB, D3DHALDP2_SWAPVERTEXBUFFER); // Don't stall because D3DHALDP2_SWAPVERTEXBUFFER is set

Please turn off these workarounds when the driver detects a DirectX 8.1 or later runtime.

If the current vertex buffer (passed in via lpDDVertex) has DDSCAPS_EXECUTEBUFFER and DDSCAPS2_VERTEXBUFFER set and there is an outstanding lock on the vertex buffer, stall at the end of D3dDrawPrimitives2 if you are not renaming (via D3DHALDP2_SWAPVERTEXBUFFER). If you rename, then there is no need to stall.

Note Although this is how it is supposed to work, due to a bug, it doesn't. The end-result is that the driver is called to render from a locked explicit vertex buffer more often then really necessary. Since the explicit vertex buffer is locked, the D3dDrawPrimitives2 call would stall and would hurt performance. However, there is a workaround that can reduce this problem in the most common slowdown case. It turns out that if D3DHALDP2_REQCOMMANDBUFSIZE is also set, then there is no need to stall. Note that D3DHALDP2_REQCOMMANDBUFSIZE has itself nothing to do with this issue or the D3D bug. But it so happens that the bug inducing code path in D3D also sets D3DHALDP2_REQCOMMANDBUFSIZE and hence it becomes a way for the driver to detect (and workaround) this case. Here is an example of when D3dDrawPrimitives2 should stall on an explicit vertex buffer:

DrawPrimitives2(Explicit VB, 0); // STALL when locked (will happen rarely)

And here is an example of when D3dDrawPrimitives2 should not stall on an explicit vertex buffer:

DrawPrimitives2(Explicit VB, D3DHALDP2_REQCOMMANDBUFSIZE); // Don't stall whether or not locked
DrawPrimitives2(Explicit VB, D3DHALDP2_SWAPVERTEXBUFFER); // Don't stall whether or not locked
DrawPrimitives2(Explicit VB, D3DHALDP2_SWAPVERTEXBUFFER | D3DHALDP2_REQCOMMANDBUFSIZE); // Don't stall

Please turn off these workarounds when the driver detects a DirectX 8.1 or later runtime.

D3DHAL_DRAWPRIMITIVES2DATA

The D3DHAL_DRAWPRIMITIVES2DATA structure contains the information required by D3dDrawPrimitives2 to render primitives.

typedef struct _D3DHAL_DRAWPRIMITIVES2DATA {
    ULONG_PTR         dwhContext;
    DWORD             dwFlags;
    DWORD             dwVertexType;
    PDD_SURFACE_LOCAL lpDDCommands;
    DWORD             dwCommandOffset;
    DWORD             dwCommandLength;
    union
    {
        PDD_SURFACE_LOCAL lpDDVertex;
        LPVOID            lpVertices;
    };
    DWORD             dwVertexOffset;
    DWORD             dwVertexLength;
    DWORD             dwReqVertexBufSize;
    DWORD             dwReqCommandBufSize;
    LPDWORD           lpdwRStates;
    union
    {
        DWORD         dwVertexSize;
        HRESULT       ddrval;
    };
    DWORD             dwErrorOffset;
} D3DHAL_DRAWPRIMITIVES2DATA;

Members

dwhContext
Specifies the context handle of the Direct3D device.
dwFlags
Specifies flags that provide additional instructions to the driver or provide information from the driver. This member can be a bitwise OR of the following values:
Value | Meaning
D3DHALDP2_EXECUTEBUFFER | The command and vertex buffers were created in system memory. The driver should update the state array that lpdwRStates points to. This flag is set by Direct3D only.
D3DHALDP2_REQCOMMANDBUFSIZE | The driver must be able to increase the current command buffer by at least the size specified in dwReqCommandBufSize. Drivers that do not support multi-buffering of command buffers can ignore this flag. This flag is set by Direct3D only.
D3DHALDP2_REQVERTEXBUFSIZE | The driver must be able to allocate a vertex buffer of at least the size specified in dwReqVertexBufSize. Drivers that do not support multi-buffering of vertex buffers can ignore this flag. This flag is set by Direct3D only.
D3DHALDP2_SWAPCOMMANDBUFFER | The driver can swap the buffer that lpDDCommands points to with a new command buffer and return immediately, asynchronously processing the original buffer while Direct3D fills the new command buffer. Drivers that do not support multi-buffering of command buffers can ignore this flag. This flag is set by Direct3D only.
D3DHALDP2_SWAPVERTEXBUFFER | The driver can swap the buffer that lpDDVertex or lpVertices points to with a new vertex buffer and return immediately, asynchronously processing the original buffer while Direct3D fills the new vertex buffer. Drivers that do not support multi-buffering of vertex buffers can ignore this flag. This flag is set by Direct3D only.
D3DHALDP2_USERMEMVERTICES | The lpVertices member is valid so the driver should obtain the vertex data from the user-allocated memory that lpVertices points to. This flag is set by Direct3D only.
D3DHALDP2_VIDMEMCOMMANDBUF | The command buffer allocated by the driver as a swap buffer is not in system memory. This flag can be set by drivers that support multi-buffering of command buffers.
D3DHALDP2_VIDMEMVERTEXBUF | The vertex buffer allocated by the driver as a swap buffer is not in system memory. This flag can be set by drivers that support multi-buffering of vertex buffers.

dwVertexType
Identifies the FVF of the data in the vertex buffer; that is, dwVertexType specifies which per-vertex data fields are present in the vertex buffer that lpDDVertex or lpVertices points to. This member can be a bitwise OR of the values in the following table. Only one of the D3DFVF_TEXx flags will be set.
Value | Meaning
D3DFVF_DIFFUSE | Each vertex has a diffuse color.
D3DFVF_SPECULAR | Each vertex has a specular color.
D3DFVF_TEX0 | No texture coordinates are provided with the vertex data.
D3DFVF_TEX1 | Each vertex has one set of texture coordinates.
D3DFVF_TEX2 | Each vertex has two sets of texture coordinates.
D3DFVF_TEX3 | Each vertex has three sets of texture coordinates.
D3DFVF_TEX4 | Each vertex has four sets of texture coordinates.
D3DFVF_TEX5 | Each vertex has five sets of texture coordinates.
D3DFVF_TEX6 | Each vertex has six sets of texture coordinates.
D3DFVF_TEX7 | Each vertex has seven sets of texture coordinates.
D3DFVF_TEX8 | Each vertex has eight sets of texture coordinates.
D3DFVF_XYZRHW | Each vertex has x, y, z, and w coordinates. This flag is always set.

lpDDCommands
Points to the DD_SURFACE_LOCAL structure that identifies the DirectDraw surface containing the command data. The fpVidMem member of the embedded DD_SURFACE_GLOBAL structure points to the buffer that contains state change and primitive drawing commands for the driver to process. Specifically, this buffer contains one or more D3DHAL_DP2COMMAND structures, each followed by a D3DHAL_DP2Xxx structure whose exact type is identified by D3DHAL_DP2COMMAND's bCommand member.
dwCommandOffset
Specifies the number of bytes into the surface that lpDDCommands points to and where the command data starts.
dwCommandLength
Specifies the number of bytes of valid command data in the surface that lpDDCommands points to starting at dwCommandOffset.
lpDDVertex
Points to the DD_SURFACE_LOCAL structure that identifies the DirectDraw surface containing the vertex data when the D3DHALDP2_USERMEMVERTICES flag is not set in dwFlags. Forms a union with lpVertices.
lpVertices
Points to a user-mode memory block containing vertex data when the D3DHALDP2_USERMEMVERTICES flag is set in dwFlags.
dwVertexOffset
Specifies the number of bytes into the surface pointed to by lpDDVertex or lpVertices where the vertex data starts.
dwVertexLength
The number of vertices for which valid data exists in the surface pointed to by lpDDVertex (starting at dwVertexOffset). Note that dwVertexOffset is specified in bytes.
dwReqVertexBufSize
Specifies the minimum number of bytes that the driver must allocate for the swap vertex buffer. This member is valid only when the D3DHALDP2_REQVERTEXBUFSIZE flag is set. Drivers that do not support multi-buffering of vertex buffers should ignore this member.
dwReqCommandBufSize
Specifies the minimum number of bytes that the driver must increase the swap command buffer by. This member is valid only when the D3DHALDP2_REQCOMMANDBUFSIZE flag is set. Drivers that do not support multi-buffering of command buffers should ignore this member.
lpdwRStates
Points to a render state array that the driver should update when it parses render state commands from the command buffer. The driver should update this array only when the D3DHALDP2_EXECUTEBUFFER flag is set in dwFlags. The driver should use the D3DRENDERSTATETYPE enumerated types to update the appropriate element of the render state array.
dwVertexSize
Specifies the size of each vertex, in bytes. Forms a union with ddrval.
ddrval
Specifies the location where the driver writes the return value of D3dDrawPrimitives2. D3D_OK indicates success. Otherwise, the driver should return the appropriate D3DERR_Xxx error code.
Value | Meaning
D3D_OK | The operation completed successfully.
D3DERR_COMMAND_UNPARSED | The driver requires that the Direct3D run-time to parse the execute buffer.

dwErrorOffset
Specifies the location where the driver should write the offset into the surface that lpDDCommands points to where the first unhandled D3DHAL_DP2COMMAND can be found. The driver must set this value when it returns an error condition in ddrval.

See Also

D3DHAL_DP2INDEXEDLINELIST, D3DHAL_DP2INDEXEDLINESTRIP, D3DHAL_DP2INDEXEDTRIANGLEFAN, D3DHAL_DP2INDEXEDTRIANGLELIST, D3DHAL_DP2INDEXEDTRIANGLESTRIP, D3DHAL_DP2LINELIST, D3DHAL_DP2LINESTRIP, D3DHAL_DP2POINTS, D3DHAL_DP2TRIANGLEFAN, D3DHAL_DP2TRIANGLELIST, D3DHAL_DP2TRIANGLESTRIP, FVF


D3dGetDriverState

D3dGetDriverState is used by both the DirectDraw and Direct3D runtimes to obtain information from the driver about its current state.

DWORD
  (APIENTRY *PDD_GETDRIVERSTATE)(
    PDD_GETDRIVERSTATEDATA  pgdsd
    );

Parameter

pgdsd
Points to a DD_GETDRIVERSTATEDATA structure.

Return Value

D3dGetDriverState returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h and dx95type. Include winddi.h.

Comments

All Direct3D drivers must support D3dGetDriverState.

The D3dGetDriverState callback is used by both the DirectDraw and Direct3D runtimes to obtain information from the driver about its current state.

DD_GETDRIVERSTATEDATA

typedef struct _DD_GETDRIVERSTATEDATA {
    DWORD    dwFlags;
    union
    {
        PDD_DIRECTDRAW_GLOBAL  lpDD;
        DWORD_PTR              dwhContext;
    };
    LPDWORD  lpdwStates;
    DWORD    dwLength;
    HRESULT  ddRVal;
} DD_GETDRIVERSTATEDATA;

Members

dwFlags
Is a set of flags to indicate the data requested.
lpDD
Points to a DD_DIRECTDRAW_GLOBAL structure describing the device.
dwhContext
Specifies the ID of the context that information is being requested for.
lpdwStates
Points to the Direct3D driver state data to be filled in by the driver.
dwLength
Specifies the length of the state data to be filled in by the driver.
ddRVal
Specifies the return value.


D3dValidateTextureStageState

D3dValidateTextureStageState returns the number of passes where the hardware can perform the blending operations specified in the current state.

DWORD
  (APIENTRY *LPD3DHAL_VALIDATETEXTURESTAGESTATECB)(
    LPD3DHAL_VALIDATETEXTURESTAGESTATEDATA  pvtssd
    );

Parameters

pvtssd
Points to a D3DHAL_VALIDATETEXTURESTAGESTATEDATA structure that contains the information required for the driver to determine and return the number of passes required to perform the blending operations.

Return Value

D3dValidateTextureStageState returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Comments

Direct3D drivers that support texturing must implement D3dValidateTextureStageState.

The driver's implementation of this function must evaluate the current texture state for all texture stages associated with the context. If the driver's hardware can perform the specified blending operations, then the driver should return the number of passes on the state data that its hardware requires. If the hardware cannot perform the specified blending operations, then the driver should return one of the following error codes in the ddrval member of the following structure:

Error Code | Meaning
D3DERR_CONFLICTINGTEXTUREFILTER | The hardware cannot do both trilinear filtering and multitexturing at the same time.
D3DERR_TOOMANYOPERATIONS | The hardware cannot handle the specified number of operations.
D3DERR_UNSUPPORTEDALPHAARG | The hardware does not support a specified alpha argument.
D3DERR_UNSUPPORTEDALPHAOPERATION | The hardware does not support a specified alpha operation.
D3DERR_UNSUPPORTEDCOLORARG | The hardware does not support a specified color argument.
D3DERR_UNSUPPORTEDCOLOROPERATION | The hardware does not support a specified color operation.
D3DERR_UNSUPPORTEDFACTORVALUE | The hardware does not support a D3DTA_TFACTOR greater than 1.0.
D3DERR_WRONGTEXTUREFORMAT | The hardware does not support the current state in the selected texture format.

Direct3D calls D3dValidateTextureStageState in response to an application request through a call to IDirect3DDevice7::ValidateDevice. The number of passes returned by the driver is propagated back to the application, which can then decide whether it will proceed with rendering using the current state or if it must change the blending operations to render faster or to render at all. There are no limits to the number of passes that a driver can return.

A driver that returns more than one pass is responsible for properly executing the passes on all state and primitive data when rendering.

D3DHAL_VALIDATETEXTURESTAGESTATEDATA

The D3DHAL_VALIDATETEXTURESTAGESTATEDATA structure contains the information required for the driver to determine and return its ability to support multi-texturing using the current state.

typedef struct _D3DHAL_VALIDATETEXTURESTAGESTATEDATA {
  ULONG_PTR  dwhContext;
  DWORD  dwFlags;
  ULONG_PTR  dwReserved;
  DWORD  dwNumPasses;
  HRESULT  ddrval;
} D3DHAL_VALIDATETEXTURESTAGESTATEDATA, FAR *LPD3DHAL_VALIDATETEXTURESTAGESTATEDATA;

Members

dwhContext
Specifies the context ID of the Direct3D device.
dwFlags
Is currently set to zero and should be ignored by the driver.
dwReserved
Is reserved for system use and should be ignored by the driver.
dwNumPasses
Specifies the location where the driver should write the number of passes required by the hardware to perform the blending operations.
ddrval
Specifies the location where the driver writes the return value of D3dValidateTextureStageState. A return code of DD_OK indicates success.

See Also

D3dDrawPrimitives2

Requests that are likely to fail D3dValidateTextureStageState:

  • Using diffuse iterated values as ARGs, or the BLENDDIFFUSE operation is sparsely supported on current hardware. Many parts can introduce only iterated color data at the last texture operation stage.
  • Trying to specify the texture for each stage as its arg1 in preference to arg2.
  • Attempting to use diffuse or scalar values at arbitrary multitexture blending stages. For many cards, these values can be used only at the final texture blending state; for others, only at the first stage.
  • Attempting to do more in the first texture than merely replicate alpha to color channels or invert the input. For many cards, the blending units associated with the first texture are incapable of handling operations more complex than these. The samples below try to use only the second texture's blending unit, if it is possible to do so. The first unit is presumed to be in its default state in the samples.dev.SetTextureStageState( n, D3DTSS_COLORARG1, D3DTA_TEXTURE ); *
    dev.SetTextureStageState( n, D3DTSS_COLOROP, D3DTOP_SELECTARG1 ); *
  • Performing operations for the output alpha that are more intricate than, or substantially different from, the operations specified for the color channels is less likely to be supported.
  • Attempting to use D3DTA_TFACTOR and D3DTA_DIFFUSE simultaneously. Some hardware does not support this.
  • Attempting the simultaneous use of multiple textures and MIP mapped trilinear filtering. Many cards do not support these operations at the same time. If trilinear filtering has been requested for a texture involved in multitexture operations and it fails validation, turn off trilinear and try again. In this case it may be best to do multipass rendering instead.

    Syntax used in the equations describing these operations:

Expression | Meaning
TexN (N = 0, 1, 2) | Texture bound to texture stage N
Ctex | This texture's RGB
Atex | This texture's Alpha
Cin | Current color value RGB (output of previous operation)
Ain | Current color value Alpha (output of previous operation)
Cdif | DIFFUSE color value RGB
Adif | DIFFUSE color value Alpha
Cfact | FACTOR, a scalar value specified at API level RGB
Afact | FACTOR, a scalar value specified at API level Alpha


D3DBuffer Callbacks

The D3DBuffer callbacks are used only if the driver manages driver-level command and vertex buffers.

To support driver-allocated command and vertex buffers, the driver must support the callback functions reported in the DD_D3DBUFCALLBACKS structure, which is exposed through the lpD3DBufCallbacks pointer member of the DD_HALINFO structure.

Each Xxx D3DBuffer callback is analogous to the similarly named Dd Xxx Surface callback; both callbacks have the same prototypes and are called with the same input parameters. The Xxx D3DBuffer callbacks are called only when the surface in question has the DDSCAPS_EXECUTEBUFFER flag set in the surface caps. The buffer creation flags are DDSCAPS_WRITEONLY, DDSCAPS2_VERTEXBUFFER and DDSCAPS2_COMMANDBUFFER.

To determine the type of buffer being requested, the driver checks the ddsCaps member of the DD_SURFACE_LOCAL structure, which is passed to CanCreateD3DBuffer and CreateD3DBuffer. This value may be one (or neither) of the following flags:

Flag | Meaning
DDSCAPS2_COMMANDBUFFER | The driver should allocate a command buffer.
DDSCAPS2_VERTEXBUFFER | The driver should allocate an Explicit Vertex Buffer.

Note If neither flag is set, the driver should allocate an Implicit Vertex Buffer. Implicit Vertex Buffers should not be placed in video memory since they are expected to be read/write. Only Explicit Vertex Buffers with the DDSCAPS_WRITEONLY flag set can be safely placed in video memory.

The Xxx D3DBuffer callbacks are shown in the following list:

CanCreateD3DBuffer

CreateD3DBuffer

DestroyD3DBuffer

LockD3DBuffer

UnlockD3DBuffer


CanCreateD3DBuffer

CanCreateD3DBuffer determines whether the driver can create a driver-level command or vertex buffer of the specified description.

DWORD
  (APIENTRY *PDD_CANCREATED3DBUFFER)(
    PDD_CANCREATESURFACEDATA  lpCanCreateD3DBuffer
    );

Parameters

lpCanCreateD3DBuffer
Points to a DD_CANCREATESURFACEDATA structure. This structure contains the information required for the driver to determine whether a command or vertex buffer can be created.

Return Value

CanCreateD3DBuffer returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint. Include winddi.h.

Comments

This callback is used only if the driver manages driver-level command and vertex buffers.

CanCreateD3DBuffer should check the surface description that the lpDDSurfaceDesc member of the DD_CANCREATESURFACEDATA structure points to in order to determine whether the driver can support the format and capabilities of the requested buffer for the mode that the driver is currently in. The driver should return DD_OK in the ddRVal member of the same structure if it supports that type of buffer. Otherwise, it should return the DDERR_Xxx error code that best describes why it does not support the buffer.

This call has the same prototype as DdCanCreateSurface. The CanCreateD3DBuffer callback is used, however, when the surface in question has the DDSCAPS_EXECUTEBUFFER flag set in the ddsCaps member of the DD_SURFACE_LOCAL structure.

The driver determines the type of buffer being requested by checking the ddsCaps member of the DD_SURFACE_LOCAL structure for the following flags:

Flag | Meaning
DDSCAPS2_COMMANDBUFFER | The driver should allocate a command buffer.
DDSCAPS2_VERTEXBUFFER | The driver should allocate an Explicit Vertex Buffer.

Note If neither flag is set, the driver should allocate an Implicit Vertex Buffer. Implicit Vertex Buffers should not be placed in video memory since they are expected to be read/write. Only Explicit Vertex Buffers with the DDSCAPS_WRITEONLY flag set can be safely placed in video memory.

DD_CANCREATESURFACEDATA

The DD_CANCREATESURFACEDATA structure contains information necessary to indicate if a buffer can be created.

typedef struct _DD_CANCREATESURFACEDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  PDD_SURFACEDESC  lpDDSurfaceDesc;
  DWORD  bIsDifferentPixelFormat;
  HRESULT  ddRVal;
  VOID*  CanCreateSurface;
} DDHAL_CANCREATESURFACEDATA;

Members

lpDD
Points to the DD_DIRECTDRAW_GLOBAL structure representing the DirectDraw object.
lpDDSurfaceDesc
Points to a DDSURFACEDESC structure that contains a description of the buffer to be created.
bIsDifferentPixelFormat
Indicates if the pixel format of the buffer to be created differs from that of the primary surface. Since the driver is attempting to create a buffer that contains vertex data or commands, rather than pixel data, this member will always be set to FALSE.
ddRVal
Specifies the location where the driver writes the return value of the CanCreateD3DBuffer callback. A return code of DD_OK indicates success.
CanCreateSurface
Is unused on Windows 2000 and later versions.

Comments

The DirectDraw surface description pointed to by the lpDDSurfaceDesc member is actually a DDSURFACEDESC2 structure (rather than a DDSURFACEDESC structure) for DirectDraw 6.0 and later runtimes. Therefore, if you need information at CanCreateD3DBuffer time from those members that are in the DDSURFACEDESC2 structure but not in the DDSURFACEDESC structure, you can simply cast the pointer to a DDSURFACEDESC structure to a pointer to a DDSURFACEDESC2 structure prior to use. The following example shows how the value of ddsCaps (a DDSCAPS2 in the DDSURFACEDESC2 structure, but a DDSCAPS in the DDSURFACEDESC structure) can be obtained from a pointer to a DDSURFACEDESC structure.

DDSURFACEDESC2* pddsd = (DDSURFACEDESC2*)pccsd->lpDDSurfaceDesc;
DDSCAPS2 ddsCaps = pddsd->ddsCaps;

See Also

CreateD3DBuffer


CreateD3DBuffer

CreateD3DBuffer is used to create a driver-level command or vertex buffer of the specified description.

DWORD
  (APIENTRY *PDD_CREATED3DBUFFER)(
    PDD_CREATESURFACEDATA  lpCreateD3DBuffer
    );

Parameters

lpCreateD3DBuffer
Points to a DD_CREATESURFACEDATA structure that contains the information required to create the buffer.

Return Value

CreateD3DBuffer returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint. Include winddi.h.

Comments

This callback is used only if the driver manages driver-level command and vertex buffers.

If the buffer is created out of system memory instead of video memory, the runtime must be notified by updating lpSurf->lpGbl->dwGlobalFlags with DDRAWISURFGBL_SYSMEMEXECUTEBUFFER.

By default, the driver is not notified when a primary surface is created on Windows 2000 and later versions. However, if the driver supports the GUID_NTPrivateDriverCaps GUID and the DDHAL_PRIVATECAP_NOTIFYPRIMARYCREATION flag is set, then the driver will be notified.

The pitch must be returned in the lPitch member of both the DD_SURFACE_GLOBAL and DDSURFACEDESC structures. For linear memory, the driver should set dwBlockSizeX to the size, in bytes, of the memory region and set dwBlockSizeY to 1. Both are members of the DD_SURFACE_GLOBAL structure.

This call has the same prototype as DdCreateSurface. The CreateD3DBuffer callback is used instead when the surface in question has the DDSCAPS_EXECUTEBUFFER flag set in the surface caps (DD_SURFACE_LOCAL.ddsCaps). The buffer creation flags are DDSCAPS_WRITEONLY, DDSCAPS2_VERTEXBUFFER and DDSCAPS2_COMMANDBUFFER.

The driver determines the type of buffer being requested by checking the ddsCaps member of the DD_SURFACE_LOCAL structure for the following flags:

Flag | Meaning
DDSCAPS2_COMMANDBUFFER | The driver should allocate a command buffer.
DDSCAPS2_VERTEXBUFFER | The driver should allocate an Explicit Vertex Buffer.

Note If neither flag is set, the driver should allocate an Implicit Vertex Buffer. Implicit Vertex Buffers should not be placed in video memory since they are expected to be read/write. Only Explicit Vertex Buffers with the DDSCAPS_WRITEONLY flag set can be safely placed in video memory.

The driver can allocate the buffer memory itself or it can request that DirectDraw perform the memory management. If the driver performs the allocation, it must:

  • Perform the allocation and write a valid pointer to the memory in the fpVidMem member of the DD_SURFACE_GLOBAL structure.

Alternatively, the driver can request that DirectDraw allocate the buffer by returning one of the following values in fpVidMem:

Value | Meaning
DDHAL_PLEASEALLOC_BLOCKSIZE | DirectDraw should allocate the buffer memory from offscreen memory.
DDHAL_PLEASEALLOC_USERMEM | DirectDraw should allocate the buffer memory from user memory. The driver must also return the size, in bytes, of the memory region in dwUserMemSize.

DD_CREATESURFACEDATA

The DD_CREATESURFACEDATA structure contains information necessary to create a command or vertex buffer.

typedef struct _DD_CREATESURFACEDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  PDD_SURFACEDESC  lpDDSurfaceDesc;
  PDD_SURFACE_LOCAL  *lplpSList;
  DWORD  dwSCnt;
  HRESULT  ddRVal;
  VOID*  CreateSurface;
} DD_CREATESURFACEDATA;

Members

lpDD
Points to the DD_DIRECTDRAW_GLOBAL structure representing the driver.
lpDDSurfaceDesc
Points to the DDSURFACEDESC structure describing the buffer that the driver should create.
lplpSList
Points to a list of DD_SURFACE_LOCAL structures describing the surface objects created by the driver. On Windows 2000 and later versions, there is usually only one entry in this array. However, if the driver supports the Windows 98/Me-style surface creation techniques using DdGetDriverInfo with GUID_NTPrivateDriverCaps GUID, and the driver sets the DDHAL_PRIVATECAP_ATOMICSURFACECREATION flag, this member will contain a list of surfaces (usually more than one).
dwSCnt
Specifies the number of surfaces in the list that lplpSList points to. This value is usually 1 on Windows 2000 and later versions. However, if the driver support the Windows 98/Me-style surface creation techniques using DdGetDriverInfo with GUID_NTPrivateDriverCaps, this member will contain the actual number of surfaces in the list (usually more than one).
ddRVal
Specifies the location where the driver writes the return value of the CreateD3DBuffer callback. A return code of DD_OK indicates success.
CreateSurface
Is unused on Windows 2000 and later versions.


DestroyD3DBuffer

DestroyD3DBuffer is used to destroy a driver-level command or vertex buffer.

DWORD
  (APIENTRY *PDD_SURFCB_DESTROYD3DBUFFER)(
    PDD_DESTROYSURFACEDATA  lpDestroyD3DBuffer
    );

Parameters

lpDestroyD3DBuffer
Points to a DD_DESTROYSURFACEDATA structure that contains the information needed to destroy a Direct3D command or vertex buffer.

Return Value

DdDestroySurface returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint. Include winddi.h.

Comments

This callback is used only if the driver manages driver-level command and vertex buffers.

If DirectDraw performed the memory allocation at buffer creation time, DestroyD3DBuffer should return DDHAL_DRIVER_NOTHANDLED.

If the driver is performing the buffer memory management itself, DestroyD3DBuffer should free the buffer memory and perform any other cleanup, such as freeing private data stored in the dwReserved1 members of the DD_SURFACE_GLOBAL and DD_SURFACE_LOCAL structures.

This call has the same prototype as DdDestroySurface. The DestroyD3DBuffer callback is used instead when the surface in question has the DDSCAPS_EXECUTEBUFFER flag set in the surface caps (DD_SURFACE_LOCAL.ddsCaps).

DD_DESTROYSURFACEDATA

The DD_DESTROYSURFACEDATA structure contains information necessary to destroy the specified buffer.

typedef struct _DD_DESTROYSURFACEDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  PDD_SURFACE_LOCAL  lpDDSurface;
  HRESULT  ddRVal;
  VOID*  DestroySurface;
} DD_DESTROYSURFACEDATA;

Members

lpDD
Points to the DD_DIRECTDRAW_GLOBAL structure that describes the driver.
lpDDSurface
Points to the DD_SURFACE_LOCAL structure representing the buffer object to be destroyed.
ddRVal
Specifies the location where the driver writes the return value of the DestroyD3DBuffer callback. A return code of DD_OK indicates success.
DestroySurface
Is unused on Windows 2000 and later versions.


LockD3DBuffer

LockD3DBuffer is used to lock a specified area of buffer memory and to provide a valid pointer to a block of memory associated with the buffer.

DWORD
  (APIENTRY *PDD_SURFCB_LOCKD3DBUFFER)(
    PDD_LOCKDATA  lpLockD3DBuffer
    );

Parameters

lpLockD3DBuffer
Points to a DD_LOCKDATA structure that contains the information required to perform the lockdown.

Return Value

LockD3DBuffer returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint. Include winddi.h.

Comments

This callback is used only if the driver manages driver-level command and vertex buffers.

LockD3DBuffer should set the ddRVal member of DD_LOCKDATA to DDERR_WASSTILLDRAWING and return DDHAL_DRIVER_HANDLED if a blt or flip is in progress.

Unless otherwise specified by the dwFlags member of DD_LOCKDATA, the driver can return a memory pointer to the top of the buffer in the lpSurfData member of DD_LOCKDATA. If the driver must calculate its own address for the buffer, it can rely on the pointer passed in the fpProcess member of DD_LOCKDATA to be a per-process pointer to the user-mode mapping of its DirectDraw-accessible frame buffer.

A lock does not provide exclusive access to the requested memory block. That is, multiple threads can lock the same buffer at the same time. It is the application's responsibility to synchronize access to the memory block that the pointer is being obtained for.

This call has the same prototype as DdLock. The LockD3DBuffer callback is used instead when the surface in question has the DDSCAPS_EXECUTEBUFFER flag set in the surface caps (DD_SURFACE_LOCAL.ddsCaps).

If a vertex buffer is being locked and is also being rendered from by the hardware, stall the LockD3DBuffer if you are not renaming (via D3DHALDP2_SWAPVERTEXBUFFER). If you rename, then there is no need to stall.

DD_LOCKDATA

The DD_LOCKDATA structure contains information to do a lock as defined by DirectDraw's parameter structures.

typedef struct _DD_LOCKDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  PDD_SURFACE_LOCAL  lpDDSurface;
  DWORD  bHasRect;
  RECTL  rArea;
  LPVOID  lpSurfData;
  HRESULT  ddRVal;
  VOID*  Lock;
  DWORD  dwFlags;
  FLATPTR  fpProcess;
} DD_LOCKDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_GLOBAL structure that describes the driver.
lpDDSurface
Points to a DD_SURFACE_LOCAL structure that describes the surface associated with the memory region to be locked down.
bHasRect
Specifies whether the area in rArea is valid.
rArea
Specifies a RECTL structure that defines the area in the buffer to lock down.
lpSurfData
Specifies the location where the driver can return a pointer to the memory region that it locked down.
ddRVal
Specifies the location where the driver writes the return value of the LockD3DBuffer callback. A return code of DD_OK indicates success.
Lock
Is unused on Windows 2000 and later versions.
dwFlags
Specifies a bitmask that tells the driver how to perform the memory lockdown. This member is a bitwise OR of any of the following values:
Value | Meaning
DDLOCK_EVENT | This flag is reserved for system use and should be ignored by the driver.
DDLOCK_READONLY | The buffer being locked will only be read from. On Windows 2000 and later versions, this flag is never set.
DDLOCK_SURFACEMEMORYPTR | The driver should return a valid memory pointer to the top of the rectangle specified in rArea. If no rectangle is specified, the driver should return a pointer to the top of the buffer.
DDLOCK_WAIT | This flag is reserved for system use and should be ignored by the driver.
DDLOCK_WRITEONLY | The buffer being locked will only be written to. On Windows 2000 and later versions, this flag is never set.

fpProcess
Points to a user-mode mapping of the driver's memory. The driver performs this mapping in DdMapMemory.

See Also

UnlockD3DBuffer


UnlockD3DBuffer

UnLockD3DBuffer is used to release a lock held on a specified area of driver-managed buffer memory.

DWORD
  (APIENTRY *PDD_SURFCB_UNLOCKD3DBUFFER)(
    PDD_UNLOCKDATA  lpUnlockD3DBuffer
    );

Parameters

lpUnlockD3DBuffer
Points to a DD_UNLOCKDATA structure that contains the information required to perform the lock release.

Return Value

DdUnlock returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint. Include winddi.h.

Comments

This callback is used only if the driver manages driver-level command and vertex buffers.

The driver does not need to verify that the memory was previously locked down by LockD3DBuffer, because DirectDraw does parameter validation before calling this routine.

This call has the same prototype as DdUnLock. The UnLockD3DBuffer callback is used instead when the surface in question has the DDSCAPS_EXECUTEBUFFER flag set in the surface caps (DD_SURFACE_LOCAL.ddsCaps).

DD_UNLOCKDATA

The DD_UNLOCKDATA structure contains information to do an unlock as defined by DirectDraw parameter structures.

typedef struct _DD_UNLOCKDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  PDD_SURFACE_LOCAL  lpDDSurface;
  HRESULT  ddRVal;
  VOID*  Unlock;
} DD_UNLOCKDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_GLOBAL structure that describes the driver.
lpDDSurface
Points to a DD_SURFACE_LOCAL structure that describes the buffer to be unlocked.
ddRVal
Specifies the location where the driver writes the return value of the DdUnlock callback. A return code of DD_OK indicates success.
Unlock
Is unused on Windows 2000 and later versions.

See Also

LockD3DBuffer


Direct3D Driver Structures

This section describes the Direct3D® driver structures. It is divided into two main groupings: the first consists of the D3DHAL_Xxx structures defined in d3dnthal.h on Windows® 2000 and later and d3dhal.h on Windows 98/Me; the second grouping consists of the remaining structures, including device description structures, and other Direct3D structures defined in d3dcaps.h and d3dtypes.h. Direct3D DDI Header Files, Sample Code, and References lists the include files that contain Direct3D structure definitions.

Direct3D callbacks and their parameter structures are described in Direct3D Driver Functions. Additional information for writing a Direct3D driver can be found in Direct3D DDI.


D3DNTHAL_Xxx Structures

This table contains all the Direct3D driver structures whose names have the form D3DNTHAL_Xxx. These structures are identical to those whose names have the form D3DHAL_Xxx, which is the form used on Windows 98/Me for DirectX 7.0 and on both Windows 98/Me and Windows 2000 and later for DirectX 8.0 and later versions. The include file dx95type.h contains type defines from D3DNTHAL_Xxx to D3DHAL_Xxx.

D3DNTHAL_Xxx Structure | D3DHAL_Xxx Structure
D3DNTHAL_CALLBACKS | D3DHAL_CALLBACKS
D3DNTHAL_CALLBACKS3 | D3DHAL_CALLBACKS3
D3DNTHAL_CONTEXTCREATEDATA | D3DHAL_CONTEXTCREATEDATA
D3DNTHAL_CONTEXTDESTROYDATA | D3DHAL_CONTEXTDESTROYDATA
D3DNTHAL_D3DEXTENDEDCAPS | D3DHAL_D3DEXTENDEDCAPS
D3DNTHAL_DP2CLEAR | D3DHAL_DP2CLEAR
D3DNTHAL_DP2COMMAND | D3DHAL_DP2COMMAND
D3DNTHAL_DP2CREATELIGHT | D3DHAL_DP2CREATELIGHT
D3DNTHAL_DP2EXT | D3DHAL_DP2EXT
D3DNTHAL_DP2INDEXEDLINELIST | D3DHAL_DP2INDEXEDLINELIST
D3DNTHAL_DP2INDEXEDLINESTRIP | D3DHAL_DP2INDEXEDLINESTRIP
D3DNTHAL_DP2INDEXEDTRIANGLEFAN | D3DHAL_DP2INDEXEDTRIANGLEFAN
D3DNTHAL_DP2INDEXEDTRIANGLELIST | D3DHAL_DP2INDEXEDTRIANGLELIST
D3DNTHAL_DP2INDEXEDTRIANGLELIST2 | D3DHAL_DP2INDEXEDTRIANGLELIST2
D3DNTHAL_DP2INDEXEDTRIANGLESTRIP | D3DHAL_DP2INDEXEDTRIANGLESTRIP
D3DNTHAL_DP2LINELIST | D3DHAL_DP2LINELIST
D3DNTHAL_DP2LINESTRIP | D3DHAL_DP2LINESTRIP
D3DNTHAL_DP2POINTS | D3DHAL_DP2POINTS
D3DNTHAL_DP2RENDERSTATE | D3DHAL_DP2RENDERSTATE
D3DNTHAL_DP2SETCLIPPLANE | D3DHAL_DP2SETCLIPPLANE
D3DNTHAL_DP2SETLIGHT | D3DHAL_DP2SETLIGHT
D3DNTHAL_DP2SETPALETTE | D3DHAL_DP2SETPALETTE
D3DNTHAL_DP2SETPRIORITY | D3DHAL_DP2SETPRIORITY
D3DNTHAL_DP2SETRENDERTARGET | D3DHAL_DP2SETRENDERTARGET
D3DNTHAL_DP2SETTEXLOD | D3DHAL_DP2SETTEXLOD
D3DNTHAL_DP2SETTRANSFORM | D3DHAL_DP2SETTRANSFORM
D3DNTHAL_DP2STARTVERTEX | D3DHAL_DP2STARTVERTEX
D3DNTHAL_DP2STATESET | D3DHAL_DP2STATESET
D3DNTHAL_DP2TEXBLT | D3DHAL_DP2TEXBLT
D3DNTHAL_DP2TEXTURESTAGESTATE | D3DHAL_DP2TEXTURESTAGESTATE
D3DNTHAL_DP2TRIANGLEFAN | D3DHAL_DP2TRIANGLEFAN
D3DNTHAL_DP2TRIANGLEFAN_IMM | D3DHAL_DP2TRIANGLEFAN_IMM
D3DNTHAL_DP2TRIANGLELIST | D3DHAL_DP2TRIANGLELIST
D3DNTHAL_DP2TRIANGLESTRIP | D3DHAL_DP2TRIANGLESTRIP
D3DNTHAL_DP2UPDATEPALETTE | D3DHAL_DP2UPDATEPALETTE
D3DNTHAL_DP2VIEWPORTINFO | D3DHAL_DP2VIEWPORTINFO
D3DNTHAL_DP2WINFO | D3DHAL_DP2WINFO
D3DNTHAL_DP2ZRANGE | D3DHAL_DP2ZRANGE
D3DNTHAL_DRAWPRIMITIVES2DATA | D3DHAL_DRAWPRIMITIVES2DATA
D3DNTHAL_GLOBALDRIVERDATA | D3DHAL_GLOBALDRIVERDATA
D3DNTHAL_VALIDATETEXTURESTAGESTATEDATA | D3DHAL_VALIDATETEXTURESTAGESTATEDATA
D3DNTHALDEVICEDESC_V1 | D3DDEVICEDESC_V1


D3DHAL_Xxx Structures

This section contains all the Direct3D driver structures whose names have the form D3DHAL_Xxx.


D3DHAL_CALLBACKS

D3DHAL_CALLBACKS is one of several callback structures that describe the Direct3D support provided by the driver.

typedef struct _D3DHAL_CALLBACKS {
    DWORD                           dwSize;
    // Device context
    LPD3DHAL_CONTEXTCREATECB        ContextCreate;
    LPD3DHAL_CONTEXTDESTROYCB       ContextDestroy;
    LPD3DHAL_CONTEXTDESTROYALLCB    ContextDestroyAll;
    // Scene Capture
    LPD3DHAL_SCENECAPTURECB         SceneCapture;
    // Execution
    LPVOID                          dwReserved10;
    LPVOID                          dwReserved11;
    LPVOID                          dwReserved22;
    LPVOID                          dwReserved23;
    ULONG_PTR                       dwReserved;
    // Textures
    LPD3DHAL_TEXTURECREATECB        TextureCreate;
    LPD3DHAL_TEXTUREDESTROYCB       TextureDestroy;
    LPD3DHAL_TEXTURESWAPCB          TextureSwap;
    LPD3DHAL_TEXTUREGETSURFCB       TextureGetSurf;
    LPVOID                          dwReserved12;
    LPVOID                          dwReserved13;
    LPVOID                          dwReserved14;
    LPVOID                          dwReserved15;
    LPVOID                          dwReserved16;
    LPVOID                          dwReserved17;
    LPVOID                          dwReserved18;
    LPVOID                          dwReserved19;
    LPVOID                          dwReserved20;
    LPVOID                          dwReserved21;
    // Pipeline state
    LPVOID                          dwReserved24;
    ULONG_PTR                       dwReserved0;
    ULONG_PTR                       dwReserved1;
    ULONG_PTR                       dwReserved2;
    ULONG_PTR                       dwReserved3;
    ULONG_PTR                       dwReserved4;
    ULONG_PTR                       dwReserved5;
    ULONG_PTR                       dwReserved6;
    ULONG_PTR                       dwReserved7;
    ULONG_PTR                       dwReserved8;
    ULONG_PTR                       dwReserved9;
} D3DHAL_CALLBACKS, *LPD3DHAL_CALLBACKS;

Members

dwSize
Specifies the size in bytes of this D3DHAL_CALLBACKS structure.
ContextCreate
Points to the driver-supplied D3dContextCreate callback. A driver must implement the callback that this member points to.
ContextDestroy
Points to the driver-supplied D3dContextDestroy callback. A driver must implement the callback that this member points to.
ContextDestroyAll
Must be set to NULL in a Windows 2000 and later driver.
SceneCapture
Must be set to NULL in a Windows 2000 and later driver. This was a pointer to the driver-supplied D3dSceneCapture callback that was replaced by the D3DRENDERSTATE_SCENECAPTURE render state. This render state is handled in D3dDrawPrimitives2.
dwReserved10, dwReserved11, dwReserved22, dwReserved23, dwReserved
Are reserved and must be set to zero.
TextureCreate
Must be set to NULL in a Windows 2000 and later driver. This was a pointer to the driver-supplied D3dTextureCreate callback, or NULL.
TextureDestroy
Must be set to NULL in a Windows 2000 and later driver. This was a pointer to the driver-supplied D3dTextureDestroy callback, or NULL.
TextureSwap
Must be set to NULL in a Windows 2000 and later driver. This was a pointer to the driver-supplied D3dTextureSwap callback, or NULL.
TextureGetSurf
Must be set to NULL in a Windows 2000 and later driver. This was a pointer to the driver-supplied D3dTextureGetSurf callback, or NULL.
dwReserved12-dwReserved21, dwReserved24, dwReserved0-dwReserved9
Are reserved and must be set to zero.

Comments

The driver allocates this structure and sets appropriate values in all members. The driver's DrvGetDirectDrawInfo function returns a pointer to this structure in the lpD3DHALCallbacks member of the DD_HALINFO structure.

Texture management is now handled though opcodes that are managed in the driver's implementation of D3dDrawPrimitives2.

See Also

D3DHAL_CALLBACKS3, DdGetDriverInfo, DrvGetDirectDrawInfo


D3DHAL_CALLBACKS3

D3DHAL_CALLBACKS3 is one of several callback structures that describe the Direct3D support provided by the driver.

typedef struct _D3DHAL_CALLBACKS3 {
    DWORD                                   dwSize;
    DWORD                                   dwFlags;
    LPD3DHAL_CLEAR2CB                       Clear2;
    LPVOID                                  lpvReserved;
    LPD3DHAL_VALIDATETEXTURESTAGESTATECB    ValidateTextureStageState;
    LPD3DHAL_DRAWPRIMITIVES2CB              DrawPrimitives2;
} D3DHAL_CALLBACKS3, *LPD3DHAL_CALLBACKS3;

Members

dwSize
Specifies the size in bytes of this structure.
dwFlags
Indicates the callbacks associated with this structure that the driver has implemented. For every bit the driver sets in dwFlags, the driver must initialize the corresponding function pointer member of this structure. This member can be the bitwise-OR of one or more of the following flags:
Flag | Meaning
D3DHAL3_CB32_CLEAR2 | Not used in DirectX® 7.0 and later versions.
D3DHAL3_CB32_DRAWPRIMITIVES2 | The DrawPrimitives2 member points to a driver-implemented D3dDrawPrimitives2 callback.
D3DHAL3_CB32_RESERVED | Not used in DirectX® 7.0 and later versions.
D3DHAL3_CB32_VALIDATETEXTURESTAGESTATE | The ValidateTextureStageState member points to a driver-implemented D3dValidateTextureStageState callback.

Clear2
Must be set to NULL. This was a pointer to the driver-supplied D3dClear2 callback that is no longer used for DirectX® 7.0 and beyond. Instead the driver should respond to the D3DDP2OP_CLEAR command stream token in its implementation of D3dDrawPrimitives2.
lpvReserved
Must be set to NULL in a Windows 2000 and later driver.
ValidateTextureStageState
Points to the driver-supplied D3dValidateTextureStageState callback, or NULL. Drivers that support multi-texturing must implement the callback that this member points to.
DrawPrimitives2
Points to the driver-supplied D3dDrawPrimitives2 callback. A driver must implement the callback that this member points to.

Comments

The driver allocates this structure and sets appropriate values in all members. The driver's DdGetDriverInfo function returns a pointer to this structure when that function is called with the GUID_D3DCallbacks3 GUID.

See Also

D3DHAL_CALLBACKS, DdGetDriverInfo


D3DHAL_CLIPPEDTRIANGLEFAN

DirectX 8.0 and later versions only.

One or more D3DHAL_CLIPPEDTRIANGLEFAN structures are parsed from the command buffer by the D3dDrawPrimitives2 callback when the D3DHAL_DP2COMMAND structure's bCommand member is set to D3DDP2OP_CLIPPEDTRIANGLEFAN, and are used to render clipped triangle fans.

typedef struct _D3DHAL_CLIPPEDTRIANGLEFAN
{
    DWORD FirstVertexOffset;       // Offset in bytes in the
                                   // current stream 0
    DWORD dwEdgeFlags;
    DWORD PrimitiveCount;
} D3DHAL_CLIPPEDTRIANGLEFAN, *LPD3DHAL_CLIPPEDTRIANGLEFAN;

Members

FirstVertexOffset
Specifies the byte offset into stream 0 of the start of the vertex data (not the index of the vertex).
dwEdgeFlags
Specifies what edges are to be drawn when rendering wire frame (to prevent the drawing of edges introduced by clipping).
PrimitiveCount
Specifies the number of triangles in the given triangle fan.


D3DHAL_D3DEXTENDEDCAPS

D3DHAL_D3DEXTENDEDCAPS describes additional 3D capabilities of the driver.

typedef struct _D3DHAL_D3DEXTENDEDCAPS {
    DWORD     dwSize;
    DWORD     dwMinTextureWidth;
    DWORD     dwMaxTextureWidth;
    DWORD     dwMinTextureHeight;
    DWORD     dwMaxTextureHeight;
    DWORD     dwMinStippleWidth;
    DWORD     dwMaxStippleWidth;
    DWORD     dwMinStippleHeight;
    DWORD     dwMaxStippleHeight;
    DWORD     dwMaxTextureRepeat;
    DWORD     dwMaxTextureAspectRatio;
    DWORD     dwMaxAnisotropy;
    D3DVALUE  dvGuardBandLeft;
    D3DVALUE  dvGuardBandTop;
    D3DVALUE  dvGuardBandRight;
    D3DVALUE  dvGuardBandBottom;
    D3DVALUE  dvExtentsAdjust;
    DWORD     dwStencilCaps;
    DWORD     dwFVFCaps;
    DWORD     dwTextureOpCaps;
    WORD      wMaxTextureBlendStages;
    WORD      wMaxSimultaneousTextures;
    DWORD     dwMaxActiveLights;
    D3DVALUE  dvMaxVertexW;
    WORD      wMaxUserClipPlanes;
    WORD      wMaxVertexBlendMatrices;
    DWORD     dwVertexProcessingCaps;
    DWORD     dwReserved1;
    DWORD     dwReserved2;
    DWORD     dwReserved3;
    DWORD     dwReserved4;
    DWORD     dwReserved5;
} D3DHAL_D3DEXTENDEDCAPS;

Members

dwSize
Specifies the size in bytes of this D3DHAL_D3DEXTENDEDCAPS structure.
dwMinTextureWidth, dwMaxTextureWidth
Specify the minimum and maximum texture widths supported by the driver or device. These fields are provided as hints to the application, and it is the application's responsibility to adjust texture sizes when necessary.
dwMinTextureHeight, dwMaxTextureHeight
Specify the minimum and maximum texture heights supported by the driver.
dwMinStippleWidth, dwMaxStippleWidth
Specify the minimum and maximum stipple widths supported by the driver.
dwMinStippleHeight, dwMaxStippleHeight
Specify the minimum and maximum stipple heights supported by the driver.
dwMaxTextureRepeat
Specifies the full range of integer (non-fractional) bits of the post-normalized texture indexes. If the D3DDEVCAPS_TEXREPEATNOTSCALEDBYSIZE bit is set, then the number of times a texture can be wrapped is specified by this member. If the D3DDEVCAPS_TEXREPEATNOTSCALEDBYSIZE bit is not set, then the number of time a texture can be wrapped is given by the expression: dwMaxTextureRepeat * (texture size).
dwMaxTextureAspectRatio
Specifies the maximum texture aspect ratio supported by the hardware. This member is typically a power of 2.
dwMaxAnisotropy
Specifies the maximum valid value for the D3DRENDERSTATE_ANISOTROPY render state.
dvGuardBandLeft, dvGuardBandTop, dvGuardBandRight, dvGuardBandBottom
Specify the screen-space coordinates of the guard-band clip region. The upper-left corner of this rectangle has coordinates (dvGuardBandLeft, dvGuardBandTop). The lower-left corner has coordinates (dvGuardBandRight, dvGuardBandBottom). Coordinates inside this rectangle but outside the viewport rectangle will automatically be clipped.
dvExtentsAdjust
Specifies the number of pixels required to adjust the extents rectangle outward to accommodate antialiasing kernels.
dwStencilCaps
Are flags that specify the stencil buffer operations supported by the driver or device. For further descriptions of the stencil buffer operations shown in the following table, see D3DSTENCILOP in the DirectX SDK documentation. Stencil operations are assumed to be valid for all three stencil buffer operation render states (D3DRENDERSTATE_STENCILFAIL, D3DRENDERSTATE_STENCILPASS, and D3DRENDERSTATE_STENCILZFAIL). This member can be a bitwise OR of any of the following values:
Value | Stencil Buffer Operation
D3DSTENCILCAPS_DECR | The D3DSTENCILOP_DECR operation is supported.
D3DSTENCILCAPS_DECRSAT | The D3DSTENCILOP_DECRSAT operation is supported.
D3DSTENCILCAPS_INCR | The D3DSTENCILOP_INCR operation is supported.
D3DSTENCILCAPS_INCRSAT | The D3DSTENCILOP_INCRSAT operation is supported.
D3DSTENCILCAPS_INVERT | The D3DSTENCILOP_INVERT operation is supported.
D3DSTENCILCAPS_KEEP | The D3DSTENCILOP_KEEP operation is supported.
D3DSTENCILCAPS_REPLACE | The D3DSTENCILOP_REPLACE operation is supported.
D3DSTENCILCAPS_ZERO | The D3DSTENCILOP_ZERO operation is supported.

dwFVFCaps
Specifies the number of texture coordinates that the driver can process. This value can be an integer in the range 0 through 8, where 0 indicates that the driver does not support texturing, 1 indicates that the driver can process only one set of texture coordinates, 2 indicates that the driver can process two sets of texture coordinates, and so on.

A driver must be able to parse all texture coordinates present in the vertex data regardless of the number of texture coordinates that the driver actually uses. The driver should use the index provided with the D3DTSS_TEXCOORDINDEX value of the D3DTEXTURESTAGESTATETYPE enumeration, described in the DirectX SDK documentation, to determine what texture coordinate set to use when rendering.

dwTextureOpCaps
Specify the texture operations supported by the device. See D3DTEXTUREOP in the DirectX SDK documentation for descriptions of the texture operations listed in the following table. This member can be a bitwise OR of the following values:
Value | Texture Operation Supported
D3DTEXOPCAPS_ADD | The D3DTOP_ADD texture blending operation is supported by this device.
D3DTEXOPCAPS_ADDSIGNED | The D3DTOP_ADDSIGNED texture blending operation is supported by this device.
D3DTEXOPCAPS_ADDSIGNED2X | The D3DTOP_ADDSIGNED2X texture blending operation is supported by this device.
D3DTEXOPCAPS_ADDSMOOTH | The D3DTOP_ADDSMOOTH texture blending operation is supported by this device.
D3DTEXOPCAPS_BLENDCURRENTALPHA | The D3DTOP_BLENDCURRENTALPHA texture blending operation is supported by this device.
D3DTEXOPCAPS_BLENDDIFFUSEALPHA | The D3DTOP_BLENDDIFFUSEALPHA texture blending operation is supported by this device.
D3DTEXOPCAPS_BLENDFACTORALPHA | The D3DTOP_BLENDFACTORALPHA texture blending operation is supported by this device.
D3DTEXOPCAPS_BLENDTEXTUREALPHA | The D3DTOP_BLENDTEXTUREALPHA texture blending operation is supported by this device.
D3DTEXOPCAPS_BLENDTEXTUREALPHAPM | The D3DTOP_BLENDTEXTUREALPHAPM texture blending operation is supported by this device.
D3DTEXOPCAPS_BUMPENVMAP. | The D3DTOP_BUMPENVMAP texture blending operation is supported by this device.
D3DTEXOPCAPS_BUMPENVMAPLUMINANCE | The D3DTOP_BUMPENVMAPLUMINANCE texture blending operation is supported by this device.
D3DTEXOPCAPS_DISABLE | The D3DTOP_DISABLE texture blending operation is supported by this device.
D3DTEXOPCAPS_DOTPRODUCT3 | The D3DTOP_DOTPRODUCT3 texture blending operation is supported by this device.
D3DTEXOPCAPS_MODULATE | The D3DTOP_MODULATE texture blending operation is supported by this device.
D3DTEXOPCAPS_MODULATE2X | The D3DTOP_MODULATE2X texture blending operation is supported by this device.
D3DTEXOPCAPS_MODULATE4X | The D3DTOP_MODULATE4X texture blending operation is supported by this device.
D3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR | The D3DTOP_MODULATEALPHA_ADDCOLOR texture blending operation is supported by this device.
D3DTEXOPCAPS_MODULATECOLOR_ADDALPHA | The D3DTOP_MODULATEALPHA_ADDCOLOR texture blending operation is supported by this device.
D3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR | The D3DTOP_MODULATEINVALPHA_ADDCOLOR texture blending operation is supported by this device.
D3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA | The D3DTOP_MODULATEINVCOLOR_ADDALPHA texture blending operation is supported by this device.
D3DTEXOPCAPS_PREMODULATE | The D3DTOP_PREMODULATE texture blending operation is supported by this device.
D3DTEXOPCAPS_SELECTARG1 | The D3DTOP_SELECTARG1 texture blending operation is supported by this device.
D3DTEXOPCAPS_SELECTARG2 | The D3DTOP_SELECTARG2 texture blending operation is supported by this device.
D3DTEXOPCAPS_SUBTRACT | The D3DTOP_SUBTRACT texture blending operation is supported by this device.

wMaxTextureBlendStages
Specifies the maximum number of texture blending stages supported by this device.
wMaxSimultaneousTextures
Specifies the maximum number of textures that can be simultaneously bound to the texture blending stages for this device. That is, wMaxSimultaneousTextures specifies how many of the texture stages can have textures bound to them through the lDirect3DDevice7::SetTexture method. See the Platform SDK documentation for more information about this method.
dwMaxActiveLights
Specifies the maximum number of active lights supported by this device. This only needs to be specified in drivers that support hardware transform and lighting (and therefore specify D3DDEVCAPS_HWTRANSFORMANDLIGHT in their device caps).
dvMaxVertexW
Specifies the maximum W range supported by this device. This only needs to be specified in drivers that support W buffering (and therefore specify D3DPRASTERCAPS_WBUFFER in their rasterization caps).
wMaxUserClipPlanes;
Specifies the maximum number of user-defined clip planes supported.
wMaxVertexBlendMatrices
Specifies the number of world matrices supported for vertex blending.
dwVertexProcessingCaps
Specifies the vertex processing caps supported.
dwReserved1, dwReserved2, dwReserved3, dwReserved4, dwReserved5
Reserved for system use.

Comments

The driver allocates and zero-initializes this structure and sets appropriate values in the members it supports. The driver's DdGetDriverInfo function returns a pointer to this structure when that function is called with the GUID_D3DExtendedCaps GUID.

When the driver fills in this structure, it can set values for execute buffer capabilities even when the interface being used to retrieve the capabilities (such as lDirect3DDevice3) doesn't support execute buffers.


D3DHAL_DP2ADDDIRTYBOX

DirectX 8.1 and later versions only.

D3DHAL_DP2ADDDIRTYBOX is used to specify that a portion of a 3D resource—a volume texture—was dirtied in system memory. Therefore, this volume must be reloaded into video memory before being used.

typedef struct _D3DHAL_DP2ADDDIRTYBOX
{
  DWORD   dwSurface;
  D3DBOX  DirtyBox;
} D3DHAL_DP2ADDDIRTYBOX,  *LPD3DHAL_DP2ADDDIRTYBOX;

Members

dwSurface
Handle to the managed 3D resource that contains a dirtied volume texture.
DirtyBox
A D3DBOX structure that specifies the volume texture that was marked as dirtied. The D3DBOX structure is described in the Platform SDK documentation.

Comments

D3DHAL_DP2ADDDIRTYBOX along with the DP2OP_ADDDIRTYBOX token is used only for driver managed resources. D3DHAL_DP2ADDDIRTYBOX is never sent unless the driver indicates that it manages resources. To indicate that it manages resources, the driver must set the DDCAPS2_CANMANAGERESOURCE bit, in addition to the DDCAPS2_CANMANAGETEXTURE bit, in the dwCaps2 member of a DDCORECAPS structure. The driver specifies this DDCORECAPS structure in the ddCaps member of a DD_HALINFO structure when the driver's DrvGetDirectDrawInfo function is called to initialize the DirectDraw component of the driver.

See Also

D3DHAL_DP2COMMAND, D3DHAL_DP2OPERATION, DDCORECAPS, DD_HALINFO, DrvGetDirectDrawInfo


D3DHAL_DP2ADDDIRTYRECT

DirectX 8.1 and later versions only.

D3DHAL_DP2ADDDIRTYRECT is used to specify that a portion of a 2D resource—a 2D texture or cube texture—was dirtied in system memory. Therefore, this 2D texture must be reloaded into video memory before being used.

typedef struct _D3DHAL_DP2ADDDIRTYRECT
{
  DWORD   dwSurface;
  RECTL   rDirtyArea;
} D3DHAL_DP2ADDDIRTYRECT,  *LPD3DHAL_DP2ADDDIRTYRECT;

Members

dwSurface
Handle to the managed 2D resource that contains a dirtied 2D texture.
rDirtyArea
A RECTL structure that specifies the 2D texture that was marked as dirtied. The RECTL structure is described in the Platform SDK documentation.

Comments

D3DHAL_DP2ADDDIRTYRECT along with the DP2OP_ADDDIRTYRECT token is used only for driver managed resources and surfaces. D3DHAL_DP2ADDDIRTYRECT is never sent unless the driver indicates that it manages resources. To indicate that it manages resources, the driver must set the DDCAPS2_CANMANAGERESOURCE bit, in addition to the DDCAPS2_CANMANAGETEXTURE bit, in the dwCaps2 member of a DDCORECAPS structure. The driver specifies this DDCORECAPS structure in the ddCaps member of a DD_HALINFO structure when the driver's DrvGetDirectDrawInfo function is called to initialize the DirectDraw component of the driver.

See Also

D3DHAL_DP2COMMAND, D3DHAL_DP2OPERATION, DDCORECAPS, DD_HALINFO, DrvGetDirectDrawInfo


D3DHAL_DP2BUFFERBLT

DirectX 8.0 and later versions only.

D3DHAL_DP2BUFFERBLT is used for vertex or index buffer blts when D3dDrawPrimitives2 responds to the D3DDP2OP_BUFFERBLT command token.

typedef struct _D3DHAL_DP2BUFFERBLT
{
  DWORD   dwDDDestSurface; // dest surface
  DWORD   dwDDSrcSurface;  // src surface
  DWORD   dwOffset;        // offset in the dest surface (in BYTES)
  D3DRANGE rSrc;           // src surface range (contains UINT Offset
                           // and UINT Size)
  DWORD   dwFlags;         // blt flags
} D3DHAL_DP2BUFFERBLT, *LPD3DHAL_DP2BUFFERBLT;

Members

dwDDDestSurface
Specifies the handle to the destination vertex or index buffer.
dwDDSrcSurface
Specifies the handle to the source vertex or index buffer.
dwOffset
Specifies the part of the destination buffer the copy should be directed into.
rSrc
Specifies what range of the source buffer should be copied.
dwFlags
Is currently unused.

Comments

The CreateD3DBuffer callback creates the small integer handles to the vertex or index buffers that can be used as source and destination buffers for buffer blts.

See Comments for D3DHAL_DP2TEXBLT.

See Also

D3dDrawPrimitives2, D3DHAL_DP2COMMAND


D3DHAL_DP2CLEAR

D3DHAL_DP2CLEAR contains all of the information that the driver needs to perform hardware-assisted clearing on the rendering target, depth buffer or stencil buffer.

typedef struct _D3DHAL_DP2CLEAR {
    DWORD     dwFlags;
    DWORD     dwFillColor;
    D3DVALUE  dvFillDepth;
    DWORD     dwFillStencil;
    RECT      Rects[1];
} D3DHAL_DP2CLEAR, *LPD3DHAL_DP2CLEAR;

Members

dwFlags
Specifies what buffer(s) the driver should clear. This member can be a bitwise OR of the following values:
Value | Meaning
D3DCLEAR_TARGET | The driver should clear the context's render target to the color specified by the dwFillColor member.
D3DCLEAR_STENCIL | The driver should clear the context's stencil buffer to the value specified by the dwFillStencil member.
D3DCLEAR_ZBUFFER | The driver should clear the context's depth buffer to the depth specified by the dwFillDepth member.
D3DCLEAR_COMPUTERECTS DirectX 8.0 and later versions only.

If this flag is set, the specified rectangles should be clipped against the current viewport. Furthermore, it is possible that when D3DCLEAR_COMPUTERECTS is specified the number of rectangles to clear can be zero (the number of rectangles to clear can be found in the wStateCount/wPrimtiveCount union of the D3DHAL_DP2COMMAND structure for the clear). In this case the entire viewport should be cleared.

dwFillColor
Specifies the color that the driver should clear the context's render target to.
dvFillDepth
Specifies the value that the driver should use to set the depth in the context's depth buffer. This member can be a value in the interval 0.0 to 1.0. The driver should convert this value to an integer using the dwZBitMask member of the depth buffer's DDPIXELFORMAT structure.
dwFillStencil
Specifies the value that the driver should clear the context's stencil buffer to. This member can be an integer in the interval 0 to 2n-1, where n is the number of bits in the stencil buffer.
Rects
Specifies the rectangular areas of the buffer that the driver should clear. The rectangles are specified in screen coordinates. This member of the structure contains the first rectangle area to be blitted. The wStateCount member of the D3DHAL_DP2COMMAND contains the total number of rectangle areas to be blitted. The other (wStateCount-1) RECT structures required will follow the D3DHAL_DP2CLEAR structure without any padding.

Comments

This structure is used with the D3DDP2OP_CLEAR command token to replace the legacy D3dClear and D3dClear2 callbacks.

It is important to note that when the number of rectangles is zero, the D3DHAL_DP2CLEAR data structure still includes space for a single RECT. Thus, the size of this single RECT should be included when advancing to the next DP2 instruction. However, the contents of the RECT in this case are undefined and the driver should not attempt to read them.


D3DHAL_DP2COMMAND

One or more D3DHAL_DP2COMMAND structures are parsed from the command buffer by the D3dDrawPrimitives2 callback, which uses the information it receives to draw one or more primitives. Each structure specifies either a primitive to draw or a state change to process.

typedef struct _D3DHAL_DP2COMMAND {
    BYTE  bCommand;
    BYTE  bReserved;
    union
    {
        WORD  wPrimitiveCount;
        WORD  wStateCount;
    };
} D3DHAL_DP2COMMAND, *LPD3DHAL_DP2COMMAND;

Members

bCommand
Specifies a primitive to draw or a state change to process. This member can be one of the D3DHAL_DP2OPERATION enumerated values.
bReserved
Is reserved for system use and should be ignored by the driver.
wPrimitiveCount
Specifies the number of primitives to process. This member is valid when bCommand is not either of D3DDP2OP_RENDERSTATE or D3DDP2OP_TEXTURESTAGESTATE.
wStateCount
Specifies the number of state changes to process. This member is valid when bCommand is one of D3DDP2OP_RENDERSTATE or D3DDP2OP_TEXTURESTAGESTATE.


D3DHAL_DP2CREATELIGHT

The D3DHAL_DP2CREATELIGHT structure is used to create a light for D3dDrawPrimitives2.

typedef struct _D3DHAL_DP2CREATELIGHT {
    DWORD  dwIndex;
} D3DHAL_DP2CREATELIGHT, *LPD3DHAL_DP2CREATELIGHT;

Member

dwIndex
Specifies the index of the light being created.

Comments

The D3DHAL_DP2CREATELIGHT structure is used to hold the index into the light array. The driver should enlarge its light array as necessary to accommodate at least as many lights as specified by the index.


D3DHAL_DP2CREATEPIXELSHADER

DirectX 8.0 and later versions only.

The D3DHAL_DP2CREATEPIXELSHADER structure is used to create a pixel shader when a D3DDP2OP_CREATEPIXELSHADER opcode is received by D3dDrawPrimitives2.

typedef struct _D3DHAL_DP2CREATEPIXELSHADER
{
    DWORD dwHandle;     // Shader handle
    DWORD dwCodeSize;   // Shader code size in bytes
    // Shader code follows
} D3DHAL_DP2CREATEPIXELSHADER, *LPD3DHAL_DP2CREATEPIXELSHADER;

Member

dwHandle
Specifies the handle assigned by the runtime. This value is guaranteed to be non-zero.
dwCodeSize
Specifies the size, in bytes, of the shader code following this data structure in the DP2 stream.

Comments

The runtime generates a handle for this shader before calling the driver. The shader code itself follows the D3DHAL_DP2CREATEPIXELSHADER in the DP2 stream.

Before calling the driver, the runtime validates the pixel shader code to ensure that it is legal for the specified shader language version.

It is important to note that the creation of a pixel shader does not imply the setting of the current shader.

See Also

D3DHAL_DP2PIXELSHADER


D3DHAL_DP2CREATEVERTEXSHADER

DirectX 8.0 and later versions only.

The D3DHAL_DP2CREATEVERTEXSHADER structure is used to create a vertex shader when a D3DDP2OP_CREATEVERTEXSHADER opcode is received by D3dDrawPrimitives2.

typedef struct _D3DHAL_DP2CREATEVERTEXSHADER
{
    DWORD dwHandle;     // Shader handle
    DWORD dwDeclSize;   // Shader declaration size in bytes
    DWORD dwCodeSize;   // Shader code size in bytes
    // Declaration follows
    // Shader code follows
} D3DHAL_DP2CREATEVERTEXSHADER, *LPD3DHAL_DP2CREATEVERTEXSHADER;

Member

dwHandle
Specifies the handle assigned by the runtime. This value is guaranteed to be non-zero. Furthermore, although vertex FVF codes are part of the shader handle name space it is guaranteed that the handle passed will not be an FVF code.
dwDeclSize
Specifies the shader declaration size in bytes.
dwCodeSize
Specifies the shader code size in bytes.

Comments

Before invoking the driver, the runtime performs validation to ensure that the specified shader is legal for the specified shader language version. The runtime flushes all pending state and rendering when this token is to be sent to the driver. Thus, processing of this token is assumed to be synchronous with the runtime and the driver reports failure of the creation request by failing the D3dDrawPrimitives2 DDI call. Thus, the driver should validate the given shader declaration and code on receipt of this token and report success of failure accordingly.

See Also

D3DHAL_DP2VERTEXSHADER


D3DHAL_DP2DRAWINDEXEDPRIMITIVE

DirectX 8.0 and later versions only.

D3DHAL_DRAWINDEXEDPRIMITIVE is parsed from the command buffer by the D3dDrawPrimitives2 callback when the D3DHAL_DP2COMMAND structure's bCommand member is set to D3DDP2OP_DRAWINDEXEDPRIMITIVE, and is used to render a primitive using vertex indices.

typedef struct _D3DHAL_DP2DRAWINDEXEDPRIMITIVE
{
    D3DPRIMITIVETYPE primType;
    DWORD BaseVertexIndex;   // Vertex that corresponds to index 0
    DWORD MinIndex;          // Min vertex index in the vertex buffer
    DWORD NumVertices;       // Number of vertices starting from
                             // MinIndex
    DWORD StartIndex;        // Start index in the index buffer
    DWORD PrimitiveCount;
} D3DHAL_DP2DRAWINDEXEDPRIMITIVE, *LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE;

Members

primType
Specifies the type of primitive to draw (one of D3DPT_POINTLIST, D3DPT_LINELIST, D3DPT_LINESTRIP, D3DPT_TRIANGLELIST, D3DPT_TRIANGLESTRIP or D3DPT_TRIANGLEFAN).
BaseVertexIndex
Specifies the amount that should be added to each index referenced by the various primitives to determine the actual index of the vertex elements in each vertex stream.
MinIndex
Specifies the minimum index of a range of vertices that are potentially accessed by the primitives to be drawn and, therefore, which vertices should be processed.
NumVertices
Specifies the number of vertices in a range that are potentially accessed by the primitives to be drawn and, therefore, which vertices should be processed.
StartIndex
Specifies the first index in the index buffer from which indices are read to draw the primitives.
PrimitiveCount
Specifies the number of triangles, lines or points to draw for the given primitive.

Comments

The vertex data can be untransformed (if the hardware supports hardware vertex processing) or transformed if the application supplied data in that form to the runtime.

As with vertices, the actual indices to use are not passed with the token data, but rather should be read from the currently selected index buffer. See Index Buffers for more details.

See Also

D3DHAL_DP2DRAWINDEXEDPRIMITIVE2


D3DHAL_DP2DRAWINDEXEDPRIMITIVE2

DirectX 8.0 and later versions only.

D3DHAL_DRAWINDEXEDPRIMITIVE2 is parsed from the command buffer by the D3dDrawPrimitives2 callback when the D3DHAL_DP2COMMAND structure's bCommand member is set to D3DDP2OP_DRAWINDEXEDPRIMITIVE2, and is used to render a primitive using vertex indices.

typedef struct _D3DHAL_DP2DRAWINDEXEDPRIMITIVE2
{
    D3DPRIMITIVETYPE primType;
    INT   BaseVertexOffset;  // Stream 0 offset of the vertex that
                             // corresponds to index 0. This
                             // offset could be negative, but when
                             // an index is added to the offset
                             // the result is positive
    DWORD MinIndex;          // Min vertex index in the vertex buffer
    DWORD NumVertices;       // Number of vertices starting from
                             // MinIndex
    DWORD StartIndexOffset;  // Offset of the start index in the
                             // index buffer
    DWORD PrimitiveCount;    // Number of triangles (points, lines)
} D3DHAL_DP2DRAWINDEXEDPRIMITIVE2, *LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE2;

Members

primType
Specifies the type of primitive to draw (one of D3DPT_POINTLIST, D3DPT_LINELIST, D3DPT_LINESTRIP, D3DPT_TRIANGLELIST, D3DPT_TRIANGLESTRIP or D3DPT_TRIANGLEFAN).
BaseVertexOffset
Specifies the offset that should be added to each vertex in vertex stream 0 by the various primitives to determine the actual vertex in vertex stream 0.
MinIndex
Specifies the minimum index of a range of vertices that are potentially accessed by the primitives to be drawn and, therefore, which vertices should be processed.
NumVertices
Specifies the number of vertices in a range that are potentially accessed by the primitives to be drawn and, therefore, which vertices should be processed.
StartIndexOffset
Specifies the offset of the first index in the index buffer from which indices are read to draw the primitives.
PrimitiveCount
Specifies the number of triangles, lines or points to draw for the given primitive.

Comments

The vertex data has been transformed by the runtime.

As with vertices, the actual indices to use are not passed with the token data, but rather should be read from the currently selected index buffer. See Index Buffers for more details.

See Also

D3DHAL_DP2DRAWINDEXEDPRIMITIVE


D3DHAL_DP2DRAWPRIMITIVE

DirectX 8.0 and later versions only.

D3DHAL_DRAWPRIMITIVE is parsed from the command buffer by the D3dDrawPrimitives2 callback when the D3DHAL_DP2COMMAND structure's bCommand member is set to D3DDP2OP_DRAWPRIMITIVE, and is used to render a primitive.

typedef struct _D3DHAL_DP2DRAWPRIMITIVE
{
    D3DPRIMITIVETYPE    primType;
    DWORD               VStart;
    DWORD               PrimitiveCount;
} D3DHAL_DP2DRAWPRIMITIVE, *LPD3DHAL_DP2DRAWPRIMITIVE;

Members

primType
Specifies the type of primitive to draw (one of D3DPT_POINTLIST, D3DPT_LINELIST, D3DPT_LINESTRIP, D3DPT_TRIANGLELIST, D3DPT_TRIANGLESTRIP or D3DPT_TRIANGLEFAN).
VStart
Specifies the index (into each active vertex stream) of the vertex elements with which to start drawing. Actual vertex data should be read from the current vertex streams (those referenced by the current vertex shader) rather than from the vertex data pointer in D3DHAL_DRAWPRIMITIVES2DATA.
PrimitiveCount
Specifies the number of triangles, lines or points to draw for the given primitive.

Comments

The vertex data can be untransformed (if the hardware supports hardware vertex processing) or transformed if the application supplied data in that form to the runtime.


D3DHAL_DP2DRAWPRIMITIVE2

DirectX 8.0 and later versions only.

D3DHAL_DRAWPRIMITIVE2 is parsed from the command buffer by the D3dDrawPrimitives2 callback when the D3DHAL_DP2COMMAND structure's bCommand member is set to D3DDP2OP_DRAWPRIMITIVE2, and is used to render a primitive.

typedef struct _D3DHAL_DP2DRAWPRIMITIVE2
{
    D3DPRIMITIVETYPE primType;
    DWORD FirstVertexOffset;       // Offset in bytes in the stream 0
    DWORD PrimitiveCount;
} D3DHAL_DP2DRAWPRIMITIVE2, *LPD3DHAL_DP2DRAWPRIMITIVE2;

Members

primType
Specifies the type of primitive to draw (one of D3DPT_POINTLIST, D3DPT_LINELIST, D3DPT_LINESTRIP, D3DPT_TRIANGLELIST, D3DPT_TRIANGLESTRIP or D3DPT_TRIANGLEFAN).
FirstVertexOffset
Specifies the offset, in bytes, in stream zero of the vertex data. This is in contrast to D3DDP2OP_DRAWPRIMITIVE where the start of the vertex data in the vertex stream is specified by a vertex index rather than an actual byte offset.
PrimitiveCount
Specifies the number of triangles, lines or points to draw for the given primitive.

Comments

The vertex data has been transformed by the runtime.

See Also

D3DHAL_DP2DRAWPRIMITIVE


D3DHAL_DP2DRAWRECTPATCH

DirectX 8.0 and later versions only.

D3DHAL_DRAWRECTPATCH is parsed from the command buffer by the D3dDrawPrimitives2 callback when the D3DHAL_DP2COMMAND structure's bCommand member is set to D3DDP2OP_DRAWRECTPATCH, and is used to render a rectangular patch.

typedef struct _D3DHAL_DP2DRAWRECTPATCH
{
    DWORD Handle;
    DWORD Flags;
    // Optionally followed by D3DFLOAT[4] NumSegments
    // and/or D3DRECTPATCH_INFO
} D3DHAL_DP2DRAWRECTPATCH, *LPD3DHAL_DP2DRAWRECTPATCH;

Members

Handle
Specifies the handle associated with the surface.
Flags
Specifies what, if any, additional information follows the D3DHAL_DP2DRAWRECTPATCH data structure in the DP2 stream.

Comments

Handle is used to associate the surface with a handle, so that the next time this surface is drawn, there is no need to re-specify the D3DRECTPATCH_INFO for this patch. This makes it possible for the driver to pre-compute and cache forward difference coefficients and/or any other information, which in turn allows subsequent D3DDP2OP_DRAWRECTPATCH tokens using the same handle to execute more efficiently.

The actual value of Handle is determined by the application and is not under runtime control. Therefore, the driver should be prepared to cope with any value specifiable by a DWORD. The special handle value of zero means that the patch is dynamic and there is no point pre-computing or caching information for this patch. A non-zero value for Handle means the patch is static (or updated with low frequency) and pre-computation and caching are possible.

The Flags is used to communicate what, if any, additional information follows the D3DHAL_DP2DRAWRECTPATCH data structure in the DP2 stream. If RTPATCHFLAG_HASSEGS is specified then four floating point values follow D3DHAL_DP2DRAWRECTPATCH in the DP2 stream. These floats give the segment counts for each of the four edges of the rectangular patch and override the value of the render state D3DRS_PATCHSEGMENTS. If RTPATCHFLAG_HASINFO is specified then a D3DRECTPATCH_INFO data structure follows in the DP2 stream. Information on this structure can be found in the DirectX 8.0 SDK documentation. If both flags are specified the four floats specifying segment counts follow D3DHAL_DP2DRAWRECTPATCH and the D3DRECTPATCH_INFO structure follows the floating point values.

There are four scenarios a driver must handle when processing D3DDP2OP_DRAWRECTPATCH.

If Handle is zero then the patch is dynamic and no pre-computation or caching should be performed. In this case a D3DRECTPATCH_INFO will follow D3DHAL_DP2DRAWRECTPATCH in the DP2 stream (and the flag RTPATCHFLAG_HASINFO will be set to indicate the presence of the D3DHAL_DP2DRAWRECTPATCH data structure). Optionally, RTPATCHFLAG_HASSEGS may also be set to indicate the presence of the segment information. However, if this is omitted the value of the render state D3DRS_PATCHSEGMENTS should be used instead.

If Handle is non-zero and the handle value has not been specified by an earlier D3DDP2OP_DRAWRECTPATCH this indicates that a new cacheable patch is being drawn. The driver should allocate memory to store cached data and add this data to its patch handle table. As this patch has not been seen before the RTPATCHFLAG_HASINFO flags should be set and a D3DRECTPATCH_INFO flag should follow in the DP2 stream. The runtime does not guarantee this, however, and the driver should verify the presence of the patch information by testing the flag. If no information is specified this token should be ignored and no handle should be allocated in the driver's patch handle table. Optionally, RTPATCHFLAG_HASSEGS may also be set to indicate the presence of the segment information. However, if this is omitted the value of the render state D3DRS_PATCHSEGMENTS should be used instead.

If Handle is non-zero, the handle value has been specified by an earlier D3DDP2OP_DRAWRECTPATCH token and the Flags field contains RTPATCHFLAG_HASINFO then the definition for the patch is being updated. A D3DRECTPATCH_INFO data structure will follow in the DP2 stream and the driver should use that to re-compute and re-cache patch information. Optionally, RTPATCHFLAG_HASSEGS may also be set to indicate the presence of the segment information. However, if this is omitted the value of the render state D3DRS_PATCHSEGMENTS should be used instead.

If Handle is non-zero, the handle value has been specified by an earlier D3DDP2OP_DRAWRECTPATCH token and the Flags field does not contain RTPATCHFLAG_HASINFO then the cached information should be used for drawing the patch. In this case the current vertex streams are ignored, the cached information should be used instead. However, it is still possible in this case for a new segment information to be specified. Therefore, the driver should check for the flag RTPATCHFLAG_HASSEGS and handle specified segment information even if using a cached patch.

The driver receives notification that cached patch information is be released via the render state D3DRS_DELETERTPATCH. The value of this render state is the patch to be deleted.

See Also

D3DHAL_DP2DRAWTRIPATCH


D3DHAL_DP2DRAWTRIPATCH

DirectX 8.0 and later versions only.

D3DHAL_DRAWTRIPATCH is parsed from the command buffer by the D3dDrawPrimitives2 callback when the D3DHAL_DP2COMMAND structure's bCommand member is set to D3DDP2OP_DRAWTRIPATCH, and is used to render a triangular patch.

typedef struct _D3DHAL_DP2DRAWTRIPATCH
{
    DWORD Handle;
    DWORD Flags;
    // Optionally followed by D3DFLOAT[3] NumSegments
    // and/or D3DTRIPATCH_INFO
} D3DHAL_DP2DRAWTRIPATCH, *LPD3DHAL_DP2DRAWTRIPATCH;

Members

Handle
Specifies the handle associated with the surface.
Flags
Specifies what, if any, additional information follows the D3DHAL_DP2DRAWTRIPATCH data structure in the DP2 stream.

Comments

Handle is used to associate the surface with a handle, so that the next time this surface is drawn there is no need to re-specify the D3DTRIPATCH_INFO for this patch. This makes it possible for the driver to pre-compute and cache forward difference coefficients and/or any other information, which in turn allows subsequent D3DDP2OP_DRAWTRIPATCH tokens using the same handle to execute more efficiently.

The actual value of Handle is determined by the application and is not under runtime control. Therefore, the driver should be prepared to cope with any value specifiable by a DWORD. The special handle value of zero means that the patch is dynamic and there is no point pre-computing or caching information for this patch. A non-zero value for Handle means the patch is static (or updated with low frequency) and pre-computation and caching are possible.

The Flags is used to communicate what, if any, additional information follows the D3DHAL_DP2DRAWTRIPATCH data structure in the DP2 stream. If RTPATCHFLAG_HASSEGS is specified then three floating point values follow D3DHAL_DP2DRAWTRIPATCH in the DP2 stream. These floats give the segment counts for each of the three edges of the triangular patch and override the value of the render state D3DRS_PATCHSEGMENTS. If RTPATCHFLAG_HASINFO is specified then a D3DTRIPATCH_INFO data structure follows in the DP2 stream. Information on this structure can be found in the DirectX 8.0 SDK documentation. If both flags are specified the three floats specifying segment counts follow D3DHAL_DP2DRAWTRIPATCH and the D3DTRIPATCH_INFO structure follows the floating point values.

There are four scenarios a driver must handle when processing D3DDP2OP_DRAWTRIPATCH.

If Handle is zero then the patch is dynamic and no pre-computation or caching should be performed. In this case a D3DTRIPATCH_INFO will follow D3DHAL_DP2DRAWTRIPATCH in the DP2 stream (and the flag RTPATCHFLAG_HASINFO will be set to indicate the presence of the D3DHAL_DP2DRAWTRIPATCH data structure). Optionally, RTPATCHFLAG_HASSEGS may also be set to indicate the presence of the segment information. However, if this is omitted the value of the render state D3DRS_PATCHSEGMENTS should be used instead.

If Handle is non-zero and the handle value has not been specified by an earlier D3DDP2OP_DRAWTRIPATCH this indicates that a new cacheable patch is being drawn. The driver should allocate memory to store cached data and add this data to its patch handle table. As this patch has not been seen before the RTPATCHFLAG_HASINFO flags should be set and a D3DTRIPATCH_INFO flag should follow in the DP2 stream. The runtime does not guarantee this, however, and the driver should verify the presence of the patch information by testing the flag. If no information is specified this token should be ignored and no handle should be allocated in the driver's patch handle table. Optionally, RTPATCHFLAG_HASSEGS may also be set to indicate the presence of the segment information. However, if this is omitted the value of the render state D3DRS_PATCHSEGMENTS should be used instead.

If Handle is non-zero, the handle value has been specified by an earlier D3DDP2OP_DRAWTRIPATCH token and the Flags field contains RTPATCHFLAG_HASINFO then the definition for the patch is being updated. A D3DTRIPATCH_INFO data structure will follow in the DP2 stream and the driver should use that to re-compute and re-cache patch information. Optionally, RTPATCHFLAG_HASSEGS may also be set to indicate the presence of the segment information. However, if this is omitted the value of the render state D3DRS_PATCHSEGMENTS should be used instead.

If Handle is non-zero, the handle value has been specified by an earlier D3DDP2OP_DRAWTRIPATCH token and the Flags field does not contain RTPATCHFLAG_HASINFO then the cached information should be used for drawing the patch. In this case the current vertex streams are ignored, the cached information should be used instead. However, it is still possible in this case for a new segment information to be specified. Therefore, the driver should check for the flag RTPATCHFLAG_HASSEGS and handle specified segment information even if using a cached patch.

The driver receives notification that cached patch information is be released via the render state D3DRS_DELETERTPATCH. The value of this render state is the patch to be deleted.

See Also

D3DHAL_DP2DRAWRECTPATCH


D3DHAL_DP2EXT

The D3DHAL_DP2EXT structure's use has yet to be defined.

typedef struct _D3DHAL_DP2EXT {
    DWORD  dwExtToken;
    DWORD  dwSize;
} D3DHAL_DP2EXT, *LPD3DHAL_DP2EXT;
‹ ›

Members

dwExtToken
Is the extension token.
dwSize
Specifies the size, in bytes of this structure.

Comments

This structure is used with hardware transform and lighting and will be explained further in future documentation releases. Contact the DirectX team at Microsoft if you need further implementation details now.


D3DHAL_DP2INDEXEDLINELIST

D3DHAL_DP2INDEXEDLINELIST is parsed from the command buffer by the D3dDrawPrimitives2 callback when the D3DHAL_DP2COMMAND structure's bCommand member is set to D3DDP2OP_INDEXEDLINELIST, and is used to render the lines using vertex indices.

typedef struct _D3DHAL_DP2INDEXEDLINELIST {
    WORD  wV1;
    WORD  wV2;
} D3DHAL_DP2INDEXEDLINELIST;

Members

wV1
Specifies the index into the vertex buffer, identifying the first endpoint of the line.
wV2
Specifies the index into the vertex buffer, identifying the second endpoint of the line.

Comments

D3dDrawPrimitives2 should process (wPrimitiveCount * 2) indexes from the command buffer, in effect processing wPrimitiveCount D3DHAL_DP2INDEXEDLINELIST structures. The value of wPrimitiveCount is specified in the D3DHAL_DP2COMMAND structure.

The driver should process a total of (wPrimitiveCount * 2) vertices from the vertex buffer, two vertices per line. The sequence of lines rendered is (wV10, wV20), (wV11, wV21), …, (wV1n, wV2n), where n equals (wPrimitiveCount - 1). The driver should interpret the vertex buffer indexes based on the current command as follows:

  • When the command is D3DDP2OP_INDEXEDLINELIST, the vertex buffer indexes are relative to the vertex buffer offset specified by the dwVertexOffset member of the D3DHAL_DRAWPRIMITIVES2DATA structure.
  • When the command is D3DDP2OP_INDEXEDLINELIST2, a D3DHAL_DP2STARTVERTEX structure immediately follows it and precedes the D3DHAL_DP2INDEXEDLINELIST structure(s) in the command buffer. The vertex buffer indexes are relative to the vertex buffer offset specified by dwVertexOffset plus the base offset obtained from the wVStart member of the D3DHAL_DP2STARTVERTEX structure.

The following figure shows a portion of a sample command buffer containing a D3DDP2OP_INDEXEDLINELIST command and two D3DHAL_DP2INDEXEDLINELIST structures. The driver should draw two lines using the following four vertices from the vertex buffer: (v[0], v[4]), (v[5], v[6]).

Similarly, the following figure shows a portion of a sample command buffer containing a D3DDP2OP_INDEXEDLINELIST2 command, a D3DHAL_DP2STARTVERTEX offset, and two D3DHAL_DP2INDEXEDLINELIST structures. The driver should process four vertices from the vertex buffer, rendering two lines defined by (v[3], v[7]), (v[8], v[9]).


D3DHAL_DP2INDEXEDLINESTRIP

D3DHAL_DP2INDEXEDLINESTRIP is parsed from the command buffer by the D3dDrawPrimitives2 callback when the D3DHAL_DP2COMMAND structure's bCommand member is set to D3DDP2OP_INDEXEDLINESTRIP, and is used to render a sequence of connected line segments using vertex indices.

typedef struct _D3DHAL_DP2INDEXEDLINESTRIP {
    WORD  wV[2];
} D3DHAL_DP2INDEXEDLINESTRIP;

Members

wV
Specifies the indexes into the vertex buffer from which the driver obtains coordinate data for the vertices making up the line strip.

Although this member has only enough space to hold two indexes, this array of indexes should be treated as a variable-sized array with (wPrimitiveCount + 1) elements. (wPrimitiveCount is a member of the D3DHAL_DP2COMMAND structure.)

Comments

Indexed line strips rendered with vertex buffers are specified using D3DHAL_DP2INDEXEDLINESTRIP. The number of line segments to process is specified by the wPrimitiveCount member of D3DHAL_DP2COMMAND. The sequence of line segments rendered will be: (wV[0], wV[1]), (wV[1], wV[2]), (wV[2], wV[3]), ..., (wVStart[wPrimitiveCount-1], wVStart[wPrimitiveCount]).

D3dDrawPrimitives2 should process (wPrimitiveCount+1) indexes from the command buffer, in effect processing wPrimitiveCount D3DHAL_DP2INDEXEDLINESTRIP structures. The value of wPrimitiveCount is specified in the D3DHAL_DP2COMMAND structure.

A D3DHAL_DP2STARTVERTEX structure immediately follows the command in the command buffer. The vertex buffer indexes are relative to the vertex buffer offset specified by the dwVertexOffset member of the D3DHAL_DRAWPRIMITIVES2DATA structure plus the base offset obtained from the wVStart member of the D3DHAL_DP2STARTVERTEX structure.

The following figure shows a portion of a sample command buffer containing a D3DDP2OP_INDEXEDLINESTRIP command, a D3DHAL_DP2STARTVERTEX offset, and a list of D3DHAL_DP2INDEXEDLINESTRIP structures. The driver should process four vertices from the vertex buffer, rendering three connected line segments defined by (v[8], v[4]), (v[4], v[7]), (v[7], v[6]).


D3DHAL_DP2INDEXEDTRIANGLEFAN

D3DHAL_DP2INDEXEDTRIANGLEFAN is parsed from the command buffer by the D3dDrawPrimitives2 callback when the D3DHAL_DP2COMMAND structure's bCommand member is set to D3DDP2OP_INDEXEDTRIANGLEFAN, and is used to render a sequence of connected triangles using vertex indices. All of the triangles share a common vertex.

typedef struct _D3DHAL_DP2INDEXEDTRIANGLEFAN {
    WORD wV[3];
} D3DHAL_DP2INDEXEDTRIANGLEFAN;

Members

wV
Specifies the indexes into the vertex buffer from which the driver obtains coordinate data for the vertices making up the triangle fan.

Although this member has only enough space to contain three indexes, this array of indexes should be treated as a variable-sized array with (wPrimitiveCount + 2) elements. (wPrimitiveCount is a member of the D3DHAL_DP2COMMAND structure.)

Comments

D3dDrawPrimitives2 should process (wPrimitiveCount+2) indexes from the command buffer, in effect, processing wPrimitiveCount D3DHAL_DP2INDEXEDTRIANGLEFAN structures. The value of wPrimitiveCount is specified in the D3DHAL_DP2COMMAND structure.

The driver should process a total of (wPrimitiveCount+2) vertices from the vertex buffer, three vertices per triangle. The sequence of triangles rendered is: (wV[1], wV[2], wV[0]), (wV[2], wV[3], wV[0]), (wV[3], wV[4], wV[0]), …, (wV[wPrimitiveCount], wV[wPrimitiveCount+1], wV[0]). Notice that all of the triangles have the vertex specified in wV[0] in common.

A D3DHAL_DP2STARTVERTEX structure immediately follows the command in the command buffer. The vertex buffer indexes are relative to the vertex buffer offset specified by the dwVertexOffset member of the D3DHAL_DRAWPRIMITIVES2DATA structure plus the base offset obtained from the wVStart member of the D3DHAL_DP2STARTVERTEX structure.

The following figure shows a portion of a sample command buffer containing a D3DDP2OP_INDEXEDTRIANGLEFAN command, a D3DHAL_DP2STARTVERTEX offset, and a logical list of D3DHAL_DP2INDEXEDTRIANGLEFAN structures. The driver should process five vertices from the vertex buffer, rendering a fan with three triangles defined by (v[4], v[5], v[7]), (v[5], v[6], v[7]), (v[6], v[9], v[7]).


D3DHAL_DP2INDEXEDTRIANGLELIST

One or more D3DHAL_DP2INDEXEDTRIANGLELIST structures are parsed from the command buffer by the D3dDrawPrimitives2 callback when the D3DHAL_DP2COMMAND structure's bCommand member is set to D3DDP2OP_INDEXEDTRIANGLELIST, and are used to render a sequence of unconnected triangles using vertex indices.

typedef struct _D3DHAL_DP2INDEXEDTRIANGLELIST {
    WORD  wV1;
    WORD  wV2;
    WORD  wV3;
    WORD  wFlags;
} D3DHAL_DP2INDEXEDTRIANGLELIST;

Members

wV1
Specifies the index into the vertex buffer location containing coordinate data for the first vertex of the triangle.
wV2
Specifies the index to the vertex buffer location containing coordinate data for the second vertex of the triangle.
wV3
Specifies the index to the vertex buffer location containing coordinate data for the third vertex of the triangle.
wFlags
Are the flags that describe how the driver should render the triangle. This member can be a bitwise OR of the following values:
Flag | Meaning
D3DTRIFLAG_EDGEENABLE1 | The driver should render the triangle edge between wV1 and wV2 when the fill mode is D3DFILL_WIREFRAME.
D3DTRIFLAG_EDGEENABLE2 | The driver should render the triangle edge between wV2 and wV3 when the fill mode is D3DFILL_WIREFRAME.
D3DTRIFLAG_EDGEENABLE3 | The driver should render the triangle edge between wV3 and wV1 when the fill mode is D3DFILL_WIREFRAME.
D3DTRIFLAG_EDGEENABLETRIANGLE | The driver should render all triangle edges when the fill mode is D3DFILL_WIREFRAME.

Comments

D3dDrawPrimitives2 should process wPrimitiveCount*3 indexes from the command buffer, processing wPrimitiveCount D3DHAL_DP2INDEXEDTRIANGLELIST structures. The value of wPrimitiveCount is specified in the D3DHAL_DP2COMMAND structure.

The driver should process a total of wPrimitiveCount*3 vertices from the vertex buffer, three vertices per triangle, for the current command. The sequence of triangles rendered is (wV10, wV20, wV30), (wV11, wV21, wV31), …, (wV1n, wV2n, wV3n), where n equals (wPrimitiveCount - 1). The driver should calculate the vertex locations based on the current command as follows:

  • When the command is D3DDP2OP_INDEXEDTRIANGLELIST, the indexes into the vertex buffer are relative to the vertex buffer offset specified by the dwVertexOffset member of the D3DHAL_DRAWPRIMITIVES2DATA structure.
  • When the command is D3DDP2OP_INDEXEDTRIANGLELIST2, there is a D3DHAL_DP2STARTVERTEX structure that immediately follows the command in the command buffer. The indexes into the vertex buffer are relative to the vertex buffer offset specified by dwVertexOffset plus the base offset obtained from the wVStart member of the D3DHAL_DP2STARTVERTEX structure.

The following figure shows a portion of a sample command buffer containing a D3DDP2OP_INDEXEDTRIANGLELIST command and two D3DHAL_DP2INDEXEDTRIANGLELIST structures. The driver should draw two triangles – with all edges enabled – using the following six vertices from the vertex buffer: (v[3], v[4], v[5]), (v[0], v[1], v[2]).

Similarly, the following figure shows a portion of a sample command buffer containing a D3DDP2OP_INDEXEDTRIANGLELIST2 command, a D3DHAL_DP2STARTVERTEX offset, and two D3DHAL_DP2INDEXEDTRIANGLELIST structures. The driver should process six vertices from the vertex buffer, rendering two triangles defined by (v[5], v[6], v[7]), (v[2], v[3], v[4]).


D3DHAL_DP2INDEXEDTRIANGLELIST2

One or more D3DHAL_DP2INDEXEDTRIANGLELIST2 structures are parsed from the command buffer by the D3dDrawPrimitives2 callback when the D3DHAL_DP2COMMAND structure's bCommand member is set to D3DDP2OP_INDEXEDTRIANGLELIST2, and are used to render a sequence of unconnected triangles using vertex indices.

typedef struct _D3DHAL_DP2INDEXEDTRIANGLELIST2 {
    WORD  wV1;
    WORD  wV2;
    WORD  wV3;
} D3DHAL_DP2INDEXEDTRIANGLELIST2, *LPD3DHAL_DP2INDEXEDTRIANGLELIST2;

Members

wV1
Specifies the index to the vertex buffer location containing coordinate data for the first vertex of the triangle.
wV2
Specifies the index to the vertex buffer location containing coordinate data for the second vertex of the triangle.
wV3
Specifies the index to the vertex buffer location containing coordinate data for the third vertex of the triangle.

Comments

The D3DHAL_DP2INDEXEDTRIANGLELIST2 structure specifies unconnected triangles to render with a vertex buffer. The vertex indexes are specified by wV1, wV2, and wV3. All edges are visible. The number of triangles to render (that is, the number of D3DHAL_DP2INDEXEDTRIANGLELIST2 structures to process) is specified by the wPrimitiveCount field of D3DHAL_DP2COMMAND. All indexes are relative to a vertex whose index is wVStart from D3DHAL_DP2STARTVERTEX. The sequence in the command stream is D3DHAL_DP2COMMAND followed by D3DHAL_DP2STARTVERTEX followed by wPrimitiveCount D3DHAL_DP2INDEXEDTRIANGLELIST2 structures.

The D3dDrawPrimitives2 callback parses D3DHAL_DP2INDEXEDTRIANGLELIST2 structure(s) from the command buffer and renders the triangles using vertex indexes when D3DHAL_DP2COMMAND is D3DDP2OP_INDEXEDTRIANGLELIST2. A D3DHAL_DP2STARTVERTEX structure immediately follows the D3DHAL_DP2COMMAND in the command stream. This allows a base index to be specified for all the indexes that follow it. Thus triangles can be easily relocated and no flags are necessary to specify the triangle edges as is the case with D3DDP2OP_INDEXEDTRIANGLELIST.


D3DHAL_DP2INDEXEDTRIANGLESTRIP

One or more D3DHAL_DP2INDEXEDTRIANGLESTRIP structures are parsed from the command buffer by the D3dDrawPrimitives2 callback when the D3DHAL_DP2COMMAND structure's bCommand member is set to D3DDP2OP_INDEXEDTRIANGLESTRIP, and are used to render strips of connected triangles using vertex indices.

typedef struct _D3DHAL_DP2INDEXEDTRIANGLESTRIP {
    WORD  wV[3];
} D3DHAL_DP2INDEXEDTRIANGLESTRIP;

Members

wV
Specifies the index into the vertex buffer containing coordinate data for the first vertex of the triangle strip.

Although this member has only enough space to contain three indexes, this array of indexes should be treated as a variable-sized array with (wPrimitiveCount + 2) elements. (wPrimitiveCount is a member of the D3DHAL_DP2COMMAND structure.)

Comments

D3dDrawPrimitives2 should process (wPrimitiveCount+2) indexes from the command buffer, in effect, processing wPrimitiveCount D3DHAL_DP2INDEXEDTRIANGLESTRIP structures.

The triangle edges in a triangle strip are rendered in this order: (wV[0], wV[1], wV[2]), (wV[1], wV[3], wV[2]), (wV[2], wV[3], wV[4]), (wV[3], wV[5], wV[4]),...

For the last triangle in the triangle strip, however, the edges will be rendered in different orders when wPrimitiveCount is odd and when it is even.

  • When wPrimitiveCount is an odd number, the last triangle's edges are rendered in this order: (wV[wPrimitiveCount - 1], wV[wPrimitiveCount], wV[wPrimitiveCount + 1]).
  • When wPrimitiveCount is an even number, the last triangle's edges are rendered in this order: (wV[wPrimitiveCount - 1], wV[wPrimitiveCount+1], wV[wPrimitiveCount]).

A D3DHAL_DP2STARTVERTEX structure immediately follows the command in the command buffer. The vertex buffer indexes are relative to the vertex buffer offset specified by the dwVertexOffset member of the D3DHAL_DRAWPRIMITIVES2DATA structure plus the base offset obtained from the wVStart member of the D3DHAL_DP2STARTVERTEX structure.

The following figure shows a portion of a sample command buffer containing a D3DDP2OP_INDEXEDTRIANGLESTRIP command, a D3DHAL_DP2STARTVERTEX offset of zero, and a logical list of D3DHAL_DP2INDEXEDTRIANGLESTRIP structures. The driver should process five vertices from the vertex buffer, rendering a strip of three triangles defined by (v[1], v[3], v[6]), (v[3], v[4], v[6]), (v[6], v[4], v[5]).


D3DHAL_DP2LINELIST

One D3DHAL_DP2LINELIST structure is parsed from the command buffer by the D3dDrawPrimitives2 callback when the D3DHAL_DP2COMMAND structure's bCommand member is set to D3DDP2OP_LINELIST, and is used to render unconnected line segments.

typedef struct _D3DHAL_DP2LINELIST {
    WORD  wVStart;
} D3DHAL_DP2LINELIST;

Members

wVStart
Specifies the index into the vertex buffer containing coordinate data for the initial vertex of the line list.

Comments

One D3DHAL_DP2LINELIST structure follows the D3DHAL_DP2COMMAND structure in the command buffer.

D3dDrawPrimitives2 should sequentially process a total of wPrimitiveCount*2 vertices from the vertex buffer, two vertices per line, rendering a total of wPrimitiveCount lines. Starting from the vertex buffer offset, the sequence of lines rendered is (wVStart, wVStart+1), (wVStart+2, wVStart+3),…, (wVStart+(wPrimitiveCount-1)*2, wVStart+(wPrimitiveCount*2-1)). The value of wPrimitiveCount is specified in the D3DHAL_DP2COMMAND structure.

The following figure shows a portion of a sample command buffer containing a D3DDP2OP_LINELIST command and one D3DHAL_DP2LINELIST structure. The driver should draw three lines using the following six vertices from the vertex buffer: (v[0], v[1]), (v[2], v[3]), (v[4], v[5]).


D3DHAL_DP2LINESTRIP

One D3DHAL_DP2LINESTRIP structure is parsed from the command buffer by the D3dDrawPrimitives2 callback when the D3DHAL_DP2COMMAND structure's bCommand member is set to D3DDP2OP_LINESTRIP, and is used to render the specified connected line segments.

typedef struct _D3DHAL_DP2LINESTRIP {
    WORD  wVStart;
} D3DHAL_DP2LINESTRIP;

Members

wVStart
Specifies the index into the vertex buffer containing coordinate data for the initial vertex of the line strip.

Comments

One D3DHAL_DP2LINESTRIP structure follows the D3DHAL_DP2COMMAND structure in the command buffer.

D3dDrawPrimitives2 should sequentially process a total of (wPrimitiveCount+1) vertices from the vertex buffer. Starting from the vertex buffer offset, the sequence of lines rendered is (wVStart, wVStart+1), (wVStart+1, wVStart+2), (wVStart+2, wVStart+3), …, (wVStart+(wPrimitiveCount-1), wVStart+wPrimitiveCount). The value of wPrimitiveCount is specified in the D3DHAL_DP2COMMAND structure.

The following figure shows a portion of a sample command buffer containing a D3DDP2OP_LINESTRIP command and one D3DHAL_DP2LINESTRIP structure. The driver should draw three connected lines using the following four vertices from the vertex buffer: (v[4], v[5]), (v[5], v[6]), (v[6], v[7]).


D3DHAL_DP2MULTIPLYTRANSFORM

DirectX 8.0 and later versions only.

The D3DHAL_DP2MULTIPLYTRANSFORM structure is used to modify the transform matrix for D3dDrawPrimitives2.

typedef struct _D3DHAL_DP2MULTIPLYTRANSFORM
{
    D3DTRANSFORMSTATETYPE xfrmType;  // which transform to multiply
    D3DMATRIX matrix;                // the matrix to multiply by
} D3DHAL_DP2MULTIPLYTRANSFORM, *LPD3DHAL_DP2MULTIPLYTRANSFORM;

Members

xfrmType
Specifies the current transform being modified.
Value | Meaning
D3DTRANSFORMSTATE_PROJECTION | Specifies the current projection transformation.
D3DTRANSFORMSTATE_VIEW | Specifies the current view transformation.
D3DTRANSFORMSTATE_WORLD | Specifies the current world transformation.

matrix
Specifies the matrix used to modify the current transform.

Comments

This structure is used with hardware transform and lighting and is used by the Direct3D run-time to inform the driver about modifications to the various transformation matrices.

See Also

D3DHAL_DP2SETTRANSFORM


D3DHAL_DP2PIXELSHADER

DirectX 8.0 and later versions only.

The D3DHAL_DP2PIXELSHADER structure is used to set the current pixel shader, or delete a pixel shader, depending on the opcode received (D3DDP2OP_SETPIXELSHADER or D3DDP2OP_DELETEPIXELSHADER) by D3dDrawPrimitives2.

typedef struct _D3DHAL_DP2PIXELSHADER
{
    // Pixel shader handle.
    // The handle could be 0, meaning that the current pixel
    // shader is invalid (not set).
    DWORD dwHandle;
} D3DHAL_DP2PIXELSHADER, *LPD3DHAL_DP2PIXELSHADER;

Member

dwHandle
Specifies the handle assigned by the runtime to the pixel shader to set or delete. For delete, the handle is guaranteed to be non-zero. For set, It is legal for this handle to be zero in which case the driver should unset any programmable pixel state and revert to fixed function pixel processing behavior (for example by using render states).

Comments

When switching from fixed function pixel processing to programmable vertex processing the values of, for example, legacy render states and texture stage states should be preserved. If and when a switch from programmable to fixed function pixel processing occurs (the driver receives a D3DDP2OP_SETPIXELSHADER with a shader handle of zero) that preserved state should be restored.

When switching between programmable shaders, any constant register that has a value specified in the definition of that shader should be set to that value. The values of all other constant registers should remain unchanged.

See Also

D3DHAL_DP2SETPIXELSHADERCONST, D3DHAL_DP2CREATEPIXELSHADER


D3DHAL_DP2POINTS

One or more D3DHAL_DP2POINTS structures are parsed from the command buffer by the D3dDrawPrimitives2 callback when the D3DHAL_DP2COMMAND structure's bCommand member is set to D3DDP2OP_POINTS, and are used to render the specified points.

typedef struct _D3DHAL_DP2POINTS {
    WORD  wCount;
    WORD  wVStart;
} D3DHAL_DP2POINTS;

Members

wCount
Specifies the number of points to render.
wVStart
Specifies the index into the vertex buffer containing coordinate data for the initial point.

Comments

D3dDrawPrimitives2 should process wPrimitiveCount D3DHAL_DP2POINTS structures from the command buffer. The value of wPrimitiveCount is specified in the D3DHAL_DP2COMMAND structure.

For each D3DHAL_DP2POINTS structure, D3dDrawPrimitives2 should sequentially process wCount vertices from the vertex buffer. Starting from the vertex buffer offset, the sequence of points rendered is wVStart, (wVStart+1), …, (wvStart+(wCount-1)).

The following figure shows a portion of a sample command buffer containing a D3DDP2OP_POINTS command and two D3DHAL_DP2POINTS structures. The driver should draw a total of seven points using the following vertices from the vertex buffer: v[2], v[3], v[4], v[7], v[8], v[9], v[10].


D3DHAL_DP2RENDERSTATE

One or more D3DHAL_DP2RENDERSTATE structures are parsed from the command buffer by the D3dDrawPrimitives2 callback when the D3DHAL_DP2COMMAND structure's bCommand member is set to D3DDP2OP_RENDERSTATE, and are used to set the appropriate render state.

typedef struct _D3DHAL_DP2RENDERSTATE {
    D3DRENDERSTATETYPE  RenderState;
    union
    {
        D3DVALUE  fState;
        DWORD  dwState;
    };
} D3DHAL_DP2RENDERSTATE;
‹ ›

Members

RenderState
Specifies a D3DRENDERSTATETYPE enumerated value that specifies the render state to be updated. The render states are described in the DirectX SDK documentation.
fState
Specifies the value that the driver should update the render state identified by the RenderState member with. This member is valid when RenderState requires a D3DVALUE.
dwState
Specifies the value that the driver should update the render state identified by RenderState to. This member is valid when RenderState requires a DWORD.

Comments

D3dDrawPrimitives2 should process wStateCount D3DHAL_DP2RENDERSTATE structures from the command buffer. The value of wStateCount is specified in the D3DHAL_DP2COMMAND structure.

For each D3DHAL_DP2RENDERSTATE structure, D3dDrawPrimitives2 should update the driver's private render state and the render state array that the lpdwRStates member of D3DHAL_DRAWPRIMITIVES2DATA points to. The element to be updated in the public render state array is lpdwRStates[RenderState].

The following figure shows a portion of a sample command buffer containing a D3DDP2OP_RENDERSTATE command and two D3DHAL_DP2RENDERSTATE structures. The driver should update lpdwRStates[D3DRENDERSTATE_FILLMODE] to be D3DFILL_SOLID and lpdwRStates[D3DRENDERSTATE_SHADEMODE] to be D3DSHADE_GOURAUD. The driver should also update its private state accordingly.

Although render states whose values are boolean in type are documented as only accepting TRUE(1) and FALSE(0) the runtime does not validate this and accepts any non-zero value as true. The sample driver interprets this strictly and does interpret values other than 1 as being TRUE. However, as the runtime does not offer validation your driver should interpret 0 as FALSE and any other non-zero value as TRUE. In this respect your driver should not mimic the behavior of the supplied sample driver.


D3DHAL_DP2SETCLIPPLANE

The D3DHAL_SETCLIPPLANE structure allows user defined clip planes to be used in world space.

typedef struct _D3DHAL_DP2SETCLIPPLANE {
    DWORD     dwIndex;
    D3DVALUE  plane[4];
} D3DHAL_DP2SETCLIPPLANE, *LPD3DHAL_DP2SETCLIPPLANE;
‹ ›

Members

dwIndex
Is the index of the clipping plane for which the plane equation coefficients will be set.
plane
Is a four-element array of the coefficients A, B, C, and D, in that order, in the general plane equation for the clipping plane.

Comments

The general plane equation in standard form is Ax + By + Cz + Dw = 0. A point with homogeneous coordinates (x, y, z, w) is visible in the half-space of this plane if Ax + By + Cz + Dw >= 0. Points that exist on or behind the clipping plane are clipped from the scene. That is, points for which Ax + By + Cz + Dw <= 0 are clipped.


D3DHAL_DP2SETINDICES

DirectX 8.0 and later versions only.

The D3DHAL_DP2SETINDICES structure is used to set the current index buffer for D3dDrawPrimitives2.

typedef struct _D3DHAL_DP2SETINDICES
{
    DWORD dwVBHandle;   // Index buffer handle
    DWORD dwStride;     // Index size in bytes (2 or 4)
} D3DHAL_DP2SETINDICES, *LPD3DHAL_DP2SETINDICES;

Member

dwVBHandle
Specifies the surface handle associated with this surface through a call to D3dCreateSurfaceEx.
dwStride
Specifies the size of the indices contained in the index buffer and will have the value 2 if the indices are 16-bit, or 4 if the indices are 32-bit quantities.

Comments

A handle value of zero is valid and indicates that the current index buffer is cleared. Subsequent attempts to draw indexed primitives (before a new current index buffer is established via another D3DDP2OP_SETINDICES token) should be handled by the driver such that a crash does not occur. The debug version of your driver should display informative messages to the debug output stream when this error condition is detected.


D3DHAL_DP2SETLIGHT

The D3DHAL_DP2SETLIGHT structure allows lights to be set for D3dDrawPrimitives2.

typedef struct _D3DHAL_DP2SETLIGHT {
    DWORD  dwIndex;
    DWORD  dwDataType;
} D3DHAL_DP2SETLIGHT, *LPD3DHAL_DP2SETLIGHT;
‹ ›

Members

dwIndex
Specifies an index into an array of lights.
dwDataType
Specifies the type of data being passed.
Value | Meaning
D3DHAL_SETLIGHT_DATA | Specifies that a D3DLIGHT7 (described in the Platform SDK documentation) structure defining the light will follow immediately in the command stream.
D3DHAL_SETLIGHT_ENABLE | Enables the light whose index is specified in dwIndex.
D3DHAL_SETLIGHT_DISABLE | Disables the light whose index is specified in dwIndex.


D3DHAL_DP2SETPALETTE

The D3DHAL_DP2SETPALETTE structure is used to associate a palette with a texture when a driver responds to D3DDP2OP_SETPALETTE in D3dDrawPrimitives2. This opcode is used to map an association between a palette handle and a surface handle, and specify the characteristics of the palette.

typedef struct _D3DHAL_DP2SETPALETTE {
    DWORD  dwPaletteHandle;
    DWORD  dwPaletteFlags;
    DWORD  dwSurfaceHandle;
} D3DHAL_DP2SETPALETTE, *LPD3DHAL_DP2SETPALETTE;
‹ ›

Members

dwPaletteHandle
Specifies a handle to the palette to be set up. If the value is zero, the surface specified by dwSurfaceHandle should be uncoupled from any palette it might have been associated with previously.
dwPaletteFlags
Is a set of flags that specify the attributes of the palette.
Flag | Meaning
DDRAWIPAL_2 | The palette has 2 entries. Currently unused.
DDRAWIPAL_4 | The palette has 4 entries. Currently unused.
DDRAWIPAL_16 | The palette has 16 entries. Currently unused.
DDRAWIPAL_256 | The palette has 256 entries. Currently unused.
DDRAWIPAL_ALLOW256 | The palette can be fully updated. Currently unused.
DDRAWIPAL_ALPHA | The palette's alpha data channel is valid and should be used.
DDRAWIPAL_DIRTY | The palette has been changed so the GDI palette is out of sync. Currently unused.
DDRAWIPAL_EXCLUSIVE | The palette is being used in exclusive mode. Currently unused.
DDRAWIPAL_GDI | The palette is allocated through GDI. Currently unused.
DDRAWIPAL_INHEL | The palette is done in the HEL (hardware emulation layer). Currently unused.
DDRAWIPAL_STORED_8 | The palette is stored using 8 bpp per entry. Currently unused.
DDRAWIPAL_STORED_16 | The palette is stored using 16 bpp per entry. Currently unused.
DDRAWIPAL_STORED_24 | The palette is stored using 24 bpp per entry. Currently unused.
DDRAWIPAL_STORED_8INDEX | The palette is stored as an 8-bit index into a destination palette. Currently unused.

dwSurfaceHandle
Specifies a handle to the Direct3D surface (texture) that this palette (identified by dwPaletteHandle) is associated to.

Comments

The number of D3DHAL_DP2SETPALETTE structures to follow is specified by the wStateCount member of the D3DHAL_DP2COMMAND structure that precedes them in the command stream.


D3DHAL_DP2SETPIXELSHADERCONST

DirectX 8.0 and later versions only.

The D3DHAL_DP2SETPIXELSHADERCONST structure is used to set one or more of the pixel shader constant registers when the D3DDP2OP_SETPIXELSHADERCONST opcode is received by D3dDrawPrimitives2.

typedef struct _D3DHAL_DP2SETPIXELSHADERCONST
{
    DWORD dwRegister;   // Const register to start copying
    DWORD dwCount;      // Number of 4-float vectors to copy
    // Data follows
} D3DHAL_DP2SETPIXELSHADERCONST, *LPD3DHAL_DP2SETPIXELSHADERCONST;

Member

dwRegister
Specifies the index of the first register to set.
dwCount
Specifies gives the number of registers to set. Immediately following this data structure in the DP2 stream are dwCount vectors of four single precision floating point numbers. This is the data to copy to the target registers.

Comments

The runtime passes the first register to set and the number of registers to set. The actual data to copy to those registers consists of vectors of four, single precision floating point numbers. These vectors (the same number as there are registers to set) follow this token and its associated data structure in the DP2 stream.

The runtime validates that the specified register range lies within the legal range for the version of the current pixel shader.

See Also

D3DHAL_DP2PIXELSHADER, D3DHAL_DP2CREATEPIXELSHADER


D3DHAL_DP2SETPRIORITY

The D3DHAL_DP2SETPRIORITY structure is used to inform the driver of the priority of the texture specified by the handle dwDDDestSurface.

typedef struct _D3DHAL_DP2SETPRIORITY {
    DWORD  dwDDDestSurface;
    DWORD  dwPriority;
} D3DHAL_DP2SETPRIORITY, *LPD3DHAL_DP2SETPRIORITY;
‹ ›

Members

dwDDDestSurface
Specifies the handle of the texture.
dwPriority
Specifies the priority of the dwDDDestSurface texture.

Comments

Drivers are notified of handles at texture creation time. The driver can expect to receive priority notifications only for driver-managed textures.

Priorities are used to determine when managed textures are to be evicted from memory. A texture assigned a low priority will be evicted before a texture with a high priority. If two textures have the same priority, the texture that was used more recently is kept in memory; the other texture is evicted.


D3DHAL_DP2SETRENDERTARGET

The D3DHAL_DP2SETRENDERTARGET structure is used with the D3DDP2OP_SETRENDERTARGET opcode to map a new rendering target surface and depth buffer in the current context.

typedef struct _D3DHAL_DP2SETRENDERTARGET {
    DWORD  hRenderTarget;
    DWORD  hZBuffer;
} D3DHAL_DP2SETRENDERTARGET, *LPD3DHAL_DP2SETRENDERTARGET;
‹ ›

Members

hRenderTarget
Is a handle to the rendering target.
hZBuffer
Is a handle to the depth buffer.

Comments

The driver should carry out the following tasks in response to a D3DDP2OP_SETRENDERTARGET opcode in the D3dDrawPrimitives2 command stream:

  1. Store the rendering target identified by hRenderTarget in the driver's context.
  2. Store the depth buffer identified by hZBuffer in the driver's context.

See the p3samp sample driver that ships with this DDK for more implementation details.


D3DHAL_DP2SETSTREAMSOURCE

DirectX 8.0 and later versions only.

The D3DHAL_DP2SETSTREAMSOURCE structure is used to bind a vertex stream source to a vertex buffer for D3dDrawPrimitives2.

typedef struct _D3DHAL_DP2SETSTREAMSOURCE
{
    DWORD dwStream;     // Stream index, starting from zero
    DWORD dwVBHandle;   // Vertex buffer handle
    DWORD dwStride;     // Vertex stride
} D3DHAL_DP2SETSTREAMSOURCE, *LPD3DHAL_DP2SETSTREAMSOURCE;

Member

dwStream
Specifies stream being bound. It will have a value between zero and the maximum number of streams specified by the driver.
dwVBHandle
Specifies the vertex buffer handle. It is legal for the vertex buffer handle to be zero, in which case the stream is no longer bound to a vertex buffer.
dwStride
Specifies the vertex size in bytes.

Comments

A driver is notified of the binding of a vertex buffer to a particular stream through a new DP2 token, D3DDP2OP_SETSTREAMSOURCE.

The debug runtime validates that dwStream is within the legal range but the retail version does not, so validation must be present in the driver. DirectX 8.0 does not define the behavior of the driver or hardware in the error case where the stream index given is larger than the maximum stream supported by the hardware (as reported through MaxStreams in D3DCAPS8) beyond requiring that the driver and hardware combination not fault or hang in this case and that, on restoration of correct state the driver and hardware combination should continue to operate normally. Debug versions of your display driver should display messages in the debug output stream indicating when this problem has been detected.

The runtime does not validate that the streams accessed by the current vertex shader are non-NULL. It is the responsibility of the driver writer to ensure the driver/hardware does not crash when this error case arises. Debug versions of your display driver should display messages in the debug output stream to indicate when this problem has been detected.

It is guaranteed that only a single stream source will be set by a D3DHAL_DP2COMMAND. That is, the wStateCount field of the D3DHAL_DP2COMMAND will always be one when bCommand is D3DDP2OP_SETSTREAMSOURCE.

See Also

D3DHAL_DP2SETSTREAMSOURCEUM


D3DHAL_DP2SETSTREAMSOURCEUM

DirectX 8.0 and later versions only.

The D3DHAL_DP2SETSTREAMSOURCEUM structure is used to bind a vertex stream source to a user memory buffer for D3dDrawPrimitives2.

typedef struct _D3DHAL_DP2SETSTREAMSOURCEUM
{
    DWORD dwStream;     // Stream index, starting from zero
    DWORD dwStride;     // Vertex stride
} D3DHAL_DP2SETSTREAMSOURCEUM, *LPD3DHAL_DP2SETSTREAMSOURCEUM;

Member

dwStream
Specifies stream being bound. For DirectX 8.0 it will always be zero.
dwStride
Specifies the vertex size in bytes.

Comments

In addition to binding a stream to a vertex buffer, it is possible for the vertex data of stream zero to be supplied in a user memory (UM) buffer. In this case, another DP2 token is used to notify the driver of stream binding. That token is D3DDP2OP_SETSTREAMSOURCEUM.

DirectX 8.0 does not support multiple vertex streams with user supplied buffers rather than vertex buffers. Additionally, it is not possible to mix user memory buffers with vertex buffers. When a user memory buffer is supplied, it is guaranteed to be stream zero and to be the only stream that should be accessed by subsequent drawing primitives. It is possible that other streams will have non-NULL vertex buffers bound to them at the time when a user memory buffer is bound to stream. However, those other streams must be ignored by the driver and hardware.

The actual user memory pointer to the vertex data should be extracted from the D3DHAL_DRAWPRIMITIVES2DATA passed when actually drawing primitives.

See Also

D3DHAL_DP2SETSTREAMSOURCE


D3DHAL_DP2SETTEXLOD

The D3DHAL_DP2SETTEXLOD structure is used to set the level of detail (LOD) for MIP maps when the D3DDP2OP_SETTEXLOD command is sent to D3dDrawPrimitives2.

typedef struct _D3DHAL_DP2SETTEXLOD {
    DWORD  dwDDSurface;
    DWORD  dwLOD;
} D3DHAL_DP2SETTEXLOD, *LPD3DHAL_DP2SETTEXLOD;

Members

dwDDSurface
Specifies a handle to a surface chain.
dwLOD
Controls the maximum MIP level loaded into video memory. Hence, if the most detailed MIP map in the chain has dimensions 256x256, setting the maximum level to 2 means that the largest MIP map ever present in video memory has dimensions 64x64.

Comments

Used only for driver-managed textures. This structure contains a surface handle to the MIP map and the maximum level of detail to set.


D3DHAL_DP2SETTRANSFORM

D3DHAL_DP2SETTRANSFORM structure is used to specify the transform state and matrix for D3dDrawPrimitives2.

typedef struct _D3DHAL_DP2SETTRANSFORM {
    D3DTRANSFORMSTATETYPE  xfrmType;
    D3DMATRIX  matrix;
} D3DHAL_DP2SETTRANSFORM, *LPD3DHAL_DP2SETTRANSFORM;
‹ ›

Members

xfrmType
Specifies the type of transform being done.
Value | Meaning
D3DTRANSFORMSTATE_PROJECTION | Specifies a projection transformation.
D3DTRANSFORMSTATE_VIEW | Specifies a view transformation.
D3DTRANSFORMSTATE_WORLD | Specifies a world transformation.

matrix
Specifies the matrix used to perform the transform.

Comments

This structure is used with hardware transform and lighting and is used by the Direct3D run-time to inform the driver about the various transformation matrices.

See Also

D3DHAL_DP2MULTIPLYTRANSFORM


D3DHAL_DP2SETVERTEXSHADERCONST

DirectX 8.0 and later versions only.

The D3DHAL_DP2SETVERTEXSHADERCONST structure is used to set one or more of the vertex shader constant registers when the D3DDP2OP_SETVERTEXSHADERCONST opcode is received by D3dDrawPrimitives2.

typedef struct _D3DHAL_DP2SETVERTEXSHADERCONST
{
    DWORD dwRegister;     // Const register to start copying
    DWORD dwCount;         // Number of 4-float vectors to copy
    // Data follows
} D3DHAL_DP2SETVERTEXSHADERCONST, *LPD3DHAL_DP2SETVERTEXSHADERCONST;

Member

dwRegister
Specifies the index of the first vertex shader constant to have its value sent.
dwCount
Specifies the number of constant registers to set and, hence, the number of four element, single precision float vectors to read from the DP2 stream.

Comments

A start register and register count are given. One or more vectors of four single precision floating point values immediately follow the D3DHAL_DP2SETVERTEXSHADERCONST data structure in the DP2 stream.

The runtime validates that the range of registers specified is legal given the level of vertex shader support reported to the driver. Furthermore, if the driver does not support any form of programmable vertex processing the runtime will not send this token to the driver.

See Also

D3DHAL_DP2VERTEXSHADER, D3DHAL_DP2CREATEVERTEXSHADER


D3DHAL_DP2STARTVERTEX

A D3DHAL_DP2STARTVERTEX structure follows certain D3DHAL_DP2COMMAND structures in the command buffer, and indicates the offset in the vertex buffer for the first vertex to use in D3dDrawPrimitives2.

typedef struct _D3DHAL_DP2STARTVERTEX {
    WORD  wVStart;
} D3DHAL_DP2STARTVERTEX, *LPD3DHAL_DP2STARTVERTEX;

Members

wVStart
Specifies an additional offset to be added to any index used for determining the location of vertices in the vertex buffer (in the case of indexed primitives).

Comments

A D3DHAL_DP2STARTVERTEX structure follows a D3DHAL_DP2COMMAND structure in the command buffer when the bCommand member of D3DHAL_DP2COMMAND is one of the following values:

  • D3DDP2OP_INDEXEDLINELIST2
  • D3DDP2OP_INDEXEDLINESTRIP
  • D3DDP2OP_INDEXEDTRIANGLELIST2
  • D3DDP2OP_INDEXEDTRIANGLESTRIP
  • D3DDP2OP_INDEXEDTRIANGLEFAN

The first vertex of such primitives is located (wVStart + dwVertexOffset) bytes from the beginning of the vertex buffer, where dwVertexOffset is a member of D3DHAL_DRAWPRIMITIVES2DATA.


D3DHAL_DP2STATESET

The D3DHAL_DP2STATESET structure is used to inform the driver about stateset operations to perform.

typedef struct _D3DHAL_DP2STATESET {
    DWORD              dwOperation;
    DWORD              dwParam;
    D3DSTATEBLOCKTYPE  sbType;
} D3DHAL_DP2STATESET, *LPD3DHAL_DP2STATESET;
‹ ›

Members

dwOperation
Specifies the operation to perform. The value of this member can be one of the following:
Value | Meaning
D3DHAL_STATESETBEGIN | Specifies the beginning of the stateset referenced by dwParam.
D3DHAL_STATESETCAPTURE | Specifies that capture is to be done. When this flag is specified, the driver must capture a snapshot of the current state that matches the state block referenced by the handle passed in dwParam. That is, only the state that is specified in the state block is captured. See Accelerated State Management for important details about state capture.
D3DHAL_STATESETCREATE DirectX 8.0 and later versions only.

On receipt of this request the driver should create a state block of the type given in the field sbType. The information to record for each state block type is described below.
D3DHAL_STATESETDELETE | Specifies that the stateset referenced by dwParam should be deleted.
D3DHAL_STATESETEND | Specifies the end of the stateset referenced by dwParam.
D3DHAL_STATESETEXECUTE | Specifies that the stateset referenced by dwParam should be executed.

dwParam
Specifies the stateset handle that references the state block being manipulated with the current dwOperation.
sbType
The driver should ignore this member unless it implements render state extensions, or implements Pure Device Support (DirectX 8.0 and later versions only).

If the driver implements extended render states, that is, render states beyond those the Direct3D run-time supplies, it can use sbType to determine what types of predefined render states are being used. From this information the driver can determine how to append the state block appropriately, to support its extensions.

The sbType member, which is valid only for D3DHAL_STATESETBEGIN, D3DHAL_STATESETEND, and D3DHAL_STATECREATE, specifies the state block type with one of the following D3DSTATEBLOCKTYPE enumerated types. For more details see the DirectX SDK documentation.
Value | Meaning
D3DSBT_ALL Signals the driver to capture all state.

When requested to capture all state in pure device mode the driver should capture all state with the exception of the current vertex stream state, the current index stream state and the currently realized textures.

The state that should be captured is as follows; the render states listed below, the texture stage states listed below, the viewport, all the world transforms, the view transform, the projection transform, the texture transform for all texture stages, all user clip planes, the current material, all lights that have been used prior to the state block creation, the current vertex shader handle, the current pixel shader handle, the current vertex shader constants and the current pixel shader constants.

The render states to record are as follows:

D3DRENDERSTATE_SPECULARENABLE
D3DRENDERSTATE_ZENABLE
D3DRENDERSTATE_FILLMODE
D3DRENDERSTATE_SHADEMODE
D3DRENDERSTATE_LINEPATTERN
D3DRENDERSTATE_ZWRITEENABLE
D3DRENDERSTATE_ALPHATESTENABLE
D3DRENDERSTATE_LASTPIXEL
D3DRENDERSTATE_SRCBLEND
D3DRENDERSTATE_DESTBLEND
D3DRENDERSTATE_CULLMODE
D3DRENDERSTATE_ZFUNC
D3DRENDERSTATE_ALPHAREF
D3DRENDERSTATE_ALPHAFUNC
D3DRENDERSTATE_DITHERENABLE
D3DRENDERSTATE_FOGENABLE
D3DRENDERSTATE_STIPPLEDALPHA
D3DRENDERSTATE_FOGCOLOR
D3DRENDERSTATE_FOGTABLEMODE
D3DRENDERSTATE_FOGSTART
D3DRENDERSTATE_FOGEND
D3DRENDERSTATE_FOGDENSITY
D3DRENDERSTATE_EDGEANTIALIAS
D3DRENDERSTATE_ALPHABLENDENABLE
D3DRENDERSTATE_ZBIAS
D3DRENDERSTATE_RANGEFOGENABLE
D3DRENDERSTATE_STENCILENABLE
D3DRENDERSTATE_STENCILFAIL
D3DRENDERSTATE_STENCILZFAIL
D3DRENDERSTATE_STENCILPASS
D3DRENDERSTATE_STENCILFUNC
D3DRENDERSTATE_STENCILREF
D3DRENDERSTATE_STENCILMASK
D3DRENDERSTATE_STENCILWRITEMASK
D3DRENDERSTATE_TEXTUREFACTOR
D3DRENDERSTATE_WRAP0
D3DRENDERSTATE_WRAP1
D3DRENDERSTATE_WRAP2
D3DRENDERSTATE_WRAP3
D3DRENDERSTATE_WRAP4
D3DRENDERSTATE_WRAP5
D3DRENDERSTATE_WRAP6
D3DRENDERSTATE_WRAP7
D3DRENDERSTATE_AMBIENT
D3DRENDERSTATE_COLORVERTEX
D3DRENDERSTATE_FOGVERTEXMODE
D3DRENDERSTATE_CLIPPING
D3DRENDERSTATE_LIGHTING
D3DRENDERSTATE_NORMALIZENORMALS
D3DRENDERSTATE_LOCALVIEWER
D3DRENDERSTATE_EMISSIVEMATERIALSOURCE
D3DRENDERSTATE_AMBIENTMATERIALSOURCE
D3DRENDERSTATE_DIFFUSEMATERIALSOURCE
D3DRENDERSTATE_SPECULARMATERIALSOURCE
D3DRENDERSTATE_VERTEXBLEND
D3DRENDERSTATE_CLIPPLANEENABLE
D3DRS_SOFTWAREVERTEXPROCESSING
D3DRS_POINTSIZE
D3DRS_POINTSIZE_MIN
D3DRS_POINTSPRITEENABLE
D3DRS_POINTSCALEENABLE
D3DRS_POINTSCALE_A
D3DRS_POINTSCALE_B
D3DRS_POINTSCALE_C
D3DRS_MULTISAMPLEANTIALIAS
D3DRS_MULTISAMPLEMASK
D3DRS_PATCHEDGESTYLE
D3DRS_PATCHSEGMENTS
D3DRS_POINTSIZE_MAX
D3DRS_INDEXEDVERTEXBLENDENABLE
D3DRS_COLORWRITEENABLE
D3DRS_TWEENFACTOR
D3DRS_BLENDOP

The texture stage states to record are as follows:

D3DTSS_COLOROP
D3DTSS_COLORARG1
D3DTSS_COLORARG2
D3DTSS_ALPHAOP
D3DTSS_ALPHAARG1
D3DTSS_ALPHAARG2
D3DTSS_BUMPENVMAT00
D3DTSS_BUMPENVMAT01
D3DTSS_BUMPENVMAT10
D3DTSS_BUMPENVMAT11
D3DTSS_TEXCOORDINDEX
D3DTSS_ADDRESSU
D3DTSS_ADDRESSV
D3DTSS_BORDERCOLOR
D3DTSS_MAGFILTER
D3DTSS_MINFILTER
D3DTSS_MIPFILTER
D3DTSS_MIPMAPLODBIAS
D3DTSS_MAXMIPLEVEL
D3DTSS_MAXANISOTROPY
D3DTSS_BUMPENVLSCALE
D3DTSS_BUMPENVLOFFSET
D3DTSS_TEXTURETRANSFORMFLAGS
D3DTSS_ADDRESSW
D3DTSS_COLORARG0
D3DTSS_ALPHAARG0
D3DTSS_RESULTARG
D3DSBT_PIXELSTATE Signals the driver to capture pixel state only.

When capturing pixel state in pure device mode the following state should be captured; the pixel processing related render states listed below, the pixel processing texture stage states listed below, the current pixel shader handle and the current pixel shader constants.

The render states to record are as follows:

D3DRENDERSTATE_ZENABLE
D3DRENDERSTATE_FILLMODE
D3DRENDERSTATE_SHADEMODE
D3DRENDERSTATE_LINEPATTERN
D3DRENDERSTATE_ZWRITEENABLE
D3DRENDERSTATE_ALPHATESTENABLE
D3DRENDERSTATE_LASTPIXEL
D3DRENDERSTATE_SRCBLEND
D3DRENDERSTATE_DESTBLEND
D3DRENDERSTATE_ZFUNC
D3DRENDERSTATE_ALPHAREF
D3DRENDERSTATE_ALPHAFUNC
D3DRENDERSTATE_DITHERENABLE
D3DRENDERSTATE_STIPPLEDALPHA
D3DRENDERSTATE_FOGSTART
D3DRENDERSTATE_FOGEND
D3DRENDERSTATE_FOGDENSITY
D3DRENDERSTATE_EDGEANTIALIAS
D3DRENDERSTATE_ALPHABLENDENABLE
D3DRENDERSTATE_ZBIAS
D3DRENDERSTATE_STENCILENABLE
D3DRENDERSTATE_STENCILFAIL
D3DRENDERSTATE_STENCILZFAIL
D3DRENDERSTATE_STENCILPASS
D3DRENDERSTATE_STENCILFUNC
D3DRENDERSTATE_STENCILREF
D3DRENDERSTATE_STENCILMASK
D3DRENDERSTATE_STENCILWRITEMASK
D3DRENDERSTATE_TEXTUREFACTOR
D3DRENDERSTATE_WRAP0
D3DRENDERSTATE_WRAP1
D3DRENDERSTATE_WRAP2
D3DRENDERSTATE_WRAP3
D3DRENDERSTATE_WRAP4
D3DRENDERSTATE_WRAP5
D3DRENDERSTATE_WRAP6
D3DRENDERSTATE_WRAP7
D3DRS_COLORWRITEENABLE
D3DRS_BLENDOP

The texture stage states to record are as follows:

D3DTSS_COLOROP
D3DTSS_COLORARG1
D3DTSS_COLORARG2
D3DTSS_ALPHAOP
D3DTSS_ALPHAARG1
D3DTSS_ALPHAARG2
D3DTSS_BUMPENVMAT00
D3DTSS_BUMPENVMAT01
D3DTSS_BUMPENVMAT10
D3DTSS_BUMPENVMAT11
D3DTSS_TEXCOORDINDEX
D3DTSS_ADDRESSU
D3DTSS_ADDRESSV
D3DTSS_BORDERCOLOR
D3DTSS_MAGFILTER
D3DTSS_MINFILTER
D3DTSS_MIPFILTER
D3DTSS_MIPMAPLODBIAS
D3DTSS_MAXMIPLEVEL
D3DTSS_MAXANISOTROPY
D3DTSS_BUMPENVLSCALE
D3DTSS_BUMPENVLOFFSET
D3DTSS_TEXTURETRANSFORMFLAGS
D3DTSS_ADDRESSW
D3DTSS_COLORARG0
D3DTSS_ALPHAARG0
D3DTSS_RESULTARG
D3DSBT_VERTEXSTATE Signals the driver to capture vertex state only.

When capturing vertex state in pure device mode the following state should be captured; the vertex processing related render states listed below, the vertex processing texture stage states listed below, all lights that have been used prior to the state block creation, the current vertex shader handle and the current vertex shader constants.

The render states to record are as follows:

D3DRENDERSTATE_SHADEMODE
D3DRENDERSTATE_SPECULARENABLE
D3DRENDERSTATE_CULLMODE
D3DRENDERSTATE_FOGENABLE
D3DRENDERSTATE_FOGCOLOR
D3DRENDERSTATE_FOGTABLEMODE
D3DRENDERSTATE_FOGSTART
D3DRENDERSTATE_FOGEND
D3DRENDERSTATE_FOGDENSITY
D3DRENDERSTATE_RANGEFOGENABLE
D3DRENDERSTATE_AMBIENT
D3DRENDERSTATE_COLORVERTEX
D3DRENDERSTATE_FOGVERTEXMODE
D3DRENDERSTATE_CLIPPING
D3DRENDERSTATE_LIGHTING
D3DRENDERSTATE_NORMALIZENORMALS
D3DRENDERSTATE_LOCALVIEWER
D3DRENDERSTATE_EMISSIVEMATERIALSOURCE
D3DRENDERSTATE_AMBIENTMATERIALSOURCE
D3DRENDERSTATE_DIFFUSEMATERIALSOURCE
D3DRENDERSTATE_SPECULARMATERIALSOURCE
D3DRENDERSTATE_VERTEXBLEND
D3DRENDERSTATE_CLIPPLANEENABLE
D3DRS_SOFTWAREVERTEXPROCESSING
D3DRS_POINTSIZE
D3DRS_POINTSIZE_MIN
D3DRS_POINTSPRITEENABLE
D3DRS_POINTSCALEENABLE
D3DRS_POINTSCALE_A
D3DRS_POINTSCALE_B
D3DRS_POINTSCALE_C
D3DRS_MULTISAMPLEANTIALIAS
D3DRS_MULTISAMPLEMASK
D3DRS_PATCHEDGESTYLE
D3DRS_PATCHSEGMENTS
D3DRS_POINTSIZE_MAX
D3DRS_INDEXEDVERTEXBLENDENABLE
D3DRS_TWEENFACTOR

The texture stage states to record are as follows:

D3DTSS_TEXCOORDINDEX
D3DTSS_TEXTURETRANSFORMFLAGS
NULL | No predefined state group is specified.

Comments

See Accelerated State Management in the Graphics Design Guide for more information about the use of this structure in state block management.


D3DHAL_DP2TEXBLT

The D3DHAL_DP2TEXBLT structure is used for texture blts when D3dDrawPrimitives2 responds to the D3DDP2OP_TEXBLT command token.

typedef struct _D3DHAL_DP2TEXBLT {
    DWORD  dwDDDestSurface;
    DWORD  dwDDSrcSurface;
    POINT  pDest;
    RECTL  rSrc;
    DWORD  dwFlags;
} D3DHAL_DP2TEXBLT, *LPD3DHAL_DP2TEXBLT;
‹ ›

Members

dwDDDestSurface
Specifies the handle to the destination texture.
dwDDSrcSurface
Specifies the handle to the source texture.
pDest
Specifies the destination point where the blt should be performed; that is, the point in the destination surface (dwDDDestSurface) to begin the blt.
rSrc
Specifies the rectangle to be blitted in the source texture; that is, the source rectangle in the source surface (dwDDSrcSurface) to blt from.
dwFlags
Is reserved for system use.

Comments

The D3dCreateSurfaceEx callback creates the small integer handles to the textures that can be used as source and destination textures for texture blts.

The D3DHAL_DP2TEXBLT structure is used with a D3DDP2OP_TEXBLT command stream token to inform the drivers to perform a blt operation from a source texture to a destination texture. A texture can also be cubic environment map. The driver should copy a rectangle specified by rSrc in the source texture to the location specified by pDest in the destination texture. The destination and source textures are identified by handles that the driver was notified with during texture creation time. If the driver is capable of managing textures, then it is possible that the destination handle is 0. This indicates to the driver that it should preload the texture into video memory (or wherever the hardware efficiently textures from). In this case, the driver can ignore rSrc and pDest.

Note that for MIP mapped textures, only one D3DDP2OP_TEXBLT instruction is inserted into the D3dDrawPrimitives2 command stream. In this case, the driver is expected to blt all the MIP map levels present in the texture. The regions to be copied in MIP map sub-levels can be obtained by dividing rSrc and pDest by 2 at each level.

It is possible that the source and destination textures may contain different number of MIP map levels. In this case, the driver is expected to blt the common levels. For example, if a 256x256 source texture has 8 MIP map levels, and if the destination is a 64x64 texture with 6 levels, then the driver should blt the 6 corresponding levels from the source. The driver can expect the dimensions of the top MIP level of the destination texture to always be less than or equal to the dimensions of the top MIP level of the source texture.

Note that the source and destination handles always refer to the top level surfaces and never to any MIP map sub-level. Due to an error in the application, it is possible that the destination texture contains extra MIP map levels. For instance, a source 256x256 texture may contain five levels, but the destination 256x256 texture may contain eight. The driver is expected to safely handle this case, but it is not expected to produce correct results. Due to legacy application compatibility issues, Direct3D does not prevent such source/destination texture pairs from being passed on to the driver.

The driver can expect the pixel formats of the source and destination textures to be identical and, in general, the specified blt will be safe to perform. Other than the single case mentioned above, the driver should not expect to be presented with any situation that makes it impossible to perform a blt. The hope of this is to ensure that the driver's TexBlt implementation is as efficient as possible.

If the driver wishes to perform asynchronous blts from system memory to video memory, then it should implement the DirectDraw® HAL call GetSysmemBltStatus, otherwise inconsistencies may arise.

With TexBlt it is not necessary for the driver to perform any synchronization because TexBlts are always issued in the proper order along with rendering commands. Before this, it was necessary for the driver to correctly handle the case when a DirectDraw blt modified any texture that was referenced by rendering commands in any Direct3D context. When multiple contexts are present, Direct3D will not issue TexBlts. This means that the driver writer can omit synchronization code in the TexBlt code path (but will still need syncing for blts).

Sample

The following pseudo code in shows how a subrectangle should be computed for consecutive MIP levels, to go to MIP level i + 1 from MIP level i:

rect.left >>= 1;
rect.top >>= 1;
DWORD right = (rect.right + 1) >> 1;
DWORD bottom = (rect.bottom + 1) >> 1;
rect.right = ((right - rect.left) < 1) ? (rect.left + 1) : (right);
rect.bottom = ((bottom - rect.top ) < 1) ? (rect.top + 1) : (bottom);


D3DHAL_DP2TEXTURESTAGESTATE

One or more D3DHAL_DP2TEXTURESTAGESTATE structures are parsed from the command buffer by the D3dDrawPrimitives2 callback when the D3DHAL_DP2COMMAND structure's bCommand member is set to D3DDP2OP_TEXTURESTAGESTATE, and are used to set the appropriate texture stage state.

typedef struct _D3DHAL_DP2TEXTURESTAGESTATE {
    DWORD                     dwStage;
    D3DTEXTURESTAGESTATETYPE  TSState;
    DWORD                     dwValue;
} D3DHAL_DP2TEXTURESTAGESTATE;

Members

dwStage
Identifies the texture stage where to update the texture state. This member can be an integer in the range 0 through 7, with the highest numbered texture being closest to the frame buffer.
TSState
Specifies a D3DTEXTURESTAGESTATETYPE enumerated value, described in the DirectX SDK documentation, that specifies the texture state to be updated.
dwValue
Specifies the value that the driver should update the texture state identified by TSState to.

Comments

D3dDrawPrimitives2 should process wStateCount D3DHAL_DP2TEXTURESTAGESTATE structures from the command buffer. The value of wStateCount is specified in the D3DHAL_DP2COMMAND structure.

For each D3DHAL_DP2TEXTURESTAGESTATE structure, D3dDrawPrimitives2 should update the driver's internal texture state associated with the texture at dwStage to reflect the new value based on TSState.

Drivers that do not support multi-texturing should implement support for texture stage 0 only.

The following figure shows a portion of a sample command buffer containing a D3DDP2OP_TEXTURESTAGESTATE command and three D3DHAL_DP2TEXTURESTAGESTATE structures. The driver should update stages zero and three of its private texture stage state accordingly.


D3DHAL_DP2TRIANGLEFAN

One D3DHAL_DP2TRIANGLEFAN structure is parsed from the command buffer by the D3dDrawPrimitives2 callback when the D3DHAL_DP2COMMAND structure's bCommand member is set to D3DDP2OP_TRIANGLEFAN, and is used to render a triangle fan.

typedef struct _D3DHAL_DP2TRIANGLEFAN {
    WORD  vVStart;
} D3DHAL_DP2TRIANGLEFAN;

Members

vVStart
Specifies the index into the vertex buffer containing coordinate data for the initial vertex of the triangle fan.

Comments

One D3DHAL_DP2TRIANGLEFAN structure follows the D3DHAL_DP2COMMAND structure in the command buffer.

D3dDrawPrimitives2 should process a total of wPrimitiveCount+2 vertices from the vertex buffer, three vertices per triangle, rendering wPrimitiveCount triangles. Starting from the vertex buffer offset, the sequence of triangles rendered is (wVStart+1, wVStart+2, wVStart), (wVStart+2, wVStart+3, wVStart),…, (wVStart+wPrimitiveCount, wVStart+wPrimitiveCount+1, wVStart). The value of wPrimitiveCount is specified in the D3DHAL_DP2COMMAND structure.

The following figure shows a portion of a sample command buffer containing a D3DDP2OP_TRIANGLEFAN command and a D3DHAL_DP2TRIANGLEFAN structure. The driver should process six vertices from the vertex buffer, rendering a fan with four triangles defined by (v[3], v[4], v[2]), (v[4], v[5], v[2]), (v[5], v[6], v[2]), (v[6], v[7], v[2]).


D3DHAL_DP2TRIANGLEFAN_IMM

One D3DHAL_DP2TRIANGLEFAN_IMM structure is parsed from the command buffer by the D3dDrawPrimitives2 callback when the D3DHAL_DP2COMMAND structure's bCommand member is set to D3DDP2OP_TRIANGLEFAN_IMM, and is used to render a triangle fan.

typedef struct _D3DHAL_DP2TRIANGLEFAN_IMM {
    DWORD  dwEdgeFlags;
} D3DHAL_DP2TRIANGLEFAN_IMM, *LPD3DHAL_DP2TRIANGLEFAN_IMM;

Members

dwEdgeFlags
Specifies a bitmask that identifies which of the fan's outside edges should be rendered when the fill mode is D3DFILL_WIREFRAME. A set bit indicates that its corresponding edge should be rendered.

Comments

One D3DHAL_DP2TRIANGLEFAN_IMM structure immediately follows the D3DHAL_DP2COMMAND structure in the command buffer. The triangle fan's vertex data is DWORD-aligned immediately following the D3DHAL_DP2TRIANGLEFAN_IMM structure in the command buffer.

D3dDrawPrimitives2 should process a total of wPrimitiveCount+2 vertices from the command buffer, three vertices per triangle, rendering wPrimitiveCount triangles. The sequence of triangles rendered is (V[1], V[2], V[0]), (V[2], V[3], V[0]), (V[3], V[4], V[0]), …, (V[wPrimitiveCount], V[wPrimitiveCount+1], V[0]). The value of wPrimitiveCount is specified in the D3DHAL_DP2COMMAND structure.

The driver must check the edge flag for each of the fan's outside edges when the fill mode is D3DFILL_WIREFRAME. Starting from the least significant bit of dwEdgeFlags, bit 0 applies to the V[0]-V[1] edge, bit 1 applies to the V[1]-V[2] edge, …, bit wPrimitiveCount applies to the V[wPrimitiveCount]-V[wPrimitiveCount+1] edge, and bit (wPrimitiveCount+1) applies to the V[wPrimitiveCount+1]-V[0] edge.

The following figure shows a portion of a sample command buffer containing a D3DDP2OP_TRIANGLEFAN_IMM command, a D3DHAL_DP2TRIANGLEFAN_IMM structure, and the vertex data. The driver should process the five vertices from the command buffer, rendering a fan with three triangles defined by (v[1], v[2], v[0]), (v[2], v[3], v[0]), (v[3], v[4], v[0]).


D3DHAL_DP2TRIANGLELIST

One D3DHAL_DP2TRIANGLELIST structure is parsed from the command buffer by the D3dDrawPrimitives2 callback when the D3DHAL_DP2COMMAND structure's bCommand member is set to D3DDP2OP_TRIANGLELIST, and is used to render the specified unconnected triangles.

typedef struct _D3DHAL_DP2TRIANGLELIST {
    WORD  wVStart;
} D3DHAL_DP2TRIANGLELIST;

Members

wVStart
Specifies the offset into the vertex buffer containing coordinate data for the initial vertex of the triangle list

Comments

One D3DHAL_DP2TRIANGLELIST structure follows the D3DHAL_DP2COMMAND structure in the command buffer.

D3dDrawPrimitives2 should sequentially process a total of wPrimitiveCount*3 vertices from the vertex buffer, three vertices per triangle, rendering wPrimitiveCount triangles. Starting from the vertex buffer offset, the sequence of triangles rendered is (wVStart, wVStart+1, wVStart+2), (wVStart+3, wVStart+4, wVStart+5),…, (wVStart+(wPrimitiveCount-1)*3, wVStart+wPrimitiveCount*3-2, wVStart+wPrimitiveCount*3-1). The value of wPrimitiveCount is specified in the D3DHAL_DP2COMMAND structure.

The following figure shows a portion of a sample command buffer containing a D3DDP2OP_TRIANGLELIST command and one D3DHAL_DP2TRIANGLELIST structure. The driver should draw two triangles using the following six vertices from the vertex buffer: (v[2], v[3], v[4]), (v[5], v[6], v[7]).


D3DHAL_DP2TRIANGLESTRIP

One D3DHAL_DP2TRIANGLESTRIP structure is parsed from the command buffer by the D3dDrawPrimitives2 callback when the D3DHAL_DP2COMMAND structure's bCommand member is set to D3DDP2OP_TRIANGLESTRIP, and is used to render the specified connected triangle strip.

typedef struct _D3DHAL_DP2TRIANGLESTRIP {
    WORD  wVStart;
} D3DHAL_DP2TRIANGLESTRIP;

Members

wVStart
Specifies the index to the vertex buffer containing coordinate data for the initial vertex of the triangle strip.

Comments

One D3DHAL_DP2TRIANGLESTRIP structure follows the D3DHAL_DP2COMMAND structure in the command buffer.

D3dDrawPrimitives2 should process a total of (wPrimitiveCount+2) vertices from the vertex buffer. The value of wPrimitiveCount is specified in the D3DHAL_DP2COMMAND structure.

The triangle edges in a triangle strip are rendered in this order: (wV[0], wV[1], wV[2]), (wV[1], wV[3], wV[2]), (wV[2], wV[3], wV[4]), (wV[3], wV[5], wV[4]),...

For the last triangle in the triangle strip, however, the edges will be rendered in different orders when wPrimitiveCount is odd and when it is even.

  • When wPrimitiveCount is an odd number, the last triangle's edges are rendered in this order: (wV[wPrimitiveCount - 1], wV[wPrimitiveCount], wV[wPrimitiveCount + 1]).
  • When wPrimitiveCount is an even number, the last triangle's edges are rendered in this order: (wV[wPrimitiveCount - 1], wV[wPrimitiveCount+1], wV[wPrimitiveCount]).

The following figure shows a portion of a sample command buffer containing a D3DDP2OP_TRIANGLESTRIP command and one D3DHAL_DP2TRIANGLESTRIP structure. The driver should process five vertices from the vertex buffer, rendering a strip of three triangles defined by (v[0], v[1], v[2]), (v[1], v[3], v[2]), (v[2], v[3], v[4]).


D3DHAL_DP2UPDATEPALETTE

The D3DHAL_DP2UPDATEPALETTE structure is used when responding to the D3DDP2OP_UPDATEPALETTE opcode in D3dDrawPrimitives2. It is used to make alterations to the palette that is used for palletized textures.

typedef struct _D3DHAL_DP2UPDATEPALETTE {
    DWORD  dwPaletteHandle;
    WORD   wStartIndex;
    WORD   wNumEntries;
} D3DHAL_DP2UPDATEPALETTE, *LPD3DHAL_DP2UPDATEPALETTE;
‹ ›

Members

dwPaletteHandle
Is a handle to the palette to be altered.
wStartIndex
Specifies the index in the palette beyond which data will be updated.
wNumEntries
Specifies the number of PALETTEENTRYs being updated.

Comments

The palette handle attached to a surface is updated with wNumEntries PALETTEENTRYs starting at a specific wStartIndex member of the palette. A PALETTEENTRY (defined in wingdi.h and wtypes.h) is actually a DWORD with an ARGB color for each byte.

After the D3DHAL_DP2UPDATEPALETTE structure in the command stream, the actual palette data will follow (without any padding), consisting of one DWORD per palette entry (in ARGB format, with 8 bits for each of the four channels). There will only be one D3DHAL_DP2UPDATEPALETTE structure (plus palette data) following the D3DHAL_DP2COMMAND structure regardless of the value of wStateCount (a member of the D3DHAL_DP2COMMAND structure).


D3DHAL_DP2VERTEXSHADER

DirectX 8.0 and later versions only.

The D3DHAL_DP2VERTEXSHADER structure is used to set the current vertex shader, or delete a vertex shader, depending on the opcode received (D3DDP2OP_SETVERTEXSHADER or D3DDP2OP_DELETEVERTEXSHADER) by D3dDrawPrimitives2.

typedef struct _D3DHAL_DP2VERTEXSHADER
{
    // Vertex shader handle.
    // The handle could be 0, meaning that the current vertex
    // shader is invalid (not set). When driver receives
    // handle 0, it should invalidate all streams pointers
    DWORD dwHandle;
} D3DHAL_DP2VERTEXSHADER, *LPD3DHAL_DP2VERTEXSHADER;

Member

dwHandle
Specifies the handle assigned by the runtime to the vertex shader to set or delete. For delete, the handle is guaranteed to be non-zero. For set, the supplied handle can be zero indicating that no vertex shader is currently realized. In this case the driver should invalidate all previously set streams and free any data associated with them. The runtime guarantees that streams will be re-initialized with D3DDP2OP_SETSTREAMSOURCE or D3DDP2OP_SETSTREAMSOURCEUM and a new vertex shader will be selected using D3DHAL_DP2VERTEXSHADER before any subsequent rendering operations.

Comments

All DirectX 8.0 level drivers must support the D3DDP2OP_SETVERTEXSHADER token because it will be sent even if the driver does not support programmable vertex processing. In that case, however, the shader handle will always be an FVF code indicating fixed function processing of the vertex data. The driver should use the FVF code stored in the dwHandle field as the format of the vertex data in stream zero. A driver that does support programmable vertex processing must examine the handle to determine whether it refers to a shader previously created with D3DDP2OP_CREATEVERTEXSHADER or an FVF code and take the appropriate action.

Pixel and vertex shaders are orthogonal. Thus, if a legacy FVF code is selected as the current vertex shader this does not imply legacy pixel processing. In order to reset pixel processing to a non-programmable mode the current pixel shader must also be set to zero. Care should be taken in the driver to only reset vertex processing state to a fixed function mode and not pixel processing state when the vertex shader is set to an FVF code.

When switching from fixed function vertex processing to programmable vertex processing, the values of legacy render state and matrices should be preserved. If and when a switch from programmable to fixed function vertex processing occurs (the driver receives a D3DDP2OP_SETVERTEXSHADER with an FVF as the shader handle), that preserved state should be restored.

When switching between programmable shaders, any constant register that has a value specified in the definition of that shader should be set to that value. The values of all other constant registers should remain unchanged.

See Also

D3DHAL_DP2SETVERTEXSHADERCONST, D3DHAL_DP2CREATEVERTEXSHADER


D3DHAL_DP2VIEWPORTINFO

The D3DHAL_DP2VIEWPORTINFO structure is used to inform guard-band aware drivers of the view clipping rectangle. The clipping rectangle is specified by the members dwX, dwY, dwWidth and dwHeight.

typedef struct _D3DHAL_DP2VIEWPORTINFO {
    DWORD  dwX;
    DWORD  dwY;
    DWORD  dwWidth;
    DWORD  dwHeight;
} D3DHAL_DP2VIEWPORTINFO, *LPD3DHAL_DP2VIEWPORTINFO;
‹ ›

Members

dwX, dwY
Specify the location, in screen coordinates, of the upper-left corner of the sub-rectangle.
dwWidth, dwHeight
Specify the width and height, respectively, of the sub-rectangle where the application is rendering. These members are specified in screen coordinates.

Comments

The D3dDrawPrimitives2 callback parses a D3DHAL_DP2VIEWPORTINFO structure from the command buffer and updates the driver's viewport description when D3DHAL_DP2COMMAND is set to D3DDP2OP_VIEWPORTINFO.

One D3DHAL_DP2VIEWPORTINFO structure follows the D3DHAL_DP2COMMAND structure in the command buffer.

The driver should update the viewport portion of its internal rendering context with the location and size values specified in this structure. The driver can use this information to perform guard band clipping.

Non-guard-band drivers should ignore and skip over these instructions and continue processing the rest of the command buffer.


D3DHAL_DP2VOLUMEBLT

DirectX 8.0 and later versions only.

The D3DHAL_DP2VOLUMEBLT structure is used for volume texture blts when D3dDrawPrimitives2 responds to the D3DDP2OP_VOLUMEBLT command token.

typedef struct _D3DHAL_DP2VOLUMEBLT
{
    DWORD   dwDDDestSurface;// dest surface
    DWORD   dwDDSrcSurface; // src surface
    DWORD   dwDestX;        // dest X (width)
    DWORD   dwDestY;        // dest Y (height)
    DWORD   dwDestZ;        // dest Z (depth)
    D3DBOX  srcBox;         // src box
    DWORD   dwFlags;        // blt flags
} D3DHAL_DP2VOLUMEBLT, *LPD3DHAL_DP2VOLUMEBLT;

Members

dwDDDestSurface
Specifies the handle to the destination volume texture.
dwDDSrcSurface
Specifies the handle to the source volume texture.
dwDestX, dwDestY, dwDestZ
Specify the location in the destination volume texture to copy the defined source sub-volume.
srcBox
Specifies a sub-volume of the source volume texture to copy to the destination.
dwFlags
Is reserved for system use.

Comments

The D3dCreateSurfaceEx callback creates the small integer handles to the volume textures that can be used as source and destination volume textures for volume texture blts.

See Comments for D3DHAL_DP2TEXBLT.


D3DHAL_DP2WINFO

The D3DHAL_DP2WINFO structure is used to inform the driver of the w-range to be used for w-buffering.

typedef struct _D3DHAL_DP2WINFO {
    D3DVALUE  dvWNear;
    D3DVALUE  dvWFar;
} D3DHAL_DP2WINFO, *LPD3DHAL_DP2WINFO;
‹ ›

Members

dvWNear, dvWFar
Specify the near and far limit of the w-buffer, respectively. These members can be any valid floating point values.

Comments

The D3dDrawPrimitives2 callback parses a D3DHAL_DP2WINFO structure from the command buffer and updates the driver's scaling parameters for w-buffering when D3DHAL_DP2COMMAND is set to D3DDP2OP_WINFO.

One D3DHAL_DP2WINFO structure follows the D3DHAL_DP2COMMAND structure in the command buffer.

The driver should update the w-buffer portion of its internal rendering context with the w-ranges specified in this structure. The driver can use this information to scale the w-buffer.

Video adapters that do not support this feature should ignore and skip over these instructions and continue processing the rest of the command buffer.


D3DHAL_DP2ZRANGE

The D3DHAL_DP2ZRANGE structure is used to specify z-range minimum and maximum in D3dDrawPrimitives2.

typedef struct _D3DHAL_DP2ZRANGE {
    D3DVALUE  dvMinZ;
    D3DVALUE  dvMaxZ;
} D3DHAL_DP2ZRANGE, *LPD3DHAL_DP2ZRANGE;

Members

dvMinZ
Specifies the minimum z value for the Mvs matrix described in the Hardware Transform and Lighting section of the design guide.
dvMaxZ
Specifies the maximum z value for the Mvs matrix described in the Hardware Transform and Lighting section of the design guide.


D3DHAL_GLOBALDRIVERDATA

The D3DHAL_GLOBALDRIVERDATA structure specifies the 3D capabilities of the driver and its device.

typedef struct _D3DHAL_GLOBALDRIVERDATA {
    DWORD                  dwSize;
    D3DHALDEVICEDESC_V1    hwCaps;
    DWORD                  dwNumVertices;
    DWORD                  dwNumClipVertices
    DWORD                  dwNumTextureFormats;
    LPDDSURFACEDESC        lpTextureFormats;
} D3DHAL_GLOBALDRIVERDATA, *LPD3DHAL_GLOBALDRIVERDATA;
‹ ›

Members

dwSize
Specifies the size in bytes of this D3DHAL_GLOBALDRIVERDATA structure.
hwCaps
Specifies a D3DDEVICEDESC_V1 structure where the driver should return its hardware capabilities.
dwNumVertices
Is reserved for system use and should be set to zero by the driver.
dwNumClipVertices
Is reserved for system use and should be set to zero by the driver.
dwNumTextureFormats
Specifies the number of DDSURFACEDESC structures that lpTextureFormats points to.
lpTextureFormats
Points to an array of DDSURFACEDESC structures where the driver should return the texture formats supported by the device.

Comments

The driver is responsible for allocating space for and setting all members of this structure. The driver returns a pointer to this structure in the lpD3DGlobalDriverData member of the DD_HALINFO structure, which is passed to the driver's DrvGetDirectDrawInfo function during driver initialization.


Other Direct3D Driver Structures

This section contains all the Direct3D® driver structures that do not begin with D3DHAL_.


D3DDEVICEDESC_V1

Obsolete in DirectX 8.0 and later versions; see Comments.

The D3DDEVICEDESC_V1 structure describes the 3D capabilities of a device.

typedef struct _D3DDeviceDesc_V1 {
    DWORD             dwSize;
    DWORD             dwFlags;
    D3DCOLORMODEL     dcmColorModel;
    DWORD             dwDevCaps;
    D3DTRANSFORMCAPS  dtcTransformCaps;
    BOOL              bClipping;
    D3DLIGHTINGCAPS   dlcLightingCaps;
    D3DPRIMCAPS       dpcLineCaps;
    D3DPRIMCAPS       dpcTriCaps;
    DWORD             dwDeviceRenderBitDepth;
    DWORD             dwDeviceZBufferBitDepth;
    DWORD             dwMaxBufferSize;
    DWORD             dwMaxVertexCount;
} D3DDEVICEDESC_V1, *LPD3DDEVICEDESC_V1;
‹ ›

Members

dwSize
Specifies the size in bytes of this D3DDEVICEDESC_V1 structure.
dwFlags
Identifies the members of this structure that contain valid data. This member can be a bitwise OR of any of the following values:
Value | Meaning
D3DDD_BCLIPPING | The bClipping member contains valid data.
D3DDD_COLORMODEL | The dcmColorModel member contains valid data.
D3DDD_DEVCAPS | The dwDevCaps member contains valid data.
D3DDD_DEVICERENDERBITDEPTH | The dwDeviceRenderBitDepth member contains valid data.
D3DDD_DEVICEZBUFFERBITDEPTH | The dwDeviceZBufferBitDepth member contains valid data.
D3DDD_LIGHTINGCAPS | The dlcLightingCaps member contains valid data.
D3DDD_LINECAPS | The dpcLineCaps member contains valid data.
D3DDD_MAXBUFFERSIZE | The dwMaxBufferSize member contains valid data.
D3DDD_MAXVERTEXCOUNT | The dwMaxVertexCount member contains valid data.
D3DDD_TRANSFORMCAPS | The dtcTransformCaps member contains valid data.
D3DDD_TRICAPS | The dpcTriCaps member contains valid data.

dcmColorModel
Specifies the device's color model.
dwDevCaps
Identifies the capabilities of the device. This member can be a bitwise OR of any of the following values:
Value | Meaning
D3DDEVCAPS_CANBLTSYSTONONLOCAL | The device supports a TexBlt from system memory to non-local video memory.
D3DDEVCAPS_CANRENDERAFTERFLIP | The device can queue rendering commands after a page flip. Devices must support this capability on Windows 2000 and later, meaning that the driver would always set this flag.
D3DDEVCAPS_DRAWPRIMITIVES2 | The device can support D3dDrawPrimitives2.
D3DDEVCAPS_DRAWPRIMITIVES2EX | The device can support Extended D3dDrawPrimitives2; i.e. a DX7-compliant driver.
D3DDEVCAPS_DRAWPRIMTLVERTEX | The device can draw TLVERTEX primitives. This flag is obsolete but must be set by the driver.
D3DDEVCAPS_EXECUTESYSTEMMEMORY | The device can use execute buffers from system memory. The driver must always set this bit.
D3DDEVCAPS_EXECUTEVIDEOMEMORY | The device can use execute buffers from display memory. The driver must never set this bit.
D3DDEVCAPS_FLOATTLVERTEX | The device accepts floating point for post-transform vertex data. This flag is obsolete but must be set by the driver.
D3DDEVCAPS_HWRASTERIZATION | The device has hardware acceleration for rasterization.
D3DDEVCAPS_HWTRANSFORMANDLIGHT | The device can support transformation and lighting in hardware. D3DDEVCAPS_DRAWPRIMITIVES2EX must also be set.
D3DDEVCAPS_SEPARATETEXTUREMEMORIES | The device is texturing from separate memory pools.
D3DDEVCAPS_SORTDECREASINGZ | The device needs data sorted for decreasing depth.
D3DDEVCAPS_SORTEXACT | The device needs data sorted exactly.
D3DDEVCAPS_SORTINCREASINGZ | The device needs data sorted for increasing depth.
D3DDEVCAPS_TEXTURENONLOCALVIDEOMEMORY | The device can texture from nonlocal video memory.
D3DDEVCAPS_TLVERTEXSYSTEMMEMORY | The device can use buffers from system memory for transformed and lit vertices. This flag is obsolete but must be set by the driver.
D3DDEVCAPS_TLVERTEXVIDEOMEMORY | The device can use buffers from display memory for transformed and lit vertices. This flag is obsolete and must not be set by the driver.
D3DDEVCAPS_TEXTURESYSTEMMEMORY | The device can retrieve textures from system memory.
D3DDEVCAPS_TEXTUREVIDEOMEMORY | The device can retrieve textures from device memory.

dtcTransformCaps
Specifies a D3DTRANSFORMCAPS structure that specifies the transformation capabilities of the device. The driver must set the dwCaps member of that structure to zero.
bClipping
Is set TRUE by the driver if the device can perform 3D clipping.
dlcLightingCaps
Is a D3DLIGHTINGCAPS structure that specifies the lighting capabilities of the device. The driver must set the dwCaps, dwLightingModel, and dwNumLights members of that structure to zero.
dpcLineCaps
Specifies a D3DPRIMCAPS structure that defines the drawing capabilities of the device for line primitives.
dpcTriCaps
Specifies a D3DPRIMCAPS structure that defines the drawing capabilities of the device for triangle primitives.
dwDeviceRenderBitDepth
Specifies the device's rendering bit-depth. This member can be a bitwise OR of the following DirectDraw® bit-depth constants: DDBD_8, DDBD_16, DDBD_24, or DDBD_32.
dwDeviceZBufferBitDepth
Specifies the device's z-buffer bit-depth. This member can be a bitwise OR of the following DirectDraw bit-depth constants: DDBD_8, DDBD_16, DDBD_24, or DDBD_32.
dwMaxBufferSize
Must be set to zero.
dwMaxVertexCount
Specifies the maximum number of vertices that the device can handle in a single call to D3dDrawPrimitives2.

Comments

This structure has been replaced by D3DCAPS8 (see the DirectX 8.0 SDK documentation) for DirectX 8.0 and later runtimes, but is required for legacy runtime (DirectX 7.0 and earlier) compatibility. See Reporting DirectX 8.0 Style Direct3D Capabilities for details.

The driver's DrvGetDirectDrawInfo function returns this information in the D3DHAL_GLOBALDRIVERDATA structure that the lpD3DGlobalDriverData member of the DD_HALINFO structure points to.

The Direct3D runtime constructs the application-level D3DDEVICEDESC7 structure (documented in the Platform SDK documentation) from the information returned in the D3DDEVICEDESC_V1 structure and the extended capabilities queried through the driver's DdGetDriverInfo function. While some of the dwDevCaps flags are obsolete at the driver level, the driver must set them appropriately in order for applications to work correctly.


D3DDEVICEDESC_V2

The D3DDEVICEDESC_V2 structure is obsolete; only D3DDEVICEDESC_V1 should be used.

The D3DDEVICEDESC_V2 structure contains fields that are already reported in the D3DHAL_D3DEXTENDEDCAPS structure when responding to the GUID_D3DExtendedCaps GUID in DdGetDriverInfo.

typedef struct _D3DDeviceDesc_V2 {
    DWORD             dwSize;
    DWORD             dwFlags;
    D3DCOLORMODEL     dcmColorModel;
    DWORD             dwDevCaps;
    D3DTRANSFORMCAPS  dtcTransformCaps;
    BOOL              bClipping;
    D3DLIGHTINGCAPS   dlcLightingCaps;
    D3DPRIMCAPS       dpcLineCaps;
    D3DPRIMCAPS       dpcTriCaps;
    DWORD             dwDeviceRenderBitDepth;
    DWORD             dwDeviceZBufferBitDepth;
    DWORD             dwMaxBufferSize;
    DWORD             dwMaxVertexCount;
    DWORD             dwMinTextureWidth;
    DWORD             dwMinTextureHeight;
    DWORD             dwMaxTextureWidth;
    DWORD             dwMaxTextureHeight;
    DWORD             dwMinStippleWidth;
    DWORD             dwMaxStippleWidth;
    DWORD             dwMinStippleHeight;
    DWORD             dwMaxStippleHeight;
} D3DDEVICEDESC_V2, *LPD3DDEVICEDESC_V2;
‹ ›


D3DDEVICEDESC_V3

The D3DDEVICEDESC_V3 structure is obsolete; only D3DDEVICEDESC_V1 should be used.

The D3DDEVICEDESC_V3 structure contains fields that are already reported in the D3DHAL_D3DEXTENDEDCAPS structure when responding to the GUID_D3DExtendedCaps GUID in DdGetDriverInfo.

typedef struct _D3DDeviceDesc_V3 {
    DWORD             dwSize;
    DWORD             dwFlags;
    D3DCOLORMODEL     dcmColorModel;
    DWORD             dwDevCaps;
    D3DTRANSFORMCAPS  dtcTransformCaps;
    BOOL              bClipping;
    D3DLIGHTINGCAPS   dlcLightingCaps;
    D3DPRIMCAPS       dpcLineCaps;
    D3DPRIMCAPS       dpcTriCaps;
    DWORD             dwDeviceRenderBitDepth;
    DWORD             dwDeviceZBufferBitDepth;
    DWORD             dwMaxBufferSize;
    DWORD             dwMaxVertexCount;
    DWORD             dwMinTextureWidth;
    DWORD             dwMinTextureHeight;
    DWORD             dwMaxTextureWidth;
    DWORD             dwMaxTextureHeight;
    DWORD             dwMinStippleWidth;
    DWORD             dwMaxStippleWidth;
    DWORD             dwMinStippleHeight;
    DWORD             dwMaxStippleHeight;
    DWORD             dwMaxTextureRepeat;
    DWORD             dwMaxTextureAspectRatio;
    DWORD             dwMaxAnisotropy;
    D3DVALUE          dvGuardBandLeft;
    D3DVALUE          dvGuardBandTop;
    D3DVALUE          dvGuardBandRight;
    D3DVALUE          dvGuardBandBottom;
    D3DVALUE          dvExtentsAdjust;
    DWORD             dwStencilCaps;
    DWORD             dwFVFCaps;
    DWORD             dwTextureOpCaps;
    WORD              wMaxTextureBlendStages;
    WORD              wMaxSimultaneousTextures;
} D3DDEVICEDESC_V3, *LPD3DDEVICEDESC_V3;
‹ ›


D3DLIGHTINGCAPS

Obsolete in DirectX 8.0 and later versions; see Comments.

The D3DLIGHTINGCAPS structure describes the lighting capabilities of a device.

typedef struct _D3DLIGHTINGCAPS {
    DWORD  dwSize;
    DWORD  dwCaps;
    DWORD  dwLightingModel;
    DWORD  dwNumLights;
} D3DLIGHTINGCAPS, *LPD3DLIGHTINGCAPS;
‹ ›

Members

dwSize
Specifies the size, in bytes, of the D3DLIGHTINGCAPS structure.
dwCaps
Specifies flags describing the capabilities of the lighting module. The following flags are defined:
Value | Meaning
D3DLIGHTCAPS_DIRECTIONAL | Directional lights are supported.
D3DLIGHTCAPS_GLSPOT | OpenGL-style spotlights are supported.
D3DLIGHTCAPS_PARALLELPOINT | Parallel-point lights are supported.
D3DLIGHTCAPS_POINT | Point lights are supported.
D3DLIGHTCAPS_SPOT | Spotlights are supported.

dwLightingModel
Specifies flags indicating whether the lighting model is RGB or monochrome. The following flags are defined:
Value | Meaning
D3DLIGHTINGMODEL_MONO | The lighting model is monochromatic.
D3DLIGHTINGMODEL_RGB | The lighting model is RGB.

dwNumLights
Specifies the number of lights that can be handled.

Comments

This structure has been replaced by D3DCAPS8 (see the DirectX 8.0 SDK documentation) for DirectX 8.0 and later runtimes, but is required for legacy runtime (DirectX 7.0 and earlier) compatibility. See Reporting DirectX 8.0 Style Direct3D Capabilities for details.

This structure is a member of the D3DDEVICEDESC_V1 structure.


D3DPRIMCAPS

Obsolete in DirectX 8.0 and later versions; see Comments.

The D3DPRIMCAPS structure defines the capabilities for each primitive type.

typedef struct _D3DPrimCaps {
    DWORD  dwSize;
    DWORD  dwMiscCaps;
    DWORD  dwRasterCaps;
    DWORD  dwZCmpCaps;
    DWORD  dwSrcBlendCaps;
    DWORD  dwDestBlendCaps;
    DWORD  dwAlphaCmpCaps;
    DWORD  dwShadeCaps;
    DWORD  dwTextureCaps;
    DWORD  dwTextureFilterCaps;
    DWORD  dwTextureBlendCaps;
    DWORD  dwTextureAddressCaps;
    DWORD  dwStippleWidth;
    DWORD  dwStippleHeight;
} D3DPRIMCAPS, *LPD3DPRIMCAPS;
‹ ›

Members

dwSize
Specifies the size, in bytes, of the D3DPRIMCAPS structure.
dwMiscCaps
Specifies the general capabilities for this primitive. This member can be one or more of the following:
Value | Meaning
D3DPMISCCAPS_CONFORMANT | The device conforms to the OpenGL® standard.
D3DPMISCCAPS_CULLCCW | The driver supports counterclockwise culling through the D3DRENDERSTATE_CULLMODE render state. (This applies only to triangle primitives.) This corresponds to the D3DCULL_CCW enumerator of the D3DCULL enumerated type.
D3DPMISCCAPS_CULLCW | The driver supports clockwise triangle culling through the D3DRENDERSTATE_CULLMODE render state. (This applies only to triangle primitives.) This corresponds to the D3DCULL_CW enumerator of the D3DCULL enumerated type.
D3DPMISCCAPS_CULLNONE | The driver does not perform triangle culling. This corresponds to the D3DCULL_NONE enumerator of the D3DCULL enumerated type.
D3DPMISCCAPS_LINEPATTERNREP The driver can handle values other than 1 in the wRepeatFactor member of the D3DLINEPATTERN structure. (This applies only to line-drawing primitives.)

D3DPMISCCAPS_LINEPATTERNREP and D3DPRASTERCAPS_PAT must be set consistently (both on or both off).
D3DPMISCCAPS_MASKPLANES | The device can perform a bitmask of color planes.
D3DPMISCCAPS_MASKZ | The device can enable and disable modification of the z-buffer on pixel operations.

dwRasterCaps
Contains information on raster-drawing capabilities. This member can be one or more of the following:
Value | Meaning
D3DPRASTERCAPS_ANISOTROPY | The device supports anisotropic filtering. For more information, see D3DTSS_MAXANISOTROPY in the DirectX SDK documentation.
D3DPRASTERCAPS_ANTIALIASEDGES | The device can antialias lines forming the convex outline of objects. For more information, see D3DRENDERSTATE_EDGEANTIALIAS in the DirectX SDK documentation.
D3DPRASTERCAPS_ANTIALIASSORTDEPENDENT | The device supports antialiasing that is dependent on the sort order of the polygons (back-to-front or front-to-back). The application must draw polygons in the right order for antialiasing to occur. For more information, see the D3DANTIALIASMODE enumerated type in the DirectX SDK documentation.
D3DPRASTERCAPS_ANTIALIASSORTINDEPENDENT | The device supports antialiasing that is not dependent on the sort order of the polygons. For more information, see the D3DANTIALIASMODE enumerated type in the DirectX SDK documentation.
D3DPRASTERCAPS_DITHER | The device can dither to improve color resolution through the D3DRENDERSTATE_DITHERENABLE render state.
D3DPRASTERCAPS_FOGRANGE | The device supports range-based fog, in which the distance of an object from the viewer, rather than the depth of the object (its z-coordinate), is used to compute fog effects in the scene. For more information, see D3DRENDERSTATE_RANGEFOGENABLE in the DirectX SDK documentation.
D3DPRASTERCAPS_FOGTABLE | The device calculates the fog value by referring to a look-up table containing fog values that are indexed to the depth of a given pixel. For more information, see D3DRENDERSTATE_FOGCOLOR, D3DRENDERSTATE_FOGDENSITY, D3DRENDERSTATE_FOGENABLE, D3DRENDERSTATE_FOGEND, D3DRENDERSTATE_FOGSTART, and D3DRENDERSTATE_FOGTABLEMODE in the DirectX SDK documentation.
D3DPRASTERCAPS_FOGVERTEX | The device calculates the fog value during the lighting operation, places the value into the alpha component of the D3DCOLOR value given for the specular member of the D3DTLVERTEX structure (defined in the Direct3D SDK documentation), and interpolates the fog value during rasterization. For more information, see D3DRENDERSTATE_FOGCOLOR, D3DRENDERSTATE_FOGDENSITY, D3DRENDERSTATE_FOGENABLE, D3DRENDERSTATE_FOGEND, D3DRENDERSTATE_FOGSTART, and D3DRENDERSTATE_FOGVERTEXMODE in the DirectX SDK documentation.
D3DPRASTERCAPS_PAT The driver can perform patterned drawing (lines or fills with D3DRENDERSTATE_LINEPATTERN or one of the D3DRENDERSTATE_STIPPLEPATTERN render states) for the primitive being queried.

D3DPRASTERCAPS_PAT and D3DPMISCCAPS_LINEPATTERNREP must be set consistently (both on or both off).
D3DPRASTERCAPS_ROP2 | The device can support raster operations other than R2_COPYPEN.
D3DPRASTERCAPS_STIPPLE | The device can stipple polygons to simulate translucency.
D3DPRASTERCAPS_SUBPIXEL | The device performs subpixel placement of z, color, and texture data, rather than working with the nearest-integer pixel coordinate. This helps avoid bleedthrough due to z imprecision, and jitter of color and texture values for pixels. Note that there is no corresponding state that can be enabled and disabled; the device either performs subpixel placement or it does not, and this bit is present only so that the Direct3D client can better determine what the rendering quality will be.
D3DPRASTERCAPS_SUBPIXELX | The device is subpixel-accurate along the x-axis only, and is clamped to an integer y-axis scan line. For information about subpixel accuracy, see the previously mentioned definition of D3DPRASTERCAPS_SUBPIXEL.
D3DPRASTERCAPS_TRANSLUCENTSORTINDEPENDENT | The hardware can perform translucency without sorting. This is an offshoot of the A buffer technique for antialiasing.
D3DPRASTERCAPS_WBUFFER | The device supports w-buffering.
D3DPRASTERCAPS_WFOG | The device supports w-based fog.
D3DPRASTERCAPS_XOR | The device can support XOR operations. If this flag is not set but D3DPRASTER_ROP2 is set, then XOR operations must still be supported.
D3DPRASTERCAPS_ZBIAS | The device supports z-bias values, integer values assigned to polygons to allow physically coplanar polygons to appear separate. For more information, see D3DRENDERSTATE_ZBIAS in the DirectX SDK documentation.
D3DPRASTERCAPS_ZBUFFERLESSHSR | The device can perform hidden-surface removal (HSR) without requiring the application to sort polygons, and without requiring the allocation of a z-buffer. This leaves more video memory for textures. The method used to perform HSR is hardware-dependent and is transparent to the application. Z-buffer-less HSR is performed if no z-buffer surface is attached to the rendering target surface and the z-buffer comparison test is enabled (that is, when the state value associated with the D3DRENDERSTATE_ZENABLE render state value is set to TRUE).
D3DPRASTERCAPS_ZFOG | The device supports z based fog.
D3DPRASTERCAPS_ZTEST | The device can perform z-test operations. This effectively renders a primitive and indicates whether any z pixels would have been rendered.

dwZCmpCaps
Specifies Z-buffer comparison functions that the driver can perform through the D3DRENDERSTATE_ZFUNC render state. This member can be one or more of the following:
Comparison Function | Description
D3DPCMPCAPS_ALWAYS | Always pass the z test.
D3DPCMPCAPS_EQUAL | Pass the z test if the new z equals the current z.
D3DPCMPCAPS_GREATER | Pass the z test if the new z is greater than the current z.
D3DPCMPCAPS_GREATEREQUAL | Pass the z test if the new z is greater than or equal to the current z.
D3DPCMPCAPS_LESS | Pass the z test if the new z is less than the current z.
D3DPCMPCAPS_LESSEQUAL | Pass the z test if the new z is less than or equal to the current z.
D3DPCMPCAPS_NEVER | Always fail the z test.
D3DPCMPCAPS_NOTEQUAL | Pass the z test if the new z does not equal the current z.

dwSrcBlendCaps
Specifies source blending capabilities supported by the driver through the D3DRENDERSTATE_SRCBLEND render state. This member can be one or more of the following values. (The RGBA values of the source and destination are indicated with the subscripts s and d.)
Value | Meaning
D3DPBLENDCAPS_BOTHINVSRCALPHA | Source blend factor is (1 - As, 1 - As, 1 - As, 1 - As) and destination blend factor is (As, As, As, As); the destination blend selection is overridden.
D3DPBLENDCAPS_BOTHSRCALPHA | Source blend factor is (As, As, As, As) and destination blend factor is (1 - As, 1 - As, 1 - As, 1 - As); the destination blend selection is overridden.
D3DPBLENDCAPS_DESTALPHA | Blend factor is (Ad, Ad, Ad, Ad).
D3DPBLENDCAPS_DESTCOLOR | Blend factor is (Rd, Gd, Bd, Ad).
D3DPBLENDCAPS_INVDESTALPHA | Blend factor is (1 - Ad, 1 - Ad, 1 - Ad, 1 - Ad).
D3DPBLENDCAPS_INVDESTCOLOR | Blend factor is (1 - Rd, 1 - Gd, 1 - Bd, 1 - Ad).
D3DPBLENDCAPS_INVSRCALPHA | Blend factor is (1 - As, 1 - As, 1 - As, 1 - As).
D3DPBLENDCAPS_INVSRCCOLOR | Blend factor is (1 - Rs, 1 - Gs, 1 - Bs, 1 - As).
D3DPBLENDCAPS_ONE | Blend factor is (1, 1, 1, 1).
D3DPBLENDCAPS_SRCALPHA | Blend factor is (As, As, As, As).
D3DPBLENDCAPS_SRCALPHASAT | Blend factor is (f, f, f, 1); f = min(As, 1 - Ad).
D3DPBLENDCAPS_SRCCOLOR | Blend factor is (Rs, Gs, Bs, As).
D3DPBLENDCAPS_ZERO | Blend factor is (0, 0, 0, 0).

dwDestBlendCaps
Specifies destination blending capabilities supported by the driver through the D3DRENDERSTATE_DESTBLEND render state. This member can be the same capabilities that are defined for the dwSrcBlendCaps member.
dwAlphaCmpCaps
Specifies alpha-test comparison functions that the driver can perform. This member uses the same comparison functions as are defined for the dwZCmpCaps member. If the dwAlphaCmpCaps member of the D3DPRIMCAPS structure is 0, the driver does not support alpha test render states D3DRENDERSTATE_ALPHAFUNC, D3DRENDERSTATE_ALPHAREF, and D3DRENDERSTATE_ALPHATESTENABLE.
dwShadeCaps
Specifies shading operations that the device can perform. It is assumed, in general, that if a device supports a given command (such as D3DOP_TRIANGLE) at all, it supports the D3DSHADE_FLAT mode (as specified in the D3DSHADEMODE enumerated type in the DirectX SDK documentation). This flag specifies whether the driver can also support Gouraud and Phong shading and whether alpha color components are supported for each of the three color-generation modes. When alpha components are not supported in a given mode, the alpha value of colors generated in that mode is implicitly 255. This is the maximum possible alpha (that is, the alpha component is at full intensity).

The color, specular highlights, fog, and alpha interpolants of a triangle each have capability flags that an application can use to find out how they are implemented by the device driver. These are modified by the shade mode and color model, and by whether the alpha component of a color is blended or stippled.

This member can be one or more of values listed in the following table. Related flags are grouped together in this table.
Value Meaning
D3DPSHADECAPS_ALPHAFLATBLEND
D3DPSHADECAPS_ALPHAFLATSTIPPLED 		The device can support an alpha component for flat-blended and stippled (D3DRENDERSTATE_STIPPLEDALPHA) transparency, respectively (the D3DSHADE_FLAT state for the D3DSHADEMODE enumerated type). In these modes, the alpha color component for a primitive is provided as part of the color for the first vertex of the primitive.
D3DPSHADECAPS_ALPHAGOURAUDBLEND
D3DPSHADECAPS_ALPHAGOURAUDSTIPPLED 		The device can support an alpha component for Gouraud blended and stippled (D3DRENDERSTATE_STIPPLEDALPHA) transparency, respectively (the D3DSHADE_GOURAUD state for the D3DSHADEMODE enumerated type). In these modes, the alpha color component for a primitive is provided at vertices and interpolated across a face along with the other color components.
D3DPSHADECAPS_ALPHAPHONGBLEND
D3DPSHADECAPS_ALPHAPHONGSTIPPLED 		The device can support an alpha component for Phong-blended and stippled (D3DRENDERSTATE_STIPPLEDALPHA) transparency, respectively (the D3DSHADE_PHONG state for the D3DSHADEMODE enumerated type). In these modes, vertex parameters are reevaluated on a per-pixel basis, applying lighting effects for the red, green, and blue color components.
D3DPSHADECAPS_COLORFLATMONO
D3DPSHADECAPS_COLORFLATRGB 		The device can support colored flat shading in the D3DCOLOR_MONO and D3DCOLOR_RGB color models, respectively. In these modes, the color component for a primitive is provided as part of the color for the first vertex of the primitive. In monochromatic lighting modes, only the blue component of the color is interpolated; in RGB lighting modes, of course, the red, green, and blue components are interpolated.
D3DPSHADECAPS_COLORGOURAUDMONO
D3DPSHADECAPS_COLORGOURAUDRGB 		The device can support colored Gouraud shading in the D3DCOLOR_MONO and D3DCOLOR_RGB color models, respectively. In these modes, the color component for a primitive is provided at vertices and interpolated across a face along with the other color components. In monochromatic lighting modes, only the blue component of the color is interpolated; in RGB lighting modes, of course, the red, green, and blue components are interpolated.
D3DPSHADECAPS_COLORPHONGMONO
D3DPSHADECAPS_COLORPHONGRGB 		The device can support colored Phong shading in the D3DCOLOR_MONO and D3DCOLOR_RGB color models, respectively. In these modes, vertex parameters are reevaluated on a per-pixel basis. Lighting effects are applied for the red, green, and blue color components in RGB mode, and for the blue component only for monochromatic mode.
D3DPSHADECAPS_FOGFLAT
D3DPSHADECAPS_FOGGOURAUD,
D3DPSHADECAPS_FOGPHONG 		The device can support fog in the flat, Gouraud, and Phong shading models, respectively.
D3DPSHADECAPS_SPECULARFLATMONO
D3DPSHADECAPS_SPECULARFLATRGB 		The device can support specular highlights through the D3DRENDERSTATE_SPECULARENABLE render state in flat shading in the D3DCOLOR_MONO and D3DCOLOR_RGB color models, respectively.
D3DPSHADECAPS_SPECULARGOURAUDMONO
D3DPSHADECAPS_SPECULARGOURAUDRGB 		The device can support specular highlights through the D3DRENDERSTATE_SPECULARENABLE render state in Gouraud shading in the D3DCOLOR_MONO and D3DCOLOR_RGB color models, respectively.
D3DPSHADECAPS_SPECULARPHONGMONO
D3DPSHADECAPS_SPECULARPHONGRGB 		The device can support specular highlights through the D3DRENDERSTATE_SPECULARENABLE render state in Phong shading in the D3DCOLOR_MONO and D3DCOLOR_RGB color models, respectively. Phong shading is not supported for DirectX 2.0.

Most hardware drivers should expose the D3DPSHADECAPS_COLORFLATRGB and D3DPSHADECAPS_COLORGOURAUDRGB capabilities. Hardware that supports intensity (grayscale) lighting (see D3DRENDERSTATE_MONOENABLE for more details) should also expose the D3DPSHADECAPS_COLORFLATMONO and D3DSHADECAPS_COLORGOURAUDMONO capabilities.

dwTextureCaps
Specifies miscellaneous texture-mapping capabilities. This member can be one or more of the following:
Value | Meaning
D3DPTEXTURECAPS_ALPHA | RGBA textures are supported in the D3DTEX_DECAL and D3DTEX_MODULATE texture filtering modes. If this capability is not set, then only RGB textures are supported in those modes. Regardless of whether this flag is set, alpha must always be supported in the D3DTEX_DECAL_MASK, D3DTEX_DECAL_ALPHA, and D3DTEX_MODULATE_ALPHA filtering modes whenever those filtering modes are available.
D3DPTEXTURECAPS_ALPHAPALETTE | Palletized texture surfaces whose palettes contain alpha information are supported (see the DDPCAPS_ALPHA flag in the DDCAPS structure in the DirectDraw SDK documentation).
D3DPTEXTURECAPS_BORDER | Texture mapping along borders is supported.
D3DPTEXTURECAPS_COLORKEYBLEND | The device is capable of performing color key blending.
D3DPTEXTURECAPS_CUBEMAP | The device is capable of supporting cube environment mapping.
D3DPTEXTURECAPS_PERSPECTIVE | Perspective correction is supported. See D3DRENDERSTATE_TEXTUREPERSPECTIVE in the DirectX SDK documentation.
D3DPTEXTURECAPS_POW2 | All non-MIP mapped textures have widths and heights specified as powers of two. (Note that all MIP mapped textures must always have dimensions that are powers of two.)
D3DPTEXTURECAPS_PROJECTED | The device can divide transformed texture coordinates by the COUNTth texture coordinate. In other words, the device can do D3DTTFF_PROJECTED. See D3DTEXTURETRANSFORMFLAGS in the DirectX SDK documentation.
D3DPTEXTURECAPS_NONPOW2CONDITIONAL | The device can use non-POW2 textures if the D3DTADDRESS_CLAMP enumerator of the D3DTEXTUREADDRESS enumerated type is set for this texture's stage, D3DRENDERSTATE_WRAPN is zero for this texture's coordinates, or MIP mapping and anisotroptic filtering are disabled.
D3DPTEXTURECAPS_SQUAREONLY | All textures must be square.
D3DPTEXTURECAPS_TEXREPEATNOTSCALESBYSIZE | Texture indexes are not scaled by the texture size before interpolation.
D3DPTEXTURECAPS_TEXTURETRANSFORM | The device is capable of doing texture transforms.
D3DPTEXTURECAPS_TRANSPARENCY | Texture transparency is supported. (Only those texels that are not the current transparent color are drawn.)

dwTextureFilterCaps
Specifies texture-mapping capabilities. This member can be one or more of the following:
Value | Meaning
D3DPTFILTERCAPS_LINEAR | Bilinear filtering is supported. A weighted average of a 2-by-2 area of texels surrounding the desired pixel is used. This applies to both zooming in and zooming out. If either zooming in or zooming out is supported, then both must be supported.
D3DPTFILTERCAPS_LINEARMIPLINEAR | Trilinear interpolation between MIP maps is supported. Performs bilinear filtering on the two nearest MIP maps, then interpolates linearly between the two colors to determine the final color.
D3DPTFILTERCAPS_LINEARMIPNEAREST | Linear interpolation between two point sampled MIP maps is supported. Chooses the nearest texel from the two closest MIP map levels, then performs linear interpolation between them.
D3DPTFILTERCAPS_MAGFAFLATCUBIC | Per-stage flat-cubic filtering for magnifying textures is supported. The flat-cubic magnification filter is represented by the D3DTFG_FLATCUBIC member of the D3DTEXTUREMAGFILTER enumeration.
D3DPTFILTERCAPS_MAGFANISOTROPIC | Per-stage anisotropic filtering for magnifying textures is supported. The anisotropic magnification filter is represented by the D3DTFG_ANISOTROPIC member of the D3DTEXTUREMAGFILTER enumeration.
D3DPTFILTERCAPS_MAGFGAUSSIANCUBIC | Per-stage Gaussian-cubic filtering for magnifying textures is supported. The Gaussian-cubic magnification filter is represented by the D3DTFG_GAUSSIANCUBIC member of the D3DTEXTUREMAGFILTER enumeration.
D3DPTFILTERCAPS_MAGFLINEAR Per-stage bilinear-interpolation filtering for magnifying textures is supported. The bilinear-interpolation magnification filter is represented by the D3DTFG_LINEAR member of the D3DTEXTUREMAGFILTER enumeration.
Specifies that bilinear filtering on the magnify filter is supported.
D3DPTFILTERCAPS_MAGFPOINT | Per-stage point-sampled filtering for magnifying textures is supported. The point-sample magnification filter is represented by the D3DTFG_POINT member of the D3DTEXTUREMAGFILTER enumeration.
D3DPTFILTERCAPS_MINFANISOTROPIC | Per-stage anisotropic filtering for minifying textures is supported. The anisotropic minification filter is represented by the D3DTFN_ANISOTROPIC member of the D3DTEXTUREMINFILTER enumeration.
D3DPTFILTERCAPS_MINFLINEAR | Per-stage bilinear-interpolation filtering for minifying textures is supported. The bilinear minification filter is represented by the D3DTFN_LINEAR member of the D3DTEXTUREMINFILTER enumeration.
D3DPTFILTERCAPS_MINFPOINT | Per-stage point-sampled filtering for minifying textures is supported. The point-sample minification filter is represented by the D3DTFN_POINT member of the D3DTEXTUREMINFILTER enumeration.
D3DPTFILTERCAPS_MIPFLINEAR | Per-stage trilinear-interpolation filtering for MIP maps (that is, bi-linear filtering between MIP levels) is supported. The trilinear-interpolation MIP mapping filter is represented by the D3DTFP_LINEAR member of the D3DTEXTUREMIPFILTER enumeration.
D3DPTFILTERCAPS_MIPFPOINT | Per-stage point-sampled filtering for MIP maps is supported. The point-sample MIP mapping filter is represented by the D3DTFP_POINT member of the D3DTEXTUREMIPFILTER enumeration.
D3DPTFILTERCAPS_MIPLINEAR | Nearest MIP mapping, with bilinear filtering applied to the result is supported. Chooses the texel from the appropriate MIP map that has the nearest coordinates, then performs a weighted average with the four surrounding texels to determine the final color.
D3DPTFILTERCAPS_MIPNEAREST | Nearest MIP mapping is supported. Chooses the texel from the appropriate MIP map with coordinates nearest to the desired pixel value.
D3DPTFILTERCAPS_NEAREST | Point sampling is supported. The texel with coordinates nearest to the desired pixel value is used. This applies to both zooming in and zooming out. If either zooming in or zooming out is supported, then both must be supported.

dwTextureBlendCaps
Specifies texture-blending capabilities. See the D3DRENDERSTATE_TEXTUREMAPBLEND enumerated type for discussions of the various texture-blending modes. This member can be one or more of the following:
Value | Meaning
D3DPTBLENDCAPS_ADD | Add mode texture-blending is supported (D3DTBLEND_COPY from the D3DTEXTUREBLEND enumerated type).
D3DPTBLENDCAPS_COPY | Copy mode texture-blending is supported (D3DTBLEND_COPY from the D3DTEXTUREBLEND enumerated type).
D3DPTBLENDCAPS_DECAL | Decal texture-blending mode is supported (D3DTBLEND_DECAL from the D3DTEXTUREBLEND enumerated type).
D3DPTBLENDCAPS_DECALALPHA | Decal-alpha texture-blending mode is supported (D3DTBLEND_DECALALPHA from the D3DTEXTUREBLEND enumerated type).
D3DPTBLENDCAPS_DECALMASK | Decal-mask texture-blending mode is supported (D3DTBLEND_DECALMASK from the D3DTEXTUREBLEND enumerated type).
D3DPTBLENDCAPS_MODULATE | Modulate-texture-blending mode is supported (D3DTBLEND_MODULATE from the D3DTEXTUREBLEND enumerated type).
D3DPTBLENDCAPS_MODULATEALPHA | Modulate-alpha texture-blending mode is supported (D3DTBLEND_MODULATEALPHA from the D3DTEXTUREBLEND enumerated type).
D3DPTBLENDCAPS_MODULATEMASK | Modulate-mask texture-blending mode is supported (D3DTBLEND_MODULATEMASK from the D3DTEXTUREBLEND enumerated type).

dwTextureAddressCaps
Specifies the texture-addressing capabilities. This member can be one or more of the following, corresponding to D3DTEXTUREADDRESS texture-addressing modes:
Value | Meaning
D3DPTADDRESSCAPS_BORDER | The device supports setting coordinates outside the range [0.0, 1.0] to the border color, as specified by the D3DTSS_BORDERCOLOR texture stage state. This ability corresponds to the D3DTADDRESS_BORDER texture-addressing mode.
D3DPTADDRESSCAPS_CLAMP | The device can clamp textures to addresses. This ability corresponds to the D3DTADDRESS_CLAMP texture-addressing mode.
D3DPTADDRESSCAPS_INDEPENDENTUV | The device can separate the texture-addressing modes of the U and V coordinates of the texture. This ability corresponds to the D3DTSS_ADDRESSU and D3DTSS_ADDRESSV texture stage states.
D3DPTADDRESSCAPS_MIRROR | The device can mirror textures to addresses. This ability corresponds to the D3DTADDRESS_MIRROR texture-addressing mode.
D3DPTADDRESSCAPS_WRAP | The device can wrap textures to addresses. This ability corresponds to the D3DTADDRESS_WRAP texture-addressing mode.

dwStippleWidth, dwStippleHeight
Specify the maximum width and height of the supported stipple (up to 32-by-32).

Comments

This structure has been replaced by D3DCAPS8 (see the DirectX 8.0 SDK documentation) for DirectX 8.0 and later runtimes, but is required for legacy runtime (DirectX 7.0 and earlier) compatibility. See Reporting DirectX 8.0 Style Direct3D Capabilities for details.

This structure is used when a device is created and when the capabilities of a device are queried. It defines several members in the D3DDEVICEDESC_V1 structure.


D3DTRANSFORMCAPS

Obsolete in DirectX 8.0 and later versions.

D3DTRANSFORMCAPS structure describes the transform capabilities of a device.

typedef struct _D3DTRANSFORMCAPS {
    DWORD  dwSize;
    DWORD  dwCaps;
} D3DTRANSFORMCAPS, *LPD3DTRANSFORMCAPS;

Members

dwSize
Specifies the size, in bytes, of the D3DTRANSFORMCAPS structure.
dwCaps
Specifies flags describing the capabilities of the lighting module. The following flag is defined:
D3DTRANSFORMCAPS_CLIP
The device can do clipping operations while transforming.

Comments

This structure has been replaced by D3DCAPS8 (see the DirectX 8.0 SDK documentation) for DirectX 8.0 and later runtimes, but is required for legacy runtime (DirectX 7.0 and earlier) compatibility. See Reporting DirectX 8.0 Style Direct3D Capabilities for details.

This structure is a member of the D3DDEVICEDESC_V1 structure.


Direct3D Driver Enumerations

This section describes the enumerated types that are used by Direct3D® drivers. Enumerated types that are used by both Direct3D drivers and applications, such as D3DRENDERSTATETYPE, are described in the DirectX SDK documentation.

Direct3D DDI Header Files, Sample Code, and References lists the include files that define Direct3D enumerated types.


D3DNTHAL_DP2OPERATION

D3DNTHAL_DP2OPERATION is type defined as D3DHAL_DP2OPERATION in dx95type.h, the shorter form is used here for clarity. Either form is equally valid on Windows 2000 and later implementations, but only the shorter form can be used on Windows 98/Me.


D3DHAL_DP2OPERATION

The D3DHAL_DP2OPERATION enumerated type specifies the D3dDrawPrimitives2 operation in the bCommand member of the D3DHAL_DP2COMMAND structure. The operations are enumerated below.

Note that since the D3DNTDP2OP_XXX format is type defined as D3DDP2OP_XXX internally in the Windows® DDK, the shorter form is used here for clarity. Either form is valid on Windows 2000 and later implementations, but only the shorter form can be used on Windows 98/Me.

Primitive-Rendering Enumerators

Operation | Meaning
D3DDP2OP_CLIPPEDTRIANGLEFAN | DirectX 8.0 and later versions only. This token is sent to the driver to draw transformed, clipped triangle fans. This token is a replacement for the DirectX 7.0 tokens that used inline vertices in the command stream. The triangle fans are specified by one or more D3DHAL_CLIPPEDTRIANGLEFAN structures.
D3DDP2OP_DRAWINDEXEDPRIMITIVE | DirectX 8.0 and later versions only. This token is sent to the driver to draw indexed primitives. D3DDP2OP_DRAWINDEXEDPRIMITIVE2 is used if the vertex data has been transformed by the runtime. The indexed primitives are specified by one or more D3DHAL_DP2DRAWINDEXEDPRIMITIVE structures.
D3DDP2OP_DRAWINDEXEDPRIMITIVE2 | DirectX 8.0 and later versions only. This token is sent to the driver to draw indexed primitives if the vertex data has been transformed by the runtime. Stream zero contains transform and lit vertices and is the only stream that should be accessed. The indexed primitives are specified by one or more D3DHAL_DP2DRAWINDEXEDPRIMITIVE2 structures.
D3DDP2OP_DRAWPRIMITIVE | DirectX 8.0 and later versions only. This token is sent to the driver to draw non-indexed primitives. D3DDP2OP_DRAWPRIMITIVE2 is used if the vertex data has been transformed by the runtime. The primitives are specified by one or more D3DHAL_DP2DRAWPRIMITIVE structures.
D3DDP2OP_DRAWPRIMITIVE2 | DirectX 8.0 and later versions only. This token is sent to the driver to draw non-indexed primitives where the vertex data has been transformed by the runtime. Stream zero contains transform and lit vertices and is the only stream that should be accessed. The primitives are specified by one or more D3DHAL_DP2DRAWPRIMITIVE2 structures.
D3DDP2OP_DRAWRECTPATCH | DirectX 8.0 and later versions only. This token is sent to the driver to draw a rectangular patch. This token is sent to the driver when drawing a new patch, drawing a cached patch or to update the specification of a previously defined patch. The patches are specified by one or more D3DHAL_DP2DRAWRECTPATCH structures.
D3DDP2OP_DRAWTRIPATCH | DirectX 8.0 and later versions only. This token is sent to the driver to draw a triangular patch. This token is sent to the driver when drawing a new patch, drawing a cached patch or to update the specification of a previously defined patch. The patches are specified by one or more D3DHAL_DP2DRAWTRIPATCH structures.
D3DDP2OP_INDEXEDLINELIST | Draws a list of lines, with each line specified by a pair of vertex indexes. The indexed line list is specified by one or more D3DHAL_DP2INDEXEDLINELIST structures.
D3DDP2OP_INDEXEDLINELIST2 | Draws a list of lines. Each line is specified by a pair of vertex indexes, with each offset from the beginning of the vertex buffer by a fixed amount. The indexed line list is specified by one or more D3DHAL_DP2INDEXEDLINELIST structures.
D3DDP2OP_INDEXEDLINESTRIP | Draws a connected strip of lines defined by a sequence of vertex indexes. The indexed line strip is specified by a D3DHAL_DP2INDEXEDLINESTRIP structure.
D3DDP2OP_INDEXEDTRIANGLEFAN | Draws a triangle fan. The triangle fan is specified by a sequence of vertex indexes. The indexed triangle fan is specified by a D3DHAL_DP2INDEXEDTRIANGLEFAN structure.
D3DDP2OP_INDEXEDTRIANGLELIST | Draws a list of triangles. Each triangle is specified by three indexes into the vertex buffer, one index per triangle vertex. The triangle list is specified by one or more D3DHAL_DP2INDEXEDTRIANGLELIST structures.
D3DDP2OP_INDEXEDTRIANGLELIST2 | Draws a list of triangles. Each triangle is specified by three indexes into the vertex buffer, one index per triangle vertex. The triangle list is specified by one or more D3DHAL_DP2INDEXEDTRIANGLELIST2 structures.
D3DDP2OP_INDEXEDTRIANGLESTRIP | Draws a connected strip of triangles that are specified by a sequence of vertex indexes. The three most current vertex indexes are used to draw each triangle. The indexed triangle list is specified by a D3DHAL_DP2INDEXEDTRIANGLELIST structure.
D3DDP2OP_LINELIST | Draws a list of lines. Each line is specified by a pair of vertices. The vertices are processed in sequential order starting at an initial specified vertex index. The line list is specified by a D3DHAL_DP2LINELIST structure.
D3DDP2OP_LINELIST_IMM | Draws a set of lines. Each line is specified by a pair of vertices stored in the command stream (immediate data). The wPrimitiveCount member of the D3DHAL_DP2COMMAND structure specifies how many pairs of vertices follow. The type and size of the vertices are determined by the dwVertexType member of the D3DHAL_DRAWPRIMITIVES2DATA structure.
D3DDP2OP_LINESTRIP | Draws a connected strip of lines defined by a sequence of vertices starting at an initial specified vertex index. The line strip is specified by a D3DHAL_DP2LINESTRIP structure.
D3DDP2OP_POINTS | Draws a list of indexed or non-indexed points. Each list is specified by one or more D3DHAL_DP2POINTS structures.
D3DDP2OP_TRIANGLEFAN | Draws a triangle fan. The fan is specified by a sequence of vertices that start at an initial specified vertex index. The triangle fan is specified by a D3DHAL_DP2TRIANGLEFAN structure.
D3DDP2OP_TRIANGLEFAN_IMM | Draws a triangle fan. The fan is specified by a sequence of vertices stored in the command stream (immediate data). The wPrimitiveCount member of the D3DHAL_DP2COMMAND structure specifies the number of triangles to render. The type and size of the vertices are specified by the dwVertexType member of the D3DHAL_DRAWPRIMITIVES2DATA structure.
D3DDP2OP_TRIANGLELIST | Draws a list of triangles. Each triangle is specified by three vertices that are processed starting at an initial specified vertex index. The triangles are processed in sequential order. The triangle list is specified by a D3DHAL_DP2TRIANGLELIST structure.
D3DDP2OP_TRIANGLESTRIP | Draws a connected strip of triangles. Each triangle is specified by a sequence of vertices starting at an initial specified vertex index. The three most current vertices are used to draw each triangle. The triangle list is specified by a D3DHAL_DP2TRIANGLESTRIP structure.

Non-Primitive-Rendering Enumerators

Operation | Meaning
D3DDP2OP_ADDDIRTYBOX | DirectX 8.1 and later versions only. Specifies a portion of a 3D resource—a volume texture—was dirtied in system memory. This volume texture is specified in a D3DHAL_DP2ADDDIRTYBOX structure. This volume must be reloaded into video memory before being used.
D3DDP2OP_ADDDIRTYRECT | DirectX 8.1 and later versions only. Specifies a portion of a 2D resource—a 2D texture or cube texture—was dirtied in system memory. This 2D texture is specified in a D3DHAL_DP2ADDDIRTYRECT structure. This 2D texture must be reloaded into video memory before being used.
D3DDP2OP_BUFFERBLT | DirectX 8.0 and later versions only. Specifies a blt operation from a source vertex or index buffer to a destination vertex or index buffer. It is specified by one or more D3DHAL_DP2BUFFERBLT structures.
D3DDP2OP_CLEAR | Specifies a clear operation. Replaces the Clear and Clear2 callbacks. See D3DHAL_DP2CLEAR.
D3DDP2OP_CREATELIGHT | Creates a light. See D3DHAL_DP2CREATELIGHT.
D3DDP2OP_CREATEPIXELSHADER | DirectX 8.0 and later versions only. This token is sent to the driver when a pixel shader is created. This token gives the driver the opportunity to convert the pixel shader code into a hardware specific format and associate this information with the given shader handle. See D3DHAL_DP2CREATEPIXELSHADER.
D3DDP2OP_CREATEVERTEXSHADER | DirectX 8.0 and later versions only. This token is sent to the driver when a vertex shader is created. This token gives the driver the opportunity to convert the vertex shader declaration and code into a hardware specific format and associate this information with the given shader handle. See D3DHAL_DP2CREATEVERTEXSHADER.
D3DDP2OP_DELETEPIXELSHADER | DirectX 8.0 and later versions only. This token is sent to the driver to notify the driver of the deletion of a pixel shader and to give the driver an opportunity to clean up any driver side resources associated with the given pixel shader. Note that this uses the same structure (D3DHAL_DP2PIXELSHADER) as D3DDP2OP_SETVPIXELSHADER.
D3DDP2OP_DELETEVERTEXSHADER | DirectX 8.0 and later versions only. This token is sent to the driver to notify the driver of the deletion of a vertex shader and to give the driver an opportunity to clean up any driver side resources associated with the given vertex shader. Note that this uses the same structure (D3DHAL_DP2VERTEXSHADER) as D3DDP2OP_SETVERTEXSHADER.
D3DDP2OP_EXT | Behavior not yet defined. See D3DHAL_DP2EXT.
D3DDP2OP_MULTIPLYTRANSFORM | Multiplies a current transform. See D3DHAL_DP2MULTIPLYTRANSFORM.
D3DDP2OP_RENDERSTATE | Specifies a render state change that requires processing. The rendering state to change is specified by one or more D3DHAL_DP2RENDERSTATE structures.
D3DDP2OP_SETCLIPPLANE | Specifies that a user-defined clip plane is being used. See D3DHAL_DP2SETCLIPPLANE.
D3DDP2OP_SETINDICES | DirectX 8.0 and later versions only. Sets the current index buffer. See D3DHAL_DP2SETINDICES.
D3DDP2OP_SETLIGHT | Specifies that a light is being set. See D3DHAL_DP2SETLIGHT.
D3DDP2OP_SETMATERIAL | Sets the properties for a material. D3DHAL_DP2SETMATERIAL is a D3DMATERIAL7 structure (described in the DirectX® SDK documentation) that is used to set the material properties.
D3DDP2OP_SETPALETTE | Specifies that the palette is being set for a texture. See D3DHAL_DP2SETPALETTE.
D3DDP2OP_SETPIXELSHADER | DirectX 8.0 and later versions only. This token is passed to the driver to set the current pixel shader. All subsequent drawing operations should use the given shader until another is selected. Note that this uses the same structure (D3DHAL_DP2PIXELSHADER) as D3DDP2OP_DELETEPIXELSHADER.
D3DDP2OP_SETPIXELSHADERCONST | DirectX 8.0 and later versions only. This token is passed to the driver to set one or more pixel shader constant registers. See D3DHAL_DP2SETPIXELSHADERCONST.
D3DDP2OP_SETPRIORITY | Sets the priority of a managed texture. See D3DHAL_DP2SETPRIORITY.
D3DDP2OP_SETRENDERTARGET | Sets the render target. Direct3D drivers must respond to this opcode exactly the same as with the older SetRenderTarget callback. See D3DHAL_DP2SETRENDERTARGET.
D3DDP2OP_SETSTREAMSOURCE | DirectX 8.0 and later versions only. Binds a vertex stream source to a vertex buffer. See D3DHAL_DP2SETSTREAMSOURCE.
D3DDP2OP_SETSTREAMSOURCEUM | DirectX 8.0 and later versions only. Binds a vertex stream source to a user memory buffer. See D3DHAL_DP2SETSTREAMSOURCEUM.
D3DDP2OP_SETTEXLOD | Indicates that the level of detail (LOD) for MIP maps is being set. See D3DHAL_DP2SETTEXLOD.
D3DDP2OP_SETTRANSFORM | Sets up a transform. See D3DHAL_DP2SETTRANSFORM.
D3DDP2OP_SETVERTEXSHADER | DirectX 8.0 and later versions only. This token is passed to the driver to set the current vertex shader. All subsequent drawing operations should use the given shader until another is selected. Note that this uses the same structure (D3DHAL_DP2VERTEXSHADER) as D3DDP2OP_DELETEVERTEXSHADER.
D3DDP2OP_SETVERTEXSHADERCONST | DirectX 8.0 and later versions only. This token is passed to the driver to set one or more vertex shader constant registers. See D3DHAL_DP2SETVERTEXSHADERCONST.
D3DDP2OP_STATESET | Specifies a stateset operation to perform. See D3DHAL_DP2STATESET.
D3DDP2OP_TEXBLT | Specifies a blt operation from a source texture to a destination texture. It is used as a more efficient alternative to the DirectDraw® Blt DDI. It is specified by one or more D3DHAL_DP2TEXBLT structures. Since Direct3D drivers maintain all the state necessary to do a blt (for example, texture handles and blending modes), a blt can be accomplished with just the information in the D3DDP2OP_TEXBLT opcode. This new token signals the driver that a texture has to be transferred from system memory into local or nonlocal video memory.
D3DDP2OP_TEXTURESTAGESTATE | Specifies a texture render state change that requires processing. The render state to change is specified by one or more D3DTEXTURESTAGESTATETYPE values following a D3DHAL_DP2COMMAND.
D3DDP2OP_UPDATEPALETTE | Specifies that a texture palette is to be updated. See D3DHAL_DP2UPDATEPALETTE.
D3DDP2OP_VIEWPORTINFO | Specifies the clipping rectangle that is used for guard-band clipping by guard-band aware drivers. The clipping rectangle (that is, the viewing rectangle) is specified by the D3DHAL_DP2VIEWPORTINFO structure.
D3DDP2OP_VOLUMEBLT | DirectX 8.0 and later versions only. Specifies a blt operation from a source volume texture to a destination volume texture. It is specified by one or more D3DHAL_DP2VOLUMEBLT structures.
D3DDP2OP_WINFO | Specifies the w range for w buffering. This range is specified by one or more D3DHAL_DP2WINFO structures.
D3DDP2OP_ZRANGE | Specifies the range of z values. See D3DHAL_DP2ZRANGE.


D3DOPCODE

The D3DOPCODE enumerated type is obsolete.

See D3DHAL_DP2OPERATION for current opcodes.


D3DRENDERSTATETYPE

The D3DRENDERSTATETYPE enumerated type lists a variety of attributes, or render states, that the driver uses when it performs graphics rendering. These attributes include such characteristics as whether alpha blending is enabled, whether dithering is enabled, whether Direct3D lighting is used, and the type of shading to be used.

Only render states that are specific to the DDK are included here. The render states accessible to DirectX applications are included in the DirectX SDK documentation.

Enumerator | Description
Miscellaneous Rendering
D3DRENDERSTATE_SCENECAPTURE | Specifies either begin scene information or end scene information for geometric data captured within a frame.
D3DRS_DELETERTPATCH | DirectX 8.0 and later versions only. Deletes a patch (rectangular or triangular).
Textures
D3DRENDERSTATE_EVICTMANAGEDTEXTURES | Determines whether textures are evicted from memory.

Comments

To update a particular render state, Direct3D stores information about the render state, and then calls the driver's D3dDrawPrimitives2 callback routine. The information provided to the driver enables it to:

  • Determine that it should update one or more render states.
  • Identify which render states to update, and what the new render state values should be.

Note that for certain render states to be honored, the driver must have previously set capability flags in the relevant member of the D3DPRIMCAPS structure.

In order to indicate a specific render state update, Direct3D inserts a D3DHAL_DP2COMMAND structure into the command buffer, setting the bCommand member of this structure to D3DDP2OP_RENDERSTATE, and setting the wStateCount member of the same structure to the number of render states to be updated.

Immediately following the D3DHAL_DP2COMMAND structure, Direct3D inserts one D3DHAL_DP2RENDERSTATE structure into the command buffer for each render state to be updated. The RenderState member of this structure identifies the render state to be changed; the new value of this render state is specified in either the dwState member (for DWORD values) or the fState member (for D3DVALUE values).

The following figure shows a portion of the command buffer containing a D3DDP2OP_RENDERSTATE command and two D3DHAL_DP2RENDERSTATE structures. The first of the three structures indicates that two render states are to be updated. The second structure indicates that the D3DRENDERSTATE_FILLMODE render state is to be changed to D3DFILL_SOLID. The third structure indicates that the D3DRENDERSTATE_SHADEMODE render state should be updated to D3DSHADE_GOURAUD.

Additional Notes

See the D3DTEXTURESTAGESTATETYPE, D3DTEXTUREOP, and D3DTEXTUREFILTER enumerated types in the DirectX SDK documentation for complete listings of all of the enabled render state types.

Some changes have been made to the D3DRENDERSTATETYPE enumerated type for DirectX 5.0 and beyond. D3DRENDERSTATE_BLENDENABLE has been removed completely although it is defined as D3DRENDERSTATE_ALPHABLENDENABLE in the d3dtypes.h header file. See D3DRENDERSTATE_COLORKEYENABLE for an explanation. The 128 integer values in the interval [128, 255] are reserved for texture coordinate wrap flags. These are constructed with the D3DWRAP_U and D3DWRAP_V macros. Using a flags word preserves forward compatibility with texture coordinates of higher dimension than 2D.

Multitexture macro ops and D3DRENDERSTATE_TEXTUREFACTOR override all of the per-texture stage blending controls (COLOR{OP,ARG1,ARG2} & ALPHA{OP,ARG1,ARG2}).


D3DRENDERSTATE_EVICTMANAGEDTEXTURES

The D3DRENDERSTATE_EVICTMANAGEDTEXTURES DDI render state is one value of the D3DRENDERSTATETYPE enumerated type. It is used to evict textures from memory.

Render State Value Type | Default Value
BOOL | None

Comments

This render state determines whether the driver evicts textures that it manages (as opposed to textures managed by the Direct3D runtime) from video memory. If the render state value is TRUE, the driver evicts the textures. Otherwise, the driver does not evict those textures.


D3DRENDERSTATE_SCENECAPTURE

The D3DRENDERSTATE_SCENECAPTURE render state is one value of the D3DRENDERSTATETYPE enumerated type. It replaces the legacy D3DHALCallbacks->D3dSceneCapture callback routine. This render state is handled along with the other render states in D3dDrawPrimitives2.

The driver responds to D3DRENDERSTATE_SCENECAPTURE by passing TRUE for begin scene information and FALSE for end scene information to capture geometric data within a frame.

See the permedia2 sample driver that ships with this DDK for an example implementation.

Render State Value Type | Default Value
BOOL | TRUE

Comments

Care must be taken in updating a driver that implements the legacy D3DHALCallbacks->D3dSceneCapture callback routine to one using the D3DRENDERSTATE_SCENECAPTURE render state. The D3DSceneCapture callback routine uses the constants D3DHAL_SCENE_CAPTURE_START and D3DHAL_SCENE_CAPTURE_END to indicate, respectively, the beginning and end of a scene. The values of these constants are, respectively, 0 and 1. If you use these constants in place of TRUE and FALSE in this render state, the meaning will be the exact opposite of what you intend.


D3DRS_DELETERTPATCH

The D3DRS_DELETERTPATCH DDI render state is one value of the D3DRENDERSTATETYPE enumerated type. It is used to delete rectangular or triangular patches from memory.

Render State Value Type | Default Value
DWORD | None

DirectX 8.0 and later versions only.

Comments

This render state notifies the driver that a patch is to be deleted. The value of this render state is the handle to the patch affected. All cached information should be freed and the handle should be removed from the driver's patch handle table. This render state is not API visible, but is generated internally by the API call DeletePatch. This render state is sent to the driver only when patches are deleted by the API explicitly. All other patches should be cleaned up when the device is destroyed.


DirectX Video Acceleration Structures

This section provides information about the video acceleration structures used by Microsoft® DirectX®. These structures are described in the following topics:

DXVA_AYUVsample2

DXVA_BlendCombination

DXVA_BufferDescription

DXVA_ConfigAlphaCombine

DXVA_ConfigAlphaLoad

DXVA_ConfigPictureDecode

DXVA_ConnectMode

DXVA_EncryptProtocolHeader

DXVA_Highlight

DXVA_MBctrl_I_HostResidDiff_1

DXVA_MBctrl_I_OffHostIDCT_1

DXVA_MBctrl_P_HostResidDiff_1

DXVA_MBctrl_P_OffHostIDCT_1

DXVA_MVvalue

DXVA_PictureParameters

DXVA_PicResample

DXVA_QmatrixData

DXVA_SliceInfo

DXVA_TCoef4Group

DXVA_TCoefSingle


DXVA_AYUVsample2

The DXVA_AYUVsample2 structure specifies the value of a color in Y, Cb, Cr color space and an associated opacity value.

typedef struct _DXVA_AYUVsample2 {
  BYTE bCrValue;
  BYTE bCbValue;
  BYTE bY_Value;
  BYTE bSampleAlpha8;
} DXVA_AYUVsample2, *LPDXVA_AYUVsample2;

Members

bCrValue
Specifies a Cr chrominance sample (scaled per ITU-R Rec. BT.601) as an unsigned quantity. Thus, the color black is nominally specified by Y=16, Cb=Cr=128, and the color white is nominally specified by Y=235, Cb=Cr=128.
bCbValue
Specifies a color in Cb color space (scaled per ITU-R Rec. BT.601) as an unsigned quantity. Thus the color black is nominally specified by Y=16, Cb=Cr=128, and the color white is nominally specified by Y=235, Cb=Cr=128.
bY_Value
Specifies a color in Y color space (scaled per ITU-R Rec. BT.601) as an unsigned quantity. Thus the color black is nominally specified by Y=16, Cb=Cr=128, and the color white is nominally specified by Y=235, Cb=Cr=128.
bSampleAlpha8
Specifies the opacity of the sample. A value of zero indicates that the sample is transparent (so that the other entries have no effect on the resulting blended picture), and a value of 255 indicates that the sample is opaque (so that the other entries completely determine the value of the resulting blended picture sample).

For nonzero values of bSampleAlpha8, the blend specified is found by adding (bSampleAlpha8+1) times the graphic value to (255–bSampleAlpha8) times the picture value and then adding this to the constant 128, and right-shifting the result by eight places.

For a zero value of bSampleAlpha8, the blend specified is to use the picture value without alteration.

Note If the alpha blending surface originates as a DVD Video subpicture, the preferred method for converting from the 4-bit alpha used by DVD video to the 8-bit alpha specified by bSampleAlpha8 is to map zero to zero and convert all nonzero 4-bit alphas to 8-bit alphas by performing a right shift of four places and adding the constant 15.

Headers

Declared in dxva.h. Include dxva.h.

Comments

The width and height of the AYUV alpha blending surface are specified in the associated buffer description list defined by the DXVA_BufferDescriptionstructure.

The DXVA_AYUVsample2 structure is used for each sample in a DXVA AYUV blending surface and for OutsideYUVcolor in a DXVA_BlendCombination structure. The same structure is also used for 16-entry AYUV alpha-blending palettes.


DXVA_BlendCombination

The DXVA_BlendCombination structure governs the generation of a blended picture from a source picture and a graphic image with accompanying alpha blending information.

typedef struct _DXVA_BlendCombination {
  WORD  wPictureSourceIndex;
  WORD  wBlendedDestinationIndex;
  RECT  PictureSourceRect16thPel;
  RECT  PictureDestinationRect;
  RECT  GraphicSourceRect;
  RECT  GraphicDestinationRect;
  WORD  wBlendDelay;
  BYTE  bBlendOn;
  BYTE  bWholePlaneAlpha;
  DXVA_AYUVsample2  OutsideYUVcolor;
} DXVA_BlendCombination, *LPDXVA_BlendCombination;

Members

wPictureSourceIndex
Specifies the index of the picture to be combined with the graphic. This value is 0xFFFF if back-end hardware alpha blending is in use (when the bConfigBlendType member of DXVA_ConfigAlphaCombine is 1).
wBlendedDestinationIndex
Specifies the index of the combined picture to be created. This value is 0xFFFF if back-end hardware alpha blending is in use (when the bConfigBlendType member of DXVA_ConfigAlphaCombine is 1).

This value cannot be equal to wPictureSourceIndex unless back-end hardware alpha blending is in use.

PictureSourceRect16thPel
Specifies the area of the source picture to be combined with the graphic, specified as a RECT structure in units of 1/16th sample in the luminance component. In other words, the members in the RECT structure are fixed-point representations that each have 28 bits before and four bits after the binary point. (This 1/16th sample accuracy allows PictureSourceRect16thPel to contain the same accuracy as the frame_centre_horizontal_offset and frame_centre_vertical_offset pan-scan parameters in MPEG-2.)

If the bConfigPictureResizing member of DXVA_ConfigAlphaCombine is zero, all dimensions in PictureSourceRect16thPel must be integer multiples of 16.

The following restrictions apply to the RECT dimensions of PictureSourceRect16thPel:

  • left and top must be greater than or equal to zero.
  • right and bottom must be greater than or equal to left and top, respectively.
  • If right is equal to left or top is equal to bottom, a case that is allowed only if the bConfigOnlyUsePicDestRectArea member of DXVA_ConfigAlphaCombine is zero, all of the RECT members must have the value zero, indicating that the source picture is not used.
  • right and bottom must not exceed sixteen times the allocated width and height, respectively, of the uncompressed source picture surface.

For example, if PictureSourceRect16thPel is used to select an entire MPEG-2 decoded picture, the PictureSourceRect16thPel values can be computed as follows:

  • left = 0
  • top = 0
  • right = 16 X horizontal_size
  • bottom = 16 X vertical_size
PictureDestinationRect
Specifies the area of the destination picture that will contain the area from the source picture. The area is specified as a RECT structure.

If the bConfigPictureResizing member of DXVA_ConfigAlphaCombineis zero, PictureDestinationRect must have the same width and height as the area specified by PictureSourceRect16thPel. If PictureDestinationRect differs in size from PictureSourceRect16thPel, the resampling method to be applied is not specified, but must have a quality which is at least equivalent to that of bilinear resampling.

The following restrictions apply to the RECT dimensions:

  • left and top must be greater than or equal to zero.
  • right and bottom must be greater than or equal to left and top, respectively.
  • If right is equal to left or top is equal to bottom, a case only allowed if the bConfigOnlyUsePicDestRectArea member of DXVA_ConfigAlphaCombine is zero, all of the RECT members must have the value zero and PictureSourceRect16thPel must also specify all values having the value zero.
  • If the bConfigBlendType member of DXVA_ConfigAlphaCombine is zero, right and bottom must not exceed the allocated width and height, respectively, of the uncompressed destination picture surface.
  • Ιf the bConfigBlendType member of DXVA_ConfigAlphaCombine is one, right and bottom must not exceed the allocated width and height, respectively, of the source graphic surface.
GraphicSourceRect
Specifies the area of the graphic picture to be combined with the source picture. This area is specified as a RECT structure.

If alpha-blend data loading uses the bConfigDataType member of DXVA_ConfigAlphaLoad with a value of 2, the following restrictions on GraphicSourceRect dimensions apply:

  • top and left must be zero.
  • right must be equal to the "End X-coordinate" minus the "Start X-coordinate" of the last preceding DVD SET_DAREA DCCMD, plus 1 to adjust for the differing rectangle interpretations as described in the note below.
  • bottom must be equal to the "End Y-coordinate" minus the "Start Y-coordinate" of the last preceding DVD SET_DAREA DCCMD, plus 1 to adjust for the differing rectangle interpretations as described in the note below.

The following restrictions apply to the RECT dimensions:

  • left and top must be greater than or equal to zero.
  • right and bottom must be greater than or equal to left and top, respectively.
  • If right is equal to left or top is equal to bottom, all of the RECT members must have the value zero, indicating no use of the graphic picture.
  • right and bottom must not exceed the allocated width and height, respectively, of the graphic source surface. The allocated width and height are defined as 720 and 576, respectively, when the bConfigDataType member of DXVA_ConfigAlphaLoad equals 2.
GraphicDestinationRect
Specifies the area of the destination picture that will contain the area from the graphic picture. This value is specified as a RECT structure.

If the bConfigGraphicResizing member of DXVA_ConfigAlphaCombine is zero, the destination picture must have the same width and height as the area specified by GraphicSourceRect. If GraphicDestinationRect differs in size from GraphicSourceRect, the resampling method to be applied to the graphic is not specified. However, the resampling method to be used should have a quality that is at least equivalent to a bilinear resampling of an AYUV surface that represents the blending information.

The following restrictions apply to the RECT members of GraphicDestinationRect:

  • left and top must be greater than or equal to zero, unless this requirement conflicts with the need to offset the graphic by eight samples. This is the case in the following scenarios:
  • Alpha-blend data loading uses the bConfigDataType member of DXVA_ConfigAlphaCombine with a value of 2 and the bConfigGraphicResizing member of DXVA_ConfigAlphaCombine with a value of zero.
  • Operation is set for DVD 704-wide non-pan-scan picture operation.
  • Operation is set for DVD 352-wide picture operation.
  • right and bottom must be greater than or equal to left and top, respectively.
  • If right is equal to left or top is equal to bottom, then all of the RECT members must have the value zero and GraphicSourceRect must also specify all members having the value zero.
  • Ιf the bConfigBlendType member of DXVA_ConfigAlphaCombine equals zero, right and bottom must not exceed the allocated width and height, respectively, of the uncompressed destination picture surface.
  • Ιf the bConfigBlendType member of DXVA_ConfigAlphaCombine is equal to 1, right and bottom must not exceed the allocated width and height, respectively, of the source graphic surface.

If alpha-blend data loading uses the bConfigDataType member of DXVA_ConfigAlphaCombine with a value of 2 and the bConfigGraphicResizing member of DXVA_ConfigAlphaCombine with a value of zero, the following additional restrictions on GraphicDestinationRect dimensions apply:

  • top must be equal to the "Start Y-coordinate" of the last preceding DVD SET_DAREA DCCMD.
  • left must be equal to either the "Start X-coordinate" of the last preceding DVD SET_DAREA DCCMD or to that value minus 8. For further information, see DVD 704-Wide Non-Pan-Scan Picture Operationand DVD 352-Wide Picture Operation.
  • right must be equal to the value of left plus the "End X-coordinate" minus the "Start X-coordinate" of the last preceding DVD SET_DAREA DCCMD, plus 1 to adjust for the differing rectangle interpretations described in the following note.
  • bottom must be equal to the value of top plus the "End Y-coordinate" minus the "Start Y-coordinate" of the last preceding DVD SET_DAREA DCCMD, plus 1 to adjust for the differing rectangle interpretations described in the following note.

Note There is a difference between the way the DVD video specification defines a subpicture rectangular area and the convention used by Microsoft. This reference follows the Microsoft convention so that a rectangle of width ten and height ten in the upper left corner of the picture is defined by top = 0, left = 0, right = 10, and bottom = 10. The DVD video specification uses an equivalent of right = 9 and bottom = 9.

wBlendDelay
If back-end hardware blending is in use (for example, if the bConfigBlendType member of DXVA_ConfigAlphaCombine is one), wBlendDelay contains a number of milliseconds of delay prior to the combination operation going into effect. This member has no meaning and must be zero if front-end blending is in use.
bBlendOn
If back-end hardware blending is in use, the specified blending is applied from the time specified in a blending combination function (with bBlendOn equal to one) until the specified execution time of a new blending combination (with bBlendOn equal to one) or until the blending is disabled by a blending combination function (with bBlendOn equal to zero). This member has no meaning and must be zero if front-end blending is in use.

If back-end hardware blending is in use and bBlendOn is zero, the only other value in the alpha-blend combination buffer that has meaning is wBlendDelay.

bWholePlaneAlpha
Contains an opacity multiplier for the alpha channel of the graphic. The value zero indicates that the graphic is transparent (so that the graphic content has no effect on the resulting blended picture) and the value 255 indicates that the graphic content uses its full sample opacity. If bWholePlaneAlpha is not equal to zero, the blend specified is to multiply the opacity of each location in the graphic content by (bWholePlaneAlpha+1)/256. For a zero value of bWholePlaneAlpha, the blend to use is the opacity specified in the graphic content without alteration. This must be equal to 255 if the bConfigWholePlaneAlpha member of DXVA_ConfigAlphaCombineis zero.
OutsideYUVcolor
Indicates whether areas outside of the PictureDestinationRect use a constant color for blending. If so, this member specifies that color constant.

OutsideYUVcolor is formatted as the DXVA_AYUVsample2 structure and uses the following convention:

  • The value of bSampleAlpha8 in OutsideYUVcolor must be 255 if the areas outside of the PictureDestinationRect are generated as a constant color for blending.
  • The value of bSampleAlpha8 in OutsideYUVcolor must be zero if either of the following two cases applies:
  1. The areas outside of the PictureDestinationRect are unaffected by the blend.
  2. The areas outside of the PictureDestinationRect cannot be used (as indicated by the bConfigStayInPicDestRectArea member of DXVA_ConfigAlphaCombine having a value of one).

All other values for bSampleAlpha8 in OutsideYUVcolor are reserved for future use.

The value of bSampleAlpha8 in OutsideYUVcolor must be zero if the bConfigStayInPicDestRectArea member of DXVA_ConfigAlphaCombine equals one.

If bSampleAlpha8 in OutsideYUVcolor is zero, the only area of the destination surface that is affected by the blend is the part within the PictureDestinationRect.

If bSampleAlpha8 in OutsideYUVcolor is 255, any area of the destination surface that is outside of the PictureDestinationRect but within the GraphicDestinationRect is generated by blending the graphic with the color specified in the non-alpha members of OutsideYUVcolor. In this case, the entire allocated area of the destination surface that falls outside of both PictureDestinationRect and GraphicDestinationRect is set to the color specified in the non-alpha members of OutsideYUVcolor. If the bConfigBlendType member of DXVA_ConfigAlphaCombine is one, the OutsideYUVcolor members are set to indicate blending with black by specifying bSampleAlpha8 = 255, bY_Value = 16, bCbValue = bCrValue = 128.

Note When the bConfigBlendType member of DXVA_ConfigAlphaCombine is 1 (back-end hardware blend), the actual blending operations may differ somewhat from those described in this reference. (However, the visual result is equivalent.) Some resizing parameters specified to map a video picture from a source to a destination size may instead be applied in an inverse manner to map the graphic content to its proper location relative to the source video picture, with the blended result displayed in a manner that compensates for this difference in operation. The final visual effect of the result must be as specified by the blend combination command.

Headers

Declared in dxva.h. Include dxva.h.

Comments

In the event that the source and destination pictures are not in 4:4:4 format, every second sample of the graphic blending information (for example, the first, third, or fifth) is applied to the subsampled source chrominance information in the vertical or horizontal direction as applicable to produce the blended result.


DXVA_BufferDescription

The DXVA_BufferDescription structure contains data about one buffer that is passed from the host to the accelerator.

typedef struct _DXVA_BufferDescription {
  DWORD  dwTypeIndex;
  DWORD  dwBufferIndex;
  DWORD  dwDataOffset;
  DWORD  dwDataSize;
  DWORD  dwFirstMBaddress;
  DWORD  dwNumMBsInBuffer;
  DWORD  dwWidth;
  DWORD  dwHeight;
  DWORD  dwStride;
  DWORD  dwReservedBits;
} DXVA_BufferDescription, *LPDXVA_BufferDescription;

Members

dwTypeIndex
Specifies the buffer type number of the associated buffer. The following table lists the buffer types.
Value | Buffer Type
1 | Picture decoding parameter buffers
2 | Macroblock control command buffers (closely associated with and having a 1:1 correspondence with residual difference block data buffers)
3 | Residual difference block data buffers
4 | Deblocking filter control command buffers (with or without a restriction on the effect of the filter)
5 | Inverse-quantization matrix buffers (only used with off-host VLD processing)
6 | Slice-control buffers (closely associated with and having a 1:1 correspondence with bitstream data buffers)
7 | Bitstream data buffers
8 | AYUV alpha blending sample buffers
9 | IA44/AI44 alpha blending surface buffers
10 | DPXD alpha blending surface buffers
11 | Highlight data buffers
12 | DCCMD data buffers
13 | Alpha blend combination buffers
14 | Picture resampling control buffers
15 | Read-back command buffers containing commands to read macroblocks of the resulting picture back to the host.
dwBufferIndex
Specifies the sequence number of the buffer within the buffers of the same type that were passed in the same buffer description list.
dwDataOffset
Specifies the offset, in bytes, of the relevant data from the beginning of the buffer. Must be zero.
dwDataSize
Specifies, in bytes, the amount of relevant data in the buffer in bytes. Thus the location of the last byte of content in the buffer is dwDataOffset plus dwDataSize minus 1.
dwFirstMBaddress
Specifies the macroblock address of the first macroblock in the buffer in raster scan order (as determined by the members of DXVA_PictureParameters, with zero being the address of the top-left macroblock, wPicWidthInMBminus1 being the address of the top-right macroblock, and wPicHeightInMBminus1 X (wPicWidthInMBminus1+1) being the address of the bottom-left macroblock, and (wPicHeightInMBminus1+1) X (wPicWidthInMBminus1+1)–1 being the address of the bottom-right macroblock). Must be zero if the data buffer is among the following types: picture decoding parameters, inverse-quantization matrix, slice control, bitstream data, AYUV, IA44/AI44, DPXD, Highlight, or DCCMD. If the data buffer is a residual difference block data buffer, dwFirstMBaddress must have the same value as for the corresponding macroblock control command buffer.
dwNumMBsInBuffer
Specifies the number of macroblocks of data in the buffer. This count includes skipped macroblocks. Must be zero if the data buffer is among the following types: picture decoding parameters, inverse-quantization matrix, AYUV, IA44/AI44, DPXD, Highlight, or DCCMD. If the data buffer is a macroblock control command buffer, dwNumMBsInBuffer must be equal to the total of the values of MBskipsFollowing plus the total number of macroblock control commands in the macroblock control command buffer. If the data buffer is a residual difference block data buffer, dwNumMBsInBuffer must have the same value as for the corresponding macroblock control command buffer. If the data buffer is a slice-control command buffer, dwNumMBsInBuffer must be equal to the total of the values of the wNumberMBsInSlice member of DXVA_SliceInfo in the slice-control buffer. If the data buffer is a bitstream data buffer, dwNumMBsInBuffer must have the same value as for the corresponding slice-control command buffer.
dwWidth
Specifies the width of the data in the buffer. Must be zero unless the data buffer is among the following types: AYUV, IA44/AI44, or DPXD.
dwHeight
Specifies the height of the data in the buffer. Must be zero unless the data buffer is among the following types: AYUV, IA44/AI44, or DPXD.
dwStride
Specifies the stride of the data in the buffer. Must be zero unless the data buffer is among the following types: AYUV, IA44/AI44, or DPXD. For the applicable buffer types, dwStride is determined from the buffer allocation setup performed by the accelerator.

Note The decoder must take care to honor the stride specified for AYUV, IA44/AI44 or DPXD buffers.

dwReservedBits
Reserved bits used for packing and/or alignment. Must be zero.

Headers

Declared in dxva.h. Include dxva.h.

Comments

An array of DXVA_BufferDescription structures is referred to as a buffer description list. When a set of buffers is sent from the host decoder to the hardware accelerator, a buffer description list is sent to describe the buffers. The buffer description list contains one DXVA_BufferDescription structure for each buffer in this set. The buffer description list starts with a DXVA_BufferDescription structure for the first buffer of the first type, followed by a DXVA_BufferDescription structure for the next buffer of the same type, and so on. The buffer description list then continues with a DXVA_BufferDescription structure for the first buffer of the next type, and so on.


DXVA_ConfigAlphaCombine

The DXVA_ConfigAlphaCombine structure establishes the configuration for how DXVA alpha-blending combination operations are to be performed.

typedef struct _DXVA_ConfigAlphaCombine {
  DWORD dwFunction;
  DWORD dwReservedBits[3];
  BYTE  bConfigBlendType;
  BYTE  bConfigPictureResizing;
  BYTE  bConfigOnlyUsePicDestRectArea;
  BYTE  bConfigGraphicResizing;
  BYTE  bConfigWholePlaneAlpha;
} DXVA_ConfigAlphaCombine, *LPDXVA_ConfigAlphaCombine;

Members

dwFunction
The first 24 bits (MSBs) of dwFunction is the QueryOrReplyFlag variable. These bits indicate the type of query or response.
Value | Description
0xFFFFF1 | Sent by the software decoder as a probing command.
0xFFFFF5 | Sent by the software decoder as a locking command.
0xFFFFF8 | Sent by the accelerator with an S_OK response to a probing command with a copy of the probed configuration.
0xFFFFF9 | Sent by the accelerator with an S_OK response to a probing command, but also suggesting an alternative configuration.
0xFFFFFC | Sent by the accelerator with an S_OK response to a locking command with a copy of the locked configuration.
0xFFFFFB | Sent by the accelerator with an S_FALSE response to a probing command with a suggested alternative configuration.
0xFFFFFF | Sent by the accelerator with an S_FALSE response to a locking command with a suggested alternative configuration.

The least significant four bits of dwFunction are interpreted as follows.
Value | Description
3 | Sent by host decoder = 0, by accelerator = 1, associated with a probe = 0, with a lock = 1
1 | Success = 0, failure = 1
0 | Duplicate configuration structure = 0, new structure = 1

The last eight bits of (LSBs) of dwFunction is the bDXVA_Func variable which is equal to three.

dwReservedBits
Reserved bits used for packing and/or alignment. Must be zero.
bConfigBlendType
Specifies the type of alpha-blend combinations to be performed, as defined by:
  • zero for front-end buffer-to-buffer blend
  • one for back-end hardware blend

The preferred value for an accelerator to support for bConfigBlendType is zero.

bConfigPictureResizing
Specifies whether the PictureSourceRect16thPel member of the DXVA_BlendCombination structure for graphic blending may differ in width and height from the PictureDestinationRect (adjusted for the 1/16th-sample scaling of PictureSourceRect16thPel) and whether the values in PictureSourceRect16thPel may not be multiples of sixteen, thus requiring the source picture to be resampled by the accelerator. A value of one indicates that resampling (whether for resizing and/or for sub-pixel accuracy) is supported, a value of zero indicates that it is not.
bConfigOnlyUsePicDestRectArea
Specifies whether the decoder can command operations that specify values for areas of an output generated destination picture that fall outside of the PictureDestinationRect member of DXVA_BlendCombination. The value zero indicates that areas outside of the PictureDestinationRect can be specified by the blend combination commands. The value 1 indicates that the host decoder cannot rely on the values of—and cannot display—any region of the blended surface outside of the area specified by PictureDestinationRect.
bConfigGraphicResizing
Specifies whether the GraphicSourceRect member of DXVA_BlendCombination for subpicture blending may differ in size from the GraphicDestinationRect member of DXVA_BlendCombination, thus requiring the alpha-blending graphic to be resampled by the accelerator. A value of 1 indicates that resizing is supported; a value of zero indicates that it is not.
bConfigWholePlaneAlpha
Specifies whether a whole-plane alpha parameter can be applied to the graphic data. A value of 1 indicates that a whole-plane alpha can be applied; a value of zero indicates that it cannot.

Headers

Declared in dxva.h. Include dxva.h.


DXVA_ConfigAlphaLoad

The DXVA_ConfigAlphaLoad structure establishes the configuration for how DXVA alpha-blending texture-loading operations are to be performed.

typedef struct _DXVA_ConfigAlphaLoad {
  DWORD  dwFunction;
  DWORD  dwReservedBits[3];
  BYTE  bConfigDataType;
} DXVA_ConfigAlphaLoad, *LPDXVA_ConfigAlphaLoad;

Members

dwFunction
The first 24 bits (MSBs) of dwFunction is the QueryOrReplyFlag variable. These bits indicate the type of query or response.
Value | Description
0xFFFFF1 | Sent by the software decoder as a probing command.
0xFFFFF5 | Sent by the software decoder as a locking command.
0xFFFFF8 | Sent by the accelerator with an S_OK response to a probing command with a copy of the probed configuration.
0xFFFFF9 | Sent by the accelerator with an S_OK response to a probing command, but also suggesting an alternative configuration.
0xFFFFFC | Sent by the accelerator with an S_OK response to a locking command with a copy of the locked configuration.
0xFFFFFB | Sent by the accelerator with an S_FALSE response to a probing command with a suggested alternative configuration.
0xFFFFFF | Sent by the accelerator with an S_FALSE response to a locking command with a suggested alternative configuration.

The least significant four bits of QueryOrReplyFlag are interpreted as follows.
Value | Description
3 | Sent by host decoder = 0, by accelerator = 1, associated with a probe = 0, with a lock = 1
1 | Success = 0, failure = 1
0 | Duplicate configuration structure = 0, new structure = 1

The last eight LSBs of dwFunction is the bDXVA_Func variable which is equal to 2.

dwReservedBits
Reserved bits used for packing and/or alignment. Is zero.
bConfigDataType
Specifies the type of alpha-blend data to be used, as defined by the following values.
Value | Description
0 | 16-entry AYUV palette with IA44 alpha blending surface
1 | 16-entry AYUV palette with AI44 alpha blending surface
2 | 16-entry AYUV palette with DPXD, Highlight, and DCCMD data
3 | AYUV graphic surface

The preferred values for an accelerator to support for bConfigDataType are 1 and 3.

Headers

Declared in dxva.h. Include dxva.h.


DXVA_ConfigPictureDecode

The DXVA_ConfigPictureDecode structure establishes the configuration for compressed picture decoding.

typedef struct _DXVA_ConfigPictureDecode {
  DWORD  dwFunction;
  DWORD  dwReservedBits[3];
  GUID  guidConfigBitstreamEncryption;
  GUID  guidConfigMBcontrolEncryption;
  GUID  guidConfigResidDiffEncryption;
  BYTE  bConfigBitstreamRaw;
  BYTE  bConfigMBcontrolRasterOrder;
  BYTE  bConfigResidDiffHost;
  BYTE  bConfigSpatialResid8;
  BYTE  bConfigResid8Subtraction;
  BYTE  bConfigSpatialHost8or9Clipping;
  BYTE  bConfigSpatialResidInterleaved;
  BYTE  bConfigIntraResidUnsigned;
  BYTE  bConfigResidDiffAccelerator;
  BYTE  bConfigHostInverseScan;
  BYTE  bConfigSpecificIDCT;
  BYTE  bConfig4GroupedCoefs;
} DXVA_ConfigPictureDecode, *LPDXVA_ConfigPictureDecode;

Members

dwFunction
The first 24 MSBs of dwFunction is the DXVA_QueryOrReplyFlag variable. These bits indicate the type of query or response.
Value | Description
0xFFFFF1 | Sent by the software decoder as a probing command.
0xFFFFF5 | Sent by the software decoder as a locking command.
0xFFFFF8 | Sent by the accelerator with an S_OK response to a probing command with a copy of the probed configuration.
0xFFFFF9 | Sent by the accelerator with an S_OK response to a probing command, but also suggesting an alternative configuration.
0xFFFFFC | Sent by the accelerator with an S_OK response to a locking command with a copy of the locked configuration.
0xFFFFFB | Sent by the accelerator with an S_FALSE response to a probing command with a suggested alternative configuration.
0xFFFFFF | Sent by the accelerator with an S_FALSE response to a locking command with a suggested alternative configuration.

The least significant four bits of QueryOrReplyFlag are interpreted as follows.
Value | Description
3 | Sent by host decoder equals zero, by accelerator equals 1, associated with a probe equals zero, with a lock equals 1
1 | Success equals zero, failure equals 1
0 | Duplicate configuration structure equals zero, new structure equals 1

The last eight LSBs of dwFunction is the bDXVA_Func variable which is equal to 1.

dwReservedBits
Reserved bits used for packing and/or alignment. Is zero.
guidConfigBitstreamEncryption
Indicates a GUID associated with the encryption protocol type for bitstream data buffers. The value DXVA_NoEncrypt (a GUID name defined in dxva.h) indicates that encryption is not applied. Is DXVA_NoEncrypt if bConfigBitstreamRaw is zero.
guidConfigMBcontrolEncryption
Indicates a GUID associated with the encryption protocol type for macroblock control data buffers. The value DXVA_NoEncrypt (a GUID name defined in dxva.h) indicates that encryption is not applied. Is DXVA_NoEncrypt if bConfigBitstreamRaw is 1.
guidConfigResidDiffEncryption
Indicates a GUID associated with the encryption protocol type for residual difference decoding data buffers (buffers containing spatial-domain data or sets of transform-domain coefficients for accelerator-based IDCT). The value DXVA_NoEncrypt (a GUID name defined in dxva.h) indicates that encryption is not applied. Is DXVA_NoEncrypt if bConfigBitstreamRaw is 1.
bConfigBitstreamRaw
Contains the bitstream processing indicator. A value of 1 specifies that the data for the pictures will be sent in bitstream buffers as raw bitstream content, and a value of zero specifies that picture data will be sent using macroblock control command buffers.

Is zero if bConfigResidDiffHost is 1 or if bConfigResidDiffAccelerator is 1. The value zero is considered the basic level of support. The additional support of level 1 is desired.

bConfigMBcontrolRasterOrder
Contains the macroblock control configuration. A value of one specifies that the macroblock control commands within each macroblock control command buffer are in raster-scan order, and a value of zero indicates arbitrary order. For some types of bitstreams, forcing raster order either greatly increases the number of required macroblock control buffers that must be processed or requires host reordering of the control information. Support of arbitrary order can thus be advantageous for the decoding process. For example, H.261 CIF-resolution decoding can require 36 macroblock control buffers per picture if raster-scan order is necessary within each buffer (H.263 Annex K's arbitrary slice ordering and rectangular slice modes have similar repercussions.). Currently, a driver is allowed to restrict support to a value of 1; however, a driver should support both zero and 1.
bConfigResidDiffHost
Contains the host residual difference configuration. A value of 1 specifies that some residual difference decoding data may be sent as blocks in the spatial domain from the host, and a value of zero specifies that spatial domain data will not be sent. Is zero if bConfigBitstreamRaw is 1. It is preferred that an accelerator support both zero and 1.
bConfigSpatialResid8
Indicates the word size used to represent residual difference spatial-domain blocks for predicted (non-intra) pictures when using host-based residual difference decoding (when bConfigResidDiffHost is equal to one).

If bConfigSpatialResid8 is 1 and bConfigResidDiffHost is 1, this indicates that the host will send residual difference spatial-domain blocks for non-intra macroblocks using 8-bit signed samples, and for intra macroblocks in predicted (non-intra) pictures in a format depending on bConfigIntraResidUnsigned as follows:

  • If bConfigIntraResidUnsigned is zero, spatial-domain blocks for intra macroblocks are sent as 8-bit signed integer values relative to a constant reference value of 128.
  • If bConfigIntraResidUnsigned is 1, spatial-domain blocks for intra macroblocks are sent as 8-bit unsigned integer values relative to a constant reference value of zero.

If bConfigSpatialResid8 is zero and bConfigResidDiffHost is 1, the host will send residual difference spatial-domain blocks of data for non-intra macroblocks using 16-bit signed samples, and for intra macroblocks in predicted (non-intra) pictures in a format depending on bConfigIntraResidUnsigned as follows:

  • If bConfigIntraResidUnsigned is zero, spatial domain blocks for intra macroblocks are sent as 16-bit signed integer values relative to a constant reference value of 2(BPP-1), where BPP is the number of bits per sample for the uncompressed video (normally a value of 8).
  • If bConfigIntraResidUnsigned is 1, spatial domain blocks for intra macroblocks are sent as 16-bit unsigned integer values relative to a constant reference value of zero.

bConfigSpatialResid8 must be zero if bConfigResidDiffHost is zero. There is no preference for one particular value of bConfigSpatialResid8 when bConfigResidDiffHost is 1.

Note For intra pictures, spatial-domain blocks must always be sent using 8-bit samples if BPP is 8 and uses 16-bit samples if BPP is greater than 8, where BPP is the number of bits per sample for the uncompressed video (normally a value of 8).

If bConfigIntraResidUnsigned is zero, these samples are sent as signed integer values relative to a constant reference value of 2(BPP-1), and if bConfigIntraResidUnsigned is 1, these samples are sent as unsigned integer values relative to a constant reference value of zero.

bConfigResid8Subtraction
A value of 1 when bConfigSpatialResid8 is 1 indicates that 8-bit difference overflow blocks are subtracted rather than added. Is zero unless bConfigSpatialResid8 is 1. If 1, this indicates that any overflow blocks will be subtracted rather than added. The preferred value for an accelerator to support is 1 if bConfigSpatialResid8 is 1. This ability to subtract differences rather than to add them allows 8-bit difference decoding to be fully compliant with the full ±255 range of values required in video decoder specifications, since +255 cannot be represented as the addition of two signed 8-bit numbers but any number in the range ±255 can be represented as the difference between two signed 8-bit numbers (+255 = +127 minus –128).
bConfigSpatialHost8or9Clipping
A value of 1 with bConfigSpatialResid8 equal to zero and bConfigResidDiffHost equal to 1 indicates that spatial-domain blocks for intra macroblocks are clipped to an 8-bit range on the host and that spatial-domain blocks for non-intra macroblocks are clipped to a 9-bit range on the host. A value of zero indicates that no such clipping is necessary by the host. Is zero unless bConfigSpatialResid8 is equal to zero and bConfigResidDiffHost is equal to 1. The preferred value for an accelerator to support is zero.
bConfigSpatialResidInterleaved
A value of 1 when bConfigResidDiffHost is 1 and the YUV format is "NV12" or "NV21" indicates that any spatial-domain residual difference data is sent in a chrominance-interleaved form matching the YUV format chrominance interleaving pattern. Is zero unless bConfigResidDiffHost is 1 and the YUV format is "NV12" or "NV21". The preferred value for an accelerator to support is zero.
bConfigIntraResidUnsigned
Indicates the method of representation of spatial-domain blocks of residual difference data for intra blocks when using host-based difference decoding (that is when bConfigResidDiffHost is equal to 1).

If bConfigIntraResidUnsigned is equal to zero with bConfigResidDiffHost equal to 1, this indicates that spatial-domain residual difference data blocks for intra macroblocks are sent as follows:

  • In a non-intra picture if bConfigSpatialResid8 is zero, the spatial-domain residual difference data blocks for intra macroblocks are sent as 16-bit signed integer values relative to a constant reference value of 2(BPP-1), where BPP is the number of bits per sample for the uncompressed video (normally a value of 8).
  • In a non-intra picture if bConfigSpatialResid8 is 1 and in an intra picture if BPP is equal to 8 (regardless of the value of bConfigSpatialResid8), the spatial-domain residual difference data blocks for intra macroblocks are sent as 8-bit signed integer values relative to a constant reference value of 128.

When bConfigIntraResidUnsigned is equal to 1 with bConfigResidDiffHost equal to 1, spatial-domain residual difference data blocks for intra macroblocks are sent as follows:

  • In a non-intra picture if bConfigSpatialResid8 is zero, the spatial-domain residual difference data blocks for intra macroblocks are sent as 16-bit unsigned integer values relative to a constant reference value of zero.
  • In a non-intra picture if bConfigSpatialResid8 is 1 and in an intra picture if BPP is equal to 8 (regardless of the value of bConfigSpatialResid8), the spatial-domain residual difference data blocks for intra macroblocks are sent as 8-bit unsigned integer values relative to a constant reference value of zero.

bConfigIntraResidUnsigned must be zero unless bConfigResidDiffHost is 1.

The preferred value for an accelerator to support is zero for bConfigIntraResidUnsigned.

bConfigResidDiffAccelerator
Contains the accelerator residual difference configuration. A value of 1 indicates that transform-domain blocks of coefficient data may be sent from the host for accelerator-based IDCT, and a value of zero specifies that accelerator-based IDCT will not be used. If both bConfigResidDiffHost and bConfigResidDiffAccelerator are one, this indicates that some residual difference decoding will be done on the host and some on the accelerator, as indicated by macroblock-level control commands. Must be zero if bConfigBitstreamRaw is 1.

The preferred value for an accelerator to support is 1 for bConfigResidDiffAccelerator.

Support for bConfigResidDiffAccelerator equal to 1 with bConfigResidDiffHost also equal to 1 indicates that the residual difference decoding can be shared between the host and accelerator on a macroblock basis, and is considered an even higher level of accelerator capability than bConfigResidDiffAccelerator equal to 1 with bConfigResidDiffHost equal to zero.

bConfigHostInverseScan
A value of 1 indicates that the inverse scan for transform-domain block processing will be performed on the host, and absolute indices will be sent instead for any transform coefficients. A value of zero indicates that inverse scan will be performed on the accelerator. Must be zero if bConfigResidDiffAccelerator is zero. Must be zero if bConfig4GroupedCoefs is 1.

The preferred value for an accelerator to support is 1 if bConfigResidDiffAccelerator is 1.

bConfigSpecificIDCT
A value of 1 indicates use of the IDCT specified in Annex W of ITU-T Recommendation H.263, and a value of zero indicates that any compliant IDCT can be used for off-host IDCT.

Must be zero if bConfigResidDiffAccelerator is zero (indicating purely host-based residual difference decoding).

Note Annex W of ITU-T Recommendation H.263 does not comply with the IDCT requirements of MPEG-2 corrigendum 2 and thus bConfigSpecificIDCT must not be one for use with MPEG-2 video.

bConfig4GroupedCoefs
A value of 1 indicates that transform coefficients for off-host IDCT will be sent using the DXVA_TCoef4Group structure rather than the DXVA_TCoefSingle structure. Is zero if bConfigResidDiffAccelerator is zero or if bConfigHostInverseScan is 1.

The preferred value for an accelerator to support is zero if bConfigResidDiffAccelerator is 1.

Headers

Declared in dxva.h. Include dxva.h.


DXVA_ConnectMode

The DXVA_ConnectMode structure establishes the defined restricted mode for operational use within a DirectX VA connection.

typedef struct _DXVA_ConnectMode {
  GUID  guidMode;
  WORD  wRestrictedMode;
} DXVA_ConnectMode, *LPDXVA_ConnectMode;

Members

guidMode
Specifies a GUID associated with the restricted mode profile to be used.
wRestrictedMode
Specifies the numeric identifier of the connection restricted mode.

Headers

Declared in dxva.h. Include dxva.h.

Comments

The restricted mode profiles are defined in Restricted Modes. The associated GUIDs and numeric identifiers are defined in dxva.h.


DXVA_EncryptProtocolHeader

The DXVA_EncryptProtocolHeader structure specifies the use of an encryption protocol.

typedef struct _DXVA_EncryptProtocolHeader {
  DWORD  dwFunction;
  DWORD  ReservedBits[3];
  GUID  guidEncryptProtocol;
} DXVA_EncryptProtocolHeader, *LPDXVA_EncryptProtocolHeader;

Members

dwFunction
The upper 24 bits of dwFunction indicate that an encryption protocol is being used. These bits must be 0xFFFF00 when sent by the host software decoder. These bits must be 0xFFFF08 when sent by the accelerator.

The lower eight bits of dwFunction indicate the function to which the encryption protocol applies. Currently, the only relevant defined value for these bits is 1, which indicates that the encryption protocol applies to compressed picture decoding.

There are only two possible values for dwFunction: 0xFFFF0001 when sent by a host software decoder, and 0xFFFF0801 when sent by the hardware accelerator.

ReservedBits
Reserved bits used for packing and/or alignment. This must be zero.
guidEncryptProtocol
Contains the GUID associated with the encryption protocol.

Headers

Declared in dxva.h. Include dxva.h.

Comments

The encryption protocol in use is externally defined and operates as described in Encryption Support.


DXVA_Highlight

The DXVA_Highlight structure specifies a highlighted rectangular area of a subpicture, and is used along with DCCMD data and a DPXD surface to create an alpha-blending surface.

typedef struct _DXVA_Highlight {
  WORD  wHighlightActive;
  WORD  wHighlightIndices;
  WORD  wHighlightAlphas;
  RECT  HighlightRect;
} DXVA_Highlight, *LPDXVA_Highlight;

Members

wHighlightActive
Indicates whether or not a rectangular highlight area is currently activated. Zero indicates inactive and 1 indicates active. If inactive, the highlight data must have no effect on the content of the blended picture.
wHighlightIndices
Contains the four-bit palette index of the highlighted rectangular area on the subpicture for each of the two-bit indices in the DPXD. The four MSBs are for index 3, the next four bits are for index 2, the next four bits are for index 1, and the four LSBs are for index 0.
wHighlightAlphas
Contains the four-bit opacity of the highlighted rectangular area on the subpicture for each of the two-bit indices used by the DPXD. The four MSBs are for index 3, the next four bits are for index 2, the next four bits are for index 1, and the four LSBs are for index 0.

The 4-bit opacity values are each referred to as a SampleAlpha4 parameter and are interpreted as follows:

  • The value zero indicates that the sample is transparent (so that the palette entry indexed by the corresponding bits of wHighlightIndices has no effect on the resulting blended picture). For a zero value of SampleAlpha4, the blend specified is to use the picture value without alteration.
  • The value 15 indicates that the sample is opaque (so that the palette entry indexed by the corresponding bits of wHighlightIndices completely determines the resulting blended picture).
  • For nonzero values of SampleAlpha4, the blend specified is to add (SampleAlpha4 plus 1) times the graphic value to (15 minus SampleAlpha4) times the picture value and to the constant 8, and right-shift the result by four places.
HighlightRect
Contains the definition of the area of the highlight rectangle as a RECT data type.

The following restrictions apply to the RECT dimensions:

  • left and top must be greater than or equal to zero.
  • right and bottom must be greater than left and top, respectively.
  • right must not exceed 720, and bottom must not exceed 576.

Note There is a difference between the way the DVD specification defines a subpicture rectangular area and the convention used by Microsoft. This section follows the Microsoft convention so that a rectangle of width 10 and height 10 in the upper left corner of the picture is defined by top = 0, left = 0, right = 10, bottom = 10. The DVD specification defines right = 9 and bottom = 9.

Headers

Declared in dxva.h. Include dxva.h.

Comments

The DXVA_Highlight structure is formulated in a manner compatible with the DVD video specification as specified by the DVD Forum.


DXVA_MBctrl_I_HostResidDiff_1

The DXVA_MBctrl_I_HostResidDiff_1 structure sends a macroblock control command when the bPicIntra member of DXVA_PictureParameters equals 1 (intra pictures), and the HostResidDiff bit within DXVA_MBctrl_I_HostResidDiff_1 or DXVA_MBctrl_I_OffHostIDCT_1 equals 1 (host-based IDCT).

typedef struct _DXVA_MBctrl_I_HostResidDiff_1 {
  WORD  wMBaddress;
  WORD  wMBtype;
  DWORD  dwMB_SNL;
  WORD  wPatternCode;
  WORD  wPC_Overflow;
  DWORD dwReservedBits2;
} DXVA_MBctrl_I_HostResidDiff_1;

Members

wMBaddress
Specifies the macroblock address of the current macroblock in raster scan order (zero being the address of the top-left macroblock, wPicWidthInMBminus1 being the address of the top-right macroblock, and wPicHeightInMBminus1 X (wPicWidthInMBminus1+1) being the address of the bottom-left macroblock, and (wPicHeightInMBminus1+1) X (wPicWidthInMBminus1+1)–1 being the address of the bottom-right macroblock). The wPicWidthInMBminus1 and wPicHeightInMBminus1 members are contained in the DXVA_PictureParameters structure.
wMBtype
Specifies the type of macroblock being processed. The following bits define macroblock processing:
Bit | Description
15 | MvertFieldSel[3] (The MSB). Must be zero.
14 | MvertFieldSel[2]. Must be zero.
13 | MvertFieldSel[1]. Must be zero.
12 | MvertFieldSel[0]. Must be zero.
11 | Reserved Bit. Must be zero.
10 HostResidDiff

Always equal to 1 in DXVA_MBctrl_I_HostResidDiff_1.

Specifies whether spatial-domain residual difference decoded blocks are sent or whether transform coefficients are sent for off-host IDCT for the current macroblock. Must be zero if bConfigResidDiffHost is zero. Must be 1 if bConfigResidDiffAccelerator is zero. The bConfigResidDiffHost and bConfigResidDiffAccelerator members are contained in the DXVA_ConfigPictureDecode structure.

If 1, when bPicIntra is 1, indicates that the macroblock control command uses a DXVA_MBctrl_I_HostResidDiff_1 structure. If zero, when bPicIntra is 1, indicates that the macroblock control command uses a DXVA_MBctrl_I_OffHostIDCT_1 structure. bPicIntra is a member of DXVA_PictureParameters.
9 and 8 MotionType

Must be zero.
7 and 6 MBscanMethod

This must equal bPicScanMethod if bPicScanFixed is 1. If bConfigHostInverseScan is zero, MBscanMethod is one of the following values:

  • • zero which is zig-zag scan (MPEG-2 Figure 7-2),
  • • 1 which is alternate-vertical (MPEG-2 Figure 7-3),
  • • 2 which is alternate-horizontal (H.263 Figure I.2 Part a)

If bConfigHostInverseScan is 1, MBscanMethod is equal to 3, which is arbitrary scan with absolute coefficient address.

The bPicScanMethod and bPicScanFixed are members of DXVA_PictureParameters. The bConfigHostInverseScan member is contained in the DXVA_ConfigPictureDecode structure.
5 FieldResidual

A variable indicating whether the residual difference blocks use a field IDCT structure as specified in MPEG-2.

Bit 5 in FieldResidual must be 1 if the bPicStructure member of DXVA_PictureParameters is 1 or 2. When used for MPEG-2, FieldResidual must be zero if the frame_pred_frame_DCT flag in the MPEG-2 syntax is 1, and must be equal to the dct_type element of the MPEG-2 syntax if dct_type is present for the macroblock.
4 | H261LoopFilter. Must be zero.
3 | Motion4MV. Must be zero.
2 | MotionBackward. Must be zero.
1 | MotionForward. Must be zero.
0 | IntraMacroblock. Must be one.

dwMB_SNL
Contains the two fields: MBskipsFollowing (in the upper eight bits) and MBdataLocation (in the lower 24 bits).

MBskipsFollowing

Must be zero.

MBdataLocation

MBdataLocation is an index into the residual difference block data buffer, indicating the location of the residual difference data for the blocks of the current macroblock, expressed as a multiple of 32 bits. Must be zero for the first macroblock in the macroblock control command buffer.

wPatternCode
Indicates whether a residual difference block is sent for a block. The bits of wPatternCode that refer to all blocks of the current macroblock must be 1 in DXVA_MBctrl_I_HostResidDiff_1.

Bit 11-i of wPatternCode (where bit zero is the LSB) indicates whether residual difference data is sent for block i, where i is the index of the block within the macroblock as specified in MPEG-2 figures 6-10, 6-11, and 6-12 (raster-scan order for Y, followed by 4:2:0 blocks of Cb in raster-scan order, followed by 4:2:0 blocks of Cr, followed by 4:2:2 blocks of Cb, followed by 4:2:2 blocks of Cr, followed by 4:4:4 blocks of Cb, followed by 4:4:4 blocks of Cr). The data for the coded blocks (those blocks having bit 11-i equal to 1) is found in the residual coding buffer in the same indexing order (increasing i). For 4:2:0 MPEG-2 data, the value of wPatternCode corresponds to shifting the decoded value of CBP left by six bit positions (those lower bit positions being for the use of 4:2:2 and 4:4:4 chroma formats).

If the bConfigSpatialResidInterleaved member of DXVA_ConfigPictureDecode is 1, host-based residual differences are sent in a chroma-interleaved form matching that of the YUV pixel format in use. In this case each Cb and spatially-corresponding Cr pair of blocks is treated as a single residual difference structure unit. This does not alter the value or meaning of wPatternCode, but it implies that both members of each pair of Cb and Cr data blocks are sent whenever either of these data blocks has the corresponding bit set in wPatternCode. If the bit in wPatternCode for a particular data block is zero, the corresponding residual difference data values must be sent as zero whenever this pairing necessitates sending a residual difference data block for a block with a wPatternCode bit equal to zero.

wPC_Overflow
Must be zero.
dwReservedBits2
Must be zero.

Headers

Declared in dxva.h. Include dxva.h.

Comments

The HostResidDiff bit within the DXVA_MBctrl_I_HostResidDiff_1 or DXVA_MBctrl_I_OffHostIDCT_1 macroblock control command structure indicates which of these two structures is used.


DXVA_MBctrl_I_OffHostIDCT_1

The DXVA_MBctrl_I_OffHostIDCT_1 structure sends a macroblock control command when the bPicIntra member of DXVA_PictureParameters equals one (intra pictures) and the bChromaFormat member equals 1 (4:2:0), and the HostResidDiff bit within DXVA_MBctrl_I_HostResidDiff_1 or DXVA_MBctrl_I_OffHostIDCT_1 equals zero (off-host IDCT).

typedef struct _DXVA_MBctrl_I_OffHostIDCT_1 {
  WORD  wMBaddress;
  WORD  wMBtype;
  DWORD  dwMB_SNL;
  WORD  wPatternCode;
  BYTE  bNumCoef[6];
} DXVA_MBctrl_I_OffHostIDCT_1;

Members

wMBaddress
Specifies the macroblock address of the current macroblock in raster scan order (0 being the address of the top-left macroblock, wPicWidthInMBminus1 being the address of the top-right macroblock, and wPicHeightInMBminus1 X (wPicWidthInMBminus1+1) being the address of the bottom-left macroblock, and (wPicHeightInMBminus1+1) X (wPicWidthInMBminus1+1)–1 being the address of the bottom-right macroblock). The wPicWidthInMBminus1 and wPicHeightInMBminus1members are contained in the DXVA_PictureParameters structure.
wMBtype
Specifies the type of macroblock being processed. The following bits define macroblock processing:
Bit | Description
15 | MvertFieldSel[3] (the MSB). Must be zero.
14 | MvertFieldSel[2] Must be zero.
13 | MvertFieldSel[1] Must be zero.
12 | MvertFieldSel[0] Must be zero.
11 | Reserved Bit. Must be zero.
10 HostResidDiff

Always equal to zero in DXVA_MBctrl_I_OffHostIDCT_1.

Specifies whether spatial-domain residual difference decoded blocks are sent or whether transform coefficients are sent for off-host IDCT for the current macroblock. Must be zero if bConfigResidDiffHost is zero. Must be 1 if bConfigResidDiffAccelerator is zero. The bConfigResidDiffHost and bConfigResidDiffAccelerator members are contained in the DXVA_ConfigPictureDecode structure.

If 1 when bPicIntra is 1, indicates that the macroblock control command uses a DXVA_MBctrl_I_HostResidDiff_1 structure. If zero when bPicIntra is 1, indicates that the macroblock control command uses a DXVA_MBctrl_I_OffHostIDCT_1 structure. bPicIntra is a member of DXVA_PictureParameters.
9 and 8 | MotionType. Both bits must be zero.
7 and 6 MBscanMethod

MBscanMethod is equal to bPicScanMethod if bPicScanFixed is 1.

If bConfigHostInverseScan is zero, MBscanMethod must be one of the following values:

  • bit 6 is zero and bit 7 is zero for zig-zag scan (MPEG-2 Figure 7-2)
  • bit 6 is 1 and bit 7 is zero for alternate-vertical (MPEG-2 Figure 7-3)
  • bit 6 is zero and bit 7 is 1 for alternate-horizontal (H.263 Figure I.2 Part a)
  • If bConfigHostInverseScan is 1, MBscanMethod must be equal to the following value:
  • bit 6 is 1 and bit 7 is 1 for arbitrary scan with absolute coefficient address.

bPicScanMethod and bPicScanFixed are members of DXVA_PictureParameters. bConfigHostInverseScan is a member of DXVA_ConfigPictureDecode.
5 FieldResidual

A variable indicating whether the residual difference blocks use a field IDCT structure as specified in MPEG-2.

Bit 5 in FieldResidual must be 1 if the bPicStructure member of DXVA_PictureParameters is 1 or 2. When used for MPEG-2, FieldResidual must be zero if the frame_pred_frame_DCT flag in the MPEG-2 syntax is 1, and must be equal to the dct_type element of the MPEG-2 syntax if dct_type is present for the macroblock.
4 | H261LoopFilter. Must be zero.
3 | Motion4MV. Must be zero.
2 | MotionBackward. Must be zero.
1 | MotionForward. Must be zero.
0 | IntraMacroblock. Must be one.

dwMB_SNL
Contains the two fields: MBskipsFollowing (in the upper 8 bits) and MBdataLocation (in the lower 24 bits).

MBskipsFollowing

Must be zero.

MBdataLocation

MBdataLocation is an index into the residual difference block data buffer, indicating the location of the residual difference data for the blocks of the current macroblock, expressed as a multiple of 32 bits. Must be zero for the first macroblock in the macroblock control command buffer.

wPatternCode
Indicates whether a residual difference block is sent for a block. The bits of wPatternCode that refer to all blocks of the current macroblock must be 1 in DXVA_MBctrl_I_OffHostIDCT_1.

Bit 11-i of wPatternCode (where bit 0 is the LSB) indicates whether residual difference data is sent for block i, where i is the index of the block within the macroblock as specified in MPEG-2 figures 6-10, 6-11, and 6-12 (raster-scan order for Y, followed by 4:2:0 blocks of Cb in raster-scan order, followed by 4:2:0 blocks of Cr, followed by 4:2:2 blocks of Cb, followed by 4:2:2 blocks of Cr, followed by 4:4:4 blocks of Cb, followed by 4:4:4 blocks of Cr). The data for the coded blocks (those blocks having bit 11-i equal to 1) is found in the residual coding buffer in the same indexing order (increasing i). For 4:2:0 MPEG-2 data, the value of wPatternCode corresponds to shifting the decoded value of CBP left by six bit positions (those lower-bit positions being for the use of 4:2:2 and 4:4:4 chroma formats).

If the bConfigSpatialResidInterleaved member of DXVA_ConfigPictureDecode is 1, host-based residual differences are sent in a chroma-interleaved form matching that of the YUV pixel format in use. In this case each Cb and spatially-corresponding Cr pair of blocks is treated as a single residual difference structure unit. This does not alter the value or meaning of wPatternCode, but it implies that both members of each pair of Cb and Cr data blocks are sent whenever either of these data blocks has the corresponding bit set in wPatternCode. If the bit in wPatternCode for a particular data block is zero, the corresponding residual difference data values must be sent as zero whenever this pairing necessitates sending a residual difference data block for a block with a wPatternCode bit equal to zero.

bNumCoef
The value of bNumCoef[i] indicates the number of coefficients in the residual difference data buffer for each block i of the macroblock, where i is the index of the block within the macroblock as specified in MPEG-2 Figures 6-10, 6-11, and 6-12 (raster-scan order for Y, followed by Cb, followed by Cr). Used only when HostResidDiff is zero and bChromaFormat is 1 (4:2:0). (If used in 4:2:2 or 4:4:4 formats, it would increase the size of typical macroblock control commands past a critical memory alignment boundary, so only an EOB within the transform coefficient structure is used for determining the number of coefficients in each block in non-4:2:0 cases.) The purpose of bNumCoef[i] is to indicate the quantity of data present for each block in the residual difference data buffer, expressed as the number of coefficients present. When the bConfig4GroupedCoefs member of DXVA_ConfigPictureDecode is 1, bNumCoef[i] may contain either the actual number of coefficients sent for the block or that value rounded up to be a multiple of 4. The data for these coefficients is found in the residual difference buffer in the same order.

Headers

Declared in dxva.h. Include dxva.h.

Comments

The HostResidDiff bit within the DXVA_MBctrl_I_HostResidDiff_1 or DXVA_MBctrl_I_OffHostIDCT_1 macroblock control command structure indicates which of these two structures is used.


DXVA_MBctrl_P_HostResidDiff_1

The DXVA_MBctrl_P_HostResidDiff_1 structure is used for sending macroblock control commands when bPicIntra is not equal to 1 (that is, for P and B pictures – and also used for concealment motion vectors in I pictures) and the HostResidDiff bit within the DXVA_MBctrl_P_HostResidDiff_1 or DXVA_MBctrl_P_OffHostIDCT_1 is 1 (host-based IDCT) and bPicOBMC and bMV_RPS are zero and at least 1 of bPicBinPB and bPic4MVallowed is zero. The bPicIntra, bPicOBMC, bMV_RPS, bPicBinPB, and bPic4MVallowed members are contained in the DXVA_PictureParameters structure.

typedef struct _DXVA_MBctrl_P_HostResidDiff_1 {
  WORD         wMBaddress;
  WORD         wMBtype;
  DWORD        dwMB_SNL;
  WORD         wPatternCode;
  WORD         wPC_Overflow;
  DWORD        dwReservedBits2;
  DXVA_MVvalue MVector[4];
} DXVA_MBctrl_P_HostResidDiff_1;

Members

wMBaddress
Specifies the macroblock address of the current macroblock in raster scan order (zero being the address of the top-left macroblock, wPicWidthInMBminus1 being the address of the top-right macroblock, and wPicHeightInMBminus1 X (wPicWidthInMBminus1+1) being the address of the bottom-left macroblock, and (wPicHeightInMBminus1+1) X (wPicWidthInMBminus1+1)–1 being the address of the bottom-right macroblock). The wPicWidthInMBminus1 and wPicHeightInMBminus1 members are contained in DXVA_PictureParameters.
wMBtype
Specifies the type of macroblock being processed. The following bits define macroblock processing:
Bit | Description
15 | MvertFieldSel[3] (the MSB)
14 | MvertFieldSel[2]
13 | MvertFieldSel[1]
12 MvertFieldSel[0]

Specifies vertical field selection for corresponding motion vectors sent later in the macroblock control command, as specified in further detail below. For frame-based motion with a frame picture structure (for example, for H.261 and H.263), these bits must all be zero. The use of these bits is the same as that specified for the corresponding bits in Section 6.3.17.2 of MPEG-2.
11 | Reserved Bit. Must be zero.
10 HostResidDiff

Always equal to 1 in DXVA_MBctrl_P_HostResidDiff_1.

Specifies whether spatial-domain residual difference decoded blocks are sent or whether transform coefficients are sent for off-host IDCT for the current macroblock. Must be zero if bConfigResidDiffHost is zero. Must be 1 if bConfigResidDiffAccelerator is zero.

If 1 when bPicIntra is zero, indicates that the macroblock control command uses a DXVA_MBctrl_P_HostResidDiff_1 structure. If zero when bPicIntra is zero, indicates that the macroblock control command uses a DXVA_MBctrl_P_OffHostIDCT_1 structure. The bPicIntra member is contained in the DXVA_PictureParameters structure.
9 and 8 MotionType

Specifies the motion type in the picture. For example, for frame-based motion with a frame picture structure (as in H.261), bit 9 must be 1 and bit 8 must be zero.

The use of these bits corresponds directly to the use of frame_motion_type or field_motion_type bits in Section 6.3.17.1 and Tables 6-17 and 6-18 of MPEG-2 when these bits are present in MPEG-2. The use of these bits are further explained in the following Comments section.
7 and 6 MBscanMethod

MBscanMethod is equal to bPicScanMethod if bPicScanFixed is 1.

If bConfigHostInverseScan is zero, MBscanMethod must be one of the following values:

  • bit 6 is zero and bit 7 is zero for zig-zag scan (MPEG-2 Figure 7-2)
  • bit 6 is 1 and bit 7 is zero for alternate-vertical (MPEG-2 Figure 7-3)
  • bit 6 is zero and bit 7 is 1 for alternate-horizontal (H.263 Figure I.2 Part a)
  • If bConfigHostInverseScan is 1, MBscanMethod must be equal to the following value:
  • bit 6 is 1 and bit 7 is 1 for arbitrary scan with absolute coefficient address.

bPicScanMethod and bPicScanFixed are members of DXVA_PictureParameters. bConfigHostInverseScan is a member of DXVA_ConfigPictureDecode.
5 FieldResidual

A variable indicating whether the residual difference blocks use a field IDCT structure as specified in MPEG-2.

Bit 5 in FieldResidual must be 1 if the bPicStructure member of DXVA_PictureParameters is 1 or 2. When used for MPEG-2, FieldResidual must be zero if the frame_pred_frame_DCT flag in the MPEG-2 syntax is 1, and must be equal to the dct_type element of the MPEG-2 syntax if dct_type is present for the macroblock.
4 H261LoopFilter

A variable specifying whether the H.261 loop filter (Section 3.2.3 of H.261) is active for the current macroblock prediction. The H.261 loop filter is a separable ¼, ½, ¼ filter applied both horizontally and vertically to all six blocks in an H.261 macroblock except at block edges where one of the taps would fall outside the block. In such cases the filter is changed to have coefficients 0, 1, 0. Full arithmetic precision is retained with rounding to 8-bit integers at the output of the 2D filter process (half-integer or higher values being rounded up).
3 Motion4MV

A variable indicating that forward motion uses a distinct motion vector for each of the four luminance blocks in the macroblock, as used in H.263 Annexes F and J. Motion4MV must be zero if MotionForward is zero or if the bPic4MVallowed member of DXVA_PictureParameters is zero.
2 MotionBackward

A variable used as specified for the corresponding macroblock_motion_backward parameter in MPEG-2. If the bPicBackwardPrediction member of DXVA_PictureParameters is zero, MotionBackward must be zero. The use of this bit is further explained in the following Comments section.
1 MotionForward

A variable used for the corresponding macroblock_motion_forward in MPEG-2. The use of this bit is further explained in the following Comments section.
0 IntraMacroblock

A variable indicating that the macroblock is coded as "intra", and no motion vectors are used for the current macroblock. Corresponds to macroblock_intra in MPEG-2. The use of this bit is further explained in the following Comments section.

dwMB_SNL
Contains the two fields MBskipsFollowing (in the upper 8 bits) and MBdataLocation (in the lower 24 bits).
MBskipsFollowing
Specifies the number of "skipped macroblocks" to be generated following the current macroblock. Each skipped macroblock must be generated in a manner mathematically equivalent to incrementing the value of wMBaddress and then repeating the same macroblock control command.

Any macroblock control command with a nonzero value for MBskipsFollowing contains the explicit specification of how motion-compensated prediction is to be performed for each macroblock to be skipped, and is equivalent (except for the value of MBskipsFollowing) to an explicit "non-skip" specification of the generation of the first of the series of skipped macroblocks. Thus, whenever MBskipsFollowing is not zero, the following parameters must all be equal to zero:

  • Motion4MV
  • IntraMacroblock
  • wPatternCode
  • wPCOverflow

    Furthermore, the generation of following skipped macroblocks must be restricted by the decoder to not include a "wrap" to a new row of macroblocks in the picture. In other words, a separate macroblock control command must be sent to generate the first (but not necessarily the last) macroblock of each row of macroblocks.

    The generation of a skipped macroblock in this context differs somewhat from that in MPEG-2 Section 7.6.6. In this specification, the manner in which the skipped macroblocks are generated is specified in a separate macroblock control command, rather than being inferred from the type of the preceding non-skipped macroblock and the type of picture (for example, in MPEG-2 the method of generating skipped macroblocks depends on whether the picture is a P picture or B picture).

    The following example illustrates this point. Suppose that in an MPEG-2 bitstream, macroblock 0 is coded with a residual difference, macroblock 1 is skipped, macroblock 2 is coded with a residual difference, macroblocks 3, 4, and 5 are skipped, and then macroblock 6 is coded with a residual difference.

    These seven macroblocks would require the generation of (at least) five DirectX VA macroblock control commands. The minimal five control commands would be characterized by the following:

  • The first command has wMBaddress equal to zero and MBskipsFollowing equal to zero.
  • The second command has wMBaddress equal to 1 and MBskipsFollowing equal to zero.
  • The third command has wMBaddress equal to 2 and MBskipsFollowing equal to zero.
  • The fourth command has wMBaddress equal to 3 and MBskipsFollowing equal to 2.
  • The fifth command has wMBaddress equal to 6 and MBskipsFollowing equal to zero.

    The following conditions are required:

  • Skipped macroblocks have no residual differences.
  • Skipped macroblocks can be generated by repeating the operation of a macroblock control command with an incremented wMBaddress.
  • Macroblock skipping is restricted to not wrap to a new row of macroblocks.

    Because of the three conditions listed above, an accelerator may actually implement motion compensation (when Motion4MV is zero) as the application of the specified motion vectors to a rectangle of width equal to (bMacroblockWidthMinus1+1) X (MBskipsFollowing+1) in the luminance component (and to a similarly-specified rectangle in the chrominance components), rather than as MBskipsFollowing+1 repetitions of the same macroblock control operation. The bMacroblockWidthMinus1 member is contained in the DXVA_PictureParametersstructure.

    The generation of macroblocks indicated as skipped in H.263 with advanced prediction mode (Annex F) active requires coding some "skipped" macroblocks as non-skipped macroblocks using this specification – in order to specify the OBMC effect within these macroblocks.

MBdataLocation
MBdataLocation is an index into the IDCT residual coding block data buffer, indicating the location of the residual difference data for the blocks of the current macroblock, expressed as a multiple of 32 bits. Must be zero for the first macroblock in the macroblock control command buffer. MBdataLocation may contain any value if wPatternCode is zero. When wPatternCode is zero, decoders are recommended but not required to set this value either to zero or to the same value as in the next macroblock control command.
wPatternCode
Indicates whether a residual difference block is sent for a block.

Bit 11-i of wPatternCode (where bit zero is the LSB) indicates whether residual difference data is sent for block i, where i is the index of the block within the macroblock as specified in MPEG-2 figures 6-10, 6-11, and 6-12 (raster-scan order for Y, followed by 4:2:0 blocks of Cb in raster-scan order, followed by 4:2:0 blocks of Cr, followed by 4:2:2 blocks of Cb, followed by 4:2:2 blocks of Cr, followed by 4:4:4 blocks of Cb, followed by 4:4:4 blocks of Cr). The data for the coded blocks (those blocks having bit 11-i equal to 1) is found in the residual coding buffer in the same indexing order (increasing i). For 4:2:0 MPEG-2 data, the value of wPatternCode corresponds to shifting the decoded value of CBP left by six bit positions (those lower bit positions being for the use of 4:2:2 and 4:4:4 chroma formats).

If the bConfigSpatialResidInterleaved member of the DXVA_ConfigPictureDecode structure is 1, host-based residual differences are sent in a chroma-interleaved form matching that of the YUV pixel format in use. In this case each Cb and spatially-corresponding Cr pair of blocks is treated as a single residual difference structure unit. This does not alter the value or meaning of wPatternCode, but it implies that both members of each pair of Cb and Cr data blocks are sent whenever either of these data blocks has the corresponding bit set in wPatternCode. If the bit in wPatternCode for a particular data block is zero, the corresponding residual difference data values must be sent as zero whenever this pairing necessitates sending a residual difference data block for a block with a wPatternCode bit equal to zero.

wPC_Overflow
Specifies which blocks of the macroblock use overflow residual difference data

When using host-based residual difference decoding with the bPicOverflowBlocks member of DXVA_PictureParameters equal to 1 and IntraMacroblock equal to zero (the 8-8 overflow method), wPC_Overflow contains the pattern code of the overflow blocks as specified in the same manner as for wPatternCode. The data for the coded overflow blocks (those blocks having bit 11-i equal to one) is found in the residual coding buffer in the same indexing order (increasing i).

dwReservedBits2
Reserved bits used for packing and/or alignment. Must be zero.
MVector[4]
An array containing the value of the motion vector(s) for the macroblock, each represented using a DXVA_MVvalue structure.

Headers

Declared in dxva.h. Include dxva.h.

Comments

The HostResidDiff bit within the DXVA_MBctrl_P_HostResidDiff_1 or DXVA_MBctrl_P_OffHostIDCT_1 macroblock control command structure indicates which of these two structures is used.

Valid combinations of IntraMacroblock, MotionForward, MotionBackward, MotionType, MvertFieldSel, and MVector[i] are shown in the following tables. The values specified in the tables are for when H261LoopFilter, Motion4MV and the bPicOBMC member of DXVA_PictureParameters are zero. The PicCurrentField parameter is derived from the bPicStructure member of DXVA_PictureParameters.

The first table indicates values for frame-structured pictures (the bPicStructure member of DXVA_PictureParameters is equal to 3). The second table indicates values for field-structured pictures (bPicStructure is equal to 1 or 2). The values shown for MotionType in single quotes are binary representations (the first number is for bit 9 and the second is for bit 8).

IntraMacroblock, MotionForward, MotionBackward | MotionType (meaning depends on picture type) | MVector[0] MvertFieldSel[0] (1st, dir1) | MVector[1] MvertFieldSel[1] (1st, dir2) | MVector[2] MvertFieldSel[2] (2nd, dir1) | MVector[3] MvertFieldSel[3] (2nd, dir2)
1,0,0 (intra) | '00' (intra) | - - | - - | - - | - -
0,0,0 (no motion) | '10' (no motion) | 0 - | - - | - - | - -
0,1,0 | '10' (frame MC) | PMV[0][0] - | - - | - - | - -
0,0,1 | '10' (frame MC) | - - | PMV[0][1] - | - - | - -
0,1,1 | '10' (frame MC) | PMV[0][0] - | PMV[0][1] - | - - | - -
0,1,0 | '01' (field MC) | PMV[0][0] sel[0][0] | - - | PMV[1][0] sel[1][0] | - -
0,0,1 | '01' (field MC) | - - | PMV[0][1] sel[0][1] | - - | PMV[1][1] sel[1][1]
0,1,1 | '01' (field MC) | PMV[0][0] sel[0][0] | PMV[0][1] sel[0][1] | PMV[1][0] sel[1][0] | PMV[1][1] sel[1][1]
0,1,0 | '11' (dual-prime) | PMV[0][0] 0 (top) | vector'[2][0][0], vector'[2][0][1]<<1 1 (bot) | PMV[0][0] 1 | vector'[3][0][0], vector'[3][0][1]<<1 0

IntraMacroblock, MotionForward, MotionBackward | MotionType (meaning depends on picture type) | MVector[0] MvertFieldSel[0] (1st, dir1) | MVector[1] MvertFieldSel[1] (1st, dir2) | MVector[2] MvertFieldSel[2] (2nd, dir1) | MVector[3] MvertFieldSel[3] (2nd, dir2)
1,0,0 (intra) | '00' (intra) | - - | - - | - - | - -
0,0,0 (no motion) | '01' (no motion) | 0 PicCurrentField | - - | - - | - -
0,1,0 | '01' (field MC) | PMV[0][0] sel[0][0] | - - | - - | - -
0,0,1 | '01' (field MC) | - - | PMV[0][1] sel[0][1] | - - | - -
0,1,1 | '01' (field MC) | PMV[0][0] sel[0][0] | PMV[0][1] sel[0][1] | - - | - -
0,1,0 | '10' (16x8 MC) | PMV[0][0] sel[0][0] | - - | PMV[1][0] sel[1][0] | - -
0,0,1 | '10' (16x8 MC) | - - | PMV[0][1] sel[0][1] | - - | PMV[1][1] sel[1][1]
0,1,1 | '10' (16x8 MC) | PMV[0][0] sel[0][0] | PMV[0][1] sel[0][1] | PMV[1][0] sel[1][0] | PMV[1][1] sel[1][1]
0,1,0 | '11' (dual-prime) | PMV[0][0] PicCurrentField | vector'[2][0] !PicCurrentField | - - | - -

  14. 1. Experience has shown that there will be bugs in any implementation that fails to properly account for every utilized macroblock type in the table (especially for field-structured pictures or dual-prime motion).
  15. In a number of places in the preceding tables, the variable PMV is used rather than the raw motion vector value. This is to distinguish between PMV, which is in frame coordinates, from a motion vector that may be in field coordinates (i.e., at half-vertical resolution). In all such cases in the preceding tables, PMV refers to the value of PMV after updating by the current motion vector.
  16. The definitions of vector'[2][0] and vector'[3][0] are found in MPEG-2 section 7.6.3.6. The shift operation shown indicates that the vertical component is modified to frame coordinates.
  17. In both "no motion" cases (0,0,0) in the preceding tables, the macroblock parameters emulate a forward prediction macroblock (0,1,0) with a zero-valued motion vector. (See also MPEG-2 Section 7.6.3.5.)

The remaining allowed cases (where bPicOBMC is a member of DXVA_PictureParameters) are as follows:

  • H261LoopFilter equal to 1, bPicOBMC equal to zero and Motion4MV equal to zero: This indicates that one forward motion vector is sent in MVector[0] and the H.261 loop filter as specified in Section 3.2.3 of H.261 is active for the forward prediction in the macroblock. MotionForward must be 1 in this case and IntraMacroblock and MotionBackward must both be zero.
  • bPicOBMC equal to zero and Motion4MV equal to 1: This indicates that four forward motion vectors are sent in MVector[0, 1, 2, 3]. MotionForward must be 1 in this case and IntraMacroblock must be zero. If MotionBackward is 1, a fifth motion vector is sent for backward prediction in MVector[4].
  • bPicOBMC equal to 1 and Motion4MV equal to zero: This indicates that ten forward motion vectors are sent in MVector[0, 1, 2, …, 9] for specification of OBMC motion, and that the values of the first four such motion vectors are all equal. If MotionBackward is 1, an eleventh motion vector is sent for backward prediction in MVvector[10].
  • bPicOBMC equal to 1 and Motion4MV equal to 1: This indicates that ten forward motion vectors are sent in MVvector[0, 1, 2, …, 9] for specification of OBMC motion, and that the values of the first four such motion vectors may differ from each other. If MotionBackward is 1, an eleventh motion vector is sent for backward prediction in MVector[10].

Note Some details about the interactions between H.263's OBMC, 4MV, B, EP, and B in PB may be helpful:

  • No current configuration of the H.263 standard would exercise the case in which bPicOBMC is equal to 1, Motion4MV is equal to 1, and MotionBackward is equal to 1.
  • OBMC cannot be used in a H.263 B or EP picture (H.263 Section 5.1.4.5 item 2).
  • OBMC cannot be used in the B part of a H.263 PB picture (H.263 Section F.1 paragraph 1).
  • 4MV cannot be transmitted in a H.263 B or EP picture (Only one MVFW and MVBW in syntax diagrams, and no 4MV macroblock types in H.263 Tables O.1 and O.2).
  • If 4MV is used in the macroblock of a H.263 P picture which is used as the future reference macroblock for "direct" prediction in a H.263 B picture, the OBMC is not used in the direct prediction. This is because four motion vectors are used according to H.263 Annex M, which uses them like H.263 Annex G which does not apply the OBMC (H.263 Section O.4 paragraph 2 and item 2 above it). Thus, H.263 would never require both OBMC and backward prediction at the same time, and never uses 4MV in a backward direction.

Note The average operator is mathematically identical ((s1+s2+1)>>1) for MPEG-1, MPEG-2 half-sample prediction filtering, bidirectional averaging, and dual prime same-opposite parity combining. The H.263 bidirectional averaging operator does not add the offset of +1 prior to right-shifting. The bBidirectionalAveragingMode member of DXVA_PictureParameters determines which of these methods is used.


DXVA_MBctrl_P_OffHostIDCT_1

The DXVA_MBctrl_P_OffHostIDCT_1 structure is used for sending macroblock control commands when the bPicIntra member of DXVA_PictureParameters is not one (that is, for P and B pictures – and also used for concealment motion vectors in I pictures) and the HostResidDiff bit within DXVA_MBctrl_P_HostResidDiff_1 or DXVA_MBctrl_P_OffHostIDCT_1 is zero (off-host IDCT) and bPicOBMC and bMV_RPS are zero and at least one of bPicBinPB and bPic4MVallowed is zero and bChromaFormat is a value of one (4:2:0). The bPicIntra, bPicOBMC, bMV_RPS, bPicBinPB, bPic4MVallowed, and bChromaFormat members are contained in the DXVA_PictureParameters structure.

typedef struct _DXVA_MBctrl_P_OffHostIDCT_1 {
  WORD         wMBaddress;
  WORD         wMBtype;
  DWORD        dwMB_SNL;
  WORD         wPatternCode;
  BYTE         bNumCoef[6];
  DXVA_MVvalue MVector[4];
} DXVA_MBctrl_P_OffHostIDCT_1;

Members

wMBaddress
Specifies the macroblock address of the current macroblock in raster scan order (0 being the address of the top-left macroblock, wPicWidthInMBminus1 being the address of the top-right macroblock, and wPicHeightInMBminus1 X (wPicWidthInMBminus1+1) being the address of the bottom-left macroblock, and (wPicHeightInMBminus1+1) X (wPicWidthInMBminus1+1)–1 being the address of the bottom-right macroblock). The wPicWidthInMBminus1 and wPicHeightInMBminus1 members are contained in the DXVA_PictureParameters structure.
wMBtype
Specifies the type of macroblock being processed. The following bits define macroblock processing:
Bit | Description
15 | MvertFieldSel[3] (the MSB).
14 | MvertFieldSel[2]
13 | MvertFieldSel[1]
12 MvertFieldSel[0]

Specifies vertical field selection for corresponding motion vectors sent later in the macroblock control command, as specified in further detail below. For frame-based motion with a frame picture structure (for example, for H.261 and H.263), these bits must all be zero. The use of these bits is the same as that specified for the corresponding bits in section 6.3.17.2 of MPEG-2.
11 | Reserved Bit. Must be zero.
10 HostResidDiff

Always equal to zero in DXVA_MBctrl_P_OffHostIDCT_1.

Specifies whether spatial-domain residual difference decoded blocks are sent or whether transform coefficients are sent for off-host IDCT for the current macroblock. Must be zero if bConfigResidDiffHost is zero. Must be 1 if bConfigResidDiffAccelerator is zero.

If 1, when bPicIntra is zero, indicates that the macroblock control command uses a DXVA_MBctrl_P_HostResidDiff_1 structure. If zero, when bPicIntra is zero, indicates that the macroblock control command uses a DXVA_MBctrl_P_OffHostIDCT_1 structure. The bPicIntra parameter is a member of the DXVA_PictureParameters structure.
9 and 8 MotionType

Specifies the motion type in the picture. For example, for frame-based motion with a frame picture structure (as in H.261), bit 9 must be 1 and bit 8 must be zero.

The use of these bits corresponds directly to the use of frame_motion_type or field_motion_type bits in section 6.3.17.1 and tables 6-17 and 6-18 of MPEG-2 when these bits are present in MPEG-2. The use of these bits are further explained in the following Comments section.
7 and 6
  • MBscanMethod

    This is equal to bPicScanMethod if bPicScanFixed is one.

    If bConfigHostInverseScan is zero, MBscanMethod must be one of the following values:

    • bit 6 is zero and bit 7 is zero for zig-zag scan (MPEG-2 Figure 7-2)
    • bit 6 is 1 and bit 7 is zero for alternate-vertical (MPEG-2 Figure 7-3)
    • bit 6 is zero and bit 7 is 1 for alternate-horizontal (H.263 Figure I.2 Part a)
    • If bConfigHostInverseScan is 1, MBscanMethod must be equal to the following value:
    • bit 6 is 1 and bit 7 is 1 for arbitrary scan with absolute coefficient address.

    bPicScanMethod and bPicScanFixed are members of DXVA_PictureParameters. bConfigHostInverseScan is a member of the DXVA_ConfigPictureDecode.

5 FieldResidual

A variable indicating whether the residual difference blocks use a field IDCT structure as specified in MPEG-2.

Bit 5 in FieldResidual must be 1 if the bPicStructure member of DXVA_PictureParameters is 1 or 2.

When used for MPEG-2, FieldResidual must be zero if the frame_pred_frame_DCT flag in the MPEG-2 syntax is 1, and must be equal to the dct_type element of the MPEG-2 syntax if dct_type is present for the macroblock.
4 H261LoopFilter

A variable specifying whether the H.261 loop filter (Section 3.2.3 of H.261) is active for the current macroblock prediction. The H.261 loop filter is a separable ¼, ½, ¼ filter applied both horizontally and vertically to all six blocks in an H.261 macroblock except at block edges where one of the taps would fall outside the block. In such cases the filter is changed to have coefficients 0, 1, 0. Full arithmetic precision is retained with rounding to 8-bit integers at the output of the 2D filter process (half-integer or higher values being rounded up).
3 Motion4MV

A variable indicating that forward motion uses a distinct motion vector for each of the four luminance blocks in the macroblock, as used in H.263 Annexes F and J. Motion4MV must be zero if MotionForward is zero or if the bPic4MVallowed member of DXVA_PictureParameters is zero.
2 MotionBackward

A variable used as specified for the corresponding macroblock_motion_backward parameter in MPEG-2. If the bPicBackwardPrediction member of DXVA_PictureParameters is zero, MotionBackward must be zero. The use of this bit is further explained in the following Comments section.
1 MotionForward

A variable used as specified for the corresponding macroblock_motion_forward in MPEG-2. The use of this bit is further explained in the following Comments section.
0 IntraMacroblock

A variable indicating that the macroblock is coded as "intra", and no motion vectors are used for the current macroblock. Corresponds to macroblock_intra in MPEG-2. The use of this bit is further explained in the following Comments section.

dwMB_SNL
Contains the two fields MBskipsFollowing (the upper eight bits) and MBdataLocation (the lower 24 bits).
MBskipsFollowing
MBskipsFollowing specifies the number of "skipped macroblocks" to be generated following the current macroblock. Each skipped macroblock must be generated in a manner mathematically equivalent to incrementing the value of wMBaddress and then repeating the same macroblock control command.

Any macroblock control command with a nonzero value for MBskipsFollowing contains the explicit specification of how motion-compensated prediction is to be performed for each macroblock to be skipped, and is equivalent (except for the value of MBskipsFollowing) to an explicit "non-skip" specification of the generation of the first of the series of skipped macroblocks. Thus, whenever MBskipsFollowing is not zero, the following values must all be equal to zero:

  • Motion4MV
  • IntraMacroblock
  • bNumCoef[i]

    Furthermore, the generation of following skipped macroblocks must be restricted by the decoder to not include a "wrap" to a new row of macroblocks in the picture. In other words, a separate macroblock control command must be sent to generate the first (but not necessarily the last) macroblock of each row of macroblocks.

    The generation of a skipped macroblock in this context differs somewhat from that in MPEG-2 Section 7.6.6. In this reference, the manner in which the skipped macroblocks are generated is specified in a separate macroblock control command, rather than being inferred from the type of the preceding non-skipped macroblock and the type of picture (for example, in MPEG-2 the method of generating skipped macroblocks depends on whether the picture is a P picture or B picture).

    The following example illustrates this point. Suppose that in an MPEG-2 bitstream, macroblock 0 is coded with a residual difference, macroblock 1 is skipped, macroblock 2 is coded with a residual difference, macroblocks 3, 4, and 5 are skipped, and then macroblock 6 is coded with a residual difference.

    These seven macroblocks would require the generation of (at least) five DirectX VA macroblock control commands. The minimal five control commands would be characterized by the following:

  • The first command has wMBaddress equal to zero and MBskipsFollowing equal to zero.
  • The second command has wMBaddress equal to 1 and MBskipsFollowing equal to zero.
  • The third command has wMBaddress equal to 2 and MBskipsFollowing equal to zero.
  • The fourth command has wMBaddress equal to 3 and MBskipsFollowing equal to 2.
  • The fifth command has wMBaddress equal to 6 and MBskipsFollowing equal to zero.

    The following conditions are required:

  • Skipped macroblocks have no residual differences.
  • Skipped macroblocks can be generated by repeating the operation of a macroblock control command with an incremented wMBaddress.
  • Macroblock skipping is restricted to not wrap to a new row of macroblocks.

    Because of the three conditions listed above, an accelerator may actually implement motion compensation (when Motion4MV is zero) as the application of the specified motion vectors to a rectangle of width equal to (bMacroblockWidthMinus1+1) X (MBskipsFollowing+1) in the luminance component (and to a similarly-specified rectangle in the chrominance components), rather than as MBskipsFollowing+1 repetitions of the same macroblock control operation. The bMacroblockWidthMinus1 member is contained in the DXVA_PictureParameters structure.

    The generation of macroblocks indicated as skipped in H.263 with Advanced Prediction mode (Annex F) active requires coding some "skipped" macroblocks as non-skipped macroblocks using this specification – in order to specify the OBMC effect within these macroblocks.

MBdataLocation
MBdataLocation is an index into the IDCT residual coding block data buffer, indicating the location of the residual difference data for the blocks of the current macroblock, expressed as a multiple of 32 bits. Must be zero for the first macroblock in the macroblock control command buffer. MBdataLocation may contain any value if wPatternCode is zero. When wPatternCode is zero, decoders are recommended but not required to set this value either to zero or to the same value as in the next macroblock control command.
wPatternCode
Indicates whether a residual difference block is sent for a block.

Bit 11-i of wPatternCode (where bit 0 is the LSB) indicates whether residual difference data is sent for block i, where i is the index of the block within the macroblock as specified in MPEG-2 figures 6-10, 6-11, and 6-12 (raster-scan order for Y, followed by 4:2:0 blocks of Cb in raster-scan order, followed by 4:2:0 blocks of Cr, followed by 4:2:2 blocks of Cb, followed by 4:2:2 blocks of Cr, followed by 4:4:4 blocks of Cb, followed by 4:4:4 blocks of Cr). The data for the coded blocks (those blocks having bit 11-i equal to 1) is found in the residual coding buffer in the same indexing order (increasing i). For 4:2:0 MPEG-2 data, the value of wPatternCode corresponds to shifting the decoded value of CBP left by six bit positions (those lower bit positions being for the use of 4:2:2 and 4:4:4 chroma formats).

If the bConfigSpatialResidInterleaved member of DXVA_ConfigPictureDecode is 1, host-based residual differences are sent in a chroma-interleaved form matching that of the YUV pixel format in use. In this case each Cb and spatially-corresponding Cr pair of blocks is treated as a single residual difference data structure unit. This does not alter the value or meaning of wPatternCode, but it implies that both members of each pair of Cb and Cr data blocks are sent whenever either of these data blocks has the corresponding bit set in wPatternCode. If the bit in wPatternCode for a particular data block is zero, the corresponding residual difference data values must be sent as zero whenever this pairing necessitates sending a residual difference data block for a block with a wPatternCode bit equal to zero.

bNumCoef
The value of bNumCoef[i] indicates the number of coefficients in the residual difference data buffer for each block i of the macroblock, where i is the index of the block within the macroblock as specified in MPEG-2 Figures 6-10, 6-11, and 6-12 (raster-scan order for Y, followed by Cb, followed by Cr). Used only when HostResidDiff is zero and bChromaFormat is 1 (4:2:0). (If used in 4:2:2 or 4:4:4 formats, it would increase the size of typical macroblock control commands past a critical memory alignment boundary, so only an EOB within the transform coefficient structure is used for determining the number of coefficients in each block in non-4:2:0 cases.) The purpose of bNumCoef[i] is to indicate the quantity of data present for each block in the residual difference data buffer, expressed as the number of coefficients present. When the bConfig4GroupedCoefs member of DXVA_ConfigPictureDecode is 1, bNumCoef[i] may contain either the actual number of coefficients sent for the block or that value rounded up to be a multiple of 4. The data for these coefficients is found in the residual difference buffer in the same order.
MVector[4]
An array containing the value of the motion vector(s) for the macroblock, each represented using a DXVA_MVvalue structure.

Headers

Declared in dxva.h. Include dxva.h.

Comments

The HostResidDiff bit within the DXVA_MBctrl_P_HostResidDiff_1 or DXVA_MBctrl_P_OffHostIDCT_1 macroblock control command structure indicates which of these two structures is used.

Valid combinations of IntraMacroblock, MotionForward, MotionBackward, MotionType, MvertFieldSel, and MVector[i] are shown in the following tables. The values specified in the tables are for when H261LoopFilter, Motion4MV and the bPicOBMC member of DXVA_PictureParameters are all zero. The PicCurrentField member is derived from the bPicStructure member of DXVA_PictureParameters.

The first table indicates values for frame-structured pictures (the bPicStructure member of DXVA_PictureParameters is equal to three). The second table indicates values for field-structured pictures (bPicStructure is equal to 1 or 2). The values shown for MotionType in single quotes are binary representations (the first number is for bit 9 and the second is for bit 8).

IntraMacroblock, MotionForward, MotionBackward | MotionType (meaning depends on picture type) | MVector[0] MvertFieldSel[0] (1st, dir1) | MVector[1] MvertFieldSel[1] (1st, dir2) | MVector[2] MvertFieldSel[2] (2nd, dir1) | MVector[3] MvertFieldSel[3] (2nd, dir2)
1,0,0 (intra) | '00' (intra) | - - | - - | - - | - -
0,0,0 (no motion) | '10' (no motion) | 0 - | - - | - - | - -
0,1,0 | '10' (frame MC) | PMV[0][0] - | - - | - - | - -
0,0,1 | '10' (frame MC) | - - | PMV[0][1] - | - - | - -
0,1,1 | '10' (frame MC) | PMV[0][0] - | PMV[0][1] - | - - | - -
0,1,0 | '01' (field MC) | PMV[0][0] sel[0][0] | - - | PMV[1][0] sel[1][0] | - -
0,0,1 | '01' (field MC) | - - | PMV[0][1] sel[0][1] | - - | PMV[1][1] sel[1][1]
0,1,1 | '01' (field MC) | PMV[0][0] sel[0][0] | PMV[0][1] sel[0][1] | PMV[1][0] sel[1][0] | PMV[1][1] sel[1][1]
0,1,0 | '11' (dual-prime) | PMV[0][0] 0 (top) | vector'[2][0][0], vector'[2][0][1]<<1 1 (bot) | PMV[0][0] 1 | vector'[3][0][0], vector'[3][0][1]<<1 0

IntraMacroblock, MotionForward, MotionBackward | MotionType (meaning depends on picture type) | MVector[0] MvertFieldSel[0] (1st, dir1) | MVector[1] MvertFieldSel[1] (1st, dir2) | MVector[2] MvertFieldSel[2] (2nd, dir1) | MVector[3] MvertFieldSel[3] (2nd, dir2)
1,0,0 (intra) | '00' (intra) | - - | - - | - - | - -
0,0,0 (no motion) | '01' (no motion) | 0 PicCurrentField | - - | - - | - -
0,1,0 | '01' (field MC) | PMV[0][0] sel[0][0] | - - | - - | - -
0,0,1 | '01' (field MC) | - - | PMV[0][1] sel[0][1] | - - | - -
0,1,1 | '01' (field MC) | PMV[0][0] sel[0][0] | PMV[0][1] sel[0][1] | - - | - -
0,1,0 | '10' (16x8 MC) | PMV[0][0] sel[0][0] | - - | PMV[1][0] sel[1][0] | - -
0,0,1 | '10' (16x8 MC) | - - | PMV[0][1] sel[0][1] | - - | PMV[1][1] sel[1][1]
0,1,1 | '10' (16x8 MC) | PMV[0][0] sel[0][0] | PMV[0][1] sel[0][1] | PMV[1][0] sel[1][0] | PMV[1][1] sel[1][1]
0,1,0 | '11' (dual-prime) | PMV[0][0] PicCurrentField | vector'[2][0] !PicCurrentField | - - | - -

Use of Macroblock Parameters for Various Motion Types

  14. 1. Experience has shown that there will be bugs in any implementation that fails to properly account for every utilized macroblock type in the table (especially for field-structured pictures or dual-prime motion).
  15. In a number of places in the preceding tables the variable PMV is used rather than the raw motion vector value. This is to distinguish between PMV, which is in frame coordinates, from a motion vector that may be in field coordinates (in other words, at half-vertical resolution). In all such cases, PMV refers to the value of PMV after updating by the current motion vector.
  16. The definitions of vector'[2][0] and vector'[3][0] are found in MPEG-2 Section 7.6.3.6. The shift operation shown indicates that the vertical component is modified to frame coordinates.
  17. In both "no motion" cases (0,0,0) in the preceding tables, the macroblock parameters emulate a forward prediction macroblock (0,1,0) with a zero-valued motion vector. (See also MPEG-2 Section 7.6.3.5.)

The remaining allowed cases (where bPicOBMC is a member of DXVA_PictureParameters) are as follows:

  • H261LoopFilter is equal to 1, bPicOBMC is equal to zero and Motion4MV is equal to zero: This indicates that one forward motion vector is sent in MVector[0] and the H.261 loop filter as specified in Section 3.2.3 of H.261 is active for the forward prediction in the macroblock. MotionForward must be 1 in this case and IntraMacroblock and MotionBackward must both be zero.
  • bPicOBMC is equal to zero and Motion4MV is equal to 1: This indicates that four forward motion vectors are sent in MVector[0, 1, 2, 3]. MotionForward must be 1 in this case and IntraMacroblock must be zero. If MotionBackward is 1, a fifth motion vector is sent for backward prediction in MVector[4].
  • bPicOBMC is equal to 1 and Motion4MV is equal to zero: This indicates that ten forward motion vectors are sent in MVector[0, 1, 2, …, 9] for specification of OBMC motion, and that the values of the first four such motion vectors are all equal. If MotionBackward is 1, an eleventh motion vector is sent for backward prediction in MVector[10].
  • bPicOBMC is equal to one and Motion4MV is equal to one: This indicates that ten forward motion vectors are sent in MVector[0, 1, 2, …, 9] for specification of OBMC motion, and that the values of the first four such motion vectors may differ from each other. If MotionBackward is 1, an eleventh motion vector is sent for backward prediction in MVvector[10].

Some details about the interactions between H.263's OBMC, 4MV, B, EP, and B in PB may be helpful:

  • No current configuration of the H.263 standard would exercise the case in which bPicOBMC is equal to 1, Motion4MV is equal to 1, and MotionBackward is equal to 1.
  • OBMC cannot be used in a H.263 B or EP picture (H.263 Section 5.1.4.5 item 2).
  • OBMC cannot be used in the B part of a H.263 PB picture (H.263 Section F.1 paragraph 1).
  • 4MV cannot be transmitted in a H.263 B or EP picture (Only one MVFW and MVBW in syntax diagrams, and no 4MV macroblock types in H.263 Tables O.1 and O.2).
  • If 4MV is used in the macroblock of a H.263 P picture which is used as the future reference macroblock for "direct" prediction in a H.263 B picture, the OBMC is not used in the direct prediction, because four motion vectors are used according to H.263 Annex M, which uses them like H.263 Annex G which doesn't apply the OBMC (H.263 Section O.4 paragraph 2 and item 2 above it). Thus, H.263 would never require both OBMC and backward prediction at the same time, and never uses 4MV in a backward direction.

    Note The average operator is mathematically identical ((s1+s2+1)>>1) for MPEG-1, MPEG-2 half-sample prediction filtering, bidirectional averaging, and dual prime same-opposite parity combining. The H.263 bidirectional averaging operator does not add the offset of +1 prior to right-shifting. The bBidirectionalAveragingMode member of DXVA_PictureParameters determines which of these methods is used.


DXVA_MVvalue

The DXVA_MVvalue structure is used for the specification of a two-dimensional motion vector value.

typedef struct _DXVA_MVvalue {
  SHORT horz;
  SHORT vert;
} DXVA_MVvalue, *LPDXVA_MVvalue;

Members

horz
Specifies the horizontal component of the value of a motion vector. Contains a signed integer motion offset in half-sample units. The value of this parameter will be even if the bMVprecisionAndChromaRelation member of DXVA_PictureParameters equals two (H.261-style motion supporting only integer-sample offsets).
vert
Specifies the vertical component of the value of a motion vector. Contains a signed integer motion offset in half-sample units. The value of this parameter will be even if the bMVprecisionAndChromaRelation member of DXVA_PictureParameters equals 2 (H.261-style motion supporting only integer-sample offsets).

Headers

Declared in dxva.h. Include dxva.h.

Comments

The DXVA_MVvalue structure is used in the DXVA_MBctrl_P_HostResidDiff_1 and DXVA_MBctrl_P_OffHostIDCT_1 structures.


DXVA_PictureParameters

The DXVA_PictureParameters structure is used to convey the picture-level parameters of a compressed picture for decoding.

typedef struct _DXVA_PictureParameters {
  WORD wDecodedPictureIndex;
  WORD wDeblockedPictureIndex;
  WORD wForwardRefPictureIndex;
  WORD wBackwardRefPictureIndex;
  WORD wPicWidthInMBminus1;
  WORD wPicHeightInMBminus1;
  BYTE bMacroblockWidthMinus1;
  BYTE bMacroblockHeightMinus1;
  BYTE bBlockWidthMinus1;
  BYTE bBlockHeightMinus1;
  BYTE bBPPminus1;
  BYTE bPicStructure;
  BYTE bSecondField;
  BYTE bPicIntra;
  BYTE bPicBackwardPrediction;
  BYTE bBidirectionalAveragingMode;
  BYTE bMVprecisionAndChromaRelation;
  BYTE bChromaFormat;
  BYTE bPicScanFixed;
  BYTE bPicScanMethod;
  BYTE bPicReadbackRequests;
  BYTE bRcontrol;
  BYTE bPicSpatialResid8;
  BYTE bPicOverflowBlocks;
  BYTE bPicExtrapolation;
  BYTE bPicDeblocked;
  BYTE bPicDeblockConfined;
  BYTE bPic4MVallowed;
  BYTE bPicOBMC;
  BYTE bPicBinPB;
  BYTE bMV_RPS;
  BYTE bReservedBits;
  WORD wBitstreamFcodes;
  WORD wBitstreamPCEelements;
  BYTE bBitstreamConcealmentNeed;
  BYTE bBitstreamConcealmentMethod;
} DXVA_PictureParameters, *LPDXVA_PictureParameters;

Members

wDecodedPictureIndex
Specifies destination frame buffer for the decoded macroblocks.
wDeblockedPictureIndex
Specifies destination frame buffer for the deblocked output picture when bPicDeblocked is 1. Has no meaning and must be zero if bPicDeblocked is zero. May be the same as wDecodedPictureIndex.
wForwardRefPictureIndex
Specifies the frame buffer index of the picture to be used as a reference picture for "forward prediction" of the current picture. Must not be the same as wDecodedPictureIndex. Must be 0xFFFF if bPicIntra is 1.
wBackwardRefPictureIndex
Specifies the frame buffer index of the picture to be used as a reference picture for "backward prediction" of the current picture. Must not be the same as wDecodedPictureIndex if backward reference motion prediction is used. Must be 0xFFFF if bPicBackwardPrediction is zero.
wPicWidthInMBminus1
Specifies the width of the current picture in units of macroblocks, minus one. The width of the picture in macroblocks is derived by adding 1 to wPicWidthInMBminus1.
wPicHeightInMBminus1
Specifies the height of the current picture in units of macroblocks, minus 1. The height of the picture in macroblocks is derived by adding 1 to wPicHeightInMBminus1.
bMacroblockWidthMinus1
Specifies the destination luminance sample width of a macroblock, minus 1. This is equal to fifteen for MPEG-1, MPEG-2, H.263, and MPEG-4. A derived term called MacroblockWidth is formed by adding 1 to bMacroblockWidthMinus1.
bMacroblockHeightMinus1
Specifies the destination luminance sample height of a macroblock, minus 1. This is equal to 15 for MPEG-1, MPEG-2, H.261, H.263, and MPEG-4. A derived term called MacroblockHeight is formed by adding 1 to bMacroblockHeightMinus1.
bBlockWidthMinus1
Specifies the block width of a residual difference block minus one. This is equal to 7 for MPEG-1, MPEG-2, H.261, H.263, and MPEG-4. Is 7 if the bConfig4GroupedCoefs member of the DXVA_ConfigPictureDecode structure is 1. Residual difference blocks within a macroblock are sent in the order specified as in MPEG-2 Figures 6-10, 6-11, and 6-12 (raster-scan order for Y, followed by all 4:2:0 blocks of Cb in raster-scan order, followed by 4:2:0 blocks of Cr, followed by 4:2:2 blocks of Cb, followed by 4:2:2 blocks of Cr, followed by 4:4:4 blocks of Cb, followed by 4:4:4 blocks of Cr). A derived term called WT is formed by adding 1 to bBlockWidthMinus1.
bBlockHeightMinus1
Specifies the block height of a residual difference block, minus 1. This is equal to 7 for MPEG-1, MPEG-2, H.261, H.263, and MPEG-4. Is 7 if bConfig4GroupedCoefs is one. A derived term called HT is formed by adding one to bBlockHeightMinus1.
bBPPminus1
Specifies the number of bits per pixel for the video sample values, minus 1. This is at least 7 (indicating 8-bit pixels). It is equal to 7 for MPEG-1, MPEG-2, H.261, and H.263. A larger number of bits per pixel is supported in some operational modes of MPEG-4. A derived term called BPP is formed by adding 1 to bBPPminus1.
bPicStructure
This value has the same meaning as the picture_structure value defined in Section 6.3.10 and Table 6-14 of MPEG-2, and indicates whether the current picture is a top-field picture (a value 1), a bottom-field picture (a value 2), or a frame picture (a value 3). In progressive-scan frame-structured coding such as in H.261, bPicStructure is three. A derived parameter PicCurrentField is defined as zero unless bPicStructure is 2 (bottom field), in which case it is 1.
bSecondField
Indicates whether, in the case of field-structured coding (when bPicStructure is 1 or 2), the current field is the second field of a picture. This is used to determine whether the opposite-parity field used as a reference for the opposite-parity lines for motion compensation prediction is the opposite-parity field of the reference picture or the opposite-parity field of the current picture. If bSecondField is 1, the current field is the second field of a picture and the field used as a reference for the opposite-parity lines for motion compensation are the opposite-parity lines of the current picture. (In both cases the field used as a reference for the same-parity lines for motion compensation are the same-parity lines of the reference picture.) Otherwise, bSecondField is zero.
bPicIntra
Indicates whether motion compensated prediction is needed for this picture. If bPicIntra is 1, all macroblocks are sent with either the DXVA_MBctrl_I_OffHostIDCT_1 or DXVA_MBctrl_I_HostResidDiff_1 macroblock control command structure, in which the IntraMacroblock flag is equal to 1 (that is, no motion compensated prediction is performed for the picture). Otherwise, some macroblocks of the picture may have the IntraMacroblock parameter of the macroblock control command equal to zero and the macroblock control command structure will use the DXVA_MBctrl_P_HostResidDiff_1 or DXVA_MBctrl_P_OffHostIDCT_1 structure.
bPicBackwardPrediction
Indicates whether any macroblocks of the current picture may include backward prediction. If bPicIntra is 1, bPicBackwardPrediction must be zero. If bPicBackwardPrediction is zero, MotionBackward must be zero in all macroblock control commands of the picture (within each DXVA_MBctrl_I_HostResidDiff_1, DXVA_MBctrl_I_OffHostIDCT_1, DXVA_MBctrl_P_HostResidDiff_1, or DXVA_MBctrl_P_OffHostIDCT_1 structure). If bPicBackwardPrediction is 1, some macroblocks of the picture may have MotionBackward equal to one.
bBidirectionalAveragingMode
This variable indicates the rounding method for combining prediction planes in bidirectional motion compensation (used for B pictures and dual-prime motion). The value zero indicates MPEG-1 and MPEG-2 rounded averaging (in which values halfway between two integers are rounded upward to the next higher integer), and the value 1 indicates H.263 truncated averaging (in which values halfway between two integers are rounded downward to the next lower integer). bBidirectionalAveragingMode must be zero if no bidirectional averaging is needed.
bMVprecisionAndChromaRelation
This member indicates the precision of luminance motion vectors and how chrominance motion vectors are derived from luminance motion vectors.

The following table lists field numbers and associated luminance motion vector types.
Value | Description
0 | Indicates that luminance motion vectors have half-sample precision and that chrominance motion vectors are derived from luminance motion vectors according to the rules in MPEG-2.
1 | Indicates that luminance motion vectors have half-sample precision and that chrominance motion vectors are derived from luminance motion vectors according to the rules in H.263.
2 | Indicates that luminance motion vectors have full-sample precision and that chrominance motion vectors are derived from luminance motion vectors according to the rules in H.261 Section 3.2.2 (dividing by 2 and truncating toward zero to full-sample values).
3 | Reserved.

bChromaFormat
Affects the number of prediction error blocks expected by the accelerator. This variable is defined in Section 6.3.5 and Table 6-5 of MPEG-2. For MPEG-1, MPEG-2 "Main Profile," H.261 and H.263 bitstreams, this value must always be set to one, indicating "4:2:0" format. If a value of two this indicates "4:2:2", and if a value of three indicates "4:4:4" sampling. Must be equal to 1 if the bConfig4GroupedCoefs member of DXVA_ConfigPictureDecode is 1 (since bConfig4GroupedCoefs operation does not include the EOB indication needed within coefficient data in 4:2:2 and 4:4:4 formats).

Note Horizontal chroma siting differs slightly between H.261, H.263, MPEG-1 versus MPEG-2 and MPEG-4. This difference is assumed to be small enough to ignore.

bPicScanFixed
When using accelerator-based IDCT processing of residual difference blocks, a value of 1 for this flag indicates that the inverse-scan method is the same for all macroblocks in the picture, and a value of zero indicates that it is not. Must be 1 if the bConfigHostInverseScan member is 1 or if the bConfigResidDiffAccelerator member is zero in DXVA_ConfigPictureDecode.
bPicScanMethod
When bPicScanFixed is 1, this member indicates the fixed inverse scan method for the picture. When bPicScanFixed is zero, this member has no meaning and must be a value of zero. If bPicScanFixed is 1 this member must have one of the following values.

If the bConfigHostInverseScan member of DXVA_ConfigPictureDecode is zero, the scan method defined by bPicScanMethod is shown in the following table.
Value | Description
0 | Zig-zag scan (MPEG-2 Figure 7-2)
1 | Alternate-vertical (MPEG-2 Figure 7-3)
2 | Alternate-horizontal (H.263 Figure I.2 Part a)

If the bConfigHostInverseScan member of DXVA_ConfigPictureDecode is 1, the scan method defined by bPicScanMethod must be set as follows.
Value | Description
3 | Arbitrary scan with absolute coefficient address

bPicReadbackRequests
Indicates whether read-back control requests are issued for the current picture to read back the values of macroblocks in the final decoded (and deblocked, if deblocking is applied with wDeblockedPictureIndex equal to wDecodedPictureIndex) picture. A value of 1 indicates that read-back requests are present, and zero indicates that they are not.
bRcontrol
Defines the rounding method to be used for half-sample motion compensation. This variable is defined in H.263 Section 6.1.2. A value of zero indicates the half-sample rounding method found in MPEG-1, MPEG-2, and the first version of H.263. A value of 1 indicates the rounding method that includes a downward averaging bias that can be selected in some optional modes of H.263 and MPEG-4. It is meaningless for H.261, since H.261 has no half-sample motion compensation. It must be set to zero for all MPEG-1, and MPEG-2 bitstreams in order to conform with the rounding operator defined by those standards.
bPicSpatialResid8
A value of 1 indicates that spatial-domain difference blocks for host-based residual difference decoding can be sent using 8-bit samples, and a value of zero indicates that they cannot.

Must be zero if the bConfigResidDiffHost member of DXVA_ConfigPictureDecode is zero or if BPP is greater than 8. Must be 1 if BPP is 8, bPicIntra is 1 and bConfigResidDiffHost is 1. Must be 1 if the bConfigSpatialResid8 member of DXVA_ConfigPictureDecode is 1.

If equal to 1, bPicSpatialResid8 indicates that spatial-domain intra macroblocks are sent as 8-bit values (that are either signed or unsigned as determined by the bConfigIntraResidUnsigned member of DXVA_ConfigPictureDecode) and that spatial-domain non-intra macroblock differences are sent as signed 8-bit difference values relative to some motion compensated prediction.

The bPicSpatialResid8 member differs from the bConfigSpatialResid8 member of DXVA_ConfigPictureDecode in that it is an indication for a particular picture, not a global indication for the entire video sequence. In some cases such as in an intra picture with BPP equal to eight, bPicSpatialResid8 will be 1 even though bConfigSpatialResid8 may be zero.

bPicOverflowBlocks
A value of 1 indicates that spatial-domain difference blocks for host-based residual difference decoding of a picture may be sent using "overflow" blocks, and a value of zero indicates that they are not. Must be zero if bConfigResidDiffHost is zero or if bConfigSpatialResid8 is zero or if BPP > 8. Parameters bConfigResidDiffHost and bConfigSpatialResid8 are members of DXVA_ConfigPictureDecode. bPicOverflowBlocks indicates whether any overflow blocks may be present for the particular picture. In an intra picture with BPP equal to 8, bPicOverflowBlocks must be zero as no overflow blocks are needed in this case.
bPicExtrapolation
Indicates whether motion vectors over picture boundaries are allowed as specified by H.263 Annex D and MPEG-4. This requires either allocation of picture planes that are two macroblocks wider (one extra macroblock at the left and another at the right) and two macroblocks taller (one extra macroblock at the top and another at the bottom) than the decoded picture size, or clipping of the address of each individual pixel access to within the picture boundaries. Macroblock addresses in this specification are for macroblocks in the interior of the picture, not including padding.
bPicDeblocked
Indicates whether deblocking commands are sent for this picture for creating a deblocked output picture in the picture buffer indicated in wDeblockedPictureIndex. If bPicDeblocked is 1, deblocking commands are sent and the deblocked frame is generated, and if bPicDeblocked is zero, no deblocking commands are sent and no deblocked picture is generated.
bPicDeblockConfined
Indicates whether deblocking filter command buffers contain commands which confine the effect of the deblocking filter operations to within the same set of macroblocks that are contained in the buffer.
bPic4MVallowed
Specifies whether four forward-reference motion vectors per macroblock are allowed as used in H.263 Annexes F and J.
bPicOBMC
Specifies whether motion compensation for the current picture operates using overlapped block motion compensation (OBMC) as specified in H.263 Annex F. Must be zero if bPic4MVallowed is zero.
bPicBinPB
Specifies whether bidirectionally-predicted macroblocks in the picture use "B in PB" motion compensation, which restricts the bidirectionally predicted area for each macroblock to the region of the corresponding macroblock in the backward reference picture, as specified in Annexes G and M of H.263.
bMV_RPS
Specifies the use of motion vector reference picture selection. If bMV_RPS is 1, this indicates that a reference picture index is sent for each motion vector rather than just forward and possibly backward motion picture indexes for the picture as a whole. If bMV_RPS is 1, the wForwardRefPictureIndex and wBackwardRefPictureIndex members have no meaning and must be zero.
bReservedBits
Reserved bits used for packing and/or alignment. Must be zero.
wBitstreamFcodes
When bConfigBitstreamRaw is 1, this member contains four motion vector f_code values as defined in MPEG-2. Each f_code value takes four bits. These values are packed into a 16-bit word as in MPEG-2 as follows:
Bits | Description
12-15 (the MSBs) | f_code[0][0]: The forward horizontal f_code
8-11 | f_code[0][1]: The forward vertical f_code
7-4 | f_code[1][0]: The backward horizontal f_code
0-3 (the LSBs) | f_code[1][1]: The backward vertical f_code

If any f_code value is unnecessary or irrelevant due to the structure of the bitstream data, due to the bConfigBitstreamRaw member of DXVA_ConfigPictureDecode being zero, or due to the f_code parameter not being needed in the relevant video coding bitstream syntax (such as in H.261 or H.263), then the f_code value is 0xF.

Note MPEG-1 bitstreams provide this information in a different form. Therefore for MPEG-1 bitstreams, f_code[0][0] and f_code[0][1] are equal to MPEG-1's forward_f_code and f_code[1][0] and f_code[1][1] are equal to MPEG-1's backward_f_code.

wBitstreamPCEelements
When the bConfigBitstreamRaw member of DXVA_ConfigPictureDecode is 1, this member contains a set of flags necessary for the bitstream decoding process of MPEG-2 video. It is not used and must be zero when bConfigBitstreamRaw is zero and for non-MPEG-2 video. The bits in this member are defined by their correspondence with bitstream elements of the MPEG-2 picture coding extension as follows:
Bits | Description
14 and 15 | IntraDCprecision is equal to intra_dc_precision
12 and 13 | AnotherPicStructure is equal to picture_structure. Must be equal to bPicStructure
11 | TopFieldFirst is equal to top_field_first
10 | FrameDCTprediction is equal to frame_pred_frame_dct
9 | ConcealmentMVs is equal to concealment_motion_vectors
8 | QuantScaleType is equal to q_scale_type
7 | IntraVLCformat is equal to intra_vlc_format
6 | AlternateScan is equal to alternate_scan
5 | RepeatFirstField is equal to repeat_first_field (not needed by the accelerator)
4 | Chroma420type is equal to chroma_420_type (not needed by the accelerator and restricted by MPEG-2 to be equal to progressive_frame)
3 | ProgressiveFrame is equal to progressive_frame
0, 1, and 2 (the LSBs) | Reserved Bits

bBitstreamConcealmentNeed
Specifies, when the bConfigBitstreamRaw member of DXVA_ConfigPictureDecode is 1, whether there is a significant likelihood of the bitstream data containing errors. Must be zero if bConfigBitstreamRaw is zero. Video accelerators must be designed not to crash or lock up, regardless of the content of the data given to them. However, it may be helpful for a video accelerator to have information about the host's assessment of the likelihood of syntactical errors in order to determine whether there is a need to be able to invoke some more complex error concealment algorithms that might slow down the bitstream decoding process. Allowed values for this member are as follows (all other values are reserved).
Value | Description
0 | Indicates that the bitstream is unlikely to contain any significant amount of errors in its syntactical format.
1 | Indicates that the bitstream may contain some errors, but these errors are likely to be infrequent (for example, some error once or twice per hour).
2 | Indicates that the bitstream is likely to contain some errors, and that these errors are likely to occur with a frequency that could have some impact on the user experience (for example, some error every five to ten minutes), but that these errors are not likely to be a constant presence.
3 | Indicates that the bitstream is likely to contain relatively significant, serious, and frequent syntactical format errors (for example, one per minute or more frequent errors).

bBitstreamConcealmentMethod
Specifies a preferred default method for error concealment processing when the bConfigBitstreamRaw member of DXVA_ConfigPictureDecode is 1. Must be zero if bConfigBitstreamRaw is zero. Allowed values for this member are as follows (all other values are reserved):
Value | Description
0 | Preferred concealment method unknown or unspecified.
1 | Preferred concealment method is to use spatial intra-picture concealment within the picture.
2 | Preferred concealment method is to use the forward-motion reference picture for inter-picture concealment (to be used most typically in a P picture or in a B picture that is temporally closer to its forward-motion reference picture than to its backward-motion reference picture).
3 | Preferred concealment method is to use the backward-motion reference picture for inter-picture concealment (to be used most typically in a B picture that is temporally closer to its backward-motion reference picture than to its forward-motion reference picture).

Headers

Declared in dxva.h. Include dxva.h.

Comments

Certain contents of the DXVA_PictureParameters structure are constrained to specific values by the configuration established using the DXVA_ConfigPictureDecode structure. Once the picture-level parameters are conveyed using DXVA_PictureParameters, the picture decoding process is primarily governed by macroblock control commands formed using the DXVA_MBctrl_I_HostResidDiff_1, DXVA_MBctrl_I_OffHostIDCT_1, DXVA_MBctrl_P_HostResidDiff_1, or DXVA_MBctrl_P_OffHostIDCT_1 structures.


DXVA_PicResample

The DXVA_PicResample structure is used for controlling the resampling process invoked when the bDXVA_Func variable is equal to 4.

typedef struct _DXVA_PicResample {
  WORD  wPicResampleSourcePicIndex;
  WORD  wPicResampleDestPicIndex;
  WORD  wPicResampleRcontrol;
  BYTE  bPicResampleExtrapWidth;
  BYTE  bPicResampleExtrapHeight;
  DWORD dwPicResampleSourceWidth;
  DWORD dwPicResampleSourceHeight;
  DWORD dwPicResampleDestWidth;
  DWORD dwPicResampleDestHeight;
  DWORD dwPicResampleFullDestWidth;
  DWORD dwPicResampleFullDestHeight;
} DXVA_PicResample, *LPDXVA_PicResample;

Members

wPicResampleSourcePicIndex
Specifies the reference buffer to be resampled.
wPicResampleDestPicIndex
Specifies the buffer to be used for the output of the reference picture resampling operation.
wPicResampleRcontrol
Specifies the averaging rounding mode of the resampling operation. In the case of H.263 Annex O Spatial Scalability, this member is 1. (This corresponds to the value of RCRPR in H.263 Annex P that is equivalent to the upsampling needed for H.263 Annex O spatial scalability.) In the case of H.263 Annex P Reference Picture Resampling, this value is equal to the H.263 parameter RCRPR.
bPicResampleExtrapWidth
If nonzero and the padding method of using motion vectors over picture boundaries is used on the accelerator, any resampling must include padding of the resampled picture as well – and this padding must cover at least the specified width around each edge of the resampled picture regardless of the resampling operation that is performed.
bPicResampleExtrapHeight
If nonzero and the padding method of using motion vectors over picture boundaries is used on the accelerator, any resampling must include padding of the resampled picture as well – and this padding must cover at least the specified height around each edge of the resampled picture regardless of the resampling operation that is performed.
dwPicResampleSourceWidth
Specifies the width of the area of the source picture to be resampled to the destination picture.
dwPicResampleSourceHeight
Specifies the height of the area of the source picture to be resampled to the destination picture.
dwPicResampleDestWidth
Specifies the width of the area of the destination picture to contain the resampled data from the source picture.
dwPicResampleDestHeight
Specifies the height of the area of the destination picture to contain the resampled data from the source picture.
dwPicResampleFullDestWidth
Specifies the full width of the area of the destination picture to contain the resampled data from the source picture. Clipping is used to generate any samples outside the source resampling area. (This value is necessary for H.263 Annex P support of custom source formats in which the luminance width or height is not divisible by 16.)
dwPicResampleFullDestHeight
Specifies the full height of the area of the destination picture to contain the resampled data from the source picture. Clipping is used to generate any samples outside the source resampling area. (This value is necessary for H.263 Annex P support of custom source formats in which the luminance width or height is not divisible by 16.)

Headers

Declared in dxva.h. Include dxva.h.


DXVA_QmatrixData

The DXVA_QmatrixData structure is used to load quantization matrix data for off-host bitstream compressed video picture decoding.

typedef struct _DXVA_QmatrixData {
  BYTE bNewQmatrix[4];
  WORD Qmatrix[4][64];
} DXVA_QmatrixData, *LPDXVA_QmatrixData;

Members

bNewQmatrix
Indicates whether a new inverse-quantization matrix of type i is present in the buffer. If bNewQmatrix[i] is 1, a new inverse-quantization matrix of type i follows in the inverse-quantization matrix buffer. Type i=0 is for intra luminance quantization, i=1 is for inter luminance quantization, i=2 is for intra-chrominance quantization, and i=3 is for inter chrominance quantization. No default values of inverse-quantization matrices may be assumed by the accelerator in the absence of any prior value sent by the host. The value of bNewQmatrix[i] must not be zero for both i=0 and i=1.

If the value of bNewQmatrix[i] is zero for i=2 or i=3, then:

  1. If bNewQmatrix[i-2] is zero, the previous inverse-quantization matrix for i must continue to be used by the accelerator, and
  2. If bNewQmatrix[i-2] is 1, the inverse-quantization matrix for i is set equal to the new inverse-quantization matrix for i-2.

If the relevant video coding specification does not need inverse-quantization matrices (for example, H.261 and H.263), inverse-quantization matrix buffers must not be sent. If the relevant video coding specification does need inverse-quantization matrices, some value must be provided for these inverse-quantization matrices by the host prior to, or in conjunction with, the transferal of any bitstream data buffers at the start of the video decoding process.

Note No default value is assumed for quantization matrices in the absence of any prior value sent from the host. The quantization matrix values must be sent explicitly, even if they contain values that are available by default in the relevant video coding specification.

Qmatrix
An inverse-quantization matrix. Present only when bNewQmatrix[i] is equal to 1. The matrix consists of (bBlockWidthMinus1+1) X (bBlockHeightMinus1+1) unsigned words (in which only the lower eight bits of each word are used for the dominant video coding standards), where bBlockWidthMinus1 and bBlockHeightMinus1 are members of DXVA_PictureParameters. The order of the data values within the inverse-quantization matrix is as specified in the relevant video coding specification.

Note For MPEG-2 bitstreams, the data values within Qmatrix[i] are in zig-zag inverse scan order, as specified in subclause 7.3.1 and Figure 7-2 of MPEG-2.

Headers

Declared in dxva.h. Include dxva.h.

Comments

An inverse-quantization matrix buffer is sent to initialize inverse-quantization matrices for off-host bitstream decoding. Inverse-quantization matrix buffers are sent only when the bConfigBitstreamRaw member of DXVA_ConfigPictureDecode is 1. Inverse-quantization matrix buffers provide information about how to decode all current and subsequent video in the bitstream, until a new inverse-quantization matrix buffer is provided. (Thus, inverse-quantization matrices are persistent.) No more than one inverse-quantization matrix buffer may be sent from the host to the accelerator at a time.


DXVA_SliceInfo

The DXVA_SliceInfo structure is used to specify the slice-level parameters of a slice of bitstream data for off-host bitstream compressed picture decoding.

typedef struct _DXVA_SliceInfo {
  WORD  wHorizontalPosition;
  WORD  wVerticalPosition;
  DWORD dwSliceBitsInBuffer;
  DWORD dwSliceDataLocation;
  BYTE  bStartCodeBitOffset;
  BYTE  bReservedBits;
  WORD  wMBbitOffset;
  WORD  wNumberMBsInSlice;
  WORD  wQuantizerScaleCode;
  WORD  wBadSliceChopping;
} DXVA_SliceInfo, *LPDXVA_SliceInfo;

Members

wHorizontalPosition
Specifies the horizontal position of the first macroblock of the slice expressed in units of macroblocks, with zero indicating the left-most or top-most macroblock of the picture.
wVerticalPosition
Specifies the vertical position of the first macroblock of the slice expressed in units of macroblocks with zero indicating the left-most or top-most macroblock of the picture.
dwSliceBitsInBuffer
Specifies the total number of bits in the corresponding bitstream data buffer that contain data for the current slice. This must be a multiple of eight for MPEG-1, MPEG-2, MPEG-4, and in the slice structured mode of H.263, since slice start codes in these cases are byte-aligned.
dwSliceDataLocation
Specifies the location of the first byte containing data for the slice (for example, the location of a slice start code) in the bitstream data buffer. Must be zero if the start of the slice is not within the corresponding bitstream data buffer.
bStartCodeBitOffset
Specifies the number of MSBs of the byte at dwSliceDataLocation that do not contain data for the slice (must be zero for MPEG-1, MPEG-2, and MPEG-4 since slice start codes in these specifications are byte aligned, but possibly nonzero for H.261 and H.263 that do not force byte alignment of GOB start codes). Must be in the range of 0…7. Must be zero if the start of the slice is not within the corresponding bitstream data buffer. MSBs marked irrelevant for the current slice by bStartCodeBitOffset may contain data for a previous slice in the case of start codes that are not byte aligned, as may occur for example in H.263 baseline mode.
bReservedBits
Reserved bits used for packing and/or alignment. Must be zero.
wMBbitOffset
Specifies the number of bits of slice header data prior to the first bit of macroblock layer data in the bitstream buffer. For example, if wMBbitOffset is 83, the macroblock layer data for the slice starts after 83 bits slice header data. Must be zero if the start of the slice is not within the corresponding bitstream data buffer.
wNumberMBsInSlice
Specifies the number of macroblocks of data in the slice, including skipped macroblocks. May be zero if this number cannot be readily determined from the header of the picture and the headers and initial macroblock data of the current and next slice in the bitstream, such as in the rectangular slice and arbitrary slice ordering submodes of the slice mode of H.263. Must not be zero for H.261, MPEG-1, MPEG-2, MPEG-4, or when not using the rectangular slice or arbitrary slice submodes of the slice structured mode in H.263.
wQuantizerScaleCode
The quantizer scaling code from the slice level of the bitstream, as specified in the particular video coding specification (ranging from 1 to 31 for H.261, H.262/MPEG-2, H.263, MPEG-1, and MPEG-4).
wBadSliceChopping
Specifies a value defined as follows.
Value | Description
0 | All bits for the slice are located within the corresponding bitstream data buffer.
1 | The bits for the start of the slice are within the corresponding bitstream data buffer, and the bits for the end of the slice are not (because the bitstream data buffer is full).
2 | The bits for the start of the slice are not within the corresponding bitstream data buffer (because the previous bitstream data buffer was full), but the bits for the end of the slice are within the corresponding bitstream data buffer.
3 | The bits for the start of the slice are not within the corresponding bitstream data buffer (because the previous bitstream data buffer was full), and the bits for the end of the slice are also not within the corresponding bitstream data buffer (because the corresponding bitstream data buffer is also full).

Note Nonzero values of wBadSliceChopping should generally be avoided by the host software decoder.

Headers

Declared in dxva.h. Include dxva.h.

Comments

Slice-control buffers are provided to guide the operation of off-host VLD bitstream processing. Slice-control buffers are sent only when the bConfigBitstreamRaw member of DXVA_ConfigPictureDecode is 1. The host software decoder must determine the location of "slice-level" resynchronization points in the bitstream. A slice is defined to be a multi-macroblock layer that includes a resynchronization point in the bitstream data. In H.261 bitstreams, a GOB is considered a slice. In H.263 bitstreams, a sequence of one or more GOBs starting with a GOB start code and containing no additional GOB start codes is considered a slice. A slice-control buffer must contain one or more DXVA_SliceInfo structures, according to the contents of a corresponding bitstream data buffer.


DXVA_TCoef4Group

The DXVA_TCoef4Group structure specifies the IDCT coefficient values.

typedef struct _DXVA_TCoef4Group {
  BYTE  TCoefIDX[4];
  SHORT TCoefValue[4];
} DXVA_TCoef4Group, *LPDXVA_TCoef4Group;

Members

TCoefIDX
Specifies the index of the coefficient in the block. Expressed as the number of zero-valued coefficients that precede the current coefficient in the scan order specified by the MBscanMethod member of the macroblock control command. These commands are defined in the following structures: DXVA_MBctrl_I_OffHostIDCT_1 or DXVA_MBctrl_P_OffHostIDCT_1. TCoefIDX contains the number of zero-valued coefficients that precede the current coefficient in the specified scan order, subsequent to the last transmitted coefficient for the block (or relative to the start of the block if none precede it). Any remaining coefficients after the last sent coefficient in the inverse-scan order are implied to have the value 0.

TCoefIDX must never be greater than or equal to 64.

TCoefValue
The value of the coefficient in the block. TCoefValue must be clipped to the appropriate range as specified in Low-Level IDCT Processing Elements by the host prior to passing the coefficient value to the accelerator for IDCT operation. MPEG-2 mismatch control, if necessary, is also the responsibility of the host, not the accelerator (this may require the creation of extra "phantom" nonzero coefficients).

Headers

Declared in dxva.h. Include dxva.h.

Comments

The DXVA_TCoef4Group structure is used only when these two members of DXVA_ConfigPictureDecode structure are set to the following values: bConfig4GroupedCoefs is 1 and bConfigHostInverseScan is zero.

In the DXVA_TCoef4Group structure, groups of four transform coefficients are sent together with associated run-length values. The ith element of each array in DXVA_TCoef4Group contains element 3-i of the actual coefficient or run-length list (so the first coefficient or index goes into element 3, the next in element 2, etc.). If only NC<4 nonzero coefficients remain that need to be sent for a block, then TCoefIDX[i] must be 63 (hexadecimal 0x3F) and TCoefValue[i] must be equal to TCoefValue[4–NC] for i=0 to 3–NC.


DXVA_TCoefSingle

The DXVA_TCoefSingle structure is used to specify IDCT coefficient values.

typedef struct _DXVA_TCoefSingle {
  WORD  wIndexWithEOB;
  SHORT TCoefValue;
} DXVA_TCoefSingle, *LPDXVA_TCoefSingle;

Members

wIndexWithEOB
wIndexWithEOB contains two fields: TCoefIDX (the 15 MSBs) and TCoefEOB (the LSB).
TCoefIDX
Specifies the index of the coefficient in the block, as determined from the bConfigHostInverseScan member of DXVA_ConfigPictureDecode.

There are two ways that TCoefIDX can be used:

  1. Run-length ordering: When bConfigHostInverseScan is zero, the MBscanMethod element of the macroblock control command indicates a zig-zag, alternate-vertical, or alternate-horizontal inverse scan. These macroblock control commands are defined in the following structures: DXVA_MBctrl_I_OffHostIDCT_1 or DXVA_MBctrl_P_OffHostIDCT_1. In this case, TCoefIDX contains the number of zero-valued coefficients that precede the current coefficient in the specified scan order, subsequent to the last transmitted coefficient for the block (or relative to the start of the block if none preceding). Any remaining coefficients after the last sent coefficient in the inverse-scan order are implied to have the value zero.
  2. Arbitrary ordering: When bConfigHostInverseScan is 1, the MBscanMethod element of the macroblock control command indicates arbitrary ordering. These macroblock control commands are defined in the following structures: DXVA_MBctrl_I_OffHostIDCT_1 or DXVA_MBctrl_P_OffHostIDCT_1. In this case, TCoefIDX simply contains the raster index of the coefficient within the block (TCoefIDX = u + 8 * v, where u and v are the transform-domain horizontal and vertical frequency coordinates), and any coefficients that are not sent are implied to have the value 0.
TCoefIDX must never be greater than or equal to 64.
TCoefEOB
Indicates whether the current coefficient is the last one associated with the current block of transform coefficients. TCoefEOB is the LSB of the first word of the DXVA_TCoefSingle structure. A value of 1 indicates that the current coefficient is the last one for the block and a value of zero indicates that it is not.
TCoefValue
The value of the coefficient in the block. TCoefValue must be clipped to the appropriate range as specified in Low-Level IDCT Processing Elements by the host prior to passing the coefficient value to the accelerator for IDCT operation. MPEG-2 mismatch control, if necessary, is also the responsibility of the host, not the accelerator (this may require the creation of extra "phantom" nonzero coefficients).

Headers

Declared in dxva.h. Include dxva.h.

Comments

The DXVA_TCoefSingle structure is used whenever the HostResidDiff bit in the macroblock control command (either DXVA_MBctrl_I_OffHostIDCT_1 or DXVA_MBctrl_P_OffHostIDCT_1) is 1 and the bConfig4GroupedCoefs member of DXVA_ConfigPictureDecode is zero.


RECT

The RECT structure defines the coordinates of the upper-left and lower-right corners of a rectangle. This structure is also described in the Platform SDK.

typedef struct _RECT {
  LONG left;
  LONG top;
  LONG right;
  LONG bottom;
} RECT, *PRECT;

Members

left
Specifies the x-coordinate of the upper-left corner of the rectangle.
top
Specifies the y-coordinate of the upper-left corner of the rectangle.
right
Specifies the x-coordinate of the lower-right corner of the rectangle.
bottom
Specifies the y-coordinate of the lower-right corner of the rectangle.

Headers

Declared in Windef.h; include Windows.h.

Comments

This function is part of the Platform SDK. To use it you must have the Platform SDK installed.

When RECT is passed to the FillRect function, the rectangle is filled up to, but not including, the right column and bottom row of pixels. This structure is identical to the RECTL structure.


Video Miniport Driver Functions

This section provides reference pages for functions that can or must be implemented in a video miniport driver.

Function names in the form of HwVid Xxx and SvgaHwIoPort Xxx are sample names only; that is, these functions can have any name chosen by the driver writer. DriverEntry is a required name. Video Miniport Header Files, Sample Code, and References lists the include files that contain declarations for these functions.

It is highly recommended that all miniport driver functions be made pageable, with a few exceptions. Miniport driver functions that must not be made pageable are:

  • HwVidInterrupt
  • An HwVidSynchronizeExecutionCallback that is passed in calls to VideoPortSynchronizeExecution
  • HwVidResetHw
  • HwVidBankedMemoryCallback
  • HwVidTimer
  • An internal function called by any of the preceding function(s)

For more information about video-specific I/O requests that must be supported by the port-miniport driver pair, see also Video I/O Control Codes. For more information about the sequence in which these miniport driver functions are called, see Video Miniport Drivers.


DriverEntry of Video Miniport Driver

DriverEntry is the initial entry point into the video miniport driver.

ULONG
  DriverEntry(
    IN PVOID  Context1,
    IN PVOID  Context2
    );

Parameters

Context1
Points to a context value with which the miniport driver must call VideoPortInitialize. This context value identifies the driver object created by the system for this miniport driver.
Context2
Points to a second context value with which the miniport driver must call VideoPortInitialize. This context value identifies the registry path for this miniport driver.

Return Value

DriverEntry returns the value returned by VideoPortInitialize.

Headers

Declared in video.h. Include video.h.

Comments

Each miniport driver must have a function explicitly named DriverEntry in order to be loaded. DriverEntry is called directly by the I/O system.

DriverEntry must perform the following steps:

  • Allocate memory on the stack for a VIDEO_HW_INITIALIZATION_DATA structure, and call VideoPortZeroMemory to zero-initialize it.
  • Fill in driver-specific and adapter-specific values in the VIDEO_HW_INITIALIZATION_DATA members, including the miniport driver's entry points. The following entry points must be set to a miniport driver-supplied routine:

    HwVidFindAdapter

    HwVidInitialize

    HwVidStartIO

    HwVidGetVideoChildDescriptor

    HwVidGetPowerState

    HwVidSetPowerState

    For each of the remaining entry point members that the driver implements, the driver should set that entry point member to point to the appropriate driver-supplied routine.

  • If the driver's hardware supports legacy resources, the driver must report them. DriverEntry should do the following if the resource list is known at driver compile time:
    • Claim and report all such resources in the HwLegacyResourceList and HwLegacyResourceCount members of VIDEO_HW_INITIALIZATION_DATA. Legacy resources are those resources not listed in the device's PCI configuration space but that are decoded by the device.
    • Fill in the RangePassive field accordingly for each VIDEO_ACCESS_RANGE structure defined in the miniport driver.

    If the legacy resource list cannot be determined until runtime, the driver should instead implement a HwVidLegacyResources function to report them.

  • Call VideoPortInitialize, passing Context1 and Context2 as the first two parameters, a pointer to the VIDEO_HW_INITIALIZATION_DATA structure as the third parameter, and NULL as the fourth parameter.

DriverEntry should propagate the value returned by VideoPortInitialize back to the caller.

If DriverEntry does claim resources, it should include only those resources that the hardware decodes but that are not claimed by PCI. The miniport driver can "reclaim" these legacy resources again in subsequent call(s) to VideoPortVerifyAccessRanges; however, the video port driver will just ignore requests for any such previously claimed resources. Power management and docking will be disabled in the system if the miniport driver attempts to claim a legacy access range in VideoPortVerifyAccessRanges that was not previously claimed in the HwLegacyResourceList during DriverEntry (or in HwVidLegacyResources, if implemented).

For Windows® 2000 and later drivers that also support machines running Windows NT® 4.0, there are two constants defined in video.h. These constants are described in the following table.

Constant | Meaning
SIZE_OF_NT4_VIDEO_PORT_CONFIG_INFO | The size, in bytes, of the Windows NT 4.0 VIDEO_PORT_CONFIG_INFO structure.
SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA | The size, in bytes, of the Windows NT 4.0 VIDEO_HW_INITIALIZATION_DATA structure. If VideoPortInitialize fails, the video miniport driver should set the HwInitDataSize member of the VIDEO_HW_INITIALIZATION_DATA structure to the size of either the Windows 2000 (and later) version of this structure or the Windows NT 4.0 version. Choose the appropriate structure size to match the operating system version on which the miniport driver will run. The video miniport driver should then call VideoPortInitialize again. For an example of use, please see the video miniport driver samples that ship in this DDK.
SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA | The size, in bytes, of the Windows 2000 and later VIDEO_HW_INITIALIZATION_DATA structure.

See Also

HwVidFindAdapter, HwVidLegacyResources, VIDEO_HW_INITIALIZATION_DATA, VideoPortInitialize, VideoPortVerifyAccessRanges, VideoPortZeroMemory


HwVidBankedMemoryCallback

HwVidBankedMemoryCallback updates the Bank Index Register.

This function is obsolete and should not be implemented in miniport drivers.

VOID
  (*PBANKED_SECTION_ROUTINE)(
    IN ULONG  ReadBank,
    IN ULONG  WriteBank,
    IN PVOID  Context
    );


HwVidExecuteDma

HwVidExecuteDma is a miniport driver-implemented callback routine that is responsible for retrieving physical address/length pairs from a scatter/gather list, and for programming the hardware to start the actual DMA transfer.

VOID
  (*PEXECUTE_DMA)(
    IN PVOID  HwDeviceExtension,
    IN PVP_DMA_ADAPTER  VpDmaAdapter,
    IN PVP_SCATTER_GATHER_LIST  SGList,
    IN PVOID  Context
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
VpDmaAdapter
Points to the VP_DMA_ADAPTER structure that represents the busmaster adapter. This structure was returned by a call to VideoPortGetDmaAdapter.
SGList
Points to a VP_SCATTER_GATHER_LIST structure. The video port driver fills in the information in this structure, and passes this structure to the miniport driver.
Context
Points to the driver-determined context passed in from VideoPortStartDma.

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

If the miniport driver reports that the device does not support scatter/gather, there will be only a single element in the scatter/gather list passed to this routine. The scatter/gather list is valid until VideoPortCompleteDma is called.

The last task that the video port driver's VideoPortStartDma function performs is to call the miniport driver's HwVidExecuteDma callback routine. It is this callback that actually carries out the DMA transfer operation.

See Also

VideoPortGetDmaAdapter, VideoPortStartDma, VideoPortCompleteDma, VP_DMA_ADAPTER, VP_SCATTER_GATHER_LIST


HwVidFindAdapter

HwVidFindAdapter gets the access ranges for a device on either an enumerable or non-enumerable bus and, if necessary, determines the device type.

VP_STATUS
  (*PVIDEO_HW_FIND_ADAPTER)(
    IN PVOID  HwDeviceExtension,
    IN PVOID  HwContext,
    IN PWSTR  ArgumentString,
    IN OUT PVIDEO_PORT_CONFIG_INFO  ConfigInfo,
    OUT PUCHAR  Again
    );

Parameters

HwDeviceExtension
Points to the driver's per-device storage area.
HwContext
Is NULL and should be ignored by the miniport driver.
ArgumentString
Points to a zero-terminated ASCII string that originates with the user. This pointer can be NULL.
ConfigInfo
Points to a VIDEO_PORT_CONFIG_INFO structure. The video port driver allocates memory for and initializes this structure with any known configuration information, such as values the miniport driver set in the VIDEO_HW_INITIALIZATION_DATA and the SystemIoBusNumber.
Again
Should be ignored by the miniport driver.

Return Value

HwVidFindAdapter must return one of the following status codes:

Value | Meaning
ERROR_DEV_NOT_EXIST | Indicates, for a non-enumerable bus, that the miniport driver could not find the device.
ERROR_INVALID_PARAMETER | Indicates the miniport driver could not configure or initialize the adapter successfully.
NO_ERROR | Indicates success.

Headers

Declared in video.h. Include video.h.

Comments

Every video miniport driver must have an HwVidFindAdapter function.

The video port driver does the following before it calls HwVidFindAdapter:

  • Allocates storage for the miniport driver's per-adapter storage area according to the HwDeviceExtensionSize that the miniport driver's DriverEntry function specified in the VIDEO_HW_INITIALIZATION_DATA structure, and zero-initializes the allocated storage.
  • Allocates storage for a VIDEO_PORT_CONFIG_INFO structure and fills in all available information based on miniport driver-supplied information in VIDEO_HW_INITIALIZATION_DATA.

The video port driver then calls the miniport driver's HwVidFindAdapter function with pointers to the initialized per-adapter storage area and configuration information in the HwDeviceExtension and ConfigInfo parameters, respectively.

The HwVidFindAdapter function for devices on an enumerable bus must do the following:

  • Check the size of the VIDEO_PORT_CONFIG_INFO structure to which ConfigInfo points to ensure proper versioning.
  • Call VideoPortGetAccessRanges to obtain the bus-relative physical addresses to which the device will respond. These addresses are assigned by the PnP Manager. The miniport driver should pass NULL in the VendorId, DeviceId, and Slot parameters of VideoPortGetAccessRanges.
  • For miniport drivers that support several device types, determine the type of device that the PnP Manager has detected. The miniport driver can call VideoPortGetBusData to obtain PCI configuration information.
  • Call VideoPortVerifyAccessRanges to claim the resources that the device decodes, such as the bus-relative access ranges of device memory and I/O ports.
  • Fill in any relevant but missing configuration information in the appropriate members of the VIDEO_PORT_CONFIG_INFO structure with adapter-specific data.

HwVidFindAdapter should not attempt to initialize the device.

For a device on a non-enumerable bus such as ISA, PnP still attempts to start the device, although it is the responsibility of HwVidFindAdapter to determine whether the device is actually present. If the device is not found, HwVidFindAdapter should return ERROR_DEV_NOT_EXIST.

HwVidFindAdapter should also call VideoPortSetRegistryParameters to store adapter-specific information in the HardwareInformation key. This information is used by the control panel's display applet. See Setting Hardware Information in the Registry for details.

Depending on the adapter and the AdapterInterfaceType value in VIDEO_PORT_CONFIG_INFO, HwVidFindAdapter can call some of the following VideoPort Xxx functions to get the necessary bus-relative configuration data and mapped access ranges to communicate with the adapter:

  • VideoPortGetBusData to get bus-type-specific configuration information about an adapter on a particular I/O bus
  • VideoPortGetDeviceData to get VIDEO_DEVICE_DATA_TYPE-specific information from the registry and call HwVidQueryDeviceCallback to process this information.
  • VideoPortGetRegistryParameters to get configuration information from the registry.
  • VideoPortGetAccessRanges to get bus-relative access ranges addresses and possibly other hardware configuration values, and to claim them in the registry for use by the driver of an adapter.
  • VideoPortVerifyAccessRanges to determine whether bus-relative video memory and/or I/O ports for the adapter can be claimed by the miniport driver; otherwise, a previously loaded driver has already claimed the resource in the registry and HwVidFindAdapter must try to claim other access ranges if possible or fail.
  • VideoPortGetDeviceBase to map each successfully claimed bus-relative base address and range size, as described in a VIDEO_ACCESS_RANGE structure, to system-space logical addresses. HwVidFindAdapter must successfully call VideoPortVerifyAccessRanges or VideoPortGetAccessRanges before it can call VideoPortGetDeviceBase.

If the driver does not handle interrupts, HwVidFindAdapter should set both BusInterruptLevel and BusInterruptVector in the VIDEO_PORT_CONFIG_INFO structure to zero after its call to VideoPortGetAccessRanges. If both members are zero, the video port driver does not connect the interrupt for the miniport driver. Explicitly setting both BusInterruptLevel and BusInterruptVector to zero in HwVidFindAdapter disables the HwVidInterrupt entry point, if any, that was set up by the miniport driver's DriverEntry routine.

HwVidFindAdapter must not leave an unsupported adapter with its state changed. For VGA/SVGA adapters, HwVidFindAdapter must leave the adapter in a VGA state and restore any extended registers it might have modified to their original condition.

HwVidFindAdapter should be made pageable.

See Also

DriverEntry, DrvAssertMode, HwVidQueryDeviceCallback, HwVidQueryNamedValueCallback, VIDEO_HW_INITIALIZATION_DATA, VIDEO_PORT_CONFIG_INFO, VideoPortFreeDeviceBase, VideoPortGetAccessRanges, VideoPortGetBusData, VideoPortGetDeviceBase, VideoPortGetDeviceData, VideoPortGetRegistryParameters, VideoPortVerifyAccessRanges


HwVidGetPowerState

HwVidGetPowerState queries whether the device can support the requested power state.

VP_STATUS
  (*PVIDEO_HW_POWER_GET)(
    PVOID  HwDeviceExtension,
    ULONG  HwId,
    PVIDEO_POWER_MANAGEMENT  VideoPowerControl
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-adapter storage area.
HwId
Points to a 32-bit number that uniquely identifies the device that the miniport driver should query. This parameter is returned by the miniport driver's HwVidGetVideoChildDescriptor function. A value of DISPLAY_ADAPTER_HW_ID indicates that power information is being requested of the adapter itself.
VideoPowerControl
Points to a VIDEO_POWER_MANAGEMENT structure that specifies the power state for which support is being queried.

Return Value

HwVidGetPowerState returns one of the following values:

NO_ERROR
The device supports the requested power state.
ERROR_DEVICE_REINITIALIZATION_NEEDED
The driver failed the power state query.

Headers

Declared in video.h. Include video.h.

Comments

HwVidGetPowerState is a required function in a video miniport driver.

The driver should check the ID specified in HwId to determine which device to query. The driver should then determine whether that device supports the power state specified in the PowerState member of the VIDEO_POWER_MANAGEMENT structure to which VideoPowerControl points.

This function must not return the current power state of the device.

HwVidGetPowerState should be made pageable.

See Also

HwVidGetVideoChildDescriptor, HwVidSetPowerState, VIDEO_POWER_MANAGEMENT


HwVidGetVideoChildDescriptor

HwVidGetVideoChildDescriptor enumerates the child devices attached to the specified device.

VP_STATUS
  (*PVIDEO_HW_GET_CHILD_DESCRIPTOR)(
    IN PVOID  HwDeviceExtension,
    IN PVIDEO_CHILD_ENUM_INFO  ChildEnumInfo,
    OUT PVIDEO_CHILD_TYPE  VideoChildType,
    OUT PUCHAR  pChildDescriptor,
    OUT PULONG  UId,
    OUT PULONG  pUnused
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-adapter storage area.
ChildEnumInfo
Is a VIDEO_CHILD_ENUM_INFO structure that describes the device being enumerated.
VideoChildType
Points to a location in which the miniport driver returns the type of child being enumerated. This member can be one of the following from the VIDEO_CHILD_TYPE enumeration:
Value | Meaning
Monitor The child device is a monitor.

If the miniport driver detects that the monitor has a DDC2-compliant EDID structure associated with it, the miniport driver should extract the EDID information from the monitor and return it in the buffer to which pChildDescriptor points. The miniport driver can more easily obtain the EDID from the monitor by calling VideoPortDDCMonitorHelper.

If the detected monitor is not DDC2-compliant, the miniport driver should not return anything in pChildDescriptor.
NonPrimaryChip | Is reserved for system use.
VideoChip The child device is the graphics chip.

The miniport driver should return this type when ChildEnumInfo.ChildIndex is DISPLAY_ADAPTER_HW_ID. The miniport driver should not return anything in pChildDescriptor.
Other The child device has a separate device driver associated with it.

The miniport driver should return the device's PnP hardware identifier as a Unicode string in the buffer to which pChildDescriptor points. This string must match the device ID specified in the driver's INF file. It will be used by the operating system as the hardware ID for this device.

pChildDescriptor
Points to a buffer in which the miniport driver can return data that identifies the device. The information returned depends on the child type specified in VideoChildType. The size of this buffer is specified by the video port driver in the ChildDescriptorSize member of VIDEO_CHILD_ENUM_INFO.
UId
Points to the location in which the miniport driver returns a unique 32-bit identifier for this device. The miniport driver should set UId to be DISPLAY_ADAPTER_HW_ID when the device is the actual display adapter.
pUnused
Is unused and must be set to zero.

Return Value

HwVidGetVideoChildDescriptor returns one of the following values:

Value | Meaning
VIDEO_ENUM_INVALID_DEVICE | Call again. The miniport driver could not enumerate the child device identified in ChildEnumInfo but there are more devices to be enumerated.
VIDEO_ENUM_MORE_DEVICES | A new child device is enumerated. The video port will call HwVidGetVideoChildDescriptor again in this case.
VIDEO_ENUM_NO_MORE_DEVICES | The miniport driver could not enumerate the child device identified in ChildEnumInfo. Stop enumeration. There are no more devices to be enumerated.

Headers

Declared in video.h. Include video.h.

Comments

By default, HwVidGetVideoChildDescriptor is not called until after the device is started by HwVidFindAdapter. To allow the enumeration of a device's children before the device is started, set the AllowEarlyEnumeration member of VIDEO_HW_INITIALIZATION_DATA. When AllowEarlyEnumeration is set, HwVidGetVideoChildDescriptor can be called at any time.

HwVidGetVideoChildDescriptor should do the following:

  • Determine the type of the child device based on the data supplied in ChildEnumInfo, and return this type in VideoChildType.
  • Fill in the buffer to which pChildDescriptor points with the appropriate data, depending on the value of VideoChildType.
  • Write a 32-bit value in UId that uniquely identifies the child device being enumerated. The video port driver will pass this handle back to the miniport driver for operations such as power management.

HwVidGetVideoChildDescriptor should be made pageable.

VIDEO_CHILD_ENUM_INFO

The VIDEO_CHILD_ENUM_INFO structure describes the child device to be enumerated by the miniport driver. All members are set by the video port driver.

typedef _VIDEO_CHILD_ENUM_INFO {
  ULONG  Size;
  ULONG  ChildDescriptorSize;
  ULONG  ChildIndex;
  ULONG  ACPIHwId;
  PVOID  ChildHwDeviceExtension;
} VIDEO_CHILD_ENUM_INFO, *PVIDEO_CHILD_ENUM_INFO;

Members

Size
Is the size in bytes of this VIDEO_CHILD_ENUM_INFO structure.
ChildDescriptorSize
Is the size in bytes of the buffer to which pChildDescriptor points. The video port driver allocates this buffer to be large enough to accommodate a DDC2-compliant EDID structure.
ChildIndex
Is the index of the child device for which the system is requesting information. This member is used to enumerate devices that are not enumerated by ACPI or other operating system components. If ChildIndex is set to zero, the driver should use the value specified in ACPIHwId as the ID of the device being enumerated.
ACPIHwId
Is the identifier returned by the ACPI BIOS that represents the child device being enumerated. The miniport driver should use this member only if ChildIndex is zero.

The ACPIHwId returned by the firmware must match the value returned in UId by the miniport driver. The System BIOS manufacturer and the graphics IHV must synchronize these IDs.

ChildHwDeviceExtension
Points to a device extension specific to this child device. This member is valid only if the miniport driver filled the ChildHwDeviceExtensionSize member of VIDEO_HW_INITIALIZATION_DATA with a value other than zero.

See Also

HwVidGetPowerState, HwVidSetPowerState, VideoPortDDCMonitorHelper, VideoPortEnumerateChildren


HwVidInitialize

HwVidInitialize performs the first initialization of the adapter, after the HAL has given up control of the video hardware to the video port driver.

BOOLEAN
  (*PVIDEO_HW_INITIALIZE)(
    PVOID  HwDeviceExtension
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-adapter storage area.

Return Value

If the initialization succeeds, HwVidInitialize returns TRUE.

Headers

Declared in video.h. Include video.h.

Comments

Every video miniport driver must have a HwVidInitialize function.

The video port driver calls HwVidInitialize in response to an open request by the corresponding display driver. As soon as HwVidInitialize is called, the miniport driver can change the state of the adapter, unlike the miniport driver's HwVidFindAdapter function, which must leave the adapter in VGA mode. On return from HwVidInitialize, the adapter must be initialized to a state equivalent to that set up by the miniport driver's HwVidResetHw function. This feature is used by autodetection to get mode information from the miniport driver.

If at all possible, HwVidInitialize should avoid programming the device hardware. The miniport driver will initialize the device later, when it is instructed to switch display modes.

HwVidInitialize should be made pageable.

See Also

HwVidFindAdapter, HwVidResetHw, DrvAssertMode


HwVidInterrupt

HwVidInterrupt detects and dismisses interrupts generated by the associated video adapter.

BOOLEAN
  (*PVIDEO_HW_INTERRUPT)(
    PVOID  HwDeviceExtension
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-adapter storage area.

Return Value

If HwVidInterrupt determines that its associated hardware did not generate the interrupt, it returns FALSE. Otherwise, it must dismiss the interrupt on its adapter before it returns TRUE.

Headers

Declared in video.h. Include video.h.

Comments

A miniport driver must implement HwVidInterrupt if its video adapter generates interrupts.

First, HwVidInterrupt should determine whether its adapter actually caused the interrupt. If not, this function should return FALSE immediately so the ISR of the device that caused the interrupt will be called promptly.

Otherwise, HwVidInterrupt is generally responsible for completing the I/O operation that caused the interrupt, and should do the following:

  • Dismiss the interrupt on the adapter (required).
  • Complete the requested operation that caused the interrupt.
  • Return control as quickly as possible (required).

If a miniport driver has an HwVidInterrupt function, no register or memory location that can be accessed by HwVidInterrupt can be visible to the corresponding display driver. An interrupt can occur while the display driver is modifying one of the registers or memory locations involved, and there is no way to ensure synchronization. Therefore, all functions requiring access to the critical registers or memory locations for interrupt-driven operations must be in the miniport driver.

If any other miniport driver function shares memory, such as part of the HwDeviceExtension, with HwVidInterrupt, it must call VideoPortSynchronizeExecution to synchronize its access to the shared area.

HwVidInterrupt can call only the following system-supplied VideoPort Xxx routines:

  • VideoPortEnableInterrupt and VideoPortDisableInterrupt
  • VideoPortZeroDeviceMemory and VideoPortZeroMemory
  • VideoPortLogError
  • VideoPortStallExecution for no more than a very few microseconds. If possible, HwVidInterrupt should avoid calling this function.
  • All VideoPortRead Xxx and VideoPortWrite Xxx routines.

HwVidInterrupt must not call any VideoPort Xxx function that is not in the preceding list. Violation of this requirement will cause system failure (a "blue screen").

A HwVidInterrupt function cannot be pageable, nor can any function that it calls.

See Also

HwVidSynchronizeExecutionCallback, VideoPortDisableInterrupt, VideoPortEnableInterrupt, VideoPortLogError, VideoPortRead Xxx, VideoPortStallExecution, VideoPortSynchronizeExecution, VideoPortWrite Xxx, VideoPortZeroDeviceMemory, VideoPortZeroMemory


HwVidLegacyResources

HwVidLegacyResources returns a list of resources that are not listed in a device's PCI configuration space but that are decoded by the device.

VOID
  (*PVIDEO_HW_LEGACYRESOURCES)(
    IN ULONG  VendorId,
    IN ULONG  DeviceId,
    IN OUT PVIDEO_ACCESS_RANGE  *LegacyResourceList,
    IN OUT PULONG  LegacyResourceCount
    );

Parameters

VendorId
Specifies a code that identifies the device's vendor. This is the vendor ID specified in the device's PCI configuration space.
DeviceId
Specifies a code that identifies the particular device. This is the device ID specified in the device's PCI configuration space.
LegacyResourceList
Points to an array of VIDEO_ACCESS_RANGE structures. Each structure describes a device I/O port or memory range for the graphics adapter that is not listed in PCI configuration space.
LegacyResourceCount
Is the number of elements in the array to which LegacyResourceList points.

Headers

Declared in video.h. Include video.h.

Comments

Legacy resources are those resources that are not listed in the device's PCI configuration space but that are decoded by the device. If the legacy resource list for the device is not known at compile time, a miniport driver should implement a HwVidLegacyResources function and initialize the HwGetLegacyResources member of VIDEO_HW_INITIALIZATION_DATA to point to this function. For example, a miniport driver that supports two devices with different sets of legacy resources would implement HwVidLegacyResources to report the legacy resources for a particular device at run time.

The resources returned by HwVidLegacyResources are added to the list of resources that PnP reserves for the device.

See Also

VIDEO_HW_INITIALIZATION_DATA


HwVidQueryDeviceCallback

HwVidQueryDeviceCallback uses the specified configuration data to configure its adapter, and, possibly, to fill in missing configuration information in the VIDEO_PORT_CONFIG_INFO structure.

VP_STATUS
  (*PMINIPORT_QUERY_DEVICE_ROUTINE)(
    PVOID  HwDeviceExtension,
    PVOID  Context,
    VIDEO_DEVICE_DATA_TYPE  DeviceDataType,
    PVOID  Identifier,
    ULONG  IdentifierLength,
    PVOID  ConfigurationData,
    ULONG  ConfigurationDataLength,
    PVOID  ComponentInformation,
    ULONG  ComponentInformationLength
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-adapter storage area.
Context
Points to the context value set up by HwVidFindAdapter. Usually, it points to the VIDEO_PORT_CONFIG_INFO buffer or to an offset in that buffer.
DeviceDataType
Specifies the type of configuration information that was requested, which is usually one of the following:

VpBusData
VpControllerData
VpMonitorData

The VpControllerData and VpMonitorData values have meaning only on ARC-compliant platforms. Miniport drivers of x86-type video adapters usually specify VpBusData, particularly for adapters on EISA buses.

Identifier
Points to the name of the device as determined by the ARC firmware. This parameter should be used only on ARC-compliant platforms. Otherwise, this pointer should be NULL.
IdentifierLength
Specifies the size in bytes of the buffered Identifier string. The value should be zero if the machine is not ARC-compliant.
ConfigurationData
Points to hardware configuration data. The format of this data is determined by the specified DeviceDataType and by the AdapterInterfaceType value in the VIDEO_PORT_CONFIG_INFO.
ConfigurationDataLength
Specifies the size in bytes of the ConfigurationData buffer. In effect, this indicates how much information was collected from the registry and stored in the ConfigurationData buffer allocated by VideoPortGetDeviceBase.
ComponentInformation
Is reserved for system use.
ComponentInformationLength
Is reserved for system use.

Return Value

HwVidQueryDeviceCallback returns the status of the operation.

Headers

Declared in video.h. Include video.h.

Comments

HwVidQueryDeviceCallback is passed in a call to VideoPortGetDeviceData from the miniport driver's HwVidFindAdapter function. VideoPortGetDeviceData calls HwVidQueryDeviceCallback after collecting available configuration information under the \Registry\Machine\Hardware\Description node of the registry.

HwVidQueryDeviceCallback examines the ConfigurationData, collected from the registry by VideoPortGetDeviceData. It uses this information to configure its adapter, and, possibly, to fill in missing configuration information in the VIDEO_PORT_CONFIG_INFO structure.

HwVidQueryDeviceCallback cannot pass access range values found in the ConfigurationData to any VideoPortRead Xxx or VideoPortWrite Xxx directly; such addresses first must be mapped by calling VideoPortGetDeviceBase.

If the ConfigurationData buffer has no access range information and the miniport driver's HwVidFindAdapter function has not already called VideoPortGetBusData (or VideoPortGetAccessRanges), its HwVidQueryDeviceCallback function can call VideoPortGetBusData. Access range information returned by VideoPortGetBusData also must be passed to VideoPortVerifyAccessRanges.

If VideoPortVerifyAccessRanges returns NO_ERROR, the miniport driver can call VideoPortGetDeviceBase to obtain mapped logical addresses that it can use to communicate with the adapter by calling the VideoPortRead Xxx and/or VideoPortWrite Xxx functions.

If it cannot get bus-relative access ranges values by calling VideoPortGetDeviceData, VideoPortGetBusData, or VideoPortGetAccessRanges, a miniport driver can use a set of driver-supplied default access-range values to find its adapter. In these circumstances, the miniport driver must call VideoPortVerifyAccessRanges with the miniport driver-supplied access ranges, and, then call VideoPortGetDeviceBase only if VideoPortVerifyAccessRanges returned NO_ERROR. If a call to VideoPortVerifyAccessRanges is unsuccessful, a given bus-relative range is already in use by the driver of another device.

HwVidQueryDeviceCallback should be made pageable.

See Also

VideoPortGetAccessRanges, VideoPortGetBusData, VideoPortGetDeviceBase, VideoPortGetDeviceData, VideoPortVerifyAccessRanges


HwVidQueryInterface

HwVidQueryInterface returns a miniport driver-implemented functional interface that a child device can call.

VP_STATUS
  (*PVIDEO_HW_QUERY_INTERFACE)(
    PVOID  HwDeviceExtension,
    PQUERY_INTERFACE  QueryInterface
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-adapter storage area.
QueryInterface
Points to a QUERY_INTERFACE structure in which the miniport driver should return information about the interface it supports.

Return Value

HwVidQueryInterface should return NO_ERROR upon success; otherwise it should return the appropriate error code. For example, a miniport driver should return ERROR_OUTOFMEMORY if it cannot allocate memory to complete the operation.

Headers

Declared in video.h. Include video.h.

Comments

HwVidQueryInterface exposes a communication mechanism between the video miniport driver and the driver of a child device. A miniport driver wishing to expose such a mechanism should implement this function.

The video port calls HwVidQueryInterface when it receives an IRP_MN_QUERY_INTERFACE request. If the miniport driver fails the call, the video port driver passes the request to the parent of the miniport driver's device.

HwVidQueryInterface should fill in the members of the INTERFACE structure to which QueryInterface->Interface points as follows:

  • Set Size to the number of bytes in the INTERFACE structure. This value must not exceed the number of bytes specified by QueryInterface->Size.
  • Set Version to the version of the interface being returned by the miniport driver. The miniport driver should best match the version requested by the child driver in QueryInterface->Version.
  • Set Context to point to a miniport driver-defined context for the interface. Typically, a miniport driver would set Context to point to the device extension identified by HwDeviceExtension.
  • Initialize InterfaceReference and InterfaceDereference to point to the miniport driver-implemented reference and dereference routines for this interface.
  • Initialize all additional interface-specific members to point to the appropriate routines of the interface being exposed.

A miniport driver that returns an interface is responsible for referencing the interface by calling QueryInterface->Interface.InterfaceReference. The child driver requesting the interface is responsible for dereferencing it when the driver no longer requires the interface by calling QueryInterface->Interface.InterfaceDereference. If the child driver passes the interface to another component, the child is responsible for taking out another reference, and the other component is responsible for removing the additional reference when it no longer needs access to the interface. Referencing allows a parent to determine when the interface is still required by the child device, and consequently when the parent can free any interface-associated resources.

The driver of a child device can call into the miniport driver through the functions exposed by HwVidQueryInterface at any time without the video port driver's knowledge. Consequently, the miniport driver must synchronize access to itself by acquiring and releasing the video port driver-maintained device lock in all of the functions exposed by HwVidQueryInterface.

A child device is enumerated by HwVidGetVideoChildDescriptor.

HwVidQueryInterface should be made pageable.

QUERY_INTERFACE

The QUERY_INTERFACE structure describes the interface being requested.

typedef struct _QUERY_INTERFACE {
  CONST GUID  *InterfaceType;
  USHORT  Size;
  USHORT  Version;
  PINTERFACE  Interface;
  PVOID  InterfaceSpecificData;
} QUERY_INTERFACE, *PQUERY_INTERFACE;

Members

InterfaceType
Points to a GUID that identifies the interface being requested. If the miniport driver does not support the specified InterfaceType, it should fail the call and return immediately.

The parent generates this GUID with uuidgen.exe. See Defining and Exporting New GUIDs for details.

Size
Specifies the size in bytes of the INTERFACE structure to which Interface points. The miniport driver must not return an INTERFACE structure larger than Size bytes.
Version
Specifies the version of the interface being requested.

If a parent supports more than one version of an interface, its driver should return the specified version or, if possible, the closest supported version without exceeding the requested version. It is the querying driver's responsibility to examine the returned Version and determine what to do based on that value.

Interface
Points to an INTERFACE structure in which the miniport driver returns the requested interface information. The querying driver is responsible for allocating this structure before calling HwVidQueryInterface.
InterfaceSpecificData
Specifies additional information about the interface being requested. Typically, this member is NULL, and the InterfaceType and Version members are sufficient for the parent to identify the interface being requested.

See Also

HwVidGetVideoChildDescriptor, VideoPortAcquireDeviceLock, VideoPortReleaseDeviceLock


HwVidQueryNamedValueCallback

HwVidQueryNamedValueCallback processes the specified data retrieved from the registry.

VP_STATUS
  (*PMINIPORT_GET_REGISTRY_ROUTINE)(
    PVOID  HwDeviceExtension,
    PVOID  Context,
    PWSTR  ValueName,
    PVOID  ValueData,
    ULONG  ValueLength
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-adapter storage area.
Context
Points to a driver-determined context to be passed to the callback routine. Usually, it points to a location on the stack at which the value data should be stored.
ValueName
Points to a zero-terminated Unicode string naming the entry.
ValueData
Points to the buffered data associated with ValueName, supplied by VideoPortGetRegistryParameters.
ValueLength
Specifies the size in bytes of the buffer at ValueData.

Return Value

HwVidQueryNamedValueCallback returns the status of the operation.

Headers

Declared in video.h. Include video.h.

Comments

HwVidQueryNamedValueCallback is an optional miniport driver function passed in a call to VideoPortGetRegistryParameters.

VideoPortGetRegistryParameters calls HwVidQueryNamedValueCallback after collecting available configuration information about the given ValueName in the adapter key of the registry.

HwVidFindAdapter or HwVidInitialize can call VideoPortGetRegistryParameters with a driver-supplied HwVidQueryNamedValueCallback function, pointers to the device extension and any driver-supplied context data (which can be the VIDEO_PORT_CONFIG_INFO buffer), and a pointer to a Unicode string naming the value to be retrieved from the registry.

HwVidFindAdapter or HwVidInitialize can set VideoPortGetRegistryParameters's IsFileNameParameter argument to TRUE if the driver-supplied Unicode string is a named registry entry whose value is a file name. For this specification, the returned data will be the contents of the named file.

When VideoPortGetRegistryParameters calls the HwVidQueryNamedValueCallback function, it processes whatever configuration data is made available. For example, HwVidQueryNamedValueCallback might use retrieved data to determine the miniport driver's access ranges and to set up its emulator access ranges (if any), interrupt vector or interrupt IRQL (if any), and so forth in the VIDEO_PORT_CONFIG_INFO buffer, as well as in the miniport driver's device extension, before returning control to the HwVidFindAdapter function.

HwVidInitialize might also call VideoPortGetRegistryParameters with IsFileNameParameter set to TRUE so that the miniport driver-supplied HwVidQueryNamedValueCallback function could use the buffered contents of a named file to set up microcode on the adapter.

The returned ValueData is on the stack, so it can be referenced locally. HwVidQueryNamedValueCallback can store some or all of the returned information for use by other miniport driver functions in the input HwDeviceExtension or use the input Context as a pointer to a location where the data can be stored.

HwVidQueryNamedValueCallback should be made pageable.

See Also

HwVidFindAdapter, VideoPortGetRegistryParameters, VideoPortSetRegistryParameters


HwVidResetHw

HwVidResetHw resets the adapter to character mode.

BOOLEAN
  (*PVIDEO_HW_RESET_HW)(
    PVOID  HwDeviceExtension,
    ULONG  Columns,
    ULONG  Rows
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-adapter storage area.
Columns
Specifies the number of columns of the mode to be set up.
Rows
Specifies the number of rows of the mode to be set up.

Return Value

HwVidResetHw should return TRUE if it completely resets the adapter to the given character mode. Otherwise, it should return FALSE to indicate that the HAL should perform the equivalent of an INT10, MODE3-type BIOS call after HwVidResetHw returns control.

Headers

Declared in video.h. Include video.h.

Comments

A video miniport driver must have a HwVidResetHw function if its adapter cannot be reset to a fully initialized state without a hard boot of the machine. For example, if the adapter's ROM initialization code cannot reset the adapter state to a boot-up mode, the miniport driver must have a HwVidResetHw function. Another reason the miniport driver must implement this function is to clean up the adapter's interrupt lines when the adapter is powered down, thereby avoiding a deluge of interrupts the next time the system boots.

The HAL calls HwVidResetHw if the system is about to crash, so that the HAL can display information on the screen while the system is being shut down. The HAL also calls HwVidResetHw just before the machine is rebooted when a soft boot occurs.

Most miniport drivers must provide this function, except for drivers of adapters that are reset to a VGA standard character mode on receipt of an INT10, MODE3-type command.

HwVidResetHw resets the adapter to character mode, according to the given Columns and Rows values. However, because the system is shutting down, HwVidResetHw cannot call the BIOS or any pageable code. HwVidResetHw should call only the VideoPortRead/WritePort Xxx and/or VideoPortRead/WriteRegister Xxx functions.

If HwVidResetHw cannot change the mode of the adapter by simply programming the adapter registers, it can set up the appropriate values in adapter registers and return FALSE. This causes the HAL to perform an extended INT10-type operation to reset the video adapter to character mode.

HwVidResetHw must not call VideoPortInt10. A miniport driver's HwVidStartIO function is called with the IOCTL_VIDEO_RESET_DEVICE VRP to reset the adapter whenever the Display applet is used to test or change the graphics display mode, not the miniport driver's HwVidResetHw function.

HwVidResetHw must not be made pageable.

See Also

HwVidInitialize, HwVidStartIO, IOCTL_VIDEO_RESET_DEVICE, VideoPortInt10, VideoPortRead Xxx, VideoPortWrite Xxx


HwVidSetPowerState

HwVidSetPowerState sets the power state of the specified device.

VP_STATUS
  (*PVIDEO_HW_POWER_SET)(
    PVOID  HwDeviceExtension,
    ULONG  HwId,
    PVIDEO_POWER_MANAGEMENT  VideoPowerControl
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-adapter storage area.
HwId
Points to a 32-bit number that uniquely identifies the device for which the miniport driver should set the power state. This parameter is the value returned by the miniport driver's HwVidGetVideoChildDescriptor function. A value of DISPLAY_ADAPTER_HW_ID indicates that the miniport driver should set the power state of the adapter itself.
VideoPowerControl
Points to a VIDEO_POWER_MANAGEMENT structure that specifies the power state to be set.

Return Value

HwVidSetPowerState should always return NO_ERROR.

Headers

Declared in video.h. Include video.h.

Comments

HwVidSetPowerState is a required function in a video miniport driver.

The driver should check the ID specified in HwId to determine the device on which to set the power state. The driver should then set that device's power state to the level specified in the PowerState member of the VIDEO_POWER_MANAGEMENT structure to which VideoPowerControl points.

HwVidSetPowerState should be made pageable.

See Also

HwVidGetVideoChildDescriptor, HwVidGetPowerState, VIDEO_POWER_MANAGEMENT


HwVidStartIO

HwVidStartIO processes the specified VRP.

BOOLEAN
  (*PVIDEO_HW_START_IO)(
    PVOID  HwDeviceExtension,
    PVIDEO_REQUEST_PACKET  RequestPacket
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-adapter storage area.
RequestPacket
Points to a VIDEO_REQUEST_PACKET structure, which contains all the parameters originally passed to EngDeviceIoControl.

Return Value

HwVidStartIO must return TRUE, indicating that it has completed the request.

Headers

Declared in video.h. Include video.h.

Comments

Every video miniport driver must have a HwVidStartIO function.

The video port driver calls HwVidStartIO in response to each GDI EngDeviceIoControl request, which originates in the corresponding display driver. When HwVidStartIO is called, the miniport driver owns the input video request packet until it completes the requested operation. HwVidStartIO must do the following:

  1. Look at the IoControlCode member of the VRP to determine the operation being requested by the display driver.
  2. Check that the VRP InputBufferLength and/or OutputBufferLength indicates a buffer that is large enough to satisfy the request. The miniport driver should return an error if either buffer is too small.
  3. Satisfy the request.
  4. Set the Status and Information members in the VRP and return TRUE.

The system video port driver serializes all requests. A miniport driver need not perform any serialization of its own unless it has a HwVidInterrupt function.

However, every miniport driver's HwVidStartIO function must complete each requested operation or set an appropriate error in the VRP's StatusBlock before it returns control.

HwVidStartIO should be made pageable.

See Also

IOCTL_VIDEO_XXX, VIDEO_REQUEST_PACKET, VideoPortSynchronizeExecution


HwVidSynchronizeExecutionCallback

HwVidSynchronizeExecutionCallback is an optional miniport driver function, passed in calls to VideoPortSynchronizeExecution.

BOOLEAN
  (*PMINIPORT_SYNCHRONIZE_ROUTINE)(
    IN PVOID  Context
    );

Parameters

Context
Points to context data passed to the callback routine through VideoPortSynchronizeExecution. Usually, this is a pointer to the device extension or an offset within the device extension.

Return Value

If the operation succeeds, HwVidSynchronizeExecutionCallback returns TRUE.

Headers

Declared in video.h. Include video.h.

Comments

A miniport driver with one or more functions that share memory with its HwVidInterrupt function must have a HwVidSynchronizeExecutionCallback function. Any function that shares memory with HwVidInterrupt must call VideoPortSynchronizeExecution with the HwVidSynchronizeExecutionCallback to maintain the integrity of data in the shared memory area. That is, only one of the HwVidSynchronizeExecutionCallback and HwInterrupt functions can update state in the shared area at any given moment.

The miniport driver of an adapter that does not generate interrupts also can have an HwVidSynchronizeExecutionCallback function to be passed to VideoPortSynchronizeExecution when such a driver needs to get some critical work done at a relatively high runtime priority. For example, VGA-compatible miniport drivers with SvgaHwIoPort Xxx functions might have a HwVidSynchronizeExecutionCallback that is responsible for transferring driver-buffered and validated application-issued I/O to the adapter.

HwVidSynchronizeExecutionCallback must not be made pageable.

See Also

HwVidInterrupt, SvgaHwIoPort Xxx, VideoPortSynchronizeExecution


HwVidTimer

HwVidTimer is a video miniport driver routine called at timed intervals by the video port driver.

VOID
  (*PVIDEO_HW_TIMER)(
    PVOID  HwDeviceExtension
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-adapter storage area.

Headers

Declared in video.h. Include video.h.

Comments

HwVidTimer is an optional miniport driver function to which calls are enabled and disabled with VideoPortStartTimer and VideoPortStopTimer, respectively.

Any miniport driver can have a HwVidTimer function at the discretion of the driver designer. For example, a HwVidTimer function could be used to read the state of the "VGA" registers on a high-end video adapter so that the miniport driver can emulate VGA-compatible behavior on an as-needed basis.

After a call to VideoPortStartTimer, the video port driver calls a miniport driver's HwVidTimer function approximately once each second until the miniport driver calls VideoPortStopTimer.

The HwVidTimer function can disable the timer with a call to VideoPortStopTimer. Another miniport driver function can re-enable the timer later with a call to VideoPortStartTimer.

HwVidTimer must not be made pageable.

See Also

VideoPortStartTimer, VideoPortStopTimer


PMINIPORT_DPC_ROUTINE

PMINIPORT_DPC_ROUTINE is a miniport driver-implemented callback that is called when a queued DPC gets scheduled.

VOID
  (*PMINIPORT_DPC_ROUTINE)(
    IN PVOID  HwDeviceExtension,
    IN PVOID  Context
    );

Parameters

HwDeviceExtension
Points to the miniport driver's hardware device extension.
Context
Contains any miniport driver-supplied data this function may need. Context can be NULL if the DPC implementation does not require additional information.

Headers

Declared in video.h. Include video.h.

Comments

The miniport driver queues this DPC by calling VideoPortQueueDpc.

Because PMINIPORT_DPC_ROUTINE is called at DPC level, it must not manipulate any pageable code or data. Further, this function must be in nonpaged memory and should complete its operations as quickly as possible.

See Also

VideoPortQueueDpc


SvgaHwIoPortUchar

SvgaHwIoPortUchar traps an I/O port to which a full-screen MS-DOS® application in an x86-based machine is sending UCHAR-sized data.

VP_STATUS
  (*PDRIVER_IO_PORT_UCHAR)(
    ULONG_PTR  Context,
    ULONG  Port,
    UCHAR  AccessMode,
    PUCHAR  Data
    );

Parameters

Context
Specifies the miniport driver-defined context value that was set in the EmulatorAccessEntriesContext member of VIDEO_PORT_CONFIG_INFO.
Port
Specifies the mapped I/O port to be trapped.
AccessMode
Specifies the type of access to be trapped, which can be one or a combination (ORed) of the following values:

EMULATOR_READ_ACCESS
EMULATOR_WRITE_ACCESS

Data
Points to the byte to be transferred.

Return Value

SvgaHwIoPortUchar returns the final status of the operation.

Headers

Declared in video.h. Include video.h.

Comments

Only miniport drivers of VGA-compatible SVGA adapters have SvgaHwIoPort Xxx functions.

SvgaHwIoPortUchar intercepts any byte access attempted by a full-screen MS-DOS application issuing either or both of the instructions OUT DX, AL and IN AL, DX.

If the miniport driver enables the Port for direct access by calling VideoPortSetTrappedEmulatorPorts, its SvgaHwIoPortUchar function will not be called. Such an application then will have direct access to the Port, unless the miniport driver disables the Port with another call to VideoPortSetTrappedEmulatorPorts.

If any application-issued x86 IN or OUT instruction(s) might affect the state of the VGA-compatible adapter sequencer register, miscellaneous output register, or any adapter-specific register and, thereby, cause the machine to hang, the miniport driver must not enable the port for direct access by calling VideoPortSetTrappedEmulatorPorts.

SvgaHwIoPortUchar must buffer subsequent instructions from the application to the Port and check that none can hang the machine. If the application issues any sequence of instructions that might hang the machine, SvgaHwIoPortUchar must discard the buffered instructions. Otherwise, it should output them, a UCHAR at a time, to the specified, mapped I/O port.

See Also

EMULATOR_ACCESS_ENTRY, SvgaHwIoPortUcharString, VIDEO_ACCESS_RANGE, VIDEO_PORT_CONFIG_INFO, VideoPortGetDeviceBase, VideoPortSetTrappedEmulatorPorts


SvgaHwIoPortUcharString

SvgaHwIoPortUcharString traps an I/O port to which a full-screen MS-DOS application in an x86-based machine is sending a sequence of UCHAR-sized data.

VP_STATUS
  (*PDRIVER_IO_PORT_UCHAR_STRING)(
    ULONG_PTR  Context,
    ULONG  Port,
    UCHAR  AccessMode,
    PUCHAR  Data,
    ULONG  DataLength
    );

Parameters

Context
Specifies the miniport driver-determined context value that was set in the EmulatorAccessEntriesContext member of VIDEO_PORT_CONFIG_INFO.
Port
Specifies the mapped I/O port.
AccessMode
Specifies the type of access allowed, which can be one or a combination (ORed) of the following values:

EMULATOR_READ_ACCESS
EMULATOR_WRITE_ACCESS

Data
Points to the UCHAR string to be transferred. One character at a time is hooked out until the whole string is transferred.
DataLength
Specifies the number of UCHAR values in the string.

Return Value

SvgaHwIoPortUcharString returns the final status of the operation.

Headers

Declared in video.h. Include video.h.

Comments

Only miniport drivers of VGA-compatible SVGA adapters have SvgaHwIoPort Xxx functions.

SvgaHwIoPortUcharString will intercept any byte access attempted by a full-screen MS-DOS application issuing either or both of the instructions REP OUTSB DX, ESI and REP INSB EDI, DX.

If the miniport driver enables the Port for direct access by calling VideoSetTrappedEmulatorPorts, its SvgaHwIoPortUcharString function will not be called. Such an application then will have direct access to the I/O port, unless the miniport driver disables the port with another call to VideoSetTrappedEmulatorPorts.

If an application-issued x86 INSB or OUTSB instruction(s) might affect the state of the VGA-compatible adapter sequencer register, miscellaneous output register, or any adapter-specific register and, thereby, cause the machine to hang, the miniport driver must not enable the port for direct access by calling VideoPortSetTrappedEmulatorPorts.

SvgaHwIoPortUcharString must buffer subsequent instructions from the application and check that none can hang the machine. If the application issues any sequence of instructions that might hang the machine, SvgaHwIoPortUcharString must discard the buffered instructions. Otherwise, it should output them, a UCHAR at a time, to the specified, mapped I/O port.

See Also

EMULATOR_ACCESS_ENTRY, SvgaHwIoPortUchar, VIDEO_ACCESS_RANGE, VIDEO_PORT_CONFIG_INFO, VideoPortGetDeviceBase, VideoPortSetTrappedEmulatorPorts


SvgaHwIoPortUlong

SvgaHwIoPortUlong traps an I/O port range to which a full-screen MS-DOS application in an x86-based machine is sending a sequence of ULONG-sized data.

VP_STATUS
  (*PDRIVER_IO_PORT_ULONG)(
    ULONG_PTR  Context,
    ULONG  Port,
    UCHAR  AccessMode,
    PULONG  Data
    );

Parameters

Context
Specifies the miniport driver-determined context value that was set in the EmulatorAccessEntriesContext member of VIDEO_PORT_CONFIG_INFO.
Port
Specifies the mapped I/O port to be trapped.
AccessMode
Specifies the type of access allowed, which can be one or a combination (ORed) of the following values:

EMULATOR_READ_ACCESS
EMULATOR_WRITE_ACCESS

Data
Points to the ULONG data to be transferred.

Return Value

SvgaHwIoPortUlong returns the final status of the operation.

Headers

Declared in video.h. Include video.h.

Comments

Only miniport drivers of VGA-compatible SVGA adapters have SvgaHwIoPort Xxx functions.

SvgaHwIoPortUlong will intercept any range access attempted by a full-screen MS-DOS application issuing either or both of the instructions OUT DX, EAX and IN EAX, DX.

If the miniport driver enables the Port range for direct access by calling VideoSetTrappedEmulatorPorts, its SvgaHwIoPortUlong function will not be called. Such an application then will have direct access to the I/O port range, unless the miniport driver disables the range with another call to VideoSetTrappedEmulatorPorts.

If an application-issued x86 IN or OUT instruction(s) might affect the state of the VGA-compatible adapter sequencer register, miscellaneous output register, or any adapter-specific register and, thereby, cause the machine to hang, the miniport driver must not enable the port for direct access by calling VideoPortSetTrappedEmulatorPorts.

SvgaHwIoPortUlong must buffer subsequent instructions from the application and check that none can hang the machine. If the application issues any sequence of instructions that might hang the machine, SvgaHwIoPortUlong must discard the buffered instructions. Otherwise, it should output them, a ULONG at a time, to the specified, mapped I/O port.

See Also

EMULATOR_ACCESS_ENTRY, SvgaHwIoPortUlongString, VIDEO_ACCESS_RANGE, VIDEO_PORT_CONFIG_INFO, VideoPortGetDeviceBase, VideoPortSetTrappedEmulatorPorts


SvgaHwIoPortUlongString

SvgaHwIoPortUlongString traps an I/O port range to which a full-screen MS-DOS application in an x86-based machine is sending a sequence of ULONG-sized data.

VP_STATUS
  (*PDRIVER_IO_PORT_ULONG_STRING)(
    ULONG_PTR  Context,
    ULONG  Port,
    UCHAR  AccessMode,
    PULONG  Data,
    ULONG  DataLength
    );

Parameters

Context
Specifies the miniport driver-determined context value that was set in the EmulatorAccessEntriesContext member of VIDEO_PORT_CONFIG_INFO.
Port
Specifies the mapped I/O port to be trapped.
AccessMode
Specifies the type of access allowed, which can be one or a combination (ORed) of the following values:

EMULATOR_READ_ACCESS
EMULATOR_WRITE_ACCESS

Data
Points to the ULONG data string to be transferred. The string is hooked out one value at a time until it is all used.
DataLength
Specifies the number of ULONG values in the string.

Return Value

SvgaHwIoPortUlongString returns the final status of the operation.

Headers

Declared in video.h. Include video.h.

Comments

Only miniport drivers of VGA-compatible SVGA adapters have SvgaHwIoPort Xxx functions.

SvgaHwIoPortUlongString will intercept any range access attempted by a full-screen MS-DOS application issuing either or both of the instructions REP OUTSD DX, ESI and REP INSD EDI, DX.

If the miniport driver enables the Port range for direct access by calling VideoSetTrappedEmulatorPorts, its SvgaHwIoPortUlongString function will not be called. Such an application then will have direct access to the I/O port range, unless the miniport driver disables the Port range with another call to VideoSetTrappedEmulatorPorts.

If an application-issued x86 INSD or OUTSD instruction(s) might affect the state of the VGA-compatible adapter sequencer register, miscellaneous output register, or any adapter-specific register and, thereby, cause the machine to hang, the miniport driver must not enable the port for direct access by calling VideoPortSetTrappedEmulatorPorts.

SvgaHwIoPortUlongString must buffer subsequent instructions from the application and check that none can hang the machine. If the application issues any sequence of instructions that might hang the machine, SvgaHwIoPortUlongString must discard the buffered instructions. Otherwise, it should output them, a ULONG at a time, to the specified, mapped I/O port.

See Also

EMULATOR_ACCESS_ENTRY, SvgaHwIoPortUlong, VIDEO_ACCESS_RANGE, VIDEO_PORT_CONFIG_INFO, VideoPortGetDeviceBase, VideoPortSetTrappedEmulatorPorts


SvgaHwIoPortUshort

SvgaHwIoPortUshort traps an I/O port range to which a full-screen MS-DOS application in an x86-based machine is sending a sequence of USHORT-sized data.

VP_STATUS
  (*PDRIVER_IO_PORT_USHORT)(
    ULONG_PTR  Context,
    ULONG  Port,
    UCHAR  AccessMode,
    PUSHORT  Data
    );

Parameters

Context
Specifies the miniport driver-determined context value that was set in the EmulatorAccessEntriesContext member of VIDEO_PORT_CONFIG_INFO.
Port
Specifies the mapped I/O port to be trapped.
AccessMode
Specifies the type of access allowed, which can be one or a combination (ORed) of the following values:

EMULATOR_READ_ACCESS
EMULATOR_WRITE_ACCESS

Data
Points to the USHORT data to be transferred.

Return Value

SvgaHwIoPortUshort returns the final status of the operation.

Headers

Declared in video.h. Include video.h.

Comments

Only miniport drivers of VGA-compatible SVGA adapters have SvgaHwIoPort Xxx functions.

SvgaHwIoPortUshort will intercept any range access attempted by a full-screen MS-DOS application issuing either or both of the instructions OUT DX, AX and IN AX, DX.

If the miniport driver enables the Port range for direct access by calling VideoSetTrappedEmulatorPorts, its SvgaHwIoPortUshort function will not be called. Such an application then will have direct access to the I/O port range, unless the miniport driver disables the Port range with another call to VideoSetTrappedEmulatorPorts.

If an application-issued x86 IN or OUT instruction(s) might affect the state of the VGA-compatible adapter sequencer register, miscellaneous output register, or any adapter-specific register and, thereby, cause the machine to hang, the miniport driver must not enable the port for direct access by calling VideoPortSetTrappedEmulatorPorts.

SvgaHwIoPortUshort must buffer subsequent instructions from the application and check that none can hang the machine. If the application issues any sequence of instructions that might hang the machine, SvgaHwIoPortUshort must discard the buffered instructions. Otherwise, it should output them, a USHORT at a time, to the specified, mapped I/O port.

See Also

EMULATOR_ACCESS_ENTRY, SvgaHwIoPortUshortString, VIDEO_ACCESS_RANGE, VIDEO_PORT_CONFIG_INFO, VideoPortGetDeviceBase, VideoPortSetTrappedEmulatorPorts


SvgaHwIoPortUshortString

SvgaHwIoPortUshortString traps an I/O port range to which a full-screen MS-DOS application in an x86-based machine is sending a sequence of USHORT-sized data.

VP_STATUS
  (*PDRIVER_IO_PORT_USHORT_STRING)(
    ULONG_PTR  Context,
    ULONG  Port,
    UCHAR  AccessMode,
    PUSHORT  Data,
    ULONG  DataLength
    );

Parameters

Context
Specifies the miniport driver-determined context value that was set in EmulatorAccessEntriesContext of VIDEO_PORT_CONFIG_INFO.
Port
Specifies the mapped I/O port to be trapped.
AccessMode
Specifies the type of access allowed, which can be one or a combination (ORed) of the following values:

EMULATOR_READ_ACCESS
EMULATOR_WRITE_ACCESS

Data
Points to the string of USHORT data values to be transferred. This string is accessed one value at a time until all values have been hooked.
DataLength
Specifies the number of USHORT values in the string.

Return Value

SvgaHwIoPortUshortString returns the final status of the operation.

Headers

Declared in video.h. Include video.h.

Comments

Only miniport drivers of VGA-compatible SVGA adapters have SvgaHwIoPort Xxx functions.

SvgaHwIoPortUshortString will intercept any range access attempted by a full-screen MS-DOS application issuing either or both of the instructions REP OUTSW DX, ESI and REP INSW EDI, DX.

If the miniport driver enables the Port range for direct access by calling VideoSetTrappedEmulatorPorts, its SvgaHwIoPortUshortString function will not be called. Such an application then will have direct access to the I/O port range, unless the miniport driver disables the Port range with another call to VideoSetTrappedEmulatorPorts.

If an application-issued x86 INSW or OUTSW instruction(s) might affect the state of the VGA-compatible adapter sequencer register, miscellaneous output register, or any adapter-specific register and, thereby, cause the machine to hang, the miniport driver must not enable the port for direct access by calling VideoPortSetTrappedEmulatorPorts.

SvgaHwIoPortUshortString must buffer subsequent instructions from the application and check that none can hang the machine. If the application issues any sequence of instructions that might hang the machine, SvgaHwIoPortUshortString must discard the buffered instructions. Otherwise, it should output them, a USHORT at a time, to the specified, mapped I/O port.

See Also

EMULATOR_ACCESS_ENTRY, SvgaHwIoPortUshort, VIDEO_ACCESS_RANGE, VIDEO_PORT_CONFIG_INFO, VideoPortGetDeviceBase, VideoPortSetTrappedEmulatorPorts


Video Port Functions for Miniport Drivers

This section describes the Agp Xxx and VideoPort Xxx functions. Together, these functions comprise the video port driver, a system-supplied component called by video miniport drivers. See Video Miniport Header Files, Sample Code, and References for a list of the include files that contain declarations for these functions. References are provided in alphabetic order.


AgpCommitPhysical

AgpCommitPhysical maps system (physical) memory to the specified range of AGP-decodable physical addresses.

BOOLEAN
  (*PAGP_COMMIT_PHYSICAL)(
    IN PVOID  HwDeviceExtension,
    IN PVOID  PhysicalReserveContext,
    IN ULONG  Pages,
    IN ULONG  Offset
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
PhysicalReserveContext
Identifies a reserved physical address range. The context handle obtained from AgpReservePhysical.
Pages
Specifies the number of pages of system memory to commit.
Offset
Specifies the page offset at which to commit the pages. The offset is applied to the reserved physical address range associated with PhysicalReserveContext

Return Value

AgpCommitPhysical returns TRUE if the mapping was successful, and FALSE otherwise.

Headers

Declared in videoagp.h. Include video.h.

Comments

A video miniport driver must first reserve physical addresses by calling AgpReservePhysical before it calls this function.

When a miniport driver calls AgpCommitPhysical, Pages pages of physical memory are locked down and mapped to the AGP-decodable physical address range. This range begins Offset pages into the range identified by PhysicalReserveContext. The miniport driver can access committed physical memory as if it were contiguous.

A miniport driver must reserve and commit virtual memory before an application can use AGP-decodable physical memory.

Callers of AgpCommitPhysical must be running at IRQL = PASSIVE_LEVEL.

See Also

AgpCommitVirtual, AgpReservePhysical, AgpReserveVirtual


AgpFreePhysical

AgpFreePhysical frees system memory that was committed by a previous call to AgpCommitPhysical.

VOID
  (*PAGP_FREE_PHYSICAL)(
    IN PVOID  HwDeviceExtension,
    IN PVOID  PhysicalReserveContext,
    IN ULONG  Pages,
    IN ULONG  Offset
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
PhysicalReserveContext
Identifies a reserved physical address range. This context handle was obtained from AgpReservePhysical.
Pages
Specifies the number of pages of system memory that the video port driver should unmap.
Offset
Specifies the page offset into the reserved physical address range identified by PhysicalReserveContext that indicates the actual base address at which to unmap system memory.

Return Value

None

Headers

Declared in videoagp.h. Include video.h.

Comments

When a miniport driver calls AgpFreePhysical, Pages pages of physical memory are unlocked and unmapped from the AGP-decodable physical address range. This range begins Offset pages into the range identified by PhysicalReserveContext. The miniport must specify that the exact offset and number of pages be freed as were committed in a prior call to AgpCommitPhysical.

Callers of AgpFreePhysical must be running at IRQL = PASSIVE_LEVEL.

See Also

AgpCommitPhysical, AgpReleasePhysical


AgpFreeVirtual

AgpFreeVirtual frees virtual memory committed by a previous call to AgpCommitVirtual.

VOID
  (*PAGP_FREE_VIRTUAL)(
    IN PVOID  HwDeviceExtension,
    IN PVOID  VirtualReserveContext,
    IN ULONG  Pages,
    IN ULONG  Offset
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
VirtualReserveContext
Identifies a reserved virtual address range. This context handle was obtained from AgpReserveVirtual.
Pages
Specifies the number of pages of virtual memory that the video port driver should unmap.
Offset
Specifies the page offset into the reserved virtual address range identified by VirtualReserveContext that indicates the actual base address at which to unmap virtual memory.

Return Value

None

Headers

Declared in videoagp.h. Include video.h.

Comments

When a miniport driver calls AgpFreeVirtual, Pages pages of virtual memory are unlocked and unmapped from the AGP-decodable physical address range. This range begins Offset pages into the range associated with VirtualReserveContext. The miniport driver must specify that the exact offset and number of pages be freed as were committed in a prior call to AgpCommitVirtual.

Callers of AgpFreeVirtual must be running at IRQL = PASSIVE_LEVEL.

See Also

AgpCommitVirtual


AgpReleasePhysical

AgpReleasePhysical frees a physical address range reserved by a previous call to AgpReservePhysical.

VOID
  (*PAGP_RELEASE_PHYSICAL)(
    IN PVOID  HwDeviceExtension,
    IN PVOID  PhysicalReserveContext
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
PhysicalReserveContext
Is the context handle that identifies the reserved physical address range to be released. This context was obtained from AgpReservePhysical.

Return Value

None

Headers

Declared in videoagp.h. Include video.h.

Comments

The miniport driver must call AgpFreePhysical to unmap all committed memory within the address range identified by PhysicalReserveContext before calling AgpReleasePhysical.

Callers of AgpReleasePhysical must be running at IRQL = PASSIVE_LEVEL.

See Also

AgpFreePhysical, AgpReservePhysical


AgpReleaseVirtual

AgpReleaseVirtual frees system memory reserved by a previous call to AgpReserveVirtual.

VOID
  (*PAGP_RELEASE_VIRTUAL)(
    IN PVOID  HwDeviceExtension,
    IN PVOID  VirtualReserveContext
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
VirtualReserveContext
Is the context handle that identifies the reserved virtual address range to be released. This context was obtained from AgpReserveVirtual.

Return Value

None

Headers

Declared in videoagp.h. Include video.h.

Comments

The miniport driver must call AgpFreeVirtual to unmap all committed memory within the range identified by VirtualReserveContext before calling AgpReleaseVirtual to release it.

Callers of AgpReleaseVirtual must be running at IRQL = PASSIVE_LEVEL.

See Also

AgpFreePhysical, AgpReservePhysical


AgpReservePhysical

AgpReservePhysical reserves a range of physical addresses on the system bus to which the AGP controller can respond.

PHYSICAL_ADDRESS
  (*PAGP_RESERVE_PHYSICAL)(
    IN PVOID  HwDeviceExtension,
    IN ULONG  Pages,
    IN ULONG  Caching,
    OUT PVOID  *PhysicalReserveContext
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
Pages
Specifies the number of pages that the video port driver should reserve.
Caching
Indicates whether the system should use USWC (write-combining) caching. To enable USWC caching; the miniport driver should set this to TRUE; otherwise, it should set this to FALSE.
PhysicalReserveContext
Specifies the location in which the video port driver writes a context handle that identifies the reserved physical address space.

Return Value

AgpReservePhysical returns the base address of the reserved physical address range if successful; otherwise, it returns NULL.

Headers

Declared in videoagp.h. Include video.h.

Comments

Upon successful return, the AGP controller can respond to the reserved physical address range on the bus. However, the video miniport driver must first call AgpCommitPhysical to cause this memory to be committed before accessing it in order for the accessed results to be defined.

The miniport driver can call AgpReservePhysical several times to reserve many smaller address ranges rather than one big range.

The miniport driver should call AgpReleasePhysical to release the physical address range when it is no longer needed.

Callers of AgpReservePhysical must be running at IRQL = PASSIVE_LEVEL.

See Also

AgpCommitPhysical, AgpReleasePhysical


AgpReserveVirtual

AgpReserveVirtual reserves a range of virtual addresses for AGP.

PVOID
  (*PAGP_RESERVE_VIRTUAL)(
    IN PVOID  HwDeviceExtension,
    IN HANDLE  ProcessHandle,
    IN PVOID  PhysicalReserveContext,
    OUT PVOID  *VirtualReserveContext
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
ProcessHandle
Is the handle of the process in which to reserve the virtual address range.
PhysicalReserveContext
Is the context handle that identifies the reserved physical address range with which to associate the virtual memory reservation. This context was obtained from AgpReservePhysical.
VirtualReserveContext
Is the location in which the video port driver writes a context handle that identifies the reserved virtual memory.

Return Value

AgpReserveVirtual returns the base address of the reserved virtual address range if successful; otherwise, returns NULL.

Headers

Declared in videoagp.h. Include video.h.

Comments

The video miniport driver must call AgpCommitVirtual to cause reserved virtual addresses to actually be mapped to physical addresses decoded by the AGP device.

The miniport driver can call AgpReserveVirtual several times to reserve many smaller address ranges rather than one big range.

The miniport driver should call AgpReleaseVirtual to release the reserved virtual address range when it is no longer needed.

Callers of AgpReserveVirtual must be running at IRQL = PASSIVE_LEVEL.

See Also

AgpCommitVirtual, AgpReleaseVirtual, AgpReservePhysical


AgpSetRate

AgpSetRate reprograms the data transfer rate of the AGP chipset.

BOOLEAN
  (*PAGP_SET_RATE)(
    IN PVOID HwDeviceExtension,
    IN ULONG AgpRate
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
AgpRate
Specifies the transfer rate to be set. This value can be one of the following:
Value | Meaning
VIDEO_AGP_RATE_1X | Single speed (66 Mhz)
VIDEO_AGP_RATE_2X | Two times single speed
VIDEO_AGP_RATE_4X | Four times single speed
VIDEO_AGP_RATE_8X | Eight times single speed

Return Value

AgpSetRate returns TRUE if it was successful in changing the transfer rate; otherwise, it returns FALSE.

Headers

Declared in videoagp.h. Include video.h.

Comments

This function is available in Windows XP and later.

The AgpSetRate function can be used to change an AGP chipset's data transfer rate to any of the rates shown in the preceding table, as long as that transfer rate has not been explicitly eliminated in the INF file that loaded the display driver. See Display INF File Sections for more information.

Callers of AgpSetRate must be running at IRQL = PASSIVE_LEVEL.

See Also

VIDEO_PORT_AGP_INTERFACE_2


I2CRead

The I2CRead function reads data over the I2C channel.

typedef
  BOOLEAN (*PI2C_READ)(
    IN PVOID  HwDeviceExtension,
    IN PI2C_CALLBACKS  I2CCallbacks,
    OUT PUCHAR  Buffer,
    IN ULONG  Length
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-adapter device extension.
I2CCallbacks
Points to an I2C_CALLBACKS structure, containing pointers to miniport driver-defined functions that read and write data and clock lines.
Buffer
Points to the data to be read.
Length
Specifies the number of bytes to be read.

Return Value

I2CRead returns TRUE if the data was successfully read, and FALSE otherwise.

Headers

Declared in video.h. Include video.h.

Comments

The video port implements this function, which can be accessed through a pointer in the VIDEO_PORT_I2C_INTERFACE structure.

Callers of I2CRead must be running at IRQL = PASSIVE_LEVEL.

See Also

VIDEO_PORT_I2C_INTERFACE


I2CStart

The I2CStart function starts I2C communication.

typedef
  BOOLEAN (*PI2C_START)(
    IN PVOID  HwDeviceExtension,
    IN PI2C_CALLBACKS  I2CCallbacks
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-adapter device extension.
I2CCallbacks
Points to an I2C_CALLBACKS structure, containing pointers to miniport driver-defined functions that read and write data and clock lines.

Return Value

I2CStart returns TRUE if I2C communication was successfully started, and FALSE otherwise.

Headers

Declared in video.h. Include video.h.

Comments

The video port implements this function, which can be accessed through a pointer in the VIDEO_PORT_I2C_INTERFACE structure.

Callers of I2CStart must be running at IRQL = PASSIVE_LEVEL.

See Also

VIDEO_PORT_I2C_INTERFACE


I2CStop

The I2CStop function ends I2C communication.

typedef
  BOOLEAN (*PI2C_STOP)(
    IN PVOID  HwDeviceExtension,
    IN PI2C_CALLBACKS  I2CCallbacks
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-adapter device extension.
I2CCallbacks
Points to an I2C_CALLBACKS structure, containing pointers to miniport driver-defined functions that read and write data and clock lines.

Return Value

I2CStop returns TRUE if I2C communication was successfully stopped, and FALSE otherwise.

Headers

Declared in video.h. Include video.h.

Comments

The video port implements this function, which can be accessed through a pointer in the VIDEO_PORT_I2C_INTERFACE structure.

Callers of I2CStop must be running at IRQL = PASSIVE_LEVEL.

See Also

VIDEO_PORT_I2C_INTERFACE


I2CWrite

The I2CWrite function writes data over the I2C channel.

typedef
  BOOLEAN (*PI2C_WRITE)(
    IN PVOID  HwDeviceExtension,
    IN PI2C_CALLBACKS  I2CCallbacks,
    IN PUCHAR  Buffer,
    IN ULONG  Length
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-adapter device extension.
I2CCallbacks
Points to an I2C_CALLBACKS structure, containing pointers to miniport driver-defined functions that read and write data and clock lines.
Buffer
Points to the data to be written.
Length
Specifies the number of bytes to be written.

Return Value

I2CWrite returns TRUE if the data was successfully written, and FALSE otherwise.

Headers

Declared in video.h. Include video.h.

Comments

The video port implements this function, which can be accessed through a pointer in the VIDEO_PORT_I2C_INTERFACE structure.

Callers of I2CWrite must be running at IRQL = PASSIVE_LEVEL.

See Also

VIDEO_PORT_I2C_INTERFACE


Int10AllocateBuffer

The Int10AllocateBuffer function can be used to allocate a single 4 KB block of memory in the context of another thread. After the block of memory has been allocated, it must be freed before another block of memory can be allocated.

typedef
VP_STATUS
  (*PINT10_ALLOCATE_BUFFER)(
    IN PVOID  Context,
    OUT PUSHORT  Seg,
    OUT PUSHORT  Off,
    IN OUT PULONG  Length
    );

Parameters

Context
Points to a video port driver-defined context for the interface. This should be the same as the value in the Context member of the VIDEO_PORT_INT10_INTERFACE structure after VideoPortQueryServices returns.
Seg
Points to a memory location that will receive the segment address of the allocated memory buffer.
Off
Points to a memory location that will receive the offset within the segment specified by *Seg, of the allocated memory buffer.
Length
Points to a memory location that contains the length, in bytes, of the requested memory buffer, which can be as large as 4096. When the function returns, this memory location will contain the value 4096, whether or not the memory was actually allocated.

Return Value

The Int10AllocateBuffer function returns NO_ERROR upon success. It returns STATUS_INSUFFICIENT_RESOURCES if the buffer has been allocated previously or if a buffer size larger than 4096 bytes is requested.

Headers

Declared in video.h. Include video.h.

Comments

The video port implements this function, which can be accessed through a pointer in the VIDEO_PORT_INT10_INTERFACE structure.

Callers of Int10AllocateBuffer must be running at IRQL = PASSIVE_LEVEL.

See Also

VIDEO_PORT_INT10_INTERFACE


Int10CallBios

The Int10CallBios function allows a miniport driver to call the kernel to perform an int10 operation, causing the BIOS ROM code on the device to execute natively.

typedef
VP_STATUS
  (*PINT10_CALL_BIOS)(
    IN PVOID  Context,
    IN OUT PINT10_BIOS_ARGUMENTS  BiosArguments
    );

Parameters

Context
Points to a video port driver-defined context for the interface. This should be the same as the value in the Context member of the VIDEO_PORT_INT10_INTERFACE structure after VideoPortQueryServices returns.
BiosArguments
Points to a video miniport driver-initialized INT10_BIOS_ARGUMENTS structure containing the values of the x86 registers. Any registers that are not needed in the INT10 BIOS call should be set to 0. When the function returns, some members of the INT10_BIOS_ARGUMENTS structures can have different values than before the call.

Return Value

The Int10CallBios function returns NO_ERROR upon success. Otherwise it returns an appropriate error code.

Headers

Declared in video.h. Include video.h.

Comments

The video port implements this function, which can be accessed through a pointer in the VIDEO_PORT_INT10_INTERFACE structure.

Callers of Int10CallBios must be running at IRQL = PASSIVE_LEVEL.

See Also

VIDEO_PORT_INT10_INTERFACE


Int10FreeBuffer

The Int10FreeBuffer function frees a buffer previously allocated by Int10AllocateBuffer.

typedef
VP_STATUS
  (*PINT10_FREE_BUFFER)(
    IN PVOID  Context,
    IN USHORT  Seg,
    IN USHORT  Off
    );

Parameters

Context
Points to a video port driver-defined context for the interface. This should be the same as the value in the Context member of the VIDEO_PORT_INT10_INTERFACE structure after VideoPortQueryServices returns.
Seg
Specifies the segment address of the buffer to be freed.
Off
Specifies the offset within the segment indicated by the Seg parameter.

Return Value

The Int10FreeBuffer function returns NO_ERROR upon success. Otherwise, the function returns an appropriate error code.

Headers

Declared in video.h. Include video.h.

Comments

The video port implements this function, which can be accessed through a pointer in the VIDEO_PORT_INT10_INTERFACE structure.

Callers of Int10FreeBuffer must be running at IRQL = PASSIVE_LEVEL.

See Also

VIDEO_PORT_INT10_INTERFACE


Int10ReadMemory

The Int10ReadMemory function reads a block of memory in the context of another thread and stores it in an output buffer.

typedef
VP_STATUS
  (*PINT10_READ_MEMORY)(
    IN PVOID  Context,
    IN USHORT  Seg,
    IN USHORT  Off,
    OUT PVOID  Buffer,
    IN ULONG  Length
    );

Parameters

Context
Points to a video port driver-defined context for the interface. This should be the same as the value in the Context member of the VIDEO_PORT_INT10_INTERFACE structure after VideoPortQueryServices returns.
Seg
Specifies the segment address of the buffer to be read.
Off
Specifies the offset within the segment indicated by the Seg parameter.
Buffer
Points to a memory location that indicates the beginning of the output buffer.
Length
Is the length, in bytes, of the output buffer specified by the Buffer parameter.

Return Value

The Int10ReadMemory function returns NO_ERROR upon success. Otherwise it returns an appropriate error code.

Headers

Declared in video.h. Include video.h.

Comments

The video port implements this function, which can be accessed through a pointer in the VIDEO_PORT_INT10_INTERFACE structure.

Callers of Int10ReadMemory must be running at IRQL = PASSIVE_LEVEL.

See Also

VIDEO_PORT_INT10_INTERFACE


Int10WriteMemory

The Int10WriteMemory function writes the contents of an input buffer to memory in the context of another thread.

typedef
VP_STATUS
(*PINT10_WRITE_MEMORY)(
    IN PVOID  Context,
    IN USHORT  Seg,
    IN USHORT  Off,
    IN PVOID  Buffer,
    IN ULONG  Length
    );

Parameters

Context
Points to a video port driver-defined context for the interface. This should be the same as the value in the Context member of the VIDEO_PORT_INT10_INTERFACE structure after VideoPortQueryServices returns.
Seg
Specifies the segment address of the buffer to be written.
Off
Specifies the offset within the segment indicated by the Seg parameter.
Buffer
Points to the memory location that marks the beginning of the input buffer.
Length
Is the length, in bytes, of the input buffer specified by the Buffer parameter.

Return Value

The Int10WriteMemory function returns NO_ERROR upon success. Otherwise it returns an appropriate error code.

Headers

Declared in video.h. Include video.h.

Comments

The video port implements this function, which can be accessed through a pointer in the VIDEO_PORT_INT10_INTERFACE structure.

Callers of Int10WriteMemory must be running at IRQL = PASSIVE_LEVEL.

See Also

VIDEO_PORT_INT10_INTERFACE


PVIDEO_PORT_GET_PROC_ADDRESS

PVIDEO_PORT_GET_PROC_ADDRESS retrieves the address of a Windows 2000 or later video port driver function.

PVOID
  (*PVIDEO_PORT_GET_PROC_ADDRESS)(
    IN PVOID  HwDeviceExtension,
    IN PUCHAR  FunctionName
    );

Parameters

HwDeviceExtension
Points to the miniport driver's hardware device extension.
FunctionName
Points to a zero-terminated ASCII string that contains the name of the function being searched for.

Return Value

PVIDEO_PORT_GET_PROC_ADDRESS returns a pointer to the function specified in FunctionName, if it exists. If that function does not exist, PVIDEO_PORT_GET_PROC_ADDRESS returns NULL.

Headers

Declared in video.h. Include video.h.

Comments

PVIDEO_PORT_GET_PROC_ADDRESS makes it possible for a video miniport driver to gain access to video port driver functions without linking to them directly. This enables a Windows 2000 or later miniport driver to take full advantage of Windows 2000 and later features but still be able to load on Windows NT 4.0.

Callers of PVIDEO_PORT_GET_PROC_ADDRESS must be running at IRQL = PASSIVE_LEVEL.

See Also

VIDEO_PORT_CONFIG_INFO


VideoDebugPrint

VideoDebugPrint prints the specified debug message to the kernel debugger.

VOID
  VideoDebugPrint(
    IN ULONG  DebugPrintLevel,
    IN PCHAR  DebugMessage,
    ...
    );

Parameters

DebugPrintLevel
Specifies the level of debug messages to be printed. This parameter can be set to one of: Error, Warn, Trace, or Info, enumeration values ranging from 0 to 3, respectively. Set this parameter to Error to ensure that the specified debug message will always be printed in a checked build. For a checked build, when the DebugPrintLevel parameter is set to any of the other three values, a debug message is printed only if the global debugging level in the registry is greater than or equal to that value. See the Comments section for more information.
DebugMessage
Points to a string containing the debug message to be printed.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

The video port driver checks the adapter key in the registry for the VideoDebugLevel entry at startup. The video port driver also has a global variable with the same name. If the VideoDebugLevel entry does not exist in the registry, the video port driver uses a default value of 0.

The global debugging level can be changed in the registry or in the debugger at runtime:

  1. Change the value of the VideoDebugLevel registry entry. The new value will take effect on the next boot.
  2. Change the video port driver's VideoDebugLevel global variable in the debugger at runtime. The new value takes effect immediately.

The compiler eliminates references to VideoDebugPrint for free builds of the video port and video miniport drivers.

Miniport drivers must not call VideoPortDebugPrint.

Callers of VideoDebugPrint can be running at any IRQL.

See Also

VideoPortLogError


VideoPortAcquireDeviceLock

VideoPortAcquireDeviceLock acquires the device lock maintained by the video port driver.

VOID
  VideoPortAcquireDeviceLock(
    IN PVOID  HwDeviceExtension
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

Typically, the video port driver guarantees threaded synchronization into the miniport driver through the use of a device lock. However, a miniport driver must perform its own synchronization when being accessed by a child device. That is, a miniport driver must perform synchronization in routines that it exposes through HwVidQueryInterface by acquiring the device lock maintained by the video port driver.

The miniport driver should release the device lock as quickly as possible by calling VideoPortReleaseDeviceLock.

Callers of VideoPortAcquireDeviceLock must be running at IRQL = PASSIVE_LEVEL.

See Also

HwVidQueryInterface, VideoPortReleaseDeviceLock


VideoPortAcquireSpinLock

VideoPortAcquireSpinLock obtains the specified spin lock.

VOID
  VideoPortAcquireSpinLock(
    IN PVOID  HwDeviceExtension,
    IN PSPIN_LOCK  SpinLock,
    OUT PUCHAR  OldIrql
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
SpinLock
Points to a memory location that contains the spin lock.
OldIrql
Points to a memory location that will receive the current IRQL.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

The current IRQL is saved in OldIrql. Then, the current IRQL is reset to DISPATCH_LEVEL, and the specified spin lock is acquired.

The OldIrql value must be specified when the spin lock is released with VideoPortReleaseSpinLock.

Spin locks can cause serious problems if not used judiciously. In particular, no deadlock protection is performed and dispatching is disabled while the spin lock is held. Therefore:

  • The code within a critical region guarded by a spin lock must neither be pageable nor make any references to pageable data.
  • The code within a critical region guarded by a spin lock can neither call any external function that might access pageable data or raise an exception, nor can it generate any exceptions.
  • The caller should release the spin lock with VideoPortReleaseSpinLock as quickly as possible.

Callers of VideoPortAcquireSpinLock must be running at IRQL <= DISPATCH_LEVEL.

See Also

VideoPortReleaseSpinLock, VideoPortAcquireSpinLockAtDpcLevel


VideoPortAcquireSpinLockAtDpcLevel

VideoPortAcquireSpinLockAtDpcLevel acquires a spin lock when the caller is already running at IRQL = DISPATCH_LEVEL.

VOID
  VideoPortAcquireSpinLockAtDpcLevel(
    IN PVOID  HwDeviceExtension,
    IN PSPIN_LOCK  SpinLock
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
SpinLock
Points to a memory location that contains the spin lock.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

Miniport drivers call VideoPortAcquireSpinLockAtDpcLevel instead of VideoPortAcquireSpinLock for better driver performance if and only if they are already running at IRQL = DISPATCH_LEVEL.

If a miniport driver is running at IRQL < DISPATCH_LEVEL, it should call VideoPortAcquireSpinLock to have IRQL raised by that routine. VideoPortAcquireSpinLockAtDpcLevel requires the caller to be running already at IRQL = DISPATCH_LEVEL, so no raise is necessary.

The caller should release the spin lock with VideoPortReleaseSpinLockFromDpcLevel as quickly as possible.

See Also

VideoPortAcquireSpinLock, VideoPortReleaseSpinLockFromDpcLevel


VideoPortAllocateBuffer

VideoPortAllocateBuffer is obsolete in Windows 2000 and later. In its place, video miniport drivers should instead use VideoPortAllocatePool.

VideoPortAllocateBuffer allocates a buffer of paged pool memory.

VP_STATUS
  VideoPortAllocateBuffer(
    IN PVOID  HwDeviceExtension,
    IN ULONG  Size,
    OUT PVOID  *Buffer
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
Size
Specifies the size of the buffer to allocate, in bytes.
Buffer
Is the location in which the video port driver returns a pointer to a pointer to the allocated pool memory.

Return Value

VideoPortAllocateBuffer returns NO_ERROR when it successfully completes the allocation request, or ERROR_NOT_ENOUGH_MEMORY if it is unable to allocate a buffer of Size bytes. A return value of ERROR_INSUFFICIENT_BUFFER indicates that a miniport driver has exceeded its maximum allowable allocation of memory.

Headers

Declared in video.h. Include video.h.

Comments

A miniport driver can use the return value of this function to determine whether the buffer allocation succeeded.

Callers of VideoPortAllocateBuffer must be running at IRQL = PASSIVE_LEVEL.

See Also

VideoPortReleaseBuffer


VideoPortAllocateCommonBuffer

VideoPortAllocateCommonBuffer allocates and maps system memory so that it is simultaneously accessible from both the processor and a device for common-buffer DMA operations.

PVOID
  VideoPortAllocateCommonBuffer(
    IN PVOID  HwDeviceExtension,
    IN PVP_DMA_ADAPTER  VpDmaAdapter,
    IN ULONG  DesiredLength,
    OUT PPHYSICAL_ADDRESS  LogicalAddress,
    IN BOOLEAN  CacheEnabled,
    PVOID  Reserved
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
VpDmaAdapter
Points to the VP_DMA_ADAPTER structure that represents the busmaster adapter. This structure was returned by a previous call to VideoPortGetDmaAdapter.
DesiredLength
Specifies the requested number of bytes of memory.
LogicalAddress
Points to a memory location that receives the logical address to be used by the adapter to access the allocated buffer.
CacheEnabled
Specifies whether the allocated memory can be cached. A value of TRUE indicates that the memory can be cached.
Reserved
Is currently ignored by the video port driver; should be set to NULL.

Return Value

VideoPortAllocateCommonBuffer returns the base virtual address of the allocated buffer if successful; otherwise, it returns NULL if the buffer cannot be allocated.

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

When the buffer is no longer needed, the video miniport driver should release it by calling VideoPortReleaseCommonBuffer.

Callers of VideoPortAllocateCommonBuffer must be running at IRQL = PASSIVE_LEVEL.

See Also

VideoPortGetDmaAdapter, VideoPortReleaseCommonBuffer, VP_DMA_ADAPTER


VideoPortAllocateContiguousMemory

VideoPortAllocateContiguousMemory is obsolete in Windows 2000 and later. Video miniport drivers should use VideoPortAllocateCommonBuffer in its place.

VideoPortAllocateContiguousMemory allocates a range of physically contiguous, cache-aligned memory from the nonpaged pool.

PVOID
  VideoPortAllocateContiguousMemory(
    IN PVOID  HwDeviceExtension,
    IN ULONG  NumberOfBytes,
    IN PHYSICAL_ADDRESS  HighestAcceptableAddress
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
NumberOfBytes
Specifies the size in bytes of the block of contiguous memory to be allocated.
HighestAcceptableAddress
Specifies the highest valid physical address the miniport driver can use. For example, if a device can only reference physical memory in the lower 16MB, this value would be set to 0x00000000FFFFFF.

Return Value

VideoPortAllocateContiguousMemory returns the base virtual address for the allocated memory, if the call is successful. If the request cannot be satisfied, NULL is returned.

Headers

Declared in video.h. Include video.h.

Comments

VideoPortAllocateContiguousMemory can be called to allocate a contiguous block of physical memory for a long-term internal buffer.

A miniport driver that must use contiguous memory should allocate only what it needs during driver initialization because nonpaged pool is likely to become fragmented as the system runs. If the miniport driver is unloaded, it must deallocate the memory. Contiguous allocations are aligned on an integral multiple of the processor's data-cache-line size to prevent cache and coherency problems.

Callers of VideoPortAllocateContiguousMemory must be running at IRQL = PASSIVE_LEVEL.

See Also

VideoPortAllocateBuffer


VideoPortAllocatePool

VideoPortAllocatePool allocates a block of pool memory, inserting a caller-supplied tag at the beginning of the memory.

PVOID
  VideoPortAllocatePool(
    IN PVOID  HwDeviceExtension,
    IN VP_POOL_TYPE  PoolType,
    IN SIZE_T  NumberOfBytes,
    IN ULONG  Tag
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
PoolType
Specifies the type of memory pool to allocate. This parameter can be set to one of the following:
Value | Meaning
VpNonPagedPool | The pool is from nonpaged memory.
VpPagedPool | The pool is from paged memory.
VpNonPagedPoolCacheAligned | The pool is from cache-aligned, nonpaged memory.
VpPagedPoolCacheAligned | The pool is from cache-aligned, paged memory.

NumberOfBytes
Specifies the number of bytes of memory to allocate.
Tag
Specifies a four-byte allocation tag, consisting of up to four characters delimited with single quotes, that uniquely identifies the driver doing the memory allocation.

Return Value

On successful allocation of the memory pool, VideoPortAllocatePool returns the address of the allocated memory pool. Otherwise, this function returns NULL.

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

VideoPortAllocatePool is intended to replace VideoPortAllocateBuffer, which is obsolete.

The Tag string should be specified in byte-reversed order. It is recommended that the first letter in the string (before it is reversed) be 'D' to denote a display driver; the other three bytes should be indicative of the driver name. For example, the Tag string 'zyxD' appears as 'Dxyz' if pool is dumped. The tag appears in any crash dump of the system that occurs.

Callers of VideoPortAllocatePool can be running at IRQL = DISPATCH_LEVEL only if the requested PoolType is one of the VpNonPaged Xxx types. Otherwise, callers must be running at IRQL < DISPATCH_LEVEL.

See Also

VideoPortFreePool


VideoPortAssociateEventsWithDmaHandle

VideoPortAssociateEventsWithDmaHandle is obsolete in Windows 2000 and later.

VideoPortAssociateEventsWithDmaHandle associates an event, which is shared by the video display driver and the video miniport driver, with a DMA handle.

PDMA
  VideoPortAssociateEventsWithDmaHandle(
    IN PVOID  HwDeviceExtension,
    IN OUT PVIDEO_REQUEST_PACKET  pVrp,
    IN PVOID  MappedUserEvent,
    IN PVOID  DisplayDriverEvent
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
pVrp
Points to a VIDEO_REQUEST_PACKET.
MappedUserEvent
Is reserved for system use.
DisplayDriverEvent
Is reserved for system use.

Return Value

VideoPortAssociateEventsWithDmaHandle always returns NULL.

Headers

Declared in video.h. Include video.h.

Comments

See Video Port Driver Support for Busmaster DMA for information about packet-based and common-buffer DMA transfers.


VideoPortCheckForDeviceExistence

VideoPortCheckForDeviceExistence determines whether the specified PCI device exists in the system.

BOOLEAN
  VideoPortCheckForDeviceExistence(
    IN PVOID  HwDeviceExtension,
    IN USHORT  VendorId,
    IN USHORT  DeviceId,
    IN UCHAR  RevisionId,
    IN USHORT  SubVendorId,
    IN USHORT  SubSystemId,
    IN ULONG  Flags
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
VendorId
Specifies the vendor ID.
DeviceId
Specifies the device ID.
RevisionId
Specifies the revision ID.
SubVendorId
Specifies the subvendor ID.
SubSystemId
Specifies the subsystem ID.
Flags
Is a set of flags that determine whether the RevisionID and SubSystemID parameters should be used in checking for the new device. This parameter can be the logical OR of the following values:
Value | Meaning
CDE_USE_REVISION | Use the value in the RevisionID parameter in checking for the new device.
CDE_USE_SUBSYSTEM_IDS | Use the value in the SubSystemID parameter in checking for the new device.

Return Value

VideoPortCheckForDeviceExistence returns TRUE if the device exists in the system, and FALSE otherwise.

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

Callers of VideoPortCheckForDeviceExistence must be running at IRQL = PASSIVE_LEVEL.


VideoPortClearEvent

VideoPortClearEvent sets a given event object to the nonsignaled state.

VOID
  VideoPortClearEvent(
    IN PVOID  HwDeviceExtension,
    IN PEVENT  pEvent
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
pEvent
Points to the event object.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

To set the state of an event object to the signaled state, use VideoPortSetEvent.

Callers of VideoPortClearEvent must be running at IRQL <= DISPATCH_LEVEL.

See Also

VideoPortSetEvent


VideoPortCompareMemory

VideoPortCompareMemory compares two blocks of system memory, byte-by-byte, and returns the number of compared bytes that are equivalent.

ULONG
  VideoPortCompareMemory(
    IN PVOID  Source1,
    IN PVOID  Source2,
    IN ULONG  Length
    );

Parameters

Source1
Points to the first block of memory to compare.
Source2
Points to the second block of memory to compare.
Length
Specifies the number of bytes to be compared.

Return Value

VideoPortCompareMemory returns the number of bytes that are equivalent. If both blocks are equivalent, it returns the Length parameter.

The given Source1 and Source2 must be in a mapped logical range returned by VideoPortGetDeviceBase and/or a system-space RAM address, such as an address on the stack.

Headers

Declared in video.h. Include video.h.

Comments

Callers of VideoPortCompareMemory can be running at any IRQL if both blocks of memory are resident.

See Also

VideoPortGetDeviceBase, VideoPortMoveMemory, VideoPortScanRom, VideoPortZeroDeviceMemory, VideoPortZeroMemory


VideoPortCompleteDma

VideoPortCompleteDma flushes any data remaining in a busmaster adapter's internal cache at the end of a DMA transfer operation, and then frees the previously allocated map registers and scatter/gather list used in scatter/gather DMA operations.

VP_STATUS
  VideoPortCompleteDma(
    IN PVOID  HwDeviceExtension,
    IN PVP_DMA_ADAPTER  VpDmaAdapter,
    IN PVP_SCATTER_GATHER_LIST  VpScatterGather,
    IN BOOLEAN  WriteToDevice
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
VpDmaAdapter
Points to a VP_DMA_ADAPTER structure that represents the busmaster adapter. This structure was returned by a call to VideoPortGetDmaAdapter.
VpScatterGather
Points to the VP_SCATTER_GATHER_LIST structure previously passed to the miniport driver callback routine, HwVidExecuteDma.
WriteToDevice
Specifies the direction of the DMA transfer. A value of TRUE denotes a transfer from the buffer to the device, and a value of FALSE denotes a transfer from the device to the buffer.

Return Value

VideoPortCompleteDma returns NO_ERROR.

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

The video miniport driver should call VideoPortCompleteDma immediately to free up system resources after a DMA transfer has been completed.

It is important to note that the scatter/gather list built by VideoPortStartDma becomes invalid when VideoPortCompleteDma is called.

Callers of VideoPortCompleteDma must be running at IRQL <= DISPATCH_LEVEL.

See Also

VideoPortGetDmaAdapter, VideoPortStartDma, VP_DMA_ADAPTER, VP_SCATTER_GATHER_LIST


VideoPortCreateEvent

VideoPortCreateEvent creates an event object.

VP_STATUS
  VideoPortCreateEvent(
    IN PVOID  HwDeviceExtension,
    IN ULONG  EventFlag,
    IN PVOID  Unused,
    OUT PEVENT  *ppEvent
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
EventFlag
Specifies the event type and initial event state. This can be an ORed combination of the following flags:
Flag | Meaning
INITIAL_EVENT_SIGNALED | Set this flag to indicate the signaled state for the event object. Otherwise, the initial state of the event is nonsignaled.
NOTIFICATION_EVENT | Set this flag to create a notification event. If this flag is not set, a synchronization event is created.

Unused
Is currently ignored by the video port driver and must be set to NULL.
ppEvent
Points to the memory location at which a pointer to the event object will be returned.

Return Value

VideoPortCreateEvent returns NO_ERROR if the event object is successfully created.

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

When a synchronization event is set to the signaled state, a single thread that was waiting on the event is released (its dispatch state transitions from waiting to ready, standby, or running), and the event is automatically reset to the nonsignaled state.

When a notification event is set to the signaled state, all threads that were waiting on the event are released, and the event remains in the signaled state until it is explicitly reset to the nonsignaled state.

Callers of this routine must be running at IRQL = PASSIVE_LEVEL.

See Also

VideoPortDeleteEvent


VideoPortCreateSecondaryDisplay

VideoPortCreateSecondaryDisplay enables dual-view support by creating a secondary device object for the given device.

VP_STATUS
  VideoPortCreateSecondaryDisplay(
    IN PVOID  HwDeviceExtension,
    IN OUT PVOID  *SecondaryDeviceExtension,
    IN ULONG  ulFlag
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension. This is the hardware extension for the device that wants to create additional display device objects.
SecondaryDeviceExtension
Points to the location in which to store the hardware device extension for the secondary display device.
ulFlag
Is a set of attributes for the secondary display device. This parameter is restricted to the following value:
Value | Meaning
VIDEO_DUALVIEW_REMOVABLE | The secondary view can be removed.

Return Value

VideoPortCreateSecondaryDisplay returns NO_ERROR if the secondary display device was successfully created. Otherwise, this function returns an error code.

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

In Windows XP and later, a removable logical device will never become the primary display.

Note that on some editions of Windows XP, VideoPortCreateSecondaryDisplay can deliberately fail to enable Dualview. In such cases, the display driver should remain in SingleView mode.

Callers of VideoPortCreateSecondaryDisplay must be running at IRQL = PASSIVE_LEVEL.


VideoPortCreateSpinLock

VideoPortCreateSpinLock creates a spin lock.

VP_STATUS
  VideoPortCreateSpinLock(
    IN PVOID  HwDeviceExtension,
    OUT PSPIN_LOCK  *SpinLock
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
SpinLock
Points to a memory location that will receive a pointer to the newly created spin lock. The caller must allocate the storage used to hold the spin lock.

Return Value

On success the function returns NO_ERROR. If an error occurs, the function returns an appropriate error code.

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

This routine must be called before an initial call to VideoPortAcquireSpinLock or to any other support routine that requires a spin lock as an argument.

Storage for a spin lock object must be resident in the miniport driver's device extension.

Callers of this routine must be running at IRQL = PASSIVE_LEVEL.

See Also

VideoPortDeleteSpinLock, VideoPortAcquireSpinLock


VideoPortDDCMonitorHelper

VideoPortDDCMonitorHelper queries a monitor for EDID information using the DDC protocol.

BOOLEAN
  VideoPortDDCMonitorHelper(
    IN PVOID  HwDeviceExtension,
    IN PVOID  DDCControl,
    IN OUT PUCHAR  EdidBuffer,
    IN ULONG  EdidBufferSize
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
DDCControl
Points to a DDC_CONTROL structure.
EdidBuffer
Points to a buffer in which the video port driver returns the EDID structure. For ACPI devices, the first four bytes are preset by the video port driver to indicate an attempt to read the EDID.
EdidBufferSize
Specifies the size in bytes of the buffer to which EdidBuffer points.

Return Value

VideoPortDDCMonitorHelper returns TRUE if successful.

Headers

Declared in video.h. Include video.h.

Comments

This function existed prior to the Windows XP release, but has been changed.

The miniport driver's HwVidGetVideoChildDescriptor function can call VideoPortDDCMonitorHelper to more easily obtain the EDID structure from a DDC2-compliant monitor. The video port driver calls the functions identified in DDCControl->I2CCallbacks to obtain the EDID; therefore, the miniport driver must implement all of its functions.

In a 256-byte buffer a caller of this function can receive:

  • One 128-byte EDID
  • Two 128-byte EDIDs
  • One 256-byte EDID (from P&D display)
  • No EDID

The caller should always ask for the full 256 bytes, because it is impossible to read just the second 128-byte block of the segment.

Callers of VideoPortDDCMonitorHelper must be running at IRQL = PASSIVE_LEVEL.

DDC_CONTROL

The DDC_CONTROL structure is a Display Data Channel (DDC) access control block.

typedef struct _DDC_CONTROL {
  ULONG  Size;
  I2C_CALLBACKS  I2CCallbacks;
  UCHAR  EdidSegment;
} DDC_CONTROL, *PDDC_CONTROL;

Members

Size
Specifies the size, in bytes, of this DDC_CONTROL structure.
I2CCallbacks
Is an I2C_CALLBACKS structure, containing pointers to functions to read and write clock and data lines.
EdidSegment
Specifies the particular EDID segment. Currently, this member is meaningful only for EEDID (EDID Version 1.3); for other EDID versions, this member should always be set to 0. For EEDID (EDID Version 1.3), segment numbers can range from 0 through 127, where each segment is 256 bytes in length. Since the EDID version number is in segment 0, this member must be set to 0 for the first call to VideoPortDDCMonitorHelper.

I2C_CALLBACKS

The I2C_CALLBACKS structure contains pointers to functions that read from or write to data and clock lines. This structure defines the interface supported by the miniport driver for communicating with a monitor over a standard protocol two-wire serial data bus. (See I2C for more information.) The miniport driver must implement all functions identified by this structure and set each structure member with the address of the relevant function.

typedef struct _I2C_CALLBACKS {
  PVIDEO_WRITE_CLOCK_LINE  WriteClockLine;
  PVIDEO_WRITE_DATA_LINE  WriteDataLine;
  PVIDEO_READ_CLOCK_LINE  ReadClockLine;
  PVIDEO_READ_DATA_LINE  ReadDataLine;
} I2C_CALLBACKS, *PI2C_CALLBACKS;

Members

WriteClockLine
Points to the function that resets the clock line. The miniport driver-defined function is prototyped as follows:
typedef VOID (*PVIDEO_WRITE_CLOCK_LINE)(PVOID HwDeviceExtension, UCHAR data);
WriteDataLine
Points to the function that resets the data line. The miniport driver-defined function is prototyped as follows:
typedef VOID (*PVIDEO_WRITE_DATA_LINE)(PVOID HwDeviceExtension, UCHAR data);
ReadClockLine
Points to the function that reads the data line. The miniport driver-defined function is prototyped as follows:
typedef BOOLEAN (*PVIDEO_READ_CLOCK_LINE)(PVOID HwDeviceExtension);
ReadDataLine
Points to the function that reads the data line. The miniport driver-defined function is prototyped as follows:
typedef BOOLEAN (*PVIDEO_READ_DATA_LINE)(PVOID HwDeviceExtension);

See Also

HwVidGetVideoChildDescriptor


VideoPortDeleteEvent

VideoPortDeleteEvent deletes the specified event object.

VP_STATUS VideoPortDeleteEvent(
    IN PVOID  HwDeviceExtension,
    IN PEVENT  pEvent
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
pEvent
Points to the event object to be deleted.

Return Value

VideoPortDeleteEvent returns NO_ERROR if the event object is successfully deleted.

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

This function should not be used to delete a mapped user event. To delete a mapped user event, use EngUnmapEvent.

Callers of this function must be running at IRQL <= DISPATCH_LEVEL.

See Also

VideoPortCreateEvent, EngUnmapEvent


VideoPortDeleteSpinLock

VideoPortDeleteSpinLock deletes a given spin lock.

VP_STATUS
  VideoPortDeleteSpinLock(
    IN PVOID  HwDeviceExtension,
    IN PSPIN_LOCK  SpinLock
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
SpinLock
Points to a memory location that contains the spin lock to delete.

Return Value

If the spin lock is successfully deleted, VideoPortDeleteSpinLock returns NO_ERROR.

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

A miniport driver uses this function to delete a spin lock that was previously created in a call to VideoPortCreateSpinLock.

Callers of VideoPortDeleteSpinLock must be running at IRQL <= DISPATCH_LEVEL.

This routine cannot be called from an ISR or from a VideoPortSynchronizeExecution callback requested where the Priority parameter is set to either VpMediumPriority or VpHighPriority.

See Also

VideoPortCreateSpinLock, VideoPortSynchronizeExecution


VideoPortDisableInterrupt

VideoPortDisableInterrupt disables interrupts from a video adapter. As a result, interrupts coming from the device are ignored by the operating system and are not forwarded to the driver.

VP_STATUS
  VideoPortDisableInterrupt(
    IN PVOID  HwDeviceExtension
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.

Return Value

VideoPortDisableInterrupt returns NO_ERROR if it disabled calls to the miniport driver's HwVidInterrupt function. Otherwise, it can return ERROR_INVALID_FUNCTION.

Headers

Declared in video.h. Include video.h.

Comments

A call to VideoPortDisableInterrupt is valid only if the interrupt is defined, thereby providing the appropriate data at initialization time to set up the interrupt and the entry point of the miniport driver's HwVidInterrupt function. After a successful call to VideoPortDisableInterrupt, interrupts from the caller's adapter remain disabled until the miniport driver calls VideoPortEnableInterrupt.

The reciprocal call to VideoPortEnableInterrupt should follow the call to VideoPortDisableInterrupt.

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortDisableInterrupt.

Callers of VideoPortDisableInterrupt can be running at any IRQL.

See Also

HwVidInterrupt, VIDEO_HW_INITIALIZATION_DATA, VideoPortEnableInterrupt


VideoPortDoDma

VideoPortDoDma is obsolete in Windows 2000 and later.

VideoPortDoDma causes the miniport driver's HwVidStartDma function to be called.

PDMA
  VideoPortDoDma(
    IN PVOID  HwDeviceExtension,
    IN PDMA  pDma,
    IN DMA_FLAGS  DmaFlags
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
pDma
Specifies a non-NULL DMA handle. This handle was obtained from a prior call to VideoPortDoDma or from the OutputBuffer member of the VIDEO_REQUEST_PACKET returned by VideoPortLockPages.
DmaFlags
Specifies the action to be performed. This member can be one of the following values:
Value | Meaning
VideoPortKeepPagesLocked
VideoPortDmaInitOnly 		If possible, the video port driver should keep the memory locked for subsequent DMA operation(s).
VideoPortUnlockAfterDma | The video port driver should unlock the memory after the DMA operation is performed.

Return Value

VideoPortDoDma always returns NULL.

Headers

Declared in video.h. Include video.h.

Comments

See Video Port Driver Support for Busmaster DMA for information about packet-based and common-buffer DMA transfers.

See Also

VideoPortLockPages, VIDEO_REQUEST_PACKET


VideoPortEnableInterrupt

VideoPortEnableInterrupt re-enables interrupts from a video adapter after a call to VideoPortDisableInterrupt.

VP_STATUS
  VideoPortEnableInterrupt(
    IN PVOID  HwDeviceExtension
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.

Return Value

VideoPortEnableInterrupt returns NO_ERROR if it re-enabled calls to the miniport driver's HwVidInterrupt function. Otherwise, it can return ERROR_INVALID_FUNCTION.

Headers

Declared in video.h. Include video.h.

Comments

A call to VideoPortEnableInterrupt is valid only if the interrupt is defined, thereby providing the appropriate data at initialization time to set up the interrupt and the entry point of the miniport driver's HwVidInterrupt function.

Even if the caller has set up a HwVidInterrupt function, a call to VideoPortEnableInterrupt is valid only following a preceding call to VideoPortDisableInterrupt.

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortEnableInterrupt.

Callers of VideoPortEnableInterrupt can be running at any IRQL.

See Also

HwVidInterrupt, VIDEO_HW_INITIALIZATION_DATA, VideoPortDisableInterrupt


VideoPortEnumerateChildren

VideoPortEnumerateChildren allows a video miniport driver to force a re-enumeration of its child devices.

VP_STATUS
  VideoPortEnumerateChildren(
    IN PVOID  HwDeviceExtension,
    IN PVOID  Reserved
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
Reserved
Must be set to NULL.

Return Value

VideoPortEnumerateChildren returns NO_ERROR.

Headers

Declared in video.h. Include video.h.

Comments

Some devices generate an interrupt when new hardware is connected to the system, or when existing hardware is disconnected from the system. For these devices, VideoPortEnumerateChildren can make such system changes as seamless as possible. The following is one possible scenario that forces the re-enumeration of child devices through VideoPortEnumerateChildren:

  • New hardware is connected, which generates an interrupt.
  • The miniport driver's interrupt handler (HwVidInterrupt) queues a DPC routine (PMINIPORT_DPC_ROUTINE) by calling VideoPortQueueDpc.
  • The asynchronously executed DPC contains a call to VideoPortEnumerateChildren.
  • VideoPortEnumerateChildren causes HwVidGetVideoChildDescriptor to be called, allowing the Plug and Play Manager to enumerate all of the adapter's child devices.

Callers of VideoPortEnumerateChildren must be running at IRQL <= DISPATCH_LEVEL.

See Also

HwVidGetVideoChildDescriptor, HwVidInterrupt, PMINIPORT_DPC_ROUTINE, VideoPortQueueDpc


VideoPortFreeCommonBuffer

VideoPortFreeCommonBuffer is obsolete and is supported only for backward compatibility with existing drivers. In its place, driver writers should use VideoPortReleaseCommonBuffer.

VideoPortFreeCommonBuffer deallocates system memory that was allocated by a call to VideoPortGetCommonBuffer.

VOID
  VideoPortFreeCommonBuffer(
    IN PVOID  HwDeviceExtension,
    IN ULONG  Length,
    IN PVOID  VirtualAddress,
    IN PHYSICAL_ADDRESS  LogicalAddress,
    IN BOOLEAN  CacheEnabled
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
Length
Specifies the number of bytes of memory to be freed.
VirtualAddress
Points to the corresponding virtual address of the allocated memory range.
LogicalAddress
Specifies the logical address of the buffer to be freed.
CacheEnabled
Indicates whether the allocated memory is cached.

Return Value

None

Comments

Except for VideoPortGetCommonBuffer's Alignment parameter, all of the parameters used in a call to VideoPortFreeCommonBuffer must have the same values as those used in the previous call to VideoPortGetCommonBuffer.

Callers of VideoPortFreeCommonBuffer must be running at IRQL = PASSIVE_LEVEL.

See Also

VideoPortReleaseCommonBuffer, VideoPortGetCommonBuffer


VideoPortFreeDeviceBase

VideoPortFreeDeviceBase frees a range of bus-relative device I/O ports or memory addresses previously mapped into the system address space. It does this by calling VideoPortGetDeviceBase.

VOID
  VideoPortFreeDeviceBase(
    IN PVOID  HwDeviceExtension,
    IN PVOID  MappedAddress
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
MappedAddress
Specifies the base address of the mapped range to be freed. This value must be the same as the value returned by a preceding call to VideoPortGetDeviceBase.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

VideoPortFreeDeviceBase must be called from the miniport driver's HwVidFindAdapter function if the miniport driver has already mapped an address range for an adapter it cannot support or does not use any longer.

When this occurs, the miniport driver also must release its claim on the corresponding hardware resources in the registry. To release all claims on resources for a particular adapter, call VideoPortVerifyAccessRanges or VideoPortGetAccessRanges with the NumAccessRanges parameter set to zero. To release claims on selected access ranges, do the following:

  1. Modify the access ranges array of claimed bus-relative ranges for the adapter by setting the appropriate elements' RangeLength(s) to zero. Leave the current specification as is in all elements on which the miniport driver will not release its claims.
  2. Call VideoPortVerifyAccessRanges with this modified AccessRanges array.

Callers of VideoPortFreeDeviceBase must be running at IRQL = PASSIVE_LEVEL.

See Also

HwVidFindAdapter, VideoPortGetAccessRanges, VideoPortGetDeviceBase, VideoPortVerifyAccessRanges


VideoPortFreePool

VideoPortFreePool deallocates a block of pool memory previously allocated by VideoPortAllocatePool.

VOID
  VideoPortFreePool(
    IN PVOID  HwDeviceExtension,
    IN PVOID  Ptr
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
Ptr
Points to the first byte of the memory to be freed.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

VideoPortFreePool is intended to replace VideoPortReleaseBuffer, which is obsolete.

Callers of VideoPortFreePool must be running at IRQL <= DISPATCH_LEVEL. A caller at DISPATCH_LEVEL must have specified a VpNonPaged Xxx PoolType when the memory was allocated. Otherwise, the caller must be running at IRQL < DISPATCH_LEVEL.

See Also

VideoPortAllocatePool, VideoPortAllocateCommonBuffer


VideoPortGetAccessRanges

VideoPortGetAccessRanges retrieves bus-relative configuration information and, if possible, claims these hardware resources in the registry for the caller.

VP_STATUS
  VideoPortGetAccessRanges(
    IN PVOID  HwDeviceExtension,
    IN ULONG  NumRequestedResources,
    IN PIO_RESOURCE_DESCRIPTOR  RequestedResources  OPTIONAL,
    IN ULONG  NumAccessRanges,
    OUT PVIDEO_ACCESS_RANGE  AccessRanges,
    IN PVOID  VendorId,
    IN PVOID  DeviceId,
    OUT PULONG  Slot
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
NumRequestedResources
Specifies the number of elements in the RequestedResources array.
RequestedResources
An array of IO_RESOURCE_DESCRIPTOR-type elements. Each descriptor specifies a single hardware resource that the miniport driver needs, prefers, or can use as an alternative to that specified in another array element. For detailed information about this structure, see the description of IoAssignResources.
NumAccessRanges
Specifies the number of elements in the AccessRanges array.
AccessRanges
Points to an area on the stack or to a static structure in the miniport driver to which VideoPortGetAccessRanges returns an array of VIDEO_ACCESS_RANGE elements filled with the bus-relative device memory ranges for the adapter.
VendorId
Should be set to NULL.
DeviceId
Should be set to NULL.
Slot
Points to a memory location in which the video port driver stores the slot number for the device, or is NULL.

For Plug and Play devices, if this is a valid pointer, the video port driver stores the slot number at the memory location specified by the pointer. If a NULL value is passed in the call, the video port driver does not store a value in the location.

Return Value

VideoPortGetAccessRanges returns NO_ERROR if it successfully filled in the AccessRanges information or returned configuration information at RequestedResources.

Headers

Declared in video.h. Include video.h.

Comments

VideoPortGetAccessRanges can be called only from a miniport driver's HwVidFindAdapter function.

For most miniport drivers, VideoPortGetAccessRanges can retrieve, verify, and claim the bus-relative access ranges and any interrupt and/or DMA channel/port used by a particular video adapter, while VideoPortVerifyAccessRanges can only verify and claim miniport driver-specified resources. That is, for all configuration information that it returns, VideoPortGetAccessRanges claims the corresponding hardware resources in the registry for the caller. A miniport driver need not call VideoPortVerifyAccessRanges with the returned bus-relative configuration information, unless the miniport driver attempts to modify any of the returned values.

Each successful call to VideoPortGetAccessRanges or VideoPortVerifyAccessRanges for a particular adapter overwrites the miniport driver's preceding claim on hardware resources in the registry.

After a successful call to VideoPortGetAccessRanges, the miniport driver must map the returned bus-relative ranges to logical ranges with VideoPortGetDeviceBase before calling the appropriate VideoPortRead/Write Xxx function to communicate with the adapter.

Generally, the miniport driver of a PCI device should have its HwVidFindAdapter function call VideoPortGetAccessRanges, rather than attempt to manipulate the nondevice-specific PCI_COMMON_CONFIG information returned by a call to VideoPortGetBusData. This miniport driver can typically call VideoPortGetAccessRanges with a NULL RequestedResources pointer. The video port driver then uses the configuration space of the PCI bus to determine the resources for the video adapter. The miniport driver can call VideoPortGetAccessRanges, using a set of driver-supplied RequestedResources specifications, if its original call fails to return valid configuration data for the adapter.

Note that miniport drivers of adapters on other types of I/O buses also can call VideoPortGetAccessRanges. These drivers should call VideoPortGetAccessRanges using a RequestedResources pointer to a driver-supplied array of I/O resource descriptors.

If the HwVidFindAdapter function claims bus-relative access ranges and possibly other hardware resources for an adapter, but then determines that it does not support the adapter, then the miniport driver must relinquish its claims on hardware resources in the registry by calling VideoPortGetAccessRanges or VideoPortVerifyAccessRanges with the NumAccessRanges parameter set to zero.

Callers of VideoPortGetAccessRanges must be running at IRQL = PASSIVE_LEVEL.

See Also

HwVidFindAdapter, IoAssignResources, PCI_COMMON_CONFIG, PCI_SLOT_NUMBER, VIDEO_PORT_CONFIG_INFO, VideoPortGetBusData, VideoPortGetDeviceBase, VideoPortSetBusData, VideoPortVerifyAccessRanges


VideoPortGetAgpServices

VideoPortGetAgpServices is obsolete and is supported only for backward compatibility with existing drivers. In its place, driver writers should use VideoPortQueryServices.

VideoPortGetAgpServices returns a list of video port driver-implemented AGP service functions.

BOOLEAN
  VideoPortGetAgpServices(
    IN PVOID  HwDeviceExtension,
    IN PVIDEO_PORT_AGP_SERVICES  AgpServices
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
AgpServices
Points to an uninitialized, miniport driver-allocated VIDEO_PORT_AGP_SERVICES structure.

Return Value

VideoPortGetAgpServices returns TRUE after it successfully initializes the VIDEO_PORT_AGP_SERVICES structure to which AgpServices points; otherwise it returns FALSE.

Headers

Declared in video.h. Include video.h.

Comments

PnP video miniport drivers that can use AGP should call VideoPortGetAgpServices.

The video port driver initializes the VIDEO_PORT_AGP_SERVICES structure as follows:

  • All function pointers are initialized to point to the corresponding video port driver-implemented AGP service functions.
  • The AllocationLimit field is initialized to the maximum amount of AGP memory that a miniport driver is allowed to commit, in bytes.

Callers of VideoPortGetAgpServices must be running at IRQL = PASSIVE_LEVEL.

See Also

VideoPortQueryServices, AgpCommitPhysical, AgpCommitVirtual, AgpFreePhysical, AgpFreeVirtual, AgpReleasePhysical, AgpReleaseVirtual, AgpReservePhysical, AgpReleasePhysical, VIDEO_PORT_AGP_SERVICES


VideoPortGetAssociatedDeviceExtension

VideoPortGetAssociatedDeviceExtension returns the device extension for the parent of the specified device object.

PVOID
  VideoPortGetAssociatedDeviceExtension(
    IN PVOID  DeviceObject
    );

Parameters

DeviceObject
Is the device object of a child device.

Return Value

VideoPortGetAssociatedDeviceExtension returns a pointer to the device extension of DeviceObject's parent.

Headers

Declared in video.h. Include video.h.

Comments

The miniport driver of a child device can call this function to obtain a description of its parent through the parent's device extension.

Callers of VideoPortGetAssociatedDeviceExtension must be running at IRQL = PASSIVE_LEVEL.


VideoPortGetAssociatedDeviceID

VideoPortGetAssociatedDeviceID obtains the child ID for a specified device object.

ULONG
  VideoPortGetAssociatedDeviceID(
    IN PVOID DeviceObject
    );

Parameters

DeviceObject
Points to the child device object, a PDO.

Return Value

VideoPortGetAssociatedDeviceID returns the child ID for the given device object.

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

VideoPortGetAssociatedDeviceID can be used to obtain the child ID for a child device object. For example, this is useful with I2C. See Using I2C to Communicate with a Child Device for more information.

Callers of VideoPortGetAssociatedDeviceID must be running at IRQL = PASSIVE_LEVEL.


VideoPortGetBusData

VideoPortGetBusData returns bus-type-specific configuration information.

ULONG
  VideoPortGetBusData(
    IN PVOID  HwDeviceExtension,
    IN BUS_DATA_TYPE  BusDataType,
    IN ULONG  SlotNumber,
    IN OUT PVOID  Buffer,
    IN ULONG  Offset,
    IN ULONG  Length
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
BusDataType
Specifies the type of bus configuration data to return. The value of this parameter can be Cmos, EisaConfiguration, or PCIConfiguration. However, additional types of bus configuration might be supported in the future. The upper bound on the types supported is always MaximumBusDataType.
SlotNumber
Specifies the location of the device on the bus for a Cmos BusDataType; zero for all other bus types.
Buffer
Points to a buffer into which VideoPortGetBusData returns the configuration information. The contents of the buffer depend on the BusDataType, as follows:
  • If Cmos is specified, the buffer contains the contents of the CMOS (bus number equals zero) or ECMOS (bus number equals one) locations, starting with the location specified for SlotNumber. A miniport driver's HwVidFindAdapter function can determine the number of the bus from the SystemIoBusNumber member of the VIDEO_PORT_CONFIG_INFO input structure.
  • If EisaConfiguration is specified, the buffer contains the CM_EISA_SLOT_INFORMATION structure, followed by zero or more CM_EISA_FUNCTION_INFORMATION structures for the specified slot.
  • If PCIConfiguration is specified, the buffer contains the PCI_COMMON_CONFIG information for the specified slot.
Offset
Specifies the offset, in bytes, into the PCI configuration space that should be retrieved If BusDataType is PCIConfiguration; otherwise zero. See Comments for more information.
Length
Specifies the length, in bytes, of Buffer.

Return Value

VideoPortGetBusData returns the number of bytes of configuration information it has written in Buffer. If the given BusDataType is not valid for the current platform, this function generally returns zero.

When the BusDataType parameter is PCIConfiguration, VideoPortGetBusData can return either of the following values to indicate an error:

Value | Meaning
0 | The PCI bus does not exist.
2 | The PCI bus exists, but Buffer contains the value PCI_INVALID_VENDOR_ID at the PCI_COMMON_CONFIG VendorId member.

Headers

Declared in video.h. Include video.h.

Comments

To obtain only a part of the configuration information, the miniport driver should set Offset to the byte offset of the information needed, and set Length to the number of bytes of the information needed. For example, if only the command register is needed, set Offset to the offset of this register, and set Length to sizeof(USHORT).

The driver should call VideoPortGetAccessRanges rather than VideoPortGetBusData to retrieve its hardware resources.

Callers of VideoPortGetBusData must be running at IRQL = PASSIVE_LEVEL.

See Also

CM_EISA_FUNCTION_INFORMATION, CM_EISA_SLOT_INFORMATION, HwVidQueryDeviceCallback, PCI_COMMON_CONFIG, PCI_SLOT_NUMBER, VIDEO_PORT_CONFIG_INFO, VideoPortGetAccessRanges, VideoPortGetDeviceBase, VideoPortGetDeviceData, VideoPortGetRegistryParameters


VideoPortGetBytesUsed

VideoPortGetBytesUsed is obsolete in Windows 2000 and later.

VideoPortGetBytesUsed determines the size, in bytes, of the buffer associated with a DMA handle.

ULONG
  VideoPortGetBytesUsed(
    IN PVOID  HwDeviceExtension,
    IN PDMA  pDma
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
pDma
Points to a DMA handle. To obtain the appropriate DMA handle, use the value in the OutputBuffer member of the pVrp parameter after VideoPortLockPages returns.

Return Value

VideoPortGetBytesUsed always returns zero.

Headers

Declared in video.h. Include video.h.

Comments

See Video Port Driver Support for Busmaster DMA for information about packet-based and common-buffer DMA transfers.


VideoPortGetCommonBuffer

VideoPortGetCommonBuffer is obsolete in Windows 2000 and later, and is supported only for backward compatibility with existing drivers. In its place, driver writers should use VideoPortAllocateCommonBuffer.

VideoPortGetCommonBuffer allocates and maps system memory so that it is simultaneously accessible from both the processor and a device for common-buffer DMA operations.

PVOID
  VideoPortGetCommonBuffer(
    IN PVOID  HwDeviceExtension,
    IN ULONG  DesiredLength,
    IN ULONG  Alignment,
    OUT PPHYSICAL_ADDRESS  LogicalAddress,
    OUT PULONG  pActualLength,
    IN BOOLEAN  CacheEnabled
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
DesiredLength
Specifies the requested number of bytes of memory.
Alignment
Specifies the requested alignment of the buffer. The video port driver currently ignores this parameter.
LogicalAddress
Points to a variable that receives the logical address to be used by the adapter to access the allocated buffer.
pActualLength
Points to a variable that receives the actual size, in bytes, of the buffer allocated for this request.
CacheEnabled
Specifies whether the allocated memory can be cached.

Return Value

VideoPortGetCommonBuffer returns the base virtual address of the allocated buffer if successful; otherwise, returns NULL if the buffer cannot be allocated.

Headers

Declared in video.h. Include video.h.

Comments

See Video Port Driver Support for Busmaster DMA for information about packet-based and common-buffer DMA transfers.

Callers of VideoPortGetCommonBuffer must be running at IRQL = PASSIVE_LEVEL.

See Also

VideoPortAllocateCommonBuffer


VideoPortGetCurrentIrql

VideoPortGetCurrentIrql gets the current IRQL.

UCHAR
  VideoPortGetCurrentIrql(
    VOID
    );

Parameters

None

Return Value

VideoPortGetCurrentIrql returns the current IRQL.

Headers

Declared in video.h. Include video.h.

Comments

Callers of VideoPortGetCurrentIrql can be running at any IRQL.


VideoPortGetDeviceBase

VideoPortGetDeviceBase maps a range of bus-relative device memory or I/O addresses into the system (kernel) address space.

PVOID
  VideoPortGetDeviceBase(
    IN PVOID  HwDeviceExtension,
    IN PHYSICAL_ADDRESS  IoAddress,
    IN ULONG  NumberOfUchars,
    IN UCHAR  InIoSpace
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
IoAddress
Specifies the base physical address of the range to be mapped. This bus-relative value is obtained by calling VideoPortGetDeviceData, VideoPortGetRegistryParameters, or VideoPortGetAccessRanges. Otherwise, this value is a driver-supplied default base address for the device memory or I/O ports.

The range described by IoAddress and NumberOfUchars must have been successfully claimed in the registry with a preceding call to VideoPortVerifyAccessRanges or VideoPortGetAccessRanges.

NumberOfUchars
Specifies the number of bytes, starting at the given IoAddress, to be mapped.
InIoSpace
Indicates the location of the IoAddress range. This parameter can be one of the following values, or certain bitwise combinations of these values:
Value | Meaning
VIDEO_MEMORY_SPACE_DENSE | Obsolete.
VIDEO_MEMORY_SPACE_IO | The indicated address ranges are in system I/O space rather than in memory space.
VIDEO_MEMORY_SPACE_MEMORY | The indicated address ranges are in memory space rather than in system I/O space.
VIDEO_MEMORY_SPACE_P6CACHE | The processor aggregates a sequence of write operations and sends them to a given cache line. The processor then flushes the cache. This flag is meaningful only when VIDEO_MEMORY_SPACE_IO is not set.

Return Value

VideoPortGetDeviceBase returns a mapped logical base address that can be used with the VideoPortRead Xxx, VideoPortWrite Xxx, and all VideoPort..Memory functions except VideoPortMapMemory and VideoPortUnmapMemory. If the given bus-relative range cannot be mapped, it returns NULL.

Headers

Declared in video.h. Include video.h.

Comments

After VideoPortGetDeviceBase has performed the mapping, the miniport driver can communicate with its adapter by calling the VideoPortRead/Write Xxx functions, using the mapped logical addresses. A miniport driver also must use mapped logical addresses to call VideoPortCompareMemory, VideoPortMoveMemory, VideoPortZeroDeviceMemory, and VideoPortZeroMemory. VideoPortGetDeviceBase must be called from the miniport driver's HwVidFindAdapter, HwVidQueryDeviceCallback, or HwVidQueryNamedValueCallback function.

Both the mapped base address returned by VideoPortGetDeviceBase and length of the mapped access range should be stored for later use in the HwDeviceExtension before HwVidFindAdapter returns control.

Access to the mapped address space must follow these rules:

  • If the input value for InIoSpace is VIDEO_MEMORY_SPACE_IO, indicating that the address is in I/O space, the returned mapped logical address should be used with the VideoPortRead/WritePort Xxx and VideoPortRead/WritePortBuffer Xxx functions where Xxx is one of Uchar, Ushort, or Ulong.
  • If the input value for InIoSpace is VIDEO_MEMORY_SPACE_MEMORY, indicating the address is not in I/O space but in memory space, the returned mapped logical address should be used with the VideoPortRead/WriteRegister Xxx and VideoPortRead/WriteRegisterBuffer Xxx functions, where Xxx is one of Uchar, Ushort, or Ulong.
  • The driver must not access addresses outside the range delimited by the given NumberOfUchars.

If a miniport driver does not support an adapter for which it has mapped a logical range, it must call VideoPortFreeDeviceBase to unmap the previously mapped range from the system address space, and then release its claims on the range in the registry using VideoPortGetAccessRanges or VideoPortVerifyAccessRanges, before it returns control to the DriverEntry function.

Callers of VideoPortGetDeviceBase must be running at IRQL = PASSIVE_LEVEL.

See Also

HwVidFindAdapter, HwVidQueryDeviceCallback, HwVidQueryNamedValueCallback, VideoPortCompareMemory, VideoPortFreeDeviceBase, VideoPortGetAccessRanges, VideoPortGetDeviceData, VideoPortGetRegistryParameters, VideoPortMoveMemory, VideoPortRead Xxx, VideoPortVerifyAccessRanges, VideoPortWrite Xxx, VideoPortZeroDeviceMemory, VideoPortZeroMemory


VideoPortGetDeviceData

VideoPortGetDeviceData retrieves system-detected configuration information from the ..\Machine\Hardware\Description tree in the registry. This information is bus-specific or adapter-specific and stored in the registry by the system loader or the HAL.

VP_STATUS
  VideoPortGetDeviceData(
    IN PVOID  HwDeviceExtension,
    IN VIDEO_DEVICE_DATA_TYPE  DeviceDataType,
    IN PMINIPORT_QUERY_DEVICE_ROUTINE  CallbackRoutine,
    IN PVOID  Context
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
DeviceDataType
Specifies the type of data being requested as a VIDEO_DEVICE_DATA_TYPE value, typically one of VpBusData, VpControllerData, or VpMonitorData.

The VpControllerData and VpMonitorData values are relevant only on ARC-compliant platforms. Miniport drivers of x86-type video adapters generally specify VpBusData, particularly for adapters on EISA buses. The VpMachineData value is reserved for future use.

CallbackRoutine
Points to a driver-supplied HwVidQueryDeviceCallback function to be called with the requested information.
Context
Points to a caller-determined context parameter to be passed to the CallbackRoutine. It typically points to the VIDEO_PORT_CONFIG_INFO buffer.

Return Value

VideoPortGetDeviceData returns NO_ERROR if it successfully called the miniport driver's HwVidQueryDeviceCallback function with configuration information.

Headers

Declared in video.h. Include video.h.

Comments

VideoPortGetDeviceData cannot be called from a miniport driver's HwVidInterrupt or HwVidTimer functions, or from VideoPortQueueDpc, or from a callback to VideoPortSynchronizeExecution.

The registry tree from which VideoPortGetDeviceData retrieves configuration information is volatile; that is, it is re-created by the system loader or HAL every time the system is loaded. Because this information is collected and stored early in the boot process, the bus-relative configuration information returned by VideoPortGetBusData can be more complete.

Callers of VideoPortGetDeviceData must be running at IRQL = PASSIVE_LEVEL.

See Also

HwVidFindAdapter, HwVidQueryDeviceCallback, VIDEO_PORT_CONFIG_INFO, VideoPortGetRegistryParameters


VideoPortGetDmaAdapter

VideoPortGetDmaAdapter returns a pointer to a VP_DMA_ADAPTER structure, which is used in subsequent calls to other DMA-related functions.

PVP_DMA_ADAPTER
  VideoPortGetDmaAdapter(
    IN PVOID  HwDeviceExtension,
    IN PVP_DEVICE_DESCRIPTION  VpDeviceDescription
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
VpDeviceDescription
Points to a VP_DEVICE_DESCRIPTION structure, which describes the attributes of the physical device.

Return Value

VideoPortGetDmaAdapter returns a pointer to a VP_DMA_ADAPTER structure on success; if it is unsuccessful in obtaining information about the DMA adapter, it returns NULL.

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

Callers of VideoPortGetDmaAdapter must be running at IRQL = PASSIVE_LEVEL.

See Also

VideoPortStartDma, VideoPortPutDmaAdapter, VideoPortCompleteDma, VP_DEVICE_DESCRIPTION


VideoPortGetDmaContext

VideoPortGetDmaContext is obsolete in Windows 2000 and later.

VideoPortGetDmaContext gets the context previously associated with the specified DMA handle.

PVOID
  VideoPortGetDmaContext(
    IN PVOID  HwDeviceExtension,
    IN PDMA  pDma
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
pDma
Points to a DMA handle. To obtain the appropriate DMA handle, use the value in the OutputBuffer member of the pVrp parameter after VideoPortLockPages returns.

Return Value

VideoPortGetDmaContext always returns NULL.

Headers

Declared in video.h. Include video.h.

Comments

See Video Port Driver Support for Busmaster DMA for information about packet-based and common-buffer DMA transfers.


VideoPortGetMdl

VideoPortGetMdl is obsolete in Windows 2000 and later.

VideoPortGetMdl retrieves the memory descriptor list (MDL) that represents the page table of the locked buffer.

PVOID
  VideoPortGetMdl(
    IN PVOID  HwDeviceExtension,
    IN PDMA  pDma
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
pDma
Is a handle to the DMA context being queried. This handle was obtained from VideoPortLockPages or VideoPortDoDma.

Return Value

VideoPortGetMdl returns pDma, for compatibility reasons.

Headers

Declared in video.h. Include video.h.

Comments

See Video Port Driver Support for Busmaster DMA for information about packet-based and common-buffer DMA transfers.


VideoPortGetRegistryParameters

VideoPortGetRegistryParameters retrieves device-specific configuration information under the adapter key in the registry at startup.

VP_STATUS
  VideoPortGetRegistryParameters(
    IN PVOID  HwDeviceExtension,
    IN PWSTR  ParameterName,
    IN UCHAR  IsParameterFileName,
    IN PMINIPORT_GET_REGISTRY_ROUTINE  CallbackRoutine,
    IN PVOID  Context
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
ParameterName
Points to a zero-terminated Unicode string that names the value entry to be retrieved from the registry. See the Comments section for more information.
IsParameterFileName
If the value is TRUE, the data value normally returned is treated as a file name. In that case, the buffered contents of that file are returned, rather than the parameter itself.
CallbackRoutine
Points to the miniport driver's HwVidQueryNamedValueCallback function.
Context
Points to a caller-determined context parameter to be passed to the CallbackRoutine, typically the VIDEO_PORT_CONFIG_INFO buffer.

Return Value

VideoPortGetRegistryParameters returns NO_ERROR if it successfully collected the requested information and called the miniport driver's HwVidQueryNamedValueCallback function; otherwise returns ERROR_INVALID_PARAMETER.

Headers

Declared in video.h. Include video.h.

Comments

VideoPortGetRegistryParameters cannot be called from a miniport driver's HwVidInterrupt or HwVidTimer functions, or from VideoPortQueueDpc, or from a callback to VideoPortSynchronizeExecution.

For Windows XP and later operating system versions, the ParameterName parameter can contain a path that references a value name one or more levels below the adapter key. For example, the string "SubKey1\Value1" can be used to obtain the value entry for the Value1 value number under the SubKey1 subkey.

The registry key from which VideoPortGetRegistryParameters retrieves configuration information cannot contain any information about the corresponding display driver, because miniport driver HwVidFindAdapter functions execute before any display driver is loaded.

Miniport drivers should not query configuration information stored in the DefaultSettings entries, which may not be supported in later versions of the operating system.

Callers of VideoPortGetRegistryParameters must be running at IRQL = PASSIVE_LEVEL.

See Also

HwVidFindAdapter, HwVidInitialize, HwVidQueryDeviceCallback, HwVidQueryNamedValueCallback, VIDEO_PORT_CONFIG_INFO, VideoPortGetDeviceData, VideoPortSetRegistryParameters


VideoPortGetRomImage

VideoPortGetRomImage reads the device's read-only memory (ROM).

PVOID
  VideoPortGetRomImage(
    IN PVOID  HwDeviceExtension,
    IN PVOID  Unused1,
    IN ULONG  Unused2,
    IN ULONG  Length
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
Unused1
Is currently ignored by the video port driver; should be set to NULL.
Unused2
Is currently ignored by the video port driver; should be set to zero.
Length
Specifies either the number of bytes of ROM data that the video port driver should read and return, or zero.

Return Value

VideoPortGetRomImage returns a pointer to a buffer containing the device's ROM (BIOS) data on success; otherwise, returns NULL to indicate either there was insufficient memory for the operation, or the device's ROM could not be accessed.

Headers

Declared in video.h. Include video.h.

Comments

The video port driver allocates a buffer of Length bytes and fills it with data read from the device's ROM. The video port driver always reads Length bytes from the beginning of the device's ROM.

If a miniport driver calls VideoPortGetRomImage multiple times, the video port driver will free the buffer from a previous call before allocating and returning a buffer in the current call. Consequently, a miniport driver must only reference the pointer returned by this call to VideoPortGetRomImage.

The miniport driver can free the buffer allocated by the video port driver by calling VideoPortGetRomImage with a Length of zero.

Callers of VideoPortGetRomImage must be running at IRQL = PASSIVE_LEVEL.

See Also

VideoPortScanRom


VideoPortGetVersion

The VideoPortGetVersion function gets version information about the currently running operating system.

VP_STATUS
  VideoPortGetVersion(
    IN PVOID  HwDeviceExtension,
    IN OUT PVPOSVERSIONINFO  pVpOsVersionInfo
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
pVpOsVersionInfo
Points to a VPOSVERSIONINFO structure that will receive the operating system version information. The caller should set the Size member of the VPOSVERSIONINFO structure to the size, in bytes, of that structure.

Return Value

VideoPortGetVersionInfo returns NO_ERROR if it successfully obtained the operating system version information. If the Size member of the VPOSVERSIONINFO does not contains the correct size of this structure, the function returns ERROR_INVALID_PARAMETER

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

Callers of VideoPortGetVersion must be running at IRQL = PASSIVE_LEVEL.

See Also

VPOSVERSIONINFO


VideoPortGetVgaStatus

VideoPortGetVgaStatus detects whether the calling device is decoding a VGA I/O address.

VP_STATUS
  VideoPortGetVgaStatus(
    IN PVOID  HwDeviceExtension,
    OUT PULONG  VgaStatus
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
VgaStatus
Points to the resulting VGA status. A value of zero (0) indicates that VGA is not enabled; a value of one (1) indicates that VGA is enabled.

Return Value

VideoPortGetVgaStatus returns one of the following values:

NO_ERROR
The function completed successfully.
ERROR_INVALID_FUNCTION
The device was not a PCI device.

Headers

Declared in video.h. Include video.h.

Comments

The VideoPortGetVgaStatus function is mainly used to determine whether a device is the sole VGA-enabled device in a multiple monitor system.

Callers of VideoPortGetVgaStatus must be running at IRQL = PASSIVE_LEVEL.


VideoPortInitialize

VideoPortInitialize performs part of the miniport driver initialization, allocating system resources for the miniport driver.

ULONG
  VideoPortInitialize(
    IN PVOID  Argument1,
    IN PVOID  Argument2,
    IN PVIDEO_HW_INITIALIZATION_DATA  HwInitializationData,
    IN PVOID  HwContext
    );

Parameters

Argument1
A pointer with which the operating system called DriverEntry.
Argument2
A second pointer with which the operating system called DriverEntry.
HwInitializationData
Points to the VIDEO_HW_INITIALIZATION_DATA structure on the stack. The miniport driver's DriverEntry routine zero-initialized this structure and then filled it in with driver-specific configuration information describing a video adapter that the miniport driver can support.
HwContext
Must be NULL.

Return Value

VideoPortInitialize returns the final status of the initialization operation.

Headers

Declared in video.h. Include video.h.

Comments

Every video miniport driver must call VideoPortInitialize from its DriverEntry function. DriverEntry can call VideoPortInitialize only after it has first zero-initialized and then set up the VIDEO_HW_INITIALIZATION_DATA structure. VideoPortInitialize can be called only from a miniport driver's DriverEntry function.

The VideoPortInitialize function:

  • Checks the validity of the miniport driver's VIDEO_HW_INITIALIZATION_DATA specifications.
  • Allocates memory for and zero-initializes a VIDEO_PORT_CONFIG_INFO structure.
  • Fills in as much adapter configuration information as it can in VIDEO_PORT_CONFIG_INFO.
  • Fills in some of the public members of the device object created by the system to represent the graphics adapter. The video port driver manages the device objects, therefore, the miniport driver need not be concerned with device object details.
  • Allocates memory for, and zero-initializes the device extension of, the device object. A device extension is each miniport driver's primary and only global storage area for adapter-specific state information. The miniport driver specifies the size of the device extension in the HwDeviceExtensionSize member of VIDEO_HW_INITIALIZATION_DATA. The video port driver passes this device extension to most of the miniport driver functions that it calls.
  • Collects and stores pertinent information in the device extension.

The miniport driver's DriverEntry routine propagates the value returned by VideoPortInitialize back to its caller. Miniport drivers should not use this return value.

Callers of VideoPortInitialize must be running at IRQL = PASSIVE_LEVEL.

See Also

DriverEntry, HwVidFindAdapter, HwVidInitialize, VIDEO_HW_INITIALIZATION_DATA, VIDEO_PORT_CONFIG_INFO, VideoPortZeroMemory


VideoPortInt10

VideoPortInt10 performs the equivalent of an MS-DOS INT10 operation, such as setting the video mode. VideoPortInt10 runs the BIOS ROM code on the device.

VP_STATUS
  VideoPortInt10(
    IN PVOID  HwDeviceExtension,
    IN PVIDEO_X86_BIOS_ARGUMENTS  BiosArguments
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
BiosArguments
Points to a structure containing values for the x86 registers that should be set before making the BIOS call. The miniport driver should set any unused registers to zero. All values set up in the VIDEO_X86_BIOS_ARGUMENTS structure are interpreted as immediate values.

Return Value

VideoPortInt10 returns NO_ERROR if it successfully called the given BIOS INT10 routine; otherwise, it returns an error status.

Headers

Declared in video.h. Include video.h.

Comments

Generally, VGA-compatible miniport drivers, which support full-screen MS-DOS applications on x86-based machines, call VideoPortInt10. Such a driver's HwVidFindAdapter function must have set up the VdmPhysicalVideoMemoryAddress and VdmPhysicalVideoMemoryLength for the range in the VIDEO_PORT_CONFIG_INFO structure.

However, other video miniport drivers also can call this function.

Because VideoPortInt10 interprets the BiosArgument parameter values as immediate values, the caller cannot pass in or retrieve data from a memory buffer with this function.

Callers of VideoPortInt10 must be running at IRQL = PASSIVE_LEVEL.

See Also

HwVidFindAdapter, VIDEO_PORT_CONFIG_INFO, VIDEO_X86_BIOS_ARGUMENTS, VideoPortGetDeviceBase


VideoPortInterlockedDecrement

VideoPortInterlockedDecrement decrements a caller-supplied variable as an atomic operation.

LONG FASTCALL
  VideoPortInterlockedDecrement(
    IN PLONG  Addend
    );

Parameters

Addend
Points to the variable to be decremented.

Return Value

VideoPortInterlockedDecrement returns the decremented value.

Headers

Declared in video.h. Include video.h.

Comments

When possible and whenever appropriate, VideoPortInterlockedDecrement is implemented inline by the compiler. It can be safely used on pageable data.

This function is atomic only with respect to other VideoPortInterlocked Xxx calls.

Callers of VideoPortInterlockedDecrement can be running at any IRQL.

See Also

VideoPortInterlockedIncrement, VideoPortInterlockedExchange


VideoPortInterlockedExchange

VideoPortInterlockedExchange locks or unlocks a block of memory by setting a user-defined lock variable to TRUE or FALSE, respectively. It returns the previously-held value of the lock variable.

LONG FASTCALL
  VideoPortInterlockedExchange(
    IN OUT PLONG  Target,
    IN LONG  Value
    );

Parameters

Target
Points to a user-defined lock variable that is used to control access to a memory buffer.
Value
Specifies the value to be stored in Target, which indicates whether the memory buffer is to be locked or unlocked. Use TRUE to lock the memory buffer, and FALSE to unlock the memory buffer.

Return Value

VideoPortInterlockedExchange returns the value that Target had prior to the function call.

Headers

Declared in video.h. Include video.h.

Comments

VideoPortInterlockedExchange can be used to prevent DMA common-buffer contention in multiple-processor systems.

When the buffer is not being read from or written to, the lock variable should have a value of FALSE. A subsequent call to VideoPortInterlockedExchange with its Target parameter set to TRUE resets the lock variable to TRUE, after which this function returns FALSE. The buffer is now locked, preventing access by other threads. When the current operations on the buffer are complete, unlock the buffer with a call to VideoPortInterlockedExchange with its Target parameter set to FALSE.

Callers of VideoPortInterlockedExchange can be running at any IRQL.

See Also

VideoPortInterlockedIncrement, VideoPortInterlockedDecrement, VideoPortGetCommonBuffer


VideoPortInterlockedIncrement

VideoPortInterlockedIncrement increments a caller-supplied variable as an atomic operation.

LONG FASTCALL
  VideoPortInterlockedIncrement(
    IN PLONG  Addend
    );

Parameters

Addend
Points to the variable to be incremented.

Return Value

VideoPortInterlockedIncrement returns the incremented value.

Headers

Declared in video.h. Include video.h.

Comments

When possible and whenever appropriate, VideoPortInterlockedIncrement is implemented inline by the compiler. It can be safely used on pageable data.

This function is atomic only with respect to other VideoPortInterlocked Xxx calls.

Callers of VideoPortInterlockedIncrement can be running at any IRQL.

See Also

VideoPortInterlockedDecrement, VideoPortInterlockedExchange


VideoPortLockBuffer

VideoPortLockBuffer probes the specified buffer, makes the buffer's memory pages resident in memory, and locks the physical pages mapped by the virtual address range.

PVOID
  VideoPortLockBuffer(
    IN PVOID  HwDeviceExtension,
    IN PVOID  BaseAddress,
    IN ULONG  Length,
    IN VP_LOCK_OPERATION  Operation
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
BaseAddress
Specifies the virtual address of the buffer to be locked.
Length
Specifies the length in bytes of the buffer to be locked.
Operation
Specifies the type of operation for which the caller wants the access rights probed and the pages locked. The operation can be one of the following: VpReadAccess, VpWriteAccess, or VpModifyAccess.

Return Value

Returns a pointer to a memory descriptor list (MDL), or a NULL pointer if the MDL for the memory to be locked cannot be allocated.

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

To unlock the buffer, the video miniport should call VideoPortUnlockBuffer.

Callers of VideoPortLockBuffer must be running at IRQL = PASSIVE_LEVEL.

See Also

VideoPortUnlockBuffer


VideoPortLockPages

VideoPortLockPages is obsolete in Windows 2000 and later. Use VideoPortLockBuffer in place of this function.

VideoPortLockPages locks the specified virtual memory and possibly performs part or all of a DMA transfer.

BOOLEAN
  VideoPortLockPages(
    IN PVOID  HwDeviceExtension,
    IN OUT PVIDEO_REQUEST_PACKET  pVrp,
    IN OUT PEVENT  pUEvent,
    IN PEVENT  pDisplayEvent,
    IN DMA_FLAGS  DmaFlags
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
pVrp
Points to a VIDEO_REQUEST_PACKET structure. The miniport driver must have set InputBuffer and InputBufferLength to contain the virtual address and the size in bytes, respectively, of the memory to be locked for the transfer. This memory was allocated by the display driver and passed to the miniport driver through an IOCTL. The video port returns a pointer to and the size in bytes of the scatter/gather list in OutputBuffer and OutputBufferLength, respectively.
pUEvent
Points to a mapped user event that is to be set by the miniport driver, or NULL. The user event was mapped by the display driver and passed to the miniport driver through an IOCTL.
pDisplayEvent
Points to an event that is to be set by the miniport driver, or NULL. This event was created by and received from the display driver through an IOCTL.
DmaFlags
Specifies the action to be performed. This parameter must be one of the following values:
Value | Meaning
VideoPortDmaInitOnly | VideoPortLockPages locks the requested memory, but does not call HwVidStartDma to start the DMA transfer. The system will try to keep the memory locked.
VideoPortKeepPagesLocked | VideoPortLockPages takes no action.
VideoPortUnlockAfterDma | VideoPortLockPages takes no action.

Return Value

VideoPortLockPages returns TRUE upon successful completion of the action requested of it. It returns FALSE if the DmaFlags parameter is not equal to VideoPortDmaInitOnly.

Headers

Declared in video.h. Include video.h.

Comments

See Video Port Driver Support for Busmaster DMA for information about packet-based and common-buffer DMA transfers.

VideoPortLockPages cannot be called from an ISR or DPC.

See Also

VideoPortLockBuffer


VideoPortLogError

VideoPortLogError logs errors to the system event log when a miniport driver detects a hardware error condition during I/O operations.

VOID
  VideoPortLogError(
    IN PVOID  HwDeviceExtension,
    IN PVIDEO_REQUEST_PACKET  Vrp  OPTIONAL,
    IN VP_STATUS  ErrorCode,
    IN ULONG  UniqueId
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
Vrp
Points to the video request packet (VRP) if one is associated with the error; otherwise NULL.
ErrorCode
Specifies a miniport driver-defined error code that indicates the type of hardware error.
UniqueId
Specifies a unique identifier for the error. This value differentiates the current error from other errors with the same ErrorCode. For some miniport drivers, this identifies the line of code where the error was detected; for others, it is a value returned by the hardware.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

Miniport drivers should call VideoPortLogError to notify the user if the driver encounters unusual hardware errors during normal operations. Posting such errors to the system event log warns the user that the video adapter might be failing so the user can replace (or reconfigure) the adapter before a total hardware failure occurs.

However, miniport drivers should not log errors, such as "failed to detect hardware," that occur frequently during normal operation.

VideoPortLogError can be called from a miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function.

Callers of VideoPortLogError must be running at IRQL <= DIRQL.

See Also

VideoDebugPrint


VideoPortMapBankedMemory

VideoPortMapBankedMemory is obsolete, and is supported only for Windows NT 4.0 and previous drivers. Windows 2000 and later drivers must use VideoPortMapMemory.

VideoPortMapBankedMemory remaps a bus-relative physical range of video memory into the corresponding display driver's virtual address space in response to a VRP with the IoControlCode member set to IOCTL_VIDEO_SHARE_VIDEO_MEMORY or IOCTL_VIDEO_MAP_VIDEO_MEMORY.

VP_STATUS
  VideoPortMapBankedMemory(
    IN PVOID  HwDeviceExtension,
    IN PHYSICAL_ADDRESS  PhysicalAddress,
    IN OUT PULONG  Length,
    PULONG  InIoSpace,
    PVOID  *VirtualAddress,
    ULONG  BankLength,
    UCHAR  ReadWriteBank,
    PBANKED_SECTION_ROUTINE  BankRoutine,
    PVOID  Context
    );

VideoPortMapBankedMemory remaps a bus-relative physical range of video memory into the corresponding display driver's virtual address space in response to a VRP with the IoControlCode member set to IOCTL_VIDEO_SHARE_VIDEO_MEMORY or IOCTL_VIDEO_MAP_VIDEO_MEMORY.

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
PhysicalAddress
Specifies the bus-relative base address of the range to be mapped.
Length
Points to a variable specifying the total number of bytes of device memory to be mapped (regardless of bank size). VideoPortMapBankedMemory returns the actual size of the memory mapped, which can be rounded to a system-determined alignment boundary, in this parameter. However, the miniport and display drivers cannot access memory outside the range delimited by the input value at Length.
InIoSpace
Indicates the location of the range. This parameter can be one of the following values:
Value | Meaning
VIDEO_MEMORY_SPACE_DENSE | Obsolete
VIDEO_MEMORY_SPACE_IO | The range is in system I/O space rather than in memory space.
VIDEO_MEMORY_SPACE_MEMORY | The range is in memory space rather than in system I/O space.
VIDEO_MEMORY_SPACE_P6CACHE | The processor aggregates a sequence of write operations and sends them to a given cache line. The processor then flushes the cache. This flag is meaningful only when VIDEO_MEMORY_SPACE_IO is not set.
VIDEO_MEMORY_SPACE_USER_MODE | Indicates that the address range specified should be mapped into user mode rather than kernel mode. This flag is meaningful only when VIDEO_MEMORY_SPACE_IO is not set.

VirtualAddress
Is a handle to the process into which the memory must be mapped, or NULL. NULL specifies that the port driver should map the logical memory range at any location in the address space of the current process. Otherwise, this handle can be a value passed in a VRP by the miniport driver's corresponding display driver. On return from a successful call, VideoPortMapBankedMemory resets the variable to the base virtual address to which it has mapped the given PhysicalAddress.
BankLength
Specifies the size of a bank, in bytes.
ReadWriteBank
If set to TRUE the bank is Read\Write; if set to FALSE there are two independent read and write banks.
BankRoutine
Points to a driver-supplied HwVidBankedMemoryCallback function to be called by the Memory Manager when a new bank is accessed by the display driver.
Context
Points to a miniport driver-supplied context that is passed back to the driver when the BankRoutine is called.

Return Value

VideoPortMapBankedMemory returns NO_ERROR if the given logical range was successfully mapped to a user-space virtual range. Otherwise, it can return ERROR_INVALID_PARAMETER.

Headers

Declared in video.h. Include video.h.

Comments

VideoPortMapBankedMemory runs in kernel mode within the same context as the user-mode thread that initiated the call.

VideoPortMapBankedMemory is called by miniport drivers to efficiently manage x86 type devices that are limited to mapping a frame buffer in banks. When this routine returns to the caller, the frame buffer managed by the miniport driver is mapped as a linear frame buffer into the address space of the requesting process (see VirtualAddress parameter). When an access is made to an address in that mapped space, the Memory Manager calls the miniport driver to update the Bank Index Register to point to a new bank that contains the currently referenced address. The Bank Index Register is maintained by the miniport driver in BankRoutine. The correct Bank Index is calculated by the Memory Manager transparently to a display driver and passed to the miniport driver in the callback to BankRoutine.

Callers of VideoPortMapBankedMemory must be running at IRQL = PASSIVE_LEVEL.

See Also

HwVidBankedMemoryCallback, IOCTL_VIDEO_MAP_VIDEO_MEMORY, IOCTL_VIDEO_SHARE_VIDEO_MEMORY, IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY, VIDEO_REQUEST_PACKET, VideoPortMapMemory, VideoPortUnmapMemory


VideoPortMapDmaMemory

VideoPortMapDmaMemory is obsolete in Windows 2000 and later.

VideoPortMapDmaMemory maps a range of memory for use in DMA transfers.

PDMA
  VideoPortMapDmaMemory(
    IN PVOID  HwDeviceExtension,
    IN PVIDEO_REQUEST_PACKET  pVrp,
    IN PHYSICAL_ADDRESS  BoardAddress,
    IN PULONG  Length,
    IN PULONG  InIoSpace,
    IN PVOID  MappedUserEvent,
    IN PVOID  DisplayDriverEvent,
    IN OUT PVOID  *VirtualAddress
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
pVrp
Points to a VIDEO_REQUEST_PACKET.
BoardAddress
Specifies the adapter's beginning address.
Length
Specifies the length, in bytes, of the range of memory.
InIoSpace
Indicates the location of the range. This parameter can be one of the following values:
Value | Meaning
VIDEO_MEMORY_SPACE_DENSE | Memory is densely mapped and linear.
VIDEO_MEMORY_SPACE_IO | The range is in system I/O space. Should not be set by the display driver.
VIDEO_MEMORY_SPACE_MEMORY | The range is in memory space. Should not be set by the display driver.
VIDEO_MEMORY_SPACE_P6CACHE | P6 MTRR caching, which is equivalent to write-combine caching. (kernel and user mode).
VIDEO_MEMORY_SPACE_USER_MODE | Memory pointer for application use.

MappedUserEvent
Is reserved for system use.
DisplayDriverEvent
Is reserved for system use.
VirtualAddress
Is reserved for system use.

Return Value

VideoPortMapDmaMemory always returns NULL.

Headers

Declared in video.h. Include video.h.

Comments

See Video Port Driver Support for Busmaster DMA for information about packet-based and common-buffer DMA transfers.


VideoPortMapMemory

VideoPortMapMemory remaps a bus-relative physical range of video memory into the corresponding display driver's virtual address space. This occurs in response to a VRP with the IoControlCode member set to IOCTL_VIDEO_MAP_VIDEO_MEMORY.

VP_STATUS
  VideoPortMapMemory(
    IN PVOID  HwDeviceExtension,
    IN PHYSICAL_ADDRESS  PhysicalAddress,
    IN OUT PULONG  Length,
    IN PULONG  InIoSpace,
    IN OUT PVOID  *VirtualAddress
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
PhysicalAddress
Specifies the bus-relative base address of the range to be mapped.
Length
Points to a variable specifying the number of bytes of device memory to be mapped. VideoPortMapMemory returns the actual size of the memory mapped, which can be rounded to a system-determined alignment boundary, in this parameter. However, the miniport and display drivers cannot access memory outside the range delimited by the input value at Length.
InIoSpace
Indicates the location of the range. This parameter can be one of the following values, or certain bitwise combinations of these values:
Value | Meaning
VIDEO_MEMORY_SPACE_DENSE | Obsolete.
VIDEO_MEMORY_SPACE_IO | The indicated address ranges are in system I/O space rather than in memory space.
VIDEO_MEMORY_SPACE_MEMORY | The indicated address ranges are in memory space rather than in system I/O space.
VIDEO_MEMORY_SPACE_P6CACHE | The processor aggregates a sequence of write operations and sends them to a given cache line. The processor then flushes the cache. This flag is meaningful only when VIDEO_MEMORY_SPACE_IO is not set.
VIDEO_MEMORY_SPACE_USER_MODE | Indicates that the address range specified should be mapped into user mode rather than kernel mode. This flag is meaningful only when VIDEO_MEMORY_SPACE_IO is not set.

VirtualAddress
Is a handle to the process into which the memory must be mapped, or NULL. NULL specifies that the port driver should map the logical memory range at any location in the address space of the current process. Otherwise, this handle can be a value passed in a VRP by the miniport driver's corresponding display driver. On return from a successful call, VideoPortMapMemory resets the variable to the base virtual address to which it has mapped the given PhysicalAddress.

Return Value

VideoPortMapMemory returns NO_ERROR if the given logical range was successfully mapped into the display driver's virtual address space; otherwise, it returns ERROR_INVALID_PARAMETER.

Headers

Declared in video.h. Include video.h.

Comments

VideoPortMapMemory runs in kernel mode within the same context as the user-mode thread that initiated the call.

VideoPortMapMemory should be used by miniport drivers to manage video adapters that allow the video frame buffer to be completely mapped at all times. That is, miniport drivers for adapters that are not restricted to using banks to map a slice at a time can use the more efficient VideoPortMapMemory.

Callers of VideoPortMapMemory must be running at IRQL = PASSIVE_LEVEL.

See Also

IOCTL_VIDEO_MAP_VIDEO_MEMORY, VIDEO_REQUEST_PACKET, VideoPortUnmapMemory


VideoPortMoveMemory

VideoPortMoveMemory copies data from the source location to the destination location in system memory.

VOID
  VideoPortMoveMemory(
    IN PVOID  Destination,
    IN PVOID  Source,
    IN ULONG  Length
    );

Parameters

Destination
Points to the destination location.
Source
Points to the location of the data to copy.
Length
Specifies the number of bytes to copy.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

VideoPortMoveMemory moves memory either forward or backward, aligned or unaligned, in 4-byte blocks, followed by any remaining bytes.

The given Destination and Source must be in a mapped logical range returned by VideoPortGetDeviceBase and/or a system-space RAM address, such as an address on the stack.

Callers of VideoPortMoveMemory can be running at any IRQL if both memory blocks are resident. Otherwise, the caller must be running at IRQL < DISPATCH_LEVEL.

See Also

VideoPortCompareMemory, VideoPortGetDeviceBase, VideoPortZeroDeviceMemory, VideoPortZeroMemory


VideoPortPutDmaAdapter

VideoPortPutDmaAdapter frees a VP_DMA_ADAPTER structure that was previously allocated by a call to VideoPortGetDmaAdapter.

VOID
  VideoPortPutDmaAdapter(
    IN PVOID  HwDeviceExtension,
    IN PVP_DMA_ADAPTER  VpDmaAdapter
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
VpDmaAdapter
Points to the VP_DMA_ADAPTER structure that represents the busmaster adapter.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

A miniport driver should call this function only if it will not use the same VP_DMA_ADAPTER structure again.

Callers of VideoPortPutDmaAdapter must be running at IRQL = PASSIVE_LEVEL.

See Also

VideoPortGetDmaAdapter, VP_DMA_ADAPTER


VideoPortQueryPerformanceCounter

VideoPortQueryPerformanceCounter provides the finest-grained running count available in the system.

LONGLONG
  VideoPortQueryPerformanceCounter(
    IN PVOID  HwDeviceExtension,
    OUT PLONGLONG  PerformanceFrequency  OPTIONAL
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
PerformanceFrequency
Specifies an optional pointer to a variable that is to receive the performance counter frequency.

Return Value

VideoPortQueryPerformanceCounter returns the performance counter value in units of ticks.

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

VideoPortQueryPerformanceCounter always returns a 64-bit integer representing the number of ticks. Accumulating the count begins when the system is booted. The count is in ticks; the frequency is reported by PerformanceFrequency if this optional parameter is supplied.

The resolution of the timer used to accumulate the current count can be obtained by specifying PerformanceFrequency. For example, if the returned PerformanceFrequency is 2 million, each tick is 1/2 millionth of a second. Each 1/x millionth increment of the count corresponds to one second of elapsed time.

VideoPortQueryPerformanceCounter is intended for time-stamping packets or for computing performance and capacity measurements. It is not intended for measuring elapsed time, for computing stalls or waits, or for iterations.

Use this routine as infrequently as possible. Depending on the platform, VideoPortQueryPerformanceCounter can disable system-wide interrupts for a minimal interval. Consequently, calling this routine frequently or repeatedly, as in an iteration, defeats its purpose of returning very fine-grained, running time-stamp information. Calling this routine too frequently can degrade I/O performance for the calling driver and for the system as a whole.

Callers of VideoPortQueryPerformanceCounter can be running at any IRQL.


VideoPortQueryServices

VideoPortQueryServices exposes interfaces to services supported by the video port driver.

VP_STATUS
  VideoPortQueryServices(
    IN PVOID HwDeviceExtension,
    IN VIDEO_PORT_SERVICES ServicesType,
    IN OUT PINTERFACE Interface
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
ServicesType
Is an enumeration of the types of requested services. The requested service type can be VideoPortServicesAGP, VideoPortServicesI2C, or VideoPortServicesInt10.
Interface
Points to an INTERFACE structure, which contains basic information about the requested services. See the following Comments section for more information.

Return Value

If VideoPortQueryServices is able to set Interface to the address of a valid interface for the requested services, this function returns NO_ERROR. If the interface is unsupported or unavailable, VideoPortQueryServices returns an error code.

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

If the ServicesType parameter is set to VideoPortServicesI2C, the Interface parameter must be a pointer to a VIDEO_PORT_I2C_INTERFACE structure, also cast as a pointer to an INTERFACE structure.

Similarly, if the ServicesType parameter is set to VideoPortServicesAGP, the Interface parameter must be a pointer to either a VIDEO_PORT_AGP_INTERFACE structure, or a VIDEO_PORT_AGP_INTERFACE_2 structure, each cast as a pointer to an INTERFACE structure.

The VIDEO_PORT_AGP_INTERFACE and VIDEO_PORT_AGP_INTERFACE_2 structures are nearly identical, except that the latter structure has a member that points to the AgpSetRate function, which is used to reset the transfer rate for an AGP chipset. A video miniport driver querying AGP support should call VideoPortQueryServices first with Interface pointing to a VIDEO_PORT_AGP_INTERFACE_2 structure. If that call fails, the miniport driver can then make another call to VideoPortQueryServices, this time with Interface pointing to a VIDEO_PORT_AGP_INTERFACE structure.

If the ServicesType parameter is set to VideoPortServicesInt10, the Interface parameter must be a pointer to a VIDEO_PORT_INT10_INTERFACE structure, cast as a pointer to an INTERFACE structure.

Callers of VideoPortQueryServices must be running at IRQL = PASSIVE_LEVEL.

See Also

INTERFACE, VIDEO_PORT_AGP_INTERFACE, VIDEO_PORT_AGP_INTERFACE_2, VIDEO_PORT_I2C_INTERFACE, VIDEO_PORT_INT10_INTERFACE, AgpSetRate


VideoPortQuerySystemTime

VideoPortQuerySystemTime obtains the current system time.

VOID
  VideoPortQuerySystemTime(
    OUT PLARGE_INTEGER  CurrentTime
    );

Parameters

CurrentTime
Points to a memory location that will receive the current system time.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

System time is a count of 100-nanosecond intervals since January 1, 1601. System time is typically updated approximately every ten milliseconds. This value is computed for the GMT time zone. To adjust this value for the local time zone use ExSystemTimeToLocalTime.

Callers of VideoPortQuerySystemTime can be running at any IRQL.

See Also

VideoPortQueryPerformanceCounter


VideoPortQueueDpc

VideoPortQueueDpc allows a miniport driver to queue a DPC.

BOOLEAN
  VideoPortQueueDpc(
    IN PVOID  HwDeviceExtension,
    IN PMINIPORT_DPC_ROUTINE  CallbackRoutine,
    IN PVOID  Context
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
CallbackRoutine
Points to the miniport driver's PMINIPORT_DPC_ROUTINE to be called when the DPC is scheduled. The callback routine must be non-paged.
Context
Points to the miniport driver-supplied context that will be passed to CallbackRoutine.

Return Value

VideoPortQueueDpc returns TRUE if the DPC is successfully queued, and FALSE otherwise.

Callers of VideoPortQueueDpc can be running at any IRQL.

See Also

PMINIPORT_DPC_ROUTINE


VideoPortReadPortBufferUchar

VideoPortReadPortBufferUchar reads a number of bytes from a mapped I/O port and writes them into a buffer.

VOID
  VideoPortReadPortBufferUchar(
    IN PUCHAR  Port,
    OUT PUCHAR  Buffer,
    IN ULONG  Count
    );

Parameters

Port
Points to the I/O port. The given Port must be in a mapped I/O-space range returned by VideoPortGetDeviceBase.
Buffer
Points to a buffer into which the UCHAR values are written.
Count
Specifies the number of bytes to be written to the buffer.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

The buffer must be large enough to contain at least the specified number of bytes.

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortReadPortBufferUchar.

Callers of VideoPortReadPortBufferUchar can be running at any IRQL, provided that the memory pointed to by the Buffer parameter is resident and that pointed to by the Port parameter is resident, mapped device memory.

See Also

HwVidInterrupt, HwVidSynchronizeExecutionCallback, VideoPortGetDeviceBase


VideoPortReadPortBufferUlong

VideoPortReadPortBufferUlong reads a number of ULONG values from a mapped I/O port and writes them into a buffer.

VOID
  VideoPortReadPortBufferUlong(
    IN PULONG  Port,
    OUT PULONG  Buffer,
    IN ULONG  Count
    );

Parameters

Port
Points to the I/O port. The given Port must be in a mapped I/O-space range returned by VideoPortGetDeviceBase.
Buffer
Points to a buffer into which the ULONG values are written.
Count
Specifies the number of ULONG values to be written to the buffer.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

The buffer must be large enough to contain at least the specified number of ULONG values.

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortReadPortBufferUlong.

Callers of VideoPortReadPortBufferUlong can be running at any IRQL, provided that the memory pointed to by the Buffer parameter is resident and that pointed to by the Port parameter is resident, mapped device memory.

See Also

HwVidInterrupt, HwVidSynchronizeExecutionCallback, VideoPortGetDeviceBase


VideoPortReadPortBufferUshort

VideoPortReadPortBufferUshort reads a number of USHORT values from a mapped I/O port and writes them into a buffer.

VOID
  VideoPortReadPortBufferUshort(
    IN PUSHORT  Port,
    OUT PUSHORT  Buffer,
    IN ULONG  Count
    );

Parameters

Port
Points to the port. The given Port must be in a mapped I/O-space range returned by VideoPortGetDeviceBase.
Buffer
Points to a buffer into which an array of USHORT values is written.
Count
Specifies the number of USHORT values to be written to the buffer.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

The buffer must be large enough to contain at least the specified number of USHORT values.

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortReadPortBufferUshort.

Callers of VideoPortReadPortBufferUshort can be running at any IRQL, provided that the memory pointed to by the Buffer parameter is resident and that pointed to by the Port parameter is resident, mapped device memory.

See Also

HwVidInterrupt, HwVidSynchronizeExecutionCallback, VideoPortGetDeviceBase


VideoPortReadPortUchar

VideoPortReadPortUchar reads a byte from a mapped I/O port.

UCHAR
  VideoPortReadPortUchar(
    IN PUCHAR  Port
    );

Parameters

Port
Points to the port. The given Port must be in a mapped I/O-space range returned by VideoPortGetDeviceBase.

Return Value

VideoPortReadPortUchar returns the byte read from the adapter.

Headers

Declared in video.h. Include video.h.

Comments

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortReadPortUchar.

Callers of VideoPortReadPortUchar can be running at any IRQL, provided that the memory pointed to by the Port parameter is resident, mapped device memory.

See Also

HwVidInterrupt, HwVidSynchronizeExecutionCallback, VideoPortGetDeviceBase


VideoPortReadPortUlong

VideoPortReadPortUlong reads a ULONG value from a mapped I/O port.

ULONG
  VideoPortReadPortUlong(
    IN PULONG  Port
    );

Parameters

Port
Points to the port. The given Port must be in a mapped I/O-space range returned by VideoPortGetDeviceBase.

Return Value

VideoPortReadPortUlong returns the ULONG value read from the adapter.

Headers

Declared in video.h. Include video.h.

Comments

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortReadPortUlong.

Callers of VideoPortReadPortUlong can be running at any IRQL, provided that the memory pointed to by the Port parameter is resident, mapped device memory.

See Also

HwVidInterrupt, HwVidSynchronizeExecutionCallback, VideoPortGetDeviceBase


VideoPortReadPortUshort

VideoPortReadPortUshort reads a USHORT value from a mapped I/O port.

USHORT
  VideoPortReadPortUshort(
    IN PUSHORT  Port
    );

Parameters

Port
Points to the port. The given Port must be in a mapped I/O-space range returned by VideoPortGetDeviceBase.

Return Value

VideoPortReadPortUshort returns the USHORT value read from the adapter.

Headers

Declared in video.h. Include video.h.

Comments

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortReadPortUshort.

Callers of VideoPortReadPortUshort can be running at any IRQL, provided that the memory pointed to by the Port parameter is resident, mapped device memory.

See Also

HwVidInterrupt, HwVidSynchronizeExecutionCallback, VideoPortGetDeviceBase


VideoPortReadRegisterBufferUchar

VideoPortReadRegisterBufferUchar reads a number of bytes from a mapped device memory range and writes them into a buffer.

VOID
  VideoPortReadRegisterBufferUchar(
    IN PUCHAR  Register,
    OUT PUCHAR  Buffer,
    IN ULONG  Count
    );

Parameters

Register
Points to the register. The given Register must be in a mapped memory-space range returned by VideoPortGetDeviceBase.
Buffer
Points to a buffer into which the UCHAR values are written.
Count
Specifies the number of bytes to be written to the buffer.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

The buffer must be large enough to contain at least the specified number of bytes.

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortReadRegisterBufferUchar.

Callers of VideoPortReadRegisterBufferUchar can be running at any IRQL, provided that the memory pointed to by the Buffer parameter is resident and that pointed to by the Register parameter is resident, mapped device memory.

See Also

HwVidInterrupt, HwVidSynchronizeExecutionCallback, VideoPortGetDeviceBase


VideoPortReadRegisterBufferUlong

VideoPortReadRegisterBufferUlong reads a number of ULONG values from a mapped device memory range and writes them into a buffer.

VOID
  VideoPortReadRegisterBufferUlong(
    IN PULONG  Register,
    OUT PULONG  Buffer,
    IN ULONG  Count
    );

Parameters

Register
Points to the register. The given Register must be in a mapped memory-space range returned by VideoPortGetDeviceBase.
Buffer
Points to a buffer into which the ULONG values are written.
Count
Specifies the number of ULONG values to be written to the buffer.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

The buffer must be large enough to contain at least the specified number of ULONG values.

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortReadRegisterBufferUlong.

Callers of VideoPortReadRegisterBufferUlong can be running at any IRQL, provided that the memory pointed to by the Buffer parameter is resident and that pointed to by the Register parameter is resident, mapped device memory.

See Also

HwVidInterrupt, HwVidSynchronizeExecutionCallback, VideoPortGetDeviceBase


VideoPortReadRegisterBufferUshort

VideoPortReadRegisterBufferUshort reads a number of USHORT values from a mapped device memory range and writes them into a buffer.

VOID
  VideoPortReadRegisterBufferUshort(
    IN PUSHORT  Register,
    OUT PUSHORT  Buffer,
    IN ULONG  Count
    );

Parameters

Register
Points to the register. The given Register must be in a mapped memory-space range returned by VideoPortGetDeviceBase.
Buffer
Points to a buffer into which the USHORT values are written.
Count
Specifies the number of USHORT values to be written to the buffer.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

The buffer must be large enough to contain at least the specified number of USHORT values.

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortReadRegisterBufferUshort.

Callers of VideoPortReadRegisterBufferUshort can be running at any IRQL, provided that the memory pointed to by the Buffer parameter is resident and that pointed to by the Register parameter is resident, mapped device memory.

See Also

HwVidInterrupt, HwVidSynchronizeExecutionCallback, VideoPortGetDeviceBase


VideoPortReadRegisterUchar

VideoPortReadRegisterUchar reads a byte from a mapped register.

UCHAR
  VideoPortReadRegisterUchar(
    IN PUCHAR  Register
    );

Parameters

Register
Points to the register. The given Register must be in a mapped memory-space range returned by VideoPortGetDeviceBase.

Return Value

VideoPortReadRegisterUchar returns the byte read from the adapter.

Headers

Declared in video.h. Include video.h.

Comments

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortReadRegisterUchar.

Callers of VideoPortReadRegisterUchar can be running at any IRQL, provided that the memory pointed to by the Register parameter is resident, mapped device memory.

See Also

HwVidInterrupt, HwVidSynchronizeExecutionCallback, VideoPortGetDeviceBase


VideoPortReadRegisterUlong

VideoPortReadRegisterUlong reads a ULONG value from a mapped register range.

ULONG
  VideoPortReadRegisterUlong(
    IN PULONG  Register
    );

Parameters

Register
Points to the register. The given Register must be in a mapped memory-space range returned by VideoPortGetDeviceBase.

Return Value

VideoPortReadRegisterUlong returns the ULONG value read from the adapter.

Headers

Declared in video.h. Include video.h.

Comments

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortReadRegisterUlong.

Callers of VideoPortReadRegisterUlong can be running at any IRQL, provided that the memory pointed to by the Register parameter is resident, mapped device memory.

See Also

HwVidInterrupt, HwVidSynchronizeExecutionCallback, VideoPortGetDeviceBase


VideoPortReadRegisterUshort

VideoPortReadRegisterUshort reads a USHORT value from a mapped register range.

USHORT
  VideoPortReadRegisterUshort(
    IN PUSHORT  Register
    );

Parameters

Register
Points to the register. The given Register must be in a mapped memory-space range returned by VideoPortGetDeviceBase.

Return Value

VideoPortReadRegisterUshort returns the USHORT value read from the adapter.

Headers

Declared in video.h. Include video.h.

Comments

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortReadRegisterUshort.

Callers of VideoPortReadRegisterUshort can be running at any IRQL, provided that the memory pointed to by the Register parameter is resident, mapped device memory.

See Also

HwVidInterrupt, HwVidSynchronizeExecutionCallback, VideoPortGetDeviceBase


VideoPortReadStateEvent

VideoPortReadStateEvent returns the current state of a given event object: signaled or nonsignaled.

LONG
  VideoPortReadStateEvent(
    IN PVOID  HwDeviceExtension,
    IN PEVENT  pEvent
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
pEvent
Points to the event object whose state is to be read.

Return Value

VideoPortReadStateEvent returns a nonzero value if the event object is currently in the signaled state. If the event object is in the nonsignaled state, this function returns zero.

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

Callers of VideoPortReadStateEvent must be running at IRQL <= DISPATCH_LEVEL.


VideoPortReleaseBuffer

VideoPortReleaseBuffer is obsolete in Windows 2000 and later. In its place, video miniport drivers should instead use VideoPortFreePool.

VideoPortReleaseBuffer deallocates a block of paged pool memory.

VOID
  VideoPortReleaseBuffer(
    IN PVOID  HwDeviceExtension,
    IN PVOID  Buffer
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
Buffer
Specifies the address of the block of pool memory being deallocated.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

This function releases memory allocated by VideoPortAllocateBuffer. A miniport driver must not access the memory block to which Buffer points after it has been freed.

Callers of VideoPortReleaseBuffer must be running at IRQL = PASSIVE_LEVEL.

See Also

VideoPortAllocateBuffer


VideoPortReleaseCommonBuffer

VideoPortReleaseCommonBuffer frees a common buffer that was previously allocated by VideoPortAllocateCommonBuffer.

VOID
  VideoPortReleaseCommonBuffer(
    IN PVOID  HwDeviceExtension,
    IN PVP_DMA_ADAPTER  VpDmaAdapter,
    IN ULONG  Length,
    IN PHYSICAL_ADDRESS  LogicalAddress,
    IN PVOID  VirtualAddress,
    IN BOOLEAN  CacheEnabled
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
VpDmaAdapter
Points to the VP_DMA_ADAPTER structure that represents the busmaster adapter. This is the structure returned after a call to VideoPortGetDmaAdapter.
Length
Specifies the number of bytes of memory to be freed.
LogicalAddress
Specifies the logical address of the buffer to be freed.
VirtualAddress
Points to the corresponding virtual address of the allocated memory range. This value was obtained in a prior call to VideoPortAllocateCommonBuffer.
CacheEnabled
Indicates whether the allocated memory is cached. A value of TRUE indicates that the allocated memory is cached.

Return Value

None

Headers

Declared in video.h. Include video.h and ntdef.h.

Comments

This function is available in Windows XP and later.

The parameters passed to VideoPortFreeCommonBuffer must match exactly those passed to and returned from VideoPortAllocateCommonBuffer. A driver cannot free only part of an allocated common buffer.

Callers of VideoPortReleaseCommonBuffer must be running at IRQL = PASSIVE_LEVEL.

See Also

VideoPortAllocateCommonBuffer, VideoPortGetDmaAdapter, VP_DMA_ADAPTER


VideoPortReleaseDeviceLock

VideoPortReleaseDeviceLock releases the device lock acquired in a prior call to VideoPortAcquireDeviceLock.

VOID
  VideoPortReleaseDeviceLock(
    IN PVOID  HwDeviceExtension
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

Typically, the video port driver guarantees threaded synchronization into the miniport driver by using of a device lock. However, a miniport driver must perform its own synchronization when being accessed by a child device; that is, a miniport driver must perform synchronization in routines that it exposes through HwVidQueryInterface. The miniport driver does this by calling VideoPortAcquireDeviceLock to acquire the device lock maintained by the video port driver.

The miniport driver should call VideoPortReleaseDeviceLock to release the device lock as quickly as possible.

Callers of VideoPortReleaseDeviceLock must be running at IRQL = PASSIVE_LEVEL.

See Also

HwVidQueryInterface, VideoPortAcquireDeviceLock


VideoPortReleaseSpinLock

VideoPortReleaseSpinLock releases ownership of a given spin lock and restores the original IRQL at which the caller was running.

VOID
  VideoPortReleaseSpinLock(
    IN PVOID  HwDeviceExtension,
    IN PSPIN_LOCK  SpinLock,
    IN UCHAR  NewIrql
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
SpinLock
Points to a memory location that contains the spin lock to be released.
NewIrql
Specifies the IRQL to be restored.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

This call is the inverse of VideoPortAcquireSpinLock. The NewIrql value must be the same as the value pointed to by OldIrql when VideoPortAcquireSpinLock returned.

Callers of VideoPortReleaseSpinLock must be running at IRQL = DISPATCH_LEVEL. On return from this routine, IRQL is restored to the NewIrql value.

See Also

VideoPortAcquireSpinLock


VideoPortReleaseSpinLockFromDpcLevel

VideoPortReleaseSpinLockFromDpcLevel releases the spin lock obtained by a previous call to VideoPortAcquireSpinLockAtDpcLevel.

VOID
  VideoPortReleaseSpinLockFromDpcLevel(
    IN PVOID  HwDeviceExtension,
    IN PSPIN_LOCK  SpinLock,
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
SpinLock
Points to a memory location that contains the spin lock to be released.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

Miniport drivers call VideoPortReleaseSpinLockFromDpcLevel to release a spin lock acquired by calling VideoPortAcquireSpinLockAtDpcLevel.

It is an error to call VideoPortReleaseSpinLockFromDpcLevel if the given spin lock was acquired by calling VideoPortAcquireSpinLock because the caller's original IRQL is not restored, which can cause deadlocks or fatal page faults.

Callers of VideoPortReleaseSpinLockAtDpcLevel must be running at IRQL = DISPATCH_LEVEL.

See Also

VideoPortAcquireSpinLockAtDpcLevel, VideoPortAcquireSpinLock


VideoPortScanRom

VideoPortScanRom performs a case-sensitive search for a specified string in ROM.

BOOLEAN
  VideoPortScanRom(
    PVOID  HwDeviceExtension,
    PUCHAR  RomBase,
    ULONG  RomLength,
    PUCHAR  String
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
RomBase
Specifies the base ROM address at which the search should start. The given RomBase must be in a mapped range returned by VideoPortGetDeviceBase.
RomLength
Specifies the size in bytes of the mapped ROM to be searched.
String
Points to the driver-allocated string to search for.

Return Value

If the string is found, VideoPortScanRom returns TRUE. Otherwise, it returns FALSE.

Headers

Declared in video.h. Include video.h.

Comments

VideoPortScanRom cannot be called from a miniport driver's HwVidInterrupt or HwVidTimer functions, or from VideoPortQueueDpc, or from a callback to VideoPortSynchronizeExecution.

Callers of VideoPortScanRom must be running at IRQL = PASSIVE_LEVEL.

See Also

HwVidFindAdapter, VideoPortGetDeviceBase, VideoPortGetRomImage


VideoPortSetBusData

VideoPortSetBusData sets bus-configuration data for an adapter on a dynamically configurable I/O bus with a published, standard interface.

ULONG
  VideoPortSetBusData(
    IN PVOID  HwDeviceExtension,
    IN BUS_DATA_TYPE  BusDataType,
    IN ULONG  SlotNumber,
    IN PVOID  Buffer,
    IN ULONG  Offset,
    IN ULONG  Length
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
BusDataType
Specifies the type of bus data to be set. Currently, its value can be one of Cmos, EisaConfiguration, or PCIConfiguration. However, additional types of standardized, dynamically configurable buses might be supported in the future. The upper bound on the bus types supported is always MaximumBusDataType.
SlotNumber
For a BusDataType value of Cmos, specifies the location of the device on the bus. This parameter should be zero for all other bus types.
Buffer
Points to a caller-supplied storage area with configuration information specific to BusDataType.

When PCIConfiguration is specified, the buffer contains some or all of the PCI_COMMON_CONFIG information for the given SlotNumber. The specified Offset and Length determine how much information is supplied.

Offset
Specifies the byte offset within the PCI_COMMON_CONFIG structure at which the caller-supplied configuration values begin. A miniport driver can use PCI_COMMON_HDR_LENGTH to specify the offset of the device-specific area in PCI_COMMON_CONFIG.
Length
Specifies the number of bytes in Buffer.

Return Value

VideoPortSetBusData returns the number of bytes of data successfully set for the given SlotNumber. If the given BusDataType is not valid for the current platform or if the supplied information is invalid, VideoPortSetBusData returns zero.

Headers

Declared in video.h. Include video.h.

Comments

Miniport drivers of adapters on a PCI bus seldom call VideoPortSetBusData, unless unusual circumstances or the nature of a particular driver's video adapter requires such a call.

For example, a miniport driver might call VideoPortSetBusData to clear a bit in the PCI status register if its adapter signals a target abort during initialization. If a PCI video adapter must be configured with device-specific data, its driver also calls this function. In either case, such a driver is then likely to call VideoPortGetAccessRanges with a RequestedResources pointer to a driver-supplied array of resource descriptors.

VideoPortSetBusData cannot be called from a miniport driver's HwVidInterrupt or HwVidTimer functions, or from VideoPortQueueDpc, or from a callback to VideoPortSynchronizeExecution.

Callers of VideoPortSetBusData must be running at IRQL = PASSIVE_LEVEL.

See Also

HalSetBusDataByOffset, HwVidFindAdapter, PCI_COMMON_CONFIG, PCI_SLOT_NUMBER, VideoPortGetAccessRanges, VideoPortGetBusData


VideoPortSetBytesUsed

VideoPortSetBytesUsed is obsolete in Windows 2000 and later.

VOID
  VideoPortSetBytesUsed(
    IN PVOID  HwDeviceExtension,
    IN OUT PDMA  pDma,
    IN ULONG  BytesUsed
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
pDma
Points to a DMA handle. To obtain the appropriate DMA handle, use the value in the OutputBuffer member of the pVrp parameter after VideoPortLockPages returns.
BytesUsed
Specifies the number of bytes written to the buffer.

Return Value

None

Headers

Declared in video.h. Include video.h.

See Also

VideoPortGetBytesUsed, VIDEO_REQUEST_PACKET


VideoPortSetDmaContext

VideoPortSetDmaContext is obsolete in Windows 2000 and later.

VOID
  VideoPortSetDmaContext(
    IN PVOID  HwDeviceExtension,
    OUT PDMA  pDma,
    IN PVOID  InstanceContext
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
pDma
Points to a DMA handle.
InstanceContext
Points to the DMA context to set.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

See Video Port Driver Support for Busmaster DMA for information about packet-based and common-buffer DMA transfers.


VideoPortSetEvent

VideoPortSetEvent sets an event object to the signaled state if it was not already in that state, and returns the event object's previous state.

LONG
  VideoPortSetEvent(
    IN PVOID  HwDeviceExtension,
    IN PEVENT  pEvent
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
pEvent
Points to the event object whose state is to be set.

Return Value

VideoPortSetEvent returns a nonzero value if the event object was previously in the signaled state.

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

Callers of this function must be running at IRQL <= DISPATCH_LEVEL.

See Also

VideoPortClearEvent


VideoPortSetRegistryParameters

VideoPortSetRegistryParameters writes information under the adapter key in the registry.

VP_STATUS
  VideoPortSetRegistryParameters(
    IN PVOID  HwDeviceExtension,
    IN PWSTR  ValueName,
    IN PVOID  ValueData,
    IN ULONG  ValueLength
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
ValueName
Points to a buffer containing a zero-terminated Unicode string that names the value entry for which data is being written in the registry.
ValueData
Points to a buffer containing the values to be written for the ValueName entry.
ValueLength
Specifies the size, in bytes, of the data to be written to the registry.

Return Value

VideoPortSetRegistryParameters returns NO_ERROR if the given data was successfully written to the registry. Otherwise, it can return ERROR_INVALID_PARAMETER.

Headers

Declared in video.h. Include video.h.

Comments

VideoPortSetRegistryParameters searches under the registry's adapter key for the value name specified in the ValueName parameter. If the value name that is searched for does not exist, this function creates it automatically. When the value name is found or created, the contents of the ValueData parameter are copied to the value name.

For Windows XP and later operating system versions, the value name specified in the ValueName parameters does not need to be directly associated with the adapter key. Instead, ValueName can be associated with a subkey whose path includes the adapter key. If the ValueName string contains one or more backslashes, VideoPortSetRegistryParameters searches for or creates the subkey whose value name is at the end of the string.

For example, if ValueName is set to the string "SubKey1\Value1", this function searches for SubKey1 under the adapter key in the registry, creating SubKey1 if it does not exist. The function then searches for the Value1 value name, creating it if necessary. VideoPortSetRegistryParameters then copies the contents of the ValueData parameter to the registry. The path specified in the ValueName parameter can refer to a value name an arbitrary number of levels below the adapter key, but the behavior of this function is essentially the same. If at any point a subkey or value name is not found, it is created automatically.

VideoPortSetRegistryParameters cannot be called from a miniport driver's HwVidInterrupt or HwVidTimer functions, or from VideoPortQueueDpc, or from a callback to VideoPortSynchronizeExecution.

Callers of VideoPortSetRegistryParameters must be running at IRQL = PASSIVE_LEVEL.

See Also

HwVidFindAdapter, HwVidInitialize, VideoPortGetRegistryParameters


VideoPortSetTrappedEmulatorPorts

VGA-compatible (SVGA) miniport drivers call VideoPortSetTrappedEmulatorPorts to dynamically change the list of I/O ports that are trapped when a VDM runs in full-screen mode on an x86-based machine.

VP_STATUS
  VideoPortSetTrappedEmulatorPorts(
    IN PVOID  HwDeviceExtension,
    IN ULONG  NumAccessRanges,
    IN PVIDEO_ACCESS_RANGE  AccessRange
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
NumAccessRanges
Specifies the number of elements in the AccessRange array.
AccessRange
Points to an array of VIDEO_ACCESS_RANGE elements. Each element describes a proper subrange of the EmulatorAccessEntries that the miniport driver set up in VIDEO_PORT_CONFIG_INFO. Setting the RangeVisible member of an AccessRange element to TRUE enables direct access to the I/O port range by the full-screen MS-DOS application. Setting a RangeVisible member to FALSE causes application-issued INs, INSB/INSW/INSDs, OUTs and/or OUTSB/OUTSW/OUTSDs to that range to be trapped and forwarded to the corresponding miniport driver SvgaHwIoPort Xxx function for validation.

The AccessRange array passed to VideoPortSetTrappedEmulatorPorts must be a proper subset of the I/O port range(s) that the HwVidFindAdapter function set up in the EmulatorAccessEntries array of the VIDEO_PORT_CONFIG_INFO structure. Any I/O port ranges in the access ranges array that are not included in the EmulatorAccessEntries array are trapped and reflected to the user-mode VDD.

Return Value

VideoPortSetTrappedEmulatorPorts returns NO_ERROR if it successfully changed the trapped ports. Otherwise, it returns ERROR_INVALID_PARAMETER.

Headers

Declared in video.h. Include video.h.

Comments

By default, the AccessRange of I/O ports that full-screen MS-DOS applications can access directly includes none of the access range array elements describing I/O port ranges that also have corresponding elements in the EmulatorAccessEntries array of the VIDEO_PORT_CONFIG_INFO structure. That is, I/O port ranges with corresponding emulator access entries are, by default, hooked to the miniport driver's SvgaHwIoPort Xxx functions so application-issued instructions are forwarded to the SvgaHwIoPort Xxx functions for validation.

A VGA-compatible SVGA miniport driver can enable and disable ranges of I/O ports on an as-needed basis with calls to VideoPortSetTrappedEmulatorPorts. Enabled port ranges allow a full-screen MS-DOS application to access those I/O ports directly, without having application-issued assembly instructions trapped and forwarded to the miniport driver's SvgaHwIoPort Xxx functions for validation first. Direct I/O port access for such an application gives the user faster video I/O response times.

VideoPortSetTrappedEmulatorPorts scans the AccessRange parameter array from the first element to the last, enabling and disabling I/O ports as directed in each element. Note that a range of enabled ports (the RangeVisible member set to TRUE) can be disabled again in the same call if the miniport driver includes a duplicate description of the same range with the RangeVisible member set to FALSE. Note also that a miniport driver can enable a wide range of I/O ports in the initial element of the AccessRange array and selectively disable subranges of ports in subsequent array elements when it calls VideoPortSetTrappedEmulatorPorts.

All full-screen MS-DOS applications use the same IOPM (I/O permission map) in x86-based machines and, therefore, the same set of enabled or disabled I/O ports. On each switch to such a full-screen application, a VGA-compatible miniport driver's HwVidStartIO function is called with the IOCTL_VIDEO_ENABLE_VDM VRP. The miniport driver should then reinitialize a default set of directly accessible I/O ports, which can include any ports in the EmulatorAccessEntries array.

While giving full-screen MS-DOS applications on x86-based machines direct access to the video ports makes application-initiated video operations faster, every VGA-compatible SVGA miniport driver must continue to trap a subset of critical I/O ports to prevent such an application from hanging the machine. In particular, such miniport drivers should always trap application I/O to the VGA-compatible adapter sequencer and miscellaneous output registers. Such a miniport driver should also trap and validate application-issued direct I/O that could cause the machine to hang for any additional adapter-dependent subset of I/O ports.

Calling VideoPortSetTrappedEmulatorPorts again and resetting the RangeVisible member of an AccessRange element to FALSE causes the application-issued instructions for that range to be forwarded to the corresponding miniport driver SvgaHwIoPort Xxx function.

Callers of VideoPortSetTrappedEmulatorPorts must be running at IRQL = PASSIVE_LEVEL.

See Also

EMULATOR_ACCESS_ENTRY, HwVidFindAdapter, HwVidStartIO, IOCTL_VIDEO_ENABLE_VDM, SvgaHwIoPort Xxx, VIDEO_ACCESS_RANGE, VIDEO_PORT_CONFIG_INFO, VideoPortSynchronizeExecution

VideoPortSignalDmaComplete

VideoPortSignalDmaComplete is obsolete in Windows 2000 and later.

VideoPortSignalDmaComplete indicates to the video miniport driver whether the current DMA transfer is compete.

BOOLEAN
  VideoPortSignalDmaComplete(
    IN PVOID  HwDeviceExtension,
    IN PVOID  pDmaHandle
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
pDmaHandle
Points to a DMA handle. To obtain the appropriate DMA handle, use the value in the OutputBuffer member of the pVrp parameter after VideoPortLockPages returns.

Return Value

VideoPortSignalDmaComplete always returns FALSE.

Headers

Declared in video.h. Include video.h.

Comments

See Video Port Driver Support for Busmaster DMA for information about packet-based and common-buffer DMA transfers.


VideoPortStallExecution

VideoPortStallExecution retains control of the processor for the specified number of microseconds and returns to the caller.

VOID
  VideoPortStallExecution(
    IN ULONG  Microseconds
    );

Parameters

Microseconds
Specifies the delay interval, in microseconds.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

Maximum acceptable values for Microseconds are thousands of microseconds during miniport driver initialization. Otherwise, the given delay interval must be no more than 50 microseconds. In general, VideoPortStallExecution can be called only if the miniport driver must wait for a very few microseconds for its adapter to update state.

While a miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortStallExecution, the miniport driver should be designed to avoid such a call if at all possible. Delays while running at high hardware priorities adversely affect the overall I/O throughput of the system and can freeze the machine.

If a miniport driver has work to be done at regular intervals of more than 50 microseconds, it should have a HwVidTimer function. Calls to a miniport driver-supplied HwVidTimer function at approximately one-second intervals can be enabled with VideoPortStartTimer and disabled with VideoPortStopTimer.

Callers of VideoPortStallExecution can be running at any IRQL.

See Also

HwVidInterrupt, HwVidSynchronizeExecutionCallback, HwVidTimer, VideoPortStartTimer, VideoPortStopTimer


VideoPortStartDma

VideoPortStartDma prepares the system for a DMA operation. As soon as the appropriate resource is available, VideoPortStartDma creates a scatter/gather list, initializes the system resources, and calls the video miniport driver-supplied HwVidExecuteDma routine to carry out the DMA operation.

VP_STATUS
  VideoPortStartDma(
    IN PVOID  HwDeviceExtension,
    IN PVP_DMA_ADAPTER  VpDmaAdapter,
    IN PVOID  Mdl,
    IN ULONG  Offset,
    IN OUT PULONG  pLength,
    IN PEXECUTE_DMA  ExecuteDmaRoutine,
    IN PVOID  Context,
    IN BOOLEAN  WriteToDevice
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
VpDmaAdapter
Points to the VP_DMA_ADAPTER structure that represents the busmaster adapter. This structure is returned from a call to VideoPortGetDmaAdapter.
Mdl
Points to the MDL that describes the buffer. This pointer is returned from a call to the video port driver's VideoPortLockBuffer function.
Offset
Specifies the byte offset in the buffer at which the DMA operation begins. The Mdl parameter describes this buffer.
pLength
Points to a variable that specifies the requested transfer size, in bytes, and that will receive the actual size to be transferred. The variable will be updated when either of the following events occurs: VideoPortStartDma returns or HwVidExecuteDma is called. It is therefore safe to read this variable from within HwVidExecuteDma even before VideoPortStartDma returns.
ExecuteDmaRoutine
Points to a miniport driver-supplied HwVidExecuteDma callback routine. VideoPortStartDma calls this routine to program the hardware registers and start the actual DMA operation.
Context
Points to the driver-determined context to be passed to the miniport driver's HwVidExecuteDma callback routine. Since the HwVidExecuteDma callback routine runs at DISPATCH level, the data that Context points to should be in nonpaged memory.
WriteToDevice
Specifies the direction of the DMA transfer. A value of TRUE denotes a transfer from the buffer to the device, and a value of FALSE denotes a transfer from the device to the buffer.

Return Value

VideoPortStartDma returns one of the following status codes:

Status Code | Meaning
NO_ERROR | The operation was successfully carried out.
ERROR_NOT_ENOUGH_MEMORY | There are not enough system resources for this operation.

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

To prepare for a DMA-transfer operation, VideoPortStartDma:

  • Flushes the memory region in the host processor's caches.
  • Builds a scatter/gather list.
  • Calls the video miniport driver's HwVidExecuteDma callback.

It is possible that not all of the requested data has been transferred, since the actual amount of memory transferred is limited by the number of map registers available to the driver. Callers of this function should inspect the actual transfer size returned at pLength to determine whether additional data remains to be transferred. If so, the miniport driver should call VideoPortStartDma (and subsequently, VideoPortCompleteDma) as many times as necessary to fulfill the entire transfer request.

Callers of VideoPortStartDma must be running at IRQL <= DISPATCH_LEVEL.

See Also

VideoPortGetDmaAdapter, VideoPortCompleteDma, HwVidExecuteDma, VP_DMA_ADAPTER


VideoPortStartTimer

VideoPortStartTimer enables calls to a miniport driver's HwVidTimer function.

VOID
  VideoPortStartTimer(
    IN PVOID  HwDeviceExtension
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension. This pointer is the input parameter to the HwVidTimer function.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

After a miniport driver calls VideoPortStartTimer, its HwVidTimer function is called periodically at approximate one-second intervals until the driver calls VideoPortStopTimer.

A miniport driver cannot call VideoPortStartTimer or VideoPortStopTimer if its DriverEntry function set the HwTimer member of the VIDEO_HW_INITIALIZATION_DATA structure to NULL.

A miniport driver's HwVidTimer function can call VideoPortStopTimer. Only another miniport driver function can re-enable calls to HwVidTimer by calling VideoPortStartTimer again.

Callers of VideoPortStartTimer must be running at IRQL <= DISPATCH_LEVEL.

See Also

DriverEntry, HwVidTimer, VIDEO_HW_INITIALIZATION_DATA, VideoPortStopTimer


VideoPortStopTimer

VideoPortStopTimer disables calls to a miniport driver's HwVidTimer function.

VOID
  VideoPortStopTimer(
    IN PVOID  HwDeviceExtension
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension. This pointer is the input parameter to the HwVidTimer function.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

VideoPortStopTimer is called to disable the miniport driver's HwVidTimer function. After a miniport driver calls VideoPortStartTimer, its HwVidTimer function is called periodically at approximate one-second intervals until the driver calls VideoPortStopTimer.

A miniport driver cannot call VideoPortStartTimer or VideoPortStopTimer if its DriverEntry function set the HwTimer member of the VIDEO_HW_INITIALIZATION_DATA structure to NULL.

A miniport driver's HwVidTimer function can call VideoPortStopTimer.

Callers of VideoPortStopTimer must be running at IRQL <= DISPATCH_LEVEL.

See Also

DriverEntry, HwVidTimer, VIDEO_HW_INITIALIZATION_DATA, VideoPortStartTimer


VideoPortSynchronizeExecution

VideoPortSynchronizeExecution synchronizes the execution of a miniport driver-supplied HwVidSynchronizeExecutionCallback function with the miniport driver's HwVidInterrupt function, if any. Otherwise, it runs HwVidSynchronizeExecutionCallback at a raised priority.

BOOLEAN
  VideoPortSynchronizeExecution(
    IN PVOID  HwDeviceExtension,
    IN VIDEO_SYNCHRONIZE_PRIORITY  Priority,
    IN PMINIPORT_SYNCHRONIZE_ROUTINE  SynchronizeRoutine,
    IN PVOID  Context
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
Priority
Specifies the type of priority at which the given SynchronizeRoutine must be run, as one of the following:
  • If Priority is set to VpLowPriority, the current thread is raised to the highest noninterrupt-masking priority. Accordingly, the current thread can be preempted only by an ISR if a device interrupts.
  • If Priority is set to VpMediumPriority and the miniport driver has an ISR associated with its video adapter, the call to the given SynchronizeRoutine is synchronized with the miniport driver's HwVidInterrupt function. Otherwise, synchronization is made at the VpLowPriority level.
  • VpHighPriority has the same effect as VpMediumPriority.
SynchronizeRoutine
Points to the miniport driver's HwVidSynchronizeExecutionCallback function.
Context
Points to a caller-supplied context to be passed to the miniport driver's HwVidSynchronizeExecutionCallback function. This pointer can be NULL.

Return Value

If the operation succeeds, VideoPortSynchronizeExecution returns TRUE.

Headers

Declared in video.h. Include video.h.

Comments

Miniport drivers seldom call this routine unless either of the following conditions hold:

  • The miniport driver's HwVidInterrupt function shares memory with other miniport driver functions. In order to access the shared memory in a multiprocessor-safe way, such miniport driver functions must call VideoPortSynchronizeExecution with HwVidSynchronizeExecutionCallback. This miniport driver function can safely access the shared memory because the video port driver prevents the HwVidInterrupt function from accessing the same memory concurrently.
  • The adapter must be programmed with a sequence of commands without being subject to a context switch. For example, a miniport driver's SvgaHwIoPort Xxx function that has buffered a sequence of I/O instructions and validated the sequence might call VideoPortSynchronizeExecution with HwVidSynchronizeExecutionCallback. This miniport driver function can transfer the buffered and validated I/O stream to the adapter very quickly.

A caller should specify the lowest practical Priority value for the work HwVidSynchronizeExecutionCallback must do. Any CallbackRoutine that is run at a high hardware priority (VpMediumPriority or VpHighPriority) should return control as quickly as possible. A driver with such a high-priority HwVidSynchronizeExecutionCallback function should be designed to do as much work as possible in every other driver function except its HwVidSynchronizeExecutionCallback and/or HwVidInterrupt function(s).

Callers of VideoPortSynchronizeExecution must be running at IRQL <= DIRQL.

See Also

HwVidInterrupt, HwVidSynchronizeExecutionCallback, SvgaHwIoPort Xxx


VideoPortUnlockBuffer

VideoPortUnLockBuffer unlocks physical pages described by the specified memory descriptor list (MDL).

VOID
  VideoPortUnLockBuffer(
    IN PVOID  HwDeviceExtension,
    IN PVOID  Mdl
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
Mdl
Points to the MDL of the buffer to be released. This parameter should be the same pointer that was returned by VideoPortLockBuffer.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

Callers of VideoPortUnlockBuffer must be running at IRQL <= DISPATCH_LEVEL.

See Also

VideoPortLockBuffer


VideoPortUnlockPages

VideoPortUnlockPages is obsolete in Windows 2000 and later. Use VideoPortUnlockBuffer in place of this function.

VideoPortUnlockPages releases memory used for packet-based DMA.

BOOLEAN
  VideoPortUnlockPages
    IN PVOID  hwDeviceExtension,
    IN OUT PDMA  pDma
    );

Parameters

hwDeviceExtension
Points to the miniport driver's device extension.
pDma
Specifies a nonNULL DMA handle.

Return Value

VideoPortUnlockPages always returns TRUE.

Headers

Declared in video.h. Include video.h.

Comments

See Video Port Driver Support for Busmaster DMA for information about packet-based and common-buffer DMA transfers.

This function can be called only within the context of a DMA IOCTL. It cannot be called from an ISR or DPC.

See Also

VideoPortUnlockBuffer

VideoPortUnmapDmaMemory

VideoPortUnmapDmaMemory is obsolete in Windows 2000 and later.

VideoPortUnmapDmaMemory unmaps a range of memory previously mapped by VideoPortMapDmaMemory.

BOOLEAN
  VideoPortUnmapDmaMemory(
    IN PVOID  HwDeviceExtension,
    IN PVOID  VirtualAddress,
    IN HANDLE  ProcessHandle,
    IN PDMA  BoardMemoryHandle
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
VirtualAddress
Points to a virtual address within the mapped range to be released.
ProcessHandle
Is the handle to the current process.
BoardMemoryHandle
Is the handle to adapter's memory.

Return Value

VideoPortUnmapDmaMemory always FALSE.

Headers

Declared in video.h. Include video.h.

Comments

See Video Port Driver Support for Busmaster DMA for information about packet-based and common-buffer DMA transfers.


VideoPortUnmapMemory

VideoPortUnmapMemory releases a mapping between a logical address range for the adapter and a virtual address range in the user-mode address space of a particular thread. This function is the complement of VideoPortMapMemory.

VP_STATUS
  VideoPortUnmapMemory(
    IN PVOID  HwDeviceExtension,
    IN OUT PVOID  VirtualAddress,
    IN HANDLE  ProcessHandle
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
VirtualAddress
Points to a virtual address within the mapped range to be released.
ProcessHandle
Should be set to zero, or to the process handle specified when the miniport driver called VideoPortMapMemory.

Return Value

VideoPortUnmapMemory returns NO_ERROR if the mapping was released. Otherwise, it returns ERROR_INVALID_PARAMETER.

Headers

Declared in video.h. Include video.h.

Comments

A miniport driver cannot release a subrange of the mapping between a logical device range and the user-space virtual address range of its corresponding display driver. Whether the VirtualAddress parameter is the base virtual address for the mapped range that was returned by VideoPortMapMemory, or is an offset into that mapped virtual range, VideoPortUnmapMemory releases the mapping for the full range.

Callers of VideoPortUnmapMemory must be running at IRQL = PASSIVE_LEVEL.

See Also

VideoPortMapMemory


VideoPortVerifyAccessRanges

VideoPortVerifyAccessRanges checks the registry for whether another driver has already claimed ownership of the specified bus-relative access ranges and any other hardware resources specified in the VIDEO_PORT_CONFIG_INFO structure. If not, this function claims the given resources for the caller.

VP_STATUS
  VideoPortVerifyAccessRanges(
    IN PVOID  HwDeviceExtension,
    IN ULONG  NumAccessRanges,
    IN PVIDEO_ACCESS_RANGE  AccessRanges
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
NumAccessRanges
Specifies the number of elements in the AccessRanges array, or zero.
AccessRanges
Points to the miniport driver's access ranges array, or NULL. Each VIDEO_ACCESS_RANGE-type element in this array specifies a bus-relative range of device memory, I/O ports, or register addresses for the adapter.

Return Value

VideoPortVerifyAccessRanges returns one of the following values:

Value | Meaning
ERROR_INVALID_PARAMETER | An error occurred or a conflict was found; that is, another driver has already claimed one or more of the given hardware resources for its device.
NO_ERROR | The given AccessRanges are valid and have been claimed for use by the caller.

Headers

Declared in video.h. Include video.h.

Comments

Every video miniport driver either must call VideoPortVerifyAccessRanges, or use access ranges returned by VideoPortGetAccessRanges before attempting to access a video adapter during the driver (and system) initialization process.

VideoPortVerifyAccessRanges can be called only by a miniport driver's HwVidFindAdapter function.

Every video miniport driver must define the bus-relative access ranges for its device, either as statically allocated memory in the driver's header file or code or on the stack. Most miniport drivers set up their video access ranges on the stack, except for those that use PC standard address ranges for video memory, such as VGA-compatible SVGA miniport drivers.

The HwVidFindAdapter function should try to obtain bus-relative access range information by calling VideoPortGetAccessRanges, or by checking the registry through calls to VideoPortGetDeviceData or VideoPortGetRegistryParameters. If HwVidFindAdapter cannot get this information, the miniport driver should have a set of bus-relative default values for access ranges.

If a miniport driver's access ranges are externally configurable, the installation program sets up access ranges for the adapter in the registry. Such a miniport driver's HwVidFindAdapter function can call VideoPortGetRegistryParameters with a miniport driver-supplied HwVidQueryNamedValueCallback function that processes information retrieved from the registry.

HwVidFindAdapter must not pass any access range addresses to VideoPortGetDeviceBase unless it calls VideoPortVerifyAccessRanges or VideoPortGetAccessRanges first and the respective function returns NO_ERROR.

VideoPortVerifyAccessRanges can be called again if the initial AccessRanges specification or value in the VIDEO_PORT_CONFIG_INFO, such as an interrupt vector, causes it to return an ERROR_XXX indicating that another driver has already claimed the resource(s).

If VideoPortVerifyAccessRanges returns NO_ERROR, a subsequent call for the same adapter overwrites the miniport driver's claim on resources for that adapter in the registry.

Note that a miniport driver cannot communicate with its video adapter, except by using mapped addresses returned by VideoPortGetDeviceBase with the VideoPortRead/Write Xxx functions.

If the HwVidFindAdapter function claims bus-relative access ranges and possibly other hardware resources for an adapter but then determines that it does not support the adapter, the miniport driver must relinquish its claims on hardware resources in the registry by calling VideoPortVerifyAccessRanges or VideoPortGetAccessRanges with NumAccessRanges set to zero and AccessRanges set to NULL.

To relinquish claims on a subset of claimed access ranges that the miniport driver is no longer using, do the following:

  1. Modify the AccessRanges specification for the adapter so that each element describing a range to be released still has RangeStart set to the bus-relative base of a claimed range, but RangeLength reset to zero.
  2. Call VideoPortVerifyAccessRanges with this modified AccessRanges array.

Callers of VideoPortVerifyAccessRanges must be running at IRQL = PASSIVE_LEVEL.

See Also

HwVidFindAdapter, HwVidQueryDeviceCallback, HwVidQueryNamedValueCallback, VIDEO_ACCESS_RANGE, VIDEO_PORT_CONFIG_INFO, VideoPortGetAccessRanges, VideoPortGetDeviceBase, VideoPortGetDeviceData, VideoPortGetRegistryParameters


VideoPortWaitForSingleObject

VideoPortWaitForSingleObject puts the current thread into a wait state until the given dispatch object is set to the signaled state, or (optionally) until the wait times out.

VP_STATUS
  VideoPortWaitForSingleObject(
    IN PVOID  HwDeviceExtension,
    IN PVOID  Object,
    IN PLARGE_INTEGER  Timeout  OPTIONAL
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
Object
Points to the event object.
Timeout
(Optional) Points to a time-out value that specifies the absolute or relative time at which the wait is to be completed. A negative value specifies a wait interval relative to the current time. The value should be expressed in units of 100 nanoseconds. Absolute expiration times track any changes in the system time; relative expiration times are not affected by system time changes.

Return Value

VideoPortWaitForSingleObject returns one of the following values:

Value | Meaning
ERROR_INVALID_PARAMETER | One of the parameters is invalid or the call attempted to wait on a mapped user event.
NO_ERROR | The event object specified in the pObject parameter satisfied the wait.
WAIT_TIMEOUT | A time-out occurred before the event object was set to the signaled state. This value can be returned when the specified set of wait conditions cannot be immediately met and Timeout is set to zero.

Headers

Declared in video.h. Include video.h.

Comments

This function is available in Windows XP and later.

The miniport driver should not attempt to wait on a mapped user event.

Callers of VideoPortWaitForSingleObject must be running at IRQL <= DISPATCH_LEVEL. Usually, the caller will be running at IRQL = PASSIVE_LEVEL and in a nonarbitrary thread context. A call to this function while running at IRQL = DISPATCH_LEVEL is valid if and only if the caller specifies a Timeout value of zero. That is, a miniport driver must not wait for a nonzero interval at IRQL = DISPATCH_LEVEL.


VideoPortWritePortBufferUchar

VideoPortWritePortBufferUchar writes a number of bytes to a mapped I/O port.

VOID
  VideoPortWritePortBufferUchar(
    IN PUCHAR  Port,
    IN PUCHAR  Buffer,
    IN ULONG  Count
    );

Parameters

Port
Points to the port. The given Port must be in a mapped I/O-space range returned by VideoPortGetDeviceBase.
Buffer
Points to a buffer containing the bytes to be written.
Count
Specifies the number of bytes to be transferred to the adapter.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortWritePortBufferUchar.

Callers of VideoPortWritePortBufferUchar can be running at any IRQL, provided that the memory pointed to by the Buffer parameter is resident and that pointed to by the Port parameter is resident, mapped device memory.

See Also

VideoPortGetDeviceBase


VideoPortWritePortBufferUlong

VideoPortWritePortBufferUlong writes a number of ULONG values to a mapped I/O port.

VOID
  VideoPortWritePortBufferUlong(
    IN PULONG  Port,
    IN PULONG  Buffer,
    IN ULONG  Count
    );

Parameters

Port
Points to the port. The given Port must be in a mapped I/O-space range returned by VideoPortGetDeviceBase.
Buffer
Points to a buffer containing the ULONG values to be written.
Count
Specifies the number of ULONG values to be transferred to the adapter.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortWritePortBufferUlong.

Callers of VideoPortWritePortBufferUlong can be running at any IRQL, provided that the memory pointed to by the Buffer parameter is resident and that pointed to by the Port parameter is resident, mapped device memory.

See Also

VideoPortGetDeviceBase


VideoPortWritePortBufferUshort

VideoPortWritePortBufferUshort writes a number of USHORT values to a mapped I/O port.

VOID
  VideoPortWritePortBufferUshort(
    IN PUSHORT  Port,
    IN PUSHORT  Buffer,
    IN ULONG  Count
    );

Parameters

Port
Points to the port. The given Port must be in a mapped I/O-space range returned by VideoPortGetDeviceBase.
Buffer
Points to a buffer containing the USHORT values to be written.
Count
Specifies the number of USHORT values to be transferred to the adapter.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortWritePortBufferUshort.

Callers of VideoPortWritePortBufferUshort can be running at any IRQL, provided that the memory pointed to by the Buffer parameter is resident and that pointed to by the Port parameter is resident, mapped device memory.

See Also

VideoPortGetDeviceBase


VideoPortWritePortUchar

VideoPortWritePortUchar writes a byte to a mapped I/O port.

VOID
  VideoPortWritePortUchar(
    IN PUCHAR  Port,
    IN UCHAR  Value
    );

Parameters

Port
Points to the port. The given Port must be in a mapped I/O-space range returned by VideoPortGetDeviceBase.
Value
Specifies a byte to be transferred to the adapter.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortWritePortUchar.

Callers of VideoPortWritePortUchar can be running at any IRQL, provided that the memory pointed to by the Port parameter is resident, mapped device memory.

See Also

VideoPortGetDeviceBase


VideoPortWritePortUshort

VideoPortWritePortUshort writes a USHORT value to a mapped I/O port.

VOID
  VideoPortWritePortUshort(
    IN PUSHORT  Port,
    IN USHORT  Value
    );

Parameters

Port
Points to the port. The given Port must be in a mapped I/O-space range returned by VideoPortGetDeviceBase.
Value
Specifies a USHORT value to be transferred to the adapter.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortWritePortUshort.

Callers of VideoPortWritePortUshort can be running at any IRQL, provided that the memory pointed to by the Port parameter is resident, mapped device memory.

See Also

VideoPortGetDeviceBase


VideoPortWriteRegisterBufferUchar

VideoPortWriteRegisterBufferUchar writes a number of unsigned bytes to a mapped register.

VOID
  VideoPortWriteRegisterBufferUchar(
    IN PUCHAR  Register,
    IN PUCHAR  Buffer,
    IN ULONG  Count
    );

Parameters

Register
Points to the register. The given Register must be in a mapped memory-space range returned by VideoPortGetDeviceBase.
Buffer
Points to a buffer containing the bytes to be written.
Count
Specifies the number of bytes to be transferred to the adapter.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortWriteRegisterBufferUchar.

Callers of VideoPortWriteRegisterBufferUchar can be running at any IRQL, provided that the memory pointed to by the Buffer parameter is resident and that pointed to by the Register parameter is resident, mapped device memory.

See Also

VideoPortGetDeviceBase


VideoPortWriteRegisterBufferUlong

VideoPortWriteRegisterBufferUlong writes a number of ULONG values to a mapped register.

VOID
  VideoPortWriteRegisterBufferUlong(
    IN PULONG  Register,
    IN PULONG  Buffer,
    IN ULONG  Count
    );

Parameters

Register
Points to the register. The given Register must be in a mapped memory-space range returned by VideoPortGetDeviceBase.
Buffer
Points to a buffer containing the ULONG values to be written.
Count
Specifies the number of ULONG values to be transferred to the adapter.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortWriteRegisterBufferUlong.

Callers of VideoPortWriteRegisterBufferUlong can be running at any IRQL, provided that the memory pointed to by the Buffer parameter is resident and that pointed to by the Register parameter is resident, mapped device memory.

See Also

VideoPortGetDeviceBase


VideoPortWriteRegisterBufferUshort

VideoPortWriteRegisterBufferUshort writes a number of USHORT values to a mapped register.

VOID
  VideoPortWriteRegisterBufferUshort(
    IN PUSHORT  Register,
    IN PUSHORT  Buffer,
    IN ULONG  Count
    );

Parameters

Register
Points to the register. The given Register must be in a mapped memory-space range returned by VideoPortGetDeviceBase.
Buffer
Points to a buffer containing the USHORT values to be written.
Count
Specifies the number of USHORT values to be transferred to the adapter.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortWriteRegisterBufferUshort.

Callers of VideoPortWriteRegisterBufferUshortcan be running at any IRQL, provided that the memory pointed to by the Buffer parameter is resident and that pointed to by the Register parameter is resident, mapped device memory.

See Also

VideoPortGetDeviceBase


VideoPortWriteRegisterUchar

VideoPortWriteRegisterUchar writes a byte to a mapped register.

VOID
  VideoPortWriteRegisterUchar(
    IN PUCHAR  Register,
    IN UCHAR  Value
    );

Parameters

Register
Points to the register. The given Register must be in a mapped memory-space range returned by VideoPortGetDeviceBase.
Value
Specifies a byte to be transferred to the adapter.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortWriteRegisterUchar.

Callers of VideoPortWriteRegisterUchar can be running at any IRQL, provided that the memory pointed to by the Register parameter is resident, mapped device memory.

See Also

VideoPortGetDeviceBase


VideoPortWriteRegisterUlong

VideoPortWriteRegisterUlong writes a ULONG value to a mapped register.

VOID
  VideoPortWriteRegisterUlong(
    IN PULONG  Register,
    IN ULONG  Value
    );

Parameters

Register
Points to the register. The given Register must be in a mapped memory-space range returned by VideoPortGetDeviceBase.
Value
Specifies a ULONG value to be transferred to the adapter.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortWriteRegisterUlong.

Callers of VideoPortWriteRegisterUlong can be running at any IRQL, provided that the memory pointed to by the Register parameter is resident, mapped device memory.

See Also

VideoPortGetDeviceBase


VideoPortWriteRegisterUshort

VideoPortWriteRegisterUshort writes a USHORT value to a mapped register.

VOID
  VideoPortWriteRegisterUshort(
    IN PUSHORT  Register,
    IN USHORT  Value
    );

Parameters

Register
Points to the register. The given Register must be in a mapped memory-space range returned by VideoPortGetDeviceBase.
Value
Specifies a USHORT value to be transferred to the adapter.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortWriteRegisterUshort.

Callers of VideoPortWriteRegisterUshort can be running at any IRQL, provided that the memory pointed to by the Register parameter is resident, mapped device memory.

See Also

VideoPortGetDeviceBase


VideoPortZeroDeviceMemory

VideoPortZeroDeviceMemory fills an adapter frame buffer or other device memory with zeros.

VOID
  VideoPortZeroDeviceMemory(
    IN PVOID  Destination,
    IN ULONG  Length
    );

Parameters

Destination
Specifies the base address of the adapter memory area. This value must be a mapped logical address returned by VideoPortGetDeviceBase.
Length
Specifies the size, in bytes, to be filled.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

Miniport drivers should always call this function, rather than VideoPortZeroMemory, to fill on-adapter memory with zeros.

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortZeroDeviceMemory.

Callers of VideoPortZeroDeviceMemory can be running at any IRQL if the memory pointed to by the Destination parameter is in nonpaged pool. Otherwise, the caller must be running at IRQL < DISPATCH_LEVEL.

See Also

HwVidInterrupt, HwVidSynchronizeExecutionCallback, VideoPortGetDeviceBase, VideoPortZeroMemory


VideoPortZeroMemory

VideoPortZeroMemory fills a block of system memory with zeros.

VOID
  VideoPortZeroMemory(
    IN PVOID  Destination,
    IN ULONG  Length
    );

Parameters

Destination
Specifies the starting address of the block of memory. This value must be in a mapped logical range returned by VideoPortGetDeviceBase.
Length
Specifies the size, in bytes, of the block.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

Miniport drivers' DriverEntry functions generally call VideoPortZeroMemory to initialize the VIDEO_HW_INITIALIZATION_DATA structure with zeros.

The given Destination must be in a mapped logical range returned by VideoPortGetDeviceBase and/or a system-space RAM address, such as an address on the stack. Use VideoPortZeroDeviceMemory to fill any device-memory block, such as a frame buffer, with zeros.

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortZeroMemory.

Callers of VideoPortZeroMemory can be running at any IRQL if the memory pointed to by the Destination parameter is in nonpaged pool. Otherwise, the caller must be running at IRQL < DISPATCH_LEVEL.

See Also

DriverEntry, HwVidInterrupt, HwVidSynchronizeExecutionCallback, VIDEO_HW_INITIALIZATION_DATA, VideoPortCompareMemory, VideoPortMoveMemory, VideoPortZeroDeviceMemory


Video Port/Miniport Structures

This section describes structures used by video miniport drivers that are linked with the video port driver. Structures are listed in alphabetic order. See Video Miniport Header Files, Sample Code, and References for the include file that contains definitions for these structures.

For more information about video requests and IOCTLs handled by the port-miniport driver pair, see Video I/O Control Codes.


EMULATOR_ACCESS_ENTRY

The EMULATOR_ACCESS_ENTRY structure specifies an element in the EmulatorAccessEntries array set up in the VIDEO_PORT_CONFIG_INFO structure by drivers of VGA-compatible (SVGA) adapters on x86-based NT-based operating system platforms.

typedef struct _EMULATOR_ACCESS_ENTRY {
  ULONG  BasePort;
  ULONG  NumConsecutivePorts;
  EMULATOR_PORT_ACCESS_TYPE  AccessType;
  UCHAR  AccessMode;
  UCHAR  StringSupport;
  PVOID  Routine;
} EMULATOR_ACCESS_ENTRY, *PEMULATOR_ACCESS_ENTRY;

Members

BasePort
Specifies the bus-relative physical address of the I/O port or ports to be hooked out by the V86 emulator. This value and the range of ports must fall within an access range of I/O ports already claimed in the registry by VideoPortGetAccessRanges or VideoPortVerifyAccessRanges.
NumConsecutivePorts
Specifies the number of consecutive ports to be hooked by the V86 emulator, starting at BasePort. This value is determined by the width of each hooked I/O port. For example, if port addresses 0x3C0 and 0x3C1 are hooked as a single USHORT-addressable port, this value should be 1.
AccessType
Specifies the size of the data transferred through the given I/O port as one of Uchar, Ulong, or Ushort.
AccessMode
Specifies how the given I/O port can be accessed as one or a combination (ORed) of the following values:

EMULATOR_READ_ACCESS
EMULATOR_WRITE_ACCESS

The I/O port range must be accessible in at least one of the preceding modes.

StringSupport
Indicates whether the driver-supplied SvgaHwIoPort Xxx function supports string accesses in cases where many values of the given AccessType are "pumped" through an I/O port consecutively. If this member is set to TRUE, the Routine member must specify the entry point of a miniport driver-supplied SvgaHwIoPort Xxx String function.
Routine
Points to the miniport driver's SvgaHwIoPort Xxx that handles accesses to the port or ports described in this structure.

Headers

Declared in miniport.h. Include miniport.h.

Comments

VGA-compatible miniport drivers of SVGA video hardware in x86-based machines must define emulator access ranges, which a VGA-compatible miniport driver can set up with VideoPortSetTrappedEmulatorPorts to be accessed directly from full-screen MS-DOS™ applications for faster I/O. Such a driver must supply a set of SvgaHwIoPort Xxx functions to validate any sequence of application-issued INs, INSB/INSW/INSDs, OUTs, and/or OUTSB/OUTSW/OUTSDs to each such I/O port range.

Data in each EMULATOR_ACCESS_ENTRY-type element is used to determine which I/O ports (memory locations at which adapter registers are accessible) in the miniport driver's access ranges have been taken over (hooked out) by the V86 emulator on x86-based platforms. Values written to these locations by full-screen MS-DOS applications are trapped and forwarded to the miniport driver's corresponding SvgaHwIoPort Xxx function for validation before they are written to or read from the video adapter. However, the miniport driver can enable the application to directly access particular I/O port ranges by calling VideoPortSetTrappedEmulatorPorts to improve performance.

See Also

SvgaHwIoPort Xxx, VIDEO_ACCESS_RANGE, VIDEO_PORT_CONFIG_INFO, VideoPortGetAccessRanges, VideoPortSetTrappedEmulatorPorts, VideoPortVerifyAccessRanges


INT10_BIOS_ARGUMENTS

The INT10_BIOS_ARGUMENTS structure is used to support full-screen MS-DOS application INT10 calls. It contains nine of the high-end x86 microprocessor registers.

typedef struct _INT10_BIOS_ARGUMENTS {
  ULONG  Eax;
  ULONG  Ebx;
  ULONG  Ecx;
  ULONG  Edx;
  ULONG  Esi;
  ULONG  Edi;
  ULONG  Ebp;
  USHORT  SegDs;
  USHORT  SegEs;
} INT10_BIOS_ARGUMENTS, *PINT10_BIOS_ARGUMENTS;

Members

Eax, Ebx, Ecx, Edx, Esi, Edi, Ebp
Are seven of the x86 microprocessor registers.
SegDs, SegEs
Are two of the x86 microprocessor segment registers.

Headers

Declared in video.h. Include video.h.

Comments

The first seven members of the INT10_BIOS_ARGUMENTS structure are identical to those of the VIDEO_X86_BIOS_ARGUMENTS structure.

See Also

Int10CallBios, VIDEO_X86_BIOS_ARGUMENTS


STATUS_BLOCK

The STATUS_BLOCK structure is a substructure within the VIDEO_REQUEST_PACKET structure. A miniport driver's HwVidStartIO function must set the status block of each VRP that it gets.

typedef struct _STATUS_BLOCK {
  union {
    VP_STATUS  Status;
    PVOID  Pointer;
  }
  ULONG_PTR Information;
} STATUS_BLOCK, *PSTATUS_BLOCK;

Members

Status
Is set to a status code that indicates the result of the requested operation, such as:
Code Description
ERROR_INSUFFICIENT_BUFFER
Either the VRP InputBuffer is too small to provide the data required to process the given request or the OutputBuffer is too small to return the requested data.
ERROR_INVALID_FUNCTION
The miniport driver does not handle this request.
ERROR_INVALID_PARAMETER
A parameter in the VRP is invalid.
ERROR_IO_PENDING
An operation has not yet completed.
ERROR_MORE_DATA
The driver has additional data to be returned but has already filled the given VRP OutputBuffer.
ERROR_NOT_ENOUGH_MEMORY
There is insufficient memory to process the request.
NO_ERROR
The requested operation has been carried out and completed successfully.

Pointer
Should be ignored by the miniport driver. This member of the union exists to guarantee field alignment across 32- and 64-bit systems.
Information
Supplies additional information about the completed operation. The meaning of the value varies according to VRP. Generally, this member is used to return the minimum size required for the input buffer if the VRP passes data in the InputBuffer. Alternatively, it contains the number of bytes of data transferred if the requested operation returns data in the VRP OutputBuffer.

Headers

Declared in video.h. Include video.h.

See Also

HwVidStartIO, VIDEO_REQUEST_PACKET


VIDEO_ACCESS_RANGE

The VIDEO_ACCESS_RANGE structure defines a device I/O port or memory range for the video adapter. Every miniport driver's HwVidFindAdapter function must set up an array of VIDEO_ACCESS_RANGE-type elements, called the access ranges array, for each video adapter the miniport driver supports.

For VGA-compatible miniport drivers, VIDEO_ACCESS_RANGE also defines an element in an array passed to VideoPortSetTrappedEmulatorPorts to enable or disable direct access to I/O ports by full-screen MS-DOS applications.

typedef struct _VIDEO_ACCESS_RANGE {
  PHYSICAL_ADDRESS  RangeStart;
  ULONG  RangeLength;
  UCHAR  RangeInIoSpace;
  UCHAR  RangeVisible;
  UCHAR  RangeShareable;
  UCHAR  RangePassive;
} VIDEO_ACCESS_RANGE, *PVIDEO_ACCESS_RANGE;

Members

RangeStart
Specifies the bus-relative base address of a memory or I/O port range for an element in the access ranges array passed to VideoPortVerifyAccessRanges or returned by VideoPortGetAccessRanges.

Specifies the bus-relative base address of an I/O port range for an array to be passed to VideoPortSetTrappedEmulatorPorts.

RangeLength
Specifies the number of I/O ports or size in bytes for the range.
RangeInIoSpace
Specifies whether the range is in I/O space or in memory space. A value of TRUE (1) indicates that the range is in I/O space; a value of FALSE (0) indicates the range is in memory space.
RangeVisible
Is ignored if the miniport driver's HwVidFindAdapter function is setting up the access ranges array.

Is set to TRUE by VGA-compatible miniport drivers and passed to VideoPortSetTrappedEmulatorPorts to enable direct access to the I/O port range by a full-screen MS-DOS application. If set to FALSE, application-issued instructions continue to be trapped and forwarded to the miniport driver's SvgaHwIo Xxx function for validation.

RangeShareable
Is set to TRUE if the access range described by this element can be shared with another driver and/or device or to FALSE if the range cannot be shared.

Is ignored by VideoPortSetTrappedEmulatorPorts.

RangePassive
Indicates whether the device actually uses the port. Values for this member are shown in the following table.
Value | Meaning
VIDEO_RANGE_PASSIVE_DECODE | The device decodes the port but the driver does not use it.
VIDEO_RANGE_10_BIT_DECODE | The device decodes ten bits of the port address.

Headers

Declared in video.h. Include video.h.

Comments

The miniport driver must claim legacy resources in its DriverEntry or HwVidLegacyResources function.

Otherwise, a miniport driver's HwVidFindAdapter function sets up the access ranges array for an adapter's PCI resources. It can use information returned by VideoPortGetAccessRanges. As an alternative, it can use information retrieved from the registry by calling VideoPortGetDeviceData with a miniport driver-supplied HwVidQueryDeviceCallback function or VideoPortGetRegistryParameters with a miniport driver-supplied HwVidQueryNamedValueCallback function. If calling these VideoPort Xxx does not supply the bus-relative access range values, HwVidFindAdapter can set up access ranges elements using driver-supplied bus-relative default values.

Claiming Access Ranges in the Registry

The miniport driver should call VideoPortVerifyAccessRanges with any access ranges obtained from VideoPortGetDeviceData, VideoPortGetAccessRanges, or supplied as defaults by the miniport driver. If VideoPortVerifyAccessRanges returns NO_ERROR for such an array of access ranges, the HwVidFindAdapter or HwVidQueryDeviceCallback function can then map the ranges with VideoPortGetDeviceBase and use the returned mapped logical addresses to access the adapter.

A successful call to VideoPortGetAccessRanges also claims the returned bus-relative access ranges in the registry for the caller. If the miniport driver modifies any of the returned values, it must call VideoPortVerifyAccessRanges with the full access range, including any unmodified elements. Each call to VideoPortGetAccessRanges or VideoPortVerifyAccessRanges for a particular video adapter overwrites the caller's claimed hardware resources in the registry.

A miniport driver must not attempt to use a range for which VideoPortVerifyAccessRanges or VideoPortGetAccessRanges does not return NO_ERROR.

Mapping Access Ranges to Communicate with the Adapter

After a miniport driver has claimed resources in the registry for an adapter, it cannot use bus-relative addresses to access or configure the adapter, because the HAL can remap all bus-relative device addresses to system space, particularly in multibus machines.

The miniport driver's HwVidFindAdapter function must call VideoPortGetDeviceBase to get mapped logical addresses for its access ranges. Only then can the miniport driver communicate with the video adapter by passing the returned mapped logical range addresses to VideoPortRead/WritePort Xxx to access device memory in I/O space and/or VideoPortRead/WriteRegister Xxx to access device memory in memory space.

Determining whether an Access Range is Shareable

Follow these guidelines to determine whether an access range can be shared:

  • If the range of memory or I/O ports should be "owned" by this driver, and/or access to this range by any other driver can cause a problem, set RangeShareable to FALSE.
  • If the range can be shared with a cooperating device driver, set RangeShareable to TRUE.

SVGA miniport drivers that implement all VGA functionality (declared in the registry as VgaCompatible set to one) should claim their access ranges as unshareable so the system VGA driver will not be loaded. On the other hand, miniport drivers for adapters such as the S3 or the XGA, which set VgaCompatible to zero in the registry, should claim all the resources they share with the system VGA driver as shareable.

However, miniport drivers for cards that work with a pass-through IOCTL and that can be connected to any VGA or SVGA card should not be using any system VGA ports or memory ranges. If they do, such a driver should not attempt to claim any of the VGA access ranges in the registry. Attempts to claim VGA resources by such a miniport driver are likely to cause a resource conflict because the driver of any SVGA card in the machine will have claimed these access ranges as unshareable.

Passing I/O Port Range Elements to VideoPortSetTrappedEmulatorPorts

All VIDEO_ACCESS_RANGE-type array elements describing I/O port ranges are assumed to be invisible, unless a VGA-compatible miniport driver in an x86-based machine explicitly resets the RangeVisible member(s) to TRUE and calls VideoPortSetTrappedEmulatorPorts to enable one or more I/O port ranges. VideoPortSetTrappedEmulatorPorts ignores the RangeShareable members of the input array.

In an array of VIDEO_ACCESS_RANGE-type elements passed to VideoPortSetTrappedEmulatorPorts, the value of each element's RangeVisible member determines whether the given I/O port(s) can be accessed directly by the VDM (MS-DOS application running in full-screen on an x86-based machine) or whether such an application-issued I/O stream is trapped and forwarded to a miniport driver-supplied SvgaHwIoPort Xxx function for validation first.

See Also

DriverEntry, EMULATOR_ACCESS_ENTRY, HwVidFindAdapter, HwVidQueryDeviceCallback, HwVidQueryNamedValueCallback, VIDEO_HW_INITIALIZATION_DATA, VideoPortGetAccessRanges, VideoPortGetDeviceBase, VideoPortGetDeviceData, VideoPortGetRegistryParameters, VideoPortInitialize, VideoPortRead Xxx, VideoPortSetTrappedEmulatorPorts, VideoPortVerifyAccessRanges, VideoPortWrite Xxx


VIDEO_CHILD_STATE

The VIDEO_CHILD_STATE structure contains information about a child device and the state into which it should be placed.

typedef struct _VIDEO_CHILD_STATE {
  ULONG  Id;
  ULONG  State;
} VIDEO_CHILD_STATE, *PVIDEO_CHILD_STATE;

Members

Id
Specifies the ID for a particular child device, as given to it by the miniport driver. This value is the same as that returned in the UId parameter of HwVidGetVideoChildDescriptor.
State
Specifies the new state, on or off, for the child device. A value of one (1) indicates that the child device should be turned on; a value of zero (0) indicates that it should be turned off. One possible use for State is in hotkey switching from one display device to another.

Headers

Declared in video.h. Include video.h.

Comments

One member of the VIDEO_CHILD_STATE_CONFIGURATION structure is an array of VIDEO_CHILD_STATE structures. Each of these structures maintains state information for one of an adapter's child devices.

See Also

VIDEO_CHILD_STATE_CONFIGURATION, HwVidGetVideoChildDescriptor


VIDEO_CHILD_STATE_CONFIGURATION

The VIDEO_CHILD_STATE_CONFIGURATION structure contains an array of VIDEO_CHILD_STATE structures, each holding the state of a particular child device.

typedef struct _VIDEO_CHILD_STATE_CONFIGURATION {
  ULONG  Count;
  VIDEO_CHILD_STATE  ChildStateArray[ANYSIZE_ARRAY];
} VIDEO_CHILD_STATE_CONFIGURATION, *PVIDEO_CHILD_STATE_CONFIGURATION;

Members

Count
Specifies the number of structures in the ChildStateArray member.
ChildStateArray
Is an array of VIDEO_CHILD_STATE structures. Each element of this array contains the ID and state for a particular child device.

Headers

Declared in video.h. Include video.h.

Comments

The video port driver sends a VIDEO_CHILD_STATE_CONFIGURATION structure to the miniport driver for the following IOCTLs:

  • IOCTL_VIDEO_VALIDATE_CHILD_STATE_CONFIGURATION, in which the video port driver queries the miniport driver to determine whether the specified state for each child device in ChildStateArray is valid.
  • IOCTL_VIDEO_SET_CHILD_STATE_CONFIGURATION, in which the video port driver requests the miniport driver to make the specified state change for each child device in ChildStateArray.

See Also

VIDEO_CHILD_STATE, VIDEO_REQUEST_PACKET, IOCTL_VIDEO_VALIDATE_CHILD_STATE_CONFIGURATION, IOCTL_VIDEO_SET_CHILD_STATE_CONFIGURATION


VIDEO_HW_INITIALIZATION_DATA

The VIDEO_HW_INITIALIZATION_DATA structure specifies the entry points and storage requirements for the miniport driver. This structure is created on the stack and initialized by the miniport driver's DriverEntry function.

typedef struct _VIDEO_HW_INITIALIZATION_DATA {
  ULONG  HwInitDataSize;
  INTERFACE_TYPE  AdapterInterfaceType;
  PVIDEO_HW_FIND_ADAPTER  HwFindAdapter;
  PVIDEO_HW_INITIALIZE  HwInitialize;
  PVIDEO_HW_INTERRUPT  HwInterrupt;
  PVIDEO_HW_START_IO  HwStartIO;
  ULONG  HwDeviceExtensionSize;
  ULONG  StartingDeviceNumber;
  PVIDEO_HW_RESET_HW  HwResetHw;
  PVIDEO_HW_TIMER  HwTimer;
  PVIDEO_HW_START_DMA  HwStartDma;
  PVIDEO_HW_POWER_SET  HwSetPowerState;
  PVIDEO_HW_POWER_GET  HwGetPowerState;
  PVIDEO_HW_GET_CHILD_DESCRIPTOR  HwGetVideoChildDescriptor;
  PVIDEO_HW_QUERY_INTERFACE  HwQueryInterface;
  ULONG  HwChildDeviceExtensionSize;
  PVIDEO_ACCESS_RANGE  HwLegacyResourceList;
  ULONG  HwLegacyResourceCount;
  PVIDEO_HW_LEGACYRESOURCES  HwGetLegacyResources;
  BOOLEAN  AllowEarlyEnumeration;
  ULONG  Reserved;
} VIDEO_HW_INITIALIZATION_DATA, *PVIDEO_HW_INITIALIZATION_DATA;

Members

HwInitDataSize
Is the size in bytes of this structure. In effect, this indicates the version of VIDEO_HW_INITIALIZATION_DATA being used.
AdapterInterfaceType
Is currently ignored by the video port and should remain zero-initialized.
HwFindAdapter
Points to the miniport driver's HwVidFindAdapter function, which is required for all miniport drivers.
HwInitialize
Points to the miniport driver's HwVidInitialize function, which is required for all miniport drivers.
HwInterrupt
Points to the miniport driver's HwVidInterrupt function, which is required only if the miniport driver's adapter generates interrupts. Otherwise, this pointer must be NULL.
HwStartIO
Points to the miniport driver's HwVidStartIO function, which is required for all miniport drivers.
HwDeviceExtensionSize
Specifies the size in bytes of the storage the miniport driver requires for its private, adapter-specific device extension. A miniport driver uses this storage to hold driver-determined per-adapter information, such as the mapped logical address ranges for the adapter registers and whatever context information the driver maintains about its I/O operations.

A pointer to the device extension is passed in every call made to the miniport driver's standard functions except DriverEntry, HwVidSynchronizeExecutionCallback, and any SvgaHwIoPort Xxx. The video port driver allocates the memory for the device extension and initializes it with zeros before it is passed to the miniport driver's HwVidFindAdapter function.

StartingDeviceNumber
Must be set to zero.
HwResetHw
Points to the miniport driver's HwVidResetHw function, which is required for any miniport driver of an adapter that does not reset fully on a soft reboot of the machine. Drivers of SVGA adapters that are fully reset to a VGA standard character mode on receipt of an INT10, MODE3-type command usually set this to NULL.
HwTimer
Points to a miniport driver's HwVidTimer function, which is optional. This pointer can be NULL.
HwStartDma
Reserved for system use.
HwSetPowerState
Points to the miniport driver's HwVidSetPowerState function, which is required for all miniport drivers.
HwGetPowerState
Points to the miniport driver's HwVidGetPowerState function, which is required for all miniport drivers.
HwGetVideoChildDescriptor
Points to the miniport driver's HwVidGetVideoChildDescriptor function, which is required for all miniport drivers.
HwQueryInterface
Points to the miniport driver's HwVidQueryInterface function. This can be optionally implemented in a miniport driver that supports external programming interfaces for inter-device communication, such as I2C (or I2C) support for MPEG decoders. Otherwise, this member should be set to NULL.
HwChildDeviceExtensionSize
Is the size in bytes of the device extension associated with the display output device. The miniport driver should fill in this member only if the miniport driver needs to manage the monitor configuration data separately from the adapter board configuration.
HwLegacyResourceList
Points to an array of VIDEO_ACCESS_RANGE structures. Each structure describes a device I/O port or memory range for the video adapter that is not listed in PCI configuration space.
HwLegacyResourceCount
Is the number of elements in the array to which HwLegacyResourceList points.
HwGetLegacyResources
Points to the miniport driver's HwVidLegacyResources function, which enables the driver to specify its legacy resources based on its device and vendor IDs.
AllowEarlyEnumeration
Allows the miniport driver to enumerate its child devices before the adapter is started; that is, the video port driver can call HwVidGetVideoChildDescriptor before HwVidFindAdapter when this member is set to TRUE.
Reserved
Reserved for system use.

Headers

Declared in video.h. Include video.h.

Comments

A miniport driver's DriverEntry function must initialize this structure with zeros before it sets relevant values in any member.

The video port driver will ignore the HwLegacyResourceCount and HwLegacyResourceList members when HwGetLegacyResources is initialized with a pointer to a HwVidLegacyResources implementation.

See Also

EMULATOR_ACCESS_ENTRY, SvgaHwIoPort Xxx, VIDEO_ACCESS_RANGE, VIDEO_PORT_CONFIG_INFO, VideoPortZeroMemory, HwVidLegacyResources


VIDEO_MEMORY

The VIDEO_MEMORY structure holds the address of a requested block of kernel-mode video memory.

typedef struct _VIDEO_MEMORY {
  PVOID  RequestedVirtualAddress;
}VIDEO_MEMORY, *PVIDEO_MEMORY;

Members

RequestedVirtualAddress
Points to the requested virtual address for either the video memory, or the base of video memory, depending on whether IOCTL_VIDEO_MAP_VIDEO_MEMORY or IOCTL_VIDEO_UNMAP_VIDEO_MEMORY is using this structure.

Headers

Declared in ntddvdeo.h. Include ntddvdeo.h.

Comments

VIDEO_MEMORY is used as an input structure to two IOCTLs: IOCTL_VIDEO_MAP_VIDEO_MEMORY, and IOCTL_VIDEO_UNMAP_VIDEO_MEMORY.

When VIDEO_MEMORY is used with IOCTL_VIDEO_MAP_VIDEO_MEMORY, RequestedVirtualAddress points to the requested virtual address for the video memory. In this case, the value is optional. If zero is specified, the operating system will choose an appropriate location.

When VIDEO_MEMORY is used with IOCTL_VIDEO_UNMAP_VIDEO_MEMORY, RequestedVirtualAddress points to the virtual address of the base of video memory. In this case, the size is implicit since it cannot change (you cannot add video memory dynamically, so it must be the same size as when it was mapped).

For structures used in mapping into user-mode video memory, see VIDEO_SHARE_MEMORY AND VIDEO_SHARE_MEMORY_INFORMATION.

See Also

IOCTL_VIDEO_MAP_VIDEO_MEMORY, IOCTL_VIDEO_UNMAP_VIDEO_MEMORY, VIDEO_MEMORY_INFORMATION


VIDEO_MEMORY_INFORMATION

The VIDEO_MEMORY_INFORMATION structure contains information about kernel-mode video memory obtained from an IOCTL_VIDEO_MAP_VIDEO_MEMORY request.

typedef struct _VIDEO_MEMORY_INFORMATION {
  PVOID  VideoRamBase;
  ULONG  VideoRamLength;
  PVOID  FrameBufferBase;
  ULONG  FrameBufferLength;
} VIDEO_MEMORY_INFORMATION, *PVIDEO_MEMORY_INFORMATION;

Members

VideoRamBase
Points to the virtual address of the video RAM in the caller's address space. This value is valid only if the memory is successfully mapped.
VideoRamLength
Specifies the linear length of the video RAM in the caller's virtual address space. Memory accessible through a bank switch mechanism is not described by this value.

This value must be equal to the product VideoMemoryBitmapHeight * ScreenStride, where each term in this product is a member of the VIDEO_MODE_INFORMATION structure.

FrameBufferBase
Points to the virtual address of the frame buffer in the caller's address space. The frame buffer is the actively displayed part of video RAM.
FrameBufferLength
Specifies the linear length of the frame buffer in the caller's virtual address space. Memory accessible through a bank switch mechanism is not described by this value.

This value must be equal to the product VisScreenWidth * ScreenStride, where each term in this product is a member of the VIDEO_MODE_INFORMATION structure.

Headers

Declared in ntddvdeo.h. Include ntddvdeo.h.

Comments

In the IOCTL_VIDEO_MAP_VIDEO_MEMORY request, VIDEO_MEMORY serves as an input structure, while VIDEO_MEMORY_INFORMATION serves as an output structure.

See Also

VIDEO_MEMORY, VIDEO_MODE_INFORMATION, IOCTL_VIDEO_MAP_VIDEO_MEMORY, IOCTL_VIDEO_UNMAP_VIDEO_MEMORY


VIDEO_MODE

The VIDEO_MODE structure contains the requested VGA mode that an adapter should set. This structure is used in conjunction with IOCTL_VIDEO_SET_CURRENT_MODE.

typedef struct _VIDEO_MODE {
  ULONG  RequestedMode;
} VIDEO_MODE, *PVIDEO_MODE;

Members

RequestedMode
Is the mode that the miniport driver should set if possible. In addition, the two high-order bits can be set to request special behavior from the miniport driver as follows:
VIDEO_MODE_ZERO_MEMORY
Indicates that the miniport driver should zero the video memory in conjunction with the mode set.
VIDEO_MODE_MAP_MEM_LINEAR
Indicates that the miniport driver should map the video memory in a linear fashion if the adapter supports such an operation.

Headers

Declared in ntddvdeo.h. Include ntddvdeo.h.


VIDEO_MODE_INFORMATION

The VIDEO_MODE_INFORMATION structure contains all of the information about one mode of a video adapter.

typedef struct _VIDEO_MODE_INFORMATION {
  ULONG  Length;
  ULONG  ModeIndex;
  ULONG  VisScreenWidth;
  ULONG  VisScreenHeight;
  ULONG  ScreenStride;
  ULONG  NumberOfPlanes;
  ULONG  BitsPerPlane;
  ULONG  Frequency;
  ULONG  XMillimeter;
  ULONG  YMillimeter;
  ULONG  NumberRedBits;
  ULONG  NumberGreenBits;
  ULONG  NumberBlueBits;
  ULONG  RedMask;
  ULONG  GreenMask;
  ULONG  BlueMask;
  ULONG  AttributeFlags;
  ULONG  VideoMemoryBitmapWidth;
  ULONG  VideoMemoryBitmapHeight;
  ULONG  DriverSpecificAttributeFlags;
} VIDEO_MODE_INFORMATION, *PVIDEO_MODE_INFORMATION;

Members

Length
Specifies the length, in bytes, of this structure. A miniport driver can use this value to determine the version of this structure.
ModeIndex
Specifies the index of the particular mode to be used in a call to the miniport driver.
VisScreenWidth
Specifies the number of visible pixels on one horizontal scan line.
VisScreenHeight
Specifies the number of visible lines (or scan lines) on the screen.
ScreenStride
Specifies the number of bytes between the start of one scan line and the next.
NumberOfPlanes
Specifies the number of separate planes combined by the device.
BitsPerPlane
Specifies the number of bits per pixel per plane.
Frequency
Specifies the screen refresh rate, in Hertz.
XMillimeter
Specifies the width, in millimeters, of the active region on the output device.
YMillimeter
Specifies the height, in millimeters, of the active region on the output device.
NumberRedBits
Specifies the number of bits in the red DAC.
NumberGreenBits
Specifies the number of bits in the green DAC.
NumberBlueBits
Specifies the number of bits in the blue DAC.
RedMask
Is the red color mask for a device with direct color modes. For example, to indicate that bits 0 through 4 are to be used for red, use the value 0x001F.
GreenMask
Is the green color mask for a device with direct color modes. For example, to indicate that bits 5 through 9 are to be used for green, use the value 0x03E0.
BlueMask
Is the blue color mask for a device with direct color modes. For example, to indicate that bits 10 through 14 are to be used for blue, use the value 0x7C00.
AttributeFlags
Is a set of flags indicating certain behavior for the device. The flags and their meanings are shown in the following table.
Flag Name Flag
Value 		Bit
Number 		Bit Value and Meaning
VIDEO_MODE_COLOR 0x0001 0 0 = Mono-compatible
1 = Color
VIDEO_MODE_GRAPHICS 0x0002 1 0 = Text mode
1 = Graphics
VIDEO_MODE_PALETTE_DRIVEN 0x0004 2 0 = Colors are direct
1 = Colors are indexed to a palette
VIDEO_MODE_MANAGED_PALETTE 0x0008 3 0 = Palette is fixed (must be queried from miniport driver)
1 = Palette is settable
VIDEO_MODE_INTERLACED 0x0010 4 0 = Non-interlaced mode
1 = Interlaced mode
VIDEO_MODE_NO_OFF_SCREEN 0x0020 5 0 = Offscreen memory is available
1 = Offscreen memory cannot be used to store information
VIDEO_MODE_NO_64_BIT_ACCESS 0x0040 6 0 = 64-bit memory writes to frame buffer are handled properly
1 = 64-bit memory writes to frame buffer are not handled

VideoMemoryBitmapWidth
Specifies the width, in pixels, of the video memory bitmap.
VideoMemoryBitmapHeight
Specifies the height, in pixels, of the video memory bitmap.
DriverSpecificAttributeFlags
Is a set of flags indicating certain behavior for the device. These private flags are defined in the miniport driver, and are for the use by the miniport and display drivers only.

Headers

Declared in ntddvdeo.h. Include ntddvdeo.h.

Comments

The video miniport driver returns an array of VIDEO_MODE_INFORMATION structures in response to an IOCTL_VIDEO_QUERY_AVAIL_MODES request, with each structure containing information about one mode of the adapter. The miniport driver returns one VIDEO_MODE_INFORMATION structure that contains information about the adapter's current mode in response to an IOCTL_VIDEO_QUERY_CURRENT_MODE request.

Three members of VIDEO_MODE_INFORMATION, VisScreenWidth, VideoMemoryBitmapWidth, and ScreenStride, are associated with horizontal screen width. For displays that use one or more bytes per pixel, these members satisfy the inequality
VisScreenWidth <= VideoMemoryBitmapWidth <= ScreenStride.

In a similar relationship for vertical screen height, VisScreenHeight and VideoMemoryBitmapHeight satisfy the inequality
VisScreenHeight <= VideoMemoryBitmapHeight.

See Also

VIDEO_MEMORY_INFORMATION, IOCTL_VIDEO_QUERY_AVAIL_MODES, IOCTL_VIDEO_QUERY_CURRENT_MODE


VIDEO_NUM_MODES

The VIDEO_NUM_MODES structure contains the number of modes supported by a video adapter, and the size of the structure that describes each mode.

typedef struct _VIDEO_NUM_MODES {
  ULONG  NumModes;
  ULONG  ModeInformationLength;
} VIDEO_NUM_MODES, *PVIDEO_NUM_MODES;

Members

NumModes
Specifies the number of modes supported by the device.
ModeInformationLength
Is the length, in bytes, of the VIDEO_MODE_INFORMATION structure that describes each of the modes supported by the device.

Headers

Declared in ntddvdeo.h. Include ntddvdeo.h.

Comments

The miniport driver returns a VIDEO_NUM_MODES structure in response to an IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES request.

See Also

VIDEO_MODE_INFORMATION, IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES


VIDEO_PORT_AGP_INTERFACE

The VIDEO_PORT_AGP_INTERFACE structure describes the AGP service routines provided by the video port driver.

typedef struct _VIDEO_PORT_AGP_INTERFACE {
  SHORT  Size;
  SHORT  Version;
  PVOID  Context;
  PINTERFACE_REFERENCE  InterfaceReference;
  PINTERFACE_DEREFERENCE  InterfaceDereference;
  PAGP_RESERVE_PHYSICAL  AgpReservePhysical;
  PAGP_RELEASE_PHYSICAL  AgpReleasePhysical;
  PAGP_COMMIT_PHYSICAL  AgpCommitPhysical;
  PAGP_FREE_PHYSICAL  AgpFreePhysical;
  PAGP_RESERVE_VIRTUAL  AgpReserveVirtual;
  PAGP_RELEASE_VIRTUAL  AgpReleaseVirtual;
  PAGP_COMMIT_VIRTUAL  AgpCommitVirtual;
  PAGP_FREE_VIRTUAL  AgpFreeVirtual;
  ULONGLONG  AgpAllocationLimit;
} VIDEO_PORT_AGP_INTERFACE, *PVIDEO_PORT_AGP_INTERFACE;

Members

Size
Specifies the size in bytes of this structure.
Version
Specifies the version of the interface to be returned by the video port driver. The current interface version is defined in video.h and has the form VIDEO_PORT_AGP_INTERFACE_N.
Context
Points to a video port driver-defined context for the interface.
InterfaceReference
Points to the video port driver-implemented reference routine for this interface.
InterfaceDereference
Points to the video port driver-implemented dereference routine for this interface.
AgpReservePhysical
Points to the video port driver-implemented AgpReservePhysical routine.
AgpReleasePhysical
Points to the video port driver-implemented AgpReleasePhysical routine.
AgpCommitPhysical
Points to the video port driver-implemented AgpCommitPhysical routine.
AgpFreePhysical
Points to the video port driver-implemented AgpFreePhysical routine.
AgpReserveVirtual
Points to the video port driver-implemented AgpReserveVirtual routine.
AgpReleaseVirtual
Points to the video port driver-implemented AgpReleaseVirtual routine.
AgpCommitVirtual
Points to the video port driver-implemented AgpCommitVirtual routine.
AgpFreeVirtual
Points to the video port driver-implemented AgpFreeVirtual routine.
AgpAllocationLimit
Specifies the maximum total number of bytes of AGP memory that a miniport driver can commit.

Headers

Declared in video.h. Include video.h.

Comments

PnP video miniport drivers that can use AGP must fill in the Size and Version members, and then call the VideoPortQueryServices function, which initializes the remaining members of this structure.

See Also

VideoPortQueryServices, INTERFACE


VIDEO_PORT_AGP_INTERFACE_2

The VIDEO_PORT_AGP_INTERFACE_2 structure describes the AGP service routines provided by the video port driver.

typedef struct _VIDEO_PORT_AGP_INTERFACE_2 {
  SHORT  Size;
  SHORT  Version;
  PVOID  Context;
  PINTERFACE_REFERENCE  InterfaceReference;
  PINTERFACE_DEREFERENCE  InterfaceDereference;
  PAGP_RESERVE_PHYSICAL  AgpReservePhysical;
  PAGP_RELEASE_PHYSICAL  AgpReleasePhysical;
  PAGP_COMMIT_PHYSICAL  AgpCommitPhysical;
  PAGP_FREE_PHYSICAL  AgpFreePhysical;
  PAGP_RESERVE_VIRTUAL  AgpReserveVirtual;
  PAGP_RELEASE_VIRTUAL  AgpReleaseVirtual;
  PAGP_COMMIT_VIRTUAL  AgpCommitVirtual;
  PAGP_FREE_VIRTUAL  AgpFreeVirtual;
  ULONGLONG  AgpAllocationLimit;
  PAGP_SET_RATE  AgpSetRate;
} VIDEO_PORT_AGP_INTERFACE_2, *PVIDEO_PORT_AGP_INTERFACE_2;

Members

Size
Specifies the size in bytes of this structure.
Version
Specifies the version of the interface to be returned by the video port driver. The current interface version is defined in video.h and has the form VIDEO_PORT_AGP_INTERFACE_N.
Context
Points to a video port driver-defined context for the interface.
InterfaceReference
Points to the video port driver-implemented reference routine for this interface.
InterfaceDereference
Points to the video port driver-implemented dereference routine for this interface.
AgpReservePhysical
Points to the video port driver-implemented AgpReservePhysical routine.
AgpReleasePhysical
Points to the video port driver-implemented AgpReleasePhysical routine.
AgpCommitPhysical
Points to the video port driver-implemented AgpCommitPhysical routine.
AgpFreePhysical
Points to the video port driver-implemented AgpFreePhysical routine.
AgpReserveVirtual
Points to the video port driver-implemented AgpReserveVirtual routine.
AgpReleaseVirtual
Points to the video port driver-implemented AgpReleaseVirtual routine.
AgpCommitVirtual
Points to the video port driver-implemented AgpCommitVirtual routine.
AgpFreeVirtual
Points to the video port driver-implemented AgpFreeVirtual routine.
AgpAllocationLimit
Specifies the maximum total number of bytes of AGP memory that a miniport driver can commit.
AgpSetRate
Points to the video port driver-implemented AgpSetRate routine.

Headers

Declared in video.h. Include video.h.

Comments

PnP video miniport drivers that can use AGP must fill in the Size and Version members, and then call the VideoPortQueryServices function, which initializes the remaining members of this structure.

This structure is identical to the VIDEO_PORT_AGP_INTERFACE structure, except for the AgpSetRate member, which that structure lacks. Video miniport drivers should first attempt to use VIDEO_PORT_AGP_INTERFACE_2 in a call to VideoPortQueryServices. If that call fails, due to the fact that the AGP filter driver does not support the newer version of the AGP interface, the video miniport driver can make a second call to VideoPortQueryServices, this time passing a VIDEO_PORT_AGP_INTERFACE structure.

See Also

VideoPortQueryServices, INTERFACE, VIDEO_PORT_AGP_INTERFACE


VIDEO_PORT_AGP_SERVICES

The VIDEO_PORT_AGP_SERVICES structure is obsolete and is supported only for backward compatibility with existing drivers. In its place, driver writers should use VIDEO_PORT_AGP_INTERFACE.

The VIDEO_PORT_AGP_SERVICES structure describes the AGP service routines provided by the video port driver. PnP video miniport drivers that can use AGP should call VideoPortGetAgpServices to initialize this structure. The video port driver initializes the entire structure; the miniport driver should never change any members.

typedef struct _VIDEO_PORT_AGP_SERVICES {
  PAGP_RESERVE_PHYSICAL  AgpReservePhysical;
  PAGP_RELEASE_PHYSICAL  AgpReleasePhysical;
  PAGP_COMMIT_PHYSICAL  AgpCommitPhysical;
  PAGP_FREE_PHYSICAL  AgpFreePhysical;

  PAGP_RESERVE_VIRTUAL  AgpReserveVirtual;
  PAGP_RELEASE_VIRTUAL  AgpReleaseVirtual;
  PAGP_COMMIT_VIRTUAL  AgpCommitVirtual;
  PAGP_FREE_VIRTUAL  AgpFreeVirtual;
  ULONGLONG  AllocationLimit;
} VIDEO_PORT_AGP_SERVICES, *PVIDEO_PORT_AGP_SERVICES;

Headers

Declared in videoagp.h. Include video.h.


VIDEO_PORT_CONFIG_INFO

The VIDEO_PORT_CONFIG_INFO structure contains bus-specific adapter configuration information. This structure is used to set up the video hardware and to supply the video port driver with configuration information. The video port driver can then allocate necessary system resources for the miniport driver and its adapter.

typedef struct _VIDEO_PORT_CONFIG_INFO {
  ULONG  Length;
  ULONG  SystemIoBusNumber;
  INTERFACE_TYPE  AdapterInterfaceType;
  ULONG  BusInterruptLevel;
  ULONG  BusInterruptVector;
  KINTERRUPT_MODE  InterruptMode;
  ULONG  NumEmulatorAccessEntries;
  PEMULATOR_ACCESS_ENTRY  EmulatorAccessEntries;
  ULONG_PTR  EmulatorAccessEntriesContext;
  PHYSICAL_ADDRESS  VdmPhysicalVideoMemoryAddress;
  ULONG  VdmPhysicalVideoMemoryLength;
  ULONG  HardwareStateSize;
  ULONG  DmaChannel;
  ULONG  DmaPort;
  UCHAR  DmaShareable;
  UCHAR  InterruptShareable;
  BOOLEAN  Master;
  DMA_WIDTH  DmaWidth;
  DMA_SPEED  DmaSpeed;
  BOOLEAN  bMapBuffers;
  BOOLEAN  NeedPhysicalAddresses;
  BOOLEAN  DemandMode;
  ULONG  MaximumTransferLength;
  ULONG  NumberOfPhysicalBreaks;
  BOOLEAN  ScatterGather;
  ULONG  MaximumScatterGatherChunkSize;
  PVIDEO_PORT_GET_PROC_ADDRESS VideoPortGetProcAddress;
  PWSTR  DriverRegistryPath;
  ULONGLONG  SystemMemorySize;
} VIDEO_PORT_CONFIG_INFO, *PVIDEO_PORT_CONFIG_INFO;

Members

Length
Is the size in bytes of this structure. The video port driver always initializes the Length member. In effect, its value indicates the version of VIDEO_PORT_CONFIG_INFO being used by the system. Because this structure might grow from one version of the system to the next, a miniport driver should check this member to determine whether it is at least the sizeof(VIDEO_PORT_CONFIG_INFO) that the miniport driver uses to configure its adapter.
SystemIoBusNumber
Specifies the system-assigned number of the I/O bus on which the miniport driver's adapter might be connected. The video port driver always initializes this member.
AdapterInterfaceType
Specifies the type of bus interface. The video port driver always sets this member based on the bus on which the PnP Manager detected the device.
BusInterruptLevel
This member is irrelevant if the video hardware does not generate interrupts, indicated by setting the HwInterrupt member in the VIDEO_HW_INITIALIZATION_DATA structure to NULL. Otherwise, it specifies the bus-relative IRQL that corresponds to the interrupt request on Isa or MicroChannel type buses. The preset default value for this member is zero. A miniport driver must supply the correct value if it handles interrupts for a video adapter on an Isa or MicroChannel type bus, or for a video adapter configured for level-sensitive interrupts on an Eisa type bus.

If a miniport driver's HwVidFindAdapter function finds that the video adapter does not generate interrupts or that it cannot determine a valid interrupt vector/level for the adapter, HwVidFindAdapter should set both BusInterruptLevel and BusInterruptVector to zero.

BusInterruptVector
This member is irrelevant if the video hardware does not generate interrupts, indicated by setting the HwInterrupt member in the VIDEO_HW_INITIALIZATION_DATA structure to NULL. Otherwise, it specifies the bus-relative vector used by the video hardware on I/O buses that use interrupt vectors, such as PCI buses. The preset default value for this member is zero.

If a miniport driver's HwVidFindAdapter function finds that the video adapter does not generate interrupts or that it cannot determine a valid interrupt vector/level for the adapter, HwVidFindAdapter should set both BusInterruptVector and BusInterruptLevel to zero.

InterruptMode
Indicates whether the video hardware uses Latched or LevelSensitive interrupts. The video port driver initializes this member if it is relevant, but a miniport driver with an ISR should check that it contains the correct value and reset it if necessary.
NumEmulatorAccessEntries
This member and all subsequent members through HardwareStateSize are irrelevant to miniport drivers that do not declare themselves to be VGA-compatible miniport drivers on x86-based NT-based operating system platforms. For miniport drivers that do not support VGA-compatible SVGA adapters on x86-based machines, this member should be zero. Otherwise, it specifies the number of EMULATOR_ACCESS_RANGE-type elements in the following array.
EmulatorAccessEntries
Points to an array of emulator access ranges set up by the VGA-compatible miniport driver. Each emulator access range must be a proper subset of the miniport driver's VIDEO_ACCESS_RANGE-type array. Each element specifies a range of I/O ports to be hooked out by the V86 emulator and, possibly, monitored by a driver-supplied SvgaHwIoPort Xxx function whenever an MS-DOS application, running full screen, attempts to write directly to the video adapter registers. Usually, this array describes all I/O port ranges in the corresponding access ranges array. If the miniport driver defines its array of emulator access entries statically in the driver itself, the port driver initializes this pointer to that array. If NumEmulatorAccessEntries is zero, this member is NULL.
EmulatorAccessEntriesContext
Specifies a value passed with each call to an SvgaHwIoPort Xxx function described in the EmulatorAccessEntries array. Usually, a VGA-compatible miniport driver sets the value of this member to the HwDeviceExtension pointer, or to an offset within the device extension, so the miniport driver can maintain state, such as batched application-issued instructions, in its SvgaHwIoPort Xxx functions.
VdmPhysicalVideoMemoryAddress
Specifies the base (mapped) logical address of a range of video memory to be mapped into a VDM's address space for x86 BIOS INT10 support. For miniport drivers that do not support VGA-compatible adapters on x86-based machines, this member should be NULL.
VdmPhysicalVideoMemoryLength
Specifies the size in bytes of the range be mapped into a VDM's address space for x86 BIOS support. For miniport drivers that do not support VGA-compatible adapters on x86-based machines, this member should be zero.
HardwareStateSize
Specifies the minimum size in bytes required to store hardware state information in response to an IOCTL_VIDEO_SAVE_HARDWARE_STATE request, which must be supported only by VGA-compatible miniport drivers on x86-based machines. The initialized value for this member is zero. A VGA-compatible miniport driver must set this member to the number of bytes it requires to hold saved adapter state.
DmaChannel
Reserved for system use.
DmaPort
Reserved for system use.
DmaShareable
Reserved for system use.
InterruptShareable
If the miniport driver's device interrupts, this member should be set to zero if the interrupt cannot be shared with another device, or set to one if the interrupt can be shared. Otherwise, a miniport driver can ignore this member.
Master
Reserved for system use.
DmaWidth
Reserved for system use.
DmaSpeed
Reserved for system use.
bMapBuffers
Reserved for system use.
NeedPhysicalAddresses
Reserved for system use.
DemandMode
Reserved for system use.
MaximumTransferLength
Reserved for system use.
NumberOfPhysicalBreaks
Reserved for system use.
ScatterGather
Reserved for system use.
MaximumScatterGatherChunkSize
Reserved for system use.
VideoPortGetProcAddress
Points to a Windows 2000 or later video port driver function. When this member is set with the address of such a video port driver function, the video miniport driver can use the video port driver function without linking to it directly. This enables a Windows 2000 (or later) driver binary to be run on Windows NT 4.0 or Windows 2000 or later. See PVIDEO_PORT_GET_PROC_ADDRESS for more information.
DriverRegistryPath
Points to the registry path containing the device's service under the key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services. The display driver can use this information in any way it deems useful.
SystemMemorySize
Indicates to a driver the amount, in bytes, of physical memory in the system.

Headers

Declared in video.h. Include video.h.

See Also

HwVidFindAdapter, IOCTL_VIDEO_SAVE_HARDWARE_STATE, VIDEO_ACCESS_RANGE, VIDEO_HW_INITIALIZATION_DATA, VideoPortGetAccessRanges, VideoPortGetDeviceBase, VideoPortGetDeviceData, VideoPortVerifyAccessRanges


VIDEO_PORT_I2C_INTERFACE

The VIDEO_PORT_I2C_INTERFACE structure describes the I2C service routines provided by the video port driver.

typedef struct _VIDEO_PORT_I2C_INTERFACE {
  USHORT  Size;
  USHORT  Version;
  PVOID  Context;
  PINTERFACE_REFERENCE  InterfaceReference;
  PINTERFACE_DEREFERENCE  InterfaceDereference;
  PI2C_START  I2CStart;
  PI2C_STOP  I2CStop;
  PI2C_WRITE  I2CWrite;
  PI2C_READ  I2CRead;
} VIDEO_PORT_I2C_INTERFACE, *PVIDEO_PORT_I2C_INTERFACE;

Members

Size
Specifies the size in bytes of this structure.
Version
Specifies the version of the interface to be returned by the miniport driver. The current interface version is defined in video.h, and has the form VIDEO_PORT_I2C_INTERFACE_N.
Context
Points to a miniport driver-defined context for the interface.
InterfaceReference
Points to the video port driver-implemented reference routine for this interface.
InterfaceDereference
Points to the video port driver-implemented dereference routine for this interface.
I2CStart
Points to the video port driver's I2CStart routine.
I2CStop
Points to the video port driver's I2CStop routine.
I2CWrite
Points to the video port driver's I2CWrite routine.
I2CRead
Points to the video port driver's I2CRead routine.

Headers

Declared in video.h. Include video.h.

Comments

PnP video miniport drivers that can use I2C should fill in the Size and Version members of this structure, and then call VideoPortQueryServices, which initializes the remaining members of this structure.

See Also

VideoPortQueryServices, INTERFACE


VIDEO_PORT_INT10_INTERFACE

The VIDEO_PORT_INT10_INTERFACE structure provides a way to allocate and deallocate memory in another thread's context, read from and write to that memory, and make INT10 BIOS calls.

typedef struct _VIDEO_PORT_INT10_INTERFACE {
  IN USHORT  Size;
  IN USHORT  Version;
  OUT PVOID  Context;
  OUT PINTERFACE_REFERENCE  InterfaceReference;
  OUT PINTERFACE_DEREFERENCE  InterfaceDereference;
  OUT PINT10_ALLOCATE_BUFFER  Int10AllocateBuffer;
  OUT PINT10_FREE_BUFFER  Int10FreeBuffer;
  OUT PINT10_READ_MEMORY  Int10ReadMemory;
  OUT PINT10_WRITE_MEMORY  Int10WriteMemory;
  OUT PINT10_CALL_BIOS  Int10CallBios;
} VIDEO_PORT_INT10_INTERFACE, *PVIDEO_PORT_INT10_INTERFACE;

Members

Size
Specifies the size in bytes of this structure.
Version
Specifies the version of the interface to be returned by the video port driver. The current interface version is defined in video.h and has the form VIDEO_PORT_INT10_INTERFACE_N.
Context
Points to a video port driver-defined context for the interface.
InterfaceReference
Points to the video port driver-implemented reference routine for this interface.
InterfaceDereference
Points to the video port driver-implemented dereference routine for this interface.
Int10AllocateBuffer
Points to the video port driver-implemented Int10AllocateBuffer routine.
Int10FreeBuffer
Points to the video port driver-implemented Int10FreeBuffer routine.
Int10ReadMemory
Points to the video port driver-implemented Int10ReadMemory routine.
Int10WriteMemory
Points to the video port driver-implemented Int10WriteMemory routine.
Int10CallBios
Points to the video port driver-implemented Int10CallBios routine.

Headers

Declared in video.h. Include video.h.

Comments

PnP video miniport drivers that intend to make BIOS calls should fill in the Size and Version members of this structure, and then call VideoPortQueryServices, which initializes the remaining members of this structure.

See Also

VideoPortQueryServices


VIDEO_POWER_MANAGEMENT

The VIDEO_POWER_MANAGEMENT structure contains information required by the miniport driver to perform power management.

typedef struct _VIDEO_POWER_MANAGEMENT {
  ULONG  Length;
  ULONG  DPMSVersion;
  ULONG  PowerState;
} VIDEO_POWER_MANAGEMENT, *PVIDEO_POWER_MANAGEMENT;

Members

Length
Is the size in bytes of this VIDEO_POWER_MANAGEMENT structure.
DPMSVersion
Specifies the version of the Display Power Management Signaling (DPMS) standard supported by the device. Currently, the video port driver sets this member to zero, which corresponds with Version 1.0 of the VESA DPMS Standard.
PowerState
Specifies the power management state to be set or queried. This member can be one of the following values in the VIDEO_POWER_STATE enumeration:
VideoPowerOn
The monitor and graphics adapter are both fully powered on and operational.
VideoPowerStandBy
The monitor is running at a reduced power level that requires a short recovery time to VideoPowerOn. The graphics adapter is powered on (registers are still active and video memory is refreshed); however, clocks might be lost.
VideoPowerSuspend
The monitor is running at a substantially reduced power level that requires a possibly longer recovery time than VideoPowerStandBy to VideoPowerOn. The graphics adapter is off.
VideoPowerOff
The monitor and graphics adapter are both off, consuming no power at all.
VideoPowerHibernate
The monitor and graphics adapter are both fully powered on and operational.

Headers

Declared in ntddvdeo.h. Include ntddvdeo.h.

Comments

The video port driver allocates and fills in the VIDEO_POWER_MANAGEMENT structure. Depending on the power management request dispatched to the video port, the video port driver passes this structure to the miniport driver's HwVidGetPowerState or HwVidSetPowerState routine.

VideoPowerHibernate is provided to the miniport driver as notification only. The miniport driver's HwVidSetPowerState function must leave the monitor and graphics adapter fully powered on and operational. For all other states, the miniport driver must put the device into the specified power state.

A driver will always enter all other power states from the VideoPowerOn state. For example, a driver will not move directly to VideoPowerHibernate from VideoPowerOff; it will always go from VideoPowerHibernate to VideoPowerOn and then to VideoPowerOff.

See Also

HwVidGetPowerState, HwVidSetPowerState


VIDEO_PUBLIC_ACCESS_RANGES

The VIDEO_PUBLIC_ACCESS_RANGES structure contains information about video resources other than frame buffers and video RAM, such as memory-mapped I/O registers or ports.

typedef struct _VIDEO_PUBLIC_ACCESS_RANGES {
  ULONG  InIoSpace;
  ULONG  MappedInIoSpace;
  PVOID  VirtualAddress;
} VIDEO_PUBLIC_ACCESS_RANGES, *PVIDEO_PUBLIC_ACCESS_RANGES;

Members

InIoSpace
Indicates the location of the range. This parameter can be one of the following values, or certain bitwise combinations of these values:
Value | Meaning
VIDEO_MEMORY_SPACE_DENSE | Obsolete.
VIDEO_MEMORY_SPACE_IO | The indicated address ranges are in system I/O space rather than in memory space.
VIDEO_MEMORY_SPACE_MEMORY | The indicated address ranges are in memory space rather than in system I/O space.
VIDEO_MEMORY_SPACE_P6CACHE | The processor aggregates a sequence of write operations and sends them to a given cache line. The processor then flushes the cache. This flag is meaningful only when VIDEO_MEMORY_SPACE_IO is not set.
VIDEO_MEMORY_SPACE_USER_MODE | Indicates that the address range specified should be mapped into user mode rather than kernel mode. This flag is meaningful only when VIDEO_MEMORY_SPACE_IO is not set.

MappedInIoSpace
Indicates, on the current platform, whether the registers or ports are mapped in I/O space or in memory space. A value of TRUE (1) indicates that the registers or ports are mapped in I/O space; a value of FALSE (0) indicates that the registers or ports are mapped in memory space.
VirtualAddress
Points to the location of the registers or I/O ports as mapped under the current architecture.

Headers

Declared in ntddvdeo.h. Include ntddvdeo.h.

Comments

VIDEO_PUBLIC_ACCESS_RANGES is similar to VIDEO_ACCESS_RANGE in that both are used by miniport drivers to obtain information about display resources. The principal difference is that VIDEO_PUBLIC_ACCESS_RANGES contains information about control and accelerator registers for an adapter, while VIDEO_ACCESS_RANGE is used to hold frame buffer and video RAM addresses.

VIDEO_PUBLIC_ACCESS_RANGES is used as an input buffer with the IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES request.

See Also

VIDEO_ACCESS_RANGE, IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES


VIDEO_REQUEST_PACKET

A pointer to a VIDEO_REQUEST_PACKET structure is passed to the miniport driver's HwVidStartIO function by the video port driver. The video port driver sets up the VRP from the IRP sent in response to a GDI call to EngDeviceIoControl. Usually, the corresponding display driver makes the call to EngDeviceIoControl when it needs support from the video port-miniport driver pair. The video port driver calls the miniport driver with the VRP to process the given IOCTL_VIDEO_XXX request.

typedef struct _VIDEO_REQUEST_PACKET {
  ULONG  IoControlCode;
  PSTATUS_BLOCK  StatusBlock;
  PVOID  InputBuffer;
  ULONG  InputBufferLength;
  PVOID  OutputBuffer;
  ULONG  OutputBufferLength;
} VIDEO_REQUEST_PACKET, *PVIDEO_REQUEST_PACKET;

Members

IoControlCode
Specifies an IOCTL_VIDEO_XXX value passed to the EngDeviceIoControl function by the caller and sent to the video port driver in an IRP. For more information about the set of system-defined IOCTL_VIDEO_XXX that miniport drivers must support, see Video I/O Control Codes.
StatusBlock
Points to a STATUS_BLOCK structure in the VRP. StatusBlock is filled in by the miniport driver with return information upon completion of each VRP.
InputBuffer
Points to an input buffer that contains information passed in by the caller. The structure for the data depends on the value of IoControlCode. This member actually points to the same buffer as that indicated by OutputBuffer.
InputBufferLength
Specifies the size in bytes of the input buffer.
OutputBuffer
Points to an output buffer into which the miniport driver transfers data to be returned to the caller. The structure for the data depends on the value of IoControlCode. Because this member points to the same buffer as InputBuffer, a miniport driver must not write output in the OutputBuffer before it has consumed all input data from the InputBuffer.
OutputBufferLength
Specifies the size in bytes of the output buffer. A miniport driver cannot enlarge this buffer. A miniport driver should set the Status member of the StatusBlock with ERROR_INSUFFICIENT_BUFFER or ERROR_MORE_DATA if the given OutputBuffer is too small to contain all the returned information.

Headers

Declared in video.h. Include video.h.

See Also

HwVidStartIO, IOCTL_VIDEO_Xxx, STATUS_BLOCK


VIDEO_SHARE_MEMORY

The VIDEO_SHARE_MEMORY structure is used in a request to the video miniport driver for a block of user-mode memory to be shared with the specified process.

typedef struct _VIDEO_SHARE_MEMORY {
  HANDLE  ProcessHandle;
  ULONG  ViewOffset;
  ULONG  ViewSize;
  PVOID  RequestedVirtualAddress;
} VIDEO_SHARE_MEMORY, *PVIDEO_SHARE_MEMORY;

Members

ProcessHandle
Is a handle to the current process. This member is usually set to NtCurrentProcess, a macro defined in ntddk.h.
ViewOffset
Indicates the byte offset from the beginning of the frame buffer. This member is usually set to 0.
ViewSize
Indicates the size, in bytes, of the frame buffer.
RequestedVirtualAddress
Indicates the location of the requested frame buffer in the process's memory. This member is normally set to NULL, which means the display driver writer does not care about the precise location of the requested memory. If this member is set to a non-NULL value, the display driver writer intends that the frame buffer be located at that address. In this case, the display driver writer must be certain that the location specified is not already in use for another purpose.

Headers

Declared in ntddvdeo.h. Include ntddvdeo.h.

Comments

VIDEO_SHARE_MEMORY is provided so that applications such as Direct Draw can have a view of video memory. Although the display driver is unable to directly provide such access to video memory, it can call into the video miniport for this purpose. The display driver does this by sending an IOCTL_VIDEO_SHARE_VIDEO_MEMORY request to the miniport driver. When the miniport driver fulfills this request, it uses the information in the VIDEO_SHARE_MEMORY structure, and fills in a VIDEO_SHARE_MEMORY_INFORMATION structure with the actual location of the requested memory, if no location was specified. When the application no longer needs the shared memory, the display driver can release this memory by making an IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY request, which also uses a VIDEO_SHARE_MEMORY structure as an input buffer.

For structures used in mapping into kernel-mode video memory, see VIDEO_MEMORY and VIDEO_MEMORY_INFORMATION.

See Also

VIDEO_SHARE_MEMORY_INFORMATION, IOCTL_VIDEO_SHARE_VIDEO_MEMORY, IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY


VIDEO_SHARE_MEMORY_INFORMATION

The VIDEO_SHARE_MEMORY_INFORMATION structure is used to communicate to the display driver that a request for a block of user-mode memory has been fulfilled.

typedef struct _VIDEO_SHARE_MEMORY_INFORMATION {
  ULONG  SharedViewOffset;
  ULONG  SharedViewSize;
  PVOID  VirtualAddress;
} VIDEO_SHARE_MEMORY_INFORMATION, *PVIDEO_SHARE_MEMORY_INFORMATION;

Members

SharedViewOffset
Indicates the offset, in bytes, from the beginning of the frame buffer.
SharedViewSize
Indicates the size, in bytes, of the frame buffer. The value of this member will always be a multiple of 64 KB.
VirtualAddress
Indicates the address in virtual memory at which the requested memory was mapped.

Headers

Declared in ntddvdeo.h. Include ntddvdeo.h.

Comments

When an application must have access to user-mode video memory, the display driver can call into the video miniport driver by sending it an IOCTL_VIDEO_SHARE_VIDEO_MEMORY request. The miniport driver uses a VIDEO_SHARE_MEMORY structure as an input buffer, and communicates back to the display driver a VIDEO_SHARE_MEMORY_INFORMATION structure.

The video miniport fills out a VIDEO_SHARE_MEMORY_INFORMATION structure based on information in a VIDEO_SHARE_MEMORY structure. The following table summarizes how the information is used:

VIDEO_SHARE_MEMORY member | Result on VIDEO_SHARE_MEMORY_INFORMATION
ProcessHandle | Is not used.
ViewOffset | Copied directly to SharedViewOffset.
ViewSize | Values that are multiples of 64 KB are copied directly to SharedViewSize. Other values are rounded up to the next larger multiple of 64 KB.
RequestedVirtualAddress | If NULL, the miniport driver determines the address of a frame buffer to assign to VirtualAddress. If non-NULL, the miniport driver attempts to assign that value to VirtualAddress.

See Also

VIDEO_SHARE_MEMORY, IOCTL_VIDEO_SHARE_VIDEO_MEMORY


VIDEO_x86_BIOS_ARGUMENTS

The VIDEO_x86_BIOS_ARGUMENTS structure is used to support full-screen MS-DOS application INT10 calls. It contains seven of the high-end x86 microprocessor registers.

typedef struct VIDEO_x86_BIOS_ARGUMENTS {
  ULONG  Eax;
  ULONG  Ebx;
  ULONG  Ecx;
  ULONG  Edx;
  ULONG  Esi;
  ULONG  Edi;
  ULONG  Ebp;
} VIDEO_x86_BIOS_ARGUMENTS, *PVIDEO_x86_BIOS_ARGUMENTS;

Members

Eax, Ebx, Ecx, Edx, Esi, Edi, Ebp
Are the seven x86 microprocessor registers.

Headers

Declared in video.h. Include video.h.

Comments

MS-DOS INT10s are usually "set mode" requests for the video adapter. Each value is put in the appropriate register and an INT10 call is performed by VideoPortInt10.

A miniport driver should not set a segment:offset-type pointer in any member of this structure. Such an address is interpreted as an unsigned DWORD value.

See Also

VideoPortInt10


VIDEOPARAMETERS

The video miniport driver receives a VIDEOPARAMETERS structure in the InputBuffer of a VIDEO_REQUEST_PACKET when the IOCTL request is IOCTL_VIDEO_HANDLE_VIDEOPARAMETERS. Depending on the dwCommand member of VIDEOPARAMETERS, the miniport driver should get the television connector and copy protection capabilities of the device or set the desired copy protection functionality, and update the structure accordingly.

typedef struct _VIDEOPARAMETERS {
  GUID   Guid;
  DWORD  dwOffset;
  DWORD  dwCommand;
  DWORD  dwFlags;
  DWORD  dwMode;
  DWORD  dwTVStandard;
  DWORD  dwAvailableModes;
  DWORD  dwAvailableTVStandard;
  DWORD  dwFlickerFilter;
  DWORD  dwOverScanX;
  DWORD  dwOverScanY;
  DWORD  dwMaxUnscaledX;
  DWORD  dwMaxUnscaledY;
  DWORD  dwPositionX;
  DWORD  dwPositionY;
  DWORD  dwBrightness;
  DWORD  dwContrast;
  DWORD  dwCPType;
  DWORD  dwCPCommand;
  DWORD  dwCPStandard;
  DWORD  dwCPKey;
  BYTE   bCP_APSTriggerBits;
  BYTE   bOEMCopyProtection[256];
} VIDEOPARAMETERS, *PVIDEOPARAMETERS, FAR *LPVIDEOPARAMETERS;

Members

Guid
Specifies the globally unique identifier (GUID) for this structure {02C62061-1097-11d1-920F-00A024DF156E}. A video miniport driver must verify the GUID at the start of the structure before processing the structure.
dwOffset
Is reserved and should be ignored by the video miniport driver.
dwCommand
Indicates the action to be performed by the driver. This member can be one of the following values:
VP_COMMAND_GET
The miniport driver should return the current TV connector and/or copy protection capabilities of the device in the appropriate members of this structure.
VP_COMMAND_SET
The miniport driver should set the TV and copy protection hardware based on the appropriate members of this structure, and update this structure accordingly.
dwFlags
Indicates which members of this structure contain valid data. When dwCommand is VP_COMMAND_GET, the driver should set the appropriate bits in this member to indicate in which corresponding members it has returned valid data. When dwCommand is VP_COMMAND_SET, the driver should set the functionality on the hardware using values in the members that correspond with the bits set in this member, and update the structure accordingly. This member can be a bit-wise OR of the following values:

VP_FLAGS_BRIGHTNESS

VP_FLAGS_CONTRAST

VP_FLAGS_COPYPROTECT

VP_FLAGS_FLICKER

VP_FLAGS_MAX_UNSCALED (not valid on VP_COMMAND_SET)

VP_FLAGS_OVERSCAN

VP_FLAGS_POSITION

VP_FLAGS_TV_MODE

VP_FLAGS_TV_STANDARD

dwMode
Specifies the current playback mode. This member is valid for both the VP_COMMAND_SET and VP_COMMAND_GET commands, and can be a bit-wise OR of the following values:
VP_MODE_TV_PLAYBACK
Describes an optimal set of fields for video playback, with the flicker filter off and overscan display on.
VP_MODE_WIN_GRAPHICS
Describes the display settings that are optimal for Windows display, with the maximum flicker filter on and any overscan display off.
dwTVStandard
Is the current world television standard. This member is valid for both the VP_COMMAND_SET and VP_COMMAND_GET commands, and can be one of the following values:

VP_TV_STANDARD_NTSC_M

VP_TV_STANDARD_NTSC_M_J

VP_TV_STANDARD_NTSC_433

VP_TV_STANDARD_PAL_B

VP_TV_STANDARD_PAL_D

VP_TV_STANDARD_PAL_G

VP_TV_STANDARD_PAL_H

VP_TV_STANDARD_PAL_I

VP_TV_STANDARD_PAL_M

VP_TV_STANDARD_PAL_N

VP_TV_STANDARD_PAL_60

VP_TV_STANDARD_SECAM_B

VP_TV_STANDARD_SECAM_D

VP_TV_STANDARD_SECAM_G

VP_TV_STANDARD_SECAM_H

VP_TV_STANDARD_SECAM_K

VP_TV_STANDARD_SECAM_K1

VP_TV_STANDARD_SECAM_L

VP_TV_STANDARD_SECAM_L1

VP_TV_STANDARD_WIN_VGA

dwAvailableModes
Indicates the playback modes the device is capable of. This member is only valid for the VP_COMMAND_GET command, and can be a bit-wise OR of the following values:

VP_MODE_TV_PLAYBACK

VP_MODE_WIN_GRAPHICS

dwAvailableTVStandard
Specifies all available world television standards. This member is only valid for the VP_COMMAND_GET command, and can be a bit-wise OR of the following values:

VP_TV_STANDARD_NTSC_M

VP_TV_STANDARD_NTSC_M_J

VP_TV_STANDARD_NTSC_433

VP_TV_STANDARD_PAL_B

VP_TV_STANDARD_PAL_D

VP_TV_STANDARD_PAL_G

VP_TV_STANDARD_PAL_H

VP_TV_STANDARD_PAL_I

VP_TV_STANDARD_PAL_M

VP_TV_STANDARD_PAL_N

VP_TV_STANDARD_PAL_60

VP_TV_STANDARD_SECAM_B

VP_TV_STANDARD_SECAM_D

VP_TV_STANDARD_SECAM_G

VP_TV_STANDARD_SECAM_H

VP_TV_STANDARD_SECAM_K

VP_TV_STANDARD_SECAM_K1

VP_TV_STANDARD_SECAM_L

VP_TV_STANDARD_SECAM_L1

VP_TV_STANDARD_WIN_VGA

dwFlickerFilter
Is a value in tenths of a percent that indicates the flicker filter state. This member can be a value between [0,1000], and is valid for both VP_COMMAND_GET and VP_COMMAND_SET.
dwOverScanX
Is a value in tenths of a percent that indicates the amount of overscan in x. This member can be a value between [0,1000], and is valid for both VP_COMMAND_GET and VP_COMMAND_SET.
dwOverScanY
Is a value in tenths of a percent that indicates the amount of overscan in y. This member can be a value between [0,1000], and is valid for both VP_COMMAND_GET and VP_COMMAND_SET.
dwMaxUnscaledX
Is the maximum x resolution that the TV can display without having the hardware scale the video image. The miniport driver must set a value in this member when dwCommand is VP_COMMAND_GET. This member is invalid for VP_COMMAND_SET.
dwMaxUnscaledY
Is the maximum y resolution that the TV can display without having the hardware scale the video image. The miniport driver must set a value in this member when dwCommand is VP_COMMAND_GET. This member is invalid for VP_COMMAND_SET.
dwPositionX
Is the value used by the hardware to determine the current x position of the image on the TV. This member is specified in pixels, and is valid for both VP_COMMAND_GET and VP_COMMAND_SET.
dwPositionY
Is the value used by the hardware to determine the current y position of the image on the TV. This member is specified in scan lines, and is valid for both VP_COMMAND_GET and VP_COMMAND_SET.
dwBrightness
Is a percentage value that indicates the brightness setting on the TV. This member can be a value between [0,100], and is valid for both VP_COMMAND_GET and VP_COMMAND_SET.
dwContrast
Is a percentage value that indicates the contrast setting on the TV. This member can be a value between [0,100], and is valid for both VP_COMMAND_GET and VP_COMMAND_SET.
dwCPType
Specifies the type of copy protection supported by the device. This member is valid for both the VP_COMMAND_SET and VP_COMMAND_GET commands, and can be CP_TYPE_APS_TRIGGER.
dwCPCommand
Is the copy protection command. This member is only valid for the VP_COMMAND_SET command, and can be one of the following values:
VP_CP_CMD_ACTIVATE
The miniport driver should turn on copy protection and generate and return a unique copy protection key in dwCPKey.
VP_CP_CMD_CHANGE
If the copy protection key in dwCPKey is valid, the miniport driver should change copy protection based on the trigger data in bCP_APSTriggerBits.
VP_CP_CMD_DEACTIVATE
If the copy protection key in dwCPKey is valid, the miniport driver should turn off copy protection.
dwCPStandard
Is the TV standards for which copy protection types are available. This member is only valid for the VP_COMMAND_GET command, and can be a bit-wise OR of the following values:

VP_TV_STANDARD_NTSC_M

VP_TV_STANDARD_NTSC_M_J

VP_TV_STANDARD_NTSC_433

VP_TV_STANDARD_PAL_B

VP_TV_STANDARD_PAL_D

VP_TV_STANDARD_PAL_G

VP_TV_STANDARD_PAL_H

VP_TV_STANDARD_PAL_I

VP_TV_STANDARD_PAL_M

VP_TV_STANDARD_PAL_N

VP_TV_STANDARD_PAL_60

VP_TV_STANDARD_SECAM_B

VP_TV_STANDARD_SECAM_D

VP_TV_STANDARD_SECAM_G

VP_TV_STANDARD_SECAM_H

VP_TV_STANDARD_SECAM_K

VP_TV_STANDARD_SECAM_K1

VP_TV_STANDARD_SECAM_L

VP_TV_STANDARD_SECAM_L1

VP_TV_STANDARD_WIN_VGA

dwCPKey
Is a driver-generated copy protection key that is unique to this instance of the driver. This field is valid only for the VP_COMMAND_SET command. The miniport driver generates and returns this key when dwCPCommand is set to VP_CP_CMD_ACTIVATE. The caller must set this key when the dwCPCommand field is either VP_CP_CMD_DEACTIVATE or VP_CP_CMD_CHANGE. If the caller sets an incorrect key, the driver must not change the current copy protection settings.
bCP_APSTriggerBits
Specifies DVD APS trigger bit data. Bits zero and 1 are valid.
bOEMCopyProtection
OEM-specific copy protection data. This field is valid for both the VP_COMMAND_SET and VP_COMMAND_GET commands.

Headers

Declared in tvout.h. Include tvout.h.

See Also

IOCTL_VIDEO_HANDLE_VIDEOPARAMETERS, VIDEO_REQUEST_PACKET


VP_DEVICE_DESCRIPTION

The VP_DEVICE_DESCRIPTION structure describes the attributes of the physical device for which a driver is requesting a DMA object.

typedef struct _VP_DEVICE_DESCRIPTION {
  BOOLEAN  ScatterGather;
  BOOLEAN  Dma32BitAddresses;
  BOOLEAN  Dma64BitAddresses;
  ULONG  MaximumLength;
} VP_DEVICE_DESCRIPTION, *PVP_DEVICE_DESCRIPTION;

Members

ScatterGather
If TRUE, indicates that the device supports scatter/gather DMA. If FALSE, the device does not support scatter/gather DMA.
Dma32BitAddresses
If TRUE, specifies that 32-bit addresses are being used for DMA operations.
Dma64BitAddresses
If TRUE, specifies that 64-bit addresses are being used for DMA operations.
MaximumLength
Specifies the maximum number of bytes the device can handle in each DMA operation.

Headers

Declared in video.h. Include video.h.

Comments

This structure is available in Windows XP and later.


VP_DMA_ADAPTER

The VP_DMA_ADAPTER structure contains attribute information about a particular DMA adapter. This structure is an opaque data type that is used internally by the video port driver.

A video miniport driver should call the video port driver's VideoPortGetDmaAdapter to obtain information about a DMA adapter.

Comments

This structure is available in Windows XP and later.

Headers

Declared in video.h. Include video.h.

See Also

VideoPortGetDmaAdapter


VP_SCATTER_GATHER_ELEMENT

The VP_SCATTER_GATHER_ELEMENT structure is used to store information about a single scatter/gather element.

typedef struct _VP_SCATTER_GATHER_ELEMENT {
  PHYSICAL_ADDRESS  Address;
  ULONG  Length;
  ULONG_PTR  Reserved;
} VP_SCATTER_GATHER_ELEMENT, *PVP_SCATTER_GATHER_ELEMENT;

Members

Address
Specifies the logical address of one scatter/gather element.
Length
Specifies the length, in bytes, of the scatter/gather element.
Reserved
Reserved for system use.

Headers

Declared in video.h. Include video.h.

Comments

This structure is available in Windows XP and later.

A VP_SCATTER_GATHER_ELEMENT structure is one element of the VP_SCATTER_GATHER_LIST structure's array member.

See Also

VP_SCATTER_GATHER_LIST


VP_SCATTER_GATHER_LIST

The VP_SCATTER_GATHER_LIST structure is a collection of one or more scatter/gather elements.

typedef struct _VP_SCATTER_GATHER_LIST {
  ULONG  NumberOfElements;
  ULONG_PTR  Reserved;
  VP_SCATTER_GATHER_ELEMENT  Elements[];
} VP_SCATTER_GATHER_LIST, *PVP_SCATTER_GATHER_LIST;

Members

NumberOfElements
Specifies the number of scatter/gather elements in the Elements array member.
Reserved
Reserved for system use.
Elements
Is an array of VP_SCATTER_GATHER_ELEMENT structures.

Headers

Declared in video.h. Include video.h.

Comments

This structure is available in Windows XP and later.

The video port driver aggregates scatter/gather information in a VP_SCATTER_GATHER_LIST structure, passing it to the miniport driver's HwVidExecuteDma callback routine. The miniport driver uses this information when it sets up the video hardware for a DMA transfer.

See Also

VP_SCATTER_GATHER_ELEMENT, HwVidEXecuteDma


VPOSVERSIONINFO

The VPOSVERSIONINFO structure contains version information about the currently running operating system.

typedef struct _VPOSVERSIONINFO {
  IN ULONG  Size;
  OUT ULONG  MajorVersion;
  OUT ULONG  MinorVersion;
  OUT ULONG  BuildNumber;
  OUT USHORT  ServicePackMajor;
  OUT USHORT  ServicePackMinor;
} VPOSVERSIONINFO, *PVPOSVERSIONINFO;

Members

Size
Specifies the size, in bytes, of the VPOSVERSIONINFO structure.
MajorVersion
Specifies the major version number of the operating system. For example, for Windows 2000, the major version number is five. For Windows XP, the major version number is six.
MinorVersion
Specifies the minor version number of the operating system. For example, for Windows 2000, the minor version number is zero.
BuildNumber
Specifies the build number of the operating system.
ServicePackMajor
Specifies the major version number of the latest Service Pack installed on the operating system. For example, for Service Pack 3, the major version number is three.
ServicePackMinor
Specifies the minor version number of the latest Service Pack installed on the operating system. For example, for Service Pack 3, the minor version number is zero.

Headers

Declared in video.h. Include video.h.

Comments

This structure is available in Windows XP and later.

To obtain version information about the currently running operating system, a video miniport driver would call the VideoPortGetVersion function, which fills in this structure.

See Also

VideoPortGetVersion


Video I/O Control Codes

This section summarizes the public IOCTL_VIDEO_XXX requests that video miniport drivers handle. These IOCTL requests are defined in ntddvdeo.h.

IOCTL_VIDEO_XXX requests are generally described as either modal or nonmodal. However, there are a few IOCTLs that are both modal and nonmodal. An IOCTL is modal if that operation is valid only with a mode. After a set-mode operation is performed, the state associated with a modal IOCTL is destroyed or reinitialized. A nonmodal IOCTL preserves its state across set-mode operations.

Every video miniport driver must provide support for at least the following requests:

IOCTL_VIDEO_MAP_VIDEO_MEMORY

IOCTL_VIDEO_UNMAP_VIDEO_MEMORY

IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES

IOCTL_VIDEO_QUERY_AVAIL_MODES

IOCTL_VIDEO_QUERY_CURRENT_MODE

IOCTL_VIDEO_SET_CURRENT_MODE

IOCTL_VIDEO_RESET_DEVICE

Depending on the adapter features, a miniport driver can be required to support additional IOCTL_VIDEO_XXX requests, while support for others is optional.

For information, see Display Drivers.


IOCTL_VIDEO_DISABLE_CURSOR

Operation

Makes the cursor invisible by disabling the cursor's visibility attribute. Miniport drivers for VGA-compatible adapters are required to support this modal request; optional for other miniport drivers.

Input

None

Output

None

Status Block

The miniport driver does not set the Information member of the STATUS_BLOCK structure.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.


IOCTL_VIDEO_DISABLE_POINTER

Operation

Makes the pointer invisible by disabling the pointer attributes. Support for this modal request is optional.

Input

None

Output

None

Status Block

The miniport driver does not set the Information member of the STATUS_BLOCK structure.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.


IOCTL_VIDEO_ENABLE_CURSOR

Operation

Makes the cursor visible by enabling the cursor's visibility attribute. Miniport drivers for VGA-compatible adapters are required to support this modal request; optional for other miniport drivers.

Input

None

Output

None

Status Block

The miniport driver does not set the Information member of the STATUS_BLOCK structure.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.


IOCTL_VIDEO_ENABLE_POINTER

Operation

Makes the pointer visible by enabling pointer attributes. Support for this modal request is optional; however, if a miniport driver supports this request, it must process an IOCTL_VIDEO_SET_POINTER_ATTR request before processing this request.

Input

None

Output

None

Status Block

The miniport driver does not set the Information member of the STATUS_BLOCK structure.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

IOCTL_VIDEO_SET_POINTER_ATTR


IOCTL_VIDEO_FREE_PUBLIC_ACCESS_RANGES

Operation

Releases the address range that was allocated by a preceding IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES request. Support for this nonmodal request is optional.

Input

The VRP InputBuffer contains an array of VIDEO_MEMORY structures to be released.

Output

None

Status Block

The miniport driver does not set the Information member of the STATUS_BLOCK structure.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES, VIDEO_MEMORY


IOCTL_VIDEO_GET_BANK_SELECT_CODE

Operation

Returns a block of x86-specific executable code to be used by a high-resolution SVGA display driver for bank-switching. Miniport drivers for VGA-compatible adapters are required to support this modal request; optional for other miniport drivers.

Input

None

Output

The miniport driver returns a VIDEO_BANK_SELECT structure in the VRP OutputBuffer.

Status Block

If the miniport driver returns its code block, it sets the Information member of the STATUS_BLOCK structure to sizeof(VIDEO_BANK_SELECT); otherwise, the miniport driver sets this member to zero.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

STATUS_BLOCK


IOCTL_VIDEO_GET_CHILD_STATE

Operation

Determines whether a child device is currently enabled. Although miniport driver support for this modal request is optional, it is highly recommended. Otherwise, Windows 2000 and later must call the BIOS to perform the operation, which is very inefficient and can adversely affect system robustness. If the BIOS cannot handle this request, then Windows 2000 or later considers the child device to be active.

Input

The VRP InputBuffer contains a pointer to a ULONG, containing the index of the child device, as specified in HwVidGetVideoChildDescriptor.

Output

The video miniport driver returns a ULONG in the VRP OutputBuffer that can be a combination of the following flags:

Value | Meaning
VIDEO_CHILD_ACTIVE | The child device is active.
VIDEO_CHILD_DETACHED | The child device is detached from the view. This flag is used in DualView implementations to indicate the logical relationships of child devices. See Supporting DualView for more information.
VIDEO_CHILD_NOPRUNE_FREQ | The child device can drive an image at any refresh rate, regardless of its EDID setting. This flag is used for mode pruning. By default, Windows 2000 and later perform mode pruning for each active child. When the miniport driver wants to prevent the operating system from performing mode pruning on specific child devices, however, it should use this flag.
VIDEO_CHILD_NOPRUNE_SIZE | The child device can drive an image of any size, regardless of its EDID setting. This flag is used for mode pruning. By default, Windows 2000 and later perform mode pruning for each active child. When the miniport driver wants to prevent the operating system from performing mode pruning on specific child devices, however, it should use this flag.

Status Block

The video miniport driver sets the Information member of the STATUS_BLOCK structure to sizeof(ULONG).

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

HwVidGetVideoChildDescriptor, STATUS_BLOCK


IOCTL_VIDEO_GET_POWER_MANAGEMENT

Operation

Returns the current power-consumption level of the adapter. Support for this nonmodal IOCTL is required for adapters that conform to the VESA DPMS standard.

Input

None

Output

The miniport driver returns a VIDEO_POWER_MANAGEMENT structure in the VRP OutputBuffer.

Status Block

If the miniport driver successfully returns the power-consumption information, it sets the Information member of the STATUS_BLOCK structure to sizeof(VIDEO_POWER_MANAGEMENT); otherwise, the miniport driver sets this member to zero.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

VIDEO_POWER_MANAGEMENT, STATUS_BLOCK


IOCTL_VIDEO_HANDLE_VIDEOPARAMETERS

Operation

Gets the capabilities of the device's television connector and/or copy protection hardware, or sets the desired functionality on the copy protection hardware. Adapters that support TV connectors should provide support for this modal IOCTL. See TV Connector and Copy Protection Support in the Video Miniport for details.

Input

The VRP InputBuffer contains a VIDEOPARAMETERS structure that describes the action to be performed by the miniport.

Output

The miniport driver returns the VIDEOPARAMETERS structure in the VRP OutputBuffer.

Status Block

If the miniport driver successfully gets or sets the requested information, it sets the Information member of the VRP's STATUS_BLOCK to sizeof(VIDEOPARAMETERS); otherwise, the miniport driver sets this member to zero.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

VIDEOPARAMETERS, STATUS_BLOCK


IOCTL_VIDEO_LOAD_AND_SET_FONT

Operation

Loads a user-defined font on the adapter. Miniport drivers for VGA-compatible adapters are required to support this modal request; optional for other miniport drivers.

Input

The VRP InputBuffer contains a VIDEO_LOAD_FONT_INFORMATION structure describing the font's width, height, and size, as well as a pointer to the font buffer.

Output

None

Status Block

The miniport driver does not set the Information member of the STATUS_BLOCK structure.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.


IOCTL_VIDEO_MAP_VIDEO_MEMORY

Operation

Maps the video hardware frame buffer and video RAM into the virtual address space of the requester. Miniport drivers are required to handle this IOCTL and to map all video memory in the caller's address space with VideoPortMapMemory.

This request is both modal and nonmodal: the miniport driver must return the location size of the frame buffer within video memory, and the frame buffer size and location can vary from mode to mode (modal characteristic). However, a subsequent set-mode operation (to the same mode) must not cause the video memory to change location (nonmodal characteristic).

Input

The VRP InputBuffer contains a VIDEO_MEMORY structure specifying either a requested virtual base address or zero, which requests the system to assign a virtual base address mapped to the adapter's RAM and frame buffer range(s).

Output

The miniport driver returns a VIDEO_MEMORY_INFORMATION structure in the VRP OutputBuffer.

Status Block

If the miniport driver successfully maps the memory, it sets the Information member of the STATUS_BLOCK structure to sizeof(VIDEO_MEMORY_INFORMATION); otherwise, it sets this member to zero.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

VideoPortMapMemory, VIDEO_MEMORY, VIDEO_MEMORY_INFORMATION, STATUS_BLOCK


IOCTL_VIDEO_QUERY_AVAIL_FONTS

Operation

None. This request is obsolete.


IOCTL_VIDEO_QUERY_AVAIL_MODES

Operation

Returns information about each video mode supported by the adapter. Miniport drivers are required to support this nonmodal request.

Input

None

Output

The miniport driver returns an array of VIDEO_MODE_INFORMATION structures in the VRP OutputBuffer.

Status Block

If the miniport driver successfully returns the available modes, it sets the Information member of the STATUS_BLOCK structure to (sizeof(VIDEO_MODE_INFORMATION) * NumberOfSupportedModes); otherwise, the miniport driver sets this member to zero.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

VIDEO_MODE_INFORMATION, STATUS_BLOCK


IOCTL_VIDEO_QUERY_COLOR_CAPABILITIES

Operation

Returns the color-capabilities information found in the VDDP description file for the adapter. Support for this nonmodal request is optional. However, if a miniport driver supports this request, it cannot return a subset of the color-capabilities information.

Input

None

Output

The miniport driver returns all VIDEO_COLOR_CAPABILITIES information in the VRP OutputBuffer.

Status Block

If the miniport driver successfully returns the color-capabilities data, it sets the Information member of the STATUS_BLOCK structure to sizeof(VIDEO_COLOR_CAPABILITIES); otherwise, the miniport driver sets this member to zero.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

STATUS_BLOCK


IOCTL_VIDEO_QUERY_CURRENT_FONT

Operation

None. This request is obsolete.


IOCTL_VIDEO_QUERY_CURRENT_MODE

Operation

Returns information about the current adapter mode. Miniport drivers are required to support this modal request.

Input

None

Output

The miniport driver returns the mode information in a VIDEO_MODE_INFORMATION structure in the VRP OutputBuffer.

Status Block

If the miniport driver successfully returns the mode data, it sets the Information member of the STATUS_BLOCK structure to sizeof(VIDEO_MODE_INFORMATION); otherwise, the miniport driver sets this member to zero.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

VIDEO_MODE_INFORMATION , STATUS_BLOCK


IOCTL_VIDEO_QUERY_CURSOR_ATTR

Operation

Returns the size, position, and visibility of the cursor. Miniport drivers for VGA-compatible adapters are required to support this modal request; optional for other miniport drivers. The cursor position is specified by top and bottom scan lines, instead of row and column information, for VGA-compatible adapters.

Input

None

Output

The miniport driver returns a VIDEO_CURSOR_ATTRIBUTES structure in the VRP OutputBuffer.

Status Block

If the miniport driver successfully returns the cursor-attribute data, it sets the Information member of the STATUS_BLOCK structure to sizeof(VIDEO_CURSOR_ATTRIBUTES); otherwise, the miniport driver sets this member to zero.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

STATUS_BLOCK


IOCTL_VIDEO_QUERY_CURSOR_POSITION

Operation

Returns the current cursor position (row and column). Miniport drivers for VGA-compatible adapters are required to support this modal request; optional for other miniport drivers.

Input

None

Output

The miniport driver returns a VIDEO_CURSOR_POSITION structure in the VRP OutputBuffer.

Status Block

If the miniport driver successfully returns the cursor position, it sets the Information member of the STATUS_BLOCK structure to sizeof(VIDEO_CURSOR_POSITION); otherwise, the miniport driver sets this member to zero.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

STATUS_BLOCK


IOCTL_VIDEO_QUERY_NUM_AVAIL_FONTS

Operation

None. This request is obsolete.


IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES

Operation

Returns the number of video modes supported by the adapter and the size in bytes of the video mode information, which can be used to allocate a buffer for an IOCTL_VIDEO_QUERY_AVAIL_MODES request. Miniport drivers are required to support this nonmodal request.

Input

None

Output

The miniport driver returns the number of modes in a VIDEO_NUM_MODES structure in the VRP OutputBuffer.

Status Block

If the miniport driver successfully returns the mode count, it sets the Information member of the STATUS_BLOCK structure to sizeof(VIDEO_NUM_MODES); otherwise, the miniport driver sets this member to zero.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

IOCTL_VIDEO_QUERY_AVAIL_MODES, VIDEO_NUM_MODES, STATUS_BLOCK


IOCTL_VIDEO_QUERY_POINTER_ATTR

Operation

Returns the attributes for the pointer, defined as a set of pixels used to paint the shape associated with the mouse. Support for this modal request is optional.

Input

None

Output

The miniport driver returns a VIDEO_POINTER_ATTRIBUTES structure in the VRP OutputBuffer.

Status Block

If the miniport driver successfully returns the pointer attributes, it sets the Information member of the STATUS_BLOCK structure to sizeof(VIDEO_POINTER_ATTRIBUTES); otherwise, the miniport driver sets this member to zero.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

STATUS_BLOCK


IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES

Operation

Returns information about the adapter's "hardware cursor" features. Support for this modal request is optional.

Input

None

Output

The miniport driver returns a VIDEO_POINTER_CAPABILITIES structure in the VRP OutputBuffer.

Status Block

If the miniport driver successfully returns the pointer capabilities, it sets the Information member of the STATUS_BLOCK structure to sizeof(VIDEO_POINTER_CAPABILITIES); otherwise, the miniport driver sets this member to zero.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

STATUS_BLOCK


IOCTL_VIDEO_QUERY_POINTER_POSITION

Operation

Returns the current position of the pointer. Support for this modal request is optional.

Input

None

Output

The miniport driver returns a VIDEO_POINTER_POSITION structure in the VRP OutputBuffer.

Status Block

If the miniport driver successfully returns the pointer position, it sets the Information member of the STATUS_BLOCK structure to sizeof(VIDEO_POINTER_POSITION); otherwise, the miniport driver sets this member to zero.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

STATUS_BLOCK


IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES

Operation

Returns an array, possibly with one element, of address ranges used to program the adapter registers or ports directly. Support for this nonmodal request is optional.

Input

None

Output

The miniport driver returns an array of VIDEO_PUBLIC_ACCESS_RANGES in the VRP OutputBuffer.

Status Block

If the miniport driver returns an address range or ranges, it sets the Information member of the STATUS_BLOCK structure to sizeof(VIDEO_PUBLIC_ACCESS_RANGES); otherwise, the miniport driver sets this member to zero.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

VIDEO_PUBLIC_ACCESS_RANGES, STATUS_BLOCK


IOCTL_VIDEO_RESET_DEVICE

Operation

Resets the video hardware to the default mode, to which it was initialized at system boot. Miniport drivers are required to support this nonmodal request.

Input

None

Output

None

Status Block

The miniport driver does not set the Information member of the STATUS_BLOCK structure.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.


IOCTL_VIDEO_RESTORE_HARDWARE_STATE

Operation

Restores all values used to set the hardware registers. Miniport drivers for VGA-compatible adapters are required to support this nonmodal request; optional for other miniport drivers.

Input

The VRP InputBuffer contains the previously-saved VIDEO_HARDWARE_STATE structure.

Output

None

Status Block

The miniport driver does not set the Information member of the STATUS_BLOCK structure.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.


IOCTL_VIDEO_SAVE_HARDWARE_STATE

Operation

Saves the state of the video adapter in the VRP OutputBuffer. Miniport drivers for VGA-compatible adapters are required to support this nonmodal request; optional for other miniport drivers.

Input

None

Output

The miniport driver returns a VIDEO_HARDWARE_STATE structure in the VRP OutputBuffer.

Status Block

If the miniport driver successfully saves the adapter state, it sets the Information member of the STATUS_BLOCK structure to sizeof(VIDEO_HARDWARE_STATE); otherwise, the miniport driver sets this member to zero.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

STATUS_BLOCK


IOCTL_VIDEO_SET_CHILD_STATE_CONFIGURATION

Operation

Performs a display device switch, a state change in which the video signal going to one display device is sent to another, possibly different type of display device. After the display device switch, the video signal can be sent to one or both display devices. When the video port driver receives a notification to switch display devices, it sends this IOCTL to the miniport driver. Normally, this IOCTL is sent after IOCTL_VIDEO_VALIDATE_CHILD_STATE_CONFIGURATION indicates that the miniport driver is ready to make the switch. If the miniport driver is capable of switching display devices, it should do so and set the Status member of StatusBlock to NO_ERROR.

If the miniport driver is not capable of performing the display device switch, it can set the Status member of StatusBlock to an appropriate error value (described in the Status Block section), choosing not to handle the request. Although this request is optional, it is highly recommended that the miniport driver handle this request. Failure to do so forces a call to the BIOS to handle the display device switch, which can be very inefficient, and can have an adverse effect on the system's robustness.

IOCTL_VIDEO_SET_CHILD_STATE_CONFIGURATION is synchronous. After this IOCTL is sent, IOCTL_VIDEO_GET_CHILD_STATE should reflect the new state.

This request is modal.

Input

The VRP InputBuffer contains a VIDEO_CHILD_STATE_CONFIGURATION structure.

Output

None

Status Block

The miniport driver sets the Status member to NO_ERROR if it is capable of performing the display device switch. If it is not able to carry out this operation, the miniport driver can set Status to an appropriate error value, or do nothing at all.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

IOCTL_VIDEO_VALIDATE_CHILD_STATE_CONFIGURATION, IOCTL_VIDEO_GET_CHILD_STATE, VIDEO_CHILD_STATE_CONFIGURATION


IOCTL_VIDEO_SET_COLOR_REGISTERS

Operation

Sets the adapter's color registers to the specified RGB values. If the adapter has a color look up table (CLUT), sometimes called a palette, the miniport driver is required to support this modal request.

Input

The VRP InputBuffer contains a VIDEO_CLUT structure, specifying an array of RGB values to be set.

Output

None

Status Block

The miniport driver does not set the Information member of the STATUS_BLOCK structure.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.


IOCTL_VIDEO_SET_CURRENT_FONT

Operation

None. This request is obsolete.


IOCTL_VIDEO_SET_CURRENT_MODE

Operation

Sets the adapter to the specified operating mode. Miniport drivers are required to support this nonmodal request because it resets the current mode. The miniport driver must also consider the two high order flags which are used to additionally control the mode set operation. See VIDEO_MODE for further information.

Input

The VRP InputBuffer contains a VIDEO_MODE structure specifying the mode to be set.

Output

None

Status Block

The miniport driver does not set the Information member of the STATUS_BLOCK structure.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

VIDEO_MODE


IOCTL_VIDEO_SET_CURSOR_ATTR

Operation

Sets the cursor size, position, and visibility. Miniport drivers for VGA-compatible adapters are required to support this request, which is modal. Support is optional for other miniport drivers.

Input

The VRP InputBuffer contains the VIDEO_CURSOR_ATTRIBUTES structure to be set.

Output

None

Status Block

The miniport driver does not set the Information member of the STATUS_BLOCK structure.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.


IOCTL_VIDEO_SET_CURSOR_POSITION

Operation

Sets the cursor position (row and column). Miniport drivers for VGA-compatible adapters are required to support this request, which is modal. It is optional for other miniport drivers.

Input

The VRP InputBuffer contains the VIDEO_CURSOR_POSITION structure to be set.

Output

None

Status Block

The miniport driver does not set the Information member of the STATUS_BLOCK structure.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.


IOCTL_VIDEO_SET_PALETTE_REGISTERS

Operation

Loads a specified portion of the adapter palette registers with an array of colors. Miniport drivers for VGA-compatible adapters are required to support this request, which is modal. Support is optional for other miniport drivers.

Input

The VRP InputBuffer contains the VIDEO_PALETTE_DATA structure, specifying an array of colors to be set in the palette registers.

Output

None

Status Block

The miniport driver does not set the Information member of the STATUS_BLOCK structure.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.


IOCTL_VIDEO_SET_POINTER_ATTR

Operation

Sets the pointer attributes. Support for this modal request is optional. A supporting miniport driver can fail this request (for example, if the attributes specify a larger pointer than the miniport driver can supply). When a miniport driver fails this request, the corresponding display driver must manage the pointer.

Input

The VRP InputBuffer contains the VIDEO_POINTER_ATTRIBUTES structure to be set.

Output

None

Status Block

The miniport driver does not set the Information member of the STATUS_BLOCK structure.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.


IOCTL_VIDEO_SET_POINTER_POSITION

Operation

Sets the pointer position. Support for this modal request is optional. A supporting miniport driver should have already processed an enable-pointer request before processing this request.

Input

The VRP InputBuffer contains the VIDEO_POINTER_POSITION structure to be set.

Output

None

Status Block

The miniport driver does not set the Information member of the STATUS_BLOCK structure.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.


IOCTL_VIDEO_SET_POWER_MANAGEMENT

Operation

Resets the power-consumption level of the adapter to the specified state. As long as the state is VideoPowerOff, the port driver intercepts and fails all IOCTL_VIDEO_XXX requests to the miniport driver until the next IOCTL_VIDEO_SET_POWER_MANAGEMENT request that resets the state to a power-on condition.

Input

The VRP InputBuffer contains the VIDEO_POWER_MANAGEMENT structure, specifying the state to be set.

Output

None

Status Block

The miniport driver does not set the Information member of the STATUS_BLOCK structure.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

VIDEO_POWER_MANAGEMENT


IOCTL_VIDEO_SHARE_VIDEO_MEMORY

Operation

This IOCTL is called by a process that will share user-mode video memory as a linear frame buffer. Miniport drivers handle this IOCTL by mapping the frame buffer into the caller's address space with VideoPortMapBankedMemory. Otherwise this IOCTL is the same as IOCTL_VIDEO_MAP_VIDEO_MEMORY.

This request is both modal and nonmodal: the miniport driver must return the location size of the frame buffer within video memory, and the frame buffer size and location can vary from mode to mode (modal characteristic), but a subsequent set-mode operation (to the same mode) must not cause the video memory to change location (nonmodal characteristic).

This IOCTL is DCI only.

Input

The VRP InputBuffer contains a VIDEO_SHARE_MEMORY structure specifying a handle to the process mapping the frame buffer, and the requested view size and offset into the shared memory. The view size plus the offset must not exceed the memory size of the adapter.

Output

The miniport driver returns the VIDEO_SHARE_MEMORY_INFORMATION structure in the VRP OutputBuffer. This output contains the virtual address where the video memory is mapped, the view size in bytes of the mapped memory and the offset into the view.

Status Block

If the miniport driver successfully maps the memory, it sets the Information member of the STATUS_BLOCK structure to sizeof(VIDEO_SHARE_MEMORY_INFORMATION); otherwise, the miniport driver sets this member to zero.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

VideoPortMapBankedMemory, IOCTL_VIDEO_MAP_VIDEO_MEMORY, VIDEO_SHARE_MEMORY, VIDEO_SHARE_MEMORY_INFORMATION, STATUS_BLOCK


IOCTL_VIDEO_SWITCH_DUALVIEW

Operation

Notifies the video miniport that a secondary view is about to be enabled or disabled. A secondary view is enabled by a call to the video port driver's VideoPortCreateSecondaryDisplay.

Windows 2000 and later send this request to the video miniport driver to notify it of a secondary view change of status. Video miniport drivers can use this notification to make video memory arrangements in advance. For example, when the display driver sets the mode of the primary view, it can reserve video memory for one or more secondary views.

Note This request, which is available in Windows XP and later, can only be used to manage video memory.

Input

The VRP InputBuffer contains a pointer to a ULONG, which can be one of the two following values:

Value | Meaning
0 | The device is about to be detached.
1 | The device is about to be attached.

Output

None

Status Block

The miniport driver does not set the Information member of the STATUS_BLOCK structure.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

VideoPortCreateSecondaryDisplay


IOCTL_VIDEO_UNMAP_VIDEO_MEMORY

Operation

Releases a mapping between the virtual address space and the adapter's frame buffer and video RAM. Miniport drivers are required to support this nonmodal request.

Input

The VRP InputBuffer contains a VIDEO_MEMORY structure, specifying the previously mapped virtual base address to be released with VideoPortUnmapMemory.

Output

None

Status Block

The miniport driver does not set the Information member of the STATUS_BLOCK structure.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

VIDEO_MEMORY, VideoPortUnmapMemory


IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY

Operation

Unmaps a video hardware frame buffer and video RAM from the virtual address space of the requester that was mapped by an IOCTL_VIDEO_SHARE_VIDEO_MEMORY request.

Input

The VRP InputBuffer contains a VIDEO_SHARE_MEMORY structure specifying the process and the virtual address where the video memory is mapped. The memory is unmapped by calling VideoPortUnmapMemory.

Output

None

Status Block

The miniport driver does not set the Information member of the STATUS_BLOCK structure.

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

IOCTL_VIDEO_SHARE_VIDEO_MEMORY, VIDEO_SHARE_MEMORY, VideoPortUnmapMemory


IOCTL_VIDEO_VALIDATE_CHILD_STATE_CONFIGURATION

Operation

Queries the miniport driver to determine whether it is ready for a display device switch. This switch is a state change in which the video signal going to one display device is sent to another, possibly different type of display device. After the display device switch, the video signal can be sent to one or both display devices. When the video port driver receives a request to switch display devices (by, for example, a hotkey being pressed), it sends this IOCTL to the video miniport driver. The value returned by the miniport driver indicates whether the video port driver should proceed with the display device switch.

When the miniport driver receives this request, it should indicate that it has successfully handled the request by:

  • Placing the appropriate value (described in the Output section) in OutputBuffer
  • Returning NO_ERROR in the Status member of the VRP's StatusBlock

The video miniport driver carries out a validated display device switch when it receives an IOCTL_VIDEO_SET_CHILD_STATE_CONFIGURATION request.

The miniport driver is not required to handle this modal IOCTL. The video port driver interprets a default return value from the miniport driver as permission to proceed with the display device switch.

Input

The VRP InputBuffer contains a VIDEO_CHILD_STATE_CONFIGURATION structure.

Output

The miniport driver returns 1 in the VRP OutputBuffer if the video port driver should proceed with the display device switch; otherwise, the driver returns 0 in the VRP OutputBuffer.

Status Block

The miniport driver stores NO_ERROR in Status if it has successfully handled this IOCTL; otherwise, the driver stores a relevant video error code in Status. In either case, the miniport driver sets the Information member of the STATUS_BLOCK structure to sizeof(ULONG).

Headers

Defined in ntddvdeo.h. Include ntddvdeo.h.

See Also

IOCTL_VIDEO_SET_CHILD_STATE_CONFIGURATION, VIDEO_CHILD_STATE_CONFIGURATION, STATUS_BLOCK


Spooler Component Functions and Structures

This section describes the functions and structures defined by Windows® 2000 and later print spooler components. The following topics are provided:

Print Provider Functions

Print Provider Structures

Print Processor Functions

Print Processor Structures

Print Monitor Functions

Print Monitor Structures

TCPMON Xcv Structures

Exported Spooler Functions

Bidi Functions, Structures, and Enumerations


Print Provider Functions

This section describes functions supplied by print providers. Most provider functions are described in the Platform SDK documentation, so this section only describes functions not included in SDK documentation. Print providers must supply pointers to all defined functions by using a PRINTPROVIDOR structure.


FindFirstPrinterChangeNotification

A print provider's FindFirstPrinterChangeNotification function informs the provider that an application has requested notification when a specified set of events occur on a specified print queue.

BOOL
  FindFirstPrinterChangeNotification(
    HANDLE  hPrinter,
    DWORD  fdwFlags,
    DWORD  fdwOptions,
    HANDLE  hNotify,
    PDWORD  pfdwStatus,
    PVOID  pPrinterNotifyOptions,
    PVOID  pPrinterNotifyInit
    );

Parameters

hPrinter
Caller-supplied printer handle, identifying the printer for which event notification is being requested. This handle must have been previously obtained from OpenPrinter (described in the Platform SDK documentation).
fdwFlags
One or more caller-supplied PRINTER_CHANGE-prefixed flags. For more information, see the description of FindFirstPrinterChangeNotification in the Platform SDK documentation.
fdwOptions
Not used.
hNotify
Caller-supplied notification handle. This handle must be saved and used as input to ReplyPrinterChangeNotification and PartialReplyPrinterChangeNotification.
pfdwStatus
Caller-supplied pointer to a location to receive provider-specified flags. The following flags are defined.
Flag Definition
PRINTER_NOTIFY_STATUS_ENDPOINT
If set, the print provider supplies print change notifications, by either the polling or the change notification method. (The notification method is identified by the PRINTER_NOTIFY_STATUS_POLL flag.)
PRINTER_NOTIFY_STATUS_POLL
If set, the print application must poll to detect printer changes.

If clear, the print provider notifies the spooler of changes by calling RefreshPrinterChangeNotification.

(See the following Comments section.)
PRINTER_NOTIFY_STATUS_INFO
Not used.

pPrinterNotifyOptions
Caller-supplied pointer to a PRINTER_NOTIFY_OPTIONS structure (described in the Platform SDK documentation).
pPrinterNotifyInit
Not used.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise the function should return FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

When the spooler calls a print provider's FindFirstPrinterChangeNotification function, fdwFlags identifies the printer events for which notification is being requested. Additionally, pPrinterNotifyOptions identifies the types of information that the print provider should send to the spooler when one of the specified events occurs.

For a list of the types of notifications an application can request, and for a list of the types of information that can be used to describe an event, see the Platform SDK documentation's description of FindFirstPrinterChangeNotification. Types of events for which an application might request notification include adding or deleting a print job or form. Types of information an application might request include job or form parameters.

If the print provider does not request polling (that is, it does not set PRINTER_NOTIFY_STATUS_POLL in pfdwStatus), it must notify the spooler when events identified by pfwFlags occur. The print provider must supply the types of information identified by pPrinterNotifyOptions, by calling PartialReplyPrinterChangeNotification or ReplyPrinterChangeNotification.

If the provider does request polling (that is, it sets PRINTER_NOTIFY_STATUS_POLL), it should not call ReplyPrinterChangeNotification. Instead, the spooler signals the application at regular intervals.

Both polled and non-polled print provider must return the current state of all requested information types whenever its RefreshPrinterChangeNotification function is called.

For additional information, see Supporting Printer Change Notifications.

See Also

PartialReplyPrinterChangeNotification, ReplyPrinterChangeNotification, RefreshPrinterChangeNotification


InitializePrintProvidor

A print provider's InitializePrintProvidor function initializes the provider and supplies the print spooler with the provider's entry points.

BOOL
  InitializePrintProvidor(
    LPPRINTPROVIDOR  pPrintProvidor,
    DWORD  cbPrintProvidor,
    LPWSTR  pFullRegistryPath
    );

Parameters

pPrintProvidor
Caller-supplied address of a PRINTPROVIDOR structure, to be filled in by the print provider.
cbPrintProvidor
Caller-supplied size, in bytes, of the PRINTPROVIDOR structure pointed to by pPrintProvidor.
pFullRegistryPath
Caller-supplied pointer to a string representing the full registry path to the provider's registry entry.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise the function should return FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Print providers are required to define an InitializePrintProvidor function, which is the first function called by the spooler after the provider has been loaded. The function must fill the supplied PRINTPROVIDOR structure with pointers to the provider's defined functions (see Functions Defined by Print Providers). The function can also perform other provider-specific initialization operations.

See Also

PRINTPROVIDOR


RefreshPrinterChangeNotification

A print provider's RefreshPrinterChangeNotification function returns change notification information to the caller.

BOOL
  RefreshPrinterChangeNotification(
    HANDLE  hPrinter,
    DWORD  Reserved,
    PVOID  pvReserved,
    PVOID  pPrinterNotifyInfo
    );

Parameters

hPrinter
Caller-supplied printer handle, identifying the printer for which event notification information is being requested. This handle must have been previously obtained from OpenPrinter (described in the Platform SDK documentation).
Reserved
Not used.
pvReserved
Not used.
pPrinterNotifyInfo
Caller-supplied address to receive a pointer to a provider-allocated PRINTER_NOTIFY_INFO structure (described in the Platform SDK documentation).

Return Value

If the operation succeeds, the function returns TRUE. Otherwise the function returns FALSE. The caller can obtain an error code by calling GetLastError (described in the Platform SDK documentation).

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

A print provider's RefreshPrinterChangeNotification function is called when an application calls FindNextPrinterChangeNotification (described in the Platform SDK documentation) with the PRINTER_NOTIFY_OPTIONS_REFRESH flag set. Applications are supposed to set this flag if a previous call to FindNextPrinterChangeNotification returns a PRINTER_NOTIFY_INFO structure with the PRINTER_NOTIFY_INFO_DISCARDED flag set. This flag means the spooler's copy of printer change information is no longer valid, so the print provider must return a new copy. (The print provider can mark the spooler's copy of printer change information as invalid by calling PartialReplyPrinterChangeNotification with a NULL pInfoDataSrc argument.)

The provider must call RouterAllocPrinterNotifyInfo to allocate a PRINTER_NOTIFY_INFO structure (described in the Platform SDK documentation). The provider must then call AppendPrinterNotifyInfoData to load the structure with requested information, as indicated by the contents of the PRINTER_NOTIFY_OPTIONS structure (described in the Platform SDK documentation) that was previously received by the print provider's FindFirstPrinterChangeNotification function. (The calling application is responsible for de-allocating the PRINTER_NOTIFY_INFO structure.)

For additional information, see Supporting Printer Change Notifications.

See Also

PartialReplyPrinterChangeNotification, RouterAllocPrinterNotifyInfo, AppendPrinterNotifyInfoData, FindFirstPrinterChangeNotification


XcvData

The print spooler's XcvData function is the means by which a port monitor UI DLL communicates with its associated port monitor server DLL. Win32® applications can also call XcvData.

BOOL WINAPI
  XcvData(
    HANDLE  hXcv,
    LPCWSTR  pszDataName,
    PBYTE  pInputData,
    DWORD  cbInputData,
    PBYTE  pOutputData,
    DWORD  cbOutputData,
    PDWORD  pcbOutputNeeded,
    PDWORD  pdwStatus
    );

Parameters

hXcv
Caller-supplied printer handle, obtained by calling the Platform SDK OpenPrinter function (described in the Platform SDK documentation).
pszDataName
Caller-supplied pointer to a string representing the name of the data being requested. For more information, see XcvDataPort.
pInputData
Caller-supplied pointer to a buffer containing input data.
cbInputData
Caller-supplied size, in bytes, of the buffer pointed to by pInputData.
pOutputData
Caller-supplied pointer to a buffer to receive output data.
cbOutputData
Caller-supplied size, in bytes, of the buffer pointed to by pOutputData.
pcbOutputNeeded
Caller-supplied pointer to a location to receive the minimum size, in bytes, required for the buffer pointed to by pOutputData.
pdwStatus
Caller-supplied pointer to a location to receive the status value returned by XcvDataPort. The returned value should be an ERROR_-prefixed Win32 error code.

Return Value

If the operation succeeds, the function returns TRUE. Otherwise the function returns FALSE. The caller can obtain an error code by calling GetLastError.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

The print spooler's XcvData function is called by port monitor UI DLLs so they can communicate with their associated port monitor server DLLs.

The XcvData function calls the port monitor server DLL's XcvDataPort function and returns its result in the location pointed to by the pdwStatus parameter.

The string pointed to by pszDataName must be one that the server DLL's XcvDataPort function recognizes. Contents, if any, of the input and output buffers are dependent on the data name string.

With the exception of pdwStatus, the function parameters for XcvData and XcvDataPort are identical. For more information about XcvData and XcvDataPort parameters, see XcvDataPort.

Win32 applications can also call XcvData, to add or delete printer ports without invoking the user interface that the Win32 AddPort function displays. Applications can specify the following standard values for pszDataName:

Data Name String | Operation
L"AddPort" | Notifies the port monitor server DLL that all information about the port has been sent, so the server can add the port. The pInputData parameter must point to a NULL-terminated port name string. The pOutputData, cbOutputData, and pcbOutputNeeded parameters are not used.
L"DeletePort" | Notifies the port monitor server DLL that the port can be deleted. The pInputData parameter must point to a NULL-terminated port name string. The pOutputData, cbOutputData, and pcbOutputNeeded parameters are not used.

Note that additional, monitor-specific data name strings might be defined. To communicate with a vendor-supplied port monitor, it might be necessary to send additional, customized data name strings before sending "AddPort" or "DeletePort".

The XcvData function can used to communicate with the standard TCP/IP port monitor. See TCPMON Xcv Interface for details.

See Also

XcvDataPort


Print Provider Structures

This section describes the structure used by print providers.


PRINTPROVIDOR

The PRINTPROVIDOR structure is used as a parameter to a print provider's InitializePrintProvidor function. All structure member values are supplied by the provider.

typedef struct _PRINTPROVIDOR {
  BOOL (*fpOpenPrinter)(LPWSTR  pPrinterName,
                        LPHANDLE  phPrinter,
                        LPPRINTER_DEFAULTS  pDefault);
  BOOL (*fpSetJob)(HANDLE  hPrinter,
                   DWORD  JobId,
                   DWORD  Level,
                   LPBYTE  pJob,
                   DWORD  Command);
  BOOL (*fpGetJob)(HANDLE  hPrinter,
                   DWORD  JobId,
                   DWORD  Level,
                   LPBYTE  pJob,
                   DWORD  cbBuf,
                   LPDWORD  pcbNeeded);
  BOOL (*fpEnumJobs)(HANDLE  hPrinter,
                     DWORD  FirstJob,
                     DWORD  NoJobs,
                     DWORD  Level,
                     LPBYTE  pJob,
                     DWORD  cbBuf,
                     LPDWORD  pcbNeeded,
                     LPDWORD  pcReturned);
  HANDLE (*fpAddPrinter)(LPWSTR  pName,
                         DWORD  Level,
                         LPBYTE  pPrinter);
  BOOL (*fpDeletePrinter)(HANDLE  hPrinter);
  BOOL (*fpSetPrinter)(HANDLE  hPrinter,
                       DWORD  Level,
                       LPBYTE  pPrinter,
                       DWORD  Command);
  BOOL (*fpGetPrinter)(HANDLE  hPrinter,
                       DWORD  Level,
                       LPBYTE  pPrinter,
                       DWORD  cbBuf,
                       LPDWORD  pcbNeeded);
  BOOL (*fpEnumPrinters)(DWORD  Flags,
                         LPWSTR  Name,
                         DWORD  Level,
                         LPBYTE  pPrinterEnum,
                         DWORD  cbBuf,
                         LPDWORD  pcbNeeded,
                         LPDWORD  pcReturned);
  BOOL (*fpAddPrinterDriver)(LPWSTR  pName,
                             DWORD  Level,
                             LPBYTE  pDriverInfo);
  BOOL (*fpEnumPrinterDrivers)(LPWSTR  pName,
                               LPWSTR  pEnvironment,
                               DWORD  Level,
                               LPBYTE  pDriverInfo,
                               DWORD  cbBuf,
                               LPDWORD  pcbNeeded,
                               LPDWORD  pcReturned);
  BOOL (*fpGetPrinterDriver)(HANDLE  hPrinter,
                             LPWSTR  pEnvironment,
                             DWORD  Level,
                             LPBYTE  pDriverInfo,
                             DWORD  cbBuf,
                             LPDWORD  pcbNeeded);
  BOOL (*fpGetPrinterDriverDirectory)(LPWSTR  pName,
                                      LPWSTR  pEnvironment,
                                      DWORD  Level,
                                      LPBYTE  pDriverDirectory,
                                      DWORD  cbBuf,
                                      LPDWORD  pcbNeeded);
  BOOL (*fpDeletePrinterDriver)(LPWSTR  pName,
                                LPWSTR  pEnvironment,
                                LPWSTR  pDriverName);
  BOOL (*fpAddPrintProcessor)(LPWSTR  pName,
                              LPWSTR  pEnvironment,
                              LPWSTR  pPathName,
                              LPWSTR  pPrintProcessorName);
  BOOL (*fpEnumPrintProcessors)(LPWSTR  pName,
                                LPWSTR  pEnvironment,
                                DWORD  Level,
                                LPBYTE  pPrintProcessorInfo,
                                DWORD  cbBuf,
                                LPDWORD  pcbNeeded,
                                LPDWORD  pcReturned);
  BOOL (*fpGetPrintProcessorDirectory)(LPWSTR  pName,
                                       LPWSTR  pEnvironment,
                                       DWORD  Level,
                                       LPBYTE  pPrintProcessorInfo,
                                       DWORD  cbBuf,
                                       LPDWORD  pcbNeeded);
  BOOL (*fpDeletePrintProcessor)(LPWSTR  pName,
                                 LPWSTR  pEnvironment,
                                 LPWSTR  pPrintProcessorName);
  BOOL (*fpEnumPrintProcessorDatatypes)(LPWSTR  pName,
                                        LPWSTR  pPrintProcessorName,
                                        DWORD  Level,
                                        LPBYTE  pDataypes,
                                        DWORD  cbBuf,
                                        LPDWORD  pcbNeeded,
                                        LPDWORD  pcReturned);
  DWORD (*fpStartDocPrinter)(HANDLE  hPrinter,
                             DWORD  Level,
                             LPBYTE  pDocInfo);
  BOOL (*fpStartPagePrinter)(HANDLE  hPrinter);
  BOOL (*fpWritePrinter)(HANDLE  hPrinter,
                         LPVOID  pBuf,
                         DWORD  cbBuf,
                         LPDWORD  pcWritten);
  BOOL (*fpEndPagePrinter)(HANDLE  hPrinter);
  BOOL (*fpAbortPrinter)(HANDLE  hPrinter);
  BOOL (*fpReadPrinter)(HANDLE  hPrinter,
                        LPVOID  pBuf,
                        DWORD  cbBuf,
                        LPDWORD  pNoBytesRead);
  BOOL (*fpEndDocPrinter)(HANDLE  hPrinter);
  BOOL (*fpAddJob)(HANDLE  hPrinter,
                   DWORD  Level,
                   LPBYTE  pData,
                   DWORD  cbBuf,
                   LPDWORD  pcbNeeded);
  BOOL (*fpScheduleJob)(HANDLE  hPrinter,
                        DWORD  JobId);
  DWORD (*fpGetPrinterData)(HANDLE  hPrinter,
                            LPWSTR  pValueName,
                            LPDWORD  pType,
                            LPBYTE  pData,
                            DWORD  nSize,
                            LPDWORD  pcbNeeded);
  DWORD (*fpSetPrinterData)(HANDLE  hPrinter,
                            LPWSTR  pValueName,
                            DWORD  Type,
                            LPBYTE  pData,
                            DWORD  cbData);
  DWORD (*fpWaitForPrinterChange)(HANDLE  hPrinter,
                                  DWORD  Flags);
  BOOL (*fpClosePrinter)(HANDLE  hPrinter);
  BOOL (*fpAddForm)(HANDLE  hPrinter,
                    DWORD  Level,
                    LPBYTE  pForm);
  BOOL (*fpDeleteForm)(HANDLE  hPrinter,
                       LPWSTR  pFormName);
  BOOL (*fpGetForm)(HANDLE  hPrinter,
                    LPWSTR  pFormName,
                    DWORD  Level,
                    LPBYTE  pForm,
                    DWORD  cbBuf,
                    LPDWORD  pcbNeeded);
  BOOL (*fpSetForm)(HANDLE  hPrinter,
                    LPWSTR  pFormName,
                    DWORD  Level,
                    LPBYTE  pForm);
  BOOL (*fpEnumForms)(HANDLE  hPrinter,
                      DWORD  Level,
                      LPBYTE  pForm,
                      DWORD  cbBuf,
                      LPDWORD  pcbNeeded,
                      LPDWORD  pcReturned);
  BOOL (*fpEnumMonitors)(LPWSTR  pName,
                         DWORD  Level,
                         LPBYTE  pMonitors,
                         DWORD  cbBuf,
                         LPDWORD  pcbNeeded,
                         LPDWORD  pcReturned);
  BOOL (*fpEnumPorts)(LPWSTR  pName,
                      DWORD  Level,
                      LPBYTE  pPorts,
                      DWORD  cbBuf,
                      LPDWORD  pcbNeeded,
                      LPDWORD  pcReturned);
  BOOL (*fpAddPort)(LPWSTR  pName,
                    HWND  hWnd,
                    LPWSTR  pMonitorName);
  BOOL (*fpConfigurePort)(LPWSTR  pName,
                          HWND  hWnd,
                          LPWSTR  pPortName);
  BOOL (*fpDeletePort)(LPWSTR  pName,
                       HWND  hWnd,
                       LPWSTR  pPortName);
  HANDLE (*fpCreatePrinterIC)(HANDLE  hPrinter,
                              LPDEVMODEW  pDevMode);
  BOOL (*fpPlayGdiScriptOnPrinterIC)(HANDLE  hPrinterIC,
                                     LPBYTE  pIn,
                                     DWORD  cIn,
                                     LPBYTE  pOut,
                                     DWORD  cOut,
                                     DWORD  ul);
  BOOL (*fpDeletePrinterIC)(HANDLE  hPrinterIC);
  BOOL (*fpAddPrinterConnection)(LPWSTR  pName);
  BOOL (*fpDeletePrinterConnection)(LPWSTR  pName);
  DWORD (*fpPrinterMessageBox)(HANDLE  hPrinter,
                               DWORD  Error,
                               HWND  hWnd,
                               LPWSTR  pText,
                               LPWSTR  pCaption,
                               DWORD  dwType);
  BOOL (*fpAddMonitor)(LPWSTR  pName,
                       DWORD  Level,
                       LPBYTE  pMonitorInfo);
  BOOL (*fpDeleteMonitor)(LPWSTR  pName,
                          LPWSTR  pEnvironment,
                          LPWSTR  pMonitorName);
  BOOL (*fpResetPrinter)(HANDLE  hPrinter,
                         LPPRINTER_DEFAULTS  pDefault);
  BOOL (*fpGetPrinterDriverEx)(HANDLE  hPrinter,
                               LPWSTR  pEnvironment,
                               DWORD  Level,
                               LPBYTE  pDriverInfo,
                               DWORD  cbBuf,
                               LPDWORD  pcbNeeded,
                               DWORD  dwClientMajorVersion,
                               DWORD  dwClientMinorVersion,
                               PDWORD  pdwServerMajorVersion,
                               PDWORD  pdwServerMinorVersion);
  BOOL (*fpFindFirstPrinterChangeNotification)(
            HANDLE  hPrinter,
            DWORD  fdwFlags,
            DWORD  fdwOptions,
            HANDLE  hNotify,
            PDWORD  pfdwStatus,
            PVOID  pPrinterNotifyOptions,
            PVOID  pPrinterNotifyInit);
  BOOL (*fpFindClosePrinterChangeNotification)(HANDLE  hPrinter);
  BOOL (*fpAddPortEx)(LPWSTR  pName,
                      DWORD  Level,
                      LPBYTE  lpBuffer,
                      LPWSTR  lpMonitorName);
  BOOL (*fpShutDown)(LPVOID  pvReserved);
  BOOL (*fpRefreshPrinterChangeNotification)(
                      HANDLE  hPrinter,
                      DWORD  Reserved,
                      PVOID  pvReserved,
                      PVOID  pPrinterNotifyInfo);
  BOOL (*fpOpenPrinterEx)(LPWSTR  pPrinterName,
                          LPHANDLE  phPrinter,
                          LPPRINTER_DEFAULTS  pDefault,
                          LPBYTE  pClientInfo,
                          DWORD  Level);
  HANDLE (*fpAddPrinterEx)(LPWSTR  pName,
                           DWORD  Level,
                           LPBYTE  pPrinter,
                           LPBYTE  pClientInfo,
                           DWORD  ClientInfoLevel);
  BOOL (*fpSetPort)(LPWSTR  pName,
                    LPWSTR  pPortName,
                    DWORD  Level,
                    LPBYTE  pPortInfo);
  DWORD (*fpEnumPrinterData)(HANDLE  hPrinter,
                             DWORD  dwIndex,
                             LPWSTR  pValueName,
                             DWORD  cbValueName,
                             LPDWORD  pcbValueName,
                             LPDWORD  pType,
                             LPBYTE  pData,
                             DWORD  cbData,
                             LPDWORD  pcbData);
  DWORD (*fpDeletePrinterData)(HANDLE  hPrinter,
                               LPWSTR  pValueName);
  DWORD (*fpClusterSplOpen)(LPCTSTR  pszServer,
                            LPCTSTR  pszResource,
                            PHANDLE  phSpooler,
                            LPCTSTR  pszName,
                            LPCTSTR  pszAddress );
  DWORD (*fpClusterSplClose)(HANDLE  hSpooler);
  DWORD (*fpClusterSplIsAlive)(HANDLE  hSpooler);
  DWORD (*fpSetPrinterDataEx)(HANDLE  hPrinter,
                              LPCWSTR  pKeyName,
                              LPCWSTR  pValueName,
                              DWORD  Type,
                              LPBYTE  pData,
                              DWORD  cbData);
  DWORD (*fpGetPrinterDataEx)(HANDLE  hPrinter,
                              LPCWSTR  pKeyName,
                              LPCWSTR  pValueName,
                              LPDWORD  pType,
                              LPBYTE  pData,
                              DWORD  nSize,
                              LPDWORD  pcbNeeded);
  DWORD (*fpEnumPrinterDataEx)(HANDLE  hPrinter,
                               LPCWSTR  pKeyName,
                               LPBYTE  pEnumValues,
                               DWORD  cbEnumValues,
                               LPDWORD  pcbEnumValues,
                               LPDWORD  pnEnumValues);
  DWORD (*fpEnumPrinterKey)(HANDLE  hPrinter,
                            LPCWSTR  pKeyName,
                            LPWSTR  pSubkey,
                            DWORD  cbSubkey,
                            LPDWORD  pcbSubkey);
  DWORD (*fpDeletePrinterDataEx)(HANDLE  hPrinter,
                                 LPCWSTR  pKeyName,
                                 LPCWSTR  pValueName);
  DWORD (*fpDeletePrinterKey)(HANDLE  hPrinter,
                              LPCWSTR  pKeyName);
  BOOL (*fpSeekPrinter)(HANDLE  hPrinter,
                        LARGE_INTEGER  liDistanceToMove,
                        PLARGE_INTEGER  pliNewPointer,
                        DWORD  dwMoveMethod,
                        BOOL  bWrite);
  BOOL (*fpDeletePrinterDriverEx)(LPWSTR  pName,
                                  LPWSTR  pEnvironment,
                                  LPWSTR  pDriverName,
                                  DWORD  dwDeleteFlag,
                                  DWORD  dwVersionNum);
  BOOL (*fpAddPerMachineConnection)(LPCWSTR  pServer,
                                    LPCWSTR  pPrinterName,
                                    LPCWSTR  pPrintServer,
                                    LPCWSTR  pProvider);
  BOOL (*fpDeletePerMachineConnection)(LPCWSTR  pServer,
                                       LPCWSTR  pPrinterName);
  BOOL (*fpEnumPerMachineConnections)(LPCWSTR  pServer,
                                      LPBYTE  pPrinterEnum,
                                      DWORD  cbBuf,
                                      LPDWORD  pcbNeeded,
                                      LPDWORD  pcReturned);
  BOOL (*fpXcvData)(HANDLE  hXcv,
                    LPCWSTR  pszDataName,
                    PBYTE  pInputData,
                    DWORD  cbInputData,
                    PBYTE  pOutputData,
                    DWORD  cbOutputData,
                    PDWORD  pcbOutputNeeded,
                    PDWORD  pdwStatus);
  BOOL (*fpAddPrinterDriverEx)(LPWSTR  pName,
                               DWORD  Level,
                               LPBYTE  pDriverInfo,
                               DWORD  dwFileCopyFlags);
  BOOL (*fpSplReadPrinter)(HANDLE  hPrinter,
                           LPBYTE  *pBuf,
                           DWORD  cbBuf);
  BOOL (*fpDriverUnloadComplete)(LPWSTR  pDriverFile);
  BOOL (*fpGetSpoolFileInfo)(HANDLE  hPrinter,
                             LPWSTR  *pSpoolDir,
                             LPHANDLE  phFile,
                             HANDLE  hSpoolerProcess,
                             HANDLE  hAppProcess);
  BOOL (*fpCommitSpoolData)(HANDLE  hPrinter,
                            DWORD  cbCommit);
  BOOL (*fpCloseSpoolFileHandle)(HANDLE  hPrinter);
  BOOL (*fpFlushPrinter)(HANDLE  hPrinter,
                         LPBYTE  pBuf,
                         DWORD  cbBuf,
                         LPDWORD  pcWritten,
                         DWORD  cSleep);
  DWORD (*fpSendRecvBidiData)(HANDLE  hPort,
                              LPCWSTR  pAction,
                              PBIDI_REQUEST_CONTAINER  pReqData,
                              PBIDI_RESPONSE_CONTAINER  *ppResData);
} PRINTPROVIDOR, *LPPRINTPROVIDOR;

In the following Members section, function pointers are listed in the order they are specified within the PRINTPROVIDOR structure. To see function descriptions grouped by related capabilities, see Functions Defined by Print Providers.

Members

fpOpenPrinter
(Required.) Points to the provider's OpenPrinter function, which is described in the Platform SDK documentation. However, at the provider level, this function must supply one of the DWORD return values listed in the following table.
Return Value | Definition
ROUTER_SUCCESS | The provider supports the specified printer and has opened it.
ROUTER_STOP_ROUTING | The provider supports the specified printer, but an error occurred and the printer could not be opened. It is assumed that no other provider can support the printer. The function must call SetLastError.
ROUTER_UNKNOWN | The provider does not support the specified printer. The function must call SetLastError and specify ERROR_INVALID_NAME.

The router calls each provider until one of them returns ROUTER_SUCCESS or ROUTER_STOP_ROUTING. If the provider returns ROUTER_SUCCESS, it must also return a unique handle. (For more information, see Introduction to Print Providers.) The router first attempts to call the provider's OpenPrinterEx function. If that function is not supported, the router calls OpenPrinter.

fpSetJob
(Required.) Points to the provider's SetJob function (described in the Platform SDK documentation).
fpGetJob
(Required.) Points to the provider's GetJob function (described in the Platform SDK documentation).
fpEnumJobs
(Required.) Points to the provider's EnumJobs function (described in the Platform SDK documentation).
fpAddPrinter
(Optional. Can be NULL.) Points to the provider's AddPrinter function (described in the Platform SDK documentation).
fpDeletePrinter
(Optional. Can be NULL.) Points to the provider's DeletePrinter function (described in the Platform SDK documentation).
fpSetPrinter
(Required.) Points to the provider's SetPrinter function (described in the Platform SDK documentation).
fpGetPrinter
(Required.) Points to the provider's GetPrinter function (described in the Platform SDK documentation). If you are writing a network print provider and GetPrinter is returning a PRINTER_INFO_2 structure, the function should supply only the cJobs and Status structure members. The local print provider supplies the rest of the structure members.
fpEnumPrinters
(Required.) Points to the provider's EnumPrinters function (described in the Platform SDK documentation).
fpAddPrinterDriver
(Optional. Can be NULL.) Points to the provider's AddPrinterDriver function (described in the Platform SDK documentation). If the provider does not support the specified driver or server, it should specify ERROR_INVALID_NAME to SetLastError before returning FALSE.
fpEnumPrinterDrivers
(Optional. Can be NULL.) Points to the provider's EnumPrinterDrivers function (described in the Platform SDK documentation). If the provider does not support the specified server, it should specify ERROR_INVALID_NAME to SetLastError before returning FALSE.
fpGetPrinterDriver
(Optional. Can be NULL.) Points to the provider's GetPrinterDriver function (described in the Platform SDK documentation). The router first attempts to call the provider's GetPrinterDriverEx function. If that function is not supported, the router calls GetPrinterDriver.
fpGetPrinterDriverDirectory
(Optional. Can be NULL.) Points to the provider's GetPrinterDriverDirectory function (described in the Platform SDK documentation). If the provider does not support the specified server, it should specify ERROR_INVALID_NAME to SetLastError before returning FALSE.
fpDeletePrinterDriver
(Optional. Can be NULL.) Points to the provider's DeletePrinterDriver function (described in the Platform SDK documentation). If the provider does not support the specified server, it should specify ERROR_INVALID_NAME to SetLastError before returning FALSE.
fpAddPrintProcessor
(Optional. Can be NULL.) Points to the provider's AddPrintProcessor function (described in the Platform SDK documentation).
fpEnumPrintProcessors
(Optional. Can be NULL.) Points to the provider's EnumPrintProcessors function (described in the Platform SDK documentation).
fpGetPrintProcessorDirectory
(Optional. Can be NULL.) Points to the provider's GetPrintProcessorDirectory function (described in the Platform SDK documentation).
fpDeletePrintProcessor
(Optional. Can be NULL.) Points to the provider's DeletePrintProcessor function (described in the Platform SDK documentation).
fpEnumPrintProcessorDatatypes
(Optional. Can be NULL.) Points to the provider's EnumPrintProcessorDatatypes function (described in the Platform SDK documentation).
fpStartDocPrinter
(Required.) Points to the provider's StartDocPrinter function (described in the Platform SDK documentation).
fpStartPagePrinter
(Optional. Can be NULL.) Points to the provider's StartPagePrinter function (described in the Platform SDK documentation).
fpWritePrinter
(Required.) Points to the provider's WritePrinter function (described in the Platform SDK documentation).
fpEndPagePrinter
(Optional. Can be NULL.) Points to the provider's EndPagePrinter function (described in the Platform SDK documentation).
fpAbortPrinter
(Required.) Points to the provider's AbortPrinter function (described in the Platform SDK documentation).
fpReadPrinter
(Optional. Can be NULL.) Points to the provider's ReadPrinter function (described in the Platform SDK documentation).
fpEndDocPrinter
(Required.) Points to the provider's EndDocPrinter function (described in the Platform SDK documentation).
fpAddJob
(Required.) Points to the provider's AddJob function (described in the Platform SDK documentation).
fpScheduleJob
(Required.) Points to the provider's ScheduleJob function (described in the Platform SDK documentation).
fpGetPrinterData
(Optional. Can be NULL.) Points to the provider's GetPrinterData function (described in the Platform SDK documentation).
fpSetPrinterData
(Optional. Can be NULL.) Points to the provider's SetPrinterData function (described in the Platform SDK documentation).
fpWaitForPrinterChange
Obsolete. Must be NULL.
fpClosePrinter
(Required.) Points to the provider's ClosePrinter function (described in the Platform SDK documentation). If a printer change notification object has been created, then the router calls the provider's FindClosePrinterChangeNotification function (described in the Platform SDK documentation) before calling ClosePrinter.
fpAddForm
(Optional. Can be NULL.) Points to the provider's AddForm function (described in the Platform SDK documentation).
fpDeleteForm
(Optional. Can be NULL.) Points to the provider's DeleteForm function (described in the Platform SDK documentation).
fpGetForm
(Optional. Can be NULL.) Points to the provider's GetForm function (described in the Platform SDK documentation).
fpSetForm
(Optional. Can be NULL.) Points to the provider's SetForm function (described in the Platform SDK documentation).
fpEnumForms
(Optional. Can be NULL.) Points to the provider's EnumForms function (described in the Platform SDK documentation).
fpEnumMonitors
(Optional. Can be NULL.) Points to the provider's EnumMonitors function, which is described in the Platform SDK documentation. However, at the provider level this function must supply one of the DWORD return values listed in the following table.
Return Value | Definition
ROUTER_SUCCESS | The provider has enumerated the monitors on the specified server.
ROUTER_UNKNOWN | The provider does not support the specified server.
ROUTER_STOP_ROUTING | The provider has enumerated the monitors on the specified server, and the router should not call other providers.

fpEnumPorts
(Required.) Points to the provider's EnumPorts function, which is described in the Platform SDK documentation. However, at the provider level this function must supply one of the DWORD return values listed in the following table.
Return Value | Definition
ROUTER_SUCCESS | The provider has enumerated the ports on the specified server.
ROUTER_STOP_ROUTING | The provider has enumerated the ports on the specified server, and the router should not call other providers.
ROUTER_UNKNOWN | The provider does not support the specified server.

fpAddPort
(Optional. Can be NULL.) Points to the provider's AddPort function (described in the Platform SDK documentation). If the provider does not support the specified port, it must supply ERROR_NOT_SUPPORTED to SetLastError before returning FALSE.
fpConfigurePort
(Required.) Points to the provider's ConfigurePort function (described in the Platform SDK documentation). If the function supplies ERROR_NOT_SUPPORTED, ERROR_INVALID_NAME, or ERROR_UNKNOWN_PORT to SetLastError, the router will attempt to call another provider.
fpDeletePort
(Required.) Points to the provider's DeletePort function (described in the Platform SDK documentation). If the provider does not support the specified port, it must supply ERROR_NOT_SUPPORTED to SetLastError before returning FALSE.
fpCreatePrinterIC
For internal use only. Must be NULL.
fpPlayGdiScriptOnPrinterIC
For internal use only. Must be NULL.
fpDeletePrinterIC
For internal use only. Must be NULL.
fpAddPrinterConnection
(Optional. Can be NULL.) Points to the provider's AddPrinterConnection function (described in the Platform SDK documentation).
fpDeletePrinterConnection
(Optional. Can be NULL.) Points to the provider's DeletePrinterConnection function (described in the Platform SDK documentation).
fpPrinterMessageBox
Not used. Must be NULL.
fpAddMonitor
(Optional. Can be NULL.) Points to the provider's AddMonitor function (described in the Platform SDK documentation). If the provider does not support the specified monitor, it must supply ERROR_INVALID_NAME to SetLastError before returning FALSE.
fpDeleteMonitor
(Optional. Can be NULL.) Points to the provider's DeleteMonitor function (described in the Platform SDK documentation). If the provider does not support the specified monitor, it must supply ERROR_INVALID_NAME to SetLastError before returning FALSE.
fpResetPrinter
(Optional. Can be NULL.) Points to the provider's ResetPrinter function (described in the Platform SDK documentation).
fpGetPrinterDriverEx
(Optional. Can be NULL.) Points to the provider's GetPrinterDriverEx function (described in the Platform SDK documentation). If GetPrinterDriverEx is not supported, the router attempts to call GetPrinterDriver.
fpFindFirstPrinterChangeNotification
(Optional. Can be NULL.) Points to the provider's FindFirstPrinterChangeNotification function.
fpFindClosePrinterChangeNotification
(Optional. Can be NULL.) Points to the provider's FindClosePrinterChangeNotification function (described in the Platform SDK documentation).
fpAddPortEx
(Optional. Can be NULL.) Points to the provider's AddPortEx function (described in the Platform SDK documentation). If the provider does not support the specified port, it must supply ERROR_NOT_SUPPORTED to SetLastError before returning FALSE.
fpShutDown
For internal use only. Must be NULL.
fpRefreshPrinterChangeNotification
(Optional. Can be NULL.) Points to the provider's RefreshPrinterChangeNotification function.
fpOpenPrinterEx
For internal use only. Must be NULL.
fpAddPrinterEx
For internal use only. Must be NULL.
fpSetPort
(Optional. Can be NULL.) Points to the provider's SetPort function (described in the Platform SDK documentation). If the function supplies ERROR_NOT_SUPPORTED, ERROR_INVALID_NAME, or ERROR_UNKNOWN_PORT to SetLastError, the router will attempt to call another provider.
fpEnumPrinterData
(Optional. Can be NULL.) Points to the provider's EnumPrinterData function (described in the Platform SDK documentation).
fpDeletePrinterData
(Optional. Can be NULL.) Points to the provider's DeletePrinterData function (described in the Platform SDK documentation).
fpClusterSplOpen
For internal use only. Must be NULL.
fpClusterSplClose
For internal use only. Must be NULL.
fpClusterSplIsAlive
For internal use only. Must be NULL.
fpSetPrinterDataEx
(Optional. Can be NULL.) Points to the provider's SetPrinterDataEx function (described in the Platform SDK documentation).
fpGetPrinterDataEx
(Optional. Can be NULL.) Points to the provider's GetPrinterDataEx function (described in the Platform SDK documentation).
fpEnumPrinterDataEx
(Optional. Can be NULL.) Points to the provider's EnumPrinterDataEx function (described in the Platform SDK documentation).
fpEnumPrinterKey
(Optional. Can be NULL.) Points to the provider's EnumPrinterKey function (described in the Platform SDK documentation).
fpDeletePrinterDataEx
(Optional. Can be NULL.) Points to the provider's DeletePrinterDataEx function (described in the Platform SDK documentation).
fpDeletePrinterKey
(Optional. Can be NULL.) Points to the provider's DeletePrinterKey function (described in the Platform SDK documentation).
fpSeekPrinter
For internal use only. Must be NULL.
fpDeletePrinterDriverEx
(Optional. Can be NULL.) Points to the provider's DeletePrinterDriverEx function (described in the Platform SDK documentation). If the provider does not support the specified server, it should specify ERROR_INVALID_NAME to SetLastError before returning FALSE.
fpAddPerMachineConnection
For internal use only. Must be NULL.
fpDeletePerMachineConnection
For internal use only. Must be NULL.
fpEnumPerMachineConnections
For internal use only. Must be NULL.
fpXcvData
(Optional. Can be NULL.) Points to the provider's XcvData function.
fpAddPrinterDriverEx
(Optional. Can be NULL.) Points to the provider's AddPrinterDriverEx function (described in the Platform SDK documentation). If the provider does not support the specified server, it should specify ERROR_INVALID_NAME to SetLastError before returning FALSE.
fpSplReadPrinter
For internal use only. Must be NULL.
fpDriverUnloadComplete
For internal use only. Must be NULL.
fpGetSpoolFileInfo
For internal use only. Must be NULL.
fpCommitSpoolData
For internal use only. Must be NULL.
fpCloseSpoolFileHandle
For internal use only. Must be NULL.
fpFlushPrinter
For internal use only. Must be NULL.
fpSendRecvBidiData
(Optional. Can be NULL.) Points to the provider's SendRecvBidiData function. If this parameter is NULL, it means that the provider does not support bidi communication.

Headers

Declared in winsplp.h. Include winsplp.h.

See Also

InitializePrintProvidor, FindFirstPrinterChangeNotification, RefreshPrinterChangeNotification, XcvData, SendRecvBidiData


Print Processor Functions

This section describes functions that must be exported by print processors. Function prototypes are located in winsplp.h.


ClosePrintProcessor

A print processor's ClosePrintProcessor function completes the printing of a print job and makes the associated handle invalid.

BOOL
  ClosePrintProcessor(
    HANDLE  hPrintProcessor
    );

Parameters

hPrintProcessor
Caller-supplied print processor handle. This is the handle returned by a previous call to OpenPrintProcessor.

Return Value

If the operation succeeds, the function should return TRUE. If the operation fails, the function should call SetLastError to set an error code, and then return FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Print processors are required to export a ClosePrintProcessor function. The spooler calls the function after the print processor's PrintDocumentOnPrintProcessor returns. The function should free all resources that were allocated by the OpenPrintProcessor function.

See Also

OpenPrintProcessor, PrintDocumentOnPrintProcessor


ControlPrintProcessor

A print processor's ControlPrintProcessor function allows the spooler to control a print job.

BOOL
  ControlPrintProcessor(
    HANDLE  hPrintProcessor,
    DWORD  Command
    );

Parameters

hPrintProcessor
Caller-supplied print processor handle. This is the handle returned by a previous call to OpenPrintProcessor.
Command
Caller-supplied command indicating the type of operation to perform. The following commands are valid:
Command | Definition
JOB_CONTROL_CANCEL | The function should cancel the current print job.
JOB_CONTROL_PAUSE | The function should pause the current print job.
JOB_CONTROL_RESUME | The function should resume the current print job.

Return Value

If the operation succeeds, the function should return TRUE. If the operation fails, the function should call SetLastError to set an error code, and then return FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Print processors are required to export a ControlPrintProcessor function. The spooler calls the function when an application calls the SetJob function, described in the Platform SDK documentation.

Based on the value received for Command, the function should either pause, resume, or cancel the current job. The ControlPrintProcessor function can be called asynchronously while the print processor's PrintDocumentOnPrintProcessor function is executing. Thus some sort of synchronization technique must be employed, such as setting an internally-defined event object to pause a job and resetting the event object when the job is resumed. The ControlPrintProcessor function can quickly return after setting or resetting the event object, and PrintDocumentOnPrintProcessor can wait for the event to be in the proper state.

See Also

OpenPrintProcessor, PrintDocumentOnPrintProcessor


EnumPrintProcessorDatatypes

A print processor's EnumPrintProcessorDatatypes function enumerates the data types that the print processor supports.

BOOL
  EnumPrintProcessorDatatypes(
    LPWSTR  pName,
    LPWSTR  pPrintProcessorName,
    DWORD  Level,
    LPBYTE  pDatatypes,
    DWORD  cbBuf,
    LPDWORD  pcbNeeded,
    LPDWORD  pcReturned
    );

Parameters

pName
Caller-supplied pointer to a string representing name of the server on which the print processor is installed. If NULL, the server is the local system.
pPrintProcessorName
Caller-supplied pointer to a string representing the print processor name.
Level
Caller-supplied value indicating the type of the structures to be returned in the buffer pointed to by pDatatypes. This value must be 1, indicating that the structure is DATATYPES_INFO_1.
pDatatypes
Caller-supplied pointer to a buffer to receive an array of DATATYPES_INFO_1 structures, followed by a set of character strings representing data type names. The DATATYPES_INFO_1 structure is described in the Platform SDK documentation.
cbBuf
Caller-supplied value representing the size, in bytes, of the buffer pointed to by pDatatypes.
pcbNeeded
Caller-supplied pointer to a location to receive the minimum required size for the buffer pointed to by pDatatypes.
pcReturned
Caller-supplied pointer to a location to receive the number of DATATYPES_INFO_1 structures returned in the buffer pointed to by pDatatypes.

Return Value

If the operation succeeds, the function should return TRUE. If the operation fails, the function should call SetLastError to set an error code, and then return FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Print processors are required to export an EnumPrintProcessorDatatypes function. The local print provider calls the function during initialization. The function is also called when an application calls the spooler's version of the same function.

The function must return an array of DATATYPES_INFO_1 structures, with each structure pointing to a string that represents a data type. The actual strings must also be included in the buffer, after the structure array. See Sample Print Processor for an example.

The function should return the number of DATATYPES_INFO_1 structures returned (that is, the number of data types supported) in the location pointed to by pcReturned.

The function should return the minimum required buffer size in the location pointed to by pcbNeeded. If the supplied buffer is too small, the function should specify a value for pcbNeeded, set the error code to ERROR_INSUFFICIENT_BUFFER, and return FALSE.


GetPrintProcessorCapabilities

A print processor's GetPrintProcessorCapabilities function returns capabilities associated with a specified input data type.

DWORD
  GetPrintProcessorCapabilities(
    LPTSTR  pValueName,
    DWORD  dwAttributes,
    LPBYTE  pData,
    DWORD  nSize,
    LPDWORD  pcbNeeded
    );

Parameters

pValueName
Caller-supplied pointer to a string representing a data type supported by the print processor.
dwAttributes
Caller-supplied attributes flags. Refer to the Attributes member of PRINTER_INFO_x structures, described in the Platform SDK documentation.
pData
Caller-supplied pointer to a PRINTPROCESSOR_CAPS_1 structure (declared in the Platform SDK documentation).
nSize
Caller-supplied value representing the size of the buffer pointed to by pData.
pcbNeeded
Caller-supplied pointer to a location to receive the minimum required size for the buffer pointed to by pData.

Return Value

If the operation succeeds, the function should return ERROR_SUCCESS. Otherwise it should return a Win32 error code.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Print processors can optionally export a GetPrintProcessorCapabilities function. The function's purpose is to return a filled-in PRINTPROCESSOR_CAPS_1 structure for every input data type that the print processor supports.

The spooler calls a print processor's GetPrintProcessorCapabilities function when an application calls GetPrinterData (described in the Platform SDK documentation), specifying a value name with a format of PrintProcCaps_datatype, where datatype is the name of an input data type. Before calling GetPrintProcessorCapabilities, the spooler removes the PrintProcCaps_ prefix from the value name string.

The function should determine if the received buffer is large enough and, if it is, should fill in the PRINTPROCESSOR_CAPS_1 structure (defined in the Platform SDK documentation) and return. The function should always use the location pointed to by pcbNeeded to return the required buffer size, whether the actual buffer is large enough or not.

The specified return value becomes the return value that the spooler provides for GetPrinterData.


OpenPrintProcessor

A print processor's OpenPrintProcessor function prepares the print processor for printing a job and returns a handle.

HANDLE
  OpenPrintProcessor(
    LPWSTR  pPrinterName,
    PPRINTPROCESSOROPENDATA  pPrintProcessorOpenData
    );

Parameters

pPrinterName
Caller-supplied pointer to the name of the printer for which the print processor is being opened.
pPrintProcessorOpenData
Caller-supplied pointer to a PRINTPROCESSOROPENDATA structure.

Return Value

If the operation succeeds, the function should return a handle that can be used as an input argument for subsequent calls to PrintDocumentOnPrintProcessor, ControlPrintProcessor, and ClosePrintProcessor. If the operation fails, the function should call SetLastError to set an error code, and then return NULL.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Print processors are required to export an OpenPrintProcessor function. The spooler calls the function when a print job is available. The function should perform initialization operations that are required before a job can be processed, based on the job's data type.

The function must return a handle. Typically, the handle is a pointer to an internal structure. The structure must contain a pointer to the printer's name and a pointer to the printer's DEVMODE structure, both of which are received in the PRINTPROCESSOROPENDATA structure. These two pointers are required by the print processor's PrintDocumentOnPrintProcessor function, and this latter function receives the handle as input when the spooler calls it.

See Also

PRINTPROCESSOROPENDATA, PrintDocumentOnPrintProcessor, ControlPrintProcessor, ClosePrintProcessor


PrintDocumentOnPrintProcessor

A print processor's PrintDocumentOnPrintProcessor function converts a print job from a spooled format into raw data that can be sent to a print monitor.

BOOL
  PrintDocumentOnPrintProcessor(
    HANDLE  hPrintProcessor,
    LPWSTR  pDocumentName
    );

Parameters

hPrintProcessor
Caller-supplied print processor handle. This is the handle returned by a previous call to OpenPrintProcessor.
pDocumentName
Caller-supplied pointer to the document name.

Return Value

If the operation succeeds, the function should return TRUE. If the operation fails, the function should call SetLastError to set an error code, and then return FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Print processors are required to export a PrintDocumentOnPrintProcessor function. The spooler calls the function after calling OpenPrintProcessor. The function's purpose is to read the contents of the file named by pDocumentName, convert (if necessary) the file's data to a data stream that can be read by printer hardware, and to send the data stream back to the spooler. The spooler can then send the data stream to the appropriate print monitor.

If the input format is NT-based operating system EMF, the PrintDocumentOnPrintProcessor function can call GDI functions for print processors. For more information see Processing a Print Job.

The converted data stream must be sent back to the spooler by calling WritePrinter, which is described in the Platform SDK documentation. For more information see Processing a Print Job.

The PrintDocumentOnPrintProcessor function must be written to handle requests to pause, resume, or cancel the print job. For more information, see ControlPrintProcessor.

See Also

OpenPrintProcessor, ControlPrintProcessor


Print Processor Structures

This section describes structures used by print processors. Structure declarations are located in winsplp.h.


PRINTPROCESSOROPENDATA

The PRINTPROCESSOROPENDATA structure is used as an input parameter to a print processor's OpenPrintProcessor function.

typedef struct _PRINTPROCESSOROPENDATA {
  PDEVMODE  pDevmode;
  LPWSTR  pDatatype;
  LPWSTR  pParameters;
  LPWSTR  pDocumentName;
  DWORD   JobId;
  LPWSTR  pOutputFile;
  LPWSTR  pPrinterName;
} PRINTPROCESSOROPENDATA, *PPRINTPROCESSOROPENDATA *LPPRINTPROCESSOROPENDATA;

Members

pDevmode
Spooler-supplied pointer to a DEVMODE structure.
pDatatype
Spooler-supplied pointer to a string representing the print job's data type.
pParameters
Spooler-supplied pointer to a parameter string, as specified in a JOB_INFO_2 structure supplied to a call to the SetJob function, described in the Platform SDK documentation.
pDocumentName
Spooler-supplied pointer to a string representing the name of the input document associated with the print job.
JobId
Spooler-supplied value identifying the print job.
pOutputFile
Spooler-supplied pointer to a string representing the name of the output spool file.
pPrinterName
Spooler-supplied pointer to a string representing the name of the printer to be used.

Headers

Declared in winsplp.h. Include winsplp.h.

See Also

OpenPrintProcessor, DEVMODE


Print Monitor Functions

This section describes the functions defined by print monitors, which include language monitors and port monitors. Function prototypes are contained in winsplp.h.


AddPort

AddPort creates a port and adds it to the list of ports currently supported by the specified monitor in the spooler environment.

BOOL
  (WINAPI *pfnAddPort)(
    HANDLE hMonitor  //MONITOR2 only
    LPWSTR  pName,
    HWND  hWnd,
    LPWSTR  pMonitorName
    );

Note The AddPort function is out of date and for use only with Windows NT 4.0 and previous versions.

Parameters

hMonitor
Caller supplied monitor instance handle. This is the handle returned by the monitor's InitializePrintMonitor2 function. (This parameter does not exist if the print monitor supports InitializePrintMonitor instead of InitializePrintMonitor2.)
pName
Points to a zero-terminated string that specifies the name of the server to which the port is connected. If pName is NULL, the port is local.
hWnd
Handle to the parent window of the dialog box in which the port name will be entered.
pMonitorName
Points to a zero-terminated string that specifies the monitor associated with the port.

Return Value

The return value is TRUE if the function is successful, and FALSE otherwise.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

The spooler calls AddPort when it receives an application request to add a port to its environment. The spooler forwards the call to the named port monitor on the named server.

AddPort allows a port to be added interactively. A monitor should prompt a user to enter the port name in a dialog box on the window associated with hWnd. AddPort should validate the entered port name by calling the Win32 EnumPorts function to ensure that no duplicate port names are added to the spooler environment. A monitor should also verify that the port is one that it supports.

The spooler does not support remote AddPort calls. Consequently, AddPort implementations can ignore the pName and pMonitorName parameters.

See Also

DeletePort, InitializePrintMonitor2


AddPortEx

The AddPortEx function creates and configures a port without user intervention.

BOOL
  (WINAPI *pfnAddPortEx)(
    HANDLE  hMonitor  //MONITOR2 only
    LPWSTR  pName,
    DWORD  Level,
    LPBYTE  lpBuffer,
    LPWSTR  lpMonitorName
    );

Note The AddPortEx function is out of date and for use only with Windows NT 4.0 and previous versions.

Parameters

hMonitor
Caller supplied monitor instance handle. This is the handle returned by the monitor's InitializePrintMonitor2 function. (This parameter does not exist if the print monitor supports InitializePrintMonitor instead of InitializePrintMonitor2.)
pName
Caller-supplied pointer to a string representing the server name, or NULL if the printer is local.
Level
Caller-supplied value indicating the type of structure pointed to by lpBuffer. Possible values are as follows:
Level | lpBuffer
1 | PORT_INFO_1
2 | PORT_INFO_2

lpBuffer
Caller-supplied pointer to a PORT_INFO_1 or PORT_INFO_2 structure. These structures are described in the Platform SDK documentation.
lpMonitorName
Caller-supplied pointer to a string representing the name of the monitor. Can be NULL.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise it should call SetLastError to set an error code and return FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

The AddPortEx function can be optionally provided by a port monitor server DLL. If provided, its address must be placed in the server DLL's MONITOR2 structure.

If an application calls the print spooler's AddPortEx function, the spooler in turn calls the server DLL's AddPortEx function.

The AddPortEx function allows the spooler to add a port by directly communicating with the port monitor server DLL, bypassing the port monitor UI DLL. The server DLL's function should add and configure a port but, because it executes on the print server, it cannot display a user interface.

If the Level argument is invalid, the function should call SetLastError with an error code of ERROR_INVALID_LEVEL.

The function should call the spooler's EnumPorts function to verify that the port name specified in the structure pointed to by lpBuffer has not already been used by this or another monitor. If the port name is available, the function should add the port without user intervention and write the port name in the registry under the Ports key.

See Also

InitializePrintMonitor2, MONITOR2


AddPortUI

A port monitor UI DLL's AddPortUI function adds a printer port, then obtains port configuration information from the user and sends it to the port monitor server DLL.

BOOL
  AddPortUI(
    PCWSTR  pszServer,
    HWND  hWnd,
    PCWSTR  pszPortNameIn,
    PWSTR  *ppszPortNameOut
    );

Parameters

pszServer
Caller-supplied pointer to a string representing a server name, or NULL if the printer is local.
hWnd
Caller-supplied handle of the window that should be used as the parent for dialog boxes. If NULL, no dialog boxes should be displayed.
pszPortNameIn
Caller-supplied pointer to a string representing the name of the monitor. Can be NULL.
ppszPortNameOut
Caller-supplied pointer to a location to receive a port name string. Can be NULL, in which case a name is not returned.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise SetLastError should be called to specify an error code, and the function should return FALSE. If the operation is canceled by the user or is unsupported, the function should call SetLastError(ERROR_CANCELLED), then return FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Port monitor UI DLLs are required to define an AddPortUI function and include the function's address in a MONITORUI structure.

The spooler calls AddPortUI from within its AddPort function. The first three arguments received by AddPortUI are the arguments received by AddPort. (The AddPort function is described in the Platform SDK documentation.)

The function should perform the following operations:

  1. Call OpenPrinter, specifying a printer name with the following format:

    \\ServerName\,XcvMonitor MonitorName

    where ServerName and MonitorName are the server and monitor names received as AddPortUI function arguments.

    The call to OpenPrinter requires a PRINTER_DEFAULTS structure, which is described in the Platform SDK documentation. The structure's DesiredAccess member must be set to SERVER_ACCESS_ADMINISTER. Its pDatatype and pDevMode members can be NULL.

    This call causes the print monitor server DLL's XcvOpenPort function to be called.

  2. Obtain a port name from the user by displaying a dialog box.
  3. Call XcvData, specifying the following input arguments:
    • The handle received from OpenPrinter
    • The port name received from the user
    • A customized data name string, such as "PortExists"

    This call causes the server DLL's XcvDataPort function to be called. The XcvDataPort function should return a value that indicates whether the specified port name has already been used. If it has, the UI DLL should request another name from the user and call XcvData again.

  4. After a valid new port name has been received, call XcvData again, this time specifying the following input arguments:
    • The handle received from OpenPrinter
    • The validated port name received from the user
    • A data name string of "AddPort"

    This call causes the server DLL's XcvDataPort function to be called again.

  5. Obtain port configuration parameters from the user by displaying a dialog box.
  6. Call XcvData one or more times, specifying customized data name strings, to send each configuration parameter to the server DLL. Each XcvData call causes the server's XcvDataPort function to be called.
  7. Call ClosePrinter, specifying the handle received from OpenPrinter. This causes the server DLL's XcvClosePort function to be called.

See Also

MONITORUI, XcvOpenPort, XcvClosePort, XcvData, XcvDataPort


ClosePort

A language or port monitor's OpenPort function closes a printer port.

BOOL
  (WINAPI *pfnClosePort)(
    HANDLE  hPort
    );

Parameters

hPort
Caller-supplied pointer to a port handle.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise it should return FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Language monitors and Port monitor server DLLs are required to define a ClosePort function and include the function's address in a MONITOR2 structure.

The handle received as the function's hPort argument is the port handle that the monitor's OpenPort or OpenPortEx function supplied.

The ClosePort function should close the port by making the received port handle invalid. It should also free all system resources that were allocated by the monitor's OpenPort or OpenPortEx function.

See Also

MONITOR2, OpenPort, OpenPortEx


ConfigurePort

ConfigurePort is a port management function that configures the specified port.

BOOL
  (WINAPI *pfnConfigurePort)(
    HANDLE  hMonitor  //MONITOR2 only
    LPWSTR  pName,
    HWND  hWnd,
    LPWSTR  pPortName
    );

Note The ConfigurePort function is out of date and for use only with Windows NT 4.0 and previous versions.

Parameters

hMonitor
Caller supplied monitor instance handle. This is the handle returned by the monitor's InitializePrintMonitor2 function. (This parameter does not exist if the print monitor supports InitializePrintMonitor instead of InitializePrintMonitor2.)
pName
Points to a zero-terminated string that specifies the name of the server on which the given port exists. If this string is NULL, the port is local.
hWnd
Handle to the parent window of the dialog box in which the configuration information will be entered.
pPortName
Points to a zero-terminated string that specifies the name of the port to be configured.

Return Value

The return value is TRUE if the function is successful.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

The spooler calls ConfigurePort so a port monitor can perform port configuration. ConfigurePort can offer a dialog box to obtain some or all of the necessary port configuration information from the user.

The spooler does not support remote ConfigurePort calls; consequently, monitors can ignore the pName parameter.

See Also

AddPort, DeletePort, InitializePrintMonitor2, InitializePrintMonitor


ConfigurePortUI

A port monitor UI DLL's ConfigurePortUI function obtains port configuration information from the user and sends it to the port monitor server DLL.

BOOL
  ConfigurePortUI(
    PCWSTR  pszServer,
    HWND  hWnd,
    PCWSTR  pszPortName
    );

Parameters

pszServer
Caller-supplied pointer to a string representing a server name, or NULL if the printer is local. (The port monitor can ignore this parameter.)
hWnd
Caller-supplied handle of the window that should be used as the parent for dialog boxes. If NULL, no dialog boxes should be displayed.
pszPortName
Caller-supplied pointer to a string representing the name of the port to be configured.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise it should return FALSE. If the operation is unsupported, or is canceled by the user (either by selecting CANCEL or by selecting OK without changing configuration parameters), the function should call SetLastError(ERROR_CANCELLED), then return FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Port monitor UI DLLs are required to define a ConfigurePortUI function and include the function's address in a MONITORUI structure.

The client's spooler calls ConfigurePortUI from within its ConfigurePort function (described in the Platform SDK documentation). The arguments received by ConfigurePortUI are the arguments received by ConfigurePort.

The function should perform the following operations:

  1. Call OpenPrinter, specifying a printer name with the following format:

    \\ServerName\,XcvPort PortName

    where ServerName and PortName are the server and port names received as ConfigurePortUI function arguments.

    The call to OpenPrinter requires a PRINTER_DEFAULTS structure, which is described in the Platform SDK documentation. The structure's DesiredAccess member must be set to SERVER_ACCESS_ADMINISTER. Its pDatatype and pDevMode members can be NULL.

    This call causes the print monitor server DLL's XcvOpenPort function to be called.

  2. Obtain port configuration parameters from the user by displaying a dialog box.
  3. Call XcvData one or more times, specifying customized data name strings, to send each configuration parameter to the server DLL. Each XcvData call causes the server's XcvDataPort function to be called.
  4. Call ClosePrinter, specifying the handle received from OpenPrinter. This causes the server DLL's XcvClosePort function to be called.

See Also

XcvOpenPort, XcvData, XcvDataPort, XcvClosePort


DeletePort

DeletePort deletes a port from the monitor's environment.

BOOL
  (WINAPI *pfnDeletePort)(
    HANDLE  hMonitor  //MONITOR2 only
    LPWSTR  pName,
    HWND  hWnd,
    LPWSTR  pPortName
    );

Note The DeletePort function is out of date and for use only with Windows NT 4.0 and previous versions.

Parameters

hMonitor
Caller supplied monitor instance handle. This is the handle returned by the monitor's InitializePrintMonitor2 function. (This parameter does not exist if the print monitor supports InitializePrintMonitor instead of InitializePrintMonitor2.)
pName
Points to a zero-terminated string that specifies the name of the server on which the port to be deleted exists. If this parameter is NULL, the port is local.
hWnd
Handle to the parent window of the port-deletion dialog box.
pPortName
Points to a zero-terminated string that names the port to be deleted.

Return Value

The return value is TRUE if the function is successful.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

The spooler calls DeletePort so a port monitor can delete a port from the monitor's environment. The monitor should delete the specified port from its state. The spooler will not call DeletePort on a monitor as long as a port is open.

Applications can delete local and remote ports. The printer UI displays a confirmation message box before the spooler calls DeletePort, so a monitor should ignore the hWnd parameter and not display another dialog box.

See Also

AddPort, InitializePrintMonitor2


DeletePortUI

A port monitor UI DLL's DeletePortUI function deletes a printer port.

BOOL
  DeletePortUI(
    PCWSTR  pszServer,
    HWND  hWnd,
    PCWSTR  pszPortName
    );

Parameters

pszServer
Caller-supplied pointer to a string representing a server name, or NULL if the printer is local. (The port monitor can ignore this parameter.)
hWnd
Caller-supplied handle of the window that should be used as the parent for dialog boxes. If NULL, no dialog boxes should be displayed.
pszPortName
Caller-supplied pointer to a string representing the name of the port to be deleted.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise it should return FALSE. If the operation is canceled by the user or is unsupported, the function should call SetLastError(ERROR_CANCELLED), then return FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Port monitor UI DLLs are required to define a DeletePortUI function and include the function's address in a MONITORUI structure.

The spooler calls DeletePortUI from within its DeletePort function. The arguments received by DeletePortUI are the arguments received by DeletePort. (The DeletePort function is described in the Platform SDK documentation.)

The function should perform the following operations:

  1. Call OpenPrinter, specifying a printer name with the following format:

    \\ServerName\,XcvPort PortName

    where ServerName and PortName are the server and port names received as DeletePortUI function arguments.

    The call to OpenPrinter requires a PRINTER_DEFAULTS structure, which is described in the Platform SDK documentation. The structure's DesiredAccess member must be set to SERVER_ACCESS_ADMINISTER. Its pDatatype and pDevMode members can be NULL.

    This call causes the print monitor server DLL's XcvOpenPort function to be called.

  2. Call XcvData, specifying the following input arguments:
    • The handle received from OpenPrinter
    • The port name received as a function argument
    • A data name string of "DeletePort"

    This call causes the server DLL's XcvClosePort function to be called.

  3. If user interaction is required, obtain information from the user by displaying a dialog box and then call XcvData, specifying customized data name strings, to send the information to the server DLL. The XcvData call causes the server's XcvDataPort function to be called.
  4. Call ClosePrinter, specifying the handle received from OpenPrinter. This causes the server DLL's XcvClosePort function to be called.

See Also

XcvOpenPort, XcvClosePort, XcvData, XcvDataPort


EndDocPort

A print monitor's EndDocPort function performs the tasks required to end a print job on the specified port.

BOOL
  (WINAPI *pfnEndDocPort)(
    HANDLE  hPort
    );

Parameters

hPort
Caller-supplied port handle.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise it should return FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Language monitors and port monitor server DLLs are required to define an EndDocPort function and include the function's address in a MONITOR2 structure.

The handle received as the function's hPort argument is the port handle that the monitor's OpenPort or OpenPortEx function supplied.

A language monitor's EndDocPort function typically calls the associated port monitor's EndDocPort function. It should also notify the spooler when the printing device has finished the job by calling SetJob (described in the Platform SDK documentation), specifying a command of JOB_CONTROL_LAST_PAGE_EJECTED. Language monitors for bidirectional printers should not call SetJob until the printer has sent notification that the job is really finished.

A port monitor server DLL's EndDocPort function typically calls the CloseHandle function, described in the Platform SDK documentation, to close the handle that was previously obtained by calling CreateFile from within StartDocPort. It should also notify the spooler when the printing device has finished the job, by calling SetJob, specifying a command of JOB_CONTROL_SENT_TO_PRINTER. (If a spooler is communicating with the port through a language monitor, it doesn't consider the job complete until the language monitor sends JOB_CONTROL_LAST_PAGE_EJECTED.)

The EndDocPort function should free all resources that were allocated by the StartDocPort function.

You might want to modify the EndDocPort function's behavior if the user has deleted or restarted the print job. The function can call GetJob, described in the Platform SDK documentation, and check for a status of JOB_STATUS_DELETING or JOB_STATUS_RESTART, to see if either of these events has occurred.

See Also

OpenPort, OpenPortEx


EnumPorts

A port monitor server DLL's EnumPorts function enumerates the ports that the port monitor supports.

BOOL
  (WINAPI *pfnEnumPorts)(
    HANDLE  hMonitor  //MONITOR2 only
    LPWSTR  pName,
    DWORD  Level,
    LPBYTE  pPorts,
    DWORD  cbBuf,
    LPDWORD  pcbNeeded,
    LPDWORD  pcReturned
    );

Parameters

hMonitor
Caller supplied monitor instance handle. This is the handle returned by the monitor's InitializePrintMonitor2 function. (This parameter does not exist if the print monitor supports InitializePrintMonitor instead of InitializePrintMonitor2.)
pName
Caller-supplied pointer to a string containing the name of the server whose ports are to be enumerated. A NULL pointer represents the system on which the port monitor server DLL is executing.
Level
Caller-supplied value indicating the type of structures to be returned in the buffer pointed to by pPorts. Possible values are as follows:
Level | pPorts
1 | PORT_INFO_1
2 | PORT_INFO_2

pPorts
Caller-supplied pointer to a buffer to receive port information. Returned information must consist of an array of PORT_INFO_1 or PORT_INFO_2 structures, followed by the strings pointed to by structure members. These structures are described in the Platform SDK documentation.
cbBuf
Caller-supplied size, in bytes, of the buffer pointed to by pPorts.
pcbNeeded
Caller-supplied pointer to a location to receive the buffer size, in bytes, required to contain all returned information.
pcReturned
Caller-supplied pointer to a location to receive the number enumerated ports.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise it should return FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Port monitor server DLLs are required to define an EnumPorts function and include the function's address in a MONITOR2 structure. Language monitors do not export this function.

The purpose of the EnumPorts function is to enumerate the ports currently supported by a print monitor. These ports are ones that were previously specified to the monitor's AddPortUI or AddPortEx function.

The EnumPorts function should fill the buffer pointed to by pPort with an array of PORT_INFO_1 or PORT_INFO_2 structures. Following the last array element, the function must load all the strings pointed to by the array's structure members. Refer to localmon.dll, a sample port monitor, for an example of how to do this. The function must also return the number of structures supplied (that is, the number of supported ports) by placing the number in the location pointed to by pcReturned.

The caller specifies the size of the supplied buffer in cbBuf. If the buffer is too small, the function should place the required buffer size in the location pointed to by pcbNeeded, call SetLastError (described in the Platform SDK documentation) specifying ERROR_INSUFFICIENT_BUFFER, and return FALSE.

If Level contains an invalid level number, the function should call SetLastError specifying ERROR_INVALID_LEVEL, and return FALSE. Some port monitors only support a level value of 1.

The port monitor must support localization of strings pointed to by the pMonitorName and pDescription members of the PORT_INFO_2 structure. Theses strings should be defined in resource files and obtained by calling LoadString (described in the Platform SDK documentation).

The fPortType member of the PORT_INFO_2 structure is not used with NT-based operating systems.

See Also

AddPortUI, AddPortEx


GetPrinterDataFromPort

A port monitor's GetPrinterDataFromPort function obtains status information from a bidirectional printer and returns it to the caller.

BOOL
  (WINAPI *pfnGetPrinterDataFromPort)(
    HANDLE  hPort,
    DWORD  ControlID,
    LPWSTR  pValueName,
    LPWSTR  lpInBuffer,
    DWORD  cbInBuffer,
    LPWSTR  lpOutBuffer,
    DWORD  cbOutBuffer,
    LPDWORD  lpcbReturned
    );

Parameters

hPort
Caller-supplied port handle.
ControlID
Caller-supplied device I/O control code. A value of zero indicates a value name is supplied by pValueName. See the following Comments section.
pValueName
Caller-supplied pointer to a string identifying the information being requested. Valid only if ControlID is zero. See the following Comments section.
lpInBuffer
Caller-supplied pointer to a buffer containing input data. Used only if ControlID is non-zero. See the following Comments section.
cbInBuffer
Caller-supplied size, in bytes, of the buffer pointed to by lpInBuffer.
lpOutBuffer
Caller-supplied pointer to a buffer to receive the requested data.
cbOutBuffer
Caller-supplied size, in bytes, of the buffer pointed to by lpOutBuffer.
lpcbReturned
Caller-supplied pointer to a location to receive the number of bytes written into the buffer pointed to by lpOutBuffer.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise it should return FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Language monitors and Port monitor server DLLs can optionally define a GetPrinterDataFromPort function and include the function's address in a MONITOR2 structure.

The function is meant for use with bidirectional printers, and can be used in the following two ways:

  • As a means for requesting a language monitor to poll the printer port, to obtain the current value of printer-specific information that is stored in the registry.
  • As a means for requesting a port monitor to send an I/O control code to the port driver.

Requesting a Language Monitor to Poll the Printer Port

If a language monitor's GetPrinterDataFromPort function receives a string pointer in pValueName, it should return a value in the supplied output buffer. Typically, the string represents a registry value name, and the spooler calls GetPrinterDataFromPort when an application calls the GetPrinterData function (described in the Platform SDK documentation).

The language monitor's responsibility is to send a command to the printer hardware by calling the port monitor's WritePort function, and reading the response by calling ReadPort, to obtain the needed value. For example, pjlmon.dll, the sample language monitor, can return values for a port's "Installed Memory" and "Available Memory" registry value names.

After the spooler calls GetPrinterDataFromPort to obtain a registry value, it updates the registry with the new value.

Typically, port monitors do not support calls to GetPrinterDataFromPort that include a string pointer in pValueName.

Requesting a Port Monitor to Send an I/O Control Code

If a language monitor's GetPrinterDataFromPort function receives a non-zero I/O control code in ControlID, it should just call the associated port monitor's GetPrinterDataFromPort function and return the result. The Kernel-Mode Drivers Reference, in this DDK, lists I/O control codes for parallel and serial ports.

When a port monitor's GetPrinterDataFromPort function receives a non-zero I/O control code in ControlID, it should call DeviceIOControl (described in the Platform SDK documentation) to pass the control code to the kernel-mode port driver. The lpInBuffer, cbInBuffer, lpOutBuffer, cbOutBuffer, and lpcbReturned parameter values should also be passed to DeviceIOControl.

See Also

WritePort, ReadPort


InitializeMonitor

The InitializeMonitor function is supported for existing print monitors only. New print monitors should export InitializePrintMonitor2 instead.

BOOL
  InitializeMonitor(
    LPWSTR  pRegistryRoot
    );


InitializeMonitorEx

The InitializeMonitorEx function is supported for existing print monitors only. New print monitors should export InitializePrintMonitor2.

BOOL
  InitializeMonitorEx(
    LPWSTR  pRegistryRoot,
    LPMONITOR  pMonitor
    );


InitializePrintMonitor

A print monitor's InitializePrintMonitor function initializes a print monitor.

LPMONITOREX
  InitializePrintMonitor(
    LPWSTR  pRegistryRoot
    );

Note This function is obsolete and supported for compatibility purposes only. New print monitors should implement InitializePrintMonitor2 so that they can be used with print server clusters.

Parameters

pRegistryRoot
Caller-supplied pointer to a string identifying a registry path that the print monitor can use to store monitor-specific values.

Return Value

If the operation succeeds, the function should return a pointer to a MONITOREX structure. Otherwise the function should call SetLastError (described in the Platform SDK documentation) to set an error code, and return NULL.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

The InitializePrintMonitor function must be exported by language monitors and by port monitor server DLLs. The function is called immediately after the monitor DLL is loaded, and is not called again until the DLL is reloaded. Its purposes are to allow the monitor to initialize itself, and to provide the spooler with pointers to internal monitor functions. Function pointers are contained in a MONITOR structure, which is referenced through the MONITOREX function.

The pRegistryRoot parameter supplies a pointer a string representing the path to a MonitorName registry key, where MonitorName is the monitor name that was specified when the spooler's AddMonitor function was called to add the monitor. The monitor can use this key to store monitor-specific value names and values. When the spooler's DeleteMonitor function is called, the spooler deletes the MonitorName key and all values stored underneath it. (The AddMonitor and DeleteMonitor functions are described in the Platform SDK documentation.)

See Also

InitializePrintMonitorUI, MONITOREX


InitializePrintMonitor2

A print monitor's InitializePrintMonitor2 function initializes a print monitor for use with clustered print servers.

LPMONITOR2 WINAPI
  InitializePrintMonitor2(
    PMONITORINIT  pMonitorInit,
    PHANDLE  phMonitor
    );

Parameters

pMonitorInit
Caller-supplied pointer to a MONITORINIT structure.
phMonitor
Caller-supplied location in which the function returns a monitor handle.

Return Value

If the operation succeeds, the function should return a pointer to a MONITOR2 structure. Otherwise the function should call SetLastError (described in the Platform SDK documentation) to set an error code, and return NULL.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

The InitializePrintMonitor2 function must be exported by language monitors and by port monitor server DLLs. The function is called immediately after the monitor DLL is loaded, and is not called again until the DLL is reloaded. Its purposes are to allow the monitor to initialize itself, and to provide the spooler with pointers to internal monitor functions. Function pointers are contained in a MONITOR2 structure.

The MONITOR2 structure is larger in Windows XP than it was in Windows 2000. In order to ensure that a monitor developed with the Windows XP DDK will also install on Windows 2000, as well as Windows XP, the monitor must do the following:

  • Perform a run-time check to determine which operating system version the monitor is running on.
  • If the monitor is running on Windows 2000, it must set the cbSize member of the MONITOR2 structure to MONITOR2_SIZE_WIN2K (defined in winsplp.h), the size appropriate for Windows 2000 version of this structure.

The following function determines whether the current operating system version is Windows 2000.

BOOL  Is_Win2000()
{
  OSVERSIONINFOEX osvi;
  DWORDLONG dwlConditionMask = 0;

  // Initialize the OSVERSIONINFOEX structure.

  ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
  osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  osvi.dwMajorVersion = 5;
  osvi.dwMinorVersion = 0;

  // Initialize the condition mask.
  VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, VER_EQUAL );
  VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, VER_EQUAL );

  // Perform the test.
  return VerifyVersionInfo(
      &osvi,
      VER_MAJORVERSION | VER_MINORVERSION,
      dwlConditionMask);
}

For a monitor that is loading on Windows 2000, the following code sets the MONITOR2 structure's cbSize member appropriately.

if ( Is_Win2000( ) )
    Monitor2.cbSize = MONITOR2_SIZE_WIN2K;

See Also

MONITORINIT


InitializePrintMonitorUI

A port monitor UI DLL's InitializePrintMonitorUI function supplies the print spooler with addresses of DLL functions.

PMONITORUI WINAPI
  InitializePrintMonitorUI(
    VOID
    );

Parameters

None.

Return Value

The function should return a pointer to an initialized MONITORUI structure.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Port monitor UI DLLs are required to export an InitializePrintMonitorUI function. The function is called immediately after the DLL is loaded, and is not called again until the DLL is reloaded. Its purposes are to allow the DLL to initialize itself, and to provide the spooler with pointers to internal functions.

See Also

InitializePrintMonitor, MONITORUI


OpenPort

A port monitor's OpenPort function opens a printer port.

BOOL
  (WINAPI *pfnOpenPort)(
    HANDLE  hMonitor  //MONITOR2 only
    LPWSTR  pName,
    PHANDLE  pHandle
    );

Parameters

hMonitor
Caller supplied monitor instance handle. This is the handle returned by the monitor's InitializePrintMonitor2 function. (This parameter does not exist if the print monitor supports InitializePrintMonitor instead of InitializePrintMonitor2.)
pName
Caller-supplied pointer to a string containing the name of the port to be opened.
pHandle
Caller-supplied pointer to a location to receive a port handle.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise it should return FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Port monitor server DLLs are required to define an OpenPort function and include the function's address in a MONITOR2 structure.

The OpenPort function is called, either by a language monitor or by the print spooler, when a print queue is being connected to a port. The OpenPort function's primary purpose is to return a port handle that the caller can use as an input argument for subsequent calls to the port monitor's StartDocPort, WritePort, ReadPort, EndDocPort, and GetPrinterDataFromPort functions.

Besides returning a port handle, the OpenPort function can perform initialization operations that need to be taken care of before read or write operations are performed. For example, if the port supports modifiable time-out values, the OpenPort function should set these values.

Calls to OpenPort are not print job-specific. Between each call to a port monitor's OpenPort and ClosePort functions, there can be multiple calls to its StartDocPort and EndDocPort functions.

You can assume that after the print spooler has called OpenPort with a particular port name, it will not call OpenPort again with the same port name before calling ClosePort.

Print monitor functions that accept a port handle as input do not also accept a monitor handle. Therefore, the OpenPort function must store the received monitor handle in a location that can be referenced by the port handle. This allows the functions that accept a port handle to reference the monitor handle.

See Also

InitializePrintMonitor2, OpenPortEx, SetPortTimeouts, StartDocPort, WritePort, ReadPort, EndDocPort, and GetPrinterDataFromPort, ClosePort


OpenPortEx

A language monitor's OpenPortEx function opens a printer port.

BOOL
  (WINAPI *pfnOpenPortEx)(
    HANDLE  hMonitor  //MONITOR2 only
    LPWSTR  pPortName,
    LPWSTR  pPrinterName,
    PHANDLE  pHandle,
    struct _MONITOR2 FAR  *pMonitor
    );

Parameters

hMonitor
Caller supplied monitor instance handle. This is the handle returned by the monitor's InitializePrintMonitor2 function. (This parameter does not exist if the print monitor supports InitializePrintMonitor instead of InitializePrintMonitor2.)
pPortName
Caller-supplied pointer to a string containing the name of the port to be opened.
pPrinterName
Caller-supplied pointer to a string containing the name of the printer that is connected to the port.
pHandle
Caller-supplied pointer to a location to receive a port handle.
pMonitor
Caller-supplied pointer to the MONITOR2 structure returned by a port monitor's InitializePrintMonitor2 function.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise it should return FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Language monitors are required to define an OpenPortEx function and include its address in a MONITOR2 structure. The OpenPortEx function is called by the print spooler when a print queue is being connected to a port.

The OpenPortEx function's primary purpose is to return a port handle that the caller can use as an input argument for subsequent calls to the language monitor's StartDocPort, WritePort, ReadPort, EndDocPort, and GetPrinterDataFromPort functions. Because a language monitor typically implements these functions by calling the equivalent functions in its associated port monitor, a language monitor typically obtains a port handle by calling the port monitor's OpenPort function. For more information see Language and Port Monitor Interaction.

The OpenPortEx function's pMonitor parameter is a pointer to the port monitor's MONITOR2 structure. This structure contains pointers to the port monitor's callable functions. The OpenPortEx function should check the structure to verify that all required function pointers are non-NULL. If the structure is valid, the function should copy it into local storage. Otherwise OpenPortEx should call SetLastError, specifying ERROR_INVALID_PRINT_MONITOR, and return FALSE.

Print monitor functions that accept a port handle as input do not also accept a monitor handle. Therefore, the OpenPortEx function must store the received monitor handle in a location that can be referenced by the port handle. This allows the functions that accept a port handle to reference the monitor handle.

See Also

MONITOR2, InitializePrintMonitor2, ClosePort, OpenPort, StartDocPort, WritePort, ReadPort, EndDocPort, GetPrinterDataFromPort


ReadPort

A port monitor's ReadPort function writes data to a printer port.

BOOL
  (WINAPI *pfnReadPort)(
    HANDLE  hPort,
    LPBYTE  pBuffer,
    DWORD  cbBuffer,
    LPDWORD  pcbRead
    );

Parameters

hPort
Caller-supplied port handle.
pBuffer
Caller-supplied pointer to a buffer to receive data read from the port.
cbBuffer
Caller-supplied size, in bytes, of pBuffer.
pcbRead
Caller-supplied pointer to a location to receive the number of bytes successfully read from the port.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise it should return FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Language monitors and port monitor server DLLs are required to define a ReadPort function and include the function's address in a MONITOR2 structure.

The handle received as the function's hPort argument is the port handle that the monitor's OpenPort or OpenPortEx function supplied.

Typically, a language monitor's ReadPort function calls the associated port monitor's ReadPort function, and returns the obtained buffer contents to the caller.

Additionally, a language monitor might create a separate thread that calls the port monitor's ReadPort function to check for unsolicited status information. If such a read operation succeeds, the status information should be returned to the spooler by calling SetPort (described in the Platform SDK documentation).

Typically, a port monitor server DLL's ReadPort function calls ReadFile (described in the Platform SDK documentation) to obtain data from the kernel-mode port driver. The function just returns the data to the caller.

Even though both language monitors and port monitors must define ReadPort functions and place their addresses in MONITOR2 structures, a language monitor's ReadPort function is never actually called by the spooler or an application. The function is solely for the internal use of the language monitor itself.

For example pjlmon.dll, the sample language monitor, creates a separate thread that calls its own ReadPort to watch for unsolicited printer status information, and the ReadPort function calls the port monitor's ReadPort function. When the port monitor returns data to the language monitor, the language monitor parses the received data and calls SetPort (described in the Platform SDK documentation) to send status information to the spooler.

The function should return the number of bytes successfully read by placing the number in the location pointed to by pcbRead. The caller determines the success or failure of the write operation by checking ReadPort's return value, not the returned byte count. So a returned byte count of zero does not represent a failed read unless the function returns FALSE.

Some sort of system-implemented or monitor-implemented time-out mechanism must ensure that the ReadPort function will return within a reasonable amount of time, to avoid stalling the spooler.

It is acceptable for a language monitor to call a port monitor's ReadPort routine outside of a StartDocPort/EndDocPort pair. (Such a call might be generated by a thread checking for unsolicited status.) However, some port monitors might fail such a call, so the language monitor must be written to handle this failure.

See Also

GetPrinterDataFromPort, OpenPort, OpenPortEx, StartDocPort, EndDocPort


SetPortTimeOuts

A port monitor server DLL's SetPortTimeOuts function sets port time-out values for an open port.

BOOL
  (WINAPI *pfnSetPortTimeOuts)(
    HANDLE  hPort,
    LPCOMMTIMEOUTS  lpCTO,
    DWORD  reserved
    );

Parameters

hPort
Caller-supplied handle to the open port on which to set the time-out values.
lpCTO
Caller-supplied pointer to a COMMTIMEOUTS structure (described in the Platform SDK documentation).
reserved
Reserved for future use. Must be set to zero.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise it should return FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

A port monitor server DLL's SetPortTimeOuts function allows a language monitor to specify port time-out values for an open port. The function is optional, and only needs to be provided if the port monitor controls a port that allows modifying of port time-out values. If the function is defined, its address must be included in a MONITOR2 structure.

The function is called by pjlmon.dll, the sample language monitor, and you can write a customized language monitor that calls it. The print spooler does not call SetPortTimeOuts.

The port monitor should initialize the port's time-out values from within its OpenPort function.

See Also

MONITOR2, OpenPort


Shutdown

A print monitor's Shutdown function performs the tasks required to delete a monitor instance.

VOID
  (WINAPI *pfnShutdown) (
    HANDLE  hMonitor
    );

Parameters

hMonitor
Caller supplied monitor instance handle. This is the handle returned by the monitor's InitializePrintMonitor2 function.

Return Value

None

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Language monitors and port monitor server DLLs are required to define a Shutdown function and include the function's address in a MONITOR2 structure.

The function must return quickly. If multiple threads need to be terminated, they should just be marked for removal. Thread termination can occur after the function returns.

The Shutdown function should mark the following information as no longer valid:

  • The spooler handle received in the MONITORINIT structure
  • The registry function pointers received in the MONITORREG structure

See Also

InitializePrintMonitor2, MONITORINIT, MONITORREG


SplIsSessionZero

The SplIsSessionZero function determines whether a certain print job (print handle plus job ID) was issued in session 0.

DWORD
  SplIsSessionZero(
    IN  HANDLE  hPrinter,
    IN  DWORD  JobID,
    OUT BOOL  *pIsSessionZero
    );

Parameters

hPrinter
Is a handle to the printer.
JobID
Specifies the print job.
pIsSessionZero
Points to a memory location that is set to TRUE if the SessionID for the session is zero; otherwise this value is set to FALSE.

Return Value

On success, the SplIsSessionZero function returns ERROR_SUCCESS; otherwise this function returns a Win32 error code.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

This function is available in Windows XP and later.

See Also

SplPromptUIInUsersSession


SplPromptUIInUsersSession

The SplPromptUIInUsersSession function displays a message box in the session indicated by the printer handle and job ID.

BOOL
  SplPromptUIInUsersSession(
    IN  HANDLE  hPrinter,
    IN  DWORD  JobId,
    IN  PSHOWUIPARAMS  pUIParams,
    OUT DWORD  *pResponse
    );

Parameters

hPrinter
Is a handle to the printer.
JobID
Specifies the print job.
pUIParams
Points to a SHOWUIPARAMS structure that contains values that determine the appearance and behavior of the message box.
pResponse
Points to a memory location that contains either the user's response or the IDASYNC constant. For more information, see the Comments section.

Return Value

On success, the SplPromptUIInUsersSession function returns TRUE; otherwise it returns FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

If pUIParams ->bWait is FALSE, this function returns immediately without waiting for the user's response. In that case, *pResponse is set to IDASYNC.

This function is available in Windows XP and later operating systems.

In Windows XP this function displays a message box in the session of spoolsv.exe. The spooler runs in session 0.

See Also

SHOWUIPARAMS, SplIsSessionZero


StartDocPort

A print monitor's StartDocPort function performs the tasks required to start a print job on the specified port.

BOOL
  (WINAPI *pfnStartDocPort)(
    HANDLE  hPort,
    LPWSTR  pPrinterName,
    DWORD  JobId,
    DWORD  Level,
    LPBYTE  pDocInfo
    );

Parameters

hPort
Caller-supplied port handle.
pPrinterName
Caller-supplied pointer to a string containing the printer name.
JobId
Caller-supplied, spooler-assigned job identifier.
Level
Caller-supplied value indicating the type of structure pointed to by pDocInfo. Possible values are as follows:
Level | pDocInfo
1 | DOC_INFO_1
2 | DOC_INFO_2

pDocInfo
Caller-supplied pointer to a DOC_INFO_1 or DOC_INFO_2 structure. These structures are described in the Platform SDK documentation.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise it should return FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Language monitors and port monitor server DLLs are required to define a StartDocPort function and include the function's address in a MONITOR2 structure.

The handle received as the function's hPort argument is the port handle that the monitor's OpenPort or OpenPortEx function supplied.

A language monitor's StartDocPort function typically calls the associated port monitor's StartDocPort function.

A port monitor server DLL's StartDocPort function typically calls the CreateFile function, described in the Platform SDK documentation, to create a connection to the kernel-mode port driver.

If necessary, the port monitor should prevent other processes from using the specified port until EndDocPort is called. For example, a port monitor for a COM port must ensure that, while a spooler is sending printer data to the port, another application doesn't assume the port is connected to, say, a modem and attempt to communicate with the modem.

See Also

OpenPort, OpenPortEx, EndDocPort


WritePort

A port monitor's WritePort function writes data to a printer port.

BOOL
  (WINAPI *pfnWritePort)(
    HANDLE  hPort,
    LPBYTE  pBuffer,
    DWORD  cbBuf,
    LPDWORD  pcbWritten
    );

Parameters

hPort
Caller-supplied port handle.
pBuffer
Caller-supplied pointer to a buffer containing data to be written to the port.
cbBuf
Caller-supplied size, in bytes, of pBuffer.
pcbWritten
Caller-supplied pointer to a location to receive the number of bytes successfully written to the port.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise it should return FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Language monitors and port monitor server DLLs are required to define a WritePort function and include the function's address in a MONITOR2 structure.

The handle received as the function's hPort argument is the port handle that the monitor's OpenPort or OpenPortEx function supplied.

Typically, a language monitor's WritePort function adds language-specific commands to the data stream contained in the buffer pointed to by pBuffer, and then passes the modified data stream to the port monitor's WritePort function.

A port monitor server DLL's WritePort function usually calls WriteFile (described in the Platform SDK documentation) to send the data stream to the kernel-mode port driver.

A typical print job consists of multiple calls to WritePort. Each call can have a different cbBuf value.

The function should return the number of bytes successfully written by placing the number in the location pointed to by pcbWritten. For language monitors, this number must not include the number of extra, language-specific bytes added to the data stream.

The spooler determines the success or failure of the write operation by checking WritePort's return value, not the returned byte count. So a returned byte count of zero does not represent a failed write unless the function returns FALSE.

Some sort of system-implemented or monitor-implemented time-out mechanism must ensure that the WritePort function will return within a reasonable amount of time, to avoid stalling the spooler.

It is acceptable for a language monitor to call a port monitor's WritePort routine outside of a StartDocPort/EndDocPort pair. However, some port monitors might fail such a call, so the language monitor must be written to handle this failure.

See Also

MONITOR2, OpenPort, OpenPortEx, StartDocPort, EndDocPort


XcvClosePort

A port monitor server DLL's XcvClosePort function closes a printer port that was opened by XcvOpenPort.

BOOL
  XcvClosePort(
    HANDLE  hXcv
    );

Parameters

hXcv
Caller-supplied printer handle obtained by calling OpenPrinter (described in the Platform SDK documentation). This handle is created and returned by XcvOpenPort.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise it should return FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Port monitor server DLLs are required to define an XcvClosePort function and include its address in a MONITOR2 structure.

The spooler's ClosePrinter function calls XcvClosePort if the printer name that was specified with a previous call to the OpenPrinter function included either of the strings "XcvPort" or "XcvMonitor". For more information, see AddPortUI. For more information on the OpenPrinter and ClosePrinter functions, see the Platform SDK documentation.

The function should close the port specified by the handle, and it should make the handle invalid.

See Also

XcvOpenPort, AddPortUI


XcvDataPort

A port monitor server DLL's XcvDataPort function receives information from, and returns information to, the port monitor's UI DLL.

DWORD
  XcvDataPort(
    HANDLE  hXcv,
    LPCWSTR  pszDataName,
    PBYTE  pInputData,
    DWORD  cbInputData,
    PBYTE  pOutputData,
    DWORD  cbOutputData,
    PDWORD  pcbOutputNeeded
    );

Parameters

hXcv
Caller-supplied printer handle, obtained by calling OpenPrinter (described in the Platform SDK documentation). This handle is created and returned by the XcvOpenPort function.
pszDataName
Caller-supplied pointer to a string representing the name of the data being requested. For more information, see the following Comments section.
pInputData
Caller-supplied pointer to a buffer containing input data.
cbInputData
Caller-supplied size, in bytes, of the buffer pointed to by pInputData.
pOutputData
Caller-supplied pointer to a buffer to receive output data.
cbOutputData
Caller-supplied size, in bytes, of the buffer pointed to by pOutputData.
pcbOutputNeeded
Caller-supplied pointer to a location to receive the minimum size, in bytes, required for the buffer pointed to by pOutputData.

Return Value

If the operation succeeds, this function should return ERROR_SUCCESS. Otherwise it should return an ERROR_-prefixed Win32 error code. The print monitor UI DLL receives this value in the pdwStatus location specified for XcvData.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Port monitor server DLLs are required to define an XcvDataPort function so they can receive information from, and return information to, port monitor UI DLLs. The function's address must be included in a MONITOR2 structure.

The XcvDataPort function is called by the spooler's XcvData function. The function parameters for XcvDataPort and XcvData are almost identical. (XcvData has an additional parameter, pdwStatus, that is not present in XcvDataPort.)

The string pointed to by pszDataName specifies the operation to be performed. The function must recognize the following data name strings:

Data Name String | Operation
L"AddPort" | All information needed for adding a port has been sent. The function should perform operations necessary to add the specified port, including writing the port name in the registry under the Ports key. The pInputData parameter points to a NULL-terminated port name string. If the function returns ERROR_SUCCESS, the spooler marks the port as added. This string is specified by the print monitor UI DLL, from within its AddPortUI function.
L"DeletePort" | All information needed for deleting a port has been sent. The function should perform operations necessary to delete the specified port, including removing the port name from the registry's Ports key. The pInputData parameter points to a NULL-terminated port name string. If the function returns ERROR_SUCCESS, the spooler marks the port as deleted. This string is specified by the print monitor UI DLL, from within its DeletePortUI function.
L"MonitorUI" | The function should use pOutputData to return the name of the associated port monitor UI DLL. This string is specified by the print spooler, when an application calls the Platform SDK AddPort function.

Typically, the function is written to recognize additional, customized strings that are sent by the UI DLL from within its AddPortUI, ConfigurePortUI, and DeletePortUI functions. These strings might represent commands that request current configuration values from the server DLL, or that deliver new values. For example, your XcvDataPort function might recognize the string "GetTransmissionRetryTimeout", which your UI DLL could send to your server DLL to request the currently stored transmission retry time-out value. Or, you might define a set of strings that must be sent before "AddPort" or "DeletePort" is sent, where the strings are used to supply information identifying the port to add or delete.

For a given pszDataName string and input buffer, XcvDataPort might first be called with a cbOutputData value of zero. The function should return a required buffer size in pcbOutputNeeded, along with a return value of ERROR_INSUFFICIENT_BUFFER. The caller can use the value received in pcbOutputNeeded to allocate an output buffer of adequate size, and can then call XcvDataPort again, this time specifying the allocated buffer size in cbOutputData.

If the string pointed to by pszDataName represents an administrative operation (typically adding, deleting, or configuring a port), the XcvDataPort function should compare the granted access mask that was previously received by the XcvOpenPort function with SERVER_ACCESS_ADMINISTER. If the comparison fails, XcvDataPort should return ERROR_ACCESS_DENIED.

For a print monitor that is intended to communicate with TCPMON, see TCPMON Xcv Interface.

See Also

XcvOpenPort, XcvData, AddPortUI, ConfigurePortUI, DeletePortUI


XcvOpenPort

A port monitor server DLL's XcvOpenPort function opens a port for configuration operations.

BOOL
  XcvOpenPort(
    HANDLE  hMonitor  //MONITOR2 only
    LPCWSTR  pszObject,
    ACCESS_MASK  GrantedAccess,
    PHANDLE  phXcv
    );

Parameters

hMonitor
Caller supplied monitor instance handle. This is the handle returned by the monitor's InitializePrintMonitor2 function. (This parameter does not exist if the print monitor supports InitializePrintMonitor instead of InitializePrintMonitor2.)
pszObject
Caller-supplied pointer to a string representing the name of the port. Can be NULL, and most monitors do not need this parameter.
GrantedAccess
Caller-supplied ACCESS_MASK structure containing the access granted to the user during a print monitor UI DLL's call to the spooler's OpenPrinter function. See the following Comments section.
phXcv
Caller-supplied pointer to a location to receive a function-supplied port handle.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise it should return FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Port monitor server DLLs are required to define an XcvOpenPort function and include its address in a MONITOR2 structure.

The spooler's OpenPrinter function (described in the Platform SDK documentation) calls XcvOpenPort if the specified printer name includes either of the strings "XcvPort" or "XcvMonitor". For more information, see AddPortUI.

The XcvOpenPort function should open the port for configuration purposes. This operation might only consist of storing the input arguments for subsequent use within XcvDataPort. The function should return a handle to the stored information in the location pointed to by phXcv. This handle is returned to the caller of OpenPrinter, and subsequently received as an input argument to XcvDataPort.

The function should save the granted access mask. Later, when the server DLL's XcvDataPort function is called, the granted access should be compared with SERVER_ACCESS_ADMINISTER and if the comparison fails, XcvDataPort should return ERROR_ACCESS_DENIED.

See Also

InitializePrintMonitor2, XcvClosePort, XcvDataPort, AddPortUI


Print Monitor Structures

This section describes the structures defined by print monitors, which include language monitors and port monitors. Function prototypes are contained in winsplp.h.


MESSAGEBOX_PARAMS

The MESSAGEBOX_PARAMS structure is used by the SplPromptUIInUsersSession function to hold information about the appearance and behavior of a message box.

typedef struct {
  DWORD  cbSize;
  LPWSTR  pTitle;
  LPWSTR  pMessage;
  DWORD  Style;
  DWORD  dwTimeout;
  BOOL  bWait;
} MESSAGEBOX_PARAMS, *PMESSAGEBOX_PARAMS;

Members

cbSize
Specifies the size, in bytes, of this structure.
pTitle
Points to a null-terminated string that is used in the title bar of the message box.
pMessage
Points to a null-terminated string that contains the message to display.
Style
Specifies the contents and behavior of the message box. For a complete list of the values to which this member can be set, see the description of the MessageBox function in the Platform SDK documentation.
dwTimeout
Specifies the time, in seconds, to wait for the user's response, provided that the bWait member is TRUE.
bWait
Specifies whether the SplPromptUIInUsersSession function should wait for a user's response. If bWait is TRUE, SplPromptUIInUsersSession does not return until either the user responds or the time-out interval elapses. If dwTimeout is zero, SplPromptUIInUsersSession does not return until the user responds. If bWait is FALSE, the function returns immediately with *pResponse set to IDASYNC.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

One member of the SHOWUIPARAMS structure is a MESSAGEBOX_PARAMS structure.

This structure is available in Windows XP and later operating systems.

See Also

SplPromptUIInUsersSession, SHOWUIPARAMS


MONITOR

This MONITOR structure is obsolete and is supported only for compatibility reasons. New print monitors should implement MONITOR2 so that they can be used with print server clusters.

The MONITOR structure contains pointers to the functions defined by print monitors.

typedef struct _MONITOR {
  BOOL (WINAPI *pfnEnumPorts)
       (LPWSTR pName, DWORD Level, LPBYTE  pPorts, DWORD cbBuf,
        LPDWORD pcbNeeded, LPDWORD pcReturned);
  BOOL (WINAPI *pfnOpenPort)
       (LPWSTR pName, PHANDLE pHandle);
  BOOL (WINAPI *pfnOpenPortEx)
       (LPWSTR  pPortName, LPWSTR pPrinterName, PHANDLE pHandle,
        struct _MONITOR FAR *pMonitor);
  BOOL (WINAPI *pfnStartDocPort)
       (HANDLE hPort, LPWSTR pPrinterName, DWORD JobId,
        DWORD Level, LPBYTE  pDocInfo);
  BOOL (WINAPI *pfnWritePort)
       (HANDLE hPort, LPBYTE pBuffer, DWORD cbBuf,
        LPDWORD pcbWritten);
  BOOL (WINAPI *pfnReadPort)
       (HANDLE hPort, LPBYTE pBuffer, DWORD cbBuffer,
        LPDWORD pcbRead);
  BOOL (WINAPI *pfnEndDocPort)
       (HANDLE hPort);
  BOOL (WINAPI *pfnClosePort)
       (HANDLE hPort);
  BOOL (WINAPI *pfnAddPort)
       (LPWSTR pName, HWND hWnd, LPWSTR pMonitorName);
  BOOL (WINAPI *pfnAddPortEx)
       (LPWSTR pName, DWORD Level, LPBYTE lpBuffer,
        LPWSTR lpMonitorName);
  BOOL (WINAPI *pfnConfigurePort)
       (LPWSTR pName, HWND hWnd, LPWSTR pPortName);
  BOOL (WINAPI *pfnDeletePort)
       (LPWSTR pName, HWND hWnd, LPWSTR pPortName);
  BOOL (WINAPI *pfnGetPrinterDataFromPort)
       (HANDLE hPort, DWORD ControlID, LPWSTR pValueName,
        LPWSTR lpInBuffer, DWORD cbInBuffer, LPWSTR lpOutBuffer,
        DWORD cbOutBuffer, LPDWORD lpcbReturned);
  BOOL (WINAPI *pfnSetPortTimeOuts)
       (HANDLE hPort, LPCOMMTIMEOUTS lpCTO,
        DWORD reserved    // must be set to 0);
  BOOL (WINAPI *pfnXcvOpenPort)
       (LPCWSTR pszObject, ACCESS_MASK GrantedAccess, PHANDLE phXcv);
  DWORD (WINAPI *pfnXcvDataPort)
        (HANDLE  hXcv, LPCWSTR pszDataName, PBYTE pInputData,
         DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
         PDWORD pcbOutputNeeded);
  BOOL (WINAPI *pfnXcvClosePort)
       (HANDLE  hXcv);
} MONITOR, FAR *LPMONITOR;

Members

pfnEnumPorts
Points to the print monitor's EnumPorts function. (Port monitors only.)
pfnOpenPort
Points to the print monitor's OpenPort function.
pfnOpenPortEx
Points to the print monitor's OpenPortEx function. (Language monitors only.)
pfnStartDocPort
Points to the print monitor's StartDocPort function.
pfnWritePort
Points to the print monitor's WritePort function.
pfnReadPort
Points to the print monitor's ReadPort function.
pfnEndDocPort
Points to the print monitor's EndDocPort function.
pfnClosePort
Points to the print monitor's ClosePort function.
pfnAddPort
(Obsolete. Should be NULL.) Points to the print monitor's AddPort function.
pfnAddPortEx
(Obsolete. Should be NULL.) Points to the print monitor's AddPortEx function. (Port monitors only.)
pfnConfigurePort
(Obsolete. Should be NULL.) Points to the print monitor's ConfigurePort function.
pfnDeletePort
(Obsolete. Should be NULL.) Points to the print monitor's DeletePort function.
pfnGetPrinterDataFromPort
Points to the print monitor's GetPrinterDataFromPort function.
pfnSetPortTimeOuts
Points to the print monitor's SetPortTimeOuts function. (Port monitors only.)
pfnXcvOpenPort
Points to the print monitor's XcvOpenPort function. (Port monitors only.)
pfnXcvDataPort
Points to the print monitor's XcvDataPort function. (Port monitors only.)
pfnXcvClosePort
Points to the print monitor's XcvClosePort function. (Port monitors only.)

Headers

Declared in winsplp.h. Include winsplp.h.

See Also

MONITORUI
MONITOR2


MONITOR2

The MONITOR2 structure contains pointers to the functions defined by print monitors.

typedef struct _MONITOR2 {
  DWORD cbSize;
  BOOL (WINAPI *pfnEnumPorts)
       (HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE pPorts,
        DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned);
  BOOL (WINAPI *pfnOpenPort)
       (HANDLE hMonitor, LPWSTR pName, PHANDLE pHandle);
  BOOL (WINAPI *pfnOpenPortEx)
       (HANDLE  hMonitor, HANDLE hMonitorPort, LPWSTR pPortName,
        LPWSTR pPrinterName, PHANDLE pHandle,
        struct _MONITOR2 FAR *pMonitor2);
  BOOL (WINAPI *pfnStartDocPort)
       (HANDLE hPort, LPWSTR pPrinterName, DWORD JobId,
        DWORD Level, LPBYTE pDocInfo);
  BOOL (WINAPI *pfnWritePort)
       (HANDLE hPort, LPBYTE pBuffer, DWORD cbBuf,
        LPDWORD pcbWritten);
  BOOL (WINAPI *pfnReadPort)
       (HANDLE hPort, LPBYTE pBuffer, DWORD cbBuffer,
        LPDWORD pcbRead);
  BOOL (WINAPI *pfnEndDocPort)
       (HANDLE hPort);
  BOOL (WINAPI *pfnClosePort)
       (HANDLE  hPort);
  BOOL (WINAPI *pfnAddPort)
       (HANDLE hMonitor, LPWSTR pName, HWND hWnd,
        LPWSTR pMonitorName);
  BOOL (WINAPI *pfnAddPortEx)
       (HANDLE hMonitor, LPWSTR pName, DWORD Level,
        LPBYTE lpBuffer, LPWSTR lpMonitorName);
  BOOL (WINAPI *pfnConfigurePort)
       (HANDLE hMonitor, LPWSTR pName, HWND hWnd,
        LPWSTR pPortName);
  BOOL (WINAPI *pfnDeletePort)
       (HANDLE hMonitor, LPWSTR pName, HWND hWnd,
        LPWSTR pPortName);
  BOOL (WINAPI *pfnGetPrinterDataFromPort)
       (HANDLE hPort, DWORD ControlID, LPWSTR pValueName,
        LPWSTR lpInBuffer, DWORD cbInBuffer, LPWSTR lpOutBuffer,
        DWORD cbOutBuffer, LPDWORD lpcbReturned);
  BOOL (WINAPI *pfnSetPortTimeOuts)
       (HANDLE hPort, LPCOMMTIMEOUTS lpCTO,
        DWORD reserved    // must be set to 0);
  BOOL (WINAPI *pfnXcvOpenPort)
       (HANDLE hMonitor, LPCWSTR pszObject,
        ACCESS_MASK GrantedAccess, PHANDLE phXcv);
  DWORD (WINAPI *pfnXcvDataPort)
        (HANDLE  hXcv, LPCWSTR pszDataName, PBYTE pInputData,
         DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
         PDWORD pcbOutputNeeded);
  BOOL (WINAPI *pfnXcvClosePort)
       (HANDLE  hXcv);
  VOID (WINAPI *pfnShutdown)
       (HANDLE hMonitor);
  DWORD (WINAPI *pfnSendRecvBidiDataFromPort)
        (HANDLE  hPort, DWORD  dwAccessBit,
         LPCWSTR  pAction, PBIDI_REQUEST_CONTAINER  pReqData,
         PBIDI_RESPONSE_CONTAINER *ppResData);
} MONITOR2, *PMONITOR2, FAR *LPMONITOR2;

Members

cbSize
Specifies the size, in bytes, of the MONITOR2 structure.
pfnEnumPorts
Points to the print monitor's EnumPorts function. (Port monitors only.)
pfnOpenPort
Points to the print monitor's OpenPort function.
pfnOpenPortEx
Points to the print monitor's OpenPortEx function. (Language monitors only.)
pfnStartDocPort
Points to the print monitor's StartDocPort function.
pfnWritePort
Points to the print monitor's WritePort function.
pfnReadPort
Points to the print monitor's ReadPort function.
pfnEndDocPort
Points to the print monitor's EndDocPort function.
pfnClosePort
Points to the print monitor's ClosePort function.
pfnAddPort
(Obsolete. Should be NULL.) Points to the print monitor's AddPort function.
pfnAddPortEx
(Obsolete. Should be NULL.) Points to the print monitor's AddPortEx function. (Port monitors only.)
pfnConfigurePort
(Obsolete. Should be NULL.) Points to the print monitor's ConfigurePort function.
pfnDeletePort
(Obsolete. Should be NULL.) Points to the print monitor's DeletePort function.
pfnGetPrinterDataFromPort
Points to the print monitor's GetPrinterDataFromPort function.
pfnSetPortTimeOuts
Points to the print monitor's SetPortTimeOuts function. (Port monitors only.)
pfnXcvOpenPort
Points to the print monitor's XcvOpenPort function. (Port monitors only.)
pfnXcvDataPort
Points to the print monitor's XcvDataPort function. (Port monitors only.)
pfnXcvClosePort
Points to the print monitor's XcvClosePort function. (Port monitors only.)
pfnShutdown
Points to the print monitor's Shutdown function.
pfnSendRecvBidiDataFromPort
Points to the print monitor's SendRecvBidiDataFromPort function.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Each language monitor and each port monitor server DLL must provide a MONITOR2 structure. The monitor must supply values for all structure members, and specify the structure's address as the return value for its InitializePrintMonitor2 function.

If a function is not defined, its pointer must be NULL.

See Also

InitializePrintMonitor2, MONITORUI


MONITOREX

The MONITOREX structure is obsolete and supported for compatibility purposes only. New print monitors should implement InitializePrintMonitor2 and MONITOR2 so that they can be used with print server clusters.

The MONITOREX structure is used as the return value for a print monitor's InitializePrintMonitor function.

typedef struct _MONITOREX {
  DWORD  dwMonitorSize;
  MONITOR  Monitor;
} MONITOREX, FAR *LPMONITOREX;

Members

dwMonitorSize
Specifies the size, in bytes, of the Monitor member.
Monitor
Is a MONITOR structure.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Print monitors are responsible for filling in the MONITOREX and MONITOR structures.

See Also

MONITOR


MONITORINIT

The MONITORINIT structure is used as an input parameter to a print monitor's InitializePrintMonitor2 function.

typedef struct _MONITORINIT {
  DWORD  cbSize;
  HANDLE  hSpooler;
  HANDLE  hckRegistryRoot;
  PMONITORREG  pMonitorReg;
  BOOL  bLocal;
  LPCWSTR  pszServerName;
} MONITORINIT, *PMONITORINIT;

Members

cbSize
Size, in bytes, of the MONITORINIT structure.
hSpooler
Spooler handle, for use as input to functions identified by the MONITORREG structure.
hckRegistryRoot
Registry handle, for use as input to functions identified by the MONITORREG structure.
pMonitorReg
Points to a MONITORREG structure.
bLocal
TRUE if the monitor is being called by a local node spooler. FALSE if the monitor is being called by a cluster spooler. (Monitors can usually ignore this member.)
pszServerName
Caller-supplied pointer to a string representing a server name.

Headers

Declared in winsplp.h. Include winsplp.h.

See Also

InitializePrintMonitor2, MONITORREG


MONITORREG

The MONITORREG structure supplies print monitors with the address of registry functions to use instead of Win32 registry API functions.

typedef struct _MONITORREG {
  DWORD cbSize;
  LONG (*fpCreateKey)(
      HANDLE hcKey,
      LPCTSTR pszSubKey,
      DWORD dwOptions,
      REGSAM samDesired,
      PSECURITY_ATTRIBUTES pSecurityAttributes,
      PHANDLE phckResult,
      PDWORD pdwDisposition,
      HANDLE hSpooler
      );
  LONG (*fpOpenKey)(
      HANDLE hcKey,
      LPCTSTR pszSubKey,
      REGSAM samDesired,
      PHANDLE phkResult,
      HANDLE hSpooler
      );
  LONG (*fpCloseKey)(
      HANDLE hcKey,
      HANDLE hSpooler
      );
  LONG (*fpDeleteKey)(
      HANDLE hcKey,
      LPCTSTR pszSubKey,
      HANDLE hSpooler
      );
  LONG (*fpEnumKey)(
      HANDLE hcKey,
      DWORD dwIndex,
      LPTSTR pszName,
      PDWORD pcchName,
      PFILETIME pftLastWriteTime,
      HANDLE hSpooler
      );
  LONG (*fpQueryInfoKey)(
      HANDLE hcKey,
      PDWORD pcSubKeys,
      PDWORD pcbKey,
      PDWORD pcValues,
      PDWORD pcbValue,
      PDWORD pcbData,
      PDWORD pcbSecurityDescriptor,
      PFILETIME pftLastWriteTime,
      HANDLE hSpooler
      );
  LONG (*fpSetValue)(
      HANDLE hcKey,
      LPCTSTR pszValue,
      DWORD dwType,
      const BYTE* pData,
      DWORD cbData,
      HANDLE hSpooler
      );
  LONG (*fpDeleteValue)(
      HANDLE hcKey,
      LPCTSTR pszValue,
      HANDLE hSpooler
      );
  LONG (*fpEnumValue)(
      HANDLE hcKey,
      DWORD dwIndex,
      LPTSTR pszValue,
      PDWORD pcbValue,
      PDWORD pType,
      PBYTE pData,
      PDWORD pcbData,
      HANDLE hSpooler
      );
  LONG (*fpQueryValue)(
      HANDLE hcKey,
      LPCTSTR pszValue,
      PDWORD pType,
      PBYTE pData,
      PDWORD pcbData,
      HANDLE hSpooler
      );
} MONITORREG, *PMONITORREG;

Members

cbSize
Size, in bytes, of the MONITORREG structure.
All other structure members
Addresses of spooler functions that simulate the behavior of similarly-named cluster registry functions. See the Comments section for more information.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

The MONITORREG structure's address is supplied in a MONITORINIT structure, which is passed to a print monitor's InitializePrintMonitor2 function.

When storing port configuration information, print monitors must not explicitly call either the Win32 registry API or the cluster registry API. Instead, they must call equivalent spooler registry functions. The MONITORREG structure supplies the addresses of these functions. The following table lists each spooler registry function and its equivalent cluster registry function.

Spooler Registry Function | Equivalent Cluster Registry Function
CreateKey | ClusterRegCreateKey
OpenKey | ClusterRegOpenKey
CloseKey | ClusterRegCloseKey
DeleteKey | ClusterRegDeleteKey
EnumKey | ClusterRegEnumKey
QueryInfoKey | ClusterRegQueryInfoKey
SetValue | ClusterRegSetValue
DeleteValue | ClusterRegDeleteValue
EnumValue | ClusterRegEnumValue
QueryValue | ClusterRegQueryValue

Input and output parameters for these spooler functions match the parameters of the equivalent cluster registry functions (described in the Platform SDK documentation), with the following exceptions:

  • Each spooler registry function requires an hSpooler input parameter. This is the spooler handle received in the MONITORINIT structure.
  • The spooler registry functions use HANDLE and PHANDLE parameter types instead of the HKEY and PHKEY types used by the cluster registry functions. Monitors receive the handle of the root registry location in the hckRegistryRoot member of the MONITORINIT structure.

See Also

MONITORINIT, InitializePrintMonitor2


MONITORUI

The MONITORUI structure contains pointers to the functions within a port monitor UI DLL that the print spooler calls.

typedef struct _MONITORUI {
  DWORD dwMonitorUISize;
  BOOL (WINAPI *pfnAddPortUI)
       (PCWSTR pszServer,
       HWND hWnd,
       PCWSTR pszMonitorNameIn,
       PWSTR *ppszPortNameOut);
  BOOL (WINAPI *pfnConfigurePortUI)
       (PCWSTR pName,
       HWND hWnd,
       PCWSTR pPortName);
  BOOL (WINAPI *pfnDeletePortUI)
       (PCWSTR pszServer,
       HWND hWnd,
       PCWSTR pszPortName);
} MONITORUI, FAR *PMONITORUI;

Members

dwMonitorUISize
Size, in bytes, of the MONITORUI structure.
pfnAddPortUI
Address of the port monitor UI DLL's AddPortUI function.
pfnConfigurePortUI
Address of the port monitor UI DLL's ConfigurePortUI function.
pfnDeletePortUI
Address of the port monitor UI DLL's DeletePortUI function.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

All structure members must be initialized by the port monitor UI DLL. The structure's address is passed to the print spooler as the return value for the InitializePrintMonitorUI function.

See Also

InitializePrintMonitorUI


SHOWUIPARAMS

The SplPromptUIInUsersSession function uses the SHOWUIPARAMS structure to hold information about the appearance and behavior of a message box.

typedef struct {
  UI_TYPE  UIType;
  union {
     MESSAGEBOX_PARAMS  MessageBoxParams;
  };
} SHOWUIPARAMS, *PSHOWUIPARAMS;

Members

UIType
Specifies the type of user interface element. This member can be set to a single value: kMessageBox.
MessageBoxParams
Specifies a MESSAGEBOX_PARAMS structure that contains the information about the message box.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

This structure is available in Windows XP and later operating systems.

See Also

SplPromptUIInUsersSession, MESSAGEBOX_PARAMS


TCPMON Xcv Structures

This section describes the structures that are defined for use in TCPMON Xcv communication. For more information, see TCPMON Xcv Interface.


CONFIG_INFO_DATA_1

The XcvData function uses a CONFIG_INFO_DATA_1 structure when it obtains configuration data for a particular port.

typedef struct _CONFIG_INFO_DATA_1 {
    BYTE  Reserved[128];
    DWORD  dwVersion;
} CONFIG_INFO_DATA_1, *PCONFIG_INFO_DATA_1;

Members

Reserved
Is reserved for system use. This member should be set to a zero-length string.
dwVersion
Specifies the version of the PORT_DATA_1 structure (currently equal to 1) that will contain the configuration information.

Headers

Declared in tcpxcv.h. Include tcpxcv.h.

Comments

When the XcvData function is called to obtain port configuration information, its pInputData parameter must be set with the address of a CONFIG_INFO_DATA_1 structure, and its pOutputData parameter must be set with the address of a PORT_DATA_1 structure, which will be filled in when the function returns. Set this function's pszDataName parameter to the string L"GetConfigInfo".

See TCPMON Xcv Interface for more information.

See Also

XcvData, PORT_DATA_1


DELETE_PORT_DATA_1

The XcvData function uses a DELETE_PORT_DATA_1 structure when it deletes a port.

typedef struct _DELETE_PORT_DATA_1 {
    WCHAR  psztPortName[MAX_PORTNAME_LEN];
    BYTE  Reserved[98];
    DWORD  dwVersion;
    DWORD  dwReserved;
} DELETE_PORT_DATA_1, *PDELETE_PORT_DATA_1;

Members

psztPortName
Specifies the name of the port to be deleted. The MAX_PORTNAME_LEN constant is defined in tcpxcv.h.
Reserved
Is reserved for system use.
dwVersion
Specifies the version of this structure, which is currently 1.
dwReserved
Is obsolete, and must be set to 0.

Headers

Declared in tcpxcv.h. Include tcpxcv.h.

Comments

When the XcvData function is called to delete a port, its pInputData parameter must be set with the address of a DELETE_PORT_DATA_1 structure. Set this function's pszDataName parameter to the string L"DeletePort".

See TCPMON Xcv Interface for more information.

See Also

XcvData


PORT_DATA_1

The XcvData function uses a PORT_DATA_1 structure when it adds a port or configures an existing port.

typedef struct _PORT_DATA_1 {
    WCHAR  sztPortName[MAX_PORTNAME_LEN];
    DWORD  dwVersion;
    DWORD  dwProtocol;
    DWORD  cbSize;
    DWORD  dwReserved;
    WCHAR  sztHostAddress[MAX_NETWORKNAME_LEN];
    WCHAR  sztSNMPCommunity[MAX_SNMP_COMMUNITY_STR_LEN];
    DWORD  dwDoubleSpool;
    WCHAR  sztQueue[MAX_QUEUENAME_LEN];
    WCHAR  sztIPAddress[MAX_IPADDR_STR_LEN];
    BYTE   Reserved[540];
    DWORD  dwPortNumber;
    DWORD  dwSNMPEnabled;
    DWORD  dwSNMPDevIndex;
} PORT_DATA_1, *PPORT_DATA_1;

Members

sztPortName
Specifies the name of the port. The MAX_PORTNAME_LEN constant is defined in tcpxcv.h.
dwVersion
Specifies the version number of the PORT_DATA_1 structure, which is currently 1.
dwProtocol
Specifies the protocol to use for the port. This value can be either PROTOCOL_RAWTCP_TYPE or PROTOCOL_LPR_TYPE, constants that are defined in tcpxcv.h.
cbSize
Specifies the size, in bytes of this structure. Use sizeof(PORT_DATA_1) for this value.
dwReserved
Reserved, must be set to zero.
sztHostAddress
Specifies the IP Address or host name of the printer. The MAX_NETWORKNAME_LEN constant is defined in tcpxcv.h.
sztSNMPCommunity
Specifies the SNMP community name of the printer. The MAX_SNMP_COMMUNITY_STR_LEN constant is defined in tcpxcv.h.
dwDoubleSpool
If TRUE, indicates that double spooling is enabled. If FALSE, double spooling is disabled.
sztQueue
Specifies the LPR queue name. The MAX_QUEUENAME_LEN constant is defined in tcpxcv.h.
sztIPAddress
Specifies the IP address of the printer. The MAX_IPADDR_STR_LEN constant is defined in tcpxcv.h.
Reserved
Is reserved for system use.
dwPortNumber
Specifies the port number of the device.
dwSNMPEnabled
If TRUE, indicates that the device supports Simple Network Management Protocol (SNMP).
dwSNMPDevIndex
Specifies the SNMP device index.

Headers

Declared in tcpxcv.h. Include tcpxcv.h.

Comments

When the XcvData function is called either to add a port or configure an existing port, its pOutputData parameter must be set with the address of a PORT_DATA_1 structure, which will be filled in when the function returns. To add a port, set this function's pszDataName parameter to the string L"AddPort". To configure a port, set this parameter to L"ConfigPort".

See TCPMON Xcv Interface for more information.

See Also

XcvData


Exported Spooler Functions

This section describes functions provided by the print spooler. Function prototypes are defined in winsplp.h.


AppendPrinterNotifyInfoData

The print spooler's AppendPrinterNotifyInfoData function adds the contents of a specified PRINTER_NOTIFY_INFO_DATA structure to a specified PRINTER_NOTIFY_INFO structure.

BOOL
  AppendPrinterNotifyInfoData(
    PPRINTER_NOTIFY_INFO  pInfoDest,
    PPRINTER_NOTIFY_INFO_DATA  pInfoDataSrc,
    DWORD  fdwFlags
    );

Parameters

pInfoDest
Caller-supplied pointer to a PRINTER_NOTIFY_INFO structure (defined in the Platform SDK documentation).
pInfoDataSrc
Caller-supplied pointer to a PRINTER_NOTIFY_INFO_DATA structure (defined in the Platform SDK documentation).
fdwFlags
Caller-supplied flags. The following flag is defined.
Flag Definition
PRINTER_NOTIFY_INFO_DATA_COMPACT
If set, the function examines the Type, Field, and Id members of the supplied PRINTER_NOTIFY_INFO_DATA structure. If they all match an existing element of the PRINTER_NOTIFY_INFO_DATA structure array, the existing element is overwritten with the supplied element. If a match is not found, the function adds the specified structure to the end of the array.

Return Value

If the operation succeeds, the function returns TRUE. Otherwise the function returns FALSE. The caller can obtain an error code by calling GetLastError (described in the Platform SDK documentation).

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

A print provider's RefreshPrinterChangeNotification function should call AppendPrinterNotifyInfoData as often as necessary to populate a PRINTER_NOTIFY_INFO_DATA structure array, after first calling RouterAllocPrinterNotifyInfo to allocate storage for the array and its associated PRINTER_NOTIFY_INFO structure.

Based on whether the PRINTER_NOTIFY_INFO_DATA_COMPACT flag is set, the function either appends the specified PRINTER_NOTIFY_INFO_DATA structure to the end of the structure array or overwrites an existing array element. If the structure is appended, the function increments the PRINTER_NOTIFY_INFO structure's Count member.

If AppendPrinterNotifyInfoData detects that the PRINTER_NOTIFY_INFO_DISCARDED flag is set in the specified PRINTER_NOTIFY_INFO structure, the function clears all PRINTER_NOTIFY_INFO_DATA structures and sets the error code to ERROR_OUT_OF_STRUCTURES.

If NULL is specified for pInfoDataSrc, AppendPrinterNotifyInfoData sets the PRINTER_NOTIFY_INFO_DISCARDED flag in the specified PRINTER_NOTIFY_INFO structure, clears all PRINTER_NOTIFY_INFO_DATA structures, and sets the error code to ERROR_OUT_OF_STRUCTURES.

(For more information about the PRINTER_NOTIFY_INFO_DISCARDED flag, see the description of FindNextPrinterChangeNotification in the Platform SDK documentation.)

For additional information, see Supporting Printer Change Notifications.

See Also

RefreshPrinterChangeNotification, RouterAllocPrinterNotifyInfo


ImpersonatePrinterClient

ImpersonatePrinterClient resumes impersonation of the client, completing the operation begun by RevertToPrinterSelf.

BOOL
 ImpersonatePrinterClient(
    HANDLE  hToken
    );

Parameters

hToken
Caller-supplied handle to a thread. This parameter must have been previously returned by a call to RevertToPrinterSelf.

Return Value

If the operation succeeds, the function returns TRUE. Otherwise the function returns FALSE. The caller can obtain an error code by calling GetLastError (described in the Platform SDK documentation).

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

This function must be called after a successful call to RevertToPrinterSelf. It resumes impersonation of the client and cleans up the thread handle.

See Also

RevertToPrinterSelf


PartialReplyPrinterChangeNotification

The print spooler's PartialReplyPrinterChangeNotification function allows a print provider to update the spooler's database of printer changes associated with a notification handle.

BOOL
  PartialReplyPrinterChangeNotification(
    HANDLE  hNotify,
    PPRINTER_NOTIFY_INFO_DATA  pInfoDataSrc
    );

Parameters

hNotify
Caller-supplied handle. This handle must have been previously received as the hNotify input to the print provider's FindFirstPrinterChangeNotification function.
pInfoDataSrc
Caller-supplied pointer to a PRINTER_NOTIFY_INFO_DATA structure (described in the Platform SDK documentation). Can be NULL (see the following Comments section).

Return Value

If the operation succeeds, the function returns TRUE. Otherwise the function returns FALSE. The caller can obtain an error code by calling GetLastError.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

For the specified notification handle, the spooler's PartialReplyPrinterChangeNotification function adds the contents of the specified PRINTER_NOTIFY_INFO_DATA structure to the array within the spooler's stored PRINTER_NOTIFY_INFO structure. (These structures are described in the Platform SDK documentation.)

Calling PartialReplyPrinterChangeNotification does not cause the spooler to notify the application that changes have occurred. If the print provider's FindFirstPrinterChangeNotification function did not set the PRINTER_NOTIFY_STATUS_POLL flag, the provider must call ReplyPrinterChangeNotification to cause the application to be notified.

If pInfoDataSrc is NULL, all stored information associated with the specified handle is deleted from the spooler. The function accomplishes this deletion by freeing all buffers associated with pBuf members of PRINTER_NOTIFY_INFO_DATA structures belonging to the specified handle. The function then sets the PRINTER_NOTIFY_INFO_DISCARDED flag in the stored PRINTER_NOTIFY_INFO structure.

For additional information, see Supporting Printer Change Notifications.

See Also

FindFirstPrinterChangeNotification, ReplyPrinterChangeNotification


ReplyPrinterChangeNotification

The print spooler's ReplyPrinterChangeNotification function allows a print provider to update the spooler's database of print queue events associated with a notification handle, and to notify the client that print queue events have occurred.

BOOL
  ReplyPrinterChangeNotification(
    HANDLE  hNotify,
    DWORD  fdwFlags,
    PDWORD  pdwResult,
    PVOID  pPrinterNotifyInfo
    );

Parameters

hNotify
Caller-supplied handle. This handle must have been previously received as the hNotify input to the print provider's FindFirstPrinterChangeNotification function.
fdwFlags
One or more caller-supplied PRINTER_CHANGE_-prefixed flags, listed in the Platform SDK documentation's description of FindNextPrinterChangeNotification.
pdwResult
Optional. If not NULL, it receives spooler-supplied PRINTER_NOTIFY_INFO-prefixed flags indicating results of updating the supplied information.
pPrinterNotifyInfo
Optional. Caller-supplieid address of a PRINTER_NOTIFY_INFO structure (described in the Platform SDK documentation). Can be NULL if no new notification information is being added.

Return Value

If the operation succeeds, the function returns TRUE. Otherwise the function returns FALSE. The caller can obtain an error code by calling GetLastError.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Print providers that do not support polling (see FindFirstPrinterChangeNotification) must notify the spooler of the occurrence of any events represented by the PRINTER_CHANGE_-prefixed flags received by the provider's FindFirstPrinterChangeNotification function. When an event occurs, the print provider can call ReplyPrinterChangeNotification to inform the spooler of the event and to supply information associated with the event. The spooler keeps track of this event information, for each notification handle, and delivers the information to an application when the application calls FindNextPrinterChangeNotification (described in the Platform SDK documentation).

When a print provider calls ReplyPrinterChangeNotification, it must identify the event that has occurred by setting a PRINTER_CHANGE_-prefixed flag in fwdFlags or by using pPrinterNotifyInfo to return a PRINTER_NOTIFY_INFO structure. (Use the flags listed in the Platform SDK documentation's description of FindNextPrinterChangeNotification – not the flags listed in the Platform SDK documentation's description of FindFirstPrinterChangeNotification.)

Calling ReplyPrinterChangeNotification causes the spooler to signal the client application that a print queue event has occurred. This happens even if the provider supplies NULL for pPrinterNotifyInfo. To update the spooler's record of print queue changes without causing the client to be notified, use PartialReplyPrinterChangeNotification. It is common to call PartialReplyPrinterChangeNotification several times to update the spooler's database, then to call ReplyPrinterChangeNotification to notify the client that changes have occurred.

For additional information, see Supporting Printer Change Notifications.

See Also

FindFirstPrinterChangeNotification, PartialReplyPrinterChangeNotification,


RevertToPrinterSelf

When RevertToPrinterSelf is called on an impersonating thread, it returns the token for the thread that is being impersonated.

HANDLE
   RevertToPrinterSelf(
    VOID
    );

Return Value

If the operation succeeds, the function returns the token of the impersonated thread. If the current thread is not impersonating another thread, this function returns NULL.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

RevertToPrinterSelf should be called when a component needs access to resources from the local system context, such as the registry. The local system context is the security context (the collection of settings that define the security behavior of a process or thread) of the system process. The system process is the process that runs in the logon session that is created for the local system account when the operating system boots.

If RevertToPrinterSelf returns a non-NULL value, ImpersonatePrinterClient must be called with the return value to complete the operation and clean up the thread handle.

See Also

ImpersonatePrinterClient


RouterAllocBidiResponseContainer

RouterAllocBidiResponseContainer allocates a BIDI_RESPONSE_CONTAINER structure containing a list of bidi responses. The bidi response list is an array of BIDI_RESPONSE_DATA structures.

PBIDI_RESPONSE_CONTAINER
  RouterAllocBidiResponseContainer(
    IN DWORD  cSize
    );

Parameters

cSize
Specifies the number of BIDI_RESPONSE_DATA structures to be allocated.

Return Value

RouterAllocBidiResponseContainer returns a pointer to the allocated structure, on success. If the function fails to allocate the structure, the caller can obtain the error code from GetLastError (described in the Platform SDK documentation).

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

This function is available in Windows XP and later.

When the memory allocated by this function is no longer needed, use RouterFreeBidiResponseContainer.

See Also

BIDI_RESPONSE_DATA, BIDI_RESPONSE_CONTAINER, RouterFreeBidiResponseContainer


RouterAllocBidiMem

RouterAllocBidiMem allocates a block of memory of a specified size. This function is used by the port monitor to allocate memory for strings and binary objects.

PVOID RouterAllocBidiMem(
  IN size_t  NumBytes
  );

Parameters

NumBytes
Specifies the size, in bytes, of the block of memory to be allocated.

Return Value

RouterAllocBidiMem returns a pointer to the block of memory if successful. If the function fails, the caller can obtain the error code by calling GetLastError (described in the Platform SDK documentation).

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

This function is available in Windows XP and later.

When the memory allocated by this function is no longer needed, it can be returned by a call to RouterFreeBidiMem.

See Also

RouterFreeBidiMem


RouterAllocPrinterNotifyInfo

The print spooler's RouterAllocPrinterNotifyInfo function allocates a PRINTER_NOTIFY_INFO structure and an array of PRINTER_NOTIFY_INFO_DATA structures. (These structures are described in the Platform SDK documentation.)

PPRINTER_NOTIFY_INFO
  RouterAllocPrinterNotifyInfo(
    DWORD  cPrinterNotifyInfoData
    );

Parameters

cPrinterNotifyInfoData
Caller-supplied number specifying size of the PRINTER_NOTIFY_INFO_DATA structure array to be allocated.

Return Value

The function returns a pointer to the allocated PRINTER_NOTIFY_INFO structure.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Print providers should call RouterAllocPrinterNotifyInfo to allocate the PRINTER_NOTIFY_INFO structure and the PRINTER_NOTIFY_INFO_DATA structure array that the provider's RefreshPrinterChangeNotification function must supply.

The RouterAllocPrinterNotifyInfo function initializes the PRINTER_NOTIFY_INFO structure's Version member to the current version of the spooler's notification implementation. It initializes the structure's Flags and Count members to zero, regardless of the number specified for cPrinterNotifyInfoData.

Print providers should call AppendPrinterNotifyInfoData to fill in members of the PRINTER_NOTIFY_INFO_DATA structure array.

If RefreshPrinterChangeNotification executes successfully and returns the allocated structures to the caller, you should assume that the caller will deallocate structure memory. However, if RefreshPrinterChangeNotification encounters an error it should call RouterFreePrinterNotifyInfo to deallocate the memory.

For additional information, see Supporting Printer Change Notifications.

See Also

RefreshPrinterChangeNotification, AppendPrinterNotifyInfoData, RouterFreePrinterNotifyInfo


RouterFreeBidiMem

RouterFreeBidiMem frees a block of memory that was previously allocated by RouterAllocBidiMem.

VOID
  RouterFreeBidiMem(
    IN PVOID  pMemPointer
    );

Parameters

pMemPointer
Points to the memory to be freed.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

This function is available in Windows XP and later.

See Also

RouterAllocBidiMem


RouterFreeBidiResponseContainer

RouterFreeBidiResponseContainer frees a BIDI_RESPONSE_CONTAINER structure previously allocated by RouterAllocBidiResponseContainer.

DWORD
  RouterFreeBidiResponseContainer(
    IN PBIDI_RESPONSE_CONTAINER  pData
    );

Parameters

pData
Points to the BIDI_RESPONSE_CONTAINER structure to be freed.

Return Value

RouterFreeBidiResponseContainer normally returns ERROR_SUCCESS, unless it throws an exception. In that case it returns an appropriate error code.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

This function is available in Windows XP and later.

See Also

BIDI_RESPONSE_CONTAINER, RouterAllocBidiResponseContainer


RouterFreePrinterNotifyInfo

The print spooler's RouterFreePrinterNotifyInfo function deallocates a specified PRINTER_NOTIFY_INFO structure and its associated PRINTER_NOTIFY_INFO_DATA structure array. (These structures are described in the Platform SDK documentation.)

BOOL
  RouterFreePrinterNotifyInfo(
    PPRINTER_NOTIFY_INFO  pInfo
    );

Parameters

pInfo
Caller-supplied pointer to a PRINTER_NOTIFY_INFO structure (described in the Platform SDK documentation).

Return Value

If the operation succeeds, the function returns TRUE. Otherwise the function returns FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

A print provider's RefreshPrinterChangeNotification function should call RouterFreePrinterNotifyInfo to deallocate structures previously allocated by RouterAllocPrinterNotifyInfo, but only if RefreshPrinterChangeNotification encounters a error. If RefreshPrinterChangeNotification succeeds, you should assume that the client application will deallocate the structures.

Besides deallocating the specified PRINTER_NOTIFY_INFO structure and its associated PRINTER_NOTIFY_INFO_DATA structure array, the function also deallocates buffer space pointed to by pBuf in any element of the PRINTER_NOTIFY_INFO_DATA structure array.

For additional information, see Supporting Printer Change Notifications.

See Also

RefreshPrinterChangeNotification, RouterAllocPrinterNotifyInfo


Bidi Functions, Structures, and Enumerations

This section contains definitions of the functions, structures, and enumerations used in bidirectional (bidi) requests and responses. The bidi functions are declared in winsplp.h. The bidi structures and enumerations are defined in winspool.h. All are available in Windows XP and later.

Bidi Functions

Bidi Structures

Bidi Enumerations


Bidi Functions

A print provider optionally can implement the SendRecvBidiData function to support communication between an application and a printer or a print server. A port monitor/language monitor optionally can implement the SendRecvBidiDataFromPort function for the same purpose.


SendRecvBidiData

A print provider DLL's SendRecvBidiData function supports bidirectional communication between an application and a printer or print server.

DWORD
  SendRecvBidiData(
    HANDLE  hPrinter,
    LPCWSTR  pAction,
    PBIDI_REQUEST_CONTAINER  pReqData,
    PBIDI_RESPONSE_CONTAINER  *ppResData
    );

Parameters

hPrinter
Specifies a caller-supplied printer handle.
pAction
Points to a caller-supplied Unicode string that contains the requested action. The value of this parameter should be one of the BIDI_ACTION_XXX constants described in the Platform SDK documentation.
pReqData
Points to a caller-supplied BIDI_REQUEST_CONTAINER structure that contains the bidi request data.
ppResData
Is a caller-supplied pointer to a memory location that will receive the address of a caller-allocated BIDI_RESPONSE_CONTAINER structure. This structure contains the bidi response.

Return Value

If the operation succeeds, the SendRecvBidiData function returns ERROR_SUCCESS. Otherwise, it returns a Win32 error code.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

This function is available in Windows XP and later.

Print providers optionally can define a SendRecvBidiData function and include the function's address in the fpSendRecvBidiData member of a Windows XP PRINTPROVIDOR structure.

The function's hPrinter parameter uses the printer handle supplied by the OpenPrinter function. Applications access bidi APIs by way of the IBidiSpooler and IBidiRequest COM interfaces. When an application calls IBidiSpooler—>BidiDevice, the COM implementation calls the OpenPrinter function to obtain a printer handle. Then, when the application calls IBidiSpooler—>SendRecvData, the COM implementation calls the print provider's SendRecvBidiData function. For more information about these COM interfaces and OpenPrinter, see the Platform SDK documentation.

Typically, in a network print provider DLL, SendRecvBidiData calls the network APIs to obtain bidirectional data from the printer and then sends the response back to the caller.

A language monitor can call a print provider's SendRecvBidiData function outside a StartDocPrinter/EndDocPrinter function pair (both are described in the Platform SDK documentation). A print provider DLL's SendRecvBidiData function must be able to handle such calls.

See Also

BIDI_REQUEST_CONTAINER, BIDI_REQUEST_CONTAINER, SendRecvBidiDataFromPort, PRINTPROVIDOR


SendRecvBidiDataFromPort

The SendRecvBidiDataFromPort function, which can be implemented in either a language monitor server DLL or a port monitor server DLL, supports bidirectional communication between an application and a printer or print server.

DWORD WINAPI
  SendRecvBidiDataFromPort(
    HANDLE  hPort,
    DWORD  dwAccessBit,
    LPCWSTR  pAction,
    PBIDI_REQUEST_CONTAINER  pReqData,
    PBIDI_RESPONSE_CONTAINER  *ppResData
    );

Parameters

hPort
Specifies a caller-supplied port handle.
dwAccessBit
Caller-supplied ACCESS_MASK structure (defined in the Platform SDK documentation) containing the access granted to the user during a call to the spooler's OpenPrinter function. For more information about ACCESS_MASK and OpenPrinter, see the Platform SDK documentation.
pAction
Points to a caller-supplied Unicode string that contains the requested action. The value of this parameter should be one of the BIDI_ACTION_XXX constants described in the Platform SDK documentation.
pReqData
Points to a BIDI_REQUEST_CONTAINER structure that contains the bidi request data.
ppResData
Points to a memory location that will receive the address of a BIDI_RESPONSE_CONTAINER structure that contains the bidi response.

Return Value

If the operation succeeds, the SendRecvBidiDataFromPort function returns ERROR_SUCCESS. Otherwise, it returns a Win32 error code.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

This function is available in Windows XP and later.

Language and port monitors optionally can define a SendRecvBidiDataFromPort function and include the function's address in the pfnSendRecvBidiDataFromPort member of a Windows XP MONITOR2 structure.

The function's hPort parameter receives the port handle supplied by the monitor's OpenPort or OpenPortEx function.

Typically, a language monitor's SendRecvBidiDataFromPort function calls the associated port monitor's SendRecvBidiDataFromPort function, and returns the resulting buffer contents to the caller.

Additionally, a language monitor can create a separate thread that calls the port monitor's SendRecvBidiDataFromPort function to check for unsolicited status information or additional bidi information. If such an operation succeeds, the language monitor should return the status information to the spooler by a call to SetPort (described in the Platform SDK documentation).

In a port monitor server's DLL for locally connected devices, the SendRecvBidiDataFromPort function can call the DeviceIoControl or ReadFile functions to obtain data from the kernel-mode port driver. In a port monitor DLL for network-attached devices, the SendRecvBidiDataFromPort function calls network APIs to obtain bidirectional data from the printer and then sends the response back to the caller. For more information about DeviceIoControl and ReadFile, see the Platform SDK documentation.

Both language and port monitors can define SendRecvBidiDataFromPort functions and place their addresses in MONITOR2 structures. If a language monitor's SendRecvBidiDataFromPort function is defined, the spooler will always call it, whether or not a port monitor's SendRecvBidiDataFromPort function is defined.

In order to avoid stalling the spooler, SendRecvBidiDataFromPort should return within the time-out interval indicated in the lpCTO parameter in the call to the SetPortTimeOuts function, if the port monitor/language monitor supports this function.

A language monitor can call a port monitor's SendRecvBidiDataFromPort function outside a StartDocPort/EndDocPort function pair, or simultaneously with other port monitor calls, such as WritePort or ReadPort, but in a different thread. (Such a call might be generated by a thread checking for unsolicited status.) However, some port monitors might fail such a call, so the language monitor must be written to handle this failure. The spooler might also call a language monitor's SendRecvBidiDataFromPort routine outside a StartDocPort/EndDocPort pair or simultaneously with other calls, but in a different thread. A language monitor must be able to handle such calls. For more information about StartDocPort and EndDocPort, see the Platform SDK documentation.

The SendRecvBidiDataFromPort function should compare the granted access against PRINTER_ACCESS_ADMINISTER (described in the Platform SDK documentation) or any other ACCESS bit that the print provider intends to enforce. If the comparison fails, SendRecvBidiDataFromPort should return ERROR_ACCESS_DENIED.

See Also

BIDI_REQUEST_CONTAINER, BIDI_REQUEST_CONTAINER, SendRecvBidiData, MONITOR2


Bidi Structures

A print provider or port monitor/language monitor can use the structures listed in this section to support bidirectional (bidi) communication between an application and a printer or print server. An application can send and receive bidi requests, and a printer or print server can respond to requests or send its own requests, to which the application responds.


BIDI_DATA

The BIDI_DATA structure is used to store the values of a bidi schema.

typedef struct _BIDI_DATA {
  DWORD  dwBidiType;
  union {
     BOOL  bData;
     INT  iData;
     LPWSTR  sData;
     FLOAT  fData;
     BINARY_CONTAINER  biData;
  } u;
} BIDI_DATA, *PBIDI_DATA, *LPBIDI_DATA;

Members

dwBidiType
Specifies the type of data in a bidi request as one of the values listed in the BIDI_TYPE enumeration. The value of this member determines which one of the following five union members is valid.
bData
Specifies the Boolean value. This member is valid only if the value of dwBidiType is BIDI_BOOL, one of the BIDI_TYPE enumerators.
iData
Specifies the integer value. This member is valid only if the value of dwBidiType is BIDI_INT, one of the BIDI_TYPE enumerators.
sData
Points to a memory location at which the first byte of the string is stored. This member is valid only if the value of dwBidiType is BIDI_STRING or BIDI_TEXT, two of the BIDI_TYPE enumerators.
fData
Specifies the floating-point value. This member is valid only if the value of dwBidiType is BIDI_FLOAT, one of the BIDI_TYPE enumerators.
biData
Specifies a BINARY_CONTAINER structure that holds the binary data. This member is valid only if the value of dwBidiType is BIDI_BLOB, one of the BIDI_TYPE enumerators.
u
Is a union consisting of the preceding five members.

Headers

Declared in winspool.h. Include winspool.h.

Comments

This structure is available in Windows XP and later.

The BIDI_REQUEST_DATA and BIDI_RESPONSE_DATA structures each have a member of this type, which holds the bidi data for the request or response.

See Also

BINARY_CONTAINER, BIDI_TYPE, BIDI_REQUEST_DATA, BIDI_RESPONSE_DATA


BIDI_REQUEST_CONTAINER

The BIDI_REQUEST_CONTAINER structure is a container for a list of bidi requests.

typedef struct _BIDI_REQUEST_CONTAINER {
  DWORD  Version;
  DWORD  Flags;
  DWORD  Count;
  BIDI_REQUEST_DATA aData[1];
} BIDI_REQUEST_CONTAINER, *PBIDI_REQUEST_CONTAINER, *LPBIDI_REQUEST_CONTAINER;

Members

Version
Specifies the version of the bidi API Schema, which is currently 1.
Flags
Is a set of flags reserved for system use. This must be zero.
Count
Specifies the number of bidi requests in the aData member. A container can contain zero or more requests, although a value of zero is valid only if the action is BIDI_ACTION_ENUM_SCHEMA.
aData
Is an array of BIDI_REQUEST_DATA structures, each holding a single bidi request.

Headers

Declared in winspool.h. Include winspool.h.

Comments

This structure is available in Windows XP and later.

Even though the aData member of this structure is an array with only a single array element, aData[0] should be thought of as the first element of an array of (possibly) an arbitrarily large size.

See Also

BIDI_REQUEST_DATA


BIDI_REQUEST_DATA

The BIDI_REQUEST_DATA structure holds a single bidi request.

typedef struct _BIDI_REQUEST_DATA {
  DWORD  dwReqNumber;
  LPWSTR  pSchema;
  BIDI_DATA  data;
} BIDI_REQUEST_DATA, *PBIDI_REQUEST_DATA, *LPBIDI_REQUEST_DATA;

Members

dwReqNumber
Specifies the index of the request, which is used to match a response with a request in a multi-request operation.
pSchema
Points to a memory location containing the first byte of the schema string.
data
Specifies a BIDI_DATA structure containing the data associated with the schema.

Headers

Declared in winspool.h. Include winspool.h.

Comments

This structure is available in Windows XP and later.

See Also

BIDI_DATA, BIDI_REQUEST_CONTAINER


BIDI_RESPONSE_CONTAINER

The BIDI_RESPONSE_CONTAINER structure is a container for a list of bidi responses.

typedef struct _BIDI_RESPONSE_CONTAINER {
  DWORD  Version;
  DWORD  Flags;
  DWORD  Count;
  BIDI_RESPONSE_DATA aData[1];
} BIDI_RESPONSE_CONTAINER, *PBIDI_RESPONSE_CONTAINER, *LPBIDI_RESPONSE_CONTAINER;

Members

Version
Specifies the version of the bidi API Schema, which is currently 1.
Flags
Is a set of flags reserved for system use. This must be zero.
Count
Specifies the number of responses in the aData member.
aData
Is an array of BIDI_RESPONSE_DATA structures, each containing a single bidi response.

Headers

Declared in winspool.h. Include winspool.h.

Comments

This structure is available in Windows XP and later.

Even though the aData member of this structure is an array with only a single array element, aData[0] should be thought of as the first element of an array of (possibly) an arbitrarily large size.

The spooler's RouterAllocBidiResponseContainer function allocates the memory needed for this structure, which is then used to hold an array of BIDI_RESPONSE_DATA structures. When a BIDI_RESPONSE_CONTAINER structure is no longer needed, it should be freed by a call to RouterFreeBidiResponseContainer.

See Also

BIDI_RESPONSE_DATA, RouterAllocBidiResponseContainer, RouterFreeBidiResponseContainer


BIDI_RESPONSE_DATA

The BIDI_RESPONSE_DATA structure holds a single bidi response.

typedef struct _BIDI_RESPONSE_DATA {
  DWORD  dwResult;
  DWORD  dwReqNumber;
  LPWSTR  pSchema;
  BIDI_DATA  data;
} BIDI_RESPONSE_DATA, *PBIDI_RESPONSE_DATA, *LPBIDI_RESPONSE_DATA;

Members

dwResult
Specifies the last error of the response.
dwReqNumber
Specifies a number used to match a response and a request in a multi-request operation.
pSchema
Points to a memory location containing the first byte of the schema string.
data
Specifies a BIDI_DATA structure containing the data associated with the schema.

Headers

Declared in winspool.h. Include winspool.h.

Comments

This structure is available in Windows XP and later.

The spooler's RouterAllocBidiResponseContainer function is used to allocate the memory needed for a BIDI_RESPONSE_CONTAINER structure, which is then used to hold an array of BIDI_RESPONSE_DATA structures. When a BIDI_RESPONSE_CONTAINER structure is no longer needed, it should be freed by a call to RouterFreeBidiResponseContainer.

When the bidi action is BIDI_ACTION_GETALL, the dwReqNumber member holds the ID of the matching request in the BIDI_REQUEST_CONTAINER structure, the pSchema member points to the schema string associated with the data, and the data member holds the bidi data. If the bidi action is BIDI_ACTION_ENUM_SCHEMA, pSchema should be set to NULL, and the data member will hold the supported schema string. In this case, data.dwDataType is set to BIDI_TEXT (a BIDI_DATA enumerator). For information about the BIDI_ACTION_Xxx constants, see IBidiSpooler::MultiSendRecv in the Platform SDK documentation.

See Also

BIDI_RESPONSE_CONTAINER, RouterAllocBidiResponseContainer, RouterFreeBidiResponseContainer


BINARY_CONTAINER

The BINARY_CONTAINER structure is a container for binary data.

typedef struct _BINARY_CONTAINER {
  DWORD  cbBuf;
  LPBYTE  pData;
} BINARY_CONTAINER, *PBINARY_CONTAINER;

Members

cbBuf
Specifies the number of bytes of binary data in the pData member.
pData
Points to a buffer that contains the binary data.

Headers

Declared in winspool.h. Include winspool.h.

Comments

This structure is available in Windows XP and later.

The BINARY_CONTAINER structure is used in a BIDI_DATA structure when the bidi data consists of binary data, as opposed to integer, float, or string data.

See Also

BIDI_DATA


Bidi Enumerations

This section describes the bidi enumerations, which consist of the following:

BIDI_TYPE


BIDI_TYPE

The BIDI_TYPE enumeration lists the possible values of data transferred in a bidi operation.

typedef enum {
  BIDI_NULL = 0,
  BIDI_INT = 1,
  BIDI_FLOAT = 2,
  BIDI_BOOL = 3,
  BIDI_STRING = 4,
  BIDI_TEXT = 5,
  BIDI_ENUM = 6,
  BIDI_BLOB = 7
} BIDI_TYPE;

Enumerators

BIDI_NULL
Indicates that there is no data.
BIDI_INT
Indicates that the bidi data is an integer.
BIDI_FLOAT
Indicates that the bidi data is a floating-point number.
BIDI_BOOL
Indicates that the bidi data is either TRUE or FALSE.
BIDI_STRING
Indicates that the bidi data is a Unicode character string.
BIDI_TEXT
Indicates that the bidi data is a non-localizable Unicode string.
BIDI_ENUM
Indicates that the bidi data is enumeration data in the form of a Unicode string.
BIDI_BLOB
Indicates that the bidi data is binary data.

Headers

Declared in winspool.h. Include winspool.h.

Comments

This enumeration is available in Windows XP and later.

See Also

Built on Wednesday, July 11, 2001


Printer Driver Functions and Structures

This section describes the functions and structures defined by Windows® 2000 and later printer drivers. The following subsections are provided:

Printer Interface DLL Functions

Printer Interface DLL Structures

Printer Graphics DLL Functions

Printer Graphics DLL Structures

User-Mode Rendering DLL Functions

Unidrv and Pscript Interfaces

Obsolete Printer Driver Functions


Printer Interface DLL Functions

This section describes the functions defined by a printer driver's printer interface DLL. Function prototypes are provided in winddiui.h.


DevQueryPrintEx

A printer interface DLL's DevQueryPrintEx function determines if a specified print job is compatible with the printer's current configuration and can therefore be printed.

BOOL
  DevQueryPrintEx(
    PDEVQUERYPRINT_INFO  pDQPInfo
    );

Parameters

pDQPInfo
Caller-supplied pointer to a DEVQUERYPRINT_INFO structure.

Return Value

If the print job can be printed, the function should return TRUE; otherwise it should return FALSE.

Headers

Declared in winddiui.h. Include winddiui.h.

Comments

Printer interface DLLs must define a DevQueryPrintEx function. The function is called by the print spooler if the Hold Mismatched Documents option is checked on the Advanced page of the printer's property sheet. If the function returns TRUE, the spooler queues the print job for printing. Otherwise the job is held, under the assumption that the printer will eventually be reconfigured so the job can print.

The received DEVQUERYPRINT_INFO structure points to a DEVMODE structure describing the printer characteristics required by the print job. The DevQueryPrintEx function should first verify that the size and version members of the received DEVMODE structure are compatible with the driver. Then it should determine if the supplied DEVMODE contents are compatible with the current printer configuration.

If the job can be printed, the function should just return TRUE. If the job should be held until later, the function should return FALSE after supplying a displayable text string (in the buffer pointed to by the DEVQUERYPRINT_INFO structure's pszErrorStr member) describing the reason the job cannot be printed.

Displayable text strings should be defined as string resources in a resource file.


DrvConvertDevMode

A printer interface DLL's DrvConvertDevMode function is responsible for converting a printer's DEVMODE structure from one version to another.

BOOL
  DrvConvertDevMode(
    LPTSTR  pPrinterName,
    PDEVMODE  pdmIn,
    PDEVMODE  pdmOut,
    PLONG  pcbNeeded,
    DWORD  fMode
    );

Parameters

pPrinterName
Caller-supplied pointer to a printer name string.
pdmIn
Caller-supplied pointer to an input DEVMODE structure. If fMode is CDM_DRIVER_DEFAULT, this pointer is NULL.
pdmOut
Caller-supplied pointer to a buffer to receive an output DEVMODE structure. If fMode is CDM_CONVERT the buffer contains, on input, a valid DEVMODE structure indicating the target driver version.
pcbNeeded
Caller-supplied pointer to the size, in bytes, of the buffer pointed to by pdmOut. On output, the printer interface DLL should overwrite the received size value with the actual size of the converted DEVMODE structure. If the received buffer is too small, the printer interface DLL should overwrite the received size value with the required buffer size.
fMode
Caller-supplied bit flag indicating the type of operation to be performed. This can be one of the flags in the following table.
Flag Definition
CDM_CONVERT
The function should convert the contents of the input DEVMODE structure (pointed to by pdmIn) into a new DEVMODE structure, and place the result in the DEVMODE structure pointed to by pdmOut. The initial contents of the received output DEVMODE structure (pointed to by pdmOut) should be used to determine the output version.
CDM_CONVERT351
The function should convert the contents of the input DEVMODE structure (pointed to by pdmIn), creating an output DEVMODE structure that is compatible with Windows NT 3.51, and place the result in the DEVMODE structure pointed to by pdmOut.

If the driver does not support a DEVMODE structure for Windows NT 3.51, the function should convert the input DEVMODE to the current version.
CDM_DRIVER_DEFAULT
The function should copy the current version of its default DEVMODE structure to the buffer pointed to by pdmOut.

Return Value

If the operation succeeds, the function should return TRUE; othewise, it should call SetLastError to set an error code, and return FALSE.

Headers

Declared in winddiui.h. Include winddiui.h.

Comments

In a client/server environment, a client might be running one version of the operating system or printer driver while the server (spooler) is running another, which means a printer's DEVMODE structure definition might be inconsistent between the client and server. The DrvConvertDevMode function must be capable of performing conversions from one version of the printer's DEVMODE structure to another.

When converting from one DEVMODE version to another, both public and private DEVMODE members must be included.

The printer name pointed to by pPrinterName can be used as an input argument to the OpenPrinter function, which can be called to obtain stored default values when the CDM_DRIVER_DEFAULT flag is received.

The function should verify that both pdmIn and pdmOut (if applicable) point to valid DEVMODE structures. If they don't, the function should call SetLastError(ERROR_INVALID_PARAMETER) and return FALSE. If the output DEVMODE size specified by pcbNeeded is too small, the driver should overwrite the size value supplied by pcbNeeded with the required buffer size, call SetLastError(ERROR_INSUFFICIENT_BUFFER), and return FALSE.

The DrvConvertDevMode function runs in the spooler's context and must therefore not display a user interface.


DrvDeviceCapabilities

A printer interface DLL's DrvDeviceCapabilities function returns requested information about a printer's capabilities.

DWORD
  DrvDeviceCapabilities(
    HANDLE  hPrinter,
    PWSTR  pDeviceName,
    WORD  iDevCap,
    VOID  *pvOutput,
    PDEVMODE  pDevMode
    );

Parameters

hPrinter
Caller-supplied printer handle.
pDeviceName
Caller-supplied pointer to a printer name string.
iDevCap
Caller-supplied bit flag indicating the information being requested. This can be one of the flags listed in the following table. (Flags are defined in wingdi.h.)
Flag | Definition
DC_BINADJUST | Not used for NT-based operating systems.
DC_BINNAMES The pvOutput parameter points to a buffer, which the function should fill with an array of string buffers, each 24 characters in length. Each array element should contain a NULL-terminated string representing a name for a paper source bin.

The function's return value should be the number of elements in the returned array.

If pvOutput is NULL, the function should just return the number of array elements required.
DC_BINS The pvOutput parameter points to a buffer, which the function should fill with a WORD array. Each array element should contain a DMBIN-prefixed constant (or customized value) representing a supported paper source bin.

The function's return value should be the number of elements in the returned array.

If pvOutput is NULL, the function should just return the number of array elements required.
DC_COLLATE The pvOutput parameter is not used.

The function's return value should be 1 if the printer supports collating; otherwise, the return value should be zero.
DC_COLORDEVICE The pvOutput parameter is not used.

The function's return value should be 1 if the printer supports color printing; otherwise, the return value should be zero.
DC_COPIES The pvOutput parameter is not used.

The function's return value should be the maximum number of copies the printer can support.
DC_DATATYPE_PRODUCED | Not used for NT-based operating systems.
DC_DRIVER The pvOutput parameter is not used.

The function's return value should be the dmDriverVersion member of the driver's internal DEVMODE structure.
DC_DUPLEX The pvOutput parameter is not used.

The function's return value should be 1 if the printer supports duplex printing; otherwise, the return value should be zero.
DC_EMF_COMPLIANT | Not used for NT-based operating systems.
DC_ENUMRESOLUTIONS The pvOutput parameter points to a buffer, which the function should fill with a LONG array. For each resolution supported by the printer, the function should return two longwords (one for the x dimension and one for the y dimension) of the resolution, in dots per inch.

The function's return value should be the number of resolutions supported.

If pvOutput is NULL, the function should just return the number of resolutions supported.
DC_EXTRA The pvOutput parameter is not used.

The function's return value should be the dmDriverExtra member of the driver's internal DEVMODE structure.
DC_FIELDS The pvOutput parameter is not used.

The function's return value should be the dmFields member of the driver's internal DEVMODE structure.
DC_FILEDEPENDENCIES The pvOutput parameter points to a buffer, which the function should fill with an array of string buffers, each 64 characters in length. Each array element should contain a NULL-terminated string representing a name for a file that must be installed with the driver.

The function's return value should be the number of elements in the returned array.

If pvOutput is NULL, the function should just return the number of array elements required.
DC_MANUFACTURER | Not used for NT-based operating systems.
DC_MAXEXTENT The pvOutput parameter is not used.

The function should return a POINT structure. The structure should contain the maximum allowable values for the dmPaperWidth (x dimension) and dmPaperLength (y dimension) members of the printer's DEVMODE structure.
DC_MEDIAREADY The pvOutput parameter points to a buffer, which the function should fill with an array of string buffers, each 64 characters in length. Each array element should contain a NULL-terminated string representing a name for a paper form that is available for use.

The function's return value should be the number of elements in the returned array.

If pvOutput is NULL, the function should just return the number of array elements required.
DC_MEDIATYPENAMES The pvOutput parameter points to a buffer, which the function should fill with an array of string buffers, each 64 characters in length. Each array element should contain a NULL-terminated string representing a name for a supported media type.

The function's return value should be the number of elements in the returned array.

If pvOutput is NULL, the function should simply return the number of array elements required.
DC_MEDIATYPES The pvOutput parameter points to a buffer, which the function should fill with a DWORD array. Each array element should contain a DMMEDIA-prefixed constant (see the DEVMODE structure) or customized value representing a supported media type.

The function's return value should be the number of elements in the returned array.

If pvOutput is NULL, the function should simply return the number of array elements required.
DC_MINEXTENT The pvOutput parameter is not used.

The function should return a POINT structure. The structure should contain the minimum allowable values for the dmPaperWidth (x dimension) and dmPaperLength (y dimension) members of the printer's DEVMODE structure.
DC_MODEL | Not used for NT-based operating systems.
DC_NUP The pvOutput parameter points to a buffer, which the function should fill with a DWORD array. Each array element should contain an integer representing an N-up option (that is, each integer should represent a supported number of document pages per physical page).

The function's return value should be the number of elements in the returned array.

If pvOutput is NULL, the function should just return the number of array elements required.
DC_ORIENTATION The pvOutput parameter is not used.

The function's return value should be the number of degrees of rotation required to produce landscape orientation from portrait orientation. A value of zero indicates landscape orientation is not supported.
DC_PAPERNAMES The pvOutput parameter points to a buffer, which the function should fill with an array of string buffers, each 64 characters in length. Each array element should contain a NULL-terminated string representing a name for a paper form.

The function's return value should be the number of elements in the returned array.

If pvOutput is NULL, the function should just return the number of array elements required.
DC_PAPERS The pvOutput parameter points to a buffer, which the function should fill with a WORD array. Each array element should contain a DMPAPER-prefixed constant (or customized value) representing a supported paper form.

The function's return value should be the number of elements in the returned array.

If pvOutput is NULL, the function should just return the number of array elements required.
DC_PAPERSIZE The pvOutput parameter points to a buffer, which the function should fill with a POINT array. Each array element should contain the x and y dimensions of a form's paper size, in 0.1 mm units, in portrait orientation.

The function's return value should be the number of elements in the returned array.

If pvOutput is NULL, the function should just return the number of array elements required.
DC_PERSONALITY The pvOutput parameter points to a buffer, which the function should fill with an array of string buffers, each 32 characters in length. Each array element should contain a NULL-terminated string representing a printer description language supported by the printer.

The function's return value should be the number of elements in the returned array.

If pvOutput is NULL, the function should just return the number of array elements required.
DC_PRINTERMEM The pvOutput parameter is not used.

The function's return value should be an integer representing the amount of available printer memory, in kilobytes.
DC_PRINTRATE The pvOutput parameter is not used.

The function's return value should be an integer representing the print rate, in the units specified for DC_PRINTRATEUNIT.
DC_PRINTRATEPPM The pvOutput parameter is not used.

The function's return value should be an integer representing the print rate, in pages per minute.
DC_PRINTRATEUNIT The pvOutput parameter is not used.

The function's return value should identify the units used for specifying the value returned for DC_PRINTRATE. One of the following constants must be specified:

PRINTRATEUNIT_PPM – pages/min.
PRINTRATEUNIT_CPS – chars./sec.
PRINTRATEUNIT_LPM – lines/min.
PRINTRATEUNIT_IPM – inches/min.
DC_SIZE The pvOutput parameter is not used.

The function's return value should be the dmSize member of the driver's internal DEVMODE structure.
DC_STAPLE The pvOutput parameter is not used.

The function's return value should be TRUE if the printer supports stapling, and FALSE if the printer does not support stapling.
DC_TRUETYPE The pvOutput parameter is not used.

The function's return value can be zero, one, or more of the following flags:

DCTT_BITMAP: The device can print TrueType fonts as graphics.
DCTT_DOWNLOAD: The device can accept downloaded TrueType fonts.
DCTT_SUBDEV: The device can substitute device fonts for TrueType fonts.
DC_VERSION The pvOutput parameter is not used.

The function's return value should be the dmSpecVersion member of the driver's internal DEVMODE structure.

pvOutput
Caller-supplied pointer to a buffer to receive function-supplied information. The buffer's use is dependent on the value received for the iDevCap parameter.
pDevMode
Caller-supplied pointer to a DEVMODE structure describing the current print job characteristics. If NULL, the function should use the driver's internal default DEVMODE structure.

Return Value

The function's return value is dependent on the value received for the iDevCap parameter. If the received iDevCap value represents a capability that the driver does not support, or if an error is encountered, the function should return GDI_ERROR.

Headers

Declared in winddiui.h. Include winddiui.h.


DrvDevicePropertySheets

A printer interface DLL's DrvDevicePropertySheets function is responsible for creating property sheet pages that describe a printer's properties.

LONG
  DrvDevicePropertySheets(
    PPROPSHEETUI_INFO  pPSUIInfo,
    LPARAM  lParam
    );

Parameters

pPSUIInfo
Caller-supplied pointer to a PROPSHEETUI_INFO structure.
lParam
Caller-supplied integer value that is dependent on the contents of the Reason member of the PROPSHEETUI_INFO structure, as listed in the following table.
Reason Value Definition of lParam
PROPSHEETUI_REASON_INIT
Pointer to a DEVICEPROPERTYHEADER structure.
All other reason values
See the description of the lParam parameter for the PFNPROPSHEETUI function type.

(The DEVICEPROPERTYHEADER structure's address is contained in the lParamInit member of the PROPSHEETUI_INFO structure.)

Return Value

See the Return Value section in the description of the PFNPROPSHEETUI function type.

Headers

Declared in winddiui.h. Include winddiui.h.

Comments

All printer interface DLLs must provide a DrvDevicePropertySheets function, which is defined using the PFNPROPSHEETUI function type. The function's purpose is to call the ComPropSheet function, provided by CPSUI, to specify a property sheet page containing user-modifiable properties for the printer.

The function should perform operations as described for the PFNPROPSHEETUI function type. The function should create the printer's Device Settings property sheet page (see the pDlgPage member of the COMPROPSHEETUI structure).

Printer device settings should be stored in the registry. If a user with administrator privilege modifies options on the Device Settings page, the DrvDevicePropertySheets function should write the updated values to the registry by calling SetPrinterData (described in the Platform SDK documentation).

See Also

DrvDocumentPropertySheets
IPrintOemUI::DevicePropertySheets


DrvDocumentEvent

A printer interface DLL's DrvDocumentEvent function can handle certain events associated with printing a document.

INT
  DrvDocumentEvent(
    HANDLE  hPrinter,
    HDC  hdc,
    int  iEsc,
    ULONG  cbIn,
    PVOID  pvIn,
    ULONG  cbOut,
    PVOID  pvOut
    );

Parameters

hPrinter
Caller-supplied printer handle.
hdc
Caller-supplied device context handle, generated by a CreateDC (described in the Platform SDK documentation) call. This is zero if iEsc is set to DOCUMENTEVENT_CREATEDCPRE.
iEsc
Caller-supplied escape code identifying the event to be handled. This parameter can be one of the following integer constants. See the Platform SDK documentation for descriptions of the functions listed in the Event column.
iEsc Constant | Event
DOCUMENTEVENT_ABORTDOC | GDI is about to process a call to its AbortDoc function.
DOCUMENTEVENT_CREATEDCPOST GDI has just processed a call to its CreateDC or CreateIC function.
This escape code should not be used unless there has been a previous call to DrvDocumentEvent with iEsc set to DOCUMENTEVENT_CREATEDCPRE.
DOCUMENTEVENT_CREATEDCPRE | GDI is about to process a call to its CreateDC or CreateIC function.
DOCUMENTEVENT_DELETEDC | GDI is about to process a call to its DeleteDC function.
DOCUMENTEVENT_ENDDOCPOST | GDI has just processed a call to its EndDoc function.
DOCUMENTEVENT_ENDDOCPRE
or DOCUMENTEVENT_ENDDOC 		GDI is about to process a call to its EndDoc function.
DOCUMENTEVENT_ENDPAGE | GDI is about to process a call to its EndPage function.
DOCUMENTEVENT_ESCAPE | GDI is about to process a call to its ExtEscape function.
DOCUMENTEVENT_QUERYFILTER | The DOCUMENTEVENT_QUERYFILTER event represents an opportunity for the spooler to query the driver for a list of the DOCUMENTEVENT_XXX events to which the driver will respond. This event is issued just prior to a call to DrvDocumentEvent that passes the DOCUMENTEVENT_CREATEDCPRE event.
DOCUMENTEVENT_RESETDCPOST GDI has just processed a call to its ResetDC function.
This escape code should not be used unless there has been a previous call to DrvDocumentEvent with iEsc set to DOCUMENTEVENT_RESETDCPRE.
DOCUMENTEVENT_RESETDCPRE | GDI is about to process a call to its ResetDC function.
DOCUMENTEVENT_STARTDOCPOST | GDI has just processed a call to its StartDoc function.
DOCUMENTEVENT_STARTDOCPRE
or DOCUMENTEVENT_STARTDOC 		GDI is about to process a call to its StartDoc function.
DOCUMENTEVENT_STARTPAGE | GDI is about to process a call to its StartPage function.

cbIn
Caller-supplied size, in bytes, of the buffer pointed to by pvIn.
pvIn
Caller-supplied pointer, the use of which is dependent on the value supplied for iEsc, as follows:
iEsc Constant | pvIn Contents
DOCUMENTEVENT_ABORTDOC | Not used.
DOCUMENTEVENT_CREATEDCPOST | pvIn contains the address of a pointer to the DEVMODE structure specified in the pvOut parameter in a previous call to this function, for which the iEsc parameter was set to DOCUMENTEVENT_CREATEDCPRE.
DOCUMENTEVENT_CREATEDCPRE | pvIn points to a DOCEVENT_CREATEDCPRE structure.
DOCUMENTEVENT_DELETEDC | Not used.
DOCUMENTEVENT_ENDDOCPOST | Not used.
DOCUMENTEVENT_ENDDOCPRE
or DOCUMENTEVENT_ENDDOC 		Not used.
DOCUMENTEVENT_ENDPAGE | Not used.
DOCUMENTEVENT_ESCAPE | pvIn points to a DOCEVENT_ESCAPE structure.
DOCUMENTEVENT_QUERYFILTER | Same as for DOCUMENTEVENT_CREATEDCPRE.
DOCUMENTEVENT_RESETDCPOST | pvIn contains the address of a pointer to the DEVMODE structure specified in the pvOut parameter in a previous call to this function, for which the iEsc parameter was set to DOCUMENTEVENT_RESETDCPRE.
DOCUMENTEVENT_RESETDCPRE | pvIn contains the address of a pointer to the DEVMODE structure supplied by the caller of ResetDC (described in the Platform SDK documentation).
DOCUMENTEVENT_STARTDOCPOST | pvIn points to a LONG that specifies the print job identifier returned by StartDoc (described in the Platform SDK documentation).
DOCUMENTEVENT_STARTDOCPRE
or DOCUMENTEVENT_STARTDOC 		pvIn contains the address of a pointer to a DOCINFO structure supplied by the caller of StartDoc (both described in the Platform SDK documentation).
DOCUMENTEVENT_STARTPAGE | Not used.

cbOut
If iEsc is DOCUMENTEVENT_ESCAPE:
Function-supplied value that will be used as the cbOutput parameter for ExtEscape.
If iEsc is DOCUMENTEVENT_QUERYFILTER:
Caller-supplied size, in bytes, of the buffer pointer to by pvOut.
For all other iEsc values:
Not used.
pvOut
Function-supplied pointer to an output buffer, the use of which is dependent on the value supplied for iEsc, as follows. CreateDC, ExtEscape, and ResetDC are described in the Platform SDK documentation.
iEsc Constant | pvOut Contents
DOCUMENTEVENT_CREATEDCPRE | Pointer to a driver-supplied DEVMODE structure, which GDI uses instead of the one supplied by the CreateDC caller. (If NULL, GDI uses the caller-supplied structure.)
DOCUMENTEVENT_ESCAPE | Buffer pointer that will be used as the lpszOutData parameter for ExtEscape.
DOCUMENTEVENT_QUERYFILTER | Caller-supplied pointer to buffer containing a DOCEVENT_FILTER structure.
DOCUMENTEVENT_RESETDCPRE | Pointer to a driver-supplied DEVMODE structure, which GDI uses instead of the one supplied by the ResetDC caller. (If NULL, GDI uses the caller-supplied structure.)
All other iEsc values | Not used.

Return Value

The function's return value is dependent on the escape supplied for iEsc. For some escape codes, the return value is not used (see the second following table). If the function supplies a return value, it must be one of the following:

Return Value | Definition
DOCUMENTEVENT_FAILURE | The driver supports the escape code identified by iEsc, but a failure occurred.
DOCUMENTEVENT_SUCCESS | The driver successfully handled the escape code identified by iEsc.
DOCUMENTEVENT_UNSUPPORTED | The driver does not support the escape code identified by iEsc.

The following table indicates the escape codes that require a return value, and explains the meaning of the DOCUMENTEVENT_SUCCESS, DOCUMENTEVENT_FAILURE and DOCUMENTEVENT_UNSUPPORTED return codes.

iEsc Constant | Meaning of Return Value
DOCUMENTEVENT_ABORTDOC | Not used.
DOCUMENTEVENT_CREATEDCPOST | Not used.
DOCUMENTEVENT_CREATEDCPRE | DOCUMENTEVENT_FAILURE – GDI does not create the device context or information context, and provides a return value of 0 for CreateDC or CreateIC (both described in the Platform SDK documentation).
DOCUMENTEVENT_DELETEDC | Not used.
DOCUMENTEVENT_ENDDOCPOST | Not used.
DOCUMENTEVENT_ENDDOCPRE or DOCUMENTEVENT_ENDDOC | Not used.
DOCUMENTEVENT_ENDPAGE | Not used.
DOCUMENTEVENT_ESCAPE | Not used.
DOCUMENTEVENT_QUERYFILTER | See Comments.
DOCUMENTEVENT_RESETDCPOST | Not used.
DOCUMENTEVENT_RESETDCPRE | DOCUMENTEVENT_FAILURE – GDI does not reset the device context, and provides a return value of 0 for ResetDC (described in the Platform SDK documentation).
DOCUMENTEVENT_STARTDOCPOST | DOCUMENTEVENT_FAILURE – GDI calls AbortDoc to stop the document, and then provides a return value of SP_ERROR for StartDoc (both described in the Platform SDK documentation).
DOCUMENTEVENT_STARTDOCPRE or DOCUMENTEVENT_STARTDOC | DOCUMENTEVENT_FAILURE – GDI does not start the document, and provides a return value of SP_ERROR for StartDoc (described in the Platform SDK documentation).
DOCUMENTEVENT_STARTPAGE | DOCUMENTEVENT_FAILURE – GDI does not start the page, and provides a return value of SP_ERROR for StartPage (described in the Platform SDK documentation).

Headers

Declared in winddiui.h. Include winddiui.h.

Comments

A printer interface DLL can optionally provide a DrvDocumentEvent function to perform pre- or post-processing of GDI calls associated with rendering a document. Calls to the DrvDocumentEvent function are made from the user-mode GDI client, when an application makes calls into the GDI client.

For an iEsc value of DOCUMENTEVENT_QUERYFILTER, the spooler can interpret a DOCUMENTEVENT_SUCCESS value returned by DrvDocumentEvent in two ways, depending on whether the driver modified certain members of the DOCEVENT_FILTER structure. (The pvOut parameter points to this structure.) When the spooler allocates memory for a structure of this type, it initializes two members of this structure, cElementsReturned and cElementsNeeded, to known values. After DrvDocumentEvent returns, the spooler determines whether the values of these members have changed, and uses that information to interpret the DrvDocumentEvent return value. The following table summarizes this situation.

Return Value | Status of cElementsReturned, cElementsNeeded | Meaning
DOCUMENTEVENT_SUCCESS | Driver made no change to either member. | The spooler interprets this return value as equivalent to DOCUMENTEVENT_UNSUPPORTED. The spooler is unable to retrieve the event filter from the driver, so it will persist in calling DrvDocumentEvent for all events.
DOCUMENTEVENT_SUCCESS | Driver wrote to one or both members. | The spooler accepts this return value without interpretation. If the driver wrote to only one of cElementsNeeded and cElementsReturned, the spooler considers the unchanged member to have a value of zero. The spooler filters out all events listed in the aDocEventCall member of DOCEVENT_FILTER.
DOCUMENTEVENT_UNSUPPORTED | Not applicable | The driver does not support DOCUMENTEVENT_QUERYFILTER. The spooler is unable to retrieve the event filter from the driver, so it will persist in calling DrvDocumentEvent for all events.
DOCUMENTEVENT_FAILURE | Not applicable | The driver supports DOCUMENTEVENT_QUERYFILTER, but encountered an internal error. The spooler is unable to retrieve the event filter from the driver, so it will persist in calling DrvDocumentEvent for all events.

If the escape code name has no suffix or is suffixed with PRE, the GDI client calls DrvDocumentEvent just prior to calling the kernel-mode GDI rendering engine. If the escape code name is suffixed with POST, the GDI client calls DrvDocumentEvent just after the kernel-mode GDI rendering engine returns.

If the escape code supplied in the iEsc parameter is DOCUMENTEVENT_CREATEDCPRE, the following rules apply:

  • If the job is being sent directly to the printer without spooling, pvIn —> pszDevice points to the printer name. (See the DOCEVENT_CREATEDCPRE structure for more information.)
  • If the job is being spooled, pvIn —> pszDevice points to the printer port name.

The DrvDocumentEvent function executes in the context of the user-mode caller of the GDI client function. When EMF spooling is disabled, the function can display a user interface. For example, the DrvDocumentEvent function for a FAX driver might display a dialog box to the user before GDI's StartDoc function (described in the Platform SDK documentation) is processed.

See Also

DOCEVENT_FILTER, DOCEVENT_CREATEDCPRE, DOCEVENT_ESCAPE


DrvDocumentPropertySheets

A printer interface DLL's DrvDocumentPropertySheets function is responsible for creating property sheet pages that describe a print document's properties.

LONG
  DrvDocumentPropertySheets(
    PPROPSHEETUI_INFO  pPSUIInfo,
    LPARAM  lParam
    );

Parameters

pPSUIInfo
Caller-supplied pointer to a PROPSHEETUI_INFO structure. Can be NULL (see the following Comments section).
lParam
Caller-supplied integer value that is dependent on the contents of the Reason member of the PROPSHEETUI_INFO structure, as listed in the following table.
Reason Value Definition of lParam
PROPSHEETUI_REASON_INIT
Pointer to a DOCUMENTPROPERTYHEADER structure.
All other reason values
See the description of the lParam parameter for the PFNPROPSHEETUI function type.

(The DOCUMENTPROPERTYHEADER structure's address is contained in the lParamInit member of the PROPSHEETUI_INFO structure.)

Return Value

See the Return Value section in the description of the PFNPROPSHEETUI function type.

Headers

Declared in winddiui.h. Include winddiui.h.

Comments

All printer interface DLLs must provide a DrvDocumentPropertySheets function, which is defined using the PFNPROPSHEETUI function type. The function's purpose is to call the ComPropSheet function, provided by CPSUI, to specify property sheet pages containing user-modifiable properties for print documents.

If the value received for the pPSUIInfo parameter is not NULL, the NT-based operating system print spooler is calling the function indirectly, through CPSUI. The following rules apply:

  • The function should perform operations as described for the PFNPROPSHEETUI function type.
  • Flags in the fMode member of the DOCUMENTPROPERTYHEADER structure indicate which property sheet pages to display and whether the user should be allowed to modify a document's properties. The only flags that might be set are DM_IN_PROMPT (or DM_PROMPT), DM_ADVANCED, DM_NOPERMISSION, and DM_OUT_BUFFER (or DM_COPY).

If the value received for the pPSUIInfo parameter is NULL, the print spooler is calling the function directly, without going through CPSUI. In this case, the following rules apply:

  • If the fMode member of the DOCUMENTPROPERTYHEADER structure is zero, the function should just return the total size of the printer's DEVMODE structure, including public and private structure members, in the DOCUMENTPROPERTYHEADER structure's cbOut member.
  • If the fMode member of the DOCUMENTPROPERTYHEADER structure is not zero, the function should perform the operations indicated by the fMode flags. The only flags that might be set are DM_IN_BUFFER (or DM_MODIFY), and DM_OUT_BUFFER (or DM_COPY).

See Also

DrvDevicePropertySheets
IPrintOemUI::DocumentPropertySheets


DrvDriverEvent

The print spooler calls a printer interface DLL's DrvDriverEvent function when the spooler processes driver-specific events that might require action by the printer driver.

BOOL
  DrvDriverEvent(
    DWORD  dwDriverEvent,
    DWORD  dwLevel,
    LPBYTE  pDriverInfo,
    LPARAM  lParam
    );

Parameters

dwDriverEvent
Caller-supplied bit flag indicating the event that has occurred. Valid flags are listed in the following table.
Flag | Definition
DRIVER_EVENT_DELETE | The driver is being removed.
DRIVER_EVENT_INITIALIZE | The driver has just been installed.

dwLevel
Caller-supplied value indicating the type of structure pointed to by the pDriverInfo parameter, as indicated in the following table.
dwLevel Value | Structure pointed to by pDriverInfo
1 | DRIVER_INFO_1
2 | DRIVER_INFO_2
3 | DRIVER_INFO_3

The DRIVER_INFO_N structures are described in the Platform SDK documentation.

pDriverInfo
Caller-supplied pointer to a structure whose type is identified by the dwLevel parameter.
lParam
Caller-supplied flags. See the following Comments section.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise it should return FALSE.

Headers

Declared in winddiui.h. Include winddiui.h.

Comments

The optional DrvDriverEvent function is called by the spooler's AddPrinterDriverEx and DeletePrinterDriverEx functions, which are described in the Platform SDK documentation.

The function's purpose is to allow a printer driver's printer interface DLL to perform operations needed when the driver is installed or removed. A typical operation for this function to perform is to create or remove extra driver-specific files that are not specified as dependent files in a printer .inf file.

If dwDriverEvent is DRIVER_EVENT_DELETE, the lparam parameter contains the flags that were specified for the DeletePrinterDriverEx function's dwDeleteFlag parameter. The lparam parameter is not used if dwDriverEvent is DRIVER_EVENT_INITIALIZE.

Because the DrvDriverEvent function is called in the context of the print spooler, it cannot display a user interface.


DrvPrinterEvent

A printer interface DLL's DrvPrinterEvent function is called by the print spooler when processing printer-specific events that might require action by the printer driver.

BOOL
  DrvPrinterEvent(
    LPWSTR  pPrinterName,
    INT  DriverEvent,
    DWORD  Flags,
    LPARAM  lParam
    );

Parameters

pPrinterName
Caller-supplied pointer to a NULL-terminated printer name string. The string format can be \\Machine\PrinterName to specify a remote printer, or PrinterName to specify a local printer.
DriverEvent
Caller-supplied event code identifying the event. The following event codes are defined:
Event Code | Definition
PRINTER_EVENT_ADD_CONNECTION | The spooler has just finished processing a call to its AddPrinterConnection function (described in the Platform SDK documentation), which allows a client user to connect to a previously created remote printer.
PRINTER_EVENT_ATTRIBUTES_CHANGED The attribute bits for a printer have changed. In response to an application's call to the SetPrinter function (described in the Platform SDK documentation), the spooler calls the printer driver's DrvPrinterEvent function, passing the event code in the call. When this event code is used, the lParam parameter points to a PRINTER_EVENT_ATTRIBUTES_INFO structure that describes the old and the new attributes.

One use for this event code is to inform the driver through the user interface about whether the printer is shared or unshared.
PRINTER_EVENT_CACHE_DELETE | The spooler is deleting the client's file cache.
PRINTER_EVENT_CACHE_REFRESH | The spooler is updating the client's cached files.
PRINTER_EVENT_DELETE_CONNECTION | The spooler has just finished processing a call to its DeletePrinterConnection function (described in the Platform SDK documentation), which allows a client user to remove a printer connection.
PRINTER_EVENT_DELETE | The spooler has just finished processing a call to its DeletePrinter function (described in the Platform SDK documentation), which allows an administrator to delete a printer instance.
PRINTER_EVENT_INITIALIZE | The spooler has just finished processing a call to its AddPrinter function, which allows an administrator to make a printer available on a server, or its SetPrinter function (both described in the Platform SDK documentation), which allows an administrator to modify a printer's state.

Flags
Caller-supplied bit flag, defined as follows:
Value | Definition
PRINTER_EVENT_FLAG_NO_UI | If set, the function must not display a user interface. During the installation of a print processor, print monitor, or printer driver, the only way in which a user interface is permitted is through the use of the VendorSetup directive. See Printer INF File Entries and Customized Printer Setup Operations for more information.

lParam
Not used, must be NULL.

Return Value

If the operation succeeds, the function should return TRUE; otherwise it should return FALSE. Currently, however, the only time the function's return value is checked is when the spooler has called DrvPrinterEvent during processing of the AddPrinter function, with DriverEvent set to PRINTER_EVENT_INITIALIZE. If DrvPrinterEvent returns FALSE in this case, the spooler does not create the printer and instead causes AddPrinter to fail.

Headers

Declared in winddiui.h. Include winddiui.h.

Comments

All printer interface DLLs must provide a DrvPrinterEvent function, and the function must support the PRINTER_EVENT_INITIALIZE event code. Support for all other event codes is optional.

Registry settings stored when handling a PRINTER_EVENT_INITIALIZE event should be stored under the HKEY_LOCAL_MACHINE key by calling SetPrinterData. For the PRINTER_EVENT_INITIALIZE and PRINTER_EVENT_DELETE event codes, the spooler verifies that the caller has administrative privilege and calls DrvPrinterEvent while impersonating the caller.

In contrast, if you need to store settings in the registry when handling a PRINTER_EVENT_ADD_CONNECTION event, the printer interface DLL should write them under the HKEY_CURRENT_USER key so that they are stored on a per-user basis. Then if a user with a roaming profile logs onto another system, the connection follows the user. The DrvPrinterEvent function is called only when the user first makes the connection, and not when the user subsequently logs onto other systems using the roaming profile.

For the PRINTER_EVENT_ADD_CONNECTION and PRINTER_EVENT_DELETE_CONNECTION event codes, the DrvPrinterEvent function's execution context is the calling application (usually the Print Folder), and the function can display a user interface. For all other event codes, the execution context is the print spooler and a user interface cannot be displayed.

An example of a driver that might display a user interface when a connection is made is a FAX driver, which could prompt the user for the name and telephone number of the user (FAX sender), and save the information until the connection is deleted.

An example of the type of file that might be stored in a client cache is a large font metrics file that contains too much information to be written to the registry. When the DrvPrinterEvent function's event code is PRINTER_EVENT_CACHE_REFRESH, the printer interface DLL can reload the file from the server to ensure the cache is up to date.


DrvQueryColorProfile

The DrvQueryColorProfile function allows a printer interface DLL to specify an ICC profile to use for color management.

BOOL
  DrvQueryColorProfile(
    HANDLE  hPrinter,
    PDEVMODEW  pdevmode,
    ULONG  ulQueryMode,
    VOID  *pvProfileData,
    ULONG  *pcbProfileData,
    FLONG  *pflProfileData
    );

Parameters

hPrinter
Caller-supplied printer handle.
pdevmode
Caller-supplied pointer to a DEVMODE structure.
ulQueryMode
One of the following caller-supplied bit flags, indicating the type of profile to be specified.
Flag | Definition
QCP_DEVICEPROFILE | The caller is requesting a device profile.
QCP_SOURCEPROFILE | The caller is requesting a source profile.

pvProfileData
Caller-supplied pointer to a buffer to receive profile information.
pcbProfileData
Caller-supplied pointer to a value representing the size, in bytes, of the buffer pointed to by pvProfileData.
pflProfileData
One of the following function-supplied bit flags, indicating the type of information the function is returning.
Flag | Definition
QCP_PROFILEDISK | The function is returning the file name of an ICC profile in the buffer pointed to by pvProfileData.
QCP_PROFILEMEMORY | The function is returning profile data in the buffer pointed to by pvProfileData.

Return Value

If the operation succeeds, the function returns TRUE; otherwise it returns FALSE.

Headers

Declared in winddiui.h. Include winddiui.h.

Comments

A printer interface DLL can optionally provide a DrvQueryColorProfile function. If the function is provided, GDI calls it if ICM has been enabled for a print job. The function's purpose is to determine and specify an ICC profile that is appropriate for use with the print job.

If a driver's printer interface DLL does not provide a DrvQueryColorProfile function, or if the function returns FALSE, GDI attempts to find a profile. For more information, see Locating ICC Profiles.

If the output buffer size specified by pcbProfileData is too small, the driver should overwrite the size value supplied by pcbProfileData with the required buffer size, call SetLastError(ERROR_INSUFFICIENT_BUFFER), and return FALSE.


DrvQueryJobAttributes

The DrvQueryJobAttributes function allows a printer interface DLL to specify support for such capabilities as printing multiple document pages on a physical page ("N-up" printing), printing multiple copies of each page, collating pages, and printing pages in reverse order.

BOOL
  DrvQueryJobAttributes(
    HANDLE  hPrinter,
    PDEVMODE  pDevMode,
    DWORD  dwLevel,
    LPBYTE  lpAttributeInfo
    );

Parameters

hPrinter
Caller-supplied printer handle.
pDevMode
Caller-supplied pointer to a DEVMODE structure.
dwLevel
Caller-supplied value indicating the type of structure pointed to by lpAttributeInfo, as indicated in the following table.
dwLevel Value | Structure pointed to by lpAttributeInfo
1 | ATTRIBUTE_INFO_1
2 | ATTRIBUTE_INFO_2
3 | ATTRIBUTE_INFO_3

lpAttributeInfo
Caller-supplied pointer to a structure identified by dwLevel.

Return Value

If the operation succeeds, the function should return TRUE. Otherwise, it should return FALSE. Returning FALSE causes the current print job to be cancelled.

Headers

Declared in winddiui.h. Include winddiui.h.

Comments

A printer interface DLL can optionally provide a DrvQueryJobAttributes function. If the function is provided, it should fill in the supplied structure, described by dwLevel and plAttributeInfo, to indicate the current print job's user-requested attributes (such as N-up parameters and the number of copies) and the driver's ability to support those attributes. The function is typically called by the EMF print processor, so it can determine which job attributes can be handled by the driver (or printer), and which must be handled by the print processor.

For descriptions of the job attributes that the function can specify, see the descriptions of ATTRIBUTE_INFO_1, ATTRIBUTE_INFO_2, and ATTRIBUTE_INFO_3.


DrvUpgradePrinter

A printer interface DLL's DrvUpgradePrinter function is used for updating a printer's registry settings when a new version of the driver is added to a system.

BOOL
  DrvUpgradePrinter(
    DWORD  Level,
    LPBYTE  pDriverUpgradeInfo
    );

Parameters

Level
Caller-supplied value indicating the type of structure pointed to by pDriverUpgradeInfo, as indicated in the following table.
Level Value | Structure pointed to by pDriverUpgradeInfo
1 | DRIVER_UPGRADE_INFO_1
2 | DRIVER_UPGRADE_INFO_2

pDriverUpgradeInfo
Caller-supplied pointer to a structure whose type is identified by dwLevel.

Return Value

If the operation succeeds, the function should return TRUE; otherwise, it should call SetLastError to set an error code and return FALSE.

Headers

Declared in winddiui.h. Include winddiui.h.

Comments

A printer interface DLL can optionally provide a DrvUpgradePrinter function. If it does, the spooler calls it for every printer when the printer driver is copied onto the system. This occurs when a system is upgraded from one operating system release to the next, or when an application updates a printer driver by calling the Win32® AddPrinterDriver function.

It is often the case that a new driver version requires different registry settings than the old version. The DrvUpgradePrinter function's purpose is to update the registry so it is compatible with the driver. For more information about storing printer information in the registry, see DrvPrinterEvent.

For Windows 2000 and later, when the spooler calls DrvUpgradePrinter, it supplies a DRIVER_UPGRADE_INFO_2 structure pointer for pDriverUpgradeInfo. If the function returns FALSE, the spooler calls the function again, this time specifying a DRIVER_UPGRADE_INFO_1 structure pointer. If this call returns FALSE, the spooler writes an entry in the event log.

For Windows® NT 4.0 and previous, when the spooler calls DrvUpgradePrinter, it supplies a DRIVER_UPGRADE_INFO_1 structure pointer for pDriverUpgradeInfo. If the function returns FALSE, the spooler writes an entry in the event log.


Printer Interface DLL Structures

This section describes the structures used in printer interface DLLs.


ATTRIBUTE_INFO_1

The ATTRIBUTE_INFO_1 structure is used as a parameter for a printer interface DLL's DrvQueryJobAttributes function. All member values are function-supplied.

typedef struct _ATTRIBUTE_INFO_1 {
  DWORD  dwJobNumberOfPagesPerSide;
  DWORD  dwDrvNumberOfPagesPerSide;
  DWORD  dwNupBorderFlags;
  DWORD  dwJobPageOrderFlags;
  DWORD  dwDrvPageOrderFlags;
  DWORD  dwJobNumberOfCopies;
  DWORD  dwDrvNumberOfCopies;
} ATTRIBUTE_INFO_1, *PATTRIBUTE_INFO_1;

Members

dwJobNumberOfPagesPerSide
Number of document pages to be placed on one side of a physical page, as requested by the user. Allowable values are 1, 2, 4, 6, 9, or 16.
dwDrvNumberOfPagesPerSide
Number of document pages that the printer and driver can place on one side of a physical page. This value must be 1 or the value specified for dwJobNumberOfPagesPerSide.
dwNupBorderFlags
One of the following bit flag values:
Flag | Definition
BORDER_PRINT | The print processor should draw a border around the page.
NO_BORDER_PRINT | The print processor should not draw a border around the page.

dwJobPageOrderFlags
One of the following bit flag values:
Flag | Definition
BOOKLET_PRINT | Pages should be printed as a booklet.
NORMAL_PRINT | Pages should be printed in normal order.
REVERSE_PRINT | Pages should be printed in reverse order.

dwDrvPageOrderFlags
Bit flags indicating which page ordering options are supported by the printer and driver. Uses the same flags as dwJobPageOrderFlags.
dwJobNumberOfCopies
Number of copies of the print job, as requested by the user.
dwDrvNumberOfCopies
Maximum number of copies the printer and driver can handle at once, taking into account such job attributes as collating and stapling.

Headers

Declared in winddiui.h. Include winddiui.h.

Comments

The caller (the EMF print processor) uses the dwJobNumberOfPagesPerSide and dwDrvNumberOfPagesPerSide members to determine whether the driver or the print processor will handle "N-up" printing.

If the print processor will handle "N-up" printing, it checks dwNupBorderFlags to determine if it should draw a page border.

The print processor checks dwJobPageOrderFlags and dwDrvPageOrderFlags to determine the order in which pages should be sent to the printer.

The print processor uses dwJobNumberOfCopies and dwDrvNumberOfCopies to determine the number of times the print job must be sent to the printer.


ATTRIBUTE_INFO_2

The ATTRIBUTE_INFO_2 structure is used as a parameter for a printer interface DLL's DrvQueryJobAttributes function. All member values are function-supplied.

typedef struct _ATTRIBUTE_INFO_2 {
  DWORD  dwJobNumberOfPagesPerSide;
  DWORD  dwDrvNumberOfPagesPerSide;
  DWORD  dwNupBorderFlags;
  DWORD  dwJobPageOrderFlags;
  DWORD  dwDrvPageOrderFlags;
  DWORD  dwJobNumberOfCopies;
  DWORD  dwDrvNumberOfCopies;
  DWORD  dwColorOptimization;
} ATTRIBUTE_INFO_2, *PATTRIBUTE_INFO_2;

Members

dwJobNumberOfPagesPerSide
Number of document pages to be placed on one side of a physical page, as requested by the user. Allowable values are 1, 2, 4, 6, 9, or 16.
dwDrvNumberOfPagesPerSide
Number of document pages that the printer and driver can place on one side of a physical page. This value must be 1 or the value specified for dwJobNumberOfPagesPerSide.
dwNupBorderFlags
One of the following bit flag values:
Flag | Definition
BORDER_PRINT | The print processor should draw a border around the page.
NO_BORDER_PRINT | The print processor should not draw a border around the page.

dwJobPageOrderFlags
One of the following bit flag values:
Flag | Definition
BOOKLET_PRINT | Pages should be printed as a booklet.
NORMAL_PRINT | Pages should be printed in normal order.
REVERSE_PRINT | Pages should be printed in reverse order.

dwDrvPageOrderFlags
Bit flags indicating which page ordering options are supported by the printer and driver. Uses the same flags as dwJobPageOrderFlags.
dwJobNumberOfCopies
Number of copies of the print job, as requested by the user.
dwDrvNumberOfCopies
Maximum number of copies the printer and driver can handle at once, taking into account such job attributes as collating and stapling.
dwColorOptimization
One of the following bit flag values:
Flag | Definition
COLOR_OPTIMIZATION | The print processor should use monochrome color optimization.
NO_COLOR_OPTIMIZATION | The print processor should not use monochrome color optimization.

Headers

Declared in winddiui.h. Include winddiui.h.

Comments

The EMF print processor uses the flag specified for dwColorOptimization to determine whether to request GDI to perform monochrome color optimization. If monochrome color optimization is enabled, the print job can be switched between monochrome and color rendering as appropriate.

For more information about other structure members, see ATTRIBUTE_INFO_1.


ATTRIBUTE_INFO_3

The ATTRIBUTE_INFO_3 structure is used as a parameter for a printer interface DLL's DrvQueryJobAttributes function. All member values are function-supplied.

typedef struct _ATTRIBUTE_INFO_3 {
  DWORD  dwJobNumberOfPagesPerSide;
  DWORD  dwDrvNumberOfPagesPerSide;
  DWORD  dwNupBorderFlags;
  DWORD  dwJobPageOrderFlags;
  DWORD  dwDrvPageOrderFlags;
  DWORD  dwJobNumberOfCopies;
  DWORD  dwDrvNumberOfCopies;
  DWORD  dwColorOptimization;
  short  dmPrintQuality;
  short  dmYResolution;
} ATTRIBUTE_INFO_3, *PATTRIBUTE_INFO_3;

Members

dwJobNumberOfPagesPerSide
Number of document pages to be placed on one side of a physical page, as requested by the user. Allowable values are 1, 2, 4, 6, 9, or 16.
dwDrvNumberOfPagesPerSide
Number of document pages that the printer and driver can place on one side of a physical page. This value must be 1 or the value specified for dwJobNumberOfPagesPerSide.
dwNupBorderFlags
One of the following bit flag values:
Flag | Definition
BORDER_PRINT | The print processor should draw a border around the page.
NO_BORDER_PRINT | The print processor should not draw a border around the page.

dwJobPageOrderFlags
One of the following bit flag values:
Flag | Definition
BOOKLET_PRINT | Pages should be printed as a booklet.
NORMAL_PRINT | Pages should be printed in normal order.
REVERSE_PRINT | Pages should be printed in reverse order.

dwDrvPageOrderFlags
Bit flags indicating which page ordering options are supported by the printer and driver. Uses the same flags as dwJobPageOrderFlags.
dwJobNumberOfCopies
Number of copies of the print job, as requested by the user.
dwDrvNumberOfCopies
Maximum number of copies the printer and driver can handle at once, taking into account such job attributes as collating and stapling.
dwColorOptimization
One of the following bit flag values:
Flag | Definition
COLOR_OPTIMIZATION | The print processor should use monochrome color optimization.
NO_COLOR_OPTIMIZATION | The print processor should not use monochrome color optimization.

dmPrintQuality
Value to be used instead of the dmPrintQuality member of the print job's DEVMODE structure, if the COLOR_OPTIMIZATION flag is set in dwColorOptimization.
dmYResolution
Value to be used instead of the dmYResolution member of the print job's DEVMODE structure, if the COLOR_OPTIMIZATION flag is set in dwColorOptimization.

Headers

Declared in winddiui.h. Include winddiui.h.

Comments

If the dmPrintQuality member of a print job's DEVMODE structure is a negative value, such as DMRES_HIGH, and if monochrome color optimization is enabled, then switching between color and monochrome could result in different resolutions being used. This is because DMRES_HIGH might be assigned to different DPI values for color and monochrome rendering. (For Unidrv-supported devices, this assignment occurs in the printer's GPD file.) To insure a consistent resolution throughout the print job, the driver can specify positive dmPrintQuality and dmYResolution values (representing a specific DPI resolution) to override the equivalent DEVMODE values. For more information about these values, see the description of DEVMODE.

For information about other ATTRIBUTE_INFO_3 structure members, see ATTRIBUTE_INFO_2.


DEVICEPROPERTYHEADER

The DEVICEPROPERTYHEADER structure is used as an input parameter to a printer interface DLL's DrvDevicePropertySheets function.

typedef struct _DEVICEPROPERTYHEADER {
  WORD  cbSize;
  WORD  Flags;
  HANDLE  hPrinter;
  LPTSTR  pszPrinterName;
} DEVICEPROPERTYHEADER, *PDEVICEPROPERTYHEADER;

Members

cbSize
Size, in bytes, of the DEVICEPROPERTYHEADER structure.
Flags
Is a set of flags that can be set to the following value:
Value | Meaning
DPS_NOPERMISSION | If set, the user is not permitted to update device settings.

hPrinter
Printer handle.
pszPrinterName
Pointer to a NULL-terminated string representing a printer name.

Headers

Declared in winddiui.h. Include winddiui.h.


DEVQUERYPRINT_INFO

The DEVQUERYPRINT_INFO structure is used as an input parameter to a printer interface DLL's DevQueryPrintEx function.

typedef struct _DEVQUERYPRINT_INFO {
  WORD  cbSize;
  WORD  Level;
  HANDLE  hPrinter;
  DEVMODE  *pDevMode;
  LPTSTR  pszErrorStr;
  DWORD   cchErrorStr;
  DWORD   cchNeeded;
} DEVQUERYPRINT_INFO, *PDEVQUERYPRINT_INFO;

Members

cbSize
Spooler-supplied size, in bytes, of the DEVQUERYPRINT_INFO structure.
Level
Spooler-supplied level of the DEVQUERYPRINT_INFO structure. Currently, this member is always set to 1.
hPrinter
Spooler-supplied printer handle.
pDevMode
Spooler-supplied pointer to a DEVMODE structure describing printer characteristics required by the print job.
pszErrorStr
Spooler-supplied pointer to a buffer to receive a NULL-terminated error text string, if the print job cannot be printed.
cchErrorStr
Spooler-supplied size, in bytes, of the string buffer pointed to by pszErrorStr.
cchNeeded
Driver-supplied length, in bytes, of the error string supplied in the buffer pointed to by pszErrorStr. If the string is too large to fit in the buffer, the string should be truncated, but the untruncated length should be specified here.

Headers

Declared in winddiui.h. Include winddiui.h.


DOCEVENT_CREATEDCPRE

The DOCEVENT_CREATEDCPRE structure assembles a set of values used in certain calls to DrvDocumentEvent and IPrintOemUI2::DocumentEvent.

typedef struct _DOCEVENT_CREATEDCPRE {
  PWSTR  pszDriver;
  PWSTR  pszDevice;
  PDEVMODEW  pdm;
  BOOL  bIC;
} DOCEVENTCREATEDCPRE, *PDOCEVENT_CREATEDCPRE;

Members

pszDriver
Is reserved for system use and should be set to zero.
pszDevice
Points to the first byte of a Unicode string that contains either the device name or the port name, depending on whether print spooling is enabled or disabled. If the print job is being sent directly to the printer (spooling is disabled), this member contains the printer name. If a print job is being spooled, this member contains the port name.
pdm
Points to a DEVMODE structure passed to either CreateIC or CreateDC (both described in the Platform SDK documentation). This member can be NULL.
bIC
Specifies whether the DEVMODE structure pointed to by the pdm member is being passed to CreateIC or CreateDC . If TRUE, CreateIC is being called. If FALSE, CreateDC is being called.

Headers

Declared in winddiui.h. Include winddiui.h.

Comments

The DOCEVENT_CREATEDCPRE structure is defined for Windows XP and later.

This structure is used in conjunction with a call to DrvDocumentEvent or IPrintOemUI2::DocumentEvent, in which the iEsc parameter is set to DOCUMENTEVENT_CREATEDCPRE. Before calling either of these functions, the caller must fill in the members of this structure.

See Also

DrvDocumentEvent, IPrintOemUI2::DocumentEvent


DOCEVENT_ESCAPE

The DOCEVENT_ESCAPE structure provides a container for values used as parameters for ExtEscape.

typedef struct _DOCEVENT_ESCAPE {
  int  iEscape;
  int  cjInput;
  PVOID  pvInData;
} DOCEVENTESCAPE, *PDOCEVENT_ESCAPE;

Members

iEscape
Specifies the value of the ExtEscape function's nEscape parameter.
cjInput
Specifies the value of the ExtEscape function's cbInput parameter.
pvInData
Specifies the value of the ExtEscape function's lpszInData parameter.

Headers

Declared in winddiui.h. Include winddiui.h.

Comments

The DOCEVENT_CREATEDCPRE structure is defined for Windows XP and later.

This structure is used in conjunction with a call to DrvDocumentEvent or IPrintOemUI2::DocumentEvent, in which the iEsc parameter is set to DOCUMENTEVENT_ESCAPE. Before calling either of these functions, the caller must fill in the members of this structure.

Refer to the Platform SDK documentation for a description of the ExtEscape function and the three parameters that correspond to the members of this structure.

See Also

DrvDocumentEvent, IPrintOemUI2::DocumentEvent


DOCEVENT_FILTER

The DOCEVENT_FILTER structure contains a list of document events to which the printer driver will respond. See DrvDocumentEvent for a complete list of the document events.

typedef struct _DOCEVENT_FILTER {
  UINT  cbSize;
  UINT  cElementsAllocated;
  UINT  cElementsNeeded;
  UINT  cElementsReturned;
  DWORD  aDocEventCall[ANYSIZE_ARRAY];
} DOCEVENT_FILTER, *PDOCEVENT_FILTER;

Members

cbSize
Spooler-supplied size, in bytes, of this structure. The spooler initializes this member to sizeof(DOCEVENT_FILTER).
cElementsAllocated
Spooler-supplied number of elements in the aDocEventCall array member. The spooler initializes this member to DOCUMENTEVENT_LAST - 1. (The DOCUMENTEVENT_LAST constant is defined in winddiui.h.)
cElementsNeeded
Driver-supplied total number of elements needed in the aDocEventCall array member. The spooler initializes this member to 0XFFFFFFFF. See Comments for more information.
cElementsReturned
Driver-supplied number of DOCUMENTEVENT_XXX events that it placed in the aDocEventCall array member. The spooler initializes this member to 0XFFFFFFFF. See Comments for more information.
aDocEventCall
Driver-filled array of DWORDs listing all of the DOCUMENTEVENT_XXX events to which the printer driver will respond. The spooler initializes this member to 0.

Headers

Declared in winddiui.h. Include winddiui.h.

Comments

This structure is available in Windows XP and later.

The printer driver lists the events to which it will respond in the DOCEVENT_FILTER structure. Since this limits the number of calls to the driver the spooler needs to make, printer performance is enhanced. When the spooler makes a call to the DrvDocumentEvent DDI with its iEsc parameter set to DOCUMENTEVENT_QUERYFILTER, the spooler allocates a buffer that will contain a DOCEVENT_FILTER structure, including its dynamic array. The amount of memory allocated for the buffer is:

sizeof(DOCEVENT_FILTER) + sizeof(DWORD) * (DOCUMENTEVENT_LAST - 2)

After allocating a buffer that will contain a DOCEVENT_FILTER structure, the spooler initializes the structure members to the following values:

Member | Initialized to:
cbSize | 0
cElementsAllocated | DOCUMENTEVENT_LAST - 1 The DOCUMENTEVENT_LAST constant is defined in winddiui.h.
cElementsNeeded | 0XFFFFFFFF
cElementsReturned | 0XFFFFFFFF
aDocEventCall | 0

After the spooler has initialized the structure members to the values shown in the preceding table, it then calls DrvDocumentEvent. When this function returns, the spooler inspects the cElementsNeeded and cElementsReturned members to see if either has been changed. If the driver has written to one of these members, but not the other, the spooler interprets the unwritten-to member as having the value 0.

If the driver supports DOCUMENTEVENT_QUERYFILTER:

  • If the aDocEventCall array is large enough to contain all of the DOCUMENTEVENT_XXX events the printer driver intends to place in it, the printer driver:
    • fills the array with those events
    • sets the cElementsReturned member to that number of events (which should be less than or equal to cElementsAllocated)
    • leaves cElementsNeeded unchanged
    • returns DOCUMENTEVENT_SUCCESS

    In this case, the spooler will use the first cElementsReturned values in the aDocEventCall array.

Note The DOCUMENTEVENT_CREATEDCPRE event is treated in a special way. When the spooler calls DrvDocumentEvent with the iEsc parameter set to DOCUMENTEVENT_CREATEDCPRE, the spooler uses the return value to determine whether future calls to this function are necessary. Unlike other DOCUMENTEVENT_XXX events, the printer driver will always receive calls to DrvDocumentEvent with DOCUMENTEVENT_CREATEDCPRE, whether this event is filtered out or not.

  • If the aDocEventCall array is not large enough to contain all of the DOCUMENTEVENT_XXX events the printer driver intends to place in it, the printer driver should:
    • set cElementsNeeded to the number of events to which it intends to respond (which should be greater than cElementsAllocated)
    • leave cElementsReturned unchanged
    • return DOCUMENTEVENT_SUCCESS

    In this case, the spooler will then allocate a new buffer that is sufficiently large, and then make another call to DrvDocumentEvent with DOCUMENTEVENT_QUERYFILTER.

If the driver does not support the DOCUMENTEVENT_QUERYFILTER event, it should return DOCUMENTEVENT_UNSUPPORTED. If the driver does support DOCUMENTEVENT_QUERYFILTER, but encounters internal errors when it handles this event, it should return DOCUMENTEVENT_FAILURE. In either case, the spooler will not be able to retrieve the event filter from the driver, so it will continue in its behavior of calling DrvDocumentEvent for all events.

See Also

DrvDocumentEvent


DOCUMENTPROPERTYHEADER

The DOCUMENTPROPERTYHEADER structure is used as an input parameter to a printer interface DLL's DrvDocumentPropertySheets function.

typedef struct _DOCUMENTPROPERTYHEADER {
  WORD    cbSize;
  WORD    Reserved;
  HANDLE  hPrinter;
  LPTSTR  pszPrinterName;
  PDEVMODE  pdmIn;
  PDEVMODE  pdmOut;
  DWORD   cbOut;
  DWORD   fMode;
} DOCUMENTPROPERTYHEADER, *PDOCUMENTPROPERTYHEADER;

Members

cbSize
Size, in bytes, of the DOCUMENTPROPERTYHEADER structure.
Reserved
Reserved. Must be zero.
hPrinter
Printer handle.
pszPrinterName
Pointer to a NULL-terminated string representing the printer's name.
pdmIn
Pointer to an input DEVMODE structure that the DrvDocumentPropertySheets function should copy into the printer interface DLL's internal DEVMODE structure (before the property sheet is displayed, if applicable). If DM_IN_BUFFER or DM_MODIFY is not set in fMode, this pointer is NULL.
pdmOut
Pointer to an output DEVMODE structure into which the DrvDocumentPropertySheets function should copy the printer interface DLL's internal DEVMODE contents (after the property sheet has been displayed, if applicable). If DM_OUT_BUFFER or DM_COPY is not set in fMode, this pointer is NULL.
cbOut
Specifies the size, in bytes, of the buffer to which pdmOut points.
fMode
One or more of the bit flags listed in the following table. (Flags are defined in wingdi.h and winddiui.h.)
Flag | Definition
No flags set (that is, fMode is 0). | The DrvDocumentPropertySheets function should return the size, in bytes, of its DEVMODE structure, including all public and private members, in the cbOut member.
DM_ADVANCED If set, the DrvDocumentPropertySheets function should only create the Advanced document page.
If not set, the DrvDocumentPropertySheets function should create both the Page Setup and Advanced document pages.

(See the description of the pDlgPage member of the COMPROPSHEETUI structure.)
DM_IN_BUFFER or
DM_MODIFY 		The caller has supplied a DEVMODE structure pointer in pdmIn, and the DrvDocumentPropertySheets function should update its internal DEVMODE structure to reflect the contents of the supplied DEVMODE.
DM_IN_PROMPT or
DM_PROMPT 		The DrvDocumentPropertySheets function should create its property sheet pages.
(This flag is never set if the DrvDocumentPropertySheets function's pPSUIInfo parameter is NULL.).
DM_NOPERMISSION | The printer interface DLL's _CPSUICALLBACK-typed callback should not allow the user to modify properties on the displayed property sheet pages.
DM_OUT_BUFFER or
DM_COPY 		The caller has supplied a DEVMODE structure pointer in pdmOut, and the DrvDocumentPropertySheets function should copy the contents of its internal DEVMODE structure into the supplied DEVMODE.
DM_USER_DEFAULT | Not used
DM_OUT_DEFAULT or
DM_UPDATE 		Not used

Headers

Declared in winddiui.h. Include winddiui.h.


DRIVER_UPGRADE_INFO_1

The DRIVER_UPGRADE_INFO_1 structure is used as an input to a printer interface DLL's DrvUpgradePrinter function.

typedef struct _DRIVER_UPGRADE_INFO_1 {
  LPTSTR  pPrinterName;
  LPTSTR  pOldDriverDirectory;
} DRIVER_UPGRADE_INFO_1, *PDRIVER_UPGRADE_INFO_1;

Members

pPrinterName
Pointer to a NULL-terminated string that specifies the name of the printer.
pOldDriverDirectory
Pointer to a NULL-terminated string that specifies the local directory in which the old printer driver files can be found.

Headers

Declared in winddiui.h. Include winddiui.h.


DRIVER_UPGRADE_INFO_2

The DRIVER_UPGRADE_INFO_2 structure is used as an input to a printer interface DLL's DrvUpgradePrinter function.

typedef struct _DRIVER_UPGRADE_INFO_2 {
  LPTSTR   pPrinterName;
  LPTSTR   pOldDriverDirectory;
  DWORD  cVersion;
  LPTSTR   pName;
  LPTSTR   pEnvironment;
  LPTSTR   pDriverPath;
  LPTSTR   pDataFile;
  LPTSTR   pConfigFile;
  LPTSTR   pHelpFile;
  LPTSTR   pDependentFiles;
  LPTSTR   pMonitorName;
  LPTSTR   pDefaultDataType;
  LPTSTR   pszzPreviousNames;
} DRIVER_UPGRADE_INFO_2, *PDRIVER_UPGRADE_INFO_2;

Members

pPrinterName
Pointer to a NULL-terminated string that specifies the name of the printer.
pOldDriverDirectory
Pointer to a NULL-terminated string that specifies the local directory in which the old printer driver files can be found.

The rest of the structure members exactly match the members of the DRIVER_INFO_4 structure, which is described in the Platform SDK documentation.

Headers

Declared in winddiui.h. Include winddiui.h.


PRINTER_EVENT_ATTRIBUTES_INFO

The PRINTER_EVENT_ATTRIBUTES_INFO structure contains the former attributes and the new attributes for a printer.

typedef struct _PRINTER_EVENT_ATTRIBUTES_INFO {
  DWORD  cbSize;
  DWORD  dwOldAttributes;
  DWORD  dwNewAttributes;
} PRINTER_EVENT_ATTRIBUTES_INFO, *PPRINTER_EVENT_ATTRIBUTES_INFO;

Members

cbSize
Specifies the size of this structure.
dwOldAttributes
Is a set of bits describing the current printer attributes.
dwNewAttributes
Is a set of bits describing the new printer attributes to be applied to the printer.

Headers

Declared in winspool.h. Include winspool.h.

Comments

The bits in the dwOldAttributes and dwNewAttributes members of this structure are set in accordance with the Attributes member of the PRINTER_INFO_2 structure (defined in the Platform SDK documentation).

Because this structure might become larger in future operating system versions, anyone using this structure is advised to check that the value in the cbSize member of this structure is at least as large as the offset of the member to be accessed.

See Also

DrvPrinterEvent, IPrintOemUI::PrinterEvent


SIMULATE_CAPS_1

The SIMULATE_CAPS_1 structure contains information about the types of simulations a spooler supports.

typedef struct _SIMULATE_CAPS_1 {
  DWORD  dwLevel;
  DWORD  dwPageOrderFlags;
  DWORD  dwNumberOfCopies;
  DWORD  dwCollate;
  DWORD  dwNupOptions;
} SIMULATE_CAPS_1, *PSIMULATE_CAPS_1;

Members

dwLevel
Specifies the version of this structure. This value must be 1.
dwPageOrderFlags
Specifies the order in which pages will be printed. This member can be set to either NORMAL_PRINT or REVERSE_PRINT.
dwNumberOfCopies
Specifies the maximum number of copies the spooler can handle.
dwCollate
Specifies whether the spooler supports collation. A value of 1 indicates that the spooler supports collation, and a value of 0 indicates that it does not.
dwNupOptions
Is a bitmask representing the various numbers of document pages the printer can print on a physical page. The least significant bit represents 1 document page per page, the next bit represents 2 document pages per page, the next bit represents 3 document pages per physical page, and so on. For example, 0x0000810B indicates that the spooler supports 1, 2, 4, 9, and 16 document pages per physical page.

Headers

Declared in printoem.h. Include printoem.h.

Comments

The IPrintCoreUI2::QuerySimulationSupport method uses this structure to report the spooler's level of simulation support to a user interface plug-in.

See Also

IPrintCoreUI2::QuerySimulationSupport


Printer Graphics DLL Functions

The graphics DDI functions that must be defined by a printer graphics DLL are described in the section entitled Graphics Driver Functions (DDI). For a list of the subset of graphics driver functions that are relevant to printer graphics DLLs, see Functions Defined by Printer Graphics DLLs.


Printer Graphics DLL Structures

The structures that are used by a printer graphics DLL are described in the section entitled Graphics Driver Structures, which describes the structures used by all types of graphics drivers.


User-Mode Rendering DLL Functions

This section describes the functions defined by user-mode rendering DLLs. Function prototypes are defined in winddiui.h.

These functions are obsolete, and are supported only so that user-mode rendering DLLs, optionally supplied with Windows NT 4.0 drivers, will execute under Windows 2000 and later. To supply user-mode image rendering code for printers, see Choosing User Mode or Kernel Mode.


DrvSplAbort

The DrvSplAbort function enables a user-mode rendering DLL to respond to a request to cancel a print job.

VOID
  DrvSplAbort(
    HANDLE  hDriver
    );

This function is obsolete, and is supported only so that user-mode rendering DLLs, optionally supplied with Windows NT 4.0 drivers, will execute under Windows 2000 and later. To supply user-mode image rendering code for printers, see Choosing User Mode or Kernel Mode.


DrvSplClose

The DrvSplClose function enables a user-mode rendering DLL to de-allocate resources.

VOID
  DrvSplClose(
    HANDLE  hDriver
    );

This function is obsolete, and is supported only so that user-mode rendering DLLs, optionally supplied with Windows NT 4.0 drivers, will execute under Windows 2000 and later. To supply user-mode image rendering code for printers, see Choosing User Mode or Kernel Mode.


DrvSplEndDoc

The DrvSplEndDoc function enables a user-mode rendering DLL to perform operations associated with the end of a print job.

VOID
  DrvSplEndDoc(
    HANDLE  hDriver
    );

This function is obsolete, and is supported only so that user-mode rendering DLLs, optionally supplied with Windows NT 4.0 drivers, will execute under Windows 2000 and later. To supply user-mode image rendering code for printers, see Choosing User Mode or Kernel Mode.


DrvSplEndPage

The DrvSplEndPage function enables a user-mode rendering DLL to perform operations needed after a physical page is rendered.

BOOL
  DrvSplEndPage(
    HANDLE  hDriver
    );

This function is obsolete, and is supported only so that user-mode rendering DLLs, optionally supplied with Windows NT 4.0 drivers, will execute under Windows 2000 and later. To supply user-mode image rendering code for printers, see Choosing User Mode or Kernel Mode.


DrvSplStartDoc

The DrvSplStartDoc function enables a user-mode rendering DLL to perform operations associated with the start of a print job.

HANDLE
  DrvSplStartDoc(
    HANDLE  hPrinter,
    DWORD  JobId
    );

This function is obsolete, and is supported only so that user-mode rendering DLLs, optionally supplied with Windows NT 4.0 drivers, will execute under Windows 2000 and later. To supply user-mode image rendering code for printers, see Choosing User Mode or Kernel Mode.


DrvSplStartPage

The DrvSplStartPage function enables a user-mode rendering DLL to perform operations needed before a physical page is rendered.

BOOL
  DrvSplStartPage(
    HANDLE  hDriver
    );

This function is obsolete, and is supported only so that user-mode rendering DLLs, optionally supplied with Windows NT 4.0 drivers, will execute under Windows 2000 and later. To supply user-mode image rendering code for printers, see Choosing User Mode or Kernel Mode.


DrvSplWritePrinter

The DrvSplWritePrinter function enables a user-mode rendering DLL to alter a print job's data stream after it has been produced by GDI and a printer graphics DLL but before it is sent to a printer port.

BOOL
  DrvSplWritePrinter(
    HANDLE  hDriver,
    LPVOID  pBuf,
    DWORD  cbBuf,
    LPDWORD  pcWritten
    );

This function is obsolete, and is supported only so that user-mode rendering DLLs, optionally supplied with Windows NT 4.0 drivers, will execute under Windows 2000 and later. To supply user-mode image rendering code for printers, see Choosing User Mode or Kernel Mode.


Unidrv and Pscript Interfaces

This section describes the programming interfaces provided for vendor-supplied customization of Unidrv and Pscript5 driver functionality. The following topics are included:

Methods for User Interface Plug-Ins

Function Types for User Interface Plug-Ins

Structures for User Interface Plug-Ins

Methods for Rendering Plug-Ins

Structures for Rendering Plug-Ins

Callback Functions

Printer Font Resource Structures


Methods for User Interface Plug-Ins

This section describes the COM interfaces used for communication between Microsoft's printer drivers (Unidrv and Pscript) and vendor-supplied user interface plug-ins. The following topics are provided:

IPrintOemUI Interface

IPrintOemUI2 Interface

IPrintOemDriverUI Interface

IPrintCoreUI2 Interface


IPrintOemUI Interface

This section describes the methods defined for the IPrintOemUI COM interface. Method prototypes are defined in prcomoem.h.


IPrintOemUI::CommonUIProp

The IPrintOemUI::CommonUIProp method allows a user interface plug-in to modify an existing printer property sheet page.

STDMETHOD
  (CommonUIProp) (
    THIS_
    DWORD  dwMode,
    POEMCUIPPARAM  pOemCUIPParam
    ) PURE;

Parameters

dwMode
Caller-supplied integer constant indicating which property sheet page should be modified. The following constants are valid.
Value | Definition
OEMCUIP_DOCPROP | The method is being called to modify the Layout, Paper/Quality, or Advanced page of the document property sheet.
OEMCUIP_PRNPROP | The method is being called to modify the Device Settings page of the printer property sheet.

pOemCUIPParam
Caller-supplied pointer to an OEMCUIPPARAM structure.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

When a user interface plug-in's IPrintOemUI::CommonUIProp method is called, it should return customized property sheet option items in order to modify an existing printer property sheet page.

The IPrintOemUI::CommonUIProp method is called by the printer driver's printer interface DLL. The method should supply an array of OPTITEM structures describing property sheet items, along with a callback function for processing user modifications to option values.

You should expect the method to be called twice for each property sheet. The method's dwMode parameter value indicates whether it is being called to make changes to the printer property sheet or the document property sheet.

The first time it is called, the method should just return the number of OPTITEM structures to be added. This number should be placed in the OEMCUIPPARAM structure's cOEMOptItems member. The printer interface DLL then allocates enough memory to store the specified number of OPTITEMs, and calls IPrintOemUI::CommonUIProp again.

The second time it is called, the IPrintOemUI::CommonUIProp method should do the following:

  • Fill the driver-supplied array of OPTITEM structures with option descriptions. This array is pointed to by the OEMCUIPPARAM structure's pOEMOptItems member, and the number of allocated array elements is contained in the structure's cOEMOptItems member. (For information about specifying OPTITEM member values, see the description of the OEMCUIPPARAM structure's pOEMOptItems member).
  • Return the number of structures added to the OPTITEM array by placing the number in the OEMCUIPPARAM structure's cOEMOptItems member.
  • Return the address of a callback function in the OEMCUIPPARAM structure's OEMCUIPCallback member. This callback function is called when a user modifies the property sheet page. The callback function must be of type OEMCUIPCALLBACK.
  • Optionally, return the address of a private data structure by placing it in the OEMCUIPPARAM structure's pOEMUserData member. The callback function specified by the structure's OEMCUIPCallback member receives the OEMCUIPPARAM structure's address as an input parameter and can therefore obtain the private data's address.

    Space for the private data structure should be allocated by calling the Platform SDK HeapAlloc function, using the handle contained in the OEMCUIPPARAM structure's hOEMHeap member.

If IPrintOemUI::CommonUIProp methods are exported by multiple user interface plug-ins, the methods are called in the order that the plug-ins are specified for installation.

For more information, see Modifying a Driver-Supplied Property Sheet Page.


IPrintOemUI::DeviceCapabilities

The IPrintOemUI::DeviceCapabilities method allows a user interface plug-in to specify customized device capabilities.

STDMETHOD
  (DeviceCapabilities) (
    THIS_
    POEMUIOBJ  poemuiobj,
    HANDLE  hPrinter,
    PWSTR  pDeviceName,
    WORD  wCapability,
    PVOID  pOutput,
    PDEVMODE  pPublicDM,
    PVOID  pOEMDM,
    DWORD  dwOld,
    DWORD  *dwResult
    ) PURE;

Parameters

poemuiobj
Caller-supplied pointer to an OEMUIOBJ structure.
hPrinter
Caller-supplied handle to the printer device.
pDeviceName
Caller-supplied pointer to a string representing the device name.
wCapability
Caller-supplied flag indicating the type of information the method should return. For a list of flags, see the description of the DrvDeviceCapabilities function.
pOutput
Caller-supplied pointer to a buffer to receive the requested information. The type of information returned is dependent on the flag specified by wCapability.
pPublicDM
Caller-supplied pointer to a validated DEVMODE structure.
pOEMDM
Caller-supplied pointer to the user interface plug-in's private DEVMODE structure members.
dwOld
Caller-supplied return value from the printer driver's DrvDeviceCapabilities function, or from another user interface plug-in. For more information, see the following Comments section.
dwResult
A return value that is dependent on the flag specified by wCapability. For more information, see the description of the DrvDeviceCapabilities function and the following Comments section.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

A user interface plug-in's IPrintOemUI::DeviceCapabilities method performs the same types of operations as the DrvDeviceCapabilities function that is exported by user-mode printer interface DLLs. The method specifies capabilities provided by the printer.

You can use the IPrintOemUI::DeviceCapabilities method to preempt Unidrv support for a capability, or to add a capability that the printer driver doesn't provide. The driver calls IPrintOemUI::DeviceCapabilities from within its DrvDeviceCapabilities function.

If the IPrintOemUI::DeviceCapabilities method indicates customized support for a capability (by setting appropriate bits in response to a received DC_FIELDS flag), then customized code must completely support the capability. Complete support typically includes returning information about the capability in response to calls to the IPrintOemUI::DeviceCapabilities method, plus providing appropriate user-mode or kernel-mode code to implement the capability.

If IPrintOemUI::DeviceCapabilities methods are exported by multiple user interface plug-ins, the methods are called in the order that the plug-ins are specified for installation. Each time a plug-in's IPrintOemUI::DeviceCapabilities method is called, its dwOld input value is the return value from the previously called plug-in's IPrintOemUI::DeviceCapabilities method. For the first plug-in called, dwOld contains the return value from the printer driver's DrvDeviceCapabilities function. Likewise, the buffer pointed to by pOutput contains, on input, any contents placed there by a previously called IPrintOemUI::DeviceCapabilities method or DrvDeviceCapabilities function.

For multiple user interface plug-ins to work in conjunction with each other, each IPrintOemUI::DeviceCapabilities method must obey the following rules:

  • If a user interface plug-in does not support a specified capability, its IPrintOemUI::DeviceCapabilities method should just return the contents of the dwOld parameter in dwResult.
  • If a user interface plug-in supports the capability, its IPrintOemUI::DeviceCapabilities method should ignore dwOld and the contents of the buffer pointed to by pOutput. It should provide a return value and buffer contents appropriate for indicating that it supports the specified capability. If the method detects an error, it should return GDI_ERROR in dwResult.
  • If you want a user interface plug-in to modify the capabilities information received in the buffer pointed to by pOutput, its IPrintOemUI::DeviceCapabilities method should modify the buffer contents and return an appropriate return value in dwResult. For example, if wCapability is DC_FIELDS, the method should OR the bits it needs to set with the bits that are set in dwOld, and return the result of the OR operation in dwResult.
  • These rules should be followed even if the received contents of dwOld is GDI_ERROR.

When the driver's DrvDeviceCapabilities function is called with the DC_FIELDS flag set, the function calls all IPrintOemUI::DeviceCapabilities methods, also specifying DC_FIELDS, and returns the union of all set bits to the caller.

For more information about creating and installing user interface plug-ins, see Customizing Microsoft's Printer Drivers.

See Also

DrvDeviceCapabilities


IPrintOemUI::DevicePropertySheets

The IPrintOemUI::DevicePropertySheets method allows a user interface plug-in to append a new page to a printer device's printer property sheet.

STDMETHOD
  (DevicePropertySheets) (
    THIS_
    PPROPSHEETUI_INFO  pPSUIInfo,
    LPARAM  lParam
    ) PURE;

Parameters

pPSUIInfo
Caller-supplied pointer to a PROPSHEETUI_INFO structure.
lParam
Caller-supplied value that depends on the reason value in pPSUIInfo—>Reason. The reason value can be one of the following constants, which are defined in compstui.h. For more information about these constants, see the Comments section and lParam parameter description in the PFNPROPSHEETUI function type.

PROPSHEETUI_REASON_DESTROY

PROPSHEETUI_REASON_GET_ICON

PROPSHEETUI_REASON_GET_INFO_HEADER

PROPSHEETUI_REASON_INIT

PROPSHEETUI_REASON_SET_RESULT

Return Value

The return value depends on the contents of PROPSHEETUI_INFO structure's Reason member. For more information, see the description of DrvDevicePropertySheets.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

A user interface plug-in's IPrintOemUI::DevicePropertySheets method performs the same types of operations as the DrvDevicePropertySheets function that is exported by user-mode printer interface DLLs. Both functions have the same input parameters.

If you provide a user interface plug-in, the IPrintOemUI::DevicePropertySheets method will be called after the driver's DrvDevicePropertySheets function is called.

When IPrintOemUI::DevicePropertySheets is called, the lParamInit member of the PROPSHEETUI_INFO structure contains the address of an OEMUIPSPARAM structure.

If you implement this method, you will typically also supply a _CPSUICALLBACK-typed callback function to handle user modifications. This callback function must call IPrintOemDriverUI::DrvUpdateUISetting to inform the driver when the value associated with a user interface setting has been modified, if the value is stored in the driver's DEVMODE structure (instead of the plug-in's private DEVMODE members ) or in registry keys.

If IPrintOemUI::DevicePropertySheets methods are exported by multiple user interface plug-ins, the methods are called in the order that the plug-ins are specified for installation.

If one user interface plug-in supports several printer models, and if you only want the new page to be displayed for some of those models, the IPrintOemUI::DevicePropertySheets method should just provide a success return value, without actually adding the page, for the models not requiring the page.

For more information about creating and installing user interface plug-ins, see Customizing Microsoft's Printer Drivers.

See Also

DrvDevicePropertySheets, IPrintOemUI::DocumentPropertySheets, PFNPROPSHEETUI


IPrintOemUI::DevMode

The IPrintOemUI::DevMode method, provided by user interface plug-ins, performs operations on the plug-in's private DEVMODE members.

STDMETHOD
  (DevMode) (
    THIS_
    DWORD  dwMode,
    POEMDMPARAM  pOemDMParam
    ) PURE;

Parameters

dwMode
Caller-supplied constant. See the following Comments section.
pOemDMParam
Caller-supplied pointer to an OEMDMPARAM structure.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

User interface plug-ins must implement a IPrintOemUI::DevMode method if they define private DEVMODE structure members. The method's purpose is to define, validate, or convert (from one version to another) the contents of the private DEVMODE structure members.

A private DEVMODE section must be prefaced by a OEM_DMEXTRAHEADER structure.

The IPrintOemUI::DevMode method must perform the operation indicated by its dwMode value. Each time IPrintOemUI::DevMode is called, dwMode contains one of the following constants, which are listed in the order they are received:

OEMDM_SIZE
Indicates the IPrintOemUI::DevMode method should return the size of the memory allocation needed to store the user interface plug-in's private DEVMODE members. This constant is set the first time the method is called. The method should place the number of bytes needed in the OEMDMPARAM structure's cbBufSize member.

The printer interface DLL allocates the specified amount of memory and passes its address to the user interface plug-in in subsequent calls to IPrintOemUI::DevMode.

OEMDM_DEFAULT
Indicates the IPrintOemUI::DevMode method should fill the private DEVMODE members with their default values. For this operation, the OEMDMPARAM structure's pOEMDMOut and cbBufSize members contain the address and size of the area that has been allocated for storage of private DEVMODE members. The method should write the private DEVMODE default values into the buffer pointed to by the pOEMDMOut member, and return the number of bytes written by placing it in the cbBufSize member.
OEMDM_CONVERT
Indicates the IPrintOemUI::DevMode method should convert private DEVMODE members to the current version, if necessary. (EMF spooling can occur over a network, and the system that spooled the EMF records might be running an older or newer version of the printer driver or user interface plug-in.) A private DEVMODE section's version number is contained in its OEM_DMEXTRAHEADER structure.

The public and private members of the DEVMODE structure to be converted are pointed to by the OEMDMPARAM structure's pPublicDMIn and pOEMDMIn members. The IPrintOemUI::DevMode method should place converted private members in the memory space described by the structure's pOEMDMOut and cbBufSize members, and it should return the count of written bytes by placing it in the structure's cbBufSize member. The value returned in cbBufSize cannot be larger than the value received.

OEMDM_MERGE
Indicates the IPrintOemUI::DevMode method should validate the information contained in private DEVMODE members and merge validated values into a private DEVMODE structure containing default values. For this constant, the method receives the following DEVMODE contents:
  • The OEMDMPARAM structure's pPublicDMIn and pOEMDMIn members point to the public and private members of the DEVMODE structure to be validated.
  • The OEMDMPARAM structure's pPublicDMOut and pOEMDMOut members point to current default DEVMODE values (obtained from property sheet contents).

The method should validate the contents of each private DEVMODE member pointed to by pOEMDMIn. Each valid value should be copied to the output buffer pointed to by pOEMDMOut, overwriting the default. For invalid input values, the default output value should not be modified. (Finding invalid values is not considered an error, so the method should return S_OK.)

See Also

IPrintOemUni::DevMode, IPrintOemPS::DevMode


IPrintOemUI::DevQueryPrintEx

The IPrintOemUI::DevQueryPrintEx method allows a user interface plug-in to help determine if a print job is printable.

STDMETHOD
  (DevQueryPrintEx) (
    THIS_
    POEMUIOBJ  poemuiobj,
    PDEVQUERYPRINT_INFO  pDQPInfo,
    PDEVMODE  pPublicDM,
    PVOID  pOEMDM
    ) PURE;

Parameters

poemuiobj
Caller-supplied pointer to an OEMUIOBJ structure.
pDQPInfo
Caller-supplied pointer to a DEVQUERYPRINT_INFO structure.
pPublicDM
Caller-supplied pointer to a validated DEVMODE structure.
pOEMDM
Caller-supplied pointer to the user interface plug-in's private DEVMODE structure members.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

A user interface plug-in's IPrintOemUI::DevQueryPrintEx method performs the same types of operations as the DrvDevQueryPrintEx function that is exported by user-mode printer interface DLLs. You can use this method to enhance the functionality provided by the DevQueryPrintEx function. Like the DevQueryPrintEx function, the IPrintOemUI::DevQueryPrintEx method's responsibility is to determine if the print job described by the supplied DEVMODE structure can be printed.

When the driver's DevQueryPrintEx function is called, it checks the DEVMODE structure, along with the currently selected printer options, to determine if the job is printable. If it is not, the function returns FALSE. If the job appears to be printable, the function calls the IPrintOemUI::DevQueryPrintEx method in each user interface plug-in associated with the driver. If all IPrintOemUI::DevQueryPrintEx methods return S_OK, then DevQueryPrintEx returns TRUE. Thus, a job is not printable unless the DevQueryPrintEx function and all IPrintOemUI::DevQueryPrintEx methods declare it to be printable.

If IPrintOemUI::DevQueryPrintEx methods are exported by multiple user interface plug-ins, the methods are called in the order that the plug-ins are specified for installation.

For more information about creating and installing user interface plug-ins, see Customizing Microsoft's Printer Drivers.

See Also

DevQueryPrintEx


IPrintOemUI::DocumentPropertySheets

The IPrintOemUI::DocumentPropertySheets method allows a user interface plug-in to append a new page to a printer device's document property sheet.

STDMETHOD
  (DocumentPropertySheets) (
    THIS_
    PPROPSHEETUI_INFO  pPSUIInfo,
    LPARAM  lParam
    ) PURE;

Parameters

pPSUIInfo
Caller-supplied pointer to a PROPSHEETUI_INFO structure.
lParam
Caller-supplied value that depends on the reason value in pPSUIInfo—>Reason. The reason value can be one of the following constants, which are defined in compstui.h. For more information about these constants, see the Comments section and lParam parameter description in the PFNPROPSHEETUI function type.

PROPSHEETUI_REASON_DESTROY

PROPSHEETUI_REASON_GET_ICON

PROPSHEETUI_REASON_GET_INFO_HEADER

PROPSHEETUI_REASON_INIT

PROPSHEETUI_REASON_SET_RESULT

Return Value

The return value depends on the contents of the PROPSHEETUI_INFO structure's Reason member. For more information, see the description of DrvDocumentPropertySheets.

Headers

Declared in prcomoem.h. Include prcomoem.h and compstui.h.

Comments

A user interface plug-in's IPrintOemUI::DocumentPropertySheets method performs the same types of operations as the DrvDocumentPropertySheets function that is exported by user-mode printer interface DLLs. Both functions have the same input parameters.

If you provide a user interface plug-in, the IPrintOemUI::DocumentPropertySheets method will be called after the driver's DrvDocumentPropertySheets function is called.

When IPrintOemUI::DocumentPropertySheets is called, the lParamInit member of the PROPSHEETUI_INFO structure contains the address of an OEMUIPSPARAM structure.

If you implement this method, you will typically also supply a _CPSUICALLBACK-typed callback function to handle user modifications. This callback function must call IPrintOemDriverUI::DrvUpdateUISetting to inform the driver when the value associated with a user interface setting has been modified, if the value is stored in the driver's DEVMODE structure (instead of the plug-in's private DEVMODE members ) or in registry keys.

If IPrintOemUI::DocumentPropertySheets methods are exported by multiple user interface plug-ins, the methods are called in the order that the plug-ins are specified for installation.

If one user interface plug-in supports several printer models, and if you only want the new page to be displayed for some of those models, the IPrintOemUI::DocumentPropertySheets method should just provide a success return value, without actually adding the page, for the models not requiring the page.

For more information about creating and installing user interface plug-ins, see Customizing Microsoft's Printer Drivers.

See Also

DrvDocumentPropertySheets, IPrintOemUI::DevicePropertySheets, PFNPROPSHEETUI


IPrintOemUI::DriverEvent

The printer driver's DrvDriverEvent function calls a user interface plug-in's IPrintOemUI::DriverEvent method for additional processing of printer driver events.

STDMETHOD
  (DriverEvent) (
    THIS_
    DWORD  dwDriverEvent,
    DWORD  dwLevel,
    LPBYTE  pDriverInfo,
    LPARAM  lParam
    ) PURE;

Parameters

dwDriverEvent
Caller-supplied bit flag indicating the event that has occurred. Valid flags are listed in the following table.
Flag | Definition
DRIVER_EVENT_DELETE | The driver is being removed.
DRIVER_EVENT_INITIALIZE | The driver has just been installed.

dwLevel
Caller-supplied value indicating the type of structure pointed to by the pDriverInfo parameter, as indicated in the following table.
dwLevel Value | Structure pointed to by pDriverInfo
1 | DRIVER_INFO_1
2 | DRIVER_INFO_2
3 | DRIVER_INFO_3

The DRIVER_INFO_N structures are described in the Platform SDK documentation.

pDriverInfo
Caller-supplied pointer to a structure whose type is identified by the dwLevel parameter.
lParam
Caller-supplied flags. See the following Comments section.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

A user interface plug-in's IPrintOemUI::DriverEvent method performs the same types of operations as the DrvDriverEvent function that is exported by user-mode printer interface DLLs. For information about driver events and how they should be processed, see the description of the DrvDriverEvent function.

If you provide a user interface plug-in, the printer driver's DrvDriverEvent function calls the IPrintOemUI::DriverEvent method. The DrvDriverEvent function performs its own processing for the specified event, and then calls the IPrintOemUI::DriverEvent method to handle additional processing of the event.

If IPrintOemUI::DriverEvent methods are exported by multiple user interface plug-ins, the methods are called in the order that the plug-ins are specified for installation.

For more information about creating and installing user interface plug-ins, see Customizing Microsoft's Printer Drivers.

See Also

DrvDriverEvent


IPrintOemUI::FontInstallerDlgProc

A user interface plug-in's IPrintOemUI::FontInstallerDlgProc method replaces the Unidrv font installer's user interface.

STDMETHOD
  (FontInstallerDlgProc) (
    THIS_
    HWND  hWnd,
    UINT  usMsg,
    WPARAM  wParam,
    LPARAM  lParam
    ) PURE;

Parameters

hWnd
Window handle.
usMsg
Message identifier.
wParam
First message parameter.
lParam
Second message parameter.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

A user interface plug-in can implement the IPrintOemUI::FontInstallerDlgProc method as a means of replacing Unidrv's font installer. For more information, see Customized Font Installers for Unidrv.

The IPrintOemUI::FontInstallerDlgProc method is used by Unidrv as a dialog box procedure, and its address is passed to DialogBoxParam (described in the Platform SDK documentation) when a user invokes the font installer from Unidrv's user interface.

If the message received for usMsg is WM_INIT or WM_USER+WM_FI_NAME, lParam points to an OEMFONTINSTPARAM structure.

See Also

IPrintOemUI::UpdateExternalFonts


IPrintOemUI::GetInfo

A user interface plug-in's IPrintOemUI::GetInfo method returns identification information.

STDMETHOD
  (GetInfo) (
    THIS_
    DWORD  dwMode,
    PVOID  pBuffer,
    DWORD  cbSize,
    PDWORD  pcbNeeded
    ) PURE;

Parameters

dwMode
Contains one of the following caller-supplied integer constants.
Constant | Definition
OEMGI_GETSIGNATURE | The method must return a unique four-byte identification signature. The plug-in must also place this signature in OPTITEM structures, as described in the description of the OEMCUIPPARAM. structure's pOEMOptItems member.
OEMGI_GETVERSION | The method must return the user interface plug-in's version number as a DWORD. The version format is developer-defined.

pBuffer
Caller-supplied pointer to memory allocated to receive the information specified by dwMode.
cbSize
Caller-supplied size of the buffer pointed to by pBuffer.
pcbNeeded
Caller-supplied pointer to a location to receive the number of bytes written into the buffer pointed to by pBuffer.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

User interface plug-ins are required to implement the IPrintOemUI::GetInfo method, which is called immediately after the plug-in is loaded. The method should return the specified information by writing it to the address specified by pBuffer and writing the size, in bytes, of the returned information into the location specified by pcbNeeded.

If pBuffer is NULL, the method should just use pcbNeeded to return the number of bytes required to store the specified information.

For more information about creating and installing user interface plug-ins, see Customizing Microsoft's Printer Drivers.

See Also

IPrintOemPS::GetInfo IPrintOemUni::GetInfo


IPrintOemUI::PrinterEvent

The IPrintOemUI::PrinterEvent method allows a user interface plug-in to process printer events.

STDMETHOD
  (PrinterEvent) (
    THIS_
    PWSTR  pPrinterName,
    INT  iDriverEvent,
    DWORD  dwFlags,
    LPARAM  lParam
    ) PURE;

Parameters

pPrinterName
Caller-supplied pointer to a NULL-terminated printer name string. The string can identify a local printer ("PrinterName") or remote printer ("\\Machine\PrinterName").
iDriverEvent
Caller-supplied value identifying the event that has occurred. For a list of valid values, see DrvPrinterEvent.
dwFlags
Caller-supplied flags. For a list of valid flags, see DrvPrinterEvent.
lParam
Caller-supplied event-specific parameter. For more information, see DrvPrinterEvent.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

A user interface plug-in's IPrintOemUI::PrinterEvent method performs the same types of operations as the DrvPrinterEvent function that is exported by user-mode printer interface DLLs. For information about printer events and how they should be processed, see the description of the DrvPrinterEvent function.

If you provide a user interface plug-in, the printer driver's DrvPrinterEvent function calls the IPrintOemUI::PrinterEvent method. The DrvPrinterEvent function performs its own processing for the specified event, and then calls the IPrintOemUI::PrinterEvent method to handle additional processing of the event.

If IPrintOemUI::PrinterEvent methods are exported by multiple user interface plug-ins, the methods are called in the order that the plug-ins are specified for installation.

For more information about creating and installing user interface plug-ins, see Customizing Microsoft's Printer Drivers.

See Also

DrvPrinterEvent


IPrintOemUI::PublishDriverInterface

The IPrintOemUI::PublishDriverInterface method allows a user interface plug-in to obtain the Unidrv or Pscript5 driver's IPrintOemDriverUI interface or the Pscript5 driver's IPrintCoreUI2 interface.

STDMETHOD
  (PublishDriverInterface) (
    THIS_
    IUnknown  *pIUnknown
    ) PURE;

Parameters

pIUnknown
Caller-supplied pointer to the IUnknown interface of either the driver's IPrintCoreUI2 COM interface or its IPrintOemDriverUI COM interface.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The Pscript5 driver supports both the IPrintCoreUI2 and IPrintOemDriverUI interfaces. A Pscript5 user interface plug-in must implement the IPrintOemUI::PublishDriverInterface method. The Pscript5 driver first calls the IPrintOemUI::PublishDriverInterface method with the pIUnknown pointer set to the IPrintCoreUI2 instance's IUnknown interface. If the plug-in is able to use the IPrintCoreUI2 interface, the method must return S_OK. Otherwise, the plug-in should return E_FAIL, in which case the Pscript5 driver will call the IPrintOemUI::PublishDriverInterface method again, but with the pIUnknown pointer set to the IPrintOemDriverUI instance's IUnknown interface. This time, the method must return S_OK, or the driver will not call the plug-in's other IPrintOemUI interface methods.

Unidrv supports the IPrintOemDriverUI interface. A Unidrv user interface plug-in must implement the IPrintOemUI::PublishDriverInterface method and the method must return S_OK, or the driver will not call the plug-in's other IPrintOemUI interface methods.

If the user interface plug-in will be calling IPrintCoreUI2 or IPrintOemDriverUI interface methods, it must use the received IUnknown interface pointer to call IUnknown::QueryInterface (described in the Platform SDK documentation) in order to obtain a pointer to the driver's supported version of the IPrintCoreUI2 or IPrintOemDriverUI interface. For more information, see Interface Identifiers for Printer Drivers.


IPrintOemUI::QueryColorProfile

The IPrintOemUI::QueryColorProfile method allows a user interface plug-in to specify an ICC profile to use for color management.

STDMETHOD
  (QueryColorProfile) (
    THIS_
    HANDLE  hPrinter,
    POEMUIOBJ  poemuiobj,
    PDEVMODE  pPublicDM,
    PVOID  pOEMDM,
    ULONG  ulQueryMode,
    VOID  *pvProfileData,
    ULONG  *pcbProfileData,
    FLONG  *pflProfileData
    ) PURE;

Parameters

hPrinter
Caller-supplied printer handle.
poemuiobj
Caller-supplied pointer to an OEMUIOBJ structure.
pPublicDM
Caller-supplied pointer to a validated DEVMODE structure.
pOEMDM
Caller-supplied pointer to the user interface plug-in's private DEVMODE structure members.
ulQueryMode
One of the following caller-supplied bit flags, indicating the type of profile to be specified.
Flag | Definition
QCP_DEVICEPROFILE | The caller is requesting a device profile.
QCP_SOURCEPROFILE | The caller is requesting a source profile.

pvProfileData
Caller-supplied pointer to a buffer to receive profile information.
pcbProfileData
Caller-supplied pointer to a value representing the size, in bytes, of the buffer pointed to by pvProfileData.
pflProfileData
One of the following method-supplied bit flags, indicating the type of information the method is returning.
Flag | Definition
QCP_PROFILEDISK | The method is returning the file name of an ICC profile in the buffer pointed to by pvProfileData.
QCP_PROFILEMEMORY | The method is returning profile data in the buffer pointed to by pvProfileData.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

A user interface plug-in's IPrintOemUI::QueryColorProfile method performs the same types of operations as the DrvQueryColorProfile function that is exported by user-mode printer interface DLLs. For information about printer events and how they should be processed, see the description of the DrvQueryColorProfile function.

If you provide a user interface plug-in, the printer driver's DrvQueryColorProfile function calls the IPrintOemUI::QueryColorProfile method. The DrvQueryColorProfile function performs its own processing for the specified event, and then calls the IPrintOemUI::QueryColorProfile method to handle additional processing of the event.

If IPrintOemUI::QueryColorProfile methods are exported by multiple user interface plug-ins, the methods are called in the order that the plug-ins are specified for installation.

For more information about creating and installing user interface plug-ins, see Customizing Microsoft's Printer Drivers.


IPrintOemUI::UpdateExternalFonts

The IPrintOemUI::UpdateExternalFonts method allows a user interface plug-in to update a printer's Unidrv Font Format file (.uff file).

STDMETHOD
  (UpdateExternalFonts) (
    THIS_
    HANDLE  hPrinter,
    HANDLE  hHeap,
    PWSTR  pwstrCartridges
    ) PURE;

Parameters

hPrinter
Caller-supplied printer handle.
hHeap
Caller-supplied handle to heap memory the method can use for local storage.
pwstrCartridges
Caller-supplied pointer to an array of strings representing the names of all cartridges currently installed on the printer.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

A user interface plug-in must implement the IPrintOemUI::UpdateExternalFonts method if the plug-in is replacing Unidrv's default font installer. For more information, see Customized Font Installers for Unidrv.

The IPrintOemUI::UpdateExternalFonts method's purpose is to examine the list of installed cartridges (supplied by pwstrCartridges) and insure that the .uff file specified by the "ExternalFontFile" registry value contains font descriptions for only the cartridge fonts contained in the installed cartridges. (This .uff file can also contain descriptions of PCL-downloadable soft fonts.)

Descriptions of cartridge fonts can be copied from the .uff file specified by the "ExtFontCartFile" registry value. For more information, see Unidrv Font Format files.

See Also

IPrintOemUI::FontInstallerDlgProc


IPrintOemUI::UpgradePrinter

The IPrintOemUI::UpgradePrinter method allows a user interface plug-in to upgrade device option values that are stored in the registry.

STDMETHOD
  (UpgradePrinter) (
    THIS_
    DWORD  dwLevel,
    PBYTE  pDriverUpgradeInfo
    ) PURE;

Parameters

dwLevel
Caller-supplied version number of the structure pointed to by pDriverUpgradeInfo. Current valid value is 1.
pDriverUpgradeInfo
Caller-supplied pointer to a DRIVER_UPGRADE_INFO_1 structure.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

If you provide a user interface plug-in for one of Microsoft's printer drivers, and if the user interface plug-in stores device option values in the registry, it should implement the IPrintOemUI::UpgradePrinter method to update those values.

A user interface plug-in's IPrintOemUI::UpgradePrinter method performs the same types of operations as the DrvUpgradePrinter function that is exported by user-mode printer interface DLLs. When the driver's DrvUpgradePrinter function is called, it updates its own registry values and then calls the IPrintOemUI::UpgradePrinter method.

If IPrintOemUI::UpgradePrinter methods are exported by multiple user interface plug-ins, the methods are called in the order that the plug-ins are specified for installation.

For more information about creating and installing user interface plug-ins, see Customizing Microsoft's Printer Drivers.


IPrintOemUI2 Interface

This section describes the methods defined for the IPrintOemUI2 COM interface. Method prototypes are defined in prcomoem.h.


IPrintOemUI2::DocumentEvent

The IPrintOemUI2::DocumentEvent method allows a UI plug-in to replace the core driver UI module's default implementation of the DrvDocumentEvent DDI.

STDMETHOD
  (DocumentEvent) (
    THIS_
    IN HANDLE  hPrinter,
    IN HDC  hdc,
    IN INT  iEsc,
    IN ULONG  cbIn,
    IN PVOID  pvIn,
    IN ULONG  cbOut,
    OUT PVOID pvOut,
    OUT PINT  piResult
    ) PURE;

Parameters

hPrinter
Is a caller-supplied printer handle.
hdc
Is a caller-supplied device context handle, generated by a CreateDC call. This is zero if iEsc is DOCUMENTEVENT_CREATEDCPRE.
iEsc
Is a caller-supplied escape code identifying the event to be handled. This parameter can be one of the following integer constants:
Escape Code | Meaning
DOCUMENTEVENT_ABORTDOC | GDI is about to process a call to its AbortDoc function.
DOCUMENTEVENT_CREATEDCPOST GDI has just processed a call to its CreateDC or CreateIC function.
This escape code should not be used unless there has been a previous call to DrvDocumentEvent with iEsc set to DOCUMENTEVENT_CREATEDCPRE.
DOCUMENTEVENT_CREATEDCPRE | GDI is about to process a call to its CreateDC or CreateIC function.
DOCUMENTEVENT_DELETEDC | GDI is about to process a call to its DeleteDC function.
DOCUMENTEVENT_ENDDOCPOST | GDI has just processed a call to its EndDoc function.
DOCUMENTEVENT_ENDDOCPRE
or DOCUMENTEVENT_ENDDOC 		GDI is about to process a call to its EndDoc function.
DOCUMENTEVENT_ENDPAGE | GDI is about to process a call to its EndPage function.
DOCUMENTEVENT_ESCAPE | GDI is about to process a call to its ExtEscape function.
DOCUMENTEVENT_QUERYFILTER | The DOCUMENTEVENT_QUERYFILTER event represents an opportunity for the spooler to query the driver for a list of the DOCUMENTEVENT_XXX events to which the driver will respond. This event is issued just prior to a call to DrvDocumentEvent that passes the DOCUMENTEVENT_CREATEDCPRE event.
DOCUMENTEVENT_RESETDCPOST GDI has just processed a call to its ResetDC function.
This escape code should not be used unless there has been a previous call to DrvDocumentEvent with iEsc set to DOCUMENTEVENT_RESETDCPRE.
DOCUMENTEVENT_RESETDCPRE | GDI is about to process a call to its ResetDC function.
DOCUMENTEVENT_STARTDOCPOST | GDI has just processed a call to its StartDoc function.
DOCUMENTEVENT_STARTDOCPRE
or DOCUMENTEVENT_STARTDOC 		GDI is about to process a call to its StartDoc function.
DOCUMENTEVENT_STARTPAGE | GDI is about to process a call to its StartPage function.

cbIn
Is the caller-supplied size, in bytes, of the buffer pointed to by pvIn.
pvIn
Caller-supplied pointer, the use of which is dependent on the value supplied for iEsc, as follows:
iEsc Constant | pvIn Contents
DOCUMENTEVENT_ABORTDOC | Not used.
DOCUMENTEVENT_CREATEDCPOST | pvIn contains the address of a pointer to the DEVMODE structure specified in the pvOut parameter in a previous call to this function, for which the iEsc parameter was set to DOCUMENTEVENT_CREATEDCPRE.
DOCUMENTEVENT_CREATEDCPRE | pvIn points to a DOCEVENT_CREATEDCPRE structure.
DOCUMENTEVENT_DELETEDC | Not used.
DOCUMENTEVENT_ENDDOCPOST | Not used.
DOCUMENTEVENT_ENDDOCPRE
or DOCUMENTEVENT_ENDDOC 		Not used.
DOCUMENTEVENT_ENDPAGE | Not used.
DOCUMENTEVENT_ESCAPE | pvIn points to a DOCEVENT_ESCAPE structure.
DOCUMENTEVENT_QUERYFILTER | Same as for DOCUMENTEVENT_CREATEDCPRE.
DOCUMENTEVENT_RESETDCPOST | pvIn contains the address of a pointer to the DEVMODE structure specified in the pvOut parameter in a previous call to this function, for which the iEsc parameter was set to DOCUMENTEVENT_RESETDCPRE.
DOCUMENTEVENT_RESETDCPRE | pvIn contains the address of a pointer to a DEVMODE structure supplied by the caller of ResetDC (described in the Platform SDK documentation).
DOCUMENTEVENT_STARTDOCPOST | pvIn points to a LONG that specifies the print job identifier returned by StartDoc (described in the Platform SDK documentation).
DOCUMENTEVENT_STARTDOCPRE
or DOCUMENTEVENT_STARTDOC 		pvIn contains the address of a pointer to a DOCINFO structure supplied by the caller of StartDoc (both described in the Platform SDK documentation).
DOCUMENTEVENT_STARTPAGE | Not used.

cbOut
If iEsc is DOCUMENTEVENT_ESCAPE:
Function-supplied value that will be used as the cbOutput parameter for ExtEscape.
If iEsc is DOCUMENTEVENT_QUERYFILTER:
Caller-supplied size, in bytes, of the buffer pointer to by pvOut.
For all other iEsc values:
Not used.
pvOut
Is a function-supplied pointer to an output buffer, the use of which is dependent on the value supplied for iEsc, as follows. CreateDC, ExtEscape, and ResetDC are described in the Platform SDK documentation.
iEsc Constant | pvOut Contents
DOCUMENTEVENT_CREATEDCPRE | Pointer to a driver-supplied DEVMODE structure, which GDI uses instead of the one supplied by the CreateDC caller. (If NULL, GDI uses the caller-supplied structure.)
DOCUMENTEVENT_ESCAPE | Buffer pointer that will be used as the lpszOutData parameter for ExtEscape.
DOCUMENTEVENT_QUERYFILTER | Caller-supplied pointer to buffer containing a DOCEVENT_FILTER structure.
DOCUMENTEVENT_RESETDCPRE | Pointer to a driver-supplied DEVMODE structure, which GDI uses instead of the one supplied by the ResetDC caller. (If NULL, GDI uses the caller-supplied structure.)
All other iEsc values | Not used.

piResult
Points to a memory location that will receive one of the following values:
Return Value | Definition
DOCUMENTEVENT_FAILURE | The driver supports the escape code identified by iEsc, but a failure occurred.
DOCUMENTEVENT_SUCCESS | The driver successfully handled the escape code identified by iEsc. Also see the Comments section for more information.
DOCUMENTEVENT_UNSUPPORTED | The driver does not support the escape code identified by iEsc.

Return Value

This method should return one of the following values. See the Comments section for more information.

Value | Meaning
S_OK | The UI plug-in implements this method.
E_NOTIMPL | The UI plug-in does not implement this method.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

A user interface plug-in's IPrintOemUI2::DocumentEvent method performs the same types of operations as the DrvDocumentEvent DDI that is exported by user-mode printer interface DLLs. For information about document events and how they should be processed, see the description of the DrvDocumentEvent DDI.

If you provide a user interface plug-in, the printer driver's DrvDocumentEvent DDI calls the IPrintOemUI2::DocumentEvent method. The DrvDocumentEvent DDI performs its own processing for the specified event, and then calls the IPrintOemUI2::DocumentEvent method to handle additional processing of the event.

When this method is called with a value of the iEsc parameter of DOCUMENTEVENT_QUERYFILTER, and returns with *piResult == DOCUMENTEVENT_SUCCESS, the spooler can interpret this value in either of two ways, depending on whether certain members of the DOCEVENT_FILTER structure changed values. For more information, see the Comments section for DrvDocumentEvent.

When the DOCUMENTEVENT_QUERYFILTER event is fired, the core driver calls plug-ins in the order they were installed, until one of them returns S_OK, or until all of the plug-ins have been called and none of them returned S_OK. In this way, at most one plug-in is allowed to handle the DOCUMENTEVENT_QUERYFILTER event, and the filter it specifies will be applied to all plug-ins in the plug-in chain.

For a plug-in writer who is implementing the IPrintOemUI2 interface, but does not need to support the IPrintOemUI2::DocumentEvent method, this method should return E_NOTIMPL for all values of iEsc. If you do need to implement this method, it should return S_OK for all values of iEsc. This signals the core driver that this method has handled the relevant event. The core driver will use the value that this method places in piResult as the return value for the DrvDocumentEvent DDI.

See Also

DrvDocumentEvent, DOCEVENT_FILTER, DOCEVENT_CREATEDCPRE, DOCEVENT_ESCAPE


IPrintOemUI2::HideStandardUI

The IPrintOemUI2::HideStandardUI method allows a Windows XP Pscript5 user interface plug-in to specify whether the standard property sheets should be displayed or hidden.

STDMETHOD
  (HideStandardUI) (
    THIS_
    IN DWORD  dwMode
    ) PURE;

Parameters

dwMode
Specifies which type of property sheet UI — document property sheet or device property sheet — to hide. This parameter should be set to one of the following constants, which are defined in printoem.h:
Value | Meaning
OEMCUIP_DOCPROP | Hide standard document property sheet UI.
OEMCUIP_PRNPROP | Hide standard device property sheet UI.

Return Value

On success, this method should return S_OK. Otherwise, it should return E_NOTIMPL. See Comments for additional information.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

This method is supported only for Windows XP Pscript5 plug-ins, not for Unidrv plug-ins.

Within the DrvDocumentPropertySheets or DrvDevicePropertySheets DDIs when pPSUIInfo—>Reason is set to PROPSHEETUI_REASON_INIT, the driver calls the IPrintOemUI2::HideStandardUI method to ask the UI plug-in about user interface requests. This method can respond in any of four ways:

  1. Hide standard document property sheet UI.
  2. Hide standard device property sheet UI.
  3. Hide all standard property sheet UI.
  4. Do not hide any standard property sheet UI.

The following table summarizes how the IPrintOemUI2::HideStandardUI method would respond in each of these situations.

To indicate this response... | IPrintOemUI2::HideStandardUI returns...
Hide standard document property sheet UI. The plug-in implements its own document property sheet UI. | If dwMode == OEMCUIP_DOCPROP, return S_OK; otherwise return E_NOTIMPL.
Hide standard device property sheet UI. The plug-in implements its own device property sheet UI. | If dwMode == OEMCUIP_PRNPROP, return S_OK; otherwise return E_NOTIMPL.
Hide all standard property sheet UI. The plug-in implements its own document property sheet and device property sheet UI. | Return S_OK, regardless of the value of dwMode.
Display all standard property sheet UI. | Return E_NOTIMPL, regardless of the value of dwMode.

If the IPrintOemUI2::HideStandardUI method indicates to the driver that all standard property sheets should be hidden, the driver will omit calls to compstui.dll (see Pscript Components) to add the standard property sheets. A UI plug-in must implement at least one custom property sheet UI if IPrintOemUI2::HideStandardUI returns S_OK.

When the printer has multiple UI plug-ins installed, the driver calls UI plug-ins in the order they were installed, until one of them returns S_OK, or until all of the UI plug-ins have been called and none of them returned S_OK. The former case indicates to the driver that the standard property sheet UI should be hidden. The latter case indicates to the driver that the standard property sheet UI should be displayed.

See Also

DrvDocumentPropertySheets, DrvDevicePropertySheets


IPrintOemUI2::QueryJobAttributes

The IPrintOemUI2::QueryJobAttributes method allows a UI plug-in to post-process the core driver's results after a call to the DrvQueryJobAttributes DDI. The plug-in can choose to overwrite the values that the core driver placed in the lpAttributeInfo output buffer.

STDMETHOD
  (QueryJobAttributes) (
    THIS_
    IN HANDLE  hPrinter,
    IN PDEVMODE  pDevmode,
    IN DWORD  dwLevel,
    OUT LPBYTE  lpAttributeInfo
    ) PURE;

Parameters

hPrinter
Specifies the caller-supplied printer handle.
pDevmode
Points to a caller-supplied DEVMODE structure.
dwLevel
Specifies a caller-supplied value indicating the type of structure pointed to by lpAttributeInfo, as indicated in the following table.
Value | Structure Pointed to by lpAttributeInfo
1 | ATTRIBUTE_INFO_1
2 | ATTRIBUTE_INFO_2
3 | ATTRIBUTE_INFO_3

Note that if this method changes any dwDrvXxx member of the ATTRIBUTE_INFO_N structures, the spooler assumes that the plug-in is able to support the behavior represented by that member.

lpAttributeInfo
Points to a memory location that will receive the address of a structure of the type identified by dwLevel.

Return Value

If the UI plug-in supports this method, and the method succeeded, it should return S_OK. This causes the core driver to return TRUE for the DrvQueryJobAttributes DDI. If the UI plug-in supports this method, but the method failed, it should return E_FAIL. This causes the core driver to return FALSE for the DrvQueryJobAttributes DDI. If the UI plug-in does not support this method, it should return E_NOTIMPL.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

When the printer has multiple UI plug-ins installed, the core driver calls the UI plug-ins in the order they were installed. The HRESULT returned by the last UI plug-in that supports this method is used to determine the core driver's DrvQueryJobAttributes DDI return value as described in the previous section.

See DrvQueryJobAttributes for more information.

See Also

DrvQueryJobAttributes, DEVMODE, ATTRIBUTE_INFO_1, ATTRIBUTE_INFO_2, ATTRIBUTE_INFO_3


IPrintOemDriverUI Interface

This section describes the methods defined for the IPrintOemDriverUI COM interface. Method prototypes are defined in prcomoem.h.


IPrintOemDriverUI::DrvGetDriverSetting

The IPrintOemDriverUI::DrvGetDriverSetting method is provided by the Unidrv and Pscript5 minidrivers so that user interface plug-ins can obtain the current status of printer features and other internal information.

STDMETHOD
  (DrvGetDriverSetting) (
    THIS_
    PVOID  pci,
    PCSTR  Feature,
    PVOID  pOutput,
    DWORD  cbSize,
    PDWORD  pcbNeeded,
    PDWORD  pdwOptionsReturned
    ) PURE;

Parameters

pci
Caller-supplied pointer to an OEMUIOBJ structure.
Feature
Caller-supplied value identifying the printer feature for which option settings will be returned. This can be either a string pointer or a constant, as described in the following Comments section.
pOutput
Caller-supplied pointer to a buffer to receive the specified information.
cbSize
Caller-supplied size, in bytes, of the buffer pointed to by pOutput.
pcbNeeded
Caller-supplied pointer to a location to receive the minimum buffer size required to contain the requested information.
pdwOptionsReturned
Caller-supplied pointer to a location to receive the number of option strings placed in pOutput.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

When calling the IPrintOemDriverUI::DrvGetDriverSetting method, a user interface plug-in can specify either a string pointer or a constant value for pFeatureKeyword.

  • If pFeatureKeyword is a string, it must represent one of the following:
    • A feature name specified in a Unidrv minidriver GPD file, or,
    • A keyword argument to an *OpenUI entry in a Pscript5 minidriver's PPD file.

    The method returns one or more NULL-terminated strings in the buffer pointed to by pOutput. Each string represents the name of a currently selected option.The number of strings is returned in pdwOptionsReturned.

  • If pFeatureKeyword is a constant, it must be one of the OEMGDS_-prefixed constants defined in printoem.h. The method returns the value indicated by the specified constant by placing it in the buffer pointed to by pOutput. The value returned in pdwOptionsReturned is always 1.


IPrintOemDriverUI::DrvUpdateUISetting

The IPrintOemDriverUI::DrvUpdateUISetting method is provided by the Unidrv and Pscript5 minidrivers so that user interface plug-ins can notify the driver of a modified user interface option.

STDMETHOD
  (DrvUpdateUISetting) (
    THIS_
    PVOID  pci,
    PVOID  pOptItem,
    DWORD  dwPreviousSelection,
    DWORD  dwMode
    ) PURE;

Parameters

pci
Caller-supplied pointer to an OEMUIOBJ structure.
pOptItem
Caller-supplied pointer to an OPTITEM structure describing a user interface option item.
dwPreviousSelection
Not used.
dwMode
Caller-supplied integer constant indicating to which property sheet page the supplied option item belongs. The following constants are valid.
Value | Definition
OEMCUIP_DOCPROP | The supplied option item belongs to the Advanced page of the document property sheet.
OEMCUIP_PRNPROP | The supplied option item belongs to the Device Settings page of the printer property sheet.

For more information, see the following Comments section.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

If you are providing a user interface plug-in that implements the IPrintOemUI::DocumentPropertySheets method or the IPrintOemUI::DevicePropertySheets method, you will typically also supply a _CPSUICALLBACK-typed callback function to handle user modifications. This callback function must call IPrintOemDriverUI::DrvUpdateUISetting to inform the driver when the value associated with a user interface setting has been modified, if the value is stored in the driver's DEVMODE structure (instead of the plug-in's private DEVMODE members ) or in registry keys.

The value specified for dwMode should be based on which method specified the callback function.


IPrintOemDriverUI::DrvUpgradeRegistrySetting

The IPrintOemDriverUI::DrvUpdateRegistrySetting method is provided by the Unidrv and Pscript5 minidrivers so that user interface plug-ins can update device settings stored in the registry.

STDMETHOD
  (DrvUpgradeRegistrySetting) (
    THIS_
    HANDLE  hPrinter,
    PCSTR  pFeature,
    PCSTR  pOption
    ) PURE;

Parameters

hPrinter
Caller-supplied printer handle.
pFeature
Caller-supplied pointer to a string identifying a printer feature name contained in the printer's GPD or PPD file.
pOption
Caller-supplied pointer to a string identifying an option name, associated with the specified feature, contained in the printer's GPD or PPD file.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemDriverUI::DrvUpdateRegistrySetting method is meant to be called from a user interface plug-in's IPrintOemUI::UpgradePrinter method, when it is necessary to update registry settings that were stored in private registry keys for an earlier version of the driver, but are now contained in a GPD or PPD file.


IPrintCoreUI2 Interface

This section describes the methods defined for the IPrintCoreUI2 COM interface. This interface inherits from the IPrintOemDriverUI COM interface. The methods in this interface are provided by the Windows XP Pscript5 driver, for the sole use of its user interface plug-ins. Method prototypes appear in prcomoem.h.


IPrintCoreUI2::DrvGetDriverSetting

The IPrintCoreUI2::DrvGetDriverSetting method is provided by the Windows XP Pscript5 driver so that Pscript5 user interface plug-ins can obtain the current status of printer features and other internal information.

STDMETHOD
  (DrvGetDriverSetting) (
    THIS_
    PVOID  pci,
    PCSTR  Feature,
    PVOID  pOutput,
    DWORD  cbSize,
    PDWORD  pcbNeeded,
    PDWORD  pdwOptionsReturned
    ) PURE;

This method is inherited from the IPrintOemDriverUI COM interface, and can be called only by Windows XP Pscript5 UI plug-ins that do not fully replace the core driver's standard UI pages, and is supported during the UI plug-in's IPrintOemUI::DocumentPropertySheets and IPrintOemUI::DevicePropertySheets functions, and their property sheet callback routines. When this method is supported, it has the same behavior as IPrintOemDriverUI::DrvGetDriverSetting. When it is not supported, this method should return E_NOTIMPL.

Headers

Declared in prcomoem.h. Include prcomoem.h.

See Also

IPrintOemDriverUI::DrvGetDriverSetting, IPrintOemUI::DocumentPropertySheets, IPrintOemUI::DevicePropertySheets


IPrintCoreUI2::DrvUpdateUISetting

The IPrintCoreUI2::DrvUpdateUISetting method is provided by the Windows XP Pscript5 driver so that Pscript5 user interface plug-ins can notify the driver of a modified user interface option.

STDMETHOD
  (DrvUpdateUISetting) (
    THIS_
    PVOID  pci,
    PVOID  pOptItem,
    DWORD  dwPreviousSelection,
    DWORD  dwMode
    ) PURE;

This method is inherited from the IPrintOemDriverUI COM interface, and can be called only by Windows XP Pscript5 UI plug-ins that do not fully replace the core driver's standard UI pages, and is supported during the UI plug-in's IPrintOemUI::DocumentPropertySheets and IPrintOemUI::DevicePropertySheets functions, and their property sheet callback routines. When this method is supported, it has the same behavior as IPrintOemDriverUI::DrvUpdateUISetting. When it is not supported, this method should return E_NOTIMPL.

Headers

Declared in prcomoem.h. Include prcomoem.h.

See Also

IPrintOemDriverUI::DrvUpdateUISetting, IPrintOemUI::DocumentPropertySheets, IPrintOemUI::DevicePropertySheets


IPrintCoreUI2::DrvUpgradeRegistrySetting

The IPrintCoreUI2::DrvUpgradeRegistrySetting method is provided by the Windows XP Pscript5 driver so that Pscript5 user interface plug-ins can update device settings stored in the registry.

STDMETHOD
  (DrvUpgradeRegistrySetting) (
    THIS_
    HANDLE  hPrinter,
    PCSTR  pFeature,
    PCSTR  pOption
    ) PURE;

This method is inherited from the IPrintOemDriverUI COM interface, which includes a DrvUpgradeRegistrySetting method. The behavior of this method is exactly the same as that of IPrintOemDriverUI::DrvUpgradeRegistrySetting.

This method should be called only by the OEM's IPrintOemUI::UpgradePrinter method.

Headers

Declared in prcomoem.h. Include prcomoem.h.

See Also

IPrintOemDriverUI::DrvUpgradeRegistrySetting


IPrintCoreUI2::EnumConstrainedOptions

The IPrintCoreUI2::EnumConstrainedOptions method determines which options of a feature are constrained.

STDMETHOD
  (EnumConstrainedOptions) (
    THIS_
    IN POEMUIOBJ  poemuiobj,
    IN DWORD  dwFlags,
    IN PCSTR  pszFeatureKeyword,
    OUT PSTR  pmszConstrainedOptionList,
    IN DWORD  cbSize,
    OUT PDWORD  pcbNeeded
    ) PURE;

Parameters

poemuiobj
Points to the current context, an OEMUIOBJ structure.
dwFlags
Is reserved and must be set to zero.
pszFeatureKeyword
Points to a caller-supplied buffer containing the single feature keyword of interest to the caller.
pmszConstrainedOptionList
Points to a caller-supplied buffer that will receive the list of option keywords, in MULTI_SZ format, for this feature. Each keyword represents an option that is constrained in the current configuration.

Set this parameter to NULL to simply query for the size (*pcbNeeded) of the constrained option list without having the list filled in.

cbSize
Specifies the size, in bytes, of the buffer pointed to by pmszConstrainedOptionList.
pcbNeeded
Points to a memory location that will receive the actual size, in bytes, of the constrained option list.

Return Value

This method must return one of the values shown in the following table:

Return Value | Meaning
S_OK | The method succeeded. The method should also return this value if none of the feature's options are constrained. In this case, the method should place one NULL character into the buffer pointed to by pmszConstrainedOptionList, and should set *pcbNeeded to 1.
E_OUTOFMEMORY | The value in cbSize was smaller than the number of bytes to be written to the output buffer (the buffer pointed to by pmszConstrainedOptionList). The method was called with pmszConstrainedOptionList set to NULL.
E_INVALIDARG | The string pointed to by pszFeatureKeyword was not a recognized feature. The poemuiobj parameter pointed to an invalid context object. The stickiness of the feature did not match that of the context object pointed to by peomuiobj. (See Replacing Driver-Supplied Property Sheet Pages.)
E_NOTIMPL | The method is not supported.
E_FAIL | The method failed.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

This method is supported only for Windows XP Pscript5 UI plug-ins that fully replace the core driver's standard UI pages, and is supported only during the UI plug-in's IPrintOemUI::DocumentPropertySheets and IPrintOemUI::DevicePropertySheets functions, and their property sheet callback routines. See Replacing Driver-Supplied Property Sheet Pages for more information.

To reduce the need to make two calls per data access, pass the method an output buffer of a fixed size (1 KB, for example), and then check the function return value. If the method returns S_OK, the buffer will already contain the data of interest. If the method returns E_OUTOFMEMORY, the value in *pcbNeeded will be the buffer size needed to hold the data of interest. The caller should then allocate a buffer of that larger size and proceed with a second call to the method.

See Also

OEMUIOBJ, IPrintOemUI::DocumentPropertySheets, IPrintOemUI::DevicePropertySheets, IPrintCoreUI2::WhyConstrained


IPrintCoreUI2::EnumFeatures

The IPrintCoreUI2::EnumFeatures method enumerates a printer's available features.

STDMETHOD
  (EnumFeatures) (
    THIS_
    IN  POEMUIOBJ  poemuiobj,
    IN  DWORD  dwFlags,
    OUT PSTR  pmszFeatureList,
    IN  DWORD  cbSize,
    OUT PDWORD  pcbNeeded
    ) PURE;

Parameters

poemuiobj
Points to the current context, an OEMUIOBJ structure.
dwFlags
Is reserved and must be set to zero.
pmszFeatureList
Points to a caller-supplied buffer that will receive a NULL-delimited list of feature keywords in MULTI_SZ format. The list is terminated with two NULL characters.

Set this parameter to NULL to simply query for the size (*pcbNeeded) of the feature list without having the list filled in.

cbSize
Specifies the size, in bytes, of the buffer pointed to by pmszFeatureList.
pcbNeeded
Points to a memory location that will receive the actual size, in bytes, of the feature list.

Return Value

This method must return one of the values shown in the following table:

Return Value | Meaning
S_OK | The method succeeded.
E_OUTOFMEMORY | The value in cbSize was smaller than the number of bytes to be written to the output buffer (the buffer pointed to by pmszFeatureList). The method was called with pmszFeatureList set to NULL.
E_INVALIDARG | The poemuiobj parameter pointed to an invalid context object.
E_FAIL | The method failed.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

This method is supported only for Windows XP Pscript5 plug-ins, not for Unidrv plug-ins.

Printer-sticky features (see Replacing Driver-Supplied Property Sheet Pages), such as those that determine installable memory and the presence of optional accessories, are included in the feature keyword list, which appears in the output buffer pointed to by pmszFeatureList when the method returns. For Pscript5, such features will have the OpenGroupType feature attribute set to "InstallableOptions".

To reduce the need to make two calls per data access, pass the method an output buffer of a fixed size (1 KB, for example), and then check the function return value. If the method returns S_OK, the buffer will already contain the data of interest. If the method returns E_OUTOFMEMORY, the value in *pcbNeeded will be the buffer size needed to hold the data of interest. The caller should then allocate a buffer of that larger size and proceed with a second call to the method.

For more information, see Using EnumFeatures.

See Also

OEMUIOBJ, IPrintCoreUI2::EnumOptions


IPrintCoreUI2::EnumOptions

The IPrintCoreUI2::EnumOptions method enumerates the available options of a specific feature.

STDMETHOD
  (EnumOptions) (
    THIS_
    IN POEMUIOBJ  poemuiobj,
    IN DWORD  dwFlags,
    IN PCSTR  pszFeatureKeyword,
    OUT PSTR  pmszOptionList,
    IN DWORD  cbSize,
    OUT PDWORD  pcbNeeded
    ) PURE;

Parameters

poemuiobj
Points to the current context, an OEMUIOBJ structure.
dwFlags
Is reserved and must be set to zero.
pszFeatureKeyword
Points to a caller-supplied buffer containing an ASCII string specifying a feature keyword whose options are requested.
pmszOptionList
Points to a caller-supplied buffer that will receive a NULL-delimited list, in MULTI_SZ format, containing the option keywords for the feature keyword pointed to by pszFeatureKeyword. This list is terminated with two NULL characters.

Set this parameter to NULL to simply query for the size (*pcbNeeded) of the option list without having the list filled in.

cbSize
Specifies the size, in bytes, of the buffer pointed to by pmszOptionList.
pcbNeeded
Points to a memory location that will receive the actual size, in bytes, of the option list.

Return Value

This method must return one of the values shown in the following table:

Return Value | Meaning
S_OK | The method succeeded.
E_OUTOFMEMORY | The value in cbSize was smaller than the number of bytes to be written to the output buffer (the buffer pointed to by pmszOptionList). The method was called with pmszOptionList set to NULL.
E_INVALIDARG | The string pointed to by pszFeatureKeyword is not a recognized feature. The poemuiobj parameter pointed to an invalid context object.
E_NOTIMPL | (Pscript only) The Pscript5 driver feature is not supported under the current configuration. The Pscript5 driver feature is supported under the current configuration, but the Pscript5 driver feature's options are not enumerable.
E_FAIL | The method failed.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

This method is supported only for Windows XP Pscript5 plug-ins, not for Unidrv plug-ins.

To reduce the need to make two calls per data access, pass the method an output buffer of a fixed size (1 KB, for example), and then check the function return value. If the method returns S_OK, the buffer will already contain the data of interest. If the method returns E_OUTOFMEMORY, the value in *pcbNeeded will be the buffer size needed to hold the data of interest. The caller should then allocate a buffer of that larger size and proceed with a second call to the method.

For more information, see Using EnumOptions.

See Also

OEMUIOBJ, IPrintCoreUI2::EnumFeatures


IPrintCoreUI2::GetFeatureAttribute

The IPrintCoreUI2::GetFeatureAttribute method retrieves the feature attribute list or the value of a specific feature attribute.

STDMETHOD
  (GetFeatureAttribute) (
    THIS_
    IN POEMUIOBJ  poemuiobj,
    IN DWORD  dwFlags,
    IN PCSTR  pszFeatureKeyword,
    IN PCSTR  pszAttribute,
    OUT PDWORD  pdwDataType,
    OUT PBYTE  pbData,
    IN DWORD  cbSize,
    OUT PDWORD  pcbNeeded
    ) PURE;

Parameters

poemuiobj
Points to the current context, an OEMUIOBJ structure.
dwFlags
Is reserved and must be set to zero.
pszFeatureKeyword
Points to a caller-supplied buffer containing an ASCII string specifying the single feature keyword to query for. This value can be obtained from a prior call to IPrintCoreUI2::EnumFeatures.
pszAttribute
Points to a caller-supplied buffer containing an ASCII string specifying the single attribute requested. If this parameter is NULL, the caller is requesting a list of all supported feature attribute names, as opposed to specifying a specific feature attribute name.
pdwDataType
Points to a memory location that will receive a value specifying the data type of the requested attribute. This value is an enumerator of the EATTRIBUTE_DATATYPE enumeration, which is defined in printoem.h.
pbData
Points to a caller-supplied buffer that will receive the requested data. To simply query for the number of bytes needed to fulfill a request, set this parameter to NULL.
cbSize
Specifies the size, in bytes of the buffer pointed to by pbData.
pcbNeeded
Points to a memory location that will receive the actual size, in bytes, of the requested data.

Return Value

This method must return one of the values shown in the following table:

Return Value | Meaning
S_OK | The method succeeded.
E_OUTOFMEMORY | The value in cbSize was smaller than the number of bytes to be written to the output buffer (the buffer pointed to by pbData). The method was called with pbData set to NULL.
E_INVALIDARG | The method attempted to query for a nonexistent attribute. The feature keyword was not recognized. The poemuiobj parameter pointed to an invalid context object.
E_FAIL | The method failed.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

This method is supported only for Windows XP Pscript5 plug-ins, not for Unidrv plug-ins.

If this method is called with its pszAttribute and pbData parameters set to NULL, the method will return with *pcbNeeded set to the number of bytes needed for the list of all supported attribute names for the feature. If the method is called a second time, with pszAttribute set to NULL and pbData pointing to a buffer of the size specified in *pcbNeeded in the previous call, the method will return with *pdwDataType set to kADT_ASCII (an enumerator of the EATTRIBUTE_DATATYPE enumerated type) and pbData pointing to a NULL-delimited list of all supported attribute names for the feature. This list will be terminated with two NULL characters.

To reduce the need to make two calls per data access, pass the method an output buffer of a fixed size (1 KB, for example), and then check the function return value. If the method returns S_OK, the buffer will already contain the data of interest. If the method returns E_OUTOFMEMORY, the value in *pcbNeeded will be the buffer size needed to hold the data of interest. The caller should then allocate a buffer of that larger size and proceed with a second call to the method.

For more information, see Using GetFeatureAttribute.

See Also

OEMUIOBJ, IPrintCoreUI2::EnumFeatures, IPrintCoreUI2::GetGlobalAttribute, IPrintCoreUI2::GetOptionAttribute


IPrintCoreUI2::GetGlobalAttribute

The IPrintCoreUI2::GetGlobalAttribute method retrieves the global attribute list or the value of a specific global attribute.

STDMETHOD
  (GetGlobalAttribute) (
    THIS_
    IN POEMUIOBJ  poemuiobj,
    IN DWORD  dwFlags,
    IN PCSTR  pszAttribute,
    OUT PDWORD  pdwDataType,
    OUT PBYTE  pbData,
    IN DWORD  cbSize,
    OUT PDWORD  pcbNeeded
    ) PURE;

Parameters

poemuiobj
Points to the current context, an OEMUIOBJ structure.
dwFlags
Is reserved and must be set to zero.
pszAttribute
Points to a caller-supplied buffer containing an ASCII string specifying the single attribute requested. If this parameter is NULL, the caller is requesting a list of all supported global attribute names, as opposed to specifying a specific global attribute name.
pdwDataType
Points to a memory location that will receive a value specifying the data type of the requested attribute. This value is an enumerator of the EATTRIBUTE_DATATYPE enumeration, which is defined in printoem.h.
pbData
Points to a caller-supplied buffer that will receive the requested data. To simply query for the number of bytes needed to fulfill a request, set this parameter to NULL.
cbSize
Specifies the size, in bytes of the buffer pointed to by pbData.
pcbNeeded
Points to a memory location that will receive the actual size, in bytes, of the requested data.

Return Value

This method must return one of the values shown in the following table:

Return Value | Meaning
S_OK | The method succeeded.
E_OUTOFMEMORY | The value in cbSize was smaller than the number of bytes to be written to the output buffer (the buffer pointed to by pbData). The method was called with pbData set to NULL.
E_INVALIDARG | The method attempted to query for a nonexistent attribute. The poemuiobj parameter pointed to an invalid context object.
E_FAIL | The method failed.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

This method is supported only for Windows XP Pscript5 plug-ins, not for Unidrv plug-ins.

If this method is called with its pszAttribute and pbData parameters set to NULL, the method will return with *pcbNeeded set to the number of bytes needed for the list of all supported global attribute names. If the method is called a second time, with pszAttribute set to NULL and pbData pointing to a buffer of the size specified in *pcbNeeded in the previous call, the method will return with *pdwDataType set to kADT_ASCII (an enumerator of the EATTRIBUTE_DATATYPE enumerated type) and pbData pointing to a NULL-delimited list of all supported global attribute names. This list will be terminated with two NULL characters.

To reduce the need to make two calls per data access, pass the method an output buffer of a fixed size (1 KB, for example), and then check the function return value. If the method returns S_OK, the buffer will already contain the data of interest. If the method returns E_OUTOFMEMORY, the value in *pcbNeeded will be the buffer size needed to hold the data of interest. The caller should then allocate a buffer of that larger size and proceed with a second call to the method.

For more information, see Using GetGlobalAttribute.

See Also

OEMUIOBJ, IPrintCoreUI2::GetFeatureAttribute, IPrintCoreUI2::GetOptionAttribute


IPrintCoreUI2::GetOptionAttribute

The IPrintCoreUI2::GetOptionAttribute method retrieves the option attribute list or the value of a specific option attribute.

STDMETHOD
  (GetOptionAttribute) (
    THIS_
    IN POEMUIOBJ  poemuiobj,
    IN DWORD  dwFlags,
    IN PCSTR  pszFeatureKeyword,
    IN PCSTR  pszOptionKeyword,
    IN PCSTR  pszAttribute,
    OUT PDWORD  pdwDataType,
    OUT PBYTE  pbData,
    IN DWORD  cbSize,
    OUT PDWORD  pcbNeeded
    ) PURE;

Parameters

poemuiobj
Points to the current context, an OEMUIOBJ structure.
dwFlags
Is reserved and must be set to zero.
pszFeatureKeyword
Points to a caller-supplied buffer containing an ASCII string specifying the single feature keyword to query for.
pszOptionKeyword
Points to a caller-supplied buffer containing an ASCII string specifying the single option keyword to query for. This value can be obtained from a prior call to IPrintCoreUI2::EnumOptions.
pszAttribute
Points to a caller-supplied buffer containing an ASCII string specifying the single attribute requested. If this parameter is NULL, the caller is requesting a list of all supported attribute names for the option, as opposed to specifying a specific attribute name for the option.
pdwDataType
Points to a memory location that will receive a value specifying the data type of the requested attribute. This value is an enumerator of the EATTRIBUTE_DATATYPE enumeration.
pbData
Points to a caller-supplied buffer that will receive the requested data. To simply query for the number of bytes needed to fulfill a request, set this parameter to NULL.
cbSize
Specifies the size, in bytes of the buffer pointed to by pbData.
pcbNeeded
Points to a memory location that will receive the actual size, in bytes, of the requested data.

Return Value

This method must return one of the values shown in the following table:

Return Value | Meaning
S_OK | The method succeeded.
E_OUTOFMEMORY | The value in cbSize was smaller than the number of bytes to be written to the output buffer (the buffer pointed to by pbData). The method was called with pbData set to NULL.
E_INVALIDARG | The method attempted to query for a nonexistent attribute. The feature keyword name or option keyword name were not recognized. The poemuiobj parameter pointed to an invalid context object.
E_FAIL | The method failed.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

This method is supported only for Windows XP Pscript5 plug-ins, not for Unidrv plug-ins.

If this method is called with its pszAttribute and pbData parameters set to NULL, the method will return with *pcbNeeded set to the number of bytes needed for the list of all supported attribute names for the option. If the method is called a second time, with pszAttribute set to NULL and pbData pointing to a buffer of the size specified in *pcbNeeded in the previous call, the method will return with *pdwDataType set to kADT_ASCII (an enumerator of the EATTRIBUTE_DATATYPE enumerated type) and pbData pointing to a NULL-delimited list of all supported attribute names for the option. This list will be terminated with two NULL characters.

To reduce the need to make two calls per data access, pass the method an output buffer of a fixed size (1 KB, for example), and then check the function return value. If the method returns S_OK, the buffer will already contain the data of interest. If the method returns E_OUTOFMEMORY, the value in *pcbNeeded will be the buffer size needed to hold the data of interest. The caller should then allocate a buffer of that larger size and proceed with a second call to the method.

For more information, see Using GetOptionAttribute.

See Also

OEMUIOBJ, IPrintCoreUI2::EnumOptions, IPrintCoreUI2::GetFeatureAttribute, IPrintCoreUI2::GetGlobalAttribute


IPrintCoreUI2::GetOptions

The IPrintCoreUI2::GetOptions method retrieves the driver's current feature settings in the format of a list of feature/option keyword pairs.

STDMETHOD
  (GetOptions) (
    THIS_
    IN POEMUIOBJ  poemuiobj,
    IN DWORD  dwFlags,
    IN PCSTR  pmszFeaturesRequested,
    IN DWORD  cbIn,
    OUT PSTR  pmszFeatureOptionBuf,
    IN DWORD  cbSize,
    OUT PDWORD  pcbNeeded
    ) PURE;

Parameters

poemuiobj
Points to the current context, an OEMUIOBJ structure.
dwFlags
Is reserved and must be set to zero.
pmszFeaturesRequested
Points to caller-supplied buffer containing a list of feature keywords (in MULTI_SZ format) whose settings are requested. Set this parameter to NULL to obtain settings for all features.
cbIn
Specifies the size, in bytes, of the buffer pointed to by pmszFeaturesRequested. The size includes the last MULTI_SZ NULL character.
pmszFeatureOptionBuf
Points to a caller-supplied buffer that will receive a list of feature/option keyword pairs (in MULTI_SZ format) obtained from the driver settings. Each feature/option keyword pair contains the feature keyword name, a NULL character, the option keyword name, and another NULL character. The list is terminated by two NULL characters.
cbSize
Specifies the size, in bytes, of the buffer pointed to by pmszFeatureOptionBuf.
pcbNeeded
Points to a memory location that will receive the actual size, in bytes, of the feature/option keyword pairs.

Return Value

The method must return one of the values shown in the following table:

Return Value | Definition
S_OK | The method succeeded.
E_OUTOFMEMORY | The value in cbSize was smaller than the number of bytes to be written to the output buffer (the buffer pointed to by pmszFeatureOptionBuf). The method was called with pmszFeatureOptionBuf set to NULL.
E_INVALIDARG | The input buffer (the buffer pointed to by pmszFeaturesRequested) was provided, but its contents were not in MULTI_SZ format. The poemuiobj parameter pointed to an invalid context object.
E_NOTIMPL | The method is not supported.
E_FAIL | The method failed.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

This method is supported only for Windows XP Pscript5 UI plug-ins that fully replace the core driver's standard UI pages, and is supported only during the UI plug-in's IPrintOemUI::DocumentPropertySheets and IPrintOemUI::DevicePropertySheets functions, and their property sheet callback routines. See Replacing Driver-Supplied Property Sheet Pages for more information.

If a requested feature keyword is not recognized, or recognized but not supported in the current sticky mode (document-sticky or printer-sticky — see Replacing Driver-Supplied Property Sheet Pages), or the feature keyword is recognized but there is currently no option selection for it, the feature will simply be ignored and the feature/option keyword pair will not be placed in the output buffer.

To reduce the need to make two calls per data access, pass the method an output buffer of a fixed size (1 KB, for example), and then check the function return value. If the method returns S_OK, the buffer will already contain the data of interest. If the method returns E_OUTOFMEMORY, the value in *pcbNeeded will be the buffer size needed to hold the data of interest. The caller should then allocate a buffer of that larger size and proceed with a second call to the method.

For more information, see Using GetOptions and SetOptions.

See Also

OEMUIOBJ, IPrintOemUI::DocumentPropertySheets, IPrintOemUI::DevicePropertySheets, IPrintCoreUI2::SetOptions


IPrintCoreUI2::QuerySimulationSupport

The IPrintCoreUI2::QuerySimulationSupport method retrieves a spooler simulation capability structure, which indicates the kinds of simulation the spooler supports.

STDMETHOD
  (QuerySimulationSupport) (
    THIS_
    IN HANDLE  hPrinter,
    IN DWORD  dwLevel,
    OUT PBYTE  pCaps,
    IN DWORD  cbSize,
    OUT PDWORD  pcbNeeded
    ) PURE;

Parameters

hPrinter
Specifies a handle to the printer.
dwLevel
Specifies the spooler simulation capability structure returned in the buffer pointed to by pCaps. Currently, only level 1 of spooler simulation support is provided.
Value | Spooler Simulation Support Structure
1 | SIMULATE_CAPS_1 (defined in printoem.h)

pCaps
Points to the output buffer, which will contain a structure of the type indicated by the value in the dwLevel parameter.
cbSize
Specifies the size, in bytes, of the output buffer, which is pointed to by pCaps.
pcbNeeded
Specifies the size, in bytes, of the memory needed to store a structure of the type indicated by dwLevel.

Return Value

The method must return one of the values shown in the following table:

Return Value | Definition
S_OK | The method succeeded.
E_OUTOFMEMORY | The value in cbSize was smaller than the number of bytes to be written to the output buffer (the buffer pointed to by pCaps). The method was called with pCaps set to NULL.
E_NOTIMPL | The method is not supported. A structure of the type specified by dwLevel is not supported.
E_FAIL | The method failed.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

This method is supported only for Windows XP Pscript5 plug-ins, not for Unidrv plug-ins.

The IPrintCoreUI2::QuerySimulationSupport method stores a spooler simulation capability structure in the buffer pointed to by pCaps. This structure specifies the level of spooler support for "N-up" printing, reverse printing, the maximum number of pages that can be printed, collation, and others.

See Also

SIMULATE_CAPS_1


IPrintCoreUI2::SetOptions

The IPrintCoreUI2::SetOptions method sets the driver's feature settings.

 STDMETHOD
  (SetOptions) (
    THIS_
    IN POEMUIOBJ  poemuiobj,
    IN DWORD  dwFlags,
    IN PCSTR  pmszFeatureOptionBuf,
    IN DWORD  cbIn,
    OUT PDWORD  pdwResult
    ) PURE;

Parameters

poemuiobj
Points to the current context, an OEMUIOBJ structure.
dwFlags
Specifies whether the core driver is to resolve conflicts. This parameter must be set to one of the following values:
Value | Meaning
SETOPTIONS_FLAG_KEEP_CONFLICT | Ask core driver to not resolve any conflict that arises.
SETOPTIONS_FLAG_RESOLVE_CONFLICT | Ask core driver to resolve any conflict that arises.

pmszFeatureOptionBuf
Points to a caller-supplied buffer containing a list of feature/option keyword pairs in MULTI_SZ format. Each item in this list is separated from the next by a NULL character, and the list is terminated with two NULL characters.
cbIn
Specifies the size, in bytes, of the buffer pointed to by pmszFeatureOptionBuf. This size includes the last MULTI_SZ NULL character.
pdwResult
Points to a memory location that will receive one of the following values. These constants are defined in printoem.h.
Value | Meaning
SETOPTIONS_RESULT_CONFLICT_REMAINED | The core driver found conflicts, but has left them unresolved.
SETOPTIONS_RESULT_CONFLICT_RESOLVED | The core driver found and resolved all conflicts.
SETOPTIONS_RESULT_NO_CONFLICT | The core driver did not find any conflict.

Return Value

The method must return one of the values shown in the following table:

Return Value | Definition
S_OK | The method succeeded.
E_NOTIMPL | The method is not supported.
E_INVALIDARG | The value in dwFlags was incorrect. The input buffer (pointed to by pmszFeatureOptionBuf) was not in MULTI_SZ format. The poemuiobj parameter pointed to an invalid context object.
E_FAIL | The method failed.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

This method is supported only for Windows XP Pscript5 plug-ins, not for Unidrv plug-ins.

This method is called to set the driver's feature settings using a list of feature/option keyword pairs. The caller can access the resultant feature settings using the IPrintCoreUI2::GetOptions method.

If this method returns any value other than S_OK, then it did not make any change in the driver's feature settings.

The pmszFeatureOptionBuf input buffer must be constructed in the same way as the output buffer of the IPrintCoreUI2::GetOptions method. That is, the feature/option keyword pairs must be in MULTI_SZ format, and each item in the list is separated from the next by a NULL character. A pair of NULL characters terminates the list.

If the input buffer contains a feature keyword or its option keyword that is not recognized, or the feature is recognized but not supported in the current sticky mode (see Replacing Driver-Supplied Property Sheet Pages), then the feature/option pair is ignored, and the current option for that feature will continue to be in effect.

This method is supported only for UI plug-ins that fully replace the core driver's standard UI pages, and is supported only during the UI plug-in's IPrintOemUI::DocumentPropertySheets and IPrintOemUI::DevicePropertySheets functions, and their property sheet callback routines.

For more information, see Using GetOptions and SetOptions.

See Also

OEMUIOBJ, IPrintOemUI::DocumentPropertySheets, IPrintOemUI::DevicePropertySheets, IPrintCoreUI2::GetOptions


IPrintCoreUI2::WhyConstrained

The IPrintCoreUI2::WhyConstrained method determines why the specified feature/option selection is constrained.

STDMETHOD
  (WhyConstrained) (
    THIS_
    IN POEMUIOBJ  poemuiobj,
    IN DWORD  dwFlags,
    IN PCSTR  pszFeatureKeyword,
    IN PCSTR  pszOptionKeyword,
    OUT PSTR  pmszReasonList,
    IN DWORD  cbSize,
    OUT PDWORD  pcbNeeded
    ) PURE;

Parameters

poemuiobj
Points to the current context, an OEMUIOBJ structure.
dwFlags
Is reserved and must be set to zero.
pszFeatureKeyword
Points to a caller-supplied buffer containing the single feature keyword of interest to the caller.
pszOptionKeyword
Points to a caller-supplied buffer containing the option keyword.
pmszReasonList
Points to a caller-supplied buffer that will receive a list of the feature/option keyword pairs that place constraints on the specified feature/option. This list is in MULTI_SZ format with each item in the list separated from the next by a NULL character. The list is terminated with two NULL characters.

Set this parameter to NULL to simply query for the size (*pcbNeeded) of the reason list without having the list filled in.

cbSize
Specifies the size, in bytes, of the buffer pointed to by pmszReasonList.
pcbNeeded
Points to a memory location that will receive the actual size, in bytes, of the reason list.

Return Value

The method must return one of the values shown in the following table:

Return Value | Definition
S_OK | The method succeeded.
E_OUTOFMEMORY | The value in cbSize was smaller than the number of bytes to be written to the output buffer (the buffer pointed to by pmszReasonList). The method was called with pmszReasonList set to NULL.
E_NOTIMPL | The method is not supported.
E_INVALIDARG | The poemuiobj parameter pointed to an invalid context object. The feature keyword or option keyword was not recognized. The feature stickiness (see Replacing Driver-Supplied Property Sheet Pages) did not match that specified in the current context.
E_FAIL | The method failed.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

This method is supported only for Windows XP Pscript5 UI plug-ins that fully replace the core driver's standard UI pages, and is supported only during the UI plug-in's IPrintOemUI::DocumentPropertySheets and IPrintOemUI::DevicePropertySheets functions, and their property sheet callback routines. See Replacing Driver-Supplied Property Sheet Pages for more information.

When a user of the OEM UI attempts to select an item that is constrained, the caller can use this method to display a message explaining why the item is constrained. When this method returns, pmszReasonList will point to a list of one or more feature/option pairs that appear in the current driver settings, but conflict with the selected feature/option keywords. If there were no conflicts, the method should return S_OK, pmszReasonList should be filled in with an empty ASCII string containing only a NULL character, and *pcbNeeded should be set to 1.

To reduce the need to make two calls per data access, pass the method an output buffer of a fixed size (1 KB, for example), and then check the function return value. If the method returns S_OK, the buffer will already contain the data of interest. If the method returns E_OUTOFMEMORY, the value in *pcbNeeded will be the buffer size needed to hold the data of interest. The caller should then allocate a buffer of that larger size and proceed with a second call to the method.

See Also

OEMUIOBJ, IPrintOemUI::DocumentPropertySheets, IPrintOemUI::DevicePropertySheets, IPrintCoreUI2::EnumConstrainedOptions


Function Types for User Interface Plug-Ins

This section describes function types used by user interface plug-ins.


OEMCUIPCALLBACK

The OEMCUIPCALLBACK function type is used for defining callback functions that are specified by a user interface plug-in's IPrintOemUI::CommonUIProp method. The structure is defined in printoem.h.

typedef LONG
  (APIENTRY *OEMCUIPCALLBACK)(
    PCPSUICBPARAM  pCPSUICBParam,
    POEMCUIPPARAM  pOEMCUIPParam
    );

Parameters

pCPSUICBParam
Points to a CPSUICBPARAM structure.
pOEMCUIPParam
Points to an OEMCUIPPARAM structure.

Return Value

See the following Comments section.

Headers

Declared in printoem.h. Include printoem.h and compstui.h.

Comments

A callback function specified by an IPrintOemUI::CommonUIProp method is called when a user modifies a printer property sheet. The callback function's purpose is to process user modifications to customized option items.

When a property sheet item is modified, CPSUI calls the printer driver's printer interface DLL. This DLL contains its own callback function, of type _CPSUICALLBACK, which processes option values contained in its own OPTITEM structures. Then the printer interface DLL's callback function calls the user interface plug-in's callback function. If multiple user interface plug-ins are provided, each plug-in's callback function is called, in turn, in the order in which the plug-ins were installed.

The callback function receives a pointer to a CPSUICBPARAM structure. The structure's Reason member identifies the event that caused the callback function to be called. The function also receives a pointer to the same OEMCUIPPARAM structure that was used when the IPrintOemUI::CommonUIProp method specified the callback function's address.

The CPSUICBPARAM structure's pOptItem and pCurItem members identify the modified option. The callback function can use these pointers, along with the pOEMOptItems and cOEMOptItem members of the OEMCUIPPARAM structure, to determine if the modified option is one that is owned by the user interface plug-in.

When a callback function is called, it must determine if any of its customized OPTITEM structures are affected by the specified Reason value. If they are, the function should process the affected options and return one of the CPSUI_ACTION-prefixed return values described for the _CPSUICALLBACK function type. Otherwise it should return CPSUICB_ACTION_NONE.

The following additional rules apply to callback function return values:

  • If Reason contains CPSUICB_REASON_APPLYNOW, then the callback must return either CPSUICB_ACTION_ITEMS_APPLIED or CPSUICB_ACTION_NO_APPLY_EXIT. In the latter case, the printer driver interface immediately returns to CPSUI without calling any other user interface plug-in's callback function.
  • If Reason contains any value except CPSUICB_REASON_APPLYNOW, then the return value must be one of the following:

    CPSUICB_ACTION_REINIT_ITEMS
    CPSUICB_ACTION_OPTIF_CHANGED
    CPSUICB_ACTION_NONE

    These return values are listed in order of decreasing priority. If multiple user interface plug-ins exist, the printer interface DLL calls each one's callback function and saves the highest-priority return value, passing it back to CPSUI.


Structures for User Interface Plug-Ins

This section describes structures used by user interface plug-ins. The structures are defined in printoem.h.


CUSTOMSIZEPARAM

The CUSTOMSIZEPARAM structure holds information pertaining to a single custom page size parameter for a printer.

typedef struct _CUSTOMSIZEPARAM {
  LONG  dwOrder;
  LONG  lMinVal;
  LONG  lMaxVal;
} CUSTOMSIZEPARAM, *PCUSTOMSIZEPARAM;

Members

dwOrder
Specifies the order in which a custom page size parameter is placed on the PostScript interpreter's operand stack. For example, a parameter for which dwOrder is set to 1 is placed on the stack first. A parameter for which dwOrder is set to 2 is placed on the stack second, and so on.
lMinVal
Specifies the minimum value of the custom page size parameter.
lMaxVal
Specifies the maximum value of the custom page size parameter.

Headers

Declared in printoem.h. Include printoem.h.

Comments

The custom page size parameters include Width, Height, WidthOffset, HeightOffset, and Orientation. For Orientation, lMinVal and lMaxVal are values in the range [0, 3]. For the other custom page size parameters, lMinVal and lMaxVal values are in units of microns.

See Also

EATTRIBUTE_DATATYPE


OEM_DMEXTRAHEADER

The OEM_DMEXTRAHEADER structure must be used to define the first members of a set of private DEVMODE structure members.

typedef struct _OEM_DMEXTRAHEADER {
  DWORD  dwSize;
  DWORD  dwSignature;
  DWORD  dwVersion
} OEM_DMEXTRAHEADER, *POEM_DMEXTRAHEADER;

Members

dwSize
Total size, in bytes, of the added private DEVMODE structure members, including the bytes contained in the OEM_DMEXTRAHEADER structure.
dwSignature
Unique signature value that the plug-in also returns when its IPrintOemUI::GetInfo method receives the OEMGI_GETSIGNATURE flag.
dwVersion
Version number of the user interface plug-in that is defining the private DEVMODE structure members. The version format is developer-defined.

Headers

Declared in printoem.h. Include printoem.h.

Comments

For more information about adding DEVMODE structure members, see Providing DEVMODE Structure Additions.


OEMCUIPPARAM

The OEMCUIPPARAM structure is used as an input parameter to a user interface plug-in's IPrintOemUI::CommonUIProp method.

typedef struct _OEMCUIPPARAM {
  DWORD  cbSize;
  POEMUIOBJ  poemuiobj;
  HANDLE  hPrinter;
  PWSTR  pPrinterName;
  HANDLE  hModule;
  HANDLE  hOEMHeap;
  PDEVMODE  pPublicDM;
  PVOID  pOEMDM;
  DWORD  dwFlags;
  POPTITEM  pDrvOptItems;
  DWORD  cDrvOptItems;
  POPTITEM  pOEMOptItems;
  DWORD  cOEMOptItems;
  PVOID  pOEMUserData;
  OEMCUIPCALLBACK  OEMCUIPCallback;
} OEMCUIPPARAM, *POEMCUIPPARAM;

Members

cbSize
Size of the OEMCUIPPARAM structure. Supplied by the Unidrv or Pscript5 driver.
poemuiobj
Pointer to an OEMUIOBJ structure.
hPrinter
Handle to the printer. Supplied by the Unidrv or Pscript5 driver.
pPrinterName
String containing the printer name. Supplied by the Unidrv or Pscript5 driver.
hModule
Handle to the user interface plug-in. Supplied by the Unidrv or Pscript5 driver.
hOEMHeap
Handle to a heap from which space can be allocated by calling the HeapAlloc function (described in the Platform SDK documentation). Supplied by the Unidrv or Pscript5 driver.
pPublicDM
Pointer to the printer's public DEVMODE structure. Valid only if the IPrintOemUI::CommonUIProp method's dwMode argument is OEMCUIP_DOCPROP. Supplied by the Unidrv or Pscript5 driver.
pOEMDM
Pointer to the user interface plug-in's private DEVMODE members. Valid only if the IPrintOemUI::CommonUIProp method's dwMode argument is OEMCUIP_DOCPROP. Supplied by the Unidrv or Pscript5 driver.
dwFlags
For calls to IPrintOemUI::CommonUIProp with its dwMode parameter set to OEMCUIP_DOCPROP:
Contains the contents of the fMode member of the DOCUMENTPROPERTYHEADER structure received by the printer driver's DrvDocumentPropertySheets function.
For calls to IPrintOemUI::CommonUIProp with its dwMode parameter set to OEMCUIP_PRNPROP:
Contains the contents of the Flags member of the DEVICEPROPERTYHEADER structure received by the printer driver's DrvDevicePropertySheets function.
pDrvOptItems
Pointer to the printer driver's OPTITEM array. Not valid the first time IPrintOemUI::CommonUIProp is called. Supplied by the Unidrv or Pscript5 driver.
cDrvOptItems
Count of OPTITEM structures in the array pointed to by pDrvOptItems. Supplied by the Unidrv or Pscript5 driver.
pOEMOptItems
Pointer to an array of OPTITEM structures. Supplied by IPrintOemUI::CommonUIProp caller. The second time the IPrintOemUI::CommonUIProp method is called, it must place OPTITEM structures defined by the user interface plug-in in this array, and it must place the structure count in cOEMOptItems. For each OPTITEM structure placed in the array, you must do the following:
  • Set the OPTITEM structure's UserItemID member to the plug-in's unique signature, which is the same value that the plug-in returns when its IPrintOemUI::GetInfo method receives the OEMGI_GETSIGNATURE flag.
  • Set the OPTITEM structure's DMPubID member either to one of the predefined values or to a value greater than DMPUB_USER. If you use any predefined values, you must search through the entire OPTITEM array for structures already containing those values, and you must set their OPTIF_HIDE flags.
  • Allocate space for OPTTYPES and OPTPARAMS structures by calling the Platform SDK HeapAlloc function, using the handle contained in the OEMCUIPPARAM structure's hOEMHeap member. The printer driver de-allocates this space when it is no longer needed.

Not valid the first time IPrintOemUI::CommonUIProp is called.

cOEMOptItems
Count of OPTITEM structures contained in the array pointed by pOEMOptItems. Supplied by the Unidrv or Pscript5 driver.

The first time the IPrintOemUI::CommonUIProp method is called, the caller-supplied value for cOEMOptItems is zero. The IPrintOemUI::CommonUIProp method must change this value to indicate the number of OPTITEM structures that the method will supply. The second time it is called, IPrintOemUI::CommonUIProp must supply the number of OPTITEM structures actually added to the array pointed to by pOEMOptItems.

pOEMUserData
Used by the IPrintOemUI::CommonUIProp method, the second time it is called, to provide the OEMCUIPCallback function with optional extra input information.
OEMCUIPCallback
Used by the IPrintOemUI::CommonUIProp method, the second time it is called, to return the address of a callback function of type OEMCUIPCALLBACK.

Headers

Declared in printoem.h. Include printoem.h.

Comments

A user interface plug-in receives this structure's address as an input argument to both its IPrintOemUI::CommonUIProp method and its OEMCUIPCALLBACK-typed callback function.

For additional information about the use of this structure and associated functions, see User Interface Plug-Ins.


OEMDMPARAM

The OEMDMPARAM structure is used as an input parameter to the IPrintOemUI::DevMode, IPrintOemUni::DevMode, and IPrintOemPS::DevMode methods.

typedef struct _OEMDMPARAM {
  DWORD  cbSize;
  PVOID  pdriverobj;
  HANDLE  hPrinter;
  HANDLE  hModule;
  PDEVMODE  pPublicDMIn;
  PDEVMODE  pPublicDMOut;
  PVOID  pOEMDMIn;
  PVOID  pOEMDMOut;
  DWORD  cbBufSize;
} OEMDMPARAM, *POEMDMPARAM;

Members

cbSize
Contains the size of the OEMDMPARAM structure. Supplied by the Unidrv or Pscript5 driver.
pdriverobj
For IPrintOemUI::DevMode:
Not used.
For IPrintOemUni::DevMode and IPrintOemPS::DevMode:
Pointer to a DEVOBJ structure.
hPrinter
Handle to the printer device. Supplied by the Unidrv or Pscript5 driver.
hModule
Handle to the user interface plug-in module. Supplied by the Unidrv or Pscript5 driver.
pPublicDMIn
Pointer to the printer device's public DEVMODE structure. Supplied by the Unidrv or Pscript5 driver. (Valid if the DevMode method's dwMode value is OEMDM_DEFAULT, OEMDM_CONVERT, or OEMDM_MERGE.)
pPublicDMOut
Pointer to a location to receive public DEVMODE structure contents. Supplied by the Unidrv or Pscript5 driver. (Valid if the DevMode method's dwMode value is OEMDM_CONVERT or OEMDM_MERGE.)
pOEMDMIn
Pointer to a set of private DEVMODE members. Supplied by the Unidrv or Pscript5 driver. (Valid if the DevMode method's dwMode value is OEMDM_CONVERT or OEMDM_MERGE.)
pOEMDMOut
Pointer to memory allocated to receive modified private DEVMODE contents. Supplied by the Unidrv or Pscript5 driver. (Valid if the DevMode method's dwMode value is OEMDM_DEFAULT, OEMDM_CONVERT or OEMDM_MERGE.)
cbBufSize
On input, contains the caller-supplied size of memory space pointed to by pOEMDMOut. (Not valid if the DevMode method's dwMode value is OEMDM_SIZE.)

On output, contains the method-supplied size of the current version of the private DEVMODE section. (Only used if the DevMode method's dwMode value is OEMDM_SIZE.)

Headers

Declared in printoem.h. Include printoem.h.

Comments

For more information about the use of OEMDMPARAM structure members, see the description of the IPrintOemUI::DevMode method.


OEMFONTINSTPARAM

The OEMFONTINSTPARAM structure is used as an input parameter to a user interface plug-in's IPrintOemUI::FontInstallerDlgProc method.

typedef struct _OEMFONTINSTPARAM {
  DWORD  cbSize;
  HANDLE  hPrinter;
  HANDLE  hModule;
  HANDLE  hHeap;
  DWORD   dwFlags;
  PWSTR  pFontInstallerName;
} OEMFONTINSTPARAM, *POEMFONTINSTPARAM;

Members

cbSize
Size, in bytes, of the OEMFONTINSTPARAM structure.
hPrinter
Unidrv-supplied printer handle.
hModule
Unidrv-supplied handle to the user interface plug-in.
hHeap
Unidrv-supplied handle to a heap from which space can be allocated by calling the HeapAlloc function (described in the Platform SDK documentation).
dwFlags
Unidrv-supplied flags. The only defined flag is FG_CANCHANGE which, if set, indicates the user interface should allow the user to change the installed fonts. Otherwise the user interface should be displayed in read-only mode.
pFontInstallerName
Pointer to a string representing the font installer's name. The IPrintOemUI::FontInstallerDlgProc method must supply this string if the received message is WM_USER+WM_FI_NAME. The string must be placed in memory allocated using hHeap.

Headers

Declared in printoem.h. Include printoem.h.


OEMUIOBJ

The OEMUIOBJ structure is used as an input argument to several of the methods exported by user interface plug-ins.

typedef struct _OEMUIOBJ {
  DWORD  cbSize;
  POEMUIPROCS  pOemUIProcs;
} OEMUIOBJ, *POEMUIOBJ;

Members

cbSize
Size of the OEMUIOBJ structure.
pOemUIProcs
Pointer to a an OEMUIPROCS structure, which is a private, internal structure.

Headers

Declared in printoem.h. Include printoem.h.

Comments

User interface plug-ins do not need to reference an OEMUIOBJ structure's members. Plug-ins receive a pointer to this structure as input to their IPrintOemUI::DeviceCapabilities, IPrintOemUI::DevQueryPrintEx and IPrintOemUI::QueryColorProfile methods. Additionally, the OEMCUIPPARAM structure contains an OEMUIOBJ structure pointer. Plug-ins must supply the received pointer when calling IPrintOemDriverUI::DrvGetDriverSetting or IPrintOemDriverUI::DrvUpdateUISetting.


OEMUIPROCS

The OEMUIPROCS structure is obsolete.

The OEMUIPROCS structure contains the address of the DrvGetDriverSetting and DrvUpdateUISetting functions that are exported by Microsoft printer drivers.

typedef struct _OEMUIPROCS {
  PFN_DrvGetDriverSetting DrvGetDriverSetting;
  PFN_DrvUpdateUISetting  DrvUpdateUISetting;
} OEMUIPROCS, *POEMUIPROCS;

Members

DrvGetDriverSetting
Points to the printer driver's DrvGetDriverSetting function. (To obtain this function's address in kernel mode, see DRVPROCS.)
DrvUpdateUISetting
Points to the printer driver's DrvUpdateUISetting function.

Headers

Declared in printoem.h. Include printoem.h.

Comments

DrvGetDriverSetting and DrvUpdateUISetting have been superseded by COM-based interfaces.

The OEMUIPROCS structure's address is contained in an OEMUIOBJ structure.


OEMUIPSPARAM

The OEMUIPSPARAM structure is passed to a user interface plug-in's IPrintOemUI::DevicePropertySheets and IPrintOemUI::DocumentPropertySheets methods.

typedef struct _OEMUIPSPARAM {
  DWORD  cbSize;
  POEMUIOBJ  poemuiobj;
  HANDLE  hPrinter;
  PWSTR  pPrinterName;
  HANDLE  hModule;
  HANDLE  hOEMHeap;
  PDEVMODE  pPublicDM;
  PVOID  pOEMDM;
  PVOID  pOEMUserData;
  DWORD  dwFlags;
  PVOID  pOemEntry;
} OEMUIPSPARAM, *POEMUIPSPARAM;

Members

cbSize
Size of the OEMUIPSPARAM structure. Supplied by the Unidrv or Pscript5 driver.
poemuiobj
Not used.
hPrinter
Handle to the printer. Supplied by the Unidrv or Pscript5 driver.
pPrinterName
String containing the printer name. Supplied by the Unidrv or Pscript5 driver.
hModule
Handle to the user interface plug-in. Supplied by the Unidrv or Pscript5 driver.
hOEMHeap
Handle to a heap from which space can be allocated by calling the SDK Platform HeapAlloc function. Supplied by the Unidrv or Pscript5 driver.
pPublicDM
For calls to IPrintOemUI::DocumentPropertySheets:
Caller-supplied pointer to the printer's public DEVMODE structure.
For calls to IPrintOemUI::DevicePropertySheets:
Not used.
pOEMDM
For calls to IPrintOemUI::DocumentPropertySheets:
Caller-supplied pointer to the user interface plug-in's private DEVMODE members.
For calls to IPrintOemUI::DevicePropertySheets:
Not used.
pOEMUserData
Pointer, supplied by user interface plug-in, to a location containing private information. This pointer is returned to the plug-in's _CPSUICALLBACK-typed callback function when a property sheet item has changed.
dwFlags
For calls to IPrintOemUI::DocumentPropertySheets:
Contains the contents of the fMode member of the DOCUMENTPROPERTYHEADER structure received by the printer driver's DrvDocumentPropertySheets function.
For calls to IPrintOemUI::DevicePropertySheets:
Contains the contents of the Flags member of the DEVICEPROPERTYHEADER structure received by the printer driver's DrvDevicePropertySheets function.
pOemEntry
Reserved for system use.

Headers

Declared in printoem.h. Include printoem.h.


USERDATA

The USERDATA structure is used by Unidrv and Pscript to specify additional information about printer features. A USERDATA structure pointer is supplied as the UserData member for each OPTITEM structure.

typedef struct _USERDATA {
  DWORD  dwSize;
  ULONG_PTR  dwItemID;
  PSTR  pKeyWordName;
  DWORD  dwReserved[8];
} USERDATA, *PUSERDATA;

Members

dwSize
Size, in bytes, of the USERDATA structure.
dwItemID
Printer feature identifier.
pKeyWordName
Pointer to a non-localized text string identifying a printer feature.
dwReserved
Reserved.

Headers

Declared in printoem.h. Include printoem.h.


Methods for Rendering Plug-Ins

This section describes the COM interfaces used for communication between Microsoft's printer drivers (Unidrv and Pscript) and vendor-supplied rendering plug-ins. The following topics are provided:

IPrintOemPS Interface

IPrintOemPS2 Interface

IPrintOemDriverPS Interface

IPrintOemUni Interface

IPrintOemUni2 Interface

IPrintOemDriverUni Interface

IPrintCorePS2 Interface

Non-COM-Based DDI Hook-out Functions


IPrintOemPS Interface

This section describes the methods defined for the IPrintOemPS COM interface. Method prototypes are defined in prcomoem.h.


IPrintOemPS::Command

The IPrintOemPS::Command method is used by rendering plug-ins for the Microsoft PostScript printer driver, in order to insert PostScript commands into the print job's data stream.

STDMETHOD
  (Command) (
    THIS_
    PDEVOBJ  pdevobj,
    DWORD  dwIndex,
    PVOID  pData,
    DWORD  cbSize,
    OUT DWORD  *pdwResult
    ) PURE;

Parameters

pdevobj
Caller-supplied pointer to a DEVOBJ structure.
dwIndex
Caller-supplied value representing the current injection point within the print job's data stream. For more information, see the following Comments section.
pData
Not used.
cbSize
Not used.
pdwResult
Receives a method-supplied value indicating the result of the insertion operation. If the insertion succeeds, this value should be ERROR_SUCCESS. If the insertion fails, the value should be one of the error codes defined in winerror.h. If the method does not attempt to insert data for a specified dwIndex value, the value should be ERROR_NOT_SUPPORTED.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemPS::Command method is used to insert PostScript commands into the data stream that is generated by the Microsoft PostScript Printer Driver. If you want to provide this method, you must define it in a rendering plug-in.

When the IPrintOemPS::Command method is called, it's dwIndex parameter specifies the current injection point within the print job's data stream. The method should use this value to determine what operation, if any, to perform. Index values, which are defined in wingdi.h, are listed in the following table.

Index Value | When Received
PSINJECT_BEGINDEFAULTS | After the printer driver sends %%BeginDefaults to the data stream.
PSINJECT_BEGINPAGESETUP | After the printer driver sends %%BeginPageSetup to the data stream.
PSINJECT_BEGINPROLOG | After the printer driver sends %%BeginProlog to the data stream.
PSINJECT_BEGINSETUP | After the printer driver sends %%BeginSetup to the data stream.
PSINJECT_BEGINSTREAM | Before the printer driver sends the first byte of the data stream.
PSINJECT_BOUNDINGBOX | When the printer driver is ready to insert %%BoundingBox: into the data stream. Data supplied by IPrintOemPS::Command replaces the driver's %%BoundingBox: comment.
PSINJECT_COMMENTS | Before the printer driver sends %%EndComments to the data stream.
PSINJECT_DOCNEEDEDRES | After the printer driver sends %%DocumentNeededResources: to the data stream, along with resource information. If the IPrintOemPS::Command method sends resource information, it is appended to the stream after the driver's resource information. Entry format is as follows: %%+ ResourceType ResourceNames The printer driver sends %%DocumentNeededResources: after sending %%Trailer section.
PSINJECT_DOCSUPPLIEDRES | After the printer driver sends %%DocumentSuppliedResources: to the data stream, along with resource information. If the IPrintOemPS::Command method sends resource information, it is appended to the stream after the driver's resource information. Entry format is as follows: %%+ ResourceType ResourceNames The printer driver sends %%DocumentSuppliedResources: after sending %%Trailer section.
PSINJECT_DOCUMENTPROCESSCOLORS
 | When the printer driver is ready to insert %%DocumentProcessColors: color into the data stream. Data supplied by IPrintOemPS::Command replaces the driver's %%DocumentProcessColors: color comment.
PSINJECT_DOCUMENTPROCESSCOLORSATEND
 | When the printer driver is ready to insert %%DocumentProcessColors: (atend) into the data stream. Data supplied by IPrintOemPS::Command replaces the driver's %%DocumentProcessColors: (atend) comment.
PSINJECT_ENDDEFAULTS | Before the printer driver sends %%EndDefaults to the data stream.
PSINJECT_ENDPAGECOMMENTS | Before the printer driver sends %%EndPageComments to the data stream.
PSINJECT_ENDPAGESETUP | Before the printer driver sends %%EndPageSetup to the data stream.
PSINJECT_ENDPROLOG | Before the printer driver sends %%EndProlog to the data stream.
PSINJECT_ENDSETUP | Before the printer driver sends %%EndSetup to the data stream.
PSINJECT_ENDSTREAM | After the printer driver sends the last byte of the data stream.
PSINJECT_EOF | After the printer driver sends %%EOF to the data stream.
PSINJECT_ORIENTATION | When the printer driver is ready to insert %%Orientation: into the data stream. Data supplied by IPrintOemPS::Command replaces the driver's %%Orientation: comment.
PSINJECT_PAGEBBOX | When the printer driver is ready to insert %%PageBoundingBox: into the data stream. Data supplied by IPrintOemPS::Command replaces the driver's %%PageBoundingBox: comment.
PSINJECT_PAGENUMBER | When the printer driver is ready to insert %%Page: into the data stream. Data supplied by IPrintOemPS::Command replaces the driver's %%Page: comment.
PSINJECT_PAGEORDER | When the printer driver is ready to insert %%PageOrder: into the data stream. Data supplied by IPrintOemPS::Command replaces the driver's %%PageOrder: comment.
PSINJECT_PAGES | When the printer driver is ready to insert %%Pages: nnn into the data stream. Data supplied by IPrintOemPS::Command replaces the driver's %%Pages: nnn comment.
PSINJECT_PAGESATEND | When the printer driver is ready to insert %%Pages: (atend) into the data stream. Data supplied by IPrintOemPS::Command replaces the driver's %%Pages: (atend) comment.
PSINJECT_PAGETRAILER | After the printer driver sends %%PageTrailer to the data stream.
PSINJECT_PLATECOLOR | When the printer driver is ready to insert %%PlateColor: color into the data stream. Data supplied by IPrintOemPS::Command replaces the driver's %%PlateColor: color comment.
PSINJECT_PSADOBE | Before the printer driver sends %!PS-Adobe to the data stream.
PSINJECT_SHOWPAGE | Before the printer driver sends a showpage command.
PSINJECT_TRAILER | After the printer driver sends %%Trailer to the data stream.
PSINJECT_VMRESTORE | After the printer driver sends a restore command. (The IPrintOemPS::Command method must resend all resources it sent after the last PSINJECT_VMSAVE, if the resources are going to be reused.)
PSINJECT_VMSAVE | Before the printer driver sends a save command. (See PSINJECT_VMRESTORE.)

The IPrintOemPS::Command method must call IPrintOemDriverPS::DrvWriteSpoolBuf to insert the PostScript commands.

If IPrintOemPS::Command methods are exported by multiple rendering plug-ins, the methods are called in the order that the plug-ins are specified for installation, each time the printer driver reaches an injection point. The following rules apply:

  • If the injection point is one for which supplied data is appended to the data provided by the printer driver, each plug-in is called and each plug-in is allowed to append PostScript commands.
  • If the injection point is one for which supplied data replaces the data provided by the printer driver, the plug-ins are called until one IPrintOemPS::Command method supplies ERROR_SUCCESS for dwResult. No other plug-ins are called. If all plug-ins supply ERROR_NOT_SUPPORTED, the driver-supplied data is not replaced.


IPrintOemPS::DevMode

The IPrintOemPS::DevMode method, provided by rendering plug-ins for Pscript5, performs operations on private DEVMODE members.

STDMETHOD
  (DevMode) (
    THIS_
    DWORD  dwMode,
    POEMDMPARAM  pOemDMParam
    ) PURE;

If you are providing a user interface plug-in for Pscript5, and if you are adding private members to the driver's DEVMODE structure, you must implement both the IPrintOemUI::DevMode and the IPrintOemPS::DevMode methods. The code implementing these methods must be identical and can be placed in a library that is statically linked to both the UI plug-in and the rendering plug-in.

For a description of the IPrintOemPS::DevMode method, see IPrintOemUI::DevMode.

Headers

Declared in prcomoem.h. Include prcomoem.h.


IPrintOemPS::DisableDriver

The IPrintOemPS::DisableDriver method allows a rendering plug-in for Pscript to free resources that were allocated by the plug-in's IPrintOemPS::EnableDriver method.

STDMETHOD
  (DisableDriver) (
    THIS
    ) PURE;

Parameters

None.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemPS::DisableDriver method, provided by rendering plug-ins for Pscript5, performs the same types of operations as the DrvDisableDriver function that is exported by Pscript5's printer graphics DLL.

This is the last IPrintOemPS interface method that is called before the rendering plug-in is unloaded.


IPrintOemPS::DisablePDEV

The IPrintOemPS::DisablePDEV method allows a rendering plug-in for Pscript5 to delete the private PDEV structure that was allocated by its IPrintOemPS::EnablePDEV method.

STDMETHOD
  (DisablePDEV) (
    THIS_
    PDEVOBJ  pdevobj
    ) PURE;

Parameters

pdevobj
Caller-supplied pointer to a DEVOBJ structure.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemPS::DisablePDEV method performs the same types of operations as the DrvDisablePDEV function that is exported by a printer graphics DLL. Its purpose is to allow a rendering plug-in to delete the private PDEV structure that is pointed to by the DEVOBJ structure's pdevOEM member. This PDEV structure is one that was allocated by the plug-in's IPrintOemPS::EnablePDEV method.


IPrintOemPS::EnableDriver

The IPrintOemPS::EnableDriver method allows a rendering plug-in for Pscript to hook out some graphics DDI functions.

STDMETHOD
  (EnableDriver) (
    THIS_
    DWORD  DriverVersion,
    DWORD  cbSize,
    PDRVENABLEDATA  pded
    ) PURE;

Parameters

DriverVersion
Caller-supplied interface version number. This value is defined by PRINTER_OEMINTF_VERSION, in printoem.h.
cbSize
Caller-supplied size, in bytes, of the structure pointed to by pded.
pded
Caller-supplied pointer to a DRVENABLEDATA structure.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemPS::EnableDriver method allows a rendering plug-in to perform the same types of operations as the DrvEnableDriver function that is exported by printer graphics DLLs.

Like the DrvEnableDriver function, the IPrintOemPS::EnableDriver method is responsible for providing addresses of internally supported graphics DDI functions, known as hooking functions. It can also perform other one-time initialization operations. Unlike the DrvEnableDriver function, implementation of the IPrintOemPS::EnableDriver method is optional.

The method should fill the supplied DRVENABLEDATA structure and allocate an array of DRVFN structures. It should fill the array with pointers to hooking functions, along with winddi.h-defined index values that identify the hooked out graphics DDI functions.

A rendering plug-in for Pscript5 can hook out a graphics DDI function only if the Pscript5 driver defines the function. The following graphics DDI functions are defined in Pscript5 and or Unidrv and can therefore be hooked out:

DrvAlphaBlend
DrvBitBlt
DrvCopyBits
DrvDitherColor (Unidrv only)
DrvEndDoc
DrvEscape
DrvFillPath
DrvFontManagement
DrvGetGlyphMode
DrvGradientFill
DrvIcmCreateColorTransform (Pscript only)
DrvIcmDeleteColorTransform (Pscript only)
DrvLineTo (Unidrv only)
DrvNextBand (Unidrv only)
DrvPlgBlt
DrvQueryDeviceSupport (Pscript only)
DrvQueryAdvanceWidths
DrvQueryFont
DrvQueryFontData
DrvQueryFontTree
DrvRealizeBrush
DrvSendPage
DrvStartBanding (Unidrv only)
DrvStartDoc
DrvStartPage
DrvStretchBlt
DrvStretchBltROP
DrvStrokeAndFillPath
DrvStrokePath
DrvTextOut
DrvTransparentBlt

If you provide a customized hooking function, it preempts the driver's equivalent graphics DDI function. Hooking functions can also call back into the driver's graphics DDI functions. For more information see Customized Graphics DDI Functions.

Customized hooking functions have the same input and output parameters as the equivalent graphics DDI function, with one exception – where graphics DDI functions receive PDEV pointers, customized hooking functions receive DEVOBJ pointers. There are two ways for these functions to receive PDEV pointers:

  1. As the contents of the dhpdev member of a SURFOBJ structure for the destination surface.

    For the equivalent customized hooking function, the destination SURFOBJ structure's dhpdev member points to a DEVOBJ structure, and must be cast to type PDEVOBJ when referenced. An example graphics DDI function is DrvBitBlt.

  2. As an input argument for a dhpdev parameter.

    The equivalent customized hooking function must cast this input parameter to type PDEVOBJ when referencing it. An example graphics DDI function is DrvDitherColor.

Note that while a printer graphics DLL includes the addresses of its DrvEnablePDEV, DrvDisablePDEV, and DrvResetPDEV functions in the DRVENABLEDATA structure, a rendering plug-in for Pscript5 implements EnablePDEV, DisablePDEV, and ResetPDEV as methods of the IPrintOemPS interface and does not place their addresses in the DRVENABLEDATA structure.

If IPrintOemPS::EnableDriver methods are exported by multiple rendering plug-ins, the methods are called in the order that the plug-ins are specified for installation.

Note Each graphics DDI function can be hooked out by one rendering plug-in. If multiple plug-ins attempt to hook out the same graphics DDI function, all hook-outs after the first one are ignored.

For more information about creating and installing rendering plug-ins, see Customizing Microsoft's Printer Drivers.


IPrintOemPS::EnablePDEV

The IPrintOemPS::EnablePDEV method allows a rendering plug-in for Pscript5 to create its own PDEV structure.

STDMETHOD
  (EnablePDEV) (
    THIS_
    PDEVOBJ  pdevobj,
    PWSTR  pPrinterName,
    ULONG  cPatterns,
    HSURF  *phsurfPatterns,
    ULONG  cjGdiInfo,
    GDIINFO  *pGdiInfo,
    ULONG  cjDevInfo,
    DEVINFO  *pDevInfo,
    DRVENABLEDATA  *pded,
    OUT PDEVOEM  *pDevOem
    ) PURE;

Parameters

pdevobj
Caller-supplied pointer to a DEVOBJ structure.
pPrinterName
Caller-supplied pointer to a text string representing the logical address of the printer.
cPatterns
Caller-supplied value representing the number of HSURF-typed surface handles contained in the buffer pointed to by phsurfPatterns.
phsurfPatterns
Caller-supplied pointer to a buffer that is large enough to contain cPatterns number of HSURF-typed surface handles. The handles represent surface fill patterns.
cjGdiInfo
Caller-supplied value representing the size of the structure pointed to by pGdiInfo.
pGdiInfo
Caller-supplied pointer to a GDIINFO structure.
cjDevInfo
Caller-supplied value representing the size of the structure pointed to by pDevInfo.
pDevInfo
Caller-supplied pointer to a DEVINFO structure.
pded
Caller-supplied pointer to a DRVENABLEDATA structure containing the addresses of the printer driver's graphics DDI hooking functions. For more information, see the following Comments section.
pDevOem
Receives a method-supplied pointer to a private PDEV structure. (For more information, see the following Comments section.)

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

If the operation fails, the method should call SetLastError to set an error code.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemPS::EnablePDEV method performs the same types of operations as the DrvEnablePDEV function that is exported by a printer graphics DLL. Its purpose is to allow a rendering plug-in to create its own PDEV structure. (For more information about PDEV structures, see Customized PDEV Structures.)

If you provide a rendering plug-in that exports the IPrintOemPS::EnablePDEV method, Pscript5's printer graphics DLL calls the method from within its DrvEnablePDEV function.

The IPrintOemPS::EnablePDEV method should allocate an instance of its private PDEV structure, initialize it, and return its address as the method's pDevOem parameter. Other plug-in methods receive the address as the pdevOEM member of the DEVOBJ structure.

The pdevOEM member of the DEVOBJ structure is not used with the IPrintOemPS::EnablePDEV method.

The structures pointed to by the phsurfPatterns, pGdiInfo, and pDevInfo parameter values are the same ones that Pscript5's DrvEnablePDEV function receives. The rendering plug-in can modify the structure contents as necessary. It can supply surface fill patterns by obtaining HSURF-typed surface handles and placing them in the buffer pointed to by phsurfPatterns. Fill pattern types and handle order are listed in the description of DrvEnablePDEV.

The DRVENABLEDATA structure pointed to by pded contains the addresses of graphics DDI functions provided by Pscript5's printer graphics DLL. You are allowed to provide customized hooking functions in your plug-in for these graphics DDI functions. The DRVENABLEDATA structure's contents enable your customized hooking functions to call back to the driver's graphics DDI functions. For more information, see Customized Graphics DDI Functions.


IPrintOemPS::GetInfo

A rendering plug-in's IPrintOemPS::GetInfo method returns identification information.

STDMETHOD
  (GetInfo) (
    THIS_
    DWORD  dwMode,
    PVOID  pBuffer,
    DWORD  cbSize,
    PDWORD  pcbNeeded
    ) PURE;

Parameters

dwMode
Contains one of the following caller-supplied integer constants.
Constant Definition
OEMGI_GETPUBLISHERINFO
The method must indicate whether the rendering plug-in will be using "publishing mode". The pBuffer parameter points to a PUBLISHERINFO structure, to be filled in by the method. For more information, see the following Comments section.
OEMGI_GETSIGNATURE
The method must return a unique four-byte identification signature. The plug-in must also place this signature in OPTITEM structures, as described in the description of the OEMCUIPPARAM. structure's pOEMOptItems member.
OEMGI_GETVERSION
The method must return the user interface plug-in's version number as a DWORD. The version format is developer-defined.

pBuffer
Caller-supplied pointer to memory allocated to receive the information specified by dwMode.
cbSize
Caller-supplied size of the buffer pointed to by pBuffer.
pcbNeeded
Caller-supplied pointer to a location to receive the number of bytes written into the buffer pointed to by pBuffer.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

Rendering plug-ins for Pscript5 are required to implement the IPrintOemPS::GetInfo method, which is called immediately after the plug-in is loaded. The method should return the specified information by writing it to the address specified by pBuffer and writing the size, in bytes, of the returned information into the location specified by pcbNeeded.

If pBuffer is NULL, the method should just use pcbNeeded to return the number of bytes required to store the specified information.

In "publishing mode", all font information to be downloaded is placed in the job header. Each font is downloaded only once and can be used for any page, allowing the job to be page-order independent. If dwMode is OEMGI_GETPUBLISHERINFO but the plug-in does not support publishing mode, IPrintOemPS::GetInfo should return E_NOTIMPL.

For more information about creating and installing rendering plug-ins, see Customizing Microsoft's Printer Drivers.

See Also

IPrintOemUI::GetInfo, IPrintOemUni::GetInfo


IPrintOemPS::PublishDriverInterface

The IPrintOemPS::PublishDriverInterface method allows a rendering plug-in for Pscript5 to obtain the Pscript5 driver's IPrintCorePS2 or IPrintOemDriverPS interface.

STDMETHOD
  (PublishDriverInterface) (
    THIS_
    IUnknown  *pIUnknown
    ) PURE;

Parameters

pIUnknown
Caller-supplied pointer to the IUnknown interface of either the driver's IPrintCorePS2 COM interface or its IPrintOemDriverPS COM interface.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The Pscript5 driver supports both the IPrintCorePS2 and IPrintOemDriverPS interfaces. A rendering plug-in for Pscript5 must implement the IPrintOemPS::PublishDriverInterface method. The Pscript5 driver first calls the IPrintOemPS::PublishDriverInterface method with the pIUnknown pointer set to the IPrintCorePS2 instance's IUnknown interface. If the plug-in is able to use the IPrintCorePS2 interface, the method must return S_OK. Otherwise, the plug-in should return E_FAIL, in which case the Pscript5 driver will call the IPrintOemPS::PublishDriverInterface method again, but with the pIUnknown pointer set to the IPrintOemDriverPS instance's IUnknown interface. This time the method must return S_OK, or the driver will not call the plug-in's other IPrintOemPS interface methods.

If the rendering plug-in will be calling IPrintCorePS2 or IPrintOemDriverPS interface methods, it must use the received IUnknown interface pointer to call IUnknown::QueryInterface (described in the Platform SDK documentation) in order to obtain a pointer to the driver's supported version of the IPrintCorePS2 or IPrintOemDriverPS interface. For more information, see Accessing Printer Driver Interfaces from Plug-Ins.


IPrintOemPS::ResetPDEV

The IPrintOemPS::ResetPDEV method allows a rendering plug-in for Pscript5 to reset its PDEV structure.

STDMETHOD
  (ResetPDEV) (
    THIS_
    PDEVOBJ  pdevobjOld,
    PDEVOBJ  pdevobjNew
    ) PURE;

Parameters

pdevobjOld
Caller-supplied pointer to a DEVOBJ structure containing current PDEV information.
pdevobjNew
Caller-supplied pointer to a DEVOBJ structure into which the method should place new PDEV information.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

If the operation fails it should call SetLastError.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

A rendering plug-in's IPrintOemPS::ResetPDEV method performs the same types of operations as the DrvResetPDEV function that is exported by a printer graphics DLL. During the processing of an application's call to the Platform SDK ResetDC function, the IPrintOemPS::ResetPDEV method is called by the DrvResetPDEV function in Pscript5's printer graphics DLL. For more information about when DrvResetPDEV is called, see its description.

The rendering plug-in's private PDEV structure's address is contained in the pdevOEM member of the DEVOBJ structure pointed to by pdevobjOld. The IPrintOemPS::ResetPDEV method should use relevant members of this old structure to fill in the new structure, which is referenced through pdevobjNew.


IPrintOemPS2 Interface

This section describes the methods defined for the IPrintOemPS2 COM interface. In addition to these methods, this interface includes all of the methods defined in the IPrintOemPS COM interface. Method prototypes are defined in prcomoem.h.


IPrintOemPS2::GetPDEVAdjustment

The IPrintOemPS2::GetPDEVAdjustment method enables a plug-in to override specific PDEV settings.

STDMETHOD
  (GetPDEVAdjustment) (
    IN THIS_
    IN PDEVOBJ  pdevobj,
    IN DWORD  dwAdjustType,
    IN OUT PVOID  pBuf,
    IN DWORD  cbBuffer,
    OUT BOOL  *pbAdjustmentDone
    ) PURE;

Parameters

pdevobj
Points to a DEVOBJ structure.
dwAdjustType
Specifies the type of adjustment asked for. The following flags are currently supported:
Flag | Meaning
PDEV_ADJUST_PAPER_MARGIN_TYPE | Adjust the paper margin setting that is reported in the PDEV. See the PDEV_ADJUST_PAPER_MARGIN structure.
PDEV_HOSTFONT_ENABLED_TYPE | Enable or disable the Hostfont support feature. See the PDEV_HOSTFONT_ENABLED structure.
PDEV_USE_TRUE_COLOR_TYPE | Enable or disable color output for monochrome and color printers. See the PDEV_USE_TRUE_COLOR structure.

pBuf
Points to a structure that contains the planned settings that will be used if there is no change. These structures are listed in the preceding table. The plug-in can overwrite the settings in the relevant structure.
cbBuffer
Specifies the size, in bytes, of the structure pointed to by pBuf.
pbAdjustmentDone
Points to a memory location that the plug-in sets to TRUE when it actually changes a value in the buffer. This may be used by the driver for optimizations.

Return Value

The IPrintOemPS2::GetPDEVAdjustment method should return S_OK if it recognizes the adjustment type, and S_FALSE if it does not. If the method fails, it should return E_FAIL. The chain of plug-ins will be called until either S_OK or a failure code other than E_NOTIMPL is returned. That is, the chain of plug-ins is called until the first plug-in that is capable of handling the adjustment is found.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

This function is available in Windows XP and later.

Currently, the Pscript5 driver calls IPrintOemPS2::GetPDEVAdjustment to adjust the paper margin setting, as reported in the PDEV, to enable or disable the Hostfont feature, or to turn PostScript color output on or off.

See Also

PDEV_ADJUST_PAPER_MARGIN, PDEV_HOSTFONT_ENABLED, PDEV_USE_TRUE_COLOR


IPrintOemPS2::WritePrinter

The IPrintOemPS2::WritePrinter method, if supported, enables a rendering plug-in to capture all output data generated by a Postscript driver. If this method is not supported, the output data would otherwise be sent to the spooler in a call to the spooler's WritePrinter API (described in the Platform SDK documentation).

STDMETHOD
  (WritePrinter) (
    IN THIS_
    IN PDEVOBJ  pdevobj,
    IN PVOID  pBuf,
    IN DWORD  cbBuffer,
    OUT PDWORD  pcbWritten
  ) PURE;

Parameters

pdevobj
Points to a DEVOBJ structure.
pBuf
Points to the first byte of an array of bytes that contains the output data generated by the PostScript driver.
cbBuffer
Specifies the size, in bytes, of the array pointed to by pBuf.
pcbWritten
Points to a DWORD value that receives the number of bytes of data that the plug-in sent to the spooler's WritePrinter function (described in the Platform SDK documentation).

Return Value

If successful, this method returns S_OK. Otherwise, this method should return an appropriate value in the returned HRESULT.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

At DrvEnablePDEV time, the PostScript driver will call this method with pBuf and pdevobj set to NULL, and cbBuf set to 0, to detect whether the plug-in implements this function. The plug-in should return S_OK to indicate it implements this method, and should return E_NOTIMPL otherwise.

This method should report the number of bytes written to the spooler's WritePrinter function in pcbWritten. A value of zero carries no special meaning; errors must be reported through the returned HRESULT.


IPrintOemDriverPS Interface

This section describes the methods defined for the IPrintOemDriverPS COM interface. Method prototypes are defined in prcomoem.h.


IPrintOemDriverPS::DrvGetDriverSetting

The IPrintOemDriverPS::DrvGetDriverSetting method is provided by the Pscript5 driver so that rendering plug-ins can obtain the current status of printer features and other internal information.

STDMETHOD
  (DrvGetDriverSetting) (
    THIS_
    PVOID  pdriverobj,
    PCSTR  Feature,
    PVOID  pOutput,
    DWORD  cbSize,
    PDWORD  pcbNeeded,
    PDWORD  pdwOptionsReturned
    ) PURE;

Parameters

pdriverobj
Caller-supplied pointer to a DEVOBJ structure.
Feature
Caller supplied value identifying the printer feature for which option settings will be returned. This can be either a string pointer or a constant, as described in the following Comments section.
pOutput
Caller-supplied pointer to a buffer to receive the specified information.
cbSize
Caller-supplied size, in bytes, of the buffer pointed to by pOutput.
pcbNeeded
Caller-supplied pointer to a location to receive the minimum buffer size required to contain the requested information.
pdwOptionsReturned
Caller-supplied pointer to a location to receive the number of option strings placed in pOutput.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

When the IPrintOemDriverPS::DrvGetDriverSetting method is called, either a string pointer or a constant value can be specified for pFeatureKeyword.

  • If pFeatureKeyword is a string, it must represent a keyword argument to an *OpenUI entry in a Pscript5 minidriver's PPD file.

    The method should return one or more NULL-terminated strings in the buffer pointed to by pOutput. Each string should represent the name of a currently selected option. The number of strings should be returned in pdwOptionsReturned.

  • If pFeatureKeyword is a constant, it must be one of the OEMGDS_-prefixed constants defined in printoem.h. The method should return the value indicated by the specified constant by placing it in the buffer pointed to by pOutput. The value returned in pdwOptionsReturned must be 1.


IPrintOemDriverPS::DrvWriteSpoolBuf

The IPrintOemDriverPS::DrvWriteSpoolBuf method is provided by the Pscript5 driver so that rendering plug-ins can send printer data to the spooler.

STDMETHOD
  (DrvWriteSpoolBuf) (
    THIS_
    PDEVOBJ  pdevobj,
    PVOID  pBuffer,
    DWORD  cbSize,
    OUT DWORD  *pdwResult
    ) PURE;

Parameters

pdevobj
Caller-supplied pointer to a DEVOBJ structure.
pBuffer
Caller-supplied pointer to a buffer containing data to be sent to the print spooler.
cbSize
Caller-supplied value representing the size, in bytes, of the buffer pointed to by pBuffer.
pdwResult
Receives a method-supplied value representing the number of bytes sent to the spooler.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

Rendering plug-ins are described in Customizing Microsoft's Printer Drivers.


IPrintOemUni Interface

This section describes the methods defined for the IPrintOemUni COM interface. Method prototypes are defined in prcomoem.h.


IPrintOemUni::CommandCallback

The IPrintOemUni::CommandCallback method is used to provide dynamically generated printer commands for Unidrv-supported printers.

STDMETHOD
  (CommandCallback) (
    THIS_
    PDEVOBJ  pdevobj,
    DWORD  dwCallbackID,
    DWORD  dwCount,
    PDWORD  pdwParams,
    OUT INT  *piResult
    ) PURE;

Parameters

pdevobj
Caller-supplied pointer to a DEVOBJ structure.
dwCallbackID
Caller-supplied value representing the printer command's *CallbackID attribute in the printer's GPD file. (For more information, see the following Comments section.)
dwCount
Caller-supplied value representing the number of elements in the array pointed to by pdwParams. Can be 0.
pdwParams
Caller-supplied pointer to an array of DWORD-sized parameters containing values specified by the printer commands *Params attribute in the printer's GPD file. (For more information, see the following Comments section.) Can be NULL.
piResult
Receives a method-supplied result value. See the following Comments section.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemUni::CommandCallback method is used by rendering plug-ins to dynamically generate printer commands, for printers that are supported by Unidrv.

If you want to dynamically generate a printer command, you must include a *CallbackID attribute and, optionally, a *Params attribute, within the command's *Command entry in the printer's GPD file. For more information see Dynamically Generated Printer Commands.

When Unidrv calls the IPrintOemUni::CommandCallback method, it supplies the *Command entry's *CallbackID attribute value as the dwCallbackID parameter. It also places the *Command entry's *Params attribute value inside a DWORD array and supplies the array's address as the pParams parameter. The array contains set of Unidrv-defined standard variable values, and the dwCount parameter specifies the number of parameters contained in the array. For more information about the attributes see Command Attributes.

The method should use the dwCallbackID parameter value to determine which command to process. For each supported command, the method must be aware of which, if any, standard variables have been specified by the *Command entry's *Params attribute, and in which order.

The method is responsible for constructing a printer command, and then sending the command to the print spooler by calling the IPrintOemDriverUni::DrvWriteSpoolBuf method.

The value supplied for piResult should always return zero unless the method is processing a cursor command. For cursor commands that move the cursor in either the x or y direction, the method should return the result of subtracting the actual new cursor position from the requested new cursor position. This value might be zero, but it must always be non-negative.

If a rendering plug-in implements IPrintOemUni::CommandCallback, the plug-in's IPrintOemUni::GetImplementedMethod method must return S_OK when it receives "CommandCallback" as input.


IPrintOemUni::Compression

The IPrintOemUni::Compression method can be used with Unidrv-supported printers to provide a customized bitmap compression method.

STDMETHOD
  (Compression) (
    THIS_
    PDEVOBJ  pdevobj
    PBYTE  pInBuf,
    PBYTE  pOutBuf,
    DWORD  dwInLen,
    DWORD  dwOutLen,
    OUT INT  *piResult
    ) PURE;

Parameters

pdevobj
Caller-supplied pointer to a DEVOBJ structure.
pInBuf
Caller-supplied pointer to input scan line data.
pOutBuf
Caller-supplied pointer to an output buffer to receive compressed scan line data.
dwInLen
Caller-supplied length of the input data.
dwOutLen
Caller-supplied length of the output buffer.
piResult
Receives a method-supplied result value. If the operation succeeds, this value should be the number of compressed bytes, which must not be larger than the value received for dwOutLen. If an error occurs, or if the method cannot compress, the result value should be -1.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemUni::Compression method is used by rendering plug-ins to compress scan line data before it is sent to the print spooler. The method's purpose is to provide support for printer-specific compression methods that are not supported by Unidrv.

If the IPrintOemUni::Compression method is defined, and if the printer's GPD file contains a CmdEnableOEMComp command entry, Unidrv calls the method each time a scan line is ready to be sent to the print spooler. (For information about the CmdEnableOEMComp command, see Raster Data Compression Commands.)

The pInBuf and dwInLen parameter values describe a buffer containing a scan line of image data to be compressed. The pOutBuf and dwOutLen parameter values describe the buffer into which the IPrintOemUni::Compression method should place the compressed data.

Before Unidrv sends a scan line to the print spooler, it tries every enabled compression method to determine which one creates the smallest data stream. After it determines the best compression algorithm (by compressing the data using each method), it spools the printer command that enables the printer to accept the best compressed format, then sends the compressed data to the printer.

Therefore, the IPrintOemUni::Compression method is called for every scan line, whether the compressed data returned by the method is actually used or not. When the method is called, dwOutLen contains the length returned by the best compression method Unidrv has tried up to then. (If no other methods have been tried, dwOutLen contains the uncompressed length.) If the algorithm cannot produce a compressed scan line that is equal to or shorter than dwOutLen bytes, it should return -1 in the location specified by piResult.

If, after Unidrv tries all enabled compression methods, the compressed data returned by IPrintOemUni::Compression has the smallest length, Unidrv sends the buffer to the print spooler, preceded by the command specified by the CmdEnableOEMComp command entry.

If possible, the method's compression algorithm should use the received dwOutLen value to determine whether it can stop the algorithm before completion, to save time if another compression method has already created a better result.

If a rendering plug-in implements IPrintOemUni::Compression, the plug-in's IPrintOemUni::GetImplementedMethod method must return S_OK when it receives "Compression" as input.


IPrintOemUni::DevMode

The IPrintOemUni::DevMode method, provided by rendering plug-ins for Unidrv, performs operations on private DEVMODE members.

STDMETHOD
  (DevMode) (
    THIS_
    DWORD  dwMode,
    POEMDMPARAM  pOemDMParam
    ) PURE;

If you are providing a user interface plug-in for Unidrv, and if you are adding private members to the driver's DEVMODE structure, you must implement both the IPrintOemUI::DevMode and the IPrintOemUni::DevMode methods. The code implementing these methods must be identical and can be placed in a library that is statically linked to both the UI plug-in and the rendering plug-in.

For a description of the IPrintOemUni::DevMode method, see IPrintOemUI::DevMode.

Headers

Declared in prcomoem.h. Include prcomoem.h.


IPrintOemUni::DisableDriver

The IPrintOemuNI::DisableDriver method allows a rendering plug-in for Unidrv to free resources that were allocated by the plug-in's IPrintOemUni::EnableDriver method.

STDMETHOD
  (DisableDriver) (
    THIS
    )PURE;

Parameters

None.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemUni::DisableDriver method, provided by rendering plug-ins for Unidrv, performs the same types of operations as the DrvDisableDriver function that is exported by Unidrv's printer graphics DLL.

This is the last IPrintOemUni interface method that is called before the rendering plug-in is unloaded.


IPrintOemUni::DisablePDEV

The IPrintOemUni::DisablePDEV method allows a rendering plug-in for Unidrv to delete the private PDEV structure that was allocated by its IPrintOemUni::EnablePDEV method.

STDMETHOD
  (DisablePDEV) (
    THIS_
    PDEVOBJ  pdevobj
    ) PURE;

Parameters

pdevobj
Caller-supplied pointer to a DEVOBJ structure.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemUni::DisablePDEV method performs the same types of operations as the DrvDisablePDEV function that is exported by a printer graphics DLL. Its purpose is to allow a rendering plug-in to delete the private PDEV structure that is pointed to by the DEVOBJ structure's pdevOEM member. This PDEV structure is one that was allocated by the plug-in's IPrintOemUni::EnablePDEV method.


IPrintOemUni::DownloadCharGlyph

The IPrintOemUni::DownloadCharGlyph method enables a rendering plug-in for Unidrv to send a character glyph for a specified soft font to the printer.

STDMETHOD
  (DownloadCharGlyph) (
    THIS_
    PDEVOBJ  pdevobj,
    PUNIFONTOBJ  pUFObj,
    HGLYPH  hGlyph,
    PDWORD  pdwWidth,
    OUT DWORD  *pdwResult
    ) PURE;

Parameters

pdevobj
Caller-supplied pointer to a DEVOBJ structure.
pUFObj
Caller-supplied pointer to a UNIFONTOBJ structure.
hGlyph
Caller-supplied glyph handle.
pdwWidth
Caller-supplied pointer to receive the method-supplied width of the character.
pdwResult
Receives a method-supplied value representing the amount of printer memory, in bytes, required to store the character glyph. If the operation fails, the returned value should be zero.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemUni::DownloadCharGlyph method is used for supporting soft fonts on printers that do not accept PCL commands. Its purpose is to enable a rendering plug-in to send a character glyph to the printer.

If a rendering plug-in implements the IPrintOemUni::DownloadCharGlyph method, Unidrv calls the method immediately after sending the command string specified by the CmdSetCharCode command entry, which is contained in the printer's GPD file. (GPD files are described in Microsoft Universal Printer Driver.) The method should do the following:

  • Call the UNIFONTOBJ_GetInfo function to obtain the glyph image specified by hGlyph.
  • Call IPrintOemDriverUni::DrvWriteSpoolBuf to send the glyph to the printer.
  • Call the UNIFONTOBJ_GetInfo function again to obtain the glyph's width, then store the width in the address pointed to by pdwWidth.
  • Return the amount of printer memory required to store the glyph by placing it in the location specified by pdwResult.

If you implement the IPrintOemUni::DownloadCharGlyph method, you must also implement the IPrintOemUni::DownloadFontHeader method.

If a rendering plug-in implements IPrintOemUni::DownloadCharGlyph, the plug-in's IPrintOemUni::GetImplementedMethod method must return S_OK when it receives "DownloadCharGlyph" as input.

For additional information see Customized Font Management.


IPrintOemUni::DownloadFontHeader

The IPrintOemUni::DownloadFontHeader method allows a rendering plug-in for Unidrv to send a font's header information to a printer.

STDMETHOD
  (DownloadFontHeader) (
    THIS_
    PDEVOBJ  pdevobj,
    PUNIFONTOBJ  pUFObj,
    OUT DWORD  *pdwResult
    ) PURE;

Parameters

pdevobj
Caller-supplied pointer to a DEVOBJ structure.
pUFObj
Caller-supplied pointer to a UNIFONTOBJ structure.
pdwResult
Receives a method-supplied value representing the amount of printer memory, in bytes, required to store the font header information. If the operation fails, the returned value should be zero.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemUni::DownloadFontHeader method is used for supporting soft fonts on printers that do not accept PCL commands. Its purpose is to allow a rendering plug-in to obtain font header information from Unidrv and to send the information to the printer.

Information that might be required for constructing a non-PCL font header can be obtained by:

  • Referencing the UNIFONTOBJ structure that is received as an input argument.
  • Calling the UNIFONTOBJ_GetInfo callback function to get the font's FONTOBJ structure.

The method should send the header information to the spooler by calling IPrintOemDriverUni::DrvWriteSpoolBuf.

If you implement the IPrintOemUni::DownloadFontHeader method, you must also implement the IPrintOemUni::DownloadCharGlyph method.

If a rendering plug-in implements IPrintOemUni::DownloadFontHeader, the plug-in's IPrintOemUni::GetImplementedMethod method must return S_OK when it receives "DownloadFontHeader" as input.

For additional information see Customized Font Management.


IPrintOemUni::DriverDMS

The IPrintOemUni::DriverDMS method allows a rendering plug-in for Unidrv to indicate that it will use a device-managed drawing surface.

STDMETHOD
  (DriverDMS) (
    THIS_
    PVOID  pDevObj,
    PVOID  pBuffer,
    DWORD  cbSize,
    PDWORD  pcbNeeded
    ) PURE;

Parameters

pDevObj
Caller-supplied pointer to a DEVOBJ structure.
pBuffer
Caller-supplied pointer to a buffer to receive method-specified flags. (See the following Comments section.)
cbSize
Caller-supplied size, in bytes, of the buffer pointed to by pBuffer.
pcbNeeded
Caller-supplied pointer to a location to receive the required minimum pBuffer size.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemUni::DriverDMS method allows a rendering plug-in to indicate that it will be using a device-managed drawing surface instead of the default GDI-managed surface.

The method must specify HOOK_-prefixed flags in the buffer pointed to by pBuffer, indicating which of the plug-in's graphics DDI hooking functions are to be called for the drawing surface. The HOOK_-prefixed flags are defined in winddi.h and described in the EngAssociateSurface function's description. Flags specified by IPrintOemUni::DriverDMS are passed by Unidrv to EngAssociateSurface. (Note that to support a device-managed surface, the rendering plug-in must hook out all drawing functions.) For more information, see Handling Device-Managed Surfaces.

If IPrintOemUni::DriverDMS sets flags in the buffer pointed to by pBuffer, Unidrv creates a device-managed surface by calling EngCreateDeviceSurface. If IPrintOemUni::DriverDMS does not set any flags, Unidrv creates a GDI-managed surface by calling EngCreateBitmap. In either of these cases, IPrintOemUni::DriverDMS should return S_OK.

If the output buffer size specified by cbSize is too small, the method should specify the required size in the location pointed to by pcbNeeded, call SetLastError(ERROR_INSUFFICIENT_BUFFER), and return E_FAIL.


IPrintOemUni::EnableDriver

The IPrintOemUni::EnableDriver method allows a rendering plug-in for Unidrv to hook out some graphics DDI functions.

STDMETHOD
  (EnableDriver) (
    THIS_
    DWORD  DriverVersion,
    DWORD  cbSize,
    PDRVENABLEDATA  pded
    ) PURE;

Parameters

DriverVersion
Caller-supplied interface version number. This value is defined by PRINTER_OEMINTF_VERSION, in printoem.h.
cbSize
Caller-supplied size, in bytes, of the structure pointed to by pded.
pded
Caller-supplied pointer to a DRVENABLEDATA structure.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemUni::EnableDriver method allows a rendering plug-in to perform the same types of operations as the DrvEnableDriver function that is exported by printer graphics DLLs.

Like the DrvEnableDriver function, the IPrintOemUni::EnableDriver method is responsible for providing addresses of internally supported graphics DDI functions, known as hooking functions. It can also perform other one-time initialization operations. Unlike the DrvEnableDriver function, implementation of IPrintOemUni::EnableDriver is optional.

The method should fill the supplied DRVENABLEDATA structure and allocate an array of DRVFN structures. It should fill the array with pointers to hooking functions, along with winddi.h-defined index values that identify the hooked out graphics DDI functions.

A rendering plug-in for Unidrv can hook out a graphics DDI function only if the Unidrv driver defines the function. The following graphics DDI functions are defined in Unidrv and/or Pscript5 and can therefore be hooked out:

DrvAlphaBlend
DrvBitBlt
DrvCopyBits
DrvDitherColor (Unidrv only)
DrvEndDoc
DrvEscape
DrvFillPath
DrvFontManagement
DrvGetGlyphMode
DrvGradientFill
DrvIcmCreateColorTransform (Pscript only)
DrvIcmDeleteColorTransform (Pscript only)
DrvLineTo (Unidrv only)
DrvNextBand (Unidrv only)
DrvPlgBlt
DrvQueryAdvanceWidths
DrvQueryDeviceSupport (Pscript only)
DrvQueryFont
DrvQueryFontData
DrvQueryFontTree
DrvRealizeBrush
DrvSendPage
DrvStartBanding (Unidrv only)
DrvStartDoc
DrvStartPage
DrvStretchBlt
DrvStretchBltROP
DrvStrokeAndFillPath
DrvStrokePath
DrvTextOut
DrvTransparentBlt

If you provide a customized hooking function, it preempts the driver's equivalent graphics DDI function. Hooking functions can also call back into the driver's graphics DDI functions. For more information see Customized Graphics DDI Functions.

Customized hooking functions have the same input and output parameters as the equivalent graphics DDI function, with one exception – where graphics DDI functions receive PDEV pointers, customized hooking functions receive DEVOBJ pointers. There are two ways for graphics DDI functions to receive PDEV pointers:

  • As the contents of the dhpdev member of a SURFOBJ structure for the destination surface.

    For the equivalent customized hooking function, the destination SURFOBJ structure's dhpdev member points to a DEVOBJ structure, and must be cast to type PDEVOBJ when referenced. An example graphics DDI function is DrvBitBlt.

  • As an input argument for a dhpdev parameter.

    The equivalent customized hooking function must cast this input parameter to type PDEVOBJ when referencing it. An example graphics DDI function is DrvDitherColor.

Note that while a printer graphics DLL includes the addresses of its DrvEnablePDEV, DrvDisablePDEV, and DrvResetPDEV functions in the DRVENABLEDATA structure, a rendering plug-in explicitly exports EnablePDEV, DisablePDEV, and ResetPDEV as methods of the IPrintOemUni interface and does not place their addresses in the DRVENABLEDATA structure.

If IPrintOemUni::EnableDriver methods are exported by multiple rendering plug-ins, the methods are called in the order that the plug-ins are specified for installation.

Note Each graphics DDI function can be hooked out by one rendering plug-in. If multiple plug-ins attempt to hook out the same graphics DDI function, all hook-outs after the first one are ignored.

For more information about creating and installing rendering plug-ins, see Customizing Microsoft's Printer Drivers.


IPrintOemUni::EnablePDEV

The IPrintOemUni::EnablePDEV method allows a rendering plug-in for Unidrv to create its own PDEV structure.

STDMETHOD
  (EnablePDEV) (
    THIS_
    PDEVOBJ  pdevobj,
    PWSTR  pPrinterName,
    ULONG  cPatterns,
    HSURF  *phsurfPatterns,
    ULONG  cjGdiInfo,
    GDIINFO  *pGdiInfo,
    ULONG  cjDevInfo,
    DEVINFO  *pDevInfo,
    DRVENABLEDATA  *pded,
    OUT PDEVOEM  *pDevOem
    ) PURE;

Parameters

pdevobj
Caller-supplied pointer to a DEVOBJ structure.
pPrinterName
Caller-supplied pointer to a text string representing the logical address of the printer.
cPatterns
Caller-supplied value representing the number of HSURF-typed surface handles contained in the buffer pointed to by phsurfPatterns.
phsurfPatterns
Caller-supplied pointer to a buffer that is large enough to contain cPatterns number of HSURF-typed surface handles. The handles represent surface fill patterns.
cjGdiInfo
Caller-supplied value representing the size of the structure pointed to by pGdiInfo.
pGdiInfo
Caller-supplied pointer to a GDIINFO structure.
cjDevInfo
Caller-supplied value representing the size of the structure pointed to by pDevInfo.
pDevInfo
Caller-supplied pointer to a DEVINFO structure.
pded
Caller-supplied pointer to a DRVENABLEDATA structure containing the addresses of the printer driver's graphics DDI hooking functions. For more information, see the following Comments section.
pDevOem
Receives a method-supplied pointer to a private PDEV structure. (For more information, see the following Comments section.)

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

If the operation fails, the method should call SetLastError to set an error code.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemUni::EnablePDEV method performs the same types of operations as the DrvEnablePDEV function that is exported by a printer graphics DLL. Its purpose is to allow a rendering plug-in to create its own PDEV structure. (For more information about PDEV structures, see Customized PDEV Structures.)

If you provide a rendering plug-in that exports the IPrintOemUni::EnablePDEV method, Undrv's printer graphics DLL calls the method from within its DrvEnablePDEV function.

The IPrintOemUni::EnablePDEV method should allocate an instance of its private PDEV structure, initialize it, and return its address as the method's pDevOem parameter. Other plug-in methods receive the address as the pdevOEM member of the DEVOBJ structure.

The pdevOEM member of the DEVOBJ structure is not used with the IPrintOemUni::EnablePDEV method.

The structures pointed to by the phsurfPatterns, pGdiInfo, and pDevInfo parameter values are the same ones that Unidrv's DrvEnablePDEV function receives. The rendering plug-in can modify the structure contents as necessary. It can supply surface fill patterns by obtaining HSURF-typed surface handles and placing them in the buffer pointed to by phsurfPatterns. Fill pattern types and handle order are listed in the description of DrvEnablePDEV.

The DRVENABLEDATA structure pointed to by pded contains the addresses of graphics DDI functions provided Unidrv's printer graphics DLL. You are allowed to provide customized hooking functions in your plug-in for these graphics DDI functions. The DRVENABLEDATA structure's contents enable your customized hooking functions to call back to the driver's graphics DDI functions. For more information, see Customized Graphics DDI Functions.


IPrintOemUni::FilterGraphics

The IPrintOemUni::FilterGraphics method can be used with Unidrv-supported printers to modify scan line data and send it to the spooler.

STDMETHOD
  (FilterGraphics) (
    THIS_
    PDEVOBJ  pdevobj,
    PBYTE  pBuf,
    DWORD  dwLen
    ) PURE;

Parameters

pdevobj
Caller-supplied pointer to a DEVOBJ structure.
pBuf
Caller-supplied pointer to a buffer containing scan line data to be printed.
dwLen
Caller-supplied value representing the length, in bytes, of the data pointed to by pBuf.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemUni::FilterGraphics method is used to modify scan line data before it is sent to the print spooler. The method's purpose is to provide customized manipulation of scan line data before it is spooled. The method is responsible for sending received data to the spooler.

If you implement the IPrintOemUni::FilterGraphics method, Unidrv does not spool printer data. Instead, Unidrv calls the method each time a buffer of image data is ready to be spooled.

The method can perform final post-processing of image data, such as removing adjacent dots or any other data stream filtering operation that Unidrv does not provide. It must then spool the data by calling the IPrintOemDriverUni::DrvWriteSpoolBuf method.

If a rendering plug-in implements IPrintOemUni::FilterGraphics, the plug-in's IPrintOemUni::GetImplementedMethod method must return S_OK when it receives "FilterGraphics" as input.

For more information about customizing Unidrv's rendering operations, see Unidrv-Specific Customized Rendering.

See Also

IPrintOemUni::ImageProcessing


IPrintOemUni::GetImplementedMethod

The IPrintOemUni::GetImplementedMethod method is used by Unidrv to determine which IPrintOemUni interface methods have been implemented by a rendering plug-in.

STDMETHOD
  (GetImplementedMethod) (
    THIS_
    PSTR  pMethodName
    ) PURE;

Parameters

pMethodName
Caller-supplied pointer to a string representing the name of an IPrintOemUni interface method, such as "ImageProcessing" for IPrintOemUni::ImageProcessing or "FilterGraphics" for IPrintOemUni::FilterGraphics.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded (the specified method is implemented).
E_FAIL | The operation failed (the specified method is not implemented).
E_NOTIMPL | The GetImplementedMethod method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

Rendering plug-ins for Unidrv must implement the IPrintOemUni::GetImplementedMethod method. The method must examine the received method name string and supply a return value indicating whether or not the specified method has been implemented within the plug-in. For methods that IPrintOemUni::GetImplementedMethod must recognize, the method's Comments section identifies the supplied name string.


IPrintOemUni::GetInfo

A rendering plug-in's IPrintOemUni::GetInfo method returns identification information.

STDMETHOD
  (GetInfo) (
    THIS_
    DWORD  dwMode,
    PVOID  pBuffer,
    DWORD  cbSize,
    PDWORD  pcbNeeded
    ) PURE;

Parameters

dwMode
Contains one of the following caller-supplied integer constants.
Constant Definition
OEMGI_GETSIGNATURE
The method must return a unique four-byte identification signature. The plug-in must also place this signature in OPTITEM structures, as described in the description of the OEMCUIPPARAM. structure's pOEMOptItems member.
OEMGI_GETVERSION
The method must return the user interface plug-in's version number as a DWORD. The version format is developer-defined.

pBuffer
Caller-supplied pointer to memory allocated to receive the information specified by dwInfo.
cbSize
Caller-supplied size of the buffer pointed to by pBuffer.
pcbNeeded
Caller-supplied pointer to a location to receive the number of bytes written into the buffer pointed to by pBuffer.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

Rendering plug-ins for Unidrv are required to implement the IPrintOemUni::GetInfo method, which is called immediately after the plug-in is loaded. The method should return the specified information by writing it to the address specified by pBuffer and writing the size, in bytes, of the returned information into the location specified by pcbNeeded.

If pBuffer is NULL, the method should just use pcbNeeded to return the number of bytes required to store the specified information.

For more information about creating and installing rendering plug-ins, see Customizing Microsoft's Printer Drivers.

See Also

IPrintOemUI::GetInfo, IPrintOemPs::GetInfo


IPrintOemUni::HalftonePattern

The IPrintOemUni::HalftonePattern method can be used with Unidrv-supported printers to create or modify a halftone pattern before it is used in a halftoning operation.

STDMETHOD
  (HalftonePattern) (
    THIS_
    PDEVOBJ  pdevobj,
    PBYTE  pHTPattern,
    DWORD  dwHTPatternX,
    DWORD  dwHTPatternY,
    DWORD  dwHTNumPatterns,
    DWORD  dwCallbackID,
    PBYTE  pResource,
    DWORD  dwResourceSize
    ) PURE;

Parameters

pdevobj
Caller-supplied pointer to a DEVOBJ structure.
pHTPattern
Caller-supplied pointer to a buffer to receive the method-supplied halftone pattern. Buffer size, in bytes, is:
(((dwHTPatternX * dwHTPatternY) + 3)/4) * 4 * dwHTNumPatterns.
dwHTPatternX
Caller-supplied length, in pixels, of the halftone pattern, as specified by the GPD file's *HTPatternSize attribute.
dwHTPatternY
Caller-supplied height, in pixels, of the halftone pattern, as specified by the GPD file's *HTPatternSize attribute.
dwHTNumPatterns
Caller-supplied number of patterns, as specified by the GPD file's *HTNumPatterns attribute. Can be 1 or 3.
dwCallbackID
Caller-supplied value identifying the halftone method, as specified by the GPD file's *HTCallbackID attribute.
pResource
Caller-supplied pointer to a buffer containing a halftone pattern, as specified by the GPD file's *rcHTPatternID attribute. Can be NULL.
dwResourceSize
Caller-supplied size of the halftone pattern contained in the buffer pointed to by pResource. Will be zero if pResource is NULL.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemUni::HalftonePattern method is used to create or modify a halftone pattern before Unidrv passes it to GDI. Its purpose is to allow proprietary halftone patterns to be either stored as encrypted resources or generated at run time.

If the IPrintOemUni::HalftonePattern method is implemented, and if the GPD file entry for the currently selected halftoning method includes an *HTCallbackID attribute, Unidrv calls the IPrintOemUni::HalftonePattern method before passing a halftone pattern to GDI.

If the GPD file entry for the currently selected halftoning method contains an *rcHTPatternID entry identifying an RC_HTPATTERN resource, Unidrv obtains the pattern and passes a pointer to it as the pResource parameter value. This allows you to store the pattern as an encrypted resource, and to use the IPrintOemUni::HalftonePattern method to decode the pattern. The decoded pattern should be returned in the buffer pointed to by pHTPattern.

You can also use the IPrintOemUni::HalftonePattern method to generate a halftone pattern. In this case an RC_HTPATTERN resource is not needed, so pResource is NULL. The IPrintOemUni::HalftonePattern method should generate a pattern and return it in the buffer pointed to by pHTPattern.

If the IPrintOemUni::HalftonePattern method returns one pattern, it is used for all colors. If the method returns three patterns, they must be specified in RGB order.

If a rendering plug-in implements IPrintOemUni::HalftonePattern, the plug-in's IPrintOemUni::GetImplementedMethod method must return S_OK when it receives "HalftonePattern" as input.

For more information about halftoning, see Customized Halftoning.

See Also

IPrintOemUni::ImageProcessing


IPrintOemUni::ImageProcessing

The IPrintOemUni::ImageProcessing method can be used with Unidrv-supported printers to modify image bitmap data, in order to perform color formatting or halftoning. The method can return the modified bitmap to Unidrv or send it directly to the print spooler.

STDMETHOD
  (ImageProcessing) (
    THIS_
    PDEVOBJ  pdevobj,
    PBYTE  pSrcBitmap,
    PBITMAPINFOHEADER  pBitmapInfoHeader,
    PBYTE  pColorTable,
    DWORD  dwCallbackID,
    PIPPARAMS  pIPParams,
    OUT PBYTE  *ppbResult
    ) PURE;

Parameters

pdevobj
Caller-supplied pointer to a DEVOBJ structure.
pSrcBitmap
Caller-supplied pointer to an input DIB.
pBitmapInfoHeader
Caller-supplied pointer to a BITMAPINFOHEADER structure that describes the bitmap pointed to by pSrcBitmap. The BITMAPINFOHEADER structure is described in the Platform SDK documentation.
pColorTable
Caller-supplied pointer to color table. Used only if the output format is eight bits per pixel. For more information, see the following Comments section.
dwCallbackID
Caller-supplied value assigned to the *IPCallbackID attribute of the currently selected option for the ColorMode feature. For more information, see the following Comments section.
pIPParams
Caller-supplied pointer to an IPPARAMS structure.
ppbResult
If the method returns the converted DIB to Unidrv:
If the conversion succeeds, the method should return a pointer to a buffer containing the converted DIB. Otherwise it should return NULL.
If the method sends the converted DIB to the print spooler:
If the operation succeeds, the method should return TRUE. Otherwise it should return FALSE.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemUni::ImageProcessing method is used to modify image bitmaps before they are sent to the print spooler. Its purpose is to provide customized support for color modes and halftoning methods not supported by Unidrv. A printer driver that sends a bitmap to the print spooler (as opposed to sending it back to Unidrv) must set the *DevBPP and *DevNumOfPlanes attributes to zero in the printer's GPD file.

If the method is implemented, and if the GPD file entry for the current color format contains an *IPCallbackID attrubute, Unidrv calls the method each time a bitmap is available. The call is made after the bitmap has been rendered, using GDI, but before it is sent to the print spooler. (For information about the *IPCallbackID attribute, see Option Attributes for the ColorMode Feature.)

If the current color mode, as specified by dwCallbackID, is one that Unidrv supports, then the IPrintOemUni::ImageProcessing method should perform halftoning operations on the received bitmap and return it to Unidrv for spooling. If the current color mode is one that Unidrv does not support, the method must perform halftoning operations and then spool the bitmap.

If the method is only performing halftoning operations, it must do the following:

  • Perform halftoning operations on the data, as indicated by the pHalftoneOption member of the IPPARAMS structure.
  • Return the modified image data to Unidrv by placing it in a buffer and supplying the buffer's address as the method's return value. The returned buffer can be the one pointed to by pSrcBitmap, or it can be one that is locally allocated.

For more information about customizing halftoning operations in Unidrv, see Customized Halftoning.

To handle customized color formatting, the IPrintOemUni::ImageProcessing method must do the following:

  • Convert DIB data, described by the pSrcBitmap and pBitmapInfoHeader parameter values, into the color format indicated by dwCallbackID.
  • Perform halftoning operations on the data, as indicated by the pHalftoneOption member of the IPPARAMS structure.
  • Send the data to the print spooler by calling the IPrintOemDriverUni::DrvWriteSpoolBuf method.
  • Modify printer's cursor position by making appropriate calls to the IPrintOemDriverUni::DrvXMoveTo and IPrintOemDriverUni::DrvYMoveTo methods.

For more information about customizing color formatting operations in Unidrv, see Customized Color Formats.

The dwCallbackID parameter indicates the type of color formatting, if any, that should be performed. Within the printer's GPD file, each *Option entry for the ColorMode feature describes a color format. If the format requires processing by the IPrintOemUni::ImageProcessing method, its *Option entry must contain an *IPCallbackID attribute. When Unidrv calls the IPrintOemUni::ImageProcessing method, it supplies the attribute value associated with the currently selected option for the ColorMode feature. This value is the dwCallbackID parameter's value.

Whether the IPrintOemUni::ImageProcessing method is performing color formatting operations and spooling image data, or just performing halftoning operations and returning processed bitmaps to Unidrv, it should export an IPrintOemUni::MemoryUsage method if it allocates significant amounts of memory for destination bitmaps or other purposes. Otherwise, system performance might be degraded.

If the method is implemented, it is called for every raster region on the page. However, if a region is blank, the bBlankBand member of the IPPARAMS structure will be TRUE, which indicates the block is blank and the data is invalid. Since a band can be broken up into alternating blocks of blank and non-blank regions to optimize performance, the block size won't always correspond to the band size.

Source Bitmap Characteristics

The source bitmap described by pSrcBitmap and pBitmapInfoHeader has the following characteristics:

  • DIB contents are top-down ordered and uncompressed.
  • The data format is one that is listed in Handling Color Formats.
  • If the format requires a color table, the table is pointed to by pColorTable.
  • Color data is in PRIMARY_ORDER_CBA format, as explained in the description of GDIINFO. In other words, if the color format is RGB or CMY, the least significant n bits must contain the red or yellow value, the next n bits must contain the green or magenta value, and the next n bits must contain the red or cyan value. Unused bits are in the most significant position. If the format uses 4 bits per pixel, then n is 1. For 24 bits per pixel, n is 8. For CYMK, the fourth n bits contain black.

Destination Bitmap Characteristics

For halftoning operations, in which a processed bitmap is returned to Unidrv, the returned bitmap must have the following characteristics:

  • DIB contents must be top-down ordered and uncompressed.
  • The data format must be one that is listed in Handling Color Formats, and it must be compatible with the *DevBPP and *DevNumOfPlanes attributes of the color format identified by dwCallbackID. (For information about these attributes, see Option Attributes for the ColorMode Feature.)
  • If the format requires a color table, the table must be created and its address must be returned in pColorTable.
  • Color data must be returned in PRIMARY_ORDER_CBA format, as described for the source bitmap.
  • The BITMAPINFOHEADER structure specified by pBitmapInfoHeader must describe both the input and output bitmaps. The IPrintOemUni::ImageProcessing method must not change the structure's contents.

If a rendering plug-in implements IPrintOemUni::ImageProcessing, the plug-in's IPrintOemUni::GetImplementedMethod method must return S_OK when it receives "ImageProcessing" as input.

See Also

IPrintOemUni::FilterGraphics


IPrintOemUni::MemoryUsage

The IPrintOemUni::MemoryUsage method can be used with Unidrv-supported printers to specify the amount of memory required for use by a rendering plug-in's IPrintOemUni::ImageProcessing method.

STDMETHOD
  (MemoryUsage) (
    THIS_
    PDEVOBJ  pdevobj,
    POEMMEMORYUSAGE  pMemoryUsage
    ) PURE;

Parameters

pdevobj
Caller-supplied pointer to a DEVOBJ structure.
pMemoryUsage
Caller-supplied pointer to an OEMMEMORYUSAGE structure.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemUni::MemoryUsage method's purpose is to help the Unidrv driver determine the optimum size for the GDI drawing surface, based on the memory requirements of the IPrintOemUni::ImageProcessing method. Implementation of the IPrintOemUni::MemoryUsage method is optional.

The IPrintOemUni::MemoryUsage method should return two values, as follows:

  • The amount of permanently-allocated, fixed-sized memory that the IPrintOemUni::ImageProcessing method needs to allocate.

    This value is returned in the dwFixedMemoryUsage member of the OEMMEMORYUSAGE structure.

  • The amount of memory required to hold a bitmap after the IPrintOemUni::ImageProcessing method has finished processing it.

    The rendering plug-in either returns this processed bitmap to Unidrv, or spools it. The amount of memory required to store the processed bitmap is returned in the dwPercentMemoryUsage member of the OEMMEMORYUSAGE structure, and is expressed as a percentage of the source bitmap's size.

The value returned in the dwPercentMemoryUsage member should include, in addition to the processed bitmap's size, the amount of any addition memory allocations that are dependent on the size of the source bitmap.

The dwMaxBandSize member of the OEMMEMORYUSAGE structure is supplied by Unidrv and specifies the default maximum band size.

Before the Unidrv driver creates a drawing surface, it requests GDI to determine the optimum size for image banding bitmaps, based on available system memory. This optimum memory space must be shared, for each banding bitmap, between a source bitmap that is passed to the IPrintOemUni::ImageProcessing method and a (typically smaller) processed bitmap that the method either returns or outputs. Unidrv calls the rendering plug-in's IPrintOemUni::MemoryUsage method, if it exists, and uses the result to calculate how best to divide the optimum memory space.

For example, suppose GDI reports that the optimum amount of memory to use for drawing is 6 megabytes (contained in the OEMMEMORYUSAGE structure's dwMaxBandSize member), while the rendering plug-in's IPrintOemUni::MemoryUsage method returns values of zero for dwFixedMemoryUsage and 50 for dwPercentMemoryUsage. The value of 50 means that the IPrintOemUni::ImageProcessing method's output bitmaps will be 50 percent smaller than the source bitmaps. Therefore, Unidrv will allocate a source bitmap size of 4 megabytes, thus causing output bitmaps to be 2 megabytes.

If an IPrintOemUni::MemoryUsage method is not provided, Unidrv allocates all the optimum available space to the source bitmap. This is acceptable if the IPrintOemUni::ImageProcessing method returns the processed bitmap in the memory space allocated for the source bitmap. However, if a rendering plug-in's IPrintOemUni::ImageProcessing method does allocate space for a destination bitmap but does not provide an IPrintOemUni::MemoryUsage method, the result is that more memory will be allocated for bitmaps than the optimum available size, potentially causing performance degradation.

If a rendering plug-in implements IPrintOemUni::MemoryUsage, the plug-in's IPrintOemUni::GetImplementedMethod method must return S_OK when it receives "MemoryUsage" as input.


IPrintOemUni::OutputCharStr

The IPrintOemUni::OutputCharStr method enables a rendering plug-in to control the printing of font glyphs.

STDMETHOD
  (OutputCharStr) (
    THIS_
    PDEVOBJ  pdevobj,
    PUNIFONTOBJ  pUFObj,
    DWORD  dwType,
    DWORD  dwCount,
    PVOID  pGlyph
    ) PURE;

Parameters

pdevobj
Caller-supplied pointer to a DEVOBJ structure.
pUFObj
Caller-supplied pointer to a UNIFONTOBJ structure.
dwType
Caller-supplied value indicating the type of glyph specifier array pointed to by pGlyph. Valid values are as follows:
Value | Definition
TYPE_GLYPHHANDLE | The pGlyph array elements are glyph handles of type HGLYPH.
TYPE_GLYPHID | The pGlyph array elements are glyph identifiers of type DWORD.

dwCount
Caller-supplied value representing the number of glyph specifiers in the array pointed to by pGlyph.
pGlyph
Caller-supplied pointer to an array of glyph specifiers, where the array element type is indicated by dwType.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemUni::OutputCharStr method is used for supporting printers that do not recognize the PCL, CAPSL, or PPDS-formatted character output commands supported by Unidrv. Its purpose is to allow a rendering plug-in to control the printing of a font's glyphs, and to provide glyph substitutions if necessary.

If a rendering plug-in implements the IPrintOemUni::OutputCharStr method, Unidrv calls the method each time a string of characters is ready to be spooled.

The method receives an array of glyph specifiers. The value received for dwType indicates the identifier type.

If the specified font is a device font, the array contains glyph handles. The handles need to be translated to character codes or commands, and then sent to the print spooler to cause device glyphs to be printed.

If the specified font is a soft (TrueType) font, the array contains glyph identifiers. The identifiers represent previously downloaded glyphs that need to be printed.

If the specified font is a device font, the method must do the following:

  1. Allocate a GETINFO_GLYPHSTRING structure with dwTypeIn set to TYPE_GLYPHHANDLE and dwTypeOut set to TYPE_TRANSDATA.
  2. Call the UNIFONTOBJ_GetInfo function, passing the GETINFO_GLYPHSTRING structure as input, to obtain glyph translations as TRANSDATA structure contents.
  3. Call IPrintOemDriverUni::DrvWriteSpoolBuf to send TRANSDATA structure contents to the print spooler, in order to print the glyphs.

If the specified font is a soft font, the method can just call IPrintOemDriverUni::DrvWriteSpoolBuf to send commands to the print spooler that will cause the specified previously-downloaded glyphs to be printed.

If a rendering plug-in implements IPrintOemUni::OutputCharStr, the plug-in's IPrintOemUni::GetImplementedMethod method must return S_OK when it receives "OutputCharStr" as input.

For additional information see Customized Font Management.


IPrintOemUni::PublishDriverInterface

The IPrintOemUni::PublishDriverInterface method allows a rendering plug-in for Unidrv to obtain the Unidrv driver's IPrintOemDriverUni interface.

STDMETHOD
  (PublishDriverInterface) (
    THIS_
    IUnknown  *pIUnknown
    ) PURE;

Parameters

pIUnknown
Caller-supplied pointer to the IUnknown interface of the driver's IPrintOemDriverUni COM interface.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

A rendering plug-in for Unidrv must implement the IPrintOemUni::PublishDriverInterface method and the method must return S_OK, or the driver will not call the plug-in's other IPrintOemUni interface methods.

If the rendering plug-in will be calling IPrintOemDriverUni interface methods, it must use the received IUnknown interface pointer to call IUnknown::QueryInterface (described in the Platform SDK documentation) in order to obtain a pointer to the driver's supported version of the IPrintOemDriverUni interface. For more information, see Interface Identifiers for Printer Drivers .


IPrintOemUni::ResetPDEV

The IPrintOemUni::ResetPDEV method allows a rendering plug-in for Unidrv to reset its PDEV structure.

STDMETHOD
  (ResetPDEV) (
    THIS_
    PDEVOBJ  pdevobjOld,
    PDEVOBJ  pdevobjNew
    ) PURE;

Parameters

pdevobjOld
Caller-supplied pointer to a DEVOBJ structure containing current PDEV information.
pdevobjNew
Caller-supplied pointer to a DEVOBJ structure into which the method should place new PDEV information.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

If the operation fails it should call SetLastError.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

A rendering plug-in's IPrintOemUni::ResetPDEV method performs the same types of operations as the DrvResetPDEV function that is exported by a printer graphics DLL. During the processing of an application's call to the Platform SDK ResetDC function, the IPrintOemUni::ResetPDEV method is called by the DrvResetPDEV function in Unidrv's printer graphics DLL. For more information about when DrvResetPDEV is called, see its description.

The rendering plug-in's private PDEV structure's address is contained in the pdevOEM member of the DEVOBJ structure pointed to by pdevobjOld. The IPrintOemUni::ResetPDEV method should use relevant members of this old structure to fill in the new structure, which is referenced through pdevobjNew.


IPrintOemUni::SendFontCmd

The IPrintOemUni::SendFontCmd method enables a rendering plug-in to modify a printer's font selection command and then send it to the printer.

STDMETHOD
  (SendFontCmd) (
    THIS_
    PDEVOBJ  pdevobj,
    PUNIFONTOBJ  pUFObj,
    PFINVOCATION  pFInv
    ) PURE;

Parameters

pdevobj
Caller-supplied pointer to a DEVOBJ structure.
pUFObj
Caller-supplied pointer to a UNIFONTOBJ structure.
pFInv
Caller-supplied pointer to an FINVOCATION structure.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemUni::SendFontCmd method is used for selecting device fonts on printers that do not recognize the PCL, CAPSL, or PPDS-formatted font commands supported by Unidrv. Its purpose is to allow a rendering plug-in to modify the font selection command that is specified in the font's .ufm (Unidrv Font Metrics) file. (To see how the command is stored, refer to the description of .ufm file's UNIDRVINFO structure.) If the command needs to be modified before being sent to the printer, you should implement the IPrintOemUni::SendFontCmd method.

The method receives the command string in the FINVOCATION structure pointed to by pFInv. Typically, the string contains variables for which values must be supplied. For example, the following font selection command requires that #FontHeight and #FontWidth be replaced with numeric values:

\x1B(9U\x1B(s4148t0b0s#FontHeight1P\x1B)6J\x1B)s4148t0b0s#FontWidth1P

Current values for the font height and width can be obtained by calling UNIFONTOBJ_GetInfo to read Unidrv's standard variables.

Whenever the IPrintOemUni::SendFontCmd method called, it must send the command string to the printer by calling IPrintOemDriverUni::DrvWriteSpoolBuf.

If a rendering plug-in implements IPrintOemUni::SendFontCmd, the plug-in's IPrintOemUni::GetImplementedMethod method must return S_OK when it receives "SendFontCmd" as input.

For additional information see Customized Font Management.


IPrintOemUni::TextOutAsBitmap

The IPrintOemUni::TextOutAsBitmap method allows a rendering plug-in to create a bitmap image of a text string, in case a downloadable font is not available.

STDMETHOD
  (TextOutAsBitmap) (
    THIS_
    SURFOBJ  *pso,
    STROBJ  *pstro,
    FONTOBJ  *pfo,
    CLIPOBJ  *pco,
    RECTL  *prclExtra,
    RECTL  *prclOpaque,
    BRUSHOBJ  *pboFore,
    BRUSHOBJ  *pboOpaque,
    POINTL  *pptlOrg,
    MIX  mix
    ) PURE;

Parameters

Parameters for IPrintOemUni::TextOutAsBitmap are identical to DrvTextOut parameters.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemUni::TextOutAsBitmap method is called from Unidrv's IPrintOemDriverUni::DrvUniTextOut method, if that method cannot create the text string using downloadable fonts, either because the font is not available or is rotated. IPrintOemUni::TextOutAsBitmap should create a bitmap image of the text and send it to the print device.

If a rendering plug-in implements IPrintOemUni::TextOutAsBitmap, the plug-in's IPrintOemUni::GetImplementedMethod method must return S_OK when it receives "TextOutAsBitmap" as input.


IPrintOemUni::TTDownLoadMethod

The IPrintOemUni::TTDownLoadMethod method enables a rendering plug-in to indicate the format that Unidrv should use for a specified TrueType soft font.

STDMETHOD
  (TTDownLoadMethod) (
    THIS_
    PDEVOBJ  pdevobj,
    PUNIFONTOBJ  pUFObj,
    OUT DWORD  *pdwResult
    ) PURE;

Parameters

pdevobj
Caller-supplied pointer to a DEVOBJ structure.
pUFObj
Caller-supplied pointer to a UNIFONTOBJ structure.
pdwResult
Receives one of the following method-supplied constant values:
Value | Definition
TTDOWNLOAD_BITMAP | Unidrv should download the specified font as bitmaps.
TTDOWNLOAD_DONTCARE | Unidrv can select the font format.
TTDOWNLOAD_GRAPHICS | Unidrv should print TrueType fonts as graphics, instead of downloading the font.
TTDOWNLOAD_TTOUTLINE | Unidrv should download the specified font as outlines. For more information, see the following Comments section.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemUni::TTDownLoadMethod method's purpose is to allow a rendering plug-in to specify a printer's preferred format for a specified TrueType soft font.

If a rendering plug-in implements the IPrintOemUni::TTDownLoadMethod method, Unidrv calls the method each time it is ready to send a TrueType font to the print spooler. Unidrv specifies the font type and the IPrintOemUni::TTDownLoadMethod method should specify the printer's preferred format in the location pointed to by pdwResult.

The method should not return TTDOWNLOAD_TTOUTLINE unless the printer can rasterize TrueType fonts. The rendering plug-in is responsible for reading and parsing TrueType font files. Pointers to TrueType font files can be obtained by calling FONTOBJ_pvTrueTypeFontFile.

If a rendering plug-in implements IPrintOemUni::TTDownLoadMethod, the plug-in's IPrintOemUni::GetImplementedMethod method must return S_OK when it receives "TTDownLoadMethod" as input.

For additional information see Customized Font Management.


IPrintOemUni::TTYGetInfo

The IPrintOemUni::TTYGetInfo method enables a rendering plug-in to supply Unidrv with information relevant to text-only printers.

STDMETHOD
  (TTYGetInfo) (
    THIS_
    PDEVOBJ  pdevobj,
    DWORD  dwInfoIndex,
    PVOID  pOutputBuf,
    DWORD  dwSize,
    DWORD  *pcbcNeeded
    ) PURE;

Parameters

pdevobj
Caller-supplied pointer to a DEVOBJ structure.
dwInfoIndex
Caller-supplied constant identifying the type of information being requested. The following constant values are defined:
Value Definition
OEMTTY_INFO_CODEPAGE
The pOutputBuf parameter points to a DWORD in which the method should return the number of the code page to be used.
OEMTTY_INFO_MARGINS
The pOutputBuf parameter points to a RECT structure in which the method should return page margin widths, in tenths of millimeters (for example, 20 represents 2 mm). If the entire page is printable, all margin values must be 0.
OEMTTY_INFO_NUM_UFMS
The pOutputBuf parameter points to a DWORD in which the method should return the number of resource IDs of the UFMs for 10, 12, and 17 CPI fonts. To actually obtain these resource IDs, perform a query using OEMTTY_INFO_UFM_IDS.
OEMTTY_INFO_UFM_IDS
The pOutputBuf parameter points to an array of DWORDs of sufficient size to hold the number of resource IDs of the UFMs for 10, 12, and 17 CPI fonts. (This number is obtained by using OEMTTY_INFO_NUM_UFMS in a query.) The method should return the resource IDs of the UFMs for 10,12, and 17 CPI fonts.

pOutputBuf
Caller-supplied pointer to a buffer to receive the requested information.
dwSize
Caller-supplied size, in bytes, of the buffer pointed to by pOutputBuf.
pcbcNeeded
Caller-supplied pointer to a location to receive the number of bytes written into the buffer pointed to by pOutputBuf. If the number of bytes required is smaller than the number specified by dwSize, the method should supply the required size and return E_FAIL.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

If a rendering plug-in implements IPrintOemUni::TTYGetInfo, the plug-in's IPrintOemUni::GetImplementedMethod method must return S_OK when it receives "TTYGetInfo" as input.


IPrintOemUni2 Interface

This section describes the methods defined for the IPrintOemUni2 COM interface. Method prototypes are defined in prcomoem.h.


IPrintOemUni2::WritePrinter

The IPrintOemUni2::WritePrinter method, if supported, enables a rendering plug-in to capture all output data generated by a Unidrv driver. If this method is not supported, the output data would otherwise be sent to the spooler in a call to the spooler's WritePrinter API (described in the Platform SDK documentation).

STDMETHOD
  (WritePrinter) (
    IN THIS_
    IN PDEVOBJ pdevobj,
    IN PVOID pBuf,
    IN DWORD cbBuffer,
    OUT PDWORD pcbWritten
    ) PURE;

Parameters

pdevobj
Points to a DEVOBJ structure.
pBuf
Points to the first byte of an array of bytes that contains the output data generated by the Unidrv driver.
cbBuffer
Specifies the size, in bytes, of the array pointed to by pBuf.
pcbWritten
Points to a DWORD value that receives the number of bytes of data that were successfully sent to the plug-in.

Return Value

If successful, this method returns S_OK. Otherwise, this method should return an appropriate value in the returned HRESULT.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

At DrvEnablePDEV time, the Unidrv driver will call this method with pBuf and pdevobj set to NULL, and cbBuf set to 0, to detect whether the plug-in implements this function. The plug-in should return S_OK to indicate it implements this method, and should return E_NOTIMPL otherwise.

This method should report the number of bytes written to the spooler's WritePrinter function in pcbWritten. A value of zero carries no special meaning; errors must be reported through the returned HRESULT.


IPrintOemDriverUni Interface

This section describes the methods defined for the IPrintOemDriverUni COM interface. Method prototypes are defined in prcomoem.h.


IPrintOemDriverUni::DrvGetDriverSetting

The IPrintOemDriverUni::DrvGetDriverSetting method is provided by the Unidrv driver so that rendering plug-ins can obtain the current status of printer features and other internal information.

STDMETHOD
  (DrvGetDriverSetting) (
    THIS_
    PVOID  pdriverobj,
    PCSTR  Feature,
    PVOID  pOutput,
    DWORD  cbSize,
    PDWORD  pcbNeeded,
    PDWORD  pdwOptionsReturned
    ) PURE;

Parameters

pdriverobj
Caller-supplied pointer to a DEVOBJ structure.
Feature
Caller supplied value identifying the printer feature for which option settings will be returned. This can be either a string pointer or a constant, as described in the following Comments section.
pOutput
Caller-supplied pointer to a buffer to receive the specified information.
cbSize
Caller-supplied size, in bytes, of the buffer pointed to by pOutput.
pcbNeeded
Caller-supplied pointer to a location to receive the minimum buffer size required to contain the requested information.
pdwOptionsReturned
Caller-supplied pointer to a location to receive the number of option strings placed in pOutput.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

When the IPrintOemDriverUni::DrvGetDriverSetting method is called, either a string pointer or a constant value can be specified for pFeatureKeyword.

  • If pFeatureKeyword is a string, it must represent a feature name specified in a Unidrv minidriver GPD file

    The method should return one or more NULL-terminated strings in the buffer pointed to by pOutput. Each string should represent the name of a currently selected option. The number of strings should be returned in pdwOptionsReturned.

  • If pFeatureKeyword is a constant, it must be one of the OEMGDS_-prefixed constants defined in printoem.h. The method should return the value indicated by the specified constant by placing it in the buffer pointed to by pOutput. The value returned in pdwOptionsReturned must be 1.


IPrintOemDriverUni::DrvGetGPDData

The IPrintOemDriverUni::DrvGetGPDData method is provided by the Unidrv driver so that rendering plug-ins can obtain data defined in a printer's GPD file.

STDMETHOD
  (DrvGetGPDData) (
    THIS_
    PDEVOBJ  pdevobj,
    DWORD  dwType,
    PVOID  pInputData,
    PVOID  pBuffer,
    DWORD  cbSize,
    PDWORD  pcbNeeded
    ) PURE;

Parameters

pdevobj
Caller-supplied pointer to a DEVOBJ structure.
dwType
Caller-supplied flag indicating the type of GPD data being requested. Currently, the following flag is the only one defined:
Flag | Definition
GPD_OEMCUSTOMDATA | The method will return the string associated with a GPD file's *OEMCustomData entry.

pInputData
Reserved. Must be zero.
pBuffer
Caller-supplied pointer to a buffer to receive the requested information.
cbSize
Caller-supplied size, in bytes, of the buffer pointed to by pBuffer.
pcbNeeded
Receives the driver-supplied minimum buffer size, in bytes, required to contain the requested information.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

If the buffer specified by pBuffer and cbSize is too small to receive the requested information, Unidrv supplies the required buffer size in the location pointed to by pcbNeeded, returns E_FAIL, and sets the error code to ERROR_INSUFFICIENT_BUFFER.


IPrintOemDriverUni::DrvGetStandardVariable

The IPrintOemDriverUni::DrvGetStandardVariable method is provided by the Unidrv driver so that rendering plug-ins can obtain the current value of Unidrv's standard variables.

STDMETHOD
  (DrvGetStandardVariable) (
    THIS_
    PDEVOBJ  pdevobj,
    DWORD  dwIndex,
    PVOID  pBuffer,
    DWORD  cbSize,
    PDWORD  pcbNeeded
    ) PURE;

Parameters

pdevobj
Caller-supplied pointer to a DEVOBJ structure.
dwIndex
Caller-supplied, SVI_-prefixed index into the list of Unidrv's standard variables. The SVI_-prefixed index values are defined in printoem.h.
pBuffer
Caller-supplied pointer to a DWORD to receive the standard variable's current value.
cbSize
Caller-supplied size of the buffer pointed to by pBuffer.
pcbNeeded
Caller-supplied pointer to a location to receive the minimum buffer size required to contain the requested information.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.


IPrintOemDriverUni::DrvUniTextOut

The IPrintOemDriverUni::DrvUniTextOut method is provided by the Unidrv driver so that a rendering plug-in using a device-managed drawing surface can easily output text strings.

STDMETHOD
  (DrvUniTextOut) (
    THIS_
    SURFOBJ  *pso,
    STROBJ  *pstro,
    FONTOBJ  *pfo,
    CLIPOBJ  *pco,
    RECTL  *prclExtra,
    RECTL  *prclOpaque,
    BRUSHOBJ  *pboFore,
    BRUSHOBJ  *pboOpaque,
    POINTL  *pptlBrushOrg,
    MIX  mix
    ) PURE;

Parameters

Parameters for IPrintOemDriverUni::DrvUniTextOut are identical to DrvTextOut parameters.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemDriverUni::DrvUniTextOut method is provided by Unidrv for use by rendering plug-ins that support a device-managed drawing surface. Such rendering plug-ins must hook out Unidrv's DrvTextOut function, and the IPrintOemDriverUni::DrvUniTextOut method is meant to be called from that hooking function. The hooking function must perform text region clipping and text rotation operations. It can then call IPrintOemDriverUni::DrvUniTextOut to request Unidrv to create the text string using downloadable fonts (and to perform glyph-based clipping).

If IPrintOemDriverUni::DrvUniTextOut cannot create the text string, either because the font is not available or is rotated, it calls the rendering plug-in's IPrintOemUni::TextOutAsBitmap method, which will draw the text string as a bitmap.

For more information, see Handling Device-Managed Surfaces.


IPrintOemDriverUni::DrvWriteAbortBuf

The IPrintOemDriverUni::DrvWriteAbortBuf method is provided by the Unidrv driver to allow an OEM rendering plug-in to send printer clean-up code after a user terminates a print job.

STDMETHOD
  (DrvWriteAbortBuf) (
    THIS_
    PDEVOBJ  pdevobj,
    PVOID  pBuffer,
    DWORD  cbSize,
    DWORD  dwWait
    ) PURE;

Parameters

pdevobj
Caller-supplied pointer to a DEVOBJ structure.
pBuffer
Caller-supplied pointer to a buffer containing a code fragment to be sent to the printer.
cbSize
Caller-supplied number of bytes in the buffer pointed to by pBuffer.
dwWait
Caller-supplied length of time the printer must wait, in milliseconds, before it can start a new print job after the current job is aborted.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

OEMs use IPrintOemDriverUni::DrvWriteSpoolBuf to send output to the printer. If a print job is terminated by the user, IPrintOemDriverUni::DrvWriteSpoolBuf returns E_FAIL and can no longer be used to send any data to the printer. When this occurs, certain printers must have a clean-up code fragment sent to them, resetting their states before they can start new print jobs. For these printers, IPrintOemDriverUni::DrvWritetAbortBuf is used to send this code fragment to the printer.

IPrintOemDriverUni::DrvWriteAbortBuf can only be called after IPrintOemDriverUni::DrvWriteSpoolBuf has returned E_FAIL. IPrintOemDriverUni::DrvWriteAbortBuf should not be called more than once per job.

Rendering plug-ins are described in Customizing Microsoft's Printer Drivers.


IPrintOemDriverUni::DrvWriteSpoolBuf

The IPrintOemDriverUni::DrvWriteSpoolBuf method is provided by the Unidrv driver so that rendering plug-ins can send printer data to the spooler.

STDMETHOD
  (DrvWriteSpoolBuf) (
    THIS_
    PDEVOBJ  pdevobj,
    PVOID  pBuffer,
    DWORD  cbSize,
    OUT DWORD  *pdwResult
    ) PURE;

Parameters

pdevobj
Caller-supplied pointer to a DEVOBJ structure.
pBuffer
Caller-supplied pointer to a buffer containing data to be sent to the print spooler.
cbSize
Caller-supplied value representing the size, in bytes, of the buffer pointed to by pBuffer.
pdwResult
Receives a method-supplied value representing the number of bytes sent to the spooler.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

OEMs use the Unidrv helper function IPrintOemDriverUni::DrvWriteSpoolBuf to send output to the printer. If a print job is terminated by the user, IPrintOemDriverUni::DrvWriteSpoolBuf returns E_FAIL and can no longer be used to send any data to the printer. When this occurs, certain printers must have a clean-up code fragment sent to them, resetting their states before they can start new print jobs. For these printers, IPrintOemDriverUni::DrvWriteAbortBuf can be used to send this code fragment to the printer.

Rendering plug-ins are described in Customizing Microsoft's Printer Drivers.


IPrintOemDriverUni::DrvXMoveTo

The IPrintOemDriverUni::DrvXMoveTo method is provided by the Unidrv driver so that rendering plug-ins can notify the driver of cursor x-position changes.

STDMETHOD
  (DrvXMoveTo) (
    THIS_
    PDEVOBJ  pdevobj,
    INT  x,
    DWORD  dwFlags,
    OUT INT  *piResult
    ) PURE;

Parameters

pdevobj
Caller-supplied pointer to a DEVOBJ structure.
x
Caller-supplied value representing the number of units the cursor should be moved. The unit is defined by the MV_GRAPHICS flags in dwFlags.
dwFlags
One or more of the following caller-supplied bit flags:
Flag Definition
MV_GRAPHICS If set, the x parameter's value is expressed in dots, based on the printer's current resolution. For example, if the x resolution is 150 DPI and x is 75, the movement is ½ inch.

If not set, the x parameter's value is expressed in master units. For example, if the x master unit is 600 and x is 300, the movement is ½ inch.
MV_PHYSICAL If set, the x parameter's value is relative to the cursor origin.

If not set, the x parameter's value is relative to the printable area's origin.

Cannot be set if MV_RELATIVE is set.
MV_RELATIVE If set, specifies that the cursor should be moved x units from its current position.

If not set, specifies that the cursor should be moved x units from its origin.
MV_UPDATE If set, specifies that Unidrv should update its current calculation of the cursor position without actually moving the cursor. (Should be set if IprintOemUni::ImageProcessing has moved the cursor.)

If not set, specifies that Unidrv should update its current calculation of the cursor position and also move the cursor.

piResult
Receives the method-supplied result of subtracting the actual new cursor position from the requested new cursor position. This value might be zero, but it is always non-negative.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemDriverUni::DrvXMoveTo and IPrintOemDriverUni::DrvYMoveTo methods allow a rendering plug-in to send image data to the printer spooler without causing the printer driver to loose track of the printer's cursor position. If you provide an IPrintOemUni::ImageProcessing method that sends image data directly to the print spooler instead of returning it to the printer driver, the method should call IPrintOemDriverUni::DrvXMoveTo and IPrintOemDriverUni::DrvYMoveTo.

Either of two techniques can be used for updating the cursor position:

  • Whenever an IPrintOemUni::ImageProcessing method needs to update the cursor position, it can call IPrintOemDriverUni::DrvXMoveTo or IPrintOemDriverUni::DrvYMoveTo with the MV_UPDATE flag cleared. This causes Unidrv to send cursor commands to the print spooler and to update its internal calculation of the current cursor position.
  • The IPrintOemUni::ImageProcessing method can update the cursor by sending cursor commands directly to the print spooler. When the method has finished its spooling operation, it can call IPrintOemDriverUni::DrvXMoveTo or IPrintOemDriverUni::DrvYMoveTo with the MV_UPDATE flag set. This causes Unidrv to update its internal calculation of the current cursor position without sending cursor commands to the print spooler.


IPrintOemDriverUni::DrvYMoveTo

The IPrintOemDriverUni::DrvYMoveTo method is provided by the Unidrv driver so that rendering plug-ins can notify the driver of cursor x-position changes.

STDMETHOD
  (DrvYMoveTo) (
    THIS_
    PDEVOBJ  pdevobj,
    INT  y,
    DWORD  dwFlags,
    OUT INT  *piResult
    ) PURE;

Parameters

pdevobj
Caller-supplied pointer to a DEVOBJ structure.
y
Caller-supplied value representing the number of units the cursor should be moved. The unit is defined by the MV_GRAPHICS flags in dwFlags.
dwFlags
One or more of the following caller-supplied bit flags:
Flag Definition
MV_GRAPHICS If set, the y parameter's value is expressed in dots, based on the printer's current resolution. For example, if the y resolution is 150 DPI and y is 75, the movement is ½ inch.

If not set, the y parameter's value is expressed in master units. For example, if the y master unit is 600 and y is 300, the movement is ½ inch.
MV_PHYSICAL If set, the y parameter's value is relative to the cursor origin.

If not set, the y parameter's value is relative to the printable area's origin.

Cannot be set if MV_RELATIVE is set.
MV_RELATIVE If set, specifies that the cursor should be moved y units from its current position.

If not set, specifies that the cursor should be moved y units from its origin.
MV_UPDATE If set, specifies that Unidrv should update its current calculation of the cursor position without actually moving the cursor. (Should be set if IprintOemUni::ImageProcessing has moved the cursor.)

If not set, specifies that Unidrv should update its current calculation of the cursor position and also move the cursor.

piResult
Receives the method-supplied result of subtracting the actual new cursor position from the requested new cursor position. This value might be zero, but it is always non-negative.

Return Value

The method must return one of the following values:

Return Value | Definition
S_OK | The operation succeeded.
E_FAIL | The operation failed.
E_NOTIMPL | The method is not implemented.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

The IPrintOemDriverUni::DrvXMoveTo and IPrintOemDriverUni::DrvYMoveTo methods allow a rendering plug-in to send image data to the printer spooler without causing the printer driver to loose track of the printer's cursor position. If you provide an IPrintOemUni::ImageProcessing method that sends image data directly to the print spooler instead of returning it to the printer driver, the method should call IPrintOemDriverUni::DrvXMoveTo and IPrintOemDriverUni::DrvYMoveTo.

Either of two techniques can be used for updating the cursor position:

  • Whenever an IPrintOemUni::ImageProcessing method needs to update the cursor position, it can call IPrintOemDriverUni::DrvXMoveTo or IPrintOemDriverUni::DrvYMoveTo with the MV_UPDATE flag cleared. This causes Unidrv to send cursor commands to the print spooler and to update its internal calculation of the current cursor position.
  • The IPrintOemUni::ImageProcessing method can update the cursor by sending cursor commands directly to the print spooler. When the method has finished its spooling operation, it can call IPrintOemDriverUni::DrvXMoveTo or IPrintOemDriverUni::DrvYMoveTo with the MV_UPDATE flag set. This causes Unidrv to update its internal calculation of the current cursor position without sending cursor commands to the print spooler.


IPrintCorePS2 Interface

This section describes the methods defined for the IPrintCorePS2 COM interface. Method prototypes are defined in prcomoem.h.


IPrintCorePS2::DrvWriteSpoolBuf

The IPrintCorePS2::DrvWriteSpoolBuf method is provided by the Pscript5 driver so that rendering plug-ins can send printer data to the spooler.

STDMETHOD
  (DrvWriteSpoolBuf) (
    THIS_
    IN PDEVOBJ  pdevobj,
    IN PVOID  pBuffer,
    IN DWORD  cbSize,
    OUT DWORD  *pdwResult
    );

This method has the same behavior as IPrintOemDriverPS::DrvWriteSpoolBuf. This method is supported for any Pscript5 render plug-ins.

Headers

Declared in prcomoem.h. Include prcomoem.h.

See Also

IPrintOemDriverPS::DrvWriteSpoolBuf


IPrintCorePS2::EnumFeatures

The IPrintCorePS2::EnumFeatures method enumerates a printer's available features.

STDMETHOD
  (EnumFeatures) (
    THIS_
    IN PDEVOBJ  pdevobj,
    IN DWORD  dwFlags,
    OUT PSTR  pmszFeatureList,
    IN DWORD  cbSize,
    OUT PDWORD  pcbNeeded
    ) PURE;

Parameters

pdevobj
Points to a DEVOBJ structure.
dwFlags
Is reserved and must be set to zero.
pmszFeatureList
Points to a caller-supplied buffer that will receive a NULL-delimited list of feature keywords in MULTI_SZ format. The list is terminated with two NULL characters.

Set this parameter to NULL to simply query for the size (*pcbNeeded) of the feature list without having the list filled in.

cbSize
Specifies the size, in bytes, of the buffer pointed to by pmszFeatureList.
pcbNeeded
Points to a memory location that will receive the actual size, in bytes, of the requested data.

Return Value

This method must return one of the values shown in the following table:

Return Value | Meaning
S_OK | The method succeeded.
E_OUTOFMEMORY | The value in cbSize was smaller than the number of bytes to be written to the output buffer (the buffer pointed to by pmszFeatureList). The method was called with pmszFeatureList set to NULL.
E_INVALIDARG | The pdevobj parameter pointed to an invalid driver context object.
E_FAIL | The method failed.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

Printer-sticky features (see Replacing Driver-Supplied Property Sheet Pages), such as those that determine installable memory and the presence of optional accessories, are included in the feature keyword list, which appears in the output buffer pointed to by pmszFeatureList. For Pscript5, such features will have the OpenGroupType feature attribute set to "InstallableOptions".

To reduce the need to make two calls per data access, pass the method an output buffer of a fixed size (1 KB, for example), and then check the function return value. If the method returns S_OK, the buffer will already contain the data of interest. If the method returns E_OUTOFMEMORY, the value in *pcbNeeded will be the buffer size needed to hold the data of interest. The caller should then allocate a buffer of that larger size and proceed with a second call to the method.

This method is supported for any Pscript5 render plug-in.

For more information, see Using EnumFeatures.

See Also

DEVOBJ, IPrintCorePS2::EnumOptions


IPrintCorePS2::EnumOptions

The IPrintCorePS2::EnumOptions method enumerates the available options of a specific feature.

STDMETHOD
  (EnumOptions) (
    THIS_
    IN PDEVOBJ  pdevobj,
    IN DWORD  dwFlags,
    IN PCSTR  pszFeatureKeyword,
    OUT PSTR  pmszOptionList,
    IN DWORD  cbSize,
    OUT PDWORD  pcbNeeded
    ) PURE;

Parameters

pdevobj
Points to a DEVOBJ structure.
dwFlags
Is reserved and must be set to zero.
pszFeatureKeyword
Points to a caller-supplied buffer containing an ASCII string, specifying a feature keyword whose options are requested.
pmszOptionList
Points to a caller-supplied buffer that will receive a NULL-delimited list, in MULTI_SZ format, containing the option keywords for the feature keyword pointed to by pszFeatureKeyword. This list is terminated with two NULL characters.

Set this parameter to NULL to simply query for the size (*pcbNeeded) of the option list without having the list filled in.

cbSize
Specifies the size, in bytes, of the buffer pointed to by pmszOptionList.
pcbNeeded
Points to a memory location that will receive the actual size, in bytes, of the requested data.

Return Value

This method must return one of the values shown in the following table:

Return Value | Meaning
S_OK | The method succeeded.
E_OUTOFMEMORY | The value in cbSize was smaller than the number of bytes to be written to the output buffer (the buffer pointed to by pmszOptionList). The method was called with pmszOptionList set to NULL.
E_INVALIDARG | The string pointed to by pszFeatureKeyword is not a recognized feature. The pdevobj parameter pointed to an invalid driver context object.
E_NOTIMPL | (Pscript only) The Pscript5 driver feature is not supported under the current configuration. The Pscript5 driver feature is supported under the current configuration, but the Pscript5 driver feature's options are not enumerable.
E_FAIL | The method failed.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

To reduce the need to make two calls per data access, pass the method an output buffer of a fixed size (1 KB, for example), and then check the function return value. If the method returns S_OK, the buffer will already contain the data of interest. If the method returns E_OUTOFMEMORY, the value in *pcbNeeded will be the buffer size needed to hold the data of interest. The caller should then allocate a buffer of that larger size and proceed with a second call to the method.

This method is supported for any Pscript5 render plug-in.

For more information, see Using EnumOptions.

See Also

DEVOBJ, IPrintCorePS2::EnumFeatures


IPrintCorePS2::GetFeatureAttribute

The IPrintCorePS2::GetFeatureAttribute method retrieves the feature attribute list or the value of a specific feature attribute.

STDMETHOD
  (GetFeatureAttribute) (
    THIS_
    IN PDEVOBJ  pdevobj,
    IN DWORD  dwFlags,
    IN PCSTR  pszFeatureKeyword,
    IN PCSTR  pszAttribute,
    OUT PDWORD  pdwDataType,
    OUT PBYTE  pbData,
    IN DWORD  cbSize,
    OUT PDWORD  pcbNeeded
    ) PURE;

Parameters

pdevobj
Points to a DEVOBJ structure.
dwFlags
Is reserved and must be set to zero.
pszFeatureKeyword
Points to a caller-supplied buffer containing an ASCII string specifying the single feature keyword to query for. This value can be obtained from a prior call to IPrintCorePS2::EnumFeatures.
pszAttribute
Points to a caller-supplied buffer containing an ASCII string specifying the single attribute requested. If this parameter is NULL, the caller is requesting a list of all supported feature attribute names, as opposed to specifying a specific feature attribute name.
pdwDataType
Points to a memory location that will receive a value specifying the data type of the requested attribute. This value is an enumerator of the EATTRIBUTE_DATATYPE enumeration, which is defined in printoem.h.
pbData
Points to a caller-supplied buffer that will receive the requested data. To simply query for the number of bytes needed to fulfill a request, set this parameter to NULL.
cbSize
Specifies the size, in bytes of the buffer pointed to by pbData.
pcbNeeded
Points to a memory location that will receive the actual size, in bytes, of the requested data.

Return Value

This method must return one of the values shown in the following table:

Return Value | Meaning
S_OK | The method succeeded.
E_OUTOFMEMORY | The value in cbSize was smaller than the number of bytes to be written to the output buffer (the buffer pointed to by pbData). The method was called with pbData set to NULL.
E_INVALIDARG | The method attempted to query for a nonexistent attribute. The feature keyword was not recognized. The pdevobj parameter pointed to an invalid driver context object.
E_FAIL | The method failed.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

If this method is called with its pszAttribute and pbData parameters set to NULL, the method will return with *pcbNeeded set to the number of bytes needed for the list of all supported attribute names for the feature. If the method is called a second time, with pszAttribute set to NULL and pbData pointing to a buffer of the size specified in *pcbNeeded in the previous call, the method will return with *pdwDataType set to kADT_ASCII (an enumerator of the EATTRIBUTE_DATATYPE enumerated type) and pbData pointing to a NULL-delimited list of all supported attribute names for the feature. This list will be terminated with two NULL characters.

To reduce the need to make two calls per data access, pass the method an output buffer of a fixed size (1 KB, for example), and then check the function return value. If the method returns S_OK, the buffer will already contain the data of interest. If the method returns E_OUTOFMEMORY, the value in *pcbNeeded will be the buffer size needed to hold the data of interest. The caller should then allocate a buffer of that larger size and proceed with a second call to the method.

This method is supported for any Pscript5 render plug-in.

For more information, see Using GetFeatureAttribute.

See Also

DEVOBJ, IPrintCorePS2::EnumFeatures, IPrintCorePS2::GetGlobalAttribute, IPrintCorePS2::GetOptionAttribute


IPrintCorePS2::GetOptionAttribute

The IPrintCorePS2::GetOptionAttribute method retrieves the option attribute list or the value of a specific option attribute.

STDMETHOD
  (GetOptionAttribute) (
    THIS_
    IN PDEVOBJ  pdevobj,
    IN DWORD  dwFlags,
    IN PCSTR  pszFeatureKeyword,
    IN PCSTR  pszOptionKeyword,
    IN PCSTR  pszAttribute,
    OUT PDWORD  pdwDataType,
    OUT PBYTE  pbData,
    IN DWORD  cbSize,
    OUT PDWORD  pcbNeeded
    ) PURE;

Parameters

pdevobj
Points to a DEVOBJ structure.
dwFlags
Is reserved and must be set to zero.
pszFeatureKeyword
Points to a caller-supplied buffer containing an ASCII string specifying the single feature keyword to query for.
pszOptionKeyword
Points to a caller-supplied buffer containing an ASCII string specifying the single option keyword to query for. This value can be obtained from a prior call to IPrintCorePS2::EnumOptions.
pszAttribute
Points to a caller-supplied buffer containing an ASCII string specifying the single attribute requested. If this parameter is NULL, the caller is requesting a list of all supported attribute names for the option, as opposed to specifying a specific attribute name for the option.
pdwDataType
Points to a memory location that will receive a value specifying the data type of the requested attribute. This value is an enumerator of the EATTRIBUTE_DATATYPE enumeration, which is defined in printoem.h.
pbData
Points to a caller-supplied buffer that will receive the requested data. To simply query for the number of bytes needed to fulfill a request, set this parameter to NULL.
cbSize
Specifies the size, in bytes of the buffer pointed to by pbData.
pcbNeeded
Points to a memory location that will receive the actual size, in bytes, of the requested data.

Return Value

This method must return one of the values shown in the following table:

Return Value | Meaning
S_OK | The method succeeded.
E_OUTOFMEMORY | The value in cbSize was smaller than the number of bytes to be written to the output buffer (the buffer pointed to by pbData). The method was called with pbData set to NULL.
E_INVALIDARG | The method attempted to query for a nonexistent attribute. The feature keyword name or option keyword name were not recognized. The pdevobj parameter pointed to an invalid driver context object.
E_FAIL | The method failed.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

If this method is called with its pszAttribute and pbData parameters set to NULL, the method will return with *pcbNeeded set to the number of bytes needed for the list of all supported attribute names for the option. If the method is called a second time, with pszAttribute set to NULL and pbData pointing to a buffer of the size specified in *pcbNeeded in the previous call, the method will return with *pdwDataType set to kADT_ASCII (an enumerator of the EATTRIBUTE_DATATYPE enumerated type) and pbData pointing to a NULL-delimited list of all the supported attribute names for the option. This list will be terminated with two NULL characters.

To reduce the need to make two calls per data access, pass the method an output buffer of a fixed size (1 KB, for example), and then check the function return value. If the method returns S_OK, the buffer will already contain the data of interest. If the method returns E_OUTOFMEMORY, the value in *pcbNeeded will be the buffer size needed to hold the data of interest. The caller should then allocate a buffer of that larger size and proceed with a second call to the method.

This method is supported for any Pscript5 render plug-in.

For more information, see Using GetOptionAttribute.

See Also

DEVOBJ, IPrintCorePS2::EnumOptions, IPrintCorePS2::GetFeatureAttribute, IPrintCorePS2::GetGlobalAttribute


IPrintCorePS2::GetOptions

The IPrintCorePS2::GetOptions method retrieves the driver's current feature settings in the format of a list of feature/option keyword pairs.

STDMETHOD
  (GetOptions) (
    THIS_
    IN PDEVOBJ  pdevobj,
    IN DWORD  dwFlags,
    IN PCSTR  pmszFeaturesRequested,
    IN DWORD  cbIn,
    OUT PSTR  pmszFeatureOptionBuf,
    IN DWORD  cbSize,
    OUT PDWORD  pcbNeeded
    ) PURE;

Parameters

pdevobj
Points to a DEVOBJ structure.
dwFlags
Is reserved and must be set to zero.
pmszFeaturesRequested
Points to caller-supplied buffer containing a list of feature keywords (in MULTI_SZ format) whose settings are requested. Set this parameter to NULL to obtain settings for all features.
cbIn
Specifies the size, in bytes, of the buffer pointed to by pmszFeaturesRequested. The size includes the last MULTI_SZ NULL character.
pmszFeatureOptionBuf
Points to a caller-supplied buffer that will receive a list of feature/option keyword pairs (in MULTI_SZ format) obtained from the driver settings. Each feature/option keyword pair contains the feature keyword name, a NULL character, the option keyword name, and another NULL character. The list is terminated by two NULL characters.
cbSize
Specifies the size, in bytes, of the buffer pointed to by pmszFeatureOptionBuf.
pcbNeeded
Points to a memory location that will receive the actual size, in bytes, of the requested data.

Return Value

The method must return one of the values shown in the following table:

Return Value | Definition
S_OK | The method succeeded.
E_OUTOFMEMORY | The value in cbSize was smaller than the number of bytes to be written to the output buffer (the buffer pointed to by pmszFeatureOptionBuf). The method was called with pmszFeatureOptionBuf set to NULL.
E_INVALIDARG | The input buffer (the buffer pointed to by pmszFeaturesRequested) was provided, but its contents were not in MULTI_SZ format. The pdevobj parameter pointed to an invalid driver context object.
E_NOTIMPL | The method is not supported.
E_FAIL | The method failed.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

This method supports both document-sticky and printer-sticky features. It is supported only after the core driver finishes its DrvEnablePDEV processing, which sets up all option settings. A call to IPrintCorePS2::GetOptions when it is not supported should cause it to return E_NOTIMPL. For example, when the core driver calls a render plug-in's IPrintOemPS::DevMode method, the driver is still occupied with its DrvEnablePDEV processing, so if the plug-in calls IPrintCorePS2::GetOptions within the plug-in's IPrintOemPS::DevMode method, the plug-in will receive the E_NOTIMPL return value. However, since the plug-in's IPrintOemPS::EnablePDEV method is called after the core driver finishes its DrvEnablePDEV processing, the plug-in is able to call IPrintCorePS2::GetOptions successfully within its IPrintOemPS::EnablePDEV method.

If a requested feature keyword is not recognized, or the feature is recognized but there is currently no option selection for it, the feature will simply be ignored and the feature/option keyword pair will not be placed in the output buffer.

To reduce the need to make two calls per data access, pass the method an output buffer of a fixed size (1 KB, for example), and then check the function return value. If the method returns S_OK, the buffer will already contain the data of interest. If the method returns E_OUTOFMEMORY, the value in *pcbNeeded will be the buffer size needed to hold the data of interest. The caller should then allocate a buffer of that larger size and proceed with a second call to the method.

This method is supported for any Pscript5 render plug-in.

For more information, see Using GetOptions and SetOptions.

See Also

DEVOBJ, DrvEnablePDEV, IPrintOemPS::DevMode, IPrintOemPS::EnablePDEV


Non-COM-Based DDI Hook-out Functions

Printer IHVs can implement some or all of the non-COM-based DDI hook-out functions listed in this section to provide custom rendering functionality.

Each OEMXxx render module function listed in this section has the same parameters as its DrvXxx counterpart, and both functions have the same return values. For these reasons, each reference page in this section directs the reader to the relevent DrvXxx reference page for detailed information.


OEMAlphaBlend

The OEMAlphaBlend function provides bit-block transfer capabilities with alpha blending.

BOOL APIENTRY
  OEMAlphaBlend(
    SURFOBJ  *psoDest,
    SURFOBJ  *psoSrc,
    CLIPOBJ  *pco,
    XLATEOBJ  *pxlo,
    RECTL  *prclDest,
    RECTL  *prclSrc,
    BLENDOBJ  *pBlendObj
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvAlphaBlend.

This function is not supported on Windows NT 4.0 and earlier.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvAlphaBlend function pointer.


OEMBitBlt

The OEMBitBlt function provides general bit-block transfer capabilities between device-managed surfaces, between GDI-managed standard-format bitmaps, or between a device-managed surface and a GDI-managed standard-format bitmap.

BOOL APIENTRY
  OEMBitBlt(
    SURFOBJ  *psoTrg,
    SURFOBJ  *psoSrc,
    SURFOBJ  *psoMask,
    CLIPOBJ  *pco,
    XLATEOBJ  *pxlo,
    RECTL  *prclTrg,
    POINTL  *pptlSrc,
    POINTL  *pptlMask,
    BRUSHOBJ  *pbo,
    POINTL  *pptlBrush,
    ROP4  rop4
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvBitBlt.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvBitBlt function pointer.


OEMCopyBits

The OEMCopyBits function performs translations between device-managed raster surfaces and GDI standard-format bitmaps.

BOOL APIENTRY
  OEMCopyBits(
    SURFOBJ  *psoDest,
    SURFOBJ  *psoSrc,
    CLIPOBJ  *pco,
    XLATEOBJ  *pxlo,
    RECTL  *prclDest,
    POINTL  *pptlSrc
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvCopyBits.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvCopyBits function pointer.


OEMDitherColor

The OEMDitherColor function requests the device to create a brush dithered against a device palette.

ULONG APIENTRY
  OEMDitherColor(
    DHPDEV  dhpdev,
    ULONG  iMode,
    ULONG  rgbColor,
    ULONG  *pulDither
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvDitherColor.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvDitherColor function pointer.


OEMEndDoc

The OEMEndDoc function is called by the GDI when it has finished sending a document to the driver for rendering.

BOOL APIENTRY
  OEMEndDoc(
    SURFOBJ  *pso,
    FLONG  fl
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvEndDoc.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvEndDoc function pointer.


OEMEscape

The OEMEscape function retrieves information from a device that is not available in a device-independent device driver interface; the particular query depends on the value of the iEsc parameter.

ULONG APIENTRY
  OEMEscape(
    SURFOBJ  *pso,
    ULONG  iEsc,
    ULONG  cjIn,
    PVOID  pvIn,
    ULONG  cjOut,
    PVOID  pvOut
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvEscape.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvEscape function pointer.


OEMFillPath

The OEMFillPath function handles the filling of closed paths.

BOOL APIENTRY
  OEMFillPath(
    SURFOBJ  *pso,
    PATHOBJ  *ppo,
    CLIPOBJ  *pco,
    BRUSHOBJ  *pbo,
    POINTL  *pptlBrushOrg,
    MIX  mix,
    FLONG  flOptions
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvFillPath.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvFillPath function pointer.


OEMFontManagement

The OEMFontManagement function is an optional entry point provided for PostScript devices.

ULONG APIENTRY
  OEMFontManagement(
    SURFOBJ  *pso,
    FONTOBJ  *pfo,
    ULONG  iMode,
    ULONG  cjIn,
    PVOID  pvIn,
    ULONG  cjOut,
    PVOID  pvOut
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvFontManagement.

If this function is hooked by the device driver, then GDI will pass calls an application makes to ExtEscape for escape numbers 0x100 through 0x3FE, or for the QUERYESCSUPPORT escape when the first DWORD pointed to by pvIn is in the range 0x100 through 0x3FE.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvFontManagement function pointer.


OEMGetGlyphMode

The OEMGetGlyphMode function informs the GDI how to cache glyph information.

ULONG APIENTRY
  OEMGetGlyphMode(
    DHPDEV  dhpdev,
    FONTOBJ  *pfo
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvGetGlyphMode.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvGetGlyphMode function pointer.


OEMGradientFill

The OEMGradientFill function shades the specified primitives.

BOOL APIENTRY
  OEMGradientFill(
    SURFOBJ  *psoDest,
    CLIPOBJ  *pco,
    XLATEOBJ  *pxlo,
    TRIVERTEX  *pVertex,
    ULONG  nVertex,
    PVOID  pMesh,
    ULONG  nMesh,
    RECTL  *prclExtents,
    POINTL  *pptlDitherOrg,
    ULONG  ulMode
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvGradientFill.

This function is not supported on Windows NT 4.0 and earlier.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvGradientFill function pointer.


OEMIcmCreateColorTransform

The OEMIcmCreateColorTransform function creates an ICM color transform.

HANDLE APIENTRY
  OEMIcmCreateColorTransform(
    DHPDEV  dhpdev,
    LPLOGCOLORSPACEW  pLogColorSpace,
    PVOID  pvSourceProfile,
    ULONG  cjSourceProfile,
    PVOID  pvDestProfile,
    ULONG  cjDestProfile,
    PVOID  pvTargetProfile,
    ULONG  cjTargetProfile,
    DWORD  dwReserved
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvIcmCreateColorTransform.

This function is not supported on Windows NT 4.0 and earlier.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvIcmCreateColorTransform function pointer.


OEMIcmDeleteColorTransform

The OEMIcmDeleteColorTransform function deletes the specified color transform.

BOOL APIENTRY
  OEMIcmDeleteColorTransform(
    DHPDEV  dhpdev,
    HANDLE  hcmXform
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvIcmDeleteColorTransform.

This function is not supported on Windows NT 4.0 and earlier.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvIcmDeleteColorTransform function pointer.


OEMLineTo

The OEMLineTo function draws a single, solid, integer-only cosmetic line.

BOOL APIENTRY
  OEMLineTo(
    SURFOBJ  *pso,
    CLIPOBJ  *pco,
    BRUSHOBJ  *pbo,
    LONG  x1,
    LONG  y1,
    LONG  x2,
    LONG  y2,
    RECTL  *prclBounds,
    MIX  mix
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvLineTo.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvLineTo function pointer.


OEMNextBand

The OEMNextBand function is called by GDI when it has finished drawing a band for a physical page, so that the driver can send the band to the printer.

BOOL APIENTRY
  OEMNextBand(
    SURFOBJ  *pso,
    POINTL  *pptl
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvNextBand.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvNextBand function pointer.


OEMPaint

The OEMPaint function is obsolete, and is no longer called by GDI in Windows 2000 and later. See DrvPaint.

BOOL APIENTRY
  OEMPaint(
    SURFOBJ  *pso,
    CLIPOBJ  *pco,
    BRUSHOBJ  *pbo,
    POINTL  *pptlBrushOrg,
    MIX  mix
    );

Headers

Declared in printoem.h. Include printoem.h.

If you call into the core driver, cast the call using the PFN_DrvPaint function pointer.


OEMPlgBlt

The OEMPlgBlt function provides rotate bit-block transfer capabilities between combinations of device-managed and GDI-managed surfaces.

BOOL APIENTRY
  OEMPlgBlt(
    SURFOBJ  *psoDst,
    SURFOBJ  *psoSrc,
    SURFOBJ  *psoMask,
    CLIPOBJ  *pco,
    XLATEOBJ  *pxlo,
    COLORADJUSTMENT  *pca,
    POINTL  *pptlBrushOrg,
    POINTFIX  *pptfixDest,
    RECTL  *prclSrc,
    POINTL  *pptlMask,
    ULONG  iMode
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvPlgBlt.

This function is not supported on Windows NT 4.0 and earlier.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvPlgBlt function pointer.


OEMQueryAdvanceWidths

The OEMQueryAdvanceWidths function returns character advance widths for a specified set of glyphs.

BOOL APIENTRY
  OEMQueryAdvanceWidths(
    DHPDEV  dhpdev,
    FONTOBJ  *pfo,
    ULONG  iMode,
    HGLYPH  *phg,
    PVOID  pvWidths,
    ULONG  cGlyphs
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvQueryAdvanceWidths.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvQueryAdvanceWidths function pointer.


OEMQueryDeviceSupport

The OEMQueryDeviceSupport function returns requested device-specific information.

BOOL APIENTRY
  OEMQueryDeviceSupport(
    SURFOBJ  *pso,
    XLATEOBJ  *pxlo,
    XFORMOBJ  *pxo,
    ULONG  iType,
    ULONG  cjIn,
    PVOID  pvIn,
    ULONG  cjOut,
    PVOID  pvOut
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvQueryDeviceSupport.

This function is not supported on Windows NT 4.0 and earlier.

Do not directly hook out this function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvQueryDeviceSupport function pointer.


OEMQueryFont

The OEMQueryFont function is used by GDI to get the IFIMETRICS structure for a given font.

PIFIMETRICS APIENTRY
  OEMQueryFont(
    DHPDEV  dhpdev,
    ULONG_PTR  iFile,
    ULONG  iFace,
    ULONG_PTR  *pid
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvQueryFont.

Do not directly hook out this function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvQueryFont function pointer.


OEMQueryFontData

The OEMQueryFontData function retrieves information about a realized font.

LONG APIENTRY
  OEMQueryFontData(
    DHPDEV  dhpdev,
    FONTOBJ  *pfo,
    ULONG  iMode,
    HGLYPH  hg,
    GLYPHDATA  *pgd,
    PVOID  pv,
    ULONG  cjSize
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvQueryFontData.

Do not directly hook out this function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvQueryFontData function pointer.


OEMQueryFontTree

The OEMQueryFontTree function provides GDI with a pointer to a structure that defines one of the following:

  • A mapping from Unicode to glyph handles, including glyph variants
  • A mapping of kerning pairs to kerning handles
PVOID APIENTRY
  OEMQueryFontTree(
    DHPDEV  dhpdev,
    ULONG_PTR  iFile,
    ULONG  iFace,
    ULONG  iMode,
    ULONG_PTR  *pid
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvQueryFontTree.

Do not directly hook out this function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvQueryFontTree function pointer.


OEMRealizeBrush

The OEMRealizeBrush function requests that the driver realize a specified brush for a specified surface.

BOOL APIENTRY
  OEMRealizeBrush(
    BRUSHOBJ  *pbo,
    SURFOBJ  *psoTarget,
    SURFOBJ  *psoPattern,
    SURFOBJ  *psoMask,
    XLATEOBJ  *pxlo,
    ULONG  iHatch
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvRealizeBrush.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvRealizeBrush function pointer.


OEMSendPage

The OEMSendPage function is called by GDI when it has finished drawing a physical page, so that the driver can send the page to the printer.

BOOL APIENTRY
  OEMSendPage(
    SURFOBJ  *pso
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvSendPage.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvSendPage function pointer.


OEMStartBanding

The OEMStartBanding function is called by GDI when it is ready to start sending bands of a physical page to the driver for rendering.

BOOL APIENTRY
  OEMStartBanding(
    SURFOBJ  *pso,
    POINTL  *pptl
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvStartBanding.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvStartBanding function pointer.


OEMStartDoc

The OEMStartDoc function is called by GDI when it is ready to start sending a document to the driver for rendering.

BOOL APIENTRY
  OEMStartDoc(
    SURFOBJ  *pso,
    PWSTR  pwszDocName,
    DWORD  dwJobId
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvStartDoc.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvStartDoc function pointer.


OEMStartPage

The OEMStartPage function is called by GDI when it is ready to start sending the contents of a physical page to the driver for rendering.

BOOL APIENTRY
  OEMStartPage(
    SURFOBJ  *pso
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvStartPage.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvStartPage function pointer.


OEMStretchBlt

The OEMStretchBlt function provides stretching bit-block transfer capabilities between any combination of device-managed and GDI-managed surfaces.

BOOL APIENTRY
  OEMStretchBlt(
    SURFOBJ  *psoDest,
    SURFOBJ  *psoSrc,
    SURFOBJ  *psoMask,
    CLIPOBJ  *pco,
    XLATEOBJ  *pxlo,
    COLORADJUSTMENT  *pca,
    POINTL  *pptlHTOrg,
    RECTL  *prclDest,
    RECTL  *prclSrc,
    POINTL  *pptlMask,
    ULONG  iMode
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvStretchBlt.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvStretchBlt function pointer.


OEMStretchBltROP

The OEMStretchBltROP function performs a stretching bit-block transfer using a ROP.

BOOL APIENTRY
  OEMStretchBltROP(
    SURFOBJ  *psoDest,
    SURFOBJ  *psoSrc,
    SURFOBJ  *psoMask,
    CLIPOBJ  *pco,
    XLATEOBJ  *pxlo,
    COLORADJUSTMENT  *pca,
    POINTL  *pptlHTOrg,
    RECTL  *prclDest,
    RECTL  *prclSrc,
    POINTL  *pptlMask,
    ULONG  iMode,
    BRUSHOBJ *pbo,
    ROP4  rop4
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvStretchBltROP.

This function is not supported on Windows NT 4.0 and earlier.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvStretchBltROP function pointer.


OEMStrokeAndFillPath

The OEMStrokeAndFillPath function concurrently strokes and fills a path.

BOOL APIENTRY
  OEMStrokeAndFillPath(
    SURFOBJ  *pso,
    PATHOBJ  *ppo,
    CLIPOBJ  *pco,
    XFORMOBJ  *pxo,
    BRUSHOBJ  *pboStroke,
    LINEATTRS  *plineattrs,
    BRUSHOBJ  *pboFill,
    POINTL  *pptlBrushOrg,
    MIX  mixFill,
    FLONG  flOptions
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvStrokeAndFillPath.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvStrokeAndFillPath function pointer.


OEMStrokePath

The OEMStrokePath function strokes a path.

BOOL APIENTRY
  OEMStrokePath(
    SURFOBJ  *pso,
    PATHOBJ  *ppo,
    CLIPOBJ  *pco,
    XFORMOBJ  *pxo,
    BRUSHOBJ  *pbo,
    POINTL  *pptlBrushOrg,
    LINEATTRS  *plineattrs,
    MIX  mix
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvStrokePath.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvStrokePath function pointer.


OEMTextOut

The OEMTextOut function calls for the driver to render a set of glyphs at specified positions.

BOOL APIENTRY
  OEMTextOut(
    SURFOBJ  *pso,
    STROBJ  *pstro,
    FONTOBJ  *pfo,
    CLIPOBJ  *pco,
    RECTL  *prclExtra,
    RECTL  *prclOpaque,
    BRUSHOBJ  *pboFore,
    BRUSHOBJ  *pboOpaque,
    POINTL  *pptlOrg,
    MIX  mix
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvTextOut.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvTextOut function pointer.


OEMTransparentBlt

The OEMTransparentBlt function provides bit-block transfer capabilities with transparency.

BOOL APIENTRY
  OEMTransparentBlt(
    SURFOBJ  *psoDst,
    SURFOBJ  *psoSrc,
    CLIPOBJ  *pco,
    XLATEOBJ  *pxlo,
    RECTL  *prclDst,
    RECTL  *prclSrc,
    ULONG  iTransColor,
    ULONG  ulReserved
    );

Headers

Declared in printoem.h. Include printoem.h.

Comments

See DrvTransparentBlt.

This function is not supported on Windows NT 4.0 and earlier.

Do not directly hook out this drawing function. Instead, implement OEMEnableDriver so that it fills in a DRVENABLEDATA structure listing all of the drawing DDIs to be hooked out.

If you call into the core driver, cast the call using the PFN_DrvTransparentBlt function pointer.


Structures for Rendering Plug-Ins

This section describes the structures used by rendering plug-ins. Structure definitions are contained in printoem.h.


DEVOBJ

The DEVOBJ structure is used as an input argument to several of a rendering plug-in's COM interface methods.

typedef struct _DEVOBJ {
  DWORD  dwSize;
  PDEVOEM  pdevOEM;
  HANDLE  hEngine;
  HANDLE  hPrinter;
  HANDLE  hOEM;
  PDEVMODE  pPublicDM;
  PVOID  pOEMDM;
  PDRVPROCS  pDrvProcs;
} DEVOBJ;

Members

dwSize
Size, in bytes, of the DEVOBJ structure. Supplied by the Unidrv or Pscript5 driver.
pdevOEM
Pointer to the rendering plug-in's private PDEV structure, as returned by IPrintOemUni::EnablePDEV or IPrintOemPS::EnablePDEV. Supplied by the Unidrv or Pscript5 driver.
hEngine
GDI handle to the physical device. This handle is received by the printer driver's DrvCompletePDEV function, as the function's hdev argument.
hPrinter
Spooler's handle to the printer. This handle is received by the printer driver's DrvEnablePDEV function, as the function's hDriver argument.
hOEM
Plug-in instance handle. Supplied by the Unidrv or Pscript5 driver.
pPublicDM
Pointer to the printer's DEVMODE structure. Supplied by the Unidrv or Pscript5 driver.
pOEMDM
Pointer to the rendering plug-in's private DEVMODE structure members. Supplied by the Unidrv or Pscript5 driver.
pDrvProcs
Not used. In a previous version of the interface, this was a pointer to a DRVPROCS structure.

Headers

Declared in printoem.h. Include printoem.h.

Comments

The DEVOBJ structure is accessible to graphics DDI hooking functions through the SURFOBJ structure's dhpdev member. For more information, see IPrintOemUni::EnablePDEV or IPrintOemPS::EnablePDEV.


DRVPROCS

The DRVPROCS structure is obsolete and is not used with the COM interfaces for Microsoft printer drivers.

The structure contains the addresses of helper functions that are provided to rendering plug-ins by Microsoft printer drivers.

typedef struct _DRVPROCS {
  PFN_DrvWriteSpoolBuf  DrvWriteSpoolBuf;
  PFN_DrvXMoveTo  DrvXMoveTo;
  PFN_DrvYMoveTo  DrvYMoveTo;
  PFN_DrvGetDriverSetting  DrvGetDriverSetting;
  PFN_DrvGetStandardVariable  BGetStandardVariable;
  PFN_DrvUnidriverTextOut  DrvUnidriverTextOut;
  PFN_DrvWriteAbortBuf  DrvWriteAbortBuf;
} DRVPROCS, *PDRVPROCS;

All of the function pointed to by members of this structure are obsolete. For information on each see:

DrvWriteSpoolBuf

DrvXMoveTo

DrvYMoveTo

DrvGetDriverSetting

BGetStandardVariable (see DrvGetStandardVariable)

DrvUnidriverTextOut

DrvWriteAbortBuf


FINVOCATION

The FINVOCATION structure is used as input to the IPrintOemUni::SendFontCmd method. The structure is defined in printoem.h.

typedef struct _FINVOCATION {
  DWORD  dwCount;
  PBYTE  pubCommand;
} FINVOCATION, *PFINVOCATION;

Members

dwCount
Unidrv-supplied length, in bytes, of the command pointed to by pubCommand.
pubCommand
Unidrv-supplied pointer to a string containing the printer's font selection command. The command is obtained from the font's .ufm (Unidrv Font Metrics) file.

Headers

Declared in printoem.h. Include printoem.h.


GETINFO_FONTOBJ

The GETINFO_FONTOBJ structure is used as input to the UNIFONTOBJ_GetInfo callback function.

typedef struct _GETINFO_FONTOBJ{
  DWORD  dwSize;
  FONTOBJ  *pFontObj;
} GETINFO_FONTOBJ;

Members

dwSize
Size, in bytes, of the GETINFO_FONTOBJ structure. Supplied by UNIFONTOBJ_GetInfo caller.
pFontObj
Pointer to an empty FONTOBJ structure. The structure is filled in by Unidrv's UNIFONTOBJ_GetInfo callback function. The pointer is supplied by the UNIFONTOBJ_GetInfo caller.

Headers

Declared in printoem.h. Include printoem.h.

Comments

To obtain a font's FONTOBJ structure contents, a rendering plug-in can supply the address of a GETINFO_FONTOBJ structure when calling Unidrv's UNIFONTOBJ_GetInfo callback function.


GETINFO_GLYPHBITMAP

The GETINFO_GLYPHBITMAP structure is used as input to the UNIFONTOBJ_GetInfo callback function.

typedef struct _GETINFO_GLYPHBITMAP{
  DWORD  dwSize;
  HGLYPH  hGlyph;
  GLYPHDATA  *pGlyphData;
} GETINFO_GLYPHBITMAP, *PGETINFO_GLYPHBITMAP;

Members

dwSize
Size, in bytes, of the GETINFO_GLYPHBITMAP structure. Supplied by UNIFONTOBJ_GetInfo caller.
hGlyph
Glyph handle. See the following Comments section. Supplied by UNIFONTOBJ_GetInfo caller.
pGlyphData
Pointer to a GLYPHDATA structure. The structure is filled in by Unidrv's UNIFONTOBJ_GetInfo callback function. The pointer is supplied by the UNIFONTOBJ_GetInfo caller.

Headers

Declared in printoem.h. Include printoem.h.

Comments

To obtain a glyph bitmap, a rendering plug-in can supply the address of a GETINFO_GLYPHBITMAP structure when calling Unidrv's UNIFONTOBJ_GetInfo callback function.

The value that a rendering plug-in specifies for the hGlyph member must have been previously received as the hGlyph parameter to the IPrintOemUni::DownloadCharGlyph method.


GETINFO_GLYPHSTRING

The GETINFO_GLYPHSTRING structure is used as input to the UNIFONTOBJ_GetInfo callback function.

typedef struct _GETINFO_GLYPHSTRING{
  DWORD  dwSize;
  DWORD  dwCount;
  DWORD  dwTypeIn;
  PVOID  pGlyphIn;
  DWORD  dwTypeOut;
  PVOID  pGlyphOut;
  DWORD  dwGlyphOutSize;
} GETINFO_GLYPHSTRING, *PGETINFO_GLYPHSTRING;

Members

dwSize
Specifies the size, in bytes, of the GETINFO_GLYPHSTRING structure. This value is supplied by the UNIFONTOBJ_GetInfo caller.
dwCount
Specifies the number of elements in the arrays pointed to by pGlyphIn and pGlyphOut. This value is supplied by the UNIFONTOBJ_GetInfo caller.
dwTypeIn
Specifies a constant value indicating the type of glyph specifier array pointed to by pGlyphIn. Valid values are as follows:
Value | Definition
TYPE_GLYPHHANDLE | The pGlyph array elements are of type HGLYPH. The HGLYPH type consist of handles to device font glyphs. For this constant, valid values for dwTypeOut are either TYPE_UNICODE or TYPE_TRANSDATA.
TYPE_GLYPHID | The pGlyph array elements are of type DWORD, and contain glyph identifiers for downloaded TrueType font glyphs. For this constant, valid values for dwTypeOut are either TYPE_UNICODE or TYPE_GLYPHHANDLE.

Supplied by the UNIFONTOBJ_GetInfo caller.

pGlyphIn
Points to an array of glyph specifiers. The array element type is indicated by dwTypeIn. This value is supplied by the UNIFONTOBJ_GetInfo caller.
dwTypeOut
Specifies a constant value indicating the type of glyph specifier array pointed to by pGlyphOut. Valid values are as follows:
Value | Definition
TYPE_GLYPHHANDLE | The pGlyph array elements are of type HGLYPH. The HGLYPH type consists of handles to device font glyphs. This value is valid only when dwTypeIn has been set to TYPE_GLYPHID.
TYPE_TRANSDATA | The pGlyph array elements are of type TRANSDATA. This value is valid only when dwTypeIn has been set to TYPE_GLYPHHANDLE.
TYPE_UNICODE | The pGlyph array elements are of type WCHAR. This value is valid when dwTypeIn has been set to either TYPE_GLYPHHANDLE or TYPE_GLYPHID.

Supplied by the UNIFONTOBJ_GetInfo caller.

pGlyphOut
Specifies a caller-supplied pointer to an empty array of glyph specifiers. The array is filled in by Unidrv's UNIFONTOBJ_GetInfo callback function. The array element type is indicated by dwTypeOut. This pointer is supplied by the UNIFONTOBJ_GetInfo caller.
dwGlyphOutSize
Specifies the size, in bytes, of the buffer pointed to by pGlyphOut. This member is used only when dwTypeIn has been set to TYPE_GLYPHHANDLE and dwTypeOut has been set to TYPE_TRANSDATA. See the following Comments section for more information.

Headers

Declared in printoem.h. Include printoem.h.

Comments

To convert an array of glyph specifiers from one type to another, a rendering plug-in can supply the address of a GETINFO_GLYPHSTRING structure when calling Unidrv's UNIFONTOBJ_GetInfo callback function.

If the conversion is from TYPE_GLYPHHANDLE to TYPE_TRANSDATA, UNIFONTOBJ_GetInfo must be called twice.

  1. Before the first call to UNIFONTOBJ_GetInfo, the rendering plug-in fills in the dwSize, dwCount, dwTypeIn, and pGlyphIn members and sets dwGlyphOutSize member to zero.

    After UNIFONTOBJ_GetInfo returns, the dwGlyphOutSize member contains the size, in bytes, of the buffer needed to store the converted string.

  2. The plug-in allocates a block of memory of the size received in the dwGlyphOutSize member, sets the pGlyphOut member to point to this memory block, and calls UNIFONTOBJ_GetInfo once more. UNIDRV then converts the string from TYPE_GLYPHHANDLE to TYPE_TRANSDATA.

The values that a rendering plug-in specifies for the dwTypeIn and pGlyphIn members typically are those that were previously received as the dwType and pGlyph parameters to the IPrintOemUni::OutputCharStr method.


GETINFO_GLYPHWIDTH

The GETINFO_GLYPHWIDTH structure is used as input to the UNIFONTOBJ_GetInfo callback function.

typedef struct _GETINFO_GLYPHWIDTH{
  DWORD  dwSize;
  DWORD  dwType;
  DWORD  dwCount;
  PVOID  pGlyph;
  PLONG  plWidth;
} GETINFO_GLYPHWIDTH, *PGETINFO_GLYPHWIDTH;

Members

dwSize
Size, in bytes, of the GETINFO_GLYPHWIDTH structure. Supplied by the UNIFONTOBJ_GetInfo caller.
dwType
Constant value indicating the type of glyph specifier array pointed to by pGlyph. Valid values are:

TYPE_GLYPHHANDLE
TYPE_GLYPHID

Supplied by the UNIFONTOBJ_GetInfo caller.

dwCount
Value indicating the number of elements in the array pointed to by pGlyph. Supplied by the UNIFONTOBJ_GetInfo caller.
pGlyph
Pointer to an array of glyph specifiers. The array element type is indicated by dwType. Supplied by the UNIFONTOBJ_GetInfo caller.
plWidth
Pointer to a location into which Unidrv's UNIFONTOBJ_GetInfo callback function places the width value. The pointer is supplied by the UNIFONTOBJ_GetInfo caller.

Headers

Declared in printoem.h. Include printoem.h.

Comments

To obtain the width of a set of glyphs, a rendering plug-in can supply the address of a GETINFO_GLYPHWIDTH structure when calling Unidrv's UNIFONTOBJ_GetInfo callback function. The callback function calculates the total width of all the glyphs described by the input array, and places the calculated value in the location pointed to by plWidth.


GETINFO_MEMORY

The GETINFO_MEMORY structure is used as input to the UNIFONTOBJ_GetInfo callback function.

typedef struct _GETINFO_MEMORY{
  DWORD  dwSize;
  DWORD  dwRemainingMemory;
} GETINFO_MEMORY, *PGETINFO_MEMORY;

Members

dwSize
Size, in bytes, of the GETINFO_MEMORY structure. Supplied by the UNIFONTOBJ_GetInfo caller.
dwRemainingMemory
Receives the amount of currently available printer memory. Supplied by Unidrv's UNIFONTOBJ_GetInfo callback function.

Headers

Declared in printoem.h. Include printoem.h.

Comments

To obtain Unidrv's calculation of the amount of printer memory currently available, a rendering plug-in can supply the address of a GETINFO_MEMORY structure when calling Unidrv's UNIFONTOBJ_GetInfo callback function.


GETINFO_STDVAR

The GETINFO_STDVAR structure is used as input to the UNIFONTOBJ_GetInfo callback function.

typedef struct _GETINFO_STDVAR{
    DWORD  dwSize;
    DWORD  dwNumOfVariables;
    struct {
      DWORD  dwStdVarID;
      LONG  lStdVariable;
    } StdVar[1];
} GETINFO_STDVAR, *PGETINFO_STDVAR;

Members

dwSize
Size, in bytes, of the GETINFO_STDVAR structure. Supplied by the UNIFONTOBJ_GetInfo caller.
dwNumOfVariables
Value indicating the number of StdVar array elements. Supplied by the UNIFONTOBJ_GetInfo caller.
dwStdVarID
Caller-supplied constant value that identifies the standard variable for which a value should be returned. Valid values are contained in the following table.
Identifier | Standard Variable
FNT_INFO_CURRENTFONTID | CurrentFontID
FNT_INFO_FONTBOLD | FontBold
FNT_INFO_FONTHEIGHT | FontHeight
FNT_INFO_FONTITALIC | FontItalic
FNT_INFO_FONTMAXWIDTH | FontMaxWidth
FNT_INFO_FONTSTRIKETHRU | FontStrikeThru
FNT_INFO_FONTUNDERLINE | FontUnderline
FNT_INFO_FONTWIDTH | FontWidth
FNT_INFO_GRAYPERCENTAGE | GrayPercentage
FNT_INFO_NEXTFONTID | NextFontID
FNT_INFO_NEXTGLYPH | NextGlyph
FNT_INFO_PRINTDIRINCCDEGREES | PrintDirInCCDegrees
FNT_INFO_TEXTXRES | TextXRes
FNT_INFO_TEXTYRES | TextYRes

Supplied by the UNIFONTOBJ_GetInfo caller.

lStdVariable
Receives the current value of the specified standard variable. Value is supplied by Unidrv's UNIFONTOBJ_GetInfo callback function.
StdVar
Is an array specifying standard variable indexes and values. Each array element contains the two previously-listed members.

Headers

Declared in printoem.h. Include printoem.h.

Comments

To obtain the current value for one or more of Unidrv's standard variables, a rendering plug-in can supply the address of a GETINFO_STDVAR structure when calling Unidrv's UNIFONTOBJ_GetInfo callback function.

For more information about standard variables, see Microsoft Universal Printer Driver.


IPPARAMS

The IPPARAMS structure is used as an input parameter to a rendering plug-in's IPrintOemUni::ImageProcessing method.

typedef struct {
  DWORD dwSize;
  POINT ptOffset;
  PSTR pHalftoneOption;
  BOOL bBanding;
  BOOL bBlankBand;
} IPPARAMS, *PIPPARAMS;

Members

dwSize
Unidrv-supplied size, in bytes of the IPPARAMS structure.
ptOffset
Unidrv-supplied pointer to a POINT structure containing the banded image's offset from the upper left corner of the drawing area. The POINT structure is described in the Platform SDK documentation.
pHalftoneOption
Unidrv-supplied pointer to a string containing the name of the currently selected halftoning option.
bBanding
Unidrv-supplied Boolean value, set to TRUE if image banding is active and FALSE otherwise.
bBlankBand
Unidrv-supplied Boolean value, set to TRUE if nothing was drawn in the source bitmap supplied to IPrintOemUni::ImageProcessing. If TRUE, data in the source bitmap is invalid and should not be processed.

Headers

Declared in printoem.h. Include printoem.h.


OEMMEMORYUSAGE

The OEMMEMORYUSAGE structure is used as an input parameter to a rendering plug-in's IPrintOemUni::MemoryUsage method.

typedef struct {
  DWORD  dwFixedMemoryUsage;
  DWORD  dwPercentMemoryUsage;
  DWORD  dwMaxBandSize;
} OEMMEMORYUSAGE, *POEMMEMORYUSAGE;

Members

dwFixedMemoryUsage
Rendering plug-in-supplied value representing the amount of fixed-sized memory required by the IPrintOemUni::MemoryUsage method.
dwPercentMemoryUsage
Rendering plug-in-supplied value representing the amount of variably-sized memory required by the IPrintOemUni::MemoryUsage method, expressed as a percentage of the size of the source bitmap received by IPrintOemUni::ImageProcessing.
dwMaxBandSize
Unidrv-supplied value specifying the maximum size that can be used for source bitmaps. This is the value that Unidrv uses to subtract from when applying the plug-in supplied values contained in dwFixedMemoryUsage and dwPercentMemoryUsage.

Headers

Declared in printoem.h. Include printoem.h.


PDEV_ADJUST_PAPER_MARGIN

The PDEV_ADJUST_PAPER_MARGIN structure specifies the imageable printing area.

typedef struct _PDEV_ADJUST_PAPER_MARGIN {
  RECTL  rcImageableArea;
} PDEV_ADJUST_PAPER_MARGIN;

Members

rcImageableArea
Is a RECTL structure that specifies the rectangular region that can be printed in. This region is specified in units of 0.001 mm.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

This structure is available in Windows XP and later.

The pBuf parameter of the IPrintOemPS2::GetPDEVAdjustment method can point to a structure of this type.

See Also

IPrintOemPS2::GetPDEVAdjustment


PDEV_HOSTFONT_ENABLED

The PDEV_HOSTFONT_ENABLED structure indicates whether the Hostfont feature is enabled.

typedef struct _PDEV_HOSTFONT_ENABLED {
  BOOL  bHostfontEnabled;
} PDEV_HOSTFONT_ENABLED;

Members

bHostfontEnabled
Specifies whether the Hostfont feature is enabled. If set to TRUE, the Hostfont feature is enabled. Otherwise, this feature is disabled.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

This structure is available in Windows XP and later.

The pBuf parameter of the IPrintOemPS2::GetPDEVAdjustment method can point to a structure of this type.

Hostfont support is designed to improve the performance of a PostScript interpreter running on a host computer system, rather than on a physical printer. When the Hostfont feature is enabled, the Pscript5 driver stops converting and downloading host font data when there is already an identical font resident on the host on which the interpreter is running. This applies only to the following fonts:

  • a TrueType Font (TTF) converted to either a PostScript Type 42 or CID2 font
  • an OpenType Font (OTF) converted to either a PostScript Type 1 or CID0 font
  • a Printer Font Binary (PFB)

See Also

IPrintOemPS2::GetPDEVAdjustment


PDEV_USE_TRUE_COLOR

The PDEV_USE_TRUE_COLOR structure indicates whether the output color space should be color or grayscale.

typedef struct _PDEV_USE_TRUE_COLOR {
  BOOL  bUseTrueColor;
} PDEV_USE_TRUE_COLOR;

Members

bUseTrueColor
Specifies whether the PostScript output should be in color mode or in monochrome/grayscale mode. If TRUE, output is in color. If FALSE, output is monochrome/grayscale.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

This structure is available in Windows XP and later.

The pBuf parameter of the IPrintOemPS2::GetPDEVAdjustment method can point to a structure of this type.

A plug-in can use this flag to turn color output on or off for Pscript5 printer output data. If the plug-in chooses to not change the current setting, it can simply return S_FALSE.

See Also

IPrintOemPS2::GetPDEVAdjustment


PUBLISHERINFO

The PUBLISHERINFO structure is used as an input parameter to the IPrintOemPS::GetInfo method.

typedef struct _PUBLISHERINFO {
  DWORD  dwMode;
  WORD  wMinoutlinePPEM;
  WORD  wMaxbitmapPPEM;
} PUBLISHERINFO, *PPUBLISHERINFO;

Members

dwMode
Bit flags. The only flag defined is OEM_MODE_PUBLISHER, which must be set if a rendering plug-in for Pscript5 will be using "publishing mode".
wMinoutlinePPEM
Value representing the minimum size required to download a Type 1 font.
wMaxbitmapPPEM
Value representing the maximum size required to download a Type 3 font.

Headers

Declared in printoem.h. Include printoem.h.


UNIFONTOBJ

The UNIFONTOBJ structure is used as an input parameter to font functions in rendering plug-ins.

typedef struct _UNIFONTOBJ{
  ULONG  ulFontID;
  DWORD  dwFlags;
  IFIMETRICS  *pIFIMetrics;
  PFNGETINFO  pfnGetInfo;
} UNIFONTOBJ, *PUNIFONTOBJ;

Members

ulFontID
Unidrv-supplied resource identifier for an RC_UFM resource contained in a Unidrv minidriver's resource DLL.
dwFlags
Unidrv-supplied bit flags. Flag definitions are as follows:
Flag | Definition
UFOFLAG_TTDOWNLOAD_BITMAP | If set, the font is a bitmap font.
UFOFLAG_TTDOWNLOAD_TTOUTLINE | If set, the font is a TrueType outline font.
UFOFLAG_TTFONT If set, the font is a downloadable TrueType font.

If not set, the font is a device font.
UFOFLAG_TTOUTLINE_BOLD_SIM | If set, the TrueType font has bold simulation done by GDI.
UFOFLAG_TTOUTLINE_ITALIC_SIM | If set, the TrueType font has italic simulation done by GDI.
UFOFLAG_TTOUTLINE_VERTICAL If set, the TrueType font is a vertical font. Note that this flag is available only for those Asian fonts that can be written vertically.
If not set, text is written horizontally.
UFOFLAG_TTSUBSTITUTED | If set, the device font is a font substituted for the TrueType font. In the font substitution, GDI requests that Unidrv print using a TrueType font. For performance reasons, Unidrv substitutes a device font for the TrueType font. (The substitution is specified by a GPD file or in a table in the registry.) For this substitution, for some printers, it is necessary to adjust the baseline position of the device font, since the baseline position of the device font can be higher than that of the TrueType font. The adjustment causes the output of the substituted device font to be shifted down to correct this discrepancy. Depending on the flags set in the UNIFONTOBJ structure, the printer minidriver is able to adjust the baseline position of device fonts.

pIFIMetrics
Unidrv-supplied pointer to an IFIMETRICS structure.
pfnGetInfo
Unidrv-supplied pointer to Unidrv's UNIFONTOBJ_GetInfo callback function.

Headers

Declared in printoem.h. Include printoem.h.


Enumerations Used in Plug-ins

This section describes enumerations used in UI and render plug-ins.


EATTRIBUTE_DATATYPE

The EATTRIBUTE_DATATYPE enumerates the possible data types for a global attribute, feature attribute or option attribute.

typedef enum _EATTRIBUTE_DATATYPE {
  kADT_UNKNOWN,
  kADT_BOOL,
  kADT_INT,
  kADT_LONG,
  kADT_DWORD,
  kADT_ASCII,
  kADT_UNICODE,
  kADT_BINARY,
  kADT_SIZE,
  kADT_RECT,
  kADT_CUSTOMSIZEPARAMS
} EATTRIBUTE_DATATYPE;

Enumerators

kADT_UNKNOWN
The attribute is of unknown type.
kADT_BOOL
The attribute is of type BOOL.
kADT_INT
The attribute is of type INT.
kADT_LONG
The attribute is of type LONG.
kADT_DWORD
The attribute is of type DWORD.
kADT_ASCII
The attribute is an ASCII string.
kADT_UNICODE
The attribute is a UNICODE string.
kADT_BINARY
The attribute consists of binary data.
kADT_SIZE
The attribute is of type SIZE.
kADT_RECT
The attribute is of type RECT.
kADT_CUSTOMSIZEPARAMS
The attribute is an array containing CUSTOMPARAM_MAX (a constant defined in printoem.h) elements. Each element is a CUSTOMSIZEPARAM structure.

Headers

Defined in printoem.h. Include printoem.h.

See Also

CUSTOMSIZEPARAM


Callback Functions

This section describes the callback functions provided by Unidrv and Pscript5.


UNIFONTOBJ_GetInfo

The UNIFONTOBJ_GetInfo callback function is provided by the Unidrv driver so that rendering plug-ins can obtain font or glyph information.

BOOL
  UNIFONTOBJ_GetInfo(
    UNIFONTOBJ  *pUFObj,
    DWORD  dwInfoID,
    PVOID  pvData,
    DWORD  dwDataSize,
    PDWORD  pcbNeeded
    );

Parameters

pUFObj
Caller-supplied pointer to the UNIFONTOBJ structure received by the function that is making the call back to UNIFONTOBJ_GetInfo.
dwInfoID
Caller-supplied constant value indicating the type structure pointed to by pData. See the following table.
pvData
Caller supplied pointer to a structure, as indicated in the following table.
dwInfoID Value | pData Structure
UFO_GETINFO_FONTOBJ | GETINFO_FONTOBJ
UFO_GETINFO_GLYPHBITMAP | GETINFO_GLYPHBITMAP
UFO_GETINFO_GLYPHSTRING | GETINFO_GLYPHSTRING
UFO_GETINFO_GLYPHWIDTH | GETINFO_GLYPHWIDTH
UFO_GETINFO_MEMORY | GETINFO_MEMORY
UFO_GETINFO_STDVARIABLE | GETINFO_STDVAR

For a summary of structure contents, see the following Comments section.

dwDataSize
Caller-supplied size of the buffer pointed to by pvData.
pcbNeeded
Caller-supplied pointer to a location to receive the minimum buffer size required to contain the structure identified by dwInfoID.

Return Value

If the operation succeeds, the function returns TRUE. Otherwise it returns FALSE.

Headers

Declared in printoem.h. Include printoem.h.

Comments

The UNIFONTOBJ_GetInfo callback function allows a rendering plug-in to call back into Unidrv to obtain font or glyph information from GDI, needed for handling customized font management operations.

A rendering plug-in receives the UNIFONTOBJ_GetInfo function's address in the UNIFONTOBJ structure that is passed to the font customization methods.

The type of information returned by the function is dependent on the input arguments. The caller supplies values for dwInfoID, pvData, and dwDataSize to indicate the type of information wanted. The following table summarizes the types of information returned. For more information, see the structure descriptions.

pData Structure | Returned Information
GETINFO_FONTOBJ | A FONTOBJ structure describing the current font.
GETINFO_GLYPHBITMAP | A single glyph bitmap.
GETINFO_GLYPHSTRING | An array of glyph specifiers in a specified format.
GETINFO_GLYPHWIDTH | Total width of a set of glyphs.
GETINFO_MEMORY | Amount of available printer memory remaining.
GETINFO_STDVAR | The current value for one or more of Unidrv's standard variables.

If the buffer described by pvData and dwDataSize is too small to receive the structure indicated by dwInfoID, the function loads the required buffer size into the location pointed by pcbNeeded and returns FALSE.


Printer Font Resource Structures

This section provides the following topics:

Unidrv Font Format Structures

Unidrv Font Metrics Structures

Unidrv Glyph Translation Table Structures


Unidrv Font Format Structures

This section describes the structures used by Unidrv Font Format files (.uff files). Structures are defined in prntfont.h.


UFF_FILEHEADER

The UFF_FILEHEADER structure is used to define the contents of Unidrv Font Format files (.uff files).

typedef struct _UFF_FILEHEADER {
  DWORD  dwSignature;
  DWORD  dwVersion;
  DWORD  dwSize;
  DWORD  nFonts;
  DWORD  nGlyphSets;
  DWORD  nVarData;
  DWORD  offFontDir;
  DWORD  dwFlags;
  DWORD  dwReserved[4];
} UFF_FILEHEADER, *PUFF_FILEHEADER;

Members

dwSignature
Signature for .uff files. This value must be UFF_FILE_MAGIC.
dwVersion
Format version for .uff files. This value must be UFF_VERSION_NUMBER. The HIWORD contains the major version number and the LOWORD contains the minor version number.
dwSize
Size, in bytes, of the UFF_FILEHEADER structure.
nFonts
The number of fonts specified within the .uff file and identified by DATA_HEADER structures. This is also the number of UFF_FONTDIRECTORY structures within the .uff file.
nGlyphSets
The number of glyph sets specified within the .uff file and identified by DATA_HEADER structures. Some fonts might share a glyph set.
nVarData
The number of variable data sections specified within the .uff file and identified by DATA_HEADER structures.
offFontDir
Offset, in bytes, from the beginning of the .uff file to the beginning of the first UFF_FONTDIRECTORY structure.
dwFlags
Bit flags, as specified in the following table.
Flag | Definition
FONT_DIR_SORTED | The array of UFF_FONTDIRECTORY structures (specified by offFontDir) is sorted by the contents of that structure's wFontID member.

dwReserved
Reserved. Must be set to zero.

Headers

Declared in prntfont.h. Include prntfont.h.


UFF_FONTDIRECTORY

The UFF_FONTDIRECTORY structure is used to specify the directory of font descriptions contained in a Unidrv Font Format file (.uff file).

typedef struct _UFF_FONTDIRECTORY {
  DWORD  dwSignature;
  WORD  wSize;
  WORD  wFontID;
  SHORT  sGlyphID;
  WORD  wFlags;
  DWORD  dwInstallerSig;
  DWORD  offFontName;
  DWORD  offCartridgeName;
  DWORD  offFontData;
  DWORD  offGlyphData;
  DWORD  offVarData;
} UFF_FONTDIRECTORY, *PUFF_FONTDIRECTORY;

Members

dwSignature
Font metrics record signature. This value must be FONT_REC_SIG.
wSize
Size, in bytes, of the UFF_FONTDIRECTORY structure.
wFontID
Font identifier. This value must match the wDataID member of a DATA_HEADER structure that specifies font metrics information within the .uff file.
sGlyphID
Glyph set identifier. This value specifies the glyph set that is to be associated with the font. See the following Comments section.
wFlags
Bit flags. One or more of the following flags can be specified.
Flag | Definition
FONT_FL_DEVICEFONT | The font is a device font.
FONT_FL_GLYPHSET_GTT | The glyph set is specified in Windows 2000 and later GTT format.
FONT_FL_GLYPHSET_RLE | The glyph set is specified in Windows NT 4.0 RLE format.
FONT_FL_IFI | Font metrics are specified in Windows NT 4.0 IFI format.
FONT_FL_PERMANENT_SF | The font is a PCL permanent soft font.
FONT_FL_SOFTFONT | The font is a PCL soft font.
FONT_FL_UFM | Font metrics are specified in Windows 2000 and later UFM format.

dwInstallerSig
Signature value of the font installer that installed the font.
offFontName
Offset, in bytes, from the beginning of the .uff file to a DWORD-aligned, NULL-terminated, UNICODE string representing the name of the font.
offCartridgeName
Offset, in bytes, from the beginning of the .uff file to a DWORD-aligned, NULL-terminated, UNICODE string representing the name of the font cartridge containing the font. If the font is not contained in a cartridge, this value should be zero.
offFontData
Offset, in bytes, from the beginning of the .uff file to a DWORD-aligned DATA_HEADER structure specifying a font metrics section.
offGlyphData
Offset, in bytes, from the beginning of the .uff file to a DWORD-aligned DATA_HEADER structure specifying a glyph set section. If sGlyphID is zero or negative, offGlyphData should be zero.
offVarData
Offset, in bytes, from the beginning of the .uff file to a DWORD-aligned DATA_HEADER structure specifying a data section. If the FONT_FL_PERMANENT_SF flag is set in wFlags, offVarData must be zero.

Headers

Declared in prntfont.h. Include prntfont.h.

Comments

If sGlyphID is a greater than zero, it must match the wDataID member of a DATA_HEADER structure that specifies a glyph set within the .uff file.

If sGlyphID is less than zero, it must be one of the CC_-prefixed constants defined in prntfont.h, which identify pre-defined glyph sets.

If sGlyphID is zero, Unidrv uses the glyph set resource identifier contained in the font's UNIFM_HDR structure. The glyph set resource must be contained in the minidriver's resource DLL, or else Unidrv uses the default glyph translation.


DATA_HEADER

The DATA_HEADER structure is used to specify a data section within a Unidrv Font Format file (.uff file).

typedef struct _DATA_HEADER {
  DWORD  dwSignature;
  WORD  wSize;
  WORD  wDataID;
  DWORD  dwDataSize;
  DWORD  dwReserved;
} DATA_HEADER, *PDATA_HEADER;

Members

dwSignature
Signature value identifying the type of data being specified. Valid signature values are listed in the following table.
Signature | Definition
DATA_CTT_SIG | This data section contains CTT-formatted glyph set information.
DATA_GTT_SIG | This data section contains GTT-formatted glyph set information.
DATA_IFI_SIG | This data section contains IFI-formatted font metrics.
DATA_UFM_SIG | This data section contains UFM-formatted font metrics.
DATA_VAR_SIG | This data section contains data to be downloaded to the printer. See the following Comments section.

wSize
Size, in bytes, of the DATA_HEADER structure.
wDataID
If the data section contains font metrics data, this value must be a unique font identifier. For fonts that are permanently downloaded by the font installer, this value should be the downloaded font's identifier.

If the data section contains glyph data, this value must be a glyph set identifier.

If the data section contains variable data, this value must be zero.

dwDataSize
Size, in bytes, of all the information represented by this DATA_HEADER structure. For example, if dwSignature is DATA_UFM_SIG, this value represents the size, in bytes of the font's UNIFM_HDR structure and all associated structures. The size value does not include any byte padding required to align the next DATA_HEADER structure to a DWORD.
dwReserved
Not used. Must be set to zero.

Headers

Declared in prntfont.h. Include prntfont.h.

Comments

If dwSignature is DATA_VAR_SIG, the data section contains variable data that Unidrv will send to the printer the first time the font is selected. Typically, this data consists of a font header and corresponding font identifier, along with downloadable glyph information for all the glyphs supported by the font. PCL soft font information includes PCL commands for loading the font header and glyph definitions for all supported glyphs. Unidrv does not validate variable data. Data validation should be performed by the font installer.

Each DATA_HEADER structure must be DWORD-aligned.


Unidrv Font Metrics Structures

This section describes the structures used in Unidrv Font Metrics files (UFM files). Structures are defined in prntfont.h.


EXTTEXTMETRIC

The EXTTEXTMETRIC structure is used to specify font-specific information within Unidrv Font Metrics files (.ufm files).

typedef struct _EXTTEXTMETRIC {
  short  emSize;
  short  emPointSize;
  short  emOrientation;
  short  emMasterHeight;
  short  emMinScale;
  short  emMaxScale;
  short  emMasterUnits;
  short  emCapHeight;
  short  emXHeight;
  short  emLowerCaseAscent;
  short  emLowerCaseDescent;
  short  emSlant;
  short  emSuperScript;
  short  emSubScript;
  short  emSuperScriptSize;
  short  emSubScriptSize;
  short  emUnderlineOffset;
  short  emUnderlineWidth;
  short  emDoubleUpperUnderlineOffset;
  short  emDoubleLowerUnderlineOffset;
  short  emDoubleUpperUnderlineWidth;
  short  emDoubleLowerUnderlineWidth;
  short  emStrikeOutOffset;
  short  emStrikeOutWidth;
  WORD   emKernPairs;
  WORD   emKernTracks;
} EXTTEXTMETRIC, *PEXTTEXTMETRIC;

Members

emSize
Size of the structure, in bytes.
emPointSize
Nominal point size of this font, in twips (1/20 of a point, or 1/1440 inch). This is the intended size of the font; the actual size may differ slightly depending on the resolution of the device.
emOrientation
Orientation of the font. The emOrientation member can be any of the following values:
Value | Meaning
0 | Either portrait or landscape orientation
1 | Portrait orientation
2 | Landscape orientation

emMasterHeight
Font size, in device units, for which the values in this font's extent table are exact.
emMinScale
Minimum valid size for this font. The following equation illustrates how the minimum point size is determined:
smallest point size = (emMinScale * 72) / dfVertRes

The value 72 represents the number of points per inch. The dfVertRes value is the number of dots per inch.

emMaxScale
Maximum valid size for this font. The following equation illustrates how the maximum point size is determined:
largest point size = (etmMaxScale * 72) / dfVertRes

The value 72 represents the number of points per inch. The dfVertRes value is the number of dots per inch.

emMasterUnits
Integer number of units per em, where an em equals the value of the emMasterHeight member. (That is, emMasterUnits is emMasterHeight expressed in font units instead of device units.)
emCapHeight
Height, in font units, of uppercase characters in the font. Typically, this is the height of uppercase H.
emXHeight
Height, in font units, of lowercase characters in the font. Typically, this is the height of lowercase x.
emLowerCaseAscent
Distance, in font units, that the ascender of lowercase letters extends above the base line. Typically, this is the height of lowercase d.
emLowerCaseDescent
Distance, in font units, that the descender of lowercase letters extends below the base line. Typically, this is specified for the descender of lowercase p.
emSlant
For an italic or slanted font, the angle of the slant measured in tenths of a degree clockwise from the upright version of the font.
emSuperScript
Recommended amount, in font units, to offset superscript characters from the base line. This is typically a negative value.
emSubScript
Recommended amount, in font units, to offset subscript characters from the base line. This is typically a positive value.
emSuperScriptSize
Recommended size, in font units, of superscript characters for this font.
emSubScriptSize
Recommended size, in font units, of subscript characters for this font.
emUnderlineOffset
Offset, in font units, downward from the base line, where the top of a single underline bar should appear.
emUnderlineWidth
Thickness, in font units, of the underline bar.
emDoubleUpperUnderlineOffset
Offset, in font units, downward from the base line, where the top of the upper double-underline bar should appear.
emDoubleLowerUnderlineOffset
Offset, in font units, downward from the base line, where the top of the lower double-underline bar should appear.
emDoubleUpperUnderlineWidth
Thickness, in font units, of the upper underline bar.
emDoubleLowerUnderlineWidth
Thickness, in font units, of the lower underline bar.
emStrikeOutOffset
Offset, in font units, upward from the base line, where the top of a strikeout bar should appear.
emStrikeOutWidth
Thickness, in font units, of the strikeout bar.
emKernPairs
Number of character kerning pairs defined for this font.
emKernTracks
Number of kerning tracks defined for this font.

Headers

Declared in prntfont.h. Include prntfont.h.


INVOC

The INVOC structure is used for describing printer command strings in Unidrv Font Metrics files (.ufm files) and Glyph Translation Table files (.gtt files).

typedef struct _INVOC {
  DWORD  dwCount;
  DWORD  loOffset;
} INVOC, *PINVOC;

Members

dwCount
Number of characters in the command.
loOffset
One of the following:
For .ufm files:
Byte offset from the beginning of the .ufm file's UNIDRVINFO structure to beginning of the command string.
For .gtt files:
Byte offset from the beginning of the .gtt file's UNI_CODEPAGEINFO structure to beginning of the command string.

Headers

Declared in prntfont.h. Include prntfont.h.

Comments

INVOC structures are used within UNIDRVINFO structures.


KERNDATA

The KERNDATA structure is used for describing printer kerning pairs.

typedef struct _KERNDATA {
  DWORD  dwSize;
  DWORD  dwKernPairNum;
  FD_KERNINGPAIR  KernPair[1];
} KERNDATA, *PKERNDATA;

Members

dwSize
Size, in bytes, of KERNDATA structure, including the KernPair array.
dwKernPairNum
Number of elements in the KernPair array.
KernPair
Array of FD_KERNINGPAIR structures.

Headers

Declared in prntfont.h. Include prntfont.h.

Comments

A .ufm file's KERNDATA structures are accessed by a pointer in the file's UNIFM_HDR structure.


UNIDRVINFO

The UNIDRVINFO structure is used to specify printer-specific information within Unidrv Font Metrics files (.ufm files).

typedef struct _UNIDRVINFO {
  DWORD  dwSize;
  DWORD  flGenFlags;
  WORD  wType;
  WORD  fCaps;
  WORD  wXRes;
  WORD  wYRes;
  short  sYAdjust;
  short  sYMoved;
  WORD  wPrivateData;
  short  sShift;
  INVOC  SelectFont;
  INVOC  UnSelectFont;
  WORD  wReserved[4];
} UNIDRVINFO, *PUNIDRVINFO;

Members

dwSize
Size, in bytes, of the UNIDRVINFO structure.
flGenFlags
Contains one or more bit flags describing font characteristics. The following flags are defined:
UFM_CART | The font is contained in a cartridge.
UFM_CART_MAIN | The font is the first one in the cartridge.
UFM_SCALABLE | The font is scalable.
UFM_SOFT | The font is a soft font, requiring downloading.

wType
Contains an integer constant describing the font type. The following constants are defined:
DF_TYPE_CAPSL | Canon CAPSL scalable font
DF_TYPE_HPINTELLIFONT | HP Intellifont font
DF_TYPE_OEM1 | OEM-supplied scalable font
DF_TYPE_OEM2 | OEM-supplied scalable font
DF_TYPE_PST1 | Lexmark PPDS scalable font
DF_TYPE_TRUETYPE | HP PCLETTO font for LJ4 printers

fCaps
Contains one or more bit flags identifying limitations on the capabilities provided by a device font. The following flags are defined:
DF_BKSP_OK If set, a single backspace character can move the cursor to the beginning of the overstrike region. If not set, an x-movement cursor command must be sent.

(Used only if MTYPE_PAIRED is specified for the character's TRANSDATA structure in MAPTABLE. Otherwise ignored.)
DF_NO_BOLD | The device font cannot be bolded using underline simulation.
DF_NO_DOUBLE_UNDERLINE | The device font cannot be double-underlined using double-underline simulation.
DF_NO_STRIKETHRU | The device font cannot be struck through using strike-through simulation.
DF_NOITALIC | The device font cannot be italicized using italic simulation.
DF_NOUNDER | The device font cannot be underlined using underline simulation.
DF_XM_CR | Unidrv must send a carriage return command after each line of text.

wXRes
The font's x-resolution.
wYRes
The font's y-resolution.
sYAdjust
The amount of vertical adjustment required before output of double-height characters on dot-matrix printers.
sYMoved
The amount of vertical cursor movement that results when a double-height character is printed on a dot-matrix printer.
wPrivateData
Can be used for printer-specific information such as, for example, HP DeskJet permutations.
sShift
The number of pixels by which each character must be shifted. Used for the Microsoft Z1a cartridge.
SelectFont
An INVOC structure containing the printer's font selection command.
UnSelectFont
An INVOC structure containing the printer's font de-selection command.
wReserved
Not used.

Headers

Declared in prntfont.h. Include prntfont.h.

Comments

A .ufm (Unidrv Font Metrics) file's UNIDRVINFO structure is accessed by a pointer in the file's UNIFM_HDR structure.


UNIFM_HDR

The UNIFM_HDR structure is used to define the contents of Unidrv Font Metrics files (.ufm files).

typedef struct _UNIFM_HDR {
  DWORD  dwSize;
  DWORD  dwVersion;
  ULONG  ulDefaultCodepage;
  LONG  lGlyphSetDataRCID;
  DWORD  loUnidrvInfo;
  DWORD  loIFIMetrics;
  DWORD  loExtTextMetric;
  DWORD  loWidthTable;
  DWORD  loKernPair;
  DWORD  dwReserved[2];
} UNIFM_HDR, *PUNIFM_HDR;

Members

dwSize
Total size, in bytes, of the .ufm file. Note that this is the total size of all structures used to define the file. This value is not the size of the UNIFM_HDR structure.
dwVersion
File version number, as defined in prntfont.h by a constant with a name format of UNIFM_VERSION_x_x.
ulDefaultCodepage
Code page identifier specifying the font's default code page. For more information, see the following Comments section.
lGlyphSetDataRCID
An RC_GTT resource identifier that identifies a .gtt (Glyph Translation Table) file, or one of the CC_-prefixed code conversion identifiers defined in prntfont.h. For more information, see the following Comments section.
loUnidrvInfo
Byte offset from the beginning of the .ufm (Unidrv Font Metrics) file to the location of the file's UNIDRVINFO structure.
loIFIMetrics
Byte offset from the beginning of the .ufm file to the location of the file's IFIMETRICS structure.
loExtTextMetric
Byte offset from the beginning of the .ufm file to the location of the file's EXTTEXTMETRIC structure.
loWidthTable
Byte offset from the beginning of the .ufm file to the location of the file's WIDTHTABLE structure.
loKernPair
Byte offset from the beginning of the .ufm file to the location of the file's KERNDATA structure.
dwReserved
Not used.

Headers

Declared in prntfont.h. Include prntfont.h.

Comments

A UNIFM_HDR structure must be the first structure contained in a .ufm file.

If lGlyphSetDataRCID is not CC_DEFAULT, then the following rules apply:

  • If lGlyphSetDataRCID contains an RC_GTT resource identifier, the code page number specified for ulDefaultCodepage must be the same code page number that is contained in the .gtt (Glyph Translation Table) file's first UNI_CODEPAGEINFO structure.
  • If lGlyphSetDataRCID contains one of the CC_-prefixed code conversion identifiers (other than CC_DEFAULT), the code page number specified for ulDefaultCodepage must be the code page number that is associated with the CC_-prefixed identifier. (These code page numbers are listed in prntfont.h, next to each CC_-prefixed identifier.)

If lGlyphSetDataRCID is CC_DEFAULT, there are no restrictions on the value specified for ulDefaultCodepage, but a default code page must be specified.


WIDTHRUN

The WIDTHRUN structure is used to define the contents of Unidrv Font Metrics files (.ufm files).

typedef struct _WIDTHRUN {
  WORD  wStartGlyph;
  WORD  wGlyphCount;
  DWORD  loCharWidthOffset;
} WIDTHRUN, *PWIDTHRUN;

Members

wStartGlyph
Index value indicating the first glyph of the width run.
wGlyphCount
Number of glyphs represented by the width run.
loCharWidthOffset
Offset from the beginning of a WIDTHTABLE structure to the location containing the width of the set of glyphs contained in the width run.

Headers

Declared in prntfont.h. Include prntfont.h.

Comments

A width run describes the widths of a set of adjacent glyphs. Sets of width runs are described by an array of WIDTHRUN elements. The array is contained in a WIDTHTABLE structure.

Index values contained in dwStartGlyph are integers, starting with 1, with each glyph in the font having an index. That is, the first glyph in the font is assigned an index value of 1, the next glyph's index is 2, and so on.

For example, suppose the first three elements of a WIDTHRUN array contain the following values:

WIDTHRUN[0]
wStartGlyph=1
wGlyphCount=3
IoCharWidthOffset=xxx
WIDTHRUN[1]
wStartGlyph=4
wGlyphCount=2
IoCharWidthOffset=yyy
WIDTHRUN[2]
wStartGlyph=7
wGlyphCount=4
IoCharWidthOffset=zzz

At offset xxx: 56, 50, 60 (WORD-sized)
At offset yyy: 54, 60
At offset zzz: 54, 60, 43, 40

In this example, widths for the first three glyphs of the font are contained in an array at location WIDTHTABLE+xxx, the widths for the next two glyphs are contained in an array at location WIDTHTABLE+yyy, and widths for the next four glyphs are contained in an array at location WIDTHTABLE+zzz.

If a device font is proportional and has variable pitch characters, the WIDTHTABLE structure's WidthRun array contains only one WIDTHRUN element, and WIDTHTABLE+loCharWidthOffset points to a character width array for all characters in the font.

For Western device fonts, the fwdAveCharWidth member of the IFIMETRICS structure is used for determining single-byte character widths, if the character widths are not specified using a WIDTHTABLE structure.

For East Asian device fonts, the fwdAveCharWidth and fwdMaxCharInc members of the IFIMETRICS structure are used for determining single-byte and double-byte character widths. If the font is proportional, the font's .ufm file should contain a WIDTHTABLE structure for the proportional glyphs.


WIDTHTABLE

The WIDTHTABLE structure is used to define the contents of Unidrv Font Metrics files (.ufm files).

typedef struct _WIDTHTABLE {
  DWORD  dwSize;
  DWORD  dwRunNum;
  WIDTHRUN  WidthRun[1];
} WIDTHTABLE, *PWIDTHTABLE;

Members

dwSize
Size, in bytes, of the WIDTHTABLE structure, including the WidthRun array.
dwRunNum
Number of elements in the WidthRun array.
WidthRun
Array of WIDTHRUN structures.

Headers

Declared in prntfont.h. Include prntfont.h.

Comments

A .ufm file's WIDTHTABLE structure, which describes character widths, is accessed by a pointer in the file's UNIFM_HDR structure.


Unidrv Glyph Translation Table Structures

This section describes the structures used in Unidrv Glyph Translation Table files (.gtt files).


GLYPHRUN

The GLYPHRUN structure is one of the structures used to define the contents of Glyph Translation Table files (.gtt files).

typedef struct _GLYPHRUN {
  WCHAR  wcLow;
  WORD  wGlyphCount;
} GLYPHRUN, *PGLYPHRUN;

Members

wcLow
UNICODE value representing the first glyph in the glyph run.
wGlyphCount
Number of glyphs represented by the glyph run.

Headers

Declared in prntfont.h. Include prntfont.h.

Comments

A .gtt (glyph translation table) file contains an array of GLYPHRUN structures. Each structure identifies a set of UNICODE values for which the printer provides glyphs. The array is described by the IoRunOffset and dwRunCount members of a .gtt file's UNI_GLYPHSETDATA structure.

The GLYPHRUN structures must be defined in ascending order, based on the value of wcLow. Unidrv uses the GLYPHRUN array to generate glyph handles and store them in an WCRUN array within an FD_GLYPHSET structure.


MAPTABLE

The MAPTABLE structure is one of the structures used to define the contents of Glyph Translation Table files (.gtt files).

typedef struct _MAPTABLE {
  DWORD  dwSize
  DWORD  dwGlyphNum;
  TRANSDATA  Trans[1];
} MAPTABLE, *PMAPTABLE;

Members

dwSize
Size, in bytes, of the MAPTABLE structure, including the Trans array.
dwGlyphNum
Number of elements in the Trans array.
Trans
Array of TRANSDATA structures.

Headers

Declared in prntfont.h. Include prntfont.h.

Comments

A .gtt file's MAPTABLE structure, which contains a glyph mapping table, is accessed by a pointer in the file's UNI_GLYPHSETDATA structure. The table maps glyph handles to the character codes or commands that must be sent to the printer in order to print glyphs.


TRANSDATA

The TRANSDATA structure is one of the structures used to define the contents of Glyph Translation Table files (.gtt files).

typedef struct _TRANSDATA {
  BYTE  ubCodePageID;
  BYTE  ubType;
  union
    {
    SHORT  sCode;
    BYTE  ubCode;
    BYTE  ubPairs[2];
    } uCode;
} TRANSDATA, *PTRANSDATA;

Members

ubCodePageID
Zero-based index into the array of UNI_CODEPAGEINFO structures that is pointed to by the UNI_GLYPHSETDATA structure's loCodePageOffset member.
ubType
One or more bit flags, as follows:
Flag | Definition
Format Flags | One, and only one, can be set.
MTYPE_COMPOSE | The sCode member of the uCode union contains an offset to a string. The string contains a command to be sent to the printer.
MTYPE_DIRECT | The ubCode member of the uCode union contains a one-byte character code to be sent to the printer.
MTYPE_PAIRED | The ubPairs member of the uCode union contains a two-byte character code to be sent to the printer.
Action Flags | All are optional. Not valid if the lPredefinedID member of the UNI_GLYPHSETDATA structure is set to CC_NOPRECNV.
MTYPE_ADD | The specified mapping is added to the map table contained in the .gtt file specified by the lPredefinedID member of the UNI_GLYPHSETDATA structure.
MTYPE_DISABLE | The specified mapping, contained in the .gtt file specified by the lPredefinedID member of the UNI_GLYPHSETDATA structure, is disabled.
MTYPE_REPLACE | The specified mapping replaces mapping in the map table contained in the .gtt file specified by the lPredefinedID member of the UNI_GLYPHSETDATA structure.
East Asian Flags
MTYPE_SINGLE | Character data is single-byte.
MTYPE_DOUBLE | Character data is double-byte.

sCode
Offset to a command string. Offset is relative to the beginning of the MAPTABLE structure containing the TRANSDATA array. The first word of the command string must be the command size. Valid if the MTYPE_COMPOSE flag is set in uType.
ubCode
One-byte character code. Valid if the MTYPE_DIRECT flag is set in uType.
ubPairs
Two-byte character code. Valid if the MTYPE_PAIRED flag is set in uType.
uCode
Union of the preceding three members: sCode, ubCode, and ubPairs.

Headers

Declared in prntfont.h. Include prntfont.h.

Comments

A .gtt file's TRANSDATA structure array, which contains glyph mapping information, is contained in the file's MAPTABLE structure.


UNI_CODEPAGEINFO

The UNI_CODEPAGEINFO structure is one of the structures used to define the contents of Glyph Translation Table files (.gtt files).

typedef struct _UNI_CODEPAGEINFO {
  DWORD  dwCodePage;
  INVOC  SelectSymbolSet;
  INVOC  UnSelectSymbolSet;
} UNI_CODEPAGEINFO, *PUNI_CODEPAGEINFO;

Members

dwCodePage
Number identifying a Windows code page.
SelectSymbolSet
An INVOC structure containing the printer command to select the code page's symbol set.
UnSelectSymbolSet
An INVOC structure containing the printer command to deselect the code page's symbol set.

Headers

Declared in prntfont.h. Include prntfont.h.


UNI_GLYPHSETDATA

The UNI_GLYPHSEDATA structure is one of the structures used to define the contents of Glyph Translation Table files (.gtt files).

typedef struct _UNI_GLYPHSETDATA {
  DWORD  dwSize;
  DWORD  dwVersion;
  DWORD  dwFlags;
  LONG   lPredefinedID;
  DWORD  dwGlyphCount;
  DWORD  dwRunCount;
  DWORD  loRunOffset;
  DWORD  dwCodePageCount;
  DWORD  loCodePageOffset;
  DWORD  loMapTableOffset;
  DWORD  dwReserved[2];
} UNI_GLYPHSETDATA, *PUNI_GLYPHSETDATA;

Members

dwSize
Total size, in bytes, of the .gtt file. Note that this is the total size of all structures used to define the file. This value is not the size of the UNI_GLYPHSETDATA structure.
dwVersion
File version number, as defined in prntfont.h by a constant with a name format of UNI_GLYPHSETDATA_VERSION_x_x.
dwFlags
Not used.
lPredefinedID
One of the CC_-prefixed code conversion identifiers defined in prntfont.h.
dwGlyphCount
Number of glyphs provided by this font.
dwRunCount
Number of GLYPHRUN structures in the array pointed to by loRunOffset.
loRunOffset
Byte offset from the beginning of the UNI_GLYPHSETDATA structure to the beginning of an array of GLYPHRUN structures.
dwCodePageCount
Number of UNI_CODEPAGEINFO structures in the array pointed to by loCodePageOffset.
loCodePageOffset
Byte offset from the beginning of the UNI_GLYPHSETDATA structure to the beginning of an array of UNI_CODEPAGEINFO structures.
loMapTableOffset
Byte offset from the beginning of the UNI_GLYPHSETDATA structure to the beginning of a MAPTABLE structure.
dwReserved
Reserved for future use.

Headers

Declared in prntfont.h. Include prntfont.h.

Comments

A UNI_GLYPHSETDATA structure must be the first structure contained in a .gtt file.


Obsolete Printer Driver Functions

This section describes obsolete printer driver helper functions for plug-ins, and printer minidriver plug-in functions. Many of the functions listed in this section have been superseded by functions exposed in COM interfaces. Where applicable, links are provided to the newer functions.

Obsolete Printer Driver-Provided Helper Functions for Plug-ins

Obsolete Printer Minidriver Plug-in Functions


Obsolete Printer Driver-Provided Helper Functions for Plug-ins

The functions listed in this section, which are declared in printoem.h, are obsolete printer driver helper functions. These helper functions have been superseded by the core driver helper methods exposed by one or more of the IPrintOemDriverUI, IPrintCoreUI2, IPrintOemDriverUni, IPrintOemDriverPS, and IPrintCorePS2 COM interfaces.


DrvGetDriverSetting

The DrvGetDriverSetting function is obsolete. Windows 2000 and later printer drivers should use IPrintOemDriverUI::DrvGetDriverSetting, IPrintCoreUI2::DrvGetDriverSetting (UI plug-ins), IPrintOemDriverUni::DrvGetDriverSetting (Unidrv plug-ins) or IPrintOemDriverPS::DrvGetDriverSetting (PScript plug-ins).

BOOL
  (APIENTRY PFN_DrvGetDriverSetting)(
    PVOID  pdriverobj,
    PCSTR  Feature,
    PVOID  pOutput,
    DWORD  cbSize,
    PDWORD  pcbNeeded,
    PDWORD  pdwOptionsReturned
    );

The preceding function pointer type defines the type of the DrvGetDriverSetting member of the OEMUIPROCS and DRVPROCS structures.

Headers

Declared in printoem.h. Include printoem.h.


DrvGetStandardVariable

This DrvGetStandardVariable function is obsolete. Windows 2000 and later printer drivers should use IPrintOemDriverUni::DrvGetStandardVariable.

typedef BOOL
  (APIENTRY PFN_DrvGetStandardVariable)(
    PDEVOBJ  pdevobj,
    DWORD  dwIndex,
    PVOID  pBuffer,
    DWORD  cbSize,
    PDWORD  pcbNeeded
    );

The preceding function pointer prototype defines the type of the BGetStandardVariable member of the DRVPROCS structure.

Headers

Declared in printoem.h. Include printoem.h.


DrvUnidriverTextOut

The DrvUnidriverTextOut function is obsolete. Windows 2000 and later printer drivers should use IPrintOemDriverUni::DrvUniTextOut.

typedef BOOL
  (APIENTRY PFN_DrvUnidriverTextOut)(
    SURFOBJ  *pso,
    STROBJ   *pstro,
    FONTOBJ  *pfo,
    CLIPOBJ  *pco,
    RECTL  *prclExtra,
    RECTL  *prclOpaque,
    BRUSHOBJ  *pboFore,
    BRUSHOBJ  *pboOpaque,
    POINTL  *pptlBrushOrg,
    MIX  mix
    );

The preceding function pointer prototype defines the type of the DrvUnidriverTextOut member of the DRVPROCS structure.

Headers

Declared in printoem.h. Include printoem.h.


DrvUpdateUISetting

The DrvUpdateUISetting function is obsolete. Windows 2000 and later UI plug-ins should use IPrintOemDriverUI::DrvUpdateUISetting or IPrintCoreUI2::DrvUpdateUISetting.

typedef BOOL
  (APIENTRY PFN_DrvUpdateUISetting)(
    PVOID  pdriverobj,
    PVOID  pOptItem,
    DWORD  dwPreviousSelection,
    DWORD  dwMode
    );

The preceding function pointer prototype defines the type of the DrvUpdateUISetting member of the OEMUIPROCS structure.

Headers

Declared in printoem.h. Include printoem.h.


DrvUpgradeRegistrySetting

The DrvUpgradeRegistrySetting function is obsolete. Windows 2000 and later UI plug-ins should use IPrintOemDriverUI::DrvUpgradeRegistrySetting or IPrintCoreUI2::DrvUpgradeRegistrySetting.

typedef BOOL
  (APIENTRY PFN_DrvUpgradeRegistrySetting)(
    HANDLE  hPrinter,
    PCSTR  pFeature,
    PCSTR  pOption
    );

The preceding function pointer prototype defines the type of the pfnUpgrade parameter of the OEMUpgradeRegistry function.

Headers

Declared in printoem.h. Include printoem.h.


DrvWriteAbortBuf

The DrvWriteAbortBuf function is obsolete. Windows 2000 and later Unidrv render plug-ins should use IPrintOemDriverUni::DrvWriteAbortBuf.

typedef DWORD
  (APIENTRY PFN_DrvWriteAbortBuf)(
    PDEVOBJ  pdevobj,
    PVOID  pBuffer,
    DWORD  cbSize,
    DWORD  dwWait
    );

The preceding function pointer prototype defines the type of the DrvWriteAbortBuf member of the DRVPROCS structure.

Headers

Declared in printoem.h. Include printoem.h.


DrvWriteSpoolBuf

The DrvWriteSpoolBuf function pointed to by this function pointer is obsolete. Windows 2000 and later render plug-ins should use IPrintOemDriverUni::DrvWriteSpoolBuf (Unidrv plug-ins), IPrintOemDriverPS::DrvWriteSpoolBuf (PScript plug-ins), or IPrintCorePS2::DrvWriteSpoolBuf (PScript plug-ins).

typedef DWORD
  (APIENTRY PFN_DrvWriteSpoolBuf)(
    PDEVOBJ  pdevobj,
    PVOID  pBuffer,
    DWORD  cbSize
    );

The preceding function pointer prototype defines the type of the DrvWriteSpoolBuf member of the DRVPROCS structure.

Headers

Declared in printoem.h. Include printoem.h.


DrvXMoveTo

The DrvXMoveTo function is obsolete. Windows 2000 and later Unidrv plug-ins should use IPrintOemDriverUni::DrvXMoveTo.

typedef INT
  (APIENTRY PFN_DrvXMoveTo)(
    PDEVOBJ  pdevobj,
    INT  x,
    DWORD  dwFlags
    );

The preceding function pointer prototype defines the type of the DrvXMoveTo member of the DRVPROCS structure.

Headers

Declared in printoem.h. Include printoem.h.


DrvYMoveTo

The DrvYMoveTo function is obsolete. Windows 2000 and later Unidrv plug-ins should use IPrintOemDriverUni::DrvYMoveTo.

typedef INT
  (APIENTRY PFN_DrvYMoveTo)(
    PDEVOBJ  pdevobj,
    INT  y,
    DWORD  dwFlags
    );

The preceding function pointer prototype defines the type of the DrvYMoveTo member of the DRVPROCS structure.

Headers

Declared in printoem.h. Include printoem.h.


Obsolete Printer Minidriver Plug-in Functions

This section consists of obsolete functions that OEMs implemented for Windows NT 4.0 and Windows 2000. Developers writing new printer drivers should not use these functions. Reference pages for these functions are included in this DDK documentation for compatibility reasons only.


OEMCommonUIProp

This function is obsolete for Windows XP and later. It is supported only for legacy plug-ins. Use IPrintOemUI::CommonUIProp instead.

BOOL APIENTRY
  OEMCommonUIProp(
    DWORD  dwMode,
    POEMCUIPPARAM  pOemCUIPParam
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMCommand

This function is obsolete for Windows XP and later. It is supported only for legacy Pscript plug-ins. Use IPrintOemPS::Command.

DWORD APIENTRY
  OEMCommand(
    PDEVOBJ  pdevobj,
    DWORD  dwIndex,
    PVOID  pData,
    DWORD  cbSize
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMCommandCallback

This function is obsolete for Windows XP and later. It is supported only for legacy Unidrv plug-ins. Use IPrintOemUni::CommandCallback.

INT APIENTRY
  OEMCommandCallback(
    PDEVOBJ  pdevobj,
    DWORD  dwCallbackID,
    DWORD  dwCount,
    PDWORD  pdwParams
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMCompression

This function is obsolete for Windows XP and later. It is supported only for legacy Unidrv plug-ins. Use IPrintOemUni::Compression.

INT APIENTRY
  OEMCompression(
    PDEVOBJ  pdevobj,
    PBYTE  pInBuf,
    PBYTE  pOutBuf,
    DWORD  dwInLen,
    DWORD  dwOutLen
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMDeviceCapabilities

This function is obsolete for Windows XP and later. It is supported only for legacy plug-ins. Use IPrintOemUI::DeviceCapabilities instead.

DWORD APIENTRY
  OEMDeviceCapabilities(
    POEMUIOBJ  poemuiobj,
    HANDLE  hPrinter,
    PWSTR  pDeviceName,
    WORD  wCapability,
    PVOID  pOutput,
    PDEVMODE  pPublicDM,
    PVOID  pOEMDM,
    DWORD  dwLastResult
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMDevicePropertySheets

This function is obsolete for Windows XP and later. It is supported only for legacy plug-ins. Use IPrintOemUI::DevicePropertySheets instead.

LRESULT APIENTRY
  OEMDevicePropertySheets(
    PPROPSHEETUI_INFO  pPSUIInfo,
    LPARAM  lParam
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMDevMode

This function is obsolete for Windows XP and later. It is supported only for legacy plug-ins. For UI plug-ins, use IPrintOemUI::DevMode; for Pscript plug-ins, use IPrintOemPS::DevMode; for Unidrv plug-ins, use IPrintOemUni::DevMode.

BOOL APIENTRY
  OEMDevMode(
    DWORD  dwMode,
    POEMDMPARAM  pOemDMParam
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMDevQueryPrintEx

This function is obsolete for Windows XP and later. It is supported only for legacy plug-ins. Use IPrintOemUI::DevQueryPrintEx instead.

BOOL APIENTRY
  OEMDevQueryPrintEx(
    POEMUIOBJ  poemuiobj,
    PDEVQUERYPRINT_INFO  pDQPInfo,
    PDEVMODE  pPublicDM,
    PVOID  pOEMDM
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMDisableDriver

This function is obsolete for Windows XP and later. It is supported only for legacy plug-ins. Use IPrintOemPS::DisableDriver (Pscript) or IPrintOemUni::DisableDriver (Unidrv).

VOID APIENTRY
  OEMDisableDriver(
    VOID
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMDisablePDEV

This function is obsolete for Windows XP and later. It is supported only for legacy plug-ins. Use IPrintOemPS::DisablePDEV (Pscript) or IPrintOemUni::DisablePDEV (Unidrv).

VOID APIENTRY
  OEMDisablePDEV(
    PDEVOBJ  pdevobj
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMDocumentPropertySheets

This function is obsolete for Windows XP and later. It is supported only for legacy plug-ins. Use IPrintOemUI::DocumentPropertySheets instead.

LRESULT APIENTRY
  OEMDocumentPropertySheets(
    PPROPSHEETUI_INFO  pPSUIInfo,
    LPARAM  lParam
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMDriverDMS

This function is obsolete for Windows XP and later. It is supported only for legacy Unidrv plug-ins. Use IPrintOemUni::DriverDMS.

BOOL APIENTRY
  OEMDriverDMS(
    PVOID  pDevObj,
    PVOID  pBuffer,
    DWORD  cbSize,
    PDWORD  pcbNeeded
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMDownloadCharGlyph

This function is obsolete for Windows XP and later. It is supported only for legacy Unidrv plug-ins. Use IPrintOemUni::DownloadCharGlyph.

DWORD APIENTRY
  OEMDownloadCharGlyph(
    PDEVOBJ  pdevobj,
    PUNIFONTOBJ  pUFObj,
    HGLYPH  hGlyph,
    PDWORD  pdwWidth
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMDownloadFontHeader

This function is obsolete for Windows XP and later. It is supported only for legacy Unidrv plug-ins. Use IPrintOemUni::DownloadFontHeader.

DWORD APIENTRY
  OEMDownloadFontHeader(
    PDEVOBJ  pdevobj,
    PUNIFONTOBJ  pUFObj
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMEnableDriver

This function is obsolete for Windows XP and later. It is supported only for legacy plug-ins. Use IPrintOemPS::EnableDriver (Pscript) or IPrintOemUni::EnableDriver (Unidrv).

BOOL APIENTRY
  OEMEnableDriver(
    DWORD  dwOemIntfVersion,
    DWORD  cbSize,
    PDRVENABLEDATA  pded
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMEnablePDEV

This function is obsolete for Windows XP and later. It is supported only for legacy plug-ins. Use IPrintOemPS::EnablePDEV (Pscript) or IPrintOemUni::EnablePDEV (Unidrv).

PDEVOEM APIENTRY
  OEMEnablePDEV(
    PDEVOBJ  pdevobj,
    PWSTR  pPrinterName,
    ULONG  cPatterns,
    HSURF  *phsurfPatterns,
    ULONG  cjGdiInfo,
    GDIINFO  *pGdiInfo,
    ULONG  cjDevInfo,
    DEVINFO  *pDevInfo,
    DRVENABLEDATA  *pded
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMFilterGraphics

This function is obsolete for Windows XP and later. It is supported only for legacy Unidrv plug-ins. Use IPrintOemUni::FilterGraphics.

BOOL APIENTRY
  OEMFilterGraphics(
    PDEVOBJ  pdevobj,
    PBYTE  pBuf,
    DWORD  dwLen
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMFontInstallerDlgProc

This function is obsolete for Windows XP and later. It is supported only for legacy plug-ins. Use IPrintOemUI::FontInstallerDlgProc.

INT_PTR CALLBACK
  OEMFontInstallerDlgProc(
    HWND  hWnd,
    UINT  usMsg,
    WPARAM  wParam,
    LPARAM  lParam
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMGetInfo

This function is obsolete for Windows XP and later. It is supported only for legacy plug-ins. For a UI plug-in, use IPrintOemUI::GetInfo; for a Pscript plug-in, use IPrintOemPS::GetInfo; for a Unidrv plug-in, use IPrintOemUni::GetInfo.

BOOL APIENTRY
  OEMGetInfo(
    IN  DWORD  dwMode,
    OUT PVOID  pBuffer,
    IN  DWORD  cbSize,
    OUT PDWORD  pcbNeeded
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMHalftonePattern

This function is obsolete for Windows XP and later. It is supported only for legacy Unidrv plug-ins. Use IPrintOemUni::HalftonePattern.

BOOL APIENTRY
  OEMHalftonePattern(
    PDEVOBJ  pdevobj,
    PBYTE  pHTPattern,
    DWORD  dwHTPatternX,
    DWORD  dwHTPatternY,
    DWORD  dwHTNumPatterns,
    DWORD  dwCallbackID,
    PBYTE  pResource,
    DWORD  dwResourceSize
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMImageProcessing

This function is obsolete for Windows XP and later. It is supported only for legacy Unidrv plug-ins. Use IPrintOemUni::ImageProcessing.

PBYTE APIENTRY
  OEMImageProcessing(
    PDEVOBJ  pdevobj,
    PBYTE  pSrcBitmap,
    PBITMAPINFOHEADER  pBitmapInfoHeader,
    PBYTE  pColorTable,
    DWORD  dwCallbackID,
    PIPPARAMS  pIPParams
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMMemoryUsage (function)

This function is obsolete for Windows XP and later. It is supported only for legacy Unidrv plug-ins. Use IPrintOemUni::MemoryUsage instead.

VOID APIENTRY
  OEMMemoryUsage(
    PDEVOBJ  pdevobj,
    POEMMEMORYUSAGE  pMemoryUsage
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMOutputCharStr

This function is obsolete for Windows XP and later. It is supported only for legacy Unidrv plug-ins. Use IPrintOemUni::OutputCharStr.

VOID APIENTRY
  OEMOutputCharStr(
    PDEVOBJ  pdevobj,
    PUNIFONTOBJ  pUFObj,
    DWORD  dwType,
    DWORD  dwCount,
    PVOID  pGlyph
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMPDriverEvent

This function is obsolete for Windows XP and later. It is supported only for legacy plug-ins. Use IPrintOemUI::DriverEvent instead.

BOOL APIENTRY
  OEMPDriverEvent(
    DWORD  dwDriverEvent,
    DWORD  dwLevel,
    LPBYTE  pDriverInfo,
    LPARAM  lParam
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMPrinterEvent

This function is obsolete for Windows XP and later. It is supported only for legacy plug-ins. Use IPrintOemUI::PrinterEvent instead.

BOOL APIENTRY
  OEMPrinterEvent(
    PWSTR  pPrinterName,
    INT  iDriverEvent,
    DWORD  dwFlags,
    LPARAM  lParam
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMQueryColorProfile

This function is obsolete for Windows XP and later. It is supported only for legacy plug-ins. Use IPrintOemUI::QueryColorProfile or IPrintOemUI::QueryColorProfile instead.

BOOL APIENTRY
  OEMQueryColorProfile(
    HANDLE  hPrinter,
    POEMUIOBJ  poemuiobj,
    PDEVMODE  pPublicDM,
    PVOID  pOEMDM,
    ULONG  ulQueryMode,
    VOID  *pvProfileData,
    ULONG  *pcbProfileData,
    FLONG  *pflProfileData
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMResetPDEV

This function is obsolete for Windows XP and later. It is supported only for legacy plug-ins. Use IPrintOemPS::ResetPDEV (Pscript) or IPrintOemUni::ResetPDEV (Unidrv).

BOOL APIENTRY
  OEMResetPDEV(
    PDEVOBJ  pdevobjOld,
    PDEVOBJ  pdevobjNew
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMSendFontCmd

This function is obsolete for Windows XP and later. It is supported only for legacy Unidrv plug-ins. Use IPrintOemUni::SendFontCmd.

VOID APIENTRY
  OEMSendFontCmd(
    PDEVOBJ  pdevobj,
    PUNIFONTOBJ  pUFObj,
    PFINVOCATION  pFInv
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMTextOutAsBitmap

This function is obsolete for Windows XP and later. It is supported only for legacy Unidrv plug-ins. Use IPrintOemUni::TextOutAsBitmap.

BOOL APIENTRY
  OEMTextOutAsBitmap(
    SURFOBJ  *pso,
    STROBJ  *pstro,
    FONTOBJ  *pfo,
    CLIPOBJ  *pco,
    RECTL  *prclExtra,
    RECTL  *prclOpaque,
    BRUSHOBJ  *pboFore,
    BRUSHOBJ  *pboOpaque,
    POINTL  *pptlOrg,
    MIX  mix
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMTTDownloadMethod

This function is obsolete for Windows XP and later. It is supported only for legacy Unidrv plug-ins. Use IPrintOemUni::TTDownloadMethod.

DWORD APIENTRY
  OEMTTDownloadMethod(
    PDEVOBJ  pdevobj,
    PUNIFONTOBJ  pUFObj
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMTTYGetInfo

This function is obsolete for Windows XP and later. It is supported only for legacy Unidrv plug-ins. Use IPrintOemUni::TTYGetInfo.

INT APIENTRY
  OEMTTYGetInfo(
    PDEVOBJ  pdevobj,
    DWORD  dwInfoIndex,
    PVOID  pOutputBuf,
    DWORD  dwSize,
    DWORD  *pcbcNeeded
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMUpdateExternalFonts

This function is obsolete for Windows XP and later. It is supported only for legacy plug-ins. Use IPrintOemUI::UpdateExternalFonts instead.

BOOL CALLBACK
  OEMUpdateExternalFonts(
    HANDLE  hPrinter,
    HANDLE  hHeap,
    PWSTR  pwstrCartridges
   );

Headers

Declared in printoem.h. Include printoem.h.


OEMUpgradePrinter

This function is obsolete for Windows XP and later. It is supported only for legacy plug-ins. Use IPrintOemUI::UpgradePrinter instead.

BOOL APIENTRY
  OEMUpgradePrinter(
    DWORD  dwLevel,
    PBYTE  pDriverUpgradeInfo
    );

Headers

Declared in printoem.h. Include printoem.h.


OEMUpgradeRegistry

This function is obsolete for Windows XP and later. It is supported only for legacy plug-ins.

BOOL APIENTRY
  OEMUpgradeRegistry(
    DWORD dwLevel,
    PBYTE  pDriverUpgradeInfo,
    PFN_DrvUpgradeRegistrySetting  pfnUpgrade
    );

Headers

Declared in printoem.h. Include printoem.h.

See Also

DrvUpgradeRegistrySetting


Point and Print DLL Functions and Structures

This section describes the functions and structures that support Windows® 2000 and later Point and Print technology.

Point and Print DLL Functions

Point and Print DLL Structures


Point and Print DLL Functions

This section describes the functions exported by Point and Print DLLs. Function prototypes are provided in winsplp.h.


GenerateCopyFilePaths

A Point and Print DLL's GenerateCopyFilePaths function is used for modifying the source and destination paths used by print spoolers when they copy print queue-associated files to a print client.

DWORD WINAPI
  GenerateCopyFilePaths(
    IN LPCWSTR  pszPrinterName,
    IN LPCWSTR  pszDirectory,
    IN LPBYTE  pSplClientInfo,
    IN DWORD  dwLevel,
    IN OUT LPWSTR  pszSourceDir,
    IN OUT LPDWORD  pcchSourceDirSize,
    IN OUT LPWSTR  pszTargetDir,
    IN OUT LPDWORD  pcchTargetDirSize,
    IN DWORD  dwFlags
    );

Parameters

pszPrinterName
Caller-supplied pointer to a string representing the name of the print queue.
pszDirectory
Caller-supplied pointer to a string representing the value supplied for the server's Directory entry in the registry. For more information, see Supporting Point and Print During Printer Installations.
pSplClientInfo
Caller-supplied pointer to an SPLCLIENT_INFO_1 structure.
dwLevel
Caller-supplied value indicating the level number of the structure pointed to by pSplClientInfo. Must be 1.
pszSourceDir
For input, receives a caller-supplied pointer to a string representing the complete server directory path (including server name) from which files are to be copied.

For output, the function can modify this string.

pcchSourceDirSize
Caller-supplied address containing the length of the buffer pointed to by pszSourceDir. (Note that this is the buffer length, not the string length.)
pszTargetDir
For input, receives a caller-supplied pointer to a string representing the client directory path to which files are to be copied. The following rules apply:
  • When the function is called on the server, this path is relative to PRINT$.
  • When the function is called on the client, the string contains a complete path.

For output, the function can modify this string.

pcchTargetDirSize
Caller-supplied address containing the length of the buffer pointed to by pszTargetDir. (Note that this is the buffer length, not the string length.)
dwFlags
Caller-supplied flag. Can be one of the following:
COPYFILE_FLAG_CLIENT_SPOOLER
Indicates the function is being called by the client's spooler.
COPYFILE_FLAG_SERVER_SPOOLER
Indicates the function is being called by the server's spooler.

Return Value

If the operation succeeds, the function should return ERROR_SUCCESS. Otherwise, it should return an error code defined in winerror.h.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

All Point and Print DLLs must export a GenerateCopyFilePaths function, which is called by the print spooler. Its purpose is to allow a Point and Print DLL to modify the source or destination directory path, or both, before the print spooler copies print queue-associated files from a server to a client. (The files are copied when a client connects to a print server. For a complete description of the steps involved in creating a Point and Print connection, see Supporting Point and Print.)

A Point and Print DLL executes on both the server and the client. The GenerateCopyFilePaths function should check the dwFlags argument to determine where it is executing.

Typically, this function is used to provide compatibility when different versions of the operating system are executing on the client and server. For example if the function, when executing on the server, determines (by reading the SPLCLIENT_INFO_1 structure) that its OS is newer than the client's, it can modify the source and destination paths to be compatible with the client's older OS. On the other hand, if the function determines that the client's OS is newer than the client's, it should probably do nothing on the server and perform modifications, if necessary, when executing on the client.

Arguments for the pszSourceDir and pszTargetDir parameters point to buffers containing strings that represent the current source and destination directory paths. If modifications to either of these strings is necessary, the function should make modifications in the supplied buffers. The maximum allowable string lengths are pointed to by the pcchSourceDirSize and pcchTargetDirSize arguments.

If no modifications to the source or destination directories are needed, the function should just return ERROR_SUCCESS.

See Also

SpoolerCopyFileEvent


SpoolerCopyFileEvent

A Point and Print DLL's SpoolerCopyFileEvent function receives notifications of events associated with copying print queue-associated files to a print client, when the client connects to a print server.

BOOL WINAPI
  SpoolerCopyFileEvent(
    LPWSTR  pszPrinterName,
    LPWSTR  pszKey,
    DWORD  dwCopyFileEvent
    );

Parameters

pszPrinterName
Caller-supplied pointer to a string representing the printer name.
pszKey
Caller-supplied pointer to a string representing a subkey under the printer's CopyFiles registry key. This subkey identifies the component to which the Point and Print DLL belongs.
dwCopyFileEvent
Caller-supplied flag that identifies the event being reported. Valid flag values are contained in the following table.
Flag | When Received | Where Received
COPYFILE_EVENT_ADD_PRINTER_CONNECTION
After a client application has called AddPrinterConnection. | Client copy of SpoolerCopyFileEvent. The calling context is the client application.
COPYFILE_EVENT_DELETE_PRINTER
After a call to DeletePrinter has been made. | Client copy of SpoolerCopyFileEvent. The calling context is the client's spooler.
COPYFILE_EVENT_DELETE_PRINTER_CONNECTION
After a client application has called DeletePrinterConnection. | Client copy of SpoolerCopyFileEvent. The calling context is the client application.
COPYFILE_EVENT_FILES_CHANGED
After the client has downloaded the files specified under the pszKey subkey of the printer's CopyFiles registry key. | Client copy of SpoolerCopyFileEvent. The calling context is the client's spooler.
COPYFILE_EVENT_SET_PRINTER_DATAEX
After a call to SetPrinterDataEx has been processed on the server. | Server copy of SpoolerCopyFileEvent. The calling context is the client application, by impersonation.

Return Value

If the function encounters errors, the function should return FALSE. Otherwise, it should return TRUE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

All Point and Print DLLs must export a SpoolerCopyFileEvent function, which is called by the print spooler. Its purpose is to allow a Point and Print DLL to be notified of events related to the downloading of print queue-associated files, from a print server to a client system, when an application on the client connects to the server. For a complete description of the steps involved in creating a Point and Print connection, see Supporting Point and Print.

A Point and Print DLL executes on both the server and the client. The SpoolerCopyFileEvent function can determine where it is executing by reading the contents of dwCopyFileEvent, which supplies a flag indicating the event. The function should process the event and return. If no processing is necessary, the function should just return TRUE.

If dwCopyFileEvent is COPYFILE_EVENT_ADD_PRINTER_CONNECTION or COPYFILE_EVENT_ADD_PRINTER_CONNECTION, the string supplied by pszPrinterName includes the server name.

See Also

GenerateCopyFilePaths


Point and Print DLL Structures

This section describes the structures exported by Point and Print DLLs. Structure definitions are provided in winsplp.h.


SPLCLIENT_INFO_1

The SPLCLIENT_INFO_1 structure is used as input to the GenerateCopyFilePaths function that is exported by Point and Print DLLs.

typedef struct _SPLCLIENT_INFO_1{
  DWORD  dwSize;
  LPWSTR  pMachineName;
  LPWSTR  pUserName;
  DWORD  dwBuildNum;
  DWORD  dwMajorVersion;
  DWORD  dwMinorVersion;
  WORD  wProcessorArchitecture;
} SPLCLIENT_INFO_1, *PSPLCLIENT_INFO_1, *LPSPLCLIENT_INFO_1;

Members

dwSize
Size of the SPLCLIENT_INFO_1 structure.
pMachineName
Not used.
pUserName
Not used.
dwBuildNum
The build number of the version of the NT-based operating system running on the client, as returned by the Platform SDK GetVersionEx function.
dwMajorVersion
The major version number of the NT-based operating system print spooler running on the client.
dwMinorVersion
The minor version number of the NT-based operating system print spooler running on the client.
wProcessorArchitecture
The client's processor architecture, as returned by the Platform SDK GetSystemInfo function.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

Values for all structure members are supplied by the print spooler before the spooler calls GenerateCopyFilePaths.


GDI Functions for Print Processors

This section describes the functions that a print processor can call when processing EMF-formatted spool files.

Function prototypes are defined in winppi.h, a header file shipped with the DDK.


GdiDeleteSpoolFileHandle

The GdiDeleteSpoolFileHandle function releases a spool file handle.

BOOL WINAPI
  GdiDeleteSpoolFileHandle(
    HANDLE  SpoolFileHandle
    );

Parameters

SpoolFileHandle
Caller-supplied spool file handle, obtained by a previous call to GdiGetSpoolFilehandle.

Return Value

If the operation succeeds, the function returns TRUE. Otherwise the function returns FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

The GdiDeleteSpoolFileHandle function is exported by gdi32.dll for use within a print processor's PrintDocumentOnPrintProcessor function.

Print processors should call GdiDeleteSpoolFileHandle after calling GdiEndDocEMF, when processing a print job's EMF data stream has been completed. The function calls ClosePrinter (described in the Platform SDK documentation) to close the printer connection.

For additional information, see Using GDI Functions for Print Processors.

See Also

GdiGetSpoolFilehandle


GdiEndDocEMF

The GdiEndDocEMF function ends EMF playback operations for an EMF-formatted print job.

BOOL WINAPI
  GdiEndDocEMF(
    HANDLE  SpoolFileHandle
    );

Parameters

SpoolFileHandle
Caller-supplied spool file handle, obtained by a previous call to GdiGetSpoolFilehandle.

Return Value

If the operation succeeds, the function returns TRUE. Otherwise the function returns FALSE, and an error code can be obtained by calling GetLastError.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

The GdiEndDocEMF function is exported by gdi32.dll for use within a print processor's PrintDocumentOnPrintProcessor function.

The function performs operations that must be performed after a print job's EMF records have been played. The function calls the spooler's EndDoc function (described in the Platform SDK documentation), which in turn calls the printer driver's DrvEndDoc function.

For additional information, see Using GDI Functions for Print Processors.

See Also

GdiStartDocEMF


GdiEndPageEMF

The GdiEndPageEMF function ends EMF playback operations for a physical page of an EMF-formatted print job.

BOOL WINAPI
  GdiEndPageEMF(
    HANDLE  SpoolFileHandle,
    DWORD  dwOptimization
    );

Parameters

SpoolFileHandle
Caller-supplied spool file handle, obtained by a previous call to GdiGetSpoolFilehandle.
dwOptimization
Caller-supplied flags. The following flag is defined:
Flag Definition
EMF_PP_COLOR_OPTIMIZATION
Enables world transformations, beginning with the next physical page. See the following Comments section.

Return Value

If the operation succeeds, the function returns TRUE. Otherwise the function returns FALSE, and an error code can be obtained by calling GetLastError.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

The GdiEndPageEMF function is exported by gdi32.dll for use within a print processor's PrintDocumentOnPrintProcessor function.

The GdiEndPageEMF function ends the processing of a physical page and causes it to be ejected from the printer. A print processor should call GdiEndPageEMF at the following times:

  • After the appropriate number of document pages have been placed on the physical page by making calls to GdiPlayPageEMF.
  • Whenever a call to GdiGetDevmodeForPage indicates a document page's DEVMODE structure is different from the previous page's DEVMODE structure.

If the caller sets dwOptimization to EMF_PP_COLOR_OPTIMIZATION, the GdiEndPageEMF function calls SetGraphicsMode with the GM_ADVANCED flag set, which enables world transformations. (The SetGraphicsMode function and world transformations are described in the Platform SDK documentation.)

If the caller sets dwOptimization to 0, then no color optimization is performed.

For additional information, see Using GDI Functions for Print Processors.

See Also

GdiStartPageEMF


GdiGetDC

The GdiGetDC function returns a handle to a printer's device context.

HDC WINAPI
  GdiGetDC(
    HANDLE  SpoolFileHandle
    );

Parameters

SpoolFileHandle
Caller-supplied spool file handle, obtained by a previous call to GdiGetSpoolFilehandle.

Return Value

If the operation succeeds, the function returns a device context handle. Otherwise the function returns NULL.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

The GdiGetDC function is exported by gdi32.dll for use within a print processor's PrintDocumentOnPrintProcessor function.

A print processor can call GdiGetDC to obtain a printer's device context handle anytime after calling GdiGetSpoolFileHandle. The print processor can use the context handle to call Win32® device context functions, in order to perform such operations as applying transformations on the print image.

For additional information, see Using GDI Functions for Print Processors.


GdiGetDevmodeForPage

The GdiGetDevmodeForPage function returns DEVMODE structures for the specified and previous pages of a print job.

BOOL WINAPI
  GdiGetDevmodeForPage(
    HANDLE  SpoolFileHandle,
    DWORD  dwPageNumber,
    PDEVMODEW  *pCurrDM,
    PDEVMODEW  *pLastDM
    );

Parameters

SpoolFileHandle
Caller-supplied spool file handle, obtained by a previous call to GdiGetSpoolFilehandle.
dwPageNumber
Caller-supplied number of the page for which DEVMODE contents are to be returned.
pCurrDM
Caller-supplied location to receive a pointer to a DEVMODE structure for the page specified by dwPageNumber.
pLastDM
Caller-supplied location to receive a pointer to a DEVMODE structure for the page previous to the one specified by dwPageNumber.

Return Value

If the operation succeeds, the function returns TRUE. Otherwise it returns FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

The GdiGetDevmodeForPage function is exported by gdi32.dll for use within a print processor's PrintDocumentOnPrintProcessor function.

Before calling GdiPlayPageEMF to execute a page's EMF instructions, a print processor must call GdiGetDevmodeForPage to determine if the DEVMODE structure associated with the page to be printed is the same as that of the last page printed. If the two returned DEVMODE structures are not identical, the print processor must perform the following steps, in order, before calling GdiPlayPageEMF for the page:

  1. Call GdiEndPageEMF.
  2. Call GdiResetDCEMF, specifying the DEVMODE pointed to by pCurrDM.
  3. Call GdiStartPageEMF.

For additional information, see Using GDI Functions for Print Processors.


GdiGetPageHandle

The GdiGetPageHandle function returns a handle to the specified page within a print job.

HANDLE WINAPI
  GdiGetPageHandle(
    HANDLE  SpoolFileHandle,
    DWORD  Page,
    LPDWORD  pdwPageType
    );

Parameters

SpoolFileHandle
Caller-supplied spool file handle, obtained by a previous call to GdiGetSpoolFilehandle.
Page
Caller-supplied page number.
pdwPageType
Caller-supplied pointer to a location that receives the page type. The possible page types are shown in the following table:
Page Type | Meaning
EMF_PP_FORM | The page is a form or has a watermark. (Not currently supported.)
EMF_PP_NORMAL | The page is a normal page.

Return Value

If the operation succeeds, the function returns TRUE. Otherwise the function returns FALSE, and an error code can be obtained by calling GetLastError.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

The GdiGetPageHandle function is exported by gdi32.dll for use within a print processor's PrintDocumentOnPrintProcessor function.

Print processors must obtain a page handle before calling GdiPlayPageEMF to draw a page. If a Page value is specified that is too large, the function returns ERROR_NO_MORE_ITEMS.

For additional information, see Using GDI Functions for Print Processors.


GdiGetSpoolFileHandle

The GdiGetSpoolFileHandle function returns a handle to a print job's EMF file.

HANDLE WINAPI
  GdiGetSpoolFileHandle(
    LPWSTR  pwszPrinterName,
    LPDEVMODEW  pDevmode,
    LPWSTR  pwszDocName
    );

Parameters

pwszPrinterName
Caller-supplied pointer to a string representing the name of the target printer. See the following Comments section.
pDevmode
Caller-supplied pointer to a DEVMODE structure. See the following Comments section.
pwszDocName
Caller-supplied pointer to the print job's document name. See the following Comments section.

Return Value

If the operation succeeds, the function returns a spool file handle. Otherwise the function returns NULL.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

The GdiGetSpoolFileHandle function is exported by gdi32.dll for use within a print processor's PrintDocumentOnPrintProcessor function.

When a print processor calls GdiGetSpoolFileHandle, it should supply arguments as illustrated in the following table.

Parameter | Argument
pwszPrinterName | Pointer to the printer name received by the print processor's OpenPrintProcessor function.
pDevmode | Pointer to the DEVMODE structure contained in the PRINTPROCESSOROPENDATA structure, received by the print processor's OpenPrintProcessor function.
pwszDocName | Document name pointer received by the print processor's PrintDocumentOnPrintProcessor function.

A print processor must call the GdiGetSpoolFileHandle function before calling any other GDI printing functions, because the returned handle must be passed to the other functions. The function calls OpenPrinter to open a connection to the printer, and CreateDC to create a device context for drawing. The print processor can obtain the device context's handle by calling GdiGetDC.

For additional information, see Using GDI Functions for Print Processors.

See Also

GdiDeleteSpoolFileHandle


GdiPlayPageEMF

The GdiPlayPageEMF function plays the EMF records within a specified rectangle for one document page of a spooled print job.

BOOL WINAPI
  GdiPlayPageEMF(
    HANDLE  SpoolFileHandle,
    HANDLE  hemf,
    RECT  *prectDocument,
    RECT  *prectBorder,
    RECT  *prectClip
    );

Parameters

SpoolFileHandle
Caller-supplied spool file handle, obtained by a previous call to GdiGetSpoolFilehandle.
hemf
Caller-supplied page handle, obtained by calling GdiGetPageHandle, identifying the page for which records are to be played.
prectDocument
Caller-supplied pointer to a RECT structure (described in the Platform SDK documentation) specifying the rectangle into which the page is to be drawn.
prectBorder
Caller-supplied pointer to a RECT structure (described in the Platform SDK documentation) specifying the page's border rectangle (if any). Can be NULL.
prectClip
Caller-supplied pointer to a RECT structure (described in the Platform SDK documentation) specifying the coordinates of the page's clip region (if any). Can be NULL.

Return Value

If the operation succeeds, the function returns TRUE. Otherwise the function returns FALSE, and an error code can be obtained by calling GetLastError.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

The GdiPlayPageEMF function is exported by gdi32.dll for use within a print processor's PrintDocumentOnPrintProcessor function.

The GdiPlayPageEMF function is the means by which a print processor positions a document page or a specified rectangular region of a document page on a physical page. The print processor uses prectClip to describe the rectangular region to be printed, and prectDocument to describe a rectangle into which the document page (or clipped region) must fit. If prectClip is NULL, the entire document page will be printed. For non-NULL values of prectClip, only the portion of the document page within the clip region will be printed. The GdiPlayPageEMF function then performs the scaling and translation operations required to make the document page (or selected portion) fit into the rectangle.

The prectBorder parameter, if it is non-NULL, describes a solid-line border rectangle to be drawn around the document page. If prectBorder is NULL, no such border will be drawn.

For additional information, see Using GDI Functions for Print Processors.


GdiResetDCEMF

The GdiResetDCEMF function resets a printer's device context during playback of a spooled EMF print job.

BOOL WINAPI
  GdiResetDCEMF(
    HANDLE  SpoolFileHandle,
    PDEVMODEW  pCurrDM
    );

Parameters

SpoolFileHandle
Caller-supplied spool file handle, obtained by a previous call to GdiGetSpoolFilehandle.
pCurrDM
Caller-supplied pointer to a DEVMODE structure, obtained by a previous call to GdiGetDevmodeForPage.

Return Value

If the operation succeeds, the function returns TRUE. Otherwise the function returns FALSE.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

The GdiResetDCEMF function is exported by gdi32.dll for use within a print processor's PrintDocumentOnPrintProcessor function.

Print processors must call GdiResetDCEMF whenever it is necessary to reset the printer's device context. The function must be called whenever the GdiGetDevmodeForPage function indicates that the current document page's DEVMODE structure is not identical to that of the previous document page.

For additional information, see Using GDI Functions for Print Processors.


GdiStartDocEMF

The GdiStartDocEMF function performs initialization operations for an EMF-formatted print job.

BOOL WINAPI
  GdiStartDocEMF(
    HANDLE  SpoolFileHandle,
    DOCINFOW  *pDocInfo
    );

Parameters

SpoolFileHandle
Caller-supplied spool file handle, obtained by a previous call to GdiGetSpoolFilehandle.
pDocInfo
Caller-supplied pointer to a DOCINFOW structure (described in the Platform SDK documentation).

Return Value

If the operation succeeds, the function returns TRUE. Otherwise the function returns FALSE, and an error code can be obtained by calling GetLastError.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

The GdiStartDocEMF function is exported by gdi32.dll for use within a print processor's PrintDocumentOnPrintProcessor function.

The function performs initializations that must take place before a print job's EMF records can be played. The function calls the spooler's StartDoc function (described in the Platform SDK documentation), which in turn calls the printer driver's DrvStartDoc function.

The print processor must set the lpszOutput member of the DOCINFOW structure to the output file name contained in the PRINTPROCESSOROPENDATA structure, previously received by the OpenPrintProcessor function.

The print processor must set the lpszDocName member of the DOCINFOW structure to the document name pointer, previously received by the PrintDocumentOnPrintProcessor function.

For additional information, see Using GDI Functions for Print Processors.

See Also

GdiEndDocEMF


GdiStartPageEMF

The GdiStartPageEMF function performs initialization operations for a physical page of an EMF-formatted print job.

BOOL WINAPI
  GdiStartPageEMF(
    HANDLE  SpoolFileHandle
    );

Parameters

SpoolFileHandle
Caller-supplied spool file handle, obtained by a previous call to GdiGetSpoolFilehandle.

Return Value

If the operation succeeds, the function returns TRUE. Otherwise the function returns FALSE, and an error code can be obtained by calling GetLastError.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

The GdiStartPageEMF function is exported by gdi32.dll for use within a print processor's PrintDocumentOnPrintProcessor function.

A print processor must call the GdiStartPageEMF function each time a new physical page is to be created. It can then call GdiPlayPageEMF for each document page that is to be placed on the physical page.

For additional information, see Using GDI Functions for Print Processors.

See Also

GdiEndPageEMF


CPSUI Functions and Structures

This section describes the functions, function types, and structures used by CPSUI. The following sections are provided:

CPSUI Functions

CPSUI Callback Function Types

CPSUI Structures


CPSUI Functions

This section describes functions provided by CPSUI. Function prototypes are contained in compstui.h.


CommonPropertySheetUI

CPSUI's CommonPropertySheetUI function displays property sheet pages and allows user modifications to displayed values.

LONG
  CommonPropertySheetUI(
    HWND  hWndOwner,
    PFNPROPSHEETUI  pfnPropSheetUI,
    LPARAM  lParam,
    LPDWORD  pResult
    );

Parameters

hWndOwner
Caller-supplied window handle identifying the window into which new property sheet pages are to be placed.
pfnPropSheetUI
Caller-supplied pointer to a PFNPROPSHEETUI-typed callback function.
lParam
Caller-supplied value that is used as an input argument to the pfnPropSheetUI function. This value can be a pointer.
pResult
Caller-supplied pointer to a DWORD that receives the pfnPropSheetUI function's final return status. If NULL, the final return status is not returned. For more information, see the following Comments section.

Return Value

The CommonPropertySheetUI function returns one of the following values:

Return Value | Description
CPSUI_CANCEL | The pfnPropSheetUI function returned a negative value.
CPSUI_OK | The operation succeeded.
CPSUI_REBOOTSYSTEM | The operation succeeded, and a dialog box procedure sent the PSM_REBOOTSYSTEM message (defined in the Platform SDK documentation).
CPSUI_RESTARTWINDOWS | The operation succeeded, and a dialog box procedure sent the PSM_RESTARTWINDOWS message (defined in the Platform SDK documentation).
ERR_CPSUI-prefixed error code | A failure occurred. The ERR_CPSUI-prefixed error codes are defined in compstui.h.

Headers

Declared in compstui.h. Include compstui.h.

Comments

The CommonPropertySheetUI function is CPSUI's entry point for applications. A CPSUI application (such as the Microsoft® NT-based operating system print spooler) can call the function to add one or more property sheet pages to a predefined parent window. CPSUI displays the pages, allows the user to modify them, and notifies the application of user activity through callback functions.

The NT-based operating system print spooler calls the CommonPropertySheetUI function when a Win32® application calls the spooler's DocumentProperties or PrinterProperties functions, which are described in the Platform SDK documentation.

The callback function specified by the pfnPropSheetUI parameter is responsible for describing the property sheet pages to be added. For more information, see the description of the PFNPROPSHEETUI function type.

The sequence of operation is as follows:

  1. The CommonPropertySheetUI function calls the pfnPropSheetUI callback so the callback can describe the pages to be added by calling CPSUI's ComPropSheet function.
  2. If the pfnPropSheetUI callback succeeds, the CommonPropertySheetUI function displays the new property sheet pages and allows the user to modify page values.
  3. If the user modifies page values, a page event callback notifies the application of the changes.
  4. When the user chooses the OK or Cancel button, the CommonPropertySheetUI function destroys the displayed pages and returns.

For more information about the sequence of operation, see Using CPSUI with Printer Drivers, in the section entitled CPSUI.

The CommonPropertySheetUI function actually calls the pfnPropSheetUI callback several times, specifying different Reason member values in the callback's PROPSHEETUI_INFO structure. Each time the callback returns, it places a result status in the PROPSHEETUI_INFO structure's Result member. When the CommonPropertySheetUI function returns, it copies the final contents of Result into the location pointed to by pResult.


ComPropSheet

The ComPropSheet function is supplied by CPSUI and can be called by CPSUI applications (including printer interface DLLs) to build property sheet pages.

typedef LONG_PTR
  (CALLBACK *PFNCOMPROPSHEET)(
    HANDLE  hComPropSheet,
    UINT  Function,
    LPARAM  lParam1,
    LPARAM  lParam2
    );

Parameters

hComPropSheet
Caller-supplied handle to a property sheet group parent. For more information, see the following Comments section.
Function
Caller-supplied, CPSFUNC_-prefixed ComPropSheet function code specifying the operation to be performed by the ComPropSheet function.
lParam1
Caller-supplied value that depends on the ComPropSheet function code supplied for Function.
lParam2
Caller-supplied value that depends on the ComPropSheet function code supplied for Function.

Return Value

The return value depends on the ComPropSheet function code supplied for Function.

Headers

Declared in compstui.h. Include compstui.h.

Comments

When CPSUI calls one of an application's PFNPROPSHEETUI-typed functions, it passes a pointer to the ComPropSheet function in a PROPSHEETUI_INFO structure. A PFNPROPSHEETUI-typed function can call the ComPropSheet function to describe property sheet pages to CPSUI.

A printer interface DLL can call ComPropSheet from within its DrvDocumentPropertySheets function or its DrvDevicePropertySheets function.

User interface plug-ins for Microsoft's Unidrv and Pscript drivers can call ComPropSheet from within their IPrintOemUI::DocumentPropertySheets and IPrintOemUI::DevicePropertySheets methods.

The group parent handle specified for the hComPropSheet parameter can be either of the following:

  • The handle received in the hComPropSheet member of a PROPSHEETUI_INFO structure.
  • The handle received as a result of previously calling ComPropSheet with a CPSFUNC_INSERT_PSUIPAGE function code, and specifying PSUIPAGEINSERT_GROUP_PARENT as the Type member for an INSERTPSUIPAGE_INFO structure.


GetCPSUIUserData

CPSUI's GetCPSUIUserData function retrieves data that was previously stored using the SetCPSUIUserData function.

ULONG_PTR APIENTRY
  GetCPSUIUserData(
    HWND  hDlg
    );

Parameters

hDlg
Caller-supplied handle to a property sheet dialog box. For more information, see the following Comments section.

Return Value

If the operation succeeds, the function returns the value that was previously supplied to SetCPSUIUserData; otherwise the function returns zero.

Headers

Declared in compstui.h. Include compstui.h.

Comments

The GetCPSUIUserData function should only be called from within a dialog box procedure that has been associated with a dialog box by using a DLGPAGE or an EXTPUSH structure.

The handle specified for hDlg must be the handle received as input to the dialog box procedure. (Dialog box procedures are described in the Platform SDK documentation.)


SetCPSUIUserData

CPSUI's SetCPSUIUserData function allows CPSUI applications (including printer interface DLLs) to associate non-displayed data with a property sheet dialog box.

BOOL APIENTRY
  SetCPSUIUserData(
    HWND  hDlg,
    ULONG_PTR  CPSUIUserData
    );

Parameters

hDlg
Caller-supplied handle to a property sheet dialog box. For more information, see the following Comments section.
CPSUIUserData
Caller-supplied value to be stored.

Return Value

The function returns TRUE if it is successful in associating the non-displayed data with the property sheet dialog box, and FALSE otherwise.

Headers

Declared in compstui.h. Include compstui.h.

Comments

The SetCPSUIUserData function should be called only from within a dialog box procedure that has been associated with a dialog box by using a DLGPAGE or an EXTPUSH structure.

A value that is stored by calling SetCPSUIUserData can be later retrieved by calling GetCPSUIUserData.

The handle specified for hDlg must be the handle received as input to the dialog box procedure. (Dialog box procedures are described in the Platform SDK documentation.)


ComPropSheet Function Codes

The following function codes can be passed to CPSUI's ComPropSheet function:

CPSFUNC_ADD_HPROPSHEETPAGE – Adds property sheet pages described by handles.

CPSFUNC_ADD_PCOMPROPSHEETUI – Adds property sheet pages described by a COMPROPSHEETUI structure.

CPSFUNC_ADD_PFNPROPSHEETUI – Requests CPSUI to call a PFNPROPSHEETUI-typed callback.

CPSFUNC_ADD_PROPSHEETPAGE – Adds property sheet pages described by PROPSHEETPAGE structures.

CPSFUNC_DELETE_HCOMPROPSHEET – Deletes property sheet pages described by handles.

CPSFUNC_DO_APPLY_CPSUI – Simulates delivery of the PSN_APPLY notification message.

CPSFUNC_GET_HPSUIPAGES – Obtains property sheet page handles.

CPSFUNC_GET_PAGECOUNT – Obtains a count or property sheet pages.

CPSFUNC_GET_PFNPROPSHEETUI_ICON – Obtains an icon handle.

CPSFUNC_IGNORE_CPSUI_PSN_APPLY – Disables or re-enables CPSUI's handling of the PSN_APPLY notification message.

CPSFUNC_INSERT_PSUIPAGE – Inserts property sheet pages at a specified position.

CPSFUNC_LOAD_CPSUI_ICON – Loads a CPSUI-supplied icon.

CPSFUNC_LOAD_CPSUI_STRING – Loads a CPSUI-supplied text string.

CPSFUNC_QUERY_DATABLOCK – Retrieves a previously stored data block.

CPSFUNC_SET_DATABLOCK – Makes one property sheet page's information available to other pages.

CPSFUNC_SET_DMPUB_HIDEBITS – "Hides" a specified set of document property options, so they are not displayed.

CPSFUNC_SET_FUSION_CONTEXT – Sets a Fusion activation context for the specified page.

CPSFUNC_SET_HSTARTPAGE – Sets a property sheet's initial top page.

CPSFUNC_SET_PSUIPAGE_ICON – Adds, replaces, or removes a property sheet page's tab icon.

CPSFUNC_SET_PSUIPAGE_TITLE – Sets a property sheet page's tab title.

CPSFUNC_SET_RESULT – Sets a result value.


CPSFUNC_ADD_HPROPSHEETPAGE

The CPSFUNC_ADD_HPROPSHEETPAGE function code causes the ComPropSheet function to add a property sheet page that has been created by calling the CreatePropertySheetPage function (described in the Platform SDK documentation).

ComPropSheet Parameters

hComPropSheet
Group parent handle.
Function
CPSFUNC_ADD_HPROPSHEETPAGE
lParam1
Handle to a property sheet page, obtained by calling the CreatePropertySheetPage function.
lParam2
Not used, must be zero.

ComPropSheet Return Value

If the operation succeeds, ComPropSheet returns a CPSUI handle to the added page; otherwise, it returns NULL.

Headers

Declared in compstui.h. Include compstui.h.

See Also

CPSFUNC_ADD_PROPSHEETPAGE


CPSFUNC_ADD_PCOMPROPSHEETUI

The CPSFUNC_ADD_PCOMPROPSHEETUI function code causes the ComPropSheet function to add a set of one or more property sheet pages that are described by a COMPROPSHEETUI structure.

ComPropSheet Parameters

hComPropSheet
Group parent handle.
Function
CPSFUNC_ADD_PCOMPROPSHEETUI
lParam1
Pointer to a COMPROPSHEETUI structure.
lParam2
Pointer to a 32-bit location to receive the number of pages added or, if a failure occurs, an ERR_CPSUI-prefixed error code.

ComPropSheet Return Value

If the operation succeeds, ComPropSheet returns a handle to the set of added pages; otherwise, the function returns NULL.

Headers

Declared in compstui.h. Include compstui.h.


CPSFUNC_ADD_PFNPROPSHEETUI

The CPSFUNC_ADD_PFNPROPSHEETUI function code causes the ComPropSheet function to call the specified PFNPROPSHEETUI-typed function, which must add a set of one or more property sheet pages.

ComPropSheet Parameters

hComPropSheet
Group parent handle.
Function
CPSFUNC_ADD_PFNPROPSHEETUI
lParam1
Pointer to a PFNPROPSHEETUI-typed function.
lParam2
A 32-bit value that is passed to the PFNPROPSHEETUI-typed function for its lParam parameter.

ComPropSheet Return Value

If the operation succeeds, ComPropSheet returns a handle to the set of added pages; otherwise, the function returns NULL.

Headers

Declared in compstui.h. Include compstui.h.


CPSFUNC_ADD_PROPSHEETPAGE

The CPSFUNC_ADD_PROPSHEETPAGE function code causes the ComPropSheet function to add a property sheet page that is described by a PROPSHEETPAGE structure (described in the Platform SDK documentation).

The ComPropSheet function creates the page by calling the CreatePropertySheetPage function (described in the Platform SDK documentation), passing the PROPSHEETPAGE structure's address.

ComPropSheet Parameters

hComPropSheet
Group parent handle.
Function
CPSFUNC_ADD_PROPSHEETPAGE
lParam1
Pointer to a PROPSHEETPAGE structure.
lParam2
Not used, must be zero.

ComPropSheet Return Value

If the operation succeeds, ComPropSheet returns a CPSUI handle to the added page; otherwise, it returns NULL.

Headers

Declared in compstui.h. Include compstui.h.

See Also

CPSFUNC_ADD_HPROPSHEETPAGE


CPSFUNC_DELETE_HCOMPROPSHEET

The CPSFUNC_DELETE_HCOMPROPSHEET function code causes the ComPropSheet function to delete a set of property sheet pages specified by a CPSUI handle.

ComPropSheet Parameters

hComPropSheet
Group parent handle.
Function
CPSFUNC_DELETE_HCOMPROPSHEET
lParam1
CPSUI handle to the set of pages to be deleted. This handle must previously have been obtained by calling ComPropSheet with one of the following function codes:

CPSFUNC_ADD_HPROPSHEETPAGE

CPSFUNC_ADD_PCOMPROPSHEETUI

CPSFUNC_ADD_PFNPROPSHEETUI

CPSFUNC_ADD_PROPSHEETPAGE

CPSFUNC_INSERT_PSUIPAGE

lParam2
Not used, must be zero.

ComPropSheet Return Value

The ComPropSheet function returns the number of property sheet pages that were deleted.

Headers

Declared in compstui.h. Include compstui.h.


CPSFUNC_DO_APPLY_CPSUI

The CPSFUNC_DO_APPLY_CPSUI function code causes the ComPropSheet function to simulate delivery of a PSN_APPLY notification message.

hComPropSheet
Group parent handle.
Function
CPSFUNC_DO_APPLY_CPSUI
lParam1
CPSUI handle to a set of one or more property sheet pages. Typically, this handle has been previously specified as the lParam1 parameter to ComPropSheet using the CPSFUNC_IGNORE_CPSUI_PSN_APPLY function code.
lParam2
Any combination of the following bit flags:
Flag Definition
APPLYCPSUI_NO_NEWDEF
Set this flag if you do not want the current default values (used for the Undo operation) to be changed.

Clear this flag if you want the current values for all options to become the defaults used for the Undo operation.
APPLYCPSUI_OK_CANCEL_BUTTON
Set this flag if the user selected the OK or Cancel button (or if you want to simulate this activity).

Clear this flag if the user selected the Close or Apply Now button (or if you want to simulate this activity).

If your code is set up to receive PSN_APPLY messages, the code should check the lParam member of the PSHNOTIFY structure. If the member is zero, this bit should be cleared. (The PSN_APPLY message and PSHNOTIFY structure are described in the Platform SDK documentation.)

ComPropSheet Return Value

If the operation succeeds, the ComPropSheet function returns a nonzero value; otherwise it returns zero and the specified pages will become active.

If you use the CPSFUNC_IGNORE_CPSUI_PSN_APPLY function code to disable CPSUI's handling of the PSN_APPLY notification message, you must use the CPSFUNC_DO_APPLY_CPSUI function code to simulate delivery of the PSN_APPLY message. Otherwise, user changes to a property sheet page cannot be obtained.

Headers

Declared in compstui.h. Include compstui.h.

Comments

CPSUI responds to the CPSFUNC_DO_APPLY_CPSUI function code by delivering the CPSUICB_REASON_APPLYNOW reason to an application's _CPSUICALLBACK-typed callback function.


CPSFUNC_GET_HPSUIPAGES

The CPSFUNC_GET_HPSUIPAGES function code causes the ComPropSheet function to return an array of CPSUI handles to property sheet pages. These handles identify the child pages associated with the specified group parent handle.

ComPropSheet Parameters

hComPropSheet
Group parent handle.
Function
CPSFUNC_GET_HPSUIPAGES
lParam1
Pointer to an array of HANDLE structures.
lParam2
Size of the HANDLE array pointed to by lParam1.

ComPropSheet Return Value

The ComPropSheet function returns the number of handles that CPSUI places into the HANDLE array.

Headers

Declared in compstui.h. Include compstui.h.

Comments

To use this function code, follow these steps:

  1. Call ComPropSheet, specifying the CPSFUNC_GET_PAGECOUNT function code, to obtain the number of child pages associated with the specified group parent.
  2. Allocate enough local memory to contain a HANDLE structure for each page.
  3. Call ComPropSheet again, specifying the CPSFUNC_GET_HPSUIPAGES function code and the address of the locally allocated memory, to obtain an array of HANDLE structures.


CPSFUNC_GET_PAGECOUNT

The CPSFUNC_GET_PAGECOUNT function code causes the ComPropSheet function to return the number of property sheet pages that are child pages of the specified group parent handle.

ComPropSheet Parameters

hComPropSheet
Group parent handle.
Function
CPSFUNC_GET_PAGECOUNT
lParam1
Not used, must be zero.
lParam2
Not used, must be zero.

ComPropSheet Return Value

The ComPropSheet function returns the number of pages counted.

Headers

Declared in compstui.h. Include compstui.h.


CPSFUNC_GET_PFNPROPSHEETUI_ICON

The CPSFUNC_GET_PFNPROPSHEETUI_ICON function code causes the ComPropSheet function to return a handle to the icon that is associated with a set of property sheet pages. The set of pages must have been previously created by a PFNPROPSHEETUI-typed function.

ComPropSheet Parameters

hComPropSheet
Group parent handle.
Function
CPSFUNC_GET_PFNPROPSHEETUI_ICON
lParam1
CPSUI handle to a set of property sheet pages. This handle must have been obtained by calling ComPropSheet with a function code of CPSFUNC_ADD_PFNPROPSHEETUI.
lParam2
Specifies two WORD-sized values representing the icon's size, in pixels. The LOWORD value is the width, and the HIWORD value is the height. If these values are zero, the system metrics SM_CXICON and SM_CYICON are used. (See GetSystemMetrics in the Platform SDK documentation.)

ComPropSheet Return Value

If the operation succeeds, the ComPropSheet function returns an icon handle; otherwise it returns NULL.

Headers

Declared in compstui.h. Include compstui.h.

Comments

The ComPropSheet function calls the PFNPROPSHEETUI-typed function associated with the specified page handle, passing a reason value of PROPSHEETUI_REASON_GET_ICON. That function is responsible for calling LoadImage (described in the Platform SDK documentation) to load an icon resource, using the size specified by lParam2, and returning a handle.


CPSFUNC_IGNORE_CPSUI_PSN_APPLY

The CPSFUNC_IGNORE_CPSUI_PSN_APPLY function code causes the ComPropSheet function to disable or re-enable CPSUI's handling of the PSN_APPLY notification message (described in the Platform SDK documentation).

ComPropSheet Parameters

hComPropSheet
Group parent handle.
Function
CPSFUNC_IGNORE_CPSUI_PSN_APPLY
lParam1
CPSUI handle to a set of one or more property sheet pages. This handle must have been obtained by calling ComPropSheet with a function code of CPSFUNC_ADD_PCOMPROPSHEETUI, or with a function code of CPSFUNC_INSERT_PSUIPAGE and an insertion type of PSUIPAGEINSERT_PROPSHEETPAGE.
lParam2
Any nonzero value disables CPSUI's delivery of the CPSUICB_REASON_APPLYNOW reason. A zero value re-enables delivery of the CPSUICB_REASON_APPLYNOW reason.

ComPropSheet Return Value

If the operation succeeds, the ComPropSheet function returns a nonzero value; otherwise it returns zero.

Headers

Declared in compstui.h. Include compstui.h.

Comments

The system sends the PSN_APPLY notification message to CPSUI when a user selects a property sheet's OK or Cancel button. CPSUI responds to this message by delivering the CPSUICB_REASON_APPLYNOW reason to an application's _CPSUICALLBACK-typed callback function.

If you disable CPSUI's handling of the PSN_APPLY notification message, you must use the CPSFUNC_DO_APPLY_CPSUI function code to simulate delivery of the PSN_APPLY message. Otherwise, user changes to a property sheet page cannot be obtained.

If the CPSFUNC_IGNORE_CPSUI_PSN_APPLY function code is not used, CPSUI's handling of the PSN_APPLY notification message is enabled by default.


CPSFUNC_INSERT_PSUIPAGE

The CPSFUNC_INSERT_PSUIPAGE function code causes the ComPropSheet function to insert a set of property sheet pages at a specific position.

ComPropSheet Parameters

hComPropSheet
Group parent handle.
Function
CPSFUNC_INSERT_PSUIPAGE
lParam1
Specifies a handle to a set of one or more pages. The new pages will be inserted before or after these pages, depending on the Mode member of the INSERTPSUIPAGE_INFO structure pointed to by lParam2. This handle must previously have been obtained by calling ComPropSheet with one of the following function codes:

CPSFUNC_ADD_HPROPSHEETPAGE

CPSFUNC_ADD_PCOMPROPSHEETUI

CPSFUNC_ADD_PFNPROPSHEETUI

CPSFUNC_ADD_PROPSHEETPAGE

CPSFUNC_INSERT_PSUIPAGE

lParam2
Pointer to an INSERTPSUIPAGE_INFO structure, describing where and how the new pages should be inserted.

ComPropSheet Return Value

If the operation succeeds, ComPropSheet returns a handle to the set of added pages; otherwise, the function returns NULL.

Headers

Declared in compstui.h. Include compstui.h.

Comments

Using the CPSFUNC_INSERT_PSUIPAGE function code is the most complex method for adding property sheet pages, but it provides the most functionality.


CPSFUNC_LOAD_CPSUI_ICON

The CPSFUNC_LOAD_CPSUI_ICON function code causes the ComPropSheet function to load a CPSUI-supplied icon resource.

ComPropSheet Parameters

hComPropSheet
Group parent handle.
Function
CPSFUNC_LOAD_CPSUI_ICON
lParam1
Resource identifier of the CPSUI-supplied icon to be loaded. This must be an IDI_CPSUI-prefixed identifier contained in compstui.h.
lParam2
Specifies two WORD-sized values representing the icon's size, in pixels. The LOWORD value is the width, and the HIWORD value is the height. If these values are zero, the system metrics SM_CXICON and SM_CYICON are used. (See GetSystemMetrics in the Platform SDK documentation.)

ComPropSheet Return Value

If the operation succeeds, the ComPropSheet function returns an icon handle; otherwise it returns NULL.

Headers

Declared in compstui.h. Include compstui.h.

Comments

CPSUI calls LoadImage (described in the Platform SDK documentation) to load the specified icon resource.


CPSFUNC_LOAD_CPSUI_STRING

The CPSFUNC_LOAD_CPSUI_STRING function code causes the ComPropSheet function to load a CPSUI-supplied string resource.

ComPropSheet Parameters

hComPropSheet
Group parent handle.
Function
CPSFUNC_LOAD_CPSUI_STRING
lParam1
An LPSTR-typed pointer to a caller-allocated buffer, into which the CPSUI-supplied string specified by HIWORD(lParam2) will be placed.
lParam2
Contains the following two caller-supplied values:
LOWORD(lParam2) | Size, in bytes, of the buffer pointed to by lParam1.
HIWORD(lParam2) | Resource identifier of the CPSUI-supplied string to be loaded. This must be an IDS_CPSUI-prefixed identifier contained in compstui.h.

ComPropSheet Return Value

If the operation succeeds, the ComPropSheet function returns the length of the string. If an invalid resource identifier is specified, the function returns zero. If lParam1 is NULL or LOWORD(lParam2) is zero, the function returns -1.

Headers

Declared in compstui.h. Include compstui.h.

Comments

The ComPropSheet function calls LoadString (described in the Platform SDK documentation) to load the specified string.


CPSFUNC_QUERY_DATABLOCK

The CPSFUNC_QUERY_DATABLOCK function code causes the ComPropSheet function to retrieve a caller-supplied data block that was previously stored using the CPSFUNC_SET_DATABLOCK function code.

ComPropSheet Parameters

hComPropSheet
Group parent handle.
Function
CPSFUNC_QUERY_DATABLOCK
lParam1
Pointer to a CPSUIDATABLOCK structure, identifying the size and location of a buffer to receive the requested data block.
lParam2
DWORD-sized identifier value, used to identify the requested CPSUIDATABLOCK structure. This value must have been specified in a previous call to ComPropSheet using the CPSFUNC_SET_DATABLOCK function code.

ComPropSheet Return Value

If the operation succeeds, ComPropSheet returns a value representing the size of the retrieved data block. If lParam1 is NULL, or if any of the supplied CPSUIDATABLOCK structure's members are zero, ComPropSheet returns the size required to store the data block. If an error occurs, the function returns a value less than or equal to zero.

Headers

Declared in compstui.h. Include compstui.h.

Comments

Typically, this function code is used by a _CPSUICALLBACK-typed callback function, when the function's CPSUICBPARAM structure contains a Reason value of CPSUICB_REASON_SETACTIVE, to retrieve values associated with another page before the current page becomes inactive.


CPSFUNC_SET_DMPUB_HIDEBITS

The CPSFUNC_SET_DMPUB_HIDEBITS function code causes the ComPropSheet function to "hide" a specified set of document property options, so they are not displayed.

ComPropSheet Parameters

hComPropSheet
Group parent handle.
Function
CPSFUNC_SET_DMPUB_HIDEBITS
lParam1
Bit array indicating the options to be hidden. This array must be created using the MAKE_DMPUB_HIDEBIT(DMPub) macro, where DMPub is one or more DMPUB_-prefixed constants (ORed together). The DMPUB_-prefixed constants are listed in the description of the OPTITEM structure. The macro and constants are defined in compstui.h.
lParam2
Not used. Must be zero.

ComPropSheet Return Value

If the operation succeeds, ComPropSheet returns the value specified for lParam1; otherwise it returns zero.

Headers

Declared in compstui.h. Include compstui.h.

Comments

Use the CPSFUNC_SET_DMPUB_HIDEBITS function code if you want to define OPTITEM structures for one or more document property sheet options, but you do not want the options to be user-modifiable. The property sheet page must be defined using the COMPROPSHEETUI structure, and the structure's pDlgPage member must be CPSUI_PDLGPAGE_DOCPROP or CPSUI_PDLGPAGE_ADVDOCPROP.

If this function code is used, it must be specified to ComPropSheet before the CPSFUNC_ADD_PCOMPROPSHEETUI or CPSFUNC_INSERT_PSUIPAGE function code is used to create the page.


CPSFUNC_SET_FUSION_CONTEXT

The CPSFUNC_SET_FUSION_CONTEXT sets a Fusion activation context for the specified page.

ComPropSheet Parameters

lParam1
Specifies the handle to the Fusion context. Compstui.dll duplicates the handle attaching it to its internal structures, so the caller is not obligated to retain the handle. Compstui.dll releases the passed-in context handle when the compstui.dll handle is deleted.
lParam2
Is not used.

ComPropSheet Return Value

If the operation succeeds, ComPropSheet returns a value greater than zero. Otherwise, ComPropSheet returns a value that is less than or equal to zero. For information about the error, use GetLastError, which is described in the Platform SDK documentation.

Headers

Declared in compstui.h. Include compstui.h.

Comments

When a page is about to be created or inserted and it does not specify an activation context in its PROPSHEETPAGE structure (described in the Platform SDK documentation), it will be created in the parent's page activation context. If the parent's activation context is not set, then compstui.dll looks up the parent's parent, continuing until the top level parent is reached or until it finds a parent with an activation context properly set. If none of the parents has an activation context set, then compstui.dll will not specify an activation context in the PROPSHEETPAGE structure. This means that the page will be created in the activation context of the caller of the PropertySheet API (described in the Platform SDK documentation).


CPSFUNC_SET_HSTARTPAGE

The CPSFUNC_SET_HSTARTPAGE function code causes the ComPropSheet function to mark a specified property sheet page to be the top page of the associated property sheet. If the property sheet is currently being displayed, the specified page becomes the active page.

ComPropSheet Parameters

hComPropSheet
Group parent handle.
Function
CPSFUNC_SET_HSTARTPAGE
lParam1
Caller-supplied CPSUI page handle, previously obtained by calling ComPropSheet with one of the following function codes:

CPSFUNC_ADD_HPROPSHEETPAGE

CPSFUNC_ADD_PCOMPROPSHEETUI

CPSFUNC_ADD_PFNPROPSHEETUI

CPSFUNC_ADD_PROPSHEETPAGE

CPSFUNC_INSERT_PSUIPAGE

If the handle represents a single page belonging to the group specified by hComPropSheet, CPSUI makes this page the top page.

If the handle represents a group parent handle (see CPSFUNC_INSERT_PSUIPAGE), then lParam2 represents a zero-based index into the group's pages and the page represented by the index becomes the top page.

lParam2
If lParam1 represents a group parent handle, this caller-supplied value is a zero-based index into the group's pages.

If lParam1 represents a single page belonging to the group specified by hComPropSheet, this parameter is not used.

If the handle specified by lParam1 was obtained using the CPSFUNC_ADD_PCOMPROPSHEETUI function code, and if the pDlgPage member of the associated COMPROPSHEETUI structure was set to CPSUI_PDLGPAGE_DOCPROP, then one of the following values can be specified for lParam2:
Value | Definition
SSP_STDPAGE1 | Make the Layout page the top page.
SSP_STDPAGE2 | Make the Paper/Quality page the top page.
SSP_TVPAGE | Make the Advanced page the top page.

ComPropSheet Return Value

If the operation succeeds, ComPropSheet returns a value greater than zero; otherwise it returns a value less than or equal to zero.

Headers

Declared in compstui.h. Include compstui.h.


CPSFUNC_SET_PSUIPAGE_ICON

The CPSFUNC_SET_PSUIPAGE_ICON function code causes the ComPropSheet function to add, replace, or remove the icon assigned a property sheet page's tab.

ComPropSheet Parameters

hComPropSheet
Group parent handle.
Function
CPSFUNC_SET_PSUIPAGE_ICON
lParam1
Caller-supplied CPSUI page handle, previously obtained by calling ComPropSheet with one of the following function codes:

CPSFUNC_ADD_HPROPSHEETPAGE

CPSFUNC_ADD_PROPSHEETPAGE

CPSFUNC_INSERT_PSUIPAGE (with the INSERTPSUIPAGE_INFO structure's Type member set to PSUIPAGEINSERT_HPROPSHEETPAGE or PSUIPAGEINSERT_PROPSHEETPAGE).

lParam2
Caller-supplied icon handle, or zero to remove the current icon.

ComPropSheet Return Value

If the operation succeeds, the ComPropSheet function returns 1. If an error is encountered, or if the specified page is not currently being displayed, the function returns zero.

Headers

Declared in compstui.h. Include compstui.h.

Comments

If lParam2 contains an icon handle, and if the page specified by lParam1 is currently being displayed, CPSUI adds the icon to the specified page's tab. If an icon is already assigned to the page, the old icon is replaced with the new one. If lParam2 is zero, the current icon (if one exists) is removed.

For all icons specified with the CPSFUNC_SET_PSUIPAGE_ICON function code, CPSUI sets the image size to 16 by 16 pixels.

Icon handles should be obtained by calling LoadImage, which is described in the Platform SDK documentation.


CPSFUNC_SET_PSUIPAGE_TITLE

The CPSFUNC_SET_PSUIPAGE_TITLE function code causes the ComPropSheet function to set the tab title for a property sheet page.

ComPropSheet Parameters

hComPropSheet
Group parent handle.
Function
CPSFUNC_SET_PSUIPAGE_TITLE
lParam1
Caller-supplied CPSUI page handle, previously obtained by calling ComPropSheet with one of the following function codes:

CPSFUNC_ADD_HPROPSHEETPAGE

CPSFUNC_ADD_PROPSHEETPAGE

CPSFUNC_INSERT_PSUIPAGE (with the INSERTPSUIPAGE_INFO structure's Type member set to PSUIPAGEINSERT_HPROPSHEETPAGE or PSUIPAGEINSERT_PROPSHEETPAGE).

lParam2
Caller-supplied pointer to a NULL-terminated string that specifies the new title.

ComPropSheet Return Value

If the operation succeeds, the ComPropSheet function returns 1. If an error is encountered, or if the specified page is not currently being displayed, the function returns zero.

Headers

Declared in compstui.h. Include compstui.h.


CPSFUNC_SET_RESULT

The CPSFUNC_SET_RESULT function code causes the ComPropSheet function to pass a specified result value to all PFNPROPSHEETUI-typed functions associated with a specified page and its parents.

ComPropSheet Parameters

hComPropSheet
Group parent handle.
Function
CPSFUNC_SET_RESULT
lParam1
Caller-supplied CPSUI handle to the page for which a result value is being passed. If lParam1 is NULL, the CPSUI uses hComPropSheet.
lParam2
Caller-supplied 32-bit DWORD result value.

ComPropSheet Return Value

The ComPropSheet function returns the number of PFNPROPSHEETUI-typed functions that were called. If the handle specified for lParam1 is invalid, the function returns -1.

Headers

Declared in compstui.h. Include compstui.h.

Comments

For more information about setting result values, see the description of the SETRESULT_INFO structure.


CPSUI Callback Function Types

This section describes callback functions that must be provided by applications using CPSUI. Function prototypes are provided in compstui.h.


_CPSUICALLBACK

The _CPSUICALLBACK function type is used by CPSUI applications (including printer interface DLLs) for defining a callback function intended for use as a CPSUI message handler.

typedef LONG
  (APIENTRY *_CPSUICALLBACK)(
    PCPSUICBPARAM  pComPropSheetUICBParam
    );

Parameters

pComPropSheetUICBParam
CPSUI-supplied pointer to a CPSUICBPARAM structure.

Return Value

A _CPSUICALLBACK-typed callback function must return one of the values listed in the following table. Each value indicates an action that CPSUI should perform.

Return Value | Reason Used | Action Performed by CPSUI
CPSUICB_ACTION_ITEMS_APPLIED
 | The CPSUICBPARAM structure's Reason member was set to CPSUICB_REASON_APPLYNOW, and the callback function has successfully processed the current option values. | CPSUI saves the page's option settings.
CPSUICB_ACTION_NO_APPLY_EXIT
 | The CPSUICBPARAM structure's Reason member was set to CPSUICB_REASON_APPLYNOW, but the callback function has detected invalid or incompatible option values. The callback function must display a pop-up dialog telling the user of the problem. | CPSUI keeps the current page active so the user can modify option values.
CPSUICB_ACTION_NONE
 | No action by CPSUI is required. | None.
CPSUICB_ACTION_OPTIF_CHANGED
 | The callback function has set the OPTIF_CHANGED flag in an OPTITEM structure to indicate that the selected option has changed, or that another OPTIF-prefixed flag has changed. | CPSUI redisplays the page.
CPSUICB_ACTION_REINIT_ITEMS
 | The callback function has set the OPTIF_CHANGED flag in an OPTITEM structure to indicate that Flags or pData members of the associated OPTTYPE or OPTPARAM structure have changed. | CPSUI re-initializes and redisplays the page.

Headers

Declared in compstui.h. Include compstui.h.

Comments

Callback functions specified using the _CPSUICALLBACK function type are supplied by applications that use CPSUI to manage property sheet pages. If one of these callback functions is associated with a property sheet page, CPSUI calls it when user activity (such as changing the page's control focus, modifying option values, or clicking on OK) is detected.

A _CPSUICALLBACK-typed callback function is assigned to a property sheet page by including its address in a COMPROPSHEETUI structure, which is passed to CPSUI's ComPropSheet function when the function code is CPSFUNC_ADD_PCOMPROPSHEETUI.

Additionally, callback functions can be assigned to extended push buttons through the use of EXTPUSH structures.

When one of these callback functions is called, it receives a pointer to a CPSUICBPARAM structure. This structure describes the current option settings for the page and indicates the user event that caused the function to be called. The callback function is responsible for validating and processing the settings. It should display a pop-up dialog if a setting (or a combination of settings) is invalid. The function's return value indicates to CPSUI whether the page needs to be redisplayed or reinitialized.

Callback functions specified with this function type cannot be used if the DlgProc member of the DLGPAGE structure specifies an application-supplied dialog box procedure. This is because _CPSUICALLBACK-typed callbacks are called from CPSUI's dialog box procedures, which are not used if the application supplies its own procedures.


PFNPROPSHEETUI

The PFNPROPSHEETUI function type is used by CPSUI applications (including printer interface DLLs) for defining page creation callbacks, which specify property sheet pages for creation.

typedef LONG
  (FAR *PFNPROPSHEETUI)(
    PPROPSHEETUI_INFO  pPSUIInfo,
    LPARAM  lParam
    );

Parameters

pPSUIInfo
CPSUI-supplied pointer to a PROPSHEETUI_INFO structure.
lParam
CPSUI-supplied integer value that is dependent on the contents of the Reason member of the PROPSHEETUI_INFO structure. Valid values are as follows:
Reason Value Definition of lParam
PROPSHEETUI_REASON_DESTROY
The lParam value is nonzero if the user has selected the property sheet's OK or Cancel button. Otherwise the value is zero.
PROPSHEETUI_REASON_GET_ICON
The lParam value is a pointer to a PROPSHEETUI_GETICON_INFO structure.
PROPSHEETUI_REASON_GET_INFO_HEADER
The lParam value is a pointer to a PROPSHEETUI_INFO_HEADER structure.
PROPSHEETUI_REASON_INIT
If the callback function is specified by the pfnPropSheetUI parameter to CommonPropertySheetUI, lParam is the lParam value passed to CommonPropertySheetUI.

If the callback function is specified using the CPSFUNC_ADD_PFNPROPSHEETUI function code with CPSUI's ComPropSheet function, lParam is the lParam2 value passed to ComPropSheet.

CPSUI copies the lParam value into the lParamInit member of the function's PROPSHEETUI_INFO structure.

The lParam value must not reside on the application's stack.
PROPSHEETUI_REASON_SET_RESULT
The lParam value is a pointer to a SETRESULT_INFO structure.

Return Value

If the operation succeeds, the function should return a value of one (or greater). Otherwise it should return a value less than one.

If the PROPSHEETUI_INFO structure's Reason member is PROPSHEETUI_REASON_SET_RESULT, the return value has the following definition:

Return Value | Definition
One or greater. | The PFNPROPSHEETUI function associated with the parent of the current page will be called.
Less than 1. | The PFNPROPSHEETUI function associated with the parent of the current page will not be called.

Headers

Declared in compstui.h. Include compstui.h.

Comments

Callback functions specified using the PFNPROPSHEETUI function type are supplied by applications that use CPSUI to manage customized property sheet pages. One such callback function must be specified when an application calls the CommonPropertySheetUI function. For example, when the NT-based operating system print spooler calls CPSUI's CommonPropertySheetUI function to support its DocumentProperties or PrinterProperties API functions (described in the Platform SDK documentation), the spooler specifies an internal PFNPROPSHEETUI-typed callback function.

Applications can specify additional PFNPROPSHEETUI-typed callback functions by calling CPSUI's ComPropSheet function with a function code of CPSFUNC_ADD_PFNPROPSHEETUI. For example, the NT-based operating system print spooler does this to notify CPSUI of the existence of a printer interface DLL's DrvDocumentPropertySheets and DrvDevicePropertySheets functions. Likewise, Microsoft's Unidrv and Pscript drivers use this technique to notify CPSUI of the existence of IPrintOemUI::DocumentPropertySheets and IPrintOemUI::DevicePropertySheets methods in user interface plug-ins.

Each PFNPROPSHEETUI-typed callback function is called by CPSUI several times. The Reason member of the PROPSHEETUI_INFO structure stipulates the operation that the function should perform, as follows:

Reason Value | Operation to be Performed by Callback
PROPSHEETUI_REASON_DESTROY
 | The callback function should release resources that were allocated in response to PROPSHEETUI_REASON_INIT.
PROPSHEETUI_REASON_GET_ICON
 | The callback function should call LoadImage (described in the Platform SDK documentation) to load an icon resource, using parameters specified by the PROPSHEETUI_GETICON_INFO structure pointed to be lParam, and it should return the icon's handle in the structure.
PROPSHEETUI_REASON_GET_INFO_HEADER
 | The callback function should supply page header information in the PROPSHEETUI_INFO_HEADER structure pointed to by lParam.
PROPSHEETUI_REASON_INIT
 | The callback function should call the ComPropSheet function to specify property sheet pages. (This is always the first reason received.)
PROPSHEETUI_REASON_SET_RESULT
 | The callback function receives result information in the SETRESULT_INFO structure pointed to by lParam. This is application-supplied status information, specified by calling CPSUI's ComPropSheet function with a function code of CPSFUNC_SET_RESULT. For more information about handling this reason value, see the description of SETRESULT_INFO.


CPSUI Structures

This section describes the structures used by CPSUI. Structure definitions are contained in compstui.h.


COMPROPSHEETUI

The COMPROPSHEETUI structure is used as an input parameter to CPSUI's ComPropSheet function, if the function code is CPSFUNC_ADD_PCOMPROPSHEETUI. All structure members must be supplied by the caller of ComPropSheet.

typedef struct _COMPROPSHEETUI {
  WORD  cbSize;
  WORD  Flags;
  HINSTANCE  hInstCaller;
  LPTSTR  pCallerName;
  ULONG_PTR  UserData;
  LPTSTR  pHelpFile;
  _CPSUICALLBACK  pfnCallBack;
  POPTITEM  pOptItem;
  PDLGPAGE  pDlgPage;
  WORD  cOptItem;
  WORD  cDlgPage;
  ULONG_PTR  IconID;
  LPTSTR  pOptItemName;
  WORD  CallerVersion;
  WORD  OptItemVersion;
  ULONG_PTR  dwReserved[4];
} COMPROPSHEETUI, *PCOMPROPSHEETUI;

Members

cbSize
Caller-supplied size, in bytes, of the COMPROPSHEETUI structure.
Flags
Optional caller-supplied bit flags, as described in the following table.
Flag Definition
CPSUIF_ABOUT_CALLBACK
If set, the page's callback function (pointed to by the structure's pfnCallback member), supports CPSUICB_REASON_ABOUT, so CPSUI will call the callback function if the user clicks on the page's About button. (CPSUI supplies an About button for each treeview root node.)
CPSUIF_ICONID_AS_HICON
If set, the structure's IconID member contains an icon handle.
If not set, the IconID member contains an icon resource identifier.
CPSUIF_UPDATE_PERMISSION
If set, the page's option values can be modified by the user.

hInstCaller
Caller-supplied module instance handle, received by the DLL's entry point function.
pCallerName
Caller-supplied pointer to a NULL-terminated text string representing the application's name. (For a printer interface DLL, this should be the driver's name, such as "PostScript Driver".)
UserData
Optional caller-supplied value, which CPSUI places in a CPSUICBPARAM structure's UserData member when calling the function pointed to by pfnCallBack.
pHelpFile
Caller-supplied pointer to a NULL-terminated text string representing a path to a help file. For printer interface DLLs, this is typically the help file path obtained by calling GetPrinterDriver (described in the Platform SDK documentation).

The help file is indexed by values contained in the HelpIndex member of OPTITEM structures.

pfnCallBack
Caller-supplied pointer to a _CPSUICALLBACK-typed callback function, which CPSUI calls when a user modifies the page's option values.

Can be used only if pDlgPage identifies a CPSUI-supplied DLGPAGE structure, or if the DlgProc member of an application-supplied DLGPAGE structure is NULL.

pOptItem
Caller-supplied pointer to an array of OPTITEM structures describing the page's options.
pDlgPage
This member specifies DLGPAGE structures that describe pages to be added to the property sheet. It can be either of the following:
  • A pointer to an array of DLGPAGE structures.
  • One of the pointers listed in the following table. These pointers reference predefined DLGPAGE structures, supplied by CPSUI for use by printer interface DLLs.
Predefined Structure Description
CPSUI_PDLGPAGE_ADVDOCPROP
Defines one treeview page whose tab reads Advanced.

Only for use by a DrvDocumentPropertySheets function.
CPSUI_PDLGPAGE_DOCPROP
Defines three pages, whose tabs are Layout, Paper/Quality, and Advanced. The Advanced page is a treeview.

Only for use by a DrvDocumentPropertySheets function.
CPSUI_PDLGPAGE_PRINTERPROP
Defines one treeview page whose tab reads Device Settings.

Only for use by a DrvDevicePropertySheets function.
CPSUI_PDLGPAGE_TREEVIEWONLY
Defines one treeview page.

cOptItem
Caller-supplied number of OPTITEM structures pointed to by pOptItem.
cDlgPage
Caller-supplied number of DLGPAGE structures pointed to by pDlgPage. Not used if pDlgPage specifies a predefined CPSUI_PDLGPAGE-prefixed structure.
IconID
Caller-supplied, can be one of the following:
  • An icon resource identifier. This can be application-defined, or it can be one of the CPSUI-supplied, IDI_CPSUI-prefixed icon resource identifiers.
  • An icon handle. If a handle is specified, CPSUIF_ICONID_AS_HICON must be set in the Flags member.

The specified icon is displayed in the root node of the property sheet page's treeview.

pOptItemName
Caller-supplied pointer to a NULL-terminated string to be displayed in the root node of the property sheet page's treeview. For printer interface DLLs, this string typically represents a printer device type, such as "HP 4si".
CallerVersion
Caller-supplied version number, representing the calling application's current version. The high byte identifies the major version, and the low byte is the minor version. For example, a CallerVersion value of 0x310 specifies a caller version number of 3.16. The version number is displayed when a user clicks on a page's About button.
OptItemVersion
Caller-supplied version number, representing the root-level option item's current version. For printer interface DLLs, this typically represents a printer device version. The high byte identifies the major version, and the low byte is the minor version. For example, an OptItemVersion value of 0x3ff specifies a caller version number of 3.255. The version number is displayed when a user clicks on a page's About button.
dwReserved
Reserved. This array must be set to zero.

Headers

Declared in compstui.h. Include compstui.h.


CPSUICBPARAM

The CPSUICBPARAM structure is used as the input parameter to _CPSUICALLBACK-typed callback functions.

typedef struct _CPSUICBPARAM {
  WORD  cbSize;
  WORD  Reason;
  HWND  hDlg;
  POPTITEM  pOptItem;
  WORD  cOptItem;
  WORD  Flags;
  POPTITEM  pCurItem;
  union {
    LONG  OldSel;
    LPTSTR  pOldSel;
  };
  ULONG_PTR  UserData;
  ULONG_PTR  Result;
} CPSUICBPARAM, *PCPSUICBPARAM;

Members

cbSize
CPSUI-supplied size, in bytes, of the CPSUICBPARAM structure.
Reason
CPSUI-supplied value indicating the reason it is calling the callback function. This can be one of the values listed in the following table.
Reason Description
CPSUICB_REASON_ABOUT
The user has clicked on the page's About button, and the application previously set the CPSUIF_ABOUT_CALLBACK flag in a COMPROPSHEETUI structure. CPSUI sets pCurItem to the value contained in pOptItem, and sets pOldSel to point to the COMPROPSHEETUI structure.
CPSUICB_REASON_APPLYNOW
The user has clicked on the page's Apply or OK button, and CPSUI has received a PSN_APPLY notification message (described in the Platform SDK documentation). CPSUI sets pCurItem to point to the option to which pOptItem points. It also sets OldSel to minus one to indicate that all valid changed option values should be applied now.
CPSUICB_REASON_DLGPROC
The option identified by pCurItem is a push button (TVOT_PUSHBUTTON option type), and the user has clicked on the button.

The push button option's OPTPARAM Style field is set to PUSHBUTTON_TYPE_DLGPROC.
CPSUICB_REASON_ECB_CHANGED
The option identified by pCurItem is an extended check box, and the user has changed the box's state.
CPSUICB_REASON_EXTPUSH
The option identified by pCurItem is an extended push button, and the user has clicked on the button.
CPSUICB_REASON_ITEMS_REVERTED
The user clicked on the page's Undo button, and CPSUI has reverted all selections to their original values.
CPSUICB_REASON_KILLACTIVE
The property sheet page is about to lose activation, and CPSUI has received a PSN_KILLACTIVE notification message (described in the Platform SDK documentation). CPSUI sets pCurItem to the value contained in pOptItem, and sets pOldSel to point to the COMPROPSHEETUI structure.
CPSUICB_REASON_OPTITEM_SETFOCUS
The option identified by pCurItem has received input focus.
CPSUICB_REASON_PUSHBUTTON
The option identified by pCurItem is a push button (TVOT_PUSHBUTTON option type), and the user has clicked on the button.

The push button item's OPTPARAM Style field is set to PUSHBUTTON_TYPE_CALLBACK.
CPSUICB_REASON_SEL_CHANGED
The user has changed the selected value for the option pointed to by pCurItem.
CPSUICB_REASON_SETACTIVE
The property sheet page is about to become active, and CPSUI has received a PSN_SETACTIVE notification message (described in the Platform SDK documentation). CPSUI sets pCurItem to the value contained in pOptItem, and sets pOldSel to point to the COMPROPSHEETUI structure.

hDlg
CPSUI-supplied handle to the currently active dialog box.
pOptItem
CPSUI-supplied pointer to an array of OPTITEM structures. This is the same pointer that the application previously supplied in a COMPROPSHEETUI structure.
cOptItem
CPSUI-supplied number of OPTITEM structures in the array pointed to by pOptItem. This is the same number that the application previously supplied in a COMPROPSHEETUI structure.
Flags
CPSUI-supplied flags. This is the same set of flags that the application previously supplied in a COMPROPSHEETUI structure.
pCurItem
CPSUI-supplied pointer to a member of the OPTITEM array pointed to by pOptItem. This array member represents the "current" option, which is the one for which the callback function was called.
OldSel, pOldSel
If the Reason member contains CPSUICB_REASON_SEL_CHANGED, CPSUI sets this union to the previous contents of the OldSel/pOldSel member of the OPTITEM structure pointed to by pCurItem.

For all other Reason values, the contents of this union should be ignored.

UserData
CPSUI-supplied user data. This is the same value that the application previously supplied in a COMPROPSHEETUI structure.
Result
Result value supplied by the _CPSUICALLBACK-typed callback function. By default, CPSUI sets this value to CPSUI_OK. After the callback function returns, CPSUI calls its ComPropSheet function with a function code of CPSFUNC_SET_RESULT, supplying the Result member contents as the result value.

This member is used only if the Reason member is CPSUICB_REASON_APPLYNOW and the callback function does not return CPSUI_ACTION_NO_APPLY_EXIT.

Headers

Declared in compstui.h. Include compstui.h.


CPSUIDATABLOCK

The CPSUIDATABLOCK structure is used as a parameter for the ComPropSheet function, if the function code is CPSFUNC_SET_DATABLOCK or CPSFUNC_QUERY_DATABLOCK.

typedef struct _CPSUIDATABLOCK {
  DWORD  cbData;
  LPBYTE  pbData;
} CPSUIDATABLOCK, *PCPSUIDATABLOCK;

Members

cbData
Size, in bytes of the buffer pointed to be lpData.
pbData
Pointer to a caller-allocated buffer.

Headers

Declared in compstui.h. Include compstui.h.


DLGPAGE

The DLGPAGE structure is used for specifying a property sheet page to CPSUI's ComPropSheet function. The structure's address is included in a COMPROPSHEETUI structure, and all member values are supplied by the ComPropSheet caller.

typedef struct _DLGPAGE {
  WORD  cbSize;
  WORD  Flags;
  DLGPROC  DlgProc;
  LPTSTR  pTabName;
  ULONG_PTR  IconID;
  union {
    WORD  DlgTemplateID;
    HANDLE  hDlgTemplate;
  };
} DLGPAGE, *PDLGPAGE;

Members

cbSize
Caller-supplied size, in bytes, of the DLGPAGE structure.
Flags
Caller-supplied bit flags, as described in the following table.
Flag Definition
DPF_ICONID_AS_HICON If set, IconID contains an icon handle.
If not set, IconID contains an icon resource identifier.
DPF_USE_HDLGTEMPLATE If set, hDlgTemplate contains a template handle.
If not set, DlgTemplateID contains a template resource identifier.

DlgProc
Optional, caller-supplied DLGPROC-typed pointer to a dialog box procedure, used to process messages sent by the system when user events occur. (The DLGPROC pointer type is described in the Platform SDK documentation.) If NULL, CPSUI supplies a dialog box procedure. For more information, see the following Comments section.
pTabName
Caller-supplied pointer to a NULL-terminated string to be displayed on the page tab.
IconID
Caller-supplied, can be one of the following:
  • An icon resource identifier. This can be application-defined, or it can be one of the CPSUI-supplied, IDI_CPSUI-prefixed icon resource identifiers.
  • An icon handle. If a handle is specified, DPF_ICONID_AS_HICON must be set in the Flags member.

The specified icon is displayed on the page tab. If this value is zero, an icon is not displayed.

DlgTemplateID
Caller-supplied resource identifier for a dialog box template. This can refer to an application-supplied DIALOG resource, or it can be one of the following CPSUI-supplied identifiers (defined in compstui.h):
Identifier | Type of Page
DP_STD_DOCPROPPAGE1 | Non-treeview page, used for a print document's Layout page.
DP_STD_DOCPROPPAGE2 | Non-treeview page, used for a print document's Paper/Quality page.
DP_STD_TREEVIEWPAGE | Generic treeview page.

The CPSUI-supplied identifiers refer to templates that can display CPSUI option types. The page size for those templates is 252 by 216 dialog box units. For more information, see CPSUI-Supplied Pages and Templates.

This member is not used if DPF_USE_HDLGTEMPLATE is set in Flags.

hDlgTemplate
Caller-supplied handle to a DLGTEMPLATE structure (described in the Platform SDK documentation).

Used only if DPF_USE_HDLGTEMPLATE is set in Flags.

Headers

Declared in compstui.h. Include compstui.h.

Comments

CPSUI creates a property sheet page by allocating a PROPSHEETPAGE structure and passing it to CreatePropertySheetPage (described in the Platform SDK documentation). If the caller has specified a DLGPROC-typed pointer to a dialog box procedure in DlgProc, that procedure is used for handling the page's window messages. If DlgProc is NULL, CPSUI's own dialog box procedures are used.

When the dialog box procedure pointed to by DlgProc is called with a message value of WM_INITDIALOG, it receives the PROPSHEETPAGE structure as input, and it also receives a PSPINFO structure.

If a caller-supplied dialog box procedure handles a message, it should return a nonzero value. If the function does not handle the message it should return zero, which causes CPSUI to handle the message.

The PROPSHEETPAGE structure, the DLGPROC pointer type, and the WM_INITDIALOG message are described in the Platform SDK documentation.


EXTCHKBOX

The EXTCHKBOX structure is used by CPSUI applications (including printer interface DLLs) for specifying an extended check box, which can be added to a property sheet page option.

typedef struct _EXTCHKBOX {
  WORD  cbSize;
  WORD  Flags;
  LPTSTR  pTitle;
  LPTSTR  pSeparator;
  LPTSTR  pCheckedName;
  ULONG_PTR  IconID;
  WORD  wReserved[4];
  ULONG_PTR  dwReserved[2];
} EXTCHKBOX, *PEXTCHKBOX;

Members

cbSize
Size, in bytes, of the EXTCHKBOX structure.
Flags
Bit flags, as described in the following table.
Flag Description
ECBF_CHECKNAME_AT_FRONT
If set, CPSUI displays strings in the order "pCheckedName pSeparator SelectName", where SelectName is the string associated with the option's selected value.
If not set, CPSUI displays strings in the order "SelectName pSeparator pCheckedName".
ECBF_CHECKNAME_ONLY_ENABLED
If set, CPSUI displays the pCheckedName string only if the option is checked and enabled (that is, OPTIF_ECB_CHECKED is set and OPTIF_DISABLED is clear in the OPTITEM structure).
If not set, CPSUI always displays the pCheckedName string if the option is checked (that is, OPTIF_ECB_CHECKED is set in the OPTITEM structure), even if the option is disabled.
ECBF_ICONID_AS_HICON
If set, the IconID member contains an icon handle.
If not set, the IconID member contains an icon resource identifier.
ECBF_OVERLAY_ECBICON_IF_CHECKED
If set, and if the check box is checked (that is, OPTIF_ECB_CHECKED is set in the OPTITEM structure), CPSUI overlays the icon identified by the IconID member onto the icon associated with the option item.
ECBF_OVERLAY_NO_ICON
If set, CPSUI overlays its IDI_CPSUI_NO icon onto the icon identified by the IconID member.
ECBF_OVERLAY_STOP_ICON
If set, CPSUI overlays the IDI_CPSUI_STOP icon onto the icon identified by the IconID member.
ECBF_OVERLAY_WARNING_ICON
If set, CPSUI overlays its IDI_CPSUI_WARNING icon onto the icon identified by the IconID member.

pTitle
String identifier, representing the check box title. This can be a 32-bit pointer to a NULL-terminated string, or it can be a 16-bit string resource identifier with HIWORD set to zero.
pSeparator
String identifier, representing a separator character to be displayed between the checked name string and the selected option string This can be a 32-bit pointer to a NULL-terminated string, or it can be a 16-bit string resource identifier with HIWORD set to zero.
pCheckedName
String identifier, representing the text to be displayed when the check box is checked. This can be a 32-bit pointer to a NULL-terminated string, or it can be a 16-bit string resource identifier with HIWORD set to zero.
IconID
One of the following icon identifiers:
  • An icon resource identifier. This can be application-defined, or it can be one of the CPSUI-supplied, IDI_CPSUI-prefixed icon resource identifiers.
  • An icon handle. If a handle is specified, ECBF_ICONID_AS_HICON must be set in the Flags member.

If this value is zero, an icon is not displayed.

wReserved
Reserved, must be initialized to zero.
dwReserved
Reserved, must be initialized to zero.

Headers

Declared in compstui.h. Include compstui.h.

Comments

An extended check box is a CPSUI-defined type of check box that can be associated with an OPTITEM structure. An OPTITEM structure can have one extended check box or one extended push button associated with it.

See Also

EXTPUSH


EXTPUSH

The EXTPUSH structure is used by CPSUI applications (including printer interface DLLs) for specifying an extended push button, which can be added to a property sheet page option. When the button is pushed, a new dialog can be displayed.

typedef struct _EXTPUSH {
  WORD  cbSize;
  WORD  lags;
  LPTSTR  pTitle;
  union {
    DLGPROC  DlgProc;
    FARPROC  pfnCallBack;
  }
  ULONG_PTR  IconID;
  union {
    WORD  DlgTemplateID;
    HANDLE  hDlgTemplate;
  }
  ULONG_PTR  dwReserved[3];
} EXTPUSH, *PEXTPUSH;

Members

cbSize
Size, in bytes, of the EXTPUSH structure.
Flags
Bit flags, as described in the following table.
Flag Description
EPF_ICONID_AS_HICON
If set, the IconID member contains an icon handle.
If not set, the IconID member contains an icon resource identifier.
EPF_INCLUDE_SETUP_TITLE
If set, CPSUI appends "Setup" to the string pointed to by pTitle.
EPF_NO_DOT_DOT_DOT
If set, CPSUI does not append "..." to the string pointed to by pTitle.
EPF_OVERLAY_NO_ICON
If set, CPSUI overlays its IDI_CPSUI_NO icon onto the icon identified by the IconID member.
EPF_OVERLAY_STOP_ICON
If set, CPSUI overlays the IDI_CPSUI_STOP icon onto the icon identified by the IconID member.
EPF_OVERLAY_WARNING_ICON
If set, CPSUI overlays its IDI_CPSUI_WARNING icon onto the icon identified by the IconID member.
EPF_PUSH_TYPE_DLGPROC
If set, the DlgProc and DlgTemplateID/hDlgTemplate members are valid.
If not set, the pfnCallBack member is valid.
EPF_USE_HDLGTEMPLATE
If set, hDlgTemplate contains a template handle.
If not set, DlgTemplateID contains a template resource identifier.

pTitle
String identifier, representing the push button title. This can be a 32-bit pointer to a NULL-terminated string, or it can be a 16-bit string resource identifier with HIWORD set to zero.
DlgProc
DLGPROC-typed pointer to a dialog box procedure to process messages for the push button's dialog box. (The DLGPROC pointer type is described in the Platform SDK documentation.) For more information, see the following Comments section.

If this pointer is supplied, EPF_PUSH_TYPE_DLGPROC must be set in Flags.

pfnCallBack
Pointer to a _CPSUICALLBACK-typed callback function to handle the CPSUICB_REASON_PUSHBUTTON reason. For more information, see the following Comments section.

If this pointer is supplied, EPF_PUSH_TYPE_DLGPROC must be cleared in Flags.

IconID
One of the following icon identifiers:
  • An icon resource identifier. This can be application-defined, or it can be one of the CPSUI-supplied, IDI_CPSUI-prefixed icon resource identifiers.
  • An icon handle. If a handle is specified, EPF_ICONID_AS_HICON must be set in the Flags member.

CPSUI displays the icon next to the push button. If this value is zero, an icon is not displayed.

DlgTemplateID
DIALOG resource identifier, describing a dialog box template.

Not used if EPF_USE_HDLGTEMPLATE is set in Flags.

hDlgTemplate
Handle to a DLGTEMPLATE structure (described in the Platform SDK documentation).

Used only if EPF_USE_HDLGTEMPLATE is set in Flags.

dwReserved
Reserved, must be initialized to zero.

Headers

Declared in compstui.h. Include compstui.h.

Comments

An extended push button is a CPSUI-defined type of push button that can be associated with an OPTITEM structure. An OPTITEM structure can have one extended push button or one extended check box associated with it.

When you use the EXTPUSH structure to create a push button, you can optionally create an additional dialog box that pops up when the user clicks on the button. To create this dialog box, you should specify a pointer to a dialog box procedure in the DlgProc member, and include a dialog template specification in either the DlgTemplateID or the hDlgTemplate member.

If EPF_USE_HDLGTEMPLATE is set in Flags, CPSUI creates the dialog box by calling DialogBoxIndirectParam (described in the Platform SDK documentation), passing the contents of the DlgProc and hDlgTemplate members.

If EPF_USE_HDLGTEMPLATE is not set in Flags, CPSUI creates the dialog box by calling DialogBoxParam (described in the Platform SDK documentation), passing the contents of the DlgProc and DlgTemplateID members.

When the dialog box procedure is called with a uMsg value of WM_INITDIALOG, the lParam value is the address of a CPSUICBPARAM structure, with the Reason member set to CPSUICB_REASON_EXTPUSH. (For more information about the uMsg and lParam parameters, see DialogProc in the Platform SDK documentation.)

If you do not need CPSUI to display a dialog box when the user clicks on the button, you can specify the address of a _CPSUICALLBACK-typed callback function in the pfnCallBack member. When a user clicks on the button, CPSUI calls the callback function. The accompanying CPSUICBPARAM structure's Reason member will be set to CPSUICB_REASON_EXTPUSH.

See Also

EXTCHKBOX


INSERTPSUIPAGE_INFO

The INSERTPSUIPAGE_INFO structure is used as an input parameter to CPSUI's ComPropSheet function, if the function code is CPSFUNC_INSERT_PSUIPAGE. All member values must be supplied by the ComPropSheet caller.

typedef struct _INSERTPSUIPAGE_INFO {
  WORD  cbSize;
  BYTE  Type;
  BYTE  Mode;
  ULONG_PTR  dwData1;
  ULONG_PTR  dwData2;
  ULONG_PTR  dwData3;
} INSERTPSUIPAGE_INFO, *PINSERTPSUIPAGE_INFO;

Members

cbSize
Caller-supplied size, in bytes, of the INSERTPSUIPAGE_INFO structure.
Type
Caller-supplied integer value indicating the type of insertion being requested. The member can contain one of the constants listed in the following table.
Value Description
PSUIPAGEINSERT_DLL
CPSUI calls the specified PFNPROPSHEETUI typed function, with a reason value of PROPSHEETUI_REASON_INIT. The function is contained in a separate DLL.
PSUIPAGEINSERT_GROUP_PARENT
CPSUI creates a new group parent.
PSUIPAGEINSERT_HPROPSHEETPAGE
CPSUI inserts a page that has been created by calling CreatePropertySheetPage (see the Platform SDK documentation).
(This is equivalent to calling ComPropSheet with a function code of CPSFUNC_ADD_HPROPSHEETPAGE.)
PSUIPAGEINSERT_PCOMPROPSHEETUI
CPSUI inserts pages described by a COMPROPSHEETUI structure.
(This is equivalent to calling ComPropSheet with a function code of CPSFUNC_ADD_PCOMPROPSHEETUI.)
PSUIPAGEINSERT_PFNPROPSHEETUI
CPSUI calls the specified PFNPROPSHEETUI typed function, with a reason value of PROPSHEETUI_REASON_INIT.
(This is equivalent to calling ComPropSheet with a function code of CPSFUNC_ADD_PFNPROPSHEETUI.)
PSUIPAGEINSERT_PROPSHEETPAGE
CPSUI inserts the page described by the specified PROPSHEETPAGE structure.
(This is equivalent to calling ComPropSheet with a function code of CPSFUNC_ADD_PROPSHEETPAGE.)

Mode
Caller-supplied value indicating where CPSUI should insert the new pages. It must be one of the values listed in the following table.
Mode Description
INSPSUIPAGE_MODE_AFTER
CPSUI inserts pages after the page identified by the CPSUI page handle that is specified by the lParam1 parameter to ComPropSheet.
INSPSUIPAGE_MODE_BEFORE
CPSUI inserts pages before the page identified by the CPSUI page handle that is specified by the lParam1 parameter to ComPropSheet.
INSPSUIPAGE_MODE_FIRST_CHILD
CPSUI inserts pages as the first children of the parent group identified by the hComPropSheet parameter to ComPropSheet.
The lParam1 parameter to ComPropSheet is ignored.
INSPUIPAGE_MODE_INDEX
CPSUI inserts pages as children of the parent group identified by the hComPropSheet parameter to ComPropSheet.
The lParam1 parameter to ComPropSheet specifies a zero-based index identifying where, within the set of children, the specified pages should be inserted. If lParam1 is 0, the pages are inserted starting at page 1; if lParam1 is 1, the pages are inserted starting at page 2; and so on. If the index is greater than the number of existing children, the new pages are added as the last children. The lParam1 value must be specified as HINSPSUIPAGE_INDEX(index).
INSPSUIPAGE_MODE_LAST_CHILD
CPSUI inserts pages as the last children of the parent group identified by the hComPropSheet parameter to ComPropSheet.
The lParam1 parameter to ComPropSheet is ignored.

dwData1, dwData2, dwData3
Caller-supplied values that are dependent on the contents of the Type member.
Type Member Value dwData1, dwData2, and dwData3 Usage
PSUIPAGEINSERT_DLL
dwData1 – Caller-supplied pointer to a NULL-terminated string representing the DLL path name.
dwData2 – Caller-supplied pointer to a NULL-terminated string representing the name of a PFNPROPSHEETUI typed function, contained in the specified DLL.
dwData3 – Caller-supplied 32-bit value, passed to the PFNPROPSHEETUI-typed function for its lParam parameter.
PSUIPAGEINSERT_GROUP_PARENT
dwData1 – Not used, must be zero.
dwData2 – Not used, must be zero.
dwData3 – Not used, must be zero.
PSUIPAGEINSERT_HPROPSHEETPAGE
dwData1 – Caller-supplied handle to a property sheet, returned by CreatePropertySheetPage.
dwData2 – Not used, must be zero.
dwData3 – Not used, must be zero.
PSUIPAGEINSERT_PCOMPROPSHEETUI
dwData1 – Caller-supplied pointer to a COMPROPSHEETUI structure.
dwData2 – On success, receives the number of pages inserted. On failure, receives an ERR_CPSUI-prefixed error code.
dwData3 – Not used, must be zero.
PSUIPAGEINSERT_PFNPROPSHEETUI
dwData1 – Caller-supplied pointer to a PFNPROPSHEETUI-typed function.
dwData2 – Caller-supplied 32-bit value, passed to the PFNPROPSHEETUI-typed function for its lParam parameter.
dwData3 – Not used, must be zero.
PSUIPAGEINSERT_PROPSHEETPAGE
dwData1 – Caller-supplied pointer to a PROPSHEETPAGE structure.
dwData2 – Not used, must be zero.
dwData3 – Not used, must be zero.

Headers

Declared in compstui.h. Include compstui.h.


OIEXT

The OIEXT structure supplies additional, optional information about a property sheet page option that is described by an OPTITEM structure.

typedef struct _OIEXT {
  WORD  cbSize;
  WORD  Flags;
  HINSTANCE  hInstCaller;
  LPTSTR  pHelpFile;
  ULONG_PTR  dwReserved[4];
} OIEXT, *POIEXT;

Members

cbSize
Size, in bytes, of the OIEXT structure.
Flags
Can contain the following bit flag:
Flag Description
OIEXTF_ANSI_STRING If set, pHelpFile points to an ANSI string.
If not set, pHelpFile points to a UNICODE string.
CPSUI does not check this flag if pHelpFile specifies a resource ID.

hInstCaller
Instance handle to a DLL containing string and icon resources belonging to the OPTITEM, OPTTYPE, and OPTPARAM structures associated with the OIEXT structure. If NULL, CPSUI obtains resources from the DLL identified by the hInstCaller member of a COMPROPSHEETUI structure.
pHelpFile
Pointer to a NULL-terminated string representing a path to a help file containing help information for the option. This can be a 32-bit pointer to a NULL-terminated string, or it can be a 16-bit string resource identifier with HIWORD set to zero. If NULL, CPSUI uses the help file identified by the pHelpFile member of a COMPROPSHEETUI structure.
dwReserved
Reserved, must be initialized to zero.

Headers

Declared in compstui.h. Include compstui.h.


OPTITEM

The OPTITEM structure is used by CPSUI applications (including printer interface DLLs) for describing one property sheet option on a property sheet page, if the page is described by a COMPROPSHEETUI structure.

typedef struct _OPTITEM {
  WORD  cbSize;
  BYTE  Level;
  BYTE  DlgPageIdx;
  DWORD  Flags;
  ULONG_PTR  UserData;
  LPTSTR  pName;
  union {
    LONG  Sel;
    LPTSTR  pSel;
  };
  union {
    PEXTCHKBOX  pExtChkBox;
    PEXTPUSH  pExtPush;
  };
  POPTTYPE  pOptType;
  DWORD  HelpIndex;
  BYTE  DMPubID;
  BYTE  UserItemID;
  WORD  wReserved;
  POIEXT  pOIExt;
  ULONG_PTR  dwReserved[3];
} OPTITEM, *POPTITEM;

Members

cbSize
Size, in bytes, of the OPTITEM structure.
Level
Specifies the level of this option in the treeview. For more information, see the following Comments section.
DlgPageIdx
Identifies the dialog to which the option belongs. Specifies an array index into the DLGPAGE array pointed to by the pDlgPage member of the COMPROPSHEETUI structure.

If pDlgPage points to a CPSUI-supplied, predefined DLGPAGE structure, CPSUI supplies this index.

Flags
Optional bit flags that modify the option's characteristics. The OPTIF_CHANGEONCE flag is set by CPSUI; all other flags are set by the caller. Any combination of the following flags can be set.
Flag Description
OPTIF_CALLBACK
When a user modifies the option, CPSUI should call the _CPSUICALLBACK-typed callback function specified in the COMPROPSHEETUI structure.
OPTIF_CHANGED
The _CPSUICALLBACK-typed callback function should set this flag if it modified the option, so that CPSUI will redisplay it.
OPTIF_CHANGEONCE
CPSUI sets this bit if a user modified the option.
OPTIF_COLLAPSE
Collapse this option and its children so that it is not expanded in the treeview.
OPTIF_DISABLED
Disables the option so that it is not user-modifiable.
OPTIF_ECB_CHECKED
The associated extended check box is in the checked state.
OPTIF_EXT_IS_EXTPUSH
If set, the pExtPush member is valid (unless NULL).
If not set, the pExtChkBox member is valid (unless NULL).
OPTIF_EXT_DISABLED
The extended check box or extended push button is not selectable.
OPTIF_EXT_HIDE
CPSUI will not display the extended check box or extended push button.
OPTIF_HAS_POIEXT
If set, the pOIExt member is valid.
OPTIF_HIDE
CPSUI will not display this option in the treeview. CPSUI examines this flag only when initially creating the treeview, so changing the flag from its initial value has no effect.
OPTIF_INITIAL_TVITEM
If set, CPSUI sets the initial window focus to this option when it displays the treeview. CPSUI expands tree nodes and scrolls the option into view as necessary. If the option is hidden, or if this flag is not set for any OPTITEM structure, CPSUI chooses the initial focus.
OPTIF_NO_GROUPBOX_NAME
If not set, and pOptype is not zero, CPSUI uses the pName string as the groupbox title.
If set, CPSUI provides a groupbox title.
OPTIF_OVERLAY_NO_ICON
If set CPSUI overlays its IDI_CPSUI_NO icon onto the icon associated with the option. (See the Sel/pSel member.)
OPTIF_OVERLAY_STOP_ICON
If set, CPSUI overlays its IDI_CPSUI_STOP icon onto the icon associated with the option. (See the Sel/pSel member.)
OPTIF_OVERLAY_WARNING_ICON
If set, CPSUI overlays its IDI_CPSUI_WARNING icon onto the icon associated with the option. (See the Sel/pSel member.)
OPTIF_SEL_AS_HICON
If set, the Sel member contains an icon handle.
If not set, the Sel member contains an icon resource identifier.

This flag can only be used when pOptType contains NULL.

UserData
Optional 32-bit value that can be set and used by the caller.

(Printer interface DLLs for Unidrv and Pscript use this member to supply a pointer to a USERDATA structure. User interface plug-ins can reference this structure.)

pName
String identifier representing a localized, displayable option name. This can be a 32-bit pointer to a NULL-terminated string, or it can be a 16-bit string resource identifier, with HIWORD set to zero. (Also see the description of DMPubID, below.)
Sel, pSel
This union indicates the option's currently selected parameter value. Its usage is dependent on the CPSUI option type.

If pOptType is NULL, the option has no parameters, so this union identifies an icon to be associated with the treeview node for the option. The icon identifier can be either an icon handle or an icon resource identifier, as indicated by OPTIF_SEL_AS_HICON in Flags.

pExtChkBox, pExtPush
This union can be a pointer to an EXTCHKBOX structure, a pointer to an EXTPUSH structure, or NULL.

An OPTITEM structure can optionally have an EXTCHKBOX structure, an EXTPUSH structure, or neither, associated with it. If this union is not NULL, and if OPTIF_EXT_IS_EXTPUSH is set in Flags, pExtPush is valid. If the flag is not set, pExtChkBox is valid.

pOptType
Pointer to an OPTTYPE structure that describes the option's display type. If NULL, the option has no parameters and is used as a parent to options with a higher Level value. The child options must immediately follow the parent in the OPTITEM array. (See the following Comments section.)
HelpIndex
Help file index, which identifies help text to be associated with the option. If zero, help file text does not exist for this option. Note that the pOIExt member of this structure must be set with the address of an OIEXT structure in order for help text functionality to exist.
DMPubID
This member is meant for use by printer interface DLLs, when creating a Document Properties property sheet (see DrvDocumentPropertySheets). It is a constant value specifying which, if any, public member of the DEVMODE structure is associated with this option. The following table lists available constants, the associated DEVMODE structure member, and the required value for pName for each constant.
Constant Value Public DEVMODE
Structure Member 		Required pName Value
DMPUB_COLOR | dmColor | IDS_CPSUI_COLOR_APPERANCE
DMPUB_COPIES_COLLATE | dmCopies and dmCollate | IDS_CPSUI_COPIES
DMPUB_DEFSOURCE | dmDefSource | IDS_CPSUI_SOURCE
DMPUB_DITHERTYPE | dmDitherType | IDS_CPSUI_DITHERING
DMPUB_DUPLEX | dmDuplex | IDS_CPSUI_DUPLEX
DMPUB_FORMNAME | dmFormName | IDS_CPSUI_FORMNAME
DMPUB_ICMINTENT | dmICMIntent | IDS_CPSUI_ICMINTENT
DMPUB_ICMMETHOD | dmICMMethod | IDS_CPSUI_ICMMETHOD
DMPUB_MEDIATYPE | dmMediaType | IDS_CPSUI_MEDIA
DMPUB_NUP | Not contained in public section of DEVMODE. | IDS_CPSUI_NUP
DMPUB_ORIENTATION | dmOrientation | IDS_CPSUI_ORIENTATION
DMPUB_OUTPUTBIN | Not contained in public section of DEVMODE. | IDS_CPSUI_OUTPUTBIN
DMPUB_PAGEORDER | Not contained in public section of DEVMODE. | IDS_CPSUI_PAGEORDER
DMPUB_PRINTQUALITY dmPrintQuality IDS_CPSUI_PRINTQUALITY or IDS_CPSUI_RESOLUTION.
If not specified, the default name is IDS_CPSUI_RESOLUTION.
DMPUB_QUALITY | Not contained in public section of DEVMODE. | IDS_CPSUI_QUALITY_SETTINGS
DMPUB_SCALE | dmScale | IDS_CPSUI_SCALE
DMPUB_TTOPTION | dmTTOption | IDS_CPSUI_TTOPTION
DMPUB_NONE | Not contained in public section of DEVMODE.
Greater than or equal to DMPUB_USER | Ignored by CPSUI, can be a caller-defined value.

CPSUI does not maintain a DEVMODE structure. The application is responsible for copying user-selected option parameters into a DEVMODE structure. CPSUI uses DMPubID contents to determine treeview placement of standard options, and to determine the contents of the Layout and Paper/Quality tabs (see the pDlgPage member of the COMPROPSHEETUI structure).

For additional information about using the DMPubID member, see the following Comments section.

UserItemID
Optional application-supplied value that can be used for option identification purposes. Not referenced by CPSUI.
wReserved
Reserved, must be initialized to zero.
pOIExt
Pointer to an optional OIEXT structure. The caller is responsible for allocating storage for this structure.
dwReserved
Reserved, must be initialized to zero.

Headers

Declared in compstui.h. Include compstui.h.

Comments

OPTITEM structures should be placed in an array, and the array's address should be placed in the pOptItem member of a COMPROPSHEETUI structure.

The Level member allows you to create child nodes in the treeview. For example, to create a set of option nodes under a level 1 parent node, specify level 2 for each child node and include their OPTITEM structures in the OPTITEM array, immediately after the parent's OPTITEM structure. In the parent's OPTITEM structure, pOptType should be NULL.

The treeview root node is level 0. Options displayed when a user expands the root node are level 1. The maximum number of levels is 256.

For option values that are stored in a printer's DEVMODE structure, the DMPubID member must identify the option. For each DMPubID value that is used, a printer interface DLL must specify the CPSUI option type listed in the following table.

DMPubID Value | Required CPSUI Option Type
DMPUB_COLOR | TVOT_2STATES
DMPUB_COPIES_COLLATE | TVOT_UDARROW plus EXTCHKBOX (See comments following this table.)
DMPUB_DEFSOURCE | TVOT_LISTBOX
DMPUB_DITHERTYPE | TVOT_LISTBOX
DMPUB_DUPLEX | TVOT_2STATES or TVOT_3STATES
DMPUB_FORMNAME | TVOT_LISTBOX
DMPUB_ICMINTENT | TVOT_2STATES or TVOT_3STATES
DMPUB_ICMMETHOD | TVOT_2STATES or TVOT_3STATES
DMPUB_MEDIATYPE | TVOT_LISTBOX
DMPUB_NUP | TVOT_LISTBOX
DMPUB_ORIENTATION | TVOT_2STATES or TVOT_3STATES
DMPUB_OUTPUTBIN | TVOT_LISTBOX
DMPUB_PAGEORDER | TVOT_2STATES or TVOT_3STATES
DMPUB_PRINTQUALITY | TVOT_LISTBOX
DMPUB_QUALITY | TVOT_2STATES or TVOT_3STATES
DMPUB_SCALE | TVOT_UDARROW
DMPUB_TTOPTION | TVOT_LISTBOX

If DMPubID is DMPUB_COPIES_COLLATE and the printer can collate copies, an extended check box (EXTCHKBOX structure) must be provided. The EXTCHCKBOX structure's members must be set as follows:

pExtCheckbox->cbSize = sizeof(EXTCHKBOX);
pExtCheckbox->pTitle = (PWSTR) IDS_CPSUI_COLLATE;
pExtCheckbox->pCheckedName = (PWSTR) IDS_CPSUI_COLLATED;
pExtCheckbox->IconID = IDI_CPSUI_COLLATE;
pExtCheckbox->Flags = ECBF_CHECKNAME_ONLY_ENABLED;
pExtCheckbox->pSeparator = (PWSTR)IDS_CPSUI_SLASH_SEP;

If OPTIF_EXT_HIDE is not set in Flags, CPSUI enables the check box if a user requests more than one copy, and disables it if only one copy is requested.

Additionally, CPSUI sets the option's display text to copy for one copy and copies for more than one copy.

If DMPubID is DMPUB_COLOR, its first OPTPARAM structure (Sel=0) must represent Gray Scale, and pData in the OPTPARAM structure must be IDS_CPSUI_GRAYSCALE. Its second OPTPARAM structure (Sel=1) must represent Color, and pData in the OPTPARAM structure must be IDS_CPSUI_COLOR. If another option's DMPubID is DMPUB_ICMINTENT and if Color is not selected, CPSUI disables the option for which DMPUB_ICMINTENT is specified.

CPSUI disables color matching when Color is not selected.


OPTPARAM

An array of OPTPARAM structures is used by CPSUI applications (including printer interface DLLs) for describing all the parameter values associated with a property sheet option. The array's address is included in an OPTTYPE structure.

typedef struct _OPTPARAM {
  WORD  cbSize;
  BYTE  Flags;
  BYTE  Style;
  LPTSTR  pData;
  ULONG_PTR  IconID;
  LPARAM  lParam;
  ULONG_PTR  dwReserved[2];
} OPTPARAM, *POPTPARAM;

Members

cbSize
Size, in bytes, of the OPTPARAM structure.
Flags
Optional bit flags that modify the parameter's characteristics. The flags in the following table can be set in any combination.
Flag Description
OPTPF_DISABLED
If set, the parameter is not user-selectable. Can be used with the following option types:
TVOT_2STATES
TVOT_3STATES
TVOT_COMBOBOX
TVOT_LISTBOX
OPTPF_HIDE
If set, the parameter not displayed in the treeview. Can be used with the following option types:
TVOT_3STATES
TVOT_COMBOBOX
TVOT_LISTBOX
OPTPF_ICONID_AS_HICON
If set, the IconID member contains an icon handle.
If not set, the IconID member contains an icon resource identifier.
OPTPF_OVERLAY_NO_ICON
If set, CPSUI overlays its IDI_CPSUI_NO icon onto the icon identified by the IconID member.
OPTPF_OVERLAY_STOP_ICON
If set, CPSUI overlays the IDI_CPSUI_STOP icon onto the icon identified by the IconID member.
OPTPF_OVERLAY_WARNING_ICON
If set, CPSUI overlays its IDI_CPSUI_WARNING icon onto the icon identified by the IconID member.
OPTPF_USE_HDLGTEMPLATE
If set, lParam contains a template handle.
If not set, lParam contains a template resource identifier.

(Used only if Style is PUSHBUTTON_TYPE_DLGPROC.)

Style
Push button style, used only for the TVOT_PUSHBUTTON option type.
pData
Pointer to the parameter's value. Use of this member is dependent on the CPSUI option type.
IconID
Usually identifies the icon to be associated with the option parameter, but is sometimes used for other purposes. Use of this member is dependent on the CPSUI option type.
lParam
Use of this member is dependent on the CPSUI option type.
dwReserved
Reserved, must be initialized to zero.

Headers

Declared in compstui.h. Include compstui.h.

Comments

If the OPTPF_HIDE flag is set in all the OPTPARAM structures associated with an option, CPSUI hides the entire option.


OPTTYPE

The OPTTYPE structure is used by CPSUI applications (including printer interface DLLs) for describing the type and other characteristics of a property sheet option, if the option is specified by an OPTITEM structure.

typedef struct _OPTTYPE {
  WORD  cbSize;
  BYTE  Type;
  BYTE  Flags;
  WORD  Count;
  WORD  BegCtrlID;
  POPTPARAM  pOptParam;
  WORD  Style;
  WORD  wReserved[3];
  ULONG_PTR  dwReserved[3];
} OPTTYPE, *POPTTYPE;

Members

cbSize
Size, in bytes, of the OPTTYPE structure.
Type
Specifies the CPSUI option type.
Flags
Optional bit flags that modify the option's characteristics. The flags in the following table can be set in any combination.
Flag Description
OPTTF_NOSPACE_BEFORE_POSTFIX
CPSUI should not add a space character between the string specified by the OPTITEM structure's pName string and the OPTPARAM structure's pData string, when displaying the option.

Valid only if the option type is or TVOT_SCROLLBAR or TVOT_TRACKBAR.
OPTTF_TYPE_DISABLED
All the OPTPARAM structures to which pOptParam points are disabled, so that none of the parameter values are user-selectable.

Count
Specifies the number of OPTPARAM structures to which pOptParam points. This member's value is dependent on the CPSUI option type.
BegCtrlID
If pDlgPage in COMPROPSHEETUI identifies a CPSUI-supplied page, or if DlgTemplateID in DLGPAGE identifies a CPSUI-supplied template, BegCtrlID is not used.

Otherwise, BegCtrlID must contain the first of a sequentially numbered set of Windows control identifiers. Control identifier usage is dependent on the CPSUI option type.

pOptParam
Pointer to an array of OPTPARAM structures describing the parameter values that a user can select for the option.
Style
Specifies flags that can be used to modify the option's display characteristics. The flags that can be specified are dependent on the CPSUI option type.
wReserved
Reserved, must be initialized to zero.
dwReserved
Reserved, must be initialized to zero.

Headers

Declared in compstui.h. Include compstui.h.


PROPSHEETUI_GETICON_INFO

The PROPSHEETUI_GETICON_INFO structure is used as an input parameter to an application's PFNPROPSHEETUI-typed function, when the function is called with a reason value of PROPSHEETUI_REASON_GET_ICON.

typedef struct _PROPSHEETUI_GETICON_INFO {
  WORD  cbSize;
  WORD  Flags;
  WORD  cxIcon;
  WORD  cyIcon;
  HICON  hIcon;
} PROPSHEETUI_GETICON_INFO, *PPROPSHEETUI_GETICON_INFO;

Members

cbSize
CPSUI-supplied size, in bytes, of the PROPSHEETUI_GETICON_INFO structure.
Flags
Reserved.
cxIcon
CPSUI-supplied icon width, in pixels.
cyIcon
CPSUI-supplied icon height, in pixels.
hIcon
Receives an application-supplied icon handle. If the icon is not loaded, the member must be set to zero.

Headers

Declared in compstui.h. Include compstui.h.


PROPSHEETUI_INFO

The PROPSHEETUI_INFO structure is used as an input parameter to PFNPROPSHEETUI-typed functions.

typedef struct _PROPSHEETUI_INFO {
  WORD  cbSize;
  WORD  Version;
  WORD  Flags;
  WORD  Reason;
  HANDLE  hComPropSheet;
  PFNCOMPROPSHEET  pfnComPropSheet;
  LPARAM  lParamInit;
  ULONG_PTR  UserData;
  ULONG_PTR  Result;
} PROPSHEETUI_INFO, *PPROPSHEETUI_INFO;

Members

cbSize
CPSUI-supplied size, in bytes, of the PROPSHEETUI_INFO structure.
Version
CPSUI-supplied version number of the PROPSHEETUI_INFO structure. The current version number is defined by PROPSHEETUI_INFO_VERSION in compstui.h.
Flags
CPSUI-supplied bit flags. The following flag is defined:
Flag | Description
PSUIINFO_UNICODE | If set, the calling application uses Unicode characters.

Reason
CPSUI-supplied constant specifying the action to be performed on the property sheet by the PFNPROPSHEETUI-typed function to which the PROPSHEETUI_INFO structure was passed. One of the following constants will be supplied:
  • PROPSHEETUI_REASON_DESTROY
  • PROPSHEETUI_REASON_GET_ICON
  • PROPSHEETUI_REASON_GET_INFO_HEADER
  • PROPSHEETUI_REASON_INIT
  • PROPSHEETUI_REASON_SET_RESULT

For information about the meaning of each constant, see the Comments section of the PFNPROPSHEETUI description.

hComPropSheet
CPSUI-supplied handle to a property sheet group parent. This handle can be passed to CPSUI's ComPropSheet function.
pfnComPropSheet
Address of CPSUI's ComPropSheet function.
lParamInit
Value received as the lParam parameter for the associated PFNPROPSHEETUI-typed function, when the function was first called with a Reason of PROPSHEETUI_REASON_INIT. For information about what this value can be, see the description of PFNPROPSHEETUI.

This value is supplied by CPSUI, and is valid for all Reason values.

UserData
Optional, private value or pointer supplied by the associated PFNPROPSHEETUI -typed function, initially set to zero by CPSUI. If the function stores a value in UserData, then for subsequent calls to the function, the stored value or pointer is unchanged unless changed by the function.
Result
Result value supplied by the associated PFNPROPSHEETUI -typed function, initially set to zero by CPSUI. If the function stores a result value in Result, then for subsequent calls to the function, the stored value is unchanged unless changed by the function.

If the PFNPROPSHEETUI-typed function's address was specified as an argument to CommonPropertySheetUI, the last value stored in Result is returned to CommonPropertySheetUI in the location pointed to by its pResult argument.

Headers

Declared in compstui.h. Include compstui.h.


PROPSHEETUI_INFO_HEADER

The PROPSHEETUI_INFO_HEADER structure is used as an input parameter to an application's PFNPROPSHEETUI-typed function, when the function is called with a reason value of PROPSHEETUI_REASON_GET_INFO_HEADER.

typedef struct _PROPSHEETUI_INFO_HEADER {
  WORD  cbSize;
  WORD  Flags;
  LPTSTR  pTitle;
  HWND  hWndParent;
  HINSTANCE  hInst;
  union {
    HICON  hIcon;
    ULONG_PTR  IconID;
  };
} PROPSHEETUI_INFO_HEADER, *PPROPSHEETUI_INFO_HEADER;

Members

cbSize
CPSUI-supplied size, in bytes, of the PROPSHEETUI_INFO_HEADER structure.
Flags
Optional, application-specified bit flags that modify the property sheet page's appearance. The flags listed in the following table can be used in any combination.
Flag | Description
PSUIHDRF_DEFTITLE | If set, CPSUI should include "Default" in the title bar string. CPSUI adds "Default" after the pTitle string and, if PSUIHDRF_PROPTITLE is set, before "Properties".
PSUIHDRF_EXACT_PTITLE | If set, CPSUI uses the text specified by pTitle without modification. This flag overrides PSUIHDRF_DEFTITLE and PSUIHDRF_PROPTITLE.
PSUIHDRF_NOAPPLYNOW | If set, CPSUI should not include an Apply Now button.
PSUIHDRF_PROPTITLE | If set, CPSUI should append "Properties" to the title bar string. (By default, CPSUI sets this flag before calling the application.)
PSUIHDRF_USEHICON | If set, the hIcon/IconID union contains an icon handle. If not set, the union contains an icon resource identifier.

pTitle
String identifier, representing text to be displayed in the property sheet's title bar. This can be a 32-bit pointer to a NULL-terminated string, or it can be a 16-bit string resource identifier with HIWORD set to zero. For printer interface DLLs, the string typically contains the printer's name.
hWndParent
Handle to the window to be used as the parent of the property sheet. By default, CPSUI supplies the window handle that it received for the hWndOwner parameter to CommonPropertySheetUI, but the application can overwrite that handle with another.
hInst
Application-supplied instance handle, which CPSUI uses when loading application resources.
hIcon, IconID
This union identifies the icon to be displayed in the property sheet's title bar. The union member is selected by PSUIHDRF_USEICON in Flags.

Headers

Declared in compstui.h. Include compstui.h.


PSPINFO

The PSPINFO structure is used as an input parameter to a property sheet page's dialog box procedure, when the Windows message is WM_INITDIALOG. The dialog box procedure's address is specified in a DLGPAGE structure.

typedef struct _PSPINFO {
  WORD  cbSize;
  WORD  wReserved;
  HANDLE  hComPropSheet;
  HANDLE  hCPSUIPage;
  PFNCOMPROPSHEET  pfnComPropSheet;
} PSPINFO, *PPSPINFO;

Members

cbSize
CPSUI-supplied size, in bytes, of the PSPINFO structure.
wReserved
Reserved.
hComPropSheet
CPSUI-supplied handle to the parent of the page whose handle is contained in hCPSUIPage.
hCPSUIPage
CPSUI-supplied handle to the property sheet page.
pfnComPropSheet
CPSUI-supplied pointer to its ComPropSheet function.

Headers

Declared in compstui.h. Include compstui.h.

Comments

Before CPSUI calls CreatePropertySheetPage to create a property sheet page, it expands the size of the standard PROPSHEETPAGE structure in order to append a PSPINFO structure. When the operating system calls a dialog box procedure (pointed to by a DLGPAGE structure) and specifies a WM_INITDIALOG message, the function's lParam member points to the expanded PROPSHEETPAGE structure containing the PSPINFO structure.

(The CreatePropertySheetPage function, PROPSHEETPAGE structure, WM_INITDIALOG message, and dialog box procedures are all described in the Platform SDK documentation.)

To obtain the PSPINFO structure's address, use the PPSPINFO_FROM_WM_INITDIALOG_LPARAM macro (defined in compstui.h) as follows:

PPSPINFO pPspInfo;
if (Msg == WM_INITDIALOG) {
    pPspInfo = PPSPINFO_FROM_WM_INITDIALOG_LPARAM(lParam);
}

The PSPINFO structure pointer can be saved for later use, but the structure's contents must not be modified.


SETRESULT_INFO

The SETRESULT_INFO structure is used as an input parameter to an application's PFNPROPSHEETUI-typed callback function.

typedef struct _SETRESULT_INFO {
  WORD  cbSize;
  WORD  wReserved;
  HANDLE  hSetResult;
  LRESULT  Result;
} SETRESULT_INFO, *PSETRESULT_INFO;

Members

cbSize
CPSUI-supplied size, in bytes, of the SETRESULT_INFO structure.
wReserved
Reserved.
hSetResult
CPSUI-supplied handle to an added property sheet page, obtained from the application. For more information, see the following Comments section.
Result
CPSUI-supplied result value, obtained from the application. For more information, see the following Comments section.

Headers

Declared in compstui.h. Include compstui.h.

Comments

When an application calls CPSUI's ComPropSheet function, specifying a function code of CPSFUNC_SET_RESULT, CPSUI calls all registered PFNPROPSHEETUI-typed functions, specifying a reason of PROPSHEETUI_REASON_SET_RESULT. When specifying this reason, CPSUI also supplies a SETRESULT_INFO structure.

The values contained in the structure's hSetResult and Result members are the lParam1 and lParam2 values, respectively, that were supplied to CPSUI's ComPropSheet function.

Each of the application's PFNPROPSHEETUI-typed functions is called in order, from the one most recently declared to the first one declared, until one of these functions provides a return value of less than one. At that point, CPSUI returns from its ComPropSheet function, providing a count of the number of PFNPROPSHEETUI-typed functions that were called.

Typically, an application's PFNPROPSHEETUI-typed function sets the Result member of its PROPSHEETUI_INFO structure to the value received in the SETRESULT_INFO structure's Result member. Then the function returns a value of 1 (or greater), so the next PFNPROPSHEETUI-typed function can also receive it. Each subsequently called function is associated with a page that is the parent of the page associated with the last-called function. A function can modify the contents of SETRESULT_INFO structure's Result member, causing the functions associated with parent pages to receive the new value.


CPSUI Option Types

When using CPSUI to create a property sheet page, user-selectable options must be defined using CPSUI-supported window controls. These controls are identified by the following CPSUI option types:

TVOT_2STATES

TVOT_3STATES

TVOT_CHKBOX

TVOT_COMBOBOX

TVOT_EDITBOX

TVOT_LISTBOX

TVOT_PUSHBUTTON

TVOT_SCROLLBAR

TVOT_TRACKBAR

TVOT_UDARROW

An option's type is specified in the Type member of an OPTTYPE structure.


TVOT_2STATES

The TVOT_2STATES option type consists of two radio buttons inside a group box.

Type-Specific Use of Structure Members

OPTITEM Structure
Sel/pSel
Index into the OPTPARAM array that is pointed to by the pOptParam member of the option's OPTTYPE structure. This specifies the currently selected option parameter.
OPTPARAM Structure Array (pOptParam member of OPTTYPE)
pData
pOptParam[0]->pData points to a text string describing state 1, used as a button label.
pOptParam[1]->pData points to a text string describing state 2, used as a button label.

If the two states are OFF/ON, FALSE/TRUE, NO/YES, and so on, state 1 must be the OFF, FALSE, or NO state.

IconID
pOptParam[0]->IconID identifies an icon to be associated with state 1.

pOptParam[1]->IconID identifies an icon to be associated with state 2.

lParam
Not used.
OPTTYPE Structure
Type
TVOT_2STATES
Count
2
Style
Not used.
BegCtrlID
If pDlgPage in COMPROPSHEETUI identifies a CPSUI-supplied page, or if DlgTemplateID in DLGPAGE identifies a CPSUI-supplied template, BegCtrlID is not used.

Otherwise, BegCtrlID must contain the first control identifier of a sequentially numbered set of control identifiers. Control identifiers must identify the following Windows controls:
Control Identifier | Windows Control
BegCtrlID contents | Group box
BegCtrlID contents+1 | Title text
BegCtrlID contents+2 | State 1 radio button
BegCtrlID contents+3 | State 1 icon
BegCtrlID contents+4 | State 2 radio button
BegCtrlID contents+5 | State 2 icon
BegCtrlID contents+6 | Extended check box or extended push button (optional)
BegCtrlID contents+7 | Extended check box or extended push button icon (optional)

For additional information, see Customizing CPSUI-Supported Window Controls.

Headers

Declared in compstui.h. Include compstui.h.


TVOT_3STATES

The TVOT_3STATES option type consists of three radio buttons inside a group box.

Type-Specific Use of Structure Members

OPTITEM Structure
Sel/pSel
Index into the OPTPARAM array that is pointed to by the pOptParam member of the option's OPTTYPE structure. This specifies the currently selected option parameter.
OPTPARAM Structure Array (pOptParam member of OPTTYPE)
pData
pOptParam[0]->pData points to a text string describing state 1, used as a button label.
pOptParam[1]->pData points to a text string describing state 2, used as a button label.
pOptParam[2]->pData points to a text string describing state 3, used as a button label.
IconID
pOptParam[0]->IconID identifies an icon to be associated with state 1.

pOptParam[1]->IconID identifies an icon to be associated with state 2.

pOptParam[2]->IconID identifies an icon to be associated with state 3.

lParam
Not used.
OPTTYPE Structure
Type
TVOT_3STATES
Count
3
Style
Not used.
BegCtrlID
If pDlgPage in COMPROPSHEETUI identifies a CPSUI-supplied page, or if DlgTemplateID in DLGPAGE identifies a CPSUI-supplied template, BegCtrlID is not used.

Otherwise, BegCtrlID must contain the first control identifier of a sequentially numbered set of control identifiers. Control identifiers must identify the following Windows controls:
Control Identifier | Windows Control
BegCtrlID contents | Group box
BegCtrlID contents+1 | Title text
BegCtrlID contents+2 | State 1 radio button
BegCtrlID contents+3 | State 1 icon
BegCtrlID contents+4 | State 2 radio button
BegCtrlID contents+5 | State 2 icon
BegCtrlID contents+6 | State 3 radio button
BegCtrlID contents+7 | State 3 icon
BegCtrlID contents+8 | Extended check box or extended push button (optional)
BegCtrlID contents+9 | Extended check box or extended push button icon (optional)

For additional information, see Customizing CPSUI-Supported Window Controls.

Headers

Declared in compstui.h. Include compstui.h.


TVOT_CHKBOX

The TVOT_CHKBOX option type consists of a check box inside a group box.

Type-Specific Use of Structure Members

OPTITEM Structure
Sel/pSel
Not used.
OPTPARAM Structure Array (pOptParam member of OPTTYPE)
pData
Not used.
IconID
Identifies an icon to be associated with the check box.
lParam
Not used.
OPTTYPE Structure
Type
TVOT_CHKBOX
Count
1
Style
Not used.
BegCtrlID
If pDlgPage in COMPROPSHEETUI identifies a CPSUI-supplied page, or if DlgTemplateID in DLGPAGE identifies a CPSUI-supplied template, BegCtrlID is not used.

Otherwise, BegCtrlID must contain the first control identifier of a sequentially numbered set of control identifiers. Control identifiers must identify the following Windows controls:
Control Identifier | Windows Control
BegCtrlID contents | Group box
BegCtrlID contents+1 | Title text
BegCtrlID contents+2 | Check box
BegCtrlID contents+3 | Check box icon
BegCtrlID contents+4 | Extended check box or extended push button (optional)
BegCtrlID contents+5 | Extended check box or extended push button icon (optional)

For additional information, see Customizing CPSUI-Supported Window Controls.

Headers

Declared in compstui.h. Include compstui.h.


TVOT_COMBOBOX

The TVOT_COMBOBOX option type consists of a combo box inside a group box.

Type-Specific Use of Structure Members

OPTITEM Structure
Sel/pSel
Index into the OPTPARAM array that is pointed to by the pOptParam member of the option's OPTTYPE structure. This specifies the currently selected option parameter.
OPTPARAM Structure Array (pOptParam member of OPTTYPE)
pData
pOptParam[0]->pData points to the first text string to be displayed in the combo box.
pOptParam[1]->pData points to the second text string to be displayed in the combo box.
pOptParam[n]->pData points to the nth text string to be displayed in the combo box.
IconID
pOptParam[0]->IconID identifies an icon to be associated with the first text string.

pOptParam[1]->IconID identifies an icon to be associated with the second text string.

pOptParam[n]->IconID identifies an icon to be associated with the nth text string.

lParam
Not used.
OPTTYPE Structure
Type
TVOT_COMBOBOX
Count
The number of OPTPARAM structures; that is, the number text strings to be displayed in the combo box.
Style
The following optional bit flags can be specified:
Flag Definition
OTS_LBCB_INCL_ITEM_NONE
If set, CPSUI includes a "None" string in the combo box. If a users selects "None", the Sel/pSel union is set to minus one.
OTS_LBCB_NO_ICON16_IN_ITEM
If set, CPSUI does not draw each option parameter's icon (IconID in OPTPARAM) when displaying the parameter's value in the combo box.
OTS_LBCB_PROPPAGE_CBUSELB
When the option is displayed on a non-treeview property sheet page, it is displayed as a listbox instead of a combobox.
OTS_LBCB_SORT
If set, CPSUI displays text strings in alphabetic order.

BegCtrlID
If pDlgPage in COMPROPSHEETUI identifies a CPSUI-supplied page, or if DlgTemplateID in DLGPAGE identifies a CPSUI-supplied template, BegCtrlID is not used.

Otherwise, BegCtrlID must contain the first control identifier of a sequentially numbered set of control identifiers. Control identifiers must identify the following Windows controls:
Control Identifier | Windows Control
BegCtrlID contents | Group box
BegCtrlID contents+1 | Title text
BegCtrlID contents+2 | Combo box
BegCtrlID contents+3 | Combo box icon
BegCtrlID contents+4 | Extended check box or extended push button (optional)
BegCtrlID contents+5 | Extended check box or extended push button icon (optional)

For additional information, see Customizing CPSUI-Supported Window Controls.

Headers

Declared in compstui.h. Include compstui.h.


TVOT_EDITBOX

The TVOT_EDITBOX option type consists of an edit box inside a group box.

Type-Specific Use of Structure Members

OPTITEM Structure
Sel/pSel
Application-supplied pointer to a NULL-terminated string containing the current contents of the edit box.
OPTPARAM Structure Array (pOptParam member of OPTTYPE)
pData
pOptParam[0]->pData points to a NULL-terminated text string to be displayed to the right of the text box.
pOptParam[1]->pData points to a NULL-terminated text string to be displayed above the edit box.
IconID
pOptParam[0]->IconID identifies an icon to be associated with the edit box.
pOptParam[1]->IconID is used for specifying the size, in bytes, of both the edit box and the buffer pointed to by pSel in the OPTITEM structure.
lParam
Not used.
OPTTYPE Structure
Type
TVOT_EDITBOX
Count
2
Style
Not used.
BegCtrlID
If pDlgPage in COMPROPSHEETUI identifies a CPSUI-supplied page, or if DlgTemplateID in DLGPAGE identifies a CPSUI-supplied template, BegCtrlID is not used.

Otherwise, BegCtrlID must contain the first control identifier of a sequentially numbered set of control identifiers. Control identifiers must identify the following Windows controls:
Control Identifier | Windows Control
BegCtrlID contents | Group box
BegCtrlID contents+1 | Title text
BegCtrlID contents+2 | Edit box
BegCtrlID contents+3 | Edit box icon
BegCtrlID contents+4 | Text positioned to the right of the edit box
BegCtrlID contents+5 | Text positioned above the edit box
BegCtrlID contents+6 | Extended check box or extended push button (optional)
BegCtrlID contents+7 | Extended check box or extended push button icon (optional)

For additional information, see Customizing CPSUI-Supported Window Controls.

Headers

Declared in compstui.h. Include compstui.h.


TVOT_LISTBOX

The TVOT_LISTBOX option type consists of a list box inside a group box.

Type-Specific Use of Structure Members

OPTITEM Structure
Sel/pSel
Index into the OPTPARAM array that is pointed to by the pOptParam member of the option's OPTTYPE structure. This specifies the currently selected option parameter.
OPTPARAM Structure Array (pOptParam member of OPTTYPE)
pData
pOptParam[0]->pData points to the first text string to be displayed in the list box.
pOptParam[1]->pData points to the second text string to be displayed in the list box.
pOptParam[n]->pData points to the nth text string to be displayed in the list box.
IconID
pOptParam[0]->IconID identifies an icon to be associated with the first text string.

pOptParam[1]->IconID identifies an icon to be associated with the second text string.

pOptParam[n]->IconID identifies an icon to be associated with the nth text string.

lParam
Not used.
OPTTYPE Structure
Type
TVOT_LISTBOX
Count
The number of OPTPARAM structures; that is, the number text strings to be displayed in the list box.
Style
The following optional bit flags can be specified:
Flag Definition
OTS_LBCB_INCL_ITEM_NONE
If set, CPSUI includes a "None" string in the list box. If a users selects "None", the Sel/pSel union is set to minus one.
OTS_LBCB_NO_ICON16_IN_ITEM
If set, CPSUI does not draw each option parameter's icon (IconID in OPTPARAM) when displaying the parameter's value in the list box.
OTS_LBCB_PROPPAGE_LBUSECB
When the option is displayed on a non-treeview property sheet page, it is displayed as a combobox instead of a listbox.
OTS_LBCB_SORT
If set, CPSUI displays text strings in alphabetic order.

BegCtrlID
If pDlgPage in COMPROPSHEETUI identifies a CPSUI-supplied page, or if DlgTemplateID in DLGPAGE identifies a CPSUI-supplied template, BegCtrlID is not used.

Otherwise, BegCtrlID must contain the first control identifier of a sequentially numbered set of control identifiers. Control identifiers must identify the following Windows controls:
Control Identifier | Windows Control
BegCtrlID contents | Group box
BegCtrlID contents+1 | Title text
BegCtrlID contents+2 | List box
BegCtrlID contents+3 | List box icon
BegCtrlID contents+4 | Extended check box or extended push button (optional)
BegCtrlID contents+5 | Extended check box or extended push button icon (optional)

For additional information, see Customizing CPSUI-Supported Window Controls.

Headers

Declared in compstui.h. Include compstui.h.


TVOT_PUSHBUTTON

The TVOT_PUSHBUTTON option type consists of a push button inside a group box.

Type-Specific Use of Structure Members

OPTITEM Structure
Sel/pSel
Depends on the Style member of OPTPARAM, as follows:
Push Button Style Sel/pSel Usage
PUSHBUTTON_TYPE_CALLBACK
Not used.
PUSHBUTTON_TYPE_DLGPROC
CPSUI stores the dialog box procedure's return value.
PUSHBUTTON_TYPE_HTCLRADJ
CPSUI stores the halftoning operation's return value.
PUSHBUTTON_TYPE_HTSETUP
CPSUI stores the halftoning operation's return value.

OPTPARAM Structure Array (pOptParam member of OPTTYPE)
pData
Depends on the Style member, as follows:
Push Button Style pData Usage
PUSHBUTTON_TYPE_CALLBACK
Pointer to a _CPSUICALLBACK-typed function.
PUSHBUTTON_TYPE_DLGPROC
DLGPROC-typed pointer to a dialog box procedure (see the Platform SDK documentation).
PUSHBUTTON_TYPE_HTCLRADJ
Pointer to COLORADJUSTMENT structure (described in the Platform SDK documentation).
PUSHBUTTON_TYPE_HTSETUP
Pointer to a DEVHTADJDATA structure.

IconID
Identifies an icon to be associated with the push button.
lParam
Depends on the Style member, as follows:
Push Button Style lParam Usage
PUSHBUTTON_TYPE_CALLBACK
Not used.
PUSHBUTTON_TYPE_DLGPROC
Resource identifier for a DIALOG resource, or handle to a DLGTEMPLATE structure (see the Platform SDK documentation). Depends on the DPF_USE_HDLGTEMPLATE flag in the OPTPARAM structure's Flags member.
PUSHBUTTON_TYPE_HTCLRADJ
Not used.
PUSHBUTTON_TYPE_HTSETUP
Not used.

Style
Specifies the operation to be performed by CPSUI when a user clicks on the push button. Can be one of the values listed in the following table.
Push Button Style Operation When Button is Pushed
PUSHBUTTON_TYPE_CALLBACK
CPSUI calls the application's _CPSUICALLBACK-typed callback function to handle button events, with the CPSUICBPARAM structure's Reason member set to CPSUICB_REASON_PUSHBUTTON. (CPSUI ignores the callback function's return value.)
PUSHBUTTON_TYPE_DLGPROC
The application's dialog box procedure handles button events. (For more information, see the Comments section for DLGPAGE.)

When the function receives a WM_INITDIALOG message, its lParam argument points to a CPSUICBPARAM structure with the Reason member set to CPSUICB_REASON_DLGPROC.
PUSHBUTTON_TYPE_HTCLRADJ
CPSUI displays a halftone color adjustment dialog box.
PUSHBUTTON_TYPE_HTSETUP
CPSUI displays a device halftone setup dialog box.

OPTTYPE Structure
Type
TVOT_PUSHBUTTON
Count
1
Style
The following optional bit flags can be specified:
Flag Definition
OTS_PUSH_ENABLE_ALWAYS
If set, the push button is always enabled, even if the user cannot modify the property sheet page (that is, even if CPSUIF_UPDATE_PERMISSION is not set in a COMPROPSHEETUI structure).

The push button's callback function must display its dialog, but it must not allow user modifications.

NOTE: You must also set this flag in the Flags member of the OPTTYPE structure.
OTS_PUSH_INCL_SETUP_TITLE
If set, CPSUI includes the word "Setup" after the button's name string (pName in OPTITEM).
OTS_PUSH_NO_DOT_DOT_DOT
If set, CPSUI includes three dots (...) after the button's name string (pName in OPTITEM).

BegCtrlID
If pDlgPage in COMPROPSHEETUI identifies a CPSUI-supplied page, or if DlgTemplateID in DLGPAGE identifies a CPSUI-supplied template, BegCtrlID is not used.

Otherwise, BegCtrlID must contain the first control identifier of a sequentially numbered set of control identifiers. Control identifiers must identify the following Windows controls:
Control Identifier | Windows Control
BegCtrlID contents | Group box
BegCtrlID contents+1 | Title text
BegCtrlID contents+2 | Push button box
BegCtrlID contents+3 | Push button icon
BegCtrlID contents+4 | Extended check box or extended push button (optional)
BegCtrlID contents+5 | Extended check box or extended push button icon (optional)

For additional information, see Customizing CPSUI-Supported Window Controls.

Headers

Declared in compstui.h. Include compstui.h.


TVOT_SCROLLBAR

The TVOT_SCROLLBAR option type consists of a scroll bar inside a group box.

Type-Specific Use of Structure Members

OPTITEM Structure
Sel/pSel
Value representing the current scroll bar position.
OPTPARAM Structure Array (pOptParam member of OPTTYPE)
pData
pOptParam[0]->pData points to a NULL-terminated text string identifying the scroll bar units.
pOptParam[1]->pData points to a NULL-terminated text string describing the low end of the scroll bar's range.
pOptParam[2]->pData points to a NULL-terminated text string describing the high end of the scroll bar's range.
IconID
pOptParam[0]->IconID identifies an icon to be associated with the scroll bar.
pOptParam[1]->IconID specifies a 16-bit signed value representing the low end of the scroll bar's range.
pOptParam[2]->IconID specifies multiplication factor that is applied to the selected scroll position before its value is displayed. (Usually, this value is 1.)
lParam
pOptParam[0]->lParam is not used.
pOptParam[1]->lParam specifies a 16-bit signed value representing the high end of the scroll bar's range.
pOptParam[2]->lParam specifies the scrolling increment value.
OPTTYPE Structure
Type
TVOT_SCROLLBAR
Count
3
Style
Not used.
BegCtrlID
If pDlgPage in COMPROPSHEETUI identifies a CPSUI-supplied page, or if DlgTemplateID in DLGPAGE identifies a CPSUI-supplied template, BegCtrlID is not used.

Otherwise, BegCtrlID must contain the first control identifier of a sequentially numbered set of control identifiers. Control identifiers must identify the following Windows controls:
Control Identifier | Windows Control
BegCtrlID contents | Group box
BegCtrlID contents+1 | Title text
BegCtrlID contents+2 | Scroll bar
BegCtrlID contents+3 | Scroll bar icon
BegCtrlID contents+4 | Text describing low end of scroll bar range
BegCtrlID contents+5 | Text describing high end of scroll bar range
BegCtrlID contents+6 | Text describing scroll bar units.
BegCtrlID contents+7 | Extended check box or extended push button (optional)
BegCtrlID contents+8 | Extended check box or extended push button icon (optional)

For additional information, see Customizing CPSUI-Supported Window Controls.

Headers

Declared in compstui.h. Include compstui.h.


TVOT_TRACKBAR

The TVOT_TRACKBAR option type consists of a track bar inside a group box.

Type-Specific Use of Structure Members

OPTITEM Structure
Sel/pSel
Value representing the current track bar position.
OPTPARAM Structure Array (pOptParam member of OPTTYPE)
pData
pOptParam[0]->pData points to a NULL-terminated text string identifying the track bar units.
pOptParam[1]->pData points to a NULL-terminated text string describing the low end of the track bar's range.
pOptParam[2]->pData points to a NULL-terminated text string describing the high end of the track bar's range.
IconID
pOptParam[0]->IconID identifies an icon to be associated with the track bar.
pOptParam[1]->IconID specifies a 16-bit signed value representing the low end of the track bar's range.
pOptParam[2]->IconID specifies multiplication factor that is applied to the selected track position before its value is displayed. (Usually, this value is 1.)
lParam
pOptParam[0]->lParam is not used.
pOptParam[1]->lParam specifies a 16-bit signed value representing the high end of the track bar's range.
pOptParam[2]->lParam specifies the tracking increment value.
OPTTYPE Structure
Type
TVOT_TRACKBAR
Count
3
Style
Not used.
BegCtrlID
If pDlgPage in COMPROPSHEETUI identifies a CPSUI-supplied page, or if DlgTemplateID in DLGPAGE identifies a CPSUI-supplied template, BegCtrlID is not used.

Otherwise, BegCtrlID must contain the first control identifier of a sequentially numbered set of control identifiers. Control identifiers must identify the following Windows controls:
Control Identifier | Windows Control
BegCtrlID contents | Group box
BegCtrlID contents+1 | Title text
BegCtrlID contents+2 | Track bar
BegCtrlID contents+3 | Track bar icon
BegCtrlID contents+4 | Text describing low end of track bar range
BegCtrlID contents+5 | Text describing high end of track bar range
BegCtrlID contents+6 | Text describing track bar units.
BegCtrlID contents+7 | Extended check box or extended push button (optional)
BegCtrlID contents+8 | Extended check box or extended push button icon (optional)

For additional information, see Customizing CPSUI-Supported Window Controls.

Headers

Declared in compstui.h. Include compstui.h.


TVOT_UDARROW

The TVOT_UDARROW option type consists of an up-down control and an edit control inside a group box.

Type-Specific Use of Structure Members

OPTITEM Structure
Sel/pSel
Numeric value representing the edit control's current contents.
OPTPARAM Structure Array (pOptParam member of OPTTYPE)
pData
pOptParam[0]->pData points to a NULL-terminated text string identifying the control's units.
pOptParam[1]->pData points to a NULL-terminated text string describing the control. (If NULL, CPSUI displays the low end and high end of the control's range of values.)
IconID
pOptParam[0]->IconID identifies an icon to be associated with the track bar.
pOptParam[1]->IconID specifies a 16-bit signed value representing the low end of the control's range.
lParam
pOptParam[0]->lParam is not used.
pOptParam[1]->lParam specifies a 16-bit signed value representing the high end of the control's range.
OPTTYPE Structure
Type
TVOT_UDARROW
Count
2
Style
Not used.
BegCtrlID
If pDlgPage in COMPROPSHEETUI identifies a CPSUI-supplied page, or if DlgTemplateID in DLGPAGE identifies a CPSUI-supplied template, BegCtrlID is not used.

Otherwise, BegCtrlID must contain the first control identifier of a sequentially numbered set of control identifiers. Control identifiers must identify the following Windows controls:
Control Identifier | Windows Control
BegCtrlID contents | Group box
BegCtrlID contents+1 | Title text
BegCtrlID contents+2 | Edit box
BegCtrlID contents+3 | Icon
BegCtrlID contents+4 | Text describing value units
BegCtrlID contents+5 | Text describing the control
BegCtrlID contents+6 | Up-Down control
BegCtrlID contents+7 | Extended check box or extended push button (optional)
BegCtrlID contents+8 | Extended check box or extended push button icon (optional)

For additional information, see Customizing CPSUI-Supported Window Controls.

Headers

Declared in compstui.h. Include compstui.h.


COM Interfaces for Printer Web Pages

The following Automation interfaces, supplied by oleprn.dll, can be used within ASP files for creating printer Web pages.

IAspHelp Automation Interface

ISNMP Automation Interface

IOleCvt Automation Interface

Active Server Pages (ASP) technology and Automation are described in the Platform SDK documentation. For more information about printer Web pages, see Internet Printing in this DDK.


IAspHelp Automation Interface

The IAspHelp object and automation interface allow an ASP page to obtain properties associated with a specified printer.

The programmatic identifier for the IAspHelp object is OlePrn.AspHelp.

This section provides the following topics:

IAspHelp Methods

IAspHelp Property Get Operations


AspHelp Methods

Previous Next

IAspHelp Methods

This section describes methods defined by the Automation interface for the IAspHelp object.


IAspHelp Close Method

The Close method allows an ASP Web page to close access to a printer.

[id(2), helpstring("method Close")]
  HRESULT
    Close(VOID);

Return Value

The return value is always S_OK.

Comments

The name of the printer being close must have been specified by a previous call to the IAspHelp Open method.

VBScript Example

    Dim objPrinter
    strPrinter = Session("MS_printer")
    Set objPrinter = Server.CreateObject ("OlePrn.AspHelp")
    objPrinter.Open strPrinter
    ...
    objPrinter.Close


IAspHelp Open Method

The Open method allows an ASP Web page to open access to a printer.

[id(1), helpstring("method Open")]
  HRESULT
    Open(
    [in] BSTR  bstrPrinterName
    );

Parameters

bstrPrinterName
Caller-supplied pointer to a string representing a printer name.

Return Value

S_OK The operation succeeded.

Win32 error codes can also be returned.

Comments

The method obtains access to the specified printer by calling the print spooler's OpenPrinter function (described in the Platform SDK documentation). The printer remains open until the IAspHelp Close method is called, or until Open is called again with a different printer name.

VBScript Example

    Dim objPrinter
    strPrinter = Session("MS_printer")
    Set objPrinter = Server.CreateObject ("OlePrn.AspHelp")
    objPrinter.Open strPrinter


IAspHelp Property Get Operations

This section describes the "property get" operations for the ISNMP object.


AspPage

The AspPage property allows an ASP Web page to obtain the directory path to the initial ASP file used for describing printer-specific details.

[propget, id(3), helpstring("property AspPage")]
  HRESULT
    AspPage(
    [in] DWORD  dwPage,
    [out, retval] BSTR  *pVal
    );

Parameters

dwPage
Must be 1.
pVal
Caller-supplied pointer to a location to receive a size-prefixed Unicode string specifying the directory path to the initial Web page describing printer-specific details.

Return Value

S_OK | The operation succeeded.
E_HANDLE | The IAspHelp Open method has not been called.
E_NOTIMPL | An ASP file is not available.
E_POINTER | Invalid pVal pointer.

Comments

The name of the printer being queried must have been specified by a previous call to the IAspHelp Open method.

To determine where to find the page's ASP file, the method uses the algorithm described in Which Printer Details Page is Displayed?.

VBScript Example

    Dim objPrinter, str
    strPrinter = Session("MS_printer")
    Set objPrinter = Server.CreateObject ("OlePrn.AspHelp")
    objPrinter.Open strPrinter
    str = objPrinter.ASPPage(1)


Color

The Color property allows an ASP Web page to determine if a printer supports color printing.

[propget, id(12), helpstring("property Color")]
  HRESULT
    Color(
    [out, retval] BOOL  *pVal
    );

Parameters

pVal
Caller-supplied pointer to a location to receive TRUE if the printer supports color printing, or FALSE if it does not.

Return Value

S_OK | The operation succeeded.
E_HANDLE | The IAspHelp Open method has not been called.
E_OUTOFMEMORY | Out of memory.

Win32 error codes can also be returned.

Comments

The name of the printer being queried must have been specified by a previous call to the IAspHelp Open method.

VBScript Example

    Dim objPrinter, HasColor
    strPrinter = Session("MS_printer")
    Set objPrinter = Server.CreateObject ("OlePrn.AspHelp")
    objPrinter.Open strPrinter
    HasColor = objPrinter.Color


Community

The Community property allows an ASP Web page to obtain a print server's SNMP community name.

[propget, id(4), helpstring("property Community")]
  HRESULT
    Community(
    [out, retval] BSTR  *pVal
    );

Parameters

pVal
Caller-supplied pointer to a location to receive a pointer to a community name string.

Return Value

S_OK | The operation succeeded.
E_HANDLE | The IAspHelp Open method has not been called.
E_OUTOFMEMORY | Out of memory.

Win32 error codes can also be returned.

Comments

The name of the printer being queried must have been specified by a previous call to the IAspHelp Open method.

If the printer is not supported by the TCP/IP port monitor, the returned string is empty.

VBScript Example

    Dim objPrinter, CommName
    strPrinter = Session("MS_printer")
    Set objPrinter = Server.CreateObject ("OlePrn.AspHelp")
    objPrinter.Open strPrinter
    CommName = objPrinter.Community


ComputerName

The ComputerName property allows an ASP Web page to obtain a print server's name.

[propget, id(18), helpstring("property ComputerName")]
  HRESULT
    ComputerName(
    [out, retval] BSTR  *pVal
    );

Parameters

pVal
Caller-supplied pointer to a location to receive a pointer to a computer name string.

Return Value

S_OK | The operation succeeded.
E_OUTOFMEMORY | Out of memory.

VBScript Example

    Dim objPrinter, CompName
    strPrinter = Session("MS_printer")
    Set objPrinter = Server.CreateObject ("OlePrn.AspHelp")
    CompName = objPrinter.ComputerName


DriverName

The DriverName property allows an ASP Web page to obtain the name of the printer driver.

[propget, id(32), helpstring("property Model")]
  HRESULT
    DriverName(
    [out, retval] BSTR  *pVal
    );

Parameters

pVal
Caller-supplied pointer to a location to receive a pointer to a driver name string.

Return Value

S_OK | The operation succeeded.
E_HANDLE | The IAspHelp Open method has not been called.
E_OUTOFMEMORY | Out of memory.

Win32 error codes can also be returned.

Comments

The name of the printer being queried must have been specified by a previous call to the IAspHelp Open method.

VBScript Example

    Dim objPrinter, DrvrName
    strPrinter = Session("MS_printer")
    Set objPrinter = Server.CreateObject ("OlePrn.AspHelp")
    objPrinter.Open strPrinter
    DrvrName = objPrinter.DriverName


Duplex

The Duplex property allows an ASP Web page to determine if a printer supports duplex printing.

[propget, id(13), helpstring("property Duplex")]
  HRESULT
    Duplex(
    [out, retval] BOOL  *pVal
    );

Parameters

pVal
Caller-supplied pointer to a location to receive TRUE if the printer supports duplex printing, or FALSE if it does not.

Return Value

S_OK | The operation succeeded.
E_HANDLE | The IAspHelp Open method has not been called.
E_OUTOFMEMORY | Out of memory.

Win32 error codes can also be returned.

Comments

The name of the printer being queried must have been specified by a previous call to the IAspHelp Open method.

VBScript Example

    Dim objPrinter, DoesDuplex
    strPrinter = Session("MS_printer")
    Set objPrinter = Server.CreateObject ("OlePrn.AspHelp")
    objPrinter.Open strPrinter
    DoesDuplex = objPrinter.Duplex


IPAddress

The IPAddress property allows an ASP Web page to obtain a printer's IP address.

[propget, id(10), helpstring("property IPAddress")]
  HRESULT
    IPAddress(
    [out, retval] BSTR  *pVal
    );

Parameters

pVal
Caller-supplied pointer to a location to receive a pointer to an IP address string.

Return Value

S_OK | The operation succeeded.
E_HANDLE | The IAspHelp Open method has not been called.
E_OUTOFMEMORY | Out of memory.

Win32 error codes can also be returned.

Comments

The name of the printer being queried must have been specified by a previous call to the IAspHelp Open method.

If the printer is not supported by the TCP/IP port monitor, the returned string is empty.

VBScript Example

    Dim objPrinter, PrinterIP
    strPrinter = Session("MS_printer")
    Set objPrinter = Server.CreateObject ("OlePrn.AspHelp")
    objPrinter.Open strPrinter
    PrinterIP = objPrinter.IPAddress


IsTCPMonSupported

The IsTCPMonSupported property allows an ASP Web page to determine if Microsoft's standard TCP/IP port monitor is being used with a printer.

[propget, id(11), helpstring("property IsTCPMonSupported")]
  HRESULT
    IsTCPMonSupported(
    [out, retval] BOOL  *pVal
    );

Parameters

pVal
Caller-supplied pointer to a location to receive TRUE if the TCP/IP port monitor is being used with the printer, or FALSE if it is not.

Return Value

S_OK | The operation succeeded.
E_HANDLE | The IAspHelp Open method has not been called.
E_OUTOFMEMORY | Out of memory.

Win32 error codes can also be returned.

Comments

The name of the printer being queried must have been specified by a previous call to the IAspHelp Open method.

VBScript Example

    Dim objPrinter, UseStdMon
    strPrinter = Session("MS_printer")
    Set objPrinter = Server.CreateObject ("OlePrn.AspHelp")
    objPrinter.Open strPrinter
    UseStdMon = objPrinter.IsTCPMonSupported


LongPaperName

The LongPaperName property allows an ASP Web page to convert a short paper name to a long paper name.

[propget, id(19), helpstring("property LongPaperName")]
  HRESULT
    LongPaperName(
    [in] BSTR  bstrShortName,
    [out, retval] BSTR  *pVal
    );

Parameters

bstrShortName
Caller-supplied pointer to a string representing a short paper name.
pVal
Caller-supplied location to receive a pointer to a string representing a long paper name.

Return Value

S_OK | The operation succeeded.
E_OUTOFMEMORY | Out of memory.

Win32 error codes can also be returned.

Comments

VBScript Example

    Dim objPrinter, LongName
    Set objPrinter = Server.CreateObject ("OlePrn.AspHelp")
    LongName = objPrinter.LongPaperName("iso-a0")


MaximumResolution

The MaximumResolution property allows an ASP Web page to determine a printer's maximum resolution.

[propget, id(14), helpstring("property MaximumResolution")]
  HRESULT
    MaximumResolution(
    [out, retval] long  *pVal
    );

Parameters

pVal
Caller-supplied location to receive a numeric value representing the printer's maximum resolution, in dots per inch.

Return Value

S_OK | The operation succeeded.
E_HANDLE | The IAspHelp Open method has not been called.
E_OUTOFMEMORY | Out of memory.

Win32 error codes can also be returned.

Comments

The name of the printer being queried must have been specified by a previous call to the IAspHelp Open method.

VBScript Example

    Dim objPrinter, MaxRes
    strPrinter = Session("MS_printer")
    Set objPrinter = Server.CreateObject ("OlePrn.AspHelp")
    objPrinter.Open strPrinter
    MaxRes = objPrinter.MaximumResolution


MibErrorDscp

The MibErrorDscp property allows an ASP Web page to convert an SNMP MIB error code into a text description of the error.

[propget, id(22), helpstring("property MibErrorDscp")]
  HRESULT
    MibErrorDscp(
    [in] DWORD  dwError,
    [out, retval] BSTR  *pVal
    );

Parameters

dwError
Caller-supplied SNMP MIB error code.
pVal
Caller-supplied location to receive a pointer to a string containing a text description of the error.

Return Value

S_OK | The operation succeeded.
E_OUTOFMEMORY | Out of memory.

Win32 error codes can also be returned.

Comments

VBScript Example

    Dim objPrinter, MIBErrorCode, MIBErrorString
    Set objPrinter = Server.CreateObject ("OlePrn.AspHelp")
    ...
    Get error code from MIB.
    ...
    MIBErrorString = objPrinter.MibErrorDscp(ErrorCodeMIB)


PageRate

The PageRate property allows an ASP Web page to determine a printer's page rate.

[propget, id(17), helpstring("property PageRate")]
  HRESULT
    PageRate(
    [out, retval] long  *pVal
    );

Parameters

pVal
Caller-supplied location to receive a numeric value representing the printer's page rate, in pages per minute.

Return Value

S_OK | The operation succeeded.
E_HANDLE | The IAspHelp Open method has not been called.
E_OUTOFMEMORY | Out of memory.

Win32 error codes can also be returned.

Comments

The name of the printer being queried must have been specified by a previous call to the IAspHelp Open method.

VBScript Example

    Dim objPrinter, PtrPageRate
    strPrinter = Session("MS_printer")
    Set objPrinter = Server.CreateObject ("OlePrn.AspHelp")
    objPrinter.Open strPrinter
    PtrPageRate = objPrinter.PageRate


PaperNames

The PaperNames property allows an ASP Web page to obtain a set of strings representing all the printer's paper forms.

[propget, id(16), helpstring("property PaperNames")]
  HRESULT
    PaperNames(
    [out, retval] VARIANT  *pVal
    );

Parameters

pVal
Caller-supplied location to receive a pointer to a set of strings representing all the printer's paper forms.

Return Value

S_OK | The operation succeeded.
E_HANDLE | The IAspHelp Open method has not been called.
E_OUTOFMEMORY | Out of memory.

Win32 error codes can also be returned.

Comments

The name of the printer being queried must have been specified by a previous call to the IAspHelp Open method.

The list of paper forms is obtained by calling the printer driver's DrvDeviceCapabilities function with the DC_PAPERNAMES flag set.

VBScript Example

    Dim objPrinter, PaperNameArray
    strPrinter = Session("MS_printer")
    Set objPrinter = Server.CreateObject ("OlePrn.AspHelp")
    objPrinter.Open strPrinter
    PaperNameArray = objPrinter.PaperNames


PortName

The Portname property allows an ASP Web page to obtain a printer's port name.

[propget, id(21), helpstring("property Portname")
  HRESULT
    PortName(
    [out, retval] BSTR  *pVal
    );

Parameters

pVal
Caller-supplied location to receive a pointer to a string representing the printer's port name.

Return Value

S_OK | The operation succeeded.
E_HANDLE | The IAspHelp Open method has not been called.
E_OUTOFMEMORY | Out of memory.

Win32 error codes can also be returned.

Comments

The name of the printer being queried must have been specified by a previous call to the IAspHelp Open method.

VBScript Example

    Dim objPrinter, PtrPortName
    strPrinter = Session("MS_printer")
    Set objPrinter = Server.CreateObject ("OlePrn.AspHelp")
    objPrinter.Open strPrinter
    PtrPortName = objPrinter.PortName


ShareName

The ShareName property allows an ASP Web page to obtain the printer's shared name.

[propget, id(32), helpstring("property ShareName")]
  HRESULT
    ShareName(
    [out, retval] BSTR  *pVal
    );

Parameters

pVal
Caller-supplied pointer to a location to receive a pointer to a share name string.

Return Value

S_OK | The operation succeeded.
E_HANDLE | The IAspHelp Open method has not been called.
E_OUTOFMEMORY | Out of memory.

Win32 error codes can also be returned.

Comments

The name of the printer being queried must have been specified by a previous call to the IAspHelp Open method.

VBScript Example

    Dim objPrinter, DrvrName
    strPrinter = Session("MS_printer")
    Set objPrinter = Server.CreateObject ("OlePrn.AspHelp")
    objPrinter.Open strPrinter
    DrvrName = objPrinter.ShareName


SNMPDevice

The SNMPDevice property allows an ASP Web page to obtain a printer's SNMP device index (as defined by RFC 1759).

[propget, id(5), helpstring("property SNMPDevice")]
  HRESULT
    SNMPDevice(
    [out, retval] DWORD  *pVal
    );

Parameters

pVal
Caller-supplied location to receive a numeric value representing the printer's SNMP device index.

Return Value

S_OK | The operation succeeded.
E_HANDLE | The IAspHelp Open method has not been called.
E_OUTOFMEMORY | Out of memory.

Win32 error codes can also be returned.

Comments

The name of the printer being queried must have been specified by a previous call to the IAspHelp Open method.

VBScript Example

    Dim objPrinter, SNMPDeviceIndex
    strPrinter = Session("MS_printer")
    Set objPrinter = Server.CreateObject ("OlePrn.AspHelp")
    objPrinter.Open strPrinter
    SNMPDeviceIndex = objPrinter.SNMPDevice


SNMPSupported

The SNMPSupported property allows an ASP Web page to determine if SNMP is being used with a printer.

[propget, id(6), helpstring("property SNMPSupported")]
  HRESULT
    SNMPSupported(
    [out, retval] BOOL  *pVal
    );

Parameters

pVal
Caller-supplied pointer to a location to receive TRUE if SNMP is being used with the printer, or FALSE if it is not.

Return Value

S_OK | The operation succeeded.
E_HANDLE | The IAspHelp Open method has not been called.
E_OUTOFMEMORY | Out of memory.

Win32 error codes can also be returned.

Comments

The name of the printer being queried must have been specified by a previous call to the IAspHelp Open method.

VBScript Example

    Dim objPrinter, UsingSNMP
    strPrinter = Session("MS_printer")
    Set objPrinter = Server.CreateObject ("OlePrn.AspHelp")
    objPrinter.Open strPrinter
    UsingSNMP = objPrinter.SNMPSupported


ISNMP Automation Interface

The ISNMP object and Automation interface are available for use with printers that use Microsoft's standard TCIP/IP port monitor. They allow an ASP page to set and retrieve values associated with SNMP OIDs.

The programmatic identifier for the ISNMP object is OlePrn.OleSNMP.


ISNMP Automation Methods

This section describes the Automation interface for the ISNMP object.


ISNMP Close Method

The Close method allows an ASP Web page to close a communication path to an SNMP agent.

[id(5), helpstring("method Close")]
  HRESULT
    Close(VOID);

Return Value

The method always returns S_OK.

Comments

The method closes the communication path that was created by the last call to the ISNMP Open method. It calls SnmpMgrClose, which is described in the Platform SDK documentation.

VBScript Example

    Dim StrIP, strCommunity, objSNMP
    strIP = Session("MS_IPaddress")
    strCommunity = Session ("MS_Community")
    Set objSNMP = Server.CreateObject("OlePrn.OleSNMP")
    objSNMP.Open strIP, strCommunity, 2, 1000
    ...
    objSNMP.Close


ISNMP Get Method

The Get method allows an ASP Web page to obtain the value associated with an SNMP OID.

[id(2), helpstring("method Get")]
  HRESULT
    Get(
    [in] BSTR  bstrOID,
    [out,retval]VARIANT  *varValue
    );

Parameters

bstrOID
Caller-supplied pointer to an OID string.
varValue
Caller-supplied location to receive the OID's value.

Return Value

S_OK | The operation succeeded.
E_FAIL | The ISNMP Open method has not been called.
E_INVALIDARG | The specified OID is invalid.
E_OUTOFMEMORY | Out of memory.

Win32 error codes can also be returned.

Comments

The ISNMP Open method must be called before the Get method can be called. The method calls SnmpMgrRequest (described in the Platform SDK documentation) to obtain OID values.

VBScript Example

    Dim StrIP, strCommunity, objSNMP, OIDValue
    strIP = Session("MS_IPaddress")
    strCommunity = Session ("MS_Community")
    Set objSNMP = Server.CreateObject("OlePrn.OleSNMP")
    objSNMP.Open strIP, strCommunity, 2, 1000
    OIDValue = objSNMP.Get ("43.18.1.1.2")


ISNMP GetList Method

The GetList method allows an ASP Web page to obtain the values associated with an array of SNMP OIDs.

[id(3), helpstring("method GetList")]
  HRESULT
    GetList(
    [in]VARIANT  *varList,
    [out,retval]VARIANT  *varValue
    );

Parameters

varList
Caller-supplied pointer to an array of OID strings.
varValue
Caller-supplied location to receive the address of an array of OID values.

Return Value

S_OK | The operation succeeded.
E_FAIL | The ISNMP Open method has not been called.
E_INVALIDARG | The specified OID is invalid.
E_OUTOFMEMORY | Out of memory.

Win32 error codes can also be returned.

Comments

The ISNMP Open method must be called before the GetList method can be called. The method calls SnmpMgrRequest (described in the Platform SDK documentation) to obtain OID values.

VBScript Example

    Dim StrIP, strCommunity, objSNMP, OIDArray, OIDValueArray
    strIP = Session("MS_IPaddress")
    strCommunity = Session ("MS_Community")
    Set objSNMP = Server.CreateObject("OlePrn.OleSNMP")
    objSNMP.Open strIP, strCommunity, 2, 1000
    OIDArray = Array("25.3.2.1.5", "25.3.5.1.1")
    OIDValueArray = objSNMP.GetList (OIDArray)


ISNMP GetTree Method

The GetTree method allows an ASP Web page to obtain the values associated with a set of sub-nodes beneath a specified root OID.

[id(4), helpstring("method GetTree")]
  HRESULT
    GetTree(
    [in] BSTR  varTree,
    [out,retval]VARIANT  *varValue
    );

Parameters

varTree
Caller-supplied string identifying a root OID.
varValue
Caller-supplied location to receive the address of an two-dimensional array containing OID strings and associated values.

Return Value

S_OK | The operation succeeded.
E_FAIL | The ISNMP Open method has not been called.
E_INVALIDARG | The specified OID is invalid.
E_OUTOFMEMORY | Out of memory.

Win32 error codes can also be returned.

Comments

The ISNMP Open method must be called before the GetTree method can be called. The method calls SnmpMgrRequest (described in the Platform SDK documentation) to obtain OID values.

VBScript Example

    Dim StrIP, strCommunity, objSNMP, OIDValueArray
    strIP = Session("MS_IPaddress")
    strCommunity = Session ("MS_Community")
    Set objSNMP = Server.CreateObject("OlePrn.OleSNMP")
    objSNMP.Open strIP, strCommunity, 2, 1000
    OIDValueArray = objSNMP.GetTree ("43.18.1.1.2")


ISNMP OIDFromString Method

The OIDFromString method allows an ASP Web page to convert an OID string into a numeric array.

[id(6), helpstring("method OIDFromString")]
  HRESULT
    OIDFromString(
    [in] BSTR  bstrOID,
    [out, retval]VARIANT  *varOID
    );

Parameters

bstrOID
Caller-supplied pointer to an OID string.
varOID
Caller-supplied location to receive a pointer to an array of integer values representing the OID.

Return Value

S_OK | The operation succeeded.
E_INVALIDARG | The specified OID is invalid.
E_OUTOFMEMORY | Out of memory.

Win32 error codes can also be returned.

Comments

VBScript Example

    Dim StrIP, strCommunity, objSNMP, OIDArray
    strIP = Session("MS_IPaddress")
    strCommunity = Session ("MS_Community")
    Set objSNMP = Server.CreateObject("OlePrn.OleSNMP")
    objSNMP.Open strIP, strCommunity, 2, 1000
    OIDArray = objSNMP.OIDFromString ("43.18.1.1.2")


ISNMP Open Method

The Open method allows an ASP Web page to create a communication path to a specified SNMP agent.

[id(1), helpstring("method Open")]
  HRESULT
    Open(
    [in] BSTR  bstrHost,
    [in] BSTR  bstrCommunity,
    [in,optional] VARIANT  varRetry,
    [in,optional] VARIANT  varTimeout
    );

Parameters

bstrHost
Caller-supplied pointer to a string identifying the SNMP agent system. This can be either a dotted-decimal IP address or a host name that can be resolved to an IP address, an IPX address (in 8.12 notation), or an ethernet address.
bstrCommunity
Caller-supplied pointer to a string representing the SNMP agent system's community name.
varRetry
Optional, caller-supplied retry value. If not specified, a default value is used. The recommended value is 2.
varTimeout
Optional, caller-supplied time-out value, in milliseconds. If not specified, a default value is used. The recommended value is 1000.

Return Value

S_OK | The operation succeeded.
E_INVALIDARG | Either the varRetry or varTimeOut value could not be converted to a short integer.
E_FAIL | The call to SnmpMgrOpen failed.

Comments

The Open method calls SnmpMgrOpen, which is described in the Platform SDK documentation and has the same parameters as Open.

The communication path remains open until the ISNMP Close method is called, or until Open is called again.

VBScript Example

    Dim StrIP, strCommunity, objSNMP
    strIP = Session("MS_IPaddress")
    strCommunity = Session ("MS_Community")
    Set objSNMP = Server.CreateObject("OlePrn.OleSNMP")
    objSNMP.Open strIP, strCommunity, 2, 1000


ISNMP Set Method

The Set method allows an ASP Web page to associate a value with an SNMP OID.

[id(7), helpstring("method Set")]
  HRESULT
    Set(
    [in] BSTR  bstrOID,
    [in] VARIANT  varValue
    );

Parameters

bstrOID
Caller-supplied pointer to an OID string.
varValue
Caller-supplied location containing the OID's value.

Return Value

S_OK | The operation succeeded.
E_FAIL | The ISNMP Open method has not been called.
E_INVALIDARG | The specified OID is invalid.
E_OUTOFMEMORY | Out of memory.

Win32 error codes can also be returned.

Comments

The ISNMP Open method must be called before the Set method can be called. The method calls SnmpMgrRequest (described in the Platform SDK documentation) to set OID values.

VBScript Example

    Dim StrIP, strCommunity, objSNMP, OIDValue
    strIP = Session("MS_IPaddress")
    strCommunity = Session ("MS_Community")
    Set objSNMP = Server.CreateObject("OlePrn.OleSNMP")
    objSNMP.Open strIP, strCommunity, 2, 1000
    ...
    Determine value to assign to OID, store in OIDValue.
    ...
    objSNMP.Set ("43.18.1.1.2", OIDValue)


ISNMP SetList Method

The SetList method allows an ASP Web page to associate values with an array of SNMP OIDs.

[id(8), helpstring("method SetList")]
  HRESULT
    SetList(
    [in] VARIANT  *varName,
    [in] VARIANT  *varValue
    );

Parameters

varName
Caller-supplied pointer to an array of OID strings.
varValue
Caller-supplied pointer to an array of OID values.

Return Value

S_OK | The operation succeeded.
E_FAIL | The ISNMP Open method has not been called.
E_INVALIDARG | The specified OID is invalid.
E_OUTOFMEMORY | Out of memory.

Win32 error codes can also be returned.

Comments

The ISNMP Open method must be called before the SetList method can be called. The method calls SnmpMgrRequest (described in the Platform SDK documentation) to set OID values.

VBScript Example

    Dim StrIP, strCommunity, objSNMP, OIDArray, OIDValueArray
    strIP = Session("MS_IPaddress")
    strCommunity = Session ("MS_Community")
    Set objSNMP = Server.CreateObject("OlePrn.OleSNMP")
    objSNMP.Open strIP, strCommunity, 2, 1000
    OIDArray = Array("25.3.2.1.5", "25.3.5.1.1")
    ...
    Determine values to assign to OIDs, store in OIDArray.
    ...
    OIDValueArray = objSNMP.SetList (OIDArray)


IOleCvt Automation Interface

The IOleCvt object and automation interface allow an ASP page to perform a variety of string conversions from one format to another. These include:

  • conversion from Unicode to ANSI
  • conversion from ANSI to Unicode
  • conversion from Unicode to UTF8 (UCS Transformation Format - 8)
  • conversion from Unicode using one code page to Unicode using another code page

The programmatic identifier for the IOleCvt object is OlePrn.OleCvt.


IOleCvt Property Get Operations

This section describes the "property get" operations for the IOleCvt object.


DecodeUnicodeName

The DecodeUnicodeName property translates a Unicode string to its ANSI equivalent.

[propget, id(3), helpstring("property DecodeUnicodeName")]
  HRESULT
    DecodeUnicodeName(
    [in] BSTR  bstrSrcName,
    [out, retval] BSTR  *pVal
    );

Parameters

bstrSrcName
Caller-supplied Unicode string to be translated.
pVal
Caller-supplied pointer to a location to receive the translated string.

Return Value

S_OK | The operation succeeded.
E_POINTER | At least one of the parameters does not point to a valid memory location.

VBScript Example

    Dim OleCvt, strPrinter, strEncodedPrinter
    Set OleCvt = Server.CreateObject("OlePrn.OleCvt")
    strEncodedPrinter = Request ( "eprinter" )
    strPrinter = OleCvt.DecodeUnicodeName (strEncodedPrinter)


EncodeUnicodeName

The EncodeUnicodeName property translates an ANSI string to its Unicode equivalent.

[propget, id(2), helpstring("property EncodeUnicodeName")]
  HRESULT
    EncodeUnicodeName(
    [in] BSTR  bstrSrcName,
    [out, retval] BSTR  *pVal
    );

Parameters

bstrSrcName
Caller-supplied ANSI string to be translated.
pVal
Caller supplied pointer to a location that will receive the translated string.

Return Value

S_OK | The operation succeeded.
E_POINTER | At least one of the parameters does not point to a valid memory location.

VBScript Example

    Dim OleCvt, strPrinter, strEncodedPrinter
    Set OleCvt = Server.CreateObject("OlePrn.OleCvt")
    strMyUrl = "MyPage.asp?MyVariable=" &
                OleCvt.EncodeUnicodeName("My&Unicode&Parameter")


ToUtf8

The ToUtf8 property translates a string of Unicode characters to the UTF8 format.

[propget, id(1), helpstring("property ToUtf8")]
  HRESULT
    ToUtf8(
    [in] BSTR  bstrUnicode,
    [out, retval] BSTR  *pVal
    );

Parameters

bstrUnicode
Caller-supplied string to be converted to UTF8 format.
pVal
Caller supplied pointer to a location that will receive the converted string.

Return Value

S_OK | The operation succeeded.
E_POINTER | At least one of the parameters does not point to a valid memory location.

Comments

UTF8 is an alternative coded-representation form for all of the characters of the UCS (Universal Multibyte Octet-Coded Character Set). It can be used to transmit text data through communication systems which assume that individual octets in the range 0x00 to 0x7F have a definition according to ISO/IEC 4873, including a C0 set of control functions according to the 8-bit structure of ISO/IEC 2022.

VBScript Example

    Function Write returns a string converted to
    UTF8 format, if global variable bUTF8 is TRUE.
    Otherwise Write returns the unmodified string.
    Function Write (strUnicode)
        If bUTF8 Then
            Write = OleCvt.ToUtf8 (strUnicode)
        Else
            Write = strUnicode
        End If
    End Function


ToUnicode

The ToUnicode property allows an ASP Web page to convert one Unicode string to another using a specified code page.

[propget, id(4), helpstring("property ToUnicode")]
  HRESULT
    ToUnicode(
    [in] BSTR  bstrString,
    [in] long  lCodePage,
    [out, retval] BSTR  *pVal
    );

Parameters

bstrString
Caller-supplied string to be converted.
lCodePage
Caller-supplied code page to use for the conversion.
pVal
Caller-supplied pointer to a location to receive the converted Unicode string.

Return Value

S_OK | The operation succeeded.
E_POINTER | pVal does not point to a valid memory location.

VBScript Example

Convert using Japanese code page, if applicable
If strLang = "JP" Then
    tmpStr = OleCvt.ToUnicode (str, 932)
Else
    tmpStr = str
End If


USBPRINT I/O Control Codes

This section provides information about two I/O control codes used to communicate with USBPRINT:

IOCTL_USBPRINT_VENDOR_GET_COMMAND

IOCTL_USBPRINT_VENDOR_SET_COMMAND


IOCTL_USBPRINT_VENDOR_GET_COMMAND

Operation

The IOCTL_USBPRINT_VENDOR_GET_COMMAND request allows upper-layer software (such as a language monitor), to issue a vendor-specific GET command to the target device.

Input

The Irp->Parameters.DeviceIoControl.OutputBufferLength member specifies the size, in bytes, of the buffer passed in the Irp->AssociatedIrp.SystemBuffer member, containing the vendor-specific GET command.

The Irp->AssociatedIrp.SystemBuffer member contains parameters packed together as an array. Interpreted as an array of bytes, the buffer contains the following elements:

Array Element | Contents
SystemBuffer[0] | Vendor Request code
SystemBuffer[1] | Vendor Request value - Most Significant Byte
SystemBuffer[2] | Vendor Request value - Least Significant Byte

Output

The Irp->AssociatedIrp.SystemBuffer member points to a buffer that contains data read from the device.

I/O Status Block

If the request is successful, the Information member is set to the size, in bytes, of a buffer that holds the data read from the device. Otherwise, the Information member is set to zero.

The Status member is set to STATUS_SUCCESS if the request is successful. Otherwise, it is set to an appropriate error condition, such as STATUS_INVALID_PARAMETER or STATUS_NO_MEMORY.

Headers

Declared in ioctl.h. Include ioctl.h.

See Also

IOCTL_USBPRINT_VENDOR_SET_COMMAND


IOCTL_USBPRINT_VENDOR_SET_COMMAND

Operation

The IOCTL_USBPRINT_VENDOR_SET_COMMAND request allows upper-layer software (such as a language monitor) to issue a vendor-specific SET command to the target device.

Input

The Irp->Parameters.DeviceIoControl.OutputBufferLength member specifies the size, in bytes, of the buffer passed in the Irp->AssociatedIrp.SystemBuffer member, containing the vendor-specific SET command.

The Irp->AssociatedIrp.SystemBuffer member contains parameters packed together as an array. Interpreted as an array of bytes, the buffer contains the following:

Array Element | Contents
SystemBuffer[0] | Vendor Request code
SystemBuffer[1] | Vendor Request value - Most Significant Byte
SystemBuffer[2] | Vendor Request value - Least Significant Byte
SystemBuffer[3...] | Request-specific data to be sent to the device

Output

None

Status Block

The Information member is set to zero.

The Status member is set to STATUS_SUCCESS if the request is successful. Otherwise, it is set to an appropriate error condition, such as STATUS_INVALID_PARAMETER or STATUS_NO_MEMORY.

Headers

Declared in ioctl.h. Include ioctl.h.

See Also

IOCTL_USBPRINT_VENDOR_GET_COMMAND


Windows Input Architecture

This section describes the following topics about the Microsoft® Windows® input architecture:

System-Supplied Components for Input Devices

Driver Stacks for HID Devices

Driver Stacks for Non-HID Keyboard and Mouse Devices

Driver Stacks for Non-HID Game Port Devices

Driver Stacks for Miscellaneous Non-HID Input Devices

Required Vendor-Supplied Drivers

Keyboard Layout

For more information about the input architecture, see:

HID Driver Overview

HID Clients

Keyboard and Mouse Drivers for Non-HID Devices

Check the Web site

Also see the following Web site, which provides additional information about Microsoft requirements for input device hardware and drivers.

http://www.microsoft.com/hwdev/input


System-Supplied Components for Input Devices

This section describes the system-supplied components for input devices.

To modularize and streamline input processing, the Microsoft® Windows® input architecture is based on the USB HID standard. The Human Interface Device (HID) standard includes keyboards, mouse and pointing devices, joysticks, gamepads, and other types of game controllers. The input architecture integrates HID and non-HID input devices.

The Windows input architecture supports the following features for HID devices:

  • The design of the system-supplied HID class driver uses minidrivers to operate devices.

    This design makes it possible for the HID class driver to operate both USB HID devices and non-HID input devices attached to buses or ports other than a USB bus. Examples of such non-HID input devices include keyboard, mouse, and game port devices.

    The system-supplied USB HID minidriver provides the interface to operate devices attached to a USB port.

  • Vendor-supplied drivers are not required for HID devices.
  • The architecture provides HID support routines for clients that user-mode applications and kernel-mode drivers use to operate HID devices. Clients can also operate non-HID input devices that are accessed through a HID minidriver.
  • The architecture uses HID mapper drivers to provide an interface between the HID class drivers and the non-HID class drivers for keyboard, mouse, and game port devices.

In addition to support for HID devices, the input architecture provides class drivers and driver stacks for non-HID keyboard, mouse, and game port devices.

The input architecture in Windows 2000 and later supplies the following drivers for input devices.

Device Type | Class Driver | Related Drivers
USB HID class device | HID class driver, hidclass.sys. | HID minidriver, usbhid.sys, and the lower-level USB driver stack.
HID keyboard and mouse devices | Class drivers, kbdclass.sys and mouclass.sys. | HID mapper drivers, kbdhid.sys and mouhid.sys.
Non-HID keyboard and mouse devices | Class drivers, kbdclass.sys and mouclass.sys. | Lower-level driver stacks for i8042 and serial ports.
Non-HID game port devices | HID class driver, hidclass.sys. | HID minidriver, hidgame.sys, and the lower-level non-USB driver stack for game port devices.
Non-HID device (other than keyboard, mouse, or a game port device) | HID class driver, hidclass.sys. | A vendor-function driver is not required. A vendor-supplied HID minidriver is required.

The input architecture in Windows Millennium Edition supplies the following drivers for input devices.

Device Type | Class Driver | Related Drivers
USB HID class device | HID class driver, hidclass.sys. | HID minidriver, usbhid.sys, and lower-level driver stack.
HID keyboard and mouse devices | Device class drivers, vkd.vxd and vmd.vxd. | HID mapper drivers, kbdhid.vxd and mouhid.vxd.
HID game port device | Joystick class driver, vjoyd.vxd. | HID mapper driver, joyhid.vxd.
Non-HID keyboard and mouse device | Device class drivers, vkd.vxd and vmd.vxd. | Lower-level minidrivers for i8042 and serial ports.
Non-HID game port device | Joystick class driver, vjoyd.vxd. | Lower-level minidrivers for game ports.
Non-HID device (other than keyboard, mouse, or a game port device) | HID class driver, hidclass.sys. | A vendor-supplied function driver is not required. A vendor-supplied HID minidriver is required.

For more information about the system-supplied components, see the following topics:

Components for HID Devices

Drivers for Non-HID Input Devices

User-Mode Components That Support Input Devices

For more information about the system-supplied driver stacks for input devices, see the following topics:

Driver Stacks for HID Devices

Driver Stacks for Non-HID Keyboard and Mouse Devices

Driver Stacks for Non-HID Game Port Devices

Driver Stacks for Miscellaneous Non-HID Input Devices

For more information about the device stacks for input devices, see the following topics:

Microsoft Windows HID Device Stacks

Types of HID Clients

Keyboard and Mouse Drivers for Non-HID Devices

Serial Devices and Drivers


Components for HID Devices

This section describes the following components that support Windows input devices that comply with the USB HID standard:

HID Class Driver

USB HID Minidriver

HID Mapper Drivers

HID Support Routines


HID Class Driver

The design of the system-supplied HID class driver uses minidrivers to operate devices. This design makes it possible for the HID class driver to operate both HID devices and non-HID devices attached to ports or buses other than USB.

The HID class driver routes and manages communication between HID clients and HID minidrivers. The HID class driver also manages input queues that allow several processes to have handles open on the same HID class device. A HID minidriver provides an interface between a device's lower-level driver stack and the HID class driver. The executable image of the HID class driver is hidclass.sys.

The HID class driver manages the different data protocols used by the input devices in the system. It obtains a device's protocol information by querying a device's hardware. Report descriptors specify the data protocol used in HID reports. HID reports are used to input and output data for a device.

The HID class driver obtains and parses a device's report descriptor as soon as the system detects the device. User-mode and kernel-mode clients can access report descriptor data in a standard preparsed data format.

For information about obtaining and interpreting preparsed data, see Initializing and Connecting a HID Client.

In addition to managing HID data protocols, the HID class driver routes report information to and from the appropriate port or bus driver stack in a manner that is transparent to the HID client.

Non-USB devices, such as game port and serial port devices, can also be operated by the HID class driver, provided a HID minidriver is supplied to operate the port or bus.

For more information about driver stacks that use the HID class driver, see:

Driver Stacks for HID Devices

Driver Stacks for non-HID Game Port Devices

Driver Stacks for Miscellaneous Non-HID Input Devices

When Do I Write a HID Minidriver?


USB HID Minidriver

The system-supplied USB HID minidriver sends and receives HID reports over the USB bus. The executable image of the USB HID minidriver is usbhid.sys.

For more information about HID minidrivers, see:

Driver Stacks for HID Devices

HID Minidrivers for Non-HID Input Devices

When Do I Write a HID Minidriver?


HID Mapper Drivers

This section describes the HID mapper drivers supplied by Microsoft® Windows®. A HID mapper driver is a kernel-mode filter driver that provides a bidirectional interface for I/O requests between a non-HID class driver and the HID class driver. The mapper driver maps the I/O requests and data protocols of one to the other.

The system-supplied HID mapper drivers for HID keyboard, mouse, and game port devices are as follows.

Windows Version | Keyboard | Mouse | Game Port
Windows 2000 and later | kbdhid.sys | mouhid.sys | None
Windows Me | kbdhid.vxd | mouhid.vxd | joyhid.vxd

  • For more information about HID mapper drivers, see:

    Driver Stacks for HID Devices

    Microsoft Windows HID Device Stacks


HID Support Routines

Clients use HID support routines for clients to interpret the preparsed data that describes HID report data associated with a HID collection. The HID support routines do not use I/O requests to interpret the preparsed data. To access the HID support routines, a client links to one of the system-supplied DLLs (user-mode components link to hid.dll and kernel-mode drivers link to hidparse.sys).

In addition to parsing services, hid.dll exports routines that use I/O requests to communicate with the HID class driver. For example, HidD_FlushQueue flushes the class driver's ring buffers, and HidD_GetPreparsedData queries the HID class driver for a particular collection's preparsed data.

Both hid.dll and hidparse.sys contain a set of routines named HidP_Xxx that interpret preparsed data. Only hid.dll has routines named HidD_Xxx, which communicate with devices by using I/O requests. Kernel-mode drivers that need the functionality of the HidD_Xxx routines must send equivalent I/O requests to a device. For example, user-mode clients use HidD_GetPreparsedData to obtain preparsed data about a device. Kernel-mode drivers, on the other hand, use an IOCTL_HID_GET_COLLECTION_DESCRIPTOR request to obtain preparsed data.

Upon obtaining preparsed data, a user-mode client extracts information from it by calling the HidP_Xxx routines exported by hid.dll. Kernel-mode drivers call routines of the same name exported by hidparse.sys.


Drivers for Non-HID Input Devices

This section describes the following drivers:

HID Minidrivers for Non-HID Input Devices

Class Drivers for Non-HID Input Devices


HID Minidrivers for Non-HID Input Devices

This section describes the system-supplied HID minidrivers and driver stacks for non-HID input devices.

Microsoft® Windows® 2000 and later supplies the following drivers:

  • The HID minidriver for game port (I/O port 201) devices, hidgame.sys.

    The HID class driver communicates with the non-HID devices as if they are USB HID devices.

  • The game port bus driver, gamenum.sys.

    The game port bus driver creates a physical device object (PDO) for each game port device that is daisy-chained to a game port.

Windows Me only supplies a USB HID minidriver.

For information about the HID minidriver stacks for non-HID input devices in Windows 2000 and later, see:

Driver Stacks for Non-HID Game Port Devices

Driver Stacks for Miscellaneous Non-HID Input Devices


Class Drivers for Non-HID Input Devices

This section describes the class drivers and lower-level drivers for non-HID input devices.

Microsoft® Windows® 2000 and later supplies the following drivers for non-HID keyboard and mouse devices.

Device Type | Driver
Keyboard | Class driver, kbdclass.sys
Mouse | Class driver, mouclass.sys
PS/2 (i8042) port | Function driver, i8042prt.sys
Serial port | Function driver, serial.sys, and filter driver, serenum.sys

For more information about the system-supplied keyboard and mouse drivers in Windows 2000 and later, see Keyboard and Mouse Drivers for Non-HID Devices.

Windows Me supplies the following drivers for non-HID keyboard, mouse, and game port devices.

Device Type | Driver
Keyboard | Class driver, vkd.vxd
Mouse | Class driver, vmd.vxd
Game port | Class driver, vjoyd.vxd
Serial port, PS/2 port, and game port | Class minidrivers

For more information about the driver stacks for non-HID input devices, see:

Driver Stacks for Non-HID Keyboard and Mouse Devices

Driver Stacks for Non-HID Game Port Devices

Driver Stacks for Miscellaneous Non-HID Input Devices

For information about system-supplied drivers and device stacks for HID input devices, see:

System-Supplied Components for Input Devices

Microsoft Windows HID Device Stacks

Types of HID Clients


User-Mode Components That Support Input Devices

This section describes the main system-supplied user-mode components that support input devices.

Microsoft® DirectInput® 5.0 and later communicates directly with the HID class driver. Vendor-supplied function drivers are not required to support DirectInput applications that access HID devices. In addition, DirectInput applications do not have to interface directly with the HID interface to benefit from the full functionality of the HID input architecture.

DirectInput 7.0 and later supports physical input devices (PID), as defined by the USB HID Standard.

Applications that use only the Microsoft® Windows® multimedia DLL (winmm.dll) can indirectly access HID joysticks because winmm.dll accesses joysticks through DirectInput COM interfaces. The physical attachment of a joystick is transparent to a Windows multimedia application.

The Microsoft Win32® subsystem DLLs, user32.dll in Windows 2000 and later and user.dll in Windows Me, access keyboard and mouse class devices through the non-HID keyboard and mouse class drivers.


Driver Stacks for HID Devices

This section illustrates the system-supplied driver stacks that support HID devices that comply with the USB HID Standard.

As shown in the following figure, the HID components are integrated with the class drivers for non-HID input devices and other input-related system components.

Driver Stacks for HID Devices

For more information about the HID components, see Components for HID Devices and Types of HID Clients.

For more information about the non-HID components, see Drivers for Non-HID Input Devices.

For more information about the user-mode components, see User-Mode Components that Support Input Devices.

See Microsoft Windows HID Device Stacks for an example of a HID device stack.


Driver Stacks for Non-HID Keyboard and Mouse Devices

This section illustrates the system-supplied driver stacks that support non-HID keyboard and mouse devices.

Driver Stacks for Non-HID Keyboard and Mouse Devices

For more information about non-HID keyboard and mouse devices, see:

Drivers for Non-HID Input Devices

Keyboard and Mouse Drivers for Non-HID Devices

Serial Devices and Drivers

For more information about the user-mode components, see User-Mode Components that Support Input Devices.

For information about support for other non-HID input devices, see:

Driver Stacks for Non-HID Game Port Devices

Driver Stacks for Miscellaneous Non-HID Input Devices


Driver Stacks for Non-HID Game Port Devices

This section illustrates the system-supplied driver stacks that support non-HID game port (I/O port 201) devices.

Driver Stacks for Non-HID Game Port Devices

For more information about the HID components see the Components for HID Devices and Types of HID Clients.

For more information about the user-mode components, see User-Mode Components that Support Input Devices.

For information about support for other non-HID input devices, see:

Drivers for Non-HID Input Devices

Driver Stacks for non-HID Keyboard and Mouse Devices

Driver Stacks for Miscellaneous Non-HID Input Devices


Driver Stacks for Miscellaneous Non-HID Input Devices

This section describes the system-supplied driver stacks that support non-HID devices other than keyboard, mouse, and game port devices. The following figure represents such a driver stack.

game port

Driver Stacks for Miscellaneous Non-HID Input Devices

For more information about the individual components and device stacks, see the following:

Components for HID Devices

Microsoft Windows HID Device Stacks

Types of HID Clients

For information about support for specific types of non-HID input devices, see:

Driver Stacks for Non-HID Keyboard and Mouse Devices

Driver Stacks for Miscellaneous Non-HID Input Devices

Built on Wednesday, July 11, 2001


Required Vendor-Supplied Drivers

This section describes what types of vendor-supplied drivers are required for input devices.

A vendor-supplied HID minidriver is required if the system-supplied drivers do not fully support a non-USB input device.

WDM function or filter drivers are optional and device-specific.

Vendor drivers are not required for the following devices:

  • Devices that comply with the USB HID Standard
  • Non-HID devices attached to ports or buses operated by a system-supplied HID minidriver
  • Keyboard, mouse, or game port devices operated by the system-supplied non-HID class drivers

For more information about required and optional vendor-supplied drivers, see the following:

Microsoft Windows HID Device Stacks

Types of HID Clients

Keyboard and Mouse Drivers for Non-HID Devices

Serial Devices and Drivers


Keyboard Layout

A keyboard layout fully describes a keyboard's input characteristics for Microsoft® Windows® 2000 and later. For example, a keyboard layout specifies the language, keyboard type and version, modifiers, scan codes, and so on.

See the following for information about keyboard layouts:

  • Keyboard header file, kdb.h, in the Windows DDK, which documents general information about keyboard layouts
  • Sample keyboard layouts in the \src\input\layout directory of the Windows DDK


HID Driver Overview

This section includes the following topics about the Human Interface Device ( HID ) architecture in Microsoft® Windows®:

USB HID Standard

HID Concepts

Microsoft Windows HID Device Stacks

Types of HID Drivers

When Do I Write a HID client Driver?

When Do I Write a HID Minidriver?


USB HID Standard

The core of the Microsoft® Windows input architecture is based on the Universal Serial Bus (USB) standard Device Class Definition for Human Interface Devices (HID), defined by the USB Implementers Forum, Inc. The USB HID standard defines the configuration and communication protocols for human interface devices – such as keyboards, mice, joysticks, and virtual reality devices – that humans use to enter data directly into a computer.

Although the core of the Windows® input architecture is based on the USB HID standard, the architecture is not limited to USB devices. The input architecture also supports serial port devices, i8042 port devices, and proprietary input devices.


HID Concepts

This section describes the following concepts that a developer needs to understand to support HID devices in Microsoft® Windows®:

HID Class-Specific Descriptors

HID Collections

HID Controls

HID Reports

HID Usages

Most of the concepts described here are defined in detail in the USB HID standard. However, Microsoft extends the concept of HID collections.


HID Class-Specific Descriptors

A HID class-specific descriptor contains configuration information about a HID device. Vendors use HID class descriptors to store device-specific information in the firmware of a device. In Windows, HID clients obtain different types of HID class descriptors by directly accessing the hardware or by querying a HID minidriver. The HID class-specific descriptors, as defined by the USB HID standard, are:

HID Descriptors

Physical Descriptors

Report Descriptors


HID Descriptors

A HID descriptor specifies the number, type, and size of physical descriptors and report descriptors that are associated with a HID device. The HID descriptor also specifies a country or region code that localizes the hardware (however, most hardware is not localized).

For information about obtaining a HID descriptor, see the IOCTL_HID_GET_DEVICE_DESCRIPTOR request and the HID_DESCRIPTOR structure.


Physical Descriptors

A physical descriptor identifies the parts of the human body that activate HID controls. The left mouse button, for instance, is a control that would be activated by the right forefinger. Physical descriptors are optional.


Report Descriptors

A report descriptor specifies the protocol and meaning assigned to HID control data. A report descriptor is composed of report items that define one or more top-level collections. Each collection defines one or more HID reports.

When the HID class driver initializes a functional device object (FDO) that represents a HID device, it queries the device to obtain the device's report descriptors. The HID class driver creates a physical device object (PDO) for each top-level collection defined by the device's report descriptors.

Note To communicate with HID devices used at boot time — for example, keyboard and mouse devices — the system BIOS uses the HID boot protocol instead of the HID class report protocol. The boot protocol is a predefined HID class subclass protocol. The boot protocol standardizes the boot process, eliminates the need for a parser in the BIOS, and reduces boot time. Because the boot protocol does not support a software key repeat capability, it uses a HID Set_Idle command to control key repeats reported by the hardware. The system BIOS is the only HID client that uses the boot protocol.

After Windows installs the HID class driver, the HID class driver changes the communication protocol from the boot protocol to the report protocol. It also uses a HID Set_Idle command to set the idle to an indefinite duration. This ensures that key repeat functionality is handled by Windows and not by the device hardware.


Report Items

A report item is a component of a report descriptor that specifies information about HID collections and HID controls.

The following table lists the report items most often referenced in the DDK documentation. See the USB HID standard for the full definition of these items.

HID Report Item Type | Description
Collection and

End Collection items

 Specify the start and end of a HID collection.
Delimiter item
 Delimit the start and end of a set of aliased usages for a HID control. Such a control can be accessed using any of its aliased usages.
Designator Index item
 Specifies a designator in a device's physical descriptor.
Designator Minimum and Designator Maximum items
 Specify indices that identify the inclusive lower bound and upper bound of a range of designators in a device's physical descriptor.
Feature item | Specifies information about feature reports.
Global item | Specifies default information about subsequent main items.
Input item | Specifies information about an input report.
Main item | Specifies an input, output, feature, collection, or end collection item.
Output item | Specifies information about an output report.
String Index item
 Specifies a string descriptor in a device's string descriptor table.
String Minimum and String Maximum items
 Specify indices that identify the inclusive lower bound and upper bound of a range of string descriptors in a device's string descriptor table.
Unit item | Specifies the units of a control value.
Usage Minimum and Usage Maximum items | Specify indices that identify the inclusive lower bound and upper bound of a range of usage IDs within a usage page.
Usage Page and Usage items | Specify the HID usage of a HID control.


HID Reports

A HID report is used to transmit HID control data between a client and a HID device. A report descriptor defines the format of a report. If a device supports more than one report of the same type, each report is assigned a unique report ID. See the following topics for more information:

Input and Output Reports

Feature Reports


Input and Output Reports

Input and output reports specify HID control data. Input controls are sources of data relevant to an application. For example, x and y data obtained from a pointing device. Output controls are a sink for application data. For example, an LED that indicates the state of a device.

For information about reading and writing reports, see Obtaining HID Reports and Sending HID Reports.


Feature Reports

A feature report specifies configuration information for a device. A user-mode client obtains and sets feature information by using the following HID support routines for clients:

HidD_GetFeature

HidD_SetFeature

A kernel-mode client obtains and sets feature information by using the following I/O requests serviced by the HID class driver:

IOCTL_HID_GET_FEATURE

IOCTL_HID_SET_FEATURE


HID Controls

A HID control is a data source or data sink associated with a HID device. An example of a data source, or input control, is a button. An example of a data sink, or output control, is an LED. Control data is obtained and sent to a device by using HID reports.

Controls that return discrete, binary values are referred to as buttons, while controls that return a continuous range of values are referred to as either value usages or, more simply, as values. A letter key on a keyboard and a CAPS LOCK light are examples of buttons. The X axis on a mouse and the intensity of vibration on a force feedback joystick are examples of values.


HID Usages

HID usages identify the intended use of HID controls and what the controls actually measure.

The following concepts and terminology are used throughout the HID documentation in the DDK:

Usage Page

Usage ID

Extended Usage

Usage Range

Aliased Usages

For specific examples of usages that Windows components access, see Top-Level Collections Opened by Windows for System Use.

For more information about determining the usages that a HID device supports, see:

Collection Capability

Button Capability Arrays

Value Capability Arrays

Initializing and Connecting a HID Client

Usage Page

The Universal Serial Bus (USB) specification HID Usage Tables, defined by the USB Implementers Forum, Inc, specifies industry standard usages. Usages are organized into usage pages of related controls. A specific control usage is defined by its usage page, a usage ID, a name, and a description. Examples of usage pages include Generic Desktop Controls, Game Controls, LEDs, Button, and so on. Examples of controls in the Generic Desktop Controls usage page include pointers, mouse and keyboard devices, joysticks, and so on. A usage page value is a 16-bit unsigned value.

Usage ID

In the context of a usage page, a valid usage identifier, or usage ID, is a positive integer greater than zero that indicates a usage in a usage page. A usage ID of zero is reserved. A usage ID value is an unsigned 16-bit value.

Extended Usage

An extended usage is a 32-bit value that specifies a 16-bit usage page value in the most-significant two bytes and a 16-bit usage ID in the least significant two bytes of the extended usage value.

Usage Range

A usage range is an inclusive, consecutive range of usage IDs, all of which are on the same usage page. A usage range is specified by usage minimum and usage maximum items in a report descriptor.

Aliased Usages

More than one usage can be specified for a link collection or a HID control. For a given collection or control, a group of such usages are aliases of one another, and are referred to as aliased usages. Delimiter items are used to specify aliased usages. Usage ranges can not be aliased.

For information about how aliased usages are specified in a top-level collection's capability arrays, see Button Capability Arrays and Value Capability Arrays.


HID Collections

A HID collection is a meaningful grouping of HID controls and their respective HID usages. Controls should be grouped together if they are logically related or are functionally dependent on one another. For instance, a SHIFT key and a letter key on a keyboard should not belong to separate collections. Collections can have nested subcollections, also referred to as link collections. Report descriptors define one or more top-level collections, and the report items, associated with each collection, define one or more HID reports.

Windows extends the concept of a HID collection to include the following:
Top-level collections

Top-level collections opened by Windows for system use

Preparsed data

Link collections

Collection capability

Button capability arrays

Value capability arrays

Data indices


Top-Level Collections

Microsoft defines a top-level collection as a HID collection that is not nested within another collection. An unnested collection is always a top-level collection, regardless of its HID type. In particular, a top-level collection does not have to be an Application collection, as defined by the USB HID standard.

A report descriptor can include more than one top-level collection. The Windows HID class driver enumerates the top-level collections of a HID device and creates a physical device object (PDO) for each top-level collection. HID clients can access a top-level collection by opening its PDO and using the HID support routines for clients and the I/O requests serviced by the HID class driver.

The internal structure and capability of a top-level collection is described by the following:

  • A HIDP_CAPS structure summarizes a top-level collection's capability.
  • Link collections describe the organization of the nested subcollections contained within a top-level collection.
  • Button capability arrays and value capability arrays describe the capability of the controls supported by the top-level collection.


Top-Level Collections Opened by Windows for System Use

Windows opens the following top-level collections for system use:

Device Type | Usage Page | Usage ID | Windows Client | Access Mode
Pointer | 0x01 | 0x01 | Win32® subsystem | Exclusive
Mouse | 0x01 | 0x02 | Win32 subsystem | Exclusive
Joystick | 0x01 | 0x04 | DirectInput® | Shared
Game pad | 0x01 | 0x05 | DirectInput | Shared
Keyboard | 0x01 | 0x06 | Win32 subsystem | Exclusive
Keypad | 0x01 | 0x07 | Win32 subsystem | Exclusive
System Control | 0x01 | 0x80 | Win32 subsystem | Shared
Consumer Audio Control | 0x0C | 0x01 | hidserv.exe in Windows 2000 and hidserv.dll (one of the SVC host services) in Microsoft Windows XP | Shared


Preparsed Data

Microsoft defines preparsed data as report descriptor data associated with a top-level collection. HID clients use preparsed data to extract information about specific HID controls without having to obtain and interpret a device's entire report descriptor. A user-mode client obtains a collection's preparsed data by using HidD_GetPreparsedData and a kernel-mode driver uses an IOCTL_HID_GET_COLLECTION_DESCRIPTOR request.

See the following HID support routines for clients, which support extracting button and value data from a report:

HidP_GetButtons

HidP_GetUsageValue

HidP_GetScaledUsageValue

HidP_GetUsageValueArray

See also the following routines, which support setting button and value data in a report:

HidP_SetButtons

HidP_UnsetButtons

HidP_SetUsageValue

HidP_SetScaledUsageValue

HidP_SetUsageValueArray


Link Collections

Microsoft defines a link collection as a nested subcollection within a top-level collection. A top-level collection can have zero or more link collections.

HidP_GetLinkCollectionNodes returns a top-level collection's link collection array, which contains information about a top-level collection's link collections.

Link Collection Array

A link collection array describes all the link collections contained within a top-level collection. Each link collection is represented by a HIDP_LINK_COLLECTION_NODE structure. The array's link nodes are linked in a manner that identifies their sequential and hierarchical order within a top-level collection. The first element of a link collection array represents a top-level collection and the remaining members represent the top-level collection's link collections.

By tracing through the nodes in the link connection array, a client can determine the organization and usage of all the link collections in a top-level collection. In addition, a client can organize controls by their link collection. This is possible because a top-level collection's button capability arrays and value capability arrays identify the link collection that contains each HID usage described by the capability arrays.

The following figure shows an example of a top-level collection containing four link collections.

Link Collection Nodes

As indicated in the above figure, link collections are linked together in a top-to-bottom and left-to-right order (ABCD). The following table indicates, for each link collection in the example, the links between the top-level collection and its link collections.

Link Node | Parent | Children | First Child | Next Sibling
A | Top-level Collection | B, C | B | None
B | A | D | D | C
C | A | None | None | None
D | B | None | None | None

In a link collection array, the following definitions hold:

Parent
A link collection's parent is the collection immediately above it in the top-to-bottom hierarchy of collections. Link collections have one parent. The Parent member of a link node specifies the index of its parent in the link collection array.
Children
A link collection is a child of its parent. A parent can have zero or more children. The NumberOfChildren member of a link node specifies the number of children that a parent has.
Sibling
A parent's children are siblings.
Next Sibling
Siblings are ordered left-to-right. A sibling's next sibling is the sibling immediately to its right, if any, in a set of siblings. The NextSibling member of a link collection node specifies the index to its next sibling in the link collection array. If a link collection node does not have a next sibling, NextSibling is set to zero.
First Child
The first child is the left-most sibling in a set of siblings. The FirstChild member of a link collection node specifies the index to its first child in the link collection array. If a link collection node has no children, FirstChild is set to zero.

A client can determine all a parent collection's children by, starting with the parent's first child, sequencing through the siblings of the first child until the NextSibling member of a sibling node is zero.

The following code is an example of using a link collection node index to find the first child of link collection seven:

HIDP_LINK_COLLECTION_NODE Collection[10] ;
HIDP_LINK_COLLECTION_NODE Node1 ;

Node1 = Collection[Collection[7].FirstChild]] ;

Aliased Collections

Delimiter items can be used in a report descriptor to delimit a set of aliased collections. Each aliased collection is represented by an aliased link collection node. A complete and unique set of n, n >=2, aliased nodes is linked together in the following way:

  • The aliased nodes are in consecutive order in the link collection array.
  • The first n-1 nodes have their IsAlias member set to TRUE. The nth node immediately following such a sequence has its IsAlias member set to FALSE. This node terminates the sequence of aliased nodes. The usage associated with this node is the preferred usage.

A client can determine which collections are aliased by repeatedly incrementing the array index of a link collection array to find such sequences.

Button capabilty arrays and value capability arrays identify, for each usage they describe, the link collection that contains the usage. If a link collection is aliased, the capability arrays specify the preferred usage.


Collection Capability

A client calls HidP_GetCaps to obtain a top-level collection's HIDP_CAPS structure. This structure contains the following information about a collection's link collections, button capability arrays, and value capability arrays:

  • The collection's usage page and usage ID
  • The size, in bytes, of the collection's input, output, and feature reports (see HID Reports)
  • The number of HIDP_LINK_COLLECTION_NODE structures in the collection's link collection array
  • For each report type, the number of HIDP_BUTTON_CAPS structures in the button capability array returned by HidP_GetButtonCaps
  • For each report type, the number of HIDP_VALUE_CAPSstructures in the value capability array returned by HidP_GetValueCaps
  • For each report type, the number of buttons and values supported by the collection, as specified by the NumberXxxDataIndices member


Button Capability Arrays

A button capability array contains information about the button usages supported by a top-level collection for a specific type of HID report. Information about a collection's capability is contained in its HIDP_CAPS structure.

A client uses one of the following HID support routines for clients to obtain button capability information:

  • HidP_GetButtonCaps returns a button capability array describing all the button usages contained in a specified report type.
  • HidP_GetSpecificButtonCaps filters the button capability information it returns by a caller-specified usage page, usage ID, and link collection.

A button capability array contains HIDP_BUTTON_CAPS structures, each one of which contains the following information about a HID usage or usage range:

  • The usage page for the usage or usage range
  • The report ID of the report that contains the button data
  • The usage ID or usage range
  • A flag that indicates whether a usage is an aliased usage
  • The link collection that contains the usage or usage range
  • The string descriptors and designators associated with the usage or usage range (see Designator Index item and String Index item)
  • The data indices that the HID parser assigned to the usage or usage range

In general, the following conditions hold for all the usages described by a button capability array:

  • Each capability structure represents a single usage or usage range that is associated with a variable main item or an array main item.
  • Aliased usages can be used with a variable main item. A usage that is associated with an array item can not be aliased. A usage range can not be aliased.
  • The HID parser uses only the minimum required number of usages to assign a usage to each button. The parser assigns usages in the order in which they are specified in a report descriptor. Usages in a report descriptor that are not required, are discarded. The button capability array does not contain any information about discarded usages.
  • If the number of usages specified for a variable item is less than the number of buttons in the item, the capability array contains only one capability structure that describes one button usage (the last usage specified in the report descriptor for the variable main item). However, see Usage Value Array for information about usage values that have a report count greater than one.
  • The HID parser assigns a unique data index to each usage described in the capability array.

See the following topics for information about how the capability structures are organized and set in a button capability array:

Button Usages in a Variable Main Item

Button Usages in an Array Main Item

Button Usages in a Variable Main Item

Each usage or usage range specified in a report descriptor is described by its own capability structure in a button capability array.

The IsAlias member of capability structures is used to specify a set of n aliased usages as follows:

  • IsAlias is set to TRUE in the first n-1 capability structures added to the capability array. IsAlias set to FALSE in the nth capability structure. The preferred usage is the last aliased usage in the sequence.

A client can determine which button usages are aliased by scanning for such sequences.

The following table summarizes an example for three aliased usages.

Aliased Usage Order in a Report Descriptor | Usage Order in a Capability Array | IsAlias Member Value
usage 1 | usage 3 | TRUE
usage 2 | usage 2 | TRUE
usage 3 | usage 1 | FALSE

See Data Indices for information about how usages and data indices are cross-referenced.

Button Usages in an Array Main Item

Each usage or usage range for a button array main item specified in a report descriptor is described by its own capability structure in a button capability array. The order in which the capability structures are added to a capability array is the reverse of the order in which the usages are specified for a main item.

The HID parser assigns a data index to each usage associated with the array item in the order in which the usages are specified in a report descriptor. For example, the following table shows the correspondence between a set of usages, as specified in a report descriptor, and the usages and data indices, as specified in the capability array. (In this table, n is the first data index that the parser assigns to the first usage associated with the array item.)

Usage Order in Report Descriptor | Usage Order in Capability Array | DataIndex or from DataIndexMin to DatatIndexMax
usage 1 | usage range 2 | from n+7 to n+8
usage range 1 (with 4 usages) | usage 2 | n+5
usage 2 | usage range 1 | from n+1 to n+4
usage range 2 (with 2 usages) | usage 1 | n


Value Capability Arrays

A value capability array contains information about the value usages supported by a top-level collection for a specific type of HID report. Information about a collection's value capability arrays is contained in its HIDP_CAPS structure.

A client uses one of the following HID support routines for clients to obtain button capability information:

  • HidP_GetValueCaps returns a value capability array describing all the values contained in a caller-specified report type.
  • HidP_GetSpecificValueCaps filters the value capability information it returns by a caller-specified usage page, usage, link collection, and report type.

A value capability array contains HIDP_VALUE_CAPS structures, each one of which describes the following information about a HID usage or usage range:

  • The usage page for a usage or usage range
  • The report ID of the report that contains the value
  • A usage ID or a usage range
  • Indicates whether a usage is an aliased usage
  • Information about the link collection that contains the usage or usage range
  • The size, in bits, of a value, and the report count (which is the number of individual values described by the structure)
  • Attributes of each value, including: whether it has a null value, its units and exponent, and its logical and physical ranges
  • Information about string descriptors and designators associated with the usage or usage range (see Designator Index item and String Index item)
  • Information about the data indices that the HID parser assigns a usage or usage range

In general, the following conditions hold for all the usages described by a value capability array:

  • Each capability structure represents a usage, a usage range, or a usage value array that is associated with a variable main item. Array main items are not supported for values.
  • Aliased usages can be used. A usage range can not be aliased. Aliased values are linked together in a value capability array in the same way as aliased buttons as linked together in a button capability array. See Button Usages in a Variable Main Item.
  • The HID parser uses only the minimum required usages to assign a usage to each value. The parser assigns usages in the order in which they are specified in a report descriptor. Usages in a report descriptor that are not required, are discarded. The value capability array does not contain any information about discarded usages.
  • The HID parser assigns a unique data index to each usage described in the capability array.

See Data Indices for a description of how data indices are assigned to values.

Usage Value Array

A usage value array is a consecutive set of values specified in a main item, all of which are assigned the same usage. This occurs if only one usage is specified for a main item whose report count is greater than one.

The following figure shows an example of a usage value array that contains five data items, each six bits long.

Usage Arrays

In the above example, the value capability structure for such a usage value array would have its IsRange member set to FALSE, its NotRange.Usage member set to seventeen, its ReportCount member set to five, and its BitSize member set to six.

If a value capability structure specifies a single usage with a report count greater than one, a client must call HidP_GetUsageValueArray to extract all the usage value array's data items.

If a usage's report count is one, clients extract the usage by calling HidP_GetUsageValue or HidP_GetScaledUsageValue. However, if the report count is greater than one, these routines only return data for the first data item in a usage value array.


Data Indices

The HID parser assigns a data index that uniquely identifies each usage described in a top-level collection's button capability arrays and value capability arrays. Conceptually, a data index is a zero-based array index that a client can use to access individual control data in a report. The parser assigns a unique set of data indices to each report type supported by each top-level collection.

Capability structures cross-reference usages and data indices in the following way:

  • Each capability structure that describes a usage has its NotRange.Usage member set to identify the usage and its NotRange.DataIndex member set to the usage's corresponding data index.
  • Each capability structure that describes a usage range has its Range.UsageMin and Range.UsageMax members set to identify the usage range and its Range.DataIndexMin and Range.DataIndexMax members set to identify the usage range's corresponding data index range. (Data index range specifies a consecutive sequence of data indices; and the number of data indices in a data index range is equal to the number of usages in a corresponding usage range.)

Fore more information about using data indices, see Extracting and Setting Control Data by Data Indices.


Microsoft Windows HID Device Stacks

The following figure illustrates the HID device stacks in Microsoft® Windows® for top-level collections that represent two keyboards, a mouse, and a toaster device.

Example of HID Device Stacks

The following device objects are used in the example of HID device stacks:

  1. Functional Device Objects (FDO), created by the HID class driver.

    The HID class driver creates an FDO for each HID device attached to an underlying bus or port, for example, each HID device attached to a USB bus.

  2. Physical Device Objects (PDO), created by the HID class driver for all top-level collections.

    The HID class driver enumerates all the top-level collections belonging to its FDOs, and creates a PDO for each collection. An FDO can have more than one top-level collection associated with it. For example, a keyboard with an integrated mouse pointer might have a collection for the standard keyboard controls and a different collection for the pointer. HID clients can access a top-level collection's PDO, opening it in "raw" mode.

  3. FDOs, created by HID mapper drivers.

    HID devices can be accessed by the non-HID input class drivers by using HID mapper drivers.

  4. Filter Device Objects, created by the non-HID input class drivers.

    The non-HID input class drivers are integrated into the HID input architecture by layering them above a HID mapper driver. (See Keyboard and Mouse Drivers for Non-HID Devices.)


Types of HID Drivers

HID drivers are either kernel-mode HID clients or HID minidrivers.

For more information about HID drivers, see the following:

When Do I Write a HID Client Driver?

When Do I Write a HID Minidriver?


When Do I Write a HID Client Driver?

The most common sort of kernel-mode HID client is the mapper driver, a driver that translates a HID data stream originating from the HID class driver into the data format that a non-HID class driver supports. A keyboard mapper driver, kbdhid.sys, and a mouse mapper driver, mouhid.sys, are supplied in Microsoft® Windows® 2000 and later.


When Do I Write a HID Minidriver?

As indicated in Windows Input Architecture, the HID class driver serves as a class driver for all types of HID devices, so that no HID-compliant device should require its own class driver. However, even non-HID input devices can make use of the HID class driver, thus saving driver development time. This can be done provided the non-HID device has a minidriver that can abstract the details of the bus that the device uses from the HID class driver.

By making a non-USB device appear to be a HID device, a properly designed HID minidriver can make connection details completely transparent to applications accessing the device. For example, consider a camera that can be controlled by a computer and that comes with either a USB connector or a serial connector for use with older computers without USB ports. With the appropriate HID minidriver that makes the serial camera controls look like HID features, a single application can control the camera through either the serial or USB connectors using Microsoft® DirectInput® APIs, without special code to handle the connection differences. HID minidrivers provide a simple mechanism for supporting devices that can be connected by way of non-USB ports, while at the same time taking advantage of the newer USB capabilities.

A minidriver for non-USB gameports, hidgame.sys, is supplied with Microsoft® Windows® 2000 and later. The following figure depicts the Microsoft-supplied minidriver interfaces to a non-USB gameport driver and to a USB bus stack.

Minidriver Interfaces to Gameport Minidriver and to USB Driver Stack


HID Clients

This section describes the two types of HID clients supported by Microsoft® Windows® 2000 and later, what clients must and can support, and how clients retrieve data from or send data to a device, as follows:

Types of HID Clients

Required and Optional Functionality for HID Clients

Installing a HID Client

Initializing and Connecting a HID Client

HID Device Data I/O

Interpreting HID Reports

Note The preceding sections contain information useful to writers of application-level clients, as well as to driver writers of kernel-mode clients.


Types of HID Clients

In the Windows Input Architecture, there are two types of HID clients:

  1. User-mode clients, sometimes called application-level clients
  2. Kernel-mode clients

Each type of client has different capabilities and restrictions but comparable functionality. Each is part of a HID communications stack built on top of a HID device.

Whether to write a user-mode or kernel-mode client depends on how much of the communications stack for a particular underlying HID device is system-supplied. However, user-mode clients are both faster and easier to write because they are Microsoft® Win32® applications. When designing a client for a HID device, developers should consider writing a user-mode client first and should avoid writing a kernel-mode client if possible.

To determine which type of client to write, consider the following illustrations and the accompanying explanations. In both these illustrations, the components that client developers can supply are shown shaded, while all system-supplied components are shown unshaded.

The following figure shows the user-mode clients in a representative HID communications stack over a hypothetical HID joystick device connected on a USB bus.

HID Joystick with User-Mode Clients

As the previous figure shows, user-mode clients can be monolithic applications that contain the necessary functionality to be a client; or they can be a separate standalone service or DLL, such as the system-supplied Direct Input component in the previous figure, that other client applications can use.

Writers of user-mode clients do not necessarily have to supply all replaceable components in the HID communications stack. The filter drivers shown shaded in the previous figure are optional components, not necessarily required by every client of every HID device.

By contrast, the system-supplied HID class driver and miniclass driver (sometimes called a HID minidriver) components shown in the previous figure are essential to all potential user-mode clients that depend on this underlying HID joystick device. This linked pair of drivers effectively controls the hypothetical joystick device connected on the USB bus as a WDM function driver.

Any user-mode client can communicate with any standard HID devices for which the system provides the paired class-miniclass drivers. To be fully functional, such user-mode clients only must follow the procedures outlined later in this chapter for connecting to and obtaining data from such a standard HID device. For all such standard devices, writing a new user-mode client, possibly with an optional filter driver, is preferable to writing a kernel-mode driver.

The following figure shows a representative HID communications stack for another hypothetical joystick device on the same USB bus, but with a kernel-mode HID client.

HID Joystick with Kernel-Mode Client

As the previous figure shows, kernel-mode clients are higher level drivers that communicate through the system-defined HID interface exposed by a HID class-miniclass driver pair. Functionally, HID kernel-mode clients are equivalent to user-mode clients in operations.

In contrast to user-mode clients, which can communicate to the underlying joystick by making Win32 function calls, the kernel-mode client shown in the previous figure is a WDM driver. As such, it must communicate to lower level drivers, particularly the HID class-miniclass driver pair, in the HID communication stack using I/O request packets.

After determining which type of client to write, a developer can skip the appropriate subsections labeled "User-Mode Clients Only" or "Kernel-Mode Clients Only," respectively, in each of the following subsections of this section. Information labeled with "All Clients" is pertinent to both types of HID clients.


Required and Optional Functionality for HID Clients

This describes the functionality that a user-mode or kernel-mode HID client must support in Microsoft® Windows® 2000 and later, as well as optional functionality that HID clients can support.

User-Mode Clients Only

User-mode clients must be capable of opening, reading from, writing to, and interpreting data for a HID device, as described in later sections of this chapter.

Kernel-Mode Clients Only

As WDM drivers, kernel-mode HID clients must have at least the following standard driver routines:

  • A DriverEntry routine to initialize the client
  • Either a Plug and Play notification routine or a Plug and Play AddDevice routine
  • An Unload routine to remove a driver from the set of loaded drivers when the underlying device stack is removed.
  • One or more Dispatch routines to handle the following IRPs:
    • IRP_MJ_CREATE
    • IRP_MJ_CLOSE
    • IRP_MJ_POWER (for drivers that attach to the driver stack)
    • IRP_MJ_PNP (for drivers that attach to the driver stack)

• Support for Windows Management Instrumentation

Any kernel-mode HID client also must export a mechanism to transmit and/or receive data from users of that client. The upper-edge interface supported by a kernel-mode HID client is specific to the type of client being written. For example, a client that supports a kernel streaming interface will have different requirements from a client that exports a private IOCTL interface to a single user-mode application.

The remainder of this section explains the preceding list of basic requirements for kernel-mode HID clients in more detail.

DriverEntry Routine

As a kernel-mode driver, any kernel-mode HID client must have a DriverEntry routine to be loaded by the system.

Kernel-mode HID clients must name this routine DriverEntry and follow the exact system-provided prototype for DriverEntry. For more information on the restrictions that operating in the context of the DriverEntry routine imposes, see Writing a DriverEntry Routine.

In general, the DriverEntry routine of any kernel-mode HID client should do the following:

  1. Allocate storage to hold configuration information retrieved from the registry, as necessary.
  2. Set up the entry points for the driver's Dispatch routines for the IRP_MJ_Xxx IRPs the client handles, and for its Unload routine in the input driver object. If it has a StartIo routine, the client should also set its entry point in the driver object.
  3. Either set the entry point of its AddDevice routine in the driver object to find HID device objects that are present in the system, or register its Plug and Play notification routine to find all device interfaces for HID collections that are present or subsequently added to the system. Drivers that must layer themselves onto the HID device stack should use an AddDevice routine, otherwise a Plug and Play notification routine is indicated.

If the driver was able to complete its initialization successfully, it should return STATUS_SUCCESS from its DriverEntry routine. If it was unable to complete initialization, it should free any resources that it might have allocated and return a meaningful error status from DriverEntry. For more detailed information about Plug and Play driver initialization, see Plug and Play.

Providing an AddDevice Routine versus a Plug and Play Notification Routine

Writers of kernel-mode clients have two alternatives for finding device objects that represent HID devices and interfaces present in the system and/or those added to the system at a later time:

  1. Set up the entry point for the client's AddDevice routine in the driver object.
  2. Register a Plug and Play notification routine with IoRegisterPlugPlayNotification.

To make an informed decision, based on the requirements of the driver or underlying HID device, about which of these routines to implement in a kernel-mode client, consider the next two subsections.

Using an AddDevice Routine

One way for HID client drivers to obtain connections to HID devices is to register an AddDevice routine by setting its entry point in the driver object within the client's DriverEntry routine. When such a client's INF file supplies the correct information, the Plug and Play Manager will call the client's AddDevice routine each time the underlying HID class-miniclass driver pair exposes a new device object that matches the device ID and compatible ID that was stored in the registy by the client's INF.

When it is called, the AddDevice routine creates a functional device object (FDO) to represent each such HID device. The client can then attach itself to the HID communication stack for this HID device by calling IoAttachDeviceToDeviceStack so that all subsequent I/O requests to the underlying HID device are routed through the client. The client's AddDevice routine also does one of the following:

  • Exposes an device interface (symbolic link) to the FDO it created by calling IoRegisterDeviceInterface, so that a user-mode application or service can connect to the client
  • Takes whatever actions are required by the upper-edge interface that it supports to make it possible for still higher level applications or services to use the client

When AddDevice attaches its FDO to the HID communication stack, it must store the pointer to the device object of the next lower driver that was the former top of the HID device object stack. The client later uses this device object pointer to send I/O requests (IRP) down the HID communications stack using IoCallDriver.

Note that a kernel-mode HID client with an AddDevice routine is notified only when a lower level WDM driver creates a new HID device object that explicitly matches the device ID and compatible ID values stored in the registry by the client's INF file. For more information about setting up the client's INF, see Installing a HID Client.

For more detailed information about Plug and Play AddDevice routines, see the Plug and Play.

Using a Plug and Play Notification Routine

Another way for kernel-mode HID clients to detect the addition of HID devices to the system is by registering a Plug and Play notification routine, rather than having an AddDevice routine.

To register a Plug and Play notification routine, a client's DriverEntry routine calls IoRegisterPlugPlayNotification specifying EventCategoryDeviceClassChange for the event category and specifying the system-defined input class GUID for the notification data. Clients must set the DEVICE_CLASS_NOTIFY_FOR_EXISTING_DEVICES flag when calling IoRegisterPlugPlayNotification to receive notifications about any HID device objects that were created before the client's DriverEntry routine was called. Otherwise, existing HID device objects will not be reported to the HID client.

When the client's Plug and Play notification routine is called and the data for the event indicates that a new HID device interface has been exposed or that an existing device interface has been found, the client's Plug and Play notification routine must connect to the exporting driver's device object or interface to determine if it is of interest to the client. From the input parameters to the client's Plug and Play notification routine, there is no immediate way to determine whether the device is of interest. Therefore, the client's Plug and Play notification routine must make a connection to the device object, get data about the HID device's capabilities, and then make the determination of whether the client should use this HID device. For more information on connecting to a HID device interface, see Initializing and Connecting a HID Client.

If the retrieved device data indicates that this is a HID device of interest, the client's Plug and Play notification routine creates a functional device object (FDO) for this connection. Like an AddDevice routine, the Plug and Play notification routine also does one of the following:

  • Exposes an interface device (symbolic link) to the FDO it created by calling IoRegisterDeviceInterface, so that a user-mode application or service can connect to the client
  • Takes whatever actions are required by the upper-edge interface that it supports to make it possible for still higher level applications or services to use the client.

When the client's Plug and Play notification routine attaches its FDO to the HID communication stack, it must store the pointer to the device object of the next lower driver that was the former top of the HID device object stack. The client later uses this device object pointer to send I/O requests (IRP) down the HID communications stack using IoCallDriver.

By contrast to an AddDevice routine, a Plug and Play notification routine will be called to examine the HID device data for a set of device objects already created by all loaded HID class-miniclass driver pairs if the client called IoRegisterPlugPlayNotification with the DEVICE_CLASS_NOTIFY_FOR_EXISTING_DEVICES flag set. In addition, such a client's registered Plug and Play notification routine will be called subsequently as new HID device objects are created dynamically by HID class-miniclass driver pairs. Possibly, such a client's Plug and Play notification routine will find that only a small subset of these HID device objects export interfaces that are of interest to the HID client. The ability to connect such a HID client to any number of underlying HID devices and use their interfaces comes at the price of additional detection and determination logic required of its Plug and Play notification routine.

For more detailed information about Plug and Play notification routines, see the Plug and Play.

Unload Routine

A WDM HID driver must have an Unload routine, which the Plug and Play Manager uses to remove the driver after the driver has no more device objects.

The driver's Unload routine should free all outstanding system resources and objects allocated by the driver.

For more information about Unload routines, see Writing an Unload Routine.

Note

If the driver uses Plug and Play notification routines, the Plug and Play Manager will not unload the driver unless the driver has first unregistered any notification routines that it registered.

IRP_MJ_CREATE

All kernel-mode clients must have a standard driver Dispatch routine to handle IRP_MJ_CREATE requests so that consumers of the client's HID device information can obtain a connection to the client. The client can, if necessary, allocate resources on a per-open basis. Examples of such per-open resources include, but are not limited to, memory buffers, Windows NT® objects, and doubly linked lists for queuing IRPs.

If a driver writer designs the client to require per-open resources, that client should use the pointer to the file object in the IO_STACK_LOCATION of the create IRP to uniquely identify the per-open state area, which must be freed correctly when an IRP_MJ_CLOSE is received. For example:

PIO_STACK_LOCATION stack ;
stack = IoGetCurrentIrpStackLocation (Irp) ;
UniqueContextId = stack->FileObject ;

If the client has layered itself on the device stack, it must store the file object pointer in the IRP stack location and use this file object pointer as the file object for all subsequent requests that it will send to the HID device in the IRP stack location as well as sending the IRP_MJ_CREATE to the underlying device. The client copies its stack location, using IoCopyCurrentIrpStackLocationToNext, into the next stack location, and calls the underlying driver.

If the driver is not layered in the device stack, it must initiate an IRP_MJ_CREATE to the underlying HID device by calling IoGetDeviceObjectPointer. IoGetDeviceObjectPointer returns a file object pointer that the client must retain for future requests to the HID device. When the client no longer requires the file object, it calls ObDereferenceObject with the file object pointer.

IRP_MJ_CLOSE

All kernel-mode clients must have a standard driver Dispatch routine to handle IRP_MJ_CLOSE requests. IRP_MJ_CLOSE is sent to the client either when an exclusive user-mode consumer of the client's HID device information closes an open handle to the file object representing the client's FDO or, if the client supports more than one client, whenever a file object that represents an open connection to the client has a reference count that goes to zero.

If the client has taken any per-open actions, such as allocating a context area, it must free those resources while handling the IRP_MJ_CLOSE IRP. If the client has taken no per-open actions, it can simply complete the IRP request with STATUS_SUCCESS.

Clients that layer themselves in the device stack need merely pass down the IRP_MJ_CLOSE to the HID device and take no further action. Once the client receives the IRP_MJ_CLOSE for a given file object, it should not use that file object pointer for its own IRP requests to the HID driver.

Clients that did not layer themselves in the device stack must call ObDereferenceObject with the file object pointer that they obtained when handling IRP_MJ_CREATE so that the file object is released properly and the HID driver is notified of such a release.

IRP_MJ_PNP

Kernel-mode clients must have a standard driver Dispatch routine to handle IRP_MJ_PNP requests if they attach themselves to a HID communication stack from an AddDevice routine. Clients that do not attach themselves to the HID communication stack in this manner are not required to handle this request.

If the client attaches itself to a HID communication stack, its Dispatch routine for IRP_MJ_PNP requests must handle at least the following requests:

  • IRP_MN_START_DEVICE
  • IRP_MN_QUERY_STOP_DEVICE
  • IRP_MN_STOP_DEVICE
  • IRP_MN_CANCEL_STOP_DEVICE
  • IRP_MN_QUERY_REMOVE_DEVICE
  • IRP_MN_REMOVE_DEVICE
  • IRP_MN_CANCEL_REMOVE_DEVICE
  • IRP_MN_QUERY_CAPABILITIES
  • IRP_MN_QUERY_PNP_DEVICE_STATE

All Plug and Play IRPs must either be implemented or passed down to the underlying driver using IoSkipCurrentIrpStackLocation routine.

For more information about how to handle IRP_MJ_PNP requests, see Plug and Play.

IRP_MJ_POWER

Kernel-mode HID clients that have AddDevice routines must have a Dispatch routine that handles IRP_MJ_POWER requests. Such a Dispatch routine is only required of those drivers that attach themselves to the device stack using the AddDevice method of finding devices. Clients that have a Plug and Play notification routine are not required to handle power-management IRPs.

In most cases, the driver need only pass down the IRP with IoSkipCurrentIrpStackLocation and PoCallDriver routines.

For more information on the IRP_MN_Xxx codes for IRP_MJ_POWER that HID clients must support, see Plug and Play.

Supporting the Windows Management Interface

This information will be available in a future release of the Windows DDK. However, in most cases the client need not implement any handling of the IRP other than to call IoSkipCurrentIrpStackLocation and IoCallDriver to pass the request to the underlying driver.


Installing a HID Client

This section describes installing HID clients in Microsoft® Windows® 2000 and later.

User-Mode Clients Only

User-mode clients install themselves through standard Microsoft Win32® application installation procedures. For more information on how applications install themselves, see the Platform SDK documentation.

Kernel-Mode Clients Only

This information will be available in a future release of the Windows DDK.


Initializing and Connecting a HID Client

This section describes the following topics about Microsoft® Windows® 2000 and later:

  • Finding HID devices
  • Determining if a device should be used by the client
  • Obtaining a connection to a HID device
  • Obtaining information about the capabilities of a HID device

First, the following explains how user-mode HID clients find and connect themselves to HID device. Next, it explains how kernel-mode HID clients perform the same operations. Finally, it explains how both types of HID clients obtain capability information about a HID device after they have made a connection.

User-Mode Clients Only

When a HID client is loaded, it must identify and connect to all HID devices that it uses.

Load Time Identification and Connection to HID Devices

Microsoft® Windows® provides SetupDi Xxx routines to find and identify the HID devices and other Win32® functions to initialize and connect to a HID device.

After a user-mode HID client is loaded, it does the following sequence of operations:

  • Calls HidD_GetHidGuid to obtain the system-defined GUID for HID devices.
  • Calls SetupDiGetClassDevs to obtain a handle to an opaque device information set that describes the device interfaces supported by all the top-level collections currently installed in the system. The client should specifying DIGCF_PRESENT and DIGCF_INTERFACEDEVICE when calling SetupDiGetClassDevs.
  • Calls SetupDiEnumDeviceInterfaces repeatedly to retrieve all the available interface information.
  • Calls SetupDiGetDeviceInterfaceDetail to format interface information for each collection as a SP_INTERFACE_DEVICE_DETAIL_DATA structure. The DevicePath member of this structure contains the user-mode name that the client uses with the Win32® function CreateFile to obtain a file handle to a top-level collection.

Obtaining Preparsed Data

A top-level collection's preparsed data is an opaque structure that describes the collection's capabilities and operations to the system HID components. A user-mode clients must obtain a collection's preparsed data before calling any of the HID support routines for clients that require the preparsed data. The client should retain access to a collection's preparsed data as long as it has an open file on the device.

After opening a file on a top-level collection, the a user-mode client calls HidD_GetPreparsedData to return a collection's preparsed data in a routine-allocated buffer.

Clients should call HidD_FreePreparsedData when the client no longer requires access to a collection.

Notification of New HID Devices

This information will be provided in a future release of the Windows DDK.

Kernel-Mode Clients Only

Load Time Identification of HID Devices

Depending on how a kernel-mode client finds underlying HID devices, as already described in Required and Optional Functionality for HID Clients, such a client must determine whether a given HID device is of interest to the client. After explaining the differences between clients that use an AddDevice versus those that use a Plug and Play notification routine, this continues with general information about obtaining preparsed HID data that is relevant to all kernel-mode HID clients.

Note It is critical to note that kernel-mode HID clients with AddDevice routines obtain HID preparsed data for their underlying devices at a different time than clients with Plug and Play notification routines.

Using an AddDevice Routine

If the HID client has an AddDevice routine, the driver writer can rely on the knowledge that the data passed into the client's AddDevice routine indicates a device of interest to the client. The client does not require to identify the device any further as a match was made by the system based on the compatible ID and hardware ID provided in its INF. However, the client must still obtain preparsed data from such an underlying HID device for use in obtaining and interpreting device data subsequently.

Clients with AddDevice routines obtain the preparsed data for an underlying HID device when that HID device is started, not when their AddDevice routine is called. For a complete discussion of how a device is started and when it is started, see the Plug and Play. See Required and Optional Functionality for HID Clients for more information on the required functionality of the AddDevice routine.

It should also be noted that a device interface for the device is not set until the HID device has been started by the Plug and Play Manager.

A kernel-mode client must not attempt to obtain a device's preparsed data until after an IRP_MN_START_DEVICE request for the device has been successfully completed for all the device objects below it in the device stack. The client should use an IoCompletion routine with a start request to determine whether all the driver's below it successfully completed the request.

Using a Plug and Play Notification Routine

If a kernel-mode HID client uses IoRegisterPlugPlayNotification to be notified of the arrival of devices, it must provide a callback routine which the Plug and Play manager calls to return notification information. For each callback, the notification information describes the addition or deletion of a device interface supported by a top-level collection. This notification information consists of two discrete structures:

  1. First, a PLUGPLAY_NOTIFICATION_HEADER structure, which contains the GUID that identifies the Plug and Play event that caused the notification routine to be called.

    Kernel-mode HID clients should verify that the GUID specified in the PLUGPLAY_NOTIFICATION_HEADER indicates that a new device interface has been exposed before attempting to connect to the underlying HID device.

  2. Immediately following the PLUGPLAY_NOTIFICATION_HEADER, a DEVICE_CLASS_CHANGE_NOTIFICATION structure. The structure immediately follows PLUGPLAY_NOTIFICATION_HEADER in memory. DEVICE_CLASS_CHANGE_NOTIFICATION contains two pieces of information critical for making a connection to the underlying HID device:
    • ClassGuid
      This member specifies the GUID that identifies the class of device to which the device interface belongs.
    • SymbolicLinkName
      This member points to a buffered Unicode string specifying the name of the device interface.

The client's callback routine examines the data provided in the preceding structures to determine whether this device interface might be worth further investigation. If so, it proceeds to obtain the preparsed data for the device that this device interface represents This data can be used to identify the capabilities of the HID device so the callback routine can determine whether this HID device interface really is of interest to the client.

To obtain the preparsed data, the client first calls IoGetDeviceObjectPointer to obtain a pointer to the device object for the device interface. The client's Plug and Play notification routine passes the SymbolicLinkName pointer from the DEVICE_CLASS_CHANGE_NOTIFICATION structure to IoGetDeviceObjectPointer, which returns pointers to both a file object and a device object.

Then, the client's callback routine uses this returned device object pointer to obtain the preparsed data for the underlying HID device so it can determine whether this interface is of interest to the client. Depending on its decision, the Plug and Play notification routine then does one of the following:

  • If it determines that that the client should use this device, it should take action as is required by the interface it supports at its upper edge. Such actions could include creating a device object and a symbolic link to the device object.
  • If the callback routine determines that a device interface is not of interest to the client, it must call ObDereferenceObject with the file object pointer returned by IoGetDeviceObjectPointer. Calling ObDereferenceObject with this file object pointer ensures that reference counts are properly maintained so the HID communication stack can be unloaded if the underlying HID device is removed.

Obtaining Preparsed HID Device Data

After a kernel-mode HID client makes the connection to an underlying HID device, obtaining the preparsed data is a two-step process:

  1. First, the client must obtain the length of the preparsed data for the device.
  2. Then, it must obtain that preparsed data for the device.

To retrieve the length of the preparsed data for a read, the client must build an IRP (I/O request packet) to send an I/O control request to the HID device. Clients build this IRP by calling IoBuildDeviceIoControlRequest specifying IOCTL_HID_GET_COLLECTION_INFORMATION as the I/O control (IOCTL) code. This IOCTL requires no input buffer, however the client must supply a pointer to an output buffer of at least sizeof(HID_COLLECTION_INFORMATION) when it calls IoBuildDeviceIoControlRequest. The data returned to the client when the underlying drivers complete this IRP will be formatted in the client-supplied buffer as a HID_COLLECTION_INFORMATION structure.

After this IRP has been built, the driver sends the IOCTL request to the device object representing the underlying HID device of the next lower driver in the HID communication stack with IoCallDriver. When the lower drivers complete this IRP with STATUS_SUCCESS and return control to the client, it can examine the returned data for the length of the preparsed data available for this underlying HID device. The DescriptorSize member of the HID_COLLECTION_INFORMATION structure specifies the number of bytes of available preparsed data. Kernel-mode clients must allocate a buffer from nonpaged pool of at least this size to hold the preparsed data.

After allocating the buffer with ExAllocatePool, the client must create another IRP to send to the HID device to obtain the preparsed data itself. Again, the client calls IoBuildDeviceIoControlRequest, this time specifying IOCTL_HID_GET_COLLECTION_DESCRIPTOR as the I/O control code, together with a pointer to the buffer it just allocated. As for the previous IRP, the client should not specify an input buffer. Again, the client submits the built IRP to the HID communication stack with IoCallDriver.

When the lower drivers complete this IRP with STATUS_SUCCESS and return control to the client, the client has obtained the preparsed data for this HID device. It can then use its pointer to the buffered preparsed data as the required parameter to the HidP_Xxx routines it calls subsequently to obtain information about the capabilities of the underlying HID device. In addition, the client can use this preparsed data returned to extract button and value results for HID reports subsequently.

All Clients

This section includes the following topics:

Obtaining Information about a Collection's Organization and Capabilities

Freeing Resources

Obtaining Information about a Collection's Organization and Capabilities

After a client has connected to a top-level collection, it can obtain the following information about the collection's capabilities and link collections:

  1. Obtains a collection's capabilities.
  2. Obtains button capability arrays and value capability arrays, which describe the capabilities of buttons and values supported by the collection.
  3. Obtains the collection's link collection array, which describes the internal organization of its link collections.

The above information includes the usage of the collection and all the controls supported by the collection. If a client does not use these usages, it should immediately close its connection to the collection.

After completing these steps, a client has the information it requires to access control data in HID reports.

Freeing Resources

HID clients should always free any resources that are no longer required.

For example, user-mode HID clients must call SetupDiDestroyDeviceInfoList with the handle to the device list that they obtained from SetupDiGetClassDevs after completing their initialization and connection operations for a HID device. Failure to call SetupDiDestroyDeviceInfoList causes a memory leak in the client.


HID Device Data I/O

After a client has initialized a top-level collection, as described in Intializing and Connecting a HID Client, it can obtain HID reports from, or send reports to, the collection.

Before a client can use a report buffer, it must properly initialize it, as described in Initializing a Report Buffer.

The following figure shows an example of a top-level collection that contains two reports.

Top-Level Collection with HID Reports

This figure shows two reports, one containing value and button data and the other containing only button data. Each report within this top-level collection has an assigned numerical ID. However, the number of reports within a top-level collection depends on the nature of the underlying HID device and the device interfaces exported by the HID minidriver that controls it.

The following topics describe how a client obtains reports from, and sends reports to, a collection:

Obtaining HID Reports

Sending HID Reports

After a HID client has obtained a report, it can use the HidP_Xxx routines to extract control data from the report, as described in Interpreting HID Reports.


Obtaining HID Reports

This section describes the following topics about how to obtain HID reports from a top-level collection:

Reading Input Reports from an Open File on a Collection

Using HidD_Get Xxx Routines and I/O Requests to Obtain HID Reports


Reading Input Reports from an Open File on a Collection

This section describes user-mode clients and kernel-mode drivers read from an open file on a collection to obtain HID input reports.

Note The HID class driver maintains a ring buffer for input reports that the client does not read immediately. Reports will be lost if buffer overflow occurs because the client does not retrieve input reports fast enough. If this condition occurs, the client can request that the HID class driver increase the size of its ring buffer. See Dropped HID Reports for information about how to set the size of the ring buffer.

User-Mode Clients

A user-mode client calls ReadFile to obtain input reports. The client uses the open file handle it obtained using CreateFile to open a file on the collection. When the client calls ReadFile, it does not have to specify overlapped I/O because the HID class driver buffers reports in a ring buffer. However, a client can use overlapped I/O to have more than one outstanding read request.

Kernel-Mode Drivers

A kernel-mode driver should use IRP_MJ_READ requests to obtain the input reports that the HID class driver buffers for a top-level collection. Consecutive read requests return input reports in the order in which they were received from the device.

For general information about using and reusing IRPs, see Handling IRPs.

Non-WDM Microsoft® Windows® 2000 drivers, and Windows XP and later drivers, can use a single IRP for all read requests to a device. However, Windows 2000 WDM drivers and Windows 98/Me WDM drivers must allocate a new IRP for each read request.

Reusing an IRP conserves system resources and yields significantly better performance in comparison to allocating and freeing a new read IRP for every read request. To reuse an IRP, a driver calls IoAllocateIrp to allocate an IRP, and subsequently calls IoReUseIrp to reinitialize the IRP before using the IRP to initiate a new read request.

If the driver reuses an IRP, the IRP's IoCompletion routine should complete the request with a status of STATUS_MORE_PROCESSING_REQUIRED (and not free the IRP). When the driver no longer requires the IRP, it should complete and free the IRP by calling IoCompleteRequest and IoFreeIrp. For example, a driver might typically complete and free the IRP in its Unload routine, or after a device is removed.

If a driver uses an IRP for only one read request, the IRP's IoCompletion routine should complete and free the IRP, and return STATUS_SUCCESS.

Before a driver can request an input report, it must first allocate a zero-initialized input report buffer from nonpaged memory pool. The size, in bytes, of the buffer is specified by the InputReportByteLength member of a top-level collection's HIDP_CAPS structure. A driver must then use an MDL to map the input report buffer for a read request. The driver calls IoAllocateMdl to allocate the MDL for an input report buffer, and sets the read IRP's Irp->MdlAddress member to the MDL address of the input report buffer. The driver should free the report buffer and the MDL when they are no longer required.

In addition to setting the read IRP's MDL address, the driver must also set the I/O stack location of the next lower-driver. A driver obtains access to the I/O stack location of the next lower-driver by calling IoGetNextIrpStackLocation. The driver sets the following members of the I/O stack location:

Parameters.Read.Length
Set to the size, in bytes, of the read buffer. This must be greater than or equal to the value specified by the InputReportByteLength member of a top-level collection's HIDP_CAPS structure.
Parameters.Read.Key
Set to zero.
Parameters.Read.ByteOffset.QuadPart
Set to zero.
MajorFunction
Set to IRP_MJ_READ.
FileObject
Set to the file object pointer that represents the open file on the top-level collection. This file object pointer is obtained in one of the following two ways:
  • Driver Uses an AddDevice Routine

    A driver with an AddDevice routine attaches itself to a HID device stack by calling IoAttachDeviceToDeviceStack. When the driver receives an IRP_MJ_CREATE request, it saves the file object pointer associated with the create request and, subsequently, sets FileObject to this file object pointer.

  • Driver Uses Plug and Play Notification

    Drivers with Plug and Play notification routines call IoGetDeviceObjectPointer, which returns a pointer to the a file object representing the HID device. The driver set FileObject to this file object pointer.

After the driver has obtained an input report, it can access control data, as described in Interpreting HID Reports.

See also Using HidD_GetXxx Routines and I/O Requests to Obtain HID Reports.


Using HidD_GetXxx Routines and I/O Requests to Obtain HID Reports

The HidD_Get Xxx routines and I/O requests described in this section return HID reports directly from the device, not from the ring buffer that the HID class driver maintains for input reports (which are obtained by using ReadFile or IRP_MJ_READ requests).

Note

A client should only use these routines and I/O requests to obtain the current state of a device. A client should use read requests as its main approach to continuously obtain input reports (see Reading Input Reports from an Open File on a Collection). If a client attempts to use HidD_GetInputReport to continuously obtain input reports, reports can be lost. In addition, some devices might not support HidD_GetInputReport, and will become unresponsive if this routine is used.

User-Mode Clients

A client can use the following HID support routines for clients to obtain the most current input reports and feature reports from a top-level collection:

HidD_GetInputReport
Returns an input report from a top-level collection (Windows® XP and later).
HidD_GetFeature
Returns a feature report from a top-level collection.

A client can request the return of a specific report. To retrieve a specific report using these routines, a client first allocates the report output buffer, zero-initializes the buffer, and sets the first byte in the buffer to the specific report ID. See Interpreting HID Reports for more information.

Kernel-Mode Drivers

A kernel-mode driver can use the following I/O requests to obtain the most current input and feature reports from a top-level collection:

IOCTL_HID_GET_INPUT_REPORT
Returns an input report from a top-level collection (Windows® XP and later).
IOCTL_HID_GET_FEATURE
Returns a feature report from a top-level collection.

A client can request the return of a specific report. To retrieve a specific report using these I/O requests, a client first allocates the output report buffer, zero-initializes the buffer, and sets the first byte in the buffer to the specific report ID. See Interpreting HID Reports for more information.


Sending HID Reports

This section describes the following topics about how to send HID reports to a top-level collection:

Writing an Output Report to an Open File on a Collection

Using HidD_Set Xxx Routines and I/O Requests to Send HID Reports

Before a client can send a report to a HID device, it first must allocate, initialize, and set usage values in the report. For more information about these topics, see Interpreting HID Reports.


Writing an Output Report to an Open File on a Collection

This section describes how user-mode and kernel-mode drivers can write an output report to an open file on a top-level collection.

User-Mode Clients

After a user-mode client has created an output report, it can send an output report to a collection using WriteFile.

Kernel-Mode Clients

A kernel-mode driver should use IRP_MJ_WRITE requests to send a continuous stream of output reports to a top-level collection.

For general information about using and reusing IRPs, see Handling IRPs.

Non-WDM Microsoft® Windows® 2000 drivers, and Windows XP and later drivers, can use a single IRP for all write requests sent to a device. However, Windows 2000 WDM drivers and Windows 98/Me WDM drivers must allocate a new IRP for each write request.

Reusing an IRP conserves system resources and yields significantly better performance in comparison with allocating and freeing a new IRP for every write request. To reuse an IRP, a driver calls IoAllocateIrp to allocate an IRP, and subsequently calls IoReUseIrp to reinitialize the IRP before reusing the IRP to initiate a new write request.

If the driver reuses a write IRP, the IRP's IoCompletion routine should complete the request with a status of STATUS_MORE_PROCESSING_REQUIRED (and not free the IRP). When the driver no longer requires the IRP, it should complete and free the IRP by calling IoCompleteRequest and IoFreeIrp. For example, a driver might typically complete and free the IRP in its Unload routine, or after a device is removed.

If a driver uses an IRP for only one write request, the IRP's IoCompletion routine should complete and free the IRP, and return STATUS_SUCCESS.

Before sending an output report, a driver must first initialize and set an output report buffer, as described in Initializing a Report Buffer. The driver must then use an MDL to map the output report buffer for a write request. A driver calls IoAllocateMdl to allocate the MDL for an output report, and sets a write IRP's Irp->MdlAddress member to the MDL address of the output report buffer. The driver must free the report buffer and the MDL when they are no longer required.

In addition to setting the write IRP's MDL address, the driver must also set the I/O stack location of the next lower-driver. A driver obtains access to the I/O stack location of the next lower-driver by calling IoGetNextIrpStackLocation. The driver sets the following members of the I/O stack location:

Parameters.Write.Length
Set to the length, in bytes, of an output report. This should be set to the length of a top-level collection's output reports, as specified by the OutputReportByteLength member of a collection's HIDP_CAPS structure.
Parameters.Write.Key
Set to zero.
Parameters.Write.ByteOffset.QuadPart
Set to zero.
MajorFunction
Set to IRP_MJ_WRITE.
FileObject
Set to the file object pointer that represents the open file on the top-level collection. This file object pointer is obtained in one of the following two ways:
  • Driver Uses an AddDevice Routine

    A driver with an AddDevice routine attaches itself to a HID device stack by calling IoAttachDeviceToDeviceStack. When the driver receives an IRP_MJ_CREATE request, it saves the file object pointer associated with the create request and, subsequently, sets FileObject to this file object pointer.

  • Driver Uses Plug and Play Notification

    Drivers with Plug and Play notification routines call IoGetDeviceObjectPointer, which returns a pointer to the a file object representing the HID device. The driver set FileObject to this file object pointer.

See also Using HidD_Set Xxx Routines and I/O Requests to Send HID Reports.


Using HidD_SetXxx Routines and I/O Requests to Send HID Reports

A user-mode client can use the following HID support routines for clients to send HID reports to a top-level collection:

HidD_SetOutputReport
Sends an output report to a top-level collection (Windows® XP and later).
HidD_SetFeature
Sends a feature report to a top-level collection.

A kernel-mode driver can use the following I/O requests to send reports to a top-level collection:

IOCTL_HID_SET_OUTPUT_REPORT
Sends an output report to a top-level collection (Windows® XP and later).
IOCTL_HID_SET_FEATURE
Sends a feature report to a top-level collection.

Note

A client should only use these routines and I/O requests to set the current state of a device. A client should use write requests as its main approach to continuously sending output reports (see Writing an Output Report to an Open File on a Collection). Some devices might not support HidD_SetOutputReport, and will become unresponsive if this routine is used.


Interpreting HID Reports

HID clients use HID reports to communicate with a top-level collection.

According to the USB HID Standard, a HID device can return report data in any order and in any precedence. To assist a client in accessing control data in a report, the Microsoft Windows input architecture includes HID support routines for clients that extract data from reports and set data in reports. Data items can be specified by their HID usages or data indices.

For information about extracting control data from a report, see the following:

Extracting Value Data by Specifying Its Usage

Extracting Button Usages That Are Set ON

Extracting and Setting Control Data by Data Indices

For information about setting control data in a report, see the following:

Initializing a Report Buffer

Setting Value Data by Specifying Its Usage

Setting Button State by Specifying Its Usage

Extracting and Setting Control Data by Data Indices

See also Troubleshooting HID Data Interpretation.


Extracting Value Data by Specifying Its Usage

To extract value data from a HID report, a client can use one of the following HID support routines for clients:

HidP_GetScaledUsageValue
Returns a signed and scaled value.
HidP_GetUsageValue
Returns a nonscaled value in an unsigned format or a scaled value that is out of its normal range.
HidP_GetUsageValueArray
Returns a usage value array.

To use HidP_GetUsageValueArray, clients must allocate a zero-initialized buffer, which is large enough to hold the usage value array. The required size, in bytes, is the product of the BitSize and ReportCount members of the usage value array's HIDP_VALUE_CAPS structure, rounded up to the nearest byte.


Extracting Button Usages That Are Set ON

To extract the usages of buttons that are set to ON (one), clients call one of the following HID support routines for clients:

HidP_GetButtons (or HidP_GetUsages)
Returns the usage ID of all buttons on a specified usage page that are set to ON.
HidP_GetButtonsEx (or HidP_GetUsagesEx)
Returns the usage page and usage ID of all buttons that are set to ON.

These routines return an array of all usage information for all buttons that are currently set to ON. Implicitly, buttons whose usage is not returned by these routines are set to OFF (zero).

To call these routines, clients first must allocate, and zero-initialize the buffer used to return the array of button usages. A client calls HidP_MaxUsageListLength to determine the number of button usages in the report that have a specified usage page. If the client specifies a usage page of zero, the routine returns the number of all the button usages in the report.

The required buffer size, in bytes, is the number returned by the HidP_MaxUsageListLength times sizeof(USAGE) (for HidP_GetButtons) or sizeof(USAGE_AND_PAGE) (for HidP_GetButtonsEx).

After a client has used these routines to obtain information about which buttons are currently set to ON, it can determine the difference between the current state and the previous state of the buttons by calling one of the following HID support routines for clients. These routines return the difference between two arrays of usage information:

HidP_UsageListDifference

HidP_UsageAndPageListDifference


Initializing a Report Buffer

Before a client can use the HidP_Set Xxx routines to set data in a new HID report, the client must create a zero-initialized report buffer of the required size, in bytes, for the report type. The Xxx ReportByteLength members of a top-level's collection HIDP_CAPS structure specify the required size of input, output, and feature reports. After initializing a report, a client can set control data in the report. On the first use of the report, the HidP_Set Xxx routines set the report ID to the one associated with a specified usage. If the client subsequently attempts to set a usage that is incompatible with the report ID, the HidP_Set Xxx routines return a status of HIDP_STATUS_INCOMPATIBLE_REPORT_ID.


Setting Value Data by Specifying Its Usage

A client can set a value in a properly initialized HID report by calling one of the following HID support routines for clients:

HidP_SetScaledUsageValue
Sets a signed and scaled value in a report.
HidP_SetUsageValue
Sets a value in a report.
HidP_SetUsageValueArray
Sets a usage value array in a report.
See also Initializing a Report Buffer.


Setting Button State by Specifying its Usage

A client can set the state of buttons in a properly initialized HID report by calling one of the following HID support routines for clients:

HidP_SetButtons (or HidP_SetUsages)
Sets a specified set of buttons to ON (one).
HidP_UnsetButtons (or HidP_UnsetUsages)
Sets a specified set of buttons to OFF (zero).
See also Initializing a Report Buffer.


Extracting and Setting Control Data by Data Indices

To use data indices to extract and set control data in a HID report, a client can use the following HID support routines for clients:

HidP_GetData

HidP_SetData

These routines are particularly useful to a client that provides a "value-added" service. For example, one that provides a custom interface to all the controls supported by a HID device. Microsoft® DirectInput® is one example.

By calling these routines, a client can most efficiently obtain and set all values in a report. For example, to obtain all value data by their HID usages, a client has to call HidP_GetUsageValue for each usage. However, to obtain all value data by data index, a client only has to call HidP_GetData once.

A client uses the data indices specified in a collection's button capability arrays and value capability arrays to map between HID usages and data indices.


Troubleshooting HID Data Interpretation

This section describes the following most common problems that kernel-mode drivers might encounter when attempting to extract or set HID usages.

HID Report ID Errors

Dropped HID Reports


HID Report ID Errors

When a client receives data from a HID device, it can be any report that the top-level collection contains, as a HID device can return HID reports in any order. The HidP_Get Xxx routines return the following status values, which inform the client about report ID errors:

HIDP_STATUS_INCOMPATIBLE_REPORT_ID
A requested usage is in a report supported by the top-level collection, but not in the report that the client provided.
HIDP_STATUS_USAGE_NOT_FOUND
A requested usage is not in any report supported by the top-level collection.

For example, the following figure shows a top-level collection that contains two reports.

HID Reports

Based on this example, assume a client just received a report from a collection and calls HidP_GetUsageValue to extract the current value of "Value X". If the report's ID is seven, the routine returns HIDP_STATUS_INCOMPATIBLE_REPORT_ID, which indicates that the device supports Value X, but that Value X is not present in the report. On the other hand, if the client requested the value of "Value Z", the routine returns HIDP_STATUS_USAGE_NOT_FOUND, which indicates that Value Z is not in any report supported by the collection.

When a client uses HidP_Set Xxx routines to set usages in a report, the routines can also return the same two status values. The meaning of HIDP_STATUS_USAGE_NOT_FOUND is the same as with the HidP_GetXxx routines. However, the meaning of HIDP_STATUS_INCOMPATIBLE_REPORT_ID is different. This status value indicates that the report was previously configured with a report ID, and the usage specified by the caller does not belong to that report ID. Using the previous figure as an example, after a client uses HidP_SetUsages to set "Button 2" in a zero-initialized report, the report is configured with a report ID of seven. If the client subsequently attempts to use HidP_SetUsageValue to set "Value X" in the same report, the routine will return HIDP_STATUS_INCOMPATIBLE_REPORT_ID.

If a HidP_Xxx routine returns HIDP_STATUS_INCOMPATIBLE_REPORT_ID, a client should take one of the following actions:

Setting Usages
Allocate a new report of the correct length, zero-initialize it, and then call the routine again. After successfully setting all usages in the report, the client can send the report to the device.
Extracting Usages
Call the routine with a different report obtained from the device.


Dropped HID Reports

When the HID class driver obtains input reports from a device, the reports are stored in a ring buffer maintained by the HID class driver. This mechanism reduces the possibility that a client will miss input reports that it requires.

By default, the HID class driver maintains an input report ring buffer that holds 32 reports. If a device transmits data to the HID class driver faster than the client retrieves it from the buffer, input reports are lost because of buffer overflow. To reduce the possibility of buffer overflow, a client can reconfigure the size, in number of reports, of the buffer. Kernel-mode clients retrieve and change the size of the buffer by using an IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS request and an IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS request. User-mode clients do the same operation by calling HidD_GetNumInputBuffers and HidD_GetNumInputBuffers.


Keyboard and Mouse Drivers for Non-HID Devices

This section includes the following topics about the Microsoft® Windows® 2000 and later system drivers for non-HID keyboard and mouse devices:

  • The features and standard configurations of the following drivers:
    • Kbdclass, the class driver for devices of GUID_CLASS_KEYBOARD device class
    • Mouclass, the class driver for devices of GUID_CLASS_MOUSE device class
    • I8042prt, the function driver for a PS/2-style keyboard device and a PS/2-style mouse device
  • Using an optional upper-level device filter driver to customize the operation of a PS/2-style keyboard or mouse device
  • The features of Kbfiltr, a sample upper-level keyboard filter driver in the Windows DDK
  • The features of Moufiltr, a sample upper-level mouse filter driver in the Windows DDK

This section does not cover detailed information about Sermouse, the Windows system function driver for a serial mouse. Note that the operational constraints that apply to I8042prt do not apply to Sermouse. In addition, upper-level device filter drivers are not used with Sermouse to customize the operation of a serial mouse. Instead, vendors need to install a device-specific function driver for the device. A device-specific function driver and Sermouse can operate at the same time, independent of one another.

See the following topics for more information on the operation of non-HID keyboard and mouse devices:

Typical Physical Configuration of Keyboard and Mouse Devices

Features of the Kbdclass and Mouclass Drivers

Features of the I8042prt Driver

Features of the Kbfiltr and Moufiltr Drivers

Standard Configuration of Keyboard and Mouse Drivers for Non-HID Devices

Operation of Non-HID Keyboard and Mouse Drivers

Installing Keyboard and Mouse Devices

Kbdclass Driver Reference

Mouclass Driver Reference

I8042prt Driver Reference

Kbfiltr Driver Reference

Moufiltr Driver Reference

Include files ntddkbd.h and ntddmou.h in the %user's install path%\inc directory in the Windows DDK

Sample code in the %user's install path%\src\input directory in the Windows DDK


Typical Physical Configuration of Keyboard and Mouse Devices

This section describes the typical physical configuration of keyboard and mouse devices in Microsoft® Windows® 2000 and later.

The following figure shows two common configurations that employ a single keyboard and a single mouse.

Left Figure: Keyboard and Mouse Devices Connected Through Independent Controllers

Right Figure: Keyboard and Mouse devices Connected Through an Integrated Controller

The previous figure on the left shows a keyboard and a mouse connected to a system bus through independent controllers. A typical configuration consists of a PS/2-style keyboard operated through an i8042 controller, and a serial-style mouse operated through a serial port controller. The previous figure on the right shows the keyboard and mouse connected through an integrated keyboard and mouse controller. A typical configuration consists of a PS/2-style keyboard and a PS/2-style mouse operated through an i8042 controller.

Windows also supports the simultaneous connection of more than one keyboard and mouse device. However, Windows does not support independent access by a client to each device. The Microsoft Win32® subsystem opens all keyboard and mouse devices for its exclusive use.

For more information on software device configuration, see the following topics:

Standard Configuration of Keyboard and Mouse Drivers for Non-HID Devices

Open and Close a Keyboard and Mouse Device


Features of the Kbdclass and Mouclass Drivers

This section describes the features of the following Microsoft® Windows® 2000 and later system class drivers:

  • Kbdclass, the class driver for devices of GUID_CLASS_KEYBOARD device class
  • Mouclass, the class driver for devices of GUID_CLASS_MOUSE device class

Kbdclass implements the Kbdclass service and its executable image is kbdclass.sys.

Mouclass implements the Mouclass service and its executable image is mouclass.sys.

Kbdclass and Mouclass each feature:

  • Generic and hardware-independent operation of the device class
  • Plug and Play, power management, and Windows Management Instrumentation (WMI)
  • Operation of legacy devices
  • Simultaneous operation of more than one device
  • Connection of a class service callback routine that a function driver uses to transfer data from the input data buffer of the device to the data buffer of the class driver


Features of the I8042prt Driver

This section describes the features of I8042prt, the Microsoft® Windows® 2000 and later system function driver for PS/2-style keyboard and mouse devices.

I8042prt implements the I8042prt service and its executable image is i8042prt.sys.

The features of I8042prt include:

  • Hardware-dependent, simultaneous operation of a PS/2-style keyboard and mouse device

    The keyboard and mouse share I/O ports, but use different interrupts, interrupt service routines (ISR), and ISR dispatch completion routines.

  • Plug and Play, power management, and WMI
  • Operation of legacy devices
  • Connection of a keyboard class service callback routine and a mouse class service callback routine

    I8042prt uses the class service callback to transfer data from the input data buffer of I8042prt to the data buffer of the class driver.

  • Addition of a custom initialization callback routine for a keyboard device

    An optional upper-level device filter driver provides the callback.

  • Addition of a custom keyboard device ISR callback and a custom mouse device ISR callback

    An optional upper-level device filter driver provides the callback.

  • Keyboard write buffer request and mouse write buffer request

    An upper-level device filter driver can use write buffer requests to synchronize its writes to a device with the ISR of the device and other reads and writes on the device.

  • Keyboard start information request and mouse start information request

    The start information request passes a pointer to an interrupt object of a device to an upper-level filter driver. The filter driver can use the interrupt object to synchronize its operation with the ISR of the device.

  • Keyboard callback routines and mouse callback routines

    An upper-level device filter driver can use the callback routines in the context of the ISR of a device to write to a device, and to queue data packets from the device.


Features of the Kbfiltr and Moufiltr Drivers

This section describes the features of the following sample filter drivers in the Microsoft® Windows® DDK:

  • Kbfiltr, an optional upper-level filter driver for a Plug and Play PS/2-style keyboard device
  • Moufiltr, an optional upper-level filter driver for a Plug and Play PS/2-style mouse device

Kbfiltr and Moufiltr demonstrate how to filter I/O requests and add callback routines that modify the operation of the class service and the operation of I8042prt.

Note The design of the Windows 2000 and later Terminal Server does not support using the sample keyboard and mouse filter drivers to filter input from devices physically installed on a remote client. A filter driver installed on a Terminal Server can only be used to filter the input from the devices physically installed on a Terminal Server. This is a consequence of the way the TermDD.sys driver for the Terminal Server handles input from remote clients.

Kbfiltr and Moufiltr support Plug and Play and power management.

Kbfiltr provides the following callback routines:

KbFilter_ServiceCallback
The keyboard filter service callback is added to the keyboard class service callback. The filter service callback can be configured to modify the keyboard input data saved in the class driver's data queue.
KbFilter_IsrHook
The keyboard filter ISR hook routine is a template for the IsrRoutine callback that I8042prt supports for a keyboard device. The callback can be configured to customize the operation of an ISR of a keyboard.
KbFilter_InitializationRoutine
The keyboard filter initialization routine is a template for the InitializationRoutine callback that I8042prt supports for a keyboard device. This callback can be configured to customize the initialization of a keyboard device.

Moufiltr provides the following callback routines:

MouFilter_ServiceCallback
The mouse filter service callback is added to the mouse class service callback. The filter service callback can be configured to modify the keyboard input data saved in the class driver's data queue.
MouFilter_IsrHook
The mouse filter ISR hook routine is a template for the IsrRoutine callback that I8042prt supports for a mouse device. The callback can be configured to customize the operation of that mouse's ISR.


Standard Configuration of Keyboard and Mouse Drivers for Non-HID Devices

This section describes the following:

Standard Keyboard and Mouse Driver Stacks

Configuration of Device Objects for a Single Keyboard or a Single Mouse Device

Configuration of Device Objects for more than One Device


Standard Keyboard and Mouse Driver Stacks

This section describes the standard device stacks for a Plug and Play PS/2-style keyboard and mouse, a Plug and Play serial mouse, and a legacy keyboard and mouse device.

Plug and Play PS/2-style Keyboard

Top to bottom, the driver stack contains:

  • Kbdclass, the upper-level keyboard class filter driver
  • An optional upper-level keyboard filter driver
  • I8042prt, the function driver
  • Root bus driver

Plug and Play PS/2-style Mouse

Top to bottom, the driver stack contains:

  • Mouclass, the upper-level mouse class filter driver
  • An optional upper-level mouse filter driver
  • I8042prt, the function driver
  • Root bus driver

Plug and Play Serial Mouse

Top to bottom, the stack contains:

  • Mouclass, the upper-level mouse class filter driver
  • Sermouse, the serial mouse function driver
  • Serenum, the upper-level device filter driver for an RS-232 port

Legacy Keyboard and Mouse

Top to bottom, the stack contains:

  • Class driver for the device
  • Function driver for the device.


Configuration of Device Objects for a Single Keyboard or a Single Mouse Device

The following figure shows the configuration of device objects for a Plug and Play PS/2-style keyboard and mouse device.

Configuration of Device Objects for a Plug and Play PS/2-style Keyboard and Mouse Device

Each class driver creates an upper-level class filter device object (DO) that is attached to a function DO through an optional upper-level device filter DO. An upper-level device filter driver creates the upper-level device filter DO. I8042prt creates the function DO and attaches it to a physical device object (PDO) created by the root bus driver.

The following figure shows the configuration of device objects for a Plug and Play serial mouse.

Configuration of Device Objects for a Plug and Play Serial Mouse

Mouclass creates an upper-level class filter DO that is attached to a function DO created by Sermouse (or a vendor replacement for Sermouse). The Sermouse DO is attached to a PDO created by Serenum.

The following figure shows the configuration of device objects for a legacy device:

Configuration of Device Objects for a Legacy Device

The class driver creates a class device object and attaches to a function device object created by the function driver.


Configuration of Device Objects for more than One Device

Kbdclass and Mouclass can support more than one device in two different modes. In the one-to-one mode, each device has an independent device stack. The class driver creates and attaches an independent class DO to each device stack. Each device stack has its own control state and input buffer. The Microsoft® Win32® subsystem accesses input from each device through a unique file object.

In the grandmaster mode, the class driver operates all the devices in the following way:

  • The class driver creates a grandmaster class DO that represents all the devices and a subordinate class DO for each device.

    The class driver attaches a subordinate class DO to each device stack. Below the subordinate class DO, the device stack is same as that created in the one-to-one mode.

  • The grandmaster class DO controls the operation of all the subordinate DOs.
  • The Win32 subsystem accesses all device input through the file object that represents the grandmaster class device.
  • All device input is buffered in the grandmaster's data queue.
  • The grandmaster maintains a single global device state.

Kbdclass and Mouclass operate in the one-to-one mode if their registry entry value ConnectMultiplePorts is set to 0x00 (under the key HKLM\Services\CurrentControlSet\<class service>\Parameters, where class service is Kbdclass or Mouclass). Otherwise Kbdclass and Mouclass operate in grandmaster mode.


Operation of Non-HID Keyboard and Mouse Drivers

This section describes the following topics about the operation in Microsoft® Windows® 2000 and later of Kbdclass, Mouclass, I8042prt, Kbfiltr, and the optional upper-level device filter drivers:

Open and Close a Keyboard and Mouse Device

Connect a Class Service Callback and a Filter Service Callback to a Device

Customize the Initialization and ISR of a Device

Synchronize the Operation of a Filter Driver with a Device's ISR

Synchronize Writes by a Filter Driver to a Device

I8042prt Callbacks that Filter Drivers Can Use

Query and Set a Keyboard Device

Query a Mouse Device

Special Requirements for Absolute Pointing Devices

Registry Settings


Open and Close a Keyboard and Mouse Device

The Microsoft® Win32® subsystem opens all keyboard and mouse devices for its exclusive use. For each device class, the Win32 subsystem treats input from all the devices as if the input came from a single input device. An application cannot request to receive input from only one particular device.

The Win32 subsystem dynamically opens Plug and Play input devices after it receives notification from the Plug and Play Manager that a GUID_CLASS_KEYBOARD or GUID_CLASS_MOUSE device interface is enabled. The Win32 subsystem closes Plug and Play devices after it receives notification that an opened interface is disabled. The Win32 subsystem also opens legacy devices by name, for example, "\Device\KeyboardLegacyClass0". Note that once the Win32 subsystem successfully opens a legacy device, it cannot determine if the device is later physically removed.

After Kbdclass and Mouclass receive a create request they do the following for Plug and Play and legacy operation:

Plug and Play Operation
If the device is in the Plug and Play started state, the class driver sends the IRP_MJ_CREATE request down the driver stack. Otherwise the class driver completes the request without sending the request down the driver stack. The class driver sets the trusted file that has read access to the device. If there is a grandmaster device, the class driver sends a create request to all the ports that are associated with the subordinate class devices.
Legacy Operation
The class driver sends an internal device control request to the port driver to enable the device.


Connect a Class Service Callback and a Filter Service Callback to a Device

The class drivers must connect their class service to a device before the device can be opened. The class drivers connect their class service after they attach a class DO to a device stack. The function driver uses the class service callback to transfer input data from a device to the class data queue for the device. The function driver's ISR dispatch completion routine for a device calls the class service callback. Kbdclass provides the class service callback KeyboardClassServiceCallback, and Mouclass provides the class service callback MouseClassServiceCallback.

A vendor can modify the operation of a class service callback by installing an upper-level filter driver for a device. The sample filter driver Kbfiltr defines the KbFilter_ServiceCallback callback, and the sample filter driver Moufiltr defines the MouFilter_ServiceCallback callback. The sample filter service callbacks can be configured to modify the input data that is transferred from the port input buffer for a device to the class data queue. For example, the filter service callback can delete, transform, or insert data.

The class and filter service callbacks are connected in the following way:

  • The class driver sends an internal device connect request down the device stack (IOCTL_INTERNAL_KEYBOARD_CONNECT or IOCTL_INTERNAL_MOUSE_CONNECT). The class connect data is specified by a CONNECT_DATA structure that includes a pointer to the class device object, and a pointer to the class service callback.
  • After the filter driver receives the connect request, it saves a copy of the class connect data, and replaces the request's connect data with filter connect data. The filter connect data specifies a pointer to the filter device object and a pointer to the filter driver service callback. The filter driver then sends the filtered connect request to the function driver.

The class and filter service callbacks are called in the following way:

  • The function driver uses the filter connect data to make the initial callback to the filter service callback.
  • After filtering the input data, the filter service callback uses the class connect data that it saved to make a callback to the class service callback.


Customize the Initialization and ISR of a Device

I8042prt supports the following optional callback routines that can be provided by upper-level device filter drivers:

Keyboard IsrRoutine
The keyboard ISR routine customizes the operation of the i8042 controller for a keyboard device. An IsrRoutine callback is not needed if the default operation of I8042prt is sufficient. The keyboard IsrRoutine callback is called by I8042prt's interrupt service routine for a keyboard device.
Mouse IsrRoutine
The mouse ISR routine customizes the operation of the i8042 controller for a mouse device. An IsrRoutine callback is not needed if the default operation of I8042prt is sufficient. The mouse IsrRoutine callback is called by I8042prt's interrupt service routine for a mouse device.
Keyboard InitializationRoutine
The keyboard initialization routine supplements the default initialization of a keyboard device by I8042prt. I8042prt calls this routine when it initializes a keyboard device.

I8042prt adds the callbacks provided by an upper-level device filter driver by using an IOCTL_INTERNAL_I8042_HOOK_KEYBOARD request for a keyboard device and an IOCTL_INTERNAL_I8042_HOOK_MOUSE request for a mouse device. After I8042prt receives a connect request from a device class driver, I8042prt synchronously sends the device-specific hook request to the top of the device stack

After a filter driver receives a hook request, it does the following:

  • Saves the upper-level driver hook information, if any, that is passed to the filter driver

    The hook information includes a pointer to a context, a pointer to an ISR callback, and a pointer to an initialization callback (initialization callback for a keyboard only).

  • Replaces the upper-level driver hook information with the filter driver's hook information
  • Saves the context of I8042prt and the pointers to callbacks that the filter driver callbacks can use

The sample filter drivers, Kbfiltr and Moufiltr, provide the following callback routines:

  • KbFilter_IsrHook is a template for the keyboard IsrRoutine callback.
  • KbFilter_InitializationRoutine is a template for the keyboard InitializationRoutine callback.
  • MouFilter_IsrHook is a template for the mouse IsrRoutine callback.


Synchronize the Operation of a Filter Driver with a Device's ISR

I8042prt uses a start information request to pass a pointer to a device's interrupt object to the upper-level drivers in its device stack. After a device is started, the filter driver can use the interrupt object to synchronize it's operation with the interrupt service routine. Filter drivers should only use the interrupt object in calls to KeSynchronizeExecution.

I8042prt passes the interrupt object pointer to the top of the device stack by using an IOCTL_INTERNAL_I8042_KEYBOARD_START_INFORMATION request for a keyboard device and an IOCTL_INTERNAL_I8042_MOUSE_START_INFORMATION request for a mouse device. I8042prt synchronously sends a start information request to the top of the device stack after the hardware initialization of a device. After a filter driver receives a start information request, it saves the start information and passes the request down the device stack. I8042prt completes the request.


Synchronize Writes by a Filter Driver to a Device

To customize the operation of a device, a filter driver needs to write control data to the device. The filter driver must synchronize writes to a device with the device's interrupt service routine and other asynchronous reads or writes on the device (for example, writes that are initiated by a set typematic request or a set keyboard indicator request).

I8042prt supports an IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER request and an IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER request for this purpose. A write buffer request is synchronized with the device's ISR and other requests that read or write the device.


I8042prt Callbacks that Filter Drivers Can Use

I8042prt supports the following callback routines, which an upper-level device filter driver can call in its ISR callback:

Keyboard IsrWritePort
The keyboard ISR write port routine writes to a keyboard device at the IRQL of the device's ISR.
Mouse IsrWritePort
The mouse ISR write port routine writes to a mouse device at the IRQL of the device's ISR.
QueueKeyboardInput
The queue keyboard input routine queues a keyboard input data packet for processing by the device's ISR DPC.
QueueMouseInput
The queue mouse input routine queues a mouse input data packet for processing by the device's ISR DPC.

I8042prt passes pointers to the keyboard device callbacks in a INTERNAL_I8042_HOOK_KEYBOARD structure that I8042prt uses to input information with an IOCTL_INTERNAL_I8042_HOOK_KEYBOARD request.

I8042prt passes pointers to the mouse device callbacks in a INTERNAL_I8042_HOOK_MOUSE structure that I8042prt uses to input information with an IOCTL_INTERNAL_I8042_HOOK_KEYBOARD request.

After a filter driver receives a hook device request, it saves the I8042prt callback pointers for use in the filter driver's ISR callback.


Query and Set a Keyboard Device

I8042prt supports the following internal device control requests to query information about a keyboard device, and to set parameters on a keyboard device:

IOCTL_KEYBOARD_QUERY_ATTRIBUTES

IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION

IOCTL_KEYBOARD_QUERY_INDICATORS

IOCTL_KEYBOARD_QUERY_TYPEMATIC

IOCTL_KEYBOARD_SET_INDICATORS

IOCTL_KEYBOARD_SET_TYPEMATIC

For more information on all keyboard device control requests, see I8042prt Keyboard Internal Device Control Requests.


Query a Mouse Device

I8042prt supports the following internal device control request to query information about a mouse device:

IOCTL_MOUSE_QUERY_ATTRIBUTES

For more information on all mouse device control requests, see I8042prt Mouse Internal Device Control Requests.


Special Requirements for Absolute Pointing Devices

For devices of type GUID_CLASS_MOUSE, a device's function driver:

  • Handles device-specific input.
  • Creates the MOUSE_INPUT_DATA structures required by MouseClassServiceCallback.
  • Transfers MOUSE_INPUT_DATA structures to the Mouclass data queue by calling MouseClassServiceCallback in its ISR dispatch completion routine.

For an absolute pointing device, the device's function driver must set the LastX, LastY, and Flags members of the MOUSE_INPUT_DATA structures in the following way:

  • In addition to dividing the device input value by the maximum capability of the device, the driver scales the device input value by 0xFFFF:
    LastX = ((device input x value) * 0xFFFF ) / (Maximum x capability of the device)
LastY = ((device input y value) * 0xFFFF ) / (Maximum y capability of the device)
  • The driver sets the MOUSE_MOVE_ABSOLUTE flag in Flags.
  • If the input should be mapped by the window manager to an entire virtual desktop, the driver sets the MOUSE_VIRTUAL_DESKTOP flag in Flags. If the MOUSE_VIRTUAL_DESKTOP flag is not set, the window manager maps the input to only the primary monitor.

The following specifies, by type of device, how these special requirements for an absolute pointing device are implemented:

  • HID devices

    Mouhid, the Windows function driver for HID mouse devices, implements these special requirements automatically.

  • PS/2-style devices

    An upper-level filter driver is required. The filter driver supplies an IsrHook callback and a class service callback. I8042prt calls the IsrHook to handle raw device input, and calls the filter class service callback to filter the input. The filter class service callback, in turn, calls MouseClassServiceCallback. The combination of the IsrHook callback and the class service callback handles device-specific input, creates the required MOUSE_INPUT_DATA structures, scales the device input data, and sets the MOUSE_MOVE_ABSOLUTE flag.

  • Plug and Play COM port devices that are enumerated by Serenum

    A Plug and Play function driver is required. The function driver creates the required MOUSE_INPUT_DATA structures, scales the device input data, and sets the MOUSE_MOVE_ABSOLUTE flag before it calls MouseClassServiceCallback.

  • Non-Plug and Play COM port devices

    A device-specific function driver is required. The function driver creates the required MOUSE_INPUT_DATA structures, scales the device input data, and sets the MOUSE_MOVE_ABSOLUTE flag before it calls MouseClassServiceCallback.

  • Device on an unsupported bus

    A device-specific function driver is required. The function driver creates the required MOUSE_INPUT_DATA structures, scales the device input data, and sets the MOUSE_MOVE_ABSOLUTE flag before it calls MouseClassServiceCallback.


Registry Settings

For more information on the registry settings for keyboard and mouse devices, see the resource kits for Microsoft® Windows® 2000 and later.


Installing Keyboard and Mouse Devices

This section documents the following class-specific INF file entries that a vendor can use to control how the Microsoft-supplied keyboard and mouse class installers install devices under Microsoft® Windows® 2000 and later:

INF DDInstall.MigrateToDevNode Section

INF SharedDriver Entry

INF PS2_Inst.NoInterruptInit.Bioses Section

INF PS2_Inst.NoInterruptInit Section

For specific examples, see the usage of these INF file entries in keyboard.inf and msmouse.inf — the Microsoft-supplied INF files for the keyboard and mouse device setup classes.


INF DDInstall.MigrateToDevNode Section

[install-section-name.MigrateToDevNode] |
[install-section-name.nt.MigrateToDevNode] |
[install-section-name.ntx86.MigrateToDevNode] |
[install-section-name.ntia64.MigrateToDevNode]

ServiceName=value-name[,value-name],...

The keyboard and mouse class installers copy the entry values specified by the list of value-name strings from the registry key HKLM\System\CurrentControlSet\Services\ServiceName\Parameters to the device node of the device being installed.

Entries and Values

ServiceName
Specifies the service name associated with a device port (for example, i8042prt, sermouse, and so on).
value-name
Specifies an entry value under the registry key HKLM\System\CurrentControlSet\Services\ServiceName\Parameters.

Comments

Microsoft supports INF DDinstall.MigratetoDevNode sections primarily to facilitate porting Windows NT® 4.0 legacy devices to Windows 2000 and later.

The keyboard and mouse class installers copy all the value-name entry values before the system starts the device stack. The specified entry values can be any valid registry entry values. The value-name entry values are not deleted from the ...\ServiceName\Parameters registry key.


INF SharedDriver Entry

[ControlFlags]

SharedDriver=install-section-name,warning-text-string

Before the keyboard or mouse class installer installs a PS/2 device, it checks for a SharedDriver entry in the INF ControlFlags Section for the device. If such an entry value exists, the class installer notifies the user by displaying the warning text string, and provides the user the option to cancel changing the PS/2 port driver.

Entries and Values

SharedDriver
Specifies that the device driver is shared by both a PS/2 keyboard and mouse device.
install-section-name
Specifies a device's DDInstall section.
warning-text-string
Specifies a string the class installer uses to warn a user before changing the PS/2 port driver.


INF PS2_Inst.NoInterruptInit.Bioses Section

[PS2_Inst.NoInterruptInit.Bioses]

Disable=disable-string

The mouse class installer checks if disable-string is a substring of the string value of HKLM\Hardware\Description\System\SystemBiosVersion. If it is, the class installer executes the INF directives specified in an INF PS2_Inst.NoInterruptInit Section.

Entries and Values

Disable
Set to the disable-string value.
disable-string
Specifies a substring in HKLM\Hardware\Description\System\SystemBiosVersion that uniquely identifies the system BIOS.

Comments

This section is used only with PS/2 mouse devices and only in combination with an INF PS2_Inst.NoInterruptInit Section.


INF PS2_Inst.NoInterruptInit Section

[PS2_Inst.NoInterruptInit]
AddReg = add-reg-section.AddReg

The mouse class installer executes the directives in this section if the Disable entry in an INF PS2_Inst.NoInterruptInit.Bios Section matches the system BIOS version.

Entries and Values

add-reg-section
Specifies an AddReg section that the mouse class installer uses to set registry values in a device's hardware key. The registry values determine whether the system initializes a mouse device by using interrupts or by polling.

Comments

This section is only used in combination with an INF PS2_Inst.NoInterruptInit.Bioses Section. The primary purpose of this section is to specify an AddReg section that adds registry values to a mouse device's hardware key.

add-reg section Entries

HKR,,"DisableInitializePolledUI",0x00010001,1
HKR,,"MouseInitializePolled",0x00010001,1

DisableInitializePolledUI
Specifies a REG_DWORD flag that indicates whether or not the Fast Initialization check box on the property page will be available. If DisableInitializePolledUI is set to a nonzero value, the check box is unavailable; otherwise the checkbox is available.
MouseInitializedPolled
Specifies a REG_DWORD flag that indicates whether or not the system must poll the device to initialize it. If MouseInitializedPolled is set to one, the system polls the mouse device; otherwise the system uses interrupts.


DirectInput

The Microsoft® DirectInput® documentation describes how to write drivers for the input components of Microsoft DirectX® versions 1.0, 2.0, 3.0, 5.0, 6.0, 7.0, 7.0a, and 8.0. DirectX versions 1.0 and 2.0 included the same joystick support as the original Microsoft Windows® 95, while DirectX 3.0 added Component Object Model (COM) interfaces for mouse and keyboard access and improved the implementation of some joystick support without changing the driver model. Mouse and keyboard drivers are not covered in this documentation; consult the Windows 95 DDK for information about writing mouse and keyboard drivers. DirectX 5.0 added a COM interface for joystick access, force feedback, and for simplified access to joystick configuration information.

This documentation includes the following topics:

Joystick Support

Force Feedback Device Driver Interface

Extending the DirectInput Game Controller Control Panel


Joystick Support

There are differences from version to version in the type of joystick support that Microsoft® DirectX® offers. In Windows® 95, DirectX supports two methods to customize joystick capabilities: through custom entries in the Windows 95 registry and by creating a virtual device driver (VxD) called a joystick minidriver. The minidrivers that are used in DirectX versions 1.0, 2.0, and 3.0 support the original minidriver interface, with minor differences in the DirectX 3.0 interface. In addition to the original minidriver model, DirectX versions 5.0 and 6.0 include an alternative driver interface that is usually described separately.

Windows 95 joystick driver and configuration programs support analog joysticks that plug into the IBM standard game port. Joystick makers can customize joystick configuration programs by providing explicit directions to the end user on how to customize the joystick. Joysticks can signal Windows 95 about their capabilities through the registry. These capabilities can include the use of throttle, point-of-view (POV) hats, rudders, and the number of buttons the joystick has.

All non-IBM standard joysticks, such as digital joysticks, MIDI joysticks, and analog joysticks driven by joystick accelerators, must provide a joystick minidriver in addition to custom registry information. A joystick OEM can write a minidriver that provides access to nonstandard joystick hardware. This provides a mechanism for digital joysticks to work with any Windows-based game that uses the joystick application programming interface (API). The driver model is capable of dealing with up to six axes, a POV hat, and a doubleword of buttons, so that an OEM can easily create a minidriver for new hardware with a higher degree of freedom than the current game port allows. The joystick minidriver provides complete flexibility to hardware vendors while allowing game creators to utilize the installed base with their titles. In DirectX 5.0, analog joystick support is also separated into a minidriver using a new interface so that it is loaded only when an analog game port is configured. The polling has also been extended with three extra POV hats, three more doublewords containing button data, and a method to specify that velocity, acceleration, and/or force data be returned for each axis.

The current virtual joystick driver (VJoyD) allows the configuration of up to 16 devices, any number of which can be driven by minidrivers. The configuration of minidrivers to devices can be one to one or one to many.


Joystick Driver Model

One of the most critical goals of the joystick driver model is to provide timely access to joystick information. Windows 95 joystick services are provided through two drivers: a 16-bit ring 3 driver (Msjstick.drv), and a 32-bit ring 0 driver (Vjoyd.vxd). The Msjstick.drv driver provides basic services such as registry updating and caps info; Vjoyd.vxd provides polling services.

The API for the joystick is provided through the Mmsystem.dll dynamic-link library (DLL) for 16-bit applications on Windows 95, and through the Winmm.dll DLL for 32-bit applications. Mmsystem.dll communicates with Msjstick.drv for all joystick services (Msjstick.drv communicates with Vjoyd.vxd to supply polling services). Winmm.dll communicates directly with Vjoyd.vxd for the polling services, and thunks to Mmsystem.dll for the basic services that are not time-critical.

Starting in DirectX 5.0, Dinput.dll offered an alternative, COM-based API. Dinput.dll uses VJoyD and, if available, the Human Input/Interface Device (HID) stack, to provide polling services. HID devices are also reported through VJoyD so that applications using the older API are still able to read the new devices. Force-feedback handling is provided by a driver supplied by the OEM, which can be either a DLL loaded by Dinput.dll, or an extended VJoyD minidriver.


Minidriver-Supplied Callbacks

Joystick hardware that is not polled or that has nonstandard polling requirements can implement a minidriver (which must be a VxD) that VJoyD loads when a device of that type is in use. VJoyD also calls the minidriver to access position and button information. Joystick minidrivers are not required to provide any interfaces other than processing the standard SYS_DYNAMIC_DEVICE_INIT and SYS_DYNAMIC_DEVICE_EXIT messages when the device is loaded and unloaded, and defining and registering four joystick-specific callbacks. In addition to supporting this original interface, the DirectX 5.0 and 6.0 VJoyD also supports an extended interface. The extended interface allows new callbacks to be registered to support polling, force feedback and hot plugging of joysticks.

On request from Msjstick.drv, VJoyD checks which minidrivers should be loaded (and unloaded). Msjstick.drv makes the request for each device it handles and whenever the call to joyConfigChanged is made. Msjstick.drv is initialized for each device it handles during the normal boot sequence, which means that some devices and services may be unavailable to the minidriver at the time it is loaded . Because VJoyD loads minidrivers when they are found to be assigned to a joystick number; not when an application needs to use the device, processing should be kept to a minimum. No background processing, shared resource usage, or large-scale memory allocations should be started simply because the VxD has been loaded. The DirectX 5.0 and 6.0 VJoyD does its initial loading of minidrivers at a later stage in the boot process than the original.


The Original Interface

The following joystick minidriver callbacks are specific to the original interface:

  • A Polling Callback for returning the joystick position and button information.
  • A Configuration Manager Callback for handling the configuration manager messages in Windows 95.
  • A Hardware Capabilities Callback for handling requests for joystick capabilities.
  • A Joystick Identification Callback used by VJoyD to inform a minidriver of those joysticks for which it should respond.

The four joystick-specific callbacks must be registered with the VJoyD VJOYD_Register_Device_Driver service before returning from processing the SYS_DYNAMIC_DEVICE_INIT message. EAX must point to the polling routine, EBX the configuration handler, ECX the capabilities callback, and EDX the identification routine. Here is an example of a joystick minidriver registration sequence:

mov | eax, offset32 _PollRoutine@8
mov | ebx, offset32 _CfgRoutine
mov | ecx, offset32 _HWCapsRoutine@8
mov | edx, offset32 _JoyIdRoutine@8
VxDcall | VJOYD_Register_Device_Driver

In addition to registering, a minidriver can do any other initialization at this time. The joystick minidriver model does not require any specific actions in response to SYS_DYNAMIC_DEVICE_EXIT, though it may still be used by the VxD for final internal cleaning up.


Polling Callback

int stdcall PollRoutine( int type, LPJOYOEMPOLLDATA pojd );

The polling routine is called either in direct response to an application calling joyGetPos or joyGetPosEx, or when Windows 95 periodically calls joyGetPos for an application that has called joySetCapture. It is only when a minidriver is first called on its poll callback that it can be certain that an application requires data from it. All the other callbacks are called for all devices that are currently in the list of 16 available joysticks, whether or not any application has requested data.

The possible return values are JOY_OEMPOLLRC_YOUPOLL, JOY_OEMPOLLRC_FAIL, and JOY_OEMPOLLRC_OK. With the exception of a button-only poll, the return value is interpreted into either JOYERR_NOERROR or JOYERR_UNPLUGGED before being returned to an application. A button poll is always assumed to succeed.

JOY_OEMPOLLRC_FAIL is returned if the device being polled is not responding, or if VJoyD has requested a poll that the minidriver cannot process. In the former case, care should be taken not to fail a device unless it really has failed, because the application is likely to stop everything and request that the user check the connections to the device. A call to joySetCapture, for example, fails if the first poll fails. Minor device failures should not cause a failure to be reported until user intervention is required or an unrecoverable device error is detected. For instance, a device that communicates using a packet-based protocol should attempt a retry before failing the poll if one packet is not valid. Of course, it is important to recognize genuine device failure and return an error eventually, otherwise an application cannot determine that user intervention is required at all. If old or fake data is returned while error recovery is performed, the meaning of data returned, the number of polls allowed, or the time allowed from the initial error should be restricted so the driver does not delay for an inordinate amount of time. When a minidriver is requested to perform a poll on a device that it does not control, or to perform a poll type or sub-type that it cannot service, a failure is always the correct response.

JOY_OEMPOLLRC_YOUPOLL can be used if the standard analog poll will yield the correct results.

JOY_OEMPOLLRC_OK should be returned in the normal case when the JOYINFOEX structure has been filled with the requested data.

Care must be taken if the first poll is used to perform initialization on the device. Applications can do an initial poll to check for the availability of the device by checking the return code. They can then make subsequent polls with no error checking. This is essentially what joySetCapture does. Ideally, all initialization and the first poll should be performed. For those cases in which the time required to set up the device lasts up to a second, it is normally sufficient to verify that the device is present and working and to return inert data for the first poll.

The API and system drivers perform validation on the request made by the application and copy the required data into the application structure upon completion. The minidriver should not replicate this functionality. However, nothing prevents one process from polling a device while another is still in the middle of a poll. The consequences of this unlikely event are usually no worse than two axes being reported from different samples. If necessary, a minidriver can perform its own process synchronization.

Return values depend upon the "type" parameter and what the device supports. The buttons and button number should always be returned. Since there is no way to specify to the minidriver that a POV poll is required, this value should also be returned if any axes are requested, setting POV_UNDEFINED if the device does not support one. For a single axis poll, the value is returned in the dwX member of the JOYPOLLDATA structure (the VJPOLLDATA structure in DirectX 5.0 and later). If multiple axes are requested and the number of axes requested is odd, the do_other member of the JOYOEMPOLLDATA structure specifies whether the last axis is returned in place or for the following axis. In a three-axis poll, for example, the member specifies whether the axes returned are X, Y, Z or X, Y, R.

The following is a list of other possible return values, broken down by type (filling in extra data does no harm, but note that all polls of an odd number of axes must decode the do_other member to decide what is returned):

  • JOY_OEMPOLL_GETBUTTONS: Nothing extra.
  • JOY_OEMPOLL_POLL1: The axis specified in the do_other member is returned in the dwX member.
  • JOY_OEMPOLL_POLL2: The X and Y axes are returned in the dwX and dwY members.
  • JOY_OEMPOLL_POLL3: The X and Y axes are returned in the dwX and dwY members.

    If the do_other member is nonzero, the R axis is returned in the dwR member. Otherwise, the Z axis is returned in the dwZ member.

  • JOY_OEMPOLL_POLL4: The X, Y, Z and R axes are returned in the dwX, dwY, dwZ, and dwR members.
  • JOY_OEMPOLL_POLL5: The X, Y, Z and R axes are returned in the dwX, dwY, dwZ, and dwR members.

    If the do_other member is nonzero, the V axis is returned in the dwR member. Otherwise, the U axis is returned in the dwZ member.

  • JOY_OEMPOLL_POLL6: The X, Y, Z, R, U and V axes are returned in the dwX, dwY, dwZ, dwR, dwU, and dwV members.

DirectX 3.0 added the nonpoll type of JOY_OEMPASSDRIVERDATA, in which case the do_other member contains a DWORD passed from an application. This DWORD can be used for any minidriver-defined function, but is intended in particular to enable custom setup applications that have fully identified the minidriver to send device-specific commands and configuration information.

A minidriver should return JOY_OEMPOLLRC_FAIL for all types it does not support.

Although the axis data is returned in doublewords, the range of axis values should be restricted to approximately 10-bit values if the standard joystick control panel configuration is used as the sole configuration mechanism. Because the user cannot easily see what is happening, this helps to avoid confusion. To aid compatibility with existing applications, the axes returned by a minidriver should be the same as those returned by an analog joystick (where applicable). For example, X would be a left-to-right movement minimized at the left, and so on.

When a POV hat is activated, the direction should be represented as the angle, in degrees, multiplied by 100, with 0 being forward, 9000 right, 18000 backwards, and 27000 left.

Because the poll routine call is the only positive indication that the device is still in use, minidrivers that use shared resources such as communications ports should keep track of the last time they were used. If usage time becomes significant , the minidrivers should stop sampling the device and free the resources in case the user has finished using the device and is now trying to use the resource for another purpose. This is particularly important if communications errors are occurring, because this could be an indication that the device has been unplugged.


Configuration Manager Callback

CONFIGRET CM_HANDLER CfgRoutine( CONFIGFUNC cfFuncName,
    SUBCONFIGFUNC scfSubFuncName, DEVNODE dnToDevNode,
    ULONG dwRefData, ULONG ulFlags );

General information on interfacing to the configuration manager is documented in the Plug and Play Environment section of the Windows 95 DDK.

Because minidrivers are passed the configuration manager callback only if they are loaded when VJoyD receives the callback, a significant problem exists with current implementations of this callback. VJoyD receives callbacks for those device nodes with which it is associated when the device nodes are enumerated during system boot, when the configuration manager sends a message during normal run time for a special event like device reconfiguration, and when the system is closing down. Therefore, only the devices that were selected on the previous boot are loaded in time to receive these messages. This limits the potential number of things that remain to be done when this callback is invoked because a user can boot the system, configure a joystick, play games, deconfigure the joystick, and shut down without this callback ever being called.

For devices that do not need any hardware resources, this is not an issue. Devices that use such resources have several options: they can work only when configured at boot time, they can dynamically allocate the resources from the configuration manager, or they can find out their allocations by searching the registry for their own device node and then that to request the information.

Given the preceding information, driver initialization is best done either when the driver is first loaded and the SYS_DYNAMIC_DEVICE_INIT message is received, or on the first time through the polling routine. Similarly, resources should be freed when a SYS_DYNAMIC_DEVICE_EXIT message is received.

Another issue is that all configuration manager callbacks for currently serviced joystick devices are sent to all loaded minidrivers. This is not bad, however, as the dnToDevNode parameter can be used to look up the device identifier, and this can be checked against the devices this driver can handle.


Hardware Capabilities Callback

int __stdcall HWCapsRoutine( int joyid, LPJOYOEMHWCAPS pjhwc );

HWCapsRoutine is called whenever the hardware capabilities of the device are requested. In particular, VJoyD calls HWCapsRoutine before returning from VJOYD_Register_Device_Driver, so it is important that any initialization upon which this call relies is complete before the device is registered. These values are usually constants. For a device that has four buttons and three axes, of which the third may return either a throttle or a rudder value, the following would be appropriate:

pjhwc->dwMaxButtons = 4;    /* This should always be the number of buttons */
pjhwc->dwMaxAxes = 4;       /* The largest axis number which may be requested */
pjhwc->dwNumAxes = 3;       /* The number of axes the device has */


Joystick Identification Callback

int __stdcall JoyIdRoutine( int joyid, BOOL used );

VJoyD calls JoyIDRoutine in response to a user configuring or deconfiguring a joystick as one of the 16 joysticks. If the minidriver can support the ID requested in joyid, JoyIdRoutine returns a nonzero value. If the minidriver cannot support the ID, the routine returns zero.

Whenever any change is made and joyConfigChanged is called to update the driver, VJoyD cycles through all 16 devices, starting with JOYSTICKID1 It resets them all to unused and then loops through them again, setting all those that are needed to used. During control panel type operations, this can entail a large number of calls, which makes using this callback for initialization problematic, at best. This is particularly true if the call is made before the system boot is complete, when other services are not available.

Minidrivers that service callbacks for more than one device should attempt to keep joystick identifiers tied to a single physical device, where possible, to avoid user confusion. This can be done relatively easily during a single session, but is probably not necessary over reboots.


The DirectX 5.0 Interface

The DirectX 5.0 interface cannot be recognized by any previous version of VJoyD, so it is imperative that a minidriver check the version of VJoyD before attempting to register. VJoyD does not support the standard version message, so this must be done manually by getting the device descriptor block (DDB) for VJoyD, then checking the version marked in the DDB. See the sample driver for an example of how this can be done. Notice that the version marked in the DDB is not the same as the version marked in the version resource.

The process by which a minidriver registers its callbacks was extended significantly in DirectX 5.0.

Minidrivers can be loaded either by VJoyD, as before, or by an external owner (such as the HID stack). When VJoyD loads a device, it still requires the minidriver to register itself using the VJoyD VJOYD_Register_Device_Driver service. However, the minidriver may now receive three system control messages which should prompt it to register. The first is the SYS_DYNAMIC_DEVICE_INIT message, which is received if the VxD was not loaded before VJoyD loaded it. This is the same mechanism as the original interface used for registration. Because it is a fresh load of the VxD, any INIT sections it has defined are available. On receipt of this message, the VxD performs any internal initialization and then registers with VJoyD. If a minidriver has already been loaded (for instance if an application has loaded it to use a private IOCTL interface), it will not receive this message again when VJoyD loads it. In these circumstances under Windows 98, the SYS_DYNAMIC_DEVICE_REINIT message is issued and a minidriver should respond by registering with VJoyD. Since this is not a fresh load of the VxD, the INIT sections are no longer available. For minidrivers not running under Windows 98, VJoyD will take the lack of response to the loading of a minidriver to mean that the VxD has already been loaded. VJoyD will issue the directed system control message BEGIN_RESERVED_PRIVATE_SYSTEM_CONTROL, to which the minidriver should respond by registering.

In addition to the load-time registration, VJoyD now accepts new types of registration when a driver detects a change in state of a device it is driving. Besides the callbacks, the DirectX 5.0 interface allows various control parameters and device descriptions to be set on registration. This includes the full description of the device (complete with the calibration information),which can be changed to fit whatever device has been detected.

The joystick minidriver callbacks for the DirectX 5.0 interface fall into five categories: control callbacks, a polling callback, and force feedback callbacks. To accommodate these changes, the VJoyD VJOYD_Register_Device_Driver service was overloaded so that EAX holds 0xFFFFFFFF to signal that the new registration is in use, and ECX holds a pointer to a structure holding the parameters. The values of EBX and EDX are undefined and it may be assumed that EBX will return from the call uncorrupted.

The following example shows a joystick minidriver registration sequence:

mov | eax, 0ffffffffh
mov | ecx, offset32 RegData
VxDcall | VJOYD_Register_Device_Driver

The VJREGDRVINFO structure is passed to the new registration.

The dwFunction member of the VJREGDRVINFO structure must be VJRT_LOADED; all other values are reserved. VJRT_LOADED is used in the new interface in the same way that the registration was used in the original interface, that is, to pass the driver's callbacks to VJoyD in response to the minidriver being loaded.

The control callbacks and the poll callback are merged into a single table because all drivers must supply the control callbacks and very few devices are output only (and therefore do not need a poll callback). These callbacks are registered using the VJPOLLREG structure.

The lpCfg member of the VJPOLLREG structure points to a standard configuration manager callback, exactly like the CfgRoutine in the original interface. The big difference is that VJoyD will call the configuration manager callback as appropriate. VJoyD links drivers to the device nodes for which they were installed and calls this callback to inform the driver of configuration manager activity. Whereas the previous interface called all loaded drivers for each configuration manager callback, the DirectX 5.0 and later interface only calls the one driver it has linked to the device node which has changed. Also, because configuration manager activity may happen while the driver is not loaded, VJoyD implements a primitive caching system so that if a device node has been started, the driver will be informed of this device node when it is loaded. Because drivers are always called for their resource allocations, they should not check default ports hoping to find the resources they need. Unfortunately, drivers that had to find some way to work with the previous interface still work in the old way. This means that while VJoyD only allocates a set of resources to a single driver, any old drivers that are loaded can still use ports that have not been allocated to them. When resources have been allocated, the driver should perform any handshaking required with the device to determine the device state.

The Initialize callback (pointed to by the fpInitialize member of the VJPOLLREG structure) replaces the JoyId callback in the previous interface. The main difference is that VJoyD passes back to the driver any device instance identification that the device passed to VJoyD during registration so the instances can be distinguished if the driver supports more than one device.

Note If you need to open registry keys, you should use the VJOYD_OpenConfigKey_Service and VJOYD_OpenTypeKey_Service macros instead of opening the registry keys directly. Using these service macros ensures that the correct registry branch will be opened. In addition, the service macros will be supported in future versions of DirectInput® when the underlying registry data may be structured differently.


Creating an INF File

All minidrivers and OEM-defined joysticks should be installed using an INF file to provide all the necessary information to the system. An INF file describes a device installation in terms of the class of the device, the files that need to be copied, any compatible devices, any system resources the device requires, and changes to the registry. INF files for customizing the standard analog driver do not need to copy any files, state compatible devices, or specify system resources. The INF file can specify other actions, such as modifying the Autoexec.bat file, but this is not usually necessary for a joystick minidriver. For a more general description of what can be done from an INF file and the details of the standard section contents, please refer to the Windows 95 DDK.

The INF file contains the elements described in the following topics:

Device Class

Source Files

Manufacturer-Specific Data

LogConfig Entries

AddReg Entries


Setting the Device Class

Joysticks fall under the MEDIA class, the one titled "Sound, video and game controllers" under the Add New Hardware control panel. The class-related sections should be copied from either the examples or the Joystick.inf file.


Selecting Source Files

The "SourceDisksFiles" section of the INF file specifies which files to copy. This includes all necessary drivers, as well as any other files, such as documentation and setup applications. As this may be the first joystick driver to be installed on a user's system, the system joystick drivers Vjoyd.vxd and Msjstrick.drv should be copied, in addition to the specific drivers for this device. The source of these two drivers should be established by reference to Layout.inf (causing the user to be prompted for the Windows 95 installation disc) and not distributed on the OEM disc. The drivers should be copied to the user's system directory, which is destination code 11.


Setting the Manufacturer-Specific Data

Normally, the INF file for a joystick minidriver has only one entry under the "Manufacturer" section. The manufacturer-specific section to which this points contains one line for each device that can be installed; again often there is only one. Each entry contains the name of the device followed by the name of the install section, the device ID, and any compatible devices. If the device has been registered as Plug and Play compatible, then the Plug and Play ID (starting with an asterisk) should be used for the device ID. If the device has not been registered, then a device ID that is not Plug and Play compatible (that is, one not starting with an asterisk) should be used. When registering this type of device, care should be taken to avoid choosing an ID that will conflict with other device IDs ("Joystick" would not be a good ID).


Setting Up LogConfig Entries

Devices requiring system resources such as input/output (I/O) ports use a LogConfig entry in the install section to specify which configurations they can use. See the Windows 95 DDK for more details. Some devices do not use resources of their own. Instead, they use another driver, such as the serial port driver, to communicate with the device. The DirectX 3.0 VJoyD differs from previous versions in its handling of analog game port I/O port requirements. Older versions worked only if at least one device had been configured with either one or two I/O port allocations with ports in the standard game port range 0x200 to 0x20f. (In addition, the second I/O range had to be a single port.) The newer VJoyD works if no game ports are configured to allow systems that have no game ports to use devices operated through minidrivers. (The second I/O range can now be more than one port.)

Devices using ports in the range 0x200 to 0x20f have particular problems, as they are interpreted to be analog game ports by VJoyD, and may therefore be considered conflicting devices by the configuration manager. VJoyD uses the last set of valid looking resources passed to it, so if these are not game ports, the device had better not mind getting treated like a game port. Any other sets of game port I/O ports are ignored; if a machine has game ports on two cards, only the ports on one card are polled. If the device needs to use a standard game port in a nonstandard way, things get even more interesting. Requesting the standard ports in LogConfig entries of the installation section for the device can work, but it usually results in a lot of reconfiguring and rebooting to swap joysticks. An alternative is to share the resources with VJoyD by using any set of I/O ranges passed through the configuration manager callback that fit the game port criteria. As long as the user does not configure joysticks to both the standard analog driver and the OEM driver, then run an application that tries to poll them both, this works well enough. In DirectX 3.0, changes were implemented to allow an OEM VxD to be called in place of the standard analog polling by setting the JOY_HWS_ISGAMEPORTDRIVER flag. The control panel allows such a device to be set up as a global driver, meaning that it, rather than the internal analog polling, gets called for any joysticks that have no minidriver associated with them. This ensures that VJoyD does not interfere with the polling of the OEM device.

If the first four devices during boot are all handled by minidrivers (which may be an OEM global driver), VJoyD does not check for — and is not able to use — any game ports, even if these devices are no longer handled by minidrivers. If VJoyD cannot use its ports (or if no game ports exist), returning JOY_OEMPOLLRC_YOUPOLL to a poll request does not cause the standard polling to be used. Reconfiguring back to devices using this polling takes effect only after the game port resources have been reallocated (probably not until a reboot).


Setting Up AddReg Entries

The INF file also needs to set up registry entries in the section selected by the AddReg entry of the install section. For devices requiring a minidriver, the following need to be set up to make sure that the driver is properly associated with the multimedia system drivers:

HKR,,DevLoader,,mmdevldr.vxd
HKR,Drivers,,,
HKR,Drivers,MIGRATED,,0
HKR,Drivers\joystick,,,
HKR,,Driver,,vjoyd.vxd
HKR,Drivers\joystick\msjstick.drv,,,
HKR,Drivers\joystick\msjstick.drv,Description,,%OEMJoy.DeviceDesc%
HKR,Drivers\joystick\msjstick.drv,Driver,,msjstick.drv

The %OEMJoy.DeviceDesc% string is replaced by whatever the device name string has been called.

Values that describe this joystick are put into the registry under an OEM-defined key, starting with the path REGSTR_PATH_JOYOEM (found under HKEY_LOCAL_MACHINE). Under this key, an OEM can place a number of static values that customize the way an OEM joystick appears in the joystick calibration program and to applications for Windows 95. The names of the values are defined in Regstr.h, so it is the names of these constants that are discussed below, rather than the names that appear in the registry. Every OEM-defined device must at least have its basic properties defined and a name that the user can see in the joystick selection box under the control panel. For a minidriver to be loaded, the value must contain the name of the minidriver VxD (including the .vxd extension). The OEM name value (REGSTR_VAL_JOYOEMNAME), and the minidriver file name(REGSTR_VAL_JOYOEMCALLOUT) values are simple strings. The basic properties REGSTR_VAL_JOYOEMDATA value is binary data, whose meaning is detailed in the following passages.

There are two doublewords; the first contains a set of flags, the second is the number of buttons the device has.

The flags specify what kind of device it is, which axes are present, and how they should be interpreted.

Most of the flags are defined in Mmddk.h (found in the Windows 95 DDK). The two new flags added in DirectX 3.0 are defined in Dinput.h. The following flags are used only to remap the axes of an OEM-defined analog joystick that is polled directly by VJoyD. They change the default behavior of VJoyD when doing analog polling, but have no effect on the data returned by minidrivers.

JOY_HWS_XISJ1Y | X is on the J1 Y axis.
JOY_HWS_XISJ2X | X is on the J2 X axis.
JOY_HWS_XISJ2Y | X is on the J2 Y axis.
JOY_HWS_YISJ1X | Y is on the J1 X axis.
JOY_HWS_YISJ2X | Y is on the J2 X axis.
JOY_HWS_YISJ2Y | Y is on the J2 Y axis.
JOY_HWS_RISJ1X | R is on the J1 X axis.
JOY_HWS_RISJ1Y | R is on the J1 Y axis.
JOY_HWS_RISJ2Y | R is on the J2 Y axis.
JOY_HWS_ZISJ1X | Z is on the J1 X axis.
JOY_HWS_ZISJ1Y | Z is on the J1 Y axis.
JOY_HWS_ZISJ2X | Z is on the J2 X axis.
JOY_HWS_POVISJ1X | Polled POV is on the J1 X axis.
JOY_HWS_POVISJ1Y | Polled POV is on the J1 Y axis.
JOY_HWS_POVISJ2X | Polled POV is on the J2 X axis.

The default behavior is:

  • X defaults to the J1 X axis.
  • Y defaults to the J1 Y axis.
  • R (rudder) defaults to the J2 X axis.
  • Z defaults to the J2 Y axis.
  • POV hat (if implemented as polling) defaults to the J2 Y axis.

Flags are also defined to determine whether POV data comes from an axis or from a button combination. If the described device is being polled by VJoyD, JOY_HWS_POVISBUTTONCOMBOS causes VJoyD to interpret button combinations to produce the POV, otherwise an axis is used to find it. If the described device is polled through a minidriver, then a value in dwPOV other than POV_UNDEFINED causes an override of any other POV calculation. However, if JOY_HWS_POVISBUTTONCOMBOS is set, VJoyD interprets the buttons as it would for an analog joystick. Otherwise the POV is taken from the Z axis value if JOY_HWS_HASZ is not set, from R otherwise. When possible, minidrivers should avoid having the generic VJoyD interpret POV information, as a minidriver usually has more information about the hardware implementation.

The following flags are used to describe which features the device has:

JOY_HWS_HASZ | Joystick has Z (3rd axis) information.
JOY_HWS_HASR | Joystick has R (4th axis) information.
JOY_HWS_HASU | Joystick has R (4th axis) information.
JOY_HWS_HASV | Joystick has R (4th axis) information.
JOY_HWS_HASPOV | Joystick has a POV hat.

The following flags are used to describe the device type:

JOY_HWS_ISYOKE | Device is a flight yoke.
JOY_HWS_ISGAMEPAD | Device is a game pad.
JOY_HWS_ISCARCTRL | Device is a race car controller.
JOY_HWS_ISHEADTRACKER | Device is a head tracker (defined in DirectX 3.0).

Finally, the JOY_HWS_ISGAMEPORTDRIVER flag that was added in DirectX 3.0 indicates that this minidriver replaces the standard polling of a game port.

For example, if you have a digital joystick that has eight buttons and returns values for X, Y, Z, R, and POV, then you need to set the bits JOY_HWS_HASZ, JOY_HWS_HASPOV, and JOY_HWS_HASR. This gives you the following:

 | 0x00000001 | JOY_HWS_HASZ | 01,00,00,00
| | 0x00000002 | JOY_HWS_HASPOV | 02,00,00,00
| | 0x00080000 | JOY_HWS_HASR | 00,00,08,00
= | 0x00080003 | combination | 03,00,08,00

Putting this DWORD in little-endian format, followed by a DWORD for the number of buttons, gives you 03,00,08,00,08,00,00,00, which is the series of bytes required in your INF file.

All of the remaining registry settings supplied in the INF file customize the instructions for calibration given by the standard control panel, and are as follows:

REGSTR_VAL_JOYOEMXYLABEL
This string is displayed below the XY position control found in the test and calibrate dialogs of the joystick CPL.
REGSTR_VAL_JOYOEMZLABEL
This string is displayed below the Z position control found in the test and calibrate dialogs of the joystick CPL.
REGSTR_VAL_JOYOEMRLABEL
This string is displayed below the R position control found in the test and calibrate dialogs of the joystick CPL.
REGSTR_VAL_JOYOEMPOVLABEL
This string is displayed below the POV hat control found in the test and calibrate dialogs of the joystick CPL.
REGSTR_VAL_JOYOEMULABEL
This string is displayed below the U position control found in the test and calibrate dialogs of the joystick CPL.
REGSTR_VAL_JOYOEMVLABEL
This string is displayed below the V position control found in the test and calibrate dialogs of the joystick CPL.
REGSTR_VAL_JOYOEMTESTMOVEDESC
This string is displayed in the movement section of the test dialog. It describes to the user how to test the joystick.
REGSTR_VAL_JOYOEMTESTBUTTONDESC
This string is displayed in the button section of the test dialog. It describes to the user how to test the buttons.
REGSTR_VAL_JOYOEMTESTMOVECAP
This string is displayed as the caption of the group box surrounding the movement section of the test dialog.
REGSTR_VAL_JOYOEMTESTBUTTONCAP
This string is displayed as the caption of the group box surrounding the button section of the test dialog.
REGSTR_VAL_JOYOEMTESTWINCAP
This string is displayed as the caption of the test dialog.
REGSTR_VAL_JOYOEMCALCAP
This string will be displayed as the caption of the calibration dialog.
REGSTR_VAL_JOYOEMCALWINCAP
This string is displayed as the caption of the calibration dialog.
REGSTR_VAL_JOYOEMCAL1
This string instructs the user how to center the XY portion of the joystick for calibration.
REGSTR_VAL_JOYOEMCAL2
This string instructs the user how to move the XY portion of the joystick for calibration.
REGSTR_VAL_JOYOEMCAL3
This string instructs the user how to re-center the XY portion of the joystick for calibration.
REGSTR_VAL_JOYOEMCAL4
This string instructs the user how to move the Z portion of the joystick for calibration.
REGSTR_VAL_JOYOEMCAL5
This string instructs the user how to move the R portion of the joystick for calibration.
REGSTR_VAL_JOYOEMCAL6
This string instructs the user how to move the U portion of the joystick for calibration.
REGSTR_VAL_JOYOEMCAL7
This string instructs the user how to move the V portion of the joystick for calibration.
REGSTR_VAL_JOYOEMCAL8
This string instructs the user how to move the POV hat up for calibration.
REGSTR_VAL_JOYOEMCAL9
This string instructs the user how to to move the POV hat right for calibration.
REGSTR_VAL_JOYOEMCAL10
This string instructs the user how to move the POV hat down for calibration.
REGSTR_VAL_JOYOEMCAL11
This string instructs the user how to move the POV hat left for calibration.
REGSTR_VAL_JOYOEMCAL12
This string consists of a message that informs the user that the calibration process is finished.


Registry Settings

The registry is used by the joystick interface to store configuration, calibration, and user preference information. It is also used to store customized text for the calibration program. The Windows 95 joystick calibration program can be customized through the registry to provide instructions to the user during calibration that are specific to the joystick.

The values fall into five groups:

Original data supplied by the OEM and installed from an INF file (described above).

User Values that specify how data is interpreted.

Current Settings reflecting which devices are currently configured.

Saved Settings that allow different configurations to be recalled.

Driver Settings that are set up by the configuration manager as a device is set up.

The user values, current settings, and saved settings are all stored in the registry under the path belonging to the "current" joystick driver. Each of the joystick devices for which a driver is installed has a key under the path REGSTR_PATH_JOYCONFIG that has the form Msjstick.drv<xxxx>, where the xxxx will be a four-digit number used to keep the key name unique. The number relates to the number of multimedia (sound, video and game controller) drivers that have been installed. At boot time, Msjstick.drv is initialized to the configuration for each of the game controller drivers. Since it can only deal with one configuration at a time, each one replaces the last and the "current" driver is the last one to be initialized. This means that the user is likely to lose all the current settings when a new driver is installed, and a minidriver cannot be structured on the assumption that the path to these registry values will always be the same.


User Values

A single value named REGSTR_VAL_JOYUSERVALUES stores the structure described following. This structure specifies how data should be manipulated by VJoyD when an application requests that data be scaled, centered, or have a dead zone defined. The minidriver writer does not have handle this data manipulation, as it is done by VJoyD.

struct {
    /* value at which to timeout internal joystick polling */
    DWORD   dwTimeOut;

    /* range of values app wants returned for axes */
    struct {
        /* minimums for each axis */
        struct {
            DWORD    dwX;
            DWORD    dwY;
            DWORD    dwZ;
            DWORD    dwR;
            DWORD    dwU;
            DWORD    dwV;
        } jpMin;
        /* maximums for each axis */
        struct {
            DWORD    dwX;
            DWORD    dwY;
            DWORD    dwZ;
            DWORD    dwR;
            DWORD    dwU;
            DWORD    dwV;
        } jpMax;
        /* center positions for each axis */
        struct {
            DWORD    dwX;
            DWORD    dwY;
            DWORD    dwZ;
            DWORD    dwR;
            DWORD    dwU;
            DWORD    dwV;
        } jpCenter;
    } jrvRanges;

    /* area around center to be considered as "dead". specified as */
    /* a percentage (0-100). Only X & Y handled by system driver */
    struct {
        DWORD    dwX;
        DWORD    dwY;
        DWORD    dwZ;
        DWORD    dwR;
        DWORD    dwU;
        DWORD    dwV;
    } jpDeadZone;
}


Current Settings

There are two parts to the current registry settings: a value to store, which is a replacement for the standard polling and a key under which the capabilities, calibrated values, and minidriver data are stored.

A minidriver that is used to poll devices that do not have an associatedminidriver to replace the standard polling can be defined in the key named REGSTR_VAL_JOYCALLOUT. This feature was new for DirectX 3.0. The values are set by the control panel from the advanced settings page when the user selects a new global driver from the list that contains all minidrivers that have the JOY_HWS_ISGAMEPORTDRIVER flag set.

The remaining settings are stored under the REGSTR_KEY_JOYCURR key. When a device is first configured to a particular joystick ID, the control panel copies values from the relevant OEM key under REGSTR_PATH_JOYOEM to the REGSTR_KEY_JOYCURR key. Each of the key value names under this key contains the joystick ID as a part of the name so each joystick has its own settings. The REGSTR_VAL_JOYOEMNAME value is copied to the relevant REGSTR_VAL_JOYNOEMNAME and, if present, the REGSTR_VAL_JOYOEMCALLOUT value is copied to REGSTR_VAL_JOYNOEMCALLOUT. The REGSTR_VAL_JOYOEMDATA value is used as the first two doublewords of the REGSTR_VAL_JOYNCONFIG value, with the whole of that value defined (when expanded) as follows:

struct {
    /* usage settings, copied from REGSTR_VAL_JOYOEMNAME */
    struct {
        DWORD   dwFlags;
        DWORD   dwNumButtons;
    } hws;

    /* usage flags, described below */
    DWORD    dwUsageSettings;

    struct {
        /* values returned by hardware during calibration */
        struct {
            /* minimums for each axis */
            struct {
                DWORD    dwX;
                DWORD    dwY;
                DWORD    dwZ;
                DWORD    dwR;
                DWORD    dwU;
                DWORD    dwV;
            } jpMin;
            /* maximums for each axis */
            struct {
                DWORD    dwX;
                DWORD    dwY;
                DWORD    dwZ;
                DWORD    dwR;
                DWORD    dwU;
                DWORD    dwV;
            } jpMax;
            /* center positions for each axis */
            struct
            {
                DWORD    dwX;
                DWORD    dwY;
                DWORD    dwZ;
                DWORD    dwR;
                DWORD    dwU;
                DWORD    dwV;
            } jpCenter;
        } jrvHardware;

        /* POV values returned by hardware during calibration */
        DWORD   dwPOVValues[JOY_POV_NUMDIRS];

        /* calibration flags, described below */
        DWORD   dwCalFlags;
    } hwv;

    /* type of joystick, described below */
    DWORD   dwType;

    /* reserved for OEM drivers */
    DWORD   dwReserved;
};

The usage settings are a combination of the following values:

JOY_US_HASRUDDER | 0x00000001l | /* joystick configured with rudder */
JOY_US_PRESENT | 0x00000002l | /* is joystick actually present? */
JOY_US_ISOEM | 0x00000004l | /* joystick is an OEM-defined type */
JOY_US_RESERVED | 0x80000000l | /* reserved */

The calibration flags are a combination of the following values:

JOY_ISCAL_XY | 0x00000001l | /* XY are calibrated */
JOY_ISCAL_Z | 0x00000002l | /* Z is calibrated */
JOY_ISCAL_R | 0x00000004l | /* R is calibrated */
JOY_ISCAL_U | 0x00000008l | /* U is calibrated */
JOY_ISCAL_V | 0x00000010l | /* V is calibrated */
JOY_ISCAL_POV | 0x00000020l | /* POV is calibrated */

The dwType member holds a number representing the type of a predefined joystick. If an OEM calibration utility sets up this value, it should set a value outside the range of values defined in Mmddk.h (found in the Windows 95 DDK). The exact value is unimportant as it is reset by the standard control panel.


Saved Settings

When the current joystick settings are saved, the REGSTR_VAL_JOYNCONFIG saved under the REGSTR_KEY_JOYCURR key is also written under the REGSTR_KEY_JOYSETTINGS key in a subkey with the same name as that from which the OEM-defined settings are taken (non-OEM settings are saved in a subkey "predef" plus the type number). When a joystick is replaced, the saved settings remain so that if the joystick is restored, the saved settings are put back into the current settings. These registry values are used only by the control panel.


Driver Settings

These registry settings are set up during installation from the INF file, as described above, and during the device enumeration at boot time.


VJoyD Minidriver Override

USB/HID devices that do not load the JoyHID.VxD device driver can sometimes display duplicate device entries present in the Gaming Options control panel when used with other USB/HID devices. This occurs when a JoyHID-compliant device is attached to the system at the same time as a non-JoyHID device.

If your device uses a VJoyD minidriver other than JoyHID—presumably developed by the device manufacturer or an affiliate—you can prevent these issues by properly setting up your device type key and related named values in the registry. The features described in this topic are available only to devices with type keys in the form "VID_vvvv&PID_pppp", where the letters v and p are zero-padded vendor and product ID values for the product.

Given a properly formatted type key, the following steps will prevent JoyHID from attempting to retrieve data from the device or displaying unnecessary device entries in the control panel/add list.
  • Set OEMData to JOY_HWS_AUTOLOAD. This prevents the device name from being displayed in the add list for devices.
  • Set OEMCallout to the driver which should be loaded for the device. This prevents JoyHID.VxD from being loaded for the device.
  • Set OEMName to the name appropriate for the device.
If needed, you can set registry values to arbitrary (but reasonable) values solely for the purpose of preventing JoyHID from reading data from the device. For example, you might employ the following values:
Name | Value
OEMName | "Unused entry for IHV device X, do not remove"
OEMData | OEMData is a binary registry field containing two DWORDs. The first is a set of JOY_HWS_* flags, the second is the number of buttons on the device. The value of the flag JOY_HWS_AUTOLOAD is defined in dinput.h to be 0x10000000. Since the number of buttons in this case is irrelevant, the eight bytes (in hex) should be 00,00,00,10,00,00,00,00.
OEMCallout | "unused"

Note that values like these merely prevent JoyHID from attempting to read data from the device. If your device uses a VJoyD minidriver, you should set the preceding values to properly reflect the device name and driver to be loaded.


Axis Selection

This section contains information about how DirectInput maps axes for use by DirectInput and Windows multimedia applications.

Windows 2000, Legacy Interfaces

When using the DirectX 7.0 API on Windows 2000, axis assignments are made in the order in which the axes are exposed by the device driver, shown in the following table:

Usage Page | Usage | DirectInput Axis
HID_USAGE_PAGE_GENERIC | HID_USAGE_GENERIC_X | GUID_XAxis
HID_USAGE_PAGE_GENERIC | HID_USAGE_GENERIC_Y | GUID_YAxis
HID_USAGE_PAGE_GENERIC | HID_USAGE_GENERIC_Z | GUID_ZAxis
HID_USAGE_PAGE_GENERIC | HID_USAGE_GENERIC_WHEEL | GUID_ZAxis
HID_USAGE_PAGE_GENERIC | HID_USAGE_GENERIC_RX | GUID_RxAxis
HID_USAGE_PAGE_GENERIC | HID_USAGE_GENERIC_RY | GUID_RyAxis
HID_USAGE_PAGE_GENERIC | HID_USAGE_GENERIC_RZ | GUID_RzAxis
HID_USAGE_PAGE_GENERIC | HID_USAGE_GENERIC_HATSWITCH | GUID_POV
HID_USAGE_PAGE_GENERIC | HID_USAGE_GENERIC_SLIDER | GUID_Slider
HID_USAGE_PAGE_GENERIC | HID_USAGE_GENERIC_DIAL | GUID_Slider
HID_USAGE_PAGE_SIMULATION | HID_USAGE_SIMULATION_STEERING | GUID_XAxis
HID_USAGE_PAGE_SIMULATION | HID_USAGE_SIMULATION_ACCELERATOR | GUID_YAxis
HID_USAGE_PAGE_SIMULATION | HID_USAGE_SIMULATION_BRAKE | GUID_RzAxis
HID_USAGE_PAGE_SIMULATION | HID_USAGE_SIMULATION_RUDDER | GUID_RzAxis
HID_USAGE_PAGE_SIMULATION | HID_USAGE_SIMULATION_THROTTLE | GUID_Slider
HID_USAGE_PAGE_GAME | HID_USAGE_ SIMULATION_POV | GUID_POV

These GUIDs are used by SetDataFormat to match the requested data format to the device objects. For applications that are compiled with DIRECTINPUT_VERSION < 0x0600, if the data format specifies a GUID_ZAxis before a GUID_Slider (as the default joystick data format does) and a Slider is found on the device before a Z-axis, then the Slider will be matched as a Z-axis. This is intended to give better compatibility with HID.

Windows 9x Platforms

Through the DirectX 7.0 interfaces on Windows 95/98/Me, the mapping of a WinMM axis to a DirectInput axis is one-dimensional:

WinMM Axis | DirectInput Assignment
X | GUID_XAxis
Y | GUID_YAxis
Z | GUID_ZAxis
R | GUID_RzAxis
U | GUID_Slider
V | GUID_Slider

WinMM axes are mapped differently through DirectX 8.0 interfaces, as described in Mappings for DirectX 8.0 Interfaces, as described below.

Note Although JoyHID.VxD does not yet map the vehicle control usages for steering, accelerate and brake, it does check for a steering usage and if one is found it will treat the device as a WinMM car controller. Also, the DirectX 8.0 version of JoyHID.VxD copies any IHV supplied WinMM controller type flags (JOY_HWS_ISYOKE, JOY_HWS_ISGAMEPAD, JOY_HWS_ISCARCTRL or JOY_HWS_ISHEADTRACKER) and button counts, so these types can be set by the IHV in the OEMData registry value.

The mappings made by the DirectX 8.0 interfaces, although similar, are not mapped in exactly the same manner as the legacy interfaces. The following tables describe mappings in the DirectX 8.0 interfaces.

For data retrieved through WinMM, the default mapping is:

WinMM Axis | DirectInput Assignment
X | GUID_XAxis
Y | GUID_YAxis
Z | GUID_Slider
R | GUID_RzAxis
U | GUID_Slider
V | GUID_Slider

Because the third axis on a gaming device is rarely a Z-axis, these mappings help provide better compatibility with Windows 2000, Windows XP and Windows 95/97/Me HID.


Axis Selection Overrides

The DirectX 8.0 release introduces a new mechanism to provide hardware vendors with limited ability to modify how DirectInput assigns axes for HID-compliant devices. The initial axis selection is made through an association between a HID usage page/usage pair on the device with an axis instance. The axis instance is described in an optional registry sub-key under the "Axes" sub-key for the device type key. (Note that the Axes sub-key is also an optional key under the device type-key.) Within the Axes sub-key, the Attributes value stores a DIOBJECTATTRIBUTES structure. Before DirectX 8.0, the wUsagePage and wUsage fields in the DIOBJECTATTRIBUTES structure assigned a HID usage page and usage to an object on a non-HID device. These members were ignored for HID-compliant devices.

With the release of DirectX 8.0, these members became relevant to HID-compliant devices as well. They describe the HID usage page and usage that DirectInput should reference to find a match for a specific DirectInput axis in the joystick data formats. Hardware vendors can take advantage of these fields to impose greater consistency in how DirectInput maps axes on different Windows operating systems. However, these are not a bulletproof mechanism for remapping axes.

Note Axis mapping is static, so the behavior is undefined if these values are changed while the device is in use. If the suggested match for an axis cannot be made, processing continues as though no mapping had been suggested.

For example, imagine a joystick device designed for use on a platform with a complete implementation of the HID_USAGE_PAGE_GAME controls. Such a device might describe its X and Y axes in HID as:

Axis | Usage Page | Usage | Description
X | 5 | 24 | Game page, move left/right
Y | 5 | 25 | Game page, move forward/backward

Because these scenarios are not directly recognized by DirectInput (or JoyHID) they are not very useful to games. To get them recognized as the X and Y axes by DirectInput, the following registry entries could be added:

[DIRECT_INPUT_TYPES\ VID_vvvv&PID_pppp)\Axes\0]
     Binary Attributes = 00 00 00 00 05 00 24 00

[DIRECT_INPUT_TYPES\ VID_vvvv&PID_pppp)\Axes\1]
     Binary Attributes = 00 00 00 00 05 00 25 00

Where "DIRECT_INPUT_TYPES" is a token for the following root key:
HKLM\SYSTEM\CurrentControlSet\Control\MediaProperties\PrivateProperties\Joystick\OEM

This mechanism has been implemented in the DirectInput 7.0 and below interfaces, the DirectInput 8.0 interfaces, as well as JoyHID.Vxd, the VJoyD minidriver used for WinMM support.

On Windows 95/98/Me, there are three possible data paths for a USB game controller:
  • The IHV can provide a VJoyD minidriver VxD that reports the data in the same way any other VJoyD minidriver does. In this case, axis selection is completely under the control of the IHV.
  • DirectInput can use the HID implementation that is provided with the operating system to communicate with the device. In this case, axis selection is made according to the device firmware or the registry flags (as described previously).
  • The system default HID-to-VJoyD driver (JoyHID.VxD) can be used

DirectInput uses JoyHID.VxD (via VJoyD.VxD) to read data for applications that specify a DIRECTINPUT_VERSION of less than 0x0700, or if the JOYTYPE_NOHIDDIRECT flag is specified for the device . If the DIRECT_INPUTVERSION is greater than or equal to 0x0700, DirectInput uses HID to interact with the device.

When the JoyHID/VJoyD path is taken, the following tables match WinMM axes to HID usage page/usage pairs:

WinMM Axis | Usage Page | Usage
X | HID_USAGE_PAGE_GENERIC | HID_USAGE_GENERIC_X
 | HID_USAGE_PAGE_GENERIC | HID_USAGE_GENERIC_RY
Y | HID_USAGE_PAGE_GENERIC | HID_USAGE_GENERIC_Y
 | HID_USAGE_PAGE_GENERIC | HID_USAGE_GENERIC_RX
Z | HID_USAGE_PAGE_GENERIC | HID_USAGE_GENERIC_Z
 | HID_USAGE_PAGE_SIMULATION | HID_USAGE_SIMULATION_THROTTLE
 | HID_USAGE_PAGE_GENERIC | HID_USAGE_GENERIC_SLIDER
 | HID_USAGE_PAGE_GENERIC | HID_USAGE_GENERIC_DIAL
R | HID_USAGE_PAGE_SIMULATION | HID_USAGE_SIMULATION_RUDDER
 | HID_USAGE_PAGE_GENERIC | HID_USAGE_GENERIC_RZ
U | HID_USAGE_PAGE_SIMULATION | HID_USAGE_SIMULATION_THROTTLE
 | HID_USAGE_PAGE_GENERIC | HID_USAGE_GENERIC_SLIDER
 | HID_USAGE_PAGE_GENERIC | HID_USAGE_GENERIC_DIAL
 | HID_USAGE_PAGE_GENERIC | HID_USAGE_GENERIC_RY
V | HID_USAGE_PAGE_GENERIC | HID_USAGE_GENERIC_RX

Note Mappings for the R, U and V axes fall through to next axis if a mapping is not found, whereas X, Y and Z mappings are completely independent of each other. This is because VJoyD.VxD only supports contiguous sets of axes (for example, X, Y, Z, R is supported, but X, Y, Z, U is not). The only exceptions to this rule are made for joysticks that use the precise combinations of X, Y and R, or X, Y, Z, R and V. This method of mapping helps to avoid the possibility that JoyHID.VxD will make axis assignments that VJoyD.VxD cannot tolerate.


Special Case Mappings

Due to the complexity and variety of input devices available today, no single set of mappings can be used for all types of devices. DirectInput supports two special cases that are described in this section.

Special Case Mapping for Z-Axes

In the rare cases where a Z-Axis described in HID is the desired WinMM mapping, there are two available overrides. If the device is a six-degree-of-freedom device, setting a type and subtype override (described in the references for DIJOYTYPEINFO) to DI8DEVTYPE_1STPERSON and DI8DEVTYPE1STPERSON_SIXDOF, respectively will invoke the following alternative mapping:

WinMM Axis | DirectInput Assignment
X | GUID_XAxis
Y | GUID_YAxis
Z | GUID_ZAxis
R | GUID_RzAxis
U | GUID_RyAxis
V | GUID_RxAxis

If the device is not a six-degree-of-freedom device, but still requires a Z-axis to be portrayed through DirectInput, the type override should be set to include JOYTYPE_INFOZISZ. This type override causes DirectInput to revert to the DirectX 7.0 mapping.

The default mapping for devices reporting through HID has not changed except that GUID_Slider axes are no longer substituted for GUID_ZAxis matches by the SetDataFormat method. Because HID axes are by nature more fully described than WinMM axes, the defaults should work in most cases. In rare cases, a slider axis (often used as a throttle) has been described as HID_USAGE_PAGE_GENERIC, HID_USAGE_Z because the axis would be used in the same way as a WinMM Z-axis. To make sure such devices can be used consistently the device override flag JOYTYPE_INFOZISSLIDER can be used.

Special-case Mappings for Car Controllers

Another set of special-case mappings are those needed for car controllers that declare more than two axes. Unfortunately, there is little consistency within the industry in this area. There presently exist three common ways to represent separate accelerator and brake pedals. DirectInput attempts to detect which method a car controller is using with logic akin to that shown in the following pseudo-code:

    if( has_r and has_Z )
        use mappings:
        X => GUID_XAxis
        Z => GUID_YAxis
        R => GUID_RzAxis
    else if( has_r )
        use mappings:
        X => GUID_XAxis
        Y => GUID_YAxis
        R => GUID_RzAxis
    else if( has_z )
        use mappings:
        X => GUID_XAxis
        Y => GUID_RzAxis
        Z => GUID_YAxis
    else
        use default mappings.

   // If the device declares any other axes, they are mapped to sliders.

The preceding logic results in all three known types of pedal mappings being reported to applications in the same way. If the default mappings fail, you can set override flags to select which type of mapping should be used. The override flags JOYTYPE_INFOYYPEDALS, JOYTYPE_INFOZYPEDALS, JOYTYPE_INFOYRPEDALS and JOYTYPE_INFOZRPEDALS are described elsewhere in this documentation.

As with WinMM, car controllers require special-case mapping when being used through the HID data-path. Mappings are made in the same way in this case as in the WinMM case, but with extra variations due to the possibility of the correct simulation page usages being reported in the device firmware.

Devices that report generic axes receive the same mappings and can use the same override mechanisms in both the HID and WinMM data paths. However, these overrides affect only the generic axes; they do not change the mapping table that is used for all axes on the device.

Axis Overrides under Windows 95/98/Me

The following interfaces are affected by axis overrides:

WinMM JoyGetPos()

WinMM JoyGetPosEx()

IDirectInput2

IDirectInput7

IDirectInput8

To perform an axis override

  1. Plug in the device whose axis is to be overridden. Run joy.cpl or any other DirectInput application to initialize the registry keys for this device. Unplug the device.
  2. Open the registry and find HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\MediaProperties\PrivateProperties\Joystick\OEM
  3. Locate the key for the device whose axis is to be overridden. The key should be located under this key, specified by its VID&PID combination.
  4. Create the following subkeys:
    • Axes
    • Under the "Axes" key, specify one key for each axis that you want to override (Axis key). The key is specified by a one-digit number from zero to 7 that describes GUID and axis information:
Key Name | DirectX GUID | WinMM Axis
0 | GUID_XAxis | X
1 | GUID_YAxis | Y
2 | GUID_ZAxis | Z
3 | GUID_RxAxis | -
4 | GUID_RyAxis | -
5 | GUID_RzAxis | R
6 | GUID_Slider | U
7 | GUID_Slider | V

  • Under each Axis key specify the Axis that you want to override. Create a binary value named Attributes and set it to: 00 00 00 00 HUP 00 HU 00. HUP is a two-digit hexadecimal number specifying the HID usage page of the device object (axis) that you want to override. HU is a two-digit hexadecimal number specifying the HID usage of the device object. Use DIQuick to determine these values, or see the HID specification.
  5. Plug the device back in and use any program to check whether the overrides work.

Meaning of the registry keys

First of all you need to differentiate between the axis mapping of the DirectX interfaces and the WinMM interfaces.

The DirectX interfaces interpret the Axiskeys to match GUIDs that are used to identify objects. The object GUIDs are used to read data from the device and specified in IDirectInputDevice8::SetDataFormat(). When data for an object is read by a program and this object is overridden, then DirectInput returns the data from the overriding object.

As you can see, there is no differentiation between slider 0 and slider 1 in the DirectInput interfaces. This means, when overriding axis 6 or 7, that you always override the first available slider. If slider 0 is not yet defined as an axis and you map an axis to 7, slider 0 will be overridden.

In contrary the WinMM interfaces do differentiate between the U and V axes, so if axis 7 is overridden, the V axis receives the data from the overriding object; if axis 6 is overridden, the data is converted to be sent by the U axis.

Rules to keep in mind

To guarantee the equal behavior of the interfaces, restrictive rules must be followed. These rules are provided by the behavior of WinMM interfaces.

Mappings that do not conform to these rules may result in failure of the WinMM interface to report any data for this device.

These rules do not apply to differences in slider mappings; such differences are acceptable.

Any mapping that does not fall within the following rules is unsupported.

  • No Holes

    The axis mapping must be continuous after applying the overrides. Only one axis can exist in an unmapped state, that is, "2"=GUID_ZAxis=Z. You can't skip axis entries. For instance: X, Y, Z, R, U, V is a valid sequence, but X, Z, R, U, V isn't because there's a "hole" between X and Z.

  • All Axes exist

    All axes that are used to perform override operations (specified by the Attributes value) must exist on the device.

  • Do not move axes "upwards" without mapping to them

    You cannot map an axis A to an axis B without mapping axis C to axis A if axis A would have a lower Key Name in the table above.

    Moving an axis upward without mapping to it will result in a hole..

If the mapping is not reflected by the interfaces

  • Always unplug the device before you change the mapping. Plug the device back in after you edit the mapping in order to reinitialize DirectInput.
  • DirectInput could deny special overrides. Check the key: HKEY_LOCAL_MACHINE\SYSTEM\Current,ControlSet\Control\MediaProperties\PrivateProperties\DirectInput\VID&PID , where VID&PID is the VID-PID-combination for the device. If there is a value Flags2 set, then DirectInput internally maps axes to axes and you cannot override these mappings. For instance you may not be able to move the mapping of a slider away from the Z-axis in the DInput7/2 and WinMM interfaces.
  • If the user installs and calibrates a joystick, the resulting calibration information is stored in the registry. If a driver is now installed which sets the axis overrides which differ from those previously stored in the registry, DirectInput will apply the overrides stored in the Registry. Because the calibration information in the registry does not reflect the axis mapping changes, the data might be reported incorrectly or might not reported at all on the overridden axes.
  • There are two ways to avoid this problem:
  • The user can recalibrate the device.
  • The driver vendor's installation can delete the calibration information in the registry.

If the device does not use joyhid.vxd as its driver, the wUsage and wUsagePage values are only used to describe what usage and usage page the object should be reported as, rather than being any form of override. The device uses joyhid.vxd only if the registry key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\MediaProperties\PrivateProperties\Joystick\OEM\VID&PID\OEMCallout equals joyhid.vxd.


Force Feedback Device Driver Interface

This section covers the interface between DirectInput and the device-specific force feedback driver. The following topics are covered:

OEMForceFeedback Registry Settings

Driver Interface

User-Mode Functions


OEMForceFeedback Registry Settings

New joystick registry entries are found under an OEM-specific key that is installed for each joystick device type under the key with the registry path HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\MediaProperties\PrivateProperties\Joystick\OEM. The data stored under this OEM-specific key is initialized when the device is first installed and then used for reference purposes only. In addition to the values defined for existing joystick devices, two new optional generic values and a set of force feedback specific values have been defined.

The two generic values are a binary value containing version information and a "Manufacturer" string value (REGSTR_VAL_MANUFACTURER in regstr.h ) containing a string for the manufacturer's name. The latter complements the existing "OEMName" value which holds the name of the device.

A new OEMForceFeedback key has been defined to hold force feedback specific keys and values. Under this key is an Effects subkey that contains two values for each effect.

Under the Effects subkey is a list of subkeys, one for each effect. The name of each subkey is a globally unique identifier (GUID) in the form "{12345678-1234-1234-1234-123456789012}". Beneath the key named "{...}" are two values. The default value is the string friendly name for the effect. The "Attributes" value is the DIEFFECTATTRIBUTES structure.

"{guid1}"
    Default value = friendly name for effect {guid1} (string)
    "Attributes" = DIEFFECTATTRIBUTES structure (binary)
"{guid2}"
    Default value = friendly name for effect {guid2} (string)
    "Attributes" = DIEFFECTATTRIBUTES structure (binary)

The OEMForceFeedback key also includes a value that contains the device attributes and one of two optional values. Of the optional values, use "CLSID" if you are using a ring 3 driver (DLL), and "VJoyD" if you are using a ring 0 driver (VxD).

"Attributes" = DIFFDEVICEATTRIBUTES structure (binary)
"CLSID" = {GUID} for force feedback effect driver (string)(optional)
"VJoyD" = zero-length binary (optional)

The name of the optional values indicate which form of interface is used. If the "CLSID" value is present, it should be a string value containing the GUID in the form "{12345678-1234-1234-1234-123456789012}" for the COM object that provides the driver interface. If the "VJoyD" value is present, it should be a zero-length binary value which indicates that the VJoyD minidriver associated with the device to be used should provide extra callbacks for the driver interface. A value is added to indicate that the Human Input/Interface Device (HID) provides the driver interface when that is implemented.

If a device supports a hardware effect that does not fall into any of the predefined categories (DIEFT_CONSTANTFORCE, DIEFT_RAMPFORCE, DIEFT_PERIODIC, DIEFT_CONDITION, or DIEFT_CUSTOMFORCE), then the DIEFFECTATTRIBUTES structure for the effect should specify DIEFT_HARDWARE as the effect type.

A device can support a hardware effect that falls into one of the predefined categories (listed in the preceding paragraph) but also receive additional parameters that are not part of the standard type-specific data structures (DICONSTANTFORCE, DIRAMPFORCE, DIPERIODIC, DICONDITION, or DICUSTOMFORCE). For information on these structures, see the DirectInput section of the DirectX Software Development Kit (SDK). In these cases, the effect should be listed twice as follows:

  • List the effect under the predefined category. If an application creates the effect in the predefined category, the driver should provide suitable defaults for the specified parameters that are not part of the standard type-specific data structure.
  • List the effect under the DIEFT_HARDWARE category. Create a special type-specific structure (such as DIPERIODICFORCEWITHDECAY) that contains the extra parameters.

In this manner, an application designed for your hardware can use the second effect descriptor to access the full capabilities of the effect, whereas an application designed for generic hardware can use the first effect descriptor to access basic capabilities of the effect.


Driver Interface

If the force-feedback driver is COM-based, an instance of the driver is created by DirectInput. If the interface specified is "VJoyD", then the VJoyD minidriver is loaded by VJoyD. Both driver paths support the following exported methods:

DestroyEffect

Initialize

DownloadEffect

GetEffectStatus

GetForceFeedbackState

Escape

SendForceFeedbackCommand

SetGain

StartEffect

StopEffect

This functionality is supported by all force feedback devices.


User-Mode Functions

DirectInput creates an instance of the force-feedback effect driver by creating the object named by the CLSID that is stored in the OEMForceFeedback registry subkey of the joystick type subkey.

Because applications using DirectInput need not load OLE, the effect driver should be careful not to rely on OLE-specific behavior. For example, applications using DirectInput cannot be relied upon to call the CoFreeUnusedLibraries method. DirectInput performs the standard COM operations to create an instance of the effect driver object. The only visible effect this should have on the implementation of the effect driver is described following.

After DirectInput releases the last effect driver object, it manually performs a FreeLibrary of the effect driver DLL. Consequently, if the effect driver DLL creates additional resources that are not associated with the effect driver object, it should manually LoadLibrary itself to artificially increase its DLL reference count, thereby preventing the FreeLibrary from DirectInput from unloading the DLL prematurely.

In particular, if the effect driver DLL creates a worker thread, the effect driver must perform this artificial LoadLibrary operation for as long as the worker thread exists. When the worker thread is no longer needed (for example, upon notification from the last effect driver object as it is being destroyed), the worker thread should call the FreeLibraryAndExitThread method to decrement the DLL reference count and terminate the thread.

All magnitude and gain values used by DirectInput are uniform and linear across the range. Any nonlinearity in the physical device must be handled by the device driver so that the application sees a linear device.

The user-mode force feedback functions that are exposed by the IDirectInputEffectDriver inferface must be implemented by a force-feedback effect driver DLL. For more information on these functions, see the IDirectInputEffectDriver section of the DirectInput Reference.


Extending the DirectInput Game Controller Control Panel

This section provides information about creating property sheets for the Microsoft® DirectInput® game controller control panel. The information is divided into the following topics:

About the DirectInput Control Panel

DirectInput Control Panel Architecture

DirectInput Control Panel Essentials


About the DirectInput Control Panel

DirectInput provides support for game controllers such as game pads, joysticks, and force-feedback devices. In Microsoft DirectX® 5.0 and later versions, DirectInput provides a new game controller control panel called Joy.cpl. This version of the control panel is the first to allow extensibility in that the property sheets that are displayed for each controller can be replaced with property pages that are specific to that controller. This is done through the creation of a DLL that contains information about these property sheets. This DLL exposes a COM interface that is called into by the DirectInput control panel.

Game controller hardware vendors are encouraged to use this extensibility feature to provide customized property sheets for their game controllers instead of creating a separate control panel. This allows the user to open a single control panel to configure and test their game controllers.


DirectInput Control Panel Architecture

This section describes the basic structure of the DirectInput control panel extensible property sheets. This structure is explained in the following topics:

Game Controller Control Panel

Gchand.dll, Services and Support

Gcdef.dll, the Default Analog Device Property Sheet

Integration with Windows


Game Controller Control Panel

The basic architecture of the DirectInput control panel consists of the DirectInput game controller control panel, the abstraction-layer library that supports the IDIGameCntrlPropSheet COM interface, and a COM object for each game controller property sheet.

Note The word "object" describes an entity created by CreateInstance to support the methods of a COM interface, even when these methods are not being called through an object-oriented programming language such as C++. The word "sheet" describes the dialog into which the pages insert. The word "page" describes the content dialogs of the "property sheet" dialog.

In the interest of portability between Microsoft Windows® 95/98/Me and Windows NT® 4.0 and later, the DirectInput control panel works directly with DirectInput, which in turn works directly with device drivers. As a by-product of this, the DirectInput control panel has access to input devices even when the application is in the background.


Gchand.dll, Services and Support

Gchand.dll is an InProcHandler that provides a layer of abstraction between Joy.cpl and the game controller property sheets. Generally, Gchand.dll does little more than simplify the Windows API call PropertySheet by reducing the number of parameters and enforcing others. As shown in Creating Your Property Sheet, to include Gchand.dll, simply add an InProcHandler32 entry to your property sheet DLL's HKEY_CLASSES_ROOT\CLSID entry in the registry. The "(default)" key should then contain the location of Gchand.dll.

Gchand.dll provides services using the COM interface IDIGameCntrlPropSheet. For information on the methods accessed by this interface, see IDIGameCntrlPropSheet.


Gcdef.dll, the Default Analog Device Property Sheet

Hardware vendors who do not create their own control panel use the services of the default analog device property sheet supplied by Gcdef.dll. Any controller that does not have a ConfigCLSID key in the registry under its HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\MediaProperties\PrivateProperties\Joystick\OEM\CONTROLLER_NAME entry uses this default property sheet. This property sheet contains the following two pages:

  • Test: This page demonstrates that the device is responding properly. It returns a graphical representation of the registry settings that are associated with the device attributes and allows the user to view them.
  • Settings: This page allows the user to write specific information about the device to the system. Services are provided for calibration and for a rudder or pedals.


Integration with Windows

Because the property sheet page is a COM object, it needs to be registered. This can be done by an INF file or through DirectInput's IDirectInputJoyConfig8 interface. A sample INF file is part of the sample property sheet in the DirectX DDK.

To register the property sheet page

  1. Use the DirectX SDK tool GUIDGEN to create a CLSID for your property sheet (this is the same as the one entered in the ConfigCLSID entry mentioned earlier). Remember, this is your device-specific property sheet GUID and it should be the same as the one in your code. If you are not familiar with COM, you may want to see the example in the DirectX DDK called CPLSVR1 (the code that reflects this process is contained in the Cplsvr1.h header file).
  2. Create a new key in the registry under My Computer\HKEY_CLASSES_ROOT\CLSID using this new GUID (it should look something like {B9EA2BE1-E8E9-11D0-9880-00AA0044480F}).
  3. Inside that key, create subkeys named InProcHandler32 and InProcServer32. (For an example, see the picture in Gchand.dll documentation).
  4. Inside the InProcHandler32 key, edit the (default) entry to reflect the location and name of Gchand.dll. An example would be "C:\windows\system\gchand.dll".
  5. Inside the InProcServer32 key, edit the (default) entry to reflect the location and name of your property sheet DLL.

Your device must also be properly registered as a gaming device. This may be done through DirectInput, or through an INF file.

To register the device

  1. In the registry key My Computer\HKEY_LOCAL_MACHINE\System\CurrentControlSet\control\MediaProperties\PrivateProperties\Joystick\OEM, enter a key for your device. It is advisable to make this key name the same as your device OEM Name.
  2. Create the following entries:
Key Value | Key value type | Key value type contents
ConfigCLSID | String Value | "{your property sheet CLSID}"
OEMName | String Value | "Product name of your device"

Note These two entries are the minimum you need to get started. Refer to the DirectX DDK for additional information about all of the available entries and their associated services.


DirectInput Control Panel Essentials

This section introduces the concepts and components of the DirectInput control panel, and provides information to help you begin implementing your own device-specific property sheet. This information is described in the following topics:

Files and Your Build Environment

Creating Your Property Sheet

Testing Your Property Sheet


Files and Your Build Environment

At a minimum, you will need the Direct X DDK include file Dicpl.h. This file provides you with the necessary interface, structures, class definitions, and errors. It is recommended that you use DirectInput's IDirectInputJoyConfig8 interface for all registry access to assure that your property sheet also works on Windows NT 4.0 and later. If you plan to use DirectInput in your property page, you must also used the associated DirectX SDK files. All structures in the DirectInput control panel are packed on 8-byte boundaries. Verify that your property sheet packs structures on 8-byte boundaries.

Note When testing your control panel, make sure to test it on a system whose primary display is set to a resolution of 640 x 480 pixels. Make sure that all the controls are still visible at this reduced resolution.


Creating Your Property Sheet

To speed your development time, consult the DirectX DDK sample property sheet application, CPLSVR1. This example demonstrates many aspects of DirectInput and provides a good starting point for your own custom property sheet.

To create your own property sheet

Creating a custom property sheet from scratch is a relatively simple process.

  1. Create a GUID to identify your property page:
    • Using the DirectX SDK tool, GUIDGEN, create a GUID for your property page (only one, no matter how many pages). Define this in your application-specific include file. It should look something like:

      DEFINE_GUID (CLSID_NAMEOFYOURDEVICE, 0x92187326, 0x72B4, 0x11D0, 0xA1, 0xAC, 0x0, 0x0, 0xF8, 0x2, 0x69, 0x77);

    • Create the required DllGetClassObject and DllCanUnloadNow. (An example of all of these steps is available in CPLSVR1; for further documentation please refer to your COM programmers manual).
    • Create an implementation for the COM ClassFactory defined in Dicpl.h.
    • Create the implementation for the IDIGamgeCntrlPropSheet interface.
    • Using Regedit, add your defined GUID to the My Computer\HKEY_CLASSES_ROOT\CLSID key. Then add the keys InProcHandler32 and InProcServer32 to your key.
    • Modify the (default) entry of the InProcHandler32 key to point to the location of Gchand.dll. (Path is not necessary if Gchand.dll is in the "Windows" system directory).
    • Modify the (default) entry of the InProcServer32 entry to point to the location of your property sheet DLL. An example would be: "C:\my_device\my_propertysheet.dll". This example shows a ProgID entry. This is not necessary, but is often used to store information about the module residing at that GUID.
  2. Create dialog templates and dialog procedures as you would for any Windows application.

    Note You may want to write a test container for your property sheets as a window that launches your pages as independent dialog boxes. At this point, you could also convert any existing control panel you might have to the DirectInput control panel.

  3. Populate the DIGCPAGEINFO and DIGCSHEETINFO structures and return that information in your implementations of IDIGameCntrlPropSheet::GetPageInfo and IDIGameCntrlPropSheet::GetSheetInfo respectively.

The generation of the property sheet pages is done through the PropertySheet function. All behaviors of this function are inherent in the property sheet pages. For example, the property sheet page reflects the largest dialog template that it receives. If the user creates one page and its associated template is very small, this will reflect directly on the size of the resulting dialog. Dialog templates are also important to remember when considering visual alignment and the centering of controls on a page. For example, consider a case in which the user creates two pages that contain items specified to be centered on the page. One item to be centered is 200 dialog units (DLUs) in width; the other is 100 units. In such a case, the latter item will not be centered on the page. Instead, the control is centered to its template and additional white space (or gray, as it may be) is added to the width of the more narrow page. You should create dialog templates of the same size, even if you are not using it all. (For more information on the PropertySheet function, see the Microsoft Win32® SDK.)


Testing Your Property Sheet

It is highly recommended that you run the debug version of both DirectInput and the DirectInput control panel during the testing of your property sheet page. DirectX components are designed to issue useful errors and warning messages to the debug window/terminal.

Debugging a control panel application can be tricky. Use the following steps to debug a custom property sheet page in Microsoft Developer Studio® 5.0 and newer(other compilers have similar behavior).

  1. From the Project menu, select Settings.
  2. Select the Debug tab.
  3. For the Executable for debug session: enter C:\WINDOWS\RUNDLL32.EXE (assuming C:\WINDOWS is the Windows 95 directory) if you are running Windows 95/98/Me, or C:\WINNT\SYSTEM32\RUNDLL32.EXE (assuming C:\WINNT is the operating system directory) if you are running Windows NT 4.0 or later.
  4. For the Program arguments enter shell32.dll,Control_RunDLL c:\windows\system\joy.cpl. Once again, this assumes that C:\WINDOWS is your Windows directory. It is case sensitive, and must be entered exactly as shown.

Once that is done, set your breakpoints and, from the build menu, select Start Debug, then Go. You are now ready to debug a custom property sheet page.


HID I/O Requests

This chapter describes I/O requests serviced by the Microsoft® Windows® HID class driver hidclass.sys and by HID minidrivers.

For more information about Windows support for HID, see the following:

Windows Input Architecture

USB HID Standard


I/O Requests Serviced by HID Class Driver

Although user applications can communicate with the HID class driver using the HID support routines for clients, kernel-mode clients must send device control requests directly to the class driver. The following section describes the IOCTLs that the HID class driver handles.

The input and output parameters are request-specific.

Upon completion of a request, the I/O status block members are set as follows:

  • The Status member is set by the class driver for all requests that it handles.
  • As described for each IOCTL, the Information member is set either by the class driver or a lower-level driver. Normally, when a lower-level driver transfers data from or to a device, the lower-level driver sets Information to the number of bytes transferred. However, the class driver might return a different value.


IOCTL_GET_PHYSICAL_DESCRIPTOR

Operation

Requests that the HID device associated with a top level collection provide information about which physical body part is used to control the device.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the output buffer.

Output

Irp->MdlAddress must point to the buffer that will receive the physical descriptor.

I/O Status Block

The HID class driver sets the following fields of Irp.IoStatus:

  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Headers

Declared in hidclass.h. Include hidclass.h.


IOCTL_HID_FLUSH_QUEUE

Operation

Dequeues all of the unparsed input reports from a top level collection's report input queue.

Input

None

Output

None

I/O Status Block

The HID class driver sets the following fields of Irp.IoStatus:

  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Headers

Declared in hidclass.h. Include hidclass.h.


IOCTL_HID_GET_COLLECTION_DESCRIPTOR

Operation

Retrieves a top-level's preparsed data, which the HID class driver extracted from the HID device's report descriptor during device initialization.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size, in bytes, of the output buffer specified by Irp->UserBuffer.

Output

Irp->UserBuffer is a PVOID pointer to a client-allocated buffer that the HID class driver uses to return a top-level collection's preparsed data. The buffer must be allocated from nonpaged pool. The size of the preparsed data is obtained using IOCTL_HID_GET_COLLECTION_INFORMATION.

I/O Status Block

The HID class driver sets the following fields of Irp.IoStatus:

  • Information is set to size, in bytes, of the preparesed data.
  • Status is set to STATUS_SUCCESS if the preparsed data was retrieved without error. Otherwise, it is set to an appropriate NTSTATUS error code. If the client-supplied output buffer is not large enough to hold the preparsed data, then status is set to STATUS_INVALID_BUFFER_SIZE.

Headers

Declared in hidclass.h. Include hidclass.h.


IOCTL_HID_GET_COLLECTION_INFORMATION

Operation

Retrieves a top-level collection's HID_COLLECTION_INFORMATION structure. This information includes the size, in bytes, of a collection's preparsed data.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the output buffer, which must be >= sizeof(HID_COLLECTION_INFORMATION).

Output

Irp->AssociatedIrp.SystemBuffer points to a buffer that will receive the collection information. This data will be formatted in the client-supplied buffer as a HID_COLLECTION_INFORMATION structure.

I/O Status Block

The HID class driver sets the following fields of Irp.IoStatus:

  • Information is set to sizeof(HID_COLLECTION_INFORMATION) if the data was retrieved successfully.
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Headers

Declared in hidclass.h. Include hidclass.h.

See Also

HID_COLLECTION_INFORMATION


IOCTL_HID_GET_FEATURE

Operation

IOCTL_HID_GET_FEATURE returns a feature report associated with a top-level collection.

Input

The Parameters.DeviceIoControl.OutputBufferLength member specifies the size, in bytes, of a client-allocated output buffer. The HID class driver uses this buffer to return a feature report. The buffer size, in bytes, must be large enough to hold the feature report — excluding its report ID, if report IDs are used — plus one additional byte that specifies a nonzero report ID or zero.

If the collection includes report IDs, the client must set the first byte of the output buffer to a nonzero report ID. Otherwise, the client must set the first byte of the output buffer to zero.

Output

The Irp->MdlAddress member points to the client-allocated output buffer that the HID class driver uses to return the feature report. The first byte of the buffer, which the client uses to input a report ID or zero, is unchanged. The feature report — excluding its report ID, if report IDs are used — is returned at ((PUCHAR)Irp->MdlAddress + 1).

I/O Status Block

The HID class driver sets the following fields of Irp.IoStatus:

  • Information is set to the number of bytes transferred from the device.
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Headers

Declared in hidclass.h. Include hidclass.h.

See Also

HidD_GetFeature, HidD_GetInputReport, HidD_SetFeature, HidD_SetOutputReport, IOCTL_HID_GET_INPUT_REPORT, IOCTL_HID_SET_FEATURE, IOCTL_HID_SET_OUTPUT_REPORT


IOCTL_HID_GET_HARDWARE_ID

Operation

Requests that the HID class driver retrieve the hardware ID from the registry for the HID device associated with a top level collection.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the output buffer.

Output

Irp->MdlAddress points to a buffer to receive the number of device input buffers.

I/O Status Block

The HID class driver sets the following fields of Irp.IoStatus:

  • Information is set to the number of bytes of registry information retrieved when the IOCTL succeeds.
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Headers

Declared in hidclass.h. Include hidclass.h.


IOCTL_HID_GET_INDEXED_STRING

Operation

Requests that the HID class driver instruct the minidriver to send a Get String Descriptor request to the device associated with a top level collection, in order to retrieve the human-readable (or "friendly") string at the indicated index in the device's string descriptor.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the input buffer at the location pointed to by Irp->AssociatedIrp.SystemBuffer. The input buffer must be >= sizeof(ULONG) and it should contain the index of the string to be retrieved.

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the output buffer.

Output

Irp->MdlAddress points to a buffer to receive the retrieved string.

I/O Status Block

The HID class driver sets the following fields of Irp.IoStatus:

  • Information is set to the number of bytes transferred from the device
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Headers

Declared in hidclass.h. Include hidclass.h.


IOCTL_HID_GET_INPUT_REPORT

Operation

IOCTL_HID_GET_INPUT_REPORT returns a HID class input report associated with a top-level collection of a HID class device.

Input

The Parameters.DeviceIoControl.OutputBufferLength member specifies the size, in bytes, of a client-allocated output buffer. The HID class driver uses this buffer to return an input report. The buffer size, in bytes, must be large enough to hold the input report — excluding its report ID, if report IDs are used — plus one additional byte that specifies a nonzero report ID or zero.

If the collection includes report IDs, the client must set the first byte of the output buffer to a nonzero report ID. Otherwise, the client must set the first byte of the output buffer to zero.

Output

The Irp->MdlAddress member points to the client-allocated output buffer that the HID class driver uses to return the input report. The first byte of the buffer, which the client uses to input a report ID or zero, is unchanged. The input report — excluding its report ID, if report IDs are used — is returned at ((PUCHAR)Irp->MdlAddress + 1).

I/O Status Block

The HID class driver sets the following fields of Irp.IoStatus:

  • Information is set to zero.
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Headers

Declared in hidclass.h. Include hidclass.h.

See Also

HidD_GetFeature, HidD_GetInputReport, HidD_SetFeature, HidD_SetOutputReport, IOCTL_HID_GET_FEATURE, IOCTL_HID_SET_FEATURE, IOCTL_HID_SET_OUTPUT_REPORT


IOCTL_HID_GET_MANUFACTURER_STRING

Operation

Requests that the HID class driver instruct the minidriver to send a Get String Descriptor request to the device associated with a top level collection, in order to retrieve the human-readable (or "friendly") name for the device's manufacturer.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the output buffer.

Output

Irp->MdlAddress points to a buffer to receive the manufacturer ID.

I/O Status Block

The HID class driver sets the following fields of Irp.IoStatus:

  • Information is set to the number of bytes transferred from the device
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Headers

Declared in hidclass.h. Include hidclass.h.


IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS

Operation

Retrieves the size of the report input queue for a top level collection.

The report input queue is implemented as a ring buffer. Therefore, if the underlying HID device transmits data to the linked HID class/miniclass drivers faster than the client can retrieve the HID reports, device data can be lost. The size of the report input queue can be tuned using IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the output buffer, which must be >= sizeof(ULONG).

Output

Irp->AssociatedIrp.SystemBuffer points to a buffer that will receive the size of the report input queue. The size of the buffer is sizeof(ULONG).

I/O Status Block

The HID class driver sets the following fields of Irp.IoStatus:

  • Information is set to sizeof(ULONG) if the size of the report input queue is successfully retrieved.
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Headers

Declared in hidclass.h. Include hidclass.h.


IOCTL_HID_GET_POLL_FREQUENCY_MSEC

Operation

Gets the current polling frequency of a top level collection.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the output buffer, which must be >= sizeof(ULONG).

Output

Irp->AssociatedIrp.SystemBuffer points to a buffer that will receive the polling frequency.

I/O Status Block

The HID class driver sets the following fields of Irp.IoStatus:

  • Information is set to sizeof(ULONG) if the polling frequency is successfully retrieved.
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Headers

Declared in hidclass.h. Include hidclass.h.


IOCTL_HID_GET_PRODUCT_STRING

Operation

Requests that the HID class driver instruct the minidriver to send a Get String Descriptor request to the device associated with a top level collection, in order to retrieve the human-readable (or "friendly") name for the device's product ID.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the output buffer.

Output

Irp->MdlAddress points to a buffer to receive the product ID string.

I/O Status Block

The HID class driver sets the following fields of Irp.IoStatus:

  • Information is set to the number of bytes transferred from the device
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Headers

Declared in hidclass.h. Include hidclass.h.


IOCTL_HID_GET_SERIALNUMBER_STRING

Operation

Requests that the HID class driver instruct the minidriver to send a Get String Descriptor request to the device associated with a top level collection, in order to retrieve the human-readable (or "friendly") name for the device's serial number.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the output buffer.

Output

Irp->MdlAddress points to a buffer to receive the serial number string.

I/O Status Block

The HID class driver sets the following fields of Irp.IoStatus:

  • Information is set to the number of bytes transferred from the device
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Headers

Declared in hidclass.h. Include hidclass.h.


IOCTL_HID_SET_FEATURE

Operation

The IOCTL_HID_SET_FEATURE sends a HID class feature report to a top-level collection of a HID class device.

Input

The Parameters.DeviceIoControl.InputBufferLength member is set to the size, in bytes, of a client-allocated input buffer that contains a HID class feature report.

The input buffer size, in bytes, must be large enough to hold the feature report — excluding its report ID, if report IDs are used - plus one additional byte that specifies a nonzero report ID or zero.

The Irp->AssociatedIrp.SystemBuffer member points to the input buffer that contains a feature report. If the collection includes report IDs, the client must set the first byte of the buffer to a nonzero report ID; otherwise the client must set the first byte to zero. The feature report — excluding its report ID, if report IDs are used - is located at ((PUCHAR)ReportBuffer + 1).

Output

None

I/O Status Block

The HID class driver sets the following fields of Irp.IoStatus:

  • Information is set to zero.
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Headers

Declared in hidclass.h. Include hidclass.h.

See Also

HidD_GetFeature, HidD_GetInputReport, HidD_SetFeature, HidD_SetOutputReport, IOCTL_HID_GET_INPUT_REPORT, IOCTL_HID_SET_OUTPUT_REPORT


IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS

Operation

Sets the size of the report input queue for a top level collection.

The report input queue is implemented as a ring buffer. Therefore, if the underlying HID device transmits data to the linked HID class-miniclass drivers faster than the client can retrieve the HID reports, device data can be lost. The size of the report input queue can be tuned using IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the input buffer, which must be >= sizeof(ULONG).

Irp->AssociatedIrp.SystemBuffer points to a buffer that will receive the new size of the report input queue. The size of the buffer is sizeof(ULONG).

Output

None

I/O Status Block

The HID class driver sets the following fields of Irp.IoStatus:

  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Headers

Declared in hidclass.h. Include hidclass.h.


IOCTL_HID_SET_OUTPUT_REPORT

Operation

IOCTL_HID_SET_OUTPUT_REPORT sends a HID class output report to a top-level collection of a HID class device.

Input

The Parameters.DeviceIoControl.InputBufferLength member is set to the size, in bytes, of a client-allocated input buffer that contains a HID class output report.

The input buffer size, in bytes, must be large enough to hold the output report — excluding its report ID, if report IDs are used — plus one additional byte that specifies a nonzero report ID or zero.

The Irp->AssociatedIrp.SystemBuffer member points to the input buffer that contains an output report. If the collection includes report IDs, the client must set the first byte of the buffer to a nonzero report ID. Otherwise, the client must set the first byte to zero. The output report — excluding its report ID, if report IDs are used — is located at ((PUCHAR)ReportBuffer + 1).

Output

None

I/O Status Block

The HID class driver sets the following fields of Irp.IoStatus:

  • Information is set to zero.
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Headers

Declared in hidclass.h. Include hidclass.h.

See Also

HidD_GetFeature, HidD_GetInputReport, HidD_SetFeature, HidD_SetOutputReport, IOCTL_HID_GET_FEATURE, IOCTL_HID_GET_INPUT_REPORT, IOCTL_HID_SET_FEATURE


IOCTL_HID_SET_POLL_FREQUENCY_MSEC

Operation

Sets the polling frequency of a top level collection.

Clients that do irregular, opportunistic reads on the polled device must furnish a polling interval of zero. In such cases, IOCTL_HID_SET_POLL_FREQUENCY_MSEC does not actually change the polling frequency of the device, but if the report data is not stale when the client does a read, the read is completed immediately with the latest report data for the indicated collection. If the report data is stale, it is refreshed immediately, without waiting for the expiration of the polling interval, and the read is completed with the new data.

If the value for the polling interval provided in the IRP is not zero, then it must be >= MIN_POLL_INTERVAL_MSEC and <= MAX_POLL_INTERVAL_MSEC.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the input buffer, which must be >= sizeof(ULONG).

Irp->AssociatedIrp.SystemBuffer contains the new polling interval.

Output

None

I/O Status Block

The HID class driver sets the following fields of Irp.IoStatus:

  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Headers

Declared in hidclass.h. Include hidclass.h.


I/O Requests Serviced by HID Minidrivers

HID minidrivers support only one IRP major function code, that being IRP_MJ_INTERNAL_DEVICE_CONTROL. The HID class driver and the HID minidriver communicate through IRP_MJ_INTERNAL_DEVICE_CONTROL IOCTLs.

Only the HID class driver sends I/O requests to the HID minidriver. Other drivers communicate with the device through the interface presented by the HID class driver.

HID minidrivers must support each IOCTL documented below.


IOCTL_GET_PHYSICAL_DESCRIPTOR

Operation

Requests the device provide information about which physical body part is used to control the HID device.

Input

Parameters.DeviceIoControl.InputBufferLength is set to the length of the system-resident buffer at Irp->UserBuffer.

Output

Miniclass drivers that complete the request to get the physical descriptor copy the results into the user buffer at Irp->UserBuffer with the physical descriptor.

I/O Status Block

Miniclass drivers that carry out the I/O to the device set the following fields of Irp.IoStatus:

  • Information is set to the number of bytes transferred from the device
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Miniclass drivers that call other drivers with this IRP to carry out the I/O to their device should ensure that the Information field of the status block is correct and not change the contents of the Status field.

Headers

Declared in hidclass.h. Include hidclass.h.


IOCTL_HID_ACTIVATE_DEVICE

Operation

Makes the device ready for I/O operations.

Input

Parameters.DeviceIoControl.Type3InputBuffer contains the collection identifier, as a ULONG value, of the collection to be made ready.

Output

None

I/O Status Block

Miniclass drivers that carry out the I/O to the device set the following fields of Irp.IoStatus:

  • Information is set to zero
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Miniclass drivers that call other drivers with this IRP to carry out the I/O to their device should ensure that the Information field of the status block is zero and not change the contents of the Status field.

Headers

Declared in hidclass.h. Include hidclass.h.


IOCTL_HID_DEACTIVATE_DEVICE

Operation

Causes the device to cease operations and terminate all outstanding I/O requests.

Input

Parameters.DeviceIoControl.Type3InputBuffer contains the collection identifier, as a ULONG value, of the collection that is ceasing operations.

Output

None

I/O Status Block

Miniclass drivers that carry out the I/O to the device set the following fields of Irp.IoStatus:

  • Information is set to zero
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Miniclass drivers that call other drivers with this IRP to carry out the I/O to their device should ensure that the Information field of the status block is zero and must not change the contents of the Status field.

Headers

Declared in hidclass.h. Include hidclass.h.


IOCTL_HID_GET_DEVICE_ATTRIBUTES

Operation

Retrieves a device's attributes in a HID_DEVICE_ATTRIBUTES structure.

Input

Parameters.DeviceIoControl.InputBufferLength contains the length, in bytes, of the HID class driver's buffer located at Irp->UserBuffer. The size, in bytes, of the buffer must be greater than or equal to the size, in bytes, of a HID_DEVICE_ATTRIBUTES structure.

Output

The miniclass driver returns the device attributes in a HID_DEVICE_ATTRIBUTES structure at Irp->UserBuffer.

I/O Status Block

  • Information is set to the number of bytes transferred from the device.
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Headers

Declared in hidclass.h. Include hidclass.h.

See Also

HID_DEVICE_ATTRIBUTES


IOCTL_HID_GET_DEVICE_DESCRIPTOR

Operation

Retrieves the device's HID descriptor.

Input

Parameters.DeviceIoControl.OutputBufferLength contains the length of the system-resident buffer provided at Irp->UserBuffer.

Output

The miniclass driver fills in the class driver-supplied system-resident buffer provided at Irp->UserBuffer with the device descriptor.

I/O Status Block

Miniclass drivers that carry out the I/O to the device set the following fields of Irp.IoStatus:

  • Information is set to the number of bytes transferred from the device
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Miniclass drivers that call other drivers with this IRP to carry out the I/O to their device should ensure that the Information field of the status block is correct and not change the contents of the Status field.

Headers

Declared in hidclass.h. Include hidclass.h.


IOCTL_HID_GET_FEATURE

Operation

IOCTL_HID_GET_FEATURE returns a HID class feature report from a HID class device.

Input

Irp->UserBuffer points to a HID_XFER_PACKET structure that the HID class driver uses to input the following members:

reportBuffer
Points to a client-allocated output buffer that a HID minidriver uses to return a HID class feature report.
reportBufferLen
Specifies the size, in bytes, of the output buffer.
reportID
Specifies a report ID associated with a top-level collection of a HID class device.

Output

((PHID_XFER_PACKET)(Irp->UserBuffer))->reportBuffer points to the client-allocated output buffer that the HID miniclass driver uses to return a feature report.

I/O Status Block

HID minidrivers that carry out the I/O to the device set the following fields of Irp.IoStatus:

  • Information is set to the number of bytes transferred from the device.
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

HID minidrivers that call other drivers with this IOCTL to carry out the I/O to their device, should ensure that the Information field of the status block is correct and not change the contents of the Status field.

Headers

Declared in hidclass.h. Include hidclass.h.

See Also

HidD_GetFeature, HidD_GetInputReport, HidD_SetFeature, HidD_SetOutputReport, IOCTL_HID_GET_INPUT_REPORT, IOCTL_HID_SET_FEATURE, IOCTL_HID_SET_OUTPUT_REPORT


IOCTL_HID_GET_INDEXED_STRING

Operation

Requests that the HID minidriver retrieve a particular human-readable string from the string descriptor of the device. The minidriver must send a Get String Descriptor request to the device, in order to retrieve the string descriptor, then it must extract the string at the indicated index from the string descriptor and return it in the output buffer indicated by the IRP.

Input

IOCTL_HID_GET_INDEXED_STRING uses two input buffers.

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the output buffer at the location pointed to by Irp->MdlAddress.

Parameters.DeviceIoControl.Type3InputBuffer in the I/O stack location of the IRP contains the language ID of the string to be retrieved in its most significant two bytes and the string index in its least significant two bytes.

Output

Irp->MdlAddress points to a buffer to receive the retrieved string. Note that unlike most device control IRPs for HID minidrivers, this IRP does not use METHOD_NEITHER buffering. In particular, it must be distinguished from IOCTL_HID_GET_STRING whose output buffer is identified by Irp->UserBuffer.

I/O Status Block

The HID class driver sets the following fields of Irp.IoStatus:

  • Information is set to the number of bytes transferred from the device
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Headers

Declared in hidclass.h. Include hidclass.h.


IOCTL_HID_GET_INPUT_REPORT

Operation

IOCTL_HID_GET_INPUT_REPORT returns a HID class input report from a HID class device.

Input

Irp->UserBuffer points to a HID_XFER_PACKET structure that the HID class driver uses to input the following members:

reportBuffer
Points to a client-allocated output buffer that a HID minidriver uses to return a HID class input report.
reportBufferLen
Specifies the size, in bytes, of the output buffer.
reportID
Specifies a report ID associated with a top-level collection of a HID class device.

Output

((PHID_XFER_PACKET)(Irp->UserBuffer))->reportBuffer points to the client-allocated output buffer that the HID miniclass driver uses to return the input report.

I/O Status Block

HID minidrivers that carry out the I/O to the device set the following fields of Irp.IoStatus:

  • Information is set to the number of bytes transferred from the device.
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

HID minidrivers that call other drivers with this IOCTL to carry out the I/O to their device, should ensure that the Information field of the status block is correct and not change the contents of the Status field.

Headers

Declared in hidclass.h. Include hidclass.h.

See Also

HidD_GetFeature, HidD_GetInputReport, HidD_SetFeature, HidD_SetOutputReport, IOCTL_HID_GET_FEATURE, IOCTL_HID_SET_FEATURE, IOCTL_HID_SET_OUTPUT_REPORT


IOCTL_HID_GET_REPORT_DESCRIPTOR

Operation

Obtains the report descriptor for the HID device.

Input

Parameters.DeviceIoControl.OutputBufferLength specifies the length, in bytes, of the locked-down buffer at Irp->UserBuffer.

Output

The miniclass driver fills the buffer at Irp->UserBuffer with the report descriptor.

I/O Status Block

Miniclass drivers that carry out the I/O to the device set the following fields of Irp.IoStatus:

  • Information is set to the number of bytes transferred from the device
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Otherwise, the miniclass driver should ensure that the Information field of the status block is correct in the completed IRP but the miniclass driver should not change the contents of the Status field.

Headers

Declared in hidclass.h. Include hidclass.h.


IOCTL_HID_GET_STRING

Operation

Requests that the HID minidriver retrieve a human-readable string for either the manufacturer ID, the product ID, or the serial number from the string descriptor of the device. The minidriver must send a Get String Descriptor request to the device, in order to retrieve the string descriptor, then it must extract the string at the appropriate index from the string descriptor and return it in the output buffer indicated by the IRP. Before sending the Get String Descriptor request, the minidriver must retrieve the appropriate index for the manufacturer ID, the product ID or the serial number from the device extension of a top level collection associated with the device.

Input

IOCTL_HID_GET_STRING makes use of two input buffers.

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the locked-down output buffer at Irp->UserBuffer.

Parameters.DeviceIoControl.Type3InputBuffer in the I/O stack location of the IRP contains a composite value. The two most significant bytes contain the language ID of the string to be retrieved. The two least significant bytes contain one of the following three constant values:

  • HID_STRING_ID_IMANUFACTURER
  • HID_STRING_ID_IPRODUCT,
  • HID_STRING_ID_ISERIALNUMBER.

The HID minidriver must determine which of these three constants is present in the lower two bytes of the input buffer, then it must retrieve the corresponding string index from the device descriptor. Device descriptor information is stored in the device extension of a top level collection associated with the device.

It is important not to confuse these three constants with the actual string indices of the IDs. These constants represent the offsets in the device descriptor where the corresponding string indices can be found.

For example, HID_STRING_ID_IMANUFACTURER indicates the location in the device descriptor where the index for the manufacturer ID is found. This index, in turn, serves as an offset into the string descriptor where the human-readable form of the manufacturer ID is located.

Output

The miniclass driver fills the buffer at Irp->UserBuffer with the requested string.

I/O Status Block

Miniclass drivers that carry out the I/O to the device set the following fields of Irp.IoStatus:

  • Information is set to the number of bytes transferred from the device
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Otherwise, the miniclass driver should ensure that the Information field of the status block is correct in the completed IRP but the miniclass driver must not change the contents of the Status field.

Headers

Declared in hidclass.h. Include hidclass.h.


IOCTL_HID_READ_REPORT

Operation

Return a report from the device into a class driver-supplied buffer.

Input

Parameters.DeviceIoControl.InputBufferLength contains the size of the buffer provided at Irp->UserBuffer.

Output

The miniclass driver fills the system-resident buffer pointed to by Irp->UserBuffer with the report data retrieved from the device.

I/O Status Block

Miniclass drivers that carry out the I/O to the device set the following fields of Irp.IoStatus:

  • Information is set to the number of bytes transferred from the device
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Miniclass drivers that call other drivers with this IRP to carry out the I/O to their device should ensure that the Information field of the status block is correct and not change the contents of the Status field.

Headers

Declared in hidclass.h. Include hidclass.h.


IOCTL_HID_SET_FEATURE

Operation

IOCTL_HID_SET_FEATURE sends a HID class output report to a top-level collection of a HID class device.

Input

Irp->UserBuffer points to a HID_XFER_PACKET structure that the HID class driver uses to input the following members:

reportBuffer
Pointer to a client-allocated input buffer that contains a HID class feature report.
reportBufferLen
Specifies the size, in bytes, of the input buffer.
reportID
Specifies the report ID for a top-level collection of a HID class device.

Output

None

I/O Status Block

HID minidrivers that carry out the I/O to the device set the following fields of Irp.IoStatus:

  • Information is set to the number of bytes transferred to the device
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

HID minidrivers that call other drivers with this IOCTL to carry out the I/O, should ensure that the Information field of the status block is correct and not change the contents of the Status field.

Headers

Declared in hidclass.h. Include hidclass.h.

See Also

HidD_GetFeature, HidD_GetInputReport, HidD_SetFeature, HidD_SetOutputReport, IOCTL_HID_GET_INPUT_REPORT, IOCTL_HID_SET_OUTPUT_REPORT


IOCTL_HID_SET_OUTPUT_REPORT

Operation

IOCTL_HID_SET_OUTPUT_REPORT sends a HID class output report to a top-level collection of a HID class device.

Input

Irp->UserBuffer points to a HID_XFER_PACKET structure that the HID class driver uses to input the following members:

reportBuffer
Pointer to a client-allocated input buffer that contains a HID class output report.
reportBufferLen
Specifies the size, in bytes, of the output buffer.
reportID
Specifies the report ID for a top-level collection of a HID class device.

Output

None

I/O Status Block

HID minidrivers that carry out the I/O to the device set the following fields of Irp.IoStatus:

  • Information is set to the number of bytes transferred to the device.
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

HID minidrivers that call other drivers with this IOCTL to carry out the I/O should ensure that the Information field of the status block is correct and not change the contents of the Status field.

Headers

Declared in hidclass.h. Include hidclass.h.

See Also

HidD_GetFeature, HidD_GetInputReport, HidD_SetFeature, HidD_SetOutputReport, IOCTL_HID_GET_INPUT_REPORT, IOCTL_HID_SET_FEATURE


IOCTL_HID_WRITE_REPORT

Operation

Transmits a class driver-supplied report to the device.

Input

Irp->UserBuffer points to a HID_XFER_PACKET structure the contains the parameters and report to be transmitted to the device. The following members are used:

  • reportBuffer points to a resident buffer containing the data to be sent to the device
  • reportBufferLen contains the length of the buffer provided at reportBuffer
  • reportId contains the report identifier, for this collection, of the report data to be written to the device

Output

None

I/O Status Block

Miniclass drivers that carry out the I/O to the device set the following fields of Irp.IoStatus:

  • Information is set to the number of bytes transferred to the device
  • Status is set to STATUS_SUCCESS if the transfer completed without error. Otherwise, it is set to an appropriate NTSTATUS error code.

Miniclass drivers that call other drivers with this IRP to carry out the I/O should ensure that the Information field of the status block is correct and not change the contents of the Status field.

Headers

Declared in hidclass.h. Include hidclass.h.


HID Support Routines for Clients

This section describes Microsoft-supplied routines that user-mode and kernel-mode clients use to support HID devices in Microsoft® Windows®. As a general rule, user-mode clients can call any routine in this section. However, kernel-mode clients can only call routines that begin with the prefix "HidP_". See the individual routine comments to determine the availability of a routine.

For more information about HID support by Windows, see:

Windows Input Architecture

USB HID Standard

Routines in this section are listed in alphabetical order.


HidD_FlushQueue

The HidD_FlushQueue routine deletes all pending input reports in a top-level collection's input queue.

BOOLEAN
  HidD_FlushQueue(
    IN HANDLE  HidDeviceObject
    );

Parameters

HidDeviceObject
Specifies an open handle to the top-level collection whose input queue is flushed.

Return Value

HidD_FlushQueue returns TRUE if it successfully flushes the queue. Otherwise, it returns FALSE.

Headers

Declared in hidsdi.h. Include hidsdi.h.

Comments

Only user-mode clients can call HidD_FlushQueue. Kernel-mode drivers can use an IOCTL_HID_FLUSH_QUEUE request.

See Also

IOCTL_HID_FLUSH_QUEUE


HidD_FreePreparsedData

The HidD_FreePreparsedData routine releases the resources that the HID class driver allocated to hold a top-level collection's preparsed data.

BOOLEAN
  HidD_FreePreparsedData(
    IN PHIDP_PREPARSED_DATA  PreparsedData
    );

Parameters

PreparsedData
Pointer to the buffer, returned by HidD_GetPreparsedData, that is freed.

Return Value

HidD_FreePreparsedData returns TRUE if it succeeds. Otherwise, it returns FALSE if the buffer was not a preparsed data buffer.

Headers

Declared in hidsdi.h. Include hidsdi.h.

Comments

Only user-mode clients can call HidD_FreePreparsedData.

See Also

HidD_GetPreparsedData


HidD_GetAttributes

The HidD_GetAttributes routine returns the attributes of a specified top-level collection.

BOOLEAN
  HidD_GetAttributes(
    IN HANDLE  HidDeviceObject,
    OUT PHIDD_ATTRIBUTES  Attributes
    );

Parameters

HidDeviceObject
Specifies an open handle to a top-level collection.
Attributes
Pointer to a caller-allocated HIDD_ATTRIBUTES structure that returns the attributes of the device specified by HidDeviceObject.

Return Value

HidD_GetAttributes returns TRUE if succeeds; otherwise, it returns FALSE.

Headers

Declared in hidsdi.h. Include hidsdi.h.

Comments

Only user-mode clients can call HidD_GetAttributes. Kernel-mode drivers can use IOCTL_HID_GET_COLLECTION_INFORMATION.

See Also

HIDD_ATTRIBUTES, IOCTL_HID_GET_COLLECTION_INFORMATION


HidD_GetFeature

The HidD_GetFeature routine returns a feature report from a specified top-level collection.

BOOLEAN
  HidD_GetFeature(
    IN HANDLE  HidDeviceObject,
    OUT PVOID  ReportBuffer,
    IN ULONG  ReportBufferLength
    );

Parameters

HidDeviceObject
Specifies an open handle to a top-level collection.
ReportBuffer
Pointer to a caller-allocated HID report buffer that the caller uses to specify a report ID. HidD_GetFeature uses ReportBuffer to return the specified feature report.

If the top-level collection includes report IDs, the caller must set the first byte of the buffer to a nonzero report ID; otherwise the caller must set the first byte to zero.

ReportBufferLength
Specifies the size, in bytes, of the report buffer. The report buffer must be large enough to hold the feature report — excluding its report ID, if report IDs are used — plus one additional byte that specifies a nonzero report ID or zero.

Return Value

If HidD_GetFeature succeeds, it returns TRUE; otherwise, it returns FALSE.

Headers

Declared in hidsdi.h. Include hidsdi.h.

Comments

The feature report — excluding its report ID, if report IDs are used — is returned at ((PUCHAR)ReportBuffer + 1).

Only user-mode clients can call HidD_GetFeature. Kernel-mode drivers can use an IOCTL_HID_GET_FEATURE request.

For more information, see the following topics:

USB HID Standard

Hid Concepts

Obtaining HID Reports

See Also

HidD_SetFeature, HidD_GetInputReport, HidD_SetOutputReport, IOCTL_HID_GET_FEATURE, IOCTL_HID_GET_INPUT_REPORT, IOCTL_HID_SET_FEATURE, IOCTL_HID_SET_OUTPUT_REPORT


HidD_GetHidGuid

The HidD_GetHidGuid routine returns the GUID for HID devices.

VOID
  HidD_GetHidGuid(
    OUT LPGUID  HidGuid
    );

Parameters

HidGuid
Pointer to a caller-allocated GUID buffer that routine uses to return the HID device GUID.

Return Value

None

Headers

Declared in hidsdi.h. Include hidsdi.h.

Comments

Only user-mode clients can call HidD_GetHidGuid.


HidD_GetIndexedString

The HidD_GetIndexedString routine returns a specified embedded string from a top-level collection.

BOOLEAN
  HidD_GetIndexedString(
    IN HANDLE  HidDeviceObject,
    IN ULONG  StringIndex,
    OUT PVOID  Buffer,
    IN ULONG  BufferLength
    ) ;

Parameters

HidDeviceObject
Specifies an open handle to a top-level collection.
StringIndex
Specifies the device-specific index of an embedded string.
Buffer
Pointer to a caller-allocated buffer that the routine uses to return the embedded string specified by StringIndex.
BufferLength
Specifies the length, in bytes, of the caller-allocated buffer provided at Buffer.

Return Value

HidD_GetIndexedString returns TRUE if it succeeds; otherwise, it returns FALSE.

Headers

Declared in hidsdi.h. Include hidsdi.h.

Comments

Only user-mode clients can call HidD_GetIndexedString. Kernel-mode drivers can use an IOCTL_HID_GET_INDEXED_STRING request.

See Also

HidD_GetManufacturerString, HidD_GetPhysicalDescriptor, HidD_GetProductString, HidD_GetSerialNumberString, IOCTL_HID_GET_INDEXED_STRING


HidD_GetInputReport

The HidD_GetInputReport routine returns an input report from a top-level collection.

BOOLEAN __stdcall
HidD_GetInputReport(
    IN HANDLE  HidDeviceObject,
    IN OUT  PVOID  ReportBuffer,
    IN ULONG  ReportBufferLength
    );

Parameters

HidDeviceObject
Specifies an open handle to a top-level collection.
ReportBuffer
Pointer to a caller-allocated input report buffer that the caller uses to specify a HID report ID and HidD_GetInputReport uses to return the specified input report.

If the top-level collection includes report IDs, the caller must set the first byte of the buffer to a nonzero report ID; otherwise the caller must set the first byte to zero.

ReportBufferLength
Specifies the size, in bytes, of the report buffer. The report buffer must be large enough to hold the input report — excluding its report ID, if report IDs are used — plus one additional byte that specifies a nonzero report ID or zero.

Return Value

HidD_GetInputReport returns TRUE if it succeeds; otherwise, it returns FALSE.

Headers

Declared in hidsdi.h. Include hidsdi.h.

Comments

The input report — excluding its report ID, if report IDs are used — is returned at ((PUCHAR)ReportBuffer + 1).

Only user-mode clients can call HidD_GetInputReport. Kernel-mode drivers can use an IOCTL_HID_GET_INPUT_REPORT request.

For more information, see the following topics:

USB HID Standard

Hid Concepts

Obtaining HID Reports

See Also

HidD_GetFeature, HidD_SetFeature, HidD_SetOutputReport, IOCTL_HID_GET_FEATURE, IOCTL_HID_GET_INPUT_REPORT, IOCTL_HID_SET_FEATURE, IOCTL_HID_SET_OUTPUT_REPORT


HidD_GetManufacturerString

The HidD_GetManufacturerString routine returns a top-level collection's embedded string that identifies the manufacturer.

BOOLEAN
  HidD_GetManufacturerString(
    IN HANDLE  HidDeviceObject,
    OUT PVOID  Buffer,
    IN ULONG  BufferLength
    );

Parameters

HidDeviceObject
Specifies an open handle to a top-level collection.
Buffer
Pointer to a caller-allocated buffer that the routine uses to return the collection's manufacturer string.
BufferLength
Specifies the length, in bytes, of the caller-allocated buffer provided at Buffer.

Return Value

HidD_GetManufacturerString returns TRUE if it succeeds; otherwise, it returns FALSE.

Headers

Declared in hidsdi.h. Include hidsdi.h.

Comments

Only user-mode clients can call HidD_GetManufacturerString. Kernel-mode drivers can use an IOCTL_HID_GET_MANUFACTURER_STRING request.

See Also

HidD_GetIndexedString, HidD_GetPhysicalDescriptor, HidD_GetProductString, HidD_GetSerialNumberString, IOCTL_HID_GET_MANUFACTURER_STRING


HidD_GetNumInputBuffers

The HidD_GetNumInputBuffers routine returns the current size, in number of reports, of the ring buffer that the HID class driver uses to queue input reports from a specified top-level collection.

BOOLEAN
  HidD_GetNumInputBuffers(
    IN HANDLE  HidDeviceObject,
    OUT PULONG  NumberBuffers
    );

Parameters

HidDeviceObject
Specifies an open handle to a top-level collection.
NumberBuffers
Pointer to a caller-allocated variable that the routine uses to return the maximum number of input reports the ring buffer can hold.

Return Value

HidD_GetNumInputBuffers returns TRUE if it succeeds; otherwise, it returns FALSE.

Headers

Declared in hidsdi.h. Include hidsdi.h.

Comments

Only user-mode clients can call HidD_GetNumInputBuffers. Kernel-mode drivers can use the IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS request.

See Also

HidD_SetNumInputBuffers, IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS, IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS


HidD_GetPhysicalDescriptor

The HidD_GetPhysicalDescriptor routine returns the embedded string of a top-level collection that identifies the collection's physical device.

BOOLEAN
  HidD_GetPhysicalDescriptor(
    IN HANDLE  HidDeviceObject,
    OUT PVOID  Buffer,
    IN ULONG  BufferLength
    );

Parameters

HidDeviceObject
Specifies an open handle to a top-level collection.
Buffer
Pointer to a caller-allocated buffer that the routine uses to return the requested physical descriptor.
BufferLength
Specifies the length, in bytes, of the buffer at Buffer.

Return Value

HidD_GetPhysicalDescriptor returns TRUE if it succeeds; otherwise, it returns FALSE.

Headers

Declared in hidsdi.h. Include hidsdi.h.

Comments

Only user-mode clients can call HidD_GetPhysicalDescriptor. Kernel-mode drivers can use an IOCTL_GET_PHYSICAL_DESCRIPTOR request.

See Also

HidD_GetIndexedString, HidD_GetManufacturerString, HidD_GetProductString, HidD_GetSerialNumberString, IOCTL_GET_PHYSICAL_DESCRIPTOR


HidD_GetPreparsedData

The HidD_GetPreparsedData routine returns a top-level collection's preparsed data.

BOOLEAN
  HidD_GetPreparsedData(
    IN HANDLE  HidDeviceObject,
    OUT PHIDP_PREPARSED_DATA  *PreparsedData
    );

Parameters

HidDeviceObject
Specifies an open handle to a top-level collection.
PreparsedData
Pointer to the address of a routine-allocated buffer that contains the collection's preparsed data.

Return Value

HidD_GetPreparsedData returns TRUE if it succeeds; otherwise, it returns FALSE.

Headers

Declared in hidsdi.h. Include hidsdi.h.

Comments

Only user-mode clients can call HidD_GetPreparsedData. Kernel-mode drivers can use an IOCTL_HID_GET_COLLECTION_DESCRIPTOR request.

When a client no longer requires the preparsed data, it should call HidD_FreePreparsedData to free the preparsed data buffer.

See Also

HidD_FreePreparsedData, IOCTL_HID_GET_COLLECTION_DESCRIPTOR


HidD_GetProductString

The HidD_GetProductString routine returns the embedded string of a top-level collection that identifies the manufacturer's product.

BOOLEAN
  HidD_GetProductString(
    IN HANDLE  HidDeviceObject,
    OUT PVOID  Buffer,
    IN ULONG  BufferLength
    );

Parameters

HidDeviceObject
Specifies an open handle to a top-level collection.
Buffer
Pointer to a caller-allocated buffer that the routine uses to return the requested product string.
BufferLength
Specifies the length, in bytes, of the buffer at Buffer.

Return Value

HidD_GetProductDescriptor returns TRUE if it succeeds; otherwise, it returns FALSE.

Headers

Declared in hidsdi.h. Include hidsdi.h.

Comments

Only user-mode clients can call HidD_GetProductString. Kernel-mode drivers can use an IOCTL_HID_GET_PRODUCT_STRING request.

See Also

HidD_GetIndexedString, HidD_GetManufacturerString, HidD_GetPhysicalDescriptor, HidD_GetSerialNumberString, IOCTL_HID_GET_PRODUCT_STRING


HidD_GetSerialNumberString

The HidD_GetSerialNumberString routine returns the embedded string of a top-level collection that identifies the serial number of the device.

BOOLEAN
  HidD_GetSerialNumberString(
    IN HANDLE  HidDeviceObject,
    OUT PVOID  Buffer,
    IN ULONG  BufferLength
    );

Parameters

HidDeviceObject
Specifies an open handle to a top-level collection.
Buffer
Pointer to a caller-allocated buffer that the routine uses to return the requested serial number string.
BufferLength
Specifies the length, in bytes, of the buffer at Buffer.

Return Value

HidD_GetSerialNumberString returns TRUE if it succeeds; otherwise, it returns FALSE.

Headers

Declared in hidsdi.h. Include hidsdi.h.

Comments

Only user-mode clients can call HidD_GetSerialNumberString. Kernel-mode drivers can use IOCTL_HID_GET_SERIALNUMBER_STRING.

See Also

HidD_GetIndexedString, HidD_GetManufacturerString, HidD_GetPhysicalDescriptor, HidD_GetProductString, IOCTL_HID_GET_SERIALNUMBER_STRING


HidD_SetFeature

The HidD_SetFeature routine sends a feature report to a top-level collection.

BOOLEAN
  HidD_SetFeature(
    IN HANDLE  HidDeviceObject,
    IN PVOID  ReportBuffer,
    IN ULONG  ReportBufferLength
    );

Parameters

HidDeviceObject
Specifies an open handle to a top-level collection.
ReportBuffer
Pointer to a caller-allocated feature report buffer that the caller uses to specify a HID report ID.

If the top-level collection includes report IDs, the caller must set the first byte of the buffer to a nonzero report ID; otherwise, the caller must set the first byte to zero.

The feature report — excluding its report ID, if report IDs are used — is located at ((PUCHAR)ReportBuffer + 1).

ReportBufferLength
Specifies the size, in bytes, of the report buffer. The report buffer must be large enough to hold the feature report — excluding its report ID, if report IDs are used — plus one additional byte that specifies a nonzero report ID or zero.

Return Value

If HidD_SetFeature succeeds, it returns TRUE; otherwise, it returns FALSE.

Headers

Declared in hidsdi.h. Include hidsdi.h.

Comments

Only user-mode clients can call HidD_SetFeature. Kernel-mode drivers can use the IOCTL_HID_SET_FEATURE request.

For more information, see the following topics:

USB HID Standard

HID Concepts

Sending HID Reports

See Also

HidD_GetFeature, HidD_GetInputReport, HidD_SetOutputReport, IOCTL_HID_GET_FEATURE, IOCTL_HID_GET_INPUT_REPORT, IOCTL_HID_SET_FEATURE, IOCTL_HID_SET_OUTPUT_REPORT


HidD_SetNumInputBuffers

The HidD_SetNumInputBuffers routine sets the maximum number of input reports that the HID class driver ring buffer can hold for a specified top-level collection.

BOOLEAN
  HidD_SetNumInputBuffers(
    IN HANDLE  HidDeviceObject,
    OUT ULONG  NumberBuffers
    );

Parameters

HidDeviceObject
Specifies an open handle to a top-level collection.
NumberBuffers
Specifies the maximum number of buffers that the HID class driver maintains for input reports from the collection specified by HidDeviceObject.

Return Value

HidD_SetNumInputBuffers returns TRUE if it succeeds; otherwise, it returns FALSE.

Headers

Declared in hidsdi.h. Include hidsdi.h.

Comments

Only user-mode clients can call HidD_SetNumInputBuffers. Kernel-mode clients can use an IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS request.

If HidD_SetNumInputBuffers returns FALSE and the Microsoft® Win32® function GetLastError indicates that an invalid parameter was supplied, the number of input buffers specified was below the minimum number allowed by the HID class driver.

See Also

HidD_GetNumInputBuffers, IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS


HidD_SetOutputReport

The HidD_SetOutputReport routine sends an output report to a top-level collection.

BOOLEAN __stdcall
  HidD_SetOutputReport(
    IN HANDLE  HidDeviceObject,
    IN PVOID  ReportBuffer,
    IN ULONG  ReportBufferLength
    );
HidDeviceObject
Specifies an open handle to a top-level collection.
ReportBuffer
Pointer to a caller-allocated output report buffer that the caller uses to specify a report ID.

If the top-level collection includes report IDs, the caller must set the first byte of the buffer to a nonzero report ID; otherwise, the caller must set the first byte to zero.

The output report — excluding its report ID, if report IDs are used — is located at ((PUCHAR)ReportBuffer + 1).

ReportBufferLength
Specifies the size, in bytes, of the report buffer. The report buffer must be large enough to hold the output report — excluding its report ID, if report IDs are used — plus one additional byte that specifies a nonzero report ID or zero.

Return Value

If HidD_SetOutputReport succeeds, it returns TRUE; otherwise, it returns FALSE.

Headers

Declared in hidsdi.h. Include hidsdi.h.

Comments

Only user-mode clients can call HidD_SetOutputReport. Kernel-mode drivers can use an IOCTL_HID_SET_OUTPUT_REPORT request.

See also Sending HID Reports.

See Also

HidD_GetFeature, HidD_GetInputReport, HidD_SetFeature, IOCTL_HID_GET_FEATURE, IOCTL_HID_GET_INPUT_REPORT, IOCTL_HID_SET_FEATURE, IOCTL_HID_SET_OUTPUT_REPORT


HidP_GetButtonCaps

The HidP_GetButtonCaps routine returns a button capability array that describes all the HID control buttons in a top level collection for a specified type of HID report.

NTSTATUS
  HidP_GetButtonCaps(
    IN HIDP_REPORT_TYPE  ReportType,
    OUT PHIDP_BUTTON_CAPS  ButtonCaps,
    IN OUT PULONG  ButtonCapsLength,
    IN PHIDP_PREPARSED_DATA  PreparsedData
    );

Parameters

ReportType
Specifies a HIDP_REPORT_TYPE enumerator value that identifies the report type.
ButtonCaps
Pointer to a caller-allocated buffer that the routine uses to return a button capability array for the specified report type.
ButtonCapsLength
Specifies the length on input, in array elements, of the buffer provided at ButtonCaps. On output, this parameter is set to the actual number of elements that the routine returns.
PreparsedData
Pointer to a top-level collection's Preparsed Data.

Return Value

HidP_GetButtonCaps returns one of the following status values.

Status Value | Description
HIDP_STATUS_ SUCCESS | The routine successfully returned the capability data.
HIDP_STATUS_ INVALID_PREPARSED_DATA | The preparsed data is not valid.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

HidP_GetButtonCaps returns the capability of all buttons in a top level collection for a specified report type.

ButtonCapsLength should be set to the value of the Number Xxx ButtonCaps member of the HIDP_CAPS structure returned by HidP_GetCaps, where "Xxx" specifies the report type.

To obtain a subset of button capabilities, selected by usage, usage page, or link collection, use HidP_GetSpecificButtonCaps.

HidP_GetButtonCaps runs at IRQL = PASSIVE_LEVEL.

For more information about a collection's capability, see:

Button Capability Arrays

Value Capability Arrays

Link Collections

Initializing and Connecting a HID Client

See Also

HidP_GetSpecificButtonCaps, HidP_GetCaps, HIDP_BUTTON_CAPS


HidP_GetButtons

The HidP_GetButtons macro is a mnemonic alias for the HidP_GetUsages routine.

NTSTATUS __stdcall
  HidP_GetUsages (
    IN HIDP_REPORT_TYPE  ReportType,
    IN USAGE  UsagePage,
    IN USHORT  LinkCollection, // Optional
    OUT USAGE  *UsageList,
    IN OUT ULONG  *UsageLength,
    IN PHIDP_PREPARSED_DATA  PreparsedData,
    IN PCHAR  Report,
    IN ULONG  ReportLength
    );

Headers

Declared in hidpi.h. Include hidpi.h.

See Also

HidP_GetUsages


HidP_GetButtonListLength

The HidP_GetButtonListLength macro is a mnemonic alias for the HidP_GetUsageListLength routine. This macro is not implemented.

Headers

Declared in hidpi.h. Include hidpi.h.

See Also

HidP_GetUsageListLength


HidP_GetButtonsEx

The HidP_GetButtonsEx macro is an mnemonic alias for the HidP_GetUsagesEx routine.

NTSTATUS
  HidP_GetButtonsEx(
    IN HIDP_REPORT_TYPE  ReportType,
    IN USHORT  LinkCollection,
    OUT PUSAGE_AND_PAGE  ButtonList,
    IN OUT ULONG  *UsageLength,
    IN PHIDP_PREPARSED_DATA  PreparsedData,
    IN PCHAR  Report,
    IN ULONG  ReportLength
    );

Headers

Declared in hidpi.h. Include hidpi.h.

See Also

HidP_GetCaps, HidP_GetUsagesEx, HidP_MaxUsageListLength, USAGE_AND_PAGE


HidP_GetCaps

The HidP_GetCaps routine returns a top-level collection's HIDP_CAPS structure.

NTSTATUS
  HidP_GetCaps(
    IN PHIDP_PREPARSED_DATA  PreparsedData,
    OUT PHIDP_CAPS  Capabilities
    );

Parameters

PreparsedData
Pointer to a top-level collection's preparsed data.
Capabilities
Pointer to a caller-allocated buffer that the routine uses to return a collection's HIDP_CAPS structure.

Return Value

HidP_GetCaps returns one of the following status values.

Status Value | Description
HIDP_STATUS_ SUCCESS | The routine successfully returned the collection capability information.
HIDP_STATUS_ INVALID_PREPARSED_DATA | The specified preparsed data is invalid.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

HidD_GetPreparsedData runs at IRQL = PASSIVE_LEVEL.

For more information about a collection's capability, see:

Button Capability Arrays

Value Capability Arrays

Link Collections

Initializing and Connecting a HID Client

See Also

HidD_GetPreparsedData, HIDP_CAPS, IOCTL_HID_GET_COLLECTION_DESCRIPTOR, IOCTL_HID_GET_COLLECTION_INFORMATION


HidP_GetData

The HidP_GetData routine returns, for a specified report, an array of HIDP_DATA structures that identify the data indices of all HID control buttons that are currently set to ON (one), and the data indices and data associated with all HID control values.

NTSTATUS
  HidP_GetData(
    IN HIDP_REPORT_TYPE  ReportType,
    OUT PHIDP_DATA  DataList,
    IN OUT PULONG  DataLength,
    IN PHIDP_PREPARSED_DATA  PreparsedData,
    IN PCHAR  Report,
    IN ULONG  ReportLength
    );

Parameters

ReportType
Specifies a HIDP_REPORT_TYPE enumerator value that indicates the type of HID report located at Report.
DataList
Specifies a caller-allocated array of HIDP_DATA structures that the routine uses to return information about all the buttons that are currently set to ON and the data associated with values.
DataLength
Specifies, on input, the number of structures that the caller-allocated DataList array holds. Specifies, on output, the number of controls for which the routine can return data, which includes all buttons that are currently set to ON and all control values.
PreparsedData
Pointer to the preparsed data of the top-level collection associated with the HID report located at Report.
Report
Pointer to a HID report.
ReportLength
Specifies the size, in bytes, of the HID report located at Report, which must be equal to the report length for the specified report type returned by HidP_GetCaps in the collection's HIDP_CAPS structure.

Return Value

HidP_GetData returns one of the following status values.

Value | Description
HIDP_STATUS_ SUCCESS | All the control data was successfully returned.
HIDP_STATUS_ INVALID_REPORT_TYPE | The report type specified by ReportType is not valid
HIDP_STATUS_ INVALID_PREPARSED_DATA | The preparsed data specified by PreparsedData is not valid
HIDP_STATUS_ INVALID_REPORT_LENGTH | The size, in bytes, of the HID report is not equal to the length specified in the collection's HIDP_CAPS structure for the specified report type.
HIDP_STATUS_ REPORT_DOES_NOT_EXIST | The top-level collection does not have a report of the specified type.
HIDP_STATUS_ BUFFER_TOO_SMALL | The Datalist array is too small to describe all the buttons, currently set to ON, and all the values in the HID report.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

Clients can call HidP_MaxDataListLength to determine the maximum possible number of HIDP_DATA structures that HidP_GetData can return.

HidP_GetData does not return data for usage value arrays.

HidP_GetData runs at IRQL <= DISPATCH_LEVEL.

See Also

HIDP_DATA, HidP_MaxDataListLength, HidP_SetData


HidP_GetExtendedAttributes

The HidP_GetExtendedAttributes routine returns the extended attributes of a HID control.

NTSTATUS __stdcall
  HidP_GetExtendedAttributes(
    IN HIDP_REPORT_TYPE  ReportType,
    IN USHORT  DataIndex,
    IN PHIDP_PREPARSED_DATA  PreparsedData,
    OUT PHIDP_EXTENDED_ATTRIBUTES  Attributes,
    IN OUT PULONG  LengthAttributes
    );

Parameters

ReportType
Specifies a HIDP_REPORT_TYPE enumerator value that indicates the type of HID report associated with the HID control specified by DataIndex.
DataIndex
Specifies the data index of the HID control.
PreparsedData
Specifies the preparsed data for the top-level collection that contains the specified control.
Attributes
Pointer to a caller-allocated buffer that the routine uses to return the extended attributes of the control specified by DataIndex.
LengthAttributes
Specifies the size, in bytes, of the Attributes buffer (which must be greater than or equal to sizeof(HIDP_EXTENDED_ATTRIBUTES).

Return Value

HidP_GetExtendedAttributes returns one of the following status values:

Value | Description
HIDP_STATUS_ SUCCESS | The routine successfully returned all the control's extended attribute information.
HIDP_STATUS_ BUFFER_TOO_SMALL | The Attribute buffer was not large enough to hold all the extended attribute information.
HIDP_STATUS_ DATA_INDEX_NOT_FOUND | The specified data index is not valid.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

HidP_GetExtendedAttributes returns a variable length HIDP_EXTENDED_ATTRIBUTES structure in the Attribute buffer. The extended attributes structure contains, in consecutive order, the fixed length members (NumGlobalUnknowns, Reserved, and GlobalUnknowns) followed by a variable length array of HIDP_UNKNOWN_TOKEN structures. The first member of the unknown token array is located at (PHID_UNKNOWN_TOKEN*)&(Attributes->Data).

The routine returns as many bytes of the extended attribute information as the Attribute buffer can hold. If the buffer is too small, the routine truncates the information it returns. To deterrmine the number of unknown tokens in the variable length array, a caller can first use the Attributes buffer to return the value of the NumGlobalUnknowns member of the extended attributes information.

HidP_GetExtendedAttributes runs at IRQL <= DISPATCH_LEVEL.

See Also

HIDP_EXTENDED_ATTRIBUTES, HIDP_UNKNOWN_TOKEN


HidP_GetLinkCollectionNodes

The HidP_GetLinkCollectionNodes routine returns a top-level collection's link collection array.

NTSTATUS
  HidP_GetLinkCollectionNodes(
    OUT PHIDP_LINK_COLLECTION_NODE  LinkCollectionNodes,
    IN OUT PULONG  LinkCollectionNodesLength,
    IN PHIDP_PREPARSED_DATA  PreparsedData
    );

Parameters

LinkCollectionNodes
Pointer to a caller-allocated array of HIDP_LINK_COLLECTION_NODE structures in which HidP_GetLinkCollectionNodes returns a top-level collection's link collection array.
LinkCollectionNodesLength
Specifies, on input, the length, in array elements, of the LinkCollectionNodes buffer. On output, the routine sets LinkCollectionNodesLength to the number of entries in the array that it set.
PreparsedData
Pointer to the preparsed data of the top-level collection for which this routine returns a link collection array.

Return Value

HidP_GetLinkCollectionNodes returns one of the following status codes.

Status Value Description
HIDP_STATUS_
SUCCESS
 The routine successfully returned the specified collection's link collection array.
HIDP_STATUS_
BUFFER_TOO_SMALL
 The LinkCollectionNodes buffer is too small to hold the entire link collection array.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

The required length of the LinkCollectionNodes buffer is specified by the NumberLinkCollectionNodes member of a collection's HIDP_CAPS structure.

If HidP_GetLinkCollectionNodes returns the status value HIDP_STATUS_BUFFER_TOO_SMALL, it also sets LinkCollectionNodesLength to the length, in array elements, required to hold the link collection nodes information.

HidP_GetLinkCollectionNodes runs at IRQL <= DISPATCH_LEVEL.

See Also

HidP_GetCaps, HIDP_CAPS, HIDP_LINK_COLLECTION_NODE


HidP_GetScaledUsageValue

The HidP_GetScaledUsageValue routine returns the signed and scaled result of a HID control value extracted from a HID report.

NTSTATUS
  HidP_GetScaledUsageValue(
    IN HIDP_REPORT_TYPE  ReportType,
    IN USAGE  UsagePage,
    IN USHORT  LinkCollection  OPTIONAL,
    IN USAGE  Usage,
    OUT PLONG  UsageValue,
    IN PHIDP_PREPARSED_DATA  PreparsedData,
    IN PCHAR  Report,
    IN ULONG  ReportLength
    );

Parameters

ReportType
Specifies a HIDP_REPORT_TYPE enumerator value that identifies the type of HID report that contains the HID usage value.
UsagePage
Specifies the usage page of the value to extract.
LinkCollection
Specifies the link collection identifier of the value to extract. A LinkCollection value of zero identifies the top-level collection.
Usage
Specifies the usage of the value to extract.
UsageValue
Pointer to the buffer in which the routine returns the signed and scaled value.
PreparsedData
Pointer to the preparsed data of the top-level collection that generated the report located at Report.
Report
Pointer to the report that contains the usage.
ReportLength
Specifies the length, in bytes, of the report located at Report.

Return Value

HidP_GetScaledUsageValue returns one of the following status values.

Status Value | Description
HIDP_STATUS_ SUCCESS | The routine successfully returned the value.
HIDP_STATUS_ INVALID_REPORT_TYPE | The specified report type is not valid.
HIDP_STATUS_ INVALID_REPORT_LENGTH | The specified report length is not valid
HIDP_STATUS_ BAD_LOG_PHY_VALUES | The device returned an illegal logical or physical value. To extract the value returned by the device, call HidP_GetUsageValue.
HIDP_STATUS_ NULL | The current state of the scaled value from the device is less than the logical minimum or is greater than the logical maximum, and the scaled value has a NULL state.
HIDP_STATUS_ VALUE_OUT_OF_RANGE | The current state of the scaled value data from the device is less than the logical minimum or is greater than the logical maximum.
HIDP_STATUS_ USAGE_NOT_FOUND | The specified usage, usage page, or link collection can not be found in any report supported by the specified top-level collection.
HIDP_STATUS_ INCOMPATIBLE_REPORT_ID | The specified value is not contained in the specified report, but is contained in another report supported by the specified top-level collection.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

The caller-allocated buffers supplied at PreparsedData, UsageValue, and Report must be allocated from non-paged pool.

Clients must use HidP_GetUsageValueArray to extract data for a usage value array.

If the routine returns status HIDP_STATUS_BAD_LOG_PHY_VALUES, a client can call HidP_GetUsageValue to extract the raw usage data.

HidP_GetScaledUsageValue runs at IRQL <= DISPATCH_LEVEL.

See Also

HidP_GetUsageValue, HidP_GetUsageValueArray


HidP_GetSpecificButtonCaps

The HidP_GetSpecificButtonCaps routine returns a button capability array that describes all HID control buttons in a top level collection that meet a specified selection criteria.

NTSTATUS
  HidP_GetSpecificButtonCaps(
    IN HIDP_REPORT_TYPE  ReportType,
    IN USAGE  UsagePage,
    IN USHORT  LinkCollection,
    IN USAGE  Usage,
    OUT PHIDP_BUTTON_CAPS  ButtonCaps,
    IN OUT PULONG  ButtonCapsLength,
    IN PHIDP_PREPARSED_DATA  PreparsedData
    );

Parameters

ReportType
Specifies a HIDP_REPORT_TYPE enumerator value that identifies the report type.
UsagePage
Specifies a usage page as a search criteria. If UsagePage is nonzero, only buttons that specify this usage page are returned.
LinkCollection
Specifies a link collection as a search criteria. If LinkCollection is nonzero, only buttons that are part of this link collection are returned.
Usage
Specifies a HID usage as a search criteria. If Usage is nonzero, only buttons that specify this usage will be returned.
ButtonCaps
Pointer to a caller-allocated buffer in which the routine returns a button capability array for the specified report type.
ButtonCapsLength
Specifies the length on input, in array elements, of the buffer provided at ButtonCaps. On output, this parameter is set to the number of elements that the routine actually returned.
PreparsedData
Pointer to a top-level collection's Preparsed Data.

Return Value

HidP_GetSpecificButtonCaps returns one of the following status values.

Status Value | Description
HIDP_STATUS_ SUCCESS | The routine successfully returned the capability data.
HIDP_STATUS_ INVALID_PREPARSED_DATA | The preparsed data is not valid.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

The required size of the ButtonCaps array is specified by the Number Xxx ButtonCaps members of a top-level collection's HIDP_CAPS structure.

When calling HidP_GetSpecificButtonCaps, specifying zero for UsagePage, Usage, and LinkCollection is equivalent to calling HidP_GetButtonCaps.

HidP_GetSpecificButtonCaps runs at IRQL = PASSIVE_LEVEL.

For more information about a collection's capability, see:

Collection Capability

Button Capability Arrays

Value Capability Arrays

Link Collections

Initializing and Connecting a HID Client

See Also

HidP_GetButtonCaps, HidP_GetCaps, HIDP_BUTTON_CAPS


HidP_GetSpecificValueCaps

The HidP_GetSpecificValueCaps routine returns a value capability array that describes all HID control values that meet a specified selection criteria.

NTSTATUS
  HidP_GetSpecificValueCaps(
    IN HIDP_REPORT_TYPE  ReportType,
    IN USAGE  UsagePage,
    IN USHORT  LinkCollection,
    IN USAGE  Usage,
    OUT PHIDP_VALUE_CAPS  ValueCaps,
    IN OUT PULONG  ValueCapsLength,
    IN PHIDP_PREPARSED_DATA  PreparsedData
    );

Parameters

ReportType
Specifies a HIDP_REPORT_TYPE enumerator value that identifies the report type.
UsagePage
Specifies a usage page as a search criteria. If UsagePage is nonzero, only values that specify this usage page are returned.
LinkCollection
Specifies a link collection as a search criteria. If LinkCollection is nonzero, only values that are part of this link collection are returned.
Usage
Specifies a HID usage as a search criteria. If Usage is nonzero, only values that specify this usage will be returned.
ValueCaps
Pointer to a caller-allocated buffer in which the routine returns a value capability array for the specified report type.
ValueCapsLength
Specifies the length on input, in array elements, of the buffer provided at ValueCaps. On output, this parameter is set to the number of elements that routine actually returns.
PreparsedData
Pointer to a top-level collection's Preparsed Data.

Return Value

HidP_GetSpecificValueCaps returns one of the following status values.

Status Value | Description
HIDP_STATUS_ SUCCESS | The routine successfully returned the capability data.
HIDP_STATUS_ INVALID_PREPARSED_DATA | The preparsed data is not valid.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

The required size of the ValueCaps buffer is specified by the Number Xxx ValueCaps members of a top-level collection's HIDP_CAPS structure.

When calling HidP_GetSpecificValueCaps, specifying zero for UsagePage, Usage, and LinkCollection is equivalent to calling HidP_GetValueCaps.

HidP_GetSpecificValueCaps runs at IRQL = PASSIVE_LEVEL.

For more information about a collection's capability, see:

Collection Capability

Button Capability Arrays

Value Capability Arrays

Link Collections

Initializing and Connecting a HID Client

See Also

HIDP_CAPS, HidP_GetCaps, HidP_GetValueCaps, HIDP_VALUE_CAPS


HidP_GetUsages

The HidP_Usages routine returns a list of all the HID control button usages that are on a specified usage page and are set to ON in a HID report.

NTSTATUS
  HidP_GetUsages(
    IN HIDP_REPORT_TYPE  ReportType,
    IN USAGE  UsagePage,
    IN USHORT  LinkCollection  OPTIONAL,
    OUT USAGE  *UsageList,
    IN OUT ULONG  *UsageLength,
    IN PHIDP_PREPARSED_DATA  PreparsedData,
    IN PCHAR  Report,
    IN ULONG  ReportLength
    );

Parameters

ReportType
Specifies a HIDP_REPORT_TYPE enumerator value that identifies the report type.
UsagePage
Specifies the usage page of the button usages. The routine only returns information about buttons on this usage page
LinkCollection
Specifies the link collection of the button usages. If LinkCollection is nonzero, the routine only returns information about the buttons that this link collection contains; otherwise, if LinkCollection is zero, the routine returns information about all the buttons in the top-level collection associated with PreparsedData.
UsageList
Pointer to a caller-allocated buffer that the routine uses to return the usages of all buttons that are set to ON and belong to the usage page specified by UsagePage.
UsageLength
Specifies, on input, the length, in array elements, of the UsageList buffer. Specifies, on output, the number of buttons that are set to ON on the specified usage page.
PreparsedData
Pointer to a top-level collection's preparsed data.
Report
Pointer to a report.
ReportLength
Specifies the length, in bytes, of the report located at Report.

Return Value

HidP_GetButtons returns one of the following status values.

Status Value | Description
HIDP_STATUS_ SUCCESS | The routine successfully returned all button usages set to ON.
HIDP_INVALID_ REPORT_LENGTH | The report length is not valid.
HIDP_INVALID_ REPORT_TYPE | The specified report type is not valid.
HIDP_STATUS_ BUFFER_TOO_SMALL | The UsageList buffer is too small to hold all the usages that are currently set to ON on the specified usage page.
HIDP_STATUS_ INCOMPATIBLE_REPORT_ID | The collection contains buttons on the specified usage page in a report of the specified type, but there are no such usages in the specified report.
HIDP_STATUS_ INVALID_PREPARSED_DATA | The preparsed data is not valid.
HIDP_STATUS_ USAGE_NOT_FOUND | The collection does not contain any buttons on the specified usage page in any report of the specified report type.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

Clients can call HidP_MaxUsageListLength to determine the maximum number of buttons that can be returned for specified report type. Alternatively, clients can call HidP_GetButtons and set UsageList to zero to return the required length in UsageLength.

Clients can determine the required report length from the Xxx ReportByteLength members in a top-level collection's HIDP_CAPS structure.

HidP_GetUsages runs at IRQL <= DISPATCH_LEVEL.

See Also

HidP_GetButtons, HidP_GetButtonsEx, HidP_GetCaps, HidP_GetScaledUsageValue, HidP_GetUsagesEx, HidP_GetUsageValue, HidP_GetUsageValueArray, HidP_MaxUsageListLength


HidP_GetUsagesEx

The HidP_GetUsagesEx routine returns a list of the all the HID control button usages that are set to ON in a HID report.

NTSTATUS
  HidP_GetUsagesEx(
    IN HIDP_REPORT_TYPE  ReportType,
    IN USHORT  LinkCollection,
    OUT PUSAGE_AND_PAGE  ButtonList,
    IN OUT ULONG  *UsageLength,
    IN PHIDP_PREPARSED_DATA  PreparsedData,
    IN PCHAR  Report,
    IN ULONG  ReportLength
    );

Parameters

ReportType
Specifies a HIDP_REPORT_TYPE enumerator value that identifies the report type.
LinkCollection
Specifies the link collection of the button usages. If LinkCollection is nonzero, the routine only returns information about the buttons that this link collection contains; otherwise, if LinkCollection is zero, the routine returns information about all the buttons in the top-level collection associated with PreparsedData.
ButtonList
Pointer to a caller-allocated buffer that routine uses to return the usage and usage page identifiers for each button that is set to ON (one).
UsageLength
Specifies, on input, the length, in array elements, of the ButtonList buffer. Specifies, on output, the number usages that are currently set to ON in the specified report.
PreparsedData
Pointer to a top-level collection's preparsed data.
Report
Pointer to a report that contains button data.
ReportLength
Specifies the length, in bytes, of the report located at Report.

Return Value

HidP_GetButtonsEx returns one of the following status values.

Status Value | Description
HIDP_STATUS_ SUCCESS | The routine successfully returned all button usages set to ON.
HIDP_INVALID_ REPORT_LENGTH | The report length is not valid.
HIDP_INVALID_ REPORT_TYPE | The specified report type is not valid.
HIDP_STATUS_ BUFFER_TOO_SMALL | The UsageList buffer is too small to hold all the usages currently set to ON in the specified report.
HIDP_STATUS_ INCOMPATIBLE_REPORT_ID | The collection contains buttons in a report of the specified type, but there are no such usages in the specified report.
HIDP_STATUS_ INVALID_PREPARSED_DATA | The preparsed data is not valid.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

Clients can call HidP_MaxUsageListLength to determine the maximum number of buttons that be returned for specified report type. Alternatively, clients can call HidP_GetUsagesEx and set UsageList to zero to return the required length in UsageLength.

Clients can determine the required report length from the Xxx ReportByteLength members in a top-level collection's HIDP_CAPS structure.

HidP_GetUsagesEx runs at IRQL <= DISPATCH_LEVEL.

See Also

HidP_GetButtons, HidP_GetButtonsEx, HidP_GetCaps, HidP_GetScaledUsageValue, HidP_GetUsagesEx, HidP_GetUsageValue, HidP_GetUsageValueArray, HidP_MaxUsageListLength, USAGE_AND_PAGE


HidP_GetUsageListLength

The HidP_GetUsageListLength routine is not implemented.

Headers

Declared in hidpi.h. Include hidpi.h.

See Also

HidP_GetButtonListLength


HidP_GetUsageValue

The HidP_GetUsageValue routine extracts the data associated with a HID control value that matches a selection criteria in a HID report.

NTSTATUS
  HidP_GetUsageValue(
    IN HIDP_REPORT_TYPE  ReportType,
    IN USAGE  UsagePage,
    IN USHORT  LinkCollection,
    IN USAGE  Usage,
    OUT PULONG  UsageValue,
    IN PHIDP_PREPARSED_DATA  PreparsedData,
    IN PCHAR  Report,
    IN ULONG  ReportLength
    );

Parameters

ReportType
Specifies a HIDP_REPORT_TYPE enumerator value that identifies the report type.
UsagePage
Specifies the value's usage page.
LinkCollection
Specifies the link collection that contains the value. If LinkCollection is nonzero, the routine only searches for the usage in this link collection; otherwise, if LinkCollection is zero, the routine searches for the usage in the top-level collection associated with PreparsedData.
Usage
Specifies the usage of the value.
UsageValue
Pointer to a buffer in which the routine returns the value data.
PreparsedData
Pointer to a top-level collection's preparsed data.
Report
Pointer to a report that contains values.
ReportLength
Specifies the length, in bytes, of the report located at Report.

Return Value

HidP_GetUsageValue returns one of the following status values.

Status Value | Description
HIDP_STATUS_ SUCCESS | The routine successfully returned the value data.
HIDP_INVALID_ REPORT_LENGTH | The report length is not valid.
HIDP_INVALID_ REPORT_TYPE | The specified report type is not valid.
HIDP_STATUS_ INCOMPATIBLE_REPORT_ID | The collection contains a value on the specified usage page in a report of the specified type, but there are no such usages in the specified report.
HIDP_STATUS_ INVALID_PREPARSED_DATA | The preparsed data is not valid.
HIDP_STATUS_ USAGE_NOT_FOUND | The collection does not contain a value on the specified usage page in any report of the specified report type.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

HidP_GetUsageValue does not sign or scale the value. To extract a signed value, use HidP_GetScaledUsageValue. To manually assign the sign bit, the position of the sign bit can be determined from the information in a value's HIDP_VALUE_CAPS structure.

To extract a usage value array, use HidP_GetUsageValueArray.

HidP_GetUsageValue runs at IRQL <= DISPATCH_LEVEL.

See Also

HidP_GetButtons, HidP_GetButtonsEx, HidP_GetCaps, HidP_GetScaledUsageValue, HidP_GetUsages, HidP_GetUsagesEx, HidP_GetUsageValueArray, HIDP_VALUE_CAPS


HidP_GetUsageValueArray

The HidP_GetUsageValueArray routine extracts the data associated with a HID control usage value array from a HID report.

NTSTATUS
  HidP_GetUsageValueArray(
    IN HIDP_REPORT_TYPE  ReportType,
    IN USAGE  UsagePage,
    IN USHORT  LinkCollection  OPTIONAL,
    IN USAGE  Usage,
    OUT PCHAR  UsageValue,
    IN USHORT  UsageValueByteLength,
    IN PDIP_PREPARSED_DATA  PreparsedData,
    IN PCHAR  Report,
    IN ULONG  ReportLength
    );

Parameters

ReportType
Specifies a HIDP_REPORT_TYPE enumerator value that identifies the report type.
UsagePage
Specifies the usage page of the usage value array.
LinkCollection
Specifies the link collection that contains the usage value array. If LinkCollection is nonzero, the routine only searches for a usage value array in this link collection; otherwise, if LinkCollection is zero, the routine searches for a usage value array in the top-level collection associated with PreparsedData.
Usage
Specifies the usage of the usage value array.
UsageValue
Pointer to a caller-allocated buffer in which the routine returns the data associated with the usage value array.
UsageValueByteLength
Specifies the length, in bytes, of the buffer at UsageValue.
PreparsedData
Pointer to a top-level collection's preparsed data.
Report
Pointer to a report that contains values.
ReportLength
Specifies the length, in bytes, of the report located at Report.

ReturnValue

HidP_GetUsageValueArray returns one of the following status values.

Status Value | Description
HIDP_STATUS_ SUCCESS | The routine successfully returned the value's data.
HIDP_INVALID_ REPORT_LENGTH | The report length is not valid.
HIDP_INVALID_ REPORT_TYPE | The specified report type is not valid.
HIDP_STATUS_ NOT_VALUE_ARRAY | The requested usage is not a usage value array.
HIDP_STATUS_ BUFFER_TOO_SMALL | The UsageValue buffer is too small to hold the requested usage.
HIDP_STATUS_ INCOMPATIBLE_REPORT_ID | The collection contains a usage value array on the specified usage page in a report of the specified type, but there are no such usages in the specified report.
HIDP_STATUS_ INVALID_PREPARSED_DATA | The preparsed data is not valid.
HIDP_STATUS_ USAGE_NOT_FOUND | The collection does not contain a usage value array on the specified usage page in any report of the specified report type.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

The required size, in bytes, of UsageValueByteLength is determined by multiplying together the BitSize and ReportCount members of the usage value array's HIDP_VALUE_CAPS structure, and rounding the result up to the nearest byte.

HidP_GetUsageValueArray sets the UsageValue buffer in little-endian order, beginning with the least significant bit of the usage's data. The data is not byte-aligned, and is shifted such that the least significant bit of the data is located at the first bit of the UsageValue buffer.

HidP_GetUsageValueArray runs at IRQL <= DISPATCH_LEVEL.

See Also

HidP_GetButtons, HidP_GetButtonsEx, HidP_GetCaps, HidP_GetScaledUsageValue, HidP_GetUsages, HidP_GetUsagesEx, HidP_GetUsageValue, HIDP_VALUE_CAPS


HidP_GetValueCaps

The HidP_GetButtonCaps routine returns a value capability array that describes all the HID control values in a top level collection for a specified type of HID report.

NTSTATUS
  HidP_GetValueCaps(
    IN HIDP_REPORT_TYPE  ReportType,
    OUT PHIDP_VALUE_CAPS  ValueCaps,
    IN OUT PULONG  ValueCapsLength,
    IN PHIDP_PREPARSED_DATA  PreparsedData
    );

Parameters

ReportType
Specifies a HIDP_REPORT_TYPE enumerator value that identifies the report type.
ValueCaps
Pointer to a caller-allocated buffer in which the routine returns a value capability array for the specified report type.
ValueCapsLength
Specifies the length, on input, in array elements, of the ValueCaps buffer. On output, the routine sets ValueCapsLength to the number of elements that the it actually returns
PreparsedData
Pointer to a top-level collection's preparsed data.

Return Value

HidP_GetValueCaps returns one of the following status values.

Status Value | Description
HIDP_STATUS_ SUCCESS | The routine successfully returned the capability data.
HIDP_STATUS_ INVALID_PREPARSED_DATA | The preparsed data is not valid.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

The correct length for ValueCapsLength is specified by the Number Xxx ValueCaps members of a top-level collection's HIDP_CAPS structure.

HidP_GetValueCaps runs at IRQL <= DISPATCH_LEVEL.

For more information about a collection's capability, see:

Collection Capability

Button Capability Arrays

Value Capability Arrays

Link Collections

Initializing and Connecting a HID Client

See Also

HIDP_CAPS, HidP_GetCaps, HidP_GetValueCaps, HIDP_VALUE_CAPS


HidP_InitializeReportForID

The HidP_InitializeReportForID routine initializes a HID report.

NTSTATUS __stdcall
  HidP_InitializeReportForID(
    IN HIDP_REPORT_TYPE  ReportType,
    IN UCHAR  ReportID,
    IN PHIDP_PREPARSED_DATA  PreparsedData,
    IN OUT PCHAR  Report,
    IN ULONG  ReportLength
    );

Parameters

ReportType
Specifies a HIDP_REPORT_TYPE enumerator that indicates the type of HID report located at Report.
ReportID
Specifies a report ID.
PreparsedData
Pointer to the preparsed data of the top-level collection associated with the HID report located at Report.
Report
Pointer to the caller-allocated buffer containing the HID report that HidP_InitializeReportForID initializes.
ReportLength
Specifies the size, in bytes, of the HID report located at Report. ReportLength must be equal to the collection's report length for the specified report type, as specified by the Xxx ReportByteLength members of a collection's HIDP_CAPS structure.

Return Value

HidP_InitializeReportForID returns one of the following status values:

Value | Description
HIDP_STATUS_ SUCCESS | The report was successfully initialized.
HIDP_STATUS_ INVALID_PREPARSED_DATA | The preparsed data is not valid.
HIDP_STATUS_ INVALID_REPORT_LENGTH | The specified length of the report is not equal to the collection's report length for the specified report type.
HIDP_STATUS_ INVALID_REPORT_TYPE | The report type is not valid.
HIDP_STATUS_ REPORT_DOES_NOT_EXIST | The specified report ID is not valid.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

Initializing a HID report sets all control data to zero or a control's null value, as defined by the USB HID Standard. (Sending or receiving a null value indicates that the current value of a control should not be modified.)

HidP_InitializeReportForID does the following:

  • Sets to zero the bit fields of all buttons and values without null values
  • Sets the bit field of all controls with null values to their corresponding null value.

HidP_InitializeReportForID runs at IRQL <= DISPATCH_LEVEL.

See Also

HIDP_CAPS, HidP_GetCaps, HIDP_REPORT_TYPE


HidP_IsSameUsageAndPage

The HidP_IsSameUsageAndPage macro determines if two extended usages, represented by USAGE_AND_PAGE structures, are equal.

BOOLEAN
  HidP_IsSameUsageAndPage(
    USAGE_AND_PAGE  u1,
    USAGE_AND_PAGE  u2
    );

Parameters

u1
Specifies an extended usage.
u2
Specifies an extended usage.

Return Value

Value | Description
TRUE | Usage u1 is the same as usage u2.
FALSE | Usage u1 is different than usage u2.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

As defined by the USB HID Standard, an extended usage is a 32-bit unsigned value. The high-order 16 bits specify the usage page, and lower-order 16 bits specify the usage ID.

See Also

Built on Wednesday, July 11, 2001


HidP_MaxDataListLength

The HidP_MaxDataListLength routine returns the maximum number of HIDP_DATA structures that HidP_GetData can return for a specified type of HID report and a specified top-level collection.

ULONG __stdcall
  HidP_MaxDataListLength(
    IN HIDP_REPORT_TYPE  ReportType,
    IN PHIDP_PREPARSED_DATA  PreparsedData
    );

Parameters

ReportType
Specifies a HIDP_REPORT_TYPE enumerator value that indicates the report type.
PreparsedData
Pointer to a top-level collection's preparsed data.

Return Value

If successful, HidP_MaxDataListLength returns the maximum number of HIDP_DATA structures that HidP_GetData might return for a specified type of HID report and a specified top-level collection. Otherwise, the routine returns zero, which indicates that either the report type or the preparsed data is not valid.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

Clients can call HidP_MaxDataListLength to determine the maximum number of HIDP_DATA structures that HidP_GetData can return.

HidP_MaxDataListLength runs at IRQL <= DISPATCH_LEVEL.

See Also

HIDP_DATA, HidP_GetData, HidP_SetData


HidP_MaxUsageListLength

The HidP_MaxUsageListLength routine returns the maximum number of HID usages that HidP_GetUsages can return for a specified type of HID report and a specified top level collection.

ULONG
  HidP_MaxUsageListLength(
    IN HIDP_REPORT_TYPE  ReportType,
    IN USAGE  UsagePage  OPTIONAL,
    IN PHIDP_PREPARSED_DATA  PreparsedData
    );

Parameters

ReportType
Specifies a HIDP_REPORT_TYPE enumerator value that indicates the report type.
UsagePage
Specifies a usage page as a search criteria. If UsagePage is zero, the routine returns the number of all the buttons in the collection.
PreparsedData
Pointer to a top-level collection's preparsed data.

Return Value

If successful, HidP_MaxUsageListLength returns the maximum number of HID usages that HidP_GetUsages can return for a specified type of HID report and a specified top level collection. If the specified preparsed data or report type is not valid, the routine returns zero.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

HidP_MaxUsageListLength runs at IRQL = PASSIVE_LEVEL.

See Also

HidP_GetButtons, HidP_GetUsages


HidP_SetButtons

The HidP_SetButtons macro is a mnemonic alias for the HidP_SetUsages routine.

NTSTATUS __stdcall
  HidP_SetUsages(
    IN HIDP_REPORT_TYPE  ReportType,
    IN USAGE  UsagePage,
    IN USHORT  LinkCollection, // Optional
    IN PUSAGE  UsageList,
    IN OUT PULONG  UsageLength,
    IN PHIDP_PREPARSED_DATA  PreparsedData,
    IN OUT PCHAR  Report,
    IN ULONG  ReportLength
    );

Headers

Declared in hidpi.h. Include hidpi.h.

See Also

HidP_GetButtons, HidP_GetData, HidP_GetUsages, HidP_SetData, HidP_SetUsages, HidP_UnsetButtons, HidP_UnsetUsages


HidP_SetData

The HidP_SetData routine sets a specified set of HID control button and value usages in a HID report.

NTSTATUS __stdcall
  HidP_SetData(
    IN HIDP_REPORT_TYPE  ReportType,
    IN PHIDP_DATA  DataList,
    IN OUT PULONG  DataLength,
    IN PHIDP_PREPARSED_DATA  PreparsedData,
    IN OUT PCHAR  Report,
    IN ULONG  ReportLength
    );

Parameters

ReportType
Specifies a HIDP_REPORT_TYPE enumerator value that indicates the type of HID report located at Report.
DataList
Pointer to a caller-allocated array of HIDP_DATA structures that specify which buttons and usage values to set.
DataLength
Specifies, on input, the number of members in the DataList array. See the Comments section for information about the output value.
PreparsedData
Pointer to a top-level's preparsed data.
Report
Pointer to a HID report.
ReportLength
Specifies the size, in bytes, of the HID report located at Report, which must be equal to the report length for the specified report type that HidP_GetCapsreturns in a collection's HIDP_CAPS structure.

Return Value

HidP_SetData returns HIDP_STATUS_SUCCESS if it successfully sets all the control data specified by DataList.

HidP_SetData returns one of the following status values if one of the input parameters is not valid.

Status Value | Description
HIDP_STATUS_ INVALID_PREPARSED_DATA | The preparsed data specified by PreparsedData is not valid
HIDP_STATUS_ INVALID_REPORT_LENGTH | The size, in bytes, of the HID report is not equal to the length specified in the collection's HIDP_CAPS structure for the specified report type.
HIDP_STATUS_ INVALID_REPORT_TYPE | ReportType is not valid.
HIDP_STATUS_ REPORT_DOES_NOT_EXIST | The collection does not contain a report of the specified type.

HidP_SetData returns one of the following error values if one of the specified button or usage values could not be set.

Status Value | Description
HIDP_STATUS_ BUFFER_TOO_SMALL | A button in an array was not set to ON (one) because all the array fields are already used to index other buttons.
HIDP_STATUS_ BUTTON_NOT_PRESSED | A DataList member specifies to set a button OFF (zero), but the button is already set to OFF.
HIDP_STATUS_ DATA_INDEX_NOT_FOUND | The data index of a DataList member is not valid.
HIDP_STATUS_ INCOMPATIBLE_REPORT_ID | A button or usage value is contained in a report, but it is not in the specified report.
HIDP_STATUS_ IS_VALUE_ARRAY | A data index specifies a usage value array.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

Except for usage value arrays, a client can use HidP_SetData to set buttons and usage values in a report. To set a usage value array, a client must use HidP_SetUsageValueArray.

HidP_SetData sets the output value of DataLength as follows.

Condition | DataLength Value
ReportType, PreparsedData, Report, or ReportLength are not valid. | The input value is unchanged.
All control data was successfully set. | The input value is unchanged.
A control's data could not be set. | Set to the index of the DataList member that caused the error.

See Also

HIDP_DATA, HidP_GetData, HidP_SetButtons, HidP_SetUsages, HidP_SetUsageValueArray, HidP_UnsetButtons, HidP_UnsetUsages


HidP_SetScaledUsageValue

The HidP_SetScaledUsageValue routine converts a signed and scaled physical number to a HID usage's logical value, and sets the usage value in a specified HID report.

NTSTATUS
  HidP_SetScaledUsageValue(
    IN HIDP_REPORT_TYPE  ReportType,
    IN USAGE  UsagePage,
    IN USHORT  LinkCollection  OPTIONAL,
    IN USAGE  Usage,
    IN LONG  UsageValue,
    IN PHIDP_PREPARSED_DATA  PreparsedData,
    IN OUT PCHAR  Report,
    IN ULONG  ReportLength
    );

Parameters

ReportType
Specifies a HIDP_REPORT_TYPE enumerator value that indicates the type of HID report located at Report.
UsagePage
Specifies the usage page of a usage.
LinkCollection
Specifies the link collection that contains the usage. If LinkCollection is nonzero, the routine only sets the usage, if one exists, in this link collection. If LinkCollection is zero, the routine sets the first usage it finds in the top-level collection associated with PreparsedData.
Usage
Specifies the usage.
UsageValue
Specifies the signed and scaled physical number, which the routine converts to the usage's logical value.
PreparsedData
Pointer to a top-level's preparsed data.
Report
Pointer to a HID report.
ReportLength
Specifies the size, in bytes, of the HID report located at Report, which must be equal to the report length for the specified report type that HidP_GetCapsreturns in a collection's HIDP_CAPS structure.

Return Value

HidP_SetScaledUsageValue returns one of the following status values.

Status Value | Description
HIDP_STATUS_ SUCCESS | The routine successfully set the usage value.
HIDP_STATUS_ BAD_LOG_PHY_VALUES | The usage has an illegal logical or physical range that prevents scaling.
HIDP_STATUS_ VALUE_OUT_OF_RANGE | The specified physical value is out-of-range and the usage does not have null value.
HIDP_STATUS_ INVALID_REPORT_LENGTH | The report length is not valid.
HIDP_STATUS_ INVALID_REPORT_TYPE | The specified report type is not valid.
HIDP_STATUS_ INCOMPATIBLE_REPORT_ID | The usage does not exist in the specified report, but it does exist in a different report of the specified type.
HIDP_STATUS_ INVALID_PREPARSED_DATA | The preparsed data is not valid.
HIDP_STATUS_ USAGE_NOT_FOUND | The usage does not exist in any report of the specified report type.
HIDP_STATUS_NULL | The specified physical value is out-of-range, the usage has a null value, and the routine set the null value.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

HidP_SetScaledUsageValue sets the sign bit.

If the routine returns HIDP_STATUS_INCOMPATIBLE_REPORT_ID, the specified report does contain the usage. However, a client can set the usage in a zero-initialized report. See Initializing a Report Buffer.

HidP_SetScaledUsageValue runs at IRQL <= DISPATCH_LEVEL.

See Also

HidP_SetUsageValue, HidP_SetUsageValueArray


HidP_SetUsages

The HidP_SetUsages routine sets specified HID control buttons ON (one) in a HID report.

NTSTATUS __stdcall
  HidP_SetUsages(
    IN HIDP_REPORT_TYPE  ReportType,
    IN USAGE  UsagePage,
    IN USHORT  LinkCollection, // Optional
    IN PUSAGE  UsageList,
    IN OUT PULONG  UsageLength,
    IN PHIDP_PREPARSED_DATA  PreparsedData,
    IN OUT PCHAR  Report,
    IN ULONG  ReportLength
    );

Parameters

ReportType
Specifies a HIDP_REPORT_TYPE enumerator value that indicates the type of report located at Report.
UsagePage
Specifies the usage page for the usages specified by UsageList.
LinkCollection
Specifies the link collection that contains the usages. If LinkCollection is nonzero, the routine only sets the usages, if they exist, in this link collection. If LinkCollection is zero, the routine sets the first usage for each specified usage in the top-level collection associated with PreparsedData.
UsageList
Pointer to the array of usages.
UsageLength
Specifies, on input, the number of usages in UsageList. See the Comments section for information about the output value.
PreparsedData
Pointer to the preparsed data of the top-level collection associated with the report located at Report.
Report
Pointer to a report.
ReportLength
Specifies the size, in bytes, of the report located at Report, which must be equal to the report length for the specified report type that HidP_GetCaps returns in a collection's HIDP_CAPS structure.

Return Value

HidP_SetUsages returns one of the following status values.

Status Value | Description
HIDP_STATUS_ SUCCESS | The routine successfully set the usage value.
HIDP_STATUS_ BUFFER_TOO_SMALL | A usage in a button array can not be set because the array is already fully set.
HIDP_STATUS_ INVALID_REPORT_LENGTH | The report length is not valid.
HIDP_STATUS_ INVALID_REPORT_TYPE | The specified report type is not valid.
HIDP_STATUS_ INCOMPATIBLE_REPORT_ID | A usage does not exist in the specified report, but it does exist in a different report of the specified type.
HIDP_STATUS_ INVALID_PREPARSED_DATA | The preparsed data is not valid.
HIDP_STATUS_ USAGE_NOT_FOUND | A usage does not exist in any report of the specified report type.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

If HidP_SetUsages cannot set a usage in UsageList, the routine sets UsageLength to the index of the usage that could not be set, and returns a status value that indicates the error.

HidP_SetUsages runs at IRQL <= DISPATCH_LEVEL.

See Also

HidP_GetButtons, HidP_GetUsages, HidP_SetButtons, HidP_UnsetButtons, HidP_UnsetUsages


HidP_SetUsageValue

The HidP_SetUsageValue routine sets a HID control value in a specified HID report.

NTSTATUS
  HidP_SetUsageValue(
    IN HIDP_REPORT_TYPE  ReportType,
    IN USAGE  UsagePage,
    IN USHORT  LinkCollection,
    IN USAGE  Usage,
    IN ULONG  UsageValue,
    IN PHIDP_PREPARSED_DATA  PreparsedData,
    IN OUT PCHAR  Report,
    IN ULONG  ReportLength
    );

Parameters

ReportType
Specifies a HIDP_REPORT_TYPE enumerator value that indicates the type of HID report located at Report.
UsagePage
Specifies the usage page of a usage.
LinkCollection
Specifies the link collection that contains the usage. If LinkCollection is nonzero, the routine only sets the usage, if one exists, in this link collection. If LinkCollection is zero, the routine sets the first usage it finds in the top-level collection associated with PreparsedData.
Usage
Specifies the usage.
UsageValue
Specifies the usage value.
PreparsedData
Pointer to a top-level's preparsed data.
Report
Pointer to a HID report.
ReportLength
Specifies the size, in bytes, of the HID report located at Report, which must be equal to the report length for the specified report type that HidP_GetCaps returns in a collection's HIDP_CAPS structure.

Return Value

HidP_SetUsageValue returns one of the following status values.

Status Value | Description
HIDP_STATUS_ SUCCESS | The routine successfully set the usage value.
HIDP_STATUS_ INCOMPATIBLE_REPORT_ID | The usage does not exist in the specified report, but it does exist in a different report of the specified type.
HIDP_STATUS_ INVALID_PREPARSED_DATA | The preparsed data is not valid.
HIDP_STATUS_ REPORT_DOES_NOT_EXIST | There are no reports of the specified type.
HIDP_STATUS_ USAGE_NOT_FOUND | The usage does not exist in any report of the specified report type.
HIDP_STATUS_ INVALID_REPORT_LENGTH | The report length is not valid.
HIDP_STATUS_ INVALID_REPORT_TYPE | The specified report type is not valid.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

HidP_SetUsageValue routine does not sign the value. A client must either sign the value, at the position provided in the HIDP_VALUE_CAPS structure for this value, or call HidP_SetScaledUsageValue.

HidP_SetUsageValue runs at IRQL <= DISPATCH_LEVEL.

See Also

HidP_SetScaledUsageValue, HIDP_VALUE_CAPS


HidP_SetUsageValueArray

The HidP_SetUsageValueArray routine sets a HID control usage value array in a specified HID report.

NTSTATUS
  HidP_SetUsageValueArray(
    IN HIDP_REPORT_TYPE  ReportType,
    IN USAGE  UsagePage,
    IN USHORT  LinkCollection  OPTIONAL,
    IN USAGE  Usage,
    IN PCHAR  UsageValue,
    IN USHORT  UsageValueByteLength,
    IN PHIDP_PREPARSED_DATA  PreparsedData,
    OUT PCHAR  Report,
    IN ULONG  ReportLength
    );

Parameters

ReportType
Specifies a HIDP_REPORT_TYPE enumerator value that indicates the type of HID report located at Report.
UsagePage
Specifies the usage page of a usage.
LinkCollection
Specifies the link collection that contains the usage. If LinkCollection is nonzero, the routine only sets the usage, if one exists, in this link collection. If LinkCollection is zero, the routine sets the first usage it finds in the top-level collection associated with PreparsedData.
Usage
Specifies the usage.
UsageValue
Pointer to a caller-allocated buffer that contains the data associated with the usage value array.
UsageValueByteLength
Specifies the length, in bytes, of the UsageValue buffer.
PreparsedData
Pointer to a top-level's preparsed data.
Report
Pointer to a HID report.
ReportLength
Specifies the size, in bytes, of the HID report located at Report, which must be equal to the report length for the specified report type that HidP_GetCapsreturns in a collection's HIDP_CAPS structure.

Return Value

HidP_SetUsageValueArray returns one of the following status values.

Status Value | Description
HIDP_STATUS_ SUCCESS | The routine successfully set the usage value.
HIDP_STATUS_ INVALID_REPORT_LENGTH | The report length is not valid.
HIDP_STATUS_ INVALID_REPORT_TYPE | The specified report type is not valid.
HIDP_STATUS_ BUFFER_TOO_SMALL | The size, in bytes, of the UsageValue buffer is too small.
HIDP_STATUS_ INCOMPATIBLE_REPORT_ID | The usage does not exist in the specified report, but it does exist in a different report of the specified type.
HIDP_STATUS_ NOT_VALUE_ARRAY | The specified usage is not a usage value array.
HIDP_STATUS_ INVALID_PREPARSED_DATA | The preparsed data is not valid.
HIDP_STATUS_ REPORT_DOES_NOT_EXIST | There are no reports of the specified type.
HIDP_STATUS_ NOT_IMPLEMENTED | The report size of data fields specified for the usage value array is not a multiple of eight bits.
HIDP_STATUS_ USAGE_NOT_FOUND | The usage does not exist in any report of the specified report type.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

The required size, in bytes, of the UsageValue buffer is determined by multiplying together the BitSize and ReportCount members of the usage value array's HIDP_VALUE_CAPS structure, and rounding the result up to the nearest byte.

HidP_SetUsageValueArray only supports usage value arrays where each data field of the array is a multiple of eight bits.

The caller must set the UsageValue buffer exactly as it should occur in the report.

HidP_SetUsageValueArray runs at IRQL <= DISPATCH_LEVEL.

See Also

HidP_SetScaledUsageValue, HidP_SetUsageValue


HidP_UnsetButtons

The HidP_UnsetButtons macro is a mnemonic alias for the HidP_UnsetUsages routine.

NTSTATUS __stdcall
  HidP_UnsetUsages(
    IN HIDP_REPORT_TYPE  ReportType,
    IN USAGE  UsagePage,
    IN USHORT  LinkCollection,
    IN PUSAGE  UsageList,
    IN OUT PULONG  UsageLength,
    IN PHIDP_PREPARSED_DATA  PreparsedData,
    IN OUT PCHAR  Report,
    IN ULONG  ReportLength
    );

Headers

Declared in hidpi.h. Include hidpi.h.

See Also

HidP_UnSetUsages


HidP_UnsetUsages

The HidP_UnsetUsages routine sets specified HID control button usages OFF (zero) in a HID report.

NTSTATUS __stdcall
  HidP_UnsetUsages(
    IN HIDP_REPORT_TYPE  ReportType,
    IN USAGE  UsagePage,
    IN USHORT  LinkCollection, // OPTIONAL
    IN PUSAGE  UsageList,
    IN OUT PULONG  UsageLength,
    IN PHIDP_PREPARSED_DATA  PreparsedData,
    IN OUT PCHAR  Report,
    IN ULONG  ReportLength
    );

Parameters

ReportType
Specifies a HIDP_REPORT_TYPE enumerator value that indicates the type of report located at Report.
UsagePage
Specifies the usage page of the usages specified by UsageList.
LinkCollection
Specifies the link collection that contains the usages. If LinkCollection is nonzero, the routine only sets the usages, if they exist, in this link collection. If LinkCollection is zero, the routine sets the first usage for each usage it finds in the top-level collection associated with PreparsedData.
UsageList
Pointer to the array of usages to set to OFF.
UsageLength
Specifies, on input, the number of usages in UsageList. See the Comments section for information about the output value.
PreparsedData
Pointer to the preparsed data of the top-level collection associated with the report located at Report.
Report
Pointer to a report.
ReportLength
Specifies the size, in bytes, of the report located at Report, which must be equal to the report length for the specified report type that HidP_GetCaps returns in a collection's HIDP_CAPS structure.

Return Value

HidP_UnsetUsages returns HIDP_STATUS_SUCCESS if it successfully sets OFF all the usages in UsageList.

HidP_UnsetUsages returns one of the following status values if one of ReportType, PreparsedData, Report, or ReportLength is not valid.

Status Value | Description
HIDP_STATUS_ INVALID_PREPARSED_DATA | The preparsed data specified by PreparsedData is not valid.
HIDP_STATUS_ INVALID_REPORT_LENGTH | The report length is not valid.
HIDP_STATUS_ INVALID_REPORT_TYPE | The report type is not valid.
HIDP_STATUS_ REPORT_DOES_NOT_EXIST | The collection does not contain a report of the specified type.

HidP_UnsetUsages returns one of the following status values if it was not able to set to OFF one of the usages in UsageList.

Status Value | Description
HIDP_STATUS_ BUTTON_NOT_PRESSED | A usage is already set to OFF.
HIDP_STATUS_ INCOMPATIBLE_REPORT_ID | A usage is not contained in the specified report, but is contained in another report of the specified type.
HIDP_STATUS_ USAGE_NOT_FOUND | The routine did not find a usage in any report of the specified type.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

HidP_UnsetUsages sets UsageLength as follows.

Condition | UsageLength Value
ReportType, PreparsedData, Report, or ReportLength is not valid. | The input value is unchanged.
All usages are successfully set to OFF. | The input value is unchanged.
A usage could not be set to OFF. | Set to the index of the usage in UsageList that caused the error.

HidP_UnSetUsages runs at IRQL <= DISPATCH_LEVEL.

See Also

HidP_SetButtons, HidP_SetData, HidP_SetUsages, HidP_UnsetButtons


HidP_UsageAndPageListDifference

The HidP_UsageListDifference routine returns the differences between two arrays of HID extended usages.

NTSTATUS __stdcall
  HidP_UsageAndPageListDifference(
    IN PUSAGE_AND_PAGE  PreviousUsageList,
    IN PUSAGE_AND_PAGE  CurrentUsageList,
    OUT PUSAGE_AND_PAGE  BreakUsageList,
    OUT PUSAGE_AND_PAGE  MakeUsageList,
    IN ULONG  UsageListLength
    );

Parameters

PreviousUsageList
Pointer to a list of usages that the routine compares with the list of usages in CurrentUsageList.
CurrentUsageList
Pointer to a list of usages that the routine compares with the list of usages in PreviousUsageList.
BreakUsageList
Pointer to a caller-allocated buffer that, on return, contains a list of the usages that are in PreviousUsageList, but not in CurrentUsageList.
MakeUsageList
Pointer to a caller-allocated buffer that, on return, contains a list of the usages that are in CurrentUsageList, but not in PreviousUsageList.
UsageListLength
Specifies the length, in array elements, of the buffers provided at CurrentUsageList and PreviousUsageList.

Return Value

HidP_UsageListDifference returns HIDP_STATUS_SUCCESS.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

A client can use this routine to compare two lists of extended usages, for example, to determine the change in button state between two usage lists returned by two HidP_GetButtons.

If the input usage lists have different lengths, a client should set UsageListLength to the length of the larger list.

The routine interprets a zero usage in an input usage list as a delimiter that ends the list. Any usages after a zero in a list are not processed. Unused usages at the end of the output lists are set to zero.

HidP_UsageAndPageListDifference runs at IRQL = PASSIVE_LEVEL.

See Also

HidP_UsageListDifference


HID Structures for Clients

This section describes system-defined structures in the Microsoft Windows input architecture that HID clients use to communicate with the HID class driver.

See also:

  • HID Structures for Minidrivers, which describes system-defined structures that a HID class driver uses to communicated with a HID minidriver.
  • USB Structures, which describes system structures specific to USB drivers.

For more information about Windows support for HID, see:

Windows Input Architecture

USB HID Standard

The structures are described in alphabetical order.


HID_COLLECTION_INFORMATION

The HID_COLLECTION_INFORMATION structure contains general information about a top-level collection.

typedef struct _HID_COLLECTION_INFORMATION {
  ULONG  DescriptorSize;
  BOOLEAN  Polled;
  UCHAR  Reserved1[ 1 ];
  USHORT  VendorID;
  USHORT  ProductID;
  USHORT  VersionNumber;
} HID_COLLECTION_INFORMATION, *PHID_COLLECTION_INFORMATION;

Members

DescriptorSize
Specifies the size, in bytes, of a collection's preparsed data.
Polled
Indicates, if TRUE, that the HID class driver must poll the device to receive data. Otherwise, if Polled is FALSE, the device uses asynchronous interrupts to signal the host that the device has HID reports to send to the host.
Reserved1
Reserved for internal system use.
VendorID
Specifies a HID device's vendor ID.
ProductID
Specifies a HID device's product ID.
VersionNumber
Specifies the manufacturer's revision number for a HID device.

Headers

Declared in hidclass.h. Defined in hidclass.h.

Comments

Kernel-mode drivers can use an IOCTL_HID_GET_COLLECTION_INFORMATION to obtain a collection's HID_COLLECTION_INFORMATION structure.

See Also

IOCTL_HID_GET_COLLECTION_DESCRIPTOR, IOCTL_HID_GET_COLLECTION_INFORMATION, HID_COLLECTION_INFORMATION


HIDD_ATTRIBUTES

The HIDD_ATTRIBUTES structure contains vendor information about a HID device.

typedef struct _HIDD_ATTRIBUTES {
  ULONG  Size;
  USHORT  VendorID;
  USHORT  ProductID;
  USHORT  VersionNumber;
} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;

Members

Size
Specifies the size, in bytes, of a HIDD_ATTRIBUTES structure.
VendorID
Specifies a HID device's vendor ID.
ProductID
Specifies a HID device's product ID.
VersionNumber
Specifies the manufacturer's revision number for a HID device.

Headers

Declared in hidpddi.h. Include hidpddi.h.

Comments

HID clients use this structure when calling HidD_GetAttributes to obtain a device's vendor information.

Before using a HIDD_ATTRIBUTES structure with HID support routines for clients, a client must set the Size member.

See Also

HidD_GetAttributes


HIDP_BUTTON_CAPS

The HIDP_BUTTON_CAPS structure contains information about the capability of a HID control button usage (or a set of buttons associated with a usage range).

typedef struct _HIDP_BUTTON_CAPS {
  USAGE  UsagePage;
  UCHAR  ReportID;
  BOOLEAN  IsAlias;
  USHORT  BitField;
  USHORT  LinkCollection;
  USAGE  LinkUsage;
  USAGE  LinkUsagePage;
  BOOLEAN  IsRange;
  BOOLEAN  IsStringRange;
  BOOLEAN  IsDesignatorRange;
  BOOLEAN  IsAbsolute;
  ULONG  Reserved[10];
  union {
    struct {
      USAGE  UsageMin, UsageMax;
      USHORT  StringMin, StringMax;
      USHORT  DesignatorMin, DesignatorMax;
      USHORT  DataIndexMin, DataIndexMax;
    } Range;
    struct  {
       USAGE  Usage, Reserved1;
       USHORT  StringIndex, Reserved2;
       USHORT  DesignatorIndex, Reserved3;
       USHORT  DataIndex, Reserved4;
    } NotRange;
  };
} HIDP_BUTTON_CAPS, *PHIDP_BUTTON_CAPS;

Members

UsagePage
Specifies the usage page for a usage or usage range.
ReportID
Specifies the report ID of the HID report that contains the usage or usage range.
IsAlias
Indicates, if TRUE, that a button has a set of aliased usages. Otherwise, if IsAlias is FALSE, the button has only one usage.
BitField
Contains the data fields (one or two bytes) associated with an input, output, or feature main item.
LinkCollection
Specifies the index of the link collection in a top-level collection's link collection array that contains the usage or usage range. If LinkCollection is zero, the usage or usage range is contained in the top-level collection.
LinkUsage
Specifies the usage of the link collection that contains the usage or usage range. If LinkCollection is zero, LinkUsage specifies the usage of the top-level collection.
LinkUsagePage
Specifies the usage page of the link collection that contains the usage or usage range. If LinkCollection is zero, LinkUsagePage specifies the usage page of the top-level collection.
IsRange
Specifies, if TRUE, that the structure describes a usage range. Otherwise, if IsRange is FALSE, the structure describes a single usage.
IsStringRange
Specifies, if TRUE, that the usage or usage range has a set of string descriptors. Otherwise, if IsStringRange is FALSE, the usage or usage range has zero or one string descriptor.
IsDesignatorRange
Specifies, if TRUE, that the usage or usage range has a set of designators. Otherwise, if IsDesignatorRange is FALSE, the usage or usage range has zero or one designator.
IsAbsolute
Specifies, if TRUE, that the button usage or usage range provides absolute data. Otherwise, if IsAbsolute is FALSE, the button data is the change in state from the previous value.
Reserved
Reserved for internal system use.
Range
Specifies, if IsRange is TRUE, information about a usage range. Otherwise, if IsRange is FALSE, NotRange contains information about a single usage.
Range.UsageMin
Indicates the inclusive lower bound of usage range whose inclusive upper bound is specified by Range.UsageMax.
Range.UsageMax
Indicates the inclusive upper bound of a usage range whose inclusive lower bound is indicated by Range.UsageMin.
Range.StringMin
Indicates the inclusive lower bound of a range of string descriptors (specified by string minimum and string maximum items) whose inclusive upper bound is indicated by Range.StringMax.
Range.StringMax
Indicates the inclusive upper bound of a range of string descriptors (specified by string minimum and string maximum items) whose inclusive lower bound is indicated by Range.StringMax.
Range.DesignatorMin
Indicates the inclusive lower bound of a range of designators (specified by designator minimum and designator maximum items) whose inclusive upper bound is indicated by Range.DesignatorMax.
Range.DesignatorMax
Indicates the inclusive upper bound of a range of designators (specified by designator minimum and designator maximum items) whose inclusive lower bound is indicated by Range.DesignatorMax.
Range.DataIndexMin
Indicates the inclusive lower bound of a sequential range of data indices that correspond, one-to-one and in the same order, to the usages specified by the usage range Range.UsageMin to Range.UsageMax.
Range.DataIndexMax
Indicates the inclusive upper bound of a sequential range of data indices that correspond, one-to-one and in the same order, to the usages specified by the usage range Range.UsageMin to Range.UsageMax.
NotRange
Specifies, if IsRange is FALSE, information about a single usage. Otherwise, if IsRange is TRUE, Range contains information about a usage range.
NotRange.Usage
Indicates a usage ID.
NotRange.Reserved1
Reserved for internal system use.
NotRange.StringID
Indicates a string descriptor ID for the usage specified by NotRange.Usage.
NotRange.Reserved2
Reserved for internal system use.
NotRange.DesignatorID
Indicates a designator ID for the usage specified by NotRange.Usage.
NotRange.Reserved3
Reserved for internal system use.
NotRange.DataIndex
Indicates the data index of the usage specified by NotRange.Usage.
NotRange.Reserved4
Reserved for internal system use.

Headers

Declared in hidpi.h. Defined in hidpi.h.

Comments

Clients obtain a button capability array by calling HidP_GetButtonCaps or HidP_GetSpecificButtonCaps. These routines return an array of HIDP_BUTTON_CAPS structures in a caller-allocated buffer. The required buffer length is specified in the HIDP_CAPS structure returned by HidP_GetCaps.

For information about the capabilities of HID control values, see Collection Capability and Value Capability Arrays.

See Also

HIDP_CAPS, HidP_GetButtonCaps, HidP_GetCaps, HidP_GetSpecificButtonCaps, HidP_GetSpecificValueCaps, HidP_GetValueCaps, HIDP_VALUE_CAPS


HIDP_CAPS

The HIDP_CAPS structure contains information about a top-level collection's capability.

typedef struct _HIDP_CAPS {
  USAGE  Usage;
  USAGE  UsagePage;
  USHORT  InputReportByteLength;
  USHORT  OutputReportByteLength;
  USHORT  FeatureReportByteLength;
  USHORT  Reserved[17];
  USHORT  NumberLinkCollectionNodes;
  USHORT  NumberInputButtonCaps;
  USHORT  NumberInputValueCaps;
  USHORT  NumberInputDataIndices;
  USHORT  NumberOutputButtonCaps;
  USHORT  NumberOutputValueCaps;
  USHORT  NumberOutputDataIndices;
  USHORT  NumberFeatureButtonCaps;
  USHORT  NumberFeatureValueCaps;
  USHORT  NumberFeatureDataIndices;
} HIDP_CAPS, *PHIDP_CAPS;

Members

Usage
Specifies a top-level collection's usage ID.
UsagePage
Specifies the top-level collection's usage page.
InputReportByteLength
Specifies the maximum size, in bytes, of all the input reports (including the report ID, if report IDs are used, which is prepended to the report data).
OutputReportByteLength
Specifies the maximum size, in bytes, of all the output reports (including the report ID, if report IDs are used, which is prepended to the report data).
FeatureReportByteLength
Specifies the maximum length, in bytes, of all the feature reports (including the report ID, if report IDs are used, which is prepended to the report data).
Reserved
Reserved for internal system use.
NumberLinkCollectionNodes
Specifies the number of HIDP_LINK_COLLECTION_NODE structures that are returned for this top-level collection by HidP_GetLinkCollectionNodes.
NumberInputButtonCaps
Specifies the number of input HIDP_BUTTON_CAPS structures that HidP_GetButtonCaps returns.
NumberInputValueCaps
Specifies the number of input HIDP_VALUE_CAPS structures that HidP_GetValueCaps returns.
NumberInputDataIndices
Specifies the number of data indices assigned to buttons and values in all input reports.
NumberOutputButtonCaps
Specifies the number of output HIDP_BUTTON_CAPS structures that HidP_GetButtonCaps returns.
NumberOutputValueCaps
Specifies the number of output HIDP_VALUE_CAPS structures that HidP_GetValueCaps returns.
NumberOutputDataIndices
Specifies the number of data indices assigned to buttons and values in all output reports.
NumberFeatureButtonCaps
Specifies the total number of feature HIDP_BUTTONS_CAPS structures that HidP_GetButtonCaps returns.
NumberFeatureValueCaps
Specifies the total number of feature HIDP_VALUE_CAPS structures that HidP_GetValueCaps returns.
NumberFeatureDataIndices
Specifies the number of data indices assigned to buttons and values in all feature reports.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

Clients should use the information provided in this structure when they call HID support routines for clients that require, as input, the size of a report type, the number of link collection nodes, the number of control capabilities, or the number of data indices.

See Also

HidP_GetCaps, HidP_GetButtonCaps, HidP_GetLinkCollectionNodes, HidP_GetSpecificButtonCaps, HidP_GetSpecificValueCaps, HidP_GetValueCaps, HIDP_LINK_COLLECTION_NODE, HIDP_BUTTON_CAPS, HIDP_VALUE_CAPS


HIDP_DATA

The HIDP_DATA structure contains information about a HID control's data index and value in a HID report.

typedef struct _HIDP_DATA {
  USHORT  DataIndex;
  USHORT  Reserved;
  union {
    ULONG  RawValue;
    BOOLEAN  On;
  };
} HIDP_DATA, *PHIDP_DATA;

Members

DataIndex
Specifies the data index of a control.
Reserved
Reserved for internal system use only.
RawValue
Contains the binary data extracted from a report if the control is a value.
On
Specifies, if TRUE and the control is a button, that the button is set to ON (one). Otherwise, if On is FALSE and the control is a button, the button is set to OFF (zero).

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

See Extracting and Setting Control Data by Data Indices.

See Also

HidP_GetData, HidP_SetData


HIDP_EXTENDED_ATTRIBUTES

The HIDP_EXTENDED_ATTRIBUTES structure contains information about the global items specified for a HID control that the HID parser did not recognize.

typedef struct _HIDP_EXTENDED_ATTRIBUTES {
  UCHAR  NumGlobalUnknowns;
  UCHAR  Reserved[3];
  PHIDP_UNKNOWN_TOKEN  GlobalUnknowns;
  ULONG  Data[1];
} HIDP_EXTENDED_ATTRIBUTES, *PHIDP_EXTENDED_ATTRIBUTES;

Members

NumGlobalUnknowns
Specifies the number of HIDP_UNKNOWN_TOKEN structures in the list specified by Data.
Reserved
Reserved for internal system use only.
GlobalUnknows
Reserved for internal system use only.
Data
Specifies the memory location where HidP_GetExtendedAttributes returns a variable length array of HIDP_UNKNOWN_TOKEN structures.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

The HIDP_EXTENDED_ATTRIBUTES structure is designed to be used with HidP_GetExtendedAttributes.

See Also

HidP_GetExtendedAttributes, HIDP_UNKNOWN_TOKEN


HIDP_LINK_COLLECTION_NODE

The HIDP_LINK_COLLECTION_NODE structure contains information about a link collection in a top-level collection's link collection array.

typedef struct _HIDP_LINK_COLLECTION_NODE {
  USAGE  LinkUsage;
  USAGE  LinkUsagePage;
  USHORT  Parent;
  USHORT  NumberOfChildren;
  USHORT  NextSibling;
  USHORT  FirstChild;
  ULONG  CollectionType: 8;
  ULONG  IsAlias: 1;
  ULONG  Reserved: 23;
  PVOID  UserContext;
} HIDP_LINK_COLLECTION_NODE, *PHIDP_LINK_COLLECTION_NODE;

Members

LinkUsage
Specifies the usage ID of a top-level collection.
LinkUsagePage
Specifies the usage page of the collection.
Parent
Specifies the index of the collection's parent collection. If the collection has no parent, Parent is zero.
NumberOfChildren
Specifies the number of child collections that the collection contains.
NextSibling
Specifies the index of the collection's immediate sibling. If the collection has no sibling, NextSibling is zero.
FirstChild
Specifies the index of the collection's first child collection. If the collection has no children, FirstChild is zero.
CollectionType
Specifies the type of collection item.
IsAlias
Specifies, if TRUE, that this collection is an aliased collection. Otherwise, if FALSE, the collection is not aliased.
Reserved
Reserved for internal system use.
UserContext
Pointer to client-specific information.

Comments

The HidP_GetLinkCollectionNodes routine returns a top-level collection's link collection array. The indices specified in a link collection node are indices in the collection's link collection array.

See Also

HidP_GetLinkCollectionNodes, HIDP_BUTTON_CAPS, HIDP_VALUE_CAPS


HIDP_VALUE_CAPS

The HIDP_VALUE_CAPS structure contains information that describes the capability of a set of HID control values (either a single usage or a usage range).

typedef struct _HIDP_VALUE_CAPS {
  USAGE  UsagePage;
  UCHAR  ReportID;
  BOOLEAN  IsAlias;
  USHORT  BitField;
  USHORT  LinkCollection;
  USAGE  LinkUsage;
  USAGE  LinkUsagePage;
  BOOLEAN  IsRange;
  BOOLEAN  IsStringRange;
  BOOLEAN  IsDesignatorRange;
  BOOLEAN  IsAbsolute;
  BOOLEAN  HasNull;
  UCHAR  Reserved;
  USHORT  BitSize;
  USHORT  ReportCount;
  USHORT  Reserved2[5];
  ULONG  UnitsExp;
  ULONG  Units;
  LONG  LogicalMin, LogicalMax;
  LONG  PhysicalMin, PhysicalMax;
    union {
      struct {
        USAGE  UsageMin, UsageMax;
        USHORT  StringMin, StringMax;
        USHORT  DesignatorMin, DesignatorMax;
        USHORT  DataIndexMin, DataIndexMax;
      } Range;
      struct {
        USAGE  Usage, Reserved1;
        USHORT  StringIndex, Reserved2;
        USHORT  DesignatorIndex, Reserved3;
        USHORT  DataIndex, Reserved4;
      } NotRange;
    };
} HIDP_VALUE_CAPS, *PHIDP_VALUE_CAPS;

Members

UsagePage
Specifies the usage page of the usage or usage range.
ReportID
Specifies the report ID of the HID report that contains the usage or usage range.
IsAlias
Indicates, if TRUE, that the usage is member of a set of aliased usages. Otherwise, if IsAlias is FALSE, the value has only one usage.
BitField
Contains the data fields (one or two bytes) associated with an input, output, or feature main item.
LinkCollection
Specifies the index of the link collection in a top-level collection's link collection array that contains the usage or usage range. If LinkCollection is zero, the usage or usage range is contained in the top-level collection.
LinkUsage
Specifies the usage of the link collection that contains the usage or usage range. If LinkCollection is zero, LinkUsage specifies the usage of the top-level collection.
LinkUsagePage
Specifies the usage page of the link collection that contains the usage or usage range. If LinkCollection is zero, LinkUsagePage specifies the usage page of the top-level collection.
IsRange
Specifies, if TRUE, that the structure describes a usage range. Otherwise, if IsRange is FALSE, the structure describes a single usage.
IsStringRange
Specifies, if TRUE, that the usage or usage range has a set of string descriptors. Otherwise, if IsStringRange is FALSE, the usage or usage range has zero or one string descriptor.
IsDesignatorRange
Specifies, if TRUE, that the usage or usage range has a set of designators. Otherwise, if IsDesignatorRange is FALSE, the usage or usage range has zero or one designator.
IsAbsolute
Specifies, if TRUE, that the usage or usage range provides absolute data. Otherwise, if IsAbsolute is FALSE, the value is the change in state from the previous value.
HasNull
Specifies, if TRUE, that the usage supports a NULL value, which indicates that the data is not valid and should be ignored. Otherwise, if HasNull is FALSE, the usage does not have a NULL value.
Reserved
Reserved for internal system use.
BitSize
Specifies the size, in bits, of a usage's data field in a report. If ReportCount is greater than one, each usage has a separate data field of this size.
ReportCount
Specifies the number of usages that this structure describes.
Reserved2
Reserved for internal system use.
UnitsExp
Specifies the usage's exponent, as described by the USB HID Standard.
Units
Specifies the usage's units, as described by the USB HID Standard.
LogicalMin
Specifies a usage's signed lower bound.
LogicalMax
Specifies a usage's signed upper bound.
PhysicalMin
Specifies a usage's signed lower bound after scaling is applied to the logical minimum value.
PhysicalMax
Specifies a usage's signed upper bound after scaling is applied to the logical maximum value.
Range
Specifies, if IsRange is TRUE, information about a usage range. Otherwise, if IsRange is FALSE, NotRange contains information about a single usage.
Range.UsageMin
Indicates the inclusive lower bound of usage range whose inclusive upper bound is specified by Range.UsageMax.
Range.UsageMax
Indicates the inclusive upper bound of a usage range whose inclusive lower bound is indicated by Range.UsageMin.
Range.StringMin
Indicates the inclusive lower bound of a range of string descriptors (specified by string minimum and string maximum items) whose inclusive upper bound is indicated by Range.StringMax.
Range.StringMax
Indicates the inclusive upper bound of a range of string descriptors (specified by string minimum and string maximum items) whose inclusive lower bound is indicated by Range.StringMax.
Range.DesignatorMin
Indicates the inclusive lower bound of a range of designators (specified by designator minimum and designator maximum items) whose inclusive upper bound is indicated by Range.DesignatorMax.
Range.DesignatorMax
Indicates the inclusive upper bound of a range of designators (specified by designator minimum and designator maximum items) whose inclusive lower bound is indicated by Range.DesignatorMax.
Range.DataIndexMin
Indicates the inclusive lower bound of a sequential range of data indices that correspond, one-to-one and in the same order, to the usages specified by the usage range Range.UsageMin to Range.UsageMax.
Range.DataIndexMax
Indicates the inclusive upper bound of a sequential range of data indices that correspond, one-to-one and in the same order, to the usages specified by the usage range Range.UsageMin to Range.UsageMax.
NotRange
Specifies, if IsRange is FALSE, information about a single usage. Otherwise, if IsRange is TRUE, Range contains information about a usage range.
NotRange.Usage
Indicates a usage ID.
NotRange.Reserved1
Reserved for internal system use.
NotRange.StringID
Indicates a string descriptor ID for the usage specified by NotRange.Usage.
NotRange.Reserved2
Reserved for internal system use.
NotRange.DesignatorID
Indicates a designator ID for the usage specified by NotRange.Usage.
NotRange.Reserved3
Reserved for internal system use.
NotRange.DataIndex
Indicates the data index of the usage specified by NotRange.Usage.
NotRange.Reserved4
Reserved for internal system use.

Comments

Clients obtain a value capability array by calling HidP_GetValueCaps or HidP_GetSpecificValueCaps. These routines return an array of HIDP_VALUE_CAPS structures in a caller-allocated buffer. The required buffer length is specified in the HIDP_CAPS structure returned by HidP_GetCaps.

For information about the capabilities of HID control values, see Collection Capability and Value Capability Arrays.

See Also

HidP_GetButtonCaps, HidP_GetSpecificButtonCaps, HidP_GetSpecificValueCaps, HidP_GetUsageValue, HidP_GetUsageValueArray, HidP_GetValueCaps, HidP_GetCaps, HIDP_CAPS


HIDP_REPORT_TYPE

The HIDP_REPORT_TYPE enumeration type is used to specify a HID report type.

typedef enum _HIDP_REPORT_TYPE {
  HidP_Input,
  HidP_Output,
  HidP_Feature
} HIDP_REPORT_TYPE;

Enumerators

HidP_Input
Indicates an input report.
HidP_Output
Indicates an output report.
HidP_Feature
Indicates a feature report.

Headers

Declared in hidpi.h. Include hidpi.h.

See Also

HidP_GetData, HidP_SetData, HIDP_BUTTON_CAPS, HIDP_VALUE_CAPS


HIDP_UNKNOWN_TOKEN

The HIDP_UNKNOWN_TOKEN structure contains information about a global item that the HID parser did not recognize.

typedef struct _HIDP_UNKNOWN_TOKEN {
  UCHAR  Token;
  UCHAR  Reserved[3];
  ULONG  BitField;
} HIDP_UNKNOWN_TOKEN, *PHIDP_UNKNOWN_TOKEN;

Members

Token
Specifies the one-byte prefix of a global item.
Reserved
Reserved for internal system use.
BitField
Specifies the data part of the global item.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

HIDP_UNKNOWN_TOKEN is designed to be used with the HIDP_EXTENDED_ATTRIBUTES structure. HidP_GetExtendedAttributes returns a HIDP_EXTENDED_ATTRIBUTES structure, which contains a variable length array of HIDP_UNKNOWN_TOKEN structures.

See Also

HIDP_EXTENDED_ATTRIBUTES, HidP_GetExtendedAttributes


_HIDP_PREPARSED_DATA

The _HIDP_PREPARSED_DATA structure contains a top-level collection's preparsed data.

typedef struct _HIDP_PREPARSED_DATA * PHIDP_PREPARSED_DATA;

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

A user-mode client uses the HidD_GetPreparsedData routine to obtain a top-level collection's preparsed data in a variable length _HIDP_PREPARSED_DATA structure.

A kernel-mode driver uses an IOCTL_HID_GET_COLLECTION_DESCRIPTOR request to obtain a pointer to a top-level collection's preparsed data.

The internal structure of a _HIDP_PREPARSED_DATA structure is reserved for internal system use.

See Also

HidD_GetPreparsedData, HidD_FreePreparsedData, IOCTL_HID_GET_COLLECTION_DESCRIPTOR


USAGE_AND_PAGE

The USAGE_AND_PAGE structure specifies the usage page and usage ID of a HID control.

typedef struct _USAGE_AND_PAGE {
  USAGE  Usage;
  USAGE  UsagePage;
} USAGE_AND_PAGE, *PUSAGE_AND_PAGE;

Members

Usage
Specifies a usage ID within the usage page specified by UsagePage.
UsagePage
Specifies a usage page.

See Also

HidP_GetButtonsEx


HID Support Routines for MiniDrivers

This section describes the Microsoft-supplied routines that HID minidrivers can use in Microsoft® Windows® 2000 and later to support HID devices.

Routines in this section are listed in alphabetic order.


HidRegisterMinidriver

HidRegisterMinidriver is called by HID minidrivers, during their initialization, to register with the HID class services.

NTSTATUS
  HidRegisterMinidriver(
    IN PHID_MINIDRIVER_REGISTRATION  MinidriverRegistration
    );

Parameters

MinidriverRegistration
Pointer to a caller-allocated buffer that contains an initialized HID_MINIDRIVER_REGISTRATION structure for the minidriver.

Return Value

HidRegisterMinidriver returns one of the following NTSTATUS codes:

STATUS_SUCCESS
Indicates that the routine completed without error and the minidriver is now registered with the HID class driver.
STATUS_INSUFFICIENT_RESOURCES
Indicates that there was insufficient memory for the system to register the minidriver.
STATUS_REVISION_MISMATCH
Indicates that the HID revision number provided in MinidriverRegistration->Revision is not supported by this version of the HID class driver.

Comments

Before calling this routine, minidrivers must initialize all members of the HID_MINIDRIVER_REGISTRATION structure that is provided at MinidriverRegistration. See HID_MINIDRIVER_REGISTRATION for details on these members.

Callers of this routine must be running at IRQL < DISPATCH_LEVEL.

See Also

HID_MINIDRIVER_REGISTRATION


HID_DESCRIPTOR

The HID_DESCRIPTOR structure represents a HID descriptor for a HID class device.

typedef struct _HID_DESCRIPTOR {
  UCHAR  bLength;
  UCHAR  bDescriptorType;
  USHORT  bcdHID;
  UCHAR  bCountry;
  UCHAR  bNumDescriptors;
    struct _HID_DESCRIPTOR_DESC_LIST {
      UCHAR  bReportType;
      USHORT  wReportLength;
    } DescriptorList [1];
} HID_DESCRIPTOR, *PHID_DESCRIPTOR;

Members

For information about HID descriptors, see Device Class Definition for Human Interface Devices, published by the USB Implementers Forum, Inc.

Headers

Defined in hidport.h. Include hidport.h.

Comments

The HID class driver uses an IOCTL_HID_GET_DEVICE_DESCRIPTOR request to obtain a device's HID descriptor from a HID minidriver.

See Also

IOCTL_HID_GET_DEVICE_DESCRIPTOR


HID_DEVICE_ATTRIBUTES

The HID_DEVICE_ATTRIBUTES structure contains information about a HID device.

typedef struct _HID_DEVICE_ATTRIBUTES {
  ULONG  Size;
  USHORT  VendorID;
  USHORT  ProductID;
  USHORT  VersionNumber;
  USHORT  Reserved[11];
} HID_DEVICE_ATTRIBUTES, *PHID_DEVICE_ATTRIBUTES;

Members

Size
Specifies the size of the structure. This member should be treated as read-only when a HID minidriver uses this structure to complete an IOCTL_HID_GET_DEVICE_ATTRIBUTES request.
VendorID
Specifies a HID device's vendor ID.
ProductID
Specifies a HID device's product ID.
VersionNumber
Specifies the manufacturer's revision number for a HID device.
Reserved
Reserved for internal system use.

Headers

Defined in hidport.h. Include hidport.h.

Comments

The HID class driver uses this structure to obtain device attributes when it sends an IOCTL_HID_GET_DEVICE_ATTRIBUTES request to a HID minidriver.

See Also

IOCTL_HID_GET_DEVICE_ATTRIBUTES


HID_DEVICE_EXTENSION

The HID_DEVICE_EXTENSION structure is used by a HID minidriver as its layout for the device extension of a functional device object.

typedef struct _HID_DEVICE_EXTENSION {
  PDEVICE_OBJECT  PhysicalDeviceObject;
  PDEVICE_OBJECT  NextDeviceObject;
  PVOID  MiniDeviceExtension;
} HID_DEVICE_EXTENSION, *PHID_DEVICE_EXTENSION;

Members

PhysicalDeviceObject
Pointer to HID device's physical device object.
NextDeviceObject
Pointer to the device object immediately below the functional device object in the HID device's device stack.
MiniDeviceExtension
Pointer to the minidriver-specific portion of the device extension.

Headers

Defined in hidport.h. Include hidport.h.

Comments

The device extension of a HID minidriver's functional device object must have the layout of this structure. The HID class driver sets the members of this structure when the device object is initialized. The minidriver can use the MiniDeviceExtension buffer for device-specific data. A minidriver must never change the information referenced by the physical device object and next device object pointers.

When a minidriver sends an IRP down the device stack, it should use the device object at NextDeviceObject as the target device object in a call to IoCallDriver. The device object pointed to by PhysicalDeviceObject should be used as a reference only, as it is a pointer to the PDO for this device, not necessarily a pointer to the device object immediately below the functional device object in the HID device's device stack. NextDeviceObject points to the top of the stack to which the minidriver's functional device object is attached.

See Also

HidRegisterMinidriver


HID_MINIDRIVER_REGISTRATION

The HID_MINIDRIVER_REGISTRATION structure contains registration information that a HID minidriver passes to the HID class driver when the minidriver registers with the class driver.

typedef struct _HID_MINIDRIVER_REGISTRATION {
  ULONG  Revision;
  PDRIVER_OBJECT  DriverObject;
  PUNICODE_STRING RegistryPath;
  ULONG  DeviceExtensionSize;
  BOOLEAN  DevicesArePolled;
  UCHAR  Reserved[3];
} HID_MINIDRIVER_REGISTRATION, *PHID_MINIDRIVER_REGISTRATION;

Members

Revision
Specifies the HID version that this minidriver supports.
DriverObject
Pointer to the minidriver's DRIVER_OBJECT.
RegistryPath
Pointer to the minidriver's registry path.
DeviceExtensionSize
Specifies the length, in bytes, that the minidriver requests for a device extension.
DevicesArePolled
Specifies that the devices on the bus that this minidriver supports must be polled in order to obtain data from the device.
Reserved
Reserved for internal system use.

Headers

Defined in hidport.h. Include hidport.h.

Comments

When a HID minidriver calls HidRegisterMinidriver, it uses this structure to pass information to the HID class driver. The minidriver must must zero-initialize this structure before setting members. A minidriver sets the members DriverObject and RegistryPath to the driver object and registry path parameters that are passed to the minidriver as system-supplied parameters to its DriverEntry routine. Revision should be set to HID_REVISION.

See Also

HidRegisterMinidriver


HID_XFER_PACKET

The HID_XFER_PACKET structure contains information about a HID report that the HID class driver uses with I/O requests to get or set a report.

typedef struct _HID_XFER_PACKET {
  PUCHAR  reportBuffer;
  ULONG  reportBufferLen;
  UCHAR  reportId;
} HID_XFER_PACKET, *PHID_XFER_PACKET;

Members

reportBuffer
Pointer to a report buffer.
reportBufferLen
Specifies the length of the report at reportBuffer.
reportId
Specifies the report ID of the report contained at reportBuffer. This parameter is optional, and, if not specified, should be set to zero.

Headers

Defined in hidport.h. Include hidport.h.

Comments

The HID class driver uses this structure to specify information about a HID report when it uses an I/O request to get or set a report.

See Also

IOCTL_HID_GET_FEATURE, IOCTL_GET_INPUT_REPORT, IOCTL_HID_SET_FEATURE, IOCTL_HID_SET_OUTPUT_REPORT


Reserved HID Routines and Data Types

This section lists, in alphabetical order, the HID routines, structures, enumeration types and data types that are reserved for internal system use.

DeviceObjectState

HID_DRIVER_CONFIG

HID_INTERFACE_HIDPARSE

HID_INTERFACE_NOTIFY_PNP

HIDD_CONFIGURATION

HidD_GetConfiguration

HidD_GetMsGenreDescriptor

HidD_SetConfiguration

HIDP_COLLECTION_DESC

HIDP_DEVICE_DESC

HidP_FreeCollectionDescription

HIDP_GETCOLDESC_DBG

HidP_GetCollectionDescription

HIDP_KEYBOARD_DIRECTION

HIDP_KEYBOARD_MODIFIER_STATE

HIDP_REPORT_IDS

HidP_SysPowerCaps

HidP_SysPowerEvent

HidP_TranslateUsageAndPagesToI8042ScanCodes

PHID_STATUS_CHANGE

PHIDP_INSERT_SCANCODES

PHIDP_REPORT_DESCRIPTOR

DeviceObjectState

The DeviceObjectState enumeration type is reserved for internal system use.

enum DeviceObjectState {
  DeviceObjectStarted,
  DeviceObjectStopped,
  DeviceObjectRemoved
};

Headers

Declared in hidclass.h.

HID_DRIVER_CONFIG

The HID_DRIVER_CONFIG structure is reserved for internal system use.

typedef struct _HID_DRIVER_CONFIG {
  ULONG  Size;
  ULONG  RingBufferSize;
} HID_DRIVER_CONFIG, *PHID_DRIVER_CONFIG;

Headers

Declared in hidclass.h.

HID_INTERFACE_HIDPARSE

The HID_INTERFACE_HIDPARSE structure is reserved for internal system use.

typedef struct _HID_INTERFACE_HIDPARSE {
#ifndef __cplusplus
  INTERFACE;
#else
  INTERFACE  i;
#endif
  PHIDP_GETCAPS  HidpGetCaps;
} HID_INTERFACE_HIDPARSE, *PHID_INTERFACE_HIDPARSE;

Headers

Declared in hidclass.h.

HID_INTERFACE_NOTIFY_PNP

The HID_INTERFACE_NOTIFY_PNP structure is reserved for internal system use.

typedef struct _HID_INTERFACE_NOTIFY_PNP {
#ifndef __cplusplus
  INTERFACE;
#else
  INTERFACE  i;
#endif
  PHID_STATUS_CHANGE  StatusChangeFn;
  PVOID CallbackContext;
} HID_INTERFACE_NOTIFY_PNP, *PHID_INTERFACE_NOTIFY_PNP;

Headers

Declared in hidclass.h.

HIDD_CONFIGURATION

The HIDD_CONFIGURATION structure is reserved for internal system use.

typedef struct _HIDD_CONFIGURATION {
  PVOID  cookie;
  ULONG  size;
  ULONG  RingBufferSize;
} HIDD_CONFIGURATION, *PHIDD_CONFIGURATION;

Headers

Declared in hidsdi.h.

HidD_GetConfiguration

The HidD_GetConfiguration routine is reserved for internal system use.

BOOLEAN __stdcall
  HidD_GetConfiguration(
    IN HANDLE  HidDeviceObject,
    OUT PHIDD_CONFIGURATION  Configuration,
    IN ULONG  ConfigurationLength
    );

Headers

Declared in hidsdi.h.

HidD_GetMsGenreDescriptor

The HidD_GetMsGenreDescriptor routine is reserved for internal system use.

BOOLEAN __stdcall
  HidD_GetMsGenreDescriptor(
    IN HANDLE  HidDeviceObject,
    OUT PVOID  Buffer,
    IN ULONG  BufferLength
    );

Headers

Declared in hidsdi.h.

HidD_SetConfiguration

The HidD_SetConfiguration routine is reserved for internal system use.

BOOLEAN __stdcall
  HidD_SetConfiguration(
    IN HANDLE  HidDeviceObject,
    IN PHIDD_CONFIGURATION  Configuration,
    IN ULONG  ConfigurationLength
    );

Headers

Declared in hidsdi.h.

HIDP_COLLECTION_DESC

The HIDP_COLLECTION_DESC structure is reserved for internal system use.

typedef struct _HIDP_COLLECTION_DESC {
  USAGE  UsagePage;
  USAGE  Usage;
  UCHAR  CollectionNumber;
  UCHAR  Reserved [15];
  USHORT  InputLength;
  USHORT  OutputLength;
  USHORT  FeatureLength;
  USHORT  PreparsedDataLength;
  PHIDP_PREPARSED_DATA  PreparsedData;
} HIDP_COLLECTION_DESC, *PHIDP_COLLECTION_DESC;

Headers

Declared in hidpddi.h.

HIDP_DEVICE_DESC

The HIDP_DEVICE_DESC structure is reserved for internal system use.

typedef struct _HIDP_DEVICE_DESC {
  PHIDP_COLLECTION_DESC  CollectionDesc;
  ULONG  CollectionDescLength;
  PHIDP_REPORT_IDS  ReportIDs;
  ULONG  ReportIDsLength;
  HIDP_GETCOLDESC_DBG  Dbg;
} HIDP_DEVICE_DESC, *PHIDP_DEVICE_DESC;

Headers

Declared in hidpddi.h.

HidP_FreeCollectionDescription

The HidP_FreeCollectionDescription routine is reserved for internal system use.

VOID
  HidP_FreeCollectionDescription(
    IN PHIDP_DEVICE_DESC  DeviceDescription
    );

Headers

Declared in hidpddi.h.

HIDP_GETCOLDESC_DBG

The HIDP_GETCOLDESC_DBG structure is reserved for internal system use.

typedef struct _HIDP_GETCOLDESC_DBG {
  ULONG  BreakOffset;
  ULONG  ErrorCode;
  ULONG  Args[6];
} HIDP_GETCOLDESC_DBG, *PHIDP_GETCOLDESC_DBG;

Headers

Declared in hidpddi.h.

HidP_GetCollectionDescription

The HidP_GetCollectionDescription routine is reserved for internal system use.

NTSTATUS
  HidP_GetCollectionDescription(
    IN PHIDP_REPORT_DESCRIPTOR  ReportDesc,
    IN ULONG  DescLength,
    IN POOL_TYPE  PoolType,
    OUT PHIDP_DEVICE_DESC  DeviceDescription
    );

Headers

Declared in hidpddi.h.

HIDP_KEYBOARD_DIRECTION

The HIDP_KEYBOARD_DIRECTION enumeration type is reserved for internal system use.

typedef enum _HIDP_KEYBOARD_DIRECTION {
  HidP_Keyboard_Break,
  HidP_Keyboard_Make
} HIDP_KEYBOARD_DIRECTION;

Headers

Declared in hidpi.h.

HIDP_KEYBOARD_MODIFIER_STATE

The HIDP_KEYBOARD_MODIFIER_STATE structure is reserved for internal system use.

typedef struct _HIDP_KEYBOARD_MODIFIER_STATE {
  union {
    struct {
      ULONG  LeftControl: 1;
      ULONG  LeftShift: 1;
      ULONG  LeftAlt: 1;
      ULONG  LeftGUI: 1;
      ULONG  RightControl: 1;
      ULONG  RightShift: 1;
      ULONG  RightAlt: 1;
      ULONG  RigthGUI: 1;
      ULONG  CapsLock: 1;
      ULONG  ScollLock: 1;
      ULONG  NumLock: 1;
      ULONG  Reserved: 21;
    };
    ULONG ul;
  };
} HIDP_KEYBOARD_MODIFIER_STATE, *PHIDP_KEYBOARD_MODIFIER_STATE;

Headers

Declared in hidpi.h.

HIDP_REPORT_IDS

The HIDP_REPORT_IDS structure is reserved for internal system use.

typedef struct _HIDP_REPORT_IDS {
  UCHAR  ReportID;
  UCHAR  CollectionNumber;
  USHORT  InputLength;
  USHORT  OutputLength;
  USHORT  FeatureLength;
} HIDP_REPORT_IDS, *PHIDP_REPORT_IDS;

Headers

Declared in hidpddi.h.

HidP_SysPowerCaps

The HidP_SysPowerCaps routine is reserved for internal system use.

NTSTATUS
  HidP_SysPowerCaps(
    IN PHIDP_PREPARSED_DATA  Ppd,
    OUT PULONG  OutputBuffer
    );

Headers

Declared in hidpddi.h.

HidP_SysPowerEvent

The HidP_SysPowerEvent routine is reserved for internal system use.

NTSTATUS
  HidP_SysPowerEvent(
    IN PCHAR  HidPacket,
    IN USHORT  HidPacketLength,
    IN PHIDP_PREPARSED_DATA  Ppd,
    OUT PULONG  OutputBuffer
    );

Headers

Declared in hidpddi.h.

HidP_TranslateUsageAndPagesToI8042ScanCodes

The HidP_TranslateUsageAndPagesToI8042ScanCodes routine is reserved for internal system use.

NTSTATUS __stdcall
  HidP_TranslateUsageAndPagesToI8042ScanCodes(
    IN PUSAGE_AND_PAGE  ChangedUsageList,
    IN ULONG  UsageListLength,
    IN HIDP_KEYBOARD_DIRECTION  KeyAction,
    IN OUT PHIDP_KEYBOARD_MODIFIER_STATE  ModifierState,
    IN PHIDP_INSERT_SCANCODES  InsertCodesProcedure,
    IN PVOID  InsertCodesContext
    );

Headers

Declared in hidpi.h.

HidP_TranslateUsagesToI8042ScanCodes

The HidP_TranslateUsagesToI8042ScanCodes routine is reserved for internal system use.

NTSTATUS __stdcall
  HidP_TranslateUsagesToI8042ScanCodes(
    IN PUSAGE  ChangedUsageList,
    IN ULONG  UsageListLength,
    IN HIDP_KEYBOARD_DIRECTION  KeyAction,
    IN OUT PHIDP_KEYBOARD_MODIFIER_STATE  ModifierState,
    IN PHIDP_INSERT_SCANCODES  InsertCodesProcedure,
    IN PVOID  InsertCodesContext
    );

Headers

Declared in hidpi.h.

PHID_STATUS_CHANGE

The PHID_STATUS_CHANGE routine is reserved for internal system use.

typedef VOID (*PHID_STATUS_CHANGE)(
    PVOID  Context,
    enum DeviceObjectState State
    );

Headers

Declared in hidclass.h.

PHIDP_INSERT_SCANCODES

The PHIDP_INSERT_SCANCODES routine is reserved for internal system use.

typedef BOOLEAN (*PHIDP_INSERT_SCANCODES)(
    IN PVOID  Context,
    IN PCHAR  NewScanCodes,
    IN ULONG  Length
    );

Headers

Declared in hidpi.h.

PHIDP_REPORT_DESCRIPTOR

The PHIDP_REPORT_DESCRIPTOR data type is reserved for internal system use.

typedef PUCHAR  PHIDP_REPORT_DESCRIPTOR;

Headers

Declared in hidpi.h.


Kbdclass Driver Reference

This section includes the following topics about Kbdclass, the class driver for device class GUID_CLASS_KEYBOARD in Microsoft® Windows® 2000 and later operating systems.

Major I/O Requests

Device Control Requests

Callback Routines

Structures

Windows uses Kbdclass as the class driver for all keyboard devices that are installed in a system. The Windows Win32® subsystem opens all keyboard devices for its exclusive use. Applications can not open the keyboard devices operated by Kbdclass.

Kbdclass can work in combination with an optional upper-level keyboard filter driver for a PS/2-style keyboard device. Kbfiltr, a sample upper-level keyboard filter driver in the Windows DDK, demonstrates how to customize the operation of a keyboard device.

For more information on Kbdclass, see the following:

Keyboard and Mouse Drivers for Non-HID Devices

Include file ntddkbd.h in the \inc directory in the Windows DDK

Sample code in the \src\input directory in the Windows DDK

Note Kbdclass supports legacy devices and Plug and Play devices. As appropriate, this material distinguishes between the operation of Kbdclass for a legacy device and for a Plug and Play device. If no distinction is made, the description applies to both legacy and Plug and Play devices.


Kbdclass Major I/O Requests

This section describes the Kbdclass-specific operation of the following major I/O requests:

IRP_MJ_CLEANUP

IRP_MJ_CLOSE

IRP_MJ_CREATE

IRP_MJ_DEVICE_CONTROL

IRP_MJ_FLUSH_BUFFERS

IRP_MJ_INTERNAL_DEVICE_CONTROL

IRP_MJ_PNP

IRP_MJ_POWER

IRP_MJ_READ

IRP_MJ_SYSTEM_CONTROL

For more information on the generic operation of these requests, see IRP Function Codes and IOCTLs.


IRP_MJ_CLOSE

Operation

The IRP_MJ_CLOSE request closes a keyboard device.

Plug and Play Operation
Kbdclass sends the request down the driver stack and clears the file that is permitted read access to the device. If there is a grandmaster device, Kbdclass sends a close request to all the function device objects that are associated with the subordinate class device objects.
Legacy Operation
Kbdclass sends an IOCTL_INTERNAL_KEYBOARD_DISABLE request to the port driver. Kbdclass also clears the file that is permitted read access to the device.

I/O Status Block

Plug and Play Operation

The Information member is set to zero.

The Status member is set to STATUS_SUCCESS or to the status returned by the function driver for the IRP_MJ_CLOSE request.

Legacy Operation

The Information member is set to zero.

The Status member is set to STATUS_SUCCESS or to the status returned by the port driver for the IOCTL_INTERNAL_KEYBOARD_DISABLE request.


IRP_MJ_CREATE

Operation

The IRP_MJ_CREATE request opens a file on a keyboard device.

Plug and Play Operation
If the device has been started, Kbdclass sends the IRP_MJ_CREATE request down the driver stack. If the device is not started, Kbdclass completes the request without sending the request down the driver stack. Kbdclass sets the trusted file that is permitted read access to the device. If there is a grandmaster device, Kbdclass sends a create request to all the keyboard devices that are associated with the subordinate class device objects.
Legacy Operation
Kbdclass sends a synchronous IOCTL_INTERNAL_KEYBOARD_ENABLE request down the device stack.

I/O Status Block

Plug and Play Operation
The Information member of the IRP is set to zero.

The Status member is set to one of the following values:

STATUS_SUCCESS
The request completed successfully.
STATUS_UNSUCCESFUL
The device is not started.
STATUS_Xxx
A lower-level driver returns an error status.
Legacy Operation
The Information member is set to zero.

The Status member is set to STATUS_SUCCESS or to the status returned by the port driver for an IOCTL_INTERNAL_KEYBOARD_ENABLE request.


IRP_MJ_DEVICE_CONTROL

Kbdclass supports the following device control requests:

IOCTL_KEYBOARD_QUERY_ATTRIBUTES

IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION

IOCTL_KEYBOARD_QUERY_INDICATORS

IOCTL_KEYBOARD_QUERY_TYPEMATIC

IOCTL_KEYBOARD_SET_INDICATORS

For most other device control requests, Kbdclass skips the current IRP stack location and sends the request down the stack to be completed by a lower-level driver. If Kbdclass does not support the request, it completes the request with a status of STATUS_INVALID_DEVICE_REQUEST.

For more information on device control requests, see Kbdclass Device Control Requests.


IRP_MJ_FLUSH_BUFFERS

Operation

The IRP_MJ_FLUSH_BUFFERS request clears the internal data queue.

I/O Status Block

The Information member is zero.

The Status member is set to one of the following values:

STATUS_SUCCESS
The request completed successfully.
STATUS_NOT_SUPPORTED
The target device is associated with a subordinate class device that does not support flushing the internal data queue.


IRP_MJ_INTERNAL_DEVICE_CONTROL

Operation

Kbdclass skips the current IRP stack location and sends the internal device control request down the device stack to be completed by a lower-level driver.


IRP_MJ_PNP

Kbdclass processes the following Plug and Play requests:

IRP_MN_QUERY_PNP_DEVICE_STATE

IRP_MN_QUERY_REMOVE_DEVICE

IRP_MN_QUERY_STOP_DEVICE

IRP_MN_REMOVE_DEVICE

IRP_MN_START_DEVICE

IRP_MN_SURPRISE_REMOVAL

IRP_MN_STOP_DEVICE

For all other Plug and Play requests, Kbdclass copies the current IRP stack location and sends the request down the device stack without further processing.

For more information on the generic operation of these requests, see Plug and Play IRPs.

I/O Status Block

Under normal operation the status block values are specific to the minor function request. If an IRP_MJ_PNP request is sent in error to a legacy device, Kbdclass completes the request with a status of STATUS_NOT_SUPPORTED.


IRP_MJ_POWER

Kbdclass supports the following power requests:

IRP_MN_SET_POWER

IRP_MN_QUERY_POWER

IRP_MN_WAIT_WAKE

For all other power requests, Kbdclass copies the current IRP stack location, requests the next power request, and sends the request down the device stack.

For more information on the generic operation of these requests, see Handling Power IRPs.

I/O Status Block

Under normal operation the status block values are specific to the minor function request. If a power request is sent in error to a grandmaster device or a legacy device, Kbdclass completes the request with a status of STATUS_NOT_SUPPORTED.


IRP_MJ_READ

Operation

The IRP_MJ_READ request transfers zero or more KEYBOARD_INPUT_DATA structures from Kbdclass's internal data queue to the Win32 subsystem buffer. If there is no data in the data queue, a read request remains pending until it is completed or canceled.

Kbdclass completes a read request and does not send the request down the device stack.

A read request can be canceled. If a cleanup is in progress when a read request is received, no action is taken.

Note that a read request can be completed successfully only if the request was made by a trusted subsystem. Kbdclass performs a privilege check to enforce this restriction. The Win32 subsystem is currently the only trusted subsystem.

Input

Parameters.Read.Length member specifies the size in bytes of zero or more KEYBOARD_INPUT_DATA structures.

Output

The AssociatedIrp.SystemBuffer member points to the output buffer that is allocated by the Win32 subsystem to output the requested number of KEYBOARD_INPUT_DATA structures.

I/O Status Block

The Information member specifies the number of bytes that are transferred to the Win32 subsystem output buffer. The number of bytes that are transferred is the smallest of the requested number of bytes and the number of bytes currently in the internal data queue.

The Status member is set to one of the following values:

STATUS_SUCCESS
At least one KEYBOARD_INPUT_DATA structure was transferred.
STATUS_BUFFER_TOO_SMALL
The number of requested bytes is not an integer multiple of the size in bytes of a KEYBOARD_INPUT_DATA structure.
STATUS_PRIVILEGE_NOT_HELD
The requesting subsystem does not have read privileges.
STATUS_CANCELLED
The request was canceled before the transfer actually took place.


IRP_MJ_SYSTEM_CONTROL

Operation

Kbdclass uses WmiSystemControl to handle WMI system control requests. Kbdclass registers the following types of WMI library callback routines, which WmiSystemControl calls to handle WMI requests sent to a device:

DpWmiQueryReginfo

DpWmiQueryDataBlock

DpWmiSetDataBlock

DpWmiSetDataItem

For all other system control requests, Kbdclass skips the current IRP stack location and sends the request down the device stack without further processing.

Kbdclass updates WMI registration information after a device is started or removed. The driver calls the IoWMIRegistrationControl routine to update WMI registration information.

I/O Status Block

For WMI requests, Kbdclass sets the Status member to one of the following values:

STATUS_SUCCESS
The request completed successfully.
STATUS_BUFFER_TOO_SMALL
The output buffer size, in bytes, is less than the required size to return the requested information.
STATUS_INVALID_DEVICE_REQUEST
The device request is not valid.
STATUS_WMI_GUID_NOT_FOUND
The WMI GUID was not found.
STATUS_WMI_READ_ONLY
The WMI data is read-only.

If Kbdclass does not handle the request and sends it down the device stack, the Status member is set by a lower-level driver.


Kbdclass Device Control Requests

This section describes the following device control requests that Kbdclass supports:

IOCTL_KEYBOARD_QUERY_ATTRIBUTES

IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION

IOCTL_KEYBOARD_QUERY_INDICATORS

IOCTL_KEYBOARD_QUERY_TYPEMATIC

IOCTL_KEYBOARD_SET_INDICATORS

IOCTL_KEYBOARD_SET_TYPEMATIC

Kbdclass changes these device control requests into internal device control request and sends the changed request down the device stack.

Kbdclass also sends a number of other device control requests for Plug and Play devices down the device stack without changing the request to an internal device control request. For a list of these requests, see IOCTL_Xxx.

Filter drivers between the class and function drivers can filter device control requests either before they send the request down the device stack or after the lower-level drivers complete the request.

If Kbdclass does not support the request, it completes the request with a status of STATUS_INVALID_DEVICE_REQUEST.

Input and Output

The Parameters.DeviceIoControlCode.IoControlCode member specifies the control code.

The AssociatedIrp->SystemBuffer member is used for request-specific input and output.

The Parameters.DeviceIoControl.InputBufferLength member is used to input the request-specific size of the input buffer.

The Parameters.DeviceIoControl.OutputBufferLength member is used to input the request-specific size of the output buffer.

I/O Status Block

Usually, the Information member is set to zero or to the number of bytes returned in the output buffer. Information can also return request-specific values or pointers.

The Status member is set to a request-specific value. Status is set to STATUS_INVALID_DEVICE_REQUEST if Kbdclass does not support the request.


IOCTL_KEYBOARD_QUERY_ATTRIBUTES

Operation

The IOCTL_KEYBOARD_QUERY_ATTRIBUTES request returns information about the keyboard attributes.

Kbdclass copies the current stack location, sets the MajorFunction member of the new stack location to IRP_MJ_INTERNAL_DEVICE_CONTROL, and sends this request down the device stack.

For more information on this request, see the description of this request in I8042prt Keyboard Internal Device Control Requests.

Input

The Parameters.DeviceIoControl.InputBufferLength member is set to zero or a value greater than or equal to the size in bytes of a KEYBOARD_UNIT_ID_PARAMETER. A value of zero specifies a default unit ID of zero.

The AssociatedIrp.SystemBuffer member points to a client-allocated buffer that is used to input and output information. On input, AssociatedIrp.SystemBuffer points to a KEYBOARD_UNIT_ID_PARAMETER structure. The client sets the UnitId member of the input structure.

The Parameters.DeviceIoControl.OutputBufferLength member specifies the size in bytes of the output buffer, which must be greater than or equal to the size in bytes of a KEYBOARD_ATTRIBUTES structure.

Output

AssociatedIrp.SystemBuffer points to a client-allocated buffer that the lower-level drivers use to output a KEYBOARD_ATTRIBUTES structure.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of a KEYBOARD_ATTRIBUTES structure, otherwise Information is set to zero.

The Status member is set to one of the following values:

STATUS_SUCCESS
The request completed successfully.
STATUS_INVALID_PARAMETER
The UnitId value is not valid.
STATUS_BUFFER_TOO_SMALL
The value of Parameters.DeviceIoControl.InputBufferLength or Parameters.DeviceIoControl.OutputBufferLength is not valid.


IOCTL_KEYBOARD_QUERY_INDICATORS

Operation

The IOCTL_KEYBOARD_QUERY_INDICATORS request returns information on the keyboard indicators.

Kbdclass copies the current stack location, sets the MajorFunction member of the new stack location to IRP_MJ_INTERNAL_DEVICE_CONTROL, and sends this request down the device stack.

Input

The Parameters.DeviceIoControl.InputBufferLength member is set to zero or a value greater than or equal to the size in bytes of a KEYBOARD_UNIT_ID_PARAMETER. A value of zero specifies a default unit ID of zero.

The AssociatedIrp.SystemBuffer member points to a client-allocated buffer that is used to input and output information. On input, AssociatedIrp.SystemBuffer points to a KEYBOARD_UNIT_ID_PARAMETER structure. The client sets the UnitId member of the input structure.

The Parameters.DeviceIoControl.OutputBufferLength member specifies the size in bytes of the output buffer, which must be greater than or equal to the size in bytes of a KEYBOARD_INDICATOR_PARAMETERS structure.

Output

AssociatedIrp.SystemBuffer points to a client-allocated buffer that the lower-level drivers use to output a KEYBOARD_INDICATOR_PARAMETERS structure.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of a KEYBOARD_INDICATOR_PARAMETERS structure.

The Status member is set to one the following values:

STATUS_SUCCESS
The request completed successfully.
STATUS_INVALID_PARAMETER
The UnitId value is not valid.
STATUS_BUFFER_TOO_SMALL
The output buffer cannot hold the KEYBOARD_INDICATOR_PARAMETERS structure.


IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION

Operation

The IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION request returns information on the mapping between scan codes and indicators.

Kbdclass copies the current stack location, sets the MajorFunction member of the new stack location to IRP_MJ_INTERNAL_DEVICE_CONTROL, and sends this request down the device stack.

Input

The Parameters.DeviceIoControl.InputBufferLength member is set to zero or a value greater than or equal to the size in bytes of a KEYBOARD_UNIT_ID_PARAMETER. A value of zero specifies a default unit ID of zero.

The AssociatedIrp.SystemBuffer member points to a client-allocated buffer that is used to input and output information. On input, AssociatedIrp.SystemBuffer points to a KEYBOARD_UNIT_ID_PARAMETER structure. The client sets the UnitId member of the input structure.

The Parameters.DeviceIoControl.OutputBufferLength member specifies the size in bytes of a client-allocated output buffer, which must be greater than or equal to the size in bytes of a KEYBOARD_INDICATOR_TRANSLATION structure. (Note that this structure includes an array of INDICATOR_LIST members and that the number of members in this array is device-specific.)

Output

AssociatedIrp.SystemBuffer points to a client-allocated buffer that the lower-level drivers use to output a KEYBOARD_INDICATOR_TRANSLATION structure.

I/O Status Block

If the request is successful, the Information member is set to the number of bytes of translation data in the KEYBOARD_INDICATOR_TRANSLATION structure.

The Status member is set to one of the following values:

STATUS_SUCCESS
The request completed successfully.
STATUS_INVALID_PARAMETER
The UnitId value is not valid.
STATUS_BUFFER_TOO_SMALL
The output buffer cannot hold the KEYBOARD_INDICATOR_TRANSLATION data.
STATUS_NOT_SUPPORTED
The target device is associated with a subordinate class device.


IOCTL_KEYBOARD_QUERY_TYPEMATIC

Operation

The IOCTL_KEYBOARD_QUERY_TYPEMATIC request returns the typematic settings.

Kbdclass copies the current stack location, sets the MajorFunction member of the new stack location to IRP_MJ_INTERNAL_DEVICE_CONTROL, and sends this request down the device stack.

Input

The Parameters.DeviceIoControl.InputBufferLength member is set to zero or a value greater than or equal to the size in bytes of a KEYBOARD_UNIT_ID_PARAMETER. A value of zero specifies a default unit ID of zero.

The AssociatedIrp.SystemBuffer member points to a client-allocated buffer that is used to input and output information. On input, AssociatedIrp.SystemBuffer points to a KEYBOARD_UNIT_ID_PARAMETER structure. The client sets the UnitId member of the input structure.

Output

AssociatedIrp.SystemBuffer points to the client-allocated buffer that the lower-level drivers use to output a KEYBOARD_TYPEMATIC_PARAMETERS structure.

I/O Status Block

If the request is successful, the Information member is set to the number of bytes of a KEYBOARD_TYPEMATIC_PARAMETERS structure.

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_INVALID_PARAMETER
The UnitId value is not valid.
STATUS_BUFFER_TOO_SMALL
The output buffer cannot hold the KEYBOARD_TYPEMATIC_PARAMETERS data.


IOCTL_KEYBOARD_SET_INDICATORS

Operation

The IOCTL_KEYBOARD_SET_INDICATORS request sets the keyboard indicators.

Kbdclass copies the current stack location, sets the MajorFunction member of the new stack location to IRP_MJ_INTERNAL_DEVICE_CONTROL, and sends this request down the driver stack.

If there is a grandmaster device, Kbdclass normally sets the keyboard indicators of all the subordinate class devices to a global setting. This operation is controlled by the registry entry value SendOutputToAllPorts under the key HKLM\Services\CurrentControlSet\Kbdclass\Parameters. If SendOutputToAllPorts is nonzero, Kdbclass sets all subordinate class devices to a gobal setting. Otherwise, Kbdclass sets only the device whose unit ID is zero.

Input

The Parameters.DeviceIoControl.InputBufferLength member specifies the size in bytes of a KEYBOARD_INDICATOR_PARAMETER structure.

The AssociatedIrp.SystemBuffer member points to a client-allocated KEYBOARD_INDICATOR_PARAMETERS structure. The client sets the UnitId and LedFlags members.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_BUFFER_TOO_SMALL
The value of Parameters.DeviceIoControl.InputBufferLength is less than the size in bytes of a KEYBOARD_INDICATOR_PARAMETER structure.
STATUS_INVALID_PARAMETER
The UnitId value is invalid.
STATUS_IO_TIMEOUT
The requested operation timed out on the device.


IOCTL_KEYBOARD_SET_TYPEMATIC

Operation

The IOCTL_KEYBOARD_SET_TYPEMATIC request sets the typematic parameters.

Kbdclass copies the current stack location, sets the MajorFunction member of the new stack location to IRP_MJ_INTERNAL_DEVICE_CONTROL, and sends this request down the device stack.

Note that if there is a grandmaster device, Kbdclass normally sets the typematic settings of all the subordinate class devices to the same global setting. This operation is controlled by the grandmaster's registry entry value SendOutputToAllPorts under the key HKLM\Services\CurrentControlSet\Kbdclass\Parameters.

Input

The Parameters.DeviceIoControl.InputBufferLength member is set to a value greater than or equal to the size in bytes of a KEYBOARD_TYPEMATIC_PARAMETERS structure.

The AssociatedIrp.SystemBuffer member points to a client-allocated KEYBOARD_TYPEMATIC_PARAMETERS structure. The client sets the UnitId, Rate, and Delay member values.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_BUFFER_TOO_SMALL
Parameters.DeviceIoControl.InputBufferLength is less than the size in bytes of a KEYBOARD_TYPEMATIC_PARAMETERS structure.
STATUS_INVALID_PARAMETER
The UnitId value is invalid.
STATUS_IO_TIMEOUT
The operation timed out.


Kbdclass Class Service Callback Routine

This section describes KeyboardClassServiceCallback, the keyboard class service callback routine.

Kbdclass uses an IOCTL_INTERNAL_KEYBOARD_CONNECT request to connect its class service callback to a keyboard device.


KeyboardClassServiceCallback

The KeyboardClassServiceCallback routine is the class service callback that is provided by Kbdclass. A function driver calls the class service callback in its ISR dispatch completion routine. The class service callback transfers input data from the input data buffer of a device to the class data queue.

VOID
  KeyboardClassServiceCallback (
    IN PDEVICE_OBJECT  DeviceObject,
    IN PKeyboard_INPUT_DATA  InputDataStart,
    IN PKeyboard_INPUT_DATA  InputDataEnd,
    IN OUT PULONG  InputDataConsumed
    );

Parameters

DeviceObject
Pointer to the class device object.
InputDataStart
Pointer to the first KEYBOARD_INPUT_DATA structure in the port device's input buffer.
InputDataEnd
Pointer to the keyboard data packet that immediately follows the last data packet in the port device's input data buffer.
InputDataConsumed
Pointer to the number of keyboard data packets that are transferred by the routine.

Include

kbdclass.h

Comments

KeyboardClassServiceCallback transfers input data from the input buffer of the device to the class data queue. This routine is called by the ISR dispatch completion routine of the function driver.

KeyboardClassServiceCallback can be supplemented by a filter service callback that is provided by an upper-level keyboard filter driver. A filter service callback filters the keyboard data that is transferred to the class data queue. For example, the filter service callback can delete, transform, or insert data. Kbfiltr, the sample filter driver in the Windows DDK, includes KbFilter_ServiceCallback, which is a template for a keyboard filter service callback.

KeyboardClassServiceCallback runs in kernel mode at IRQL=DISPATCH_LEVEL.


Kbdclass Structures

This section describes the following Kbdclass structures:

KEYBOARD_INPUT_DATA


KEYBOARD_INPUT_DATA

KEYBOARD_INPUT_DATA contains one packet of keyboard input data.

typedef struct _KEYBOARD_INPUT_DATA {
  USHORT  UnitId;
  USHORT  MakeCode;
  USHORT  Flags;
  USHORT  Reserved;
  ULONG  ExtraInformation;
} KEYBOARD_INPUT_DATA, *PKEYBOARD_INPUT_DATA;

Members

UnitId
Specifies the port unit ID for the keyboard device. For example, the unit ID of device \Device\KeyboardPort0 is zero, the unit ID of device \Device\KeyboardPort1 is one, and so on. The Microsoft® Windows® Win32® subsystem does not use this value.
MakeCode
Specifies the scan code associated with a key press.
Flags
Specifies a bitwise OR of one or more of the following flags that indicate whether a key was pressed or released, and other miscellaneous information.
Value | Meaning
KEY_MAKE | The key was pressed.
KEY_BREAK | The key was released.
KEY_E0 | Extended scan code used to indicate special keyboard functions. See the Kbdclass sample code.
KEY_E1 | Extended scan code used to indicate special keyboard functions. See the Kbdclass sample code.

Reserved
Reserved for operating system use.
ExtraInformation
Specifies device-specific information associated with a keyboard event.

Headers

Declared in ntddkbd.h. Include ntddkbd.h.

Comments

In response to an IRP_MJ_READ request, Kbdclass transfers zero or more KEYBOARD_INPUT_DATA structures from its internal data queue to the Win32 subsystem buffer.

See Also

IRP_MJ_READ, KeyboardClassServiceCallback


Mouclass Driver Reference

This section includes the following topics about Mouclass, the Microsoft® Windows® 2000 and later system class driver for device class GUID_CLASS_MOUSE:

Major I/O Requests

Device Control Requests

Callback Routines

Structures

Windows uses Mouclass as the class driver for all mouse devices installed in a system. The Windows Win32® subsystem opens all mouse devices for its exclusive use. Applications can not open the mouse devices opened by Mouclass.

Mouclass can work in combination with an optional upper-level mouse filter driver for a PS/2-style mouse device. Moufiltr, a sample upper-level mouse filter driver in the Windows DDK, can be used to customize the operation of a mouse device.

For more information on Mouclass, see the following topics:

  • Keyboard and Mouse Drivers for Non-HID Devices
  • Include file ntddkbd.h in the \inc directory of the Windows DDK
  • Sample code in the \src\input directory of the Windows DDK

Note Mouclass supports legacy devices and Plug and Play devices. When appropriate, this material distinguishes between the operation of Mouclass for a legacy device and a Plug and Play device. If no distinction is made, the description applies to both legacy and Plug and Play devices.


Mouclass Major I/O Requests

This section describes Mouclass-specific operation of the following major I/O requests:

IRP_MJ_CLEANUP

IRP_MJ_CLOSE

IRP_MJ_CREATE

IRP_MJ_DEVICE_CONTROL

IRP_MJ_FLUSH_BUFFERS

IRP_MJ_INTERNAL_DEVICE_CONTROL

IRP_MJ_PNP

IRP_MJ_POWER

IRP_MJ_READ

IRP_MJ_SYSTEM_CONTROL

For more information about how Mouclass handles the generic operation of these requests, see IRP Function Codes and IOCTLs.


IRP_MJ_CLOSE

Operation

Plug and Play Operation
Mouclass sends the request down the device stack and clears the "trusted" file that is permitted read access to the device. If there is a grandmaster device, Mouclass sends a request to close to all the ports associated with the subordinate class devices.
Legacy operation
Mouclass sends an IOCTL_INTERNAL_MOUSE_DISABLE request to the port driver. Mouclass also clears the "trusted" file that is permitted read access to the device.

I/O Status Block

Plug and Play Operation
The Information member is set to zero.

Mouclass sets the Status member to STATUS_SUCCESS or to the status returned by the function driver for the IRP_MJ_CLOSE request.

Legacy Operation
The Information member is set to zero.

The Status member is set to STATUS_SUCCESS or to the status returned by the port driver for the IOCTL_INTERNAL_MOUSE_DISABLE request.


IRP_MJ_CREATE

Operation

The IRP_MJ_CREATE request opens a file on mouse device.

Plug and Play Operation
If the device is started, Mouclass sends the IRP_MJ_CREATE request down the device stack. If the device is not started, Mouclass completes the request without sending the request down the driver stack. Mouclass sets the "trusted" file that is permitted read access to the device. If there is a grandmaster device, Mouclass sends a create request to all the mouse devices associated with the subordinate class device objects.
Legacy Operation
Mouclass sends a synchronous IOCTL_INTERNAL_MOUSE_ENABLE request down the device stack.

I/O Status Block

Plug and Play Operation
The Information member of the IRP is set to zero.

The Status member is set to one of the following values:

STATUS_SUCCESS
The request completed successfully.
STATUS_UNSUCCESFFUL
The device is not started.
STATUS_Xxx
A lower-level driver returned an error status.
Legacy Operation
The Information member is set to zero.

The Status member is set to STATUS_SUCCESS or the status returned by a lower-level driver for the IOCTL_INTERNAL_MOUSE_ENABLE request.


IRP_MJ_DEVICE_CONTROL

Mouclass supports the following major device control request:

IOCTL_MOUSE_QUERY_ATTRIBUTES

For most other device control requests, Mouclass skips the current IRP stack location and sends the request down the device stack to be completed by a lower-level driver. If Mouclass does not support the request, Mouclass completes the request with a status of STATUS_INVALID_DEVICE_REQUEST.

For more information on device control requests, see Mouclass Device Control Requests.


IRP_MJ_FLUSH_BUFFERS

Operation

The IRP_MJ_FLUSH_BUFFERS request clears the internal data queue.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the following values:

STATUS_SUCCESS
The request completed successfully.
STATUS_NOT_SUPPORTED
The target device is associated with a subordinate class device that does not support flushing the internal data queue.
STATUS_PRIVILEGE_NOT_HELD


IRP_MJ_INTERNAL_DEVICE_CONTROL

Operation

Mouclass skips the current IRP stack location and sends the internal device control request down the device stack to be completed by a lower-level driver.


IRP_MJ_PNP

Operation

Mouclass processes the following Plug and Play requests:

IRP_MN_REMOVE_DEVICE

IRP_MN_START_DEVICE

IRP_MN_STOP_DEVICE

For all other Plug and Play requests, Mouclass copies the current IRP stack location and sends the request down the device stack without further processing.

For more information on the generic operation of these requests, see Plug and Play IRPs.

I/O Status Block

Under normal operation the status block values are specific to the minor function request. If a Plug and Play request is sent in error to a legacy device, Mouclass completes the request with a status of STATUS_NOT_SUPPORTED.


IRP_MJ_POWER

Operation

Mouclass supports the following power requests and, as appropriate, sends them down the device stack:

IRP_MN_SET_POWER

IRP_MN_QUERY_POWER

IRP_MN_WAIT_WAKE

For all other power requests, Mouclass copies the current IRP stack location, requests the next power request, and sends the request down the device stack.

For more information on the generic operation of these requests, see Handling Power IRPs.

I/O Status Block

Under normal operation the status block values are specific to the minor function request. If a power request is sent in error to a grandmaster device or a legacy device, Mouclass completes the request with a status of STATUS_NOT_SUPPORTED.


IRP_MJ_READ

Operation

The IRP_MJ_READ request transfers zero or more MOUSE_INPUT_DATA structures from the internal data queue to the Win32 subsystem buffer. If there is no data in the data queue, a read request remains pending until it is completed or canceled.

The read request is not sent down the device stack and is completed by Mouclass.

A read request can be canceled. A read request is not executed if a cleanup is in progress when the request is received.

Note that a read request can be completed successfully only if it is made by a trusted subsystem. The Win32 subsystem is currently the only trusted subsystem. Mouclass performs a privilege check to enforce this restriction.

Input

Parameters.Read.Length member specifies the size in bytes of zero or more of MOUSE_INPUT_DATA structures.

Output

The AssociatedIrp.SystemBuffer member points to an output buffer that is allocated by the Win32 subsystem to output the requested number of MOUSE_INPUT_DATA structures.

I/O Status Block

The Information member specifies the number of bytes transferred to the Win32 subsystem buffer. The number of bytes that are transferred is the smallest of the requested number of bytes and the number of bytes currently in the data queue.

The Status member is set to one of the following values:

STATUS_SUCCESS
At least one MOUSE_INPUT_DATA structure was transferred.
STATUS_BUFFER_TOO_SMALL
The number of requested bytes is not an integer multiple of the size in bytes of a MOUSE_INPUT_DATA structure.
STATUS_PRIVILEGE_NOT_HELD
The requesting subsystem does not have read privileges.
STATUS_CANCELLED
The request was canceled before the transfer actually took place.


IRP_MJ_SYSTEM_CONTROL

Operation

Mouclass uses WmiSystemControl to handle WMI system control requests. Mouclass registers the following types of WMI library callback routines, which WmiSystemControl calls to handle WMI requests sent to a device:

DpWmiQueryReginfo

DpWmiQueryDataBlock

DpWmiSetDataBlock

DpWmiSetDataItem

For all other system control requests, Mouclass skips the current IRP stack location and sends the request down the device stack without further processing.

Mouclass updates WMI registration information after a device is started or removed. The driver calls the IoWMIRegistrationControl routine to update WMI registration information.

I/O Status Block

For WMI requests, Mouclass sets the Status member to one of the following values:

STATUS_SUCCESS
The request completed successfully.
STATUS_BUFFER_TOO_SMALL
The output buffer size, in bytes, is less than the required size to return the requested information.
STATUS_INVALID_DEVICE_REQUEST
The device request is not valid.
STATUS_WMI_GUID_NOT_FOUND
The WMI GUID was not found.
STATUS_WMI_READ_ONLY
The WMI data is read-only.

If Mouclass does not handle the request and sends it down the device stack, the Status member is set by a lower-level driver.


Mouclass Device Control Requests

This section describes the following device control requests that Mouclass supports:

IOCTL_MOUSE_QUERY_ATTRIBUTES

Mouclass changes this device control request into an internal device control request and sends the changed request down the device stack.

Mouclass also sends a number of other device control requests for Plug and Play devices down the device stack without changing the request to an internal device control request. For a list of these requests, see IOCTL_Xxx Device Control Requests.

Filter drivers between the class and function drivers can filter these requests before they send the request down the device stack or after the lower-level drivers complete the request.

If Mouclass does not support the request, it completes the request with a status of STATUS_INVALID_DEVICE_REQUEST.


IOCTL_MOUSE_QUERY_ATTRIBUTES

Operation

The IOCTL_MOUSE_QUERY_ATTRIBUTES request returns information about the mouse attributes.

Mouclass copies the current stack location, sets the MajorFunction member of the new stack location to IRP_MJ_INTERNAL_DEVICE_CONTROL, and sends this request down the device stack.

For more information on this request, see I8042prt Mouse Internal Device Control Requests.

Input

The Parameters.DeviceIoControl.InputBufferLength member is set to zero or a value greater than or equal to the size in bytes of a MOUSE_UNIT_ID_PARAMETER. A value of zero specifies a default unit ID of zero.

The AssociatedIrp.SystemBuffer member points to a client-allocated buffer that is used to input and output information. On input, AssociatedIrp.SystemBuffer points to a MOUSE_UNIT_ID_PARAMETER structure. The client sets the UnitId member of the input structure.

The Parameters.DeviceIoControl.OutputBufferLength member specifies the size in bytes of an output buffer, which must be greater than or equal to the size in bytes of a MOUSE_ATTRIBUTES structure.

Output

AssociatedIrp.SystemBuffer points to the client-allocated buffer that the lower-level drivers use to output a MOUSE_ATTRIBUTES structure.

I/O Status Block

The Information member is set to the number of bytes of attribute data that are returned if the request is successful.

The Status member is set to one of the following values:

STATUS_SUCCESS
The request completed successfully.
STATUS_INVALID_PARAMETER
The UnitId value is invalid.
STATUS_BUFFER_TOO_SMALL
The Parameters.DeviceIoControl.InputBufferLength value is greater than zero but less than the size in bytes of a MOUSE_UNIT_ID_PARAMETER structure.
STATUS_NOT_SUPPORTED
The target device is associated with a subordinate class device.


IOCTL_Xxx Device Control Requests

Mouclass skips the current IRP stack and sends the following control requests down the device stack to be completed by a lower-level driver:

IOCTL_GET_SYS_BUTTON_CAPS

IOCTL_GET_SYS_BUTTON_EVENT

IOCTL_HID_GET_DRIVER_CONFIG

IOCTL_HID_SET_DRIVER_CONFIG

IOCTL_HID_GET_POLL_FREQUENCY_MSEC

IOCTL_HID_SET_POLL_FREQUENCY_MSEC

IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS

IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS

IOCTL_HID_GET_COLLECTION_INFORMATION

IOCTL_HID_GET_COLLECTION_DESCRIPTOR

IOCTL_HID_FLUSH_QUEUE

IOCTL_HID_SET_FEATURE

IOCTL_HID_GET_FEATURE

IOCTL_GET_PHYSICAL_DESCRIPTOR

IOCTL_HID_GET_HARDWARE_ID

IOCTL_HID_GET_MANUFACTURER_STRING

IOCTL_HID_GET_PRODUCT_STRING

IOCTL_HID_GET_SERIALNUMBER_STRING

IOCTL_HID_GET_INDEXED_STRING


Mouclass Class Service Callback Routine

This section describes MouseClassServiceCallback, the mouse class service callback routine.

Mouclass uses an IOCTL_INTERNAL_MOUSE_CONNECT request to connect its class service callback to a mouse device.


MouseClassServiceCallback

The MouseClassServiceCallback routine is the class service callback that is provided by Mouclass. A function driver calls the class service callback in its ISR dispatch completion routine. The class service callback transfers input data from the input data buffer of a device to the class data queue.

VOID
  MouseClassServiceCallback(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PMOUSE_INPUT_DATA  InputDataStart,
    IN PMOUSE_INPUT_DATA  InputDataEnd,
    IN OUT PULONG  InputDataConsumed
    );

Parameters

DeviceObject
Pointer to the class device object.
InputDataStart
Pointer to the first mouse data packet, a MOUSE_INPUT_DATA structure, in the port device's input buffer.
InputDataEnd
Pointer to the mouse data packet that immediately follows the last data packet in the port device's input data buffer.
InputDataConsumed
Pointer to the number of mouse data packets that are transferred by the routine.

Include

mouclass.h

Comments

MouseClassServiceCallback transfers input data from the input buffer of the device to the class data queue. This routine is called by the ISR dispatch completion routine of the function driver.

MouseClassServiceCallback can be supplemented by a filter service callback that is provided by an upper-level mouse filter driver. A filter service callback can filter the mouse data that is transferred to the class data queue. For example, the filter service callback can delete, transform, or insert data. Moufiltr, the sample filter driver in the Microsoft® Windows® DDK, includes MouFilter_ServiceCallback, which is a template for a filter service callback.

MouseClassServiceCallback runs in kernel mode at IRQL DISPATCH_LEVEL.


MouClass Structures

This section describes the following MouClass structures:

MOUSE_INPUT_DATA


MOUSE_INPUT_DATA

MOUSE_INPUT_DATA contains one packet of mouse input data.

typedef struct MOUSE_INPUT_DATA {
  USHORT  UnitId;
  USHORT  Flags;
  union {
    ULONG  Buttons;
      struct {
         USHORT  ButtonFlags;
         USHORT  ButtonData;
      };
  };
  ULONG  RawButtons;
  LONG  LastX;
  LONG  LastY;
  ULONG  ExtraInformation;
} MOUSE_INPUT_DATA, *PMOUSE_INPUT_DATA;

Members

UnitID
Specifies the zero-based number of the pointer port device that is the source of the mouse data. For example, the unit number of device \Device\PointerPort0 is zero, the unit number of device \Device\PointerPort1 is one, and so on. The Microsoft® Windows® Win32® subsystem does not use this value.
Flags
Specifies a bitwise OR of one or more of the following mouse indicator flags.
Value | Meaning
MOUSE_MOVE_RELATIVE | The LastX and LastY are set relative to the previous location.
MOUSE_MOVE_ABSOLUTE | The LastX and LastY values are set to absolute values.
MOUSE_VIRTUAL_DESKTOP | The mouse coordinates are mapped to the virtual desktop.
MOUSE_ATTRIBUTES_CHANGED | The mouse attributes have changed. The other data in the structure is not used.

Buttons
Specifies both ButtonFlags and ButtonData values. Mouclass uses Buttons in its interrupt service routine to do a fast single memory access to ButtonFlags and ButtonData.
ButtonFlags
Specifies the transition state of the mouse buttons.
Flag | Meaning
MOUSE_LEFT_BUTTON_DOWN | The left mouse button changed to down.
MOUSE_LEFT_BUTTON_UP | The left mouse button changed to up.
MOUSE_RIGHT_BUTTON_DOWN | The right mouse button changed to down.
MOUSE_RIGHT_BUTTON_UP | The right mouse button changed to up.
MOUSE_MIDDLE_BUTTON_DOWN | The middle mouse button changed to down.
MOUSE_MIDDLE_BUTTON_UP | The middle mouse button changed to up.
MOUSE_BUTTON_4_DOWN | The fourth mouse button changed to down.
MOUSE_BUTTON_4_UP | The fourth mouse button changed to up.
MOUSE_BUTTON_5_DOWN | The fifth mouse button changed to down.
MOUSE_BUTTON_5_UP | The fifth mouse button changed to up.
MOUSE_WHEEL | Mouse wheel data is present.

ButtonData
Specifies mouse wheel data, if MOUSE_WHEEL is set in ButtonFlags.
RawButtons
Specifies the raw state of the mouse buttons. The Win32 subsystem does not use this member.
LastX
Specifies the signed relative or absolute motion in the X direction.
LastY
Specifies the signed relative or absolute motion in the Y direction.
ExtraInformation
Specifies device-specific information.

Headers

Declared in ntddmou.h. Include ntddmou.h.

Comments

In response to IRP_MJ_READ requests, Mouclass transfers zero or more MOUSE_INPUT_DATA structures from its internal data queue to the Win32 subsystem buffer.

See Also

IRP_MJ_READ_Mouclass_KR, MouseClassServiceCallback


I8042prt Driver Reference

This section includes the following topics about I8042prt, the Microsoft® Windows® 2000 and later system function driver for a PS/2-style keyboard device and a PS/2-style mouse device:

I8042prt Keyboard Major I/O Requests

I8042prt Keyboard Internal Device Control Requests

I8042prt Mouse Internal Device Control Requests

I8042prt Keyboard Callback Routines

I8042prt Mouse Callback Routines

Note that the operational constraints of I8042prt do not apply to Sermouse, the Windows system function driver for a serial mouse.

For more information on I8042prt operation, see the following topics:

Keyboard and Mouse Drivers for Non-HID Devices

Include files ntddkbd.h and ntddmou.h in the %user's install path%\inc directory in the Windows DDK

Sample code in the %user's install path%\src\input directory in the Windows DDK


I8042prt Keyboard Major I/O Requests

This section describes the I8042prt-specific operation of the following major I/O requests that I8042prt supports for a keyboard device:

IRP_MJ_CLOSE

IRP_MJ_CREATE

IRP_MJ_PNP

IRP_MJ_POWER

IRP_MJ_SYSTEM_CONTROL

For information on how I8042prt handles the generic operation of these requests, see IRP Function Codes and IOCTLs.


IRP_MJ_CREATE

Operation

The IRP_MJ_CREATE request opens a file on a keyboard device.

Note that Kbdclass uses an IOCTL_INTERNAL_KEYBOARD_CONNECT request to connect to a device before Kbdclass can open the device. There can be only one connection to the device. For more information, see Open and Close a Keyboard and Mouse Device.

I8042prt completes the IRP_MJ_CREATE request.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the following status codes:

STATUS_SUCCESS
STATUS_INVALID_DEVICE_STATE
The keyboard class service is not connected.
STATUS_NO_SUCH_DEVICE
The keyboard device is not present.


IRP_MJ_DEVICE_CONTROL

I8042prt supports the following device control requests for a keyboard device:

IOCTL_GET_SYS_BUTTON_CAPS

IOCTL_GET_SYS_BUTTON_EVENT

These requests are used exclusively by the Power Manager.

No other device control requests are supported.

If the device is in a Plug and Play stopped state or removed state, or a request is not supported, I8042prt completes the request with a status of STATUS_INVALID_DEVICE_REQUEST.


IRP_MJ_INTERNAL_DEVICE_CONTROL

I8042prt supports the following internal device control requests:

IOCTL_INTERNAL_I8042_CONTROLLER_WRITE_BUFFER

IOCTL_INTERNAL_I8042_HOOK_KEYBOARD

IOCTL_INTERNAL_I8042_KEYBOARD_START_INFORMATION

IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER

IOCTL_INTERNAL_KEYBOARD_CONNECT

IOCTL_INTERNAL_KEYBOARD_DISCONNECT

IOCTL_KEYBOARD_QUERY_ATTRIBUTES

IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION

IOCTL_KEYBOARD_QUERY_INDICATORS

IOCTL_KEYBOARD_QUERY_TYPEMATIC

IOCTL_KEYBOARD_SET_INDICATORS

IOCTL_KEYBOARD_SET_TYPEMATIC

For more information on these requests, see I8042prt Keyboard Internal Device Control Requests.

I8042prt completes all other requests with a status of STATUS_INVALID_DEVICE_REQUEST.


IRP_MJ_PNP

Operation

I8042prt processes the following Plug and Play requests for a keyboard device:

IRP_MN_CANCEL_REMOVE_DEVICE

IRP_MN_CANCEL_STOP_DEVICE

IRP_MN_FILTER_RESOURCE_REQUIREMENTS

IRP_MN_QUERY_PNP_DEVICE_STATE

IRP_MN_QUERY_REMOVE_DEVICE

IRP_MN_QUERY_STOP_DEVICE

IRP_MN_REMOVE_DEVICE

IRP_MN_START_DEVICE

For all other Plug and Play requests, I8042prt skips the current IRP stack and sends the request down the device stack.

For more information on the generic operation of these requests, see Plug and Play IRPs.

I/O Status Block

The status block values are function-specific.


IRP_MJ_POWER

Operation

I8042prt processes the following power requests for a keyboard device:

IRP_MN_SET_POWER

For all other power requests, I8042prt skips the current IRP stack, requests the next power IRP, and sends the request down the device stack.

For more information on the generic operation of these requests, see Handling Power IRPs.

I/O Status Block

The status block values are function-specific.


IRP_MJ_SYSTEM_CONTROL

Operation

I8042prt supports the following Windows® Management Instrumentation (WMI) system control requests for a keyboard device:

IRP_MN_REGINFO

IRP_MN_QUERY_DATA_BLOCK

For all other system control requests, I8042prt skips the current IRP stack location, and sends the request down the device stack to be completed by a lower-level driver.

I8042prt calls WmiSystemControl to process WMI requests. I8042prt registers the WMI data block that contains a KEYBOARD_PORT_WMI_STD_DATA structure.

When Called

The WDM provider sends an IRP_MN_REGINFO request after a driver calls IoWMIRegistrationControl to update WMI registration information – see DpWmiQueryReginfo. The port driver updates WMI registration information when the device is started and removed.

At the request of a WMI client, the WDM provider sends an IRP_MN_QUERY_DATA_BLOCK request to the port driver to obtain a data block containing a keyboard KEYBOARD_PORT_WMI_STD_DATA structure.

I/O Status Block

If the request is handled by I8042prt, the Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_INVALID_DEVICE_REQUEST
STATUS_WMI_GUID_NOT_FOUND
The data block GUID is not valid.
STATUS_WMI_INSTANCE_NOT_FOUND
The WMI context is not valid.


I8042prt Keyboard Internal Device Control Requests

This section describes the following internal device control requests that I8042prt supports for a keyboard device:

IOCTL_INTERNAL_I8042_CONTROLLER_WRITE_BUFFER

IOCTL_INTERNAL_I8042_HOOK_KEYBOARD

IOCTL_INTERNAL_I8042_KEYBOARD_START_INFORMATION

IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER

IOCTL_INTERNAL_KEYBOARD_CONNECT

IOCTL_INTERNAL_KEYBOARD_DISCONNECT

IOCTL_KEYBOARD_QUERY_ATTRIBUTES

IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION

IOCTL_KEYBOARD_QUERY_INDICATORS

IOCTL_KEYBOARD_QUERY_TYPEMATIC

IOCTL_KEYBOARD_SET_INDICATORS

IOCTL_KEYBOARD_SET_TYPEMATIC

I8042prt completes all other internal device control with a status of STATUS_INVALID_DEVICE_REQUEST.


IOCTL_INTERNAL_I8042_CONTROLLER_WRITE_BUFFER

Operation

The IOCTL_INTERNAL_I8042_CONTROLLER_WRITE_BUFFER request is not supported.

I/O Status Block

The Status member is set to STATUS_NOT_SUPPORTED.


IOCTL_INTERNAL_I8042_HOOK_KEYBOARD

Operation

The IOCTL_INTERNAL_I8042_HOOK_KEYBOARD request adds the following callback routines to I8042prt's operation:

  • An optional initialization callback routine that I8042prt calls when it initializes a keyboard
  • An optional callback routine into I8042prt's interrupt service routine

These optional callback routines are added by an upper-level filter driver for the keyboard device.

After I8042prt receives an IOCTL_INTERNAL_KEYBOARD_CONNECT request, it sends a synchronous IOCTL_INTERNAL_I8042_HOOK_KEYBOARD request to the top of the keyboard device stack. When the upper-level filter driver receives this request, the filter driver sets the keyboard IsrRoutine member and the keyboard InitializationRoutine member of the INTERNAL_I8042_HOOK_KEYBOARD structure that is passed with the request.

Input

The Parameters.DeviceIoControl.Type3InputBuffer points to an INTERNAL_I8042_HOOK_KEYBOARD structure. This structure includes:

  • The InitializationRoutine member that points to a callback routine that is called by I8042prt's initialization service routine
  • The IsrRoutine member that points to a callback routine that is called by I8042prt's interrupt service routine

I/O Status Block

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_INVALID_PARAMETER
Parameters.DeviceIoControl.Type3InputBuffer is less than the size in bytes of an INTERNAL_I8042_HOOK_KEYBOARD structure.


IOCTL_INTERNAL_I8042_KEYBOARD_START_INFORMATION

Operation

The IOCTL_INTERNAL_I8042_KEYBOARD_START_INFORMATION request passes a pointer to a keyboard interrupt object. I8042prt sends this request synchronously to the top of the device stack after the keyboard interrupt object is created. Upper-level filter drivers that need to synchronize their callback operation with the keyboard interrupt service routine (ISR) can use the pointer to the keyboard interrupt object. For more information on this request, see Synchronize the Operation of a Filter Driver with a Device's Interrupt Service Routine.

Input

The AssociatedIrp.SystemBuffer points to a buffer allocated by I8042prt to input an INTERNAL_I8042_START_INFORMATION structure.

The Parameters.DeviceIoControl.InputBufferLength specifies the size in bytes of an INTERNAL_I8042_START_INFORMATION structure.

I/O Status Block

The Information member is set to zero.

The Status member is set to STATUS_SUCCESS.


IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER

Operation

The IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER request writes data to the i8042 controller to control operation of a keyboard device. A filter driver can use this request to control the operation of a keyboard.

I8042prt synchronizes write buffer requests and other keyboard requests that write to the i8042 controller, including IOCTL_KEYBOARD_SET_INDICATORS and IOCTL_KEYBOARD_SET_TYPEMATIC. I8042prt synchronizes the actual write of data with the keyboard ISR.

Input

The Parameters.DeviceIoControl.InputBufferLength is set to the number of bytes in the input buffer, which must be greater than one.

The Parameters.DeviceIoControl.Type3InputBuffer points to a client-allocated buffer to input the data to write to an i8042 controller.

I/O Status Block

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_DEVICE_NOT_READY
The keyboard interrupt is not initialized.
STATUS_INVALID_PARAMETER
The input parameters are not valid.
STATUS_IO_TIMEOUT
The request timed out.


IOCTL_INTERNAL_KEYBOARD_CONNECT

Operation

The IOCTL_INTERNAL_KEYBOARD_CONNECT request connects the Kbdclass service to the keyboard device.

After I8042prt receives a keyboard connect request, it sends a synchronous IOCTL_INTERNAL_I8042_HOOK_KEYBOARD request to the top of keyboard device stack. The connect request is completed after the IOCTL_INTERNAL_I8042_HOOK_KEYBOARD request is completed.

For more information, Connect a Class Service Callback and a Filter Service Callback to a Device.

Input

The Parameters.DeviceIoControl.Type3InputBuffer points to a CONNECT_DATA structure. This structure includes a pointer to a device object and a pointer to a class service callback routine. The connect data is set by Kbdclass and can be filtered (reset) by a filter driver below Kbdclass in the device stack.

The Parameters.DeviceIoControl.InputBufferLength specifies the size in bytes of a CONNECT_DATA structure.

I/O Status Block

The Information member is set by the port driver.

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_INVALID_PARAMETER
Parameters.DeviceIoControl.InputBufferLength is less than the size in bytes of a CONNECT_DATA structure.
STATUS_SHARING_VIOLATION
The port driver is already connected.


IOCTL_INTERNAL_KEYBOARD_DISCONNECT

Operation

The IOCTL_INTERNAL_KEYBOARD_DISCONNECT request is not implemented.

Note that the Plug and Play Manager can dynamically add and remove Plug and Play devices.

I/O Status Block

The Status member is set to STATUS_NOT_IMPLEMENTED.


IOCTL_KEYBOARD_QUERY_ATTRIBUTES

Operation

The IOCTL_KEYBOARD_QUERY_ATTRIBUTES request returns information about the keyboard attributes.

Input

The Parameters.DeviceIoControl.OutputBufferLength member is set to a value greater than or equal to the size in bytes of a KEYBOARD_ATTRIBUTES structure.

Output

AssociatedIrp.SystemBuffer points to a client-allocated buffer that I8042prt uses to output a KEYBOARD_ATTRIBUTES structure.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of a KEYBOARD_ATTRIBUTES structure. Otherwise the Information member is set to zero.

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_BUFFER_TOO_SMALL
Parameters.DeviceIoControl.OutputBufferLength is less than the size in bytes of a KEYBOARD_ATTRIBUTES structure.


IOCTL_KEYBOARD_QUERY_INDICATORS

Operation

The IOCTL_KEYBOARD_QUERY_INDICATORS request returns information about the keyboard indicators.

Input

The Parameters.DeviceIoControl.OutputBufferLength is set to a value greater than or equal to the size in bytes of a KEYBOARD_INDICATOR_PARAMETERS structure.

Output

AssociatedIrp.SystemBuffer points to a client-allocated buffer that I8042prt uses to output a KEYBOARD_INDICATOR_PARAMETERS structure.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of a KEYBOARD_INDICATOR_PARAMETERS structure. Otherwise, Information is set to zero.

The Status member is set to one the following values:

STATUS_SUCCESS
STATUS_BUFFER_TOO_SMALL
Parameters.DeviceIoControl.OutputBufferLength is less than the size in bytes of a KEYBOARD_INDICATOR_PARAMETERS structure.


IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION

Operation

The IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION request returns information about the mapping between scan codes and keyboard indicators.

Input

The Parameters.DeviceIoControl.OutputBufferLength is set to a value greater than or equal to the size in bytes of a device-specific KEYBOARD_INDICATOR_TRANSLATION structure. This structure includes a variable-sized array of INDICATOR_LIST members that is device-specific.

Output

AssociatedIrp.SystemBuffer points to a client-allocated buffer that I8042prt uses to output a KEYBOARD_INDICATOR_TRANSLATION structure. This structure includes a variable-sized array of INDICATOR_LIST members that is device-specific.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of the device-specific KEYBOARD_INDICATOR_TRANSLATION structure. Otherwise, Information is set to zero.

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_BUFFER_TOO_SMALL
Parameters.DeviceIoControl.OutputBufferLength is less than the size in bytes of the device-specific KEYBOARD_INDICATORS_TRANSLATION structure.


IOCTL_KEYBOARD_QUERY_TYPEMATIC

Operation

The IOCTL_KEYBOARD_QUERY_TYPEMATIC request returns the keyboard typematic settings.

Input

The Parameters.DeviceIoControl.OutputBufferLength member is set to a value greater than or equal to the size in bytes of a KEYBOARD_TYPEMATIC_PARAMETERS structure.

Output

AssociatedIrp.SystemBuffer points to a client-allocated output buffer that I8042prt uses to output a KEYBOARD_TYPEMATIC_PARAMETERS structure.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of a KEYBOARD_TYPEMATIC_PARAMETERS structure. Otherwise, Information is set to zero.

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_BUFFER_TOO_SMALL
Parameters.DeviceIoControl.OutputBufferLength is less than the size in bytes of a KEYBOARD_TYPEMATIC_PARAMETERS structure.


IOCTL_KEYBOARD_SET_INDICATORS

Operation

The IOCTL_KEYBOARD_SET_INDICATORS request sets the keyboard indicators.

Input

The AssociatedIrp.SystemBuffer member points to a client-allocated buffer to input a KEYBOARD_INDICATORS_PARAMETERS structure. The client sets the indicator parameters in this structure.

The Parameters.DeviceIoControl.InputBufferLength member is set to a value greater than or equal to the size in bytes of a KEYBOARD_INDICATORS_PARAMETERS structure.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_DEVICE_NOT_READY
STATUS_INVALID_PARAMETER
Parameters.DeviceIoControl.InputBufferLength is less than the size in bytes of a KEYBOARD_INDICATORS_PARAMETERS structure, or the specified indicator parameters are invalid.
STATUS_IO_TIMEOUT
The request timed out.


IOCTL_KEYBOARD_SET_TYPEMATIC

Operation

The IOCTL_KEYBOARD_SET_TYPEMATIC request sets the keyboard typematic settings.

Input

The AssociatedIrp.SystemBuffer member points to a client-allocated buffer to input a KEYBOARD_TYPEMATIC_PARAMETERS structure. The client sets the typematic parameters in this structure.

The Parameters.DeviceIoControl.InputBufferLength member is set to a value greater than or equal to the size in bytes of a KEYBOARD_TYPEMATIC_PARAMETERS structure.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_DEVICE_NOT_READY
STATUS_INVALID_PARAMETER
Parameters.DeviceIoControl.InputBufferLength is less than the size in bytes of a KEYBOARD_TYPEMATIC_PARAMETERS structure, or the specified typematic settings are invalid.
STATUS_IO_TIMEOUT
The request timed out.


I8042prt Mouse Major I/O Requests

This section describes the I8042prt-specific operation of the following major I/O requests for a mouse device:

IRP_MJ_CLOSE

IRP_MJ_CREATE

IRP_MJ_DEVICE_CONTROL

IRP_MJ_INTERNAL_DEVICE_CONTROL

IRP_MJ_PNP

IRP_MJ_POWER

IRP_MJ_SYSTEM_CONTROL

For the generic operation of these requests, see IRP Function Codes and IOCTLs.


IRP_MJ_CREATE

Operation

The IRP_MJ_CREATE request opens a file on a mouse device.

Note that Mouclass uses an IOCTL_INTERNAL_MOUSE_CONNECT request to connect to a mouse device before Mouclass can open the device. There can be only one connection to the device. For more information, see Open and Close a Keyboard and Mouse Device.

I8042prt completes the IRP_MJ_CREATE request.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_INVALID_DEVICE_STATE
The Mouclass service is not connected.
STATUS_NO_SUCH_DEVICE
The device is not present.


IRP_MJ_DEVICE_CONTROL

I8042prt does not support any device control requests for a mouse device.

I8042prt completes all device control requests with a status of STATUS_INVALID_DEVICE_REQUEST.


IRP_MJ_INTERNAL_DEVICE_CONTROL

I8042prt supports the following internal device control requests for a mouse device:

IOCTL_INTERNAL_I8042_HOOK_MOUSE

IOCTL_INTERNAL_I8042_MOUSE_START_INFORMATION

IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER

IOCTL_INTERNAL_MOUSE_CONNECT

IOCTL_INTERNAL_MOUSE_DISCONNECT

IOCTL_MOUSE_QUERY_ATTRIBUTES

For more information on these requests, see I8042prt Mouse Internal Device Control Requests.

I8042prt completes all other internal device control requests with a status of STATUS_INVALID_DEVICE_REQUEST.


IRP_MJ_PNP

I8042prt processes the following Plug and Play requests for a mouse device:

IRP_MN_CANCEL_REMOVE_DEVICE

IRP_MN_CANCEL_STOP_DEVICE

IRP_MN_FILTER_RESOURCE_REQUIREMENTS

IRP_MN_QUERY_PNP_DEVICE_STATE

IRP_MN_QUERY_REMOVE_DEVICE

IRP_MN_QUERY_STOP_DEVICE

IRP_MN_REMOVE_DEVICE

IRP_MN_START_DEVICE

For all other Plug and Play requests, I8042prt skips the current IRP stack and sends the request down the device stack.

For more information on the generic operation of these requests, see Plug and Play IRPs.

I/O Status Block

The values of the status block members are function-specific.


IRP_MJ_POWER

Operation

I8042prt processes the following power requests for a mouse device:

IRP_MN_SET_POWER

For all other power requests, I8042prt skips the current IRP stack, requests the next power IRP, and sends the request down the device stack.

For more information on the generic operation of these requests, see Handling Power IRPs.

I/O Status Block

The values of the status block members are function-specific.


IRP_MJ_SYSTEM_CONTROL

Operation

I8042prt supports the following Windows® Management Instrumentation (WMI) system control requests for a mouse device:

IRP_MN_REGINFO

IRP_MN_QUERY_DATA_BLOCK

For all other system control requests, I8042prt skips the current IRP stack location and sends the request down the device stack to be completed by a lower-level driver.

I8042prt calls WmiSystemControl to process WMI requests. I8042prt registers a WMI data block that contains a POINTER_PORT_WMI_STD_DATA structure.

When Called

The WDM provider sends an IRP_MN_REGINFO request after the port driver calls IoWMIRegistrationControl to update WMI registration information – see DpWmiQueryReginfo. I8042prt updates WMI registration information when the device is started and removed.

At the request of a WMI client, the WDM provider sends an IRP_MN_QUERY_DATA_BLOCK request to I8042prt. This request obtains a WMI data block containing a POINTER_PORT_WMI_STD_DATA structure.

I/O Status Block

If I8042prt handles the request, the Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_INVALID_DEVICE_REQUEST
STATUS_WMI_GUID_NOT_FOUND
The data block GUID is not valid.
STATUS_WMI_INSTANCE_NOT_FOUND
The WMI context is not valid.


I8042prt Mouse Internal Device Control Requests

I8042prt supports the following internal device control requests for a mouse device:

IOCTL_INTERNAL_I8042_HOOK_MOUSE

IOCTL_INTERNAL_I8042_MOUSE_START_INFORMATION

IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER

IOCTL_INTERNAL_MOUSE_CONNECT

IOCTL_INTERNAL_MOUSE_DISCONNECT

IOCTL_MOUSE_QUERY_ATTRIBUTES

I8042prt completes all other device control requests with a status of STATUS_INVALID_DEVICE_REQUEST.


IOCTL_INTERNAL_I8042_HOOK_MOUSE

Operation

The IOCTL_INTERNAL_I8042_HOOK_MOUSE request adds an optional callback routine into the interrupt service routine that I8042prt provides for a mouse device.

The optional callback routine is provided by an optional upper-level filter driver for the mouse device.

After I8042port receives an IOCTL_INTERNAL_MOUSE_CONNECT request request, it sends a synchronous IOCTL_INTERNAL_I8042_HOOK_MOUSE request to the top of the keyboard device stack. When the upper-level filter driver receives this request, the filter driver sets the mouse IsrRoutine member of the INTERNAL_I8042_HOOK_MOUSE structure that is passed with the request.

Input

The Parameters.DeviceIoControl.Type3InputBuffer points to an INTERNAL_I8042_HOOK_MOUSE structure. This structure includes an IsrRoutine member that points to a callback that is called by the interrupt service routine that I8042prt provides for a mouse device.

I/O Status Block

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_INVALID_PARAMETER
Parameters.DeviceIoControl.Type3InputBuffer is less than the size in bytes of an INTERNAL_I8042_HOOK_MOUSE structure.


IOCTL_INTERNAL_I8042_MOUSE_START_INFORMATION

Operation

The IOCTL_INTERNAL_I8042_MOUSE_START_INFORMATION request passes a pointer to a mouse interrupt object. I8042prt sends this request synchronously to the top of the device stack after the mouse interrupt object is created. Upper-level filter drivers that need to synchronize their callback operation with the mouse ISR can use the pointer to the mouse interrupt object. For more information on this request, see Synchronize the Operation of a Filter Driver with a Device's ISR.

Input

The AssociatedIrp.SystemBuffer points to an input buffer allocated by I8042prt to input an INTERNAL_I8042_START_INFORMATION structure.

The Parameters.DeviceIoControl.InputBufferLength specifies the size in bytes of an INTERNAL_I8042_START_INFORMATION structure.

I/O Status Block

The Information member is set to zero.

The Status member is set to STATUS_SUCCESS.


IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER

Operation

The IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER request writes data to the i8042 controller to control operation of a mouse device. An upper-level filter driver can use this request to control the operation of a mouse.

I8042prt synchronizes write buffer requests with one another. I8042prt synchronizes the actual write of data with the mouse ISR.

Input

The Parameters.DeviceIoControl.InputBufferLength is set to the number of bytes in the input buffer, which must be greater than one.

The Parameters.DeviceIoControl.Type3InputBuffer points to a client-allocated buffer to input the data to write to an i8042 controller.

I/O Status Block

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_DEVICE_NOT_READY
The mouse interrupt is not initialized.
STATUS_INVALID_PARAMETER
The input parameters are not valid.
STATUS_IO_TIMEOUT
The request timed out.


IOCTL_INTERNAL_MOUSE_CONNECT

Operation

The IOCTL_INTERNAL_MOUSE_CONNECT request connects the Mouclass service to a mouse device.

After I8042prt receives a mouse connect request, it sends a synchronous INTERNAL_I8042_HOOK_MOUSE request to the top of mouse device stack. The connect request is completed after the INTERNAL_I8042_HOOK_MOUSE request is completed.

For more information, see Connect a Class Service Callback and a Filter Service Callback to a Device.

Input

The Parameters.DeviceIoControl.Type3InputBuffer points to a CONNECT_DATA structure. This structure includes a pointer to a device object and a pointer to a mouse class service callback routine. The connect data is set by the class service and can be filtered (reset) by filter drivers.

The Parameters.DeviceIoControl.InputBufferLength specifies the size in bytes of a CONNECT_DATA structure.

I/O Status Block

The Information member is set by the port driver.

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_INVALID_PARAMETER
Parameters.DeviceIoControl.InputBufferLength is less than the size in bytes of a CONNECT_DATA structure.
STATUS_SHARING_VIOLATION
The port driver is already connected.


IOCTL_INTERNAL_MOUSE_DISCONNECT

Operation

The IOCTL_INTERNAL_MOUSE_DISCONNECT request is not implemented.

Note that the Plug and Play Manager can dynamically add and remove Plug and Play devices.

I/O Status Block

The Status member is set to STATUS_NOT_IMPLEMENTED.


IOCTL_MOUSE_QUERY_ATTRIBUTES

Operation

The IOCTL_MOUSE_QUERY_ATTRIBUTES request returns information about the mouse attributes.

Input

The Parameters.DeviceIoControl.OutputBufferLength member is set to a value greater than or equal to the size in bytes of a MOUSE_ATTRIBUTES structure.

Output

AssociatedIrp.SystemBuffer points to a client-allocated output buffer that I8042prt uses to output a MOUSE_ATTRIBUTES structure.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of a MOUSE_ATTRIBUTES structure. Otherwise, the Information member is set to zero.

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_BUFFER_TOO_SMALL
Parameters.DeviceIoControl.OutputBufferLength is less than the size in bytes of a MOUSE_ATTRIBUTES structure.


I8042prt Keyboard Callback Routines

This section describes the following keyboard callback routines that I8042prt supports:

  • Callbacks that an upper-level keyboard filter driver can provide to supplement the operation of I8042prt:

    Keyboard InitializationRoutine

    Keyboard IsrRoutine

  • Callbacks that I8042prt provides that an upper-level keyboard filter driver can use:

    Keyboard IsrWritePort

    QueueKeyboardInput

I8042prt uses an IOCTL_INTERNAL I8042_HOOK_KEYBOARD request to add, or hook, the filter driver callbacks into the operation of I8042prt. The hook request also passes pointers to the I8042prt keyboard callbacks to the filter driver.


Keyboard InitializationRoutine

The keyboard InitializationRoutine callback routine supplements the default initialization of a keyboard device by I8042prt.

NTSTATUS
  (*InitializationRoutine)(
    IN PVOID  InitializationContext,
    IN PVOID  SynchFuncContext,
    IN PI8042_SYNCH_READ_PORT  ReadPort,
    IN PI8042_SYNCH_WRITE_PORT  WritePort,
    OUT PBOOLEAN  TurnTranslationOn
    );

Parameters

InitializationContext
Pointer to the filter device object of the driver that supplies the callback routine.
SynchFuncContext
Pointer to the context for the routines pointed to by ReadPort and Writeport.
ReadPort
Pointer to a routine that reads from the port.
WritePort
Pointer to a routine that writes to the port.
TurnTranslationOn
Specifies whether to turn translation on or off. If TranslationOn is TRUE, translation is turned on; otherwise, translation is turned off.

Include

ntdd8042.h

Return Value

The keyboard InitializationRoutine callback returns an appropriate NTSTATUS code.

Comments

An upper-level keyboard filter driver can provide a keyboard InitializationRoutine callback routine.

If an upper-level keyboard filter driver supplies an initialization callback, I8042prt calls the filter initialization callback when I8042prt initializes the keyboard. Default keyboard initialization includes the following operations: reset the keyboard, set the typematic rate and delay, and set the light-emitting diodes (LED).

The keyboard InitializationRoutine callback runs in kernel mode at IRQL DISPATCH_LEVEL.

See Also

KbFilter_InitializationRoutine


Keyboard IsrRoutine

The keyboard IsrRoutine callback routine customizes the operation of a keyboard ISR.

(*IsrRoutine)(
    IN PVOID  IsrContext,
    IN PKEYBOARD_INPUT_DATA  CurrentInput,
    IN POUTPUT_PACKET  CurrentOutput,
    IN OUT UCHAR  StatusByte,
    IN PUCHAR  DataByte,
    OUT PBOOLEAN  ContinueProcessing,
    IN PKEYBOARD_SCAN_STATE  ScanState
    );

Parameters

IsrContext
Pointer to the filter device object of the driver that supplies a callback routine.
CurrentInput
Pointer to the input KEYBOARD_DATA_INPUT structure that is being constructed by the ISR.
CurrentOutput
Pointer to the array of bytes that is being written to the hardware device.
StatusByte
Specifies the status byte that is read from I/O port 60 when an interrupt occurs.
DataByte
Specifies the data byte that is read from I/O port 64 when an interrupt occurs.
ContinueProcessing
Specifies whether processing in the ISR will continue after this routine completes.
ScanState
Specifies the keyboard scan state.

Include

ntdd8042.h

Return Value

The keyboard IsrRoutine callback returns TRUE if the interrupt service routine should continue; otherwise it returns FALSE.

Comments

A keyboard IsrRoutine callback routine is not needed if the default operation of I8042prt's ISR is sufficient.

An upper-level keyboard filter driver can provide a keyboard IsrRoutine callback. I8042prt's ISR calls the callback after it validates the interrupt and reads the scan code.

The keyboard IsrRoutine callback runs in kernel mode at the IRQL of the I8042prt's keyboard ISR.

See Also

KbFilter_IsrHook


Keyboard IsrWritePort

The keyboard IsrWritePort callback routine writes data to a keyboard device. I8042prt provides this routine.

VOID
  (*IsrWritePort)(
    IN PVOID  Context,
    IN UCHAR  Value
    );

Parameters

Context
Pointer to the function device object that represents a keyboard device.
Value
Specifies the data to write to a keyboard device.

Include

ntdd8042.h

Comments

The keyboard IsrWritePort callback routine should only be called by a keyboard IsrRoutine callback routine. I8042prt calls the keyboard IsrRoutine callback in its keyboard ISR.

I8042prt passes a pointer to the keyboard IsrWritePort callback routine in the IsrWritePort member of the INTERNAL_I8042_HOOK_KEYBOARD structure that I8042prt uses with an IOCTL_INTERNAL_I8042_HOOK_KEYBOARD request.

See Also

I8042prt Callbacks that Filter Drivers Can Use, INTERNAL_I8042_HOOK_KEYBOARD


QueueKeyboardInput

The QueueKeyboardInput callback routine queues a keyboard input data packet for processing by the ISR DPC of the keyboard. I8042prt provides this routine.

(*QueueKeyboardInput)(
    IN PVOID  Context
    );

Parameters

Context
Pointer to the function device object that represents a keyboard device.

Include

ntdd8042.h

Comments

The QueueKeyboardInput callback routine should only be called by a keyboard IsrRoutine callback routine. I8042prt calls the keyboard IsrRoutine callback in its keyboard ISR. I8042prt passes a pointer to the callback in the QueueKeyboardInput member of the INTERNAL_I8042_HOOK_KEYBOARD structure that I8042prt uses with an IOCTL_INTERNAL_I8042_HOOK_KEYBOARD request.

See Also

I8042prt Callbacks that Filter Drivers Can Use


I8042prt Mouse Callback Routines

This section describes the following mouse callback routines that I8042prt supports:

  • Callbacks that an upper-level mouse filter driver can provide to supplement the operation of I8042prt:
    • Mouse IsrRoutine
  • Callbacks that I8042prt provides that an upper-level mouse filter driver can use:
    • Mouse IsrWritePort
    • QueueMouseInput

I8042prt uses an IOCTL_INTERNAL_I8042_HOOK_MOUSE request to add, or hook, the filter driver callbacks into the operation of I8042prt. The hook request also passes pointers to the I8042prt mouse callbacks to the filter driver.


Mouse IsrRoutine

The mouse IsrRoutine routine customizes the operation of the mouse ISR.

BOOLEAN
  (*IsrRoutine)(
    IN PVOID  IsrContext,
    IN PMOUSE_INPUT_DATA  CurrentInput,
    IN POUTPUT_PACKET  CurrentOutput,
    IN UCHAR  StatusByte,
    IN OUT PUCHAR  Byte,
    OUT PBOOLEAN  ContinueProcessing,
    IN PMOUSE_STATE  MouseState,
    IN PMOUSE_RESET_SUBSTATE  ResetSubState
    );

Parameters

IsrContext
Pointer to the filter device object of the driver that supplies this callback routine.
CurrentInput
Pointer to the input MOUSE_DATA_INPUT structure being constructed by the ISR.
CurrentOutput
Pointer to the array of bytes being written to the hardware device.
StatusByte
Specifies a status byte that is read from I/O port 60 when the interrupt occurs.
Byte
Specifies a data byte that is read from I/O port 64 when the interrupt occurs.
ContinueProcessing
Specifies a flag indicating whether processing in the ISR will continue after this routine completes.
MouseState
Specifies the mouse state.
ResetSubState
Specifies a mouse substate.

Include

ntdd8042.h

Return Value

The mouse IsrRoutine callback routine returns TRUE if the interrupt service routine should continue; otherwise it returns FALSE.

Comments

A mouse IsrRoutine callback routine is not needed if the default operation of I8042prt is sufficient.

An upper-level keyboard filter driver can provide a mouse IsrRoutine callback. After the I8042prt's mouse ISR validates the interrupt, it calls the IsrRoutine callback.

The mouse IsrRoutine routine runs in kernel mode at the IRQL of I8042prt's mouse ISR.

See Also

MouFilter_IsrHook


Mouse IsrWritePort

The mouse IsrWritePort callback routine writes data to a mouse device. I8042prt provides this routine.

VOID
  (*IsrWritePort)(
    IN PVOID  Context,
    IN UCHAR  Value
    );

Parameters

Context
Pointer to the function device object that represents a mouse device.
Value
Specifies the data to write to a mouse device.

Include

i8042prt.h

Comments

The mouse IsrWritePort callback routine should only be called by a mouse IsrRoutine callback routine. I8042prt calls the mouse IsrRoutine callback in its mouse ISR. I8042prt passes a pointer to this callback in the IsrWritePort member of an INTERNAL_I8042_HOOK_MOUSE structure that I8042prt uses with an IOCTL_INTERNAL_I8042_HOOK_MOUSE request.

See Also

I8042prt Callbacks that Filter Drivers Can Use


QueueMouseInput

The QueueMouseInput callback routine queues a mouse input data packet for processing by the device's ISR deferred procedure call (DPC). I8042prt provides this routine.

(*QueueMousePacket)(
    IN PVOID  Context
    );

Parameters

Context
Pointer to the function device object that represents a mouse device.

Include

ntdd8042prt.h

Comments

The QueueMouseInput callback routine should only be called by a mouse IsrRoutine callback routine. I8042prt calls the mouse IsrRoutine callback in its mouse ISR. I8042prt passes a pointer to the callback in the QueueMouseInput member of an INTERNAL_I8042_HOOK_MOUSE structure that I8042prt uses with an IOCTL_INTERNAL_I8042_HOOK_MOUSE request.

See Also

I8042prt Callbacks that Filter Drivers Can Use


Kbfiltr Driver Reference

This chapter includes the following topics about Kbfiltr, the sample upper-level keyboard filter driver in the Microsoft® Windows® DDK:

Internal Device Control Requests

Callback Routines

Kbfiltr is designed to be used with Kbdclass, the Windows 2000 and later system class driver for keyboard devices, and I8042prt, the Windows 2000 and later function driver for a PS/2-style keyboard. Kbfiltr demonstrates how to filter I/O requests and how to add callback routines that modify the operation of Kbdclass and I8042prt.

See the following topics for more information about Kbfiltr operation:

Keyboard and Mouse Drivers for Non-HID Devices

Include file %user's install path%\inc\ntddkbd.h in the Windows DDK

Sample Kbfiltr source code in the %user's install directory%\src\input\kbfiltr directory in the Windows DDK


Kbfiltr Internal Device Control Requests

This section describes the operation of the following internal device control requests:

IOCTL_INTERNAL_I8042_HOOK_KEYBOARD

IOCTL_INTERNAL_KEYBOARD_CONNECT

IOCTL_INTERNAL_KEYBOARD_DISCONNECT

For all other device control requests, Kbfiltr skips the current IRP stack and sends the request down the device stack without further processing.


IOCTL_INTERNAL_I8042_HOOK_KEYBOARD

Operation

The IOCTL_INTERNAL_I8042_HOOK_KEYBOARD request does the following:

  • Adds an initialization callback to I8042prt's keyboard initialization routine
  • Adds an ISR callback to I8042prt's interrupt service routine

The initialization and ISR callbacks are optional and are provided by an upper-level filter driver for a PS/2-style keyboard device.

After I8042prt receives an IOCTL_INTERNAL_KEYBOARD_CONNECT request, it sends a synchronous IOCTL_INTERNAL_I8042_HOOK_KEYBOARD request to the top of the keyboard device stack.

After Kbfiltr receives the hook keyboard request, Kbfiltr filters the request in the following way:

  • Saves the upper-level information passed to Kbfiltr, which includes the context of an upper-level device object, a pointer to an initialization callback, and a pointer to an ISR callback
  • Replaces the upper-level information with its own
  • Saves the context of I8042prt and pointers to callbacks that the Kbfiltr ISR callback can use

For more information on this request and the callback routines, see the following topics:

Operation of Non-HID Keyboard and Mouse Drivers

I8042prt Callback Routines

Kbfiltr Callback Routines

Input

The Parameters.DeviceIoControl.InputBufferLength member is set to a value greater than or equal to the size in bytes of an INTERNAL_I8042_HOOK_KEYBOARD structure.

The Parameters.DeviceIoControl.Type3InputBuffer points to an INTERNAL_I8042_HOOK_KEYBOARD structure. This structure includes the following members:

InitializationRoutine
Pointer to an optional callback routine that is called by I8042prt when it initializes a keyboard device.
IsrRoutine
Pointer to an optional callback routine that is called by the interrupt service routine of I8042prt.

I/O Status Block

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_INVALID_PARAMETER
Parameters.DeviceIoControl.InputBufferLength is less than the size in bytes of an INTERNAL_I8042_HOOK_KEYBOARD structure.


IOCTL_INTERNAL_KEYBOARD_CONNECT

Operation

The IOCTL_INTERNAL_KEYBOARD_CONNECT request connects the Kbdclass service to the keyboard device. Kbdclass sends this request down the keyboard device stack before it opens the keyboard device.

After Kbfiltr received the keyboard connect request, Kbfiltr filters the connect request in the following way:

  • Saves a copy of Kbdclass's CONNECT_DATA structure that is passed to the filter driver by Kbdclass
  • Substitutes its own connect information for the class driver connect information
  • Sends the IOCTL_INTERNAL_KEYBOARD_CONNECT request down the device stack

If the request is not successful, Kbfiltr completes the request with an appropriate error status.

Kbfiltr provides a template for a filter service callback that can supplement the operation of KeyboardClassServiceCallback, the Kbdclass class service callback. The filter service callback can filter the input data that is transferred from the device input buffer to the class data queue.

For more information on the connection of the Kbdclass service, see the following topics:

Connect a Class Service Callback and a Filter Service Callback to a Device

Kbdclass Callback Routines

Kbfiltr Callback Routines

Input

The Parameters.DeviceIoControl.InputBufferLength member is set to a value greater than or equal to the size in bytes of a CONNECT_DATA structure.

The Parameters.DeviceIoControl.Type3InputBuffer member points to a CONNECT_DATA structure that is allocated and set by Kbdclass.

Output

The Parameters.DeviceIoControl.Type3InputBuffer member points to a CONNECT_DATA structure that is set by Kbfiltr.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_INVALID_PARAMETER
Parameters.DeviceIoControl.InputBufferLength is less that the size in bytes of a CONNECT_DATA structure.
STATUS_SHARING_VIOLATION
Kbfiltr is already connected (the filter driver supports only one connect request).


IOCTL_INTERNAL_KEYBOARD_DISCONNECT

Operation

The IOCTL_INTERNAL_KEYBOARD_DISCONNECT request is completed with a status of STATUS_NOT_IMPLEMENTED. Note that a Plug and Play keyboard can be added or removed by the Plug and Play Manager.

I/O Status Block

The Status member is set to STATUS_NOT_IMPLEMENTED.


Kbfiltr Callback Routines

This section describes the following Kbfiltr callback routines:

KbFilter_InitializationRoutine

KbFilter_IsrHook

KbFilter_ServiceCallback


KbFilter_InitializationRoutine

The KbFilter_InitializationRoutine routine is a template for a keyboard InitializationRoutine callback routine that supplements the default initialization of a keyboard device by I8042prt.

NTSTATUS
  KbFilter_InitializationRoutine(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PVOID  SynchFuncContext,
    IN PI8042_SYNCH_READ_PORT  ReadPort,
    IN PI8042_SYNCH_WRITE_PORT  WritePort,
    OUT PBOOLEAN  TurnTranslationOn
    );

Parameters

DeviceObject
Pointer to the device object that is the context for this routine.
SynchFuncContext
Pointer to the context for the routines pointed to by ReadPort and Writeport.
ReadPort
Pointer to a routine that reads from the port.
WritePort
Pointer to a routine that writes to the port.
TurnTranslationOn
Specifies whether to turn translation on or off. If TranslationOn is TRUE, translation is turned on; otherwise, translation is turned off.

Include

kbfiltr.h

Return Value

KbFilter_InitializationRoutine returns an appropriate NTSTATUS code.

Comments

KbFilter_InitializationRoutine is not needed if I8042prt's default initialization of a keyboard is sufficient.

I8042prt calls KbFilter_InitializationRoutine when it initializes the keyboard. Default keyboard initialization includes the following operations: reset the keyboard, set the typematic rate and delay, and set the light-emitting diodes (LED).

KbFilter_InitializationRoutine runs in kernel mode at IRQL DISPATCH_LEVEL.

See Also

Keyboard InitializationRoutine


KbFilter_IsrHook

The KbFilter_IsrHook routine is a template for a keyboard IsrRoutine callback routine that customizes the operation of I8042prt's keyboard ISR.

KbFilter_IsrHook(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PKEYBOARD_INPUT_DATA  CurrentInput,
    IN POUTPUT_PACKET  CurrentOutput,
    IN OUT UCHAR  StatusByte,
    IN PUCHAR  DataByte,
    OUT PBOOLEAN  ContinueProcessing,
    IN PKEYBOARD_SCAN_STATE  ScanState
    );

Parameters

DeviceObject
Pointer to the filter device object of the driver that supplies this callback routine.
CurrentInput
Pointer to the input KEYBOARD_DATA_INPUT structure that is being constructed by the ISR.
CurrentOutput
Pointer to the array of bytes that is being written to the hardware device.
StatusByte
Specifies the status byte that is read from I/O port 60 when an interrupt occurs.
DataByte
Specifies the data byte that is read from I/O port 64 when an interrupt occurs.
ContinueProcessing
Specifies whether processing in the ISR will continue after this routine completes.
ScanState
Specifies the keyboard scan state.

Include

kbfiltr.h

Return Value

KbFilter_IsrHook returns TRUE if the interrupt service routine should continue; otherwise it returns FALSE.

Comments

This callback is not needed if the default operation of I8042prt is sufficient.

I8042prt's keyboard ISR calls KbFilter_IsrHook after it validates the interrupt and reads the scan code.

KbFilter_IsrHook runs in kernel mode at the IRQL of I8042prt's keyboard ISR.


KbFilter_ServiceCallback

The KbFilter_ServiceCallback routine is a template for a filter service callback that supplements the operation of KeyboardClassServiceCallback.

VOID
  KbFilter_ServiceCallback(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PKEYBOARD_INPUT_DATA  InputDataStart,
    IN PKEYBOARD_INPUT_DATA  InputDataEnd,
    IN OUT PULONG  InputDataConsumed
    );

Parameters

DeviceObject
Pointer to the class device object.
InputDataStart
Pointer to the first keyboard data packet (a KEYBOARD_INPUT_DATA structure) in the port device's input buffer.
InputDataEnd
Pointer to the keyboard data packet that immediately follows the last data packet in the port device's input data buffer.
InputDataConsumed
Pointer to the number of keyboard data packets that are transferred by the routine.

Include

kbfiltr.h

Comments

The ISR dispatch completion routine of the function driver calls KbFilter_ServiceCallback, which then calls KeyboardClassServiceCallback. The filter service callback can be configured to modify the input data that is transferred from the device's input buffer to the class data queue. For example, the callback can delete, transform, or insert data.

KbFilter_ServiceCallback runs in kernel mode at IRQL DISPATCH_LEVEL.


Moufiltr Driver Reference

This section includes the following topics about Moufiltr, the sample upper-level mouse filter driver in the Microsoft® Windows® DDK:

Internal Device Control Requests

Callback Routines

Moufiltr is designed to be used with Mouclass, the Windows 2000 and later system class driver for mouse devices, and I8042prt, the Windows 2000 and later function driver for a PS/2-style mouse. Moufiltr demonstrates how to filter I/O requests and add callback routines that modify the operation of Mouclass and I8042prt.

See the following topics for more information about Moufiltr operation:

Keyboard and Mouse Drivers for Non-HID Devices

Include file %user's install path%\inc\ntddmou.h in the Windows DDK

Sample Moufiltr source code in the %user's install directory%\src\input\Moufiltr directory in the Windows DDK


Moufiltr Internal Device Control Requests

This section describes the operation of the following internal device control requests that Moufiltr supports:

IOCTL_INTERNAL_I8042_HOOK_MOUSE

IOCTL_INTERNAL_MOUSE_CONNECT

IOCTL_INTERNAL_MOUSE_DISCONNECT

For all other requests, Moufiltr skips the current IRP stack and sends the request down the device stack without further processing.


IOCTL_INTERNAL_I8042_HOOK_MOUSE

Operation

The IOCTL_INTERNAL_I8042_HOOK_MOUSE request adds an ISR callback to I8042prt's interrupt service routine for a PS/2-style mouse. The ISR callback is optional and is provided by an upper-level mouse filter driver.

I8042prt sends this request after it receives an IOCTL_INTERNAL_MOUSE_CONNECT request. I8042prt sends a synchronous IOCTL_INTERNAL_I8042_HOOK_MOUSE request to the top of the mouse device stack.

After Moufiltr receives the hook mouse request, it filters the request in the following way:

  • Saves the upper-level information passed to Moufiltr, which includes the context of an upper-level device object and a pointer to an ISR callback
  • Replaces the upper-level information with its own
  • Saves the context of I8042prt and pointers to callbacks that the Moufiltr ISR callback routine can use

For more information on this request and the callback routines, see the following topics:

Operation of Non-HID Keyboard and Mouse Drivers

I8042prt Mouse Callback Routines

Moufiltr Callback Routines

Input

The Parameters.DeviceIoControl.InputBufferLength member is set to a value greater than or equal to the size in bytes of an INTERNAL_I8042_HOOK_MOUSE structure.

The Parameters.DeviceIoControl.Type3InputBuffer points to an INTERNAL_I8042_HOOK_MOUSE structure that is allocated and set initially by I8042prt.

I/O Status Block

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_INVALID_PARAMETER
Parameters.DeviceIoControl.InputBufferLength is less than the size in bytes of an INTERNAL_I8042_HOOK_MOUSE structure.


IOCTL_INTERNAL_MOUSE_CONNECT

Operation

The IOCTL_INTERNAL_MOUSE_CONNECT request connects Mouclass service to a mouse device. Mouclass sends this request down the device stack before it opens a mouse device.

After Moufiltr receives the mouse connect request, it filters the request in the following way:

  1. Saves a copy of CONNECT_DATA structure that was passed to Moufiltr
  2. Substitutes its own connect information for the class driver connect information
  3. Sends the IOCTL_INTERNAL_MOUSE_CONNECT request down the device stack

If the request is not successful, Moufiltr completes the request with an appropriate error status.

Moufiltr provides a template for a filter service callback that can supplement the operation of MouseClassServiceCallback, the Mouclass service callback. The filter service callback can filter the input data that is transferred from the device input buffer to the class driver data queue.

For more information on the connection of the Kbdclass service, see the following topics:

Connect a Class Service Callback and a Filter Service Callback to a Device

I8042prt Mouse Callback Routines

Moufiltr Callback Routines

Input

The Parameters.DeviceIoControl.InputBufferLength member is set to a value greater than or equal to the size in bytes of a CONNECT_DATA structure.

The Parameters.DeviceIoControl.Type3InputBuffer member points to a CONNECT_DATA structure that is allocated and set by Mouclass.

Output

The Parameters.DeviceIoControl.Type3InputBuffer member points to a CONNECT_DATA structure that is set by Moufiltr.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the following values:

STATUS_INVALID_PARAMETER
Parameters.DeviceIoControl.InputBufferLength is less than the size in bytes of a CONNECT_DATA structure.
STATUS_SHARING_VIOLATION
Moufiltr is already connected (a filter driver supports only one connect request).


IOCTL_INTERNAL_MOUSE_DISCONNECT

Operation

The IOCTL_INTERNAL_MOUSE_DISCONNECT request is completed by Moufiltr with an error status of STATUS_NOT_IMPLEMENTED. (Note that a Plug and Play mouse device can be added or removed by the Plug and Play Manager.)

I/O Status Block

The Status member is set to STATUS_NOT_IMPLEMENTED.


Moufiltr Callback Routines

This section describes the following Moufiltr callback routines:

MouFilter_IsrHook

MouFilter_ServiceCallback


MouFilter_IsrHook

MouFilter_IsrHook is a template for a mouse IsrRoutine callback routine that customizes the operation of I8042prt's mouse ISR.

BOOLEAN
  MouFilter_IsrHook(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PMOUSE_INPUT_DATA  CurrentInput,
    IN POUTPUT_PACKET  CurrentOutput,
    IN UCHAR  StatusByte,
    IN OUT PUCHAR  DataByte,
    OUT PBOOLEAN  ContinueProcessing,
    IN PMOUSE_STATE  MouseState,
    IN PMOUSE_RESET_SUBSTATE  ResetSubState
    );

Parameters

DeviceObject
Pointer to the filter device object of the driver that supplies this callback routine.
CurrentInput
Pointer to the input MOUSE_DATA_INPUT structure being constructed by the ISR.
CurrentOutput
Pointer to the array of bytes being written to the hardware device.
StatusByte
Specifies a status byte that is read from I/O port 60 when the interrupt occurs.
DataByte
Specifies a data byte that is read from I/O port 64 when the interrupt occurs.
ContinueProcessing
Specifies a flag indicating whether processing in the ISR will continue after this routine completes.
MouseState
Specifies the mouse state.
ResetSubState
Specifies a mouse substate.

Include

moufiltr.h

Return Value

MouFilter_IsrHook returns TRUE if the interrupt service routine should continue; otherwise it returns FALSE.

Comments

A MouFilter_IsrHook callback routine is not needed if the default operation of I8042prt is sufficient.

I8042prt's ISR calls MouFilter_IsrHook after it validates the interrupt.

MouFilter_IsrHook runs in kernel mode at the IRQL of I8042prt's ISR for mouse device.


MouFilter_ServiceCallback

MouFilter_ServiceCallback is a template for a filter service callback that supplements MouseClassServiceCallback.

VOID
  MouFilter_ServiceCallback(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PMOUSE_INPUT_DATA  InputDataStart,
    IN PMOUSE_INPUT_DATA  InputDataEnd,
    IN OUT PULONG  InputDataConsumed
    );

Parameters

DeviceObject
Pointer to the class device object.
InputDataStart
Pointer to the first mouse data packet (a MOUSE_INPUT_DATA structure) in the input data buffer of the port device.
InputDataEnd
Pointer to the mouse data packet immediately following the last mouse data packet in the port device's input data buffer.
InputDataConsumed
Pointer to the number of mouse data packets that are transferred by the routine.

Include

moufiltr.h

Comments

The ISR DPC of I8042prt calls MouFilter_ServiceCallback, which then calls MouseClassServiceCallback. A filter service callback can be configured to modify the input data that is transferred from the device's input buffer to the class data queue. For example, the callback can delete, transform, or insert data.

MouFilter_ServiceCallback runs in kernel mode at IRQL DISPATCH_LEVEL.


DirectInput Reference

This section contains reference information for the API elements provided by Microsoft® DirectInput®. The reference material is described in the following topics:

DirectInput Interfaces

DirectInput Callbacks

DirectInput Kernel-Mode Service Macros

DirectInput Structures

DirectInput Messages


DirectInput Interfaces

Microsoft® DirectInput® defines the following interfaces:

  • IDirectInputEffectDriver. This interface exposes methods that DirectInput uses for user-mode force feedback.
  • IDirectInputJoyConfig8.This interface exposes methods that allow hardware developers who are writing property sheets to get information in and out of the registry.
  • IDIGameCntrlPropSheet This interface exposes methods that define the control panel property sheet.


IDirectInputEffectDriver

The IDirectInputEffectDriver interface exposes the following methods:

DestroyEffect

DeviceID

DownloadEffect

Escape

GetEffectStatus

GetForceFeedbackState

GetVersions

SendForceFeedbackCommand

SetGain

StartEffect

StopEffect

In addition, all COM interfaces inherit the following IUnknown interface methods:

AddRef

QueryInterface

Release

These three methods allow additional interfaces to be added to the DirectInputEffectDriver object without affecting the functionality of the original interface.


IDirectInputEffectDriver::AddRef

The IDirectInputEffectDriver::AddRef method increases the reference count of the DirectInputEffectDriver object by 1. This method is part of the IUnknown interface inherited by DirectInputEffectDriver.

HRESULT
  IDirectInputEffectDriver::AddRef(
    );

Parameters

None

Return Value

Returns S_OK if successful; otherwise returns an error.

Comments

When the DirectInputEffectDriver object is created, its reference count should be set to 1. Each time an application obtains an interface to the object or calls the AddRef method, the object's reference count is increased by 1. The application uses the Release method to decrease the reference count of the object by 1.


IDirectInputEffectDriver::DestroyEffect

The IDirectInputEffectDriver::DestroyEffect method removes an effect from the device. If the effect is playing, the driver should stop it before unloading it.

HRESULT
  IDirectInputEffectDriver::DestroyEffect(
    DWORD  dwID,
    DWORD  dwEffect
    );

Parameters

dwID
Specifies the external joystick number being addressed.
dwEffect
Specifies the effect to be destroyed.

Return Value

Returns S_OK if successful; otherwise returns an error..


IDirectInputEffectDriver::DeviceID

The IDirectInputEffectDriver::DeviceID method signals the driver of the identity of the device. For example, if a device driver is passed dwExternalID = 2 and dwInternalID = 1, then unit 1 on the device corresponds to joystick ID number 2.

HRESULT
  IDirectInputEffectDriver::DeviceID(
    DWORD  dwDIVer,
    DWORD  dwExternalID,
    DWORD  fBegin,
    DWORD  dwInternalId,
    LPVOID  lpReserved
    );

Parameters

dwDIVer
Specifies the version number of DirectInput that loaded the effect driver. For example, DirectInput 5.0 passes the value 0x00000500.
dwExternalID
Specifies the joystick ID number. The Microsoft® Windows® joystick subsystem allocates external IDs.
fBegin
Specifies the availability of the device. This value is nonzero if access to the device is beginning. This is zero if the access to the device is ending.
dwInternalId
Specifies the ID of the internal joystick. The device driver manages internal IDs.
pvReserved
Reserved for future use.

Return Value

Returns S_OK if successful; otherwise returns an error.


IDirectInputEffectDriver::DownloadEffect

The IDirectInputEffectDriver::DownloadEffect method sends an effect to the device.

HRESULT
  IDirectInputEffectDriver::DownloadEffect(
    DWORD  dwID,
    DWORD  dwEffectID,
    LPDWORD  pdwEffect,
    LPCDIEFFECT  peff,
    DWORD  dwFlags
    );

Parameters

dwID
Specifies the external joystick number being addressed.
dwEffectID
Specifies the dwEffectId member of the DIEFFECTATTRIBUTES structure associated with the effect the application is attempting to create. The DIEFFECTATTRIBUTES structure is stored in the registry under the corresponding effect registry key and can be any 32-bit value. DirectInput passes the 32-bit value to the driver with no interpretation.
pdwEffect
On entry, this parameter is a pointer to the handle of the effect being downloaded. If this parameter points to a zero, then a new effect is downloaded. On exit, this parameter is a pointer to a DWORD that contains the new effect handle. On failure, the DWORD pointed to by this parameter is set to zero if the effect is lost, or left alone if the effect is still valid with its old parameters. Note that zero is never a valid effect handle.
peff
Pointer to a DIEFFECT structure that describes the new effect. The axis and button values have been converted to object identifiers, which consist of the following:
One type specifier:
DIDFT_RELAXIS
DIDFT_ABSAXIS
DIDFT_PSHBUTTON
DIDFT_TGLBUTTON
DIDFT_POV
One instance identifier:
DIDFT_MAKEINSTANCE(n)

Other bits in the object identifier are reserved and should be ignored.

For example, 0x02000104 = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE(1) | other stuff

This value indicates that the effect uses button 1.

dwFlags
Specifies which portions of the effect information have changed from the effect already applied to the device. This information is passed to drivers to allow for the optimization of effect modification. If an effect is being modified, a driver may be able to update the effect in its original position and transmit to the device only the information that has changed. Drivers are not, however, required to implement this optimization. All members in the DIEFFECT structure pointed to by the peff parameter are valid, and a driver may choose simply to update all parameters of the effect at each download. (For information on the DIEFFECT structure, see the DirectInput section of the stand alone DirectX SDK.)

This parameter can be zero, one, or more of the following:

DIEP_DURATION
Indicates the dwDuration member of the DIEFFECT structure is being downloaded for the first time or has changed since its last download.
DIEP_SAMPLEPERIOD
Indicates the dwSamplePeriod member of the DIEFFECT structure is being downloaded for the first time or has changed since its last download.
DIEP_GAIN
Indicates the dwGain member of the DIEFFECT structure is being downloaded for the first time or has changed since its last download.
DIEP_TRIGGERBUTTON
Indicates the dwTriggerButton member of the DIEFFECT structure is being downloaded for the first time or has changed since its last download.
DIEP_TRIGGERREPEATINTERVAL
Indicates the dwTriggerRepeatInterval member of the DIEFFECT structure is being downloaded for the first time or has changed since its last download.
DIEP_AXES
Indicates the cAxes and rgdwAxes members of the DIEFFECT structure are being downloaded for the first time or have changed since their last download.
DIEP_DIRECTION
Indicates the cAxes and rglDirection members of the DIEFFECT structure are being downloaded for the first time or have changed since their last download. (The dwFlags member of the DIEFFECT structure specifies, through DIEFF_CARTESIAN or DIEFF_POLAR, the coordinate system in which the values should be interpreted.)
DIEP_ENVELOPE
Indicates the lpEnvelope member of the DIEFFECT structure is being downloaded for the first time or has changed since its last download. If this flag is set and the lpEnvelope member is a null pointer, then the effect is being created with no envelope, or the existing envelope is being deleted.
DIEP_TYPESPECIFICPARAMS
Indicates the cbTypeSpecificParams and lpTypeSpecificParams members of the DIEFFECT structure are being downloaded for the first time or have changed since their last download.
DIEP_START
Indicates that the effect is to be restarted from the beginning after the parameters of the effect have been updated. Note that the DIEP_NODOWNLOAD flag overrides the DIEP_START flag.
DIEP_NORESTART
If this flag is not specified, the effect device driver is permitted to restart the effect if doing so is necessary to change the specified parameters. Note that the DIEP_NODOWNLOAD and DIEP_START flags override this flag.
DIEP_NODOWNLOAD
Suppresses the automatic download that is normally performed after the parameters are updated. If this flag is set, the driver should validate parameters without performing an actual download.

Return Value

Returns S_OK if successful, or an error value otherwise.


IDirectInputEffectDriver::Escape

The IDirectInputEffectDriver::Escape method escapes to the driver. This method is called in response to an application invoking the IDirectInputEffect::Escape or IDirectInputDevice::Escape methods.

HRESULT
  IDirectInputEffectDriver::Escape(
    DWORD  dwID,
    DWORD  dwEffect,
    LPDIEFFESCAPE  pesc
    );

Parameters

dwID
Indicates the joystick ID number being used.
dwEffect
Specifies the effect at which the command is directed, or zero if the command is directed at the device itself and not any particular effect.
pesc
Pointer to a DIEFFESCAPE structure that describes the command to be sent. On success, the cbOutBuffer member contains the number of output buffer bytes actually used.

Return Value

Returns S_OK if successful; otherwise returns an error value.


IDirectInputEffectDriver::GetEffectStatus

The IDirectInputEffectDriver::GetEffectStatus method obtains information about the status of an effect.

HRESULT
  IDirectInputEffectDriver::GetEffectStatus(
    DWORD  dwID,
    DWORD  dwEffect,
    LPDWORD  pdwStatus
    );

arameters

dwID
Indicates the external joystick number being addressed.
dwEffect
Specifies the effect to be queried.
pdwStatus
Pointer to a DWORD that receives the effect status. The DWORD should be filled in with one of the following values:
DIEGES_PLAYING
The effect is still playing.
0
The effect is not playing.

Return Value

Returns S_OK if successful; otherwise returns an error value..


IDirectInputEffectDriver::GetForceFeedbackState

The IDirectInputEffectDriver::GetForceFeedbackState method retrieves the force-feedback state for the device.

HRESULT
  IDirectInputEffectDriver::GetForceFeedbackState(
    DWORD  dwID,
    LPDIDEVICESTATE  pds
    );

Parameters

dwID
Indicates the external joystick number being addressed.
pds
Pointer to a DIDEVICESTATE structure that receives the device state. DirectInput sets the dwSize member of the DIDEVICESTATE structure to sizeof(DIDEVICESTATE) before calling this method.

Return Value

Returns S_OK if successful; otherwise returns an error value.


IDirectInputEffectDriver::GetVersions

The IDirectInputEffectDriver::GetVersions method obtains version information about the force-feedback hardware and driver.

HRESULT
  IDirectInputEffectDriver::GetVersions(
    LPDIDRIVERVERSIONS  pvers
    );

Parameters

pvers
Pointer to a DIDRIVERVERSIONS structure that should be filled in with version information describing the hardware, firmware, and driver. DirectInput sets the dwSize member of the DIDRIVERVERSIONS structure to sizeof(DIDRIVERVERSIONS) before calling this method.

Return Value

Returns S_OK if successful; otherwise returns an error value.


IDirectInputEffectDriver::QueryInterface

The IDirectInputEffectDriver::QueryInterface method determines whether the DirectInputEffectDriver object supports a particular COM interface. If it does, the system increases the reference count for the object by 1, and the application can begin using that interface immediately. This method is part of the IUnknown interface inherited by DirectInputEffectDriver.

HRESULT
  IDirectInputEffectDriver::QueryInterface(
    REFIID  riid,
    LPVOID  *ppvObj
    );

Parameters

riid
Reference identifier of the interface being requested.
ppvObj
Address of a pointer to be filled with the interface pointer if the query is successful.

Return Value

Returns a COM error code.

Comments

When the application no longer needs to use the interface retrieved by a call to this method, it must call the Release method for that interface to free it.


IDirectInputEffectDriver::Release

The IDirectInputEffectDriver::Release method decreases the reference count of the DirectInputEffectDriver object by 1. This method is part of the IUnknown interface inherited by DirectInputEffectDriver.

HRESULT
  IDirectInputEffectDriver::Release(
    );

Parameters

None

Return Value

Returns the new reference count of the object.

Comments

The DirectInputEffectDriver object deallocates itself when its reference count reaches 0. Use the IDirectInputEffectDriver::AddRef method to increase the reference count of the object by 1.


IDirectInputEffectDriver::SendForceFeedbackCommand

The IDirectInputEffectDriver::SendForceFeedbackCommand method changes the force-feedback state for the device.

HRESULT
  IDirectInputEffectDriver::SendForceFeedbackCommand(
    DWORD  dwID,
    DWORD  dwCommand
    );

Parameters

dwID
Indicates the external joystick number being addressed.
dwCommand
Indicates which of the following commands is being sent:
DISFFC_RESET
Indicates that playback of any active effects should be stopped and that all effects should be removed from the device. Once the device has been reset, all effects are no longer valid and must be recreated.
DISFFC_STOPALL
Indicates that playback of all effects should be stopped. Sending the DISFFC_STOPALL command is equivalent to invoking the IDirectInputEffect::Stop method on all effects that are playing. If the device is in a paused state, the device driver is permitted to lose the paused state.
DISFFC_PAUSE
Indicates that playback of all effects should be paused. When effects are paused, time "stops" until the DISFFC_CONTINUE command is sent. For example, suppose an effect of five seconds duration is started. After one second, all effects are paused. After two more seconds, all effects are continued. The effect should then play for four additional seconds. While a force-feedback device is paused, starting a new effect or modifying existing ones can cause the paused state to be lost.
DISFFC_CONTINUE
Indicates that playback should be resumed at the point at which it was interrupted for those effects that were paused by a previous DISCFFC_PAUSE command.
DISFFC_SETACTUATORSON
Indicates that the device's force-feedback actuators should be enabled.
DISFFC_SETACTUATORSOFF
Indicates that the device's force-feedback actuators should be disabled. If successful, force feedback effects are "muted". Note that time continues to elapse while actuators are off. For example, suppose an effect of five seconds' duration is started. After one second, actuators are turned off. After two more seconds, actuators are turned back on. The effect should then play for two additional seconds.

Return Value

Returns S_OK if successful; otherwise returns an error value.


IDirectInputEffectDriver::SetGain

The IDirectInputEffectDriver::SetGain method sets the overall device gain.

HRESULT
  IDirectInputEffectDriver::SetGain(
    DWORD  dwID,
    DWORD  dwGain
    );

Parameters

dwID
Indicates the joystick ID number being used.
dwGain
Specifies the new gain value (1 to 10,000).

Return Value

Returns S_OK if successful; otherwise returns an error value.


IDirectInputEffectDriver::StartEffect

The IDirectInputEffectDriver::StartEffect method begins the playback of an effect. If the effect is already playing, it is restarted from the beginning.

HRESULT
  IDirectInputEffectDriver::StartEffect(
    DWORD  dwID,
    DWORD  dwEffect,
    DWORD  dwMode,
    DWORD  dwCount
    );

Parameters

dwID
Identifies the external joystick number being addressed
dwEffect
Specifies the effect to be played.
dwMode
Specifies how the effect is to affect other effects. Only the mode listed below can be used; all other modes are reserved. For example, the driver never receives the DIES_NODOWNLOAD flag because it is managed by DirectInput and not the driver. This parameter can be zero, one, or more of the following flags:
DIES_SOLO
Indicates that all other effects on the device should be stopped before the specified effect is played. If this flag is omitted, the effect is mixed with existing effects that have already started on the device.
dwCount
Specifies the number of times to perform the effect. If the value is INFINITE, then the effect should be repeated until explicitly stopped or paused.

Return Value

Returns S_OK if successful; otherwise returns an error value.


IDirectInputEffectDriver::StopEffect

The IDirectInputEffectDriver::StopEffect method halts the playback of an effect.

HRESULT
  IDirectInputEffectDriver::StopEffect(
    DWORD  dwID,
    DWORD  dwEffect
    );

Parameters

dwID
Indicates the external joystick number being addressed.
dwEffect
Specifies the effect to be stopped.

Return Value

Returns S_OK if successful; otherwise returns an error value.


IDirectInputJoyConfig8

The IDirectInputJoyConfig8 interface contains methods that allow hardware developers who are writing property sheets to write and read information to and from the registry.

Note If you need to open registry keys, you should use the IDirectInputJoyConfig8::OpenConfigKey and IDirectInputJoyConfig8::OpenTypeKey methods rather than opening registry keys directly. Using either of these methods ensures that the correct registry branch is opened. In addition, the IDirectInputJoyConfig8 interface will be supported in future versions of DirectInput when the underlying registry data may be structured differently.

The IDirectInputJoyConfig8 interface consists of the following methods:

Acquire

AddNewHardware

DeleteConfig

DeleteType

EnumTypes

GetConfig

GetTypeInfo

GetUserValues

OpenAppStatusKey

OpenConfigKey

OpenTypeKey

SendNotify

SetConfig

SetCooperativeLevel

SetTypeInfo

SetUserValues

Unacquire

In addition, all COM interfaces inherit the following IUnknown interface methods:

AddRef

QueryInterface

Release

These three methods allow additional interfaces to be added to the DirectInputJoyConfig object without affecting the functionality of the original interface.

Also please note the following difference between Windows Millennium Edition and Windows XP:

On Windows XP machines. Using the IDirectInputJoyConfig8 interface, use the instructions in the order described following to change the joystick ID:

    hres = GetConfig(uSrcID);
    if (SUCCEEDED(hres)) {
        SetConfig(uDstID);
        DeleteConfig(uSrcID);
    }

However, this order of instructions does not work on Windows 95/98/Me. For these operating systems, use code written as follows:

    hres = GetConfig(uSrcID);
    if (SUCCEEDED(hres)) {
        DeleteConfig(uSrcID);
        SetConfig(uDstID);
    }


IDirectInputJoyConfig8::Acquire

The IDirectInputJoyConfig8::Acquire method acquires "joystick configuration mode." Only one application can be in joystick configuration mode at a time; subsequent applications should receive the error DIERR_OTHERAPPHASPRIO. After entering configuration mode, the application can make alterations to the global joystick configuration settings. The application should check the existing settings before installing the new ones in case another application changed the settings in the interim.

HRESULT
  IDirectInputJoyConfig8::Acquire(
    );

Parameters

None

Return Value

Returns DI_OK on success; otherwise returns one of the following COM error values:

DIERR_OTHERAPPHASPRIO
Another application is already in joystick configuration mode.
DIERR_INSUFFICIENTPRIVS
The current user does not have the necessary permissions to alter the joystick configuration.
DIERR_DEVICECHANGE
Another application has changed the global joystick configuration. The interface needs to be re-initialized.


IDirectInputJoyConfig8::AddNewHardware

The IDirectInputJoyConfig8::AddNewHardware method displays the Add New Hardware dialog box to guide the user through installing a new input device.

HRESULT
  IDirectInputJoyConfig8::AddNewHardware(
    HWND  hwndOwner,
    REFGUID  rguidClass
    );

Parameters

hwndOwner
Handle to the window to act as owner window for the user interface.
rguidClass
GUID that specifies the class of the hardware device to be added. DirectInput comes with the following class GUIDs already defined:
GUID_KeyboardClass
Keyboard devices.
GUID_MouseClass
Mouse devices.
GUID_MediaClass
Media devices, including joysticks.
GUID_HIDClass
HID devices.

Return Value

Returns DI_OK on success; otherwise returns one of the following COM error values:

DIERR_INVALIDPARAM
E_INVALIDARG. One or more parameters was invalid.
DIERR_INVALIDCLASSINSTALLER
The class installer for the specified device could not be found or is invalid.
DIERR_CANCELLED
The user canceled the operation.
DIERR_BADINF
The INF file for the device that the user selected could not be found or is invalid or damaged.
S_FALSE
DirectInput could not determine whether the operation completed successfully.


IDirectInputJoyConfig8::AddRef

The IDirectInputJoyConfig8::AddRef method increases the reference count of the DirectInputJoyConfig object by 1. This method is part of the IUnknown interface inherited by DirectInputJoyConfig.

HRESULT
  IDirectInputJoyConfig8::AddRef(
    );

Parameters

None

Return Value

Returns the new reference count of the object.

Comments

When the DirectInputJoyConfig object is created, its reference count should be set to 1. Every time an application obtains an interface to the object or calls the AddRef method, the object's reference count is increased by 1. The application uses the Release method to decrease the reference count of the object by 1.


IDirectInputJoyConfig8::DeleteConfig

The IDirectInputJoyConfig8::DeleteConfig method deletes configuration information about a joystick.

HRESULT
  IDirectInputJoyConfig8::DeleteConfig(
    UINT  idJoy
    );

Parameters

idJoy
Indicates a zero-based joystick identification number.

Return Value

Returns DI_OK on success; otherwise returns one of the following COM error values (these values are intended to be illustrative and are not necessarily comprehensive):

DIERR_NOTACQUIRED
Joystick configuration has not been acquired. You must call IDirectInputJoyConfig8::Acquire before you can alter joystick configuration settings.
DIERR_INVALIDPARAM
One or more parameters was invalid.


IDirectInputJoyConfig8::DeleteType

The IDirectInputJoyConfig8::DeleteType method removes information about a joystick type. Use this method with caution; it is the caller's responsibility to ensure that no joystick refers to the deleted type.

HRESULT
  IDirectInputJoyConfig8::DeleteType(
    LPCWSTR  pwszTypeName
    );

Parameters

pwszTypeName
Pointer to the name of the type. The name of the type cannot exceed MAX_PATH characters, including the terminating null character. Also, the name cannot begin with a "#" character. Types beginning with "#" are reserved by DirectInput.

Return Value

Returns DI_OK on success; otherwise returns one of the following COM error values (these values are intended to be illustrative and are not necessarily comprehensive):

DIERR_NOTACQUIRED
Joystick configuration has not been acquired. You must call IDirectInputJoyConfig8::Acquire before you can alter joystick configuration settings.
DIERR_INVALIDPARAM
One or more parameters was invalid.


IDirectInputJoyConfig8::EnumTypes

The IDirectInputJoyConfig8::EnumTypes method enumerates the joystick types currently supported by DirectInput. A joystick type describes how DirectInput should communicate with a joystick device. It includes information such as the presence and location of each of the axes and the number of buttons supported by the device.

HRESULT
  IDirectInputJoyConfig8::EnumTypes(
    LPDIJOYTYPECALLBACK  lpCallback,
    LPVOID  pvRef
    );

Parameters

lpCallback
Pointer to an application-defined DIEnumJoyTypeProc callback function that receives the DirectInput joystick types.
pvRef
Specifies a 32-bit application-defined value to be passed to the callback function. This value can be any 32-bit value; it is prototyped as an LPVOID for convenience.

Return Value

Returns DI_OK on success; otherwise returns one of the following COM error values:

DIERR_INVALIDPARAM
One or more parameters was invalid.


IDirectInputJoyConfig8::GetConfig

The IDirectInputJoyConfig8::GetConfig method obtains information about a joystick's configuration.

HRESULT
  IDirectInputJoyConfig8::GetConfig(
    UINT  uiJoy,
    LPDIJOYCONFIG  pjc,
    DWORD  dwFlags
    );

Parameters

uiJoy
Indicates a joystick identification number. This is a non-negative integer. To enumerate joysticks, begin with joystick zero and increment the joystick number by one until the function returns DIERR_NOMOREITEMS.
pjc
Receives information about the joystick configuration. The caller "must" initialize the dwSize member of the DIJOYCONFIG structure before calling this method.
dwFlags
Specifies the members of the structure pointed to by pjc that are to be filled in. This parameter can be zero, one, or more of the following:
DIJC_GUIDINSTANCE
Indicates that the instance GUID for the joystick is being requested. An application can pass the instance GUID to IDirectInput::CreateDevice to obtain an IDirectInputDevice interface to the joystick. Note that this flag is not a valid parameter for IDirectInputJoyConfig8::SetConfig.
DIJC_REGHWCONFIGTYPE
Indicates that the hardware configuration for the joystick (the hwc member of the DIJOYCONFIG structure) and the joystick type name (the wszType member of the same structure) are being requested. Note that the hardware configuration and type name cannot be retrieved separately.
DIJC_GAIN
Indicates that the force-feedback gain for the joystick is being requested.
DIJC_CALLOUT
Indicates that the joystick polling callout is being requested.

Return Value

Returns DI_OK on success; otherwise returns one of the following COM error values:

DIERR_INVALIDPARAM
One or more parameters was invalid.
S_FALSE
The specified joystick has not yet been configured.
DIERR_NOMOREITEMS
No more joysticks are available.


IDirectInputJoyConfig8::GetTypeInfo

The IDirectInputJoyConfig8::GetTypeInfo method obtains information about a joystick type.

HRESULT
  IDirectInputJoyConfig8::GetTypeInfo(
    LPCWSTR  pwszTypeName,
    LPDIJOYTYPEINFO  pjti,
    DWORD  dwFlags
    );

Parameters

pwszTypeName
Pointer to the name of the type, previously obtained from a call to IDirectInputJoyConfig8::EnumTypes.
pjti
Receives information about the joystick type. The caller must initialize the dwSize member of the DIJOYTYPEINFO structure before calling this method.
dwFlags
Specifies the parts of the DIJOYTYPEINFO structure pointed to by pjti that are to be filled. There may be zero, one, or more of the following:
DITC_REGHWSETTINGS
Indicates that the registry hardware settings for the joystick are being requested.
DITC_CLSIDCONFIG
Indicates that the joystick configuration CLSID is being requested. If the value is all zeros, then there is no custom configuration for this joystick type.
DITC_DISPLAYNAME
Indicates that the display name for the joystick type is being requested.
DITC_CALLOUT
Indicates that the callout for the joystick type is being requested.

Return Value

Returns DI_OK on success; otherwise returns one of the following COM error values:

DIERR_INVALIDPARAM
One or more parameters was invalid.
DIERR_NOTFOUND
The joystick type was not found.


IDirectInputJoyConfig8::GetUserValues

The IDirectInputJoyConfig8::GetUserValues method obtains information about user settings for the joystick.

HRESULT
  IDirectInputJoyConfig8::GetUserValues(
    LPDIJOYUSERVALUES  pjuv,
    DWORD  dwFlags
    );

Parameters

pjuv
Receives information about the user joystick configuration. The caller must initialize the dwSize member of the DIJOYUSERVALUES structure before calling this method.
dwFlags
Specifies which parts of the DIJOYUSERVALUES structure contain values to be retrieved. There may be zero, one, or more of the following:
DIJU_USERVALUES
Indicates that the user configuration settings (the ruv member of the DIJOYUSERVALUES structure) is being requested.
DIJU_GLOBALDRIVER
Indicates that the global port driver (the wszGlobalDriver member of the DIJOYUSERVALUES structure) is being requested.

A list of valid global drivers can be obtained by enumerating the list of joystick types. If the joystick type has the JOY_HWS_ISGAMEPORTDRIVER flag set in the dwFlags member of the JOYHWSETTINGS structure, then the wszCallout member of the DIJOYTYPEINFO structure contains the name of a driver that can be used as a global driver.

DIJU_GAMEPORTEMULATOR
Unused.

Return Value

Returns DI_OK on success; otherwise returns the following COM error value::

DIERR_INVALIDPARAM
One or more parameters was invalid.


IDirectInputJoyConfig8::OpenAppStatusKey

The IDirectInputJoyConfig8::OpenAppStatusKey method opens the root key of the application status registry keys, and obtains a handle to the key as a return parameter.

HRESULT
  IDirectInputJoyConfig8::OpenAppStatusKey(
   PHKEY  phKey
    );

Parameters

phKey
Address of a variable (of type HKEY) that will contain a registry key handle if the method succeeds. See Comments for additional usage details.

Return Value

Returns DI_OK on success; otherwise returns one of the following COM error values: The following error codes are intended to be illustrative and not necessarily comprehensive.

DIERR_INVALIDPARAM
One or more parameters was invalid.
DIERR_NOTFOUND
The key is missing on this system. Applications should proceed as if the key were empty.

Comments

The registry key handle returned in the phKey parameter can be used with the standard Win32® registry functions. The dinputd.h header file defines the following string constants for use in accessing subkeys and named values contained by the application status root key.

Subkey String Contants
DIRECTINPUT_REGSTR_KEY_LASTAPP
Corresponds to the "MostRecentApplication" subkey. This key contains the name of the last application that used DirectInput services.
DIRECTINPUT_REGSTR_KEY_LASTMAPAPP
Corresponds to the "MostRecentMapperApplication" subkey. This key contains the name of the last application that used DirectInput mapper services, as detected the first time the application calls the IDirectInput8::BuildActionMap method.
Named Value String Constants
DIRECTINPUT_REGSTR_VAL_VERSION
Corresponds to the "Version" named value, of type REG_BINARY. This value is the DIRECTINPUT_VERSION passed by the application to initialize DirectInput.
DIRECTINPUT_REGSTR_VAL_NAME
Corresponds to the "Name" named value, of type REG_SZ. This value represents the application file name, in upper-case characters.
DIRECTINPUT_REGSTR_VAL_ID
Corresponds to the "Id" named value under either DIRECTINPUT_REGSTR_KEY_LASTMAPAPP or DIRECTINPUT_REGSTR_KEY_LASTAPP subkeys. This REG_SZ value is the application ID value. For DirectX® 8.0 applications, this is also the key name of a sibling key specific to this application.
DIRECTINPUT_REGSTR_VAL_MAPPER
Corresponds to the "UsesMapper" named value, under one of DirectX 8.0 application subkeys of the key opened by IDirectInputJoyConfig::OpenAppStatusKey. This is a REG_BINARY value as a DWORD. It is set to 0 if the application has not used Mapper functionality, or 1 if it has.
DIRECTINPUT_REGSTR_VAL_LASTSTART
Corresponds to the "MostRecentStart" named value, under either DIRECTINPUT_REGSTR_KEY_LASTMAPAPP or DIRECTINPUT_REGSTR_KEY_LASTAPP subkeys. This REG_BINARY value is a FILETIME structure, which describes the time the key contents were written.


IDirectInputJoyConfig8::OpenConfigKey

The IDirectInputJoyConfig8::OpenConfigKey method opens the registry key associated with a joystick configuration. Control panel applications can use this key to store per-joystick persistent information, such as button mappings. Such private information should be kept in a subkey named OEM; do not store private information in the main configuration key. The application should use RegCloseKey to close the registry key.

HRESULT
  IDirectInputJoyConfig8::OpenConfigKey(
    UINT  idJoy,
    REGSAM  regsam,
    PHKEY  phk
    );

Parameters

idJoy
Indicates a zero-based joystick identification number.
regsam
Specifies a registry security access mask. This can be any of the values permitted by the RegOpenKeyEx function. If write access is requested, then joystick configuration must first be acquired. If only read access is requested, then acquisition is not required. At least one access mask must be specified.
phk
Receives the opened registry key on success.

Return Value

Returns DI_OK on success; otherwise returns one of the following COM error values:

DIERR_NOTACQUIRED
Joystick configuration has not been acquired. You must call IDirectInputJoyConfig8::Acquire before you can open a joystick type configuration key for writing.
DIERR_INVALIDPARAM
One or more parameters was invalid.
DIERR_NOTFOUND
The application attempted to open the configuration key for reading, but no configuration key for the joystick had been created. Applications should proceed as if the key were empty.
MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ErrorCode)
A Win32 error code if access to the key is denied by registry permissions or some other external factor.


IDirectInputJoyConfig8::OpenTypeKey

The IDirectInputJoyConfig8::OpenTypeKey method opens the registry key associated with a joystick type. Control panel applications can use this key to store per-type persistent information, such as global configuration parameters. Such private information should be kept in a subkey named OEM; do not store private information in the main type key. Control panel applications can also use this key to read configuration information, such as the strings to use for device calibration prompts. The application should use RegCloseKey to close the registry key.

HRESULT
  IDirectInputJoyConfig8::OpenTypeKey(
    LPCWSTR  pwszType,
    REGSAM  regsam,
    PHKEY  phk
    );

Parameters

pwszType
Pointer to the name of the type. The name of the type cannot exceed MAX_PATH characters, including the terminating null character. The name cannot begin with a "#" character. Types beginning with "#" are reserved by DirectInput.
regsam
Specifies a registry security access mask. This can be any of the values permitted by the RegOpenKeyEx function. If write access is requested, then joystick configuration must first have been acquired. If only read access is requested, then acquisition is not required.
phk
Receives the opened registry key on success.

Return Value

Returns DI_OK on success; otherwise returns one of the following COM error values:

DIERR_NOTACQUIRED
Joystick configuration has not been acquired. You must call IDirectInputJoyConfig8::Acquire before you can open a joystick type configuration key for writing.
DIERR_INVALIDPARAM
One or more parameters was invalid.
MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ErrorCode)
A Win32 error code if access to the key is denied by registry permissions or some other external factor.


IDirectInputJoyConfig8::QueryInterface

The IDirectInputJoyConfig8::QueryInterface method determines whether the DirectInputJoyConfig object supports a particular COM interface. If it does, the system increases the reference count for the object by 1, and the application can begin using that interface immediately. This method is part of the IUnknown interface inherited by DirectInputJoyConfig.

HRESULT
  IDirectInputJoyConfig8::QueryInterface(
    REFIID  riid,
    LPVOID  *ppvObj
    );

Parameters

riid
Reference identifier of the interface being requested.
ppvObj
Address of a pointer to be filled with the interface pointer if the query is successful.

Return Value

Returns a COM error code.

Comments

When the application no longer needs to use the interface retrieved by a call to this method, it must call the Release method for that interface to free it.


IDirectInputJoyConfig8::Release

The IDirectInputJoyConfig8::Release method decreases the reference count of the DirectInputJoyConfig object by 1. This method is part of the IUnknown interface inherited by DirectInputJoyConfig.

HRESULT
  IDirectInputJoyConfig8::Release(
    );

Parameters

None

Return Value

Returns the new reference count of the object.

Comments

The DirectInputJoyConfig object deallocates itself when its reference count reaches 0. Use the IDirectInputJoyConfig8::AddRef method to increase the reference count of the object by 1.


IDirectInputJoyConfig8::SendNotify

The IDirectInputJoyConfig8::SendNotify method notifies device drivers and applications that changes to the device configuration have been made. An application that changes device configurations must invoke this method after the changes have been made (and before unacquiring).

HRESULT
  IDirectInputJoyConfig8::SendNotify(
    );

Parameters

None

Return Value

Returns DI_OK on success; otherwise returns the following COM error value (this value is intended to be illustrative and is not necessarily comprehensive):

DIERR_NOTACQUIRED
Joystick configuration has not been acquired. You must call IDirectInputJoyConfig8::Acquire before you can notify applications and drivers of changes to joystick configuration.


IDirectInputJoyConfig8::SetConfig

The IDirectInputJoyConfig8::SetConfig method creates or redefines configuration information about a joystick.

HRESULT
  IDirectInputJoyConfig8::SetConfig(
    UINT  idJoy,
    IN LPDIJOYCONFIG  pcfg,
    DWORD  dwFlags
    );

Parameters

idJoy
Indicates a zero-based joystick identification number.
pcfg
Contains information about the joystick.
dwFlags
Specifies the parts of the DIJOYCONFIG structure pointed to by pcfg that contain information to be set. There may be zero, one, or more of the following:
DIJC_REGHWCONFIGTYPE
Indicates that the hardware configuration for the joystick (the hwc member of the DIJOYCONFIG structure) and the joystick type name (the wszType member of the DIJOYCONFIG) are valid. Note that the hardware configuration and type name cannot be set separately.
DIJC_GAIN
Indicates that the force-feedback gain for the joystick is valid.
DIJC_CALLOUT
Indicates that the joystick polling callout is valid.

Return Value

Returns DI_OK on success; otherwise returns one of the following COM error values:

DIERR_NOTACQUIRED
Joystick configuration has not been acquired. You must call IDirectInputJoyConfig8::Acquire before you can notify applications and drivers of changes to joystick configuration.
DIERR_INVALIDPARAM
One or more parameters was invalid.


IDirectInputJoyConfig8::SetCooperativeLevel

The IDirectInputJoyConfig8::SetCooperativeLevel method establishes the cooperation level for the instance of the device. The only cooperative levels supported for the IDirectInputJoyConfig8 interface are DISCL_EXCLUSIVE and DISCL_BACKGROUND.

HRESULT
  IDirectInputJoyConfig8::SetCooperativeLevel(
    HWND  hwnd,
    DWORD  dwFlags
    );

Parameters

hwnd
Handle to the window associated with the interface. This parameter must be non-NULL and must be a top-level window. It is an error to destroy the window while it is still associated with an IDirectInputJoyConfig8 interface.
dwFlags
Specifies one of a set of flags that describe the level of cooperation associated with the device. The value must be DISCL_EXCLUSIVE | DISCL_BACKGROUND.

Return Value

Returns DI_OK on success; otherwise returns the following COM error value (this value is intended to be illustrative and is not necessarily comprehensive):

DIERR_INVALIDPARAM
One or more parameters was invalid.


IDirectInputJoyConfig8::SetTypeInfo

The IDirectInputJoyConfig8::SetTypeInfo method creates a new joystick type or redefines information about an existing joystick type.

HRESULT
  IDirectInputJoyConfig8::SetTypeInfo(
    LPCWSTR  pwszTypeName,
    LPDIJOYTYPEINFO  pjti,
    DWORD  dwFlags
    );

Parameters

pwszTypeName
Pointer to the name of the type. The name of the type cannot exceed MAX_JOYSTRING characters, including the terminating null character. If the type name does not already exist, then it is created. You cannot change the type information for a predefined type. The name cannot begin with a "#" character. Types beginning with "#" are reserved by DirectInput.
pjti
Contains information about the joystick type.
dwFlags
Specifies the parts of the DIJOYTYPEINFO structure pointed to by pjti that contain values to be set.
DITC_REGHWSETTINGS
Indicates that the registry hardware settings for the joystick are valid.
DITC_CLSIDCONFIG
Indicates that the joystick configuration CLSID is valid. If the value is all zeros, then there is no custom configuration for this joystick type.
DITC_DISPLAYNAME
Indicates that the display name for the joystick type is valid.
DITC_CALLOUT
Indicates that the callout for the joystick type is valid.

Return Value

Returns DI_OK on success; otherwise returns one of the following COM error values:

DIERR_NOTACQUIRED
Joystick configuration has not been acquired. You must call IDirectInputJoyConfig8::Acquire before you can notify applications and drivers of changes to joystick configuration.
DIERR_INVALIDPARAM
One or more parameters was invalid.
DIERR_READONLY
Attempted to change a predefined type.


IDirectInputJoyConfig8::SetUserValues

The IDirectInputJoyConfig8::SetUserValues method sets the user settings for the joystick.

HRESULT
  IDirectInputJoyConfig8::SetUserValues(
    LPCDIJOYUSERVALUES  pjuv,
    DWORD  dwFlags
    );

Parameters

pjuv
Contains information about the new user joystick settings.
dwFlags
Specifies the parts of the DIJOYUSERVALUES structure that contain values to be set. There may be zero, one, or more of the following:
DIJU_USERVALUES
Indicates that the user configuration settings ( the ruv member of the DIJOYUSERVALUES structure) is valid.
DIJU_GLOBALDRIVER
Indicates that the global port driver (the wszGlobalDriver member of the DIJOYUSERVALUES structure) is valid.

A list of valid global drivers can be obtained by enumerating the list of joystick types. If the joystick type has the JOY_HWS_ISGAMEPORTDRIVER flag set in the dwFlags member of the JOYHWSETTINGS structure, then the wszCallout member of the DIJOYTYPEINFO structure contains the name of a driver that can be used as a global driver.

DIJU_GAMEPORTEMULATOR
Unused.

Return Value

Returns DI_OK on success; otherwise returns one of the following COM error values:

DIERR_NOTACQUIRED
Joystick configuration has not been acquired. You must call IDirectInputJoyConfig8::Acquire before you can notify applications and drivers of changes to joystick configuration.
DIERR_INVALIDPARAM
One or more parameters was invalid.


IDirectInputJoyConfig8::Unacquire

The IDirectInputJoyConfig8::Unacquire method unacquires "joystick configuration mode". Before unacquiring configuration mode, the application performs an IDirectInputJoyConfig8::SendNotify to propagate the changes in the joystick configuration to all device drivers and applications. Applications that hold interfaces to a joystick that is materially affected by a change in configuration should receive the DIERR_DEVICECHANGE error code until the device is re-initialized. Examples of material changes to configuration include altering the number of axes or the number of buttons. In comparison, changes to device calibration are handled internally by DirectInput and are transparent to the application.

HRESULT
  IDirectInputJoyConfig8::Unacquire(
    );

Parameters

None

Return Value

Returns DI_OK on success; otherwise returns a COM error value.


IDIGameCntrlPropSheet

The IDIGameCntrlPropSheet interface consists of the following methods:

GetSheetInfo

GetPageInfo

GetID

SetID

In addition, all COM interfaces inherit the following IUnknown interface methods:

AddRef

QueryInterface

Release

These three methods allow additional interfaces to be added to the DirectInput game controller property sheet object without affecting the functionality of the original interface.


IDIGameCntrlPropSheet::AddRef

The IDIGameCntrlPropSheet::AddRef method increases the reference count of the DIGameCntrlPropSheet object by 1. This method is part of the IUnknown interface inherited by DIGameCntrlPropSheet.

HRESULT
  IDIGameCntrlPropSheet::AddRef(
    );

Parameters

None

Return Value

Returns the new reference count of the object.

Comments

When the DIGameCntrlPropSheet object is created, its reference count should be set to 1. Every time an application obtains an interface to the object or calls the AddRef method, the object's reference count is increased by 1. The application uses the Release method to decrease the reference count of the object by 1.


IDIGameCntrlPropSheet::GetID

The IDIGameCntrlPropSheet::GetID method returns the m_nID member of DIGameCntrlPropSheet.

USHORT
  IDIGameCntrlPropSheet::GetID(
    void
    );

Parameters

None

Return Value

Returns private member m_nID of IDIGameCntrlPropSheet.


IDIGameCntrlPropSheet::GetPageInfo

The IDIGameCntrlPropSheet::GetPageInfo method populates members of the DIGCPAGEINFO structure. This structure defines a page in a property sheet.

HRESULT
  IDIGameCntrlPropSheet::GetPageInfo(
    LPDIGCPAGEINFO  *ppDIGCPageInfo
    );

Parameters

ppDIGCPageInfo
Pointer to a DIGCPAGEINFO structure that contains information regarding the generation of a requested control panel property sheet page.

Return Value

Returns a COM error code.


IDIGameCntrlPropSheet::GetSheetInfo

The IDIGameCntrlPropSheet::GetSheetInfo method populates members of a DIGCSHEETINFO structure. This structure defines the frame and pages of a property sheet.

HRESULT
  IDIGameCntrlPropSheet::GetSheetInfo(
    LPDIGCSHEETINFO  *ppDIGCSheetInfo
    );

Parameters

ppDIGCSheetInfo
Pointer to a DIGCSHEETINFO structure that contains information regarding the generation of a requested control panel property sheet.

Return Value

Returns a COM error code.


IDIGameCntrlPropSheet::QueryInterface

The IDIGameCntrlPropSheet::QueryInterface method determines whether the DIGameCntrlPropSheet object supports a particular COM interface. If it does, the system increases the reference count for the object by 1, and the application can begin using that interface immediately. This method is part of the IUnknown interface inherited by DIGameCntrlPropSheet.

HRESULT
  IDIGameCntrlPropSheet::QueryInterface(
    REFIID  riid,
    LPVOID  *ppvObj
    );

Parameters

riid
Reference identifier of the interface being requested.
ppvObj
Address of a pointer to be filled with the interface pointer if the query is successful.

Return Value

Returns a COM error code.

Comments

When the application no longer needs to use the interface retrieved by a call to this method, it must call the Release method for that interface to free it.


IDIGameCntrlPropSheet::Release

The IDIGameCntrlPropSheet::Release method decreases the reference count of the DIGameCntrlPropSheet object by 1. This method is part of the IUnknown interface inherited by DIGameCntrlPropSheet.

HRESULT
  IDIGameCntrlPropSheet::Release(
    );

Parameters

None

Return Value

Returns the new reference count of the object.

Comments

The DIGameCntrlPropSheet object deallocates itself when its reference count reaches 0. Use the IDIGameCntrlPropSheet::AddRef method to increase the reference count of the object by 1.


IDIGameCntrlPropSheet::SetID

The IDIGameCntrlPropSheet::SetID method populates the m_nID member of DIGameCntrlPropSheet.

HRESULT
  IDIGameCntrlPropSheet::SetID(
    USHORT  nID
    );

Parameters

nID
Indicates the joystick ID assigned to the device that is represented by this page. This is sent by Gchand.dll after successful calls to IDIGameCntrlPropSheet::GetPageInfo and IDIGameCntrlPropSheet::GetSheetInfo.

Return Value

Returns a COM error code.


DirectInput Callbacks

This section contains reference information for the callbacks used by DirectInput. These callbacks are described in the following topics:

IDirectInputJoyConfig8 Callback

General Kernel-Mode Callbacks

Kernel-Mode Force Feedback Callbacks


DIEnumJoyTypeProc

The DIEnumJoyTypeProc callback receives DirectInput joystick types as a result of a call to the IDirectInputJoyConfig8::EnumTypes method.

BOOL
  CALLBACK DIEnumJoyTypeProc(
    LPCWSTR  pwszTypeName,
    LPVOID  pvRef
    );

Parmeters

pwszTypeName
The name of the joystick type. A buffer of MAX_JOYSTRING characters is sufficient to hold the type name. The type name should never be shown to the end user; instead, the "display name" should be shown. Use IDirectInputJoyConfig8::GetTypeInfo to obtain the display name of a joystick type. Type names that begin with a pound sign ("#") represent predefined types that cannot be modified or deleted.
pvRef
Specifies the application-defined value given in the IDirectInputJoyConfig8::EnumTypes method.

Return Value

Returns DIENUM_CONTINUE to continue the enumeration or DIENUM_STOP to stop the enumeration.


General Kernel-Mode Callbacks

DirectInput utilizes the following general kernel-mode callbacks:

CtrlMsg

Escape

Initialize

Poll


CtrlMsg

The CtrlMsg callback sends specific messages to a minidriver.

HRESULT
  (__stdcall *CTRLMSGRTN)(
    DWORD  dwDeviceID,
    DWORD  dwMsgId,
    DWORD  dwParam
    );

Parameters

dwDeviceID
Indicates the joystick ID number being used.
dwMsgId
Indicates the message being sent to the minidriver. If the value is VJCM_PASSDRIVERDATA, it indicates that the dwParam parameter contains a DWORD to pass to the driver. If the value is VJCM_CONFIGCHANGED, it indicates that the dwParam parameter informs the minidriver of a change in configuration.
dwParam
Specifies one of the following:

If the dwMsgId parameter is set to VJCM_PASSDRIVERDATA, this parameter contains a DWORD to pass to the driver. This allows the JOY_OEMPOLL_PASSDRIVERDATA poll type that was used to pass driver data to a DirectX 3.0 driver to still be used for a driver designed for DirectX 5.0 and later versions.

If the dwMsgId parameter is set to VJCM_CONFIGCHANGED, this parameter contains a pointer to a VJCFGCHG structure that informs the minidriver of a change in configuration.

Return Value

Returns S_OK if the message is recognized and completed, S_FALSE for an unrecognized (and therefore unprocessed) message, or an error value otherwise.


Escape

The Escape callback escapes to the driver. It is called in response to an application invoking the IDirectInputEffect::Escape or IDirectInputDevice::Escape methods.

HRESULT
  (__stdcall *ESCAPERTN)(
    DWORD  dwDeviceID,
    DWORD  dwEffectID,
    LPDIEFFESCAPE  lpEscape
    );

Parameters

dwDeviceID
Indicates the joystick ID number being used.
dwEffectID
Specifies the effect at which the command is directed. This value is zero if the command is directed at the device itself and not at any particular effect.
lpEscape
Pointer to a DIEFFESCAPE structure that contains the command block. On success, the cbOutBuffer member contains the number of bytes of the output buffer that were actually used.

Return Value

Returns S_OK if successful; otherwise returns a DIERR_* error code, or a custom error code in the range DIERR_DRIVERFIRST through DIERR_DRIVERLAST.


Poll

The Poll callback is the polling routine used in DirectX 5.0 and later. This replaces the polling routine documented in the Polling Callback section.

HRESULT
  (__stdcall *JOYPOLLRTN)(
    DWORD  dwDeviceID,
    LPDWORD  lpdwMask,
    LPVJPOLLDATA  lpPollData
    );

Parameters

dwDeviceID
Indicates the joystick ID number being used.
lpdwMask
Pointer to a DWORD mask that describes the data requested on entry, and the data returned on exit. The mask is a combination of the following:
JOYPD_X
Bitmask for the dwX member of the VJPOLLDATA structure.
JOYPD_Y
Bitmask for the dwY member of the VJPOLLDATA structure.
JOYPD_Z
Bitmask for the dwZ member of the VJPOLLDATA structure.
JOYPD_R
Bitmask for the dwR member of the VJPOLLDATA structure.
JOYPD_U
Bitmask for the dwU member of the VJPOLLDATA structure.
JOYPD_V
Bitmask for the dwV member of the VJPOLLDATA structure.
JOYPD_POV0
Bitmask for the dwPOV0 member of the VJPOLLDATA structure.
JOYPD_POV1
Bitmask for the dwPOV1 member of the VJPOLLDATA structure.
JOYPD_POV2
Bitmask for the dwPOV2 member of the VJPOLLDATA structure.
JOYPD_POV3
Bitmask for the dwPOV3 member of the VJPOLLDATA structure.
JOYPD_BTN0
Bitmask for the dwBTN0 member of the VJPOLLDATA structure.
JOYPD_BTN1
Bitmask for the dwBTN1 member of the VJPOLLDATA structure.
JOYPD_BTN2
Bitmask for the dwBTN2 member of the VJPOLLDATA structure.
JOYPD_BTN3
Bitmask for the dwBTN3 member of the VJPOLLDATA structure.
JOYPD_RESERVED0
Bitmask for the dwReserved0 member of the VJPOLLDATA structure.
JOYPD_RESERVED1
Bitmask for the dwReserved1 member of the VJPOLLDATA structure.
JOYPD_ELEMENT_MASK
Bitmask for all members of the VJPOLLDATA structure.
JOYPD_POSITION
Bitmask for the position attribute of the device.
JOYPD_VELOCITY
Bitmask for the velocity attribute of the device.
JOYPD_ACCELERATION
Bitmask for the acceleration attribute of the device.
JOYPD_FORCE
Bitmask for the force attribute of the device.
JOYPD_ATTRIB_MASK
Bitmask for all possible attributes of the device.
lpPollData
Contains the polling data.

Return Value

Returns S_OK if the poll was completed, returns S_FALSE if returned data is (partially or wholly) out of date; otherwise returns an error value.

Comments

The upper and lower words of the lpdwMask parameter are treated separately. The lower word is a simple bitmask of the elements in the VJPOLLDATA structure. The upper word describes the attributes for which these elements are requested. The lpPollData parameter to the poll contains an array of at least as many VJPOLLDATA structures as there are bits set in the upper word of the mask.

The first VJPOLLDATA structure should contain the position information. The next three VJPOLLDATA structures should contain information about the acceleration, velocity, and force, in that order. For example, if the device only supports position and force, the first structure will contain position data, the second and third structures are skipped, and the fourth structure will contain force information.

The minidriver should always set the mask to what it can return, even if the poll fails because the device is unplugged. So if the device has less than 33 buttons, X, Y and R, for position only, it should perform an operation such as *pdwMask &= ( JOYPD_POSITION | JOYPD_BTN0 | JOYPD_X | JOYPD_Y | JOYPD_R ); before searching for the available data.

If the device can return data for more than one attribute, the upper word has a bit set for each attribute and the lower word should have the bit set for any element that can be returned for any of the supported attributes. So even though force is an unlikely value for the button masks (which are single bit), if the device reports buttons in the position data and force for X and Y, then position, force, X, Y and buttons should all have their bits set.


Kernel-Mode Force Feedback Callbacks

This section contains reference information for the kernel-mode force feedback callbacks used by DirectInput. The COM methods are documented in the IDirectInputEffectDriver section of the DirectInput Reference. The equivalent VJoyD minidriver callbacks take the same parameters and return the same codes. Any exceptions to this are noted. These force feedback callbacks are divided into the following categories:

DestroyEffect

DownloadEffect

GetEffectStatus

GetForceFeedbackState

SendForceFeedbackCommand

SetGain

StartEffect

StopEffect

The return codes listed for the preceding callbacks do not represent the complete set of those possible. Some errors, such as an out-of-memory condition, may result in the DIERR_OUTOFMEMORY error code for any of the methods.

DirectInput has already done parameter checking where possible, so a driver should only attempt further validation where its requirements are nonstandard.

All magnitude and gain values used by DirectInput are uniform and linear across the range. Any nonlinearity in the physical device must be handled by the device driver so that the application interfaces with the device as if it were a linear device.


DestroyEffect

The DestroyEffect callback commands the device to "destroy" a currently downloaded effect. The effect ID and any data that is associated with the effect are freed and available for reallocation.

HRESULT
  (__stdcall *DESTROYEFFECTRTN)(
    DWORD  dwDeviceID,
    DWORD  dwDnloadID
    );

Parameters

dwDeviceID
Indicates the external joystick number being addressed.
dwDnloadID
Indicates the effect ID that was obtained from the device when the effect was downloaded.

Return Value

Returns S_OK on success; otherwise returns an error value.


DownloadEffect

The DownloadEffect callback sends an effect to the device.

HRESULT
  (__stdcall *DOWNLOADEFFECTRTN)(
    DWORD  dwDeviceID,
    DWORD  dwInternalEffectType,
    LPDWORD  lpdwDnloadID,
    LPDIEFFECT  lpEffect,
    DWORD  dwFlags
    );

Parameters

dwDeviceID
Indicates the external joystick number being addressed.
dwInternalEffectType
Indicates the dwEffectId member of the DIEFFECTATTRIBUTES structure which is associated with the effect that the application is attempting to create. The DIEFFECTATTRIBUTES structure is stored in the registry under the registry key for the corresponding effect and can be any 32-bit value. DirectInput passes the 32-bit value to the driver with no interpretation.
lpdwDnloadID
On entry, this parameter points to the handle of the effect being downloaded. If the parameter points to a zero, then a new effect is downloaded. On exit, the DWORD pointed to by this parameter contains the new effect handle. On failure, the DWORD pointed to by this parameter is set to zero if the effect is lost, or left alone if the effect is still valid with its old parameters. Note that zero is never a valid effect handle.
lpEffect
The new parameters for the effect. The axis and button values have been converted to object identifiers, which consist of the following:
One type specifier:
DIDFT_RELAXIS
DIDFT_ABSAXIS
DIDFT_PSHBUTTON
DIDFT_TGLBUTTON
DIDFT_POV
One instance identifier:
DIDFT_MAKEINSTANCE(n)

Other bits in the object identifier are reserved and should be ignored.

For example, 0x02000104 = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE(1) | other stuff

This value indicates that the effect uses button 1.

dwFlags
Specifies which portions of the effect information have changed from the effect already on the device. This information is passed to drivers to allow for the optimization of effect modification. If an effect is being modified, a driver may be able to update the effect in its original position and transmit to the device only the information that has changed. Drivers are not, however, required to implement this optimization. All members of the DIEFFECT structure that are pointed to by the peff parameter are valid, and a driver may choose simply to update all parameters of the effect at each download. (For information on the DIEFFECT structure, see the DirectInput section of the stand alone DirectX SDK. There may be zero, one, or more of the following:
DIEP_DURATION
Indicates the dwDuration member of the DIEFFECT structure is being downloaded for the first time or has changed since its last download.
DIEP_SAMPLEPERIOD
Indicates the dwSamplePeriod member of the DIEFFECT structure is being downloaded for the first time or has changed since its last download.
DIEP_GAIN
Indicates the dwGain member of the DIEFFECT structure is being downloaded for the first time or has changed since its last download.
DIEP_TRIGGERBUTTON
Indicates the dwTriggerButton member of the DIEFFECT structure is being downloaded for the first time or has changed since its last download.
DIEP_TRIGGERREPEATINTERVAL
Indicates the dwTriggerRepeatInterval member of the DIEFFECT structure is being downloaded for the first time or has changed since its last download.
DIEP_AXES
Indicates the cAxes and rgdwAxes members of the DIEFFECT structure are being downloaded for the first time or have changed since their last download.
DIEP_DIRECTION
Indicates the cAxes and rglDirection members of the DIEFFECT structure are being downloaded for the first time or have changed since their last download. (The dwFlags member of the DIEFFECT structure specifies, through DIEFF_CARTESIAN or DIEFF_POLAR, the coordinate system in which the values should be interpreted.)
DIEP_ENVELOPE
Indicates the lpEnvelope member of the DIEFFECT structure is being downloaded for the first time or has changed since its last download. If this flag is set and the lpEnvelope member is a NULL pointer, then the effect is being created with no envelope, or the existing envelope is being deleted.
DIEP_TYPESPECIFICPARAMS
Indicates the cbTypeSpecificParams and lpTypeSpecificParams members of the DIEFFECT structure are being downloaded for the first time or have changed since their last download.
DIEP_START
Indicates that the effect is to be restarted from the beginning after the parameters of the effect have been updated.. Note that the DIEP_NODOWNLOAD flag overrides the DIEP_START flag.
DIEP_NORESTART
If this flag is not specified, the effect device driver is permitted to restart the effect if doing so is necessary to change the specified parameters. Note that the DIEP_NODOWNLOAD and DIEP_START flags override this flag.
DIEP_NODOWNLOAD
Suppresses the automatic download that is normally performed after the parameters are updated. If this flag is set, the driver should validate parameters without performing an actual download.

Return Value

Returns S_OK if successful; otherwise returns an error value.


GetEffectStatus

The GetEffectStatus callback returns the device effects status.

HRESULT
  (__stdcall *GETEFFECTSTATUSRTN)(
    DWORD  dwDeviceID,
    DWORD  dwDnloadID,
    LPDWORD  lpdwStatusCode
    );

Parameters

dwDeviceID
Indicates the external joystick number being addressed.
dwDnloadID
Indicates the effect to be queried.
lpdwStatusCode
Receives the effect status. The DWORD pointed to by this parameter should be filled in with one of the following values:
DIEGES_PLAYING
The effect is still playing.
0
The effect is not playing.

Return Value

Returns S_OK if successful; otherwise returns an error value.


GetForceFeedbackState

The GetForceFeedbackState callback returns the state of the device.

HRESULT
  (__stdcall *GETFFSTATERTN)(
    DWORD  dwDeviceID,
    LPDIDEVICESTATE  lpDeviceState
    );

Parameters

dwDeviceID
Indicates the external joystick number being addressed.
lpDeviceState
Pointer to a DIDEVICESTATE structure that receives the device state. DirectInput sets the dwSize member of the DIDEVICESTATE structure to sizeof(DIDEVICESTATE) before calling this method.

Return Value

Returns S_OK if successful; otherwise returns an error value.


SendForceFeedbackCommand

The SendForceFeedbackCommand callback sends a command to the device.

HRESULT
  (__stdcall *SENDFFCOMMANDRTN)(
    DWORD  dwDeviceID,
    DWORD  dwState
    );

Parameters

dwDeviceID
Indicates the external joystick number being addressed.
dwState
Indicates the command being sent. That command can be one of the following:
DISFFC_RESET
Indicates that playback of any active effects should be been stopped and that all effects should be removed from the device. Once the device has been reset, all effects are no longer valid and must be re-created.
DISFFC_STOPALL
Indicates that playback of all effects should be stopped. Sending the DISFFC_STOPALL command is equivalent to invoking the IDirectInputEffect::Stop method on all effects that are playing. If the device is in a paused state, the device driver is permitted to lose the paused state.
DISFFC_PAUSE
Indicates that playback of all effects should be paused. When effects are paused, time "stops" until the DISFFC_CONTINUE command is sent. For example, suppose an effect of five seconds' duration is started. After one second, all effects are paused. After two more seconds, all effects are continued. The effect should then play for four additional seconds. While a force-feedback device is paused, starting a new effect or modifying existing ones can cause the paused state to be lost.
DISFFC_CONTINUE
Indicates that playback should be resumed at the point at which it was interrupted for those effects that were paused by a previous DISCFFC_PAUSE command.
DISFFC_SETACTUATORSON
Indicates that the device's force-feedback actuators should be enabled.
DISFFC_SETACTUATORSOFF
Indicates that the device's force-feedback actuators should be disabled. If successful, force-feedback effects are "muted". Note that time continues to elapse while actuators are off. For example, suppose an effect of five seconds' duration is started. After one second, actuators are turned off. After two more seconds, actuators are turned back on. The effect should then play for two additional seconds.

Return Value

Returns S_OK if successful; otherwise returns an error value.


SetGain

The SetGain callback sets the overall device gain.

HRESULT
  (__stdcall *SETGAINRTN)(
    DWORD  dwDeviceID,
    DWORD  dwGain
    );

Parameters

dwDeviceID
Indicates the external joystick number being addressed.
dwGain
Indicates the device gain level. This value can be a number between 1 and 10,000.

Return Value

Returns S_OK if successful; otherwise returns an error value.


StartEffect

The StartEffect callback commands the device to play back an effect that was previously loaded.

HRESULT
  (__stdcall *STARTEFFECTRTN)(
    DWORD  dwDeviceID,
    DWORD  dwDnloadID,
    DWORD  dwMode,
    DWORD  dwIterations
    );

Parameters

dwDeviceID
Indicates the external joystick number being addressed.
dwDnloadID
Indicates the effect to be played.
dwMode
Specifies the playback mode. Only the following mode can be used (all other modes are reserved):
DIES_SOLO
Stop other forces that are playing and play only this one.
dwIterations
Specifies the number of times to perform the effect. If the value is INFINITE, then the effect should be repeated until explicitly stopped or paused.

Return Value

Returns S_OK if successful; otherwise returns an error value.


StopEffect

The StopEffect callback commands the device to stop an effect that was previously started.

HRESULT
  (__stdcall *STOPEFFECTRTN)(
    DWORD  dwDeviceID,
    DWORD  dwDnloadID
    );

Parameters

dwDeviceID
Indicates the external joystick number being addressed.
dwDnloadID
Indicates the effect to be stopped.

Return Value

Returns S_OK if successful; otherwise returns an error value.


DirectInput Kernel-Mode Service Macros

DirectInput provides a set of macros that contain entry points to kernel-mode services. These entry points are:

Windows Services

VJOYD_Register_Device_Driver

VJOYD_GetPosEx_Service

DirectInput Services

VJOYD_GetInitParams_Service

VJOYD_Poll_Service

Device Services

VJOYD_Escape_Service

VJOYD_CtrlMsg_Service

Force Feedback Device Services

VJOYD_DestroyEffect_Service

VJOYD_DownloadEffect_Service

VJOYD_GetEffectStatus_Service

VJOYD_GetFFState_Service

VJOYD_SendFFCommand_Service

VJOYD_SetGain_Service

VJOYD_StartEffect_Service

VJOYD_StopEffect_Service

Interrupt Polling Service

VJOYD_DeviceUpdateNotify_Service

Screen Saver Service

VJOYD_JoystickActivity_Service

Registry Access Services

VJOYD_OpenTypeKey_Service

VJOYD_OpenConfigKey_Service

Note If you need to open registry keys, you should use the VJOYD_OpenConfigKey_Service and VJOYD_OpenTypeKey_Service service macros instead of opening the registry keys directly. Using these services ensures that the correct registry branch is opened. In addition, the service macros will be supported in future versions of DirectInput when the underlying registry data may be structured differently.


VJOYD_CtrlMsg_Service

For information on this service macro, see CtrlMsg.


VJOYD_DestroyEffect_Service

For information on this service macro, see DestroyEffect.


VJOYD_DeviceUpdateNotify_Service

A minidriver that receives asynchronous updates from its device should call VJOYD_DeviceUpdateNotify_Service to notify DirectInput that new data is available. If an application has requested data from this device, DirectInput responds by issuing a poll to retrieve the data. If no applications request data from this device, or if the applications are not using DirectInput (if they are using WinMM functions instead) this service does nothing.


VJOYD_DownloadEffect_Service

For information on this service macro, see DownloadEffect.


VJOYD_Escape_Service

For information on this service macro, see Escape.


VJOYD_GetEffectStatus_Service

For information on this service macro, see GetEffectStatus.


VJOYD_GetFFState_Service

For information on this service macro, see GetForceFeedbackState.


VJOYD_GetInitParams_Service

For information on this service macro, see Initialize.


VJOYD_GetPosEx_Service

The VJOYD_GetPosEx_Service macro allows kernel-mode components to get joystick data bypassing WinMM.

VJOYDAPI_GetPosEx_Service, SERVICE
ENTRY:
eax = pointer to JOYINFOEX

ebx = joystick ID

EXIT:
eax = joystick return code


VJOYD_JoystickActivity_Service

The VJOYD_JoystickActivity_Service macro is called internally to allow DirectInput to receive information about the joystick activity that is being reported through the WinMM functions. This information should prevent a screen saver from being activated. This macro should not be called by minidrivers and may not be supported in future versions.


VJOYD_OpenConfigKey_Service

The VJOYD_OpenConfigKey_Service macro is used by joystick drivers to open a configuration key. This should mirror the IDirectInputJoyConfig8::OpenConfigKey method.

VJOYD_OpenConfigKey_Service, SERVICE
ENTRY:
eax = ID of key to open

ecx = address of a DWORD in which to store the key

EXIT:
eax = same as _RegOpenKey except that ERROR_CANTOPEN is returned if VJoyD has not yet established the current configuration key.


VJOYD_OpenTypeKey_Service

The VJOYD_OpenTypeKey_Service macro is used by joystick drivers to open a type key. It should mirror the IDirectInputJoyConfig8::OpenTypeKey method.

VJOYD_OpenTypeKey_Service, SERVICE
ENTRY:
eax = pointer to name of type

ecx = pointer to DWORD in which to store the key

EXIT:
eax = same as _RegOpenKey


VJOYD_Poll_Service

For information on this service macro, see Poll.


VJOYD_Register_Device_Driver

For information on this service macro, see The DirectX 5.0 Interface.

DDK_The_DirectX_5_0_Interface_DI


VJOYD_SendFFCommand_Service

For information on this service macro, see SendForceFeedbackCommand.


VJOYD_SetGain_Service

For information on this service macro, see SetGain.


VJOYD_StartEffect_Service

For information on this service macro, see StartEffect.


VJOYD_StopEffect_Service

For information on this service macro, see StopEffect.


DirectInput Structures

This section contains reference information on the following structures used by DirectInput:

DID_INITPARAMS

DIDEVICESTATE

DIDRIVERVERSIONS

DIEFFECTATTRIBUTES

DIEFFESCAPE

DIFFDEVICEATTRIBUTES

DIFFOBJECTATTRIBUTES

DIGCPAGEINFO

DIGCSHEETINFO

DIHIDFFINITINFO

DIJOYCONFIG

DIJOYTYPEINFO

DIJOYUSERVALUES

DIOBJECTATTRIBUTES

DIOBJECTCALIBRATION

JOYOEMHWCAPS

JOYOEMPOLLDATA

VJCFGCHG

VJDEVICEDESC

VJFORCEREG

VJGPEMULREG

VJPOLLDATA

VJPOLLREG

VJREGDRVINFO


DID_INITPARAMS

The DID_INITPARAMS structure contains the initialization parameters.

 typedef struct DID_INITPARAMS {
  DWORD  dwSize;
  DWORD  dwFlags;
  DWORD  dwUnitId;
  DWORD  dwDevnode;
  JOYREGHWSETTINGS  hws;
} DID_INITPARAMS, *LPDID_INITPARAMS;

Members

dwSize
Specifies the size of the structure in bytes. This member must be initialized before the structure is used.
dwFlags
Specifies one of the following driver initialization flags:
VJIF_BEGIN_ACCESS
VJIF_END_ACCESS
dwUnitId
Reserved, is set to 0.
dwDevnode
Specifies the device node with which the device ID should be associated.
hws
Specifies the hardware settings for this device ID.


DIDEVICESTATE

The DIDEVICESTATE structure rereturns information about the state of a force feedback device.

typedef struct {
  DWORD  dwSize;
  DWORD  dwState;
  DWORD  dwLoad;
} DIDEVICESTATE;

Members

dwSize
Specifies the size of the structure in bytes. This member must be initialized before the structure is used.
dwState
Indicates various aspects of the device state. Can indicate zero, one, or more of the following:
DIGFFS_EMPTY
Indicates that the force feedback device is devoid of any downloaded effects.
DIGFFS_STOPPED
Indicates that no effects are currently playing and the device is not paused.
DIGFFS_PAUSED
Indicates that playback of effects has been paused by a previous DISFFC_PAUSE command.
DIGFFS_ACTUATORSON
Indicates that the device's force-feedback actuators are enabled.
DIGFFS_ACTUATORSOFF
Indicates that the device's force-feedback actuators are disabled.
DIGFFS_POWERON
Indicates that power to the force-feedback system is currently available. If the device cannot report the power state, then neither DIGFFS_POWERON nor DIGFFS_POWEROFF should be returned.
DIGFFS_POWEROFF
Indicates that power to the force-feedback system is not currently available. If the device cannot report the power state, then neither DIGFFS_POWERON nor DIGFFS_POWEROFF should be returned.
DIGFFS_SAFETYSWITCHON
Indicates that the safety switch (dead-man switch) is currently on, meaning that the device can operate. If the device cannot report the state of the safety switch, then neither DIGFFS_SAFETYSWITCHON nor DIGFFS_SAFETYSWITCHOFF should be returned.
DIGFFS_SAFETYSWITCHOFF
Indicates that the safety switch (dead-man switch) is currently off, meaning that the device cannot operate. If the device cannot report the state of the safety switch, then neither DIGFFS_SAFETYSWITCHON nor DIGFFS_SAFETYSWITCHOFF should be returned.
DIGFFS_USERFFSWITCHON
Indicates that the user force-feedback switch is currently on, meaning that the device can operate. If the device cannot report the state of the user force-feedback switch, then neither DIGFFS_USERFFSWITCHON nor DIGFFS_USERFFSWITCHOFF should be returned.
DIGFFS_USERFFSWITCHOFF
Indicates that the user force-feedback switch is currently off, meaning that the device cannot operate. If the device cannot report the state of the user force-feedback switch, then neither DIGFFS_USERFFSWITCHON nor DIGFFS_USERFFSWITCHOFF should be returned.
DIGFFS_DEVICELOST
Indicates that the device suffered an unexpected failure and is in an indeterminate state. It must be reset either by unacquiring and reacquiring the device, or by explicitly sending a DISFFC_RESET command. For example, the device may be lost if the user suspends the computer, causing on-board memory on the device to be lost.
dwLoad
A value indicating the percentage of device memory in use. A value of zero indicates that the device memory is completely available. A value of 100 indicates that the device is full.


DIDRIVERVERSIONS

The DIDRIVERVERSIONS structure is used by the DirectInput effect driver to report version information back to DirectInput. The semantics of the version numbers are left to the discretion of the device driver. The only requirement is that later versions have higher version numbers than earlier versions.

typedef struct {
  DWORD  dwSize;
  DWORD  dwFirmwareRevision;
  DWORD  dwHardwareRevision;
  DWORD  dwFFDriverVersion;
} DIDRIVERVERSIONS;

Members

dwSize
Specifies the size of the structure in bytes. This member must be initialized before the structure is used.
dwFirmwareRevision
Specifies the firmware revision of the device.
dwHardwareRevision
Specifies the hardware revision of the device.
dwFFDriverVersion
Specifies the version number of the force-feedback device driver.


DIEFFECTATTRIBUTES

The DIEFFECTATTRIBUTES structure describes the information contained in the "Attributes" value of the registry key for each effect that is supported by a force-feedback device.

typedef struct {
  DWORD  dwEffectId;
  DWORD  dwEffType;
  DWORD  dwStaticParams;
  DWORD  dwDynamicParams;
  DWORD  dwCoords;
} DIEFFECTATTRIBUTES;

Members

dwEffectId
Specifies an arbitrary 32-bit value that is passed to the driver to identify the effect. The driver receives this value as the dwEffectID parameter to the IDirectInputEffectDriver::DownloadEffect method.
dwEffType
Describes the category and capabilities of the effect. This member must consist of exactly one of the following values:
DIEFT_CONSTANTFORCE
The effect represents a constant force effect. When creating or modifying a constant force effect, the lpvTypeSpecificParams member of the DIEFFECT structure points to a DICONSTANTFORCE structure and the cbTypeSpecificParams member of the DIEFFECT structure is set to sizeof(DICONSTANTFORCE).
DIEFT_RAMPFORCE
The effect represents a ramp-force effect. When creating or modifying a ramp-force effect, the lpvTypeSpecificParams member of the DIEFFECT structure points to a DIRAMPFORCE structure and the cbTypeSpecificParams member of the DIEFFECT structure is set to sizeof(DIRAMPFORCE).
DIEFT_PERIODIC
The effect represents a periodic effect. When creating or modifying a periodic effect, the lpvTypeSpecificParams member of the DIEFFECT structure points to a DIPERIODIC structure and the cbTypeSpecificParams member of the DIEFFECT structure is set to sizeof(DIPERIODIC).
DIEFT_CONDITION
The effect represents a condition. When creating or modifying a condition, the lpvTypeSpecificParams member of the DIEFFECT structure points to an array of DICONDITION structures (either exactly one DICONDITION structure or one DICONDITION structure per axis) and the cbTypeSpecificParams member of the DIEFFECT structure is set to sizeof(DICONDITION) or cAxis * sizeof(DICONDITION), respectively. If cbTypeSpecificParams is set to sizeof(DICONDITION), then the effect represents a single-axis condition that may be rotated. If cbTypeSpecificParams is set to cAxis * sizeof(DICONDITION), then the effect represents a multiple-axis condition, with each DICONDITION structure applying to the respective axis in the rgdwAxes list.
DIEFT_CUSTOMFORCE
The effect represents a custom force effect. When creating or modifying a custom force effect, the lpvTypeSpecificParams member of the DIEFFECT structure points to a DICUSTOMFORCE structure and the cbTypeSpecificParams member of the DIEFFECT structure is set to sizeof(DICUSTOMFORCE).
DIEFT_HARDWARE
The effect represents a hardware-specific effect. The hardware vendor is required to provide additional documentation to the application writer on how the effect should be used.

In addition to the category code, this member can also contain zero, one, or more of the following flags that describe the effect's capabilities:

DIEFT_FFATTACK
The effect generator for this effect supports the attack envelope parameter. If the effect generator does not support attack, then the attack level and attack time parameters of the DIENVELOPE structure are ignored by the effect.
DIEFT_FFFADE
The effect generator for this effect supports the fade parameter. If the effect generator does not support fade, the fade level and fade time parameters of the DIENVELOPE structure are ignored by the effect. If DIEFT_FFATTACK or DIEFT_FFFADE is not set, then the effect does not support an envelope, and any provided envelope is ignored.
DIEFT_SATURATION
The effect generator for this effect supports the saturation of condition effects. If the effect generator does not support saturation, then the force generated by a condition is limited only by the maximum force that the device can generate.
DIEFT_POSNEGCOEFFICIENTS
The effect generator for this effect supports two coefficient values for conditions, one for the positive displacement of the axis and one for the negative displacement of the axis. If the device does not support both coefficients, then the negative coefficient in the DICONDITION structure is ignored and the positive coefficient is used in both directions.
DIEFT_POSNEGSATURATION
The effect generator for the effect supports a maximum saturation for both positive and negative force output. If the device does not support both saturation values, then the negative saturation in the DICONDITION structure is ignored and the positive saturation is used in both directions.
dwStaticParams
Describes the parameters supported by the effect. For example, if DIEP_ENVELOPE is set, then the effect supports an envelope. All effects should support at least DIEP_DURATION, DIEP_AXES, and DIEP_TYPESPECIFICPARAMS. It is not an error for an application to attempt to use effect parameters that are not supported by the device. The unsupported parameters are merely ignored. This value can be zero, one, or more of the following flags:
DIEP_DURATION
Indicates that the driver supports changing the dwDuration (see the DIEFFECT structure) of an effect when the effect is not playing.
DIEP_SAMPLEPERIOD
Indicates that the driver supports changing the dwSamplePeriod (see the DIEFFECT structure) of an effect when the effect is not playing.
DIEP_GAIN
Indicates that the driver supports changing the dwGain (see the DIEFFECT structure) of an effect when the effect is not playing.
DIEP_TRIGGERBUTTON
Indicates that the driver supports changing the dwTriggerButton (see the DIEFFECT structure) of an effect when the effect is not playing.
DIEP_TRIGGERREPEATINTERVAL
Indicates that the driver supports changing the dwTriggerRepeatInterval (see the DIEFFECT structure) of an effect when the effect is not playing.
DIEP_AXES
Indicates that the driver supports changing the cAxes and rgdwAxes (see the DIEFFECT structure) of an effect when the effect is not playing.
DIEP_DIRECTION
Indicates that the driver supports changing the cAxes and rglDirection (see the DIEFFECT structure) of an effect when the effect is not playing. (The dwFlags member of the DIEFFECT structure specifies, through DIEFF_CARTESIAN or DIEFF_POLAR, the coordinate system in which the values should be interpreted.)
DIEP_ENVELOPE
Indicates that the driver supports changing the lpEnvelope (see the DIEFFECT structure) of an effect when the effect is not playing.
DIEP_TYPESPECIFICPARAMS
Indicates that the driver supports changing the cbTypeSpecificParams and lpTypeSpecificParams (see the DIEFFECT structure) of an effect when the effect is not playing. Note that the buffer pointed to by the lpTypeSpecificParams member of the DIEFFECT structure must remain valid for the lifetime of the effect (or until the type-specific parameter is set to a new value). DirectInput does not make a private copy of the buffer.
dwDynamicParams
Describes the parameters of the effect that can be modified while the effect is playing. If an application attempts to change a parameter while the effect is playing, and the driver does not support modifying that effect dynamically, then the driver shall return DIERR_EFFECTPLAYING. This member uses the same flags as the dwStaticParams member, except that the flags are interpreted as describing whether the driver can modify the parameters of an effect while the effect is playing, rather than while it is not playing.
dwCoords
One or more coordinate system flags (DIEFF_CARTESIAN, DIEFF_POLAR, DIEFF_SPHERICAL) indicating which coordinate systems are supported by the effect. At least one coordinate system must be supported. If an application attempts to set a direction in an unsupported coordinate system, DirectInput automatically converts it to a coordinate system that the device does support.

Comments

For information on the DIEFFECT, DICONSTANTFORCE, DIRAMPFORCE, DIPERIODIC, DICONDITION, DICUSTOMFORCE, and DIENVELOPE structures, see the DirectInput section of the DirectX SDK.


DIEFFESCAPE

The DIEFFESCAPE structure passes hardware-specific data directly to the device driver.

typedef struct DIEFFESCAPE {
  DWORD  dwSize;
  DWORD  dwCommand;
  LPVOID  lpvInBuffer;
  DWORD  cbInBuffer;
  LPVOID  lpvOutBuffer;
  DWORD  cbOutBuffer;
} DIEFFESCAPE, *LPDIEFFESCAPE;

Members

dwSize
Specifies the size of the structure in bytes. This member must be initialized before the structure is used.
dwCommand
Specifies a driver-specific command number. Contact the hardware vendor for a list of valid commands and their parameters.
lpvInBuffer
Buffer containing the data required to perform the operation.
cbInBuffer
Specifies the size, in bytes, of the lpvInBuffer buffer.
lpvOutBuffer
Buffer in which the operation's output data is returned.
cbOutBuffer
On entry, specifies the size, in bytes, of the lpvOutBuffer buffer. On exit, specifies the number of bytes actually produced by the command.


DIFFDEVICEATTRIBUTES

The DIFFDEVICEATTRIBUTES structure describes the information contained in the "Attributes" value of the OEMForceFeedback registry key.

typedef struct {
  DWORD  dwFlags;
  DWORD  dwFFSamplePeriod;
  DWORD  dwFFMinTimeResolution;
} DIFFDEVICEATTRIBUTES;

Members

dwFlags
Reserved for future use. This member must be set to zero.
dwFFSamplePeriod
Specifies the minimum time between playback of force commands, in microseconds.
dwFFMinTimeResolution
Specifies the minimum amount of time that the device can resolve, in microseconds. The device rounds any times to the nearest supported increment. For example, if the value of dwFFMinTimeResolution is 1000, then the device would round any times to the nearest millisecond.


DIFFOBJECTATTRIBUTES

The DIFFOBJECTATTRIBUTES structure describes the information contained in the "FFAttributes" value of the registry key for each "object" on a force-feedback device. If the "FFAttributes" value is absent, then the object is assumed not to support force feedback.

typedef struct {
  DWORD  dwFFMaxForce;
  DWORD  dwFFForceResolution;
} DIFFOBJECTATTRIBUTES;

Members

dwFFMaxForce
Specifies the magnitude of the maximum force that can be created by the actuator associated with this object. Force is expressed in Newtons and measured in relation to where the hand would be during normal operation of the device. If this member is zero, the object is assumed not to support force feedback.
dwFFForceResolution
Specifies the force resolution of the actuator associated with this object. The returned value represents the number of gradations, or subdivisions, of the maximum force that can be expressed by the force feedback system from 0 (no force) to maximum force.


DIGCPAGEINFO

The DIGCPAGEINFO structure defines a page in a property sheet.

typedef struct
{
  DWORD  dwSize;
  LPWSTR  lpwszPageTitle;
  DLGPROC  fpPageProc;
  BOOL  fProcFlag;
  DLGPROC  fpPrePostProc;
  BOOL  fIconFlag;
  LPWSTR  lpwszPageIcon;
  LPWSTR  lpwszTemplate;
  LPARAM  lParam;
  HINSTANCE  hInstance;
} DIGCPAGEINFO, *LPDIGCPAGEINFO;

Members

dwSize
Specifies the size of the structure in bytes. This member must be initialized before the structure is used.
lpwszPageTitle
Title of the property sheet dialog box. This title overrides the title specified in the dialog box template. This member can specify either the identifier of a string resource or the address of a string that specifies the title.
fpPageProc
Pointer to the dialog box procedure for the page. The dialog box procedure must not call the EndDialog function.
fProcFlag
If this member is TRUE, the fpPrePostProc is called when it is created and when it is about to be destroyed. If this flag is FALSE, the fpPrePostProc is ignored.
fpPrePostProc
Pointer to an application-defined callback function that is called when the page is created and when it is about to be destroyed. For more information about the callback function, see the description of the PropSheetPageProc function as defined in the DirectInput portion of the DirectX SDK.
fIconFlag
Specifies a Boolean value that indicates the name of the icon resource to load. If this value is TRUE, lpwszPageIcon is used as the name of the icon resource to load and use as the small icon on the tab of the page.
lpwszPageIcon
Icon resource to use as the small icon in the tab for the page. If fIconFlag is FALSE, this parameter is ignored. This member is ignored for Windows CE.
lpwszTemplate
Dialog box template used to create the page. This member can specify either the resource identifier of the template or the address of a string that specifies the name of the template.
lParam
Application-defined data.
hInstance
Handle to the instance from which to load the dialog box template, icon, or title string resource.


DIGCSHEETINFO

The DIGCSHEETINFO structure defines a page in a property sheet.

typedef struct {
  DWORD  dwSize;
  USHORT  nNumPages;
  LPWSTR  lpwszSheetCaption;
  BOOL  fSheetIconFlag;
  LPWSTR  lpwszSheetIcon;
} DIGCSHEETINFO, *LPDIGCSHEETINFO;

Members

dwSize
Specifies the size of the structure in bytes. This member must be initialized before the structure is used.
nNumPages
Specifies the number of pages in this sheet.
lpwszSheetCaption
Title of the property sheet dialog box. This member can specify either the identifier of a string resource or the pointer to a string that specifies the title.
fSheetIconFlag
Specifies a Boolean value that indicates the name of the icon resource to load. If this value is TRUE, lpwszSheetIcon becomes the name of the icon resource to load and use as the small icon for the sheet.
lpwszSheetIcon
Icon resource to use as the small icon for the title bar of the property sheet dialog box. This member can specify either the identifier of a string resource or the pointer to a string that specifies the title. If fIconFlag is FALSE, this parameter is ignored. This member is ignored for Windows CE.


DIHIDFFINITINFO

The DIHIDFFINITINFO structure is used by DirectInput to provide information to a HID force-feedback driver about the device it is being asked to control.

typedef struct {
  DWORD  dwSize;
  LPWSTR  pwszDeviceInterface;
  GUID  GuidInstance;
} DIHIDFFINITINFO;

Members

dwSize
Specifies the size of the structure in bytes. This member must be initialized before the structure is used.
pwszDeviceInterface
Pointer to a null-terminated UNICODE string that identifies the device interface for the device. The driver can pass the device interface to the Win32 CreateFile function to obtain access to the device.
GuidInstance
Specifies a device instance GUID for this device.


DIJOYCONFIG

The DIJOYCONFIG structure contains information about a joystick's configuration.

typedef struct {
  DWORD  dwSize;
  GUID  guidInstance;
  JOYREGHWCONFIG  hwc;
  DWORD  dwGain;
  WCHAR  wszType[MAX_JOYSTRING];
  WCHAR  wszCallout[MAX_JOYSTRING];
  GUID  guidGameport;
} DIJOYCONFIG;

Members

dwSize
Specifies the size of the structure in bytes. This member must be initialized before the structure is used.
guidInstance
Specifies the instance GUID for the joystick.
hwc
Joystick hardware configuration.
dwGain
Specifies the global gain setting. This value is applied to all force feedback effects as a "master volume control".
wszType[MAX_JOYSTRING]
The joystick type for the joystick. It must be one of the values enumerated by IDirectInputJoyConfig8::EnumTypes.
wszCallout[MAX_JOYSTRING]
The callout driver for the joystick.
guidGameport
Specifies a GUID that identifies the Gameport being used for this joystick.

Comments

WDM gameports can be found during enumeration by calling IDirectInputJoyConfig8::GetTypeInfo method for an enumerated joystick, then studying the flags present in the dwFlags member of the DIJOYTYPEINFO structure. If the JOY_HWS_ISGAMEPORTBUS flag is set, the currently enumerated object is an available WDM gameport.


DIJOYTYPEINFO

The DIJOYTYPEINFO structure contains information about a joystick type.

typedef struct DIJOYTYPEINFO {
  DWORD  dwSize;
  JOYREGHWSETTINGS  hws;
  CLSID  clsidConfig;
  WCHAR  wszDisplayName[MAX_JOYSTRING];
  WCHAR  wszCallout[MAX_JOYSTICKOEMVXDNAME];
  WCHAR  wszHardwareId[MAX_JOYSTRING];  // WDM Only
  DWORD  dwFlags1;
  DWORD  dwFlags2;
} DIJOYTYPEINFO, *LPDIJOYTYPEINFO;

Members

dwSize
Specifies the size of the structure in bytes. This member must be initialized before the structure is used.
hws
Joystick hardware settings.
clsidConfig
Specifies a CLSID for the joystick type configuration object. Pass this CLSID to CoCreateInstance to create a configuration object. This field is zero if the type does not have custom configuration.
wszDisplayName[MAX_JOYSTRING]
The display name for the joystick type. The display name is the name that should be used to display the name of the joystick type to the end user.
wszCallout[MAX_JOYSTICKOEMVXDNAME]
The device responsible for handling polling for devices of this type. This is a null string if the global polling callout is to be used.
wszHardwareId
The hardware ID for the joystick type. The hardware ID is used by Plug and Play on Windows 2000 and Windows 98 (DirectX 7.0 only) to find the drivers for the joystick.
dwFlags1
Joystick type flags. This member can be set to a combination of the following flags.
JOYTYPE_ZEROGAMEENUMOEMDATA
Zero GameEnum's OEM data field.
JOYTYPE_NOAUTODETECTGAMEPORT
Device does not support Autodetect gameport.
JOYTYPE_NOHIDDIRECT
Do not use HID directly for this device. (Windows 98 only.)
JOYTYPE_DEFAULTPROPSHEET
CPL overrides custom property sheet.
dwFlags2
Combination of device filtering, and device type/subtype override flags. Device-filtering flags should be placed in the high WORD of dwFlags2. Device type and subtype should be placed in the low and high WORDs of the member, respectively.
Device Filtering Flags
JOYTYPE_DEVICEHIDE
Hide unclassified devices.
JOYTYPE_MOUSEHIDE
Hide mice.
JOYTYPE_KEYBHIDE
Hide keyboards.
JOYTYPE_GAMEHIDE
Hide game controllers.
JOYTYPE_HIDEACTIVE
Hide flags are active. This flag must be included if any other hide flags are specified.
Device Type and Subtype Override Flags
Device Type | Device Subtype
DI8DEVTYPE_1STPERSON | DI8DEVTYPE1STPERSON_LIMITED
DI8DEVTYPE1STPERSON_UNKNOWN
DI8DEVTYPE1STPERSON_SIXDOF
DI8DEVTYPE1STPERSON_SHOOTER
DI8DEVTYPE_DEVICE | n/a
DI8DEVTYPE_DEVICECTRL | DI8DEVTYPEDEVICECTRL_UNKNOWN
DI8DEVTYPEDEVICECTRL_COMMSSELECTION
DI8DEVTYPEDEVICECTRL_COMMSSELECTION_HARDWIRED
DI8DEVTYPE_DRIVING | DI8DEVTYPEDRIVING_LIMITED
DI8DEVTYPEDRIVING_COMBINEDPEDALS
DI8DEVTYPEDRIVING_DUALPEDALS
DI8DEVTYPEDRIVING_THREEPEDALS
DI8DEVTYPEDRIVING_HANDHELD
DI8DEVTYPE_FLIGHT | DI8DEVTYPEFLIGHT_LIMITED
DI8DEVTYPEFLIGHT_STICK
DI8DEVTYPEFLIGHT_YOKE
DI8DEVTYPEFLIGHT_RC
DI8DEVTYPE_GAMEPAD | DI8DEVTYPEGAMEPAD_LIMITED
DI8DEVTYPEGAMEPAD_STANDARD
DI8DEVTYPEGAMEPAD_TILT
DI8DEVTYPE_JOYSTICK | DI8DEVTYPEJOYSTICK_LIMITED
DI8DEVTYPEJOYSTICK_STANDARD
DI8DEVTYPEJOYSTICK_ENHANCED
DI8DEVTYPE_KEYBOARD | DI8DEVTYPEKEYBOARD_UNKNOWN
DI8DEVTYPEKEYBOARD_PCXT
DI8DEVTYPEKEYBOARD_OLIVETTI
DI8DEVTYPEKEYBOARD_PCAT
DI8DEVTYPEKEYBOARD_PCENH
DI8DEVTYPEKEYBOARD_NOKIA1050
DI8DEVTYPEKEYBOARD_NOKIA9140
DI8DEVTYPEKEYBOARD_NEC98
DI8DEVTYPEKEYBOARD_NEC98LAPTOP
DI8DEVTYPEKEYBOARD_NEC98106
DI8DEVTYPEKEYBOARD_JAPAN106
DI8DEVTYPEKEYBOARD_JAPANAX
DI8DEVTYPEKEYBOARD_J3100
DI8DEVTYPE_MOUSE | DI8DEVTYPEMOUSE_UNKNOWN
DI8DEVTYPEMOUSE_TRADITIONAL
DI8DEVTYPEMOUSE_FINGERSTICK
DI8DEVTYPEMOUSE_TOUCHPAD
DI8DEVTYPEMOUSE_TRACKBALL
DI8DEVTYPEMOUSE_ABSOLUTE
DI8DEVTYPE_REMOTE | DI8DEVTYPEREMOTE_UNKNOWN
DI8DEVTYPE_SCREENPOINTER | DI8DEVTYPESCREENPTR_UNKNOWN
DI8DEVTYPESCREENPTR_LIGHTGUN
DI8DEVTYPESCREENPTR_LIGHTPEN
DI8DEVTYPESCREENPTR_TOUCH
DI8DEVTYPE_SUPPLEMENTAL | DI8DEVTYPESUPPLEMENTAL_UNKNOWN
DI8DEVTYPESUPPLEMENTAL_2NDHANDCONTROLLER
DI8DEVTYPESUPPLEMENTAL_HEADTRACKER
DI8DEVTYPESUPPLEMENTAL_HANDTRACKER
DI8DEVTYPESUPPLEMENTAL_SHIFTSTICKGATE
DI8DEVTYPESUPPLEMENTAL_SHIFTER
DI8DEVTYPESUPPLEMENTAL_THROTTLE
DI8DEVTYPESUPPLEMENTAL_SPLITTHROTTLE
DI8DEVTYPESUPPLEMENTAL_COMBINEDPEDALS
DI8DEVTYPESUPPLEMENTAL_DUALPEDALS
DI8DEVTYPESUPPLEMENTAL_THREEPEDALS
DI8DEVTYPESUPPLEMENTAL_RUDDERPEDALS

Comments

A "joystick type" describes how DirectInput should communicate with the device and how it should report device data. For example, "A Frobozz Industries SuperStick 5X is a three-axis, five-button joystick with the third axis reported as the first bit on the second port."

DirectInput comes with the following predefined joystick types, all with axes in their default locations.

  • Two-axis, two-button joystick.
  • Two-button game pad.
  • Two-button flight yoke.
  • Two-button flight yoke with throttle.
  • Three-axis, two-button joystick.
  • Three-axis, four-button joystick.
  • Four-button game pad.
  • Four-button flight yoke.
  • Four-button flight yoke with throttle.

If the joystick type has the JOY_HWS_ISGAMEPORTDRIVER flag set in the dwFlags member of the JOYHWSETTINGS structure, then the wszCallout member of the DIJOYTYPEINFO structure contains the name of a driver that can be used as a global driver. The joystick type should be shown on the list of global drivers and not shown on the list of joystick types that can be assigned.

New in DirectX 8.0

The dwFlags2 member was added to the DIJOYCONFIG structure. This member carries information that controls how DirectInput enumerates the device to applications. The dwFlags2 member carries device type and subtype override flags in the low word, and device enumeration "hiding" flags in the high word. The device type and subtype override flags control how DirectInput portrays your device to applications that use DirectInput. These are the same flags that applications receive from DirectInput during device enumeration. For example, if your device is described in its firmware as a telephony device, it would not normally be enumerated to games because telephony devices aren't considered relevant to games. However, if you used the DI8DEVTYPE_DEVICECONTROL and DI8DEVTYPE_DEVICECONTROL_COMMSELECTION to describe this device, DirectInput overrides the data it retrieves from the firmware and enumerates the device to games.

The high word of dwFlags2 can be set to contain flags that scope how DirectInput enumerates the device to DirectInput applications. For example, some devices declare multiple top-level HID collections. Such a device might declare that it can act as a keyboard, a mouse, and a joystick all in one. Generally, one or more of these top-level collections is merely a phantom device, which shouldn't be enumerated to games. For this device, the high word of dwFlags2 could be set to a combination of the JOYTYPE_HIDEACTIVE, JOYTYPE_MOUSEHIDE, and JOYTYPE_KEYBHIDE flags. The JOYTYPE_HIDEACTIVE flag indicates that DirectInput should not enumerate the device by all its types. The JOYTYPE_MOUSEHIDE and JOYTYPE_KEYBHIDE flags also present in the high word indicate to DirectInput that enumeration of the phantom mouse and keyboard on the device should be suppressed. Note that applications can include the DIEDFL_INCLUDEHIDDEN flag to enumerate devices, even if they are hidden.


DIJOYUSERVALUES

The DIJOYUSERVALUES structure contains information about the user's joystick settings.

typedef struct {
  DWORD  dwSize;
  JOYREGUSERVALUES  ruv;
  WCHAR  wszGlobalDriver[MAX_JOYSTRING];
  WCHAR  wszGameportEmulator[MAX_JOYSTRING];
} DIJOYUSERVALUES;

Members

dwSize
Specifies the size of the structure in bytes. This member must be initialized before the structure is used.
ruv
Joystick user configuration. In addition to the fields contained in the mmddk.h header file, the previously unused jrvRanges.jpCenter field contains the user saturation levels for each axis. A control panel application sets the dead zone and saturation values based on the values set by the end-user during calibration or fine-tuning. Dead zone can be interpreted as "sensitivity in the center" and saturation can be interpreted as "sensitivity along the edges".
wszGlobalDriver[MAX_JOYSTRING]
The global port driver.
wszGameportEmulator[MAX_JOYSTRING]
Unused.


DIOBJECTATTRIBUTES

The DIOBJECTATTRIBUTES structure describes the information contained in the "Attributes" value of the registry key for each "object" on a device. If the "Attributes" value is absent, then default attributes are used.

typedef struct {
  DWORD  dwFlags;
  WORD  wUsagePage;
  WORD  wUsage;
} DIOBJECTATTRIBUTES;

Members

dwFlags
There may be zero, one, or more of the following flags:
DIDOI_FFACTUATOR
Indicates that the object can have force feedback effects applied to it.
DIDOI_FFEFFECTTRIGGER
Indicates that the object can trigger playback of force feedback effects.
DIDOI_ASPECTPOSITION
Indicates that the object reports position information.
DIDOI_ASPECTVELOCITY
Indicates that the object reports velocity information.
DIDOI_ASPECTACCEL
Indicates that the object reports acceleration information.
DIDOI_ASPECTFORCE
Indicates that the object reports force information.
DIDOI_ASPECTMASK
Indicates the bits that are used to report aspect information. An object can represent, at most, one aspect.
DIDOI_POLLED
Indicates that the object must be explicitly polled in order for data to be retrieved from it. If this flag is not set, then data for the object is interrupt-driven.
wUsagePage
Specifies the HID usage page to associate with the object.
wUsage
Specifies the HID usage to associate with the object.


DIOBJECTCALIBRATION

The DIOBJECTCALIBRATION structure describes the information contained in the "Calibration" value of the registry key for each axis on a device.

typedef struct {
  LONG  lMin;
  LONG  lCenter;
  LONG  lMax;
} DIOBJECTCALIBRATION;

Members

lMin
Specifies the logical value for the axis minimum position.
lCenter
Specifies the logical value for the axis center position.
lMax
Specifies the logical value for the axis maximum position.

Comments

If the "Calibration" value is absent, then the calibration information is taken from the joystick JOYREGHWVALUES configuration structure.

Only HID joysticks have a "Calibration" value.


JOYOEMHWCAPS

The JOYOEMHWCAPS structure contains the hardware capabilities.

typedef struct {
  DWORD  dwMaxButtons;
  DWORD  dwMaxAxes;
  DWORD  dwNumAxes;
} JOYOEMHWCAPS, *LPJOYOEMHWCAPS;

Members

dwMaxButtons
Indicates the number of buttons on the device.
dwMaxAxes
Indicates the highest axis number that can be polled.
dwNumAxes
Indicates the number of axes on the device.


JOYOEMPOLLDATA

The JOYOEMPOLLDATA structure is passed to joystick minidrivers for a poll request.

typedef struct {
  DWORD  id;
  DWORD  do_other;
  JOYPOS  jp;
  DWORD  dwPOV;
  DWORD  dwButtons;
  DWORD  dwButtonNumber;
} JOYOEMPOLLDATA, *LPJOYOEMPOLLDATA;

Members

id
Indicates the identifier of the device being polled.
do_other
The definition of this parameter depends on the type of poll. The type of polling and the definition of this parameter are:
JOY_OEMPOLL_POLL1
Axis to poll.
JOY_OEMPOLL_POLL2
Unused.
JOY_OEMPOLL_POLL3
Poll X, Y, and R if nonzero, or poll X, Y, and Z otherwise.
JOY_OEMPOLL_POLL4
Unused.
JOY_OEMPOLL_POLL5
Poll X, Y, Z, R, and V if nonzero, or poll X, Y, Z, R, and U otherwise.
JOY_OEMPOLL_POLL6
Unused.
JOY_OEMPOLL_GETBUTTONS
Unused.
JOY_OEMPOLL_PASSDRIVERDATA
DWORD of data to pass to the driver. (This was introduced in DirectX 3.0.)
jp
Contains the axis data.
dwPOV
Contains the POV hat information (0 to 35999).
dwButtons
Specifies a bitmap of pressed buttons, with the first button in the least significant bit.
dwButtonNumber
Specifies the number of the lowest button number pressed, or zero if none. For example, this parameter is 1 for the first button, 2 for the second, or 1 for the first and second.


JOYREGHWVALUES

The JOYREGHWVALUES structure contains the range of values returned by the hardware (filled in by calibration).

typedef struct joyreghwvalues_tag
{
  DWORD  dwSize;
    JOYRANGE    jrvHardware;
    DWORD       dwPOVValues[JOY_POV_NUMDIRS];
    DWORD       dwCalFlags;

} JOYREGHWVALUES, FAR *LPJOYREGHWVALUES;

Members

jrvHardware
The values returned by the hardware.
dwPOVValues[JOY_POV_NUMDIRS]
The POV values returned by the hardware.
dwCalFlags
What has been calibrated.


VJCFGCHG

The DirectInput effect driver passes the VJCFGCHG structure in the dwParam of a CtrlMsg callback to report version information back to DirectInput.

 typedef struct VJCFGCHG
{
  DWORD  dwSize;
  DWORD  dwChangeType;
  DWORD  dwTimeOut;
} VJCFGCHG, *LPVJCFGCHG;

Members

dwSize
Specifies the size, in bytes, of the structure. This member must be initialized before the structure is used.
dwChangeType
Indicates the type of change that has been made. One of the following:
VJCMCT_GENERAL
Generic change type notification.
dwTimeOut
Specifies the dwTimeOut value from the user data registry values. This value is passed as a convenience to drivers that use it, because there are no other driver values in this structure.


VJDEVICEDESC

The VJDEVICEDESC structure contains data that describes the device being registered.

typedef struct VJDEVICEDESC
{
  DWORD  dwSize;
  LPSTR  lpszOEMName;
  DWORD  dwUnitId;
  LPJOYOEMHWCAPS  lpHWCaps;
  LPJOYREGHWCONFIG  lpHWConfig;
} VJDEVICEDESC, *VJLPDEVICEDESC;

Members

dwSize
Specifies the size, in bytes, of the structure. This member must be initialized before the structure is used.
lpszOEMName
Reserved for future use.
dwUnitId
Specifies the unit ID of this device.
lpHWCaps
Reserved for future use.
lpHWConfig
Reserved for future use.


VJFORCEREG

The VJFORCEREG structure registers the callbacks to the ring 0 (kernel-mode) force-feedback driver.

typedef struct VJFORCEREG
{
  DWORD  dwSize;
  SETGAINRTN  fpSetFFGain;
  SENDFFCOMMANDRTN  fpSendFFCommand;
  GETFFSTATERTN  fpGetFFState;
  DOWNLOADEFFECTRTN  fpDownloadEff;
  DESTROYEFFECTRTN  fpDestroyEff;
  STARTEFFECTRTN  fpStartEff;
  STOPEFFECTRTN  fpStopEff;
  GETEFFECTSTATUSRTN  fpGetStatusEff;
} VJFORCEREG, *VJLPFORCEREG;

Members

dwSize
Specifies the size, in bytes, of the structure. This member must be initialized before the structure is used.
fpSetFFGain
Pointer to the SetGain callback.
fpSendFFCommand
Pointer to the SendForceFeedbackCommand callback.
fpGetFFState
Pointer to the GetForceFeedbackState callback.
fpDownloadEff
Pointer to the DownloadEffect callback.
fpDestroyEff
Pointer to the DestroyEffect callback.
fpStartEff
Pointer to the StartEffect callback.
fpStopEff
Pointer to the StopEffect callback.
fpGetStatusEff
Pointer to the GetEffectStatus callback.


VJGPEMULREG

The VJGPEMULREG structure is reserved for future use and should not be used.

typedef struct VJGPEMULREG
{
  DWORD  dwSize;
    JOYOEMGPEMULCTRL  lpGPEmulCtrl;
    JOYOEMGPEMULTRAP  lpGPEmulTrap;
} VJGPEMULREG, *LPVJGPEMULREG;


VJPOLLDATA

The VJPOLLDATA structure collects sensor data from a minidriver for DirectX 5.0 and later versions.

typedef struct _VJPOLLDATA
{
  DWORD  dwX;
  DWORD  dwY;
  DWORD  dwZ;
  DWORD  dwR;
  DWORD  dwU;
  DWORD  dwV;
  DWORD  dwPOV0;
  DWORD  dwPOV1;
  DWORD  dwPOV2;
  DWORD  dwPOV3;
  DWORD  dwBTN0;
  DWORD  dwBTN1;
  DWORD  dwBTN2;
  DWORD  dwBTN3;
  DWORD  dwReserved0;
  DWORD  dwReserved1;
} VJPOLLDATA, *LPVJPOLLDATA;

Members

dwX
Contains the X axis value.
dwY
Contains the Y axis value.
dwZ
Contains the Z axis value.
dwR
Contains the R axis value.
dwU
Contains the U axis value.
dwV
Contains the V axis value.
dwPOV0
Contains the first POV value.
dwPOV1
Contains the second POV value.
dwPOV2
Contains the third POV value.
dwPOV3
Contains the fourth POV value.
dwBTN0
Contains the first DWORD of button bits (buttons 1 to 32).
dwBTN1
Contains the second DWORD of button bits (buttons 33 to 64).
dwBTN2
Contains the third DWORD of button bits (buttons 65 to 96).
dwBTN3
Contains the fourth DWORD of button bits (buttons 97 to 128).
dwReserved0 and dwReserved1
Reserved for future use.


VJPOLLREG

The VJPOLLREG structure contains the callbacks to the minidriver.

typedef struct VJPOLLREG
{
  DWORD  dwSize;
  JOYPOLLRTN  fpPoll;
  CMCONFIGHANDLER  fpCfg;
  INITIALIZERTN  fpInitialize;
  ESCAPERTN  fpEscape;
  CTRLMSGRTN  fpCtrlMsg;
} VJPOLLREG, *LPVJPOLLREG;

Members

dwSize
Specifies the size, in bytes, of the structure. This member must be initialized before the structure is used.
fpPoll
Pointer to the Poll callback.
fpCfg
Pointer to the configuration manager callback. For more information, see Configuration Manager Callback.
fpInitialize
Pointer to the Initialize callback.
fpEscape
Pointer to the Escape callback.
fpCtrlMsg
Pointer to the CtrlMsg callback.


VJREGDRVINFO

The VJREGDRVINFO structure passes the new style registration information to VJoyD. All of the members of this structure must be filled in, although the version members can be set to zero for unknown, and the last four pointers can be set selectively to none.

typedef struct VJREGDRVINFO
{
  DWORD  dwSize;
  DWORD  dwFunction;
  DWORD  dwFlags;
  LPSTR  lpszOEMCallout;
  DWORD  dwFirmwareRevision;
  DWORD  dwHardwareRevision;
  DWORD  dwDriverVersion;
  LPVJDEVICEDESC  lpDeviceDesc;
  LPVJPOLLREG  lpPollReg;
  LPVJFORCEREG  lpForceReg;
  LPVJGPEMULREG  lpGPEmulReg;
} VJREGDRVINFO, *LPVJREGDRVINFO;

Members

dwSize
Specifies the size, in bytes, of the structure. This member must be initialized before the structure is used.
dwFunction
Indicates the type of registration to be performed. This value can be one of the following:
VJRT_CHANGE
Indicates that anything can change except the driver and initialization parameters. For future use.
VJRT_LOADED
Indicates that the driver has been loaded.
VJRT_PLUG
Indicates a new instance of a device. For future use.
VJRT_UNPLUG
Indicates to VJoyD that a registered device is no longer available. For future use.
dwFlags
Flags associated with this registration. One or more of the following:
VJDF_UNUSED
Indicates the driver is not in use.

The following flags are interface attributes (that is, the result is combination of OEM flag and VJoyD):

VJDF_UNIT_ID
Indicates the unit ID is valid.
VJDF_ISHID
Indicates that this is an HID device, so refuse polls.
VJDF_SENDSNOTIFY
Indicates the driver calls VJOYD_DeviceUpdateNotify_Service.
VJDF_NEWIF
Indicates that use new interface may be changed on registration (is set by VJoyD).
VJDF_ATTR_MASK
Indicates a combination of VJDF_NEWIF, VJDF_UNIT_ID, and VJDF_ISHID.

The following flags are interface requirements:

VJDF_AUTOLOAD
Indicates that VxD must not be loaded by VJoyD.
VJDF_HOTPLUG
Uses PLUG/UNPLUG.
VJDF_IF_REQ_MASK
Indicates a combination of VJDF_AUTOLOAD and VJDF_HOTPLUG.

The following are device node requirement flags:

VJDF_NODEVNODE
Indicates that the device did not get its resources via CFG_MGR.
VJDF_ISANALOGPORTDRIVER
Indicates that the device plugs into a standard game port.
VJDF_NOCHAINING
Indicates a limit of one device node per device.
VJDF_DN_REQ_MASK
Indicates a combination of the attributes signified by the VJDF_NODEVNODE, VJDF_ISANALOGPORTDRIVER, and VJDF_NOCHAINING flags.
lpszOEMCallout
Pointer to a string, such as "Msanalog.vxd", that identifies the driver associated with this registration.
dwFirmwareRevision
Specifies the firmware revision of the device. If the revision is unknown, a value of zero should be used.
dwHardwareRevision
Specifies the hardware revision of the device. If the revision is unknown, a value of zero should be used.
dwDriverVersion
Specifies the version number of the device driver. If the revision is unknown, a value of zero should be used.
lpDeviceDesc
Pointer to a VJDEVICEDESC structure that describes the configuration properties of the device. This allows drivers to supply the description of the device rather than use the registry for this purpose. If no description is available, this member should be set to NULL.
lpPollReg
Pointer to a VJPOLLREG structure that contains the most common driver callbacks. In the very rare case that a driver does need to register any of these callbacks, this member should be set to NULL.
lpForceReg
Pointer to a VJFORCEREG structure that contains all of the force feedback specific callbacks. If the ring 0 (kernel mode) driver does not support force feedback, this member should be set to NULL.
lpGPEmulReg
Reserved. This member must be set to NULL.


DirectInput Messages

DirectInput Application Access Message

DirectInput® supports new notification messages that are broadcast to notify when DirectInput applications have begun to use DirectInput services. These notifications can be used to detect recently started applications that use DirectInput and how those applications are making use of DirectInput's features. Your application can register for notifications by calling the Win32® function, RegisterWindowMessage, and passing DIRECTINPUT_NOTIFICATION_MSGSTRING (defined in dinputd.h).

As with any other call to RegisterNotificationMessageString, the UINT value returned by the function is the message value that registered applications should hook in their window process. Once received, the wParam parameter for the message describes the type of notification being sent. The value of wParam is one of the following constants, defined in dinputd.h:

Messages (wParam)
DIMSGWP_NEWAPPSTART
DirectInput has been initialized by an application that has not been used by the current user before.
DIMSGWP_DX8APPSTART
A DirectInput has been initialized by an application that is using DirectX® 8.0 DirectInput features, but did not use DirectInput mapper functions on any previous run by the current user.
DIMSGWP_DX8MAPPERAPPSTART
A DirectInput has been initialized by an application that uses DirectInput mapper functions provided in DirectX 8.0.

Comments

Upon receiving these notifications, an application can query for additional information by way of the IDirectInputJoyConfig8::OpenAppStatusKey method.


Supporting IEEE 1284.4 Devices

This section includes the following topics about support for multifunction IEEE 1284.4 devices in Microsoft® Windows® 2000 and later:

Dot4 Device Setup Classes

Dot4 Device Drivers

Installing a Dot4 Device

See the following topics for more information about Dot4 device support:

The Microsoft Dot4 Driver

Dot4 Driver Reference


Dot4 Device Setup Classes

This section describes the following device setup classes that a vendor uses with multifunction IEEE 1284.4 devices:

Dot4 Device Setup Class

Dot4Print Device Setup Class

Image Device Setup Class and Dot4 Scanner Functions


Dot4 Device Setup Class

Microsoft defines the Dot4 device setup class for the parent device that controls the operation of a multifunction IEEE 1284.4 peripheral device. Note that in the DDK, Dot4 refers to the Dot4 device setup class, not to the IEEE specification IEEE P1284.4, Standard for Data Delivery and Logical Channels for IEEE Std. 1284 Interfaces.

An IEEE 1284.4-compliant device can:

  • Export its functionality as a set of services, which a client accesses over channels.
  • Communicate by using a protocol that supports:
    • Multiple, concurrent, independent exchanges of data and control information between peers over an IEEE 1284.4 data link.
    • A packet-based, non-blocking, flow control system.

See the IEEE 1284.4 specification for more information about IEEE 1284.4 compliant devices.

Microsoft provides the Dot4 driver, the system-supplied function and bus driver for Dot4 devices, in Windows 2000 and later. The Dot4 driver abstracts the IEEE 1284.4 protocol and operates a Dot4 device in the following way:

  • A Dot4 device is a Plug and Play parent device that supports one or more Plug and Play child devices, or Dot4 functions.
  • A Dot4 function supports one or more subfunctions, or Dot4 services.
  • To access a Dot4 service, a client opens a Dot4 function, creates a Dot4 socket for the service, and opens a Dot4 channel on the socket.

To install a Dot4 device, a vendor must:

  • Publish the name and IEEE 1284.4 secondary socket ID of each service.
  • Supply an INF file for the parent Dot4 device and the INF files that are required to install the child Dot4 functions supported by the Dot4 device — see Installing a Dot4 Device.

An example of a Dot4 device is a multifunction device that supports one or more of the following functional capabilities: printing, scanning, and faxing. The Dot4 driver represents each functional capability as an independent Dot4 function. Examples of Dot4 services include generic operations such as: data write, data read, configuration download, configuration upload, fax send, and fax receive.


Dot4Print Device Setup Class

A Dot4 print function, which is a Dot4 function that implements a print function, is a member of the Dot4Print device setup class. A Dot4Print device is a parent device that has a single child device; the child device is a member of the Printer device setup class.

Dot4Print devices do not require vendor drivers because Microsoft provides the following:

  • Dot4prt driver — the system function driver for a parent Dot4Print device
  • Dot4prt.inf file that installs a Dot4Print device
  • Port monitor support for Printer devices

Note Microsoft supplies the Dot4prt driver to provide a software connection layer between existing system printer components and Dot4 print functions.

A vendor must provide an INF file for the child Printer device associated with the parent Dot4 print function.

See the following topics for more information about support for a Dot4Print device:

Dot4 Device Driver Stacks

Device Stacks for Dot4 Devices

Installing a Dot4 Print Function

Introduction to Printing


Image Device Setup Class and Dot4 Scanner Functions

A Dot4 scanner function, which is a Dot4 function that implements a scanner function, is a member of the Image device setup class.

Dot4 scanner functions do not require vendor drivers because Microsoft provides the following:

  • Dot4scan driver — the system function driver for Dot4 scanner functions.
  • Windows Image Acquisition (WIA) drivers, which support user-mode clients communicating with imaging devices such as digital cameras and scanners.

Note Microsoft supplies the Dot4scan driver to provide a software connection layer between existing system imaging components and Dot4 scanner functions.

A vendor must provide an INF file to install a Dot4 scanner function.

See the following topics for more information about support for Dot4 scanner functions:

Dot4 Device Driver Stacks

Device Stacks for Dot4 Devices

Installing a Dot4 Scanner Function


Dot4 Device Drivers

This section includes the following topics:

Dot4 Device Driver Stacks

Device Stacks for Dot4 Devices

System-Supplied Drivers for Dot4 Devices

Vendor-Supplied Drivers for Dot4 Devices


Dot4 Device Driver Stacks

The following figure shows the driver stacks that support a Dot4 device:

Driver Stacks for a Parent Dot4 Device and its Child Dot4 Functions

See the following topics for more information about supporting a Dot4 device:

Device Stacks for Dot4 Devices

System-Supplied Drivers for Dot4 Devices

Vendor-Supplied Drivers for Dot4 Devices

Installing a Dot4 Device

The Microsoft Dot4 Driver


Device Stacks for Dot4 Devices

The following figure shows the device stacks for Dot4 devices:

Device Stacks for a Dot4 Device that Supports a Printer, a Scanner, and a Toaster Device

See the following for more information about supporting a Dot4 device:

Dot4 Device Driver Stacks

System-Supplied Drivers for Dot4 Devices

Vendor-Supplied Drivers for Dot4 Devices

Installing a Dot4 Device

The Microsoft Dot4 Driver


System-Supplied Drivers for Dot4 Devices

Microsoft® Windows® 2000 and later includes the following driver support for Dot4 devices:

  • The Dot4 driver is the function driver and bus driver for the Dot4 device setup class. The Dot4 driver enumerates and controls access to all its child devices, or Dot4 functions. The executable image of the Dot4 driver is dot4.sys.
  • The system-supplied bus driver for parallel ports is the parent bus driver for Dot4 devices that are attached to a parallel port. This bus driver supports the Dot4 data link that the Dot4 driver requires to access a Dot4 device. For more information about the parallel port bus driver, see System-Supplied Parallel Drivers.
  • The Dot4prt driver is the function and bus driver for the Dot4Print device setup class. The Dot4prt driver provides a connection layer between existing system printer components and Dot4 print functions. The Dot4prt driver creates a functional device object (FDO) for a Dot4Print device and a physical device object (PDO) for a single-child device, which is a member of the Printer device setup class. Upper-level system printer components and drivers access and operate Printer devices. The executable image of the Dot4prt driver is dot4prt.sys.
  • The Dot4scan driver is the function driver for Dot4 scanner functions, which are Dot4 functions that implement a scanner. The Dot4scan driver provides a connection layer between existing system imaging components and Dot4 scanner functions. A Dot4 scanner function is a member of the Image device setup class, and is operated through the services of the WIA drivers. The executable image of the Dot4scan driver is dot4scan.sys.


Vendor-Supplied Drivers for Dot4 Devices

A vendor usually does not have to supply drivers for a Dot4 device because:

  • Microsoft provides the Dot4 driver, which is the system function and bus driver for the Dot4 device setup class.
  • The Dot4 driver provides the necessary functionality to directly operate a Dot4 device's child devices, or Dot4 functions. A client uses the Dot4 function I/O control codes that the Dot4 driver supports to operate a Dot4 function.

A vendor only has to supply a WDM function driver for a Dot4 function if the vendor chooses to provide an upper-level interface for the Dot4 function that the Dot4 driver does not provide. However, Microsoft requires that the function driver only use the services of the Dot4 driver to actually operate the Dot4 function.


Installing a Dot4 Device

This section includes the following topics about installing a parent Dot4 device and its child Dot4 functions:

Installing a Parent Dot4 Device and its Child Dot4 Functions

Installing a Dot4 Print Function

Installing a Dot4 Scanner Function


Installing a Parent Dot4 Device and its Child Dot4 Functions

To install a parent Dot4 device and its child Dot4 functions, a vendor supplies:

  • An INF file for the Dot4 device
  • An INF file for each Dot4 function that the device supports
  • A WDM function driver for each Dot4 function

    A Dot4 function requires a vendor driver if there is no system-supplied class driver and a client can not directly operate a Dot4 function by using Dot4 function I/O control codes.

See the following topics for more information:

System and Sample INF files

Specifying Dot4 Functions

Copying System Driver Files

Specifying Optional Dot4 Device Configuration Settings

System and Sample INF files

The following system and sample INF files document the sections that install a parent Dot4 device and its child Dot4 functions:

  • System INF files
    • dot4.inf, for the Dot4 device setup class
    • dot4prt.inf, for the Dot4Print device setup class
  • Sample INF files in the src\print\infs\mfp directory of the Windows DDK
    • dot4oem.inf, for the Dot4 device setup class
    • oemprnd4.inf, for the child Printer device of a parent Dot4Print device
    • dot4oems.inf, for a Dot4 scanner function

Specifying Dot4 Functions

A Dot4 device INF file must include an AddReg directive in the device's hardware install section that specifies the Dot4 functions that the device supports. The following excerpt from dot4oem.inf specifies that the device supports a "PRINT" function (a Dot4Print device) and a "SCAN" function (an Image device):

[OEM_MFP_AddReg]
HKR,%Printer_Func%,%Desc_Val%,,%OEM_MFP_Printer%
HKR,%Scanner_Func%,%Desc_Val%,,%OEM_MFP_Scanner%
. . . .
[Strings]
. . . .
Desc_Val            = "Description"
Printer_Func        = "Functions\PRINT"
Scanner_Func        = "Functions\SCAN"
. . . .
OEM_MFP_Printer     = "OEM Company 1284.4 MFP - Printer"
OEM_MFP_Scanner     = "OEM Company 1284.4 MFP - Scanner"

The system INF file dot4prt.inf installs a Dot4Print device, and a vendor dot4oems.inf file installs the Dot4 scanner function.

Copying System Driver Files

Vendors should not distribute copies of the Dot4 system drivers. To copy a system driver file, a vendor should include in a device's INF file one of the following install sections that dot4.inf contains:

  • [Dot4_OEM] – copies dot4.sys
  • [Dot4Prt_OEM] – copies dot4prt.sys
  • [Dot4Scan_OEM] – copies dot4scan.sys

For example, dot4oems.inf contains the following Include and Needs entry pair to copy the system Dot4 scan driver:

[Dot4Scan_Inst.NT]
;
; These entries tell the Image class installer what files to copy and
;   whet type of device to install.
;
. . . .
Include=DOT4.INF
Needs=DOT4SCAN_OEM

Specifying Optional Dot4 Device Configuration Settings

A vendor can add optional INF AddReg directives to a Dot4 device's hardware install section to specify the following configuration settings:

Dot4 Services

Dot4 Flow Control Policy

Dot4 Timeouts


Installing a Dot4 Print Function

By default, system setup uses dot4prt.inf (and the Dot4prt driver) to install the Dot4Print device setup class. The vendor only has to supply an INF file for the child Printer device.

For information about creating an INF file for a child Printer device, see the sample INF file oemprnd4.inf provided in the DDK. The system class installer ntprint.dll installs the Printer device.

The following table summarizes the device setup classes and example hardware IDs associated with a Dot4 print function, as specified in dot4oem.inf, dot4prt.inf, and oemprnd4.inf:

Device Setup Class | Enumerator | Hardware ID
Printer | Dot4prt.sys | DOT4PRT\OEM_Company_1284.4_M9C9C
Dot4Print | Dot4.sys | DOT4\PRINT
Dot4 | Parallel.sys | LPTENUM\OEM_Company_1284.4_M9C9C

The dot4prt.inf INF file includes the following AddReg directive that specifies the default service configuration settings for a Dot4Print device:

[Dot4Print_AddReg]
;
; Add keys under Enum\enumeratorID\device-instance-id
;
;HKR,,"ReadService",,%ReadServiceName%
;HKR,,"WriteService",,%WriteServiceName%
HKR,,"ReadSocketId",0x00010001,0x0002
HKR,,"WriteSocketId",0x00010001,0x0002
HKR,,"ReadBufferSize",0x00010001,0x7FFF
HKR,,"WriteBufferSize",0x00010001,0x7FFF

Service Configuration Settings for a Dot4Print Device

The following table describes the default service configuration settings that dot4prt.inf specifies for a Dot4Print device:

Service Entry Value | Description
ReadService (REG_SZ) | Specifies the read service name. If the INF file does not specify a read service name, but does specify a write service name, the Dot4prt driver uses the write service to read and write. If the INF file does not specify a read or write service name, the Dot4prt driver uses the IEEE 1284.4 secondary socket ID specified by the entry value ReadSocketId. If the read service entry value does not exist, the Dot4prt driver creates one and sets its default value to "\0".
WriteService (REG_SZ)
 Specifies the write service name. If the INF file does not specify a write service name, but does specify a read service name, the Dot4prt driver uses the read service to read and write. If the INF file does not specify a read or write service name, the Dot4prt driver uses the IEEE 1284.4 secondary socket ID specified by the entry value WriteSocketId. If the write service entry value does not exist, the driver creates one and sets its default value to "\0".
ReadSocketId (REG_SZ)
 Specifies an IEEE 1284.4 secondary socket ID that the Dot4prt driver uses to read from a Dot4Print device. If the read socket ID entry value does not exist, the driver creates one and sets its default value to 0x2.
WriteSocketId (REG_SZ)
 Specifies an IEEE 1284.4 secondary socket ID that the Dot4prt driver uses to write to a device. If the write socket ID entry value does not exist, the driver creates one and sets its default value to 0x2.
ReadBufferSize (REG_DWORD)
 Specifies the size, in bytes, of an internal read buffer that the Dot4prt driver uses to copy data from the device to the host. If the read buffer size entry value does not exist, the Dot4prt driver creates one and sets its default value to 0x7FFF.
WriteBufferSize (REG_DWORD)
 Specifies the size, in bytes, of an internal write buffer that the Dot4prt driver use to copy data from the host to the device. If the write buffer size entry value does not exist, the driver creates one and sets its default value to 0x7FFF.


Installing a Dot4 Scanner Function

A vendor only has to supply an INF file for the Dot4 scanner function. The sample INF file dot4oems.inf describes the sections that install a Dot4 scanner function.

The following table summarizes the device setup classes and example hardware IDs for a Dot4 scanner function, as specified in dot4oem.inf and dot4oems.inf:

Device Setup Class | Enumerator | Hardware ID
Image | Dot4.sys | DOT4\OEM_Company_1284.4_M9C9C&SCAN
Dot4 | Parallel.sys | LPTENUM\OEM_Company_1284.4_M9C9C

A client accesses an Image device by using the services of the WIA drivers. A client opens a device by using its symbolic link name, which has the format "\DosDevices\Parscan<n>", where n is an integer greater than or equal to zero.

The dot4oems.inf INF file includes the following AddReg directive that specifies default service configuration information for a Dot4 scanner function:

[Dot4Scan_AddReg]
;
; Add keys under Enum\enumeratorID\device-instance-id
;
;       These entries in the registry control
HKR,,"ReadSocketId",0x00010001,0x0004
HKR,,"WriteSocketId",0x00010001,0x0004
HKR,,"ReadBufferSize",0x00010001,0x7FFF
HKR,,"WriteBufferSize",0x00010001,0x7FFF

The meaning of these settings is the same as that described in Service Configuration Settings for a Dot4Print Device. Note, however, that the default values for a Dot4 scanner function and a Dot4Print device are different.


The Microsoft Dot4 Driver

This chapter includes the following topics about the Dot4 driver, the system-supplied function and bus driver for the Dot4 device setup class in Microsoft® Windows® 2000 and later:

Dot4 Driver Features

Dot4 Driver Operation

Note In this documentation, Dot4 refers to the Dot4 device class, not to the IEEE specification IEEE P1284.4, Standard for Data Delivery and Logical Channels for IEEE Std. 1284 Interfaces.


Dot4 Driver Features

This section summarizes the features of the Dot4 driver.

The Dot4 driver:

  • Operates an independent logical bus for each Dot4 device that is installed on a host system.

    Each Dot4 device supports one or more independent Dot4 functions that are child devices of the Dot4 device. Each Dot4 function supports one or more subfunctions, or Dot4 services. Each service is accessed over a Dot4 channel that is bound to an IEEE 1284.4 primary socket.

  • Supports Dot4 function I/O control codes that abstract the IEEE 1284.4 communication protocol.

    Clients must use these I/O control codes to access a Dot4 function. A client can be a Windows 2000 or later application, a subsystem of the operating system, or a kernel-mode driver.


Dot4 Driver Operation

This section includes the following topics about the operation of the Dot4 driver:

  • Dot4 Session

    To operate a Dot4 device, a client starts a Dot4 session (or joins a running session), and then uses a sequence of device control requests that specify Dot4 Function I/O control codes.

  • Dot4 Function

    A Dot4 function is a generic name for an independent function supported by a Dot4 device.

  • Dot4 Service

    The functionality of Dot4 device is exported as a set of Dot4 services.

  • Dot4 Socket

    A Dot4 socket represents a communication endpoint of a Dot4 channel.

  • Dot4 Channel

    A Dot4 channel is a bidirectional communication link that a client can use to access a Dot4 service.

  • Dot4 Data Link

    The Dot4 driver establishes an IEEE 1284.4 data link with a Dot4 device.

  • Reading and Writing Over a Dot4 Channel

    Clients use IOCTL_DOT4_READ and IOCTL_DOT4_WRITE I/O control codes to read and write data over a Dot4 channel.

  • Dot4 Activity Broadcasting

    A client can use Dot4 activity broadcasting to be notified after certain events, or activities, occur on a Dot4 channel.

  • Dot4 Flow Control Policy

    Dot4 supports a credit-based flow control policy, which a client can set, that partly regulates the flow of data over Dot4 channels during a Dot4 session.

  • Dot4 Timeouts

    Dot4 supports timeout values, which a client can set, that partly control the operation of a Dot4 session.

  • Dot4 Plug and Play Support
  • Dot4 Power Management Support
  • Dot4 WMI Support
  • Dot4 Registry Settings


Dot4 Session

To operate a Dot4 device, a client starts a Dot4 session (or joins a running session), and then uses a sequence of device control requests that specify Dot4 Function I/O control codes — see Dot4 Session.

A Dot4 session is the set of Dot4 driver operations on a Dot4 device during a continuous period of time in which at least one Dot4 function, opened with write access, remains open. If a Dot4 session is not running, the Dot4 driver starts a session after it receives the first create request that specifies write access for a Dot4 function. The Dot4 driver ends a session after either all Dot4 functions, opened with write access, are closed, or a fatal error occurs when attempting to communicate with a Dot4 device. If a fatal communication error occurs, the Dot4 driver's error handling ends the session, and completes I/O requests with status STATUS_UNSUCCESSFUL until the Dot4 driver resets device communication. The Dot4 driver resets device communication after clients close all Dot4 functions opened with write access. After the Dot4 driver resets device communication, a client can try to start a new session.

Before a client starts a Dot4 session, it can dynamically set Dot4 flow control policy and Dot4 timeouts for the Dot4 session.

A Dot4 session is based on the concept of an IEEE 1284.4 conversation between two IEEE 1284.4 peers. Only the Dot4 driver can initiate a Dot4 session. During a Dot4 session (and associated IEEE 1284.4 conversation), the host system is the IEEE 1284.4 primary device, and the peripheral device is an IEEE 1284.4 secondary device.

Example of a Dot4 Session

A client uses the following sequence of I/O requests to start (or join) a Dot4 session, access a Dot4 service, and end (or leave) a Dot4 session:

  • An IRP_MJ_CREATE request (specifying write access) opens the Dot4 function that supports a Dot4 service.

    If a Dot4 session is not running when the Dot4 driver receives the create request, the Dot4 driver starts a Dot4 session.

  • An IOCTL_DOT4_CREATE_SOCKET request creates a Dot4 Socket (an IEEE 1284.4 primary socket) for the Dot4 service supported by the Dot4 function.
  • An IOCTL_DOT4_OPEN_CHANNEL request opens a Dot4 channel for the Dot4 service. Alternatively, the client can use an IOCTL_DOT4_WAIT_FOR_CHANNEL request to wait for the Dot4 function to open a channel for the service.
  • A sequence of IOCTL_DOT4_WRITE and IOCTL_DOT4_READ requests write and read data over the service channel.
  • An IOCTL_DOT4_CLOSE_CHANNEL request closes a service channel.
  • An IOCTL_DOT4_DESTROY_SOCKET request deletes the socket created for the service.
  • An IRP_MJ_CLOSE request closes the Dot4 function.

    If no Dot4 functions, opened with write access, remain open after the Dot4 driver closes the Dot4 function, the Dot4 driver ends the Dot4 session.

Note A client can also use Dot4 activity broadcasting during a Dot4 session to be notified about activities that dynamically occur on a Dot4 channel.


Dot4 Function

A Dot4 function is a generic name for a child device of a Dot4 device.

A Dot4 device's INF file adds the specific name and description of each Dot4 function under the Functions key of the Dot4 device's Plug and Play hardware device key. A client can enumerate a Dot4 device's Functions key to determine which Dot4 functions the device supports. See Dot4 Functions Registry Key and Installing a Dot4 Device for more information.

A Dot4 function is opened and closed by using an IRP_MJ_CREATE request and an IRP_MJ_CLOSE request.

Opening a Dot4 Function Without Write Access

Opening a Dot4 function without write access has the following results:

  • A Dot4 function is not associated with a Dot4 session, and opening and closing a function has no affect on a session.
  • A client can receive Plug and Play notifications (or other types of notifications) for a device. For example, a client using the services the Microsoft Windows Image Acquisition (WIA) drivers can receive Plug and Play notifications.

Opening a Dot4 Function with Write Access

Opening a Dot4 function with write access has the following results:

  • A Dot4 function is associated with a Dot4 session.
  • If the Dot4 driver detects a device communication error during a session, its error handling operation ends the session, and completes I/O requests with status STATUS_UNSUCCESSFUL until the Dot4 driver resets device communication. The Dot4 driver resets device communication after clients close all Dot4 functions that were opened with write access. After the Dot4 driver resets device communication, a client can try to start a new session.


Dot4 Service

The functionality of a Dot4 device is exported as a set of Dot4 services. A vendor must document the service names and associated IEEE 1284.4 secondary socket IDs that a Dot4 device supports.

To access a service, a client uses the following I/O requests:

  • IRP_MJ_CREATE

    An IRP_MJ_CREATE request, which specifies write access, opens a Dot4 function that supports a service.

  • IOCTL_DOT4_CREATE_SOCKET

    An IOCTL_DOT4_CREATE_SOCKET request obtains an IEEE 1284.4 primary socket ID for the service. A client uses a vendor-documented service name or IEEE 1284.4 secondary socket ID to specify the service. If the client specifies the service name, the secondary socket ID is not used. A client uses the primary socket ID to open a Dot4 channel for the service.

  • IOCTL_DOT4_OPEN_CHANNEL

    An IOCTL_DOT4_OPEN_CHANNEL request opens a Dot4 channel for the service.

  • Dot4 function I/O control codes

    Dot4 function I/O control codes control the operation of the Dot4 channel.

To disconnect from the service, a client uses an IOCTL DOT4_CLOSE_CHANNEL request. This request is normally followed by an IOCTL_DOT4_DESTROY_SOCKET request.

A client can discover what services are defined for a device by enumerating the service names under the Services key of the device's Plug and Play hardware device key. See Dot4 Services Registry Key and Installing a Dot4 Device for more information.


Dot4 Socket

A Dot4 socket is a logical endpoint for a Dot4 channel. A Dot4 channel is associated with an IEEE 1284.4 primary socket on the host system (the IEEE 1284.4 primary device) and an IEEE 1284.4 secondary socket on the peripheral (an IEEE 1284.4 secondary device).

A client binds a primary socket to a secondary socket by using an IOCTL_DOT4_CREATE_SOCKET request. A client uses a DOT4_DC_CREATE_DATA structure to input and output information.

A Dot4 socket can be a packet-type socket or a stream-type socket. The Dot4 driver transmits data over a packet-type socket using independent packets. The maximum amount of data that can be transmitted over a packet-type socket by a single read or write request is 65529 bytes. The Dot4 driver transmits data over a stream-type socket in a continuous, ordered sequence of packets.


Dot4 Channel

A Dot4 channel provides a logical conduit for bidirectional communication between a client and a Dot4 device. The client uses a Dot4 channel to access a Dot4 service. Dot4 channels operate concurrently and independently of one another, and the transmission of data is flow-controlled. A Dot4 channel can be a packet-type channel or a stream-type channel, which is determined by the type of IEEE 1284.4 primary socket that was created for the channel.

A client opens a Dot4 channel on a Dot4 socket by using an IOCTL_DOT4_OPEN_CHANNEL request. A client uses a DOT4_DC_OPEN_DATA structure to input and output information.

A client can wait for a Dot4 device to open a Dot4 channel by using an IOCTL_DOT4_WAIT_FOR_CHANNEL request.

A client closes a Dot4 channel by using an IOCTL_DOT4_CLOSE_CHANNEL request. A close channel request is normally followed by an IOCTL_DOT4_DESTROY_SOCKET request.


Dot4 Data Link

The Dot4 driver requires that the drivers below it in a Dot4 device stack support an IEEE 1284.4 data link. The Dot4 driver uses internal device control requests to establish the required data link. In response to these internal device control requests, the system-supplied bus driver for parallel ports establishes an IEEE 1284.3 data link with a device. (An IEEE 1284.3 data link meets the requirements of an IEEE 1284.4 data link.)


Reading and Writing Over a Dot4 Channel

A client uses IOCTL_DOT4_READ and IOCTL_DOT4_WRITE requests to read and write data over a Dot4 channel. The Dot4 driver does not support IRP_MJ_READ and IRP_MJ_WRITE requests because these requests do not provide a way to specify a channel.

The Dot4 driver supports two types of read requests:

  • Read-bytes request

    Copies data from a channel to a client-allocated read buffer. The Dot4 driver uses direct I/O to copy the data from the channel to the read buffer.

  • Query-read-bytes request

    Determines the number of data bytes that are available on a channel.

The Dot4 driver supports two types of write requests:

  • Write-bytes request

    Copies data to a channel from a client-allocated write buffer. The Dot4 driver uses direct I/O to copy the data from the write buffer to the channel.

  • Query-write-bytes request

    Determines the number of data bytes that a channel is ready to accept.

A client specifies read and write information using a DOT4_DRIVER_CMD structure.


Dot4 Activity Broadcasting

A client can use Dot4 activity broadcasting to be notified after certain events, or activities, occur on a Dot4 channel.

A client can add activity broadcasting when a Dot4 channel is opened or by using an IOCTL_DOT4_ADD_ACTIVITY_BROADCAST request. If activity broadcasting is active on a channel, the Dot4 driver queues activities on an activity queue in the order in which they occur. An activity is represented by a DOT4_ACTIVITY structure.

A client registers to be notified if an activity occurs by using an IOCTL_DOT4_WAIT_ACTIVITY_BROADCAST request. The Dot4 driver completes the wait request if an activity exists on the activity queue. If there are no queued activities when the Dot4 driver processes the wait request, it sets the status of the request to STATUS_PENDING, and queues the wait request.

After a client adds activity broadcasting, it should immediately use an IOCTL_DOT4_WAIT_ACTIVITY_BROADCAST request. If activities are not removed at the same rate as they are added to the queue, the activity queue will expand indefinitely.

A client removes activity broadcasting by using an IOCTL_DOT4_REMOVE_ACTIVITY_BROADCAST request. The Dot4 driver deletes all activities on the activity queue, and completes all pending wait requests.


Dot4 Flow Control Policy

The Dot4 driver uses a credit-based flow control policy to regulate the flow of data over each Dot4 channel. The Dot4 flow control policy is based on the following IEEE 1284.4 data flow control mechanism:

A receiving IEEE 1284.4 peer controls the amount of data sent to it by granting credits to a sending IEEE 1284.4 peer. There is a one-to-one correspondence between credits and packets.

See the IEEE 1284.4 specification for more information on IEEE 1284.4 credit-based data flow control.

On a packet-type Dot4 channel, the Dot4 driver always uses IEEE 1284.4 piggyback credit to grant credits to the peripheral. A piggy back credit is a credit that is specified in an IEEE 1284.4 packet header.

On a stream-type Dot4 channel, Dot4 flow control policy is partly controlled by entry values in the Policy key of a device's Plug and Play hardware device key. When the Dot4 driver starts a session, it uses the entry values in the Policy key to set flow control policy. If a policy entry value does not exist, the Dot4 driver sets a default. To fine-tune flow control, a client can dynamically adjust the following aspects of flow control policy before it starts a session:

  • credit on zero length

    Specifies whether the Dot4 driver grants credits to a peripheral by using piggyback credits in a header-only packet. The default value is FALSE.

  • piggyback credit

    Specifies whether the Dot4 driver grants available peripheral-to-host credits by sending piggyback credits when a packet is written to the peripheral. The default value is FALSE.

  • ask credit after write

    Specifies whether the Dot4 driver requests credit by using an IEEE 1284.4 CreditRequest transaction if host-to-peripheral credits are exhausted after a write operation. The default value is TRUE.

  • command packet two parts

    Specifies whether the Dot4 driver sends command packets over an IEEE 1284.4 Transaction Channel in two parts (that is, separate, consecutive writes of the packet header and payload). The default value is TRUE.

See Dot4 Policy Registry Key for more information about setting flow control policy.


Dot4 Timeouts

The Dot4 driver supports timeouts that partly control the operation of a Dot4 session. Entry values in the Timeout key under a device's Plug and Play hardware device key specify the limits associated with these timeouts. See Dot4 Timeout Registry Key for more information about the timeout entry values.

When the Dot4 driver starts a session, it uses the existing timeout entry values to set the timeout limits. If an entry value does not exist, the Dot4 driver sets a default value. A client can dynamically set the following timeout limits:

  • interbyte timeout

    Limits the maximum time, in milliseconds, that can occur between sending or receiving consecutive packet parts over a Dot4 channel. If the limit is exceeded, the Dot4 session is terminated. The interbyte timeout does not restrict the total time used to send or receive a packet — except, by implication, the total time required must be less than or equal to (interbyte timeout limit)*(number of packet bytes transferred). The default value is 500 milliseconds.

  • standard packet timeout

    Limits the maximum time, in milliseconds, that a peripheral has to respond to an IEEE 1284.4 command. If the standard packet timeout is exceeded, the Dot4 driver terminates a Dot4 session. The default value is 3000 milliseconds.

  • credit timeout

    Limits the maximum time that can occur between the completion of a host-initiated IEEE 1284.4 CreditRequest transaction, in which the peripheral grants zero credits; and a subsequent peripheral-initiated IEEE 1284.4 Credit transaction that grants one or more credits.

    If the limit is exceeded, the Dot4 driver "pings" the peripheral to verify the Dot4 data link by sending an IEEE 1284.4 Credit command with zero credits. The corresponding CreditReplay from the peripheral is subject to the interbyte timeout and the standard packet timeout. If the peripheral responds to the Credit command in time, the session remains active, and the credit timeout is reset. Otherwise, the Dot4 driver terminates a Dot4 session.

    The default value is 5000 milliseconds.


Dot4 Plug and Play Support

A Dot4 function handles the following Plug and Play requests:

IRP_MN_CANCEL_REMOVE_DEVICE

IRP_MN_CANCEL_STOP_DEVICE

IRP_MN_QUERY_BUS_INFORMATION

IRP_MN_QUERY_CAPABILITIES

IRP_MN_QUERY_DEVICE_RELATIONS

IRP_MN_QUERY_DEVICE_TEXT

IRP_MN_QUERY_ID

IRP_MN_QUERY_PNP_DEVICE_STATE

IRP_MN_QUERY_REMOVE_DEVICE

IRP_MN_QUERY_STOP_DEVICE

IRP_MN_REMOVE_DEVICE

IRP_MN_START_DEVICE

IRP_MN_STOP_DEVICE

IRP_MN_SURPRISE_REMOVAL

For all other Plug and Play requests, the Dot4 driver sets the Status member of the I/O status block to STATUS_SUCCESS, and completes the request without further processing.


Dot4 Power Management Support

A Dot4 function supports the following power requests:

IRP_MN_QUERY_POWER

IRP_MN_SET_POWER

The Dot4 driver does not support the following requests, and completes them as indicated:
IRP_MN_POWER_SEQUENCE
Returns STATUS_NOT_IMPLEMENTED.
IRP_MN_WAIT_WAKE
Returns STATUS_NOT_SUPPORTED.

The parent bus driver of a Dot4 device is the power policy owner for the device.


Dot4 WMI Support

The Dot4 driver registers the following types of WMI library callback routines for a Dot4 function:

DpWmiQueryReginfo

DpWmiQueryDataBlock

The Dot4 driver's DpWmiQueryReginfo routine registers a DOT4_WMI_BYTES_TRANSFERRED_GUID GUID, and the driver's DpWmiQueryDataBlock routine returns a WMI data block that contains a single instance of a DOT4_WMI_XFER_INFO structure. The DOT4_WMI_XFER_INFO structure contains information about data flow over Dot4 channels.

See Windows Management Instrumentation for more information about WMI operation.


Dot4 Registry Settings

This section describes the following registry settings for a Dot4 device and a Dot4 function:

PortName Entry Value

Dot4 Functions Registry Key

Dot4 Services Registry Key

Dot4 Policy Registry Key

Dot4 Timeout Registry Key


Dot4 PortName Entry Value

The following PortName entry value is located under the Plug and Play hardware device key for a Dot4 device and a Dot4 function:

PortName entry value (REG_SZ)
Specifies the name of the parallel port used by a Dot4 device. A Dot4 device, and all its child devices (Dot4 functions), use the same port name.


Dot4 Functions Registry Key

The following Functions key is located under a Dot4 device's Plug and Play hardware device key:

Functions key
Contains a set of Function name subkeys for a Dot4 device.
Functions\<Function name> key
Specifies the name of a Dot4 function supported by the Dot4 device. Each Function name corresponds to an independent function supported by the device. The Dot4 driver creates a named physical device object for each function name. The device name has the format "\Device\DOT4\<Function name><Bus number>". A Function name key has the following entry value:
Description entry value (REG_SZ)
Contains function type.


Dot4 Services Registry Key

The following Services key is located under a Dot4 device's Plug and Play hardware device key:

Services key
Contains a set of Service name subkeys for a Dot4 device.
Services\<Service name> key
Specifies the name of a service. The Service name key contains the following configuration entry values:
HostToPeriSize entry value (REG_DWORD)
Specifies the maximum packet size that can be used over a Dot4 channel to transfer data from the host to the peripheral. The default value is TO_PERI_PACKET_SIZE.
PeriToHostSize entry value (REG_DWORD)
Specifies the maximum packet size that can be used over a Dot4 channel to transfer data from the peripheral to the host. The default value is TO_PERI_PACKET_SIZE.

The Dot4 driver creates registry entries for Dot4 services that are statically defined in the driver. If a static service name is not present, Dot4 adds the service name to the registry. If a service name is present, but a configuration entry value is not present, Dot4 adds the entry value, and sets it to a default value.


Dot4 Policy Registry Key

The following Policy key is located under a Dot4 device's Plug and Play hardware device key:

Policy key
Contains the following flow control entry values:
CreditOnZeroLength entry value (REG_DWORD)
Boolean flag that specifies whether the Dot4 driver can issue credits to a peripheral by sending only a header packet. The default value is FALSE (zero).
PiggyBackCredit entry value (REG_DWORD)
Boolean flag that specifies whether the Dot4 driver can piggyback credits when it sends a header packet to a peripheral over a stream channel. The default value is FALSE (zero).
AskCreditAfterWrite entry value (REG_DWORD)
Boolean flag that specifies whether the Dot4 driver requests host-to-peripheral credits if Dot4 is out of credits after writing a data packet. The default value is TRUE (nonzero).
CommandPacketTwoParts entry value (REG_DWORD)
Boolean flag that specifies whether the Dot4 driver sends command packets over the Transaction Channel in two parts (that is, it uses separate, consecutive writes of the header and data). The default value is TRUE (nonzero).

The Dot4 driver creates a Policy key if one does not exist. If an entry value does not exist under the Policy key, the Dot4 driver creates the entry value and sets it to the specified default value.


Dot4 Timeout Registry Key

The following Timeout key is located under a Dot4 device's Plug and Play hardware device key:

Timeout key
Contains the following timeout entry values for a Dot4 device:
InterByteTimeout entry value (REG_DWORD)
Specifies the maximum time that can occur between packet parts before a timeout on the Dot4 data link can occur. The default value is 500 (in milliseconds).
StandardPacketTimeout entry value (REG_DWORD)
The value of the StandardPacketTimeout entry value specifies the maximum time that a peripheral can take to reply to a command packet. The default value is 3000 (in milliseconds).
CreditTimeout entry value (REG_DWORD)
Specifies the maximum time Dot4 waits to be granted credits by a Dot4 device. The default value is 5000 (in milliseconds).

The Dot4 driver creates a Timeout key if one does not exist. If an entry values does not exist under the Timeout key, The Dot4 driver creates the entry value and sets it to the specified default value.


Dot4 Driver Reference

This section includes the following topics about the Dot4 driver, the system-supplied function and bus driver for the Dot4 device setup class in Microsoft® Windows® 2000:

Dot4 Function I/O Control Codes

Dot4 Data Structures

Note The Dot4 refers to the Dot4 device class, not to the IEEE 1284.4 specification (IEEE P1284.4, Standard for Data Delivery and Logical Channels for IEEE Std. 1284 Interfaces).


Dot4 Function I/O Control Codes

This section describes the following I/O control codes that a client can use with an IRP_MJ_DEVICE_CONTROL request to operate a Dot4 function:

IOCTL_DOT4_ADD_ACTIVITY_BROADCAST

IOCTL_DOT4_CLOSE_CHANNEL

IOCTL_DOT4_CREATE_SOCKET

IOCTL_DOT4_DESTROY_SOCKET

IOCTL_DOT4_OPEN_CHANNEL

IOCTL_DOT4_READ

IOCTL_DOT4_REMOVE_ACTIVITY_BROADCAST

IOCTL_DOT4_WAIT_ACTIVITY_BROADCAST

IOCTL_DOT4_WAIT_FOR_CHANNEL

IOCTL_DOT4_WRITE

For all other I/O control codes, the Dot4 driver skips the current stack location, and sends the associated device control requests down the device stack of the Dot4 device. The device control requests are completed by the lower-level drivers without further processing by the Dot4 driver.

The Dot4 driver only processes device control requests for Dot4 functions that are opened with write access.

The Dot4 driver queues device control requests for later processing.

Generic Status Values for Dot4 IOCTLS

The Information member is set to a request-specific value.

The Status member is set to a request-specific value or to one of the following generic values:

STATUS_SUCCESS
STATUS_BUFFER_TOO_SMALL
The Parameters.DeviceIoControl.InputBufferLength member of the IRP's current I/O stack location is less than the size, in bytes, of a DOT4_DRIVER_CMD structure.
STATUS_DELETE_PENDING
Plug and Play is removing the device.
STATUS_INSUFFICIENT_RESOURCES
One of the following errors occurred:
  • System memory for a dynamic data structure is not available.
  • The channel handle or channel is not valid.
  • The specified channel is closed.
STATUS_IO_DEVICE_ERROR
An error occurred that is fatal to the Dot4 session.
STATUS_PENDING
The Dot4 driver queued the request for later processing.
STATUS_UNSUCCESSFUL
One of the following errors occurred:
  • A Dot4 session is not running.
  • The client does not have write access to the Dot4 function.
  • An error occurred that is not fatal to a Dot4 session.


IOCTL_DOT4_ADD_ACTIVITY_BROADCAST

Operation

The IOCTL_DOT4_ADD_ACTIVITY_BROADCAST request adds Dot4 activity broadcasting on a Dot4 channel.

Input

Irp->AssociatedIrp.SystemBuffer is a pointer to a client-allocated DOT4_DRIVER_CMD structure that inputs the following information:

hChannelHandle
Specifies a channel handle that is obtained by the client by using an IOCTL_DOT4_OPEN_CHANNEL request.

Other members should be set to zero.

The Parameters.DeviceIoControl.InputBufferLength member of the IRP's current I/O stack location is set to the size, in bytes, of a DOT4_DRIVER_CMD structure.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values for Dot4 IOCTLS.

See Also

IOCTL_DOT4_REMOVE_ACTIVITY_BROADCAST, IOCTL_DOT4_WAIT_ACTIVITY_BROADCAST


IOCTL_DOT4_CLOSE_CHANNEL

Operation

The IOCTL_DOT4_CLOSE_CHANNEL request closes a Dot4 channel.

If Dot4 activity broadcasting is active on the channel when the Dot4 driver receives this request, it removes activity broadcasting, and then closes the channel.

Input

Irp->AssociatedIrp.SystemBuffer is a pointer to a client-allocated DOT4_DRIVER_CMD structure that inputs the following information:

hChannelHandle
Specifies a channel handle.

Other members must be set to zero.

The Parameters.DeviceIoControl.InputBufferLength member of the IRP's current I/O stack location is set to the size, in bytes, of a DOT4_DRIVER_CMD structure.

I/O Status Block

The Information member is set to the size, in bytes, of a DOT4_DRIVER_CMD structure.

The Status member is set to one of the generic status values for Dot4 IOCTLS.

See Also

IOCTL_DOT4_REMOVE_ACTIVITY_BROADCAST, IOCTL_DOT4_OPEN_CHANNEL


IOCTL_DOT4_CREATE_SOCKET

Operation

The IOCTL_DOT4_CREATE_SOCKET request creates an IEEE 1284.4 primary socket for a specified Dot4 service. A client uses the primary socket ID with an IOCTL_DOT4_OPEN_CHANNEL request to open a Dot4 channel for a service. See Dot4 Socket for more information about Dot4 sockets.

Input

Irp->AssociatedIrp.SystemBuffer is a pointer to a client-allocated DOT4_DRIVER_CMD structure, whose members must be set to zero.

The Parameters.DeviceIoControl.InputBufferLength member of the IRP's current I/O stack location is set to the size, in bytes, of a DOT4_DRIVER_CMD structure.

Irp->MdlAddress is a pointer to a client-allocated MDL buffer for a DOT4_DC_CREATE_DATA structure that inputs and outputs information. The client inputs the following information:

bPsid
Specifies a well-known IEEE 1284.4 secondary socket ID (that is, a socket ID that a device vendor documents). If a Dot4 service name is specified, the socket ID is not used. A socket ID of zero is associated with an IEEE 1284.4 Transaction Channel, and is invalid if the socket ID is used.
pServiceName
Specifies an array that contains the service name (a NULL-terminated ANSI string) of a secondary socket. If a service name is specified, the secondary socket ID is not used.
bType
Specifies the type of socket, either STREAM_TYPE_CHANNEL or PACKET_TYPE_CHANNEL.
ulBufferSize
Specifies the size, in bytes, of the socket's internal read buffer. The Dot4 driver sets the internal buffer size to the larger of ulBufferSize and the peripheral-to-host packet size that the Dot4 driver sets for the socket. The ulBufferSize member should be set to zero for a write-only socket.
usMaxHtoPPacketSize
Specifies the maximum size, in bytes, of a packet that can be sent from the host to the peripheral. The Dot4 driver negotiates the largest packet size that the peripheral supports, bounded by the maximum requested by the client.
usMaxPtoHPacktetSize
Specifies the maximum size, in bytes, of a packet that can be sent from the peripheral to the host. The Dot4 driver negotiates the largest packet size that the peripheral supports, bounded by the maximum requested by the client.

The Parameters.DeviceIoControl.OutputBufferLength member of the IRP's current I/O stack location is set to the size, in bytes, of a DOT4_DC_CREATE_DATA structure.

Output

Irp->MdlAddress is a pointer to the client-allocated MDL buffer for a DOT4_DC_CREATE_DATA structure that outputs the following information:

bHsid
Specifies the IEEE 1284.4 primary socket ID for the specified service.

I/O Status Block

The Information member is set to the size, in bytes, of a DOT4_DC_CREATE_DATA structure.

The Status member is set to one of the generic status values for Dot4 IOCTLS or to one of the following request-specific values:

STATUS_BUFFER_TOO_SMALL
The Parameters.DeviceIoControl.OutputBufferLength member of the IRP's current I/O stack location is less than the size, in bytes, of a DOT4_DC_CREATE_DATA structure.
STATUS_NO_MEMORY
The system did not successfully map the client-allocated MDL buffer for the DOT4_DC_CREATE_DATA structure that inputs and outputs information.
STATUS_UNSUCCESSFUL
One of the following errors occurred:
  • The secondary socket ID is zero, and the service name is NULL or an empty string.
  • The service name or secondary socket ID is not valid.
  • Both usMaxHtoPPacketSize and usMaxPtoHPacktetSize are set to zero.

See Also

IOCTL_DOT4_OPEN_CHANNEL


IOCTL_DOT4_DESTROY_SOCKET

Operation

The IOCTL_DOT4_DESTROY_SOCKET request deletes a specified IEEE 1284.4 primary socket. See Dot4 Socket for more information about Dot4 sockets.

Input

Irp->AssociatedIrp.SystemBuffer is a pointer to a client-allocated DOT4_DRIVER_CMD structure, whose members must be set to zero.

The Parameters.DeviceIoControl.OutputBufferLength member of the IRP's current I/O stack location is set to a value greater than or equal to the size, in bytes, of a DOT4_DC_DESTROY_DATA structure.

Irp->MdlAddress is a pointer to a client-allocated MDL buffer that holds a DOT4_DC_DESTROY_SOCKET structure that inputs the following information:

bHsid
Specifies the socket ID of the IEEE 1284.4 primary socket to delete.

I/O Status Block

The Information member is set to the size, in bytes, of a DOT4_DC_DESTROY_DATA structure.

The Status member is set to one of the generic status values for Dot4 IOCTLS or to one of the following request-specific values:

STATUS_BUFFER_TOO_SMALL
The Parameters.DeviceIoControl.OutputBufferLength member of the IRP's current I/O stack location is less than the size, in bytes, of a DOT4_DC_DESTROY_DATA structure.
STATUS_NO_MEMORY
The system did not successfully map the client-allocated MDL buffer for the DOT4_DC_DESTROY_DATA structure that inputs information.
STATUS_UNSUCCESSFUL
A Dot4 channel is open on the specified primary socket, or the socket ID is invalid.

See Also

IOCTL_DOT4_CREATE_SOCKET


IOCTL_DOT4_OPEN_CHANNEL

Operation

The IOCTL_DOT4_OPEN_CHANNEL request opens a Dot4 channel for a specified Dot4 service.

The client can specify that the Dot4 driver add Dot4 activity broadcasting immediately after the channel is opened.

Input

Irp->AssociatedIrp.SystemBuffer is a pointer to a client-allocated DOT4_DRIVER_CMD structure, whose members must be set to zero.

The Parameters.DeviceIoControl.InputBufferLength member of the IRP's current I/O stack location is set to the size, in bytes, of a DOT4_DRIVER_CMD structure.

Irp->MdlAddress is a pointer to a client-allocated MDL buffer for a DOT4_DC_OPEN_DATA structure that inputs and outputs information.

The client inputs the following information:

bHsid
Specifies an IEEE 1284.4 primary socket ID, which is obtained by using an IOCTL_DOT4_CREATE_SOCKET request.
fAddActivity
Specifies whether to add activity broadcasting on a Dot4 channel immediately after the channel is opened. If fAddActivity is set to TRUE (nonzero), the Dot4 driver adds activity broadcasting; otherwise, activity broadcasting is not added.

The Parameters.DeviceIoControl.OutputBufferLength member of the IRP's current I/O stack location is set to the size, in bytes, of a DOT4_DC_OPEN_DATA structure.

Output

Irp->MdlAddress is a pointer to the client-allocated MDL buffer for the DOT4_DC_OPEN_DATA structure that outputs the following information:

hChannelHandle
Specifies a channel handle.

I/O Status Block

The Information member is set to the size, in bytes, of a DOT4_DC_OPEN_DATA structure.

The Status member is set to one of the generic status values for Dot4 IOCTLS or to one of the following values:

STATUS_BUFFER_TOO_SMALL
The Parameters.DeviceIoControl.OutputBufferLength member of the IRP's current I/O stack location is less than the size, in bytes, of a DOT4_DC_OPEN_DATA structure.
STATUS_NO_MEMORY
The system did not successfully map the client-allocated MDL buffer for the DOT4_DC_OPEN_DATA structure that inputs and outputs information.
STATUS_UNSUCCESSFUL
One of the following errors occurred:
  • The specified primary socket ID or associated channel is invalid.
  • The channel is already open.


IOCTL_DOT4_READ

Operation

The IOCTL_DOT4_READ request copies data from a specified Dot4 channel to a client-allocated read buffer.

The Dot4 driver supports the following two types of read requests:

  • Read-bytes request

    Copies data from a channel to a client-allocated read buffer. The Dot4 driver uses direct I/O to copy the data from the channel to the read buffer.

  • Query-read-bytes request

    Determines the number of data bytes that are available on a channel.

If the request is a read-bytes request, the Dot4 driver continues to copy available data from the channel to the read buffer until one of the following events occurs:

  • The requested number of bytes is read.
  • The time limit specified for the request is exceeded, and there is no more data available on the channel.
  • The Dot4 channel is closed.
  • An internal error occurs that ends the Dot4 session.

If the request is a query-read-bytes request, the Dot4 driver immediately completes the request.

Input

The following input depends on the two types of read requests:

  • Read-bytes request

    Irp->MdlAddress is a pointer to a client-allocated MDL read buffer that is used to hold the data copied from the channel.

    The Parameters.DeviceIoControl.OutputBufferLength member of the IRP's current I/O stack location specifies the size of the read buffer.

  • Query-read-bytes request

    The client sets Irp->MdlAddress to NULL and Parameters.DeviceIoControl.OutputBufferLength to zero.

The following input applies to both types of read requests:

Irp->AssociatedIrp.SystemBuffer is a pointer to a client-allocated DOT4_DRIVER_CMD structure that inputs the following information:

hChannelHandle
Specifies a channel handle.
ulSize
Specifies the number of bytes to read.
ulOffset
Specifies a byte offset in the read buffer. The Dot4 driver copies data to the read buffer starting at the byte specified by ulOffset.
ulTimeout
Specifies the maximum time, in milliseconds, that the request can take to complete. The Dot4 driver starts timing the request immediately after it is queued. If the request times out and the device is not ready to read or write more data, the Dot4 driver completes the request.

The Parameters.DeviceIoControl.InputBufferLength member of the IRP's current I/O stack location is set to the size, in bytes, of a DOT4_DRIVER_CMD structure.

Output

Irp->MdlAddress is a pointer to the client-allocated MDL read buffer that holds the data that is copied from the channel.

I/O Status Block

The Information member depends on the type of read request, and is set to one of the following values:

Query-read-bytes request
The number of bytes available to be read over the channel.
Read-bytes request
The current byte offset in the read buffer where the Dot4 driver will copy the next block of data that is read from the channel. The byte offset is initialized to ulOffset. While the request remains pending, the Dot4 driver dynamically updates the Information member each time it copies a block of data from the channel to the read buffer.

The Status member is set to one of the following values:

STATUS_BUFFER_TOO_SMALL
The MDL read buffer is too small to hold the requested read data.
STATUS_NO_MEMORY
The system did not successfully map the client-allocated MDL read buffer.
STATUS_TIMEOUT
The device did not satisfy the write request within the specified time limit.
STATUS_UNSUCCESSFUL
The channel is closed.

See Also

IOCTL_DOT4_WRITE


IOCTL_DOT4_REMOVE_ACTIVITY_BROADCAST

Operation

The IOCTL_DOT4_REMOVE_ACTIVITY_BROADCAST request removes Dot4 activity broadcasting on a specified Dot4 channel.

Input

Irp->AssociatedIrp.SystemBuffer is a pointer to a client-allocated DOT4_DRIVER_CMD structure that inputs the following information:

hChannelHandle
Specifies the channel handle value that is obtained by a client by using an IOCTL_DOT4_OPEN_CHANNEL request.

Other members must be set to zero.

The Parameters.DeviceIoControl.InputBufferLength member of the IRP's current I/O stack location is set to the size, in bytes, of a DOT4_DRIVER_CMD structure.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values for Dot4 IOCTLS.

See Also

IOCTL_DOT4_ADD_ACTIVITY_BROADCAST, IOCTL_DOT4_WAIT_ACTIVITY_BROADCAST


IOCTL_DOT4_WAIT_ACTIVITY_BROADCAST

Operation

A client uses an IOCTL_DOT4_WAIT_ACTIVITY_BROADCAST request to be notified after certain events, or activities, occur on a Dot4 channel. See Dot4 Activity Broadcasting for more information about using activity broadcasting.

Input

Irp->AssociatedIrp.SystemBuffer is a pointer to a client-allocated DOT4_DRIVER_CMD structure that is used to input the following information:

hChannelHandle
Specifies a channel handle value that was obtained by the client by using an IOCTL_DOT4_OPEN_CHANNEL request.
ulTimeout
Specifies the maximum time, in milliseconds, that Dot4 driver waits for an activity. The Dot4 driver starts timing the request immediately after it is queued. If the request times out, the Dot4 driver completes the request.

Other members must be set to zero.

The Parameters.DeviceIoControl.InputBufferLength member of the IRP's current I/O stack location is set to the size, in bytes, of a DOT4_DRIVER_CMD structure.

The Parameters.DeviceIoControl.OutputBufferLength member of the IRP's current I/O stack location is set to the size, in bytes, of a DOT4_ACTIVITY structure.

Output

Irp->MdlAddress is a pointer to a client-allocated MDL buffer for a DOT4_ACTIVITY structure that outputs activity information. If Irp->MdlAddress is set to NULL, the Dot4 driver does not return information.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values for Dot4 IOCTLS or to one of the following request-specific values:

STATUS_BUFFER_TOO_SMALL
The Parameters.DeviceIoControl.OutputBufferLength member of the IRP's current I/O stack location is less than the size, in bytes, of a DOT4_ACTIVITY structure.
STATUS_NO_MEMORY
The system did not successfully map the client-allocated MDL buffer for the DOT4_ACTIVITY structure that outputs information.
STATUS_TIMEOUT
An activity did not occur within the specified time limit.

See Also

IOCTL_DOT4_REMOVE_ACTIVITY_BROADCAST, IOCTL_DOT4_ADD_ACTIVITY_BROADCAST


IOCTL_DOT4_WAIT_FOR_CHANNEL

Operation

A client uses an IOCTL_DOT4_WAIT_FOR_CHANNEL request to wait for a Dot4 device to open a specified Dot4 channel.

The client can specify that the Dot4 driver add Dot4 activity broadcasting immediately after the channel is opened.

Input

Irp->AssociatedIrp.SystemBuffer is a pointer to a client-allocated DOT4_DRIVER_CMD structure, whose members must be set to zero.

The Parameters.DeviceIoControl.InputBufferLength member of the IRP's current I/O location is set to the size, in bytes, of a DOT4_DRIVER_CMD structure.

Irp->MdlAddress is a pointer to a client-allocated MDL buffer for a DOT4_DC_OPEN_DATA structure that inputs and outputs the following information:

bHsid
Specifies an IEEE 1284.4 primary socket ID, which is obtained using an IOCTL_DOT4_CREATE_SOCKET request.
fAddActivity
Specifies whether to add activity broadcasting on a channel immediately after it is opened. The fAddActivity member is set to TRUE (nonzero) to add activity broadcasting, otherwise fAddActivity is set to FALSE (zero).

The Parameters.DeviceIoControl.OutputBufferLength member of the IRP's current I/O stack location is set to the size, in bytes, of a DOT4_DC_OPEN_DATA structure.

Output

Irp->MdlAddress is a pointer to the client-allocated MDL buffer for the DOT4_DC_OPEN_DATA structure that outputs the following information:

hChannelHandle
Specifies a channel handle.

I/O Status Block

The Information member is set to the size, in bytes, of a DOT4_DC_OPEN_DATA structure.

The Status member is set to one of the generic status values for Dot4 IOCTLS or to one of the following request-specific values:

STATUS_BUFFER_TOO_SMALL
The Parameters.DeviceIoControl.OutputBufferLength member of the IRP's current I/O stack location is less than the size, in bytes, of a DOT4_DC_OPEN_DATA structure.
STATUS_NO_MEMORY
The system did not successfully map the client-allocated MDL buffer for the DOT4_DC_OPEN_DATA structure that inputs and outputs information.

See Also

IOCTL_DOT4_OPEN_CHANNEL


IOCTL_DOT4_WRITE

Operation

The IOCTL_DOT4_WRITE request copies data from a client-allocated write buffer to a specified Dot4 channel.

The Dot4 driver supports the following two types of write requests:

  • Write-bytes request

    Copies data to a channel from a client-allocated write buffer. The Dot4 driver uses direct I/O to copy the data from the write buffer to the channel.

  • Query-write-bytes request

    Determines the number of data bytes that a channel is ready to accept.

If the request is a write-bytes request, the Dot4 driver continues to copy data from the write buffer to the channel until one of the following events occurs:

  • The requested number of bytes is written to the channel.
  • The time limit specified for the request is exceeded and the channel is not ready to receive additional data.
  • The channel is closed.
  • An internal error occurs that ends the Dot4 session.

If the request is a query-write-bytes request, the Dot4 driver immediately completes the request and returns the number of data bytes that the channel can accept.

Input

The following input depends on the two types of write requests:

  • Write-bytes request

    Irp->MdlAddress points to a client-allocated MDL write buffer from which data is copied to a channel.

    The Parameters.DeviceIoControl.OutputBufferLength member of the IRP's current I/O stack location specifies the size of the write buffer.

  • Query-write-bytes request

    The client sets Irp->MdlAddress to NULL and Parameters.DeviceIoControl.OutputBufferLength to zero.

The following input applies to both types of write requests:

Irp->AssociatedIrp.SystemBuffer is a pointer to a client-allocated DOT4_DRIVER_CMD structure that inputs the following information:

hChannelHandle
Specifies a channel handle.
ulSize
Specifies the number of bytes to write to the channel.
ulOffset
Specifies a byte offset in the write buffer. The Dot4 driver copies data from the write buffer to the channel, starting at the byte specified by ulOffset.
ulTimeout
Specifies the maximum time, in milliseconds, that the request can take to complete. The Dot4 driver starts timing the request immediately after it is queued. If the request times out and the channel is not ready to accept data, the Dot4 driver completes the request.

The Parameters.DeviceIoControl.InputBufferLength member of the IRP's current I/O stack location is set to the size, in bytes, of a DOT4_DRIVER_CMD structure.

I/O Status Block

The Information member depends on the two types of write requests as follows:

  • Query-write-bytes request

    The number of bytes that a channel is ready to accept.

  • Write-bytes request

    The current byte offset in the write buffer that specifies the start of the next block of data that the Dot4 driver will write to a channel. The byte offset is initialized to ulOffset. While the request remains pending, The Dot4 driver dynamically updates the Information member each time it copies a block of data from the write buffer to the channel.

The Status member is set to one of the generic status values for Dot4 IOCTLS or to one of the following request-specific values:

STATUS_BUFFER_TOO_SMALL
The MDL write buffer can not hold the requested write data.
STATUS_NO_MEMORY
The system could not map the client-allocated MDL write buffer.
STATUS_TIMEOUT
The device did not satisfy the request within the specified time limit.
STATUS_UNSUCCESSFUL
The channel is closed.

See Also

IOCTL_DOT4_READ


Dot4 Data Structures

This section describes the following Dot4 data structures that input and output information with device control requests that specify a Dot4 function I/O control code:

DOT4_ACTIVITY

DOT4_DC_CREATE_DATA

DOT4_DC_DESTROY_DATA

DOT4_DC_OPEN_DATA

DOT4_DRIVER_CMD

DOT4_WMI_XFER_INFO


DOT4_ACTIVITY

A DOT4_ACTIVITY structure represents an activity, or event, that occurs on a Dot4 channel.

typedef struct _DOT4_ACTIVITY {
  ULONG  ulMessage;
  ULONG  ulByteCount;
  CHANNEL_HANDLE  hChannel;
} DOT4_ACTIVITY, *PDOT4_ACTIVITY;

Members

ulMessage
Specifies one of the following activity types:
Activity Type | Meaning
DOT4_CHANNEL_CLOSED | The channel is closed.
DOT4_DISCONNECT | The Dot4 data link is not connected.
DOT4_MESSAGE_RECEIVED | A message was received on a channel.
DOT4_STREAM_CREDITS | Credits are available to send data over a stream-type channel.
DOT4_STREAM_RECEIVED | Stream data was successfully received on a channel.
ulByteCount
Specifies one of the following message-specific values:
Activity Type | Value
DOT4_DISCONNECT and DOT4_CHANNEL_CLOSED | The value is set to zero.
DOT4_MESSAGE_RECEIVED and DOT4_STREAM_RECEIVED | The number of bytes received.
DOT4_STREAM_CREDITS | The number of credits issued by a Dot4 device.
hChannel
Specifies the handle of the channel on which the activity took place. A DOT4_DISCONNECT message returns a channel handle of zero.

Headers

Declared in d4iface.h. Include d4iface.h

Comments

A client uses an IOCTL_DOT4_ADD_ACTIVITY_BROADCAST request to start Dot4 activity broadcasting. If activity broadcasting is activated, the client uses an IOCTL_DOT4_WAIT_ACTIVITY_BROADCAST request to be notified after an activity occurs on the channel. The Dot4 driver returns a DOT4_ACTIVITY structure that describes the activity.

See Also

IOCTL_DOT4_ADD_ACTIVITY_BROADCAST, IOCTL_DOT4_WAIT_ACTIVITY_BROADCAST


DOT4_DC_CREATE_DATA

The DOT4_DC_CREATE_DATA structure specifies information that Dot4 driver uses to create an IEEE 1284.4 primary socket.

typedef struct _DOT4_DC_CREATE_DATA
{
  unsigned char  bPsid;
  CHAR  pServiceName[MAX_SERVICE_LENGTH + 1];
  unsigned char  bType;
  ULONG  ulBufferSize;
  USHORT  usMaxHtoPPacketSize;
  USHORT  usMaxPtoHPacketSize;
  unsigned char bHsid;
} DOT4_DC_CREATE_DATA, *PDOT4_DC_CREATE_DATA;

Members

bPsid
Specifies a well-known IEEE 1284.4 secondary socket ID (that is, a socket ID that a device vendor documents). If a Dot4 service name is specified, the socket ID is not used. A socket ID of zero is associated with an IEEE 1284.4 Transaction Channel, and is invalid if the socket ID is used.
pServiceName
Specifies an array that contains the service name (a NULL-terminated ANSI string) of a secondary socket. If a service name is specified, the socket ID is not used.
bType
Specifies the type of socket, which is either STREAM_TYPE_CHANNEL or PACKET_TYPE_CHANNEL.
ulBufferSize
Specifies the size, in bytes, of the socket's internal read buffer. The Dot4 driver sets the internal buffer size to the larger of ulBufferSize and the peripheral-to-host packet size that the Dot4 driver sets for the socket. The ulBufferSize member should be set to zero for a write-only socket.
usMaxHtoPPacketSize
Specifies the maximum size, in bytes, of a packet that can be sent from the host to the peripheral. The Dot4 driver negotiates the largest packet size that the peripheral supports, bounded by the maximum requested by the client.
usMaxPtoHPacketSize
Specifies the maximum size, in bytes, of a packet that can be sent from the peripheral to the host. The Dot4 driver negotiates the largest packet size that the peripheral supports, bounded by the maximum requested by the client.
bHsid
Specifies the IEEE 1284.4 primary socket ID that a client uses to open a Dot4 channel. The Dot4 driver sets this value.

Headers

Declared in d4iface.h. Include d4iface.h

Comments

A client uses a DOT4_DC_CREATE_DATA structure to input and output information with an IOCTL_DOT4_CREATE_SOCKET request. A client sets all the members except the bHsid member, and the Dot4 driver sets bHsid.

See Also

IOCTL_DOT4_CREATE_SOCKET, IOCTL_DOT4_OPEN_CHANNEL, IOCTL_DOT4_WAIT_FOR_CHANNEL


DOT4_DC_DESTROY_DATA

A DOT4_DC_DESTROY_DATA structure is used with an IOCTL_DOT4_DESTROY_SOCKET request.

typedef struct _DOT4_DC_DESTROY_DATA
{
    unsigned char  bHsid;
} DOT4_DC_DESTROY_DATA, *PDOT4_DC_DESTROY_DATA;

Members

bHsid
Specifies the socket ID of the IEEE 1284.4 primary socket to delete.

Headers

Declared in d4iface.h. Include d4iface.h

See Also

IOCTL_DOT4_CREATE_SOCKET, IOCTL_DOT4_DESTROY_SOCKET


DOT4_DC_OPEN_DATA

The DOT4_DC_OPEN_DATA structure specifies information Dot4 driver uses to open a Dot4 channel.

typedef struct _DOT4_DC_OPEN_DATA {
  unsigned char  bHsid;
  unsigned char  fAddActivity;
  CHANNEL_HANDLE  hChannelHandle;
} DOT4_DC_OPEN_DATA, *PDOT4_DC_OPEN_DATA;

Members

bHsid
Specifies an IEEE 1284.4 primary socket ID, which is obtained by using an IOCTL_DOT4_CREATE_SOCKET request.
fAddActivity
Specifies whether to add activity broadcast on a channel immediately after the channel is opened. To add activity broadcasting, fAddActivity is set to TRUE (nonzero), otherwise fAddActivity is set to FALSE (zero).
hChannelHandle
Specifies a handle to a Dot4 channel. The Dot4 driver sets this value.

Headers

Declared in d4iface.h. Include d4iface.h

Comment

The client uses a DOT4_DC_OPEN_DATA structure to input and output information with an IOCTL_DOT4_OPEN_CHANNEL request. A client sets hHsid and fAddActivity, and the Dot4 driver sets hChannelHandle.

See Also

IOCTL_DOT4_CREATE_SOCKET, IOCTL_DOT4_OPEN_CHANNEL, IOCTL_DOT4_WAIT_FOR_CHANNEL


DOT4_DRIVER_CMD

A DOT4_DRIVER_CMD structure is used with all Dot4 function I/O control codes to specify command information.

typedef struct _DOT4_DRIVER_CMD
{
  CHANNEL_HANDLE  hChannelHandle;
  ULONG  ulSize;
  ULONG  ulOffset;
  ULONG  ulTimeout;
} DOT4_DRIVER_CMD, *PDOT4_DRIVER_CMD;

Members

hChannelHandle
Specifies a Dot4 channel handle that is obtained by using an IOCTL_DOT4_OPEN_CHANNEL request.
ulSize
Specifies the size of a client-allocated buffer that is used with read and write requests.
ulOffset
Specifies the initial byte offset in the client-allocated buffer that is used with read and write requests.
ulTimeout
Specifies a timeout value, in milliseconds, for the request.

Headers

Declared in d4iface.h. Include d4iface.h

Comments

The setting of the members is request-specific.


DOT4_WMI_XFER_INFO

A DOT4_WMI_XFER_INFO structure is used to output information about data flow over Dot4 channels.

typedef struct _DOT4_WMI_XFER_INFO
{
  ULONG  ulStreamBytesWritten;
  ULONG  ulStreamBytesRead;
  ULONG  ulPacketBytesWritten;
  ULONG  ulPacketBytesRead;
} DOT4_WMI_XFER_INFO, *PDOT4_WMI_XFER_INFO;

Members

ulStreamBytesWritten
Specifies the total number of data bytes written over stream-type channels. The value returned does not include the IEEE 1284.4 packet headers.
ulStreamBytesRead
Specifies the total number of data bytes read over stream-type channels. The value returned does not include the IEEE 1284.4 packet headers.
ulPacketBytesWritten
Specifies the total number of data bytes written over packet-type channels. The value returned does not include the IEEE 1284.4 packet headers.
ulPacketBytesRead
Specifies the total number of bytes read over packet-type channels. The value returned does not include the IEEE 1284.4 packet headers.

Headers

Declared in d4iface.h. Include d4iface.h


Overview of Modem INF Files

Modem information (INF) files are required to install modem class devices. For more information about modem class devices, see Modem Class Devices . These INF files are similar to INF files of other types of devices. This document describes how to use standard Microsoft® Windows® INF file structures as well as the unique features of modem INF files.

The Microsoft Windows Driver Development Kit (DDK) includes sample and tools to aid in creating and testing Modem INF files. For more information about the sample files, see Sample Modem INF Files

This section includes the following topics. These topics describe the information necessary to create a modem INF file:

Modem Class Devices

Function of Modem INF Files

Modem INF File Structure

Creating a Modem INF File

Testing a Modem INF File

To understand this guide, you should be familiar with the material described in INF File Sections and Directives. Basic knowledge of modem features and terminology is also assumed.


Modem Class Devices

Unimodem is a set of software components that implements the base modem class device behavior on Windows systems. Therefore, a modem class device is any device that is supported by Unimodem on Windows. There are many types of modems that are not supported by Unimodem. This documentation always uses the term "modem" to indicate a modem class device that is supported by Unimodem unless specified otherwise.

Unimodem handles application requests such as dialing and answering that are passed down from TAPI. It also passes result codes to TAPI that are sent up from the modem. The sequence of commands required by a given modem to complete a TAPI request and the result codes returned by the modem are defined in the Windows registry. Unimodem accesses the registry as needed to get the command strings, result codes, and other information such as modem capabilities.

The command strings sent to the modem are generally modem AT commands. The AT command set was an early standard that was followed for modem compatibility and there are many standard AT commands. Manufacturers implement new features by creating additional AT commands, many of which are manufacturer-specific or modem-specific.

Many modems are external and are attached to standard serial COM ports or other types of communications adapters; other modems are internal but emulate standard serial UARTs (such as the 8250 and 16550).

Unimodem provides many services that make any differences between modems transparent to applications. These services include:

  • Initializing port speed and protocols
  • Managing calls, for example, dial and answer
  • Managing the stage dialing process
  • Interpreting modem responses
  • Providing fax modem and voice modem features
  • Providing ISDN and GSM support for devices that support the AT command set

Sample Call Scenario

The following simplified call scenario illustrates some Unimodem functions:

  1. An application calls TAPI to open access to a modem. Unimodem establishes an interface to the correct modem device and then sends a series of modem AT commands specified in the registry to initialize the modem.
  2. The AT commands are echoed back by the modem, along with an OK response code. Unimodem discards the echoed commands and correctly interprets the OK responses.

    Note This is the dynamic initialization stage Unimodem sent the strings to configure the modem to settings requested by the user or application. The command string is built dynamically, based on registry entries.

  3. Unimodem sends the AT commands to activate dial-tone detection, to take the modem off-hook, and to dial the phone number provided by the TAPI lineMakeCall function.
  4. Based on the response codes, Unimodem recognizes that this is a 28800 call with error compression but no data compression. The call is now in progress. Data is being passed between the modem and the application.
  5. Unimodem detects carrier loss. The call was disconnected by the other computer. Unimodem directs the modem to hang up and indicates to the application that the call has been disconnected.

This scenario would be different if Unimodem had been called by TAPI to disconnect.

The implementation of Unimodem varies between Windows versions; however, the fundamental concept of Unimodem remains constant.


Function of Modem INF Files

Modem INF files provide configuration information used to install modems. The modem configuration information includes:

  • Data entries that are added to the Windows registry during installation.
  • Text strings that are displayed in a modem user interface.
  • A modem ID that uniquely identifies the modem.
  • Optional support for modem device drivers.

In many cases, data entries in the INF file are initial defaults that can be changed by the user. In some cases, multiple versions of the entries are provided to support modem installation differences across multiple Windows versions or to support differences between modems in a multiple modem INF file.

The INF file includes friendly strings that are displayed in the modem user interfaces, such as the Modem Control Panel. These strings provide descriptive names for the modem and the manufacturer name.

Modem IDs identify the modem device for Plug and Play. Some legacy modems do not have Plug and Play device IDs. Unimodem provides the ability to detect Unimodem IDs for these legacy modems.

At one time, there was no need to provide device drivers for modems because nearly all modems supported a common command set and modem functionality was implemented in the device. Competition among manufacturers and advances in technology have led to architectures where feature implementation is split between the modem device and a Windows device driver. Modem INF files provide the ability to install device drivers for these types of devices, called controllerless and softmodem devices.


Modem INF File Structure

This topic summarizes the general structure and content of Windows INF file sections as they are commonly used in modem INF files. For a complete reference to the general structure and content of Windows INF files, see INF File Sections and Directives.

An INF file is comprised of sections, directives and entries. Each section of an INF file begins with its unique name enclosed in square brackets. The rest of the section is made up of one or more directives or entries.

Sections can be arranged in any order in an INF file. However, the sample modem INF files that are included in the DDK are organized as follows:

  • Beginning—sections that define modem IDs
  • Middle—sections that support modem-specific commands and voice modem commands
  • Near the end—modem responses
  • End—Strings section

The following example includes three modem INF sections:

[Manufacturer]
%Mfg% = Microsoft

[Microsoft]
%Modem1% = Modem1, PCMCIA\RIPICAB-RC144ACL-3BD0
%Modem2% = Modem2, UNIMODEME9DF4BA4

[Strings]
; This section lists strings that are used by the Modems control panel
; and the Install New Modem wizard. For example,
; Modem1 will appear as "Microsoft 144 PCMCIA Data Fax Modem".
ClassName = "Modem"
Mfg = "Microsoft"
Modem1 = "Microsoft 144 PCMCIA Data Fax Modem"
Modem2 = "Microsoft 288 External Data Fax Modem"

The INF sections that are commonly used in a modem INF file are listed in the following table:

INF file section | Description | Comments
Version section | Contains the standard header for all INF files. | Every INF file must have a header section named [Version].
Manufacturer section | Lists the names of manufacturers and the names of the corresponding Models sections. | Every INF file must have a [Manufacturer] section.
Models sections | Identifies the DDInstall sections for each device installed by the INF file, and specifies the modem IDs for each modem. | Every INF file must have a Models section.
Install sections | Identify other sections in the INF file that describe the resource requirements of a device and add entries to the registry, copy files, and so on. | Every INF file must have at least one DDInstall section. Generally one for each modem model the INF file is capable of installing.
Add Registry sections | Add subkeys or value names to the registry, while optionally setting their values. | Contains most of the information in a modem INF file.
ControlFlags section | Provides limited control over UI displays and events during device installation. | Can be used to prevent the names of modems from being displayed in a list of modems the user may choose to install.
CopyFiles sections | Names the files copied from the source disks to the destination directories during device installation. | Required if your modem requires driver files to be installed in addition to the INF file.
Rename Files sections | Names the files to be renamed when they are copied from the source disks to the destination directories during device installation; displays those new file names on the destination directories. | Could be used if your modem requires driver files to be installed in addition to the INF file.
DelFiles sections | Names the files to be deleted from destination directories during device installation. | Could be used in the uninstall section of your INF file.
Delete Registry sections | Deletes subkeys or value names from the registry. | Could be used in the uninstall part of your INF file.
Disk Names section | Identifies and names the disks that are the source of files that are copied to the hard disk during installation. Also names the files that are on each of the installation disks. | Required to install the INF from disks.
Strings section | Defines one or more names that represent a string of displayable characters. | Every INF file has a [Strings] section.


Sample Modem INF Files

You can find installed Windows operating system distribution is a good source for example modem INF files. Look in the Windows operating system distribution for INF files that support similar modems (mdm*.inf).

The following sample INF files are included in the DDK:

smpdata.inf
Installs a data modem.
smpvoice.inf
Installs a voice modem.
smpserwv.inf
Installs the serial wave driver required by most voice modems.
For more information about the serial wave driver, see Adding Voice Support.
smpwrap.inf
Installs the wave wrapper required by some voice modems. For more information about the wave wrapper, see Adding Voice Support.


Creating a Modem INF File

Modem INF files are generally created by copying existing modem INF file and modifying it to meet new device requirements. This process is described in the following topics:

Determine Modem ID

Create the Data Modem Entries

Add Optional Fax Support

Add Optional Voice Support

Add Optional WDM Driver Support


Determining Modem ID

All modems, including Plug and Play modems and non-Plug and Play (or legacy) modems, are identified by at least one modem ID string. This string can be either a Plug and Play device ID or a Unimodem ID. All modems have a Unimodem ID which is generated by interrogating the modem with standard modem AT commands.

A modem INF file requires one or more modem ID strings for each modem it supports. Any given modem can produce multiple modem ID strings, and different types of modems use different ID string formats.

To help insure error free modem installations

  1. Identify the modem type (for example, legacy, PCI, or USB).
  2. Obtain the appropriate modem ID strings.
  3. Choose a strategy for using the modem IDs.
  4. When upgrading, make appropriate changes to the modem ID.

For more information on modem IDs, see Modem ID Strings .

Note Unimodem IDs are not supported in Windows Me or in Windows XP and later versions of the operating system.


Tools for Creating a Modem INF File

You can use a simple text editor to perform most of the work required to create a modem INF file. After you have reviewed the information contained in Modem INF File Entries and in this document, you will be able to create a modem INF file using a text editor.

In some cases, there is a procedure to follow that provides the data required to configure a modem feature. For these cases, the procedure is documented with the description of the INF file entries for that feature.

The Microsoft Windows Driver Development Kit (DDK) includes an application called ProcCalc. This application is packaged in the ProCalc.exe executable.. ProCalc provides a simple user interface that you can use to create common modem INF registry entries. Using ProCalc to create these entries simplifies the creation of modem INF files.

You can select an INF entry type from the ProCalc drop-down menu to access data entry fields such as checkboxes, edit boxes, and so on, that are specific to the particular INF file entry. More complex entries, such as the Properties entry, have secondary-level data fields.

For more information about using ProCalc to create data modem INF entries, see Creating and Modifying Data Modem INF Files . For more information about using ProCalc to create voice modem INF entries, see Adding Optional Voice Support.


Creating and Modifying Data Modem INF Files

This topic summarizes the activities involved in creating and modifying a modem INF file. For detailed information about creating data modem INF files, see Creating a Data Modem INF File .

When creating a modem INF file:
  • Keep the file small to support Windows 95/98/Me operating systems, and to improve performance.
  • Create modem INF entries using ProCalc whenever possible.
  • Double-check your files for common errors.

A sample modem INF file is presented in the topic, Sample Modem INF Files. You can adapt this file to your application by modifying the following INF file sections:

  • Version
  • Manufacturer
  • Models
  • DDInstall
  • Add Registry (including All, MfgAddReg, and <ModemN>.AddReg Sections)
  • Strings

For additional information on configuring a subset the data modem features supported by Windows, see Creating a Data Modem INF File . This subset includes the most commonly supported features and a few solutions to configuration problems. For complete details of the data modem features that are supported, see Data Modem INF File Entries.


Adding Optional FAX Support

Registry settings control Microsoft fax modem drivers and the T.30 protocol engine. These settings are defined the first time the fax software is run, using a combination of the following techniques:

  • Querying the modem for capabilities.
  • Querying the modem to get an ID, and using this ID to look up an internal table.
  • Reading the Uimodem INF section for the modem. If an entry is present in the INF section, it overrides information obtained by either of the two methods listed above.

The T.30 protocol engine is not a part of Unimodem. Part of T.30 is implemented in the modem and part is implemented in the fax application software that generates the fax image data. Windows 2000 and later versions of the operating system include a basic T.30 Fax application. The details of this application are outside the scope of this documentation.

Note Most of the modems tested by Microsoft do not require INF file fax entries. The INF file fax entries are required to fix known incompatibilities or to support adaptive answering.

For more information about fax modem support, see Adding Fax Support. For complete details of the fax modem features that are supported, see Fax Modem INF File Entries.


Adding Optional Voice Support

To provide optional voice support, you must add entries to the add-registry-sections of the modem INF file. A voice modem may support any or all of these features provided by Unimodem:

  • Caller ID
  • Distinctive ringing (not supported on Windows 2000 and later versions of the operating system)
  • Speaker phone capability
  • Wave playback and record to and from the phone line
  • Wave playback and record to and from the handset
  • Answering voice calls
  • Voice call dial-out
  • Generation of DTMF digits in voice mode
  • Switching between voice and data answering
  • Full duplex

Windows NT 4.0 does not include voice modem support. Voice support was added to Windows 95/98/Me beginning with the Windows 95 OSR2 release. The voice support included in Windows 2000 and later versions of the operating system is similar to that provided by Windows 95/98/Me.

On Windows 95/98/Me systems, a separate INF file is required for wave device configuration. The wave device entries are integrated into the modem INF file on Windows 2000 and later versions of the operating system.

For more information about voice modem support, see Adding Voice Support. For complete details of the voice modem features that are supported, see Voice Modem INF File Entries.


Adding Optional WDM Modem Support

WDM is the standard device driver model for Windows 2000 and later versions, as well as the preferred device driver model for Windows Me. All Windows 95 device drivers are based on the VxD device driver model. Windows 98/Me supports the WDM and the VxD-based driver models.

Note Windows Me can use INF files used on the NT-based version of the operating system to install WDM drivers. To install a Vxd-based driver on Windows Me, the folder containing the Vxd INF files must be different than the folder containing the INF file used on the NT-based version of the operating system. If the INF files are in the same folder, Windows Me will use the INF file used on the NT-based version of the operating system.

WDM modem drivers written for Windows 98/Me can be made source code compatible, and in some cases binary code compatible, with Windows 2000 and later versions of the operating system. WDM and the previous VxD device driver model are not directly compatible. Therefore, there are two additional drivers (ccport.sys and wdmmdmld.vxd) required for modem support on Windows 98/Me. These are unique in design and do not follow the architecture of either a VxD driver or a WDM driver because they are used to span the two driver models.

For more information about WDM modem drivers, see Adding WDM Modem Support.


Testing a Modem INF File

This topic provides an overview of modem INF file installation testing issues.

Microsoft provides modem testing and support resources through Windows Hardware Quality Labs (WHQL).

The test tools generally used include:

  • Terminal Applications, for example HyperTerminal
  • The INF File Syntax Checker (ChkINF)
  • Modem Compatibility Test (MCT)

Test the INF file using the Microsoft-supplied tools. Generally, this means testing the INF file by running ChkINF; using the INF file to install the modem on the desired Windows platform; and testing the modem installation using MCT and a Terminal Application.

Have Microsoft test and certify the INF file. To do so, send the INF file, the modem, and any driver files required by the modems to the Microsoft Windows Hardware Quality Labs (WHQL). Certification is an optional but highly recommended testing step.

For more information about modem INF file installation and testing, see Modem Installation Testing .


Modem ID Strings

All modems, including Plug and Play modems and non-Plug and Play (legacy) modems, are identified by modem ID strings. These strings can be either Plug and Play device IDs or Unimodem IDs. All modems have a Unimodem ID (legacy ID) that is generated by interrogating the modem using standard modem AT commands. For more information about device IDs, see INF File Sections and Directives.

A modem INF file requires one or more modem ID strings for each modem it supports. Most modems can produce multiple modem ID strings, and different types of modems use different ID string formats.

The following topics describe how to work with modem ID strings:

Determining the Modem Type

Obtaining Modem ID Strings

Using Modem ID Strings

Changing the Modem ID When Upgrading a Modem

Note Windows Me and Windows XP and later versions of the operating system do not support Unimodem IDs.


Determining the Modem Type

The modem type determines which type of modem ID strings must be included in the INF file. The following table lists modem types and the modem ID strings typically associated with those types.

Modem type | Modem ID strings
Non–Plug and Play | Unimodem ID string only.
Plug and Play SERENUM (modem that is available in both external and internal ISA forms) | SERENUM Plug and Play hardware ID string and Unimodem ID string.
Plug and Play ISA modem | ISAPNP hardware ID string, ISAPNP compatible ID string, and Unimodem ID string.
Plug and Play PCMCIA modem | PCMCIA Plug and Play hardware ID string and Unimodem ID string.
Parallel-port modem | LPTENUM string and Unimodem ID string. Note Windows 2000 and later versions do not provide native support for parallel port modems. Windows Me also does not provide such support.
PCI bus modem | PCI Plug and Play device ID and Unimodem ID.
USB bus modem | USB Plug and Play device ID and Unimodem ID.
BIOS motherboard modem | BIOS enumeration and Unimodem ID string.
Custom | Some ISA card modems can present either a SERENUM or ISAPNP ID in addition to a Unimodem ID. The type of ID presented depends on a jumper setting. Some PCMCIA modems can contain an LPT enumeration ID string in addition to PCMCIA and Unimodem IDs.

The following table provides examples of modem ID string types.

Modem ID string type | Example
Unimodem ID | UNIMODEMAC9AF91E
SERENUM Plug and Play Hardware ID | SERENUM\PPI1907
ISAPNP Hardware ID | ISAPNP\SSC0001_DEV0002 (long form) or *SSC0002 (short form)
ISAPNP-Compatible ID | *PNPB003 (short form)
PCMCIA Plug and Play modem ID | PCMCIA\RIPICAB-RC144ACL-3BD0
USB Plug and Play device ID | USB\VID_04C1&PID_0082
PCI Plug and Play device ID | PCI\VEN_11C1&DEV_0448&SUBSYS_20001668&REV_01
Parallel-port modem ID | LPTENUM\MICROCOMTRAVELPORTE_1FF4
Platform modem ID | BIOS\*PNPC003 or *PNPC003 (The BIOS\*XXXXXXX format is not supported in Windows 2000 and later versions of the operating system.)


Obtaining Modem ID Strings

This section describes how to obtain modem ID strings from modems; it does not include information about how to obtain Plug and Play prefixes or device assignments. For more information about prefixes and device assignments, see INF File Sections and Directives .

There are three types of modem ID strings:

  • Plug and Play hardware ID strings identify a particular modem model and are written into the registry by the Plug and Play system during hardware enumeration.
  • Plug and Play compatible ID strings, if available, are also written into the registry by Plug and Play during hardware enumeration.
  • Unimodem ID strings are obtained by interrogating a modem with AT commands and can be obtained from both Plug and Play modems and non-Plug and Play modems. Unimodem IDs are obtained during Autodetection (or detection) of the modem.

The following topics describe tools and procedures used to obtain modem ID strings for use in INF files:

Obtaining Unimodem ID Strings

Obtaining SERENUM Plug and Play Hardware IDs

Obtaining ISAPNP Hardware IDs

Obtaining Compatible IDs

Obtaining PCMCIA Plug and Play Hardware_IDs


Obtaining Unimodem ID Strings

You can obtain a Unimodem ID from any type of modem by using either autodetection from the Modem Control Panel or the ProCalc tool.

To generate a Unimodem ID using autodetection

  1. Click the modem icon in Control Panel to install a new modem.
  2. During installation, autodetection creates a file named ModemDet.txt in the Windows directory.
  3. Copy the modem ID string from ModemDet.txt.
  4. Paste the modem ID string into the appropriate location in the modem INF file.

The following is a sample ModemDet.txt file:

 Tuesday, June 06, 2000 4:48:16 PM
 A modem was found on COM1:
ATI0<cr> = <cr><lf>28800
ATI0<cr> = <cr><lf>28800
ATI1<cr> = <cr><lf>255
ATI1<cr> = <cr><lf>
ATI2<cr> = <cr><lf>ERROR
ATI2<cr> = <cr><lf>ERROR
ATI3<cr> = <cr><lf>V1.000-V34_DS
ATI3<cr> = <cr><lf>-_DS
ATI4<cr> = <cr><lf>a007840284C6002F
ATI4<cr> = <cr><lf>a007840284C6002F
ATI5<cr> = <cr><lf>022
ATI5<cr> = <cr><lf>
ATI6<cr> = <cr><lf>RC288DPi Rev 0
ATI6<cr> = <cr><lf>RC288DPiRev
ATI7<cr> = <cr><lf>000
ATI7<cr> = <cr><lf>
ATI8<cr> = <cr><lf>ERROR
ATI8<cr> = <cr><lf>ERROR
ATI9<cr> = <cr><lf>ERROR
ATI9<cr> = <cr><lf>ERROR
ATI10<cr> = <cr><lf>ERROR
ATI10<cr> = <cr><lf>ERROR
AT%V<cr> = <cr><lf>ERROR
AT%V<cr> = <cr><lf>ERROR
Modem ID = UNIMODEMCC96FDC7.

You can also use Procalc, which is included with the Microsoft Windows DDK, to generate the Unimodem ID string.

To generate a Unimodem ID using Procalc

  1. In order for ProCalc to calculate a modem ID, your modem must be connected to the computer.
  2. Copy the modem ID string from Procalc.
  3. Paste the modem ID string into the appropriate location in the modem INF file.

For more information about placing Unimodem IDs in the modem INF file, see Creating a Data Modem INF File .

An example of a Unimodem ID string is UNIMODEMCC96FDC7.


Obtaining SERENUM Plug and Play Hardware IDs

Both an ISA-card modem and an external serial Plug and Play modem can have a SERENUM Plug and Play Hardware ID. Some ISA card modems have only SERENUM Plug and Play Hardware IDs. Other ISA card modems have both SERENUM and ISAPNP IDs.

To determine which ID string to use for ISA card modems

  1. Install the modem hardware and start the computer. Microsoft Windows displays a dialog box that indicates an unknown Plug and Play device has been installed.
  2. Install the modem using the Windows default modem device. This creates the ID string in the Windows registry.
  3. Use the Registry Editor to locate the device ID; then locate the hardware ID field of the correct modem class device.
  4. Copy the device ID from the Registry display and paste it into the INF file.

For more information about placing IDs in the modem INF file, see Creating a Data Modem INF File .

In Microsoft Windows 98/Me, you can locate the hardware ID by using the Registry Editor to open HKEY_LOCAL_MACHINE\ENUM\SERENUM. In the following example, a SERENUM ID (SERENUM\ELS0218) entry is visible in the Registry Editor's right window:

Windows 98/Me Serinum ID Registry Entries

In Windows 2000 and later versions of the operating system, you can locate the hardware ID by opening HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\ENUM\SERENUM with the Registry Editor. In the following example, a SERENUM ID (SERENUM\USR0051) entry is visible in the Registry Editor's right window:

Windows 2000 and Later Serinum ID Registry Entries


Obtaining ISAPNP Hardware IDs

A Plug and Play modem that uses an ISA bus has an ISAPNP ID. Unlike a SERENUM ID, an ISAPNP ID cannot be assigned to an RS232 external modem.

To determine which ID string to use for ISA Plug and Play modems

  1. Install the modem hardware and start the computer. Microsoft Windows displays a dialog box that indicates an unknown Plug and Play device has been installed.
  2. Install the modem using the Windows default modem device. This creates the ID string in the Windows registry.
  3. Use the Registry Editor to locate the device ID, and then locate the hardware ID field of the correct modem class device. Both the short and the long form ID can be listed in the registry. Use the short form of the ISAPNP ID in the modem INF file.
  4. Copy the device ID from the Registry Editor display and paste it into the INF file.

For more information about placing IDs in the modem INF file, see Creating a Data Modem INF File.

In Microsoft Windows 98/Me, you can locate the hardware ID by using the Registry Editor to open the path HKEY_LOCAL_MACHINE\ENUM\ISAPNP. Both the short form ID (*XYZ2171) and the long form ID (ISAPNP\XYZ2171) are shown in the following example:

Windows 98/Me Hardware ID Registry Entries

In Windows 2000 and later versions of the operating system, you can locate the hardware ID by using the Registry Editor to open the path HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\ENUM\ISAPNP. Both the short form ID (*USR2070) and the long form ID (ISAPNP\USR2070) are shown in the following example:

Windows 2000 and Later Hardware ID Registry Entries


Obtaining Compatible IDs

To locate a compatible ID, follow the procedure defined in Obtaining ISAPNP Hardware IDs. A compatible ID is listed in the compatible ID field instead of the hardware ID field.


Obtaining PCMCIA Plug and Play Hardware IDs

This topic describes how to obtain a PCMCIA hardware ID.

To obtain a hardware ID from a PCMCIA modem

  1. Insert the modem into a PCMCIA slot in your computer.
  2. Install the modem using the Windows default modem device. This creates the ID string in the Windows registry.
  3. Use the Registry Editor to read the PCMCIA hardware ID from the registry.

    In Windows 98/Me, you can locate the hardware ID string by using the Registry Editor to open the path HKEY_LOCAL_MACHINE\ENUM\PCMCIA.

    In Windows 2000 and later versions of the operating system, you can locate the hardware ID string by using the Registry Editor to open the path HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\ENUM\PCMCIA.

  4. The hardware ID that was read from the modem card appears immediately below the PCMCIA key. The process of locating the hardware ID is similar to that described in Obtaining ISAPNP Hardware IDs.

The following is an example of a PCMCIA modem ID string:

PCMCIA\ATI__-14.4_MODEM/FAX_-D904

Some earlier versions of multifunction PCMCIA cards do not fully implement the PC Card multifunction standard. For information about creating child device INF files and child device IDs for these multifunction PCMCIA cards, see INF File Sections and Directives .


Using Modem ID Strings

Your modem INF file should include every type of modem ID string that can be obtained from your modem and is supported by the Windows operating systems you are targeting. By doing so, you can eliminate duplicate enumerations and increase the probability of a successful installation.

For example, if your modem is a Plug and Play ISA modem, you should include the following IDs:

  • ISAPNP hardware ID.
  • ISAPNP–compatible ID string (if supported by your modem).
  • Unimodem ID string (if supported by the target Windows version).

When specifying modem IDs in your INF file:

  • Use the correct format for your modem ID strings.
  • Include compatible IDs when appropriate. For more information on compatible IDs, see Using Compatible IDs.


Support for Modem ID Types

The following table describes how Unimodem ID and Plug and Play device ID support different modem ID types across versions of the Windows operating system:

Windows version | Supported ID types
Windows 98 | Compatible with the Plug and Play in Windows 95 OSR2. Supports additional buses, including 1394 and USB. All support detection of Unimodem IDs.
Windows Me | Supports Plug and Play.
Windows NT 4.0 | Requires a Unimodem ID to install most modems. Windows NT version 4.0 supports a limited implementation of Plug and Play, including a Plug and Play Enabler that supports ISA Plug and Play devices. Requires user to manually select resources after a Plug and Play modem has been detected.
Windows 2000 and later versions | Supports Plug and Play and detection of Unimodem IDs. Note Later versions do not support Unimodem IDs.


Using Compatible IDs

A Plug and Play modem hardware ID string identifies a specific Plug and Play modem. Use a compatible ID to identify modems that can be installed with identical drivers and INF file entries.

The compatible ID enables a modem to be installed with a compatible INF file in the absence of an INF file that matches the modem's hardware ID. For example, you represent an OEM selling a modem to other vendors and you want to provide a generic INF file that will work for the modem regardless of the vendor.

For general information about compatible IDs or obtaining a compatible ID assignment for a device, see INF File Sections and Directives. For information about obtaining compatible IDs for modems, see Obtaining Modem ID Strings .


Changing the Modem ID When Upgrading a Modem

To ensure that the operating system can recognize an upgraded modem

  1. Change the device IDs.
  2. Create a new corresponding INF file.
  3. Create new drivers when needed.


Avoiding ID Problems When Upgrading a Modem

WHQL standards require that upgradable modems have hardware ID strings that can be updated. Some legacy modems do not support updating the hardware ID string.

The following problems might occur during a modem upgrade if the modem's hardware ID cannot be updated:

  • The upgraded modem might not be automatically detected as a new device. Remove the old modem installation (for example, registry entries, unused files) during your upgrade process to avoid this problem.
  • There can be a duplication of hardware IDs between the old INF file and the new INF file. In this case, Windows will check the INF file date and use the INF file with the latest date. This does not apply to Windows Me, or to Windows 2000 and later versions of the operating system.

If the user upgrades to (or reinstalls) a version of Windows that supports Plug and Play, then the upgraded modem will be detected and automatically reinstalled at system startup. If the hardware ID was not changed after a modem firmware upgrade, the operating system will use the old (and possibly incorrect) INF file to install the old drivers.


Modem Upgrade Example

To upgrade a modem that operates at 33.6 Kbps (V.34), the modem manufacturer distributes a software or firmware upgrade that supports 56 Kbps (V.90) operation.

The modem's INF file must be upgraded to enable these new features. For example, new support commands that enable 56 Kbps and new responses, such as CONNECT messages, must be added to the modem INF file.

The upgrade requires the assignment of a new hardware ID to the modem. If the INF file has been updated but the modem hardware ID has not been changed, Windows will not detect the firmware change and will not install the updated INF file.

The upgrade process of the modem manufacturer performs the following actions:

  1. Writes a new INF file to the system. The hardware ID in the INF file must match the new modem hardware ID.
  2. Downloads the new modem firmware into the modem.
  3. Modifies the hardware ID, using either the PC-based upgrade software or the modem firmware.
  4. Cleans up any unused files or remaining registry entries from a previous installation.


Upgrades That Require a New Hardware ID

Windows cannot recognize an upgraded modem as such unless the modem's hardware ID has been updated. If there is any need for the operating system to distinguish between non-upgraded and upgraded versions of a modem, these versions of the modem must have different hardware IDs.

You should update a modem's hardware ID if:

  • A modem is sold by various PC manufacturers, each of which requires its own manufacturer and model name strings.
  • The display name of the modem has changed. For example, a new PC OEM is distributing the modem.
  • The command strings have changed. For example, there are new initialization strings that support an upgrade.
  • The response strings are new or have changed. For example, V.90 connect responses have been added.
  • A hardware change requires a new driver. For example, a different digital signal process has been introduced.
  • An upgrade includes new features supported by the operating system.
  • An upgrade includes new features supported by applications and these applications use the hardware ID to verify that the device supports these features.


Upgrades That Do Not Require a New Hardware ID

You do not have to update a modem's hardware ID if you are:

  • Making updates to the modem firmware that do not affect the content of the modem INF file or the modem drivers.
  • Adding features that are supported by applications but not directly supported by the operating system. In this case, distinct hardware IDs can still help applications identify modems that support these features.
  • Distributing a modem through multiple PC manufacturers, where the end user is expecting the same name for the modem from all the manufacturers (for example, branding a bundled modem).


Creating a Data Modem INF File

This section provides information about creating INF files for data modems. A basic understanding of Microsoft® Windows® support for INF files and modems is required to understand this information. For an overview of modem INF files, see Overview of Modem INF Files.

This section also provides modem INF file information for a subset of the data modem features supported by Windows. This subset includes the most commonly supported features and a few solutions configuration problems. For detailed information about the features supported, see Data Modem INF File Entries.

This section includes the following topics:

INF File Compatibility

INF File Size and Modem Response Codes

Using ProCalc to Create Data Modem INF Entries

Avoiding Errors When Writing a Modem INF File

Modifying the Sample Modem INF File

Adding Additional Modem Capabilities


INF File Compatibility

Data modem INF files are generally backward compatible across Microsoft Windows operating systems. Commands that are not supported by a particular version are transparent to the operating system; for example, newer INF registry entries, GUIDs, and most voice registry entries found in a modem INF file are transparent to earlier Windows operating systems that do not use these entries. In some cases, however, you will need to create a separate modem INF file version. For example, in the case of INF files that are shipped with the operating system.

For more information about INF file sections and directives, see INF File Sections and Directives.


INF File Size and Modem Response Codes

The size of an INF file is limited by the available disk space for computers running Microsoft Windows 2000 and later versions of the operating system. In Windows 95/98/Me, the INF file size is limited to 64 KB.

In addition, modem INF files that are specific to Windows 2000 or later versions of the operating system can benefit from improved connection times by reducing the number of registry entries called Responses entries. These entries are used by Unimodem to interpret modem responses. For more information about Responses entries, see Using ProCalc to Create Data Modem INF Entries.

There are several strategies you can use to minimize the size of your INF files:

  • Minimize extraneous INF comments.
  • Eliminate Responses entries for responses that your modem is unlikely to make. For example, if your modem supports 56 Kbps but the firmware supports up to 60 Kbps, you can eliminate the Responses entries for 60 Kbps because the modem will rarely report responses that high.
  • Reduce the connection Responses entries to just the verbose set of "CONNECT" and the DCE rate. Remove extra Responses entries for error correction or data compression messages.

Note Modify the Init entry so that the modem returns only the "CONNECT " and DCE rate messages. For more information about the Init entry, see Modem INF File Entries.


Using ProCalc to Create Data Modem INF Entries

The DDK includes an application called ProCalc. ProCalc is packaged in the executable ProCalc.exe. ProCalc provides a simple user interface you can use to create common modem INF registry entries. ProCalc is a particularly useful tool because the bulk of the work involved in creating a modem INF file is creating modem INF registry entries

You can select an INF file entry type from the ProCalc drop-down menu to access such data entry fields as check boxes, edit boxes, and so on, that are specific to the particular INF entry. More complex entries, such as the Properties entry, have secondary level data fields.

For detailed information about the bit fields and data fields required for all modem INF registry entries, see Modem INF File Entries. The ProCalc status bar (at the bottom of the ProCalc window) displays a description of the currently selected data entry field. Use the status bar descriptions to help you find the detailed description in Modem INF File Entries.

After you create an entry with ProCalc, you can copy and paste the entry into your INF file. You can also copy and paste entries from your INF file into ProCalc. ProCalc displays the property values for these entries.

ProCalc creates modem INF file entries in the add-registry-sections of INF files in the following form:

HKR,, [value-entry-name], [flags], [value]

These entries appear in add-registry-sections of INF files. For more information about the add-registry-section HKR entries, see Device Installation Design Guide. For more information on modem INF add-registry-sections, see Modifying the add-registry-sections.

ProCalc creates modem INF entries (selected from the list in the UI) with correct value-entry-names and their corresponding flags and values for the following:

  • Data profile
  • Voice profile
  • Response state
  • Locking the port speed (DCB)
  • Inactivity scale
  • Speaker phone specifications
  • XformID (Win9x)
  • XformID (NT)
  • UnimodemID

The voice profile, speaker phone specifications and XformID items are associated with voice modem support. For more information, see Adding Voice Support.

The following topics provide information about creating modem INF entries that are not associated with voice modem support:

Data Profile

Response State

Locking the Port Speed (DCB)

Inactivity Scale

UnimodemID


Data Profile

You create a modem INF Properties entry using the Data Profile option. The Properties entry contains bitmaps for the following:

  • Supported dial options
  • Speaker volume
  • Speaker mode
  • Modem options

The Properties entry also contains a maximum value for each of the following:

  • Call setup fail timeout (seconds)
  • Inactivity timeout (seconds)
  • DTE rate (bits/second)
  • DCE rate (bits/second)

Tabs in the ProCalc UI are used to access the data entry screens for each item in the preceding list.

An example of a Properties entry follows:

HKR,, Properties, 1, 80,01,00,00, ff,00,00,00, ff,00,00,00, 07,00,00,00, 0f,00,00,00, f7,03,00,00, 00,c2,01,00, 40,38,00,00

Note Make sure that the Properties entry contains the correct maximum DTE and DCE speed.

You can generally determine the maximum DTE speed by examining the ModemDet.txt file that Windows generates when a new modem is installed. You can also determine maximum DTE and DCE by consulting your specific manufacturer's documentation, or by trial and error using any communications program. Use the communications program to transmit initialization strings to the modem at various DTE speeds to find the maximum DTE value.


Response State

Modems can respond to commands in various ways; therefore, it is necessary to describe the responses a modem will send in response to various events. These responses are specified by Responses INF file entries. Unimodem uses the binary state structure in the Responses entries to interpret modem responses.

The Responses entry contains the following fields:

  • Response text
  • Response state
  • Negotiated options
  • Negotiated DCE rate
  • Negotiated DTE rate

Click the appropriate ProCalc tabbed property sheet to enter the corresponding data for each of the preceding items.

An example of a Responses entry follows:

HKR, Responses, "<cr><lf>CONNECT<cr><lf>",  1, 02, 00, 00,00,00,00, 00,00,00,00


Locking the Port Speed (DCB)

A DCB entry locks the modem's port speed to a specific default. It also controls XON/XOFF software flow-control settings.

The following example of a DCB entry is from the sample INF file, MdmHayes.inf:

; DCB's - DWORDS and words are byte reversed.
; ByteSize (Number of bits/byte, 4-8).
; Parity (0-4=None,Odd,Even,Mark,Space). StopBits (0,1,2 = 1, 1.5, 2)
;       |DCBLength  |BaudRate  |Bit Mask
HKR,, DCB, 1, 1C,00,00,00, 80,25,00,00, 15,20,00,00, <cont. next line>

;|Rsvd |XonLim|XofLim|  |  |  |Xon|Xof|Err|Eof|Evt
 00,00, 0a,00, 0a,00, 08, 00, 00, 11, 13, 00, 00, 00  <end DCB line>

The comment lines in the preceding example describe all the fields in the DCB line. Typically, the only field that is modified is the baud rate. The other fields are used in advanced applications, which are beyond scope of this document.


Inactivity Scale

The InactivityScale value is multiplied by the InactivityTimeout value in the Properties entry to obtain the inactivity timeout in seconds.

The ProCalc inactivity scale feature provides predefined values of 1, 10, and 60 seconds for InactivityScale. If required, other values can be typed into the provided edit box and ProCalc will translate them.

An example of an InactivityScale entry follows:

HKR,, InactivityScale, 1, 0A,00,00,00


UnimodemID

Unlike the other fields created using ProCalc, the Unimodem ID is not a registry entry. Your modem must be connected to the computer for ProCalc to calculate a Unimodem ID.

Unimodem IDs are required for legacy modems that do not use Plug and Play device IDs. However, Unimodem IDs are not required for Plug and Play modems supported by Microsoft Windows 2000 and are not supported in later NT-based operating systems.

The following is an example of a Unimodem ID:

UNIMODEMCC96FDC7

Unimodem IDs are included in the Models section of the INF file. For more information, see Modifying the Models Section and Modem ID Strings.


Avoiding Errors When Writing a Modem INF File

Use the following guidelines to avoid common errors in creating and editing a modem INF file:

  • Do not use the following characters in modem names: angle brackets (< >), semicolon (:), quotation marks ("), slash mark (/), backslash (\), and pipe (|) in the Strings section because these characters generally cause errors during installation or testing.
  • Do not use a period (.) at the end of a modem name in the Strings section; however, the modem manufacturer's name can end in a period.
  • Use the correct command or initialization strings specific to each modem supported by your INF file. Do not incorrectly apply an AT command or an initialization string to all modems by using a common add-registry-section. For example, a specific modem might require AT&F1 instead of AT&F, or a modem might use \Tn for the inactivity timer instead of S30.
  • Make sure you use double percent signs (%%) or double quotation marks ("") in INF commands that contain % or " symbols. For example, use %%C1, not %C1, in a modem INF entry to enable compression, and use ""H3, not "H3. For more information about INF file syntax, see INF File Sections and Directives.


Modifying the Sample Modem INF File

The DDK includes a sample data modem file called SmpData.inf. You can create your modem INF file by modifying the SmpData.inf file.

The SmpData.inf file has the following characteristics:

  • Installs modems made by a single manufacturer.
  • Installs either a PCMCIA Data Fax or an External Data Fax Modem.
  • Uses multiple add-registry-sections, which can be easily modified to support additional modems.

Your modem INF file, however, can install any number of modems from multiple manufacturers and can contain any number of add-registry-sections.

Section | Description
[Version] | Identifies which operating system the INF file supports, the class of device being installed, and the providing organization. Standard header section for all INF files. Value of %CompanyName% is defined in the Strings section.
[Manufacturer] and [Microsoft] | Identifies the modem manufacturer, the friendly (displayable) modem name, the DDInstall sections for each device installed by the INF file, and the modem IDs for each modem. [Modem1] and [Modem2] are the DDInstall sections. Text values of %Modem1% and %Modem2% defined in the Strings section.
[Modem1] | Lists the sections of the INF file that define registry entries for the Microsoft 144 PCMCIA Data Fax Modem. Modem1 is defined in the Microsoft section.
[Modem2] | Lists the sections of the INF file that define registry entries for the Microsoft 288 External Data Fax Modem. Modem2 is defined in the Microsoft section.
[Modem3] | Lists the sections of the INF file that define registry entries for the Microsoft 56k USB Modem. Modem3 is defined in the Microsoft section and uses the standard Microsoft USB modem driver.
[All] | Contains the registry entries that are common to all the modem models that can be installed by this INF file.
[EXTERNAL] | Contains the registry entries common to all external modems, such as the example Microsoft 288 External Data Fax Modem.
[PCMCIA] | Contains the registry entries common to all PCMCIA modems, such as the example Microsoft 144 PCMCIA Data Fax Modem.
[Modem1.AddReg] | Contains registry entries for only the Microsoft 144 PCMCIA Data Fax Modem.
[Modem2.AddReg] | Contains registry entries for only the Microsoft 288 External Data Fax Modem.
[Modem3.NT] | Contains registry entries for the Microsoft 56k USB Modem.
[MfgAddReg] | Contains the registry entries common to all modem models made by the manufacturer named in this INF file.
[Strings] | Defines strings that are displayed by the Modem's Control Panel and the Install New Modem wizard. Grouping all the displayable strings in one section enables easy translation of the INF file for use in international markets.

The following topics provide detailed instructions for modifying the SmpData.inf file:

Modifying the Version Section

Modifying the Manufacturer Section

Modifying the Models Section

Using the ExcludeFromSelect Directive in the ControlFlags Section

Modifying the DDInstall Sections

Modifying the add-registry-sections

Modifying the Strings Section


Modifying the Version Section

In most cases, it should not be necessary to modify the Version section of SmpData.inf.

The Version section of a modem INF file has the following modem-specific characteristics:

Class

The Version section should contain a Class entry so that someone reading the file can easily determine that the file installs a modem.

The Class entry for modems is always Modem.

ClassGuid

All devices are assigned their own class type ID so the class installer can identify them.

The Version section of the modem INF must contain a ClassGuid entry:

Modem Class | ClassGuid
Modem | {4D36E96D-E325-11CE-BFC1-08002BE10318}

Signature

The Signature entry in modem INF files is generally set to $Chicago$.

For more information about the version section, see INF Version Section.

Example Version Section

The following is an example of a Version section for an INF file that installs a modem:

[Version]
Signature="$CHICAGO$"
Class=Modem
ClassGUID={4D36E96D-E325-11CE-BFC1-08002BE10318}
Provider=%CompanyName%
DriverVer=06/24/1999,5.00.2071.1

Note that the Provider entry indicates who developed the INF file — not who developed the component that is installed by the INF file.


Modifying the Manufacturer Section

The Manufacturer section identifies the manufacturer of one or more modems that can be installed with the INF file. It also defines the Models section name for the installation of that manufacturer's modems.

The manufacturers listed in this section of the INF file appear in the Install New Modem Wizard's list of manufacturers.

For more information about the manufacturer section, see INF Manufacturer Section.

Example Manufacturer Section

An example adaptation of the modem INF file Manufacturer section follows:

[Manufacturer]
%Mfg% = Models

In the preceding example, the manufacturer is specified by %Mfg% (%Microsoft% in SmpData.inf) in the Strings section and the Models section is called "Models" ("Microsoft" in SmpData.inf).


Modifying the Models Section

Each per-manufacturer Models section identifies at least one modem, references the DDInstall section for that modem, and specifies one or more identifiers for that modem.

The Models section does not have to be named "Models". In SmpData.inf the Models section is named "Microsoft". For information about how to name the Models section, see Modifying the Manufacturer Section.

The Modem Control Panel and Install New Modem wizard use the model names listed in this section. They will appear in the install new modem wizard's list of models.

The most important modification in the Models section is changing the modem ID strings to match the modem IDs of the modems that the INF will install. For more information about how to obtain modem ID strings, see Modem ID Strings.

For more information about the models section, see INF Models Section.

Example Models Section

The following example shows the association of two IDs with a single modem and supports two modems:

[Models]
%Modem1% = Modem1, *ZIP1234
%Modem1% = Modem1, UNIMODEMAC9AF91E
%Modem2% = Modem2, UNIMODEME9DF4BA4

In the preceding example, the two modem names are defined by %Modem1% and %Modem2%, as referenced in the Strings section.

Modem1 is the DDInstall section name of the first modem. Modem2 is the DDInstall section name of the second modem. For more information about the DDInstall section, see Modifying the add-registry-sections.


Using the ExcludeFromSelect Directive in the ControlFlags Section

The ControlFlags section of a modem INF file can have one or more ExcludeFromSelect entries. Each ExcludeFromSelect entry specifies a device that is excluded from the Select Device dialog box, as well as from all other user interfaces during modem installation.

The following guidelines apply to the use of the ExcludeFromSelect directive in modem INF files:

  • Do not use ExcludeFromSelect if your modem is not Plug and Play and the user needs to select the modem from the Select Device dialog box.
  • If your modem is a child device on a multifunction card, use ExcludeFromSelect to exclude it from the Select Device dialog so that the user selects the ID of the multifunction card itself. Using ExcludeFromSelect with a multifunction card does not exclude the daughter modem device from the Device Manager dialog boxes. Users might employ the Device Manager dialog boxes to change a device driver for a daughter device.
  • Do not use ExcludeFromSelect if your Plug and Play modem is not on a multifunction card, you are creating an INF for an installation disk to be shipped with the modem, and your modem ID string is a Hardware ID.

Note If you examine the modem INF files in the \Windows\Inf directory, ExcludeFromSelect is used with hardware modem IDs. The Plug and Play system detects the modem and installs it without displaying the Select Device dialog box. This does not apply to creating an INF file for an installation disk.

For more information on the ControlFlags section, see INF ControlFlags Section.


Modifying the DDInstall Sections

Each per-model DDInstall section contains one or more directives that reference additional named sections in the INF file. The most commonly specified INF directives are CopyFiles and AddReg. The sections referenced by these directives contain instructions for installing driver files and writing any device-specific and/or driver-specific information into the registry.

For Windows 2000 and later versions of the operating system, DDInstall sections in modem INF files must include an ".NT" decoration. If this decoration is not included, the modem class installer will not install the modem.

For more information on DDInstall sections, see INF DDInstall Section.

This section includes the following topics:

Modifying the AddReg Directive in the DDInstall Section

Using CopyFiles in the DDInstall Section


Modifying the AddReg Directive in the DDInstall Section

The AddReg directive lets you specify multiple add-registry-sections. When different registry values are specified in more than one add-registry-section, the value in the section listed furthest to the right in the AddReg line is the value installed in the registry. For more information on the AddReg directive, see INF AddReg Directive.

The Models section from SmpData.inf references the Modem1 DDInstall section in the following sample.

[Microsoft]
%Modem1% = Modem1, PCMCIA\RIPICAB-RC144ACL-3BD0
%Modem1% = Modem1, UNIMODEM16A163D5
 .
 .
 .
[Modem1]
AddReg=All, MfgAddReg, Modem1.AddReg

In the preceding example, the registry entries for Modem1 specified by the sections All, MfgAddReg, and Modem1.AddReg, are created in the order these sections are listed, from left to right in the AddReg line.

All
Creates registry entries required for all modem models installed by the INF file; that is, the registry entries common to all modems, regardless of the manufacturer, described by the INF file.
MfgAddReg
Creates registry entries common to all modems from the manufacturer named in the Manufacturer section.
Modem1.AddReg
Creates registry entries specific to one particular modem.

In this example, the All section is processed first, followed by the MfgAddReg section next, and then the Modem1.AddReg section. Suppose that the All section does not contain a command for hardware flow control, the MfgAddReg section contains the hardware flow control command &K3, and the Modem1.AddReg section contains the hardware flow control command \Q3.

When the installer processes the add-registry-sections, the installer:

  • Does not write a hardware flow-control entry from the All section.
  • Writes a key value of &K3 from the MfgAddReg section.
  • Overwrites the &K3 value with the \Q3 value from Modem1.AddReg section.


Using CopyFiles in the DDInstall Section

The following example demonstrates the use of CopyFiles in the DDInstall section:

[Modem1]
AddReg=All, MfgAddReg, Modem1.AddReg

[Modem2]
AddReg=All, MfgAddReg, Modem2.AddReg
CopyFiles=@sample.vxd

An INF file for Windows 95/98/Me that installs modems that require a VCOMM port driver other than serial.vxd (for example, sample.vxd) must have a CopyFiles line, as defined in the Modem2 section. This specifies the port driver name, preceded by the at (@) sign. This port driver file is copied to the \Windows\System directory (the default destination directory for INF files). In the Control Panel, click the Modems icon to verify these settings.

An INF file which installs modems that require a WDM modem driver on Windows Me and Windows 2000 and later versions of the operating system, must include a CopyFiles line to install that driver.

For more information on the CopyFiles directive, see INF CopyFiles Directive.


Modifying the add-registry-sections

This document does not describe how to configure every possible modem feature. You must determine the capabilities of your modem and adapt the content of these sample INF sections to your modem. To determine which items to add, delete, or modify in these add-registry-sections, see Modem INF File Entries.

The SmpData.inf file includes the following add-registry-sections:

All
Defines registry entries common to all modems installed by the INF file.
MfgAddReg
Defines registry entries common to all modems made by Microsoft that can be installed by the INF file.
<ModemN>.AddReg
Defines registry entries specific to each modem.

The relationships between these add-registry-sections are established by INF entries similar those in the following example, which specifies the Manufacturer section, Models section, and add-registry-section for Modem1:

[Manufacturer]
%Microsoft% = Microsoft

[Microsoft]
%Modem1% = Modem1, PCMCIA\RIPICAB-RC144ACL-3BD0
%Modem1% = Modem1, UNIMODEM16A163D5

[Modem1]
AddReg=All, MfgAddReg, Modem1.AddReg

The preceding example shows the structure for Modem1. Similar structures are required for additional modems.

SmpData.inf only has one manufacturer: Microsoft. Additional manufacturers can be added in the Manufacturers section. Also "Microsoft" can be changed to "Models" or something appropriate to your application. For more information, see Modifying the Manufacturer Section and Modifying the Models Section.

The following sections contain additional information about modifying the modem INF add-registry-sections to support data modem features. The features documented here are the features most likely to require changes or that otherwise require special attention. For information about how to configure additional features, see Modem INF File Entries.


Modifying Common add-registry-section Entries

The most commonly modified data modem INF entries include:

  • Properties
  • Responses
  • DCB
  • InactivityScale

Use ProCalc to create these entries, as described in Using ProCalc to Create Data Modem INF Entries .


Enable Modem Answering

For some modems, the NVRAM setting of the S0 register defaults to values greater than zero after startup. Setting the S0 register to zero will enable modem answering.

Add the following entries to your INF file MFGAddReg section to force S0 to zero:

HKR, Monitor, 1,, "ATS0=0<cr>"

HKR, Monitor, 2,, "None"


InactivityTimeout/InactivityScale Settings Example

Use ProCalc to specify the Inactivity Timeout value in the Properties entry and the InactivityScale entry, as described in Using ProCalc to Create Data Modem INF Entries .

An inactivity timeout is the period of data inactivity after which a modem hangs up. If a modem does not have this feature, set the Inactivity Timeout value in the Properties entry to zero.

The InactivityScale value is multiplied by the Inactivity Timeout value in the Properties entry to obtain the inactivity timeout in seconds.

The following is an example of the InactivityScale entry:

HKR,, InactivityScale, 1, 3c,00,00,00

If the InactivityScale entry is omitted from an INF file, a default value of 10 seconds is assigned.


Using Padded Responses and Stripped Responses

Padded Responses entries are modem INF Responses entries that have leading and trailing <cr><lf> sequences — for example:

HKR, Responses, "<cr><lf>CONNECT 300/V42<cr><lf>",   1, 02, 02, 2C,01,00,00, 00,00,00,00

In contrast, the following example shows a stripped response that lacks a leading or trailing <cr><lf> and that requires a separate <cr> and <lf> response:

HKR, Responses, "CONNECT 300/V42",   1, 02, 02, 2C,01,00,00, 00,00,00,00
HKR, Responses, "<cr>",    1, 01, 00, 00,00,00,00, 00,00,00,00
HKR, Responses, "<lf>",    1, 01, 00, 00,00,00,00, 00,00,00,00

Use padded responses rather than stripped responses in modem INF Responses entries. Unimodem can process padded responses faster and more reliably than stripped responses. Also, the additional entries required for stripped responses make the INF file larger.

Use ProCalc to create Responses entries, as described in Using ProCalc to Create Data Modem INF Entries.


Setting the Maximum DCE Speed for a 56 Kbps Modem

Use ProCalc to set the maximum DCE speed in the modem INF Properties entry. For more information about ProCalc and the Properties entry, see Using ProCalc to Create Data Modem INF Entries.

Set the maximum DCE rate to 56 Kbps if the modem responses available in firmware go to 56 Kbps. If your modem firmware contains responses up to 60 Kbps and the modem can be expected to connect at speeds that high, set the maximum DCE rate to 60 Kbps.


Configuring the Modem Volume Level

Use ProCalc to set the modem volume levels in the modem INF Properties entry. For more information about ProCalc and the Properties entry, see Using ProCalc to Create Data Modem INF Entries.

Some modems support only one volume level. Such modems might respond to the usual ATL1-3 command but do not adjust the volume level. When configuring the Properties entry in the INF file for such a modem, do not indicate that the modem supports any of the volume levels. Doing so would cause the Volume Control Slider in the Modem Control Panel to be disabled. In this case, you should enable only the appropriate bits in the speaker mode data, and you should not enable any bits in the speaker volume data.


Supporting Bongtone Settings

Use ProCalc to set the wait-for-bongtone feature in the dial options field of the Properties entry. Fore more information about ProCalc and the Properties entry, see Using ProCalc to Create Data Modem INF Entries.

DialSettings Bongtone on many modems requires some alternate AT-style character rather than the dollar sign ($). If your modem supports bongtone but does not use the $ character, you cannot specify bongtone in your modem INF file and you should disable bongtone in the Properties entry.


Supporting Cellular Features

When you set the cellular flag in the Properties entry, cellular features are enabled.

To set the cellular flag

  1. Select Data Profile from the ProCalc menu.
  2. Click the Modem Options tab.
  3. Check the Cellular check box.

For more information about enabling cellular features, see Using ProCalc to Create Data Modem INF Entries.


Supporting V.23 Override

Use ProCalc to modify the Properties entry and enable V.23 Override.

To activate V.23 Override

  1. Select Data Profile from the list.
  2. Click the Modem Options tab and set V.23 Override to ON.
  3. Include the appropriate registry entries in the appropriate add-registry-section of your INF file. The content of each entry depends on the chip set used. For example:
    HKR, Settings, Modulation_CCITT_V23,, "+MS=3"

    or

    HKR, Settings, Modulation_CCITT_V23,, "B0 +MS=3,0,1200,1200"

    or

    HKR, Settings, Modulation_CCITT_V23,, "S27=16"
  4. Include the appropriate Responses entries, for example:
    HKR,Responses,"<cr><lf>CONNECT 75/1200<cr><lf>" ,1,2,0, B0,04,0,0, 0,0,0,0
HKR,Responses,"<cr><lf>CONNECT 1200/75<cr><lf>" ,1,2,0, B0,04,0,0, 0,0,0,0
HKR,Responses,"<cr><lf>CONNECT 75/1200/NONE<cr><lf>"    ,1,2,0, B0,04,0,0, 0,0,0,0
HKR,Responses,"<cr><lf>CONNECT 1200/75/NONE<cr><lf>"    ,1,2,0, B0,04,0,0, 0,0,0,0
HKR, Responses, "CONNECT 1200TX/75RX",   1, 02, 00, B0,04,00,00, 00,00,00,00
HKR, Responses, "CONNECT 1200RX/75TX",   1, 02, 00, B0,04,00,00, 00,00,00,00
  5. Make sure your change to the Properties entryis correct by checking the settings in the Control Panel. Click the Modems icon and click the Properties button. Then click the Connection tab and click Advanced. The V.23(Minitel) option should be displayed in the Modulation type drop-down dialog box.


Supporting Blacklisting and Delayed

Blacklisting and Delayed are response characteristics. Blacklisting occurs when the modem does not dial because there have been too many unsuccessful attempts. Delayed occurs when the modem does not dial, until some time has elapsed, because there have been too many recent unsuccessful attempts.

Two codes in the bResponseState field of a Responses entry correspond to Delayed and Blacklisting. For more information on the bResponseState settings in the Responses entries, see Data Modem INF File Entries. For more information about creating Responses entries, see Using ProCalc to Create Data Modem INF Entries.


Disabling Dial Suffix

The dial suffix should cause the modem to return to command state after dialing. The DialSuffix entry is a string of characters (generally ";") that will be appended to any dial string before the terminator character string (generally "<cr>"). The following example shows how to set the DialSuffix value:

HKR, Settings, DialSuffix,, ";"

Use a null DialSuffix if a dial suffix is not applicable. Use a null suffix for devices that inadvertently listen for dial tone at each dial command. The following example shows how to set the null DialSuffix:

HKR, Settings, DialSuffix,, ""

During staged dialing, several initialization strings are issued as Unimodem dial-out proceeds (for example, a number is dialed to get an outside line then another is dialed to connect, and so forth). Unimodem uses the dial suffix during its staged dialing process.

Some modem firmware contains a bug that causes a dial suffix to break all or part of any initialization that follows the dial suffix. Modem firmware that contains a dial suffix bug of this type should be fixed, even though it is possible to disable dial suffix as a workaround within an INF file.

To disable dial suffix, do not include the DialSuffix entry in the INF file. If the dial suffix is disabled, the modem might not be able to dial long numbers or calling card numbers.

For detailed information about the DialSuffix entry, see Settings, DialSuffix.

Some voice modems support staged dialing in data mode but not in voice mode. Set the flag in the VoiceProfile entry if the dial string must always end with DialSuffix in voice mode. For more information about the VoiceProfile entry, see Adding Voice Support.


Modifying the Strings Section

The Strings section is generally the last section in the INF file. This section lists strings that are displayed by the Modem Control Panel.

The Strings section contains one line for each string including:

  • One line per manufacturer
  • One line per modem
  • One line for provider

For more information about the Strings section, see INF Strings Section.

Example Strings Section

Suppose you are working for XYZ Corporation and want to adapt the SmpData.inf sample for your ISA Plug and Play 56 Kbps modem. Change the Strings section to include the friendly (displayable) names of the XYZ Corporation and the XYZ modem models as follows:

[Manufacturer]
%Mfg% = Models

[Strings]
Mfg = "XYZ"
CompanyName = "Your Name"
Modem1 = "XYZ 56K Data Fax Modem"

Note If you change the manufacturer symbol name (for example, Microsoft to Mfg), you must update the Manufacturer section of the INF file.


Adding Additional Modem Capabilities

Windows 2000 and later versions of the operating system support certain capabilities of IDSN and GSM modems. The following topics provide a summary of this support:

Supporting ISDN-TA Modems

Supporting GSM Modems

For detailed information about ISDN and GSM modem support, see ISDN-TA Modem INF File Entries and GSM Modem INF File Entries.


Supporting ISDN-TA Modems

Previous Next

Supporting ISDN–TA Modems

There are two common types of Integrated Services Digital Network – Terminal Adapters (ISDN–TAs):

  1. Parallel bus (ISA, PCI, and so forth) devices that are driven by NDIS WAN drivers.
  2. Serial port devices that are supported by Unimodem.

This topic addresses how to support the second type, serial port ISDN adapters, referred to herein as either ISDN-TAs or ISDN modems.

ISDN modems share common features:

  • ISDN Basic Rate Interface (2B + D)
  • Serial AT command language, with proprietary ISDN extensions

This topic describes registry entries that support both the static and dynamic configuration of ISDN modems in Windows 2000 and later versions of the operating system. Specifically, this topic describes the proprietary and standard (V.254) commands that configure and control ISDN modems under Unimodem. For more information on the static and dynamic configuration of ISDN modems, see Static Configuration and Dynamic Configuration.

ISDN-related entries are preceded by HKR, ISDN\, which places them in the appropriate registry subfolder. There is no entry for ISDN modems equivalent to the Properties entry for PSTN (analog) modems. ISDN modem properties are set through separate INF file entries. The presence of the ISDN-related entries in the INF file activates the associated portions of the user interface and identifies the protocols that the ISDN modem supports for TAPI.


Static Configuration

During static configuration, Unimodem sets the D channel protocol (switch type) and associated information (EAZ, MSN, Directory Number and SPID), using information defined in the modem INF file add-registry-sections and entered by the user through the modem configuration interface.

The information is stored in the modem's NVRAM by issuing AT commands. The AT commands issued are specified in the ISDN\NvSave registry entry. Because the information is stored in the modem's NVRAM, there is no need for the information to be reissued to the modem prior to each call. The information is reissued to the modem at startup and following any user-applied change to the switch type or B channel identification information (directory number, MSN, SPID, EAZ).

A 10-second delay following the issuing of the NvSave entry allows the ISDN network to be reset (that is, it allows the D channel to reset and enable change of D channel protocol).

For more information about registry commands and the configuration information that is issued by Unimodem during static configuration, see the following entries in ISDN-TA Modem INF File Entries:

ISDN\SwitchType

ISDN\DirectoryNo

ISDN\SetSpid

ISDN\SetMSN

ISDN\SetEAZ

ISDN, CompatibilityFlags

ISDN\NvSave

You should omit entries of type ISDN\SwitchType if your ISDN modem meets one of the following requirements:

  • Does not require static configuration of the SPID/MSN/EAZ/Directory Number.
  • D channel configuration information is provided through an alternate configuration interface (for example, a vendor supplied or third-party interface).


Dynamic Configuration

Dynamic configuration is performed on the basis of per-call configuration requirements. Unimodem sends AT commands to the ISDN modem during dynamic configuration to select the protocol and authentication method. For more information on commands issued during dynamic configuration, see the Protocol\ISDN entry in ISDN-TA Modem INF File Entries.


Supporting MSN Entry

You can support MSN entry by including a single registry entry containing AT<cr> as follows:

HKR, ISDN\SwitchType, SWITCH_DSS1,,"AT<cr>"

If your ISDN MODEM defaults to DSS1 and does not support any AT commands for switch selection, omit the ISDN\SwitchType entries from the INF file. The user interface for MSN entry is no longer available if the ISDN\SwitchType entries are omitted.


Assigning MSN/DN/EAZ/SPID to the Analog Port

There are two keys provided for setting MSN/DN/EAZ/SPID:

HKR, ISDN\SetSpid, 1,,     "AT SPID1=%s<cr>"
HKR, ISDN\SetSpid, 2,,     "AT SPID2=%s<cr>"

The first key should always be used for your device's data port; the second can be used for the voice port on your ISDN modem.

For more information, see ISDN\SetSpid.


Disabling SwitchType Entries

If you are writing an INF file for CAPI cards and want to configure SwitchType, MSN, DN, EAZ or SPID using your CAPI subsystem, do not include any of the registry entries of type ISDN\SwitchType. The corresponding Unimodem B channel protocol selection entries will still function.

If you bundle setup applications with your devices that support automatic SPID detection and verification, do not include any of the entries of type ISDN\SwitchType. The affected Unimodem D channel protocol selection keys will still function.


Disabling the Second MSN

To prevent the option for entering the second MSN from being active in the Unimodem TSP and user interface, include the following entry in the INF file:

HKR, ISDN\SetMSN, 1 ,, "AT MSN1=%s<cr>"

and omit the following entry:

HKR, ISDN\SetMSN, 2 ,, "AT MSN2=%s<cr>"

For more information, see ISDN\SetMSN.


ISDN Features Not Supported by Unimodem

Unimodem does not support the following B Channel protocols:

  • Bonding mode 0
  • Bonding mode 1
  • Cfos channel bundling
  • TurboPPP
  • AimUX
  • Manufacturer specific MLP X.75 bundling

There is no way for a user to specify the second number required to make multi-link PPP calls. For this reason, Unimodem supports only ISDN modems with the capability to set up multi-link calls by dialing a single hunt group number. Devices that require ATD########## <joining character> ########### are not supported.

You might have to write a WDM modem driver to add support for these features or for other features unique to your device. For more information about supporting WDM, see Adding WDM Modem Support.


Setting the D Channel Command Sequence

The Unimodem default sequence for D channel configuration commands is the switch type followed by the directory number and SPID. Some ISDN devices, however, require D channel configuration commands to be issued in the reverse order:

  1. Directory number and SPID
  2. Switch type

To reverse the order in which these commands are issued, include the following INF entry in the add-registry-section that contains your ISDN registry entries:

HKR,ISDN, CompatibilityFlags, 1,00,00,00,01

For more information, see ISDN, CompatibilityFlags.


Supporting GSM Modems

Unimodem supports the dynamic configuration of GSM modems. The registry entries discussed in this section support connection-by-connection selection of the radio link protocols and end-to-end protocols.

GSM-specific entries are preceded by Protocol\GSM\, which places them in the appropriate registry subfolder.

A limited range of additional entries are provided to support high-speed, circuit-switched data (HSCSD), as documented in ETSI 07.07, in order to support the configuration of faster data connections using emerging GSM technology.

There is no entry for GSM modems equivalent to the Properties entry for PSTN (analog) modems. GSM modem properties are set through separate INF file entries. The presence of the GSM-related entries in the INF file activates the associated portions of the user interface and identifies the protocols that the GSM modem supports for TAPI.

GSM supports a large number of logical protocols. The three major protocol classes include:

Analog
Connects to a remote PSTN voice band modem via another modem in a modem pool in the GSM network provider facilities, for example V.90, V.34, and V.32bis.
V.110 and V.120
Connects to a remote ISDN DCE via V.110 or V.120 provided by the GSM network provider.
HDLC PPP
Connects to the Internet via the GSM network provider.

Windows 2000 and later versions of the operating system support the dynamic selection of GSM logical protocols by users and communications applications such as RAS. The inclusion of one or more Protocol\GSM registry entries enables the corresponding protocols to be selected in the user interface and indicated via TAPI and Unimodem. When a protocol is selected in the user interface, Unimodem issues the corresponding AT commands prior to originating a call. These commands are issued as part of a sequence of commands that set response format and presentation, carrier detect on, and so forth.

For more information about GSM modem support, see GSM Modem INF File Entries.


Adding Fax Support

This section describes how to add fax entries to a modem INF file. Fax entries are required to avoid known incompatibility problems and to support adaptive answering.

Most modem INF file entries install registry settings. The fax registry settings control the behavior of the Microsoft fax modem drivers and T.30 protocol engine. These settings are defined the first time the fax software is run, using a combination of the following techniques:

  • Querying the modem for capabilities
  • Querying the modem to get an ID, and then using this ID to look up an internal table
  • Reading the INF file for the modem. If an entry is present in the INF file, it overrides information obtained by either of the other methods.

Note The T.30 protocol engine is not a part of Unimodem. Part of T.30 is implemented in the modem and part is implemented in the fax application software that generates the fax image data. Microsoft® Windows® Me and Windows 2000 and later versions of the operating system include a basic T.30 fax application.

Note Most of the modems tested by Microsoft do not need any INF file fax entries.

This section includes the following topics:

Known Fax Problems

Personal Fax with Adaptive Answering

For more detailed information about modem fax entries, see Fax Modem INF File Entries .


Known Fax Problems

This topic documents known incompatibility problems. Solutions for many of these problems involve specifying one or more fax entries (for example, ResetCommand). For more information about these INF file entries, see Fax Modem INF File Entries.

The most common initialization problem occurs when the fax uses the wrong command for software flow control. For more information about configuring the fax modem reset and setup commands, see ResetCommand and SetupCommand.

Some modems offer, but do not properly support, Class 1 drivers. This can be fixed by using the FixModemClass INF entry.

Windows supports additional INF entries to maintain backward compatibility with the legacy fax modems. These entries provide workarounds for some problems not found in newer modems. For more information about these INF file entries, see Fax Modem INF File Entries.


Personal Fax with Adaptive Answering

Windows Me and Windows 2000 and later versions of the operating system provide adaptive answering for fax modems. The adaptive answering algorithm distinguishes between voice and fax or data and fax. There is no way to distinguish between voice and data.

With adaptive answering enabled, the fax modem and computer determine the proper way to handle the call. For example, the fax modem receives fax calls which are handled by fax software or data calls handled by RAS.

The adaptive answer fax software included in Windows Me and Windows 2000 and later versions of the operating system work with class 1 fax modems. It is possible to support adaptive answer in class 2 with a third-party application. However, there is no interface provided to integrate such an application with RAS.

The following topics provide information about the adaptive answering algorithm and fax entries for modem INF files:

Adaptive Answering Algorithm

Modem INF File Fax Entries


Adaptive Answering Algorithm

The adaptive answering algorithm is implemented in the Microsoft T.30 protocol engine. This algorithm provides auto-detection of data and fax calls using a fax modem.

The adaptive answering algorithm proceeds as follows

  1. A call to the modem is initiated.
  2. The Modem sends "RING" strings to the system.
  3. TAPI gets "RING" events and passes them to T.30.
  4. T.30 starts answering the incoming call.
  5. If there is a Fax\Class1\AdaptiveAnswer registry key, the following procedure will be executed:
    1. T.30 configures the DTE-DCE baud rate and flow control using either the registry settings (installed from the INF file) or the default settings (19200 Kbps, software flow control).
    2. T.30 sends the ResetCommand string to the modem.
    3. T.30 sends the SetupCommand string to the modem.
    4. T.30 sends a group of Fax\Class1\AdaptiveAnswer\AnswerCommand strings to a modem.
    5. T.30 receives the ModemResponseFaxDetect string if the modem detected a fax call, or, T.30 receives the ModemResponseDataDetect string if the modem detected a data call.
  6. At this point in the process, the incoming call type has been detected. Some modems will change the modem-to-host baud rate while other modems need to be instructed explicitly to go online. The following INF entries are defined to control this behavior:
    • SerialSpeedFaxDetect requires the system to switch to the specified DTE-DCE speed immediately after an incoming call has been identified as a fax call.
    • SerialSpeedDataDetect requires the system to switch to the specified DTE-DCE speed immediately after an incoming call has been identified as a data call.
    • HostCommandFaxDetectOptional requires the system to connect to a remote modem after an incoming call has been identified as a fax call.
    • HostCommandDataDetect requires the system to connect to a remote modem after an incoming call has been identified as a data call.
  7. T.30 expects a connect string after the local fax-modem is connected to a remote fax-modem. Connect strings for data or fax calls are defined by:
    • ModemResponseFaxConnect, indicating a fax connection.
    • ModemResponseDataConnect, indicating a data connection.
  8. For a fax call, T.30 continues handling this call. For a data call, T.30 hands the call off to the appropriately TAPI registered DATA application (for example, RAS).


Modem INF File Fax Entries

The hardware flow control, host-to-modem transmission rate including reliable transfers above 19200 bps, and adaptive answer algorithm are modem specific. INF file entries are required to configure these parameters.

For incoming data calls, configure the fax-modem to use hardware flow control and a DTE-DCE speed of at least 57600 bps to achieve the best RAS performance. You should also set up the fax-modem with the appropriate RAS settings for the proper modulation, data compression and error control. Use the AdaptiveAnswer fax entries to configure adaptive answer support.

The fax settings are organized in a hierarchy of registry keys that represent the modem state. The modem class (Class1, Class2)and the current modem operation (Send, Receive, AdaptiveAnswer) define a fax modem state. These registry keys are configurable through INF entries. Fax INF entries with the same name are allowed at different locations of the fax registry hierarchy.

For a detailed description of the fax INF entries, see Fax Modem INF File Entries. A sample representation of the fax registry key hierarchy follows:

Fax

ExitCommand

PreAnswerCommand

PreDialCommand

ResetCommand

SetupCommand

EnableV17Recv

EnableV17Send

FixModemClass

FixSerialSpeed

HighestSendSpeed

LowestSendSpeed

HardwareFlowControl

SerialSpeedInit

Class1

SetupCommand

HardwareFlowControl

Send

ResetCommand

SetupCommand

Receive

SerialSpeedInit

AdaptiveAnswer

AnswerCommand 1

AnswerCommand 2

AnswerCommand 3

ModemResponseFaxDetect

ModemResponseDataDetect

SerialSpeedFaxDetect

SerialSpeedDataDetect

HostCommandFaxDetect

HostCommandDataDetect

ModemResponseFaxConnect

ModemResponseDataConnect

The Microsoft T.30 protocol engine (T.30) accesses the Registry value at the hierarchy location corresponding to the current fax modem state. If these entries are not defined at a given location of the hierarchy, T.30 will search upward in the hierarchy until it reaches the Fax root. If the entry is not defined at any level in the hierarchy, T.30 will try to auto-detect the value or use the default value.

For example, if a fax-modem is receiving an adaptive answer in Class1, T.30 will use the SetupCommand defined in one of the following entries (from first to last):

  1. Fax\Class1\AdaptiveAnswer\SetupCommand
  2. Fax\Class1\SetupCommand
  3. Fax\SetupCommand

Using the preceding example, if SetupCommand is not defined at any level, T.30 will auto-define SetupCommand using the algorithm described in Modem INF File Entries.

Examples of fax INF file entries for two modems follow:

Example 1: USR Courier V.Everything

Fax, HardwareFlowControl,, "1"
Fax, SerialSpeedInit,, "57600"
Fax, ResetCommand,, "AT&FS0=0E0V1Q0"
Fax, SetupCommand,, "ATS7=255X4&D2&C1&H1&R2&I0"
Fax\Class1\AdaptiveAnswer\AnswerCommand, 1,, "ATE0Q0V1"
Fax\Class1\AdaptiveAnswer\AnswerCommand, 2,, "AT+FCLASS=1"
Fax\Class1\AdaptiveAnswer\AnswerCommand, 3,, "ATE0Q0V1"
Fax\Class1\AdaptiveAnswer\AnswerCommand, 4,, "AT&B1&C1&D2E0Q0V1&A3S0=0"
Fax\Class1\AdaptiveAnswer\AnswerCommand, 5,, "ATS7=60S19=0M1&M4&K1&H1&R2&I0B0X4"
Fax\Class1\AdaptiveAnswer\AnswerCommand, 6,, "AT+FAA=1"
Fax\Class1\AdaptiveAnswer\AnswerCommand, 7,, "ATA"
Fax\Class1\AdaptiveAnswer, ModemResponseFaxDetect,, "FAX"
Fax\Class1\AdaptiveAnswer, ModemResponseFaxConnect,, "CONNECT"
Fax\Class1\AdaptiveAnswer, ModemResponseDataDetect,, "DATA"
Fax\Class1\AdaptiveAnswer, HostCommandDataDetect,, "ATO"
Fax\Class1\AdaptiveAnswer, ModemResponseDataConnect,, "CONNECT"

Example 2: Diamond Supra Voice modem

HKR, Fax, HardwareFlowControl,, "1"
HKR, Fax, SerialSpeedInit,, "19200"
HKR, Fax, ResetCommand,, "AT E0 V1 Q0"
HKR, Fax, SetupCommand,, "AT &F2 E0 V1 Q0 X4 &K3"
HKR, Fax, FixModemClass,, "2"
HKR, Fax\Class2, Cl2IsEx,, "1"
HKR, Fax\Class1\AdaptiveAnswer, ModemResponseFaxDetect,, "FAX"
HKR, Fax\Class1\AdaptiveAnswer, ModemResponseDataDetect,, "CARRIER"
HKR, Fax\Class1\AdaptiveAnswer, ModemResponseFaxConnect,, "CONNECT"
HKR, Fax\Class1\AdaptiveAnswer, ModemResponseDataConnect,, "CONNECT"
HKR, Fax\Class1\AdaptiveAnswer\AnswerCommand, 1,, "AT &F2 E0 V1 Q0 W1 S95=47 S0=0"
HKR, Fax\Class1\AdaptiveAnswer\AnswerCommand, 2,, "ATS7=60 S30=0 L M1 &Q5 \N3 %C3 &K3 B N1 X4"
HKR, Fax\Class1\AdaptiveAnswer\AnswerCommand, 3,, "AT+FAE=1"
HKR, Fax\Class1\AdaptiveAnswer\AnswerCommand, 4,, "ATA"


Adding Voice Support

This section describes the modem INF file entries required to install voice modem features. These features include the range of capabilities supported by Unimodem. You can use modem INF file entries to support these capabilities in your modems. The following topics describe the purpose and usage of the voice modem INF file entries.

This section includes the following topics:

Voice Modem Support of Unimodem Features

Creating Voice Modem INF Entries with ProCalc

Adding Modem-Specific Voice Support

Voice Modem Wave Devices

Platform-Specific Considerations for Voice Support

Except where noted, the information presented in this section applies to both Windows 95/98/Me and Windows 2000 and later versions.


Voice Modem Support of Unimodem Features

A voice modem may support any or all of the features provided by Unimodem. These features are configured using modem INF file entries.

Unimodem supports the following features:

  • Caller ID
  • Distinctive ringing (Not available on Windows 2000 and later versions of the operating system)
  • Speakerphone capability
  • Wave playback and record to and from the phone line
  • Wave playback and record to and from the handset
  • Answering voice calls
  • Voice call dial-out
  • Generation of DTMF digits in voice mode
  • Voice-to-data answering switch

Windows NT 4.0 does not include any voice modem support. Voice support was added to Windows 95/98 beginning with the Windows 95 OSR2 release. The voice support of Windows 2000 and later versions of the operating system is very similar to that provided by Windows 95/98.

Note Windows Me provides both Windows 95/98 and Windows 2000 and later versions of the operating system forms of voice support. Because Windows Me supports both architectures, it can be assumed that all version-specific references also apply to Windows Me. The architecture of Windows 2000 and later versions of the operating system is preferred on Windows Me.

On Windows 95/98 systems, a separate INF file is required for wave device configuration. The wave device entries are integrated into the modem INF file on Windows 2000 and later versions of the operating system.

For more information about sample voice INF files, see Voice Modem Wave Devices. For more information about the differences between Windows 95/98 and Windows 2000 and later versions of the operating system, see Platform-Specific Considerations for Voice Support.


Creating Voice Modem INF Entries with ProCalc

ProCalc is an application that you can use to create registry entries for modem INF files. ProCalc is packaged in the ProCalc.exe executable included in the Driver Development Kit (DDK). The ProCalc application provides a simple user interface to create the most common modem INF file registry entries. This is very useful because the bulk of the work involved in a modem INF file is creating modem INF file entries.

Always use ProCalc to create the following voice modem INF file entries:

Voice Profile

Speaker Phone Specs

XformID (Win9x)

XformID (NT)

The following topics provide more information about using ProCalc to create these voice modem entries.

For more information about using ProCalc to create modem INF file entries, see Creating a Data Modem INF File .


Voice Profile

The VoiceProfile entry is a bit-field used to define voice modem capabilities. ProCalc provides a simple interface to set the VoiceProfile entry option fields.

An example of a VoiceProfile entry follows:

HKR,, VoiceProfile,    1 , 07,a1,02,00


Speaker Phone Specs

The SpeakerPhoneSpecs entry specifies the range of values for speakerphone volume and gain.

The SpeakerPhoneSpecs entry contains the following fields:

  • Max. Volume
  • Min. Volume
  • Max. Gain
  • Min. Gain

An example of a SpeakerPhoneSpecs entry follows:

HKR,, SpeakerPhoneSpecs,1, 00,00,00,00, 0f,00,00,00, 03,00,00,00, 00,00,00,00


XformID (Win9x)

The XformID entry is used in the serial wave device INF file (not the modem INF file) on Windows 95/98. It specifies the serial wave format.

An example of an XformID entry follows:

HKR,Config,XformID, 1, 01, 00, 00, 00 ;e.g. Rockwell 4-bit ADPCM @7200


XformID (NT)

Use the XformID (NT) selection in ProCalc to create an XformID modem INF file entry for Windows 2000 and later versions of the operating system.

An example of an XformID entry for Windows 2000 and later versions of the operating system follows:

HKR,WaveDriver,XformID, 1, 00,00

For more information about the XformID entry in Windows 2000 and later versions of the operating system, see XformID (NT Wavedriver).


Adding Modem-Specific Voice Support

All of the additions required to add voice capability to a modem must be added to add-registry-sections of the modem INF file. You must include the following items in all voice mode INF files:

  • Voice support INF file sections
  • Primary voice modem INF file entries
  • The VoiceProfile entry

The following are features are optional:

  • Audio Mixer
  • Caller ID
  • Distinctive ringing
  • Speakerphone capability
  • Phone message recording and playback
  • Support for answering voice calls
  • Voice call dial-out
  • Support for generation of DTMF digits in voice mode
  • Voice-to-data answering switch

The following topics describe how to add support for both required and optional features to your modem INF file:

Adding Voice Support INF File Sections

Primary Voice Modem INF File Entries

Creating a VoiceProfile INF File Entry

Adding Support for the Audio Mixer

Adding Caller ID Support

Adding Distinctive Ring Support

Adding Speaker Phone Support

Adding Support for Phone Message Recording and Playback

Adding Support for Answering Voice Calls

Adding Voice Call Dial-Out Support

Adding Support for Generation of DTMF Digits in Voice Mode

Adding Support for Voice-to-Data Answering Switch


Adding Voice Support INF File Sections

If you add new add-registry-sections to the INF file, also add the name of the new sections to the AddReg directive in the INF file DDInstall section. A typical AddReg directive is shown below:

AddReg=All, MfgAddReg, Modem1.AddReg, INTERNAL

SmpVoice.inf is a sample voice modem INF file included with the DDK. SmpVoice.inf demonstrates a modem with a serial wave driver that plays and records audio to the handset and phone line.

In SmpVoice.inf, the add-registry-section named MICROSOFT_VOICE contains all the voice modem INF file entries with sample values.

For further information about each INF file entry, see the Voice Modem INF File Entries.


Primary Voice Modem INF File Entries

Unimodem uses the values defined in the Init, Monitor, VoiceDialNumberSetup, and VoiceAnswer INF file entries to control the initialization of voice modems. Examples of these entries follow:

HKR, Init, 2,, "AT &F E0 V1 &D2 &C1 S95=47 S0=0<cr>"

HKR, Monitor, 1,, "ATS0=0<cr>"
HKR, Monitor, 2,, "None"

HKR, VoiceDialNumberSetup, 1,, "at#cls=8<cr>"
HKR, VoiceDialNumberSetup, 2,, "at#vls=0<cr>"
HKR, VoiceDialNumberSetup, 3,, "at#vrn=0<cr>"
HKR, VoiceDialNumberSetup, 4,, "at#vbt=1<cr>"
HKR, VoiceDialNumberSetup, 5,, "at#vsr=7200<cr>"
HKR, VoiceDialNumberSetup, 6,, "at#vbs=4<cr>"

HKR, VoiceAnswer, 1,, "at#cls=8<cr>"
HKR, VoiceAnswer, 2,, "at#vls=0<cr>"
HKR, VoiceAnswer, 3,, "at#vbt=1<cr>"
HKR, VoiceAnswer, 4,, "at#vsr=7200<cr>"
HKR, VoiceAnswer, 5,, "at#vbs=4<cr>"
HKR, VoiceAnswer, 6,, "ata<cr>"

Unimodem sends the commands stored in these INF entries to the modem when TAPI functions are called. The TAPI functions called and their parameters are listed in the following table:

Registry Key(s) Holding Command | TAPI Function Called | Parameter(s)
Init and Monitor | lineOpen | LINECALLPRIVILEDGE_OWNER
Init | lineOpen | LINECALLPRIVILEDGE_NONE or _MONITOR LINEMEDIAMODE_INTERACTIVEVOICE or _AUTOMATEDVOICE followed by lineMakeCall
VoiceDialNumberSetup | lineMakeCall | none
VoiceAnswer | lineAnswer | none


Creating a VoiceProfile INF File Entry

A VoiceProfile entry must be included in all voice modem INF files. The bit settings in the VoiceProfile entry define the capabilities of the voice modem. All the bit settings in the VoiceProfile entry are listed in Modem INF File Entries. Use ProCalc to create the VoiceProfile entry.

The example value used in SmpVoice.inf is:

    HKR,, VoiceProfile,         1, 27,02,40,00

There is a handset bit in the VoiceProfile entry and a related handset entry (WaveDevices) in the serial wave driver INF file. The VoiceProfile handset bit should be set when a modem has any element of a TAPI handset phone device. For example, it can play audio to the handset and report handset hook-switch events.

The following are examples of the WaveDevices entry that appears in the serial wave driver INF file:

    HKR,Config,WaveDevices,  1, 01, 00

    HKR,Config,WaveDevices,  1, 02, 00

Set the WaveDevices entry to 2 when a voice modem has the ability to play back and record to a handset. Set this entry to 1 if the modem does not have this ability or does not have a handset device. A default state of 2 is assumed when the WaveDevices entry is absent from the serial wave driver INF file.

The VoiceProfile entry handset bit and the WaveDevices entry must define support for the same features in there corresponding INF files.

A new Plug and Play node appears in Device Manager if the modem supports an audio device such as a SoundBlaster, Crystal, or other mixer chip. Set the mixer bit in the VoiceProfile entry if the modem has a mixer chip.


Adding Support for the Audio Mixer

There is an audio mixer bit in the VoiceProfile entry. For information about setting the audio mixer bit in the VoiceProfile entry, see Creating a VoiceProfile INF File Entry.

The following entries in SmpVoice.inf describe the audio mixer used by the voice modem:

    HKR,, VoiceMixerMid,     1, 02,00
    HKR,, VoiceMixerPid,     1, 99,01
    HKR,, VoiceMixerLineID,  1, 00, 05 00, 00

For more information about these INF file entries, see VoiceMixerMid.


Adding Caller ID Support

Add EnableCallerID, CallerIDPrivate, CallerIDOutSide and VariableTerminator entries to enable caller ID support.

The EnableCallerID entry is the command string Unimodem sends to the modem to enable Caller ID. For example, the SmpVoice.inf file contains the following entry:

    HKR, EnableCallerID, 1,, "at#cid=1<cr>"

The CallerIDPrivate, CallerIDOutSide entries define characters the modem returns for Caller ID information that is blocked because it is private or originates outside the area. For example, the SmpVoice.inf file contains the following entries:

    HKR,, CallerIDPrivate,, "P"
    HKR,, CallerIDOutSide,, "O"

Caller ID information returned by the modem is variable-length. Therefore, string terminator characters must be specified. For example, the SmpVoice.inf file contains the following entry:

    HKR,, VariableTerminator,,<cr><lf>


Adding Distinctive Ring Support

The EnableDistinctiveRing entry is the command string Unimodem sends to the modem to enable distinctive ring support. For example, the SmpVoice.inf file contains the following item:

    HKR, EnableDistinctiveRing, 1,, "at-sdr=7<cr>"

Distinctive Ring information returned by the modem is variable-length. Therefore, string terminator characters must be specified. For example, the SmpVoice.inf file contains the following entry:

    HKR,, VariableTerminator,,<cr><lf>


Adding Speaker Phone Support

Add SpeakerPhoneSpecs, SpeakerPhoneEnable, SpeakerPhoneDisable, SpeakerPhoneMute, SpeakerPhoneUnMute and SpeakerPhoneSetVolumeGain entries to support speaker phone capabilities. For example, here are the six INF file entries from SmpVoice.inf.

    HKR,, SpeakerPhoneSpecs, 1, 00,00,00,00,  0f,00,00,00,  03,00,00,00,  00,00,00,00
    HKR, SpeakerPhoneEnable,       1,, "at#vls=5<cr>"
    HKR, SpeakerPhoneDisable,      1,, "at#vls=0<cr>"
    HKR, SpeakerPhoneMute,         1,, "at#spk=0,,,<cr>"
    HKR, SpeakerPhoneUnMute,       1,, "at#spk=1,,,<cr>"
    HKR, SpeakerPhoneSetVolumeGain,1,, "at#spk=,<Vol>,<Gain><cr>"

The four values in the SpeakerPhoneSpecs entry define the minimum and maximum speaker phone volumes, as well as the minimum and maximum gain. The SpeakerPhoneSpecs entry must be included even if all four values are zero. Use ProCalc to create the SpeakerPhoneSpecs entry, as described in Creating Voice Modem INF Entries with ProCalc .

The SpeakerPhoneSetVolumeGain entry values are used to scale the speaker phone volume and gain when TAPI passes Unimodem a speaker volume setting. Scaling is based on the values assigned in the SpeakerPhoneSpecs entry. For more information about speaker phone volume and gain scaling, see Modem INF File Entries.

Set the SpeakerPhoneEnable, SpeakerPhoneDisable, SpeakerPhoneMute, and SpeakerPhoneUnMute INF file entries to command strings Unimodem can send to the voice modem to accomplish those functions.

Volume and gain must both be set for modems with volume control. If there is no gain control, use AT volume control commands that approximate gain control.


Adding Support for Phone Message Recording and Playback

Adding support for phone message recording and playback requires definition of the AT commands that control these functions. The following table describes the voice modem INF file entries that define the AT commands for phone message recording and playback:

INF File Entry | Command Description
AbortPlay | Stops playing audio data immediately (does not play the rest of the audio buffer contents). This command is needed for modems that are using a serial wave device.
CloseHandset | Resets the modem to Class 0.
HandsetSetPlayFormat | Sets the modem's handset playback format.
HandsetSetRecordFormat | Sets the modem's handset recording format.
LineSetPlayFormat | Sets the modem's line playback format.
LineSetRecordFormat | Sets the modem's line recording format.
OpenHandset | Puts modem in a mode that enables audio to be played back through the handset when there is no active call.
StartPlay | Starts playing audio (.wav files) through the modem. If a serial wave driver is being used, a bit in the VoiceProfile entry determines if the baud rate is set prior to, or after, the StartPlay command is issued.
StartRecord | Starts recording audio (.wav files) from the modem. If a serial wave driver is being used, a bit in the VoiceProfile file determines if the baud rate is set prior to, or after, the StartRecord command is issued.
StopPlay | Resets the modem's baud rate after an AbortPlay or TerminatePlay command is issued. A bit in the VoiceProfile entry indicates whether Unimodem has to reset the UART's baud rate.
StopRecord | Stops recording audio (.wav files) from the modem. If a serial wave driver is being used, a bit in the VoiceProfile entry determines if the baud rate is set prior to, or after, the StopRecord command is issued.
TerminateRecord | Directs the modem to finish recording its local buffer and stop recording audio data. This command is needed for modems with a serial wave device.
TerminatePlay | Directs the modem to finish playing the contents of its local buffer and stop playing audio data after that. This command is needed for modems with a serial wave device.

The following example demonstrates these entries:

    HKR, CloseHandset,            1,, "at#cls=0<cr>"
    HKR, StartPlay,               1,, "at#vtx<cr>"
    HKR, StopPlay,                1,, "None"
    HKR, StopPlay,                2,, "NoResponse"
    HKR, StartRecord,             1,, "at#vrx<cr>"
    HKR, StopRecord,              1,, "None"
    HKR, StopRecord,              2,, "NoResponse"
    HKR,, TerminateRecord,,       "!"
    HKR,, TerminatePlay,,         "<h10><h03>at<cr>"
    HKR,, AbortPlay,,             "<h10><h18>at<cr>"
    HKR, LineSetPlayFormat,       1,, "at#vls=0<cr>"
    HKR, LineSetRecordFormat,     1,, "None"
    HKR, LineSetRecordFormat,     2,, "NoResponse"
    HKR, HandsetSetRecordFormat,  1,,"at#vsr=7200<cr>"
    HKR, HandsetSetRecordFormat,  2,,"at#vbs=4<cr>"
    HKR, HandsetSetPlayFormat,    1,,"at#vsr=7200<cr>"
    HKR, HandsetSetPlayFormat,    2,,"at#vbs=4<cr>"
    HKR, OpenHandset,             1,, "at#cls=8<cr>"
    HKR, OpenHandset,             2,, "at#vls=2<cr>"

For more information about these voice modem INF entries, see Voice Modem INF File Entries.


Adding Support for Answering Voice Calls

The VoiceAnswer entries are a sequence of commands that Unimodem sends to the modem to answer voice calls and monitor for other calling tones. The following example contains four VoiceAnswer entries that define a sequence of commands to answer a voice call:

HKR, VoiceAnswer,    1,, "at#cls=8<cr>"    (select voice)
HKR, VoiceAnswer,    2,, "at#vls=8<cr>"    (route phone line i/f thru modem)
HKR, VoiceAnswer,    3,, "at#vbt=1<cr>"    (beep tone timer)
HKR, VoiceAnswer,    4,, "ata<cr>"         (answer)


Adding Voice Call Dial-Out Support

The VoiceDialNumberSetup entries are a sequence of commands that Unimodem sends to the modem to dial out for a voice call. The following example contains four VoiceDialNumberSetup entries that define a sequence of commands to dial out for a voice call:

HKR, VoiceDialNumberSetup,    1,, "at#cls=8<cr>"    (select voice)
HKR, VoiceDialNumberSetup,    2,, "at#vls=8<cr>"    (route phone line  i/f thru modem)
HKR, VoiceDialNumberSetup,    3,, "at#vrn=0<cr>"    (ringback never came timer)
HKR, VoiceDialNumberSetup,    4,, "at#vbt=1<cr>"    (beep tone timer)


Adding Support for Generation of DTMF Digits in Voice Mode

Unimodem uses the GenerateDigit entry to generate DTMF digits while in voice mode. The following example demonstrates the GenerateDigit entry:

HKR, GenerateDigit,    1,, "at#vts=<Digit><cr>"    (generate tone signal <Digit>)


Adding Support for Voice to Data Answering Switch

The VoiceToDataAnswer entries are a sequence of commands Unimodem sends to the modem to switch it to data answering mode after it has been in voice answering mode. The following example demonstrates a sequence of commands for switching voice to data mode:

HKR, VoiceToDataAnswer,    1,, "at#cls=0<cr>"    (select data)
HKR, VoiceToDataAnswer,    2,, "ata<cr>"         (answer)

Note Unless the voice features are disabled, Unimodem answers all incoming calls on voice modems as voice calls.


Voice Modem Wave Devices

Digital playback and recording of audio required by voice modems is done by the Windows Multimedia System (MMSystem) with wave devices and stored in .wav files. There are the two basic types of voice modem wave devices:

  1. Serial wave device
  2. Wave wrapper device

Each of these types requires a different interface with Unimodem on Windows 95/98. Windows 95/98 requires a wave device INF file for a serial wave device or a wave wrapper device. Windows 2000 and later versions of the operating system do not require a wave device INF file. The wave device settings are contained in the voice modem INF file on Windows 2000 and later versions of the operating system.

For more information about supporting a wave device on Windows 2000 and later versions of the operating system, see Platform-Specific Considerations for Voice Support .


Voice Modem Support Sample INF Files

Serial port modems send and receive wave input/output data through a serial communications port. On Windows 95/98 systems Serwvdrv.drv is used by Unimodem as the serial wave device driver. Serwvdrv.drv supports the entries documented in Modem INF File Entries.

Voice modems with a separate, non-serial, wave device interface require synchronization between the modem and wave device. The wave wrapper performs all synchronization for these wave devices. The wave wrapper is called by the MMSystem and calls Unimodem to send modem AT commands. The wave driver wrapper calls back the MMSystem to control the wave device.

To use either the serial wave device or the wave wrapper on Windows 95/98 systems, the following entry must be added to an add-registry-section in the modem INF file:

    HKR,, Enumerator, ,serwave.vxd

This entry is always SerWave.vxd. SerWave.vxd has the ability to associate either type of wave device with a modem.

A wave device INF file is required on Windows 95/98. Sample wave device INF files are included with the DDK for both types of wave drivers:

  1. SmpSerwv.inf is a sample INF file that installs the serial wave driver.
  2. SmpWrap.inf is a sample INF file that installs the wave wrapper.

The following types of multimedia devices are usually installed by the wave driver INF:

  • A line device that allows audio to be recorded from and played to the phone line during an active call.
  • A handset device that allows audio to be recorded from and played to the local telephone handset. If the modem does not support a handset device, this device will not be installed.
  • A game-compatible device that ensures compatibility with Windows games and other multimedia applications.


Changing Items in SmpSerwv.inf

Few changes are required to adapt SmpSerwv.inf to a new modem. The sections that contain items changed most often are discussed in this topic.

To help determine the correct INF settings

  1. Search the modem INF file set (mdm*.inf) distributed with Windows for "VoiceProfile".
  2. Compare the voice sections for modems with similar modem chip set support.
  3. Cut and paste the necessary entries.

Change the XformID entry to define the wave support your devices offers. Use ProCalc to create the VoiceProfile entry, as described in Creating Voice Modem INF Entries with ProCalc . The following is an example XformID entry:

HKR,Config,XformID,     1, 01, 00, 00, 00     ;; format

Change the WaveDevices entry to define the support your devices offers. The following is an example WaveDevices entry:

;; normally, there are 2 wave devices, line and handset.
;; If handset is not supported, use the following
HKR,Config,WaveDevices,  1, 01, 00

Use the value of the WaveDevices entry to define the voice modems ability to play back and record to a handset device. Valid values for the WaveDevices entry are listed in the following table:

WaveDevices Value | Meaning
0x00000001 | Voice modem plays back and records to line only.
0x00000002 | Voice modem plays back and records to line and handset device.


Changing Items in Smpwrap.inf

Few changes are required to adapt SmpSrwv.inf to a new modem. This topic describes INF file sections which contain items that require the most frequent changes.

Use the values of the LowerMid, LowerWaveInPid, and LowerWaveOutPid entries to specify the audio wave driver that the wave wrapper must use. The LowerMid entry is the wave driver manufacturer's ID, the LowerWaveInPid entry is the wave input product ID, and the LowerWaveOutPid entry is the wave output product ID. The following example demonstrates these entries:

HKR,Config,LowerMid,1,        5c, 00
HKR,Config,LowerWaveInPid,1,  81, 00
HKR,Config,LowerWaveOutPid,1, 82, 00

The wave wrapper has a mixer device. Four INF entries define the connection between the wave wrapper mixer device and the wave driver mixer. The wave wrapper mixer controls the wave driver mixer while the wave wrapper is loaded. When the wave wrapper is not loaded, the wave driver mixer settings are set back to their original values.

Examples of these entries are provided below:

HKR,Config,WaveOutMixerDest,    1, 00, 00, 00, 00
HKR,Config,WaveOutMixerSource,  1, 00, 00, 00, 00

HKR,Config,WaveInMixerDest,     1, 01, 00, 00, 00
HKR,Config,WaveInMixerSource,   1, 00, 00, 00, 00

The WaveOutMixerDest entry identifies the multimedia line for wave output. The wave output line is normally the speakers. Use the WaveOutMixerSource entry to identify the multimedia line used as the wave source for the WaveOutMixerDest entry. The wave output source is normally the analog to digital converter.

The value in the WaveInMixerDest entry indicates the multimedia line corresponding to wave input. Use the value in the WaveInMixerSource entry to indicate the multimedia line used as the wave source relative to WaveInMixerDest entry. The wave input source is normally line in or wave in.


Platform-Specific Considerations for Voice Support

Most voice modem INF entries work under both Windows 95/98 and Windows 2000. This section provides guidance for adapting voice modem support to Windows 95/98 and Windows 2000 and later versions of the operating system. For details of the voice modem INF entries, see Voice Modem INF File Entries.

Windows 2000 and later versions of the operating system do not require a serial wave driver INF file. All voice INF file entries and settings are contained in the modem INF file on Windows 2000 and later versions of the operating system. Voice modem INF files for Windows 2000 and later versions of the operating system support additional entries and require setting a VoiceProfile entry bit that is specific to Windows 2000 and later versions of the operating system.

Note The following examples assume a Rockwell modem. Substitute the correct settings for the target modem.

To add voice support for Windows 98 to a modem INF file created for Windows 95

  1. Add this INF file entry to the modem INF file:
    HKR, WaveDriver,  WaveHardwareID ,, "RockwellADPCMVoiceModemWave"
  2. Add the following entry to the model section of the serial wave driver INF file:
    %Rockwell.DeviceDesc%=ROCKWELL.Mem, MODEMWAVE\RockwellADPCMVoiceModemWave  ; Memphis-NT5 voice INF file update
  3. In the strings section of the serial wave driver INF file, provide an appropriate friendly string:
    Rockwell.DeviceDesc="Rockwell Voice Modem Serial Wave Device"
  4. Add an installation section to the serial wave driver INF file:
    [ROCKWELL.Mem]
AddReg=MSSERWAVE.AddReg, ROCKWELLMem.AddReg
  5. Add an add-registry-section to the serial wave driver INF file:
    [ROCKWELLMem.AddReg]  HKR,Drivers\wave\serwvdrv.drv,Description,,%Rockwell.DeviceDesc%

To add voice support for Windows 2000 and later versions of the operating system

  1. Use ProCalc to add the voice support bit for Windows 2000 and later versions of the operating system to the VoiceProfile entry in the modem INF file.

    This is an example VoiceProfile with the bit set for Windows 2000 and later versions of the operating system:

    HKR,, VoiceProfile,     1,25,02,19,02
  2. Use the current serial wave driver INF file wave settings to add corresponding voice INF file entries for Windows 2000 and later versions of the operating system in the voice section of the modem INF file. Adjust the voice INF file entries for Windows 2000 and later versions of the operating system to reflect the properties and commands of the modem chip set.

    The following example shows the original settings in the serial wave INF file:

    HKR,Config,XformModule,  , "umdmxfrm.dll"
HKR,Config,XformID,     1, 01, 00, 00, 00
HKR,Config,WaveDevices, 1, 01, 00

    This example shows the settings in the modem INF file for Windows 2000 and later versions of the operating system:

    HKR, WaveDriver,  XformModule    ,, "umdmxfrm.dll"
HKR, WaveDriver,  XformID        ,1, 01, 00
HKR, WaveDriver,  WaveDevices, 1, 01, 00
HKR, WaveDriver,  WaveHardwareID ,, "RockwellADPCMVoiceModemWave"
HKR, WaveDriver,  BaudRate       ,1, 00, c2, 01, 00


Adding WDM Modem Support

WDM is the standard device driver model on Windows 2000 and later operating systems. WDM is the preferred device driver model on Windows Me. All Windows 95 device drivers are based on the VxD device driver model. Windows 98/Me supports the WDM and the VxD based driver models.

WDM and the previous VxD device driver model are not directly compatible. Therefore, there are two additional drivers (ccport.sys and wdmmdmld.vxd) required for Windows 98/Me WDM modem support. These drivers are unique in design and do not follow the architecture of either a VxD driver or a WDM driver because they are used to span the two driver models.

Note Windows Me can use INF files used on the NT-based version of the operating system to install WDM drivers. To install a Vxd-based driver on Windows Me, the folder containing the Vxd INF files must be different than the folder containing the INF file used on the NT-based version of the operating system. If the INF files are in the same folder, Windows Me will use the INF file used on the NT-based version of the operating system.

This section provides additional information about:

Architectural Differences for WDM Modem Drivers

WDM Modem Support for Windows 98/Me

WDM Modem INF Entries for Windows 2000 and Later Operating Systems

WDM Modem Driver Example

For more information about WDM drivers, see Introduction to Windows Drivers.


Architectural Differences for WDM Modem Drivers

The Windows 95/98/Me VxD based architecture for modem drivers is called VCOMM. VCOMM interfaces with VxD based serial drivers. Modem drivers for Windows 2000 and later versions must interface with the system component modem.sys. Modem.sys is actually very similar in function to VCOMM, but has a different architecture. The Ccport.sys component interfaces with VCOMM and performs functions similar to a VxD based serial driver, and then translates calls into the form that a WDM-based modem driver typically receives from modem.sys. The following illustration shows the WDM modem driver interfaces used on Windows 2000 and later operating systems, as well as those used on Windows 95/98/Me:

WDM Modem Driver Interfaces on Windows 2000 and Windows 95/98/Me

Note Because wdmmdmld.vxd is not part of the translation between VCOMM and the WDM modem driver, it was omitted from the preceding driver architecture illustration.

Note Windows Me has an enhanced INF file interpreter that allows it to load WDM drivers using the INF files that are used on NT-based operating systems. The underlying system architecture is based on Windows 98. However, Windows Me supports the use of INF files written for Windows 98 and can also provide the same WDM support offered NT-based operating systems.


WDM Modem Support for Windows 98/Me

A "device node" or PDO is required to load a driver. This devnode is used by the system to keep track of the hardware that is connected to the computer. There is normally a one-to-one ratio between devnodes and device drivers.

On Windows 98/Me a WDM modem has two drivers but only one devnode to load a driver. Also, these two drivers are implemented with different driver models in the system. To solve this problem, another devnode needs to be created to load the extra driver. Ccport.sys provides a special type of driver called an "enumerator" that you must use to create the devnode.

Because of the technology behind WDM modems, the WDM driver is required to load first. Therefore, the WDM driver is assigned to the devnode associated with the Hardware ID of the device as specified in the INF file.

Once the WDM driver is loaded, the CCPORT enumerator reads a ChildID registry key (specified in the WDM device INF file) and creates a devnode associated with the ChildID.

When the ChildID-devnode is created, it receives the following information:

  • The device type "MODEM"
  • The device ID found in the ChildID registry key
  • The parent devnode of the WDM device

The modem is a child to the WDM parent device. For this reason, power management and Plug and Play events that occur on one device automatically affect the other. For example, if you remove the parent device from the device manager, the child is also automatically removed.

The modem class installer reads the modem INF file and builds all the modem registry keys necessary for Unimodem to access the modem. It also writes out the PortDriver key, which tells the system to load wdmmdmld.vxd as the VCOMM port driver.

Note The WDM device INF file and the modem INF file are not the same file.

The following topics describe the INF file entries used to provide WDM support on Windows 98/Me:

CCPORT INF File Entries

WDMMDMLD Modem INF File Entry

Installation Sequence

WDM Device INF Files


CCPORT INF File Entries

CCPORT includes all the functions required in a VCOMM port driver and the services to translate those functions to WDM IRPs. CCPORT must be loaded as the upper-edge driver on the WDM modem stack. Therefore, you load CCPORT along with your WDM modem driver.

There is a sample INF file in the DDK named wdmmdm.inf that demonstrates a modem INF created to support WDM.

The following example INF file entries identify the device loader for the WDM drivers and direct the system to load CCPORT as the top-edge driver and the USB modem driver as the bottom-edge driver.

HKR,,DevLoader,0,*ntkern
HKR,,NTMPDriver,,"usbser.sys,ccport.sys"

In addition to providing the mapping layer between VCOMM and the WDM modem driver, CCPORT also acts as the enumerator for the modem.

This strategy uses the devnode that is associated with the ChildID to load the VCOMM part of the driver stack. For this reason, a slightly different device ID structure is required.

The WDM driver INF must include the following entry to define the ChildID:

[MSAddReg.HW]        ; actually generation of ChildID
HKR,,ChildID,2,"USB\MSF9999"

The modem driver INF must include the ChildID as the device ID for the modem as demonstrated in the following example:

[Models]
%MS1PNP% = Modem1, USB\MSF9999

In the preceding example, the modem device ID is MSF9999, indicating that the modem is attached to USB port.


WDMMDMLD Modem INF File Entry

All devices must have a unique device loader (the system component that loads the device driver at installation or startup). Additionally, all modems must have VCOMM as their device loader and VCOMM only loads VxD drivers. In this instance, WDMMDMLD fills in for CCPORT because CCPORT is not a VxD.

CCPORT and the WDM modem driver are loaded under the WDM driver space and use the device loader of ntkern (ntkern provides the NT kernel interface to Windows 98/Me). Therefore, CCPORT has to load under ntkern and WDMMDMLD fills its place under VCOMM.

When VCOMM first loads a driver, it requests the starting address for the VCOMM port driver interface. During this initialization, WDMMDMLD provides the address of the CCPORT VCOMM port driver interface, creating a link between VCOMM and the WDM mapping layer, CCPORT. WDMMDMLD provides no additional functionality.

Because a WDM modem does not use the standard VCOMM port driver, serial.vxd, you must specify Wdmmdmld.vxd by including the PortDriver entry in the modem INF file as follows:

[USB]
HKR,, DeviceType, 1, 01
HKR,,PortDriver,,wdmmdmld.vxd
HKR,,Contention,0,

Note The PortDriver entry is also used to support controller-less and soft-modem devices on Windows 98/Me.


Installation Sequence

The following outlines the installation sequence for WDM modem drivers on Windows 98:

  1. Attach the device, for example, plug in the USB device or power up the system after installing a PCI card. The primary bus driver and enumerator detect a new device is present.
  2. The Hardware ID is used to locate the WDM device INF file. The system uses the INF file to determine what drivers to load along with other details about the modem.
  3. The system writes the registry keys specified in the INF to the devices key in the registry and loads the driver stack of CCPORT and the WDM modem driver.

    Note One of the registry keys is the ChildID string that is used for the virtual modem device.

  5. The driver stack of CCPORT and the WDM modem driver are started. The CCPORT enumerator is registered during this driver startup process.
  6. The system request that the CCPORT enumerator identify any new devices and a modem device is created using the ChildID string. The ChildID string is used to identify the modem INF file.
  7. The modem class installer performs the same tasks as with a non-WDM modem installation. It reads the modem INF and builds all the modem registry keys necessary for Unimodem to access the modem. It also writes out the PortDriver key, which tells the system to load wdmmdmld.vxd as the VCOMM port driver.
  8. VCOMM takes over and asks WDMMDMLD for the entry point and is pointed to CCPORT.


WDM Device INF Files

A WDM device INF must include:

  • The device Hardware ID to match
  • The friendly name string for the device
  • The DevLoader entry identifying ntkern
  • The NTMPDriver entry listing the device drivers

You can have additional standard INF sections, for example, CopyFiles for getting device drivers copied to the system.

For WDM modem support, the ChildID entry is required to provide the enumerator part of CCPORT with an ID for the modem devnode.

The following is a minimal example WDM modem INF:

[Version]            ; standard version section
Signature=$CHICAGO$
Class=USB
Provider=%String0%

[Manufacturer]
%String0%=Microsoft

[Microsoft]        ; device ID match
%MS1%=MSUSB,USB\VID_9999&PID_9999

[MSUSB]            ; what todo when you have match
AddReg=MSUSB.AddReg

[MSUSB.AddReg]        ; specify devloader and driver stack
HKR,,DevLoader,0,*ntkern
HKR,,NTMPDriver,,"usbser.sys,ccport.sys"

[MSUSB.HW]        ; reference to put ChildID key in hardware devnode
AddReg=MSAddReg.HW

[MSAddReg.HW]        ; actually generation of ChildID
HKR,,ChildID,2,"USB\MSF9999"

[PreCopySection]
HKR,,NoSetupUI,,1

[Strings]            ; friendly name strings
String0="Microsoft Corporation"
MS1="Microsoft 56K USB Modem"


WDM Modem INF Entries for Windows 2000 and Later Operating Systems

WDM is the standard driver model on Windows 2000 and later operating systems. For more information about WDM drivers, see Introduction to Windows Drivers.

Use standard INF file directives and entries to install WDM modem drivers on Windows 2000 and later versions of the operating system. The examples in this section are based on installing a USB-based modem. For more information on INF file driver support, see Device Installation Overview.

To support WDM modem device drivers on Windows 2000

  1. The model section should identify the Hardware ID of the modem as demonstrated in the following example:
    [Manufacturer]
%Microsoft% = Microsoft

[Microsoft]
%Modem3% = Modem3, USB\VID_04C1&PID_0082
  2. Specify the drivers to load as demonstrated in the following example:
    [Modem3.NT.Services]
AddService=usbser, 0x00000000, LowerFilter_Service_Inst

[LowerFilter_Service_Inst]
DisplayName=%USBFilterString%
ServiceType= 1
StartType  = 3
ErrorControl = 0
ServiceBinary = %12%\usbser.sys

  3. Specify any files to copy using the CopyFiles directive as demonstrated in the following example:

    [Modem3.NT]
DriverVer=5/13/1999
include=MDMGL007.INF,mdmgl004.inf,mdmgl001.inf
CopyFiles=USBModemCopyFileSection
AddReg = All,MfgAddReg,Modem2.AddReg, EXTERNAL

[USBModemCopyFileSection]
usbser.sys,,,0x20

    4.

  4. Specify any additional registry entries as demonstrated in the following example:

    [Modem3.NT.HW]
AddReg=LowerFilterAddReg

;USB
[LowerFilterAddReg]
HKR,,"LowerFilters",0x00010000,"usbser"

    5.


WDM Modem Driver Example

The Serial.sys driver is an example of a WDM driver used to support COM port based modems on Windows 2000 and later versions of the operating system. Serial is a function driver for legacy COM ports and Plug and Play COM ports. Serial is also a lower-level device filter driver for Plug and Play devices that require a 16550 UART-compatible interface, but are not attached to a COM port.

For more information about the operation of the serial.sys driver, see Serial Devices and Drivers and Serial Driver Reference.

You can also find information about the serial.sys driver from the following sources:

  • Data definitions in the #include file \inc\ntddser.h in the Windows DDK
  • Sample code in the \src\kernel\serial directory in the Windows DDK
  • Microsoft Win32® Communications API

There is also another WDM example available called FakeModem.sys.


Modem Installation Testing

This section provides information about modem INF file installation testing issues. These issues are described in the following topics:

Modem Testing and Support Resources

Modem Test Tools

WHQL Modem Testing

For an overview of Modem INF files, see Overview of Modem INF Files.


Modem Testing and Support Resources

Microsoft's Windows Hardware Quality Labs (WHQL) ensures the compatibility of hardware with Windows. WHQL provides Hardware Compatibility Test (HCT) kits that are used to qualify devices, including modems, for the Microsoft Windows logos and for inclusion on Microsoft's Hardware Compatibility List (HCL).

Internet Resources

WHQL information, including HCL and HCT kits: http://microsoft.com/hwtest/

Windows Hardware and Driver Development information: http://www.microsoft.com/hwdev/

Microsoft Driver Development Kit (DDK) and developer support: http://www.microsoft.com/support/

Microsoft Developer Network (MSDN®) membership information: http://www.microsoft.com/msdn/

Email Addresses

General input and questions for the Unimodem team: modemfb@microsoft.com

Controllerless and softmodems: wdmmodem@microsoft.com

WHQL test kit questions: mcthelp@microsoft.com


Modem Test Tools

You should consult the WHQL Web site for the latest information and tools available concerning modem testing.

The tools available for modem testing are discussed in the following topics:

Modem Testing Using a Terminal Application

Using ChkINF

Testing a Modem Installation Using MCT


Modem Testing Using a Terminal Application

You can use HyperTerminal or any other terminal communications application for simple initialization, AT command testing, and debugging.

To use HyperTerminal

  1. Close MCT if it is running.
  2. Start a HyperTerminal session to access the modem directly.
  3. Issue AT commands until you find one or more commands that do not produce an OK response from the modem.
  4. Modify these commands in the INF file, or remove them entirely.
  5. Uninstall the modem from the Control Panel and reinstall it again so that the newly modified INF is in use.
  6. Rerun the MCT.

Note To speed testing, cut and paste initialization strings from the modem INF file into HyperTerminal. After pasting, connect to a dependent modem to see verbose or numeric responses received.


Using ChkINF

Use the INF File Syntax Checker (ChkINF) to check the syntax and content of a modem INF file. This topic provides some general information about using ChkINF, describes how to handle certain error messages, supplements the complete instructions that are included with ChkINF.

Always include all possible responses for your modem in your INF file. Do not include responses that the modem cannot actually provide. Use your modem documents and firmware to determine the actual responses you should put in the INF. ChkINF might respond with a large number of warnings about missing INF responses. These warnings point out cases you might have overlooked and should only be taken as reminders.

ChkINF warns about PCMCIA card tuple hardware IDs of more than 50 characters. This warning can be ignored in Windows 98/Me and Windows 2000 and later versions of the operating system. If you need to support older Windows versions, consider shortening your tuple if you do not require the extra length. Do not confuse this issue (tuple ID length) with a long friendly string.

Incorrect Response State Example

The following INF entry will generate an error in ChkINF:

HKR, Responses, "RINGING",     1, 01, 00, 00,00,00,00, 00,00,00,00
;(E3117) The response contains no keyword for the state 0x01 (Negotiation Progress).

Assuming your modem supports the RING and RINGING responses, the Responses INF file entries should have the bResponseState byte set to 0x08 as shown in the following examples:

HKR, Responses, "RING",        1, 08, 00, 00,00,00,00, 00,00,00,00
HKR, Responses, "RINGING",     1, 08, 00, 00,00,00,00, 00,00,00,00

Unrecognized Response Example

In this example, ChkINF warns about the following response entry:

HKR, Responses, "<cr><lf>NO CARRIER: HEADSET<cr><lf>", 1, 04, 00, 00,00,00,00, 00,00,00,00
;(E3117) The response contains no keyword for the state 0x04 (No Carrier).

The ChkINF lookup table does not have information about the response. Verify that the correct bResponseState for your modem is indicated in the Responses entry. In this example, the modem is not connected, and an error has occurred. Therefore the Responses entry is correct. In this event, attach a note with your submission to WHQL to make them aware of the ChkINF issue.

Connect Response Example

ChkINF generates a warning in response to the following INF entry:

HKR, Responses, "<cr><lf>connect<cr><lf>", 1, 01, 00, 00,00,00,00, ff,01,00,00

Two errors are present in this example:

  1. The bResponseState byte is set incorrectly for a connect message.
  2. In addition, the last DWORD (dwNegotiatedDTERate) should not be used.

The correct response entry is as follows:

HKR, Responses, "<cr><lf>connect<cr><lf>", 1, 02, 00, 00,00,00,00, 00,00,00,00

Note The dwNegotiatedDTERate data field should rarely be used. For modems that support only direct modes, it is possible to direct Unimodem to lower its DTE speed by specifying a value for dwNegotiatedDTERate. This is not usually needed because most modems make connections with automatic speed buffering.

TerminateRecord Warning Example

It is possible to create errors by cutting and pasting from an old INF file. Obsolete voice INF files had TerminateRecord settings ending in AT<cr> as shown in the following example

HKR,, TerminateRecord,,      "<h10>E<cr>at<cr>"
;(W4040) Command "TerminateRecord" should not terminate in AT<cr>.

Use the following INF file entry instead:

HKR,, TerminateRecord,,      "<h10>E<cr>"

The following warning messages all require a similar fix:

;(W4040) Command "TerminateRecord" should not terminate in AT<cr>.
;(W4040) Command "TerminatePlay" should not terminate in AT<cr>.
;(W4040) Command "AbortPlay" should not terminate in AT<cr>.

Mixer Chip Example

ChkINF generates a warning message about the mixer chip setting in the VoiceProfile entry as follows:

HKR,, VoiceProfile,          1, 27,03,08,00
;(W4052) Separate sound mixer chip required.

This message is a reminder to verify the correct mixer chip setting. Ignore this message if you have verified the correct mixer chip setting.


Testing a Modem Installation Using MCT

You can use the Modem Compatibility Test kit (MCT) to verify that your modem INF file properly installs and runs with your modem on a Windows platform. After successfully completing the pre-test of the modem and INF file with the MCT kit, follow the directions outlined in the MCT kit to submit the INF file and modem hardware to Microsoft Windows Hardware Quality Labs (WHQL).

Use the current version of MCT for WHQL submissions. Other versions of MCT could be preliminary versions provided for testing new system features or could be obsolete. For more information about WHQL submissions, see WHQL Modem Testing.

MCT is updated frequently to provide support for the latest features. Instructions for running the current version of MCT can be obtained from WHQL.

Microsoft often receives requests to add additional features to MCT. Generally this is done when something significant is needed. Submit your requests for new features to WHQL.

Note The voice modem support for distinctive ring and caller ID should be tested with MCT. The Microsoft® Phone application used previously is no longer required for testing those features.

Note During the running of the "Compression" or "Error Control" tests, you might receive a "PASS/COM Port" response. This indicates a conditional pass. MCT will sometimes try to lower port speeds to get a successful file transfer. MCT will allow a conditional pass based on the COM port speed adjustment if the subsequent file send/receive is successful.


WHQL Modem Testing

Modem INF files that pass Microsoft Windows Hardware Quality Labs (WHQL) testing are eligible for distribution in the Windows Driver Library on the World Wide Web and in future Windows operating system releases.

The WHQL Hardware Compatibility Test Kit (HCT) provides step-by-step instructions for submitting modems and INF files to WHQL for compatibility and logo testing. The HCT contains the current versions of the modem test tools including ChkINF and the Modem Compatibility Test kit (MCT).

You will receive a test report when testing is complete.

When the modem and INF passes WHQL testing, you will receive:

  • A signed Windows Logo License Agreement and a Logo Kit containing camera-ready artwork.
  • Addition of the modem product to the Windows Hardware Compatibility Lists (HCL).
  • An opportunity to distribute the INF file through the Windows Driver Library (WDL) on the World Wide Web and in future Windows releases.

To obtain information about the latest WHQL modem tests, see Modem Testing and Support Resources .


Distributing Your INF File

Beginning with Windows 95, all Windows-based operating systems have included modem INF files. Existing modem INF files are sometimes used as a template to create new INF files.

Follow these guidelines to avoid conflicts with other INF files:

  • Make sure that your modem ID strings are not already being used in another modem INF file. Using a suitable find utility, search all pre-existing Windows modem INF files in your target Windows version for all of the modem IDs available from your new modem. You must check for all ID strings that may be present in the new modem. For example, PCMCIA modems have both tuple ID strings and Unimodem ID strings. Change your modem ID strings if there are matches in the pre-existing INF files.
  • Make sure that your new INF file contains only the entries necessary to support your new modem. Do not include entries for modems that are already included in the release of the Windows versions you are targeting.
  • Make sure that your new INF file will not be explicitly copied to the INF file directory. When a user is prompted for a disk or directory from which to install the new INF, Windows will automatically copy the new INF file to the correct location. Copying the new file explicitly to the INF directory is not permitted.
  • Before distributing your INF files:
  • Use the Microsoft test tools to test your modem installation. For more information about test tools, see Modem Installation Testing .
  • Test your modem with any application software you intend to distribute with the modem.
  • To obtain support for your modem in future Windows operating systems, send a modem submission to Microsoft Windows Hardware Quality Labs (WHQL). Your submission should include your modem INF file and hardware. For more information about WHQL, see Modem Installation Testing .


Modem INF File Entries

A Windows modem class device (modem) is defined herein as any device supported by the Windows universal modem driver (Unimodem). There are many types of "modems" that are not modem class devices. Windows modem class devices are installed with modem INF files. For a complete overview of modem INF files and additional information about using, creating and installing modem INF files, see Overview of Modem INF Files.

Modem INF file entries consist primarily of add-registry-section entries. Each named section referenced by an AddReg directive in an INF file has the following form:

[add-registry-section]

reg-root, [subkey], [value-entry-name], [flags], [value]
...

An add-registry-section section can have any number of entries, to be determined by the writer of the INF file. Each entry should be placed on a separate line.

The DDK documentation provides examples of each modem INF file entry. For more general information about the AddReg directive and its entries, see DDK INF File Sections and Directives.

A modem INF file generally consists of standard INF file entries which are required by all modems and entries that provide Unimodem with additional information about the modem being installed. This section includes a complete list of the modem INF file entries.

Different entries are used depending on the modem's capabilities. This section includes the following topics:

Data Modem INF File Entries

Fax Modem INF File Entries

Voice Modem INF File Entries

ISDN-TA Modem INF File Entries

GSM Modem INF File Entries


Data Modem INF File Entries

All modems provide data modem features. This topic describes the modem INF file entries that support data modem features.

Answer

This entry specifies the AT command that is sent to the modem to answer a data call.

Format

One or more command strings.

Sample

HKR, Answer,    1,, "ATA<cr>"

Note

Normally "ATA".

Hangup

This entry specifies the AT command that is used to disconnect a call after Unimodem puts the modem into command mode.

Format

One or more command strings.

Sample

HKR, Hangup,    1,, "ATH<cr>"

InactivityScale

This entry specifies the scale value for InactivityTimeout. The equation for inactivity timeout is as follows:

InactivityTimeout * InactivityScale = inactivity timeout in seconds.

Format

A single DWORD hexadecimal value.

Sample

HKR,, InactivityScale, 1, 0a,00,00,00

Note

If InactivityScale is omitted from an INF file, a default value of 10 seconds will be used. It is important to verify that the correct InactivityScale and InactivityTimeout are specified.

Examples and common values follow:

3c,00,00,00 = 60 seconds = 1 minute

0a,00,00,00 = 10 seconds

01,00,00,00 = 1 second

68,01,00,00 = 360 seconds = 6 minutes

80,33,e1,01 = 31536000 seconds = 525600 minutes = 8760 hours = 365 days = 1 year

See Also

Settings, InactivityTimeout INF file entry, InactivityTimeout value in the Properties INF file entry

Init

Use this INF file entry to specify the AT commands that are sent to initialize a modem.

Format

One or more command strings.

Samples

(1)
    HKR, Init,    1,, "AT<cr>"
    HKR, Init,    2,, "AT &F E0 V1 &D2 &C1 W2 S95=47<cr>"
(2)
    HKR, Init,    1,, "AT<cr>"
    HKR, Init,     2,, "AT &F E0 S0=0 $BA0 S25=20<cr>"

Note

The Init command should put the modem in the following state:

  • Set Factory Defaults (&F)
  • No Echo (E0)
  • Return Result Codes (Q0)
  • Return all possible Negotiation and Call progress messages (W2 S95=47)
  • Track status of carrier detect signal (&C1)
  • Monitor DTR. When an off-to-on transition occurs, hang up and enter command state (&D2)
  • Communicate in fixed DTE mode (&Q5)
  • Assert DSR always (&S0)
  • Do not answer automatically (S0=0)

If the modem is set to these values after the factory default reset (&F), the values need not be included in the Init command strings. It is important to verify that the factory default reset (&F) uses the correct values.

The default modulation, compression, and protocol options set in the Init command strings should be set to enable maximum flexibility. Do not put any settings in the Init string that restrict these capabilities.

A large number of modems require that command lines be no greater than 40 characters in length. To be safe, Unimodem assumes that modems can only handle commands that are less than 40 characters long.

A modem is generally set to report verbose responses. However, either verbose or numeric responses are acceptable. It is important that the correct responses are put in the Responses INF file entries.

The user can define a custom Init command string in the CPL which will be issued after Unimodem has done its dynamic initialization. This setting is found in the modem control panel interface under the advanced modem properties tab. The field name in the dialog is Extra Settings.

See Also

Responses INF file entry

Monitor

This entry defines the AT command that directs the modem to report all incoming calls. A modem normally reports incoming calls through a RING response.

Format

One or more command strings.

Sample

HKR, Monitor, 1,, "ATS0=0<cr>"
HKR, Monitor, 2,, "None"

Note

The modem must not be in an auto-answer state.

Properties

The Properties entry defines a set of modem properties that are contained in a binary structure. Unimodem requires this modem properties structure to respond to the GetCommProperties function.

Format

Eight DWORD hexadecimal values.

Sample

HKR,, Properties, 1, 80,01,00,00, ff,00,00,00, ff,00,00,00, 07,00,00,00, 0f,00,00,00, f7,03,00,00, 00,c2,01,00, 40,38,00,00

Note

The ProCalc tool, included in the DDK, should be used to create this entry.

The Properties entry can be described in a C structure as follows:

typedef struct ModemProp {
DWORD    DialOptions;          // bitmap of supported options
DWORD    CallSetupFailTimeout; // Maximum value in seconds
DWORD    InactivityTimeout;    // Maximum value in units
                               //   specified by InactivityScale
DWORD    SpeakerVolume;        // bitmap of supported values
DWORD    SpeakerMode;          // bitmap of supported values
DWORD    ModemOptions;         // bitmap of supported values
DWORD    MaxDTERate;           // Maximum value in bit/sec
DWORD    MaxDCERate;           // Maximum value in bit/sec
} ModemProp

The members in this structure are defined as follows:

DialOptions
Specifies a bit vector of the embedded commands that the modem supports in dial commands:
DIALOPTION_DIALBILLING | 0x00000040 | Supports wait for bongtone "&"
DIALOPTION_DIALQUIET | 0x00000080 | Supports wait for quiet "@"
DIALOPTION_DIALDIALTONE | 0x00000100 | Supports wait for dial tone "W"

Note These characters ('&', '@', 'W') cannot be changed. If they are not the same for a given modem, these settings cannot be used at all. For example, if the modem supports "Wait for bongtone", but uses '!' instead of '&', it must not set DIALOPTION_DIALBILLING, and Unimodem will proceed as if it does not support "Wait for bongtone".

CallSetupFailTimeout
Specifies the maximum value allowed for the call setup timer. The call setup time is the delay between dialing and responding to an incoming carrier signal after initial connection. If the modem does not detect a carrier within this time, the modem hangs up. If the modem does not have this feature, set this value to 0.

For more information, see Settings, CallSetupFailTimer INF file entry.

InactivityTimeout
Specifies the maximum value allowed for the data inactivity timer. The inactivity timeout is the allowed period of time after which an inactive modem will time out and hang up. If the modem does not have this feature, set this value to 0.

Multiply this number by the value in InactivityScale to convert to the maximum value in seconds.

For more information, see Settings, InactivityTimeout INF file entry.

SpeakerVolume
Specifies a bit vector of possible speaker volume settings defined as follows:
Supports low speaker volume | 0x00000001
Supports medium speaker volume | 0x00000002
Supports high speaker volume | 0x00000004

For more information, see the corresponding entries described in Settings, SpeakerVolume_XXX INF File entries.

SpeakerMode
Specifies a bit vector of possible speaker mode settings defined as follows:
Supports speaker mode off | 0x00000001
Supports speaker mode dial | 0x00000002
Supports speaker mode on | 0x00000004
Supports speaker mode setup | 0x00000008

For more information, see the corresponding entries described in Settings, SpeakerMode_XXX INF File entries.

ModemOptions
Specifies a bit vector of settings that can be changed using lineSetDevConfig. The bit values are defined as follows:
Supports enabling/disabling of data compression negotiation | 0x00000001
Supports enabling/disabling of error control protocol negotiation | 0x00000002
Supports enabling/disabling of forced error control | 0x00000004
Supports enabling/disabling of a cellular protocol | 0x00000008
Supports enabling/disabling of hardware flow control | 0x00000010
Supports enabling/disabling of software flow control | 0x00000020
Supports CCITT/Bell toggling | 0x00000040
Supports enabling/disabling of speed negotiation | 0x00000080
Supports tone and pulse dialing | 0x00000100
Supports blind dialing | 0x00000200
Supports CCITT V.21-V.22/CCITT V.23 toggling | 0x00000400
Supports modem diagnostics (for example, AT#UD) | 0x00000800

For more information, see the corresponding entries in the following topics: Settings, ErrorControl

Settings, FlowControl

Settings, Compression

Settings, Modulation

Settings, SpeedNegotiation

Settings, Pulse

Settings, Tone

Settings, Blind

MaxDTERate
Specifies the maximum data transmission speed supported between the modem and the computer.
MaxDCERate:
Specifies the maximum data transmission speed supported between the two modems.

Reset

The Reset entry specifies the command string that Unimodem sends to the modem to return it to a base configuration that works with communications programs for MS-DOS and Windows operating systems

Format

One command string.

Sample

HKR,, Reset,, "AT&F<cr>"

Note

This entry is generally "AT&F" or "ATZ". Some modems may use "AT&F1" or "AT&F2" for IBM PC-compatible configurations. It is important to ensure that the modem is in a state that the MS-DOS–based communications program requires (for example, verify echo is on).

Responses

Use Responses entries to specify the response strings Unimodem is programmed to receive from the modem.

Format

A single entry containing the exact response, and a data structure containing information about the response.

Sample

HKR, Responses, "<cr><lf>CONNECT<cr><lf>",    1, 02, 00, 00,00,00,00, 00,00,00,00

HKR, Responses, "<cr><lf>CONNECT 300<cr><lf>",     1, 02, 00, 2C,01,00,00, 00,00,00,00

Note

The binary data structure corresponds to the following C structure:

typedef struct MSS {
BYTE  bResponseState;
BYTE  bNegotiatedOptions;
DWORD dwNegotiatedDCERate;
DWORD dwNegotiatedDTERate;
};

The members in this structure are defined as follows:

bResponseState
Indicates the type of response. Response types belong to one of the following three groups:
  1. Data/Fax modem responses
  2. Additional Voice responses
  3. Additional call control responses

Data/Fax modem responses include:
The modem accepted the previous command | OK | 0x00
Status information about a new connection is being reported | Negotiation Progress | 0x01
A call is connected, the modem is in DATA mode | Connect | 0x02
The modem rejected the previous command | Error | 0x03
The call was disconnected | No Carrier | 0x04
No dial tone is present | No Dialtone | 0x05
The dialed modem is busy | Busy | 0x06
The dialed modem did not answer | No Answer | 0x07
There is an incoming call | Ring | 0x08
Reserved for VoiceView responses | 0x09-0x10

Additional Voice responses include:
Distinctive ring – length of ring – variable length response | Ring duration | 0x91
Distinctive ring – length of time between rings – variable length response | Ring break | 0x92
Date reported by Caller ID - variable length response | Date | 0x93
Time reported by Caller ID - variable length response | Time | 0x94
Number reported by Caller ID - variable length response | Number | 0x95
Name reported by Caller ID - variable length response | Name | 0x96
Message reported by Caller ID - variable length response | Message | 0x97
Single ring distinctive ring | Single Ring | 0x98
Double ring distinctive ring | Double ring | 0x99
Triple ring distinctive ring | Triple Ring | 0x9A
Reserved for Sierra Voice Modem | 0x9B

Additional call control responses include:
The modem will not dial because there have been too many unsuccessful attempts (for example, Blacklisted, as per ETS 300 001) | Blocked | 0x0000001C
The modem will not dial until after some time has elapsed, because there have been too many recent unsuccessful attempts (for example, Delayed, as per ETS 300 001) | Delayed | 0x0000001D

Note The VCON modem response should be entered as an OK response from the modem.

bNegotiatedOptions
Specifies information about a connection being made. This value is used only for response codes of type Negotiation Progress or Connect. Unimodem recognizes the following values (which may be combined in a single response):
Compression negotiated | 0x00000001
Error control negotiated | 0x00000002
Cellular protocol negotiated | 0x00000008

The only valid values for this member are "0x01, 0x02, 0x03, 0x0a, 0x0b", since compression will not be used unless error correction is required.

dwNegotiatedDCERate
Specifies the modem-to-modem line speed to be negotiated.
dwNegotiatedDTERate
Specified only to cause Unimodem to change its DTE port speed. Generally this is not needed since modems will make "normal" connections with automatic speed buffering and the port speed will remain locked. However, for modems that support only direct modes, it is possible to cause Unimodem to lower its DTE speed by specifying this value.

The Responses entries contain all of the modem's response codes. Unimodem matches against these entries and uses the binary state structure to determine the meaning of the response.

Verbose or numeric response strings can be used. Specify the verbose or normal response choice in the Init string and verify that the Responses entries match this Init setting. In addition, it is usually necessary to include entries for the following two response strings:

<cr><lf>OK<cr><lf>
<cr><lf>ERROR<cr><lf>

Numeric responses 0 through 8 might also need to be listed in case the modem gets into a numeric response state.

The modem may return these strings after Unimodem's first few initialization commands (before the modem is fully configured).

The response strings can contain the following macros:

Carriage Return | <CR> or <cr>
Line Feed | <LF> or <lf>
Binary | <hxx> or <Hxx> where xx are two hex digits. Example: <h41> = 'A'.
Less-Than escape | <<

See Also

Init INF file entry

Settings

The following registry entries are all subkeys of the Settings INF file entry.

Settings, Blind_Off

Settings, Blind_On

Blind_Off and Blind_On define the AT commands used to set the modem's blind dialing modes.

Blind_Off | Detect dial tone before dialing
Blind_On | Do not detect dial tone before dialing

Format

A single command string.

Sample

HKR, Settings, Blind_Off,, "X4"
HKR, Settings, Blind_On,, "X3"

Note

An INF file entry should not be included if the modem does not support blind dialing. The supported commands must be indicated in the ModemOptions member of the Properties INF file entry.

See Also

ModemOptions in the Properties INF file entry documentation

Settings, CallSetupFailTimer

This setting entry defines the AT command used to set the modem's call fail timer.

Format

A single command string.

Sample

HKR, Settings, CallSetupFailTimer,, "S7=<#>"

Note

If the modem does not have this feature, set the value to 0 in the Properties INF file entry. Do not set this command to S7=<0>.

CallSetupFailTimer should not have a specific value. Instead, it should be set to "<#>". The "#" is a placeholder. Unimodem fills in the actual number sent to the modem based on the CallSetupFailTimeout member of the Properties INF file entry.

See Also

CallSetupFailTimeout in the Properties INF file entry documentation

Settings, CompatibilityFlags

The CompatibilityFlags setting directs Unimodem to lower DTR and then wait 50 ms before closing the communications port.

Format

A single command string.

Sample

HKR, ,CompatibilityFlags, 1, 01, 00, 00, 00

Note

The command is a single bit. The remaining bits are reserved and should be set to 0. This flag is rarely used and currently applies to only a few US Robotics® Sportster® modems. This is supported in NT-based operating systems and Windows Me.

Settings, Compression_On

Settings, Compression_Off

This setting specifies the command strings required to set the modem's compression modes.

Format

A single command string.

Sample

(1)
    HKR, Settings, Compression_On,, "%%C3"
    HKR, Settings, Compression_Off,, "%%C0"
(2)
    HKR, Settings, Compression_On,, "%%C1 S101=35"
    HKR, Settings, Compression_Off,, "%%C0 S101=0"

Note

The default modulation, compression and protocol options set in the Init strings should be set to enable maximum flexibility. If the modem supports compression (enable and disable), it is important to include these settings. If the modem does not support any compression settings, this INF file entry should not be included. The supported commands must be indicated in the ModemOptions member of the Properties INF file entry.

See Also

Init INF file entry and ModemOptions in the Properties INF file entry documentation

Settings, ConfigDelay

This INF file entry specifies the delay between opening the modem's communications port and issuing AT commands. This delay allows the modem sufficient time to power itself up and initialize its firmware state. The delay is expressed in units of milliseconds.

Format

A single command string.

Sample

HKR, ,ConfigDelay, 1, b8, 0b, 00, 00

Note

In the previous example, 0x00000bb8 = 3000 ms, or three seconds.

This setting is generally not needed. It is provided to support power-managed modems that are not always ready to respond within the default two seconds. This setting is used in Windows 2000 and later versions and Windows 95/98/Me versions beginning with Windows 95 OSR2.

Settings, DialPrefix

This entry indicates characters that are appended to dial strings following the Settings, Prefix characters.

Format

A single command string.

Sample

HKR, Settings, DialPrefix,, "D"

See Also

Settings, DialSuffix and Settings, Prefix

Settings, DialSuffix

This entry indicates characters that are appended to dial strings before the Settings, Terminator characters.

Format

A single command string.

Sample

HKR, Settings, DialSuffix,, ";"
HKR, Settings, DialSuffix,, "" \\ NULL modem, see note below

Note

The DialSuffix key should cause the modem to return to command state after dialing, if possible. A null DialSuffix can be used if a dial suffix is not applicable. This null suffix would be used for devices which inadvertently listen for dial tone at each dial command. For voice modems, there is a setting in the VoiceProfile INF file entry that should use a null DialSuffix while dialing in voice mode.

See Also

Settings, DialPrefix and Settings, Terminator

Settings, ErrorControl_On

Settings, ErrorControl_Off

Settings, ErrorControl_Forced

Settings, ErrorControl_Cellular

Settings, ErrorControl_Cellular_Forced

These entries configure the commands that set the modem's error control.

ErrorControl_On | Error control enabled (auto reliable)
ErrorControl_Off | Error control disabled (normal mode, not direct)
ErrorControl_Forced | Error control required to connect (reliable)
ErrorControl_Cellular | Special error control for wireless links. (auto reliable)
ErrorControl_Cellular_Forced | Special error control for wireless links required for connect (reliable)

Format

A single command string.

Samples

(1)
    HKR, Settings, ErrorControl_On,, "\N3"
    HKR, Settings, ErrorControl_Off,, "\N0"
    HKR, Settings, ErrorControl_Forced,, "\N2"
(2)
    HKR, Settings, ErrorControl_On,,"\N3-J1"
    HKR, Settings, ErrorControl_Off,, "\N0"
    HKR, Settings, ErrorControl_Forced,, "\N4-J1"
(3)
    HKR, Settings, ErrorControl_Cellular,, "\N3 )M1 *H2 -K2 -Q1 @M18 :E0"
    HKR, Settings, ErrorControl_Cellular_Forced,, "\N2 )M1 *H2 -K2 -Q1 @M18 :E0"

Note

Error control INF file entries should not be included if the modem does not support any error control settings. The supported commands must be indicated in the ModemOptions member of the Properties INF file entry.

See Also

ModemOptions in the Properties INF file entry documentation

Settings, FlowControl_Off

Settings, FlowControl_Hard

Settings, FlowControl_Soft

These entries identify the command strings that configure the modem's flow control.

Format

A single command string.

Samples

(1)
    HKR, Settings, FlowControl_Off,,    "&K0"
    HKR, Settings, FlowControl_Hard,,    "&K3"
    HKR, Settings, FlowControl_Soft,,    "&K4"
(2)
    HKR, Settings, FlowControl_Off,,    "\Q0"
    HKR, Settings, FlowControl_Hard,,    "\Q3"
    HKR, Settings, FlowControl_Soft,,    "\Q1"

Note

Do not include a flow control INF entry if the modem does not support any FlowControl settings. The supported commands must be indicated in the ModemOptions member of the Properties INF file entry.

See Also

ModemOptions in the Properties INF file entry documentation

Settings, InactivityTimeout

This entry specifies the InactivityTimeout command string. The equation for InactivityTimeout is as follows:

InactivityTimeout * InactivityScale = inactivity timeout in seconds.

Format

A single command string.

Sample

HKR, Settings, InactivityTimeout,, "S30=<#>"

Note

InactivityTimeout should not have a specific value. Instead, it should be set to "<#>". The "#" is a placeholder. Unimodem fills in the actual number sent to the modem based on the InactivityTimeout member of the Properties INF file entry.

See Also

InactivityTimeout in the Properties INF file entry documentation, InactivityScale

Settings, Modulation_CCITT

Settings, Modulation_Bell

Settings, Modulation_CCITT_V23

These entries specify the command strings required to set the modems modulation modes. The available modulation modes are as follows:

Modulation_CCITT | CCITT modulations for 300 & 1200 bps
Modulation_Bell | Bell modulations for 300 & 1200 bps
Modulation_CCITT_V23 | CCITT modulations for V23

Format

A single command string.

Sample

(1)
    HKR, Settings, Modulation_CCITT,, "B0 "
    HKR, Settings, Modulation_Bell,, "B1 "
(2)
    HKR, Settings, Modulation_CCITT,, "B0B15"
    HKR, Settings, Modulation_Bell,, "B1B16"

Note

Do not include these entries if the modem does not support any Modulation settings. The supported commands must be indicated in the ModemOptions member of the Properties INF file entry.

See Also

ModemOptions in the Properties INF file entry documentation

Settings, Prefix

This entry specifies the command string that indicates which characters will be prefixed to every Settings command sent to the modem.

Format

A single command string.

Sample

HKR, Settings, Prefix,, "AT"

Note

The initialization commands should include appropriate Prefix (generally AT) and Terminator (generally <cr>) characters. Do not exceed the maximum allowable length for individual command strings.

See Also

Settings, Terminator

Settings, Pulse

Settings, Tone

The command strings in these entries specify the characters that are required to indicate Pulse or Tone dialing. These characters are inserted into the dialing string immediately following the Settings, DialPrefix characters.

Format

A single command string.

Sample

HKR, Settings, Pulse,, "P"
HKR, Settings, Tone,, "T"

Note

If the modem does not support both tone and pulse dialing, the corresponding INF file entry should not be included. The supported commands must be indicated in the ModemOptions member of the Properties INF file entry.

See Also

Settings, DialPrefix INF file entry and ModemOptions in the Properties INF file entry documentation

Settings, SpeakerMode_Off

Settings, SpeakerMode_Dial

Settings, SpeakerMode_On

Settings, SpeakerMode_Setup

These entries specify the command strings used to set the modem's speaker mode.

Format

A single command string.

Sample

HKR, Settings, SpeakerMode_Off,, "M0"
HKR, Settings, SpeakerMode_Dial,, "M1"
HKR, Settings, SpeakerMode_On,, "M2"
HKR, Settings, SpeakerMode_Setup,, "M3"

Note

If the modem does not support any SpeakerMode settings, do not include the corresponding INF file entry. The supported commands must be indicated in the SpeakerMode member of the Properties INF file entry .

See Also

SpeakerMode in the Properties INF file entry documentation

Settings, SpeakerVolume_Low

Settings, SpeakerVolume_Med

Settings, SpeakerVolume_High

These entries specify the command strings used to set the modem's speaker volume.

Format

A single command string.

Samples

(1)
    HKR, Settings, SpeakerVolume_Low,,    "L1"
    HKR, Settings, SpeakerVolume_Med,,    "L2"
    HKR, Settings, SpeakerVolume_High,,    "L3"
(2)
    HKR, Settings, SpeakerVolume_Low,,    "L0"
    HKR, Settings, SpeakerVolume_Med,,    "L2"
    HKR, Settings, SpeakerVolume_High,,    "L3"

Note

If the modem does not support any SpeakerVolume settings, do not include the corresponding INF file entry. The supported commands must be indicated in the SpeakerVolume member of the Properties INF file entry.

See Also

SpeakerVolume in the Properties INF file entry documentation

Settings, SpeedNegotiation_Off

Settings, SpeedNegotiation_On

These entries specify the command strings used to set the modem's speed negotiation modes.

SpeedNegotiation_Off | Connect only at DTE speed, not lower.
SpeedNegotiation_On | Use lower DCE speed to connect, if necessary.

Format

A single command string.

Sample

(1)
    HKR, Settings, SpeedNegotiation_Off,, "N0"
    HKR, Settings, SpeedNegotiation_On,, "N1"
(2)
    HKR, Settings, SpeedNegotiation_Off,, "&A0"
    HKR, Settings, SpeedNegotiation_On,, "&A1"

Note

Be sure to include these entries if the modem supports SpeedNegotiation.

If the modem does not support a SpeedNegotiation setting, do not include the corresponding INF file entry. The supported commands must be indicated in the ModemOptions member of the Properties INF file entry.

See Also

ModemOptions in the Properties INF file entry documentation

Settings, Terminator

This entry specifies the command string indicating which characters will be appended to every Settings command sent to the modem.

Format

A single command string.

Sample

HKR, Settings, Terminator,, "<cr>"

Note

The initialization commands should include appropriate Prefix (generally AT) and Terminator (generally <cr>) characters. Do not exceed the maximum allowable length for individual command strings.

See Also

Settings, Prefix

Data Modem INF File Entries for Windows 2000 and Later Versions

This section contains descriptions of data modem INF file entries that are supported by Windows 2000 and later versions of the operating system.

The following entries are also supported on Windows Me.

CurrentCountry

This setting defines the country/region where the modem is currently located. The modem control panel updates this registry key when the user changes the country/region selection from a drop-down dialog in the advanced tab. This entry is provided for driver-based modems and should only be used when required by software.

The DWORD specified by this entry is the integer value assigned to the country/region. The country/region list and values are located in the TAPI country/region code list located at:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Telephony\Courntry List\CountryCodeValue

Where CountryCodeValue is a sub-key named with the integer value assigned to the specified country/region. The key contains values that include the country/region name and so forth.

Format

One country/region code DWORD.

Sample

HKR,, CurrentCountry, 0x10001, 101

Note

This entry is required to enable the drop-down dialog. The initial value is the default country/region at the time when the modem is installed. This initial value must also be listed in the available country/region list.

For information on creating the available country/region list, see CountryX.

See Also

CountryX

CountryX

The country/region select feature for driver-based modems requires a country/region list. This is the list of countries/regions that the modem supports. This list will be presented to the user in the drop-down dialog box. At least one country/region must be listed. These entries must be numbered with the numbering beginning at zero.

The value in an entry is a DWORD. The DWORD is the integer value assigned to the specified country/region. The country/region list and values are located in the TAPI country/region code list located at:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Telephony\Courntry List\CountryCodeValue

where CountryCodeValue is a sub-key named with the integer value assigned to the specified country/region. The key contains values that include the country/region name and so forth.

A value of zero is used to make the modem setting follow the TAPI country/region setting. It is useful to follow the TAPI setting if the modem is capable of adapting to any country/region specified by TAPI while a user modifies the modem setting.

"Current TAPI Country Setting" indicates the zero value in the drop-down dialog. If the CurrentCountry INF file entry is set to zero, the modem driver should set the modem's country/region setting to the value currently defined by TAPI.

Format

One country/region code DWORD.

Sample

HKR, Countries, Country0, 0x10001, 101  ; a country/region (Anguilla)
HKR, Countries, Country1, 0x10001, 102  ; another country/region (Antigua)
HKR, Countries, Country2, 0x10001, 103  ; another country/region (Bahamas)

Note

For information about creating the default/currently selected country/region, see CurrentCountry.

MaximumPortSpeed

This entry specifies the maximum DTE port speed for the modem.

Format

A single command of type DWORD.

Sample

HKR,,MaximumPortSpeed,    1, 00, c2, 01, 00

Note

Supported in Windows Me and in Windows 2000 and later versions of the operating system.

PowerDelay

After the modem has been powered, the modem driver will delay the number of milliseconds specified in PowerDelay before sending data to the serial driver.

Format

A single command of type DWORD.

Sample

HKR,,PowerDelay,    0x10001, 1500

Note

In the preceding example, the delay is set to 1500 milliseconds.

This entry should only be used for PC card modems.

See Also

ConfigDelay

ConfigDelay

When a application opens the modem, the modem driver will raise DTR and wait the number of milliseconds specified by ConfigDelay before completing the open request to the application.

Format

A single command of type DWORD.

Sample

HKR,,ConfigDelay,    0x10001, 1500

Note

In the preceding example, the delay is set to 1500 milliseconds.

This entry should only be used for PC card modems.

See Also

PowerDelay

Built on Wednesday, July 11, 2001


Fax Modem INF File Entries

This section describes the modem INF file entries that support fax modem features.

ExitCommand

This entry identifies the command string that is issued to the modem after hang-up, and just before releasing the port.

Format

Single command string.

Sample

HKR, Fax, ExitCommand,,

Note

The default is the empty string.

PreAnswerCommand

The PreAnswerCommand entry identifies the modem command string that is issued to the modem just before issuing the ATA command.

Format

Single command string.

Sample

HRK, Fax, PreAnswerCommand,,

Note

Microsoft Fax issues the Setup command, and the command to go to the appropriate Fax class (Class1 or 2) prior to issuing the PreAnswerCommand.

The default is the empty string.

PreDialCommand

The PreDialCommand entry specifies the modem command string that is issued to the modem just before issuing the ATD command.

Format

Single command string.

Sample

HKR, Fax, PreDialCommand,,

Note

Microsoft Fax issues the setup command and the command to go to the appropriate fax class (Class1 or 2) prior to issuing the PreDialCommand.

The default is the empty string.

ResetCommand

The ResetCommand entry identifies the command string sent before every send and before every answer.

Format

Single command string.

Sample

HKR, Fax, ResetCommand,,    "AT&FS0=0E0V1Q0"

Note

In Windows 98, this string is sent before every send operation and before every answer operation. In Windows 2000 and later versions and Windows Me, this string is not sent before an answer operation if the fax is configured to be in auto-answer mode (in which case Unimodem has already set up the modem). The command should reset the modem to the following state:

  • Load factory defaults
  • Disable auto-answer
  • Echo OFF
  • Verbose ON
  • Quiet OFF

In Windows 98/Me and Windows 2000 and later versions , the default ResetCommand string is "AT&FS0=0E0V1Q0". If that fails, Unimodem tries "AT&FS0=0E0". If that fails, it tries "AT&FE0". If all these attempts fail, modem initialization fails. If a ResetCommand entry is placed in the modem's INF file, it will try to use the latter string.

A null string ("") is a valid entry. In this case, the fax driver will not issue a reset command.

SetupCommand

This entry identifies the AT command sent before every send operation and before every answer operation (after the reset command).

Format

Single command string.

Sample

HKR, Fax, SetupCommand,, "ATS7=255&D3&K4"

Note

The command should configure the modem as follows:

  • Max dial-tone timeout
  • Tie DTR drop to reset
  • Xon/Xoff flow control

Windows 98/Me and Windows NT 4.0 and earlier versions. Fax software requires software (Xon/Xoff) flow control.

The software uses this algorithm to determine the flow control command

  1. Try "AT&K4" and wait for the response.
  2. Try "AT\Q1" (even if the modem returned OK to AT&K4). If that works, try "ATJ0".
  3. If no commands work, try "AT&K5".

Using this algorithm results in the selection of one of the following flow control commands: "AT&K4", "AT&K4\Q1", "AT&K4\Q1\J0", "AT\Q1", "AT\Q1\J0", or "AT&K5".

This algorithm works in most cases. Two known exceptions are US Robotics® and certain Hayes® modems. These are special cases in the fax driver but could have also been addressed in an INF file.

EnableV17Recv

This entry identifies the command that disables the use of V.17 during a FAX call.

Format

Single command string.

Sample

HRK, Fax, EnableV17Recv,,

Note

If this entry is set to "0", it disables the use of V.17 (14.4 Kbps, short train) when receiving a fax. If this entry is set to "1", the V.17 capability is not disabled when receiving a fax. The default setting is "1".

EnableV17Send

This entry identifies the command that enables the use of V.17 during a FAX call.

Format

Single command string.

Sample

HKR, Fax, EnableV17Send,,

Note

If this entry is set to "0", it disables the use of V.17 (14.4 Kbps, short train) when sending a fax. If this entry is set to "1", the V.17 capability is not disabled when sending. The default setting is "1".

FixModemClass

This entry specifies the preferred fax class.

Format

Single command string.

Sample

HKR, Fax, FixModemClass,,

Note

The default setting for this entry is "1". Some modems claim to support Class1 but do not support it correctly. In such cases, specify a value of "2" for this entry.

FixSerialSpeed

This entry specifies the DTE-DCE baud rate to be used when the modem is in Class1 or Class2 mode.

Format

Single command string.

Sample

HKR, Fax, FixSerialSpeed,,

Note

The default value for this entry is "19200".

HighestSendSpeed

This entry specifies the highest over-the-wire speed when sending a fax, in bits per second.

Format

Single command string.

Sample

HKR, Fax, HighestSendSpeed,,

Note

A value of "0" for this entry indicates the highest available speed. The default value is "0". The T.30 protocol engine uses this setting when creating the DIS frame.

LowestSendSpeed

This entry specifies the lowest over-the-wire speed that is acceptable when sending a fax, in bits per second.

Format

Single command string.

Sample

HKR, Fax, LowestSendSpeed,,

Note

A value of "0" indicates that negotiated settings should be used. The default value is "0". The T.30 protocol engine uses this setting when determining if transmission should continue at a lower speed after transmission errors (after receiving FTT, RTP, and so forth.).

Additional Fax Entries, Including Adaptive Answering

The fax settings have been set up as a hierarchical Fax Registry tree with INF file entries defining the modem state. The modem class (Class1, Class2)and the current modem operation (Send, Receive, AdaptiveAnswer) define a fax modem state. This allows the specification of Fax Registry values using the same name at different locations of the fax tree. T.30 will use the registry value at the tree location corresponding to the current fax-modem state. For a complete overview of modem INF files and additional information about the fax entry hierarchy, see Overview of Modem INF Files.

HardwareFlowControl

This entry specifies the hardware flow control.

Format

Single command string.

Sample

Fax, HardwareFlowControl,, "1"

Note

If this entry is set to "1", DTE will be configured to use the hardware flow control. The default setting is "0".

SerialSpeedInit

This entry specifies the initial DTE-DCE baud rate.

Format

Single command string.

Sample

Fax, SerialSpeedInit,, "57600"

Note

The default value for this entry is "19200".

AnswerCommand

The AnswerCommand entry identifies commands that are sent to the modem to configure it for adaptive answer and to answer a call.

Format

One or more command strings.

Sample

HKR, Fax\Class1\AdaptiveAnswer\AnswerCommand, 1,, "ATS7=60S19=0M1&M4"
HKR, Fax\Class1\AdaptiveAnswer\AnswerCommand, 2,, "ATA"

ModemResponseFaxDetect

This entry identifies the modem response that indicates the incoming call is a FAX call.

Format

Single command string.

Sample

Fax\Class1\AdaptiveAnswer, ModemResponseFaxDetect,, "FAX"

ModemResponseDataDetect

This entry identifies the modem response that indicates the incoming call is a DATA call.

Format

Single command string.

Sample

Fax\Class1\AdaptiveAnswer, ModemResponseDataDetect,, "DATA"

SerialSpeedFaxDetect

This is an optional entry that specifies a DTE-DCE speed. If this entry is present in the INF file, the system is required to switch to the specified DTE-DCE speed immediately after an incoming call has been identified as a FAX call.

Format

Single command string.

Sample

Fax\Class1\AdaptiveAnswer, SerialSpeedFaxDetect,, "19200"

Note

By default this entry is not defined and the host does not change DTE-DCE speed.

SerialSpeedDataDetect

This is an optional entry that specifies a DTE-DCE speed. If this entry is present in the INF file, the system is required to switch to the specified DTE-DCE speed immediately after an incoming call has been identified as a DATA call.

Format

Single command string.

Sample

Fax\Class1\AdaptiveAnswer, SerialSpeedDataDetect,, "28800"

Note

By default this entry is not specified and the host does not change DTE-DCE speed.

HostCommandFaxDetect

This is an optional entry that requires the host to connect to a remote modem after an incoming call has been identified as a FAX call.

Format

Single command string.

Sample

Fax\Class1\AdaptiveAnswer, HostCommandFaxDetect,,

Note

By default the entry is not specified and the host makes no additional connections.

HostCommandDataDetect

This is an optional entry that requires the host to connect to a remote modem after an incoming call has been identified as a DATA call.

Format

Single command string.

Sample

Fax\Class1\AdaptiveAnswer, HostCommandDataDetect,, "ATO"

Note

By default the entry is not specified and the host makes no additional connections.

ModemResponseFaxConnect

This entry defines the response string that a modem sends to indicate that the modem is connected to a remote modem on a FAX call.

Format

Single command string.

Sample

Fax\Class1\AdaptiveAnswer, ModemResponseFaxConnect,, "CONNECT"

ModemResponseDataConnect

This entry defines the response string that a modem sends to indicate that the modem is connected to a remote modem on a DATA call.

Format

Single command string.

Sample

Fax\Class1\AdaptiveAnswer, ModemResponseDataConnect,, "CONNECT"

Class 1-Specific Entries

Cl1FCS

This entry specifies the FCS checking behavior of the Class1 driver.

Format

Single command string.

Sample

HKR, Fax, Cl1FCS,,

Note

The following values are valid for this entry:

0 | Check (default and ONLY value for Windows 95 4.0.0.950)
1 | Do not check – assume there is no FCS
2 | Do not check – assume there is an FCS (default for Windows 95 4.0.0.951 and later)

Due to incompatibilities between Windows 95 version 4.0.0.950 and the software of several modem manufactures, the "0" option is explicitly required to properly transfer binary data. This option is not required for any other version of Windows 95 or for other Windows-based operating system.

Class 2-Specific Entries

The Microsoft Fax Class2 driver uses an internal table to identify modem-specific behavior. However, the table entries can be overridden by specifying the corresponding entries in the modem's INF file.

Cl2DC2Char

This entry defines the decimal value for the character that is sent to the modem after an AT+FDR command is issued and after receipt of the modem's CONNECT response.

Format

Single command string.

Sample

HKR, Fax, Cl2DC2Char,,

Note

The default value for this entry is 82 decimal (Ctrl-R).

Cl2lsEx

This entry specifies the command string to suppress the "AT+FDIS?", "AT+FDIS=.xxx", and "AT+FPTS=xxx"strings.

Format

Single command string.

Sample

HKR, Fax, Cl2lsEx,,

Note

The command expects a non-standard FPTS response: FPTS:1 indicates a good page and FPTS:1,2,0,0 indicates a bad page.

The value for this entry is modem-specific, but it is generally "0".

Cl2lsSr

This entry specifies the command string to suppress "AT+FCQ=0".

Format

Single command string.

Sample

HKR, Fax, Cl2lsSr,,

Note

If this entry is non-zero, the driver will not issue "AT+FCQ=0". Some modems will not work if they receive this command. The default value for this entry is "0".

Cl2RecvBOR

This entry specifies a value of "AT+FBOR=xxx" for receive operations.

Format

Single command string.

Sample

HKR, Fax, Cl2RecvBOR,,

Note

The default value is modem-specific, but it is typically "1".

Cl2SendBOR

This entry specifies value of "AT+FBOR=xxx" for send operations.

Format

Single command string.

Sample

HKR, Fax, Cl2SendBOR,,

Note

The default value is modem-specific, but it is typically "0".

Cl2SkipCtrlQ

This entry indicates that the modem will not wait for a Ctrl-Q character before sending page data.

Format

Single command string.

Sample

HKR, Fax, Cl2SkipCtrlQ,,

Note

If this entry is non-zero, the driver will not wait to receive a Ctrl-Q character before sending page data. The default value for this entry is "0".

Cl2SWBOR

If this entry is non-zero, and if Cl2RecvBOR equals 1, "AT+FBOR=0" is issued and the received data is bit-reversed.

Format

Single command string.

Sample

HKR, Fax, Cl2SWBOR,,

Note

Set this entry to "1" for modems that do not implement the "AT+FBOR" command. The default value for this entry is "0".


Voice Modem INF File Entries

This section describes the modem INF file entries that support voice modem features.

Note Unless otherwise specified, all the modem INF file entries that are supported by Windows 2000, and all the modem INF file entries that are supported by Windows 98, are also supported by Windows Me.

AbortPlay

This entry identifies the command issued to the modem to stop playing the audio data immediately.

Format

One or more command strings.

Sample

HKR,, AbortPlay,,            "<h10><h18>"

Note

This command is issued after StartPlay, and before StopPlay.

This command is only called for modems that use a serial wave device. It is not used for modems that use a wave wrapper.

See Also

StartPlay, StopPlay, TerminatePlay entries

BaudRate

This entry is used in the serial wave device INF file. It specifies the port speed.

Format

A single command of type DWORD.

Sample

HKR,Config,BaudRate,    1, 00, c2, 01, 00

Note

The preceding example sets the port speed to 115200 bps.

BaudRate (NT Wavedriver)

This entry provides voice functionality for Windows 2000 and later versions of the operating system. It specifies port speed.

Format

A single command of type DWORD.

Sample

HKR, WaveDriver,  BaudRate       ,1, 00, c2, 01, 00

Note

The preceding example sets the port speed to 115200 bps.

This command is placed only in the modem INF file . This command is not placed in a serial wave driver INF because Windows 2000 and later versions of the operating system do not use a serial wave driver INF file.

In addition, the following entries collectively are found in a modem INF file which is enabled for voice functionality in Windows 2000 and later versions of the operating system. These entries are compatible with Windows 95/98 and Windows NT 4.0 and their presence in a modem INF file will have no adverse affects when used with those Windows versions. .

XformID (NT Wavedriver)

BaudRate (NT Wavedriver)

XformModule (NT Wavedriver)

WaveHardwareID (NT Wavedriver)

WaveDevices (NT Wavedriver)

The VoiceProfile bit (0x02000000) should also be enabled for Windows 2000 and later versions of the operating system.

VoiceBaudRate

This entry specifies port speed prior to switching into voice mode with VoiceAnswer or VoiceDialNumberSetup. The BaudRate setting is used at the beginning of serial wave operation.

Format

A single command of type DWORD.

Sample

HKR,, VoiceBaudRate,  1, 00, c2, 01, 00

Note

The preceding example sets port speed to 115200 bps.

This command is placed in the modem INF file only. Do not place it in a serial wave driver INF file.

Generally the VoiceBaudRate and BaudRate values should be the same.

See Also

VoiceAnswer, VoiceDialNumberSetup and BaudRate INF file entry descriptions.

CallerIDPrivate

CallerIDOutSide

These entries identify the characters that the modem returns when it reports that Caller ID information was not sent. The information that is not sent can been blocked (private) or out of the area.

Format

Single line — can be one or more characters.

Sample

HKR,, CallerIDPrivate,,"P"
HKR,, CallerIDOutSide,,"O"

Note

This entry is case sensitive.

See Also

EnableCallerID INF file entry

EnableCallerID

This entry defines the AT command used to enable Caller ID reporting.

Format

One or more command strings.

Sample

HKR, EnableCallerID, 1,, "at#cid=1<cr>"

Note

If the modem does not have the ability to report Caller ID, this entry should be omitted from the modem INF file. The VoiceProfile INF file entry can also indicate that the modem supports Caller ID. If Caller ID is enabled, make sure that Caller ID responses are in the Responses INF File entries.

See Also

VoiceProfile INF file entry and Responses INF File entry

EnableDistinctiveRing

This entry identifies the AT command that enables distinctive ring reporting. This feature is available with Windows 95/98/Me. It is not supported in Windows NT 4.0 and later versions of the operating system .

Format

One or more command string.

Sample

HKR, EnableDistinctiveRing, 1,, "at-sdr=7<cr>"

Note

If the modem does not have the ability to report distinctive rings, this entry can be omitted from the modem INF file. Distinctive ringing can be enabled or disabled from the modem's property page. The VoiceProfile INF file entry can also indicate that distinctive ringing is supported, and what type of distinctive ringing is supported. If distinctive ringing is enabled, make sure that the correct distinctive ringing responses are listed in the Responses INF File entries.

See Also

VoiceProfile INF file entry and the Responses INF File entry

Enumerator

Every voice modem should have this entry. It creates the wave device for the voice modem.

Sample

HKR,,Enumerator,,serwave.vxd

Note

This entry should never change. It is required for all voice modems.

ForwardDelay

This entry specifies the delay in milliseconds between dialing the call-forwarding cancel code and hanging up. This entry also specifies the delay between dialing the call-forwarding dial string and hanging up.

Format

One or more command strings.

Sample

HKR,, ForwardDelay, 1,88,13

GenerateDigit

This entry specifies the AT command used to generate a DTMF digit during a voice call.

Format

One or more command strings.

Sample

HKR, GenerateDigit,  1,, "at#vts=<Digit><cr>"

Note

This command will only be issued during an active voice call. This entry can be omitted if the modem cannot generate DTMF digits during a voice call.

HandsetCloseDelay

This entry specifies the amount of time, in seconds, that the CloseHandset command will be issued after a call to the Multimedia function waveClose.

Format

One or more command strings.

Sample

HKR,, HandsetCloseDelay,         1, 1e,00,00,00

Note

If waveOpen is called before this delay expires, the OpenHandset command will not be reissued. This entry is used to work around a feature in some modems that requires the handset to be on the hook when the OpenHandset command is issued. Using this entry will keep the handset wave device open during the interval that occurs between playing audio files through the handset. This avoids a requirement for the handset to be put back on hook.

See Also

OpenHandset and CloseHandset INF file entries

LineSetPlayFormat

LineSetRecordFormat

HandsetSetPlayFormat

HandsetSetRecordFormat

These entries define commands that direct the modem to set the record/play format.

Format

One or more command strings.

Sample

HKR, LineSetPlayFormat,        1,, "at#vls=0<cr>"

HKR, LineSetRecordFormat,      1,, "None"
HKR, LineSetRecordFormat,      2,, "NoResponse"

HKR, HandsetSetRecordFormat,   1,,"at#vsr=7200<cr>"
HKR, HandsetSetRecordFormat,   2,,"at#vbs=4<cr>"

HKR, HandsetSetPlayFormat,     1,,"at#vsr=7200<cr>"
HKR, HandsetSetPlayFormat,     2,,"at#vbs=4<cr>"

Note

If the modem is using the serial wave driver, and the baud rate needs to be set, the baud rate command should be the last command listed.

LowerMid

LowerWaveInPid

LowerWaveOutPid

These entries appear in the wave wrapper INF file. These entries identify the audio wave driver's Manufacturer ID and Product ID for the wave wrapper.

Format

Single WORD values.

Sample

HKR,Config,LowerMid,1,        5c, 00
HKR,Config,LowerWaveInPid,1,  81, 00
HKR,Config,LowerWaveOutPid,1, 82, 00

Note

These values identify the wave driver that is being "wrapped" by the wave wrapper.

OpenHandset

CloseHandset

These entries define the AT commands used to access the handset.

OpenHandset puts the modem into a mode that will allow playing audio (wave files) to the handset. CloseHandset resets the modem to class 0.

Format

One or more command strings.

Sample

HKR, OpenHandset, 1,, "at#cls=8<cr>"
HKR, OpenHandset, 2,, "at#vls=1<cr>"
HKR, CloseHandset, 1,, "at#cls=0<cr>"

Note

These commands are used to play audio through the handset while there is no active call.

SpeakerPhoneEnable

SpeakerPhoneDisable

These entries define the AT commands used to enable and disable the speakerphone.

Format

One or more command strings.

Sample

HKR, SpeakerPhoneEnable,    1,, "at#vls=6<cr>"
HKR, SpeakerPhoneDisable, 1,, "at#vls=6<cr>"
HKR, SpeakerPhoneDisable, 2,, "at#spk=0,15,,<cr>"
HKR, SpeakerPhoneDisable, 3,, "at#vls=0<cr>"

Note

These commands are issued after a call has been connected in voice mode. The SpeakerPhoneEnable command is sent when the TAPI function phoneSetHookSwitchMode is called with the bits set for PHONESETHOOKSWITCHDEV_SPEAKERPHONE and PHONESETHOOKSWITCHMODE_MICSPEAKER or PHONESETHOOKSWITCHMODE_SPEAKER.

SpeakerPhoneMute

SpeakerPhoneUnMute

These entries define the AT commands that mute and unmute the speakerphone.

Format

One or more command strings.

Sample

HKR, SpeakerPhoneMute,    1,, "at#spk=0,,,<cr>"
HKR, SpeakerPhoneUnMute,    1,, "at#spk=1,,,<cr>"

Note

These commands are issued after a call has been connected in voice mode and speakerphone has been enabled. These commands are sent only after the speaker phone has been enabled and the TAPI function phoneSetHookSwitch is called with the to change the mute setting.

SpeakerPhoneSetVolumeGain

This entry identifies the AT commands used to set the speakerphone volume and gain.

Format

One or more command strings.

Samples

(1)
    HKR, SpeakerPhoneSetVolumeGain,  1,, "at#spk=,<Vol>,<Gain><cr>"
(2)
    HKR, SpeakerPhoneSetVolumeGain, 1,,"at#vgs=<Vol><cr>"
    HKR, SpeakerPhoneSetVolumeGain, 2,,"at#vgm=<Gain><cr>"

Note

These commands are issued after a call has been connected in voice mode and the speakerphone has been enabled.

The <Vol> macro represents the volume to be set and the <Gain> macro represents the gain to be set based on the SpeakerPhoneSpecs and the volume passed down from TAPI (for example, from the TAPI function phoneSetVolume). Unimodem fills in the correct values for the <Vol> and <Gain> placeholders.

See Also

SpeakerPhoneSpecs INF file entry.

SpeakerPhoneSpecs

This entry defines the supported range of values for speakerphone volume and gain.

Format

One or more command strings each of four DWORDs.

Sample

HKR,, SpeakerPhoneSpecs,1, 00,00,00,00, 0f,00,00,00, 03,00,00,00, 00,00,00,00

Note

The value corresponds to the following C structure:

typedef struct SPEAKERPHONE_SPEC {
    DWORD    SpeakerPhoneVolMax;
    DWORD    SpeakerPhoneVolMin;
    DWORD    SpeakerPhoneGainMax;
    DWORD    SpeakerPhoneGainMin;
};

The values used for the maximum volume and gain can be greater or less than the minimum. For example, a microphone's attenuation setting can have a maximum value that is numerically less that the minimum. The speakerphone volume and gain are set through the TAPI functions phoneSetVolume and phoneSetGain.

StartPlay

This entry identifies the AT commands that are issued to the modem to start playing audio (wave files) through the modem. These commands are issued during an active call to play to the line and are issued when there is no active call to play to the handset.

Format

One or more command strings.

Sample

HKR, StartPlay,  1,, "at#vtx<cr>"

See Also

VoiceProfile

StartRecord

This entry identifies the AT commands that are issued to the modem to start recording audio (wave files) from the modem. These commands are issued during an active call to record from the line and are issued when there is no active call to record from the handset.

Format

One or more command strings.

Samples

(1)
    HKR, StartRecord, 1,, "at#vrx<cr>"

See Also

VoiceProfile

StopPlay

For modems that use the serial wave device, this command is made after AbortPlay or TerminatePlay. It can be used to reset the modem's baud rate, if it was changed for playing. For modems that use the wave wrapper wave device, this command is called after StartPlay, and should issue all necessary modem commands to stop playing the wave file.

Format

One or more command strings.

Sample

HKR, StopPlay,                1,, "None"
HKR, StopPlay,                2,, "NoResponse"

See Also

VoiceProfile

StopRecord

For modems that use the serial wave device, this command is called after TerminateRecord. It can be used to reset the modem's baud rate, if it was changed for playing. For modems that use the wave wrapper wave device, this command is called after StartRecord, and should issue all necessary modem commands to stop playing the wave file.

Format

One or more command strings.

Sample

HKR, StopRecord,                1,, "None"
HKR, StopRecord,                2,, "NoResponse"

See Also

VoiceProfile

TerminatePlay

The TerminatePlay entry identifies the command issued to the modem to empty (finish playing) the local buffer and stop playing the audio data.

Format

Single command string.

Sample

HKR,, TerminatePlay,,        "<h10><h03>"

Note

This command is issued after StartPlay, and before StopPlay. This command is called only for modems that use the serial wave device. It is not used for modems that use the wave wrapper.

See Also

StartPlay, StopPlay, AbortPlay registry entries

TerminateRecord

This entry identifies the command issued to the modem to finish recording the local buffer and stop recording the audio data.

Format

Single command string.

Samples

(1)
    HKR,, TerminateRecord,,     "<h10>E<cr>"

Note

This command is issued after StartRecord, and before StopRecord. This command is called only for modems that use the serial wave device. It is not used for modems that use the wave wrapper.

See Also

StartRecord and StopRecord registry entries

VariableTerminator

This entry identifies the characters that terminate a Caller ID or distinctive ring response from modem.

Format

Single line of one or more characters.

Sample

HKR,, VariableTerminator,,<cr><lf>

Note

A variable length response is composed of a fixed response (which is listed in the Responses registry entries) followed by a variable-length terminator string. In order for the response to be interpreted as a variable-length response, the high bit of the first byte of the Responses binary data INF file entry must be set.

See Also

Responses INF file entry

VoiceAnswer

This entry identifies the AT commands sent to the modem to answer a call in voice mode.

Format

One or more command strings.

Sample

HKR, VoiceAnswer,               1,, "at#cls=8<cr>"
HKR, VoiceAnswer,               2,, "at#vls=0<cr>"
HKR, VoiceAnswer,               3,, "at#vbt=1<cr>"
HKR, VoiceAnswer,               4,, "ata<cr>"

Note

Usually, the following actions are implemented in VoiceAnswer:

  • Place the modem into voice mode.
  • Set the DTMF tone generation duration.
  • Make sure speakerphone is on the hook.
  • Answer the modem.

VoiceDialNumberSetup

This entry identities the AT commands that are used to place a call in voice mode.

Format

One or more command strings.

Sample

HKR, VoiceDialNumberSetup,               1,, "at#cls=8<cr>"
HKR, VoiceDialNumberSetup,               2,, "at#vls=0<cr>"
HKR, VoiceDialNumberSetup,               3,, "at#vrn=0<cr>"
HKR, VoiceDialNumberSetup,               4,, "at#vbt=1<cr>"

Note

Usually, the following actions are implemented in VoiceDialNumberSetup:

  • Place the modem into voice mode.
  • Set the DTMF tone-generation duration.
  • Make sure speakerphone is on the hook.
  • Set the modem to connect immediately after dialing. However, if the modem cannot detect a busy line while in voice mode (or in speakerphone mode while in voice mode), the modem should not be set to connect immediately, so that the modem has a chance to report a busy line before it is connected.

VoiceMixerMid

VoiceMixerPid

VoiceMixerLineID

These entries are used to identify the mixer control used to control the speakerphone volume. These entries are optional. They are used if the speakerphone volume is controlled through a multimedia mixer device.

Format

One WORD value for Mid and Pid. One DWORD value for LineID.

Sample

HKR,, VoiceMixerMid,        1,02,00
HKR,, VoiceMixerPid,        1,99,01
HKR,, VoiceMixerLineID,    1,00,00,05,00

Note

VoiceMixerMid is the Manufacturer ID (MID) of the mixer device.

VoiceMixerPid is the Product ID (PID) of the mixer device.

VoiceMixerLineID is the line ID of the volume control.

When the TAPI line is initialized, Unimodem looks for a volume control on this mixer line. If the volume is set to the minimum level, Unimodem will move the volume to the maximum.

When the speakerphone is enabled, the control is not muted. When the speakerphone is disabled, the control is muted. When the TAPI line is closed, this control is not muted.

Unimodem does not use the mixer at any other time. It is not used to control the speakerphone volume. Speakerphone volume is set through the SpeakerPhoneSetVolumeGain command.

Setting Wave Driver MID, PID, and Mixer IDs

To set the wave driver MID, PID, and mixer IDs

  1. Install and run MixApp.

    MIXAPP is a sample application included in the Platform SDK. For MIXAPP to work correctly, the sound card driver must be installed. Also, make sure the mixer is listed in the title bar.

    1. Run the Mixer Driver command from the File menu of the MIXAPP application to display the Mid (Manufacturer ID) and Pid (Product ID). Convert these values to the hexadecimal format.
    2. In the MIXAPP main window, find the output (speakers, Wave out) listing for the mixer control that is the modem volume and note its line ID.
  2. Convert the ID formats and insert them into the main modem INF file.

    You will need to edit three entries in the INF file.

Editing the VoiceMixerMid Item

The general format of a VoiceMixerMid entry in a modem INF file is:

HKR,, VoiceMixerMid, 1, xx, yy

where yy is the HIGH 2 digits of the hexadecimal MID, and xx is the LOW 2 digits of the hexadecimal MID.

For example, if MID = 144, the hexadecimal format of that MID is 0x0090, so xx = 90 and yy = 00. The INF file entry would be coded as:

HKR,, VoiceMixerMid, 1, 90, 00

Editing the VoiceMixerPid Item

The general format of a VoiceMixerpid item in a modem INF file is:

HKR,, VoiceMixerPid, 1, xx, yy

where xx and yy have the same meaning as in the VoiceMixerMid item. Use the same procedure to edit the VoiceMixerPid as previously described for editing the VoiceMixerMid.

Editing the VoiceMixerLineID Entry

The general format of a VoiceMixerLineID entry in a modem INF file is:

HKR,, VoiceMixerLineID, 1, ww, xx, yy, zz

where ww, xx, yy, and zz express the hexadecimal value of the mixer line ID in hexadecimal format, LSB to MSB. For example, if the mixer line ID = 0x00040000 then ww = 00, xx = 00, yy = 04, and zz = 00. The INF file entry would be coded as:

HKR,, VoiceMixerLineID, 1, 00, 00, 04, 00

See Also

SpeakerPhoneSetVolumeGain

VoiceProfile

Unimodem uses this entry to determine the voice modem capabilities of a modem.

Format

A single command string of type DWORD.

Samples

(1)
    HKR,, VoiceProfile,    1 , 07,a1,02,00
(2)
    HKR,, VoiceProfile,    1, 27,03,00,00
(3)
    HKR,, VoiceProfile,    1, 25,12,00,00

Note

The ProCalc tool should be used to create the voice profile entry. For more information about ProCalc, see Creating Voice Modem INF Entries with ProCalc.

The bits in the VoiceProfile DWORD are set as follows:

Identifies a voice modem (should always be set). | 0x00000001
Modem has some element of a TAPI phone device. For example, it can play audio to the handset and/or report handset hookswitch events. | 0x00000002
Modem has a speakerphone phone device. | 0x00000004
Modem will use serial wave driver to play audio to the handset and line. | 0x00000020
Dial string must always end with DialSuffix in voice mode. | 0x00000040
Modem does not support Caller ID. | 0x00000080
Modem speaker volume can be changed using multimedia mixer. | 0x00000100
Force blind dialing after dial tone detection. long dial strings are broken up into two or more dial strings. If the modem tries to detect the dial tone every time the dial command is issued, this bit should be set. | 0x00000200
Speakerphone state must be reset after recording from line. | 0x00000400
Speakerphone state must be reset after playing from line. | 0x00000800
Modem does not report distinctive ring. | 0x00001000
Modem supports distinctive ringing with ring duration (DRON and DROF). Ignored if modem does not support distinctive ringing. | 0x00002000
If distinctive ringing is enabled, the first ring reported by modem may not be correct. Unimodem will not report the first ring. | 0x00004000
Modem does not report the first ring when distinctive ringing is enabled. | 0x00008000
The modem reports silence DLE. | 0x00010000
Modem does not support DTMF generation while in voice mode. | 0x00020000
Modem does not monitor DTMF digits while in voice mode. | 0x00040000
UART baud rate will be set before issuing StartPlay or StartRecord commands. If this bit is not set, UART baud rate will be set after the StartPlay or StartRecord command. | 0x00080000
UART baud rate will be reset after the StopPlay or StopRecord command is issued. | 0x00100000
Modem keeps handset disconnected from modem while in voice mode. If this bit is set, Unimodem will display "Talk/Drop" dialog during outgoing calls. Unimodem will not allow the line to be opened as Owner/InteractiveVoice. | 0x00200000
Speakerphone cannot be muted. Speakerphone can be ONHOOK or MICSPEAKER. | 0x00400000
Sierra chipset Voice Modem. | 0x00800000
Enable for voice modem use on Windows 2000 and later versions of the operating system | 0x02000000

Note VOICEPROF_SET_BAUD_BEFORE_WAVE 0x00080000

This bit indicates the DTE should adjust the baud rate prior to issuing the StartPlay/StartRecord commands. If the bit is disabled or cleared, then the baud rate will be adjusted after these commands are issued. Usually this bit is set for Rockwell chipset modems.

The VoiceProfile bit (0x02000000) for Windows 2000 and later versions of the operating system is backward compatible with Windows 95/98, and with Windows NT 4.0. For this reason, the VoiceProfile bit can be used in modem INF files that will be installed on such earlier operating systems. This bit should also be used in conjunction with the following voice entries that are specific to Windows Me and Windows 2000 and later versions of the operating system:

XformID (NT Wavedriver)

BaudRate (NT Wavedriver)

XformModule (NT Wavedriver)

WaveHardwareID (NT Wavedriver)

WaveDevices (NT Wavedriver)

Note Unless otherwise specified, all the modem INF file entries that are supported by Windows 2000 are also supported by Windows Me.

See Also

VoiceProfile

VoiceToDataAnswer

This entry identifies the AT command used to switch to data answer after a call has been answered in voice mode.

Format

One or more command strings.

Sample

HKR, VoiceToDataAnswer,         1,, "at#cls=0<cr>"
HKR, VoiceToDataAnswer,         2,, "ata<cr>"

WaveDevices

This entry is used in the serial wave INF file.

It specifies the number of wave devices that the serial wave driver supports.

Format

A two-byte value.

Sample

HKR,Config,WaveDevices,  1, 01, 00

Note

This entry can only be used to indicate that a voice modem has the ability to play back and record to a handset device. If it does not have this ability or does not have a handset device, this entry should be set to "1". If this entry is set to "2", the serial wave device will report a handset and line device. No other value can be used in this entry. If this entry is omitted, the default value is "2".

The VoiceProfile handset bit (0x00000002) is usually enabled if the WaveDevices entry is enabled; conversely, that bit is disabled if the WaveDevices entry is disabled.

WaveDevices (NT Wavedriver)

This entry provides voice functionality for Windows 2000 and later versions of the operating system. It specifies the number of wave devices that the serial wave driver supports.

Format

A two-byte value.

Sample

HKR, WaveDriver,    WaveDevices, 1, 02, 00

Note

This entry can only be used to indicate that a voice modem has the ability to play back and record to a handset device. If it does not have this ability or does not have a handset device, this entry should be set to "1". If this entry is set to "2", the serial wave device will report a handset and line device. No other value can be used in this entry. If this entry is omitted, the default value is "2".

The VoiceProfile handset bit (0x00000002) is usually enabled if the WaveDevices entry is enabled; conversely, that bit is disabled if the WaveDevices entry is disabled.

This command is placed in the modem INF file only and NOT in a serial wave driver INF file because Windows 2000 and later versions of the operating system do not use a serial wave driver INF file.

In addition, the following keys are collectively found in a modem INF file which is enabled to provide voice functionality in Windows 2000 and later versions of the operating system. These keys are backward compatible with Windows 95/98 and with Windows NT 4.0. You can use the following keys in modem INF files that will be installed on these earlier Windows-based operating systems:

XformID (NT Wavedriver)

BaudRate (NT Wavedriver)

XformModule (NT Wavedriver)

WaveHardwareID (NT Wavedriver)

WaveDevices (NT Wavedriver)

The Windows 2000 VoiceProfile bit (0x02000000) should also be enabled.

Note Unless otherwise specified, all the modem INF file entries that are supported by Windows 2000 are also supported by Windows Me.

See Also

VoiceProfile

WaveHardwareID (NT Wavedriver)

This entry provides voice functionality for Windows 2000 and later versions of the operating system. It defines the ID string for the wave device.

Format

String

Sample

HKR, WaveDriver,    WaveHardwareID ,, "RockwellADPCMVoiceModemWave"

Note

This command is placed only in the modem INF file. This command should not be placed in a serial wave driver INF file because Windows 2000 and later versions of the operating system do not use a serial wave driver INF file.

In addition, the following keys are collectively found in a modem INF file that is enabled for voice functionality in Windows 2000 and later versions of the operating system. These keys are backward compatible with Windows 95/98, and with Windows NT 4.0. You can use the following keys in modem INF files that will be installed on these earlier Windows-based operating systems:

XformID (NT Wavedriver)

BaudRate (NT Wavedriver)

XformModule (NT Wavedriver)

WaveHardwareID (NT Wavedriver)

WaveDevices (NT Wavedriver)

The Windows 2000 VoiceProfile bit (0x02000000) should also be enabled.

Note Unless otherwise specified, all the modem INF file entries that are supported by Windows 2000 are also supported by Windows Me.

See Also

VoiceProfile

WaveOutMixerDest

WaveOutMixerSource

WaveInMixerDest

WaveInMixerSource

These entries appear in the wave wrapper INF files. These entries identify the multimedia source and destination devices associated with the phone line.

Format

A single command string of type DWORD.

Sample

HKR,Config,WaveOutMixerDest,    1, 00,00,00,00
HKR,Config,WaveOutMixerSource,  1, 01,00,00,00
HKR,Config,WaveInMixerDest,     1, 01,00,00,00
HKR,Config,WaveInMixerSource,   1, 01,00,00,00

Note

WaveOutMixerDest is the multimedia line connected to the wave output. Usually, this would correspond to the speakers.

WaveOutMixerSource is the multimedia line to be used as the source relative to WaveOutMixerDest. Usually, this would correspond to "wave/out" (or, physically, the ADC).

WaveInMixerDest is the multimedia line corresponding to wave in.

WaveInMixerSource is the multimedia line to be used as the source relative to WaveInMixerDest. Usually, this would correspond to "line in" or "wave in".

XformID

This entry appears in the serial wave device INF file. It specifies the serial wave format.

Format

A single command of type DWORD. The first two bytes are used, the remaining two bytes are reserved.

Sample

HKR,Config,XformID, 1, 01, 00, 00, 00 ;e.g. Rockwell 4-bit ADPCM @7200 Hz sample rate
HKR,Config,XformID, 1, 02, 00, 00, 00 ;e.g. IMA 4-bit ADPCM @4800 Hz
HKR,Config,XformID, 1, 04, 00, 00, 00 ;e.g. IMA 4-bit ADPCM @8000 Hz
HKR,Config,XformID, 1, 09, 00, 00, 00 ;e.g. Rockwell 4-bit ADPCM w/o fixed gain increase

Note

XformID Value | Meaning
Null transform, no conversion | 0x00000000
4-bit Rockwell ADPCM 7200 Hz format | 0x00000001
4-bit IMA ADPCM 4800 Hz format | 0x00000002
4-bit IMA ADPCM 7200 Hz format | 0x00000003
4-bit IMA ADPCM 8000 Hz format | 0x00000004
Reserved. | 0x00000005
Reserved. | 0x00000006
8-bit unsigned linear PCM at 7200 Hz format | 0x00000007
8-bit unsigned linear PCM at 8000 Hz format. | 0x00000008
4-bit Rockwell ADPCM 7200 Hz format, without fixed gain increase. | 0x00000009
8 bit u-law (G.711) at 8000 Hz. | 0x00000010
8 bit A-law (G.711) at 8000 Hz. | 0x00000011

XformID (NT Wavedriver)

This entry provides voice functionality for Windows 2000 and later versions of the operating system. It specifies the serial wave format.

Format

Two-byte value.

Sample

HKR, WaveDriver,    XformID       , 1,  01, 00

Note

XformID Value | Meaning
Null transform, no conversion | 0x0000
4-bit Rockwell ADPCM 7200 Hz format | 0x0001
4-bit IMA ADPCM 4800 Hz format | 0x0002
4-bit IMA ADPCM 7200 Hz format | 0x0003
4-bit IMA ADPCM 8000 Hz format | 0x0004
Reserved. | 0x0005
Reserved. | 0x0006
8-bit unsigned linear PCM at 7200 Hz format | 0x0007
8-bit unsigned linear PCM at 8000 Hz format. | 0x0008
4-bit Rockwell ADPCM 7200 Hz format, without fixed gain increase. | 0x0009
8 bit u-law (G.711) at 8000 Hz. | 0x0010
8 bit A-law (G.711) at 8000 Hz. | 0x0011

This command is placed only in the modem INF file. This command is not placed in a serial wave driver INF file because Windows 2000 and later versions of the operating system do not use a serial wave driver INF file.

In addition, the following keys collectively are found in a modem INF file that is enabled for voice functionality in Windows 2000 and later versions of the operating system. These keys are backward compatible with Windows 95/98, and with Windows NT 4.0 . You can use the following keys in modem INF files that will be installed on these earlier Windows-based operating systems.:

XformID (NT Wavedriver)

BaudRate (NT Wavedriver)

XformModule (NT Wavedriver)

WaveHardwareID (NT Wavedriver)

WaveDevices (NT Wavedriver)

The Windows 2000 VoiceProfile bit (0x02000000) should also be enabled.

Note Unless otherwise specified, all the modem INF file entries that are supported by Windows 2000 are also supported by Windows Me.

See Also

VoiceProfile

XformModule (NT Wavedriver)

This entry provides voice functionality in Windows 2000 and later versions of the operating system. It specifies the wave driver file.

Format

String.

Sample

HKR, WaveDriver,    XformModule    ,, "umdmxfrm.dll"

Note

This command is placed only in the modem INF file. This command should not be placed in a serial wave driver INF file because Windows 2000 and later versions of the operating system do not use a serial wave driver INF file.

In addition, the following keys are collectively found in a modem INF file that is enabled for voice functionality in Windows 2000 and later versions of the operating system. These keys are backward compatible with Windows 95/98, and with Windows NT 4.0. You can use them in a modem INF file that will be installed on these earlier Windows-based operating systems:

XformID (NT Wavedriver)

BaudRate (NT Wavedriver)

XformModule (NT Wavedriver)

WaveHardwareID (NT Wavedriver)

WaveDevices (NT Wavedriver)

The Windows 2000 VoiceProfile bit (0x02000000) should also be enabled.

Note Unless otherwise specified, all the modem INF file entries that are supported by Windows 2000 are also supported by Windows Me.

See Also

VoiceProfile

Built on Wednesday, July 11, 2001


ISDN-TA Modem INF File Entries

ISDN-TA Modem INF file settings are supported in Windows Me and in Windows 2000 and later versions of the operating system.

Note Unless otherwise specified, all the modem INF entries that are supported by Windows 2000 are also supported by Windows Me and later NT-based versions of the operating system.

ISDN\SwitchType

Use the ISDN\SwitchType entry to define a series of registry keys that store AT commands. Each of these commands configures the ISDN modem for use with a particular type of switch.

Format

One or more command strings.

Sample

ISDN SwitchType registry entries have the following form:

HKR, ISDN\SwitchType, SWITCH_XXX,, "command string"

The following table lists the switch types with the corresponding SWITCH_XXX entries.

Switch Type | SWITCH_XXX Entry | Sample
AT&T 5ESS Custom | SWITCH_ATT1 Note: Point-to-point configuration line code 2B1Q | AT&O1<cr>
Northern Telecom DMS-100 | SWITCH_ DMS100 Note: Point-to-point configuration line code 2B1Q | AT&O3<cr>
National ISDN 1 | SWITCH_NI1 Note: Default for North America | AT&O4<cr>
NTT INS64 | SWITCH_ INS64 Note: Default for Japan | AT!C1=4<cr> or AT*W=7<cr>
DSS1 | SWITCH_ DSS1 Note: Default for Europe "Euro ISDN" | AT&O6<cr> or AT$IDP=DSS1 <cr>
1TR6 | SWITCH_1TR6 Note: Must include SetEAZ key (below) | AT&O7<cr>
VN3 | SWITCH_ VN3 | AT&O8<cr>
Belgian National | SWITCH_ BELGIUM1 Note: Default for Belgium | AT&O9<cr>
Australian National TPH | SWITCH_AUS1 Note: Default for Australia | AT&O10<cr>
Unknown Switch type | SWITCH_UNKNOWN Note: Supporting auto-detection of switch type in the U.S | ATS50=0

If the ISDN modem supports only one default switch type (for example, DSS1) and does not support AT commands for selecting this switch type, it might appear impossible to support static configuration. However, an ISDN\SwitchType entry must still be included in the INF file so that the MSN number is available through the Unimodem configuration interface.

Example:

HKR, ISDN\SwitchType, SWITCH_DSS1,,"AT<cr>"      ;DSS1 (Euro-ISDN)

If several switch types are included, the default is based on the end user's location, such as DSS1 (Euro-ISDN) for Europe or National ISDN for North America.

The inclusion of an ISDN\SwitchType entry enables the ISDN tab on the modem properties dialog.

It offers the user a Switch Type drop-down box that displays entry boxes for:

  • First Number and SPID/EAZ
  • Second Number and SPID/EAZ

Note

If the 1TR6 entry is included in the INF file, the accompanying ISDN\SetEAZ should also be included in the INF file. ISDN\SetEAZ contains commands issued to set EAZ (Endgerateauswahlziffer).

ISDN\DirectoryNo

This entry specifies the AT command sent to the ISDN modem to set the directory number (US Switch Types).

Format

One or more command strings.

Samples

HKR, ISDN\DirectoryNo,1,,  "AT N1=%s<cr>"
HKR, ISDN\DirectoryNo,2,,  "AT N2=%s<cr>"

Note

There are several issues related to using this entry::

  • %s represents the number being sent.
  • The entry of two directory numbers, two MSNs or two EAZs is supported.
  • The second entry can be used to assign a directory number to an analog port. The first entry should always be used to assign numbers to the data port.
  • The %s must be in lower case. The letters <cr> must also be in lowercase.
  • If the device supports the entry of only one number, include only one entry to automatically disable the user interface for the second number.

ISDN\SetSpid

Use this entry to specify the AT commands used to set the service provider identification number as required by certain US switch types.

Format

One or more command strings.

Samples

The following are valid forms for this entry:

HKR, ISDN\SetSpid, 1,,     "AT SPID1=%s<cr>"
HKR, ISDN\SetSpid, 2,,     "AT SPID2=%s<cr>"

Or:

HKR, ISDN\SetSpid, 1,,     "ATSS60=%s<cr>"
HKR, ISDN\SetSpid, 2,,     "ATSS61=%s<cr>"

Or:

HKR, ISDN\SetSpid, 1,,     "AT!C6=%s<cr>"
HKR, ISDN\SetSpid, 2,,     "AT*1!C6=%s<cr>"

Note

The characters %s and <cr> must be entered in lowercase.

ISDN\SetMSN

Use these entries to specify commands that set the ISDN modem to answer incoming calls directed towards particular MSNs. These commands are issued in conjunction with ISDN\SwitchType, SWITCH_DSS1 during static configuration.

Format

One or more command strings.

Samples

The following are valid forms for this entry:

HKR, ISDN\SetMSN, 1 ,,"AT!N1=%s<cr>"
HKR, ISDN\SetMSN, 2 ,,"AT*1!N1=%s<cr>"

Or:

HKR, ISDN\SetMSN, 1 ,,"AT&ZI3=%s<cr>"
HKR, ISDN\SetMSN, 2 ,,"AT&ZI4=%s<cr>"

Or:

HKR, ISDN\SetMSN, 1 ,,"AT$IMSN=0,"","","%s""<cr>"
HKR, ISDN\SetMSN, 2 ,,"AT$IMSN=1,"","","%s""<cr>"

Note

A maximum of two MSNs can be supported. Include one entry in the INF file to support one MSN. The first MSN should always be assigned to the device's data port; the second MSN can be assigned to the device's analog port.

On a device that does not have analog ports, both numbers may be assigned to data ports. The characters %s and <cr> must be entered in lowercase.

ISDN\SetEAZ

This entry defines commands issued to set EAZ (Endgerateauswahlziffer).

These are used by German 1TR6 switches.

Format

One or more command strings.

Sample

HKR, ISDN\SetEAZ, 1 ,,   "AT EAZ1=%s<cr>"
HKR, ISDN\SetEAZ, 2 ,,   "AT EAZ2=%s<cr>"

Note

If only one SetEAZ entry is included, the ISDN configuration UI only accepts one EAZ.

ISDN\Init

These entries define the commands that are sent to initialize the ISDN modem.

Samples

The following are valid forms for this entry:

HKR, ISDN\Init, 1,, "AT E0<cr>"
HKR, ISDN\Init, 2,, "AT V1<cr>"

Or:

HKR, ISDN\Init, 1,, "AT E0V1<cr>"

Note

These entries should not include commands that affect the switch type, EAZs, MSN, or the protocol to dial. The modem should not be in an auto-answer state following the issuing of these commands.

The format of the entries allows long initialization commands to be issued by breaking command lines down into two or more separately issued lines.

ISDN, CompatibilityFlags

The CompatibilityFlags entry is used to change the order in which configuration information is sent to the ISDN modem during static configuration.

If this entry is not included, or if the entry is set as follows:

HKR,ISDN, CompatibilityFlags,  1,00,00,00,00

Unimodem will issue commands in the following order:

  • Switch type
  • Directory number(s)
  • SPID(s)

If the INF file entry is as follows:

HKR,ISDN, CompatibilityFlags,  1,00,00,00,00

Unimodem will issue commands in the following order:

  • Directory number(s)
  • SPID(s)
  • Switch type

Format

One or more command strings.

Sample

 HKR,ISDN, CompatibilityFlags,  1,00,00,00,00
Another possible configuration is as follows:
HKR,ISDN, CompatibilityFlags,  1,00,00,00,01

ISDN\Protocol

ISDN supports a large number of B channel protocols. Windows 2000 allows users and communications applications (for example, RAS) to select them dynamically. The inclusion of one or more Protocol\ISDN INF file entries enables the corresponding protocols to be selected in the user interface (see Data Connection Preferences), and indicated through TAPI and Unimodem. When a protocol is selected in the user interface, Unimodem will issue the corresponding AT commands prior to originating a call as part of a sequence of commands setting response format and presentation, carrier detect on, and so forth.

Note that this entry does not set a direct mode. The rate is the DCE-DCE rate, not the DTE-DCE rate.

Format

For each B channel protocol, ISDN Protocol registry entries have the following form:

HKR, Protocol\ISDN\<protocol_type>, 1,, "command string<cr>"

Sample

The following example selects a V.120 on one 64 kbps channel, using the command *V2=1.

HKR, Protocol\ISDN\V120_64K, 1,,"AT*V2=1<cr>"

The following table lists the ISDN protocols, the entries, sample command strings and notes.

Protocol type | <protocol_ type> entry | Sample commands
V.120, 1B, 64kbps | V120_64K Note: Does not initialize device for V.42bis over V.120. See Note 1. | AT*V2=1<cr> AT\N4<cr> AT\N4%C0<cr> AT&E0B20 &J0<cr> AT&F$IBP=V120<cr>
V.120, 1B, 56kbps | V120_56K | AT*V2=1S67.1=1S67.2=0<cr>
V.120, 2B w/MLB, 128kbps | V120_128K | AT&E0B20 &J3<cr>
V.120, 2B w/MLB, 112kbps | V120_112K | AT&E0B20 &J3<cr>
V.110, 1B, 1.2kbps | V110_1DOT2K | AT%B1200 %G1\N0<cr>
V.110, 1B, 2.4kbps | V110_2DOT4K | AT%B2400 %G1\N0<cr>
V.110, 1B, 4.8kbps | V110_4DOT8K | AT%B4800 %G1\N0<cr>
V.110, 1B, 9.6kbps | V110_9DOT6K | AT%B9600 %G1\N0<cr>
V.110, 1B, 12.0kbps | V110_12DO T0K | AT%B12000 %G1 \N0<cr>
V.110, 1B, 14.4kbps | V110_14DO T4K | AT%B14400 %G1\N0<cr>
V.110, 1B, 19.2kbps | V110_19DOT2K | AT%B19200%G1 \N0<cr> AT*V2=2S80.3=0<cr>
V.110, 1B, 28.8kbps | V110_28DOT8K | AT%B28800%G1 \N0<cr> ATB19&J0<cr >
V.110, 1B, 38.4kbps | V110_38DOT4K | AT*V2=2S80.3=1<cr>
V.110, 1B, 57.6kbps | V110_57DOT6K | AT%B57600%G1 \N0<cr> ATB19&J0<cr>
X.75, 1B, 57.6kbps | X75_64K | ATB00&J0<cr> AT&F$IBP=X75<cr>
X.75, T.70, 57.6kbps | X75_T_70 |
X.75 BTX | X75_BTX | AT&F$IBP=BTX<cr>"
Automatic protocol selection on origination | AUTO_1CH Note: Must include auto-detection of HDLC at 64kbps |
Automatic protocol selection on answer | AUTO_2CH Note: Must include dual channel connections, HDLC at 128kbps using PAP/CHAP. |
HDLC PPP, 1B, 56kbps | HDLC_PPP_56K Note: RFC 1662 | AT%B57600%G1 \N0<cr>
HDLC PPP, 1B, 64kbps | HDLC_PPP_64K Note: RFC 1662 | AT%%A4=0%%A2=95@B0=1<cr> AT&F$IBP=HDLCP<cr>
HDLC PPP, 2B, 112kbps | HDLC_PPP_112K Note: RFC 1662 & RFC 1717, Note 2 below | AT%A2=95@B0=2 %A4=1<cr>
HDLC PPP, 2B, 128kbps | HDLC_PPP_128K Note: RFC 1662 & RFC 1717, Note 2 below | AT%A2=95@B0=2 %A4=0<cr>
HDLC PPP, 2B, 128kbps, with PAP in the modem | HDLC_PPP_128K_PAP Note: PAP is in RFC 1334 | AT%A2=95@B0=2%A4=0@M2=P<cr>
HDLC PPP, 2B, 128kbps, With CHAP in the modem | HDLC_PPP_128K_CHAP | AT%A2=95@B0=2%A4=0@M2=M<cr>
HDLC PPP, 2B, 128kbps, With MSCHAP in the modem | HDLC_PPP_128K_MSCHAP Note: MS CHAP is Microsoft's version of RSA MD4 | AT%A2=95@B0=2%A4=0@M2=M<cr>
PAIFS Incoming | PIAFS_ INCOMING | ATPIAFSI<cr>
PAIFS Outgoing | PIAFS_ OUTGOING | ATPIAFSO<cr>
Analog V34 1B Channel | ANALOG_V34 Note: Analog connectivity over ISDN | AT+PSTN<cr>

Note

These entries are not intended to initialize the device to use V42bis over V.120. If the device defaults to using V.42bis compression when initialized to V.120 the entries should initialize to V.120 with compression off.

These entries should also contain commands to disable any authentication method on the B channel that is not exposed to the operating system over the RS232 communications interface.

ISDN\NvSave

This INF entry defines AT commands that are used to configure the ISDN modem for storage of the current configuration in NvRAM. This will always store ISDN\init and ISDN\SwitchType. Depending on the switch type, it may also store MSN, EAZ, SPIDs and directory number.

Format

One or more command strings.

Samples

The following forms are valid for this entry:

HKR, ISDN\NvSave,1,,"AT&W<cr>"
Or:
HKR, ISDN\NvSave,1,,"AT&W<cr>"
HKR, ISDN\NvSave,2,,"ATZ<cr>"

Or:

HKR, ISDN\NvSave,1,, "AT&W0<cr>"
HKR, ISDN\NvSave,2,, "AT>W<cr>"
HKR, ISDN\NvSave,3,, "ATZ0<cr>"
HKR, ISDN\NvSave,4,, "AT>Z<cr>"

Note

As demonstrated by the samples, a multi-line format can be used if it is required to cause the ISDN modem to reset the D channel and network .

The device has 10 seconds to recover from this reset or Unimodem will assume the device is failing to respond and return an appropriate error.


GSM Modem INF File Entries

This topic defines the modem INF file entries required to support GSM modems.

Protocol\GSM

GSM supports many logical protocols. The major protocol classes are::

  • Analog, which connects to a remote PSTN voice band modem through a modem in a pool in the GSM network provider facilities. Examples of analog protocols include: V.90, V.34 and V.32bis.
  • V.110 and V.120, which connects to a remote ISDN DCE by way of V.110 or V.120 provided by a GSM network provider.
  • HDLC PPP, which connects to the Internet through a GSM network provider.

Windows 2000 allows users and communications applications (for example, RAS) to select protocols dynamically. The inclusion of one or more Protocol\GSM INF file entries enables the corresponding protocol to be selected in the user interface under Data Connection Preferences. The protocol is also indicated through TAPI and Unimodem.

When a given protocol is selected in the user interface, Unimodem will issue the corresponding AT commands prior to originating a call as part of a sequence of commands that set response format and presentation, carrier detect on, and so forth.

This entry does not set a direct mode. The rate is the DCE-DCE rate, not the DTE-DCE rate.

Format

GSM Protocol registry entries have the following form:

HKR, Protocol\GSM\<protocol_type>, 1,,"command string<cr>"

Sample

The following example selects a V-series PSTN modem with Radio Link Protocol on:

HKR, Protocol\GSM\ANALOG_RLP, 1,,"AT+CBST=0,,1<cr>"

The following table lists the GSM protocols, the entries, sample command strings and notes.

Protocol type | <protocol _type> entry | Sample commands
V-series PSTN modem, with Radio Link Protocol ON | ANALOG_RLP Note: See ETSI/GSM 7.07 for RLP and +CBST commands, see note 1 | AT+CBST=0,,1<cr> AT\N3<cr>
V-series PSTN modem, with Radio Link Protocol OFF | ANALOG_NRLP | AT +CBST7,,0<cr> AT \N0<cr>
V.110, 1.2kbps | V110_1DOT2K Note: See Note 2 | AT+CBST=66,,<cr>
V.110, 2.4kbps | V110_2DOT4K Note: See Note 2 | AT+CBST=68,,<cr>
V.110, 4.8kbps | V110_4DOT8K Note: See Note 2 | AT+CBST=70,,<cr>
V.110, 9.6kbps | V110_9DOT6K Note: See Note 2 | AT+CBST=71,,<cr>
V.110, 14.4kbps | V110_14DOT4K Note: See Note 2 | AT+CBST=75,,<cr>
V.110, 19.2kbps | V110_19DOT2K Note: See Note 2 | AT+CBST=79,,<cr>
V.110, 28.8kbps | V110_28DOT8K Note: See Note 2 | AT+CBST=80,,<cr>
V.110, 38.4kbps | V110_38DOT4K Note: See Note 2 | AT+CBST=81,,<cr>
V.120, 56kbps | V120_56K | AT+CBST=51,,<cr>
HDLC PPP, 56kbps | HDLC_PPP_56K Note: RFC 1662 | AT+CBST=115,,<cr>
HDLC PPP, 64kbps | HDLC_PPP_64K Note: RFC 1662 | AT+CBST=116,,<cr>
General Packet Radio Service (GPRS) | GPRS | AT<cr>

Note

The following notes are keyed to the preceding table:

  1. It is also recommended that autobauding be enabled for RLP connections as specified in ETSI/GSM 07.07.
  2. Direct mode V.110 connections are not supported – a variable DCE speed (for example, 1200 bps) and a DTE speed of 115200 bps should be established


Supporting Multifunction Devices

A multifunction device occupies one location on its parent bus but contains more than one function. Combination printer/scanner/fax devices and modem/network cards are common multifunction devices.

In a multifunction device, the individual functions are independent. This means the functions must have the following characteristics:

  • The functions cannot have start-order dependencies.
  • The resource requirements for one function cannot be expressed in terms of the resources of another function (for example, function1 uses I/O port x and function2 uses port x + 200).
  • Each function must be able to operate as a separate device, even if it is serviced by the same drivers as another function.

Additionally, the following requirements must be met so that a multifunction device can be correctly configured on an NT-based platform:

  • Each function on the device must be enumerated.
  • Resource requirements for each function must be communicated to the PnP Manager.
  • There must be INF files and drivers for each function.

The component responsible for each of these tasks depends on the multifunction standard for the device's parent bus, the extent to which the device conforms to the standard, and the capabilities of the parent bus driver.

If the device complies with the multifunction standards for its bus, your driver requirements are significantly reduced. Industry-wide multifunction standards have been defined for the PC Card and PCI buses. For the applicable hardware standards and guidelines, see www.microsoft.com/hwdev/mf.

Microsoft® Windows® XP and later systems support the IEEE 1284.4 (Dot 4) standard for multifunction print devices. For details on providing drivers for such devices, see Supporting IEEE 1284.4 Devices.

If you are working with a multifunction DVD/CD-ROM device used for data storage (not for audio/video playback) on a Windows XP or later operating system, you should use the system-supplied WDM DVD class driver, which treats the device as a single logical unit. For Windows® 2000 and Windows® 98, you should treat the device as two logical units (so it will appear with two drive letters). If the DVD capabilities are combined with some other type of function, you should treat the device as a single logical unit and supply a class driver that implements common command sets for all the features of the device. For more information, see www.microsoft.com/hwdev/dvd.

For a multifunction device that combines other functionality, you can use a system-supplied driver and INF file if the device complies with the multifunction standards for its bus. The system supplied multifunction driver (mf.sys) can handle the bus-level enumeration and resource allocation requirements for the device, and the system-supplied INF (mf.sys) can install the multifunction device. You need to supply only a function driver and INF file for each of the individual device functions.

If the device does not comply with the standard for its bus, you might need to supply a driver equivalent to mf.sys in functionality, in addition to function drivers and INF files for the device functions.

To install a multifunction device, you typically provide a base INF file for the device and an additional INF file for each of the device's functions. The base INF file typically copies the INF files for the device's individual functions. For information on how to accomplish this, see Copying INFs.

The following sections describe driver and installation requirements for various types of multifunction devices:

Supporting Multifunction PC Card Devices

Supporting Multifunction PCI Devices

Supporting Multifunction Devices On Other Buses

Using the System-Supplied Multifunction Bus Driver

Creating Resource Maps for a Multifunction Device

See INF File Sections and Directives for information on INF file syntax.

The rest of this section describes how to support multifunction devices on Windows 2000 and later NT-based platforms only.

This DDK includes a separate section that describes how to support multifunction audio devices.


Supporting Multifunction PC Card Devices

The PC Card multifunction standard specifies that a multifunction device has a set of configuration registers in attribute memory for each function. These registers allow the PCMCIA bus driver to, for example, enable each function independently and define a range of I/O resources that are exclusive to each function. The standard also specifies that a multifunction device contains, in attribute memory, the address of each set of configuration registers. These addresses enable the PCMCIA bus driver to program the configuration registers.

If a 16-bit PC Card device implements the PC Card multifunction standard completely and correctly, the vendor of such a device has minimal INF and driver requirements to ensure that the device is configured properly on an NT-based system. See Supporting PC Cards that Conform to the Multifunction Standard for more information.

If a 16-bit PC Card device does not fully implement the PC Card multifunction standard, the vendor must provide the missing information in an INF file. There are two ways that a multifunction PC Card device might fail to implement the multifunction standard:

  1. The device implements a set of multifunction configuration registers per function but does not contain the locations of all sets of registers in its attribute memory.
  2. The device does not implement a set of multifunction configuration registers per function.

If a device has the limitations listed above, the PCMCIA bus driver can program the configuration registers if the device's INF has the necessary information in DDInstall.LogConfigOverride section(s). See the following sections for further information:

Supporting PC Cards That Have Incomplete Configuration Register Addresses

Supporting PC Cards That Have Incomplete Configuration Registers

Cardbus devices essentially follow the PCI multifunction rules. See Supporting Multifunction PCI Devices.


Supporting PC Cards That Conform to the Multifunction Standard

If a 16-bit, ISA-style PC Card device implements the PC Card multifunction standard completely and correctly, the vendor of such a device on an NT-based platform can rely on the following system-supplied components to handle the software aspects of the multifunction semantics:

  • An INF file for the multifunction device. (system-supplied)

    The PCMCIA bus driver specifies a hardware ID for the device that causes the Configuration Manager to use the system-supplied multifunction INF file (mf.inf) to configure the device. The mf.inf file specifies the class "MultiFunction" and its associated GUID (as defined in devguid.h).

  • A function driver for the multifunction device. (system-supplied)

    The mf.inf file specifies the system-supplied multifunction bus driver (mf.sys) as the function driver for the device.

    The mf.sys bus driver enumerates the functions of the device. The PCMCIA bus driver reads the configuration registers on the device to determine the resource requirements of each function.

    See Using the System-Supplied Multifunction Bus Driver for more information on using the system-supplied mf.sys driver.

The vendor of a multifunction PC Card device that conforms to the standard must provide the following support for the individual functions:

  • A PnP function driver for each function of the device. (vendor-supplied)

    Since the multifunction bus driver handles the multifunction semantics, the function drivers can be the same drivers that would be used if the functions were packaged as individual devices.

  • An INF file for each function of the device. (vendor-supplied)

    The INF files can be the same files that would be used if the functions were packaged as individual devices. The INF files do not need any special multifunction semantics.

Child Function Hardware IDs Created by the PCMCIA Bus Driver

For a true multifunction PC Card device, the PCMCIA bus driver, together with mf.sys, creates hardware IDs for the child functions. Those IDs have the format:

    <Manufacturer-name>-<Product-ID-string>-DEV<number>-CRC

In this format, <number> is a zero-based number for the function.

For example, the PCMCIA bus driver creates child function hardware IDs such as the following:

    3COM_Corporation-3C562D/3C563D-DEV0-4893
    3COM_Corporation-3C562D/3C563D-DEV1-4893

An INF file for a child function of a multifunction PC Card device must specify the hardware ID that is reported by the PCMCIA bus driver and mf.sys.


Supporting PC Cards That Have Incomplete Configuration Register Addresses

If a multifunction 16-bit PC Card device has configuration registers for each function but does not contain pointers in attribute memory to all register sets (does not support the LONGLINK_MFC tuple), the vendor of such a device can use the system-supplied multifunction bus driver (mf.sys) but must provide a custom INF file and support for the individual functions.

The vendor of such a device on an NT-based platform can use a system-supplied function driver for the multifunction device.

A custom INF for the device must specify mf.sys as the function driver for the device. The system-supplied mf.sys driver will then enumerate the functions of the device.

See Using the System-Supplied Multifunction Bus Driver for more information on using the system-supplied mf.sys driver.

The vendor of such a device on must provide the following:

  • A custom INF file for the multifunction device. (vendor-supplied)

    The vendor must supply a multifunction INF file that specifies mf.sys as the multifunction bus driver, specifies the class "MultiFunction" (with its associated GUID as defined in devguid.h), and provides the missing configuration register address(es). See further information later in this section.

  • A PnP function driver for each function of the device. (vendor-supplied)

    Since the multifunction bus driver handles the multifunction semantics, the function drivers can be the same drivers that are used when the functions are packaged as individual devices.

  • An INF file for each function of the device. (vendor-supplied)

    The INF files can be the same files that are used when the functions are packaged as individual devices. The INF files do not need any special multifunction semantics.

The custom INF for such a multifunction device must contain at least one INF DDInstall.LogConfigOverride section. The override section must contain an MfCardConfig entry for each function, identifying the location of each set of configuration registers.

The INF must restate all the resource requirements specified by the device because if override configurations are present in the INF, the PnP Manager does not use any device resource requirements from the device.

Specify the MfCardConfig entries using the syntax described in INF LogConfig Directive.

For example, consider the following excerpt from a custom INF for a multifunction PC Card device that contains a modem and a network adapter:

;...

[DDInstall.LogConfigOverride]
LogConfig = DDInstall.Override0

[DDInstall.Override0]
IOConfig     =    3F8-3FF                  ; Com1
IOConfig     =    10@100-FFFF%FFF0         ; NIC I/O
IRQConfig    =    3,4,5,7,9,10,11          ; IRQ
MemConfig    =    2000@0-FFFFFFFF%FFFFE000 ; Memory Descriptor 0
MemConfig    =    1000@0-FFFFFFFF%FFFFF000 ; Memory Descriptor 1
MfCardConfig =    1000:47:0(A)
MfCardConfig =    1080:47:1
;...

The example shows two MfCardConfig entries, one for each function of the device. The first MfCardConfig entry contains the following information:

1000 (ConfigRegBase)
Specifies that there is a set of configuration registers in the attribute memory of the card at offset 0x1000. In this example, the information in these registers describes the modem function on the card.
47 (ConfigOptions)
Specifies the hexadecimal value for the bus driver to program into the configuration option register at the ConfigRegBase offset (0x1000).
0 (IoConfigIndex)
Specifies that the I/O resources for this function are listed in the first IOConfig entry in this section. An index of zero indicates the first entry, which in this example is "IOConfig = 3F8-3FF".
A (attrs)
Directs the bus driver to turn on audio enable for this function, which is typical for a modem.

The second MfCardConfig entry contains information about the second function on the device (the network adapter, in this example). This entry specifies that there is a second set of configuration registers at offset 0x1080. The bus driver will write the ConfigOptions value of 0x47 to the configuration option register for this function. The IoConfigIndex value of one directs the bus driver to use the second IOConfig entry in this section (IOConfig = 10@100-FFFF%FFF0) to program the I/O base and limit registers for this function.

Include more than one DDInstall.Override N section in the INF to specify more than one choice of nonsequential I/O port ranges.

If the device uses a memory window that is not based at zero, the DDInstall.Override N section(s) must also include a PcCardConfig entry. If an override section has both an MfCardConfig entry and a PcCardConfig entry, the PCMCIA bus driver ignores the ConfigIndex value in the PcCardConfig entry and just uses the MemoryCardBaseN information. See Supporting PC Cards That Have Incomplete Configuration Registers for further information on the PcCardConfig entry.


Supporting PC Cards That Have Incomplete Configuration Registers

If a multifunction 16-bit PC Card device does not have configuration registers for each function, the vendor of such a device can use the system-supplied multifunction bus driver (mf.sys) but must provide a custom INF file and support for the individual functions.

The vendor of such a device on an NT-based platform can use the following system-supplied component:

  • A function driver for the multifunction device. (system-supplied)

    A custom INF for the device must specify mf.sys as the function driver for the device. The system-supplied mf.sys driver will then enumerate the functions of the device.

    See Using the System-Supplied Multifunction Bus Driver for more information on using the system-supplied mf.sys driver.

The vendor of such a device must provide the following:

  • A custom INF file for the multifunction device. (vendor-supplied)

    The vendor must supply a multifunction INF file that specifies mf.sys as the multifunction bus driver, specifies the class "MultiFunction" (with its associated GUID as defined in devguid.h), and provides the missing configuration register information. See further information later in this section.

  • A PnP function driver for each function of the device. (vendor-supplied)

    Since the multifunction bus driver handles the multifunction semantics, the function drivers can be the same drivers that are used when the functions are packaged as individual devices.

  • An INF file for each function of the device. (vendor-supplied)

    The INF files can be the same files that are used when the functions are packaged as a individual devices. The INF files do not need any special multifunction semantics.

The vendor-supplied custom INF for such a device must specify:

  • mf.sys as the service for the device.

    See Using the System-Supplied Multifunction Bus Driver for more information.

  • The resource requirements of the multifunction device.

    Specify the resource requirements in INF DDInstall.LogConfigOverride sections.

  • The hardware ID for each function of the device.

    Specify the hardware IDs in an INF DDInstall.HW section.

  • A resource map for each function of the device, identifying the parent resources required by each child function.

    Specify the resource maps in an INF DDInstall.HW section. See Creating Resource Maps for a Multifunction Device for more information about creating resource maps.

The INF must restate all the resource requirements specified by the device because if override configurations are present in the INF, the PnP Manager does not use any device resource requirements from the device.

For such a device, the configuration option register can be programmed using a PcCardConfig entry, similar to programming a single-function device. The PcCardConfig entry contains information that applies to the entire device. The PcCardConfig entry is documented in INF LogConfig Directive.

When specifying a PcCardConfig entry for a multifunction device, the format of the ConfigIndex is the same as that defined for a single-function device. The configuration register for single-function PC Cards contains an index to a set of resources defined in that device's attributes. This directive can also be used with certain multifunction devices that use the index-based format of the configuration option register.

The following example shows an INF file for installing a multifunction device that uses mf.sys as its bus driver and has incomplete configuration registers.

; MFSupra.inf
; This file installs the Supra Dual 56K modem
; Copyright 1999 Microsoft Corporation

[version]
Signature  = "$Windows NT$"
provider   = %MSFT%
Class      = MultiFunction              ; system-defined class
ClassGUID  = {4d36e971-e325-11ce-bfc1-08002be10318}

[ControlFlags]
ExcludeFromSelect=*SUP2440  ; don't include PnP devices in lists of
                            ; devices to be manually installed

[Manufacturer]
%M_Supra% = Supra

[Supra]
%Supra1% = Sup2231GoCard.mf, *SUP2440

[Sup2231GoCard.mf.NT]
Include = mf.inf           ; specify that this device needs mf.sys
Needs = MFINSTALL.mf

[Sup2231GoCard.mf.NT.HW]
AddReg=Sup2231.mf.RegHW

[Sup2231.mf.RegHW]
HKR, Child0000, HardwareID,  ,  MF\Shotgun_DEV0  ;modem1
HKR,Child0000,ResourceMap,1,00,02
HKR, Child0001, HardwareID,  ,  MF\Shotgun_DEV1  ;modem2
HKR,Child0001,ResourceMap,1,01,02

[Sup2231GoCard.mf.NT.Services]
Include = mf.inf
Needs = MFINSTALL.mf.Services

[Sup2231GoCard.mf.NT.LogConfigOverride]
LogConfig = Sup223x.mf.Override0, Sup223x.mf.Override1, \
    Sup223x.mf.Override2, Sup223x.mf.Override3

[Sup223x.mf.Override0]
ConfigPriority = NORMAL
IOConfig     = 2F8-2FF                  ; Com2
IOConfig     = 20@100-FFFF%FFE0         ; NIC I/O
IRQConfig    = 3,4,5,7,9,10,11,12,15          ; IRQ
MemConfig    = 1000@0-FFFFFFFF%FFFFF000 ; Memory Descriptor
PCCardConfig = 59(W)                    ; ConfigIndex

[Sup223x.mf.Override1]
ConfigPriority = NORMAL
IOConfig     = 3E8-3EF                  ; Com3
IOConfig     = 20@100-FFFF%FFE0         ; NIC I/O
IRQConfig    = 3,4,5,7,9,10,11,12,15          ; IRQ
MemConfig    = 1000@0-FFFFFFFF%FFFFF000 ; Memory Descriptor
PCCardConfig = 69(W)                    ; ConfigIndex

[Sup223x.mf.Override2]
ConfigPriority = NORMAL
IOConfig     = 2E8-2EF                  ; Com4
IOConfig     = 20@100-FFFF%FFE0         ; NIC I/O
IRQConfig    = 3,4,5,7,9,10,11,12,15          ; IRQ
MemConfig    = 1000@0-FFFFFFFF%FFFFF000 ; Memory Descriptor
PCCardConfig = 79(W)                    ; ConfigIndex

[Sup223x.mf.Override3]
ConfigPriority = NORMAL
IOConfig     = 3F8-3FF                  ; Com1
IOConfig     = 20@100-FFFF%FFE0         ; NIC I/O
IRQConfig    = 3,4,5,7,9,10,11,12,15          ; IRQ
MemConfig    = 1000@0-FFFFFFFF%FFFFF000 ; Memory Descriptor
PCCardConfig = 49(W)                    ; ConfigIndex

[strings]
MSFT = "Microsoft"
M_Supra = "Supra"
Supra1 = "Supra Dual 56K modem"

An INF like the one shown above copies the ID and resource information for the child functions to the registry. The mf.sys driver retrieves the information from the registry when it enumerates the child functions of the device.


Supporting Multifunction PCI Devices

If a multifunction PCI device conforms completely to the PCI multifunction standard, the PCI bus driver enumerates the individual functions. The PCI bus driver manages the fact that there is more than one function residing at a single device location. To the rest of the system, the individual functions operate like independent devices.

Vendors of a PCI multifunction device on an NT-based platfrom must do the following:

  • Ensure that the device conforms to the PCI multifunction specification.
  • Provide a PnP function driver for each function of the device.

    Since the system-supplied bus driver handles the multifunction semantics, the function drivers can be the same drivers that would be used if the functions were packaged as individual devices.

  • Provide an INF file for each function of the device.

    The INF files can be the same files that would be used if the functions were packaged as a individual devices. The INF files do not need any special multifunction semantics.

For example, the following figure shows the sample device stacks that might be created for a multifunction PCI device with ISDN and modem functions.

Sample Device Stacks for a Multifunction Device Whose Parent Enumerates Each Function

As shown in the previous figure, rather than enumerating one multifunction device, the PCI driver enumerates two child devices. The PnP Manager treats each child device like a typical device, locating INF files, loading the appropriate drivers, calling their AddDevice routines, and so forth until a device stack is created for each device. The PCI driver arbitrates the resources for the child devices and manages any other multifunction aspects of the device. The vendor of the multifunction card provides function drivers and INFs for the ISDN and modem devices, just as if they were separate devices.

The illustration focuses on the function driver and bus driver for each function and their associated FDO and PDO. Any filter drivers (and filter DOs) are omitted for simplicity.


Supporting Multifunction Devices On Other Buses

For a multifunction device on a PnP ISA, USB, or 1394 bus, the parent bus driver enumerates the individual functions if the device conforms to the bus standard.

For such a device, the parent bus driver manages the fact that there is more than one device residing at a single bus location. To the rest of the system, the individual functions operate like independent devices.

Vendors of this type of multifunction device must do the following:

  • Ensure that the device conforms to the specification for the bus on which the device will reside.
  • Provide a PnP function driver for each function of the device.

    Since the system-supplied bus driver handles the multifunction semantics, the function drivers can be the same drivers that are used when the functions are packaged as individual devices.

  • Provide an INF file for each function of the device.

    The INF files can be the same files that are used when the functions are packaged as a individual devices. The INF files do not need any special multifunction semantics.


Using the System-Supplied Multifunction Bus Driver

If a device's underlying bus supports a multifunction bus standard, such as PC Card, the vendor for a multifunction device on an NT-based platform can use the system-supplied multifunction bus driver (mf.sys) to support the device.

The mf.sys bus driver handles PnP enumeration of the device functions and arbitrates resources, such as I/O ports and IRQs, between the functions. The mf.sys driver handles power management for the child functions by power managing the parent multifunction device.

To use mf.sys, a multifunction device must meet the following requirements:

  • The device's underlying bus must have a multifunction standard.
  • The DEVICE_CAPABILITIES of the child functions must be identical and must match those of the parent device. When queried for the device capabilities of a child function (IRP_MN_QUERY_CAPABILITIES), the mf.sys driver reports the device capabilities of the parent device.
  • The driver for the bus on which the multifunction device resides, such as pcmcia.sys, must handle any IRP_MN_READ_CONFIG and IRP_MN_WRITE_CONFIG requests. The mf.sys driver just passes these IRPs to the parent bus driver.
  • The functions must be independent: they cannot have start-order dependencies; the resource requirements for one function cannot be expressed in terms of the resources of another function (for example, function1 uses I/O port X and function2 uses portX + 200); and each function must be able to operate as a separate device, even if it is serviced by the same driver(s) as another function.

To use mf.sys, a vendor supplies an INF for the multifunction device that specifies mf.sys as the driver for the device. If a device completely and accurately conforms to the multifunction standard for its underlying bus, the vendor of such a device can use the system-supplied mf.inf. If a device does not completely conform to the standard, the vendor must provide a custom INF.

In either case, the vendor also supplies drivers and INF files for the individual functions on the device.

The following skeleton of a custom multifunction INF illustrates the required syntax for specifying mf.sys as the driver for a multifunction device:

[Version]
Signature = "$Windows NT$"
; ...
Class = Multifunction   ; the system-defined class for MF devices
ClassGUID  = {4d36e971-e325-11ce-bfc1-08002be10318} ; GUID for MF
; ...
; ...
[ControlFlags]
ExcludeFromSelect = *   ; don't include PnP devices in a displayed list of
                        ; devices available for manual installation
[Manufacturer]
; ...
; ...
[ModelsSection]         ; models section
; ...
; ...
[DDInstall.NT]          ; install section
Include = mf.inf        ; specify that this device requires mf.sys
Needs = MFINSTALL.mf
; ...

[DDinstall.NT.Services]
Include = mf.inf
Needs = MFINSTALL.mf.Services

[DDInstall.NT.HW]
AddReg=DDInstall.RegHW

[DDInstall.RegHW]
; put entries with child function hardware IDs here
; ...

; put override sections here...
; ...

[Strings]
; ...

Consider a combination LAN/modem PC Card device. Without any special multifunction support, such a device might be reported by the PCMCIA bus driver as a single modem device. With the additional support of a multifunction INF and the mf.sys bus driver, both functions of the device are enumerated. The following figure shows the sample device stacks that might be created for such a combo PC Card with the required multifunction support.

Sample Device Stacks for a Multifunction Device Enumerated by mf.sys

As shown in the preceding figure, the driver for the bus on which the multifunction device resides enumerates one device. The hardware ID in the multifunction INF file causes the PnP Manager to load the mf.sys bus driver as the function driver for the device. The mf.sys bus driver enumerates two child devices, a LAN device and a modem.

The PnP Manager treats each child device like a typical device, locating INF files, loading the appropriate drivers, calling their AddDevice routines, and so forth until a device stack is created for each device. The mf.sys bus driver arbitrates the resources for the child devices and manages any other multifunction aspects of the device. The vendor of the multifunction card provides function drivers and INFs for the multiple functions (LAN and modem), just as if they were separate devices.

The illustration focuses on the function drivers and parent bus drivers and their associated FDOs and PDOs. Any filter drivers (and filter DOs) are omitted for simplicity.


Creating Resource Maps for a Multifunction Device

A resource map identifies the resources of a multifunction device that are used by a child function. Resource maps are specified using an INF AddReg directive. If a multifunction device requires resource maps, the INF for the device typically contains a resource map for each function of the device.

There are two types of resource maps – standard resource maps and varying resource maps. This section describes how to construct resource maps and includes the following topics:

Creating Standard Resource Maps

Creating Varying Resource Maps

Some multifunction devices can be described using only standard resource maps. Others require varying resource maps, or a combination of standard and varying maps. Still others require no resource maps at all. See Supporting Multifunction PC Card Devices to determine which multifunction devices require resource maps.


Creating Standard Resource Maps

If a multifunction device's INF contains an INF DDInstall.LogConfigOverride section, the parent resources are implicitly numbered 00 through nn as they appear in the INF's log-config-section sections (see INF LogConfig Directive). For example, consider a multifunction PC Card with the following INF DDInstall.LogConfigOverride section:

[DDInstall.LogConfigOverride]
LogConfig = DDInstall.Override0

[DDInstall.Override0]    ;com2
IOConfig=2f8-2ff                      ; resource 00
IOConfig=20@100-FFFF%FFE0             ; resource 01
IRQConfig=3,4,5,7,9,10,11             ; resource 02
MemConfig=4000@0-FFFFFFFF%FFFFC000    ; resource 03
PcCardConfig=41:100000(W)             ; resource 04

The device in this example has five resources, which are numbered 00 through 04. If there is more than one DDInstall.LogConfigOverride section, the resources must be listed in the same order in each section.

If one child function (Child0000) requires the first and third resources listed above, the resource map for this child would be: 00,02. If another child function (Child00001) requires all five resources, then its resource map would be: 00,01,02,03,04. In this example, resources 00 (IoConfig=2f8-2ff) and 02 (IRQConfig=3,4,5,7,9,10,11) are shared. These resource maps would be specified in the INF as follows:

[DDInstall.RegHW]
    ; for each "child" function list hardware ID and resource map
HKR,Child0000,HardwareID,,child0000-hardware-ID
HKR,Child0000,ResourceMap,1,00,02                 ; map for Child0000
HKR,Child0001,HardwareID,,child0001-hardware-ID
HKR,Child0001,ResourceMap,1,00,01,02,03,04        ; map for Child0001

The "1" following the ResourceMap parameter specifies that the registry entry is a REG_BINARY data type. The numbers following the "1" are the resource map values.

If there are no DDInstall.LogConfigOverride sections in the INF, the parent resources are numbered in the order that the resource requirements are constructed by the driver for the underlying bus. For PC Cards, the bus driver reports resources in this order: IRQ, I/O ports, memory addresses. For multiple I/O and memory requirements, they are numbered in the same order as the tuples on the card. Other bus drivers might list resources in other orders.


Creating Varying Resource Maps

Windows XP and later

While standard resource maps can only assign an entire parent resource to a child of a multifunction device, varying resource maps let you subdivide a parent resource among children enumerated by mf.sys. Varying resource maps are supported on Windows XP and later versions of the NT-based operating system.

For example, consider a multi-port serial card on the PCI bus. Assume each of the card's 16550 UART functions requires a set of eight I/O ports and a single, shared interrupt. Also assume that the card is implemented as a single PCI function. In this scenario, it is typical to request a single block of I/O ports and to then split this block into eight segments, one for each 16550 UART function.

In addition to the I/O port and interrupt resources required by the card's 16550 UART functions, assume that the device also requires memory ranges and device-private resources.

Based on these assumptions, mf.sys will return a resource requirements list for this device, constructed as follows:

Resource Number | Resource
00 | Memory Range Base Register Address (BAR) 0
01 | Private Data
02 | Memory Range BAR 1
03 | Private Data
04 | I/O Port Range BAR 2
05 | Private Data
06 | Interrupt

Vendors use INF file directives to specify the sharing of these resources among the card's 16550 UART functions. For each function that requires a segment of the device's resources, you must use a VaryingResourceMap entry in the INF to create a registry entry. Following is an excerpt from the INF file for this device:

[DDInstall.RegHW]
; for each "child" function list hardware ID and resource map
; and/or varying resource map
HKR,Child0002,HardwareID,, child0002-hardware ID
HKR,Child0002,VaryingResourceMap,1,04, 10,00,00,00, 08,00,00,00
HKR,Child0002,ResourceMap,1,06

The line containing VaryingResourceMap is interpreted as follows:

  • The "1" following the VaryingResourceMap parameter specifies that the registry entry's data type is REG_BINARY.
  • The numbers following the "1" are the varying resource map values. The '04' indicates the parent resource, a segment of which we are assigning to this child. In this case, we're assigning a segment of resource 04 (BAR 2) to the child (that is, a piece of the resource representing the eight I/O port ranges for each serial port).
  • The next two DWORDs indicate, first, the offset into the resource and, second, the length of the range that should be allocated to this child. In this case, eight I/O ports are being allocated to this child, starting at offset 0x10 into the parent resource.
  • If this child required another parent resource, the resource's number, length, and offset would be included on the same line of the INF, following the first resource.

The ResourceMap parameter is described in Creating Standard Resource Maps and indicates that this child should get a share of resource 06, which in this case is the PCI device's interrupt.

Following is a more complete example for this device, specifying four child functions:

[Version]
Signature="$Windows NT$"
Class=MultiFunction
ClassGUID={4d36e971-e325-11ce-bfc1-08002be10318}
Provider=%MYCOMPANY%
LayoutFile=layout.inf
DriverVer=1/20/2000
[ControlFlags]
ExcludeFromSelect=*
[Manufacturer]
%MYCOMPANY%=MYCOMPANY

[MYCOMPANY]
%MYCOMPANY_4PORT%=MYCOMPANY4PORT_inst, PCI\VEN_10B5&DEV_9050&SUBSYS_003112E0

[MYCOMPANY4PORT_inst]
Include = mf.inf
Needs = MFINSTALL.mf

[MYCOMPANY4PORT_inst.HW]
AddReg=MYCOMPANY4PORT_inst.RegHW

[MYCOMPANY4PORT_inst.Services]
Include = mf.inf
Needs = MFINSTALL.mf.Services

[MYCOMPANY4PORT_inst.RegHW]
HKR,Child0000,HardwareID,,*PNP0501
HKR,Child0000,VaryingResourceMap,1,04, 00,00,00,00, 08,00,00,00
HKR,Child0000,ResourceMap,1,06
HKR,Child0001,HardwareID,,*PNP0501
HKR,Child0001,VaryingResourceMap,1,04, 08,00,00,00, 08,00,00,00
HKR,Child0001,ResourceMap,1,06
HKR,Child0002,HardwareID,,*PNP0501
HKR,Child0002,VaryingResourceMap,1,04, 10,00,00,00, 08,00,00,00
HKR,Child0002,ResourceMap,1,06
HKR,Child0003,HardwareID,,*PNP0501
HKR,Child0003,VaryingResourceMap,1,04, 18,00,00,00, 08,00,00,00
HKR,Child0003,ResourceMap,1,06

[Strings]
MYCOMPANY= "MYCOMPANY Inc."
MYCOMPANY_4PORT="MYCOMPANY 4PORT"


Using the Network Driver Design Guide

Windows-based operating systems support several types of kernel-mode network drivers. The network drivers documentation describes how to write these drivers. This topic briefly describes the supported network driver types and explains which sections of this guide you should read before writing each type of network driver.

Microsoft® Windows® 2000 and later versions of the operating system support four types of kernel-mode network drivers:

  • Miniport drivers

    A miniport driver directly manages a network interface card (NIC) and provides an interface to higher-level drivers.

  • Intermediate drivers

    An intermediate driver interfaces between upper-level protocol drivers, such as a legacy transport driver, and a miniport driver. A typical reason to develop an intermediate protocol driver is to perform media translation between an existing legacy transport driver and a miniport driver that manages a NIC for a new media type unknown to the transport driver.

  • Protocol drivers

    An upper-level protocol driver implements a TDI interface, or possibly an application-specific interface, at its upper edge to provide services to users of the network. At its lower edge, a protocol driver provides a protocol interface to pass packets to and receive incoming packets from the next-lower driver.

    Another type of protocol driver is a connection-oriented call manager. A call manager provides call setup and tear-down services for connection-oriented clients, which are also protocol drivers.

  • Filter-hook driver

    A filter-hook driver is used to filter packets. This driver extends the functionality of the IP filter driver, which is supplied with the operating system.

For general information about Windows network architecture and programming considerations, see Network Architecture for Kernel-Mode Drivers and Network Driver Programming Considerations. For information about network INF files, which are used to install network components, see Installing Network Components. If your network driver requires a notify object—for example, to control bindings—see also Nofity Objects for Network Components.

To find out which additional chapters to read for a particular driver type, see the following sections.

Miniport Drivers

There are several types of miniport drivers. Read the sections that are recommended for the type of driver you are writing:

To learn about connectionless miniport drivers
If you are writing a miniport driver that controls a NIC for connectionless network media, such as Ethernet, FDDI, or Token Ring; read:

NDIS Miniport Drivers

Overview of Miniport Driver Operations and Functions

Miniport Driver DriverEntry Function and Initialization

Transferring Data

Obtaining and Setting Miniport Driver Information and NDIS Support for WMI

Power Management for Miniport Drivers

Reset, Halt and Shutdown

To learn about connection-oriented miniport drivers
If you are writing a miniport driver that controls a NIC for connection-oriented network media, such as ATM or ISDN, read:

All the chapters listed for connectionless miniport drivers

Connection-Oriented NDIS

To learn about WAN miniport drivers
If you are writing a miniport driver that controls a WAN NIC, read:

All the chapters listed for connectionless miniport drivers

WAN Miniport Drivers

To learn about integrated miniport driver call managers (MCM)
If you are writing a miniport driver that controls a connection-oriented NIC and that also provides call manager services, read:

All the chapters listed for connectionless miniport drivers

Connection-Oriented NDIS

To learn about miniports with a WDM lower interface
If you are writing a miniport driver that has a WDM lower interface read:

All the chapters listed for connectionless miniport drivers

Miniport Driver with a WDM Lower Interface

To learn about IrDA miniport drivers
If you are writing a miniport driver that controls an IrDA adapter, read:

All the chapters listed for connectionless miniport drivers

IrDA Miniport Drivers

To learn about additional miniport capabilities
To learn about additional miniport capabilities, read:

Task Offload

Load Balancing and Fail Over

Intermediate Drivers

You can write an intermediate driver that has either a connectionless or a connection-oriented lower edge. Read the sections that are recommended for the type of driver you are writing:

To learn about intermediate drivers that have a connectionless lower edge
If you are writing an intermediate driver whose lower edge provides an interface to connectionless miniport drivers, read:

NDIS Intermediate Drivers

To learn about intermediate drivers that have a connection-oriented lower edge
If you are writing an intermediate driver whose lower edge provides an interface to connection-oriented miniport drivers, read:

NDIS Intermediate Drivers

Connection-Oriented NDIS

Protocol Drivers

You can write a protocol driver that has either a connectionless or a connection-oriented lower edge. In addition, your protocol driver can expose a transport driver interface (TDI) at its upper edge and can also provide Winsock support. Read the sections that are recommended for the type of driver you are writing:

To learn about protocol drivers that have a connectionless lower edge
If you are writing a protocol driver whose lower edge provides an interface to connectionless miniport drivers, read:

NDIS Protocol Drivers

To learn about protocol drivers that are connection-oriented clients, or that are connection-oriented providers of call manager services
If you are writing a connection-oriented client, which provides an interface to connection-oriented miniport drivers, or if you will be writing a connection-oriented call manager, read:

NDIS Protocol Drivers
Connection-Oriented NDIS

To learn about protocol drivers that have a TDI upper edge
If you are writing a protocol that has a TDI upper edge, read:

NDIS Protocol Drivers

TDI Transports and Their Clients

TDI Routines, Macros, and Callbacks

TDI Operations

To learn about protocol drivers that have Winsock support
If you are writing a protocol that provides Winsock support, read:

NDIS Protocol Drivers

Transport Helper DLLs for Windows Sockets

Filter-Hook Drivers

To learn about filter hook drivers, read the following section:

Filter Hook Driver


Network Architecture for Kernel-Mode Drivers

This section describes the network architecture used by kernel-mode drivers in Microsoft® Windows® 2000 and later operating systems. This section includes the following topics:

Windows 2000 and Later Network Architecture and the OSI Model

NDIS Network Drivers

Network Driver Environments


Windows 2000 and Later Network Architecture and the OSI Model

Microsoft® Windows® 2000 and later operating systems use a network architecture based on the seven-layer networking model developed by the International Standards Organization (ISO). Introduced in 1978, the ISO Open Systems Interconnection (OSI) Reference model describes networking as: "a series of protocol layers with a specific set of functions allocated to each layer. Each layer offers specific services to higher layers while shielding these layers from the details of how the services are implemented. A well-defined interface between each pair of adjacent layers defines the services offered by the lower layer to the higher one and how those services are accessed."

OSI Reference Model

In Windows 2000 and later versions of the operating system, network drivers implement the bottom four layers of the OSI Reference Model:

Physical Layer
This is the lowest layer of the OSI model. This layer is involves the reception and transmission of the unstructured raw bit stream over a physical medium. It describes the electrical/optical, mechanical, and functional interfaces to the physical medium. The physical layer carries the signals for all the higher layers. Under Windows 2000 and later versions, the physical layer is implemented by the network interface card (NIC), its transceiver, and the medium to which the NIC is attached. For network components that use serial ports, the physical layer can also include low-level network software that defines how the serial stream of bits is divided into packets of data.
Data Link Layer
This OSI layer is further divided by Institute of Electrical and Electronics Engineers (IEEE) into two sublayers: LLC and MAC. The LLC sublayer provides error-free transfer of data frames from one node to another. The LLC sublayer establishes and terminates logical links, controls frame flow, sequences frames, acknowledges frames, and retransmits unacknowledged frames. The LLC sublayer uses frame acknowledgement and retransmission to provide virtually error-free transmission over the link to the layers above. The MAC sublayer manages access to the network media, checks frame errors, and manages address recognition of received frames. In the network architecture used by Windows 2000 and later versions of the operating system, the Logical Link Control sublayer is implemented in the transport driver, while the Media Access Control sublayer is implemented in the network interface card (NIC). The NIC is controlled by a software device driver called the NIC driver. Windows 2000 and later versions of the operating system ship with NIC drivers for a number of popular NICs.
Network Layer
This layer controls the operation of the subnet. It determines the physical path the data should take, based on the following:
  • network conditions
  • priority of service
  • other factors, including routing, traffic control, frame fragmentation and reassembly, logical-to-physical address mapping, and usage accounting
Transport Layer
This layer ensures that messages are delivered error-free, in sequence, and with no loss or duplication. It relieves the higher-layer protocols from any concern with the transfer of data between them and their peers. A minimal Transport Layer is required in protocol stacks that include a reliable Network or Logical Link Control sublayer that provides virtual circuit capability. For example, because the NetBEUI transport driver for Windows 2000 and later versions includes an OSI-compliant LLC sublayer, its Transport Layer functions are minimal. If the protocol stack does not include an LLC sublayer, and if the Network Layer is unreliable and/or supports datagrams (as with TCP/IP's IP layer or NWLink's IPX layer), the Transport Layer should include frame sequencing and acknowledgment, as well as retransmission of unacknowledged frames.

In the network architecture used in Windows 2000 and later versions of the operating system, the Logical Link Control, Network, and Transport layers are implemented by software drivers known as transport drivers, which are sometimes referred to as protocols, protocol drivers, or protocol modules. Windows 2000 and later versions ship with TCP/IP, IPX/SPX, NetBEUI, and AppleTalk transport drivers.


NDIS Drivers

The Network Driver Interface Specification (NDIS) library abstracts the network hardware from network drivers. NDIS also specifies a standard interface between layered network drivers, thereby abstracting lower-level drivers that manage hardware from upper-level drivers such as network transports. NDIS also maintains state information and parameters for network drivers, including pointers to functions, handles, and parameter blocks for linkage, and other system values.

As the following figure shows, NDIS supports the following types of network drivers:

  • Miniport drivers
  • Intermediate drivers
  • Protocol drivers

NDIS Drivers

Built on Wednesday, July 11, 2001


NDIS Miniport Drivers

A NDIS miniport driver (also called a miniport driver) has two basic functions:

  • Managing a network interface card (NIC), including sending and receiving data through the NIC
  • Interfacing with higher-level drivers, such as intermediate drivers and transport protocol drivers

A miniport driver communicates with its NIC and with higher-level drivers through the NDIS library. The NDIS library exports a full set of functions (Ndis Xxx functions) that encapsulate all the operating system functions that a miniport driver needs to call. The miniport driver, in turn, must export a set of entry points (MiniportXxx functions) that NDIS calls for its own purposes or on behalf of higher-level drivers to access the miniport driver.

Send and receive operations illustrate the interaction of miniport drivers with NDIS and with higher-level drivers:

  • When a transport driver has a packet to transmit, it calls an Ndis Xxx function exported by the NDIS library. NDIS then passes the packet to the miniport driver by calling the appropriate MiniportXxx function exported by the miniport driver. The miniport driver then forwards the packet to the NIC for transmission by calling the appropriate Ndis Xxx functions.
  • When a NIC receives a packet addressed to the NIC, it can post a hardware interrupt that is handled by NDIS or the NIC's miniport driver. NDIS notifies the NIC's miniport driver by calling the appropriate MiniportXxx function. The miniport driver sets up the transfer of data from the NIC and then indicates the presence of the received packet to bound higher-level drivers by calling the appropriate Ndis Xxx function.

NDIS supports miniport drivers for both connectionless environments and connection-oriented environments.

Connectionless miniport drivers control NICs for connectionless network media, such as Ethernet, FDDI, and Token Ring. Connectionless miniport drivers are further divided into the following subtypes:

  • Serialized drivers that rely on NDIS to serialize calls to their MiniportXxx functions and to manage their send queues.
  • Deserialized drivers that serialize the operation of their own MiniportXxx functions and that queue internally all incoming send packets. This results in significantly better full-duplex performance, provided that the driver's critical sections (code which only a single thread at a time can execute) are kept small.

Connection-oriented miniport drivers control NICs for connection-oriented network media, such as ATM and ISDN. Connection-oriented miniport drivers are always deserialized — they always serialize the operation of their own MiniportXxx functions and queue internally all incoming send packets.

An NDIS miniport driver can have a non-NDIS lower edge (see the following figure).

NDIS Mininiport with Non-NDIS Lower Edge

Through its non-NDIS lower edge, a miniport driver uses the class interface for a bus such as the Universal Serial Bus (USB) or IEEE 1394 (firewire) to control a device on the bus. The miniport driver communicates with the device by sending I/O request packets (IRPs) either to the bus or directly to remote devices that are attached to the bus. At it's upper edge, the miniport driver exposes a standard NDIS miniport driver interface, which enables the miniport driver to communicate with overlying NDIS drivers.

NDIS also supports Wide Area Network (WAN) extensions for miniport drivers that manage WAN NICs. For more information on the WAN network environment, see Environment for WAN Network Drivers.


NDIS Intermediate Drivers

As the following figure illustrates, intermediate drivers are typically layered between miniport drivers and transport protocol drivers.

Intermediate Driver Layered Between Miniport Driver and Transport Driver

Because of its intermediate position in the driver hierarchy, an intermediate driver must communicate with both overlying protocol drivers and underlying miniport drivers in order to expose:

  • Protocol entry points

    At its lower edge, NDIS calls the ProtocolXxx functions to communicate requests from underlying miniport drivers. The intermediate driver looks a protocol driver to an underlying miniport driver.

  • Miniport driver entry points

    At its upper edge, NDIS calls the MiniportXxx functions to communicate the requests of one or more overlying protocol drivers. The intermediate driver looks like a miniport driver to an overlying protocol driver.

Although it exports a subset of the MiniportXxx functions at its upper edge, an intermediate driver does not actually manage a physical NIC. Instead, it exports one or more virtual adapters, to which overlying protocols can bind. To a protocol driver, a virtual adapter exported by an intermediate driver appears to be a physical NIC. When a protocol driver sends packets or requests to a virtual adapter, the intermediate driver propagates these packets and requests to the underlying miniport driver. When the underlying miniport driver indicates up receives packets, responds to a protocol's requests for information, or indicates status, the intermediate driver propagates such packets, responses, and status up to the protocol drivers that are bound to the virtual adapter.

Intermediate drivers are typically used to:

  • Translate between different network media

    For example, the function of an intermediate driver layered between Ethernet and Token Ring transports and an ATM miniport driver is to map Ethernet and Token Ring packets to ATM packets and vice versa.

  • Filter packets

    A packet scheduler is an example of an intermediate driver that is used as a filter driver. A packet scheduler reads priority information in each send packet passed down by a transport for transmission and each receive packet indicated up by a miniport driver. The packet scheduler then schedules each packet for transmission or reception based on its priority.

  • Balance packet transmission across more than one NIC

    A load balancing driver exposes one virtual adapter to overlying transport protocols but distributes send packets across more than one NIC.


NDIS Protocol Drivers

A network protocol, which is the highest driver in the NDIS hierarchy of drivers, is often used as the lowest-level driver in a transport driver that implements a transport protocol stack, such as a TCP/IP or IPX/SPX stack. A transport protocol driver allocates packets, copies data from the sending application into the packet, and sends these packets to the lower level driver by calling NDIS functions. A protocol driver also provides a protocol interface to receive incoming packets from the next lower-level driver. A transport protocol driver transfers received data to the appropriate client application.

At its lower edge, a protocol driver interfaces with intermediate network drivers and miniport drivers. The protocol driver calls Ndis Xxx functions to send packets, read and set information maintained by lower-level drivers, and use operating system services. The protocol driver also exports a set of entry points (ProtocolXxx functions) that NDIS calls for its own purposes or on behalf of lower-level drivers to indicate up receive packets, indicate the status of lower-level drivers, and to otherwise communicate with the protocol driver.

At its upper edge, a transport protocol driver has a private interface to a higher-level driver in the protocol stack.


TDI Drivers

The Transport Driver Interface (TDI) defines a kernel-mode network interface that is exposed at the upper edge of transport protocol stacks (see the following figure).

TDI Clients and Transports

TDI clients, which are kernel-mode drivers such as Redirector and Server, interface with such transports through TDI. TDI simplifies the task of developing transport drivers in that only the TDI interface needs to be coded. It also simplifies the task of developing clients by minimizing the amount of transport-specific code that must be written.

Transport drivers that expose only the TDI interface can be used only by TDI clients. To provide increased access to such transports, Windows 2000 and later versions include emulator modules for two popular existing network interfaces, Windows Sockets and NetBIOS. Each of these emulator modules exposes its native set of functions, which are accessible through standard call mechanisms in user mode. When called, the emulator module maps the native function and its associated parameters and procedural rules to one or more TDI functions, and then calls the indicated transport driver through TDI.

For increased performance, the TCP/IP and IPX/SPX transport drivers are implemented as native TDI transport drivers.


Network Driver Environments

This section describes the network environments used with Microsoft® Windows® 2000 and later operating systems for kernel-mode drivers including connectionless drivers, connection-oriented drivers, and WAN drivers. These network environments are described in the following topics:

Connectionless Environment for Network Drivers

Connection-Oriented Environment for Network Drivers

Environment for WAN Network Drivers


Connectionless Environment for Network Drivers

The connectionless environment is the standard network driver environment for connectionless media, such as Ethernet and Token Ring. For a description of the drivers in this environment, see NDIS Drivers.

The following figure shows the NDIS environment for connectionless network drivers.

Connectionless Network Driver Environment


Connection-Oriented Environment for Network Drivers

NDIS supports the following connection-oriented drivers:

  • Connection-oriented miniport drivers
  • Connection-oriented clients
  • Call managers
  • Integrated miniport call manager (MCM) drivers

The following figure shows a configuration of connection-oriented clients, a call manager, and a connection-oriented miniport driver.

Connection-Oriented Environment with a Call Manager

The following figure shows a configuration of connection-oriented clients and an MCM driver.

Connection-Oriented Environment with an MCM Driver

A connection-oriented miniport driver controls one or more network interface cards (NIC) and provides an interface between connection-oriented protocols (connection-oriented clients and call managers) and the NIC hardware.

A call manager is an NDIS protocol driver that provides call setup and tear-down services for connection-oriented clients. A call manager uses the send and receive capabilities of a connection-oriented miniport driver to exchange signaling messages with network entities, such as network switches or remote peers. A call manager supports one or more signaling protocols, such as ATM UNI 3.1 as specified by the ATM Forum.

An MCM driver is a connection-oriented miniport driver that also provides call manager services to connection-oriented clients. Although an MCM driver provides the same connection-oriented services to clients as does a call manager paired with a connection-oriented miniport driver, its call manager/miniport driver interface is internal to the driver and therefore opaque to NDIS.

More than one call manager and/or MCM driver can coexist in the same environment. Also, each call manager or MCM driver can support more than one signaling protocol.

A connection-oriented client uses the call-setup and tear-down services of a call manager or MCM driver. A connection-oriented client also uses the send and receive capabilities of a connection-oriented miniport driver or an MCM driver to send and receive data.

A connection-oriented client can be similar to a connectionless protocol in that it can, at its upper edge, provide its own network and transport-layer services to a higher-layer application. However, unlike a connectionless protocol, a connection-oriented client, at its lower edge, uses the services of a call manager and a connection-oriented miniport driver, or it uses the services of an MCM driver.

Alternatively, a connection-oriented client can be an adaptation layer (that can be an intermediate driver) residing between a legacy protocol and connection-oriented NDIS. Examples of such an adaptation layer are IP/ATM and LAN Emulation (LANE), both of which use call management services to establish underlying connections, but which hide the connection-oriented nature of this interface from the connectionless protocols above it. Note that the definition of such a connection-oriented client's upper-edge interface is beyond the scope of NDIS documentation. If a client is serving as an adaptation layer, its upper-edge interface is defined by the protocol that it is adapting to connection-oriented NDIS.

For more information on connection-oriented drivers, see Connection-Oriented Environment for Network Drivers.


Environment for WAN Network Drivers

Windows 2000 and later operating systems support wide area network (WAN) connections over both connectionless and connection-oriented media. The following figure shows the WAN environment.

WAN Environment for Windows 2000 and Later Operating Systems

The WAN environment includes the following components:

  • Remote Access Service (RAS)

    RAS allows user-mode applications to make dial-up connections. After a RAS connection has been established, a user application can connect to network services through a standard network interface, such as Windows Sockets, NetBIOS, Named Pipes, or RPC.

  • TAPI service provider

    The TAPI service provider is a user-mode component that accepts call setup and teardown requests from RAS clients and from TAPI-aware applications through the Service Provider Interface (SPI). The TAPI service provider converts such SPI requests to TAPI requests and sends the requests to NDISTAPI if the call is over connectionless media or to TAPI Proxy if the call is over connection-oriented media.

  • NDISTAPI

    NDISTAPI is a kernel-mode component that exposes connectionless miniport drivers to the TAPI device space. NDISTAPI accepts call setup and teardown requests from the TAPI service provider and directs such requests through NDISWAN to the correct miniport driver to set up, monitor, and tear down lines and calls.

  • NDPROXY

    The TAPI proxy is a kernel-mode component that exposes connection-oriented miniport drivers to the TAPI device space. NDPROXY serves as a call manager to NDISWAN and as a connection-oriented client to connection-oriented miniport drivers. For more information on the connection-oriented network environment, see Connection-Oriented Environment for Network Drivers.

  • NDISWAN

    NDISWAN is an intermediate NDIS driver that performs PPP protocol/link framing, compression, and encryption. NDISWAN converts an NDIS_PACKET from an upper-layer transport driver to an NDIS_WAN_PACKET and passes the reformatted packet to an underlying WAN miniport driver. NDISWAN supports both connectionless and connection-oriented miniport drivers.

    When functioning in a connection-oriented environment, NDISWAN acts as a connection-oriented client with respect to the TAPI proxy driver, which presents a call manager interface to NDISWAN.

  • WAN miniport driver

    A WAN miniport driver calls many of the same NDIS functions and supplies many of the same handlers as does a non-WAN NDIS miniport driver. A WAN miniport driver, however, calls special WAN-related NDIS functions when sending packets and when indicating receive packets to overlying protocols. WAN miniport drivers also use an NDIS_WAN_PACKET structure instead of an NDIS_PACKET structure. In addition, WAN miniport drivers maintain WAN-specific information and respond to WAN-specific queries of this information. A WAN miniport driver can support connectionless or connection-oriented media.

  • Serial driver

    The serial driver is a standard device driver for internal serial ports or multiport serial cards. The built-in asynchronous WAN miniport driver for Windows 2000 and later operating systems uses the internal serial driver for modem communications.


Network Driver Programming Considerations

Windows network drivers share similar design goals. Network drivers should be written to be portable, to be scalable, to provide simple configuration of hardware and software, to use object-based interfaces, and to support asynchronous I/O. This section describes how to apply these general design goals to the network drivers that you write for Microsoft® Windows® 2000 and later operating systems.

This section includes the following topics:

Portability

Multiprocessor Support

IRQLs

Synchronization and Notification

Packet Structure

Using Shared Memory

Asynchronous I/O and Completion Functions


Portability

NDIS drivers should be written so that they are easily portable across all platforms that support Windows 2000 and later operating systems. In general, porting from one hardware platform to another should only require recompilation with a system-compatible compiler.

Follow these guidelines for writing NDIS drivers:

  • Avoid calling operating system-specific functions; instead, use the NDIS equivalents. NDIS exports a rich set of support functions for writing drivers, and by calling these functions, you can port the code between Microsoft operating systems that support NDIS.
  • Write drivers in C; specifically, the ANSI C Standard. Avoid using any language features that are not supported by other system-compatible compilers. Do not use any features that the ANSI C standard designates as "implementation defined."
  • Avoid dependencies on data types whose size and layout vary across platforms. For example, do not write driver code that calls any C Run-Time Library functions instead of NDIS-provided functions.
  • Do not use floating point operations in kernel mode. Attempting such operations will result in a fatal error.
  • Use #ifdef and #endif statements to encapsulate code used to support platform-specific features.


Multiprocessor Support

Writing code to safely run on machines with more than one, concurrently executing processors is an essential part of writing a portable driver for Windows® 2000 and later versions. A network driver must be multiprocessor-safe and must use the provided NDIS library functions.

In a uniprocessor environment, a single processor runs only one machine instruction at a time, even though it is possible for a NIC or other device to interrupt the current execution stream when packets arrive or as timer interrupts occur. Typically, when manipulating data structures such as packet queues, a driver disables interrupts on the NIC, performs the manipulation, and then re-enables interrupts. Many threads in a uniprocessor environment appear to run simultaneously but actually run in interleaved time slices.

In a multiprocessor environment, processors simultaneously run several machine instructions. A driver must synchronize so that when one driver function manipulates common data structures, the same or another driver function on another processor does not attempt to modify shared data at the same time. All driver code is re-entrant in an SMP machine. To eliminate this resource protection problem, Windows 2000 and later device drivers use spin locks.

For NDIS miniport drivers, the NDIS library functions handle many of these multiprocessor considerations. The NDIS library queues requests and serializes calls to the standard miniport driver functions, unless the NIC is designed for either:

  • A connectionless network medium—The miniport driver is deserialized in design and implementation, whether because the NIC has some on-board support for packet queuing and synchronization or because the driver writer prefers to manage packets, queuing, and synchronization issues internally in the miniport driver.
  • A connection-oriented medium—NDIS assumes that the driver of any connection-oriented NIC is a deserialized miniport driver.


IRQLs

Every driver function called by NDIS runs at a system-determined IRQL, one of PASSIVE_LEVEL < DISPATCH_LEVEL < DIRQL. For example, a miniport driver's initialization function, halt function, reset function, and sometimes the shutdown function commonly run at PASSIVE_LEVEL. Interrupt code runs at DIRQL, so an NDIS intermediate or protocol driver never runs at DIRQL. All other NDIS driver functions run at IRQL <= DISPATCH_LEVEL.

The IRQL at which a driver function runs affects which NDIS functions it can call. Certain functions can only be called at IRQL PASSIVE_LEVEL. Others can be called at DISPATCH_LEVEL or lower. A driver writer should check every NDIS function for IRQL restrictions.

Any driver function that shares resources with the driver's ISR must be able to raise its IRQL to DIRQL to prevent race conditions. NDIS provides such a mechanism.


Synchronization and Notification

Whenever two threads of execution share resources that can be accessed at the same time, either in a uniprocessor machine or on an SMP machine, they need to be synchronized. For example, on a uniprocessor machine, if one driver function is accessing a shared resource, and is interrupted by another function that runs at a higher IRQL, such as an ISR, the shared resource must be protected to prevent race conditions that leave the resource in an indeterminate state. On an SMP machine, two threads could be running simultaneously on different processors and attempting to modify the same data. Such accesses must be synchronized.

NDIS provides spin locks that can be used to synchronize access to shared resources between threads that execute at the same IRQL. When two threads that share a resource execute at different IRQLs, NDIS provides a mechanism for temporarily raising the IRQL of the lower IRQL code so that access to the shared resource can be serialized.

When a thread is dependent on the occurrence of an event outside the thread, the thread relies on notification. For example, a driver might need to be notified when some time period has passed so that it can check its device. Or a NIC driver might have to perform a periodic operation such as polling. Timers provide such a mechanism.

Events provide a mechanism that two threads of execution can use to synchronize operations. For example, a miniport driver can test the interrupt on its NIC by writing to the device. It must wait for an interrupt to notify the driver that the operation was successful. Events can be used to synchronize an operation between the thread waiting for the interrupt to complete and the thread that handles the interrupt.

A description of these NDIS mechanisms follows.

Spin Locks

A spin lock provides a synchronization mechanism for protecting resources shared by kernel-mode threads running at IRQL > PASSIVE_LEVEL in either a uniprocessor or a multiprocessor machine. A spin lock handles synchronization among various threads of execution running concurrently on an SMP machine. A thread acquires a spin lock before accessing protected resources. The spin lock keeps any thread but the one holding the spin lock from using the resource. On a SMP machine, a thread that is waiting on the spin lock loops attempting to acquire the spin lock until it is released by the thread that holds the lock.

Another characteristic of spin locks is the associated IRQL. Attempted acquisition of a spin lock temporarily raises the IRQL of the requesting thread to the IRQL associated with the spin lock. This prevents all lower IRQL threads on the same processor from preempting the executing thread. Threads, on the same processor, running at a higher IRQL can preempt the executing thread, but these threads cannot acquire the spin lock because it has a lower IRQL. Therefore, once a thread has acquired a spin lock, no other threads can acquire the spin lock until it has been released. A well-written network driver minimizes the amount of time a spin lock is held.

A typical use for a spin lock is to protect a queue. For example, the miniport driver send function, MiniportSend, might queue packets passed to it by a protocol driver. Because other driver functions also use this queue, MiniportSend must protect the queue with a spin lock so that only one thread at a time can manipulate the links or contents. MiniportSend acquires the spin lock, adds the packet to the queue and then releases the spin lock. Using a spin lock ensures that the thread holding the lock is the only thread modifying the queue links while the packet is safely added to the queue. When the miniport driver takes the packets off the queue, such an access is protected by the same spin lock. When executing instructions that modify the head of the queue or any of the link fields making up the queue, the driver must protect the queue with a spin lock.

A driver must take care not to overprotect a queue. For example, the driver can perform some operations (for example, filling in a field containing the length) in the network driver-reserved field of a packet before it queues the packet. The driver can do this outside the code region protected by the spin lock, but must do it before queuing the packet. Once the packet is on the queue and the executing thread releases the spin lock, the driver must assume that other threads can dequeue the packet immediately.

Avoiding Spin Lock Problems

Windows® 2000 and later operating systems do not restrict a network driver from simultaneously holding more than one spin lock. However, if one section of the driver attempts to acquire spin lock A while holding spin lock B, and another section attempts to acquire spin lock B while holding spin lock A, deadlock results. If it acquires more than one spin lock, a driver should avoid deadlock by enforcing an order of acquisition. That is, if a driver enforces acquiring spin lock A before spin lock B, the situation described above will not occur.

Acquiring a spin lock raises the IRQL to DISPATCH_LEVEL and stores the old IRQL in the spin lock. Releasing the spin lock sets the IRQL to the value stored in the spin lock. Because NDIS sometimes enters drivers at PASSIVE_LEVEL, problems can arise with the following code sequence:

NdisAcquireSpinLock(A);
NdisAcquireSpinLock(B);
NdisReleaseSpinLock(A);
NdisReleaseSpinLock(B);

A driver should not access spin locks in this sequence for the following reasons:

  • Between releasing spin lock A and releasing spin lock B the code is running at PASSIVE_LEVEL instead of DISPATCH_LEVEL and is subject to inappropriate interruption.
  • After releasing spin lock B the code is running at DISPATCH_LEVEL which could cause the caller to fault at much later time with an IRQL_NOT_LESS_OR_EQUAL stop error.

Using spin locks impacts performance and, in general, a driver should not use many spin locks. Occasionally, functions that are usually distinct (for example, send and receive functions) have minor overlaps for which two spin locks can be used. Use of more than one spin lock might be a worthwhile tradeoff in order to allow the two functions to operate independently on separate processors.

Timers

Timers are used for polling or timing out operations. A driver creates a timer and associates a function with the timer. The associated function is called when the period specified in the timer expires. Timers can be one-shot or periodic. Once a periodic timer is set, it will continue to fire at the expiration of every period until explicitly cleared. A one-shot timer must be reset each time it fires.

Timers are created and initialized by calling NdisMInitializeTimer, and set by calling NdisMSetTimer or for a periodic timer, by calling NdisMSetPeriodicTimer. If a nonperiodic timer is used, it must reset by calling NdisMSetTimer. A timer is cleared by calling NdisMCancelTimer.

Events

Events are used to synchronize operations between two threads of execution. An event is allocated by a driver and initialized by calling NdisInitializeEvent. A thread running at IRQL PASSIVE_LEVEL calls NdisWaitEvent to put itself into a wait state. When a driver thread waits on an event, it specifies a maximum time to wait as well as the event to be waited on. The thread's wait is satisfied when NdisSetEvent is called causing the event to be signaled, or when the specified maximum wait-time interval expires, whichever occurs first.

Typically, the event is set by a cooperating thread that calls NdisSetEvent. Events are unsignaled when they are created and must be set in order to signal waiting threads. Events remain signaled until NdisResetEvent is called.


Packet Structure

NDIS packets are allocated by a protocol driver, filled with data, and passed to the next lower NDIS driver so that the data can be sent on the network. Some lowest level NIC drivers allocate packets to hold received data and pass the packet up to interested higher-layer drivers. Sometimes, a protocol driver allocates a packet and passes it to a NIC driver with a request that the NIC driver copy received data into the provided packet. NDIS provides functions for allocating and manipulating the substructures that make up a packet. The following figure illustrates a structure of a packet.

Packet Structure

A packet is composed of the following:

  • A packet descriptor that contains private areas for the miniport driver and a protocol driver, a set of flags associated with the packet and whose meaning is defined by a cooperating miniport driver(s) and protocol driver(s), the number of physical pages that contain the packet, the total length of the packet, and a pointer to the first buffer descriptor that maps the first buffer in the packet.
  • A set of buffer descriptors. A buffer descriptor describes the starting virtual address of each buffer, the buffer's byte offset into the page pointed to by the virtual address, the total number of bytes in the buffer and a pointer to the next buffer descriptor, if any.
  • The virtual range, possibly spanning more than one page, that makes up the buffer described by the buffer descriptor. These virtual pages map to physical memory.

A bus-master NIC driver that allocates shared memory for receiving incoming packets or a protocol driver that allocates memory for sending a packet must insure that any buffer used to contain incoming or outgoing data is cache-aligned. This is necessary so that the miniport driver can flush the buffer to assure coherency before sending a packet and to flush a received buffer before indicating the data to an upper layer.


Using Shared Memory

Miniport drivers for bus-master DMA devices must allocate shared memory for use by the NIC and the NIC driver. Special precautions are necessary when sharing cached memory between such a driver and its NIC. On certain architectures, specific steps must be taken to insure that the memory is coherent because the NIC can access the shared physical memory directly, while the NIC driver accesses memory through the cache. This can cause differences in what the driver and the NIC detect in memory, even if they look at the same location.

The use of noncached shared memory avoids most of the problems associated with cached shared memory. However, noncached memory is a scarce system resource and allocation of such memory can be limited. When data written to physical memory must use a small write queue, even noncached data might not appear in physical memory immediately. Additionally, there are cases when using noncached memory is neither recommended nor possible. For example, data that the NIC driver reads repeatedly should always be cached to improve performance. Or, as another example, a NIC driver might be required to pass a received data packet to a number of different protocol drivers. Cached memory would be highly recommended in these cases. The NIC driver should also use cached memory for any data passed in by a protocol driver.

NdisMAllocateSharedMemory can be called by a bus-master NIC driver to allocate memory for permanent sharing between the network adapter and the NIC driver. This function returns a virtual address and a physical address for the shared memory. The addresses are valid until a call to NdisMFreeSharedMemory frees the memory.

When shared cached memory is used, NDIS provides a function that must be called by the NIC driver to insure coherency between what the NIC sees and what the NIC driver sees. Before accessing the shared memory on a send or on a receive, the NIC driver must call NdisFlushBuffer and also NdisMUpdateSharedMemory to ensure cache coherence.


Asynchronous I/O and Completion Functions

Because of the latency inherent in some network operations, many of the upper-edge functions provided by a NIC driver and the lower-edge functions of a protocol driver are designed to support asynchronous operation. Rather than wasting CPU cycles waiting in a loop for some time-consuming task to finish or a hardware event to signal, network drivers rely on the ability to handle most operations asynchronously.

Asynchronous network I/O is supported by using a completion function. The following example illustrates using a completion function for a network send operation, but this same mechanism exists for many other operations performed by a protocol or NIC driver.

When a protocol driver calls NDIS to send a packet, resulting in a call to the NIC driver's MiniportSend function, the NIC driver can try to complete this request immediately and return an appropriate status value as a result. For synchronous operation, the possible responses are NDIS_STATUS_SUCCESS for successful completion of the send, NDIS_STATUS_RESOURCES, and NDIS_STATUS_FAILURE indicating a failure of some kind.

But a send operation can take some time to complete while the NIC driver (or NDIS) queues the packet and waits for the NIC to indicate the result of the send operation. The NIC driver MiniportSend function can handle this operation asynchronously by returning a status value of NDIS_STATUS_PENDING. When the NIC driver completes the send operation, it calls the completion function, NdisMSendComplete, passing a pointer to the packet descriptor that was sent. This information is passed to the protocol driver, signaling completion.

Most driver operations that can require an extended time to complete support asynchronous operation with a similar completion function. Such functions have names of the form NdisM Xxx Complete.

Completion functions are also provided for:

  • setting and querying configuration.
  • resetting hardware.
  • indicating status.
  • indicating received data.
  • transferring received data.


NDIS Versions

If you are writing an NDIS driver for more than one version of Windows, be sure the features you are using are supported on each Windows version. New features have been added to NDIS with each release. Also, some features have become obsolete and have been removed from later NDIS versions.

Windows operating system and DDK version support for NDIS versions, and support for major NDIS features across NDIS versions, are described in the following table:

Operating System | Supported NDIS Version | CoNDIS | Deserialized Driver | Intermediate Driver
Windows 95 Windows NT 4.0 DDK Windows 95 DDKs | 3.1 |  |  |
 | Added support for miniport drivers and Plug and Play.
Windows 95 OSR2 Windows NT 4.0 DDK Windows 95 DDK | 4.0 |  |  |
 | Protocol driver is a vxd-type driver.
Windows 98 Windows NT4.0 DDK Windows 98 DDK | 4.1 | X | X | X
 | Protocol driver is a vxd-type driver.
Windows 98 SE Windows NT 4.0 DDK Windows 98 DDK | 5.0 | X | X | X
 | Added support for Power Management and WMI.
Windows Me Windows 2000 DDK Windows 98 DDK for Vxds | 5.0 | X | X | X
Windows NT 3.5 Windows NT 3.5 DDK | 3.0 |  |  |
Windows NT 4.0 Windows NT 4.0 DDK | 4.0 |  |  |
 | Added these features: • MiniportSendPackets • ProtocolReceivePacket • MiniportAllocateComplete
Windows NT 4.0 SP3 Windows NT DDK with updated NDIS header and library | 4.1 | X | X | X
Windows 2000 Windows 2000 DDK | 5.0 | X | X | X
 | Added support for: • New INF file format compatible with Windows 95/98/Me • Plug and Pay and Power Management • WMI • LBFO • Scatter/gather DMA support for deserialized miniport drivers
Windows XP Windows XP DDK | 5.1 | X | X | X
 | Added support for: • MiniportCancelSendPackets • MiniportPnPEventNotify • MiniportShutdown • Scatter/gather support for both serialized and deserialized miniport drivers • Packet stacking for intermediate drivers • VLAN tagging Dropped support for: • Full Mac drivers • NDIS 3.0 protocols


NDIS Miniport Drivers

This section introduces miniport drivers for Windows® 2000 and later versions of the operating system. This section includes the following topics:

Types of NDIS Miniport Drivers

Network Interface Card Support

Important Features of Miniport Driver Code

Sample NDIS Miniport Drivers


Types of NDIS Miniport Drivers

NDIS supports basic types of network interface card (NIC) drivers. These NDIS miniport drivers are described in the following topics:

Deserialized NDIS Miniport Drivers

Serialized NDIS Miniport Drivers

Connection-Oriented NDIS Miniport Drivers

NDIS Miniport Drivers with a WDM Lower Edge


Deserialized NDIS Miniport Drivers

A deserialized NDIS miniport driver serializes the operation of its own MiniportXxx functions and queues internally all incoming send packets rather than relying on NDIS to perform these functions. By doing so, a deserialized miniport driver can achieve significantly better full-duplex performance than a serialized miniport driver.

The deserialized driver model is the default model for NDIS miniport drivers. When writing a new NDIS miniport driver, you should write a deserialized driver. Note that connection-oriented miniport drivers, as well as miniport drivers with a WDM lower edge, must be deserialized.

A deserialized miniport driver must meet the following requirements when interfacing with NDIS:

  • A deserialized miniport driver must identify itself as such to NDIS during initialization. Its MiniportInitialize function must call NdisMSetAttributesEx with the NDIS_ATTRIBUTES_DESERIALIZE flag set in the AttributeFlags.
  • A deserialized miniport driver's MiniportSendPackets function cannot synchronously complete a multipacket send. Instead, it must always complete each packet asynchronously with NdisMSendComplete for each packet in the incoming array.
  • A deserialized miniport driver's MiniportSendPackets function usually ignores the Status member of the NDIS_PACKET_OOB_DATA block, but it can set this member to the same status that it will pass to NdisMSendComplete.
  • If a deserialized miniport driver cannot immediately transmit incoming send packets, it cannot return the packets to NDIS for requeuing. Instead, the miniport driver must queue them internally until sufficient resources are available to transmit the packets. A deserialized miniport driver's MiniportSend or MiniportSendPackets function cannot return NDIS_STATUS_RESOURCES.
  • A deserialized miniport driver must not examine the Status of indicated packets on return of NdisMIndicateReceivePacket. Instead, a deserialized miniport driver must save a packet's Status in a local variable before indicating up the packet descriptor. If the miniport driver set the packet's Status to NDIS_STATUS_SUCCESS before indicating up the packet descriptor, the miniport driver must not reclaim the packet descriptor until NDIS subsequently returns the packet descriptor to the miniport driver's MiniportReturnPacket function.

A deserialized miniport driver must meet the following driver-internal requirements:

  • A deserialized miniport driver must protect its packet queues with spin locks. A deserialized miniport driver must also protect its shared state from simultaneous access by its own MiniportXxx functions. For more information about using spin locks, see Introduction to Spin Locks.
  • A deserialized miniport driver's MiniportXxx functions can run at IRQL <= DISPATCH_LEVEL. Consequently, the driver writer cannot assume that MiniportXxx functions will be called in the sequence in which they process packets. One MiniportXxx function can pre-empt another MiniportXxx function that is running at a lower IRQL.
  • A deserialized miniport driver is responsible for packet-queue management. When the miniport driver experiences a resource problem, it cannot return send packets to NDIS for requeuing. Instead, the miniport driver must queue internally all incoming packets until sufficient resources are available to send the packets.
  • A deserialized miniport driver must transmit each array of packets in the protocol-determined order. That is, the miniport driver must transmit the first packet in the array first, the second packet in the array second, and so forth. The miniport driver cannot reorder the packets in any given array.

Note that a deserialized miniport driver usually transmits packets in protocol-determined order. However, a miniport driver that supports packet priority (for example, IEEE 802.1p) can reorder packets based on priority information.


Serialized NDIS Miniport Drivers

A serialized driver controls a NIC for connectionless media, such as Ethernet, FDDI, and Token Ring. Unlike a deserialized miniport driver, a serialized miniport driver relies on NDIS to serialize the operation of its own MiniportXxx functions and to manage the queue for send packets.

Serialized miniport drivers are legacy drivers. If you are writing a new miniport driver, write a deserialized driver. For more information on deserialized drivers, see Deserialized NDIS Miniport Drivers.


Connection-Oriented NDIS Miniport Drivers

A connection-oriented miniport driver controls one or more NICs for connection-oriented media, such as ATM. Connection-oriented miniport drivers must be deserialized. For more information on deserialized drivers, see Deserialized NDIS Miniport Drivers.

A connection-oriented miniport driver provides an interface between connection-oriented protocols (connection-oriented clients and call managers) and the NIC hardware. For a summary of connection-oriented operations performed by a connection-oriented miniport driver, see Connection-Oriented Operations Performed by Miniport Drivers.

A connection-oriented miniport drivers must register the following MiniportXxx functions that are specific to connection-oriented operations:

MiniportCoCreateVc

MiniportCoDeleteVc

MiniportCoActivateVc

MiniportCoDeActivateVc

MiniportCoSendPackets

MiniportCoRequest

For more information on registering these functions, see NdisMRegisterMiniport.


NDIS Miniport Drivers with a WDM Lower Edge

You can write an NDIS miniport driver that controls a device on a bus—for example, the Universal Serial Bus (USB) or the IEEE 1394 (firewire) bus. Such a miniport driver must expose a standard NDIS miniport driver interface at its upper edge and use the class interface for the particular bus at its lower edge. The miniport driver communicates with devices that are attached to the bus by sending I/O request packets (IRPs) to the bus through its Windows Driver Model (WDM) lower interface.

A miniport driver with a WDM lower edge must be deserialized. For more information on deserialized drivers, see Deserialized NDIS Miniport Drivers.

For more information on miniport drivers with a WDM lower edge, see Miniport Driver with a WDM Lower Interface.


Network Interface Card Support

Windows® 2000 and later versions of the operating system support the following types of network interface cards:

  • Ethernet (802.3)
  • Token Ring (802.5)
  • FDDI
  • LocalTalk
  • Raw ARCNET (ARCNET encapsulated in Ethernet)
  • ARCNET 878.2
  • WAN (point-to-point and WAN cards)
  • Connection-oriented WAN
  • Wireless
  • ATM
  • IrDA

When NDIS calls a NIC driver's MiniportInitialize function, it passes an array of NDIS-supported mediums. If the NIC driver supports only one medium type, it selects the medium that it supports. Or, if the NIC driver supports more than one medium type, it selects the one that it prefers and returns its choice to NDIS.

When a higher level NDIS protocol driver calls NdisOpenAdapter to bind to a specified NIC, it provides a list of medium types on which it can operate. NDIS uses the information from the NIC driver and from the protocol driver to bind them appropriately. This binding provides the path by which packets are passed down the stack and sent out over the network and by which received packets are passed up the stack to higher level drivers.

The NDIS medium type defined for ARCNET is NdisMediumArcnet878_2. This medium type definition provides full compatibility with Novell's ARCNET specification for Raw ARCNET.

The Raw ARCNET format, defined in the ARCNET Packet Header Definition Standard published by Novell, is used by NetWare. A transport driver that supports this format is responsible for selecting from three different frame formats (short, long, or exception), depending on the length of the data it wishes to send. The transport driver is then responsible for performing the necessary actions related to the use of this standard, including fragmenting, padding, and setting the split flag and sequence number.

The NdisMediumArcnet878_2 format informs a transport driver that it is running over ARCNET, without having to deal with the details of fragmenting and unfragmenting. With NdisMediumArcnet878_2, the on-the-wire format is the same as the Raw ARCNET format. However, the transport driver is shielded from most of the details of the frame format. The NIC driver is responsible for fragmenting the frame, selecting the appropriate frame format, and inserting the padding, split flag, sequence number, and other related fields.

The NDIS Library also supports Ethernet over ARCNET. NDIS performs 802.3-to-ARCNET encapsulation on packets to be sent and de-encapsulation on packets received from ARCNET miniport drivers.

The Tcpip and Nwlink transport drivers for Windows® 2000 and later versions use NdisMediumArcnet878_2.

A NIC driver that supports the NdisMediumAtm format can use NDIS 5.0's native support for ATM.

A NIC driver that supports the NdisMediumIrda format can use NDIS 5.0's native support for infrared devices.

Types of NICs

The Ndis Xxx functions that a miniport driver calls to initialize its adapter and to send and receive packets depend on the features of its NIC, as follows.

  • Bus-master DMA NICs

    These NICs can directly access host memory through an on-board DMA controller that manages the transfer of data between the network and host memory without using the host CPU.

    To send, the miniport driver sets up the NIC to map the outgoing buffers. The miniport driver then causes the device to start its transfer from this memory. The NIC DMA controller transfers the data from shared system memory onto the network and interrupts the CPU when the send is complete. To receive, the DMA controller transfers incoming data to host memory before notifying the host with an interrupt.

    A bus-master DMA NIC typically has an onboard ring buffer that the miniport driver maps to a set of buffers in system memory. Typically, the NIC can be programmed to efficiently handle several packets. A miniport driver that manages such a NIC usually supports multipacket sends and receives since the NIC can efficiently handle several packets and thereby improve its I/O throughput.

  • Non-bus-master DMA NICs

    These include three general types of NICs:

    1. NICs that contain on-board shared memory

      A miniport driver that manages such a NIC must map the NIC's shared memory to host memory, and then copy outgoing packets to the NIC memory or copy incoming frames from NIC memory to buffers supplied by upper layer protocol drivers or other drivers. Such a miniport driver generally cannot improve its performance by supporting multipacket sends and receives.

    2. Slave DMA NICs

      A miniport driver that manages such a NIC uses the system DMA controller to manage the transfer of packet data to and from the network. Transfer of the data requires the cooperation of the host CPU.

    3. NICs that use programmed I/O

      The miniport driver that manages a PIO device uses NDIS functions to move outgoing frames byte by byte, word by word, or long by long to device registers, and then causes the device to send the data. The driver for such a device does not benefit from NDIS support for multipacket sends and receives. Miniport drivers for this type of NIC should implement single packet sends and receives, as described in Transferring Data.


Important Features of Miniport Driver Code

This section introduces major features of miniport driver code. These features are described in the following topics:

MiniportXxx Functions

Linking to the NDIS Library

Miniport Driver Adapter Context

Virtual Connection Context

Network OIDs


MiniportXxx Functions

The typical miniport driver uses a small number of functions to communicate through NDIS with the upper layers and hardware. The complete list of upper-edge (MiniportXxx) functions that NDIS can call to communicate with a miniport driver, whether on its own behalf or on the behalf of protocol drivers, is provided in Miniport Driver Upper Edge Functions; not all of these functions are required. For information about which functions are optional, which are required, and why, see Registering MiniportXxx Functions.

NDIS miniport drivers and upper-layer drivers use the NDIS Library (ndis.sys) to communicate with each other through calls to Ndis Xxx functions. A summary of the Ndis Xxx functions and macros that a miniport driver can call is provided in NDIS Functions Called by Miniport Drivers.

Many miniport driver functions can operate either synchronously or asynchronously. The asynchronous functions have Ndis Xxx…Complete functions that must be called when an operation is finished. For example, if a protocol driver calls NdisRequestto query miniport driver information, the miniport driver's MiniportQueryInformation function can pend the reset operation by returning NDIS_STATUS_PENDING. Eventually, the MiniportReset function must call NdisMQueryInformationComplete to indicate the final status of the query request. For more information about asynchronous MiniportXxx functions and the corresponding completion functions, see Overview of Miniport Driver Operations and Functions.


Linking to the NDIS Library

The NDIS Library is packaged in ndis.sys, a kernel-mode export library as a set of functions, with emphasis on macros for maximum performance. (An export library is a .sys file that functions similarly to a dynamic-link library.) The NDIS Library functions are described in the Network Driver Reference. Both protocol and NIC drivers, including WAN NIC drivers, link themselves to the NDIS Library. The NDIS Library functions are described in the Network Driver Reference.

The Windows DDK provides ndis.h as the main header file for miniport drivers. This file defines the entry points for the miniport driver, the NDIS Library functions, and common data structures. The Network Reference describes the miniport driver, protocol driver, and Ndis Xxx functions, as well as the common data structures and OIDs.


Miniport Driver Adapter Context

NDIS uses a software object called a logical adapter to represent each NIC in the system. This object is maintained by NDIS and is opaque to the miniport driver and to protocol drivers. NDIS passes a handle to this structure to the NIC driver's MiniportInitialize function. The miniport driver subsequently supplies this handle in all calls to Ndis Xxx functions that pertain to the NIC designated by the handle.

When a miniport driver is called to initialize a NIC it manages, it creates its own internal data structure to represent the NIC. The driver uses this structure, referred to as the miniport driver adapter context, to maintain device-specific state information it needs to manage the NIC. The driver passes a handle to this structure to NDIS when its MiniportInitialize function calls NdisMSetAttributes or NdisMSetAttributesEx. When NDIS calls one of the miniport driver's MiniportXxx functions that pertains to the NIC, it passes this handle to identify the correct NIC to the driver. The miniport driver adapter context is owned and maintained by the miniport driver and is opaque to NDIS and to protocol drivers.


Virtual Connection Context

Before making a call, a connection-oriented client requests a connection-oriented miniport driver to set up a virtual connection (VC) over which packets can be transmitted and/or received. Similarly, before indicating an incoming call to a connection-oriented client, a call manager or integrated miniport call manager (MCM) driver requests the miniport driver to set up a VC for the incoming call. A virtual connection is a logical connection between two connection-oriented entities. Connection-oriented transmissions and receptions always occur on a specific VC.

A connection-oriented miniport driver maintains state information in a miniport driver-allocated context area about each VC that it sets up. This per-VC context is maintained by the miniport driver and is opaque to NDIS and to protocol drivers. In its MiniportCoCreateVc function, a connection-oriented miniport driver passes a handle to the VC context area to NDIS, and NDIS passes an NdisVcHandle that uniquely identifies the created VC back to the miniport driver, to the appropriate connection-oriented client, and to the call manager or integrated miniport call manager (MCM) driver.

Before data can be sent or received on a VC, the VC must be activated. The call manager initiates activation of the VC by calling Ndis(M)CmActivateVc and passing call parameters that include the characteristics of the VC to be activated. In response to this call, NDIS calls the miniport driver's MiniportCoActivateVc function, which activates the VC.

After a call is complete or a VC is otherwise not needed, the call manager can deactivate the VC by calling Ndis(M)CmDeactivateVC, which causes NDIS to call the miniport driver's MiniportC0DeactivateVc function. Either the connection-oriented client or the call manager can initiate the deletion of the VC by calling NdisCoDeleteVc, which causes NDIS to call the miniport driver's MiniportCoDeleteVc function.

For more information on miniport driver operations on VCs, see Operations on VCs.


Network OIDs

A miniport driver maintains information about its capabilities and current status, as well as information about each NIC that it controls. Each information type is identified by an object identifier (OID). OIDs are system-defined.

NDIS and higher level drivers can query and, in some cases, set information using OIDs.

  • Higher level drivers for connectionless media call NdisRequest to query or set information in a connectionless miniport driver. To perform a query operation, NDIS calls the miniport driver's MiniportQueryInformation function. To perform a set operation, NDIS calls the miniport driver's MiniportSetInformation function.
  • Higher level drivers for connection-oriented media call NdisCoRequest to query or set information in a connection-oriented miniport driver. To perform both query and set operations, NDIS calls the miniport driver's MiniportCoRequest function.

NDIS maps many of the system-defined OIDs for miniport drivers to globally unique identifiers (GUIDs). NDIS registers these GUIDs with the kernel-mode Windows Management Instrumentation (WMI) that supports user-mode Web-Based Enterprise Management (WBEM) applications. When a WMI client queries or sets one of these GUIDs, NDIS translates the request to a query OID operation or a set OID operation, as appropriate, and then passes any returned information and the status back to WMI. Driver writers can map custom GUIDs to custom OIDs or miniport driver status. A miniport driver must register custom GUID-to-OID or GUID-to-status mappings with NDIS during initialization.

For more information on querying and setting OIDs, creating custom OIDs, and NDIS support for WMI, see Obtaining and Setting Miniport Driver Information.


Sample NDIS Miniport Drivers

The DDK includes sample code for miniport drivers that manage several types of network cards. These sample drivers can be tailored to a driver developer's needs. The sample drivers contain functions that can be adapted to a new but similar driver. There are always hardware-dependent functions that must be written by the driver developer. However, many functions are fairly standard. For example, functions that communicate with the NDIS Library instead of a network interface card are generally standard. For these driver functions, the code in a sample driver might be usable with little or no modification.


Overview of Miniport Driver Operations and Functions

This section provides an overview of miniport driver operations, such as initializing and sending data. These operations involve the use of both MiniportXxx functions and Ndis Xxx functions. This section also provides an overview of the MiniportXxx functions that miniport drivers export and the Ndis Xxx functions miniport drivers call.

This section includes the following topics:

Miniport Driver Operations

Miniport Driver Upper-Edge Functions

NDIS Functions Called by Miniport Drivers


Miniport Driver Operations

Miniport drivers perform numerous operations. These operations are described in the following topics:

Initializing the NDIS Library and Registering the Miniport Driver

Initializing Network Interface Cards

Responding to Queries and Sets of Miniport Driver Information

Creating, Activating, Deactivating, and Deleting Virtual Connections

Sending Data

Indicating and Transferring Received Data

Indicating Status

Resetting a Network Interface Card

Halting a Miniport Driver


Initializing the NDIS Library and Registering the Miniport Driver

When a miniport driver is loaded, the operating system creates a driver object for the miniport driver and calls the DriverEntry function of that driver. Within the context of its DriverEntry function, the miniport driver calls:

  • NdisMInitializeWrapper, with the address of the driver object and the associated registry path to the driver-specific information
  • NdisMRegisterMiniport, to register itself with NDIS, indicating which NDIS version it is compatible with and supplying the entry points of its upper-edge (MiniportXxx) functions. The NDIS Library saves these entry points for use in subsequent calls to the miniport driver.

If the call to NdisMRegisterMiniport or NdisIMRegisterLayeredMiniport does not return NDIS_STATUS_SUCCESS:

  • DriverEntry returns the value returned by NdisMRegisterMiniport or NdisIMRegisterLayeredMiniport.
  • DriverEntry calls NdisTerminateWrapper, which causes NDIS to clean up the resources it allocated when the miniport driver called NdisMInitializeWrapper.

For a detailed description of the DriverEntry function, see NDIS Miniport Driver DriverEntry Function.


Initializing Network Interface Cards

Before it receives and sends packets on the network, a miniport driver must initialize each network interface card (NIC) that it manages.

The MiniportInitialize function:

  • Allocates memory for the adapter-specific context area where it maintains the NIC's run-time state.
  • Obtain a list of hardware resources for the NIC by calling NdisMQueryAdapterResources.
  • Reads the configuration registry database to determine advanced parameters for the NIC it is initializing. The miniport driver stores this information in the adapter-specific context area for the NIC.
  • Reads bus-specific information maintained by the I/O bus, if available.
  • Registers the NIC with NDIS by calling NdisMSetAttributesEx. A deserialized miniport driver must call NdisMSetAttributesEx with the NDIS_ATTRIBUTE_DESERIALIZE flag set to indicate that it is deserialized.
  • Claims the system resources required to operate the NIC. These resources include memory for packets and buffers, I/O port addresses used to read from and write to the device, and so forth. A miniport driver for a busmaster DMA device should call NdisMInitializeScatterGatherDma to initialize system resources used in DMA operations. A legacy miniport for a busmaster DMA device calls NdisMAllocateMapRegistersinstead.
  • Initializes the NIC.
  • Registers an interrupt if the NIC generates an interrupt.
  • Registers a shutdown handler.
  • Initializes timers.

For a detailed description of the MiniportInitialize function, see NDIS Miniport Driver Initialization.


Responding to Queries and Sets of Miniport Driver Information

To query a connectionless miniport driver's capabilities or statistics information, NDIS calls the miniport driver's MiniportQueryInformation function. NDIS can call this function on its own behalf or on the behalf of upper layers. To query a connection-oriented miniport driver, NDIS calls the miniport driver's MiniportCoRequest function. The MiniportQueryInformation or MiniportCoRequest function obtains the information and returns it to NDIS.

To set information maintained by a connectionless miniport driver, NDIS calls the miniport driver's MiniportSetInformation function, which sets the specified object identifier and returns the status of the operation to NDIS. To set object identifiers (OIDs) maintained by a connection-oriented miniport driver, NDIS calls the miniport driver's MiniportCoRequest function.

Miniport driver query and set functions are potentially asynchronous. If they complete synchronously, they return immediately with a status code other than NDIS_STATUS_PENDING. If they complete asynchronously, the function returns NDIS_STATUS_PENDING. To complete a query or set asynchronously, a connectionless miniport driver respectively calls NdisMQueryInformationComplete or NdisMSetInformationComplete. A connection-oriented miniport driver calls NdisMCoRequestComplete to complete a query or set asynchronously.

The NDIS Library guarantees that the miniport driver will never have more than one outstanding query or set request, so there is no need for the miniport driver to queue requests.

For more information on querying and setting connectionless miniport drivers, see Obtaining and Setting Miniport Driver Information. For information on specific OIDs, see General Objects .


Creating, Activating, Deactivating, and Deleting Virtual Connections

A connection-oriented miniport driver always sends and receives data, whether packets for a connection-oriented client or signaling messages for a call manager, on a virtual connection (VC). Before it can send or receive data on a VC, a connection-oriented miniport driver must set up the per-VC context, which involves allocating and initializing memory. Ndis…NPagedLookasideList functions are recommended for this task. The miniport driver must then activate the VC, which involves doing any processing required by the NIC to satisfy the request. When the VC is no longer needed for a call, the miniport driver deactivates and perhaps deletes the VC.

A connection-oriented miniport driver creates a VC in the following situations:

  • After the call manager and miniport driver finish their initialization, the call manager calls NdisCoCreateVc to request that the miniport driver set up a VC on which the call manager can send signaling messages. In response to this call, NDIS calls the miniport driver's MiniportCoCreateVc function, which sets up the per-VC context.
  • When a network administrator manually adds a permanent VC (PVC), the call manager calls NdisCoCreateVc to request that the miniport driver set up the VC.
  • Before requesting a call manager to set up an outgoing call, a connection-oriented client calls NdisCoCreateVC to request that the miniport driver set up a VC on which to send the call data.
  • Before indicating an incoming call to a connection-oriented client, a call manager calls NdisCoCreateVc to request that the miniport driver set up a VC on which to receive the call data.

After a call is finished or a VC is otherwise not needed, the call manager or integrated miniport call manager (MCM) can deactivate the VC by calling NdisCmDeactivateVc, which causes NDIS to call the miniport driver's MiniportCoDeactivateVc function. Either the connection-oriented client or the call manager can initiate deletion of the VC by calling NdisCoDeleteVc, which causes NDIS to call the miniport driver's MiniportCoDeleteVc function. MiniportCoDeleteVc tears down the per-VC state allocated by the miniport driver.

For more information about miniport driver operations on VCs, and for an overview of the connection-oriented architecture provided by NDIS, see Connection Oriented NDIS.


Sending Data

A connectionless miniport driver can have either of two functions for sending packets:

  • MiniportSendPackets

    NDIS passes MiniportSendPackets one or more packets at a time as an array of pointers to the packet descriptors.

  • MiniportSend

    NDIS always passes MiniportSend a single packet descriptor at a time.

A connection-oriented miniport driver must have a MiniportCoSendPackets function to send packets. NDIS passes MiniportCoSendPackets one or more packets at a time as an array of pointers to the packet descriptors.


Multipacket Sends

MiniportSendPackets in a connectionless miniport driver or MiniportCoSendPackets in a connection-oriented miniport driver receives a pointer to an array of pointer(s) to one or more packets to be sent on the network. The miniport driver must preserve the protocol-determined ordering of packet descriptors incoming to its Miniport(Co)SendPackets function.

The NIC driver can extract out-of-band (OOB) media-specific and priority information from the packet descriptor using NDIS macros supplied for this purpose. For more information, see Packet Out-of-Band Data.

Multipacket Sends from Serialized Miniport Drivers

A serialized miniport driver can complete a send operation either synchronously or asynchronously. In its MiniportSendPackets function (if it exports such a function), a serialized miniport driver must set send-completion status in the OOB data for each packet before MiniportSendPackets returns. Any such status other than NDIS_STATUS_PENDING indicates that the miniport driver is done with the packet (that is, has completed the send operation synchronously) and is returning ownership of the packet descriptor and its associated resources to the caller for reuse or to be freed. If the miniport driver returns NDIS_STATUS_PENDING in a packet, the driver retains ownership of the packet resources and must call NdisMSendComplete when it is done with the packet. For a detailed description of a multipacket send operation from a serialized miniport driver, see Multipacket Sends from Serialized Miniport Drivers.

Multipacket Sends from Deserialized Miniport Drivers

A deserialized miniport driver's MiniportSendPackets function cannot return NDIS_STATUS_RESOURCES and must always complete sends of each packet asynchronously with a call to NdisMSendComplete. NDIS therefore ignores the send-completion status in the OOB data for packets sent by deserialized miniport drivers. Rather than relying on NDIS to queue and resubmit send packets whenever MiniportSendPackets has insufficient resources to transmit the given packets, a deserialized miniport driver manages its own internal packet queuing. A deserialized miniport driver is responsible for holding incoming send packets in its internal queue until they can be transmitted over the network. In addition, a deserialized miniport driver must synchronize the execution of its own functions so that MiniportSendPackets can run concurrently with all other MiniportXxx functions. For more information on deserialized miniport drivers, see Deserialized NDIS Miniport Drivers. For detailed information on multipacket sends from deserialized miniport drivers, see Multipacket Sends from Deserialized Miniport Drivers.

Multipacket Sends by Connection-Oriented Miniport Drivers

Like a deserialized miniport driver, a connection-oriented miniport driver:

  • Cannot return NDIS_STATUS_RESOURCES in response to a multipacket send
  • Does not indicate the send-completion status for each packet in a multipacket send
  • Must queue internally all send packets passed to it by NDIS
  • Synchronizes the execution of its own MiniportXxx functions

A connection-oriented miniport driver differs from a connectionless miniport driver, however, in that it uses a MiniportCoSendPackets and always sends (and also receives) packets on a virtual connection (VC). For detailed information on multipacket sends from connection-oriented miniport drivers, see Multipacket Sends from Connection-Oriented Miniport Drivers.


Single-Packet Sends

Connectionless miniport drivers, both serialized and deserialized, can have a MiniportSend function for transmitting a single packet through the NIC onto the network. MiniportSend translates the packet into a data frame and carries out the send operation.

If MiniportSend completes the send operation before returning, it returns a status code other than NDIS_STATUS_PENDING or NDIS_STATUS_RESOURCES. Completing the send operation means that the miniport driver is finished with the packet descriptor and the resources that it describes and is returning it to the caller for reuse or to be freed.

In the asynchronous case, the miniport driver returns NDIS_STATUS_PENDING and must call NdisMSendComplete when it is done with the packet to indicate that it is relinquishing the packet for reuse or to be freed.

A serialized miniport driver can return NDIS_STATUS_RESOURCES to indicate that it does not have enough internal resources to transmit a packet. In this case, NDIS queues the returned packet descriptor internally and resubmits it to the NIC driver when more resources are available, either when the miniport driver calls NdisMSendComplete or NdisMSendResourcesAvailable, whichever occurs first.

When a serialized miniport driver calls NdisMSendComplete or NdisMSendResourcesAvailable, it indicates to NDIS that send resources are available and the miniport driver is ready to accept a new packet descriptor.

For a detailed description of single-packet sends from connectionless miniport drivers, see Single Packet Sends from Connectionless Miniport Drivers.


Indicating and Transferring Received Data

To indicate one or more receive packets to higher drivers, connectionless miniports call NdisMIndicateReceivePacket; connection-oriented packets call NdisMCoIndicateReceivePacket.

Legacy connectionless miniports that do not support NdisMIndicateReceivePacket call a medium-specific NdisM Xxx IndicateReceive function to indicate a single packet to higher drivers.


Indicating Receives with NdisM(Co)IndicateReceivePacket

When a connectionless miniport driver calls NdisMIndicateReceivePacket or a connection-oriented miniport driver calls NdisMCoIndicateReceivePacket, the miniport driver passes a pointer to an array of packet descriptors, each of which describes a packet. Each packet that is indicated up must be completed separately by the miniport driver.

Connection-oriented miniport drivers identify the virtual connection (VC) on which the packet(s) have been received. At the request of the connection-oriented call manager or integrated miniport call manager (MCM) that received the incoming call from the network, the miniport driver previously set up and activated the VC in its MiniportCoCreateVc and MiniportCoActivateVc functions, respectively. The miniport driver passes an NDIS-supplied handle that identifies the VC in its call to NdisMCoIndicateReceivePacket.

For a detailed description of indicating up receive data with NdisM(Co)IndicateReceivePacket , see Indicating Receive Packets with NdisM(Co)IndicateReceivePacket .


Indicating Receives with an NdisMXxxIndicateReceive function

A legacy connectionless miniport driver that does not support the NdisMIndicateReceivePacket function calls a medium-specific NdisM Xxx IndicateReceive function to indicate a single packet to higher drivers. When the network interface card (NIC) receives a data packet over the network, its miniport driver indicates the packet up by calling the appropriate function for the network medium:

Network medium | Function
ARCNET | NdisMArcIndicateReceive
Ethernet | NdisMEthIndicateReceive
FDDI | NdisMFddiIndicateReceive
Token Ring | NdisMTrIndicateReceive

The miniport driver indicates up a partial packet, or possibly the complete packet if it is small enough. NDIS forwards the indication to all interested protocols. If it is a partial packet and a protocol is interested in the complete packet, the protocol calls NdisTransferData to request the remaining net packet data, passing down a protocol-allocated packet descriptor.

NDIS then initiates the transfer of the data to the protocol-allocated buffers chained to the packet descriptor by calling the miniport driver's MiniportTransferData function. MiniportTransferData copies the received data frames into the buffers.

If MiniportTransferData completes synchronously, it simply writes the received data into the provided buffers and returns a status other than NDIS_STATUS_PENDING.

If MiniportTransferData is unable to complete the transfer operation before returning, it returns NDIS_STATUS_PENDING. The miniport driver must call NdisMTransferDataComplete when the data has been transferred.

After all incoming data frames have been received by the NIC, the miniport driver calls the appropriate NdisM Xxx IndicateReceiveComplete function for the network medium. This causes a call to the overlying protocol driver to indicate that post-receive processing can be performed.

For a detailed description of indicating a single packet with an NdisMXxxIndicateReceive function, see Indicating a Receive Packet with an NdisMXxxIndicateReceive function.


Indicating Status

To indicate a change in the status of a NIC that it manages, a connectionless miniport driver calls NdisMIndicateStatus. A connection-oriented miniport driver calls NdisMCoIndicateStatus to indicate such a change.

NdisM(Co)IndicateStatus forwards the call to the bound protocol drivers, which interpret the general status code. Then the protocol drivers, NDIS Library, WMI, or other OS entities can log the status change, take corrective action, or both.

A connectionless miniport driver must indicate when it is done transmitting status changes. Following one or more NdisMIndicateStatus calls, a connectionless miniport driver calls NdisMIndicateStatusComplete. NDIS forwards the completion call to the protocol drivers so they can perform any necessary postprocessing. A connection-oriented miniport driver does not indicate when it is done transmitting status changes.

A miniport driver is not allowed to indicate status in the context of its MiniportInitialize, MiniportISR, MiniportHalt, or MiniportShutdown functions.

For a detailed description of indicating status, see Reporting Hardware Status.


Resetting a Network Interface Card

NDIS resets a NIC when:

  • The NIC driver's MiniportCheckForHang function returns TRUE.
  • A request (query or set) operation to the miniport driver times out.
  • A serialized miniport driver's send operation times out.

When the NDIS Library determines that a NIC must be reset, it calls the miniport driver's MiniportReset function. MiniportReset issues a hardware reset to the NIC and updates its own software state.

MiniportReset completes synchronously with a success or error status code, or asynchronously with NDIS_STATUS_PENDING. If the function is asynchronous, the miniport driver later calls NdisMResetComplete to allow postprocessing.

The NIC driver is guaranteed that NDIS will not send any requests or sends while a reset is in progress. Also, For serialized miniport drivers, NDIS will complete any currently outstanding requests or sends, so the miniport driver need not explicitly complete them.

For a detailed description of resetting a NIC managed by a serialized miniport driver, see Hardware Reset.


Halting a Miniport Driver

NDIS halts a miniport driver by calling the miniport driver's MiniportHalt function. The MiniportHalt function releases system resources claimed by the miniport driver. For example, if the miniport driver's MiniportInitialize function registered an interrupt with NdisMRegisterInterrupt, the miniport driver's MiniportHalt function must deregister the interrupt with NdisMDeregisterInterrupt.

If the miniport driver fails to initialize a NIC or to claim required system resources, its MiniportInitialize function releases all miniport driver-allocated resources. Otherwise, the miniport driver releases its resources in the context of its MiniportHalt function.

If the miniport driver has any outstanding receive packets (packets that it has indicated up to NDIS but which NDIS has not yet returned), the miniport driver must not return from its MiniportHalt function until such packets are returned to the miniport driver's MiniportReturnPacket function.

If the driver has a MiniportTimer function associated with any timer object that might be in the system timer queue, MiniportHalt should call NdisMCancelTimer. If a call to NdisMCancelTimer fails, the miniport should wait for the timer to fire before returning from MiniportHalt.

Note that a miniport driver's MiniportShutdown function should not release any allocated resources. The MiniportShutdown function should stop any data transfers in progress and put the NIC in its initial state.

For more information on halting a miniport driver, see Halt Handler.


Miniport Driver Upper-Edge Functions

This section provides an overview of the upper-edge functions exported by miniport drivers. NDIS calls these functions on behalf of itself or other layers of the network software, such as a higher level protocol driver that is bound to a NIC managed by the NIC driver. A miniport driver must export some or all of the upper-edge functions.

Names of the miniport driver functions discussed here use Miniport as a generic prefix. However, functions written for an actual miniport driver should use a more descriptive prefix to make debugging easier. Because the addresses of the functions (not the names) are passed to the NDIS Library during initialization, the naming of MiniportXxx functions is at the discretion of the driver developer.

Some of the NIC driver functions are inherently synchronous, while others can complete either synchronously or asynchronously. When a miniport driver function returns NDIS_STATUS_PENDING, the miniport driver must complete the request by calling the appropriate NdisM...Complete function. NDIS takes care of any further coordination with other layers, calling the completion functions of those layers for asynchronous requests as required.

The following table summarizes the NDIS-defined miniport driver functions.

Function | Description | Async Option
DriverEntry
 | Called by the operating system to activate and initialize the miniport driver. | Not Applicable
MiniportAllocateComplete
 | Called to indicate that a preceding call to NdisMAllocateSharedMemoryAsync is now complete. | No
MiniportCancelSendPackets
 | For a specified adapter, cancels the transmission of all packets marked with a specified cancellation identifier | No
MiniportCheckForHang
 | Checks the internal state of the NIC. | No
MiniportCoActivateVc
 | Activates a virtual connection (VC). Exported only by connection-oriented miniport drivers. | Yes
MiniportCoCreateVc
 | Sets up per-VC state for a VC. Exported only by connection-oriented miniport drivers. | No
MiniportCoDeactivateVc
 | Releases per-VC state for a VC. Exported only by connection-oriented miniport drivers. | Yes
MiniportCoDeleteVc
 | Deletes a VC. Exported only by connection-oriented miniport drivers. | No
MiniportCoRequest
 | Queries the capabilities and current status of the miniport driver or changes (sets) information about the miniport driver or its NIC. Exported only by connection-oriented miniport drivers. | Yes
MiniportCoSendPackets
 | Transmits an array of packets through a NIC onto the network. Exported only by connection-oriented miniport drivers. | Yes
MiniportDisableInterrupt
 | Disables the NIC from generating interrupts. | No
MiniportEnableInterrupt
 | Enables the NIC to generate interrupts. | No
MiniportHalt
 | Deallocates and deregisters resources used for the NIC and halts the NIC so that it is no longer functioning. | No
MiniportHandleInterrupt
 | Deferred processing function called to complete interrupt-driven I/O processing. | No
MiniportInitialize
 | Initializes the NIC. | No
MiniportISR
 | Runs at a high priority as the interrupt service routine for the NIC. | No
MiniportPnPEventNotify
 | Handles notification of Plug and Play (PnP) events. | No
MiniportQueryInformation
 | Queries the capabilities and current status of the miniport driver. Exported only by connectionless miniport drivers. | Yes
MiniportReconfigure
 | Not used. | No
MiniportReset
 | Issues a hardware reset to the NIC. | Yes
MiniportReturnPacket
 | Receives from an upper layer a packet that was previously passed up by a call to NdisMIndicateReceivePacket. | No
MiniportSend
 | Transmits a packet through the NIC onto the network. Exported only by legacy connectionless miniport drivers. Required if the driver has no MiniportSendPackets or MiniportWanSend function. | Yes
MiniportSendPackets
 | Transmits an array of packets through the NIC onto the network. Exported only by connectionless miniport drivers. | Yes
MiniportSetInformation
 | Changes (sets) information about the miniport driver or its NIC. Exported only by connectionless miniport drivers. | Yes
MiniportShutdown
 | Restores a NIC to its initial state when the system is shut down. NDIS 5.1 miniports should register a MiniportShutdown function by calling NdisMRegisterMiniport—not by calling NdisMRegisterAdapterShutdownHandler. | No
MiniportSynchronizeISR
 | Synchronizes access to resources shared with MiniportISR or MiniportDisableInterrupt. Required if any NIC driver function that runs at less than DIRQL shares resources with that driver's MiniportISR or MiniportDisableInterrupt function. | No
MiniportTimer
 | Polls the state of the NIC. | No
MiniportTransferData
 | Copies the contents of a packet received by the NIC into a given packet buffer. Exported only by connectionless miniports. | Yes
MiniportWanSend
 | Transmits a packet through the NIC onto the network. Required if the driver controls a WAN NIC. | No

The following table summarizes the NDIS completion function that corresponds to each possibly asynchronous upper-edge driver function.

Function(s) | Asynchronous Completion Function
MiniportCoActivateVc | NdisMCoActivateVcComplete
MiniportCoDeactivateVc | NdisMCoDeactivateVcComplete
MiniportCoRequest | NdisCoRequestComplete
MiniportCoSendPackets | NdisMCoSendComplete
MiniportSend, MiniportSendPackets | NdisMSendComplete
MiniportQueryInformation | NdisMQueryInformationComplete
MiniportReset | NdisMResetComplete
MiniportSetInformation | NdisMSetInformationComplete
MiniportTransferData | NdisMTransferDataComplete

Connection-oriented miniport drivers differ from connectionless miniport drivers with respect to MiniportXxx functions as follows:

  • Connection-oriented miniport drivers must be able to create, activate, deactivate and delete VCs. The MiniportCoCreateVc, MiniportCoActivateVc, MiniportCoActivateVc, and MiniportCoDeleteVc functions accomplish these tasks.
  • The MiniportSend or MiniportSendPackets function of connectionless miniport drivers are replaced by the MiniportCoSendPackets function in connection-oriented miniport drivers.
  • The MiniportQueryInformation and MiniportSetInformation functions of connectionless miniport drivers are replaced by the MiniportCoRequest function in connection-oriented miniport drivers.
  • Since connection-oriented miniport drivers always indicate complete packets to bound protocols, they do not need a MiniportTransferData function.


NDIS Functions Called by Miniport Drivers

An NDIS miniport driver must call NDIS (Ndis Xxx) functions or macros when it needs system resources such as spin locks or memory buffers. The Ndis Xxx functions can, in turn, call kernel-mode support routines to satisfy the miniport driver's requests.

NDIS defines several hundred functions and macros, many of which can be called by miniport drivers. The NDIS Library can be thought of as the standard C Library in that it provides a rich framework for writing NIC drivers. Only a small subset of NDIS functions is likely to be called by any given NIC driver.

The NDIS Library functions are provided as an export library (ndis.lib). Both NDIS protocols and miniport drivers link to this export library.

The NDIS Library supplies numerous functions to miniport drivers. These functions are described in the following topics:

NDIS-Supplied Initialization and Registration Functions

NDIS-Supplied Hardware Configuration Functions

NDIS-Supplied I/O Port Functions

NDIS-Supplied DMA-Related Functions

NDIS-Supplied Interrupt Handling Functions

NDIS-Supplied Synchronization Functions

NDIS-Supplied Query and Set Completion Functions

NDIS-Supplied Status Indication Functions

NDIS-Supplied Send and Receive Functions for Connectionless Miniport Drivers

NDIS-Supplied Send and Receive Functions for Connection-Oriented Miniport Drivers

NDIS-Supplied Out-of-Band Data Macros

NDIS-Supplied Packet- and Buffer-Handling Functions

NDIS-Supplied Support Functions

NDIS-Supplied Media-Specific Macros


NDIS-Supplied Initialization and Registration Functions

During initialization, a miniport driver configures itself and registers with NDIS by calling configuration functions provided by NDIS. Some of these functions access configuration information written to the registry by the miniport driver's INF file.

The following table describes the initialization and registration functions supplied by NDIS.

Function | Definition
NdisMInitializeWrapper
 | Initializes the NDIS Library data structures for the miniport driver.
NdisMRegisterMiniport
 | Provides the NDIS Library with information about the miniport driver.
NdisMSetAttributesEx
 | Informs the NDIS Library of the type of NIC supported by the miniport driver and passes the handle to the miniport driver's context area. NDIS will pass this handle in subsequent calls to MiniportXxx functions. This function can also change the default NIC timeout behavior and allows a driver to specify some additional flags, including flags that must be set by a deserialized miniport driver or an NDIS intermediate driver.
NdisMGetDeviceProperty
 | Retrieves device objects required to set up communication with a NIC through a bus driver. For example, USB and IEEE 1394 bus drivers.
NdisMQueryAdapterResources
 | Returns a list of hardware resources for a NIC.
NdisMQueryInformationComplete
 | Indicates that a call to MiniportQueryInformation has completed. Called only by connectionless miniport drivers.
NdisMSetInformationComplete
 | Informs the NDIS Library that the previous MiniportSetInformation operation has completed. Called only by connectionless miniport drivers.
NdisOpenConfiguration
 | Supplies a handle that the caller can use to call NdisReadConfiguration, NdisWriteConfiguration, NdisOpenConfigurationByIndex, or NdisOpenConfigurationByName.
NdisOpenConfigurationByIndex
 | Opens a subkey of a given open registry key designated by a caller-supplied handle.
NdisOpenConfigurationByName
 | Opens a named subkey of a given open registry key designated by a caller-supplied handle.
NdisReadConfiguration
 | Uses the Parameters handle obtained by calling NdisOpenConfiguration to read key values stored in the registry at the keyword passed to NdisReadConfiguration.
NdisWriteConfiguration
 | Uses the Parameters handle obtained by calling NdisOpenConfiguration to write key values into the registry at the keyword passed to NdisWriteConfiguration.
NdisCloseConfiguration
 | Closes the handle to the registry that was opened with a call to NdisOpenConfiguration.
NdisMRegisterAdapterShutdownHandler
 | Registers a NIC-driver-supplied MiniportShutdown function to be called when the system is shutting down.
NDIS_INIT_FUNCTION
 | Marks a driver function to be run only once during initialization.
NDIS_PAGEABLE_FUNCTION
 | Marks a driver function as pageable code.


NDIS-Supplied Hardware Configuration Functions

The NDIS Library provides bus-related functions for EISA, PCI, and PC Card. These functions are called by MiniportInitialize to obtain bus-specific information needed to initialize the network interface card (NIC).

The following table describes the hardware configuration functions supplied by NDIS.

Function | Definition
NdisReadPciSlotInformation
 | Reads a specified number of bytes from the configuration space of a specified PCI device.
NdisWritePciSlotInformation
 | Writes a specified number of bytes to the configuration space of a specified PCI device.
NdisReadPcmciaAttributeMemory
 | Reads bus-relative configuration parameters for a PC Card NIC from attribute memory.
NdisWritePcmciaAttributeMemory
 | Writes bus-relative configuration parameters for a PC Card NIC to attribute memory.
NdisReadNetworkAddress
 | Returns the software-configurable network address that was stored in the registry for a NIC when the NIC was installed in the machine.


NDIS-Supplied I/O Port Functions

The NDIS Library provides a set of I/O functions that a miniport network interface card (NIC) driver calls to access I/O ports. These calls provide a standard portable interface that supports the various operating environments for NDIS drivers. Functions are provided for mapping ports, for claiming I/O resources, and for reading from and writing to the mapped and unmapped I/O ports.

The following table describes the I/O port functions supplied by NDIS.

Function | Definition
NdisMRegisterIoPortRange
 | Sets up access to I/O ports for using NdisRawReadPort Xxx and NdisRawWritePort Xxx.
NdisMDeregisterIoPortRange
 | Removes access to I/O ports previously registered with NdisMRegisterIoPortRange.
NdisMMapIoSpace
 | Maps a range of device memory for subsequent memory-mapped I/O operations.
NdisZeroMappedMemory
 | Fills a block of memory with zeros that was mapped with a preceding call to NdisMMapIoSpace.
NdisMoveFromMappedMemory
 | Copies data from device memory that was mapped during initialization with NdisMMapIoSpace to a system-space buffer.
NdisMoveToMappedMemory
 | Copies data from a system-space buffer to device memory that was mapped during initialization with NdisMMapIoSpace.
NdisMUnmapIoSpace
 | Releases a region mapped by a call to NdisMMapIoSpace.
NdisRawReadPort Xxx
 | Reads a single piece of data from an I/O port. Specific functions include: NdisRawReadPortUchar NdisRawReadPortUlong NdisRawReadPortUshort
NdisRawReadPortBuffer Xxx
 | Reads a buffer of data a piece at a time from an I/O port. Specific functions include: NdisRawReadPortBufferUchar NdisRawReadPortBufferUlong NdisRawReadPortBufferUshort
NdisRawWritePort Xxx
 | Writes a single piece of data to an I/O port. Specific functions include: NdisRawWritePortUchar NdisRawWritePortUlong NdisRawWritePortUshort
NdisRawWritePortBuffer Xxx
 | Writes a buffer of data to I/O port. Specific functions include: NdisRawWritePortBufferUchar NdisRawWritePortBufferUlong NdisRawWritePortBufferUshort


NDIS-Supplied DMA-Related Functions

A miniport driver calls NDIS functions for direct memory access (DMA) operations between the host and the NIC. For example, miniport drivers allocate and manage virtual memory buffers in the host for DMA transfers. The following table summarizes functions provided by the NDIS Library that allow the drivers to allocate, construct, and inspect such buffers.

The following table describes the DMA-related functions supplied by NDIS.

Function | Definition
NdisMAllocateMapRegisters
 | Allocates map registers for use with bus-master DMA devices.
NdisMAllocateSharedMemory
 | Allocates memory to be shared between the system and a bus-master DMA NIC. It is called during driver initialization at IRQL PASSIVE_LEVEL.
NdisMAllocateSharedMemoryAsync
 | Called at raised IRQL, such as in a miniport driver's MiniportHandleInterrupt function to allocate shared memory for a bus-master DMA NIC.
NdisMCompleteBufferPhysicalMapping
 | Releases the map registers used by a previous call to NdisMStartBufferPhysicalMapping for a bus-master DMA operation. Called only by drivers that call NdisMAllocateMapRegisters during DMA initialization.
NdisMCompleteDmaTransfer
 | Indicates to the NDIS Library that a slave DMA operation has completed.
NdisMDeregisterDmaChannel
 | Releases a miniport driver's claim on its DMA channel.
NdisFlushBuffer
 | Called by the driver before sending data to the NIC or transferring data from the NIC to ensure coherence between cache memory and host physical memory during bus-master DMA operations.
NdisMFreeMapRegisters
 | Frees map registers for bus-master DMA that were previously allocated by NdisMAllocateMapRegisters.
NdisMFreeSharedMemory
 | Frees memory that was previously allocated by NdisMAllocateSharedMemory or NdisMAllocateSharedMemoryAsync.
NdisMGetDmaAlignment
 | Returns the alignment requirements of the DMA system for the NIC. A miniport driver can use this function to determine alignment requirements for DMA buffers it allocates.
NdisMInitializeScatterGatherDma
 | Reserves system resources for use with DMA devices.
NdisMReadDmaCounter
 | Reads the current value of the system DMA controller counter.
NdisMRegisterDmaChannel
 | Sets up a DMA channel for future slave DMA operations.
NdisMSetupDmaTransfer
 | Sets up the host system DMA controller for a slave DMA transfer.
NdisMStartBufferPhysicalMapping
 | Creates a physical address mapping for a bus-master DMA operation. Called only by drivers that call NdisMAllocateMapRegisters during DMA initialization.
NdisMUpdateSharedMemory
 | Ensures that data to be read from a shared memory region is up-to-date during bus-master DMA operations.


NDIS-Supplied Interrupt Handling Functions

The NDIS Library provides several interrupt handling functions for use in a multiprocessor environment. These functions relate to network interface card (NIC) interrupts on a host processor.

The following table describes the interrupt handling functions supplied by NDIS.

Function | Definition
NdisMDeregisterInterrupt
 | Stops an interrupt handler from receiving interrupts. The operating system disconnects the interrupt service function from its associated NIC interrupt.
NdisMRegisterInterrupt
 | Associates the miniport driver interrupt service function (MiniportISR) with interrupts generated by its NIC.
NdisMSynchronizeWithInterrupt
 | Any NIC driver function that shares resources with the MiniportISR or MiniportDisableInterrupt functions must synchronize access to these resources to prevent race conditions. Functions that must synchronize with MiniportISR and MiniportDisableInterrupt do so by calling NdisMSynchronizeWithInterrupt and passing the address of a MiniportSynchronizeISR function. The MiniportSynchronizeISR function runs at DIRQL so that it can safely access the shared resource.


NDIS-Supplied Synchronization Functions

The timer functions allow the miniport driver to implement an operation that occurs at a driver-requested interval. For instance, a driver can use a timer to poll its NIC. Events can be used to synchronize operations between two threads, at least one of which is running at IRQL PASSIVE_LEVEL. Spin locks are used to synchronize access to shared resources.

The following table describes the synchronization functions supplied by the NDIS Library for miniport drivers.

Function | Definition
NdisMCancelTimer
 | Cancels a timer that was previously set with NdisMSetTimer.
NdisMInitializeTimer
 | Initializes a timer object and associates a MiniportTimer function with the object.
NdisMSetTimer
 | Sets a timer to go off after a specified interval.
NdisMSetPeriodicTimer
 | Sets a timer to go off at a specified interval or until cancelled with a call to NdisMCancelTimer.
NdisMSleep
 | Causes the caller's thread to block for the specified interval. A driver calls NdisMSleep during initialization or when halting the adapter; for instance, while waiting for the NIC to complete initialization. NdisMSleep is only called at IRQL PASSIVE_LEVEL.
NdisStallExecution
 | Causes the caller's thread to stall for a specified interval not to exceed 50 milliseconds. NdisStallExecution is only called at raised IRQL when NdisMSleep cannot be used.
NdisInitializeEvent
 | Creates and initializes an event which can be used to synchronize driver operations.
NdisSetEvent
 | Signals the specified event.
NdisResetEvent
 | Resets the specified event to the unsignaled state.
NdisWaitEvent
 | Causes the caller to wait until the specified event is signaled or the specified time interval expires.
NdisAllocateSpinLock
 | Initializes a variable of type NDIS_SPIN_LOCK, used to synchronize access to resources shared among nonISR driver functions.
NdisFreeSpinLock
 | Releases a spin lock initialized in a preceding call to NdisAllocateSpinLock.
NdisAcquireSpinLock
 | Acquires a spin lock to protect access to shared resources between nonISR driver functions in an SMP-safe way. Miniport drivers that are running at IRQL < DISPATCH_LEVEL call this function to acquire a spin lock.
NdisReleaseSpinLock
 | Releases a spin lock previously acquired by calling NdisAcquireSpinLock.
NdisDprAcquireSpinLock
 | Acquires a spin lock at IRQL DISPATCH_LEVEL. Protects access to shared resources between nonISR driver functions in an SMP-safe way. Faster than calling NdisAcquireSpinLock for driver functions running at IRQL DISPATCH_LEVEL.
NdisDprReleaseSpinLock
 | Releases a spin lock previously acquired by calling NdisDprAcquireSpinLock.
NdisInitializeReadWriteLock
 | Initializes a variable of type NDIS_RW_LOCK. An NDIS_RW_LOCK variable is used to limit write access to shared resources to one nonISR-driver thread at a time. This NDIS_RW_LOCK can allow multiple nonISR-driver threads concurrent read access to those resources. Such read access is not permitted during a write access.
NdisAcquireReadWriteLock
 | Acquires a lock that the caller uses for either write or read access to the resources that are shared among driver threads. Miniport drivers that are running at IRQL < DISPATCH_LEVEL call this function to acquire a read-write lock. Read-write locks are used for resources that are frequently accessed for reading and infrequently accessed for writing.
NdisReleaseReadWriteLock
 | Releases a read-write lock that was acquired in a preceding call to NdisAcquireReadWriteLock.
NdisMSynchronizeWithInterrupt
 | Any NIC driver function that shares resources with the MiniportISR or MiniportDisableInterrupt functions must synchronize access to resources with these two functions to prevent race conditions. Functions that must synchronize with MiniportISR and MiniportDisableInterrupt do so by calling NdisMSynchronizeWithInterrupt with a MiniportSynchronizeISR function that also runs at DIRQL while it accesses the shared resource.


NDIS-Supplied Query and Set Completion Functions

The following table summarizes the query and set completion functions provided by NDIS for miniport drivers.

Function | Definition
NdisMCoRequestComplete
 | Indicates that a prior call to MiniportCoRequest has completed.
NdisMQueryInformationComplete
 | Indicates that a prior call to MiniportQueryInformation has completed.
NdisMSetInformationComplete
 | Indicates that a prior call to MiniportSetInformation has completed.


NDIS-Supplied Status Indication Functions

The following table summarizes the status indication functions provided by NDIS for miniport drivers.

Function | Definition
NdisMCoIndicateStatus
 | Indicates a change in the status of a connection-oriented NIC to bound protocols, or a change in the status of a particular virtual connection (VC) active on the network interface card (NIC).
NdisMIndicateStatus
 | Indicates to the NDIS Library that the NIC status has changed. Called only by connectionless miniport drivers.
NdisMIndicateStatusComplete
 | Indicates to the NDIS Library that the status change has completed. Called only by connectionless miniport drivers.


NDIS-Supplied Send and Receive Functions for Connectionless Miniport Drivers

The following table summarizes the NDIS Library functions that a connectionless miniport driver can call for sending and receiving packets.

Function | Definition
NdisMIndicateReceivePacket
 | Indicates up one or more packets to interested upper layers.
NdisMArcIndicateReceive NdisMEthIndicateReceive NdisMFddiIndicateReceive NdisMTrIndicateReceive
 | Indicate that a packet of a specific media type is being received.
NdisMArcIndicateReceiveComplete NdisMEthIndicateReceiveComplete NdisMFddiIndicateReceiveComplete NdisMTrIndicateReceiveComplete
 | Indicate that a packet receive operation has completed.
NdisMSendComplete
 | Indicates that the previous packet send operation has completed. This function is used when the previous MiniportSend function operated asynchronously.
NdisMSendResourcesAvailable
 | Notifies the NDIS Library that a miniport driver has sufficient internal resources to accept another send request, even though one or more outstanding send packets are pending within the miniport driver.
NdisMTransferDataComplete
 | Informs the NDIS Library that the previous MiniportTransferData request is complete. This function is used when the previous call to the MiniportTransferData function returned NDIS_STATUS_PENDING.


NDIS-Supplied Send and Receive Functions for Connection-Oriented Miniport Drivers

A connection-oriented miniport driver sends an array of packets on the network in its MiniportCoSendPackets function.

A connection-oriented miniport NIC transfers one or more receive packets by calling NdisMCoIndicateReceivePacket and passing a complete packet or packets. NDIS calls the miniport driver's MiniportReturnPacket function to return the packet(s).

The following table describes NDIS Library functions that a connection-oriented miniport driver calls when sending and receiving packets.

Function | Definition
NdisMCoIndicateReceivePacket
 | Indicates up one or more packets to interested upper layers. Packets are indicated on a per-VC basis.
NdisMCoSendComplete
 | Indicates that the previous packet send operation that was initiated with a call to MiniportCoSendPackets has completed.


NDIS-Supplied Out-of-Band Data Macros

Miniport drivers can use the following macros to access the out-of-band (OOB) data that may be associated with a packet. For more information on OOB data, see Packet Out-of-Band Data.

Function | Definition
NDIS_OOB_DATA_FROM_PACKET
 | Returns a pointer to the OOB data block associated with a given packet descriptor.
NDIS_GET_PACKET_HEADER_SIZE
 | Returns the HeaderSize value from the out-of-band data block associated with a given packet descriptor.
NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO
 | Returns the MediaSpecificInformation pointer and the SizeMediaSpecificInfo value from the OOB data block associated with a given packet descriptor.
NDIS_GET_PACKET_PROTOCOL_TYPE
 | Returns the protocol ID associated with a given packet descriptor.
NDIS_GET_PACKET_STATUS
 | Returns the Status value from the OOB data block associated with a given packet descriptor.
NDIS_GET_PACKET_TIME_RECEIVED
 | Returns the TimeReceived value from the out-of-band data block associated with a given packet descriptor.
NDIS_GET_PACKET_TIME_SENT
 | Returns the TimeSent value from the out-of-band data block associated with a given packet descriptor.
NDIS_GET_PACKET_TIME_TO_SEND
 | Returns the TimeToSend value from the OOB data block associated with a given packet descriptor.
NDIS_SET_PACKET_HEADER_SIZE
 | Sets the HeaderSize value in the OOB data block associated with a given packet descriptor for a subsequent receive indication.
NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO
 | Sets the MediaSpecificInformation pointer and the SizeMediaSpecificInfo value in the OOB data block associated with a given packet descriptor.
NDIS_SET_PACKET_STATUS
 | Sets the Status value in the OOB data block associated with a given packet descriptor just before a driver calls NdisM(Co)IndicateReceivePacket or before a driver's Miniport(Co)SendPackets function returns control.
NDIS_SET_PACKET_TIME_RECEIVED
 | Sets the TimeReceived value in the OOB data block associated with a given packet descriptor.
NDIS_SET_PACKET_TIME_SENT
 | Sets the TimeSent value in the OOB data block associated with a given packet descriptor.
NDIS_SET_PACKET_TIME_TO_SEND
 | Sets the TimeToSend value in the out-of-band data block associated with a given packet descriptor.


NDIS-Supplied Packet and Buffer Handling Functions

Miniport drivers must allocate buffers to receive incoming data. The driver of a bus-master DMA device that indicates the entire incoming packet up to interested protocols must allocate and manage packets for this purpose. A NIC driver might need to allocate buffer space to stage data on a send operation if the packet it receives from an upper layer is small and fragmented. On a send, all miniport drivers receive a complete packet and must call NDIS functions to manipulate those packets and extract the data to be sent. A miniport driver that transfers incoming data to an upper layer driver receives a packet from the upper layer and must manipulate the packet structure to fill it with received data. NDIS provides functions that miniport drivers can call to allocate, construct, and inspect packets.

NDIS defines a packet as a packet descriptor with a chain of one or more buffers containing the network packet data. The NDIS Library describes a packet descriptor by defining the NDIS_PACKET structure. The descriptor consists of two parts: a public component that a miniport driver can see, and a private component that is invisible to the driver. The public component allows a miniport driver to maintain context information about the packet. A miniport driver can use this component to link packets into data transfer queues.

The following table describes the functions supplied by NDIS to handle packets and buffers:

Function | Definition
NdisAllocatePacketPool
 | Allocates and initializes a block of nonpaged packet pool. The caller supplies the requested number of packet descriptors and the length of the protocol reserved space for each packet.
NdisAllocatePacketPoolEx
 | Allocates and initializes a block of nonpaged packet pool. In addition to supplying the requested number of packet descriptors and protocol reserved length, the caller supplies the number of packet descriptors reserved for an overflow situation.
NdisAllocatePacket
 | Allocates a fixed-size packet descriptor from the packet pool returned by NdisAllocatePacketPool.
NdisAllocateBufferPool
 | Returns a handle that the caller can use to allocate buffer descriptors with NdisAllocateBuffer.
NdisAllocateBuffer
 | Creates a buffer descriptor that maps a specified virtual range within an allocated, nonpaged memory block, given a handle returned by NdisAllocateBufferPool.
NdisAdjustBufferLength
 | Modifies the length of the range specified in a given buffer descriptor.
NdisBufferLength
 | Returns the length in bytes of a given mapped buffer.
NdisBufferVirtualAddress(Safe)
 | Returns the base virtual address for the buffer mapped by a given buffer descriptor and maps the physical pages described by the given buffer descriptor onto system space if these pages are not already mapped to system space. Drivers should call NdisBufferVirtualAddressSafe instead of NdisBufferVirtualAddress. NDIS 5.1 miniport drivers must call NdisBufferVirtualAddressSafe instead of NdisBufferVirtualAddress.
NdisCopyBuffer
 | Creates a buffer descriptor for a specified range, given a handle for a block of already allocated memory and a pointer to the buffer descriptor for the block.
NdisCopyFromPacketToPacket(Safe)
 | Copies a specified number of bytes from one packet to another, given a specified source packet and a destination packet and specified offsets in each. Drivers should call NdisCopyFromPacketToPacketSafe instead of NdisCopyFromPacketToPacket. NDIS 5.1 miniport drivers must call NdisCopyFromPacketToPacketSafe instead of NdisCopyFromPacketToPacket.
NdisCreateLookaheadBufferFromSharedMemory
 | Returns the virtual address of a buffer within a block of memory shared with a bus-master DMA NIC. Allows a driver to map a portion of received data to indicate up to interested protocols as a read-only lookahead buffer.
NdisDestroyLookaheadBufferFromSharedMemory
 | Releases a buffer acquired by calling NdisCreateLookaheadBufferFromSharedMemory.
NdisQueryPacket
 | Returns a set of information that describes a packet and a pointer to the initial buffer in the chain.
NdisQueryBuffer(Safe)
 | Returns the base virtual address and size of a buffer that is mapped by a given buffer descriptor. Drivers should call NdisQueryBufferSafe instead of NdisQueryBuffer. NDIS 5.1 miniport drivers must call NdisQueryBufferSafe instead of NdisQueryBuffer.
NdisQueryBufferOffset
 | Returns the offset of a virtual address within a page at which a given buffer begins.
NdisGetFirstBufferFromPacket(Safe)
 | Returns pointers to the buffer descriptor and base virtual address, for the first buffer chained to a given packet, along with the sizes of the first buffer and the total buffer. Drivers should call NdisGetFirstBufferFromPacketSafe instead of NdisGetFirstBufferFromPacket. NDIS 5.1 miniport drivers must call NdisGetFirstBufferFromPacketSafe instead of NdisGetFirstBufferFromPacket.
NdisGetNextBuffer
 | Returns the next buffer descriptor in a chain, given the current buffer descriptor.
NdisGetBufferPhysicalArraySize
 | Returns the number of discontiguous physical blocks backing a buffer, given the buffer descriptor. The driver of a bus-master DMA NIC might call this function to determine how many NDIS_PHYSICAL_ADDRESS structures to allocate and fill in before calling NdisMStartBufferPhysicalMapping.
NdisGetPacketFlags
 | Returns the flags, if any, set by a protocol driver in a given packet.
NdisFreePacketPool
 | Releases a block of nonpaged pool allocated by calling NdisAllocatePacketPool.
NdisPacketPoolUsage
 | Returns the number of packet descriptors currently allocated from a packet pool.
NdisFreePacket
 | Releases a packet allocated by calling NdisAllocatePacket.
NdisFreeBufferPool
 | Releases a handle obtained by calling NdisAllocateBufferPool.
NdisFreeBuffer
 | Releases a buffer descriptor allocated by calling NdisAllocateBuffer.
NdisChainBufferAtFront
 | Links a given buffer descriptor at the front of a chain of buffer descriptors for a given packet.
NdisChainBufferAtBack
 | Links a given buffer descriptor at the end of a chain of buffer descriptors for a given packet.
NdisUnchainBufferAtFront
 | Removes a given buffer descriptor from the front of a chain of buffer descriptors for a given packet and returns a pointer to that buffer descriptor.
NdisUnchainBufferAtBack
 | Removes a given buffer descriptor from the back of a chain of buffer descriptors for a given packet and returns a pointer to that buffer descriptor.
NdisReinitializePacket
 | Removes any chained buffers from a given packet and reinitializes it for reuse.
NdisRecalculatePacketCounts
 | Resets the valid count for a given packet so that the next call to NdisQueryPacket recalculates the counts.
NDIS_BUFFER_LINKAGE
 | Returns a pointer to the next buffer, given a pointer to a buffer descriptor. This macro allows a driver to queue allocated buffer descriptors.
NDIS_BUFFER_TO_SPAN_PAGES
 | Determines how many physical pages of memory are being used to back a given buffer.


NDIS-Supplied Support Functions

Ndis Xxx functions are divided up into classes. The following topics describe these classes of functions and how they support miniport driver operations:

Memory Functions

Queuing Functions

System Information Functions

Logging Functions

String Functions

File Functions

Address Functions

Variable Functions

Register Functions

WorkItem Functions

Memory Functions

Function | Definition
NdisAllocateMemoryWithTag
 | Allocates resident (nonpaged) system-space memory. The caller supplies a tag that can be used to track the driver's memory allocation.
NdisEqualMemory
 | Compares a specified number of characters in one block of memory with the same number of characters in a second block of memory.
NdisFillMemory
 | Fills a caller-supplied buffer with the given character.
NdisFreeMemory
 | Releases a block of memory previously allocated with NdisAllocateMemoryWithTag.
NdisMoveMemory
 | Copies a specified number of bytes from one caller-supplied location to another.
NdisZeroMemory
 | Fills a block of memory with zeros.
NdisInitializeNPagedLookasideList
 | Initializes a lookaside list. After a successful initialization, nonpaged fixed-size blocks can be allocated from, and freed to, the lookaside list.
NdisAllocateFromNPagedLookasideList
 | Removes the first entry from the given lookaside listhead. If the lookaside list is empty, an entry is allocated from nonpaged pool.
NdisDeleteNPagedLookasideList
 | Removes a nonpaged lookaside list from the system.
NdisFreeToNPagedLookasideList
 | Returns an entry to the given lookaside list.

Queuing Functions

Function | Definition
NdisInitializeListHead
 | Initializes the head of a sequenced, doubly linked list.
NdisInterlockedInsertHeadList
 | Inserts an entry, usually a packet, at the head of a doubly linked list so that access to the list is synchronized in a multiprocessor-safe way.
NdisInterlockedInsertTailList
 | Inserts an entry, usually a packet, at the tail of a doubly linked list so that access to the list is synchronized in a multiprocessor-safe way.
NdisInterlockedRemoveHeadList
 | Removes an entry, usually a packet, from the head of a doubly linked list so that access to the list is synchronized in a multiprocessor-safe way.
NdisInitializeSListHead
 | Initializes the head of a sequenced, interlocked, singly linked list.
NdisInterlockedPopEntrySList
 | Removes the first entry from a sequenced, singly linked list.
NdisInterlockedPushEntrySList
 | Inserts an entry at the head of a sequenced, singly linked list.
NdisQueryDepthSList
 | Returns the current number of entries in a given sequenced, singly linked list.

System Information Functions

Function | Definition
NdisSystemProcessorCount
 | Determines whether its caller is running on a uniprocessor or multiprocessor machine. An NDIS driver might call this function during initialization before allocating resources.
NdisGetCurrentProcessorCounts
 | Returns counts for the current processor that a driver can use to determine CPU utilization for a particular time interval.
NdisGetCurrentProcessorCpuUsage
 | Returns a value representing how busy the current processor is as a percentage.
NdisGetCurrentSystemTime
 | Returns the current system time, suitable for setting timestamps.
NdisGetSystemUpTime
 | Returns the number of milliseconds that have elapsed since the system was booted.

Logging Functions

Function | Definition
NdisMCreateLog
 | Allocates and opens a log file in which a miniport driver can write data to be displayed by a driver-dedicated Win32® application.
NdisMWriteLogData
 | Transfers driver-supplied information into the log file for consumption and display by a driver-dedicated Win32 application.
NdisMFlushLog
 | Clears the log file.
NdisMCloseLog
 | Releases resources that were used for logging.
NdisWriteErrorLogEntry
 | Writes an entry to the system I/O error log file.

String Functions

Function | Definition
NdisAnsiStringToUnicodeString
 | Converts a given counted ANSI string into a counted Unicode string.
NdisEqualAnsiString
 | Compares two ANSI strings and returns a value indicating whether they are equal.
NdisEqualString
 | Compares two strings, in the OS-default character set, to determine whether they are equal.
NdisEqualUnicodeString
 | Compares two Unicode strings and returns a value indicating whether they are equal.
NdisFreeString
 | Releases storage that was allocated for a buffered string.
NdisInitAnsiString
 | Initializes a counted ANSI string.
NdisInitializeString
 | Allocates storage for and initializes a counted string in the system-default character set.
NdisInitUnicodeString
 | Initializes a counted Unicode string.
NdisPrintString
 | Displays a given string on the debugging window.
NdisUnicodeStringToAnsiString
 | Converts a given counted Unicode string into a counted ANSI string.
NdisUpcaseUnicodeString
 | Converts a copy of a given Unicode string to upper case and returns the converted string.

File Functions

Function | Definition
NdisOpenFile
 | Returns a handle for an opened file.
NdisMapFile
 | Maps an already open file into a caller-accessible buffer if the file is unmapped.
NdisUnmapFile
 | Releases a virtual address mapping of a file that was set up with NdisMapFile.
NdisCloseFile
 | Releases a handle returned by NdisOpenFile and frees the memory allocated to hold the file contents when it was opened.

Address Functions

Function | Definition
NdisGetPhysicalAddressHigh
 | Returns the high-order part of a given physical address.
NdisGetPhysicalAddressLow
 | Returns the low-order part of a given physical address.
NdisSetPhysicalAddressHigh
 | Sets the high-order part of a given physical address to a given value.
NdisSetPhysicalAddressLow
 | Sets the low-order part of a given physical address to a given value.
NDIS_PHYSICAL_ADDRESS_CONST
 | Initializes a static constant of type physical address.

Variable Functions

Function | Definition
NdisRetriveUlong
 | Retrieves a ULONG value from the source address, avoiding alignment faults.
NdisStoreUlong
 | Stores a ULONG value at a particular address, avoiding alignment faults.
NdisInterlockedAddUlong
 | Adds an unsigned long value to a given unsigned integer as an atomic operation, using a caller-supplied spin lock to synchronize access to the integer variable.
NdisInterlockedDecrement
 | Decrements a caller-supplied variable of type LONG as an atomic operation.
NdisInterlockedIncrement
 | Increments a caller-supplied variable as an atomic operation.

Register Functions

Function | Definition
NdisReadRegisterUchar
 | Reads a UCHAR from a memory-mapped device register.
NdisReadRegisterUlong
 | Reads a ULONG from a memory-mapped device register.
NdisReadRegisterUshort
 | Reads a USHORT from a memory-mapped device register.
NdisWriteRegisterUchar
 | Writes a UCHAR to a memory-mapped device register.
NdisWriteRegisterUlong
 | Writes a ULONG to a memory-mapped device register.
NdisWriteRegisterUshort
 | Writes a USHORT to a memory-mapped device register.

WorkItem Functions

Function | Definition
NdisInitializeWorkItem
 | Initializes a work-queue item with a caller-supplied context and callback routine to be queued for execution when a system worker thread is given control.
NdisScheduleWorkItem
 | Inserts a given work item into a queue. A system worker thread removes the item and gives control to the callback function that the driver previously supplied to NdisInitializeWorkItem.


NDIS-Supplied Media-Specific Macros

A miniport driver can use these macros to perform medium-specific operations.

Function | Definition
ETH_COPY_NETWORK_ADDRESS
 | Copies a given Ethernet address to a given location.
FDDI_IS_BROADCAST
 | Sets a caller-supplied variable to a Boolean value indicating whether a given FDDI address is a broadcast address.
FDDI_IS_MULTICAST
 | Sets a caller-supplied variable to a Boolean value indicating whether a given FDDI address is a multicast address.
FDDI_IS_SMT
 | Sets a caller-supplied variable to a Boolean value indicating whether a given FDDI frame is SMT.
TR_COMPARE_NETWORK_ADDRESSES
 | Sets a caller-supplied variable to a value indicating whether a given Token Ring address is greater than, less than, or equal to another given Token Ring address.
TR_COPY_NETWORK_ADDRESSES
 | Copies a given Token Ring address to a given location.
TR_IS_BROADCAST
 | Sets a caller-supplied variable to a Boolean value indicating whether a given Token Ring address is a broadcast address.
TR_IS_FUNCTIONAL
 | Sets a caller-supplied variable to a Boolean value indicating whether a given Token Ring address is a functional address.
TR_IS_GROUP
 | Sets a caller-supplied variable to a Boolean value indicating whether a given Token Ring address is a group address.
TR_IS_NOT_DIRECTED
 | Sets a caller-supplied variable to a Boolean value indicating whether a given Token Ring address is neither a functional nor a group address.
TR_IS_SOURCE_ROUTING
 | Sets a caller-supplied variable to a Boolean value indicating whether a given Token Ring address is a source-routing address.


Miniport Driver DriverEntry Function and Initialization

This section describes the DriverEntry function and the MiniportInitialize function, both of which must be supplied by all NDIS miniport drivers. In the context of its DriverEntry function, a miniport driver associates itself with NDIS, specifies the NDIS version that it is using, and registers its entry points. In the context of its MiniportInitialize function, a miniport driver initializes each NIC that it manages, claims system resources (such as packets, buffers, and I/O ports), and registers an interrupt and a shutdown handler.

This section includes the following topics:

NDIS Miniport Driver DriverEntry Function

NDIS Miniport Driver Initialization

Querying Miniport Driver Information

Minimizing Miniport Driver Initialization Time


NDIS Miniport Driver DriverEntry Function

Every miniport driver must provide a function called DriverEntry. DriverEntry is called by the system to load the driver. DriverEntry creates an association between the miniport driver and the NDIS Library, and registers the miniport driver's version number and entry points with NDIS.

Initializing NDIS Library and Registering a Miniport Driver

The declaration of the DriverEntry function is:

NTSTATUS
  DriverEntry(
    IN PDRIVER_OBJECT  DriverObject,
    IN PUNICODE_STRING  RegistryPath
    );

Two arguments are passed to DriverEntry:

  • A pointer to the driver object, which was created by the I/O system.
  • A pointer to the registry path, which specifies where driver-specific parameters are stored.

As shown in the preceding figure, DriverEntry calls NdisMInitializeWrapper and then NdisMRegisterMiniport. DriverEntry passes both input pointers to NdisMInitializeWrapper, which returns a wrapper handle. DriverEntry passes the wrapper handle to NdisMRegisterMiniport.


Initializing the Wrapper

The DriverEntry function associates the miniport driver with NDIS by calling the NdisMInitializeWrapper function with the same input parameters with which DriverEntry was called. These parameters are the pointer to the driver object and the pointer to the registry path. NdisMInitializeWrapper allocates a structure to represent this association, stores the miniport driver-specific information that the NDIS Library needs in this structure, and returns NdisWrapperHandle, which is a handle to this structure representing the miniport driver. The driver must retain and pass this handle to NdisMRegisterMiniport when it registers its entry points. NDIS will use NdisWrapperHandle to identify the miniport driver. The miniport driver must retain this handle but it should never attempt to access or interpret this handle.


Registering the Miniport Driver

After the DriverEntry function has called NdisMInitializeWrapper to create an association with the NDIS Library, it must initialize a structure of type NDIS_MINIPORT_CHARACTERISTICS. The NDIS_MINIPORT_CHARACTERISTICS structure specifies the version of NDIS that is compatible with the miniport driver (see Specifying the NDIS Version Number) and the entry points of the required and optional upper-edge (MiniportXxx) functions that the miniport driver exports (see Registering MiniportXxx Functions). DriverEntry then calls NdisMRegisterMiniport with a pointer to the NDIS_MINIPORT_CHARACTERISTICS structure.


Specifying the NDIS Version Number

The MajorNdisVersion and MinorNdisVersion members in the NDIS_MINIPORT_CHARACTERISTICS structure specify the NDIS version that is compatible with the miniport driver. Valid NDIS versions numbers are 5.1, 5.0, 4.0, or 3.0. The current version is 5.1. NDIS continues to support legacy miniport drivers written for versions 4.0, and 3.0.

Note that the NDIS version number, in addition to being included in NDIS_MINIPORT_CHARACTERISTICS, must also be specified when the miniport driver source code is compiled. The following shows the appropriate compiler directives to embed at the start of a miniport driver's source code if the driver uses a version 5.1 NDIS_MINIPORT_CHARACTERISTICS structure:

#define NDIS_MINIPORT_DRIVER
#define NDIS51_MINIPORT   1
#include <ndis.h>  // AFTER preceding directives

The following directive specifies the NDIS driver version:

#define NDISXX_MINIPORT

where XX is the NDIS version number.

This define statement must appear before the #include <ndis.h> statement.

Instead of using the preceding compiler directives, the same driver can set the following build directive in its sources file:

...
C_FLAGS=$(C_FLAGS) -DNDIS_MINIPORT_DRIVER -DNDIS50_MINIPORT_DRIVER
...

The NDIS version specified in the NDIS_MINIPORT_CHARACTERISTICS structure must be consistent with the compiler or build directives set for the miniport driver.


Registering MiniportXxx Functions

Each address member of the NDIS_MINIPORT_CHARACTERISTICS structure must be initialized — that is, it must be set to the address of a miniport driver-supplied function or to NULL. The miniport driver must supply entry points for all mandatory MiniportXxx functions; otherwise, NDIS will fail the driver. The MiniportXxx functions are defined in the ndis.h header file.

Because the miniport driver supplies the addresses, and not the names, of its MiniportXxx functions, driver developers are free to name these functions whatever they wish. A reasonable miniport driver-development strategy is to give these functions names that make debugging easier. For instance, the miniport driver mp.sys could name the entry points MpISR, MpSend, etc.

Registering MiniportXxx Functions of Connectionless Miniport Drivers

The MiniportXxx functions that can be exported by a connectionless miniport driver are described in Miniport Driver Upper-Edge Functions.

A connectionless miniport driver must always register the following mandatory MiniportXxx functions:

MiniportHalt

MiniportInitialize

MiniportQueryInformation

MiniportReset

MiniportReturnPacket or MiniportTransferData

MiniportSetInformation

MiniportShutdown (required for miniport drivers that directly manage hardware)

A LAN miniport driver must export a MiniportReturnPacket function if it supports multipacket-receive indications by calling NdisM(Co)IndicateReceivePacket or NdisMCoIndicateReceivePacket. If a LAN miniport driver indicates the initial portions of received network packets in lookahead buffers from which received data is copied by interested upper layers, it must export a MiniportTransferData function. A WAN miniport driver does not export either a MiniportReturnPacket function or a MiniportTransferData function.

  • MiniportSend or MiniportSendPackets

    A LAN miniport driver must export either a MiniportSendPackets function or a MiniportSend function. A WAN miniport driver must export a MiniportWanSend function.

  • MiniportSetInformation

A connectionless miniport driver can also, and in some cases must, register the following MiniportXxx functions:

  • MiniportAllocateComplete

    Required if the miniport driver controls a bus-master DMA NIC and allocates shared memory at raised IRQL with NdisMAllocateSharedMemoryAsync.

  • MiniportISR

    Not required if the NIC managed by the miniport driver does not generate interrupts. For more information, see Registering Handlers for Interrupt Support.

  • MiniportHandleInterrupt

    Required if a NIC managed by the miniport driver generates interrupts.

  • MiniportEnableInterrupt and MiniportDisableInterrupt

    Not required if the NIC managed by the miniport driver does not generate interrupts.

  • MiniportCheckForHang

    If not supplied, the miniport driver relies on NDIS to determine whether the NIC has stopped responding, based on sends and requests that timeout.

A connectionless miniport driver cannot export the following MiniportXxx functions:

MiniportCoActivateVc

MiniportCoCreateVc

MiniportCoDeactivateVc

MiniportCoDeleteVc

MiniportCoRequest

MiniportCoSendPackets

Registering MiniportXxx Functions of Connection-Oriented Miniport Drivers

The MiniportXxx functions that can be exported by a connection-oriented miniport driver are described in Miniport Driver Upper-Edge Functions. A connection-oriented miniport driver must register the following mandatory MiniportXxx functions:

MiniportCoActivateVc

MiniportCoCreateVc

MiniportCoDeactivateVc

MiniportCoDeleteVc

MiniportCoRequest

MiniportCoSendPackets

MiniportHalt

MiniportInitialize

MiniportReset

MiniportReturnPacket

A connection-oriented miniport driver can also, and in some cases must, export the following MiniportXxx functions:

  • MiniportAllocateComplete

    Required if the miniport driver controls a bus-master DMA NIC and allocates memory at raised IRQL with NdisMAllocateSharedMemoryAsync.

  • MiniportISR

    Not required if the NIC managed by the miniport driver does not generate interrupts, the miniport driver polls the NIC state with a miniport driver-supplied timer function, or if other conditions apply. For more information, see Registering Handlers for Interrupt Support.

  • MiniportHandleInterrupt

    Required if a NIC managed by the miniport driver generates interrupts.

  • MiniportEnableInterrupt and MiniportDisableInterrupt

    Not required if the NIC managed by the miniport driver does not generate interrupts.

  • MiniportCheckForHang

    If not supplied, the miniport driver relies on NDIS to determine whether the NIC is hung, based on sends and requests that timeout.

A connection-oriented miniport driver cannot export the following MiniportXxx functions:

MiniportQueryInformation

MiniportSetInformation

MiniportSend

MiniportSendPackets

MiniportTransferData

The following topics describe the criteria for choosing when to register optional MiniportXxx functions.


Registering Handlers for Interrupt Support

This section describes how to choose interrupt-support handlers for a miniport driver that manages a NIC that generates interrupts. For a detailed description of interrupt handling, see Handling an Interrupt.

When a NIC interrupts, NDIS fields the interrupt; that is, NDIS is always called first when a NIC interrupts. NDIS determines to which miniport driver the interrupt belongs and either calls that miniport driver's MiniportISR function or handles the interrupt for the miniport driver if the interrupt is not shared and if the miniport driver specified in its call to NdisMRegisterInterrupt that NDIS should not call its MiniportISR function. If NDIS does not call a miniport driver's ISR function, NDIS disables further interrupts by calling the miniport driver's MiniportDisableInterrupt function and then queues the miniport driver's MiniportHandleInterrupt DPC function.

If a miniport driver handles its device interrupts, it must register its ISR handler in an NDIS_MINIPORT_CHARACTERISTICS structure and indicate that it wants its ISR handler called by setting the RequestIsr argument of NdisMRegisterInterrupt to TRUE.

Registering an ISR Handler

A miniport driver for a NIC that generates interrupts must register an ISR handler if any of the following is true:

  • The miniport driver manages a NIC that can interrupt during miniport driver initialization or during a miniport driver halt operation
  • The miniport driver's NIC shares an IRQ with another device
  • The miniport driver must capture interrupt-specific data from NIC registers at DIRQL.

Such a miniport driver must also set RequestIsr to TRUE when it calls NdisMRegisterInterrupt. If the interrupt is shared, the miniport driver must also set SharedInterrupt to TRUE when calling NdisMRegisterInterrupt.

If none of the above-listed conditions are true, a miniport driver for a NIC that generates interrupts can specify that NDIS handle interrupts by calling NdisMRegisterInterrupt with RequestIsr set to FALSE and SharedInterrupt set to FALSE.

Registering a HandleInterrupt Handler

A miniport driver must register an HandleInterrupt Handler if it manages a NIC that generates interrupts. Even if NDIS completely handles the interrupt, it will always queue a DPC for the miniport driver, causing the miniport driver's MiniportHandleInterrupt handler to run.

Enabling and Disabling Interrupts

If the NIC does not generate an interrupt, the miniport driver does not need to provide a MiniportEnableInterrupt or MiniportDisableInterrupt function. If a miniport driver always handles its interrupts in a MiniportISR function and schedules a MiniportHandleInterrupt function, it might not provide specific MiniportEnableInterrupt or MiniportDisableInterrupt functions. Instead, such a miniport driver can choose to disable interrupts within its ISR and enable them within its DPC, without providing specific driver functions for this purpose. If a miniport driver specifies that NDIS handle its interrupts, it must supply a MiniportDisableInterrupt function, and if the miniport driver does not reenable interrupts in its MiniportHandleInterrupt function, it must have a MiniportEnableInterrupt function.


Choosing a Send Function for Connectionless Miniport Drivers

A miniport driver for connectionless media handles send packets with its MiniportSendPackets function. NDIS also supports a MiniportSend function for legacy connectionless miniports.

MiniportSendPackets can input more than one packet in a single call. NDIS passes packets to MiniportSendPackets as an array of pointers to packet descriptors. MiniportSend, however, can input only one packet in a single call.

In general, a miniport driver supplies a MiniportSendPackets function if it can simultaneously send multiple packets to its NIC. For example, a miniport driver that manages a bus-master DMA NIC that has an onboard ring typically supplies a MiniportSendPackets function. For such a NIC, the miniport driver can set up the ring with a number of packets and transmit them in a single operation.

Even if a NIC can only accept one packet at a time for transmission, improved performance can be attained by queuing within the miniport driver packets received by MiniportSendPackets. Such a strategy avoids the latency of repeated calls to MiniportSend.

If a miniport driver supplies entry points for both MiniportSend and MiniportSendPackets in NDIS_MINIPORT_CHARACTERISTICS, NDIS always calls MiniportSendPackets to pass send requests to the miniport driver.


Choosing a Receive Function for Connectionless Miniport Drivers

The way in which a connectionless miniport driver passes incoming packets to upper layers determines whether it must register a MiniportReturnPacket function or a MiniportTransferData function:

  • If the miniport driver indicates packets to upper layers by calling NdisMIndicateReceivePacket, it must register a MiniportReturnPacket function.
  • If the miniport driver is a legacy driver that indicates packets to upper layers by calling a filter-specific NdisM Xxx IndicateReceive function, it must register a MiniportTransportData function.

For a description of miniport driver receive operations, see Receiving Data.


Registering an AllocateComplete Handler

A bus-master DMA miniport driver must supply a MiniportAllocateComplete function if it calls NdisMAllocateSharedMemoryAsync to allocate buffer space. NdisMAllocateSharedMemoryAsync can be called at raised IRQL—for example, from a driver's MiniportHandleInterrupt function. Rather than forcing a driver to allocate all the buffer space it will ever require in MiniportInitialize, a driver can call NdisMAllocateSharedMemoryAsync when it runs short of buffers. Usually only a miniport driver that calls NdisMIndicateReceivePacket will have such a need.

A miniport driver that indicates up a complete packet (typically a miniport driver that manages a bus-master DMA device with a ring buffer) relinquishes ownership of indicated packets to upper layers; therefore, it relies on the upper layers to return the packets promptly. If the miniport driver runs short of buffers for received data because packets are not returned promptly, it can allocate a buffer in its MiniportHandleInterrupt function at raised IRQL by calling NdisMAllocateSharedMemoryAsync. NDIS calls the miniport driver's MiniportAllocateComplete function when the asynchronous allocation is finished.


Registering a CheckForHang Handler

A miniport driver can optionally supply a MiniportCheckForHang function when it calls NdisMRegisterMiniport. If a miniport driver does not register such a handler, it relies on NDIS to detect whether its NIC has stopped responding.

If a miniport driver supplies a MiniportCheckForHang function, NDIS calls this function every two seconds or at a driver-requested timeout interval. The MiniportCheckForHang function determines whether the NIC has stopped responding. MiniportCheckForHang returns TRUE if it detects that the NIC has stopped responding; otherwise, it returns FALSE.

If a miniport driver does not register a MiniportCheckForHang function, NDIS concludes that a miniport driver has stopped responding if:

  • A send packet has been pending longer than twice the timeout period. For example, the miniport driver was passed a packet to send, it returned NDIS_STATUS_PENDING, and did not call NdisMSendComplete for the pending packet in a period equal to twice the timeout period. This applies only to serialized miniport drivers.
  • A request sent to MiniportQueryInformation or MiniportSetInformation has not completed within the timeout period. In Windows XP and later, NDIS allows for three times the normal timeout period for queries of OID_GEN_LINK_SPEEDand OID_GEN_MEDIA_CONNECT_STATUS.

A miniport driver can change timeout parameters by calling NdisMSetAttributesEx in the context of its MiniportInitialize function. For more information, see Initializing a NIC. With NdisMSetAttributesEx, the miniport driver can increase the default two-second timeout interval to a driver-specified interval. NDIS will call the miniport driver's MiniportCheckForHang function at this new interval. Miniport drivers for slow NICs can specify a timeout interval that is appropriate for the NIC.

The miniport portion of an intermediate driver should set the following flags related to timeouts when calling NdisMSetAttributesEx:

  • NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT to prevent NDIS from timing out pending send packets that it has queued for the driver
  • NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT flags to prevent NDIS from timing out query and set requests that it has queued for the driver

If the miniport driver specifies that NDIS should ignore packet timeout and request timeout, the miniport driver is responsible for detecting when a NIC is hung.

If MiniportCheckForHang returns TRUE, or if a send or a request has been pending for more than twice the timeout period, NDIS calls MiniportReset.


NDIS Miniport Driver Initialization

When a miniport driver's DriverEntry function returns, NDIS calls the miniport driver's MiniportInitialize function once for each NIC managed by the miniport driver.

If a new NIC is plugged into the system, that miniport driver's MiniportInitialize function will be called to initialize the newly installed device. Consequently, a MiniportInitialize function and any functions it calls, all of which run at IRQL PASSIVE_LEVEL, can be specified as pageable. Code is specified as pageable by using the NDIS_PAGABLE_FUNCTION macro. Initialization code cannot be specified with the NDIS_INIT_FUNCTION macro, because code marked this way is no longer mapped once the initial system boot is complete. Only the DriverEntry function and any functions called only from DriverEntry can be passed to the NDIS_INIT_FUNCTION macro.

The initialization function is declared as follows:

NDIS_STATUS
  MiniportInitialize (
    OUT PNDIS_STATUS  OpenErrorStatus,
    OUT PUINT  SelectedMediumIndex,
    IN PNDIS_MEDIUM  MediumArray,
    IN UINT  MediumArraySize,
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN NDIS_HANDLE  ConfigurationHandle
    );

The following arguments are passed to MiniportInitialize.

  • An array of NdisMedium Xxx at MediumArray. The miniport driver must choose the medium it supports or prefers and must return the index of that medium in SelectedMediumIndex. If the miniport driver does not find a medium it can support in MediumArray, it must return a failure status of NDIS_STATUS_UNSUPPORTED_MEDIA.
  • A handle, MiniportAdapterHandle, that NDIS uses to refer to the miniport driver. The miniport driver must retain this handle so that it can pass it in subsequent calls to NDIS—for instance, in such calls as NdisMRegisterAdapterShutdownHandler and NdisMInitializeTimer.
  • A configuration handle that identifies the registry key containing NIC-specific information (the advanced parameters) associated with this miniport driver. The miniport driver must retain and pass this handle to NdisOpenConfiguration. For information on parameter values written to the registry by network INF files, see Add-registry-sections.

Experimental Medium Types

NDIS media types and associated identifiers are contained in the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NDIS\MediaTypes. This key contains a current list of the system-defined media types. Only media found in this key will be passed to MiniportInitialize at MediumArray. To specify an unsupported experimental media type, the driver writer can add an experimental media type to the registry as described in Installing Network Components.


Initializing a NIC

From its MiniportInitialize function, a miniport driver must initialize its NIC. This process involves three major steps:

  1. The miniport driver allocates memory for the adapter-specific context area in which it typically maintains the NIC state.
  2. The miniport driver reads configuration information and stores this information in the adapter-specific context area.
  3. The miniport driver registers the NIC with NDIS.

Registering a Network Interface Card with NDIS


Allocating an Adapter-Specific Context Area

From its MiniportInitialize function, a miniport driver typically allocates memory for a driver-internal structure in which it stores adapter-specific context such as the following:

  • The miniport driver adapter handle provided by NDIS to MiniportInitialize
  • The configuration information derived from calling NdisReadConfiguration
  • Any other state information the miniport driver requires

For instance, a driver that allocates a staging buffer for received data in its MiniportInitialize function could attach the buffer to this structure. If the driver queues sends, the listhead for this queue could be part of this structure.

A miniport driver calls NdisAllocateMemoryWithTag to allocate storage for such a structure. The miniport driver calls NdisZeroMemory to clear this storage before initializing it. The miniport driver subsequently passes a pointer to this structure to NdisMSetAttributesEx. NDIS retains the pointer to this adapter-specific context and passes it to the miniport driver's MiniportXxx functions—for example, to MiniportSend, MiniportISR, and MiniportHandleInterrupt. A miniport driver uses the adapter-specific context to maintain whatever adapter-specific run-time state it requires to process sends, receives, and requests.


Reading Configuration Information

After allocating and zero-initializing a structure to contain adapter-specific information, a miniport driver must obtain configuration information for its NIC. Within the context of its MiniportInitialize function, a miniport driver obtains configuration information for a NIC as follows:

  1. The miniport driver calls NdisMQueryAdapterResourcesto obtain a list of hardware resources for the NIC.
  2. The miniport driver calls NdisOpenConfiguration to open and obtain a handle to the registry key that contains the advanced parameters for the NIC.
  3. The miniport driver calls NdisReadConfiguration to read the entries in the key for which NdisOpenConfiguration obtained a handle. The miniport driver calls NdisReadConfiguration once for each keyword to retrieve the associated value. NdisReadConfiguration finds the value entry name that matches the keyword and returns the value and NDIS_STATUS_SUCCESS to the miniport driver.
  4. The miniport driver can call NdisOpenConfigurationKeyByIndex or NdisOpenConfigurationKeyByName to open and get a handle to information stored in a subkey below the registry key opened with NdisOpenConfiguration. The miniport driver then calls NdisReadConfiguration to read values stored in the opened key.
  5. After a miniport driver has obtained the values it requires from the registry, it calls NdisCloseConfiguration. When NdisCloseConfiguration returns, the handle to the registry key is no longer valid.
  6. The miniport driver obtains bus-type-specific information with bus-type-specific functions if such functions exist for the type of I/O bus on which the adapter is connected. For example, if the bus-type is PCI, the miniport driver calls NdisReadPciSlotInformation. The bus-type specific functions are listed in NDIS-Supplied Hardware Configuration Functions.
  7. If the NIC is software-programmable, the miniport driver calls NdisReadNetworkAddress to read the network address of the NIC from the registry so that the address subsequently can be written to the adapter EPROM.

A miniport adapter should default values for all advanced parameters. If the miniport driver cannot obtain the advanced parameter values from the registry, it must use the default values for the advanced parameters.


Initializing the NIC

After the miniport driver has read the information it needs to describe the characteristics of the NIC and stored the information as required in its miniport driver adapter context, the miniport driver calls NdisMSetAttributesEx. In this call, the miniport driver does the following:

  • Passes the miniport driver adapter handle that NDIS supplied to the miniport driver's MiniportInitialize function
  • Passes a handle to the miniport driver adapter context. NDIS will pass the handle to this adapter-specific context area back to the miniport driver when it calls any MiniportXxx function.
  • Specifies whether its NIC is a bus-master DMA device
  • Specifies the I/O bus interface type of the caller's NIC

The miniport driver can also set one or more of the following attribute flags when calling NdisMSetAttributesEx:

NDIS_ATTRIBUTE_BUS_MASTER
Set if the caller's NIC is a bus-master DMA device.
NDIS_ATTRIBUTE_DESERIALIZE
Set if the caller is a deserialized miniport driver.
NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT
Set if NDIS should not attempt to time-out pending send packets that it holds queued to the caller. Intermediate drivers should set this flag, but miniport drivers should not.
NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT
Set if NDIS should not attempt to time-out pending query and set requests that it holds queued to the caller. Intermediate drivers should set this flag, but miniport drivers should not.
NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER
Set if the caller is an intermediate driver.
NDIS_ATTRIBUTE_IGNORE_TOKEN_RING_ERRORS
Set if NDIS should not call a Token Ring NIC driver's MiniportReset function if Token Ring errors are indicated.
NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND
Set if NDIS should not call a driver's MiniportHalt function before the system transitions to a low-power (sleeping) state. An intermediate driver must set this flag. A legacy miniport driver that manages a non-PM-aware NIC can set this flag to prevent NDIS from halting the miniport driver before the system transitions to the sleeping (D3) state. A legacy miniport driver should set this flag only if it saves all hardware context that it may require, can put its NIC in an appropriate state for the sleeping state (D3), and can reactivate the NIC to the working state (D0). Drivers that rely on hardware-maintained state should not set this flag.
NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK
Set if the driver can handle removal of its NIC without user notification. Such a driver exports a MiniportPnPEventNotify function. System support for NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK is available in Windows XP and later operating systems.
NDIS_ATTRIBUTE_NOT_CO_NDIS
Set by a driver that can support both connection-oriented and connectionless devices to indicate that the device is a connectionless device. System support for NDIS_ATTRIBUTE_NOT_CO_NDIS is available in Windows XP and later operating systems.
NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS
Set by a driver that uses NdisBufferVirtualAddressSafe, NdisGetFirstBufferFromPacketSafe, and NdisQueryBufferSafe exclusively to access system virtual addresses for send packet buffers. NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS is also set by a driver that exclusively uses physical addresses to access such buffers. Setting NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS can improve performance since the operating system will not have to map send packet buffers to system virtual addresses. System support for NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS is available in Windows XP and later OS versions.


Claiming Resources

After a miniport driver has determined its hardware resources and called NdisMSetAttributesEx, it claims the system resources it will use. The miniport driver must call NdisMSetAttributesEx before claiming resources, including initializing timers.

Regardless of the type of NIC it manages, a miniport driver must allocate the memory it needs to manage its device. This memory is in addition to that allocated by the miniport driver for its miniport driver adapter context. For instance, the miniport driver might allocate memory for receiving incoming frames or for staging buffers for outgoing data.

The following sections describe how miniport drivers allocate memory and register I/O ports. These operations are described in general terms and then specifically for bus-master DMA NICs, programmed I/O NICs, memory-mapped NICs, and slave DMA NICs.


Allocating Memory

During initialization, a miniport driver generally allocates any buffers, packet descriptors and buffer descriptors that it requires to send and receive data. The type and amount of memory that must be allocated depends on the type of NIC, as well as on the type of receive paradigm supported by the miniport driver.

Memory can be shared or unshared. A driver allocates shared memory only when that memory will be accessed by a bus-master DMA NIC. Miniport drivers for bus-master DMA NICs must allocate shared memory for any buffers that will be accessed by both the miniport driver and the NIC. Shared memory is a scarce system resource and is therefore harder to allocate.

A miniport driver that manages a bus-master DMA NIC must ensure that any cached memory it uses is coherent before reading received data from the buffer or before sending data from the buffer. Such a miniport driver must flush its buffers to ensure cache coherency on sends and receives.

A miniport driver that manages a slave DMA NIC or a non-DMA NIC does not have to maintain cache coherency. The Ndis Xxx functions called by a miniport driver for slave DMA NIC perform memory flushes on behalf of the miniport driver. A miniport driver for a non-DMA NIC does not allocate cached memory.

The following functions can be called to allocate memory.

  • NdisAllocateMemoryWithTag allocates, from resident (nonpaged) system-space memory, a buffer whose length is specified by the caller. The memory is not shared, but it can be cached or noncached, depending on the caller's request. The memory can be contiguous and within a particular physical address boundary.
  • NdisMAllocateSharedMemory allocates shared memory, which can be cached or noncached. This call returns both a physical address pointer that the NIC uses and a virtual address pointer that the miniport driver uses. NdisMAllocateSharedMemory must be called after NdisMSetAttributesEx and after NdisMAllocateMapRegisters or NdisMInitializeScatterGatherDma.
  • NdisAllocatePacketPool or NdisAllocatePacketPoolEx allocates and initializes a block of nonpaged system memory from which packet descriptors are allocated.
  • NdisAllocatePacket allocates a packet descriptor from the packet pool allocated by calling NdisAllocatePacketPool(Ex).
  • NdisAllocateBufferPool returns a handle that the caller can use to allocate buffer descriptors with NdisAllocateBuffer.
  • NdisAllocateBuffer allocates a buffer descriptor from the buffer pool allocated with NdisAllocateBufferPool.


Registering Ports

A miniport driver calls NdisMRegisterIoPortRange to claim the I/O port addresses it requires to write to or read from the port using NdisRawWrite(Read)Port Xxx.

When a miniport driver calls NdisMRegisterIoPortRange, the function:

  1. Verifies that the I/O port that the NIC is trying to register has been allocated for the device.
  2. Maps the I/O port so that the miniport driver can write to and read from the device registers using NdisRawWrite(Read)Port Xxx. The NdisRawWrite(Read)Xxx functions cannot be used until NdisMRegisterIoPortRange completes successfully.


Bus-master DMA Device Initialization

A miniport driver that manages a bus-master DMA NIC calls NdisMInitializeScatterGatherDma from its MiniportInitialize function to initialize DMA resources. The benefits of using NdisMInitializeScatterGatherDma are that system resources, such as map registers, are dynamically allocated and deallocated for each DMA transfer (thereby better utilizing system resources) and that DMA performance is improved through a streamlined procedure for obtaining the physical addresses of mapped virtual ranges. NdisMInitializeScatterGatherDma supports only 32-bit and 64-bit DMA addresses; it does not support 24-bit DMA addresses.

A legacy miniport driver that manages a bus-master DMA NIC calls NdisMAllocateMapRegistersfrom its MiniportInitialize function instead of NdisMInitializeScatterGatherDma. In effect, NdisMAllocateMapRegisters statically allocates map registers; however, this results in poorer DMA performance and poorer utilization of system resources. A miniport driver allocates map registers once, during initialization. After the registers are successfully allocated, they belong to the miniport driver until they are deallocated until the driver is halted.

Allocating a Packet Pool, a Buffer Pool, and Shared Memory for Buffers

The amount of memory allocated for packet pool, buffer descriptors, and shared memory allocated for buffers, should be driven by the number of map registers and, possibly, by whether the miniport driver is running on a uniprocessor or multiprocessor machine. A miniport driver can determine the type of machine with NdisSystemProcessorCount. Typically, a machine with more than one processor is a server. Servers usually handle more network traffic than uniprocessor machines (which are typically clients); therefore, it generally makes sense to allocate more resources for servers.

In addition to the memory allocated for its miniport driver adapter context, a bus-master DMA miniport driver should set up the packet pool it will use for indicated packets. During initialization, the miniport driver must:

  • Allocate packet pool for packet descriptors by calling NdisAllocatePacketPool. It must call NdisAllocatePacket to allocate single packet descriptors from the packet pool.
  • Allocate buffer pool for buffer descriptors to map the buffers that will make up the packet by calling NdisAllocateBufferPool.
  • Allocate shared memory for the number of buffers that will be used for receiving data incoming from the network by calling NdisMAllocateSharedMemory. The memory must be shared memory because it is accessible both by the NIC and the miniport driver. When the memory is used for sending and receiving, the NIC is using host memory. The NIC uses the physical address of the memory; the miniport driver uses the virtual address. Note that the call to NdisMAllocateSharedMemory fails unless the caller has first allocated map registers with NdisMAllocateMapRegisters or initialized system resources with NdisMInitializeScatterGatherDma.

Generally, a miniport driver for a DMA NIC should allocate cached memory. There are exceptions that are noted in Cache Considerations for Receiving Data. The miniport driver for such a NIC must flush its buffers to ensure cache coherency on sends on receives.

If the miniport driver supports multipacket receive indications up to NDIS, it must also allocate memory for the array used to pass the pointers to the packets, which can be of any type.


Programmed I/O Device Initialization

A miniport driver that manages a programmed I/O (PIO) device performs sends and receives by writing and reading data to and from a port range. The miniport driver calls NdisRawReadPort Xxx to read the data from the port to a receive buffer either in its MiniportTransferData function if the buffer belongs to the protocol or in its MiniportHandleInterrupt function into a staging buffer. On a send, the miniport driver uses NdisRawWritePort Xxx to write the data from the packet sent to its MiniportSend or MiniportSendPackets function into the NIC registers it claimed at initialization time.

If it uses a staging buffer, the miniport driver must allocate the buffer with NdisAllocateMemoryWithTag. Unless the driver supports multipacket-receive indications, any additional memory it needs to manage its device can be also be nonshared, allocated by calling NdisAllocateMemory. If the miniport driver indicates using NdisMIndicateReceivePacket, it must allocate at least one packet as described in Allocating Memory.

To set up its port range, the miniport driver must:

  1. Call NdisMQueryAdapterResources to obtain a list of hardware resources for the NIC.
  2. Call NdisMRegisterIoPortRange to claiming the I/O ports
  3. Use NdisRead(Write)Port Xxx calls to move data


Memory-Mapped Device Initialization

The miniport driver for a memory-mapped device must map the NIC's on-board memory to system-space memory on the host so that it can transfer incoming data from the board and outgoing data to the board. The memory to which and from which the miniport driver transfers data is part of the NIC; however, the driver uses mapped virtual system-space addresses.

When data is received, the miniport driver indicates the receive as one or more virtual ranges mapped by buffer descriptors and when/if its MiniportTransferData function is called, the miniport driver copies the data from the on-board memory to the protocol driver's supplied buffer. If no protocol driver transfers the data, the data is discarded when the miniport driver returns from its MiniportHandleInterrupt function. If the miniport driver uses a staging buffer, it is allocated with NdisAllocateMemoryWithTag.

Like a PIO device, a miniport driver for a NIC with on-board RAM must call NdisMRegisterIoPortRange to register its claimed port addresses. This call returns a mapped virtual port addresses that a miniport driver can use to access the registers on the adapter. The port addresses mapped by this function are used only to manage the device with NdisRawWrite(Read)Port Xxx calls (to clear interrupts; to set and clear requested functions) but not to move data as is done for a PIO device.

To move data to and from the board, a miniport driver for this type of NIC must map the NIC device memory onto host address space. During initialization, the miniport driver reads the physical address and size of the on-device memory by calling NdisMQueryAdapterResources. After the configuration is determined, the miniport driver must call:

  • NdisSetPhysicalAddressHigh and NdisSetPhysicalAddressLow to set the 32-bit physical address and then call
  • NdisMMapIoSpace with this physical address to map the device memory into a miniport driver-accessible host address space. NdisMMapIoSpace returns a virtual address pointer that the miniport driver can use to refer to this device memory.

Such a driver uses NdisRead(Write)Register Xxx to read from or write to the NIC's registers.

If the driver indicates requested data with NdisMIndicateReceivePacket or NdisMCoIndicateReceivePacket, it must allocate at least one packet with chained buffer(s) as described in Allocating Memory.


Slave DMA Device Initialization

A miniport driver that manages a slave DMA NIC calls NdisMAllocateSharedMemoryto allocate memory from which it transfers data to the system DMA controller on a send, and to which received data is transferred on a receive.

A miniport driver that manages a slave DMA device calls the following:

  • NdisMRegisterDmaChannel to claim a channel to use for sends and receives
  • NdisMAllocateSharedMemory to allocate memory from which it will write data to and read data from the DMA controller.

The memory is mapped for the DMA transfer when the send or receive occurs. If the driver indicates received data with NdisMIndicateReceivePacket or NdisMCoIndicateReceivePacket, it must allocate at least one packet as described in Allocating Memory.


Registering an Interrupt

After calling NdisMSetAttributesEx, allocating memory, and claiming resources, a miniport driver that manages an interrupting NIC must call NdisMRegisterInterrupt to identify the interrupt and to claim an interrupt vector/level. The miniport driver allocates resident storage for an opaque variable of type NDIS_MINIPORT_INTERRUPT, and passes a pointer to the variable to NdisMRegisterInterrupt. The miniport driver passes information about its interrupt, such as the following:

  • The bus-relative interrupt vector and interrupt level
  • Whether its MiniportISR should be called at every interrupt
  • Whether its interrupt is shared
  • Its interrupt mode

The interrupt mode specified by the miniport driver is either NdisInterruptLevelSensitive or NdisInterruptLatched. NdisMRegisterInterrupt makes HAL calls on behalf of the miniport driver to claim an interrupt vector, and then connects to the interrupt by calling the I/O system. When NDIS connects to the interrupt, it supplies its own ISR function to be called first on any interrupt. Therefore, when an interrupt occurs, control always goes to NDIS first. Within the NDIS ISR, the decision is made (based on the value of RequestIsr supplied to NdisMRegisterInterrupt) whether to pass the interrupt to the miniport driver's MiniportISR or MiniportDisableInterrupt function or to handle the interrupt within NDIS and then to queue MiniportHandleInterrupt.

NdisMRegisterInterrupt has no effect on the state of the NIC. However, the miniport driver could receive interrupts as soon as it calls NdisMRegisterInterrupt (that is, before NdisMRegisterInterrupt returns), even if the NIC's interrupts are disabled. The miniport driver can keep getting interrupts until its call to NdisMDeregisterInterrupt returns. Before calling NdisMRegisterInterrupt, the miniport driver should therefore perform whatever adapter-specific steps it requires to prepare itself to handle interrupts. That is, the miniport driver must create and initialize any structures it needs, perhaps initializing any spin locks it needs to synchronize access to shared data. When a miniport driver has registered its interrupt and is prepared to handle interrupts, the miniport driver can enable interrupts in a device-specific manner — for instance, by resetting the NIC.

It is good practice for a miniport driver to test its device during initialization to make sure that the device is capable of generating interrupts. When NdisMRegisterInterrupt returns, a miniport driver can perform this test. If the device is not operating correctly, the miniport driver should free all claimed resources and return NDIS_STATUS_FAILURE from MiniportInitialize so that the miniport driver can be unloaded by the system.


Registering a Shutdown Function

NDIS 5.1 miniport drivers should register an entry point for a shutdown function when calling NdisMRegisterMiniport. Other miniport drivers should call NdisMRegisterAdapterShutdownHandler to register a shutdown function.

A miniport driver passes to NdisMRegisterAdapterShutdownHandler the address of its MiniportShutdown function, the miniport driver adapter handle supplied by NDIS to MiniportInitialize, and the context to be passed to MiniportShutdown when it is called. NdisMRegisterAdapterShutdownHandler is typically called last from MiniportInitialize, just before the miniport driver returns from MiniportInitialize.

For more information about the shutdown handler, see Shutdown Handler.


Initializing Polling Timers

MiniportInitialize calls NdisMInitializeTimer to initialize a timer object for each timer that the miniport driver requires. NdisMInitializeTimer associates a miniport driver-supplied timer function with the timer being initialized. When the timer expires, this MiniportTimer function is called. NDIS provides two types of timers: one-shot timers and periodic timers. When a one-shot timer is set by calling NdisMSetTimer and the timer expires, it must be reset by a call to NdisMSetTimer. This requirement can cause the wait time to drift due to the time it takes on each expiration to reset the timer. A periodic timer, once set, continues to expire at every requested time interval. Such a periodic timer is well suited to polling within a miniport driver. Once set with a call to NdisMSetPeriodicTimer, the timer will continue to expire, causing the associated timer function to be called until the timer is reset in a subsequent call to NdisMSetPeriodicTimer or cleared with a call to NdisMCancelTimer.

If a timer function shares resources with any other miniport driver function, access to those resources must be protected. If a timer function shares resources with functions that run at the same IRQL (DISPATCH_LEVEL), access to those resources is synchronized with a spin lock. To acquire the previously initialized spin lock, a function calls NdisDprAcquireSpinLock and NdisDprReleaseSpinLock. These functions are faster than NdisAcquireSpinLock and NdisReleaseSpinLock.

If the timer function shares resources with MiniportISR or MiniportDisableInterrupt, access must be synchronized by calling NdisMSynchronizeWithInterrupt. The miniport driver performs any timer-related operations on the shared resources, which are typically device registers, within its MiniportSynchronizeISR function, whose address is passed to NdisMSynchronizeWithInterrupt.


Synchronization During Initialization

When a miniport driver initializes its NIC, it might need to wait for a state change before continuing execution:

  • MiniportInitialize can call NdisMSleep to delay execution for a specified interval expressed in microseconds. When MiniportInitialize calls NdisMSleep, it is put into a suspended state. When the sleep interval expires, MiniportInitialize resumes execution. MiniportInitialize should not call NdisStallExecution, a function that is only called for intervals less than 50 microseconds.
  • MiniportInitialize can also synchronize with events. MiniportInitialize can create an event by calling NdisInitializeEvent. Then, after MiniportInitialize writes to its NIC, it calls NdisWaitEvent. When an interrupt occurs and MiniportHandleInterrupt runs, it clears the interrupt on the NIC and sets the event by calling NdisSetEvent. MiniportInitialize, which was waiting on the event, now has its wait satisfied, so it clears the event by calling NdisResetEvent and continues with its execution.


Handling Errors During Initialization

If a miniport driver returns a failure status at any time during its initialization — for instance, if it cannot obtain the resources it needs or if it cannot find a medium it supports — it must undo actions that it has taken that affect the overall system. In particular:

  • If it has allocated any memory, the miniport driver must call NdisFreeMemory to deallocate that memory.
  • If it has claimed I/O resources, the miniport driver must call NdisMDeregisterIoPortRange to release those resources.
  • If it has called NdisOpenConfiguration, the miniport driver must call NdisCloseConfiguration.
  • If it has allocated shared memory with NdisMAllocateSharedMemory, it must call NdisMFreeSharedMemory.
  • If it has allocated map registers, the miniport driver must call NdisMFreeMapRegisters. A miniport driver must call NdisMFreeSharedMemory before calling NdisMFreeMapRegisters.
  • If it has allocated a DMA channel, the miniport driver must call NdisMDeregisterDmaChannel.
  • If it has set any timers, the miniport driver must call NdisMCancelTimer once for each timer that it has set. If a call to NdisMCancelTimer fails, the miniport driver must wait for that timer to fire.

A miniport driver that fails during initialization can record the problem in the error log by calling NdisWriteErrorLogEntry with an error code and error-type-specific values.


Querying Miniport Driver Information

Previous Next

Querying Miniport Driver

If MiniportInitialize returns NDIS_STATUS_SUCCESS, NDIS queries and saves the operational characteristics of the driver. These characteristics are represented by object identifiers (OIDs) maintained by the miniport driver. The miniport driver must support all the mandatory general and media-specific OIDs. For more information, see Obtaining and Setting Miniport Driver Information.

Protocol drivers can also issue queries and sets to the miniport driver once MiniportInitialize returns NDIS_STATUS_SUCCESS returns. In particular, a protocol driver can query or set OID_GEN_CURRENT_PACKET_FILTER.


Minimizing Miniport Driver Initialization Time

The time spent in driver initialization can significantly impact the total time required to boot the operating system. It is therefore important to minimize driver initialization time. Driver initialization time should be in the 10s of milliseconds or less.

To reduce initialization time, an NDIS miniport driver should do the following:

  • Perform media detection before checking the link speed. If media detection fails (because a network cable is not connected to the NIC), the miniport driver should not attempt to check the link speed.
  • If media detection is successful, the miniport driver should defer link-speed detection to a timer function. Network protocols are not loaded until after the miniport driver is loaded; therefore, the miniport driver should have sufficient time to obtain the link speed before a protocol requests the link speed by issuing an OID_GEN_LINK_SPEED request.

If a miniport driver receives an OID_GEN_LINK_SPEED request, a OID_GEN_MEDIA_CONNECT_STATUS request, or a request to send a packet before it has obtained the link speed, it should delay the completion of the request or send operation and complete it after obtaining the link speed. The miniport driver should not fail such a request or a send operation. In Windows XP and later, NDIS allows for three times the normal timeout period for queries of OID_GEN_LINK_SPEED and OID_GEN_MEDIA_CONNECT_STATUS. Miniport drivers running under earlier versions of the operating system can use NdisMSetAttributesEx to set an appropriate timeout interval for these queries.

The following pseudocode examples illustrate how to:

  • Handle media detection and link-speed detection during initialization
  • Use a timer function to obtain the link speed and to complete any pending OID requests and send operations
  • Delay completion of OID_GEN_LINK_SPEED and OID_GEN_MEDIA_CONNECT_STATUS requests if link-speed detection is not finished
  • Schedule send operations if link-speed detection is not finished

Handling Media Detection and Link-Speed Detection During Initialization

The following pseudocode illustrates how to handle media detection and link-speed detection in the context of MiniportInitialize:

If (there is no link pulse on the physical layer interface)
  // The cable is not connected to NIC.
{
  // Do not do link-speed detection.
}
else
{
  Adapter->NegotiationDone = FALSE;
  Command NIC to start the link-speed negotiation.
  Start a timer to check for completion of link-speed detection.
  }

Using a Timer Function to Obtain the Link Speed and to Complete Pending OID Requests and Send Operations

To minimize the time it spends in initialization, the miniport driver should defer link-speed detection to a timer function. The following pseudocode illustrates how to use a timer function to obtain the link speed. After the timer function obtains the link speed, it should complete any pending OID requests and restart any pending send operations.

If (NIC has finished link-speed negotiation)
{
  Adapter->NegotiationDone = TRUE;
  if (Adapter->QueryPending)
  {
    // Complete the pending OID request after getting the link speed.
    NdisMQueryInformationComplete();   // If the miniport exports an
// NdisMCoRequestComplete
// function, call
// NdisMCoRequestComplete
// instead.
  }
  if (Adapter->SetPending)
  {
    Send the set filter down to the adapter;
    // The NIC generates an interrupt to indicate the completion
// of the set-filter operation.
  NdisMSendResourcesAvailable();    // Restarts any pending send
                          // operations.
  // This timer does not fire again.
}
else
{
  Restart timer;
}

Pending OID_GEN_LINK_SPEED and OID_GEN_CURRENT_PACKET_FILTER Requests if Link-Speed Detection is Not Finished

If a miniport driver has not completed link-speed detection, it should schedule an OID_GEN_LINK_SPEED request or an OID_GEN_CURRENT_PACKET_FILTER request that it receives. The miniport driver should complete such a pending OID request asynchronously in its timer function (see above) after the timer function has completed link-speed detection.

The following pseudocode shows how to schedule an OID_GEN_LINK_SPEED request in MiniportQueryInformation or MiniportCoRequest if link-speed detection is not finished:

if (!Adapter->NegotiationDone && (OID == OID_GEN_LINK_SPEED))
{
  // Save the current OID request.
  Adapter->QueryPending = TRUE;  //Timer function tests this value.
  return NDIS_STATUS_PENDING;

The following pseudocode shows how to schedule an OID_GEN_CURRENT_PACKET_FILTER request in MiniportQueryInformation or MiniportCoRequest if link-speed detection is not finished:

if (!Adapter->NegotiationDone && (OID == OID_GEN_CURRENT_PACKET_FILTER))
{
  // Save the current OID request.
  Adapter->SetPending = TRUE;  //Timer function tests this value.
  return NDIS_STATUS_PENDING;
}

Pending Send Operations if Link-Speed Detection is not Finished

If a serialized miniport driver has not completed link-speed detection, it should schedule any send operations that it receives and restart such operations in a timer function (see above) after the timer function has completed link-speed detection.

The following pseudocode illustrates how to schedule send operations in MiniportSend if link-speed detection is not finished:

if (!Adapter_>NegotiationDone)
return NDIS_STATUS_RESOURCES;  // Force NDIS to resubmit the send
// when link-speed negotiation is
// finished.

The following pseudocode illustrates how to schedule send operations in MiniportSendPackets if link-speed detection is not finished:

if (!Adapter_>NegotiationDone)
Set the Status member of the NDIS_PACKET_OOB_DATA block
associated with the packet descriptor to NDIS_STATUS_RESOURCES;
return;

A deserialized or connection-oriented miniport driver must queue such send operations internally and complete the send operations after link-speed detection is finished.


Transferring Data

This section describes how a miniport driver handles send and receive operations. This information is described in the following topics:

Handling an Interrupt

Deferred Procedure Handler

Packet Out-Of-Band Data

Sending Packets

Receiving Data

Keeping Statistics

802.1P Packet Priority


Handling an Interrupt

This section describes the handling of interrupts. For more information on registering interrupts, see Registering Handlers for Interrupt Support.

When a network interface card (NIC) generates an interrupt, NDIS fields it and calls the MiniportISR routine of each miniport driver that registered the interrupt during initialization.

Generally, MiniportISR:

  • Determines and records the reason for the interrupt
  • Copies any volatile interrupt-specific information it needs to handle the interrupt into a permanent structure (usually somewhere in the MiniportAdapterContext passed to MiniportISR)
  • Clears the interrupt on the NIC

The definition of MiniportISR is:

VOID
  MiniportISR(
    OUT PBOOLEAN  InterruptRecognized,
    OUT PBOOLEAN  QueueMiniportHandleInterrupt,
    IN NDIS_HANDLE  MiniportAdapterContext
    );

MiniportISR is passed two arguments, InterruptRecognized and QueueMiniportHandleInterrupt, that must be set before returning. MiniportISR must set InterruptRecognized to TRUE if it recognizes the interrupt, or FALSE if it does not. If the interrupt is shared and if the miniport driver does not recognize the interrupt, it returns FALSE.

If MiniportISR recognizes the interrupt and wants its MiniportHandleInterrupt function queued, it must set QueueMiniportHandleInterrupt to TRUE. NDIS does the actual queuing of the MiniportHandleInterrupt function when MiniportISR returns.

While an ISR is executing, all other interrupts on the processor at the same or lower IRQL are masked off. Therefore, it is important for a miniport driver to minimize the time spent in MiniportISR. Otherwise, the overall performance of the system, as well as I/O throughput for the miniport driver, degrades.

It is important for a miniport driver that manages a NIC that shares an interrupt with other devices on the same bus to quickly determine if the interrupt belongs to the miniport driver. If the interrupt does not belong to the miniport driver, the miniport driver should set InterruptRecognized to FALSE and return immediately.

If the interrupt is shared and belongs to the miniport driver, or if the interrupt is not shared but is recognized by the miniport driver (the interrupt is not spurious), the miniport driver should disable interrupts on its NIC and then capture the interrupt-specific information it needs from the NIC registers. The miniport driver captures the interrupt-specific information immediately in MiniportISR, if absolutely necessary, or preferably, the miniport driver captures the interrupt-specific information in the MiniportHandleInterrupt function, which runs at a lower IRQL.

MiniportISR must disable interrupts to ensure that when MiniportHandleInterrupt runs, no information in the NIC will be overwritten by a subsequent interrupt. MiniportISR should read and save only the information that cannot be accessed after it returns. MiniportISR should then return.

If the miniport driver does not want its MiniportHandleInterrupt function to be queued and if it previously disabled interrupts in MiniportISR, it must re-enable the interrupt on the NIC before returning from MiniportISR.

Synchronizing with an ISR Function

A miniport driver's MiniportISR function and its MiniportDisableInterrupt function run at DIRQL. Other miniport driver code runs at IRQL <= DISPATCH_LEVEL. To prevent race conditions, any miniport driver function that shares resources with MiniportISR or MiniportDisableInterrupt must synchronize access to the shared resources. A function synchronizes with MiniportISR and MiniportDisableInterrupt by calling NdisMSynchronizeWithInterrupt, supplying a MiniportSynchronizeISR function. MiniportSynchronizeISR runs at DIRQL and can safely access the shared resource.

For example, MiniportHandleInterrupt calls NdisMSynchronizeWithInterrupt before clearing an interrupt status register. This NDIS call takes a SynchronizeFunction argument. Within NdisMSynchronizeWithInterrupt, NDIS calls the miniport driver's SynchronizeFunction at DIRQL, so that this function can safely clear the interrupt status register and be sure that MiniportISR or MiniportDisableInterrupt are not modifying the same register at the same time. SynchronizeFunction should execute as quickly as possible, like the MiniportISR and MiniportDisableInterrupt functions.

The execution of MiniportISR and MiniportDisableInterrupt, both of which run at DIRQL, is synchronized with a spin lock associated with the interrupt object.


DPC Handler

Every miniport driver that manages a network interface card (NIC) that interrupts must have a MiniportHandleInterrupt function. Even if NDIS completely handles the interrupt, it always queues a deferred procedure call (DPC) for the miniport driver, causing the miniport driver's MiniportHandleInterrupt handler to run. If MiniportISR processes an interrupt, it controls whether MiniportHandleInterrupt is queued by the value MiniportISR returns in the InterruptRecognized and QueueMiniportHandleInterrupt arguments. If MiniportISR sets QueueMiniportHandleInterrupt to TRUE, MiniportHandleInterrupt is queued for execution at IRQL DISPATCH_LEVEL.

MiniportHandleInterrupt is called after interrupts have been disabled on the NIC by the MiniportISR or MiniportDisableInterrupt function. MiniportHandleInterrupt should read whatever data it needs to finish processing the interrupt-driven I/O operation. MiniportHandleInterrupt then re-enables interrupts on the NIC, either by letting NDIS call the miniport driver's MiniportEnableInterrupt function after MiniportHandleInterrupt returns control or by enabling the interrupt from within MiniportHandleInterrupt, which is faster. Until interrupts are re-enabled, no further interrupts can occur on the NIC. To ensure that no receive data is missed, MiniportHandleInterrupt should re-enable interrupts as quickly as possible.

A miniport driver that processes interrupts handles data receives and send completes in the context of its MiniportHandleInterrupt function. For example, if MiniportHandleInterrupt determines that the reason for the interrupt is a receive, it indicates the data up by calling NdisMIndicateReceivePacket, NdisMCoIndicateReceivePacket, or NdisM Xxx IndicateReceive in the context of the DPC. For more information about how a miniport driver processes receives, see Receiving Data.

If a connectionless miniport driver determines that the reason for the interrupt is a send completion, it calls NdisMSendComplete to signal the completion of a packet previously sent to MiniportSend or MiniportSendPackets. Similarly, if a connection-oriented miniport driver determines that the reason for the interrupt is a send completion, it calls NdisMCoSendComplete to signal the completion of a packet that was previously sent to MiniportCoSendPackets, which returned NDIS_STATUS_PENDING. The send operations of a miniport driver are described in Sending Packets.

Sustained bursts of network activity, which are typically data receives, can force a miniport driver's MiniportHandleInterrupt function to run for a long time, handling outstanding receive and send-completion events from the NIC. However, MiniportHandleInterrupt should not continue to run indefinitely to handle such outstanding events because MiniportHandleInterrupt runs at DISPATCH_LEVEL and thus prevents all other threads that run at DISPATCH_LEVEL or lower from running on a particular processor. Therefore, MiniportHandleInterrupt should limit the time it spends handling outstanding events. For example, MiniportHandleInterrupt might limit the number of iterations it executes based on the total number of receive descriptors on the NIC.

When a miniport driver processes a receive, it must not re-enable interrupts until either of the following has occurred:

  • The miniport driver has passed up an entire miniport driver-allocated packet or an array of packets containing the received data
  • The miniport driver's MiniportTransferData function has transferred the incoming data to a protocol driver-supplied packet if any protocol driver is interested in the data (Only connectionless miniports can have a MiniportTransferData function.)

If a miniport driver-allocated packet is passed up to a protocol driver and the protocol keeps the packet, the miniport driver must supply a new empty packet for the next receive. After it has completely processed the receive and is prepared for the next receive, the miniport driver can re-enable interrupts.


Packet Out-of-Band Data

Every NDIS_PACKET-type descriptor has an associated out-of-band (OOB) data block in which media-specific and priority information is passed. This substructure is defined as:

typedef struct _NDIS_PACKET_OOB_DATA {
    Union {
        ULONGLONG   TimeToSend;
        ULONGLONG   TimeSent
         }
    ULONGLONG       TimeReceived;
    UINT            HeaderSize;
    UINT            SizeMediaSpecificInformation;
    PVOID           MediaSpecificInformation;
    NDIS_STATUS     Status;
    }; NDIS_PACKET_OOB_DATA, *PNDIS_PACKET_OOB_DATA

A miniport driver that has support for OOB data should use the NDIS macros provided for accessing such data. It should never attempt to calculate offsets or otherwise take actions that depend on knowing the exact structure of a packet's OOB data.

The NDIS macros for OOB data include the following:

NDIS_OOB_DATA_FROM_PACKET( Packet )
Returns a pointer to the NDIS_PACKET_OOB_DATA substructure. This pointer can be used to access members of NDIS_PACKET_OOB_DATA by member name.
NDIS_SET_PACKET_STATUS( Packet, Status )
Sets the Status member.
NDIS_SET_PACKET_TIME_TO_SEND( Packet, TimeToSend )
Sets the TimeToSend member.
NDIS_SET_PACKET_TIME_SENT( Packet, TimeSent )
Sets the TimeSent member.
NDIS_SET_PACKET_TIME_RECEIVED( Packet, TimeReceived )
Sets the TimeReceived member.
NDIS_SET_PACKET_HEADER_SIZE( Packet, HeaderSize )
Sets the HeaderSize member.
NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO( Packet, MediaSpecificInfo, SizeMediaSpecificInfo )
Sets the MediaSpecificInformation and SizeMediaSpecificInformation members)
NDIS_GET_PACKET_STATUS( Packet )
Returns the Status member.
NDIS_GET_PACKET_TIME_TO_SEND( Packet )
Returns the TimeToSend member.
NDIS_GET_PACKET_TIME_SENT( Packet )
Returns the TimeSent member.
NDIS_GET_PACKET_TIME_RECEIVED( Packet )
Returns the TimeReceived member.
NDIS_GET_PACKET_HEADER_SIZE( Packet )
Returns the HeaderSize member.
NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO( Packet, pMediaSpecificInfo, pSizeMediaSpecificInfo )
Returns media-specific information in a buffer whose address is provided by the caller. Returns the size in bytes of that information stored in a caller-supplied variable.


OOB Data on a Send

When a miniport driver that supports media-specific information, or priority receives a packet to send, it might either:

  • Get TimeToSend
  • Get SizeMediaSpecificInformation and MediaSpecificInformation

Before returning, MiniportSendPackets in a serialized miniport driver sets the Status member for each packet that it is passed. It sets Status to something other than NDIS_STATUS_PENDING if it completes the send synchronously. Otherwise, MiniportSendPackets sets the Status member to NDIS_STATUS_PENDING. When the send completes, the status of the send must be returned in the Status parameter to NdisMSendComplete. After MiniportSendPackets returns, the Status member of the OOB data, as well as all other members, are inaccessible to the NIC driver.

The NDIS library ignores the OOB block in all packet descriptors it submits to the MiniportSendPackets function of a deserialized driver or the MiniportCoSendPackets function of a connection-oriented driver. NDIS assumes a deserialized miniport driver will complete each packet descriptor input to MiniportSendPackets asynchronously with NdisMSendComplete, and that a connection-oriented driver will complete each packet descriptor input to MiniportCoSendPackets with NdisMCoSendComplete. Consequently, the MiniportSendPackets function of a deserialized driver or the MiniportCoSendPackets function of a connection-oriented driver usually ignores the Status member of the NDIS_PACKET_OOB_DATA block, but it can set this member to the same status that it subsequently passes to NdisM(Co)SendComplete.

If MiniportSend is called, and the send is synchronous, status is returned as the status of MiniportSend. The OOB data is never used to return the status of a MiniportSend operation.

In summary:

  • All but the Status member of the OOB data is read-only to the MiniportSendPackets function of a serialized miniport driver. Status is written to return the status of the send for each packet that is completed synchronously.
  • NDIS ignores the Status member in packet descriptors that it submits to the MiniportSendPackets function of a deserialized driver or to the MiniportCoSendPackets function of a connection-oriented driver. The MiniportSendPackets function of a deserialized driver must complete each packet asynchronously with NdisMSendComplete for each packet in the incoming array. Similarly, the MiniportCoSendPackets function of a connection-oriented driver must complete each packet asynchronously with NdisMCoSendComplete for each packet in the incoming array.
  • When a packet is sent asynchronously, either by MiniportSend or MiniportSendPackets, the final status of the send is always returned as a parameter to NdisMSendComplete. When a packet is sent asynchronously by MiniportCoSendPackets, the final status of the send is always returned as a parameter to NdisMCoSendComplete.
  • All the OOB data is read-only to MiniportSend. MiniportSend always returns the status of the send as the status of MiniportSend. If the status returned is NDIS_STATUS_PENDING, the status is returned as a parameter to NdisMSendComplete.


OOB Data on a Receive

If a miniport driver passes media-specific information or priority, it must indicate received data by indicating up one or more entire packets with NdisMIndicateReceivePacket or, if the miniport driver is connection-oriented, with NdisMCoIndicateReceivePacket. Before indicating the packet, the miniport driver must write the Status member of the out-of-band (OOB) data. The miniport driver must always set the Status member, either to NDIS_STATUS_RESOURCES if it doesn't want the higher layer drivers to keep the packet, or to NDIS_STATUS_SUCCESS.

In addition, the miniport driver might do one or more of the following:

  • Set TimeSent if this time can be determined (for example, by an ATM NIC driver).
  • Set TimeReceived.
  • Set HeaderSize. Typically, a miniport driver only needs to set this once per packet descriptor when the packet descriptor is initialized.
  • Set the pointer to MediaSpecificInformation and SizeMediaSpecificInfo.
  • If the miniport driver indicates timestamps for received packets, it must set the TimeReceived and/or TimeSent members in the NDIS_PACKET_OOB_DATA associated with the packet descriptor, using the NDIS_SET_PACKET_TIME_RECEIVED and/or NDIS_SET_PACKET_TIME_SENT macros. If the miniport driver uses the system time for timestamps, it can call NdisGetCurrentSystemTime once to set the receive timestamp for all packets in a particular packet array.
  • If the driver indicates additional OOB information with receives, it must set the SizeMediaSpecificInfo to the number of bytes of information supplied in the caller-allocated buffer at MediaSpecificInformation. The miniport driver can use the NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO macro to set these values. Otherwise, SizeMediaSpecificInfo should be zero, and MediaSpecificInformation should be NULL.

When NdisM(Co)IndicateReceivePacket returns, the OOB data is read-only to the miniport driver. A serialized miniport driver should read the Status member to determine which packets are available for reuse because they have already been consumed by higher layers. Such packets have a status other than NDIS_STATUS_PENDING. Any packet with a Status of NDIS_STATUS_PENDING is owned by a higher layer drivers, is currently unavailable to the miniport driver, and will be returned later to the miniport driver at its MiniportReturnPacket function.

If the miniport driver writes a status of NDIS_STATUS_RESOURCES in any packet in the array of packets that it indicates up, that packet will be returned to the miniport driver when NdisMIndicateReceivePacket returns.

A deserialized or connection-oriented miniport driver must not examine the Status of indicated packets on return of NdisMIndicateReceivePacket. Instead, a deserialized miniport driver must save a packet's Status in a local variable before indicating up the packet descriptor. When NdisMIndicateReceivePacket returns, the miniport driver should check the saved packet Status. If the miniport driver set the packet's Status to NDIS_STATUS_RESOURCES before indicating up the packet descriptor, it should reclaim the packet descriptor immediately after NdisMIndicateReceivePacket returns, preferably by calling its own MiniportReturnPacket function. In this case, NDIS does not call the miniport driver's MiniportReturnPacket function to return the packet descriptor. If the miniport driver set the packet's Status to NDIS_STATUS_SUCCESS before indicating up the packet descriptor, the miniport driver must not reclaim the packet descriptor until NDIS subsequently returns the packet descriptor to the miniport driver's MiniportReturnPacket function.


Sending Packets

A connectionless miniport driver can call one of the following functions to send packets:

MiniportSendPackets
NDIS passes MiniportSendPackets one or more packets at a time as an array of pointers to the packet descriptors.
MiniportSend
NDIS always passes MiniportSend a single packet descriptor at a time.

If a connectionless miniport driver registers both a MiniportSendPackets function and a MiniportSend function with NdisMRegisterMiniport, NDIS calls only MiniportSendPackets.

A connection-oriented miniport driver must use its MiniportCoSendPackets function to send packets. NDIS passes MiniportCoSendPackets one or more packets at a time as an array of pointers to the packet descriptors.

It is generally preferable to allocate cached memory for transmit data. Noncached memory is a scarce system resource. Allocating a large block of noncached memory is not always possible. Any miniport driver that uses noncached memory must allocate it during driver initialization.

A miniport driver should always assume that buffers set up by a protocol driver are cached memory.


Multipacket Sends from Connectionless Miniport Drivers

A connectionless miniport driver that supports multipacket sends declares the following miniport driver function:

VOID
  MiniportSendPackets(
    IN NDIS_HANDLE  MiniportAdapterContext,
    IN PPNDIS_PACKET  PacketArray,
    IN UINT  NumberofPackets
    );

Each PacketArray is a pointer to an array of pointers to one or more packet descriptors. The miniport driver is responsible for sending packets in the priority order specified by the protocol driver. NDIS does not order the packets that it receives from a protocol driver but passes them to the miniport driver in the order that it received them from the protocol driver.

A miniport driver is not required to check the packet size; rather, the miniport driver should assume that a protocol driver will never send a packet that is too large. The protocol driver queries the miniport driver during initialization to determine the maximum packet size it supports. The protocol is responsible for passing only packets of a size supported by the miniport driver.


Multipacket Sends from Serialized Miniport Drivers

Each packet descriptor has associated out-of-band (OOB) data, as described in Packet Out-of-Band Data. The OOB block lets a protocol driver specify a time-to-send (TimeToSend) to a cooperating miniport driver that supports priority sends. The Status member of the OOB block is set by a serialized miniport driver before returning from MiniportSendPackets to indicate the return value of the call. The other members of the NDIS_PACKET_OOB_DATA block are read-only to the miniport driver.

A serialized miniport driver that provides MiniportSendPackets and returns NDIS_STATUS_PENDING for one or more packets must save the pointers to the individual packets for which it returns this pending status. When MiniportSendPackets returns, the array containing the pointers will be returned to the caller.

A serialized miniport driver that does not have the resources to send a packet can set the Status member to NDIS_STATUS_RESOURCES. In this case, NDIS queues the packets and then resubmits them to the miniport driver when it completes a send by calling NdisMSendComplete or calls NdisMSendResourcesAvailable, whichever is called first.

NDIS assumes that, if NDIS_STATUS_RESOURCES is set for one element, it is set for all subsequent array elements. In effect, the miniport driver relinquishes ownership, temporarily or permanently, of any packet in an array of packets for which it sets a Status other than NDIS_STATUS_PENDING before returning from MiniportSendPackets. Otherwise, the miniport driver owns those packet resources until it later relinquishes ownership by calling NdisMSendComplete, passing the final status of the send as a parameter to this call (see preceding figure).

Instead of returning NDIS_STATUS_RESOURCES when it does not have the resources to send a packet, a serialized miniport driver can queue the send request internally. The miniport driver can use the miniport driver-reserved fields in the packet header to link queued packets, which may be linked to its adapter-specific context structure. If the miniport driver queues a packet, it must return NDIS_STATUS_PENDING as the status for the queued packet. To increase throughput, the miniport driver might implement packet queuing to avoid the latency incurred when the packet is returned to NDIS and later resubmitted to the miniport driver.

A serialized miniport driver sets the Status field of every packet before it returns from MiniportSendPackets, whether the packet is completed synchronously or asynchronously.

If a serialized miniport driver completes the send synchronously (see the following figure), it should set the Status member of the OOB data in the packet with the status of the send, which is NDIS_STATUS_SUCCESS, NDIS_STATUS_FAILURE, NDIS_STATUS_RESOURCES, or a miniport driver-determined status. The miniport driver sets the Status member to NDIS_STATUS_PENDING if it keeps the packet and therefore will complete the send later. If the miniport driver returns a status of NDIS_STATUS_RESOURCES for a packet in the array, NDIS requeues that packet and any following packets in the array and submits them later when the miniport driver indicates that it has available resources.

Multipacket Send From a Serialized Miniport Driver—Synchronous Completion

After MiniportSendPackets returns, the Status field of the OOB data is unavailable. Therefore, when a serialized miniport driver completes a packet for which it has previously returned NDIS_STATUS_PENDING, the miniport driver must return the status of the send in the Status parameter of its call to NdisMSendComplete. The miniport driver must not write the Status member of the OOB data for any packets that are completed by calling NdisMSendComplete.


Multipacket Sends from Deserialized Miniport Drivers

Each packet descriptor has associated out-of-band (OOB) data, as described in Packet Out-of-Band Data. The OOB block lets a protocol driver specify a time-to-send (TimeToSend) to a cooperating miniport driver that supports priority sends. Although a deserialized miniport driver can set the Status member of the OOB block before returning from MiniportCoSendPackets, this member is ignored by NDIS. The other members of the NDIS_PACKET_OOB_DATA block are read-only to a miniport driver.

The NDIS library ignores the OOB block in all packet descriptors it submits to the MiniportSendPackets functions of deserialized drivers. NDIS assumes that a deserialized miniport driver will complete each packet descriptor input to its MiniportSendPackets function asynchronously with NdisMSendComplete. Consequently, a deserialized driver's MiniportSendPackets function usually ignores the Status member of the NDIS_PACKET_OOB_DATA block, but it can set this member to the same status that it subsequently passes to NdisMSendComplete.

Rather than relying on NDIS to queue and resubmit send packets whenever MiniportSendPackets lacks sufficient resources for transmitting the packets, a deserialized miniport driver manages its own internal packet queuing. The driver is responsible for holding incoming send packets in its internal queue until they can be transmitted over the network. The driver is also responsible for preserving the protocol-determined ordering of packet descriptors passed to its MiniportSendPackets function. A deserialized miniport driver must complete each incoming send packet with NdisMSendComplete (see the following figure). A deserialized miniport driver cannot call NdisMSendResourcesAvailable.

Multipacket Send From a Deserialized Miniport Driver

A deserialized miniport driver should never pass NDIS_STATUS_RESOURCES to NdisMSendComplete with a protocol-allocated packet descriptor that was originally submitted to its MiniportSendPackets function. The return of such a status would effectively fail the send operation requested by the protocol, resulting in NDIS returning the packet descriptor and all associated resources to the protocol that originally allocated it.


Single-Packet Sends from Connectionless Miniport Drivers

For a single packet send, a connectionless miniport driver declares the following function:

NDIS_STATUS
  MiniportSend(
    IN NDIS_HANDLE  MiniportAdapterContext,
    IN PNDIS_PACKET  Packet,
    IN UINT  Flags
    );

The Flags parameter is defined by cooperating protocol drivers and miniport drivers; NDIS does not define or make any assumptions about this parameter. However, NDIS provides a function, NdisGetPacketFlags, that is called by the miniport driver to retrieve the flag values. The miniport driver retains the packet until the send completes.

A miniport driver is not required to check the packet size; rather, the miniport driver should assume that a protocol driver will never send a packet that is too large. The protocol driver queries the miniport driver during initialization to determine the maximum packet size it supports. The protocol is responsible for passing only packets of a size supported by the miniport driver.

If a miniport driver can complete the send immediately (see the following figure), it returns NDIS_STATUS_SUCCESS, NDIS_STATUS_FAILURE if the send failed for any reason, such as a miniport driver-determined failure status, and then relinquishes ownership of the packet back to the sender. The miniport driver always returns the send status as the status of MiniportSend; it never sets the Status member of the OOB data block for such a packet.

Single-Packet Send From a Connectionless Miniport Driver—Synchronous Completion

If a miniport driver cannot complete the send immediately (see the following figure), it returns NDIS_STATUS_PENDING. In this case, the miniport driver retains ownership of the packet until the send completes. For example, the miniport driver might have queued the packet internally or started but not completed the send before returning a pending status. When the send completes, the miniport driver must call NdisMSendComplete, passing a pointer to the packet descriptor that has been sent and relinquishing ownership of the packet resources back to the sender for reuse or to be freed.

Single-Packet Send From a Serialized Miniport Driver — Asynchronous Completion

How Serialized Miniports Handle a Resource Problem

If a serialized miniport driver lacks the resources for a send, it can return NDIS_STATUS_RESOURCES. In such a case, NDIS queues the packet and resends it to MiniportSend when the miniport driver calls NdisMSendResourcesAvailable or NdisMSendComplete to indicate that it can now accept packets (see the preceding figure).

How Deserialized Miniport Drivers Handle a Resource Problem

If a deserialized miniport driver lacks the resources for a send, it must queue the packet internally and return NDIS_STATUS_PENDING (see the following figure). A deserialized miniport driver cannot return NDIS_STATUS_RESOURCES. The return of such a status would effectively fail the send operation requested by the protocol, resulting in NDIS returning the packet descriptor and all associated resources to the protocol that originally allocated it.

Single-Packet Send From a Deserialized Miniport Driver—Asynchronous Completion

Rather than relying on NDIS to queue and resubmit send packets whenever MiniportSend lacks the resources to transmit a packet, a deserialized miniport driver manages its own internal packet queuing. The miniport driver is responsible for holding incoming send packets in its internal queue until they can be transmitted over the network.


Multipacket Sends from Connection-Oriented Miniports

Previous Next

Multipacket Sends from Connection-Oriented Miniport Drivers

Before transmitting data, a connection-oriented miniport driver typically creates and always activates a virtual connection (VC) on which to send the data. The miniport driver then uses its MiniportCoSendPackets function to send the data. After the data is sent, the miniport driver deactivates and sometimes deletes the VC on which it sent the data. For more information on creating, activating, deactivating, and deleting VCs, see Creating, Activating, Deactivating, and Deleting Virtual Connections.

The following figure illustrates a multipacket send from a connection-oriented miniport driver.

Multipacket Send From a Connection-Oriented Miniport Driver

The definition of MiniportCoSendPackets is:

VOID
  MiniportCoSendPackets(
    IN NDIS_HANDLE  MiniportVcContext,
    IN PPNDIS_PACKET  PacketArray,
    IN UINT  NumberofPackets
    );

The MiniportVcContext identifies the virtual circuit (VC) on which the packet or packets are to be transmitted. The VC was created with a connection-oriented client's or call manager/MCM's call to NdisCoCreateVc, which caused NDIS to call the miniport driver's MiniportCoCreateVc function.

Each PacketArray is a pointer to an array of pointers to one or more packet descriptors. The miniport driver is responsible for sending packets in the priority order specified by the protocol driver. NDIS does not order packets it receives from a protocol driver but passes them to the miniport driver in the order that NDIS received them from the miniport driver.

A miniport driver is not required to check the packet size; rather, the miniport driver should assume that a protocol driver will never send a packet that is too large. The protocol driver queries the miniport driver during initialization to determine the maximum packet size it supports. The protocol is responsible for passing only packets of a size supported by the miniport driver.

Each packet descriptor has associated out-of-band (OOB) data, as described in Packet Out-of-Band Data. The OOB block lets a protocol driver specify a time-to-send (TimeToSend) to a cooperating miniport driver that supports priority sends. Although a connection-oriented miniport driver can set the Status member of the OOB block before returning from MiniportCoSendPackets, this member is ignored by NDIS. The other members of the NDIS_PACKET_OOB_DATA block are read-only to the miniport driver.

The NDIS library ignores the OOB block in all packet descriptors it submits to the MiniportCoSendPackets functions of connection-oriented miniport drivers. NDIS assumes that connection-oriented miniport drivers will complete each packet descriptor input to their MiniportCoSendPackets functions asynchronously with NdisMCoSendComplete. Consequently, MiniportCoSendPackets usually ignores the Status member of the NDIS_PACKET_OOB_DATA block, but it can set this member to the same status that it subsequently passes to NdisMCoSendComplete.

Rather than relying on NDIS to queue and resubmit send packets whenever MiniportCoSendPackets lacks the resources to transmit the packets, a connection-oriented miniport driver manages its own internal packet queuing. Such a miniport driver is responsible for holding incoming send packets in its internal queue until they can be transmitted over the network. The miniport driver must also preserve the protocol-determined ordering of packet descriptors passed to its MiniportCoSendPackets function. A connection-oriented miniport driver must complete each incoming send packet with NdisMCoSendComplete.

A connection-oriented miniport driver should never pass STATUS_INSUFFICIENT_RESOURCES to NdisMCoSendComplete with a protocol-allocated packet descriptor that was originally submitted to its MiniportCoSendPackets function. The return of such a status would effectively fail the send operation requested by the protocol, resulting in NDIS returning the packet descriptor and all associated resources to the protocol that originally allocated it.


Synchronizing Memory Before Sending Data

If a miniport driver manages a bus-master DMA NIC, it must ensure that any data passed to the NIC to be sent over the network is present in physical memory before the NIC attempts to read such data from this shared memory. Therefore, the miniport driver must call NdisFlushBuffer to force flushing of the processor cache. The timing of the flush call is not critical but must be made in MiniportSend or Miniport(Co)SendPackets after the data is written to shared memory and before it is released to the NIC.

For example, to send a packet on the network, MiniportSendPackets usually gives a bus-master DMA NIC the physical addresses of the packet segments in shared memory, and then calls NdisFlushBuffer and NdisMUpdateSharedMemory. The call to NdisFlushBuffer specifies the WriteToDevice parameter as TRUE, indicating that the direction of the transfer is from the host to the NIC. After the miniport driver has called NdisFlushBuffer and NdisMUpdateSharedMemory, it can release the data to the NIC, usually by writing to a NIC register.

Because cache-line tearing is not a problem for transmitted data, the miniport driver can flush the data without concern for cache fill size.

Miniports that manage programmed I/O (PIO) devices are guaranteed that the correct data is transferred to a NIC; therefore, such miniport drivers do not call NdisFlushBuffer.

Miniports for slave DMA NICs are guaranteed that NDIS will ensure cache coherency during DMA transfers.

It is generally preferable to allocate cached memory for transmit data. Noncached memory is a scarce system resource. Allocating a large block of noncached memory is not always possible. Any miniport driver that uses noncached memory must allocate it during driver initialization.

A miniport driver should always assume that buffers set up by a protocol driver are cached memory.


Steps in Sending

The sequence of calls made by a miniport driver to send a packet or packets depends on the type of NIC that the miniport driver manages. This section describes the steps involved in sending a packet on a bus-master DMA NIC, on a PIO device, and using a NIC's onboard memory.


Sending a Packet on a Bus-master DMA NIC

The steps involved in sending a packet on a bus-master DMA NIC depend on how the miniport driver initialized or reserved system resources during DMA initialization:

  • A serialized miniport driver that manages a bus-master DMA NIC must call NdisMAllocateMapRegisters from its MiniportInitialize function to allocate map registers for DMA operations.
  • A deserialized or connection-oriented NIC that manages a bus-master DMA NIC should call NdisMInitializeScatterGatherDma from its MiniportInitialize function to initialize DMA resources. The benefits of using NdisMInitializeScatterGatherDma are that system resources, such as map registers, are dynamically allocated and deallocated for each DMA transfer (thereby better utilizing system resources) and that DMA performance is improved through a streamlined procedure for obtaining the physical addresses of mapped virtual ranges. Instead of calling NdisMInitializeScatterGatherDma, a deserialized or connection-oriented miniport that manages a busmaster DMA NIC can call NdisMAllocateMapRegisters to statically allocate map registers; however, this results in poorer DMA performance and poorer utilization of system resources.

Miniport Drivers that Reserve DMA Resources with NdisMAllocateMapRegisters

Generally, a connectionless miniport driver (either serialized or deserialized) that manages a bus-master DMA NIC exports a MiniportSendPackets function to get the best performance from its NIC. A connection-oriented miniport driver that manages a bus-master DMA NIC always exports MiniportCoSendPackets.

After receiving one or more packet descriptors in its Miniport(Co)SendPackets function, a miniport driver that allocated map registers with NdisMAllocateMapRegisters during DMA initialization performs the following steps when sending a packet using DMA:

  1. The miniport driver calls NdisQueryPacket to read the packet length, to obtain a pointer to the first buffer descriptor, and to determine the number of buffer descriptors and the physical segment count.
  2. The miniport driver may need to determine whether it has available transmit buffers and available transmit buffer descriptors that map buffers in the ring. If either of these resources is unavailable, a serialized miniport driver either fails the call to MiniportSend or MiniportSendPackets with NDIS-STATUS_RESOURCES, returning the packet to NDIS, or queues the packet internally and returns NDIS_STATUS_PENDING. A deserialized or connection-oriented miniport driver always queues the packet internally and returns.
  3. A DMA device can have an upper limit on the number of physical segments that it can map for a single DMA operation. If a miniport driver is given a packet to send that is too fragmented, it must copy the buffers chained to the packet into a single transmit buffer. A miniport should, from its MiniportInitialize function, allocate such a staging buffer and a buffer descriptor to map it. A miniport calls NdisMoveMemory to move data from each protocol-supplied buffer into this transmit staging buffer. A miniport must copy send data only when the packet is too fragmented, because copying to a staging buffer is an expensive operation and adversely affects performance if done too frequently. Generally, if the buffer to be sent is less than 256 bytes, the miniport can improve performance by copying the data into a staging buffer and passing a miniport-allocated descriptor for the buffer to NdisMStartBufferPhysicalMapping.
  4. The miniport calls NdisMStartBufferPhysicalMapping to map the previously allocated shared memory buffer whose contents will be sent. This call takes a Boolean argument, WriteToDevice, that indicates whether data is being moved from host memory to the NIC or from the NIC to host memory. For a send, WriteToDevice is set to TRUE. The miniport must also supply the index of the map register it is using to map the buffer, and this index must be one of the registers returned from calling NdisMAllocateMapRegisters at miniport-initialization time.
  5. If the miniport allocated cached memory for its transmit buffers, it calls NdisFlushBuffer, supplying the address of the buffer being sent and specifying the WriteToDevice parameter as TRUE to indicate that the direction of the transfer is from the host to the NIC. NdisFlushBuffer flushes the processor cache line, ensuring that the memory contents seen by the NIC and the miniport are the same. Because cache-line tearing is not a problem for transmitted data, the miniport can flush the data without concern for cache fill size. To ensure cache-coherency on all platforms, the miniport should also call NdisMUpdateSharedMemory.
  6. The miniport programs the NIC for the transmission, for example, by writing to the control registers. The NIC then performs the DMA transfer.
  7. When the send completes, the miniport calls NdisMCompleteBufferPhysicalMapping to release the map register. If the NIC interrupts at the completion of the send, this call is made from MiniportHandleInterrupt.
  8. The miniport calls NdisMSendComplete or NdisMCoSendComplete.

For more information, see Bus-master DMA Device Initialization.

Miniport Drivers that Initialize DMA Resources with NdisMInitializeScatterGatherDma

Generally, a deserialized miniport driver that manages a bus-master DMA NIC exports a MiniportSendPackets function to get the best performance from its NIC. A connection-oriented miniport driver that manages a bus-master DMA NIC always exports a MiniportCoSendPackets function.

After receiving one or more packet descriptors in its Miniport(Co)SendPackets function, a bus-master DMA miniport driver that initialized system resources with NdisMInitializeScatterGatherDma during DMA initialization performs the following steps when sending a packet using DMA:

  1. The miniport driver calls NDIS_PER_PACKET_INFO_FROM_PACKET with an InfoType of ScatterGatherListPacketInfo. NDIS_PER_PACKET_INFO_FROM_PACKET returns a pointer to a SCATTER_GATHER_LIST structure. This structure specifies an array of SCATTER_GATHER_ELEMENT structures, each of which specifies the base physical address and length of a contiguous range of DMA data to be transferred.
  2. The miniport driver may need to determine whether it has available transmit buffers and available transmit buffer descriptors that map buffers in the ring. If either of these resources is unavailable, a deserialized or connection-oriented miniport driver always queues the packet internally and returns.
  3. A DMA device can have an upper limit on the number of physical segments that it can map for a single DMA operation. If a miniport driver is given a packet to send that is too fragmented, it must copy the buffers chained to the packet into a single transmit buffer. A miniport driver should have allocated such a staging buffer and a buffer descriptor to map it by calling NdisMAllocateSharedMemory from its MiniportInitialize function. A miniport driver calls NdisMoveMemory to move data from each protocol-supplied buffer into this transmit staging buffer. A miniport driver must copy send data only when the packet is too fragmented, because copying to a staging buffer is an expensive operation and adversely affects performance if done too frequently. Generally, if the buffer to be sent is less than 256 bytes, the miniport driver can improve performance by copying the data into a staging buffer.
  4. If the miniport driver allocated cached memory for its transmit buffers, it calls NdisFlushBuffer, supplying the address of the buffer being sent and specifying the WriteToDevice parameter as TRUE to indicate that the direction of the transfer is from the host to the NIC. NdisFlushBuffer flushes the processor cache line to ensure that the memory contents seen by the NIC and the miniport driver are the same. Because cache-line tearing is not a problem for transmitted data, the miniport driver can flush the data without concern for cache fill size. To ensure cache-coherency on all platforms, the miniport driver should also call NdisMUpdateSharedMemory.
  5. The miniport driver programs the NIC for the transmission—for example, by writing to the control registers. The NIC then performs the DMA transfer.
  6. The miniport driver calls NdisMSendComplete or NdisMCoSendComplete. The call to NdisM(Co)SendComplete releases the mapping resources used for the DMA transfer.

For more information, see Bus-master DMA Device Initialization.


Sending a Single Packet on a PIO Device

A miniport driver that controls a NIC that sends data using programmed I/O (PIO) performs the following steps in its send function:

  1. Calls NdisQueryPacket to get the length of the packet. The miniport driver then checks whether there are transmit resources available to send the packet. If resources are not available, the miniport driver returns NDIS_STATUS_RESOURCES or queues the packet internally and returns from its send handler. If a packet is queued in the miniport driver, the miniport driver must return NDIS_STATUS_PENDING for that packet. If the miniport driver supports out-of-band (OOB) data, it uses NDIS macros to read any relevant data from the OOB block. If send resources are available, the NIC driver continues.
  2. Calls NdisQueryPacket to get a pointer to the first buffer descriptor in the packet.
  3. Calls NdisQueryBufferSafe or NdisQueryBuffer to obtain the virtual address of the buffer containing the data to be sent and the number of bytes in that buffer.
  4. Calls NdisRawWritePort Xxx to write the length of the buffer to the port. Miniports that manage PIO NICs are guaranteed that the correct data is transferred to the NIC; therefore, such miniports do not call NdisFlushBuffer.
  5. Calls NdisRawWritePortBuffer Xxx to write the buffer whose address was returned from NdisQueryBuffer(Safe).
  6. Calls NdisGetNextBuffer to get the next buffer in the packet.
  7. Repeats steps 3 through 6 until it has successfully sent all the buffers in the packet.
  8. When MiniportSend is done with a packet, it returns the status as the status of MiniportSend. If the status is not NDIS_STATUS_PENDING, the miniport driver relinquishes the packet descriptor and the resources it specifies back to the caller. The MiniportSendPackets function of a serialized miniport driver returns the status of the send in the Send member of the OOB block for the packet descriptor. If the miniport driver returned a pending status for any packet, it must call NdisMSendComplete when it is done with the packet resources and is ready to relinquish it to the caller. The NDIS library ignores the OOB block in all packet descriptors it submits to the Miniport(Co)SendPackets functions of deserialized and connection-oriented miniports. NDIS assumes that such miniports will complete each packet descriptor input to their MiniportSendPackets or MiniportCoSendPackets functions asynchronously with NdisM(Co)SendComplete. Consequently, the Miniport(Co)SendPackets function usually ignores the Status member of the NDIS_PACKET_OOB_DATA block, but it can set this member to the same status that it will pass to NdisM(Co)SendComplete.


Sending a Packet Using On-Board Memory

A miniport driver that supports a NIC that has on-board memory that appears in the I/O space of the host calls NdisMMapIoSpace from MiniportInitialize to map the adapter's on-board memory onto host memory and to give the miniport driver a virtual address that can be used to refer to the memory. A miniport driver sends data on this type of NIC by moving the buffers to be sent into mapped memory and then writing, in a device-specific way, to the port (or registers) that the miniport driver claimed when it called NdisMRegisterIoPortRange. These actions cause the NIC to put the data on the network medium. If the miniport driver lacks send resources, it either queues the packets or returns the packets to NDIS, as described earlier.

If the miniport driver has send resources available, it calls:

  1. NdisQueryPacket to get the start and length of the packet containing the buffers to be sent.
  2. NdisQueryBufferSafe or NdisQueryBuffer to get the buffer descriptor.
  3. NdisMoveToMappedMemory to move one buffer at a time to the mapped adapter memory buffer.
  4. NdisGetNextBuffer to retrieve the next buffer from the packet and again call NdisMoveToMappedMemory. Repeat these two calls until all the buffers have been transferred.
  5. NdisMRawWritePort Xxx or NdisWriteRegister Xxx to cause the send to occur in a device-specific manner.

The miniport driver should use the length returned from NdisQueryPacket to make sure that there is enough room in on-board memory to contain all the buffers in the packet before starting the copy. If the NIC's memory does not have enough free space for the current packet, a serialized miniport driver can return a status of NDIS_STATUS_RESOURCES, in which case, NDIS queues the packet and resends it later when the miniport driver indicates that it has available resources. Alternatively, a serialized miniport driver can return NDIS_STATUS_PENDING and queue the packet internally. In this case, deserialized miniport drivers, connection-oriented miniport drivers, and WAN miniport drivers must return NDIS_STATUS_PENDING and queue the packet internally.

Sending a Packet on a Slave DMA Device

A slave DMA NIC uses the system DMA controller to transfer data from a packet supplied to its send handler (typically MiniportSend) to the NIC for transmission on the network. Miniports for slave DMA NICs are guaranteed that NDIS will ensure cache coherency during DMA transfers.

For any packet for which the miniport driver has send resources, a miniport driver for a slave DMA NIC does the following:

  1. Calls NdisMSetupDmaTransfer to set up the system DMA controller for the send. The miniport driver passes the handle to a DMA channel that it allocated during miniport driver initialization by calling NdisMRegisterDmaChannel, a pointer to the host memory buffer containing the data to be sent, an offset into the buffer, the length of the data, and a Boolean value that indicates the direction of the transfer—in this case, from host memory to the device. On return from NdisMSetupDmaTransfer, the controller is programmed to transfer the data, including ensuring that the buffer is cache-coherent.
  2. Performs device-dependent steps to cause the transfer (for example by calling NdisRawWritePort Xxx).
  3. When the transfer is complete, the miniport driver calls NdisMCompleteDmaTransfer.

Generally, the miniport driver sets up the complete buffer for transfer. However, if the size of the buffer is greater than the DMA constraints of the NIC, the miniport driver uses the length and offset parameters to send a subrange of the buffer. If the buffer to be sent is less than 256 bytes, the miniport driver can improve performance by copying the data into a staging buffer and passing a miniport driver-allocated descriptor for the buffer to NdisMSetupDmaTransfer.


Receiving Data

To indicate one or more receive packets to higher-level drivers, connectionless miniports call NdisMIndicateReceivePacket; and connection-oriented packets call NdisMCoIndicateReceivePacket.

Legacy connectionless miniports that do not support NdisMIndicateReceivePacket call a medium-specific NdisM Xxx IndicateReceive function to indicate a single packet to higher-level drivers.


Indicating Receive Packets with NdisM(Co)IndicateReceivePacket

To indicate receive data with NdisM(Co)IndicateReceivePacket, a miniport driver:

  • Allocates and manages an array of packet descriptors (The miniport driver must allocate and set up a packet descriptor for a full network packet rather than a lookahead buffer. For more information, see Allocating Memory.)
  • Fills the chained buffers with the received data
  • Calls NdisM(Co)IndicateReceivePacket, passing a pointer to the array of packet descriptors

Before calling NdisMCoIndicateReceivePacket, a connection-oriented miniport driver typically sets up and always activates a virtual connection (VC) on which to receive the data. When the remote party terminates the incoming call, the miniport driver deactivates and sometimes deletes the VC on which it received the data. For a description of VC creation activation, deactivation, and deletion, see Creating, Activating, Deactivating, and Deleting Virtual Connections.

The following figure illustrates indicating receive data with NdisM(Co)IndicateReceivePacket.

Indicating Receive Packets with NdisM(Co)IndicateReceivePacket

The miniport driver passes status, such as the time a packet is received or sent, or other media-specific information, to upper layers by setting members in the out-of-band (OOB) data block associated with each packet descriptor. If the miniport driver is willing to let a protocol keep the packet and return it later to the miniport driver's MiniportReturnPacket function, the miniport driver must set the Status member of the OOB block to NDIS_STATUS_SUCCESS. If the miniport driver is running short of free packet descriptors or buffers and wants to force any interested upper layer driver to copy the packet data before NdisM(Co)IndicateReceivePacket returns, the miniport driver must set the Status member to NDIS_STATUS_RESOURCES. For more information, see Packet Out-of-Band Data.

A serialized miniport driver must always check the Status member in the OOB block that is associated with each packet descriptor when NdisM(Co)IndicateReceivePacket returns:

  • If the Status member is anything except NDIS_STATUS_PENDING, the packet descriptor and all the resources it describes are returned to the miniport driver.
  • If the Status member is NDIS_STATUS_PENDING, ownership of the miniport-allocated packet resources transfers to the protocol driver or to the intermediate protocol driver until the packet descriptor is returned to the miniport's MiniportReturnPacket function.
  • If the miniport driver sets the Status member for any packet in the array to NDIS_STATUS_RESOURCES before calling NdisM(Co)IndicateReceivePacket, that packet will be returned to the miniport driver after higher level drivers have copied the data in the indicated packets. The Status member for all such packets will be set to NDIS_STATUS_SUCCESS.

A deserialized miniport driver must not examine the Status of indicated packets on return of NdisM(Co)IndicateReceivePacket. Instead, a deserialized miniport driver must save a packet's Status in a local variable before indicating up the packet descriptor. When NdisM(Co)IndicateReceivePacket returns, the miniport driver should check the saved packet Status. If the miniport driver set the packet's Status to NDIS_STATUS_RESOURCES before indicating up the packet descriptor, it should reclaim the packet descriptor immediately after NdisM(Co)IndicateReceivePacket returns, preferably by calling its own MiniportReturnPacket function. In this case, NDIS does not call the miniport driver's MiniportReturnPacket function to return the packet descriptor. If the miniport driver set the packet's Status to NDIS_STATUS_SUCCESS before indicating up the packet descriptor, the miniport driver must not reclaim the packet descriptor until NDIS subsequently returns the packet descriptor to the miniport driver's MiniportReturnPacket function.

A miniport driver that manages a bus-master DMA NIC typically indicates packets by calling NdisM(Co)IndicateReceivePacket because its NIC usually has sufficient ring buffer space to receive multiple packets. The miniport driver improves performance by processing several packets at a time.

Usually, a miniport driver for any other type of network interface card (NIC), such as a programmed I/O (PIO) NIC or an adapter-shared-memory NIC, calls NdisM(Co)IndicateReceivePacket only if it needs to pass priority, media-specific information, or the receive time. A non-DMA NIC typically receives only one packet at a time and must be reset between single receives. The miniport driver for such a device can indicate up only one packet at a time with NdisM(Co)IndicateReceivePacket.

Because the miniport driver passes ownership of the packets up when it calls NdisM(Co)ndicateReceivePacket, it must manage its receive buffers well to ensure that buffers are available when new data arrives on the network. Typically, the miniport driver preallocates, in its MiniportInitialize function, a few more buffers than required for the ring buffer and allocates sufficient buffer descriptors to map these buffers and a few packet descriptors for making receive indications.

Handling a Resource Problem

If a miniport driver determines that it is running low on receive buffer space, it can use either of the following strategies:

  • When it calls NdisM(Co)IndicateReceivePacket, the miniport driver should set the Status member of the OOB block to NDIS_STATUS_RESOURCES for each packet descriptor that it does not want the protocol to keep. This tells NDIS that the miniport driver will not give up ownership of the packet's resources to the protocol driver to which the packet is indicated. NDIS ensures that the packet is copied by the protocol driver rather than passed to the protocol driver. If the miniport driver is serialized, NDIS calls the ProtocolReceive function rather than ProtocolReceivePacket function, forcing the protocol driver to copy the packet. If the miniport driver is a deserialized, NDIS calls the protocol driver's Protocol(Co)ReceivePacket function. When the protocol determines that the Status member of the OOB block is set to NDIS_STATUS_RESOURCES, it copies the packet. Because the miniport driver does not have to provide a MiniportTransferData function if it supports the multipacket receive paradigm described here, NDIS intercepts the protocol driver's transfer request and performs the transfer.
  • The miniport driver maintains a high-water mark and low-water mark for its set of free buffers. When the number of buffers approaches the low-water mark, the miniport driver calls NdisMAllocateSharedMemoryAsync to allocate more buffers, and then it calls NdisAllocateBuffer to allocate buffer descriptors to map these buffers. Unlike NdisMAllocateSharedMemory, which can be called only at IRQL < DISPATCH_LEVEL, NdisMAllocateSharedMemoryAsync can be called at IRQL DISPATCH_LEVEL, even in the MiniportHandleInterrupt function. When the set of free buffers exceeds the high-water mark, the miniport driver calls NdisMFreeSharedMemory to free excess buffers, and then it calls NdisFreeBuffer to free the buffer descriptors that map these buffers.


Indicating a Receive Packet with an NdisMXxxIndicateReceive function

Legacy connectionless miniport drivers that do not support NdisMIndicateReceivePacket call a medium-specific NdisM Xxx IndicateReceive function to indicate a single packet to higher drivers.

During initialization, a connectionless miniport driver's MiniportQueryInformation function is called to determine the miniport driver's or network interface card's (NIC) operational characteristics. These characteristics include the minimum size of the lookahead buffer that the miniport driver indicates up. The miniport driver must indicate up at least this minimum amount of data, but it can indicate up more if more data is available on the NIC. For example, because a DMA adapter transfers all the data directly into memory, it usually indicates the complete received buffer up. This makes it possible for a protocol driver to copy the buffer on the indication without having to call NdisTransferData to get the rest of the data.

On the other hand, connectionless miniport drivers that manage programmed I/O (PIO) NICs pass a minimum lookahead buffer up to protocol drivers; the rest of the data is not read until the miniport driver is called at its MiniportTransferData function. Because transferring data in this manner is slow, the miniport driver optimizes for the case that no protocol accepts the packet and that the minimum number of protocols request calls to MiniportTransferData.

A connectionless miniport driver that calls NdisM Xxx IndicateReceive must have a MiniportTransferData function and must be prepared to be called to copy incoming data into a packet with chained buffers passed down by a protocol driver. MiniportTransferData is called in the context of the miniport driver's NdisM Xxx IndicateReceive call. After NdisM Xxx IndicateReceive returns control, the miniport driver can receive new data; that is, it can re-enable receive interrupts.

MiniportTransferData is passed a packet descriptor that can specify a single buffer or a chain of buffers. The miniport driver must divide up the incoming data into these buffers. If the buffers supplied by the protocol driver are insufficient, the miniport driver should fail the transfer call with an appropriate status. However, the protocol driver should not make this mistake because the miniport driver indicates the total size of the incoming network packet in its NdisM Xxx IndicateReceive call. Data transfer can complete synchronously if all the data is transferred inside MiniportTransferData (see the following figure).

Indicating a Receive Packet with an NdisMXxxIndicateReceive Function —Synchronous Completion

Otherwise, MiniportTransferData can return NDIS_STATUS_PENDING. If the miniport driver returns a pending status, it must call NdisMTransferDataComplete after all the data has been transferred (see the following figure). Again, the miniport driver must not re-enable interrupts until the transfer of data has been completed so that the data already received is not overwritten by an incoming receive.

Indicating a Receive Packet with an NdisMXxxIndicateReceive Function ——Asynchronous Completion

A miniport driver must periodically call NdisM Xxx ReceiveComplete, thereby causing NDIS to call each bound protocol drivers' ProtocolReceiveComplete function. The call to ProtocolReceiveComplete notifies a protocol driver that it can process the data that it has already received but not yet fully processed. For example, the miniport driver could indicate the received data to its clients. A miniport driver should call NdisM Xxx ReceiveComplete in its MiniportHandleInterrupt function after every ten receives or before exiting MiniportHandleInterrupt if fewer than ten receives are processed.


Restrictions on Indicating Receive Packets

A connectionless miniport must not indicate a receive packet to a protocol driver while the miniport driver's packet filter for that protocol driver is set to zero. When a miniport driver's MiniportInitialize function is called, the miniport driver's packet filter should be set to zero. When the packet filter is zero, receive indications are disabled. After a miniport driver's MiniportInitialize function has returned, a protocol driver can set OID_GEN_CURRENT_PACKET_FILTER to a non-zero value, thereby enabling the miniport driver to indicate receive packets to that protocol. For more information on packet filters, see OID_GEN_CURRENT_PACKET_FILTER.

All miniport drivers must refrain from indicating receive packets when in a low-power (sleeping) state. For more information on miniport requirements for low-power states, see Handling an OID_PNP_SET_POWER.


Cache Considerations for Receiving Data

If a miniport driver allocates cached memory, it must do the following:

  • Make receive buffers cache-aligned.
  • Flush the cache before starting the receive by calling NdisFlushBuffer and NdisMUpdateSharedMemory.

A miniport driver that manages a bus-master DMA device receives data into memory shared with the network interface card (NIC). The miniport driver must ensure that incoming data is present in shared memory, and not in processor cache, before it begins to read the data. To accomplish this, the miniport driver for such a DMA NIC must call NdisFlushBuffer and NdisMUpdateSharedMemory (for example, in its MiniportHandleInterrupt function) before indicating the receive or otherwise causing a read of the data.

A miniport driver must also prevent cache-line tearing by allocating cache-aligned memory for receive buffers. If a miniport driver allocates a large block of memory and then reallocates that block into smaller buffers for received data, the start of each receive buffer must be cache-aligned so that the buffers do not cross cache blocks. A miniport driver calls the NdisMGetDmaAlignment function during initialization and saves the value that NdisMGetDmaAlignment returns in its adapter-specific context area. The miniport driver uses this value to round up the size of a receive buffer to a cache-line size or a multiple of that size when it allocates such a buffer. The miniport driver must also use the cache block size to calculate where in the preallocated block of memory to begin allocating receive buffers.

In general, a miniport driver for a bus-master DMA NIC should allocate cached shared memory because it is a faster and more available resource. There are two cases in which a miniport driver must use noncached memory:

  • If the NIC managed by the miniport driver receives consecutive packets into contiguous memory, the end of one packet can occupy the same cache block as the start of the next packet. Therefore, the miniport driver must allocate noncached memory because reading the first packet can cause stale cache data for the start of the second one.
  • If releasing the buffers involves writing to them. For example, the receive buffer could be contiguous with a header containing an ownership bit that indicates whether the buffer belongs to the adapter or to the miniport driver. In this case, the adapter may write to that bit before releasing the buffer. A miniport driver that uses this technique must allocate these buffers from noncached memory.


Steps in Receiving Data

How a miniport driver processes received data depends to some extent on the type of network interface card (NIC) that the miniport driver manages. This section describes the process of receiving data for each of the following device types:

  • Bus-master DMA NICs
  • PIO NICs
  • Non-DMA NICs with on-board memory

Some operations are common to all these devices. These operations include:

  • A miniport driver calls NdisRawWritePort Xxx functions to program its NIC.
  • Before indicating up a buffer, a miniport driver that indicates up a complete packet structure must call NdisAdjustBufferLength to adjust the length of the buffer descriptor that describes the buffer. The miniport driver must set the length of the buffer descriptor to the length of the data in the buffer. When the packet is returned, the miniport driver must call this function again to reset it to the actual buffer length.
  • A miniport driver does not enable more receives until the current data has been indicated up and a new set of buffers has been allocated to the receive ring or copied by an interested protocol driver to which the data was indicated.


Packet Management During Receives

Some miniport drivers, such as a miniport drivers for Ethernet network interface cards (NICs), receive packets that have a fixed and known size frame. If the frame size is always the same, the miniport driver can allocate packets with one or more chained buffers and can use the same packets for receives.

If, however, a miniport driver controls a NIC that receives variable-length frames, the size of a packet needed to handle a receive can vary from one receive to the next.

If a miniport driver must handle variable-length receives, it must do the following:

  1. Chain and unchain buffers from a packet by calling Ndis(Un)ChainBufferAtBack or Ndis(Un)ChainBufferAtFront to build a larger, or make a smaller, packet indication.
  2. Call NdisAdjustBufferLength before indicating a packet to set the size in the buffer descriptor for the last buffer in a chain if the full buffer is not used. Call NdisAdjustBufferLength when the packet is returned to reset the length to the actual full length of the buffer.

Buffers that are unchained from a packet descriptor should be kept in a free list to ensure they do not get "lost" and that they will be available when needed.


Receiving Data on a Bus-master DMA NIC

When one or more packets are received, the miniport driver does the following:

  1. Calls NdisFlushBuffer and NdisMUpdateSharedMemory to ensure that the incoming data is coherent in the memory area to be accessed by the miniport driver.
  2. Calls NdisAdjustBufferLength to adjust the length in the buffer descriptor field that maps the network interface card (NIC) receive/ring buffer to match the actual length of the data in the buffer before indicating up. When the packet is returned, the miniport driver must again call NdisAdjustBufferLength to adjust the length back to the full, as-allocated length of the receive/ring buffer.
  3. If the miniport driver indicates up an array of packets by calling NdisMIndicateReceivePacket or NdisMCoIndicateReceivePacket, it must set the Status member of the out-of-band (OOB) block associated with each packet descriptor. If the miniport driver determines that it must force the protocol driver to copy the indicated packets because the miniport driver is running short of receive buffers, it should set the Status member in the OOB block to NDIS_STATUS_RESOURCES. Otherwise, the miniport driver should set the Status member to NDIS_STATUS_SUCCESS, NDIS_STATUS_FAILURE, NDIS_STATUS_PENDING, or a driver-determined status.
  4. If a connectionless miniport driver indicates up a single packet by calling NdisM Xxx IndicateReceive, the miniport driver indicates all the received data, indicating its full size as the lookahead size.
  5. After the packet is indicated up (Step 3) or copied (Step 4), the miniport driver replaces the buffer descriptors on the ring. A buffer descriptor is replaced by one of the following:
    • a buffer descriptor from a previously allocated and currently available packet
    • a buffer descriptor from a packet that the protocol driver was forced to copy and return
    • a buffer descriptor allocated by calling NdisAllocateBuffer for a buffer descriptor to describe a buffer that was allocated by calling NdisMAllocateSharedMemoryAsync

Miniports for NICs that receive variable-size frames must chain and unchain packets, depending on the amount of incoming data to build varying size packets. Some miniport drivers receive data on a medium that uses fixed-size frames. This kind of miniport driver can allocate fixed-size buffers once, chain them to packet descriptors, and reuse them without being required to chain and unchain buffers.

If the miniport driver calls NdisMAllocateSharedMemoryAsync to allocate a buffer, it will be called at its MiniportAllocateComplete function when the allocation is complete.


Receiving Data on a PIO NIC

A miniport driver for a programmable I/O (PIO) network interface card (NIC) reads data from the NIC ports by calling NdisRawReadPort Xxx and using ports previously claimed with NdisMRegisterIoPortRange. Typically such a device indicates the lookahead portion of a received packet to bound protocol drivers by calling a filter-specific Ndis Xxx IndicateReceive function and transfers the rest of the data to interested protocol drivers in its MiniportTransferData function. After the data is transferred, the data can be overwritten by new data after receive interrupts are re-enabled.

A miniport driver for a PIO NIC should ensure that new data is not missed because of the time delay in transferring current data to an upper layer protocol driver. If a NIC has a relatively small on-board FIFO buffer, the miniport driver can preallocate a buffer in its MiniportInitialize function and then stage the received data into this buffer to be indicated up. Staging is done to try to keep the FIFO as empty as possible and available for new incoming data.

Alternatively, the miniport driver can indicate up data copied directly from the NIC port and move the rest of the received data directly from the NIC when its MiniportTransferData function is called. This receive technique incurs a delay equal to the time between when the received data was indicated up by calling Ndis Xxx IndicateReceive and when MiniportTransferData is called and moves the received data into the buffer provided to MiniportTransferData.

If the miniport driver calls NdisMIndicateReceivePacket or NdisMCoIndicateReceivePacket, it transfers the data into buffers chained to a preallocated packet before it makes the call.


Receiving Data on a Memory-Mapped Device

A miniport driver that manages a network interface card (NIC) with on-board memory typically transfers the received data in MiniportTransferData directly from the NIC to a buffer supplied in the MiniportTransferData call. Like a programmable I/O (PIO) miniport driver, the miniport driver can stage the receive if there is a possibility that new data will be lost because of the latency caused by the direct transfer from the NIC to the protocol driver-supplied buffers.

The miniport driver calls NdisM Xxx IndicateReceive to indicate up an amount of data equal to the lookahead size or, if the buffer is small and the miniport driver has the complete buffer, it indicates up the complete buffer. MiniportTransferData calls NdisMoveFromMappedMemory to transfer data from the NIC's on-board memory to the protocol driver's packet or to a staging buffer. After the data is transferred, the miniport driver can re-enable interrupts so that new data can be received.

If the miniport driver calls NdisMIndicateReceivePacket or NdisMCoIndicateReceivePacket, it transfers the data into buffers that are chained to a pre-allocated packet before it makes the call.


Keeping Statistics

Every miniport driver network interface card (NIC) driver should maintain both the mandatory general statistics and the media-specific statistics object identifiers (OIDs) for their particular media. For more information on how miniport drivers handle queries and sets to OIDs, see Obtaining_and_Setting_Miniport Driver Information and NDIS Support for WMI.

General Mandatory Statistics OIDs for Connectionless Miniport Drivers

The general mandatory statistics OIDs that apply to all connectionless miniport drivers include the following:

  • OID_GEN_XMIT_OK
  • OID_GEN_RCV_OK
  • OID_GEN_XMIT_ERROR
  • OID_GEN_RCV_ERROR
  • OID_GEN_RCV_NO_BUFFER

The MiniportQueryInformation function must return the corresponding value it has accumulated for each of these statistics when it receives a request with one of these OIDs.

General Mandatory Statistics OIDs for Connection-Oriented Miniport Drivers

The general mandatory statistics OIDs that apply to all connection-oriented miniport drivers include the following:

  • OID_GEN_CO_XMIT_PDUS_OK
  • OID_GEN_CO_RCV_PDUS_OK
  • OID_GEN_CO_XMIT_PDUS_ERROR
  • OID_GEN_CO_RCV_PDUS_ERROR
  • OID_GEN_CO_RCV_PDUS_NO_BUFFER

The MiniportCoRequest function must return the corresponding value it has accumulated for each of these statistics when it receives a request with one of these OIDs.


802.1p Packet Priority

802.1p packet priority is an extension to the standard Media Access Control (MAC) header in network packets. This extension includes a three-bit value that hubs and switches use to establish packet priority in shared-media 802 networks. Typically, when a network segment becomes congested, the hub-and-switch workload results in the delay or dropping of packets. On a network using the 802.1p MAC extension, a packet with a higher priority receives preferential treatment and is serviced before a packet with a lower priority.

Operating system components that are aware of Quality of Service (QOS) provide 802.1p priority information to miniport drivers. The NDIS_PACKET structure that describes each transferred packet is used to send priority information. QOS-aware components derive this priority information by mapping service types to IEEE 802.1p priority values. The Integrated Services Working Group (Intserv) of the Internet Engineering Task Force (IETF) defines this service-type mapping. The Intserv specification of these 802.1p priority values, also called "user priority" objects, can be located in the IETF Internet site.

To locate this specification

  1. Click the URL for the IETF Internet site, http://search.ietf.org
  2. Click Internet-Drafts
  3. Click Internet-Drafts Index
  4. Click Integrated Services over Specific Link Layers (issll)
  5. Click the Integrated Service Mappings on IEEE 802 Networks specification

Note that IETF might supersede this specification with later drafts or the final specification. This specification describes prioritizing packets using IEEE 802.1p priority values whereas the IEEE 802.1q specification describes how to actually mark packets for network priority. Either QOS-aware applications or QOS-aware operating system components that work on behalf of these applications can determine the intserv service types used for the mapping.

Unless a host computer has properly negotiated QOS with the network, the host computer should only mark packets transmitted with a "best effort" 802.1p priority value. If the host computer has a Packet Scheduler installed, the host uses the appropriate QOS-signaling components to negotiate with the network for higher 802.1p priority values. The Packet Scheduler then passes the appropriate priority values in NDIS packets to the miniport driver.

Miniport drivers that support 802.1p packet priority use the priority value obtained from the NDIS_PACKET structure to generate the corresponding member in the MAC headers of packets to be transmitted over the network. These miniport drivers also extract the appropriate information from the MAC headers of received packets. The priority value is copied to the NDIS_PACKET structure before the miniport driver indicates the packet to higher protocol layers. The IEEE 802.1q specification describes how packets are marked to specify network priority.

Note that upper link-layer drivers can interpret priority information in the NDIS_PACKET structure. This capability allows those drivers to use priority information as appropriate for a particular media.

Support for 802.3 priority is included in NDIS 4.0 in Windows NT® version 4.0 and Windows 95, Windows 98, and Windows Me. When 802.3 priority was initially introduced to NDIS, it was used in the context of PACE and 100-VG. The members that designated this priority were located in the out-of-band (OOB) data portion of the NDIS packet descriptor, NDIS_PACKET_OOB_DATA. These members still exist but they are not used for 802.1p priority values.

The following topics describe how to implement a miniport driver to support 802.1p packet priority:

Query for 802.1p Priority Support

Packet Support for 802.1p Priority

Specify Packet Size for Sends and Receives

Disable 802.1p Priority Support by Default


Query for 802.1p Priority Support

Upper link-layer drivers send queries to underlying miniport drivers to determine the capabilities of those miniport drivers or their NICs. If miniport drivers support 802.1p packet priority, they should be implemented to process these queries and to return information that indicates their support. These upper link-layer drivers call the NdisRequest function for a connectionless miniport driver and the NdisCoRequest function for a connection-oriented miniport driver and pass in a NDIS_REQUEST structure that is filled with the following OID_XXX code for the query.

OID_GEN_MAC_OPTIONS

The OID_GEN_MAC_OPTIONS query returns a bitmask to the upper link-layer driver. This bitmask defines optional properties of the underlying miniport driver or of the miniport driver's NIC. A protocol that initiates this query can determine which flags in the bitmask are set by the underlying miniport driver. Such a protocol can also take advantage of the miniport driver properties that are associated with the flags. For example, a miniport driver that sets the NDIS_MAC_OPTION_8021P_PRIORITY flag in the bitmask. Such a miniport driver can receive 802.1p priority values in NDIS_PACKET structures from higher-layer drivers. This miniport driver can then generate the appropriate information in the MAC headers of packets to transmit over the network. This miniport driver also supports extracting the appropriate information from the MAC headers of packets received from the network. After the information is extracted, the miniport driver uses NDIS_PACKET structures to indicate the information to higher-layer drivers. If the miniport driver or the miniport driver's NIC supports other optional properties, the miniport driver should also set flags for those properties in the bitmask. The Windows DDK defines all bitmask flags for OID_GEN_MAC_OPTIONS in the Network Reference.


Packet Support for 802.1p Priority

Upper link-layer drivers send packets to underlying miniport drivers. Miniport drivers can also receive packets and can indicate those packets up to link-layer drivers. To support 802.1p packet priority, miniport drivers must be able to access the priority information that is transferred by the NDIS_PACKET structure.

A miniport driver that supports 802.1p packet priority receives packets that contain priority values from the network. The miniport driver should extract the appropriate information from the MAC headers of the packets. The miniport driver should then insert the priority value into the packet descriptor before indicating the packet to higher protocol layers. To insert an 802.1p priority value into a packet descriptor, a miniport driver calls the NDIS_PER_PACKET_INFO_FROM_PACKET macro. In this call, the miniport driver passes a pointer to NDIS_PACKET that describes the packet, and the Ieee8021QInfo NDIS_PER_PACKET_INFO value that indicates that NDIS should insert the 802.1p priority value in the packet. For example, in the following operation, the pPacketDesc variable points to a packet, and the UserPriority variable holds the priority value to insert into that packet. To insert the priority value into the packet, a miniport driver performs the following operation:

NDIS_PACKET_8021Q_INFO VlanPriInfo;
UINT32 UserPriority;
VlanPriInfo.Value =          // Get current value.
      NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, Ieee8021QInfo);
VlanPriInfo.TagHeader.UserPriority = UserPriority; // Set priority.
NDIS_PER_PACKET_INFO_FROM_PACKET(pPacketDesc, Ieee8021QInfo) =
                                            VlanPriInfo.Value;

After miniport drivers that support 802.1p packet priority retrieve priority values from packets sent by upper link-layer drivers, those miniport drivers should generate the corresponding member in the MAC headers of packets to be transmitted over the network. To retrieve the 802.1p priority value from a packet descriptor, a miniport driver calls the NDIS_PER_PACKET_INFO_FROM_PACKET macro. In this call, the miniport driver passes a pointer to NDIS_PACKET that describes the packet. In this call, the miniport driver also passes the Ieee8021QInfo NDIS_PER_PACKET_INFO value that indicates that NDIS should retrieve the 802.1p priority value from the packet. For example, to retrieve the priority value that is contained in the packet pointed to by the pPacketDesc variable, and then to assign this priority value to the UserPriority variable, a miniport driver performs the following operation:

VlanPriInfo.Value =
      NDIS_PER_PACKET_INFO_FROM_PACKET(pPacketDesc, Ieee8021QInfo);
UserPriority = VlanPriInfo.TagHeader.UserPriority;

If the priority value that is retrieved from NDIS_PACKET is zero, the miniport driver should not mark the packet with an 802.1p priority value before transmitting the packet over the network. On Ethernet (802.3) networks, an unmarked packet is the same as a packet that is marked with the "best effort" priority value appended to it. Not marking packets ensures backward compatibility with devices on the network that do not support the 802.1p MAC extension.

If the miniport driver receives a packet from the network that contains the "best effort" 802.1p priority value in the packet's MAC header, the miniport driver should insert zero in NDIS_PACKET before indicating it to higher-layer drivers.

Note that miniport drivers must use NDIS_PER_PACKET_INFO_FROM_PACKET to insert and retrieve packet 802.1p priority values. Miniport drivers must not use the NdisClass802_3Priority NDIS_CLASS_ID value of the MediaSpecificInformation member of a NDIS_PACKET_OOB_DATA structure to insert and retrieve packet 802.1p priority values. A NDIS_PACKET_OOB_DATA structure contains out-of-band information that is associated with a packet descriptor.


Specify Packet Size for Sends and Receives

Miniport drivers that specify support for 802.1p packet priority as described in Query for 802.1p Priority Support might specify different sizes for packets that upper-layer drivers can send to those miniport drivers as opposed to packets that those miniport drivers receive over the network and subsequently indicate to upper-layer drivers as described following:

  • Miniport drivers might place constraints on the size of packets that upper-layer drivers can send to them. For example, a miniport driver might limit, by 4 bytes, the maximum size of packets that upper-layer drivers send so that it can append appropriate priority values to those packets and still transit those packets over a legacy network. On the other hand, if transmitted packets are not expected to traverse legacy network equipment, the miniport driver is not required to limit, by 4 bytes, the maximum size of packets that upper-layer drivers send. Miniport drivers limit packet size by 4 bytes because that is the size of an 802.1p priority value as defined by IETF. Miniport drivers use OID_GEN_MAXIMUM_FRAME_SIZE to specify the maximum size of packets that their NICs support for receiving from upper-layer drivers.
  • Miniport drivers must specify the maximum size of packets that they receive over the network and that they subsequently indicate to upper-layer drivers. Even if a miniport driver removes 4-byte priority values from some packets that it receives over the network before it indicates those packets to upper-layer drivers, it must still specify the maximum size of all possible packets that it will ever indicate to upper-layer drivers. For example, the miniport driver might receive packets over the network that are not marked with priority values but are still the maximum size that the underlying medium supports. Miniport drivers use OID_GEN_MAXIMUM_TOTAL_SIZE to specify the maximum size of packets that their NICs receive over the network.


Disable 802.1p Priority Support by Default

Miniport drivers should make support for 802.1p priority a NIC property that is disabled by default. Because transmitting 802.1p priority-marked packets will not work in all network environments and there are currently no standardized mechanisms for determining if it will, miniport drivers must disable this 802.1p priority property by default. Miniport drivers should be set up so that users can enable this 802.1p priority property by clicking the Network icon in the Control Panel.


Obtaining and Setting Miniport Driver Information and NDIS Support for WMI

This section describes how upper layers and NDIS query and set miniport driver information, and how a miniport driver reports changes in hardware status to upper layers. This section also provides an overview of NDIS support for Windows Management Instrumentation (WMI).

This section includes the following topics:

NDIS Management Information and OIDs

Querying Miniport Driver Information

Setting Miniport Driver Information

Reporting Hardware Status

NDIS Support for WMI


NDIS Management Information and OIDs

Each miniport driver contains its own MIB, which is an information block in which the driver stores dynamic configuration information and statistical information that a management entity can query or set. An Ethernet multicast address list is an example of configuration information. The number of broadcast packets received is an example of statistical information. Each information element within the MIB is referred to as an object. To refer to each such managed object, NDIS defines an Object Identifier. Therefore, if a management entity wants to query or set a particular managed object, it must provide the specific OID for that object.

The MIB tracks three classes of objects:

  • Those general to all NDIS miniport drivers
  • Those specific to all NDIS miniport drivers for a given medium type, such as Ethernet or Token Ring
  • Those specific to a particular vendor implementation

The general and mandatory media-specific OIDs are documented in the Network Driver Reference. The implementation-specific OIDs for a particular NIC driver should be listed and described in the documentation accompanying a given NIC driver.

Besides being classified as either operational characteristics (for example, multicast address list) or statistics (for example, broadcast packets received), objects are classified as either mandatory or optional. All operational characteristics objects for either general or media-specific classes are mandatory, but only some statistics objects are mandatory. All implementation-specific objects are classified as mandatory.

The following figure shows the structure of an OID.

NDIS OID Format

The first 3 bytes of the OID provide a key to the OID's various classifications. The fourth byte identifies the specific information management object within those classifications.

For more information, see General Objects.


Querying Miniport Driver Information

The NdisXxx function that a protocol driver calls to query miniport driver information, as well as the MiniportXxx function used to satisfy such a query, depends on whether the miniport driver is connectionless or connection-oriented.


Querying a Connectionless Miniport Driver

To query OIDs maintained by a connectionless miniport driver, a bound protocol calls NdisRequest and passes a structure of type NDIS_REQUEST that specifies the object (OID) being queried and that points to a buffer into which NDIS eventually writes the requested information. The call to NdisRequest causes NDIS to call the miniport driver's MiniportQueryInformation function, which returns the requested information to NDIS. MiniportQueryInformation can complete synchronously or asynchronously with a call to NdisMQueryIndformationComplete (see the following figure).

NDIS can also call a miniport driver's MiniportQueryInformation function on its own behalf — for example, after the miniport driver's MiniportInitialize function has returned NDIS_STATUS_SUCCESS—to query the miniport driver's capabilities, status, or statistics.

Querying a Connectionless Miniport Driver

The set of mandatory general operational OIDs for connectionless miniport drivers includes:

OID_GEN_SUPPORTED_LIST

OID_GEN_HARDWARE_STATUS

OID_GEN_MEDIA_SUPPORTED

OID_GEN_MEDIA_IN_USE

OID_GEN_MAXIMUM_LOOKAHEAD

OID_GEN_MAXIMUM_FRAME_SIZE

OID_GEN_LINK_SPEED

OID_GEN_TRANSMIT_BUFFER_SPACE

OID_GEN_RECEIVE_BUFFER_SPACE

OID_GEN_TRANSMIT_BLOCK_SIZE

OID_GEN_RECEIVE_BLOCK_SIZE

OID_GEN_VENDOR_ID

OID_GEN_VENDOR_DESCRIPTION

OID_GEN_VENDOR_DRIVER_VERSION

OID_GEN_CURRENT_PACKET_FILTER

OID_GEN_CURRENT_LOOKAHEAD

OID_GEN_DRIVER_VERSION

OID_GEN_MAXIMUM_TOTAL_SIZE

OID_GEN_MAC_OPTIONS

OID_GEN_MEDIA_CONNECT_STATUS

OID_GEN_MAXIMUM_SEND_PACKETS

In particular, the miniport driver's MiniportQueryInformation function must be prepared to respond to OID_GEN_MAXIMUM_LOOKAHEAD, OID_GEN_MAXIMUM_SEND_PACKETS, and OID_GEN_MAC_OPTIONS.

If the miniport driver indicates received data by calling Ndis Xxx IndicateReceive, it should respond to OID_GEN_MAXIMUM_LOOKAHEAD with the maximum number of bytes the NIC can provide as lookahead data. If that value is different from the size of the lookahead buffer supported by bound protocols, NDIS will call MiniportSetInformation to set the size of the lookahead buffer provided by the miniport driver to the minimum of the miniport driver and protocol(s) values.

If the driver always indicates up full packets with NdisMIndicateReceivePacket, it should set this value to the maximum total packet size, which excludes the header.

If a miniport driver registers a MiniportSendPackets function, MiniportQueryInformation will be called with the OID_GEN_MAXIMUM_SEND_PACKETS request. The miniport driver must respond with the maximum number of packets it is prepared to handle on a single send request. The miniport driver should pick a maximum that minimizes the number of packets that it has to queue internally because it has no resources (its device is full). A miniport driver for a bus-master DMA NIC should attempt to pick a value that keeps its NIC filled under anticipated loads.

When MiniportQueryInformation is called with OID_GEN_MAC_OPTIONS, it must return a bit mask that specifies the optional operations that the miniport driver performs. The set of flags includes:

  • NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA

    Indicates to a protocol driver that it is free to access indicated data by any means. If a miniport driver indicates data out of on-board shared memory, it must not set this flag.

  • NDIS_MAC_OPTION_NO_LOOPBACK

    If set, indicates that the miniport driver does not loopback a packet passed to MiniportSend(Packets) that is directed to a receiver on the same machine, and that the miniport driver expects NDIS to perform the loopback. If NDIS performs the loopback of a packet, the packet is not passed down to the miniport driver. A miniport driver always sets this flag unless its NIC performs hardware loopbacks.

  • NDIS_MAC_OPTION_RECEIVE_SERIALIZED

    If set, the miniport driver does not indicate any newly received packet up until the previously received packet has been fully processed, including transferring the data. Most miniport drivers, except those that indicate up packets by calling NdisMIndicateReceivePacket, set this flag.

  • NDIS_MAC_OPTION_TRANSFERS_NOT_PEND

    If set, a miniport driver never returns NDIS_STATUS_PENDING from MiniportTransferData.

A miniport driver must never use the flag NDIS_MAC_OPTION_RESERVED, which is reserved for NDIS internal use.

MiniportQueryInformation is also be queried with a media-specific OID to determine the NIC's current address. For instance, the miniport driver for a NIC of type 802.3 will be queried with OID_802_3_CURRENT_ADDRESS.

The miniport drivers for certain media types will receive additional OIDs that are media-specific. For example, a miniport driver whose NIC is of type 802.3 is queried with OID_802.3_MAXIMUM_LIST_SIZE. For more information, see General Objects.

Miniport drivers should support 64-bit statistics OID queries. For a statistics OID query, the requester sets the InformationBufferLength member of the NDIS_REQUEST structure to four (bytes) to indicate a 32-bit statistics request or to eight (bytes) to indicate a 64-bit statistics request. In its response, the miniport driver sets the BytesNeeded member to the size of the statistics supported by the miniport driver (four for 32-bits or eight for 64-bits). The miniport driver sets the BytesWritten member to the smaller of the InformationBufferlength value and the size of statistics supported by the miniport driver. For more information about statistics OIDs, see General Statistics.


Querying a Connection-Oriented Miniport Driver

To query information objects maintained by a connection-oriented miniport driver, a bound protocol calls NdisCoRequest and passes a structure of type NDIS_REQUEST that specifies the object (OID) being queried and that provides a buffer into which NDIS eventually writes the requested information. The call to NdisCoRequest causes NDIS to call the miniport driver's MiniportCoRequest function, which returns the requested information to NDIS. MiniportCoRequest can complete synchronously or asynchronously with a call to NdisMCoRequestComplete (see the following figure).

NDIS can also call a miniport driver's MiniportCoRequest function on its own behalf—for example, after the miniport driver's MiniportInitialize function has returned NDIS_STATUS_SUCCESS—to query the miniport driver's capabilities, status, or statistics.

Querying a Connection-Oriented Miniport Driver

A connection-oriented miniport driver must be able to provide information on a global basis for all VCs for a particular NIC and also on a per-VC basis. For example, if a nonNULL NdisVcHandle is supplied to MiniportCoRequest for a query of OID_GEN_CO_RCV_CRC_ERROR, the miniport driver returns the number of CRC errors encountered in all receives on the specified VC. For the same request with a NULL NdisVcHandle, the miniport driver returns the total number of CRC errors encountered for all incoming receives through its NIC.

The set of mandatory general operational OIDs for connection-oriented miniport drivers includes:

OID_GEN_CO_SUPPORTED_LIST

OID_GEN_CO_HARDWARE_STATUS

OID_GEN_CO_MEDIA_SUPPORTED

OID_GEN_CO_MEDIA_IN_USE

OID_GEN_CO_LINK_SPEED

OID_GEN_CO_VENDOR_ID

OID_GEN_CO_VENDOR_DESCRIPTION

OID_GEN_CO_VENDOR_DRIVER_VERSION

OID_GEN_CO_DRIVER_VERSION

OID_GEN_CO_MAC_OPTIONS

OID_GEN_CO_MEDIA_CONNECT_STATUS

OID_GEN_CO_MINIMUM_LINK_SPEED

The miniport driver's MiniportCoRequest function must be prepared to respond to queries or sets, as appropriate, to any of the above OIDs.

When MiniportCoRequest is called with OID_GEN_CO_MAC_OPTIONS, it must return a bit mask that specifies the optional operations that the miniport driver performs. The set of flags includes:

  • NDIS_MAC_OPTION_NO_LOOPBACK

    If set, indicates the miniport driver does not loopback a packet passed to MiniportCoSendPackets that is directed to a receiver on the same machine, and that the miniport driver expects NDIS to perform the loopback. If NDIS performs the loopback of a packet, the packet is not passed down to the miniport driver. A miniport driver always sets this flag unless its NIC performs hardware loopbacks.

  • NDIS_MAC_ETOX_INDICATION

    If set, indicates that the miniport driver indicates that a send is complete only after the packet has been transmitted by the NIC.

A miniport driver must never use the flag NDIS_MAC_OPTION_RESERVED, which is reserved for NDIS internal use.

MiniportCoRequest will also be queried with a media-specific OID to determine the NIC's current address. For instance, the miniport driver for a NIC of type ATM is queried with OID_ATM_HW_CURRENT_ADDRESS.

For more information, see OIDs for Connection-Oriented Call Managers and Clients and General Objects.

Miniport drivers should support 64-bit statistics OID queries. For a statistics OID query, the requester sets the InformationBufferLength member of the NDIS_REQUEST structure to four (bytes) to indicate a 32-bit statistics request or to eight (bytes) to indicate a 64-bit statistics request. In its response, the miniport driver sets the BytesNeeded member to the size of the statistics supported by the miniport driver (four for 32-bits or eight for 64-bits). The miniport driver sets the BytesWritten member to the smaller of the InformationBufferlength value and the size of statistics supported by the miniport driver. For more information about statistics OIDs for connection-oriented miniport drivers, see General Statistics for Connection-Oriented Miniport Drivers.


Setting Miniport Driver Information

The NdisXxx function that a protocol driver calls to set miniport driver information, as well as the MiniportXxx function that satisfies a set operation, depends on whether the miniport driver is connectionless or connection-oriented.


Setting Information for a Connectionless Miniport Driver

To set an OID maintained by a connectionless miniport driver, a bound protocol calls NdisRequest and passes a structure of type NDIS_REQUEST that specifies the object (OID) being queried and that points to a buffer that contains the value to which the object should be set. The call to NdisRequest causes NDIS to call the miniport driver's MiniportSetInformation function, which sets the object with the supplied value.

The call to MiniportSetInformation can complete synchronously or asynchronously. To complete the call asynchronously, the miniport driver calls NdisMSetInformationComplete.

Setting Information in a Connectionless Miniport Driver (Per Binding)


Setting Information for a Connection-Oriented Miniport Driver

To set an OID maintained by a connection-oriented miniport driver, a bound protocol calls NdisCoRequest and passes a structure of type NDIS_REQUEST that specifies the object (OID) being queried and that points to a buffer that contains the value to which the object should be set. The call to NdisCoRequest causes NDIS to call the miniport driver's MiniportCoRequest function, which sets the object with the supplied value.

The call to NdisCoRequest can complete synchronously or asynchronously. To complete the call asynchronously, a miniport driver calls NdisCoRequestComplete.

Setting Information in a Connection-Oriented Miniport Driver


Occasions for Setting Miniport Driver Information

Besides being called during initialization, the MiniportSetInformation function in a connectionless miniport driver or the MiniportCoRequest function in a connection-oriented miniport driver is called in two additional cases:

  • during a hardware reset, and
  • as a result of a protocol call to NdisCloseAdapter

MiniportSetInformation or MiniportCoRequest is called during a hardware reset operation as described in Hardware Reset. In this case, MiniportSetInformation or MiniportCoRequest is called to reset the miniport driver to its initial state with respect to its addresses.

NDIS calls MiniportSetInformation or MiniportCoRequest when a miniport driver's NIC is closed by a protocol's NdisCloseAdapter call. Such a miniport driver will be requested to update its addressing information.


Reporting Hardware Status

A connectionless miniport driver indicates changes in hardware status to upper layers by calling NdisMIndicateStatus. A connection-oriented miniport driver indicates changes by calling NdisMCoIndicateStatus.

NdisM(Co)IndicateStatus takes both a general status code and a buffer containing media-specific information that further defines the reason for the status change. NDIS reports this status change to bound protocol drivers. NDIS does not interpret or otherwise intercept the status code. The miniport driver can make one or more such calls; however, when a connectionless miniport driver has finished sending status, it must call NdisMIndicateStatusComplete to let interested protocol drivers know that it is done reporting status. A connection-oriented miniport driver does not have to indicate that it has finished sending status. The protocol driver or configuration manager can log the status or take corrective action, as appropriate.

NdisMCoIndicateStatus takes any valid NDIS_STATUS_XXX value. The miniport driver is responsible for indicating status codes that make sense to a protocol or higher level driver. A protocol driver ignores any status values in which it is not interested or that don't make sense in the context of its operations.

For instance, a miniport driver can report NDIS_STATUS_RING_STATUS to report a ring failure. The StatusBuffer argument to NdisMCoIndicateStatus further details the ring status. The contents of StatusBuffer encodes a set of possible ring conditions that are the reason for the status report, such as NDIS_RING_SIGNAL_LOSS and NDIS_RING_HARD_ERROR.

A miniport driver cannot indicate status in the context of its MiniportInitialize, MiniportISR, MiniportHalt, or MiniportShutdown function.

A miniport driver can also be interrogated by an upper layer driver or by NDIS about the miniport driver's hardware status. When the MiniportQueryInformation function of a connectionless miniport driver or the MiniportCoRequest function of a connection-oriented miniport driver receives OID_GEN_HARDWARE_STATUS, it responds with any of the applicable statuses defined in NDIS_HARDWARE_STATUS. These include:

  • NdisHardwareStatusReady
  • NdisHardwareStatusInitializing
  • NdisHardwareStatusReset
  • NdisHardwareStatusClosing
  • NdisHardwareStatusNotReady

The miniport driver can be queried so that NDIS can synchronize operations between layers of NDIS drivers — for instance, by determining whether a NIC is ready to accept packets.


NDIS Support for WMI

Through NDIS, clients of Windows Management Instrumentation (WMI) can query and set OIDs maintained by NDIS miniport drivers. WMI clients can also register to receive miniport driver status indications.

NDIS automatically registers miniport drivers and named VCs with WMI, as well as a standard set of OIDs for each miniport driver. For more information, see Standard Miniport Driver OIDs Registered with WM. As described in Customized OIDs and Status Indications, miniport drivers can provide support for custom OIDs and custom status indications.

NDIS does not provide WMI support for protocol drivers. A protocol, such as an intermediate driver, can create a device object for itself and register directly with WMI.

For more information on the WMI architecture, see Windows Management Instrumentation.


Mapping of GUIDs to OIDs and Miniport Driver Status

When WMI sends a query or set to a miniport driver (that is, when WMI sends an IRP to a functional device object created by NDIS), NDIS intercepts the query or set, maps the GUID to an OID supported by the miniport driver, and then queries or sets the miniport driver-maintained OID. If the miniport driver is a connectionless miniport driver, NDIS calls the miniport driver's MiniportQueryInformation function or MiniportSetInformation function. If the miniport driver is a connection-oriented miniport driver, NDIS calls the miniport driver's MiniportCoRequest function. NDIS returns to WMI the results of the query or set to the miniport driver OID.

If a miniport driver makes a status indication with NdisM(Co)IndicateStatus that a WMI client has registered to receive, NDIS maps that indication to a GUID, and passes the status indication to WMI. WMI then passes the status indication to all its clients that have registered to be notified of the indication.


Support for Named VCs

NDIS allows WMI clients to query and set OIDs on a per-VC basis for connection-oriented miniport drivers. WMI clients can also enumerate VCs. Before a WMI client can query or set information for an OID relative to a particular VC, a call manager, MCM, or connection-oriented client must name the VC with NdisCoAssignInstanceName.

After initiating the setup of a VC with NdisCoCreateVC, a call manager or connection-oriented client can name the VC with NdisCoAssignInstanceName. NDIS assigns the VC an instance name and registers the instance name with WMI. WMI clients can then enumerate the VC and query or set OIDs relative to the VC.

An MCM cannot use NdisCoAssignInstanceName to name its VCs. Instead, an MCM should create a custom GUID and OID for the VC and register the GUID-to-OID mapping with NDIS. For more information, see Customized OIDs and Status Indications.


NDIS-Supported WMI Operations

NDIS supports the following WMI operations:

  • Enumerate adapter and Enumerate VC

    NDIS registers global GUIDs (GUID_NDIS_ENUMERATE_ADAPTER and GUID_NDIS_ENUMERATE_VC) with WMI that allow WMI clients to enumerate all adapters (miniport driver instances) and all named VCs. Since NDIS itself keeps track of all loaded miniport drivers and all named VCs, NDIS does not need to query miniport drivers for such information.

  • QUERY SINGLE INSTANCE and SET SINGLE INSTANCE

    Through NDIS, a WMI client can query or set a single instance of a data block, which corresponds to single OID. For a query, NDIS returns all the information associated with an OID. A WMI client cannot query or set a data item within an OID. For example, a query of GUID_NDIS_GEN_CO_LINK_SPEED returns both the outbound and inbound speed. A WMI client cannot query just the outbound speed or just the inbound speed.

  • QUERY ALL DATA

    NDIS satisfies a QUERY ALL DATA request on a particular GUID by obtaining the appropriate data and returning the combined data for all instances of the GUID to WMI. For example, in response to a QUERY ALL DATA on GUID_NDIS_ENUMERATE_ADAPTER, NDIS returns to WMI a list of all loaded miniport drivers. For a QUERY ALL DATA on the GUID that maps to OID_GEN_CO_XMIT_PDUS_OK, NDIS queries that OID for each VC on each connection-oriented miniport driver and returns the combined data to WMI. Since the overhead for a QUERY ALL DATA may be very high, it is recommended that WMI clients QUERY ALL DATA only to enumerate adapters and VCs. After determining the adapter or VC interest, the client can then query individual GUID instances.

  • EVENT NOTIFICATION

    WMI clients can register with NDIS to be notified for a particular miniport driver status indication. When such a event occurs, NDIS passes the status information with the appropriate GUID to WMI for delivery to the client(s).


Standard Miniport Driver OIDs Registered with WMI

NDIS automatically registers GUIDs with WMI for the following general OIDs for connectionless miniport drivers:

OID_GEN_HARDWARE_STATUS
OID_GEN_MEDIA_SUPPORTED
OID_GEN_MEDIA_IN_USE
OID_GEN_MAXIMUM_LOOKAHEAD
OID_GEN_MAXIMUM_FRAME_SIZE
OID_GEN_LINK_SPEED
OID_GEN_TRANSMIT_BUFFER_SPACE
OID_GEN_RECEIVE_BUFFER_SPACE
OID_GEN_TRANSMIT_BLOCK_SIZE
OID_GEN_RECEIVE_BLOCK_SIZE
OID_GEN_VENDOR_ID
OID_GEN_VENDOR_DESCRIPTION
OID_GEN_CURRENT_PACKET_FILTER
OID_GEN_CURRENT_LOOKAHEAD
OID_GEN_DRIVER_VERSION
OID_GEN_MAXIMUM_TOTAL_SIZE
OID_GEN_MAC_OPTIONS
OID_GEN_MEDIA_CONNECT_STATUS
OID_GEN_MAXIMUM_SEND_PACKETS
OID_GEN_VENDOR_DRIVER_VERSION
OID_GEN_XMIT_OK
OID_GEN_RCV_OK
OID_GEN_XMIT_ERROR
OID_GEN_RCV_ERROR
OID_GEN_RCV_NO_BUFFER

NDIS automatically registers GUIDs with WMI for the following general OIDs for connection-oriented miniport drivers:

OID_GEN_CO_HARDWARE_STATUS
OID_GEN_CO_MEDIA_SUPPORTED
OID_GEN_CO_MEDIA_IN_USE
OID_GEN_CO_LINK_SPEED
OID_GEN_CO_VENDOR_ID
OID_GEN_CO_VENDOR_DESCRIPTION
OID_GEN_CO_DRIVER_VERSION
OID_GEN_CO_MAC_OPTIONS
OID_GEN_CO_MEDIA_CONNECT_STATUS
OID_GEN_CO_VENDOR_DRIVER_VERSION
OID_GEN_CO_MINIMUM_LINK_SPEED
OID_GEN_CO_XMIT_PDUS_OK
OID_GEN_CO_RCV_PDUS_OK
OID_GEN_CO_XMIT_PDUS_ERROR
OID_GEN_CO_RCV_PDUS_ERROR
OID_GEN_CO_RCV_PDUS_NO_BUFFER

NDIS automatically registers GUIDs with WMI for the following Ethernet OIDs:

OID_802_3_PERMANENT_ADDRESS
OID_802_3_CURRENT_ADDRESS
OID_802_3_MULTICAST_LIST
OID_802_3_MAXIMUM_LIST_SIZE
OID_802_3_MAC_OPTIONS
OID_802_3_RCV_ERROR_ALIGNMENT
OID_802_3_XMIT_ONE_COLLISION
OID_802_3_XMIT_MORE_COLLISIONS

NDIS automatically registers GUIDs with WMI for the following Token Ring OIDs:

OID_802_5_PERMANENT_ADDRESS
OID_802_5_CURRENT_ADDRESS
OID_802_5_CURRENT_FUNCTIONAL
OID_802_5_CURRENT_GROUP
OID_802_5_LAST_OPEN_STATUS
OID_802_5_CURRENT_RING_STATUS
OID_802_5_CURRENT_RING_STATE
OID_802_5_LINE_ERRORS
OID_802_5_LOST_FRAMES

NDIS automatically registers GUIDs with WMI for the following FDDI OIDs:

OID_FDDI_LONG_PERMANENT_ADDR
OID_FDDI_LONG_CURRENT_ADDR
OID_FDDI_LONG_MULTICAST_LIST
OID_FDDI_LONG_MAX_LIST_SIZE
OID_FDDI_SHORT_PERMANENT_ADDR
OID_FDDI_SHORT_CURRENT_ADDR
OID_FDDI_SHORT_MULTICAST_LIST
OID_FDDI_SHORT_MAX_LIST_SIZE
OID_FDDI_ATTACHMENT_TYPE
OID_FDDI_UPSTREAM_NODE_LONG
OID_FDDI_DOWNSTREAM_NODE_LONG
OID_FDDI_FRAME_ERRORS
OID_FDDI_FRAMES_LOST
OID_FDDI_RING_MGT_STATE
OID_FDDI_LCT_FAILURES
OID_FDDI_LEM_REJECTS
OID_FDDI_LCONNECTION_STATE

NDIS automatically registers GUIDs with WMI for the following ATM OIDs:

OID_ATM_SUPPORTED_VC_RATES
OID_ATM_SUPPORTED_SERVICE_CATEGORY
OID_ATM_SUPPORTED_AAL_TYPES
OID_ATM_HW_CURRENT_ADDRESS
OID_ATM_MAX_ACTIVE_VCS
OID_ATM_MAX_ACTIVE_VCI_BITS
OID_ATM_MAX_ACTIVE_VPI_BITS
OID_ATM_MAX_AAL0_PACKET_SIZE
OID_ATM_MAX_AAL1_PACKET_SIZE
OID_ATM_MAX_AAL34_PACKET_SIZE
OID_ATM_MAX_AAL5_PACKET_SIZE
OID_ATM_RCV_CELLS_OK
OID_ATM_XMIT_CELLS_OK
OID_ATM_RCV_CELLS_DROPPED


Standard Miniport Driver Status Registered with WMI

NDIS automatically registers GUIDs with WMI for the following NDIS_STATUS codes that miniport drivers indicate with NdisM(Co)IndicateStatus:

NDIS_STATUS_RESET_START
NDIS_STATUS_RESET_END
NDIS_STATUS_MEDIA_CONNECT
NDIS_STATUS_MEDIA_DISCONNECT
NDIS_STATUS_MEDIA_SPECIFIC_INDICATION
NDIS_STATUS_LINK_SPEED_CHANGE


Customized OIDs and Status Indications

A driver writer can create a custom OID or miniport driver status indication that NDIS maps to a custom GUID created by the writer. NDIS registers the custom GUID with WMI on behalf of the miniport driver so that WMI clients can query or set the OID or receive the custom status indication.

NDIS obtains a miniport driver's custom OIDs or status indications by querying the miniport driver after the miniport driver has completed initialization. To obtain such information, NDIS queries a connectionless miniport driver OID_GEN_SUPPORTED_GUIDS and a connection-oriented miniport driver with OID_GEN_CO_SUPPORTED_GUIDS.

The query to OID_GEN_(CO_)SUPPORTED_GUIDS returns an array of NDIS_GUID structures to NDIS. Each NDIS_GUID structure maps a custom GUID to a custom OID or custom status indication. As described in Filling in an NDIS_GUID Structure, a major portion of the work involved in supporting custom OIDs and status indications is filling in NDIS_GUID structures. As described in Including a MOF File, the other major task is to create a MOF file that describes the GUID and to compile this file with the miniport driver.


Filling in an NDIS_GUID Structure

An NDIS_GUID structure is defined as follows:

typedef struct _NDIS_GUID
{
    GUID             Guid;
    union
    {
        NDIS_OID     Oid;
        NDIS_STATUS  Status;
    };
    ULONG            Size;
    ULONG            Flags;
} NDIS_GUID, *PNDIS_GUID;

To obtain a GUID for the Guid member of the structure, the driver writer must run the uuidgen.exe program. For more information on this utility, see the Platform SDK.

The Oid or Status member is a ULONG that is an OID code or status code. In both cases, the most significant byte of the code is 0xFF and the rest is vendor-defined. The code must be unique within the scope of the miniport driver.

If the NDIS_GUID structure maps a OID that returns data, the Size member specifies the size in bytes of each data item in the returned array. If the size of the returned data items is variable, if the OID does not return data, or if the NDIS_GUID structure maps a status indication, the Size member must be -1.

The following Flags can be ORed together to indicate whether the GUID maps to an OID or to an NDIS_STATUS string and to indicate the type of data supplied for the GUID:

fNDIS_GUID_TO_OID
When set, indicates that the NDIS_GUID structure maps a GUID to an OID.
fNDIS_GUID_TO_STATUS
When set, indicates that the NDIS_GUID structure maps a GUID to an NDIS_STATUS string.
fNDIS_GUID_ANSI_STRING
When set, indicates that a zero-terminated ANSI string is supplied for the GUID.
fNDIS_GUID_UNICODE_STRING
When set, indicates that a UNICODE string is supplied for the GUID.
fNDIS_GUID_ARRAY
When set, indicates that an array of data items is supplied for the GUID. The specified Size indicates the length of each data item in the array.
fNDIS_GUID_ALLOW_READ
When set, indicates that all users are allowed to use this GUID to obtain information.
fNDIS_GUID_ALLOW_WRITE
When set, indicates that all users are allowed to use this GUID to set information.

Note By default, custom WMI GUIDs supplied by a miniport driver are only accessible to users with administrator privileges. A user with administrator privileges can always read or write to a custom GUID if the miniport driver supports the read or write operation for that GUID. Set the fNDIS_GUID_ALLOW_READ and fNDIS_GUID_ALLOW_WRITE flags to allow all users to access a custom GUID.

Note that all custom GUIDs registered by a miniport driver must set either fNDIS_GUID_TO_OID or fNDIS_GUID_TO_STATUS (never set both). All other flags may be combined by using the OR operator as applicable.


Including a MOF File

A description of all custom GUIDs that map to a miniport driver's custom OIDs and/or custom status indications must be included in a Managed Object Format (MOF) file that must be compiled and included in the miniport driver's resource (*.rc) file.

The MOF source file must be of type MOFDATA and have a file extension of .mof. The MOF source file must be compiled into a binary file with mofcomp.exe and checked with wmimofck.exe, both of which are included in the DDK. The following line must be inserted in the miniport driver's *.rc file to include the MOF binary:

MofResource MOFDATA filename.bmf

where filename is the file name of the MOF source file.


Power Management for Miniport Drivers

This section describes the power management (PM) services provided by NDIS for NDIS miniport drivers, as well the miniport driver requirements for supporting power management. The following topics are discussed:

Required and Optional OIDs for Power Management

Network Device Power States

Network Wake-up Events

Handling an OID_PNP_QUERY_POWER

Handling an OID_PNP_SET_POWER

Power Management for Legacy Miniport Drivers

For more information, see Power Management.


Required and Optional OIDs for Power Management

For a miniport driver, supporting power management involves supporting power management object identifiers (OIDs). For a detailed description of how miniport drivers process queries and sets to OIDs, see Obtaining and Setting Miniport Driver Information and NDIS Support for WMI.

There are two levels of power management support for miniport drivers:

  • A miniport driver can support its NIC making a transition between power states. This is the minimum level of power management support. For a description of network device power states, see Network Device Power States.
  • A miniport driver can also support one more network wake-up events. For a description of network wake-up events, see Network Wake-Up Events.

To support its NIC making a transition between power states, a miniport driver must support the following object identifiers (OIDs):

  • OID_PNP_CAPABILITIES

    NDIS considers a miniport driver power management-aware if the miniport driver returns NDIS_STATUS_SUCCESS to a query of this OID. If the miniport driver returns NDIS_STATUS_NOT_SUPPORTED, NDIS considers the miniport driver to be a legacy miniport driver that is not power management-aware.

  • OID_PNP_QUERY_POWER

    This OID specifies a network device power state to which the NIC is being requested to transition. A miniport driver must always return NDIS_STATUS_SUCCESS to a query of OID_PNP_QUERY_POWER. By returning NDIS_STATUS_SUCCESS to this OID request, the miniport guarantees that it will transition the NIC to the specified device power state on receipt of a subsequent OID_PNP_SET_POWER request. The miniport, in this case, must do nothing to jeopardize the transition.

  • OID_PNP_SET_POWER

    This OID indicates that the NIC will transition to the indicated network device power state. A miniport driver must prepare the NIC for the transition to the specified state before returning NDIS_STATUS_SUCCESS. A miniport driver must always return NDIS_STATUS_SUCCESS to this OID.

To support network wake-up events, a miniport driver must also support OID_PNP_ENABLE_WAKE_UP, which both protocols and NDIS use this OID to enable a NIC's wake-up capabilities. For more information, see Enabling Wake-Up Events.

To support network wake-up frames (see Network Wake-Up Frames), a miniport driver must also support the following OIDs related to wake-up events:

  • OID_PNP_ADD_WAKE_UP_PATTERN
  • OID_PNP_REMOVE_WAKE_UP_PATTERN

    A protocol uses this OID to delete one or more wake-up patterns that it previously specified to a miniport driver.

NDIS miniport drivers that support network wake-up events can optionally support the following statistical OIDs related to wake-up events:

  • OID_PNP_WAKE_UP_ERROR

    This OID queries the number of false wake-ups signaled by the miniport driver's NIC.

  • OID_PNP_WAKE_UP_OK

    This OID queries the number of valid wake-ups signaled by the miniport driver's NIC.


Network Device Power States

A network device power state describes a NIC's level of power consumption and computing activity. There are four network device power states: D0, D1, D2, and D3. D0 is the fully on state. D1, D2, and D3 are the sleeping states. The state number is inversely related to power consumption: higher numbered states use less power. Power may be fully removed from the NIC in the D3 state.

The network device power states are defined as follows:

D0

Power consumption
The device is fully powered and delivering full functionality and performance.
Device context
The hardware device context is maintained.
Miniport driver and NIC behavior
The NIC is fully compliant with the requirements of the attached network. There are no power management restrictions on the NIC or miniport driver.
Restore time
Not applicable

D1

Power consumption
The highest-powered sleeping state. Power consumption is less than that in the D0 state and greater than or equal to that in the D2 state.
Device context
The hardware device context may be lost.
Miniport driver and NIC behavior
The miniport driver does not honor transmission requests from protocols. In fact, the miniport driver will not receive such requests from protocols, because NDIS will either notify a bound protocol of the transition to the sleeping state or, if the protocol is a legacy protocol that is not power management-aware, disable such requests from the protocol.

The miniport driver does not indicate up any packets that the NIC may receive while in this state.

The NIC does not generate interrupts. However, the miniport driver must be able to field interrupts, because a shared interrupt could be generated on the bus.

Restore time
The time to restore the NIC to the D0 state is less than that required when the NIC is in the D2 state.

D2

Power consumption
An intermediate sleeping state. Power consumption is less than that in the D1 state and greater than or equal to that in the D3 state.
Device context
The hardware device context may be lost.
Miniport driver and NIC behavior
The miniport driver does not honor transmission requests from protocols. In fact, the miniport driver will not receive such requests from protocols, because NDIS will either notify a bound protocol of the transition to the sleeping state or, if the protocol is a legacy protocol that is not Power management-aware, disable such requests from the protocol.

The miniport driver does not indicate up any packets that the NIC may receive while in this state.

The NIC does not generate interrupts. However, the miniport driver must be able to field interrupts, because a shared interrupt could be generated on the bus.

Restore time
The time to restore the NIC to the D0 state is greater than that required when the NIC is in the D1 state and less than that required when the NIC is in the D3 state.

D3

Power consumption
The lowest-powered sleeping state. In this state, power may be completely removed from the NIC.
Device context
The hardware device context is assumed to be lost.
Miniport driver and NIC behavior:
The miniport driver does not honor transmission requests from protocols. In fact, the miniport driver will not receive such requests from protocols, because NDIS will either notify a bound protocol that the miniport driver is in a sleeping state or, if the protocol is a legacy protocol that is not power management-aware, in effect disable such requests from the protocol.

The miniport driver does not indicate up any packets that the NIC may receive while in this state.

The NIC does not generate interrupts. However, the miniport driver must be able to field interrupts, because a shared interrupt could be generated on the bus.

Restore time
The time to restore the NIC to the D0 state is greater than that required when the NIC is in the D2 state.

Before a NIC can transition to a sleeping state, its miniport driver must turn off everything under the miniport driver's control: interrupts must disabled, timers must be canceled, and so on. A miniport driver cannot access the NIC hardware after the NIC has been set to the D3 state by the bus driver.

Transitions Allowed Between Device Power States

The only transitions allowed between device power states are from the fully on state (D0) to a sleeping state (D1, D2, D3), or from a sleeping state to the fully on state. NDIS never explicitly commands a NIC to transition directly from one sleeping state to another.


Network Wake-Up Events

A network wake-up event is an external event that causes a NIC to wake the system. A NIC wakes the system by asserting a bus-specific wake-up signal that eventually results in the system making a transition from a sleeping state to the working state.

NDIS defines the following two network wake-up events:

  • Receipt of a network wake-up frame that contains a pattern specified by a bound protocol
  • Receipt of a Magic Packet

After a miniport driver completes initialization, both NDIS and bound protocols can query the miniport driver with OID_PNP_CAPABILITIES to determine the wake-up capabilities of the miniport driver's NIC. A NIC can support any combination of network wake-up events, including none at all. NDIS considers the miniport driver to be power management-aware if the miniport driver returns NDIS_STATUS_SUCCESS to a query of OID_PNP_CAPABILITIES, regardless of the wake-up capabilities reported by the miniport driver.

Depending on the capabilities of the NIC, a network wake-up event can occur from any device power state, including the fully on state, D0.

This section includes the following topics:

Network Wake-Up Frames

Magic-Packet Wake-Up


Network Wake-Up Frames

If a miniport driver, in its response to an OID_PNP_CAPABILITIES query, indicates that its NIC can signal a wake up on the receipt of a packet that contains a specified pattern, a bound protocol can enable network wake-up frames for the NIC and specify one or more wake-up patterns. A protocol enables this type of wake-up by setting the NDIS_PNP_WAKE_UP_PATTERN_MATCH flag in OID_PNP_ENABLE_WAKE_UP. A protocol specifies one or more wake-up patterns, along with a mask that indicates which bytes of an incoming packet should be compared with the pattern, with OID_PNP_ADD_WAKE_UP_PATTERN. The wake-up pattern can be stored in the NIC or in host memory, depending on the capabilities of the NIC. A protocol can remove one or more wake-up patterns with OID_PNP_REMOVE_WAKE_UP_PATTERN.

For more information on network wake-up frames, see the Network Device Class Power Management Reference Specification on the Microsoft Web site at http:/www.microsoft.com/hwdev/onnow.htm.


Magic-Packet Wake-Up

A Magic Packet™ is a packet that contains 16 contiguous copies of the receiving NIC's Ethernet address.


Enabling Wake-Up Events

After querying a miniport driver's wake-up capabilities with OID_PNP_CAPABILITIES, a protocol driver can send OID_PNP_ENABLE_WAKE_UP to enable one or more of the NIC's wake-up capabilities. NDIS does not immediately enable the wake-up capabilities specified by a protocol with OID_PNP_ENABLE_WAKE_UP. Instead, NDIS keeps track of the wake-up capabilities enabled by the protocol and, just before the miniport driver transitions to a sleeping state, sends an OID_PNP_WAKE_UP_ENABLE to the miniport driver to enable the appropriate wake-up events.

Before the miniport driver transitions to a low-power state (that is, before NDIS sends the miniport driver an OID_PNP_SET_POWER), NDIS sends the miniport driver an OID_PNP_ENABLE_WAKE_UP to enable the appropriate wake-up capabilities. If the protocol enabled Magic-Packet™ wake-up and/or pattern-match wake-up, NDIS enables enable Magic-Packet™ wake-up and/or pattern-match wake-up.


Handling a Wake-up Event

A miniport driver does not handle a wake-up event detected by its NIC. When a NIC detects an enabled wake-up event, it asserts a bus-specific wake-up line to notify the bus driver. The bus driver notifies NDIS, which notifies the system Power Manager. The Power Manager then sends a power IRP to NDIS, and NDIS sends the miniport driver an OID_PNP_SET_POWER to the working state.


Handling an OID_PNP_QUERY_POWER

An OID_PNP_QUERY_POWER requests the miniport to indicate whether it can transition its NIC to the low-power state. A miniport driver must always return NDIS_STATUS_SUCCESS to a query of OID_PNP_QUERY_POWER. By returning NDIS_STATUS_SUCCESS to this OID request, the miniport guarantees that it will transition the NIC to the specified device power state on receipt of a subsequent OID_PNP_SET_POWER request. The miniport, in this case, must do nothing to jeopardize the transition.

An OID_PNP_QUERY_POWER is always followed by an OID_PNP_SET_POWER. The OID_PNP_SET_POWER may immediately follow the OID_PNP_QUERY_POWER request or may arrive at an unspecified interval after the OID_PNP_QUERY_POWER request. A device state of D0 specified in the OID_PNP_SET_POWER request effectively cancels a preceding OID_PNP_QUERY_POWER request.


Handling an OID_PNP_SET_POWER

NDIS sends an OID_PNP_SET_POWER to notify a miniport driver that its NIC will be making a transition to from the working state to a sleeping state or from a sleeping state to the working state. OID_PNP_SET_POWER may be preceded by an OID_PNP_QUERY_POWER.


Transitioning to a Sleeping State

Before sending a miniport driver an OID_PNP_SET_POWER, NDIS sends the miniport driver an OID_PNP_ENABLE_WAKE_UP request if the miniport driver supports any wake-up events. For more information, see Enabling Wake-Up Events. A miniport driver must not fail an OID_PNP_SET_POWER.

Before returning NDIS_STATUS_SUCCESS to an OID_PNP_SET_POWER request, the miniport driver must perform the device-dependent operations needed to prepare the NIC for the sleeping state. A miniport driver must also save any packet filters that were previously set with OID_GEN_CURRENT_PACKET_FILTER. If its NIC is making a transition to the D3 state, the miniport driver must turn off everything under its control: interrupts must disabled, timers must be canceled, and so on. A miniport driver cannot access the NIC hardware after the NIC has been set to the D3 state by the bus driver.

While in any sleeping state, a miniport driver must not indicate receive packets to higher drivers.


Transitioning to the Working State

NDIS initiates the transition to the working power state (D0) by sending the miniport driver an OID_PNP_SET_POWER that specifies state D0. The miniport driver must then perform any device-dependent operations needed to restore the NIC to a working state. On returning NDIS_STATUS_SUCCESS to this OID request, the miniport driver and its NIC must be ready for normal operation.

If any filters were set for the miniport driver before its NIC transitioned to a sleeping state, the miniport driver must restore these filters. For power management-aware miniport drivers, NDIS does not restore such filters.


Power Management for Legacy Miniport Drivers

NDIS considers a miniport driver to be a legacy miniport driver that is not power management-aware if:

  • the bus driver indicates, during initialization, that the NIC is not power management-aware
  • the miniport driver returns NDIS_STATUS_UNSUPPORTED to query of OID_PNP_CAPABILITIES
  • the system or BIOS does not support power management
  • the user disables power management in the user interface

Legacy miniport drivers support only the fully on (D0) and the fully off (D3) network device power states.

During initialization, a legacy miniport driver can indicate that NDIS should not halt it before the system transitions to the sleeping (D3) state. A miniport driver makes such an indication by setting the NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND flag in the AttributeFlags parameter that the miniport driver passes to NdisMSetAttributesEx. A legacy miniport driver should set this flag only if it can:

  • Save all hardware context that it may require
  • Put its NIC in an appropriate state for the sleeping state (D3)
  • Reactivate the NIC to the working state (D0)

If NDIS can determine from the bus driver that the NIC is not power management-aware and if the miniport driver did not set the NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND flag, NDIS will not query the miniport driver's power management capabilities. However, if the miniport driver set the NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND flag, NDIS issues an OID_PNP_CAPABILITIES request to the miniport driver. In this case, the miniport driver should succeed the OID_PNP_CAPABILITIES request with NDIS_STATUS_SUCCESS. The miniport driver must also specify a device power state of NdisDeviceStateUnspecified for each wake-up capability in the NDIS_PM_WAKE_UP_CAPABILITIES structure that the miniport driver returns in response to the OID_PNP_CAPABILITIES request.

NDIS provides the following power management support for legacy miniport drivers:

  • NDIS succeeds all IRP_MN_QUERY_POWER requests that the system Power Manager sends to the device object that represents the NIC. That is, NDIS guarantees that the miniport driver's NIC will transition to the D3 state in response to any Query Power request from the system.
  • If the miniport driver did not set the NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND flag during initialization, NDIS calls the miniport driver's MiniportHalt function before the miniport driver's NIC transitions to state D3. The miniport driver's NIC loses all hardware context.
  • If the miniport driver set the NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND flag during initialization, NDIS does not halt the miniport driver before the system transitions to state D3. Instead, NDIS issues the miniport driver an OID_PNP_SET_POWER request to D3 state. The miniport driver must save any hardware context that it uses and put its NIC in a state appropriate for the D3 state.
  • While the system is transitioning to the S0 state, NDIS calls the miniport driver's MiniportInitialize function if NDIS halted the miniport driver. If NDIS did not halt the miniport driver, NDIS issues the miniport driver an OID_PNP_SET_POWER request to D0 state. The miniport driver must put its NIC in a state appropriate for the D0 state.
  • If any packet filters were set for the miniport driver before it went to sleep, NDIS restores these filters by sending an OID_GEN_CURRENT_PACKET_FILTER to the miniport driver. NDIS restores these filters only if the driver was halted.


Reset, Halt, and Shutdown

Previous Next

Reset, Halt, and Shutdown Functions

This section describes the reset, halt, and shutdown functions. These functions are described in the following topics:

Hardware Reset

Halt Handler

Shutdown Handler


Hardware Reset

A miniport driver must register a MiniportReset function with NdisMRegisterMiniport. The definition of MiniportReset is:

NDIS_STATUS
  MiniportReset(
    OUT PBOOLEAN  AddressingReset,
    IN NDIS_HANDLE  MiniportAdapterContext
    );

MiniportReset is called if NDIS determines that the miniport driver's network interface card (NIC) has hung, because of one of the following:

  • The miniport driver's MiniportCheckForHang function returned TRUE.
  • NDIS detected a pending send packet (for serialized miniport drivers only).
  • NDIS detected a pending request that did not complete in a specified timeout period.

MiniportReset can complete synchronously or asynchronously with a call to NdisMResetComplete (see the following figure).

Resetting a Network Interface Card

MiniportReset should:

  • Disable further interrupts
  • Clear out the packets associated with any sends in progress. For instance, on a ring buffer for a bus-master direct memory access (DMA) device, the pointers to send buffers should be cleared. A serialized miniport driver relinquishes pending packet ownership, regardless of the state of the send. For such a miniport driver, NDIS completes any pending sends to higher layers with an appropriate status. Deserialized and connection-oriented miniport drivers must return NDIS_STATUS_REQUEST_ABORTED for any queued send packets.
  • Restore the hardware state and the miniport driver's internal state back to the initial state it had with respect to multicast addresses and registered filters. Either the miniport driver takes responsibility for doing this or it relies on NDIS.

If the miniport driver returns FALSE in the AddressingReset parameter, the miniport driver returns its addressing values to their initial state. If the miniport driver returns TRUE in AddressingReset, NDIS calls a connectionless miniport driver's MiniportSetInformation function or a connection-oriented miniport driver's MiniportCoRequest function to set addresses and filters to their initial state. Note that the driver writer determines whether the miniport driver saves this addressing state so that the it can restore the state on reset or whether the miniport driver relies on NDIS to restore the addressing state on reset.


Halt Handler

A miniport driver must supply a MiniportHalt function to NdisMRegisterMiniport. The definition of MiniportHalt is:

VOID
  MiniportHalt(
    IN NDIS_HANDLE  MiniportAdapterContext
    );

MiniportHalt can be called:

  • After the failure of a request to set up multicast addresses or to set MAC_OPTIONS
  • After the unbinding of all the protocol drivers bound to the miniport driver
  • During an unload operation; for instance, when a NetStop command has caused an unload operation to be carried out
  • During system shutdown

MiniportHalt should undo everything that MiniportInitialize did, including the following:

  • Free ports
  • Release all the hardware resources it claimed
  • Free interrupt resources by calling NdisMDeregisterInterrupt
  • Free any memory it has allocated
  • Stop the NIC, unless the MiniportShutdown function has already restored the NIC to its initial state

Unloading a Miniport Driver

MiniportHalt should carry out the operations necessary to unload the driver before returning. If the miniport driver has any outstanding receive packets (packets that it has indicated up to NDIS but which NDIS has not yet returned), MiniportHalt must not return until such packets are returned to the miniport driver's MiniportReturnPacket function.

The preceding figure shows a set of calls that could be made by a MiniportHalt function. These calls are only a subset of the calls that could be made. The actual set of calls depends on previous actions of the miniport driver. The miniport driver can make these same calls in MiniportInitialize if it cannot successfully initialize the network adapter because of hardware problems or because it cannot acquire a resource that it needs. In such a case, MiniportInitialize should unload the driver by undoing its previous actions. Otherwise, MiniportHalt will undo the actions of MiniportInitialize.

The following lists the calls required to reverse certain actions that have been taken by the miniport driver:

  • If the miniport driver registered an interrupt, it should call NdisMDeregisterInterrupt.
  • If the miniport driver registered a shutdown handler, it should call NdisMDeregisterAdapterShutdownHandler.
  • If the miniport driver set up a timer or timers, it should call NdisMCancelTimer for each timer that it created.
  • If the miniport driver allocated any memory with NdisAllocateMemory, it should call NdisFreeMemory to free that memory.
  • If the miniport driver allocated any memory with NdisMAllocateSharedMemory, or NdisMAllocateSharedMemoryAsync., it should call NdisMFreeSharedMemory to free that memory.
  • If the miniport driver allocated and initialized storage for a pool of packet descriptors with NdisAllocatePacketPool, it should call NdisFreePacketPool to free that storage.
  • If the miniport driver allocated or reserved any hardware resources, these should be returned—for example, by calling NdisMDeregisterIoPortRange or, if the NIC is a bus-master DMA NIC, by calling NdisMFreeMapRegisters. A miniport driver that allocated shared memory must call NdisMFreeSharedMemory before calling NdisMFreeMapRegisters.


Shutdown Handler

A miniport driver should register a shutdown handler during initialization. The definition of the MiniportShutdown handler is:

VOID
  MiniportShutdown(
    IN PVOID  ShutdownContext
    );

A driver's shutdown handler should only:

  • Ensure that the hardware is not trying to copy any data to memory after returning from the shutdown handler. That is, if there is a direct memory access (DMA) operation in progress, the operation should be terminated.
  • Reset the NIC hardware to its initial state.

The shutdown handler can be called as a result of a user operation, in which case it runs at IRQL PASSIVE_LEVEL. It can also be called as a result of an unrecoverable system error. If so, MiniportShutdown can be running at any IRQL. MiniportShutdown should call no Ndis Xxx functions.

Unlike MiniportHalt, MiniportShutdown should not release any allocated resources. MiniportShutdown should just stop the NIC.


WAN Miniport Drivers

This section describes NDIS structures and functions for supporting WAN miniport drivers in both standard and Connection-oriented NDIS (CoNDIS) environments. This section also provides information about implementing both standard and CoNDIS WAN miniport drivers.

Microsoft® Windows® 2000 and later versions of the operating system support implementations of both standard and CoNDIS WAN miniport drivers. However, driver writers are encouraged to write CoNDIS WAN miniport drivers.

Standard WAN miniport drivers do the following:

  • Use most of the NDIS functions used by nonWAN connectionless miniport drivers
  • Replace a set of NDIS functions used by nonWAN connectionless miniport drivers
  • Provide additional WAN-specific capabilities

CoNDIS WAN miniport drivers do the following:

  • Export the same set of functions that all connection-oriented miniport drivers do
  • Use the set of NDIS functions used by all connection-oriented miniport drivers
  • Provide additional WAN-specific capabilities

WAN miniport drivers for both standard and CoNDIS environments are developed using the requirements and functions described in Overview of Miniport Driver Operations and Functions, NDIS Miniport Driver DriverEntry Function, and Transferring Data with the exceptions and additional considerations described in this section.

Remote Access Service (RAS) enables remote workstations to dial in to the LAN and transparently access resources on the LAN.

The following topics describe how drivers for wide area network cards communicate in both standard and connection-oriented environments. These topics also describe how to implement WAN miniport drivers for both environments and describe packet framing:

RAS Architecture

NDISWAN Overview

Network Cards, Bindings, and Connections

Implementing WAN Miniport Drivers

WAN Packet Framing

Extensions to Support Telephonic Services Over Standard NDIS

Using CoNDIS Extensions that Support Telephonic Services


RAS Architecture

This section shows the relationship between Remote Access Service (RAS) and how drivers for wide area network cards such as ISDN, X.25, and Switched 56 adapters use the services of NDIS and NDISWAN to communicate in both standard WAN and connection-oriented WAN environments.

The following figure shows the RAS architecture.

RAS Architecture

The following describes the NDISWAN intermediate NDIS driver, the NDISTAPI driver, and the NDPROXY driver and provides a more detailed view of the entire RAS system.

The components of WAN, RAS, and TAPI that are shown in the preceding figures are described next.

RAS Functions

The RAS set of functions allows user-mode applications to make RAS connections. After a RAS connection is established, applications can connect to network services using standard network interfaces such as Windows Sockets, NetBIOS, Named Pipes, or RPC.

Transports

The RAS system component provides transports such as PPP Authentication (PAP, CHAP) and network configuration protocols (IPCP, IPXCP, NBFCP, LCP, and so forth). A WAN miniport driver implements only PPP media-specific framing.

TAPI Service

The TAPI service (tapisrv.exe) presents the Telephony Service Provider Interface (TSPI) of different service providers to TAPI-aware applications. Applications use specific service providers to communicate with specific device types. These service providers are DLLs that run in the context of the TAPI service process. The operating system supplies service providers that both standard and CoNDIS WAN miniport drivers can use to communicate with user-mode applications.

KMDDSP

This component is a service provider DLL that runs in the context of the TAPI service process. The kmddsp.tsp component presents a TSPI interface to TAPI-aware applications so that NDISTAPI can communication with user-mode applications. This component converts user-mode requests to corresponding TAPI OIDs for NDISTAPI.

NDISTAPI

This component implements TAPI with a kernel-mode portion of the TAPI interface. The ndistapi.sys component communicates with standard WAN miniport drivers by routing TAPI-related OID requests with the NdisRequest function to the appropriate standard WAN miniport driver.

NDPTSP

This component is a service provider DLL that runs in the context of the TAPI service process. The ndptsp.tsp component presents a TSPI interface to TAPI-aware applications so that NDPROXY can communication with user-mode applications. This component converts user-mode requests to corresponding TAPI-CO-related OIDs for NDPROXY.

NDPROXY

This component implements TAPI by encapsulating TAPI parameters in NDIS structures when making and accepting calls. The ndproxy.sys component communicates with TAPI through the TSPI interface of NDPTSP. The ndproxy.sys component communicates through NDIS with NDISWAN and a CoNDIS WAN NIC miniport driver. This component presents a client interface to a miniport driver and a call manager interface to NDISWAN. NDISWAN presents a client interface to this component. A miniport driver presents a call manager interface to this component. This component enumerates TAPI capability of a CoNDIS WAN miniport driver by calling the NdisCoRequest function with TAPI-CO-related OIDs. This component also registers the TAPI-specific address family, creates virtual connections (VCs), makes and accepts calls, and activates VCs so that data can be sent and received on those VCs.

NDISWAN

The NDISWAN intermediate NDIS driver supports PPP protocol/link framing, compression, and encryption. NDISWAN supports both standard and connection-oriented miniport drivers.
The ndiswan.sys driver communicates with standard WAN NIC drivers through two interfaces:

  • NDIS WAN interface
  • NDIS miniport driver interface

The ndiswan.sys driver communicates with CoNDIS WAN miniport drivers through the connection-oriented miniport driver interface.

Serial Driver

This component is a standard device driver for internal serial ports or multiport serial cards. The built-in asynchronous WAN miniport driver for Windows® 2000 and later uses the internal serial driver for modem communications. Any driver that exports the same functions as the serial driver will work with the built-in asynchronous WAN miniport driver.

X.25 vendors can choose to implement serial driver emulators for the X.25 card. In this case, each virtual circuit on the X.25 card appears as a serial port (with an X.25 PAD attached to it). The connection interface must correctly emulate serial signals such as DTR, DCD, CTS, RTS, and DSR.

X.25 vendors who choose to implement a serial driver emulator for their X.25 card must also make an entry for their PAD in the pad.inf file. This file contains the command/response script needed to make a connection through the X.25 PAD. For more information about the pad.inf file, see the Remote Access Service in the Platform SDK.

WAN Miniport Driver

Depending on environment, ISDN, Switched 56, and X.25 vendors should write either a standard or CoNDIS WAN miniport driver for their NICs.


NDISWAN Overview

NDISWAN is an intermediate NDIS driver that works in both standard and connection-oriented environments. NDISWAN presents both standard and CoNDIS 802.3 miniport driver interfaces to protocol drivers above it. NDISWAN also presents a protocol-driver interface to a WAN miniport driver below it that manages a WAN-capable NIC. For CoNDIS, this WAN miniport driver can be an integrated miniport call manager (MCM) driver.

NDISWAN converts an out-going packet from LAN to PPP format. NDISWAN uses simple HDLC framing. Most of the media-specific framing must be done in the miniport driver. NDISWAN gets hints about the framing performed by a standard WAN miniport driver from the miniport driver's response to the OID_WAN_MEDIUM_SUBTYPE query request.

Before a WAN miniport driver can send or receive packets on a wide area network, a connection must be created. The way a connection is created depends on whether the WAN miniport driver operates in a standard or a CoNDIS environment as described following:

  • In a standard environment, an application must set up a connection that originates on the sending node or accept a connection that originates on a remote node by making or accepting a call. The setup, supervision and tear-down of a connection is done through TAPI. TAPI requests and status indications to TAPI all go through NDISWAN. For details about setting up a standard WAN miniport driver to use TAPI services, see Extensions to Support Telephonic Services Over Standard NDIS.
  • In a CoNDIS environment, a virtual connection (VC) is created. The NDPROXY driver creates a VC for an outgoing call that an application originated. Similarly, an MCM driver initiates the creation of a VC for an incoming call that the MCM driver indicates to NDISWAN and NDPROXY. The MCM driver must communicate and sometimes negotiate the parameters for the VC with the remote party. The setup, supervision and tear-down of a connection is done through TAPI. TAPI requests and status indications to TAPI all go through NDPROXY. For more information about the TAPI services that NDPROXY implements, see Using CoNDIS Extensions that Support Telephonic Services.

After an application establishes a connection with a remote node, packets can be exchanged on a wide area network. The way packets are exchanged depends on whether the WAN miniport driver operates in a standard or a CoNDIS environment as described following:

  • In a standard environment, the typical path of a packet from a protocol driver to the standard WAN miniport driver begins when a protocol driver calls NdisSend with a packet descriptor. NDISWAN examines the header of the packet descriptor and decides over which link the packet will be sent. NDISWAN copies the typically discontiguous data packet into a contiguous buffer with the appropriate header and tail padding specified by the standard WAN miniport driver during its initialization and registration.
  • In a CoNDIS environment, packet flow on a VC from a protocol driver to the CoNDIS WAN miniport driver typically begins after a protocol driver calls the NdisCoSendPackets function with a handle to the VC and an array of pointers to packet descriptors. NDISWAN receives the packet array for the specific VC.

Packets that NDISWAN receives have several possible configuration options: header compression, data compression, and encryption. These configuration options are applied in that order on these packets. On the receive side, the reverse path is applied. Anytime a configuration option such as compression or encryption is enabled, the particular WAN miniport driver is informed.

Before sending packets to the WAN miniport driver's send function, NDISWAN does simple PPP HDLC framing. Simple PPP HDLC framing is PPP's HDLC framing without the FCS, bit or byte stuffing, and any beginning or end flags. For more information on media-specific framing, see the WAN Packet Framing section. Finally, the NDISWAN driver sends the packets. NDIS in turn calls the WAN miniport driver's send function. The send function that NDIS calls depends on whether the WAN miniport driver is a standard or CoNDIS type as described following:

  • For a standard WAN miniport driver, this send function is MiniportWanSend instead of the comparable function implemented by other LAN-miniport drivers.
  • For a CoNDIS WAN miniport driver, this send function is MiniportCoSendPackets, which is the same send function that all connection-oriented miniport drivers implement.

After packets are received by the WAN miniport driver, it should send the packets out on the active connection. For a standard environment, this connection is an established link. For a CoNDIS environment, this connection is a VC. The number of outstanding packets that the WAN miniport driver can handle per connection is specified by the miniport driver to a protocol driver. The way the WAN miniport driver specifies this number depends on whether the WAN miniport driver is a standard or CoNDIS type as described following:

  • The standard WAN miniport driver specifies the default number of outstanding packets that it can have per data channel in the MaxTransmit member of the NDIS_WAN_INFO structure. The miniport driver provides this structure when the miniport driver responds to the OID_WAN_GET_INFO request from the protocol driver. However, the miniport driver can manage the send window dynamically and on a per-line basis by calling NdisMIndicateStatus with a line-up indication. In this call, the miniport driver provides a new nonzero value for the SendWindow member of the NDIS_MAC_LINE_UP structure passed in the call. If the miniport driver sets the value of the SendWindow member to zero, NDISWAN uses the default value in MaxTransmit for that line.
    The standard WAN miniport driver might have to modify or add to the header as well as add to the end (tail) of the packet (for example, to add the FCS). Appropriate padding at the beginning and end of the packet was provided previously by the miniport driver. The WAN miniport driver can alter the data in the packet in any way it sees fit in order to send that packet on the WAN medium.
  • The CoNDIS WAN miniport driver specifies the number of outstanding packets that it can have per VC in the MaxSendWindow member of the NDIS_WAN_CO_INFO structure. The miniport driver provides this structure when the miniport driver responds to the OID_WAN_CO_GET_INFO request from the protocol driver. However, the miniport driver can adjust this number dynamically and on a per-VC basis using the SendWindow member in the WAN_CO_LINKPARAMS structure that the miniport driver can pass to the NdisMCoIndicateStatus function. NDISWAN uses the current SendWindow value as its limit on outstanding sends. The miniport driver can set the value of the SendWindow member to zero to specify that it cannot handle any outstanding packets. That is, if the SendWindow member is set to zero, the send window is shut down.

Note that if a CoNDIS WAN miniport driver sets SendWindow to zero, its send window is shut down. If a standard WAN miniport driver sets SendWindow to zero, its send window is set to the default value.


Network Cards, Bindings, and Connections

WAN miniport drivers can manage many connections per binding and thus many connections per NIC. For a standard environment, these connections are established links. For a CoNDIS environment, these connections are virtual connections (VC).

Like other miniport drivers, every WAN miniport driver must have at least one NIC for which it allocates and maintains a NIC-specific context area. The NIC-specific context area is simply a way to store, retrieve, and use information about the hardware specifics of the NIC, such as interrupt, bus type, I/O range, and memory, as well as to maintain run-time state. A miniport driver should specify one NIC-specific context area for each network card in the system that it supports.

From a WAN miniport driver's point-of-view, there is only one binding per NIC even if several protocols above the miniport driver are bound to a particular NIC. Because WAN miniport drivers are ignorant of such protocols, the miniport drivers do not maintain bindings for their NICs. NDISWAN handles bindings that WAN miniport drivers have to various protocols. In effect, NDISWAN binds to one or more WAN miniport drivers and one or more protocol drivers bind to NDISWAN.

Standard and CoNDIS WAN miniport drivers use different types of connections on a NIC as described following:

  • The connections that a standard WAN miniport driver uses are links. Links are logical, point-to-point bidirectional communication channels. There can be many links per NIC. Links are dynamically brought up and torn down. The link speed and quality of the link can be different for each connection. However, it is assumed that the padding and link capabilities are universal for all links on an NIC. If a standard WAN miniport driver specifies a 20-byte header padding and 4-byte tail padding, these paddings must remain constant for all links on that miniport driver's NIC.
  • A CoNDIS WAN miniport driver uses virtual connections (VCs) just as all connection-oriented miniport drivers do . There can be many VCs per NIC. The speed of each VC can be different. However, the capabilities for all VCs on a NIC are the same. If a CoNDIS WAN miniport driver specifies a maximum frame size for any net packet that the miniport driver can send and receive, that maximum frame size must remain constant for all VCs on that NIC.

If a particular WAN miniport driver specifies that it does not require PPP address and control-field compression, it is assumed true for all connections on the miniport driver's NIC.

Bindings for WAN Miniport Drivers

Protocols bind once to NDISWAN and do not bind to WAN miniport drivers. This type of binding saves memory and simplifies WAN miniport drivers. Because there will typically be several protocols in a given system and there could be more than one WAN miniport driver, the reduction in the number of bindings saves memory. That is, each protocol does not have to bind to each WAN miniport driver. In the preceding figure, if each protocol bound to each WAN miniport driver, there would be nine bindings. Also, because protocols can rely on only having a single WAN binding, these protocols might be simplified.

A WAN miniport driver must be an NDIS miniport driver. Full NIC drivers are not supported for WAN NICs. This section, in combination with other NDIS Miniport Drivers sections, provide the design information that a driver developer needs to write a WAN miniport driver.

Miniport drivers must add the following line to their sources file before building to identify the driver as a miniport driver.

C_DEFINES=/DNDIS_MINIPORT_DRIVER

Standard WAN miniport drivers that support connections through TAPI must add the following line to their sources file before building to identify the TAPI version that they support.

C_DEFINES=–DNDIS_TAPI_CURRENT_VERSION=0x00010003

CoNDIS WAN miniport drivers that are integrated miniport call manager (MCM) drivers and that support the CoNDIS address family type CO_ADDRESS_FAMILY_TAPI_PROXY must add the following line to their sources file before building to identify the TAPI version that they support.

C_DEFINES=–DNDIS_TAPI_CURRENT_VERSION=0x00030000

For WAN miniport drivers, the include paths should include ndiswan.h as well as ndis.h.

If the WAN miniport driver supports connections through TAPI, the driver should also include ndistapi.h.


Implementing WAN Miniport Drivers

To support such media as ISDN, Frame Relay, Switch 56, and so forth with Remote Access Service (RAS), a NIC vendor must supply a WAN miniport driver.

Standard WAN miniport drivers call the WAN-specific variations of a few NDIS functions. While a standard WAN miniport driver calls many of the same NDIS functions as a LAN NIC miniport driver, equivalent WAN-specific NDIS calls replace certain NDIS calls of a LAN miniport driver. In addition, a standard WAN miniport driver provides a WAN-specific send function whose definition differs from the definition of the MiniportSend function implemented by LAN miniport drivers. These WAN-specific calls and functions are described later in this section.

CoNDIS WAN miniport drivers call the same set of NDIS functions that all connection-oriented miniport drivers call and provide the same set of functions that all connection-oriented miniport drivers implement.

WAN miniport drivers communicate with the NDISWAN intermediate NDIS driver through the NDIS Library. NDISWAN can provide common services such as data compression, encryption, loopback, simple PPP framing, and so forth, so that WAN miniport drivers require only features specific to the medium (for example, Q931 signaling required for ISDN).

WAN miniport drivers are miniport drivers that:

  • Perform connection-management operations passed from the NDISWAN intermediate NDIS driver to WAN miniport drivers.
  • Accept send requests and indicate received data to the NDISWAN driver.

Note that in addition to the information in this section, developers of WAN miniport drivers should also refer to other NDIS Miniport Drivers sections on LAN miniport drivers and to the Network Reference for details on the many NDIS functions, for example, NdisMSetTimer, NdisOpenConfiguration, and others, that are provided for all miniport drivers.

The following topics define the interface between the NDISWAN driver and WAN miniport drivers and provide details about implementing miniport drivers:

Differences Between Standard WAN and LAN Miniport Drivers

Additional Features of CoNDIS WAN Miniport Drivers

WAN Miniport Driver Services

WAN Miniport Driver Indications


Differences Between Standard-WAN and LAN Miniport Drivers

Previous Next

Differences Between Standard WAN and LAN Miniport Drivers

There are several differences in the way a standard WAN miniport driver interfaces with NDIS as compared to a LAN miniport driver described in the previous chapters. Such differences affect how a standard WAN miniport driver is implemented.

  • A standard WAN miniport driver must not register a MiniportTransferData handler with NdisMRegisterMiniport. Instead, a WAN miniport driver always passes an entire packet to the NdisMWanIndicateReceive function. After NdisMWanIndicateReceive returns, the packet has been copied and the WAN miniport driver can reuse the packet resources it allocated.
  • Standard WAN miniport drivers provide a MiniportWanSend function instead of a MiniportSend function. MiniportWanSend accepts an NDIS_WAN_PACKET instead of an NDIS_PACKET-type descriptor and an additional parameter that specifies a specific data channel on which a packet is to be sent.
  • Standard WAN miniport drivers never return NDIS_STATUS_RESOURCES as the status of MiniportWanSend or any other MiniportXxx function and cannot call NdisMSendResourcesAvailable.
  • Standard WAN miniport drivers support a set of WAN-specific OIDs to set and query operating characteristics.
  • Standard WAN miniport drivers support a set of WAN-specific status indications which are passed to NdisMIndicateStatus. These status indications report changes in the status of a link.
  • Standard WAN miniport drivers call alternative WAN-specific NDIS functions to complete the WAN-specific NDIS calls for send and receive. The two completion calls are:

    NdisMWanIndicateReceiveComplete

    NdisMWanSendComplete

  • Standard WAN miniport drivers use an NDIS_WAN_PACKET instead of an NDIS_PACKET-type descriptor.
  • Standard WAN miniport drivers keep a WAN-specific set of statistics.
  • Standard WAN miniport drivers never do loopback; it is always provided by NDISWAN.


Additional Features of CoNDIS WAN Miniport Drivers

CoNDIS WAN miniport drivers must be implemented with the following additional features:

  • CoNDIS WAN miniport drivers must support a set of CoNDIS-WAN-specific OIDs to set and query operating characteristics.
  • CoNDIS WAN miniport drivers must support a set of CoNDIS-WAN-specific status indications which are passed to NdisMCoIndicateStatus. These status indications report changes in the status of a VC.
  • CoNDIS WAN miniport drivers should keep a set of statistics for each VC on the miniport driver's NIC.
  • CoNDIS WAN miniport drivers use an NDIS_PACKET-type descriptor instead of the NDIS_WAN_PACKET-type descriptor that standard WAN miniport drivers use.
  • CoNDIS WAN miniport drivers never attempt to loop back any packets; NDISWAN provides loop-back support.


WAN Miniport Driver Services

Standard and CoNDIS WAN miniport drivers each provide a different upper-edge interface to the NDISWAN driver. The upper-edge interface provided by a standard WAN miniport driver is identical to a LAN miniport driver except for the send request. The upper-edge interface provided by a CoNDIS WAN miniport driver is identical to a connection-oriented miniport driver. A WAN miniport driver receives and responds to a set of WAN-specific OIDs. For standard WAN miniport drivers, the query and set OIDs are passed to MiniportQueryInformation and MiniportSetInformation functions respectively. For CoNDIS WAN miniport drivers, the query and set OIDs are passed to the MiniportCoRequest function. A WAN miniport driver identifies itself as a WAN miniport driver when it registers itself.

The following topics describe how a WAN miniport driver identifies itself, how it processes send operations, and the OIDs that can be used to get or set characteristics of both standard and CoNDIS WAN miniport drivers and WAN NICs.

Registering as a WAN Miniport Driver

Querying Information in a WAN Miniport Driver

Setting the State of a WAN Miniport Driver

Sending on a WAN Miniport Driver


Registering as a WAN Miniport Driver

The miniport driver calls the NdisMRegisterMiniport function in its DriverEntry function to register with NDIS. In this call, the standard WAN miniport driver does the following:

  • Identifies itself as either a standard or connection-oriented miniport driver
  • Indicates that it requires WAN services by setting the flag NDIS_USE_WAN_WRAPPER in the Reserved member of the NDISXX_MINIPORT_CHARCTERISTICS structure.
  • Specifies the appropriate NDIS version number. NDIS 3.0, 4.0, and 5.0 support standard WAN miniport drivers. Only NDIS 5.0 and later support CoNDIS WAN miniport drivers.
  • Specifies the entry points for driver-supplied MiniportXxx functions.

To receive the appropriate NDISXX_MINIPORT_CHARCTERISTICS structure from NDIS, the WAN miniport driver must also either embed the appropriate compiler directives at the start of the miniport driver's source code or set the appropriate build directives in the miniport driver's sources file. These directives depend on whether the WAN miniport driver operates in a standard or a CoNDIS environment as described following:

  • For a standard WAN miniport driver, the following compiler directives at the start of the miniport driver's source code indicate that the miniport driver uses a 4.0 NDIS_MINIPORT_CHARACTERISTICS structure:
    #define NDIS_MINIPORT_DRIVER
#define NDIS40_MINIPORT 1
#include <ndis.h> // After preceding directives

    If the NDIS40_MINIPORT directive is omitted, the standard WAN miniport driver uses a 3.0 NDIS_MINIPORT_CHARACTERISTICS structure.

  • For a CoNDIS WAN miniport driver, the following compiler directives at the start of the miniport driver's source code indicate that the miniport driver uses a 5.0 NDIS_MINIPORT_CHARACTERISTICS structure:
    #define NDIS_MINIPORT_DRIVER
#define NDIS50_MINIPORT 1
#include <ndis.h> // After preceding directives

Note that the members of NDISXX_MINIPORT_CHARCTERISTICS that specify the version numbers of NDIS must be consistent with the compiler or build directives set for the miniport driver.

Following execution of a WAN miniport driver's DriverEntry function the miniport driver has registered its miniport driver entry points for one or more NICs. The WAN miniport driver must then provide information about its capabilities and the capabilities of its NICs to upper-layer drivers, such as NDISWAN and NDPROXY. The way this capability information is provided depends on whether the WAN miniport driver operates in a standard or a CoNDIS environment as described following:

  • For a standard WAN miniport driver, the miniport driver's MiniportInitialize function first completes the initialization of one or more NICs. The NDISWAN driver then queries the miniport driver for information with an OID_WAN_GET_INFO query. NDIS in turn calls the miniport driver's MiniportQueryInformation function and passes the query. A miniport driver that is TAPI-capable should set the TAPI_PROVIDER bit of the FramingBits member of the NDIS_WAN_INFO structure that is passed with the query. Setting the TAPI_PROVIDER bit informs upper-layer drivers to send TAPI OIDs to the miniport driver. The standard WAN miniport driver uses TAPI OIDs to set up, use, and tear down TAPI connections. For more information about setting up a standard WAN miniport driver to use TAPI services, see Extensions to Support Telephonic Services Over Standard NDIS.
  • For a CoNDIS WAN miniport driver, the miniport driver calls the NdisCmRegisterAddressFamily function from within its MiniportInitialize function to register its call-manager entry points and the address family type CO_ADDRESS_FAMILY_TAPI_PROXY. By doing so, the miniport driver advertises that it implements TAPI services. NDIS in turn notifies NDPROXY of the newly registered address family. NDPROXY determines that it can use the TAPI services provided by the call manager that is integrated into the WAN miniport driver. A TAPI-capable CoNDIS WAN miniport driver can be an integrated miniport call manager (MCM) driver. NDPROXY opens the TAPI-proxy address family that is associated with the miniport driver and registers NDPROXY's connection-oriented entry points with NDIS. These entry points are used to communicate with the miniport driver. Once NDPROXY determines that it can use the miniport driver's TAPI services, NDPROXY can enumerate the TAPI capabilities of the miniport driver and later send TAPI requests that are encapsulated in NDIS structures. For details about using CoNDIS extensions for Telephonic-service support, see Using CoNDIS Extensions that Support Telephonic Services.

    The NDISWAN driver can also query the miniport driver for information about the miniport driver's virtual connections (VCs) with an OID_WAN_CO_GET_INFO query. NDIS in turn calls the miniport driver's MiniportCoRequest function and passes the query.


Querying WAN Miniport Driver Information

An upper-layer driver calls either NdisRequest or NdisCoRequest functions with a query request to determine WAN-specific capabilities and current status of either a particular standard or CoNDIS WAN miniport driver and the miniport driver's NIC. After the NDISWAN driver forwards the query request, NDIS in turn calls the WAN miniport driver's query-request function. The query-request function that NDIS calls depends on whether the WAN miniport driver is a standard or CoNDIS type as described following:

  • For a standard WAN miniport driver, this query-request function is MiniportQueryInformation. In a standard WAN miniport driver, this function is the same as in a LAN miniport driver, except that the WAN miniport driver recognizes standard WAN OIDs. For more information about standard WAN OIDs, see Standard WAN Objects.
  • For a CoNDIS WAN miniport driver, this query-request function is MiniportCoRequest. In a CoNDIS WAN miniport driver, this function is the same as in a standard connection-oriented miniport driver, except that the CoNDIS WAN miniport driver recognizes CoNDIS WAN OIDs.

If the particular WAN miniport driver completes either NdisRequest or NdisCoRequest asynchronously by returning a status of NDIS_STATUS_PENDING, it must complete the query later by calling a completion function. The completion function that the miniport driver later calls depends on whether the miniport driver is a standard or CoNDIS type as described following:

  • For a standard WAN miniport driver, this completion function is NdisMQueryInformationComplete.
  • For a CoNDIS WAN miniport driver, this completion function is NdisCoRequestComplete.

When NDIS calls the particular WAN miniport driver's query-request function, NDIS passes a pointer to the NDIS_REQUEST structure that contains the query OID and a buffer to hold the information retrieved from the WAN miniport driver. The WAN miniport driver controls this buffer until the request completes. If the number of bytes specified in the InformationBufferLength member of NDIS_REQUEST is insufficient for the information required by the OID, the WAN miniport driver should fail the query request and set the BytesNeeded member of NDIS_REQUEST to the number of bytes that the OID requires.

No other requests will be submitted to the particular WAN miniport driver until the current query request completes.

A WAN miniport driver must recognize and respond properly to a group of WAN query OIDs. This group of WAN query OIDs depends on whether the WAN miniport driver is a standard or CoNDIS type as described in the following sections:

Standard WAN query OIDs

CoNDIS WAN query OIDs

Standard WAN Query OIDs

A standard WAN miniport driver must recognize and respond properly to the standard WAN OIDs summarized next.

OID_WAN_MEDIUM_SUBTYPE

The OID_WAN_MEDIUM_SUBTYPE OID is queried to determine the media subtypes supported by a standard WAN miniport driver. The information returned by the standard WAN miniport driver should be one of the following subtypes from the NDIS_WAN_MEDIUM_SUBTYPE enumeration:

  • NdisWanMediumHub
  • NdisWanMediumX_25
  • NdisWanMediumIsdn
  • NdisWanMediumSerial
  • NdisWanMediumFrameRelay
  • NdisWanAtm
  • NdisWanSonet
  • NdisWanMediumSW56K
  • NdisWanMediumPPTP
  • NdisWanMediumL2TP
  • NdisWanMediumIrda
  • NdisWanMediumParallel

OID_WAN_GET_INFO

The OID_WAN_GET_INFO OID is queried after a standard WAN miniport driver initializes to determine a range of information about the miniport driver and the miniport driver's NIC. The structure of this OID is documented in the Network Driver Reference. The information returned by the standard WAN miniport driver is contained in members of a NDIS_WAN_INFO structure. This information includes:

Parameter | Contents
MaxFrameSize | The driver sets this to the maximum frame size in bytes it can send and receive. Typically this is 1500 but driver should handle 32 bytes larger than its anticipated maximum. The value does not include the driver's own framing overhead or the PPP HDLC overhead.
MaxTransmit | The default maximum number of outstanding packets that the WAN miniport driver can handle on a line. The NDISWAN driver ensures that the miniport driver does not exceed that number, that is, NDISWAN holds send packets if the maximum is reached unless the miniport driver resets the maximum in a subsequent line-up indication. The miniport driver can change this value dynamically and on a per-line basis by setting the SendWindow member in line-up indications to a nonzero value.
HeaderPadding | The amount of required buffer space, in bytes, at the beginning of the largest packet.
TailPadding | The amount of required buffer space, in bytes, at the end of the largest packet.
Endpoints | The maximum number of links this NIC can support. This is an adapter-specific characteristic.
MemoryFlags | Zero if the NIC is not a DMA device. If the NIC supports DMA, this flag can be set to NDIS_MEMORY_NONCACHED and/or NDIS_MEMORY_CONTIGUOUS.
HighestAcceptableAddress | If the WAN miniport driver's NIC supports DMA, set this flag to NDIS_PHYSICAL_ADDRESS_CONST (-1,-1); otherwise, if the NIC supports DMA and up to 24-bit addresses, set this flag to NDIS_PHYSICAL_ADDRESS_CONST (0x1000000,0). Subsequently, memory within the specified range will be allocated for all packets to be transmitted by the NIC. Thus, memory can just be DMAed directly to the NIC instead of having to be double-buffered through a CPU-memory copy.
FramingBits | The driver sets bits that specify the types of framing the driver supports.

OID_WAN_PERMANENT_ADDRESS

The OID_WAN_PERMANENT_ADDRESS OID is queried for the address of the NIC that is encoded in the hardware.

OID_WAN_CURRENT_ADDRESS

The OID_WAN_CURRENT_ADDRESS OID is queried for the address the NIC is currently using.

The standard WAN miniport driver should return a unique address for each NIC. The address is presented to bound protocols as an Ethernet address. The least significant bit of the first byte must not be a 1, or it could be interpreted as an Ethernet multicast address. If the vendor has an assigned Ethernet vendor code, this code should be used to assure that the address does not conflict with another vendor's address.

OID_WAN_GET_LINK_INFO

The OID_WAN_GET_LINK_INFO OID is queried to determine the current state of a link. The structure of this OID is documented in the Network Driver Reference. The standard WAN miniport driver returns the values that it set on a previous OID_WAN_SET_LINK_INFO OID set request. If a set request was not previously made, the standard WAN miniport driver should return the current state of the link. If the link is inactive or does not exist, an error NDIS_STATUS_INVALID_DATA should be returned. The information returned by the standard WAN miniport driver is contained in members of a NDIS_WAN_GET_LINK_INFO structure. This information includes:

Parameter | Contents
NdisLinkHandle | Identifies the link context of the WAN miniport driver for this query.
MaxSendFrameSize | Specifies the maximum buffer size, in bytes, that the WAN miniport driver can accept for transmission on this link. The miniport driver's MiniportWanSend function can reject incoming send packets that are larger than this size.
MaxRecvFrameSize | The largest packet, excluding padding, that will be accepted by the miniport driver from the network. Larger packets may be dropped.
HeaderPadding | The amount of padding, in bytes, in the head of the frame.
TailPadding | The amount of padding at the tail of the frame.
SendFramingBits | A bit mask that describes what types of framing should be sent.
RecvFramingBits | A bit mask that describes what type of framing should be received.
SendCompressionBits | Reserved.
RecvCompressionBits | Reserved.
SendACCM | Specific to asynchronous media types. If present, logical bits 0-31 indicate the respective byte to be byte stuffed. That is, if bit 0 is set to 1, then ASCII character 0x00 should be byte stuffed, and so forth.
RecvACCM | As described for SendACCM.

OID_WAN_GET_STATS_INFO

The OID_WAN_GET_STATS_INFO OID is queried to determine status for a link on the standard WAN miniport driver's NIC. A standard WAN NIC miniport driver is expected to keep statistics for its links. The structure of this OID is documented in the Network Driver Reference. The information returned by the standard WAN miniport driver is contained the in members of an NDIS_WAN_GET_STATS_INFO structure. This information includes:

Members | Contents
NdisLinkHandle | Identifies the link context of the WAN miniport driver for this query.
BytesSent | Specifies the number of bytes transmitted.
BytesRcvd | Specifies the number of bytes received.
FramesSent | Specifies the number of frames (WAN packets) sent.
FramesRcvd | Specifies the number of frames received.
CRCErrors | Specifies the number of CRC errors encountered for this link. CRC errors are caused by the failure of a cyclic redundancy check. A CRC error indicates that one or more bytes in the frame received were found garbled on arrival.
TimeoutErrors | Specifies the number of time-out errors encountered for this link. Time-out errors occur when an expected byte is not received in time.
AlignmentErrors | Specifies the number of alignment errors encountered for this link. Alignment errors occur when a byte received is different from the byte expected. This typically happens when a byte is lost or when a time-out error occurs.
SerialOverrunErrors | Specifies the number of serial overruns encountered for this link. Serial overruns occur when the WAN NIC cannot handle the rate at which data is received.
FramingErrors | Specifies the number of framing errors encountered for this link. A framing error occurs when an asynchronous byte is received with an invalid start or stop bit.
BufferOverrunErrors | Specifies the number of buffer overruns encountered for this link. Buffer overruns occur when the standard WAN miniport driver cannot handle the rate at which data is received.

CoNDIS WAN Query OIDs

A CoNDIS WAN miniport driver must recognize and respond properly to the connection-oriented WAN OIDs summarized next.

OID_WAN_CO_GET_INFO

The OID_WAN_CO_GET_INFO OID is queried after a CoNDIS WAN miniport driver initializes to determine a range of information about all VCs on the miniport driver's NIC. The structure of this OID is documented in the Network Driver Reference. The information returned by the CoNDIS WAN miniport driver is contained in the members of a NDIS_WAN_CO_INFO structure. This information includes:

Members | Contents
MaxFrameSize | The CoNDIS WAN miniport driver sets this member to the maximum frame size in bytes for net packets that the miniport driver can send and receive. This value should exclude the miniport driver's own framing overhead and/or the PPP HDLC overhead. Typically this value is around 1500 but the miniport driver should handle frames that are 32 bytes larger than the anticipated maximum.
MaxSendWindow | The CoNDIS WAN miniport driver sets this member to the maximum number of outstanding packets that the miniport driver can handle on each VC. The NDISWAN driver ensures that the miniport driver does not exceed that number, that is, NDISWAN holds send packets if the maximum is reached unless the miniport driver resets the maximum in a subsequent link-parameters indication. The miniport driver can change this value dynamically and on a per-VC basis by setting the SendWindow member in the WAN_CO_LINKPARAMS structure. The miniport driver then indicates this structure up to NDISWAN.
FramingBits | The CoNDIS WAN miniport driver sets this member to a 32-bit mask that specifies the types of framing the miniport driver supports. The miniport driver also can specify if it supports TAPI connections and if it performs its own framing.
DesiredACCM | The CoNDIS WAN miniport driver sets this member to the type of asynchronous control character mapping that it requires.

OID_WAN_CO_GET_LINK_INFO

The OID_WAN_CO_GET_LINK_INFO OID is queried to determine PPP framing information about the current state of a VC on the NIC. The structure of this OID is documented in the Network Driver Reference. The CoNDIS WAN miniport driver returns the values that it set on a previous OID_WAN_CO_SET_LINK_INFO OID set request. If a set request was not previously made, the CoNDIS WAN miniport driver should return the current state of the VC. If the VC is inactive or does not exist, an error NDIS_STATUS_INVALID_DATA should be returned. The information returned by the CoNDIS WAN miniport driver is contained in members of a NDIS_WAN_CO_GET_LINK_INFO structure. This information includes:

Members | Contents
MaxSendFrameSize | Specifies the maximum buffer size, in bytes, that the miniport driver can accept for transmission on this VC. The miniport driver's MiniportCoSendPackets function can reject incoming send packets that are larger than this size.
MaxRecvFrameSize | Specifies the largest packet that will be received from the network. The miniport driver can drop any packets that are larger.
SendFramingBits | A 32-bit mask that specifies the types of framing that the miniport driver should send.
RecvFramingBits | A 32-bit mask that specifies the types of framing that the miniport driver should receive.
SendACCM | This member is specific to asynchronous media types. If present, logical bits 0-31 indicate the respective byte to be byte stuffed. That is, if bit 0 is set to 1, then ASCII character 0x00 should be byte stuffed, and so forth.
RecvACCM | As described for SendACCM.

OID_WAN_CO_GET_STATS_INFO

The OID_WAN_CO_GET_STATS_INFO OID is queried to determine status for a VC on the CoNDIS WAN miniport driver's NIC. A CoNDIS WAN miniport driver is expected to keep statistics for its VCs. The structure of this OID is documented in the Network Driver Reference. The information returned by the CoNDIS WAN miniport driver is contained in members of a NDIS_WAN_CO_GET_STATS_INFO structure. This information includes:

Members | Contents
BytesSent | Specifies the number of bytes transmitted.
BytesRcvd | Specifies the number of bytes received.
FramesSent | Specifies the number of frames (packets) sent.
FramesRcvd | Specifies the number of frames received.
CRCErrors | Specifies the number of CRC errors encountered for this VC. CRC errors are caused by the failure of a cyclic redundancy check. A CRC error indicates that one or more bytes in the frame received were found garbled on arrival.
TimeoutErrors | Specifies the number of time-out errors encountered for this VC. Time-out errors occur when an expected byte is not received in time.
AlignmentErrors | Specifies the number of alignment errors encountered for this VC. Alignment errors occur when a byte received is different from the byte expected. This typically happens when a byte is lost or when a time-out error occurs.
SerialOverrunErrors | Specifies the number of serial overruns encountered for this VC. Serial overruns occur when the WAN NIC cannot handle the rate at which data is received.
FramingErrors | Specifies the number of framing errors encountered for this VC. A framing error occurs when an asynchronous byte is received with an invalid start or stop bit.
BufferOverrunErrors | Specifies the number of buffer overruns encountered for this VC. Buffer overruns occur when the CoNDIS WAN miniport driver cannot handle the rate at which data is received.


Setting WAN Miniport Driver State

An upper-layer driver calls either NdisRequest or NdisCoRequest functions with a set request to change information that a particular standard or CoNDIS WAN miniport driver and the miniport driver's NIC maintain. After the NDISWAN driver forwards the set request, NDIS in turn calls the WAN miniport driver's set-request function. The set-request function that NDIS calls depends on whether the WAN miniport driver is a standard or CoNDIS type as described following:

  • For a standard WAN miniport driver, this set-request function is MiniportSetInformation. In a standard WAN miniport driver, this function is the same as in a LAN miniport driver, except that the WAN miniport driver recognizes standard WAN OIDs. For more information about standard WAN OIDs, see Standard WAN Objects.
  • For a CoNDIS WAN miniport driver, this set-request function is MiniportCoRequest. In a CoNDIS WAN miniport driver, this function is the same as in a standard connection-oriented miniport driver, except that the CoNDIS WAN miniport driver recognizes CoNDIS WAN OIDs.

No other requests will be submitted to the WAN miniport driver until the current set request is complete. If the WAN miniport driver does not immediately complete the set request, it must later call a completion function. The WAN miniport driver returns NDIS_STATUS_PENDING from its set-request function to indicate that it has not completed its set request. The completion function that the miniport driver later calls depends on whether the miniport driver is a standard or CoNDIS type as described following:

  • For a standard WAN miniport driver, this completion function is NdisMSetInformationComplete.
  • For a CoNDIS WAN miniport driver, this completion function is NdisCoRequestComplete.

A WAN miniport driver can use all of the NDIS global-set OIDs.

A WAN miniport driver must recognize and respond properly to a WAN set OID. This WAN set OID depends on whether the WAN miniport driver is a standard or CoNDIS type as described in the following list:

  • Standard WAN Set OID

    A standard WAN miniport driver must recognize and respond properly to the following standard WAN OID.

    OID_WAN_SET_LINK_INFO
    The OID_WAN_SET_LINK_INFO OID is used to set a link's characteristics. The structure of this OID is documented in the Network Driver Reference. The information passed to the standard WAN miniport driver is contained in members of a NDIS_WAN_SET_LINK_INFO structure. The members of NDIS_WAN_SET_LINK_INFO are the same as the members of NDIS_WAN_GET_LINK_INFO, which are described in Standard WAN Query OIDs.
  • CoNDIS WAN Set OID

    A CoNDIS WAN miniport driver must recognize and respond properly to the following connection-oriented WAN OID.

    OID_WAN_CO_SET_LINK_INFO
    The OID_WAN_CO_SET_LINK_INFO OID is used to change PPP framing information for a specific VC. The structure of this OID is documented in the Network Driver Reference. The information passed to the CoNDIS WAN miniport driver is contained in members of a NDIS_WAN_CO_SET_LINK_INFO structure. The members of NDIS_WAN_CO_SET_LINK_INFO are the same as the members of NDIS_WAN_CO_GET_LINK_INFO, which are described in CoNDIS WAN Query OIDs.


Sending on a WAN Miniport Driver

An upper-layer driver calls either NdisSend or NdisCoSendPackets functions to send packets to an underlying WAN miniport driver that is either the standard or CoNDIS type. The NDISWAN intermediate driver in turn forwards those packets from the upper-layer driver. Before NDISWAN forwards packets, it repackages them. For a standard WAN miniport driver, NDISWAN also reformats the structure of packets from NDIS_PACKET structures into NDIS_WAN_PACKET structures before forwarding. For a CoNDIS WAN miniport driver, NDISWAN forwards packets as new NDIS_PACKET structures.

After NDISWAN forwards packets, NDIS in turn calls the WAN miniport driver's send function. The send function that NDIS calls depends on whether the WAN miniport driver is a standard or CoNDIS type as described following:

  • For a standard WAN miniport driver, this send function is MiniportWanSend. MiniportWanSend transmits packets through the NIC onto the wide area network.
  • For a CoNDIS WAN miniport driver, this send function is MiniportCoSendPackets. For more information on how a CoNDIS WAN miniport driver sends packets, see Sending Packets on a VC.

Ownership of both the packet descriptor and the packet data is transferred to the WAN miniport driver until the send completes, either synchronously or asynchronously. The WAN miniport driver returns NDIS_STATUS_PENDING from its send function to indicate that it has not finished transmitting the packet. The completion function that the miniport driver later calls depends on whether the miniport driver is a standard or CoNDIS type as described following:

  • For a standard WAN miniport driver, this completion function is NdisMWanSendComplete.
  • For a CoNDIS WAN miniport driver, this completion function is NdisMCoSendComplete.

These completion calls do not necessarily imply that a packet has been transmitted, although, with the exception of intelligent NICs, the packet generally has been transmitted. These calls do however, mean that the WAN miniport driver is ready to release ownership of the packet.

If the WAN miniport driver returns a status other than NDIS_STATUS_PENDING, the send operation is considered to be complete, and ownership of the packet immediately reverts to the caller. In this case, the WAN miniport driver does not call a completion function for that packet.

After packets are received by the WAN miniport driver, it should send the packets out on the active connection. For a standard environment, this connection is an established link. For a CoNDIS environment, this connection is a VC.

Unlike LAN miniport drivers, the WAN miniport driver cannot return a status of NDIS_STATUS_RESOURCES to indicate that it does not have enough resources currently available to process the transmission of packets. Instead, the WAN miniport driver should queue the send internally for a later time and perhaps lower the send-window value on the connection. This send-window value is the number of outstanding packets that the WAN miniport driver can handle per connection. This send-window value is specified by the miniport driver to an upper-layer driver. The way the WAN miniport driver specifies this send-window value depends on whether the WAN miniport driver is a standard or CoNDIS type as described following:

  • The standard WAN miniport driver specifies the default number of outstanding packets that it can have per data channel in the MaxTransmit member of the NDIS_WAN_INFO structure. The miniport driver provides this structure when the miniport driver responds to the OID_WAN_GET_INFO request from the protocol driver. However, the miniport driver can manage the send window dynamically and on a per-line basis by calling NdisMIndicateStatus with a line-up indication. In this call, the miniport driver provides a new nonzero value for the SendWindow member of the NDIS_MAC_LINE_UP structure passed in the call. If the miniport driver sets the value of the SendWindow member to zero, NDISWAN uses the default value in MaxTransmit for that line.
    The standard WAN miniport driver might have to modify or add to the header as well as add to the end (tail) of the packet (for example, to add the FCS). Appropriate padding at the beginning and end of the packet was provided previously by the miniport driver. The WAN miniport driver can alter the data in the packet in any way it sees fit in order to send that packet on the WAN medium.
  • The CoNDIS WAN miniport driver specifies the number of outstanding packets that it can have per VC in the MaxSendWindow member of the NDIS_WAN_CO_INFO structure. The miniport driver provides this structure when the miniport driver responds to the OID_WAN_CO_GET_INFO request from the protocol driver. However, the miniport driver can adjust this number dynamically and on a per-VC basis using the SendWindow member in the WAN_CO_LINKPARAMS structure that the miniport driver can pass to the NdisMCoIndicateStatus function. NDISWAN uses the current SendWindow value as its limit on outstanding sends. The miniport driver can set the value of the SendWindow member to zero to specify that it cannot handle any outstanding packets. That is, if the SendWindow member is set to zero, the send window is shut down and NDISWAN stops sending packets for the particular VC.

It is also an error for the WAN miniport driver to call the NdisMSendResourcesAvailable function.

Packets that are passed to the WAN miniport driver's send function will contain simple HDLC PPP framing if PPP framing is set. For SLIP or RAS framing, packets contain only the data portion with no framing whatsoever. Simple HDLC PPP framing is discussed later in more detail.

A WAN NIC driver must not attempt to provide software loopback or promiscuous-mode loopback. Both of these loopback types are fully supported in the NDISWAN driver.

For a standard WAN miniport driver, the following applies to the WAN packet. For more information about the WAN packet descriptor structure, see NDIS_WAN_PACKET.

  • The MacReserved x members as well as the WanPacketQueue member of the NDIS_WAN_PACKET structure is fully available for use by the standard WAN miniport driver.
  • The available header padding is simply CurrentBuffer-StartBuffer. The available tail padding is EndBuffer-(CurrentBuffer+CurrentLength). The header and tail padding is guaranteed to be at least the amount requested, but it can be more.


WAN Miniport Driver Indications

Standard and CoNDIS WAN miniport drivers each indicate status and received data differently to the NDISWAN driver.

To indicate WAN-specific status:

  • A standard WAN miniport driver calls the NdisMIndicateStatus function just as all LAN miniport drivers do.
  • A CoNDIS WAN miniport driver calls the NdisMCoIndicateStatus function just as all connection-oriented miniport drivers do.

To indicate data that has been received over a wide area network:

  • A standard WAN miniport driver calls the NdisMWanIndicateReceive function instead of the comparable function used by a LAN miniport driver.
  • A CoNDIS WAN miniport driver calls the NdisMCoIndicateReceivePacket function just as all connection-oriented miniport drivers do.

The following topics describe how a standard WAN miniport driver indicates data that has been received over a WAN and describe the WAN-specific types of status that both standard and CoNDIS WAN miniport drivers indicate to the NDISWAN driver.

Indicating Received Data From a Standard WAN Miniport Driver

Indicating WAN Miniport Driver Status


Indicating Received Data From a Standard WAN Miniport Driver

A standard WAN miniport driver calls the NdisMWanIndicateReceive function to indicate that a packet has arrived and that the entire packet is available for inspection. After this call is made, NDISWAN indicates the arrival of the packet to the ProtocolReceive handlers of bound higher-level drivers. The entire packet is available for inspection because the miniport driver does not pass any lookahead data.

Because the entire packet is always passed up, the miniport driver will never receive a transfer-data call (the data is copied by NDISWAN and then passed up to the next higher driver). The entire packet is always passed up because compression and encryption might have been applied to the packet. Also, because the link is point-to-point, at least one bound protocol will always require the packet for processing.

After the NIC receives a packet, the WAN miniport driver physically removes driver-specific encapsulation from that packet only if required. For example, the WAN miniport driver adjusts the PacketBuffer and PacketSize parameters before calling NdisMWanIndicateReceive to remove PPPoE encapsulation. However, the WAN miniport driver should leave encapsulated data, such as PPP header and payload, intact.

A WAN miniport driver calls the NdisMWanIndicateReceiveComplete function to indicate the end of one or more receive indications so that protocols can postprocess received packets. As a result, NDISWAN calls the ProtocolReceiveComplete handlers of bound protocols to notifying each protocol that it can begin to process the received data. In a protocol's receive-complete handler, the protocol need not operate under the severe time constraints that it does in its receive handler.

The protocol should assume that interrupts are enabled during the call to ProtocolReceiveComplete. In an SMP machine, the receive handler and the receive complete handler can be running concurrently on different processors.

Note that a standard WAN miniport driver need not deliver NdisMWanIndicateReceiveComplete indications in one-to-one correspondence with NdisMWanIndicateReceive indications. The miniport driver can issue a single receive-complete indication after several receive indications have occurred. For example, a standard WAN miniport driver could call NdisMWanIndicateReceiveComplete from its receive handler for every ten packets completed or before exiting the handler, whichever occurs first.


Indicating WAN Miniport Driver Status

A WAN miniport driver should keep a WAN-specific set of statistics. A WAN miniport driver indicates status with unique status codes and buffer contents. After changes in the status of a WAN NIC occur, the WAN miniport driver calls a specific indicate-status function to indicate these changes up to bound protocol drivers. The WAN miniport driver generates these status indications. Bound protocol drivers can ignore these indications. However, processing these indications typically results in improved performance for protocols and the miniport driver. The NDISWAN intermediate driver passes status indications to ProtocolStatus functions of bound protocols or to a configuration manager. These protocols or configuration manager can log these indications and possibly take corrective action. The indicate-status function that the WAN miniport driver calls depends on whether the WAN miniport driver is a standard or CoNDIS type as described following:

  • For a standard WAN miniport driver, this indicate-status function is NdisMIndicateStatus. In a standard WAN miniport driver, this function is the same as in a LAN miniport driver, except that the WAN miniport driver indicates a WAN-specific set of statistics.
  • For a CoNDIS WAN miniport driver, this indicate-status function is NdisMCoIndicateStatus. In a CoNDIS WAN miniport driver, this function is the same as in a standard connection-oriented miniport driver, except that the CoNDIS WAN miniport driver indicates a WAN-specific set of statistics for each VC on the miniport driver's NIC. The miniport driver calls NdisMCoIndicateStatus with an explicit VC handle to indicate these changes up to a protocol driver that shares this VC.

Each status indication provides two basic pieces of information:

  • A status code that specifies the general status. There are a limited number of defined general status codes; this list is subject to future expansion.
  • A buffer that contains the status information. This status information can be specific to a NIC, or for a CoNDIS WAN miniport driver, specific to a VC on a NIC. For example, a buffer might contain the new transmit speed of an X.25 connection, which recently decreased by a factor of two. For a standard WAN miniport driver, this buffer might indicate that a new link is becoming active or that an existing link is changing to the idle state.

Status indications that a WAN miniport driver makes depend on whether the WAN miniport driver is a standard or CoNDIS type as described in the following topics:

Standard WAN Miniport Driver Status Indications

CoNDIS WAN Miniport Driver Status Indications

Standard WAN Miniport Driver Status Indications

Status indications for a standard WAN miniport driver use a general status of NDIS_STATUS_WAN_XXX. The three types of status indications are:

  • NDIS_STATUS_WAN_LINE_UP

    A standard WAN miniport driver calls NdisMIndicateStatus to indicate that a new data channel has become active or to indicate that an existing channel's parameters have changed. In this call, the miniport driver passes NDIS_STATUS_WAN_LINE_UP in the GeneralStatus parameter and a pointer to a NDIS_MAC_LINE_UP structure in the StatusBuffer parameter. NDIS_MAC_LINE_UP identifies the data channel for a particular link and describes parameters for the link. Until this status indication occurs, the WAN NIC will accept packets and can let them succeed or fail, but it is unlikely that such packets will actually be received by any remote-node process. Until a data channel becomes active, protocols should reduce their timers and retry counts so that any outgoing connection attempts quickly fail.

    A standard WAN miniport driver must make the initial line-up indication before it returns from an OID_TAPI_GET_ID request. This request uses an NDIS_TAPI_GET_ID structure. The line-up indication is made if NDIS_TAPI_GET_ID contains the NDIS value in the DeviceClass member and LINECALLSELECT_CALL in the ulSelect member. Before the OID_TAPI_GET_ID request completes, the miniport driver sets the value of the DeviceID member of NDIS_TAPI_GET_ID to the value of the NdisLinkContext member of NDIS_MAC_LINE_UP that was returned from the line up indication For more information on making a line-up indication, see Line-Up Indication.

  • NDIS_STATUS_WAN_LINE_DOWN

    A standard WAN miniport driver calls NdisMIndicateStatus whenever a link goes down. In this call, the miniport driver passes NDIS_STATUS_WAN_LINE_DOWN in the GeneralStatus parameter, and a pointer to a NDIS_MAC_LINE_DOWN structure in the StatusBuffer parameter. The NdisLinkContext member of NDIS_MAC_LINE_DOWN identifies the link that is no longer valid.

    After this status indication occurs, bound protocols should reduce their timers and retry counts until the next line-up indication.

  • NDIS_STATUS_WAN_FRAGMENT

    A standard WAN miniport driver calls NdisMIndicateStatus whenever it receives a partial packet from a remote peer. In this call, the miniport driver passes NDIS_STATUS_WAN_FRAGMENT in the GeneralStatus parameter and a pointer to a NDIS_MAC_FRAGMENT structure in the StatusBuffer parameter. NDIS_MAC_FRAGMENT identifies a particular link and describes the reason that the partial packet was received.

    If the miniport driver does not make a fragment indication when it receives a partial packet from a remote peer, NDISWAN will be unaware of the particular error. After a fragment indication occurs, the protocol should send frames to the remote peer to notify the remote peer of the fragment indication, rather than waiting for a time-out to occur.
    NDISWAN monitors dropped packets by counting the number of fragment indications on the link.

A standard WAN miniport driver can also indicate TAPI status. The miniport driver calls NdisMIndicateStatus to indicate TAPI status. In this call, the miniport driver passes NDIS_STATUS_TAPI_INDICATION in the GeneralStatus parameter and a pointer to a NDIS_TAPI_EVENT structure in the StatusBuffer parameter. NDIS_TAPI_EVENT describes the TAPI line or call event that occurs. The general type of TAPI-status indications of interest to miniport driver developers are changes in line states, changes in call states, the arrival of an incoming call, and the closing by a remote node or by the miniport driver of an existing call or line. For more information, see Extensions to Support Telephonic Services Over Standard NDIS.

CoNDIS WAN Miniport Driver Status Indications

VC status indications for a CoNDIS WAN miniport driver use a general status of NDIS_STATUS_WAN_CO_XXX. The two types of VC status indications are:

  • NDIS_STATUS_WAN_CO_LINKPARAMS

    A CoNDIS WAN miniport driver calls NdisMCoIndicateStatus to indicate that parameters for a particular VC that is active on the NIC have changed. In this call, the miniport driver passes the handle to the VC in the NdisVcHandle parameter, NDIS_STATUS_WAN_CO_LINKPARAMS in the GeneralStatus parameter, and a pointer to a WAN_CO_LINKPARAMS structure in the StatusBuffer parameter. WAN_CO_LINKPARAMS describes new parameters for the VC.

  • NDIS_STATUS_WAN_CO_FRAGMENT
    A CoNDIS WAN miniport driver calls NdisMCoIndicateStatus to indicate that it has received a partial packet from the endpoint of a VC. In this call, the miniport driver passes the handle to the VC in the NdisVcHandle parameter, NDIS_STATUS_WAN_CO_FRAGMENT in the GeneralStatus parameter, and a pointer to a NDIS_WAN_CO_FRAGMENT structure in the StatusBuffer parameter. NDIS_WAN_CO_FRAGMENT describes the reason that the partial packet was received.

    After this indication occurs, a connection-oriented client should send frames to the connection-oriented client at the other end of the VC. These frames will notify the opposite endpoint of the partial-packet situation, rather than waiting for a time-out to occur.

    NDISWAN monitors dropped packets by counting the number of fragment indications on each VC.


WAN Packet Framing

This section provides information about WAN packet framing. This information is described in the following topics:

Asynchronous Framing

X.25 Framing

ISDN and Switched-56K Framing


Asynchronous Framing

Asynchronous Framing with Compression Turned Off

The DDK provides a sample asynchronous miniport driver that supports SLIP and RAS compression.


X.25 Framing

X.25 Framing with Protocol Field Compression On or Off

Address and Control Field Compression should not be enabled for X.25. If Protocol Field Compression is turned ON, the NLPID should be removed. It is the responsibility of the X.25 driver or hardware to provide for transparency, add any padding, add any FCS, and add any end flag.


ISDN and Switched 56K Framing

Initially, ISDN B channels (not D channels) should be used. Multiple B channel support is done through NDISWAN's multilink support. Initially, bit-synchronous HDLC framing with NRZ encoding should be used. Transparency should be provided by the driver or ISDN hardware. It is also the responsibility of the ISDN driver or hardware to provide for NRZ encoding, to calculate the FCS to add the PPP end flag (0x7E), and to insert any inter-frame time fill. Switched 56K drivers should frame in the same manner as ISDN.


Extensions to Support Telephonic Services Over Standard NDIS

This section describes how standard WAN miniport drivers implement Telephonic services using the functions available through the NDISTAPI driver and NDISWAN driver. The NDISTAPI driver communicates with telephony applications through a telephony service provider. For more information, see the Telephony Application Programming Interface (TAPI) the in the Platform SDK.

The following topics describe the NDISTAPI driver more fully and details for implementing telephonic services in standard WAN miniport drivers:

NDISTAPI Overview

Line Devices, Addresses, and Calls

TAPI Set and Query Requests

Maintaining State Information

Setting Up Handles

TAPI Registration

TAPI Initialization

Line Open

Accepting an Incoming Call

Making a TAPI Call

Unsolicited Event Handling

Line Up Indication

Call Line Shutdown

NDISTAPI Interface


NDISTAPI Overview

The NDISTAPI driver defines how standard WAN miniport drivers implement telephonic services. It is closely related to the Service Provider Interface established in Windows Telephony, with telephony-capable NDIS miniport drivers providing kernel-mode support for user-mode TAPI service providers. This section presents an overview of how a TAPI-capable standard WAN miniport driver initializes, brings up lines, sets up calls and closes calls using TAPI and WAN OIDs. This description touches briefly on the concepts embodied in Windows Telephony, but the reader should consult the documentation published with the Telephony SDK for an in-depth discussion.

A TAPI-capable standard WAN miniport driver registers and initializes itself as a user of both WAN and TAPI services. When registration and initialization are complete, a user-level application can make telephonic requests to the user-mode KMDDSP service provider module which converts SPI requests to corresponding OIDs. The KMDDSP module passes the OIDs to the NDISTAPI driver, the kernel-mode component of TAPI. NDISTAPI routes the OIDs to the correct NIC driver in order to set up, monitor, and tear down lines, and calls. NDISTAPI passes the OIDs in NdisRequest calls to the NDISWAN intermediate driver. NDISWAN passes these NDIS requests on, resulting in a call to the MiniportQueryInformation function or the MiniportSetInformation function of a TAPI-capable standard WAN miniport driver.

A TAPI-capable standard WAN miniport driver communicates changes in the states of lines and calls, for example, a change from the proceeding state to the connected state, the arrival of an incoming call, or a remote disconnection. State changes are communicated to upper-layers by passing appropriate NDIS_STATUS_TAPI_XXX and NDIS_STATUS_WAN_XXX status messages to NdisMIndicateStatus.

To view the relationship among the components described in this section, see RAS Architecture. The kernel-mode flow of communication is from NDISTAPI to NDISWAN, through NDIS to a TAPI-capable standard WAN miniport driver.


Line Devices Addresses and Calls

Previous Next

Line Devices, Addresses, and Calls

A TAPI-capable standard WAN miniport driver models lines, addresses, and calls. A line device is an abstraction of a physical device having one or more communications channels (used for signaling and/or information). Modeling of the line devices is left to the discretion of the WAN miniport driver developer. For example, consider a BRI-ISDN line with two 64K "B" channels. A standard WAN miniport driver could choose to model this as any one of the following:

  • One line device with two channels
  • Two line devices, each with its own channel
  • Two line devices that each support one or two channels, selecting from a common pool
  • Two single-channel line devices and one two-channel line device

In the latter two models, channels can be assigned to different line devices at different times.

Each line device is assigned one or more addresses. An address corresponds to a telephone directory number. An address ID is a number between zero and the number of addresses on the line minus one.

From the TAPI client's point of view, the number of line devices and the number of corresponding addresses remains constant between the time the client calls lineInitialize (to initialize a TAPI client session) and the time it calls lineShutdown (to end a TAPI client session). However, the status of line devices and addresses will commonly change over the life of the client's telephony session. For example, a line device might be taken out of service for some reason, and become available later. Several requests and notification messages are available to allow client applications to track line and address status and capabilities.

A call represents a connection between two or more addresses. Unlike line devices and addresses, calls are dynamic in that they can be created and destroyed. As with lines and addresses, there are both requests and notification messages defined to allow client applications to follow call state and information changes.


Set and Query Requests

TAPI requests are passed to the standard WAN miniport driver as OID_TAPI_XXX requests with an associated structure that describes the action to be taken. The NdisRequestQueryInformation request type is specified in a call to NdisRequest when the miniport driver should pass information back to the caller. The NdisRequestSetInformation request type is specified for requests that do not return any information other than completion status. An NdisRequest call from NDISWAN is routed by the NDIS Library to the target miniport driver's MiniportQueryInformation function or MiniportSetInformation function.

All requests sent to a standard WAN miniport driver by the NDISTAPI driver can be completed either synchronously or asynchronously. If a NIC driver determines that it cannot complete the request immediately, then it can simply return NDIS_STATUS_PENDING and call NdisMQueryInformationComplete or NdisMSetInformationComplete when it has completed the request.


Maintaining State Information

A standard WAN miniport driver must track changes in the state of the links it manages such as the current call, address, and line state, and report any changes to NDISWAN by calling NdisMIndicateStatus.

A miniport driver must always send a call state-change message whenever the state of a call changes. The reported call states have the form LINECALLSTATE_XXX and LINECALLINFOSTATE_XXX. There is no filtering of call state messages.

Some typical call states a miniport driver reports include LINECALLSTATE_IDLE, LINECALLSTATE_CONNECTED, LINECALLSTATE_OFFERING, LINECALLSTATE_DISCONNECTED, LINECALLINFOSTATE_CALLERID and LINECALLINFOSTATE_MEDIAMODE.

Changes in the line state or the address state are only indicated if enabled by a previous OID_TAPI_SET_STATUS_MESSAGES request(s) to the miniport driver.

Address state changes that a miniport driver can be enabled to report have the form LINEADDRESSSTATE_XXX and include such states as LINEADDRESSSTATE_INUSEMANY and LINEADDRESSSTATE_FORWARD.

Line state changes that a miniport driver can be enabled to report have the form LINEDEVSTATE_XXX and include such states as LINEDEVSTATE_RINGING, LINEDEVSTATE_CONNECTED, LINEDEVSTATE_OPEN and LINEDEVSTATE_CLOSE.

A standard WAN NIC miniport driver can receive one or more OID_TAPI_SET_STATUS_MESSAGES request(s) to inform the miniport driver of which status changes it must report. Initially, a miniport driver should consider all line and address status indications disabled with the exception of LINEDEVSTATE_REINIT, which is never disabled.

When a standard WAN miniport driver calls NdisMIndicateStatus to report such state changes, the GeneralStatus argument for reporting TAPI status changes is always NDIS_STATUS_TAPI_INDICATION. The StatusBuffer parameter points to a structure of type NDIS_TAPI_EVENT. The miniport driver must pass the htLine and htCall members that identify the line and call to which the state change applies. The ulMsg member of the NDIS_TAPI_EVENT structure is set to, for example, LINE_CALLSTATE and ulParam1 describes the state being reported.


Setting Up Handles

After the NDISTAPI driver has initialized a standard WAN miniport driver as a provider, the miniport driver can expect a request to open a line device at its MiniportQueryInformation function specifying OID_TAPI_OPEN and the appropriate parameters. Upon receiving an open request the miniport driver would typically do the following:

  • Mark the line device as open in the miniport driver's internal data structures.
  • Save the NDISTAPI driver's handle to the line device (passed in the htLine member), which is to be used in subsequent event notifications.
  • Return its own handle to the line device (passed back in the hdLine member).

Once again, the impetus for this request would be a client process calling lineOpen.

After a client process has successfully opened a line, it can place a call on that line by calling lineMakeCall. This will result in the NDISTAPI driver's calling NdisRequest with an OID_TAPI_MAKE_CALL, specifying the NDISTAPI-supplied handle to the line in the htLine member, and the NDISTAPI-supplied handle to the call in the htCall member. This request is passed to the miniport driver's MiniportQueryInformation function, specifying OID_LINE_MAKE_CALL. If the NIC driver can successfully create the call, it passes back its own handle to the call in the hdCall member.

The two-stage ht Xxx/hd Xxx ("handle of TAPI object Xxx/handle of Driver object Xxx") handle scheme provides both the NDISTAPI driver and the standard WAN miniport driver the flexibility of defining their own means of reference for the same logical object. Requests made to NIC drivers specify driver handles (hdLines and hdCalls), while notifications made to the NDISTAPI driver contain TAPI handles (htLines and htCalls). In the already mentioned cases where the miniport driver is defining its driver handle to some object (for example, hdLine, hdCall), it is typically to the advantage of the NIC driver to specify a pointer to the appropriate driver-internal data structure that represents the object.

When the client process has finished with the call it will call lineDrop to drop the call, and then lineDeallocateCall to free the call instance. This will result in the NDISTAPI driver sending two more requests, OID_TAPI_DROP and OID_TAPI_CLOSE_CALL, respectively, through NDISWAN to the standard WAN miniport driver to drop the call and deallocate the call instance. It is also possible that the miniport driver will get an OID_TAPI_CLOSE_CALL request without a preceding OID_TAPI_DROP, in which case the miniport driver should drop the call and deallocate the call instance as if it had received both OIDs.

Finally, when the last TAPI client has called lineClose, the NDISTAPI driver will call NdisRequest to send the miniport driver an OID_TAPI_CLOSE request at its MiniportSetInformation function. An OID_TAPI_CLOSE can also be received on an active line. In this case, the miniport driver must complete or abort all outstanding calls and asynchronous requests on the device and close the line. An OID_TAPI_CLOSE request with a valid hdLine cannot be failed.


TAPI Registration

A standard WAN miniport driver sets itself to accept TAPI commands in two steps. When the miniport driver registers with NDIS in its DriverEntry function by calling NdisMRegisterMiniport, it indicates that it requires WAN services by setting the flag NDIS_USE_WAN_WRAPPER in the Reserved member of the NDISXX_MINIPORT_CHARCTERISTICS structure.

Following execution of the DriverEntry function and after MiniportInitialize has been called to complete the initialization of one or more adapters, the NDISWAN driver will make an NdisRequest call to the standard WAN miniport driver's MiniportQueryInformation function, with an OID_WAN_GET_INFO request. A miniport driver that is TAPI-capable should set the TAPI_PROVIDER bit of the FramingBits member of the NDIS_WAN_INFO structure passed in this call.

The TAPI-capable standard WAN miniport driver sets the MaxTransmit member of the NDIS_WAN_INFO structure to the default maximum number of outstanding send packets the miniport driver will accept. NDIS will hold send packets after this maximum is reached. However, a TAPI-capable miniport driver can dynamically provide a new send window that is different from this initialization-time default value. When the miniport driver indicates a line up status to NdisMIndicateStatus, it can provide a new nonzero value for that line by setting the SendWindow passed in the NDIS_MAC_LINE_UP structure. If the miniport driver passes a SendWindow of zero, NDISWAN uses the default value, MaxTransmit, that was set at initialization time for that line.

As the WAN driver's MiniportInitialize is called to initialize each adapter it manages, NDISWAN calls NDISTAPI to register each TAPI-capable adapter. This creates an association that NDISTAPI can use to send telephonic requests through NDISWAN to the miniport driver for specific adapters that have been registered.


TAPI Initialization

After a standard WAN miniport driver has registered, been initialized and indicated that it is a TAPI provider, MiniportQueryInformation is called with an OID_TAPI_PROVIDER_INITIALIZE request. There is a one-to-one relationship between a provider and a TAPI-capable adapter. The NDIS_TAPI_PROVIDER_INITIALIZE structure passed in the call contains a ulDeviceIDBase representing an offset. The miniport driver should add this offset to its zero-based line device identifiers when it refers to a device in subsequent OID responses. If the miniport driver manages two devices and it is passed a ulDeviceIDBase of n, those devices will be referenced in future calls as n and n+1, for example, in the ulDeviceID member passed to the miniport driver in the structure for an OID_TAPI_OPEN.

The standard WAN miniport driver should fill in two members of the OID structure before returning from MiniportQueryInformation. The ulNumLineDevs is set to the number of line devices supported by the adapter. The NIC driver should also set the ulProviderID member to a unique (per adapter) value. Since there is currently no means to guarantee unique ulProviderID values, a good strategy is to pass the NDIS handle passed to MiniportInitialize as the ulProviderID. The ulRequestID member of the structure is reserved for NDISTAPI and is opaque to the miniport driver.

The OID_TAPI_PROVIDER_INITIALIZE request sent to registered standard WAN miniport drivers is always the result of a higher-level telephony module being loaded and initialized by the first client process. A miniport driver will only receive the OID_TAPI_PROVIDER_INITIALIZE request once per adapter when the first client process on the machine makes a lineInitialize request.

Communicating Device Characteristics

After the standard WAN miniport driver has returned the number of devices it supports, its MiniportQueryInformation function will be called to return the capabilities of its devices with an OID_TAPI_GET_DEV_CAPS and to return its device configuration with an OID_TAPI_GET_DEV_CONFIG. This information describes how the WAN miniport driver models its device. For example, the same ISDN adapter can be modeled as:

  • 1 line, with 1 address, supporting 2 calls per address
  • 1 line, with 2 addresses on this line, supporting one call per address
  • 2 lines, each with 1 address, supporting 1 call per address

A miniport driver will be queried for its characteristics using these already mentioned OIDs, once for each device that it indicated in its response to OID_TAPI_PROVIDER_INITIALIZE.


Line Open

A line is opened as a result of an application making a lineOpen request. The request is passed to the standard WAN miniport driver by TAPI to NDISTAPI to NDISWAN through NDIS as an OID_TAPI_OPEN request. This request passes the NDIS_TAPI_OPEN structure specifying a device identifier, ulDeviceID, the device on which the line is to be opened. In addition, the structure contains htLine, a handle by which NDISTAPI refers internally to the line. The miniport driver must retain this line handle and return it in any status indications or responses to queries for that line, for example, when it reports a state change using NdisMIndicateStatus.

The standard WAN miniport driver creates a structure to represent the line in which to keep its line-specific context. The miniport driver should return a value representing this context in the hdLine member of NDIS_TAPI_OPEN before returning from MiniportQueryInformation. The line-specific value in hdLine will be passed to the miniport driver in subsequent calls concerning this line, in the OIDs passed to MiniportQueryInformation and MiniportSetInformation requests, for example, in an OID_TAPI_MAKE_CALL.

Setting Modes On a Line

If an application makes a lineOpen request with owner privilege, the application indicates it wants to receive incoming calls. The application must specify the valid types of incoming calls it will accept on that line. For example, an application could request to receive such types as g3fax, interactive voice, datamodem, and so forth. MiniportSetInformation can be called one or more times with the OID_SET_DEFAULT_MEDIA_DETECTION request to set up the types the miniport driver should accept on behalf of a client.

If more than one application sets the media types, and one application's list is different from another application's list, the miniport driver will be called to set the media-detection types to the union of those requested by the two applications. If an incoming call appears with a media mode type not specified in the preceding successfully completed SET_DEFAULT_MEDIA_DETECTION request for that line, the miniport driver should not indicate the new call to TAPI. If a miniport driver does not receive a SET_DEFAULT_MEDIA_DETECTION request for a line, it should not indicate any incoming calls; that line is to be used only for outbound calls.

A standard WAN miniport driver receives the OID_TAPI_CONDITIONAL_MEDIA_DETECTION request to determine whether it supports the indication of new incoming calls of a specified media mode type or types, without actually committing the miniport driver. If the miniport driver can monitor for the indicated set of media modes and can support the capabilities indicated in LineCallParams and can place a call of the specified type, it returns NDIS_STATUS_SUCCESS. If so, the miniport driver will most likely receive subsequent requests such as OID_TAPI_OPEN, OID_SET_DEFAULT_MEDIA_DETECTION, and so forth.


Accepting an Incoming Call

After a standard WAN miniport driver has successfully completed an OID_TAPI_PROVIDER_INITIALIZE request, an OID_TAPI_OPEN request, and an OID_TAPI_SET_DEFAULT_MEDIA_DETECTION, it can receive an incoming call on the previously opened line. If the media type matches one it has been set to detect, the miniport driver should call NdisMIndicateStatus to notify upper layers of the offered call, passing NDIS_STATUS_TAPI_INDICATION as the GeneralStatus, and a pointer to the NDIS_TAPI_EVENT structure as the StatusBuffer.

The ulMsg member of NDIS_TAPI_EVENT is set to LINE_NEWCALL, and the ulParam1 is set to hdCall, the driver-assigned handle for the call. The htCall, ulParam2, and ulParam3 are set to zero. NDISTAPI will supply an htCall in ulParam2 before returning from NdisMIndicateStatus. The miniport driver should retain this handle and use it in any subsequent indications pertaining to this call instance. For example, the miniport driver will supply this value as the ConnectionWrapperID when it indicates a line up to NDISWAN.

After the miniport driver has given a LINE_NEWCALL status indication, it should call NdisMIndicateStatus, with a LINECALLSTATE_XXX message, typically a LINECALLSTATE_OFFERING message. The ulParam3 of this message is set with the media mode of the incoming call.

If the call is accepted by an application, MiniportSetInformation will be called with an OID_TAPI_ACCEPT followed by an OID_TAPI_ANSWER request or simply with an OID_TAPI_ANSWER request.

If the miniport driver receives an OID_TAPI_ACCEPT request, it should allocate and initialize a call-state context for the call, but it should not answer the call until it receives an answer request. Later, if it receives an OID_TAPI_ANSWER request, it should do the following:

  • Answer the call.
  • Set the state of the line to connected and call NdisMIndicateStatus to report this new status if reporting of this status is enabled.

If the miniport driver receives an OID_TAPI_ANSWER request without first receiving an OID_TAPI_ACCEPT request, it should behave as if it had received both requests.

It is possible that a WAN NIC driver will never receive an OID_TAPI_ANSWER request or an OID_TAPI_ACCEPT request for an incoming call. This could occur when client applications are busy with other calls, or when clients are not interested in calls of the type indicated (for example, the media mode), and so forth. After waiting a certain amount of time for an answer or accept request or detecting that the remote party disconnected, the WAN NIC driver should notify the NDISTAPI driver that the call has transitioned to the idle state. Then, at some later time, an OID_TAPI_CLOSE_CALL request will be sent to the WAN NIC driver to free up the call instance. It is also possible that after the miniport driver offers the incoming call, it will receive an OID_TAPI_CLOSE_CALL before it can time out the new call offer.


Making a TAPI Call

A standard WAN miniport driver with an open line can also receive a request to initiate a call in one of two ways. Either the miniport driver receives:

  • An OID_TAPI_MAKE_CALL request that contains the destination address or that specifies that a predefined default number should be used
  • Or, an OID_TAPI_MAKE_CALL request that does not include a destination address

    In this case, the OID_TAPI_MAKE_CALL will be followed by an OID_TAPI_DIAL request that includes the destination address

When MiniportQueryInformation is called with an OID_TAPI_MAKE_CALL request, NDISTAPI passes the line identifier for the line on which the call is to be made in the hdLine member of the NDIS_TAPI_MAKE_CALL structure. The hdLine value is the value returned by the miniport driver to an OID_TAPI_OPEN request.

The miniport driver should store the htCall value passed in this request with the call context it maintains and pass it in subsequent status calls and responses related to this call instance. For example, the miniport driver will supply this value as the ConnectionWrapperID when it indicates a line up to NDISWAN.

The ulDestAddressSize can be zero for undialed addresses, such as for a hot phone, which always automatically connects to a predefined number, or when dialing will be done subsequently with an OID_TAPI_DIAL request.

If the bUseDefaultLineCallParams member of NDIS_TAPI_MAKE_CALL is set to FALSE, the miniport driver should use the call parameters in the LineCallParams member. If bUseDefaultLineCallParams is TRUE, the previously set default call parameters should be used.

The miniport driver must check the state of the line on which the make-call request is made to ensure that it can make the requested call. If not, the miniport driver should fail the call.

MiniportQueryInformation returns when either:

  • It has made the call,
  • Or, if the number will be dialed as a result of a subsequent OID_TAPI_DIAL request, the miniport driver allocates a structure and sets itself in a state, probably the dialtone state, to subsequently complete the call.

The miniport driver must return a call-specific context value in the hdCall member if MiniportQueryInformation returns NDIS_STATUS_SUCCESS. This unique hdCall value will be passed to the miniport driver in subsequent requests related to this call.

If a call is made in two steps by first making an OID_TAPI_MAKE_CALL request to MiniportQueryInformation, followed by an OID_TAPI_DIAL request to MiniportSetInformation, the destination number is passed to the miniport driver in the NDIS_TAPI_DIAL structure. The OID_TAPI_DIAL request requires an hdCall member to be passed in the NDIS_TAPI_DIAL structure; its value will match the handle the miniport driver returned from a previous OID_TAPI_MAKE_CALL request.


Unsolicited Event Handling

During the course of a telephonic session, the standard WAN miniport driver will most likely need to notify the NDISTAPI driver of unsolicited events. Typical examples of unsolicited events are an incoming call on an open line, a state transition on an existing call (for example, from ringing to connected), or a change in line-device status (from in-service to out-of-service or vice versa).

The NDIS_STATUS_TAPI_INDICATION status is used when reporting spontaneously occurring events on the line or on a call on the line to the NDISTAPI driver. The miniport driver calls NdisMIndicateStatus, specifying a GeneralStatus of NDIS_STATUS_TAPI_INDICATION and a StatusBuffer parameter which points to an initialized structure of type NDIS_TAPI_EVENT.

This structure contains the following members:

Structure Member | Meaning
htLine | Specifies the NDISTAPI driver's handle for the line on which the event occurred.
htCall | For line-related events where there is no call, this parameter should be zero; otherwise, it is the NDISTAPI driver's handle for the call related to the reported event.
ulMsg | Specifies the event type, of the form LINE_XXX.
ulParam1 | An event-specific parameter, for example, a pointer to a structure that describes the specific event.
ulParam2 | Same as above.
ulParam3 | Same as above.

The notification messages of concern to standard WAN miniport driver developers are the following:

  • LINE_ADDRESSSTATE
  • LINE_CALLINFO
  • LINE_CALLSTATE
  • LINE_CLOSE
  • LINE_DEVSPECIFIC
  • LINE_LINEDEVSTATE
  • LINE_NEWCALL
  • LINE_CALLDEVSPECIFIC


Line-Up Indication

From the telephony standpoint, the life of a call is a series of state transitions. For outgoing calls, a typical sequence of states might be: dialing, proceeding, ringing, connected, disconnected, and finally, idle. For an incoming call, this sequence might look as follows: offering, ringing, connected, disconnected, and finally, idle. In either case, the transition to the connected state is of particular interest, since this is the state in which data can flow across the wire.

A standard WAN miniport driver calls NdisMIndicateStatus with a GeneralStatus value of NDIS_STATUS_WAN_LINE_UP to indicate that a new data channel has become active. The buffer at StatusBuffer is formatted as an NDIS_MAC_LINE_UP structure. Prior to indicating a line up, the adapter will accept frames and can let them succeed or fail, but it is unlikely that such packets will actually be received by any remote system. Before a line-up indication, protocols are encouraged to reduce their timers and retry counts so that any outgoing connection attempts quickly fail.

An NDIS_STATUS_WAN_LINE_UP status must be completed prior to returning from the OID_TAPI_GET_ID request. The NdisLinkContext returned from the NDIS_STATUS_WAN_LINE_UP indication is passed back in the NDIS_TAPI_GET_ID structure as the DeviceID.

The NDIS_STATUS_WAN_LINE_UP must also be completed prior to indicating the LINECALLSTATE_CONNECTED to NDISWAN. Otherwise, the user-mode client of the connection might attempt to send data on a connection before NDISWAN is aware of the line.

When the line-up indication completes, NDISWAN and the miniport driver have exchanged handles, one that NDISWAN uses to subsequently direct send packets onto a data channel and the other that the miniport driver uses to identify the correct data channel for sends and in any status indications it makes to NDISWAN. Before NDISWAN gets a line-up indication and establishes a data channel for a particular call instance, it will not pass send packets on to the miniport driver's MiniportWanSend function.

A miniport driver indicates a line-up status in the context of an OID_TAPI_GET_ID request if either of the following occurs:

  • The ulSelect member of NDIS_TAPI_GET_ID structure is set to LINECALLSELECT_CALL, and
  • This request is the first OID_TAPI_GET_ID request for the hdCall member of the NDIS_TAPI_GET_ID structure

or

  • The ulSelect member of NDIS_TAPI_GET_ID structure is set to LINECALLSELECT_CALL, and
  • This request is not the first OID_TAPI_GET_ID request for the hdCall member of the NDIS_TAPI_GET_ID structure, but the DeviceClass is different from any previous get-id request for this call instance, and
  • The miniport driver supports separate data channels for different device classes.

The StatusBuffer passed to NdisMIndicateStatus should point to a buffer of type NDIS_MAC_LINE_UP. This structure has the following definition:

typedef struct _NDIS_MAC_LINE_UP {
  IN ULONG  LinkSpeed;
  IN NDIS_WAN_QUALITY  Quality;
  IN USHORT  SendWindow;
  IN NDIS_HANDLE  ConnectionWrapperID;
  IN NDIS_HANDLE  NdisLinkHandle;
  IN OUT NDIS_HANDLE  NdisLinkContext;
} NDIS_MAC_LINE_UP, *PNDIS_MAC_LINE_UP;

The standard WAN miniport driver should set the value of the ConnectionWrapperID member in the NDIS_MAC_LINE_UP structure to that of the htCall (the TAPI call handle) associated with the call because it is guaranteed to be unique across all telephony-capable miniport drivers. The ConnectionWrapperID is valid until the miniport driver issues a line-down indication.

The NdisLinkHandle represents the miniport driver's handle for this data channel on this call instance. Typically it references the state the miniport driver maintains for this call. NDISWAN will retain this handle and return it to the miniport driver on any sends on this data channel. The NdisLinkContext is set to NULL when the miniport driver calls NdisMIndicateStatus. It will be set to a value supplied by NDISWAN before returning from NdisMIndicateStatus. This opaque handle must be retained by the miniport driver and supplied in subsequent calls to NDISWAN regarding this link, for example, to NdisMWanIndicateReceive.

The NdisLinkContext must be returned in the DeviceID member of NDIS_TAPI_GET_ID when MiniportQueryInformation returns from the OID_TAPI_GET_ID request. This context binds the call connection and the device class as seen by NDISTAPI with a handle that NDISWAN recognizes and has tied to a particular data channel. NDISWAN uses this handle to ensure that packets from a TAPI client are directed by NDISWAN to the correct miniport driver data channel.

Changing the Send Window

The SendWindow member of the NDIS_MAC_LINE_UP structure specified in a line-up indication acts as a throttle, controlling how many packets NDISWAN passes to a MiniportWanSend function for a particular line before it starts queuing packets. The MaxTransmit member of NDIS_WAN_INFO returned in response to the OID_WAN_GET_INFO request during driver initialization represents a default value for this window for all lines supported by an adapter. The miniport driver can reset the send window value on a per-line basis when it makes the first line-up indication for a new line. It can also change this send window value for a line dynamically by making a subsequent line-up indication to NDISWAN with a new nonzero SendWindow. That is, the miniport driver does not have to wait for an incoming or outgoing call to generate a line-up indication. If a miniport driver specifies a SendWindow of zero, NDISWAN will revert to using the default MaxTransmit value as the send window.

If the miniport driver makes a line-up indication to change the SendWindow, it must fill in both the NdisLinkHandle and NdisLinkContext members with the values that apply to the data channel on which the send window is to be changed. LinkSpeed and Quality are set to zero or possibly to new values. Both LinkSpeed and Quality can also be changed dynamically and independently by making a line-up indication and resetting the value(s).


Call Line Shutdown

A session begins when a standard WAN miniport driver successfully completes an OID_TAPI_PROVIDER_INITIALIZE request. Within a session, one or more lines can be opened with an OID_TAPI_OPEN request, and on a line, one or more calls can be established by OID_TAPI_MAKE_CALL, OID_TAPI_DIAL, or OID_TAPI_ANSWER requests. During the time a line is up, many calls can be established and then closed or dropped. During a session, one or more lines can go through transitions from open to closed many times. How a miniport driver handles such transitions is described here.

Closing a Call

An in-process call can be closed either by the local node or by the remote node. The call can be closed on the local node, either because the last application with a handle to the call has closed the handle, or perhaps because the miniport driver's MiniportHalt or MiniportReset has been called. If the remote node hangs up an in-process call, the miniport driver must indicate this status change to upper layers.

If an application on the local node closes the call, MiniportSetInformation will be called either with an OID_TAPI_DROP request followed by an OID_TAPI_CLOSE_CALL, or it will simply be called with an OID_TAPI_CLOSE_CALL.

If the miniport driver receives an OID_TAPI_DROP request, the driver must:

  1. Drop the call.
  2. Change the status of the call to LINECALLSTATE_IDLE
  3. Report the state change by calling NdisMIndicateStatus.

The handles for the dropped call, htCall and hdCall remain valid. The miniport driver must not deallocate, reuse, or otherwise modify the state associated with the hdCall that it created for the call instance, since the miniport driver can receive queries related to the call, for example, a request for statistics related to the call. If MiniportHalt or MiniportReset is called, the miniport driver should disconnect the call but retain the state maintained for the call instance until the miniport driver receives an OID_TAPI_CLOSE_CALL request.

MiniportSetInformation can also receive an OID_TAPI_CLOSE_CALL request when the last application with an open handle to the call instance closes the handle. The miniport driver cannot fail this close call request. After MiniportSetInformation returns after processing this request, htCall is no longer valid.

A miniport driver must be prepared to handle timing issues involving such occurrences as getting an OID_TAPI_CLOSE_CALL before getting an OID_TAPI_DROP. If the miniport driver gets an OID_TAPI_CLOSE_CALL without a preceding OID_TAPI_DROP, it should behave as if it had received both a drop and a close call request. If the miniport driver receives a drop after a close call request has already closed the referenced call, the call handle is no longer valid and the miniport driver should return an appropriate error message.

If the miniport driver detects that the remote node has dropped the call, the miniport driver should change the call state to LINECALLSTATE_DISCONNECTED and indicate the change by calling NdisMIndicateStatus passing the htCall for this call instance. After the state change is propagated to the connected application on the local node, the miniport driver will receive an OID_TAPI_DROP followed by an OID_TAPI_CLOSE_CALL, or perhaps just the OID_TAPI_CLOSE_CALL request. The miniport driver should handle the drop and close call requests as described earlier.

Closing a Line

A line is closed when the last application with an open handle to the line has closed the handle. When the miniport driver subsequently receives an OID_TAPI_CLOSE, it should tear down the line instance, that is, any state related to the line maintained by the miniport driver can be reused or deallocated because the information is no longer valid.

An OID_TAPI_CLOSE call must succeed if the line handle, htLine, passed in the call exists and is still valid. A miniport driver will never receive an OID_TAPI_CLOSE request for a line if there are calls on the line. All existing calls on a line will be closed with an OID_TAPI_CLOSE_CALL request before the line-close request is made.

Existing calls must be closed when a line is closed; the miniport driver should drop those calls and clean up their state. The miniport driver should also change the state of the line to idle. Any handle that the miniport driver has for the line is no longer valid. If the miniport driver receives any requests which pass the htLine handle or any htCall after the close request is received, such request(s) must be failed with an appropriate status.

Closing a Session

Session termination can be initiated by either the upper layers or a WAN miniport driver. When the last client process has detached from the higher-level Telephony module, the NDISTAPI driver will be informed that it needs to terminate its session with each of the registered adapters. The NDISTAPI driver does this by calling NdisRequest specifying OID_TAPI_PROVIDER_SHUTDOWN. Upon receiving this request, NDISWAN will call the miniport driver's MiniportSetInformation function, which should terminate any related activities it has in progress on the specified adapter and release any relevant resources.

Driver-initiated session termination can occur when the miniport driver is being unloaded in its MiniportHalt function. Typically, the miniport driver would complete any outstanding NDISTAPI driver requests and notify the NDISWAN that its line devices are going off-line by calling NdisMIndicateStatus. NDISWAN would, in turn, call the NDISTAPI driver to deregister the adapter. If the miniport driver were reloaded again later, it would go through the same initialization process described previously.

The standard WAN miniport driver might also initiate session termination if it underwent some dynamic reconfiguration that necessitated a complete reinitialization of all clients and drivers. For example, if an adapter's line-device modeling (for example, the number of line devices supported) was changed on the fly, the miniport driver would call NdisMIndicateStatus with a LINE_LINEDEVSTATE event and the LINEDEVSTATE_REINIT flag set.


NDISTAPI Interface

This section describes the OID requests that define the interface between the NDISTAPI driver, NDISWAN and underlying standard WAN miniport drivers. Each OID request described herein has a corresponding SPI function defined in the Telephony Software Development Kit, documented in the Platform SDK.

Standard WAN miniport driver developers should consult the SPI specifications when designing and implementing drivers. Note that function definitions and parameters might differ slightly between the NDISTAPI specification and the SPI specification, in which case the developer should adhere to the NDISTAPI driver Interface specification.

The following chart summarizes the OID requests that define the NDISTAPI interface.

OID | Optional or Required
OID_TAPI_ACCEPT | Optional
OID_TAPI_ANSWER | Required
OID_TAPI_CLOSE | Required
OID_TAPI_CLOSE_CALL | Required
OID_TAPI_CONDITIONAL_MEDIA_DETECTION | Required
OID_TAPI_CONFIG_DIALOG | Optional
OID_TAPI_DEV_SPECIFIC | Optional
OID_TAPI_DIAL | Optional
OID_TAPI_DROP | Required
OID_TAPI_GET_ADDRESS_CAPS | Required
OID_TAPI_GET_ADDRESS_ID | Required
OID_TAPI_GET_ADDRESS_STATUS | Required
OID_TAPI_GET_CALL_ADDRESS_ID | Required
OID_TAPI_GET_CALL_INFO | Required
OID_TAPI_GET_CALL_STATUS | Required
OID_TAPI_GET_DEV_CAPS | Required
OID_TAPI_GET_DEV_CONFIG | Optional
OID_TAPI_GET_EXTENSION_ID | Optional
OID_TAPI_GET_ID | Required
OID_TAPI_GET_LINE_DEV_STATUS | Required
OID_TAPI_MAKE_CALL | Required
OID_TAPI_NEGOTIATE_EXT_VERSION | Optional
OID_TAPI_OPEN | Required
OID_TAPI_PROVIDER_INITIALIZE | Required
OID_TAPI_PROVIDER_SHUTDOWN | Required
OID_TAPI_SECURE_CALL | Optional
OID_TAPI_SELECT_EXT_VERSION | Optional
OID_TAPI_SEND_USER_USER_INFO | Optional
OID_TAPI_SET_APP_SPECIFIC | Required
OID_TAPI_SET_CALL_PARAMS | Required
OID_TAPI_SET_DEFAULT_MEDIA_DETECTION | Required
OID_TAPI_SET_DEV_CONFIG | Optional
OID_TAPI_SET_MEDIA_MODE | Required
OID_TAPI_SET_STATUS_MESSAGES | Required

Definitions for these OIDs are found in ntddndis.h. Definitions for NDIS_TAPI_EVENT messages are found in ndistapi.h.

The extent to which a given standard WAN miniport driver supports this interface depends in large part on the discretion of the miniport driver developer and the capabilities of the underlying hardware. The functional requirements are quite simple for several of the requests; for example, the OID_TAPI_SET_APP_SPECIFIC request only requires the driver to associate a ULONG value with a specified call instance, which can be retrieved later through an OID_TAPI_GET_CALL_INFO request.

Requests that the NIC driver developer chooses not to support should be completed with the NDIS_STATUS_TAPI_OPERATIONUNAVAIL status code. The NIC driver can indicate what types of requests it supports (which can vary over time depending on line, address, or call state) by setting or clearing specific bits in the members of structures present in some of the OID_TAPI_GET_XXX requests (for example, the ulAddrCapFlags member in the LINE_ADDRESS_CAPS structure).

The following topics describe query and set requests over the NDISTAPI interface:

Query Information Requests

Set Information Requests


Query Information Requests

Query information-type requests differ from set information-type requests in that one or more members in the request structure, denoted by the OUT prefix in the structure definition, are reserved for information to be passed back to the calling process. Members prefixed with IN should be considered read-only. The first member in all query information requests, ulRequestID, is reserved for future use, and should be ignored.

Definitions for the following structures are found in ndistapi.h.

OID_TAPI_DEV_SPECIFIC

This request is used as a general extension mechanism to enable WAN NIC drivers to provide access to features not described in other requests. The meaning of the extensions are device-specific, and taking advantage of these extensions requires the application to be fully aware of them. This function uses an NDIS_TAPI_DEV_SPECIFIC structure.

OID_TAPI_GET_ADDRESS_CAPS

This request queries the specified address on the specified line device to determine its telephony capabilities. This request uses an NDIS_TAPI_GET_ADDRESS_CAPS structure.

OID_TAPI_GET_ADDRESS_ID

This request returns the address ID associated with the address in a different format on the specified line. This request uses an NDIS_TAPI_GET_ADDRESS_ID structure.

OID_TAPI_GET_ADDRESS_STATUS

This request queries the specified address for its current status and uses an NDIS_TAPI_GET_ADDRESS_STATUS structure.

OID_TAPI_GET_CALL_ADDRESS_ID

This request retrieves the address ID for the indicated call using an NDIS_TAPI_GET_CALL_ADDRESS_ID structure.

OID_TAPI_GET_CALL_INFO

This request returns detailed information about the specified call using an NDIS_TAPI_GET_CALL_INFO structure.

OID_TAPI_GET_CALL_STATUS

This request returns the current status of the specified call using an NDIS_GET_CALL_STATUS structure.

OID_TAPI_GET_DEV_CAPS

This request queries a specified line device to determine its telephony capabilities. The returned information is valid for all addresses on the line device. The request uses an NDIS_TAPI_GET_DEV_CAPS structure.

OID_TAPI_GET_DEV_CONFIG

This request returns a data structure object, the contents of which are specific to the line (WAN miniport driver) and device class, giving the current configuration of a device associated one-to-one with the line device. This request uses an NDIS_TAPI_GET_DEV_CONFIG structure.

OID_TAPI_GET_EXTENSION_ID

This request returns the extension ID that the WAN miniport driver supports for the indicated line device. The request uses an NDIS_TAPI_GET_EXTENSION_ID structure.

OID_TAPI_GET_ID

This request returns a device ID for the specified device class associated with the selected line, address, or call. The request uses an NDIS_TAPI_GET_ID structure.

OID_TAPI_GET_LINE_DEV_STATUS

This request queries the specified open line device for its current status. The information returned is global to all addresses on the line. The request uses an NDIS_TAPI_GET_LINE_DEV_STATUS structure.

OID_TAPI_MAKE_CALL

This request places a call on the specified line to the specified destination address. Optionally, call parameters can be specified if anything but default call-setup parameters are requested. The request uses an NDIS_TAPI_MAKE_CALL structure.

OID_TAPI_NEGOTIATE_EXT_VERSION

This request returns the highest version extension number that the miniport driver is willing to operate under for this device, given the range of possible extension versions. The request uses an NDIS_TAPI_NEGOTIATE_EXT_VERSION structure.

OID_TAPI_OPEN

This request opens the line device whose device ID is given, returning the NIC driver's handle for the device. The NIC driver must retain the NDISTAPI driver's handle for the device for use in subsequent calls to the LINE_EVENT callback procedure. The request uses an NDIS_TAPI_OPEN structure.

OID_TAPI_PROVIDER_INITIALIZE

This request initializes the WAN miniport driver to handle TAPI operations. The request uses an NDIS_TAPI_PROVIDER_INIT structure.


Set Information Requests

Set information requests return no information other than completion status. All request structure members should be considered as read-only, and should not be modified by standard WAN miniport drivers. The first member in all query information requests, ulRequestID, is reserved for future use, and should be ignored.

Definitions for the following structures are found in ndistapi.h.

OID_TAPI_ACCEPT

This request accepts the specified offered call. It may optionally send the specified user-to-user information to the calling party. The request uses an NDIS_TAPI_ACCEPT structure.

OID_TAPI_ANSWER

This request answers the specified offering call. It may optionally send the specified user-to-user information to the calling party. The request uses an NDIS_TAPI_ANSWER structure.

OID_TAPI_CLOSE

This request closes the specified open line device after completing or aborting all outstanding calls and asynchronous requests on the device. The request uses an NDIS_TAPI_CLOSE structure.

OID_TAPI_CLOSE_CALL

This request deallocates the call after completing or aborting all outstanding asynchronous requests on the call. The request uses an NDIS_TAPI_CLOSE_CALL structure.

OID_TAPI_CONDITIONAL_MEDIA_DETECTION

This request is made by the NDISTAPI driver whenever a client application uses LINEMAPPER as the dwDeviceID in the lineOpen function to request that lines be scanned to find one that supports the desired media mode or modes and call parameters.

The NDISTAPI driver scans based on the union of the desired media modes and the other media modes currently being monitored on the line, to give the miniport driver the opportunity to indicate if it cannot simultaneously monitor for all of the requested media modes. If the miniport driver can monitor for the indicated set of media modes, and support the capabilities indicated in LineCallParams, and can support a call of the specified type at that time, it replies with a "success" indication. The miniport driver leaves the active media monitoring modes for the line unchanged. The request uses an NDIS_TAPI_CONDITIONAL_MEDIA_DETECTION structure.

OID_TAPI_DIAL

This request dials the specified dialable number on the specified call. The request uses an NDIS_TAPI_DIAL structure.

OID_TAPI_DROP

This request drops or disconnects the specified call. User-to-user information can optionally be transmitted as part of the call disconnect. This request can be initiated by the application at any time. When OID_TAPI_DROP returns with success, the call should be idle. The request uses an NDIS_TAPI_DROP structure.

OID_TAPI_PROVIDER_SHUTDOWN

This request shuts down the miniport driver. The miniport driver should terminate any in-progress activities and make line-down indications to NDISWAN for any lines left open. The request uses an NDIS_TAPI_PROVIDER_SHUTDOWN structure.

OID_TAPI_SECURE_CALL

This request secures the call from any interruptions or interference that may affect the call's media stream. The request uses an NDIS_TAPI_SECURE_CALL structure.

OID_TAPI_SELECT_EXT_VERSION

This request selects the indicated extension version for the indicated line device. Subsequent requests operate according to that extension version. The request uses an NDIS_TAPI_SELECT_EXT_VERSION structure.

OID_TAPI_SEND_USER_USER_INFO

This request sends user-to-user information to the remote party on the specified call. The request uses an NDIS_TAPI_SEND_USER_INFO structure.

OID_TAPI_SET_APP_SPECIFIC

This request sets the application-specific member of the specified call's LINECALLINFO structure. The request uses an NDIS_TAPI_SET_APP_SPECIFIC structure.

OID_TAPI_SET_CALL_PARAMS

This request sets certain call parameters for an existing call. The request uses an NDIS_TAPI_SET_CALL_PARAMS structure.

OID_TAPI_SET_DEFAULT_MEDIA_DETECTION

This request informs the miniport driver of the new set of media modes to detect for the indicated line (replacing any previous set). The request uses an NDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION structure.

OID_TAPI_SET_DEV_CONFIG

This request restores the configuration of a device associated one-to-one with the line device from a data previously obtained using OID_TAPI_GET_DEV_CONFIG. The contents of this data structure are specific to the line (WAN NIC driver) and device class. The request uses an NDIS_TAPI_SET_DEV_CONFIG structure.

OID_TAPI_SET_MEDIA_MODE

This request changes a call's media mode as stored in the call's LINE_CALL_INFO structure. The request uses an NDIS_TAPI_SET_MEDIA_MODE structure.

OID_TAPI_SET_STATUS_MESSAGES

This request specifies which notification messages the NIC driver should generate for events related to status changes for the specified line or any of its addresses. By default, address and line-status reporting is initially disabled for a line. The request uses an NDIS_TAPI_SET_STATUS_MESSAGES structure.

OID_TAPI_CONFIG_DIALOG

This request retrieves the name of a user-mode dynamic link library that can be loaded and called to configure the specified device. The configuration DLL shall export the following function by name:

LONG
WINAPI
  ConfigDialog(
    IN HWND  hwndOwner,
    IN ULONG  ulDeviceID,
    IN LPCSTR  lpszDeviceClass
    );

This request uses an NDIS_TAPI_CONFIG_DIALOG structure.


Using CoNDIS Extensions that Support Telephonic Services

This section describes how CoNDIS WAN miniport drivers implement Telephonic services using NDIS functions in a connection-oriented environment. CoNDIS WAN miniport drivers communicate through NDIS with the NDPROXY and NDISWAN drivers. The NDPROXY driver communicates with telephony applications through a telephony service provider. For more information, see the Telephony Application Programming Interface (TAPI) in the Windows Platform SDK documentation.

The following topics describe the NDPROXY driver more fully. These topics also describe how a CoNDIS WAN miniport driver registers and enumerates its TAPI capabilities, brings up lines, and sets up and closes calls that are initiated by TAPI requests.

NDPROXY Overview

CoNDIS TAPI Registration

CoNDIS TAPI Initialization

Making Outgoing Calls

Accepting Incoming Calls

CoNDIS TAPI Shutdown

Call Manager Requirements for Voice Streaming

Non-WAN-Specific Extensions to Support Telephonic Services Over Connection-Oriented NDIS

These descriptions touch briefly on the concepts embodied in TAPI, but the reader should consult the Platform SDK for details about TAPI. Information about how TAPI models line devices and how all WAN miniport drivers should maintain the state of their connections can be found in the preceding topics, Line Devices, Addresses, and Calls and Maintaining State Information.


NDPROXY Overview

The NDPROXY driver is a provider for the Windows Telephony service. Applications make TAPI requests and the Windows Telephony service routes these requests to NDPROXY. NDPROXY implements the Telephony Service Provider Interface (TSPI) for the Windows Telephony service. NDPROXY then communicates through NDIS with the NDISWAN driver and CoNDIS WAN miniport drivers. These CoNDIS WAN miniport drivers must provide TAPI capability.

The NDPROXY driver passes TAPI requests by encapsulating TAPI parameters in NDIS structures. NDPROXY presents a client interface to CoNDIS WAN miniport drivers and a call manager interface to NDISWAN. NDISWAN presents a client interface to NDPROXY. CoNDIS WAN miniport drivers present a call manager interface to NDPROXY and a CoNDIS miniport interface to NDISWAN.

A TAPI-capable CoNDIS WAN miniport driver registers and initializes itself as a user of both WAN and TAPI services. After registration and initialization are complete, a user-level application can make telephonic requests to the Windows Telephony service module, which converts TAPI requests to TSPI requests. The Windows Telephony service module passes these requests to the NDPROXY driver. NDPROXY encapsulates parameters for TAPI requests in NDIS structures and routes the requests to the appropriate CoNDIS WAN miniport driver. These requests are routed in order to set up, monitor, and tear down lines, and calls.

A TAPI-capable CoNDIS WAN miniport driver can also communicate changes in the states of lines and calls, for example, the arrival of an incoming call or a remote disconnection.


CoNDIS TAPI Registration

This section discusses how a CoNDIS WAN miniport driver registers that it supports TAPI services and how it sets up TAPI-specific communications with the NDISWAN and NDPROXY drivers.

After a CoNDIS WAN miniport driver has registered its miniport driver entry points for one or more NICs, the following operations cause the NDISWAN and NDPROXY drivers to become associated, in a TAPI-specific way, with those NICs.

  • The CoNDIS WAN miniport driver calls the NdisMCmRegisterAddressFamily function from within its MiniportInitialize function to register its call-manager entry points and the address family type CO_ADDRESS_FAMILY_TAPI_PROXY. By doing so, the miniport driver advertises that it implements TAPI services.
  • NDIS calls NDPROXY's ProtocolCoAfRegisterNotify function to notify NDPROXY of the newly registered address family. NDPROXY's ProtocolCoAfRegisterNotify examines the address-family data and determines that it can use the TAPI services provided by the call manager that is integrated into the CoNDIS WAN miniport driver. A TAPI-capable CoNDIS WAN miniport driver is an integrated miniport call manager (MCM) driver.
  • NDPROXY calls the NdisClOpenAddressFamily function to open the TAPI-proxy address family that is associated with the CoNDIS WAN miniport driver. NdisClOpenAddressFamily registers NDPROXY's connection-oriented entry points with NDIS. These entry points are used to communicate with a TAPI-capable CoNDIS WAN miniport driver.
  • NDPROXY calls NdisCmRegisterAddressFamily to register its call-manager entry points and the address family type CO_ADDRESS_FAMILY_TAPI. By doing so, NDPROXY advertises that it implements TAPI services.
  • NDIS calls NDISWAN's ProtocolCoAfRegisterNotify function to notify NDISWAN of the newly registered address family. NDISWAN's ProtocolCoAfRegisterNotify examines the address-family data and determines that NDISWAN can use the TAPI services provided by NDPROXY.
  • NDISWAN calls the NdisClOpenAddressFamily function to open the TAPI address family that is associated with NDPROXY. NdisClOpenAddressFamily registers NDISWAN's connection-oriented entry points with NDIS. These entry points are used to communicate with NDPROXY.
  • NDISWAN calls the NdisClRegisterSap function to inform NDPROXY that NDISWAN can accept incoming calls on a particular Service Access Point (SAP). In this call, NDISWAN passes a CO_SAP structure that describes the SAP. NDISWAN sets the SapType member of CO_SAP to AF_TAPI_SAP_TYPE to specify that the SAP will be used for TAPI calls. NDISWAN sets the Sap member of CO_SAP to a string for a particular TAPI device class. A TAPI application provides this string when the application calls the TAPI lineGetID function. NDPROXY should notify NDISWAN about all incoming calls addressed to the SAP.


CoNDIS TAPI Initialization

This section discusses how a CoNDIS WAN miniport driver enumerates its TAPI capabilities for applications. These TAPI capabilities consist of:

  • Number of line devices the miniport driver supports—Line devices include, for example, a modem, a fax board, and an ISDN card.
  • Information for specific lines—Line information includes, for example, a line identifier and the number of channel addresses (telephone numbers) the line supports for simultaneous transmission of voice and data.
  • Information for specific channel addresses on lines of devices—Address information includes, for example, the identity of a caller (Caller ID) and the number of active calls possible.

To retrieve information about underlying hardware, NDPROXY issues requests for line and channel-address capabilities. That is, the NDPROXY driver queries the TAPI capabilities of a CoNDIS WAN miniport driver. The NDPROXY driver calls the NdisCoRequest function to query the TAPI capabilities of the miniport driver. In this call, NDPROXY passes a NDIS_REQUEST structure. NDPROXY specifies the following in NDIS_REQUEST:

  • NdisRequestQueryInformation value in the RequestType member
  • Object identifier (OID) that specifies the TAPI capability to retrieve from the miniport driver in the Oid member
  • Buffer to hold the TAPI-capability information that is returned in the InformationBuffer member

All queries sent to a CoNDIS WAN miniport driver by the NDPROXY driver can be completed either synchronously or asynchronously. If a CoNDIS WAN miniport driver determines that it cannot complete the query immediately, then it can simply return NDIS_STATUS_PENDING and call the NdisMCmRequestComplete function from within its ProtocolCoRequest function when it has completed the query.

After a CoNDIS WAN miniport driver notifies NDPROXY about the registration of a new address family as specified in CoNDIS TAPI Registration, NDPROXY queries the following OIDs to determine the TAPI-specific capabilities of the CoNDIS WAN miniport driver and the miniport driver's NIC.

  • NDPROXY queries the miniport driver with OID_CO_TAPI_CM_CAPS to determine the number of lines supported by the miniport driver's device (the device for which it provides TAPI services). This OID also requests the miniport driver to indicate whether these lines have dissimilar line capabilities.
  • NDPROXY next queries the miniport driver with OID_CO_TAPI_LINE_CAPS to determine the telephony capabilities for the specified line. This OID also requests the miniport driver to indicate whether addresses on this line have dissimilar address capabilities.
    • If the previous query of OID_CO_TAPI_CM_CAPS indicated that the miniport driver's device supports only one line, or if the device supports multiple lines that have the same line capabilities, NDPROXY only has to query OID_CO_TAPI_LINE_CAPS once to obtain the line capabilities of the device. In this case, the line capabilities returned by the miniport driver apply to all lines on the device.
    • If the device supports multiple lines with dissimilar line capabilities, NDPROXY must query OID_CO_TAPI_LINE_CAPS once for each line to obtain the line capabilities of each line.
  • Finally, NDPROXY queries the miniport driver with OID_CO_TAPI_ADDRESS_CAPS to determine the telephony capabilities for a specified address on a specified line.
    • If the previous query of OID_CO_TAPI_LINE_CAPS indicated that the line supports only one address or that all addresses on the line have the same address capabilities, NDPROXY queries OID_CO_TAPI_ADDRESS_CAPS only once to determine the capabilities of all the addresses on the line.
    • If a line supports multiple addresses that have dissimilar capabilities, NDPROXY queries OID_CO_TAPI_ADDRESS_CAPS once for each address on the line.

The NDPROXY driver uses the information obtained with the TAPI enumeration OIDs to do the following:

  • Create TAPI parameters for subsequent TAPI calls
  • Determine whether to accept or reject subsequent incoming TAPI calls
  • Register one or more TAPI service access points (SAPs) on which to receive subsequent incoming TAPI calls.


Making Outgoing Calls

If an application attempts to make an outgoing call, it first must open a line. A line is opened as a result of an application calling the TAPI lineOpen function. To place a telephony call on the previously opened line, the application calls the TAPI lineMakeCall function and passes a pointer to the specific destination address. If anything but default call-setup parameters are requested, the application also passes a pointer to a LINECALLPARAMS structure. If the application uses default call-setup parameters, lineMakeCall provides those parameters in a LINECALLPARAMS structure. Members of this structure specify how the telephony call should be set up.

These TAPI-function calls cause the NDPROXY driver to first create a virtual connection (VC) with the CoNDIS WAN miniport driver and then to encapsulate TAPI parameters in NDIS structures in order to make the outgoing call. The miniport driver will use these TAPI parameters to set up the outgoing call. The following describes how the outgoing call is connected, set up, and made:

  • NDPROXY calls NdisCoCreateVc to initiate the creation of the VC with the miniport driver. After NDPROXY calls NdisCoCreateVc, NDIS calls, as a synchronous operation, the ProtocolCoCreateVc function of the call manager integrated into the miniport driver. NDIS passes to ProtocolCoCreateVc a handle that represents the VC. If the call to NdisCoCreateVc is successful, NDIS fills and returns the VC handle. ProtocolCoCreateVc performs any necessary allocations of dynamic resources and structures that the miniport call manager (MCM) driver requires to perform subsequent operations on the VC that will later be activated. Such resources include, but are not limited to, memory buffers, data structures, events, and other such similar resources.
  • NDPROXY specifies the TAPI parameters for an outgoing call in a CO_AF_TAPI_MAKE_CALL_PARAMETERS structure. NDPROXY fills this structure's members with the following information that was passed in the TAPI lineMakeCall function:
    • the destination address in the DestAddress member
    • the open-line identifier in the ulLineID member
    • the LINECALLPARAMS structure in the LineCallParams member
  • NDPROXY overlays the CO_AF_TAPI_MAKE_CALL_PARAMETERS structure on the Parameters member of a CO_SPECIFIC_PARAMETERS structure and sets the Length member of CO_SPECIFIC_PARAMETERS to the size of CO_AF_TAPI_MAKE_CALL_PARAMETERS.
  • NDPROXY sets the CO_SPECIFIC_PARAMETERS structure to the MediaSpecific member of a CO_MEDIA_PARAMETERS structure.
  • NDPROXY sets a pointer to the CO_MEDIA_PARAMETERS structure to the MediaParameters member of a CO_CALL_PARAMETERS structure.
  • Once NDPROXY encapsulates TAPI parameters, NDPROXY calls the NdisClMakeCall function to initiate the outgoing call. In this function call, NDPROXY passes a pointer to the filled CO_CALL_PARAMETERS structure. NDIS in turn calls the ProtocolCmMakeCall function of the CoNDIS WAN miniport driver's call manager. The miniport driver should examine only the CO_AF_TAPI_MAKE_CALL_PARAMETERS structure embedded in CO_CALL_PARAMETERS. No other call parameters are meaningful in this case. If the miniport driver subsequently activates the VC for the outgoing call, the miniport driver calls the NdisMCmActivateVc function and passes a pointer to the filled CO_CALL_PARAMETERS.
  • After the miniport driver has negotiated with the network to establish the telephony-call parameters for the VC and set up its NIC for those call parameters, the miniport driver calls the NdisMCmMakeCallComplete function to indicate that it is ready to make data transfers on the VC. In this call, the miniport driver must pass the handle to the VC and modifications made to telephony-call parameters.
  • The miniport driver must modify the CallMgrParameters member of the CO_CALL_PARAMETERS structure to specify the quality of service (QoS) of transferring packets, such as the bandwidth. To set this CallMgrParameters member, the miniport driver fills members of a CO_CALL_MANAGER_PARAMETERS structure and points this structure to CallMgrParameters. For example, to identify the transmit and receive speeds in bytes per second for the VC, the miniport driver must set the PeakBandwidth members of the Transmit and Receive members of CO_CALL_MANAGER_PARAMETERS. The Transmit and Receive members are FLOWSPEC structures. For more information on the FLOWSPEC structure, see the Platform SDK.
  • If the miniport driver has modified telephony-call parameters, it must set the Flags member in the CO_CALL_PARAMETERS structure with CALL_PARAMETERS_CHANGED. As a result of the NdisMCmMakeCallComplete call made by the miniport driver, NDIS calls NDPROXY's ProtocolClMakeCallComplete function to complete the asynchronous operations that were initiated with NdisClMakeCall.
  • After the miniport driver successfully completes the outgoing call, NDPROXY notifies a TAPI application that the call is connected. This TAPI application then calls the TAPI lineGetID function to inform NDPROXY to locate the appropriate CoNDIS client. In this lineGetID call, the TAPI application supplies a string for a particular TAPI device class to which the application requires a handle. NDPROXY uses this string to locate the CoNDIS client that previously registered a SAP for the particular TAPI device class. If the CoNDIS client is NDISWAN, the string is NDIS. If NDPROXY locates a SAP with a string that matches the string passed by the TAPI application, NDPROXY calls NdisMCmCreateVc to set up a connection endpoint with NDISWAN on which it can dispatch notification of the outgoing call that was made. NDIS in turn calls NDISWAN's ProtocolCoCreateVc function and passes a handle that represents the VC.
  • After NDPROXY sets up the connection endpoint with NDISWAN, it calls the NdisCmDispatchIncomingCall function to notify NDISWAN about the outgoing call. In this call, NDPROXY passes the encapsulated CO_AF_TAPI_MAKE_CALL_PARAMETERS structure that contains the outgoing call parameters. NDIS in turn calls NDISWAN's ProtocolClIncomingCall function, within which NDISWAN either accepts or rejects the requested connection. If NDISWAN changes the call parameters passed to it, it must set the Flags member in the CO_CALL_PARAMETERS structure with CALL_PARAMETERS_CHANGED.
  • After deciding whether to accept the connection and after possibly changing the call parameters, NDISWAN calls the NdisClIncomingCallComplete function. NDIS in turn calls the miniport driver's ProtocolCmIncomingCallComplete function. Depending on whether NDISWAN accepted the outgoing call and whether the miniport driver accepts or rejects NDISWAN's proposed changes to the call parameters, the miniport driver calls either NdisCmDispatchCallConnected or NdisCmDispatchIncomingCloseCall functions. NdisCmDispatchCallConnected notifies NDISWAN that data transfers can begin on the VC that NDPROXY created for the outgoing call. NdisCmDispatchIncomingCloseCall informs NDISWAN and NDPROXY to tear down the proposed outgoing call.
  • After NDISWAN accepts the outgoing call, NDPROXY calls the NdisCoGetTapiCallId function to retrieve a string that identifies NDISWAN's context for the VC. NDPROXY passes this string back to the TAPI application. The TAPI application uses this VC-context string to complete its call to lineGetID.


Accepting Incoming Calls

Before an application can accept an incoming call, it first must have a line open. A line is opened as a result of an application calling the TAPI lineOpen function. This TAPI-function call causes underlying drivers to encapsulate TAPI parameters in NDIS structures in order to prepare to receive an incoming call. After the CoNDIS WAN miniport driver receives an incoming call, the miniport driver must first create a virtual connection (VC) with the NDPROXY driver and then notify NDPROXY of the incoming call. NDPROXY in turn notifies the application through TAPI. The following describes how the incoming call is set up, connected, and made:

  • NDPROXY specifies the TAPI parameters for an incoming connection in a CO_AF_TAPI_SAP structure. NDPROXY fills this structure's members with the following information that was passed in the TAPI lineOpen function:
    • Open-line identifier in the ulLineID member
    • Address of the incoming connection in the ulAddressID member
    • Media mode of the incoming connection's information stream in the ulMediaModes member
  • NDPROXY overlays the CO_AF_TAPI_SAP structure on the Sap member of a CO_SAP structure and sets the SapLength member of CO_SAP to the size of CO_AF_TAPI_SAP. NDPROXY must also set the SapType member of CO_SAP to AF_TAPI_SAP_TYPE.
  • Once NDPROXY encapsulates TAPI parameters, NDPROXY calls the NdisClRegisterSap function to make itself ready to receive incoming calls. In this function call, NDPROXY passes a pointer to the filled CO_SAP structure that specifies the Service Access Point (SAP) on which NDPROXY can receive incoming calls. NDIS forwards the CO_SAP structure to the ProtocolCmRegisterSap function of the CoNDIS WAN miniport call manager (MCM) driver. ProtocolCmRegisterSap communicates with network control devices or other media-specific agents, as necessary, to register the SAP on the network for NDPROXY. After the miniport driver has registered the SAP, it can accept an incoming-call offer directed to that SAP.
  • A CoNDIS WAN miniport driver is alerted to an incoming call by signaling messages from the network. From these signaling messages, the miniport driver extracts the call parameters for the call, including the SAP to which the incoming call is addressed.
  • Before indicating an incoming call to NDPROXY, the miniport driver calls the NdisMCmCreateVc function to initiate the creation of a VC with NDPROXY. NDPROXY allocates and initializes resources required for the VC and stores the handle to the VC.
  • The CoNDIS WAN miniport driver sets the TAPI parameters for an incoming call in a CO_AF_TAPI_INCOMING_CALL_PARAMETERS structure. The miniport driver fills this structure's members with the following information that was extracted from signaling messages:
    • Line identifier in the ulLineID member
    • Address of the incoming call in the ulAddressID member
    • CO_TAPI_FLAG_INCOMING_CALL bit in the ulFlags member. All other bits of ulFlags are reserved and must be set to 0.
    • LINECALLPARAMS structure in the LineCallInfo member. Members of LINECALLPARAMS specify TAPI call parameters for an incoming call.
  • The miniport driver overlays CO_AF_TAPI_INCOMING_CALL_PARAMETERS on the Parameters member of a CO_SPECIFIC_PARAMETERS structure and sets the Length member of CO_SPECIFIC_PARAMETERS to the size of CO_AF_TAPI_INCOMING_CALL_PARAMETERS.
  • The miniport driver sets the CO_SPECIFIC_PARAMETERS structure to the MediaSpecific member of a CO_MEDIA_PARAMETERS structure.
  • The miniport driver sets a pointer to the CO_MEDIA_PARAMETERS structure to the MediaParameters member of a CO_CALL_PARAMETERS structure.
  • The miniport driver must also set the CallMgrParameters member of the CO_CALL_PARAMETERS structure to specify the quality of service (QoS) of transferring packets, such as the bandwidth. To set this CallMgrParameters member, the miniport driver fills members of a CO_CALL_MANAGER_PARAMETERS structure and points this structure to CallMgrParameters. For example, to identify the transmit and receive speeds in bytes per second for the VC, the miniport driver must set the PeakBandwidth members of the Transmit and Receive members of CO_CALL_MANAGER_PARAMETERS. The Transmit and Receive members are FLOWSPEC structures. For more information on the FLOWSPEC structure, see the Platform SDK.
  • After the miniport driver encapsulates TAPI parameters and fills the CallMgrParameters member of CO_CALL_MANAGER_PARAMETERS, it calls the NdisMCmDispatchIncomingCall function to indicate the incoming call to NDPROXY. In this call, the miniport driver passes the following:
    • a handle that identifies the SAP to which the incoming call is addressed
    • a handle that identifies the VC for the incoming call
    • a pointer to the filled CO_CALL_PARAMETERS structure
  • NDPROXY returns NDIS_STATUS_PENDING to the miniport driver so NDPROXY can complete NdisMCmDispatchIncomingCall asynchronously.
  • After the TAPI application answers the incoming call with the lineAnswer function, NDPROXY calls the NdisClIncomingCallComplete function. NDIS in turn calls the miniport driver's ProtocolCmIncomingCallComplete function. If NDPROXY returns an NDIS_STATUS_SUCCESS code, it indicates acceptance of the call parameters. If NDPROXY finds the call parameters unacceptable, it can request a change in the call parameters by setting the Flags member in the CO_CALL_PARAMETERS structure to CALL_PARAMETERS_CHANGED and by supplying revised call parameters. If NDPROXY accepts the incoming call, the miniport driver should send signaling messages to indicate to the calling entity that the call has been accepted. Otherwise, the miniport driver should send signaling messages to indicate that the call has been rejected. If NDPROXY is requesting a change in call parameters, the miniport driver sends signaling messages to request a change in call parameters.
  • The miniport driver activates the VC that the miniport driver created with NDPROXY and must also call the NdisMCmActivateVc function to notify NDPROXY that the miniport driver is ready to transfer packets on the VC.
  • If NDPROXY rejects the call, the miniport driver calls the NdisMCmDeactivateVc function to deactivate the VC that the miniport driver created for the incoming call. After the VC is deactivated, the miniport driver calls the NdisMCmDeleteVc function to delete the VC.
  • Depending on whether NDPROXY accepted the incoming call and whether the end-to-end connection was successfully established, the miniport driver calls either NdisMCmDispatchCallConnected or NdisMCmDispatchIncomingCloseCall functions. Note that if the remote calling entity tore down the call, it sends signaling messages to indicate that the end-to-end connection was not successfully established. NdisMCmDispatchCallConnected notifies NDPROXY that data transfers can begin on the VC that the miniport driver created and activated for the incoming call. NdisMCmDispatchIncomingCloseCall informs NDPROXY to tear down the incoming call.
  • If NDPROXY is directed to tear down the incoming call, it calls the NdisClCloseCall function to acknowledge that it will neither attempt to send nor expect to receive data on the VC. NDIS in turn calls the miniport driver's ProtocolCmCloseCall function. The miniport driver then calls the NdisMCmDeactivateVc function to deactivate the VC. After the VC is deactivated, the miniport driver calls the NdisMCmDeleteVc function to delete the VC.
  • After the TAPI application accepts the incoming call and NDPROXY notifies the application that the call is connected, the application calls the TAPI lineGetID function to inform NDPROXY to locate the appropriate CoNDIS client. In this lineGetID call, the TAPI application supplies a string for a particular TAPI device class to which the application requires a handle. NDPROXY uses this string to locate the CoNDIS client that previously registered a SAP for the particular TAPI device class. If the CoNDIS client is NDISWAN, the string is NDIS. If NDPROXY locates a SAP with a string that matches the string passed by the TAPI application, NDPROXY calls NdisMCmCreateVc to set up a connection endpoint with NDISWAN on which it can dispatch notification of the incoming call. NDIS in turn calls NDISWAN's ProtocolCoCreateVc function and passes a handle that represents the VC.
  • After NDPROXY sets up the connection endpoint with NDISWAN, it calls the NdisCmDispatchIncomingCall function to notify NDISWAN about the incoming call. In this call, NDPROXY passes the encapsulated CO_AF_TAPI_INCOMING_CALL_PARAMETERS structure that contains the incoming call parameters. NDIS in turn calls NDISWAN's ProtocolClIncomingCall function, within which NDISWAN either accepts or rejects the requested connection.
  • After deciding whether to accept the connection and after possibly changing the call parameters, NDISWAN calls the NdisClIncomingCallComplete function. NDIS in turn calls the miniport driver's ProtocolCmIncomingCallComplete function. Depending on whether NDISWAN accepted the incoming call and whether the miniport driver accepts or rejects NDISWAN's proposed changes to the call parameters, the miniport driver calls either NdisCmDispatchCallConnected or NdisCmDispatchIncomingCloseCall functions. NdisCmDispatchCallConnected notifies NDISWAN that data transfers can begin on the VC that the miniport driver created for the incoming call. NdisCmDispatchIncomingCloseCall informs NDISWAN and NDPROXY to tear down the incoming call.
  • After NDISWAN accepts the incoming call, NDPROXY calls the NdisCoGetTapiCallId function to retrieve a string that identifies NDISWAN's context for the VC. NDPROXY passes this string back to the TAPI application. The TAPI application uses this VC-context string to complete its call to lineGetID.


CoNDIS TAPI Shutdown

A TAPI session begins after a CoNDIS WAN miniport driver has enumerated its TAPI capabilities to an application. Within a session, one or more lines can be opened and one or more calls can be established. During the time a line is open, many calls can be established and then closed or dropped. During a session, one or more lines can go through transitions from open to closed many times. How a miniport driver handles such transitions is described in this section.

Closing a Call

An in-process call can be closed either by the local node or by the remote node. The call can be closed on the local node, either because the last application with a handle to the call has closed the handle, or perhaps because the miniport driver's MiniportHalt or MiniportReset has been called. If the remote node hangs up an in-process call, the miniport driver must inform upper layers to tear down the call.

If an application on the local node closes the call, it must disconnect the call. A call is disconnected as a result of an application calling the TAPI lineDrop function. This TAPI-function call causes the NDPROXY driver to call the NdisClCloseCall function and to pass a handle that represents the VC for the call. NDIS in turn calls the CoNDIS WAN miniport driver's ProtocolCmCloseCall function. The miniport driver should return NDIS_STATUS_PENDING to NDPROXY so the miniport driver can complete NdisClCloseCall asynchronously.

The miniport driver's ProtocolCmCloseCall must communicate with network control devices to terminate a connection between the local node and a remote node. The miniport driver must then call the NdisMCmDeactivateVc function to initiate deactivation of the VC used for the call.

After the miniport driver terminates the connection, its ProtocolCmCloseCall can call the NdisMCmCloseCallComplete function to complete the call closure.

If the remote node hangs up an in-process call, the miniport driver calls the NdisCmDispatchIncomingCloseCall function to inform NDISWAN and NDPROXY to tear down the incoming call.

Closing a Line

A line is closed when the last application with an open handle to the line has closed the handle. A line is closed as a result of an application calling the TAPI lineClose function. This TAPI-function call causes the NDPROXY driver to initiate the closure of all calls on that line as described in the preceding section. The miniport driver should drop those calls and clean up their state.

Closing a Session

Session termination can be initiated by either the upper layers or a CoNDIS WAN miniport driver. After the last client process has detached from the higher-level Telephony module, the NDPROXY driver will be informed that it must terminate its session with each of the registered adapters. To do so, the NDPROXY driver calls the NdisClCloseAddressFamily function and passes the handle to the TAPI address family. NDIS in turn calls the miniport driver's ProtocolCmCloseAf function. The miniport driver should terminate any related activities it has in progress on the specified adapter and release any relevant resources. After calling NdisClCloseAddressFamily, the client should consider the handle to the TAPI address family invalid.

Driver-initiated session termination can occur if the miniport driver is being unloaded in its MiniportHalt function. Typically, the miniport driver would complete any outstanding NDPROXY requests and notify NDISWAN that all calls are closing. If the miniport driver were reloaded again later, it would go through the same initialization process described previously.

The CoNDIS WAN miniport driver might also initiate session termination if it underwent some dynamic reconfiguration that necessitated a complete reinitialization of all clients and drivers. For example, if an adapter's line-device modeling (for example, the number of line devices supported) was changed on the fly.


Call Manager Requirements for Voice Streaming

This section describes requirements that a call manager or integrated miniport call manager (MCM) driver must meet to support voice streaming over connection-oriented media. These requirements are described in the following topics:

Responding to an OID_CO_TAPI_LINE_CAPS Query

Specifying Parameters for an Outgoing Call

Specifying Parameters for an Incoming Call


Responding to an OID_CO_TAPI_LINE_CAPS Query

In response to an OID_CO_TAPI_LINE_CAPS query, a call manager or MCM driver returns a CO_TAPI_LINE_CAPS structure that contains a LINE_DEV_CAPS structure. To support voice streaming, a call manager or MCM driver must specify the following values in the LINE_DEV_CAPS structure:

  • ulMediaModes

    This field should contain LINEMEDIAMODE_AUTOMATEDVOICE, which maps to TAPIMEDIAMODE_AUDIO in TAPI 3.0.

  • ulAddressTypes

    This field must be filled in appropriately. For a description of valid values, see the description of dwAddressTypes in the Platform SDK. This field must not be zero.

  • ulGenerateDigitModes

    This field must be filled in with a bitwise OR of the LINEDIGITMODE_constants that specify the digit modes that can be generated on the line. For a description of the LINEDIGITMODE_constant, see the description of dwGenerateDigitModes in the Platform SDK.

  • ulMonitorDigitModes

    This field must be filled in with a bitwise OR of the LINEDIGITMODE_constants that specify the digit modes than can be detected on this line. For a description of the LINEDIGITMODE_constants, see the description of dwMonitorDigitModes in the Platform SDK.


Specifying Parameters for an Outgoing Call

When making an outgoing call, a call manager or MCM driver that supports voice streaming must supply the following values in the CO_CALL_MANAGER_PARAMETERS structure:

  • Maximum transmit SDU size (CallMgrParameters->Transmit.MaxSduSize)
  • Maximum receive SDU size (CallMgrParameters->Receive.MaxSduSize)

A call manager or MCM driver that supports an address family other than CO_ADDRESS_FAMILY_TAPI_PROXY fills in these values when translating TAPI call parameters to NDIS call parameters in response to a query of OID_CO_TAPI_TRANSLATE_TAPI_CALLPARAMS.

A call manager or MCM driver that supports the CO_ADDRESS_FAMILY_TAPI_PROXY family writes these values to the CO_CALL_MANAGER_PARAMETERS structure in the context of its ProtocolCmMakeCall function. Note that the maximum SDU sizes passed to the ProtocolCmMakeCall function are incorrect. The ProtocolCmMakeCall function must overwrite the incorrect values with correct values.


Specifying Parameters for an Incoming Call

When indicating an incoming call with Ndis(M)CmDispatchIncomingCall, a call manager or MCM driver that supports voice streaming must specify the following values in the CO_CALL_MANAGER_PARAMETERS structure:

  • Maximum transmit SDU size (CallMgrParameters->Transmit.MaxSduSize)
  • Maximum receive SDU size (CallMgrParameters->Receive.MaxSduSize)

In addition, a call manager or an MCM driver must specify the following values in the LINE_CALL_INFO structure:

  • ulMediaMode

    This field should contain LINEMEDIAMODE_AUTOMATEDVOICE, which maps to TAPIMEDIAMODE_AUDIO in TAPI 3.0.

  • ulCallerIDFlags
  • ulCallerIDSize
  • ulCallerIDOffset
  • ulCallerIDNameSize
  • ulCallerIDNameOffset
  • ulCalledIDFlags
  • ulCalledIDSize
  • ulCalledIDOffset
  • ulCalledIDNameSize
  • ulCalledDNameOffset
  • ulCallerIDAddressType
  • ulCalledIDAddressType

A call manager or MCM driver that supports an address family other than CO_ADDRESS_FAMILY_TAPI_PROXY specifies the above-listed LINE_CALL_INFO members when responding to an OID_CO_TAPI_TRANSLATE_NDIS_CALLPARAMS query.

A call manager or an MCM driver that supports the CO_ADDRESS_FAMILY_TAPI_PROXY family specifies the above-listed LINE_CALL_INFO members in the media-specific portion of the CO_CALL_MANAGER_PARAMETERS structure that it supplies to Ndis(M)CmDispatchIncomingCall.

For a description of the members in the LINE_CALL_INFO structure, see the LINECALLINFO structure in the Platform SDK.


Non-WAN-Specific Extensions to Support Telephonic Services Over Connection-Oriented NDIS

This topic describes non-WAN-specific extensions for TAPI support over connection-oriented NDIS. These extensions are the NDIS/TAPI translation OIDs. These extensions allow non-WAN-specific call managers and integrated miniport call manager (MCM) drivers to translate TAPI parameters to NDIS parameters or TAPI parameters to NDIS parameters. These extensions allow call managers and MCM drivers that support ATM, for example, to provide TAPI access over connection-oriented media. For information on WAN-specific extensions for TAPI support over connection-oriented NDIS, see Using CoNDIS Extensions that Support Telephonic Services.

The NDIS/TAPI translation OIDs should not be used for call managers or MCM drivers that respectively register CO_ADDRESS_FAMILY_TAPI_PROXY with NdisCmRegisterAddressFamily or NdisMCmRegisterAddressFamily. Instead, such call managers and MCM drivers, as well as their TAPI clients, should encapsulate TAPI parameters inside connection-oriented structures, as described in Using CoNDIS Extensions that Support Telephonic Services.

The NDIS/TAPI translation OIDs are as follows:

  • OID_CO_TAPI_TRANSLATE_TAPI_CALLPARAMS

    This OID requests a call manager or MCM driver to translate TAPI call parameters supplied by the client to NDIS call parameters. The client typically uses the NDIS call parameters returned by the call manager or MCM driver as an input (formatted as a CO_CALL_PARAMETERS structure) to NdisClMakeCall. The client uses NdisClMakeCall to initiate a connection-oriented call.

  • OID_CO_TAPI_TRANSLATE_NDIS_CALLPARAMS

    This OID requests a call manager or MCM driver to translate NDIS call parameters for an incoming call (passed in a CO_CALL_PARAMETERS structure to the client's ProtocolClIncomingCall function) to TAPI call parameters. The client uses the translated TAPI call parameters returned by the call manager or MCM driver to determine whether to accept or reject the incoming call.

  • OID_CO_TAPI_TRANSLATE_SAP

    This OID requests a call manager or MCM driver to prepare one or more NDIS SAPs from TAPI call parameters that are supplied by the client. The client typically uses an NDIS SAP returned by the call manager or MCM driver as an input (formatted as a CO_SAP structure) to NdisClRegisterSap, with which the client registers a SAP on which to receive incoming calls.


Task Offload

To achieve a significant performance boost, the Microsoft TCP/IP transport can offload one or more of the following tasks to a NIC that has the appropriate task-offload capabilities:

  • Checksum tasks

    The TCP/IP transport can offload the calculation and/or validation of IP and/or TCP checksums. The initial release of Windows® 2000 does not support UDP checksum offloads; however, future service packs and update releases of Windows 2000 and later versions may support UDP checksum offloads.

  • IP Security tasks

    The TCP/IP transport can offload the calculation and validation of encrypted checksums for authentication headers (AH) and/or encapsulating security payloads (ESP). The TCP/IP transport can also offload the encryption and decryption of ESP payloads.

  • Segmentation of large TCP packets

    The TCP/IP transport can offload the segmentation of large TCP packets.

The TCP/IP transport in Windows 2000 and later versions can process IPv4 (but not IPv6) packets and therefore supports task offload only for IPv4 packets.

Offloading tasks from the TCP/IP transport to a NIC involves two major operations:

  • Querying and enabling a NIC's task-offload capabilities. For more information, see Querying Task Offload Capabilities and Enabling Task Offload Capabilities.
  • Passing per-packet information (extended out-of-band data) related to offloaded tasks. For more information, see Accessing Per-Packet Information, Offloading TCP/IP Checksum Tasks, Offloading IP Security Tasks, and Offloading the Segmentation of Large TCP/IP Packets.


Querying Task-Offload Capabilities

The TCP/IP transport determines a NIC's task-offload capabilities by querying OID_TCP_TASK_OFFLOAD. In this query, the TCP/IP transport supplies, in the InformationBuffer, an NDIS_TASK_OFFLOAD_HEADER, which is defined as follows:

typedef struct _NDIS_TASK_OFFLOAD_HEADER
{
    ULONG  Version;
    ULONG  Size;
    ULONG  Reserved;
    UCHAR  OffsetFirstTask;
    NDIS_ENCAPSULATION_FORMAT  EncapsulationFormat;
} NDIS_TASK_OFFLOAD, *PNDIS_TASK_OFFLOAD;

The NDIS_TASK_OFFLOAD_HEADER structure specifies the following:

  • The task-offload version supported by the TCP/IP transport
  • The size of the NDIS_TASK_OFFLOAD_HEADER structure (used for checking the version of the structure)
  • The offset in bytes from the beginning of the InformationBuffer to the first NDIS_TASK_OFFLOAD structure.
  • The encapsulation format for send and receive packets passed between the TCP/IP transport and the miniport driver

With the information supplied by the NDIS_TASK_OFFLOAD_HEADER, the miniport driver or its NIC can locate the beginning of the first IP header in a send or receive packet. This is a prerequisite for performing offload tasks.

In response to a query of OID_TCP_TASK_OFFLOAD, a miniport driver returns, in the InformationBuffer, the NDIS_TASK_OFFLOAD header followed by one or more NDIS_TASK_OFFLOAD structures. The NDIS_TASK_OFFLOAD structure is defined as follows:

typedef struct _NDIS_TASK_OFFLOAD
{
    ULONG      Version;
    ULONG      Size;
    NDIS_TASK  Task;
    ULONG      OffsetNextTask;
    ULONG      TaskBufferLength;
    UCHAR      TaskBuffer[1];
} NDIS_TASK_OFFLOAD, *PNDIS_TASK_OFFLOAD;

The NDIS_TASK_OFFLOAD structure specifies the following:

  • The version of the specified offload task
  • The size of the NDIS_TASK_OFFLOAD structure (used for checking the version of the structure)
  • The offload task
  • The offset from the beginning of the InformationBuffer to the next NDIS_TASK_OFFLOAD structure
  • The length of the TaskBuffer
  • A variable-length array that contains task-specific information

Each NDIS_TASK_OFFLOAD structure specifies a task-offload capability supported by the miniport driver's NIC. If the miniport driver's NIC supports multiple versions of a particular task-offload capability, it returns one NDIS_TASK_OFFLOAD structure for each version.


Reporting a NIC's Checksum Capabilities

If a miniport driver's NIC can calculate and/or validate IP, TCP, and/or UDP checksums, the miniport driver indicates such capabilities in an NDIS_TASK_TCP_IP_CHECKSUM structure. The miniport driver overlays the NDIS_TASK_TCP_IP_CHECKSUM structure on the TaskBuffer of an NDIS_TASK_OFFLOAD structure that it returns in the InformationBuffer in response to a query of OID_TCP_TASK_OFFLOAD.

The NDIS_TASK_TCP_IP_CHECKSUM structure is defined as follows:

typedef struct _NDIS_TASK_TCP_IP_CHECKSUM
{
  struct
  {
    ULONG    IpOptionsSupported:1;
    ULONG    TcpOptionsSupported:1;
    ULONG    TcpChecksum:1;
    ULONG    UdpChecksum:1;
    ULONG    IpChecksum:1;
  } V4Transmit;

  struct
  {
    ULONG    IpOptionsSupported:1;
    ULONG    TcpOptionsSupported:1;
    ULONG    TcpChecksum:1;
    ULONG    UdpChecksum:1;
    ULONG    IpChecksum:1;
  } V4Receive;

  struct
  {
    ULONG    IpOptionsSupported:1;
    ULONG    TcpOptionsSupported:1;
    ULONG    TcpChecksum:1;
    ULONG    UdpChecksum:1;
  } V6Transmit;

  struct
  {
    ULONG    IpOptionsSupported:1;
    ULONG    TcpOptionsSupported:1;
    ULONG    TcpChecksum:1;
    ULONG    UdpChecksum:1;
  } V6Receive;

A miniport driver indicates the following checksum capabilities for IPv4 send packets and for IPv4 receive packets:

  • Whether its NIC can calculate and/or validate checksums for a packet whose IP header(s) contain(s) IP options.
  • Whether its NIC can calculate and/or validate checksums for a packet whose TCP header contain TCP options.
  • The types of checksums (IP, TCP, and/or UDP) its NIC can calculate for send packets and validate for receive packets. The initial release of Windows 2000 does not support UDP checksum offloads; however, future service packs and update releases of Windows 2000 and later versions may support UDP checksum offloads.

A miniport driver can indicate similar checksum capabilities for IPv6 send packets and for IPv6 receive packets; however, since the TCP/IP transport in the initial release of Windows 2000 can process only IPv4 packets, it never enables checksum capabilities for IPv6 packets.


Reporting a NIC's IP Security Capabilities

A miniport driver specifies its NIC's IP Security capabilities in an NDIS_TASK_IPSEC structure. The miniport driver overlays this structure on the TaskBuffer of an NDIS_TASK_OFFLOAD structure that the miniport driver returns in an InformationBuffer in response to a query of OID_TCP_TASK_OFFLOAD.

The NDIS_TASK_IPSEC structure is defined as follows:

typedef struct _NDIS_TASK_IPSEC
{
  struct
  {
    ULONG    AH_ESP_COMBINED;
    ULONG    TRANSPORT_TUNNEL_COMBINED;
    ULONG    V4_OPTIONS;
    ULONG    RESERVED;
  } Supported;

  struct
  {
    ULONG    MD5:1;
    ULONG    SHA_1:1;
    ULONG    Transport:1;
    ULONG    Tunnel:1;
    ULONG    Send:1;
    ULONG    Receive:1;
  } V4AH;

  struct
  {
    ULONG    DES:1;
    ULONG    RESERVED:1;
    ULONG    TRIPLE_DES:1;
    ULONG    NULL_ESP:1;
    ULONG    Transport:1;
    ULONG    Tunnel:1;
    ULONG    Send:1;
    ULONG    Receive:1;
  } V4ESP

} NDIS_TASK_IPSEC, *PNDIS_TASK_IPSEC;

A miniport driver indicates the following general capabilities in the NDIS_TASK_IPSEC structure:

  • Whether its NIC can perform combined IP security operations on a packet—that is, process a packet that contains both an authentication header (AH) and an encapsulating security payload (ESP) in a packet with the following format: [IP][AH][ESP][rest of packet].
  • Whether its NIC can do IP Security processing on both the transport-mode portion and the tunnel-mode portion of send and receive packets. The transport-mode portion of a packet pertains to an end-to-end security association. The tunnel-mode portion of a packet pertains to a tunnel security association.
  • Whether its NIC can perform IP Security operations on packets whose IP header(s) contain(s) IP options

A miniport driver specifies its NIC's capabilities for calculating and/or validating encrypted checksums for AH payloads and authentication information as follows:

  • The integrity algorithm(s) (MD5 or SHA 1) that its NIC can use
  • Whether its NIC can process an AH security payloads for the transport-mode portion of a packet
  • Whether its NIC can process an AH security payload for the tunnel-mode portion of a packet
  • Whether its NIC can process AH security payloads for send packets
  • Whether its NIC can process AH security payloads for receive packets

A miniport driver specifies its NIC's capabilities for processing ESP payloads as follows:

  • The confidentiality algorithm(s) (DES and/or triple DES) that its NIC can use
  • Whether its NIC supports null encryption, which is the ESP payload without encryption but with authentication hashes
  • Whether its NIC can do ESP processing for the transport-mode portion of the packet
  • Whether its NIC can do ESP processing for the tunnel-mode portion of a packet
  • Whether its NIC can do ESP processing for send packets
  • Whether its NIC can do ESP processing for receive packets


Reporting a NIC's TCP-Packet-Segmentation Capabilities

The miniport driver specifies its NIC's packet-segmentation capabilities in an NDIS_TASK_TCP_LARGE_SEND structure. The miniport driver overlays this structure onto the TaskBuffer of an NDIS_TASK_OFFLOAD structure that the miniport driver returns in the InformationBuffer in response to a query of OID_TCP_TASK_OFFLOAD.

The NDIS_TASK_TCP_LARGE_SEND structure is defined as follows:

typedef struct _NDIS_TASK_TCP_LARGE_SEND
{
    ULONG      Version;
    ULONG      MaxOffLoadSize;
    ULONG      MinSegmentCount;
    BOOLEAN    TcpOptions;
    BOOLEAN    IpOptions;
} NDIS_TASK_TCP_LARGE_SEND, *PNDIS_TASK_TCP_LARGE_SEND;

The miniport driver must specify the following in the NDIS_TASK_TCP_LARGE_SEND structure:

  • The MaxOffLoadSize, which is the maximum bytes of user data that the TCP/IP transport can pass to the miniport driver in a large TCP packet.
  • The MinSegmentCount, which is the minimum number of segments that a large TCP packet must be divisible by before the TCP/IP transport can offload it to the miniport driver's NIC for segmentation.
  • Whether its NIC can segment a large TCP packet that contains TCP options
  • Whether its NIC can segment a large TCP packet that contains IP options.


Enabling Task-Offload Capabilities

The TCP/IP transport enables a NIC's task-offload capabilities by setting OID_TCP_TASK_OFFLOAD. In this set operation, the TCP/IP transport passes, in the InformationBuffer, an NDIS_TASK_OFFLOAD_HEADER structure followed immediately by an NDIS_TASK_OFFLOAD structure for each offload task that it is enabling.

The miniport driver must examine each NDIS_TASK_OFFLOAD structure in the InformationBuffer to determine which offload tasks (checksum, IP Security, and/or large packet segmentation) are being enabled. The miniport driver must also examine the task-specific structure (NDIS_TASK_TCP_IP_CHECKSUM, NDIS_TASK_IPSEC, or NDIS_TASK_TCP_LARGE_SEND) in the TaskBuffer of each NDIS_TASK_OFFLOAD structure to determine which specific capabilities for a particular offload task are being enabled.

The TCP/IP transport enables all offload capabilities for a NIC with a single set of OID_TCP_TASK_OFFLOAD. The miniport driver must fail any subsequent attempts to set OID_TCP_TASK_OFFLOAD.


Disabling Task-Offload Capabilities

To disable all of a NIC's task-offload capabilities, the TCP/IP transport sets OID_TCP_TASK_OFFLOAD, passing only an NDIS_TASK_OFFLOAD_HEADER in the InformationBuffer. The TCP/IP transport sets the OffsetFirstTask member of the NDIS_TASK_OFFLOAD_HEADER to zero.


Accessing Per-Packet Information

The TCP/IP transport and a miniport driver use a packet's per-packet information to pass information about task offload operations to each other. Per-packet information is out-of-band data specified by an NDIS_PACKET_EXTENSION structure, which is defined as follows:

typedef struct _NDIS_PACKET_EXTENSION
{
    PVOID  NdisPacketInfo[MaxPerPacketInfo];
} NDIS_PACKET_EXTENSION, *PNDIS_PACKET_EXTENSION;\

Every packet descriptor allocated with NdisAllocatePacket has an associated NDIS_PACKET_EXTENSION structure. This structure contains an array of pointers (PVOIDs), each of which points to or contains a particular type of per-packet information associated with the packet descriptor.

To access per-packet information, drivers should use the NDIS_PER_PACKET_INFO_FROM_PACKET macro. The NDIS_PER_PACKET_INFO_FROM_PACKET macro is defined as follows:

PVOID
    NDIS_PER_PACKET_INFO_FROM_PACKET(
        IN PNDIS_PACKET  Packet,
        IN NDIS_PER_PACKET_INFO InfoType
        );

This macro returns a pointer that points to or contains the specified type of per-packet information for a specified packet. The InfoType values that pertain offload tasks are TcpIpCheckSumPacketInfo, IpSecPacketInfo, and TcpLargeSendPacketInfo. These values are identical to the index values (described above) that return pointers or values from the NdisPacketInfo array in the NDIS_PACKET_EXTENSION structure. For example, if the specified InfoType is TcpIpCheckSumPacketInfo, the macro returns a pointer to an NDIS_TCP_IP_CHECKSUM_PACKET_INFO structure associated with the given packet descriptor. A driver can call this macro once for each type of per-packet information that it needs to access.

Alternatively, drivers can use the NDIS_PACKET_EXTENSION_FROM_PACKET macro to access per-packet information. The NDIS_PACKET_EXTENSION_FROM_PACKET macro is defined as follows:

PNDIS_PACKET_EXTENSION
    NDIS_PACKET_EXTENSION_FROM_PACKET(
        IN PNDIS_PACKET  Packet
        );

This macro returns a pointer to the NDIS_PACKET_EXTENSION structure associated with the given packet descriptor. After obtaining the pointer to the NDIS_PACKET_EXTENSION structure, the driver can use the appropriate array index to access a particular type of per-packet information. The index values that pertain to offload tasks are as follows:

TcpIpCheckSumPacketInfo
Indexes a pointer that points to an NDIS_TCP_IP_CHECKSUM_PACKET_INFO structure. This structure specifies per-packet information for checksum operations offloaded to a miniport driver.
IpSecPacketInfo
Indexes a pointer that points to an NDIS_IPSEC_PACKET_INFO structure. This structure specifies per-packet information for IP Security operations offloaded to a miniport driver.
TcpLargeSendPacketInfo
Indexes a pointer that contains a ULONG value used to offload the segmentation of large TCP packets.


Offloading TCP/IP Checksum Tasks

TCP/IP checksum tasks cannot be offloaded to a load-balancing miniport driver. For more information on load balancing, see Load Balancing and Fail Over.

Before passing to the miniport driver a packet descriptor for a packet on which the miniport driver will perform one or more checksum tasks, the TCP/IP transport specifies the checksum information associated with the packet descriptor. This information is specified by an NDIS_TCP_IP_CHECKSUM_PACKET_INFO structure, which is part of the per-packet information (extended out-of-band data) associated with the packet descriptor.

The NDIS_TCP_IP_CHECKSUM_PACKET_INFO structure is defined as follows:

typedef struct _NDIS_TCP_IP_CHECKSUM_PACKET_INFO
{
  union
  {
    struct
    {
      ULONG    NdisPacketChecksumV4:1;
      ULONG    NdisPacketChecksumV6:1;
      ULONG    NdisPacketTcpChecksum:1;
      ULONG    NdisPacketUdpChecksum:1;
      ULONG    NdisPacketIpChecksum:1;
    } Transmit;

    struct
    {
      ULONG   NdisPacketTcpChecksumFailed:1;
      ULONG   NdisPacketUdpChecksumFailed:1;
      ULONG   NdisPacketIpChecksumFailed:1;
      ULONG   NdisPacketTcpChecksumSucceeded:1;
      ULONG   NdisPacketUdpChecksumSucceeded:1;
      ULONG   NdisPacketIpChecksumSucceeded:1;
      ULONG   NdisPacketLoopback:1;
    } Receive;

  ULONG    Value;
  };
} NDIS_TCP_IP_CHECKSUM_PACKET_INFO, *PNDIS_TCP_IP_CHECKSUM_PACKET_INFO;

Before offloading the checksum calculation for a TCP packet, the TCP/IP transport calculates the one's complement sum for the TCP pseudo-header. The TCP/IP transport calculates the one's complement sum across all the fields in the pseudo-header, including the source IP address, the destination IP address, the protocol field, and the TCP length for TCP packets. The TCP/IP transport places one's complement sum for the pseudo-header in the checksum field of the TCP header.

The one's complement sum for the pseudo-header provided by the TCP/IP transport gives the NIC a head start in calculating the real TCP checksum for the send packet. To calculate the real TCP checksum, the NIC calculates the variable part of the TCP checksum (for the TCP header and payload), adds this checksum to the one's complement sum for the pseudo-header calculated by the TCP/IP transport, and then calculates the 16-bit one's complement for the checksum. For more information on calculating such checksums, see RFC 793 and RFC 1122.

After receiving the packet descriptor in its MiniportSend, MiniportSendPackets, or MiniportCoSendPackets function, a miniport driver typically does the following checksum processing:

  1. The miniport driver calls the NDIS_GET_PACKET_PROTOCOL_TYPE macro to determine the packet's protocol.
  2. If the protocol ID returned by the macro is not NDIS_PROTOCOL_ID_TCP_IP, the miniport driver's NIC should not perform any checksum operations on the packet.
  3. If the returned protocol ID is NDIS_PROTOCOL_ID_TCP_IP, the miniport driver calls the NDIS_PER_PACKET_INFO_FROM_PACKET macro with an InfoType of TcpIpCheckSumPacketInfo to obtain a pointer to the NDIS_TCP_IP_CHECKSUM_PACKET_INFO structure. Alternatively, the miniport driver can call the NDIS_PACKET_EXTENSION_FROM_PACKET macro to obtain a pointer to the NDIS_PACKET_EXTENSION structure. The miniport driver can then use the TcpIpCheckSumPacketInfo array index to obtain a pointer to the NDIS_TCP_IP_CHECKSUM_PACKET_INFO structure.
  4. The miniport driver tests the NdisPacketChecksumV4 flag in the NDIS_TCP_IP_CHECKSUM_PACKET_INFO structure. If the NdisPacketChecksumV4 flag is not set, the miniport driver's NIC should not perform any checksum operations on the packet.
  5. If the NdisPacketChecksumV4 flag is set, the miniport driver tests the NdisPacketTcpChecksum, NdisPacketUdpChecksum, and NdisPacketIpChecksum flags to determine which checksums its NIC should calculate for the packet.
  6. The miniport driver passes the packet to its NIC, which calculates the appropriate checksums for the packet. If a packet has both a tunnel IP header and a transport IP header, a NIC that supports IP checksum offloads performs IP checksum tasks only on the tunnel header. The TCP/IP transport performs IP checksum tasks on the transport IP header.

Before indicating up a receive packet on which it performs checksum tasks, the miniport driver validates the appropriate checksum(s) and sets the appropriate NdisPackeXxxChecksumFailed and/or NdisPacketXxxChecksumSucceeded flags in the NDIS_TCP_IP_CHECKSUM_PACKET_INFO structure.


Offloading IP Security Tasks

This discussion assumes an understanding of IP Security, as specified in the following RFCs and drafts published by the IP Security Working Group of the Internet Engineering Task Force (IETF):

IPSec Architecture:

  • Security Architecture for the Internet Protocol (RFC 2401)

Authentication Header (AH):

  • IP Authentication Header (RFC 2402)
  • The Use of HMAC-MD5-96 within ESP and AH (RFC 2403)
  • The Use of HMAC-SHA-1-96 within ESP and AH (RFC 2404)
  • HMAC-MD5 IP Authentication with Replay Prevention (RFC 2085)

Encapsulating Security Payload (ESP):

  • IP Encapsulating Security Payload (ESP) (RFC 2406)
  • The ESP CBC-Mode Cipher Algorithms (RFC 2451)
  • The ESP DES-CBC Cipher Algorithm with Explicit IV (RFC 2405)
  • The NULL Encryption Algorithm and its Use with IPSec (RFC 2410)

Requirements and Restrictions That Apply to IP Security Offloads

The following requirements and restrictions apply to IP Security offloads:

  • The NIC must maintain the Security Association (SA) tables. This improves performance by eliminating the need to include keys or other information needed for AH and ESP processing in send packets.
  • A NIC may be able to process both AH and ESP payloads for a single packet. In this case, the NIC must support the following possible combinations of integrity (authentication) algorithms for AH and ESP:
    AH | ESP
    MD5 | MD5
    SHA 1 | SHA 1
    MD5 | SHA 1
    SHA 1 | MD5
    MD5 | Null (only if the NIC supports null encryption)
    SHA 1 | Null (only if the NIC supports null encryption)

  • A NIC that supports DES algorithms must generate the IV required by these algorithms.
  • The only IP security tasks performed by a NIC are processing encrypted AH checksums and/or ESP checksums and encrypting and decrypting ESP payloads. For a send packets, the TCP/IP transport creates all headers, padding, and replay numbers, and chooses SPI values unique to destination address/IP Security protocol pairs. For receive packets, the TCP/IP transport performs inbound policy checks, handles replay detection and prevention, and handles audit events.
  • For a send packet, the TCP/IP transports does not provide explicit offsets — for example, to indicate the start of encrypted data — since the offload driver can easily determine such information from the particular security association (SA) that it uses to process the packet.
  • A packet with IP Security protocols must have authentication information in an authentication header (AH) and/or the encapsulating security payload (ESP) header. It is not permissible for a IP Security packet to have no authentication whatsoever.
  • IP Security tasks are not offloaded for send packets that require IP fragmentation or for receive packets that require reassembly from IP fragmentation.
  • IP Security tasks are not offloaded for send and received packets that pass through a load balancing miniport driver. For more information on load balancing, see Load Balancing and Fail Over.

Adding a Security Association to a NIC

After the TCP/IP transport has determined that a NIC can perform IP security operations (see Reporting a NIC's IP Security Capabilities), the transport must request the NIC's miniport driver to add one or more inbound and outbound Security Associations (SAs) to the NIC before the transport can offload IP Security tasks to the NIC. To request that a miniport driver add one or more SAs to its NIC, the TCP/IP transport sets OID_TCP_TASK_IPSEC_ADD_SA.

Deleting a Security Association from a NIC

If necessary, the TCP/IP transport can set OID_TCP_TASK_IPSEC_DELETE_SA to request that the miniport driver delete a Security Association (SA) from its NIC.

To make room for another SA on the NIC, the miniport driver can set SA_DELETE_REQ in the NDIS_IPSEC_PACKET_INFO structure for a receive packet. The TCP/IP transport subsequently issues OID_TCP_TASK_IPSEC_DELETE_SA once to delete the inbound security association (SA) over which the packet was received and once again to delete the outbound SA that corresponds to the deleted inbound SA. The miniport driver's NIC must not remove either of these SAs before receiving the corresponding OID_TCP_TASK_IPSEC_DELETE_SA request. The miniport driver can set SA_DELETE_REQ independently of CRYPTO_DONE.

Offloading IP Security Tasks in the Send Path

Before passing to the miniport driver a packet descriptor for a packet on which the miniport driver's NIC will perform IP Security tasks, the TCP/IP transport updates the IP Security information associated with the packet descriptor. The TCP/IP transport specifies this information in an NDIS_IPSEC_PACKET_INFO structure, which is part of the per-packet (extended out-of-band) data associated with the packet descriptor.

The NDIS_IPSEC_PACKET_INFO structure is defined as follows:

typedef struct _NDIS_IPSEC_PACKET_INFO
{
    union
    {
        struct
        {
            NDIS_HANDLE    OffloadHandle;
            NDIS_HANDLE    NextOffloadHandle;
        } Transmit;

        struct
        {
            ULONG    SA_DELETE_REQ:1;
            ULONG    CRYPTO_DONE:1;
            ULONG    NEXT_CRYPTO_DONE:1;
            ULONG    CryptoStatus;
        } Receive;
    };
} NDIS_IPSEC_PACKET_INFO, *PNDIS_IPSEC_PACKET_INFO;

The TCP/IP transport supplies an OffloadHandle, which specifies the handle to the outbound SA for the transport (end-to-end connection) portion of the send packet. If the packet is going to be transmitted through a tunnel, the TCP/IP transport also supplies the NextOffloadHandle, which specifies the handle to the outbound SA for the tunnel portion of the send packet.

After receiving the packet descriptor in its MiniportSend, MiniportSendPackets, or MiniportCoSendPackets function, the miniport driver can call the NDIS_PER_PACKET_INFO_FROM_PACKET macro with an InfoType of IpSecNdisTask to obtain a pointer to the NDIS_IPSEC_PACKET_INFO structure associated with the packet descriptor. Alternatively, it can call the NDIS_PACKET_EXTENSION_FROM_PACKET macro to obtain a pointer to the NDIS_PACKET_EXTENSION structure associated with the packet descriptor. The miniport driver can then use the IpSecPacketInfo array index to obtain a pointer to the NDIS_IPSEC_PACKET_INFO structure.

When performing IP security processing on a send packet, the NIC calculates the AH and/or ESP encryption checksums for the packet and, if the packet contains an ESP payload, encrypts the packet. The TCP/IP transport has already framed the packet, padded it, if necessary, and assigned it a sequence number and SPI.

Offloading IP Security Tasks in the Receive Path

When performing IP security processing on a receive packet, a NIC decrypts the packet if the packet contains an ESP payload and calculates the AH and/or ESP encryption checksum(s) for the packet. Before indicating the packet up to the TCP/IP transport, the miniport driver should call the NDIS_PER_PACKET_INFO_FROM_PACKET macro with an InfoType of IpSecNdisTask to obtain a pointer to the NDIS_IPSEC_PACKET_INFO structure associated with a packet. Alternatively, it can call the NDIS_PACKET_EXTENSION_FROM_PACKET macro to obtain a pointer to the NDIS_PACKET_EXTENSION structure associated with the packet descriptor.

The miniport driver sets the CRYPTO_DONE flag in the NDIS_IPSEC_PACKET_INFO structure to indicate that it's NIC performed IP security checking on at least one IP security payload in the receive packet. If the miniport driver's NIC performed IP security checking on both the tunnel and transport portions of a receive packet, the miniport driver also sets the NEXT_CRYPTO_DONE flag in the NDIS_IPSEC_PACKET_INFO structure. NEXT_CRYPTO_DONE is set only if a packet has both tunnel and transport IP Security payloads; otherwise, NEXT_CRYPTO_DONE is set to zero. The miniport driver must also supply a CryptoStatus value in the NDIS_IPSEC_PACKET_INFO structure to indicate the results of the IP Security check(s). If the NIC detects a checksum failure or a decryption failure, the miniport driver must indicate up the receive packet in whatever form it is in and specify the appropriate CryptoStatus.

After the miniport driver indicates the packet to the TCP/IP transport, the transport examines the results of the IP security checks performed by the NIC, checks the sequence number(s) for the packet, and determines what to do with a packet that has failed the checksum and/or sequencing tests.

Impact of Network Interface Changes on IP Security Offloads

The following changes in the network interface affect the offloading of IP Security tasks:

  • A NIC is removed.

    Before a NIC to which tasks are being offloaded is removed from the system, its miniport driver should delete all Security Associations (SAs) from the NIC. The miniport driver does not have to request the TCP/IP transport to delete the SAs.

  • A routing interface is changed.

    When network traffic is routed through a new interface, the TCP/IP stack temporarily performs IP Security tasks itself until it has added the appropriate SAs to the NIC used in the new interface. The TCP/IP stack adds an SA to a NIC by issuing OID_TCP_TASK_IPSEC_ADD_SA. After the SAs on the NIC used for the old interface expire, the TCP/IP transport issues OID_TCP_TASK_IPSEC_DELETE_SA as many times as necessary to request that the NIC's miniport driver delete the SAs from the NIC.


Offloading the Segmentation of Large TCP Packets

A NIC that supports the segmentation of large TCP packets (TCP packets that are larger than the maximum transmission unit of the network medium), must also be able to:

  • Calculate IP checksums for send packets that contain IP options
  • Calculate TCP checksums for send packets that contain TCP options

If a miniport driver indicates that its NIC supports large-TCP-packet segmentation, the TCP/IP stack assumes that the NIC can perform this segmentation on large TCP packets that contain IP options and/or TCP options.

The TCP/IP transport offloads only those large TCP packets that meet the following criteria:

  • The packet is a TCP packet. The TCP/IP transport does not offload large UDP packets for segmentation.
  • The packet must be divisible by at least the minimum number of segments specified by the miniport driver. For more information, see Reporting a NIC's TCP Packet Segmentation Capabilities.
  • The packet is not a loopback packet.
  • The packet is not going to be sent through a tunnel.
  • The packet is not going to be sent to a load-balancing miniport driver. For more information on load balancing, see Load Balancing and Fail Over.

Before offloading a large TCP packet for segmentation, the TCP/IP transport does the following:

  • Updates the large-packet segmentation information associated with the packet descriptor. This information is a ULONG value that is part of the per-packet information associated with the packet descriptor. For more information on per-packet information, see NDIS_PACKET_EXTENSION. The TCP/IP transport sets this ULONG value to the maximum segment size (MSS), which is equivalent to the current maximum transmission unit (MTU). The MTU is the maximum number of user data bytes that the miniport driver can currently include in a single packet.
  • Writes the total length of the large TCP packet to the Total Length field of the packet's IP header. The total length includes the following: the length of the IP header, the length of the IP options if they are present; the length of the TCP header, the length of the TCP options if they are present; and the length of the TCP payload.
  • Calculates a one's complement sum for the TCP pseudo-header and writes this sum to the checksum field of the TCP header. The TCP/IP transport calculates the one's complement sum over the following fields in the pseudo-header: the source IP address, the destination IP address, and the protocol field. The one's complement sum for the pseudo-header provided by the TCP/IP transport gives the NIC a head start in calculating the real TCP checksum for each packet that the NIC derives from the large TCP packet without having to examine the IP header.
  • Writes the correct sequence number to the sequence number field of the TCP header. The sequence number identifies the first byte of the TCP payload.

After the miniport driver has obtained the packet descriptor in its MiniportSend, MiniportSendPackets, or MiniportCoSendPackets function, it can call the NDIS_PER_PACKET_INFO_FROM_PACKET macro with an InfoType of TcpLargeSendPacketInfo to obtain the MSS value written by the TCP/IP transport. Alternatively, the miniport driver can call the NDIS_PACKET_EXTENSION_FROM_PACKET macro to obtain a pointer to the NDIS_PACKET_EXTENSION structure. The miniport driver can then use the TcpLargeSendPacketInfo array index to obtain the MSS value.

The miniport driver obtains the total length of the large packet from the packet's IP header and uses the MSS value to segment the large TCP packet into smaller packets. Each of the smaller packets contains MSS or less user data bytes.

The miniport driver affixes IP and TCP headers to each segment derived from the large packet. The miniport driver must calculate the IP and TCP checksums for these packet headers. To calculate the TCP checksum for each packet derived from the large TCP packet, the NIC calculates the variable part of the TCP checksum (for the TCP header and TCP payload), adds this checksum to the one's complement sum for the pseudo-header calculated by the TCP/IP transport, and then calculates the 16-bit one's complement for the checksum. For more information on calculating such checksums, see RFC 793 and RFC 1122.

The following assumptions and restrictions apply to the processing of IP and TCP headers:

  • The MF bit in the IP header of the large TCP packet offloaded by the TCP/IP transport will not be set, and the Fragment Offset in the IP header will be zero.
  • The URG, RST, and SYN flags in the TCP header of the large TCP packet will not be set, and the urgent offset (pointer) in the IP header will be zero.
  • If the FIN bit in the TCP header of the large packet is set, the miniport driver must set this bit in the TCP header of the last packet that it creates from the large TCP packet.
  • If the PSH bit in the TCP header of the large TCP packet is set, the miniport driver must set this bit in the TCP header of the last packet that it creates from the large TCP packet.
  • If the large TCP packet contains IP options and/or TCP options, the miniport driver copies these options, unaltered, to each packet derived from the large TCP packet. Specifically, the NIC will not increment the Time Stamp option.

The miniport driver must send packets in the order that it receives them from the TCP/IP transport. However, the miniport driver can interleave packets created from a large TCP packet with other packets.

The miniport driver must also preserve the order of the ACKs that it receives in response to the transmission of packets derived from the large TCP packet. The miniport driver must indicate up packets that contain such ACKs in the order that are received so that the fast retransmit algorithms, fast recovery algorithms, and selective ACK algorithms performed by the TCP/IP transport work correctly.

When processing a large TCP packet, the miniport driver is responsible only for segmenting the packet and affixing IP and TCP headers to the packets derived from the large TCP packet. All other tasks (for example, adjusting the send window size based on the remote host's receive window size) are performed by the TCP/IP transport.

Before completing the send operation for the large packet (for example, with NdisMSendComplete or NdisMCoSendComplete), the miniport driver writes the ULONG value (the per-packet information for large-TCP-packet offloads) with the total number of TCP user data bytes sent in all packets created from the large TCP packet.


Combinations of Offloads

Which tasks the TCP/IP transport actually offloads to a NIC for a particular packet depends on the offload capabilities reported by the NIC's miniport driver and whether an IP Security policy is active on the system:

  • If no IP Security policy is active on a system, the TCP/IP stack offloads checksum tasks and/or large-TCP-packet segmentation if the NIC's miniport driver indicated that the NIC supports such tasks.
  • If an IP Security policy is active on the system, the TCP/IP stack does not offload checksum tasks and/or large-TCP-packet segmentation. The TCP/IP stack offloads IP Security tasks if the NIC's miniport driver indicated that the NIC supports such tasks.
  • If an IP Security policy becomes active on the system, the TCP/IP stack immediately stops offloading checksum tasks and/or large-TCP-packet segmentation and begins offloading IP Security tasks if the NIC's miniport driver indicated that the NIC supports such tasks.
  • If IP Security becomes inactive on the system, the TCP/IP stack resumes offloading checksum and/or large-TCP-packet segmentation to the NIC.

Future Windows 2000 service packs and releases, as well as later operating systems, may support both checksum offloads and IP Security offloads for the same packet. Therefore, if a NIC supports both checksum and IP Security offloads, it must be able to perform both checksum and IP Security operations on the same packet.

The following table summarizes the tasks that are offloaded, given a particular set of enabled task-offload capabilities:

Offload Capabilities |  |  |  | Offloaded Tasks
IP Cksm | TCP Cksm | Large TCP | IPSec | IP Cksm | TCP Cksm | Large TCP | IPSec
Off | Off | Off | Off | No | No | No | No
Off | Off | Off | On | No | No | No | Yes2
Off | Off | On | Off | No | No | Yes1 | No
Off | Off | On | On | No | No | Yes1 | Yes2
Off | On | Off | Off | No | Yes1 | No | No
Off | On | Off | On | No | Yes1 | No | Yes2
Off | On | On | Off | No | Yes1 | Yes1 | No
Off | On | On | On | No | Yes1 | Yes1 | Yes2
On | Off | Off | Off | Yes | No | No | No
On | Off | Off | On | Yes1 | No | No | Yes2
On | Off | On | Off | Yes | No | Yes1 | No
On | Off | On | On | Yes1 | No | Yes1 | Yes2
On | On | Off | Off | Yes | Yes1 | No | No
On | On | Off | On | Yes1 | Yes1 | No | Yes2
On | On | On | Off | Yes | Yes1 | Yes1 | No
On | On | On | On | Yes1 | Yes1 | Yes1 | Yes2
1. The task is offloaded if the system does not have an active IP Security policy. 2. IP Security is not offloaded for send packets that require IP fragmentation or for receive packets that require reassembly from IP fragmentation. Also, IP Security is offloaded only if the appropriate IP Security capabilities are enabled for the NIC. For example, if the ISAKMP/Oakley (IKE) negotiation between the system and a peer specifies an algorithm combination for the security association that the NIC does not support, IP security is not offloaded. For more information, see Offloading IP Security Tasks.


Using Registry Values to Enable and Disable Task Offloading

When debugging a driver's task-offload functionality, it can be useful to enable or disable task offloading. Two registry values control this aspect of task offloading:

  • HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Paramters\DisableTaskOffload

    Setting this value to zero disables all task offloads from the TCP/IP transport. Setting this value to 1 enables all task offloads.

  • HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Ipsec\EnabledOffload

Setting this value to zero disables IP Security offloads from the TCP/IP transport. The offloading of TCP/IP checksum tasks and the offloading of large TCP packets for segmentation are not affected. Setting this value to 1 enables IP Security offloads.


Load Balancing and Fail Over

Load balancing and fail over (LBFO) functionality can improve the reliability and performance of a miniport driver's network adapters. A miniport driver can use LBFO to balance its workload by distributing the workload over the miniport driver's bundle of adapters. That is, the miniport driver can use LBFO to off-load tasks from the primary adapter to any secondary adapter. For example, suppose a protocol driver requests a miniport driver to transmit packets. To balance packet-transmission workload, that miniport driver can use its primary adapter to transmit some of those packets and can off-load some of those packet transmissions to secondary adapters. LBFO functionality also makes it possible for a miniport driver to set one of the secondary adapters to take over packet transfers and information requests if the primary adapter fails.

The following topics describe LBFO and how to implement miniport drivers to support LBFO:

About LBFO

Specifying Support of LBFO

Implementing LBFO in a Miniport Driver

For information on adding LBFO functionality to a miniport driver, see the readme for the Passthru driver. This miniport driver is a sample intermediate miniport driver in the Microsoft® Windows DDK.


About LBFO

A miniport driver can be implemented to support LBFO. Such a miniport driver can balance its workload of packet transfers by distributing the workload over its bundle of miniport instances and can set a secondary miniport instance to take over packet indications and information requests if the primary miniport instance fails. The bundle of miniport instances that a miniport driver manages can include miniport instances from both single-port and multiple-port NICs.

NDIS only exposes the miniport driver's primary miniport instance to transports. If transports request to send packets to the miniport driver or request to set or query information in the miniport driver, NDIS passes these requests to the primary miniport instance.

Only miniport instances that have been initialized by the same miniport driver can be part of an LBFO solution. In order for two or more miniport instances that have been initialized by different miniport drivers to be part of an LBFO solution, an intermediate miniport driver must be implemented to provide LBFO for those miniport instances.

A secondary miniport instance should only use the handle to the primary miniport instance to indicate packets up to bound transports.

The primary miniport instance handles all requests for information that transports make. However, NDIS can send specific requests to secondary miniport instances. For example, NDIS might query all miniport instances for their media connectivity. Secondary miniport instances must process and respond to this query.

A miniport driver must specify that it implements LBFO when it is installed. To specify LBFO support, the miniport driver's information (INF) file specifies the BundleId keyword and a case-insensitive string value to identify the miniport driver's bundle of adapters. The registry is then configured with this information.

During initialization, the miniport driver must determine if a miniport instance that is being initialized belongs to an existing bundle. To determine if a miniport instance is a member of the bundle, the miniport driver retrieves the string value from the BundleId keyword under the miniport instance's registry key. Each miniport instance should copy the bundle-identifier value to the miniport instance's internal structure.

The miniport instance should then search through the internal structures of the miniport instances that have already been initialized to locate a miniport instance that has an identical bundle-identifier value. If the miniport instance does not locate a match, it becomes the bundle's primary miniport instance. This situation occurs if the miniport instance is the first miniport instance from the bundle to be initialized. If the miniport instance locates an identical bundle-identifier value, the miniport instance should set itself to the secondary role in relation to the primary miniport instance. The miniport driver can set multiple secondary miniport instances, that is, multiple secondary miniport instances can exist in a bundle.

A miniport driver must provide LBFO for packet transfers and information requests, as appropriate. The following describes examples of a miniport driver providing LBFO:

  • The miniport driver reroutes packet transfers and information requests to secondary miniport instances.
  • If the bundle's primary miniport instance fails, the miniport driver can remove the primary miniport instance from the bundle and promote the secondary miniport instance to the primary role.


Specifying Support of LBFO

A miniport driver specifies that it implements LBFO during installation. To specify LBFO support, the miniport driver's information (INF) file must contain the BundleId keyword and a case-insensitive string value (REG_SZ). This string value identifies the miniport driver's bundle of adapters. The registry is configured using the bundle-identifier information.

The miniport driver's bundle-identifier value must be exposed as an adapter property through the Network applet, a Control Panel application, so that if a user changes the property, the NIC is stopped and then restarted. A user would change the bundle-identifier property to adjust bundle membership.

The following is an example of an add-registry-section in a miniport driver's INF file that adds the BundleId subkey to the Ndi\params key and gives the ParamDesc (parameter description) for BundleId a string value of "Bundle1".

[a1.params.reg]
HKR, Ndi\params\BundleId, ParamDesc, 0, "Bundle1"

For more information on adding keys and values to a miniport driver's INF file, see Add-registry-sections. For more information on specifying adapter configuration parameters and values, see Specifying Configuration Parameters for the Advanced Properties Page and Specifying Custom Property Pages for Network Adapters.


Implementing LBFO in a Miniport Driver

In order to support LBFO, a miniport driver must be implemented to perform initialization and workload balancing operations. A miniport driver that supports LBFO must also be able to promote a secondary miniport instance in the event that the primary miniport instance fails. These operations are described in the following topics:

Initializing a Bundle of Miniport Instances

Balancing a Miniport Driver's Workload

Promoting a Secondary Miniport Driver After the Primary Miniport Driver Fails


Initializing a Bundle of Miniport Instances

NDIS calls a miniport driver's MiniportInitialize function once for each network adapter that the driver manages. To support LBFO, MiniportInitialize must determine if the miniport instance being initialized belongs to an existing bundle.

To determine if a miniport instance is a member of the bundle, MiniportInitialize first calls the NdisOpenConfiguration function to obtain the handle for a registry key in which the miniport instance's configuration parameters are stored. Next, MiniportInitialize calls the NdisReadConfiguration function to retrieve the string value (REG_SZ) from the BundleId keyword under the miniport instance's registry key. Each miniport instance should copy the bundle-identifier value to its internal structure. This internal structure is also known as MiniportAdapterContext. Each miniport instance should also copy its MiniportAdapterHandle to its MiniportAdapterContext. NDIS uses the MiniportAdapterHandle to refer to the associated miniport instance.

After the miniport instance retrieves the bundle-identifier value, the miniport instance should search through the internal structures of miniport instances that have already been initialized to locate a miniport instance that has an identical bundle-identifier value. To perform this search, the miniport instance inspects each miniport instance's MiniportAdapterContext. The miniport driver sets the miniport instance to either the primary or a secondary role, as described following:

  • The miniport instance is the first miniport instance from the bundle to be initialized. In other words, the miniport instance could not locate an identical bundle-identifier value. In this situation, the miniport instance defaults to become the primary.
  • The miniport instance locates an identical bundle-identifier value. MiniportInitialize should call the NdisMSetMiniportSecondary function to set the miniport instance to the secondary role in relation to the primary miniport instance. In this call, the miniport instance passes its handle in the MiniportAdapterHandle parameter and the handle to the primary miniport instance that has already been initialized in the PrimaryMiniportAdapterHandle parameter. The miniport instance retrieves the handle to the primary miniport instance from the primary miniport instance's MiniportAdapterContext.

Multiple secondary miniport instances can exist in a bundle. MiniportInitialize can call NdisMSetMiniportSecondary for multiple miniport instances during the initialization of each instance to set them all to secondary roles in relation to the primary miniport instance.

MiniportInitialize can call NdisMSetMiniportSecondary only if the miniport instance can potentially belong to an existing bundle of miniport instances that were initialized by the same miniport driver. Before MiniportInitialize calls NdisMSetMiniportSecondary, the miniport instance cannot be considered as part of an existing bundle. A miniport instance becomes a secondary member of an existing bundle only after a successful call to NdisMSetMiniportSecondary.


Balancing a Miniport Driver's Workload

A miniport driver that previously initialized multiple miniport instances and made those miniport instances members of a bundle can use those miniport instances to balance the driver's workload.

NDIS only exposes the primary miniport instance to transports. If transports request to send packets to a miniport driver or if they request to set or query information in a miniport driver, NDIS will pass these requests to the primary miniport instance. To balance the miniport driver's workload, the driver should be implemented to off-load some of these requests to secondary miniport instances. If the miniport driver requires secondary miniport instances to perform tasks that are associated with requests, the driver can reroute those requests to the secondary miniport instances. The miniport driver should use the handle to the primary miniport instance to subsequently complete those requests, regardless of whether the primary or a secondary miniport instance actually executes the requests.

However, if NDIS sends a request to a secondary miniport instance, that secondary miniport instance should use the handle to itself to complete the request.


Promoting a Secondary Miniport Driver After the Primary Miniport Driver Fails

A miniport driver that supports LBFO can promote a secondary miniport adapter to the primary role if the primary adapter fails. If the miniport driver's primary adapter fails, the driver can call the NdisMRemoveMiniport function to remove the primary miniport adapter from the bundle. The driver can then call the NdisMPromoteMiniport function to promote the secondary miniport adapter to the primary role. NDIS will forward subsequent requests from transports to the miniport driver using the new miniport adapter as the primary.


Miniport Driver with a WDM Lower Interface

This section describes how to implement an NDIS-WDM miniport driver. Such a miniport driver:

  • Uses a Windows Driver Model (WDM) lower interface.
  • Can call both NDIS and non-NDIS functions. However, whenever possible, the miniport driver should call NDIS functions.
  • Can initialize a miniport instance that is used to control devices attached to a particular bus and that communicates with those devices over that bus.

For example, a miniport driver that controls devices on either Universal Serial Bus (USB) or IEEE 1394 (firewire) buses must expose a standard NDIS miniport driver interface at its upper edge and use the class interface for the particular bus at its lower edge. Such a miniport driver communicates with devices that are attached to the bus by sending I/O request packets (IRPs) to the bus.

The following topics describe how to implement a miniport driver that uses a WDM lower edge:

Miniport Driver with a WDM Lower Edge

Registering Miniport Driver Functions for WDM Lower Edge

Initializing a Miniport Driver with a WDM Lower Edge

Issuing Commands to Communicate with Devices

Implementation Tips and Requirements for WDM Lower Edge

Compile Flags for WDM Lower Edge

Windows 98/Me Compatibility Notes

Power Management for WDM Lower Edge

Installing NDIS-WDM Miniport Drivers


Miniport Driver with a WDM Lower Edge

The following diagram shows a miniport driver that interfaces with the USB driver.

Miniport Driver For USB


Registering Miniport Driver Functions for WDM Lower Edge

A miniport driver that has a WDM lower edge must call the NdisMRegisterMiniport function in its DriverEntry routine to register certain entry-point functions with the NDIS library. These entry-point functions compose the miniport driver's upper edge and are described in Registering MiniportXxx Functions. However, a miniport driver that has a WDM lower edge is not required to set up certain entry-point functions. For example, the following entry-point functions are not set up for the following reasons:

  • MiniportISR, MiniportHandleInterrupt, MiniportEnableInterrupt, MiniportDisableInterrupt

    Because the miniport driver does not receive interrupts from a physical NIC, it does not require these entry-point routines. The driver for the particular bus receives interrupts when packets arrive on the bus that are intended for the miniport driver. The bus driver then notifies the miniport driver.

  • MiniportTransferData

    The miniport driver passes entire packets when it indicates those packets. Higher-level drivers will never initiate calls to this entry-point routine to transfer the remaining contents of packets, so it is not specified.

  • MiniportAllocateComplete

    Since the miniport driver does not allocate shared memory, a completion entry-point routine is not specified.

  • MiniportCheckForHang

    The miniport driver can rely on NDIS to determine if its miniport instance is hung, based on sends and requests that time out, so this routine is not typically required.

  • MiniportShutdown

    The miniport driver does not set up a shut-down routine because the miniport instance has no hardware that must be shut down.


Initializing a Miniport Driver with a WDM Lower Edge

After a miniport driver has been loaded by the operating system, NDIS calls the miniport driver's MiniportInitialize function to initialize a miniport instance that the miniport driver manages. To communicate through a miniport instance that has a WDM lower edge, the miniport driver must retrieve specific information to set up its communications. During initialization of this miniport instance, the miniport driver must call the NdisMGetDeviceProperty function to retrieve device objects that are required to set up communication with the miniport instance through a WDM interface. In this call, the miniport driver passes the handle to the miniport instance in the MiniportAdapterHandle parameter and buffers that receive pointers to DEVICE_OBJECT structures. The miniport driver uses the retrieved pointer to the next-device object (NextDeviceObject parameter) to create and submit IRPs. For more information, see Handling IRPs.

A miniport driver with a WDM lower edge must be a deserialized miniport driver. A deserialized miniport driver manages its own queue of send and receive requests internally whenever it has insufficient resources to handle these requests immediately; if a miniport driver is not deserialized, NDIS manages this queue. An NDIS-WDM miniport driver must be deserialized because it sends and receives packets outside of the context of NDIS calls. During initialization of a miniport instance, an NDIS-WDM miniport driver must specify the deserialized feature. To specify this feature, the miniport driver must set the NDIS_ATTRIBUTE_DESERIALIZE flag when it calls the NdisMSetAttributesEx function.

Note that an NDIS-WDM miniport driver cannot be an intermediate driver—a driver that exposes a miniport driver interface at the top and a protocol driver interface at the bottom—so it should not set the NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER flag when it calls NdisMSetAttributesEx.


Issuing Commands to Communicate with Devices

A miniport driver with a WDM lower edge that controls devices on a bus issues commands to the bus interface to communicate with those devices. For more information, see Handling IRPs. See also the documentation for the particular bus-driver interface.


Implementation Tips and Requirements for WDM Lower Edge

This topic discusses tips and requirements for implementing an NDIS-WDM miniport driver that uses a WDM lower interface. Such a miniport driver can call both NDIS and non-NDIS functions. These non-NDIS functions include, for example, WDM-kernel-mode support routines and functions for a particular bus-driver interface.

When implementing an NDIS-WDM miniport driver, the following items should be observed:

  • Building an NDIS-WDM miniport driver requires that the NDIS_WDM flag is defined before the ndis.h header file is included. Defining the NDIS_WDM flag ensures that ndis.h automatically includes the appropriate WDM header file. The NDIS_WDM flag should be either embedded at the start of the miniport driver's source code or set in the miniport driver's sources file. An NDIS-WDM miniport driver requires a WDM header file in order to call kernel-mode functions such as IoCallDriver and IoAllocateIrp.
  • Function calls for a particular bus-driver interface require the header files for that bus driver.
  • Including NDIS and non-NDIS headers in the same source file is not recommended because they might not be compatible. That is, separate source files should be created for code that calls NDIS functions, and for code that calls non-NDIS functions.
  • An NDIS-WDM miniport driver should call appropriate NDIS functions to allocate and release resources unless the NDIS-WDM miniport driver allocates and releases resources as described in either of the following scenarios:
    • a resource, typically a memory resource, is allocated by the NDIS-WDM miniport driver and is later released by a non-NDIS entity such as a bus-driver interface
    • a resource, typically a memory resource, is allocated by a non-NDIS entity and is later released by the NDIS-WDM miniport driver

    For the preceding scenarios, the NDIS-WDM miniport driver should call the appropriate WDM functions to allocate or release resources for the non-NDIS entity.


Compile Flags for WDM Lower Edge

This topic lists compile flags that must be included in the sources file for an NDIS-WDM miniport driver in order to build the NDIS-WDM miniport driver. The following compile flags must be included:

  • -DNDIS_WDM=1

    Directs NDIS to include the appropriate WDM header file.

  • -DUSE_KLOCKS=1

    Directs spin locks of NDIS-WDM miniport drivers built for Windows 98/Me platforms to operate; otherwise, these spin locks do not operate.

As an alternative, compile flags can be embedded at the start of the miniport driver's source code before the ndis.h header file is included.


Windows 98/Me Compatibility Notes

NDIS-WDM miniport drivers built for Windows 98/Me platforms must indicate received packets, complete packet transmissions, indicate status, and complete requests in the context of NDIS-timer threads or NDIS-called functions. Typically, the NDIS-WDM miniport driver is notified about these operations through the driver's WDM lower interface. The NDIS-WDM miniport driver must queue such an operation, start another thread using an NDIS timer object with a time-out set to zero, and complete the operation in the new thread.

The following code snippet shows how to queue a packet that is received and then indicate this packet up the stack using an NDIS timer object:

// Code for queuing packet
// Acquire spinlock to Adapter structure.
// Queue NDIS_PACKET for the packet to the tail of the list of
// pending receives.
if (Adapter->IndicatingReceives == FALSE) {
    Adapter->IndicatingReceives = TRUE;
    NdisSetTimer(&Adapter->IndicateTimer, 0); // Start timer thread.
}
// Release spinlock;

// Code for timer thread (&Adapter->IndicateTimer function)
// Acquire spinlock to Adapter structure.
while (/* pending receive queue is not empty */) {
    // Dequeue NDIS_PACKET from pending receive queue.
    // Release spinlock.
    Status = NDIS_GET_PACKET_STATUS(pNdisPacket);
    NdisMIndicateReceivePacket(
        MiniportAdapterHandle,
        pNdisPacket,
        NumberOfPackets);
    if (Status == NDIS_STATUS_RESOURCES) {
        // Call own MiniportReturnPacket handler with the packet.
    }
    // Reacquire spinlock to Adapter structure.
}
Adapter->IndicatingReceives = FALSE;
// Release spinlock.


Power Management for WDM Lower Edge

NDIS handles all Plug and Play and power management IRPs on behalf of NDIS-WDM miniport drivers. Therefore, NDIS-WDM miniport drivers should respond to Plug and Play and power management OIDs, based on device capabilities, as described in Power Management for Miniport Drivers. For more information on these OIDs, see Plug and Play and Power Management OIDs.


Installing NDIS-WDM Miniport Drivers

When implementing the installation mechanism for an NDIS-WDM miniport driver, the following items should be observed:

  • Create an information (INF) file for a Net class of network component as described in Creating Network INF Files.
  • Include Plug and Play identifiers (ID) of devices as is typically done for any Net class of network component; however, make these IDs specific to the bus type to which the devices are attached.


IrDA Miniport Drivers

The Infrared Data Association (IrDA) has defined a half-duplex protocol for encoding data frames as infrared light pulses. Infrared transceivers are created to transmit and receive these infrared light pulses. These infrared transceivers consist of a transmitter light emitting diode (LED) and a receiver diode. The receiver diode is sensitive to transmissions of infrared light pulses that it receives from a remote infrared LED that is located a short distance away. The transmitter LED must transmit infrared light pulses to a remote receiver diode that is located at the same distance.

An infrared adapter is a type of network interface card (NIC) that combines an infrared transceiver with supporting hardware for encoding and decoding frames. An IrDA miniport driver is implemented to control an infrared NIC.

The following topics describe the architecture surrounding IrDA miniport drivers, features of IrDA miniport drivers, and the frame format of the IrDA media type that IrDA miniport drivers must support:

About IrDA Miniport Drivers

IrDA Architecture

IrDA Protocol Driver

IrDA Medium Features

IrLAP Frame Format

IrDA Miniport Driver Packet Coding Schemes

Sending and Receiving Packet Arrays

Plug and Play


About IrDA Miniport Drivers

The interface between IrDA hardware (infrared transceivers) and the core IrDA protocol stack is through Network Driver Interface Specification (NDIS) and IrDA miniport drivers. The IrDA protocol stack expects that IrDA hardware and IrDA miniport drivers handle framing, transparency, error detection, and support commands for sensing media activity and changing speed. IrDA miniport drivers are responsible for discarding incoming frames that contain bad cyclic redundancy checks (CRC); these frames must never be forwarded to the IrDA protocol stack.

The operating system supplies an implementation of the core IrDA protocol stack. The IrDA protocol stack is loaded dynamically by the Plug and Play system when an IrDA miniport driver is installed. The IrDA Tiny Transport Protocol (TinyTP) layer of the IrDA protocol stack is exposed to applications through Windows® Sockets (WinSock) with the support of the user-space component wshirda.dll. Applications can only use WinSock to communicate with IrDA miniport drivers. For more information on WinSock, refer to the Platform SDK documentation.

For most purposes, the operating system treats IrDA miniport drivers as miniport drivers that bind only to the IrDA protocol stack. An IrDA co-installer displays these drivers to the user as IrDA adapters and handles IrDA-specific user interface and setup issues.

Unlike NDIS drivers for other media, an IrDA miniport driver is never simultaneously bound to more than one protocol, and it is always bound to the same protocol. This is because, unlike other NDIS media, the IrDA protocol stack implements part of the media-control algorithm. This algorithm precludes multiple protocols.

System-supplied and vendor-supplied INF files are used to install IrDA miniport drivers and the IrDA protocol stack. These INF files must adhere to the Net INF and IrDA INF conventions.

The operating system supplies one IrDA miniport driver, irsir.sys, which is used to communicate with existing external Universal Asynchronous Receiver/Transmitter (UART)-attached SIR adapters and internal SIR IrDA adapters. Vendors should ensure that their SIR hardware is supported correctly through irsir.sys.

High-quality IrDA miniport drivers and INFs can be included with the operating system. This practice is encouraged because it improves the user IrDA installation experience.

The IrDA protocol stack can support multiple IrDA NICs concurrently. Vendors who wish to exploit this feature should expose multiple IrDA NICs through their IrDA miniport driver. Each exposed NIC should represent a unique transceiver and supporting hardware, capable of running a separate infrared connection.

There are a number of Plug and Play issues that must be considered when implementing IrDA miniport drivers for various IrDA hardware configurations. The Plug and Play section explores these issues.


IrDA Architecture

The following diagram shows components of the IrDA protocol layer and how IrDA miniport drivers communicate through the NDIS library with their NICs and with applications.

IrDA Architecture

Built on Wednesday, July 11, 2001


IrDA Protocol Driver

The IrDA protocol driver, irda.sys, is the only protocol driver that opens IrDA miniport drivers. This protocol driver is an implementation of the IrDA Infrared Link Access Protocol (IrLAP). This protocol driver is responsible for detecting infrared devices, establishing a link between local and remote devices, and reliably delivering data between local and remote devices. The IrDA protocol driver uses IrDA miniport drivers to deliver data between local and remote devices.

The services of the IrDA protocol driver are similar to the services that the TCP/IP protocol exposes. Using these services, applications that run on two different computers are able to easily open multiple reliable connections between themselves for the purpose of sending and receiving data. The IrDA protocol driver provides the following services:

  • Tiny Transport Protocol (TinyTP) is exposed through Winsock to applications. Applications can use TinyTP to make connections and to send and receive data.
  • Infrared Link Management Protocol (IrLMP) adds multiple session support to IrLAP. Multiple applications can use IrLMP to monitor for incoming connections without interfering with each other. A single application can also use IrLMP to open a control connection and a data connection at the same time. IrLMP also adds per-connection flow control to the flow control provided by the single IrLAP connection. IrLMP lets an application offer data in large blocks to the IrDA protocol stack. The IrDA protocol stack can then send this data at optimal speeds. Using IrLMP, applications are not required to monitor lost data or flow control.
  • Information Access Service (IAS) runs directly on top of IrLMP. IAS maps an ASCII service name to a LSAP-SEL. LSAP-SEL is a protocol element that is used to select one application from possibly many applications running on the server. This service name is a friendlier abstraction that is exposed to applications.
  • Infrared Link Printer Transport (IrLPT) communicates with printers. TinyTP is not used with IrLPT. IrLPT uses exclusive mode, which only supports a single IrLMP connection. This single IrLMP connection uses the flow control features of IrLAP. IrLMP defines the exclusive mode service.

The IrDA protocol driver binds to all IrDA miniport drivers that support the NdisMediumIrDA media type. IrDA miniport drivers only bind to the IrDA protocol driver because, unlike other NDIS media, the IrDA protocol layer implements part of the media control algorithm. The media control algorithm precludes multiple protocols.


IrDA Medium Features

Controlling and communicating over the IrDA medium, NdisMediumIrDA, involves some unique issues, compared to typical NDIS media. IrDA miniport drivers are implemented with these features in mind. The following sections describe features of the infrared medium:

Communication Link Speeds

Communication Link Turnaround Times

Receiver Synchronization


Communication Link Speeds

Unlike typical NDIS media, the infrared medium supports a large number of different speeds for transmitting and receiving bits. Current definitions for operating speed vary from 2,400 bits per second (bps) to 16 megabits per second (Mbps). In the future, more speeds may be defined by IrDA. Varying design goals at different speeds have led to different coding methods for frames: SIR, MIR, FIR, and VFIR. The differences in frame coding methods must be handled by the IrDA miniport driver and be transparent to the protocol.

The currently defined IrDA speeds and their corresponding frame coding methods are listed in the following table.

Speed (in bps) | Frame coding method
2,400 | SIR
9,600 | SIR
19,200 | SIR
38,400 | SIR
57,600 | SIR
115,200 | SIR
576,000 | MIR
1.152 Mbps | MIR
4 Mbps | FIR
16 Mbps | VFIR

For definitions of the frame coding methods, see IrDA Miniport Driver Packet Coding Schemes.

A particular infrared adapter does not necessarily support all the speeds listed in the preceding table. However, for two IrDA devices to communicate with one another, there must be an overlap in the supported speeds. IrDA standards specify that all IrDA devices must support the 9,600 bps rate. This IrDA specification guarantees that all IrDA devices are at least able to communicate at 9,600 bps. By communicating at 9,600 bps, IrDA devices can possibly negotiate a higher speed. For example, two IrDA devices must negotiate at 9,600 bps, but if both IrDA devices support 115.2 kilobits per second (Kbps), they can communicate data at that higher speed. Note that in rare cases, negotiation between two IrDA devices takes place at 9,600 bps, but the only speed those two IrDA devices share for data communications is the slower speed of 2,400 bps.

The IrLAP protocol can determine what speeds an IrDA miniport driver supports by sending an OID_IRDA_SUPPORTED_SPEEDS query to the driver.

The IrLAP protocol sets the IrDA miniport driver's link speed using OID_IRDA_LINK_SPEED along with one of the values returned from OID_IRDA_SUPPORTED_SPEEDS before transmitting packets. Link speed indicates the speed with which an infrared adapter transmits outgoing frames and possibly the speed with which the infrared adapter receives incoming frames. For information on how to set OID_IRDA_LINK_SPEED to control the speed of incoming frames, see the description of OID_IRDA_RATE_SNIFF.


Communication Link Turnaround Times

An infrared adapter consists of an infrared transceiver along with supporting hardware for encoding and decoding frames. This infrared transceiver contains a transmitter LED and a receiver diode that are typically located quite close together. The receiver diode is sensitive to infrared light because it must receive transmissions from a remote infrared LED over distances up to at least one meter. The transmitter LED is quite powerful because it must transmit to a remote receiver diode over the same distances.

During transmission, a local LED typically emits enough light to saturate the local receiver diode. In much the same way that it is difficult for people to see well after staring at the sun, it is difficult for the local receiver diode to correctly receive incoming frames immediately after the local LED transmits outgoing frames.

To allow time for the local receiver diode to recover from the saturation state and become capable of again receiving incoming frames, the IrDA protocol defines a parameter known as turnaround time. Turnaround time specifies the amount of time, in milliseconds, that it takes the receiver diode to recover from saturation. In some IrDA devices, the turnaround time may be negligible; in other IrDA devices, it can be a relatively long period of time.

The turnaround time of the local receiver diode does not affect the behavior of the local transceiver. However, the turnaround time of the local receiver diode affects the anticipated behavior of the remote transceiver. For example, if a local transceiver requires a one millisecond delay from the time its LED finishes transmitting to the time its receiver diode is capable of receiving, the remote station must wait one millisecond from receiving the last bit of a frame before beginning to transmit a new frame. The remote station performs this wait to honor the local transceiver's turnaround time.

The IrDA miniport driver must always be informed of the turnaround time of its local transceiver. The IrDA miniport driver uses OID_IRDA_TURNAROUND_TIME to specify this time value. IrLAP can send an OID_IRDA_TURNAROUND_TIME query to the IrDA miniport driver at any time to retrieve the local transceiver's turnaround time.

To honor the turnaround time of the remote transceiver, the IrLAP protocol might sometimes specify to delay transmission of a packet. To do so, the IrLAP protocol specifies the amount of time before a packet should be transmitted. The IrDA miniport driver must not transmit the packet before waiting the requested amount of time, although the driver can wait longer if necessary. The IrLAP protocol specifies transmission-delay time of a packet in the media-specific member of the packet's associated out-of-band (OOB) data block. For more information, see Sending and Receiving Packet Arrays.


Receiver Synchronization

Some infrared transceivers use information in the infrared signal itself to synchronize with that signal so that they can receive incoming frames. Depending on hardware that some infrared transceivers use, different amounts of time are required for those infrared transceivers to synchronize to the point that they can reliably receive data. Typically, infrared transceivers synchronize with the infrared signal while they receive Beginning of Frame (BOF) flags at the beginning of each incoming frame. Due to the requirements of some hardware, infrared transceivers might require one or more BOF flags to achieve receiver synchronization.

The IrDA miniport driver must always have information about the extra number of BOF flags that its transceiver requires to synchronize on the incoming infrared signal. The IrDA miniport driver uses OID_IRDA_EXTRA_RCV_BOFS to specify the required extra BOF flags. IrLAP can send an OID_IRDA_EXTRA_RCV_BOFS query to the IrDA miniport driver at any time to retrieve the local transceiver's number of extra BOF flags. The IrDA miniport driver must also be informed of the extra BOF flags that the remote receiving station requires. After IrLAP negotiates link speed with the remote receiving station and sets the IrDA miniport driver's link speed, the IrDA miniport driver must determine the required number of extra BOF flags using the scaling table that follows.

The value specified in OID_IRDA_EXTRA_RCV_BOFS applies to a Serial Infrared (SIR) link speed of 115.2 kilobits per second (Kbps). The values for all other SIR link speeds are scaled from that value. IrDA miniport drivers use the following scaling table to determine the required extra BOF flags from link speeds for those drivers.

Speed | Required Extra BOF Flags
2400 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9600 | 4 | 2 | 1 | 0 | 0 | 0 | 0 | 0
19200 | 8 | 4 | 2 | 1 | 0 | 0 | 0 | 0
38400 | 16 | 8 | 4 | 2 | 1 | 0 | 0 | 0
57600 | 24 | 12 | 6 | 3 | 1 | 1 | 0 | 0
115200 | 48 | 24 | 12 | 6 | 3 | 2 | 1 | 0

To determine the OID_IRDA_EXTRA_RCV_BOFS value that an IrDA miniport driver should indicate to the IrDA protocol driver:

  1. Find the link speed to which the NIC's transceiver is set in the left-most column.
  2. In that row, find the required number of extra BOF flags for the transceiver at that speed.
  3. Go down that column to the row for 115.2 Kbps. The number of extra BOF flags that the scaling table specifies for 115.2 Kbps is the number of extra BOF flags that the miniport driver should indicate to the IrDA protocol driver.

The following examples show how an IrDA miniport driver uses the preceding scaling table to determine the appropriate OID_IRDA_EXTRA_RCV_BOFS value to specify:

  • At 2,400 bps, if the NIC's transceiver requires one extra BOF flag for synchronization, the IrDA miniport driver must specify 48 for the OID_IRDA_EXTRA_RCV_BOFS value.
  • At 57.6 Kbps, if the NIC's transceiver requires eight extra BOFs for synchronization, the IrDA miniport driver must specify 24 for the OID_IRDA_EXTRA_RCV_BOFS value. Because eight is between values 6 and 12 in the table, the IrDA miniport driver uses the higher number 12 to determine the OID_IRDA_EXTRA_RCV_BOFS value to specify.
  • At 115.2 Kbps, if the NIC's transceiver requires one extra BOF flag for synchronization, the IrDA miniport driver must specify one for the OID_IRDA_EXTRA_RCV_BOFS value.

Note that an infrared transceiver for the MIR, FIR, and VFIR link speeds must work with the exact number of BOF flags for that speed.

To honor the number of extra BOF flags that are required by the remote station, IrLAP must specify the number of extra BOF flags along with every packet that it sends to the IrDA miniport driver for transmission. This value is always the number of extra BOF flags required at the current link speed. Because IrLAP specifies the number of extra BOF flags along with every packet, the IrDA miniport driver is not required to use the preceding scaling table each time the IrDA miniport driver prepares a packet for transmission. The IrLAP protocol specifies the number of extra BOF flags for a packet in the media-specific member of the packet's associated out-of-band (OOB) data block. For more information, see Sending and Receiving Packet Arrays.


IrLAP Frame Format

The lowest protocol level of the IrDA protocol stack is referred to as Infrared Link Access Protocol (IrLAP). IrLAP defines the format of the frames sent and received on the infrared media. The following topics describe features of the IrLAP frame format.

About IrLAP Frame Format

Use of Frame Information

Address Member


About IrLAP Frame Format

IrLAP defines the format of the frames sent and received on the infrared media. Each IrLAP frame consists of the following elements:

  • One or more Beginning of Frame (BOF) flags that mark the beginning of the frame. The size of the BOF member varies in length depending on the speed as described in Receiver Synchronization.
  • An address (A) member that identifies the secondary connection address. The address member is eight bits. The address member specifies the address of a device that belongs to a particular IrDA miniport driver. This IrDA miniport driver transmits or receives the frame that contains this address through this device. For more information on the address member, see Address Member.
  • A control (C) member that specifies the function of the particular frame. The control member is eight bits.
  • An optional information (I) member that contains the information data. The information member is an integral number of octets.
  • A frame check sequence (FCS) member that allows the receiving station to check the transmission accuracy of the frame. The FCS member is either 16 or 32 bits, depending on the speed.
  • An end of frame (EOF) flag that signals the end of the frame. The size of the EOF member varies depending on the speed.

The following example of an IrLAP frame shows the order of the elements that are described preceding.

BOF A C I FCS EOF

The coding of packets and BOF, EOF, and FCS members varies depending on the operating speed of the infrared media. Complete documentation about physical frames can be found in the publication Infrared Data Association Serial Infrared Physical Layer Link Specification, available from IrDA. A brief summary of the differences in coding schemes is provided in IrDA Miniport Driver Packet Coding Schemes.


Use of Frame Information

The IrDA protocol driver calls the NdisSendPackets function to send an array of packet descriptors (NDIS_PACKET structures) to an underlying IrDA miniport driver. These packet descriptors only specify the frame from the address element to the end of the information element. The IrDA miniport driver must add all other frame elements before it transmits the frame. Likewise, the IrDA miniport driver must strip from a received packet all elements other than those from the address element to the end of the information element, before the IrDA miniport driver indicates the packet to the IrDA protocol driver.

The IrDA miniport driver must perform any coding that is required to transform a packet that is transmitted to the infrared media. Likewise, the IrDA miniport driver must perform any decoding that is required to transform a packet, that is received from the infrared media, back into its original form.

If a packet that is received from the infrared media is invalid, the IrDA miniport driver must not indicate the packet to the IrDA protocol driver. A packet might be invalid for the following reasons:

  • The packet is incomplete.
  • The packet's cyclic redundancy check (CRC) is invalid.
  • The packet contains a reject sequence.


Address Member

The following example shows the eight bits that are contained in the address member of an IrLAP frame.

C/R A A A A A A A

The first bit of the address member is used as the command and response (C/R) bit. If this bit is set, the packet specifies that it is being sent from the primary station to the secondary station. If the C/R bit is clear, the packet specifies that it is being sent from the secondary station to the primary station. Because the IrDA miniport driver does not require information about the C/R bit, the driver does not monitor the bit. Note that primary stations initiate connections to secondary stations and run the timers that keep those connections active.

The least-significant 7 bits of the address member specify the Link Access Protocol (LAP) address. The LAP address is the address of a device that belongs to a particular IrDA miniport driver. The IrDA miniport driver transmits and receives packets through this device.

The IrLAP protocol can specify a list of addresses of devices from which it can receive packets; thereby restricting all other devices from receiving packets. To specify this list, the IrLAP protocol requests the IrDA miniport driver to set addresses in a UNICAST list using OID_IRDA_UNICAST_LIST. A UNICAST list is an array of addresses of devices from which the IrDA miniport driver accepts packets. If the UNICAST list is set, the IrDA miniport driver must accept only valid infrared packets from the specified addresses. If the UNICAST list is not set or contains zero elements, the IrDA miniport driver must accept all valid infrared packets. The IrDA miniport driver then indicates packets up to the IrLAP protocol.


IrDA Miniport Driver Packet Coding Schemes

The actual format of packets that travel on the infrared media can vary, according to the speed at which those packets are transmitted and received. The way that an IrDA miniport driver formats packets depends on the hardware implementation of its infrared NIC. The following sections briefly describe different methods of coding frames for different types of infrared NICs:

SIR Coding

MIR Coding

FIR Coding

VFIR Coding

If hardware for infrared NICs does not isolate developers from coding for the infrared media, they can obtain publications Infrared Data Association Serial Infrared Physical Layer Link Specification and Infrared Data Association Serial Infrared Link Access Protocol (IrLAP). These publications explain in detail how to code frames for all types of infrared NICs and are available from IrDA.


SIR Coding

This topic discusses how IrDA miniport drivers or their infrared NICs code frames for transmission at Serial IrDA (SIR) link speeds. The SIR specification defines a short-range infrared asynchronous serial transmission mode with one start bit, eight data bits, and one stop bit. The maximum data rate is 115.2Kbps (half duplex). This SIR coding scheme is called Return-to-Zero-Inverted (RZI). The primary benefit of coding frames for SIR speeds is that existing serial hardware can be used very cheaply. The low cost of using serial hardware is one of the reasons for the widespread availability of infrared SIR devices.

The BOF flag for SIR speeds is defined as 0xC0. The EOF value is defined as 0xC1. To avoid ambiguity in a frame that contains BOF and EOF, an escape sequence is defined for values of 0xC0 and 0xC1 that occur in other parts of the frame. The escape character is defined as 0x7D.

For each byte that the transmitter encounters that is the same as a BOF, EOF, or the escape character, the transmitter performs the following steps:

  1. Inserts a control-escape byte (0x7D) preceding such a byte.
  2. Complements bit five of each byte that is the same as the BOF, EOF, or escape character. That is, performs an exclusive OR operation on such a byte with 0x20.

The IrDA miniport driver must compute the FCS member for the frame before the driver inserts any control escape bytes.

Before the FCS computation, the receiving station also examines the entire frame contents between the BOF and EOF values. The receiving station performs the following steps on each escape byte encountered:

  1. Discards the escape byte.
  2. Complements bit five of the byte following the escape byte.

The IrDA miniport driver calculates the FCS sequence for the frame using the address (A), control (C), and information (I) members. For SIR link speeds, the IrDA miniport driver typically calculates the CRC value rather than the driver's hardware. An algorithm for calculating the 16-bit CRC is available in publications Infrared Data Association Serial Infrared Physical Layer Link Specification and The Internet Working Group Request For Comments (RFC) 1171 available from IrDA.

For SIR link speeds, the IrDA miniport driver can also code a reject sequence in a packet. This reject sequence informs the infrared transceiver that receives such a packet to reject the packet. The reject sequence is 0x7D 0xC1.


MIR Coding

This topic discusses how IrDA miniport drivers and their infrared NICs code frames for transmission at Medium IrDA (MIR) link speeds. The MIR data rates are 0.576 Mbps and 1.152 Mbps (half duplex).

For MIR link speeds, definitions for BOF and EOF values are the same; both BOF and EOF are defined as 0x7E. To avoid ambiguity in the frame with BOF and EOF, rather than using an escape sequence as is done at SIR rates, a zero is inserted at MIR rates after any five consecutive one bits in all members except BOF and EOF. Because the process of inserting and stripping zeros at the bit level is highly processor-intensive, it is strongly recommended that this logic be implemented in hardware. At MIR link speeds, two BOF flags are required on every frame.

For MIR link speeds, the CRC used is the same as for SIR speeds. That is, for MIR link speeds, the IrDA miniport driver also typically calculates the CRC value rather than the driver's hardware.


FIR Coding

This topic discusses how IrDA miniport drivers and their infrared NICs code frames for transmission at Fast IrDA (FIR) link speeds. The FIR specification defines short-range low power operation at 4Mbps (half duplex). All FIR devices are also required to support SIR operation.

For FIR link speeds, an entirely different coding scheme, called four pulse position modulation (4PPM), is used. The 4PPM coding scheme defines special flags for BOF and EOF. The 4PPM coding scheme should always be implemented in hardware.

The IrDA miniport driver might still be required to calculate the CRC to validate the frame. For FIR link speeds, a 32-bit CRC is used. An algorithm for calculating the 32-bit CRC is available in the publication Infrared Data Association Serial Infrared Physical Layer Link Specification available from IrDA.


VFIR Coding

This topic discusses how IrDA miniport drivers and their infrared NICs code frames for transmission at Very Fast IrDA (VFIR) link speeds. The VFIR specification defines short-range low power operation at 16Mbps (half duplex). All VFIR devices are also required to support FIR and SIR operation.

For VFIR link speeds, an entirely different coding scheme, called HHH(1,13), is used. The letters HHH that represent this coding scheme are the initials of the three researchers who invented it. The HHH(1,13) coding scheme should always be implemented in hardware. For more information on HHH(1,13), see the publication Infrared Data Association Serial Infrared Physical Layer Link Specification available from IrDA.

The IrDA miniport driver's hardware can calculate the CRC to validate the frame. However, if hardware does not calculate CRC, the IrDA miniport driver must calculate CRC. For VFIR link speeds, a 32-bit CRC is used, which is the same as that used for FIR link speeds. An algorithm for calculating the 32-bit CRC is available in the publication Infrared Data Association Serial Infrared Physical Layer Link Specification.


Sending and Receiving Packet Arrays

IrDA miniport drivers should support sending and receiving packet arrays as described in the following.

An IrDA miniport driver should implement a MiniportSendPackets function to transmit an array of packets over the network. IrLAP calls the NdisSendPackets function to send an array of packet descriptors to the underlying IrDA miniport driver. Each of these packet descriptors have associated out-of-band (OOB) information. The IrDA miniport driver can retrieve and use information that is specific to the infrared media from the OOB data block, NDIS_PACKET_OOB_DATA.

After packets arrive from a remote station, a NIC's transceiver receives those incoming packets and then passes interrupts to NDIS. NDIS, in turn, calls a particular routine to service those interrupts. The IrDA miniport driver for the NIC should implement MiniportIsr and MiniportHandleInterrupt functions to handle interrupts for incoming packets. To indicate packets to the IrDA protocol driver, the IrDA miniport driver sets information that is specific to the infrared media in the OOB data block for each packet and calls the NdisMIndicateReceivePacket function.

The IrDA miniport driver should use the macros that NDIS provides to set and retrieve OOB data. For more information on OOB data and accessing OOB data, see Packet Out-Of-Band Data.

The MediaSpecificInformation member of the OOB data block points to a structure of type MEDIA_SPECIFIC_INFORMATION. This structure, in turn, has a ClassInformation member that is a structure of type NDIS_IRDA_PACKET_INFO, which is defined as follows:

typedef struct _NDIS_IRDA_PACKET_INFO{
        UINT     ExtraBOFs;
        UINT     MinTurnAroundTime;
} NDIS_IRDA_PACKET_INFO, *PNDIS_IRDA_PACKET_INFO;

The ExtraBOFs member specifies the number of extra Beginning of Frame (BOF) flags that is added to the packet for transmission. For more information, see Receiver Synchronization.

The MinTurnAroundTime member specifies the minimum transmission-delay time for the packet. For more information, see Communication Link Turnaround Times.


Plug and Play

There are a number of Plug and Play issues that must be considered when implementing IrDA miniport drivers for NIC infrared transceivers of various hardware configurations. These configurations include, for example, support of Plug and Play, type of connection to the system, and link speed. The following topics describe these issues.

Non-Plug and Play External Serial-Attached SIR Adapters

Non-PnP Internal SIR Adapters or Internal SIR Adapters Incorrectly Exposed as Serial Ports

PnP External Serial-Attached SIR Adapters

PnP Internal SIR Adapters

Non-PnP Bus-Attached FIR Adapters

PnP Bus-Attached FIR Adapters


Non-Plug and Play External Serial-Attached SIR Adapters

Infrared SIR devices that attach to an external serial port and that do not support any Plug and Play functionality are supported by the IrDA miniport driver that is supplied by the operating system, irsir.sys. This system-supplied IrDA miniport driver uses services that are provided by a serial driver to access the serial port. The serial driver can be the one that is supplied by the operating system, serial.sys, or a compatible third-party serial driver.

The external serial port is visible to the user in the Ports (COM & LPT) element in the list in Device Manager, a Control Panel application. The system-supplied IrDA miniport driver ignores the specific settings of the serial port. Therefore, a user cannot incorrectly configure the serial port so that infrared devices that are attached to an external serial port do not work.

The user must manually install these devices through the Add New Hardware function of the Hardware Wizard. The user should select:

  1. The type of IrDA adapter device.
  2. The IrDA adapter device from the list of supported adapter types.
  3. The serial port to which the adapter is attached. The serial port is selected by its name.

The system-supplied IrDA miniport driver opens the selected serial port from the name that was selected by the user. The resources that are required to support the port are not visible to or configurable by the user through any user interface of the IrDA adapter. The user can only configure the serial port name.

Vendors who want support for their hardware in the operating system should request such support and provide procedures for device-specific initialization and speed change.


Non-PnP Internal SIR Adapters or Internal SIR Adapters Incorrectly Exposed as Serial Ports

Infrared SIR devices that attach internally and that do not support any Plug and Play functionality are not exposed as Plug and Play SIR devices through the system BIOS. These devices are detected and installed or they are manually installed as conventional serial ports.

If the IrDA UART of an infrared SIR device is exposed through the BIOS only as a conventional serial device, the device is installed as such. In this case, the user experience is the same as in the Non-Plug and Play External Serial-Attached SIR Adapters case.

This configuration is not recommended.


PnP External Serial-Attached SIR Adapters

No Infrared SIR devices that attach to an external serial port currently support serial enumeration. This configuration is not supported.


PnP Internal SIR Adapters

Infrared SIR devices that attach internally and that support Plug and Play functionality are exposed as infrared SIR Plug and Play devices through the system BIOS (PNP0510 or PNP0511). These devices appear to IrDA miniport drivers as conventional UARTs. These devices are supported by the combination of the IrDA miniport driver, that is supplied by the operating system, irsir.sys, and a serial driver. The serial driver can be the one that is supplied by the operating system, serial.sys, or a compatible third-party serial driver.

These devices do not appear in the Ports (COM & LPT) element in the list in Device Manager, a Control Panel application, because they are not exposed through the BIOS as serial devices. This means that the serial driver does not load automatically on this port, and these devices are otherwise invisible to users and application programs as conventional serial ports.

Once these devices are installed through Plug and Play, they appear to the user in the Infrared adapters element in the list in Device Manager. In addition, the system-supplied IrDA miniport driver is installed and it uses the resources that describe the underlying IrDA UART. To use IrDA UART resources, the system-supplied IrDA miniport driver loads the serial driver as a lower filter driver.

The resources that the SIR IrDA UART requires must be exposed in the conventional Plug and Play manner through the system BIOS. Plug and Play attempts to locate a set of non-conflicting resources. To enable all system hardware to work together, built-in or OEM-bundled hardware must always supply suitable resource sets. The operating system does not allow interrupt sharing. Therefore, SIR UART hardware must be configurable to work on interrupts other than interrupts three and four, which are the traditional serial interrupts. The interrupt configuration must be exposed through the BIOS.

Note that in many cases, requiring that interrupts three and four be exposed for the SIR IrDA UART might not work.


Non-PnP Bus-Attached FIR Adapters

This topic discusses infrared FIR devices that attach to a bus and that do not support any Plug and Play functionality.

In this case, lack of Plug and Play support specifies that the FIR hardware does not respond to bus enumeration or is not exposed through the system BIOS. If users attempted to install more primitive FIR hardware, they would probably not succeed. More primitive FIR hardware includes, for example, FIR hardware with numerous jumpers.

All FIR hardware is required to also support SIR protocols and speeds. FIR hardware typically exposes a UART for SIR, in addition to the DMA mechanism for FIR, to satisfy this requirement. This configuration typically requires IrDA miniport driver and installation INF file that are both complex. SIR and FIR components must both be programmable. In addition, SIR must support interrupts other than interrupts three and four and have the ability to use at least the traditional I/O space of COM3 or COM4. These resource requirements are necessary to avoid conflicts with conventional serial ports. These conflicts might be subtle and difficult to diagnose.

These FIR devices must be supplied with IrDA miniport drivers and installation INF files. The INF must list the supported combinations of resources and must be able to program the FIR hardware once the user has selected a non-conflicting resource set. The INF must describe any other parameters that are required, and the user must be able to configure those parameters. Other parameters include, for example, the type of infrared transceiver.

Once these FIR devices are installed, they appear to the user in the Infrared adapters element in the list in Device Manager, a Control Panel application. In addition, IrDA miniport drivers for the FIR devices are installed and they use FIR resources and the resources that describe the underlying IrDA UART.

To use IrDA UART resources, an IrDA miniport driver can load the system-supplied serial driver, serial.sys, as a lower filter driver, but the IrDA miniport driver is not required to do so.

This configuration is not recommended.


PnP Bus-Attached FIR Adapters

This topic discusses infrared FIR devices that attach to a bus and that support Plug and Play functionality.

The same constraints that apply to FIR devices that are not Plug and Play also apply to Plug and Play FIR devices. That is, SIR and FIR components must both be programmable. In addition, SIR must support interrupts other than interrupts three and four and use at least the traditional I/O space of COM3 or COM4. These resources must also be either reported correctly through the system BIOS or described in an installation INF file.

FIR devices that support Plug and Play must report unique device ID that accurately describe chip set and transceiver combinations. Standards for FIR device ID do not currently exist. Note that an organization could publish known combinations of FIR hardware and suitable device ID. This organization could be, for example, IrDA or a group of vendors of chip sets and transceivers.

These FIR devices must be supplied with IrDA miniport drivers and installation INF files. The INF must list the supported combinations of SIR and FIR resources that can support Plug and Play for the IrDA miniport driver.

Once these FIR devices are installed, they appear to the user in the Infrared adapters element in the list in Device Manager, a Control Panel application. In addition, IrDA miniport drivers for the FIR devices are installed and they use FIR resources and the resources that describe the underlying IrDA UART.

An IrDA miniport driver for a FIR device should not load the system-supplied serial driver, serial.sys, as a lower filter driver. A FIR device typically overloads the standard UART registers to provide FIR functionality. Using the serial driver as a filter precludes direct access to the hardware or IRQ.

FIR devices that support Plug and Play can be exposed with unique FIR device ID and standard SIR Plug and Play aliases. If the operating system can match the FIR device ID with an IrDA miniport driver, the operating system installs that driver; otherwise, the operating system installs the serial driver.

FIR devices that are incorrectly exposed as conventional serial ports can only be supported by manual installation. In this case, the user experience is the same as described in Non-PnP Internal SIR Adapters or Internal SIR Adapters Incorrectly Exposed as Serial Ports.


NDIS Intermediate Drivers

NDIS intermediate drivers interface between upper-level protocol drivers and miniport drivers. Some applications that might require an intermediate driver include:

  • Media translation between a legacy transport driver and a miniport driver that manages a media type unknown to the transport driver.
  • Data filtering for security or other purposes.
  • Load Balancing Fail Over (LBFO) solutions.
  • Monitoring and collecting of network data statistics.

Before attempting to write an intermediate driver, you should read about NDIS miniport and protocol drivers. For more information about NDIS miniport drivers, see NDIS Miniport Drivers. For more information about NDIS protocol drivers, see NDIS Protocol Drivers.

This section includes the following topics:

Introduction to Intermediate Drivers

Writing an NDIS Intermediate Driver

Installing Intermediate Drivers


Introduction to Intermediate Drivers

NDIS driver stacks must include miniport drivers and protocol drivers and can also include intermediate drivers. Since intermediate drivers are optional, you must understand the relationships between miniport drivers, protocol drivers, and NDIS before addressing intermediate drivers.

Miniport drivers control NIC devices and communicate with the lower edge of protocol drivers. Protocol drivers implement protocols, such as TCP/IP, and are above the miniport drivers in the driver stack. NDIS provides services to simplify development and maintenance of miniport drivers and protocol drivers.

The relationships between miniport drivers, protocol drivers and NDIS are illustrated in the following figure.

Relationships Between NDIS, Miniport Drivers, and Protocol Drivers

NDIS miniport drivers and protocol drivers are bound together through standard NDIS interfaces.

NDIS intermediate drivers include a protocol driver interface at their lower edge and a miniport driver interface at their upper edge. The intermediate driver's protocol interface allows it to load above a driver with a miniport driver interface. Therefore, intermediate drivers can load above miniport drivers or other intermediate drivers. The intermediate driver's miniport interface allows it to load below a driver with a protocol lower edge interface. Therefore, intermediate drivers can load below protocol drivers or below other intermediate drivers.

The relationships between miniport drivers, protocol drivers, intermediate drivers and NDIS are illustrated in the following figure.

Intermediate Driver in the NDIS Driver Stack

The intermediate driver miniport interface is called a virtual miniport. It is virtual in that it does not control a physical device directly. Instead, it relies on an underlying miniport driver to communicate with the physical device.

Bindings between the intermediate driver and other drivers are called external bindings. NDIS controls external bindings. The upper edge of the virtual miniport binds with the next-higher driver, which can be a protocol driver or another intermediate driver. The lower edge of the intermediate driver protocol binds to the next lower driver, which can be another intermediate driver or an underlying miniport driver.

The lower edge of the virtual miniport and the upper edge of the intermediate driver protocol do not require external bindings. Instead, the intermediate driver binds its virtual miniport and its protocol internally. These internal bindings, which are implementation specific, are not controlled by NDIS.

The following figure illustrates the internal bindings between the virtual miniport and the intermediate driver protocol.

Intermediate Driver Internal Bindings

There are two types of NDIS intermediate drivers: filter intermediate drivers and MUX intermediate drivers. The following topics describe these driver types.


NDIS Filter Intermediate Drivers

An NDIS filter intermediate driver exposes one virtual miniport for each underlying miniport driver that is bound to the intermediate driver's lower (protocol) edge.

Protocol drivers located above the intermediate driver bind to a virtual miniport that is exposed by the intermediate driver, as if the virtual miniport were a miniport driver controlling a physical adapter. When the virtual miniport receives requests and data packets, the intermediate driver forwards them down to the associated NDIS miniport driver. The filter intermediate driver can modify packets before sending them to, and after receiving them from, the NDIS miniport driver below. For example, the filter intermediate driver can encrypt and compress outgoing data in packets, and decrypt and decompress incoming data in packets.

The following figure illustrates the one-to-one relationship between the virtual miniports of the filter intermediate driver and the miniport driver for the underlying device.

NDIS Filter Intermediate Driver Configuration

When a filter intermediate driver is initialized it inserts itself into all existing protocol-to-miniport bindings, as appropriate to the media type associated with the driver. For information about assigning the media type for a filter intermediate driver, see Filter Intermediate Driver Installation.

Filter intermediate driver virtual miniport bindings are not displayed in the Windows user interface. This allows the filter intermediate driver to operate transparently from the user perspective.

The following are examples of filter intermediate drivers:

  • The Windows QoS Packet Scheduler is a filter intermediate driver that is provided with Windows 2000 and later versions of the operating system. The packet scheduler enforces quality-of-service parameters for network data flows.
  • The PassThru sample intermediate driver demonstrates the basic concepts of an NDIS filter intermediate driver. PassThru passes on information without modifying it. This driver exposes a virtual miniport at its upper edge for each binding to an underlying miniport.


NDIS MUX Intermediate Drivers

The number of virtual miniports exposed by a MUX intermediate driver can be different than the number of lower physical adapters that are bound to the driver. A MUX intermediate driver exposes virtual miniports in a one-to-n, n-to-one, or even an m-to-n relationship with underlying adapters. This results in complicated internal bindings and data paths.

In a one-to-n configuration, a single MUX intermediate driver can bind to many physical adapters below. Transport drivers bind to the virtual miniport of the MUX intermediate driver in the same way that they bind to non-virtual miniports. The MUX intermediate driver repackages and passes down all requests and send packets that are submitted to the intermediate driver for a specific connection. . A Load Balancing Fail Over (LBFO) driver is an example of this type of MUX intermediate driver. (For more information about LBFO solutions, see Load Balancing and Fail Over.)

The following figure illustrates a one-to-n MUX intermediate driver configuration:

NDIS One-to-N MUX Intermediate Driver Configuration

In an n-to-one configuration, a MUX intermediate driver can expose many virtual miniports for a single physical adapter below. Overlying protocols bind to these virtual miniports of the MUX intermediate driver in the same way that they bind to non-virtual miniports. The MUX intermediate driver handles requests and sends that are submitted to the driver for specific connections at each virtual miniport. The driver repackages and transfers these requests and sends down to the NDIS miniport driver for the bound physical adapter.

The following figure illustrates an n-to-one MUX intermediate driver configuration:

NDIS N-to-One MUX Intermediate Driver Configuration

MUX intermediate drivers require a notify object DLL. When a MUX intermediate driver is initialized, its bindings are determined by the configuration established by it's notify object DLL. For more information about installing MUX intermediate drivers, see MUX Intermediate Driver Installation.

The following are examples of n-to-one MUX intermediate drivers:

  • Windows ATM LAN Emulation is an intermediate driver that emulates Ethernet over an ATM network. This driver is similar in structure to the MUX sample. This driver is included in Windows 2000 and later versions of the operating system.
  • 802 and proprietary virtual LANs are technologies that could be implemented as intermediate drivers similar to the MUX sample.
  • The MUX Intermediate Driver Sample is an n-to-one MUX intermediate driver. MUX creates multiple virtual miniports layered above a single underlying miniport.


Writing an NDIS Intermediate Driver

This section provides some basic information to help you start writing an NDIS intermediate driver. To write an NDIS intermediate driver you must understand the NDIS miniport driver and protocol driver operations and functions.

See also the Passthru and MUX intermediate driver samples in the DDK. These samples provide basic examples of a filter intermediate driver and an n-to-one MUX intermediate driver that you can adapt to your specific needs.

Intermediate Driver Fundamentals

The virtual miniport of an NDIS intermediate driver must be deserialized. Deserialized drivers serialize the operation of their own MiniportXxx functions and queue internally all incoming send packets instead of relying on NDIS to perform these operations. This results in significantly better full-duplex performance, provided that the driver's critical sections (code that can be executed by only one thread at a time) are kept small. For more information on deserialized drivers, see Deserialized NDIS Miniport Drivers.

An NDIS intermediate driver can support only connectionless communication at its virtual miniport. At its protocol interface, however, an NDIS intermediate driver can support either connectionless communication or connection-oriented communication. For more information about connection-oriented communication, see Connection-Oriented NDIS.

An intermediate driver is typically layered above one or more NDIS miniport drivers and below a transport driver. Intermediate drivers can also be layered with other intermediate drivers. The NDIS 5.1 packet-stacking interface allows an intermediate driver to be layered with other intermediate drivers while limiting performance penalties associated with packet management.


MUX and Filter Intermediate Driver Differences

There are significant differences between filter intermediate drivers and MUX intermediate drivers. These differences are summarized as follows:

  • Filter intermediate drivers must always have a one-to-one relationship between virtual miniport instances and underlying miniports. MUX intermediate drivers can have one-to-n, n-to-one, or m-to-n relationships between virtual miniport instances and underlying miniports. This configuration flexibility results in complicated internal bindings and data paths in MUX intermediate drivers.
  • MUX intermediate drivers require a notify object DLL for configuration. Filter intermediate drivers can have a notify object DLL, but it is not required.
  • For filter intermediate drivers, the protocol device class is NetService. For MUX intermediate drivers, the protocol device class is NetTrans.
  • For filter intermediate drivers, you must set the NCF_FILTER (0x1) flag in the Characteristics entry of the driver's protocol INF file. The Characteristics entry is in the DDInstall section.
  • The UpperBindings registry key identifies the device instance for a filter intermediate driver's virtual miniport. The notify object DLL manages device instance information for a MUX intermediate driver. The UpperBindings registry key holds a list of virtual miniport device identifiers for a MUX intermediate driver.
  • For filter intermediate drivers, you set the UpperRange INF entry to noupper and the LowerRange INF entry to nolower. Filter intermediate drivers must have a FilterMediaTypes INF file entry. During Initialization, a filter intermediate driver inserts itself into all existing protocol-to-miniport bindings, as appropriate to the media types listed in FilterMediaTypes . For a MUX intermediate driver, you set the UpperRange INF entry for the protocol lower edge to noupper and the LowerRange INF entry for the virtual miniport to nolower. The MUX intermediate driver virtual miniport UpperRange and protocol lower edge LowerRange are established just as with any miniport driver or protocol driver.


Intermediate Driver Platform-Specific Differences

The following NDIS functions are not supported on Windows 98/Me:

  • NdisIMCopySendPerPacketInfo
  • NdisIMCopySendCompletePerPacketInfo
  • NdisIMCancelInitializeDeviceInstance

NDIS 5.1 features for intermediate drivers (packet stacking, query pending I/O count) are supported only on Windows XP.


Intermediate Driver DriverEntry Function

An intermediate driver's initial required entry point must be explicitly named DriverEntry so that the loader can properly identify it. All other exported driver functions, described here as MiniportXxx and ProtocolXxx, can have any developer-specified name because they are passed as addresses to NDIS. The definition of DriverEntry is that of any kernel-mode driver:

NTSTATUS
  DriverEntry(
    IN PDRIVER_OBJECT  DriverObject,
    IN PUNICODE_STRING  RegistryPath
    );

In an intermediate driver, DriverEntry must at a minimum:

  1. Call NdisMInitializeWrapper and save the handle returned at NdisWrapperHandle.
  2. Call NdisIMRegisterLayeredMiniport to register the driver's MiniportXxx functions, passing the handle obtained in Step 1.
  3. Call NdisRegisterProtocol to register the driver's ProtocolXxx functions if the driver subsequently binds itself to an underlying NDIS driver.
  4. Call NdisIMAssociateMiniport to inform NDIS about the association between the driver's miniport lower edge and protocol upper edge.

An intermediate driver should call NdisMRegisterUnloadHandler to register an unload handler. This unload handler is called when the system unloads the intermediate driver. If DriverEntry fails, the unload handler is not called, the driver is simplyunloaded.

The unload handler registered with NdisMRegisterUnloadHandler should call NdisDeregisterProtocol to deregister the protocol portion of the intermediate driver. The unload handler should also perform any necessary cleanup operations, such as de-allocating resources used by the protocol portion of the driver.

Note that an unload handler differs from a MiniportHalt function: the unload handler has a more global scope, whereas the scope of the MiniportHalt function is restricted to a particular miniport driver instance. The intermediate driver should clean up state information and de-allocate resources when each underlying miniport driver that is bound to it is halted.

ProtocolUnload is an optional unload handler. Register an entry point for this function in the ProtocolCharacteristics structure that you pass to NdisRegisterProtocol. NDIS calls ProtocolUnload in response to a user request to uninstall an intermediate driver. NDIS calls ProtocolUnbindAdapter once for each bound adapter, then it calls ProtocolUnload. This handler is called before the system actually unloads the driver. This timing provides a chance to release any device objects or other resources that might otherwise prevent the system from calling the unload handler registered with NdisMRegisterUnloadHandler and unloading the driver.

DriverEntry can initialize spin locks for any globally-shared resources that the intermediate driver allocates, such as structures and memory areas that the driver uses to track connections and to track sends in progress.

If DriverEntry fails to allocate any resources that the driver needs to carry out network I/O operations, it should release any previously allocated resources and return an appropriate error status. For example, if DriverEntry has called NdisMInitializeWrapper, DriverEntry must call NdisTerminateWrapper.


Registering as an NDIS Intermediate Driver

An NDIS intermediate driver must register its MiniportXxx functions and its ProtocolXxx operations with NDIS in the context of its DriverEntry function. To register its MiniportXxx functions, an intermediate driver must make call NdisIMRegisterLayeredMiniport. This call exports the intermediate driver's MiniportXxx functions. Note that the intermediate driver controls when its virtual miniport is initialized and, thus, when the driver is ready to accept sends and requests on that NIC.

NDIS calls the intermediate driver's MiniportInitialize function after the Plug and Play Manager has started the virtual miniport device and after the intermediate driver has called NdisIMInitializeDeviceInstanceEx for that device. The call to MiniportInitialize will only be in the context of NdisIMInitializeDeviceInstanceEx if the Plug and Play Manager has already started the virtual miniport device. If the intermediate driver exports more than one virtual miniport, the driver must call NdisIMInitializeDeviceInstanceEx for each NIC that it makes available for network requests. To register its ProtocolXxx functions, an intermediate driver must call NdisRegisterProtocol.


Registering an Intermediate Driver as a Miniport

An intermediate driver calls NdisIMRegisterLayeredMiniport to export its MiniportXxx functions. NdisIMRegisterLayeredMiniport is declared as follows:

NDIS_STATUS
  NdisIMRegisterLayeredMiniport(
    IN NDIS_HANDLE  NdisWrapperHandle,
    IN PNDIS_MINIPORT_CHARACTERISTICS  MiniportCharacteristics,
    IN UINT  CharacteristicsLength,
    OUT PNDIS_HANDLE  DriverHandle
    );

The DriverHandle that is returned by NdisIMRegisterLayeredMiniport must be retained by the intermediate driver and input to NDIS when the driver calls NdisIMInitializeDeviceInstanceEx.

NdisWrapperHandle was returned by a previous call to NdisMInitializeWrapper.

The intermediate driver must:

  1. Zero-initialize a structure of type NDIS_MINIPORT_CHARACTERISTICS with NdisZeroMemory.
  2. Store the addresses of the mandatory MiniportXxx functions, as well as any optional MiniportXxx functions the driver exports. Any other MiniportXxx entry points must be set to NULL.

An intermediate driver that does support NDIS 5.1 features should register as a version 5.1 miniport. An intermediate driver that does not support NDIS 5.1 features should register either as a version 4.0 miniport or a version 5.0 miniport.

You must set the following entries in MiniportCharacteristics to a valid MiniportXxx function address unless the function is optional and is not exported. I the driver does not export the function, set the address to NULL.

HaltHandler
HaltHandler is a required function. This function is called by NDIS if the virtual miniport device exposed by the intermediate driver is disabled or stopped, or if the intermediate driver itself initiated its removal by calling NdisIMDeInitializeDeviceInstance.
InitializeHandler
This function is called as a result of the intermediate driver calling NdisIMInitializeDeviceInstanceEx to initialize its miniport operations for the virtual miniport being initialized.
QueryInformationHandler
This function receives OID_XXX requests originating from or passed through by an overlying driver that has called NdisRequest with a request type of NdisRequestQueryInformation.
ResetHandler
NDIS can call an intermediate driver's MiniportReset function at the behest of a higher-level protocol driver that has called NdisReset.
SetInformationHandler
This function processes OID_XXX requests made by or passed through an overlying driver that has called NdisRequest with a request type of NdisRequestSetInformation.
SendPacketsHandler
This function receives an array of one or more pointers to packet descriptors specifying packets for transmission over the network. Every intermediate driver should supply a MiniportSendPackets function. For more information, see Transmitting Packets Through an Intermediate Driver.
TransferDataHandler
This function is called to transfer the remaining part of a received packet that was not previously indicated up in the lookahead buffer passed by the intermediate driver to NdisM Xxx IndicateReceive. This indicated packet can be a converted packet previously received at the intermediate driver's ProtocolReceive function or ProtocolReceivePacket handler. This handler is required if the intermediate driver indicates received packets to its overlying driver by calling any medium-specific NdisM Xxx IndicateReceive function except for NdisMWanIndicateReceive. If the intermediate driver always indicates packets to the overlying driver by calling NdisMIndicateReceivePacket, it need not provide a MiniportTransferData function.
ReturnPacketHandler
This function receives a returned packet descriptor that was previously indicated to a higher-level driver by calling NdisMIndicateReceivePacket. The call to NdisMIndicateReceivePacket relinquishes control of the resources indicated to the higher-level driver. After each such indication is consumed by the higher-level driver, the intermediate allocated packet descriptor and the resources it describes will be returned to the MiniportReturnPacket function. A MiniportReturnPacket function is not supplied if the intermediate driver always indicates packets up by calling a medium-specific NdisM Xxx IndicateReceive function, or if it always sets the status in the OOB data block associated with each packet descriptor to NDIS_STATUS_RESOURCES before calling NdisMIndicateReceivePacket.
CheckForHangHandler
This function is called at an NDIS-determined or, alternatively, at an intermediate-driver-determined interval. If supplied, the MiniportCheckForHang function is called every two (or at a driver-requested interval) seconds. Generally, an NDIS intermediate driver does not provide a MiniportCheckForHang function because such a driver has no way to determine if an underlying NIC is hung. An intermediate driver probably would provide this handler if it was layered over a non-NDIS driver whose state is inaccessible to NDIS.

The following miniport driver handler functions are never supplied by an intermediate driver, because such drivers do not manage interrupting devices, do not allocate buffers at raised IRQL, or in the case of the ReconfigureHandler, because NDIS currently does not call a MiniportReconfigure function:

  • DisableInterruptHandler
  • EnableInterruptHandler
  • HandleInterruptHandler
  • ISRHandler
  • AllocateCompleteHandler
  • ReconfigureHandler


Registering an Intermediate Driver as a Protocol

An intermediate driver registers its ProtocolXxx functions with NDIS by calling NdisRegisterProtocol, which is declared as follows:

VOID
  NdisRegisterProtocol(
    OUT PNDIS_STATUS  Status,
    OUT PNDIS_HANDLE  NdisProtocolHandle,
    IN NDIS_PROTOCOL_CHARACTERISTICS  ProtocolCharacteristics,
    IN UINT  CharacteristicsLength
    );

Before calling NdisRegisterProtocol, the intermediate driver must:

  1. Zero a structure of type NDIS_PROTOCOL_CHARACTERISTICS. For Windows 2000 and Windows 98/Me, protocol drivers can specify a version number of 3.0, 4.0, or 5.0. For Microsoft® Windows® XP and later, protocol drivers can specify a version number of 4.0 or 5.0. Protocol drivers must be PnP-ready. Version 3.0 protocol drivers are therefore not supported.
  2. Store the addresses of the mandatory ProtocolXxx functions, as well as any optional ProtocolXxx functions that the driver supports.

The NdisProtocolHandle returned by this call is opaque to an intermediate driver. The handle must be retained by the intermediate driver and provided as an input parameter in future calls made by the protocol part of the intermediate driver to NDIS—for example, to open an underlying adapter.

Registering the ProtocolXxx Functions of an Intermediate Driver with a Connectionless Lower Edge

The following lists the protocol handler functions that an intermediate driver with a connectionless lower edge can export. These include both optional and required functions.

BindAdapterHandler
This is a required function. NDIS calls ProtocolBindAdapter to request that the intermediate driver bind to an underlying NIC or virtual miniport whose name is passed as a parameter to this handler. For more information on dynamic binding, see Dynamic Binding in an Intermediate Driver.
UnbindAdapterHandler
This is a required function. ProtocolUnbindAdapter is called by NDIS to close a binding to the underlying NIC or virtual miniport. ProtocolUnbindAdapter calls NdisCloseAdapter and deallocates resources when the binding is successfully closed.
OpenAdapterCompleteHandler
This is a required function. If an intermediate driver's call to NdisOpenAdapter returns NDIS_STATUS_PENDING, ProtocolOpenAdapterComplete is subsequently called to complete the binding.
CloseAdapterCompleteHandler
This is a required function. If an intermediate driver's call to NdisCloseAdapter returns NDIS_STATUS_PENDING, ProtocolCloseAdapterComplete is subsequently called to complete the unbinding.
ReceiveHandler
This is a required function. ProtocolReceive is called with a pointer to a lookahead buffer containing data received over the network. If this buffer contains less than the full net packet, ProtocolReceive calls NdisTransferData with a packet descriptor to get the remainder of the net packet. If the underlying driver calls NdisMIndicateReceivePacket to indicate receives, the lookahead buffer passed to ProtocolReceive will always contain a full net packet.
ReceivePacketHandler
This is a required function. Provide a ProtocolReceivePacket function to handle receive data that an underlying miniport driver indicates by calling NdisMIndicateReceivePacket. These receive indications include an array of pointers to one or more packet descriptors or out-of-band data.
ReceiveCompleteHandler
This is a required function. ProtocolReceiveComplete is called when any packets previously indicated to ProtocolReceive can be postprocessed.
TransferDataCompleteHandler
This is a required function if the ProtocolReceive function will call NdisTransferData. If a previous call to NdisTransferData to copy the remainder of a received packet returned NDIS_STATUS_PENDING, ProtocolTransferDataComplete is called when the transfer operation is done.
ResetCompleteHandler
This is a required function. ProtocolResetComplete is called when a reset operation, begun with a call to NdisReset that returned NDIS_STATUS_PENDING, is done. Usually, intermediate drivers do not call NdisReset, but the drivers above them might, so an intermediate driver could forward such a reset request to the underlying NDIS driver.
RequestCompleteHandler
This is a required function. ProtocolRequestComplete is called upon completion of a query/set operation, begun with a call to NdisRequest that returned NDIS_STATUS_PENDING.
SendCompleteHandler
This is a required function. ProtocolSendComplete is called once for each packet which is transmitted with a call to NdisSend that returned NDIS_STATUS_PENDING as the status of the send operation. If an array of packets is sent by calling NdisSendPackets, ProtocolSendComplete is called once for each packet passed to NdisSendPackets.
StatusHandler
This is a required function. ProtocolStatus is called by NDIS with status notifications initiated by an underlying miniport driver.
StatusCompleteHandler
This is a required function. ProtocolStatusComplete is called by NDIS to indicate that a status change, previously indicated to ProtocolStatus, is now complete.
PnPEventHandler
This is a required function. NDIS calls ProtocolPnPEvent to indicate a Plug and Play event or a Power Management event. For more information, see Handling PnP Events and PM Events in an Intermediate Driver.
UnloadHandler
This is an optional function. NDIS calls ProtocolUnload in response to a user request to uninstall an intermediate driver. NDIS calls ProtocolUnload after calling ProtocolUnbindAdapter once for each bound adapter. ProtocolUnload performs driver-determined clean-up operations.

Registering the ProtocolXxx Functions of an Intermediate Driver with a Connection-Oriented Lower Edge

An intermediate driver with a connection-oriented lower edge must register the following protocol handler functions that are common to both connectionless and connection-oriented miniport drivers:

  • BindHandler
  • UnbindHandler
  • OpenAdapterCompleteHandler
  • CloseAdapterCompleteHandler
  • ReceiveCompleteHandler
  • ResetCompleteHandler
  • RequestCompleteHandler
  • StatusCompleteHandler
  • PnPEventHandler

An intermediate driver with a connection-oriented lower edge must also register the following connection-oriented protocol functions:

CoSendCompleteHandler
This is a required function. ProtocolCoSendComplete is called once for each packet that is passed to NdisCoSendPackets. The intermediate driver can determine the status of a send operation that calls NdisCoSendPackets only from the status argument input to ProtocolCoSendComplete.
CoStatusHandler
This is a required function. ProtocolCoStatus is called by NDIS with status notifications initiated by an underlying miniport driver.
CoReceivePacketHandler
This is a required function. When a bound connection-oriented miniport driver or integrated miniport call manager (MCM) indicates an array of pointers by calling NdisMCoIndicateReceivePacket, NDIS calls the intermediate driver's ProtocolCoReceivePacketHandler.
CoAfRegisterNotifyHandler
If the intermediate driver is a connection-oriented client that uses the call manager services of a call manager or an MCM driver, it must register a ProtocolCoAfRegisterNotify function. ProtocolCoAfRegisterNotify determines whether the intermediate driver can use the services of a call manager or MCM that has advertised its services by registering an address family.


Dynamic Binding in an Intermediate Driver

An intermediate driver must support dynamic binding to underlying NICs by providing both a ProtocolBindAdapter and a ProtocolUnbindAdapter function. An intermediate driver registers these functions with NDIS by calling NdisRegisterProtocol and defining the ProtocolBindHandler and ProtocolUnbindHander. NDIS calls the ProtocolBindAdapter function of any intermediate driver that can bind to a NIC when that NIC becomes available.

VOID
  ProtocolBindAdapter(
    OUT PNDIS_STATUS  Status,
    IN NDIS_HANDLE  BindContext,
    IN PNDIS_STRING  DeviceName,
    IN PVOID  SystemSpecific1,
    IN PVOID  SystemSpecific2
    );

The handle at BindContext represents NDIS' context for the bind request. The intermediate driver must retain this handle and pass it back to NDIS as a parameter to NdisCompleteBindAdapter after the intermediate driver has completed its binding-related activities and is ready to accept transmit requests.

Binding-time actions include allocating and initializing a NIC-specific context area for the binding, and calling NdisOpenAdapter to bind to the adapter passed at DeviceName. DeviceName string can refer to a NIC managed by an underlying miniport driver, or it can be the name of a virtual miniport exported by an intermediate driver that is layered between the called intermediate driver and an underlying miniport driver.

The DeviceName paramter is valid only in the context of the call to ProtocolBindAdapter. If the intermediate driver will call NdisOpenAdapter from a different thread context (after returning NDIS_STATUS_PENDING from ProtocolBindAdapter), then it must copy the string pointed to by DeviceName and pass a pointer to this new string to NdisOpenAdapter.

The intermediate driver can store the BindContext in the allocated binding-related context area or in another driver-accessible location. The BindContext value must be stored if NdisOpenAdapter can return NDIS_STATUS_PENDING. In this case, the intermediate driver cannot call NdisCompleteBindAdapter until the open-adapter operation is complete and the intermediate driver is called at its ProtocolOpenAdapterComplete function. BindContext must then be retrieved from a known location and passed by ProtocolOpenAdapterComplete to NdisCompleteBindAdapter.

SystemSpecific1 points to a registry path if the intermediate driver stores adapter-specific information in the registry. This value is passed to NdisOpenProtocolConfiguration to obtain a handle that is used to read and possibly to write such information.

SystemSpecific2 is reserved for system use.

If an intermediate driver converts incoming packets from one medium format to another, ProtocolBindAdapter can allocate a pool of packet descriptors and buffer descriptors that it will need on a per-binding basis. For information about the requirement to allocate and manage packets, see Intermediate Driver Packet Management. Also, if an intermediate driver receives incoming data only at its Protocol(Co)Receive function, it should allocate packet pools and buffer pools to copy received data. Drivers that implement packet stacking should also allocate these pools because packet stacking does not guarantee that there is always a stack location available.


Opening an Adapter Underlying an Intermediate Driver

ProtocolBindAdapter uses the value at DeviceName to open an underlying NIC or virtual miniport, thereby establishing a binding to the underlying miniport driver. It can also read additional configuration information that it requires from the registry. NdisOpenProtocolConfiguration is called to obtain a handle to the registry key where the intermediate driver stores any adapter-specific information. The intermediate driver can call NdisOpenConfigurationKeyByIndex or NdisOpenConfigurationKeyByName to open and get a handle to a subkey below the key opened with NdisOpenProtocolConfiguration. The intermediate driver can then call NdisRead(Write)Configuration functions to read and write registry information from an opened key or subkey. The NdisRead(Write)Configuration functions are described in the Network Driver Reference.

Typically, ProtocolBindAdapter uses the context area that it allocates to represent its binding to DeviceName as storage for any binding-specific information associated with the bound adapter.

Binding is accomplished by calling NdisOpenAdapter, which is declared as follows:

VOID
  NdisOpenAdapter(
    OUT PNDIS_STATUS  Status,
    OUT PNDIS_STATUS  OpenErrorStatus,
    OUT PNDIS_HANDLE  NdisBindingHandle,
    OUT PUINT  SelectedMediumIndex,
    IN PNDIS_MEDIUM  MediumArray,
    IN UINT  MediumArraySize,
    IN NDIS_HANDLE  NdisProtocolHandle,
    IN NDIS_HANDLE  ProtocolBindingContext,
    IN PNDIS_STRING  AdapterName,
    IN UINT  OpenOptions,
    IN PSTRING  AddressingInformation
    );

An intermediate driver passes a handle at ProtocolBindingContext that represents the binding-specific context area that it allocated and initialized. NDIS will pass this context back to the intermediate driver in future calls pertaining to the binding — for example, in calls to Protocol(Co)Receive or Protocol(Co)Status. Similarly, NDIS will pass a handle at NdisBindingHandle to the intermediate driver when NdisOpenAdapter returns. This handle must be retained by the intermediate driver, usually in its binding-specific context area. The intermediate driver passes this handle to NDIS in future calls relating to this binding, such as calls to NdisSend or Ndis(Co)SendPackets.

ProtocolBindAdapter also passes the types of mediums that it supports at MediumArray. If NdisOpenAdapter is successful, the underlying miniport driver selects a medium that it can support and returns the index of the selected medium from MediumArray at SelectedMediumIndex.

ProtocolBindAdapter passes the value returned from a previous successful call to NdisRegisterProtocol at NdisProtocolHandle.

If NdisOpenAdapter returns an error, the intermediate driver should deallocate the memory used for the context area and release any other resources that it allocated for the binding. Typically, ProtocolBindAdapter logs any failed binding operations with appropriate descriptive information by calling NdisWriteErrorLogEntry.


Initializing as a Miniport

ProtocolBindAdapter, after it has successfully opened an underlying NIC and is ready to accept requests and sends on its virtual miniports , calls NdisIMInitializeDeviceInstanceEx one or more times to request initialization of one or more virtual miniports.

Note An intermediate driver is not required to call NdisIMInitializeDeviceInstanceEx when it opens an underlying NIC. There does not have to be a one-to-one relationship between virtual miniports and open adapters.

The DriverInstance parameter of NdisIMInitializeDeviceInstanceEx is set to the device name for the virtual miniport being initialized. The intermediate driver obtains the device name from the UpperBindings registry key.

A filter intermediate driver has a one-to-one relationship between virtual miniports and physical NICs. Therefore, the UpperBindings registry key contains exactly one name. For filter intermediate drivers, the net class installer creates a virtual miniport instance for each physical NIC and stores a string that identifies the virtual miniport in the UpperBindings registry key.

For an n-to-one MUX intermediate driver that layers multiple virtual miniports over a single physical NIC, there must be a device name for every virtual miniport. The MUX intermediate driver requires a notify object that maintains the list of virtual miniport device names. The recommended location for the list is the UpperBindings registry key. In this case, the UpperBindings registry key is a MULTI_SZ entry containing the list of device names. The MUX intermediate driver calls NdisIMInitializeDeviceInstanceEx once for each device name specified in the device name list.

Calling NdisIMInitializeDeviceInstanceEx results in a call to the intermediate driver's MiniportInitialize function to perform the initialization of the specified virtual miniport. The call to MiniportInitialize can happen at a later time and therefore is not necessarily within the context of the call to NdisIMInitialzieDeviceInstanceEx. If NDIS never calls MiniportInitialize for the virtual miniport referenced in a call to NdisIMInitialzieDeviceInstanceEx, and the intermediate driver no longer requires the virtual miniport, the intermediate driver should call NdisIMCancelInitializeDeviceInstance to cancel the initialization of the virtual miniport. For example, suppose that an intermediate driver creates a virtual miniport in response to a successful binding to an underlying miniport. If that binding is removed before NDIS calls MiniportInitialize, the intermediate driver should call NdisIMCancelInitializeDeviceInstance to cancel the initialization of the miniport.

MiniportInitialize must allocate and initialize a virtual-miniport-specific context area. As part of initialization, MiniportInitialize must call NdisMSetAttributesEx and pass a handle to that context area. NDIS will pass this context handle in subsequent calls to the MiniportXxx functions. MiniportInitialize also must set the NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER flag the AttributeFlags passed to NdisMSetAttributesEx. An intermediate driver sets the NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER flag to identify its driver type to NDIS.

In addition, MiniportInitialize should set the NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT and NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT flags in AttributeFlags passed to NdisMSetAttributesEx. These timeouts are not needed because intermediate drivers are de-serialized and NDIS does not queue packets for de-serialized drivers.

If the intermediate driver registers an entry point at CheckForHangHandler, and does not change the time-out interval, its MiniportCheckForHang function will be called, by default, every two seconds. If MiniportCheckForHang returns TRUE, the MiniportReset function will be called. If the driver supplies a MiniportCheckForHang function, it can change the default two-second interval by explicitly specifying a different TimeInSeconds when it calls NdisMSetAttributesEx.

An intermediate driver must operate as a deserialized driver and must register itself as such by setting the NDIS_ATTRIBUTE_DESERIALIZE flag in the AttributeFlags parameter passed to NdisMSetAttributesEx. A deserialized driver serializes the operation of its MiniportXxx functions and queues internally all incoming send packets rather than relying on NDIS to maintain its send queue. For more information about deserialized drivers, see Deserialized NDIS Miniport Drivers.

An intermediate driver must also set the NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND flag in the AttributeFlags parameter that is passed to NdisMSetAttributesEx. Setting this flag prevents NDIS from halting the virtual miniport when the system makes a transition to a low-power state.

An intermediate driver should make sure that the state information it maintains is properly initialized. If the driver requires send-related resources—for example, new packet descriptors for packets that MiniportSend or MiniportSendPackets will transmit to the next lower layer—the packet pool can be allocated at this time.


Intermediate Driver Query and Set Operations

After it has successfully bound to an underlying miniport driver and initialized its virtual miniports, an intermediate driver queries the operating characteristics of the underlying miniport driver and sets its own internal state. If appropriate, the intermediate driver also negotiates such parameters as lookahead buffer size for the binding with the underlying miniport driver. An intermediate driver with a connectionless lower edge accomplishes this by calling NdisRequest. An intermediate driver with a connection-oriented lower edge accomplishes this by calling NdisCoRequest.

An intermediate driver can also receive query and set requests from protocol drivers at its MiniportQueryInformation and MiniportSetInformation functions, respectively. The driver can either respond to those requests or pass them down to the underlying driver. How an intermediate driver responds to queries and sets depends on the implementation.

Note The behavior of intermediate drivers can also be affected by the power state of the virtual miniport and the underlying miniport driver. To learn more about the effects of the power state on query and set operations, see Handling a Set Power Request.

The Network Driver Reference contains information about all the general, connection-oriented, non-media-specific OIDs and about required media-specific OIDs of interest to intermediate driver developers. The following mentions typical and commonly used general category OIDs, connection-oriented OIDs, and a few media-specific OIDs.

Issuing Set and Query Requests

An intermediate driver with a connectionless lower edge typically issues an OID_GEN_MAXIMUM_FRAME_SIZE request to query the maximum frame size, in bytes, that is supported by an underlying miniport driver. The size returned does not include the header.

An intermediate driver with a connectionless lower edge can query a binding with OID_GEN_MAXIMUM_TOTAL_SIZE to determine the largest packet an underlying miniport driver can accommodate on the NIC that it manages. The intermediate driver must always set up send packets that conform to this size. It is an error for an overlying driver to submit a larger packet than a miniport driver to which it is bound can support.

An intermediate driver with a connectionless lower edge can query the size of the lookahead data buffer. The OID used is OID_GEN_CURRENT_LOOKAHEAD. If the intermediate driver issues this as a query, NDIS returns the current lookahead buffer size for the given binding to the underlying miniport driver. If the intermediate driver makes a set request, it indicates its preferred lookahead buffer size but the intermediate driver is not assured that the underlying miniport driver will conform to this.

An intermediate driver with a connectionless lower edge queries the underlying miniport driver for its link speed with OID_GEN_LINK_SPEED and uses the response to set any internal time-out values that it maintains. An intermediate driver with a connection-oriented lower edge queries the underlying miniport driver for its link speed with OID_GEN_CO_LINK_SPEED and can also set the link speed of the underlying miniport driver with OID_GEN_CO_LINK_SPEED.

If an intermediate driver is bound to a WAN miniport driver, it cannot determine the link speed until it receives a line-up indication, indicating that a connection has been established between the local node and a remote node. For a description of the line-up indication, see WAN Miniport Driver Indications.

An intermediate driver must also determine the set of operating characteristics of the underlying miniport driver. An intermediate driver with a connectionless lower edge accomplishes this by issuing an OID_GEN_MAC_OPTIONS. An intermediate driver with a connection-oriented lower edge accomplishes this by issuing an OID_GEN_CO_MAC_OPTIONS.

An intermediate driver with a connectionless lower edge usually issues an OID_GEN_MAXIMUM_SEND_PACKETS query, particularly if the intermediate driver exports a MiniportSendPackets function. Such an intermediate driver can propagate the returned value when it, in turn, responds to an OID_GEN_MAXIMUM_SEND_PACKETS query from a still higher-level driver.

An intermediate driver also can query the medium-dependent current address with a medium-specific OID. For example, an intermediate driver with a connectionless lower edge might issue an OID_WAN_CURRENT_ADDRESS, OID_802_3_CURRENT_ADDRESS, OID_802_5_CURRENT_ADDRESS, or OID_FDDI_LONG_CURRENT_ADDRESS. An intermediate driver with a connection-oriented lower edge might issue an OID_ATM_HW_CURRENT_ADDRESS.

If needed, the intermediate driver issues a set request to inform NDIS of its operating characteristics. An intermediate driver with a connectionless lower edge accomplishes this by passing OID_GEN_PROTOCOL_OPTIONS to NdisRequest. An intermediate driver with a connection-oriented lower edge accomplishes this by passing OID_GEN_CO_PROTOCOL_OPTIONS to NdisCoRequest.

An intermediate driver bound to a WAN-capable NIC must also make the following set-information requests:

  • OID_WAN_PROTOCOL_TYPE to inform the underlying miniport driver of the protocol's type. The type is supplied as a single-byte, network-level protocol identifier.
  • OID_WAN_HEADER_FORMAT to inform the underlying miniport driver of the header format of the packets it sends.

Responding to Sets and Queries

Because an intermediate NDIS driver is bound to by an overlying NDIS driver, it can also receive queries and sets at its MiniportQueryInformation and MiniportSetInformation functions. In some cases, the intermediate driver just passes such requests through to the underlying miniport driver. Otherwise, it can respond to these queries and sets as appropriate to the medium it exports at its upper edge. Note that an intermediate driver must always pass through any OID_PNP_XXX requests that it receives from an overlying NDIS driver to the underlying miniport driver.

Typically, the general OIDs received by an intermediate driver will be the same or similar to those that the intermediate driver makes to the underlying miniport driver. The medium-specific OIDs received by an intermediate driver will be the type of the medium expected by the overlying driver.

Note If an intermediate driver modifies the contents of TCP packets that it forwards down to an underlying miniport driver such that TCP offload functions cannot be performed on the packets, the intermediate driver should respond to OID_TCP_TASK_OFFLOAD queries with a status of NDIS_STATUS_NOT_SUPPORTED instead of passing the request down to the underlying miniport.


Registering an Intermediate Driver as a Connection-Oriented Client

An intermediate driver with a connection-oriented lower edge must register as a connection-oriented client. A connection-oriented client uses the call-set-up and tear-down services of a call manager or integrated miniport call manager (MCM). A connection-oriented client also uses the send and receive capabilities of a connection-oriented miniport driver or an MCM to send and receive data. For more information, see Connection-Oriented NDIS.

When a call manager or MCM, from its ProtocolBindAdapter function, calls Ndis(M)CmRegisterAddressFamily to register an address family, NDIS calls the ProtocolCoRegisterAfNotify function of all protocol drivers on the binding. If an intermediate driver registered a ProtocolCoAfRegisterNotify function when it registered as a protocol, NDIS calls the intermediate driver's ProtocolCoAfRegisterNotify function.

If ProtocolCoAfRegisterNotify determines that the intermediate driver can use the services of the call manager or MCM that registered the address family, it allocates a per-AF context area for the client and calls NdisClOpenAddressFamily. With the call to NdisClOpenAddressFamily¸ an intermediate driver registers a set of client-supplied functions

NdisClOpenAddressFamily is declared as follows:

NDIS_STATUS
  NdisClOpenAddressFamily(
    IN NDIS_HANDLE  NdisBindingHandle,
    IN PCO_ADDRESS_FAMILY  AddressFamily,
    IN NDIS_HANDLE  ProtocolAfContext,
    IN PNDIS_CLIENT_CHARACTERISTICS  ClCharacterisitics,
    IN UINT  SizeOfClCharacteristics,
    OUT PNDIS_HANDLE  NdisAfHandle
    );

Before calling NdisClOpenAddressFamily, the intermediate driver must:

  1. Zero a structure of type NDIS_CLIENT_CHARACTERISTICS. The current version of the ClCharacteristics structure is 5.0.
  2. Store the addresses of the ProtocolXxx client functions that that driver supports.

The NdisAfHandle returned by this call is opaque to an intermediate driver. The handle must be retained by the intermediate driver and provided as an input parameter in future calls made by the protocol part of the intermediate driver to NDIS—for example, to register a SAP with NdisClRegisterSap.

The client functions that an intermediate driver must register with NdisClOpenAddressFamily are listed below:

ClCreateVcHandler
Specifies the entry point of the caller's ProtocolCoCreateVc function.
ClDeleteVcHandler
Specifies the entry point of the caller's ProtocolCoDeleteVc function.
ClRequestHandler
Specifies the entry point of the caller's ProtocolCoRequest function.
ClRequestCompleteHandler
Specifies the entry point of the caller's ProtocolCoRequestComplete function.
ClOpenAfCompleteHandler
Specifies the entry point of the caller's ProtocolClOpenAfComplete function.
ClCloseAfCompleteHandler
Specifies the entry point of the caller's ProtocolClCloseAfComplete function.
ClRegisterSapCompleteHandler
Specifies the entry point of the caller's ProtocolClRegisterSapComplete function. ProtocolClRegisterSapComplete is called to notify the client that its call to NdisRegisterSap that returned NDIS_STATUS_PENDING has now completed.
ClDeregisterSapCompleteHandler
Specifies the entry point of the caller's ProtocolClDeregisterSapComplete function.
ClMakeCallCompleteHandler
Specifies the entry point of the caller's ProtocolClMakeCallComplete function. A client uses this function to make outgoing calls to remote machines.
ClModifyCallQoSCompleteHandler
Specifies the entry point of the caller's ProtocolClModifyCallQoSComplete function. ProtocolClModifyCallQoSComplete is called to notify the client that its call to NdisClModifyCallQos that returned NDIS_STATUS_PENDING has now completed.
ClCloseCallCompleteHandler
Specifies the entry point of the caller's ProtocolClCloseCallComplete function.
ClAddPartyCompleteHandler
Specifies the entry point of the caller's ProtocolClAddPartyComplete function. ProtocolClAddPartyComplete is called to notify the client that its call to NdisClAddParty that returned NDIS_STATUS_PENDING has now completed.
ClDropPartyCompleteHandler
Specifies the entry point of the caller's ProtocolClDropPartyComplete function.
ClIncomingCallHandler
Specifies the entry point of the caller's ProtocolClIncomingCall function. A client uses this function to accept incoming calls from remote machines.
ClIncomingCallQoSChangeHandler
Specifies the entry point of the caller's ProtocolClIncomingCallQoSChange function.
ClIncomingCloseCallHandler
Specifies the entry point of the caller's ProtocolClIncomingCloseCall function.
ClIncomingDropPartyHandler
Specifies the entry point of the caller's ProtocolClIncomingDropParty function.
ClCallConnectedHandler
Specifies the entry point of the caller's ProtocolClCallConnected function. A client uses this function to accept incoming calls from remote machines.

The intermediate driver must set every Cl Xxx member in the NDIS_CLIENT_CHARACTERISTICS structure to a caller-supplied ProtocolCl/CoXxx function when it calls NdisClOpenAddressFamily, even if it does not support incoming calls, outgoing calls, or point-to-multipoint connections. For whatever subset of connection-oriented functionality that such an intermediate driver does not support, its ProtocolCl/CoXxx functions simply return NDIS_STATUS_NOT_SUPPORTED.


Intermediate Driver Unbinding Operations

An intermediate driver unbinds from the underlying miniport driver by calling NdisCloseAdapter from its ProtocolUnbindAdapter function which NDIS calls when the underlying NIC is no longer available.

An intermediate driver's ProtocolUnbindAdapter function might be called when the driver has an outstanding call to NdisIMInitializeDeviceInstanceEx. This situation occurs when the corresponding virtual miniport has not been initialized yet by a call to MiniportInitialize. In this case, the intermediate driver must attempt to cancel initialization of these virtual miniports by calling NdisIMCancelInitializeDeviceInstance.

An intermediate driver also must unbind from an adapter during initialization if some action subsequent to opening an adapter, such as allocating a required resource, fails, and the intermediate driver needs to unbind because it cannot carry out network operations on the binding.

The intermediate driver must not release the per-binding resources until it completes a call to NdisCloseAdapter either synchronously or asynchronously. If NdisCloseAdapter returns NDIS_STATUS_PENDING, the intermediate driver cannot deallocate any per-binding resources until its ProtocolCloseAdapterComplete function is called.

NDIS does not call ProtocolCloseAdapterComplete until all outstanding requests on the binding have completed. When ProtocolCloseAdapterComplete returns control to NDIS, the ProtocolBindingContext handle that the intermediate driver allocated to represent the binding is invalid.

Before returning synchronously from ProtocolUnbindAdapter or before completing the unbind operation asynchronously with NdisCompleteUnbindAdapter, the intermediate driver must do the following:

  • Finish cleaning up any state that it maintains for the binding
  • Release any resources that it allocated to establish the binding
  • Call NdisCloseAdapter

If the underlying miniport driver binding that is being closed is mapped to a device exported by the intermediate driver, and if that device was initialized by calling NdisIMInitializeDeviceInstanceEx, the intermediate driver can close these devices by calling NdisIMDeInitializeDeviceInstance . The result is that the intermediate driver's virtual miniport becomes no longer available for sends or requests made by higher-level drivers.

After an intermediate driver calls NdisCloseAdapter, it should fail any send requests for that binding with an appropriate error status.


Intermediate Driver Packet Management

An intermediate driver receives a packet descriptor with one or more chained buffers of data from a higher-level driver to send over the network. The intermediate driver can pass the packet through to the underlying driver by calling NdisSend or NdisSendPackets if the driver has a connectionless lower edge, or by calling NdisCoSendPackets if the driver has a connection-oriented lower edge. Alternatively the intermediate driver can take some actions to modify either the contents of the chained buffers or perhaps the ordering or timing of the incoming packets relative to other transmissions.

NDIS 4.0 and 5.0 intermediate drivers must allocate a new NDIS_PACKET to encapsulate data that they pass on. These intermediate drivers must also copy any out-of-band (OOB) data to the new packet. Even if the intermediate driver does nothing other than simply pass on incoming packets(s) — for example, if it simply counts the packets — it must allocate a fresh packet descriptor and manage some or all of a new packet structure.

NDIS 5.1 intermediate drivers that support packet stacking avoid this extra data handling in most common cases. Each NDIS_PACKET allocated includes "stacks", where each stack is defined as:

typedef struct _NDIS_PACKET_STACK
{
  ULONG_PTR  IMReserved[2];
  ULONG_PTR  NdisReserved[4];
} NDIS_PACKET_STACK, *PNDIS_PACKET_STACK;

NDIS 5.1 intermediate drivers call the NdisIMGetCurrentPacketStack function to access the IMReserved member in the NDIS_PACKET_STACK structure. This member can be used by an NDIS 5.1 intermediate driver to store its context information, if any, for the packet. NDIS 4.0 and 5.0 intermediate drivers use the ProtocolReserved and MiniportReserved members, for sent and received packets, in the NDIS_PACKET structure. If a call to NdisIMGetCurrentPacketStack indicates *StacksRemaining is FALSE, the NDIS 5.1 intermediate driver must revert to the NDIS 5.0 packet handling model.Every NDIS 4.0 and 5.0 intermediate driver must allocate new packet descriptors to replace those of the overlying driver. If an intermediate driver converts the packet from one format to another, it also can allocate buffer descriptors to map intermediate-allocated buffers into which the converted data is copied. If there is OOB data associated with the packet descriptor being copied, this data can be copied to the new OOB block associated with the intermediate-allocated packet descriptor, using the macro NDIS_OOB_DATA_FROM_PACKET, to obtain a pointer to the OOB data area and, then, calling NdisMoveMemory to move the contents into the OOB area associated with the new packet descriptor. Alternatively, such an intermediate driver can use the NDIS_GET_PACKET_XXX and NDIS_SET_PACKET_XXX macros to read specific items from the OOB data associated with the old packet descriptor and to write the OOB data for the new packet descriptor.

Packet descriptors must be allocated by calling the following NDIS functions:

  1. NdisAllocatePacketPool or NdisAllocatePacketPoolEx to allocate and initialize a block of nonpaged pool for a caller-specified number of fixed-size packet descriptors
  2. NdisAllocatePacket to allocate a packet descriptor from the pool allocated by NdisAllocatePacketPool(Ex)

Depending on the purpose of the intermediate driver, such a driver can repackage buffers chained to incoming packet descriptors. For example, an intermediate driver allocates buffer pool and repackages incoming packet data in the following circumstances:

  • The intermediate driver receives a larger data buffer from an overlying protocol driver than can be sent in a single buffer over the underlying medium. Consequently, the intermediate driver must divide the incoming data into smaller buffers.
  • The intermediate driver changes the length or content of the packet data by compressing or encrypting the data before forwarding each send to the underlying driver.

Such buffers can be allocated by calling the following NDIS functions:

  1. NdisAllocateBufferPool to obtain a handle with which to allocate buffer descriptors
  2. NdisAllocateMemoryWithTag to allocate a buffer
  3. NdisAllocateBuffer to allocate and set up a buffer descriptor to map the buffer allocated by calling NdisAllocateMemoryWithTag and to chain to the packet descriptor allocated by calling NdisAllocatePacket

Buffer descriptors are chained to a packet descriptor by calling NdisChainBufferAtBack or NdisChainBufferAtFront. The virtual address and the length of the buffer returned by NdisAllocateMemory(WithTag) are passed in the call to NdisAllocateBuffer to initialize the buffer descriptor that maps the buffer.

Packet descriptors to meet typical needs can be allocated as needed, at driver initialization time, or in the ProtocolBindAdapter function. An intermediate driver developer can, if necessary and for performance reasons, allocate a number of packet descriptors and possibly buffers mapped by buffer descriptors at initialization time so that ProtocolReceive has preallocated resources into which to copy incoming data for indicating to a higher-level driver, and so that MiniportSend or MiniportSendPackets has available descriptors (and possibly buffers) to pass incoming send packets on to the next lower driver.

Note NDIS manages received and sent packets differently. If an intermediate drivers preallocates and reuses packets, it should manage separate send and receive packet pools.

If an intermediate driver copies send data or received data to a new buffer or buffers, and the length of actual data in the last buffer is less than the allocated length of the buffer, the intermediate driver calls NdisAdjustBufferLength to adjust the buffer descriptor to the actual length of the data. When the packet is returned to the intermediate driver, it should again make this call to readjust the length to the full length of its buffer.

An intermediate driver with a connectionless lower edge can receive incoming data from an underlying miniport driver by:

  • Receiving a complete packet, specified by a packet descriptor of type NDIS_PACKET, at its ProtocolReceivePacket function, or
  • the data can be indicated to its ProtocolReceive function and copied into an intermediate-driver-supplied packet.

An intermediate driver with a connection-oriented lower edge always receives incoming data from an underlying miniport driver as a complete packet at its ProtocolCoReceivePacket function.

An intermediate driver can retain ownership of a received packet in the following circumstances:

  • When an intermediate driver with a connectionless lower edge has a complete packet indicated to its ProtocolReceivePacket function
  • When an intermediate driver with a connection-oriented lower edge has a packet indicated to its ProtocolCoReceivePacket function with the Status member of NDIS_PACKET_OOB_DATA set to anything other than NDIS_STATUS_RESOURCES

In these cases, the driver can retain ownership of the packet descriptor and the resources that it describes until the received data is consumed and return these resources to the underlying driver later by calling NdisReturnPackets. If ProtocolReceivePacket passes the packets that it received to a higher-level driver, it must, at a minimum, replace the input packet descriptor with one that the intermediate driver has allocated.

Depending on an intermediate driver's purpose when it receives a full packet from an underlying driver, several packet-management strategies are possible. For example, it can do either of the following:

  • Copy the buffered contents into an intermediate driver-allocated buffer mapped and chained to a fresh packet descriptor, return the input packet descriptor to the underlying driver, and then indicate the new packet to the higher-level driver.
  • Create a new packet descriptor and chain the buffers from the indicated packet descriptor to this new descriptor. This new packet descriptor can then be indicated up to the higher-level driver. When this higher-level driver returns the packet descriptor, the intermediate driver must unchain the buffers from its packet descriptor, chain them to the packet descriptor it originally received from the underlying driver, and return the original packet descriptor and the resources that it describes to the underlying driver.

Even if an intermediate driver with a connectionless lower edge has a ProtocolReceivePacket function, it must also have a ProtocolReceive function. NDIS calls ProtocolReceive whenever the underlying driver will not relinquish ownership of the resources it indicates with a packet descriptor, and the intermediate driver must copy the received data into its own buffers when such an indication occurs. If the underlying driver also indicates out-of-band data with receives, ProtocolReceive can call NdisGetReceivedPacket and NDIS_GET_ORIGINAL_PACKET to get the per-packet information associated with the receive indication.

When an underlying connection-oriented miniport driver will not relinquish ownership of the resources that it indicates with a packet descriptor, it sets the Status member of the packet's NDIS_PACKET_OOB_DATA to NDIS_STATUS_RESOURCES. The ProtocolCoReceivePacket function of the intermediate driver then must copy the received data into its own buffers.

Reusing Packets

After NDIS returns an intermediate-driver-allocated packet descriptor to the intermediate driver by calling ProtocolSendComplete, or by calling MiniportReturnPacket, the intermediate driver owns the packet descriptor and all the resources that it describes. If a higher-level or lower-level driver supplied the buffers chained to such a returned packet descriptor, the intermediate driver should return these resources back to the allocating driver promptly.

If the intermediate driver originally allocated the packet descriptor and/or the chained buffers, it can reclaim its resources and use them in subsequent sends or use them for received data that is indicated to ProtocolReceive. It is more efficient for the intermediate driver to reinitialize and reuse the packet descriptors that it allocates, and to reuse any intermediate driver-allocated chained buffer descriptors and buffers, than to deallocate and then later reallocate these resources.

An intermediate driver reinitializes a packet descriptor by calling NdisReinitializePacket. However, the intermediate driver should first take care to remove any chained buffers and their buffer descriptors by calling NdisUnchainBufferAt Xxx. Otherwise, because NdisReinitializePacket will clear the member that points to the chain of buffers, such a call without previously deallocating or saving the chained buffers will cause a memory leak. Similarly, if there is OOB data at MediaSpecificInformation associated with the packet descriptor, this memory must be reclaimed before reinitializing the packet descriptor.


Restrictions on Intermediate Drivers

Previous sections have described specific actions an intermediate driver must follow to perform correctly, summarized as follows:

  1. An intermediate driver must set the NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER flag when it calls NdisMSetAttributesEx in its MiniportInitialize function. NDIS identifies that a driver is an intermediate type only through the presence of this flag.
  2. An NDIS 4.0 or NDIS 5.0 intermediate driver must always, at a minimum, replace an incoming packet descriptor for a packet that it passes down to an underlying driver on a send or up to a higher-level driver on a receive with a fresh packet descriptor, allocated by the intermediate driver. NDIS 5.1 drivers that support packet-stacking do not have this restriction. The NDIS 4.0 or NDIS 5.0 intermediate driver must also then replace its own packet descriptor with the one that originally was associated with the packet when it was passed to the intermediate driver—for example, when completing a send or completing a receive indication. The intermediate driver must return the resources that it has "borrowed" from a higher or lower driver promptly by returning that driver's packet descriptor and the resources that it specifies.
  3. An intermediate driver must follow the rules that apply to any deserialized miniport driver in particular, the following guideline:

    If any internal driver resources are shared between an intermediate driver's send function and any other MiniportXxx function, that resource must be protected by a spin lock.

    As for any deserialized miniport driver, an intermediate driver that organizes its per-binding context area into discrete receive-specific, send-specific, and shared ranges, with only the shared resources protected by spin locks, will exhibit far better performance than a driver that must overprotect its context area because send-specific, receive-specific, and shared variables are scattered throughout.


Receiving Data in an Intermediate Driver

Intermediate drivers receive data at their protocol lower edge in much the same way as protocol drivers. The following list summaries the basic requirements:

  • Intermediate driver protocols should provide both ProtocolReceive and ProtocolReceivePacket functions when layered above connectionless miniports.
  • For NDIS 5.1, intermediate drivers should use packet stacking.
  • If an intermediate driver must create new packet descriptors, because it does not support packet stacking or to handle the case where stack locations are not available, it should also copy the OOB data.

For more information about managing received packets in intermediate drivers and packet-stacking, see Intermediate Driver Packet Management. For more information about receiving data in an NDIS protocol driver, see Receiving Data in a Protocol Driver.

Additional information about receiving data in intermediate drivers is also provided in the following sections:

Receiving Data in an Intermediate Driver with a Connectionless Lower Edge

Receiving Data in an Intermediate Driver with a Connection-Oriented Lower Edge

Indicating Receive Packets to Higher Level Drivers

Accessing Per-Packet Information from an Intermediate Driver


Receiving Data in an Intermediate Driver with a Connectionless Lower Edge

Underlying connectionless miniport drivers can indicate packets in two ways:

  • A miniport driver calls the non-media-specific NdisMIndicateReceivePacket, passing a pointer to an array of pointers to one or more packet descriptors, relinquishing ownership of the indicated packet resources to higher level drivers. When the higher level drivers have consumed the data, they return the packet descriptors (and the resources they specify) to the NIC driver.
  • A miniport driver calls a media-specific NdisM Xxx IndicateReceive function, passing a pointer to a lookahead buffer and the total size of the packet.

An intermediate driver with a connectionless lower edge must have ProtocolReceive and ProtocolReceivePacket functions.

Because the underlying miniport driver also indicates per-packet information and/or OOB data, the intermediate driver must retrieve this information in ProtocolReceive by calling NdisGetReceivedPacket and NDIS_GET_ORIGINAL_PACKET.

For more information about receiving data in an intermediate driver with a connectionless lower edge, see Receiving Data in a Connectionless Protocol Driver.


Receiving Data in an Intermediate Driver with a Connection-Oriented Lower Edge

An underlying connection-oriented miniport driver indicates packets by calling NdisMCoIndicateReceivePacket, passing a pointer to an array of pointers to one or more packet descriptors. If an intermediate driver is layered above the miniport driver, NDIS then calls the intermediate driver's ProtocolCoReceivePacket function.

For more information about receiving data in an intermediate driver with a connection-oriented lower edge, see Receiving Data in a Connection-Oriented Protocol Driver.


Indicating Receive Packets to Higher Level Drivers

An intermediate driver indicates receive packets to the next higher driver by calling NdisMIndicateReceivePacket or a media-specific NdisM Xxx IndicateReceive function.

Before indicating the packet, it processes the receive packet, perhaps converting it to the format expected by a higher-level driver, and if required, coping relevant data into buffers chained to an intermediate-driver-allocated packet descriptor.

Note Typically, an NDIS 5.1 intermediate driver that implements packet stacking will not have to allocate a new packet descriptor.


Accessing Per-Packet Information from an Intermediate Driver

NDIS per-packet information includes items such as checksum, security and priority information. Intermediate drivers should use the NDIS_PER_PACKET_INFO_FROM_PACKET macro to retrieve per-packet out-of-band (OOB) data. NDIS_PER_PACKET_INFO_FROM_PACKET returns a pointer to a specific type of per-packet information associated with a packet descriptor. For more information about per-packet information, see Accessing Per-Packet Information.

If NDIS indicates data to an intermediate driver's ProtocolReceive function, the intermediate driver calls NdisGetReceivedPacket and NDIS_GET_ORIGINAL_PACKET to retrieve the original packet.

The intermediate driver can obtain information from the OOB data associated with the packet, using NDIS-supplied macros as follows:

  • Media-specific information is read using NDIS_GET_MEDIA_SPECIFIC_INFO, and written using NDIS_SET_MEDIA_SPECIFIC_INFO
  • TimeSent is read using NDIS_GET_TIME_SENT, and written using NDIS_SET_TIME_TO_SEND
  • TimeReceived is read using NDIS_GET_TIME_RECEIVED

Note Most miniport drivers do not support TimeSent and TimeReceived.


Transmitting Packets Through an Intermediate Driver

As discussed in Registering an Intermediate Driver as a Miniport, an intermediate driver must provide a MiniportSendPackets function when it registers with NdisIMRegisterLayeredMiniport. The MiniportSendPackets function can forward incoming packet arrays by calling NdisSendPackets if the driver has a connectionless lower edge or NdisCoSendPackets if the driver has a connection-oriented lower edge. MiniportSendPackets can send the array of packets it receives with NdisSendPackets without regard to the capabilities of the underlying miniport driver. NDIS can, transparently to the intermediate driver, queue the packets in the array and send each individual packet to the underlying connectionless miniport driver's MiniportSend function when the miniport driver is able to accept the send request.

An NDIS 4.0 or 5.0 intermediate driver will, at a minimum, replace the packet descriptor for each incoming send with its own. It must retain the original descriptor (and chained buffers if it copies them to new buffers) from the higher-level driver and, when the send completes, the intermediate driver must return the original packet descriptor and the data buffers of the as-sent packet before completing the send back to the higher-level driver.

In most common cases, an NDIS 5.1 intermediate driver that implements packet-stacking will not have to allocate a new packet descriptor. For more information on how to allocate packet resources and copy information from one packet to another, see Intermediate Driver Packet Management.

MiniportSendPackets receives an array of packet descriptors arranged in an order determined by the caller of NdisSendPackets. In most cases, the intermediate driver should maintain this ordering as it passes an incoming array of packets on to the underlying miniport driver. An intermediate driver that modifies per-packet information or OOB data in incoming packets before passing them on to the underlying driver might reorder an incoming array.

NDIS always preserves the ordering of packet descriptor pointers as passed as an array to NdisSendPackets. The underlying miniport driver also assumes that an array of packet pointers passed in to its MiniportSendPackets function implies the packets should be transmitted in the same order.

An intermediate driver with a connectionless lower edge can call NdisRequest with a RequestType of NdisQueryInformation and an OID_GEN_MAXIMUM_SEND_PACKETS to obtain the maximum number of send packets that the underlying driver will accept in a packet array. When an intermediate driver with a connectionless lower edge transmits one or more packets by calling NdisSendPackets or when an intermediate driver with a connection-oriented lower edge transmits one or more packets by calling NdisCoSendPackets, the send operation is implicitly asynchronous. The caller relinquishes ownership of its packet descriptors and all the resources that they describe until each packet descriptor and the final status of the send for that packet is returned to Protocol(Co)SendComplete. Protocol(Co)SendComplete must propagate the status of the send of each packet back to the next higher driver as described in the previous paragraph.

As a consequence, when an intermediate driver sends packets in an array using NdisSendPackets, the intermediate driver should not attempt to read the Status members of the associated OOB blocks on return from NdisSendPackets. This member is in use by NDIS to track the progress of an in-transition send request and is volatile. An intermediate driver can only obtain the status of a transmit request by examining the Status argument passed to its Protocol(Co)SendComplete function.

If an intermediate driver requests the transmission of an array of packets of different priorities by rearranging the packets that it receives from an overlying driver before transmitting them, it should place the highest priority packets at the beginning of the array. NDIS retains this ordering when it passes the packets to either the MiniportSend or to the Miniport(Co)SendPackets function of the underlying miniport driver, even if NDIS queues some of the packets internally. This ordering is maintained by NDIS for each call to Ndis(Co)SendPackets.

Unless an intermediate driver has special knowledge of the manner in which a miniport driver handles packet priority, it should assume that the miniport driver transmits the packets in the order in which it receives them, preserving the as-received order.

The structure of the Private member of an NDIS_PACKET-type descriptor is opaque to an intermediate driver and is accessed to read and, in some cases, to write using NDIS-supplied macros or functions.


Sending Media-Specific OOB Information

NDIS per-packet information includes items such as checksum, security, and priority information. Intermediate drivers should use the NDIS_PER_PACKET_INFO_FROM_PACKET macro to set per-packet information. For more information about per-packet information, see Accessing Per-Packet Information.

Some media-specific information can be passed by an older intermediate driver in the out-of-band (OOB) block associated with each NDIS_PACKET descriptor. The OOB block is defined in the NDIS_PACKET_OOB_DATA data structure.If the intermediate driver knows that the underlying miniport driver to which it is sending packets supports OOB data, it can optionally set certain OOB structure members. For example, an intermediate driver can:

  • Request that the packet be sent at a specific time by writing the TimeToSend member using the NDIS_SET_PACKET_TIME_TO_SEND macro. This macro passes the requested time in system time units. The driver can call NdisGetCurrentSystemTime in order to obtain the current system time with which to calculate a requested send time.

    Note Most minport drivers do not support this feature.

  • Pass media-specific information in a caller-allocated buffer at MediaSpecificInformation using the NDIS_PACKET_SET_MEDIA_SPECIFIC_INFO macro.


Handling PnP Events and PM Events in an Intermediate Driver

An intermediate driver must be capable of handling Plug and Play events and Power Management (PM) events. Specifically:

  • An intermediate driver must set the NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND flag in the AttributeFlags parameter passed to NdisMSetAttributesEx. For more information, see Initializing as a Miniport.
  • The virtual miniport of an intermediate driver must handle OID_PNP_XXX requests.
  • The protocol section of an intermediate driver must propagate the appropriate OID_PNP_XXX requests to the underlying miniport driver. The virtual miniport of the intermediate driver must pass the underlying miniport driver's responses to these requests back to the protocol driver that originated the requests.
  • The protocol portion of an intermediate driver must supply a ProtocolPnPEvent handler.

Intermediate driver protocol and miniport event handlers are not called in any particular order. Event handlers for intermediate drivers should be implemented accordingly.


Handling OID_PNP_XXX Queries and Sets

The virtual miniport of an intermediate driver must export MiniportQueryInformation and MiniportSetInformation functions. NDIS calls the intermediate driver's MiniportQueryInformation or MiniportSetInformation function when an overlying driver bound to the intermediate driver's virtual miniport calls NdisRequest to query or set information objects (OID_XXX), or NDIS can also call MiniportQueryInformation or MiniportSetInformation on its own behalf. For more information on miniport driver handling of sets and queries to information objects, see Obtaining and Setting Miniport Driver Information and NDIS Support for WMI.

The intermediate driver is not required to maintain information about the capabilities of the underlying miniport driver. However, the intermediate driver can query or set OID_XXX maintained by the underlying miniport driver with NdisRequest (if the intermediate driver has a connectionless lower edge) or with NdisCoRequest (if the intermediate driver has a connection-oriented lower edge).

An intermediate driver should handle queries and sets as follows:

  • OID_PNP_CAPABILITIES

    The intermediate driver forwards OID_PNP_CAPABILITIES requests to the underlying miniport driver. The response from the underlying miniport driver must be modified before forwarding the response at the intermediate driver's upper edge. If the underlying NIC is PM-aware, the intermediate driver must return NDIS_STATUS_SUCCESS to a query of OID_PNP_CAPABILITIES. In the NDIS_PM_WAKE_UP_CAPABILITIES structure returned by this OID, the intermediate driver must specify a device power state of NdisDeviceStateUnspecified for each wake-up capability:

    • MinMagicPacketWakeUp
    • MinPatternWakeUp
    • MinLinkChangeWakeUp

    Such a response indicates that the intermediate driver is PM-aware but is incapable of waking up the system.

    If the underlying NIC is not PM-aware, the intermediate driver must return NDIS_STATUS_NOT_SUPPORTED to a query of OID_PNP_CAPABILITIES.

  • OID_PNP_QUERY_POWER and OID_PNP_SET_POWER

    The intermediate driver must always return NDIS_STATUS_SUCCESS to a query of OID_PNP_QUERY_POWER or a set of OID_PNP_SET_POWER. The intermediate driver must never propagate either of these OID requests to the underlying miniport driver.

  • "Wake-up OIDs"

    If the underlying NIC is PM-aware, the intermediate driver must pass to the underlying miniport driver (by calling Ndis(Co)Request) the following OID_PNP_XXX relating to wake-up events:

    OID_PNP_ENABLE_WAKE_UP

    OID_PNP_ADD_WAKE_UP_PATTERN

    OID_PNP_REMOVE_WAKE_UP_PATTERN

    OID_PNP_WAKE_UP_PATTERN_LIST

    OID_PNP_WAKE_UP_ERROR

    OID_PNP_WAKE_UP_OK

The intermediate driver must also propagate the underlying miniport driver's response to these OIDs to the overlying protocol drivers.

If the underlying NIC is not PM-aware, the intermediate driver should return NDIS_STATUS_NOT_SUPPORTED in response to a query or set of these OIDs.


Implementing a ProtocolPnPEvent Handler in an Intermediate Driver

When the operating system issues a Plug and Play IRP or a Power Management IRP to a target device object that represents an underlying NIC, NDIS intercepts the IRP and then indicates the event to each bound intermediate driver and each bound protocol driver by calling the driver's ProtocolPnPEvent handler. In the call to ProtocolPnPEvent, NDIS passes a pointer to a NET_PNP_EVENT structure that describes the Plug and Play event or Power Management event being indicated.

NDIS 5.1 intermediate drivers pass on PnP events to higher layer drivers by calling NdisIMNotifyPnPEvent.

There are six possible Plug and Play and Power Management events, as indicated by the NetEvent code in the NET_PNP_EVENT structure:

  • NetEventSetPower

    Indicates a Set Power request, which specifies that the underlying miniport driver should transition to a particular power state. An intermediate driver should always succeed this event by returning NDIS_STATUS_SUCCESS. For more information on handling a Set Power request, see Handling a Set Power Request.

  • NetEventQueryPower

    Indicates a Query Power request, which queries whether the intermediate driver's protocol edge can handle the underlying NIC's transition to a particular power state. An intermediate driver should always succeed this event by returning NDIS_STATUS_SUCCESS. Note that a NetEventQueryPower is always followed by a NetEventSetPower. A NetEventSetPower to the device's current power state in effect cancels the NetEventQueryPower.

  • NetEventQueryRemoveDevice

    Indicates a Query Remove Device request, which queries whether the underlying NIC can be removed without disrupting operations. If an intermediate driver cannot release a device (for example, because the device is in use) it must fail a NetEventQueryRemoveDevice by returning NDIS_STATUS_FAILURE.

  • NetEventCancelRemoveDevice

    Indicates a Cancel Remove Device request, which cancels the removal of an underlying NIC. The intermediate driver should always succeed this event by returning NDIS_STATUS_SUCCESS.

  • NetEventReconfigure

    Indicates that the configuration has changed for a network component. For example, if a user changes the IP address for TCP/IP, NDIS indicates this event to the TCP/IP protocol with the NetEventReconfigure code. The intermediate driver can, in rare circumstances, return a failure code if it is not able to apply the indicated configuration changes and there are no available default values. A failed attempt to allocate memory is an example of a circumstance in which the driver returns a failure code. Returning an error code can result in prompting the user to reboot the system.

  • NetEventBindList

    Indicates to a protocol that its bind list processing order has been reconfigured. This list indicates a relative order to be applied to the protocol's bindings when processing, for example, a user request that might be routed to one of several bindings. The buffer passed with this event contains a list of device names formatted as null-terminated Unicode strings. The format of each device name is identical to the DeviceName parameter passed to a call to ProtocolBindAdapter.

  • NetEventBindComplete

    Indicates that the intermediate driver protocol edge has bound to all the NICs to which it can bind. NDIS will not indicate any more bindings to the intermediate driver unless, for example, a Plug and Play NIC is plugged into the system.

The Buffer member of the NET_PNP_EVENT points to a buffer that contains information specific to the event being indicated. For more information, see NET_PNP_EVENT.

An intermediate driver can complete the call to ProtocolPnPEvent asynchronously with NdisCompletePnPEvent.


Handling a Set Power Request

Previous Next

Handling a Set-Power Request

An intermediate driver must handle set-power requests to the working state (a network device power state of D0) and to sleeping states (a network device power state of D1, D2, or D3). The intermediate driver should also maintain power state variables and a StandBy flag. These issues are discussed further in this topic. You can also see the PassThru intermediate driver sample for examples of intermediate driver power management.

Handling a Set Power Request to a Sleeping State

There are two cases where an intermediate driver must handle a set power request to a sleeping state:

  • NDIS requests the virtual miniport upper edge of the intermediate driver to go to a sleeping state.
  • The intermediate driver protocol lower edge handles the underlying miniport driver transition to a sleeping state when it receives a Plug and Play event notification.

These events can happen in any order and one event does not necessarily accompany the other.

The sequence of events in handling set power requests to a sleeping state for the virtual miniport is as follows:

  1. NDIS calls the ProtocolPnPEvent function of each protocol driver bound to the virtual miniport. The call to ProtocolPnPEvent specifies a NetEventSetPower to a sleeping state. Protocol drivers that are bound to the intermediate driver stop sending packets and making OID requests to the intermediate driver virtual miniport. The protocol lower edge of the intermediate driver can continue to send packets and requests down until NDIS indicates that the underlying miniport driver is making the transition to a sleeping state.
  2. NDIS issues an OID_PNP_SET_POWER request to the virtual miniport of the intermediate driver. The intermediate driver succeeds the request by returning NDIS_STATUS_SUCCESS. The intermediate driver must not propagate the OID_PNP_SET_POWER request to the underlying miniport driver. Once the intermediate driver completes this request, it should not indicate any more receive packets or indicate status even if it keeps receiving packets and status indications from the underlying miniport driver.
  3. Typically, an intermediate driver does not de-initialize its virtual miniport. If the underlying miniport driver is PM-aware and supports wake-up events, the intermediate driver should not de-initialize its virtual miniport. If the intermediate driver does de-initialize its virtual miniport by calling NdisIMDeinitializeDeviceInstance, NDIS calls the ProtocolUnbindAdapter function of each bound protocol driver to unbind it from the virtual miniport.

The sequence of events in handling set power requests to a sleeping state for the underlying miniport driver is as follows:

  1. NDIS calls the ProtocolPnPEvent function of the intermediate driver protocol lower edge. The call to ProtocolPnPEvent specifies a NetEventSetPower to a sleeping state. The intermediate driver must stop sending packets and making OID requests to the underlying miniport driver. Before returning from the ProtocolPnPEvent function, the intermediate driver can use the NdisQueryPendingIOCount function to verify that outstanding requests and sends submitted to the underlying miniport driver have completed. If there are outstanding requests or sends, the intermediate driver should return NDIS_STATUS_PENDING from the call to ProtocolPnPEvent and then call NdisQueryPendingIOCount periodically until it returns zero. When NdisQueryPendingIOCount returns zero, the intermediate driver calls NDISCompletePnPEvent to complete the call to ProtocolPnPEvent. The protocol edge of an intermediate driver can still get received packet and status indications from the underlying miniport driver. Received packets can be ignored. If an intermediate driver's implementation depends upon monitoring the status of the underlying miniport driver, status indications should still be monitored.
  2. NDIS issues an OID_PNP_SET_POWER request to the underlying miniport driver or if the underlying miniport driver does not support power management, it will be halted. In this case, even though NDIS halts the underlying miniport driver, it does not request the intermediate driver protocol to unbind from the underlying miniport driver and NIC. Once the underlying miniport driver has successfully completed processing the OID (or the miniport driver is halted), it will not indicate any more packets or status.

Handling a Set Power Request to the Working State

There are two cases where an intermediate driver handles a set power request to the working state:

  • NDIS requests the virtual miniport (upper edge) of the intermediate driver to go to the working state.
  • The intermediate driver protocol lower edge handles the underlying miniport driver transition to the working state when it receives a Plug and Play event notification.

These events can occur in any order and one event does not necessarily accompany the other.

The sequence of events in handling set-power requests to a working state for the virtual miniport is as follows:

  1. NDIS issues an OID_PNP_SET_POWER to the virtual miniport of the intermediate driver. The intermediate driver returns NDIS_STATUS_SUCCESS to the set-power request. The intermediate driver must not propagate the OID_PNP_SET_POWER request to the underlying miniport driver.
  2. If the intermediate driver de-initialized its virtual miniport by calling NdisIMDeInitializeDeviceInstance, it can reinitialize the virtual miniiport with NdisIMInitializeDeviceInstanceEx. The virtual miniport should be reinitialized when the intermediate driver is ready to accept I/O requests.

The sequence of events in handling set power requests to a working state for the underlying miniport driver is as follows:

  1. NDIS issues an OID_PNP_SET_POWER to the underlying miniport driver or calls its MiniportInitialize handler if the underlying miniport driver was halted.
  2. NDIS calls the ProtocolPnPEvent function of the intermediate driver. The call to ProtocolPnPEvent specifies a NetEventSetPower to the working state. Bound protocol drivers can start sending packets to the intermediate driver.

Power States and the Standby Flag

The intermediate driver should maintain a separate power state variable for each virtual miniport instance and for each underlying miniport driver to which the driver is bound. The intermediate driver should also maintain a StandingBy flag for each virtual miniport that is:

  • Set to TRUE when the power state of either the virtual miniport or the underlying miniport driver leaves D0.
  • Set to FALSE when the power state of either the virtual miniport or the underlying miniport driver returns to D0.

Note For MUX intermediate drivers there can be multiple virtual miniports associated with an underlying miniport driver or multiple underlying miniports associated with each virtual miniport. When the power state of any miniport changes, the behavior of all the associated miniports are also affected. How the behavior is affected is implementation specific. For example, a driver that implements an Load Balancing Fail Over (LBFO) solution might not deactivate the virtual miniports when a single underlying miniport driver is deactivated. However, a driver implementation that depends on all underlying miniport drivers would require deactivation of virtual miniports when any underlying miniport driver is deactivated.

The intermediate driver should use the StandingBy flag and power state variables when processing requests as follows:

  • The driver's MiniportSend function should fail unless the virtual miniport and its underlying miniport driver are both in D0.
  • The driver's MiniportQueryInformation function should always succeed OID_PNP_QUERY_POWER to ensure that the driver receives the subsequent OID_PNP_SET_POWER requests. MiniportQueryInformation should fail all other requests if the indicated virtual miniport is not in D0, or if its StandingBy flag is TRUE. Otherwise, if the underlying miniport driver that is associated with the indicated virtual miniport is not in D0, MiniportQueryInformation should queue a single request for the virtual miniport. A queued request should be processed when the underlying miniport driver state becomes D0.
  • The driver's MiniportSetInformation function should fail if the virtual miniport is not in D0 or StandingBy is TRUE. Otherwise, it should queue a single request if the underlying miniport driver is not in D0. A queued request should be processed when the underlying miniport driver state becomes D0.
  • The intermediate driver virtual miniport should only report status if both the underlying miniport driver and virtual miniport are in D0.


Intermediate Driver Reset Operations

An intermediate driver must be prepared to handle the situation where its outstanding sends on a binding to an underlying driver can be dropped because the underlying NIC is reset.

An underlying driver typically resets its NIC because NDIS calls the miniport driver's MiniportReset function when NDIS times out queued sends or requests bound for the NIC. A miniport driver can also reset its NIC because a higher-level driver called NdisReset. If an underlying NIC is reset, NDIS calls the Protocol(Co)Status function of each bound protocol and intermediate driver with a status of NDIS_STATUS_RESET_START, and then calls the same bound driver's ProtocolStatusComplete function. When the miniport driver completes the reset, NDIS again calls Protocol(Co)Status with a status of NDIS_STATUS_RESET_END followed by a call to ProtocolStatusComplete.

When a NIC is reset, if a bound intermediate driver has any transmit packets pending to that NIC, NDIS completes those packets back to the intermediate driver with an appropriate status. The intermediate driver must resubmit these packets again when the reset is completed.

When an intermediate driver receives a status of NDIS_STATUS_RESET_START, it should:

  • Hold any packets ready to be transmitted until Protocol(Co)Status receives an NDIS_STATUS_RESET_END notification and ProtocolStatusComplete is called.
  • Hold any received packets that are ready to be indicated up to the next higher driver until Protocol(Co)Status receives an NDIS_STATUS_RESET_END notification and ProtocolStatusComplete is called.
  • Clean up any internal state it maintains for in-progress operations and NIC status.

After Protocol(Co)Status receives NDIS_STATUS_RESET_END and ProtocolStatusComplete is called, the intermediate driver can resume sending packets, making requests and making indications to higher-level drivers.

Because an intermediate driver usually disables timing out of sends and requests by NDIS when it calls NdisMSetAttributesEx, its MiniportReset function is seldom called. If MiniportReset is called, possibly because a higher-level driver called NdisReset, the intermediate driver should reset its internal state if necessary and it should always set AddressingReset to TRUE before it returns.


Status Indications in an Intermediate Driver

An intermediate driver with a connectionless lower edge is required to supply a ProtocolStatus function and a ProtocolStatusComplete function. NDIS calls ProtocolStatus when an underlying connectionless miniport driver calls NdisMIndicateStatus to report a change in its hardware status. ProtocolStatus is called when the status change begins. NdisMIndicateStatusComplete is subsequently called by the underlying miniport driver. When this occurs, ProtocolStatusComplete is called to carry out any postprocessing for the status change. However, a miniport driver need not deliver NdisMIndicateStatusComplete indications in one-to-one correspondence with its NdisMIndicateStatus indications. It can issue a single status-complete indication for several status indications.

A connection-oriented intermediate driver is required to supply a ProtocolCoStatus function and a ProtocolStatusComplete function. NDIS calls ProtocolCoStatus when an underlying connection-oriented miniport driver calls NdisMCoIndicateStatus to report a change in its hardware status. ProtocolCoStatus is called when the status change begins.

Examples of GeneralStatus reported to ProtocolStatus include:

  • NDIS_STATUS_MEDIA_CONNECT and NDIS_STATUS_MEDIA_DISCONNECT. When a miniport driver senses that the network connection has been lost, it calls NdisMIndicateStatus or NdisMCoIndicateStatus with NDIS_STATUS_MEDIA_DISCONNECT. When the connection is restored, it must then call NdisM(Co)IndicateStatus with NDIS_STATUS_MEDIA_CONNECT.
  • NDIS_STATUS_RESET_START and NDIS_STATUS_RESET_END. Both these are reported to both Protocol(Co)Status and ProtocolStatusComplete as explained in Intermediate Driver Reset Operations.
  • NDIS_STATUS_LINE_UP, if the intermediate driver is layered over a WAN-capable miniport driver that has established a connection with a remote node. For more information about WAN drivers, see WAN Miniport Drivers.
  • NDIS_STATUS_RING_STATUS, for which StatusBuffer provides more detailed information, for example on problems specific to a Token Ring medium.

When an intermediate driver receives a status indication, it indicates it up to the higher-level drivers by calling NdisMIndicateStatus only if the status indication causes the intermediate driver to change its internal state in a way that affects the operation of its MiniportXxx functions. That is, if the status indicated to the intermediate driver causes the driver to fail sends or requests, it can pass the status indication to the higher-level drivers which presumably will then hold off on submitting sends and requests. If, however, the intermediate driver continues to accept sends and requests, perhaps queuing them internally, it should not pass the status indication up.


Installing Intermediate Drivers

Intermediate drivers require two INF files. One of the INF files defines the installation parameters for the protocol lower edge. The other INF file defines the installation parameters for the virtual miniport upper edge.

The protocol INF file is the primary INF file. After the protocol lower edge is installed, the virtual miniport upper edge is installed, based upon references to the miniport INF that are defined in the protocol INF.

On Windows 2000 you can use a notify object or a custom setup application to copy the miniport INF file to the system INF directory. For Windows XP and later versions you should use the INF CopyINF directive in the protocol INF to copy the miniport INF. For more information about the notify object and copying INF files, see Intermediate Driver Notify Object.

The system-supplied device setup class for the protocol lower edge is NetService for filter intermediate drivers and NetTrans for MUX intermediate drivers. The driver class for the virtual miniport is always Net.

In addition to the INF files, you must also provide a notify object with a MUX intermediate driver. The notify object is optional for filter intermediate drivers.

The virtual miniport device is always removed from the user interface by using the ExcludeFromSelect directive. Therefore, the user only sees the protocol and installs the protocol from the protocol INF file.

Note The ExcludeFromSelect directive does not remove the virtual device from the Connections dialog box. However, the NCF_HIDDEN flag in the miniport INF file DDInstall section's Characteristics entry prevents the virtual miniport from being displayed in any part of the user interface, including the Connections dialog box.

This section includes the following topics, which discuss intermediate INF files and notify objects.

Intermediate Driver UpperRange And LowerRange INF File Entries

Filter Intermediate Driver Installation

MUX Intermediate Driver Installation


Intermediate Driver UpperRange And LowerRange INF File Entries

This topic describes how to use the UpperRange and LowerRange INF file entries to define NDIS intermediate driver binding relationships.

In a network driver INF file, the UpperRange entry lists the possible upper bindings and the LowerRange entry lists the possible lower bindings. There are various system-defined values for these lists.

For filter intermediate drivers, you must set the value of the UpperRange and LowerRange entries to noupper and nolower, respectively. You should define these entries only in the protocol INF file; they are not required in the miniport INF file. The following example illustrates these entries for a filter intermediate driver:

HKR, Ndi\Interfaces, UpperRange, , noupper
HKR, Ndi\Interfaces, LowerRange, , nolower

In a filter intermediate driver, the FilterMediaTypes entry in the protocol INF file defines the driver's bindings to other drivers . FilterMediaTypes specifies the media types serviced by the filter intermediate driver. For a list of possible media types, see the list of Microsoft-supplied LowerRange values in Specifying Binding Interfaces. The following example illustrates this entry for a filter intermediate driver:

HKR, Ndi\Interfaces, FilterMediaTypes, , "ethernet, tokenring, fddi, wan"

When a filter intermediate driver is initialized, it inserts itself into all existing protocol-to-miniport bindings, as appropriate to the media types listed in FilterMediaTypes .

For MUX intermediate drivers, you always set UpperRange in the protocol INF file to noupper. You set LowerRange to a list of values taken from those values allowed for LowerRange, as specified in Specifying Binding Interfaces. The following example illustrates these entries for a MUX intermediate driver's lower edge:

HKR, Ndi\Interfaces, UpperRange, 0, "noupper"
HKR, Ndi\Interfaces, LowerRange, 0, "ndis5"

For MUX intermediate drivers, you always set LowerRange in the miniport INF file to nolower. You set the UpperRange to a list of values taken from those values allowed for the UpperRange, as specified in Specifying Binding Interfaces. The following example illustrates these entries for a MUX intermediate driver virtual miniport:

HKR, Ndi\Interfaces, UpperRange, 0, "ndis5"
HKR, Ndi\Interfaces, LowerRange, 0, "nolower"


Filter Intermediate Driver Installation

This topic provides an overview of NDIS filter intermediate driver installation issues. For additional information about the structure of intermediate driver INF files, see Installation Requirements for Network Filter Intermediate Drivers.

A filter intermediate driver requires two INF files. The protocol INF file defines the installation parameters for the protocol lower edge. The virtual miniport INF file defines the installation parameters for the virtual miniport upper edge. You set the Class INF file entry to Net in the virtual miniport INF file and NetService in the protocol INF file. A sample Class entry for the protocol INF file follows:

Class = NetService

The DDInstall section in a filter intermediate driver INF file must have a Characteristics entry. You define the Characteristics entry in your protocol INF file as demonstrated in the following sample:

Characteristics = 0x410

The 0x410 value indicates that the NCF_FILTER and NCF_NO_SERVICE flags are set. NCF_FILTER is required for filter intermediate drivers. NCF_NO_SERVICE is optional.

You define the Characteristics entry in your virtual miniport INF file as demonstrated in the following sample:

Characteristics = 0x29

The Characteristics value 0x29 indicates the NCF_VIRTUAL (0x1), NCF_HIDDEN (0x8) and NCF_NOT_USER_REMOVABLE (0x20) flags are set. NCF_VIRTUAL specifies that the device is a virtual adapter. NCF_NOT_USER_REMOVABLE is optional and specifies that the user cannot remove the intermediate driver. NCF_HIDDEN is optional. You define NCF_HIDDEN if you want to hide the virtual miniport from the user (you should not do this if your user must install devices manually).

The values of the NCF_* flags are defined in netcfgx.h. For more information about NCF_* flags, see DDInstall Section.

The DDInstall section of the protocol INF file for a filter intermediate driver must include an Addreg directive for an Ndi key. The protocol INF file must specify the Service entry under the Ndi key. The virtual miniport INF file, in turn, contains an AddService directive that references a service-install section. The ServiceName value of this AddService directive must match the name of the protocol INF Service entry. The ServiceBinary entry in the service-install section of the virtual miniport INF file specifies the path to the binary for the filter intermediate driver. During virtual miniport installation, this filter intermediate driver must have been already transferred to the target computer using the CopyFiles directive of the protocol INF file. For more information, see Adding Service-Related Values to the Ndi Key and DDInstall.Services Section.

The following example shows how a filter intermediate driver protocol INF file specifies the name of the service:

HKR, Ndi,            Service,             , Passthru

This name is the name of the driver's service as it is reported to NDIS. Note that the name of a filter intermediate driver's service need not be the same as the name of the binary for the driver although typically they are the same.

The following is an example of how the virtual miniport INF file references the name of the filter intermediate driver's service when it adds that service:

[PassthruMP.ndi.Services]
AddService = Passthru,0x2, PassthruMP.AddService

[PassthruMP.AddService]
DisplayName    = %PassthruMP_Desc%
ServiceType    = 1 ;SERVICE_KERNEL_DRIVER
StartType      = 3 ;SERVICE_DEMAND_START
ErrorControl   = 1 ;SERVICE_ERROR_NORMAL
ServiceBinary  = %12%\passthru.sys
LoadOrderGroup = PNP_TDI

The user installs the protocol INF file. The protocol INF file references the virtual miniport INF from the FilterDeviceInfId INF file entry as follows:

HKR, Ndi,            FilterDeviceInfId,   , ms_passthrump

Define the virtual miniport INF part of the reference as follows:

%PassthruMP_Desc% = PassthruMP.ndi, ms_passthrump

[Strings]
Msft = "Microsoft"
PassthruMP_Desc = "Passthru Miniport"

The FilterDeviceInfld (ms_passthrump in the example) in the protocol INF file must match the name provided in the virtual miniport INF file.

The FilterClass value of a filter intermediate driver determines its order in a stack of filters. Filter intermediate drivers must define the FilterClass key. The class of the driver can be one of the values in the following table:

Value | DescriptionMeaning
scheduler | Packet-scheduling filter service. This class of filter intermediate driver is the highest driver in a stack. A packet scheduler detects the 802.1p priority classification given to packets by QoS-signaling components, and sends those packets according to their priority levels to underlying drivers.
loadbalance | Load-balancing filter service. This class of filter intermediate driver exists between packet-scheduling and fail-over drivers. A load balancing filter service balances its workload of packet transfers by distributing the workload over its bundle of underlying miniport instances.
failover | Fail-over filter service. This class of filter intermediate driver is the lowest driver in a stack. That is, no other drivers that belong to other classes, if installed, can be between this driver's virtual miniport and the adapter being filtered.

Note Only one filter intermediate driver of a specific class can exist in a layered stack of filter intermediate drivers. For example, two filter intermediate drivers of FilterClass "schedule" cannot exist in a stack simultaneously.

A sample FilterClass entry follows:

HKR, Ndi,            FilterClass,         , failover

You must define the following entries in the filter intermediate driver protocol INF file to control the driver bindings:

HKR, Ndi\Interfaces, UpperRange,          , noupper
HKR, Ndi\Interfaces, LowerRange,          , nolower
HKR, Ndi\Interfaces, FilterMediaTypes,    , "ethernet, tokenring, fddi, wan"

For more information about controlling the driver bindings, see Intermediate Driver UpperRange And LowerRange INF File Entries.

A filter intermediate driver does not require a notify object for proper installation. When no notify object DLL is provided, the network class installer completes the installation automatically.

A notify object can be used to provide a user interface for the entry of component specific parameters and configuration information. For more information about creating a notify object, see Intermediate Driver Notify Object.

Adapting the Passthru Sample INF files

The best way to create your own filter intermediate driver INF files is to copy the INF files from the Passthru sample driver and modify them.

To adapt the protocol INF file

  1. Change passthru.sys to the name of your own driver in the SourceDiskFiles and Passthru.CopyFiles.Sys sections.
  2. Change the values for BindForm and MiniportId in the Passthru.ndi.AddReg section to appropriate values.

To adapt the virtual miniport INF file

  1. Replace "MS_PassthruMP" with the InfId of your virtual miniport.
  2. Change ServiceBinary in the PassthruMP.AddService section to the name of your driver.
  3. Change "Passthru" in the PassthruMP.ndi.AddReg section "Service" line to reflect the appropriate name.


Using a Notify Object DLL with a Filter Intermediate Driver

You can use a notify object DLL with your filter intermediate driver to provide a user interface for the entry of component specific parameters and configuration information.

To use a notify object DLL with a filter intermediate driver, you must create the DLL and install it from the intermediate driver protocol INF file.

The protocol INF file must include the following attributes to install the notify object:

  • You must define the ClsID and ComponentDll INF file entries as follows:
HKR, Ndi, ClsID, , {df2e4f67-e93a-11d1-bb14-0000f8779051}
HKR, Ndi, ComponentDll, , passthru.dll
  • You should change Passthru.dll to the name of your notify object DLL. You should also change the Clsid to a new ID that you created with the Uuidgen.exe tool.
  • Define the NCF_HAS_UI flag in the Characteristics entry. The values of this NCF_* flags are defined in netcfgx.h. A sample Characteristics entry follows:
Characteristics = 0x490
  • The 0x490 value indicates that NCF_HAS_UI , NCF_FILTER and NCF_NO_SERVICE are set.
  • Add the name of the Notify Object DLL to the copy files list as follows:
[SourceDisksFiles]
passthru.dll=1
passthru.sys=1
netsf_m.inf=1
  • Substitute the name of your notify object DLL for passthru.dll.
  • Add an new section name to the copy files line. Include the files you need to install to support your notify object DLL in the new copy files section as shown:
CopyFiles=Passthru.CopyFiles.Sys, Passthru.CopyFiles.Init

[Passthru.CopyFiles.Init]
passthru.dll,,,2


MUX Intermediate Driver Installation

This topic provides an overview of MUX intermediate driver installation issues. For additional information about the structure of intermediate driver INF files, see Installation Requirements for Network MUX Intermediate Drivers.

A MUX Intermediate driver requires two INF files. The protocol INF file defines the installation parameters for the protocol lower edge. The miniport INF file defines the installation parameters for the virtual miniport upper edge. Set the Class INF file entry to Net in the virtual miniport INF file and NetTrans in the protocol INF file. A sample Class entry for the protocol INF file follows:

Class = NetTrans

The DDInstall section in a MUX intermediate driver INF file must have a Characteristics entry. You define the Characteristics entry in your protocol INF file as demonstrated in the following sample:

Characteristics = 0x80

NCF_HAS_UI (0x80) is required to enable custom property pages, which in this case is the notify object

You define the Characteristics entry in your miniport INF file as demonstrated in the following sample:

Characteristics = 0x21

The Characteristics value 0x21 indicates the NCF_VIRTUAL (0x1) and NCF_NOT_USER_REMOVABLE (0x20) flags are set. NCF_VIRTUAL specifies that the device is a virtual adapter. NCF_NOT_USER_REMOVABLE is optional and specifies that the user cannot remove the intermediate driver. If you want to hide the virtual miniport from the user (you should not do this if your user must install devices manually) you can define the NCF_HIDDEN (0x8) flag. The NCF_* flags are defined in netcfgx.h. For more information about the Characteristics entry and NCF_* flags, see Ddinstall Section.

The DDInstall section of the protocol INF file for a MUX intermediate driver must include an Addreg directive for an Ndi key. For more information, see Adding Service-Related Values to the Ndi Key and DDInstall.Services Section.

In addition to the INF files, you must also provide a notify object with a MUX Intermediate driver. The notify object is responsible for installation of virtual miniports. You reference the notify object with the ComponentDll entry in the protocol INF as follows:

HKR, Ndi,            ComponentDll,   , mux.dll

The user installs the protocol INF file which defines configuration parameters, copies installation files and also installs the notify object DLL. The user adds virtual miniports through the user interface provided by the notify object. The miniport INF file should define the ExcludeFromSelect entry to prevent the user from installing the miniport INF file instead of the protocol INF file.

The protocol name registered by the driver must match the service name.

HKR, Ndi, Service, 0, MUXP

The UpperRange and LowerRange INF file entries determine the bindings for a MUX intermediate driver. The protocol INF file must define the protocol edge bindings as follows:

HKR, Ndi\Interfaces, UpperRange,    0,          "noupper"
HKR, Ndi\Interfaces, LowerRange,    0,          "ndis5"

The miniport INF file must define the upper edge bindings as follows:

HKR, Ndi\Interfaces,    UpperRange, 0,  "ndis5"
HKR, Ndi\Interfaces,    LowerRange, 0,  "nolower"

You should replace "ndis5" in the preceding examples with the protocol bindings required by your driver. For more information about intermediate driver bindings and the UpperRange/LowerRange entries, see Intermediate Driver UpperRange And LowerRange INF File Entries.


Intermediate Driver Notify Object

An intermediate driver notify object is an extension of the network class installer. The network class installer loads and initializes your notify object and sends it notifications of events (such as virtual miniport removal notifications) related to your driver. If you want an overview of notify objects in general or more information about notify objects, see Notify Objects for Network Components.

To include the notify object in your installation, you must reference it in your intermediate driver protocol INF. Filter intermediate drivers do not require a notify object. You can include a notify object with your filter intermediate driver if you would like to provide more flexible configuration options to your user. For more information about including a notify object with your filter intermediate driver, see Using a Notify Object DLL with a Filter Intermediate Driver.

On Windows 2000 you can use the notify object or a custom setup application to copy the miniport INF file to the system INF directory. For either of these, you use SetupCopyOEMInf (described in Platform SDK documentation) to copy the INF. For Windows XP and later versions you should use the INF CopyINF Directive in the protocol INF to copy the miniport INF. For more information about copying INF files, see Copying INFs.

A MUX intermediate driver notify object must provide services to install and remove virtual miniports. This can be done automatically or by providing a user interface. It must manage the miniport device name list in the registry. The device name list defines the bindings between virtual miniports and physical devices. For example, the n-to-one MUX intermediate driver sample notify object maintains a list of virtual miniports bound to each physical device in an UpperBindings registry entry. The MUX sample driver reads the UpperBindings list and initializes a virtual miniport for each entry.

Your MUX intermediate driver should use the UpperRange/LowerRaange entries to control external bindings. However, you can control external bindings from your notify object if necessary. For more information about bindings in intermediate drivers, see Intermediate Driver UpperRange And LowerRange INF File Entries

Your notify object can optionally provide a user interface that allows the user to change or view your driver's configuration. The MUX intermediate driver sample includes an example user interface for a notify object.


NDIS Protocol Drivers

This section describes the features of an NDIS driver that exports a set of ProtocolXxx functions at its lower edge. Such a protocol driver communicates with NDIS to send and receive network packets and to bind to and use an underlying miniport NIC driver or intermediate NDIS driver that exports a MiniportXxx interface at its upper edge.

Such an NDIS protocol driver might support TDI at its upper edge, or it might export a private interface to a higher level kernel-mode driver, possibly through a transport stack of drivers, including one that supports TDI at the top of the stack. For instance, an NDIS protocol driver can be the lowest module of a multimodule transport implementation of a standard protocol such as TCP/IP with TDI support in the highest module.

Protocol drivers that communicate with lower level NDIS drivers to send and receive packets always use NDIS-provided functions to communicate with the lower level NDIS drivers. For example, a protocol driver that has a connectionless lower-edge (which communicates with underlying drivers for connectionless media such as Ethernet or token ring) must call NdisSend or NdisSendPackets to send a packet or packets to a lower level NDIS driver and must call NdisRequest to make or pass through query- or set-information requests with network related OID_XXXs that are supported by underlying connectionless drivers. A protocol driver that has a connection-oriented lower edge (which communicates with underlying drivers for connection-oriented media such as ATM and ISDN) must call NdisCoSendPackets to send a packet or packets to a lower-level NDIS driver and must call NdisCoRequest to query or set OID_XXXs that are supported by underlying connection-oriented drivers.

NDIS also provides a set of Ndis Xxx functions that hide the details of the underlying operating system. For example, a protocol driver can call NdisInitializeEvent to create an event for synchronization purposes and NdisInitializeListHead to create a linked list. Protocol drivers that use the NDIS versions of such functions are more portable across Microsoft operating systems that support the Win32® interface. However, protocol drivers can also call kernel-mode support routines, such as IoCreateDevice. For more information, see Summary of Kernel-Mode Support Routines.

Pageable and Discardable Code

Every ProtocolXxx function runs at an IRQL in the range from PASSIVE_LEVEL to DISPATCH_LEVEL.

Functions that run exclusively at IRQL=PASSIVE_LEVEL should be marked as pageable using the NDIS_PAGABLE_FUNCTION macro. Driver developers should designate code as pageable whenever possible, freeing system space for code that must be memory-resident. A driver function that runs at IRQL=PASSIVE_LEVEL can be made pageable as long as it neither calls nor is called by any function that runs at IRQL >= DISPATCH_LEVEL—such as a function that acquires a spin lock. Acquiring a spin lock causes the IRQL of the acquiring thread to be raised to IRQL DISPATCH_LEVEL. A driver function, such as ProtocolBindAdapter, that runs at IRQL=PASSIVE_LEVEL must not call any Ndis Xxx functions that run at IRQL >= DISPATCH_LEVEL if that driver function is marked as pageable code. See NDIS Library Functions , which specifies the IRQL for each Ndis Xxx function.

The DriverEntry function of a protocol driver, as well as code that is called only from DriverEntry, should be specified as initialization-only code, using the NDIS_INIT_FUNCTION macro. Code identified with this macro is assumed to only run once at system initialization time, and, as a result, is only mapped during that time. After a function marked as initialization-only returns, it is discarded.

Access to any driver-allocated shared resource must be synchronized if the resource can be simultaneously shared by two driver functions or if the protocol driver can run on an SMP machine such that the same protocol driver function can be attempting to simultaneously access a resource from more than one processor. For instance, if a driver maintains a shared queue, a spin lock can be used to serialize access to that queue. The spin lock should be initialized when such a queue is created.

However, care should be taken not to overprotect a shared resource, such as an internal driver queue. Some read-only operations can be done without serializing access to a queue, but any operation that manipulates the queue links must be serialized. Spin locks always should be used sparingly and held as short a time as possible. See Spin Locks for more information.


Protocol DriverEntry and Initialization

A protocol driver's initial required entry point must be explicitly named DriverEntry so that the loader can identify it. All other exported functions, described here as ProtocolXxx, can have any developer-specified name since they are passed as addresses to NDIS. The definition of DriverEntry is that of any kernel-mode driver.

If the protocol driver exports a set of standard kernel-mode driver routines, such as any (Tdi)DispatchXxx and Unload routines, in addition to the NDIS-defined ProtocolXxx functions, the protocol driver must set the entry points of its standard routines in the DriverObject passed to DriverEntry, like any other kernel-mode intermediate driver.

To set up communication with the NDIS library, a protocol's DriverEntry must register as a protocol driver by calling NdisRegisterProtocol, as described later.

DriverEntry also can initialize any spin locks the protocol requires — for example, to protect state variables that track connections and sends in progress or driver-allocated queues.

If DriverEntry fails to allocate any resources the protocol needs to operate, it should release any previously allocated resources, including making a call to NdisDeregisterProtocol, if necessary, and return an appropriate error status.

When called at its ProtocolBindAdapter function, the protocol allocates resources for managing bindings with the adapter to which it is being requested to bind. It then calls NdisOpenAdapter to create the binding.


Registering as an NDIS Protocol Driver

A driver registers its ProtocolXxx functions with NDIS in the context of its DriverEntry function by calling NdisRegisterProtocol, defined as follows:

VOID
NdisRegisterProtocol(
  OUT PNDIS_STATUS  Status,
  OUT PNDIS_HANDLE  NdisProtocolHandle,
  IN PNDIS_PROTOCOL_CHARACTERISTICS
                                           ProtocolCharacteristics,
  IN UINT  CharacteristicsLength
  );

The NdisProtocolHandle returned by this call is opaque to a protocol driver. The handle must be retained by the protocol driver and provided as an input parameter in future calls to NDIS — for example, to open an adapter:

Before making this call, DriverEntry must do the following:

  1. Zero-initialize a structure of type NDIS_PROTOCOL_CHARACTERISTICS — for instance, with a call to NdisZeroMemory. This assures that unused members for optional entry points are set to NULL. If the structure is not zeroed, any unused members must be set to NULL before calling NdisRegisterProtocol.
  2. Specify in the NDIS_PROTOCOL_CHARACTERISTICS structure the NDIS version with which the protocol is compatible, as described in Specifying the NDIS Version Number for a Protocol Driver.
  3. Store the addresses of the mandatory ProtocolXxx functions, as well as any optional ProtocolXxx functions the driver exports, in the NDIS_PROTOCOL_CHARACTERISTICS structure, as described in Registering the ProtocolXxx Functions of a Connectionless Protocol Driver and Registering the ProtocolXxx Functions of a Connection-Oriented Protocol Driver.


Specifying the NDIS Version Number for a Protocol Driver

The MajorNdisVersion and MinorNdisVersion members in the NDIS_PROTOCOL_CHARACTERISTICS structure specify the NDIS version with which the protocol is compatible. Valid NDIS version numbers for protocol drivers are as follows (formatted as MajorNdisVersion.MajorNdisVersion):

  • For Windows 2000 and Windows 98/Me, protocol drivers can have a 3.0, 4.0, or 5.0 version.
  • For Windows XP and later, protocol drivers can have a 4.0 or 5.0 version number. Protocol drivers must be PnP-ready. Version 3.0 protocol drivers are therefore not supported.


Registering the ProtocolXxx Functions of a Connectionless Protocol Driver

The possible and required protocol functions that a connectionless protocol driver can export are listed below:

BindAdapterHandler
This is a required function. NDIS calls this function to request that the protocol driver bind to an underlying miniport driver or virtual miniport. See Dynamic Binding in a Protocol Driver for more information on dynamic binding.
UnbindAdapterHandler
This is a required function. ProtocolUnbindAdapter is called by NDIS to close a binding to the underlying miniprt driver or virtual miniport. ProtocolUnbindAdapter calls NdisCloseAdapter and deallocates resources when the binding is successfully closed.
OpenAdapterCompleteHandler
This is a required function. If a protocol driver's call to NdisOpenAdapter returns NDIS_STATUS_PENDING, ProtocolOpenAdapterComplete is subsequently called to complete the binding operation.
CloseAdapterCompleteHandler
This is a required function. If a protocol driver's call to NdisCloseAdapter returns NDIS_STATUS_PENDING, ProtocolCloseAdapterComplete is subsequently called to complete the unbinding operation.
ReceiveHandler
This is a required function. ProtocolReceive is called with a pointer to a lookahead buffer. If this buffer contains less than the full, received network packet, ProtocolReceive calls NdisTransferData with a protocol-allocated packet descriptor specifying protocol-allocated buffers to obtain the remainder of the received packet.
ReceiveCompleteHandler
This is a required function. ProtocolReceiveComplete is called to indicate that any received packets previously indicated to ProtocolReceive can now be postprocessed.
TransferCompleteHandler
This is a required function. ProtocolTransferDataComplete is called when a previous call to NdisTransferData returned NDIS_STATUS_PENDING and the remaining data has been copied into the protocol-supplied buffers chained to a given packet descriptor.
ReceivePacketHandler
This is an optional function. It is recommended that protocols provide this function to obtain better performance from miniport drivers that indicate receive packets by calling NdisMIndicateReceivePacket.
SendCompleteHandler
This is a required function. ProtocolSendComplete is called for each packet transmitted with a call to NdisSend that returned NDIS_STATUS_PENDING as the status of the send operation. If an array of packets is sent, ProtocolSendComplete is called once for each packet passed to NdisSendPackets, whether or not it returned pending.
ResetCompleteHandler
This is a required function. ProtocolResetComplete is called when a protocol-initiated reset operation, begun with a call to NdisReset that returned NDIS_STATUS_PENDING, is completed.
RequestCompleteHandler
This is a required function. ProtocolRequestComplete is called when a protocol-initiated query or set operation, begun with a call to NdisRequest that returned NDIS_STATUS_PENDING, is completed.
StatusHandler
This is a required function. ProtocolStatus is called to handle status changes indicated by the underlying NDIS driver.
StatusCompleteHandler
This is a required function. ProtocolStatusComplete is called by NDIS, along with ProtocolStatus, to report the start and end of an NDIS- or NIC-driver-initiated reset operation.
PnPEventHandler
This is a required function. NDIS calls ProtocolPnPEvent to indicate a Plug and Play event or a Power Management event. See Handling PnP Events and Power Management Events in a Protocol Driver for more information.
UnloadHandler
This is an optional function. NDIS calls ProtocolUnload in response to a user request to uninstall a protocol driver. NDIS calls ProtocolUnload after calling ProtocolUnbindAdapter once for each bound adapter. ProtocolUnload performs driver-determined clean-up operations.

A protocol driver should set the ProtocolCharacteristics TranslateHandler member to NULL. The TranslateHandler member is reserved for future use.


Registering the ProtocolXxx Functions of a Connection-Oriented Protocol Driver

A connection-oriented protocol must register the following protocol handler functions that are common to both connectionless and connection-oriented protocols:

  • BindHandler (required)
  • UnbindHandler (required)
  • OpenAdapterCompleteHandler (required)
  • CloseAdapterCompleteHandler (required)
  • ReceiveCompleteHandler (required)
  • ResetCompleteHandler (required)
  • RequestCompleteHandler (required)
  • StatusCompleteHandler (required)
  • PnPEventHandler (required)

These functions are summarized in Registering the ProtocolXxx Functions of a Connectionless Protocol Driver.

A connection-oriented protocol must also register the following connection-oriented protocol functions. Specifying these entry points requires a V5.0 structure at ProtocolCharacteristics:

CoSendCompleteHandler
This is a required function. ProtocolCoSendComplete is called once for each packet passed to NdisCoSendPackets. The protocol driver can determine the status of a send operation that calls NdisCoSendPackets only from the status argument input to ProtocolCoSendComplete.
CoStatusHandler
This is a required function. ProtocolCoStatus is called by NDIS with status notifications initiated by an underlying NIC driver.
CoReceivePacketHandler
This is a required function. When a bound connection-oriented NIC driver or MCM indicates an array of pointers by calling NdisMCoIndicateReceivePacket, NDIS calls the protocol driver's ProtocolCoReceivePacketHandler.
CoAfRegisterNotifyHandler
If the protocol driver is a connection-oriented client that uses the call manager services of a call manager or an MCM driver, it must register a ProtocolCoAfRegisterNotify function. NDIS calls the ProtocolCoAfRegisterNotify function of each protocol on a binding when a call manager or MCM driver registers an address family with Ndis(M)CmRegisterNotify. ProtocolCoAfRegisterNotify determines whether the protocol driver can use the services of a call manager or MCM that has advertised its services. Protocol drivers that are standalone call managers must also register a CoAfRegisterNotifyHandler. When called by NDIS, the ProtocolCoAfRegisterNotify function of a call manager simply returns control.


Opening an Adapter Underlying a Protocol Driver

Whenever an underlying NIC to which a protocol driver can bind itself becomes available (that is, whenever the Plug and Play manager reports such an event to NDIS), NDIS calls the protocol's ProtocolBindAdapter function. The protocol driver typically reads adapter-specific configuration information from the registry and calls NdisOpenAdapter to set up a binding to the adapter.

A protocol driver obtains a handle to the registry key that contains adapter-specific information by calling NdisOpenProtocolConfiguration with ProtocolSection set to the SystemSpecific1 value that was passed to its ProtocolBindAdapter handler. It can call NdisReadConfiguration and NdisWriteConfiguration to read and write adapter-specific information. It can call NdisOpenConfigurationKeyByIndex or NdisOpenConfigurationKeyByName to obtain a handle to a subkey of the registry key opened with NdisOpenProtocolConfiguration.

The protocol binds itself to an underlying NIC and the miniport driver that controls it by calling NdisOpenAdapter, declared as follows:

VOID
NdisOpenAdapter(
  OUT PNDIS_STATUS  Status,
  OUT PNDIS_STATUS  OpenErrorStatus,
  OUT PNDIS_HANDLE  NdisBindingHandle,
  OUT PUINT  SelectedMediumIndex,
  IN PNDIS_MEDIUM  MediumArray,
  IN UINT  MediumArraySize,
  IN NDIS_HANDLE  NdisProtocolHandle,
  IN NDIS_HANDLE  ProtocolBindingContext,
  IN PNDIS_STRING  AdapterName,
  IN UINT  OpenOptions,
  IN PSTRING  AddressingInformation
  );

A protocol driver passes a handle at ProtocolBindingContext to an adapter-specific context area that it allocated to store state information for the binding. NDIS will return this handle to the protocol driver in subsequent calls pertaining to the binding — for instance, in calls to ProtocolReceive or ProtocolStatus. NDIS returns a handle at NdisBindingHandle to the protocol driver. This handle must be retained by the protocol, usually in its adapter-specific context area. The protocol driver must pass this handle to NDIS in future calls relating to this binding.

The protocol driver passes the name of the adapter that was input to the ProtocolBindAdapter function at DeviceName to NdisOpenAdapter at AdapterName. It passes the types of mediums it supports at MediumArray. If the call to NdisOpenAdapter succeeds, the underlying NIC driver will select a medium from MediumArray and return its index at SelectedMediumIndex. The value at NdisProtocolHandle is the value returned to the protocol driver from a successful call to NdisRegisterProtocol.

If a protocol driver cannot successfully bind to an underlying adapter, it deallocates any resources it previously allocated for that adapter. If the protocol driver cannot successfully open any of the possible adapters, it should deallocate any global resources the protocol has previously allocated and return an appropriate failure status. Typically, its ProtocolBindAdapter function should log failed binding attempts with appropriate descriptive informationby calling NdisWriteEventLogEntry.


Protocol Driver Query and Set Operations

After a protocol driver successfully bound to one or more adapters, it can call Ndis(Co)Request to query the underlying NDIS driver for its characteristics and to set the protocol's own operating characteristics. The protocol can also negotiate certain parameters for the binding.

NDIS defines Object Identifier (OID) values to identify adapter parameters which include; device characteristics, configurable settings and statistics.The driver can make requests with general OID_GEN_(CO_)XXX types of OIDs, which are independent of the underlying medium. The driver can also make requests with medium-specific OIDs that are defined for a particular medium type. The Network Driver Reference documents both types of OIDs. Some OIDs are mandatory, meaning an underlying driver must support them; others are optional.


Queries and Sets from Connectionless Protocol Drivers

A connectionless protocol calls NdisRequest to query or set the characteristics of an underlying miniport.

A connectionless protocol driver uses the general OID_GEN_MAXIMUM_FRAME_SIZE to query the maximum frame size, in bytes, supported by an underlying NIC driver. The size returned does not include the packet header.

A connectionless protocol driver queries a binding with the general OID_GEN_MAXIMUM_TOTAL_SIZE to determine the largest packet the underlying NIC driver can accommodate on the NIC it manages. The protocol driver must restrict the size of the packets it subsequently sends to this size. It is an error for a protocol driver to submit a larger packet to the underlying NIC driver than the NIC driver has indicated it can support.

A connectionless protocol driver should use OID_GEN_MAXIMUM_SEND_PACKETS to determine the number of send packets that an underlying driver can accept each time the protocol calls NdisSendPackets. See Sending Protocol Driver-Originated Packets for a discussion of how this request can affect the protocol driver's subsequent send operations.

A connectionless protocol driver can make a query request and/or a set request concerning the size of the lookahead data buffer the underlying driver supplies whenever the protocol's ProtocolReceive function is called. The OID used is OID_GEN_CURRENT_LOOKAHEAD. If the protocol driver issues this as a query request, NDIS returns the current lookahead buffer size for the given binding to the underlying NIC driver. If the protocol driver makes a set request with this OID code, it indicates its preferred lookahead buffer size, but the protocol is not assured that an underlying driver will conform to this request.

A connectionless protocol driver can query the underlying NIC driver for its link speed with OID_GEN_LINK_SPEED and use the results to set any internal time-out values it maintains. If the protocol driver is bound to NDISWAN, it cannot determine the link speed until it receives a line-up indication from the WAN NIC driver, indicating that a connection has been established between the local node and a remote node.

A connectionless protocol driver must also issue an OID_GEN_MAC_OPTIONS query to determine the operating characteristics of the underlying NIC driver. This query returns information such as, whether the underlying driver supports 802.1 priority.

If needed, a connectionless protocol driver issues a set request to inform NDIS of its own operating characteristics, passing OID_GEN_PROTOCOL_OPTIONS.

Protocol drivers should support 64-bit statistics OID queries. In a statistics OID query, the protocol driver sets the InformationBufferLength member of the NDIS_REQUEST structure to four (bytes) to indicate a 32-bit statistics request or to eight (bytes) to indicate a 64-bit statistics request. In its response, the miniport driver sets the BytesNeeded member to the size of the statistics supported by the miniport driver (four for 32-bits or eight for 64-bits). The miniport driver sets the BytesWritten member to the smaller of the InformationBufferlength value and the size of statistics supported by the miniport driver. For more information about statistics OIDs, see General Statistics.


Queries and Sets from Connection-Oriented Protocol Drivers

A connection-oriented protocol calls NdisCoRequest to query or set the characteristics of an underlying connection-oriented miniport.

A connection-oriented protocol driver can query the underlying NIC driver for its link speed with OID_GEN_CO_LINK_SPEED and use the results to set any internal time-out values it maintains. If the protocol driver is bound to NDISWAN, it cannot determine the link speed until it receives a line-up indication from the WAN NIC driver, indicating that a connection has been established between the local node and a remote node. A connection-oriented protocol driver can also set the speed of the underlying NIC with OID_GEN_CO_LINK_SPEED.

A connection-oriented protocol driver canissue an OID_GEN_CO_MAC_OPTIONS query to determine the operating characteristics of the underlying NIC driver. See the Network Driver Reference for the set of NDIS-defined flags that can be returned for this query.

If needed, a connection-oriented protocol driver issues a set request to inform NDIS of its own operating characteristics, passing OID_GEN_CO_PROTOCOL_OPTIONS.

Protocol drivers should support 64-bit statistics OID queries. In a statistics OID query, the protocol driver sets the InformationBufferLength member of the NDIS_REQUEST structure to four (bytes) to indicate a 32-bit statistics request or to eight (bytes) to indicate a 64-bit statistics request. In its response, the miniport driver sets the BytesNeeded member to the size of the statistics supported by the miniport driver (four for 32-bits or eight for 64-bits). The miniport driver sets the BytesWritten member to the smaller of the InformationBufferlength value and the size of statistics supported by the miniport driver. For more information about statistics OIDs for connection-oriented miniport drivers, see General Statistics for Connection-Oriented Miniport Drivers.


Queries and Sets to WAN Miniports

A connectionless or connection-oriented protocol driver bound above a WAN-capable NIC must also make the following set-information requests:

  • OID_WAN_PROTOCOL_TYPE to inform the underlying NDISWAN driver of the type of the protocol driver. The type is supplied as a single-byte, network-level protocol identifier.
  • OID_WAN_HEADER_FORMAT to inform the underlying NDISWAN driver of the header format of the packets it sends.


Medium-Dependent Queries

A protocol driver queries the medium-dependent current address with a medium-dependent OID. For example, a connectionless protocol might query one of the following: OID_WAN_CURRENT_ADDRESS, OID_802_3_CURRENT_ADDRESS, OID_802_5_CURRENT_ADDRESS, or OID_FDDI_LONG_CURRENT_ADDRESS. A connection-oriented protocol might query OID_WAN_CURRENT_ADDRESS or OID_ATM_HW_CURRENT_ADDRESS.


Registering as a Call Manager or a Connection-Oriented Client

A connection-oriented protocol must register either as a call manager or a connection-oriented client. See Connection-Oriented Environment for Network Drivers for an description of call managers and connection-oriented clients.


Registering as a Call Manager

A protocol driver registers itself as a call manager by calling NdisCmRegisterAddressFamily. The protocol driver calls NdisCmRegisterAddressFamily from its ProtocolBindAdapter function after the driver has established a binding to the underlying miniport with NdisOpenAdapter. The protocol driver calls NdisCmRegisterAddressFamily each time that its ProtocolBindAdapter function is called, effectively registering an address family for each NIC on which it provides call-management services to connection-oriented clients.

By calling NdisCmRegisterAddressFamily, a protocol driver both registers its call manager functions and advertises its specific signaling services for all clients on the binding. After the call manager's ProtocolBindAdapter function returns control with a successful registration as a stand-alone call manager, NDIS calls the ProtocolCoRegisterAfNotify functions of all connection-oriented clients on the binding (see Registering as a Connection-Oriented Client).

NdisCmRegisterAddressFamily is declared as follows:

NDIS_STATUS
NdisCmRegisterAddressFamily(
  IN NDIS_HANDLE  NdisBindingHandle,
  IN PCO_ADDRESS_FAMILY  AddressFamily,
  IN PNDIS_CALL_MANAGER_CHARACTERISTICS
                                                        CmCharacteristics,
  IN UINT  SizeOfCmCharacteristics
  );

Before calling NdisCmRegisterAddressFamily, the protocol driver must:

  1. Zero a structure of type NDIS_CALL_MANAGER_CHARACTERISTICS. The current version of the CmCharacteristics structure is 5.0.
  2. Store the addresses of the ProtocolXxx call manager functions that that driver supports.

The call manager functions that a protocol driver must register with NdisCmRegisterAddressFamily are listed below:

CmCreateVcHandler
Specifies the entry point of the caller's ProtocolCoCreateVc function.
CmDeleteVcHandler
Specifies the entry point of the caller's ProtocolCoDeleteVc function.
CmOpenAfHandler
Specifies the entry point of the caller's ProtocolCmOpenAf function.
CmCloseAfHandler
Specifies the entry point of the caller's ProtocolCmCloseAf function.
CmRegisterSapHandler
Specifies the entry point of the caller's ProtocolCmRegisterSap function.
CmDeregisterSapHandler
Specifies the entry point of the caller's ProtocolCmDeregisterSap function.
CmMakeCallHandler
Specifies the entry point of the caller's ProtocolCmMakeCall function.
CmCloseCallHandler
Specifies the entry point of the caller's ProtocolCmCloseCall function.
CmIncomingCallCompleteHandler
Specifies the entry point of the caller's ProtocolCmIncomingCallComplete function.
CmAddPartyHandler
Specifies the entry point of the caller's ProtocolCmAddParty function.
CmDropPartyHandler
Specifies the entry point of the caller's ProtocolCmDropParty function.
CmActivateVcCompleteHandler
Specifies the entry point of the caller's ProtocolCmActivateVcComplete function.
CmDeactivateVcCompleteHandler
Specifies the entry point of the caller's ProtocolCmDeactivateVcComplete function.
CmModifyCallQoSHandler
Specifies the entry point of the caller's ProtocolCmModifyCallQoS function.
CmRequestHandler
Specifies the entry point of the caller's ProtocolCoRequest function.
CmRequestCompleteHandler
Specifies the entry point of the caller's ProtocolCoRequestComplete function.

A protocol driver must set every Cm Xxx member in the NDIS_CALL_MANAGER_CHARACTERISTICS structure, even if it does not support incoming calls, outgoing calls, or point-to-multipoint connections. For whatever subset of connection-oriented functionality that such a call manager does not support, its placeholder ProtocolCmXxx functions simply return NDIS_STATUS_NOT_SUPPORTED.

After a stand-alone call manager calls NdisCmRegisterAddressFamily successfully, NDIS ignores any entry points that the CM previously specified in the RequestHandler and RequestCompleteHandler members of the NDIS_PROTOCOL_CHARACTERISTICS structure that it passed to NdisRegisterProtocol.


Registering as a Connection-Oriented Client

When a call manager or MCM, from its ProtocolBindAdapter function, calls Ndis(M)CmRegisterAddressFamily to register an address family, NDIS calls the ProtocolCoRegisterAfNotify function of all protocol drivers on the binding. If a protocol driver registered a ProtocolCoAfRegisterNotify function when it registered as a protocol, NDIS calls the protocol driver's ProtocolCoAfRegisterNotify function.

If ProtocolCoAfRegisterNotify determines that the protocol driver can use the services of the call manager or MCM that registered the address family, it allocates a per-AF context area for the client and calls NdisClOpenAddressFamily. With the call to NdisClOpenAddressFamily, a protocol driver registers a set of client-supplied functions.

NdisClOpenAddressFamily is declared as follows:

NDIS_STATUS
NdisClOpenAddressFamily(
  IN NDIS_HANDLE  NdisBindingHandle,
  IN PCO_ADDRESS_FAMILY  AddressFamily,
  IN NDIS_HANDLE  ProtocolAfContext,
  IN PNDIS_CLIENT_CHARACTERISTICS  ClCharacterisitics,
  IN UINT  SizeOfClCharacteristics,
  OUT PNDIS_HANDLE  NdisAfHandle
  );

Before calling NdisClOpenAddressFamily, the protocol driver must:

  1. Zero a structure of type NDIS_CLIENT_CHARACTERISTICS. The current version of the ClCharacteristics structure is 5.0.
  2. Store the addresses of the ProtocolXxx client functions that that driver supports.

The NdisAfHandle returned by this call is opaque to a protocol driver. The handle must be retained by the driver and provided as an input parameter in future calls made by the protocol part of the driver to NDIS — for instance, to register a SAP with NdisClRegisterSap.

The client functions that a protocol driver must register with NdisClOpenAddressFamily are listed below:

ClCreateVcHandler
Specifies the entry point of the caller's ProtocolCoCreateVc function.
ClDeleteVcHandler
Specifies the entry point of the caller's ProtocolCoDeleteVc function.
ClRequestHandler
Specifies the entry point of the caller's ProtocolCoRequest function.
ClRequestCompleteHandler
Specifies the entry point of the caller's ProtocolCoRequestComplete function.
ClOpenAfCompleteHandler
Specifies the entry point of the caller's ProtocolClOpenAfComplete function.
ClCloseAfCompleteHandler
Specifies the entry point of the caller's ProtocolClCloseAfComplete function.
ClRegisterSapCompleteHandler
Specifies the entry point of the caller's ProtocolClRegisterSapComplete function. If a client calls NdisClRegisterSap and it returns NDIS_STATUS_PENDING, NDIS calls this function to notify the client of the completion of the call to NdisClRegisterSap .
ClDeregisterSapCompleteHandler
Specifies the entry point of the caller's ProtocolClDeregisterSapComplete function.
ClMakeCallCompleteHandler
Specifies the entry point of the caller's ProtocolClMakeCallComplete function. A client uses this function to make outgoing calls to remote machines.
ClModifyCallQoSCompleteHandler
Specifies the entry point of the caller's ProtocolClModifyCallQoSComplete function. If a client calls NdisClModifyCallQoS and it returns NDIS_STATUS_PENDING, NDIS calls this function to notify the client of the completion of the call to NdisClModifyCallQoS .
ClCloseCallCompleteHandler
Specifies the entry point of the caller's ProtocolClCloseCallComplete function.
ClAddPartyCompleteHandler
Specifies the entry point of the caller's ProtocolClAddPartyComplete function. If a client calls NdisClAddParty and it returns NDIS_STATUS_PENDING, NDIS calls this function to notify the client of the completion of the call to NdisClAddParty .
ClDropPartyCompleteHandler
Specifies the entry point of the caller's ProtocolClDropPartyComplete function.
ClIncomingCallHandler
Specifies the entry point of the caller's ProtocolClIncomingCall function. A client uses this function to accept incoming calls from remote machines.
ClIncomingCallQoSChangeHandler
Specifies the entry point of the caller's ProtocolClIncomingCallQoSChange function.
ClIncomingCloseCallHandler
Specifies the entry point of the caller's ProtocolClIncomingCloseCall function.
ClIncomingDropPartyHandler
Specifies the entry point of the caller's ProtocolClIncomingDropParty function.
ClCallConnectedHandler
Specifies the entry point of the caller's ProtocolClCallConnected function. A client uses this function to accept incoming calls from remote machines.

The protocol driver must set every Cl Xxx member in the NDIS_CLIENT_CHARACTERISTICS structure to a caller-supplied ProtocolCl/CoXxx function when it calls NdisClOpenAddressFamily, even if it does not support incoming calls, outgoing calls, or point-to-multipoint connections. For whatever subset of connection-oriented functionality that such an intermediate driver does not support, its ProtocolCl/CoXxx functions simply return NDIS_STATUS_NOT_SUPPORTED.


Protocol Driver Packet Management

A protocol driver receives one or more buffers of data from a client to transmit over the network. A protocol driver must, at a minimum, allocate and initialize a packet descriptor to which the client's data buffers are chained. Packet descriptors must be allocated from packet pool, as follows:

  1. Call NdisAllocatePacketPool or NdisAllocatePacketPoolEx to allocate and initialize a block of nonpaged pool for a caller-specified number of fixed-size packet descriptors during driver initialization or when each binding is first established.
  2. Call NdisAllocatePacket to allocate a packet descriptor from the pool allocated by NdisAllocatePacketPool.

Buffer descriptors mapping such buffers are chained to a packet descriptor by calling NdisChainBufferAtBack or NdisChainBufferAtFront. If a protocol driver receives a data buffer from a client that must be sent in several smaller buffers, the protocol driver can copy the data into protocol-allocated buffers, map its buffers with previously allocated buffer descriptors, and chain these buffer descriptors to protocol-allocated packet descriptors. Such buffers can be allocated by calling a kernel-mode support routine, NdisAllocateMemory, or NdisAllocateMemoryWithTag and can be mapped with protocol-allocated buffer descriptors as follows:

  1. Call NdisAllocateBufferPool to obtain a handle with which to allocate buffer descriptors during driver initialization or when each binding is first established.
  2. Call NdisAllocateMemoryWithTag to allocate a buffer to chain to a packet descriptor allocated by calling NdisAllocatePacket.
  3. Call NdisAllocateBuffer to allocate and set up a buffer descriptor that maps the buffer allocated by calling NdisAllocateMemoryWithTag.

The base virtual address and the length returned by NdisAllocateMemoryWithTag are passed in the call to NdisAllocateBuffer to initialize a buffer descriptor.

Packet descriptors to meet typical transmit needs can be allocated as needed, when the driver initializes, and/or at binding time. A protocol driver developer can allocate a number of packet descriptors with chained buffer descriptors at initialization time to hold receives that can occur as soon as the protocol binds itself to an underlying NIC driver. Then ProtocolReceive can return control to the underlying driver as quickly as possible. Otherwise, subsequently received data can be lost. As described later, a connectionless protocol driver can either receive incoming data from an underlying NIC driver at its ProtocolReceivePacket function as a packet descriptor specifying a full network packet or have data indicated to its ProtocolReceive function, which must copy the indicated data into a protocol-supplied buffer chained to a protocol-allocated packet descriptor. A connection-oriented protocol always receives incoming data at its ProtocolCoReceivePacket function.

Every connectionless protocol driver must provide a ProtocolReceive function. When this function is called, the protocol driver must copy the indicated lookahead data into a protocol-allocated buffer chained to a preallocated packet descriptor, which it must pass to NdisTransferData. This call passes the packet descriptor to the underlying NIC driver to be filled if there is additional data received beyond the indicated lookahead data.

If a protocol driver binds itself only to underlying NDIS drivers that indicate arrays of packets with NdisMCoIndicateReceivePackets, ProtocolCoReceivePacket need not provide packet descriptors, buffers, and buffer descriptors for incoming data. When the protocol driver has a full network packet indicated to its Protocol(Co)ReceivePacket function, it can give clients direct read-only access to the buffered data described by an input packet descriptor until the data is consumed and the clients release the packet descriptor and all the resources it specifies. When the protocol driver takes ownership of such packet resources, it has no need to copy data into a preallocated packet and call NdisTransferData to obtain the remaining packet data.

If a protocol driver supplies a packet descriptor with more than one chained buffer to NdisTransferData, NdisSendPackets, or NdisCoSendPackets and the length of actual data in the last buffer is less than the allocated length of its buffer, the protocol driver should call NdisAdjustBufferLength to set the actual length of the data in the buffer descriptor. When the packet descriptor is returned to the protocol driver, the driver should readjust the buffer descriptor's specified length to the full length of the buffer.

Reusing Packets

Ownership of protocol-allocated packet resources for sends reverts to the protocol driver when NdisCoSendPackets returns anything other than NDIS_STATUS_PENDING or when the driver's Protocol(Co)SendComplete function is called. Then the protocol driver can reclaim the returned packet resources for subsequent sends or, if it's a connectionless driver, for copying received data in ProtocolReceive.

It is more efficient for a protocol driver to reinitialize and reuse the packet descriptor and buffers than to deallocate these resources and then later reallocate them again for a subsequent send or data-transfer operation. A protocol usually exhibits better performance if it saves unchained buffer descriptors and buffers for reuse rather than deallocating and reallocating such resources.

A protocol driver reinitializes a packet descriptor by calling NdisReinitializePacket. First, the protocol driver should take care to remove any chained buffers and their buffer descriptors by calling NdisUnchainBufferAt Xxx to release the buffer descriptors and the buffers mapped by these descriptors. Otherwise, NdisReinitializePacket sets the member that points to the chained buffer descriptors to NULL, so reinitializing the packet descriptor without first releasing and saving the chained buffer descriptors will cause a memory leak. Similarly, if the protocol and underlying driver use out-of-band information, the resources specified in the OOB data block associated with each packet descriptor must be reclaimed before a call to NdisReinitializePacket.


Dynamic Binding in a Protocol Driver

A protocol driver must support dynamic binding to underlying NICs by providing both a ProtocolBindAdapter function and a ProtocolUnbindAdapter function.

Whenever an underlying NIC becomes available, NDIS will call the ProtocolBindAdapter function of any protocol driver that can bind itself to that adapter, and whenever an underlying NIC is removed, NDIS will call the reciprocal ProtocolUnbindAdapter function.

NDIS supplies the name of the newly available adapter for ProtocolBindAdapter to open at DeviceName. NDIS passes a handle at BindContext that represents its context for the bind request. The protocol driver must retain this handle and pass it back to NDIS as a parameter to NdisCompleteBindAdapter when the driver has completed its binding-related activities and is ready to transmit and receive packets.

Binding-time actions include allocating and initializing an adapter-specific context area for the binding and calling NdisOpenAdapter to open the adapter passed at DeviceName.

NdisOpenAdapter can return NDIS_STATUS_PENDING. If NdisOpenAdapter returns a pending status, the protocol driver cannot call NdisCompleteBindAdapter until the open operation is complete and the protocol driver is called at its ProtocolOpenAdapterComplete function.

SystemSpecific1 is a string that must be passed to NdisOpenProtocolConfiguration. This string is opaque to protocol drivers.

SystemSpecific2 is reserved for system use. It is the physical device object of the adapter to which the protocol is requested to bind.

For more information about dynamic unbinding, see Protocol Driver Unbinding Operations.


Receiving Data in a Protocol Driver

This section describes how data is received in a connectionless protocol driver and also in a connection-oriented protocol driver.


Receiving Data in a Connectionless Protocol Driver

Underlying connectionless NIC drivers can indicate packets in two ways:

  • A NIC driver calls NdisMIndicateReceivePacket, passing a pointer to an array of packet descriptor pointers to one or more full packets and relinquishing ownership of the resources for these packets to the overlying drivers, which can consume the data and return the packet resources at a later time.
  • A NIC driver calls a filter-specific NdisM Xxx IndicateReceive function, passing a pointer to a lookahead buffer, the size of the lookahead buffer, and the total size of the received net packet.

Every connectionless protocol driver must have at least one of two possible receive handlers and can have both of the following:

  1. ProtocolReceive is a required function that is called with a pointer to a lookahead buffer.

    After ProtocolReceive examines the lookahead data and determines that the packet is intended for one or more of its clients, it must copy the lookahead data into a protocol-allocated buffer, possibly to be chained to a protocol-allocated packet descriptor. If the size of the lookahead buffer is less than the total size of the received packet, ProtocolReceive must call NdisTransferData with the protocol-allocated packet descriptor to obtain the rest of the received data, which the underlying driver copies into the protocol-supplied buffer.

  2. ProtocolReceivePacket is an optional function that receives a pointer to packet descriptor specifying a buffered full network packet.

    ProtocolReceivePacket also examines the packet data and determines whether the packet is intended for one or more of its clients. If so, the protocol can give its clients ownership of the indicated packet resources, including direct read-only access to the buffered net packet data, by returning a nonzero value (a count of clients to which the protocol forwarded the receive indication) from ProtocolReceivePacket. The protocol driver's clients must subsequently call NdisReturnPackets to return the packet descriptor and all the resources it specifies to the underlying driver. Each client must return the packet descriptor until all clients' calls total the nonzero value returned from ProtocolReceivePacket for that receive indication.

    When the protocol driver's clients call return the packet descriptor the required number of times, they relinquish ownership of the returned packet resources to the underlying NIC driver that originally indicated the receive.

    On the other hand, if a protocol driver returns zero from ProtocolReceivePacket, it relinquishes ownership of the packet resources when ProtocolReceivePacket returns. Relinquishing such a received packet immediately could occur, for instance, if the client for the packet has closed the connection or in some manner become unavailable, or if the protocol copies the indicated data into buffers of its own and processes the data internally before indicating up to its clients.


Implementing a ProtocolReceivePacket Handler in a Protocol Driver

When an underlying connectionless NIC driver indicates an array of one or more packet descriptors with NdisMIndicateReceivePacket, NDIS will usually call a bound protocol driver's ProtocolReceivePacket function with each packet descriptor, thereby allowing the protocol driver (or its clients) to retain the packet descriptor and all the resources it specifies until the protocol or its clients have consumed the data and returned the packet descriptor.

The ProtocolReceivePacket functionallows the protocol driver to:

  • Receive indications of full network packets from the underlying NIC driver.
  • Read the OOB data associated with each packet descriptor using NDIS-supplied macros.
  • Retain ownership of the input packet descriptor and direct read-only access to the buffered data specified by the descriptor if the protocol makes copies of the data for its clients, or even to forward the indicated packet descriptor to its clients after selecting the range of packet data of interest to the clients.
  • Return the packet descriptor and the resources it described, possibly along with other retained packet descriptors, with NdisReturnPackets when the protocol has consumed the indicated data if it retains ownership of the input packet descriptor; otherwise, to have clients to which the protocol forwarded a receive indication return the packet descriptor.

Even when a protocol driver provides a ProtocolReceivePacket handler, there are cases when a call by a NIC driver to NdisMIndicateReceivePacket results in a call to the protocol driver's ProtocolReceive function. Since a NIC driver temporarily relinquishes ownership of driver-allocated resources when it calls NdisMIndicateReceivePacket, the underlying driver depends on the consumers of those packets to return them in a timely manner. Otherwise, the NIC driver can run short of receive resources, such as receive buffer space in the NIC. When it does, the NIC driver sets NDIS_STATUS_RESOURCES in the OOB block associated with a packet descriptor in the packet array it passes to NdisMIndicateReceivePacket. Indicating a packet with this status causes NDIS to call the overlying driver's ProtocolReceive function with such a packet and with any subsequent packets in the array, thus forcing the protocol driver to copy the packet data immediately, rather than retaining the NIC-driver-allocated packet resources.

If the protocol driver requires the OOB data associated with a packet descriptor but is called at ProtocolReceive, it must call NdisGetReceivedPacket and NDIS_GET_ORIGINAL_PACKET to copy the media-specific information into a protocol-supplied buffer and possibly the TimeSent and TimeReceived values if the underlying NIC driver provides these timestamps.


Implementing a ProtocolReceive Handler in a Protocol Driver

If the underlying connectionless NIC driver calls a filter-specific NdisM Xxx IndicateReceive function, NDIS always calls the ProtocolReceive function of each bound protocol driver.

If one or more of such a protocol driver's clients are the target of the packet and the lookahead buffer size is less than the total packet size, ProtocolReceive must do the following:

  1. Copy the lookahead data into an internal buffer mapped by a protocol-allocated packet descriptor.
  2. Chain buffer descriptors mapping sufficient protocol-allocated buffers to contain the rest of the network packet data to a protocol-allocated packet descriptor.
  3. Call NdisTransferData with the packet descriptor, so the underlying driver copies the rest of the received data into the protocol's buffers.

When NdisTransferData returns STATUS_SUCCESS or the ProtocolTransferDataComplete function is called, the lookahead buffer can be chained to the packet descriptor containing this transferred data and indicated up to any interested clients.

NdisTransferData can only be called once for each receive indication and it must be called within the context of the call to ProtocolReceive . It is the responsibility of the protocol driver to set up its packet descriptor with chained buffers of a sufficient size to contain the full network packet.

The size of the lookahead buffer passed to ProtocolReceive is greater than or equal to the lookahead size returned by an OID_GEN_CURRENT_LOOKAHEAD query plus the size of the MAC header. However, if the total size of the packet (including the MAC header size) is less than this value, the lookahead buffer size is the size of the packet. All data in the lookahead buffer is read-only to ProtocolReceive.

If the lookahead buffer size is less than or equal to the size of the total packet indicated by a filter-specific NdisM Xxx IndicateReceive function, ProtocolReceive should call NdisTransferData to copy the lookahead data into an internal buffer.

If the call to ProtocolReceive occurred because the underlying NIC driver set the status for one or more packets in a packet array to NDIS_STATUS_RESOURCES before calling NdisMIndicateReceivePacket, the size of the lookahead buffer will always be equal to the size of the full network packet minus the MAC header size. In these circumstances, the protocol driver never calls NdisTransferData because ProtocolReceive can copy the full indication into an internal buffer immediately.

If the NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA bit is set in response to an OID_GEN_MAC_OPTIONS request, a protocol driver can use any means to copy lookahead data into an internal buffer, such as calling NdisMoveMemory. If this flag was not set, the protocol driver must call NdisCopyLookaheadData to copy the indicated data; otherwise, the results from a copy operation are indeterminate.

ProtocolReceive must execute as quickly as possible. The protocol driver must ensure that it has protocol-allocated packet resources available before it receives incoming indications. After the protocol driver examines the packet and determines that the packet is not one it will copy, ProtocolReceive should simply return NDIS_STATUS_NOT_ACCEPTED.

ProtocolReceive must not process the received data as soon as it is copied since that would adversely impact system performance, as well as possibly causing dropped receives in the underlying NIC driver. Instead, the protocol driver processes the received data later in its ProtocolReceiveComplete function. Following one or more receive indications, ProtocolReceiveComplete is called when the underlying NIC driver calls NdisM Xxx IndicateReceiveComplete. Typically, this occurs when the underlying NIC driver has received and indicated a miniport-determined number of packets or before it exits its receive handler. The protocol driver must queue the received data in ProtocolReceive so that it is available to ProtocolReceiveComplete for postprocessing.


Accessing OOB Information From a Connectionless Protocol Driver

When a received network packet is indicated to ProtocolReceive, it forces the driver to copy the received data into a protocol-supplied buffer. If such an indication has associated media-specific and/or timestamp information in the OOB block associated with the packet descriptor, a protocol driver can call NdisGetReceivedPacket and NDIS_GET_ORIGINAL_PACKET to copy the media-specific information, as well as any TimeSent and TimeReceived timestamps.

If a received packet is passed to ProtocolReceivePacket, the protocol driver can copy the information from the associated OOB block using NDIS-supplied macros as follows:

  • Media-specific information is copied using NDIS_GET_MEDIA_SPECIFIC_INFO.
  • TimeSent is copied using NDIS_GET_TIME_SENT.
  • TimeReceived is copied using NDIS_GET_TIME_RECEIVED.

Note Most miniport drivers do not support TimeSent and TimeReceived.

TimeSent is the time a packet was sent by the NIC driver on the remote node, and is retrieved and stored by the underlying NIC driver on the local node if available. TimeReceived is the time that the incoming packet was received on the underlying NIC on the local node.

The current system time can be determined using NdisGetCurrentSystemTime or KeQuerySystemTime if the protocol converts these timestamps into another format.


Receiving Data in a Connection-Oriented Protocol Driver

Underlying connection-oriented NIC drivers indicate packets by calling NdisMCoIndicateReceivePacket, passing a pointer to an array of packet descriptor pointers to one or more full packets and relinquishing ownership of the resources for these packets to the overlying drivers, which can consume the data and return the packet resources at a later time.

A connection-oriented protocol receives indicated packets at its ProtocolCoReceivePacket function. ProtocolCoReceivePacket receives a pointer to packet descriptor that specifies a buffered full network packet.

ProtocolCoReceivePacket also examines the packet data and determines whether the packet is intended for one or more of its clients. If so, the protocol can give its clients ownership of the indicated packet resources, including direct read-only access to the buffered net packet data, by returning a nonzero value (a count of clients to which the protocol forwarded the receive indication) from ProtocolCoReceivePacket. The protocol driver's clients must subsequently return the packet descriptor and all the resources it specifies to the underlying driver. Each client must make this call with the packet descriptor until all clients' calls total the nonzero value returned from ProtocolCoReceivePacket for that receive indication.

When the protocol driver's clients return the packet descriptor the required number of times, they relinquish ownership of the returned packet resources to the underlying NIC driver that originally indicated the receive.

On the other hand, if a protocol driver returns zero from ProtocolCoReceivePacket, it relinquishes ownership of the packet resources when ProtocolCoReceivePacket returns. Relinquishing such a received packet immediately could occur, for instance, if the client for the packet has closed the connection or in some manner become unavailable, or if the protocol copies the indicated data into buffers of its own and processes the data internally before indicating up to its clients.


Implementing a ProtocolCoReceivePacket Handler

When an underlying connection-oriented NIC driver indicates an array of one or more packet descriptors with NdisMCoIndicateReceivePacket, NDIS calls a bound protocol driver's ProtocolReceivePacket function with each packet descriptor. ProtocolCoReceivePacket must call the NDIS_GET_PACKET_STATUS macro once for each packet descriptor to obtain the OOB block Status for the associated packet.

If a NIC driver, before calling NdisMCoIndicateReceivePacket, set the OOB block Status associated with a packet descriptor to NDIS_STATUS_SUCCESS, the NIC driver temporarily relinquished ownership of the resources associated with the packet descriptor. In this case, the NIC driver depends on the consumers of those packets to return them in a timely manner. Otherwise, the NIC driver can run short of receive resources, such as receive buffer space in the NIC.

When it does run short of resources, a NIC driver sets a packet's OOB block Status to NDIS_STATUS_RESOURCES. Indicating a packet with this status forces the ProtocolCoReceivePacket function of the protocol driver to copy the packet data immediately rather than retaining the NIC-driver-allocated packet resources. ProtocolCoReceivePacket must return zero in such a situation.

It the underlying NIC driver does not set NDIS_STATUS_RESOURCES in the OOB block associated with a packet descriptor in the packet array that it passes to NdisMCoIndicateReceivePacket, it allows the protocol driver (or its clients) to retain the packet descriptor and all the resources it specifies until the protocol or its clients have consumed the data and returned the packet descriptor.


Accessing OOB Information From a Connection-Oriented Protocol

A connection-oriented protocol driver can copy the information from the associated OOB block of an indicated receive packet using NDIS-supplied macros as follows:

  • Media-specific information is copied using NDIS_GET_MEDIA_SPECIFIC_INFO.
  • TimeSent is copied using NDIS_GET_TIME_SENT.
  • TimeReceived is copied using NDIS_GET_TIME_RECEIVED.

Note Most miniport drivers do not support TimeSent and TimeReceived.

TimeSent is the time a packet was sent by the NIC driver on the remote node, and is retrieved and stored by the underlying NIC driver on the local node, if available. TimeReceived is the time that the incoming packet was received on the underlying NIC on the local node.

The current system time can be determined using NdisGetCurrentSystemTime if the protocol converts these timestamps into another format.

A connection-oriented miniport may be able to indicate the TimeReceived for a packet in the NIC's local time. To query a connection-oriented miniport's or MCM's local timing capabilities, a protocol calls NdisCoRequest with OID_GEN_CO_GET_TIME_CAPS. To obtain the NIC's local time, a protocol calls NdisCoRequest with OID_GEN_CO_GET_NETCARD_TIME.


Sending Protocol Driver-Originated Packets

This section describes sending packets from a connectionless protocol driver and also from a connection-oriented protocol driver.


Sending Packets from a Connectionless Protocol Driver

A connectionless protocol driver can transmit a single packet by calling NdisSend, passing in a pointer to a packet descriptor with chained buffer descriptors mapping the buffered data to be sent. Alternatively, a connectionless protocol driver can transmit several packets using NdisSendPackets, passing in a pointer to an array of pointers to one or more packet descriptors.

In general, a connectionless protocol driver developer should choose whether to call NdisSend or NdisSendPackets based upon the driver's own requirements and on the characteristics of the underlying NIC driver.

When it has bound itself to an underlying NIC driver, a connectionless protocol driver should call NdisRequest with an OID_GEN_MAXIMUM_SEND_PACKETS query to determine the maximum number of send packets that the underlying driver will accept in a packet array. If the NIC driver supports only single-packet sends, either at its MiniportSend or its MiniportSendPackets function, the return value will be one or, possibly NDIS_STATUS_NOT_SUPPORTED. Either of these returns implies the protocol driver is likely to call NdisSend rather than NdisSendPackets. If the underlying driver returns a value greater than one, both drivers' performance will be better if the protocol driver sends an array of packets with NdisSendPackets. If OOB information is passed between the protocol driver and the NIC driver, either NDIS function can be called, since, in either case, the underlying driver can read the OOB data using NDIS-supplied macros

Whenever a protocol driver calls NdisSend, it relinquishes ownership of the given packet resources until the send completes, either synchronously or asynchronously. If the status returned by NdisSend is something other than NDIS_STATUS_PENDING, the send completes synchronously and ownership of the protocol-allocated packet resources reverts to the protocol driver. If the status returned by NdisSend is NDIS_STATUS_PENDING, when the send subsequently completes, the final status of the send and the protocol-allocated packet descriptor will be passed in to the ProtocolSendComplete function.

When a protocol driver transmits one or more packets by calling NdisSendPackets, send operations are always asynchronous. The protocol driver relinquishes ownership of the packet resources that it allocated until each packet descriptor and the final status of the send for that packet is returned to ProtocolSendComplete.

As a consequence, a protocol driver never reads the Status member in the OOB block associated with a packet descriptor on return from NdisSend(Packets). The protocol cannot learn the status of its send request in this manner because this member is in use by NDIS to track the progress of an in-transition send request and is volatile until the packet descriptor is returned to ProtocolSendComplete. A protocol driver always obtains the status of a transmit request either by examining the value returned by NdisSend or from the Status parameter passed to ProtocolSendComplete.

If a protocol driver requests the transmission of an array of packets of different priorities by arranging the packets it receives from clients before transmitting them, the protocol should place the highest priority packets at the beginning of the array. NDIS always preserves the ordering of packets in any array passed to NdisSendPackets, even if NDIS queues some of the packets internally.

NDIS does not attempt to examine and make queuing decisions based on any of the OOB data associated with the packet descriptors given to NdisSendPackets (or to NdisSend). Unless a protocol driver has special knowledge of the manner in which the underlying NIC driver handles packet priorities or the TimeToSend timestamps, the protocol should assume that the underlying NIC driver transmits all packets in the order in which it receives them, preserving the as-received order. Consequently, a protocol should order the packet arrays it sends according to the order in which those packets should be transmitted over the network.


Sending Packets from a Connection-Oriented Protocol Driver

A connection-oriented protocol driver can transmit one or more packets with NdisCoSendPackets, passing in a pointer to an array of pointers to one or more packet descriptors.

When a protocol driver transmits one or more packets by calling NdisCoSendPackets, send operations are always asynchronous. The protocol driver relinquishes ownership of the packet resources that it allocated until each packet descriptor and the final status of the send for that packet is returned to ProtocolCoSendComplete.

As a consequence, a protocol driver never reads the Status member in the OOB block associated with a packet descriptor on return from NdisCoSendPackets. The protocol cannot learn the status of its send request in this manner because this member is in use by NDIS to track the progress of an in-transition send request and is volatile until the packet descriptor is returned to ProtocolCoSendComplete. A protocol driver always obtains the status of a transmit request from the Status parameter passed to ProtocolCoSendComplete.

If a protocol driver requests the transmission of an array of packets of different priorities by arranging the packets it receives from clients before transmitting them, the protocol should place the highest priority packets at the beginning of the array. NDIS always preserves the ordering of packets in any array passed to NdisCoSendPackets.

NDIS does not attempt to examine and make queuing decisions based on any the OOB data associated with the packet descriptors given to NdisCoSendPackets. Unless a protocol driver has special knowledge of the manner in which the underlying NIC driver handles packet priorities or the TimeToSend timestamps, the protocol should assume that the underlying NIC driver transmits all packets in the order in which it receives them, preserving the as-received order. Consequently, a protocol should order the packet arrays it sends according to the order in which those packets should be transmitted over the network.


Passing Media-Specific Information from a Connection-Oriented Protocol Driver

Before sending a packet, a protocol driver can call NdisSetPacketFlags to set protocol-defined flags in the NDIS-private portion of the packet descriptor. Such flags are not defined by NDIS, but are defined for use by a cooperating pair of protocol and lower level NDIS drivers. The structure of the Private member of an NDIS_PACKET is opaque to all NDIS drivers and is accessed to read and, in some cases, to write using NDIS-supplied functions or macros.

More media-specific information can be passed by a protocol driver in the OOB block associated with each NDIS_PACKET-type descriptor. The definition of the OOB block is:

typedef struct _NDIS_PACKET_OOB_DATA {
    union {
         ULONGLONG      TimeToSend;
         ULONGLONG      TimeSent;
          };
         ULONGLONG      TimeReceived;
         UINT           HeaderSize;
         UINT           SizeMediaSpecificInfo;
         PVOID          MediaSpecificInformation;
         NDIS_STATUS    Status;
} NDIS_PACKET_OOB_DATA, *PNDIS_PACKET_OOB_DATA;

The structure of individual records within a driver-allocated buffer at MediaSpecificInformation is defined as follows:

typedef struct MediaSpecificInformation {
    UINT                NextEntryOffset;
    NDIS_CLASS_ID       ClassId;
    UINT                Size;
    UCHAR               ClassInformation[1];
} MEDIA_SPECIFIC_INFORMATION;

The ClassId member is an NDIS-defined enumeration that defines the type of information found at ClassInformation[1]. Currently, there is one class ID in use across Microsoft operating systems that support Win32:NdisClassAtmAALInfo.

If the protocol driver knows that the underlying NIC driver to which it is sending packets uses OOB data, the protocol can set the following OOB structure members:

  • Request that the packet be sent at a specific time by setting the TimeToSend member using the NDIS_SET_PACKET_TIME_TO_SEND macro. This macro passes the requested time in system time units. The protocol can call NdisGetCurrentSystemTime in order to obtain the current system time with which to calculate a requested send time.
  • Pass media-specific information in a protocol-allocated buffer at MediaSpecificInformation using the NDIS_PACKET_SET_MEDIA_SPECIFIC_INFO macro to set this member to the address of the buffer.

A connection-oriented protocol can use a NICs local time for scheduling the transmission of packets and for time-stamping send packets. To query a connection-oriented miniport's or MCM's local timing capabilities, a protocol calls NdisCoRequest with OID_GEN_CO_GET_TIME_CAPS. To obtain the NIC's local time, a protocol calls NdisCoRequest with OID_GEN_CO_GET_NETCARD_TIME.


Handling PnP Events and Power Management Events in a Protocol Driver

When the operating system issues a Plug and Play IRP or a Power Management IRP to a target device object that represents a NIC, NDIS intercepts the IRP and then indicates the event to each bound protocol and each bound intermediate driver by calling the driver's ProtocolPnPEvent handler. In the call to ProtocolPnPEvent, NDIS passes a pointer to a NET_PNP_EVENT structure that describes the Plug and Play event or Power Management event being indicated.

There are six possible Plug and Play and Power Management events, as indicated by the NetEvent code in the NET_PNP_EVENT structure:

  • NetEventSetPower

    Indicates a Set Power request, which specifies that the NIC transition to a particular power state. A PM-aware protocol should always succeed this event by returning NDIS_STATUS_SUCCESS. A legacy protocol can return NDIS_STATUS_NOT_SUPPORTED to indicate that NDIS should unbind it from the NIC.

  • NetEventQueryPower

    Indicates a Query Power request, which queries whether the NIC can a transition to a particular power state. A protocol should always succeed a NetEventQueryPower. After establishing an active connection, a protocol can call PoRegisterSystemState to register a continuous busy state. As long as the state registration is in effect, the Power Manager does not attempt to put the system to sleep. After the connection becomes inactive, the protocol cancels the state registration by calling PoUnregisterSystemState. A protocol should never try to prevent the system from transitioning to the sleeping state by failing a NetEventQueryRemoveDevice. Note that a NetEventQueryPower is always followed by a NetEventSetPower. A NetEventSetPower to the device's current power state in effect cancels the NetEventQueryPower.

  • NetEventQueryRemoveDevice

    Indicates a Query Remove Device request, which queries whether the NIC can be removed without disrupting operations. If a protocol cannot release a device (for example, because the device is in use) it must fail a NetEventQueryRemoveDevice by returning NDIS_STATUS_FAILURE.

  • NetEventCancelRemoveDevice

    Indicates a Cancel Remove Device request, which cancels the removal of the NIC. The protocol should always succeed this event by returning NDIS_STATUS_SUCCESS.

  • NetEventReconfigure

    Indicates that the configuration has changed for a network component. For example, if a user changes the IP address for TCP/IP, NDIS indicates this event to the TCP/IP protocol with the NetEventReconfigure code. The protocol can, in rare circumstances, return a failure code if it is not able to apply the indicated configuration changes and there are no available default values. A failed attempt to allocate memory is an example of a circumstance in which the protocol returns a failure code. Returning an error code can result in prompting the user to reboot the system.

  • NetEventBindList

    Indicates to a protocol driver that its bind list processing order has been reconfigured. . This list indicates a relative order to be applied to the protocol's bindings when processing, for example, a user request that might be routed to one of several bindings. The buffer passed with this event contains a list of device names formatted as NULL-terminated Unicode strings. The format of each device name is identical to the DeviceName parameter passed to a call to ProtocolBindAdapter.

  • NetEventBindsComplete

    Indicates that a protocol driver has bound to all the NICs that it can bind to. Indicates that a protocol driver has bound to all the NICs that it can bind to. NDIS will not indicate any more NICs to the protocol unless a Plug and Play NIC is plugged into the system.

The Buffer member of the NET_PNP_EVENT points to a buffer that contains information specific to the event being indicated.

A protocol can complete the call to ProtocolPnPEvent asynchronously with NdisCompletePnPEvent.


Protocol Driver Reset Operations

A protocol driver can initiate a reset operation by calling NdisReset. If its reset request returns NDIS_STATUS_PENDING, ProtocolResetComplete is called when the reset operation is complete.

A protocol driver seldom calls NdisReset unless it has special knowledge that the underlying NIC is not functioning correctly. For instance, if a protocol driver detects that it has not received completion calls for an unusually large number of sends or requests, and it has enough knowledge of the underlying NIC to conclude that this indicates hardware problems, it can call NdisReset. Typically, however, the need for a reset is detected and initiated by NDIS and/or the NIC driver itself using time-out logic. Any protocol driver bound to an underlying NDIS driver that reports its medium type as NdisMediumWan cannot call NdisReset.

Typically, an underlying NIC driver resets its NIC because the NIC is timing out during send or request operations, which causes NDIS to call the NIC driver's MiniportCheckForHang and subsequently MiniportReset function, or because the NIC driver determines the NIC's receive capability is disfunctional. If a reset is initiated by NDIS and MiniportReset returns NDIS_STATUS_PENDING, NDIS first calls the Protocol(Co)Status function of each bound protocol driver with a status of NDIS_STATUS_RESET_START, and then calls the same bound protocol driver's ProtocolStatusComplete function. When the NIC driver calls NdisResetComplete, NDIS again calls ProtocolCoStatus with a status of NDIS_STATUS_RESET_END followed by a call to ProtocolStatusComplete.

A protocol driver must handle the possibility that outstanding sends on a binding to an underlying NIC can be cancelled because the NIC is reset. If a bound protocol driver has any transmit packets pending, NDIS will complete those packets back to the protocol driver with an appropriate status. The protocol driver must resubmit the packets again when the reset operation is completed, assuming the NIC becomes operational again.

When a protocol driver receives a status of NDIS_STATUS_RESET_START, it should do the following:

  • Hold any packets ready to be transmitted until Protocol(Co)Status receives an NDIS_STATUS_RESET_END notification.
  • Not make any NDIS calls directed to the underlying miniport, except calls to return resources such as returning packets with NdisReturnPackets.

After ProtocolCoStatus receives an NDIS_STATUS_RESET_END message and ProtocolStatusComplete is called, the protocol driver can resume sending packets and requests.


Protocol Driver Unbinding Operations

A protocol driver unbinds from an underlying NIC by calling NdisCloseAdapter. NDIS will call the protocol driver's ProtocolUnbindAdapter function if the underlying NIC is no longer available.

A protocol driver also should unbind from an adapter from ProtocolUnbindAdapter if some action subsequent to opening an adapter, such as allocating a required resource, fails, and the driver needs to unbind because it cannot carry out network operations on the binding.

ProtocolUnbindAdapter calls NdisCloseAdapter. However, the protocol must not deallocate all its binding-specific resources until it calls NdisCompleteUnbindAdapter. The protocol can deallocate any previously allocated resources when either NdisCloseAdapter returns NDIS_STATUS_SUCCESS, or, if NdisCloseAdapter returns NDIS_STATUS_PENDING, when ProtocolCloseAdapterComplete is called.

NDIS delays calling ProtocolCloseAdapterComplete until all outstanding requests on the binding have completed. Once the close request completes, the ProtocolBindingContext handle the protocol driver allocated to represent the binding becomes invalid.

As soon as a protocol calls NdisCloseAdapter, the handle at NdisBindingHandle should be considered invalid by the caller. It is a programming error to pass this handle in any subsequent call to an Ndis Xxx function.

Before returning synchronously from ProtocolUnbindAdapter or before completing the unbind operation asynchronously with NdisCompleteUnbindAdapter, the driver must do the following:

  • Finish cleaning up any state that it maintains for the binding
  • Release any resources that it allocated to establish the binding
  • Call NdisCloseAdapter


Status Indications in a Protocol Driver

A connectionless protocol driver is required to supply both ProtocolStatus and ProtocolStatusComplete functions. A connection-oriented protocol driver is required to supply both ProtocolCoStatus and ProtocolStatusComplete functions.

NDIS calls ProtocolStatus when an underlying connectionless NDIS driver calls NdisMIndicateStatus to report a change in its NIC. NDIS calls ProtocolCoStatus when an underlying connection-oriented NDIS driver calls NdisMCoIndicateStatus.

ProtocolCoStatus is called when the status change begins. If the action indicated by the status message is not complete when the ProtocolStatus function or a connectionless protocol is called, NdisMIndicateStatusComplete is subsequently called by an underlying connectionless NIC driver When this occurs, ProtocolStatusComplete is called to carry out any postprocessing indicated by the status change. Note that a connection-oriented miniport does not have to indicate that it has finished sending status and therefore does not call ProtocolStatusComplete.

Examples of GeneralStatus reported to ProtocolStatus include:

  • NDIS_STATUS_RESET_START and NDIS_STATUS_RESET_END — In this case, both of these statuses are reported to both Protocol(Co)Status and ProtocolStatusComplete as explained already in Protocol Driver Reset Operations.
  • NDIS_STATUS_LINE_UP — This status is indicated if the protocol driver is layered over NDISWAN while an underlying WAN-capable NIC driver has an established connection with a remote node. The protocol driver exchanges handles for an active connection on which it can send and receive as well as query the connection for call-specific information. See WAN Miniport Drivers.
  • NDIS_STATUS_RING_STATUS or any other medium-specific status value, for which StatusBuffer provides more detailed information about the status, for instance, problems specific to a Token Ring medium.
  • NDIS_STATUS_MEDIA_CONNECT and NDIS_STATUS_MEDIA_DISCONNECT. When a NIC miniport senses that the network connection has been lost, it calls NdisMIndicateStatus or NdisMCoIndicateStatus with NDIS_STATUS_MEDIA_DISCONNECT. When the connection is restored, it must then call NdisM(Co)IndicateStatus with NDIS_STATUS_MEDIA_CONNECT.


Transport Helper DLLs for Windows Sockets

Originally an application programming interface specific to TCP/IP, Windows Sockets has since become the primary user-mode interface to network transports for Windows® 2000 and later versions of the operating system. In addition to TCP/IP, the Windows Sockets dynamic-link library works in conjunction with several other transports that provide extensions in the form of transport-specific user-mode Windows Sockets helper (WSH) DLLs.

This section describes the WSH DLL to be supplied with a new transport driver to support application calls through Windows Sockets. This information includes an overview of the architectural relationships among Windows Sockets, transport drivers, and transport-specific WSH DLLs; a discussion about how Windows Sockets communicates with transport-specific WSH DLLs; descriptions of how to set up the configuration registry and manage synchronization for WSH DLLs; and details about how WSH DLLs can support additional information that is sent over the network during connections and disconnections.

This section includes the following topics:

Windows Sockets Helper DLL Architecture

Communicating with a WSH DLL

Configuring a WSH DLL

WSH DLL Synchronization

Supporting Connect and Disconnect Data with a WSH DLL

WSH DLL Function Summary

For information about how applications interface with Windows Sockets 2, see the Microsoft Windows Platform Software Development Kit (SDK).


Windows Sockets Helper DLL Architecture

Windows Socket Helper (WSH) DLLs are user-mode components provided by transport driver writers to facilitate the usage of Windows Sockets with their transports. The following figure shows an overview of this architecture.

Windows Sockets Helper DLL architecture

Windows 2000 and later versions provide a dynamic-link library, msafd.dll, which is a sockets service provider. When a transport driver is installed in the system and it installs a transport-specific WSH DLL, network setup will automatically configure msafd.dll to be the service provider for that WSH DLL. When an application makes a call to a Windows Sockets function, such as WSASocket, MSAFD as the service provider will resolve the call and make a call to the appropriate WSH DLL for assistance as necessary.

Some Windows Sockets functions require no assistance from any WSH DLL. For example, sending or receiving data does not require the WSH DLL as the connections have already been established. In cases such as these, MSAFD can communicate directly with the transport by calling Win32® functions.

However, for function calls that rely on transport-specific features or where the implementation can vary from transport to transport, the transport-specific WSH DLL will be used to resolve these ambiguities. For example, WSAJoinLeaf adds a socket to an established multipoint session. Each transport implements the addition of new connections to a multipoint session differently. Consequently, MSAFD calls the appropriate WSH DLL to support the sockets interface according to the transport-specific implementation. To support application calls to WSAJoinLeaf, MSAFD calls the WSH DLL's WSHJoinLeaf function to validate the options requested and calls the transport with the appropriate information to add a new socket to a multipoint session.

If a transport supports the new features of Windows Sockets 2, including multipoint session sockets, socket grouping, and logical representations of socket addresses, the corresponding WSH DLL must export the Windows Sockets 2 functions, summarized later in WSH DLL Function Summary.


Communicating with a WSH DLL

Each transport that supports Windows Sockets applications supplies a user-mode Windows Sockets helper dynamic-link library to interpret network addresses and to process socket options in the architecture as outlined in Windows Sockets Helper DLL Architecture.

For example, when any application calls socket, it specifies an address family, a socket type, and a protocol. These three arguments must uniquely identify a transport driver to support the socket. Windows Sockets searches for a match between these application-supplied arguments and the standardized configuration information stored in the registry for WSH DLLs. If it finds a match, Windows Sockets subsequently calls down through MSAFD to the WSH Xxx functions exported by the WSH DLL as necessary. Otherwise, the application's call to socket fails.

When a match is found, Windows Sockets calls LoadLibrary on the WSH DLL, and then calls GetProcAddress to retrieve the entry point for each exported WSH Xxx function. These WSH Xxx functions are called whenever necessary to query for protocols supported by the helper DLL, to translate addresses, and to process WSH-supported options as getsockopt and setsockopt calls occur. For example, when an application passes an option to setsockopt that is not explicitly supported by Windows Sockets, the appropriate WSH DLL is called to process the option. The WSH DLL takes any necessary action to support each such option the corresponding transport supports.

The following conventions permit mechanical transformations between socket addresses, application-specified as SOCKADDR structures, and the TDI-defined addresses used by underlying transport drivers.

  • TDI address types, specified as values in the AddressType member of TA_ADDRESS structures, are identical to the address family values of socket address structures.
  • The Address[ ] array of a TA_ADDRESS structure has exactly the same format as the data following sa_family in a socket address structure for a given address type.


Configuring a WSH DLL

Two places in the registry must be set up with standardized configuration information for each WSH DLL:

  1. Under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet
    \Services\Winsock\Parameters     is a value entry of type REG_MULTI_SZ specifying a list of protocols (transport drivers) that each have a corresponding WSH DLL. The names stored in this list match the key names for the corresponding transport drivers under ..\CurrentControlSet\Services.
  2. Under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet
    \Services\    TransportDriverName\Parameters for each such transport driver is a Winsock subkey. Windows Sockets opens this key by forming a name string from the path to its own key under the Services key, the transport name specified in the list under ..Winsock\Parameters, and the transport's ..Parameters\Winsock key, which must contain the following value entries:
    • Mapping — a REG_BINARY value that describes the address family, socket type, and protocol parameter triples supported by the WSH DLL. The format for this binary data is the WINSOCK_MAPPING structure, as defined in wsahelp.h.
    • HelperDllName — a REG_EXPAND_SZ value that specifies the path to the WSH DLL itself.
    • MinSockaddrLength — a REG_DWORD value that specifies the smallest valid SOCKADDR size, in bytes, for the WSH DLL.
    • MaxSockaddrLength — a REG_DWORD value that specifies the largest valid SOCKADDR size, in bytes, for the WSH DLL.

Storing this information in two distinct places under ..\CurrentControlSet\Services helps to localize information about a transport driver under that driver's own Parameters key. The information under ..\Services\Winsock\Parameters provides a pointer to the actual information for each transport's WSH DLL, allowing setup programs to interoperate more easily.

Setup utilities for Windows 2000 and later versions provide functions that perform most of the necessary work to set up WSH DDL registry information for a transport driver. These routines are AddWinsockInfo and RemoveWinsockInfo in the setup file utility.inf, which can be found in the system directory. A transport driver's installation script can call AddWinsockInfo, passing in the key name under Services of the transport driver, the full path name of the transport-specific WSH DLL, and the minimum and maximum SOCKADDR lengths. AddWinsockInfo then stores the standardized information already described in the registry.

For an example of a transport's call to this setup function, see oemnxptc.inf, the installation script for TCP/IP, also located in the system directory.


WSH DLL Synchronization

Windows Sockets guarantees synchronization to a WSH DLL on a per-socket basis. That is, two threads cannot be executing concurrently in WSH Xxx functions for the same socket. Consequently, a WSH DLL that maintains its state information on a per-socket basis need not do any synchronization of its own.

If a WSH DLL maintains global state or per-process state, it must synchronize access to such state information internally. Windows® 2000 and later versions provide several user-mode synchronization mechanisms such a WSH DLL might use, including semaphores, events, and critical sections. Which type of synchronization mechanism to use is up to the WSH DLL developer.


Supporting Connect and Disconnect Data with a WSH DLL

Some transports, such as DECNet and OSI TP4, support connect and disconnect data: additional data, not in the normal network data stream, that is sent on the wire along with connect or disconnect requests. Typically, connect and disconnect data is used for operations like application-level version negotiation.

TDI supports the transmission of connect and disconnect data in the TDI_CONNECTION_INFORMATION structure, which has members specifying the UserDataLength, UserData, OptionsLength, and Options. This structure is passed in TDI connect, accept, and disconnect requests by kernel-mode TDI clients.

However, Windows Sockets does not provide input parameters for connect data to the connect function or for disconnect data to the shutdown and closesocket functions. WSH DLLS can add support for connect and disconnect data for applications that call the Windows Sockets setsockopt and getsockopt functions.

The setsockopt function can be called to specify connect and disconnect data to be sent to a remote node, and getsockopt can be called to retrieve connect and disconnect data sent from the remote node. To support this, see the SO_XXX options in the header file winsock.h.

How an application uses these options in conjunction with getsockopt and setsockopt depends on whether the application is a server or client, and on how the application uses the transmitted connect data. For information about client applications, see Client Applications and Connect Data. Server Applications and Connect Data.For transports, such as DECNet, that have a preexisting definition of connect data different from what is described here, a WSH DLL translates between the transport's semantics and the semantics expected by Windows Sockets, making calls to getsockopt and setsockopt.

Connect and disconnect options are effectively the same as connect and disconnect data from the standpoint of Windows Sockets. These are actually a buffer of data passed to the transport prior to the connect or disconnect, and a buffer containing data that is retrieved following a connect or disconnect. Consequently, an application uses connect or disconnect options in much the same manner as connect or disconnect data. The only difference is the option names used for the parameter passed to getsockopt and setsockopt; for example, SO_CONNOPT in place of SO_CONNDATA.


Client Applications and Connect Data

An application written to communicate through Windows Sockets with a transport that supports connect data should call setsockopt with SOL_SOCKET as the level, SO_CONNDATA as the option name, and an option value that is a pointer to a buffer containing the connect data the transport should send to the remote node with the connection request. Such an application must call setsockopt before it calls connect, and the application-supplied connect data is transmitted when the application makes its call to connect.

Besides making a call to connect, retrieving response-connect data requires two additional steps:

  1. Before calling connect, the application must inform Windows Sockets of how much space to reserve for the expected response-connect data. To do this, the application calls setsockopt with option level SOL_SOCKET, option name SO_CONNDATALEN, and option pointing to an integer that specifies the maximum number of bytes the application expects. Windows Sockets allocates a buffer of this size to contain connect data sent by the server application from the remote node.
  2. After connect has completed successfully, the application can call getsockopt with an option level of SOL_SOCKET, option name of SO_CONNDATA, and option pointing to a large enough buffer to hold the response-connect data. Then, Windows Sockets copies the response-connect data, if any, into the application's buffer.

After an application has set up a response-connect buffer, Windows Sockets uses that buffer for the lifetime of the socket. That is, an application can retrieve response-connect data for a particular socket at any time after the socket is connected and before it is closed.


Server Applications and Connect Data

Server applications use connect data differently from client applications in two important ways:

  1. A server application receives the client's connect data before it sends back its own.
  2. Because Windows Sockets does not support delayed-connection acceptances as TDI does, a server application must send the same response-connect data to all clients.

To receive connect data sent by clients, a server application calls setsockopt with the SO_CONNDATALEN option to force Windows Sockets to reserve buffer space for receiving connect data for incoming connect requests. The specified amount of connect-data buffer space is used subsequently for all incoming connects, but Windows Sockets allocates a separate buffer for each connect.

After a newly connected socket is accepted with accept, the server application calls getsockopt with the SO_CONNDATA option and a server-allocated buffer large enough to hold the expected data. Windows Sockets fills in this buffer with the connect data sent by the client.

To send response-connect data to clients, a server application calls setsockopt with the SO_CONNDATA option and a buffer of data before any incoming connections are accepted (typically before listen). Thereafter, any client that connects to the server receives that server-supplied connect-response data. The connect-response data for a server can be changed at any time with another setsockopt call, which discards the previous data and replaces it with the new data.


Disconnect Data

Client and server applications send and receive disconnect data in a manner similar to the way each sends and receives connect data.

To send disconnect data, a client application calls setsockopt with the SO_DISCDATA option and a buffer of disconnect data to be transmitted to the server on the remote node. This data is sent either when the client application calls shutdown to disconnect the send side of the socket or when the application calls closesocket on the socket.

To receive disconnect data, a client application must call setsockopt with the SO_DISCDATALEN option prior to a remote's closure of the connection. This option specifies the amount of disconnect data the application expects to receive.

After the remote has disconnected, any server-supplied disconnect data can be retrieved with the SO_DISCDATA option to getsockopt. The client application passes in a buffer large enough to hold all the disconnect data, and Windows Sockets copies the received disconnect data into this buffer.


WSH DLL Function Summary

This summarizes the set of WSH Xxx functions that every WSH DLL must export. Each supplier of a new transports can implement these functions in a corresponding WSH DLL according to the features supported by each transport. Windows Sockets treats all WSH DLLs as trusted code. Consequently, any bug in a WSH Xxx function manifests itself as bug(s) in Windows Sockets.

The following summarizes the set of functions that must be exported by any transport-specific WSH DLL:

WSHEnumProtocols returns a list of protocols (Windows Sockets PROTOCOL_INFO structures) that the WSH DLL supports.

WSHGetSockAddrType parses a socket address.

WSHGetSocketInformation is called whenever getsockopt is passed an option that Windows Sockets does not explicitly support.

WSHGetWildCardSockAddr is called when Windows Sockets needs to perfom an "automatic" bind of a socket.

WSHGetWinsockMapping returns information about the address family, socket type, and protocol parameter triples supported by the WSH DLL.

WSHNotify is called to notify the helper DLL of a state transition.

WSHOpenSocket is called when a socket is opened.

WSHSetSocketInformation is called whenever setsockopt is passed an option that Windows Sockets does not explicitly support.

To support the new Windows Sockets 2 extensions for leaf/root sockets, socket groups, and logical representation of sockets, the following optional functions should be implemented:

WSHAddressToString returns a logical string representation of a socket address that can be used for display purposes.

WSHGetBroadcastSockaddr obtains a valid broadcast address for a socket.

WSHGetProviderGuid returns the GUID that identifies the protocols supported by a helper DLL.

WSHGetWSAProtocolInfo returns a pointer to protocol information for the protocol(s) supported by a helper DLL. This function is only used during setup.

WSHIoctl obtains information or performs actions based on a unique control code.

WSHJoinLeaf performs any protocol-specific actions that must be taken to add a socket to a multipoint session.

WSHOpenSocket2 performs the protocol-specific actions for creating a new socket. If this function is exported, it replaces the WSHOpenSocket function.

WSHStringToAddress converts a logical string representation of a socket address to a SOCKADDR structure.

For more detailed information about these WSH Xxx functions, see Windows Sockets Support Reference.


TDI Transports and Their Clients

This section describes the relationship between TDI transport drivers and TDI kernel-mode clients, such as higher level network-interface emulators, redirectors, and servers, that communicate with any transport protocol stack using the system-defined TDI interface.

This discussion includes information about:

  • How PnP-aware TDI transports use device objects to represent their transport-to-NIC bindings.
  • How PnP-aware TDI transports dynamically register network addresses available to clients through these bindings with TDI.
  • How TDI uses file objects to represent network entities.
  • Transport driver dispatch routines required by TDI.
  • Interactions between TDI clients and their underlying transports.
  • Distinctions between TDI requests and events.

This section includes the following topics:

Transport Driver Interface

TDI Device Objects

TDI File Objects

TDI Transport Driver Routines

TDI Kernel-Mode Client Interactions

TDI Requests Versus Events


Transport Driver Interface

The following figure shows the general relationship between TDI clients and transport drivers.

TDI Clients and Transport Providers

As this figure shows, the Transport Driver Interface (TDI) defines a kernel-mode network interface that is exposed at the upper edge of all transport protocol stacks. The highest level protocol driver in every such stack supports the TDI interface for still higher level kernel-mode network clients.

This interface includes the following:

  • A set of standard kernel-mode intermediate driver Dispatch routines exported by each TDI transport driver to which clients can submit I/O requests (IRPs) by making calls to support routines, such as the Zw..File routines or IoCallDriver
  • A set of ClientEventXxx callback routines exported by each TDI client that can be registered with the underlying transport driver to receive notifications of specific network events when they occur
  • A set of ClientPnPXxx callback routines exported by TDI clients that can be registered with TDI to receive notifications of dynamic binding, network address, and power-state changes from PnP-aware transports for Windows® 2000 and later versions of the operating system.
  • Parameters, structures, IOCTLs, and procedural rules associated with these TDI transport and ClientEventXxx and ClientPnPXxx routines
  • A set of system-supplied Tdi Xxx functions that transports and clients can call to communicate with each other
  • A set of system-supplied TdiBuild Xxx macros and functions that clients can use to set up I/O requests to be submitted to their underlying transports

Requiring that all transport drivers expose a single common interface (TDI) simplifies the task of transport driver development in that all transports need code to support only a single defined interface. It also simplifies the task of client development by minimizing the amount of transport-specific code that must be written.

Windows® 2000 and later versions of the operating system include interface modules for several popular network interfaces, such as Windows Sockets and NetBIOS. Each of these interface modules exposes a native set of primitive functions, which are accessible through standard calls from user mode. When called, the interface module maps the native (frequently user-mode) function and its associated parameters and procedural rules, to one or more calls to the underlying TDI transport driver.

Key features of TDI include the following:

High Level of Granularity
TDI accommodates all primitives and conventions from existing popular network interfaces because it is relatively granular in nature, with several small TDI-defined requests that can be mixed and matched to accommodate mapping from existing network-interface functions.
Asynchronous Operation
Most kernel-mode TDI operations are asynchronous, using client-supplied callback routines to indicate asynchronous network events as they occur and completing most client-initiated operations submitted as IRPs asynchronously as well.
32-bit Addressing and Values
Like all kernel-mode components for Windows 2000 and later versions, TDI transports and their clients are 32-bit code. TDI-defined structures and parameters use 32-bit pointers and values.
Flexible Addressing Scheme
TDI does not mandate any particular address format, such as the 16-character NetBIOS name defined for legacy operating systems. Instead, it features an extensible mechanism by which many address formats can be identified and used.
Extensible Communication
TDI defines a TDI_ACTION IOCTL request that any TDI transport can use to support a set of transport-determined operations initiated by requests from its clients. This allows the client to submit transport-specific requests to the underlying transport driver that are not expressly defined by TDI.
Event Notification
TDI defines a scheme by which transports can notify their clients of interesting events that occur on the network without requiring the client to submit an explicit I/O request. For certain types of events, such as connects, disconnects, and receives, the transport driver can indicate data along with the event notification when it calls its client with such a notification.
Plug-and-Play Event Notifications
TDI defines a scheme by which transports for Windows 2000 and later versions can notify their clients of certain PnP events, such as the availablity of underlying NICs and the creation/deletion of connections on local network addresses.
System Power-State Change Notifications
TDI defines a scheme by which transports for Windows 2000 and later versions can notify their clients of proposed system power-state changes, thereby giving the client an opportunity to keep an active connection powered up.

The following features can be supported by a TDI transport driver as additional options:

Data Transfer Modes
TDI supports sending and receiving data as discrete messages (message mode) or as a stream of bytes (byte-stream mode). Support for either mode (or both) depends on the transport driver writer or on the nature of the protocol.
Internal Buffering
TDI transports can buffer their client's sends and receives internally. Transport-internal buffering allows the TDI client to set and query driver internal buffer sizes, request nonblocking send operations, receive notification of available buffer space, and look at (peek) buffered data before receiving it.
Management Options
All transports maintain some TDI-defined state about their respective features, limits, and run-time statistics. This allows each client to dynamically query and, in some cases to set, transport-provider static information, statistics, and configuration parameters. In addition, the extensible TDI_ACTION IOCTL, mentioned previously, allows any TDI transport driver to implement unique network-management features that can be accessed by its clients through action requests to the transport.
Quality of Service (QOS)
TDI transports can provide QOS negotiation upon establishment of a network connection. In addition, such a driver can support QOS for connectionless datagram transmission. To support either, TDI-defined connection-establishment and datagram-send requests include Options and OptionsLength parameters that allow a TDI client to include a transport-specific, variable-length counted string specifying QOS options.

In fact, the Options and OptionsLength parameters can be used to pass any transport-specific connection- or datagram-related options to the transport driver at the discretion of the driver writer, not just QOS specifications.

Expedited Delivery
When sending messages, the client can flag particular messages as expedited. At the sending side, the underlying transport sends these messages ahead of non-expedited messages. At the receiving side, expedited messages are indicated to the client before or separate from non-expedited messages.
Chained Receive Indications
If the underlying NDIS miniport drivers support multipacket receive indications, a TDI transport can give its clients direct read-only access to a full TSDU in a single call, and the client can retain control of the buffer containing the TSDU until it has consumed the indicated data. This feature improves the performance of both transport and client by cutting down on call overhead for receive indications.


TDI Device Objects

Transports for Windows 2000 and later versions support Plug and Play and system power management by creating device objects to represent their respective bindings to underlying NICs. Each such transport registers itself with TDI during system startup as a network provider to make the PnP-aware transport available to potential clients when the underlying network hardware comes online.

Potential clients of these PnP-aware transports register their respective ClientPnPXxx callbacks with TDI to receive notifications of the availablility of active transport-to-NIC bindings and of transport-established network addresses on which these clients can subsequently send and receive data over the network while these network addresses remain valid.

As such a transport establishes a binding to an underlying NIC from the ProtocolBindAdapter function that the lowest module in the transport stack (or monolithic tranport driver) registered with NDIS, the TDI transport driver creates a named device object to represent its binding to the underlying NDIS miniport driver. During system startup, such a PnP-aware transport registers each named device object it creates with TDI and sets up its per-binding state. The transport also registers any known network addresses on each such binding with TDI and sets up its per-registered-address state. When NDIS calls the ProtocolPnPEvent function at the bottom of the transport stack with the PnP event code NetEventBindsComplete, such a transport then notifies TDI if it is ready to transfer data over the network on at least one such transport-to-NIC binding.

TDI gives each network client that has registered its ClientPnPXxx handlers the opportunity to bind itself to each such transport-created device object by calling ZwCreateFile from the client's registered ClientPnPBindingChange routine. TDI subsequently calls its registered ClientPnPAddNetAddress routine one or more times with each network address that the underlying transport has already registered for its device object. TDI also notifies these clients with calls to their registered ClientPnPBindingChange routines when any particular transport indicates it is ready to carry out network transfers and again when all startup-time transport-to-NIC bindings have been established.

At run time, these PnP-aware transports (or NDIS) continue to call TDI whenever a dynamic binding change occurs, whether because a NIC has been enabled/disabled or because the end user has initiated a binding change, and whenever such a transport makes or breaks a connection to a remote-node network address as follows:

  • If a new NIC is enabled, NDIS calls the ProtocolBindAdapter function at the bottom of each transport stack, thereby giving that transport an opportunity to bind itself to the new NIC, to create another device object to represent its new binding, and to register its new device object with TDI. As each such transport-created device object is registered, TDI calls the set of currently registered ClientPnPBindingChange routines and offers these clients the opportunity to open the new bindings.
  • After registering a new device object, the transport also registers any known network addresses on its new binding with TDI. TDI calls the set of registered ClientPnPAddNetAddress routines when transports register known network addresses on their new (or existing) bindings. These calls also give clients the opportunity to open a connection to such a registered address (and even to a binding). Whenever such a transport breaks a connection to a remote node, it calls TDI to deregister the corresponding network address.
  • Before an existing NIC is disabled, NDIS typically calls the ProtocolPnPEvent function at the bottom of the transport stack to ask whether it is safe to remove the NIC. The transport, in turn, notifies TDI of such a request to remove that NIC, and TDI notifies the clients with calls to their registered ClientPnPPowerChange routines. If no client objects to the NIC's removal, NDIS subsequently calls the ProtocolUnbindAdapter function at the bottom of the transport stack and the transport tears down its binding. In this process, the transport calls TDI to deregister all the network addresses it formerly registered on the binding, and it also calls TDI to deregister the device object that it created to represent that binding. In turn, TDI notifies clients of these unbinding operations by making calls to their registered ClientPnPDelAddress and ClientPnPBindingChange routines.
  • If the end user initiates a binding change in the network connections folder, NDIS calls TDI directly to notify registered network clients of the proposed binding change. If no client objects (and, therefore, the user is not prompted to cancel the binding-change operation), NDIS proceeds to call the appropriate ProtocolPnPEvent, ProtocolBindAdapter, or ProtocolUnbindAdapter functions at the bottom of the transport stacks.

In a similar manner, TDI notifies the clients of PnP-aware transports about proposed system power-state changes for underlying NICs. When the system Power Manager calls NDIS to power down (or up) a NIC, NDIS calls the ProtocolPnPEvent function at the bottom of each transport stack that is currently bound to the NIC. Each such PnP-aware transport, in turn, notifies TDI of the proposed power-state change and TDI forwards the notification to the transport's clients for their approval or rejection.


TDI File Objects

All I/O requests are directed to an open file object, which can represent a physical or virtual device, a data file, or any logical target of I/O requests, that can be opened by a particular process. Open file objects are process-specific. For example, the I/O Manager creates a file object for each process that opens a particular data file.

TDI uses file objects to represent entities that exist in any network communication environment. In particular, TDI uses file objects to represent the following types of TDI-defined entities:

  • To represent transport addresses opened by specific processes or groups of processes on a network node. For more information, see File Objects Represent Transport Addresses.
  • To represent connection endpoints identifying specific endpoints associated with particular transport addresses, opened to set up endpoint-to-endpoint connections with remote-node peer processes. For more information see, File Objects Represent Connection Endpoints.
  • To represent control channels identifying transport providers, opened for the purpose of setting and querying global configuration, features, limits, or statistics information maintained by the underlying transport. For more information, see File Objects Represent Control Channels .

A TDI transport driver and the underlying NDIS drivers provide a mechanism by which data can be transferred from a process on one network node to one or more processes that reside either on the same node or other network nodes. The preceding address and connection endpoint entities represented by open file objects are the means by which such transfers occur.

For example, the redirector process for Windows® 2000 and later versions opens two file objects, one representing a transport address and the other a connection endpoint associated with that address, to send SMB (Server Message Block) messages to a server process on a remote node and to receive messages back from the server process on the remote node.


File Objects Represent Transport Addresses

TDI supports both unreliable connectionless and reliable connection-oriented data transfers.

Unreliable connectionless data can be sent to one or a group of processes that have opened a particular transport address on a remote node. When sending unreliable connectionless data, as datagrams, the sender need only identify the target remote-node address for the process or group of processes for them to receive each such datagram.

Reliable connection-oriented data transfers can be sent between two processes if an endpoint-to-endpoint connection (also called a virtual circuit) has been established between them. An endpoint-to-endpoint connection is a one-to-one association between two, and only two, processes. To establish such a connection, one process must identify the process with which it wants to establish the connection. Each such process must have opened a transport address and a connection endpoint on its respective network node and associated its connection endpoint with the open transport address. For more information about connection endpoints, see File Objects Represent Connection Endpoints.

The TDI entity used to identify a specific process, or a specific group of processes is one or more open process-specific file objects that represent a particular transport address. Such a file object contains transport-supplied pointers to driver-maintained state that identifies the specific process and the node on which that process resides. The state that a "routable" transport, such as TCP/IP, Mcsxns, AppleTalk and NWLink, maintains about such an address also contains information that identifies the network (or subnet) on which the node resides.

Certain TDI-defined transport address types accommodate explicit or implicit indications of whether the address identifies a single process (unique address), or can identify a group of processes (group address). In the case of a group address, the TDI-defined address can contain information that identifies the specific processes, that is, the node on which the process resides, and the network (or subnet) on which the node resides.

A number of address types are supported by TDI. The following describes the format and usage of three commonly used TDI address types:

TDI_ADDRESS_NETBIOS
The NetBIOS-type address consists of a standard 16-character NetBIOS name, and a member that indicates if the name is registered (or to be registered) as a unique name (indicating that the name identifies a single process), or as a group name (indicating that the name can identify a group of processes).

Because the transport driver ensures that a unique name is in use by only one process on the network at a time, such a name not only identifies the process, it also implicitly identifies the node on which that process resides.

If the registered name is a group name, it can be an address available to many processes on many stations. Thus a group name identifies all processes that registered the name as well as the nodes on which those processes reside.

TDI_ADDRESS_IP
The IP-type address consists of a port number and a standard Internet Protocol (IP) address. Because TCP/IP allows the same port number to be registered by processes on many nodes, the IP address is required to uniquely identify the node and the port number is required to uniquely identify the process on that node.

For connectionless data transfer (using the TCP/IP UDP protocol), the same port number can be registered by many processes on the same station. In addition, certain IP addresses can be used by more than one node. Data sent to a TDI address that consists of this type of port number and IP address will be received by all nodes to which the IP address applies; on those nodes, the data will be passed to all processes that have registered the specified (UDP) port number.

TDI_ADDRESS_IPX
The IPX-type address consists of a four-byte network number, a six-byte node number, and a two-byte port number. Because IPX allows the same port number to be registered by processes on many nodes, an IPX address is required to uniquely identify the network and the node, while the port number can be used to uniquely identify the process on that node.


File Objects Represent Connection Endpoints

A file object that represents an open connection endpoint identifies a specific connection on which local and remote-node peer processes are communicating with each other across the network or will communicate with each other when the local-node process has established an endpoint-to-endpoint connection with a remote-node peer.

Any such file object must be associated with another open file object that represents a particular transport address. The transport address identifies the process, as already described in File Objects Represent Transport Addresses.

In a similar manner, the transport uses the file object representing the local connection endpoint to maintain state about the remote-node peer process, such as the remote-node transport address, with which its local-node client establishes an endpoint-to-endpoint connection.

A client process can establish many endpoint-to-endpoint connections between itself and other processes on remote nodes. For example, the redirector establishes separate connections between itself and each remote server for Windows 2000 and later with which it communicates. Such a client can have several open connection endpoints all separately associated with an open transport address.

A process cannot send data over an endpoint-to-endpoint connection unless it has a means of identifying which of all existing connections the data is to be sent over. Each open file object that represents a connection endpoint is used to discriminate among established endpoint-to-endpoint connections of the same process.


File Objects Represent Control Channels

A network management process can query or set global configuration or statistical information with respect to a specific transport provider. To do so, such a process must have a means of identifying a particular transport among several possible transport providers.

Such a client opens a file object that represents a control channel so that it can query the appropriate transport. In effect, the client opens a file object that represents the device object created by the underlying transport driver when the client opens a control channel, either by calling ZwCreateFile or IoGetDeviceObjectPointer.

Other TDI clients that send and receive data across the network also can open a control channel to query their underlying transports. For example, such a client might issue a query to determine the transport's limit on datagram size so the client could effectively size the buffers that it will allocate to send and receive datagrams subsequently.

In general, a TDI transport maintains global state information about its features and current statistics, rather than process-specific state information tied to a particular open file object. For example, a client that queries the current state of its open transport address passes a pointer to a client-specific file object representing that address, but the transport returns information common to all clients that currently have the same address open.


TDI Transport Driver Routines

Every TDI-compliant transport driver is a standard intermediate driver that must export a number of entry points called by the I/O Manager.

Some of a TDI transport's standard driver routines initialize and unload the driver itself. Others are standard Dispatch routines that the I/O Manager calls when TDI clients make calls to system support routines, such as ZwCreateFile and IoCallDriver.

Like other kernel-mode drivers, a TDI transport's DriverEntry routine sets up one or more driver-supplied Dispatch routines to handle various types of I/O requests passed in as IRPs. A TDI driver can export a single Dispatch routine to handle all incoming IRPs or a separate DispatchXxx routine to handle each IRP_MJ_XXX the driver must support. General requirements for Dispatch routines are discussed in detail in the Kernel-mode Driver Design Guide. For more information about TDI-specific requirements for dispatch routines, see TDI Routines, Macros, and Callbacks and the Network Driver Reference.

As a TDI transport completes an operation requested by its client, the I/O Manager calls any client-supplied IoCompletion routine that the client set in the IRP before that client submitted it to the underlying transport.

In addition, such a transport driver must call the TDI client at preregistered entry points within the TDI client's code when specific network events occur. These client-supplied event handlers also summarized in TDI Routines, Macros, and Callbacks and are described in the Network Driver Reference.

At its lower edge, a TDI driver that is monolithic must export a set of ProtocolXxx functions to be called by the NDIS library on behalf of underlying NDIS intermediate or NIC drivers. These NDIS driver lower-edge functions are described earlier in this guide and in a function-specific manner in the Network Driver Reference.


TDI Kernel-Mode Client Interactions

The following figure shows how TDI clients make I/O requests to their underlying TDI transports and how transports make callbacks to their clients.

TDI Client/Transport Interactions

A TDI client interacts with its underlying transport driver as follows:

Creating TDI File Objects
A client calls ZwCreateFile to create or open a file object that represents a transport address, a connection endpoint, or a control channel. This call causes the I/O Manager to allocate an IRP, to marshal the client-supplied parameters into the IRP, and to pass the IRP to the underlying transport driver's TdiDispatchCreate routine. When the transport driver has set up all the state it maintains for the newly created file object, it calls IoCompleteRequest (or TdiCompleteRequest) with the IRP and STATUS_SUCCESS. ZwCreateFile then returns to the TDI client with a handle to the file object.

Each client process's call to ZwCreateFile creates a separate file object, even if two clients have specified the same transport address in their calls to ZwCreateFile.

A successful call to ZwCreateFile opens a transport address, a connection endpoint, or a control channel, depending on the EaXxx parameters the client passes in its call.

Submitting Requests
After the appropriate file objects have been created, the client can submit requests that reference those objects. For example, after it opens a file object that represents a particular transport address, the client can submit an address-information query or "send datagram from this address" request.

Such a client uses standard I/O system mechanisms and conventions to submit all such requests:

  • The client prepares an IRP with an IRP_MJ_XXX opcode that identifies what operation the client wants the transport driver to perform. The client supplies all appropriate parameters for the given IRP_MJ_XXX, and, optionally, sets up its own IoCompletion routine that will be called when the request is completed by the transport.

    The Windows DDK includes a set of TdiBuild Xxx macros (in tdikrnl.h) that can be linked into client code and used to prepare IRPs for TDI-defined IOCTL requests, as well as the TdiBuildInternalDeviceControl function to allocate such an IRP.

  • When the IRP has been set up, the client calls IoCallDriver with pointers to the IRP, to the file object that represents the address, connection endpoint, or control channel, and to the transport driver's device object. The I/O Manager passes the IRP directly to the appropriate TdiDispatch(Xxx) routine of the transport driver.
  • When the transport driver has completed the requested operation, it calls TdiCompleteRequest or IoCompleteRequest. The I/O Manager then calls the client-supplied IoCompletion routine if the client supplied one for the IRP.
Handling Event Notifications
If a client has preregistered its entry points for one or more event handlers, the transport driver calls each such routine when the corresponding network event occurs. For example, if the client has registered a ClientEventReceive handler on an address associated with an endpoint-to-endpoint connection, the transport calls this handler when data sent by the remote-node peer process is received on the local node.
Deleting TDI Objects
The client calls ZwClose to delete a file object when the address, connection endpoint, or control channel is no longer needed by the client. The close request is forwarded to the transport's TdiDispatchCleanup and, subsequently, TdiDispatchClose routines.

For more information about the kernel-mode support routines mentioned here, see Summary of Kernel-Mode Support Routines. For detailed information about the Tdi Xxx functions, TdiBuild Xxx macros, and ClientEvent Xxx routines mentioned here, see TdiBuildXxx Macros and Functions and TDI Client Event and PnP Notification Handlers.


TDI Requests Versus Events

Many low-level network interfaces, such as NetBIOS and Windows Sockets, are primarily one-way. A client can call the underlying transport driver whenever it wants, but the transport driver cannot call the client. The only way such a transport driver can "say anything" to its client is by returning a specific error code on return from a client-initiated request. In the NetBIOS interface, for example, a transport informs its clients of a connection "hangup" by returning pending NCB_Receives (or an NCB_Receive_Any) with a specific error code (0x0A for a session being closed, for example).

TDI provides an event-notification mechanism that allows a TDI transport to call its affected kernel-mode clients whenever a specific network event occurs (receipt of a datagram, for example) if each such client has registered its ClientEventXxx handler with the transport for that type of event. The TDI client-supplied callback then takes appropriate action and returns control to the transport driver.

TDI also defines a means for PnP-aware transports for Windows 2000 and later to notify their clients whenever such a transport binds itself to or unbinds itself from an underlying NIC, whenever the transport establishes or breaks a connection to a remote node on any particular binding, and whenever a system power-state change is proposed (or effected) by the Power Manager. The clients of such a transport register a set of ClientPnPXxx handlers with TDI to receive these types of notifications, as describedin TDI Device Objects.

When a TDI transport driver calls a client's registered ClientEventXxx handler, it can pass a limited amount of data as a parameter of that call. This feature allows the client to receive messages from the transport without having to allocate a buffer.

For example, the redirector takes advantage of this TDI feature. Many of the SMB requests that the redirector sends to the server (such as write SMBs) require little more than the standard SMB header to be present in the corresponding SMB response. The length of this header, which includes status indicators, multiplex ID, and so on, is quite small, typically less than 100 bytes.

When the underlying TDI transport driver calls the redirector's registered ClientEventReceive handler with such an SMB response message to a preceding send, the redirector need only view (not necessarily copy) the indicated message, note the SMB response status indicator, and return to the transport driver. In such a transaction, the redirector receives the SMB response message without having to allocate a buffer.


TDI Routines, Macros, and Callbacks

This section summarizes the routines and requests particular to TDI transport drivers. It also summarizes callback routines exported by TDI kernel-mode clients, as well as the macros and TDI functions provided by the system for transports and clients to use.

This section includes the following topics:

TDI Driver Initialization

TDI Driver Dispatch Routines

TDI IOCTL Requests

TDI Client Callbacks

TDI Library Functions and Macros

For more information about the sequence of interactions between TDI clients and transports when the preceding are used, see TDI Operations.

For detailed information about each request, macro, or routine, see TDI Transport Driver Dispatch Routines, TDI IOCTLs for Transport Drivers, TDI Functions, and TdiBuildXxx Macros and Functions.


TDI Driver Initialization

Every TDI transport driver must provide an initialization routine explicitly named DriverEntry. In addition, a transport driver should have as many TdiDispatchXxx routines and internal driver functions as it needs to satisfy the I/O requests of its kernel-mode clients. A TDI transport driver or one of the underlying protocol drivers in its transport stack also must provide the NDIS driver lower-edge functions described in NDIS Protocol Drivers and in NDIS Driver Lower-Edge Functions.

Every transport driver must have a DriverEntry routine to be called by the I/O Manager when the transport is loaded. DriverEntry must be declared in the driver code to make the transport automatically loadable.

When it loads the driver, the I/O Manager creates a driver object to represent the transport and passes a pointer to the driver object when it calls the TDI transport's DriverEntry routine. Then, its DriverEntry routine does the following:

  • Possibly, reads the registry (using kernel-mode support routines) to retrieve configuration information written into the registry by the transport's INF file. Using the registry information, configure itself as needed.
  • Sets all the driver's TdiDispatchXxx entry points in the driver object. The driver's TdiDispatchXxx routines will be called later by the I/O Manager to handle requests from TDI clients.
  • Calls TdiRegisterProvider to notify TDI of the transport's Plug and Play and power management support.
  • Creates at least one named device object for itself with IoCreateDevice. The names of each driver's device objects are the device names stored under the transport driver's registry section Linkage key in the Export entry. Each transport driver's Export entry determines what device objects will be created by any particular transport driver during system setup.

    Some transport drivers, such as NWLink, create only one named device object no matter how many NICs they bind themselves to. Some transports, such as TCP/IP, create one or more named device objects and "export" a set of device interfaces for each such device object. Other transport drivers create a separate named device object for each bound NIC, such as Nbf_Elnkii1, Nbf_Elnkii2, and so forth.

  • Performs any other necessary initialization tasks, such as binding to underlying NDIS intermediate and/or NIC drivers.
  • As it establishes bindings to each underlying NIC, a PnP-aware transport for Windows 2000 and later also calls TdiRegisterDeviceObject with the named device object that the transport creates. Then, it makes one or more calls to TdiRegisterNetAddress to register all known network addresses (whether of the local machine or of remote nodes) associated with the transport-created device object for its newly established binding.

When such a PnP-aware transport has completed its initialization on at least one but possibly more bindings so that it is capable of transferring data over the network, the transport must call TdiProviderReady. Typically, such a PnP-aware TDI transport calls TdiProviderReady as a consequence of an NDIS call to the ProtocolPnPEvent function at the lower edge of the transport stack with the input NET_PNP_EVENT code NetEventBindsComplete.

A TDI transport driver must provide an Unload routine unless that driver cannot be unloaded without rendering the system unusable. Most TDI transport drivers declare an Unload routine, and their DriverEntry routines set its entry point in the driver object. For more information about transport Unload routines, see Unloading and Deregistering a TDI Transport Driver.

For more information about the kernel-mode support routines and objects used by TDI drivers, see Summary of Kernel-Mode Support Routines.


Registering a TDI Transport Driver

When TDI is loaded, the configuration registry has entries for each TDI transport driver and kernel-mode client operating on a particular network. Using binding information in the registry, the operating system loads network drivers.

Then, the I/O Manager creates driver objects and calls the DriverEntry routine of each TDI transport driver. The I/O Manager calls each transport driver's DriverEntry routine until all TDI drivers are loaded and registered on the network.

A TDI transport driver or a lower protocol component in its transport stack must register with the NDIS library by calling NdisRegisterProtocol if it will bind itself to an underlying NDIS NIC driver. As NDIS is called by the PnP Manager to initialize each NIC found in the machine, NDIS calls the registered ProtocolBindAdapter functions at the lower edge of the appropriate TDI transport drivers or transport stacks to give each transport the opportunity to bind itself to the appropriate NDIS miniport drivers.

When a TDI transport driver is bound to an NDIS miniport driver or has layered itself above an NDIS protocol driver that has bound itself to such a miniport driver, the TDI driver should be ready to respond to any registered TDI client that submits a request to open any network address that the TDI transport has already registered with TDI on that binding.

Consequently, a PnP-aware TDI transport must not call TdiProviderReady until it has set up its per-device-object and per-address state for each initialization-time call that it makes to TdiRegisterDeviceObject and TdiRegisterNetAddress.

Note that such a TDI transport calls TdiRegisterProvider and TdiProviderReady only once each during system startup. However, the transport can make many run-time calls to the TDI-provided PnP for Windows 2000 and later and power-management functions. For example, TdiRegister/DeregisterDeviceObject, TdiRegister/DeregisterNetAddress, and TdiPnPPowerRequest.

For more information about PnP and power-management support for Windows 2000 and later, see Plug and Play and Power Management. For particulars on how the NDIS library indicates PnP and power events, see Handling PnP Events and Power Management Events in a Protocol Driver.


Unloading and Deregistering a TDI Transport Driver

Before a NIC is removed from the machine, TDI transports for Windows® 2000 and later versions that are bound to that NIC are usually given the opportunity to first notify their clients that the NIC might be disabled and removed. That is, unless a "surprise" removal of a NIC occurs, NDIS calls the ProtocolPnPEvent function at the lower edge of each transport bound to that NIC with the input NetEventQueryRemoveDevice code so that each such TDI transport can forward this notification to its clients by calling TdiPnPPowerRequest.

Such a PnP-aware TDI transport does not actually tear down its binding or make calls to TdiDeregisterNetAddress and TdiDeregisterDeviceObject until NDIS has called the ProtocolUnbindAdapter function at the lower edge of the transport stack. Furthermore, a transport driver cannot be unloaded until it has released all its bindings to all underlying NICs.

However, after a NIC is removed from the machine, the system can unload a TDI transport driver that was either bound directly only to that underlying NIC's driver or layered over an NDIS protocol driver that was bound to that NIC driver. To accomplish this, the system calls the TDI transport's Unload routine.

The transport's Unload routine will be called by the I/O Manager when the Service Controller unloads the driver from memory. A transport driver's Unload routine frees all remaining driver-allocated resources.

A PnP-aware TDI transport driver must make a reciprocal call to TdiDeregisterProvider from its Unload routine. If the TDI driver exports a set of NDIS-defined ProtocolXxx functions, it also must call NdisDeregisterProtocol from its Unload routine.

For more information about standard intermediate driver Unload routines, see Unload Routine Functionality. For more information about PnP and power-management support for Windows 2000 and later versions of the operating system, see Plug and Play and Power Management. For particulars on how the NDIS library indicates PnP and power events, see Handling PnP Events and Power Management Events in a Protocol Driver.


TDI Driver Dispatch Routines

I/O requests are formatted as IRPs either by the I/O Manager or explicitly by a TDI client and submitted to the transport driver by calling IoCallDriver. Completed IRPs are returned to the caller when the transport driver calls IoCompleteRequest or TdiCompleteRequest. Any kernel-mode TDI client can set its IoCompletion routine for an IRP before it calls IoCallDriver.

There are five IRP_MJ_XXX codes used to send I/O requests to TDI transport drivers. These transports handle incoming IRPs in which the MajorFunctionCode is one of the following:

IRP_MJ_CREATE
Opens a named device object created by the transport and, subsequently, opens a transport address, connection endpoint, or control channel in the underlying transport.

This request originates in a client's call to ZwCreateFile.

IRP_MJ_INTERNAL_DEVICE_CONTROL
Specifies kernel-mode client requests (TDI IOCTLs), for which internal transport functions handle operations other than opening and closing file objects.

This request usually originates in a client's call to a TdiBuild Xxx macro followed by its call to IoCallDriver.

IRP_MJ_DEVICE_CONTROL
Specifies user-mode-visible IOCTL requests issued by a transport-dedicated application. Except for any transport-defined "private" IOCTLs, such requests usually are forwarded to the same internal driver functions that handle internal-device control requests.

This request originates in a call by a transport-dedicated user-mode application to DeviceIoControl.

IRP_MJ_CLEANUP
Closes an open address, connection endpoint, or control channel when the NT executive is closing the last handle for the corresponding file object.

This request originates in a client's call to ZwClose.

IRP_MJ_CLOSE
Closes an address, connection endpoint, or control channel if the executive is removing its last reference to the file object handle. When no outstanding file object handles are open, closes a transport-created device object.

This request follows an IRP_MJ_CLEANUP request on the same file object.

The entry points in the TDI driver are one or more Dispatch routines that handle these IRP_MJ_XXX requests. Because a TDI client communicates with the driver only through IRPs, the driver has one or more TdiDispatchXxx routines that determine what operation to carry out. Usually, these TdiDispatchXxx routines pass the client requests to appropriate internal driver functions for further processing.

A TDI transport driver exports all its TdiDispatchXxx entry points by setting them in the driver object passed in to its DriverEntry routine. The I/O Manager calls a TdiDispatchXxx routine whenever a client makes an I/O request. A transport driver can have a separate TdiDispatchXxx to handle each of the possible IRP_MJ_XXX opcodes, a single TdiDispatch routine that processes IRPs with all possible IRP_MJ_XXX opcodes, or a number of TdiDispatchXxx that handle discrete subsets of the IRP_MJ_XXX opcodes.

Since all Dispatch entry points are exported by address in the driver object, not by name, a TDI transport driver writer can name these routines anything. In this TDI documentation, TdiDispatchXxx routines have the following metanames, each describing their basic functionality, to correspond to the preceding IRP_MJ_XXX:

IRP_MJ_CREATE
TdiDispatchCreate
IRP_MJ_DEVICE_INTERNAL_CONTROL
TdiDispatchInternalDeviceControl
IRP_MJ_DEVICE_CONTROL
TdiDispatchDeviceControl
IRP_MJ_CLEANUP
TdiDispatchCleanup
IRP_MJ_CLOSE
TdiDispatchClose


TDI IOCTL Requests

As already mentioned in the preceding topic, kernel-mode clients pass TDI IOCTLs in IRPs to the underlying transport driver with calls to IoCallDriver. These requests are passed with a MajorFunctionCode of IRP_MJ_INTERNAL_DEVICE_CONTROL and MinorFunctionCode that specifies one of the following TDI-defined operations:

TDI_ACCEPT
Allows the local-node client to accept an incoming connection offer from a remote-node peer so that it can send and receive connection-oriented data on the network.
TDI_ACTION
Initiates transport-specific extension operations for an address, a connection endpoint, or a control channel.
TDI_ASSOCIATE_ADDRESS
Associates an open connection endpoint with an open local transport address, which is a prerequisite to establishing an endpoint-to-endpoint connection with a remote-node peer process.
TDI_CONNECT
Initiates a connection offer from one endpoint to another on a remote node.
TDI_DISASSOCIATE_ADDRESS
Disassociates a connection endpoint for an inactive connection from its associated address object.
TDI_DISCONNECT
Terminates an established endpoint-to-endpoint connection for the local-node client or acknowledges connection termination initiated by a remote-node peer.
TDI_LISTEN
Passively listens for an incoming connection offer from a remote-node peer process.
TDI_QUERY_INFORMATION
Queries the underlying TDI transport for a specific type of information.
TDI_RECEIVE
Returns all or part of a TSDU received on an endpoint-to-endpoint connection.
TDI_RECEIVE_DATAGRAM
Returns a datagram TSDU on an open transport address.
TDI_SEND
Sends a normal or expedited TSDU to the remote-node peer on an endpoint-to-endpoint connection.
TDI_SEND_DATAGRAM
Sends a datagram to a specified remote-node address.
TDI_SET_EVENT_HANDLER
Registers a ClientEventXxx handler that the transport will call whenever the corresponding network event occurs.
TDI_SET_INFORMATION
Sets a specific type of information in the underlying transport.


TDI Client Callbacks

Most TDI clients' routines are highly variable and environment-dependent. However, TDI defines a set of callback routines that clients can register with the underlying TDI transport to receive notifications when network events of interest occur. A kernel-mode TDI client can register any of these ClientEventXxx routines if the TDI driver is to notify it of a particular type of network event occurrence. The client can even use such a registered ClientEventXxx handler as an alternative to issuing certain TDI_XXX IOCTL requests to the driver.

Like the TdiDispatchXxx routines described already, the client-supplied event handlers can have any names the client writer chooses. Each ClientEventXxx mentioned here is registered as an entry point passed in a client-supplied IRP submitted to the TdiDispatchInternalDeviceControl routine.

A TDI client can have one or more of the callbacks listed next, registered at the beginning of network operations on an open transport address with the TDI transport driver by issuing successive TDI_SET_EVENT_HANDLER requests, set up with TdiBuildSetEventHandler:

ClientEventConnect
Notifies the client of a connection offer from a remote-node peer process.
ClientEventDisconnect
Notifies the local-node client that its remote-node peer is terminating the endpoint-to-endpoint connection between them.
ClientEventError and/or ClientEventErrorEx
Notifies the client of an error condition in its underlying transport driver, in one of the lower protocol layers of the transport stack, or in a still lower NDIS driver that has made subsequent I/O on the client's open transport address unreliable or even impossible.
ClientEventReceive
Notifies the client that its transport has received normal data from the remote-node peer on an endpoint-to-endpoint connection and makes all or part of the received data available to be copied by the client.
ClientEventChainedReceive
Notifies the client that its transport has received a normal TSDU from the remote-node peer on an endpoint-to-endpoint connection and makes the full TSDU available for consumption by the client.
ClientEventReceiveExpedited
Notifies the client that its transport has received expedited data from the remote-node peer on an endpoint-to-endpoint connection and makes all or part of the received data available to be copied by the client.
ClientEventChainedReceiveExpedited
Notifies the client that its transport has received an expedited TSDU from the remote-node peer on an endpoint-to-endpoint connection and makes the full TSDU available for consumption by the client.
ClientEventReceiveDatagram
Notifies the client that the TDI driver has received a datagram directed to a transport address that the client has opened.
ClientEventChainedReceiveDatagram
Notifies the client that the TDI driver has received a datagram directed to a transport address that the client has opened and makes the full TSDU available for consumption by the client.
ClientEventSendPossible
Notifies the client that the transport, which buffers send data internally, again has buffer space available for sends.

TDI clients for Windows 2000 and later versions can also register a set of ClientPnPXxx callbacks with TDI to receive notifications of dynamic PnP binding-change, net-address-change, and power-state-change events from PnP-aware TDI transports. Like the ClientEventXxx handlers, these client-supplied PnP event handlers can have any names the client writer chooses.

Such a TDI client for Windows 2000 and later has the set of callbacks listed next, which are registered with a call to TdiRegisterPnPHandlers when the client initializes itself:

ClientPnPBindingChange
During system startup, TDI calls this routine to notify the client of all available transport-created named device objects that represent transport-to-NIC bindings, again when each such PnP-aware TDI transport indicates its readiness to carry out network data transfers on its bindings, and again when all possible TDI transport-to-NIC bindings have been established.

During run time, TDI calls this client routine whenever a PnP-aware transport registers another device object to represent a newly established transport-to-NIC binding or deregisters an existing device object while tearing down a binding. TDI also calls this client routine if the end user makes binding-list-order changes in the network connections folder.

ClientPnPAddNetAddress
During system startup, TDI calls this routine to notify the client of all network addresses currently registered with TDI by PnP-aware transports on their established bindings. Subsequently, TDI calls this client whenever a PnP-aware transport registers a new network address (usually for a newly established connection to a remote node) on an established binding.
ClientPnPDelNetAddress
TDI calls this routine to notify the client whenever a PnP-aware TDI transport deregisters an existing network address (usually when breaking a connection to a remote node) on an established binding.
ClientPnPPowerChange
TDI calls this routine to notify the client of proposed NIC removals and of proposed system-power-state changes that could affect that client's ability to transfer data over the network on a particular binding.

A client that registers such a set of ClientPnPXxx handlers with TDI typically maintains dynamic state, usually as one or more internal lists, about all valid network addresses on the bindings of all TDI transports it uses to communicate over the network.


TDI Library Functions and Macros

Windows® 2000 and later versions of the operating system provide a small set of TDI library functions as a kernel-mode dynamic-link library (the tdi.sys export library) with which TDI drivers and kernel-mode clients link themselves. However, most of the system-supplied TdiBuild Xxx called by kernel-mode clients are implemented as macros in the tdikrnl.h header that both clients and transports include.

Any kernel-mode TDI client can use the TdiBuild Xxx macros as needed in preparing the TDI_XXX IOCTL IRPs, already mentioned in TDI IOCTL Requests. After the client has set up such an IRP with a TdiBuild Xxx macro, it submits the request to the underlying TDI driver by passing the IRP to IoCallDriver. Each of these macros fills in the relevant members of the client-provided IRP, except for the Status and Information members, which the underlying transport fills in after processing its client's request. Before using one of TdiBuild Xxx IOCTL macros, a client can call TdiBuildInternalDeviceControlIrp to allocate the IRP if it has not already been allocated by a still higher level network component and given to the client.

A transport driver never uses the TdiBuild Xxx macros. However, a TDI driver can use some of the remaining TDI library routines, such as TdiCompleteRequest and TdiCopyBufferToMdl, for assistance in processing client requests.

TDI library routines and macros include the following:

TdiBuildInternalDeviceControlIrp
Allocates an IRP if the client does not receive an IRP from a higher network layer.
TdiBuildAccept
Sets up an IRP for a client-submitted TDI_ACCEPT request.
TdiBuildAction
Sets up an IRP for a client-submitted TDI_ACTION request.
TdiBuildAssociateAddress
Sets up an IRP for a client-submitted TDI_ASSOCIATE_ADDRESS request.
TdiBuildConnect
Sets up an IRP for a client-submitted TDI_CONNECT request.
TdiBuildDisassociateAddress
Sets up an IRP for a client-submitted TDI_DISASSOCIATE_ADDRESS request.
TdiBuildListen
Sets up an IRP for a client-submitted TDI_LISTEN request.
TdiBuildQueryInformation
Sets up an IRP for a client-submitted TDI_QUERY_INFORMATION request.
TdiBuildReceive
Sets up an IRP for a client-submitted TDI_RECEIVE request.
TdiBuildReceiveDatagram
Sets up an IRP for a client-submitted TDI_RECEIVE_DATAGRAM request.
TdiBuildSend
Sets up an IRP for a client-submitted TDI_SEND request.
TdiBuildSendDatagram
Sets up an IRP for a client-submitted TDI_SEND_DATAGRAM request.
TdiBuildSetEventHandler
Sets up an IRP for a client-submitted TDI_SET_EVENT_HANDLER request.
TdiBuildSetInformation
Sets up an IRP for a client-submitted TDI_SET_INFORMATION request.
TdiBuildNetbiosAddress
Sets up a NetBIOS address for a client.
TdiBuildNetbiosAddressEa
Sets up a buffered NetBIOS address that a client can pass subsequently to ZwCreateFile to open the address.
TdiReturnChainedReceives
Relinquishes control of the buffer that was passed to a ClientEventChainedReceive(Xxx) handler after the client has consumed the received TSDU.
TdiCopyBufferToMdl
Copies a range of buffered data into a destination buffer mapped by a given MDL.

Both clients and transports can use this function.

TdiCopyMdlToBuffer
Copies data from buffers mapped by a given MDL into a caller-supplied destination buffer.

Both clients and transports can use this function.

TdiCopyLookaheadData
Safely copies received data indicated to the transport by a NIC driver, whatever the nature of the memory (including mapped device memory) that the NIC is using.
TdiMapUserRequest
Converts an IRP passed in to a transport's TdiDispatchDeviceControl routine into a TDI_XXX IOCTL IRP if TdiMapUserRequest recognizes the minor function code specified in the input IRP.
TdiCompleteRequest
Completes an IRP with the system-defined network-specific priority boost for a transport driver.
TdiRegisterPnPHandlers
Registers a set of ClientPnPXxx routines with TDI to receive notifications of PnP binding-change, network-address-change, and power-state-change events from underlying PnP-aware TDI transports.
TdiDeregisterPnPHandlers
Removes a set of ClientPnPXxx routines from being notified about subsequent PnP binding-change, network-address-change, and power-state-change events.
TdiRegisterProvider
Registers a PnP-aware transport driver for Windows 2000 and later versions with TDI during system startup.
TdiProviderReady
Indicates a PnP-aware transport driver's readiness to carry out network I/O on one or more newly established transport-to-NIC bindings.
TdiDeregisterProvider
Deregisters a PnP-aware transport driver just before it unloads.
TdiRegisterDeviceObject
Registers a named, transport-created device object that the clients of such a PnP-aware transport can subsequently "open" for network I/O. In effect, such a transport's call to this TDI function notifies all potential clients of this transport that it has just established a new transport-to-NIC binding.
TdiDeregisterDeviceObject
Deregisters a transport-created device object when a PnP-aware transport is tearing down a binding.
TdiRegisterNetAddress
Registers a valid network address that a PnP-aware transport has just created for the local machine or has just obtained when establishing a connection to a remote node on a particular binding. In effect, a PnP-aware transport's call to this TDI function notifies its potential clients that they (or their remote-node peers) can subsequently use this protocol-specific address for network communications.
TdiDeregisterNetAddress
Removes a network address from the list of those valid on a particular PnP-aware transport-to-NIC binding.
TdiPnPPowerRequest
Forwards certain NET_PNP_EVENT-type notifications (by NDIS to the lower edge of the transport stack) to a PnP-aware transport's clients. In effect, a PnP-aware transport's call to this TDI function gives its clients the opportunity to notify their own still higher level clients about binding changes or power-state changes to the underlying NIC on which the transport depends.
TdiPnPPowerComplete
Indicates that a client has completed its processing of a binding-change or power-state-change notification for which it previously returned STATUS_PENDING.
TdiEnumerateAddresses
Returns a list of all valid network addresses to the calling client. (This TDI function is almost never called because it has a severe adverse effect on the caller's performance.)


TDI Operations

This section describes TDI run-time operations. Clients of PnP-aware transports for Windows 2000 and later use the protocol-specific network addresses currently registered with TDI to establish connections across the network when they begin the operations described here. For more information about PnP-aware TDI transports and their clients, see also Transports and Their Clients and Routines, Macros, and Callbacks.

Many TDI run-time operations involve an endpoint-to-endpoint connection between a local-node client and a remote-node client. These TDI operations are connection-oriented and include the following:

  • Opening a local-node connection endpoint
  • Requesting a connection
  • Accepting a connection
  • Sending connection-oriented data
  • Receiving connection-oriented data
  • Disconnecting
  • Closing a local-node connection endpoint

TDI also permits connectionless communications between nodes on a network. This type of operation does not require the local-node client to establish an endpoint-to-endpoint connection with a remote-node client. They are faster but less reliable than connection-oriented communications. TDI connectionless operations include the following:

  • Sending a datagram
  • Receiving a datagram

The remaining TDI operations are common to connection-oriented and connectionless communication, including the following:

  • Opening a local-node transport address represented by a file object
  • Packaging and submitting a request
  • Setting and querying information
  • Receiving error notification
  • Requesting transport-specific actions if the underlying transport supports any extensions to the TDI interface for its clients
  • Closing a previously opened transport address

The following topics describe the main TDI operations, as much as possible in the same order as these operations are likely to occur:

Opening a Transport Address

Opening a Connection Endpoint

Packaging and Submitting IOCTL Requests

Setting and Querying Information

Making an Endpoint-to-Endpoint Connection

Sending and Receiving Connection-Oriented Data

Sending and Receiving Connectionless Data

Connection-Oriented Versus Connectionless Transfers

Requesting Transport-Specific Actions

Receiving Error Notifications

Disconnecting an Endpoint-to-Endpoint Connection

Closing a Connection Endpoint

Closing a Transport Address or Control Channel

For more detailed information about the TDI, transport, and client routines mentioned in this section, see TDI Transport Driver Dispatch Routines and TDI Client Event and PnP Notification Handlers.

For more detailed information about the support routines, such as ZwCreateFile and IoCallDriver, see ZwXxx Routines and I/O Manager Routines.


Opening a Transport Address

The following figure shows how a kernel-mode client opens a transport address in its underlying transport driver.

Opening a Transport Address

After opening a transport-created device object for a binding, a TDI client usually begins communicating with its local-node transport by opening a file object that represents a transport address. To do this, the client calls ZwCreateFile, passing the address specification in the EA (extended attributes) buffer parameter to ZwCreateFile. Within the EA buffer, the client sets the EaName member to the system-defined value TdiTransportAddress followed by an EA value of the TDI-defined type TRANSPORT_ADDRESS, set up by the client to specify the transport-specific address to be opened.

The client can specify that a particular transport address be either sharable with other clients or exclusive to the client when it calls ZwCreateFile. The initial client to successfully open a particular transport address for exclusive use prevents other clients from opening the same address until the original client closes that address.

To do subsequent connectionless communication over the network, the client can specify the underlying transport's broadcast address in the EA buffer, assuming the transport supports broadcast datagrams. Such an address cannot be opened for exclusive use by any client.

The client's call to ZwCreateFile causes the I/O Manager to create a client-process-specific file object to represent the address and to call the TDI transport driver's TdiDispatchCreate routine with an IRP containing the client-supplied parameters to ZwCreateFile. TdiDispatchCreate parses the EA information, and the transport sets up internal state for the open address and for this client if the call succeeds.

After its successful call to ZwCreateFile returns a file handle to the client and the client has obtained a pointer to the file object with ObReferenceObjectByHandle, it is ready to make certain TDI_XXX IOCTL requests to its underlying transport. For example, the client can send or receive datagrams on such an open address.

Usually, a client must first decide whether to register one or more of its ClientEventXxx handlers and whether it will use the open address to communicate with a remote-node peer process, in which case the client also must open a connection endpoint.

If the client wants to receive notifications of various network events, it can register its ClientEventXxx handler for each type of event by submitting one or more TDI_SET_EVENT_HANDLER requests, set up with TdiBuildSetEventHandler, to the underlying transport. For more information about setting up IOCTL requests and submitting them to an underlying transport, see Packaging and Submitting IOCTL Requests.

After the client has registered its ClientEventXxx handlers, if any, on the open transport address, it is ready to make preparations for connection-oriented communication by opening a connection endpoint, as described in Opening a Connection Endpoint, or to begin connectionless communication, as described in Sending and Receiving Connectionless Data.

When it is done with network communications on the opened transport address, the client must close the file object that represents that transport address by calling ZwClose with the handle returned by ZwCreateFile, as described later in Closing a Transport Address or Control Channel.


Opening a Connection Endpoint

The following figure shows how a kernel-mode client opens a connection endpoint in its underlying transport driver.

Opening a Connection Endpoint

If a local-node client requires connection-oriented communication with a remote-node peer process, the local-node client must first open a transport address and then open a connection endpoint in its underlying transport. The client makes two calls to ZwCreateFile, first to open an address and, then, a connection endpoint.

When opening a connection endpoint, the client passes a client-supplied context for the connection in the EA (extended attributes) buffer parameter to ZwCreateFile. Within the EA buffer, the client sets the EaName member to the system-defined value TdiConnectionContext followed by an EA value that is usually the address of a client-allocated context area in which the client will subsequently maintain state about the endpoint-to-endpoint connection to be established.

The client's call to ZwCreateFile causes the I/O Manager to create a client-process-specific file object to represent the connection endpoint and to call the TDI transport driver's TdiDispatchCreate routine with an IRP containing the client-supplied parameters to ZwCreateFile. TdiDispatchCreate parses the EA information, and the transport sets up internal state for the open connection endpoint of this client if the call succeeds.

After its successful call to ZwCreateFile returns a file handle to the client and the client has obtained a pointer to the file object with ObReferenceObjectByHandle, it is ready to make certain TDI_XXX IOCTL requests to the underlying transport to establish an endpoint-to-endpoint connection with a remote-node peer.

First, the client must associate the connection endpoint with its open transport address by submitting a TDI_ASSOCIATE_ADDRESS request, set up with TdiBuildAssociateAddress, to its underlying transport.

For more information about setting up TDI_XXX IOCTL IRPs, see Packaging and Submitting IOCTL Requests, next. For more information about how to establish an endpoint-to-endpoint connection, see Making an Endpoint-to-Endpoint Connection.

When the endpoint-to-endpoint connection has been disconnected and the client no longer will use any connection-oriented communications, the client must close the connection endpoint by passing the file handle that was returned by ZwCreateFile to ZwClose, as described later in Closing a Connection Endpoint.


Packaging and Submitting IOCTL Requests

The following figure shows how TDI clients set up and submit TDI_XXX IOCTL requests to their underlying TDI transports.

Preparing an IOCTL IRP and Making a Request

A kernel-mode client prepares its own IOCTL IRPs for communication with the underlying transport driver, using one of the TdiBuild Xxx macros summarized in TDI Routines, Macros, and Callbacks. The client can either obtain an IRP from a still higher layer of the network or call TdiBuildInternalDeviceControlIrp to allocate an IRP for itself.

A subsequent call to a TdiBuild Xxx macro sets the appropriate TDI_XXX code in the MinorFunctionCode of the IRP and sets the MajorFunctionCode to IRP_MJ_INTERNAL_DEVICE_CONTROL for the underlying transport driver, as well as setting the client-supplied and IOCTL-specific parameters to each TdiBuild Xxx macro in the IRP. For example, to set up the TDI_ASSOCIATE_ADDRESS request, mentioned in the preceding section, the client passes both a pointer to the file object that represents its connection endpoint and the handle to the file object that represents its transport address when it uses TdiBuildAccept.

When the IRP is set up, the client calls IoCallDriver to submit its IOCTL request to its underlying transport. The transport's TdiDispatchInternalDeviceControl routine receives the client-supplied IRP from IoCallDriver and usually forwards the client's request to an internal driver function for further processing. The transport completes the requested operation, sets the I/O status block in the IRP with the results of the operation, and calls TdiCompleteRequest (or IoCompleteRequest) with the IRP when the client's request has been satisfied.

If the client supplied the entry point of its IoCompletion routine when it called the TdiBuild Xxx macro, the client's IoCompletion routine is called when the transport completes the requested operation and calls Io/TdiCompleteRequest with the client-supplied TDI_XXX IOCTL request.


Setting and Querying Information

The following figure shows how a TDI client can make queries about the features of its underlying transport or request its underlying transport to set its state data to client-specified values.

Setting and Querying Information in the Transport

A TDI client can query certain transport driver information, such as connection-status information, activity on a particular transport address, transport-specific limits on datagram size and number, driver statistics, and internal send/receive buffer sizes if the transport buffers data internally. A client also can set some state information in the underlying transport, although it cannot override the underlying transport-determined values for certain size limits by issuing set-information requests.

If a client wants to query information concerning an open transport address or a connection endpoint, it submits a TDI_QUERY_INFORMATION request, set up with TdiBuildQueryInformation, to the underlying transport. When it uses this macro, the client passes pointers to the file object that represents the address or connection endpoint and to a client-supplied buffer in which the transport returns the requested information.

To set transport information, the client issues a TDI_SET_INFORMATION request, set up with TdiBuildSetInformation.

For each of these operations, the client also passes a system-defined TDI_QUERY_XXX value as the QType or SType parameter to the TdiBuild..Information macros to discriminate among the types of information that can be queried and set.

To query or set information that does not specifically concern an address or a connection endpoint, a client first must open a control channel in the TDI driver before submitting its query/set-information requests. For example, a client querying information about the underlying transport's broadcast address for connectionless-data transmission or the transport's current statistics uses a control channel.

To open a control channel, the client calls ZwCreateFile with a NULL EaBuffer pointer. The client's call to ZwCreateFile causes the I/O Manager to create a client-process-specific file object to represent the control channel and to call its underlying transport's TdiDispatchCreate routine with an IRP containing the client-supplied parameters to ZwCreateFile. TdiDispatchCreate notes the absence of EA information, and the transport sets up internal state for the open control channel and for this client if the call succeeds.

As an alternative for opening a file object that represents a control channel, the client can call IoGetDeviceObjectPointer, which returns pointers to the named device object and corresponding file object.

After its successful call to ZwCreateFile returns a file handle to the client and the client has obtained a pointer to the file object with ObReferenceObjectByHandle, it is ready to make certain types of TDI_QUERY_INFORMATION or TDI_QUERY_SET_INFORMATION IOCTL requests to its underlying transport.

When its query- and/or set-information operations are complete, the client must close the open control channel by passing the file handle that was returned by ZwCreateFile to ZwClose or passing the file object pointer that was returned by IoGetDeviceObjectPointer to ObDereferenceObject, as described later in Closing a Transport Address or Control Channel.


Making an Endpoint-to-Endpoint Connection

TDI clients on separate nodes of the network and their respective transports cooperate to establish an endpoint-to-endpoint connection between them. Before such a connection can be attempted, each client on its own node must do the following:

  1. Open a transport address, as already described in Opening a Transport Address.
  2. Open a connection endpoint, as already described in Opening a Connection Endpoint.
  3. Associate its open connection with the open address by submitting a TDI_ASSOCIATE_ADDRESS IOCTL request to its underlying transport, as mentioned in Opening a Connection Endpoint and described in Packaging and Submitting IOCTL Requests.

Then, one of the clients makes a connection offer to the other, while the other usually listens (passively) for the connection offer to come in.

Either client also might have registered its ClientEventConnect handler with its underlying transport (see Opening a Transport Address). The transport driver calls ClientEventConnect when any connection offer directed to its client's open transport address comes in from a remote node.

Requesting a Connection to a Remote Node

The following figure shows how a local-node TDI client initiates a connection offer to a remote-node peer process.

Requesting a Connection

The local-node client makes a connection offer to a remote-node peer process by submitting a TDI_CONNECT request, set up with TdiBuildConnect, to its underlying transport.

The local-node transport determines the client-specified target remote-node address from its client's connect request and transmits the connection offer to the corresponding remote-node transport.

The remote-node transport notifies its client of the incoming connection offer, either by satisfying a TDI_LISTEN request previously submitted by its client or by calling the previously registered ClientEventConnect handler.

The local-node transport fails the connect IRP if the remote-node client is not listening or if the remote-node transport does not respond. The remote-node client can accept or reject the offered connection if both transports support delayed-connection acceptance, as described next.

Accepting a Connection Offer from a Remote Node

The following figure shows how a local-node client listens for a connection offer from a remote-node peer process.

Accepting a Connection (Listen Operation)

To establish an endpoint-to-endpoint connection, one client makes a connection offer, and the other indicates to its underlying transport that it is waiting for a connection offer to occur.

A local-node client can passively listen for such an incoming connection offer by submitting a TDI_LISTEN request, set up with TdiBuildListen, to its underlying transport. The client can specify the remote-node transport address from which an acceptable offer can occur when it sets up the listen IRP. If the transports support delayed-connection acceptances, the client can direct the transport to either accept an offer from a particular remote-node address immediately or allow the client to inspect the offer and decide whether to accept it.

When the transport receives a TDI_LISTEN request, it monitors connection offers coming from remote nodes that are directed to the transport address opened by the client. When it receives such a connection offer from an acceptable remote-node address, the transport copies information transmitted with the offer into a buffer the local-node client supplied with its TDI_LISTEN request and completes the IRP back to the listening client.

If the client directed the transport to accept the incoming connection offer immediately, completion of the listen request occurs as the transport notifies the remote-node transport that an endpoint-to-endpoint connection has been established with the remote-node client. In effect, the local-node client has made an endpoint-to-endpoint connection with its remote-node peer even before it "knows" that its listen IRP has been completed, and the local-node client can receive data on that endpoint-to-endpoint connection at once. Otherwise, the transport's completion of the listen request notifies the local-node client of the offer to connect, and the client either accepts or rejects the request by issuing a TDI_ACCEPT or TDI_DISCONNECT request, respectively. The local-node client uses TdiBuildAccept or TdiBuildDisconnect to set up the IRP it submits to its underlying transport for a delayed-connection acceptance operation.

Accepting a connection is even simpler if the local-node client is using event handling to communicate with the underlying TDI transport driver. When its transport receives a connection offer from a remote-node client that is directed to the open transport address of the local-node client, the transport calls the registered ClientEventConnect handler of the local-node client, passing in the transport address of the offering client and any connect data the transport received with the connection offer. ClientEventConnect then accepts or rejects the connection offer immediately.


Sending and Receiving Connection-Oriented Data

TDI clients on separate nodes of the network must establish an endpoint-to-endpoint connection between them to send and receive connection-oriented data. Before either client sends data to the other, each client on its own node must do the following:

  1. Open a transport address, as already described in Opening a Transport Address.
  2. Open a connection endpoint, as already described in Opening a Connection Endpoint.
  3. Associate its open connection with the open address by submitting a TDI_ASSOCIATE_ADDRESS IOCTL request to its underlying transport, as mentioned in Opening a Connection Endpoint and described in Packaging and Submitting IOCTL Requests.
  4. Establish the endpoint-to-endpoint connection between them, one by making a connection offer and the other by accepting that offer, as described in Making an Endpoint-to-Endpoint Connection.

In fact, the client that accepts a connection offer can receive data from its remote-node peer as soon as the local-node transport sends a connection-acceptance frame to the remote-node transport, which can occur before the accepting client's TDI_LISTEN IRP has been fully completed back to that client.

After an endpoint-to-endpoint connection has been made by the underlying transports, either client can send data to the other across the network.

Sending Data on an Endpoint-to-Endpoint Connection

The following figure shows how a kernel-mode client sends data on an endpoint-to-endpoint connection through its underlying local-node transport to a remote-node peer.

Sending Data to a Remote-Node Peer

A local-node TDI client issues a send request to transmit data from its connection endpoint to the remote-node connection endpoint. To do this, the local-node client submits a TDI_SEND IOCTL request to its transport. This IRP, which the client sets up with TdiBuildSend, contains a pointer to a client-supplied buffer containing a stream-oriented or message-oriented TSDU. This buffer can be any size up to the maximum the TDI transport driver allows. If the transport supports expedited sends, the client can request that the TSDU be transmitted as expedited data, ahead of any preceding normal sends it has already submitted that are currently pending in its underlying transport. If the transport driver supports internal buffering, its client can issue a non-blocking send.

The client's call to IoCallDriver with the TDI_SEND IRP forwards the IRP to the underlying transport's TdiDispatchInternalDeviceControl routine. This routine checks the MinorFunction code in the transport's I/O stack location of the IRP and usually calls a send-specific internal driver function to process the IRP further. For send requests, the internal driver function usually queues the IRP if the client has already submitted other send requests that have not yet been transmitted over the network to the remote node. The transport always queues requests to send expedited data ahead of requests to send normal TSDUs to the client's remote-node peer. Whether normal or expedited, the queuing transport always transmits client-requested sends over the network in FIFO order. The transport either copies the client-supplied data into its internal buffers or sends the specified data on the network before it completes each client-submitted TDI_SEND IRP.

If the underlying transport has failed a non-blocking send request due to insufficient internal buffer space in the transport, the driver calls its client's registered ClientEventSendPossible handler when the transport again has available buffer space for sends. Then, ClientEventSendPossible can resubmit the TDI_SEND request that the transport previously failed.

Receiving Data on an Endpoint-to-Endpoint Connection

The following figure shows how a kernel-mode client receives data on an endpoint-to-endpoint connection through its local-node transport from its remote-node peer.

Receiving Data from a Remote-Node Peer

A local-node client can receive a TSDU, either normal or expedited, on a connection by making a TDI_RECEIVE request to the underlying transport. This IRP, which the client sets up with TdiBuildReceive, contains a pointer to a client-supplied buffer into which the transport copies all or part of the TSDU data it received from the client's remote-node peer. This buffer can be any size up to the maximum the TDI transport driver allows.

The client's call to IoCallDriver with the TDI_RECEIVE IRP forwards the IRP to the underlying transport's TdiDispatchInternalDeviceControl routine. This routine checks the MinorFunction code in the transport's I/O stack location of the IRP and usually calls a receive-specific internal driver function to process the IRP further. The internal driver function transfers received data into the client-supplied buffer until it is full or until the received TSDU data is exhausted.

However, expedited data takes precedence over normal data during receive operations. If an expedited TSDU comes in from the remote node while the transport is processing a client-submitted receive request for normal data, the transport completes the IRP back to its client with whatever normal TSDU data has already been transferred into the client-supplied buffer. Then, the transport processes the expedited receive to completion, and the client must issue another TDI_RECEIVE request to obtain the remainder of the normal TSDU.

A client can also receive data from its remote-node peer as an event notification from the underlying TDI transport driver. For these notifications, the driver removes the transport layer header from the TSDU that it receives from the remote node and calls the client's registered ClientEventReceive, ClientEventChainedReceive, ClientEventReceiveExpedited, or ClientEventChainedReceiveExpedited handler. The client's event handler can then copy as much of the data as possible. If ClientEventReceive or ClientEventReceiveExpedited does not receive all the data, it can do one of the following:

  • Return a not-accepted status immediately, effectively telling the transport that the received TSDU is not of interest to the client.
  • Make another TDI_RECEIVE receive request to obtain the remainder of the TSDU data.
  • Rely on subsequent driver receive-event notifications to obtain the remainder of the data.

The ClientEventChainedReceive and ClientEventChainedReceiveExpedited handlers are always given read-only access to a full TSDU by the underlying transport. Consequently, these routines have no need to issue a sequence of TDI_RECEIVE requests to the underlying transport or to process partial indications of received TSDUs. However, the client is responsible for calling TdiReturnChainedReceives promptly to return the resources associated with such an indication to the NDIS miniport driver that originally allocated them.

For more information about registering ClientEventXxx handlers, see Opening a Transport Address.


Sending and Receiving Connectionless Data

A kernel-mode client can engage in connectionless communication by sending data over the network as soon as it has successfully opened a transport address in the underlying TDI transport.

To receive data in this manner, the client must register its ClientEventReceiveDatagram and, possibly, ClientEventChainedReceiveDatagram handlers with the underlying transport or issue an explicit TDI_RECEIVE_DATAGRAM request to the underlying transport.

For more information about opening a transport address and registering an event handler on that address, see Opening a Transport Address.

Sending a Datagram

The following figure shows how a TDI client sends a datagram to a remote-node address.

Sending a Datagram

As this figure shows, sending a datagram is similar to sending connection-oriented data. However, the local-node client submits a TDI_SEND_DATAGRAM request to its underlying transport on an open transport address, instead of a send request on an established endpoint-to-endpoint connection as already described in Sending and Receiving Connectino-Oriented Data.

A TDI_SEND_DATAGRAM IRP requests the underlying transport to transmit a client-supplied datagram to an unknown number of remote-node clients at a particular remote-node transport address.

The local-node client with an open transport address can use TdiBuildSendDatagram to set up such a request. Along with the target remote-node address, the client provides buffered data that can be any size up to the maximum the TDI transport driver allows for datagram sends. The client can determine this limit by querying the underlying transport, as described already in Setting and Querying Information.

Receiving a Datagram

The following figure shows how a kernel-mode client receives a datagram through its underlying transport from a remote node.

Receiving a Datagram

As this figure shows, receiving a datagram is similar to receiving connection-oriented data. However, the local-node client submits a TDI_RECEIVE_DATAGRAM request to its underlying transport on its open transport address, instead of a receive request on an established endpoint-to-endpoint connection as already described in Sending and Receiving Connection-Oriented Data.

However, the client can receive a datagram sent by any remote-node client that specifies the local client's open transport address as the destination of the datagram. Other local clients that have opened the same transport address can also receive the same datagram.

A TDI_RECEIVE_DATAGRAM IRP requests the underlying transport to return a datagram from any remote-node client that has sent one to the local-node client's open transport address. The local-node client can use TdiBuildReceiveDatagram to set up such a request. Along with a pointer to the file object that represents its open transport address, the client provides a buffer that can be any size up to the maximum the TDI transport driver allows for received datagrams. Because TDI transports never fragment datagrams, the local-node client usually issues one receive-datagram request to accept one datagram.

When it satisfies such a request, the transport driver copies a received datagram into the client-supplied buffer and returns the transport address of the remote-node client that sent the datagram with the completed IRP. If the received datagram is too large for the buffer, the transport returns as much data as possible and discards the remaining data.

A client can also receive a datagram from a remote node as an event notification by the underlying TDI transport driver. For these notifications, the transport removes its header from the TSDU that it receives from the remote node and calls the client's registered ClientEventReceiveDatagram, or possibly ClientEventChainedReceiveDatagram, handler. ClientEventReceiveDatagram can do one of the following:

  • Return a not-accepted status immediately, effectively telling the transport that the TSDU is not of interest to the client.
  • Copy as much data as possible into an internal buffer and set up a TDI_RECEIVE_DATAGRAM request for the remainder of the TSDU if the transport provided only part of the data and return control.
  • Copy all of the TSDU into an internal buffer and return control.

Non-buffering transport drivers can discard data after a receive-datagram event indication if their clients do not copy the data or return an IRP. Buffering transport drivers retain a certain amount of datagram information that their clients can retrieve later by making explicit TDI_RECEIVE_DATAGRAM requests.

The ClientEventChainedReceiveDatagram handler is always given read-only access to a full TSDU by the underlying transport. Consequently, this routine has no need to issue a TDI_RECEIVE_DATAGRAM request to the underlying transport or to process partial indications of received TSDUs. However, the client is responsible for calling TdiReturnChainedReceives promptly to return the resources associated with such an indication to the NDIS miniport driver that originally allocated them.

For more information about registering ClientEventXxx handlers, see Opening a Transport Address.


Connection-Oriented Versus Connectionless Transfers

TDI provides connection-oriented services at the transport layer to provide the highest quality of service at the lowest cost. Depending on the specific driver protocol, this can involve packetizing of client data, sequencing, acknowledgment, retransmission, flow-control, and error recovery.

TDI also provides connectionless services for datagrams. However, these services are lightweight: they do not provide error-free delivery or flow control. The transport layer generally does not segment or reassemble datagrams. Delivery of connectionless data is best-effort only for TDI transports.

A datagram send is an inherently unreliable form of network communication. The sending client has no way of determining how many or which remote-node clients have opened the target remote-node address or whether the remote-node transport is currently accepting datagrams. Furthermore, the local-node TDI driver can lose or duplicate a datagram at the discretion of the transport driver writer. By contrast, the local-node transport is responsible for retrying sends on an established endpoint-to-endpoint connection until the transmitted data is accepted on the remote node and acknowledged by the remote-node transport while the endpoint-to-endpoint connection is active.

Like a datagram-send, a datagram receive operation can be unreliable. That is, the local-node TDI driver can lose or duplicate a received datagram at the discretion of the transport driver writer. By contrast, the local-node transport is responsible for delivering a receive on an established endpoint-to-endpoint connection until the transmitted data is accepted (or rejected) by its client and acknowledged to the remote-node transport while the endpoint-to-endpoint connection is active.

An endpoint-to-endpoint connection remains active until it is broken by a disconnect operation, as described later in Disconnecting an Endpoint-to-Endpoint Connection or until the underlying transport's time-out logic determines that the remote node is failing to respond.


Requesting Transport-Specific Actions

The following figure shows how a TDI client can make transport-specific action requests to the underlying TDI driver if that transport defines such extensions to TDI.

Requesting Transport-Specific Extensions

A TDI client can send special or proprietary extension requests to a TDI transport driver that defines a set of transport-specific action codes for these operations. These extensions, which can concern an open address, an open connection endpoint, or an open control channel, apply only to the calling client and not to any other TDI transport clients or drivers.

To request such a transport-defined action operation, the client first must open the address, connection endpoint, or control channel, as already described in Opening a Transport Address, Opening a Connection Endpoint, or Setting and Querying Information, respectively. Then, the client can use TdiBuildAction to set up a TDI_ACTION request with a client-supplied buffer containing the transport-defined action code and corresponding action parameter block for the requested operation.


Receiving Error Notifications

In response to client-submitted IRPs, the transport driver notifies a TDI client of error conditions in the status codes that it returns. While this provides a client with request-specific errors, it would be difficult for the client to maintain a count of failed IRPs and apply internal logic to determine whether the underlying drivers are in a state that renders the client's subsequent network I/O operations unreliable.

To receive a notification of unexpected error conditions in an underlying driver or in the underlying physical medium, the client can register its ClientEventError or ClientEventErrorEx handler with its underlying transport, as already described in Opening a Transport Address. Then, if the transport itself or any lower driver that the transport depends on to carry out client communications over the network encounters such an error condition, the transport calls ClientEventError(Ex). This call notifies its client that network I/O on the client's open transport address is no longer reliable (or, sometimes, even possible). Then, the client can notify its own higher level clients of the network failure and clean up all TDI-client-allocated resources for pending operations on the affected open transport address.


Disconnecting an Endpoint-to-Endpoint Connection

The following figure shows how TDI clients release an endpoint-to-endpoint connection.

Disconnecting an Endpoint-To-Endpoint Connection

Disconnection behavior is transport-specific in nature. When a connection-oriented TDI client initiates a disconnect between nodes, both nodes might need to participate in the disconnection operation. That is, when one client initiates a disconnect, the remote-node client possibly must respond to it.

During a disconnect operation, the TDI transport driver usually refuses incoming requests on the open connection endpoint and stops all activity at the specified connection endpoint unless both transports support controlled disconnects and the initiating client requests one.

As the preceding figure shows, one client on an endpoint-to-endpoint connection can initiate a disconnection operation by submitting a TDI_DISCONNECT request, set up with TdiBuildDisconnect, to its underlying transport. When that transport finishes processing the initiating client's request, it notifies the remote-node transport driver that a disconnection is in progress, and this transport begins returning an appropriate status code for client-submitted I/O requests on the endpoint-to-endpoint connection.

If the responding client registered its ClientEventDisconnect handler, the TDI transport driver notifies the client when the disconnect occurs by calling this handler. Then, ClientEventDisconnect acknowledges the disconnection by making a TDI_DISCONNECT request to its underlying transport. This notification allows the responding client to clean up client-allocated state for the endpoint-to-endpoint connection promptly.

However, a disconnection operation does not close either client's open connection endpoints or transport addresses. After TDI_DISCONNECT requests have been satisfied, both clients can reuse the file objects representing these open resources in their underlying transports. For example, either client might make a subsequent connection offer to another remote node on the network, as already described in Making an Endpoint-to-Endpoint Connection. Until each client closes the file objects representing its respective connection endpoint and the associated transport address as described in Closing a Connection Endpoint and Closing a Transport Address or Control Channel, respectively, these resources remain allocated to the client and available for client-submitted IOCTL requests to the underlying transport.


Closing a Connection Endpoint

The following figure shows how a kernel-mode client closes a connection endpoint.

Closing a Local-Node Connection Endpoint

After an endpoint-to-endpoint connection has been disconnected, as already described in Disconnecting an Endpoint-to-Endpoint Connection, a client can close the connection endpoint.

When a client no longer has any use for an open connection endpoint, it must close that connection endpoint as follows:

  • Pass the file object pointer returned by ObReferenceObjectByHandle to ObDereferenceObject.
  • Pass the file handle that was returned by ZwCreateFile when the connection endpoint was opened to ZwClose.

Then, the I/O Manager submits IRPs to the transport's TdiDispatchCleanup and, subsequently, TdiDispatchClose routines.

These transport routines immediately close the connection endpoint and free all associated transport driver resources. TdiDispatchCleanup also terminates any active connection involved with the endpoint by sending a disconnect notification to the corresponding remote-node transport.

As the preceding sentence implies, it is unnecessary for a TDI client to disassociate the connection endpoint from its associated transport address before making a close-connection-endpoint request. If necessary, the underlying transport driver simulates the effects of a disassociation.

However, a client can explicitly disassociate a connection endpoint from an open transport address before closing the connection endpoint by making a TDI_DISSOCIATE_ADDRESS request to the transport, set up with TdiBuildDisassociateAddress.

For example, a client might make a disassociate-address request and reassociate the open connection endpoint with another open transport address.


Closing a Transport Address or Control Channel

After closing any associated connections, a TDI client is ready to close an open transport address.

When a client no longer has any use for an open transport address or control channel, it must release that object as follows:

  • Pass the file object pointer returned by ObReferenceObjectByHandle to ObDereferenceObject.
  • Pass the file handle that was returned by ZwCreateFile when the connection endpoint was opened to ZwClose.

In a similar manner, a TDI client also can close any control channel it has opened in its underlying transport driver.

If the client opened the file object representing a control channel with a call to IoGetDeviceObjectPointer, it must pass the returned file object pointer to ObDereferenceObject to release the file object.

Then, the I/O Manager submits IRPs to the transport's TdiDispatchCleanup and TdiDispatchClose routines.

These transport routines immediately close the transport address or control channel and free all associated client-specific transport driver resources. For example, TdiDispatchCleanup cancels any pending requests on a transport address that is being closed, deregisters any ClientEventXxx handlers on that address, and cleans up client-specific state for that address. If this client has released the last file handle for a particular transport address, the transport also releases internal state for that transport address.

After ZwClose returns to the client, it cannot submit a request to the underlying transport for the transport address or control channel it previously had open. The client-specific file object representing that address or control channel no longer exists.


Connection-Oriented NDIS

The Network Driver Interface Specification (NDIS) provides support for connection-oriented media such as Asynchronous Transfer Mode (ATM) and ISDN.

The following sections describe connection-oriented NDIS:

Connection-Oriented Environment

Using AFs, VCs, SAPs, and Parties

Quality of Service

How an MCM Driver Differs from a Call Manager

Connection-Oriented Timing Features

Connection-Oriented Operations


Connection-Oriented Environment

NDIS supports the following connection-oriented drivers:

  • Connection-oriented client
  • Call manager
  • Integrated miniport call manager (MCM) driver
  • Connection-oriented miniport driver

The following figure shows a configuration of connection-oriented clients, a call manager, and a miniport driver.

Connection-Oriented Environment with Call Manager

The following figure shows a configuration of connection-oriented clients and an integrated MCM driver.

Connection-Oriented Environment with Integrated MCM Driver

A connection-oriented minipor drivert controls one or more network interface cards (NICs) and provides an interface between connection-oriented protocols (connection-oriented clients and call managers) and the NIC hardware. For a summary of connection-oriented operations performed by a connection-oriented miniport driver, see Connection-Oriented Operations Performed by Miniport Drivers.

A call manager is an NDIS protocol driver that provides call setup and tear-down services for connection-oriented clients. A call manager has the following characteristics:

  • Uses the send and receive capabilities of a connection-oriented miniport driver to exchange signaling messages with network entities, such as network switches or remote peers.
  • Supports one or more signaling protocols, such as ATM UNI 3.1, as specified by the ATM Forum. For a summary of connection-oriented operations performed by a call manager, see Connection-Oriented Operations Performed by Call Managers.

An integrated MCM driver is a connection-oriented miniport driver that also provides call manager services to connection-oriented clients. An MCM driver has the following characteristics:

  • Provides the same connection-oriented services to clients as a call manager that is paired with a connection-oriented miniport driver; however, the call manager-to-miniport driver interface is internal to the driver and therefore opaque to NDIS.
  • Multiple call managers and MCM drivers can coexist in the same environment.
  • Each call manager or MCM driver can support multiple signaling protocols.

For a detailed comparison, see How an MCM Driver Differs from a Call Manager.

A connection-oriented client has the following characteristics:

  • Uses the call setup and tear-down services of a call manager or MCM driver. A connection-oriented client also
  • Uses the send and receive capabilities of a connection-oriented miniport driver or an MCM driver to send and receive data.
  • At its upper edge can provide its own network and transport-layer services to a higher-layer application
  • At its lower edge uses the services of a call manager and a connection-oriented miniport driver, or it uses the services of an MCM driver
  • Can be an adaptation layer, such as IP/ATM and LAN Emulation (LANE), that resides between a legacy protocol and connection-oriented NDIS.

    Both IP/ATM and LAN Emulation (LANE) use call management services to establish underlying connections, but hide the connection-oriented nature of this interface from the connectionless protocols above it.

Note The definition of a connection-oriented client's upper-edge interface is beyond the scope of NDIS documentation. If a client serves as an adaptation layer, its upper-edge interface is defined by the protocol that it adapts to connection-oriented NDIS.

For a summary of connection-oriented operations performed by a connection-oriented client, see Connection-Oriented Operations Performed by Clients .


Using AFs, VCs, SAPs, and Parties

Connection-oriented drivers create and use the following:

Address Families

Virtual Connections

Service Access Points

Parties

When a connection-oriented driver registers an AF or creates a VC, SAP, or party, it passes a pointer to its local context area for that entity to NDIS. NDIS then returns to the driver (as well as to other appropriate connection-oriented drivers) a handle that represents the newly registered AF or the newly created VC, SAP, or party.


Address Families

An address family (AF) represents an association between either of the following sets of drivers:

  • A connection-oriented client, a call manager, and the underlying connection-oriented miniport driver, or
  • A connection-oriented client and an MCM driver for a specific signaling protocol

An address family also specifies a particular signaling protocol, such as ATM UNI 3.1.

A call manager or MCM driver advertises its call manager services for a specific signaling protocol by registering the address family with NDIS. NDIS then notifies each client on the binding of the newly registered address family. Before it can use the call manager services provided by a call manager or MCM driver, a connection-oriented client must open the address family with the call manager or MCM driver that advertised it.

For more information on operations on address families, see Registering and Opening an Address Family and Closing an Address Family.


Virtual Connections

On a local system, a virtual connection (VC) is an endpoint (or association) that can host a single call between a client, call manager or MCM driver, and a miniport driver. On the network, a VC refers to a connection between two communicating endpoints, such as two connection-oriented clients.

Many VCs can be active on a NIC at the same time, allowing the NIC to simultaneously service many calls. Each connection can be to different endpoints on different computers.

VCs on a network vary in the type of service that they provide to clients. For example, a VC can provide unidirectional or bidirectional service. Quality of Service (QoS) parameters for each direction can guarantee specific performance thresholds, such as bandwidth and latency. Depending on the signaling protocol, the QoS for a VC may be negotiable. For more information on NDIS support of QoS, see Quality of Service Service.

A VC on a network can be a switched VC (SVC) or a permanent VC (PVC):

  • An SVC is created as needed for a particular call. For example, a connection-oriented client initiates the creation of a VC for an outgoing call that it is going to make. Similarly, a call manager or MCM driver initiates the creation of a VC for an incoming call that it is going to indicate to a connection-oriented client. The call manager or MCM driver must communicate and sometimes negotiate the parameters for the VC with the remote party.
  • A permanent VC is manually created and eventually deleted by an operator using a configuration utility, which is not supplied in NDIS. A client that monitors such manual creation and deletion of PVCs can use OID_CO_ADD_PVC and OID_CO_DELETE_PVC to request that a call manager or MCM driver add or delete a PVC to or from its list of configured PVCs. The QoS for a PVC is configured by the operator and is not negotiable over the network.

In NDIS, a VC consists of resources allocated by a miniport driver to maintain state information about a VC on a network. These resources could include, but are not limited to, memory buffers, events, and data structures. The miniport driver is requested to create such a context for a VC by a connection-oriented client for an outgoing call or a call manager for an incoming call. For more information on the creation of VCs, see Creating a VC.

Before a created VC can be used for data transmission, it must be activated by a call manager or MCM driver. To activate a VC, a miniport driver or MCM driver sets up resources for the VC and communicates with its NIC as necessary to prepare the NIC to receive or transmit data on the VC. For more information on VC activation, see Activating a VC.

When tearing down a call, a call manager or MCM driver deactivates the VC used for the call. For more information on VC deactivation, see Deactivating a VC.

After a call is torn down, the creator of the VC (a connection-oriented client, call manager, or MCM driver) can either initiate the deletion of the VC or use the VC for another call. For more information on VC deletion, see Deleting a VC.


Service Access Points

A service access point (SAP) identifies the characteristics of incoming calls of interest to a connection-oriented client. By registering a SAP with a call manager or MCM driver, a client indicates that the call manager or MCM driver should notify the client of all incoming calls addressed to that SAP.

A client does not always register a SAP, for example, if it does not handle incoming calls. A client can register multiple SAPs with a call manager or MCM driver.

For more information, see Registering a SAP and Deregistering a SAP.


Parties

A party represents one of possibly many leaves of a point-to-multipoint connection. When making an outgoing call, a connection-oriented client can specify a party. This makes the call a multipoint call, with the client acting as the root of the call and the remote party as a leaf. The client can then request that additional remote parties be added as leaf nodes to the call.

For more information on adding parties to a point-to-multipoint call, see Adding a Party to a Multipoint Call. For information on deleting parties from a point-to-multipoint call, see Dropping a Party from a Multipoint Call.


Quality of Service

The originator of a call on an SVC can specify Quality of Service (QoS) parameters for the call that specify performance parameters for the call. Depending on the signaling protocol being used, a call manager or MCM driver setting up an outgoing or incoming call can negotiate the QoS with a network entity such as a network switch or a remote client. If allowed by the signaling protocol, a connection-oriented client might also request a change of QoS when determining whether to accept an incoming call.

The QoS parameters for a call are specified as call parameters in a CO_CALL_PARAMETERS structure. CO_CALL_PARAMETERS points to two other structures:

  • CO_CALL_MANAGER_PARAMETERS, which specifies call manager parameters used by a call manager or MCM driver to set up a call
  • CO_MEDIA_PARAMETERS, which specifies media parameters used by a miniport driver or MCM driver to activate a VC

Both CO_CALL_MANAGER_PARAMETERS and CO_MEDIA_PARAMETERS contain generic parameters (flags) that apply to all drivers that use the parameters. Each of these structures also points to a CO_SPECIFIC_PARAMETERS structure that specifies call manager-specific parameters (when pointed to by a CO_CALL_MANAGER_PARAMETERS structure) or media-specific parameters (when pointed to by a CO_MEDIA_PARAMETERS structure).

For more information on QoS operations, see Client-Initiated Request to Change Call Parameters and Incoming Request to Change Call Parameters.


How an MCM Driver Differs from a Call Manager

An integrated MCM driver is a connection-oriented miniport driver that also provides call manager services to connection-oriented clients. As such, an MCM driver performs all the connection-oriented functions of both a connection-oriented miniport driver and a call manager. Like all miniport drivers, MCM drivers must use Ndis Xxx calls to communicate with the underlying NIC hardware.

An MCM driver differs from a call manager in two major ways:

  • A call manager is an NDIS connection-oriented protocol driver with added call manager functionality. An MCM driver is an NDIS connection-oriented miniport driver with added call manager functionality.
  • The interface between a call manager and a connection-oriented miniport driver is fully exposed to NDIS—that is, all communication between the call manager and the miniport driver passes through NDIS. Except for the activation and deactivation of client VCs (VCs used for transmitting outgoing and/or incoming client data), the interface between the call manager part of an MCM driver and the miniport driver part of an MCM driver is opaque to NDIS. The activation and deactivation of client VCs must be accomplished through NDIS because NDIS keeps track of client VCs.

The differences between an MCM driver and a call manager are further described in the following sections:

Differences in Initialization

Differences in Calls to NdisXxx Functions

Differences in Virtual Connections


Differences in Initialization

A call manager is an NDIS protocol; therefore, it follows the initialization sequence for a connection-oriented protocol, but with one additional step. in its ProtocolBindAdapter handler, immediately after completing the initialization steps for a connection-oriented protocol, a call manager must register an address family by calling NdisCmRegisterAddressFamily. The call to NdisCmRegisterAddressFamily, in which a call manager registers its call manager functions, identifies the protocol as a call manager. The call manager must register an address family for each NIC to which it binds itself.

An MCM driver is a miniport driver; therefore, it follows the initialization sequence for a connection-oriented miniport driver with the addition of the following step: an MCM driver must register an address family by calling NdisMCmRegisterAddressFamily in its MiniportInitialize function, immediately after completing the miniport driver initialization sequence . The call to NdisMCmRegisterAddressFamily, in which an MCM driver registers its call manager functions, distinguishes the MCM driver from a regular connection-oriented miniport driver. Although an MCM driver registers its miniport driver handlers only once during initialization by calling NdisMRegisterMiniport, it must call NdisMCmRegisterAddressFamily once for each NIC that it controls.


Differences in Calls to NdisXxx Functions

A call manager calls a different set of call manager functions than an MCM driver. A call manager calls NdisCmXxx functions, whereas an MCM driver calls NdisMCmXxx functions.

An integrated MCM driver does not call the NdisCoXxx functions that both connection-oriented clients and call managers call. Instead, an MCM driver calls the following comparable NdisMCmXxx functions:

  • NdisMCmCreateVc instead of NdisCoCreateVc
  • NdisMCmDeleteVc instead of NdisCoDeleteVc
  • NdisMCmRequest instead of NdisCoRequest
  • NdisMCmRequestComplete instead of NdisCoRequestComplete

An MCM driver does not require a call that is comparable to NdisCoSendPackets, since the send interface between the call manager and the miniport driver is internal to an MCM driver and therefore opaque to NDIS.


Differences in Virtual Connections

A call manager uses signaling VCs to send and receive signaling messages to and from network entities such as switches. A call manager's signaling VCs are visible to NDIS. The call manager must create, activate, deactivate, and delete all VCs with calls to NDIS. An MCM driver's signaling VCs, however, are opaque to NDIS. An MCM driver does not create, activate, deactivate, and delete signaling VCs with calls to NDIS. Instead, an MCM driver performs such operations internally. An MCM driver must call NDIS to perform operations on VCs used to send and/or receive client data. This is because NDIS must keep track of client VCs.

The fact that an MCM driver is both a call manager and a miniport driver means that certain connection-oriented functions are redundant. Specifically, MiniportCoCreateVc and MiniportCoDeleteVc are redundant and are therefore not supplied by an MCM driver. VC operations are handled by:

  • An MCM driver's ProtocolCoCreateVc and ProtocolCoDeleteVc functions when a client requests the creation or deletion of a VC
  • NdisMCmCreateVc and NdisMCmDeleteVc when the MCM driver creates or deletes a VC
  • NdisMCmActivateVc and NdisCmDeactivateVc when the MCM driver activates or deactivates a VC

An MCM driver must supply a MiniportCoRequest function for a client to use in querying or setting miniport driver information, as well as a MiniportCoSendPackets function to handle send operations from a client.


Connection-Oriented Timing Features

Connection-oriented NDIS supports using a NIC's local time for scheduling the transmission of packets and for time-stamping send and receive packets.

Note These connection-oriented timing features are optional. These features are not supported by all CoNDIS NICs.

A connection-oriented protocol can call NdisCoRequest to query the local timing capabilities of a connection-oriented miniport driver or an MCM driver with OID_GEN_CO_GET_TIME_CAPS. In response to such a query, the miniport driver or MCM driver returns the following information:

  • Whether there is a readable clock on the NIC
  • Whether the NIC derives its time from the network connection
  • The precision of the local clock
  • Whether the NIC can timestamp received packets with its local time
  • Whether the NIC can schedule a send packet for transmission according to its local time
  • Whether the NIC can timestamp transmitted packets with its local time

To obtain a NIC's local time, a connection-oriented protocol can call NdisCoRequest to query a connection-oriented miniport driver or MCM driver with OID_GEN_CO_GET_NETCARD_TIME. The connection-oriented miniport driver or MCM driver synchronously returns its local time, which the connection-oriented protocol can then use to schedule the transmission of packets.

Timing information for a send or receive packet is contained in the packet's out-of-band (OOB) data. For more information, see NDIS_PACKET_OOB_DATA.


Connection-Oriented Operations

This section describes connection-oriented operations from a global perspective. The description of each connection-oriented operation includes all connection-oriented drivers involved in the operation and summarizes all the connection-oriented functions called by the drivers and NDIS during that operation.


Summary of Connection-Oriented Operations

This section describes the connection-oriented operations performed by connection-oriented clients, call managers, and miniport drivers. An integrated MCM driver performs the connection-oriented operations of both a call manager and a connection-oriented miniport driver.


Connection-Oriented Operations Performed by Clients

A connection-oriented client performs the following connection-oriented operations:

  • Opens and closes an address family

    On receiving notification from NDIS that a call manager or MCM driver has registered an address family, a connection-oriented driver can open that address family with the call manager or MCM driver (see Registering and Opening an Address Family). The client can then use the call manager services provided by the call manager or MCM driver. A client releases the association between itself and a call manager or MCM driver by closing the address family (see Closing an Address Family).

  • Registers and deregisters SAPs

    After opening an address family with a call manager or an MCM driver, a connection-oriented client can register one or more SAPs with the call manager or MCM driver (see Registering a SAP). The call manager or MCM driver will then indicate to the client any incoming calls addressed to the registered SAP(s). A client releases a SAP by deregistering it (see Deregistering a SAP).

  • Adds and deletes PVCs

    A connection-oriented client can monitor when an operator manually configures or deconfigures a permanent VC (PVC). In response to such an action, the client can request a call manager or MCM driver to add a PVC to its list of configured PVCs or to delete a PVC from such a list (see OID_CO_ADD_PVC and OID_CO_DELETE_PVC).

  • Makes outgoing calls

    Before making an outgoing call, a client must initiate the creation of a VC for the call (see Creating a VC). A client can then make an outgoing call (see Making a Call). To make a point-to-multipoint call, a client specifies a party when making the call.

  • Adds a party to or drops a party from a point-to-multipoint call

    A client can add a party to a point-to-multipoint call (see Adding a Party to a Multipoint Call) and delete a party from a point-to-multipoint call (see Dropping a Party from a Multipoint Call). A client can also respond to an incoming request to drop a party from a point-to-multipoint call (see Request to Drop a Party from a Multipoint Call).

  • Accepts or rejects an incoming call

    A client can accept or reject an incoming call addressed to a SAP that the client previously registered with a call manager or MCM driver (see Indicating an Incoming Call).

  • Negotiates the call parameters for an active VC

    Depending on what is allowed by the signaling protocol, a client can negotiate the call parameters for an active VC. A client can request a change in Quality of Service (QoS) (see Client-Initiated Request to Change Call Parameters) and respond to an incoming request to change the QoS for an active VC. A client can also respond to a request from the remote party to change the QoS for a call (see Incoming Request to Change Call Parameters).

  • Sends and receives packets

    A client can send packets through a connection-oriented miniport driver or MCM driver (see Sending Packets on a VC). A client can also receive packets through a connection-oriented miniport driver or MCM driver (see Receiving Packets on a VC).

  • Initiates the deletion of a VC

    A client can initiate the deletion of a VC that it created (see Deleting a VC).

  • Initiates the tear-down of a call

    A client can initiate the tear-down of a outgoing call that it made or an incoming call that it accepted (see Client-Initiated Request to Close a Call).

  • Queries or sets information

    A client can query or set information maintained by a bound call manager or the call manager portion of an MCM driver. A client can also respond to queries and sets from a bound call manager or MCM driver (see Querying or Setting Information).

    In addition, a client can query or set information maintained by a bound miniport driver or the miniport driver portion of a bound MCM driver (see Querying or Setting Information).

  • Inputs miniport driver status indications

    A client can input status indicated by a connection-oriented miniport driver or an MCM driver (see Indicating Miniport Driver Status).

  • Resets a NIC

    A connection-oriented client can cause a connection-oriented miniport driver or MCM driver to reset its NIC (see Reset).


Connection-Oriented Operations Performed by Call Managers

A call manager performs the following connection-oriented operations:

  • Registers and deregisters one or more address families

    A call manager registers one or more address families with NDIS (see Registering and Opening an Address Family). By registering an address family, a call manager registers the entry points of its call manager functions with NDIS and also advertises its call manager services (specifically, a signaling protocol) to bound connection-oriented clients.

  • Registers and deregisters SAPs at the request of a connection-oriented client

    A call manager receives a bound connection-oriented client's requests to register SAPs (see Registering a SAP) and to deregister SAPs (see Deregistering a SAP). The call manager sends signaling messages over the network to register or deregister SAPs on behalf of clients.

  • Sets up an outgoing call at the request of a connection-oriented client

    When a connection-oriented client makes an outgoing call, the call manager communicates (exchanges signaling messages) with network control devices, as necessary, to make a connection (see Making a Call). If the call is accepted by the remote party, the call manager activates the VC created for the call (see Activating a Call).

  • Sets up and indicates an incoming call to a connection-oriented client

    A call manager indicates to a bound connection-oriented client all calls addressed to a SAP registered by that client (see Indicating an Incoming Call). Before indicating the incoming call to the client, the call manager initiates creation of a VC for the call (see Creating a VC) and then initiates activation of the VC (see Activating a VC).

  • Communicates requests for a change in QoS

    Depending on the signaling protocol, the call manager can communicate a request from the local client to change the QoS for an outgoing or incoming call (see Client-Initiated Request to Change Call Parameters) or a request from the remote party to change the QoS for a call (see Incoming Request to Change Call Parameters).

  • Communicates requests to add and drop parties

    A call manager communicates a local client's request to add a party to or drop a party from a point-to-multipoint call (see Adding a Party to a Multipoint Call and Dropping a Party from a Multipoint Call). A call manager also communicates a remote party's incoming request to drop itself from a point-to-multipoint call (see Incoming Request to Drop a Party from a Multipoint Call).

  • Tears down a call

    At the request of a connection-oriented client, a call manager closes a call by communicating with network control devices to terminate a connection (see Client-Initiated Request to Close a Call). At the request of a remote party, a call manager indicates to a local connection-oriented client a remote party's request to close a call (see Incoming Request to Close a Call ). In the process of tearing down a call, the call manager deactivates the VC used for the call (see Deactivating a VC). If the call manager created the VC (for an incoming call), the call manager can also delete the VC (see Deleting a VC).

  • Queries or sets information

    A call manager can query or set information maintained by a bound connection-oriented client (see Querying or Setting Information). A call manager can also respond to query and set operations from a bound connection-oriented client.

    In addition, a call manager can query or set information maintained by a bound miniport driver or by the miniport driver portion of a bound MCM driver (see Querying or Setting Information).

  • Inputs miniport driver status indications

    A call manager inputs status indications from a bound connection-oriented miniport driver (see Indicating Miniport Driver Status).

  • Resets a NIC

    A call manager can cause a connection-oriented miniport driver to reset its NIC (see Reset).


Connection-Oriented Operations Performed by Miniport Drivers

In addition to controlling NIC hardware, a connection-oriented miniport driver performs the following connection-oriented functions:

  • Sends and receives packets

    A connection-oriented miniport driver sends and receives packets on behalf of connection-oriented clients or call managers (see Sending Packets on a VC and Receiving Packets on a VC).

  • Creates (sets up) VCs

    At the request of a connection-oriented client, a connection-oriented miniport driver allocates and initializes the resources for a VC for an outgoing call (see Creating a VC). At the request of a call manager, a connection-oriented miniport driver allocates and initializes the resources for a VC for an incoming call or on which the call manager will send and/or receive signaling messages (see Creating a VC).

  • Activates VCs

    At the request of a call manager, a connection-oriented miniport driver communicates with its NIC to prepare the NIC to receive or transmit data across a VC (see Activating a VC).

  • Deactivates VCs

    At the request of a call manager, a connection-oriented miniport driver communicates with its NIC to terminate all communication across a VC (see Deactivating a VC).

  • Deletes VCs

    At the request of a connection-oriented client, a connection-oriented miniport driver deallocates the resources for a VC whose creation was initiated by that client (see Deleting a VC). At the request of a call manager, a connection-oriented miniport driver deallocates the resources for a VC whose creation was initiated by that call manager (see Deleting a VC).

  • Responds to information queries or sets

    A connection-oriented miniport driver responds to query and set operations by a bound connection-oriented client or call manager (see Querying or Setting Information).

  • Indicates status

    A connection-oriented miniport driver can indicate changes in its status or the status of its NIC to bound connection-oriented clients and call managers (see Indicating Miniport Driver Status).

  • Resets the NIC

    At the request of a connection-oriented client, call manager, or NDIS, a connection-oriented miniport driver resets its NIC (see Reset).


Operations on Address Families and SAPs

A call manager or MCM driver must register its call manager entry points with NDIS and advertise its call manager services to connection-oriented clients. A call manager or MCM driver does this by registering an address family.

To use the call manager services of a call manager or MCM driver, a connection-oriented client must open an address family with that call manager or MCM driver. To receive incoming calls, the client must also register one or more SAPs with the call manager or MCM driver.

This following connection-oriented operations pertain to address families and SAPs:

Registering and Opening an Address Family

Registering a SAP

Deregistering a SAP

Closing an Address Family


Registering and Opening an Address Family

A call manager must register an address family for each NIC on which it provides call manager services to connection-oriented clients. Similarly, an MCM driver must register an address family for the NIC that it manages.

By registering an address family, a call manager or MCM driver registers its call manager entry points with NDIS and causes NDIS to advertise the call manager's or MCM driver's services to all connection-oriented clients that bind to the adapter.

If a connection-oriented client can use the services advertised by a call manager or MCM driver, it can open an address family with the call manager or MCM driver.

Registering an Address Family from a Call Manager

After its ProtocolBindAdapter function binds to an underlying miniport driver with NdisOpenAdapter, a call manager calls NdisCmRegisterAddressFamily to register an address family for the binding (see the following figure).

Registering and Opening an Address Family with a Call Manager

The call to NdisCmRegisterAddressFamily registers the call manager entry points for the call manager and also advertises the call manager's specific signaling services. A call manager must register an address family each time that its ProtocolBindAdapter function and is called and successfully binds to a NIC with NdisOpenAdapter.

The call manager can support more than one address family across all the NIC drivers to which it is bound. The call manager can also support more than one address family on a single NIC to which it is bound. In this case, however, the call manager must register the same entry points for each address family on the binding. Only one call manager can support a particular type of address family for clients bound to any particular NIC driver.

Registering an Address Family from an MCM Driver

An MCM driver calls NdisMCmRegisterAddressFamily from its MiniportInitialize function after registering its miniport driver entry points with NdisMRegisterMiniport. An MCM driver calls NdisMCmRegisterAddressFamily once to register its call manager entry points with NDIS and to advertise its services to connection-oriented clients (see the following figure).

Registering and Opening an Address Family with an MCM Driver

A miniport driver of a NIC that has on-board connection-oriented signaling support can register itself as an MCM driver even though a call manager may be available. By doing so, such an MCM driver preempts the call manager as the call manager for that NIC.

Opening an Address Family

A call manager's or MCM driver's call to Ndis(M)CmRegisterAddressFamily causes NDIS to call the ProtocolCoAfRegisterNotify function of each connection-oriented client on the binding (as shown in two previous figures).

ProtocolCoAfRegisterNotify examines the address-family data to determine whether the client can use the services of this particular CM or MCM driver. Whether the client can make modifications in the (M)CM-supplied address-family data depends on the particular signaling-protocol support of the call manager or MCM driver.

If the client finds the offered call-management services acceptable, ProtocolCoAfRegisterNotify allocates a per-AF context area for the client and calls NdisClOpenAddressFamily. NdisClOpenAddressFamily registers the client's connection-oriented entry points with NDIS.

The call to NdisClOpenAddressFamily causes NDIS to call the call manager's or MCM driver's ProtocolCmOpenAf function (as shown already in two previous figures). ProtocolCmOpenAf ensures that the client passed in a valid address family and allocates and initializes the resources necessary to perform operations on behalf of the client that is opening this instance of the address family. ProtocolCmOpenAf also stores an NDIS-supplied NdisAfHandle that represents the association between the call manager and client for the open address family.

ProtocolCmOpenAf can complete synchronously or asynchronously. To complete asynchronously. The ProtocolCmOpenAf function of a call manager calls NdisCmOpenAddressFamilyComplete; the ProtocolCmOpenAf function of an MCM driver calls NdisMCmOpenAddressFamilyComplete. The call to Ndis(M)CmOpenAddressFamilyComplete causes NDIS to call the ProtocolOpenAfComplete function of the client that originally called NdisClOpenAddressFamily.

If the client's call to NdisClOpenAddressFamily is successful, NDIS returns to the client an NdisAfHandle that represents the association between the call manager and client for the open address family.

If a client accepts incoming calls, it usually registers one or more SAPs from its ProtocolClOpenAfComplete function by calling NdisClRegisterSap following its successful call to NdisClOpenAddressFamily. (see Registering a SAP)

If a client makes outgoing calls, it could create one or more VCs (see Creating a VC) in its ProtocolClOpenAfComplete function in anticipation of a request by one or more its clients to make an outgoing call.


Registering a SAP

If a client accepts incoming calls, its ProtocolClOpenAfComplete function (see Registering and Opening an Address Family) usually registers one or more SAPs with the call manager by calling NdisClRegisterSap.

The following figure shows a client of a call manager registering a SAP.

Registering a SAP with a Call Manager

The following figure shows a client of an MCM driver registering a SAP.

Registering a SAP with an MCM Driver

With the call to NdisClRegisterSap, a client requests notifications of incoming calls on a particular SAP. NDIS forwards the SAP information supplied by the client to the call manager's or MCM driver's ProtocolCmRegisterSap function for validation. If the given SAP is already in use or if the call manager or MCM driver does not recognize the client-supplied SAP specification, the call manager or MCM driver fails this request.

In ProtocolCmRegisterSap, the call manager or MCM driver might communicate with network control devices or other media-specific agents to register the SAP on the network for a connection-oriented client. ProtocolCmRegisterSap also stores an NDIS-supplied NdisSapHandle that represents the SAP.

ProtocolCmRegisterSap can complete synchronously or asynchronously. To complete asynchronously, the ProtocolCmRegisterSap function of a call manager calls NdisCmRegisterSapComplete. The ProtocolCmRegisterSap function of an MCM driver calls NdisMCmRegisterSapComplete. The call to Ndis(M)CmRegisterSapComplete causes NDIS to call the client's ProtocolClRegisterSapComplete function.

If the client's call to NdisClRegisterSap is successful, NDIS returns to the client an NdisSapHandle that represents the SAP.

After a call manager registers a SAP on behalf of a connection-oriented client, it notifies that client of an incoming call offer directed to that SAP by calling NdisCmDispatchIncomingCall. An MCM driver calls NdisMCmDispatchIncomingCall (see Indicating an Incoming Call). A client can receive incoming calls on a SAP even while SAP registration is still pending; that is, before its ProtocolClRegisterSapComplete function is called.


Deregistering a SAP

A connection-oriented client deregisters a SAP with NdisClDeregisterSap.

The following figure shows a client of a call manager deregistering a SAP.

Deregistering a SAP with a Call Manager

The following figure shows a client of an MCM driver deregistering a SAP.

Deregistering a SAP with an MCM Driver

The call to NdisClDeregisterSap causes NDIS to call the call manager's or MCM driver's ProtocolCmDeregisterSap function. In ProtocolCmDeregisterSap, the call manager or MCM driver might communicate with network control devices or other media-specific agents to deregister the SAP on the network. In addition, ProtocolCmDeregisterSap must free any resources that it dynamically allocated for the SAP.

ProtocolCmDeregisterSap can complete synchronously or asynchronously. To complete asynchronously, the ProtocolCmDeregisterSap function of a call manager calls NdisCmDeregisterSapComplete. The ProtocolCmDeregisterSap function of an MCM driver calls NdisMCmDeregisterSapComplete. Ndis(M)CmDegisterSapComplete notifies both NDIS and the client that the call manager has completed the SAP-deregistration request for which its ProtocolCmDeregisterSap function previously returned NDIS_STATUS_PENDING.

A call to Ndis(M)CmDeregisterSapComplete causes NDIS to call the client's ProtocolClDeregisterSapComplete function. A call to ProtocolClDeregisterSapComplete indicates that the client's preceding call to NdisClDeregisterSap has been processed by the call manager or MCM driver.

Note that a client can deregister a SAP without affecting an incoming call that has already been received on that SAP and without affecting the VC for that incoming call.


Closing an Address Family

A connection-oriented client calls NdisClCloseAddressFamily to delete the association between itself, a call manager, and a particular underlying NIC.

The following figure shows a client of a call manager closing an address family.

Closing an Address Family Through a Call Manager

The following figure shows a client of an MCM driver closing an address family.

Closing an Address Family Through an MCM Driver

A client commonly calls NdisClCloseAddressFamily from its ProtocolUnbindAdapter function after it closes all its open VCs on the binding (see Client-Initiated Request to Close a Call) and deregisters any SAPs (see Deregistering a SAP). NDIS calls a client's ProtocolUnbindAdapter function whenever an underlying NIC to which that client is bound is removed from the machine or is reconfigured. A client can also call NdisClCloseAddressFamily in the context of processing an OID_CO_AF_CLOSE request.

The call to NdisClCloseAddressFamily causes NDIS to call the ProtocolCmCloseAf function of the call manager or MCM driver that the client originally used to open the address family. ProtocolCmCloseAf releases and/or deactivates any resources that were allocated by the call manager in its ProtocolCmOpenAf function. The call manager also should undo any other actions it took on behalf of the connection-oriented client when the address family was opened by that client.

ProtocolCmCloseAf can complete synchronously or asynchronously. To complete asynchronously, the ProtocolCmCloseAf function of a call manager calls NdisCmCloseAddressFamilyComplete. The ProtocolCmCloseAf function of an MCM driver calls NdisMCmCloseAddressFamilyComplete.

If any outstanding requests or connections remain open on an address family, a call manager can respond to a client's request to close the address family in either of the following ways:

  • The call manager or MCM driver can fail the request with NDIS_STATUS_NOT_ACCEPTED.
  • The call manager or MCM driver can return NDIS_STATUS_PENDING. After the client has closed all calls and deregistered all SAPs, the call manager or MCM driver can then close the address family and call Ndis(M)CmCloseAddressFamilyComplete to notify the client. This is the preferred response.

The call to Ndis(M)CmCloseAddressFamilyComplete causes NDIS to call the ProtocolClCloseAfComplete function of the connection-oriented client that originally called NdisClCloseAddressFamily.


Operations on VCs

All connection-oriented communication over the network occurs on virtual connections (VCs). The following VC operations are described in this section:

Creating a VC

Activating a VC

Deactivating a VC

Deleting a VC


Creating a VC

Before making an outgoing call, a connection-oriented client initiates the creation a virtual connection (VC). Before indicating an incoming call to a connection-oriented client, a call manager or an MCM driver initiates the creation of a VC . After the VC has been set up and activated, client data can be transmitted and/or received on the VC.

A call manager or an MCM driver can also initiate the creation of a VC on which signaling messages are exchanged with network components, such as a network switch.

Client-Initiated Creation of a VC

Before making a call with NdisClMakeCall (see Making a Call), a connection-oriented client calls NdisCoCreateVc to initiate the creation of a VC.

The following figure shows a client of a call manager initiating the creation of a VC.

Client-Initiated Creation of a VC (Call Manager Present)

The following figure shows a client of an MCM driver initiating the creation of a VC.

Client-Initiated Creation of a VC (MCM Driver Present)

When a connection-oriented client of a call manager calls NdisCoCreateVC, NDIS calls, as a synchronous operation, the ProtocolCoCreateVC function of the call manager and the MiniportCoCreateVc function of the underlying miniport (see Client-Initiated Creation of a VC (Call Manager Present)). NDIS passes to both ProtocolCoCreateVC and MiniportCoCreateVC an NdisVcHandle that represents the VC. If the call to NdisCoCreateVc is successful, NDIS returns the NdisVcHandle to NdisCoCreateVc.

ProtocolCoCreateVc allocates and initializes any dynamic resources and structures that the call manager requires to perform subsequent operations on a VC that will be activated. MiniportCoCreateVc allocates and initializes any resources that the miniport requires to maintain state information about the VC. Both ProtocolCoCreateVc and MiniportCoCreateVc store the NdisVcHandle.

When a connection-oriented client of an MCM driver, the call to NdisCoCreateVc causes NDIS to call the MCM driver's ProtocolCoCreateVc function (see Client-Initiated Creation of a VC (MCM Driver Present)). In this case, ProtocolCoCreateVc performs the necessary allocation and initialization of resources for the VC. There is no call (internal or otherwise) to MiniportCoCreateVc, since an MCM driver does not supply such a function.

Call-Manager-Initiated Creation of a VC

Before indicating an incoming call to a connection-oriented client with NdisCmDispatchIncomingCall (see Indicating an Incoming Call), a call manager calls NdisCoCreateVc to initiate the creation of a VC (see the following figure).

Call Manager Initiates VC Creation

When a call manager calls NdisCoCreateVC, NDIS calls, as a synchronous operation, the ProtocolCoCreateVC function of the connection-oriented client that registered the SAP on which the call is being received, as well as the MiniportCoCreateVc function of the underlying miniport. NDIS passes to both ProtocolCoCreateVC and MiniportCoCreateVC, an NdisVcHandle that represents the VC. If the call to NdisCoCreateVc is successful, NDIS returns the NdisVcHandle to NdisCoCreateVc.

MCM Driver-Initiated Creation of a VC

Before indicating an incoming call to a connection-oriented client with NdisMCmDispatchIncomingCall (see Indicating an Incoming Call), an MCM driver calls NdisMCmCreateVc to initiate the creation of a VC (see the following figure).

An MCM Driver Initiates VC Creation

When an MCM driver calls NdisMCmCreateVC, NDIS calls, as a synchronous operation before NdisMCmCreateVC returns, the ProtocolCoCreateVC function of the connection-oriented client that registered the SAP on which the call is being received. NDIS passes to ProtocolCoCreateVC an NdisVcHandle that represents the VC. If the call to NdisMCmCreateVc is successful, NDIS returns the NdisVcHandle to NdisMCmCreateVc.

ProtocolCoCreateVc allocates and initializes any dynamic resources and structures that the client requires to perform subsequent operations on the VC. ProtocolCoCreateVc also stores the NdisVcHandle.

Note that when an MCM driver creates a VC for exchanging signaling messages with a network component, it does not use Ndis Xxx calls to create a VC. In fact, an MCM driver does not use Ndis Xxx calls to create, activate, deactivate, or delete such VCs. Instead, an MCM driver performs these operations internally. Such VCs are therefore opaque to NDIS.


Activating a VC

After a virtual connection (VC) has been created (see Creating a VC), it must be activated before data can be transmitted and/or received on it. A call manager initiates the activation of a VC by calling NdisCmActivateVc (see the following figure).

Call Manager Initiates VC Activation

An MCM driver initiates the activation of a VC by calling NdisMCmActivateVC (see the following figure).

MCM Driver Initiates VC Activation

A call manager or MCM driver could initiate reactivation of an active VC if the local client or a remote party successfully negotiates a change in call parameters on that VC (see Client-Initiated Request to Close a Call and Incoming Request to Change Call Parameters). The call manager or MCM driver can call Ndis(M)CmActivateVc many times for a single VC to change the call parameters for an already active call.

For a client-initiated outgoing call, a call manager or an MCM driver usually calls Ndis(M)CmActivateVc immediately following the packet exchange confirming a negotiated agreement with the remote target of the call or successful call-setup at the switch. The call manager or MCM driver calls Ndis(M)CmActivateVc before it notifies NDIS (and the client) of outgoing call completion with Ndis(M)CmMakeCallComplete (see Making a Call). For an incoming call, a call manager or MCM driver usually calls Ndis(M)CmActivateVc after it has called NdisCo(MCm)CreateVc successfully and before it calls Ndis(M)CmDispatchIncomingCall (see Indicating an Incoming Call).

A call manager's call to NdisCmActivateVc causes NDIS to call the MiniportCoActivateVc function of the underlying miniport driver. MiniportCoActivateVc must validate the call parameters for this VC to verify that the adapter can support the requested call. If the call parameters are acceptable, MiniportCoActivateVc communicates with its adapter as necessary to prepare the adapter to receive or transmit data across the virtual connection (for example, programming receive buffers). If the requested call parameters cannot be supported, the miniport driver fails the request.

MiniportCoActivateVc can complete synchronously or asynchronously. The call to NdisMCoActivateVcComplete. causes NDIS to call the call manager's ProtocolCmActivateVcComplete function. ProtocolCmActivateVcComplete must check the status returned by NdisMCoActivateVcComplete to ensure that the virtual connection has been activated successfully. If the miniport driver did not successfully activate the VC, the call manager must not attempt to communicate over the VC. ProtocolCmActivateVcComplete must also complete any processing required by the network media to ensure that the virtual connection is ready for data transmission before returning control to NDIS.

An MCM driver's call to NdisMCmActivateVc informs NDIS that it has set up call and media parameters on a newly created VC or changed the call parameters on an established VC. This notifies NDIS that the MCM driver has made its NIC ready for transfers on the VC. NDIS completes the activation sequence by calling the MCM driver's ProtocolCmActivateVcComplete function.

An MCM driver calls NdisMCmActivateVc to activate only VCs used for transmitting and/or receiving client data, but not to activate VCs used for exchanging signaling messages between the MCM driver and network components such as a switch. An MCM driver activates a signaling VC internally without calling any NdisXxx function. Any VC that an MCM driver sets up for its own signaling purposes is therefore opaque to NDIS.


Deactivating a VC

A call manager calls NdisCmDeactivateVc as an essential step in closing either an outgoing or incoming call, usually after the packet exchange with network components that tears down the call (see Client-Initiated Request to Close a Call and Incoming Request to Close a Call). An MCM driver does the same thing by calling NdisMCmDeactivateVc.

The call to NdisCmDeactivateVc causes NDIS to call the underlying NIC driver's MiniportCoDeactivateVc function (see the following figure). MiniportCoDeactivateVc communicates with its network adapter to terminate all communication across this VC (for example, clearing receive or send buffers on the adapter).

Call Manager Initiates VC Deactiavtion

Before it deactivates a VC, the miniport driver must complete any pending transfers on the VC. That is, the miniport driver must wait until it has completed all sends in progress and until all receive packets that it has indicated are returned to it. After deactivating the VC, the miniport driver cannot indicate receives or transmit sends on the VC.

Note that MiniportCoDeactivateVc does not delete the VC. The creator (client, call manager, or MCM driver) of a particular VC that will not be reused calls NdisCoDeleteVc to destroy that VC (see Deleting a VC). A deactivated VC can be reactivated by a connection-oriented client, a call manager, or an MCM driver (see Activating a VC).

MiniportCoDeactivateVc can complete synchronously or asynchronously. A call to NdisMCoDeactivateVcComplete. causes NDIS to call the ProtocolCmDeactivateVcComplete function of the call manager that originally requested the VC deactivation. Completion of the deactivation means that all call parameters for the VC used on activation are no longer valid. Any further use of the VC is prohibited except to reactivate it with a new set of call parameters.

An MCM driver's call to NdisMCmDeactivateVc informs NDIS that it has deactivated a VC or changed the call parameters on an established VC (see the following figure). NDIS completes the deactivation sequence by calling the MCM driver's ProtocolCmDeactivateVcComplete function.

MCM Driver Initiates VC Deactivation

An MCM driver does not call NdisMCmDeactivateVc to deactivate VCs used for exchanging signaling messages between the MCM driver and network components such as a switch. An MCM driver deactivates a signaling VC internally without calling any NdisXxx function.


Deleting a VC

Only the connection-oriented client, call manager, or MCM driver that initiated the creation of a virtual circuit (VC) can initiate the deletion of that VC. A client therefore deletes a VC that it previously created for an outgoing call, a call manager or MCM driver deletes a VC that it previously created for an incoming call over the network, and a call manager deletes a VC that it previously created for exchanging signaling messages over the network. (An MCM driver does not call NDIS to delete a VC that it created for exchanging signaling messages. The MCM driver deletes such a VC with an internal operation that is opaque to NDIS.)

A connection-oriented client or call manager initiates the deletion of a VC with NdisCoDeleteVc.

The following figure shows a client of a call manager initiating the deletion of a VC.

Connection-Oriented Client Initiates VC Deletion Through a Call Manager

The following figure shows a client of an MCM driver initiating the deletion of a VC.

Client Initiates VC Deletion Through an MCM Driver

The following figure shows a call manager initiating the deletion of a VC.

Call Manager Initates VC Deletion

When a client or call manager calls NdisCoDeleteVc or when an MCM driver calls NdisMCmDeleteVC, there must be no outstanding calls on the given VC and that VC must already have been deactivated (see Deactivating a VC ). To meet these requirements implies that the following conditions hold:

  • The client has already called NdisClCloseCall with the given NdisVcHandle and its close-call request has completed successfully (see Client-Initiated Request to Close a Call).
  • Thecall manager has already called NdisCmDeactivateVc or the MCM driver has already called NdisMCmDeactivateVc with the given NdisVcHandle and the deactivation request has completed successfully (see Incoming Request to Close a Cal).

A client's or call manager's call to NdisCoDeleteVc causes NDIS to call both the underlying NIC driver's MiniportCoDeleteVc function and the ProtocolCoDeleteVc function of the client or call manager with which the caller shares the NdisVcHandle (see the three previous figures).

MiniportCoDeleteVc frees any resources allocated for the VC, as well as the miniport driver's context for the VC. ProtocolCoDeleteVc releases any resources that the client or call manager used to perform operations on and track state for the VC. Both MiniportCoDeleteVc and ProtocolCoDeleteVc are synchronous functions that cannot return NDIS_STATUS_PENDING.

An MCM driver initiates the deletion of a VC with NdisMCmDeleteVc (see the following figure).

MCM Driver Initates VC Deletion

An MCM driver's call to NdisMCmDeleteVc causes NDIS to call the ProtocolCoDeleteVc function of the client with which the MCM driver shared the NdisVcHandle.

When NdisCoDeleteVc or NdisMCmDeleteVc returns control, the NdisVcHandle is no longer valid.


Setting Up a Call

A connection-oriented client initiates the call setup when making an outgoing call. A call manager or MCM driver initiates the call setup when indicating an incoming call to a connection-oriented client.


Making a Call

The following figure shows a client making an outgoing call through a call manager.

Making a Call Through a Call Manager

The following figure shows a client making an outgoing call through an MCM driver.

Making a Call Through an MCM Driver

Before making an outgoing call, a connection-oriented client must do the following:

  • Initialize call parameters in a structure of type CO_CALL_PARAMETERS. The call manager or MCM driver typically uses the call parameters specified by the client to set up the call and to derive media parameters for use by the miniport driver.
  • Initiate the creation of a VC with NdisCoCreateVc (see Creating a VC).

On the successful return of NdisCoCreateVc, the client calls NdisClMakeCall to initiate the call (see the two figures in this section).

In its call to NdisClMakeCall, the client passes a pointer to the CO_CALL_PARAMETERS structure initialized previously. The client also passes an NdisVcHandle (returned by NdisCoCreateVc) that identifies the VC on which the client will transmit (and perhaps receive) data for the call. If the client is making a multipoint call (a call to more than one remote party), it also passes a ProtocolPartyContext that specifies a handle to a client-allocated resident context area in which the client will maintain per-party state for the initial party on the multipoint VC.

The call to NdisClMakeCall causes NDIS to forward this request to the ProtocolCmMakeCall function of the call manager or MCM driver with which the client shares the given NdisVcHandle. ProtocolCmMakeCall must validate the input call parameters that were set up by the client.

ProtocolCmMakeCall communicates (exchanges signaling messages) with network control devices to make a connection. A call manager calls NdisCoSendPackets to initiate such an exchange (see Sending Packets on a VC). An MCM driver never calls NdisCoSendPackets. Instead, it transmits the data directly across the network.

The call manager or MCM driver can modify the client-supplied call parameters while negotiating with relevant network components and can return different traffic parameters than the client originally gave to NdisClMakeCall (see Incoming Request to Change Call Parameters)

An explicit NdisPartyHandle passed to ProtocolCmMakeCall indicates that the VC created by the client will be used for a multipoint call. The call manager or MCM driver must allocate and initialize any necessary resources required to maintain per-party state information and control the multipoint call.

After a call manager has done all the necessary communication with its networking hardware as required by its medium, it must call NdisCmActivateVc to initiate the activation of the VC on which call data will be sent and perhaps received (see Activating a VC) An MCM driver must call NdisMCmActivateVc.

When the underlying miniport driver is ready to make data transfers on the VC (that is, after the VC has been activated), a call manager calls NdisCmMakeCallComplete, and an MCM driver calls NdisMCmMakeCallComplete. At this point, the call manager or MCM driver should have negotiated with the network to establish call parameters for the VC, and the underlying miniport driver should have completed activation of the VC.

In the call to Ndis(M)CmMakeCallComplete, the call manager or MCM driver passes the call parameters for the VC as a pointer to a structure of type CO_CALL_PARAMETERS. If the call manager has modified the call parameters as originally specified by the client, it can notify the client by setting the CALL_PARAMETERS_CHANGED flag in the CO_CALL_PARAMETERS structure.

A call to Ndis(M)CmMakeCallComplete causes NDIS to call the ProtocolClMakeCallComplete function of the client that originated the outgoing call. A call to ProtocolClMakeCallComplete indicates that the call manager has completed processing the client's request to establish a virtual connection with NdisClMakeCall.

If the client's attempt to establish an outgoing call was successful, ProtocolClMakeCallComplete should check the CALL_PARAMETERS_CHANGED flag to determine whether the call parameters originally specified by the client were modified. If the flag is set, indicating that the call parameters were changed, ProtocolClMakeCallComplete should examine the returned call parameters to determine whether they are acceptable for this connection.

If the call parameters are acceptable, ProtocolClMakeCallComplete simply returns control. If the call parameters are not acceptable and if the signaling protocol allows renegotiation at this point, the client can call NdisClModifyCallQoS to request a change in call parameters (see Client-Initiated Request to Close a Call). If the signaling protocol does not allow renegotiation of unacceptable call parameters, ProtocolClMakeCallComplete must tear down the call with NdisClCloseCall (see Client-Initiated Request to Close a Call).


Indicating an Incoming Call

A call manager or MCM driver is alerted to an incoming call by signaling messages from the network. From these signaling messages, the call manager or MCM driver extracts the call parameters for the call, including the SAP to which the incoming call is addressed.

The following figure shows a call manager indicating an incoming call.

Indicating an Incoming Call Through a Call Manager

The following figure shows a call manager indicating an incoming call.

Indicating an Incoming Call Through an MCM Driver

If the incoming call parameters are unacceptable to the call manager or MCM driver, it can attempt to negotiate a change in these parameters with the remote party if such negotiation is allowed by the signaling protocol. Alternatively, the client to which the incoming call is directed could attempt to negotiate the call parameters after receiving the call indication from the call manager or MCM driver (see Client-Initiated Request to Change Call Parameters). If the call manager or MCM driver cannot negotiate acceptable call parameters for the call with the remote party, it might refuse the call. The signaling protocol determines what is possible in such cases.

Before indicating an incoming call to a client, the call manager or MCM driver must identify the SAP to which the call is directed. The SAP must have been previously registered by a client (see Registering a SAP) The call manager or MCM driver must also initiate the creation of a virtual connection (see Creating a VC) and initiate the activation of this VC (see Activating a VC).

The call manager or MCM driver then indicates the incoming call to the client that registered the SAP to which the incoming call is directed. A call manager indicates an incoming call with NdisCmDispatchIncomingCall. An MCM driver indicates an incoming call with NdisMCmDispatchIncomingCall.

In the call to Ndis(M)CmDispatchIncomingCall, the call manager or MCM driver passes the following:

  • An NdisSapHandle that identifies the SAP to which the incoming call is addressed
  • An NdisVcHandle that identifies the virtual circuit for the incoming call
  • A pointer to a structure of type CO_CALL_PARAMETERS, which contains the call parameters for the call

The call to Ndis(M)CmDispatchIncomingCall causes NDIS to call the client's ProtocolClIncomingCall function, within which the client either accepts or rejects the requested connection. ProtocolClIncomingCall should validate the SAP, VC, and call parameters.

ProtocolClIncomingCall can complete synchronously or it can return NDIS_STATUS_PENDING and complete asynchronously with NdisClIncomingCallComplete. A call to NdisClIncomingCallComplete causes NDIS to call the call manager's or MCM driver's ProtocolCmIncomingCallComplete function.

The NDIS_STATUS code returned by a synchronous completion of ProtocolClIncomingCall or supplied to NdisClIncomingCallComplete indicates the client's acceptance or rejection of the incoming call. The client also returns the call parameters for the call in a buffered CO_CALL_PARAMETERS structure. If the client finds the call parameters unacceptable, it can, if allowed by the signaling protocol, request a change in the call parameters by setting the Flags member in the CO_CALL_PARAMETERS structure with CALL_PARAMETERS_CHANGED and by supplying the revised call parameters in a buffered CO_CALL_PARAMETERS structure.

If the client accepts the incoming call, the call manager or MCM driver should send signaling messages to indicate to the calling entity that the call has been accepted. Otherwise, the call manager or MCM driver should send signaling messages to indicate that the call has been rejected. If the client is requesting a change in call parameters, the call manager or MCM driver sends signaling messages to request a change in call parameters.

If the client accepted the call, or if the client's requested change in call parameters was accepted by the remote party, a call manager calls NdisCmDispatchCallConnected, and an MCM driver calls NdisMCmDispatchCallConnected. The call to Ndis(M)CmDispatchCallConnected causes NDIS to call the client's ProtocolClCallConnected function.

If the client rejected the call and the call manager or MCM driver has already activated a VC for the incoming call, the call manager or MCM driver calls Ndis(M)CmDeactivateVc to deactivate the VC if the VC is activated. The call manager or MCM driver can then initiate deletion of the VC by calling NdisCoDeleteVc in the case of the call manager or NdisMCmDeleteVc in the case of the MCM driver (see Deleting a VC ).

If the client accepted the call but the end-to-end connection was not successfully established (because, for example, the remote party tore down the call), then the call manager or MCM driver will not call Ndis(M)CmDispatchCallConnected. Instead, it will call Ndis(M)CmDispatchIncomingCloseCall, which causes NDIS to call the client's ProtocolClIncomingCloseCall function. The client must then call NdisClCloseCall to complete the teardown of the call. The call manager or MCM driver then calls Ndis(M)CmDeactivateVC to deactivate the VC that it created for the incoming call (see Deactivating a VC). The call manager or MCM driver can then initiate deletion of the VC by calling NdisCoDeleteVc in the case of the call manager or NdisMCmDeleteVc in the case of the MCM driver (see Deleting a VC).


Changing the QoS of an Active VC

A connection-oriented client can request a change in the quality of service (QoS) on an active virtual connection (VC) for an outgoing or an incoming call. A remote client can also make such a request. In this case, a call manager or MCM driver driver indicates the remote client's incoming request to change the QoS.


Client-Initiated Request to Change Call Parameters

A client requests a change in quality of service (QoS) on an active virtual connection (VC) with NdisClModifyCallQoS.

The following figure shows the client of a call manager requesting a change in quality of service.

Client Initiates a Request to Change Call Parameters Through a Call Manager

The following figure shows the client of an MCM driver requesting a change in quality of service.

Client Initiates a Request to Change Call Parameters Through an MCM Driver

In the call to NdisClModifyCallQoS, the client supplies the following:

  • An NdisVcHandle that identifies the VC
  • A pointer to a CO_CALL_PARAMETERS structure that contains the call parameters the client is requesting

The circumstances under which a client can request a change in QoS are determined by the signaling protocol.

The call to NdisClModifyCallQoS causes NDIS to call the call manager's or MCM driver's ProtocolCmModifyCallQoS function, which inputs the NdisVcHandle and buffered CO_CALL_PARAMETERS structure passed by the client to NdisClModifyCallQoS. ProtocolCmModifyQoS communicates with network control devices or other media-specific agents, as necessitated by its media, to modify the media-specific call parameters for an established virtual connection.

After communicating with the network and determining that the changes were successful, a call manager must call NdisCmActivateVc (and an MCM driver must call NdisMCmActivateVC) to activate the specified VC with the new call parameters.

If the network does not accept the new call parameters or if the underlying miniport driver cannot accept the parameters, the call manager or MCM driver must restore the VC to the state that existed before any modifications were attempted, and return NDIS_STATUS_FAILURE.

To indicate the status of the client's request to change QoS, a call manager calls NdisCmModifyCallQoSComplete, and an MCM driver calls NdisMCmModifyCallQoSComplete. In this call, the call manager or MCM driver passes the following:

  • An NDIS_STATUS that indicates the status of the request
  • An NdisVcHandle that identifies the VC
  • A pointer to a CO_CALL_PARAMETERS structure that contains the call parameters for the VC

If allowed by the signaling protocol, the call manager or MCM driver can pass modified call parameters back to the client. These modifications can be the product of negotiation with the network or they can be supplied by the call manager or MCM driver itself. A call manager or MCM driver should indicate that the call parameters have been modified by setting the CALL_PARAMETERS_CHANGE flag in the CO_CALL_PARAMETERS structure.

The call to Ndis(M)CmModifyCallQoSComplete causes NDIS to call the client's ProtocolClModifyCallQoSComplete function. NDIS passes the following to ProtocolClModifyCallQosComplete:

  • An NDIS_STATUS that indicates the status of the client's request to change the QoS
  • A ProtocolVcContext handle that identifies the VC
  • A pointer to a CO_CALL_PARAMETERS structure that contains the call parameters passed by the call manager or MCM driver to Ndis(M)CmModifyCallQoSComplete

If the CALL_PARAMETERS_CHANGED flag is set in the CO_CALL_PARAMETERS structure, the client must examine the returned call parameters and determine whether the modifications are acceptable. If the client's call to NdisClModifyCallQoS succeeds, ProtocolClModifyCallQoSComplete can accept the QoS change by simply returning control. Otherwise, ProtocolClModifyCallQoSComplete can engage in further negotiation with the call manager if allowed by the signaling protocol and as long as the client's developer places some reasonable limit on the number of possible renegotiations. Alternatively, ProtocolClModifyCallQoSComplete can simply tear down the call with NdisClCloseCall (see Client-Initiated Request to Close a Call) whenever the call manager rejects a request to change the QoS and the previously established QoS has become unacceptable to the client.


Incoming Request to Change Call Parameters

A call manager or MCM driver is alerted to an incoming request from a remote party to change the call parameters on an active VC by signaling messages from the network. Whether a call manager or MCM driver supports dynamic QoS changes on active calls depends on the signaling protocol. For example, ATM UNI 3.1 networks do not support dynamic QoS changes on active connections.

The following figure shows an incoming request through a call manager to change call parameters.

Incoming Request Through a Call Manager to Change Call Parameters

The following figure shows an incoming request through a call manager to change call parameters.

Incoming Request Through an MCM Driver to Change Call Parameters

After receiving an incoming request to change call parameters, a call manager passes appropriately modified call parameters to NdisCmActivateVc to notify the underlying NIC driver of the proposed QoS change. An MCM driver passes modified call parameters to NdisMCmActivateVc (see Activating a VC). If the underlying NIC driver accepts the changed call parameters, a call manager then calls NdisCmDispatchIncomingCallQosChange (see Incoming Request Through a Call Manager to Change Call Parameters). An MCM driver calls NdisMCmDispatchIncomingCallQosChange (see Incoming Request Through an MCM Driver to Change Call Parameters). The call manager or MCM driver passes an NdisVcHandle and a buffered CO_CALL_PARAMETERS structure to Ndis(M)CmDispatchIncomingCallQoSChange.

A call to Ndis(M)CmDispatchIncomingCallQoSChange causes NDIS to call the client's ProtocolClIncomingCallQoSChange function. NDIS passes a ProtocolVcContext handle, that identifies the VC, and the modified call parameters in a buffered CO_CALL_PARAMETERS structure, to ProtocolClIncomingCallQoSChange.

The client accepts the proposed modifications to the call parameters for the VC by doing nothing, except possibly updating any state it maintains about the QoS for the VC, and returning control. If the proposed modifications are unacceptable, the client can attempt to renegotiate the call parameters with NdisClModifyCallQoS if allowed by the signaling protocol (see Client-Initiated Request to Change Call Parameters). Otherwise, the client rejects the proposed QoS change by tearing down the call with NdisClCloseCall (see Client-Initiated Request to Close a Call).

After ProtocolClIncomingCallQoS returns, the call manager or MCM driver communicates the client's acceptance or rejection of the proposed change to the remote party that originated the request.


Adding and Dropping Parties

A connection-oriented client can add a party to an outgoing multipoint call that it initiated with NdisClMakeCall. A connection-oriented client can also delete a party from a multipoint call either at its own discretion or at the request of the remote party to be dropped.


Adding a Party to a Multipoint Call

A client requests to add a party to a multipoint call with NdisClAddParty. A client can add a party only to an existing multipoint call—that is, a call for which the client supplied a ProtocolPartyContext to NdisClMakeCall (see Making a Call).

The following figure shows a client of a call manager requesting to add a party to multipoint call.

Adding a Party Through a Call Manager to a Multipoint Call

The following figure shows a client of an MCM driver requesting to add a party to multipoint call.

Adding a Party Through an MCM Driver to a Multipoint Call

Before it calls NdisClAddParty, a client must allocate and initialize its context area for the party to be added. Clients commonly pass a pointer to such a context area as the ProtocolPartyContext and a pointer to a variable within that context area as the NdisPartyHandle parameters when they call NdisClAddParty.

In addition to an NdisVcHandle and a ProtocolPartyContext, the client passes call parameters (a buffered CO_CALL_PARAMETERS structure) to NdisClAddParty. The underlying network medium determines whether a client can specify per-party traffic parameters on a multipoint VC. For example, traffic parameters on a multipoint VC are identical for all parties on ATM networks.

The call to NdisClAddParty causes NDIS to forward this request to the ProtocolCmAddParty function of the call manager or MCM driver with which the client shares the given NdisVcHandle. NDIS passes the following to the ProtocolCmAddParty:

  • A CallMgrVcContext that indicates the VC for the call
  • A pointer to a CO_CALL_PARAMETERS structure that contains the call parameters passed by the client to NdisClAddParty
  • An NdisPartyHandle that identifies the party to be added

ProtocolCmAddParty allocates and initializes any dynamic resources needed for the party being added to the call. From ProtocolCmAddParty, a call manager or MCM driver communicates with network control devices or other media-specific agents, as necessary, to add the specified party to the multipoint call.

If the client passed in call parameters that did not match those already established for the multipoint VC, the call manager or MCM driver can, for example:

  • Set up the per-party traffic parameters if the underlying network medium supports this feature on multipoint VCs
  • Reset the client-supplied traffic parameters to those originally established for the VC
  • Change the call parameters for the VC and, for every party currently connected on it
  • Fail the client's attempt to add a party

ProtocolCmAddParty can complete synchronously or, more probably, asynchronously with NdisCmAddPartyComplete, in the case of a call manager, or NdisMCmAddPartyComplete, in the case of an MCM driver. Whether the call manager or MCM driver completes the operation synchronously or asynchronously, it passes the buffered call parameters to NDIS.

The call to Ndis(M)CmAddPartyComplete causes NDIS to call the client's ProtocolClAddPartyComplete function. If the client's request to add the party succeeded and if the signaling protocol allows the call manager or MCM driver to modify the call parameters, ProtocolClAddPartyComplete should test the CALL_PARAMETERS_CHANGED flag in the buffered CO_CALL_PARAMETERS structure to determine whether the call parameters were modified. The signaling protocol determines what the client can do if it finds the modifications to CO_CALL_PARAMETERS unacceptable. Usually, a client calls NdisClDropParty in this case (see Dropping a Party from a Multipoint Call).


Dropping a Party from a Multipoint Call

A connection-oriented client that serves as the root of a multipoint call must eventually drop each party from that call with NdisClDropParty or NdisClCloseCall.

A client drops a party from a call in the following situations:

  • Before initiating the tear down of a multipoint call with NdisClCloseCall (see Client-Initiated Request to Close a Call), a client must drop all but the last party with successive calls to NdisClDropParty. The client specifies the last party to drop from the call with NdisClCloseCall.
  • In response to a remote party's request to be dropped from a multipoint call (see Incoming Request to Drop a Party from a Multipoint Call), a client, from its ProtocolClIncomingDropParty function, calls NdisClDropParty.

A client's call to NdisClDropParty causes NDIS to call the ProtocolCmDropParty function of the call manager or MCM driver that shares the same NdisVcHandle to the multipoint VC.

The following figure shows the client of a call manager requesting to drop a party from a multipoint call.

Dropping a Party From a Multipoint Call Through a Call Manager

The next figure shows the client of a call manager requesting to drop a party from a multipoint call.

Dropping a Party From a Multipoint Call Through an MCM Driver

ProtocolCmDropParty communicates with network control devices to drop a party from an existing multipoint call. NDIS can pass to ProtocolCmDropParty a pointer to a buffer containing data (supplied to the client in the call to NdisClDropParty). ProtocolCmDropParty must send any such data across the network before the connection is dropped.

ProtocolCmDropParty can complete synchronously, or more probably, asynchronously with NdisCmDropPartyComplete, in the case of a call manager, or NdisMCmDropPartyComplete, in the case of an MCM driver.

The call to Ndis(M)CmDropPartyComplete causes NDIS to call the client's ProtocolClDropPartyComplete function. If the client is in the process of tearing down a multipoint VC that it created, ProtocolClDropPartyComplete can call NdisClDropParty with any valid NdisPartyHandle to one of the remaining parties on the client's active multipoint VC. If only one party remains on its multipoint VC, the client should drop that party by passing its NdisPartyHandle to NdisClCloseCall (see Client-Initiated Request to Close a Call).


Incoming Request to Drop a Party from a Multipoint Call

A call manager or MCM driver is alerted to an incoming request from a remote party to drop that party from a multipoint call by signaling messages from the network. A call manager or MCM driver can also signal an incoming request to drop a party if it detects network problems that prevent further data transfers on the VC.

If the party being dropped from the call is not the last party on the VC, a call manager calls NdisCmDispatchIncomingDropParty. An MCM driver calls NdisMCmDispatchIncomingDropParty. If the party being dropped is the last party on the VC, a call manager calls NdisCmDispatchIncomingCloseCall, and an MCM driver calls NdisMCmDispatchIncomingCloseCall (see Incoming Request to Close a Call).

A call to Ndis(M)CmDispatchIncomingDropParty causes NDIS to call the client's ProtocolClIncomingDropParty function.

The following shows an incoming request through a call manager to drop a party through a multipoint call.

Incoming Request Through a Call Manager to Drop a Party From a Multipoint Call

The next figure shows an incoming request through an MCM driver to drop a party through a multipoint call.

Incoming Request Through an MCM Driver to Drop a Party From a Multipoint Call

ProtocolClIncomingDropParty should carry out any protocol-determined operations for dropping the party from the client's multipoint VC. If the party being dropped is not the last party on the VC, ProtocolClIncomingDropParty must call NdisClDropParty (see Dropping a Party from a Multipoint Call). If the party being dropped is the last party on the VC, ProtocolClIncomingDropParty must call NdisClCloseCall (see Client-Initiated Request to Close a Call).


Sending and Receiving Data

Transferring data involves sending or receiving packets over an established and activated VC.

Note Protocol drivers must not call NdisCoSendPackets to send data to a VC after calling NdisClCloseCall for that VC.


Sending Packets on a VC

To send packets over the network, a connection-oriented client or call manager calls NdisCoSendPackets. A connection-oriented client associated with an MCM driver also calls NdisCoSendPackets. An MCM driver, however, never calls NdisCoSendPackets; instead, since the interface between the call manager and MCM driver is internal to the MCM driver, the MCM driver passes packets directly to the NIC without notifying NDIS.

The following figure shows a client or call manager sending packets through a miniport driver.

Sending Packets from a Client or Call Manager Through a Miniport Driver

The next figure shows a client sending packets through an MCM driver.

Sending Packets from a Client Through an MCM Driver

Before calling NdisCoSendPackets, the client or call manager should set up an array of packet pointers in the same order that the packets should be sent over the wire. The client or a call manager then calls NdisCoSendPackets, passing (among other things) a pointer to the array of packet pointers and an NdisVcHandle that identifies the VC on which the packets should be sent.

As soon as the client or call manager calls NdisCoSendPackets, it relinquishes ownership of the following:

  • All packet descriptors accessible at PacketArray
  • All buffers mapped by the buffer descriptors chained to those packet descriptors
  • All out-of-band (OOB) data blocks associated with the packet descriptors, including any medium-specific buffers specified in the OOB blocks

A call to NdisCoSendPackets causes NDIS to call the miniport driver's MiniportCoSendPackets function. MiniportCoSendPackets should transmit each packet in the array sequentially, preserving the order of packets in the array. MiniportCoSendPackets can call NdisQueryPacket to extract information, such as the number of buffer descriptors chained to the packet and the total size in bytes of the requested transfer.

MiniportCoSendPackets can call NdisGetFirstBufferFromPacket(Safe), NdisQueryBuffer(Safe), or NdisQueryBufferOffset to extract information about individual buffers containing the data to be transmitted. MiniportCoSendPackets can retrieve protocol-supplied OOB information associated with each packet by using the appropriate NDIS_GET_PACKET_XXX macros. The MiniportCoSendPackets function usually ignores the Status member of the NDIS_PACKET_OOB_DATA block, but it can set this member to the same status that it subsequently passes to NdisMCoSendComplete.

Rather than relying on NDIS to queue and resubmit send packets whenever MiniportCoSendPackets has insufficient resources to transmit the given packets, a connection-oriented miniport manages its own internal packet queuing. The miniport must hold incoming send packets in its internal queue until they can be transmitted over the network. This queue preserves the protocol-determined ordering of packet descriptors incoming to the miniport's MiniportCoSendPackets function.

A connection-oriented miniport driver must complete each incoming send packet with NdisMCoSendComplete. It cannot call NdisMSendResourcesAvailable. A connection-oriented miniport driver should never pass STATUS_INSUFFICIENT_RESOURCES to NdisMCoSendComplete with a protocol-allocated packet descriptor that was originally submitted to its MiniportCoSendPackets function.

The call to NdisMCoSendComplete causes NDIS to call the ProtocolCoSendComplete function of the client that initiated the send operation. ProtocolCoSendComplete performs any postprocessing necessary for a completed transmit operation, such as notifying the client that originally requested the protocol to send data over the network on the VC.

Completion of a send operation usually implies that the underlying NIC driver actually has transmitted the given packet over the network. However, the driver of an "intelligent" NIC can consider a send complete as soon as it downloads the net packet to its NIC.

After ProtocolCoSendComplete is called, the driver regains ownership of the following protocol-allocated resources:

  • The packet descriptor
  • All buffer descriptors chained to the packet descriptor that map buffers containing the net packet data and any protocol-allocated buffers mapped by these descriptors
  • Any OOB block associated with the packet descriptor
  • Any protocol-allocated buffer specified in the OOB block

Although NDIS always submits protocol-supplied packet arrays to the underlying miniport driver in the protocol-determined order passed in calls to NdisCoSendPackets, the underlying driver can complete the given packets in random order. That is, every bound protocol can rely on NDIS to submit the packets the protocol passes to NdisCoSendPackets in FIFO order to the underlying driver, but no protocol can rely on that underlying driver to call NdisMCoSendComplete with those packets in the same order.


Receiving Packets on a VC

A connection-oriented miniport driver or MCM driver calls NdisMCoIndicateReceivePacket to indicate one or more received packets up to a connection-oriented client or call manager. If the miniport driver or MCM driver handles interrupts, it calls NdisMCoIndicateReceivePacket from its MiniportHandleInterrupt function.

The following figure shows a miniport driver indicating received packets.

Receiving Packets Through a Miniport Driver

The next figure shows an MCM driver indicating received packets.

Receiving Packets Through an MCM Driver

In the call to NdisMCoIndicateReceivePacket, the miniport driver or MCM driver passes a pointer to an array of packet descriptor pointers. The miniport driver or MCM driver also passes an NdisVcHandle that identifies the VC on which the packets were received. Before calling NdisMCoIndicateReceivePacket, the miniport driver or MCM driver must set up a packet array (see Receiving Data).

The call to NdisMCoIndicateReceivePacket causes NDIS to call the ProtocolCoReceivePacket function of the protocol driver (connection-oriented client or call manager) that shares the indicated VC with the miniport driver. The ProtocolCoReceivePacket function processes the receive indication.

After some miniport driver-determined number of calls to NdisMCoIndicateReceivePacket, the miniport driver must call NdisMCoReceiveComplete to indicate the completion of the previous receive indications made with one or more calls to NdisMCoIndicateReceivePacket. The call to NdisMCoReceiveComplete causes NDIS to call the ProtocolReceiveComplete function of the connection-oriented client or call manager.

If a protocol does not return the miniport driver-allocated resources for a receive indication promptly enough, the miniport driver or MCM driver can call NdisMCoIndicateStatus with NDIS_STATUS_RESOURCES to alert the offending protocol that the miniport driver or MCM driver is running low on available packet or buffer descriptors (or even on NIC receive buffer space) for subsequent receive indications.

For more information on receiving packets, see Receiving Data).


Tearing Down a Call

A connection-oriented client can initiate the teardown of an outgoing call that it has made or an incoming call that it has accepted. Similarly, a remote party can initiate the teardown of an outgoing call that it has made or an incoming call that it has accepted.


Client-Initiated Request to Close a Call

If a client is closing a multipoint call to which more than one party is still connected, it must first call NdisClDropParty as many times as necessary to drop all but the last party from the call (see Dropping a Party from a Multipoint Call).

A client initiates the closing of a call with NdisClCloseCall. The following figure shows a client initiating the closing of a call through a call manager.

Client Initiates a Request to Close a Call Through a Call Manager

The next figure shows a client initiating the closing of a call through a call manager.

Client Initiates a Request to Close a Call Through an MCM Driver

A connection-oriented client usually calls NdisClCloseCall in any one of the following circumstances:

  • To close an established outgoing or incoming call.
  • From the ProtocolClIncomingCloseCall function to tear down an established call (see Incoming Request to Close a Call).
  • From the ProtocolClIncomingCallQoSChange function to tear down an established call if a QoS change proposed by the remote party is unacceptable (see Incoming Request to Change Call Parameters).
  • From the ProtocolClModifyCallQoSComplete function to tear down an established call if a QoS change proposed by the client is unacceptable to the remote party (see Client-Initiated Request to Change Call Parameters).

A client's call to NdisClCloseCall causes NDIS to call the call manager's or MCM driver's ProtocolCmCloseCall function. ProtocolCmCloseCall must communicate with network control devices to terminate a connection between the local node and a remote node.

If ProtocolCmCloseCall is passed an explicit CallMgrPartyContext, then the call being terminated is a multipoint call. The call manager or MCM driver must perform any necessary network communication with its networking hardware, as appropriate to its media type, to terminate the call as a multipoint call.

NDIS can pass ProtocolCmCloseCall a pointer to a buffer containing data supplied by the client in the call to NdisClClose. This data can be diagnostic data indicating why the call was closed or any other data required by the signaling protocol. ProtocolCmCloseCall must send any such data across the network before completing the call termination. If sending data concurrent with a connection being terminated is not supported, a call manager or MCM driver should return NDIS_STATUS_INVALID_DATA.

ProtocolCmCloseCall can complete synchronously or, more probably, asynchronously with NdisCmCloseCallComplete (in the case of a call manager) or NdisMCmCloseCallComplete (in the case of an MCM driver). A call to Ndis(M)CmCloseCallComplete causes NDIS to call the client's ProtocolClCloseCallComplete function.

The call manager or MCM driver must then initiate deactivation of the VC used for the call by respectively calling NdisCmDeactivateVc or NdisMCmDeactivateVc (see Deactivating a VC). The creator of the VC (client, call manager, or MCM driver) can then optionally initiate deletion of the VC (see Deleting a VC).


Incoming Request to Close a Call

When the remote client closes a call, the local call manager or MCM driver must indicate this incoming request to the local client. To indicate such a request, a call manager calls NdisCmDispatchIncomingCloseCall with the CloseStatus set to NDIS_STATUS_SUCCESS (see the following figure).

Incoming Request Through a Call Manager to Close a Call

An MCM driver calls NdisMCmDispatchIncomingCloseCall to indicate an incoming request to close a call (see the following figure).

Incoming Request Through an MCM Driver to Close a Call

A call manager or MCM driver also can call Ndis(M)CmDispatchIncomingCloseCall in the following situations:

  • From its ProtocolCmIncomingCallComplete function if it determines that the connection-oriented client is requesting an unacceptable change in call parameters in response to an incoming call previously indicated by the call manager or MCM driver (see Incoming Request to Change Call Parameters).
  • If abnormal network conditions force the call manager to tear down active calls.

The call to Ndis(M)CmDispatchIncomingCloseCall causes NDIS to call the ProtocolClIncomingCloseCall function of the connection-oriented client on that connection. ProtocolClIncomingCloseCall should carry out any protocol-determined operations, such as notifying its own client or clients that the connection is being broken. If the call to be closed is a multipoint VC created by the client, ProtocolClIncomingCloseCall must call NdisClDropParty one or more times until only a single party remains on the VC (see Dropping a Party from a Multipoint Call).

ProtocolClIncomingCloseCall must then call NdisClCloseCall (with the handle to the last party on the VC if the VC is a multipoint VC created by the client) to acknowledge that the client will no longer attempt to send or expect to receive data on this particular VC. If the call manager or MCM driver created this VC, ProtocolClIncomingCloseCall should return control after it calls NdisClCloseCall. The call manager or MCM driver must also deactivate the VC (see Deactivating a VC).

If the client originally created this VC for an outgoing call and CloseStatus is NDIS_STATUS_SUCCESS, ProtocolClIncomingCloseCall can optionally tear down the VC with NdisCoDeleteVc (see Deleting a VC) or reuse the VC for another call. If CloseStatus is not NDIS_STATUS_SUCCESS, ProtocolClIncomingCloseCall must call NdisCoDeleteVc.

If the call manager or MCM driver originally created this VC for an incoming call, the call manager or MCM driver can optionally delete the VC by respectively calling NdisCoDeleteVc or NdisMCmDeleteVc (see Deleting a VC).


Obtaining and Setting Information

A connection-oriented client, call manager, or MCM driver can query or set information maintained by other drivers on a binding. In addition, a miniport driver or an MCM driver can indicate miniport driver status to other drivers on a binding.


Querying or Setting Information

A connection-oriented client or call manager calls NdisCoRequest to query or set information maintained by another protocol driver on a binding or by the underlying miniport driver.

Before it calls NdisCoRequest, a client or call manager allocates a buffer for its request and initializes an NDIS_REQUEST structure. This structure specifies the type of request (query or set), identifies the information (OID) being queried or set, and points to buffers used for passing OID data.

If the connection-oriented client or call manager passes a valid NdisAfHandle (see Address Families), NDIS calls the ProtocolCoRequest function of each protocol driver on the binding (see the following figure).

Query or Set of Client or Call Manager Information

If the underlying miniport driver is an MCM driver, NDIS calls the ProtocolCoRequest function of the MCM driver (see the following figure):

Query or Set of an MCM Driver's Call Manager Information

If the connection-oriented client or call manager passes a NULL address family handle, NDIS calls the MiniportCoRequest function of the underlying miniport driver or MCM driver.

The following figure shows a client or a call manager querying or setting miniport driver information.

Query or Set of Miniport Driver Information

The next figure shows a client querying or setting an MCM driver's miniport driver information.

Query or Set of an MCM Driver's Miniport Driver Information

To query or set information maintained by its clients, an MCM driver calls NdisMCmRequest (see the following figure).

MCM Driver-Iniatiated Query of Client Information

The caller of NdisCoRequest or NdisMCmRequest can narrow the scope of the request by specifying a VC handle that identifies a VC, or a party handle that identifies a party on a multipoint VC. Passing a NULL NdisVcHandle makes such a request global in nature, whether the request is directed to the client, call manager, miniport driver, or MCM driver.

ProtocolCoRequest or MiniportCoRequest can complete synchronously, or these functions can complete asynchronously with NdisCoRequestComplete. The call to NdisCoRequestComplete causes NDIS to call the ProtocolCoRequestComplete function of the driver that called NdisCoRequest.


Indicating Miniport Driver Status

To report a change in the status of a connection-oriented NIC or a change in the status of a particular VC active on the NIC, a connection-oriented miniport driver calls NdisMCoIndicateStatus. If the miniport driver is reporting a change in the status of a particular VC, it supplies an NdisVcHandle that identifies the VC.

The following figure shows a miniport driver indicating status.

Indicating Miniport Driver Status

The next figure shows an MCM driver indicating status.

Indicating Miniport Driver Status From an MCM Driver

The call to NdisMCoIndicateStatus causes NDIS to call the ProtocolCoStatus function of all protocol drivers bound to the NIC if no NdisVcHandle is supplied. If the miniport driver supplies an NdisVcHandle, NDIS calls only those protocol drivers with which the miniport driver shares the VC handle. When an MCM driver calls NdisMCoIndicateStatus, NDIS calls the ProtocolCoStatus function only of bound connection-oriented clients since there is no call manager bound to the MCM driver.

The ProtocolCoStatus function can log the change in status and possibly take corrective action. For example, when a miniport driver calls NdisMCoIndicateStatus to report operational problems in its NIC, a protocol might call NdisReset (or NDIS itself can call the miniport driver's MiniportReset function) to try restoring the NIC to a working condition (see Reset).


Reset

A protocol bound to a connection-oriented miniport driver or MCM driver can call NdisReset to cause the underlying miniport driver or MCM driver to reset its NIC. NDIS itself can call the miniport driver's or MCM driver's MiniportReset function to reset the NIC.

Note AF, SAP, and VC handles that are active and valid before a reset are active and valid after the reset.

The following figure shows a client issuing a reset request to a miniport driver.

Resetting a NIC Through a Miniport Driver

The next figure shows a client issuing a reset request to an MCM driver.

Resetting a NIC Through an MCM Driver

When an underlying connection-oriented driver is resetting its NIC, NDIS notifies each bound protocol by calling the protocol's ProtocolCoStatus function with NDIS_STATUS_RESET_START. NDIS then call's the protocol's ProtocolStatusComplete function.

NDIS will not accept protocol-initiated sends and requests to a miniport driver or MCM driver while the miniport driver's or MCM driver's NIC is being reset. While a reset is in progress, a protocol driver must not attempt to send packets to the miniport driver with NdisCoSendPackets or request information from the miniport driver with NdisCoRequest.

MiniportReset performs any device-dependent actions that are required to reset the NIC. MiniportReset can complete synchronously, or it can complete asynchronously with a call to NdisMResetComplete:

  • If the reset completes synchronously, NDIS calls each bound protocol's ProtocolCoStatus function with NDIS_STATUS_RESET_END. NDIS then calls the protocol's ProtocolStatusComplete function.
  • If the reset completes asynchronously, NDIS calls each bound protocol's ProtocolCoStatus function with NDIS_STATUS_RESET_END. NDIS then calls the protocol's ProtocolStatusComplete function. If the reset was initiated by a bound protocol, NDIS also calls the ProtocolResetComplete function of that protocol.


Installing Network Components

This section provides detailed information about the components and files that are used to install network components and how to create information (INF) files for them.

This section includes the following topics:

Components and Files Used to Install Network Components

Creating Network INF Files


Components and Files Used for Network Component Installation

The following components and files are used to install network components on Windows® 2000 and later versions of the operating system:

  • A required class installer and optional co-installer
  • One or more information (INF) files
  • An optional notify object
  • An optional network migration DLL and associated files

In addition to one or more of the above components, a vendor also supplies the following files:

  • One or more device driver image (.sys) files and driver library (.dll ) files
  • An optional driver catalog file
  • An optional text-mode setup information file (txtsetup.oem)

Class installer and co-installer

Network components are installed by the network class installer or by a custom class installer created by the vendor. A class installer is a dynamic-link library (DLL) that installs, configures, or removes devices of a particular class in the system. For more information about class installers, see Writing a Class Installer.

If the network class installer does not provide all the features that a vendor requires, a vendor can customize the installation process by writing a device co-installer. A co-installer is a Win32® DLL that assists in device installation on machines using Windows 2000 and later versions of the operating system. Co-installers are called by the system Device Installer as "helpers" or filters for Class Installers. For more information about co-installers, see Writing a Co-installer.

INF files

Each network component must have an information (INF) file that the network class installer uses to install the component. Network INF files are based on the common INF file format. For more information about the INF file format, see INF File Sections and Directives.

For detailed information on creating INF files for network components, see Creating Network INF Files.

Notify object

A software component, such as a network protocol, client, or service, can have a notify object. A notify object can display a user interface, notify the component of binding events so that the component can exercise some control over the binding process, and provide for conditional installations and conditional removals. For more information about notify objects, see Notify Objects for Network Components.

A network adapter cannot have a notify object. It can have co-installers. For more information about co-installers, see Writing a Co-installer.

Network migration DLL

Network vendors whose drivers do not ship with Windows 2000 and later versions of the operating system should provide upgrade support for such components. The network upgrade process migrates a network component's pre-upgrade parameter values from Windows NT® 3.51 or Windows NT 4.0 to Windows 2000. For more information on upgrading network components, see Network Upgrade Functions.

Vendor-supplied files

A vendor supplies one or more drivers for the device, which typically consists of a driver image (.sys ) file and a driver library (.dll ) file. A vendor may also supply an optional driver catalog file. A vendor gets a digital signature by submitting its driver package to the Windows Hardware Quality Lab (WHQL) for testing and signing. WHQL returns the package with a catalog (.cat ) file. The vendor must list the catalog file in the INF file for the device.

An optional text-mode setup information file (txtsetup.oem) may also be supplied by the vendor. If a network device is required to boot the machine, the driver or drivers for the device must be included in the operating system kit or the vendor of such a device must provide a txtsetup.oem file. The txtsetup.oem file contains information that is used by the system setup components to install the device during text-mode setup.


Creating Network INF Files

A network INF file is based on the standard INF file format but also includes network-specific items, such as network-specific sections, directives, section entries, and values. The following description of network INF files assumes an understanding of base INF files. Read the description of base INF files before attempting to create a network INF file. For more information about base INF files, see INF File Sections and Directives.

Important Network INF files for Microsoft® Windows® 2000 and later versions are not compatible with network INF files for Microsoft Windows NT® 4.0 and earlier versions. To support the installation of a network component on Windows 2000 and later versions, as well as on Windows NT 4.0, you must create one INF file for Windows 2000 and later versions, and another INF file for Windows NT 4.0.

A single INF file can be used to install a network component on various Windows platforms. For more information, see INF File Sections and Directives.

The INF file requirements vary by type of network component. For more information about the INF file requirements for each type of network component, see Summary of Installation Requirements for Network Components.


Network INF File Naming Conventions

File names for INF files that ship with Windows 2000 must conform to the following requirements:

  • Cannot exceed eight characters. INF files that do not ship with Windows 2000 are not bound by this limitation.
  • Uses the .inf file name extension
  • The file name begins with net to indicate that the network class installer is used to process the INF file, except INF files for IrDA devices, which must begin with ir.
  • Indicates either the manufacturer of the network components installed by the INF file, describes the components, or includes the product model number.

The following are examples of the file name components that are used to create valid network INF file names:

File name components | Valid file name
net + manufacturer | netMsft.inf
net + product description | netDlc.inf
net + product model number | net999.inf


Version Section

The Version section of a network INF file has the following network-specific entries:

Class

The Version section should contain a Class entry which identifies the class of network component that is installed by the file.

There are four network classes:

Net
Specifies a physical or virtual network adapter. NDIS intermediate drivers, which export virtual network adapters, are included in the Net class.
NetTrans
Specifies a network protocol, such as TCP/IP, IPX, a connection-oriented client, or a connection-oriented call manager.
NetClient
Specifies a network client, such as the Microsoft Client for Networks or the NetWare Client. A NetClient component is considered to be a network provider and, if it provides print services over the network, it is also considered to be a print provider.
NetService
Specifies a network service, such as a file service or a print service.

Note Infrared Data Association (IrDA) compliant devices are not categorized as any of the previous four network classes, even though they are installed by the network class installer. An INF file that is used to install an IrDA device should have a Class value of Infrared. This class includes both Serial-IR and Fast-IR devices.

ClassGuid

The Version section must contain a ClassGuid entry. The network class installer uses the ClassGuid entry to determine the class of network component being installed.

There are four network ClassGuid values, each of which corresponds to a network class:

Network Class | ClassGuid
Net | {4D36E972-E325-11CE-BFC1-08002BE10318}
NetTrans | {4D36E975-E325-11CE-BFC1-08002BE10318}
NetClient | {4D36E973-E325-11CE-BFC1-08002BE10318}
NetService | {4D36E974-E325-11CE-BFC1-08002BE10318}

An INF file for an IrDA device should have a ClassGuid value of
{6bdd1fc5-81d0-bec7-08002be2092f}.

Signature and OS Entries

The Signature entry can be one of three possible values, depending on which platform the INF file uses:

Value | Platform
$Windows 95$ | Windows 95/98/Me only
$Windows NT$ | NT-based operating systems
$Chicago$ | All Windows operating systems

Note An INF file that has a $Windows 95$ signature will not run on Windows 2000 and later versions of the operating system. Conversely, an INF file that has a $Windows NT$ signature will not run on Windows 95/98/Me.

If the INF file will be used on both Windows 95/98/Me and Windows 2000 and later versions, the INF file must also have the following line in the Version section:

Compatible=1

A network INF file that has a $Chicago$ signature will not run on Windows 2000 and later versions unless the Compatible entry in the Version section is set to 1.

Windows Me Directive

The Windows Me extension directive for network device INF files gives you the ability to specify Windows Me specific installation information. When this directive is present in the INF file, Windows Me will install from the DDInstall.ME section. You must include the following settings in the Version section of your network INF file to enable the Windows Me directive:

  • Signature=$Chicago$.
  • Class=Net, NetTrans, NetClient or NetService and the corresponding ClassGuid is defined.
  • Compatible=1.
  • MillenniumPreferred=.ME.
  • Note The period before "ME" is required.

Version Section Example

The following is an example of a Version section for an INF file that installs a network adapter:

[Version]
Signature = $Chicago$
Compatible = 1
Class=Net
ClassGuid = {4D36E972-E325-11CE-BFC1-08002BE10318}
Provider = %Msft%
DriverVer=08/20/1999

Note The Provider entry indicates the developer of the INF file, not the developer of the component that is installed by the INF file.


Models Section

The Models section of an INF file contains an entry of the following format for each type of component installed by the INF file:

[device-description=install-section.name,hw-id[,compatible-id…]

For a detailed description of this entry, see Creating an INF File.

The hw-id (also known as the device, hardware, or component ID) for a network adapter must match the hardware ID supplied by the adapter to the PnP Manager.

The hw-id for a network software component should consist of a provider name, followed by an underscore, and a manufacturer name or the product name, for example:

  • MS_DLC
  • MS_IBMDLC

A provider name identifies the provider of the INF file. A manufacturer name identifies the manufacturer of the software component. The product name identifies the software component.


DDInstall Section

A DDInstall section of a network INF file has the following network-specific entries:

Characteristics

Each DDInstall section in a network INF file must have a Characteristics entry. The Characteristics entry specifies certain characteristics of the network component being installed and may limit the user's actions regarding that component. For example, the Characteristics entry can specify whether the component supports a user interface, whether it can be removed, or whether it is hidden from the user.

The Characteristics entry can have one or more of the following values (multiple values are summed together):

Hex Value | Name | Description
0x1 | NCF_VIRTUAL | Component is a virtual adapter.
0x2 | NCF_SOFTWARE_ENUMERATED | Component is a software-enumerated adapter.
0x4 | NCF_PHYSICAL | Component is a physical adapter.
0x8 | NCF_HIDDEN | Component should not be shown in any user interface.
0x10 | NCF_NO_SERVICE | Component does not have an associated service (device driver).
0x20 | NCF_NOT_USER_ REMOVABLE | Component cannot be removed by the user (for example, through the Control Panel or Device Manager).
0x40 | NCF_MULTIPORT_INSTANCED_ ADAPTER | Component has multiple ports, each of which is installed as a separate device. Each port has its own hw-id (component ID) and can be individually installed. This is applicable only to EISA adapters.
0x80 | NCF_HAS_UI | Component supports a user interface (for example, the Advanced Page or a custom properties sheet).
0x400 | NCF_FILTER | Component is a filter.
0x4000 | NCF_NDIS_PROTOCOL | Component requires the unload event that is provided by the binding engine to the NetTrans device setup class (typically used by filter Intermediate drivers which use the NetService device setup class).

The following combinations of Characteristics values are not allowed:

  • NCF_VIRTUAL, NCF_SOFTWARE_ENUMERATED, and NCF_PHYSICAL are mutually exclusive.
  • NCF_NO_SERVICE cannot be used with NCF_VIRTUAL, NCF_SOFTWARE_ENUMERATED, or NCF_PHYSICAL. A virtual, software-enumerated, or physical adapter must always have an associated service (device driver).

The following is an example of a Characteristics entry for a physical adapter that supports a user interface:

Characteristics = 0x84; NCF_PHYSICAL, NCF_HAS_UI

BusType

A DDInstall section for a physical network adapter must contain a BusType entry that specifies the type of bus (such as PCI or ISA) on which the adapter can function. The possible values for the BusType entry are specified by the INTERFACE_TYPE enumeration in the NDIS header file (ndis.h) as follows:

BusType Entry | Value
ISA | 1
EISA | 2
MicroChannel | 3
TurboChannel | 4
PCIBus | 5
VMEbus | 6
NuBus | 7
PCMCIABus | 8
Cbus | 9
MPIBus | 10
MPSABus | 11
PNPISABus | 14
PNPBus | 15

Note If an adapter can function on more than one type of bus, the INF file that installs that adapter should contain a DDInstall section for each bus type.

For example, if an adapter can function on both the ISA bus and the PnPISA bus, the INF file for that adapter should contain a DDInstall section for ISA and a DDInstall section for PnPISA. The BusType entry in each such DDInstall section should specify the appropriate bus type for that section as follows:

[a1.isa]
BusType=1

[a1.pnpisa]
BusType=14

EisaCompressedId and AdapterMask

The DDInstall section of an INF file that installs an EISA network adapter must include an EisaCompressedId entry that specifies both an EISA Compressed ID and an adapter mask for the adapter. The following example illustrates this case:

EisaCompressedId = 0x24322432
AdapterMask = 0xfffff

Port1DeviceNumber and Port1FunctionNumber

The DDInstall section of an INF file that installs a multiport network adapter must include either a Port1DeviceNumber entry or a Port1FunctionNumber entry. Specifying such an entry causes the adapter's port information to be displayed in the Connection Properties dialog box (which is accessed through the Network and Dial-Up Connections folder) when you select the adapter name or icon.

  • If an adapter's port numbers map sequentially to PCI device numbers, use the Port1DeviceNumber entry. Set Port1DeviceNumber to the first PCI device number in the sequence. For example, if PCI device number 4 maps to port 1, PCI device number 5 maps to port 2, PCI device number 6 maps to port 3, and so forth, use the following entry:
    Port1DeviceNumber = 4
  • If an adapter's port numbers map sequentially to PCI function numbers, use the Port1FunctionNumber entry. Set Port1FunctionNumber to the first PCI function number in the sequence. For example, if PCI function number 2 maps to port 1, PCI function number 3 maps to port 2, PCI function number 4 maps to port 3, and so forth, use the following entry:
    Port1FunctionNumber = 2

Note It is assumed that the mapping of PCI device numbers or PCI functions to port numbers is static. It is also assumed that the adapter's ports are numbered sequentially.

The Port1DeviceNumber and Port1FunctionNumber entries are mutually exclusive. If both entries are present in a given DDInstall Section, only the Port1DeviceNumber entry is used.

MaxInstance

MaxInstance is a Windows 98/Me specific directive that limits the number of instances of a network component that a user can install. An example of this directive follows:

MaxInstance=6

When a user adds a network component to their computer, they will receive the following error message if the MaxInstance value is exceeded:

Your system allows only <number> instances of <component>

The <number> field is the number of the components that are installed on the system plus one and <component> is the name of the component that the user installed.

If MaxInstance is exceeded while installing a network adapter, protocols will not be able to bind to that adapter.


Remove Section

Remove sections are supported for NetClient, NetTrans, and NetService components but not for Net components (adapters). The network class installer does not keep track of adapter instances. A Remove section that removes files that are shared by other adapters or by multiple instances of an adapter could render those adapters or adapter instances inoperative.

If it is necessary to remove a driver file that is used by a Net component, use a co-installer that keeps track of all drivers that are using the file. Such a co-installer should also track multiple instances of the same device, as well as drivers for multiple devices. For more information on co-installers, see Creating an INF File.


ControlFlags Section

The ControlFlags section of a network INF file typically has one or more ExcludeFromSelect entries. Each ExcludeFromSelect entry specifies a network component that will not be displayed to the end user as an option during a manual installation.

The ControlFlags section in a network INF file must contain an ExcludeFromSelect entry for each Plug and Play adapter that it installs, and for any software component that should be added programmatically rather than manually by the user.

Adapters that are not compatible with Plug and Play must be added manually by the user and therefore should not be listed in the ControlFlags section. For example, ISA and EISA adapters must be manually added by the user.

Note An ExcludeFromSelect entry performs a different function than does the NCF_HIDDEN value of the Characteristics entry in the DDInstall section. For more information, see DDInstall Section.

An ExcludeFromSelect entry prevents an adapter or software component from being listed in the Select Component for Installation dialog box. The adapter or component, however, can still be listed in the Connections dialog box. The NCF_HIDDEN value prevents the adapter or component from being displayed in any part of the user interface, including the Connections dialog box.

For more information on the ControlFlags section, see INF ControlFlags Section.


Add-registry-sections

An INF file contains one or more add-registry-sections for each component that it installs. An add-registry-section adds keys and values to the registry. The DDInstall section of an INF file contains an AddReg directive that references one or more add-registry-sections. For more information on the add-registry-section and the AddReg directive, see Creating an INF File.

Adding Keys and Values to Instance Keys

One or more add-registry-sections can add keys and values to the instance key for a component to accomplish any of the following:

  • Set static parameters for a component — that is, configuration parameters that cannot be modified through a user interface. For more information, see Setting Static Parameters.
  • Specify the number of endpoints (also known as channels, circuits or bearer channels) for a WAN adapter. For more information, see Specifying WAN Endpoints for a WAN Adapter .
  • Specify keys and values for an ISDN adapter. For more information, see Specifying ISDN Keys and Values for an ISDN Adapter.
  • Require the installation of another network component. For more information, see Requiring the Installation of Another Network Component.
  • Specify values that support a custom properties sheet for a network adapter. For more information, see Specifying Custom Property Pages for Network Adapters.

Adding Keys and Values to a NetClient Component

An add-registry-section in an INF file for a NetClient component must add a NetworkProvider key to the service key for that component. The NetworkProvider key has two values: a Name that specifies the name of the network provider, and a ProviderPath that specifies the full path to the network provider DLL. For more information, see Specifying the Name and Provider Path for a NetClient Component.

Creating the Ndi Key

Each network INF file must contain at least one add-registry-section that adds an Ndi key for the component installed by the file. The Ndi key is a network-specific key that is added to the instance key for the component. The keys and values that are added to the Ndi key vary according to the type of network component being installed and its capabilities. The Ndi key specifies the following:

  • HelpText value for a NetTrans, NetClient, or NetService component. For more information, see Adding a HelpText value.
  • Values for a notify object. For more information, see Adding Registry Values for a Notify Object.
  • Service-related values. For more information, see Adding Service-Related Values to the Ndi Key.
  • Binding interfaces. For more information, see Specifying Binding Interfaces.
  • Adapter configuration parameters for the Advanced page. For more information, see Specifying Configuration Parameters for the Advanced Properties Page.
  • Bundle membership. For more information, see Specifying Bundle Membership.

For a list of Ndi registry keys and values that are available in Windows 95/98/Me but not used in Windows 2000 and later versions, see Ndi Values and Keys Not Used in Windows 2000 and Later Versions.


Setting Static Parameters

An INF file sets a static parameter only once. This parameter cannot be reconfigured through a properties page in the user interface.

An add-registry-section adds a static parameter as a REG_SZ value to a component's instance key as shown in the following example:

[a1.staticparams.reg]
HKR,, MediaType, 0, "1"
HKR,, InternalId, 0, "232"

An add-registry-section can add any vendor-defined static parameter to a component's instance key.


Specifying WAN Endpoints for a WAN Adapter

A INF file for a WAN adapter must add a WanEndpoints value to the instance key for the adapter. WanEndpoints is a REG_DWORD value that specifies the number of endpoints (also known as channels, circuits or bearer channels) that are supported by the WAN adapter. For example, the WanEndpoints value for a basic rate interface (BRI) ISDN adapter is 2, whereas the WanEndpoints value for a primary rate interface (PRI) ISDN adapter is typically 23.

The following is an example of an add-registry-section that adds a WanEndpoints value of 2 for a BRI ISDN adapter:

[a1.reg]
HKR,, WanEndpoints, 0x00010001, 2


Specifying ISDN Keys and Values for an ISDN Adapter

In addition to a WanEndpoints value, an INF file for an ISDN adapter must add (through an add-registry-section) the following keys and values to the instance key for the adapter. For more information, see Specifying WAN Endpoints for a WAN Adapter.

  • IsdnNumDChannels

    Specifies the number of D-channels that are supported by the ISDN adapter.

  • sdnAutoSwitchDetect (Optional)

    Specifies whether the ISDN adapter supports automatic switch detection. A value of 1 indicates that the adapter supports automatic switch detection. A value of zero indicates that the adapter does not support automatic switch detection.

  • IsdnSwitchTypes

    Specifies the switch types that are supported by the ISDN adapter.

Switch | Description
ISDN_SWITCH_AUTO | Auto Detect (North America only)
ISDN_SWITCH_ATT | ESS5 (AT&T, North America)
ISDN_SWITCH_NI1 | National ISDN 1 (NI-1)
ISDN_SWITCH_NI2 | National ISDN 2 (NI-2)
ISDN_SWITCH_NT1 | Northern Telecom DMS 100 (NT-1)
ISDN_SWITCH_INS64 | NTT INS64 (Japan)
ISDN_SWITCH_1TR6 | German National (1TR6). This switch type is rarely used.
ISDN_SWITCH_VN3 | French National (VN3). This switch type is rarely used.
ISDN_SWITCH_NET3 | European ISDN (DSS1)
ISDN_SWITCH_DSS1 | European ISDN (DSS1)
ISDN_SWITCH_AUS | Australian National. This switch type is rarely used.
ISDN_SWITCH_BEL | Belgium National. This switch type is rarely used.
ISDN_SWITCH_VN4 | French National (VN4)
ISDN_SWITCH_SWE | Swedish National
ISDN_SWITCH_ITA | Italian National
ISDN_SWITCH_TWN | Taiwan

To specify multiple switch types, simply add the individual switch type values together.

The ISDN Wizard, which runs automatically during the installation of an ISDN component, allows the user to select one of the switch types specified by IsdnSwitchTypes. The selected switch type determines which other ISDN parameters the ISDN Wizard subsequently displays for configuration. These ISDN parameters include the phone number, the SPID (service profile identifier), the subaddress, and the multisubscriber number.

  • An IsdnNumBChannels value and a D-channel key for each D-channel

    The D-channel key is an zero-based index from 0 through 9 that identifies the D-channel. IsdnNumBChannels is a REG_DWORD value added to the D-channel key. IsdnNumBChannels specifies the number of B-channels supported by the D-channel.

The following is an example of an add-registry-section that adds ISDN keys and values to the instance key of an ISDN adapter. Two D-channels are specified for the adapter, and two B-channels are specified for each D-channel.

[ISDNadapter.reg]
HKR,,  WanEndPoints,         0x00010001, 4
HKR,,  IsdnNumDChannels,     0x00010001, 2
HKR,,  IsdnAutoSwitchDetect, 0x00010001, 1
HKR,,  IsdnSwitchTypes,      0x00010001, 0x00000004  ;NI1

HKR, 0, IsdnNumBChannels,    0x00010001, 2

HKR, 1, IsdnNumBChannels,    0x00010001, 2

The ISDN Wizard itself also adds ISDN keys and values to the instance key for an ISDN adapter, based on the parameter values specified by the user. The ISDN Wizard adds the following keys and values:

  • IsdnSwitchType

    A REG_DWORD that indicates the switch type that was selected by the user for the ISDN adapter.

  • IsdnMultiSubscriberNumbers value for each D-channel

    A REG_MULTI_SZ value that indicates the multisubscriber numbers that were specified by the user for the D-channel.

  • A B-channel key and an IsdnSpid, IsdnPhoneNumber, and/or an IsdnSubaddress value for each B-channel:
Key or Value | Description
B-channel key | A zero-based index that identifies the B-channel. The maximum value for a B-channel key is one less than the IsdnNumBchannels value assigned to the D-channel to which the B-channel belongs.
IsdnSpid | A REG_SZ value that indicates the SPID, if any, specified by the user for the B-channel.
IsdnPhoneNumber | The phone number, if any, specified by the user for the B-channel.
IsdnSubaddress | The subaddress, if any, specified by the user for the B-channel.

The following example is an ISDN adapter's registry section layout . Each registry key is enclosed in square brackets, for example: [keyname]. The ISDN keys and values that were added by the INF file for the ISDN adapter are highlighted in boldface text; the ISDN keys and values that were added by the ISDN Wizard appear in normal (non-boldface) text.

[…Enum\emumeratorID\device-instance-id]  ;ISDN adapter instance key
WanEndpoints=4
IsdnNumDChannels=2
IsdnAutoSwitchDetect=1
IsdnSwitchType=0x4  ;National ISDN 1

[…Enum\emumeratorID\device-instance-id\0]  ;D-channel 0
IsdnNumBChannels=2
IsdnMultiSubscriberNumbers=1234567 2345678 3456789

[…Enum\emumeratorID\device-instance-id\0\0]  ;B-channel 0 for D-channel 0
IsdnSpid=00555121200
IsdnPhoneNumber=5551212
IsdnSubaddress=

[…Enum\emumeratorID\device-instance-id\0\1]  ;B-channel 1 key for D-channel 0
IsdnSpid=00555121300
IsdnPhoneNumber=5551213
IsdnSubaddress=

[…Enum\emumeratorID\device-instance-id\1]  ;D-channel 1 key
IsdnNumBChannels=2
IsdnMultiSubscriberNumbers=8675309 2390125 7658156

[…Enum\emumeratorID\device-instance-id\1\0]  ;B-channel 0 for D-channel 1
IsdnSpid=00555987600
IsdnPhoneNumber=5559876
IsdnSubaddress=

[…Enum\emumeratorID\device-instance-id\1\0]  ;B-channel 1 for D-channel 1
IsdnSpid=00555876500
IsdnPhoneNumber=5558765
IsdnSubaddress=


Installing a Multiprotocol WAN NIC

A multiprotocol WAN NIC provides more than one WAN protocol. For example, such a NIC might allow the user to select ISDN, Frame Relay, or channelized T1. The user selects the WAN protocol during installation of the NIC or when configuring the NIC.

A vendor of a multiprotocol WAN NIC must provide a co-installer that installs a wizard page. (For more information on co-installers, see Writing a Co-installer). The wizard page prompts the user to select a WAN protocol:

  • If the user selects ISDN, the ISDN Wizard is displayed. The ISDN Wizard prompts the user for the ISDN switch type and, depending on the selected switch type, other ISDN parameter values. For more information, see Specifying ISDN Keys and Values for an ISDN Adapter.
  • If the user selects a WAN protocol other than ISDN, the Wizard adds the ShowIsdnPages registry value to the WAN NIC's instance key. The Wizard, in this case, sets ShowIsdnPages to zero to suppress the display of the ISDN Wizard. As long as ShowIsdnPages is zero, the ISDN Wizard is suppressed.

After the WAN NIC has been installed, the user can reconfigure the NIC, using the NIC's property page:

  • If the user changes the protocol from ISDN to another WAN protocol, the property page adds the ShowIsdnPages registry value to the WAN NIC's instance key, if necessary. The property page sets ShowIsdnPages to zero to suppress the display of the ISDN Wizard.
  • If the user changes the protocol to ISDN, the property page for the WAN NIC displays a dialog box that prompts the user to apply the change. When the user applies the change, the property page sets ShowIsdnPages to 1. When the user again opens the NIC's property page, the ISDN Wizard is displayed.

Note that the LowerRange binding interface for a multiprotocol WAN NIC that supports ISDN must be set to isdn. For more information, see Specifying Binding Interfaces. If the ShowIsdnPages registry value is not present and if the NIC's LowerRange is set to isdn, the ISDN Wizard is displayed during installation and configuration of the NIC. If ShowIsdnPages is set to zero, the ISDN Wizard is not displayed. If ShowIsdnPages is set to 1, the ISDN Wizard is displayed during configuration of the NIC.


Requiring the Installation of Another Network Component

A network component may require the installation of one or more other network components in order to function properly. A network INF file specifies each such dependency with a RequiredAll value. The RequiredAll value is added (through an add-registry-section) to the Ndi key of the network component that requires the installation of another network component.

The following example shows a RequiredAll entry in an add-registry-section:

[ndi.reg]
HKR, Ndi, RequiredAll, 0, "component id"

The component ID is the hw-id of the required network component. For more information, see Models Section. If a network component requires the installation of more than one other network component, use one RequiredAll entry for each network component that must be installed, as shown in the following example:

[HKR, Ndi, RequiredAll, 0, "component1 id, component2 id"

Important The RequiredAll value should only be used to install hidden network components that cannot be installed by the user. Such components should not support a user interface.

Note Any network components specified by RequiredAll cannot be removed until the network component that required their installation through RequiredAll is itself removed.

For example, if the INF file for component A specifies, through RequiredAll, a dependency on component B, component B cannot be removed until component A is removed. RequiredAll should therefore install only network components that are absolutely required for the operation of another network component. For example, if an INF file for a Net component (an adapter) uses RequiredAll to specify that TCP/IP must be installed, the user will not be able to remove TCP/IP until that adapter is removed. Since the adapter does not require TCP/IP to operate, the INF for the adapter should not use RequiredAll to specify a dependency on TCP/IP.

The INF file that specifies a RequiredAll dependency must ensure that the INF file for the required network component is present in the inf directory. Typically, this is accomplished with a CopyINF directive. For more information on the CopyINF directive, see INF CopyINF Directive. For more information on copying INF files, see Copying INFs.

If the installation of a network component specified by a RequiredAll entry fails, the installation of the network component that requires the specified component fails as well.


Specifying the Name and Provider Path for a NetClient Component

An INF file that installs a NetClient component must add a NetworkProvider key to the service key for the component. The INF file adds the NetworkProvider key through an add-registry-section that is referenced by an AddReg directive in the service-install section for the component.

The NetworkProvider key has two values: a Name that specifies the name of the network provider, and a ProviderPath that specifies the full path to the network provider DLL.

The following is an example of an add-registry-section that adds the NetworkProvider key to the instance key for a component:

[NWCWorkstation.AddReg]
HKR, NetworkProvider, Name, 0, "NetWare or Compatible Network"
HKR, NetworkProvider, ProviderPath, 0x20000, "%11%\nwprovau.dll"

Note An INF file that installs a NetClient component does not have to update the ProviderOrder value under the component's … Control\Network\Provider\Order key. This is done automatically by the network class installer.


Adding a HelpText Value

The INF file for a NetTrans, NetClient, or NetService network component that is visible in a user interface should add a HelpText value (REG_SZ) to the component's Ndi key.

The HelpText value is a localizable string that explains how the component benefits the user. For example, the HelpText value for a NetClient component should not simply identify the client but indicate what the client allows the user to connect to. The HelpText value is displayed at the bottom of the General page of the Connection Properties dialog box when a component on the page is selected.

Note Net components (adapters) and IrDA components do not support a HelpText value.

The following is an example of an add-registry-section that adds a HelpText value to the Ndi key:

[MS_Protocol.ndi_reg]
HKR, Ndi, HelpText, 0, %MyTransport_Help%

The HelpText value is a %strkey% token that is defined in the Strings section of the INF file. For more information on the Strings section, see the INF Strings Section.


Adding Registry Values for a Notify Object

A NetTrans, NetClient, or NetService component can have a notify object that performs one or more of the following actions:

  • Displays a user interface for the component
  • Notifies the component of binding events so that the component can exercise some control over the binding process
  • Provides for conditional installations

For more information on notify objects, see Notify Objects for Network Components.

Note Net components (adapters) do not support notify objects; therefore, these components should use a co-installer.

For more information on co-installers, see Writing a Co-installer.

If a component has a notify object, the INF file for that component must add (through an add-registry-section) the following values to the component's Ndi key:

ClsID
A REG_SZ value that specifies the GUID (globally unique identifier) for the notify object. Obtain this GUID by running the uuidgen.exe utility. For more information about this utility, see the Platform SDK.
ComponentDll
A REG_SZ value that specifies the path to the notify object DLL. The ComponentDll must specify the complete path to the DLL if the DLL is not in the Windows\System32 directory.

The following is an example of an add-registry-section that adds ClsID and ComponentDll values to the Ndi key:

[MS_Protocol.ndi.reg]
HKR, Ndi, ClsID, 0, "GUID"
HKR, Ndi, ComponentDll, 0, "notifyobject.dll"

The DDInstall section for a component that has a notify object must also contain a CopyFiles directive which references a file-list-section that copies the notify object DLL to the destination directory specified by the DirectionDirs section. For more information on the CopyFiles directive and DirectionDirs sections, see Sections and Directives.


Adding Service-Related Values to the Ndi Key

If a component has an associated service (device driver), the add-registry-section referenced by the DDInstall section for that component must add a Service value to the Ndi key. The Service value is a REG_SZ value that specifies the primary service associated with the component. The Service value must match the ServiceName parameter of the AddService directive that references the service-install-section for the primary service. For more information, see DDInstall Services Section.

If a component has one or more associated services, the add-registry-section referenced by the DDInstall section for that component must add a CoServices value to the Ndi key. The CoServices value is a MULTI_SZ value that specifies all the services that the component installs, including the primary service specified by the Service value. The CoServices value is required for all NetTrans, NetClient, and NetService components.

Note Net components (adapters) should not have a CoServices value, because only one service can be associated with an adapter.

Except for shutting down services, all service-related actions are performed on the CoServices in the order that they are listed. For example, services are started in the order that they are listed. Services are stopped, however, in reverse order. Service-related actions for a component are performed on a service only if that service is listed in CoServices.

If one or more of the services that are listed in CoServices should not be started during the installation of the component, that service or services should be listed in an ExcludeSetupStartServices value (MULTI_SZ) added to the Ndi key by the add-registry-section for the component.

The following is an add-registry-section that adds service-related values to the Ndi key:

[Ms_Protocol.ndi.reg]
HKR, Ndi, Service, 0, "MYT3"
HKR, Ndi, CoServices, 0x10000, "MYT3", "MYT3CO"
HKR, Ndi, ExcludeSetupStartService, 0x10000, "MYT3CO"


Specifying Binding Interfaces

For each network component that it installs, a network INF file must specify the upper and lower binding interfaces for the component by adding the Interfaces key to the Ndi key.

The Interfaces key has at least two values:

UpperRange
A REG_SZ value that defines the interfaces to which the component can bind at its top edge.
LowerRange
A REG_SZ value that defines the interfaces to which the component can bind at its lower edge. For physical adapters, this interface should always be the network media, such as Ethernet or token ring, to which the adapter connects.

Note The DefUpper and DefLower values in Windows 95/98/Me network INF files, however, are not supported for INF files that will be used on Windows 2000 and later versions of the operating system.

The following table lists the Microsoft-supplied UpperRange values:

Value | Description
netbios | NetBIOS
ipx | IPX
tdi | TDI interface to TCP/IP
ndis5 | NDIS 5.x (ndis2, ndis3, and ndis4 should no longer be used). This value should be specified for any non-ATM network component, such as a non-ATM adapter, that interfaces with NDIS at its upper edge.
Ndisatm | NDIS 5.x with ATM support. Specified value for any ATM network component, such as an ATM adapter, whose upper edge interfaces with NDIS
ndiswan | Upper edge for a WAN adapter. When specified, this value causes the operating system to automatically enable the WAN adapter for use with RAS
Ndiscowan | Upper edge for a WAN adapter over which connection-oriented NDIS runs
noupper | Upper edge for any component that does not expose an upper edge for binding; such a component typically has a private interface at its upper edge
winsock | The Windows socket interface
ndis5_atalk | Upper edge for an NDIS 5.x Net component (adapter) that binds only to an AppleTalk interface at its upper edge
ndis5_dlc | Upper edge for an NDIS 5.x Net component (adapter) that binds only to a DLC interface at its upper edge
ndis5_ip | Upper edge for an NDIS 5.x Net component (adapter) that binds only to a TCP/IP interface at its upper edge
ndis5_ipx | Upper edge for an NDIS 5.x Net component (adapter) that binds only to an IPX interface at its upper edge
ndis5_nbf | Upper edge for an NDIS 5.x Net component (adapter) that binds only to a NetBEUI interface at its upper edge
ndis5_streams | Upper edge for an NDIS 5.x Net component (adapter) that binds only to a streams interface at its upper edge

The following table lists the Microsoft-supplied LowerRange values:

Value | Description
ethernet | Lower edge for an Ethernet adapter
atm | Lower edge for an ATM adapter
tokenring | Lower edge for a token ring adapter
serial | Lower edge for a serial adapter
fddi | Lower edge for an FDDI adapter
baseband | Lower edge for a baseband adapter
broadband | Lower edge for a broadband adapter
arcnet | Lower edge for an Arcnet adapter
isdn | Lower edge for an ISDN adapter
localtalk | Lower edge for a LocalTalk adapter
wan | Lower edge for a WAN adapter
nolower | Lower edge for any component that does not expose a lower edge for binding
ndis5 | NDIS 5.x. (ndis2, ndis3, and ndis4 should no longer be used.) For any network component whose lower edge interfaces through NDIS with non-ATM components
Ndisatm | Ndis 5.x with ATM support. For any network component whose lower edge interfaces through NDIS with ATM components

The UpperRange and LowerRange values specify the types of interfaces — not the actual components — to which a component can bind. The binding engine binds a network component to all components that provide the specified interface at the appropriate (upper or lower) edge. For example, a protocol with a LowerRange of ndis5 binds to all components that have an UpperRange of ndis5, such as physical or virtual adapters.

If an NDIS 5.x Net component (adapter) works only with one or more specific protocols, then its UpperRange should be assigned one or more protocol-specific values, such as ndis5_atalk, ndis5_dlc, ndis5_ip, ndis5_ipx, ndis5_nbf, or ndis5_streams. Such a net class component should not be assigned an UpperRange value of ndis5, because this would cause that component to bind to all protocols that provide an ndis5 lower edge.

An INF-file-writer can define and use vendor-specific UpperRange and LowerRange values for private binding interfaces. For example, if a vendor wants to bind its adapter only to its own proprietary protocol driver, the INF-file-writer could specify XXX for the UpperRange of the adapter and XXX for the LowerRange of the proprietary protocol. The Windows 2000 binding engine will bind all components that have an UpperRange of XXX (in this case, the adapter) with all components that have a LowerRange of XXX (in this case, the proprietary protocol).

The following is an example of an add-registry-section that adds UpperRange and LowerRange values for an ATM adapter:

[addreg-section]
HKR, Ndi\Interfaces, UpperRange, 0, "ndisATM"
HKR, Ndi\Interfaces, LowerRange, 0, "atm"


Specifying Configuration Parameters for the Advanced Properties Page

An INF file that installs a Net component (adapter) can specify adapter configuration parameters for display in the Advanced properties page for the component. Configuration values specified by the user in the Advanced properties page are written to the root instance key for the component.

Note that if an adapter supports an Advanced properties page, the Characteristics entry in the DDInstall section for the adapter must include the NCF_HAS_UI value.

A network INF file specifies configuration parameters for display in the Advanced page through an add-registry-section that is referenced by the DDInstall section for the component. Such an add-registry-section adds one or more configuration subkeys to the Ndi\params key. The format for a configuration parameter subkey is Ndi\params\SubkeyName, where SubkeyName is a REG_SZ value that specifies a vendor-specific parameter name. For example, the key for a parameter that specifies a transceiver type could be named Ndi\params\TransceiverType.

The following keywords are reserved and cannot be used as a Ndi\params\SubkeyName: BundleId, Characteristics, ComponentId, Description, DriverDesc, InfPath, InfSection, InfSectionExt, Manufacturer, NetCfgInstanceId, Provider, and ProviderName.

For each parameter subkey that is added to Ndi\params, the add-registry-section must add ParamDesc (parameter description) and Type values. The add-registry-section can also add Default and Optional values for the parameter and, if the parameter is numeric, Min, Max, and Step values. The following table describes the values that can be added to each Ndi\params key.

Name | Value | Description
ParamDesc | string | Name displayed for the parameter on the Advanced page
Type | int, long, word, dword, edit, or enum | Type of parameter: int, long, word,and dword specify a numeric parameter; edit and enum specify a text parameter.
Default | default value | Default value for the parameter: for a numeric parameter, must be a numeric value (int, long, word, or dword) that matches the specified parameter type; for a text parameter, must be a string. Default values must be specified for required parameters but not for optional parameters.
Optional | 0 or 1 | 0 required. Specify a value for the parameter or use the default value. 1 optional. Can be marked Not Present on the Advanced page.
Min | numeric value | Minimum value for a numeric parameter.
Max | numeric value | Maximum value for a numeric parameter.
Step | numeric value | Step (interval) between valid values for a numeric parameter. The minimum value is the starting point.

The range of values for an enum parameter are specified with a subkey that has the following format:

Ndi\params\SubKeyName\enum

Each enumerated value must have a subkey. Each enum subkey specifies a numeric value (starting with zero for the first enumerated value) and a description for that value.

The following is an example of an add-registry-section that adds a configuration parameter named TransType.

[a1.params.reg]
HKR, Ndi\params\TransType,      ParamDesc, 0, "Transceiver Type"
HKR, Ndi\params\TransType,      Type,      0, "enum"
HKR, Ndi\params\TransType,      Default,   0, "0"
HKR, Ndi\params\TransType,      Optional   0, "0"
HKR, Ndi\params\TransType\enum, "0"        0, "Auto-Connector"
HKR, Ndi\params\TransType\enum, "1"        0, "Thick Net(AUI/DIX)"
HKR, Ndi\params\TransType\enum, "2"        0, "Thin Net (BNC/COAX)"
HKR, Ndi\params\TransType\enum, "3"        0, "Twisted-Pair (TPE)"


Specifying Custom Property Pages for Network Adapters

If the Advanced property page is not suitable for displaying the configuration choices for a Net component (adapter), you can create one or more custom property pages.

To create a custom property page

  1. Create a Microsoft® Win32® property page. Then create a property sheet extension DLL that provides AddPropSheetPageProc and ExtensionPropSheetPageProc callback functions. For more information, see the Windows 2000 Platform SDK.
  2. Use the add-registry-section that is referenced by the DDInstall section for the adapter to add the EnumPropPages32 key to the instance key for the adapter. The EnumPropPages32 key has two REG_SZ values: the name of the DLL that exports the ExtensionPropSheetPageProc function and the name of the ExtensionPropSheetPageProc function. The following is an example of an add-registry-section that adds the EnumPropPages32 key:
    HKR, EnumPropPages32, 0, "DLL name, ExtensionPropSheetPageProc function name"
  3. In the INF file for the adapter, include a CopyFiles section that copies the property sheet extension DLL to the Windows\System32 directory. For more information about the CopyFiles section, see Sections and Directives.
  4. In the DDInstall section for the adapter, specify NCF_HAS_UI as one of the Characteristics values to indicate that the adapter supports a user interface. For more information, see DDInstall Section.
  5. After the user applies changes to a property page, the property sheet extension DLL must:
    • Call SetupDiGetDeviceInstallParams
    • Set the DI_FLAGSEX_PROPCHANGE_PENDING flag in the SP_DEVINSTALL_PARAMS structure supplied by SetupDiGetDeviceInstallParams
    • Pass the updated SP_DEVINSTALL_PARAMS structure to SetupDiSetDeviceInstallParams.

      This reloads the driver so that it can read the changed parameter values.


Specifying Bundle Membership

An INF file that installs Net components (physical or virtual network adapters) can specify that those network adapters belong to the same bundle of adapters. Note that NDIS intermediate drivers and filter drivers, which export virtual network adapters, are included in the Net class. An NDIS driver can use adapters that it installed to balance its workload by distributing the workload over the bundle of adapters. For more information on load balancing, see Load Balancing and Fail Over.

To specify that an adapter belongs to a particular bundle of adapters, the INF file for the driver that installs the adapter must contain the BundleId keyword and a case-insensitive string value (REG_SZ). This string value identifies the driver's bundle of adapters. The registry is configured using the bundle-identifier information.

The following is an example of an add-registry-section in a driver's INF file that adds the BundleId subkey to the Ndi\params key and gives the ParamDesc (parameter description) for BundleId a string value of "Bundle1".

[a1.params.reg]
HKR, Ndi\params\BundleId, ParamDesc, 0, "Bundle1"


Ndi Values and Keys Not Used in Windows 2000 and Later Versions

The following Ndi registry keys and values are available in Windows 95/98/Me but are not used in Windows 2000 and later versions of the operating system. This information is provided to aid developers who are migrating network drivers from Windows 95/98/Me to Windows 2000 and later versions of the operating system.

DeviceVxD

DevLoader

DriverDesc

InfFile

InfSelection

Ndi\CardType

Ndi\Compability

Ndi\DeviceID

Ndi\filename\…

Ndi\Install

Ndi\InstallInf

Ndi\Interfaces\DefLower

Ndi\Interfaces\DefUpper

Ndi\Interfaces\ExcludeAny

Ndi\Interfaces\RequireAny

Ndi\NdiInstaller

Ndi\param-key-name\resc

Ndi\Params\param-key-name\flag

Ndi\Params\param-key-name\location

Ndi\Remove

NDIS\…

StaticVxD

In particular, Windows 2000 does not support Ndi\param-key-name\resc and Ndi\Params\param-key-name\flag values. This means that a user cannot specify adapter resources through the Advanced properties page.


DDInstall.Services Section

A DDInstall.Services section contains one or more AddService directives, each of which references an INF-writer-defined service-install-section that specifies how and when the services of particular component drivers are loaded.

A DDInstall.Services section is required in an INF file that installs a Net component (adapter); it is optional in an INF file that installs a NetTrans, NetClient, or NetService component.

An AddService directive in a DDInstall.Services section can also reference an error-log-install-section that installs an error log for a component. An error log is optional for all network components.

For more information, see INF DDInstall.Services Section and INF AddService Directive.

The following is an example of a DDInstall.Services section, a service-install-section, an error-log-install-section, and an add-registry-section that is referenced by an AddReg directive in the error-log-install-section:

[a1.ndi.NT.Services]
AddService = a1, 2, a1.AddService, a1.AddEventLog

[a1.AddService]
DisplayName = %Adapter1.DispName%
ServiceType = 1 ;SERVICE_KERNEL_DRIVER
StartType = 2 ;SERVICE_AUTO_START
ErrorControl = 1 ;SERVICE_ERROR_NORMAL
ServiceBinary = %12%\al.sys
LoadOrderGroup = NDIS

[a1.AddEventLog]
AddReg = a1.AddEventLog.reg

[a1.AddEventLog.reg]
HKR,,EventMessageFile,0x00020000,"%%SystemRoot%%\System32\netevent.dll"
HKR,,TypesSupported,0x00010001,7

The ServiceName parameter of the AddService directive, which in the above example is a1 (the first AddService parameter), must match the component's Ndi\Service value. For more information, see Adding Service-Related Values to the Ndi Key.


NetworkProvider and PrintProvider Sections

NetClient components are considered to be network providers because they provide network services to user applications. The Microsoft Client for Networks and the NetWare Client are examples of NetClient components.

In addition to being a network provider, a NetClient component can also be a print provider. A print provider provides print services to user applications over a network.

A NetClient component is always installed as a network provider. An INF file that installs a NetClient component does not require a NetworkProvider section for that component unless at least one of the following is true:

  • An alternative device name is specified for the component.
  • A short name for the component is specified for use with the net view command. For more information, see Including a NetworkProvider Section.

An INF that installs a NetClient component that is a print provider must contain a PrintProvider section for that component. For more information, see Including a PrintProvider Section.

An INF file that installs a NetClient component must also contain an add-registry-section (referenced by a AddReg directive in the service-install-section for a component) that adds a NetworkProvider key to the component's service key. For more information, see Specifying the Name and Provider Path for a NetClient Component.


Including a NetworkProvider Section

A NetworkProvider section specifies either a substitute device name for a NetClient component or a short name for use with the NetWare net view command, or both. To create a NetworkProvider section, add the NetworkProvider extension to the DDInstall section for the component, as shown in the following example:

[DDInstall] ; Install section
[DDInstall.NetworkProvider] ; NetworkProvider section

Specifying a Device Name

The network class installer usually creates the device name for a network provider by copying the Ndi\Service value for the component to the NetworkProvider key under the component's Service key. For more information, see Adding Service-Related Values to the Ndi Key. To specify a different device name for the component, include a DeviceName entry in the NetworkProvider section for the component, as shown in the following example:

[DDInstall-section.NetworkProvider]
DeviceName = "nwrdr"

The DeviceName is optional and should be specified only if the Ndi\Service value for the component is inadequate as a device name for the network provider.

Specifying a Short Name

To specify a short name for a network provider for use with the NetWare net view command, include a ShortName entry in the NetworkProvider section for the component, as shown in the following example:

[DDInstall-section.NetworkProvider]
ShortName = "nw"

The following is an example of a short name used with the net view command:

net view /n:nw

The ShortName is easier to remember and type than the entire name of the network provider.

The ShortName is optional and should only be specified if needed.


Including a PrintProvider Section

An INF file that installs a NetClient component that is a print provider must contain a PrintProvider section for that component. To create a PrintProvider section, add the PrintProvider extension to the DDInstall section for the component, as shown in the following example:

[DDInstall-section] ; Install section
[DDInstall-section.PrintProvider] ; PrintProvider section

The PrintProvider section must include the following entries:

PrintProviderName
A non-localized string that specifies the name of the print provider.
PrintProviderDll
The file name of the print provider DLL.
DisplayName
A localizable string that specifies the name of the print provider. The DisplayName can differ from the PrintProviderName.

The PrintProviderName and PrintProviderDll entries supply information that is used as input (in a PROVIDOR_INFO_1 structure) to the AddPrintProvidor function. The AddPrintProvidor function adds the print provider component as a print provider. For more information about the AddPrintProvidor function, see the Platform SDK.

The following is an example of a PrintProvider section:

[DDnstall-section.PrintProvider]
PrintProviderName = "NetWare or Compatible Network"
PrintProviderDll  = "nwprovau.dll"
DisplayName       = "%NWC_Network_Display_Name%"


Winsock Sections

An INF file for a NetTrans component that provides a Winsock interface must specify this Winsock dependency. Such an INF file must contain a Winsock-install section. To create a Winsockinstall section, add the .Winsock extension to the DDInstall section name for the protocol. For example, if the DDInstall section for a protocol is named Ipx, the Winsock-install section for that protocol must be named Ipx.Winsock.

A Winsock install section must contain an AddSock directive. The AddSock directive specifies a vendor-named section that contains values to be added to the component's HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\
TransportDriverName\Params\Winsock key.

The vendor-named section referenced by the AddSock directive must contain the following required values:

Value Name | Description
TransportService | A REG_SZ value that specifies the service name of the protocol. This must be the same as the Ndi\Service value for the protocol. For more information, see Adding Service-Related Values to the Ndi Key.
HelperDllName | A REG_EXPAND_SZ value that specifies the path to the Windows Sockets helper (WSH) DLL for the protocol. For more information, see WSH DLL Function Summary.
MaxSockAddrLength | A REG_DWORD value that specifies the largest valid SOCKADDR size, in bytes, for the WSH DLL
MinSockAddrLength | A REG_DWORD value that specifies the smallest valid SOCKADDR size, in bytes, for the WSH DLL

If an optional ProviderId for a name space provider is specified, the following values must also be specified:

Value Name | Description
ProviderId | A REG_SZ value that specifies the Globally Unique Identifier (GUID) that identifies the name space provider. The GUID is used as a key to all subsequent references to the name space provider. Obtain the GUID by running the uuidgen.exe utility. For more information about this utility, see the Platform SDK.
LibraryPath | A REG_EXPAND_SZ value that specifies the complete path to the name space provider DLL.
DisplayString | A localizable string that specifies the name displayed for the name space provider in the user interface.
SupportedNameSpace | A REG_DWORD value which specifies the name space that is supported by the namespace provider.
Version | An optional REG_DWORD value that specifies the version number of the name space provider. If this value is not specified, the default value (1) is used for the version number.

The following name space values can be assigned to SupportedNameSpace and are defined in Winsock2.h:

Namespace | Value
NS_ALL | 0
NS_SAP | 1
NS_NDS | 2
NS_PEER_BROWSE | 3
NS_TCPIP_LOCAL | 10
NS_TCPIP_HOSTS | 11
NS_DNS | 12
NS_NETBT | 13
NS_WINS | 14
NS_NBP | 20
NS_MS | 30
NS_STDA | 31
NS_CAIRO | 32
NS_X500 | 40
NS_NIS | 41
NS_WRQ | 50

For more information about name space providers, see the Platform SDK documentation.

The following example shows Winsock sections for an IPX protocol:

[Ipx.Winsock]
AddSock = Install.IpxWinsock

[Install.IpxWinsock]
TransportService = nwlinkipx
HelperDllName = "%%SystemRoot%%\System32\wshisn.dll"
MaxSockAddrLength = 0x10
MinSockAddrLength = 0xe
ProviderId = "GUID"
LibraryPath = "%SystemRoot%\\System32\\nwprovau.dll"
DisplayString = %NwlnkIpx_Desc%
SupportedNameSpace = 1
Version = 2

An INF file can remove a Winsock dependency for a protocol by including a Winsock-remove section. To create a Winsock-remove section, add the .Winsock extension to the Remove section name for the protocol. For example, if the Remove section for a protocol is named Ipx.Remove, the Winsock-remove section for the protocol must be named Ipx.Remove.Winsock.

The Winsock-remove section contains a DelSock directive that specifies an INF-writer-named section. The INF-writer-named section must specify the transport service to remove. If a ProviderId was previously registered for the protocol, the vendor-named section must also specify the ProviderId to remove.

The following example shows two sections that remove the Winsock dependency for an IPX protocol:

[Ipx.Remove.Winsock]
DelSock = Remove.IpxWinsock

[Remove.IpxWinsock]
TransportService = nwlinkipx
ProviderId = "GUID"


Installation Requirements for Network Components

This section summarizes the installation requirements for certain types of network components. These requirements are described in the following topics:

Installation Requirements for Network Adapters

Installation Requirements for Network Protocols

Installation Requirements for Network MUX Intermediate Drivers

Installation Requirements for Network Filter Intermediate Drivers

Installation Requirements for Network Clients

Installation Requirements for Network Services


Installation Requirements for Network Adapters

This topic summarizes the installation requirements for network adapters.

General Requirements

INF File Section | Status | Comments
Version Required Class = Net
ClassGuid = {4D36E972-E325-11CE-BFC1-08002BE10318}
SourceDisksNames and SourceDisksFiles Required if … Required if the INF file is not distributed with Windows 2000. If the INF file is distributed with Windows 2000, a LayoutFile entry must be specified in the Version section, and the SourceDiskNames and SourceDisksFiles sections are not used.

No network-specific requirements.
DestinationDirs | Required | No network-specific requirements.
ControlFlags Required Must contain an ExcludeFromSelect entry for each Plug and Play (PnP) adapter installed by the INF file.

Non-PnP adapters, such as ISA and EISA adapter, should not be listed.

Manufacturer | Required | No network-specific requirements.
Models | Required | The hw-id must match the hardware ID supplied by the adapter to the PnP Manager.
DDInstall Required Characteristics entry
Allowable values:

NCF_VIRTUAL,
NCF_SOFTWARE_ENUMERATED, NCF_PHYSICAL, NCF_MULTIPORT_INSTANCED_ADAPTER, NCF_HAS_UI, NCF_HIDDEN, NCF_NOT_USER_REMOVABLE

NCF_VIRTUAL, NCF_SOFTWARE_ENUMERATED, and NCF_PHYSICAL are mutually exclusive.

The BusType entry is required for a physical adapter.

The EisaCompressedId entry is required for an EISA adapter. This entry specifies both an EISA Compressed ID and an adapter mask for the adapter.

A Port1DeviceNumber or Port1FunctionNumber entry is required for a multiport network adapter.
DDInstall.Services | Required | No network-specific requirements.
add-reg-sections Required Creating the Ndi key

Specifying service-related values

Specifying bundle membership (only for LBFO miniport drivers)

Specifying binding interfaces

Allowable binding interfaces:

UpperRange:
ndis5, ndisatm, ndiswan, ndiscowan, noupper, ndis5_atalk, ndis5_dlc, ndis5_ip, ndis5_ipx, ndis5_nbf, ndis5_streams

LowerRange:
ethernet, atm, tokenring, serial, fddi, baseband, broadband, arcnet, isdn, localtalk, wan
Optional Setting static parameters for the component

Requiring the installation of another network component

Specifying configuration parameters for the Advanced property page

Creating custom property pages
Strings | Required | No network-specific requirements.

Additional Requirements for WAN Adapters

WAN adapters have additional installation requirements that are described in the following topics:

Specifying the number of endpoints (also known as channels, circuits or bearer channels) for a WAN adapter

Specifying keys and values for an ISDN adapter

Installing a multiprotocol WAN NIC

Note The Remove Section and Notify Object are not supported.


Installation Requirements for Network Protocols

This topic summarizes the installation requirements for network protocols.

INF File Section | Status | Comments
Version | Required | Class = NetTrans ClassGuid = {4D36E975-E325-11CE-BFC1-08002BE10318}
SourceDisksNames and SourceDisksFiles | Required if … | Required if the INF file is not distributed with Windows 2000. If the INF file is distributed with Windows 2000, a LayoutFile entry must be specified in the Version section, and the SourceDiskNames and SourceDisksFiles sections are not used. No network-specific requirements.
DestinationDirs | Required | No network-specific requirements.
ControlFlags | Optional | No network-specific requirements.
Manufacturer | Required | No network-specific requirements.
Models | Required | The hw-id should consist of a provider name followed by an underscore and a manufacturer name or the product name, for example: MS_DLC.
DDInstall | Required | Characteristics entry Allowable values: NCF_HIDDEN NCF_NO_SERVICE NCF_NOT_USER_REMOVABLE NCF_HAS_UI
DDInstall.Services | Optional | No network-specific requirements.
add-reg-sections | Required | Required: Creating the Ndi key Specifying binding interfaces Allowable binding interfaces: UpperRange: netbios, ipx, tdi, winsock, noupper LowerRange: ndis5, ndisatm, nolower
 | Optional | Setting static parameters for the component Requiring the installation of another network component Specifying service-related values Specifying a HelpText value Specifying values for a notify object
Remove | Optional |
Winsock sections | Optional | For a protocol that provides a Winsock interface, a Winsock-install section is required and a Winsock-remove section is optional.
Strings | Required | No network-specific requirements.


Installation Requirements for Network MUX Intermediate Drivers

This topic summarizes the installation requirements for network MUX intermediate drivers.

Two INF files are required to install a network MUX intermediate driver :

  • Driver protocol (Class = NetTrans)
  • Driver device (Class = Net)

Protocol INF File for a Network MUX Intermediate Driver

INF File Section | Status | Comments
Version | Required | Class = NetTrans ClassGuid = {4D36E975-E325-11CE-BFC1-08002BE10318}
SourceDisksNames and SourceDisksFiles | Required if … | Required if the INF file is not distributed with Windows 2000. If the INF file is distributed with Windows 2000, a LayoutFile entry must be specified in the Version section, and the SourceDiskNames and SourceDisksFiles sections are not used. No network-specific requirements.
DestinationDirs | Required | No network-specific requirements.
ControlFlags | Optional | No network-specific requirements.
Manufacturer | Required | No network-specific requirements.
Models | Required | The hw-id should consist of a provider name followed by an underscore and a manufacturer name or the product name—for example: MS_DLC.
DDInstall | Required | Characteristics entry: NCF_HAS_UI is required. The device INF must be copied to the system INF directory, see Copying INFs.
DDInstall.Services | Optional | No network-specific requirements.
add-reg-sections | Required | Creating the Ndi key Specifying binding interfaces UpperRange: noupper LowerRange: ethernet, atm, tokenring, serial, fddi, baseband, broadband, arcnet, isdn, localtalk, wan
 | Optional | Setting static parameters for the component Requiring the installation of another network component Specifying service-related values Specifying a HelpText value Specifying values for a notify object
Remove | Optional |
Strings | Required | No network-specific requirements.

Device INF File for a Network MUX Intermediate Driver

INF File Section | Status | Comments
Version | Required | Class = Net ClassGuid = {4D36E972-E325-11CE-BFC1-08002BE10318}
ControlFlags | Required | This section must contain an ExcludeFromSelect entry for the device.
Manufacturer | Required | No network-specific requirements.
Models | Required | The hw-id should consist of a provider name followed by an underscore and a manufacturer name or the product name—for example: MS_DLC.
DDInstall | Required | Characteristics entry: NCF_VIRTUAL is required. NCF_HIDDEN and NCF_NOT_USER_REMOVABLE are optional.
DDInstall.Services | Required | No network-specific requirements.
add-reg-sections | Required | Creating the Ndi key Specifying service-related values Specifying binding interfaces Allowable binding interfaces: UpperRange: ndis5, ndisatm, ndiswan, ndiscowan, noupper, ndis5_atalk, ndis5_dlc, ndis5_ip, ndis5_ipx, ndis5_nbf, ndis5_streams LowerRange: nolower
 | Optional | Setting static parameters for the component Requiring the installation of another network component
Strings | Required | No network-specific requirements.


Installation Requirements for Network Filter Intermediate Drivers

This topic summarizes the INF file requirements for network filter intermediate drivers.

Two INF files are required to install a network filter intermediate driver :

  • Driver service (Class = NetService)
  • Driver device (Class = Net)

Service INF File for a Network Filter Intermediate Driver

INF File Section | Status | Comments
Version | Required | Class = NetService ClassGuid = {4D36E974-E325-11CE-BFC1-08002BE10318}
SourceDisksNames and SourceDisksFiles | Required if … | Required if the INF file is not distributed with Windows 2000. If the INF file is distributed with Windows 2000, a LayoutFile entry must be specified in the Version section, and the SourceDiskNames and SourceDisksFiles sections are not used. No network-specific requirements.
DestinationDirs | Required | No network-specific requirements.
ControlFlags | Optional | No network-specific requirements.
Manufacturer | Required | No network-specific requirements.
Models | Required | The hw-id should consist of a provider name followed by an underscore and a manufacturer name or the product name—for example: MS_DLC.
DDInstall | Required | Characteristics entry: NCF_FILTER is required. NCF_HAS_UI and NCF_NO_SERVICE are optional. The device INF must be copied to the system INF directory, see Copying INFs.
DDInstall.Services | Optional | No network-specific requirements.
add-reg-sections | Required | Creating the Ndi key FilterClass, FilterDeviceInfId, FilterMediaTypes Specifying binding interfaces Allowable binding interfaces: UpperRange: noupper LowerRange: nolower
 | Optional | Setting static parameters for the component Requiring the installation of another network component Specifying a HelpText value Specifying values for a notify object
Remove | Optional |
Strings | Required | No network-specific requirements.

Device INF File for a Network Filter Intermediate Driver

INF File Section | Status | Comments
Version | Required | Class = Net ClassGuid = {4D36E972-E325-11CE-BFC1-08002BE10318}
ControlFlags | Required | This section must contain an ExcludeFromSelect entry for the device.
Manufacturer | Required | No network-specific requirements.
Models | Required | The hw-id should consist of a provider name followed by an underscore and a manufacturer name or the product name—for example: MS_DLC.
DDInstall | Required | Characteristics entry: NCF_VIRTUAL is required. NCF_HIDDEN and NCF_NOT_USER_REMOVABLE are optional.
DDInstall.Services | Required | The ServiceName value of the AddService directive must match the filter component's Service value under the Ndi key.
add-reg-sections | Required | Creating the Ndi key Specifying service-related values
 | Optional | Setting static parameters for the component Requiring the installation of another network component
Strings | Required | No network-specific requirements.


Installation Requirements for Network Clients

This topic summarizes the installation requirements for network clients.

INF File Section | Status | Comments
Version | Required | Class = NetClient ClassGuid = {4D36E973-E325-11CE-BFC1-08002BE10318}
SourceDisksNames and SourceDisksFiles | Required if … | Required if the INF file is not distributed with Windows 2000. If the INF file is distributed with Windows 2000, a LayoutFile entry must be specified in the Version section, and the SourceDiskNames and SourceDisksFiles sections are not used. No network-specific requirements.
DestinationDirs | Required | No network-specific requirements.
ControlFlags | Optional | No network-specific requirements.
Manufacturer | Required | No network-specific requirements.
Models | Required | The hw-id should consist of a provider name followed by an underscore and a manufacturer name or the product name—for example: MS_DLC.
DDInstall | Required | Characteristics entry Allowable values: NCF_HIDDEN NCF_NO_SERVICE NCF_NOT_USER_REMOVABLE NCF_HAS_UI
DDInstall.Services | Optional | No network-specific requirements.
add-reg-sections | Required | Creating the Ndi key Specifying binding interfaces Allowable binding interfaces: UpperRange: noupper LowerRange: ipx, tdi, winsock, netbios, nolower
 | Optional | Setting static parameters for the component Requiring the installation of another network component Specifying service-related values Specifying a HelpText value Specifying values for a notify object
Remove | Optional |
NetworkProvider | Required if … | Required if an alternative device name is specified for the network client or a short name for the component is specified for use with the net view command.
PrintProvider | Required if … | Required if the network client is a print provider.
Strings | Required | No network-specific requirements.


Installation Requirements for Network Services

This topic summarizes the installation requirements for network services.

INF File Section | Status | Comments
Version | Required | Class = NetService ClassGuid = {4D36E974-E324-11CE-BFC1-08002BE10318}
SourceDisksNames and SourceDisksFiles | Required if … | Required if the INF file is not distributed with Windows 2000. If the INF file is distributed with Windows 2000, a LayoutFile entry must be specified in the Version section, and the SourceDiskNames and SourceDisksFiles sections are not used. No network-specific requirements.
DestinationDirs | Required | No network-specific requirements.
ControlFlags | Optional | No network-specific requirements.
Manufacturer | Required | No network-specific requirements.
Models | Required | The hw-id should consist of a provider name followed by an underscore and a manufacturer name or the product name—for example: MS_DLC.
DDInstall | Required | Characteristics entry—allowable values: NCF_HIDDEN NCF_NO_SERVICE NCF_NOT_USER_REMOVABLE NCF_HAS_UI
DDInstall.Services | Optional | No network-specific requirements.
add-reg-sections | Required | Creating the Ndi key Specifying binding interfaces Allowable binding interfaces: UpperRange: noupper LowerRange: ipx, tdi, winsock, netbios, nolower
 | Optional | Setting static parameters for the component Requiring the installation of another network component Specifying service-related values Specifying a HelpText value Specifying values for a notify object
Remove | Optional |
Strings | Required | No network-specific requirements.


Notify Objects for Network Components

A notify object processes notifications that are sent by the network configuration subsystem to the object on behalf of a specific network component. A notify object is served up by a dynamic-link library (DLL). A notify object is used to display Property pages for a network component and to give that component programmatic control over the network configuration.

Note A network component does not generally require a notify object if both of the following conditions are TRUE:

  • A network component can be installed and removed through its information (INF) file
  • Reacting to changes in network configuration is not a requirement

The following sections describe notify objects and explain how to develop them.

About the Notify Object

Creating the Notify Object

For reference information for the interface methods that support notify objects, see Notify Object Reference.


About Notify Objects

A notify object processes notifications that the network configuration subsystem sends to the object on behalf of a specific network component. This network component owns the notify object. Network components that can own a notify object are:

  • Transports such as a protocol driver
  • Services such as an intermediate driver
  • Clients such as a Client for Microsoft Networks

Note Network cards do not support and cannot own notify objects. Physical or virtual network cards that participate in either configuring the network or installing and uninstalling must use INF files or the device co-installer mechanism.

For more information, see Writing a Co-installer.

A notify object performs the following actions:

  • Exposes interface methods to the network configuration subsystem so that the network configuration subsystem can inform the notify object about the occurrence of events on which the notify object requested notification.
  • Calls methods of the network configuration subsystem's public interfaces to perform actions that include but are not limited to installing and removing network devices. For more information, see Network Configuration Interfaces.

To request and receive notifications and to communicate with each other, the notify object and the network configuration subsystem implement Component Object Model (COM) interfaces.

Notify objects are COM objects that reside within dynamic-link libraries (DLLs). These DLLs are COM component servers. Each type of network component is associated with a class installer which installs specific types of network components and registers COM class objects that are owned by these network components. After the main install phase for network components is complete, the objects are registered. To register a COM class object, the class installer calls the object's DLL entry-point function.

Whenever the operating system installs, upgrades, or removes networking functionality, or whenever applications configure the network, the operating system or those applications must start the network configuration subsystem. After the network configuration subsystem starts, it creates an instance of a notify object, and the notify object performs particular operations.

The following topics describe the types of notifications that notify objects receive and the operations that notify objects perform:

Notify Object Diagram

Types of Notifications

Installation of the Network Component

Removal of the Network Component

Upgrade to the Network Component

Displaying and Changing Properties

Configuration of the Network


Notify Object Diagram

The following diagram shows how client applications that install or control networking call the network configuration subsystem. This subsystem calls network class installers to install network components and to register notify objects for those components. Notify objects call back to the subsystem to configure the network on behalf of those components that own the objects.

Network Configuration


Notification Types

The network configuration subsystem sends notifications to notify objects at the following intervals:

  • During networking setup—including operating system installation, installing networking capability on an operating system that did not previously support networking, upgrading the operating system, or uninstalling networking features
  • During network configuration—including adding, removing, enabling, and disabling network components, changing network components, and changing how the network configuration subsystem binds network components together
  • After an application directs the subsystem to display the properties of network components that own notify objects

To process notifications, a notify object performs the following general sequence of operations:

  1. When the notify object is loaded, it reads the system registry to form a model of the current network configuration in its internal data structures.
  2. After the network configuration subsystem sends notifications to the notify object about networking changes that the notify object previously requested, the notify object modifies its internal data structures to keep track of those changes.
  3. When the network configuration subsystem is done sending notifications to the notify object, the subsystem calls the notify object's INetCfgComponentControl::ApplyRegistryChanges method to commit the changes to the system registry.

Note The notifications mentioned in the preceding sequence can also include a call to the notify object's INetCfgComponentControl::CancelChanges method in which case the notify object should revert back to the original network configuration.

Before modifying the original network configuration, the notify object should make two copies of the configuration. The notify object can modify one copy to include changes and leave the other copy in the original condition. The notify object can use the unmodified copy when reverting back to the original network configuration.


Installing Network Components

Network components are installed by the network configuration subsystem.

To install a network component

  1. The network configuration subsystem calls the class installer for the particular component type. The class installer then calls the Setup API to retrieve information from the component's INF file and to install the component.

    If the component owns a notify object, the class installer retrieves the name of the DLL that houses the notify object. This DLL appears in the component's INF file as follows:

    HKR, Ndi, ComponentDll,     0,     "notifyobject.dll"

    The class installer calls the DLL's entry-point function to register the notify object. The network configuration subsystem creates an instance of the notify object and calls the object's INetCfgComponentControl::Initialize method. This method initializes the object and provides access to the component and all aspects of network configuration.

  2. To perform operations required to install the component, the network configuration subsystem calls the notify object's INetCfgComponentSetup::Install method. If installation of the component is unattended, the network configuration subsystem calls the notify object's INetCfgComponentSetup::ReadAnswerFile method. This method opens and retrieves the component's parameters from a file for unattended setup that is known as an answer file.
  3. After the network configuration subsystem creates an instance of and initializes the notify object, the subsystem calls the notify object's INetCfgComponentNotifyGlobal::GetSupportedNotifications method to retrieve the types of notifications required by the object. The subsystem uses this information to send required notifications to the object. The object can use these notifications to control aspects of networking setup and configuration that might affect the component that owns the object. For example, if the subsystem calls the INetCfgComponentNotifyGlobal::SysNotifyComponent method to notify the object that the subsystem installed or removed another network component, the object has the opportunity to perform operations related to the change.

    After the network configuration subsystem creates an instance of and initializes the notify object, the subsystem also calls any of the methods of the notify object's INetCfgComponentNotifyBinding interface to notify the object about changes to the way the subsystem binds other network components to the component that owns the notify object.

  4. When the network configuration subsystem is ready to apply the component's properties to the operating system, it calls the notify object's INetCfgComponentControl::ApplyRegistryChanges method to assign the component's parameters under the component's registry key. The notify object calls its component's INetCfgComponent::OpenParamKey method to open and retrieve the component's registry key.
  5. To configure the component's driver, the network configuration subsystem calls the notify object's INetCfgComponentControl::ApplyPnpChanges method and passes the INetCfgPnpReconfigCallback interface. The notify object calls the INetCfgPnpReconfigCallback::SendPnpReconfig method to send configuration information to its component's driver.

For more information on the Setup API and on files for unattended setup, see the Platform SDK.


Removing Network Components

Network components are removed by the network configuration subsystem.

To remove a network component

  1. The network configuration subsystem creates an instance of the notify object and calls the object's INetCfgComponentControl::Initialize method. This method initializes the object and provides access to the component and all aspects of network configuration.
  2. The subsystem calls the notify object's INetCfgComponentSetup::Removing method to perform operations required to remove the component. The Removing method performs cleanup operations to prepare for the component's removal.
  3. The subsystem calls the notify object's INetCfgComponentControl::ApplyRegistryChanges method to remove information about the network component from the registry.


Upgrading Network Components

Network components are upgraded by the network configuration subsystem.

To upgrade a network component

  1. The network configuration subsystem creates an instance of the notify object and calls the object's INetCfgComponentControl::Initialize method. This method initializes the object and provides access to the component and all aspects of network configuration.
  2. When the operating system is installed or upgraded to a different version, the network configuration subsystem calls the notify object's INetCfgComponentSetup::Upgrade method.
  3. The subsystem calls the notify object's INetCfgComponentControl::ApplyRegistryChanges method to modify information about the network component in the registry and then calls the notify object's INetCfgComponentControl::ApplyPnpChanges method and passes the INetCfgPnpReconfigCallback interface to configure the component's driver with the upgraded information.


Displaying and Changing Properties

The network configuration subsystem displays Property pages for a network component and changes the component's parameters.

A component's properties can be displayed and modified from the Control Panel. When you click the Network icon, you start the network configuration subsystem, which creates an instance of the notify object and calls the object's INetCfgComponentControl::Initialize method. This method initializes the object and provides access to the component and all aspects of network configuration.

The application calls the component's INetCfgComponent::RaisePropertyUi method to display the component's properties. The RaisePropertyUi method then calls the following notify object methods:

  • INetCfgComponentPropertyUi::QueryPropertyUi method to determine if a specific context is appropriate to display properties for the component.
  • INetCfgComponentPropertyUi::SetContext method to direct the component's notify object to display the component's properties in the specified context.
  • INetCfgComponentPropertyUi::MergePropPages method to create and merge custom pages for the component's property sheet into the default set.

If the user changes one of the component's parameters on one of the custom pages, RaisePropertyUi calls the notify object's INetCfgComponentPropertyUi::ApplyProperties method to store the change in memory.

To apply the change, the network configuration subsystem calls the notify object's INetCfgComponentControl::ApplyRegistryChanges method to modify information about the network component in the registry. To configure the component's driver with the modified information, the network configuration subsystem calls the notify object's INetCfgComponentControl::ApplyPnpChanges method and passes the INetCfgPnpReconfigCallback interface.


Configuring the Network

A notify object can provide the network component that owns it with programmatic control over network configuration .

A network component's properties can be configured from the Network Control Panel application. When you click the Network icon, you start the network configuration subsystem, which creates an instance of the notify object and calls the object's INetCfgComponentControl::Initialize method. This method initializes the object and provides access to the component and all aspects of network configuration.

After the network configuration subsystem creates an instance of and initializes the notify object, the subsystem calls the notify object's INetCfgComponentNotifyGlobal::GetSupportedNotifications method to retrieve the types of notifications required by the object. Using this information, the subsystem can send required notifications to the object. The object can use these notifications to control aspects of networking setup and configuration that might affect the component that owns the object. For example, if the subsystem calls the notify object's INetCfgComponentNotifyGlobal::SysQueryBindingPath method to notify the object that the subsystem is about to add a binding path to which other network components belong, the object has the opportunity to request that the subsystem disable that binding path. In addition, the subsystem calls any of the methods of the notify object's INetCfgComponentNotifyBinding interface. These methods notify the object about changes to the way the subsystem binds other network components to the component that owns the notify object.


Creating a Notify Object

A notify object should be created for a network component if the network component requires some control over networking setup and configuration and the ability to display custom property pages that users can use to modify the component's properties.

The following topics describe how to create a notify object:

Loading the Notify Object DLL and Class Object

Defining a Notify Class

Creating and Initializing an Instance of a Notify Object

Installing, Upgrading, and Removing the Component

Creating Property Pages for the Component

Setting Context to Display Properties

Evaluating Changes to Network Configuration

Applying Component Changes to the Registry

Configuring the Component's Driver

Retrieving Network Configuration Interface Pointers


Loading the Notify Object DLL and Class Object

Notify objects for network components should be implemented as Component Object Model (COM) objects. These COM objects reside in DLLs that are COM component servers. For more information on developing DLL COM servers, see the Platform SDK.

The DLL for a particular notify object should be implemented to export a set of entry-point functions:

  • A DllMain function to let the network configuration subsystem load the DLL into the virtual address space for the subsystem.
  • DllRegisterServer and DllUnregisterServer functions to put information into the operating system registry for the DLL's class objects. The network configuration subsystem uses this registry information to locate and load a network component's notify object.
  • A DllCanUnloadNow function to let the network configuration subsystem determine whether the DLL is in use. If the DLL is not in use, the subsystem can safely unload the DLL from memory.

In order for a notify object DLL to be a COM server, it must expose a class factory for the notify object the server supports. This class factory lets the network configuration subsystem create an instance of the notify object. The class factory should inherit from the IClassFactory interface. For more information on implementing classes that inherit from IClassFactory, see the Platform SDK.


Defining a Notify Class

Notify classes must be implemented so that they inherit from the INetCfgComponentControl interface. However, if notify objects perform certain operations their notify classes must also be implemented to inherit from the following interfaces:

  • If a notify object performs operations related to installing, upgrading, and removing the component that owns the object, the associated notify class must inherit from the INetCfgComponentSetup interface.
  • If a notify object displays custom property pages for the component that owns the object, the associated notify class must inherit from the INetCfgComponentPropertyUi interface.
  • If a notify object evaluates changes to the way the network configuration subsystem binds the component that owns the object to other network components, the associated notify class must inherit from the INetCfgComponentNotifyBinding interface.
  • If a notify object evaluates changes to network configuration that might affect the component that owns the object, the associated notify class must inherit from the INetCfgComponentNotifyGlobal interface.

Certain data members within notify classes should be defined as common to all notify objects. Certain data members should be defined as specific to their component. Data members that all notify objects should define include:

  • A pointer to an instance of the network component that owns the object of type INetCfgComponent interface. An instance of a notify object uses this pointer to access and control the component that owns the object.
  • A pointer to an instance of the network configuration object of type INetCfg interface. An instance of a notify object uses this pointer to access all aspects of network configuration.
  • Variables to store parameter information for the component that owns the notify object
  • A variable that specifies the action that a notify object previously performed. Define constants to indicate the different actions that notify objects might perform. When the network configuration subsystem calls the notify object's INetCfgComponentControl::ApplyRegistryChanges method to apply configuration changes to the registry, ApplyRegistryChanges uses this variable to determine how to make registry changes. For example, if a notify object previously performed operations relating to installing the component that owns the object in its INetCfgComponentSetup::Install method, Install should set this variable to indicate the action as install.
  • A registry key of type HKEY. A notify object calls the INetCfgComponent::OpenParamKey method of the component that owns the object to open and retrieve the registry key that contains parameters for the component. The notify object then sets the HKEY member to that key.

Define a constructor and a destructor for your notify class. Also consider defining private methods that only the notify class can use.

All the IUnknown interface methods should be implemented for a notify class. If a notify class inherits from any of the optional interfaces noted in the preceding list, all the methods of those interfaces must be implemented. Note that E_NOTIMPL is not a valid return type for any of the methods of the notify object interfaces. If a notify object does not require an implementation for a particular method, simply implement the method to return S_OK.


Creating and Initializing an Instance of a Notify Object

The network configuration subsystem must create an instance of the notify object and initialize the object before the subsystem can inform a notify object about changes to network configuration and display custom property pages for the component that owns the object.

The subsystem creates an instance of the notify object from the DLL's class factory. The class factory then calls the constructor for the notify class.

The class constructor should first assign initial values to class data members. Values that the constructor should initially assign include the following:

  • The constructor should set the interface pointer to an instance of a network component, INetCfgComponent, to a NULL value.
  • The constructor should set the interface pointer to an instance of the network configuration object, INetCfg, to a NULL value.
  • The constructor should set the variable that specifies the action that the notify object previously performed to a constant that identifies an unknown action. For more information on this variable, see Defining a Notify Class.

After the network configuration subsystem creates an instance of the notify object, the subsystem calls the object's INetCfgComponentControl::Initialize method to initialize the object instance. In this call, the subsystem passes an INetCfgComponent interface pointer. This INetCfgComponent provides the notify object with an instance of the object's component that the object can use to access and control the component. In this call, the subsystem also passes an INetCfg interface pointer to provide the notify object with an instance of the network configuration object that the notify object uses to access all aspects of network configuration.

The Initialize method should assign the INetCfgComponent and INetCfg interface pointers provided by the network configuration subsystem to data members of the notify class. Initialize should then call:

  • the INetCfg::AddRef method to increment the reference count of the network configuration object
  • the INetCfgComponent::AddRef method to increment the reference count of the component that owns the notify object

No other notify object interface methods are called until Initialize returns.


Installing, Upgrading, and Removing the Component

When the network configuration subsystem installs, upgrades, or removes a network component, the subsystem also calls the component's notify object to complete the installation, upgrade, and removal. The component's notify object can be implemented to perform operations that the component might require. For example:

  • A component's notify object can be implemented so that when the subsystem installs the component, the notify object will install other network components that the component requires to operate properly. To install a network component, a notify object's INetCfgComponentSetup::Install method calls the network configuration's INetCfgClassSetup::Install method. In this call, a notify object's Install method passes the identifier of the component to install.
  • A component's notify object can be implemented so that when the subsystem removes the component, the notify object will remove other network components. To remove a network component, a notify object's INetCfgComponentSetup::Removing method calls the network configuration's INetCfgClassSetup::DeInstall method. In this call, Removing passes the pointer to the INetCfgComponent interface of the component to remove.
  • The component's notify object can be implemented so that when the subsystem upgrades a component, the notify object will change the order of the component's binding path. To change this order, a notify object's INetCfgComponentSetup::Upgrade method calls either the INetCfgComponentBindings::MoveBefore or the INetCfgComponentBindings::MoveAfter methods.


Creating Property Pages for the Component

A notify object creates custom property pages after the network configuration subsystem calls the notify object's INetCfgComponentPropertyUi::MergePropPages method. Custom property pages can be merged into the default set of pages on the component's property sheet using the MergePropPages method. MergePropPages will return the appropriate number of default pages into which the custom pages can be merged.

To create custom property pages, MergePropPages calls the COM CoTaskMemAlloc function to allocate memory for handles to PROPSHEETPAGE structures. Each of these handles represents a property page to create. If CoTaskMemAlloc successfully allocates the memory for the handles, MergePropPages will declare and fill PROPSHEETPAGE structures for each property page. After MergePropPages fills these structures, it calls the Win32® CreatePropertySheetPage function for each property page. In this call, MergePropPages passes the address of the PROPSHEETPAGE structure to create.

A dialog-box callback function should also be implemented for each property page that MergePropPages creates. A dialog-box callback function processes messages that the operating system sends to the property page that is associated with that dialog-box function. To associate a property page with a dialog-box function, MergePropPages should point the pfnDlgProc member of each PROPSHEETPAGE structure for each page to the dialog-box function for the page.

A dialog-box function processes the following messages:

  • The WM_INITDIALOG message, which is sent to the dialog-box function immediately before the operating system displays its associated property page. Dialog-box functions typically use this message to initialize the property page and to perform tasks that affect the appearance of the property page.
  • The WM_NOTIFY message, which is sent to the dialog-box function after an event occurs in the property page. Other information sent with this message identifies what event has occurred. This event information is contained in a pointer to a NMHDR structure. Information that NMHDR can contain for a property sheet includes, for example:
    • The PSN_APPLY event, which indicates that a user clicks OK, Close, or Apply on the property page. If the user clicks OK, Close, or Apply, the dialog-box function can call the PropSheet_Changed macro to inform the property sheet that information in the page has changed. In this call, the dialog-box function passes handles to the property sheet and the page. The dialog-box function can call the Win32® GetParent function and pass the handle to the page to retrieve the handle to the property sheet.

      After the dialog-box function notifies the property sheet about the change, the network configuration subsystem calls the INetCfgComponentPropertyUi::ValidateProperties method to check the validity of all changes. If all changes are valid, the subsystem calls the notify object's INetCfgComponentPropertyUi::ApplyProperties method to cause all changes to take effect. The network configuration subsystem calls ApplyProperties before the operating system closes the dialog box.

      The ApplyProperties method can be implemented to retrieve information that the user enters and to set the information to the notify object's data members.

    • The PSN_RESET event, which indicates that the operating system is about to destroy a property page. A user might click Cancel on the property page to initiate this action. If the user clicks Cancel, the network configuration subsystem calls the INetCfgComponentPropertyUi::CancelProperties method to cause all changes to be disregarded. The network configuration subsystem calls CancelProperties before the dialog box is closed.
    • The PSN_KILLACTIVE event, which indicates that a property page is about to become inactive. This event occurs when a user activates another page or clicks OK.

Property-page callback functions can also be implemented for each property page that MergePropPages creates. A property-page callback function performs initialization and cleanup operations for the page. To associate a property page with a property-page callback function, MergePropPages should point the pfnCallback member of each PROPSHEETPAGE structure for each page to the property-page callback function for that page.

See the Platform SDK documentation for more information on:

  • creating property pages and on structures, functions, and notifications for property pages
  • dialog-box callback procedures, messages, and structures


Setting Context to Display Properties

A notify object can set the context in which to display properties for the network component that owns the object. The notify object sets the display context after the network configuration subsystem calls the object's INetCfgComponentPropertyUi::SetContext method but before the subsystem calls the object's INetCfgComponentPropertyUi::MergePropPages method.

When the network configuration subsystem calls SetContext, it passes an IUnknown interface. SetContext calls the QueryInterface method on this IUnknown interface to determine the interface of the specific object that the subsystem supplied.

For example, the network configuration subsystem can supply the INetLanConnectionUiInfo interface when it calls SetContext. SetContext can use the GetDeviceGuid method of INetLanConnectionUiInfo to retrieve the GUID of a LAN device. The notify object can subsequently display properties for its network component in the context of this LAN device. For example, the notify object for the TCP/IP protocol can display an IP address that is associated with a particular LAN adapter in the context of that adapter. Doing so enables users to specify an IP address for that adapter.


Evaluating Changes to Network Configuration

After the network configuration subsystem calls the methods of a notify object's INetCfgComponentNotifyGlobal and INetCfgComponentNotifyBinding interfaces, the notify object should evaluate the proposed change in network configuration that the subsystem sends and should perform operations related to the change. The methods of a notify object's INetCfgComponentNotifyGlobal and INetCfgComponentNotifyBinding interfaces should be implemented to process only the changes that affect the component that owns the object.

The following sections describe examples of how a notify object processes changes to network configuration.

Adding a Component

Changing Bindings for a Component


Adding a Component

The network configuration subsystem can inform a notify object when the subsystem adds network components. After initializing a notify object, the subsystem calls the notify object's INetCfgComponentNotifyGlobal::GetSupportedNotifications method to retrieve the types of notifications required by the object. If the notify object specified that it required notification when network components are added, the subsystem calls the notify object's INetCfgComponentNotifyGlobal::SysNotifyComponent method and passes NCN_ADD to inform the notify object that the subsystem installed a network component. If the component that owns the notify object should bind to the specified component, the notify object should perform operations to facilitate the binding. For example, the following code shows how the notify object can bind its component to the specified component if the specified component is a required physical network card.

HRESULT CSample::SysNotifyComponent(DWORD dwChangeFlag,
        INetCfgComponent* pnccItem)
{
    HRESULT hr = S_OK;
    INetCfgComponentBindings *pncfgcompbind;
    // Retrieve bindings for the notify object's component (m_pncc)
    hr = m_pncc->QueryInterface(IID_INetCfgComponentBindings,
                                (LPVOID*)&pncfgcompbind);
    // Determine if notification is about adding a component
    if (SUCCEEDED(hr) && (NCN_ADD & dwChangeFlag)) {
        // Retrieve the characteristics of the added component
        DWORD dwcc;
        hr = pnccItem->GetCharacteristics(&dwcc);
        // Determine if the added component is a physical adapter
        if (SUCCEEDED(hr) && (dwcc & NCF_PHYSICAL)) {
            // Determine the component's ID
            LPWSTR pszwInfId;
            hr = pnccItem->GetId(&pszwInfId);
            if (SUCCEEDED(hr)) {
                // Compare the component's ID to the required ID
                // and if they are the same perform the binding.
                static const TCHAR c_szCompId[] = TEXT("BINDTO_NIC");
                if (!_tcsicmp(pszwInfId, c_szCompId)) {
                    hr = pncfgcompbind->BindTo(pnccItem);
                }
            }
        }
    }
    return hr;
}


Changing Bindings for a Component

The network configuration subsystem always informs a notify object about changes in binding that affect the notify object's network component. The subsystem calls the notify object's INetCfgComponentNotifyBinding::NotifyBindingPath method and passes a value that specifies the change along with a pointer to the INetCfgBindingPath interface of the binding path involved in the change. If the subsystem passes NCN_DISABLE to disable the binding path that the notify object's network component shares with a specific network card, the notify object can activate the binding with another network card as shown in the following code.

HRESULT CSample::NotifyBindingPath(DWORD dwChangeFlag,
        INetCfgBindingPath* pncbp1)
{
    INetCfgComponent *pnccLow;
    INetCfgComponentBindings *pncbind;
    IEnumNetCfgBindingPath *penumncbp;
    INetCfgBindingPath *pncbp2;
    IEnumNetCfgBindingInterface *penumncbi;
    INetCfgBindingInterface *pncbi;
    DWORD dwFlags = EBP_BELOW;
    ULONG celt = 1; // Request one enumeration element.
    HRESULT hr = S_OK;
    // Retrieve bindings for the notify object's component (m_pncc)
    hr = m_pncc->QueryInterface(IID_INetCfgComponentBindings,
                                (LPVOID*)&pncbind);
    // Determine if notification is about disabling a binding path.
    if (SUCCEEDED(hr) && (NCN_DISABLE & dwChangeFlag)) {
        // Retrieve enumerator for binding paths for the component.
        hr = pncbind->EnumBindingPaths(dwFlags, &penumncbp);
        // Reset the sequence and retrieve a binding path.
        hr = penumncbp->Reset();
        hr = penumncbp->Next(celt, &pncbp2, NULL);
        // Ensure the binding path is different.
        do {
            if (pncbp1 != pncbp2) break;
            hr = penumncbp->Skip(celt); // skip one element
            hr = penumncbp->Next(celt, &pncbp2, NULL);
        } while (SUCCEEDED(hr));
        if (SUCCEEDED(hr) {
            // Retrieve enumerator for interfaces of the binding path.
            hr = pncbp2->EnumBindingInterfaces(&penumncbi);
            // Retrieve a binding interface for the binding path.
            hr = penumncbi->Next(celt, &pncbi, NULL);
            // Retrieve the lower network component.
            hr = pncbi->GetLowerComponent(&pnccLow);
            // If the component is a physical network card and binding
            // is currently disabled, enable binding.
            DWORD dwcc;
            hr = pnccLow->GetCharacteristics(&dwcc);
            if (SUCCEEDED(hr) && (dwcc & NCF_PHYSICAL)) {
                hr = pncbp2->IsEnabled(); // S_FALSE for disabled
                if (hr == S_FALSE)  hr = pncbp2->Enable(TRUE);
            }
        }
        else return hr;
    }
    return hr;
}


Applying Component Changes to the Registry

After the network configuration subsystem calls a notify object's INetCfgComponentControl::ApplyRegistryChanges method, the notify object should set, modify, or delete information from the registry depending on the action previously performed by the notify object. After the notify object performs specific actions related to installing, removing, or modifying parameters of the component that owns the object, the notify object should set a data member that indicates the action performed. After the subsystem calls ApplyRegistryChanges to apply configuration changes to the registry, ApplyRegistryChanges should use this data member to determine how to make registry changes. For example:

  • If a notify object previously performed operations related to installing the component that owns the object, the notify object should have set the data member that indicates the action as "install". After the subsystem calls ApplyRegistryChanges to apply configuration changes to the registry, ApplyRegistryChanges should set information about the component in the registry.
  • If a notify object previously performed operations related to removing the component that owns the object, the notify object should have set the data member that indicates the action as "remove". After the subsystem calls ApplyRegistryChanges to apply configuration changes to the registry, ApplyRegistryChanges should remove information about the component from the registry.
  • If a user displays one of a component's custom property pages and modifies one of the component's parameters, the component's notify object should have set the data member that indicates the action as "modify parameter". After the subsystem calls ApplyRegistryChanges to apply configuration changes to the registry, ApplyRegistryChanges should change information about the component's parameter in the registry.

To open and retrieve a component's registry key to modify information about the component, the ApplyRegistryChanges method should be implemented to call the component's INetCfgComponent::OpenParamKey method. To set values in the registry under the component's registry key, implement ApplyRegistryChanges to write registry data using Win32 functions. For example, ApplyRegistryChanges can call the RegCreateKeyEx function to create a subkey to hold values, and the RegSetValueEx function to create and set those values.

Formore information on the registry, writing data to it, and retrieving data from it, see the Platform SDK.


Configuring the Component's Driver

After the network configuration subsystem calls a notify object's INetCfgComponentControl::ApplyPnpChanges method, the notify object should send configuration information to the driver of the network component that owns the notify object. The network configuration subsystem calls ApplyPnpChanges after it calls the INetCfgComponentControl::ApplyRegistryChanges method and after drivers and services for the particular network component have started. In the ApplyPnpChanges call, the network configuration subsystem passes the INetCfgPnpReconfigCallback interface. The component's notify object can use the INetCfgPnpReconfigCallback interface to send configuration information to the component's driver. This driver must be either a TDI provider or an NDIS miniport driver.

The notify object can call INetCfgPnpReconfigCallback::SendPnpReconfig within its ApplyPnpChanges implementation to send configuration information to its component's driver. SendPnpReconfig passes configuration information to the driver.

Alternatively, the notify object can call the Win32® CreateFile function to open a connection to its component's driver. The notify object can call the Win32® DeviceIoControl function to send a control code along with input data directly to its component's driver.

The notify object is not required to use INetCfgPnpReconfigCallback. But, if the notify object uses INetCfgPnpReconfigCallback, a user will not be required to reboot the operating system to cause configuration changes to take effect in the driver.


Retrieving Network Configuration Interface Pointers

When the network configuration subsystem initializes an instance of the notify object as described in Creating and Initializing an Instance of a Notify Object, the object receives INetCfgComponent and INetCfg interface pointers. INetCfgComponent points to the notify object's component interface that the object can use to access and control the component. INetCfg points to the root network configuration interface that the notify object can use to access all aspects of network configuration. The following code uses these INetCfgComponent and INetCfg interface pointers to retrieve other network configuration interfaces that the notify object might require.

// Using the notify object's component interface that the notify
// object received:
INetCfgComponent *pncfgcompThis, *pncfgcompUp, *pncfgcompLow;
INetCfgComponentBindings *pncfgcompbind;
IEnumNetCfgBindingPath *penumncfgbindpath;
INetCfgBindingPath *pncfgbindpath;
IEnumNetCfgBindingInterface *penumncfgbindintrfc;
INetCfgBindingInterface *pncfgbindintrfc;
HRESULT hr;
DWORD dwFlags;  // EBP_ABOVE or EBP_BELOW
ULONG celt, celtFetched; // Number of requested and returned elements

// Retrieve a pointer to INetCfgComponentBindings to control and
// retrieve information about bindings for the component.
hr = pncfgcompThis->QueryInterface(IID_INetCfgComponentBindings,
                                  (LPVOID*)&pncfgcompbind);
// Retrieve a pointer to IEnumNetCfgBindingPath to enumerate binding
// paths for the component.
hr = pncfgcompbind->EnumBindingPaths(dwFlags, &penumncfgbindpath);
// Retrieve a pointer to INetCfgBindingPath that points to one or more
// binding paths for the component.
hr = penumncfgbindpath->Next(celt, &pncfgbindpath, &celtFetched);
// Retrieve a pointer to IEnumNetCfgBindingInterface to enumerate
// the collection of binding interfaces for the binding path.
hr = pncfgbindpath->EnumBindingInterfaces(&penumncfgbindintrfc);
// Retrieve a pointer to INetCfgBindingInterface that points to one or
// more binding interfaces for the binding path.
hr = penumncfgbindintrfc->Next(celt, &pncfgbindintrfc, &celtFetched);
// Retrieve pointers to INetCfgComponent for network components
// above and below the binding interface.
hr = pcfgbindintrfc->GetUpperComponent(&pncfgcompUp);
hr = pcfgbindintrfc->GetLowerComponent(&pncfgcompLow);

// Using the root network configuration interface that the notify
// object received:
INetCfg *pnetcfg;
INetCfgLock *pncfglock;
INetCfgClass *pncfgclass;
INetCfgComponent *pncfgcompOther, *pncfgcompInstall;
INetCfgClassSetup *pncfgclsSetup
GUID *pguidClass; // For example, set to GUID_DEVCLASS_NETTRANS
IEnumNetCfgComponent *penumncfgcomp;
HWND hwndParent; // Handle to Window for selecting.
OBO_TOKEN *pOboToken; // Another component or the user installs.
DWORD dwSetupFlags, dwUpgradeFromBuildNo;

// Retrieve a pointer to INetCfgLock to obtain a lock on network
// configuration.
hr = pnetcfg->QueryInterface(IID_INetCfgLock, (LPVOID*)&pncfglock);
// Retrieve a pointer to INetCfgComponent for a specific component.
hr = pnetcfg->FindComponent(TEXT("MS_TCPIP"), &pncfgcompOther);
// Retrieve a pointer to IEnumNetCfgComponent to enumerate
// the collection of a particular type of component.
hr = pnetcfg->EnumComponents(pguidClass, &penumncfgcomp);
// Retrieve a pointer to INetCfgClass for a specific class of
// component.
hr = pnetcfg->QueryNetCfgClass(pguidClass, IID_INetCfgClass,
                              (LPVOID*)&pncfgclass);
// Retrieve a pointer to INetCfgComponent for a specific component.
hr = pncfgclass->FindComponent(TEXT("MS_TCPIP"), &pncfgcompOther);
// Retrieve a pointer to IEnumNetCfgComponent to enumerate
// the collection of a particular type of component.
hr = pncfgclass->EnumComponents(&penumncfgcomp);
// Retrieve a pointer to INetCfgComponent that points to one or
// more components for the particular type of component.
hr = penumncfgcomp->Next(celt, &pncfgcompOther, &celtFetched);
// Retrieve a pointer to INetCfgClassSetup that enables installation
// or removal of a particular type of component.
hr = pncfgclass->QueryInterface(IID_INetCfgClassSetup,
                               (LPVOID*)&pncfgclsSetup);
// Retrieve a pointer to INetCfgComponent for an installed component.
hr = pncfgclsSetup->SelectAndInstall(hwndParent, pOboToken,
                                     &pncfgcompInstall);
// Retrieve a pointer to INetCfgComponent for an installed component.
hr = pncfgclsSetup->Install(TEXT("MS_TCPIP"), pOboToken, dwSetupFlags,
                           dwUpgradeFromBuildNo, TEXT("AnswerFile"),
                    TEXT("AnswerFileSections"), &pncfgcompInstall);


Upgrading Network Components

The network upgrade process migrates parameter values for network components during an operating system upgrade. The network upgrade process thus eliminates the need to reconfigure upgraded network components after the new operating system is installed.

The network upgrade process upgrades network components from Microsoft® Windows NT® version 3.51 or Windows NT version 4.0 to Microsoft® Windows® 2000 or later versions of the operating system. The network upgrade process does not upgrade network components from Windows 2000 to later versions of the operating system.

Vendors whose network components are not released as part of Windows 2000 or later should provide upgrade support for these components by supplying the following:

  • A network migration DLL that migrates the pre-upgrade parameter values for one or more network components.
  • A netmap.inf file that maps the pre-upgrade device, hardware, or compatible ID of one or more network components, to the corresponding ID in the new operating system.
  • Optional custom Help message files that provide information about upgrading network components.

The network upgrade process is described in the following topics:

Customizing the Network Upgrade Process

The Network Upgrade Process

Writing a Network Migration DLL

Creating a Netmap.inf File

Testing the Upgrade of Network Components

Network components whose drivers are released as part of Windows 2000 or later operating systems are automatically upgraded when the operating system is installed. No additional upgrade support is required for such components.


Customizing the Network Upgrade Process

System administrators can customize the network upgrade process.

To customize the network upgrade process

  1. Create a directory on the system for each network component to be upgraded.
  2. Copy the vendor-supplied upgrade files for each network component to the appropriate directory that you created in Step 1. These files must include a netmap.inf file. NetSetup uses the netmap.inf file to identify which network components to upgrade.
  3. Create a netupg.inf file and place it a directory of your choice. Each line in the netupg.inf file specifies a path to a directory created in Step 1. Each directory specified in the netupg.inf file must contain the vendor-supplied upgrade files for the network component, including a netmap.inf file.
  4. Set the NET_UPGRD_INIT_FILE_DIR environment variable to the directory that contains the netupg.inf file.

During the Winnt32 phase of the network upgrade, NetSetup locates the netupg.inf file in the directory specified by the NETUPGRD_INIT_FILE_DIR environment variable. In each directory specified in the netupg.inf file, NetSetup then locates the netmap.inf file and other vendor files for the network component to be upgraded. NetSetup processes these files to upgrade the component. For more information, see The Network Upgrade Process.


Creating a Netupg.inf File

The netupg.inf file contains a single section called OemNetUpgradeDirs. Each entry in this section specifies the complete path to a directory that contains the vendor-supplied upgrade files for a non-Microsoft-supported network component. Every network component being upgraded must have a corresponding entry in the OemNetUpgradeDirs section.

The following is an example of a netupg.inf file:

[OemNetUpgradeDirs]
c:\temp\adapter1
c:\temp\adapter2
c:\temp\protocol1
c:\temp\netclient1
c:\temp\netservice1

Each directory specified in the OemNetUpgradeDirs section must contain a netmap.inf file. This file, which is provided by the vendor of the network component, maps the pre-upgrade device, hardware or compatible ID of a network component to the corresponding ID in the upgraded operating system.


The Network Upgrade Process

The network upgrade process is divided into three distinct phases, which can be briefly summarized as follows:

  • Winnt32 phase

    Winnt32.exe calls NetSetup. NetSetup writes network component-specific information to the AnswerFile and calls any vendor-supplied network migration DLLs. The DLLs write component-specific information to the AnswerFile. Winnt32.exe copies the Windows 2000 or later files to the system being upgraded and prepares the boot sector on the system. The system then boots into text mode.

  • Text mode phase

    Installation messages are displayed on a blue, text-based screen. Setup performs the basic Windows 2000 or later installation. The system then boots into GUI mode.

  • GUI mode phase

    NetSetup processes the winnt.sif file, which is also known as the AnswerFile, and installs the network components. Network migration DLLs can display a user interface in which a user or system administrator can specify parameter values for network components. Either NetSetup or a network migration DLL writes a network component's pre-upgrade parameter values to the Windows 2000 or later registry.

The phases of the network upgrade process are described in more detail in the following topics:

Winnt32 Phase of the Network Upgrade Process

Text Mode Phase of the Network Upgrade Process

GUI Mode Phase of the Network Upgrade Process


Winnt32 Phase of the Network Upgrade Process

The user or system administrator starts the upgrade process by taking either of the following actions:

  • Selecting the component upgrade in the user interface that is displayed after the Windows 2000 or later CD-ROM spins up
  • Selecting and running \i386\winnt32.exe on the CD-ROM

If the user or system administrator has set the NETUPGRD_INIT_FILE_DIR environment variable on the system being upgraded, NetSetup searches for a netupg.inf file in the directory specified by that variable. The netupg.inf file contains only one section: OemNetUpgradeDirs. Each entry in this section specifies the complete path to a directory that contains the vendor-supplied upgrade files, including a netmap.inf file, for a network component. If the NETUPGRD_INIT_FILE_DIR environment variable is not set, NetSetup (netupgrd.dll) looks for netmap.inf files in its own directory.

NetSetup reads the netmap.inf files to identify the network components that do not have built-in upgrade support. If NetSetup is running in unattended mode, it displays a wizard; however, the user or system administrator cannot use the wizard. If NetSetup is not running in unattended mode, the wizard displays a list of the network components that do not have built-in upgrade support.

Using the wizard, a user or system administrator can:

  • Click Cancel to abort the installation of the operating system.
  • Click Next to install the operating system without upgrading the listed network components.
  • Specify the drive and directory location of vendor-supplied upgrade files for listed network components.

    NetSetup reads the netmap.inf file at the specified location and copies the vendor-supplied upgrade files at that location to a temporary directory on the system's hard disk. This temporary directory becomes the working directory for the vendor-supplied network migration DLL. NetSetup also removes any component that has a netmap.inf file from the component list in the wizard.

    A user can chose to upgrade only a subset of the network components listed in the wizard. At any time, the user can click Next to avoid upgrading the remaining listed network components. This action continues the installation of the operating system. The user can also click Cancel at any time to abort the installation of the operating system.

NetSetup generates the winnt.sif file (also known as the AnswerFile) in the $Win_nt$.~bt directory, which is usually located on the C: drive.

NetSetup generates the AnswerFile as follows:

  1. NetSetup reads the registry of the pre-upgraded system to enumerate each network component. For each network component that has built-in upgrade support, NetSetup writes the information that is read from the registry to the AnswerFile.
  2. For each network component that does not have built-in upgrade support, NetSetup reads the component's netmap.inf file. The netmap.inf file maps the pre-upgrade device, hardware, or compatible ID of a network component to the corresponding ID in the upgraded operating system. If NetSetup matches the pre-upgrade ID of the network component that it read from the registry with a pre-upgrade ID in the OemNetAdapters, OemNetProtocols, OemNetServices, or OemAsyncAdapters section of the netmap.inf file, NetSetup writes vendor-provided information for the component to the AnswerFile.
  3. Using the component's operating system device, hardware, or compatible ID, NetSetup reads the OemUpgradeSupport section of the netmap.inf file to determine which network migration DLL to load. NetSetup then loads the network migration DLL, and calls the DLL's PreUpgradeInitialize function. The PreUpgradeInitialize function supplies information that the DLL uses to initialize itself.
  4. NetSetup calls the DLL's DoPreUpgradeProcessing function once for each network component supported by the network migration DLL. DoPreUpgradeProcessing reads a network component's pre-upgrade parameter values from the registry and calls the NetUpgradeAddSection and NetUpgradeAddLineToSection functions to write these parameters, along with other component-specific information, to the AnswerFile. DoPreUpgradeProcessing can also migrate binary data associated with the pre-upgraded component by making appropriate entries in the AnswerFile.
  5. After the AnswerFile is completely generated, NetSetup copies the vendor-supplied upgrade files to the appropriate directories and then boots into the text mode phase of the upgrade process.


Text Mode Phase of the Network Upgrade Process

Setup strips all comments from the AnswerFile and writes the AnswerFile to the System32 directory under the name $Winnt$.inf. Then the system boots into GUI mode setup. No network-specific processing occurs during the text mode phase.


GUI Mode Phase of the Network Upgrade Process

Before the Windows 2000 or later operating system is installed on the system, NetSetup reads the network-specific information that was written to the AnswerFile during the Winnt32 phase.

If a network migration DLL wrote the InfToRunBeforeInstall key to a component's OEM section in the AnswerFile, NetSetup finds the INF file and section specified by the key and processes the INF directives in this section. This section usually contains the AddReg, DelReg, AddService, or DelService directives.

After the Windows 2000 or later operating system is installed, NetSetup installs each network component detected in the system, using the default parameter values specified for the component in the component's Windows 2000 or later INF file. NetSetup then installs network components listed in the AnswerFile.

If a network component's OEM section in the AnswerFile contains an OemDllToLoad key, NetSetup loads the network migration DLL if the DLL is not already loaded and then calls the DLL's PostUpgradeInitialize function. The PostUpgradeInitialize function supplies the DLL with information that the DLL uses to initialize itself. NetSetup then calls the DLL's DoPostUpgradeProcessing function once for each network component to be upgraded by the DLL. DoPostUpgradeProcessing can display a user interface that allows a user to specify parameter values for a component. DoPostUpgradeProcessing writes any user-specified parameter values to the registry.

If the miniport driver for a network adapter required the adapter's instance ID before the upgrade, it will probably require the adapter's instance ID after the upgrade. A network migration DLL can call HrGetInstanceGuidOfPreNT5NetCardInstance from its DoPostUpgradeProcessing function to obtain the Windows 2000 or later instance GUID for a network adapter.

NetSetup starts the installed network protocols, clients, and services.

NetSetup processes the entries in the Identification section of the AnswerFile and tries to connect the system to the workgroup or domain specified in that section.

If the system being upgraded contains any Async adapters, Setup calls the Async class installer, which upgrades each Async adapter as follows:

  • The Async class installer locates the OEM section for the Async adapter in the AnswerFile.
  • From the Async adapter's OEM section, the Async class installer reads the pre-upgrade parameter values for the adapter. These parameter values were written by the network migration DLL for the adapter during the Winnt32 phase of the upgrade.
  • The Async class installer writes the adapter's pre-upgrade parameter values to the Windows 2000 or later registry.


Writing a Network Migration DLL

A network migration DLL migrates the parameter values for one or more network components from Windows 3.51 or Windows NT 4.0 to Windows 2000 or later.

A network migration DLL must:

  • Load under the pre-upgrade operating system (Windows NT 3.51 or Windows 4.0)
    The DLL cannot call any functions specific to Windows 2000 or later or use any features specific to Windows 2000 or later. If the DLL runs in the post-upgrade (GUI mode) phase, it must also load under Windows 2000 and later operating systems.
  • Export the PreUpgradeInitialize and DoPreUpgradeProcessing functions
    If the DLL runs in the GUI mode phase, it must export the PostUpgradeInitialize and DoPostUpgradeProcessing functions, as well.
  • Make no irreversible changes during the Winnt32 phase
    The DLL must not make any irreversible changes, such as deleting files or modifying registry keys, during this phase because a user can cancel the upgrade of a network component or the operating system. The DLL can, however, modify files in its temporary working directory, which is specified by NetSetup in the call to PreUpgradeInitialize.


Creating a Netmap.inf File

The netmap.inf file is a vendor-supplied file that resides either in a directory specified by an entry in the OemNetUpgradeDirs section of a netupg.inf file or in the directory that contains netupgrd.dll. The netmap.inf file:

  • Maps a network component's pre-upgrade device ID to the component's Windows 2000 or later device ID
  • Specifies the network migration DLL that NetSetup loads
  • Optionally specifies an alternative Help message file

A network component that has built-in upgrade support in Windows 2000 or later operating systems does not require a vendor-supplied netmap.inf file because these components are automatically upgraded during the installation of Windows 2000 and later operating systems.


Mapping IDs in a Netmap.inf File

A netmap.inf file contains one or more of the following top-level sections. Each section contains ID mappings for the components listed in the Map column.

Section | Map
OemNetAdapters | Network adapters, excluding Async adapters
OemAsyncAdapters | Async network adapters
OemNetProtocols | Network protocol drivers
OemNetServices | Network services
OemNetClients | Network clients

Each entry in a section maps a network component's pre-upgrade device, hardware, or compatible ID to its corresponding Windows 2000 or later ID. Each entry specifies either one-to-one ID mapping or one-to-many ID mapping. These mapping strategies are described following.

Network clients are not defined as such in Windows NT 3.51 and Windows NT 4.0; therefore, if an earlier network service becomes a network client under Windows 2000 or later, its device ID mapping must be listed in the OemNetClients section, not in the OemNetServices section.


One-to-One ID Mapping

An entry in an Oem Xxx section of a netmap.inf file that specifies one-to-one ID mapping has the following format:

preupgrade-ID=postupgrade-ID

For example:

netservice=netservice_2000

A one-to-one ID mapping must be used for network protocols, services, and clients. Either one-to-one ID mapping or one-to-many ID mapping can be used for network adapters.


One-to-Many ID Mapping

A one-to-many ID mapping maps a single pre-upgrade ID that represents more than one network adapter. The only way to differentiate the adapters associated with a single pre-upgrade ID is to inspect the values under the registry key that contains the parameter values for the network adapter instance.

An entry in an OemAdapters or OemAsyncAdapters section that specifies a one-to-many ID mapping has the following format:

preupgrade-ID=mapping-method-number,section-name

where:

mapping-method-number must be 0

section-name specifies a section in the netmap.inf file that contains the mapping information

The netmap.inf file section specified by section-name contains the following entries:

ValueName="Name"

Specifies the value that NetSetup reads under the registry key that contains the parameter values for the network adapter instance. Name identifies a particular network adapter.

ValueType=Type

Specifies the registry value type for ValueName. Type is an integer that corresponds to a specific registry type.

ValueName=postupgrade-ID

ValueName is the value that NetSetup reads under the registry key that contains the parameter values for the network adapter instance. postupgrade-ID is the Windows 2000 or later device ID for the adapter. One ValueName entry should be provided for each adapter type that will be upgraded. If ValueName is set to the keyword ValueNotPresent and if NetSetup finds no parameters values for the adapter instance, NetSetup uses the postuprgrade-ID associated with ValueNotPresent for the adapter.

The following example shows a one-to-many device ID mapping:

[OemAdapters]
DATAFIREU=0, DATAFIREU

[DATAFIREU]
ValueName            = "BoardType"
ValueType            = 1
DataFireIsaU        = "DATAFIRE - ISA1U"
DataFireIsa1ST    = "DATAFIRE - ISA1ST"
DataFireIsa4ST    = "DATAFIRE - ISA4ST"
DataFireIsaGeneric = "ValueNotPresent"

The OemAdapters section in the above example contains a single entry that identifies the pre-upgrade device ID of the network adapter as DATAFIREU and specifies that the DATAFIREU section of the netmap.inf file contains the mapping information for this adapter.

The DATAFIREU section contains the following information:

  • The ValueName entry directs NetSetup to look for the BoardType value under the Parameters key of the network adapter instance.
  • The ValueType entry, which is set to 1, specifies that the BoardType value is a DWORD.
  • Each remaining value specifies a pre-upgrade device ID and a corresponding Windows 2000 or later ID. For example, the ID for the DataFireIsaU board type is DATAFIRE - ISA1U. The ValueNotPresent keyword can be specified instead of a pre-upgrade ID.

NetSetup performs a one-to-many ID mapping as follows:

  1. NetSetup reads the specified ValueName under the registry key that contains the parameter values for the network adapter instance.
  2. NetSetup attempts to match the ValueName with one of the ValueNames listed in the specified section of the netmap.inf file. If no ValueName is listed under the registry key, NetSetup attempts to find the ValueNotPresent keyword in the specified section of the netmap.inf file.
  3. If NetSetup finds a match, it installs the network adapter, using the INF file that has the same name as the mapped Windows 2000 or later ID.

If the registry keys or values for an adapter instance are identical for different adapter types, it is not possible to map a single pre-upgrade device ID to more than one Windows 2000 or later device ID without first modifying these registry keys or values.

The most effective way of handling this situation is as follows:

  1. The network migration DLL's PreUpgradeInitializeDDK_PreUpgradeInitialize_NR function modifies the registry so that the registry contains unique values for each instance of the network adapter. These unique values should indicate the adapter type.
  2. The PreUpgradeInitialize function sets the NUA_REQUEST_ABORT_UPGRADE flag, which causes NetSetup to display a message that prompts the user to restart winnt32.exe and abort the upgrade.
  3. The user aborts the upgrade and then restarts winnt32.exe. The network migration DLL can now use the unique values to map the single pre-upgrade device ID to more than one Windows 2000 or later device ID.


Specifying the Upgrade DLL in a Netmap.inf File

A netmap.inf file must have an OemUpgradeSupport section. For each network component to be upgraded, the OemUpgradeSupport section must contain an entry that has the following format:

postupgrade-ID=network-migration-DLL[,Inf-file-name]

where:

postupgrade-ID is the network component's Windows 2000 or later device ID, which was obtained by NetSetup, as described in Winnt32 Phase of the Network Upgrade Process.

network-migration-DLL is the name of the network migration DLL that NetSetup must load to upgrade the network component. Only one migration DLL can be specified in a netmap.inf file. If the netmap.inf file contains device ID mappings for more than one component, then all such components must be upgraded by the same migration DLL.

Inf-file-name is the name of the INF file that installs the network component.


Specifying Alternative Help Message Files in a Netmap.inf File

If NetSetup fails to find the device ID mapping for a network component in any of the netmap.inf files, it lists this component on the Compatibility Report page in the wizard. Associated with each such component is a Help message file.

By default, NetSetup displays a Help message contained in the \winntupg\unsupmsg.txt file or, if an HTML browser is installed on the system, in the \winntupg\unsupmsg.htm file. You can optionally supply a custom message file that overrides the unsupmsg.txt and unsupmsg.txt message files. For example, if a vendor provides upgrade support for only some of its network components, the vendor could supply a custom Help message file that indicates that upgrade support is not provided for certain components.

An optional OemUpgradeHelpFiles section in a netmap.inf file specifies one or more custom Help message files. Each entry in the this section has the following format:

postupgrade-ID=text-name, htm-file

where:

postupgrade-ID is the Windows 2000 or later device ID of network component

text-name is the path and name of the text version of the custom Help message file

htm-file is the path and name of the HTML version of the custom Help message file.

If a full path name is not specified in text-name or htm-file, the specified path is appended to the i386 directory--for example: \i386\mydirectory\myfile.txt.

The following example of a netmap.inf file contains an OemUpgradeHelpFiles section.

[Version]
signature="$WindowsNT$

[OemNetProtocols]
Protocol1=Protoco1_2000
Protocol2=Protocol2_2000

[OemUpgradeSupport]
Protocol1=NotSupported
Protocol2=abc_upgrade.dll, abc.inf

[OemUpgradeHelpFiles]
Protoco11=helpmsg.txt, helpmsg.htm

Even though this sample netmap.inf file does not provide upgrade support for Protocol1, it provides a device ID mapping for Protocol1 in the OemNetProtocols section. This mapping specifies a Windows 2000 device ID for Protocol1. The Windows 2000 device ID is required to associate custom Help message files with a network component.

Notice that the keyword NotSupported is assigned to Protocol1 in the OemUpgradeHelpFiles section. This keyword indicates that there is no need to load a migration DLL to upgrade Protocol1.

In the OemUpgradeHelpFiles section of the previous example, the Protoco11=helpmsg.txt, helpmsg.htm entry specifies two custom Help message files for Protocol1. The custom Help message contained in these files could indicate, for example, that the vendor does not support the upgrade of Protocol1 and that the user must separately upgrade Protocol1 to Protocol2 before attempting to upgrade the system to Windows 2000 or later.


Testing the Upgrade of Network Components

There are two major steps involved in testing the upgrade of network components. These are described in the following topics:

Setting Up the Test System

Running the Upgrade Test and Examining the Results


Setting Up the Test System

Before you upgrade network components, make sure that the network components to be upgraded are correctly installed and configured.

To set up the test system

  1. Create one partition for the pre-upgrade operating system and another partition for the Windows 2000 or later operating system.

    Important Do not install the pre-upgrade operating system and the upgrade operating system in the same partition. If the pre-upgrade operating system and Windows 2000 or later are installed in the same partition, they will share the same Program Files directory.

  2. On the test system, boot an operating system build other than the one to be upgraded. Then copy the entire partition to be upgraded, except for the pagefile.sys file, into a back-up directory. There is no need to copy the pagefile.sys file, since it is created on the start-up of Windows 2000 or later.

    This method of creating a back-up installation is preferable to creating a disk-image program, because it allows you to use xcopy, which takes less time to copy files than a disk-image program. You can repeat an upgrade test by simply copying the contents of the back-up partition into a new partition to be upgraded; it is not necessary to reinstall the pre-upgrade operating system.

  3. Create a test directory for storing the network migration DLL and the netmap.inf file, and then copy these files to the test directory.
  4. Create another directory for storing the Windows 2000 or later files required for the Winnt32 upgrade phase.
  5. Insert the Windows 2000 or later DDK CD-ROM that contains the checked build of Windows 2000 or later. From the \i386 directory on the CD-ROM, copy the following files to the back-up directory (Step 2):
    • winnt32.exe
    • winnt32u.dll
    • pidgen.dll
    • wetuplog.*
  6. Create an upgrade directory named winntupg. Copy the files in the \i386\winntupg directory on the CD-ROM to the winntupg directory on the test system.
  7. Enable the debugger on the text system or start debugmon.exe, which is included with the Resource Kit for Windows 2000 or later operating systems. Then copy a netcfg.ini file to %windir%. The netcfg.ini file enables debug tracing.

    The following is a sample netcfg.ini file:

    [DebugFlags]
BreakOnAddLegacy=0
BreakOnAlloc=0
BreakonDoUnattend=0
BreakonDwrefProblem=0
BreakOnError=0
BreakOnHr=0
BreakOnHrInteraction=0
BreakOnIteration=0
BreakOnNetInstall=0
BreakOnWizard=0
DisableTray=0
DumpLeaks=0
DumpNetCfgTree=0
NetShellBreakOnInit=0
ShowIngnoreErrors=0
ShowProcessAndThreadIds=0
SkipLanEnum=0
TracingTimeStamps=0

[Default]
OutputToDebug=1

[EsLocks]
OutputToDebug=0

[ShellViewMsgs]
OutputToDebug=0

[OptErrors]
OutputToDebug=0


Running the Upgrade Test and Examining the Results

Before you upgrade the system to Windows 2000 or later, note the parameter values in the registry for each network component to be upgraded.

To run the upgrade test

  1. Make sure that the CD-ROM that contains the checked build of Windows 2000 or later is in the CD-ROM drive.
  2. Run winnt32.exe on the test system. For example, use the following command to run winnt32.exe on an Intel-based system with the CD-ROM in drive O:
    winnt32.exe /s:o\i386
  3. After Windows 2000 or later is installed, verify that the upgraded network component's parameters have been correctly migrated to the new operating system.


Examining the AnswerFile

Immediately before the "Setup is Copying Files" progress bar is displayed on a system being upgraded, the AnswerFile is created. NetSetup and vendor-supplied network migration DLLs create sections in the AnswerFile and then write entries to these sections during the Winnt32 upgrade phase.

You can examine the AnswerFile by copying c:\$win_nt$.~bt\winnt.sif to %TEMP%. After the AnswerFile has been copied, you can click Cancel to cancel file copying. You do not have to wait until file copying is finished.

The following table lists the top-level sections in the AnswerFile and the corresponding entries that each section contains that pertain to network components:

Section | Entries Contained
NetAdapters | Network adapters, including ISDN adapters
AsyncAdapters | Async adapters
NetProtocols | Network protocols
NetServices | Network services
NetClients | Network clients

For each network component that it finds during the Winnt32 phase, NetSetup writes an entry to the appropriate top-level section of the AnswerFile. Each entry has the following format:

params.postupgrade-ID

The postupgrade-ID entry is the Windows 2000 or later device ID that NetSetup obtained from the netmap.inf file for the component.

Each entry specifies the name of the parameters section for that component in the AnswerFile. For example, if a component's Windows 2000 or later device ID is netadapter2, its entry in the NetAdapters section is params.netadapter2. The top-level sections and the parameter sections in an AnswerFile are not visible to a network migration DLL.

To the parameters section name for a component, NetSetup adds the extension OemSection to create the OEM-section name for the component. For example, if the parameters section for a component is params.netadapter2, the OEM-section name for the component is params.netadapter2.OemSection. NetSetup passes the OEM-section name as the szSectionName parameter to the DoPreUpgradeProcessing function supplied by the network migration DLL for the component. The DoPreUpgradeProcessing function calls the NetUpgradeAddSection function to create the OEM-section for a component in the AnswerFile. The DoPreUpgradeProcessing function then calls the NetUpgradeAddLineToSection to add component-specific information to the OEM-section.

The following portion of an AnswerFile shows the sections and entries for a network adapter whose Windows 2000 or later device ID is adapter2:

[NetAdapter]              ;top-level adapters section
adapter2=params.adapter2      ;entry for adapter2
[params.adapter2]          ;parameters section for adapter2
InfID=adapter2            ;Windows 2000 or later device ID
OemSection=params.adapter2.OemSection  ;Identifies the OemSection

[params.adapter2.OemSection]  ;OemSection created by migration DLL
InfToRunAfterInstall="", adapter2.SectionToRun ;Written by DLL

[adapter2.SectionToRun]      ;Section created by migration DLL
AddReg=adapter2.SectionToRun.AddReg ;AddReg directive

[adapter2.SectionToRun.AddReg] ;AddReg section created by DLL
HKR,0\0,IsdnPhoneNumber,0,"111-1111" ;AddReg entries written by DLL
HKR,0\1,IsdnPhoneNumber,0,"222-2222"
HKR,0\0,IsdnSpid,0,"111"
HKR,0\1,IsdnSpid,0,"222"
HKR,0,IsdnSwitchType,0x00010001,1

During the GUI mode phase, NetSetup detects the InfToRunAfterInstall key written by the migration DLL to the params.adapter2.OemSection of the example AnswerFile. As directed by this key, NetSetup processes the adapter2.SectionToRun.AddReg section. The adapter2.SectionToRun.AddReg section directs NetSetup to add parameter values to adapater2's instance key in the Windows 2000 or later registry. These parameter values should match the pre-upgrade parameter values that the migration DLL read from adapter2's the registry during the Winnt32 phase of the upgrade.

If a network migration DLL is to be loaded during the GUI mode phase, its DoPreUpgradeProcessing function sets the NUA_LOAD_POST_UPGRADE flag. This flag causes NetSetup to write the OemDllToLoad entry to the component's parameters section in the AnswerFile. The OemDllToLoad entry causes NetSetup to load the migration DLL for the component during the GUI mode phase.

The following example shows the AnswerFile sections and entries for a component whose network migration DLL is loaded during the GUI mode phase:

[NetAdapter]              ;top-level adapters section
adapter2=params.adapter2      ;entry for adapter2
[params.adapter2]          ;parameters section for adapter2
InfID=adapter2            ;postupgrade device ID
OemSection=params.adapter2.OemSection    ;Identifies the OemSection
OemDllToLoad=c:\temp\oem0001\migration.dll

Note the OemDllToLoad entry in the params.adapter2 section. Also note that the migration DLL did not create a params.adapter2.OemSection. When the migration DLL is to be loaded during the GUI mode phase, it typically does not write an InfToRunAfterInstall key to the AnswerFile. The DLL performs the post-installation upgrade; therefore, it does not need to create an Oem-Section name that contains directives for NetSetup to perform during the GUI mode phase.


Filter-Hook Driver

A filter-hook driver is a kernel-mode driver that is used to filter network packets. Filter-hook drivers extend the functionality of the system-supplied Internet Protocol (IP) filter driver. A filter-hook driver can only be installed on the Microsoft® Windows® 2000 operating system and later versions.

Only a single filter-hook driver can be installed on the operating system and used by the IP filter driver. A filter-hook driver can only register itself with the IP filter driver if the pointer to the extension hook for the IP filter driver is set to NULL. After the filter-hook driver is registered, the IP filter driver assigns the file object for the filter-hook driver to the extension hook for the IP filter driver, thereby ensuring that it can only accept and use a single filter-hook driver.

This section includes the following topics:

Creating a Filter-Hook Driver

For reference information, see the Filter-Hook Driver Reference.


Creating a Filter-Hook Driver

A filter-hook driver is a kernel-mode driver that implements a callback function called a filter hook and registers that callback function with the system-supplied IP filter driver. The IP filter driver then uses the filter hook to determine how to process incoming and outgoing packets. For more information on developing a kernel-mode driver, see Kernel-Mode Driver Components in the Microsoft® Windows DDK.

To supplement the Packet Filtering application programming interface (API), a filter-hook driver can be created to filter network packets. User-mode applications use this API to create and manage, in the system-supplied IP filter driver, input and output filters that filter packets with specific IP addresses or TCP/UDP port numbers. Because the Packet Filtering API optimizes the system-supplied IP filter driver to process packets without the overhead that is associated with a filter-hook driver, you should consider using this API if possible. For more information about the Packet Filtering API, see the Microsoft Windows Platform SDK documentation.

The following topics describe how to create a filter-hook driver:

Creating a Filter Hook

Filter Hook Example

Initializing and Unloading the Filter-Hook Driver

Setting and Clearing a Filter Hook

Implementing Filter Hook IOCTLs

Implementing Filter-Hook Drivers


Creating a Filter Hook

A filter hook is created by implementing a function of type PacketFilterExtensionPtr.

When a filter-hook driver registers its filter hook's entry point with the system-supplied IP filter driver, the filter-hook driver supplies the symbolic address of its filter hook. Because a filter-hook driver supplies the address, and not the name, of its filter hook entry point, the name of the filter hook can be any name that the driver writer chooses. However, it is good programming practice to choose a name that describes the filter hook's basic functionality.

A filter hook performs the following actions on incoming and outgoing packets:

  • Compares specific information with information that the IP filter driver passed to the filter hook to determine how packets should be further processed.
  • After the filter hook inspects packets, returns with one of the following response codes that direct the IP filter driver:
    PF_FORWARD
    Returns the forward response immediately to the IP stack.

    For local packets, IP forwards them up the stack. If the destination for packets is another computer and routing is enabled, IP routes them accordingly.

    PF_DROP
    Returns the drop response immediately to the IP stack. IP should drop the packet.
    PF_PASS
    Filters packets and return the resulting response to the IP stack. Continue to filter packets as defined by the Packet Filtering API.

    The filter hook returns this pass response if it determined that it should not process the packet but should allow the IP filter driver to filter the packet.


Filter Hook Example

The filter hook in this example is a simple filter hook that makes forward and drop decisions, based on certain packet properties. This example shows how the filter hook specifies to drop Transmission Control Protocol (TCP) packets and to forward packets from all other protocols.

If packets with specific IP addresses or TCP/UDP port numbers must be filtered, consider creating a user-mode application that uses the Packet Filtering API instead. The Packet Filtering API optimizes the system-supplied IP filter driver to process packets without the overhead that is associated with a filter-hook driver. For more information about the Packet Filtering API, see the Microsoft Windows Platform SDK documentation.

#define PROT_TCP   6

// Drop all TCP packets

PF_FORWARD_ACTION
DropTcpPackets(
        unsigned char   *PacketHeader,
        unsigned char   *Packet,
        unsigned int    PacketLength,
        unsigned int    RecvInterfaceIndex,
        unsigned int    SendInterfaceIndex,
        IPAddr          RecvLinkNextHop,
        IPAddr          SendLinkNextHop
        )
{
    if (PacketHeader->iph_protocol == PROT_TCP)
    {
        return PF_DROP;
    }
    return PF_FORWARD;
}


Initializing and Unloading the Filter-Hook Driver

All kernel-mode drivers create and initialize a device object for the driver object. The filter-hook driver's DriverEntry routine can also register the driver's filter hook with the IP filter driver.

If a user-mode application or a higher-level driver sends an I/O control request to the filter-hook driver to set up the filter hook, then the DriverEntry routine must specify and export an entry point that enables device control. This entry point is an IRP_MJ_DEVICE_CONTROL dispatch routine. If DriverEntry enables device control in this way, this device-control routine registers the driver's filter hook rather than DriverEntry.

The DriverEntry routine must specify and export an entry point that unloads the filter-hook driver. This unload routine removes the device that was created in DriverEntry but must not clear the previously registered filter hook when the operating system unloads the filter-hook driver.

For more information, see:

Setting and Clearing a Filter Hook

Implementing Filter Hook IOCTLs


Setting and Clearing a Filter Hook

A filter-hook driver sets its filter-hook callback function to the IP filter driver to inform that IP filter driver to call the hook callback for every IP packet that is received or transmitted. A filter-hook driver might also clear a previously registered hook callback. To register or clear a hook callback function, the filter-hook driver must first create an IRP using a pointer to the device object for the IP filter driver and IOCTL_PF_SET_EXTENSION_POINTER. The filter-hook driver then submits this IRP to the IP filter driver.

The filter-hook driver sets or clears hook callback functions as follows:

  • Calls the IoGetDeviceObjectPointer function to retrieve a pointer to the device object for the IP filter driver

    The filter-hook driver passes:

    • A pointer to a buffer that contains the string for the name of the IP filter driver
    • Values that specify synchronous, read, and write access to the IP filter driver
    • Pointers to buffers to hold the returned file and device objects
  • Calls the IoBuildDeviceIoControlRequest function to set up an IRP

    The filter-hook driver passes parameters that specify:

    • IOCTL_PF_SET_EXTENSION_POINTER value
    • Pointer to the device object for the IP filter driver
    • Buffer that contains an PF_SET_EXTENSION_HOOK_INFO structure

      To set the filter hook, this structure holds information that specifies the address of the filter-hook callback function. To clear the filter hook, this structure contains a NULL value.

    This call returns a pointer to an IRP with the I/O stack location set up from the supplied parameters.

  • Calls the IoCallDriver function to submit the IRP to the IP filter driver

    The filter-hook driver passes parameters that specify the pointer to the device object for the IP filter driver and a pointer to the previously created IRP.

The filter-hook driver must clear its filter hook from the same entity to which it registered its filter hook; therefore, the filter-hook driver should store the pointers to the IP filter driver's file and device objects in global variables. Only then can the filter-hook driver call the ObDereferenceObject function to decrement the reference count of the IP filter driver's file and device objects.


Implementing Filter Hook IOCTLs

A filter-hook driver implements an IRP_MJ_DEVICE_CONTROL dispatch routine in order for applications or higher-level drivers to send I/O control (IOCTL) requests down to the filter-hook driver to set up the filter hook. This dispatch routine processes these IOCTLs. The DriverEntry routine must specify and export an entry point for this dispatch routine.

Driver writers should define and publish information about these IOCTLs and what type of processing the filter hook performs. Applications or higher-level drivers can then use the published IOCTLs to setup the filter hook.

To retrieve an IOCTL request, a filter-hook driver's device-control routine must call the IoGetCurrentIrpStackLocation function, in which the routine passes a pointer to the IRP that was passed to the routine. The device-control routine then determines which IOCTL request was received and processes the request accordingly.

After the current IOCTL request completes, the device-control routine calls the IoCompleteRequest function and passes the status of the operation. This status is returned to the application or higher-level driver that made the request.

The following are typical IOCTLs that a filter-hook driver's device-control routine might process:

Set-Hook IOCTL
Registers a filter hook
Clear-Hook IOCTL
Clears the previously registered filter hook


Implementing Filter-Hook Drivers

When you implement a filter-hook driver, you should consider both the reliability and the efficiency of using this type of driver.

As with any kernel-mode driver, a filter-hook driver is considered a trusted component and can crash the system if it executes an illegal instruction or references an invalid region of memory.

The integrity of data being sent over the network might be suspicious or faulty hardware or other drivers might submit data in unexpected or improper formats. Therefore, a filter hook must validate the format of such data.

A filter hook must limit the amount of per-packet processing that it performs to reduce the overhead associated with each incoming and outgoing packet as well as registering the filter hook. A filter hook should be optimized to minimize the average time it spends processing packets.


Firewall-Hook Drivers

It is not recommended to implement a firewall-hook driver (or firewall driver) for Microsoft® Windows® XP and later versions of the operating system.

The Microsoft® Windows® 2000 DDK introduced the concept of a firewall-hook driver. The intent of a firewall-hook driver was to manage network packets that were sent and received across a firewall in the context of the TCP/IP protocol. A firewall is a control system that prevents unauthorized users from gaining access to a local network that is connected to the Internet.

A firewall-hook driver did not meet firewall requirements because it ran too high in the network stack. A firewall-hook driver could also interfere with the operations of Internet Connection Sharing (ICS) or a personal firewall implementation.

To provide firewall functionality on Windows XP and later, you should create an NDIS intermediate miniport driver to manage packets sent and received across a firewall. For information on creating an NDIS intermediate miniport driver, see NDIS Intermediate Drivers.


Supporting System Area Networks

A system area network (SAN) is a group of devices that are linked by a high-speed, high-performance connection. A SAN connection uses Internet Protocol (IP) addresses, which are assigned by TCP/IP to each SAN network interface controller (NIC), to determine data routing. It also uses a reliable transport, which is built into the SAN, to perform data delivery. A SAN can include, for example, clusters of client and server computers.

The following topics describe the performance benefits that client and server computers can achieve by interfacing with a SAN, and the software components you need to implement and supply.

Introduction to System Area Networks

Using a SAN with Windows Sockets Applications

Creating Components for Using a SAN

Virtual Interface Architecture and Support for SAN


Introduction to System Area Networks

A system area network (SAN) is a high-performance, connection-oriented network that can link a cluster of computers. A SAN delivers high bandwidth (1 Gbps or greater) with low latency. A SAN is typically switched by hubs that support eight or more nodes. The cable lengths between nodes on a SAN range from a few meters to a few kilometers.

Unlike existing network technologies such as Ethernet and ATM, a SAN offers a reliable transport service; that is, a SAN guarantees to deliver uncorrupted data in the same order in which it was sent. Connection endpoints in a SAN are not required to use the TCP/IP protocol stack to transfer data unless traffic must be routed between subnets. SAN-local communication can use a native SAN transport, bypassing the TCP/IP protocol stack.

A SAN network interface controller (NIC), a transport driver for the SAN NIC, or a combination of both exposes a private transport interface. However, because most networking applications are written to use TCP/IP through Windows Sockets, they cannot use a SAN directly. The Windows Sockets Direct components shown in the following figure let these applications benefit from using a SAN transparently without requiring modification. Windows Sockets Direct is part of:

  • Microsoft® Windows® 2000 Datacenter Server
  • Microsoft® Windows® 2000 Advanced Server SP2
  • Microsoft® Windows® 2000 Server Applicance Kit SP2
  • Microsoft® Windows® .NET Server

The following figure shows the architecture required to support a SAN. The shaded areas represent components that a SAN NIC vendor supplies to enable using a SAN.

SAN Architecture

The following is a description of the components shown in this figure.

Windows Sockets application
Application that interfaces with Windows Sockets for network services.
Windows Sockets
The Windows Sockets interface (Ws2_32.dll).
Windows Sockets SPI
The Windows Sockets service provider interface (SPI).
Windows Sockets switch
The Windows Sockets switch switches between use of the standard TCP/IP service provider and particular SAN service providers.
TCP/IP service provider
A user-mode DLL and associated kernel-mode proxy driver that comprise the standard base Windows Sockets service provider for TCP/IP. The proxy driver exposes a TDI interface.
TCP/IP
The standard TCP/IP protocol driver.
SAN service provider
The user-mode DLL portion of the SAN service provider.
Proxy driver for a SAN service provider
The kernel-mode proxy driver of the SAN service provider.
NDIS miniport driver
The NDIS miniport driver that supports communication to the SAN NIC using the standard TCP/IP protocol driver.
SAN transport
A reliable transport service, which can be fully implemented in the NIC, fully implemented in software, or implemented in a combination of both hardware and software.
SAN NIC
The physical SAN network interface controller (NIC).


Using a SAN with Windows Sockets Applications

Windows Sockets applications can benefit from using a system area network (SAN). These applications can use a SAN to transfer data in bulk form and to drop data directly onto the SAN network, without copying across the user-kernel boundary, using a technology called Windows Sockets Direct. Windows Sockets Direct lets these applications use a SAN transparently.

For each Windows Sockets application, Windows Sockets Direct can either:

  • Route data traffic that flows over a SAN directly to the SAN.

    The system-supplied Windows Sockets switch component of Windows Sockets Direct routes data traffic for a SAN that originates from a Windows Sockets application directly to the SAN NIC to be transferred over the SAN network. The switch uses that SAN's particular Windows Sockets service provider to transfer data.

  • Route data traffic that flows over other networks through TCP/IP.

    To route data traffic that is not for a specific SAN from a Windows Sockets application, the switch must use the TCP/IP service provider. Non-SAN–specific data traffic includes, for example, datagrams, multicast, and connections that must be routed. Non-SAN–specific data traffic is then routed through TCP/IP and the NDIS miniport driver to the SAN NIC.


Creating Components for Using a SAN

Windows Sockets applications can benefit from using a system area network (SAN). To use a SAN, these applications must have a SAN service provider DLL and a proxy driver for that DLL.

To use a specific SAN to transfer data, you also need a reliable transport for that SAN. If a reliable transport is not fully implemented in the SAN NIC hardware, you need a transport driver for the SAN. If required, a SAN transport driver is specified by the SAN NIC vendor and communicates with its overlying SAN proxy driver and underlying SAN NIC through private interfaces.

For information on implementing a SAN service provider DLL and its proxy driver, see Windows Sockets Direct. Note, however, that this section does not specify how to write a SAN transport driver.

You need an NDIS miniport driver to transfer data that must flow over networks other than your specific SAN such as Ethernet, ATM, or another SAN. TCP/IP uses the NDIS miniport driver to send data both to the SAN NIC and over such networks.

For information on implementing miniport and transport drivers, see NDIS Miniport Drivers and TDI Transports and Their Clients.


Virtual Interface Architecture and Support for SAN

The Virtual Interface (VI) architecture, proposed by Compaq, Intel, and Microsoft, is a design for an interface between a SAN NIC and a host computer system. This architecture represents only one aspect of design with regard to system area networks (SAN). There are alternate designs that share the same fundamental characteristics.

The VI architecture defines a set of capabilities and characteristics for SAN interconnects. For example, the VI architecture includes support for remote direct memory access (RDMA) operations. The VI architecture also describes specific mechanisms for interacting with a SAN NIC to manage endpoints and connections, and to process data transfer requests. For more information about the VI architecture, see the VI Architecture Web site.

The Windows Sockets switch works with a broader class of SAN interconnects beyond those that use the VI architecture. SAN extensions to the Windows Sockets service provider interface (SPI) shield the switch from the hardware interface for a particular SAN NIC. That hardware interface is encapsulated within a SAN service provider DLL and its kernel-mode proxy driver. These components are supplied by a SAN vendor. For more information about SAN extensions, see Windows Sockets SPI Extensions for SANs.


Windows Sockets Direct

Windows Sockets Direct is a technology that, when possible, routes data at high speed and with high performance to and from Windows Sockets applications through a system area network (SAN) instead of the TCP/IP transport and an NDIS miniport driver.

Windows Sockets Direct is included in:

  • Microsoft® Windows® 2000 Datacenter Server
  • Microsoft® Windows® 2000 Advanced Server SP2
  • Microsoft® Windows® 2000 Server Applicance Kit SP2
  • Microsoft® Windows® .NET Server

The following topics describe Windows Sockets Direct features and operations, the software components that enable Windows Sockets Direct, and the requirements for writing a SAN service provider and its associated proxy driver:

Windows Sockets Direct Architecture

Windows Sockets Direct Component Operation

Creating a Service Provider for a SAN

Creating a Proxy Driver for a SAN Service Provider


Windows Sockets Direct Architecture

Windows Sockets Direct provides a high-speed, high-performance connection between two network nodes on the same system area network (SAN) by mapping a SAN transport interface directly into an application process. This SAN connection enables user-mode processes to perform direct input and output (I/O) without copying across the user-kernel boundary.

The SAN architecture figure in Introduction to System Area Networks shows how Windows Sockets Direct provides a SAN connection. The shaded areas in the figure represent components that a SAN NIC vendor must supply to enable use of a SAN.

The following paragraphs describe the components that appear in the figure.

Supplied Components for SAN Network Interface Controllers

Each SAN network interface controller (NIC) uses the following software components to provide support for NDIS and for Windows Sockets Direct.

  • An NDIS miniport driver for a SAN NIC provides support for NDIS so that it can communicate with Windows Sockets applications using a standard TCP/IP protocol driver. This NDIS miniport driver supports standard media types such as Ethernet or ATM.
  • The SAN service provider DLL and its associated proxy driver provide support for Windows Sockets Direct. These Windows Sockets Direct components export the native transport semantics of an interconnect for the SAN to Windows Sockets applications. These semantics can include, for example, address family and message orientation.

The SAN NIC vendor supplies the NDIS miniport driver and Windows Sockets Direct components. The SAN NIC vendor might also supply a SAN transport driver if transport service is not implemented fully in the NIC. The proxy driver for a SAN service provider DLL and possibly a SAN transport driver are contained either in the NDIS miniport driver or in separate drivers, at the discretion of the SAN NIC vendor.

Windows Sockets Switch Components

The Windows Sockets switch is an operating system-supplied component of Windows Sockets Direct. The switch is a Windows Sockets service provider that is layered on top of TCP/IP and SAN service providers. Microsoft Windows inserts the switch between the Windows Sockets interface and the other service providers. For clarity, the switch appears in the figure as a separate entity. However, the switch and the base TCP/IP service provider are actually implemented in the same DLL. The switch performs the following actions:

  • Makes the installed collection of SAN service providers and the standard TCP/IP provider look like a single provider to Windows Sockets applications.
  • Chooses, on a per-connection basis, whether to use a native SAN service provider or the standard TCP/IP provider to service an application socket.
  • Emulates TCP/IP semantics when using a native SAN service provider.

The top and bottom interfaces of the switch conform to the Windows Sockets Service Provider Interface (SPI). The switch's bottom interface uses extensions to the Windows Sockets SPI to take advantage of a SAN's capabilities. Those extensions are described in Windows Sockets SPI Extensions for SANs and fully documented in the Windows Sockets Direct Reference.

The switch manages application access to all networks. A computer can contain multiple SAN NICs from multiple vendors, as well as one or more LAN and WAN NICs, such as a LAN NIC that supports an Ethernet network. The switch manages application access to all networks associated with these NICs transparently.

TCP/IP Functions

As with any NIC exposed through NDIS, the TCP/IP protocol driver assigns one or more IP addresses to each SAN NIC. The Windows Sockets switch and SAN service providers determine these assignments, as described in Receiving and Translating NIC Addresses. The switch uses this IP address information to determine which SAN service provider to use for a given socket connection. SAN service providers use this IP address information to translate IP addresses into native SAN addresses.

The switch works closely with the standard base TCP/IP service provider to obtain functionality that SAN service providers do not support. The TCP/IP service provider supports listening for connections on multiple providers and synchronization across multiple providers.

The TCP/IP service provider also handles all communication over standard LAN and WAN interconnects, raw IP sockets, all UDP sockets, and connections between subnets.


Windows Sockets Direct Component Operation

This sections describes Windows Sockets Direct operations, including the operation of the Windows Sockets switch, a SAN service provider, and the SAN service provider's associated proxy driver.

This section includes the following topics:

Installing Windows Sockets Direct Components

Initializing the Use of a SAN

Setting Up a SAN Connection

Transferring Data on a SAN

Synchronizing Operations on a SAN

Shutting Down the Use of a SAN

Blocking Calls for a SAN

Duplicating Socket Handles for a SAN

Handling Socket Options and Control Codes for a SAN

Handling Microsoft Extensions to Windows Sockets


Installing Windows Sockets Direct Components

The following topics describe how Windows Sockets Direct components (that is, the Windows Sockets switch and individual SAN service providers) are installed:

Installing the Windows Sockets Switch

Installing a SAN Service Provider


Installing the Windows Sockets Switch

Microsoft Windows installs the Windows Sockets switch as a layered service provider, with the Windows Sockets service provider interface (SPI) as both the top and bottom interface. The switch exports the protocol characteristics of TCP/IP just like the TCP/IP service provider. The switch is the first visible TCP/IP provider, which makes the switch the default choice for applications that open sockets for the AF_INET address family.


Installing a SAN Service Provider

A SAN service provider is typically installed as a base Windows Sockets service provider that interfaces with the Windows Sockets switch. Although a SAN service provider can be installed for direct use by an application instead, the Windows Sockets Direct technology does not support using a SAN service provider in this manner. A SAN service provider that is installed for direct use by an application exports its native address family and protocol characteristics rather than those of TCP/IP protocol.

A SAN service provider that is indirectly exposed to applications through the Windows Sockets switch must set the PFL_HIDDEN flag in the dwProviderFlags member of the SAN service provider's WSAPROTOCOL_INFOW structure. To install the SAN service provider on the operating system, the SAN service provider's installation mechanism passes this structure in a call to the WSCInstallProvider function. For more information on WSCInstallProvider, see the Platform SDK documentation. The SAN service provider's installation mechanism can be for example, a setup program or a function exported by the SAN service provider and called by a INF file directive.

The SAN service provider's installation mechanism must add a value of type REG_BINARY to the following key in the registry before the SAN service provider can be detected by the Windows Sockets switch as a base Windows Sockets service provider:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Winsock\
Parameters\TCP on SAN

This value contains the binary representation of the value in the ProviderId member from the WSAPROTOCOL_INFOW structure. This value registers a SAN service provider with the Windows Sockets switch. This member contains the globally unique identifier (GUID) that the vendor assigned to the SAN service provider.

The vendor can also assign a unique name that represents this GUID, for example:

  • Trademarked name of the product
  • Unique numeric value
  • Textual representation of the GUID

To register a SAN service provider

  1. The switch calls the WSAProviderConfigChange function to detect Windows Sockets provider installation and removal events.
  2. After a new Windows Sockets service provider is installed, the switch calls the WSCEnumProtocols function to query the Windows Sockets catalog and the list of SAN service providers in the registry to determine whether the new service provider controls a SAN. For more information on WSCEnumProtocols, see the Platform SDK.
  3. If the switch detects a new SAN service provider, the switch initializes that service provider as described in Initializing SAN Service Provider.
  4. The switch also calls the following functions of the newly installed SAN service provider after the SAN service provider is initialized to service any existing listening sockets bound to the wildcard IP address (0.0.0.0) (the wildcard IP address implies that the SAN service provider should accept incoming connection requests from all NICs it controls):
    WSPSocket
    Creates a socket
    WSPBind
    Binds the socket to the wildcard IP address
    WSPListen
    Sets the socket to acknowledge and queue incoming connection requests until accepted by the switch


Initializing the Use of a SAN

The following topics describe how to initialize the use of a SAN:

Initializing SAN Service Provider

Receiving and Translating NIC Addresses


Initializing SAN Service Provider

Previous Next

Initializing a SAN Service Provider

The Windows Sockets switch initializes a SAN service provider as described in the following figure.

Initializing a SAN Service Provider

After Windows loads the Windows Sockets switch DLL into an application's process, the following sequence of events occur.

To initialize a SAN service provider

  1. The switch detects and loads the TCP/IP provider and then queries the list of SAN service providers in the registry to detect all of those providers, as described in Installing a SAN service provider. The switch calls each detected provider's WSPStartupEx function to initiate use of that provider.
  2. In the WSPStartupEx call, the switch passes a pointer to a WSAPROTOCOL_INFOW structure that contains the TCP/IP provider's protocol information. The TCP/IP provider's protocol indicates to the SAN service provider that it has been initialized by the switch rather than by other layered service providers or the Windows Sockets interface. The switch passes the TCP/IP provider's protocol information instead of the SAN service provider's transport information, as suggested in the Windows Sockets service provider Interface (SPI) section of the Platform SDK documentation.

    Because a SAN service provider can detect that it is initialized by the switch, it can expose the appropriate set of entry-point functions to the switch. If the SAN service provider is initialized directly by an application, it can expose another set of entry-point functions to that application. If a SAN service provider is layered under the switch, that provider must adhere to the extensions and behavior described in this section.

  3. A SAN service provider's proxy driver obtains the list of IP addresses assigned to each NIC under its control as described in Registering for SAN NIC Notifications. The SAN service provider uses a private interface to retrieve this list from its proxy driver. The switch calls a SAN service provider's WSPSocket function to create a socket. The switch uses this socket to retrieve the complete list of IP addresses assigned to the NICs under control of the SAN service provider's proxy driver. The switch retrieves this list as described in Receiving and Translating NIC Addresses. Based on this list and the lists of other SAN service providers, the switch builds a table that maps local IP subnets to SAN service providers.
  4. The Windows Sockets switch must retrieve pointers to the SAN service provider's entry-point functions that extend Windows Sockets service provider Interface (SPI) for use with SANs. To retrieve each of these extended functions, the Windows Sockets switch calls a SAN service provider's WSPIoctl function and passes the SIO_GET_EXTENSION_FUNCTION_POINTER command code along with the GUID whose value identifies one of these extended functions.

    For a complete description of these functions, see Windows Sockets SPI Extensions for SANs.

  5. The switch can create threads to support listening sockets as well as nonblocking connect requests, as described in Setting Up a SAN Connection.


Receiving and Translating NIC Addresses

The Windows Sockets switch always uses the AF_INET address family, which contains IP addresses, when it interacts with SAN service providers and SAN NICs. The switch does not use a SAN's native address family. Therefore, a SAN service provider must use its associated proxy driver to retrieve the list of IP addresses assigned to its NICs. The SAN service provider uses these IP addresses when interacting with its proxy driver. The proxy driver must translate between IP addresses and native addresses.

During initialization, a proxy driver typically registers with Transport Driver Interface (TDI) for address change notifications. All Plug and Play (PnP) aware transports, including TCP/IP, supply address change notifications through TDI to clients that have registered for such notifications.

Registering for Address Change Notification

During initialization, a proxy driver calls the TdiRegisterPnPHandlers function to register for address change notifications. In this call, the proxy driver passes pointers to callback functions for address additions and deletions in the AddAddressHandlerV2 and DelAddressHandlerV2 members of the TDI_CLIENT_INTERFACE_INFO structure. After the proxy driver registers to receive these notifications, TDI promptly indicates all currently active network addresses using the add-address callback.

TDI passes the following parameters to a proxy driver's add-address or delete-address callback functions:

Address
Pointer to a TA_ADDRESS structure that describes the network address assigned to or removed from the NIC. In the case of TCP/IP, this pointer is actually a pointer to a TA_ADDRESS_IP structure.
DeviceName
Pointer to a Unicode string that identifies the transport-to-NIC binding with which the address is associated. In case of TCP/IP, the Unicode string has the following format:

\Device\Tcpip_{NIC-GUID}

where NIC-GUID is the globally unique identifier assigned by the network configuration subsystem to the NIC.

The preceding structure definitions are defined in the tdi.h header file. The preceding registration and callback functions are defined in the tdikrnl.h header file. These header files are available in the Windows Driver Development Kit (DDK). Detailed information about TDI PnP notifications is also available at TDI Client Callbacks and TDI Client Event and PnP Notification Handlers.

Maintaining a List of IP Addresses

A SAN service provider's proxy driver uses add-address and delete-address notifications to maintain the list of IP addresses assigned to each NIC under its control. The proxy driver uses this list to translate between one or more IP addresses assigned to a SAN NIC by the TCP/IP transport and native SAN addresses. The proxy driver must also supply a device-control routine that makes the list of IP addresses assigned to a NIC available to the Windows Sockets switch whenever the switch makes an SIO_ADDRESS_LIST_QUERY control-code query. The proxy driver's DriverEntry routine must specify an entry point for this device-control routine.

The Windows Sockets switch maintains a list of all IP addresses assigned to each SAN NIC. To retrieve IP addresses for this inclusive list, the switch calls each SAN service provider 's WSPIoctl function, passing the SIO_ADDRESS_LIST_QUERY control code. Each SAN service provider, in turn, queries its associated proxy driver for its individual list of IP addresses assigned to its SAN NICs. After the switch is notified of an address change, it again queries each SAN service provider for updates in each individual list.


Setting Up a SAN Connection

During connection setup, the Windows Sockets switch determines which service provider will service the TCP socket. This provider will handle most subsequent operations on the socket. Regardless of whether the switch chooses a SAN service provider, the TCP/IP provider exclusively handles a few types of setup operations.

The following topics describe the connection setup operations that a SAN service provider performs and include information about the connection setup operations that the TCP/IP provider handles.

Creating and Binding SAN Sockets

Initiating a Connection

Listening for Connections on a SAN

Accepting Connection Requests

Registering Memory for Operations on a SAN

Caching Registered Memory


Creating and Binding SAN Sockets

If the Windows Sockets switch determines that it can route data through a SAN connection rather than through the TCP/IP stack, it requests the appropriate SAN service provider to create, bind, and set options for a socket on which the data can be transferred.

The socket created by the SAN service provider is a companion to the socket that the TCP/IP service provider created at the request of the application, either from or to which the data is being transferred. The companion socket created by the SAN service provider has the same options as the socket created by the TCP/IP service provider, if the SAN service provider supports those options.

The companion socket also has the same IP address and TCP port as the socket that was created by the TCP/IP service provider. The SAN data is transferred through the companion socket created by the SAN service provider rather than the socket created by the TCP/IP service provider. The SAN socket is not visible to the application. From the application's perspective, the data is transferred on the socket that it requested to be created for the data transfer.

Note The switch always uses the TCP/IP service provider to transfer data over raw sockets. The switch therefore never requests a SAN service provider to create a raw socket.

The following figure shows an overview of how the Windows Sockets switch creates a companion socket. The sequence in the sections that follow describe creating a companion socket in more detail.

Creating a Companion Socket

Initiating Creation of a TCP/IP Socket

  1. After the Windows Sockets switch receives a WSPSocket call that was initiated by an application, the switch calls the TCP/IP provider's WSPSocket function to request the TCP/IP provider to create a socket.
  2. The Windows Sockets switch returns the descriptor for the created socket to the application and stores this descriptor in a private data structure that is associated with the socket.

    From the application's perspective, the socket created by the TCP/IP provider is the socket used for data transfers, whether the switch uses the TCP/IP service provider or the SAN service provider to transfer the data.

Binding a TCP/IP Socket

  3. The switch receives a WSPBind call if an application requests to bind the socket to a specific network interface controller (NIC) or to the wildcard IP address (0.0.0.0). A socket bound to the wildcard IP address can listen for incoming connection requests from all NICs.
  4. The switch forwards this call to the TCP/IP service provider by calling the TCP/IP provider's WSPBind function.

Service Provider Determination

  5. The switch determines whether to use a SAN service provider for data transfer on a socket after the application initiates a WSPListen or WSPConnect call to the switch, as described in Setting Up a SAN Connection.
  6. If the switch determines that it cannot use a SAN service provider for a data transfer, the switch routes the data transfer through the TCP/IP service provider.
  7. If the switch chooses a SAN service provider to service an application's socket, the switch calls the SAN service provider's WSPSocket function to create a companion socket.

Initiating Creation of a Companion Socket

  8. The SAN service provider's WSPSocket function initializes an internal data structure in which it stores information about the companion socket.
  9. The SAN service provider's WSPSocket function must next call the WPUCreateSocketHandle function to acquire a socket descriptor from the switch.
  10. The SAN service provider must store the switch's socket descriptor in its internal data structure for the companion socket and must return its own descriptor for the companion socket to complete the WSPSocket call. The socket descriptor returned by the SAN service provider can be any meaningful value, such as a pointer to a private data structure.
  11. To perform an operation on the socket, the switch supplies the socket descriptor that was returned by the SAN service provider to the appropriate function of the SAN service provider. Similarly, the SAN service provider must supply the socket descriptor that was acquired from the switch in the WPUCreateSocketHandle call if the SAN service provider makes any of the following up calls:

    WPUQuerySocketHandleContext

    WPUCloseSocketHandle

    WPUCompleteOverlappedRequest

    For more information about these functions, see the Platform SDK documentation.

Binding a Companion Socket

  12. If a SAN service provider's WSPSocket function completes successfully, the switch immediately calls the SAN service provider's WSPBind function to assign a local IP address and TCP port to the socket.
  13. The switch assigns the same IP address and TCP port to the SAN socket as was assigned to the socket that was created by the TCP/IP provider. The SAN service provider must translate this TCP/IP address into its native format.
  14. The switch supplies a fully qualified IP address and TCP port (that is, nonzero values) to the SAN service provider's WSPBind function unless an application requested to listen for incoming connections from all NICs. In the later case, the switch supplies the wildcard IP address to the SAN service provider's WSPBind function.

Setting Options for a Companion Socket

  15. If the application specified any socket options, the switch stores those options. After creating the SAN socket, the switch calls the SAN service provider's WSPSetSockOpt function for each supported option that was specified by the application to immediately set these options for the SAN socket.

Failing a Companion Socket Call

  16. If a SAN service provider fails any of the preceding calls to its WSPSocket, WSPBind, or WSPSetSockOpt functions, the switch calls the SAN service provider's WSPCloseSocket function to destroy the SAN socket. The switch then uses the TCP/IP provider to continue servicing the application socket. Note that, after the switch establishes a connection using a SAN service provider, the switch cannot use the TCP/IP provider to service the application's socket. In this case, the switch returns the appropriate error to the application.

Connecting the Companion Socket

  17. After the switch sets up the companion socket, the switch calls either the WSPListen or WSPConnect function for the SAN service provider to perform the operation that caused the SAN service provider to originally set up the socket. For example, if an application originally requested to listen for incoming connections, the switch calls the SAN service provider's WSPListen function.


Initiating a Connection

After the Windows Sockets switch receives a WSPConnect call that was initiated by an application, the switch compares the destination address of the connect request with addresses in the switch's table of IP subnets that SAN service providers serve. If one of those subnets includes this destination address, the switch calls the WSPSocket and WSPBind functions of the corresponding SAN service provider to create and bind a socket, as described in Creating and Binding SAN Sockets. The switch processes the application's connect request using the SAN socket. If the destination address of the connect request is not on a SAN subnet, or if the SAN service provider fails to create and bind a socket, the switch uses the TCP/IP provider to establish the connection.

The following figure shows an overview of how the Windows Sockets switch requests a connection with a remote peer. The sequence and sections that follow describe the connection request in more detail.

Connection Request Flow Diagram

After creating and binding the SAN socket, the switch executes a connect request, using the SAN socket in nonblocking mode, as described in the following procedure.

To execute a connect request

  1. The switch calls the SAN service provider's WSPEventSelect function. In this call, the switch passes the FD_CONNECT code and the event object to be associated with that code. The call to WSPEventSelect requests notification of connection events and informs the SAN service provider that any subsequent WSPConnect call executes in nonblocking mode.
  2. After the WSPEventSelect function returns, the switch calls the SAN service provider's WSPConnect function. In this call, the switch passes the destination address in AF_INET format. The SAN service provider's proxy driver maps this destination address to a native address and attempts to establish the connection.
  3. If the SAN service provider's WSPConnect function can complete or fail the connection operation immediately, it returns the appropriate success or failure code. If the SAN service provider's WSPConnect function cannot complete a connection request immediately, the SAN service provider's connection operation proceeds asynchronously in another thread. The SAN service provider's WSPConnect function returns with the error WSAEWOULDBLOCK to indicate that the socket is marked as nonblocking and that the connection operation cannot be completed immediately.
  4. After the connection operation completes, the SAN service provider calls the Win32® SetEvent function to signal the event object that was previously registered in the WSPEventSelect call.
  5. After the event object is signaled, the switch calls the SAN service provider's WSPEnumNetworkEvents function to obtain the result of the connection operation.

Note After the switch establishes a connection through a SAN service provider, the switch can no longer use the TCP/IP provider for that connection. SAN service providers must fully implement all functionality required to service an established connection.

Destroying the SAN Socket

If the SAN service provider's WSPConnect function fails, the switch calls the SAN service provider's WSPCloseSocket function to destroy the SAN socket. The switch then calls the TCP/IP service provider's WSPConnect function to forward the connection operation to the TCP/IP service provider unless the SAN service provider returned one of the following error codes as the result of its connection operation:

WSAECONNRESET
Indicates that no application is listening on the specified port at the destination address
WSAECONNREFUSED
Indicates that the remote application actively refused the connection request
WSAEHOSTUNREACH
Indicates that the destination address does not exist

These preceding error codes guarantee that an attempt to establish the connection through TCP/IP will also fail. A SAN service provider must not return one of these error codes if it cannot make that guarantee. For example, if a target computer that does not support Windows Sockets Direct exists on the SAN but can only communicate through NDIS, the SAN service provider cannot return WSAEHOSTUNREACH as the result of a failed SAN connection request to this target because a connection request through the TCP/IP provider might succeed. In this case, the SAN service provider should return WSAETIMEDOUT.

Session Negotiation

After the switch establishes a connection through a SAN service provider, the switch calls the SAN service provider's WSPRegisterMemory extension function to preregister the memory for the buffer array that is to receive incoming messages. The switch next calls the SAN service provider's WSPRecv function to post one or more buffers to receive incoming message data from the remote peer. The switch then negotiates a session with its remote peer by exchanging a pair of messages that contain initial flow control information. After the switch negotiates a session, it completes the WSPConnect call that the application initiated. The application can then begin sending and receiving data on the connection. For more information, see Accepting Connection Requests.

After a connection is established over a SAN socket, the switch does not call the SAN service provider's WSPConnect function. The switch internally handles applications that initiate a call to the switch's WSPConnect function to poll for connection requests.


Listening for Connections on a SAN

The following figure shows an overview of how the Windows Sockets switch sets a SAN socket to acknowledge and queue—that is, listen for—incoming connection requests from a remote peer. The topics that follow describe the listening process in more detail.

Setting a SAN Socket to Listen Mode

When the Windows Sockets switch receives a WSPListen call that was initiated by an application, the switch always calls the TCP/IP provider's WSPListen function first to set the TCP/IP provider's socket to acknowledge and queue incoming connection requests. If the application's socket is bound to the IP address of a SAN NIC or to the wildcard IP address, the switch also uses the appropriate SAN service provider to create and bind an additional socket. For more information, see Creating and Binding SAN Sockets.

Listening for Incoming Connection Requests

After requesting a SAN service provider to create and bind the SAN socket, the switch calls the WSPListen function of the SAN service provider to cause the SAN socket to listen for incoming connections and to specify a limit on the number of incoming connection requests that the SAN service provider can queue.

Setting Up to Accept Incoming Connections

The switch accepts incoming connections only in nonblocking mode. The switch calls the SAN service provider's WSPEventSelect function to put a socket in nonblocking mode and to request notification of incoming connection events. In this call, the switch passes the FD_ACCEPT code and the event object to be associated with that code. After the SAN service provider receives a connection request on its socket that was previously established for listening, the SAN service provider calls the Win32® SetEvent function to signal the associated event object. The switch listens for incoming connection events in a dedicated thread and accepts or rejects the connection after the event object is signaled. For more information, see Accepting Connection Requests.

Indicating Refusal of a Connection Request to a Remote Peer

If a connection request arrives and the SAN service provider's backlog of connection requests is full, the SAN service provider should immediately indicate to the remote peer that it refuses the connection request. In this case, the SAN service provider does not signal the event object to inform the switch to accept or reject the connection request. The SAN service provider on the remote peer must then fail its connection operation that was initiated by a WSPConnect call with the WSAECONNREFUSED error code.


Accepting Connection Requests

If an application calls the WSAAccept, accept, or AcceptEx function to accept an incoming connection request on a socket, the Windows Sockets switch always forwards this call to the TCP/IP service provider. If an incoming connection request arrives from a nonSAN network, it flows through the NDIS path and the TCP/IP service provider handles it. If a connection request arrives from a remote peer on a SAN, the switch acts as an intermediary between the TCP/IP service provider and the SAN service provider in determining whether to accept the connection request and in completing the application's WSAAccept, accept, or AcceptEx function.

The following figure shows an overview of the interaction between the Windows Sockets switch and the SAN service provider in determining whether to accept or reject an incoming connection request. The sequences and sections that follow describe acceptance determination in more detail.

Accepting an Incoming Connection Request

To accept or reject a connect request

  1. On receiving an incoming connection request from a remote peer, the SAN service provider signals an event object as described in Listening for Connections on a SAN.
  2. The Windows Sockets switch calls the SAN service provider's WSPEnumNetworkEvents function to receive the FD_ACCEPT event code.
  3. On receiving the FD_ACCEPT event code, the switch calls the SAN service provider's WSPAccept function to accept or reject the incoming connection request.
  4. In the switch's call to the SAN service provider's WSPAccept function, the switch specifies a condition function. The SAN service provider must call this condition function in the same thread in which the WSPAccept function was called before returning from the WSPAccept call.
  5. The switch returns the CF_ACCEPT, CF_DEFER, or CF_REJECT code from this condition function to indicate that it accepts, defers, or rejects the connection request respectively.

Accepting a Connection Request and Creating an Accepting Socket

If an application accepts an incoming connection request, the switch returns the CF_ACCEPT code to the SAN service provider to complete the switch's condition function. On receiving CF_ACCEPT, the SAN service provider initializes an internal data structure in which it stores information about the accepting socket. The SAN service provider's WSPAccept function must next call the WPUCreateSocketHandle function to acquire a descriptor for the accepting socket from the switch. The SAN service provider must store the switch's descriptor in its internal data structure for the accepting socket and must return its own descriptor for the accepting socket to complete the WSPAccept call. The switch must supply the SAN service provider's internal descriptor for the accepting socket when calling the SAN service provider's functions, while the SAN service provider must supply the switch's socket descriptor in up calls to the switch.

Before successfully completing WSPAccept, the SAN service provider should call the Win32® ResetEvent function to reset the event object. Doing so enables the SAN service provider to later call the Win32® SetEvent function to signal the switch to accept the next incoming connection request.

Rejecting a Connection Request

If an application rejects an incoming connection request, the switch returns the CF_REJECT code to the SAN service provider to complete the switch's condition function. On receiving CF_REJECT, the SAN service provider should return the WSAECONNREFUSED error code to the switch to complete the WSPAccept call.

Deferring Connection Request Acceptance

If an application defers acceptance of an incoming connection request, either explicitly through a condition function or implicitly by delaying its accept call, the switch returns the CF_DEFER code to the SAN service provider to complete the switch's condition function. On receiving CF_DEFER, the SAN service provider should keep the connection request in the queue and return the WSATRY_AGAIN error code to the switch to complete the WSPAccept call.

To prevent a SAN service provider from signaling the switch to accept an additional incoming connection request while awaiting the acceptance or rejection of a deferred connection request, a SAN service provider must not call the Win32 ResetEvent function to reset the event object before returning from the WSPAccept call. Instead, the SAN service provider should queue such incoming connection requests. The maximum number of incoming connection requests that the SAN service provider can queue was specified in the backlog parameter that the switch passed to the SAN service provider's WSPListen function. When the application eventually accepts or rejects the deferred connection request, the switch again calls the SAN service provider's WSPAccept function and returns either CF_ACCEPT or CF_REJECT codes from its condition function. At this point, the SAN service provider should call the Win32 ResetEvent function to reset the event object. Doing so enables the SAN service provider to later call the Win32 SetEvent function to signal the switch to accept the next incoming connection request in the SAN service provider's backlog queue.

Indicating Acceptance or Refusal of a Connection Request to a Remote Peer

Before a SAN service provider can indicate to a remote peer that it accepts or refuses the remote peer's connection request, the SAN service provider must call the switch's condition function. Depending on the value that the switch's condition function returns, the SAN service provider should make one of the following indications to the remote peer:

If the switch's condition function returns CF_ACCEPT, the SAN service provider should indicate that it accepts the remote peer's connection request. The SAN service provider on the remote peer can then successfully complete its connection operation that was initiated by a WSPConnect call.

If the switch's condition function returns CF_REJECT, the SAN service provider should indicate that it refuses the remote peer's connection request. The SAN service provider on the remote peer must fail its connection operation that was initiated by a WSPConnect call with the WSAECONNREFUSED error code.

If the switch's condition function returns CF_DEFER, the SAN service provider should indicate that it accepts the remote peer's connection request and should keep the connection request in the queue. (Note that the TCP/IP service provider also has this behavior of indicating acceptance of the connection request even though the application has deferred acceptance.) When the switch later calls the SAN service provider's WSPAccept function to accept or reject the deferred connection request, the switch's condition function returns either the CF_ACCEPT or CF_REJECT value. If the switch's condition function returns CF_REJECT, the SAN service provider should tear down the already established connection.

Session Negotiation

After the switch has successfully used a SAN service provider to accept a connection request from a remote peer, the switch negotiates a session with that peer.

To negotiate a session

  1. The switch at the remote peer calls the SAN service provider's WSPRecv function to post a set of receive buffers.
  2. The switch at the remote peer calls the SAN service provider's WSPSend function to send a session negotiation message to the switch at the local accepting endpoint. This message includes the number of receive buffers that the switch at the remote peer posted.
  3. The switch at the local accepting endpoint calls the local SAN service provider's WSPRecv function to post its own receive buffers, but it might not be able to do so in time to receive the session negotiation message. If the local switch does not post a receive buffer in time, the SAN service provider at the local accepting endpoint must buffer the remote switch's session negotiation message. Note that a SAN service provider must not drop a connection simply because the switch did not post a receive buffer before the session negotiation message arrived. The maximum length of a session negotiation message is 256 bytes.
  4. The switch at the local accepting endpoint posts its receive buffers before responding to the session negotiation message. The local switch calls the local SAN service provider's WSPSend function to respond to the session negotiation message. The local switch's response includes the number of receive buffers that the local switch posted. From this point forward, the local switch guarantees that the posted set of receive buffers is of sufficient size to receive any message that arrives on the connection.
  5. If an application specifies an initial receive buffer in its AcceptEx call, the switch waits until it receives the first data message from its remote peer before completing the application's AcceptEx call.
  6. If the application cancels its own accept call, the switch calls the appropriate SAN service provider's WSPCloseSocket function to close the accepting SAN socket.


Registering Memory for Operations on a SAN

The Windows Sockets switch calls a SAN service provider's extension functions to register all data buffers for sending and receiving messages and for RDMA operations on a system area network. These extension functions register a buffer to a region of physical memory for use on a particular SAN socket that is connected to a remote peer. For a description of these extension functions, see the Windows Sockets SPI Extensions for SANs.

Registering Data Buffers

The switch calls a SAN service provider's WSPRegisterMemory extension function on behalf of an application that runs in a local process to register data buffers that can be accessed only by that process. The buffer handles that WSPRegisterMemory returns are valid only in the context of the local process that performed the registration. The switch calls WSPRegisterMemory to register buffers that serve as the message receiving buffer in a call to the WSPRecv function or the message sending buffer in a call to the WSPSend function. The switch also calls WSPRegisterMemory to register buffers that serve as the local receiving RDMA buffer in a call to the WSPRdmaRead extension function or the local RDMA source in a call to the WSPRdmaWrite extension function. After the local process finishes using buffers that were registered with WSPRegisterMemory, the switch calls the WSPDeregisterMemory extension function to release those buffers.

The switch calls the SAN service provider's WSPRegisterRdmaMemory extension function on behalf of an application that runs in a local process to register RDMA buffers that both local and remote processes can access. The buffer descriptors that WSPRegisterRdmaMemory returns are valid only for RDMA data transfer operations that a remote peer initiates in the context of the peer's connection to the SAN socket on which the registration was performed. The switch at the remote peer connection uses these RDMA buffers as either the target in a call to the WSPRdmaWrite extension function or the source in a call to the WSPRdmaRead extension function. After the local and remote processes finish using buffers that were registered with WSPRegisterRdmaMemory, the switch calls the WSPDeregisterRdmaMemory extension function to release those buffers.

Managing Memory Access

A SAN service provider must prevent unauthorized access to registered memory.

Memory must be registered and accessible as follows:

Memory registered for local access should be available only to the process in which the switch called WSPRegisterMemory.

Memory registered for both local and remote access can be accessed by either the process in which the switch called WSPRegisterRdmaMemory to register memory, or by the remote peer that is connected to the SAN socket to which the memory is registered.

Memory must be accessible only while registered and while the connection is established. A SAN service provider must ensure that it does not inadvertently make such memory accessible to other processes running on the same computer or on other computers on the SAN.

Memory registered only for read access must not be available for write access. Memory registered only for write access must not be available for read access.

Using Registered Memory

The switch registers two virtually contiguous regions of memory for each connected TCP socket to use for negotiating a data-transfer session. The switch uses one region of memory to provide message buffers containing send data when calling a SAN service provider's WSPSend function. The switch uses the other region of memory to post message buffers to receive data when calling a SAN service provider's WSPRecv function.

The switch typically registers RDMA buffers only if it transfers application data in RDMA operations.

Before the switch closes a socket, the switch calls either WSPDeregisterMemory or WSPDeregisterRdmaMemory functions of a SAN service provider to release any memory that a pending data transfer operation is not currently using. The SAN service provider must also release memory associated with outstanding data transfer operations.


Transferring Data on a SAN

Many system area networks (SANs) lack flow control; therefore, the Windows Sockets switch uses a lightweight session protocol to transfer data on a SAN. The following topics describe features of the switch's session protocol that enable data transfer operations for a SAN service provider:

Using Session Protocol

Sending Urgent Data on a SAN

Completing Data Transfer Requests


Using Session Protocol

The Windows Sockets switch uses its session protocol to transfer data over a SAN connection. If the switch transfers a small amount of data, it transfers that data within a control message. Each control message consists of a header and an optional payload of application data. If the switch transfers a large amount of data, it transfers that data using RDMA operations.

This section describes how to set up and perform a data transfer.

Note Depending on the behavior of applications that load the switch, the switch optimizes its session protocol to reduce the overhead involved in transferring application data.

This section also provides examples of how the switch's session protocol performs data transfers. However, these examples do not include definitive descriptions of these operations.

Setting Up a Data Transfer

The switch allocates a pool of control message buffers for each connected socket. The switch then makes calls to the SAN service provider's WSPRegisterMemory function to register those message buffers to regions of physical memory. The switch uses part of the buffer pool to send flow control information to a remote peer when calling a SAN service provider's WSPSend function. The switch uses the other part of the pool to post message buffers to receive flow control information from a remote peer when calling a SAN service provider's WSPRecv function. After the switch receives control messages, it immediately consumes them. After consuming control messages, the switch calls the SAN service provider's WSPRecv function and passes receive buffers to post them again so they can receive additional control messages from a remote peer.

Transferring Application Data

The size of the data transfer affects how the switch will handle the data transfer operation.

If an application requests to send a small amount of data, the switch transfers that data as described in Sending Urgent Data on a SAN.

If an application requests to send a large amount of data, the switch copies the initial portion of the data to a control message buffer that is used for sending. The header for this control message contains information that specifies the amount of application data. The switch then calls the SAN service provider's WSPSend function to send this control message to the SAN socket's remote peer.

The switch completes the transfer of application data in either of the following two ways:

Data Transfer to WSPRdmaRead-Supported Provider

The following figure shows an overview of how the switch completes the transfer of application data if the SAN service provider at the remote peer supports a WSPRdmaRead function. The sequence that follows describes transferring application data in more detail.

Remote Peer Supports WSPRdmaRead

To transfer data when the remote peer supports WSPRdmaRead

  1. The local switch must call the SAN service provider's WSPRegisterRdmaMemory function to register RDMA memory for read access. In this case, the control header for the message buffer also identifies the descriptor for the RDMA memory that holds the application's remaining data.
  2. The switch at the remote peer then calls WSPRdmaRead to transfer application data from RDMA memory to receiving buffers that the switch at the remote peer previously registered with WSPRegisterMemory calls. The SAN service provider transmits the buffered data in the background. Doing so allows applications that do not post more than one send at a time to post another send request while the SAN service provider sends buffered data.
  3. The switch at the remote peer then calls WSPSend to send a control message to the local switch to indicate that the transfer is complete.
  4. The local switch calls the WSPDeregisterRdmaMemory function to release RDMA memory.
  5. The local switch completes the application's send request. If the switch cannot fully register memory for the application's data buffers or if temporary memory cannot be fully allocated, it completes an application's send request with the WSAENOBUFS error code.

Data Transfer to Non-WSPRdmaRead-Supported Provider

The following figure shows an overview of how the switch completes the transfer of application data if the SAN service provider at the remote peer does not support a WSPRdmaRead function. The sequence that follows describes transferring application data in more detail.

Remote Peer Does Not Support WSPRdmaRead

To transfer data when the remote peer does not support WSPRdmaRead

  1. The switch at the remote peer calls WSPRegisterRdmaMemory to register RDMA memory for write access.
  2. The switch at the remote peer then calls WSPSend to send a control message to the local switch that indicates the location of RDMA memory to which the local switch can write.
  3. The local switch calls the WSPRdmaWrite function to transfer application data to the RDMA memory. The SAN service provider transmits the buffered data in the background. Doing so allows applications that do not post more than one send at a time to post another send request while the SAN service provider sends buffered data.
  4. The local switch calls the WSPGetOverlappedResult function to obtain the results of the transfer. For more information, see the Completing Data Transfer Requests section.
  5. The local switch calls WSPSend to send a control message to the remote peer to indicate that the transfer is complete.
  6. The switch at the remote peer calls WSPDeregisterRdmaMemory to release RDMA memory.
  7. The local switch completes the application's send request. If the switch cannot register memory for the application's data buffers or if temporary memory cannot be allocated, it completes an application's send request with the WSAENOBUFS error code.


Sending Urgent Data on a SAN

If an application sends urgent data on a SAN, the Windows Sockets switch transfers that data as described in the following sequence:

  1. For requests to send urgent data, the switch receives a WSPSend call in which the MSG_OOB flag is set.
  2. The switch copies the urgent data to the payload portion of a control message buffer.
  3. The switch calls the appropriate SAN service provider's WSPSend function to transmit the urgent data contained in the control message to the remote peer connection for a SAN socket. The SAN NIC in turn transmits the urgent data.
  4. The switch at the remote peer receives the transmitted data into receive buffers that it posted with the WSPRecv function.
  5. The switch at the remote peer copies the received data from the receive buffers to private storage.
  6. The switch at the remote peer calls WSPRecv to repost the receive buffers.
  7. The switch at the remote peer delivers the data to an application in accordance with standard Windows Sockets procedures.


Completing Data Transfer Requests

The Windows Sockets switch transfers data on a SAN socket asynchronously. Whenever the switch calls the SAN service provider's WSPSend, WSPRecv, WSPRdmaWrite, or WSPRdmaRead data-transfer function, it specifies a pointer to an overlapped structure (WSAOVERLAPPED) and NULL for a completion routine. Even if the switch calls the SAN service provider's WSPEventSelect function to indicate that the socket is in nonblocking mode, the SAN service provider is not required to implement nonblocking semantics for these data-transfer functions.

As described in the Windows Sockets API and SPI documentation in the Platform SDK documentation, both blocking and nonblocking sockets treat overlapped operations the same. That is, the SAN service provider starts the particular data transfer operation and then immediately returns control to the switch. These data-transfer functions return error code WSA_IO_PENDING to indicate that an asynchronous operation started and that completion of that operation occurs later. After the operation completes, the SAN service provider signals completion if the switch requires completion notification as described in following paragraphs.

Because the switch always specifies NULL for a completion routine for overlapped data transfer operations, a SAN service provider is not required to support completion through the use of asynchronous procedure calls (APCs).

Whenever possible, the switch attempts to call the SAN service provider's WSPGetOverlappedResult function to poll for completion of data transfer requests. In this way, the switch can avoid the overhead associated with active overlapped completion mechanisms. To indicate to a SAN service provider that the switch does not require completion notification for a particular overlapped data transfer operation, the switch sets the low-order bit of the hEvent member in the WSAOVERLAPPED structure to one. The SAN service provider must not notify the switch of the completion of requests submitted in this manner.

If the switch requires notification of the completion of an overlapped data transfer operation, it sets the low-order bit of the hEvent member in the WSAOVERLAPPED structure to zero. The SAN service provider must complete data transfer operations that are initiated in this way by calling the WPUCompleteOverlappedRequest function to signal completion. In this call, the SAN service provider passes a pointer to the WSAOVERLAPPED structure that corresponds to a completed data transfer operation. In this WPUCompleteOverlappedRequest call, the SAN service provider also passes the socket descriptor that was acquired from the switch in a call to the WPUCreateSocketHandle function. The switch receives completion notifications, matches them to an application's I/O requests, and completes those I/O requests, as appropriate, for the application. For information about the WPUCompleteOverlappedRequest and WPUCreateSocketHandle functions, see the Platform SDK documentation.


Synchronizing Operations on a SAN

The Windows Sockets switch uses its session protocol to handle almost all synchronization between a SAN service provider and applications. That is, the switch, in conjunction with the TCP/IP provider, handles most WSPAsyncSelect, WSPEventSelect, and WSPSelect calls from applications. The switch does not forward these calls to a SAN service provider except when specifying the FD_ACCEPT and FD_CONNECT network event codes in calls to a SAN service provider's WSPEventSelect function, as described in Setting Up a SAN Connection.


Shutting Down the Use of a SAN

The following topics describe how to terminate the use of a SAN:

Shutting Down a SAN Connection

Closing a SAN Socket

Cleaning up a Process for a SAN


Shutting Down a SAN Connection

The Windows Sockets switch uses its session protocol to shut down a connection to a SAN socket. That is, the switch handles WSPRecvDisconnect, WSPSendDisconnect, and WSPShutdown calls from applications. The switch does not forward these calls to a SAN service provider. The switch uses its session protocol to disable the reception and transmission of data on a SAN socket.


Closing a SAN Socket

After the Windows Sockets switch on either side of a connection calls a SAN service provider's WSPCloseSocket function, the SAN service provider performs the following procedure to close a SAN socket:

  1. Each SAN service provider on either side of the connection tears down the connection and completes receive requests—WSPRecv function calls—by returning the appropriate error code at the lpErrno parameter. For example, a SAN service provider returns WSAECONNRESET to indicate that the remote peer reset the connection.

    Each SAN service provider also signals completion of pending overlapped operations for the SAN socket to be closed. The SAN service provider calls the WPUCompleteOverlappedRequest function to signal completion of an overlapped operation. In this call, the SAN service provider passes a pointer to the WSAOVERLAPPED structure that is associated with the overlapped operation. The SAN service provider also passes the WSA_OPERATION_ABORTED error code to specify that the overlapped operation was canceled because the SAN socket was closed. Before signaling completion of an overlapped operation, the SAN service provider should release any memory that was required for the operation.

  2. After the SAN service provider is done making up-calls—calls to functions that are prefixed with WPU—to the switch using the handle to the SAN socket that was obtained through a WPUCreateSocketHandle up-call, the SAN service provider must make a final up-call to the switch by calling the WPUCloseSocketHandle function to close the socket handle. The SAN service provider then cleans up everything related to the SAN socket. Up-calls are function calls from the switch's up-call dispatch table. The switch provides a pointer to this up-call dispatch table when it calls the SAN service provider's WSPStartupEx function to start using the provider. For more information about these up-call functions, see the Platform SDK documentation.

As long as a SAN service provider performs the preceding procedure to close a SAN socket, the switch takes care of everything else.

To prevent race conditions between a SAN service provider and the switch initiating socket closures, the SAN service provider should never release data structures related to a SAN socket until the switch calls WSPCloseSocket.


Cleaning up a Process for a SAN

When an application is ready to clean up the process in which it is running, it initiates a call to the Windows Sockets switch's WSPCleanup function. The switch, in turn, calls the WSPCleanup function of the TCP/IP provider and all SAN service providers. All providers are expected to release any resources that they were using. Resources can include, for example, objects used to synchronize events and memory used to perform data transfers.


Blocking Calls for a SAN

The Windows Sockets switch handles blocking calls and the cancellation of such calls internally or forwards them to the TCP/IP service provider. The switch never calls a WSPCancelBlockingCall function for a SAN service provider to cancel a blocking request that is in progress. Therefore, a SAN service provider is not required to implement a WSPCancelBlockingCall function.

The switch handles the following blocking requests and corresponding cancellations in the following ways:

  • When an application requests to connect a SAN socket to a specific destination address in blocking mode, the switch receives a blocking WSPConnect call. The switch forwards the connect request in nonblocking mode to the appropriate SAN service provider's WSPConnect function. If the switch must cancel this connection request for some reason, it calls the SAN service provider's WSPCloseSocket function. The SAN service provider must promptly abort the connection request and release resources for the socket.
  • When the switch receives a blocking request that was initiated by an application to perform a data transfer operation on a SAN socket, it forwards the data transfer request in an overlapped (nonblocking) manner to the appropriate SAN service provider. For example, if the switch receives a synchronous (blocking) WSPSend call, it calls the appropriate SAN service provider's WSPSend function in an overlapped (nonblocking) manner. If the application later cancels the data transfer operation and the switch has control of the application's buffer, the switch completes the application's request with a failure status. If the application's buffer is involved in an outstanding RDMA operation, the switch waits for the operation to complete. If an RDMA transfer takes too long to complete, the switch calls the appropriate SAN service provider's WSPCloseSocket function to close the connection in an abortive manner, thereby forcing completion.

Important If an application cancels a blocking call, it cannot rely on a connection being preserved. Only the WSPCloseSocket call is guaranteed to succeed on the socket after the cancellation of a blocking request. For more information, see the Windows Sockets SPI documentation in the Platform SDK.


Duplicating Socket Handles for a SAN

Multiple applications that run in different processes can use the Windows Sockets switch to perform operations on a shared underlying socket. However, only one application at a time can perform operations on that shared underlying socket.

To use a shared underlying socket, an application must retrieve a duplicate handle to that underlying socket in one of the following ways:

  • Directly, by calling the Windows Sockets WSADuplicateSocket function

    The call is made in the context of the controlling process (the process in which the socket was created).

  • Indirectly, by calling the Win32® DuplicateHandle function

    The call is made in the context of a noncontrolling process (other than the process in which the socket was created).

  • Using the handle inheritance mechanism

    A child process (the noncontrolling process) inherits all or some of the handles created in its parent process (the controlling process).

  • During graceful connection closure

    If an application in the controlling process closes a socket and exits while some data still remains to be sent, this remaining data is buffered in the Windows Sockets DLL. Another application in the context of the system service process (the noncontrolling process) subsequently sends this data.

The Windows Sockets switch, in conjunction with the TCP/IP provider, detects and handles each of the preceding conditions. The switch allows only one process at a time to execute operations that either transfer data or change state for an underlying shared socket. Processes dynamically swap control of the underlying socket, as required, to execute requested operations. The switch serializes operations that different processes request to perform on a shared socket and executes those operations in first-in-first-out (FIFO) order. The switch waits for all in-progress operations to complete before swapping control of an underlying socket to another process. Logically, the switch takes control of the underlying socket away from the controlling process as soon as a noncontrolling process requests a qualifying operation. After control is taken away, the switch treats the original controlling process like a noncontrolling process if the original controlling process requests qualifying operations. Note that the switch takes no action on a duplicate socket handle until the noncontrolling process actually uses the duplicate socket handle for a data transfer or state-change operation.

Both the switch and the appropriate SAN service provider are loaded into all processes that share access to a particular underlying socket. The switch maintains its own socket context and connection state information in all processes that share the socket. The SAN service provider is required to maintain its socket context and connection state information only in the process that has control of the underlying socket at any given point in time. The SAN service provider must swap control of its context and connection state information from the current controlling process to the next controlling process whenever the switch requires the swap as described in the following sequence. To minimize the amount of resources that are required for swapping, a SAN service provider can maintain its context and connection state information in all processes that share an underlying socket.

Because the switch does not create the SAN socket that corresponds to an application socket until an application calls either the connect or listen function, the switch cannot request that the SAN service provider perform a swap operation before the application socket is connected or listening. Even after the application socket is connected or listening, one of the following conditions must be met before the switch requests that the SAN service provider swap control of the socket:

  • A process that does not control the socket initiates a data transfer. The SAN service provider does not swap control of the socket until all data transfer operations that were initiated by the controlling process have completed.
  • A process that does not control the socket calls the WSAAccept, WSPAccept, or AcceptEx function to start a connection-acceptance operation on a listening socket. The SAN service provider does not swap control of the socket until all accept requests that were initiated by the controlling process have completed.

The switch performs the following steps to swap control of a connected SAN socket from the controlling process to the next-controlling process (For an overview of the swapping process, see the table in the Comments section of the documentation for the WSPDuplicateSocket function.):

  1. The switch suspends processing of new requests from the application in the controlling process. When all send and RDMA operations in progress on the SAN socket have completed, the switch calls the SAN service provider's WSPSend function to send a message to a connected peer to request a suspension of the session and calls the SAN service provider's WSPDeregisterMemory function to release all local buffers used for send operations. As a result, the switch at the peer connection suspends processing of new application requests, waits for all send and RDMA operations in progress on the SAN socket to complete, and releases all RDMA memory. The peer connection next sends a reply message indicating that the session is suspended. On receiving this confirmation message, the switch at the local endpoint calls the SAN service provider's WSPDeregisterRdmaMemory function to release all RDMA memory. At this point, SAN sockets at both endpoints of the connection can only have receive requests pending. These receive requests remain pending on the remote peer's SAN socket to permit reactivation of the session. The receive requests on the local SAN socket in the controlling process are completed in the next step. While the connection is suspended, the switch at the remote peer connection queues new blocking or overlapped requests, buffers new nonblocking sends up to the SO_SNDBUF setting, fails new nonblocking sends after the buffer limit is reached, and fails all new nonblocking receives with WSAEWOULDBLOCK. The local switch in the controlling process handles new requests on the application socket as if the process did not have control of the socket.
  2. After the session is suspended, the switch calls the SAN service provider's WSPDuplicateSocket function in the controlling process to direct the SAN service provider to transfer the socket context into the address space of the next-controlling process. The switch specifies the next-controlling process in the dwProcessId parameter of WSPDuplicateSocket. The WSPDuplicateSocket function must call the WPUCompleteOverlappedRequest function to complete all outstanding receive requests on the socket with a success status and zero bytes. The SAN service provider must also automatically release all buffers associated with these requests. The SAN service provider releases all buffers since the switch does not request any more operations on the SAN socket after WSPDuplicateSocket returns. The only possible exception is a WSPCloseSocket function call, as described in the next step. After WSPDuplicateSocket returns, the switch saves the value in the dwProviderReserved member of the WSAPROTOCOL_INFOW structure to which the lpProtocolInfo output parameter points. The switch uses this value to identify the underlying socket in the context of the next-controlling process. Therefore, the value in dwProviderReserved must uniquely identify the underlying socket and the connection for that socket across all processes on the system. In addition, this value must be valid only in the context of the process that the switch specified in the dwProcessId parameter of WSPDuplicateSocket.
  3. After the socket context is transferred into the address space of the next-controlling process, the switch calls the SAN service provider's WSPSocket function in the context of the next-controlling process. In this call, the switch passes the value for the underlying socket that was returned in the WSPDuplicateSocket call to the dwProviderReserved member of the WSAPROTOCOL_INFOW structure to which the lpProtocolInfo input parameter points. If the next-controlling process did not request the creation of the SAN socket, the SAN service provider must create a new socket and call the WPUCreateSocketHandle function to obtain a handle, as required for any new socket. If the SAN socket was created in the context of the next-controlling process, the SAN service provider can reactivate the former socket and return the same descriptor for the socket that was used previously. In this case, the SAN service provider should not call WPUCreateSocketHandle, but should continue to use the original socket handle that the switch provided. Alternatively, the SAN service provider can create a new socket, regardless of whether a socket previously existed in the process. In this case, the switch must call the SAN service provider's WSPCloseSocket function in the context of the next-controlling process to dispose of the former socket descriptor.
  4. The switch restarts processing of new requests from the application in the next-controlling process.

The switch duplicates a listening socket in a similar manner, except that the switch is not required to suspend a session. The switch waits until it completes all WSPAccept calls that were initiated by an application's accept and AcceptEx calls before calling the SAN service provider's WSPDuplicateSocket function in the controlling process.

Because the switch suspends processing of new requests on a SAN socket prior to calling the SAN service provider's WSPDuplicateSocket function, the SAN service provider can release all resources associated with a local endpoint in the controlling process. The SAN service provider can even terminate an underlying connection. If the SAN service provider closes an underlying connection in the controlling process, the SAN service provider must re-establish the connection after the switch calls the SAN service provider's WSPSocket function within the next-controlling process. After the WSPSocket call returns, the SAN socket within the next-controlling process must be in the same state, from the switch's perspective, as the SAN socket in the controlling process was prior to the switch calling the SAN service provider's WSPDuplicateSocket function.

If a SAN NIC supports sharing resources between endpoints that run in different processes, the SAN service provider does not have to release resources for a local endpoint in the controlling process prior to receiving a WSPDuplicateSocket call. In such a case, the SAN socket associated with a local endpoint remains inactive in the former-controlling process until the switch either swaps the socket context back from the next-controlling process or calls the SAN service provider's WSPCloseSocket function to explicitly close the socket. Because most applications perform their final access to the socket in the process that originally created it—generally to close the connection—the SAN service provider can improve performance if the SAN service provider preserves the socket context in the controlling process after the switch swaps control of the socket to the next-controlling process.

Note that, in all cases, a SAN socket descriptor must remain valid until the switch calls the SAN service provider's WSPCloseSocket function to explicitly close the socket. Even if the SAN service provider releases all resources for the socket in a particular process prior to receiving a WSPDuplicateSocket call, the SAN service provider must not reuse the descriptor for the socket until the switch calls WSPCloseSocket on that descriptor.

An unexpected process exit or some other error condition can interrupt a SAN service provider's socket-duplication operation. For example, a shortage of resources can cause such an interruption. The switch treats such error conditions as it does any other error situation. If necessary, the switch closes all descriptors that are associated with the underlying socket in all processes to forcefully terminate the socket's connection. If at all possible, the SAN service provider at the remote peer should complete WSPRecv calls that receive incoming data with an appropriate error code, such as WSAECONNRESET. This error code informs the remote peer of the connection termination. If the switch at the remote peer does not receive this connection-termination indication, the switch at the remote peer times out a suspended connection if the system that requested the suspension fails.


Handling Socket Options and Control Codes for a SAN

The Windows Sockets switch, in conjunction with the TCP/IP provider, handles most WSPGetSockOpt, WSPSetSockOpt, and WSPIoctl calls initiated by applications. These requests are generally to set and retrieve options and operating parameters associated with an application's socket. The switch does not generally forward these calls to a SAN service provider except as described in the following sections.

Retrieving SAN socket options

The Windows Sockets switch calls a SAN service provider's WSPGetSockOpt function and passes one of the following socket options to retrieve the current value of that option, if the SAN service provider supports that option:

SO_DEBUG
SAN service providers are not required to support this option. They are encouraged, but not required, to supply output debug information if applications set the SO_DEBUG option.
SO_MAX_MSG_SIZE
A SAN service provider must support this option if the underlying SAN transport is message-oriented and the transport limits the amount of data that the switch can send in a call to the SAN service provider's WSPSend function. The switch does not subsequently pass send requests to the SAN service provider that exceed the size that the SAN service provider returns for the value of this option.
SO_MAX_RDMA_SIZE
A SAN service provider must support this option if the underlying SAN transport limits the amount of data that the switch can transfer in calls to either the SAN service provider's WSPRdmaRead or WSPRdmaWrite function. The switch does not subsequently pass RDMA transfer requests to the SAN service provider that exceed the size that the SAN service provider returns for the value of this option.
SO_RDMA_THRESHOLD_SIZE
A SAN service provider supports this option to indicate its preference for the minimum amount of data that the switch can transfer in calls to either the SAN service provider's WSPRdmaRead or WSPRdmaWrite function. However, the switch can set the actual threshold to a value different from the value returned by the SAN service provider. The switch subsequently calls the WSPRdmaRead or WSPRdmaWrite function to transfer data blocks (RDMA transfers) that exceed the size of this threshold and the WSPSend or WSPRecv function to transfer data blocks (message-oriented transfers) that are less than or equal to the size of this threshold.
SO_GROUP_ID, SO_GROUP_PRIORITY
A SAN service provider must support these options if it supports quality of service (QOS). Otherwise, the switch forwards these options to the TCP/IP provider, which maintains default values. A SAN service provider indicates that it supports QOS by setting the XP1_QOS_SUPPORTED bit in the dwServiceFlags member of the WSAPROTOCOL_INFO structure.

Setting SAN socket options

The Windows Sockets switch calls a SAN service provider's WSPSetSockOpt function and passes one of the following socket options to set a value for that option, if the SAN service provider supports that option:

SO_DEBUG
For a description of this socket option, see the preceding list.
SO_GROUP_PRIORITY
For a description of this socket option, see the preceding list.

Accessing SAN socket information

The Windows Sockets switch calls a SAN service provider's WSPIoctl function and passes one of the following control codes to set or retrieve information for that SAN service provider, if the SAN service provider supports that control code:

SIO_GET_EXTENSION_FUNCTION_POINTER
Retrieves a pointer to an extension function that a SAN service provider must support. For more information on extension functions, see Windows Sockets SPI Extensions for SANs. The input buffer of the WSPIoctl call contains the GUID whose value identifies the specified extension function. The SAN service provider returns the pointer to the requested function in WSPIoctl's output buffer. The following table contains GUIDs for extension functions that a SAN service provider can support:
Extension function | GUID
WSPRegisterMemory | {C0B422F5-F58C-11d1-AD6C-00C04FA34A2D}
WSPDeregisterMemory | {C0B422F6-F58C-11d1-AD6C-00C04FA34A2D}
WSPRegisterRdmaMemory | {C0B422F7-F58C-11d1-AD6C-00C04FA34A2D}
WSPDeregisterRdmaMemory | {C0B422F8-F58C-11d1-AD6C-00C04FA34A2D}
WSPRdmaWrite | {C0B422F9-F58C-11d1-AD6C-00C04FA34A2D}
WSPRdmaRead | {C0B422FA-F58C-11d1-AD6C-00C04FA34A2D}
WSPMemoryRegistrationCacheCallback | {E5DA4AF8-D824-48CD-A799-6337A98ED2AF}

SIO_GET_QOS, SIO_GET_GROUP_QOS, SIO_SET_QOS, SIO_SET_GROUP_QOS
A SAN service provider must support these control codes if it supports QOS. Otherwise, the switch forwards these options to the TCP/IP provider, which maintains default values. A provider indicates that it supports QOS by setting the XP1_QOS_SUPPORTED bit in the dwServiceFlags member of the WSAPROTOCOL_INFO structure.
SIO_ADDRESS_LIST_QUERY
Retrieves the list of local IP addresses that are assigned to the network interface cards (NICs) that the SAN service provider controls. The SAN service provider uses a SOCKET_ADDRESS_LIST structure, defined as follows, to return the list in WSPIoctl's output buffer:
typedef struct _SOCKET_ADDRESS_LIST {
    INT             iAddressCount;
    SOCKET_ADDRESS  Address[1];
} SOCKET_ADDRESS_LIST, FAR * LPSOCKET_ADDRESS_LIST;

The members of this structure contain the following information:

iAddressCount
Specifies the number of address structures in the list.
Address
Array of IP address structures.

The switch uses this IOCTL code internally to decide whether to use a given SAN service provider to execute an application's requests to make connections or to listen for incoming connections. The switch forwards actual application requests for the list of local IP addresses to the TCP/IP provider. The switch also uses the TCP/IP provider to detect changes in address lists that all SAN service providers service. After TCP/IP reports a change, the switch queries all SAN service providers to refresh their lists.


Handling Microsoft Extensions to Windows Sockets

The Windows Sockets switch handles all Microsoft-specific Windows Sockets extension functions internally. The Windows Sockets documentation in the Platform SDK defines an extension as a mechanism that exposes advanced transport functionality to application programs. These extension functions are: TransmitFile, AcceptEx, and GetAcceptExSockAddrs. The switch converts these calls, as necessary, and forwards them to the appropriate SAN service provider function: WSPSend, WSPAccept, WSPRdmaWrite, or WSPRdmaRead.


Creating a Service Provider for a SAN

This section provides a brief description of the functions that make up the interface between a SAN service provider DLL and the Windows Sockets switch. The SAN service provider DLL exports a single entry point for its initialization function WSPStartupEx. The SAN service provider's WSPStartupEx function in turn makes most of the other interface functions accessible to the Windows Sockets switch through a dispatch table. The remaining interface functions are supplied to the switch through calls to the SAN service provider's WSPIoctl function. The interface functions include Windows Sockets SPI functions and SAN-specific extensions to the Windows Sockets SPI interface.

The Windows Sockets Direct reference provides detailed information on these functions as implemented in a SAN service provider. Do not use the Platform SDK descriptions of the Windows Sockets SPI functions. The Platform SDK descriptions do not contain SAN-specific requirements.

This section also lists the Windows Sockets SPI functions that a SAN service provider is not required to supply.


Windows Sockets SPI Functions Required for SANs

This section describes the functions of the Windows Sockets SPI that a SAN service provider DLL must supply. These functions are defined in Ws2spi.h and are fully documented in the Windows Sockets Direct Reference of the DDK documentation:

WSPAccept
Conditionally accepts a connection for a socket that is listening for connections, based on the return value of a supplied condition function.
WSPBind
Associates the local IP address, or name, of a network interface with a socket. This network interface is serviced by the SAN service provider.
WSPCleanup
Terminates use of the SAN service provider DLL.
WSPCloseSocket
Closes a socket.
WSPConnect
Establishes the connection of a socket to a peer, exchanges connect data, and specifies required quality of service (QOS) based on the supplied flow specification.
WSPDuplicateSocket
Retrieves a WSAPROTOCOL_INFOW structure that can be used to create a new socket descriptor for a shared socket in the context of another process.
WSPEnumNetworkEvents
Reports occurrences of network events for a socket.
WSPEventSelect
Specifies an event object for a socket. This event object is subsequently set by the occurrence of the supplied set of network events.
WSPGetOverlappedResult
Returns the results of an asynchronous (overlapped) operation on a socket. This operation previously indicated that it was pending completion.
WSPGetQOSByName
Initializes a QOS structure based on a named template, or retrieves an enumeration of the available template names.

A SAN service provider DLL that supports QOS must fully implement WSPGetQOSByName. If the SAN service provides does not support QOS, its WSPGetQOSByName function must at least return the error WSAEOPNOTSUPP.

WSPGetSockOpt
Retrieves the current value of an option for a socket.
WSPIoctl
Sets or retrieves operating parameters associated with a socket.
WSPListen
Establishes a socket to listen for incoming connections.
WSPRecv
Receives data on a connected socket.
WSPSend
Sends data on a connected socket.
WSPSetSockOpt
Sets the value of an option for a socket.
WSPSocket
Creates a socket that uses the TCP/IP protocol and asynchronous (overlapped) data transfer.


Windows Sockets SPI Functions not Required for SANs

This section describes the functions of the Windows Sockets SPI that a SAN service provider is not required to implement. These functions are defined in Ws2spi.h.

WSPAddressToString
The Windows Sockets switch uses the TCP/IP provider to convert all components of a SOCKADDR structure into a human-readable numeric string that represents the IP address of a socket.
WSPAsyncSelect
The Windows Sockets switch uses its session protocol internally to handle notification of network events for a socket, if necessary.
WSPCancelBlockingCall
The Windows Sockets switch internally handles the cancellation of blocking requests that are in progress. Therefore, it never issues cancel blocking calls to a SAN service provider DLL. The Windows Sockets switch can either:

Cancel an outstanding connect request by closing the SAN socket. The SAN service provider DLL should abort the connect request.

Cancel outstanding send and receive requests by discarding data for those requests if the switch buffers that data internally, or by waiting for those requests to complete if they are RDMA transfers to or from application buffers. For lengthy RDMA transfers, the switch can close the connection altogether.

The Windows Sockets SPI documentation in the Platform SDK warns that if a blocking call is canceled, an application cannot rely on a connection being preserved. In this case, the only call that is guaranteed to succeed on the socket after the cancellation of a blocking request is WSPCloseSocket.

WSPGetPeerName
The Windows Sockets switch caches the IP address of a peer when the switch establishes a connection to the peer in a WSPConnect call or accepts a connection to the peer in a WSPAccept call. The switch provides this cached value to applications, if necessary.
WSPGetSockName
The Windows Sockets switch caches the local IP address for a socket when the switch associates the address with the socket in a WSPBind call or accepts a connection to a peer in a WSPAccept call. The switch provides this cached value to applications, if necessary.
WSPJoinLeaf
The Windows Sockets switch exclusively uses the TCP/IP provider to handle multipoint sessions.
WSPRecvDisconnect
The Windows Sockets switch internally handles termination of data reception on a socket and retrieves any incoming disconnect data from the remote party.
WSPRecvFrom
The current version of Windows Sockets Direct does not support SAN service providers handling sockets that receive datagrams with User Datagram Protocol (UDP) semantics. Therefore, the Windows Sockets switch calls a SAN service provider's WSPRecv function on a connected socket to receive stream data with Transmission Control Protocol (TCP) semantics.
WSPSelect
The Windows Sockets switch uses its session protocol internally in cooperation with the TCP/IP provider to determine the status of sockets, if necessary.
WSPSendDisconnect
The Windows Sockets switch internally handles termination of the connection for a socket and sends disconnect data to the remote party.
WSPSendTo
The current version of Windows Sockets Direct does not support SAN service providers handling sockets that send datagrams with User Datagram Protocol (UDP) semantics. Therefore, the Windows Sockets switch calls a SAN service provider's WSPSend function on a connected socket to send stream data with Transmission Control Protocol (TCP) semantics.
WSPShutdown
The Windows Sockets switch internally disables the reception and transmission of data on a socket.
WSPStartup
The Windows Sockets switch does not call WSPStartup to start the operation of a SAN service provider. The switch instead uses the SAN service provider's WSPStatupEx function.
WSPStringToAddress
The Windows Sockets switch uses the TCP/IP provider to convert a human-readable numeric string that represents the IP address of a socket into a socket address structure (SOCKADDR) that is suitable to pass to Windows Sockets routines that take such a structure.


Windows Sockets SPI Extensions for SANs

This section provides a brief description of the SAN extension functions that a SAN service provider DLL must supply. These functions extend the Windows Sockets SPI for use with a SAN. The extended functions are defined in Ws2san.h and are fully documented in the Windows Sockets Direct Reference of the DDK documentation.

Except for the WSPStartupEx function, the extended functions listed in this section are retrieved by the Windows Sockets switch. To retrieve the entry point to each of these extended functions, the Windows Sockets switch calls a SAN service provider's WSPIoctl function and passes the SIO_GET_EXTENSION_FUNCTION_POINTER command code along with the GUID whose value identifies one of these extended functions.

A SAN service provider must implement all of the following extension functions with the exception of the WSPRdmaRead and WSPMemoryRegistrationCacheCallback functions. If a SAN service provider does not support either the WSPRdmaRead or WSPMemoryRegistrationCacheCallback extension function, its WSPIoctl function must return the error WSAEOPNOTSUPP when the Windows Sockets switch requests the entry point to either WSPRdmaRead or WSPMemoryRegistrationCacheCallback.

WSPStartupEx
Initiates the Windows Sockets switch's use of a SAN service provider.
WSPRegisterMemory
Registers a buffer array that a socket uses as either the local source or the local target of a data transfer operation. Such a socket can use this buffer array as the source buffer in WSPRdmaWrite and WSPSend calls and the receiving buffer in WSPRdmaRead and WSPRecv calls.
WSPDeregisterMemory
Releases a buffer array that was registered by a previous call to the WSPRegisterMemory function.
WSPRegisterRdmaMemory
Registers an RDMA buffer array that is exposed to a remote peer connection for transferring data to or from that peer connection. A socket at the remote peer can use this RDMA buffer array as the target buffer in a WSPRdmaWrite call and the source buffer in a WSPRdmaRead call.
WSPDeregisterRdmaMemory
Releases a buffer array that was registered by a previous call to the WSPRegisterRdmaMemory function.
WSPMemoryRegistrationCacheCallback
Releases ownership of an application's buffer and the lock between the buffer and physical memory and removes the buffer from the SAN service provider's cache and the buffer registration from the SAN NIC.
WSPRdmaRead
Transfers data from an RDMA buffer in the address space that a socket's remote peer can access to a buffer in the address space that the local socket can access.
WSPRdmaWrite
Transfers data from a source buffer in the address space that a local socket can access to a target RDMA buffer in the address space that the socket's remote peer can access.


Creating a Proxy Driver for a SAN Service Provider

A proxy driver for a SAN service provider is a kernel-mode driver that performs tasks required by the Windows Sockets switch and the SAN service provider. Such tasks include managing memory and determining the IP addresses of network interface controllers (NICs) that are under the proxy driver's control. The proxy driver is not required to be a Windows Driver Model (WDM) driver. That is, it is not required to support Plug and Play or power management. For more information on developing a kernel-mode driver, see Kernel-Mode Driver Components.

Different vendors might use different underlying technologies to implement their SAN network interface controllers (NICs), therefore Windows Sockets Direct does not specify an interface between a SAN service provider and its proxy driver or between the proxy driver and a SAN transport.

A SAN NIC vendor must implement a transport interface that is suitable for its underlying technologies. A vendor can implement this interface in the SAN NIC, in a kernel-mode driver for the SAN NIC, or both. A SAN service provider maps this interface directly into a user-mode process's address space. A vendor must ensure that all buffers passed across this interface are locked down and registered with the SAN NIC.

The following sections describe how to create a proxy driver for a SAN service provider DLL:

Initializing and Unloading a SAN Proxy Driver

Allocating and Releasing Memory for a SAN Proxy Driver

Securing and Releasing Ownership of Virtual Addresses

Registering for SAN NIC Notifications

Translating to a SAN Native Address

Implementing IOCTLs for a SAN service provider


Initializing and Unloading a SAN Proxy Driver

In addition to creating and initializing a device object for the driver object, the proxy driver's DriverEntry routine can register to be notified when NICs under the driver's control are either added or removed. For more information, see Registering for SAN NIC Notifications.

If the proxy driver's SAN service provider sends I/O control requests down to the proxy driver, then DriverEntry must specify an entry point that enables device control. The provider might request, for example, to retrieve the list of IP addresses assigned to the driver's NICs. An entry point for this request is an IRP_MJ_DEVICE_CONTROL dispatch routine that returns the list of IP addresses assigned to the driver's NICs. For more information, see Implementing IOCTLs for a SAN service provider.

The DriverEntry routine must specify an entry point for a routine that unloads the proxy driver. This unload routine removes the device that was created in DriverEntry.


Allocating and Releasing Memory for a SAN Proxy Driver

The proxy driver must set up access to user buffers so that the Windows Sockets switch can transfer control messages and perform RDMA operations. To request this type of buffer access, the proxy driver sets a bit in the Flags member of its device object to DO_DIRECT_IO. The proxy driver must also allocate or release memory that is used for message transfer and RDMA whenever requested to do so. When the Windows Sockets switch requests a SAN service provider to register or release memory, the SAN service provider requests its proxy driver to respectively allocate or release physical memory. For more information on setting up buffer access and allocating and releasing memory, see Memory Management and Buffer Management.

Allocating Low Memory for RDMA

A proxy driver must allocate memory that can be accessed for RDMA operations. The proxy driver can allocate low memory for RDMA operations even on an system that is configured so that no physical memory below 4 GB can be allocated. (This is called a NOLOWMEM configuration.) The proxy driver calls either the MmAllocateContiguousMemorySpecifyCache function or its own DMA AllocateCommonBuffer function to retrieve low memory.

To retrieve a pointer to its DMA AllocateCommonBuffer function, the proxy driver performs the following steps:

  1. Zero-initializes a DEVICE_DESCRIPTION structure and then writes relevant information for its SAN NIC to this structure.
  2. Calls IoGetDmaAdapter to retrieve a pointer to the DMA adapter structure for its SAN NIC. In this call, the driver passes a pointer to the filled-in DEVICE_DESCRIPTION structure. IoGetDmaAdapter returns a pointer to a DMA adapter structure that contains a pointer to a DMA_OPERATIONS structure. DMA_OPERATIONS contains pointers to a system-defined set of DMA functions. One of these functions is AllocateCommonBuffer, which allocates a physically contiguous DMA buffer.


Securing and Releasing Ownership of Virtual Addresses

The proxy driver must secure ownership of the virtual addresses of user-mode buffers whenever the SAN service provider for the proxy driver caches those buffers. For more information on caching buffers, see Caching Registered Memory. The proxy driver secures ownership of a user-mode buffer, so that the operating system notifies the Windows Sockets switch if the buffer is released back to the operating system by an application. To secure ownership of a buffer, the proxy driver must call the MmSecureVirtualMemory function. In this call, the proxy driver passes a pointer to the starting address of the buffer and the size, in bytes, of the buffer.

If the virtual-to-physical mappings for the cached buffer are scheduled to change, the switch is notified and calls the SAN service provider's WSPMemoryRegistrationCacheCallback function to remove the buffer registration from the SAN NIC and the buffer from the SAN service provider's cache. The SAN service provider's proxy driver, in turn, must call the MmUnsecureVirtualMemory function to release ownership of the buffer. In this call, the proxy driver passes the handle to the buffer that was previously returned from the MmSecureVirtualMemory call.

Note A driver that tries to secure or release ownership of a user-mode buffer can potentially bring down the operating system. Therefore, when the proxy driver calls either the MmSecureVirtualMemory or MmUnsecureVirtualMemory function, it must also use the try/except mechanism around these calls. For more information on try/except, see the Visual C++® documentation.

A SAN service provider can send I/O control (IOCTL) requests to the proxy driver to secure and release ownership of a buffer. For more information, see Implementing IOCTLs for a SAN Service Provider.


Registering for SAN NIC Notifications

When a proxy driver receives a request from its associated SAN service provider to supply the list of IP addresses assigned to NICs under the driver's control, the driver determines and passes this list to the provider.

In order to obtain these IP addresses, the proxy driver must register with the Transport Driver Interface (TDI) to receive address change notifications. The proxy driver calls the TdiRegisterPnPHandlers function. In this call, this proxy driver passes pointers to callback functions in the AddAddressHandlerV2 and DelAddressHandlerV2 members of the TDI_CLIENT_INTERFACE_INFO structure to specify callback functions for address additions and deletions. After the TdiRegisterPnPHandlers function has returned successfully, TDI immediately indicates all currently active network addresses to the proxy driver, using the address-addition callback. The indication contains both network addresses and identifiers for the devices to which those addresses are bound.

Whenever TDI calls either of these callback functions to indicate address additions or deletions, the proxy driver requires the following parameters:

Address
Pointer to a TA_ADDRESS structure that describes the network address either assigned to or removed from the NIC. In the case of TCP/IP, this pointer is actually be a pointer to a TA_ADDRESS_IP structure.
DeviceName
Pointer to a Unicode string that identifies the transport-to-NIC binding with which the address is associated. In case of TCP/IP, the Unicode string has the following format: \Device\Tcpip_{NIC-GUID}, where NIC-GUID is the globally unique identifier assigned by the network configuration subsystem to the NIC.

The preceding structure definitions are defined in the tdi.h header file. The preceding registration and callback functions are defined in the tdikrnl.h header file. These header files are available in the Windows DDK. For detailed information on TDI Plug and Play (PnP) notifications, see TDI Client Callbacks and TDI Client Event and PnP Notification Handlers.

At system startup, TDI calls the proxy driver's address-addition callback to indicate all currently active IP addresses. TDI also calls this callback whenever the TCP/IP transport protocol registers a new IP address with TDI. The proxy driver includes in its list of IP addresses only those addresses assigned to the proxy driver's NICs. The driver's address-addition callback should return control promptly if the driver does not recognize the NIC at DeviceName.

TDI calls the proxy driver's address-removal callback whenever the TCP/IP transport protocol indicates to TDI that a NIC has been removed. If the IP address of the NIC belongs to one of the proxy driver's NICs, the proxy driver removes the IP address from the list.


Translating to a SAN Native Address

The Windows Sockets switch always uses the AF_INET address family to interact with a SAN service provider, not the SAN's native address family. Therefore, a proxy driver for a SAN service provider must translate between AF_INET addresses and native addresses accordingly.

A proxy driver uses TDI Plug and Play (PnP) notifications to maintain the list of IP addresses assigned to each NIC under its control, as described in Registering for SAN NIC Notifications. The proxy driver uses this list to translate between native SAN addresses and IP addresses.

The proxy driver receives requests from its SAN service provider that contain IP addresses. These requests include, for example, the request to bind to a specific NIC and the request to connect to a remote peer. The proxy driver must translate to native SAN addresses to complete these requests. The proxy driver also receives incoming connection requests from remote peers that contain SAN native addresses of those remote peers. The proxy driver must translate to the IP addresses of those remote peers to complete these requests.


Implementing IOCTLs for a SAN Service Provider

If a SAN service provider sends I/O control (IOCTL) requests to the proxy driver, the driver should implement an IRP_MJ_DEVICE_CONTROL dispatch routine to process these requests. An IOCTL request can be a request to retrieve the list of IP addresses assigned to the driver's NICs, for example, or a request to allocate or release memory. The DriverEntry routine must specify an entry point for the dispatch routine.

The proxy driver's device control routine calls the IoGetCurrentIrpStackLocation function, in which the device control routine passes a pointer to the IRP that was passed to the routine. The device control routine then determines which IOCTL request was received and processes the request accordingly.

After the current IOCTL request completes, the device control routine calls the IoCompleteRequest function and passes the status of the operation. This status is returned to the SAN service provider.


Overview of Remote NDIS

This section provides an overview of the Remote NDIS specification, including messaging, device control, and devices.

This section includes the following topics:

Description of Remote NDIS

Benefits of Remote NDIS

Remote NDIS Concepts and Definitions

Remote NDIS Messaging

Remote NDIS Device Control

Types of Remote NDIS Devices


Description of Remote NDIS

Remote NDIS is a bus-independent class specification for Ethernet (802.3) network devices on dynamic PnP buses such as USB, 1394, Bluetooth, and InfiniBand. Remote NDIS defines a bus-independent message protocol between a host PC and a Remote NDIS device over abstract control and data channels. Remote NDIS is precise enough to allow vendor-independent class driver support for Remote NDIS devices on the host PC.

Remote NDIS messages are sent to a Remote NDIS device from the host, and a Remote NDIS device responds with an appropriate completion message. There are also messages sent in a unsolicited fashion from a Remote NDIS device to the host.


Benefits of Remote NDIS

Remote NDIS is an extension of the well-understood and time-tested NDIS architecture. NDIS defines a function-call interface for device-specific NDIS miniport drivers. This interface defines primitives to send and receive network data, and to query and set configuration parameters and statistics. Remote NDIS leverages NDIS by defining a message wrapping for the NDIS miniport driver interface, thus moving the NDIS-handling code from a miniport driver into the device itself. In this and other ways, Remote NDIS allows for a wide range of device functionality and performance levels. The Remote NDIS model has many advantages:

  • Extensibility without change to the bus-specific message transport mechanisms
  • Ability to support more protocols over more buses in a short time
  • Driver architecture that has been proven for both networking and external bus device models

Value-added mechanisms that already exist in the NDIS network stack are supported for Remote NDIS devices.


Remote NDIS Concepts and Definitions

This section presents an overview of the Remote NDIS requirements on the communication channel and lower-layer drivers that are used to communicate between the host and the Remote NDIS device. Device state transitions and major operations such as initialization, halt and reset are also described in this section.

  • Control Channel

    The control channel must be reliable and ensure sequenced delivery. It is used for all communication except for the transmission of network data packets. All required control messages, except REMOTE_NDIS_HALT_MSG and REMOTE_NDIS_INDICATE_STATUS_MSG, are request and response exchanges initiated by the host. The device must respond within the timeout period as specified for each bus.

  • Data Channel

    The data channel is used exclusively for the transmission of network data packets. It may consist of multiple subchannels (for example, for varying quality of service) as defined for the appropriate bus.

  • Initialization and Teardown

    The control and data channels are initialized and set up as specified for the appropriate bus. The host sends a REMOTE_NDIS_INITIALIZE_MSG message to the Remote NDIS device. The Remote NDIS device provides information about its type (connectionless or connection-oriented), supported medium, and version in the response message REMOTE_NDIS_INITIALIZE_CMPLT.

    Either the host or the Remote NDIS device can tear down the communication channel through the REMOTE_NDIS_HALT_MSG message. All outstanding requests and packets are discarded on receipt of this message.

  • Device State Definitions

    Following bus-level initialization, the device is said to be in the rndis-uninitialized state. Upon receiving a REMOTE_NDIS_INITIALIZE_MSG and responding with a REMOTE_NDIS_INITIALIZE_CMPLT with a status of RNDIS_STATUS_SUCCESS, the device enters the rndis-initialized state.

    Upon receiving REMOTE_NDIS_SET_MSG specifying a non-zero filter value for OID_GEN_CURRENT_PACKET_FILTER, the device enters the rndis-data-initialized state.

    When in the state rndis-data-initialized, reception of a REMOTE_NDIS_SET_MSG specifying a zero filter value for OID_GEN_CURRENT_PACKET_FILTER forces the device back to the rndis-initialized state.

    Reception of REMOTE_NDIS_HALT_MSG or a bus-level disconnect or hard-reset at any time forces the device to the rndis-uninitialized state.

  • Halt

    At any time that the device is in the rndis-initialized or rndis-data-initialized state, the host computer may terminate the Remote NDIS functionality of the device by sending REMOTE_NDIS_HALT_MSG to the device.

  • Resetting the Communication Channel

    The communication channel is reset when an error, such as message timeout, occurs. The host may initiate a reset at any time when the device is in the rndis-initialized state by sending the message REMOTE_NDIS_RESET_MSG to the device and the device must send a response message when it has completed the reset. For example, the host may initiate a reset when an error, such as a message timeout, has occurred.

    Note that this is a soft reset in the sense that any handles (for example, VCs for connection-oriented devices) continue to be valid after the reset. The Remote NDIS device discards all outstanding requests and packets as part of the reset process. The remote device might reset some of its hardware components, but keeps the communication channel intact.

    If the Remote NDIS device performs a reboot, this event is equivalent to "Remove" followed by "Add" plug-and-play events. The host NDIS miniport driver will be halted and removed, and a new instance will be added and started. All bus-level and Remote NDIS initialization will be re-executed. A Remote NDIS device may reboot itself in the event of a critical device failure.

  • Flow Control

    The Remote NDIS device may need to exercise flow control to prevent the host from overflowing its data buffers with packets. Any flow control provisions or requirements are bus specific.

  • Numeric Byte Ordering

    All numeric values in Remote NDIS messages must be coded in little-endian format (least significant byte first).

  • NDIS Message Encapsulation

    There is no Remote NDIS specification for the way NDIS messages are encapsulated in native bus messages or primitives.


Remote NDIS Messaging

There are two types of Remote NDIS messages: control messages and data messages. Control messages allow the host and Remote NDIS device to communicate with each other over the communication channel. Data messages contain the message data information needed for the communication between the host and device and are communicated over the data channel.

  • Remote NDIS Control Messages

    Remote NDIS control messages can be sent by the host to the Remote NDIS device and by the Remote NDIS device to the host. The following Remote NDIS control messages must be supported by an Ethernet 802.3 connectionless device:

    REMOTE_NDIS_INITIALIZE_MSG

    REMOTE_NDIS_INITIALIZE_CMPLT

    REMOTE_NDIS_HALT_MSG

    REMOTE_NDIS_QUERY_MSG

    REMOTE_NDIS_QUERY_CMPLT

    REMOTE_NDIS_SET_MSG

    REMOTE_NDIS_SET_CMPLT

    REMOTE_NDIS_RESET_MSG

    REMOTE_NDIS_RESET_CMPLT

    REMOTE_NDIS_INDICATE_STATUS_MSG

    REMOTE_NDIS_KEEPALIVE_MSG

    REMOTE_NDIS_KEEPALIVE_CMPLT

  • Remote NDIS Data Message

    A Remote NDIS device must send and receive data through Remote NDIS data packets contained in the REMOTE_NDIS_PACKET_MSG message structure. Remote NDIS data packets may also contain out of band data as well as the data that goes across the network.

    Both connectionless (for example, 802.3) and connection-oriented (for example, ATM) devices use the same REMOTE_NDIS_PACKET_MSG message structure, in order to facilitate common code for packet processing.


Remote NDIS Device Control

The host uses REMOTE_NDIS_QUERY_MSG and REMOTE_NDIS_SET_MSG to control the operation of the Remote NDIS device. An NDIS object ID (OID) is used with each such message to identify a device operational parameter or statistics counter. The lists of Remote NDIS OIDs are broken down into two groups: general OID and 802.3-specific OID. Additionally, each group includes a subsection of statistic OID queries. The general OIDs are required of any networking device.


Types of Remote NDIS Devices

Remote NDIS supports Ethernet 802.3 connectionless devices for Windows® Millennium Edition and Microsoft® Windows XP.


Remote NDIS Communication

This section includes the following topics:

Remote NDIS Control Messages

Remote NDIS Data Message

Setting Device-Specific Parameters

Example Connectionless (802.3) Initialization Sequence

Remote NDIS OIDs

Remote NDIS Version

Status Values


Remote NDIS Control Messages

Remote NDIS control messages are sent by the host to the Remote NDIS device and by the Remote NDIS device to the host. All Remote NDIS control messages indicate the type of message being sent and the total length of the message, from the beginning of the message.

The following Remote NDIS control messages must be supported by an Ethernet 802.3 connectionless device.

Message Identifier | Value | Description
REMOTE_NDIS_INITIALIZE_MSG | 0x00000002 | Initialize the device.
REMOTE_NDIS_INITIALIZE_CMPLT | 0x80000002 | Device response to initialization request.
REMOTE_NDIS_HALT_MSG | 0x00000003 | Halt the device. This is the only host control message that doesn't get a response.
REMOTE_NDIS_QUERY_MSG | 0x00000004 | Send a 'query' OID.
REMOTE_NDIS_QUERY_CMPLT | 0x80000004 | Device response to 'query' OID request.
REMOTE_NDIS_SET_MSG | 0x00000005 | Send a 'set' OID.
REMOTE_NDIS_SET_CMPLT | 0x80000005 | Device response to 'set' OID request.
REMOTE_NDIS_RESET_MSG | 0x00000006 | Perform a soft reset on the device.
REMOTE_NDIS_RESET_CMPLT | 0x80000006 | Device responses to reset request.
REMOTE_NDIS_INDICATE_STATUS_MSG | 0x00000007 | Indicates 802.3 link state or undefined message error.
REMOTE_NDIS_KEEPALIVE_MSG | 0x00000008 | During idle periods, sent every few seconds to check that the device is still responsive (may optionally also be sent by the device).
REMOTE_NDIS_KEEPALIVE_CMPLT | 0x80000008 | Device response to keep alive message.


REMOTE_NDIS_INITIALIZE_MSG

REMOTE_NDIS_INITIALIZE_MSG is sent by the host to a Remote NDIS device to initialize the network connection. It is sent through the control channel and only when the device is in the rndis-uninitialized state. The message indicates the following:

  • Maximum size, in bytes, of any single bus data transfer that the host expects to receive from the device. Typically, each bus data transfer accommodates a single RNDIS message. However, as described in Remote NDIS Data Message, the device may bundle several RNDIS messages containing data packets into a single transfer.
  • Major and minor Remote NDIS protocol version implemented by the host. This value is the highest Remote NDIS protocol version supported by the host.


REMOTE_NDIS_INITIALIZE_CMPLT

REMOTE_NDIS_INITIALIZE_CMPLT is sent by the Remote NDIS device to the host in response to a REMOTE_NDIS_INITIALIZE_MSG message.

In this message, the Remote NDIS device indicates the following:

  • Remote NDIS message ID value. This value is used to match the messages sent by the host with device responses.
  • Status value of RNDIS_STATUS_SUCCESS if the device initialized successfully, otherwise the status value is set to an error code indicating the failure.
  • Highest Remote NDIS protocol version number that the device can support. The combined version number should be less than or equal to the version number specified by the host in the REMOTE_NDIS_INITIALIZE_MSG message. This allows the device to fall back to a compatibility mode when the host implements a Remote NDIS protocol version that is lower than that supported by the device.
  • Medium type supported by the device. Set to RNDIS_MEDIUM_802_3 (0x00000000).
  • Maximum number of RNDIS data messages that the device can handle in a single transfer to it. This value should be at least one.
  • Maximum size, in bytes, of a single data transfer that the device expects to receive from the host. The device can specify the byte alignment it expects for each RNDIS message that is part of a multi-message transfer to it. This alignment value is specified in terms of powers of two. For example, this value is set to 3 to indicate 8-byte alignment.


REMOTE_NDIS_HALT_MSG

REMOTE_NDIS_HALT_MSG is sent by either the host or the Remote NDIS device in order to terminate the network connection. Unlike the other host initiated control messages, there is no device response to REMOTE_NDIS_HALT_MSG. The message may be sent at any time that the device is in the rndis-initialized or rndis-data-initialized state. All outstanding requests and packets should be discarded on receipt of this message.

It is optional for the device to implement sending the message REMOTE_NDIS_HALT_MSG. If implemented, the device sends this message to the host through the control channel only when the device is in the rndis-initialized or rndis-data-initialized state. The device must terminate all communication immediately after sending this message. Sending this message causes the device to enter the rndis-uninitialized state.


REMOTE_NDIS_QUERY_MSG

REMOTE_NDIS_QUERY_MSG is sent to a Remote NDIS device from a host when it needs to query the device for its characteristics or statistics information or status. The parameter or statistics counter being queried for is identified by means of an NDIS Object Identifier (OID).

The host may send REMOTE_NDIS_QUERY_MSG to the device through the control channel at any time that the device is in the rndis-initialized or rndis-data-initialized state. A Remote NDIS device will respond to REMOTE_NDIS_QUERY_MSG with information about the desired capabilities or status.

The host sends the following information in this message:

  • Remote NDIS message ID value. This value is used to match the messages sent by the host with device's responses.
  • NDIS OID.
  • Length of the input data, if any, for the query.
  • Byte offset from the beginning of the Remote NDIS message ID value where the input data, if any, for the query is located.


REMOTE_NDIS_QUERY_CMPLT

A Remote NDIS device will respond to a REMOTE_NDIS_QUERY_MSG message with a REMOTE_NDIS_QUERY_CMPLT message. This message is used to relay the result of a query for a device parameter or statistics counter.


REMOTE_NDIS_SET_MSG

REMOTE_NDIS_SET_MSG is sent to a Remote NDIS device from a host, when it needs to set the value of some operational parameter on the device. The specific parameter being set is identified by means of an Object Identifier (OID), and the value it is to be set to is contained in an information buffer sent along with the message. The host may send REMOTE_NDIS_SET_MSG to the device through the control channel at any time that the device is in the rndis-initialized or rndis-data-initialized state. A Remote NDIS device will respond to a REMOTE_NDIS_SET_MSG message with a status.


REMOTE_NDIS_SET_CMPLT

The device sends the REMOTE_NDIS_QUERY_CMPLT message to the host in response to REMOTE_NDIS_SET_MSG. This message is used to relay the result of setting the value of a device parameter.


REMOTE_NDIS_RESET_MSG

A REMOTE_NDIS_RESET_MSG message is sent to a Remote NDIS device from a host through the control channel to reset the device and return status. This message may be sent at any time that the device is in the rndis-initialized or rndis-data-initialized state. A reset does not affect RNDIS message communication with the host. The device typically resets its network-side controller(s) during this process. A Remote NDIS device will respond to a REMOTE_NDIS_RESET_MSG message with a status.


REMOTE_NDIS_RESET_CMPLT

When the device receives REMOTE_NDIS_RESET_MSG, it performs a reset and then sends REMOTE_NDIS_RESET_CMPLT to the host with the result status.


REMOTE_NDIS_INDICATE_STATUS_MSG

The device may send REMOTE_NDIS_INDICATE_STATUS_MSG to the host through the control channel in an unsolicited fashion at any time that the device is in the rndis-initialized or rndis-data-initialized state. This message is used to indicate a change in the status of the device. A common use of this message is to notify the host of changes in link state (media connect status), using RNDIS_STATUS_MEDIA_CONNECT and RNDIS_STATUS_MEDIA_DISCONNECT status values. The device must send REMOTE_NDIS_INDICATE_STATUS_MSG with one of these status values whenever its link state changes. REMOTE_NDIS_INDICATE_STATUS_MSG can also be used to indicate an error event, such as an unrecognized message.

In the specific case where this message is sent in response to a host message that the device could not handle, the returned status value must be set to RNDIS_STATUS_INVALID_DATA, and the status buffer is formatted to contain the following:

  • Additional status information about the error itself (for example, RNDIS_STATUS_NOT_SUPPORTED).
  • Zero-based byte offset in the original message where the error was detected.

If the error condition was caused by an RNDIS message, for example the device can't recognize a particular RNDIS message, the device should append the original message at the end of the status message defined above.

REMOTE_NDIS_INDICATE_STATUS_MSG is used to report an error event only in circumstances where the device is not able to generate a response message with appropriate status. Examples of appropriate usage are:

  • On receiving a message with unsupported message type.
  • On receiving a REMOTE_NDIS_PACKET_MSG with unacceptable contents.


REMOTE_NDIS_KEEPALIVE_MSG

The host sends a REMOTE_NDIS_KEEPALIVE_MSG message to the device through the control channel in order to check the health of the device. When the device is in the rndis-data-initialized state, the host sends this message periodically when there has been no other control or data traffic from the device to the host for the KeepAliveTimeoutPeriod. KeepAliveTimeoutPeriod is bus-dependent and is defined in the appropriate bus-mapping specifications.

Upon receiving this message, the remote device must send back a response whose Status field indicates whether the device solicits a REMOTE_NDIS_RESET_MSG message from the host.

The host will not send REMOTE_NDIS_KEEPALIVE_MSG until the KeepAliveTimeoutPeriod has elapsed since the last message received from the remote device. This avoids unnecessary exchange of REMOTE_NDIS_KEEPALIVE_MSG messages when the communication channel is active.

The device may optionally send this message to the host as well. For example, the device may use this message to trigger a response from the host for the purpose of computing round-trip delay time. If implemented, the device must send REMOTE_NDIS_KEEPALIVE_MSG through the control channel and only when in the rndis-initialized or rndis-data-initialized state.

The device does not need to perform any specific action if it stops seeing REMOTE_NDIS_KEEPALIVE_MSG messages from the host.


REMOTE_NDIS_KEEPALIVE_CMPLT

A Remote NDIS device will respond to a REMOTE_NDIS_KEEPALIVE_MSG message from the host by sending back a REMOTE_NDIS_KEEPALIVE_CMPLT response message. If the returned Status is not RNDIS_STATUS_SUCCESS, then the host will send REMOTE_NDIS_RESET_MSG to reset the device.


Remote NDIS Data Message

A Remote NDIS device transfers NDIS packets, encapsulated as REMOTE_NDIS_PACKET_MSG across the data channel. REMOTE_NDIS_PACKET_MSG may contain out of band (OOB) data and/or per-packet information.


REMOTE_NDIS_PACKET_MSG

A Remote NDIS device must send and receive data through NDIS data packets. The bus used by the device determines how these packets are passed from host to device and device to host. It could be shared memory, or, in the case of USB for example, Isoch and Bulk pipes. NDIS packets may also contain out-of-band (OOB) data as well as the data that goes across the network.

A Remote NDIS device transfers NDIS packets, encapsulated as REMOTE_NDIS_PACKET_MSG across the data channel. Both connectionless (for example, 802.3) and connection-oriented (for example, ATM) devices use the same packet message structure, in order to facilitate common code for packet processing. Each REMOTE_NDIS_PACKET_MSG message contains information about a single network data unit (for example an Ethernet 802.3 frame).

Any out-of-band data records must appear in sequence. If there are multiple out-of-band data blocks attached to a REMOTE_NDIS_PACKET_MSG, then each subsequent out-of-band data record must immediately follow the previous out-of-band record's data. There is no out of band information currently defined for Ethernet 802.3 devices.

See the Windows 2000 DDK NDIS sections for more information about out-of-band packet data.

Each REMOTE_NDIS_PACKET_MSG may contain one or more per-packet-info data records. Per-packet-info is used to convey packet metadata such as TCP checksum. If there are multiple per-packet-info data blocks, then each subsequent per-packet-info data record must immediately follow the previous per-packet-info record's data.

See the Windows 2000 DDK NDIS sections for more information about per-packet info data.


Multi-Packet Messages

Multiple REMOTE_NDIS_PACKET_MSG messages may be sent in a single transfer, in either direction. A multi-packet message is formed by concatenating multiple REMOTE_NDIS_PACKET_MSG elements. The maximum length of such a transfer is governed by the MaxTransferSize parameter passed in the REMOTE_NDIS_INITIALIZE_MSG and response messages. The host will also limit the number of messages it bundles into a single transfer to the MaxPacketsPerMessage parameter returned by the device in the REMOTE_NDIS_INITIALIZE_CMPLT response message.

The difference from the single-packet message case is that the MessageLength field in each REMOTE_NDIS_PACKET_MSG header includes some additional padding bytes. These padding bytes are added to all but the last REMOTE_NDIS_PACKET_MSG such that the succeeding REMOTE_NDIS_PACKET_MSG starts at an appropriate byte boundary. For messages sent from the device to the host, this padding should result in each REMOTE_NDIS_PACKET_MSG starting at a byte offset that is a multiple of 8 bytes starting from the beginning of the multi-packet message. When the host sends a multi-packet message to the device, it will adhere to the PacketAlignmentFactor specified by the device in the REMOTE_NDIS_INITIALIZE_CMPLT response message.

Note that neither the combined length of a multi-packet message nor the number of REMOTE_NDIS_PACKET_MSG elements in a combined message is given explicitly in any Remote NDIS defined field. The combined length is implicit in the bus-specific transfer mechanism, and the host or device must walk the MessageLength fields of the combined message to determine the number of combined messages.

The following table is an example of a multi-packet message that is made up of two REMOTE_NDIS_PACKET_MSGs, sent from the host to the device. During the REMOTE_NDIS_INITIALIZE_MSG exchange, the device requested a PacketAlignmentFactor of 3 (an alignment along na 8-byte boundary).

Offset | Size | Field | Value
0 | 4 | MessageType | 0x1
4 | 4 | MessageLength | 72 (includes 2 padding bytes; see below)
8 | 4 | DataOffset | 36
12 | 4 | DataLength | 26
16 | 4 | OOBDataOffset | 0
20 | 4 | OOBDataLength | 0
24 | 4 | NumOOBDataElements | 0
28 | 4 | PerPacketInfoOffset | 0
32 | 4 | PerPacketInfoLength | 0
36 | 4 | VcHandle | 0
40 | 4 | Reserved | 0
44 | 26 | Payload (data) | Some network data of 26 bytes in length
70 | 2 | Padding | Doesn't matter – unused
72 | 4 | MessageType (start of second REMOTE_NDIS_PACKET _MSG) | 0x1
76 | 4 | MessageLength | 60
80 | 4 | DataOffset | 36
84 | 4 | DataLength | 16
88 | 4 | OOBDataOffset | 0
92 | 4 | OOBDataLength | 0
96 | 4 | NumOOBDataElements | 0
100 | 4 | PerPacketInfoOffset | 0
104 | 4 | PerPacketInfoLength | 0
108 | 4 | VcHandle | 0
112 | 4 | Reserved | 0
116 | 16 | Payload (data) | Some network data of 16 bytes in length


Setting Device-Specific Parameters

It is expected that most Remote NDIS devices will function well without the need to configure parameters on the host. However, there may be cases where proper network operation requires some configuration on the host. If the device supports configurable parameters, then it should include the following optional OID in the list of supported OIDs it reports in response to a query for OID_GEN_SUPPORTED_LIST:

#define OID_GEN_RNDIS_CONFIG_PARAMETER    0x0001021B

If the device supports the OID_GEN_RNDIS_CONFIG_PARAMETER OID, the host uses it to set device-specific parameters, soon after the device enters the rndis_initialized state from the rndis_uninitialized state. The host will send zero or more REMOTE_NDIS_SET_MSGs to the device, with OID_GEN_RNDIS_CONFIG_PARAMETER as the OID value to set. Each such REMOTE_NDIS_SET_MSG corresponds to one device-specific parameter that is configured on the host.

The InformationBuffer associated with each such REMOTE_NDIS_SET_MSG has the following format. Note that the Offset values are relative to the beginning of the information buffer.

Offset | Size | Field | Description
0 | 4 | ParameterNameOffset | Specifies the byte offset from the beginning of the ParameterNameOffset field at which a Unicode character string representing the parameter name is located. The string does not include a NULL terminator.
4 | 4 | ParameterNameLength | Specifies the byte length of the parameter name string.
8 | 4 | ParameterType | Specifies the data type of the parameter value. This is one of the following: 0 – numeric value; 2 – string value.
12 | 4 | ParameterValueOffset | Specifies the byte offset from the beginning of the ParameterNameOffset field at which the parameter value is located.
16 | 4 | ParameterValueLength | Specifies the byte length of the parameter value.

The device sends a REMOTE_NDIS_SET_CMPLT in response to each REMOTE_NDIS_SET_MSG, after applying the parameter value. If the parameter setting is acceptable, it returns a status of RNDIS_STATUS_SUCCESS in the response. If the parameter setting is not acceptable, and the device cannot apply a useful default value for this parameter, then the device returns an appropriate error status value (see section on status values). If an error status is returned, then the host will initiate a halt process for the device.

Device-specific parameters are expected to be configured in the Windows registry. The keys that define parameter values are typically created in the registry during the process of device installation. The list of keys, type information, default values and optional range of valid values are specified in the INF file for the device. For more information on using an INF to set up configuration parameters in the registry for network devices, consult the Windows 2000 DDK.


Example Connectionless (802.3) Initialization Sequence

This section describes the general order of events that a device can expect upon startup as a Remote NDIS connectionless device. Because the basic operation of Remote NDIS is the same, regardless of the underlying bus, the require bus enumeration and start up process has been left out of the example.

Host | Device | Description
REMOTE_NDIS_INITIALIZE_MSG |  | Hosts sends Remote NDIS Initialization message to device.
 | REMOTE_NDIS_INITIALIZE_CMPLT | Device response with Initialize Complete message.
Receiving. Successful Initialization |  | Host starts accepting data on incoming data channel. (Example: on USB starts doing reads on IN pipe).
REMOTE_NDIS_QUERY_MSG AND REMOTE_NDIS_SET_MSG | REMOTE_NDIS_QUERY_CMPLT OR REMOTE_NDIS_SET_CMPLT | Host initiates a series of sets and queries to determine state of device and to setup initial parameters. The device responses appropriately with the correct complete messages. The following NDIS OID's may be queried: OID_802_3_CURRENT_ADDRESS, OID_802_3_MAXIMUM_LIST_SIZE, etc.
REMOTE_NDIS_SET_MSG |  | Host sends an OID_GEN_CURRENT_PACKET_FILTER OID with a non-zero filter value to the device. At this point the device should start sending data packets on the incoming data channel. The host will also start sending data packets on the outgoing data channel.


Remote NDIS OIDs

This section lists the required and optional NDIS OIDs for Remote NDIS Ethernet devices. The list takes into account the unique properties of a Remote NDIS device and the Remote NDIS miniport driver, so the list is not identical to the list that a normal NDIS connectionless miniport driver would support. Some OIDs are both set and query OIDs; if a mandatory OID is defined as both, then it must be supported by a Remote NDIS device for both REMOTE_NDIS_SET_MSG and REMOTE_NDIS_QUERY_MSG. For a detailed explanation of the OIDs, see the Microsoft® Windows® DDK.

The lists of Remote NDIS OIDs are broken down into two groups — general OID and 802.3 specific OID. Additionally, each group includes a subsection of statistic OID queries. The general OIDs are required for any networking device.


General OIDs

The following table lists the general OIDs for Remote NDIS Ethernet devices.

Support | OID | Description
Required | OID_GEN_SUPPORTED_LIST | List of supported OIDs.
Required | OID_GEN_HARDWARE_STATUS | Hardware status.
Required | OID_GEN_MEDIA_SUPPORTED | Media types supported (encoded).
Required | OID_GEN_MEDIA_IN_USE | Media types in use (encoded).
Required | OID_GEN_MAXIMUM_FRAME_SIZE | Maximum frame size in bytes.
Required | OID_GEN_LINK_SPEED | Link speed in units of 100 bps.
Required | OID_GEN_TRANSMIT_BLOCK_SIZE | Minimum amount of storage, in bytes, that a single packet occupies in the transmit buffer space of the NIC.
Required | OID_GEN_RECEIVE_BLOCK_SIZE | Amount of storage, in bytes, that a single packet occupies in the receive buffer space of the NIC.
Required | OID_GEN_VENDOR_ID | Vendor NIC code.
Required | OID_GEN_VENDOR_DESCRIPTION | Vendor network card description.
Optional | OID_GEN_VENDOR_DRIVER_VERSION | Vendor-assigned version number of driver
Required | OID_GEN_CURRENT_PACKET_FILTER | Current packet filter (encoded).
Required | OID_GEN_MAXIMUM_TOTAL_SIZE | Maximum total packet length in bytes.
Optional | OID_GEN_RNDIS_CONFIG_PARAMETER | Device-specific configuration parameter (set only).
Optional | OID_GEN_PHYSICAL_MEDIUM | Information about the underlying physical medium.
Required | OID_GEN_MEDIA_CONNECT_STATUS | Status of the NIC network connection.
Optional | OID_GEN_MAC_OPTIONS | A bitmask that specifies optional properties of the NIC. Must be supported only by NICs that support 802.1p packet priority .


General Statistic OIDs

The following table lists the general statistic OIDs for Remote NDIS Ethernet devices.

Support | OID | Description
Required | OID_GEN_XMIT_OK | Frames transmitted without errors
Required | OID_GEN_RCV_OK | Frames received without errors
Required | OID_GEN_XMIT_ERROR | Frames not transmitted or transmitted with errors
Required | OID_GEN_RCV_ERROR | Frames received with errors
Required | OID_GEN_RCV_NO_BUFFER | Frame missed, no buffers
Optional | OID_GEN_DIRECTED_BYTES_XMIT | Directed bytes transmitted without errors
Optional | OID_GEN_DIRECTED_FRAMES_XMIT | Directed frames transmitted without errors
Optional | OID_GEN_MULTICAST_BYTES_XMIT | Multicast bytes transmitted without errors
Optional | OID_GEN_MULTICAST_FRAMES_XMIT | Multicast frames transmitted without errors
Optional | OID_GEN_BROADCAST_BYTES_XMIT | Broadcast bytes transmitted without errors
Optional | OID_GEN_BROADCAST_FRAMES_XMIT | Broadcast frames transmitted without errors
Optional | OID_GEN_DIRECTED_BYTES_RCV | Directed bytes received without errors
Optional | OID_GEN_DIRECTED_FRAMES_RCV | Directed frames received without errors
Optional | OID_GEN_MULTICAST_BYTES_RCV | Multicast bytes received without errors
Optional | OID_GEN_MULTICAST_FRAMES_RCV | Multicast frames received without errors
Optional | OID_GEN_BROADCAST_BYTES_RCV | Broadcast bytes received without errors
Optional | OID_GEN_BROADCAST_FRAMES_RCV | Broadcast frames received without errors
Optional | OID_GEN_RCV_CRC_ERROR | Frames received with circular redundancy check (CRC) or frame check sequence (FCS) error
Optional | OID_GEN_TRANSMIT_QUEUE_LENGTH | Length of transmit queue


802.3 OIDs

The following table lists the specific 802.3 OIDs for Remote NDIS Ethernet devices.

Support | OID | Description
Required | OID_802_3_PERMANENT_ADDRESS | Permanent station address
Required | OID_802_3_CURRENT_ADDRESS | Current station address
Required | OID_802_3_MULTICAST_LIST | Current multicast address list
Optional | OID_802_3_MAC_OPTIONs | NIC flags (encoded)
Required | OID_802_3_MAXIMUM_LIST_SIZE | Maximum size of multicast address list


802.3 Statistic OIDs

The following table lists the 802.3 statistic OIDs for Remote NDIS Ethernet devices.

Support | OID | Description
Required | OID_802_3_RCV_ERROR_ALIGNMENT | Frames received with alignment error
Required | OID_802_3_XMIT_ONE_COLLISION | Frames transmitted with one collision
Required | OID_802_3_XMIT_MORE_COLLISIONS | Frames transmitted with more than one collision
Optional | OID_802_3_XMIT_DEFERRED | Frames transmitted after deferral
Optional | OID_802_3_XMIT_MAX_COLLISIONS | Frames not transmitted due to collisions
Optional | OID_802_3_RCV_OVERRUN | Frames not received due to overrun
Optional | OID_802_3_XMIT_UNDERRUN | Frames not transmitted due to underrun
Optional | OID_802_3_XMIT_HEARTBEAT_FAILURE | Frames transmitted with heartbeat failure
Optional | OID_802_3_XMIT_TIMES_CRS_LOST | Times carrier sense signal lost during transmission
Optional | OID_802_3_XMIT_LATE_COLLISIONS | Late collisions detected


Optional Power Management OIDs

For NDIS to consider a device power-management — aware, it must respond to the three power management OIDs listed in the following table. If the device returns a failure status code in response to a query for OID_PNP_CAPABILITIES, then the host will consider the device as not being power manageable. NDIS decides whether to query this OID based on the underlying bus technology that the Remote NDIS device is connected to. Some buses are power-manageable, such as USB, so it is expected that these types of Remote NDIS devices will support the minimal OIDs to be considered power-manageable.

Support | OID | Description
Optional | OID_PNP_CAPABILITIES | The NIC's Power Management abilities
Optional | OID_PNP_QUERY_POWER | A query to determine whether the device can transition to a specific power state.
Optional | OID_PNP_SET_POWER | A command to set the device to specified power state


Optional Network Wakeup OIDs

Previous Next

Optional Network Wake Up OIDs

To support network wake up events, a Remote NDIS device must additionally support the OID_PNP_ENABLE_WAKE_UP OID that is used by both the network protocols (TCP/IP) and NDIS to enable the wake up capabilities. Additionally, the options listed in the following table are available to enable specific types of wake up patterns. For further details, consult the Windows 2000 DDK.

Support | OID | Description
Optional | OID_PNP_ENABLE_WAKE_UP | The Remote NDIS device's wake-up capabilities that can be enabled
Optional | OID_PNP_ADD_WAKE_UP_PATTERN | Wake-up patterns that the Remote NDIS mini-port should load into the device
Optional | OID_PNP_REMOVE_WAKE_UP_PATTERN | Wake-up patterns that the Remote NDIS mini-port should remove from the device


Remote NDIS Version

The following table defines the Remote NDIS protocol version identifiers exchanged between host and device.

Version Identifier | Value | Description
RNDIS_MAJOR_VERSION | 1 | Remote NDIS Major Version
RNDIS_MINOR_VERSION | 0 | Remote NDIS Minor Version


Status Values

The Remote NDIS status values are generally equivalent to the 32-bit status values defined in the Windows 2000 DDK. The specific Remote NDIS status values used in this specification are listed below, others can be inferred from the Windows 2000 DDK or MSDN. A device may return any semantically correct Remote NDIS status value in a Status field of a message that it generates.

Status Identifier | Value | Description
RNDIS_STATUS_SUCCESS | 0x00000000 | Success
RNDIS_STATUS_FAILURE | 0xC00000001 | Unspecified error (equivalent to STATUS_UNSUCCESSFUL)
RNDIS_STATUS_INVALID_DATA | 0xC0010015 | Invalid data error
RNDIS_STATUS_NOT_SUPPORTED | 0xC00000BB | Unsupported request error
RNDIS_STATUS_MEDIA_CONNECT | 0x4001000B | Device is connected to network medium (equivalent to NDIS_STATUS_MEDIA_CONNECT from Windows 2000 DDK)
RNDIS_STATUS_MEDIA_DISCONNECT | 0x4001000C | Device is disconnected from network medium (equivalent to NDIS_STATUS_MEDIA_DISCONNECT from Windows 2000 DDK)
RNDIS_STATUS_Xxx | … | Equal to NDIS_STATUS_Xxx values defined in Windows 2000 DDK or MSDN


Remote NDIS To USB Mapping

This section includes the following topics:

Overview

USB-Level Initialization

USB-Level Termination

Control Channel Characteristics

Data Channel Characteristics

Power Management

Timer Constants

USB 802.3 Device Sample


Overview

A USB Remote NDIS device is implemented as a USB CDC device with two interfaces. A Communication Class interface, of type Abstract Control, and a Data Class interface combine to form a single functional unit representing the USB Remote NDIS device. The Communication Class interface includes a single endpoint for event notification and uses the shared bidirectional Control endpoint for control messages. The Data Class interface includes two bulk endpoints for data traffic.

Note An understanding of the Universal Serial Bus (USB) Specification version 1.1 is required. The USB Communication Device Class (CDC) Specification version 1.1 is suggested as a reference. Both documents can be found at http://www.usb.org.


USB-Level Initialization

The host issues standard USB requests to obtain a set of standard USB descriptors for the device. The relevant portions of those descriptors are given below. See the USB Specification for generic USB device initialization.


USB Device Descriptor

The device returns a USB Device Descriptor as defined in the USB Specification. The following table defines the prominent fields of the USB Device Descriptor.

Offset (bytes) | Field | Size (bytes) | Value | Description
4 | bDeviceClass | 1 | 02h | Communication Device Class code.
5 | bDeviceSubClass | 1 | 00h | Communication Device Subclass code, unused at this time.
6 | bDeviceProtocol | 1 | 00h | Communication Device Protocol code, unused at this time.


USB Configuration Descriptor

The device returns a Configuration Descriptor as defined in the USB Specification. See the USB Specification for details.


Communication Class Interface

The Communication Class interface is described by a USB interface descriptor, three class-specific descriptors, and an endpoint descriptor for the notification endpoint. The notification endpoint descriptor is a standard USB Interrupt-type IN endpoint descriptor whose wMaxPacketSize field is 8 bytes. The following table defines the prominent fields of the Communication Class interface descriptor.

Offset (bytes) | Field | Size (bytes) | Value | Description
5 | bInterfaceClass | 1 | 02h | Communication Interface Class code.
6 | bInterfaceSubClass | 1 | 02h | Communication Interface Class SubClass code for Abstract Control Model.
7 | bInterfaceProtocol | 1 | FFh | Communication Interface Class Protocol code for vendor specific protocol.


USB-Level Termination

See the USB Specification for a description of generic USB bus-level termination.


Control Channel Characteristics

The Control channel for the device is its USB Control endpoint. A control message from the host to the device is sent as a SEND_ENCAPSULATED_COMMAND transfer. This transfer is defined in the following table.

BmRequestType | bRequest | wValue | wIndex | wLength | Data
0x21 | 0x00 | 0x0000 | bInterfaceNumber field of Communication Class interface descriptor | Byte length of control message block | Control message block

The host does not continuously poll the USB Control endpoint for input control messages. Upon placing a control message on its Control endpoint, the device must return a notification on the Communication Class interface's Interrupt IN endpoint, which is polled by the host whenever the device can return control messages. The transfer from the device's interrupt IN endpoint to the host is a standard USB Interrupt IN transfer. The only defined device notification is the RESPONSE_AVAILABLE notification, defined in the following table.

Offset (bytes) | Length (bytes) | Field | Data
0 | 4 | Notification | RESPONSE_AVAILABLE (0x00000001)
4 | 4 | Reserved | 0

Upon receiving the RESPONSE_AVAILABLE notification, the host reads the control message from the Control endpoint using a GET_ENCAPSULATED_RESPONSE transfer, defined in the following table.

bmRequestType | bRequest | wValue | wIndex | wLength | Data
0xA1 | 0x01 | 0x0000 | bInterfaceNumber field of Communication Class interface descriptor | 0x0400 (this is the minimum byte length of the buffer posted by host) | Control message block

If for some reason the device receives a GET_ENCAPSULATED_RESPONSE and is unable to respond with a valid data on the Control endpoint, then it should return a one-byte packet set to 0x00, rather than stalling the Control endpoint.


Data Channel Characteristics

The data channel for the device consists of the Bulk IN and OUT endpoints in the Data Class interface.

A single USB data transfer in either direction may consist of a single REMOTE_NDIS_PACKET_MSG or a longer multi-packet message.

The USB transfer to send a data message from the host to the device is a standard USB bulk transfer to the Bulk OUT endpoint of the Data Class interface.

The USB transfer to send a data message from the device to the host is a standard USB bulk transfer from the Bulk IN endpoint of the Data Class interface. The host will read up to the number of bytes indicated by the MaxTransferSize field of REMOTE_NDIS_INITIALIZE_MSG, which will be no greater than 0x4000 bytes for a USB 1.1 device.


USB Short Packets

USB passes data over the wire in the form of USB packets, which should not be confused with NDIS or networking packets. The maximum length of a USB packet to or from a USB endpoint is limited to the value of the wMaxPacketSize field of the endpoint's descriptor. For bulk pipes the maximum packet size is 64 bytes. Due to constraints of certain USB host controllers, there is a penalty associated with using short USB packets (for example, those of less then 64 bytes, when streaming data).

To work around this limitation, Remote NDIS USB devices may append zero-byte padding to data messages so that a short packet will not occur (within the constraints of the MaxTransferSize field of REMOTE_NDIS_INITIALIZE_MSG). The MessageLength field of the final REMOTE_NDIS_PACKET_MSG does not include these appended padding bytes.

If the device has transmitted its last available REMOTE_NDIS_PACKET_MSG (so no more are left in the device's queue), then it is acceptable to send a short USB packet.

If the last REMOTE_NDIS_PACKET_MSG of a device-send RNDIS data message (without any zero-byte padding) ends with a USB packet whose length is exactly the wMaxPacketSize for that endpoint, then the device may send an additional one-byte zero packet as an appended part of the transfer. Some device implementations are simplified by this allowance.

Similarly, some device-side USB chipsets do not detect the end of a received USB transfer that ends with a USB packet whose length is the wMaxPacketSize for that endpoint. For this reason, the host must append a one-byte zero packet to a data transfer that otherwise would have a length that is a multiple of the wMaxPacketSize of the receiving endpoint. USB RNDIS devices must tolerate the appended byte. The MessageLength field of the final REMOTE_NDIS_PACKET_MSG does not include this appended byte.


Flow Control

Flow control for a USB Remote NDIS device is defined by the USB Specification.

Since all communication on USB is based on a host to device transaction, all the host must do to slow the flow of data is stop issuing IN tokens to the device on the bulk pipe. If the device needs to assert flow control, then it should NAK data transfers from the host until it is able to process data again. For a detailed explanation of this process, review Section 8.4.4 in the USB Specification, version 1.1.


Power Management

A USB Remote NDIS device must support the Power Management OIDs as well as Network wake-up OIDs listed in the Windows 2000 DDK under NDIS OIDs. See the USB specification for a description of USB bus-level power management.


Timer Constants

The ControlTimeoutPeriod for a USB Remote NDIS device is 10 seconds.

The KeepAliveTimeoutPeriod for a USB Remote NDIS device is 5 seconds.


USB 802.3 Device Sample

The following is a sample set of descriptors for a USB Remote NDIS Ethernet Device. It includes a CDC Communication Class interface and a CDC Data Class interface. The Device Descriptor is returned independently. The Configuration descriptor and all following descriptors are returned as a single block in the order shown.

Control messages are sent on the Control endpoint. Notification messages are sent on the Interrupt In endpoint in the CDC Communication Class interface. Data messages are sent on the Bulk In and Bulk Out endpoints in the CDC Data Class interface. String descriptors are not shown.

The Remote NDIS implementation in Windows Millennium Edition assumes that the Communication Class interface precedes the Data Class interface. Vendors should choose this descriptor ordering so that devices initialize correctly on Windows Millennium Edition.

If any portion of this sample contradicts a controlling specification, follow the specification.


Device Descriptor

Offset | Field | Size | Value | Description
0 | bLength | 1 | 0x12 | Size of this descriptor, in bytes
1 | bDescriptorType | 1 | 0x01 | DEVICE descriptor
2 | bcdUSB | 2 | 0x0110 | 1.1 - current revision of USB spec
4 | bDeviceClass | 1 | 0x02 | Communication Device Class
5 | bDeviceSubClass | 1 | 0x00 | Unused
6 | bDeviceProtocol | 1 | 0x00 | Unused
7 | bMaxPacketSize0 | 1 | 0x08 | Max packet size on control pipe
8 | idVendor | 2 | 0xXXXX | Vendor ID
10 | idProduct | 2 | 0xXXXX | Product ID
12 | bcdDevice | 2 | 0xXXXX | Device Release Code
14 | iManufacturer | 1 | 0x01 | Index of manufacturer string
15 | iProduct | 1 | 0x02 | Index of product string
16 | iSerialNumber | 1 | 0x03 | Index of device serial number string
17 | bNumConfigurations | 1 | 0x01 | One configuration


Configuration Descriptor

Offset | Field | Size | Value | Description
0 | bLength | 1 | 0x09 | Size of this descriptor, in bytes
1 | bDescriptorType | 1 | 0x02 | CONFIGURATION descriptor
2 | wTotalLength | 2 | 0x003E | Length of the total configuration block, including this descriptor and all following descriptors, in bytes
4 | bNumInterfaces | 1 | 0x02 | Two interfaces
5 | bConfigurationValue | 1 | 0x01 | ID of this configuration
6 | iConfiguration | 1 | 0x00 | Unused
7 | bmAttributes | 1 | 0x80 | Bus Powered
8 | MaxPower | 1 | 0x64 | 200 mA


Interface Descriptor for Communication Class Interface

Offset | Field | Size | Value | Description
1 | bDescriptorType | 1 | 0x04 | INTERFACE descriptor
2 | bInterfaceNumber | 1 | 0x00 | Index of this interface
3 | bAlternateSetting | 1 | 0x00 | Index of this setting
4 | bNumEndpoints | 1 | 0x01 | 1 endpoint
5 | bInterfaceClass | 1 | 0x02 | Communication Class
6 | bInterfaceSubclass | 1 | 0x02 | Abstract Control Model
7 | bInterfaceProtocol | 1 | 0xFF | Vendor-specific protocol
8 | iInterface | 1 | 0x00 | Unused


Notification Endpoint Descriptor

Offset | Field | Size | Value | Description
0 | bLength | 1 | 0x07 | Size of this descriptor, in bytes
1 | bDescriptorType | 1 | 0x05 | ENDPOINT descriptor
2 | bEndpointAddress | 1 | 0x81 | Endpoint 1 IN
3 | bmAttributes | 1 | 0x03 | Interrupt Endpoint
4 | wMaxPacketSize | 2 | 0x0008 | 8 byte maximum packet size
6 | bInterval | 1 | 0x01 | Polling interval


Interface Descriptor for Data Class Interface

Offset | Field | Size | Value | Description
0 | bLength | 1 | 0x09 | Size of this descriptor, in bytes
1 | bDescriptorType | 1 | 0x04 | INTERFACE descriptor
2 | bInterfaceNumber | 1 | 0x01 | Index of this interface
3 | bAlternateSetting | 1 | 0x00 | Index of this setting
4 | bNumEndpoints | 1 | 0x02 | 2 endpoints
5 | bInterfaceClass | 1 | 0x0A | Data Class
6 | bInterfaceSubclass | 1 | 0x00 | Unused
7 | bInterfaceProtocol | 1 | 0x00 | Unused
8 | iInterface | 1 | 0x00 | Unused


Data In Endpoint Descriptor

Offset | Field | Size | Value | Description
0 | bLength | 1 | 0x07 | Size of this descriptor, in bytes
1 | bDescriptorType | 1 | 0x05 | ENDPOINT descriptor
2 | bEndpointAddress | 1 | 0x82 | Endpoint 2 IN
3 | bmAttributes | 1 | 0x02 | Bulk Endpoint
4 | wMaxPacketSize | 2 | 0x0040 | 64 byte maximum packet size
6 | bInterval | 1 | 0x00 | Unused


Data Out Endpoint Descriptor

Offset | Field | Size | Value | Description
0 | bLength | 1 | 0x07 | Size of this descriptor, in bytes
1 | bDescriptorType | 1 | 0x05 | ENDPOINT descriptor
2 | bEndpointAddress | 1 | 0x03 | Endpoint 3 OUT
3 | bmAttributes | 1 | 0x02 | Bulk Endpoint
4 | wMaxPacketSize | 2 | 0x0040 | 64 byte maximum packet size
6 | bInterval | 1 | 0x00 | Unused


NDIS Debugging

Good and plentiful debugging information is the key to successfully debugging network drivers. The following sections describe how to use NDIS debugger extensions and the Verifier utility to gather debugging information from network drivers:

NDIS Debugger Extensions

NDIS Verifier

For more information on the Verifier utility, see Activating and Monitoring Driver Verifier.


NDIS Debug Extensions For Windows 2000 and Later

For Windows 2000 and later versions of the operating system, you can use extensions in the NDIS debugger DLL (Ndiskd.dll) along with a checked version of the NDIS library of functions (Ndis.sys) to debug various NDIS components. You can also use extensions in the NDIS debugger DLL to examine NDIS data structures. The Debugging Tools for Windows package contains the NDIS debugger DLL. For more information, see Debugging Tools for NT-Based Operating Systems.

The following topics describe how to use NDIS debugger extensions and how to set up NDIS debug tracing:

Installing NDIS Debugger Extensions

Loading NDIS Debugger Extensions

Using NDIS Debugger Extensions

Enabling NDIS Debug Tracing on Windows 2000 and Later

Note To debug NDIS components, a checked version of Ndis.sys is required on the target computer. However, instead of installing an entire checked-build operating system, just copy the checked version of Ndis.sys onto an otherwise free-build operating system. Before you copy the checked version of Ndis.sys to the target computer, you must disable Windows File Protection (WFP). To ensure that WFP is disabled, start the operating system in safe mode.

Note The NDIS debugging variables that are described in NDIS Debug Extensions For Windows NT 4.0 are also available on Windows 2000 and later versions of the operating system. However, the extensions in the NDIS debugger DLL provide an easier method of enabling debug tracing and allow you to debug more NDIS component types.


Installing NDIS Debugger Extensions

Perform the following procedure to install NDIS Debugger extensions so that you can either enable debug tracing or use other extensions:

To install the NDIS Debugger extensions

  1. Depending on whether the target computer is running a checked or free build of the operating system, copy either the checked or free version of Ndiskd.dll respectively from the Debugger Tools for Windows package to the directory that contains the debugger to be used. For example, the debugger could be either Windbg.exe or i386kd.exe.
  2. Copy the corresponding Ndis.sys symbols files (for example, the Ndis.pdb and Ndis.dbg files) to the symbols directory of the host computer.


Loading NDIS Debugger Extensions

Before you can use NDIS Debugger extensions, the debugger you are using must load the NDIS debugger DLL. The debugger can either load the NDIS debugger DLL explicitly with the debugger's own load command, or implicitly when the debugger first runs one of the NDIS debugger DLL's extension commands. The following procedures show both methods of loading NDIS Debugger extensions:

To explicitly load the NDIS Debugger DLL

  1. At the debugger's command prompt, enter the following command:
    !load ndiskd.dll
  2. The debugger loads Ndiskd.dll but does not run an extension.

To implicitly load the NDIS Debugger DLL

  1. At the debugger's command prompt, enter the following command:
    !ndiskd.extension_name [arguments]
  2. The debugger loads Ndiskd.dll, calls a DLL entry point to run a specific extension command, and passes arguments to that extension.

Once the debugger loads the NDIS debugger DLL, you can specify any of the NDIS debugger DLL's extensions at the debugger's command prompt to run that extension command as shown in the following example:

!extension_name

Note When you run an extension without also specifying Ndiskd.dll, the debugger searches for the extension in the extension DLL that the debugger most recently loaded. If the debugger does not find the extension, the debugger searches through extension DLLs in the order that they were loaded and runs the first instance of the extension that the debugger finds.


Using NDIS Debugger Extensions

After you load the NDIS debugger DLL, you can examine NDIS data structures and set up NDIS debug tracing by using the following NDIS debugger extensions:

Extension | Description
!dbglevel | Selects the NDIS debug level.
!dbgsystems | Selects NDIS components to debug.
!findpacket | Finds specified packets.
!gminiports | Displays a list of all miniport instances, including those that have not yet started.
!help | Displays all Ndiskd.dll extension commands.
!mem | Displays a log of all allocated memory.
!miniport | Displays a miniport block.
!miniports | Displays a list of all miniport instances, except for those that have not yet started.
!mopen | Displays a miniport open block.
!ndis | Displays NDIS information.
!opens | Displays a list of all open objects.
!pkt | Displays information about a packet.
!pktpools | Displays a list of all allocated packet pools.
!protocol | Displays the contents of a protocol block.
!protocols | Displays a list of all protocols and their open objects.

For reference information on the NDIS debugger DLL's extensions, see NDIS Extensions (ndiskd.dll) in the Debugger documentation.

For a quick reference of all the extension commands, enter the help extension at the debugger's command prompt.


Enabling NDIS Debug Tracing on Windows 2000 and Later

You can enable debug tracing either by entering NDIS debugger extensions during a debugger session, or by setting values in the registry.

Enabling NDIS Debug Tracing During a Debugger Session

You can enable different levels of debug tracing in various NDIS components by using the following extensions in the NDIS debugger DLL:

dbglevel [Value]
Selects the level or amount of debug tracing in NDIS components that are selected with the dbgsystems extension. The following values specify levels that you can select:

INFO

LOG

WARN

ERR

FATAL

dbgsystems [Values]
Selects various NDIS components to debug trace. The following values specify the NDIS components that you can select:

INIT

CONFIG

SEND

RECV

PROTOCOL

BIND

BUS_QUERY

REGISTRY

MEMORY

FILTER

REQUEST

WORK_ITEM

PNP

PM

OPEN

LOCKS

RESET

WMI

NDIS_CO

REFERENCE

You can select more than one NDIS component. If more than one component is selected, separate each component value with a space. For example, to select SEND and RECV:

!dbgsystems SEND RECV

If you previously selected an NDIS component, running the command again with that component selected turns off debug tracing for that component.

Enabling NDIS Debug Tracing Through Registry Settings

You can enable different levels of debug tracing in various NDIS components through the registry by adding the following entries and values to the HKLM\SYSTEM\CurrentControlSet\Services\NDIS\Parameters registry key:

"DebugLevel"=dword:00000000
"DebugSystems"=dword:000030F3
"DebugBreakPoint"=dword:00000001

The following indicates acceptable values to set for DebugBreakPoint, DebugLevel and DebugSystems:

DebugBreakPoint
Setting to 1 causes NDIS to debug break in its DriverEntry function.
DebugLevel
Selects the level or amount of debug tracing in NDIS components that are selected with the DebugSystems value. The following values specify levels that you can select:
Level Description | Value
DBG_LEVEL_INFO | 0x00000000
DBG_LEVEL_LOG | 0x00000800
DBG_LEVEL_WARN | 0x00001000
DBG_LEVEL_ERR | 0x00002000
DBG_LEVEL_FATAL | 0x00003000

DebugSystems
Selects various NDIS components to debug trace. The following values specify the NDIS components that you can select:
Component Description | Value
DBG_COMP_INIT | 0x00000001
DBG_COMP_CONFIG | 0x00000002
DBG_COMP_SEND | 0x00000004
DBG_COMP_RECV | 0x00000008
DBG_COMP_PROTOCOL | 0x00000010
DBG_COMP_BIND | 0x00000020
DBG_COMP_BUSINFO | 0x00000040
DBG_COMP_REG | 0x00000080
DBG_COMP_MEMORY | 0x00000100
DBG_COMP_FILTER | 0x00000200
DBG_COMP_REQUEST | 0x00000400
DBG_COMP_WORK_ITEM | 0x00000800
DBG_COMP_PNP | 0x00001000
DBG_COMP_PM | 0x00002000
DBG_COMP_OPENREF | 0x00004000
DBG_COMP_LOCKS | 0x00008000
DBG_COMP_RESET | 0x00010000
DBG_COMP_WMI | 0x00020000
DBG_COMP_CO | 0x00040000
DBG_COMP_REF | 0x00080000
DBG_COMP_ALL | 0xFFFFFFFF

You can select more than one NDIS component. If more than one component is selected, OR the data values together. For example, to select PNP, PM, INIT and CONFIG:

"DebugSystems"=dword:00003003

Note Using the registry technique to enable debug tracing is a good idea if the symbols directory of the host computer does not contain the checked symbols of Ndis.sys. However, whenever you change settings for debug tracing, you must restart your computer for the new settings to take effect.


NDIS Debug Extensions For Windows NT 4.0

For Windows NT 4.0, you can use a checked version of the NDIS library of functions (Ndis.sys) plus debugging variables in NDIS to debug various NDIS 4.0 drivers. The following topics list acceptable values for these debugging variables and describe how to set up NDIS debug tracing:

Values for NDIS Debugging Variables in Windows NT 4.0

Setting Up NDIS Debug Tracing on Windows NT 4.0

Note By enabling the trace levels within NDIS, you could adversely affect timing and performance parameters, which could cause or contribute to additional failures.

Note These debugging variables are also available on Windows 2000 and later versions of the operating system. However, using extensions in the NDIS debugger DLL provides an easier method to enable debug tracing and allows you to debug more NDIS component types. For more information, see NDIS Debug Extensions For Windows 2000 and Later.


Values For NDIS Debugging Variables in Windows NT 4.0

You can enable different levels of debug tracing in various NDIS components by using the following values for NDIS debugging variables:

ndisDebugLevel
Selects the level or amount of debug tracing in NDIS components that are selected with the ndisDebugSystems value. The following values specify levels that you can select:
Level Description | Value
DBG_LEVEL_INFO | 0x00000000
DBG_LEVEL_WARN | 0x00001000
DBG_LEVEL_ERR | 0x00002000
DBG_LEVEL_FATAL | 0x00003000

ndisDebugSystems
Selects various NDIS components to debug trace. The following values specify the NDIS components that you can select:
Component Description | Value
DBG_COMP_INIT | 0x00000001
DBG_COMP_CONFIG | 0x00000002
DBG_COMP_SEND | 0x00000004
DBG_COMP_RECV | 0x00000008
DBG_COMP_MEMORY | 0x00000010
DBG_COMP_FILTER | 0x00000020
DBG_COMP_PROTOCOL | 0x00000040
DBG_COMP_REQUEST | 0x00000080
DBG_COMP_UNLOAD | 0x00000100
DBG_COMP_WORK_ITEM | 0x00000200
DBG_COMP_OPEN | 0x00000400
DBG_COMP_LOCKS | 0x00000800
DBG_COMP_ALL | 0xFFFFFFFF

You can select more than one NDIS component. If more than one component is selected, OR the data values together.


Setting Up NDIS Debug Tracing on Windows NT 4.0

You can use a debugger to modify the NDIS debugging variables at any time after the operating system loads Ndis.sys. You can choose either to break into the target computer through the ^C system request or by setting a breakpoint at some location in your driver. In either case, Ndis.sys must be loaded so that the debugger can access the NDIS debugging variables.

The following sequence shows how to modify NDIS debugging variables using the Windbg.exe debugger and by stopping the debugger:

To modify NDIS debugging variables

  1. Press ^C to break into the target computer and to stop the debugger after NDIS loads as shown in the following code snippet:
    ^C <process stopping...>
Hard coded breakpoint hit
  2. To debug (that is, to obtain DbgPrint statements within NDIS) filter components (DBG_COMP_FILTER), enter the following DWORD for the ndisDebugSystems variable at the debugger command prompt:
    kd> ed ndis!ndisDebugSystems 00000020
  3. To obtain informational-level debugging (that is, the lowest level of debugging), enter the following DWORD for the ndisDebugLevel variable at the debugger command prompt:
    kd> ed ndis!ndisDebugLevel 0
  4. Press the F5 key to restart the target computer.


Setting NDIS Debugging Options in the Registry

You can enable different levels of debug tracing in various NDIS components by setting values for the following entries under the HKLM\System\CurrentControlSet\Services\VxD\NDIS registry key:

(DWORD) DebugBreak (Boolean)
(DWORD) TraceImpt (Boolean)
(DWORD) DebugSystems
(DWORD) DebugLevel

The following indicates acceptable values to set for DebugBreak, TraceImpt, DebugLevel and DebugSystems:

DebugBreak
Setting to 1 (enabled) causes NDIS to break into the debugger through an INT 3 when NDIS loads (that is, debug breaks in NDIS's DriverEntry function).
TraceImpt
The trace-important flag. Setting to 1 (enabled) causes trace output to be emitted to the debugger. While debugging, this flag should always be enabled.
DebugLevel
Selects the level or amount of trace information that is emitted to the debugger for the NDIS components that are selected with the DebugSystems value. The following values specify levels that you can select:
Level Description | Value
INFO | 0x00000000
LOG | 0x00000800
WARN | 0x00001000
ERR | 0x00002000
FATAL | 0x00003000

INFO produces the most trace information. If TraceImpt is enabled, DebugLevel's default value is INFO; otherwise, it is FATAL.

DebugSystems
Selects various NDIS components to emit debug trace information. The following values specify the NDIS components that you can select:
Component Description | Value
INIT | 0x00000001
CONFIG | 0x00000002
SEND | 0x00000004
RECV | 0x00000008
PROTOCOL | 0x00000010
BIND | 0x00000020
BUSINFO | 0x00000040
REG | 0x00000080
MEMORY | 0x00000100
FILTER | 0x00000200
REQUEST | 0x00000400
WORK_ITEM | 0x00000800
PNP | 0x00001000
PM | 0x00002000
OPENREF | 0x00004000
LOCKS | 0x00008000
RESET | 0x00010000
WMI | 0x00020000
CO | 0x00040000
REF | 0x00080000
ALL | 0xFFFFFFFF

You can select more than one NDIS component. If more than one component is selected, OR the data values together. By default, if TraceImpt is enabled, the INIT, CONFIG, PNP, PM, PROTOCOL, BIND, BUSINFO, and REG components are selected. That is, the DebugSystems value appears as follows with these values selected:

"DebugSystems"=dword:000030F3


Setting NDIS Debugging Options in the Debugger

One debugging option cannot be set through a registry entry. This debugging option is the NdisTraceAll flag and must be set during a debugger session. You are not required to set the NdisTraceAll flag; however, if it is enabled, the debugger produces verbose trace information.

The following sequence shows how to enable the NdisTraceAll flag:

To enable the NdisTraceAll flag

  1. Set the DebugBreak value in the registry to 1 (enabled). Doing so, causes NDIS to break at startup as described in Setting NDIS Debugging Options in the Registry.
  2. When NDIS hits the breakpoint, load symbols for NDIS and then set the NdisTraceAll flag as shown in the following code snippet:
    kd> wa ndis
kd> e ndistraceall 1


Setting Debugging Options in the Network Class Installer

The network class installer (Netdi.dll) is the class installer for all network components for Windows Me. During installation, Netdi.dll produces diagnostic information in the NetLog.txt log file in the operating system's root directory. The checked version of Netdi.dll can emit extensive diagnostic information to the debugger, if a debugger is installed on the target computer. You can also set a debugging option so that Netdi.dll emits diagnostic information to the NetLog.txt file in addition to the debugger. You can set debugging options in Netdi.dll by setting values for the following entries under the HKLM\Software\Microsoft\Windows\CurrentVersion\Network registry key:

DisableEmitToDebugger (DWORD)
EnableLogging (DWORD)
ShowSelectBestCompat (DWORD)
ShowSelectedDriver (DWORD)

The following describes these debugging options:

DisableEmitToDebugger
If set to 1, debug output is not sent to the debugger. The default value is zero.
EnableLogging
If set to 1, debug output is also appended to the NetLog.txt log file. By default, logging is disabled.
ShowSelectBestCompat
If set to 1 (enabled), Netdi.dll produces a dialog box that shows the compatible driver list during driver selection of a selected device. Device node and INF file information is shown for the most compatible and other compatible drivers. This option is available only in checked versions of Netdi.dll. By default, this option is disabled.
ShowSelectedDriver
If set to 1 (enabled), Netdi.dll produces a dialog box that is similar to the one produced with the ShowSelectBestCompat option when driver selection completes for a device. This option is available only in checked versions of Netdi.dll. By default, this option is disabled.

Also, if you are analyzing a network installation problem during the installation or upgrade to Windows Me, the checked version of Netdi.dll can be placed in the same directory as all the other .cab files for Windows Me. This private copy of Netdi.dll overrides the retail copy found in the .cab file. Because a debugger is not available during an installation or upgrade, diagnostic information is automatically sent to the NetLog.txt file.

Note You must disable System File Protection (SFP) before you copy the checked version of Netdi.dll to the Windows\System directory of the target computer; otherwise, the original copy is silently restored. To ensure that SFP is disabled, either start from the Microsoft® Windows® Me startup floppy or start Windows Me in safe mode.


NDIS Debug Extensions For Windows 98

For Windows 98 and Windows 98 SE, you can use a checked version of the NDIS library of functions (Ndis.vxd) plus global debugging symbols to produce debug output for various network drivers as execution passes through NDIS. You enable these debugging symbols during a debugger session. The following topics list acceptable values for these debugging symbols and describe how to set up NDIS debug tracing:

Values For NDIS Debugging Options in Windows 98

Setting Up NDIS Debug Tracing on Windows 98


Values For NDIS Debugging Options in Windows 98

You can enable different levels of debug tracing in various NDIS components by using the following global debugging symbols:

ndistraceimpt
The trace-important flag. Setting to 1 (enabled) causes trace output to be emitted to the debugger. While debugging, this flag should always be enabled.
ndisdebuglevel
Selects the level or amount of debug tracing in NDIS components that are selected with the ndisdebugsystems value. The following values specify the levels that you can select:
Level Description | Value
INFORMATION | 0x00000000
LOG | 0x00000800
WARNING | 0x00001000
ERROR | 0x00002000
FATAL | 0x00003000

ndisdebugsystems
Selects various NDIS components to debug trace. The following values specify the NDIS components that you can select:
Component Description | Value
INITIALIZE | 0x00000001
CONFIGURATION | 0x00000002
SEND | 0x00000004
RECEIVE | 0x00000008
MEMORY | 0x00000010
FILTER | 0x00000020
PROTOCOL | 0x00000040
REQUEST | 0x00000080
UNLOAD | 0x00000100
WORK ITEM | 0x00000200
OPEN | 0x00000400
LOCKS | 0x00000800
PLUG AND PLAY | 0x00001000
PM | 0x00002000
RESET | 0x00004000
Windows Machine Instrumentation | 0x00008000
CoSTATUS | 0x00010000
REFERENCE | 0x00020000
ALL | 0xFFFFFFFF

You can select more than one NDIS component. If more than one component is selected, OR the data values together.


Setting Up NDIS Debug Tracing on Windows 98

You can use the Windows 98 debugger (WDEB98/RTERM98) to modify the global debugging symbols for NDIS. The Windows 98 debugger is available in the Windows 98 DDK. The following sequence shows how to modify these global debugging symbols:

To modify global debugging symbols for NDIS

  1. When you load the debugger, add the /B option to cause the debugger to break after VMM32 loads.

    At the break, you can load the global debugging symbols and set their values as shown in the following steps.

  2. Load the global debugging symbols as shown in the following code snippet. These symbols must be on the debug console in the location specified in RTERM98's Symbol Search Path (Settings/Options).
    kd> wa ndis
  3. Set the ndistraceimpt flag as shown in the following code snippet:
    kd> e ndistraceimpt 1
  4. Set the ndistraceall flag as shown in the following code snippet:
    kd> e ndistraceall 1
  5. To obtain error-level debugging, enter the following value for the ndisdebuglevel symbol:
    kd> e ndisdebuglevel 00 20 00 00
  6. To obtain component-trace information for RECEIVE and SEND, enter the following value for the ndisdebugsystems symbol:
    kd> e ndisdebugsystems 0C 00 00 00
  7. All trace output is emitted to the debugger.


NDIS WAN Debug Extensions For NT-Based Operating Systems

For NT-based operating systems, you can use a checked version of the NDISWAN intermediate driver (Ndiswan.sys) plus debugging variables in NDISWAN to debug various WAN miniport drivers. You can enable NDISWAN debug tracing by setting values in the registry. When you set up NDISWAN debug tracing, you are actually enabling one or more levels of DbgPrint statements within NDISWAN, which, in most cases, provides enough information to successfully debug most WAN miniport driver problems.

Note By enabling the trace levels within NDISWAN, you could adversely affect timing and performance parameters, which could cause or contribute to additional failures.

You can enable different levels of debug tracing in various NDISWAN components by adding the following entries and values to the HKLM\System\CurrentControlSet\Services\NdisWan\Parameters key in the registry:

REG_DWORD DebugIdentifier
REG_DWORD DebugLevel

The following indicates acceptable values to set for DebugLevel and DebugIdentifier:

DebugLevel
Selects the level or amount of debug tracing in NDISWAN components that are selected with the DebugIdentifier value. The following values specify levels that you can select:
Level Description | Value
DBG_DEATH | 1
DBG_CRITICAL_ERROR | 2
DBG_FAILURE | 4
DBG_INFO | 6
DBG_TRACE | 8
DBG_VERBOSE | 10

DebugIdentifier
Selects various NDISWAN components to debug. The following values specify the NDISWAN components that you can select:
Component Description | Value
DBG_INIT | 0x00000001
DBG_MINIPORT | 0x00000002
DBG_PROTOCOL | 0x00000004
DBG_SEND | 0x00000008
DBG_RECEIVE | 0x00000010
DBG_IO | 0x00000020
DBG_MEMORY | 0x00000040
DBG_VJ | 0x00000080
DBG_TAPI | 0x00000100
DBG_CCP | 0x00000200
DBG_LOOPBACK | 0x00000400
DBG_MULTILINK_RECV | 0x00000800
DBG_MULTILINK_SEND | 0x00001000
DBG_SEND_VJ | 0x00002000
DBG_RECV_VJ | 0x00004000
DBG_CL | 0x00008000
DBG_CM | 0x00010000
DBG_INDICATE | 0x00020000
DBG_BACP | 0x00040000
DBG_REQUEST | 0x00080000
DBG_ALL | 0xFFFFFFFF

You can select more than one NDISWAN component. If more than one component is selected, OR the data values together.


NDIS Verifier

The NDIS Verifier is a feature that is included in the checked version of the NDIS library of functions (Ndis.sys) for Windows XP and later versions of the operating system. You can use the NDIS Verifier to verify that your network driver is not making invalid or obsolete function calls. You can also use the NDIS Verifier to check the validity of values that are passed to certain functions.

The following topics describe how to enable and use the NDIS Verifier and list examples of warning messages that can be displayed for certain types of function calls.

Enabling the NDIS Verifier

Displaying Warning Messages


Enabling the NDIS Verifier

This topic explains how to enable the NDIS Verifier.

To enable the NDIS Verifier

  1. Install a checked version of Ndis.sys to the %SystemRoot%\System32\Drivers directory on the target computer.

    Note Instead of installing an entire checked-build operating system, just copy the checked version of Ndis.sys onto an otherwise free-build operating system.
    Because Windows File Protection (WFP) protects against the replacement of any system files, you must start the operating system in safe mode.

  2. Enable the network driver that is to be verified in the input/output (I/O) manager's Driver Verifier. For more information, see the Driver Verifier.
  3. Enable different levels for NDIS Verifier by adding the following Flags entry and value to the HKLM\System\CurrentControlSet\Services\NDIS\Parameters key in the registry:
    "Flags":dword:0x00000FFF

    The following table indicates acceptable values to set for Flags:
    Flag Bit | Value
    NDIS_GFLAG_INIT_TIME | 0x00000001
    NDIS_GFLAG_TRACK_PKTS | 0x00000002
    NDIS_GFLAG_INJECT_ALLOCATION_FAILURE | 0x00000004
    NDIS_GFLAG_SPECIAL_POOL_ALLOCATION | 0x00000008
    NDIS_GFLAG_DONT_VERIFY | 0x00000100
    NDIS_GFLAG_BREAK_ON_WARNING | 0x00000200
    NDIS_GFLAG_WARNING_LEVEL_MASK | 0x00000030
    NDIS_GFLAG_WARN_LEVEL_0 | 0x00000000
    NDIS_GFLAG_WARN_LEVEL_1 | 0x00000010
    NDIS_GFLAG_WARN_LEVEL_2 | 0x00000020
    NDIS_GFLAG_WARN_LEVEL_3 | 0x00000030

    You can select more than one Flags bit. If more than one bit is selected, OR the values together.

Note Along with enabling the network driver in the Driver Verifier, you should enable NDIS debug tracing to let the Ndis.sys driver perform most of the debugging work on behalf of the network driver. For more information, see NDIS Debug Extensions For Windows 2000 and Later.

By setting bits for the Flags entry, you can control how the NDIS Verifier behaves. For example, if you set the NDIS_GFLAG_BREAK_ON_WARNING bit, the debugger breaks on every warning. In addition, the various warning level bits let you specify how strictly you want NDIS to verify. The higher you set the level, the stricter NDIS Verifier is as indicated in the following examples:

  • Warning level 0 breaks on outright bugs only. For example, indicating packets before you set the filter or not registering a MiniportShutdown function.
  • Warning level 1 warns you that your driver called a function that is obsolete for Windows 2000 and later operating systems. For example, the NdisOverrideBusNumber function.
  • Warning level 2 warns you about actions that you should not implement in your driver. For example, if you wrote your driver to call the NdisReadConfiguration function instead of the NdisMQueryAdapterResources function to get the standard resources.
  • Warning level 3 warns you that your driver called a function that is obsolete for Windows XP and later operating systems. For example, the immediate functions such as NdisImmediateRead/WritePciSlotInformation.

Typically, you should set the level to "Warning level 3" to detect everything.


Displaying Warning Messages

The NDIS Verifier currently enables a DbgPrint warning message and breaks into the debugger if the NDIS_GFLAG_BREAK_ON_WARNING is set for the following cases:

  • Drivers that use reserved keywords instead of NdisMQueryAdapterResources to get assigned resources.
  • Drivers that use the following functions:
    • NdisImmediateRead/WritePciSlotInformation: Use instead NdisReadPciSlotInformation and NdisWritePciSlotInformation.
    • NdisImmediateRead/WritePortUchar/Ushort/Ulong: Register the I/O port range and use instead NdisRead/WritePortUchar/Ushort/Ulong.
    • NdisImmediateRead/NdisWriteSharedMemory: Map the I/O space and do a direct read/write operation.
    • NdisRead/WritePciSlotInformation with a slot number that is anything but zero.
    • NdisMPciAssignResources: Use instead NdisMQueryAdapterResources.
    • NdisAllocateMemory: Use instead NdisAllocateMemoryWithTag.
    • NdisQuerymapRegisterCount: Obsolete function. Instead, use the NdisMAllocateMapRegisters function in a loop, or the NdisMInitializeScatterGatherDma function.
  • Miniport drivers that specify NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT/NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT in the NdisMSetAttributesEx function. The NDIS Verifier catches only hardware drivers that use I/O resources. Intermediate drivers and WAN miniport drivers can specify these flags.
  • Drivers that indicate packets (such as when drivers call the NdisMIndicateReceivePacket function) before setting the filter.

• Drivers that do not register a MiniportShutdown function.


NDIS Driver Upper-Edge Functions

This section describes, in alphabetic order, the system-defined functions implemented in NIC drivers and in intermediate drivers that export a set of NDIS upper-edge functions.

Two types of NDIS drivers have some or all of the functions described here:

  1. NDIS miniport drivers, whether for LAN or WAN NICs, export the DriverEntry and MiniportXxx functions described here.

    NIC drivers for WAN media export the same functions as NIC drivers for LAN media with one exception: a MiniportWanSend function replaces the MiniportSendPackets or MiniportSend function of LAN miniports. Each of these MiniportXxx functions is described later.

  2. Intermediate drivers export a subset of the MiniportXxx functions described here and a DriverEntry function that fulfills the initialization-time requirements of the NDIS library.

    Intermediate drivers also can export a set of the NDIS Driver Lower-Edge Functions, described later, or they can use another interface to communicate with underlying drivers of devices other than a NIC.

    NDIS intermediate drivers export both ProtocolXxx and MiniportXxx functions, but they need not have certain functions, such as MiniportISR or MiniportTimer, that any NIC driver must have to communicate with and control its NIC.

Driver Function Names

All NDIS driver functions with the prefix "Miniport" have been given metanames describing their respective basic functionality in the alphabetical references that follow.

Except for the DriverEntry function, NDIS driver functions can have any name the driver writer chooses. For easy debugging, most system-supplied miniports simply substitute a driver-specific prefix for the "Miniport" prefix used in this documentation.

The initial entry point of any kernel-mode driver has the explicit name DriverEntry in order to be loaded. For more information about the general requirements for and functionality of DriverEntry routines, see Standard Driver Routine Requirements.

Calling NdisXxx Functions at Appropriate IRQLs

NDIS drivers' functions run, by default, at one of the following IRQLs, shown in order of increasing priority:
PASSIVE_LEVEL < DISPATCH_LEVEL < DIRQL.

NDIS intermediate drivers' functions run, by default, at either of the preceding lower priority IRQLs. Only drivers of NICs that generate interrupts have functions that run at device IRQL.

Any driver function running at IRQL PASSIVE_LEVEL can be pre-empted by a thread of execution running at a higher priority IRQL. Any driver function running at PASSIVE_LEVEL or DISPATCH_LEVEL can be pre-empted by an interrrupt, that is, by an interrupt service routine or by a synchronization routine that also runs at DIRQL.

Each of the following DriverEntry and MiniportXxx descriptions specifies the default IRQL at which that function runs. The default IRQLs of certain MiniportXxx effectively restrict the set of Ndis Xxx functions that these MiniportXxx can call. For example, it is a fatal error for a MiniportISR function, which runs at DIRQL, to call any Ndis Xxx function that requires calls from IRQL <= DISPATCH_LEVEL.

For specific information about the range of valid IRQLs for calls to each Ndis Xxx function, see NDIS Library Function References.

Initialization-Only and Pageable Driver Code

NDIS miniport drivers and intermediate drivers mark their DriverEntry functions as initialization-only code, using the NDIS_INIT_FUNCTION macro. This causes DriverEntry to be discarded after it returns control.

Other driver functions can be marked as pageable code, using the NDIS_PAGABLE_FUNCTION macro. However, a driver function can be pageable code if and only if it never runs at IRQL >= DISPATCH_LEVEL. This restriction implies the following:

  • A function marked pageable cannot acquire any spin lock and should not call other functions that do.
  • A function marked pageable cannot be called by any function that is holding a spin lock when the call occurs.
  • A function marked pageable must run always at IRQL < DISPATCH_LEVEL.


DriverEntry of NDIS Miniport Drivers

The DriverEntry function is required and is the first function that the system calls in any NDIS driver.

NDIS_STATUS
  DriverEntry(
    IN PVOID  Argument1,
    IN PVOID  Argument2
    );

Parameters

Argument1
Pointer to a system-supplied parameter. For Windows® 2000 and later drivers, this points to a driver object, which is opaque to any NDIS driver that exports only MiniportXxx functions.
Argument2
Pointer to a second system-supplied parameter. For Windows 2000 and later drivers, this points to a registry path, which is opaque to any NDIS driver that exports only MiniportXxx functions.

Return Value

DriverEntry returns the value returned by NdisMRegisterMiniport or NdisIMRegisterLayeredMiniport.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NDIS miniports and intermediate drivers carry out two basic tasks in their DriverEntry functions:

  1. Call NdisMInitializeWrapper to notify the NDIS library that the driver is about to register itself as a miniport driver.

    NDIS sets up the state it needs to track the driver and returns an NdisWrapperHandle, which the driver saves for subsequent calls to Ndis Xxx configuration and initialization functions.

  2. Fill in an NDISXX_MINIPORT_CHARCTERISTICS structure with the appropriate version numbers and the entry points for driver-supplied MiniportXxx functions and, then, call NdisMRegisterMiniport or NdisIMRegisterLayeredMiniport.

    Usually, NIC drivers call NdisMRegisterMiniport, as do intermediate drivers that export only a set of MiniportXxx functions. Usually, NDIS intermediate drivers call NdisIMRegisterLayeredMiniport, which effectively defers the initialization of such a driver's virtual NIC until the driver calls NdisIMInitializeDeviceInstance from its ProtocolBindAdapter function.

DriverEntry can allocate the NDISXX_MINIPORT_CHARACTERISTICS structure on the stack since the NDIS library copies the relevant information to its own storage. DriverEntry should clear the memory for this structure with NdisZeroMemory before setting any driver-supplied values in its members. The current MajorNdisVersion is 0x05, and the current MinorNdisVersion is 0x00. In each Xxx Handler member of the characteristics structure, DriverEntry must set the name of a driver-supplied MiniportXxx function, or the member must be NULL.

Calling NdisMRegisterMiniport causes the driver's MiniportInitialize function to run in the context of NdisMRegisterMiniport. Calling NdisIMRegisterLayeredMiniport defers the call to MiniportInitialize until the driver calls NdisIMInitializeDeviceInstance.

Drivers that call NdisMRegisterMiniport must be prepared for an immediate call to their MiniportInitialize functions. Such a driver must have sufficient installation and configuration information stored in the registry or available from calls to an Ndis Xxx bus-type-specific configuration function to set up any NIC-specific resources the driver will need to carry out network I/O operations.

Drivers that call NdisIMRegisterLayeredMiniport defer the call to their MiniportInitialize functions to another driver-supplied function that makes a call to NdisIMInitializeDeviceInstance. NDIS intermediate drivers usually register a ProtocolBindAdapter function and call NdisIMRegisterLayeredMiniport so that NDIS will call the ProtocolBindAdapter function after all underlying NIC drivers have initialized. This strategy gives such an NDIS intermediate driver, which makes the call to NdisIMInitializeDeviceInstance from ProtocolBindAdapter, the advantage of having its MiniportInitialize function configure driver-allocated resources for the intermediate's virtual NIC to the features of the underlying NIC driver to which the intermediate has already bound itself.

If NdisMRegisterMiniport or NdisIMRegisterLayeredMiniport does not return NDIS_STATUS_SUCCESS, DriverEntry must release any resources it allocated, such as memory to hold the NdisWrapperHandle, and must call NdisTerminateWrapper before it returns control. The driver will not be loaded if this occurs.

DriverEntry runs at IRQL PASSIVE_LEVEL.

See Also

DriverEntry of NDIS Protocol Drivers, NdisIMInitializeDeviceInstance, MiniportInitialize, NdisIMRegisterLayeredMiniport, NdisMInitializeWrapper, NdisMRegisterMiniport, NdisTerminateWrapper, NdisZeroMemory, ProtocolBindAdapter


MiniportAllocateComplete

The MiniportAllocateComplete function is an optional function, supplied by drivers of bus-master DMA NICs that call NdisMAllocateSharedMemoryAsync.

VOID
  MiniportAllocateComplete(
    IN NDIS_HANDLE  MiniportAdapterContext,
    IN PVOID  VirtualAddress,
    IN PNDIS_PHYSICAL_ADDRESS  PhysicalAddress,
    IN ULONG  Length,
    IN PVOID  Context
    );

Parameters

MiniportAdapterContext
Specifies the handle to a miniport driver-allocated context area in which the driver maintains per-NIC state, set up by MiniportInitialize.
VirtualAddress
Specifies the base virtual address of the shared memory allocated by a preceding call to NdisMAllocateSharedMemoryAsync or NULL if the allocation attempt failed.
PhysicalAddress
Specifies the base physical address, suitable for use by the NIC, mapped to VirtualAddress.
Length
Specifies the number of bytes allocated by the preceding call to NdisMAllocateSharedMemoryAsync.
Context
Pointer to a driver-determined context passed in the preceding call to NdisMAllocateSharedMemoryAsync.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Drivers of bus-master DMA NICs are most likely to achieve significant performance gains by supporting multipacket receive indications. Such a driver supplies a MiniportAllocateComplete function so it can call NdisMAllocateSharedMemoryAsync when it is running low on shared memory for receive buffers due to high network traffic.

NdisMAllocateSharedMemoryAsync allocates memory that is shareable between the driver, which uses virtual addresses, and its bus-master DMA NIC, which uses the corresponding physical addresses. NdisMAllocateSharedMemoryAsync calls MiniportAllocateComplete whether its allocation attempt succeeds or fails.

A call to NdisMAllocateSharedMemoryAsync can occur at IRQL <= DISPATCH_LEVEL, possibly from the driver's MiniportHandleInterrupt or MiniportTimer function as it indicates incoming receives to bound protocols with NdisMIndicateReceivePacket. Such a driver also must have a MiniportReturnPacket function.

MiniportAllocateComplete should test the value of VirtualAddress to determine whether the call to NdisMAllocateSharedMemoryAsync succeeded. If the call succeeded, VirtualAddress is nonNULL. If the call failed, VirtualAddress is NULL.

If the call to NdisMAllocateSharedMemoryAsync succeeded, MiniportAllocateComplete can set up additional receive buffers in the newly allocated shared memory block. If this call allocated cached memory, MiniportAllocateComplete should align each new receive buffer on a cache-line boundary. MiniportAllocateComplete must allocate the buffer descriptors that map these new receive buffers from buffer pool. Such a miniport driver can continue making multipacket receive indications, which NDIS forwards to the ProtocolReceivePacket function(s) of bound protocol(s) that export this function or as individual packets to the ProtocolReceive functions of other bound protocols.

If the call to NdisMAllocateSharedMemoryAsync failed, MiniportAllocateComplete should set a state variable in the MiniportAdapterContext area to indicate that the driver must set NDIS_STATUS_RESOURCES in the Status member of the out-of-band block for the packets it subsequently indicates. This status causes NDIS to call the ProtocolReceive function(s) of bound protocol(s) with each packet for which the miniport driver set NDIS_STATUS_RESOURCES, so protocol driver(s) release the miniport driver-allocated packets with chained receive buffers individually as they are indicated, rather than holding on to packets until the protocol(s) have processed all indicated data. When the receive buffer space in the miniport's existing shared memory area is replenished, the driver can reset its state variable and resume indicating packet arrays with NDIS_STATUS_SUCCESS.

MiniportAllocateComplete runs at IRQL DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportReturnPacket, MiniportTimer, NdisAllocateBuffer, NdisMAllocateSharedMemory, NdisMAllocateSharedMemoryAsync, NdisMIndicateReceivePacket, NDIS_PACKET_OOB_DATA, ProtocolReceive, ProtocolReceivePacket


MiniportCancelSendPackets

The MiniportCancelSendPackets function is optional. For a specified adapter, MiniportCancelSendPackets cancels the transmission of all packets that are marked with a specified cancellation identifier.

VOID
  MiniportCancelSendPackets(
    IN NDIS_HANDLE  MiniportAdapterContext
    IN ULONG_PTR CancelId
    );

Parameters

MiniportAdapterContext
Specifies the handle to a miniport driver-allocated context area in which the miniport driver maintains per-NIC state, set up by MiniportInitialize.
CancelId
A cancellation identifier. This identifier specifies the packet or group of packets whose transmission is being canceled.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Miniport drivers and intermediate drivers that queue send packets for more than one second should export a MiniportCancelSendPackets function. The MiniportCancelSendPackets function allows the miniport driver or intermediate driver to cancel the pending transmission of specified send packets.

When a protocol driver or intermediate driver calls the NdisCancelSendPackets function, NDIS calls the MiniportCancelSendPackets function of the appropriate lower-level driver (miniport driver or intermediate driver) on the binding, provided that the lower-lever driver exports a MiniportCancelSendPackets function.

A miniport driver's MiniportCancelSendPackets function performs the following operations:

  1. Traverses its list of queued packets for the specified adapter and calls NDIS_GET_PACKET_CANCEL_ID to obtain the cancellation identifier for each queued packet. The miniport driver compares the cancellation ID returned by NDIS_GET_PACKET_CANCEL_ID with the cancellation ID supplied to MiniportCancelSendPackets.
  2. Unlinks all packets whose cancellation identifiers match the specified cancellation identifier.
  3. Calls the NdisMSendComplete¸ NdisMSendWanComplete, or NdisMCoSendComplete function for all unlinked packets to return the packet with a completion status of NDIS_STATUS_ABORTED.

An intermediate driver's MiniportCancelSendPackets function performs the following operations:

  1. Performs the operations listed above for a miniport driver's MiniportCancelSendPackets function.
  2. Calls the NdisCancelSendPackets function, specifying the binding that maps to the adapter specified in the call to MiniportCancelSendPackets. In the call to NdisCancelSendPackets, the intermediate miniport driver passes the appropriate NdisBindingHandle and cancellation identifier (CancelId) passed to its MiniportCancelSendPackets function.

An intermediate driver performs these operations regardless of whether it supports packet stacking.

System support for MiniportCancelSendPackets is available in Windows XP and later operating systems.

MiniportCancelSendPackets runs at IRQL <= DISPATCH_LEVEL.

See Also

NdisCancelSendPackets, NDIS_GET_PACKET_CANCEL_ID, NdisGeneratePartialCancelId, NdisMCoSendComplete, NdisMSendComplete, NDIS_SET_PACKET_CANCEL_ID


MiniportCheckForHang

The MiniportCheckForHang function is an optional function that reports the state of the NIC, or monitors the responsiveness of an underlying device driver.

BOOLEAN
  MiniportCheckForHang(
    IN NDIS_HANDLE  MiniportAdapterContext
    );

Parameters

MiniportAdapterContext
Specifies the handle to a miniport driver-allocated context area in which the driver maintains per-NIC state, set up by MiniportInitialize.

Return Value

MiniportCheckForHang returns TRUE if the driver determines that its NIC is not operating or if an intermediate driver determines that the underlying device driver is unresponsive.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

In NIC drivers, MiniportCheckForHang does nothing more than check the internal state of the NIC and return TRUE if it detects that the NIC is not operating correctly.

In intermediate drivers, MiniportCheckForHang can periodically check the state of the driver's virtual NIC to determine whether the underlying device driver appears to be hung.

By default, the NDIS library calls MiniportCheckForHang approximately every two seconds.

If MiniportCheckForHang returns TRUE, NDIS then calls the driver's MiniportReset function.

If a NIC driver has no MiniportCheckForHang function and NDIS judges the driver unresponsive as, for example, when NDIS holds many pending sends and requests queued to the miniport driver for a time-out interval, NDIS calls the driver's MiniportReset function. The NDIS library's default time-out interval for queued sends and requests is around four seconds. However, a NIC driver's MiniportInitialize function can extend NDIS's time-out interval by calling NdisMSetAttributesEx from MiniportInitialize to avoid unnecessary resets.

The MiniportInitialize function of an intermediate driver should disable NDIS's time-out interval with NdisMSetAttributesEx because such a driver can neither control nor estimate a reasonable completion interval for the underlying device driver.

MiniportCheckForHang can be pre-empted by an interrupt.

MiniportCheckForHang runs at IRQL DISPATCH_LEVEL.

See Also

MiniportInitialize, MiniportReset, NdisMSetAttributesEx


MiniportCoActivateVc function

Previous Next

MiniportCoActivateVc

The MiniportCoActivateVc function is required for connection-oriented miniports. MiniportCoActivateVc is called by NDIS to indicate to the miniport driver that a virtual connection is being activated.

NDIS_STATUS
  MiniportCoActivateVc(
    IN NDIS_HANDLE  MiniportVcContext,
    IN OUT PCO_CALL_PARAMETERS  CallParameters
    );

Parameters

MiniportVcContext
Specifies the handle to a miniport driver-allocated context area in which the miniport driver maintains its per-VC state. The miniport driver supplied this handle to NDIS from its MiniportCoCreateVc function.
CallParameters
Specifies the call parameters, as specified by the call manager, to be established for this VC. On output, the miniport driver returns altered call parameters if certain flags are set in the CO_CALL_PARAMETERS structure.

Return Value

NDIS_STATUS_SUCCESS
Indicates that the VC was activated successfully.
NDIS_STATUS_PENDING
Indicates that the miniport driver will complete the request to activate a VC asynchronously. When the miniport driver has finished with its operations, it must call NdisMCoActivateVcComplete.
NDIS_STATUS_INVALID_DATA
Indicates that the call parameters specified at CallParameters are invalid or illegal for the media type that this miniport driver supports.
NDIS_STATUS_RESOURCES
Indicates that the miniport driver could not activate the VC because it could not allocate all of the required resources that the miniport driver needs to maintain state information about the active VC.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The miniport driver must validate the call parameters for this VC, as specified in CallParameters, to verify that the adapter can support the requested call. If the requested call parameters cannot be satisfied, the miniport driver should fail the request with NDIS_STATUS_INVALID_DATA.

MiniportCoActivateVc can be called many times for a single VC in order to change the call parameters for an already active call. At every call, the miniport driver should validate the parameters and perform any processing as required by its adapter in order to satisfy the request. However, if it cannot set the given call parameters, MiniportCoActivateVc must leave the VC in a usable state, because the connection-oriented client or a call manager can continue to send or receive data using the older call parameters.

If the ROUND_UP_FLOW or ROUND_DOWN_FLOW flags are set in the call parameters structure at CallParameters->MediaParameters->Flags, the miniport driver has been requested to return the actual flow rate of the VC after the flow rate has been rounded according to the appropriate flag that has been set. If the miniport driver does change any of the call parameters because these flags have been set, it must return the actual call parameters in use for the VC at CallParameters.

If the call parameters are acceptable, MiniportCoActivateVc communicates with its adapter as necessary to prepare the adapter to receive or transmit data across the virtual connection (in other words, programming receive buffers).

MiniportCoActivateVc must be written so that it can be run from IRQL <= DISPATCH_LEVEL.

See Also

MiniportCoCreateVc, MiniportCoDeactivateVc, NdisMCoActivateVcComplete


MiniportCoCreateVc

The MiniportCoCreateVc function is required for connection-oriented miniports. MiniportCoCreateVc is called by NDIS to indicate to the miniport driver that a new VC is being created.

NDIS_STATUS
  MiniportCoCreateVc(
    IN NDIS_HANDLE  MiniportAdapterContext,
    IN NDIS_HANDLE  NdisVcHandle,
    OUT PNDIS_HANDLE  MiniportVcContext
    );

Parameters

MiniportAdapterContext
Specifies the handle to a miniport driver-allocated context area in which the miniport driver maintains state information about this instance of the adapter. The miniport driver provided this handle to NDIS by calling NdisMSetAttributes or NdisMSetAttributesEx from its MiniportInitialize function.
NdisVcHandle
Specifies a handle, supplied by NDIS, that uniquely identifies the VC being created. This handle is opaque to the miniport driver and reserved for NDIS library use.
MiniportVcContext
Specifies, on output, a handle to a miniport driver-supplied context area in which the miniport driver maintains state about the VC.

Return Value

NDIS_STATUS_SUCCESS
Indicates that the miniport driver successfully allocated all necessary resources and prepared itself for handling requests for the newly created VC.
NDIS_STATUS_RESOURCES
Indicates that the call manager could not obtain dynamically allocated resources necessary for it to operate on the new VC.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

MiniportCoCreateVc must be written as a synchronous function and cannot, under any circumstances, return NDIS_STATUS_PENDING without causing a system-wide failure.

MiniportCoCreateVc allocates any necessary resources that the miniport driver requires to maintain state information about the VC. The resources could include, but are not limited to memory buffers, events, data structures, and other such similar resources.

After allocating all required resources the miniport driver should initialize the resources into a usable state and return a pointer to the state area in MiniportVcContext. The handle is set by dereferencing the handle and storing a pointer to the state buffer as the value of the handle. For example:

*MiniportVcContext = SomeBuffer ;

Miniport drivers must store the handle to the VC, NdisVcHandle, in their state area as it is a required parameter to other NDIS library routines that are subsequently called by the miniport driver.

MiniportCoCreateVc must be written such that it can be run at IRQL DISPATCH_LEVEL.

See Also

MiniportInitialize, NdisMSetAttributes, NdisMSetAttributesEx


MiniportCoDeactivateVc

The MiniportCoDeactivateVc function is required for connection-oriented miniports. MiniportCoDeactivateVc is called by NDIS to indicate that a VC is being marked as unusable.

NDIS_STATUS
  MiniportCoDeactivateVc(
    IN NDIS_HANDLE  MiniportVcContext
    );

Parameter

MiniportVcContext
Specified the handle to a miniport driver-allocated context area in which the miniport driver maintains state information per-VC. The miniport driver supplied this handle to NDIS from its MiniportCoCreateVc function.

Return Value

NDIS_STATUS_SUCCESS
Indicates that the miniport driver successfully halted any communication across the VC and marked it as unusable.
NDIS_STATUS_PENDING
Indicates that the miniport driver will complete the request to halt the VC asynchronously. When the miniport driver has completed halting the VC, it must then call NdisMCoDeactivateVcComplete to signal NDIS that this operation has been completed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

MiniportCoDeactivateVc communicates with its network adapter to terminate all communication across this VC (in other words, deprogramming receive or send buffers on the adapter). The miniport driver should also mark the VC, it its context area, as being inactive to prevent any further communication across the VC.

There is not a one-to-one relationship between calls to MiniportCoActivateVc and MiniportCoDeactivateVc. While NDIS may call MiniportCoActivateVc multiple times on a single VC, only one call to MiniportCoDeactivateVc is made to shut down a virtual connection. For example, a VC can be reused for different calls possibly causing multiple calls to MiniportCoActivateVc.

See Also

MiniportCoActivateVc, NdisMCoDeactivateVcComplete


MiniportCoDeleteVc

The MiniportCoDeleteVc function is required for connection-oriented miniports. MiniportCoDeleteVc indicates that a VC is being torn down and deleted by NDIS.

NDIS_STATUS
  MiniportCoDeleteVc(
    IN NDIS_HANDLE  MiniportVcContext
    );

Parameter

MiniportVcContext
Specifies the handle to a miniport driver-allocated context area in which the miniport driver maintains its per-VC state. The miniport driver supplied this handle to NDIS from its MiniportCoCreateVc function.

Return Value

NDIS_STATUS_SUCCESS
Indicates that the miniport driver successfully freed all resources allocated for this VC.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

MiniportCoDeleteVc must be written as a synchronous function and cannot, under any circumstances, return NDIS_STATUS_PENDING without causing a system-wide failure.

MiniportCoDeleteVc frees any resources allocated on a per-VC basis and stored in the context area MiniportVcContext. The miniport driver must also free the MiniportVcContext that is allocated in its MiniportCoCreateVc function.

MiniportCoDeleteVc must be written such that it can be run from IRQL DISPATCH_LEVEL.

See Also

MiniportCoCreateVc


MiniportCoRequest

The MiniportCoRequest function is required for connection-oriented miniports. MiniportCoRequest handles a protocol-initiated request to get or set information from the miniport driver.

NDIS_STATUS
  MiniportCoRequest(
    IN NDIS_HANDLE  MiniportAdapterContext,
    IN NDIS_HANDLE  MiniportVcContext OPTIONAL,
    IN OUT PNDIS_REQUEST  NdisRequest
    );

Parameters

MiniportAdapterContext
Specifies the handle to a miniport driver-allocated context area in which the miniport driver maintains state information about this instance of the adapter. The miniport driver provided this handle to NDIS by calling NdisMSetAttributes or NdisMSetAttributesEx from its MiniportInitialize function.
MiniportVcContext
Specifies the handle to a miniport driver-allocated context area in which the miniport driver maintains its per-VC state. The miniport driver supplied this handle to NDIS from its MiniportCoCreateVc function.
NdisRequest
Pointer to a NDIS_REQUEST structure that contains both the buffer and the request packet for the miniport driver to handle. Depending on the request, the miniport driver returns requested information in the structure provided.

Return Value

NDIS_STATUS_SUCCESS
Indicates that the miniport driver has either set or obtained the data as requested.
NDIS_STATUS_PENDING
Indicates that the miniport driver will complete the request asynchronously. Once the miniport driver has completed all processing it must call NdisMCoRequestComplete to signal NDIS that the request is complete.
NDIS_STATUS_INVALID_OID
Indicates that the request, specified at NdisRequest, is invalid or not recognized.
NDIS_STATUS_NOT_SUPPORTED
Indicates that the request, specified at NdisRequest, is recognized, but not supported by the miniport driver.
NDIS_STATUS_INVALID_LENGTH
Indicates that the buffer, supplied at NdisRequest, is of an insufficient size to hold the data requested.
NDIS_STATUS_INVALID_DATA
Indicates that one or more of the parameters specified for the request at NdisRequest is invalid.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NDIS calls the MiniportCoRequest function either on its own behalf or on behalf of a bound protocol driver that called NdisCoRequest. Miniport drivers should examine the request supplied at NdisRequest and take the action requested. For more information about the required and optional OID_GEN_CO_XXX that connection-oriented miniport drivers must handle, see General Objects.

MiniportCoRequest must be written such that it can be run from IRQL DISPATCH_LEVEL.

See Also

MiniportCoCreateVc, MiniportInitialize, NdisCoRequest, NdisMCoRequestComplete, NdisMSetAttributes, NdisMSetAttributesEx


MiniportCoSendPackets

The MiniportCoSendPackets is required for connection-oriented miniports. MiniportCoSendPackets is called to transfer some number of packets, specified as an array of pointers, over the network.

VOID
  MiniportCoSendPackets(
    IN NDIS_HANDLE  MiniportVcContext,
    IN PPNDIS_PACKET  PacketArray,
    IN UINT  NumberOfPackets
    );

Parameters

MiniportVcContext
Specifies the handle to a miniport driver-allocated context area in which the miniport driver maintains its per-VC state. The miniport driver supplied this handle to NDIS from its MiniportCoCreateVc function.
PacketArray
Pointer to the initial element in a packet array, with each element specifying the address of a packet descriptor for a packet to be transmitted, along with an associated out-of-band data block containing information such as the packet priority, an optional timestamp, and the per-packet status to be set by MiniportCoSendPackets.
NumberOfPackets
Specifies the number of pointers to packet descriptors at PacketArray.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

MiniportCoSendPackets is called by NDIS in response to a request by a bound protocol driver to send a ordered list of data packets across the network.

MiniportCoSendPackets should transmit each packet in any given array sequentially. MiniportCoSendPackets can call NdisQueryPacket to extract information, such as the number of buffer descriptors chained to the packet and the total size in bytes of the requested transfer. It can call NdisGetFirstBufferFromPacket(Safe), NdisQueryBuffer(Safe), or NdisQueryBufferOffset to extract information about individual buffers containing the data to be transmitted.

MiniportCoSendPackets can retrieve protocol-supplied out-of-band information associated with each packet by using the appropriate NDIS_GET_PACKET_XXX macros.

MiniportCoSendPackets can use only the eight-byte area at MiniportReserved within the NDIS_PACKET structure for its own purposes.

The NDIS library ignores the OOB block in all packet descriptors it submits to MiniportCoSendPackets and assumes that every connection-oriented miniport driver is a deserialized driver that will complete each input packet descriptor asynchronously with NdisMCoSendComplete. Consequently, such a deserialized driver's MiniportCoSendPackets function usually ignores the Status member of the NDIS_PACKET_OOB_DATA block, but it can set this member to the same status as it subsequently passes to NdisMCoSendComplete.

Rather than relying on NDIS to queue and resubmit send packets whenever MiniportCoSendPackets has insufficient resources to transmit the given packets, a deserialized miniport driver manages its own internal packet queuing. Such a driver is responsible for holding incoming send packets in its internal queue until they can be transmitted over the network and for preserving the protocol-determined ordering of packet descriptors incoming to its MiniportCoSendPackets function. A deserialized miniport driver must complete each incoming send packet with NdisMCoSendComplete, and it cannot call NdisMSendResourcesAvailable.

A deserialized miniport driver should never pass STATUS_INSUFFICIENT_RESOURCES to NdisMCoSendComplete with a protocol-allocated packet descriptor that was originally submitted to its MiniportCoSendPackets function. Such a returned status effectively fails the send operation requested by the protocol, and NDIS would return the packet descriptor and all associated resources to the protocol that originally allocated it.

MiniportCoSendPackets can be called at any IRQL <= DISPATCH_LEVEL. Consequently, MiniportCoSendPackets function is responsible for synchronizing access to its internal queue(s) of packet descriptors with the driver's other MiniportXxx functions that also access the same queue(s).

See Also

MiniportCoCreateVc, MiniportCoRequest, MiniportInitialize, NdisAllocatePacket, NdisCoSendPackets, NdisGetBufferPhysicalArraySize, NdisGetFirstBufferFromPacket, NdisGetFirstBufferFromPacketSafe, NdisGetNextBuffer, NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO, NDIS_GET_PACKET_TIME_TO_SEND, NdisMCoSendComplete, NdisMoveMemory, NdisMoveToMappedMemory, NdisMSendResourcesAvailable, NdisMSetupDmaTransfer, NdisMStartBufferPhysicalMapping, NDIS_OOB_DATA_FROM_PACKET, NDIS_PACKET, NDIS_PACKET_OOB_DATA, NdisQueryBuffer, NdisQueryBufferOffset, NdisQueryBufferSafe, NdisQueryPacket, NdisZeroMemory


MiniportDisableInterrupt

The MiniportDisableInterrupt function is optional, supplied by drivers of NICs that support dynamic enabling and disabling of interrupts but do not share an IRQ.

VOID
  MiniportDisableInterrupt(
    IN NDIS_HANDLE  MiniportAdapterContext
    );

Parameters

MiniportAdapterContext
Specifies the handle to a miniport driver-allocated context area in which the driver maintains per-NIC state, set up by MiniportInitialize.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

MiniportDisableInterrupt typically disables interrupts by writing a mask to the NIC. If a driver does not have this function, typically its MiniportISR disables interrupts on the NIC.

If its NIC does not support dynamic enabling and disabling of interrupts or if it shares an IRQ, the NIC driver must register a MiniportISR function and set RequestIsr to TRUE when it calls NdisMRegisterMiniport. Such a driver's MiniportISR function must acknowledge each interrupt generated by the NIC and save any necessary interrupt information for the driver's MiniportHandleInterrupt function.

MiniportDisableInterrupt runs at DIRQL, in particular at the DIRQL assigned when the NIC driver's MiniportInitialize function called NdisMRegisterInterrupt. Therefore, MiniportDisableInterrupt can call only a subset of the NDIS library functions, such as the NdisRaw Xxx functions that are safe to call at any IRQL.

If MiniportDisableInterrupt shares resources, such as NIC registers, with another MiniportXxx that runs at a lower IRQL, that MiniportXxx must call NdisMSychronizeWithInterrupt so the driver's MiniportSynchronizeISR function will access those shared resources in a synchronized and multiprocessor-safe manner. Otherwise, while it is accessing the shared resources, that MiniportXxx function can be pre-empted by MiniportDisableInterrupt, possibly undoing the work just done by MiniportXxx.

See Also

MiniportEnableInterrupt, MiniportHandleInterrupt, MiniportInitialize, MiniportISR, MiniportSynchronizeISR, NdisMRegisterInterrupt, NdisMSynchronizeWithInterrupt


MiniportEnableInterrupt

The MiniportEnableInterrupt function is optional, supplied by some drivers of NICs that support dynamic enabling and disabling of interrupts but do not share an IRQ.

VOID
  MiniportEnableInterrupt(
    IN NDIS_HANDLE  MiniportAdapterContext
    );

Parameters

MiniportAdapterContext
Specifies the handle to a miniport driver-allocated context area in which the driver maintains per-NIC state, set up by MiniportInitialize.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

MiniportEnableInterrupt typically enables interrupts by writing a mask to the NIC.

A NIC driver that exports a MiniportDisableInterrupt function need not have a reciprocal MiniportEnableInterrupt function. Such a driver's MiniportHandleInterrupt function is responsible for re-enabling interrupts on the NIC.

If its NIC does not support dynamic enabling and disabling of interrupts or if it shares an IRQ, the NIC driver must register a MiniportISR function and set RequestIsr to TRUE when it calls NdisMRegisterMiniport. Such a driver's MiniportISR function must acknowledge each interrupt generated by the NIC and save any necessary interrupt information for the driver's MiniportHandleInterrupt function.

MiniportEnableInterrupt can be pre-empted by an interrupt.

MiniportEnableInterrupt runs at IRQL DISPATCH_LEVEL.

See Also

MiniportDisableInterrupt, MiniportHandleInterrupt, MiniportInitialize, MiniportISR, NdisMRegisterInterrupt


MiniportHalt

The MiniportHalt function is a required function that deallocates resources when the NIC is removed and halts the NIC.

VOID
  MiniportHalt(
    IN NDIS_HANDLE  MiniportAdapterContext
    );

Parameters

MiniportAdapterContext
Specifies the handle to a miniport driver-allocated context area in which the driver maintains per-NIC state, set up by MiniportInitialize.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

MiniportHalt should stop the NIC, if it controls a physical NIC, and must free all resources that the driver allocated for its NIC before MiniportHalt returns control. In effect, MiniportHalt undoes everything that was done by MiniportInitialize for a particular NIC.

If the NIC driver allocated memory, claimed an I/O port range, mapped on-board device memory to host memory, initialized timer(s) and/or spin lock(s), allocated map registers or claimed a DMA channel, and registered an interrupt, that driver must call the reciprocals of the Ndis Xxx functions with which it originally allocated these resources.

As a general rule, a MiniportHalt function should call reciprocal Ndis Xxx functions in inverse order to the calls the driver made from MiniportInitialize. That is, if a NIC driver's MiniportInitialize function called NdisMRegisterAdapterShutdownHandler just before it returned control, its MiniportHalt function would call NdisMDeregisterAdapterShutdownHandler first.

If its NIC generates interrupts, a NIC driver's MiniportHalt function can be pre-empted by the driver's MiniportISR or MiniportHandleInterrupt function until MiniportHalt's call to NdisMDeregisterInterrupt returns. Such a driver's MiniportHalt function usually disables interrupts on the NIC, and calls NdisMDeregisterInterrupt as soon as it can. Note that a miniport driver can keep getting interrupts until NdisMDeregisterInterrupt returns.

If the driver has a MiniportTimer function associated with any timer object that might be in the system timer queue, MiniportHalt should call NdisMCancelTimer. If NdisMCancelTimer fails, the driver should wait for the timer to fire before returning from MiniportHalt.

Otherwise, it is unnecessary for the miniport driver to complete outstanding requests to its NIC before MiniportHalt begins releasing allocated resources. NDIS submits no further requests to the miniport driver for the NIC designated by the MiniportAdapterContext handle when NDIS has called MiniportHalt.

If the miniport driver has any outstanding receive packets (packets that it has indicated up to NDIS but which NDIS has not yet returned), the miniport driver must not return from its MiniportHalt function until such packets are returned to the miniport driver's MiniportReturnPacket function.

An NDIS intermediate driver's call to NdisIMDeinitializeDeviceInstance causes a call to its MiniportHalt function.

MiniportHalt runs at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, MiniportReturnPacket, MiniportShutdown, NdisFreeMemory, NdisFreeSpinLock, NdisIMDeinitializeDeviceInstance, NdisMCancelTimer, NdisMDeregisterAdapterShutdownHandler, NdisMDeregisterDmaChannel, NdisMDeregisterInterrupt, NdisMDeregisterIoPortRange, NdisMFreeMapRegisters, NdisMFreeSharedMemory, NdisMUnmapIoSpace, ProtocolUnbindAdapter


MiniportHandleInterrupt

The MiniportHandleInterrupt function is required if a driver's NIC generates interrupts. MiniportHandleInterrupt does the deferred processing of all outstanding interrupt operations.

VOID
  MiniportHandleInterrupt(
    IN NDIS_HANDLE  MiniportAdapterContext
    );

Parameters

MiniportAdapterContext
Specifies the handle to a miniport driver-allocated context area in which the driver maintains per-NIC state, set up by MiniportInitialize.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

When a NIC generates an interrupt, a miniport's MiniportISR or MiniportDisableInterrupt function dismisses the interrupt on the NIC, saves any necessary state about the operation, and returns control as quickly as possible, thereby deferring most interrupt-driven I/O operations to MiniportHandleInterrupt. MiniportHandleInterrupt does the deferred processing of all outstanding interrupt operations.

If the NIC shares an IRQ, MiniportHandleInterrupt is called only if the MiniportISR function returned QueueMiniportHandleInterrupt set to TRUE.

When MiniportHandleInterrupt is called, interrupts have typically been disabled on the NIC by the MiniportISR or MiniportDisableInterrupt function. Before it returns control, MiniportHandleInterrupt can re-enable interrupts on the NIC.

For more information about operations that a miniport driver's MiniportHandleInterrupt function typically performs and for details on how to perform those operations, see DPC Handler.

A miniport driver can call NdisMDeregisterMiniport from its MiniportInitialize or MiniportHalt function to release resources that it allocated with NdisMRegisterInterrupt. After NdisMDeregisterMiniport returns, NDIS does not call a miniport driver's MiniportISR or MiniportHandleInterrupt functions.

MiniportHandleInterrupt runs at IRQL DISPATCH_LEVEL.

See Also

MiniportDisableInterrupt, MiniportEnableInterrupt, MiniportInitialize, MiniportISR, MiniportSend, MiniportSendPackets, MiniportWanSend, NdisAdjustBufferLength, NdisAllocateBuffer, NdisAllocateMemory, NdisAllocatePacket, NdisMArcIndicateReceive, NdisMDeregisterInterrupt, NdisMEthIndicateReceive, NdisMFddiIndicateReceive, NdisMIndicateReceivePacket, NdisMRegisterInterrupt, NdisMSynchronizeWithInterrupt, NdisMTrIndicateReceive, NdisMWanIndicateReceive, NDIS_PACKET, NDIS_PACKET_OOB_DATA


MiniportInitialize

The MiniportInitialize function is a required function that sets up a NIC (or virtual NIC) for network I/O operations, claims all hardware resources necessary to the NIC in the registry, and allocates resources the driver needs to carry out network I/O operations.

NDIS_STATUS
  MiniportInitialize(
    OUT PNDIS_STATUS  OpenErrorStatus,
    OUT PUINT  SelectedMediumIndex,
    IN PNDIS_MEDIUM  MediumArray,
    IN UINT  MediumArraySize,
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN NDIS_HANDLE  WrapperConfigurationContext
    );

Parameters

OpenErrorStatus
Pointer to a variable that MiniportInitialize sets to an NDIS_STATUS_XXX code specifying additional information about the error if MiniportInitialize will return NDIS_STATUS_OPEN_ERROR.
SelectedMediumIndex
Pointer to a variable in which MiniportInitialize sets the index of the MediumArray element that specifies the medium type the driver or its NIC uses.
MediumArray
Specifies an array of NdisMedium Xxx values from which MiniportInitialize selects one that its NIC supports or that the driver supports as an interface to higher-level drivers.
MediumArraySize
Specifies the number of elements at MediumArray.
MiniportAdapterHandle
Specifies a handle identifying the miniport's NIC, which is assigned by the NDIS library. MiniportInitialize should save this handle; it is a required parameter in subsequent calls to Ndis Xxx functions.
WrapperConfigurationContext
Specifies a handle used only during initialization for calls to Ndis Xxx configuration and initialization functions. For example, this handle is a required parameter to NdisOpenConfiguration and the NdisImmediateRead Xxx and NdisImmediateWrite Xxx functions.

Return Value

MiniportInitialize can return either of the following:

NDIS_STATUS_SUCCESS
MiniportInitialize configured and set up the NIC, and it allocated all the resources the driver needs to carry out network I/O operations.
NDIS_STATUS_FAILURE
MiniportInitialize could not set up the NIC to an operational state or could not allocate needed resources. MiniportInitialize called NdisWriteErrorLogEntry with parameters specifying the configuration or resource allocation failure.

As alternatives to NDIS_STATUS_FAILURE, MiniportInitialize can return one of the following values, as appropriate, when it fails an initialization:

NDIS_STATUS_UNSUPPORTED_MEDIA
The values at MediumArray did not include a medium the driver (or its NIC) can support.
NDIS_STATUS_ADAPTER_NOT_FOUND
MiniportInitialize did not recognize the NIC either from its description in the registry, using NdisOpenConfiguration and NdisReadConfiguration, or by probing the NIC on a particular I/O bus, using one of the NdisImmediate Xxx or bus-type-specific Ndis Xxx configuration functions. This return can be propagated from the miniport's call to certain Ndis Xxx functions, such as NdisOpenConfiguration.
NDIS_STATUS_OPEN_ERROR
MiniportInitialize attempted to set up a NIC but was unsuccessful.
NDIS_STATUS_NOT_ACCEPTED
MiniportInitialize could not get its NIC to accept the configuration parameters that it got from the registry or from a bus-type-specific Ndis Xxx configuration function.
NDIS_STATUS_RESOURCES
Either MiniportInitialize could not allocate sufficient resources to carry out network I/O operations or an attempt to claim bus-relative hardware resources in the registry for the NIC failed. This return can be propagated from the miniport's call to an Ndis Xxx function.

If another device has already claimed a resource in the registry that its NIC needs, MiniportInitialize also should call NdisWriteErrorLogEntry to record the particular resource conflict (I/O port range, interrupt vector, device memory range, as appropriate). Supplying an error log record gives the user or system administrator information that can be used to reconfigure the machine to avoid such hardware resource conflicts.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NDIS submits no requests to a driver until its initialization is completed.

In NIC and intermediate drivers that call NdisMRegisterMiniport from their DriverEntry functions, NDIS calls MiniportInitialize in the context of NdisMRegisterMiniport. The underlying device driver must initialize before an intermediate driver that depends on that device calls NdisMRegisterMiniport.

For NDIS intermediate drivers that export both ProtocolXxx and MiniportXxx functions and that call NdisIMRegisterLayeredMiniport from their DriverEntry functions, NDIS calls MiniportInitialize in the context of NdisIMInitializeDeviceInstance. Such a driver's ProtocolBindAdapter function usually makes the call to NdisIMInitializeDeviceInstance.

For NIC drivers, NDIS must find at least the NIC's I/O bus interface type and, if it is not an ISA bus, the bus number already installed in the registry by the driver's installation script. For more information about installing drivers created for Windows 2000 and later operating systems, see the Driver Writer's Guide.

The NIC driver obtains configuration information for its NIC by calling NdisOpenConfiguration and NdisReadConfiguration. The NIC driver obtains bus-specific information by calling the appropriate bus-specific function:

Bus | Function for Obtaining Bus-Specific Information
EISA | NdisReadEisaSlotInformation or NdisReadEisaSlotInformationEx
PCI | NdisReadPciSlotInformation
PC Card | NdisReadPcmciaAttributeMemory

The NIC driver for an EISA NIC obtains information on the hardware resources for its NIC by calling NdisReadEisaSlotInformation or NdisReadEisaSlotInformationEx. NIC drivers for PCI NICs and PC Card NICs obtain such information by calling NdisMQueryAdapterResources.

When it calls MiniportInitialize, the NDIS library supplies an array of supported media types, specified as system-defined NdisMedium Xxx values. MiniportInitialize reads the array elements and provides the index of the medium type that NDIS should use with this driver for its NIC. If the miniport driver is emulating a medium type, its emulation must be transparent to NDIS.

The MiniportInitialize function of a NIC driver must call NdisMSetAttributes or NdisMSetAttributesEx before it calls any Ndis Xxx function, such as NdisRegisterIoPortRange or NdisMMapIoSpace, that claims hardware resources in the registry for the NIC. MiniportInitialize must call NdisMSetAttributes(Ex) before it attempts to allocate resources for DMA operations as well. If the NIC is a bus master, MiniportInitialize must call NdisMAllocateMapRegisters following its call to NdisMSetAttributes(Ex) and before it calls NdisMAllocateSharedMemory. If the NIC is a slave, MiniportInitialize must call NdisMSetAttributes(Ex) before it calls NdisMRegisterDmaChannel.

Intermediate driver MiniportInitialize functions must call NdisMSetAttributesEx with NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER set in the AttributeFlags argument. Setting this flag causes NDIS to treat every intermediate driver as a full-duplex miniport driver, thereby preventing rare but intermittent deadlocks when concurrent send and receive events occur. Consequently, every intermediate driver must be written as a full-duplex driver capable of handling concurrent sends and indications. Every intermediate driver also should call NdisMSetAttributesEx with NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT and NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT set in the AttributeFlags so that NDIS will not attempt to time out sends and requests that NDIS holds queued to the intermediate driver.

An intermediate driver must operate as a deserialized driver and must register itself as such by setting the NDIS_ATTRIBUTE_DESERIALIZE flag in the AttributeFlags parameter passed to NdisMSetAttributesEx. A deserialized driver serializes the operation of its MiniportXxx functions and queues internally all incoming send packets rather than relying on NDIS to maintain its send queue.

An intermediate driver must also set the NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND flag in the AttributeFlags parameter passed to NdisMSetAttributesEx. Setting this flag prevents NDIS from halting the driver before the underlying miniport transitions to a low-power state.

If the NDIS library's default four-second time-out interval on outstanding sends and requests is too short for the driver's NIC, MiniportInitialize can call NdisMSetAttributesEx to extend the interval.

The call to NdisMSetAttributes or NdisMSetAttributesEx includes a MiniportAdapterContext handle to a driver-allocated context area, in which the miniport driver maintains run-time state information. NDIS subsequently passes the supplied MiniportAdapterContext handle as an input parameter to other MiniportXxx functions.

Consequently, the MiniportInitialize function of an intermediate driver must call NdisMSetAttributesEx to set up the MiniportAdapterContext handle for a driver-allocated per-virtual-NIC context area. Otherwise, NDIS would pass a NULL MiniportAdapterContext handle in its subsequent calls to the intermediate driver's other MiniportXxx functions.

After a call to NdisMRegisterIoPortRange, a miniport driver must call the NdisRaw Xxx functions with the PortOffset value returned by NdisMRegisterIoPortRange to communicate with its NIC. The NIC driver can no longer call the NdisImmediateRead/WritePort Xxx functions. Similarly, after a call to NdisMMapIoSpace, a NIC driver can no longer call NdisImmediateRead/WriteSharedMemory.

After it has claimed any bus-relative hardware resources for its NIC in the registry, a miniport driver should no longer call any bus-type-specific NdisRead Xxx function.

After MiniportInitialize calls NdisMRegisterInterrupt, the driver's MiniportISR function is called if the driver's NIC generates an interrupt or if any other device with which the NIC shares an IRQ interrupts. NDIS does not call the MiniportDisableInterrupt and MiniportEnableInterrupt functions, if the driver supplied them, during initialization, so it is such a miniport's responsibility to acknowledge and clear any interrupts its NIC generates. If the NIC shares an IRQ, the driver must first determine whether its NIC generated the interrupt; if it did not, the miniport driver must return FALSE as soon as possible. Note that a miniport driver can get an interrupt as soon as it calls NdisMRegisterInterrupt and keep getting interrupts until its call to NdisMDeregisterInterrupt returns.

If the NIC does not generate interrupts, MiniportInitialize should call NdisMInitializeTimer with a driver-supplied polling MiniportTimer function and a pointer to driver-allocated memory for a timer object. Drivers of NICs that generate interrupts and intermediate drivers also can set up one or more MiniportTimer functions, each with its own timer object. MiniportInitialize usually calls NdisMSetPeriodicTimer to enable a polling MiniportTimer function; a driver calls NdisMSetTimer subsequently when conditions occur such that the driver's nonpolling MiniportTimer function should be run.

If the driver subsequently indicates receives with NdisMIndicateReceivePacket, the MiniportInitialize function should call NdisAllocatePacketPool and NdisAllocateBufferPool and save the handles returned by these NDIS functions. The packets that the driver subsequently indicates with NdisMIndicateReceivePacket must reference descriptors that were allocated with NdisAllocatePacket and NdisAllocateBuffer.

If driver functions other than MiniportISR or MiniportDisableInterrupt share resources, MiniportInitialize should call NdisAllocateSpinLock to set up any spin lock necessary to synchronize access to such a set of shared resources, particularly in a full-duplex driver or in a driver with a polling MiniportTimer function rather than an ISR. Resources shared by other driver functions with MiniportISR or MiniportDisableInterrupt, such as NIC registers, are protected by the interrupt object set up when MiniportInitialize calls NdisMRegisterInterrupt and accessed subsequently by calling NdisMSynchronizeWithInterrupt.

Any NIC driver's MiniportInitialize function should test the NIC to be sure the hardware is configured correctly to carry out subsequent network I/O operations. If it must wait for state changes to occur in the hardware, MiniportInitialize either can call NdisWaitEvent with the pointer to a driver-initialized event object, or it can call NdisMSleep.

Unless the MiniportInitialize function of a NIC driver will return an error status, it should call NdisMRegisterAdapterShutdownHandler with a driver-supplied MiniportShutdown function.

If MiniportInitialize will fail the initialization, it must release all resources it has already allocated before it returns control.

If MiniportInitialize returns NDIS_STATUS_OPEN_ERROR, NDIS can examine the value returned at OpenErrorStatus to obtain more information about the error.

When MiniportInitialize returns NDIS_STATUS_SUCCESS, the NDIS library calls the driver's MiniportQueryInformation function next.

MiniportInitialize runs at IRQL PASSIVE_LEVEL.

See Also

DriverEntry of NDIS Miniport Drivers, DriverEntry of NDIS Protocol Drivers, MiniportDisableInterrupt, MiniportEnableInterrupt, MiniportISR, MiniportQueryInformation, MiniportShutdown, MiniportTimer, NdisAllocateBuffer, NdisAllocateBufferPool, NdisAllocateMemory, NdisAllocatePacket, NdisAllocatePacketPool, NdisAllocateSpinLock, NdisAnsiStringToUnicodeString, NdisIMInitializeDeviceInstance, NdisImmediateReadPciSlotInformation, NdisImmediateReadPortUchar, NdisImmediateReadSharedMemory, NdisIMRegisterLayeredMiniport, NdisInitializeEvent, NdisMAllocateMapRegisters, NdisMAllocateSharedMemory, NdisMCreateLog, NdisMDeregisterInterrupt, NdisMIndicateReceivePacket, NdisMInitializeTimer, NdisMMapIoSpace, NdisMPciAssignResources, NdisMQueryAdapterResources, NdisMRegisterAdapterShutdownHandler, NdisMRegisterDmaChannel, NdisMRegisterInterrupt, NdisMRegisterIoPortRange, NdisMRegisterMiniport, NdisMSetAttributes, NdisMSetAttributesEx, NdisMSetPeriodicTimer, NdisMSetTimer, NdisMSleep, NdisOpenConfiguration, NdisRawReadPortBufferUchar, NdisRawReadPortBufferUlong, NdisRawReadPortBufferUshort, NdisRawReadPortUchar, NdisRawReadPortUlong, NdisRawReadPortUshort, NdisRawWritePortBufferUchar, NdisRawWritePortBufferUlong, NdisRawWritePortBufferUshort, NdisRawWritePortUchar, NdisRawWritePortUlong, NdisRawWritePortUshort, NdisReadConfiguration, NdisReadEisaSlotInformation, NdisReadEisaSlotInformationEx, NdisReadNetworkAddress, NdisReadPciSlotInformation, NdisReadPcmciaAttributeMemory, NdisReadRegisterUchar, NdisReadRegisterUlong, NdisReadRegisterUshort, NdisUnicodeStringToAnsiString, NdisWaitEvent, NdisWriteErrorLogEntry, NdisWriteRegisterUchar, NdisWriteRegisterUlong, NdisWriteRegisterUshort, ProtocolBindAdapter


MiniportISR

The MiniportISR function is required if the driver's NIC generates interrupts.

VOID
  MiniportISR(
    OUT PBOOLEAN  InterruptRecognized,
    OUT PBOOLEAN  QueueMiniportHandleInterrupt,
    IN NDIS_HANDLE  MiniportAdapterContext
    );

Parameters

InterruptRecognized
Pointer to a variable in which MiniportISR returns whether the NIC actually generated the interrupt. MiniportISR sets this to TRUE if it detects that the interrupt came from the NIC designated at MiniportAdapterContext.

If its NIC shares an IRQ with other devices on the same bus, MiniportISR should return FALSE as quickly as possible whenever it determines that the NIC did not interrupt.

QueueMiniportHandleInterrupt
Pointer to a variable that MiniportISR sets to TRUE if the MiniportHandleInterrupt function should be called to complete the interrupt-driven I/O operation.
MiniportAdapterContext
Specifies the handle to a miniport driver-allocated context area in which the driver maintains per-NIC state, set up by MiniportInitialize.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A NIC driver should do as little work as possible in its MiniportISR function, deferring I/O operations for each interrupt that the NIC generates to the MiniportHandleInterrupt function. A NIC driver's ISR is not re-entrant, although two instantiations of a MiniportISR function can execute concurrently in SMP machines, particularly if the miniport driver supports full-duplex sends and receives.

When an interrupt occurs on its NIC's bus, the miniport driver's Miniport ISR function is called under the following conditions:

  • The NIC shares an IRQ with other devices on that bus.

    If the NIC shares an IRQ with other devices, the Miniport ISR function must be called to determine whether the NIC generated the interrupt. If the NIC did not generated the interrupt, MiniportISR should return FALSE immediately so that the driver of the device that generated the interrupt is called quickly.

  • The miniport driver, in its call to NdisMRegisterInterrupt from MiniportInitialize, specified that its MiniportISR function should be called for every interrupt on the bus

    Miniports that do not provide MiniportDisable/EnableInterrupt functionality must have their ISRs called on every interrupt.

  • An interrupt occurs on the NIC while the driver's MiniportInitialize or MiniportHalt function is running.

    The MiniportISR function is always called in the case, regardless of whether the miniport's NIC shares an IRQ with another device or whether the miniport driver specified that its MiniportISR function should be called for every interrupt on the bus.

MiniportISR dismisses the interrupt on the NIC, saves whatever state it must about the interrupt, and defers as much of the I/O processing for each interrupt as possible to the MiniportHandleInterrupt function.

After MiniportISR returns control with the variables at InterruptRecognized and QueueMiniportHandleInterrupt set to TRUE, the corresponding MiniportHandleInterrupt function runs at a lower hardware priority (IRQL DISPATCH_LEVEL) than that of the ISR (DIRQL). As a general rule, MiniportHandleInterrupt should do all the work for interrupt-driven I/O operations except for determining whether the NIC actually generated the interrupt, and, if necessary, preserving the type (receive, send, reset...) of interrupt.

A driver writer should not rely on a one-to-one correspondence between the execution of MiniportISR and MiniportHandleInterrupt. A MiniportHandleInterrupt function should be written to handle the I/O processing for more than one NIC interrupt. Its MiniportISR and MiniportHandleInterrupt functions can run concurrently in SMP machines. Moreover, as soon as MiniportISR acknowledges a NIC interrupt, the NIC can generate another interrupt, while the MiniportHandleInterrupt DPC can be queued for execution once for such a sequence of interrupts.

If MiniportISR shares resources, such as NIC registers or state variables, with another MiniportXxx that runs at lower IRQL, that MiniportXxx must call NdisMSychronizeWithInterrupt so the driver's MiniportSynchronizeISR function will access those shared resources in a synchronized and multiprocessor-safe manner. Otherwise, while it is accessing the shared resources, that MiniportXxx function can be pre-empted by MiniportISR, possibly undoing the work just done by MiniportXxx.

A miniport driver can call NdisMDeregisterMiniport from its MiniportInitialize or MiniportHalt function to release resources that it allocated with NdisMRegisterInterrupt. After NdisMDeregisterMiniport returns, NDIS does not call a miniport driver's MiniportISR or MiniportHandleInterrupt functions.

MiniportISR runs at DIRQL, in particular at the DIRQL assigned when the driver initialized the interrupt object with NdisMRegisterInterrupt. Therefore, MiniportIsr can call only a subset of the NDIS library functions, such as the NdisRaw Xxx or NdisRead/WriteRegister Xxx functions that are safe to call at any IRQL.

See Also

MiniportDisableInterrupt, MiniportEnableInterrupt, MiniportHalt, MiniportHandleInterrupt, MiniportInitialize, MiniportSynchronizeISR, NdisMDeregisterInterrupt, NdisMRegisterInterrupt, NdisMSynchronizeWithInterrupt, NdisRawReadPortBufferUchar, NdisRawReadPortBufferUlong, NdisRawReadPortBufferUshort, NdisRawReadPortUchar, NdisRawReadPortUlong, NdisRawReadPortUshort, NdisRawWritePortBufferUchar, NdisRawWritePortBufferUlong, NdisRawWritePortBufferUshort, NdisRawWritePortUchar, NdisRawWritePortUlong, NdisRawWritePortUshort, NdisReadRegisterUchar, NdisReadRegisterUlong, NdisReadRegisterUshort, NdisWriteRegisterUchar, NdisWriteRegisterUlong, NdisWriteRegisterUshort


MiniportPnPEventNotify

The MiniportPnPEventNotify function handles the notification of Plug and Play (PnP) events.

VOID
  MiniportPnPEventNotify(
    IN NDIS_HANDLE  MiniportAdapterContext,
    IN NDIS_DEVICE_PNP_EVENT  PnPEvent,
    IN PVOID  InformationBuffer,
    IN ULONG  InformationBufferLength,
    );

Parameters

MiniportAdapterContext
Specifies the handle to a miniport-allocated context area in which the miniport driver maintains per-NIC state, set up by MiniportInitialize.
PnPEvent
An event code that describes the Plug and Play event as one of the following:
NdisDevicePnPEventSurpriseRemoved
Indicates that the specified adapter has been unexpectedly removed from the system.
NdisDevicePnPEventPowerProfileChanged
Indicates that the power profile of the host system has changed.
InformationBuffer
When PnPEvent is set to NdisDevicePnPEventPowerProfileChanged, InformationBuffer points to a ULONG variable that is set to either of the following values:
NdisPowerProfileBattery
Specifies that the host system is running on battery power.
NdisPowerProfileAcOnline
Specifies that the host system is running on AC power.

When PnPEvent is set to NdisDevicePnPEventSurpriseRemoved, InformationBuffer is NULL.

InformationBufferLength
Size, in bytes, of the buffer at InformationBuffer.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The following types of miniports should export a MiniportPnPEventNotify function:

  • Miniports that can adjust their NIC's power consumption based on the current power source for the system
  • Miniports that have a WDM lower edge

Note that all NDIS 5.1 miniports must export a MiniportPnPEventNotify function.

After initializing a miniport driver or after a miniport driver receives an OID_PNP_SET_POWER notification that specifies a device power state of NdisDeviceStateD0 (the powered-on state), NDIS calls the miniport's MiniportPnPEventNotify function with PnPEvent set to NdisDevicePnPEventPowerProfileChanged. InformationBuffer, in this case, points to a ULONG variable, the value of which indicates whether the system is running on battery power (NdisPowerProfileBattery) or AC power (NdisPowerProfileAcOnline). A miniport can use this information to adjust the power consumption of its NIC. For example, the miniport for a wireless LAN device could reduce power consumption if the system is running on battery power or increase power consumption if the system is running on AC power.

An NDIS miniport driver with a WDM lower edge should export a MiniportPnPEventNotify function so that it can be notified when its NIC is removed without prior notification through the user interface. If such a miniport driver does not export a MiniportPnPEventNotify function, any pending IRPs that the miniport driver sent to the underlying bus driver cannot be completed after the surprise removal of the device.

When a miniport driver receives notification of a surprise removal, it should note internally that the device has been removed and cancel any pending IRPs that it sent down to the underlying bus driver. After calling the MiniportPnPEventNotify function to indicate the surprise removal, NDIS calls the miniport's MiniportHalt function. If the miniport driver receives any requests to send packets or query or set OIDs before its MiniportHalt function is called, it should immediately complete such requests with a status value of NDIS_STATUS_NOT_ACCEPTED.

System support for MiniportPnPEventNotify is available in Windows XP and later operating systems.

MiniportPnPEventNotify runs synchronously at IRQL PASSIVE_LEVEL and in the context of a system thread.


MiniportQueryInformation

The MiniportQueryInformation function is a required function that returns information about the capabilities and status of the driver and/or its NIC.

NDIS_STATUS
  MiniportQueryInformation(
    IN NDIS_HANDLE  MiniportAdapterContext,
    IN NDIS_OID  Oid,
    IN PVOID  InformationBuffer,
    IN ULONG  InformationBufferLength,
    OUT PULONG  BytesWritten,
    OUT PULONG  BytesNeeded
    );

Parameters

MiniportAdapterContext
Specifies the handle to a miniport driver-allocated context area in which the driver maintains per-NIC state, set up by MiniportInitialize.
Oid
Specifies the system-defined OID_XXX code designating the global query operation the driver should carry out.
InformationBuffer
Pointer to a buffer in which MiniportQueryInformation should return the OID-specific information.
InformationBufferLength
Specifies the number of bytes at InformationBuffer.
BytesWritten
Pointer to a variable that MiniportQueryInformation sets to the number of bytes it is returning at InformationBuffer.
BytesNeeded
Pointer to a variable that MiniportQueryInformation sets to the total number of bytes it needs to satisfy the request if InformationBufferLength is less than Oid requires.

Return Value

MiniportQueryInformation can return one of the following:

NDIS_STATUS_SUCCESS
MiniportQueryInformation returned the requested information at InformationBuffer and set the variable at BytesWritten to the amount of information it returned.
NDIS_STATUS_PENDING
The driver will complete the request asynchronously with a call to NdisMQueryInformationComplete when it has gathered the requested information.
NDIS_STATUS_INVALID_OID
MiniportQueryInformation does not recognize the Oid.
NDIS_STATUS_INVALID_LENGTH
The InformationBufferLength does not match the length required by the given Oid. MiniportQueryInformation returned how many bytes the buffer should be at BytesNeeded.
NDIS_STATUS_NOT_ACCEPTED
MiniportQueryInformation attempted to gather the requested information from the NIC but was unsuccessful.
NDIS_STATUS_NOT_SUPPORTED
MiniportQueryInformation does not support the Oid, which is optional.
NDIS_STATUS_RESOURCES
MiniportQueryInformation could not allocate sufficient resources to return the requested information. This return value does not necessarily mean that the same request, submitted at a later time, will be failed for the same reason.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NDIS calls the MiniportQueryInformation function either on its own behalf, such as to determine which options the driver supports or to manage binding-specific information for the miniport driver, or when a bound protocol driver calls NdisRequest.

NDIS makes one or more calls to MiniportQueryInformation just after a driver's MiniportInitialize function returns NDIS_STATUS_SUCCESS. NDIS supplies the following OIDs in its initialization-time calls to the driver's MiniportQueryInformation function:

OID_GEN_MAXIMUM_LOOKAHEAD
MiniportQueryInformation must return how many bytes of lookahead data the NIC can provide, that is, the initial transfer capacity of the NIC.

Even if a driver supports multipacket receives and, therefore, will indicate an array of pointers to fully set up packets, MiniportQueryInformation must supply this information. Such a driver should return the maximum packet size it can indicate.

OID_GEN_MAC_OPTIONS
MiniportQueryInformation must return a bitmask set with the appropriate NDIS_MAC_OPTION_XXX flags indicating which options it (or its NIC) supports, or it can return zero at InformationBuffer if the driver supports none of the options designated by these flags.

For example, a NIC driver always sets the NDIS_MAC_OPTION_NO_LOOPBACK flag if its NIC has no internal hardware support for loopback. This tells NDIS to manage loopback for the driver, which cannot provide software loopback code as efficient as the NDIS library's because NDIS manages all binding-specific information for miniports. Any miniport driver that tries to provide software loopback must check the destination address of every send packet against the currently set filter addresses to determine whether to loop back each packet. WAN NIC drivers must set this flag.

If the NIC driver sets the NDIS_MAC_OPTION_FULL_DUPLEX flag, the NDIS library serializes calls to the MiniportSendPackets or Miniport(Wan)Send function separately from its serialized calls to other MiniportXxx functions in SMP machines. However, NDIS returns incoming send packets to protocols while such a driver's MiniportReset function is executing: that is, NDIS never calls a full-duplex miniport driver to transmit a packet until its reset operation is completed. The designer of any full-duplex driver can expect that driver to achieve significantly higher performance in SMP machines, but the driver must synchronize its accesses to shared resources carefully to prevent race conditions or deadlocks from occurring. NDIS assumes that all intermediate drivers are full-duplex drivers.

Depending on the NdisMedium Xxx that MiniportInitialize selected, NDIS submits additional intialization-time requests to MiniportQueryInformation, such as the following:

OID_XXX_CURRENT_ADDRESS
If the driver's MiniportInitialize function selected an NdisMedium Xxx for which the system supplies a filter, NDIS calls MiniportQueryInformation to return the NIC's current address in medium-specific format. For FDDI drivers, NDIS requests both long and short current addresses.
OID_802_3_MAXIMUM_LIST_SIZE
For Ethernet drivers, NDIS requests the multicast list size.
OID_FDDI_LONG/SHORT_MAX_LIST_SIZE
For FDDI drivers, NDIS requests the multicast list sizes.

If possible, MiniportQueryInformation should not return NDIS_STATUS_PENDING for initialization-time requests. Until NDIS has sufficient information to set up bindings to the miniport driver, such requests should be handled synchronously.

Subsequently, the NDIS library intercepts all protocol-initiated queries on certain OIDs, such as the following:

OID_GEN_CURRENT_PACKET_FILTER
OID_GEN_PROTOCOL_OPTIONS
OID_802_5_CURRENT_FUNCTIONAL
OID_802_3_MULTICAST_LIST
OID_FDDI_LONG_MULTICAST_LIST
OID_FDDI_SHORT_MULTICAST_LIST

For more information about the system-defined OIDs, see Connection-Oriented Objects.

If MiniportQueryInformation does not complete a request synchronously and returns NDIS_STATUS_PENDING, the driver must complete the request later with a call to NdisMQueryInformationComplete. Until it completes any such request, the miniport driver can safely access the memory at InformationBuffer, BytesWritten, and BytesNeeded. After the miniport driver completes any query, ownership of these variables and the buffer reverts to NDIS or the caller of NdisRequest, whichever allocated the memory.

After a call to MiniportQueryInformation, NDIS submits no other requests to the driver until it has completed the current request, either synchronously or asynchronously. Instead, NDIS holds requests queued until the current query is completed.

MiniportQueryInformation can be pre-empted by an interrupt.

MiniportQueryInformation runs at IRQL DISPATCH_LEVEL.

See Also

MiniportInitialize, MiniportSetInformation, NdisMQueryInformationComplete, NdisRequest, NDIS_REQUEST


MiniportReconfigure

MiniportReconfigure is an function that the NDIS library currently never calls but that a MiniportInitialize function can call as an internal driver function.

NDIS_STATUS
  MiniportReconfigure(
    OUT PNDIS_STATUS  OpenErrorStatus,
    IN NDIS_HANDLE  MiniportAdapterContext,
    IN NDIS_HANDLE  WrapperConfigurationContext
    );

Parameters

OpenErrorStatus
Pointer to a variable that MiniportReconfigure sets to an NDIS_STATUS_XXX code specifying additional information about the error if MiniportReconfigure will return NDIS_STATUS_OPEN_ERROR.
MiniportAdapterContext
Specifies the handle to a miniport driver-allocated context area in which the driver maintains per-NIC state, set up by MiniportInitialize with NdisMSetAttributes or NdisMSetAttributesEx.
WrapperConfigurationContext
Specifies a handle used only during initialization for calls to Ndis Xxx configuration and initialization functions. For example, this handle is a required parameter to NdisOpenConfiguration and the NdisImmediateRead Xxx and NdisImmediateWrite Xxx functions.

Return Value

MiniportReconfigure either returns NDIS_STATUS_SUCCESS or it can return any driver-determined value, such as one of the following:

NDIS_STATUS_NOT_ACCEPTED
NDIS_STATUS_OPEN_ERROR
NDIS_STATUS_FAILURE

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

As an internal driver function, MiniportReconfigure might be called from MiniportInitialize to reconfigure a NIC to new parameters returned by one of the Ndis Xxx bus-relative configuration functions. For example, a MiniportReconfigure function might be used to support Plug and Play NICs or software-configurable NICs.

Because an internal MiniportReconfigure function is called from MiniportInitialize, no other driver request can be outstanding when MiniportReconfigure is called, and NDIS will never submit another request to the miniport driver until its caller, MiniportInitialize, returns control.

Like MiniportInitialize, MiniportReconfigure can be pre-empted by an interrupt if the driver has already called NdisMRegisterInterrupt or if the NIC shares an IRQ.

As an internal driver function called from MiniportInitialize, MiniportReconfigure can be pageable code.

MiniportReconfigure runs at the same IRQL as MiniportIntialize.

See Also

MiniportInitialize


MiniportReset

MiniportReset is a required function that issues a hardware reset to the NIC and/or resets the driver's software state.

NDIS_STATUS
  MiniportReset(
    OUT PBOOLEAN  AddressingReset,
    IN NDIS_HANDLE  MiniportAdapterContext
    );

Parameters

AddressingReset
Pointer to a variable that MiniportReset sets to TRUE if the NDIS library should call MiniportSetInformation to restore addressing information to the current values.
MiniportAdapterContext
Specifies the handle to a miniport driver-allocated context area in which the driver maintains per-NIC state, set up by MiniportInitialize.

Return Value

MiniportReset can return one of the following:

NDIS_STATUS_SUCCESS
MiniportReset successfully reset the NIC to an operational state.
NDIS_STATUS_PENDING
The driver will complete the reset operation asynchronously by calling NdisMResetComplete when the operation is done.
NDIS_STATUS_NOT_RESETTABLE
The NIC does not provide reset capabilities under software control.
NDIS_STATUS_RESET_IN_PROGRESS
MiniportReset determined that the NIC was currently being reset, so this call is superfluous.
NDIS_STATUS_SOFT_ERRORS
MiniportReset successfully reset the NIC but a recoverable error occurred during the operation. MiniportReset has called NdisWriteErrorLogEntry with more information about the error.
NDIS_STATUS_HARD_ERRORS
MiniportReset attempted to reset the NIC but an unrecoverable error occurred during the operation. MiniportReset has called NdisWriteErrorLogEntry with more information about the error.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

MiniportReset can reset the parameters of its NIC. If a reset causes a change in the NIC's station address, the miniport driver automatically restores the station address following the reset to its prior value. Any multicast or functional addressing masks reset by the hardware do not have to be reset in this function.

If other information, such as multicast or functional addressing information or the lookahead size, is changed by a reset, MiniportReset must set the variable at AddressingReset to TRUE before it returns control. This causes NDIS to call the MiniportSetInformation function to restore the information.

As a general rule, the MiniportReset function of an NDIS intermediate driver should always set AddressingReset to TRUE. Until the underlying NIC driver resets its NIC, such an intermediate driver cannot determine whether it must restore addressing information for its virtual NIC. Because an intermediate driver disables the NDIS library's timing out of queued sends and requests to itself with an initialization-time call to NdisMSetAttributesEx, such a driver's MiniportReset function is called only when a reset request is directed to the underlying NIC driver.

Intermediate drivers that layer themselves above other types of device drivers also must have a MiniportReset function. Such a MiniportReset function must handle reset requests initiated by protocol drivers' calls to NdisReset. If the intermediate driver also has a MiniportCheckForHang function, its MiniportReset function will be called whenever MiniportCheckForHang returns TRUE.

Before MiniportReset begins resetting the NIC or updating the NIC's software state:

  • The miniport driver can optionally complete any pending OID requests. NDIS will submit no further OID requests to the miniport driver for the NIC being reset until the reset operation has finished. After the reset, NDIS will resubmit to the miniport driver any OID requests that were pending but not completed by the miniport driver before the reset.
  • A serialized miniport driver should complete any pending send operations. If the miniport driver does not complete all pending send operations before completing the reset, NDIS will complete those operations with a failure status after the reset operation has finished.
  • A deserialized miniport driver must complete any pending send operations. NDIS will not requeue pending send packets for a deserialized driver since NDIS does not maintain the send queue for such a driver.

After the reset operation has finished, a miniport driver must not attempt to complete any send operations that were pending but not completed before the reset.

A miniport driver need not call NdisM(Co)IndicateStatus to signal the start and finish of each reset operation because NDIS notifies bound protocols when a reset begins and ends.

If MiniportReset must wait for state changes in the NIC during reset operations, it can call NdisStallExecution. However, a MiniportReset function should never call NdisStallExecution with an interval greater than 50 microseconds.

If MiniportReset returns NDIS_STATUS_PENDING, the driver must complete the original request subsequently with a call to NdisMResetComplete.

MiniportReset can be pre-empted by an interrupt.

If a NIC driver supplies a MiniportCheckForHang function, the NDIS library calls it periodically to determine whether to call the driver's MiniportReset function. Otherwise, the NDIS library calls a NIC driver's MiniportReset function whenever requests NDIS submitted to the MiniportQueryInformation, MiniportSetInformation, MiniportSendPackets, MiniportSend, or MiniportWanSend function seem to have timed out. (NDIS does not call a deserialized NIC driver's MiniportReset function if the driver's MiniportSend or MiniportSendPackets function seems to have timed out, nor does NDIS call a connection-oriented NIC driver's MiniportReset function if the driver's MiniportCoSendPackets function seems to have timed out.) By default, the NDIS-determined time-out interval for outstanding sends and requests is around four seconds. If this default is too short, a NIC driver can make an initialization-time call to NdisMSetAttributesEx, rather than NdisMSetAttributes, to lengthen the time-out interval to suit its NIC.

Every NDIS intermediate driver should call NdisMSetAttributesEx from MiniportInitialize and disable NDIS's attempts to time out requests and sends in the intermediate driver. NDIS runs an intermediate driver's MiniportCheckForHang function, if any, approximately every two seconds.

NDIS cannot determine whether a NIC might be hung on receives, so supplying a MiniportCheckForHang function allows a driver to monitor its NIC for this condition and to force a reset if it occurs.

MiniportReset runs at IRQL DISPATCH_LEVEL.

See Also

MiniportCheckForHang, MiniportCoSendPackets, MiniportInitialize, MiniportQueryInformation, MiniportSend, MiniportSendPackets, MiniportSetInformation, MiniportWanSend, NdisMIndicateStatus, NdisMResetComplete, NdisMSetAttributesEx, NdisWriteErrorLogEntry


MiniportReturnPacket

The MiniportReturnPacket function is required in drivers that indicate receives with NdisM(Co)IndicateReceivePacket.

VOID
  MiniportReturnPacket(
    IN NDIS_HANDLE  MiniportAdapterContext,
    IN PNDIS_PACKET  Packet
    );

Parameters

MiniportAdapterContext
Specifies the handle to a miniport driver-allocated context area in which the driver maintains per-NIC state, set up by MiniportInitialize.
Packet
Pointer to a packet descriptor being returned to the miniport driver, which previously indicated a packet array that contained this pointer.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The following types of drivers must supply a MiniportReturnPacket function:

  • A miniport driver of a bus-master DMA NIC that supports multipacket receives. Such drivers include serialized miniports that export a MiniportSendPackets function, deserialized miniports, and connection-oriented miniports.
  • A miniport driver that supplies media-specific information, such as packet priorities, with its receive indications
  • An NDIS intermediate driver that binds itself to a miniport driver that supplies a MiniportReturnPacket function

For Serialized Drivers

Any receive packet with associated NDIS_PACKET_OOB_DATA in which the Status is set to NDIS_STATUS_PENDING on return from NdisMIndicateReceivePacket will be returned to MiniportReturnPacket. When all bound protocols have called NdisReturnPackets as many times as necessary to release their references to the originally indicated packet array, NDIS returns pended packets from the array to the MiniportReturnPacket function of the driver that originally allocated the packet array.

If the driver, before indicating up a receive packet descriptor with NdisMIndicateReceivePacket, set the Status member in the NDIS_PACKET_OOB_DATA associated with the descriptor to NDIS_STATUS_SUCCESS, the driver must check the packet's Status on return of NdisMIndicateReceivePacket:

  • If the Status is set to NDIS_STATUS_SUCCESS, the packet descriptor and associated buffer descriptors have been returned to the driver.
  • If the Status is set to NDIS_STATUS_PENDING, NDIS will return the packet descriptor to the driver's MiniportReturnPacket function.

For Deserialized and Connection-Oriented Drivers

If the driver, before indicating up a receive packet descriptor with NdisM(Co)IndicateReceivePacket, sets the Status member in the NDIS_PACKET_OOB_DATA associated with the packet descriptor to NDIS_STATUS_SUCCESS, NDIS returns that packet descriptor to the driver's MiniportReturnPacket function. However, if the miniport driver sets the Status member to NDIS_STATUS_RESOURCES, thereby indicating that it needs to retain ownership of the packet descriptor and associated buffer descriptors, NDIS implicitly returns the packet descriptor to the driver on return of NdisM(Co)IndicateReceivePacket.

A deserialized or connection-oriented miniport driver must not examine the Status of indicated packets on return of NdisMIndicateReceivePacket. Instead, a deserialized miniport driver must save a packet's Status in a local variable before indicating up the packet descriptor. When NdisMIndicateReceivePacket returns, the miniport driver should check the saved packet Status. If the miniport driver set the packet's Status to NDIS_STATUS_RESOURCES before indicating up the packet descriptor, it should reclaim the packet descriptor immediately after NdisMIndicateReceivePacket returns, preferably by calling its own MiniportReturnPacket function. In this case, NDIS does not call the miniport driver's MiniportReturnPacket function to return the packet descriptor. If the miniport driver set the packet's Status to NDIS_STATUS_SUCCESS before indicating up the packet descriptor, the miniport driver must not reclaim the packet descriptor until NDIS subsequently returns the packet descriptor to the miniport driver's MiniportReturnPacket function.

For All Drivers

Usually, MiniportReturnPacket prepares such a returned packet to be used in a subsequent receive indication. Although MiniportReturnPacket could return the buffer descriptors chained to the packet to buffer pool and the packet descriptor itself to packet pool, it is far more efficient to reuse returned descriptors.

MiniportReturnPacket must call NdisUnchainBufferAt Xxx as many times as necessary to save the pointers to all chained buffer descriptors before it calls NdisReinitializePacket. Otherwise, MiniportReturnPacket cannot recover the buffer descriptors the driver originally chained to the packet for the indication.

MiniportReturnPacket also can call NdisZeroMemory with the pointer returned by NDIS_OOB_DATA_FROM_PACKET to prepare the packet's associated out-of-band block for reuse.

If a particular buffer descriptor was shortened to match the size of an indicated range of data, MiniportReturnPacket should call NdisAdjustBufferLength with that buffer descriptor to restore its mapping of the NIC's receive buffer range.

MiniportReturnPacket runs at IRQL DISPATCH_LEVEL.

See Also

NdisAdjustBufferLength, NdisAllocateBuffer, NdisAllocatePacket, NdisMCoIndicateReceivePacket, NdisMIndicateReceivePacket, NDIS_OOB_DATA_FROM_PACKET, NDIS_PACKET, NDIS_PACKET_OOB_DATA, NdisReinitializePacket, NdisReturnPackets, NdisUnchainBufferAtBack, NdisUnchainBufferAtFront, NdisZeroMemory


MiniportSend

The MiniportSend function is required function for drivers that do not have a MiniportSendPackets, MiniportWanSend, or MiniportCoSendPackets function. MiniportSend transfers a protocol-supplied packet over the network.

NDIS_STATUS
  MiniportSend(
    IN NDIS_HANDLE  MiniportAdapterContext,
    IN PNDIS_PACKET  Packet,
    IN UINT  Flags
    );

Parameters

MiniportAdapterContext
Specifies the handle to a miniport driver-allocated context area in which the driver maintains per-NIC state, set up by MiniportInitialize.
Packet
Pointer to a packet descriptor specifying the data to be transmitted.
Flags
Specifies the packet flags, if any, set by the protocol.

Return Value

MiniportSend can return any of the following:

NDIS_STATUS_SUCCESS
The driver (or its NIC) has accepted the packet data for transmission, so MiniportSend is returning the packet, which NDIS will return to the protocol.
NDIS_STATUS_PENDING
The driver will complete the packet asynchronously with a call to NdisMSendComplete.
NDIS_STATUS_RESOURCES
The driver (or NIC) currently has insufficient resources available to process the given packet so NDIS should queue the send packet for a resubmission when the driver next calls NdisMSendResourcesAvailable or NdisMSendComplete.

If a deserialized miniport driver returns NDIS_STATUS_RESOURCES from its MiniportSend function, NDIS returns the given packet back to the protocol with an error status.

NDIS_STATUS_NO_CABLE
The NIC has failed the send operation because the network cable is disconnected from the NIC.
NDIS_STATUS_RESET_IN_PROGRESS
The NIC has failed the send operation because the NIC is resetting.
NDIS_STATUS_FAILURE
The given packet was invalid or unacceptable to the NIC. MiniportSend should return NDIS_STATUS_FAILURE only if there is no NDIS_STATUS_XXX value that adequately describes the failure. Preferably, MiniportSend should return an NDIS_STATUS_XXX value that indicates the specific cause of the failure.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If a driver registers both MiniportSend and MiniportSendPackets functions when it initializes, its MiniportSend function is never called by NDIS.

MiniportSend can safely access the packet and all buffer descriptors chained to the packet until the given packet is complete. If MiniportSend returns a status other than NDIS_STATUS_PENDING or, from a serialized driver NDIS_STATUS_RESOURCES, the request is considered complete and ownership of the packet descriptor and all memory associated with the packet reverts to the allocating protocol.

If the MiniportSend function of a deserialized driver returns NDIS_STATUS_RESOURCES, the request is also considered complete. Such a deserialized driver's MiniportSend function should queue the given packet internally if the driver currently has insufficient resources to transmit it and the packet is valid. In these circumstances, MiniportSend should return NDIS_STATUS_PENDING for the packet it queued and call NdisMSendComplete subsequently when it has transmitted the packet. A deserialized miniport driver cannot call NdisMSendResourcesAvailable.

If MiniportSend returns NDIS_STATUS_PENDING, the driver subsequently must signal completion of the request by calling NdisMSendComplete. When MiniportSend returns NDIS_STATUS_RESOURCES, the NDIS library reflects this status to the protocol as NDIS_STATUS_PENDING if the driver is serialized.

When a serialized driver returns a packet with NDIS_STATUS_RESOURCES, the next packet submitted to its MiniportSend function is the same packet it just returned to NDIS. Consequently, MiniportSend can optimize by retaining information about such a returned packet if the driver currently has sufficient resources to store the information. NDIS assumes MiniportSend is ready to accept that packet as soon as the serialized driver calls NdisMSendResourcesAvailable or NdisMSendComplete, whichever occurs first.

Each protocol driver must pass packet descriptors to NdisSend that are fully set up to be passed by the underlying driver's MiniportSend function to its NIC. That is, the protocol is responsible for determining what is required, based on the medium type selected by the miniport driver to which the protocol bound itself. However, a protocol can supply net packets mapped by the chained buffer descriptors that are shorter than the minimum for the selected medium, which MiniportSend must pad if its medium imposes a minimum-length requirement on transmits.

Any NDIS intermediate driver that layers itself betwen a higher-level protocol and an underlying NIC driver has the same responsibility as any protocol driver to set up packets according to the requirements of the underlying miniport driver and its selected medium. Such an intermediate driver must repackage each incoming send packet in a fresh packet descriptor that was allocated by the intermediate driver.

MiniportSend can use only the eight-byte area at MiniportReserved within the NDIS_PACKET structure for its own purposes. Consequently, an NDIS intermediate driver that forwards send requests to an underlying NIC driver must repackage the packets input to its MiniportSend function in fresh packet descriptors, which the intermediate driver allocates from packet pool, so that the underlying miniport driver has a MiniportReserved area it can use.

MiniportSend can call NdisQueryPacket to extract information, such as the number of buffer descriptors chained to the packet and the total size in bytes of the requested transfer. It can call NdisGetFirstBufferFromPacket(Safe), NdisQueryBuffer(Safe), or NdisQueryBufferOffset to extract information about individual buffers containing the data to be transmitted.

The Flags parameter can provide information about a send that is not contained in the packet data itself. Currently, there are no system-defined flags, but a pair of closely coupled protocol and miniport drivers can pass information in this parameter, which MiniportSend can retrieve with NdisGetPacketFlags. However, such a pair of drivers can communicate more information, such as timestamps and packet priority, in the NDIS_PACKET_OOB_DATA block associated with each packet descriptor.

If the underlying driver's MiniportQueryInformation function set the NDIS_MAC_OPTION_NO_LOOPBACK flag when the NDIS library queried the OID_GEN_MAC_OPTIONS, the miniport driver must not attempt to loop back any packets. The NDIS library provides software loopback support for such a driver.

MiniportSend can be pre-empted by an interrupt.

MiniportSend runs at IRQL DISPATCH_LEVEL.

See Also

MiniportCoSendPackets, MiniportInitialize, MiniportQueryInformation, MiniportSendPackets, MiniportWanSend, NdisAllocatePacket, NdisGetBufferPhysicalArraySize, NdisGetFirstBufferFromPacket, NdisGetFirstBufferFromPacketSafe, NdisGetNextBuffer, NdisGetPacketFlags, NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO, NDIS_GET_PACKET_TIME_TO_SEND, NdisMoveMemory, NdisMoveToMappedMemory, NdisMSendComplete, NdisMSendResourcesAvailable, NdisMSetupDmaTransfer, NdisMStartBufferPhysicalMapping, NDIS_PACKET, NDIS_PACKET_OOB_DATA, NdisQueryBuffer, NdisQueryBufferOffset, NdisQueryBufferSafe, NdisQueryPacket, NdisSend, NdisZeroMemory


MiniportSendPackets

The MiniportSendPackets function is required for drivers that do not have a MiniportSend, MiniportWanSend, or MiniportCoSendPackets function. MiniportSendPackets transfers some number of packets, specified as an array of packet pointers, over the network.

VOID
  MiniportSendPackets(
    IN NDIS_HANDLE  MiniportAdapterContext,
    IN PPNDIS_PACKET  PacketArray,
    IN UINT  NumberOfPackets
    );

Parameters

MiniportAdapterContext
Specifies the handle to a miniport driver-allocated context area in which the driver maintains per-NIC state, set up by MiniportInitialize.
PacketArray
Pointer to the initial element in a packet array, with each element specifying the address of a packet descriptor for a packet to be transmitted, along with an associated out-of-band data block containing information such as the packet priority, an optional timestamp, and the per-packet status to be set by MiniportSendPackets.
NumberOfPackets
Specifies the number of pointers to packet descriptors at PacketArray.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If a driver registers both MiniportSendPackets and MiniportSend functions when it initializes, NDIS always calls its MiniportSendPackets function. If a driver registers both MiniportSendPackets and MiniportCoSendPackets functions, NDIS calls its MiniportCoSendPackets function when any bound protocol calls NdisCoSendPackets.

The input packet packet descriptor pointers have been ordered according to the order in which the packets should be sent over the network by the protocol driver that set up the packet array. The NDIS library preserves the protocol-determined ordering when it submits each packet array to MiniportSendPackets.

Consequently, MiniportSendPackets should transmit each packet in any given array sequentially. MiniportSendPackets can call NdisQueryPacket to extract information, such as the number of buffer descriptors chained to the packet and the total size in bytes of the requested transfer. It can call NdisGetFirstBufferFromPacket(Safe), NdisQueryBuffer(Safe), or NdisQueryBufferOffset to extract information about individual buffers containing the data to be transmitted.

MiniportSendPackets can retrieve any protocol-supplied out-of-band information associated with each packet by using the relevant NDIS_GET_PACKET_TIME_TO_SEND and NDIS_GET_MEDIA_SPECIFIC_INFO macros.

Each protocol driver must set up packet arrays with packet descriptors that are fully set up to be passed by the underlying driver's MiniportSendPackets function to its NIC. That is, the protocol is responsible for determining what is required, based on the medium type selected by the miniport driver to which the protocol bound itself. However, a protocol can supply packets shorter than the minimum for the selected medium, which MiniportSendPackets must pad if its medium imposes a minimum-length requirement on transmits.

Any NDIS intermediate driver that layers itself between a higher-level protocol and an underlying NIC driver has the same responsibility as any protocol driver to set up packets according to the requirements of the underlying miniport driver and its selected medium. Such an intermediate driver must repackage each incoming send packet in a fresh packet descriptor that was allocated by the intermediate driver.

MiniportSendPackets can use only the eight-byte area at MiniportReserved within the NDIS_PACKET structure for its own purposes. Consequently, an NDIS intermediate driver that forwards send requests to an underlying NIC driver must repackage the packets given to its MiniportSendPackets function in fresh packet descriptors, which the intermediate driver allocates from packet pool, so that the underlying miniport driver has a MiniportReserved area it can use.

If the underlying driver's MiniportQueryInformation function set the NDIS_MAC_OPTION_NO_LOOPBACK flag when the NDIS library queried the OID_GEN_MAC_OPTIONS, the miniport driver must not attempt to loop back any packets. The NDIS library provides software loopback support for such a driver.

Whether the driver is serialized or deserialized determines how its MiniportSendPackets function handles the completion of input packet descriptor(s) when this driver function is called.

Serialized Miniports

The MiniportSendPackets function of a serialized driver sets one of the following values in the Status member of the NDIS_PACKET_OOB_DATA block associated with an input packet descriptor:

NDIS_STATUS_SUCCESS
The driver (or its NIC) has accepted the packet data for transmission, so MiniportSendPackets is returning the packet and the associated out-of-band data, which NDIS will return to the protocol that made this request.
NDIS_STATUS_PENDING
The driver will complete the transmit operation asynchronously with NdisMSendComplete.
NDIS_STATUS_RESOURCES
The serialized miniport driver currently cannot set up the transmit operation due to resource constraints, so NDIS should queue this packet and all remaining packets in the given array for resubmission to MiniportSendPackets when the driver next calls NdisMSendResourcesAvailable or NdisMSendComplete.

When MiniportSendPackets sets this value for a packet in the input array, the NDIS library assumes all remaining packets in the array have the same status set, so NDIS requeues the associated packets in the same order, which preserves the protocol-determined ordering of the packet array. NDIS reflects this status to the protocol as NDIS_STATUS_PENDING for this packet and for all remaining packets in the given array.

NDIS_STATUS_FAILURE
The given packet was invalid or unacceptable to the NIC. Setting this status or any other driver-determined NDIS_STATUS_XXX error value for a packet effectively completes the packet, which NDIS returns to the allocating protocol as a failed send request.

When MiniportSendPackets returns control, a serialized driver can no longer access anything in the given packet array with the following exceptions:

  • If MiniportSendPackets set the Status for a packet to NDIS_STATUS_PENDING, the miniport driver can access the packet descriptor and any media-specific information in the associated out-of-band data block. MiniportSendPackets can use the buffer descriptors chained to that packet descriptor, as well.

    After the driver calls NdisMSendComplete with the final status of the transmit operation, ownership of the given packet descriptor, out-of-band data block, and associated buffers reverts to the allocating protocol. A miniport driver should never return NDIS_STATUS_RESOURCES for a packet it passes to NdisMSendComplete.

  • If MiniportSendPackets set the Status for a packet to NDIS_STATUS_RESOURCES, the miniport driver can access the packet descriptor, its associated out-of-band data block, and the buffer descriptors chained to that packet when NDIS resubmits the send request, along with subsequent elements of the packet array, to MiniportSendPackets.

Setting NDIS_STATUS_RESOURCES for an incoming packet causes NDIS to requeue the associated packet and those specified by all remaining array elements for subsequent resubmission to the MiniportSendPackets function of a serialized driver. NDIS assumes that a subsequent call to NdisMSendResourcesAvailable or NdisMSendComplete, whichever occurs first, indicates that such a driver's MiniportSendPackets function is ready to accept more packets for transmission. NDIS preserves the original ordering of returned array elements when it resubmits them as a packet array to MiniportSendPackets.

The MiniportSendPackets function of a serialized miniport driver runs at IRQL DISPATCH_LEVEL.

Deserialized Miniports

The NDIS library ignores the OOB block in all packet descriptors it submits to the MiniportSendPackets functions of deserialized drivers and assumes that all deserialized miniports will complete each packet descriptor input to their MiniportSendPackets functions asynchronously with NdisMSendComplete. Consequently, such a deserialized driver's MiniportSendPackets function usually ignores the Status member of the NDIS_PACKET_OOB_DATA block, but it can set this member to the same status as it subsequently passes to NdisMSendComplete.

Rather than relying on NDIS to queue and resubmit send packets whenever MiniportSendPackets has insufficient resources to transmit the given packets, a deserialized miniport driver manages its own internal packet queuing. Such a driver is responsible for holding incoming send packets in its internal queue until they can be transmitted over the network and for preserving the protocol-determined ordering of packet descriptors incoming to its MiniportSendPackets function. A deserialized miniport driver must complete each incoming send packet with NdisMSendComplete, and it cannot call NdisMSendResourcesAvailable.

A deserialized miniport driver should never pass STATUS_INSUFFICIENT_RESOURCES to NdisMSendComplete with a protocol-allocated packet descriptor that was originally submitted to its MiniportSendPackets function. Such a returned status effectively fails the send operation requested by the protocol, and NDIS would return the packet descriptor and all associated resources to the protocol that originally allocated it.

The MiniportSendPackets function of a deserialized miniport driver can be called at any IRQL <= DISPATCH_LEVEL. Consequently, the MiniportSendPackets function of a deserialized driver is responsible for synchronizing access to its internal queue(s) of packet descriptors with the driver's other MiniportXxx functions that also access the same queue(s).

See Also

MiniportCoSendPackets, MiniportInitialize, MiniportQueryInformation, NdisAllocatePacket, NdisGetBufferPhysicalArraySize, NdisGetFirstBufferFromPacket, NdisGetFirstBufferFromPacketSafe, NdisGetNextBuffer, NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO, NDIS_GET_PACKET_TIME_TO_SEND, NdisMoveMemory, NdisMoveToMappedMemory, NdisMSendComplete, NdisMSendResourcesAvailable, NdisMSetupDmaTransfer, NdisMStartBufferPhysicalMapping, NDIS_OOB_DATA_FROM_PACKET, NDIS_PACKET, NDIS_PACKET_OOB_DATA, NdisQueryBuffer, NdisQueryBufferOffset, NdisQueryBufferSafe, NdisQueryPacket, NdisSendPackets, NdisZeroMemory


MiniportSetInformation

The MiniportSetInformation function is a required function that allows bound protocol drivers (or NDIS) to request changes in the state information that the miniport driver maintains for particular OIDs, such as changes in multicast addresses.

NDIS_STATUS
  MiniportSetInformation(
    IN NDIS_HANDLE  MiniportAdapterContext,
    IN NDIS_OID  Oid,
    IN PVOID  InformationBuffer,
    IN ULONG  InformationBufferLength,
    OUT PULONG  BytesRead,
    OUT PULONG  BytesNeeded
    );

Parameters

MiniportAdapterContext
Specifies the handle to a miniport driver-allocated context area in which the driver maintains per-NIC state, set up by MiniportInitialize.
Oid
Specifies the system-defined OID_XXX code designating the set operation the driver should carry out.
InformationBuffer
Pointer to a buffer containing the OID-specific data used by MiniportSetInformation for the set.
InformationBufferLength
Specifies the number of bytes at InformationBuffer.
BytesRead
Pointer to a variable that MiniportSetInformation sets to the number of bytes it read from the buffer at InformationBuffer.
BytesNeeded
Pointer to a variable that MiniportSetInformation sets to the total number of bytes it needs to satisfy the request if InformationBufferLength is less than Oid requires.

Return Value

MiniportSetInformation can return one of the following:

NDIS_STATUS_SUCCESS
MiniportSetInformation used the data at InformationBuffer to set itself or its NIC to the state required by the given Oid, and it set the variable at BytesRead to the amount of supplied data it used.
NDIS_STATUS_PENDING
The driver will complete the request asynchronously with a call to NdisMSetInformationComplete when it has set itself or its NIC to the state requested.
NDIS_STATUS_INVALID_OID
MiniportSetInformation did not recognize the Oid.
NDIS_STATUS_INVALID_LENGTH
The InformationBufferLength does not match the length required by the given Oid. MiniportSetInformation returned how many bytes the buffer should be at BytesNeeded.
NDIS_STATUS_INVALID_DATA
The data supplied at InformationBuffer was invalid for the given Oid.
NDIS_STATUS_NOT_ACCEPTED
MiniportSetInformation attempted the requested set operation on the NIC but was unsuccessful.
NDIS_STATUS_NOT_SUPPORTED
MiniportSetInformation does not support the Oid, which is optional.
NDIS_STATUS_RESOURCES
MiniportSetInformation could not carry out the requested operation due to resource constraints. This return value does not necessarily mean that the same request, submitted at a later time, will be failed for the same reason.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NDIS calls MiniportSetInformation either on its own behalf, such as to manage bindings to the miniport driver, or when a bound protocol driver calls NdisRequest.

If MiniportSetInformation returns NDIS_STATUS_PENDING, the driver must complete the request later by calling NdisMSetInformationComplete. Until it completes any request, the miniport driver can safely access the memory at InformationBuffer, BytesRead, and BytesNeeded. After the miniport driver completes any set request, ownership of these variables and the buffer reverts to NDIS or the caller of NdisRequest, whichever allocated the memory.

After a call to MiniportSetInformation, NDIS submits no other requests to the driver until it has completed the operation, either synchronously or asynchronously. Instead, NDIS holds requests queued until the current set operation is completed.

For more information about the system-defined OIDs, see Connection-Oriented Objects.

MiniportSetInformation can be pre-empted by an interrupt.

MiniportSetInformation runs at IRQL DISPATCH_LEVEL.

See Also

MiniportInitialize, MiniportQueryInformation, NdisMSetInformationComplete, NdisRequest, NDIS_REQUEST


MiniportShutdown

The MiniportShutdown function restores a NIC to its initial state when the system is shut down, whether by the user or because an unrecoverable system error occurred.

VOID
  MiniportShutdown(
    IN PVOID  ShutdownContext
    );

Parameters

ShutdownContext
Pointer to a context area supplied when the miniport driver's MiniportInitialize function called NdisMRegisterAdapterShutdownHandler. Usually, this input parameter is the NIC-specific MiniportAdapterContext pointer passed to other MiniportXxx functions.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Every miniport driver should have a MiniportShutdown function. NDIS 5.1 miniport drivers and intermediate drivers must register a MiniportShutdown function.

MiniportShutdown does nothing more than restore the NIC to its initial state (before the miniport's DriverEntry function runs). However, this ensures that the NIC is in a known state and ready to be reinitialized when the machine is rebooted after a system shutdown occurs for any reason, including a crash dump.

An NDIS 5.0 miniport driver's or intermediate driver's MiniportInitialize function must call NdisMRegisterAdapterShutdownHandler to set up a MiniportShutdown function. The driver's MiniportHalt function must make a reciprocal call to NdisMDeregisterAdapterShutdownHandler.

An NDIS 5.1 miniport driver or intermediate driver, however, should register its MiniportShutdown function in the call to NdisMRegisterMiniport or NdisIMRegisterLayeredMiniport, respectively.

If MiniportShutdown is called due to a user-initiated system shutdown, it runs at IRQL PASSIVE_LEVEL in a system-thread context. If it is called due to an unrecoverable error, MiniportShutdown runs at an arbitrary IRQL and in the context of whatever component raised the error. For example, MiniportShutdown might be run at high DIRQL in the context of an ISR for a device essential to continued execution of the system.

MiniportShutdown should call no Ndis Xxx functions.

See Also

MiniportHalt, MiniportInitialize, NdisIMRegisterLayeredMiniport, NdisMDeregisterAdapterShutdownHandler, NdisMRegisterAdapterShutdownHandler, NdisMRegisterMiniport, NdisRawReadPortBufferUchar, NdisRawReadPortBufferUlong, NdisRawReadPortBufferUshort, NdisRawReadPortUchar, NdisRawReadPortUlong, NdisRawReadPortUshort, NdisRawWritePortBufferUchar, NdisRawWritePortBufferUlong, NdisRawWritePortBufferUshort, NdisRawWritePortUchar, NdisRawWritePortUlong, NdisRawWritePortUshort, NdisReadRegisterUchar, NdisReadRegisterUlong, NdisReadRegisterUshort, NdisWriteRegisterUchar, NdisWriteRegisterUlong, NdisWriteRegisterUshort


MiniportSynchronizeISR

The MiniportSynchronizeISR function is required if any NIC driver function that runs at less than DIRQL shares resources with that driver's MiniportISR or MiniportDisableInterrupt function.

BOOLEAN
  MiniportSynchronizeISR(
    IN PVOID  SynchronizeContext
    );

Parameters

SynchronizeContext
Pointer to a context area supplied when the NIC driver's MiniportXxx or internal function called NdisMSynchronizeWithInterrupt. Usually, this input parameter is a pointer to a set of shared resources at an offset within the NIC-specific MiniportAdapterContext area passed to other MiniportXxx functions.

Return Value

MiniportSynchronizeISR returns a Boolean value with a driver-determined meaning that is propagated to the caller of NdisMSynchronizeWithInterrupt.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If any NIC driver function shares resources, such as device registers, with the driver's MiniportISR or MiniportDisableInterrupt function, the driver function that runs, by default, at less than DIRQL cannot access those resources directly. If it attempted to access such shared resources directly, the lower priority function might be pre-empted by execution of MiniportISR or MiniportDisableInterrupt, which could change state out from under the lower priority driver function.

To synchronize access to such shared resources with MiniportISR or MiniportDisableInterrupt, lower priority driver functions must call NdisMSynchronizeWithInterrupt to have the driver's MiniportSynchronizeISR function access those shared resources at DIRQL. Calling NdisMSynchronizeWithInterrupt prevents race conditions and deadlocks in such a NIC driver, particularly in SMP machines.

Any lower priority driver functions that share resources among themselves (but not with any function that runs at DIRQL) should use a spin lock to protect those shared resources.

MiniportSynchronizeISR runs at the DIRQL assigned when the driver's MiniportInitialize function called NdisMRegisterInterrupt. Like any driver function that runs at DIRQL, MiniportSynchronizeISR should return control as quickly as possible, and it can call only those Ndis Xxx functions that are safe to call at any IRQL.

See Also

MiniportDisableInterrupt, MiniportInitialize, MiniportISR, NdisAllocateSpinLock, NdisMRegisterInterrupt, NdisMSynchronizeWithInterrupt, NdisRawReadPortBufferUchar, NdisRawReadPortBufferUlong, NdisRawReadPortBufferUshort, NdisRawReadPortUchar, NdisRawReadPortUlong, NdisRawReadPortUshort, NdisRawWritePortBufferUchar, NdisRawWritePortBufferUlong, NdisRawWritePortBufferUshort, NdisRawWritePortUchar, NdisRawWritePortUlong, NdisRawWritePortUshort, NdisReadRegisterUchar, NdisReadRegisterUlong, NdisReadRegisterUshort, NdisWriteRegisterUchar, NdisWriteRegisterUlong, NdisWriteRegisterUshort


MiniportTimer

The MiniportTimer function is required if a miniport driver sets a timer..

VOID
  MiniportTimer(
    IN PVOID  SystemSpecific1,
    IN PVOID  FunctionContext,
    IN PVOID  SystemSpecific2,
    IN PVOID  SystemSpecific3
    );

Parameters

SystemSpecific1
Pointer to a system-specific variable, which is opaque to MiniportTimer and reserved for system use.
FunctionContext
Specifies the context pointer passed to NdisMInitializeTimer when MiniportInitialize set up the associated timer object.
SystemSpecific2
Pointer to a system-specific value that is reserved for system use.
SystemSpecific3
Pointer to a system-specific value that is reserved for system use.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A miniport driver can have a MiniportTimer function to poll the state of the NIC. After such a driver's MiniportInitialize function sets up the driver-allocated timer object with NdisMInitializeTimer, a call to NdisMSetPeriodicTimer causes the MiniportTimer function associated with the timer object to be run repeatedly and automatically at the interval specified by MillisecondsPeriod.

By contrast, calling NdisMSetTimer causes the MiniportTimer function associated with the timer object to be run once when the given MillisecondsToDelay expires. Such a MiniportTimer function usually performs some driver-determined action if a particular operation times out.

If either type of MiniportTimer function shares resources with other driver functions, the driver should synchronize access to those resources with a spin lock.

Any NIC driver or intermediate driver can have more than one MiniportTimer function at the discretion of the driver writer. Each such MiniportTimer function must be associated with a driver-allocated and initialized timer object.

A call to NdisMCancelTimer cancels execution of a MiniportTimer function, provided that the interval passed in the immediately preceding call to NdisMSetTimer has not yet expired. After a call to NdisMSetPeriodicTimer, a call to NdisMSetTimer or NdisMCancelTimer with the same timer object disables MiniportTimer function: either the MiniportTimer function runs once, or it is canceled.

The MiniportHalt function of any driver with a MiniportTimer function should call NdisMCancelTimer to ensure that the MiniportTimer function does not attempt to access resources that MiniportHalt has already released.

MiniportTimer runs at IRQL DISPATCH_LEVEL.

See Also

MiniportHalt, MiniportInitialize, NdisAcquireSpinLock, NdisAllocateSpinLock, NdisDprAcquireSpinLock, NdisMCancelTimer, NdisMInitializeTimer, NdisMSetPeriodicTimer, NdisMSetTimer


MiniportTransferData

The MiniportTransferData function is required in NIC drivers that do not indicate multipacket receives and/or media-specific information with NdisMIndicateReceivePacket and in those that do not support WAN media.

NDIS_STATUS
  MiniportTransferData(
    OUT PNDIS_PACKET  Packet,
    OUT PUINT  BytesTransferred,
    IN NDIS_HANDLE  MiniportAdapterContext,
    IN NDIS_HANDLE  MiniportReceiveContext,
    IN UINT  ByteOffset,
    IN UINT  BytesToTransfer
    );

Parameters

Packet
Pointer to a packet descriptor with chained buffers into which MiniportTransferData should copy the received data.
BytesTransferred
Pointer to a variable that MiniportTransferData sets to the number of bytes it copied into the packet. This value is meaningless if MiniportTransferData returns NDIS_STATUS_PENDING.
MiniportAdapterContext
Specifies the handle to a miniport driver-allocated context area in which the driver maintains per-NIC state, set up by MiniportInitialize.
MiniportReceiveContext
Specifies the context handle previously passed to NdisM..IndicateReceive. The miniport driver can examine this value to determine which receive to copy.
ByteOffset
Specifies the offset within the received packet at which MiniportTransferData should begin the copy. If the entire packet is copied, ByteOffset is zero.
BytesToTransfer
Specifies how many bytes to copy. The sum of ByteOffset and BytesToTransfer should be less than or equal to the packet size that was specified in the miniport's receive indication. This value can be zero.

Return Value

MiniportTransferData can return one of the following:

NDIS_STATUS_SUCCESS
MiniportTransferData copied the requested data into the protocol-supplied packet, and it set BytesTransferred to the number of bytes copied.
NDIS_STATUS_PENDING
The driver will complete the transfer asynchronously with a call to NdisMTransferDataComplete.
NDIS_STATUS_FAILURE
Either the data could not be copied or the input transfer range was invalid.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

MiniportTransferData copies the contents of the received packet to a given protocol-allocated packet.

NDIS calls MiniportTransferData when a ProtocolReceive function calls NdisTransferData. The media header associated with a packet cannot be copied; only the data portion of a packet can be copied. The range passed to NdisTransferData never includes the media header. Usually, the ByteOffset input to MiniportTransferData excludes data that the miniport driver already indicated in the lookahead buffer.

A miniport driver must be prepared to copy a given packet more than once. If its NIC supports reading a given packet only once, the miniport driver must copy each received network packet to a staging buffer.

MiniportTransferData can call NdisQueryPacket to determine how many buffer descriptors the allocating protocol has provided. The protocol is responsible for supplying a packet descriptor that accommodates the transfer it requested. MiniportTransferData can call NdisQueryBuffer(Safe) to determine how much data to copy into each protocol-supplied buffer.

MiniportTransferData can fail a request if the given ByteOffset and BytesToTransfer exceed the packet size originally indicated. Alternatively, MiniportTransferData can simply transfer all available data starting at any valid ByteOffset.

Because MiniportTransferData is asynchronous, a miniport driver that has this function cannot deliver receive indications while a transfer is pending. If MiniportTransferData returns NDIS_STATUS_PENDING, the miniport driver must call NdisMTransferDataComplete when the transfer is complete.

A driver that indicates packets with NdisMIndicateReceivePacket does not need a MiniportTransferData function because such a driver always indicates full packets to bound protocols.

Interrupts are still disabled when MiniportTransferData is called.

MiniportTransferData runs at IRQL DISPATCH_LEVEL.

See Also

MiniportInitialize, NdisGetFirstBufferFromPacket, NdisGetFirstBufferFromPacketSafe, NdisGetNextBuffer, NdisMArcIndicateReceive, NdisMEthIndicateReceive, NdisMFddiIndicateReceive, NdisMIndicateReceivePacket, NdisMoveMemory, NdisMTransferDataComplete, NdisMTrIndicateReceive, NdisQueryBuffer, NdisQueryBufferSafe, NdisQueryPacket, NdisTransferData, ProtocolReceive


MiniportWanSend

The MiniportWanSend function is required if the driver controls a WAN NIC. Such a driver does not have a MiniportSendPackets or MiniportSend function.

NDIS_STATUS
  MiniportWanSend(
    IN NDIS_HANDLE  MiniportAdapterContext,
    IN NDIS_HANDLE  NdisLinkHandle,
    IN PNDIS_WAN_PACKET  WanPacket
    );

Parameters

MiniportAdapterContext
Specifies the handle, originally input to MiniportInitialize, identifying the miniport driver and WAN NIC it controls.
NdisLinkHandle
Specifies the handle to a miniport driver-allocated context area for this link. The driver previously returned this handle in an NDIS_MAC_LINE_UP indication when the link was established.
WanPacket
Pointer to an NDIS_WAN_PACKET structure, specifying the data to be transmitted. This structure specifies the virtual range for a buffer with guaranteed padding at the beginning and end. The driver can manipulate the data in this buffer in any way.

Return Value

MiniportWanSend can return one of the following:

NDIS_STATUS_SUCCESS
The driver (or its NIC) has accepted the packet data for transmission, so MiniportWanSend is returning the packet.
NDIS_STATUS_PENDING
The driver will complete the packet asynchronously with a call to NdisMWanSendComplete.
NDIS_STATUS_FAILURE or NDIS_STATUS_XXX
The given packet was invalid or unacceptable to the NIC.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

When MiniportWanSend is called, ownership of both the packet descriptor and the packet data is transferred to the driver until it completes the given packet, either synchronously or asynchronously. If MiniportWanSend returns a status other than NDIS_STATUS_PENDING, the request is considered complete and ownership of the packet immediately reverts to the initiator of the send request. If MiniportWanSend returns NDIS_STATUS_PENDING, the miniport driver subsequently must call NdisMWanSendComplete with the packet to indicate completion of the transmit request.

MiniportWanSend can use both the MacReserved x and WanPacketQueue areas within the NDIS_WAN_PACKET structure. However, the miniport driver cannot access the ProtocolReserved x members.

Any NDIS intermediate driver that binds itself to an underlying WAN miniport driver is responsible for providing a fresh NDIS_WAN_PACKET structure to the underlying driver's MiniportWanSend function. Before such an intermediate driver calls NdisSend, it must repackage the send packet given to its MiniportWanSend function so the underlying driver will have MacReserved x and WanPacketQueue areas of its own to use.

The available header padding within a given packet can be calculated as (CurrentBuffer - StartBuffer), the available tail padding as (EndBuffer - (CurrentBuffer + CurrentLength)). The header and tail padding is guaranteed to be at least the length that the miniport driver requested in response to a preceding OID_WAN_GET_INFO query. The header and/or tail padding for any packet given to MiniportWanSend can be more than the length that was requested.

MiniportWanSend can neither return NDIS_STATUS_RESOURCES for an input packet nor call NdisMSendResourcesAvailable. Instead, the miniport driver must queue incoming send packets internally for subsequent transmission. The miniport driver controls how many packets NDIS will submit to MiniportWanSend when the NIC driver sets the SendWindow value in the driver's NDIS_MAC_LINE_UP indication to establish the given link. NDISWAN uses this value as an upper bound on uncompleted sends submitted to MiniportWanSend, so the miniport's internal queue cannot be overrun, and the miniport driver can adjust the SendWindow dynamically with subsequent line-up indications for established links. If the miniport driver set the SendWindow to zero when it called NdisMIndicateStatus with a particular line-up indication, NDISWAN uses the MaxTransmit value that the driver originally set in response to the OID_WAN_GET_INFO query as its limit on submitted but uncompleted send packets.

Each packet passed to MiniportWanSend is set up according to one of the flags that the miniport driver set in the FramingBits member in response to the OID_WAN_GET_INFO query. It will contain simple HDLC PPP framing if the driver claimed to support PPP. For SLIP or RAS framing, such a packet contains only the data portion with no framing whatsoever.

For more information about system-defined WAN and TAPI OIDs, see WAN Objects and TAPI Objects.

A WAN driver cannot manage software loopback or promiscuous mode loopback internally. NDISWAN supplies this loopback support for WAN drivers.

MiniportWanSend can be pre-empted by an interrupt.

MiniportWanSend runs at IRQL DISPATCH_LEVEL.

See Also

MiniportQueryInformation, NDIS_MAC_LINE_UP, NdisMIndicateStatus, NdisMWanSendComplete , NDIS_WAN_PACKET


NDIS Library Functions

This section summarizes the set of NDIS-supplied functions and macros that NDIS drivers use to communicate with the system and with other NDIS drivers.

NDIS miniport drivers can call the functions described in the following topics:

NDIS Library Functions Used by Miniport Drivers

NDIS Library Functions Used by WAN NIC Miniport Drivers

NDIS protocol drivers can call the functions described in the following topics:

NDIS Library Functions Used by Protocol Drivers

NDIS intermediate drivers can call functions described in the following topics:

NDIS Library Functions Used by Miniport Drivers

NDIS Library Functions Used by WAN NIC Miniport Drivers

NDIS Library Functions Used by Protocol Drivers

However, NDIS intermediate drivers have no use for certain Ndis Xxx functions, such as DMA functions, that support communication with a physical NIC.


NDIS Library Functions Used by Miniport Drivers

ETH_COPY_NETWORK_ADDRESS
Copies a given Ethernet address to a given location.
FDDI_IS_BROADCAST
Sets a caller-supplied variable to a Boolean value indicating whether a given FDDI address is a broadcast address.
FDDI_IS_MULTICAST
Sets a caller-supplied variable to a Boolean value indicating whether a given FDDI address is a multicast address.
FDDI_IS_SMT
Sets a caller-supplied variable to a Boolean value indicating whether a given FDDI frame is SMT (systems management utility).
NdisAcquireReadWriteLock
Acquires a lock that the caller uses for either write or read access to the resources that are shared among driver threads.
NdisAcquireSpinLock
Acquires a spin lock so the caller can synchronize access to resources shared among nonISR driver routines in a multiprocessor-safe way.
NdisAdjustBufferLength
Modifies the length specified in a given buffer descriptor that was allocated or copied by the caller.
NdisAllocateBuffer
Creates a buffer descriptor describing a specified virtual (sub)range within an already allocated, nonpaged memory block, given a handle returned by NdisAllocateBufferPool.
NdisAllocateBufferPool
Returns a handle with which the caller can allocate buffer descriptors with NdisAllocateBuffer.
NdisAllocateFromNPagedLookasideList
Removes the first entry from the given lookaside list head. If the lookaside list currently is empty, an entry is allocated from nonpaged pool.
NdisAllocateMemory
Allocates resident (nonpaged) system-space memory, optionally within a specified address limit, as a physically contiguous allocation, and/or as a noncached allocation.
NdisAllocateMemoryWithTag
Allocates resident (nonpaged) system-space memory.
NdisAllocatePacket
Allocates a packet descriptor, given a handle returned by a preceding call to NdisAllocatePacketPool.
NdisAllocatePacketPool
Allocates and initializes a block of nonpaged packet pool, given the number of packet descriptors and how many bytes each fixed-size packet descriptor should contain.
NdisAllocatePacketPoolEx
Allocates and initializes a block of storage for a pool of packet descriptors.
NdisAllocateSpinLock
Initializes a variable of type NDIS_SPIN_LOCK, used to synchronize access to resources shared among nonISR driver functions. An initialized spin lock, for which the caller supplies resident storage, is a required parameter to the Ndis..SpinLock and NdisInterlocked Xxx functions.
NdisAnsiStringToUnicodeString
Converts a given counted ANSI string into a counted Unicode string.
NdisBufferLength
Returns the length in bytes of a given mapped buffer.
NDIS_BUFFER_LINKAGE
Returns a pointer to a linked buffer, given a pointer to an NDIS buffer descriptor.
NDIS_BUFFER_TO_SPAN_PAGES
Determines how many pages of host memory are being used to back a given buffer.
NdisBufferVirtualAddress
Returns the base virtual address for the buffer mapped by a given buffer descriptor. It maps the physical pages described by the given buffer descriptor onto system space, if they are not already mapped to system space. Drivers should call NdisBufferVirtualAddressSafe instead of NdisBufferVirtualAddress. NDIS 5.1 miniport drivers must call NdisBufferVirtualAddressSafe instead of NdisBufferVirtualAddress.
NdisBufferVirtualAddressSafe
NdisBufferVirtualAddressSafe is the safe version of NdisBufferVirtualAddress. Unlike NdisBufferVirtualAddress, NdisBufferVirtualAddressSafe will not cause a bug check if system resources are low or exhausted. Drivers should call NdisBufferVirtualAddressSafe instead of NdisBufferVirtualAddress. NDIS 5.1 miniport drivers must call NdisBufferVirtualAddressSafe instead of NdisBufferVirtualAddress.
NdisChainBufferAtBack
Links a given buffer descriptor at the end of the chain of buffer descriptors for a given packet descriptor.
NdisChainBufferAtFront
Links a given buffer descriptor at the start of the chain of buffer descriptors for a given packet descriptor.
NdisCloseConfiguration
Releases the handle returned by NdisOpenConfiguration after the caller has retrieved configuration information for a NIC or itself and/or, possibly, stored additional information about its NIC in the registry.
NdisCloseFile
Releases a handle returned by NdisOpenFile and frees the memory allocated to hold the file contents when it was opened.
NdisCopyBuffer
Creates a buffer descriptor for a specified virtual (sub)range, given a handle for a block of already allocated memory and a pointer to the buffer descriptor for the block.
NdisCopyFromPacketToPacket
Copies a specified number of bytes of data from one packet to another, starting at a specified offset in a given source packet's data and copying the data to a specified offset in the target packet. Returns the number of bytes actually copied, which can be less than the requested number, depending on the source packet and specified starting offset for the copy operation.
NdisCreateLookaheadBufferFromSharedMemory
Returns the virtual address of a buffer within a block of memory shared with a bus-master DMA NIC so the caller can set up a read-only lookahead buffer for a receive indication to higher-level drivers.
NdisDeleteNPagedLookasideList
Removes a nonpaged lookaside list from the system.
NdisDestroyLookaheadBufferFromSharedMemory
Releases access to the buffer obtained in the preceding call to NdisCreateLookaheadBufferFromSharedMemory.
NdisDprAcquireSpinLock
Acquires a spin lock so the caller can synchronize access to resources shared among nonISR driver functions in a multiprocessor-safe way, provided that the caller is running at IRQL DISPATCH_LEVEL.
NdisDprAllocatePacket
Allocates and initializes a packet descriptor when the caller is running at IRQL DISPATCH_LEVEL, given a handle returned by a preceding call to NdisAllocatePacketPool.
NdisDprFreePacket
Releases a driver-allocated packet descriptor and returns it to the free list when the caller is running at IRQL DISPATCH_LEVEL.
NdisDprReleaseSpinLock
Releases a spin lock that was acquired in a preceding call to NdisDprAcquireSpinLock.
NdisEqualAnsiString
Compares two ANSI strings and returns whether they are equal.
NdisEqualMemory
Compares a specified number of characters in one block of memory with the same number of characters in a second block of memory.
NdisEqualString
Compares two strings to determine whether they are equal.
NdisEqualUnicodeString
Compares two Unicode strings and returns whether they are equal.
NdisFillMemory
Fills a caller-supplied buffer with the given character.
NdisFlushBuffer
Flushes the memory region described by a given buffer descriptor from all processor caches.
NdisFreeBuffer
Releases a buffer descriptor obtained in a preceding call to NdisAllocateBuffer or NdisCopyBuffer.
NdisFreeBufferPool
Releases a handle obtained in a preceding call to NdisAllocateBufferPool.
NdisFreeMemory
Releases a handle, usually when the driver is being unloaded, that was obtained in a preceding call to NdisAllocateMemory.
NdisFreePacket
Releases a packet descriptor that was allocated from packet pool with NdisAllocatePacket and returns it to the free list.
NdisFreePacketPool
Releases a handle to a block of packet pool that was allocated with NdisAllocatePacketPool.
NdisFreeSpinLock
Releases a spin lock initialized in a preceding call to NdisAllocateSpinLock, usually when a driver is unloading.
NdisFreeString
Frees the storage for a buffered string.
NdisFreeToNPagedLookasideList
Returns an entry to the given lookaside list.
NdisGetBufferPhysicalArraySize
Returns the number of discontiguous physical blocks in a buffer, given a buffer descriptor.
NdisGetCacheFillSize
Returns the size of the microprocessor cache boundary in bytes. (This information is useful primarily to drivers of bus-master DMA NICs.)
NdisGetCurrentProcessorCounts
Returns counts for the current processor that the driver can use to determine CPU utilization for a particular time interval.
NdisGetCurrentProcessorCpuUsage
Returns how busy the current processor is as a percentage.
NdisGetCurrentSystemTime
Returns the current system time, suitable for use as a timestamp.
NdisGetFirstBufferFromPacket
Returns pointers to the buffer descriptor and base virtual address for the initial buffer chained to a given packet, along with the sizes of the initial buffer and full buffer, in case the buffer is fragmented. Drivers should call NdisGetFirstBufferFromPacketSafe instead of NdisGetFirstBufferFromPacket. NDIS 5.1 miniports must call NdisGetFirstBufferFromPacketSafe instead of NdisGetFirstBufferFromPacket.
NdisGetFirstBufferFromPacketSafe
NdisGetFirstBufferFromPacketSafe is the safe version of NdisGetFirstBufferFromPacket. Unlike NdisGetFirstBufferFromPacket, NdisGetFirstBufferFromPacketSafe does not cause a bug check if system resources are low or exhausted. Drivers should call NdisGetFirstBufferFromPacketSafe instead of NdisGetFirstBufferFromPacket. NDIS5.1 miniports must use NdisGetFirstBufferFromPacketSafe instead of NdisGetFirstBufferFromPacket.
NdisGetNextBuffer
Returns the next buffer descriptor in a chain, given the current buffer descriptor.
NDIS_GET_ORIGINAL_PACKET
Returns a pointer to a packet descriptor that the lowest-level driver in a layered stack of NDIS drivers indicated. The calling driver should access the out-of-band (OOB) data block from this original packet rather than the packet that the driver below the calling driver indicated. If the calling driver is not part of a layered stack, the returned packet descriptor will be identical to the packet that the driver below the calling driver indicated.
NdisGetPacketFlags
Returns the flags, if any, set by a protocol driver in a given packet descriptor.
NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO
Returns the address (MediaSpecificInformation) and length (SizeMediaSpecificInfo) from the NDIS_PACKET_OOB_DATA block associated with the packet descriptor of a buffer containing out-of-band information, such as packet priority, about a given send packet set up by a protocol.
NDIS_GET_PACKET_PROTOCOL_TYPE
Returns the protocol ID associated with a given packet descriptor.
NDIS_GET_PACKET_STATUS
Returns the Status of an indicated receive packet on return from NdisMIndicateReceivePacket so the driver can determine whether its miniport driver-allocated packet descriptor (and chained buffer descriptors) can be prepared for reuse immediately.
NDIS_GET_PACKET_TIME_TO_SEND
Returns the protocol-set TimeToSend timestamp, directing the miniport driver when to send the given packet, from the NDIS_PACKET_OOB_DATA block associated with the incoming packet descriptor.
NdisGetPhysicalAddressHigh
Returns the high-order part of a given physical address.
NdisGetPhysicalAddressLow
Returns the low-order part of a given physical address.
NdisGetReceivedPacket
Retrieves a packet that was received from the underlying driver.
NdisGetSystemUpTime
Returns the number of milliseconds that have elapsed since the system was booted.
NdisIMAssociateMiniport
Informs the NDIS library that the given lower and upper interfaces for the miniport driver and protocol respectively belong to the same intermediate driver.
NdisIMCancelInitializeDeviceInstance
Cancels the immediately preceding call to NdisIMInitializeDeviceInstance.
NdisIMCopySendCompletePerPacketInfo
Copies per-packet information from a packet returned by a lower miniport driver into a new packet that is to be returned to an upper-level driver.
NdisIMCopySendPerPacketInfo
Copies per-packet information from a packet sent down by an upper-level driver into a new packet to be sent down to a lower miniport driver.
NdisIMDeInitializeDeviceInstance
Calls an NDIS intermediate driver's MiniportHalt function to tear down the driver's virtual NIC.
NdisIMDeregisterLayeredMiniport
Releases a previously registered intermediate driver.
NdisIMGetDeviceContext
Allows an NDIS intermediate driver's MiniportInitialize function to access the device context area allocated by its ProtocolBindAdapter function.
NdisIMInitializeDeviceInstance
Calls an NDIS intermediate driver's MiniportInitialize function to set up the driver's virtual NIC for I/O operations bound for an underlying NIC driver to which the intermediate driver is bound.
NdisIMInitializeDeviceInstanceEx
Calls an NDIS intermediate driver's MiniportInitialize function to initialize the driver's virtual NIC and optionally to set up state information about the driver's virtual NIC for subsequently bound protocols.
NdisImmediateReadPciSlotInformation
Returns a specified range of PCI configuration information to a caller-supplied buffer, given a handle to the wrapper configuration context and the slot number for the NIC on the I/O bus.
NdisImmediateReadPortUchar
Reads a byte from a specified port on an I/O bus during driver initialization, given the handle to the wrapper configuration context. If necessary, this function maps the specified bus-relative port address in order to read the data.
NdisImmediateReadPortUlong
Reads a ULONG from a specified port on an I/O bus during driver initialization, given a handle to the wrapper configuration context. If necessary, this function maps the specified bus-relative port address in order to read the data.
NdisImmediateReadPortUshort
Reads a USHORT from a specified port on an I/O bus during driver initialization, given a handle to the wrapper configuration context. If necessary, this function maps the specified bus-relative port address in order to read the data.
NdisImmediateReadSharedMemory
Reads a specified number of bytes into a caller-supplied buffer from shared device RAM, given the base physical address for the shared memory and a handle to the wrapper configuration context. If necessary, this function maps the specified bus-relative memory range in order to read the data.
NdisImmediateWritePciSlotInformation
Writes data from a caller-supplied buffer to a specified range of the PCI configuration space, given a handle to the wrapper configuration context and the slot number for the NIC on the I/O bus.
NdisImmediateWritePortUchar
Writes a byte to a specified port on an I/O bus during driver initialization, given the handle to the wrapper configuration context. If necessary, this function maps the specified bus-relative port address in order to write the data.
NdisImmediateWritePortUlong
Writes a ULONG to a specified port on an I/O bus during driver initialization, given the handle to the wrapper configuration context. If necessary, this function maps the specified bus-relative port address in order to write the data.
NdisImmediateWritePortUshort
Writes a USHORT to a specified port on an I/O bus during driver initialization, given the handle to the wrapper configuration context. If necessary, this function maps the specified bus-relative port address in order to write the data.
NdisImmediateWriteSharedMemory
Writes a specified number of bytes from a caller-supplied buffer to shared device RAM, given the base physical address for the shared memory and a handle to the wrapper configuration context. If necessary, this function maps the specified bus-relative memory range in order to write the data.
NdisIMRegisterLayeredMiniport
Registers an NDIS intermediate driver's MiniportXxx entry points and name with the NDIS library when the driver initializes.
NdisInitAnsiString
Initializes a counted ANSI string.
NDIS_INIT_FUNCTION
Marks a given driver function as initialization-only code to be discarded after the function has run once.
NdisInitializeEvent
Sets up an event object during driver initialization to be used subsequently as a synchronization mechanism.
NdisInitializeListHead
Sets up a queue header for a driver's internal queue, given a pointer to driver-supplied resident storage for the queue header and queue. Then, entries (usually packets) can be added to and removed from the doubly-linked queue with the NdisInterlocked..List functions.
NdisInitializeNPagedLookasideList
Initializes a lookaside list. After a successful initialization, nonpaged fixed-size blocks can be allocated from and freed to the lookaside list.
NdisInitializeReadWriteLock
Initializes a variable of type NDIS_RW_LOCK. An NDIS_RW_LOCK variable is used to limit write access to shared resources to one nonISR-driver thread at a time. This NDIS_RW_LOCK can allow multiple nonISR-driver threads concurrent read access to those resources. Such read access is not permitted during a write access.
NdisInitializeSListHead
Initializes the head of a sequenced, interlocked, singly linked list.
NdisInitializeString
Allocates a buffer for and initializes a counted string in the system-default character set, given a source string and a NULL pointer.
NdisInitializeWorkItem
Initializes a work-queue item with a caller-supplied context and callback routine to be queued for execution when a system worker thread is given control.
NdisInitUnicodeString
Initializes a counted Unicode string.
NdisInterlockedAddUlong
Adds an unsigned long value to a given unsigned integer as an atomic operation, using a caller-supplied and initialized spin lock.
NdisInterlockedDecrement
Decrements a caller supplied variable of type LONG as an atomic operation.
NdisInterlockedIncrement
Increments a caller supplied variable as an atomic operation.
NdisInterlockedInsertHeadList
Inserts an entry, usually a packet, at the head of a doubly linked list using a caller-supplied and initialized spin lock so that access to queued entries is synchronized in a multiprocessor-safe way among nonISR driver functions.
NdisInterlockedInsertTailList
Inserts an entry, usually a packet, at the end of a doubly linked list using a caller-supplied and initialized spin lock so that access to queued entries is synchronized in a multiprocessor-safe way among nonISR driver functions.
NdisInterlockedPopEntrySList
removes the first entry from a sequenced, singly linked list.
NdisInterlockedPushEntrySList
Inserts an entry at the head of a sequenced, singly linked list.
NdisInterlockedRemoveHeadList
Removes an entry, usually a packet, from the head of a doubly linked list using a caller-supplied and initialized spin lock so that access to queued entries is synchronized in a multiprocessor-safe way among nonISR driver functions.
NdisMAllocateMapRegisters
Reserves system resources during NIC driver initialization for subsequent bus-master DMA operations.
NdisMAllocateSharedMemory
Allocates and maps a memory range so it is simultaneously accessible from both the system and a bus-master DMA device, given the MiniportAdapterHandle for the NIC input to MiniportInitialize, the number of bytes to be allocated, and whether the memory should be cached. Returns the base (system) virtual address of the allocation for use by the miniport driver and a mapped base logical address for use by the NIC.
NdisMAllocateSharedMemoryAsync
Allocates additional memory shared between a miniport driver and its bus-master DMA NIC, usually when the miniport driver is running low on available receive buffers.
NdisMapFile
Maps the contents of an already open file to a caller-accessible buffer if the file currently is unmapped, given a handle returned by NdisOpenFile.
NdisMArcIndicateReceive
Notifies NDIS that an ARCNET packet is being received on a particular NIC, identified by the adapter handle, and that the packet or some initial lookahead portion of the packet, along with the packet header, is available to be forwarded to the appropriate bound protocol driver(s).
NdisMArcIndicateReceiveComplete
Notifies NDIS that an ARCNET receive packet, identified in a preceding call to NdisMArcIndicateReceive, has been fully transferred through a particular NIC, identified by the given adapter handle, so that NDIS can notify the appropriate bound protocol driver(s).
NdisMCancelTimer
Cancels a preceding call to NdisMSetPeriodicTimer or cancels the immediately preceding call to NdisMSetTimer if the interval given to NdisMSetTimer has not yet expired.
NdisMCloseLog
Releases resources allocated when the driver called NdisMCreateLog.
NdisMCmActivateVc
Notifies NDIS that a connection-oriented NIC miniport driver with integrated call-management support (also called an MCM driver) is ready to make transfers on a particular VC (virtual circuit).
NdisMCmAddPartyComplete
Returns the final status of a connection-oriented client's request, for which the MCM driver previously returned NDIS_STATUS_PENDING, to add a party on an active multipoint VC.
NdisMCmCloseAddressFamilyComplete
Returns the final status of a connection-oriented client's request, for which the MCM driver previously returned NDIS_STATUS_PENDING, to close the address family.
NdisMCmCloseCallComplete
Returns the final status of a connection-oriented client's request, for which the MCM driver previously returned NDIS_STATUS_PENDING, to tear down a call.
NdisMCmCreateVc
Sets up a connection-oriented endpoint (virtual circuit) on which an MCM driver can dispatch incoming calls.
NdisMCmDeactivateVc
Notifies NDIS to expect no further transfers on a particular VC.
NdisMCmDeleteVc
Destroys an MCM driver-created VC.
NdisMCmDeregisterSapComplete
Returns the final status of a connection-oriented client's request, for which the MCM driver previously returned NDIS_STATUS_PENDING, to release a previously registered SAP on which the client could receive incoming call notifications.
NdisMCmDispatchCallConnected
Notifies NDIS and the connection-oriented client that data transfers can begin on a VC that the MCM driver created for an incoming call initiated on a remote node.
NdisMCmDispatchIncomingCall
Notifies the connection-oriented client of an incoming call offer on a SAP previously registered by that client with the MCM driver.
NdisMCmDispatchIncomingCallQoSChange
Notifies the connection-oriented client that a request to change the quality of service on that client's active connection has been received over the network by the MCM driver.
NdisMCmDispatchIncomingCloseCall
Tells a connection-oriented client to tear down an active or offered call, usually because the MCM driver has received a request from the network to close the connection.
NdisMCmDispatchIncomingDropParty
Notifies a connection-oriented client that it should remove a particular party on the given multipoint VC, usually because the MCM driver has received a close-call request that was initiated at the remote node.
NdisMCmDropPartyComplete
Returns the final status of a connection-oriented client's request, for which the MCM driver previously returned NDIS_STATUS_PENDING, to remove a party from an active multipoint VC.
NdisMCmMakeCallComplete
Returns the final status of a connection-oriented client's request, for which the MCM driver previously returned NDIS_STATUS_PENDING, to make an outgoing call.
NdisMCmModifyCallQoSComplete
Returns the final status of a connection-oriented client's request, for which the MCM driver previously returned NDIS_STATUS_PENDING, to change the quality of service on an active VC.
NdisMCmOpenAddressFamilyComplete
Returns the final status of a connection-oriented client's request, for which the MCM driver previously returned NDIS_STATUS_PENDING, to open the MCM driver's address family.
NdisMCmRegisterAddressFamily
Registers a set of MCM driver-supplied call-management functions for connection-oriented communications using the specified address family.
NdisMCmRegisterSapComplete
Returns the final status of a connection-oriented client's request, for which the MCM driver previously returned NDIS_STATUS_PENDING, to register a SAP on which to receive offers of incoming calls from the network.
NdisMCmRequest
Issues an OID_GEN_CO_XXX request from the MCM driver to a client.
NdisMCmRequestComplete
Returns the final status of a client's OID_GEN_CO_XXX request, for which the MCM driver previously returned NDIS_STATUS_PENDING.
NdisMCoActivateVcComplete
Returns the final status of a call manager's request, for which the connection-oriented miniport driver previously returned NDIS_STATUS_PENDING, to activate a VC. In effect, this call notifies NDIS and the call manager that the miniport driver either has set up the NIC for per-VC transfers or is failing the activation.
NdisMCoDeactivateVcComplete
Returns the final status of a call manager's request, for which the connection-oriented NIC miniport driver previously returned NDIS_STATUS_PENDING, to deactivate a VC.
NdisMCoIndicateReceivePacket
Notifies NDIS that a multipacket receive on a VC is available to be forwarded to the appropriate connection-oriented client or call manager.
NdisMCoIndicateStatus
Indicates a change in the status of a connection-oriented NIC to bound protocols or a change in the status of a particular VC active on the NIC.
NdisMCompleteBufferPhysicalMapping
Flushes any data remaining in a bus-master NIC's internal cache at the end of a transfer operation that was set up with NdisMStartBufferPhysicalMapping.
NdisMCompleteDmaTransfer
Completes a system DMA transfer operation begun with a preceding call to NdisMSetupDmaTransfer, ensuring that the data is flushed to system memory or to the NIC, depending on the transfer direction.
NdisMCoReceiveComplete
Notifies NDIS that the processing of one or more preceding receive indications have been fully transferred so that NDIS can notify the appropriate connection-oriented client or call manager.
NdisMCoRequestComplete
Returns the final status of a client's or call manager's OID_GEN_CO_XXX or medium-specific OID_XXX request, for which the connection-oriented NIC miniport driver previously returned NDIS_STATUS_PENDING.
NdisMCoSendComplete
Returns a packet descriptor and its associated resources to the connection-oriented client or call manager that request the send.
NdisMCreateLog
Allocates and opens a log file in which a NIC miniport driver can write data to be displayed by a driver-dedicated Win32® application.
NdisMDeregisterAdapterShutdownHandler
Removes a driver-supplied MiniportShutdown function when the driver is unloading from the set of shutdown handlers that were registered with NdisMRegisterAdapterShutdownHandler.
NdisMDeregisterDevice
Removes from the system a device object that was created with NdisMRegisterDevice and removes the symbolic link that is associated with this device object.
NdisMDeregisterDmaChannel
Releases DMA system resources, including claimed hardware resources in the registry, that were acquired with NdisMRegisterDmaChannel. Drivers call NdisMDeregisterDmaChannel when they are unloading.
NdisMDeregisterInterrupt
Releases the mapping created with an initialization-time call to NdisMRegisterInterrupt. Drivers call NdisMDeregisterInterrupt when they are unloading.
NdisMDeregisterIoPortRange
Releases a mapping that was set up with NdisMRegisterIoPortRange during driver initialization.
NdisMEthIndicateReceive
Notifies NDIS that an Ethernet packet is being received on a particular NIC, identified by the adapter handle, and that the packet or some initial lookahead portion of the packet, along with the packet header, is available to be forwarded to the appropriate bound protocol driver(s).
NdisMEthIndicateReceiveComplete
Notifies NDIS that an Ethernet receive packet, identified in a preceding call to NdisMEthIndicateReceive, has been fully transferred through a particular NIC, identified by the given adapter handle, so that NDIS can notify the appropriate bound protocol driver(s).
NdisMFddiIndicateReceive
Notifies NDIS that an FDDI packet is being received on a particular NIC, identified by the adapter handle, and that the packet or some initial lookahead portion of the packet, along with the packet header, is available to be forwarded to the appropriate bound protocol driver(s).
NdisMFddiIndicateReceiveComplete
Notifies NDIS that an FDDI receive packet, identified in a preceding call to NdisMFddiIndicateReceive, has been fully transferred through a particular NIC, identified by the given adapter handle, so that NDIS can notify the appropriate bound protocol driver(s).
NdisMFlushLog
Clears a miniport's log file that was allocated with NdisMCreateLog.
NdisMFreeMapRegisters
Releases system resources for bus-master DMA that were reserved with NdisMAllocateMapRegisters. Drivers call NdisMFreeMapRegisters when they are unloading or during initialization if they fail to successfully initialize a NIC.
NdisMFreeSharedMemory
Releases a block of memory that was allocated with NdisMAllocateSharedMemory. Drivers call NdisMFreeSharedMemory when they are unloading or during initialization if they fail to successfully initialize a NIC.
NdisMGetDeviceProperty
Retrieves device objects required to set up communication with a NIC through a bus driver.
NdisMGetDmaAlignment
Returns the alignment requirements of the DMA system for a NIC.
NdisMIndicateReceivePacket
Notifies NDIS that an array of received packets is available to be forwarded to the appropriate bound protocol driver(s).
NdisMIndicateStatus
Notifies NDIS of a change in the runtime status of a NIC that might be corrected with a reset operation or possibly even require the NIC to be taken out of service, depending on the given NDIS_STATUS_XXX and additional driver-supplied information.
NdisMIndicateStatusComplete
Notifies NDIS that the driver, which has previously called NdisMIndicateStatus one or more times to indicate hardware anomalies or runtime state changes in the NIC, is ready to resume normal device I/O operations.
NdisMInitializeScatterGatherDma
Initializes system resources during miniport driver initialization for use in subsequent DMA operations. Called only by deserialized or connection-oriented miniports that manage bus-master DMA NICs.
NdisMInitializeTimer
Sets up a caller-supplied MiniportTimer function to be associated with a timer object during driver initialization; returns a handle at the caller-supplied resident storage for the timer object. This handle is a required parameter to all other NdisM..Timer functions.
NdisMInitializeWrapper
Notifies NDIS that a new NIC driver is initializing and returns a WrapperConfigurationContext handle to be passed in subsequent calls to Ndis Xxx initialization and configuration functions.
NdisMMapIoSpace
Maps a given bus-relative "physical" range of device memory, such as on-board device RAM or a set of NIC registers, onto system-space nonpaged pool and returns the mapped virtual base address for subsequent use in PIO operations.
NdisMoveFromMappedMemory
Copies data from device memory that was mapped with NdisMMapIoSpace to a system-space buffer.
NdisMoveMappedMemory
Copies data from one location to another in a memory block that was mapped with NdisMMapIoSpace.
NdisMoveMemory
Copies a specified number of bytes from one caller-supplied location to another.
NdisMoveToMappedMemory
Copies data from a system-space buffer to device memory that was mapped with NdisMMapIoSpace.
NdisMPciAssignResources
Claims resources in the registry for the caller and returns the hardware configuration information for a PCI NIC, given a handle passed in to the MiniportInitialize function and the slot number of its NIC on the PCI bus.
NdisMPromoteMiniport
Promotes a secondary miniport driver adapter to the primary role after the primary miniport driver adapter is stopped.
NdisMQueryAdapterInstanceName
Retrieves the friendly name of a physical NIC or a virtual adapter.
NdisMQueryAdapterResources
Either returns a list of resources used by a NIC or returns NDIS_STATUS_NOT_SUPPORTED.
NdisMQueryInformationComplete
Returns the final status of a query-information request for which the driver previously returned NDIS_STATUS_PENDING.
NdisMReadDmaCounter
Returns the number of bytes remaining to be transferred during a DMA operation if the NIC uses the host DMA controller's autoinitialize mode, given a handle returned by NdisMRegisterDmaChannel.
NdisMRegisterAdapterShutdownHandler
Registers a driver-supplied MiniportShutdown function to be called with a pointer to a caller-supplied context buffer when the system is about to be shut down, given a handle passed in to the MiniportInitialize function. Such a MiniportShutdown function restores the NIC to its initial state.
NdisMRegisterDevice
Creates a named device object and a symbolic link between the device object and a user-visible name for that device.
NdisMRegisterDmaChannel
Reserves system resources during driver initialization for subsequent slave DMA operations or ISA bus-master DMA operations and claims a DMA channel in the registry, returning a handle to be passed in subsequent calls to the NdisM Xxx DMA functions.
NdisMRegisterInterrupt
Sets up a mapping between the miniport's ISRHandler and HandleInterruptHandler (DPC) functions, already registered with NdisMRegisterMiniport, and the bus-relative vector (or level) on which its NIC interrupts, given a pointer to caller-allocated storage for opaque interrupt state and the adapter handle for the NIC. The interrupt handle initialized in this call is a required parameter to NdisMSynchronizeWithInterrupt.
NdisMRegisterIoPortRange
Claims a range of device memory in the registry and maps a given bus-relative range of I/O ports to a range of system logical addresses during initialization, which the driver can pass in subsequent calls to the NdisRaw Xxx to communicate with its NIC.
NdisMRegisterMiniport
Registers a miniport's entry points and name with the NDIS library, given a handle obtained from NdisMInitializeWrapper and a pointer to the NDIS_MINIPORT_CHARACTERISTICS structure set up by the caller.
NdisMRegisterUnloadHandler
Registers an unload handler for a driver.
NdisMRemoveMiniport
Removes the specified miniport driver adapter that the miniport driver has determined is unrecoverable from the system.
NdisMResetComplete
Returns the final status of a reset request for which the driver previously returned NDIS_STATUS_PENDING and indicates whether the reset operation on the NIC affected its network address information.
NdisMSendComplete
Returns the packet and final status of a completed send request for which the driver previously returned NDIS_STATUS_PENDING, so that NDIS can return the completed packet to the appropriate bound protocol driver(s).
NdisMSendResourcesAvailable
Notifies NDIS that the driver has internal resources available to process another send request when the driver has an outstanding send request for which it returned NDIS_STATUS_PENDING but has not yet called NdisMSendComplete.
NdisMSetAttributes
Informs the NDIS library about significant features of the caller's NIC, such as whether it is a bus master and the type of I/O bus on which the NIC can be found, so the miniport can call other Ndis Xxx initialization and configuration routines, particularly the NdisRegister Xxx. NIC drivers can call this function or NdisMSetAttributesEx. Intermediate drivers must call NdisMSetAttributesEx.
NdisMSetAttributesEx
Informs the NDIS library about significant features of the caller's NIC, such as whether it is a bus master and the type of I/O bus on which the NIC can be found, so the miniport driver can call other Ndis Xxx initialization and configuration routines, particularly the NdisRegister Xxx. In addition, this function prevents NDIS from timing out sends and requests in an intermediate driver or optionally resets the interval at which a NIC driver's MiniportCheckForHang function is called.
NdisMSetInformationComplete
Returns the final status of a set-information request for which the driver previously returned NDIS_STATUS_PENDING.
NdisMSetMiniportSecondary
Sets the specified miniport driver adapter to the secondary role in relation to the primary miniport driver adapter. The primary miniport driver adapter handles all packet transfers and requests for information that are made by protocol drivers. However, NDIS can send specific requests to the secondary miniport driver adapter.
NdisMSetPeriodicTimer
Sets a timer to fire periodically, thereby running an associated MiniportTimer function repeatedly at a specified fixed interval.
NdisMSetTimer
Sets a caller-initialized timer object to a specified interval, thereby running an associated MiniportTimer function once when the given interval expires.
NdisMSetupDmaTransfer
Sets up the host DMA controller to transfer a specified range of data from a given buffer, given the handle returned by a preceding call to NdisMRegisterDmaChannel and the transfer direction.
NdisMSleep
Delays execution of the caller for a given interval in microseconds.
NdisMStartBufferPhysicalMapping
Sets up a bus-master NIC for a DMA transfer operation, given the adapter handle for the NIC, the direction of the transfer, a pointer to the buffer descriptor, an index to the initial map register, a pointer to caller-allocated memory for a variable-size array of NDIS_PHYSICAL_UNIT structures, and the number of elements in the array.
NdisMSynchronizeWithInterrupt
Synchronizes the execution of a caller-supplied MiniportSynchronizeISR function with that of the ISR associated with the given initialized interrupt handle. When it runs, the supplied function can access data shared with the ISR in a multiprocessor-safe way.
NdisMTrIndicateReceive
Notifies NDIS that a Token Ring packet is being received on a particular NIC, identified by the adapter handle, and that the packet or some initial lookahead portion of the packet, along with the packet header, is available to be forwarded to the appropriate bound protocol driver(s).
NdisMTrIndicateReceiveComplete
Notifies NDIS that a Token Ring packet, identified in a preceding call to NdisMTrIndicateReceive, has been fully transferred through a particular NIC, identified by the given adapter handle, so that NDIS can notify the appropriate bound protocol driver(s).
NdisMTransferDataComplete
Returns the packet and final status of a completed transfer-data request for which the driver previously returned NDIS_STATUS_PENDING and returns the number of bytes actually transferred.
NdisMUnmapIoSpace
Releases a mapping obtained with NdisMMapIoSpace, usually when a driver is unloading.
NdisMUpdateSharedMemory
Ensures that data read from shared memory is current when the bus-master NIC has just written data to shared memory on platforms that require explicit coherency support from the system.
NdisMWriteLogData
Transfers miniport driver-supplied information into its log file for consumption and display by a driver-dedicated Win32 application.
NDIS_OOB_DATA_FROM_PACKET
Returns a pointer to the NDIS_PACKET_OOB_DATA block associated with a given packet descriptor.
NdisOpenConfiguration
Returns a handle for the registry key in which an NDIS NIC driver's configuration parameters are stored. This handle is a required parameter to other Ndis Xxx configuration functions.
NdisOpenConfigurationKeyByIndex
Opens a subkey of a given open registry key designated by a caller-supplied handle.
NdisOpenConfigurationKeyByName
Opens a named subkey of a given open registry key designated by a caller-supplied handle.
NdisOpenFile
Returns a handle for an opened file, given its name and the highest acceptable address at which to allocate memory for the file data. The returned handle is a required parameter to NdisMapFile, which gives the caller exclusive access to the file data until it calls NdisUnmapFile.
NDIS_PACKET_EXTENSION_FROM_PACKET
Returns a pointer to the NDIS_PACKET_EXTENSION structure associated with a packet descriptor.
NdisPacketPoolUsage
Returns the number of packet descriptors currently allocated from a packet pool.
NDIS_PAGABLE_FUNCTION
Marks a driver function as pageable code.
NDIS_PER_PACKET_INFO_FROM_PACKET
Returns a pointer to a specific type of per-packet information associated with a packet descriptor.
NDIS_PHYSICAL_ADDRESS_CONST
Initializes a constant of type NDIS_PHYSICAL_ADDRESS.
NdisPrintString
Displays a given string in the debugging window.
NdisQueryBuffer
Retrieves the size of the range, and optionally its base virtual address, specified in a given buffer descriptor. Drivers should call NdisQueryBufferSafe instead of NdisQueryBuffer. NDIS 5.1 miniports must call NdisQueryBufferSafe instead of NdisQueryBuffer.
NdisQueryBufferOffset
Retrieves the base virtual address of the range specified in a given buffer descriptor.
NdisQueryBufferSafe
NdisQueryBufferSafe is the safe version of NdisQueryBuffer. Unlike NdisQueryBuffer, NdisQueryBufferSafe does not cause a bug check if system resources are low or exhausted. Drivers should call NdisQueryBufferSafe instead of NdisQueryBuffer. NDIS 5.1 miniports must call NdisQueryBufferSafe instead of NdisQueryBuffer.
NdisQueryDepthSList
Returns the current number of entries in a given sequenced, singly linked list.
NdisQueryPacket
Returns any or all of the following information about a given packet descriptor: a count of buffer descriptors chained to the packet descriptor, the total number of bytes in all buffers mapped by the buffer descriptor chained to the packet descriptor, the total number of physically discontiguous blocks for all such buffers, and a pointer to the initial buffer descriptors in the chain.
NdisQuerySendFlags
See NdisGetPacketFlags.
NdisRawReadPortBufferUchar
Reads a specified number of bytes into a caller-supplied buffer, given an I/O port mapped during initialization with NdisMRegisterIoPortRange.
NdisRawReadPortBufferUlong
Reads a specified number of ULONGs into a caller-supplied buffer, given an I/O port mapped during initialization with NdisMRegisterIoPortRange.
NdisRawReadPortBufferUshort
Reads a specified number of USHORTs into a caller-supplied buffer, given an I/O port mapped during initialization with NdisMRegisterIoPortRange.
NdisRawReadPortUchar
Reads a byte from a given I/O port mapped during initialization with NdisMRegisterIoPortRange.
NdisRawReadPortUlong
Reads a ULONG from a given I/O port mapped during initialization with NdisMRegisterIoPortRange.
NdisRawReadPortUshort
Reads a USHORT from a given I/O port mapped during initialization with NdisMRegisterIoPortRange.
NdisRawWritePortBufferUchar
Writes a specified number of bytes from a caller-supplied buffer to a given I/O port mapped during initialization with NdisMRegisterIoPortRange.
NdisRawWritePortBufferUlong
Writes a specified number of ULONGs from a caller-supplied buffer to a given I/O port mapped during initialization with NdisMRegisterIoPortRange.
NdisRawWritePortBufferUshort
Writes a specified number of USHORTs from a caller-supplied buffer to a given I/O port mapped during initialization with NdisMRegisterIoPortRange.
NdisRawWritePortUchar
Writes a given byte to a given I/O port mapped during initialization with NdisMRegisterIoPortRange.
NdisRawWritePortUlong
Writes a given ULONG to a given I/O port mapped during initialization with NdisMRegisterIoPortRange.
NdisRawWritePortUshort
Writes a given USHORT to a given I/O port mapped during initialization with NdisMRegisterIoPortRange.
NdisReadConfiguration
Reads the value of a named entry of the specified type, given the registry handle returned by NdisOpenConfiguration.
NdisReadEisaSlotInformation
Returns EISA configuration information to a caller-supplied buffer during initialization, given a handle to the wrapper configuration context and the slot number for the NIC on the I/O bus.
NdisReadEisaSlotInformationEx
Returns EISA configuration information, including all available EISA function information, to a caller-supplied buffer during initialization, given a handle to the wrapper configuration context and the slot number for the NIC on the I/O bus.
NdisReadNetworkAddress
Returns the size and value, in binary, of the NetworkAddress entry, specifying the setup-configured network address of the NIC, from the caller's Parameters key in the registry, given the handle obtained from NdisOpenConfiguration.
NdisReadPciSlotInformation
Returns a specified range of PCI configuration information to a caller-supplied buffer during initialization, given an adapter handle and the slot number for the NIC on the I/O bus.
NdisReadPcmciaAttributeMemory
Reads bus-relative configuration parameters for a PC Card NIC from attribute memory.
NdisReadPortBufferUchar
Reads a specified number of bytes from a given I/O port into a caller-supplied buffer, after mapping the port address if necessary.
NdisReadPortBufferUlong
Reads a specified number of ULONGs from a given I/O port into a caller-supplied buffer, after mapping the port address if necessary.
NdisReadPortBufferUshort
Reads a specified number of USHORTs from a given I/O port into a caller-supplied buffer, after mapping the port address if necessary.
NdisReadPortUchar
Reads a byte from a given I/O port, after mapping the port address if necessary.
NdisReadPortUlong
Reads a ULONG from a given I/O port, after mapping the port address if necessary.
NdisReadPortUshort
Reads a USHORT from a given I/O port, after mapping the port address if necessary.
NdisReadRegisterUchar
Reads a byte from a device register, given its mapped memory-space address.
NdisReadRegisterUlong
Reads a ULONG from a device register, given its mapped memory-space address.
NdisReadRegisterUshort
Reads a USHORT from a device register, given its mapped memory-space address.
NdisRecalculatePacketCounts
Resets the valid counts of chained buffer descriptors for a given packet descriptor.
NdisReinitializePacket
Sets to NULL the queue head for any chained buffers in a given packet descriptor and reinitializes it for reuse.
NdisReleaseReadWriteLock
Releases a lock that was acquired in a preceding call to NdisAcquireReadWriteLock.
NdisReleaseSpinLock
Releases a spin lock that was acquired in a preceding call to NdisAcquireSpinLock.
NdisResetEvent
Clears the Signaled state of a given event.
NdisRetrieveUlong
Retrieves a ULONG value from the source address, avoiding alignment faults.
NdisScheduleWorkItem
Inserts a given work item into a queue from which a system worker thread removes the item and gives control to the callback function that the driver previously supplied to NdisInitializeWorkItem.
NdisSetEvent
Sets a given event to the Signaled state if it was not already Signaled, thereby causing waits on the event to be satisfied.
NDIS_SET_ORIGINAL_PACKET
Sets the information in a given packet descriptor to the information from a packet descriptor that was originally indicated up by a lower-level driver.
NDIS_SET_PACKET_HEADER_SIZE
Sets the HeaderSize in the NDIS_PACKET_OOB_DATA block associated with a miniport driver-allocated packet descriptor for received net packet(s) to be indicated.
NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO
Sets the MediaSpecificInformation and SizeMediaSpecificInfo in the NDIS_PACKET_OOB_DATA block associated with a miniport driver-allocated packet descriptor for a received net packet about to be indicated.
NDIS_SET_PACKET_STATUS
Sets the Status in the NDIS_PACKET_OOB_DATA block associated with packet descriptor for a received net packet about to be indicated or for a given send packet completed in the MiniportSend(Packets) function.
NDIS_SET_PACKET_TIME_RECEIVED
Sets the TimeReceived in the NDIS_PACKET_OOB_DATA block associated with a miniport driver-allocated packet descriptor for a received net packet about to be indicated with NdisMIndicateReceivePacket.
NDIS_SET_PACKET_TIME_SENT
Sets the TimeSent in the NDIS_PACKET_OOB_DATA associated with a miniport driver-allocated packet descriptor for a received net packet about to be indicated with NdisMIndicateReceivePacket.
NdisSetPhysicalAddressHigh
Sets the high-order part of a given physical address to a given value.
NdisSetPhysicalAddressLow
Sets the low-order part of a given physical address to a given value.
NdisStallExecution
Stalls the caller on the current processor for a given interval in microseconds.
NdisStoreUlong
Stores a ULONG value at a particular address, avoiding alignment faults.
NdisSystemProcessorCount
Determines whether its caller is running on a uniprocessor or multiprocessor machine, which is useful information for allocating resources during driver initialization.
NdisTerminateWrapper
Releases system resources allocated when the driver called NdisMInitializeWrapper. Drivers call NdisTerminateWrapper during initialization if they cannot find and successfully initialize at least one NIC or when they are unloading.
NdisUnchainBufferAtBack
Removes a given buffer descriptor at the end of the chain of buffer descriptors for a given packet descriptor and returns a pointer to the buffer descriptor.
NdisUnchainBufferAtFront
Removes a given buffer descriptor at the start of the chain of buffer descriptors for a given packet descriptor and returns a pointer to the buffer descriptor.
NdisUnicodeStringToAnsiString
Converts a given counted Unicode string into a counted ANSI string.
NdisUnmapFile
Releases the file mapping set up by the preceding call to NdisMapFile.
NdisUpcaseUnicodeString
Converts a copy of a given Unicode string to upper case and returns the converted string.
NdisWaitEvent
Puts the caller into a wait state until the given event is set to the Signaled state or the wait times out.
NdisWriteConfiguration
Writes a caller-supplied value entry in the registry, given the handle returned by NdisOpenConfiguration
NdisWriteErrorLogEntry
Allocates an error-log record, fills it in, and writes it to the I/O error log, given the adapter handle for the NIC, an NDIS_XXX error code, a count of caller-supplied error values, and a corresponding number of ULONGs specifying additional information about the I/O error or configuration error.
NdisWritePciSlotInformation
Writes data from a caller-supplied buffer to a specified range of the PCI configuration space, given a handle to the adapter and the slot number for the NIC on the I/O bus.
NdisWritePcmciaAttributeMemory
Writes bus-relative configuration parameters for a PC Card NIC to attribute memory.
NdisWritePortBufferUchar
Writes a specified number of bytes from a caller-supplied buffer to a given I/O port, after mapping the port address if necessary.
NdisWritePortBufferUlong
Writes a specified number of ULONGs from a caller-supplied buffer to a given I/O port, after mapping the port address if necessary.
NdisWritePortBufferUshort
Writes a specified number of USHORTs from a caller-supplied buffer to a given I/O port, after mapping the port address if necessary.
NdisWritePortUchar
Writes a given byte to a given I/O port, mapping the port address if necessary.
NdisWritePortUlong
Writes a given ULONG to a given I/O port, after mapping the port address if necessary.
NdisWritePortUshort
Writes a given USHORT to a given I/O port, after mapping the port address if necessary.
NdisWriteRegisterUchar
Writes a given byte to a device register, given its mapped memory-space address.
NdisWriteRegisterUlong
Writes a given ULONG to a device register, given its mapped memory-space address.
NdisWriteRegisterUshort
Writes a given USHORT to a device register, given its mapped memory-space address.
NdisZeroMappedMemory
Fills a block of memory that was mapped in a preceding call to NdisMMapIoSpace with zeros, given a pointer to the block and the length in bytes to be filled.
NdisZeroMemory
Fills a block of memory with zeros, given a pointer to the block and the length in bytes to be filled.
TR_COMPARE_NETWORK_ADDRESSES
Sets a caller-supplied variable to a value indicating whether a given Token Ring address is greater than, less than, or equal to another given Token Ring address.
TR_COPY_NETWORK_ADDRESS
Copies a given Token Ring address to a given location.
TR_IS_BROADCAST
Sets a caller-supplied variable to a Boolean value indicating whether a given Token Ring address is a broadcast address.
TR_IS_FUNCTIONAL
Sets a caller-supplied variable to a Boolean value indicating whether a given Token Ring address is a functional address.
TR_IS_GROUP
Sets a caller-supplied variable to a Boolean value indicating whether a given Token Ring address is a group address.
TR_IS_NOT_DIRECTED
Sets a caller-supplied variable to a Boolean value indicating whether a given Token Ring address is neither a functional nor a group address.
TR_IS_SOURCE_ROUTING
Sets a caller-supplied variable to a Boolean value indicating whether a given Token Ring address is a source-routing address.

To ensure their portability across Microsoft operating systems that support Win32, most NDIS miniport drivers call only functions exported by the NDIS library and use only macros explicitly declared in the master header file, ndis.h, or in the appropriate efilter.h, ffilter.h, tfilter.h, or afilter.h, if the NDIS uses the system-supplied Ethernet, FDDI, Token Ring, or ARCNET filter-library support to manage bindings for the miniport driver.

However, in addition to the NDIS library functions listed here, a miniport driver might use some of the macros and support routines exported by other kernel-mode components, such as the following:
CONTAINING_RECORD
InitializeListHead
InsertHeadList
InsertTailList
IsListEmpty
RemoveEntryList
RemoveHeadList

For more information about the preceding macro and functions, see Run-time Library Routines.


NDIS Library Functions Used by WAN NIC Miniport Drivers

NDIS miniport drivers of WAN NICs call the same NDIS library functions that other NIC miniport drivers call with very few exceptions. For a list of the common functions that WAN and LAN miniports call, see the preceding summary of NDIS Library Functions Used by Miniport Drivers.

However, WAN miniport drivers cannot call the following Ndis Xxx functions:
NdisMIndicateReceive
NdisMIndicateReceiveComplete
NdisMSendComplete

Instead, WAN miniport drivers call these functions:

NdisMWanIndicateReceive
Notifies NDIS that a packet has been received on a particular link, identified by the given link-context handle, and on a particular NIC, identified by the adapter handle, and that the full packet is available to be forwarded to the appropriate bound protocol driver(s).
NdisMWanIndicateReceiveComplete
Notifies NDIS that one or more receives on a particular link, identified by the given link-context handle, and on a particular NIC, identified by the adapter handle, are complete (that is, the preceding call to NdisMWanIndicateReceive has returned) so that NDIS can notify the appropriate bound protocol driver(s).
NdisMWanSendComplete
Returns the packet and final status of a completed send request for which the driver previously returned NDIS_STATUS_PENDING so that NDIS can return the completed packet to the appropriate bound protocol driver.


NDIS Library Functions Used by Protocol Drivers

In addition to the Ndis Xxx listed here, highest-level NDIS protocol drivers that are Windows® 2000 and later transport protocols call the Tdi Xxx functions described later.

NdisAcquireReadWriteLock
Acquires a lock that the caller uses for either write or read access to the resources that are shared among driver threads.
NdisAcquireSpinLock
Acquires a spin lock so the caller can synchronize access to resources shared among nonISR driver routines in a multiprocessor-safe way.
NdisAdjustBufferLength
Modifies the length specified in a given buffer descriptor that was allocated or copied by the caller.
NdisAllocateBuffer
Creates a buffer descriptor describing a specified virtual (sub)range within an already allocated, nonpaged memory block, given a handle returned by NdisAllocateBufferPool or NdisAllocateMemory.
NdisAllocateBufferPool
Returns a handle with which the caller can allocate buffer descriptors with NdisAllocateBuffer.
NdisAllocateFromNPagedLookasideList
Removes the first entry from the given lookaside list head. If the lookaside list currently is empty, an entry is allocated from nonpaged pool.
NdisAllocateMemory
Allocates resident (nonpaged) system-space memory, optionally within a specified address limit, as a physically contiguous allocation, and/or as a noncached allocation.
NdisAllocateMemoryWithTag
Allocates resident (nonpaged) system-space memory.
NdisAllocatePacket
Allocates a packet descriptor, given a handle returned by a preceding call to NdisAllocatePacketPool.
NdisAllocatePacketPool
Allocates and initializes a block of nonpaged packet pool, given the number of packet descriptors and how many bytes each fixed-size packet descriptor should contain.
NdisAllocatePacketPoolEx
Allocates and initializes a block of storage for a pool of packet descriptors.
NdisAllocateSpinLock
Initializes a variable of type NDIS_SPIN_LOCK, used to synchronize access to data shared among driver routines. An initialized spin lock, for which the caller supplies resident storage, is a required parameter to the Ndis..SpinLock and NdisInterlocked Xxx functions.
NdisAnsiStringToUnicodeString
Converts a given counted ANSI string into a counted Unicode string.
NdisBufferLength
Returns the length in bytes of a given mapped buffer.
NDIS_BUFFER_LINKAGE
Returns a pointer to a linked buffer, given a pointer to an NDIS buffer descriptor.
NdisBufferVirtualAddress
Returns the base virtual address for the buffer mapped by a given buffer descriptor. It maps the physical pages described by the given buffer descriptor onto system space, if they are not already mapped to system space. Drivers should call NdisBufferVirtualAddressSafe instead of NdisBufferVirtualAddress. NDIS 5.1 miniport drivers must call NdisBufferVirtualAddressSafe instead of NdisBufferVirtualAddress.
NdisBufferVirtualAddressSafe
NdisBufferVirtualAddressSafe is the safe version of NdisBufferVirtualAddress. Unlike NdisBufferVirtualAddress, NdisBufferVirtualAddressSafe will not cause a bug check if system resources are low or exhausted. Drivers should call NdisBufferVirtualAddressSafe instead of NdisBufferVirtualAddress.
NdisCancelTimer
Cancels the immediately preceding call to NdisSetTimer if the interval given to NdisSetTimer has not yet expired.
NdisChainBufferAtBack
Links a given buffer descriptor at the end of the chain of buffer descriptors for a given packet descriptor.
NdisChainBufferAtFront
Links a given buffer descriptor at the start of the chain of buffer descriptors for a given packet descriptor.
NdisClAddParty
Adds a party on a connection-oriented client's multipoint virtual circuit (VC).
NdisClCloseAddressFamily
Releases the association between a connection-oriented client and a call manager's registered address family for a particular NIC to which the client is bound.
NdisClCloseCall
Requests that a connection-oriented client's call be torn down.
NdisClDeregisterSap
Releases a connection-oriented client's registered SAP on which it could receive offers of incoming calls.
NdisClDropParty
Removes a party from a connection-oriented client's multipoint VC.
NdisClGetProtocolVcContextFromTapiCallId
Retrieves the client context for a virtual connection (VC) identified by a TAPI Call ID string.
NdisClIncomingCallComplete
Returns a connection-oriented client's acceptance or rejection of an offered incoming call for which the client previously returned NDIS_STATUS_PENDING.
NdisClMakeCall
Sets up an outgoing call on a VC created by a connection-oriented client.
NdisClModifyCallQoS
Requests a client-initiated change in the quality of service on an active VC.
NdisClOpenAddressFamily
Registers a set of client-supplied functions for connection-oriented communications through a NIC to which the client is bound, using the specified address family registered by a particular call manager.
NdisCloseAdapter
Releases the binding set up with NdisOpenAdapter, given the binding handle that it previously returned.
NdisCloseConfiguration
Releases the handle returned by NdisOpenProtocolConfiguration after the caller has retrieved configuration information and/or, possibly, stored additional information about itself in the registry.
NdisClRegisterSap
Registers a SAP on which a connection-oriented client can receive incoming calls from a remote node.
NdisCmActivateVc
Passes the call parameters, including media parameters, for a particular VC down to the underlying connection-oriented NIC driver so it can set up its NIC for transfers.
NdisCmAddPartyComplete
Returns the final status of a connection-oriented client's request, for which the call manager previously returned NDIS_STATUS_PENDING, to add a party on an active multipoint VC.
NdisCmCloseAddressFamilyComplete
Returns the final status of a connection-oriented client's request, for which the call manager previously returned NDIS_STATUS_PENDING, to close the CM's address family.
NdisCmCloseCallComplete
Returns the final status of a connection-oriented client's request, for which the call manager previously returned NDIS_STATUS_PENDING, to tear down a call.
NdisCmDeactivateVc
Notifies NDIS and the underlying connection-oriented NIC driver to expect no further transfers on a particular VC.
NdisCmDeregisterSapComplete
Returns the final status of a connection-oriented client's request, for which the call manager previously returned NDIS_STATUS_PENDING, to release a previously registered SAP on which the client could receive incoming call notifications.
NdisCmDispatchCallConnected
Notifies NDIS and the connection-oriented client that data transfers can begin on a VC that the call manager created for an incoming call initiated on a remote node.
NdisCmDispatchIncomingCall
Notifies the connection-oriented client of an incoming call offer on a SAP previously registered by that client with the call manager.
NdisCmDispatchIncomingCallQoSChange
Notifies the connection-oriented client that a request to change the quality of service on that client's active connection has been received over the network.
NdisCmDispatchIncomingCloseCall
Tells a connection-oriented client to tear down an active or offered call, usually because the call manager has received a request from the network to close the connection.
NdisCmDispatchIncomingDropParty
Notifies a connection-oriented client that it should remove a particular party on the given mulipoint VC, usually because the call manager has received a close-call request that was initiated at the remote node.
NdisCmDropPartyComplete
Returns the final status of a connection-oriented client's request, for which the call manager previously returned NDIS_STATUS_PENDING, to remove a party from an active multipoint VC.
NdisCmMakeCallComplete
Returns the final status of a connection-oriented client's request, for which the call manager previously returned NDIS_STATUS_PENDING, to make an outgoing call.
NdisCmModifyCallQoSComplete
Returns the final status of a connection-oriented client's request, for which the call manager previously returned NDIS_STATUS_PENDING, to change the quality of service on an active VC.
NdisCmOpenAddressFamilyComplete
Returns the final status of a connection-oriented client's request, for which the call manager previously returned NDIS_STATUS_PENDING, to open the CM's address family.
NdisCmRegisterAddressFamily
Registers a set of call manager-supplied functions for connection-oriented communications using the specified address family and underlying NIC driver identified by the given NdisBindingHandle.
NdisCmRegisterSapComplete
Returns the final status of a connection-oriented client's request, for which the call manager previously returned NDIS_STATUS_PENDING, to register a SAP on which to receive offers of incoming calls from the network.
NdisCoAssignInstanceName
Assigns an instance name to a VC and causes NDIS to register a GUID (globally unique identifier) for the assigned name with Windows Management Instrumentation (WMI).
NdisCoCreateVc
Sets up a connection-oriented endpoint (virtual circuit) from which a client can make outgoing calls or on which a call manager can dispatch incoming calls.
NdisCoDeleteVc
Destroys a caller-created VC.
NdisCoGetTapiCallId
Retrieves a string that TAPI applications can use to identify a particular NDIS virtual connection (VC).
NdisCompletePnPEvent
Completes a protocol's response to a Plug and Play or Power Management event for which the protocol's PnPEventHandler function previously returned NDIS_STATUS_PENDING.
NdisConvertStringToAtmAddress
Converts a Unicode string that contains an ATM address into a ATM_ADDRESS structure that a connection-oriented client can include in a set of call parameters.
NdisCopyLookaheadData
Safely copies receive data indicated in a lookahead buffer to the transport protocol by the underlying NDIS driver.
NdisCoRequest
Issues an OID_GEN_CO_XXX or medium-specific OID_XXX request from a client to a call manager or vice versa and/or from either protocol to the underlying connection-oriented NIC miniport driver to which both are bound.
NdisCoRequestComplete
Returns the final status of an OID_GEN_CO_XXX request, for which the client or call manager previously returned NDIS_STATUS_PENDING, to the protocol that originally issued the request.
NdisCoSendPackets
Forwards a multipacket send on a particular VC to the underlying connection-oriented NIC miniport driver for transmission over the network.
NdisCompleteBindAdapter
Completes a binding operation when the driver returned NDIS_STATUS_PENDING from its ProtocolBindAdapter function.
NdisCompleteUnbindAdapter
Completes a close-adapter operation when the driver returned NDIS_STATUS_PENDING from its ProtocolUnbindAdapter function.
NdisCopyBuffer
Creates a buffer descriptor for a specified virtual (sub)range, given a handle for a block of already allocated memory and a pointer to the memory descriptor for the block.
NdisCopyFromPacketToPacket
Copies a specified number of bytes of data from one packet to another, starting at a specified offset in a given source packet's data and copying the data to a specified offset in the target packet. Returns the number of bytes actually copied, which can be less than the requested number, depending on the source packet and specified starting offset for the copy operation.
NdisDeleteNPagedLookasideList
Removes a nonpaged lookaside list from the system.
NdisDeregisterProtocol
Releases the resources allocated when the driver called NdisRegisterProtocol, given the protocol handle it returned at initialization.
NdisDprAllocatePacket
Allocates and initializes a packet descriptor when the caller is running at IRQL DISPATCH_LEVEL, given a handle returned by a preceding call to NdisAllocatePacketPool.
NdisDprAllocatePacketNonInterlocked
Allocates a packet descriptor when the caller is running at IRQL DISPATCH_LEVEL and that caller provides internal synchronization for accessing packet pool, given a handle returned by a preceding call to NdisAllocatePacketPool.
NdisDprFreePacket
Releases a driver-allocated packet descriptor and returns it to the free list when the caller is running at IRQL DISPATCH_LEVEL.
NdisDprFreePacketNonInterlocked
Releases a packet descriptor that was allocated with NdisDprAllocatePacketNonInterlocked and returns it to the free list.
NdisEqualAnsiString
Compares two ANSI strings and returns whether they are equal.
NdisEqualMemory
Compares a specified number of characters in one block of memory with the same number of characters in a second block of memory.
NdisEqualString
Compares two strings to determine whether they are equal.
NdisEqualUnicodeString
Compares two Unicode strings and returns whether they are equal.
NdisFillMemory
Fills a caller-supplied buffer with the given character.
NdisFreeBuffer
Releases a buffer descriptor obtained in a preceding call to NdisAllocateBuffer or NdisCopyBuffer.
NdisFreeBufferPool
Releases a handle obtained in a preceding call to NdisAllocateBufferPool.
NdisFreeMemory
Releases a handle that was obtained in a preceding call to NdisAllocateMemory.
NdisFreePacket
Releases a packet descriptor that was allocated from packet pool with NdisAllocatePacket and returns it to the free list.
NdisFreePacketPool
Releases a handle to a block of packet pool that was allocated with NdisAllocatePacketPool.
NdisFreeSpinLock
Releases a spin lock initialized in a preceding call to NdisAllocateSpinLock, usually when a driver is unloading.
NdisFreeString
Frees the storage for a buffered string.
NdisFreeToNPagedLookasideList
Returns an entry to the given lookaside list.
NdisGetBufferPhysicalArraySize
Returns the number of physical discontiguities in a buffer, given the buffer descriptor.
NdisGetCurrentProcessorCounts
Returns counts for the current processor that the driver can use to determine CPU utilization for a particular time interval.
NdisGetCurrentProcessorCpuUsage
Returns how busy the current processor is as a percentage.
NdisGetCurrentSystemTime
Returns the current system time, suitable for use as a timestamp.
NdisGetDriverHandle
Retrieves a handle to the NIC miniport driver that owns a bound adapter port, given a handle to the adapter port.
NdisGetFirstBufferFromPacket
Returns pointers to the buffer descriptor and base virtual address for the initial buffer chained to a given packet, along with the sizes of the initial buffer and full buffer, in case the buffer is fragmented. Drivers should call NdisGetFirstBufferFromPacketSafe instead of NdisGetFirstBufferFromPacket. NDIS 5.1 miniports must call NdisGetFirstBufferFromPacketSafe instead of NdisGetFirstBufferFromPacket.
NdisGetFirstBufferFromPacketSafe
NdisGetFirstBufferFromPacketSafe is the safe version of NdisGetFirstBufferFromPacket. Unlike NdisGetFirstBufferFromPacket, NdisGetFirstBufferFromPacketSafe does not cause a bug check if system resources are low or exhausted. Drivers should call NdisGetFirstBufferFromPacketSafe instead of NdisGetFirstBufferFromPacket.
NdisGetNextBuffer
Returns the next buffer descriptor in a chain, given the current buffer descriptor.
NDIS_GET_ORIGINAL_PACKET
Returns a pointer to a packet descriptor that the lowest-level driver in a layered stack of NDIS drivers indicated. The calling driver should access the out-of-band (OOB) data block from this original packet rather than the packet that the driver below the calling driver indicated. If the calling driver is not part of a layered stack, the returned packet descriptor will be identical to the packet that the driver below the calling driver indicated.
NdisGetPacketFlags
Returns the flags, if any, set by a higher-level protocol driver in a given packet.
NDIS_GET_PACKET_HEADER_SIZE
Returns the number of bytes in a received net packet header from the HeaderSize set in the NDIS_PACKET_OOB_DATA block associated with a given packet descriptor by the indicating miniport driver.
NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO
Returns a pointer to buffered out-of-band information, such as packet priority, and the number of bytes in the buffer from the MediaSpecificInformation and SizeMediaSpecificInfo set in the NDIS_PACKET_OOB_DATA block associated with a given packet descriptor by the indicating miniport driver.
NDIS_GET_PACKET_TIME_RECEIVED
Returns the TimeReceived timestamp from the NDIS_PACKET_OOB_DATA block associated with an indicated receive packet.
NDIS_GET_PACKET_TIME_SENT
Returns the TimeSent timestamp from the associated NDIS_PACKET_OOB_DATA block associated with an indicated receive packet.
NdisGetReceivedPacket
Retrieves a packet that was received from the underlying driver.
NdisGetSystemUpTime
Returns the number of milliseconds that have elapsed since the system was booted.
NdisIMDeInitializeDeviceInstance
Calls an NDIS intermediate driver's MiniportHalt function to tear down the driver's virtual NIC.
NdisIMGetBindingContext
Allows an NDIS protocol to access the device context area, created by an underlying intermediate driver, for a virtual NIC to which the higher level protocol is bound.
NdisIMInitializeDeviceInstance
Calls an NDIS intermediate driver's MiniportInitialize function to set up the driver's virtual NIC for I/O operations bound for an underlying NIC driver to which the intermediate driver is bound.
NdisIMInitializeDeviceInstanceEx
Calls an NDIS intermediate driver's MiniportInitialize function to initialize the driver's virtual NIC and optionally to set up state information about the driver's virtual NIC for subsequently bound protocols.
NdisIMRegisterLayeredMiniport
Registers an NDIS intermediate driver's MiniportXxx entry points and name with the NDIS library when the driver initializes.
NdisInitAnsiString
Initializes a counted ANSI string.
NDIS_INIT_FUNCTION
Marks a given driver function as initialization-only code to be discarded after the function has run once.
NdisInitializeEvent
Sets up an event object during driver initialization to be used subsequently as a synchronization mechanism.
NdisInitializeListHead
Sets up a queue header for a driver's internal queue, given a pointer to driver-supplied resident storage for the queue header and queue. Then, entries (usually packets) can be added to and removed from the doubly-linked queue with the NdisInterlocked..List functions.
NdisInitializeNPagedLookasideList
Initializes a lookaside list. After a successful initialization, nonpaged fixed-size blocks can be allocated from and freed to the lookaside list.
NdisInitializeReadWriteLock
Initializes a variable of type NDIS_RW_LOCK. An NDIS_RW_LOCK variable is used to limit write access to shared resources to one nonISR-driver thread at a time. This NDIS_RW_LOCK can allow multiple nonISR-driver threads concurrent read access to those resources. Such read access is not permitted during a write access.
NdisInitializeSListHead
Initializes the head of a sequenced, interlocked, singly linked list.
NdisInitializeString
Allocates a buffer for and initializes a counted string in the system-default character set, given a source string and a NULL pointer.
NdisInitializeTimer
Initializes a timer object associated with a driver's timer function.
NdisInitUnicodeString
Initializes a counted Unicode string.
NdisInitializeWorkItem
Initializes a work-queue item with a caller-supplied context and callback routine to be queued for execution when a system worker thread is given control.
NdisInterlockedAddUlong
Adds an unsigned long value to a given unsigned integer as an atomic operation, using a caller-supplied and initialized spin lock.
NdisInterlockedDecrement
Decrements a caller supplied variable of type LONG as an atomic operation.
NdisInterlockedIncrement
Increments a caller supplied variable as an atomic operation.
NdisInterlockedInsertHeadList
Inserts an entry, usually a packet, at the head of a doubly linked list using a caller-supplied and initialized spin lock so that access to queued entries is synchronized in a multiprocessor-safe way among driver functions.
NdisInterlockedInsertTailList
Inserts an entry, usually a packet, at the end of a doubly linked list using a caller-supplied and initialized spin lock so that access to queued entries is synchronized in a multiprocessor-safe way among driver functions.
NdisInterlockedPopEntrySList
removes the first entry from a sequenced, singly linked list.
NdisInterlockedPushEntrySList
Inserts an entry at the head of a sequenced, singly linked list.
NdisInterlockedRemoveHeadList
Removes an entry, usually a packet, from the head of a doubly linked list using a caller-supplied and initialized spin lock so that access to queued entries is synchronized in a multiprocessor-safe way among driver functions.
NdisMoveMemory
Copies a specified number of bytes from one caller-supplied location to another.
NdisMSetAttributesEx
Informs the NDIS library about significant features of an intermediate driver's virtual NIC and prevents NDIS from timing out sends and requests in the intermediate driver.
NDIS_OOB_DATA_FROM_PACKET
Returns a pointer to the NDIS_PACKET_OOB_DATA block associated with a given packet descriptor.
NdisOpenAdapter
Sets up a binding between the caller and an underlying NIC driver, given an array of medium types that the protocol driver supports, the number of elements in the supplied array, the handle already returned by NdisRegisterProtocol, a handle to a protocol-supplied context area to be passed back to the protocol in subsequent receive indications, the name of the NIC to be opened, a mask set with the caller's preferred open options, and, possibly, a pointer to some caller-supplied addressing information, as well as four caller-specified locations at which NdisOpenAdapter returns values. If the call succeeds, NdisOpenAdapter returns a binding handle for the protocol to use in subsequent Ndis Xxx calls that forward device I/O requests to the NIC driver, an index specifying the NIC driver's preferred medium type, and NDIS_STATUS_SUCCESS; otherwise, it returns both a general failure status and an informational error status.
NdisOpenConfigurationKeyByIndex
Opens a subkey of a given open registry key designated by a caller-supplied handle.
NdisOpenConfigurationKeyByName
Opens a named subkey of a given open registry key designated by a caller-supplied handle.
NdisOpenProtocolConfiguration
Returns a handle for the registry key in which a protocol driver's per-adapter information is stored. This handle is a required parameter to other Ndis Xxx configuration functions.
NDIS_PACKET_EXTENSION_FROM_PACKET
Returns a pointer to the NDIS_PACKET_EXTENSION structure associated with a packet descriptor.
NdisPacketPoolUsage
Returns the number of packet descriptors currently allocated from a packet pool.
NDIS_PAGABLE_FUNCTION
Marks a driver function as pageable code.
NDIS_PER_PACKET_INFO_FROM_PACKET
Returns a pointer to a specific type of per-packet information associated with a packet descriptor.
NdisPrintString
Displays a given string in the debugging window.
NdisQueryAdapterInstanceName
Retrieves the friendly name of a physical NIC or a virtual adapter to which the calling protocol is bound.
NdisQueryBuffer
Retrieves the size of the range, and optionally its base virtual address, specified in a given buffer descriptor. Drivers should call NdisQueryBufferSafe instead of NdisQueryBuffer.
NdisQueryBufferOffset
Retrieves the base virtual address of the range specified in a given buffer descriptor.
NdisQueryBufferSafe
NdisQueryBufferSafe is the safe version of NdisQueryBuffer. Unlike NdisQueryBuffer, NdisQueryBufferSafe does not cause a bug check if system resources are low or exhausted. Drivers should call NdisQueryBufferSafe instead of NdisQueryBuffer.
NdisQueryDepthSList
Returns the current number of entries in a given sequenced, singly linked list.
NdisQueryPacket
Returns any or all of the following information about a given packet descriptor: a count of buffer descriptors chained to the packet descriptor, the total number of bytes in all buffers mapped by the buffer descriptor chained to the packet descriptor, the total number of physically discontiguous blocks for all such buffers, and a pointer to the initial buffer descriptor in the chain.
NdisReadConfiguration
Reads the value of a named entry of the specified type, given the registry handle returned by NdisOpenProtocolConfiguration.
NdisRecalculatePacketCounts
Resets the valid counts of chained buffer descriptors for a given packet descriptor.
NdisRegisterProtocol
Registers a protocol driver's upper-edge entry points (ProtocolXxx) and name with the NDIS library, given a pointer to the NDIS_PROTOCOL_CHARACTERISTICS structure set up by the caller and the size in bytes of this structure. NDIS returns the status of the registration attempt and, if the call is successful, a protocol handle representing the driver, which can be passed in a subsequent call to NdisOpenAdapter.
NdisReinitializePacket
Sets to NULL the queue head for any chained buffers in a given packet descriptor and reinitializes it for reuse.
NdisReleaseReadWriteLock
Releases a lock that was acquired in a preceding call to NdisAcquireReadWriteLock.
NdisReleaseSpinLock
Releases a spin lock that was acquired in a preceding call to NdisAcquireSpinLock.
NdisRequest
Forwards a caller-initialized NDIS_REQUEST-type query or set request to the underlying NIC driver, given the binding handle previously returned by NdisOpenAdapter.
NdisReset
Forwards a reset request to the underlying NIC driver, given the binding handle and a pointer to a variable in which the status of the reset operation is returned.
NdisResetEvent
Clears the Signaled state of a given event.
NdisRetrieveUlong
Retrieves a ULONG value from the source address, avoiding alignment faults.
NdisReturnPackets
Releases ownership of one or more receive packets after a protocol driver has consumed the receive data.
NdisScheduleWorkItem
Inserts a given work item into a queue from which a system worker thread removes the item and gives control to the callback function that the driver previously supplied to NdisInitializeWorkItem.
NdisSend
Forwards a packet to the NIC driver for transmission over the wire, given the binding handle, a pointer to the packet to be sent, and a pointer to a variable in which the status of the send is returned.
NdisSendPackets
Forwards a multipacket send request, possibly specifying out-of-band information for each packet in the array, such as packet priority, to the underlying driver.
NdisSetEvent
Sets a given event to the Signaled state if it was not already Signaled, thereby causing waits on the event to be satisfied.
NdisSetPacketFlags
Sets the Flags member in a given packet descriptor to the given value, before the protocol calls NdisSendPackets or NdisSend.
NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO
Sets the MediaSpecificInformation and SizeMediaSpecificInfo in the NDIS_PACKET_OOB_DATA block, specifying out-of-band information associated with a protocol-allocated packet descriptor for a send request.
NDIS_SET_PACKET_TIME_TO_SEND
Sets the TimeToSend timestamp in the NDIS_PACKET_OOB_DATA block associated with a protocol-allocated packet descriptor, specifying when the underlying driver should transmit the packet data over the wire.
NdisSetSendFlags
See NdisSetPacketFlags.
NdisSetTimer
Sets a timer object to fire after a specified interval, thereby running an associated timer function after the timer fires.
NdisStoreUlong
Stores a ULONG value at a particular address, avoiding alignment faults.
NdisTransferData
Forwards a request that the underlying NIC driver transfer (copy) received data to a supplied packet, given the binding handle, the receive-context handle passed to the protocol when the receive was indicated, the byte offset in the indication at which to start the transfer and the number of bytes to transfer, and pointers to variables in which the status of the completed transfer operation and the number of bytes actually transferred are returned.
NdisUnchainBufferAtBack
Removes a given buffer descriptor at the end of the chain of buffer descriptors for a given packet descriptor and returns a pointer to the buffer descriptor.
NdisUnchainBufferAtFront
Removes a given buffer descriptor at the start of the chain of buffer descriptors for a given packet descriptor and returns a pointer to the buffer descriptor.
NdisUnicodeStringToAnsiString
Converts a given counted Unicode string into a counted ANSI string.
NdisUpcaseUnicodeString
Converts a copy of a given Unicode string to upper case and returns the converted string.
NdisWaitEvent
Puts the caller into a wait state until the given event is set to the Signaled state or the wait times out.
NdisWriteConfiguration
Writes a caller-supplied value entry in the registry, given the handle returned by NdisOpenProtocolConfiguration.
NdisWriteErrorLogEntry
Allocates an error-log record, fills it in, and writes it to the I/O error log, given a binding handle for the underlying NIC, an NDIS_XXX error code, a count of caller-supplied error values, and a corresponding number of ULONGs specifying additional information about the I/O error or configuration error.
NdisWriteEventLogEntry
Logs an event to the Win32 event log.
NdisZeroMemory
Fills a block of memory with zeros, given a pointer to the block and the length in bytes to be filled.

Highest-level NDIS drivers that export only the lower-edge ProtocolXxx functions also can call support routines exported by other kernel-mode components. For more information about these support routines, see Summary of Kernel-Mode Support Routines.


NDIS Library Function References

Functions and macros described here are in alphabetical order. They include all macros and functions defined in the master header, ndis.h, or in a system-supplied filter-library header, _filter.h, that NDIS protocol, miniport, WAN miniport, and intermediate drivers call.

To ensure their portability across Windows® 2000 and later platforms and binary compatibility across Microsoft operating systems that support Win32®, NDIS miniport drivers should call only the functions described here. Such a miniport driver might require recompilation for different Windows 2000 and later platforms and separate installation scripts to install its NIC on all Microsoft Win32 platforms but such a device driver is otherwise OS-independent.

On the other hand, NDIS intermediate drivers that have both NDIS-defined upper-edge (MiniportXxx) and lower-edge (ProtocolXxx) functions and highest-level NDIS transport protocol drivers usually call additional driver support routines provided by the operating system. For more information about kernel-mode support routines that can be called by NDIS intermediate and highest-level protocol drivers, see Summary of Kernel-Mode Support Routines.

For a summary of the NDIS functions and macros used by protocol drivers, by miniport drivers, and/or by WAN miniport drivers, respectively, see NDIS Library Functions.

For a summary of obsolete NDIS functions and macros, which support only legacy drivers, see Obsolete NdisXxx Functions and Macros.


ETH_COPY_NETWORK_ADDRESS

ETH_COPY_NETWORK_ADDRESS copies a given Ethernet address to a given location.

VOID
  ETH_COPY_NETWORK_ADDRESS(
    OUT PCHAR  D,
    IN PCHAR  S
    );

Parameters

D
Pointer to a caller-supplied variable to which this function copies the source address.
S
Pointer to the source address.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Callers of this macro can be running at any IRQL as long as the source and destination address pointers are resident.


FDDI_COMPARE_NETWORK_ADDRESSES

FDDI_COMPARE_NETWORK_ADDRESSES sets a caller-supplied variable to a value indicating whether a given FDDI address is greater than, less than, or equal to another given FDDI address.

VOID
  FDDI_COMPARE_NETWORK_ADDRESSES(
    IN PUCHAR  A,
    IN PUCHAR  B,
    IN ULONG  AddressLength,
    OUT PINT  Result
    );

Parameters

A
Pointer to the first network address.
B
Pointer to the second network address.
AddressLength
Specifies the length in bytes of the addresses (either 2 or 6).
Result
Pointer to a caller-supplied variable in which this macro returns the result of its comparison as one of the following values:
Result < zero
B is greater than A.
Result > zero
A is greater than B.
Zero
A equals B.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A caller can use the FDDI_LENGTH_OF_SHORT_ADDRESS and FDDI_LENGTH_OF_LONG_ADDRESS constants, corresponding to two and six bytes, respectively, as the value for AddressLength.

FDDI network addresses do not have a defined ordering relationship. Consequently, the results of this macro for unequal addresses depend on the argument ordering.

Callers of this macro can be running at any IRQL if all pointer parameters access resident memory.


FDDI_IS_BROADCAST

FDDI_IS_BROADCAST sets a caller-supplied variable to a Boolean value indicating whether a given FDDI address is a broadcast address.

VOID
  FDDI_IS_BROADCAST(
    IN PUCHAR  Address,
    IN ULONG  AddressLength,
    OUT PBOOLEAN  Result
    );

Parameters

Address
Pointer to a network address.
AddressLength
Specifies the size in bytes of the address (either 2 or 6).
Result
Pointer to a caller-supplied variable in which this macro returns TRUE if the given address is broadcast.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A caller can use the FDDI_LENGTH_OF_SHORT_ADDRESS and FDDI_LENGTH_OF_LONG_ADDRESS constants, corresponding to two and six bytes, respectively, as the value for AddressLength.

A broadcast address applies to all stations in the extended network.

Callers of this macro can be running at any IRQL as long as the source address and supplied variable are resident.

See Also

FDDI_IS_MULTICAST


FDDI_IS_MULTICAST

FDDI_IS_MULTICAST sets a caller-supplied variable to a Boolean value indicating whether a given FDDI address is a multicast address.

VOID
  FDDI_IS_MULTICAST(
    IN PUCHAR  Address,
    IN ULONG  AddressLength,
    OUT PBOOLEAN  Result
    );

Parameters

Address
Pointer to a network address.
AddressLength
Specifies the size in bytes of the address (either 2 or 6).
Result
Pointer to a caller-supplied variable in which this macro returns TRUE if the given address is multicast.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A caller can use the FDDI_LENGTH_OF_SHORT_ADDRESS and FDDI_LENGTH_OF_LONG_ADDRESS constants, corresponding to two and six bytes, respectively, as the value for AddressLength.

A multicast address applies to zero or more stations in a network and can be bridged to the extended network.

Callers of this macro can be running at any IRQL as long as the source address and supplied variable are resident.

See Also

FDDI_IS_BROADCAST


FDDI_IS_SMT

FDDI_IS_SMT sets a caller-supplied variable to a Boolean value indicating whether a given FDDI frame is SMT.

VOID
  FDDI_IS_SMT(
    IN UCHAR  FcByte,
    OUT PBOOLEAN  Result
    );

Parameters

FcByte
Specifies the FC code retrieved from the packet.
Result
Pointer to a caller-supplied variable in which this macro returns TRUE if the given FC byte indicates an SMT frame.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Callers of this macro can be running at any IRQL as long as the source address and supplied variable are resident.

See Also

FDDI_IS_BROADCAST, FDDI_IS_MULTICAST


NdisAcquireReadWriteLock

NdisAcquireReadWriteLock acquires a lock that the caller uses for either write or read access to the resources that are shared among driver threads.

VOID
  NdisAcquireReadWriteLock(
    IN PNDIS_RW_LOCK  Lock,
    IN BOOLEAN  fWrite,
    IN PLOCK_STATE  LockState
    );

Parameters

Lock
Pointer to an opaque variable that represents a lock. The caller can use this lock to access shared resources.
fWrite
Specifies a Boolean value. If the value is TRUE, this function is provided with write access to shared resources; if the value is FALSE, this function is provided with read access.
LockState
Pointer to an opaque variable that tracks the state of the lock. This variable exists in the interval between the time the caller acquires and releases the lock. The caller must use a different variable of type LOCK_STATE for each attempt it makes to acquire the lock from the same nonISR-driver thread.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The driver must initialize a variable of type NDIS_RW_LOCK using NdisInitializeReadWriteLock before the driver calls any other Ndis..ReadWriteLock function. The driver must provide resident storage for the locks it uses.

After acquiring a lock by using NdisAcquireReadWriteLock, the caller must release that lock by calling NdisReleaseReadWriteLock. To decrement the reference count of the lock, a driver must call NdisReleaseReadWriteLock once for each call to NdisAcquireReadWriteLock.

To modify resources shared among driver threads, a driver thread must acquire a write lock. To simply monitor those resources, a driver thread must acquire a read-only lock. Read access does not require interlocked operations or contention for spin locks. Using read-only access helps to maintain good operating system and driver performance.

A driver thread should never hold a write lock for more than 25 microseconds. Holding a write lock for a prolonged period degrades both operating system and driver performance.

The driver cannot use a lock to protect resources from read or write access that its other functions share with the MiniportISR and/or MiniportDisableInterrupt functions. Instead, the driver must call NdisMSynchronizeWithInterrupt so that its MiniportSynchronizeISR function accesses such shared resources at the same DIRQL at which its MiniportISR and/or MiniportDisableInterrupt functions do.

Callers of NdisAcquireReadWriteLock run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportDisableInterrupt, MiniportISR, MiniportSynchronizeISR, NdisInitializeReadWriteLock, NdisMSynchronizeWithInterrupt, NdisReleaseReadWriteLock


NdisAcquireSpinLock

NdisAcquireSpinLock acquires a spin lock so the caller gains exclusive access to the resources, shared among driver functions, that the spin lock protects.

VOID
  NdisAcquireSpinLock(
    IN PNDIS_SPIN_LOCK  SpinLock
    );

Parameters

SpinLock
Pointer to an opaque spin lock, already initialized by the caller.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The driver must initialize a variable of type NDIS_SPIN_LOCK with NdisAllocateSpinLock before it calls any other Ndis..SpinLock function. The driver must provide resident storage for the spin lock(s) it uses.

After acquiring a spin lock with NdisAcquireSpinLock, the caller must release that lock with a call to NdisReleaseSpinLock. A driver must call NdisReleaseSpinLock following each call to NdisAcquireSpinLock. Otherwise, a deadlock occurs, hanging the driver.

A spin lock acquired with NdisAcquireSpinLock must be released with NdisReleaseSpinLock. A spin lock acquired with NdisDprAcquireSpinLock must be released with NdisDprReleaseSpinLock.

A driver should never hold a spin lock for an extended period (more than a few instructions). Holding a spin lock for longer than 25 microseconds degrades both system and driver performance.

A miniport driver cannot use a spin lock to protect resources that its other functions share with the MiniportISR and/or MiniportDisableInterrupt functions. Instead, a miniport driver must call NdisMSynchronizeWithInterrupt so that its MiniportSynchronizeISR function accesses such shared resources at the same DIRQL at which its MiniportISR and/or MiniportDisableInterrupt functions do.

Callers of NdisAcquireSpinLock run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportDisableInterrupt, MiniportHalt, MiniportInitialize, MiniportISR, MiniportSynchronizeISR, NdisAllocateSpinLock, NdisDprAcquireSpinLock, NdisMSynchronizeWithInterrupt, NdisReleaseSpinLock


NdisAdjustBufferLength

NdisAdjustBufferLength modifies the length specified in a buffer descriptor allocated or copied by the caller.

VOID
  NdisAdjustBufferLength(
    IN PNDIS_BUFFER  Buffer,
    IN UINT  Length
    );

Parameters

Buffer
Pointer to the buffer descriptor, previously allocated with NdisAllocateBuffer or NdisCopyBuffer.
Length
Specifies the new length in bytes to be set in the buffer descriptor.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The caller of NdisAdjustBufferLength can pass only a buffer descriptor that was allocated by the caller. It cannot pass a buffer descriptor that was allocated by another driver.

For example, the driver of a bus-master DMA NIC calls this function with buffer descriptors that it allocated to specify receive buffers in its shared memory block. Before such a driver indicates received data, it calls NdisAdjustBufferLength to make the buffer descriptor that it will include in the receive indication match the size of the received data if it is less than the size of the NIC's receive buffer. When a receive packet with such an adjusted buffer descriptor has been consumed and returned to the miniport driver, the driver again calls NdisAdjustBufferLength to make the buffer descriptor match the actual size of its receive buffer again.

The Length passed to NdisAdjustBufferLength cannot be larger than the Length that was passed to NdisAllocateBuffer or NdisCopyBuffer when the buffer descriptor was allocated.

The caller of NdisAdjustBufferLength must restore the length to its original value before it frees the buffer descriptor with NdisFreeBuffer.

The driver must release any spin lock it is currently holding before calling NdisAdjustBufferLength.

Callers of NdisAdjustBufferLength can run at any IRQL, but usually run at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocateBuffer, NdisCopyBuffer, NdisFreeBuffer, NdisReleaseSpinLock


NdisAllocateBuffer

NdisAllocateBuffer creates a buffer descriptor mapping a specified virtual (sub)range within an already allocated, nonpaged memory block.

VOID
  NdisAllocateBuffer(
    OUT PNDIS_STATUS  Status,
    OUT PNDIS_BUFFER  *Buffer,
    IN NDIS_HANDLE  PoolHandle,
    IN PVOID  VirtualAddress,
    IN UINT  Length
    );

Parameters

Status
Pointer to a caller-supplied variable in which this function returns the final status of the buffer allocation, which is NDIS_STATUS_SUCCESS if it returned a valid buffer descriptor pointer at Buffer and otherwise NDIS_STATUS_FAILURE.
Buffer
Pointer to a caller-supplied variable in which this function returns a pointer to the allocated buffer descriptor.
PoolHandle
Specifies the handle returned by a preceding call to NdisAllocateBufferPool.
VirtualAddress
Pointer to the base virtual address of previously allocated system-space memory to be mapped in the returned buffer descriptor.
Length
Specifies the number of bytes to be mapped.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisAllocateBuffer allocates storage for and initializes a buffer descriptor to map a specified range of previously allocated memory, such as memory used for a packet header or a NIC receive buffer.

Buffer descriptor allocation draws on the buffer pool that NdisAllocateBufferPool creates. A driver can call NdisAllocateBuffer as many times as necessary to allocate the buffer descriptors that it requires if it called NdisAllocateBufferPool during initialization.

All lower-level NDIS drivers must allocate all buffer descriptors that they chain to packets from buffer pool. Only highest-level protocol drivers can be given OS-dependent descriptors mapping virtual memory ranges, and, if these memory descriptors are equivalent to NDIS buffer descriptors, a highest-level protocol can pass such descriptors as parameters to Ndis Xxx functions.

Callers of NdisAllocateBuffer run at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocateBufferPool, NdisAllocateMemory, NdisFreeBuffer


NdisAllocateBufferPool

NdisAllocateBufferPool returns a handle with which the caller can allocate buffer descriptors by calling NdisAllocateBuffer.

VOID
  NdisAllocateBufferPool(
    OUT PNDIS_STATUS  Status,
    OUT PNDIS_HANDLE  PoolHandle,
    IN UINT  NumberOfDescriptors
    );

Parameters

Status
Pointer to a caller-supplied variable in which this function returns the final status of the buffer pool allocation, which is always NDIS_STATUS_SUCCESS.
PoolHandle
Pointer to a caller-supplied variable in which this function returns a handle to the buffer pool. This handle is a required parameter to the Ndis..Buffer functions that the driver calls subsequently.
NumberOfDescriptors
Specifies the number of buffer descriptors the caller expects to allocate from the buffer pool without releasing any allocated buffer descriptors back to the pool.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

After NdisAllocateBufferPool returns, the driver calls NdisAllocateBuffer one or more times to allocate the buffer descriptors that it requires. A driver should call NdisAllocateBufferPool during initialization.

The NumberOfDescriptors specified by a NIC driver usually depends on the features of the NIC. For example, the driver of a bus-master DMA NIC with ring buffers would specify at least a large enough NumberOfDescriptors to map the full ring.

The NumberOfDescriptors specified in the call to NdisAllocateBufferPool is the effective limit on how many times the driver can call NdisAllocateBuffer before it must call NdisFreeBuffer to return a buffer descriptor to the free list for the buffer pool.

When a driver no longer needs the buffer pool it allocated, it calls NdisFreeBufferPool to release the buffer pool handle.

All lower-level NDIS drivers must allocate all buffer descriptors that they chain to packets from buffer pool. Only highest-level protocol drivers can be given OS-dependent descriptors mapping virtual memory ranges, and, if these memory descriptors are equivalent to NDIS buffer descriptors, a highest-level protocol can pass such descriptors as parameters to Ndis Xxx functions.

Callers of NdisAllocateBufferPool run at IRQL <= DISPATCH_LEVEL.

See Also

NdisAdjustBufferLength, NdisAllocateBuffer, NdisChainBufferAtBack, NdisChainBufferAtFront, NdisCopyBuffer, NdisCreateLookaheadBufferFromSharedMemory, NdisFreeBuffer, NdisFreeBufferPool, NdisQueryBuffer, NdisQueryBufferSafe, NdisReleaseSpinLock


NdisAllocateFromNPagedLookasideList

NdisAllocateFromNPagedLookasideList removes the first entry from the given lookaside list head. If the lookaside list currently is empty, an entry is allocated from nonpaged pool.

PVOID
  NdisAllocateFromNPagedLookasideList(
    IN PNPAGED_LOOKASIDE_LIST  Lookaside
    );

Parameters

Lookaside
Pointer to the head of the lookaside list from which the entry will be allocated. The caller already initialized the list head with NdisInitializeNPagedLookasideList.

Return Value

NdisAllocateFromNPagedLookasideList returns a pointer to an entry if one can be removed from the lookaside list or allocated; otherwise, it returns NULL.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If the lookaside list is not empty, NdisAllocateFromNPagedLookasideList removes the first entry from the list and returns its address to the caller. If the lookaside list is empty, NdisAllocateFromNPagedLookasideList either calls the Allocate function that the caller specified at list initialization, if any, or it allocates an entry on behalf of the caller. NdisAllocateFromNPagedLookasideList returns NULL if the caller-supplied Allocate function, if any, or if this function itself cannot allocate an nonpaged entry.

All entries allocated from a nonpaged lookaside list are of a fixed size, specified when the driver originally called NdisInitializedNPagedLookasideList. Consequently, a lookaside list is particularly useful to drivers that must allocate fixed-size blocks in which to maintain state in response to dynamic I/O demand. For example, any connection-oriented NDIS driver might allocate the VC context areas it needs from a lookaside list as VCs are created and release each such entry back to the lookaside list with NdisFreeToNPagedLookasideList as each VC is torn down.

Callers of NdisAllocateFromNPagedLookasideList must be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisDeleteNPagedLookasideList, NdisFreeToNPagedLookasideList, NdisInitializeNPagedLookasideList


NdisAllocateMemory

NdisAllocateMemory allocates resident (nonpaged) system-space memory, optionally within a specified address limit, as a physically contiguous allocation, and/or as a noncached allocation.

NDIS_STATUS
  NdisAllocateMemory(
    OUT PVOID  *VirtualAddress,
    IN UINT  Length,
    IN UINT  MemoryFlags,
    IN NDIS_PHYSICAL_ADDRESS  HighestAcceptableAddress
    );

Parameters

VirtualAddress
Pointer to a caller-supplied variable in which this function returns the base virtual address of the allocated memory or NULL if memory of the specified type is unavailable.
Length
Specifies the size in bytes to be allocated.
MemoryFlags
Specifies zero or a bitmask designating the type(s) of memory to allocate, as follows:
Value | Meaning
zero Allocate nonpaged system-space memory.

Note: You should call NdisAllocateMemoryWithTag to allocate nonpaged system-space memory.
NDIS_MEMORY_CONTIGUOUS | Allocate physically contiguous memory.
NDIS_MEMORY_NONCACHED | Allocate noncached memory.

Only NIC drivers specify the allocation of contiguous and/or noncached memory during driver initialization. These two flags can be ORed into MemoryFlags before NdisAllocateMemory is called.

HighestAcceptableAddress
Specifies -1.

Return Value

NdisAllocateMemory can return either of the following:

NDIS_STATUS_SUCCESS
The caller can use the allocated memory range starting at the value returned at VirtualAddress.
NDIS_STATUS_FAILURE
An attempt to allocate the requested memory failed. This return does not necessarily mean that a subsequent call will fail.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Any NDIS driver might call NdisAllocateMemory with the MemoryFlags set to zero. For example, NDIS drivers that export a set of NDIS upper-edge (MiniportXxx) functions can call NdisAllocateMemory to allocate a context area in which the driver will maintain per-NIC (or per-virtual-NIC) runtime state information and pass the pointer returned at VirtualAddress to NdisMSetAttributes(Ex). NDIS drivers that export a set of NDIS lower-edge (ProtocolXxx) functions also can call NdisAllocateMemory whenever such a driver needs to allocate buffer space.

Only miniport drivers can set the MemoryFlags with either or both of the NDIS_MEMORY_XXX when they make initialization-time calls to NdisAllocateMemory. During initialization, miniport drivers allocate these types of memory to be shared with their NICs.

If such a miniport driver specifies physically contiguous memory in a call to NdisAllocateMemory, the virtual memory allocation maps to a single physically contiguous region. If a miniport driver specifies noncached memory, the allocated virtual range is not cached. A NIC driver can access noncached memory without flushing cache buffers during DMA operations.

Whatever the value of the input MemoryFlags, a successful caller of NdisAllocateMemory uses a range of virtual addresses to access the allocated memory. Depending on the size of the allocation and on the type of memory requested, one or more physical memory ranges (pages) back this single virtual range.

While the NDIS_MEMORY_XXX can be ORed in MemoryFlags to request a contiguous and noncached allocation by a NIC driver, both contiguous and noncached memory are very limited system resources. A NIC driver should never request more contiguous memory and/or more noncached memory than it needs. Attempts to allocate either of these types of memory except during driver initialization are a programming error. Such an attempt is unlikely to be successful because system-space memory becomes fragmented due to allocations by other kernel-mode components, including other drivers, and due to runtime paging.

If such an initialization-time call fails, a NIC driver can attempt to allocate one or more smaller blocks of contiguous and/or noncached memory, rather than failing to initialize if it cannot allocate a large block.

Callers of NdisAllocateMemory can run at IRQL <= DISPATCH_LEVEL to allocate memory from nonpaged pool. NIC drivers that allocate contiguous and/or noncached memory must be running at IRQL PASSIVE_LEVEL during initialization.

See Also

MiniportInitialize, NdisAllocateMemoryWithTag, NdisFreeMemory, NdisMAllocateSharedMemory, NdisMSetAttributes, NdisMSetAttributesEx


NdisAllocateMemoryWithTag

NdisAllocateMemoryWithTag allocates resident (nonpaged) system-space memory.

NDIS_STATUS
  NdisAllocateMemoryWithTag(
    OUT PVOID  *VirtualAddress,
    IN UINT  Length,
    IN ULONG  Tag
    );

Parameters

VirtualAddress
Pointer to a caller-supplied variable in which this function returns the base virtual address of the allocated memory or NULL if sufficient nonpaged memory is currently unavailable.
Length
Specifies the size in bytes to be allocated.
Tag
Is a string, delimited by single quote marks, with up to four characters, usually specified in reversed order. The NDIS-supplied default tag for this call is 'maDN', but the caller can override this default by supplying an explicit value.

Return Value

NdisAllocateMemoryWithTag can return either of the following:

NDIS_STATUS_SUCCESS
The caller can use the allocated memory range starting at the value returned at VirtualAddress.
NDIS_STATUS_FAILURE
An attempt to allocate the requested memory failed. This return does not necessarily mean that a subsequent call will fail.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A call to NdisAllocateMemoryWithTag is equivalent to calling NdisAllocateMemory, except that NdisAllocateMemoryWithTag allows the caller to supply a tag that appears in any crash dump of the system that occurs subsequently.

During driver development on a checked build of the system, this function also can be useful for crash debugging. Calling this routine, rather than NdisAllocateMemory, inserts the caller-supplied tag into a crash dump of pool memory.

The Tag passed to this function is more readable if its characters are reversed when NdisAllocateMemoryWithTag is called. For example, if a caller passes 'Fred' as a Tag, it would appear as 'derF' if pool is dumped or when tracking pool usage in the debugger. The NDIS-supplied default tag appears as 'NDam' (indicating NDIS allocate memory) when pool is dumped.

Callers of NdisAllocateMemoryWithTag can be running at IRQL <= DISPATCH_LEVEL.

See Also

MiniportInitialize, NdisAllocateMemory, NdisFreeMemory, NdisMAllocateSharedMemory, NdisMSetAttributes, NdisMSetAttributesEx


NdisAllocatePacket

NdisAllocatePacket allocates and initializes a packet descriptor.

VOID
  NdisAllocatePacket(
    OUT PNDIS_STATUS  Status,
    OUT PNDIS_PACKET  *Packet,
    IN NDIS_HANDLE  PoolHandle
    );

Parameters

Status
Pointer to a caller-supplied variable in which this function returns the final status of the request, which can be one of the following:
NDIS_STATUS_SUCCESS
The caller can use the packet descriptor returned at Packet. A subsequent call to NdisFreePacket will return the given entry to the free list.
NDIS_STATUS_RESOURCES
The free list for the packet pool currently has no available entries.
Packet
Pointer to a caller-supplied variable in which this function returns a pointer to the allocated packet descriptor.
PoolHandle
Specifies the handle returned by a preceding call to NdisAllocatePacketPool.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NDIS drivers must allocate packet descriptors from packet pool. Protocol drivers call NdisAllocatePacket one or more times for their subsequent calls to NdisSend or NdisSendPackets. Miniport drivers call NdisAllocatePacket one or more times for subsequent calls to NdisMIndicateReceivePacket. NDIS intermediate drivers must call NdisAllocatePacket to repackage sends and receive indications in fresh packet descriptors before passing incoming transfer requests on to other NDIS drivers.

Each packet descriptor will eventually have one or more buffer descriptors chained to it. NdisAllocatePacket zero-initializes the packet descriptor and sets its buffer chain pointer to NULL. The caller must chain the buffer descriptor(s) mapping the packet data to the packet descriptor before it is sent or indicated. Most NDIS drivers allocate buffer descriptors with NdisAllocateBuffer.

Drivers must use the NDIS_GET/SET_PACKET_XXX macros or NDIS_OOB_DATA_FROM_PACKET to access or set up any out-of-band information associated with the packet descriptor.

Callers of NdisAllocatePacket run at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocateBuffer, NdisAllocatePacketPool, NdisDprAllocatePacket, NdisDprFreePacket, NdisFreePacket, NDIS_GET_PACKET_HEADER_SIZE, NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO, NDIS_GET_PACKET_STATUS, NDIS_GET_PACKET_TIME_RECEIVED, NDIS_GET_PACKET_TIME_SENT, NDIS_GET_PACKET_TIME_TO_SEND, NdisMArcIndicateReceive, NdisMEthIndicateReceive, NdisMFddiIndicateReceive, NdisMIndicateReceivePacket, NdisMTrIndicateReceive, NDIS_OOB_DATA_FROM_PACKET, NDIS_PACKET, NDIS_PACKET_OOB_DATA, NdisSend, NdisSendPackets, NDIS_SET_PACKET_HEADER_SIZE, NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO, NDIS_SET_PACKET_STATUS, NDIS_SET_PACKET_TIME_RECEIVED, NDIS_SET_PACKET_TIME_SENT, NDIS_SET_PACKET_TIME_TO_SEND


NdisAllocatePacketPool

NdisAllocatePacketPool allocates and initializes a block of storage for a pool of packet descriptors.

VOID
  NdisAllocatePacketPool(
    OUT PNDIS_STATUS  Status,
    OUT PNDIS_HANDLE  PoolHandle,
    IN UINT  NumberOfDescriptors,
    IN UINT  ProtocolReservedLength
    );

Parameters

Status
Pointer to a caller-supplied variable in which this function returns the status of the packet pool allocation, which can be one of the following:
NDIS_STATUS_SUCCESS
The driver can make calls to NdisAllocatePacket when it needs packet descriptors to make indications up to higher-level drivers or to send packets down to lower-level drivers.
NDIS_STATUS_RESOURCES
The attempt to allocate packet pool failed, possibly due to a shortage of memory. This return does not necessarily mean that a subsequent call will fail. However, the caller might attempt to decrease the NumberOfDescriptors and call again immediately.
PoolHandle
Pointer to a caller-supplied variable in which this function returns a handle to the packet pool. This handle is a required parameter to the Ndis..Packet functions that the driver calls subsequently.
NumberOfDescriptors
Specifies the number of packet descriptors the pool should contain.
ProtocolReservedLength
Specifies the number of bytes to be allocated for the ProtocolReserved array of each packet descriptor. For packet descriptors to be used in receive indications, this parameter is 4*sizeof(PVOID), which is reserved for use by protocols. On 32-bit systems, four pointer's worth of ProtocolReserved space equals 16 bytes. On 64-bit systems, four pointer's worth of ProtocolReserved space equals 32 bytes.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A successful call to NdisAllocatePacketPool returns a handle to the packet pool, which the caller should save. Usually, the driver next calls NdisAllocatePacket one or more times with this handle to allocate a set of packet descriptors. The NumberOfDescriptors specified in the call to NdisAllocatePacketPool is the effective limit on how many times the driver can call NdisAllocatePacket before it must call NdisFreePacket to return a packet descriptor to the free list for the packet pool.

As packets sent or indicated are returned to the allocating driver, it can reuse each packet descriptor after calling NdisReinitializePacket and setting it up again with a chain of buffer descriptors, or the driver can call NdisFreePacket to return that packet to the free list. Reinitializing and reusing packets allocated from packet pool is far faster than freeing and, then, having to reallocate them again. Before a driver calls NdisReinitializePacket with a packet descriptor, it must save the pointers to buffer descriptors that are chained to the packet descriptor since NdisReinitializePacket sets the head of the buffer chain to NULL.

When the driver no longer needs the packet pool, it calls NdisFreePacketPool to release the packet pool storage.

Callers of NdisAllocatePacketPool run at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocatePacket, NdisDprAllocatePacket, NdisDprAllocatePacketNonInterlocked, NdisFreePacketPool, NdisMIndicateReceivePacket, NDIS_PACKET, NDIS_PACKET_OOB_DATA, NdisReinitializePacket, NdisSendPackets, NdisUnchainBufferAtBack, NdisUnchainBufferAtFront, ProtocolSendComplete


NdisAllocatePacketPoolEx

NdisAllocatePacketPoolEx allocates and initializes a block of storage for a pool of packet descriptors.

VOID
  NdisAllocatePacketPoolEx(
    OUT PNDIS_STATUS  Status,
    OUT PNDIS_HANDLE  PoolHandle,
    IN UINT  NumberOfDescriptors,
    IN UINT  NumberOfOverflowDescriptors,
    IN UINT  ProtocolReservedLength
    );

Parameters

Status
Pointer to a caller-supplied variable in which this function returns the status of the packet pool allocation, which can be one of the following:
NDIS_STATUS_SUCCESS
The driver can make calls to NdisAllocatePacket when it needs packet descriptors to make indications up to higher-level drivers or to send packets down to lower-level drivers.
NDIS_STATUS_RESOURCES
The attempt to allocate packet pool failed, possibly due to a shortage of memory. This return does not necessarily mean that a subsequent call will fail. However, the caller might attempt to decrease the NumberOfDescriptors and call again immediately.
PoolHandle
Pointer to a caller-supplied variable in which this function returns a handle to the packet pool. This handle is a required parameter to the Ndis..Packet functions that the driver calls subsequently.
NumberOfDescriptors
Specifies the number of packet descriptors that the pool should contain for anticipated normal use. The maximum NumberOfDescriptors that can be allocated is 0xFFFF. If an attempt is made to allocate more than this, NdisAllocatePacketPoolEx returns a Status of NDIS_STATUS_RESOURCES.
NumberOfOverflowDescriptors
Specifies the number of packet descriptors reserved for an overflow situation (that is, when all the descriptors specified by NumberOfDescriptors are in use). If the sum of this parameter and NumberOfDescriptors exceeds 0xFFFF, NdisAllocatePacketPoolEx reduces the value supplied as this parameter so that the total NumberOfDescriptors and NumberOfOverflowDescriptors equals 0xFFFF.
ProtocolReservedLength
Specifies the number of bytes to be allocated for the ProtocolReserved array of each packet descriptor. For packet descriptors to be used in receive indications, this parameter is 4*sizeof(PVOID). On 32-bit systems, four pointer's worth of ProtocolReserved space equals 16 bytes. On 64-bit systems, four pointer's worth of ProtocolReserved space equals 32 bytes.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A successful call to NdisAllocatePacketPoolEx returns a handle to the packet pool, which the caller should save. Usually, the driver next calls NdisAllocatePacket one or more times with this handle to allocate a set of packet descriptors.

NdisAllocatePacketPoolEx statically allocates only enough memory to accommodate the number of packet descriptors specified by NumberOfDescriptors. The total number of packet descriptors that can be allocated from the pool with calls to NdisAllocatePacket is the lesser of 0xFFFF or the sum of NumberOfDescriptors and NumberOfOverflowDescriptors originally passed to NdisAllocatePacketPoolEx. Overflow descriptors are allocated dynamically only during an overflow situation — that is, when the given NumberOfDescriptors have already been allocated and are still in use.

The sum of NumberOfDescriptors and NumberOfOverflowDescriptors is the effective limit on how many times the driver can call NdisAllocatePacket before it must call NdisFreePacket to return a packet descriptor to the free list for the packet pool. When no overflow descriptor has yet been allocated, NdisFreePacket returns the packet descriptor to the statically allocated pool. If one or more overflow descriptors have already been allocated, NdisFreePacket returns the packet descriptor to system memory—not to the pool.

The caller of NdisAllocatePacketPoolEx should set NumberOfDescriptors to the number of packet descriptors needed for anticipated normal loads. The driver should set NumberOfOverflowDescriptors to the number of additional descriptors needed to accommodate anticipated peak loads. If the total possible number of packet descriptors (NumberOfDescriptors plus NumberOfOverflowDescriptors) has been allocated from the pool, a call to NdisAllocatePacket returns NDIS_STATUS_RESOURCES.

As packets sent or indicated are returned to the allocating driver, it can reuse each packet descriptor after calling NdisReinitializePacket and setting it up again with a chain of buffer descriptors, or the driver can call NdisFreePacket to return that packet to the free list. Reinitializing and reusing packets allocated from packet pool is far faster than freeing and, then, having to reallocate them again. Before a driver calls NdisReinitializePacket with a packet descriptor, it must save the pointers to buffer descriptors that are chained to the packet descriptor since NdisReinitializePacket sets the head of the buffer chain to NULL.

When a driver no longer needs packet descriptors, it calls NdisFreePacketPool to release the storage that it allocated with NdisAllocatePacketPoolEx.

Callers of NdisAllocatePacketPoolEx run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportReturnPacket, NdisAllocatePacket, NdisDprAllocatePacket, NdisDprAllocatePacketNonInterlocked, NdisFreePacketPool, NdisMIndicateReceivePacket, NDIS_PACKET, NDIS_PACKET_OOB_DATA, NdisReinitializePacket, NdisSendPackets, NdisUnchainBufferAtBack, NdisUnchainBufferAtFront, ProtocolSendComplete


NdisAllocateSpinLock

NdisAllocateSpinLock initializes a variable of type NDIS_SPIN_LOCK, used to synchronize access to resources shared among nonISR driver functions.

VOID
  NdisAllocateSpinLock(
    IN PNDIS_SPIN_LOCK  SpinLock
    );

Parameters

SpinLock
Pointer to an opaque variable that represents a spin lock.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Before a driver calls NdisAcquireSpinLock, NdisDprAcquireSpinLock, or any of the NdisInterlocked Xxx functions, it must call NdisAllocateSpinLock to initialize the spin lock passed as a required parameter to these Ndis Xxx functions. The caller must provide nonpaged storage for the variable at SpinLock.

After calling NdisAllocateSpinLock, the driver can call NdisAcquireSpinLock to obtain exclusive use of the resource(s) the spin lock protects. When resource access is complete, the driver calls NdisReleaseSpinLock so that other driver functions can access the resource(s) protected by that spin lock.

As a general rule, to improve performance a driver should use different locks to protect different critical sections. Thus, a driver might initialize more than one spin lock with NdisAllocateSpinLock.

Each spin lock that a driver allocates protects a discrete set of shared resources from simultanous access by driver functions that run at IRQL <= DISPATCH_LEVEL. For example, a driver that maintains an internal queue of packets might initialize one spin lock to protect its queue and another to protect a set of state variables that several driver functions, not including the MiniportISR or MiniportDisableInterrupt function, access while the driver is processing packets.

NdisAcquireSpinLock raises the IRQL to DISPATCH_LEVEL and stores the old IRQL in the spin lock. Releasing the spin lock sets the IRQL to the value stored in the spin lock. Because NDIS sometimes enters drivers at PASSIVE_LEVEL, problems can arise with the following code:

NdisAcquireSpinLock(A);
NdisAcquireSpinLock(B);
NdisReleaseSpinLock(A);
NdisReleaseSpinLock(B);

A driver should not access spin locks in this sequence for the following reasons:

  • Between NdisReleaseSpinLock(A) and NdisReleaseSpinLock(B) the code is running at PASSIVE_LEVEL instead of DISPATCH_LEVEL and is subject to inappropriate interruption.
  • After NdisReleaseSpinLock(B) the code is running at DISPATCH_LEVEL which could cause the caller to fault at much later time with an IRQL_NOT_LESS_OR_EQUAL stop error.

A driver should never use two spin locks to protect the same (sub)set of resources because nested spin lock acquisitions so frequently cause deadlocks. Even if a driver could be designed to prevent deadlocks, nested spin lock acquisitions have an adverse effect on driver performance and I/O throughput.

A miniport driver cannot use a spin lock to protect resources that its nonISR functions share with its MiniportISR or MiniportDisableInterrupt function. To access resources shared with a MiniportISR or MiniportDisableInterrupt function, a miniport driver must call NdisMSynchronizeWithInterrupt to have its MiniportSynchronizeISR function access those resources at DIRQL.

When a driver no longer requires resource protection, for example, when a NIC is being removed and the driver is releasing the resources it allocated for that NIC, the driver calls NdisFreeSpinLock.

Freeing a spin lock and releasing a spin lock are potentially confusing. NdisFreeSpinLock clears the memory at SpinLock so it no longer represents a spin lock. Releasing an acquired spin lock with NdisReleaseSpinLock simply allows another thread of execution to acquire that spin lock.

Callers of NdisAllocateSpinLock can run at any IRQL. Usually a caller is running at IRQL PASSIVE_LEVEL during initialization.

See Also

DriverEntry of NDIS Protocol Drivers, MiniportDisableInterrupt, MiniportHalt, MiniportInitialize, MiniportISR, MiniportTimer, NdisAcquireSpinLock, NdisDprAcquireSpinLock, NdisDprReleaseSpinLock, NdisFreeSpinLock, NdisInterlockedAddUlong, NdisInterlockedInsertHeadList, NdisInterlockedInsertTailList, NdisInterlockedRemoveHeadList, NdisMSynchronizeWithInterrupt, NdisReleaseSpinLock


NdisAnsiStringToUnicodeString

NdisAnsiStringToUnicodeString converts a given counted ANSI string into a counted Unicode string. The translation conforms to the current system locale information.

NDIS_STATUS
  NdisAnsiStringToUnicodeString(
    IN OUT PUNICODE_STRING  DestinationString,
    IN PNDIS_PANSI_STRING  SourceString
    );

Parameters

DestinationString
Pointer to a caller-allocated buffer in which this function should return the converted Unicode string.
SourceString
Pointer to the ANSI string to be converted.

Return Value

NdisAnsiStringToUnicodeString returns NDIS_STATUS_SUCCESS if the conversion succeeds. Otherwise, the contents of the buffer at DestinationString are unaffected.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The caller must allocate storage for both the source and destination strings and release these buffers as soon as the strings are no longer needed. The buffer at DestinationString must be at least twice the size of that at SourceString.

Callers of NdisAnsiStringToUnicodeString run at IRQL PASSIVE_LEVEL.

See Also

ANSI_STRING, DriverEntry of NDIS Protocol Drivers, MiniportInitialize, NdisInitAnsiString, NdisInitializeString, NdisInitUnicodeString, NdisUnicodeStringToAnsiString, ProtocolBindAdapter, UNICODE_STRING


NdisBufferLength

NdisBufferLength returns the length in bytes of a given mapped buffer.

ULONG
  NdisBufferLength(
    IN PNDIS_BUFFER  Buffer
    );

Parameters

Buffer
Pointer to the buffer descriptor mapping the buffer.

Return Value

NdisBufferLength returns the byte count of the mapped buffer.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Callers of NdisBufferLength must be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisAdjustBufferLength, NdisBufferVirtualAddress, NdisBufferVirtualAddressSafe, NdisQueryBuffer, NdisQueryBufferSafe, NdisQueryBufferOffset, NdisQueryBufferOffset


NDIS_BUFFER_LINKAGE

NDIS_BUFFER_LINKAGE returns a pointer to a linked buffer, given a pointer to a buffer descriptor.

PVOID
  NDIS_BUFFER_LINKAGE(
    IN PNDIS_BUFFER  Buffer
    );

Parameters

Buffer
Pointer to a buffer descriptor. This buffer descriptor must not be chained to a packet descriptor.

Return Value

NDIS_BUFFER_LINKAGE returns a pointer to the structure member containing the linkage, or NULL if it fails.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

This macro allows a driver to queue allocated buffer descriptors without having to supply its own buffer descriptor linkage.

Callers of this macro can be running at any IRQL.

See Also

NdisAllocateBuffer


NDIS_BUFFER_TO_SPAN_PAGES

NDIS_BUFFER_TO_SPAN_PAGES determines how many physical pages of memory are being used to back a given buffer.

ULONG
  NDIS_BUFFER_TO_SPAN_PAGES(
    IN PNDIS_BUFFER  Buffer
    );

Parameters

Buffer
Specifies the buffer descriptor mapping the buffer.

Return Value

NDIS_BUFFER_TO_SPAN_PAGES returns the number of pages backing the virtual range for the buffer.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

This macro can be used by DMA drivers to determine how many physical discontiguities exist in a given virtual buffer.

Callers of NDIS_BUFFER_TO_SPAN_PAGES can be running at any IRQL.

See Also

NdisMSetupDmaTransfer, NdisMStartBufferPhysicalMapping


NdisBufferVirtualAddress

NdisBufferVirtualAddress returns the base virtual address for the buffer mapped by a given buffer descriptor. It maps the physical pages described by the given buffer descriptor onto system space if these pages are not already mapped to system space.

PVOID
  NdisBufferVirtualAddress(
    IN PNDIS_BUFFER  Buffer
    );

Parameters

Buffer
Pointer to a buffer descriptor from which the base virtual address is to be returned.

Return Value

NdisBufferVirtualAddress returns the base system-space virtual address that maps the physical pages described by the given buffer descriptor.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Drivers should call NdisBufferVirtualAddressSafe instead of NdisBufferVirtualAddress. NDIS 5.1 miniport drivers must call NdisBufferVirtualAddressSafe instead of NdisBufferVirtualAddress. Unlike NdisBufferVirtualAddress, NdisBufferVirtualAddressSafe does not cause a bug check if system resources are low or exhausted.

Drivers of PIO devices call NdisBufferVirtualAddress to translate a virtual address range, described by the buffer, for a user buffer to a system-space address range.

The returned base address has the same offset as the virtual address in the buffer.

Callers of NdisBufferVirtualAddress can be running at IRQL <= DISPATCH_LEVEL. However, a caller running at IRQL = DISPATCH_LEVEL must supply a buffer descriptor that maps nonpaged system-space addresses. The buffer itself must have been allocated from nonpaged pool, contiguous memory, or noncached memory.

See Also

NdisAllocateBuffer, NdisAllocateBufferPool, NdisAllocateMemory, NdisFreeBuffer, NdisBufferVirtualAddressSafe


NdisBufferVirtualAddressSafe

NdisBufferVirtualAddressSafe returns the base virtual address for the buffer mapped by a given buffer descriptor. It maps the physical pages described by the given buffer descriptor onto system space if these pages are not already mapped to system space.

PVOID
  NdisBufferVirtualAddressSafe(
    IN PNDIS_BUFFER  Buffer
    IN MM_PAGE_PRIORITY  Priority
    );

Parameters

Buffer
Pointer to a buffer descriptor from which the base virtual address is to be returned.
Priority
Indicates the priority of the request as one of the following:
LowPagePriority
Specifies a low priority. It is acceptable for NdisBufferVirtualAddressSafe to fail if system resources are low.
NormalPagePriority
Specifies a normal priority. It is acceptable for NdisBufferVirtualAddressSafe to fail if system resources are low.
HighPagePriority
Specifies a high priority. It is not acceptable for NdisBufferVirtualAddressSafe to fail unless system resources are exhausted.

Return Value

NdisBufferVirtualAddressSafe returns either of the following:

  • The base system-space virtual address that maps the physical pages described by the given buffer descriptor.
  • NULL if system resources are low (if Priority was set to LowPagePriority or NormalPagePriority) or exhausted (if Priority was set to HighPagePriority)

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisBufferVirtualAddressSafe is the safe version of NdisBufferVirtualAddress. If system resources are low or exhausted, calling NdisBufferVirtualAddress causes a bug check. Drivers should therefore call NdisBufferVirtualAddressSafe instead of NdisBufferVirtualAddress. NDIS 5.1 miniport drivers must call NdisBufferVirtualAddressSafe instead of NdisBufferVirtualAddress.

Drivers of PIO devices call NdisBufferVirtualAddressSafe to translate a virtual address range, described by the buffer, for a user buffer to a system-space address range.

The returned base address has the same offset as the virtual address in the buffer.

If Priority was set to LowPagePriority or NormalPagePriority, NdisBufferVirtualAddressSafe returns NULL if system resources are low or exhausted. If Priority was set to HighPagePriority, NdisBufferVirtualAddressSafe returns NULL if system resources are exhausted.

Callers of NdisBufferVirtualAddressSafe can be running at IRQL <= DISPATCH_LEVEL. However, a caller running at IRQL = DISPATCH_LEVEL must supply a buffer descriptor that maps nonpaged system-space addresses. The buffer itself must have been allocated from nonpaged pool, contiguous memory, or noncached memory.

See Also

NdisAllocateBuffer, NdisAllocateBufferPool, NdisAllocateMemory, NdisBufferVirtualAddress, NdisFreeBuffer


NdisCancelSendPackets

NdisCancelSendPackets cancels transmission of all packets marked with the specified cancellation identifier on the miniport driver identified by the binding handle.

VOID
  NdisCancelSendPackets(
    IN NDIS_HANDLE  NdisBindingHandle
    IN ULONG_PTR  CancelId
    );

Parameters

NdisBindingHandle
Specifies the handle returned by NdisOpenAdapter that identifies the NIC or virtual adapter to which the cancellation applies.
CancelId
The cancellation identifier. This identifier specifies the packet or group of packets for which transmission is being canceled.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Transport protocols map IRPs received from higher-level software to NDIS packets, which the protocols then send to lower-level drivers for transmission. If an IRP is canceled, a transport protocol can call the NdisCancelSendPackets function to cancel the pending transmission of the corresponding NDIS packet.

The NdisCancelSendPackets function cancels packet transmissions on a single binding. To cancel packet transmissions on more than one binding, a protocol or intermediate driver must call the NdisCancelSendPackets function once for each binding.

The protocol or intermediate driver must ensure that NdisBindingHandle, which represents the driver's binding to the adapter, remains valid for the duration of the call to NdisCancelSendPackets. That is, the protocol or intermediate driver must not call the NdisCloseAdapter function to close the binding before NdisCancelSendPackets returns.

There is no guarantee that calling NdisCancelSendPackets will cancel the pending transmission of all packets with the specified cancellation ID. For example, if the next-lower driver to which the protocol or intermediate driver is bound does not provide a MiniportCancelSendPackets function, a call to NdisCancelSendPackets does nothing.

In all cases, packets submitted for transmission are returned to the originating protocol or intermediate driver through a call to the driver's ProtocolSendComplete or ProtocolCoSendComplete function. Canceled send packets are returned with a completion status of NDIS_STATUS_ABORTED. The delay between calling NdisCancelSendPackets and the return of the canceled packets can vary and therefore cannot be exactly specified.

System support for NdisCancelSendPackets is available in Windows XP and later OS versions.

Callers of the NdisCancelSendPackets function run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportCancelSendPackets, NdisGeneratePartialCancelId, NDIS_GET_PACKET_CANCEL_ID, NDIS_SET_PACKET_CANCEL_ID


NdisCancelTimer

NdisCancelTimer cancels the immediately preceding call to NdisSetTimer if the interval given to NdisSetTimer has not yet expired.

VOID
  NdisCancelTimer(
    IN PNDIS_TIMER  Timer,
    OUT PBOOLEAN  TimerCanceled
    );

Parameters

Timer
Pointer to a timer object, already initialized with NdisInitializeTimer and set with NdisSetTimer.
TimerCanceled
Pointer to a caller-supplied variable. NdisCancelTimer sets this variable to TRUE if the timer was queued and then canceled, or to FALSE if the timer either was not set or has already fired and caused the associated timer function to run.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

All Ndis..Timer functions operate on an opaque timer object, for which a protocol driver must supply resident storage. The protocol driver must call NdisInitializeTimer with a caller-supplied pointer to this storage, thereby associating a driver-supplied timer function with the timer object. The protocol driver must call NdisInitializeTimer before the driver passes the Timer pointer to any other Ndis..Timer function.

The following describes the syntax of the driver-supplied timer function:

VOID
  (*PNDIS_TIMER_FUNCTION)(
    IN PVOID  SystemSpecific1,
    IN PVOID  FunctionContext,
    IN PVOID  SystemSpecific2,
    IN PVOID  SystemSpecific3
    );

Calls to the NdisSetTimer functions insert the timer object in the system timer queue. During the interval in which the timer object is queued, calls to NdisCancelTimer remove the timer object from the queue, thereby canceling the execution of the associated timer function. Only one instance of a particular timer object can be queued at any given moment.

A subsequent call to NdisSetTimer requeues the timer object so the timer function again will be run when the given interval expires.

A call to NdisCancelTimer returns TRUE in the TimerCanceled parameter if the timer was queued and then canceled. NdisCancelTimer returns FALSE if the timer function is already running or if there is no way to stop the timer function from running. If NdisCancelTimer returns FALSE, the caller must take appropriate action.

Callers of NdisCancelTimer run at IRQL <= DISPATCH_LEVEL.

See Also

NdisInitializeTimer, NdisSetTimer


NdisChainBufferAtBack

NdisChainBufferAtBack links a given buffer descriptor to the tail of the buffer-descriptor chain attached to a packet descriptor.

VOID
  NdisChainBufferAtBack(
    IN OUT PNDIS_PACKET  Packet,
    IN OUT PNDIS_BUFFER  Buffer
    );

Parameters

Packet
Pointer to the packet descriptor.
Buffer
Pointer to the caller-supplied buffer descriptor to be added to the chain.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisChainBufferAtBack either links the given buffer descriptor to the end of an existing chain or, if the given packet has no associated buffer descriptors already, at the head of the chain.

It also resets the valid counts for the packet to FALSE, thereby forcing NdisQueryPacket to recalculate information about the given packet if it is called subsequently with that packet.

Callers of NdisChainBufferAtBack can run at any IRQL but usually run at IRQL <= DISPATCH_LEVEL.

See Also

NdisChainBufferAtFront, NdisQueryPacket, NdisUnchainBufferAtBack


NdisChainBufferAtFront

NdisChainBufferAtFront links a given buffer descriptor to the head of the buffer-descriptor chain attached to a packet descriptor.

VOID
  NdisChainBufferAtFront(
    IN OUT PNDIS_PACKET  Packet,
    IN OUT PNDIS_BUFFER  Buffer
    );

Parameters

Packet
Pointer to the packet descriptor.
Buffer
Pointer to the caller-supplied buffer descriptor to be added to the chain.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisChainBufferAtFront links the given buffer descriptor at the head of the chain for the given packet.

It also resets the valid counts for the packet to FALSE, thereby forcing NdisQueryPacket to recalculate information about the given packet if it is called subsequently with that packet.

Callers of NdisChainBufferAtFront can run at any IRQL but usually run at IRQL <= DISPATCH_LEVEL.

See Also

NdisChainBufferAtBack, NdisQueryPacket, NdisUnchainBufferAtFront


NdisClAddParty

NdisClAddParty adds a party on the client's multipoint VC.

NDIS_STATUS
  NdisClAddParty(
    IN NDIS_HANDLE  NdisVcHandle,
    IN NDIS_HANDLE  ProtocolPartyContext,
    IN OUT PCO_CALL_PARAMETERS  CallParameters,
    OUT PNDIS_HANDLE  NdisPartyHandle
    );

Parameters

NdisVcHandle
Pointer to the VC handle returned by NdisCoCreateVc.
ProtocolPartyContext
Specifies the handle to a caller-allocated resident context area in which the client will maintain per-party state if its call succeeds.
CallParameters
Pointer to a structure of type CO_CALL_PARAMETERS in which the caller has specified the addressing information for the party to be added on its multipoint VC.
NdisPartyHandle
Pointer to a variable to be set by NDIS if the add-party operation succeeds.

Return Value

When NdisClAddParty returns anything other than NDIS_STATUS_PENDING, the client should make an internal call to its ProtocolClAddPartyComplete function. Otherwise, NDIS calls the client's ProtocolClAddPartyComplete function when this operation is completed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Before it calls NdisClAddParty, a client must set up a multipoint connection on its VC with NdisClMakeCall, as well as allocating and initializing its context area for the party to be added. Clients commonly pass a pointer to such a context area as the ProtocolPartyContext and a pointer to a variable within that context area as the NdisPartyHandle parameters when they call NdisClAddParty.

A call to NdisClAddParty causes NDIS to forward this request to the ProtocolCmAddParty function of the call manager with which the client shares the given NdisVcHandle. The call manager either returns an error status immediately or, more commonly, NDIS_STATUS_PENDING if it attempts to satisfy this request. If its attempt is rejected on the remote endpoint or by the underlying NIC driver, the call manager returns a final error status, such as NDIS_STATUS_FAILURE, when it calls Ndis(M)CmAddPartyComplete. The client's ProtocolClAddPartyComplete function should check the input Status argument for NDIS_STATUS_SUCCESS before proceeding further.

The underlying network medium determines whether a client can specify per-party traffic parameters on a multipoint VC. For example, traffic parameters on a multipoint VC are identical for all parties on ATM networks. When a client on an ATM network calls NdisClAddParty, the traffic parameters, such as the bandwidth, at CallParameters should match those already established for the multipoint VC originally set up by the client with NdisClMakeCall. For each party that the client subsequently adds on its multipoint VC, the ATM call manager uses the same traffic parameters, so the client need specify only new addressing information and the already established multipoint VC's traffic parameters at CallParameters for NdisClAddParty.

If the underlying network medium, like ATM, does not support per-party traffic parameters on multipoint VCs, a call manager can do one of the following whenever a client attempts to add a party with a specification at CallParameters that does not match the already established traffic parameters for that VC:

  • Reject the request to add a new party.
  • Reset the traffic parameters to those already established for the multipoint VC when it successfully adds the party on that VC.
  • Change the traffic parameters for every party already on the VC when it successfully adds the new party.

If the add-party operation suceeds, the variable at NdisPartyHandle has been set by NDIS to a valid handle shared among NDIS, the client, and the call manager. The client must treat this NDIS-supplied handle as an opaque variable to be passed, unmodified and uninterpreted, in subsequent calls to NdisCl/Co Xxx functions concerning the newly added party.

In turn, NDIS passes the client-supplied ProtocolPartyContext handle in subsequent calls to the client's ProtocolClXxx functions that concern this newly added party, including the call to ProtocolClAddPartyComplete.

Whether a multipoint call permits transfers in both directions and/or per-party transfers with per-party traffic parameters depends on the medium of the underlying NIC driver to which the client is bound. The NdisPartyHandle represents only the specific party added by a successful call to NdisClAddParty, rather than the multipoint VC. Consequently, the client can use its ProtocolPartyContext area only for subsequent party-specific call-management requests. For data transfers over network media that do not support per-party transfers or traffic parameters, the client must use the NdisVcHandle instead. For example, on ATM networks, there is no way for the client to send data exclusively to a particular party on a VC that represents an established multipoint connection.

Callers of NdisClAddParty can be running at IRQL <= DISPATCH_LEVEL.

See Also

CO_CALL_PARAMETERS, NdisAllocateFromNPagedLookasideList, NdisClCloseCall, NdisClMakeCall, NdisClDropParty, NdisCmAddPartyComplete, NdisCoCreateVc, NdisCoRequest, NdisCoRequestComplete, NdisMCmAddPartyComplete, ProtocolClAddPartyComplete, ProtocolCmAddParty


NdisClCloseAddressFamily

NdisClCloseAddressFamily releases the association between a client protocol and a call manager's or MCM driver's registered AF for a particular NIC to which the client is bound.

NDIS_STATUS
  NdisClCloseAddressFamily(
    IN NDIS_HANDLE  NdisAfHandle
    );

Parameter

NdisAfHandle
Specifies the NDIS-supplied handle returned by NdisClOpenAddressFamily.

Return Value

When NdisClCloseAddressFamily returns anything other than NDIS_STATUS_PENDING, the client should make an internal call to its ProtocolClCloseAfComplete function. Otherwise, NDIS calls the client's ProtocolClCloseAfComplete function when this operation is completed.

If NdisClCloseAddressFamily returns NDIS_STATUS_PENDING, a client that is waiting for its ProtocolClCloseAfComplete function to be called should not block the current thread since this could cause a deadlock. This is particularly important when a client calls NdisClCloseAddressFamily in the context of handling an OID_CO_AF_CLOSE request. In this case, the call manager may not close the address family until after the client has returned from handling the OID_CO_AF_CLOSE request. If the client blocks the current thread, the client will never complete the handling of the OID_CO_AF_CLOSE request, thus causing a deadlock.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A client commonly calls NdisClCloseAddressFamily from its ProtocolUnbindAdapter function, after it closes all the client's open VCs on the binding with calls to NdisClCloseCall and/or NdisClDeregisterSap. A client can also call NdisClCloseAddressFamily in the context of processing an OID_CO_AF_CLOSE request.

NDIS calls a client's ProtocolUnbindAdapter function whenever an underlying NIC to which that client is bound is being removed from the machine or is being reconfigured. A PnP reconfiguration of the underlying miniport driver causes the call manager or MCM driver to reregister the address family it supports over that NIC. This, in turn, causes a subsequent call to the client's ProtocolCoAfRegisterNotify function. In either scenario, the client's ProtocolUnbindAdapter function must call NdisClCloseAddressFamily with any outstanding NdisAfHandle it is currently using that depends on the underlying NIC driver.

As a general guideline, a client should release all the resources it allocated for connection-oriented communications through the miniport driver before its ProtocolUnbindAdapter function calls NdisCloseAdapter.

The NdisAfHandle passed to NdisClCloseAddressFamily becomes invalid for the client as soon as this call occurs.

Callers of NdisClCloseAddressFamily can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisClCloseCall, NdisClDeregisterSap, NdisClOpenAddressFamily, ProtocolClCloseAfComplete, ProtocolCmCloseAf, ProtocolCoAfRegisterNotify, ProtocolUnbindAdapter


NdisClCloseCall

NdisClCloseCall requests that a call on the specified VC be torn down.

NDIS_STATUS
  NdisClCloseCall(
    IN NDIS_HANDLE  NdisVcHandle,
    IN NDIS_HANDLE  NdisPartyHandle  OPTIONAL,
    IN PVOID  Buffer  OPTIONAL,
    IN UINT  Size
    );

Parameters

NdisVcHandle
Specifies the handle to the VC of the call being closed or disconnected. This handle was supplied by NDIS when the VC was originally created with NdisCoCreateVc, whether by the client in preparation for making an outgoing call or by the call manager in preparation for dispatching an incoming call to the client.
NdisPartyHandle
Specifies the handle to the last party to be dropped on a multipoint VC or NULL. If this is a multipoint VC, the client obtained this handle either from a preceding call to NdisClMakeCall or NdisClAddParty.
Buffer
Pointer to a caller-allocated buffer containing any data to be transmitted to the party on the remote node when the connection is closed. Depending on the underlying medium, this pointer can be NULL. For example, this parameter is NULL on ATM networks.
Size
Specifies the size in bytes at Buffer, zero if Buffer is NULL.

Return Value

When NdisClCloseCall returns anything other than NDIS_STATUS_PENDING, the client should make an internal call to its ProtocolClCloseCallComplete function. Otherwise, NDIS calls the client's ProtocolClCloseCallComplete function when this operation is completed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Clients usually call NdisClCloseCall in any one of the following circumstances:

  • To close an established call, whether the call was initiated by the client with NdisClMakeCall or was offered by a remote peer and accepted by the client's ProtocolClIncomingCall function
  • From the ProtocolClIncomingCloseCall function to tear down an established call

    This occurs when the remote party closes an incoming call that the remote party originally initiated and that the client accepted. For client-initiated outgoing calls, this occurs either when the remote party closes the point-to-point connection on the remote node or when the last remaining party on a multipoint VC closes the call on the remote node.

  • From the ProtocolClMakeCallComplete function to tear down a client-initiated attempt to make an outgoing call

    This occurs if the call manager has modified the client-specified call parameters passed to NdisClMakeCall and the client finds these modifications unacceptable.

  • From the ProtocolClIncomingQoSChange function to tear down an established call

    This occurs if a QoS change proposed by the other party on the VC is unacceptable to the client.

  • From the ProtocolClModifyCallQoSComplete function to tear down an established call

    This occurs if a client-proposed QoS change on the VC is not accepted and the CM-modified QoS returned to ProtocolClModifyCallQoSComplete is unacceptable to the client.

Before calling NdisClCloseCall, a protocol must ensure that all it's outstanding send packets have been returned to it's ProtocolCoSendComplete function. (Packets sent via NdisCoSendPackets are always returned asynchronously to ProtocolCoSendComplete.) After calling NdisClCloseCall, a protocol must not call NdisCoSendPackets to send packets on the VC referenced by NdisClCloseCall.

A client's call to NdisClCloseCall causes NDIS to mark the NdisVcHandle as closing and to call the CM's ProtocolCmCloseCall function.

To tear down an established call on a client-created multipoint VC, the client must call NdisClDropParty one or more times to release all but the last party on the VC before it calls NdisClCloseCall. The call manager will fail any client's request to close a multipoint call if the given VC still has more than one party connected. The NdisPartyHandle passed to NdisClCloseCall can be any valid handle that the client obtained from its preceding calls to NdisClAddParty or NdisClMakeCall with the given NdisVcHandle.

As remote parties to a client-initiated multipoint call request that their connections be closed, NDIS calls that client's ProtocolClDropParty function as long as more than one outstanding party exists on the client-created multipoint VC. When the last remaining remote party closes its connection, NDIS calls the client's ProtocolClIncomingCloseCall function instead. Consequently, the ProtocolClIncomingCloseCall function of any client that sets up multipoint connections must identify the last remaining party on its multipoint VCs and pass the appropriate NdisPartyHandle to NdisClCloseCall.

After the client releases an NdisPartyHandle with NdisClCloseCall, it can release (or reinitialize for reuse) the resources for the per-party state it was maintaining. However, the client cannot release or reuse its per-VC resources in a similar manner on completion of the operation it initiated with NdisClCloseCall because the NdisVcHandle, which cannot be reused to make another call because it is marked as closing, is still valid until the VC is destroyed. Either the client must call NdisCoDeleteVc if it created the VC for an outgoing call before it releases or reinitializes its per-VC resources, or the client must defer the release or reinitialization of these resources until its ProtocolCoDeleteVc function is called.

Callers of NdisClCloseCall can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisClDropParty, NdisClModifyCallQoS, NdisClMakeCall, NdisCoDeleteVc,

NdisCoSendPackets,

ProtocolClCloseCallComplete, ProtocolClIncomingCloseCall, ProtocolClIncomingDropParty, ProtocolClIncomingCallQoSChange, ProtocolClMakeCallComplete, ProtocolClModifyCallQoSComplete, ProtocolCmCloseCall ProtocolCoSendComplete


NdisClDeregisterSap

NdisClDeregisterSap releases a previously registered SAP.

NDIS_STATUS
  NdisClDeregisterSap(
    IN NDIS_HANDLE  NdisSapHandle
    );

Parameters

NdisSapHandle
Specifies the handle returned by NdisClRegisterSap.

Return Value

NdisClDeregisterSap can return one of the following:

NDIS_STATUS_PENDING
The call manager's ProtocolCmDeregisterSap function has been called to complete the requested operation. NDIS calls the client's ProtocolClDeregisterSapComplete function when this operation is completed.
NDIS_STATUS_FAILURE
The SAP already is being closed, so this is a redundant call. If NdisClRegisterSap returns anything other than NDIS_STATUS_PENDING, the client should make an internal call to its ProtocolClRegisterSapComplete function.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisClDeregisterSap releases a SAP on which the client previously registered itself to receive incoming calls with NdisClRegisterSap.

The client should consider the given NdisSapHandle invalid as soon as it calls NdisClDeregisterSap.

Callers of NdisClDeregisterSap can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisClRegisterSap, NdisCmRegisterSapComplete, ProtocolClDeregisterSapComplete, ProtocolCmDeregisterSap, ProtocolUnbindAdapter


NdisClDropParty

NdisClDropParty drops a party from the client's multipoint VC.

NDIS_STATUS
  NdisClDropParty(
    IN NDIS_HANDLE  NdisPartyHandle,
    IN PVOID  Buffer  OPTIONAL,
    IN UINT  Size
    );

Parameters

NdisPartyHandle
Specifies the handle identifying the party to be dropped on the multipoint connection. The client obtained this handle from a preceding call to NdisClAddParty or NdisClMakeCall.
Buffer
Pointer to a caller-allocated buffer containing any data to be transmitted to close the multipoint connection of the party on the remote node. Depending on the underlying medium, this pointer can be NULL. For example, this parameter is NULL on ATM networks.
Size
Specifies the size in bytes at Buffer, zero if Buffer is NULL.

Return Value

When NdisClDropParty returns anything other than NDIS_STATUS_PENDING, the client should make an internal call to its ProtocolClDropPartyComplete function. Otherwise, NDIS calls the client's ProtocolClDropPartyComplete function when this operation is completed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Clients usually call NdisClDropParty in either of the following circumstances:

  • From the ProtocolClIncomingDropParty function to remove the given party from a multipoint connection

    This occurs when a party on a remote node closes its connection with NdisClCloseCall. When NDIS calls the local client's ProtocolClDropPartyComplete function, it can release or reuse the context area at ProtocolPartyContext in which the client was maintaining state about this party.

  • Before the client calls NdisClCloseCall with the last party on a multipoint connection that the client originally set up with NdisClMakeCall

    For such a client-initiated close of its own multipoint call, the client must call NdisClDropParty one or more times to drop every other remaining party on the multipoint VC.

A client's call to NdisClDropParty causes NDIS to call the ProtocolCmDropParty function of the call manager that shares the same NdisVcHandle to the multipoint VC. The call manager is responsible for notifying its remote-node peer that the party connection has been or should be closed, depending on which client initiated the drop-party operation.

As a general guideline, a client must call NdisClDropParty as many times as it called NdisClAddParty with a particular NdisVcHandle obtained from NdisClMakeCall before it closes its multipoint connection with NdisClCloseCall. Since remote parties can initiate closes of their connections, thereby causing calls to the local client's ProtocolClIncomingDropParty function, the local client must keep track of the number of active parties on its multipoint VCs in order to know how many calls it must make to NdisClDropParty before it can call NdisClCloseCall.

However, the client is not required to pass NdisClCloseCall the same NdisPartyHandle returned by NdisClMakeCall when the client originally set up its multipoint connection. The client can release parties on its multipoint VC in any order, as long as it releases every NdisPartyHandle returned by NdisClAddParty or NdisClMakeCall in its calls to NdisClDropParty, followed by a final call with the last party handle to NdisClCloseCall for the same multipoint VC. After the client has closed its multipoint call, it can release the VC that it originally created with NdisCoDeleteVc.

The caller of NdisClDropParty should consider the input NdisPartyHandle invalid as soon as it makes this call. If it stored this handle in the party context area it allocated, the client's ProtocolClDropPartyComplete function should reset the handle variable to NULL if it reinitializes its per-party context area for reuse when the party has been dropped.

Callers of NdisClDropParty can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisClAddParty, NdisClCloseCall, NdisClMakeCall, NdisCoDeleteVc, ProtocolClDropPartyComplete, ProtocolClIncomingDropParty, ProtocolCmDropParty


NdisClGetProtocolVcContextFromTapiCallId

NdisClGetProtocolVcContextFromTapiCallId retrieves the client context for a virtual connection (VC) identified by a TAPI Call ID string.

NDIS_STATUS
  NdisClGetProtocolVcContextFromTapiCallId(
    IN UNICODE_STRING  TapiCallId,
    OUT PNDIS_HANDLE  ProtocolVcContext
    );

Parameters

TapiCallId
Unicode string that identifies a particular VC. This string is the Unicode version of a string identifier that was previously returned by the NdisCoGetTapiCallID function.
ProtocolVcContext
Pointer to a caller-allocated NDIS_HANDLE that receives a handle to the client context for the VC. The client supplied this context to NDIS on return from its ProtocolCoCreateVc handler.

Return Value

Returns one of the following status values:

NDIS_STATUS_SUCCESS
NDIS successfully retrieved the handle to the client VC context for the VC identified by the TAPI Call ID string.
NDIS_STATUS_FAILURE
The attempt to retrieve the handle to the client VC context failed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Suppose a call manager calls NdisCoCreateVc to create a VC for a TAPI call. NDIS in turn supplies the handle to the VC to a client. The client passes this VC handle in a call to the NdisCoGetTapiCallId function to retrieve a string identifier for the VC. The client can then present this identifier as a Unicode string to NdisClGetProtocolVcContextFromTapiCallId to get back its context for the VC.

The client creates a context for each VC that it manages. The client uses NdisCoGetTapiCallID to retrieve a string identifier for each VC. The client passes each string identifier to a TAPI application to identify each VC. Later, if a TAPI application passes one of these string identifiers down to the client in a VC-related operation, the client must pass this string identifier as a Unicode string in a call to NdisClGetProtocolVcContextFromTapiCallId to get back the correct context for the VC.

See the UNICODE_STRING structure for more information.

Callers of NdisClGetProtocolVcContextFromTapiCallId must be running at IRQL DISPATCH_LEVEL.

See Also

NdisCoCreateVc, NdisCoGetTapiCallId, UNICODE_STRING


NdisClIncomingCallComplete

NdisClIncomingCallComplete returns a client's acceptance or rejection of an offered incoming call, for which the client's ProtocolClIncomingCall function previously returned NDIS_STATUS_PENDING.

VOID
  NdisClIncomingCallComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisVcHandle,
    IN PCO_CALL_PARAMETERS  CallParameters
    );

Parameters

Status
Is set to NDIS_STATUS_SUCCESS if the client accepts the offered call. Otherwise, this parameter can be set to any NDIS_STATUS_XXX except NDIS_STATUS_PENDING to indicate the client-determined reason for rejecting the call.
NdisVcHandle
Specifies the handle to the VC that was created by the call manager to represent the incoming call. The client obtained this handle from it per-VC state designated by the ProtocolVcContext passed as an input parameter to its ProtocolClIncomingCall function.
CallParameters
Pointer to a structure of type CO_CALL_PARAMETERS, specifying the call parameters for the incoming call.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If a client's ProtocolClIncomingCall function returns NDIS_STATUS_PENDING for an offered call incoming on a particular SAP, previously registered by the client with NdisClRegisterSap, the client subsequently must call NdisClIncomingCallComplete to indicate whether it is accepting or rejecting the offered call.

Before it calls NdisClIncomingCallComplete, such a client can negotiate with the call manager by calling NdisClModifyCallQoS one or more times until both drivers reach an agreement on an acceptable quality of service for the incoming call or the client determines it should reject the offered call because its attempts to modify the QoS reach some client-determined limit without resulting in an agreement.

If the client has changed the call parameters passed in to its ProtocolClIncomingCall function, it must set the Flags member in the CO_CALL_PARAMETERS structure with CALL_PARAMETERS_CHANGED when it passes these changes to NdisClIncomingCallComplete. Depending on whether the call manager accepts or rejects the client's proposed changes to the call parameters, NDIS subsequently calls either the client's ProtocolClCallConnected function or its ProtocolClIncomingCloseCall function, respectively.

A call to NdisClIncomingCallComplete causes NDIS to call the CM's ProtocolCmIncomingCallComplete function. NDIS passes the client-supplied parameters of NdisClIncomingCallComplete as input parameters to ProtocolCmIncomingCallComplete.

If a client rejects an offered call by setting Status to something other than NDIS_STATUS_SUCCESS, the client must consider the CallParameters pointer invalid as soon as its call to NdisClIncomingCallComplete occurs.

Callers of NdisClIncomingCallComplete can be running at IRQL <= DISPATCH_LEVEL.

See Also

CO_CALL_PARAMETERS, NdisClModifyCallQoS, NdisClRegisterSap, NdisCmDispatchIncomingCall, ProtocolClCallConnected, ProtocolClIncomingCall, ProtocolClIncomingCloseCall, ProtocolCmIncomingCallComplete


NdisClMakeCall

NdisClMakeCall sets up an outgoing call on a client-created VC.

NDIS_STATUS
  NdisClMakeCall(
    IN NDIS_HANDLE  NdisVcHandle,
    IN OUT PCO_CALL_PARAMETERS  CallParameters,
    IN NDIS_HANDLE  ProtocolPartyContext  OPTIONAL,
    OUT PNDIS_HANDLE  NdisPartyHandle  OPTIONAL
    );

Parameters

NdisVcHandle
Specifies the handle returned by a preceding call to NdisCoCreateVc.
CallParameters
Pointer to a structure of type CO_CALL_PARAMETERS in which the caller has specified the attributes for this connection, such as the address of the target for the call, latency, bandwidth, and quality of service if the network medium and address family supported by the call manager permits QoS specifications.
ProtocolPartyContext
Optionally specifies a caller-supplied handle to a resident context area in which the client will maintain per-party state for the initial party on its multipoint VC. This parameter is NULL if the given VC does not represent a multipoint connection. For a multipoint VC, NDIS passes this handle back to the client's ProtocolClXxx functions in all subsequent calls that affect this particular party.
NdisPartyHandle
Pointer to a caller-supplied variable, usually in the caller-allocated party context area, in which NDIS returns a handle representing the initial party to the multipoint connection if the request to set up an outgoing call is successful. If ProtocolPartyContext is NULL, this variable, usually in the client's VC context area, also is set to NULL on completion of outgoing-call setup.

Return Value

When NdisClMakeCall returns anything other than NDIS_STATUS_PENDING, the client should make an internal call to its ProtocolClMakeCallComplete function. Otherwise, NDIS calls the client's ProtocolClMakeCallComplete function when this operation is completed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisClMakeCall sets up the attributes of a client-created VC for a client-initiated outgoing call. The client must set up the VC with NdisCoCreateVc before it attempts to make an outgoing call.

A call to NdisClMakeCall causes NDIS to forward this request to the ProtocolCmMakeCall function of the call manager with which the client shares the given NdisVcHandle. The CM is responsible for validating the given data at CallParameters. It can modify this client-supplied data while negotiating with relevant network components and can return different traffic parameters than the client originally gave to NdisClMakeCall. The client's ProtocolClMakeCallComplete function is responsible for accepting the modified call parameters if this occurs or for tearing down the call if the CM's proposed call parameters are unacceptable.

Consequently, the data at CallParameters must remain available to the call manager at least for the duration of call setup. The client cannot free this buffer when NdisClMakeCall returns NDIS_STATUS_PENDING. It must defer releasing this client-allocated resource until its ProtocolClMakeCallComplete function is called.

If NdisClMakeCall sets up a multipoint connection, the client is establishing the traffic parameters globally for the given VC, unless the underlying network medium supports per-party traffic parameters. For example, no matter how many parties a client subsequently adds on an ATM multipoint VC with NdisClAddParty, these parties will all share the same traffic parameters on their multipoint connection. A client on an ATM network cannot specify bandwidth, QoS, and so forth, as CallParameters on a per-party basis. In addition, if a client on an ATM network changes the QoS on an established multipoint VC with NdisClModifyCallQoS, its change affects all parties on the multipoint VC.

The client's ProtocolClMakeCallComplete function should check the input Status for NDIS_STATUS_SUCCESS before it uses any returned handle at NdisPartyHandle. If the call manager fails the request to set up a call on a multipoint connection, the value of this client-supplied variable is invalid.

Callers of NdisClMakeCall can be running at IRQL <= DISPATCH_LEVEL.

See Also

CO_CALL_PARAMETERS, NdisAllocateFromNPagedLookasideList, NdisClAddParty, NdisClCloseCall, NdisClModifyCallQoS, NdisCmActivateVc, NdisCmMakeCallComplete, NdisCoCreateVc, ProtocolClMakeCallComplete, ProtocolCmMakeCall


NdisClModifyCallQoS

NdisClModifyCallQoS requests a change in the quality of service on a connection.

NDIS_STATUS
  NdisClModifyCallQoS(
    IN NDIS_HANDLE  NdisVcHandle,
    IN PCO_CALL_PARAMETERS  CallParameters
    );

Parameters

NdisVcHandle
Specifies the handle to the VC for which the client wants to modify the QoS. The client originally obtained this handle by calling NdisCoCreateVc, and, more recently, retrieved this handle from its per-VC state area.
CallParameters
Pointer to a structure of type CO_CALL_PARAMETERS that specifies the new QoS requested by the caller.

Return Value

When NdisClModifyCallQoS returns anything other than NDIS_STATUS_PENDING, the client should make an internal call to its ProtocolClModifyCallQoSComplete function. Otherwise, NDIS calls the client's ProtocolClModifyCallQoSComplete function when this operation is completed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A call to NdisClModifyCallQoS causes NDIS to call the CM's ProtocolCmModifyCallQoS function, which, in turn, calls NdisCmActivateVc to notify the underlying NIC driver to change the call parameters if the requested QoS change can be made.

If the call manager does not accept the client's proposed QoS change, the client either can continue using the unchanged QoS for the call or can tear down the call. If the client and call manager cannot agree on the QoS for a particular call, the creator of the VC is responsible for initiating the teardown of the VC.

Callers of NdisClModifyCallQoS can be running at IRQL <= DISPATCH_LEVEL.

See Also

CO_CALL_PARAMETERS, MiniportCoActivateVc, NdisClCloseCall, NdisCmModifyCallQoSComplete, NdisCoCreateVc, ProtocolClModifyCallQoSComplete, ProtocolCmModifyCallQoS


NdisClOpenAddressFamily

NdisClOpenAddressFamily registers a set of client-supplied functions for connection-oriented communication through a particular NIC using an address family registered by a particular call manager.

NDIS_STATUS
  NdisClOpenAddressFamily(
    IN NDIS_HANDLE  NdisBindingHandle,
    IN PCO_ADDRESS_FAMILY  AddressFamily,
    IN NDIS_HANDLE  ProtocolAfContext,
    IN PNDIS_CLIENT_CHARACTERISTICS  ClCharacteristics,
    IN UINT  SizeOfClCharacteristics,
    OUT PNDIS_HANDLE  NdisAfHandle
    );

Parameters

NdisBindingHandle
Specifies the handle returned by NdisOpenAdapter that identifies the target NIC or the virtual adapter of the next-lower driver to which the caller is bound.
AddressFamily
Pointer to a structure of type CO_ADDRESS_FAMILY describing the call manager and address family to be opened.

This pointer is an input parameter to the client's ProtocolCoAfRegisterNotify function, which calls NdisClOpenAddressFamily.

ProtocolAfContext
Specifies the handle to a caller-supplied resident context area in which the client maintains state for this address family after it has been opened. NDIS passes this handle back to the client in all subsequent calls concerning this address family if the call to NdisClOpenAddressFamily succeeds.
ClCharacteristics
Pointer to an NDIS_CLIENT_CHARACTERISTICS structure set up by the caller. The structure at ClCharacteristics is defined as follows:
typedef struct _NDIS_CLIENT_CHARACTERISTICS {
    UCHAR   MajorVersion;
    UCHAR   MinorVersion;
    USHORT  Filler;           // reserved for system use
    UINT    Reserved;         // reserved for system use
    CO_CREATE_VC_HANDLER  ClCreateVcHandler;
    CO_DELETE_VC_HANDLER  ClDeleteVcHandler;
    CO_REQUEST_HANDLER  ClRequestHandler;
    CO_REQUEST_COMPLETE_HANDLER  ClRequestCompleteHandler;
    CL_OPEN_AF_COMPLETE_HANDLER  ClOpenAfCompleteHandler;
    CL_CLOSE_AF_COMPLETE_HANDLER  ClCloseAfCompleteHandler;
    CL_REG_SAP_COMPLETE_HANDLER  ClRegisterSapCompleteHandler;
    CL_DEREG_SAP_COMPLETE_HANDLER  ClDeregisterSapCompleteHandler;
    CL_MAKE_CALL_COMPLETE_HANDLER  ClMakeCallCompleteHandler;
    CL_MODIFY_CALL_QOS_COMPLETE_HANDLER
                                    ClModifyCallQoSCompleteHandler;
    CL_CLOSE_CALL_COMPLETE_HANDLER  ClCloseCallCompleteHandler;
    CL_ADD_PARTY_COMPLETE_HANDLER  ClAddPartyCompleteHandler;
    CL_DROP_PARTY_COMPLETE_HANDLER  ClDropPartyCompleteHandler;
    CL_INCOMING_CALL_HANDLER  ClIncomingCallHandler;
    CL_INCOMING_CALL_QOS_CHANGE_HANDLER
                                    ClIncomingCallQoSChangeHandler;
    CL_INCOMING_CLOSE_CALL_HANDLER  ClIncomingCloseCallHandler;
    CL_INCOMING_DROP_PARTY_HANDLER  ClIncomingDropPartyHandler;
    CL_CALL_CONNECTED_HANDLER  ClCallConnectedHandler;
} NDIS_CLIENT_CHARACTERISTICS, *PNDIS_CLIENT_CHARACTERISTICS;

The driver should initialize this structure with zeros before setting up the following members:

MajorVersion
Specifies the major version of this structure that the client is using. The current value is 0x05.
MinorVersion
Specifies the minor version of this structure that the client is using. The current value is 0x00.
Filler and Reserved
The caller should ignore these members after zero-initializing this structure.
ClCreateVcHandler
Specifies the entry point of the caller's ProtocolCoCreateVc function.
ClDeleteVcHandler
Specifies the entry point of the caller's ProtocolCoDeleteVc function.
ClRequestHandler
Specifies the entry point of the caller's ProtocolCoRequest function.
ClRequestCompleteHandler
Specifies the entry point of the caller's ProtocolCoRequestComplete function.
ClOpenAfCompleteHandler
Specifies the entry point of the caller's ProtocolClOpenAfComplete function.
ClCloseAfCompleteHandler
Specifies the entry point of the caller's ProtocolClCloseAfComplete function.
ClRegisterSapCompleteHandler
Specifies the entry point of the caller's ProtocolClRegisterSapComplete function. A client uses this function to accept incoming calls from remote machines.
ClDeregisterSapCompleteHandler
Specifies the entry point of the caller's ProtocolClDeregisterSapComplete function.
ClMakeCallCompleteHandler
Specifies the entry point of the caller's ProtocolClMakeCallComplete function. A client uses this function to make outgoing calls to remote machines.
ClModifyCallQoSCompleteHandler
Specifies the entry point of the caller's ProtocolClModifyCallQoSComplete function. A client uses this function to make changes in the quality of service on an established VC dynamically or to negotiate with the call manager to establish the QoS when setting up an incoming call.
ClCloseCallCompleteHandler
Specifies the entry point of the caller's ProtocolClCloseCallComplete function.
ClAddPartyCompleteHandler
Specifies the entry point of the caller's ProtocolClAddPartyComplete function. A client uses this function to establish point-to-multipoint VCs for outgoing calls to remote machines.
ClDropPartyCompleteHandler
Specifies the entry point of the caller's ProtocolClDropPartyComplete function.
ClIncomingCallHandler
Specifies the entry point of the caller's ProtocolClIncomingCall function. A client uses this function to accept incoming calls from remote machines.
ClIncomingCallQoSChangeHandler
Specifies the entry point of the caller's ProtocolClIncomingCallQoSChange function. A client uses this function to accept incoming calls from remote machines on which the sending client can change the QoS dynamically.
ClIncomingCloseCallHandler
Specifies the entry point of the caller's ProtocolClIncomingCloseCall function.
ClIncomingDropPartyHandler
Specifies the entry point of the caller's ProtocolClIncomingDropParty function.
ClCallConnectedHandler
Specifies the entry point of the caller's ProtocolClCallConnected function. A client uses this function to accept incoming calls from remote machines.
SizeOfClCharacteristics
Specifies the size in bytes of the structure at ClCharacteristics.
NdisAfHandle
Pointer to a caller-supplied variable in which this function returns a handle representing the newly opened address family.

Return Value

When NdisClOpenAddressFamily returns anything other than NDIS_STATUS_PENDING, the client should make an internal call to its ProtocolClOpenAfComplete function. Otherwise, NDIS calls the client's ProtocolClOpenAfComplete function when this operation is completed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A connection-oriented client calls NdisClOpenAddressFamily from its ProtocolCoAfRegisterNotify function, after checking the input buffer at AddressFamily to determine whether the client recognizes the call manager and registered addresses. NDIS forwards the client's call of NdisClOpenAddressFamily to the call manager's ProtocolCmOpenAf function, which ensures that the client has passed in a valid address family structure.

The client must set every Cl Xxx member in the NDIS_CLIENT_CHARACTERISTICS structure to a caller-supplied ProtocolCl/CoXxx function when it calls NdisClOpenAddressFamily, even if it does not support incoming calls, outgoing calls, or point-to-multipoint connections. For whatever subset of connection-oriented functionality that such a client does not support, its ProtocolCl/CoXxx functions simply return NDIS_STATUS_NOT_SUPPORTED.

A successful call to NdisClOpenAddressFamily sets up communication from the client either to a connection-oriented NIC driver through a particular call manager that is bound to the same NIC or to an integrated MCM driver for the NIC to which the client is bound. The client can then make itself ready to receive incoming calls with NdisClRegisterSap or can set up a virtual connection with NdisCoCreateVc in order to make an outgoing call with NdisClMakeCall.

If its call to NdisClOpenAddressFamily fails, the client should call NdisCloseAdapter to release its binding to the underlying NIC driver.

Otherwise, the client must save the handle returned at NdisAfHandle. This handle identifies the call manager to which subsequent requests concerning the given address family are directed. The client must treat this returned handle as an opaque variable, passing it unmodified and uninterpreted in subsequent calls to certain NDIS library functions. Usually, callers of NdisClOpenAddressFamily pass an NdisAfHandle pointer to a variable stored in the client-allocated state area at ProtocolAfContext.

NDIS passes the ProtocolAfContext pointer to the client's registered ProtocolClXxx functions in all subsequent calls concerning this address family until the client calls NdisClCloseAddressFamily with the same NdisAfHandle. After the address family is closed, the client can release or reuse the storage it allocated at ProtocolAfContext.

Callers of NdisClOpenAddressFamily must be running at IRQL < DISPATCH_LEVEL.

See Also

CO_ADDRESS_FAMILY, NdisAllocateFromNPagedLookasideList, NdisClCloseAddressFamily, NdisCloseAdapter, NdisClRegisterSap, NdisCoRequest, NdisZeroMemory, ProtocolClAddPartyComplete, ProtocolClCallConnected, ProtocolClCloseAfComplete, ProtocolClCloseCallComplete, ProtocolClDeregisterSapComplete, ProtocolClDropPartyComplete, ProtocolClIncomingCall, ProtocolClIncomingCallQoSChange, ProtocolClIncomingCloseCall, ProtocolClIncomingDropParty, ProtocolClMakeCallComplete, ProtocolClModifyCallQoSComplete, ProtocolClOpenAfComplete, ProtocolClRegisterSapComplete, ProtocolCmOpenAf, ProtocolCoAfRegisterNotify, ProtocolCoCreateVc, ProtocolCoDeleteVc, ProtocolCoRequest, ProtocolCoRequestComplete


NdisCloseAdapter

NdisCloseAdapter releases the binding established and the resources allocated when the protocol called NdisOpenAdapter.

VOID
  NdisCloseAdapter(
    OUT PNDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisBindingHandle
    );

Parameters

Status
Pointer to a caller-supplied variable in which this function returns the status of the close operation, which can be one of the following values:
NDIS_STATUS_SUCCESS
The binding was closed and all resources pertaining to that binding have been released.
NDIS_STATUS_PENDING
A close-adapter request is being handled asynchronously, and the caller's ProtocolCloseAdapterComplete function will be called when the close operation is done.
NdisBindingHandle
Specifies the handle returned by NdisOpenAdapter that identifies the virtual adapter or NIC to be closed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A protocol driver typically calls NdisCloseAdapter from its ProtocolUnbindAdapter function. It can also call NdisCloseAdapter from its ProtocolBindAdapter function, for example, if it failed to set an OID value after calling NdisOpenAdapter to setup a binding.

As soon as a protocol calls NdisCloseAdapter, the handle at NdisBindingHandle should be considered invalid by the caller. It is a programming error to pass this handle in any subsequent call to an Ndis Xxx function.

Callers of NdisCloseAdapter run at IRQL PASSIVE_LEVEL.

See Also

NdisCompleteUnbindAdapter, NdisOpenAdapter, ProtocolCloseAdapterComplete, ProtocolUnbindAdapter


NdisCloseConfiguration

NdisCloseConfiguration releases the handle to the registry key returned by NdisOpenConfiguration, NdisOpenProtocolConfiguration, NdisOpenConfigurationKeyByIndex, or NdisOpenConfigurationKeyByName.

VOID
  NdisCloseConfiguration(
    IN NDIS_HANDLE  ConfigurationHandle
    );

Parameters

ConfigurationHandle
Specifies the handle returned by NdisOpenConfiguration or NdisOpenProtocolConfiguration.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

This function frees any temporary storage allocated in calls to other Ndis Xxx functions that required the returned ConfigurationHandle as a parameter.

Callers of NdisCloseConfiguration run at IRQL PASSIVE_LEVEL.

See Also

DriverEntry of NDIS Protocol Drivers, MiniportInitialize, NdisOpenConfiguration, NdisOpenConfigurationKeyByIndex, NdisOpenConfigurationKeyByName,

NdisOpenProtocolConfiguration, NdisReadConfiguration, NdisReadNetworkAddress, NdisWriteConfiguration, ProtocolBindAdapter


NdisCloseFile

NdisCloseFile releases a handle returned by NdisOpenFile and frees the memory allocated to hold the file contents when it was opened.

VOID
  NdisCloseFile(
    IN NDIS_HANDLE  FileHandle
    );

Parameters

FileHandle
Specifies the handle returned in a preceding call to NdisOpenFile.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

For miniport drivers, calls to this function are valid only during initialization. If the MiniportInitialize function calls NdisOpenFile, it must call NdisCloseFile before it returns control.

Callers of NdisCloseFile run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisMapFile, NdisOpenFile, NdisUnmapFile


NdisClRegisterSap

NdisClRegisterSap registers a SAP on which the client can receive incoming calls from a remote node.

NDIS_STATUS
  NdisClRegisterSap(
    IN NDIS_HANDLE  NdisAfHandle,
    IN NDIS_HANDLE  ProtocolSapContext,
    IN PCO_SAP  Sap,
    OUT PNDIS_HANDLE  NdisSapHandle
    );

Parameters

NdisAfHandle
Specifies the handle returned by NdisClOpenAddressFamily, which implicitly identifies the call manager with which to register the SAP.
ProtocolSapContext
Specifies the handle to a caller-supplied resident context area in which the client maintains state for this SAP after it has been opened. NDIS passes this handle back to the client in all subsequent calls concerning this SAP if the call to NdisClRegisterSap succeeds.
Sap
Pointer to a client-supplied specification for the SAP to be opened, formatted as a structure of type CO_SAP.
NdisSapHandle
Pointer to a variable in which a handle to the newly registered SAP is returned if this call succeeds.

Return Value

When NdisClRegisterSap returns anything other than NDIS_STATUS_PENDING, the client should make an internal call to its ProtocolClRegisterSapComplete function. Otherwise, NDIS calls the client's ProtocolClRegisterSapComplete function when this operation is completed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

With a call to NdisClRegisterSap, a client requests notifications of incoming calls on a particular SAP. NDIS forwards the given SAP information to the call manager's ProtocolCmRegisterSap function for validation. If the given SAP is already in use or if the call manager does not recognize the client-supplied specification at Sap, the call manager fails this request.

SAP format is medium-dependent and specific to the address family supported by the call manager, which uses registered SAPs subsequently to route incoming calls to the appropriate client. A call manager can register SAPs for established PVCs without contacting other network components, depending on the underlying medium. For example, if a SAP specification given to NdisClRegisterSap matches one or more PVCs already set up by an ATM call manager, the client can receive incoming calls on those PVCs immediately, even while its SAP registration is still pending.

If its call to NdisClRegisterSap succeeds, the client must save the handle returned at NdisSapHandle because it is a required parameter to NdisClDeregisterSap. Callers of NdisClRegisterSap usually pass a pointer to a variable in the client-allocated state area at ProtocolSapContext so that NDIS can set it to the NdisSapHandle if this call succeeds. NDIS passes the given ProtocolSapContext to the client's registered ProtocolCl/CoXxx functions in all subsequent calls concerning this SAP until the client calls NdisClDeregisterSap.

Usually, a client calls NdisClRegisterSap from its ProtocolAfRegisterNotify function following its successful call to NdisClOpenAddressFamily. Registering one or more SAPs allows the client to receive its incoming call(s) as soon as the call manager receives them over the network.

By contrast with client-initiated outgoing calls, a client does not call NdisCoCreateVc before it calls NdisClRegisterSap. For incoming calls, the call manager initiates the creation of the VC, as follows:

  • On receipt of an incoming call on a registered SAP, the call manager first calls NdisCoCreateVc, causing NDIS to call the client's ProtocolCoCreateVc function.
  • When the VC has been set up and activated, the call manager calls NdisCmDispatchIncomingCall, causing NDIS to call the client's ProtocolClIncomingCall function.

Callers of NdisClRegisterSap can be running at IRQL <= DISPATCH_LEVEL.

See Also

CO_SAP, NdisClDeregisterSap, NdisClMakeCall, NdisCmDispatchIncomingCall, NdisCoCreateVc, ProtocolClIncomingCall, ProtocolClRegisterSapComplete, ProtocolCmRegisterSap, ProtocolCoAfRegisterNotify, ProtocolCoCreateVc


NdisCmActivateVc

NdisCmActivateVc passes CM-supplied call parameters, including media parameters, for a particular VC down to the underlying NIC driver.

NDIS_STATUS
  NdisCmActivateVc(
    IN NDIS_HANDLE  NdisVcHandle,
    IN OUT PCO_CALL_PARAMETERS  CallParameters
    );

Parameters

NdisVcHandle
Specifies the handle identifying the VC on which to set call parameters. The call manager either obtained this handle from NdisCoCreateVc for an incoming call or as an input parameter to its ProtocolCoCreateVc function for a client-initiated outgoing call.
CallParameters
Pointer to a CM-allocated resident buffer, formatted as a structure of type CO_CALL_PARAMETERS, containing all the media-specific parameters that the underlying miniport driver uses for VC activation.

Return Value

When NdisCmActivateVc returns anything other than NDIS_STATUS_PENDING, the call manager should make an internal call to its ProtocolCmActivateVcComplete function. Otherwise, NDIS calls the CM's ProtocolCmActivateVcComplete function when this operation is completed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisCmActivateVc notifies the underlying NIC driver to set up call and media parameters on a newly created VC or to change those of an established VC. NDIS forwards the given call parameters and VC handle to the underlying NIC driver's MiniportCoActivateVc function, which sets up all necessary resources to track the state of the VC and makes itself and its NIC ready for data transfers on the VC.

A stand-alone CM always calls NdisCmActivateVc after establishing a connection on a VC but before any data is sent or received on that VC. For the duration of the connection, a CM can call NdisCmActivateVc many times with the same NdisVcHandle as conditions on the network change and/or whenever the client calls NdisClModifyCallQoS. At each such call to NdisCmActivateVc, the underlying NIC driver's MiniportCoActivateVc function must do either of the following:

  • Update the state that the NIC driver maintains about call parameters to the new values supplied by the call manager if the miniport driver can continue to make transfers on the VC according to the newly modified call parameters.
  • Fail the call if the NIC driver cannot continue to make transfers under the constraints of the given call parameters.

When the underlying miniport driver fails a request to set or reset call parameters, the call manager might modify its original specification at CallParameters and call NdisCmActivateVc again. The limit on the number of times any call manager makes repeated attempts to activate a VC is implementation-dependent.

For a client-initiated outgoing call, a stand-alone CM usually calls NdisCmActivateVc immediately following the packet exchange confirming a negotiated agreement with the remote target of the call or successful call-setup at the switch, before it notifies NDIS (and the client) of outgoing call completion with NdisCmMakeCallComplete. For an incoming call, a call manager usually calls NdisCmActivateVc after it has called NdisCoCreateVc successfully and before it calls NdisCmDispatchIncomingCall.

In the process of setting up an outgoing call and while any VC remains activated, the client can request changes to the call parameters for that VC, for example, by calling NdisClModifyCallQos. After verifying the validity of the given call parameters for any such a request, the stand-alone call manager must call NdisCmActivateVc to pass the modified call parameters down to the underlying miniport driver.

Only stand-alone call managers, which register themselves with NDIS as protocols, can call NdisCmActivateVc. Connection-oriented miniport drivers that provide integrated call-management support call NdisMCmActivateVc instead.

Callers of NdisCmActivateVc can be running at IRQL <= DISPATCH_LEVEL.

See Also

CO_CALL_PARAMETERS, MiniportCoActivateVc, NdisClMakeCall, NdisClModifyCallQos, NdisCmDeactivateVc, NdisCmDispatchIncomingCall, NdisMCmActivateVc, NdisCoCreateVc, ProtocolCmActivateVcComplete, ProtocolCoCreateVc


NdisCmAddPartyComplete

NdisCmAddPartyComplete returns the final status of a client's request, for which the call manager previously returned NDIS_STATUS_PENDING, to add a party on an established multipoint VC.

VOID
  NdisCmAddPartyComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisPartyHandle,
    IN NDIS_HANDLE  CallMgrPartyContext  OPTIONAL,
    IN PCO_CALL_PARAMETERS  CallParameters
    );

Parameters

Status
Specifies the final status of the call manager's add-party operation, either NDIS_STATUS_SUCCESS or any NDIS_STATUS_XXX except NDIS_STATUS_PENDING.
NdisPartyHandle
Specifies the handle identifying the party. This handle was input to the call manager's ProtocolCmAddParty function.
CallMgrPartyContext
Specifies the handle to a caller-allocated resident context area in which the call manager will maintain party-specific state information if the add-party operation succeeded. Otherwise, this parameter can be NULL because it is ignored.
CallParameters
Pointer to a structure of type CO_CALL_PARAMETERS that contains the call parameters, originally supplied by the client, for the party to be added.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If a stand-alone call manager's ProtocolCmAddParty function returns NDIS_STATUS_PENDING, the CM subsequently must call NdisCmAddPartyComplete to notify the client and NDIS that its attempt to add a party on the multipoint VC has completed, whether successfully or with an error.

If the client passed in traffic parameters at CallParameters that did not match those already established for the multipoint VC, the designer of the call manager must determine how to handle this condition, subject to any constraints imposed by the network medium. Possibilities include the following:

  • Set up the per-party traffic parameters if the underlying network medium supports this feature on multipoint VCs.
  • Reset the client-supplied traffic parameters to those established for the VC when the original outgoing call was made before the CM calls NdisCmAddPartyComplete with NDIS_STATUS_SUCCESS as the Status.
  • Change the traffic parameters for the VC and, for every party currently connected on it, to the client-supplied values before the CM calls NdisCmAddPartyComplete with NDIS_STATUS_SUCCESS as the Status.
  • Fail the client's attempt to add a party. (This alternative implicitly forces clients to set up their traffic parameters for a multipoint VC with NdisClMakeCall and to specify the same traffic parameters at each subsequent call to NdisClAddParty for the given multipoint VC.)

For some connection-oriented media, such as ATM, traffic parameters are per-VC in nature and, consequently, identical for all parties on a multipoint VC.

If the CM sets Status to NDIS_STATUS_SUCCESS, it must supply an explicit handle, which is usually a pointer to the CM-allocated per-party state area, as CallMgrPartyContext when it calls NdisCmAddPartyComplete.

A call to NdisCmAddPartyComplete causes NDIS to call the client's ProtocolClAddPartyComplete function.

Only stand-alone call managers, which register themselves with NDIS as protocols, can call NdisCmAddPartyComplete. Connection-oriented miniport drivers that provide integrated call-management support call NdisMCmAddPartyComplete instead.

Callers of NdisCmAddPartyComplete can be running at IRQL <= DISPATCH_LEVEL.

See Also

CO_CALL_PARAMETERS, NdisAllocateFromNPagedLookasideList, NdisClAddParty, NdisMCmAddPartyComplete, ProtocolClAddPartyComplete, ProtocolCmAddParty


NdisCmCloseAddressFamilyComplete

NdisCmCloseAddressFamilyComplete returns the final status of a client's request, for which the CM's ProtocolCmCloseAf function returned NDIS_STATUS_PENDING, to close the AF.

VOID
  NdisCmCloseAddressFamilyComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisAfHandle
    );

Parameters

Status
The call manager sets this to NDIS_STATUS_SUCCESS.
NdisAfHandle
Specifies the NDIS-supplied handle passed to the call manager's ProtocolCmOpenAf function when this client originally opened the address family.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A stand-alone call manager must call NdisCmCloseAddressFamilyComplete if its ProtocolCmCloseAf function previously returned NDIS_STATUS_PENDING for the given NdisAfHandle. The client, which initiated the pended close-AF operation with a call to NdisClCloseAddressFamily, cannot release the resources it allocated to track communications on the AF until the CM's call to NdisCmCloseAddressFamilyComplete causes a call to that client's ProtocolClCloseAfComplete function.

After a call to NdisCmCloseAddressFamilyComplete, the call manager cannot subsequently use the NdisAfHandle, which becomes invalid for the call manager as soon as this call occurs.

Only stand-alone call managers, which register themselves with NDIS as protocols, can call NdisCmCloseAddressFamilyComplete. Connection-oriented miniport drivers that provide integrated call-management support must call NdisMCmCloseAddressFamilyComplete instead.

Callers of NdisCmOpenAddressFamilyComplete can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisClCloseAddressFamily, NdisMCmCloseAddressFamilyComplete, ProtocolClCloseAfComplete, ProtocolCmCloseAf, ProtocolCmOpenAf


NdisCmCloseCallComplete

NdisCmCloseCallComplete returns the final status of a client's request, for which the call manager previously returned NDIS_STATUS_PENDING, to tear down a call.

VOID
  NdisCmCloseCallComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisVcHandle,
    IN NDIS_HANDLE  NdisPartyHandle  OPTIONAL
    );

Parameters

Status
Specifies the final status of the client's request that the CM close the connection, either NDIS_STATUS_SUCCESS or any CM-determined NDIS_STATUS_XXX except NDIS_STATUS_PENDING.
NdisVcHandle
Specifies the handle to the VC for the call. This handle was supplied by NDIS when the VC was originally created, whether by the call manager or client, with NdisCoCreateVc. More recently, the call manager obtained this handle from its per-VC state designated by the CallMgrVcContext passed as an input parameter to its ProtocolCmCloseCall function.
NdisPartyHandle
Specifies either NULL if the NdisVcHandle represents a point-to-point VC or the handle to the last remaining party on a multipoint connection, which the CM obtained from its per-party state designated by the CallMgrPartyContext passed as an input parameter to its ProtocolCmCloseCall function.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If a stand-alone call manager's ProtocolCmCloseCall function returns NDIS_STATUS_PENDING, the CM must call NdisCmCloseCallComplete subsequently to notify the client and NDIS that its attempt to break the connection has completed, whether successfully or with an error. A call to NdisCmCloseCallComplete causes NDIS to call the client's ProtocolClCloseCallComplete function.

If it passes NDIS_STATUS_SUCCESS as the Status, the call manager should consider the NdisVcHandle (and NdisPartyHandle, if any) unusable for transfers over the network as soon as it calls NdisCmCloseCallComplete. If the call manager originally created the VC, it should call NdisCoDeleteVc with the same NdisVcHandle that it just passed to NdisCmCloseCallComplete. If the client created this VC, the call manager can expect a call to its ProtocolCoDeleteVc function with the ProtocolVcContext, where it has the same NdisVcHandle, as an input parameter.

Only stand-alone call managers, which register themselves with NDIS as protocols, can call NdisCmCloseCallComplete. Connection-oriented miniport drivers that provide integrated call-management support call NdisMCmCloseCallComplete instead.

Callers of NdisCmCloseCallComplete can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisClCloseCall, NdisMCmCloseCallComplete, NdisCoDeleteVc, ProtocolClCloseCallComplete, ProtocolCoDeleteVc


NdisCmDeactivateVc

NdisCmDeactivateVc notifies NDIS and the underlying NIC driver that there will be no further transfers on a particular active VC.

NDIS_STATUS
  NdisCmDeactivateVc(
    IN NDIS_HANDLE  NdisVcHandle
    );

Parameter

NdisVcHandle
Specifies the handle identifying the VC. This handle was supplied by NDIS to the call manager either when it called NdisCoCreateVc for an incoming call or when its ProtocolCoCreateVc function set up the VC for a client-initiated outgoing call.

Return Value

When NdisCmDeactivateVc returns anything other than NDIS_STATUS_PENDING, the call manager should make an internal call to its ProtocolCmDeactivateVcComplete function. Otherwise, NDIS calls the CM's ProtocolCmDeactivateVcComplete function when this operation is completed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A stand-alone call manager calls NdisCmDeactivateVc as an essential step in closing a call, usually after the packet exchange with network components that tears down the call.

A call to NdisCmDeactivateVc causes NDIS to call the underlying NIC driver's MiniportCoDeactivateVc function, which can discard the current call parameters for transfers on the VC, possibly reinitializing them to miniport driver-determined default values. If the VC is reactivated subsequently for another call, the client or call manager will supply new call parameters to the miniport driver.

The NdisVcHandle passed to NdisCmDeactivateVc remains valid after VC deactivation is completed. The deactivation of any VC allows its creator to reinitialize the VC for reuse:

  • Following VC deactivation and the closing of the call, a client can reuse a VC that it originally created to make another call with NdisClMakeCall.
  • Following VC deactivation and the closing of the call, a CM can reuse a VC that it originally created to indicate another incoming call to the same client with NdisCmDispatchIncomingCall.

The creator of a particular VC that will not be reused calls NdisCoDeleteVc to destroy that VC.

Only stand-alone call managers, which register themselves with NDIS as protocols, can call NdisCmDeactivateVc. Connection-oriented miniport drivers that provide integrated call-managment support call NdisMCmDeactivateVc instead.

Callers of NdisCmDeactivateVc can be running at IRQL <= DISPATCH_LEVEL.

See Also

MiniportCoDeactivateVc, NdisClCloseCall, NdisClMakeCall, NdisCmActivateVc, NdisCmDispatchIncomingCall, NdisMCmDeactivateVc, ProtocolCmCloseCall, ProtocolCmDeactivateVcComplete


NdisCmDeregisterSapComplete

NdisCmDeregisterSapComplete returns the final status of a client's request, for which the call manager previously returned NDIS_STATUS_PENDING, to deregister a SAP.

VOID
  NdisCmDeregisterSapComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisSapHandle
    );

Parameters

Status
Specifies NDIS_STATUS_SUCCESS.
NdisSapHandle
Specifies the handle identifying the SAP.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisCmDeregisterSapComplete notifies both NDIS and the client that the call manager has completed the SAP-deregistration request for which its ProtocolCmDeregisterSap function previously returned NDIS_STATUS_PENDING.

A call to NdisCmDeregisterSapComplete causes NDIS to call the client's ProtocolClDeregisterSapComplete function.

The call manager should consider the NdisSapHandle invalid when NdisCmDeregisterSapComplete returns control.

Only stand-alone call managers, which register themselves with NDIS as protocols, can call NdisCmDeregisterSapComplete. Connection-oriented miniport drivers that provide integrated call-managment support call NdisMCmDeregisterSapComplete instead.

Callers of NdisCmDeregisterSapComplete can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisClDeregisterSap, NdisMCmDeregisterSapComplete, ProtocolClDeregisterSapComplete, ProtocolCmDeregisterSap


NdisCmDispatchCallConnected

NdisCmDispatchCallConnected notifies NDIS and the client that data transfers can begin on a VC that the call manager created for an incoming call initiated on a remote node.

VOID
  NdisCmDispatchCallConnected(
    IN NDIS_HANDLE  NdisVcHandle
    );

Parameter

NdisVcHandle
Specifies the handle to the VC that represents the connection, which was created with NdisCoCreateVc when the call manager's ProtocolCoReceivePacket function was notified of the incoming call.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A stand-alone CM's ProtocolCmIncomingCallComplete function calls NdisCmDispatchCallConnected to complete the final handshake for an incoming call from a remote node, which the client has already accepted.

A call to NdisCmDispatchCallConnected causes NDIS to call the client's ProtocolClCallConnected function.

Only stand-alone call managers, which register themselves with NDIS as protocols, can call NdisCmDispatchCallConnected. Connection-oriented miniport drivers that provide integrated call-managment support call NdisMCmDispatchCallConnected instead.

Callers of NdisCmDispatchCallConnected can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisCmDispatchIncomingCall, NdisMCmDispatchCallConnected, ProtocolClCallConnected, ProtocolCmIncomingCallComplete, ProtocolCoReceivePacket


NdisCmDispatchIncomingCall

NdisCmDispatchIncomingCall informs the client of an incoming call on a SAP previously registered by that client.

NDIS_STATUS
  NdisCmDispatchIncomingCall(
    IN NDIS_HANDLE  NdisSapHandle,
    IN NDIS_HANDLE  NdisVcHandle,
    IN PCO_CALL_PARAMETERS  CallParameters
    );

Parameters

NdisSapHandle
Specifies the handle identifying the SAP. NDIS set up this handle when the client originally called NdisClRegisterSap, and the call manager originally obtained this handle as an input parameter to its ProtocolCmRegisterSap function.
NdisVcHandle
Specifies the handle identifying the VC, created with NdisCoCreateVc when the call manager processes the incoming call offer directed to this registered SAP.
CallParameters
Pointer to a structure of type CO_CALL_PARAMETERS that specifies the traffic and media parameters for the VC.

Return Value

When NdisCmDispatchIncomingCall returns anything other than NDIS_STATUS_PENDING, the call manager should make an internal call to its ProtocolCmIncomingCallComplete function. Otherwise, NDIS calls the CM's ProtocolCmIncomingCallComplete function when this operation is completed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Before calling NdisCmDispatchIncomingCall, a stand-alone call manager has already done the following:

  • Identified the target SAP, previously registered by a particular client, for the call (actually, a request to make a connection) that it received over the network
  • Created a VC for the incoming call with NdisCoCreateVc
  • Possibly negotiated about acceptable call parameters over the network, or accepted the call parameters sent from the remote node
  • Activated the VC with NdisCmActivateVc, causing the underlying NIC driver to make itself ready for transfers on the VC in accord with the negotiated or accepted call parameters

The CM's call to NdisCmDispatchIncomingCall causes NDIS to call the client's ProtocolClIncomingCall function, within which the client either accepts or rejects the requested connection. After deciding whether to accept the connection, the client calls NdisClIncomingCallComplete, which, in turn, calls the CM's ProtocolCmIncomingCallComplete function. If the client accepted the call, the CM next calls NdisCmDispatchCallConnected. Otherwise, it deactivates (and possibly deletes) the VC it created, after notifying the remote node that the offered call was rejected.

Only stand-alone call managers, which register themselves with NDIS as protocols, can call NdisCmDispatchIncomingCall. Connection-oriented miniport drivers that provide integrated call-managment support call NdisMCmDispatchIncomingCall instead.

Callers of NdisCmDispatchIncomingCall can be running at IRQL <= DISPATCH_LEVEL.

See Also

CO_CALL_PARAMETERS, NdisClRegisterSap, NdisClIncomingCallComplete, NdisCmActivateVc, NdisCmDeactivateVc, NdisCmDispatchCallConnected, NdisCoCreateVc, NdisCoDeleteVc, NdisCoSendPackets, NdisMCmDispatchIncomingCall, ProtocolClIncomingCall, ProtocolCmIncomingCallComplete, ProtocolCmRegisterSap, ProtocolCoReceivePacket


NdisCmDispatchIncomingCallQoSChange

NdisCmDispatchIncomingCallQoSChange notifies a client that a request to change the quality of service on that client's active connection has been received over the network.

VOID
  NdisCmDispatchIncomingCallQoSChange(
    IN NDIS_HANDLE  NdisVcHandle,
    IN PCO_CALL_PARAMETERS  CallParameters
    );

Parameters

NdisVcHandle
Specifies the handle to the VC for which the change in QoS is being requested. The call manager originally obtained this handle either when it called NdisCoCreateVc to set up this connection for an incoming call or as an input parameter to its ProtocolCoCreateVc function.
CallParameters
Pointer to a structure of type CO_CALL_PARAMETERS that specifies the new QoS, requested by the client on the remote node, for this connection.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A stand-alone call manager calls NdisCmDispatchIncomingCallQoSChange to notify the client that it has received a request to modify the QoS on an active connection. Such a CM supports dynamic QoS changes on active calls, which is a feature like QoS itself that depends on the signalling protocol. For example, ATM networks do not support dynamic QoS changes on active connections.

When the CM itself receives a request for a QoS change, the call manager passes appropriately modified call parameters to NdisCmActivateVc, so the underlying NIC driver also is notified of the proposed QoS change. Assuming the underlying NIC driver accepts the changed call parameters, the CM then calls NdisCmDispatchIncomingCallQosChange.

A call to NdisCmDispatchIncomingCallQoSChange causes NDIS to call the client's ProtocolClIncomingQoSChange function. The client accepts the proposed modifications to the call parameters for the VC by doing nothing, except possibly updating any state it maintains about the QoS for the VC, and returning control. Otherwise, the client rejects the proposed QoS change by tearing down the call.

Only stand-alone call managers, which register themselves with NDIS as protocols, can call NdisCmDispatchIncomingCallQoSChange. Connection-oriented miniport drivers that provide integrated call-management support call NdisMCmDispatchIncomingCallQoSChange instead.

Callers of NdisCmDispatchIncomingCallQoSChange can be running at IRQL <= DISPATCH_LEVEL.

See Also

CO_CALL_PARAMETERS, MiniportCoActivateVc, NdisClCloseCall, NdisClModifyCallQoS, NdisCmActivateVc, NdisMCmDispatchIncomingCallQoSChange, ProtocolClIncomingCallQosChange, ProtocolCoReceivePacket


NdisCmDispatchIncomingCloseCall

NdisCmDispatchIncomingCloseCall tells a client to tear down an active or offered call, usually because the call manager has received a request from the network to close the connection.

VOID
  NdisCmDispatchIncomingCloseCall(
    IN NDIS_STATUS  CloseStatus,
    IN NDIS_HANDLE  NdisVcHandle,
    IN PVOID  Buffer  OPTIONAL,
    IN UINT  Size
    );

Parameters

CloseStatus
Specifies a CM-determined NDIS_STATUS_XXX, indicating the reason for the disconnect request. During normal network operations, a call manager passes NDIS_STATUS_SUCCESS to indicate that it has received a request, initiated by the remote party, to close an active call.
NdisVcHandle
Specifies the handle to the VC of the call being disconnected. This handle was supplied by NDIS when the VC was originally created, whether by the call manager or client, with NdisCoCreateVc.
Buffer
Pointer to a caller-allocated resident buffer containing additional protocol-specific disconnect data, if any. Depending on the underlying medium, this pointer can be NULL. For example, this parameter is NULL on ATM networks.
Size
Specifies the size in bytes of the buffer, zero if Buffer is NULL.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

In the course of normal network operations, a stand-alone CM calls NdisCmDispatchIncomingCloseCall with the CloseStatus set to NDIS_STATUS_SUCCESS because the corresponding client on the remote node has called NdisClCloseCall.

However, a call manager also can call NdisCmDispatchIncomingCloseCall if either of the following occurs:

  • The call manager has notified a client of an incoming call offer. When the CM's ProtocolCmIncomingCallComplete function is called with the client's acceptance, it validates the input call parameters, which that client has modified. ProtocolCmIncomingCallComplete determines that the client is proposing unsupportable call parameters for the connection, so it calls NdisCmDispatchIncomingCloseCall.
  • Abormal network conditions force the call manager to tear down active calls. For example, if the call manager is notified when any link on the connection between this client and the remote party to the connection goes down, the CM would call NdisCmDispatchIncomingCloseCall to prevent the client from attempting (or expecting) further data transfers on such a broken connection.

After tearing down any call, the original creator of the VC is responsible for calling NdisCoDeleteVc after releasing any additional resources it had associated with the VC.

A call to NdisCmDispatchIncomingCloseCall causes NDIS to call the client's ProtocolClIncomingCloseCall function.

Only stand-alone call managers, which register themselves with NDIS as protocols, can call NdisCmDispatchIncomingCloseCall. Connection-oriented miniport drivers that provide call-management support call NdisMCmDispatchIncomingCall instead.

Callers of NdisCmDispatchIncomingCloseCall can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisClCloseCall, NdisCmDispatchIncomingDropParty, NdisCoDeleteVc, NdisMCmDispatchIncomingCloseCall, ProtocolClIncomingCloseCall, ProtocolCoReceivePacket, ProtocolCoStatus


NdisCmDispatchIncomingDropParty

NdisCmDispatchIncomingDropParty notifies a client that it should remove a particular party on a multipoint VC, usually because the call manager has received a request over the network to close an active multipoint connection.

VOID
  NdisCmDispatchIncomingDropParty(
    IN NDIS_STATUS  DropStatus,
    IN NDIS_HANDLE  NdisPartyHandle,
    IN PVOID  Buffer  OPTIONAL,
    IN UINT  Size
    );

Parameters

DropStatus
Indicates the reason this party is being dropped, usually NDIS_STATUS_SUCCESS if the remote party simply requested that its connection be closed.
NdisPartyHandle
Specifies the handle that identifies the party to be dropped from the multipoint VC, which must have other parties that are still connected.
Buffer
Pointer to a caller-allocated resident buffer containing additional protocol-specific data received from the remote party, if any. Depending on the underlying medium, this pointer can be NULL. For example, this parameter is NULL on ATM networks.
Size
Specifies the size in bytes of the buffer, zero if Buffer is NULL.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

In the course of normal network operations, a stand-alone call manager's ProtocolCoReceivePacket function calls NdisCmDispatchIncomingDropParty with the CloseStatus set to NDIS_STATUS_SUCCESS because a remote client on a multipoint connection has called NdisClCloseCall.

However, a call manager also can call NdisCmDispatchIncomingDropParty with a CM-determined CloseStatus at the behest of the network itself if abnormal network conditions occur, such as the failure of a switch on the path between the local client and one or more client(s) on an established multipoint connection.

A call to NdisCmDispatchIncomingDropParty causes NDIS to call the client's ProtocolClIncomingDropParty function.

If the NdisPartyHandle identifies the last remaining party on the given VC, the CM calls NdisCmDispatchIncomingCloseCall, rather than NdisCmDispatchIncomingDropParty.

Only stand-alone call managers, which register themselves with NDIS as protocols, can call NdisCmDispatchIncomingDropParty. Connection-oriented miniport drivers that provide integrated call-management support call NdisMCmDispatchIncomingDropParty instead.

Callers of NdisCmDispatchIncomingDropParty can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisClDropParty, NdisCmDispatchIncomingCloseCall, NdisMCmDispatchIncomingDropParty, ProtocolClIncomingDropParty, ProtocolCoReceivePacket


NdisCmDropPartyComplete

NdisCmDropPartyComplete returns the final status of a client's request, for which the call manager previously returned NDIS_STATUS_PENDING, to remove a party from a multipoint VC.

VOID
  NdisCmDropPartyComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisPartyHandle
    );

Parameters

Status
Specifies the final status of the requested operation, either NDIS_STATUS_SUCCESS or any CM-determined NDIS_STATUS_XXX except NDIS_STATUS_PENDING.
NdisPartyHandle
Specifies the handle to the party that the client requested to be dropped. The call manager obtained this handle from the state area designated by CallMgrPartyContext that was passed as an input parameter to its ProtocolCmDropParty function.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A stand-alone call manager must call NdisCmDropPartyComplete if its ProtocolCmDropParty function previously returned NDIS_STATUS_PENDING for the given NdisPartyHandle. Neither NDIS nor the client, which initiated the pended drop-party operation with a call to NdisClDropParty, can release the resources they allocated to maintain per-party state until the CM's call to NdisCmDropPartyComplete causes a call to that client's ProtocolClDropPartyComplete function.

If it passes NDIS_STATUS_SUCCESS for the Status, the call manager should consider the NdisPartyHandle invalid as soon as it calls NdisCmDropPartyComplete. The CM can release (or reinitialize for reuse) any resources that it allocated to maintain state for this party when NdisCmDropPartyComplete returns control.

Only stand-alone call managers, which register themselves with NDIS as protocols, can call NdisCmDropPartyComplete. Connection-oriented miniport drivers that provide integrated call-management support call NdisMCmDropPartyComplete instead.

Callers of NdisCmDropPartyComplete can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisClDropParty, NdisMCmDropPartyComplete, ProtocolClDropPartyComplete, ProtocolCmDropParty


NdisCmMakeCallComplete

NdisCmMakeCallComplete returns the final status of a client's request, for which the call manager previously returned NDIS_STATUS_PENDING, to make an outgoing call.

VOID
  NdisCmMakeCallComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisVcHandle,
    IN NDIS_HANDLE  NdisPartyHandle  OPTIONAL,
    IN NDIS_HANDLE  CallMgrPartyContext  OPTIONAL,
    IN PCO_CALL_PARAMETERS  CallParameters
    );

Parameters

Status
Specifies the final status of the attempt to make the connection, either NDIS_STATUS_SUCCESS or any CM-determined NDIS_STATUS_XXX except NDIS_STATUS_PENDING.
NdisVcHandle
Specifies the handle to the client-created VC, which the call manager originally obtained as an input parameter to its ProtocolCoCreateVc function. More recently, the CM obtained this handle from its per-VC state designated by the CallMgrVcContext passed in to its ProtocolCmMakeCall function.
NdisPartyHandle
Specifies the handle to the initial party on the client-created multipoint VC, which the call manager obtained as an input parameter to its ProtocolCmMakeCall function. If the given NdisVcHandle represented a point-to-point VC, this parameter was NULL.
CallMgrPartyContext
Specifies the CM-supplied handle to a caller-allocated resident context area, in which the CM will maintain per-party state information, or NULL if NdisPartyHandle is NULL. For a multipoint VC, NDIS passes this CM-supplied CallManagerPartyContext handle in all subsequent calls to the ProtocolCmXxx functions that concern this party. Otherwise, NDIS ignores this parameter.
CallParameters
Pointer to a structure of type CO_CALL_PARAMETERS that specifies the call parameters set up for this connection if Status is NDIS_STATUS_SUCCESS.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A stand-alone call manager should call NdisMCmMakeCallComplete with NDIS_STATUS_SUCCESS only if the underlying miniport driver is ready to make data transfers on the VC. That is, the call manager has negotiated with the network to establish call parameters for the VC and called NdisCmActivateVc successfully.

A stand-alone call manager must call NdisCmMakeCallComplete if its ProtocolCmMakeCall function previously returned NDIS_STATUS_PENDING for the given NdisVcHandle. The client that initiated the pending outgoing call cannot use the VC to make transfers until the CM calls NdisCmMakeCallComplete with NDIS_STATUS_SUCCESS.

Even if the attempted connection failed, neither NDIS nor the client can release the resources they allocated to maintain state until the CM's call to NdisCmMakeCallComplete causes a call to that client's ProtocolClMakeCallComplete function. In fact, neglecting to call NdisCmMakeCallComplete for a failed attempt to set up such a connection causes a memory leak in the call manager as well; it prevents the client from tearing down the VC it created for its failed outgoing call, so the CM is not called to release the resources it allocated for that VC.

If the CM passes an error, such as NDIS_STATUS_FAILURE, for the Status, it should consider the NdisPartyHandle, if any, invalid as soon as it calls NdisCmMakeCallComplete. The CM can release (or reinitialize for reuse) any resources that it allocated to maintain state for the given party when NdisCmMakeCallComplete returns control. The CM's ProtocolCoDeleteVc function will subsequently be called to release any resources that the CM allocated for tracking the state of the client-created VC whenever the CM passes an error status to NdisCmMakeCallComplete.

In the course of setting up a client-initiated outgoing call, the CM can modify the client-supplied call parameters originally passed in to its ProtocolCmMakeCall function. If it does, the CM must pass its modifications in the buffer at CallParameters when it calls NdisCmMakeCallComplete. If the client finds these modified call parameters unacceptable, it will then tear down the call, which also causes a call to the CM's ProtocolCoDeleteVc function.

Only stand-alone call managers, which register themselves with NDIS as protocols, can call NdisCmMakeCallComplete. Miniport drivers that provide integrated call-management support call NdisMCmMakeCallComplete instead.

Callers of NdisCmMakeCallComplete can be running at IRQL <= DISPATCH_LEVEL.

See Also

CO_CALL_PARAMETERS, NdisAllocateFromNPagedLookasideList, NdisClMakeCall, NdisMCmMakeCallComplete, ProtocolClMakeCallComplete, ProtocolCmMakeCall, ProtocolCoDeleteVc


NdisCmModifyCallQoSComplete

NdisCmModifyCallQoSComplete indicates the completion of the client's request, for which the call manager previously returned NDIS_STATUS_PENDING, to modify the quality of service on a VC.

VOID
  NdisCmModifyCallQoSComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisVcHandle,
    IN PCO_CALL_PARAMETERS  CallParameters
    );

Parameters

Status
Specifies the final status of the client's request to modify the QoS on this VC, either NDIS_STATUS_SUCCESS or any CM-determined NDIS_STATUS_XXX except NDIS_STATUS_PENDING.
NdisVcHandle
Specifies the handle to the VC, obtained from the CallMgrVcContext passed in to the CM's ProtocolCmModifyCallQoS function for this request.
CallParameters
Pointer to a structure of type CO_CALL_PARAMETERS specifying a QoS acceptable to the call manager and underlying NIC driver if Status is set to NDIS_STATUS_SUCCESS.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A call to NdisCmModifyCallQoSComplete causes NDIS to call the client's ProtocolClModifyCallQoSComplete function.

Because the CM can modify the client-supplied call parameters that were input to its ProtocolCmModifyCallQoS function before it calls NdisCmModifyCallQoSComplete, the client's ProtocolClModifyCallQoSComplete function examines the QoS to determine whether it is acceptable to the client. ProtocolClModifyCallQoSComplete simply returns control if the client accepts the given call parameters. Otherwise, the client tears down the call.

Only stand-alone call managers, which register themselves with NDIS as protocols, can call NdisCmModifyCallQosComplete. Connection-oriented miniport drivers that provide integrated call-management support call NdisMCmModifyCallQosComplete instead.

Callers of NdisCmModifyCallQoSComplete can be running at IRQL <= DISPATCH_LEVEL.

See Also

CO_CALL_PARAMETERS, NdisClModifyCallQoS, NdisMCmModifyCallQosComplete, ProtocolClModifyCallQoSComplete, ProtocolCmModifyCallQoS


NdisCmOpenAddressFamilyComplete

NdisCmOpenAddressFamilyComplete returns the final status of a stand-alone call manager's open of a given AF for a particular client after the call manager returned NDIS_STATUS_PENDING in response to that client's original open-AF request.

VOID
  NdisCmOpenAddressFamilyComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisAfHandle,
    IN NDIS_HANDLE  CallMgrAfContext
    );

Parameters

Status
Specifies the final status of the open-AF operation, either NDIS_STATUS_SUCCESS or any CM-determined error NDIS_STATUS_XXX except NDIS_STATUS_PENDING.
NdisAfHandle
Specifies the NDIS-supplied handle that was input to the call manager's ProtocolCmOpenAf function, which returned NDIS_STATUS_PENDING.
CallMgrAfContext
Specifies the handle to a caller-allocated resident context area in which the call manager maintains state about this client's open of the address family, including the NdisAfHandle, if the open succeeded. If Status is not NDIS_STATUS_SUCCESS, NDIS ignores this parameter.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A stand-alone call manager must call NdisCmOpenAddressFamilyComplete if its ProtocolCmOpenAf function previously returned NDIS_STATUS_PENDING for the given NdisAfHandle. The client, which initiated the pended open-AF operation with a call to NdisClOpenAddressFamily, cannot carry out further connection-oriented operations on the same binding until NdisCmOpenAddressFamilyComplete causes a call to that client's ProtocolClOpenAfComplete function.

If the caller of NdisCmOpenAddressFamilyComplete sets Status to NDIS_STATUS_SUCCESS, NDIS subsequently passes the given CallMgrAfContext handle as an input parameter to all CM-supplied ProtocolCmXxx and ProtocolCoXxx functions that concern the client's open of the address family until the client closes the AF. The call manager should release or reuse any AF context area that it allocated before it passes a failure status to NdisCmOpenAddressFamilyComplete.

For a successful open, the NDIS-supplied NdisAfHandle represents an association between the call manager and client for the opened AF on a particular NIC driver to which the call manager and client are bound. Both protocols must treat NdisAfHandle as an opaque variable to be passed, unmodified and uninterpreted, in subsequent calls to NdisCl/Cm/Co Xxx functions for which this handle is a required parameter. For a failed open, the call manager should consider the NdisAfHandle invalid when NdisMCmOpenAddressFamilyComplete returns control.

Only stand-alone call managers, which register themselves with NDIS as protocols, can call NdisCmOpenAddressFamilyComplete. Connection-oriented miniport drivers that provide integrated call-management support must call NdisMCmOpenAddressFamilyComplete instead.

Callers of NdisCmOpenAddressFamilyComplete can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocateFromNPagedLookasideList, NdisClOpenAddressFamily, NdisMCmOpenAddressFamilyComplete, ProtocolClOpenAfComplete, ProtocolCmOpenAf


NdisCmRegisterAddressFamily

NdisCmRegisterAddressFamily registers a set of call-manager-supplied functions for connection-oriented communication over a CM-specified address family.

NDIS_STATUS
    NdisCmRegisterAddressFamily(
    IN NDIS_HANDLE  NdisBindingHandle,
    IN PCO_ADDRESS_FAMILY  AddressFamily,
    IN PNDIS_CALL_MANAGER_CHARACTERISTICS  CmCharacteristics,
    IN UINT  SizeOfCmCharacteristics
    );

Parameters

NdisBindingHandle
Specifies the handle returned by NdisOpenAdapter that identifies the target NIC or the virtual adapter of the next-lower driver to which the caller is bound.
AddressFamily
Pointer to a structure of type CO_ADDRESS_FAMILY identifying the call manager and the address family it supports for this binding.

The given AddressFamily becomes an input parameter to the ProtocolCoAfRegisterNotify functions of all clients bound to the same connection-oriented miniport driver.

CmCharacteristics
Pointer to an NDIS_CALL_MANAGER_CHARACTERISTICS structure set up by the caller. The structure at CmCharacteristics is defined as follows:
typedef struct _NDIS_CALL_MANAGER_CHARACTERISTICS {
    UCHAR  MajorVersion;
    UCHAR  MinorVersion;
    USHORT  Filler;           // reserved for system use
    UINT    Reserved;         // reserved for system use
    CO_CREATE_VC_HANDLER  CmCreateVcHandler;
    CO_DELETE_VC_HANDLER  CmDeleteVcHandler;
    CM_OPEN_AF_HANDLER  CmOpenAfHandler;
    CM_CLOSE_AF_HANDLER  CmCloseAfHandler;
    CM_REG_SAP_HANDLER  CmRegisterSapHandler;
    CM_DEREG_SAP_HANDLER  CmDeregisterSapHandler;
    CM_MAKE_CALL_HANDLER  CmMakeCallHandler;
    CM_CLOSE_CALL_HANDLER  CmCloseCallHandler;
    CM_INCOMING_CALL_COMPLETE_HANDLER
                             CmIncomingCallCompleteHandler;
    CM_ADD_PARTY_HANDLER  CmAddPartyHandler;
    CM_DROP_PARTY_HANDLER  CmDropPartyHandler;
    CM_ACTIVATE_VC_COMPLETE_HANDLER  CmActivateVcCompleteHandler;
    CM_DEACTIVATE_VC_COMPLETE_HANDLER
                             CmDeactivateVcCompleteHandler;
    CM_MODIFY_CALL_QOS_HANDLER  CmModifyCallQoSHandler;
    CO_REQUEST_HANDLER  CmRequestHandler;
    CO_REQUEST_COMPLETE_HANDLER  CmRequestCompleteHandler;
} NDIS_CALL_MANAGER_CHARACTERISTICS,
                   *PNDIS_CALL_MANAGER_CHARACTERISTICS;

The protocol should initialize this structure with zeros before setting up the following members:

MajorVersion
Specifies the major version of this structure that the call manager is using. The current value is 0x05.
MinorVersion
Specifies the major version of this structure that the call manager is using. The current value is 0x00.
Filler and Reserved
The caller should ignore these members after zero-initializing this structure.
CmCreateVcHandler
Specifies the entry point of the caller's ProtocolCoCreateVc function.
CmDeleteVcHandler
Specifies the entry point of the caller's ProtocolCoDeleteVc function.
CmOpenAfHandler
Specifies the entry point of the caller's ProtocolCmOpenAf function.
CmCloseAfHandler
Specifies the entry point of the caller's ProtocolCmCloseAf function.
CmRegisterSapHandler
Specifies the entry point of the caller's ProtocolCmRegisterSap function.
CmDeregisterSapHandler
Specifies the entry point of the caller's ProtocolCmDeregisterSap function.
CmMakeCallHandler
Specifies the entry point of the caller's ProtocolCmMakeCall function.
CmCloseCallHandler
Specifies the entry point of the caller's ProtocolCmCloseCall function.
CmIncomingCallCompleteHandler
Specifies the entry point of the caller's ProtocolCmIncomingCallComplete function.
CmAddPartyHandler
Specifies the entry point of the caller's ProtocolCmAddParty function.
CmDropPartyHandler
Specifies the entry point of the caller's ProtocolCmDropParty function.
CmActivateVcCompleteHandler
Specifies the entry point of the caller's ProtocolCmActivateVcComplete function.
CmDeactivateVcCompleteHandler
Specifies the entry point of the caller's ProtocolCmDeactivateVcComplete function.
CmModifyCallQoSHandler
Specifies the entry point of the caller's ProtocolCmModifyCallQoS function.
CmRequestHandler
Specifies the entry point of the caller's ProtocolCoRequest function.
CmRequestCompleteHandler
Specifies the entry point of the caller's ProtocolCoRequestComplete function.
SizeOfCmCharacteristics
Specifies the size in bytes of the structure at CmCharacteristics.

Return Value

NdisCmRegisterAddressFamily can return any of the following:

NDIS_STATUS_SUCCESS
The protocol has been registered with NDIS as the call manager for the given address family, so NDIS will call the ProtocolCoAfRegisterNotify functions of all clients that bind themselves to the same NIC driver.
NDIS_STATUS_RESOURCES
The requested operation failed because NDIS could not allocate sufficient memory or initialize the state it uses to track the call manager or this address family
NDIS_STATUS_FAILURE
NDIS failed this call, possibly for one of the following reasons:
  • This caller was not registered as a connection-oriented protocol.
  • The NIC driver to which the caller is bound was not registered as a connection-oriented miniport driver.
  • Another call manager has already registered this address family.
  • The caller supplied invalid or insufficient information at CmCharacteristics.
  • The caller's binding is being closed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Only stand-alone call managers, which register themselves as NDIS protocol drivers with NdisRegisterProtocol, also call NdisCmRegisterAddressFamily. Such a driver calls NdisCmRegisterAddressFamily from its ProtocolBindAdapter function to register itself on a particular binding with NDIS.

A stand-alone call manager's ProtocolBindAdapter function first establishes the binding to the underlying miniport driver with NdisOpenAdapter before it calls NdisCmRegisterAddressFamily. Each time NDIS calls ProtocolBindAdapter with another BindContext handle, this call manager function establishes a binding and registers an address family that it supports. In other words, a stand-alone call manager eventually registers an address family and reregisters its ProtocolCm/CoXxx functions for each NIC on which it provides call-management services to connection-oriented clients. The call manager can support more than one address family across all the NIC drivers to which it is bound. The call manager can also support more than one address family on a single NIC to which it is bound. In this case, however, the call manager must register the same entry points for each address family on the binding. Only one call manager can support a particular type of address family for clients bound to any particular NIC driver.

In effect, such a protocol driver both registers itself as a stand-alone call manager and advertises its specific signaling services for all clients bound to the same miniport driver when it calls NdisCmRegisterAddressFamily. After its ProtocolBindAdapter returns control with a successful registration as a stand-alone call manager, NDIS calls the ProtocolCoRegisterAfNotify functions of all clients bound to the same miniport driver. These clients, in turn, cause NDIS to call the ProtocolCmOpenAf function that the call manager just registered for the address family.

A stand-alone call manager must set every Cm Xxx member in the NDIS_CALL_MANAGER_CHARACTERISTICS structure to a driver-supplied ProtocolCm/CoXxx function when it calls NdisCmRegisterAddressFamily, even if it does not support incoming calls, outgoing calls, or point-to-multipoint connections. For whatever subset of connection-oriented functionality that such a call manager does not support, its placeholder ProtocolCmXxx functions simply return NDIS_STATUS_NOT_SUPPORTED.

After a stand-alone call manager calls NdisCmRegisterAddressFamily successfully, NDIS ignores any entry point(s) that the CM previously specified in the RequestHandler and RequestCompleteHandler members of the NDIS_PROTOCOL_CHARACTERISTICS structure that it passed to NdisRegisterProtocol.

By contrast to stand-alone call managers, a connection-oriented miniport driver that provides integrated call-managment support, also called an MCM driver, would call NdisMCmRegisterAddressFamily to register its ProtocolCmXxx and ProtocolCoXxx driver functions with NDIS. Such a miniport driver never calls NdisRegisterProtocol or NdisOpenAdapter.

Callers of NdisCmRegisterAddressFamily usually run at IRQL PASSIVE_LEVEL and in the context of a system thread. NdisCmRegisterAddressFamily must be called at IRQL < DISPATCH_LEVEL.

See Also

CO_ADDRESS_FAMILY, NdisMCmRegisterAddressFamily, NdisOpenAdapter, NdisRegisterProtocol, NdisZeroMemory, ProtocolBindAdapter, ProtocolCmActivateVcComplete, ProtocolCmAddParty, ProtocolCmCloseAf, ProtocolCmCloseCall, ProtocolCmDeactivateVcComplete, ProtocolCmDeregisterSap, ProtocolCmDropParty, ProtocolCmIncomingCallComplete, ProtocolCmMakeCall, ProtocolCmModifyCallQoS, ProtocolCmOpenAf, ProtocolCmRegisterSap, ProtocolCoAfRegisterNotify, ProtocolCoCreateVc, ProtocolCoDeleteVc, ProtocolCoRequest, ProtocolCoRequestComplete


NdisCmRegisterSapComplete

NdisCmRegisterSapComplete returns the final status of a client's request, for which the CM previously returned NDIS_STATUS_PENDING, to register a SAP.

VOID
  NdisCmRegisterSapComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisSapHandle,
    IN NDIS_HANDLE  CallMgrSapContext
    );

Parameters

Status
Specifies the final status of the client's original request to register the SAP, either NDIS_STATUS_SUCCESS or any CM-determined NDIS_STATUS_XXX except NDIS_STATUS_PENDING.
NdisSapHandle
Specifies the NDIS-supplied handle to the SAP if the registration is successful. The call manager obtained this handle as an input parameter to its ProtocolCmRegisterSap function.
CallMgrSapContext
Specifies the handle to a caller-supplied resident context area in which the CM maintains state for this SAP if the registration is successful. If so, NDIS passes this handle back to the CM in all subsequent calls concerning this SAP. If Status is set to something other than NDIS_STATUS_SUCCESS, NDIS ignores this parameter.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A stand-alone call manager must call NdisCmRegisterSapComplete if its ProtocolCmRegisterSap function returned NDIS_STATUS_PENDING when it was called with the given NdisSapHandle. The call to NdisCmRegisterSapComplete causes NDIS to call the client's ProtocolClRegisterSapComplete function.

If the call manager sets Status to anything other than NDIS_STATUS_SUCCESS, it should consider the NdisSapHandle invalid as soon as it calls NdisCmRegisterSapComplete. After failing a SAP registration, the CM can release or reuse the per-SAP context area that it allocated when NdisCmRegisterSapComplete returns control. NDIS also releases its context for the SAP if the call manager fails the registration.

Only stand-alone call managers, which register themselves with NDIS as protocols, can call NdisCmRegisterSapComplete. Connection-oriented NIC drivers that provide integrated call-management support call NdisMCmRegisterSapComplete.

Callers of NdisCmRegisterSapComplete can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocateFromNPagedLookasideList, NdisClRegisterSap, NdisMCmRegisterSapComplete, ProtocolClRegisterSapComplete, ProtocolCmRegisterSap


NdisCoAssignInstanceName

NdisCoAssignInstanceName assigns an instance name to a VC and causes NDIS to register a GUID (globally unique identifier) for the assigned name with Windows Management Instrumentation (WMI).

NDIS_STATUS
  NdisCoAssignInstanceName(
    IN NDIS_HANDLE  NdisVcHandle,
    IN PNDIS_STRING  BaseInstanceName,
    OUT PNDIS_STRING  VcInstanceName
    );

Parameters

NdisVcHandle
Specifies the handle to the VC being named. This handle was supplied by NDIS when the VC was originally created with NdisCoCreateVc, whether by the client in preparation for making an outgoing call or by the call manager in preparation for dispatching an incoming call to the client.
BaseInstanceName
Pointer to an NDIS_STRING type that describes a caller-supplied Unicode string that specifies the base name of the VC. The base name can be any localizable Unicode string that uniquely identifies the VC with respect to the other named VCs within the scope of the miniport driver. For Windows 2000 and later, NDIS defines the NDIS_STRING type as a UNICODE_STRING type.
VcInstanceName
Pointer to a caller-allocated NDIS_STRING type in which this routine returns a Unicode string that specifies the NDIS-assigned instance name assigned for the VC.

Return Value

NdisCoAssignInstanceName can return any of the following:

NDIS_STATUS_SUCCESS
NDIS assigned an instance name to the specified VC and registered a GUID for the instance name with WMI.
NDIS_STATUS_FAILURE
The attempt to assign an instance name to the VC failed.
NDIS_STATUS_RESOURCES
NDIS could not allocate a buffer for the instance name.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

After initiating the setup of a VC with NdisCoCreateVC, a call manager or connection-oriented client can name the VC with NdisCoAssignInstanceName. Calling NdisCoAssignInstanceName, causes NDIS to assign the VC an instance name and register the instance name with WMI. WMI clients can then enumerate the VC and query or set OIDs relative to the VC.

An integrated miniport call manager (MCM) driver cannot use NdisCoAssignInstanceName to name its VCs. Instead, an MCM driver should create a custom GUID and OID for the VC and register the GUID-to-OID mapping with NDIS.

NDIS creates an instance name for the specified VC by appending an index to the base name pointed to by the caller. NDIS returns the complete instance name (base name + index) to the caller and then registers a GUID for the instance name with WMI. Only named VCs can be enumerated and queried by WMI clients. Unnamed VCs are not visible to WMI clients.

If the specified VC already has an instance name (assigned in a previous call to NdisCoAssignInstanceName), NDIS returns NDIS_STATUS_SUCCESS and the original instance name assigned to the VC. An instance name remains assigned to a VC until that VC is deleted.

The caller can associate the returned instance name with the handle for the named VC that NDIS previously returned to the caller from NdisCoCreateVc. NDIS, however, will continue to use the VC handle—not the instance name—to refer to the VC in subsequent calls. The caller of NdisCoAssignInstanceName might find the need to return the instance name to some other management entity.

The caller is responsible for freeing the buffer containing the returned instance name. After deleting the named VC with NdisCoDeleteVc, the caller must free the buffer with NdisFreeString.

Callers of NdisCoAssignInstanceName must be running at IRQL DISPATCH_LEVEL.

See Also

MiniportCoRequest, MiniportQueryInformation, NdisCoCreateVc, NdisCoDeleteVC, NdisFreeString, UNICODE_STRING


NdisCoCreateVc

NdisCoCreateVc sets up a connection endpoint from which a client can make outgoing calls or on which a stand-alone call manager can dispatch incoming calls.

NDIS_STATUS
  NdisCoCreateVc(
    IN NDIS_HANDLE  NdisBindingHandle,
    IN NDIS_HANDLE  NdisAfHandle  OPTIONAL,
    IN NDIS_HANDLE  ProtocolVcContext,
    IN OUT PNDIS_HANDLE  NdisVcHandle
    );

Parameters

NdisBindingHandle
Specifies the handle returned by NdisOpenAdapter that identifies the target NIC or virtual adapter of the next-lower driver to which the caller is bound.
NdisAfHandle
Specifies the handle returned by NdisClOpenAddressFamily if the caller is a client. A call manager sets this parameter to NULL if it is creating a VC for itself, such as a VC to a network switch. When it creates a VC for incoming call notifications, a call manager passes the AF handle that it saved in its per-AF state designated by the CallMgrAfContext that was passed as an input parameter to its ProtocolCmRegisterSap function.
ProtocolVcContext
Specifies the handle to a caller-supplied resident context area in which the caller maintains state for this VC. NDIS passes this handle back to the VC creator in all subsequent calls concerning this endpoint if the call to NdisCoCreateVc succeeds.
NdisVcHandle
Pointer to a caller-supplied variable that must be initialized to NULL when NdisCoCreateVc is called. On return from a successful call, this points to a variable that NDIS has set to its handle for the newly created VC. The caller must save this handle for subsequent calls to connection-oriented Ndis Xxx functions.

Return Value

NdisCoCreateVc can return one of the following:

NDIS_STATUS_SUCCESS
NDIS created the VC successfully.
NDIS_STATUS_RESOURCES
NDIS could not allocate sufficient memory to set up the VC.
NDIS_STATUS_FAILURE
The given NdisAfHandle is invalid.
NDIS_STATUS_XXX
The underlying NIC driver failed the creation of the VC for a miniport driver-determined reason, which NDIS has propagated to the caller.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A client or stand-alone call manager creates a VC with NdisCoCreateVc, depending on whether the VC represents an outgoing or incoming call, respectively.

In the process of VC creation, NDIS supplies an NdisVcHandle to the client, the call manager, and the miniport driver to which both protocols are bound. This handle identifies the virtual circuit for the client, call manager, and miniport driver to which subsequent requests concerning the given VC are directed. Each driver must treat this VC handle as an opaque variable, passing it unmodified and uninterpreted in subsequent calls to certain connection-oriented NDIS library functions.

Usually, callers of NdisCoCreateVc store the returned NdisVcHandle in the caller-allocated state area at ProtocolVcContext. NDIS passes this handle as an input parameter to the ProtocolCoCreateVc and MiniportCoCreateVc functions of the other two drivers involved in each creation of a VC.

To make an outgoing call, a client must call NdisCoCreateVc first. As a synchronous operation, NDIS calls the underlying NIC driver's MiniportCoCreateVc function and the call manager's ProtocolCoCreateVc function before NdisCoCreateVc returns control. If its call to NdisCoCreateVc succeeds, the client can proceed in making an outgoing call, passing the returned NdisVcHandle to NdisClMakeCall.

When its ProtocolCoReceivePacket function processes the offer of an incoming call directed to one of its registered SAPs, a call manager must call NdisCoCreateVc first. As a synchronous operation, NDIS calls the underlying NIC driver's MiniportCoCreateVc function and the client's ProtocolCoCreateVc function before NdisCoCreateVc returns control. If its call to NdisCoCreateVc succeeds, the call manager can proceed in notifying the appropriate client, passing the returned value at NdisVcHandle to NdisCmDispatchIncomingCall.

Stand-alone call managers, which register themselves with NDIS as protocols, can call NdisCoCreateVc. Connection-oriented NIC drivers that provide integrated call-management support call NdisMCmCreateVc, instead.

Callers of NdisCoCreateVc can be running at IRQL <= DISPATCH_LEVEL.

See Also

MiniportCoCreateVc, NdisAllocateFromNPagedLookasideList, NdisClMakeCall, NdisCmDispatchIncomingCall, NdisCoDeleteVc, NdisMCmCreateVc, ProtocolCmRegisterSap, ProtocolCoCreateVc, ProtocolCoReceivePacket


NdisCoDeleteVc

NdisCoDeleteVc destroys a caller-created VC.

NDIS_STATUS
  NdisCoDeleteVc(
    IN NDIS_HANDLE  NdisVcHandle
    );

Parameters

NdisVcHandle
Specifies the handle identifying the VC to be deleted. The caller originally obtained this handle from NdisCoCreateVc.

Return Value

NdisCoDeleteVc can return one of the following:

NDIS_STATUS_SUCCESS
NDIS deleted the VC.
NDIS_STATUS_NOT_ACCEPTED
The VC is still active, so it could not be deleted.
NDIS_STATUS_CLOSING
This call is redundant, but deactivation on the given VC is still pending.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

When a protocol calls NdisCoDeleteVc, there must be no outstanding calls on the given VC and that VC already has been deactivated. To meet these requirements implies that the following conditions hold:

  • If the call tear-down was initiated by a local client, that client has already called NdisClCloseCall with the given NdisVcHandle and its close-call request has completed successfully.
  • If the call tear-down was initiated by a remote client, the stand-alone call manager has already called NdisCmDeactivateVc with the given NdisVcHandle and its deactivation request has completed successfully.

Only the protocol that created a particular VC can delete that VC. A call to NdisCoDeleteVc causes NDIS to call both the underlying NIC driver's MiniportCoDeleteVc function and the ProtocolCoDeleteVc function of the client or call manager with which the caller shares the NdisVcHandle.

When NdisCoDeleteVc returns control, the NdisVcHandle is no longer valid.

Stand-alone call managers, which register themselves with NDIS as protocols, can call NdisCoDeleteVc. Connection-oriented miniport drivers that provide integrated call-management support call NdisMCmDeleteVc instead.

Callers of NdisCoDeleteVc can be running at IRQL <= DISPATCH_LEVEL.

See Also

MiniportCoDeleteVc, NdisClCloseCall, NdisCmDeactivateVc, NdisCoCreateVc, NdisMCmDeleteVc, ProtocolClCloseCallComplete, ProtocolClIncomingCloseCall, ProtocolCmCloseCall, ProtocolCoDeleteVc


NdisCoGetTapiCallId

NdisCoGetTapiCallId retrieves a string that TAPI applications can use to identify a particular NDIS virtual connection (VC).

NDIS_STATUS
  NdisCoGetTapiCallId(
    IN NDIS_HANDLE  NdisVcHandle,
    IN OUT PVAR_STRING  TapiCallId
    );

Parameters

NdisVcHandle
Specifies the NDIS handle to the VC. This handle was supplied by NDIS when the VC was originally created with the NdisCoCreateVc function.
TapiCallId
Pointer to a caller-allocated buffer that receives a data structure of type VAR_STRING. Upon successful return, this structure describes a string that TAPI applications can use to identify the VC.

Return Value

Returns one of the following status values:

NDIS_STATUS_SUCCESS
NDIS successfully returned a string identifier for the VC.
NDIS_STATUS_BUFFER_TOO_SHORT
The ulTotalSize member of the VAR_STRING structure specifies that the size of the buffer is not large enough to hold the string that identifies the VC. NdisCoGetTapiCallId sets the ulNeededSize member of the VAR_STRING structure to the required size in bytes.
NDIS_STATUS_INVALID_DATA
The handle to the VC specified by NdisVcHandle is not valid.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Suppose a call manager calls NdisCoCreateVc to create a VC for a TAPI call. NDIS in turn supplies the handle to the VC to a client. The client passes this VC handle in a call to the NdisCoGetTapiCallId function to retrieve a string that identifies the VC. The client can pass this string identifier to a TAPI application to identify the VC.

The client creates a context for each VC that it manages. The client uses NdisCoGetTapiCallID to retrieve a string identifier for each VC. The client passes each string identifier to a TAPI application to identify each VC. Later, if a TAPI application passes one of these string identifiers down to the client in a VC-related operation, the client must pass this string identifier as a Unicode string in a call to NdisClGetProtocolVcContextFromTapiCallId to get back the correct context for the VC.

For more information on the VAR_STRING structure, see TAPI Objects.

Callers of NdisCoGetTapiCallId must be running at IRQL DISPATCH_LEVEL.

See Also

NdisClGetProtocolVcContextFromTapiCallId, NdisCoCreateVc


NdisCompleteBindAdapter

NdisCompleteBindAdapter completes a binding operation for which the caller's ProtocolBindAdapter function previously returned NDIS_STATUS_PENDING.

VOID
  NdisCompleteBindAdapter(
    IN NDIS_HANDLE  BindAdapterContext,
    IN NDIS_STATUS  Status,
    IN NDIS_STATUS  OpenStatus
    );

Parameters

BindAdapterContext
Specifies the BindContext handle passed in to ProtocolBindAdapter.
Status
Specifies the final status of the completed bind operation.
OpenStatus
Specifies the status returned by the preceding call to NdisOpenAdapter for this binding attempt.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

When a protocol returns NDIS_STATUS_PENDING from its ProtocolBindAdapter function, that driver must eventually call NdisCompleteBindAdapter when the binding operation is completed.

If the binding operation was successful, the protocol is ready to accept receive indications from underlying drivers and to send transmit, query, and set requests down to the underlying driver(s). If NdisCompleteBindAdapter is called with an input error Status, the binding attempt failed and the protocol has released any resources it allocated to establish the binding.

In either case, the protocol calls NdisCompleteBindAdapter to notify the NDIS library of the completion of the binding operation that this driver initiated when its ProtocolBindAdapter function called NdisOpenAdapter.

Callers of NdisCompleteBindAdapter run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisIMInitializeDeviceInstance, NdisOpenAdapter, NdisRequest, ProtocolBindAdapter, ProtocolUnbindAdapter


NdisCompletePnPEvent

NdisCompletePnPEvent completes a protocol's response to a Plug and Play or Power Management event for which the protocol's ProtocolPnPEvent function previously returned NDIS_STATUS_PENDING.

VOID
  NdisCompletePnPEvent(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisBindingHandle,
    IN PNET_PNP_EVENT  NetPnPEvent
    );

Parameters

Status
Specifies the protocol's response to the previously indicated Plug and Play or Power Management event. To succeed such an event, a protocol returns NDIS_STATUS_SUCCESS. A protocol should always succeed a NetEventQueryPower, a NetEventSetPower, a NetEventCancelRemoveDevice, a NetEventReconfigure, a NetEventBindList, a NetEventBindsComplete, or a NetEventPnPCapabilities. A protocol can fail a NetEventQueryRemoveDevice by returning any caller-determined NDIS_STATUS_XXX except NDIS_STATUS_PENDING.
NdisBindingHandle
Specifies the handle returned by NdisOpenAdapter that identifies the target NIC or the virtual adapter of the next-lower driver to which the caller is bound.
NetPnPEvent
Pointer to a buffered NET_PNP_EVENT structure that was passed in to the protocol's ProtocolPnPEvent function.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

When a protocol returns NDIS_STATUS_PENDING from its ProtocolPnPEvent function, it must eventually call NdisCompletePnPEvent to indicate its response to the given Plug and Play or Power Management request.

A protocol can fail a NetEventQueryRemoveDevice by returning NDIS_STATUS_FAILURE.

A protocol should always succeed a NetEventQueryPower, a NetEventSetPower, a NetEventCancelRemoveDevice, a NetEventReconfigure, a NetEventBindList, a NetEventBindsComplete, or a NetEventPnPCapabilities by returning NDIS_STATUS_SUCCESS:

Callers of NdisCompletePnPEvent run at IRQL PASSIVE_LEVEL.

See Also

NET_PNP_EVENT, ProtocolPnPEvent


NdisCompleteUnbindAdapter

NdisCompleteUnbindAdapter completes an unbinding operation for which the caller's ProtocolUnbindAdapter function previously returned NDIS_STATUS_PENDING.

VOID
  NdisCompleteUnbindAdapter(
    IN NDIS_HANDLE  UnbindAdapterContext,
    IN NDIS_STATUS  Status
    );

Parameters

UnbindAdapterContext
Specifies the ProtocolBindingContext handle passed in to ProtocolUnbindAdapter.
Status
Specifies the Status of the completed unbind operation, always NDIS_STATUS_SUCCESS.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

When a protocol returns NDIS_STATUS_PENDING from its ProtocolUnbindAdapter function, that driver must eventually call NdisCompleteUnbindAdapter when the unbinding operation is completed.

When NdisCompleteUnbindAdapter is called, the protocol has finished cleaning up any state the driver maintains about the binding and released any resources it allocated to establish the binding. This call notifies the NDIS library of the completion of the unbinding operation that this driver initiated when it called NdisOpenAdapter from ProtocolBindAdapter.

On return from NdisCompleteUnbindAdapter the UnbindAdapterContext handle should be considered invalid. That is, the protocol should not pass this handle in calls to any Ndis Xxx function.

Callers of NdisCompleteUnbindAdapter run at IRQL PASSIVE_LEVEL.

See Also

MiniportHalt, NdisCloseAdapter, NdisIMDeInitializeDeviceInstance, ProtocolBindAdapter, ProtocolUnbindAdapter


NdisConvertStringToAtmAddress

NdisConvertStringToAtmAddress converts a Unicode string that contains an ATM address into a ATM_ADDRESS structure that a connection-oriented client can include in a set of call parameters.

VOID
  NdisConvertStringToAtmAddress(
    OUT PNDIS_STATUS  Status,
    IN PNDIS_STRING  String,
    OUT PATM_ADDRESS  AtmAddress
    );

Parameters

Status
Pointer to a caller-supplied variable in which this function returns the status of the conversion. Possible return values are:
NDIS_STATUS_SUCCESS
The conversion was successful.
NDIS_STATUS_INVALID_LENGTH
The ATM address in String did not have the correct length.
NDIS_STATUS_RESOURCES
NDIS could not allocate the resources it needed to make the conversion.
NDIS_STATUS_FAILURE
The string could not be converted to a valid ATM address.
String
Pointer to an NDIS_STRING type that describes a caller-supplied Unicode string that specifies the ATM address to be converted. For Windows 2000 and later, NDIS defines the NDIS_STRING type as a UNICODE_STRING type.
AtmAddress
Pointer to a caller-allocated buffer in which this routine returns an ATM address formatted as an ATM_ADDRESS structure, defined as follows:
typedef struct _ATM_ADDRESS {
    ATM_ADDRESSTYPE  AddressType;
    ULONG            NumberOfDigits;
    UCHAR            Address[ATM_ADDRESS_LENGTH];
} ATM_ADDRESS, *PATM_ADDRESS;

The members of this structure contain the following data:

AddressType
Specifies the format of the ATM address. A value of ATM_NSAP specifies an ATM Endstation Address (NSAP format). A value of ATM_E164 specifies an E.164 address (telephony format).
NumberOfDigits
Indicates the number of digits in the ATM address.
Address[ATM_ADDRESS_LENGTH]
An array that contains the converted ATM address.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A connection-oriented client calls NdisConvertStringToAtmAddress to convert a ATM address in a Unicode string to an ATM_ADDRESS structure. Typically, the client retrieved the input ATM address string from the registry.

If the conversion is successful, NdisConvertStringToAtmAddress returns the converted ATM address without punctuation, formatted as an ATM_ADDRESS structure. In addition to providing the converted ATM address, the ATM_ADDRESS structure also indicates the address type and the number of digits in the address.

The client uses the converted ATM address when creating a set of call parameters, which the client subsequently passes as an argument to various NdisCl Xxx functions.

Callers of NdisConvertStringToAtmAddress run at IRQL PASSIVE_LEVEL.

See Also

CO_CALL_PARAMETERS, NdisClAddParty, NdisClIncomingCallComplete, NdisClMakeCall, NdisClModifyCallQoS, UNICODE_STRING


NdisCopyBuffer

NdisCopyBuffer creates a buffer descriptor for a specified virtual (sub)range, given a handle for a block of already allocated memory and a pointer to the memory descriptor for the block.

VOID
  NdisCopyBuffer(
    OUT PNDIS_STATUS  Status,
    OUT PNDIS_BUFFER  *Buffer,
    IN NDIS_HANDLE  PoolHandle,
    IN PVOID  MemoryDescriptor,
    IN UINT  Offset,
    IN UINT  Length
    );

Parameters

Status
Pointer to a caller-supplied variable in which this function returns the final status of the buffer descriptor copy operation, which can be one of the following:
NDIS_STATUS_SUCCESS
The driver can use the buffer descriptor or buffer descriptor chain returned at Buffer.
NDIS_STATUS_FAILURE
An attempt to map the given range failed, possibly because of an out-of-range Offset and Length specification.
Buffer
Pointer to a caller-supplied variable in which this function returns a pointer to the new buffer descriptor if the call is successful.
PoolHandle
Specifies the handle returned by a preceding call to NdisAllocateBufferPool.
MemoryDescriptor
Pointer to the memory descriptor, which can be of type NDIS_BUFFER.
Offset
Specifies the byte offset within the memory block at which to start the copy.
Length
Specifies the number of bytes to copy.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisCopyBuffer creates a buffer descriptor mapping a (sub)range within a block of memory, described by a given memory descriptor. This function allocates storage for the new buffer descriptor and then copies information from the given MemoryDescriptor into the new buffer descriptor.

If the given memory descriptor contains chained elements, the buffer descriptor that NdisCopyBuffer creates can be the head of a chain of buffer descriptors. A driver can call NdisGetNextBuffer and then NdisQueryBuffer(Safe) to query each chained buffer descriptor.

The driver must release any spin lock it is holding before calling NdisCopyBuffer. The driver must call NdisFreeBuffer to release the buffer descriptor when it is no longer needed.

Callers of NdisCopyBuffer can be runing at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocateBufferPool, NdisFreeBuffer, NdisGetNextBuffer, NdisQueryBuffer, NdisQueryBufferSafe, NdisReleaseSpinLock


NdisCopyFromPacketToPacket

NdisCopyFromPacketToPacket copies a specified range of data from one packet to another.

VOID
  NdisCopyFromPacketToPacket(
    IN PNDIS_PACKET  Destination,
    IN UINT  DestinationOffset,
    IN UINT  BytesToCopy,
    IN PNDIS_PACKET  Source,
    IN UINT  SourceOffset,
    OUT PUINT  BytesCopied
    );

Parameters

Destination
Pointer to the destination packet descriptor.
DestinationOffset
Specifies the byte offset within the destination packet at which to begin writing the copied data.
BytesToCopy
Specifies the number of bytes to copy.
Source
Pointer to the source packet descriptor.
SourceOffset
Specifies the byte offset within the source packet at which to begin copying the data.
BytesCopied
Pointer to the caller-supplied variable in which this function returns the number of bytes actually copied. This number can be less than the value of BytesToCopy if the source packet runs out of data or the destination packet runs out of space.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Drivers should call NdisCopyFromPacketToPacketSafe instead of NdisCopyFromPacketToPacket. NDIS 5.1 miniport drivers must call NdisCopyFromPacketToPacketSafe instead of NdisCopyFromPacketToPacket. Unlike NdisCopyFromPacketToPacket, NdisCopyFromPacketToPacketSafe does not cause a bug check if system resources are low or exhausted.

The caller of NdisCopyFromPacketToPacket allocates the destination packet, if not the source packet as well. The packet descriptor of the destination packet should have enough chained buffer descriptors to receive the data.

If the source packet runs out of data or the destination packet out of space before the specified number of bytes has been copied, the copy operation stops. In either case, NdisCopyFromPacketToPacket returns the number of bytes successfully copied from the source to the destination packet.

NdisCopyFromPacketToPacket does not copy any out-of-band information associated with the given Source to the Destination. To copy this information, the driver can use pointers returned by NDIS_OOB_DATA_FROM_PACKET and then call NdisMoveMemory.

The driver must release any spin lock it is holding before calling NdisCopyFromPacketToPacket.

Callers of NdisCopyFromPacketToPacket run at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocateBuffer, NdisAllocatePacket, NdisCopyFromPacketToPacketSafe,NdisMoveMemory, NDIS_OOB_DATA_FROM_PACKET, NDIS_PACKET_OOB_DATA


NdisCopyFromPacketToPacketSafe

NdisCopyFromPacketToPacketSafe copies a specified range of data from one packet to another.

VOID
  NdisCopyFromPacketToPacketSafe(
    IN PNDIS_PACKET  Destination,
    IN UINT  DestinationOffset,
    IN UINT  BytesToCopy,
    IN PNDIS_PACKET  Source,
    IN UINT  SourceOffset,
    OUT PUINT  BytesCopied
    IN MM_PAGE_PRIORITY Priority
    );

Parameters

Destination
Pointer to the destination packet descriptor.
DestinationOffset
Specifies the byte offset within the destination packet at which to begin writing the copied data.
BytesToCopy
Specifies the number of bytes to copy.
Source
Pointer to the source packet descriptor.
SourceOffset
Specifies the byte offset within the source packet at which to begin copying the data.
BytesCopied
Pointer to the caller-supplied variable in which this function returns the number of bytes actually copied. This number can be less than the value of BytesToCopy if the source packet runs out of data, the destination packet runs out of space, or the system is low on resources.
Priority
Indicates the priority of the request as one of the following:
LowPagePriority
Specifies a low priority. It is acceptable for NdisCopyFromPacketToPacketSafe to fail if system resources are low.
NormalPagePriority
Specifies a normal priority. It is acceptable for NdisCopyFromPacketToPacketSafe to fail if system resources are low.
HighPagePriority
Specifies a high priority. It is unacceptable for NdisCopyFromPacketToPacketSafe to fail unless system resources are exhausted. Since it can always recover from a failed copy operation, the miniport driver should never specify this priority.

Return Value

None.

If the copy operation was successful, BytesCopied is equal to BytesToCopy on the return of NdisCopyFromPacketToPacketSafe. If BytesCopied is less than BytesToCopy on the return of the function, the copy operation was not successful.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisCopyFromPacketToPacketSafe is the safe version of NdisCopyFromPacketToPacket. Unlike NdisCopyFromPacketToPacket, NdisCopyFromPacketToPacketSafe does not cause a bug check if system resources are low or exhausted. Drivers should call NdisCopyFromPacketToPacketSafe instead of NdisCopyFromPacketToPacket. NDIS 5.1 driver must call NdisCopyFromPacketToPacketSafe instead of NdisCopyFromPacketToPacket.

The caller of NdisCopyFromPacketToPacketSafe allocates the destination packet, if not the source packet as well. The packet descriptor of the destination packet should specify enough buffer space to receive the data.

If the source packet runs out of data, the destination packet runs out of space before the specified number of bytes has been copied, or the system is low on resources, the copy operation stops. In either case, NdisCopyFromPacketToPacketSafe returns the number of bytes successfully copied from the source to the destination packet.

NdisCopyFromPacketToPacketSafe does not copy any out-of-band information associated with the given Source to the Destination. To copy this information, the driver can use pointers returned by NDIS_OOB_DATA_FROM_PACKET and then call NdisMoveMemory.

If Priority was set to LowPagePriority or NormalPagePriority, NdisCopyFromPacketToPacketSafe returns as soon as system resources become low or exhausted. If Priority was set to HighPagePriority, NdisCopyFromPacketToPacketSafe returns as soon as system resources are exhausted. Since miniport drivers can always recover from a failed copy operation, they should never call NdisCopyFromPacketToPacketSafe with Priority set to HighPagePriority. Setting Priority to HighPagePriority does not improve performance.

To determine whether the copy operation succeeded, the driver should compare BytesCopied with BytesToCopy after NdisCopyFromPacketToPacketSafe returns. If BytesCopied is equal to BytesToCopy, the copy operation succeeded. If BytesCopied is less than BytesToCopy, the source packet did not contained less data than BytesToCopy, the destination packet did not have enough buffer space to contain all the data to be copied, or the copy operation was aborted because system resources were low or exhausted.

Callers of NdisCopyFromPacketToPacketSafe run at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocateBuffer, NdisAllocatePacket, NdisCopyFromPacketToPacket,

NdisMoveMemory, NDIS_OOB_DATA_FROM_PACKET, NDIS_PACKET_OOB_DATA


NdisCopyLookaheadData

NdisCopyLookaheadData safely copies receive data indicated in a lookahead buffer to the transport protocol by the underlying NDIS driver.

VOID
NdisCopyLookaheadData(
  IN PVOID  Destination,
    IN PVOID  Source,
    IN ULONG  Length,
    IN ULONG  MacOptions
    );

Parameters

Destination
Pointer to a caller-supplied buffer into which to copy the data.
Source
Pointer to the source buffer from which to copy the data.
Length
Specifies how many bytes of data to copy.
MacOptions
Specifies a combination (ORed) of flags, which should be identical to the bitmask that the underlying driver returned in response to the protocol's binding-time call to NdisRequest with the OID_GEN_MAC_OPTIONS query.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisCopyLookaheadData can be called by a transport's ProtocolReceive function to copy receive data from a lookahead buffer that was indicated up by the underlying NIC driver. In particular, NdisCopyLookaheadData must be called if the underlying NIC driver did not set the NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA flag in response to the transport's OID_GEN_MAC_OPTIONS query. For more information about this OID request, see NDIS Object Identifiers.

However, NdisCopyLookaheadData can be called by any NDIS driver's ProtocolReceive function, whatever the nature of the receive buffers on the underlying NIC.

Any driver that exports a ProtocolReceive function can call NdisCopyLookaheadData.

Callers of NdisCopyLookaheadData can be running at any IRQL if the buffer at Destination was allocated from nonpaged pool. Otherwise, a caller must be running at IRQL < DISPATCH_LEVEL.

See Also

NdisRequest, OID_GEN_MAC_OPTIONS, ProtocolReceive


NdisCoRequest

NdisCoRequest issues an OID_GEN_CO_XXX or connection-oriented medium-specific OID_XXX request from a client to a stand-alone call manager or vice versa and from either client or call manager to the underlying miniport driver.

NDIS_STATUS
  NdisCoRequest(
    IN NDIS_HANDLE  NdisBindingHandle,
    IN NDIS_HANDLE  NdisAfHandle  OPTIONAL,
    IN NDIS_HANDLE  NdisVcHandle  OPTIONAL,
    IN NDIS_HANDLE  NdisPartyHandle  OPTIONAL,
    IN OUT PNDIS_REQUEST  NdisRequest
    );

Parameters

NdisBindingHandle
Specifies the handle returned by NdisOpenAdapter that identifies the target NIC or the virtual NIC of the next-lower driver to which the caller is bound.
NdisAfHandle
Specifies the handle identifying the open address family, which is shared among the client, call manager, and NDIS.
  • If the caller is a client making a request to the call manager, the client originally obtained this handle from a successful call to NdisClOpenAddressFamily.
  • If the caller is a stand-alone call manager making a request to the client, the CM originally obtained this handle as an input parameter to its ProtocolCmOpenAf function.
  • For a request from either a client or stand-alone call manager to the underlying miniport driver, this parameter must be NULL.
NdisVcHandle
Specifies the handle identifying the VC for which the caller is requesting or setting information if the request is VC-specific, or this parameter is NULL. For any VC-specific request, the caller originally obtained this handle either when it created the VC with NdisCoCreateVc, or as an input parameter to its ProtocolCoCreateVc function. For a VC-specific request directed to the underlying miniport driver, this handle identifies the VC, while NdisAfHandle and NdisPartyHandle are NULL.
NdisPartyHandle
Specifies the handle identifying the party on a multipoint VC for which the caller is requesting or setting information if the request is party-specific, or this parameter is NULL. For any party-specific request, the client originally obtained this handle from a successful call to NdisClAddParty or NdisClMakeCall, and the call manager obtained this handle as an input parameter to its ProtocolCmAddParty function. If NdisAfHandle is NULL, this parameter also is NULL.
NdisRequest
Pointer to a caller-allocated resident buffer, formatted as a structure of type NDIS_REQUEST and set up by the caller.

Return Value

When NdisCoRequest returns anything other than NDIS_STATUS_PENDING, the caller should make an internal call to its ProtocolCl/CmRequestComplete function. Otherwise, NDIS calls that driver's ProtocolCl/CmRequestComplete function when this operation is completed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Before it calls NdisCoRequest, a protocol allocates a buffer for its request and initializes an NDIS_REQUEST structure. Such a driver sets the Oid member of the NDIS_REQUEST structure with a system-defined OID_GEN_CO_XXX code when communicating with the call manager or client. For requests directed to an underlying miniport driver, the protocol can set the Oid member either with an OID_GEN_CO_XXX or a connection-oriented, medium-specific OID_XXX code, such as OID_ATM_ALIGNMENT_REQUIRED when calling NdisCoRequest.

Depending on the value of NdisAfHandle, clients and stand-alone call managers call NdisCoRequest to communicate with each other or with the underlying connection-oriented miniport driver.

Passing a NULL NdisVcHandle makes such a request global in nature, whether the request is directed to the client, call manager, or miniport driver. For example, an OID_GEN_CO_RCV_CRC_ERROR request to an underlying connection-oriented miniport driver returns the number of CRC errors encountered in all receives the miniport driver has indicated on a particular VC if the caller supplies an explicit NdisVcHandle. For the same request with a NULL NdisVcHandle, the underlying miniport driver returns the total number of CRC errors encountered for all incoming receives through its NIC.

Clients and stand-alone call managers should call NdisRequest with all OIDs that are not connection-oriented, such as those returned for an OID_GEN_SUPPORTED_LIST query, commonly issued during initialization after the protocol has bound itself to the underlying NIC driver.

For more information about the sets of OIDs defined for use with NdisCoRequest and NdisRequest, see NDIS Object Identifiers.

Only clients and stand-alone call managers, which register themselves with NDIS as protocols, can call NdisCoRequest. Connection-oriented miniport drivers with integrated call-management support call NdisMCmRequest to communicate with their clients instead.

Callers of NdisCoRequest can be running at IRQL <= DISPATCH_LEVEL.

See Also

MiniportCoRequest, NdisClOpenAddressFamily, NdisCoCreateVc, NdisCoRequestComplete, NdisMCmRequest, NdisMCmRequestComplete, NdisMCoRequestComplete, NDIS_REQUEST, NdisRequest, ProtocolCmAddParty, ProtocolCmOpenAf, ProtocolCoCreateVc, ProtocolCoRequest, ProtocolCoRequestComplete


NdisCoRequestComplete

NdisCoRequestComplete returns the final status of an OID_GEN_CO_XXX request for which the call manager's or client's ProtocolCoRequest or ProtocolCoRequest function previously returned NDIS_STATUS_PENDING.

VOID
  NdisCoRequestComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisAfHandle,
    IN NDIS_HANDLE  NdisVcHandle  OPTIONAL,
    IN NDIS_HANDLE  NdisPartyHandle  OPTIONAL,
    IN PNDIS_REQUEST  NdisRequest
    );

Parameters

Status
Specifies the final status of the requested operation, either NDIS_STATUS_SUCCESS or any protocol-determined NDIS_STATUS_XXX except NDIS_STATUS_PENDING.
NdisAfHandle
Specifies the AF handle stored in the caller's per-AF state, designated by the ProtocolAfContext passed in to the caller's ProtocolCl/CmRequest function.
NdisVcHandle
Specifies the VC handle stored in the caller's per-VC state, designated by ProtocolVcContext passed in to the caller's ProtocolCl/CmRequest function, or this parameter is NULL if the caller of NdisCoRequest passed it a NULL VC handle.
NdisPartyHandle
Specifies the party handle stored in the caller's per-party state, designated by the ProtocolPartyContext passed in to the caller's ProtocolCl/CmRequest function, or this parameter is NULL if the caller of NdisCoRequest passed it a NULL party handle.
NdisRequest
Pointer to a buffer formatted as an NDIS_REQUEST structure, which the caller of NdisCoRequest supplied.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A call to NdisCoRequestComplete causes a call to the ProtocolCoRequestComplete function of the driver that originally called NdisCoRequest with the given handle(s) and NdisRequest pointer.

Any protocol driver that returns NDIS_STATUS_PENDING from its ProtocolCoRequest function must call NdisCoRequestComplete subsequently when the driver has finished the requested operation.

Only clients and stand-alone call managers, which register themselves with NDIS as protocols, can call NdisCoRequestComplete. Connection-oriented NIC drivers that provide integrated call-management support call NdisMCmRequestComplete or NdisMCoRequestComplete instead, depending on whether the NIC driver's ProtocolCoRequest or MiniportCoRequest, respectively, handled the client's request.

Callers of NdisCoRequestComplete can be running at IRQL <= DISPATCH_LEVEL.

See Also

MiniportCoRequest, NdisCoRequest, NdisMCmRequestComplete, NdisMCoRequestComplete, NdisRequest, NDIS_REQUEST, ProtocolCoRequest, ProtocolCoRequestComplete


NdisCoSendPackets

NdisCoSendPackets forwards a multipacket send on a particular VC to the underlying NIC driver for transmission over the network.

VOID
  NdisCoSendPackets(
    IN NDIS_HANDLE  NdisVcHandle,
    IN PPNDIS_PACKET  PacketArray,
    IN UINT  NumberOfPackets
    );

Parameters

NdisVcHandle
Specifies the handle to the VC, thereby identifying the target of the send.
PacketArray
Pointer to an array of pointers to caller-allocated packet descriptors. Each packet descriptor in the array has chained buffer descriptors mapping buffers containing the data that the underlying NIC driver should transmit over the wire.

Each packet descriptor also has an associated NDIS_PACKET_OOB_DATA block, which the caller can set up with any timestamp and/or medium-specific out-of-band information relevant to the underlying driver and network medium.

NumberOfPackets
Specifies the number of pointers at PacketArray.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A call to NdisCoSendPackets causes NDIS to call the NIC driver's MiniportCoSendPackets function. NDIS submits packet arrays to the underlying driver's MiniportCoSendPackets function in the same order as they are passed to NdisCoSendPackets. Before a protocol calls NdisCoSendPackets, it should set up the array of packet pointers in the same order as the packets should be sent over the wire.

The caller of NdisCoSendPackets should test the returned status for each packet descriptor in such an array individually when its ProtocolCoSendComplete function is called. While NDIS always submits packets for transmission in the FIFO order determined by the sending protocol, the underlying NIC driver might complete such sends in random order.

As soon as a protocol calls NdisCoSendPackets, it relinquishes ownership of the following:

  • All packet descriptors accessible at PacketArray
  • All buffers mapped by the buffer descriptors chained to those packet descriptors
  • All out-of-band data blocks associated with the packet descriptors, including any medium-specific buffers specified in the OOB blocks

The allocating protocol regains ownership of these resources, one packet descriptor at a time, as its ProtocolCoSendComplete function is called with each packet descriptor in the array that it passed to NdisCoSendPackets.

Then, ProtocolCoSendComplete can either release the resources the protocol allocated or prepare these resources for reuse. During periods of average-to-high network I/O traffic, reusing the packet descriptors and buffers that a protocol allocates yields better performance than releasing buffers and the packet descriptor, only to reallocate them almost immediately for a subsequent send. However, any protocol that manages its usage of system resources carefully would not retain a large set of reusable packet descriptors with mapped buffers indefinitely after a period of high traffic falls into a sustained period of very low I/O demand. When ProtocolCoSendComplete reuses packet descriptors, it must save the buffer descriptors chained to each input packet descriptor with calls to an NdisUnchainBufferAt Xxx function before it calls NdisReinitializePacket with the input packet descriptor.

Callers of NdisCoSendPackets can be running at IRQL <= DISPATCH_LEVEL.

See Also

MiniportCoSendPackets, NDIS_PACKET, NDIS_PACKET_OOB_DATA, NdisReinitializePacket, NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO, NDIS_SET_PACKET_TIME_TO_SEND, NdisUnchainBufferAtBack, NdisUnchainBufferAtFront, ProtocolCoSendComplete


NdisCreateLookaheadBufferFromSharedMemory

NdisCreateLookaheadBufferFromSharedMemory returns the virtual address of a buffer within a block of memory shared with a bus-master DMA NIC.

VOID
  NdisCreateLookaheadBufferFromSharedMemory(
    IN PVOID  pSharedMemory,
    IN UINT  LookaheadLength,
    OUT PVOID  *pLookaheadBuffer
    );

Parameters

pSharedMemory
Specifies the base address of the shared memory range containing the data for the lookahead buffer.
LookaheadLength
Specifies the length in bytes for the lookahead buffer.
pLookaheadBuffer
Pointer to a caller-supplied variable in which this function returns the virtual address of the lookahead buffer.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisCreateLookaheadBufferFromSharedMemory provides a lookahead buffer that is a virtual memory copy of shared memory for miniport driver receive indications. To bound protocol drivers, such a lookahead buffer represents a read-only version of the shared memory.

This function accommodates system architectures that do not allow the NIC driver to read shared memory on a network interface card directly.

Callers of NdisCreateLookaheadBufferFromSharedMemory run at any IRQL.

See Also

MiniportHandleInterrupt, MiniportTimer, NdisDestroyLookaheadBufferFromSharedMemory, NdisMArcIndicateReceive, NdisMEthIndicateReceive, NdisMFddiIndicateReceive, NdisMTrIndicateReceive, NdisMWanIndicateReceive, ProtocolReceive


NdisDeleteNPagedLookasideList

NdisDeleteNPagedLookasideList removes a nonpaged lookaside list from the system.

VOID
  NdisDeleteNPagedLookasideList(
    IN  PNPAGED_LOOKASIDE_LIST  Lookaside
    );

Parameters

Lookaside
Pointer to the head of the lookaside list to be deleted.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

After freeing any remaining entries in the given lookaside list, NdisDeleteNPagedLookasideList removes the list from the OS-maintained set of nonpaged lookaside lists.

However, a call to NdisDeleteNPagedLookasideList does not free the list head, for which the caller originally allocated the memory. An NDIS driver is responsible for calling NdisFreeMemory to release any memory that it allocated.

Callers of NdisDeleteNPagedLookasideList must be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocateFromNPagedLookasideList, NdisFreeToNPagedLookasideList, NdisInitializeNPagedLookasideList


NdisDeregisterProtocol

NdisDeregisterProtocol releases the resources allocated when the driver called NdisRegisterProtocol.

VOID
  NdisDeregisterProtocol(
    OUT PNDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisProtocolHandle
    );

Parameters

Status
Pointer to a caller-supplied variable that is set to NDIS_STATUS_SUCCESS on return from this function.
NdisProtocolHandle
Specifies the handle returned by NdisRegisterProtocol when the driver initialized.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Registered protocol drivers call NdisDeregisterProtocol in any of the following circumstances:

  • The driver already called NdisRegisterProtocol successfully but it cannot bind to any underlying NDIS driver in the machine.
  • The driver is being unloaded. That is, the Unload routine set up in its driver object during initialization has been called or the ProtocolUnbindAdapter function has been called to release the driver's last remaining binding.

    For more information about the Unload routine and other standard kernel-mode driver routines, see Kernel-Mode Driver Components.

  • The system is being shut down. Because the driver, which is a highest-level protocol, called IoRegisterShutdownNotification when it initialized, its Shutdown routine has been called.

    See IoRegisterShutdownNotification for more information.

If a protocol has any open bindings, its call to NdisDeregisterProtocol causes NDIS to call the protocol's ProtocolUnbindAdapter function once for each open binding. ProtocolUnbindAdapter calls NdisCloseAdapter to close the binding.

When outstanding opens, if any, have been closed, NdisDeregisterProtocol releases all filters its caller has set up and frees the memory NDIS allocated to track bindings and filters for the protocol driver.

Callers of NdisDeregisterProtocol run at IRQL <= DISPATCH_LEVEL.

See Also

NdisCloseAdapter, NdisIMDeInitializeDeviceInstance, NdisOpenAdapter, NdisRegisterProtocol, ProtocolCloseAdapterComplete, ProtocolStatus, ProtocolUnbindAdapter


NdisDestroyLookaheadBufferFromSharedMemory

NdisDestroyLookaheadBufferFromSharedMemory releases the buffer mapping obtained in a preceding call to NdisCreateLookaheadBufferFromSharedMemory.

VOID
  NdisDestroyLookaheadBufferFromSharedMemory(
    IN PVOID  pLookaheadBuffer
    );

Parameters

pLookaheadBuffer
Specifies the lookahead buffer pointer returned in a preceding call to NdisCreateLookaheadBufferFromSharedMemory.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Callers of NdisDestroyLookaheadBufferFromSharedMemory run at any IRQL.

See Also

NdisCreateLookaheadBufferFromSharedMemory


NdisDprAcquireSpinLock

NdisDprAcquireSpinLock acquires a spin lock so the caller can synchronize access to resources shared among nonISR driver functions in a multiprocessor-safe way.

VOID
  NdisDprAcquireSpinLock(
    IN PNDIS_SPIN_LOCK  SpinLock
    );

Parameters

SpinLock
Pointer to an opaque spin lock, already initialized by the caller.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The NIC driver must initialize a variable of type NDIS_SPIN_LOCK with NdisAllocateSpinLock before it calls any other Ndis..SpinLock function. The driver must provide resident storage for the spin lock(s) it uses.

NdisDprAcquireSpinLock is an optimized version of NdisAcquireSpinLock that a miniport driver can call only while running at IRQL DISPATCH_LEVEL.

After acquiring a spin lock with NdisDprAcquireSpinLock, the caller must release that lock with a call to NdisDprReleaseSpinLock. A NIC driver must call NdisDprReleaseSpinLock following each call to NdisDprAcquireSpinLock. Otherwise, a deadlock occurs, hanging the driver.

A spin lock acquired with NdisDprAcquireSpinLock must be released with NdisDprReleaseSpinLock. A spin lock acquired with NdisAcquireSpinLock must be released with NdisReleaseSpinLock.

A driver should never hold a spin lock for an extended period (more than a few instructions). Holding a spin lock for longer than 25 microseconds degrades both system and driver performance.

A miniport driver cannot use a spin lock to protect resources that its other functions share with the MiniportISR and/or MiniportDisableInterrupt functions. Instead, a miniport driver must call NdisMSynchronizeWithInterrupt so that its MiniportSynchronizeISR function accesses such shared resources at the same DIRQL at which its MiniportISR and/or MiniportDisableInterrupt functions do.

Callers of NdisDprAcquireSpinLock must be running at IRQL DISPATCH_LEVEL.

See Also

MiniportDisableInterrupt, MiniportISR, MiniportSynchronizeISR, MiniportTimer, NdisAcquireSpinLock, NdisAllocateSpinLock, NdisDprReleaseSpinLock, NdisMSynchronizeWithInterrupt


NdisDprAllocatePacket

NdisDprAllocatePacket allocates and initializes a packet descriptor when the caller is running at IRQL DISPATCH_LEVEL.

VOID
  NdisDprAllocatePacket(
    OUT PNDIS_STATUS  Status,
    OUT PNDIS_PACKET  *Packet,
    IN NDIS_HANDLE  PoolHandle
    );

Parameters

Status
Pointer to a caller-supplied variable in which this function returns the final status of the request, which can be one of the following:
NDIS_STATUS_SUCCESS
The caller can use the packet descriptor returned at Packet.
NDIS_STATUS_RESOURCES
The free list for the packet pool currently has no available entries. A subsequent call to NdisDprFreePacket or NdisFreePacket will return the given entry to the free list. The variable at Packet is set to NULL.
Packet
Pointer to a caller-supplied variable in which this function returns a pointer to the allocated packet descriptor.
PoolHandle
Specifies the handle returned by a preceding call to NdisAllocatePacketPool.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisDprAllocatePacket runs slightly faster than NdisAllocatePacket because NDIS can acquire the spin lock it uses to synchronize access to the packet pool without having to raise IRQL.

A caller of NdisDprAllocatePacket must be running at IRQL DISPATCH_LEVEL. Otherwise, the driver should call NdisAllocatePacket.

See Also

NdisAllocatePacket, NdisAllocatePacketPool, NdisDprAllocatePacketNonInterlocked, NdisDprFreePacket, NdisFreePacket, NdisReleaseSpinLock


NdisDprAllocatePacketNonInterlocked

NdisDprAllocatePacketNonInterlocked allocates and initializes a packet descriptor when the caller is running at IRQL DISPATCH_LEVEL and that caller provides internal synchronization for accessing packet pool.

VOID
  NdisDprAllocatePacketNonInterlocked(
    OUT PNDIS_STATUS  Status,
    OUT PNDIS_PACKET  *Packet,
    IN NDIS_HANDLE  PoolHandle
    );

Parameters

Status
Pointer to a caller-supplied variable in which this function returns the final status of the request, which can be one of the following:
NDIS_STATUS_SUCCESS
The caller can use the packet descriptor returned at Packet.
NDIS_STATUS_RESOURCES
The free list for the packet pool currently has no available entries. A subsequent call to NdisDprFreePacketNonInterlocked will return the given entry to the free list. The variable at Packet is set to NULL.
Packet
Pointer to a caller-supplied variable in which this function returns a pointer to the allocated packet descriptor.
PoolHandle
Specifies the handle returned by a preceding call to NdisAllocatePacketPool.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A caller of NdisDprAllocatePacketNonInterlocked and its reciprocal NdisDprFreePacketNonInterlocked is responsible for synchronizing all accesses to the packet pool that driver allocated with NdisAllocatePacketPool. Otherwise, the driver should let NDIS manage this synchronization on its behalf by calling NdisAllocatePacket or NdisDprAllocatePacket.

NdisDprAllocatePacketNonInterlocked runs slightly faster than NdisAllocatePacket because NDIS need not acquire a spin lock, which NDIS typically uses to synchronize access to packet pools that drivers allocate.

Instead, a caller of NdisDprAllocatePacketNonInterlocked and NdisDprFreePacketNonInterlocked manages the synchronization of its accesses to packet pool internally.

Usually, such a driver protects its packet pool with a driver-allocated spin lock. Before calling NdisDprAllocatePacketNonInterlocked, the driver calls NdisAcquireSpinLock, which raises IRQL to DISPATCH_LEVEL. Only when the driver resumes execution holding its spin lock does it call NdisDprAllocatePacketNonInterlocked. Such a driver releases its spin lock with NdisReleaseSpinLock when NdisDprAllocatePacketNonInterlocked returns control.

In a similar manner, such a driver calls NdisAcquireSpinLock before it releases a packet descriptor back to pool with NdisDprFreePacketNonInterlocked and, then, it calls NdisReleaseSpinLock.

Any packet descriptor allocated with NdisDprAllocatePacketNonInterlocked must be freed with NdisDprFreePacketNonInterlocked except, possibly, when a driver is releasing its allocated resources just before being unloaded. Otherwise, it is a runtime synchronization error that can cause race conditions to release any packet descriptor with NdisDprFreePacket or NdisFreePacket if that packet descriptor was allocated with NdisDprAllocatePacketNonInterlocked.

The caller of NdisDprAllocatePacketNonInterlocked must be running at IRQL DISPATCH_LEVEL.

See Also

NdisAcquireSpinLock, NdisAllocatePacket, NdisAllocatePacketPool, NdisAllocateSpinLock, NdisDprAllocatePacket, NdisDprFreePacket, NdisDprFreePacketNonInterlocked, NdisFreePacket, NdisReleaseSpinLock


NdisDprFreePacket

NdisDprFreePacket releases a driver-allocated packet descriptor and returns it to the free list when the caller is running at IRQL DISPATCH_LEVEL.

VOID
  NdisDprFreePacket(
    IN PNDIS_PACKET  Packet
    );

Parameters

Packet
Pointer to the packet descriptor returned by NdisDprAllocatePacket or NdisAllocatePacket.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Before calling NdisDprFreePacket, the driver either must call NdisFreeBuffer as many times as necessary to release all buffer descriptors chained to the packet, or it must call an NdisUnchainBufferAt Xxx function as many times as necessary to save all pointers to buffer descriptors. Otherwise, memory associated with buffer descriptors in the chain remains unusable by the driver and by NDIS until the system is rebooted.

Callers of NdisDprFreePacket must be running at IRQL DISPATCH_LEVEL. Otherwise, drivers should call NdisFreePacket.

See Also

NdisAllocatePacket, NdisAllocatePacketPool, NdisDprAllocatePacket, NdisFreeBuffer, NdisFreePacket, NdisUnchainBufferAtBack, NdisUnchainBufferAtFront


NdisDprFreePacketNonInterlocked

NdisDprFreePacketNonInterlocked releases a driver-allocated packet descriptor and returns it to the free list when the caller is running at IRQL DISPATCH_LEVEL and that caller provides internal synchronization for accessing packet pool.

VOID
  NdisDprFreePacketNonInterlocked(
    IN PNDIS_PACKET  Packet
    );

Parameters

Packet
Pointer to a packet descriptor returned by NdisDprAllocatePacketNonInterlocked.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Before calling NdisDprFreePacketNonInterlocked, the driver either must call NdisFreeBuffer as many times as necessary to release all buffer descriptors chained to the packet, or it must call an NdisUnchainBufferAt Xxx function as many times as necessary to save all pointers to buffer descriptors. Otherwise, memory associated with buffer descriptors in the chain remains unusable by the driver

A caller of NdisDprFreePacketNonInterlocked and its reciprocal NdisDprAllocatePacketNonInterlocked is responsible for synchronizing all accesses to the packet pool that driver allocated with NdisAllocatePacketPool. Otherwise, the driver should let NDIS manage this synchronization on its behalf by calling NdisAllocate/FreePacket or NdisDprAllocate/FreePacket.

Usually, such a driver protects its packet pool with a driver-allocated spin lock. Before calling NdisDprFreePacketNonInterlocked, the driver calls NdisAcquireSpinLock, which raises IRQL to DISPATCH_LEVEL. Only when the driver resumes execution holding its spin lock does it call NdisDprFreePacketNonInterlocked. Such a driver releases its spin lock with NdisReleaseSpinLock when NdisDprFreePacketNonInterlocked returns control.

Callers of NdisDprFreePacketNonInterlocked must be running at IRQL DISPATCH_LEVEL.

See Also

NdisAcquireSpinLock, NdisAllocatePacketPool, NdisDprAllocatePacketNonInterlocked, NdisDprFreePacket, NdisFreeBuffer, NdisFreePacket, NdisReleaseSpinLock, NdisUnchainBufferAtBack, NdisUnchainBufferAtFront


NdisDprReleaseSpinLock

NdisDprReleaseSpinLock releases a spin lock acquired in the immediately preceding call to NdisDprAcquireSpinLock.

VOID
  NdisDprReleaseSpinLock(
    IN PNDIS_SPIN_LOCK  SpinLock
    );

Parameters

SpinLock
Pointer to the acquired spin lock to be released.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Release of the spin lock allows another driver function to use the resources the lock protects after that function acquires the spin lock.

A spin lock acquired with NdisDprAcquireSpinLock must be released with NdisDprReleaseSpinLock. A spin lock acquired with NdisAcquireSpinLock must be released with NdisReleaseSpinLock.

Callers of NdisDprReleaseSpinLock are running at IRQL DISPATCH_LEVEL.

See Also

NdisDprAcquireSpinLock


NdisEqualAnsiString

NdisEqualUnicodeString compares two ANSI strings and returns whether they are equal.

BOOLEAN
  NdisEqualAnsiString(
    IN PNDIS_STRING  String1,
    IN PNDIS_STRING  String2,
    IN BOOLEAN  CaseInSensitive
    );

Parameters

String1
Pointer to an NDIS_STRING type that describes the first ANSI string. The NDIS_STRING type is a counted string in the system-default character set.
String2
Pointer to an NDIS_STRING type that describes the second ANSI string.
CaseInSensitive
If TRUE, case should be ignored when doing the comparison.

Return Value

NdisEqualAnsiString returns TRUE if the two ANSI strings are equal.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Callers of NdisEqualAnsiString must be running at IRQL PASSIVE_LEVEL.

See Also

ANSI_STRING, NdisEqualUnicodeString, NdisEqualString


NdisEqualMemory

NdisEqualMemory compares a specified number of characters in one block of memory with the same number of characters in a second block of memory.

ULONG
  NdisEqualMemory (
    CONST VOID  *Source1,
    CONST VOID  *Source2,
    ULONG  Length
    );

Parameters

Source1
Pointer to the first block of memory to be compared.
Source2
Pointer to the second block of memory to be compared.
Length
Specifies the number of bytes to be compared.

Return Value

NdisEqualMemory returns one if the compared blocks are the same; otherwise, this function returns a zero.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisEqualMemory compares the initial Length bytes in the first block of memory to the initial Length bytes in the second block of memory. The data type of anything in the compared memory blocks is irrelevant.

Callers of NdisEqualMemory can be running at IRQL <= DISPATCH_LEVEL if both memory blocks are resident. If either block is pageable, callers must be running at IRQL < DISPATCH_LEVEL.

See Also

NdisAllocateMemory, NdisCopyBuffer, NdisFillMemory, NdisFreeMemory, NdisMoveMemory, NdisZeroMemory


NdisEqualString

NdisEqualString compares two strings, in the OS-default character set, to determine whether they are equal.

BOOLEAN
  NdisEqualString(
    IN PNDIS_STRING  String1,
    IN PNDIS_STRING  String2,
    IN BOOLEAN  CaseInsensitive
    );

Parameters

String1
Pointer to an NDIS_STRING type that describes the first string.
String2
Pointer to an NDIS_STRING type that describes the second string.
CaseInsensitive
Specifies TRUE if case should be ignored when doing the comparison.

Return Value

NdisEqualString returns TRUE if the two strings are equal.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

For Windows 2000 and later drivers, a string of type NDIS_STRING is a counted, zero-terminated Unicode string. That is, for Windows 2000 and later, NDIS defines the NDIS_STRING type as a UNICODE_STRING type.

Callers of NdisEqualString run at IRQL PASSIVE_LEVEL.

See Also

ANSI_STRING, MiniportInitialize, NdisInitializeString, ProtocolBindAdapter, UNICODE_STRING


NdisEqualUnicodeString

NdisEqualUnicodeString compares two Unicode strings and returns whether they are equal.

BOOLEAN
  NdisEqualUnicodeString(
    IN PNDIS_STRING  String1,
    IN PNDIS_STRING  String2,
    IN BOOLEAN  CaseInSensitive
    );

Parameters

String1
Pointer to an NDIS_STRING type that describes the first Unicode string.
String2
Pointer to an NDIS_STRING type that describes the second Unicode string.
CaseInSensitive
If TRUE, case should be ignored when doing the comparison.

Return Value

NdisEqualUnicodeString returns TRUE if the two Unicode strings are equal.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

For Windows 2000 and later drivers, a string of type NDIS_STRING is a counted, zero-terminated Unicode string. That is, for Windows 2000 and later, NDIS defines the NDIS_STRING type as a UNICODE_STRING type.

Callers of NdisEqualUnicodeString must be running at IRQL PASSIVE_LEVEL.

See Also

NdisEqualAnsiString, NdisEqualString, UNICODE_STRING


NdisFillMemory

NdisFillMemory fills a caller-supplied buffer with the given character.

VOID
  NdisFillMemory(
    IN PVOID  Destination,
    IN ULONG  Length,
    IN UCHAR  Fill
    );

Parameters

Destination
Pointer to the buffer to be filled.
Length
Specifies the number of bytes to be filled.
Fill
Specifies the value to fill the buffer.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Callers of NdisFillMemory can be running at any IRQL, provided that the Destination buffer is resident. If the buffer is pageable, a caller must be running at IRQL < DISPATCH_LEVEL.

See Also

NdisZeroMemory


NdisFlushBuffer

NdisFlushBuffer flushes the memory region described by a given buffer descriptor from all processor caches.

VOID
  NdisFlushBuffer(
    IN PNDIS_BUFFER  Buffer,
    IN BOOLEAN  WriteToDevice
    );

Parameters

Buffer
Pointer to a buffer description mapping a buffer from which or into which data is transferred as a bus-master DMA operation.
WriteToDevice
Specifies TRUE if the NIC driver calls this function to flush a buffer before making a transfer from host memory to the NIC.

If the NIC driver specifies FALSE, it must ensure the buffer begins and ends on a cache-line boundary.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Drivers of bus-master DMA NICs call NdisFlushBuffer to maintain data integrity in shared memory. Flushing the buffer ensures coherency between the host memory cache and processor physical memory before a DMA transfer to or from the network interface card.

The driver flushes such a buffer when data that it shares with its NIC might be cached. For any transfer between host memory and a bus-master DMA NIC, the miniport driver must flush the buffer before the transfer starts. Such a driver also must ensure that host memory is not accessed until the transfer completes.

Callers of NdisFlushBuffer run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, NdisMAllocateSharedMemory, NdisMUpdateSharedMemory


NdisFreeBuffer

NdisFreeBuffer releases a buffer descriptor obtained in a preceding call to NdisAllocateBuffer or NdisCopyBuffer.

VOID
  NdisFreeBuffer(
    IN PNDIS_BUFFER  Buffer
    );

Parameters

Buffer
Pointer to a buffer descriptor.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisFreeBuffer returns the given buffer descriptor to the free list.

A driver must not call NdisFreePacket with a packet to which buffers are chained, because doing this causes a memory leak. Before it releases such a packet, either the driver should call NdisFreeBuffer as many times as necessary to release all buffer descriptors chained to the packet, or it should call either NdisUnchainBufferAt Xxx function as many times as necessary to save the pointers to all chained buffer descriptors.

Callers of NdisFreeBuffer run at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocateBuffer, NdisCopyBuffer, NdisFreePacket, NdisReleaseSpinLock, NdisUnchainBufferAtBack, NdisUnchainBufferAtFront


NdisFreeBufferPool

NdisFreeBufferPool releases a handle obtained in a preceding call to NdisAllocateBufferPool.

VOID
  NdisFreeBufferPool(
    IN NDIS_HANDLE  PoolHandle
    );

Parameters

PoolHandle
Specifies the handle returned when the driver called NdisAllocateBufferPool. The pool handle is no longer valid after this function returns.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Before calling NdisFreeBufferPool, the driver must call NdisFreeBuffer as many times as necessary to release all buffer descriptors that were allocated with NdisAllocateBuffer but not yet released. Otherwise, the call to NdisFreeBufferPool causes a memory leak.

Callers of NdisFreeBufferPool run at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocateBuffer, NdisAllocateBufferPool, NdisFreeBuffer, NdisReleaseSpinLock


NdisFreeMemory

NdisFreeMemory releases a block of memory previously allocated with NdisAllocateMemory or NdisAllocateMemoryWithTag.

VOID
  NdisFreeMemory(
    IN PVOID  VirtualAddress,
    IN UINT  Length,
    IN UINT  MemoryFlags
    );

Parameters

VirtualAddress
Pointer to the base virtual address of the allocated memory. This address was returned by NdisAllocateMemory.
Length
Specifies the size in bytes of the memory block to be released. This parameter must be identical to the Length that was passed to NdisAllocateMemory. However, if the MemoryFlags setting is zero, this parameter is ignored.
MemoryFlags
Specifies zero or the bitmask originally passed to NdisAllocateMemory for the preceding range, designating the following:
Value | Meaning
zero | Nonpaged system-space memory
NDIS_MEMORY_CONTIGUOUS | Physically contiguous memory
NDIS_MEMORY_NONCACHED | Noncached memory

This value must be identical to the MemoryFlags that was passed to NdisAllocateMemory. This value must be zero if the memory was allocated with NdisAllocateMemoryWithTag.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The parameters passed to NdisFreeMemory must be identical to those passed to NdisAllocateMemory when the block of memory was allocated. That is, a caller of NdisFreeMemory cannot release a subrange of the block that was allocated.

Because noncached memory and contiguous memory are seldom released until the allocating NIC driver is unloading, a caller of NdisFreeMemory usually is running at IRQL PASSIVE_LEVEL for these types of deallocations. In any case:

  • When releasing contiguous memory, a caller of NdisFreeMemory must be running at IRQL PASSIVE_LEVEL
  • When releasing noncached memory, a caller of NdisFreeMemory must be running at IRQL < DISPATCH_LEVEL
  • When releasing memory that is neither contiguous nor noncached, a caller of NdisFreeMemory must be running at IRQL <= DISPATCH_LEVEL

See Also

MiniportHalt, NdisAllocateMemory,NdisAllocateMemoryWithTag


NdisFreePacket

NdisFreePacket releases a packet that was allocated from packet pool with NdisAllocatePacket and returns it to the free list.

VOID
  NdisFreePacket(
    IN PNDIS_PACKET  Packet
    );

Parameters

Packet
Pointer to the packet descriptor returned by NdisAllocatePacket or NdisDprAllocatePacket.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Before calling NdisFreePacket, the driver either must call NdisFreeBuffer as many times as necessary to release all buffer descriptors chained to the packet, or it must call an NdisUnchainBufferAt Xxx function as many times as necessary to save all pointers to buffer descriptors. Otherwise, memory associated with buffer descriptors in the chain remains unusable by the driver and by NDIS until the system is rebooted.

The driver must release any spin lock it is holding before calling NdisFreePacket.

Callers of NdisFreePacket run at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocatePacket, NdisDprAllocatePacket, NdisFreeBuffer, NdisReleaseSpinLock, NdisUnchainBufferAtBack, NdisUnchainBufferAtFront


NdisFreePacketPool

NdisFreePacketPool releases a handle to a block of packet pool that was allocated with NdisAllocatePacketPool.

VOID
  NdisFreePacketPool(
    IN NDIS_HANDLE  PoolHandle
    );

Parameters

PoolHandle
Specifies the handle returned when the driver called NdisAllocatePacketPool. The pool handle is no longer valid after this function returns.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisFreePacketPool frees the storage for the packet pool. Before calling this function, the driver must call NdisFreePacket as many times as necessary to release all packet descriptors that it has allocated with NdisAllocatePacket but not yet freed.

Callers of NdisFreePacketPool run at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocatePacket, NdisAllocatePacketPool, NdisFreePacket, NdisReleaseSpinLock


NdisFreeSpinLock

NdisFreeSpinLock releases a spin lock initialized in a preceding call to NdisAllocateSpinLock.

VOID
  NdisFreeSpinLock(
    IN PNDIS_SPIN_LOCK  SpinLock
    );

Parameters

SpinLock
Pointer to the spin lock to be deinitialized.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If the caller of NdisFreeSpinLock needs to use the spin lock again, it must call NdisAllocateSpinLock before passing that spin lock pointer to any of the Ndis..SpinLock or NdisInterlocked Xxx functions.

Callers of NdisFreeSpinLock run at IRQL PASSIVE_LEVEL. Usually, this function is not called until a driver is unloading.

See Also

MiniportHalt, NdisAcquireSpinLock, NdisAllocateSpinLock, NdisDprAcquireSpinLock, NdisDprReleaseSpinLock, NdisInterlockedAddUlong, NdisInterlockedInsertHeadList, NdisInterlockedInsertTailList, NdisInterlockedRemoveHeadList, NdisReleaseSpinLock


NdisFreeToNPagedLookasideList

NdisFreeToNPagedLookasideList returns an entry to the given lookaside list.

VOID
  NdisFreeToNPagedLookasideList(
    IN PNPAGED_LOOKASIDE_LIST  Lookaside,
    IN PVOID  Entry
    );

Parameters

Lookaside
Pointer to the head of the lookaside list to which the entry will be returned.
Entry
Pointer to the entry to be freed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If the lookaside list has not reached the system-determined maximum number of entries, Entry is inserted at the front of the lookaside list. If the list has reached its maximum size, Entry is released to nonpaged pool. That is, NdisFreeToNPagedLookasideList either calls the driver's Free function if the driver provided one to NdisInitializeNPagedLookasideList, or it frees the given entry itself.

Callers of NdisFreeToNPagedLookasideList must be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocateFromNPagedLookasideList, NdisDeleteNPagedLookasideList, NdisInitializeNPagedLookasideList


NdisGeneratePartialCancelId

NdisGeneratePartialCancelId returns a value that the calling driver must use as the high-order byte of a cancellation ID.

UCHAR
  NdisGeneratePartialCancelId(
    VOID
    );

Return Value

NdisGeneratePartialCancelId returns a value that the calling driver uses as the high-order byte of a cancellation ID.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Before marking send packets with cancellation IDs by calling NDIS_SET_PACKET_CANCEL_ID, a protocol or intermediate driver should call NdisGeneratePartialCancelId one or more times. NdisGeneratePartialCancelId returns a value that the calling driver can use as the high-order byte of a cancellation ID. Prefixing a cancellation ID with the value returned by NdisGeneratePartialCancelId ensures that the cancellation ID will not be a duplicate of a cancellation ID assigned by another driver in the system.

Typically, a protocol or intermediate driver calls NdisGeneratePartialCancelId one or more times during its initialization sequence and stores the returned value or values for later use. A protocol driver, for example, could call NdisGeneratePartialCancelId once for each client (such as DHCP or ARC) that it supports.

System support for NdisGeneratePartialCancelId is available in Windows XP and later OS versions.

Callers of NdisGeneratePartialCancelId run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportCancelSendPackets, NdisCancelSendPackets, NDIS_GET_PACKET_CANCEL_ID, NDIS_SET_PACKET_CANCEL_ID


NdisGetBufferPhysicalArraySize

NdisGetBufferPhysicalArraySize returns the number of discontiguous physical blocks backing a buffer, given the buffer descriptor.

VOID
  NdisGetBufferPhysicalArraySize(
    IN PNDIS_BUFFER  Buffer,
    OUT PUINT  ArraySize
    );

Parameters

Buffer
Pointer to the buffer descriptor.
ArraySize
Pointer to a caller-supplied variable in which this function returns the number of discrete physical ranges backing the buffer.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The driver of a bus-master DMA NIC might call NdisGetBufferPhysicalArraySize to determine how many NDIS_PHYSICAL_ADDRESS structures to allocate and fill in before calling NdisMStartBufferPhysicalMapping.

A protocol driver might call NdisGetBufferPhysicalArraySize to build a scatter/gather list for an underlying NIC driver. However, a protocol driver with such NIC-specific functionality is unlikely to be bindable to any other NIC driver.

The maximum number of physical blocks in the buffer can be one more than the number this function writes, depending on the arrangement of the buffer in paged memory. NdisGetBufferPhysicalArraySize returns the number of pages required to back a buffer of the given length, so if the buffer descriptor actually maps a buffer that begins at an offset within a page, the value returned by this call is one less than the number of page breaks.

A driver must release any spin lock it is holding before calling NdisGetBufferPhysicalArraySize.

Callers of NdisGetBufferPhysicalArraySize run at IRQL <= DISPATCH_LEVEL.

See Also

NDIS_PHYSICAL_ADDRESS, NdisMStartBufferPhysicalMapping


NdisGetCacheFillSize

This function is obsolete for Windows XP and later. Windows XP supports this function for legacy drivers; however, the Windows XP DDK will not build an NDIS driver that calls this function.

NdisGetCacheFillSize returns the microprocessor's data cache-line boundary in bytes.

ULONG
  NdisGetCacheFillSize(
    );

Return Value

If NdisGetCacheFillSize succeeds, it returns the host cache fill size.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Drivers of DMA NICs can use the information returned by this function to avoid cache-line tearing during DMA transfers.

For example, a NIC driver might use the value returned by NdisGetCacheFillSize in any (or all) of the following ways:

  • Allocate cache-aligned buffers for DMA operations.
  • Transfer data from aligned buffers that are sized as an integral of the value returned by this function.
  • Subtract one from the returned value and use the result as a mask to determine whether a "physical" address in shared memory is aligned on a cache-line boundary.

Windows XP and later OS versions support the NdisMGetDmaAlignment function for retrieving the microprocessor's data cache-line boundary.

Callers of NdisGetCacheFillSize run at IRQL PASSIVE_LEVEL. Usually, miniport drivers call this function during initialization and save the value it returns.

See Also

MiniportInitialize, NdisMAllocateMapRegisters, NdisMAllocateSharedMemory, NdisMAllocateSharedMemoryAsync, NdisMGetDmaAlignment


NdisGetCurrentProcessorCounts

NdisGetCurrentProcessorCounts returns counts for the current processor that a driver can use to determine CPU utilization for a particular time interval.

VOID
  NdisGetCurrentProcessorCounts(
    OUT PULONG  pIdleCount,
    OUT PULONG  pKernelAndUser,
    OUT PULONG  pIndex
    );

Parameters

pIdleCount
Pointer to a caller-supplied variable in which this function returns the cumulative idle time for the processor since the system was booted.
pKernelAndUser
Pointer to a caller-supplied variable in which this function returns the cumulative processing time (kernel-mode time plus user-mode time) for the processor since the system was booted.
pIndex
Pointer to a caller-supplied variable in which this function returns a zero-based index that identifies the processor within the machine.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisGetCurrentProcessorCounts returns idle and CPU-usage counts that the caller can use to determine CPU utilization for the current processor. The CPU utilization value indicates how loaded the CPU was since the immediately preceding call to this function. If the CPU was heavily loaded, such a driver can change how it handles certain operations to improve driver performance.

A driver might call NdisGetCurrentProcessorCounts periodically within a timer function. The driver can use the following calculation to determine the CPU utilization for a multiple of the timer interval:

CpuUsage = 100-100*(Idle - Idle[n])/(KernelAndUser - KernelAndUser[n]);

where:

  • CpuUsage is CPU utilization as a percentage of the total interval time
  • Idle is the IdleCount value returned by the most recent call to NdisGetCurrentProcessorCounts
  • Idle[n] is an IdleCount value returned by a previous call, stored as the nth element in an array
  • KernelandUser is the KernelAndUser value returned by the most recent call to NdisGetCurrentProcessorCounts
  • KernelandUser[n] is the KernelandUser value returned by a previous call, stored as the nth element in an array

For example, as the percentage of CPU usage trends higher, a miniport driver can disable interrupts on the NIC and switch to polling the state of its NIC. This strategy yields higher performance during periods of high network traffic by eliminating interrupt-processing overhead while the NIC is generating many interrupts. Instead, such a NIC driver's polling MiniportTimer function makes indications and completes sends until network traffic declines again. When its periodic calls to NdisGetCurrentProcessorCounts indicate that CPU usage is trending lower again, such a driver would re-enable interrupts on its NIC and cancel its polling MiniportTimer function.

Callers of NdisGetCurrentProcessorCounts must be running at IRQL <= DISPATCH_LEVEL.

See Also

MiniportDisableInterrupt, MiniportHandleInterrupt, MiniportISR, MiniportTimer, NdisGetCurrentProcessorCpuUsage, NdisMCancelTimer, NdisMSetPeriodicTimer


NdisGetCurrentProcessorCpuUsage

NdisGetCurrentProcessorCpuUsage returns how busy the current processor is as a percentage.

VOID
  NdisGetCurrentProcessorCpuUsage(
    PULONG  pCpuUsage
    );

Parameters

pCpuUsage
Pointer to a caller-supplied variable in which this function returns the percentage of CPU, on which the caller is running, that is currently in use.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NDIS drivers can call NdisGetCurrentProcessorCpuUsage to determine how loaded the CPU on which they are running is so they can change how they handle certain operations to improve driver performance.

For example, a NIC driver might call this function periodically and, as its percentage of CPU usage trends higher, disable interrupts on the NIC and switch to polling the state of the NIC. This strategy yields higher performance during periods of high network traffic by eliminating interrupt-processing overhead while the NIC is generating many interrupts. Instead, the driver's polling MiniportTimer function makes indications and completes sends until network traffic declines again. When its periodic calls to NdisGetCurrentProcessorCpuUsage indicate CPU usage is trending lower again, such a driver would re-enable interrupts on the NIC and cancel its polling MiniportTimer function.

Callers of NdisGetCurrentProcessorCpuUsage can run at any IRQL.

See Also

MiniportDisableInterrupt, MiniportHandleInterrupt, MiniportISR, MiniportTimer, NdisMCancelTimer, NdisMSetPeriodicTimer


NdisGetCurrentSystemTime

NdisGetCurrentSystemTime returns the current system time, suitable for setting timestamps.

VOID
  NdisGetCurrentSystemTime(
    IN PLARGE_INTEGER  pSystemTime
    );

Parameters

pSystemTime
Pointer to a caller-supplied variable in which this function returns a count of 100-nanosecond intervals since January 1, 1601.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

An NDIS driver can call NdisGetCurrentSystemTime to set timestamps in the out-of-band blocks associated with packets it indicates or sends.

An NDIS driver also might call NdisGetCurrentSystemTime if it maintains a count of how many packets it receives within any particular interval to tune its performance dynamically. For example, a NIC driver could call NdisGetCurrentSystemTime for each receive interrupt to determine periods of particularly high network traffic, when the driver might disable one or more types of interrupts on the NIC and enable a polling MiniportTimer function to process receives and/or sends.

Callers of NdisGetCurrentSystemTime can be running at any IRQL.

See Also

MiniportHandleInterrupt, MiniportTimer, NdisGetCurrentProcessorCpuUsage, NdisMSetPeriodicTimer, NDIS_PACKET_OOB_DATA, NDIS_SET_PACKET_TIME_RECEIVED, NDIS_SET_PACKET_TIME_SENT, NDIS_SET_PACKET_TIME_TO_SEND


NdisGetDriverHandle

NdisGetDriverHandle retrieves a handle to the miniport driver that owns the adapter port that is referenced by a caller-supplied handle.

VOID
  NdisGetDriverHandle(
    IN PNDIS_HANDLE  NdisBindingHandle,
    OUT PNDIS_HANDLE  NdisDriverHandle
    );

Parameters

NdisBindingHandle
Pointer to a handle to the bound adapter port for which a handle to the miniport driver is to be retrieved. Typically, NdisBindingHandle is returned by NdisOpenAdapter.
NdisDriverHandle
Pointer to a caller-supplied variable. If the call succeeds, NdisGetDriverHandle returns a handle to a miniport driver in this caller-supplied variable. This miniport driver exports the bound adapter port that is specified by NdisBindingHandle.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

An adapter port is exposed in the NdisBindingHandle binding. A protocol driver uses NdisGetDriverHandle to retrieve a handle to the miniport driver that owns this adapter port. The protocol driver cannot use the handle to the miniport driver for any purpose other than identifying the miniport driver for a given binding.

A protocol driver retrieves the same handle to the miniport driver in NdisDriverHandle for all bindings to adapter ports that are exported by the same miniport driver. A protocol driver typically uses NdisGetDriverHandle to check if two bound adapter ports that were opened by the protocol are owned by the same miniport driver.

Callers of NdisGetDriverHandle run at IRQL <= DISPATCH_LEVEL.

See Also

NdisOpenAdapter


NdisGetFirstBufferFromPacket

NdisGetFirstBufferFromPacket returns pointers to the buffer descriptor and base virtual address for the first buffer chained to a given packet descriptor, along with the sizes of the first buffer and the total buffer in case the buffer.

VOID
  NdisGetFirstBufferFromPacket(
    IN PNDIS_PACKET  Packet,
    OUT PNDIS_BUFFER  *FirstBuffer,
    OUT PVOID  *FirstBufferVA,
    OUT PUINT  FirstBufferLength,
    OUT PUINT  TotalBufferLength
    );

Parameters

Packet
Pointer to the packet descriptor from which this macro extracts information about the initial buffer.
FirstBuffer
Pointer to a caller-supplied variable in which this macro returns the address of the initial buffer descriptor chained to the given packet descriptor.
FirstBufferVA
Pointer to a caller-supplied variable in which this macro returns the base virtual address of the initial buffer associated with the packet.
FirstBufferLength
Pointer to a caller-supplied variable in which this macro returns the number of bytes mapped by the initial buffer descriptor chained to the packet descriptor.
TotalBufferLength
Pointer to a caller-supplied variable in which this macro returns the total number of bytes mapped by all buffer descriptors chained to the packet descriptor.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Drivers should call NdisGetFirstBufferFromPacketSafe instead of NdisGetFirstBufferFromPacket. NDIS 5.1 miniport drivers must call NdisGetFirstBufferFromPacketSafe instead of NdisGetFirstBufferFromPacket. Unlike NdisGetFirstBufferFromPacket, NdisGetFirstBufferFromPacketSafe does not cause a bug check if system resources are low or exhausted.

Drivers call NdisGetFirstBufferFromPacketSafe to get information about the initial buffer and amount of data associated with a given packet faster than they can by making calls to NdisQueryPacket and, then, NdisQueryBuffer(Safe).

Callers of NdisGetFirstBufferFromPacket run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportSend, MiniportSendPackets, NdisGetFirstBufferFromPacketSafe, NdisGetNextBuffer, NDIS_PACKET, NdisQueryBuffer, NdisQueryBufferSafe, NdisQueryPacket, ProtocolReceivePacket


NdisGetFirstBufferFromPacketSafe

NdisGetFirstBufferFromPacketSafe returns pointers to the buffer descriptor and base virtual address for the first buffer chained to a given packet descriptor, along with the sizes of the first buffer and the total buffer.

VOID
  NdisGetFirstBufferFromPacketSafe(
    IN PNDIS_PACKET  Packet,
    OUT PNDIS_BUFFER  *FirstBuffer,
    OUT PVOID  *FirstBufferVA,
    OUT PUINT  FirstBufferLength,
    OUT PUINT  TotalBufferLength
    IN MM_PAGE_PRIORITY  Priority
    );

Parameters

Packet
Pointer to the packet descriptor from which this macro extracts information about the initial buffer.
FirstBuffer
Pointer to a caller-supplied variable in which this macro returns the address of the initial buffer descriptor chained to the given packet descriptor.
FirstBufferVA
Pointer to a caller-supplied variable in which this macro returns the base virtual address of the initial buffer associated with the packet. If NdisGetFirstBufferFromPacketSafe fails, it sets FirstBufferVA to NULL.
FirstBufferLength
Pointer to a caller-supplied variable in which this macro returns the number of bytes mapped by the initial buffer descriptor chained to the packet descriptor.
TotalBufferLength
Pointer to a caller-supplied variable in which this macro returns the total number of bytes mapped by all buffer descriptors chained to the packet descriptor.
Priority
Indicates the priority of the request as one of the following:
LowPagePriority
Specifies a low priority. It is acceptable for NdisGetFirstBufferFromPacketSafe to fail if system resources are low.
NormalPagePriority
Specifies a normal priority. It is acceptable for NdisGetFirstBufferFromPacketSafe to fail if system resources are low.
HighPagePriority
Specifies a high priority. It is unacceptable for NdisGetFirstBufferFromPacketSafe to fail unless system resources are exhausted.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisGetFirstBufferFromPacketSafe is the safe version of NdisGetFirstBufferFromPacket. Unlike NdisGetFirstBufferFromPacket, NdisGetFirstBufferFromPacketSafe does not cause a bug check if system resources are low or exhausted. Drivers should call NdisGetFirstBufferFromPacketSafe instead of NdisGetFirstBufferFromPacket. NDIS 5.1 drivers must call NdisGetFirstBufferFromPacketSafe instead of NdisGetFirstBufferFromPacket.

Drivers call NdisGetFirstBufferFromPacketSafe to get information about the initial buffer and amount of data associated with a given packet faster than they can by making calls to NdisQueryPacket and, then, NdisQueryBuffer(Safe).

System support for NdisGetFirstBufferFromPacketSafe is available in Windows XP and later OS versions.

Callers of NdisGetFirstBufferFromPacketSafe run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportSend, MiniportSendPackets, NdisGetFirstBufferFromPacket, NdisGetNextBuffer, NDIS_PACKET, NdisQueryBuffer, NdisQueryBufferSafe, NdisQueryPacket, ProtocolReceivePacket


NDIS_GET_ORIGINAL_PACKET

NDIS_GET_ORIGINAL_PACKET returns a pointer to a packet descriptor that the lowest-level driver in a layered stack of NDIS drivers indicated. The calling driver should access the out-of-band (OOB) data block from this original packet rather than the packet that the driver below the calling driver indicated. If the calling driver is not part of a layered stack, the returned packet descriptor will be identical to the packet that the driver below the calling driver indicated.

PNDIS_PACKET
  NDIS_GET_ORIGINAL_PACKET(
    IN PNDIS_PACKET  Packet
    );

Parameters

Packet
Pointer to a packet descriptor that the driver below the calling driver indicated.

Return Value

NDIS_GET_ORIGINAL_PACKET returns a pointer to the packet descriptor that the lowest-level driver in a layered stack of NDIS drivers indicated, or if the calling driver is not part of a layered stack, NDIS_GET_ORIGINAL_PACKET returns the packet descriptor that the driver below the calling driver indicated.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Typically, the packet that is returned by NDIS_GET_ORIGINAL_PACKET is the same packet that was indicated up by the driver below the calling driver. To indicate packets to a higher-level driver, a driver can call, for example, the NdisMIndicateReceivePacket function. To retrieve packets that were indicated up from a lower-level driver, a driver can call the NdisGetReceivedPacket function.

To obtain a pointer to a packet that was indicated up by the lowest-level driver in a layered stack of NDIS drivers, protocol and intermediate drivers call NDIS_GET_ORIGINAL_PACKET. In this call, they pass the pointer to the received packet. Using this call, each driver in the layered stack can access the OOB data block that is associated with packets that are received from the network without requiring that packets be copied to each layer.

Callers of this macro can be running at any IRQL.

Example

The following example code retrieves a packet that was received from the driver below and obtains the original packet from the retrieved packet.

// Get the original packet, which could be the received packet
// or the packet originating from the lowest-level driver.
// This result is based on the number of layered drivers in the stack.
//
Pkt = NdisGetReceivedPacket(BindingHandle, MacReceiveContext);
OrigPkt = NDIS_GET_ORIGINAL_PACKET(Pkt);

See Also

NdisGetReceivedPacket, NdisMIndicateReceivePacket, NDIS_PACKET, NDIS_PACKET_EXTENSION, NDIS_PACKET_EXTENSION_FROM_PACKET, NDIS_PER_PACKET_INFO_FROM_PACKET, NDIS_SET_ORIGINAL_PACKET


NdisGetNextBuffer

NdisGetNextBuffer returns the next buffer descriptor in a chain, given a pointer to the current buffer descriptor.

VOID
  NdisGetNextBuffer(
    IN PNDIS_BUFFER  CurrentBuffer,
    OUT PNDIS_BUFFER  *NextBuffer
    );

Parameters

CurrentBuffer
Pointer to the current buffer descriptor.
NextBuffer
Pointer to a caller-supplied variable in which this function returns a pointer to the buffer descriptor, if any, that follows CurrentBuffer in the buffer descriptor chain.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisGetNextBuffer returns NULL at NextBuffer if CurrentBuffer points to the last buffer descriptor in the chain.

A driver usually calls this function after it calls NdisQueryPacket or NdisGetFirstBufferFromPacket(Safe).

A driver also can call NdisQueryBuffer(Safe) orto get details about a buffer descriptor that NdisGetNextBuffer finds.

NdisGetNextBuffer does not perform any synchronization. Therefore, a caller must handle any synchronization issues internally if more than one driver function can access buffer descriptors chained to a packet simultaneously.

Callers of NdisGetNextBuffer can run at any IRQL.

See Also

NdisGetFirstBufferFromPacket, NdisGetFirstBufferFromPacketSafe, NdisQueryBuffer, NdisQueryBufferSafe, NdisQueryPacket


NDIS_GET_PACKET_CANCEL_ID

NDIS_GET_PACKET_CANCEL_ID returns the cancellation identifier assigned to a packet.

PVOID
  NDIS_GET_PACKET_CANCEL_ID(
    IN PNDIS_PACKET  Packet
    );

Parameters

Packet
Pointer to an NDIS_PACKET structure that is the descriptor for a packet.

Return Value

Returns the cancellation identifier for the specified packet.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A protocol or intermediate driver can calls NDIS_GET_PACKET_CANCEL_ID to obtain the cancellation identifier for a packet.

A miniport driver calls NDIS_GET_PACKET_CANCEL_ID from its MiniportCancelSendPackets function to obtain cancellation identifiers of packets in its send queue. If a packet's cancellation ID matches the cancellation ID passed to the miniport driver's MiniportCancelSendPackets function, the miniport driver cancels the pending transmission of the packet.

System support for NDIS_GET_PACKET_CANCEL_ID is available in Windows XP and later OS versions.

Callers of NDIS_GET_PACKET_CANCEL_ID run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportCancelSendPackets, NdisCancelSendPackets, NdisGeneratePartialCancelId, NDIS_GET_PACKET_CANCEL_ID


NdisGetPacketFlags

NdisGetPacketFlags returns the flags, if any, set by a protocol driver in a given packet descriptor.

UINT
  NdisGetPacketFlags(
    IN PNDIS_PACKET  Packet
    );

Parameters

Packet
Pointer to the packet.

Return Value

NdisGetPacketFlags returns the value of the flags in the given packet descriptor. This function returns zero if the packet has no explictly set flags information.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisGetPacketFlags returns information set in the flags packet descriptor that a protocol driver passes down to the underlying NDIS driver, usually with NdisSend or NdisSendPackets. These flags can contain protocol-determined information about the send that is not included in the packet data nor in the out-of-band block associated with the packet descriptor.

Protocol drivers can set the flags in packets to be sent on any medium that transmits data in an expedited manner. The MiniportSendPackets function of an underlying NIC driver calls NdisGetPacketFlags to retrieve this information. For underlying NIC drivers that do not support multipacket sends, calls to NdisGetPacketFlags are unnecessary because the packet flags value is passed as an input parameter to the MiniportSend function.

Callers of NdisGetPacketFlags can run at any IRQL.

See Also

MiniportSend, MiniportSendPackets, MiniportWanSend, NDIS_PACKET, NDIS_PACKET_OOB_DATA, NdisSetPacketFlags


NDIS_GET_PACKET_HEADER_SIZE

NDIS_GET_PACKET_HEADER_SIZE returns the HeaderSize value from the out-of-band data block associated with a given packet descriptor.

UINT
  NDIS_GET_PACKET_HEADER_SIZE(
    IN PNDIS_PACKET  Packet
    );

Parameters

Packet
Pointer to a packet descriptor.

Return Value

NDIS_GET_PACKET_HEADER_SIZE returns the value set in the HeaderSize member of the NDIS_PACKET_OOB_DATA block associated with the given packet descriptor.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The HeaderSize specifies the number of bytes of medium-specific header mapped by the initial buffer descriptor chained to the packet descriptor. A NIC driver sets this value with NDIS_SET_PACKET_HEADER_SIZE in the out-of-band data block for the receive packets it will indicate with NdisMIndicateReceivePacket. Typically, a miniport driver sets the HeaderSize once in each packet descriptor it allocates with NdisAllocatePacket for subsequent receive indications, and the value it sets depends on the medium it selected during initialization.

An NDIS intermediate driver that translates indicated packets to another medium for still higher level protocols would use NDIS_SET_PACKET_HEADER to set the header size to a value appropriate to its own medium as it translates incoming receives.

Callers of NDIS_GET_PACKET_HEADER_SIZE run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportInitialize, NdisAllocatePacket, NdisMIndicateReceivePacket, NDIS_OOB_DATA_FROM_PACKET, NDIS_PACKET_OOB_DATA, NdisSend, NdisSendPackets, NDIS_SET_PACKET_HEADER_SIZE


NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO

NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO returns the MediaSpecificInformation pointer and the SizeMediaSpecificInfo value from the out-of-band data block associated with a given packet descriptor.

VOID
  NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(
    IN PNDIS_PACKET  Packet,
    IN PPVOID  pMediaSpecificInfo,
    IN PUINT  pSizeMediaSpecificInfo
    );

Parameters

Packet
Pointer to a packet descriptor.
pMediaSpecificInfo
Pointer to a caller supplied variable that this macro sets to the MediaSpecificInformation pointer. The returned address gives the caller access to any buffered out-of-band information, such as packet priority, associated with the specified net packet indicated or to be transmitted.
pSizeMediaSpecificInfo
Pointer to a caller-supplied variable that this macro sets to the SizeMediaSpecificInfo value, which specifies the size in bytes of the buffer at MediaSpecificInformation.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO returns a NULL pointer at pMediaSpecificInfo and zero at pSizeMediaSpecificInfo if there is no media-specific information in the NDIS_PACKET_OOB_DATA block associated with the given packet descriptor.

Depending on the medium, a miniport driver might set these members with NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO in the out-of-band data blocks associated with the packet descriptors it allocates for receive indications.

Depending on the medium of the underlying driver to which it is bound, a protocol might set MediaSpecificInformation and SizeMediaSpecificInfo in the out-of-band blocks associated with the packet descriptors it allocates for sends.

In either case, while a higher-level protocol is consuming a receive indication or a lower-level miniport driver is processing a send, that driver must have exclusive access to the buffer at MediaSpecificInformation. This restriction implies the following:

  • A miniport driver cannot access the buffer it set up with media-specific information when NdisMIndicateReceivePacket returns control if NDIS_STATUS_PENDING is set in the Status member of the associated out-of-band block. The driver can use NDIS_GET_PACKET_STATUS to determine whether each packet in the packet array it just indicated has this status set or has been returned with NDIS_STATUS_SUCCESS.
  • A protocol driver cannot access the media-specific information buffer it set up for a send, nor anything else in the out-of-band data block associated with a packet descriptor it passes to NdisSendPackets or NdisSend, until the packet descriptor is returned to its ProtocolSendComplete function.

    Because NDIS queues send packets and resubmits them if the MiniportSend function returns NDIS_STATUS_RESOURCES or if the MiniportSendPackets function sets NDIS_STATUS_RESOURCES for the Status of a packet in a submitted array, the final status of each packet in a send (array) is volatile until that packet has been returned to ProtocolSendComplete.

A protocol driver can call NdisGetReceivedPacket followed by NDIS_GET_ORIGINAL_PACKET to obtain this information from the NDIS_PACKET_OOB_DATA block associated with a packet descriptor when its ProtocolReceive function is given an indication. However, these calls are superfluous if the protocol is bound to an underlying driver that does not supply out-of-band information with its indications.

Callers of NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportSend, MiniportSendPackets, MiniportTimer, NdisAllocatePacket, NDIS_GET_ORIGINAL_PACKET, NdisGetReceivedPacket, NdisMIndicateReceivePacket, NDIS_OOB_DATA_FROM_PACKET, NDIS_PACKET_OOB_DATA, NdisSend, NdisSendPackets, NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO, ProtocolReceive, ProtocolReceivePacket, ProtocolSendComplete


NDIS_GET_PACKET_PROTOCOL_TYPE

NDIS_GET_PACKET_PROTOCOL_TYPE returns the protocol ID associated with a given packet descriptor.

UINT
  NDIS_GET_PACKET_PROTOCOL_TYPE(
    IN PNDIS_PACKET  Packet,
    );

Parameters

Packet
Pointer to a packet descriptor.

Return Value

NDIS_GET_PACKET_PROTOCOL_TYPE returns the protocol ID associated with a given packet descriptor as one of the following values:

NDIS_PROTOCOL_ID_DEFAULT
Unspecified
NDIS_PROTOCOL_ID_TCP_IP
TCP/IP
NDIS_PROTOCOL_ID_IPX
IPX
NDIS_PROTOCOL_ID_NBF
NetBEUI

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Drivers can test the Protocol ID associated with a packet descriptor to determine whether to perform an operation on a packet. For example, before passing a TCP/IP checksum operation to its NIC, a miniport driver could test the Protocol ID associated with a packet descriptor. If the Protocol ID is not NDIS_PROTOCOL_ID_TCP_IP, the miniport driver's NIC should not perform checksum operations on the associated packet.

Callers of NDIS_GET_PACKET_PROTOCOL_TYPE run at IRQL <= DISPATCH_LEVEL.

See Also

NDIS_PACKET


NDIS_GET_PACKET_STATUS

NDIS_GET_PACKET_STATUS returns the Status value from the out-of-band data block associated with a given packet descriptor.

NDIS_STATUS
  NDIS_GET_PACKET_STATUS(
    IN PNDIS_PACKET  Packet
    );

Parameters

Packet
Pointer to a packet descriptor.

Return Value

NDIS_GET_PACKET_STATUS returns the Status value currently set in the NDIS_PACKET_OOB_DATA block associated with the given packet descriptor, usually one of the following:

NDIS_STATUS_SUCCESS
If this is set on return from a miniport driver's call to NdisMIndicateReceivePacket, the miniport driver regains ownership of the following:
  • The packet descriptor
  • The associated out-of-band data block and of any media-specific information buffer specified in this block
  • All buffers mapped by buffer descriptors chained to the packet the miniport driver just indicated

The miniport driver can prepare these descriptors, the out-of-band block, and media-specific information buffer, if any, for reuse in subsequent receive indications, and, if it is a NIC driver, can receive new data in the NIC's receive buffers mapped by the returned buffer descriptors.

NDIS_STATUS_PENDING
If this is set on return from NdisMIndicateReceivePacket, protocols retain ownership of the following:
  • The packet descriptor
  • The associated out-of-band data block and of any media-specific information buffer specified in this block
  • All buffers mapped by buffer descriptors chained to the packet the miniport driver just indicated

Until the packet descriptor is returned to the MiniportReturnPacket function of the indicating driver, it should not access any of the buffers specified with the packet descriptor.

NDIS_STATUS_RESOURCES
If this is set, a connection-oriented protocol driver's ProtocolCoReceivePacket function must copy the packet data immediately rather than retaining the NIC-driver-allocated packet resources.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Serialized drivers (miniport drivers or intermediate drivers) that indicate receives up to higher-level drivers use this macro. Connection-oriented protocols call this macro from ProtocolCoReceivePacket to determine whether they have ownership of an indicated packet's resources or whether they must copy the packet data immediately before the packet is returned to the indicating underlying driver.

Deserialized drivers and connection-oriented drivers do not have to use this macro. When such drivers indicate up a packet whose Status is not set to NDIS_STATUS_RESOURCES, NDIS always returns the packet to the driver's MiniportReturnPacket function. When such drivers indicate up a packet whose Status is set to NDIS_STATUS_RESOURCES, NDIS always returns the packet implicitly on return from NdisM(Co)IndicateReceivePacket. In short, when NDIS returns a packet to a such driver — either on the return from NdisM(Co)IndicateReceivePacket or to the driver's MiniportReturnPacket function — the returned packet and all its associated resources belong to the driver. The driver should save the Status of each received packet that it indicates up so that it knows, on the return of NdisM(Co)IndicateReceivePacket whether the packet's Status is NDIS_STATUS_RESOURCES.

Protocol drivers should never test the Status value in an associated out-of-band data block on return from NdisSendPackets or NdisSend. NDIS or the underlying driver retains ownership of the packet descriptor, of the associated out-of-band block and any buffers specified in this block, and of all buffers mapped by buffer descriptors chained to the packet descriptor until the ProtocolSendComplete function is called with the packet descriptor.

Callers of NDIS_GET_PACKET_STATUS run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportReturnPacket, MiniportTimer, NdisAllocatePacket, NdisMIndicateReceivePacket, NDIS_OOB_DATA_FROM_PACKET, NDIS_PACKET_OOB_DATA, NdisSend, NdisSendPackets, NDIS_SET_PACKET_STATUS, ProtocolCoReceivePacket, ProtocolSendComplete


NDIS_GET_PACKET_TIME_RECEIVED

NDIS_GET_PACKET_TIME_RECEIVED returns the TimeReceived value from the out-of-band data block associated with a given packet descriptor.

ULONGLONG
  NDIS_GET_PACKET_TIME_RECEIVED(
    IN PNDIS_PACKET  Packet
    );

Parameters

Packet
Pointer to a packet descriptor.

Return Value

NDIS_GET_PACKET_TIME_RECEIVED returns the timestamp, if any, set by the miniport driver when the net packet was received on the underlying NIC.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

When a protocol driver's ProtocolReceivePacket function is called with an indication, it can use this macro to retrieve the TimeReceived timestamp using the Packet pointer it is given on entry.

A protocol driver can call NdisGetReceivedPacket and NDIS_GET_ORIGINAL_PACKET to obtain this timestamp from the NDIS_PACKET_OOB_DATA block associated with a packet descriptor when its ProtocolReceive function is given an indication. However, these calls are superfluous if the protocol is bound to an underlying driver that does not supply out-of-band information with its indications.

All timestamps set in the NDIS_PACKET_OOB_DATA blocks associated with packet descriptors are expressed in system time units as the number of 100-nanosecond intervals since January 1, 1601.

A highest-level protocol driver might use this macro before it forwards a received net packet to clients if its clients expect timestamps. Still higher-level drivers or system components can convert this timestamp into locale-specific values more meaningful to the end user.

Callers of NDIS_GET_PACKET_TIME_RECEIVED run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportTimer, NdisGetCurrentSystemTime, NDIS_GET_ORIGINAL_PACKET, NDIS_GET_PACKET_TIME_SENT, NdisGetReceivedPacket, NdisMIndicateReceivePacket, NDIS_OOB_DATA_FROM_PACKET, NDIS_PACKET_OOB_DATA, NDIS_SET_PACKET_TIME_RECEIVED, ProtocolReceive, ProtocolReceivePacket


NDIS_GET_PACKET_TIME_SENT

NDIS_GET_PACKET_TIME_SENT returns the TimeSent value from the out-of-band data block associated with a given packet descriptor.

ULONGLONG
  NDIS_GET_PACKET_TIME_SENT(
    IN PNDIS_PACKET  Packet
    );

Parameters

Packet
Pointer to a packet descriptor.

Return Value

NDIS_GET_PACKET_TIME_SENT returns the timestamp, if any, set by the miniport driver when the net packet was received on the underlying NIC.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

When a protocol driver's ProtocolReceivePacket function is called with an indication, it can use this macro to retrieve the TimeSent timestamp using the Packet pointer it is given on entry. This value was set originally by a protocol on the remote node that transmitted the packet as the TimeToSend timestamp.

A protocol driver can call NdisGetReceivedPacket followed by NDIS_GET_PACKET_TIME_SENT to obtain this timestamp from the NDIS_PACKET_OOB_DATA block associated with a packet descriptor when its ProtocolReceive function is given an indication. However, these calls are superfluous if the protocol is bound to an underlying driver that does not supply out-of-band information with its indications.

All timestamps set in the NDIS_PACKET_OOB_DATA blocks associated with packets are expressed in system time units as the number of 100-nanosecond intervals since January 1, 1601.

A highest-level protocol driver might use this macro before it forwards a received net packet to clients if its clients expect timestamps. Still higher-level drivers or system components can convert this timestamp into locale-specific values more meaningful to the end user.

Callers of NDIS_GET_PACKET_TIME_SENT run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportTimer, NdisGetCurrentSystemTime, NDIS_GET_ORIGINAL_PACKET, NdisGetReceivedPacket, NDIS_GET_PACKET_TIME_RECEIVED, NdisMIndicateReceivePacket, NDIS_OOB_DATA_FROM_PACKET, NDIS_PACKET_OOB_DATA, NDIS_SET_PACKET_TIME_SENT, ProtocolReceive, ProtocolReceivePacket


NDIS_GET_PACKET_TIME_TO_SEND

NDIS_GET_PACKET_TIME_TO_SEND returns the TimeToSend value from the out-of-band data block associated with a given packet descriptor.

ULONGLONG
  NDIS_GET_PACKET_TIME_TO_SEND(
    IN PNDIS_PACKET  Packet
    );

Parameters

Packet
Pointer to a packet descriptor.

Return Value

NDIS_GET_PACKET_TIME_TO_SEND returns the timestamp, if any, set by the protocol driver before passing the Packet in an array to NdisSendPackets or as a parameter to NdisSend.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The MiniportSendPackets or MiniportSend function of an underlying NIC driver might use NDIS_GET_PACKET_TIME_TO_SEND to determine when a given packet should be transmitted over the network.

All timestamps set in the NDIS_PACKET_OOB_DATA blocks associated with packets are expressed in system time units as the number of 100-nanosecond intervals since January 1, 1601.

Callers of NDIS_GET_PACKET_TIME_TO_SEND run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportSend, MiniportSendPackets, NdisGetCurrentSystemTime, NDIS_OOB_DATA_FROM_PACKET, NDIS_PACKET_OOB_DATA, NdisSend, NdisSendPackets, NDIS_SET_PACKET_TIME_TO_SEND, ProtocolSendComplete


NdisGetPoolFromPacket

NdisGetPoolFromPacket returns the handle to the packet pool from which a packet was allocated.

NDIS_Handle
  NdisGetPoolFromPacket(
    IN PNDIS_PACKET  Packet
    );

Parameters

Packet
Pointer to an NDIS_PACKET structure that is the descriptor for a packet.

Return Values

NdisGetPoolFromPacket returns a handle to the packet pool for the specified packet. If Packet points to an invalid packet descriptor, NdisGetPoolFromPacket returns an indeterminate value.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

After a descriptor for a send or receive packet returns to an intermediate driver at the conclusion of a data transfer, an intermediate driver can call NdisGetPoolFromPacket to retrieve the handle to the packet pool from which the packet was allocated. The intermediate driver compares the returned handle with the handle to the driver's own packet pool. If the handles are the same, the intermediate driver can reclaim the packet descriptor. If the handles are not the same, the intermediate driver cannot reclaim the packet descriptor; instead, it must allow the driver that allocated the packet descriptor to reclaim that descriptor.

System support for NdisGetPoolFromPacket is available in Windows XP and later OS versions.

Callers of NdisGetPoolFromPacket run at IRQL <= DISPATCH_LEVEL.

See Also

NdisIMGetCurrentPacketStack


NdisGetPhysicalAddressHigh

NdisGetPhysicalAddressHigh returns the high-order part of a given physical address.

ULONG
  NdisGetPhysicalAddressHigh(
    IN NDIS_PHYSICAL_ADDRESS  PhysicalAddress
    );

Parameters

PhysicalAddress
Specifies a physical address of an OS-dependent size.

Return Value

NdisGetPhysicalAddressHigh returns the value of the high-order part of the physical address.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Callers of NdisGetPhysicalAddressHigh can be running at any IRQL.

See Also

NdisGetPhysicalAddressLow, NDIS_PHYSICAL_ADDRESS, NdisSetPhysicalAddressHigh


NdisGetPhysicalAddressLow

NdisGetPhysicalAddressLow returns the low-order part of a given physical address.

ULONG
  NdisGetPhysicalAddressLow(
    IN NDIS_PHYSICAL_ADDRESS  PhysicalAddress
    );

Parameters

PhysicalAddress
Specifies a physical address of an OS-dependent size.

Return Value

NdisGetPhysicalAddressLow returns the value of the low-order part of the physical address.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Callers of NdisGetPhysicalAddressLow can run at any IRQL.

See Also

NdisGetPhysicalAddressHigh, NDIS_PHYSICAL_ADDRESS, NdisSetPhysicalAddressLow


NdisGetReceivedPacket

NdisGetReceivedPacket retrieves a packet that was received from the underlying driver.

PNDIS_PACKET
  NdisGetReceivedPacket(
    IN PNDIS_HANDLE  NdisBindingHandle,
    IN PNDIS_HANDLE  MacContext
    );

Parameters

NdisBindingHandle
Specifies the handle that was returned by NdisOpenAdapter that identifies the target NIC or the virtual adapter of the underlying driver to which the calling driver is bound.
MacContext
Specifies a context handle that the underlying driver associates with the packet received from the network. This handle was passed as an input parameter to the calling driver's ProtocolReceive function. This handle is opaque to the calling driver and reserved for use by the underlying driver that made the indication.

Return Values

Returns a pointer to a packet descriptor that contains data that was received on the underlying driver.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Several protocol or intermediate drivers can be bound to a single underlying NIC, and each such driver can receive an indication for the same packet. Such a packet is read-only to these drivers. Each such driver's ProtocolReceive function determines whether to call NdisGetReceivedPacket to retrieve the indicated packet.

Callers of NdisGetReceivedPacket run at IRQL <= DISPATCH_LEVEL.

See Also

NdisOpenAdapter


NdisGetSharedDataAlignment

NdisGetSharedDataAlignment returns the boundary value on which drivers should align data in shared memory.

ULONG
  NdisGetSharedDataAlignment(
    VOID
    );

Return Value

The boundary value, in bytes, on which drivers should align data in shared memory.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

To enhance performance, drivers should align data structures (such as packet descriptions) in shared memory on the boundary value returned by this function.

System support for NdisGetSharedDataAlignment is available in Windows XP and later OS versions.

Callers of NdisGetSharedDataAlignment run at IRQL <= DISPATCH_LEVEL.

See Also

NdisMAllocateSharedMemory


NdisGetSystemUpTime

NdisGetSystemUpTime returns the number of milliseconds that have elapsed since the system was booted.

VOID
  NdisGetSystemUpTime(
    OUT PULONG  pSystemUpTime
    );

Parameters

pSystemUpTime
Pointer to a caller-supplied variable in which this function returns the system uptime.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisGetSystemUpTime is typically called by protocol drivers.

Callers of NdisGetSystemUpTime can be running at any IRQL.

See Also

NdisGetCurrentSystemTime


NdisIMAssociateMiniport

NdisIMAssociateMiniport informs NDIS that the specified lower and upper interfaces for miniport and protocol drivers respectively belong to the same intermediate driver.

VOID
  NdisIMAssociateMiniport(
    IN NDIS_HANDLE  DriverHandle,
    IN NDIS_HANDLE  ProtocolHandle
    );

Parameters

DriverHandle
Specifies the handle to the miniport driver interface that is returned by NdisIMRegisterLayeredMiniport.
ProtocolHandle
Specifies the handle to the protocol interface that is returned by NdisRegisterProtocol.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Any NDIS intermediate driver that exports both MiniportXxx and ProtocolXxx functions calls NdisIMAssociateMiniport to inform the NDIS library about its miniport driver lower edge and its protocol upper edge. Such an intermediate driver calls NdisIMAssociateMiniport during its DriverEntry routine. Before an intermediate driver calls NdisIMAssociateMiniport to associate its miniport driver and protocol interfaces, it must first perform the following tasks:

  • Calls the NdisMInitializeWrapper function to notify NDIS that it is about to register its miniport driver lower edge.
  • Fills in an NDIS_MINIPORT_CHARCTERISTICS structure with the entry points for its MiniportXxx functions and then calls the NdisIMRegisterLayeredMiniport function to register those MiniportXxx entry points.
  • Fills in an NDIS_PROTOCOL_CHARACTERISTICS structure with the entry points for its ProtocolXxx functions and then calls the NdisRegisterProtocol function to register those ProtocolXxx entry points.

Callers of NdisIMAssociateMiniport run at IRQL PASSIVE_LEVEL.

See Also

DriverEntry of NDIS Miniport Drivers, DriverEntry of NDIS Protocol Drivers, NdisIMRegisterLayeredMiniport, NdisMInitializeWrapper, NdisRegisterProtocol


NdisIMCancelInitializeDeviceInstance

NdisIMCancelInitializeDeviceInstance cancels the immediately preceding call to NdisIMInitializeDeviceInstance.

NDIS_STATUS
  NdisIMCancelInitializeDeviceInstance(
    IN NDIS_HANDLE  DriverHandle,
    IN PNDIS_STRING  DeviceInstance
    );

Parameters

DriverHandle
Specifies the handle returned by NdisIMRegisterLayeredMiniport.
DeviceInstance
Pointer to an NDIS_STRING type that describes a caller-initialized counted string, in the system-default character set, naming the registry key in which the driver stores information about its virtual NIC and, possibly, binding-specific information. For Windows 2000 and later drivers, this string contains Unicode characters. That is, for Windows 2000 and later, NDIS defines the NDIS_STRING type as a UNICODE_STRING type.

Return Values

NdisIMCancelInitializeDeviceInstance returns NDIS_STATUS_SUCCESS if it canceled the preceding call to NdisIMInitializeDeviceInstance. Otherwise, it returns NDIS_STATUS_FAILURE if there is no way to stop the intermediate driver from initializing its virtual NIC.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

An intermediate driver calls the NdisIMInitializeDeviceInstance function to set up its virtual NIC for I/O operations on an underlying NIC driver to which the intermediate driver is bound. A call to NdisIMCancelInitializeDeviceInstance cancels this call to NdisIMInitializeDeviceInstance.

Callers of NdisIMCancelInitializeDeviceInstance run at IRQL PASSIVE_LEVEL.

See Also

ANSI_STRING, NdisIMInitializeDeviceInstance, NdisIMRegisterLayeredMiniport, UNICODE_STRING


NdisIMCopySendCompletePerPacketInfo

NdisIMCopySendCompletePerPacketInfo copies per-packet information from a packet returned up by a lower miniport driver into a new packet that is to be returned to an upper-level driver.

VOID
  NdisIMCopySendCompletePerPacketInfo(
    IN PNDIS_PACKET  DstPacket,
    IN PNDIS_PACKET  SrcPacket
    );

Parameters

DstPacket
Pointer to the destination packet descriptor in which per-packet information is to be copied.
SrcPacket
Pointer to the source packet descriptor from which per-packet information is copied.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

When an intermediate driver handles the completion of a send request from a lower miniport driver, that intermediate driver calls NdisIMCopySendCompletePerPacketInfo to copy per-packet information. The intermediate driver copies the per-packet information from a packet that was returned by the lower miniport driver into a new packet that the intermediate driver returns to an upper-level driver. The intermediate driver calls NdisIMCopySendCompletePerPacketInfo for each packet returned through the stack unless the intermediate driver must modify a packet's per-packet information.

Per-packet information is contained in an NDIS_PACKET_EXTENSION structure and includes, for example, checksum information, IP Security information, and 802.1p priority information.

If an intermediate driver must modify a packet's per-packet information, that intermediate driver should use the NDIS_PER_PACKET_INFO_FROM_PACKET macro to accesses the information. The driver can call this macro once for each type of per-packet information that it needs to access.

Drivers can also use the NDIS_PACKET_EXTENSION_FROM_PACKET macro, which returns a pointer to the NDIS_PACKET_EXTENSION structure. A driver can call this macro if it needs to access more than one type of per-packet information associated with a packet descriptor. After obtaining the pointer to the NDIS_PACKET_EXTENSION structure, the driver can use the appropriate array index to obtain a pointer to a particular type of per-packet information.

To copy a range of data from one packet to another, use the NdisCopyFromPacketToPacket function.

Callers of NdisIMCopySendCompletePerPacketInfo can be running at any IRQL.

See Also

NdisCopyFromPacketToPacket, NdisIMCopySendPerPacketInfo, NDIS_PACKET, NDIS_PACKET_EXTENSION, NDIS_PACKET_EXTENSION_FROM_PACKET, NDIS_PER_PACKET_INFO_FROM_PACKET


NdisIMCopySendPerPacketInfo

NdisIMCopySendPerPacketInfo copies per-packet information from a packet that was sent down by an upper-level driver into a new packet to be sent down to a lower miniport driver.

VOID
  NdisIMCopySendPerPacketInfo(
    IN PNDIS_PACKET  DstPacket,
    IN PNDIS_PACKET  SrcPacket
    );

Parameters

DstPacket
Pointer to the destination packet descriptor in which per-packet information is to be copied.
SrcPacket
Pointer to the source packet descriptor from which per-packet information is copied.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

When an intermediate driver forwards a send request from an upper-level driver to a lower miniport driver, that intermediate driver calls NdisIMCopySendPerPacketInfo to copy per-packet information. The intermediate driver copies the per-packet information from a packet sent down by the upper-level driver into a new packet that the intermediate driver sends down to the lower miniport driver. The intermediate driver calls NdisIMCopySendPerPacketInfo for each packet sent down through the stack unless the intermediate driver must modify a packet's per-packet information.

Per-packet information is contained in an NDIS_PACKET_EXTENSION structure and includes, for example, checksum information, IP Security information, and 802.1p priority information.

If an intermediate driver must modify a packet's per-packet information, that intermediate driver should use the NDIS_PER_PACKET_INFO_FROM_PACKET macro to accesses the information. The driver can call this macro once for each type of per-packet information that it needs to access.

Drivers can also use the NDIS_PACKET_EXTENSION_FROM_PACKET macro, which returns a pointer to the NDIS_PACKET_EXTENSION structure. A driver can call this macro if it needs to access more than one type of per-packet information associated with a packet descriptor. After obtaining the pointer to the NDIS_PACKET_EXTENSION structure, the driver can use the appropriate array index to obtain a pointer to a particular type of per-packet information.

To copy a range of data from one packet to another, use the NdisCopyFromPacketToPacket function.

Callers of NdisIMCopySendPerPacketInfo can be running at any IRQL.

See Also

NdisCopyFromPacketToPacket, NdisIMCopySendCompletePerPacketInfo, NDIS_PACKET, NDIS_PACKET_EXTENSION, NDIS_PACKET_EXTENSION_FROM_PACKET, NDIS_PER_PACKET_INFO_FROM_PACKET


NdisIMDeInitializeDeviceInstance

NdisIMDeInitializeDeviceInstance calls an NDIS intermediate driver's MiniportHalt function to tear down the driver's virtual NIC.

NDIS_STATUS
  NdisIMDeInitializeDeviceInstance(
    IN NDIS_HANDLE  NdisMiniportHandle
    );

Parameters

NdisMiniportHandle
Specifies the handle originally input to MiniportInitialize.

Return Value

NdisIMDeInitializeDeviceInstance returns NDIS_STATUS_SUCCESS if the NIC has been torn down. Otherwise, it can return NDIS_STATUS_FAILURE if the given NdisMiniportHandle is invalid.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

For NDIS intermediate drivers, NdisIMDeInitializeDeviceInstance is the reciprocal of NdisIMInitializeDeviceInstance(Ex). Such a driver usually calls NdisIMDeInitializeDeviceInstance(Ex) from its ProtocolUnbindAdapter function, when the underlying NIC to which it was bound is being removed from the system, possibly because it is being reconfigured.

The call to NdisIMDeInitializeDeviceInstance causes a call to the intermediate driver's MiniportHalt function after NDIS has told all higher level protocols that had bound themselves to the intermediate's virtual NIC that they must unbind.

Callers of NdisIMDeInitializeDevice instance run at IRQL PASSIVE_LEVEL.

See Also

MiniportHalt, NdisIMInitializeDeviceInstance, NdisIMInitializeDeviceInstanceEx, ProtocolUnbindAdapter


NdisIMDeregisterLayeredMiniport

NdisIMDeregisterLayeredMiniport releases a previously registered intermediate driver.

VOID
  NdisIMDeregisterLayeredMiniport(
    IN NDIS_HANDLE  DriverHandle
    );

Parameters

DriverHandle
Specifies the handle returned by NdisIMRegisterLayeredMiniport.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

An intermediate driver that called NdisIMRegisterLayeredMiniport from its DriverEntry routine must call NdisIMDeregisterLayeredMiniport when it cleans up the resources it allocated before it is unloaded. If the intermediate driver encounters a fatal initialization error within its DriverEntry routine, such as an inability to obtain system resources, it must call NdisMDeregisterLayeredMiniport.

The NdisIMDeregisterLayeredMiniport function is the reciprocal of NdisIMRegisterLayeredMiniport. An intermediate driver typically calls NdisIMDeregisterLayeredMiniport from its ProtocolUnbindAdapter function after calling NdisDeregisterProtocol.

Callers of NdisIMDeregisterLayeredMiniport run at IRQL PASSIVE_LEVEL.

See Also

NdisDeregisterProtocol

NdisIMRegisterLayeredMiniport


NdisIMGetBindingContext

NdisIMGetBindingContext allows an NDIS protocol to access the device context area, created by an underlying intermediate driver, for a virtual NIC to which the higher level protocol is bound.

NDIS_HANDLE
  NdisIMGetBindingContext(
    IN NDIS_HANDLE  NdisBindingHandle
    );

Parameters

NdisBindingHandle
Specifies the handle returned by NdisOpenAdapter that identifies the virtual NIC of the next lower intermediate driver to which the caller is bound.

Return Value

NdisIMGetBindingContext returns access to the device context area for the given virtual NIC, or it returns NULL if no such context area exists.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A highest level NDIS protocol driver or intermediate protocol can call NdisIMGetBindingContext from its ProtocolBindAdapter function to access the device context for a virtual NIC to which it is bound. The device context provides a common context area for all higher level protocols bound to the same underlying intermediate driver.

Such a device context area was allocated and defined by the lower level NDIS intermediate driver and passed to NDIS in a call to NdisIMInitializeDeviceInstanceEx. This intermediate driver's MiniportInitialize function calls NdisIMGetDeviceContext to gain access this device context area if it was allocated by the intermediate driver's ProtocolBindAdapter function.

All protocols that call NdisIMGetBindingContext can safely assume that the underlying intermediate driver allocated its context area from nonpaged pool. They should treat the returned context area as read-only, preserving the state set up by the underlying NDIS intermediate driver that defined it.

Callers of NdisIMGetBindingContext must be running at IRQL < DISPATCH_LEVEL.

See Also

NdisIMInitializeDeviceInstanceEx, NdisIMGetDeviceContext, ProtocolBindAdapter


NdisIMGetCurrentPacketStack

NdisIMGetCurrentPacketStack returns a pointer to an NDIS_PACKET_STACK structure that is a descriptor for the current stack in a packet. NdisIMGetCurrentPacketStack also indicates whether one or more stack locations are available in the packet.

PNDIS_PACKET_STACK
  NdisIMGetCurrentPacketStack(
    IN PNDIS_PACKET  Packet
    OUT BOOLEAN  *StacksRemaining
    );

Parameters

Packet
Pointer to an NDIS_PACKET structure that is the descriptor for a packet.
StacksRemaining
Pointer to a caller-supplied variable in which NDIS returns TRUE to indicate that one or more stack locations are available in the packet or FALSE to indicate that the number of stack locations is zero or that the maximum number of stack locations has been exceeded. The intermediate driver can reuse this packet in a call to NdisSendPackets or NdisCoSendPackets only if the value returned is TRUE.

Return Value

NdisIMGetCurrentPacketStack returns a pointer to an NDIS_PACKET_STACK structure that is a descriptor for the current stack in a packet. The NDIS_PACKET_STACK structure is defined as follows:

typedef struct _NDIS_PACKET_STACK
{
    ULONG_PTR   IMReserved[2];
    ULONG_PTR   NdisReserved[4];
} NDIS_PACKET_STACK, *PNDIS_PACKET_STACK;

The members of this structure contain the following information:

IMReserved
An array of two pointers that the caller of NdisIMGetCurrentPacketStack can use.
NdisReserved
An array of pointers that NDIS uses.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

By default, each NDIS packet contains two NDIS_PACKET_STACK structures. After calling NdisIMGetCurrentPacketStack to obtain a pointer to an NDIS_PACKET_STACK structure, an intermediate driver can store or retrieve driver-defined information at the locations referenced by the pointers in the IMReserved array. This capability allows the intermediate driver to "reuse" a packet--that is, pass the packet to the adjacent driver without having to allocate an additional packet into which the intermediate driver copies the original packet. An intermediate driver typically calls NdisIMGetCurrentPacketStack in the context of its send and receive functions.

NDIS modifies the stack pointer as the packet traverses through each intermediate driver. If all stack locations for intermediate drivers are in use in the packet, NdisIMGetCurrentPacketStack returns NULL and, in StacksRemaining, FALSE.

If NdisIMGetCurrentPacketStack returns FALSE in StacksRemaining, the intermediate driver must allocate a packet pool and a packet descriptor and copy the original packet into the newly allocated packet before passing the packet to another driver. NdisIMGetCurrentPacketStack returns FALSE in StacksRemaining if the number of intermediate drivers that the packet traverses through exceeds the number of configured stacks. Note that the number of stacks in a packet cannot be dynamically altered.

System support for NdisIMGetCurrentPacketStack is available in Windows XP and later OS versions.

Callers of NdisIMGetCurrentPacketStack run at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocatePacket, NdisAllocatePacketPool, NdisAllocatePacketPoolEx, NdisGetPoolFromPacket


NdisIMGetDeviceContext

NdisIMGetDeviceContext allows an NDIS intermediate driver's MiniportInitialize function to access the device context area allocated by its ProtocolBindAdapter function.

NDIS_HANDLE
  NdisIMGetDeviceContext(
    IN NDIS_HANDLE  MiniportAdapterHandle
    );

Parameters

MiniportAdapterHandle
Specifies the handle input to MiniportInitialize.

Return Value

NdisIMGetDeviceContext returns access to the device context area for the virtual NIC identified by MiniportAdapterHandle, or it returns NULL if the driver's ProtocolBindAdapter function did not allocate such a device context area.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

An NDIS intermediate driver's MiniportInitialize function calls NdisIMGetDeviceContext to access the device context area for the virtual NIC it is initializing. Usually, the memory for such an area is provided by the intermediate driver's ProtocolBindAdapter function, which calls NdisIMInitializeDeviceInstanceEx with a pointer to this area, thereby causing the driver's MiniportInitialize function to be called. However, an intermediate driver is not required to have such a context area.

On return from NdisIMGetDeviceContext, MiniportInitialize sets up the driver-defined state for the virtual NIC with whatever information the intermediate driver writer intends to be useful to still higher level protocols that bind themselves subsequently to its virtual NIC.

Still higher level NDIS protocols bound to the same virtual NIC subsequently can access this device context area by calling NdisIMGetBindingContext from their ProtocolBindAdapter functions.

Callers of NdisIMGetDeviceContext can be running at IRQL <= DISPATCH_LEVEL. Typically, NDIS calls MiniportInitialize functions at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisIMGetBindingContext, NdisIMInitializeDeviceInstanceEx


NdisIMInitializeDeviceInstance

NdisIMInitializeDeviceInstance calls an NDIS intermediate driver's MiniportInitialize function to set up the driver's virtual NIC for I/O operations on an underlying NIC driver to which the intermediate driver is bound.

NDIS_STATUS
  NdisIMInitializeDeviceInstance(
    IN NDIS_HANDLE  DriverHandle,
    IN PNDIS_STRING  DeviceInstance
    );

Parameters

DriverHandle
Specifies the handle returned by NdisIMRegisterLayeredMiniport.
DeviceInstance
Pointer to an NDIS_STRING type that describes a caller-initialized counted string, in the system-default character set, naming the registry key in which the driver stores information about its virtual NIC and, possibly, binding-specific information. For Windows 2000 and later drivers, this string contains Unicode characters. That is, for Windows 2000 and later, NDIS defines the NDIS_STRING type as a UNICODE_STRING type.

Return Values

NdisIMInitializeDeviceInstanceEx can return either of the following:

NDIS_STATUS_SUCCESS
The intermediate driver's virtual NIC was successfully initialized.
NDIS_STATUS_NOT_ACCEPTED
NdisIMInitializeDeviceInstanceEx failed because the device specified by DriverHandle has already been initialized.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

An NDIS intermediate driver usually calls NdisIMInitializeDeviceInstance or NdisIMInitializeDeviceInstanceEx from its ProtocolBindAdapter function.

The driver's installation script created the key designated by DeviceInstance in the configuration registry tree.

Before it calls NdisIMInitializeDeviceInstance, ProtocolBindAdapter must make a successful call to NdisOpenAdapter, thereby binding the intermediate driver to the underlying NIC driver. Then, its subsequent call to NdisIMInitializeDeviceInstance allows the driver's MiniportInitialize function to allocate any resources the driver needs to carry out network I/O operations and to initialize the driver's virtual NIC, to which higher-level protocol drivers can bind themselves when the NDIS intermediate driver's initialization is complete.

Callers of NdisIMInitializeDeviceInstance run at IRQL PASSIVE_LEVEL.

See Also

ANSI_STRING, MiniportInitialize, NdisIMDeInitializeDeviceInstance, NdisIMInitializeDeviceInstanceEx, NdisIMRegisterLayeredMiniport, NdisInitializeString, NdisOpenAdapter, ProtocolBindAdapter, UNICODE_STRING


NdisIMInitializeDeviceInstanceEx

NdisIMInitializeDeviceInstanceEx calls an NDIS intermediate driver's MiniportInitialize function to initialize the driver's virtual NIC and optionally to set up state information about the driver's virtual NIC for subsequently bound protocols.

NDIS_STATUS
  NdisIMInitializeDeviceInstanceEx(
    IN NDIS_HANDLE  DriverHandle,
    IN PNDIS_STRING  DriverInstance,
    IN NDIS_HANDLE  DeviceContext  OPTIONAL
    );

Parameters

DriverHandle
Specifies the handle returned by NdisIMRegisterLayeredMiniport.
DriverInstance
Pointer to an NDIS_STRING type that describes a caller-initialized counted string, in the system-default character set, naming the registry key in which the driver stores information about its virtual NIC and, possibly, binding-specific information. For Windows 2000 and later drivers, this string contains Unicode characters. That is, for Windows 2000 and later, NDIS defines the NDIS_STRING type as a UNICODE_STRING type.

The intermediate driver's installation script created its key designated by DeviceInstance in the HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services registry tree.

DeviceContext
Pointer to caller-supplied memory to be set up with driver-defined device context information about the virtual NIC, which still higher level protocols that subsequently bind themselves to this virtual NIC can use. This parameter can be NULL if the intermediate driver has no such device context area.

Return Values

NdisIMInitializeDeviceInstanceEx can return either of the following:

NDIS_STATUS_SUCCESS
The intermediate driver's virtual NIC was successfully initialized.
NDIS_STATUS_NOT_ACCEPTED
NdisIMInitializeDeviceInstanceEx failed because the device specified by DriverHandle has already been initialized.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

An NDIS intermediate driver should call NdisIMInitializeDeviceInstanceEx from its ProtocolBindAdapter function, thereby controlling when NDIS calls the driver's MiniportInitialize function to set up the driver's virtual NIC. A failure to call NdisIMInitializeDeviceInstanceEx or NdisIMInitializeDeviceInstance from an NDIS intermediate driver effectively prevents that driver from loading itself successfully. Such a driver cannot make its virtual NIC operational for still higher level protocols unless its MiniportInitialize function runs.

Before it calls NdisIMInitializeDeviceInstanceEx, the intermediate driver's ProtocolBindAdapter function must make a successful call to NdisOpenAdapter, thereby binding the intermediate driver as a protocol to the underlying miniport driver. The ProtocolBindAdapter function can allocate an area at DeviceContext as well, possibly setting it up with intermediate driver-determined information about the capabilities of the underlying NIC, collected by ProtocolBindAdapter. The intermediate driver's MiniportInitialize function might use such information subsequently to set up this context area with information about the driver's virtual NIC.

After its successful call to NdisOpenAdapter, the intermediate driver's subsequent call to NdisIMInitializeDeviceInstanceEx causes NDIS to call the intermediate driver's MiniportInitialize function. MiniportInitialize allocates any resources the driver needs to carry out network I/O operations, such as calling NdisMSetAttributesEx, and to initialize the driver's virtual NIC to an operational state. Then, still higher level protocols can bind themselves to its virtual NIC when the intermediate driver's initialization is completed successfully. The intermediate driver's MiniportInitialize function can call NdisIMGetDeviceContext to gain access to the area at DeviceContext if such an area is provided by its ProtocolBindAdapter function.

After MiniportInitialize returns control, the intermediate driver's device context area, if any, can contain any intermediate-driver-defined data that subsequently allows all higher level protocols bound to the same virtual NIC to access information in that context area. Such a higher level protocol can query the intermediate-driver-supplied device context with NdisIMGetBindingContext.

Callers of NdisIMInitializeDeviceInstanceEx run at IRQL < DISPATCH_LEVEL.

See Also

ANSI_STRING, MiniportInitialize, NdisAllocateMemory, NdisIMDeInitializeDeviceInstance, NdisIMGetBindingContext, NdisIMGetDeviceContext, NdisIMInitializeDeviceInstance, NdisIMRegisterLayeredMiniport, NdisInitializeString, NdisMSetAttributesEx, NdisOpenAdapter, ProtocolBindAdapter, UNICODE_STRING


NdisImmediateReadPciSlotInformation

This function is obsolete for Windows XP and later. Windows XP supports this function for legacy drivers; however, the Windows XP DDK will not build an NDIS driver that calls this function.

NdisImmediateReadPciSlotInformation returns a specified range of PCI configuration information in a caller-supplied buffer.

ULONG
  NdisImmediateReadPciSlotInformation(
    IN NDIS_HANDLE  WrapperConfigurationContext,
    IN ULONG  SlotNumber,
    IN ULONG  Offset,
    IN PVOID  Buffer,
    IN ULONG  Length
    );

Parameters

WrapperConfigurationContext
Specifies the handle passed to the caller's MiniportInitialize function.
SlotNumber
Reserved. NDIS ignores this paramter.
Offset
Specifies the byte offset within the PCI configuration space at which to begin transferring the configuration information.
Buffer
Pointer to a caller-allocated buffer in which to return the requested configuration information.
Length
Specifies the size in bytes of the buffer at Buffer and, therefore, how many bytes of configuration information to return.

Return Value

NdisImmediateReadPciSlotInformation returns the number of bytes it wrote at Buffer.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisImmediateReadPciSlotInformation helps a miniport driver find a NIC that it supports on a PCI bus, possibly before MiniportInitialize calls the Ndis Xxx Configuration functions to get configuration information stored in the registry. This function cannot be called after the driver has claimed hardware resources in the registry for its NIC with NdisQueryAdapterResources or NdisMPciAssignResources.

NdisImmediateReadPciSlotInformation returns the same bus-relative PCI configuration information as NdisReadPciSlotInformation. However, callers of NdisReadPciSlotInformation pass the adapter handle, rather than the WrapperConfigurationContext handle that is valid only during NIC driver initialization.

Callers of NdisImmediateReadPciSlotInformation can run at IRQL <= DISPATCH_LEVEL. Usually, callers are running at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisMPciAssignResources, NdisMQueryAdapter Resources NdisOpenConfiguration, NdisReadPciSlotInformation


NdisImmediateReadPortUchar

This function is obsolete for Windows XP and later. Windows XP supports this function for legacy drivers; however, the Windows XP DDK will not build an NDIS driver that calls this function.

NdisImmediateReadPortUchar reads a byte from a given bus-relative I/O port.

VOID
  NdisImmediateReadPortUchar(
    IN NDIS_HANDLE  WrapperConfigurationContext,
    IN ULONG  Port,
    OUT PUCHAR  Data
    );

Parameters

WrapperConfigurationContext
Specifies the handle input to MiniportInitialize.
Port
Specifies the bus-relative I/O port address.
Data
Pointer to a caller-supplied variable in which this function returns the value read from the I/O port.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisImmediateReadPortUchar determines how the host accesses the given I/O port, maps the bus-relative port address, and then reads a byte from the device.

A miniport driver can call NdisImmediateReadPortUchar during initialization to read data from a device I/O port when that driver has not yet called NdisMRegisterIoPortRange to obtain mapped device memory ranges. After its call to NdisMRegisterIoPortRange, the driver uses the faster NdisRaw Xxx functions to communicate with its NIC.

A miniport driver should not call NdisImmediateReadPortUchar in a Plug and Play environment.

Callers of NdisImmediateReadPortUchar run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisImmediateReadPortUlong, NdisImmediateReadPortUshort, NdisImmediateWritePortUchar, NdisMRegisterIoPortRange, NdisRawReadPortUchar


NdisImmediateReadPortUlong

This function is obsolete for Windows XP and later. Windows XP supports this function for legacy drivers; however, the Windows XP DDK will not build an NDIS driver that calls this function.

NdisImmediateReadPortUlong reads a ULONG from a given bus-relative I/O port.

VOID
  NdisImmediateReadPortUlong(
    IN NDIS_HANDLE  WrapperConfigurationContext,
    IN ULONG  Port,
    OUT PULONG  Data
    );

Parameters

WrapperConfigurationContext
Specifies the handle input to MiniportInitialize.
Port
Specifies the bus-relative I/O port address.
Data
Pointer to a caller-supplied variable in which this function returns the value read from the I/O port.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisImmediateReadPortUlong determines how the host accesses the given I/O port, maps the bus-relative port address, and then reads a ULONG-type value from the device.

A miniport driver can call NdisImmediateReadPortUlong during initialization to read data from a device I/O port when that driver has not yet called NdisMRegisterIoPortRange to obtain mapped device memory ranges. After its call to NdisMRegisterIoPortRange, the driver uses the faster NdisRaw Xxx functions to communicate with its NIC.

A miniport driver should not call NdisImmediateReadPortUlong in a Plug and Play environment.

Callers of NdisImmediateReadPortUlong run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisImmediateReadPortUchar, NdisImmediateReadPortUshort, NdisImmediateWritePortUlong, NdisMRegisterIoPortRange, NdisRawReadPortUlong


NdisImmediateReadPortUshort

This function is obsolete for Windows XP and later. Windows XP supports this function for legacy drivers; however, the Windows XP DDK will not build an NDIS driver that calls this function.

NdisImmediateReadPortUshort reads a USHORT from a given bus-relative I/O port.

VOID
  NdisImmediateReadPortUshort(
    IN NDIS_HANDLE  WrapperConfigurationContext,
    IN ULONG  Port,
    OUT PUSHORT  Data
    );

Parameters

WrapperConfigurationContext
Specifies the handle input to MiniportInitialize.
Port
Specifies the bus-relative I/O port address.
Data
Pointer to a caller-supplied variable in which this function returns the value read from the I/O port.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisImmediateReadPortUshort determines how the host accesses the given I/O port, maps the bus-relative port address, and then reads a USHORT-type value from the device.

A miniport driver can call NdisImmediateReadPortUshort during initialization to read data from a device I/O port when that driver has not yet called NdisMRegisterIoPortRange to obtain mapped device memory ranges. After its call to NdisMRegisterIoPortRange, the driver uses the faster NdisRaw Xxx functions to communicate with its NIC.

A miniport driver should not call NdisImmediateReadPortUshort in a Plug and Play environment.

Callers of NdisImmediateReadPortUshort run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisImmediateReadPortUchar, NdisImmediateReadPortUlong, NdisImmediateWritePortUshort, NdisMRegisterIoPortRange, NdisRawReadPortUshort


NdisImmediateReadSharedMemory

This function is obsolete for Windows XP and later. Windows XP supports this function for legacy drivers; however, the Windows XP DDK will not build an NDIS driver that calls this function.

NdisImmediateReadSharedMemory reads a specified number of bytes from shared device RAM.

VOID
  NdisImmediateReadSharedMemory(
    IN NDIS_HANDLE  WrapperConfigurationContext,
    IN ULONG  SharedMemoryAddress,
    IN OUT PUCHAR  Buffer,
    IN ULONG  Length
    );

Parameters

WrapperConfigurationContext
Specifies the handle passed to MiniportInitialize.
SharedMemoryAddress
Specifies the bus-relative base address of the shared device memory range.
Buffer
Pointer to a caller-allocated buffer in which this function returns the data read from the device memory range starting at SharedMemoryAddress.
Length
Specifies the size in bytes of the buffer at Buffer and, therefore, how many bytes of data to return.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisImmediateReadSharedMemory determines how the host accesses shared device memory, maps the bus-relative base address, and then copies Length bytes of data from the device memory area into the given buffer.

A miniport driver can call NdisImmediateReadSharedMemory during initialization to read data from a range of device memory when that driver has not yet called NdisMMapIoSpace to obtain mapped virtual addresses for the bus-relative device memory range. After its call to NdisMMapIoSpace, the driver uses the returned mapped virtual addresses in PIO operations.

Miniports should not call NdisImmediateReadSharedMemory in a Plug and Play environment.

Callers of NdisImmediateReadSharedMemory run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisImmediateWriteSharedMemory, NdisMMapIoSpace


NdisImmediateWritePciSlotInformation

This function is obsolete for Windows XP and later. Windows XP supports this function for legacy drivers; however, the Windows XP DDK will not build an NDIS driver that calls this function.

NdisImmediateWritePciSlotInformation writes PCI configuration information from a caller-supplied buffer to a specified range in the PCI configuration space for the NIC.

ULONG
  NdisImmediateWritePciSlotInformation(
    IN NDIS_HANDLE  WrapperConfigurationContext,
    IN ULONG  SlotNumber,
    IN ULONG  Offset,
    IN PVOID  Buffer,
    IN ULONG  Length
    );

Parameters

WrapperConfigurationContext
Specifies the handle passed to the caller's MiniportInitialize function.
SlotNumber
Reserved. NDIS ignores this parameter.
Offset
Specifies the byte offset within the PCI configuration space at which to begin transferring the caller-supplied configuration information.
Buffer
Pointer to a caller-allocated buffer containing the PCI configuration information to be written.
Length
Specifies the size in bytes of the buffer at Buffer and, therefore, how many bytes of PCI configuration information to write.

Return Value

NdisImmediateWritePciSlotInformation returns the number of bytes written.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisImmediateWritePciSlotInformation writes PCI configuration information for a NIC. However, drivers of NICs on PCI buses call NdisImmediateReadPciSlotInformation, NdisReadPciSlotInformation, or NdisMPciAssignResources far more frequently than this function. NdisImmediateWritePciSlotInformation cannot be called after the driver has claimed hardware resources in the registery for its NIC with NdisMQueryAdapterResources or NdisMPciAssignResources.

NdisImmediateWritePciSlotInformation transfers the same type of bus-relative PCI configuration information as NdisWritePciSlotInformation. However, callers of NdisWritePciSlotInformation pass the adapter handle, rather than the WrapperConfigurationContext handle that is valid only during NIC driver initialization.

Callers of NdisImmediateWritePciSlotInformation can run at IRQL <= DISPATCH_LEVEL. Usually, callers are running at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisImmediateReadPciSlotInformation, NdisMPciAssignResources, NdisMQueryAdapterResources NdisWritePciSlotInformation


NdisImmediateWritePortUchar

This function is obsolete for Windows XP and later operating systems. Windows XP supports this function for legacy drivers; however, the Windows XP DDK will not build an NDIS driver that calls this function.

NdisImmediateWritePortUchar writes a byte to a given bus-relative I/O port.

VOID
  NdisImmediateWritePortUchar(
    IN NDIS_HANDLE  WrapperConfigurationContext,
    IN ULONG  Port,
    IN UCHAR  Data
    );

Parameters

WrapperConfigurationContext
Specifies the handle input to MiniportInitialize.
Port
Specifies the bus-relative I/O port address.
Data
Specifies the caller-supplied byte value to write to the I/O port.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisImmediateWritePortUchar determines how the host accesses the given I/O port, maps the bus-relative port address, and then writes the given byte to the device.

A miniport driver can call NdisImmediateWritePortUchar during initialization to write data to a device I/O port when that driver has not yet called NdisMRegisterIoPortRange to obtain mapped device memory ranges. After its call to NdisMRegisterIoPortRange, the driver uses the faster NdisRaw Xxx functions to communicate with its NIC.

A miniport driver should not call NdisImmediateWritePortUchar in a Plug and Play environment.

Callers of NdisImmediateWritePortUchar run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisImmediateReadPortUchar, NdisImmediateWritePortUlong, NdisImmediateWritePortUshort, NdisMRegisterIoPortRange, NdisRawWritePortUchar


NdisImmediateWritePortUlong

This function is obsolete for Windows XP and later operating systems. Windows XP supports this function for legacy drivers; however, the Windows XP DDK will not build an NDIS driver that calls this function.

NdisImmediateWritePortUlong writes a ULONG to a given bus-relative I/O port.

VOID
  NdisImmediateWritePortUlong(
    IN NDIS_HANDLE  WrapperConfigurationContext,
    IN ULONG  Port,
    IN ULONG  Data
    );

Parameters

WrapperConfigurationContext
Specifies the handle input to MiniportInitialize.
Port
Specifies the bus-relative I/O port address.
Data
Specifies the caller-supplied ULONG value to write to the I/O port.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisImmediateWritePortUlong determines how the host accesses the given I/O port, maps the bus-relative port address, and then writes the given ULONG to the device.

A miniport driver can call NdisImmediateWritePortUlong during initialization to write data to a device I/O port when that driver has not yet called NdisMRegisterIoPortRange to obtain mapped device memory ranges. After its call to NdisMRegisterIoPortRange, the driver uses the faster NdisRaw Xxx functions to communicate with its NIC.

A miniport driver should not call NdisImmediateWritePortUlong in a Plug and Play environment.

Callers of NdisImmediateWritePortUlong run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisImmediateReadPortUlong, NdisImmediateWritePortUchar, NdisImmediateWritePortUshort, NdisMRegisterIoPortRange, NdisRawWritePortUlong


NdisImmediateWritePortUshort

This function is obsolete for Windows XP and later operating systems. Windows XP supports this function for legacy drivers; however, the Windows XP DDK will not build an NDIS driver that calls this function.

NdisImmediateWritePortUshort writes a USHORT to a given bus-relative I/O port.

VOID
  NdisImmediateWritePortUshort(
    IN NDIS_HANDLE  WrapperConfigurationContext,
    IN ULONG  Port,
    IN USHORT  Data
    );

Parameters

WrapperConfigurationContext
Specifies the handle input to MiniportInitialize.
Port
Specifies the bus-relative I/O port address.
Data
Specifies the caller-supplied USHORT value to write to the I/O port.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisImmediateWritePortUshort determines how the host accesses the given I/O port, maps the bus-relative port address, and then writes the given USHORT to the device.

A miniport driver can call NdisImmediateWritePortUshort during initialization to write data to a device I/O port when that driver has not yet called NdisMRegisterIoPortRange to obtain mapped device memory ranges. After its call to NdisMRegisterIoPortRange, the driver uses the faster NdisRaw Xxx functions to communicate with its NIC.

A miniport driver should not call NdisImmediateWritePortUshort in a Plug and Play environment.

Callers of NdisImmediateWritePortUshort run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisImmediateReadPortUshort, NdisImmediateWritePortUchar, NdisImmediateWritePortUlong, NdisMRegisterIoPortRange, NdisRawWritePortUshort


NdisImmediateWriteSharedMemory

This function is obsolete for Windows XP and later operating systems. Windows XP supports this function for legacy drivers; however, the Windows XP DDK will not build an NDIS driver that calls this function.

NdisImmediateWriteSharedMemory writes a specified number of bytes from a caller-supplied buffer to shared device RAM.

VOID
  NdisImmediateWriteSharedMemory(
    IN NDIS_HANDLE  WrapperConfigurationContext,
    IN ULONG  SharedMemoryAddress,
    IN PUCHAR  Buffer,
    IN ULONG  Length
    );

Parameters

WrapperConfigurationContext
Specifies the handle passed to MiniportInitialize.
SharedMemoryAddress
Specifies the bus-relative base address of the shared device memory range.
Buffer
Pointer to a caller-allocated buffer containing the data to be written to the device memory range starting at SharedMemoryAddress.
Length
Specifies the size in bytes of the buffer at Buffer and, therefore, how many bytes of data to transfer to device RAM.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisImmediateWriteSharedMemory determines how the host accesses shared device memory, maps the bus-relative base address, and then copies Length bytes of data from the given buffer to the device memory area.

A miniport driver can call NdisImmediateWriteSharedMemory during initialization to transfer data to a range of device memory when that driver has not yet called NdisMMapIoSpace to obtain mapped virtual addresses for the bus-relative device memory range. After its call to NdisMMapIoSpace, the driver uses the returned mapped virtual addresses in PIO operations.

Miniport drivers should not call NdisImmediateWriteSharedMemory in a Plug and Play environment.

Callers of NdisImmediateWriteSharedMemory run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisImmediateReadSharedMemory, NdisMMapIoSpace


NdisIMNotifyPnPEvent

NdisIMNotifyPnPEvent propagates notification of a Plug and Play or Power Management event to an overlying driver.

NDIS_STATUS
  NdisIMNotifyPnPEvent(
    IN  NDIS_HANDLE  MiniportHandle,
    IN  PNET_PNP_EVENT  NetPnPEvent
    );

Parameters

MiniportHandle
The handle input to MiniportInitialize. This handle represents the miniport driver affected by the Plug and Play or Power Management event passed to the caller's ProtocolPnPEvent function.
NetPnPEvent
Pointer to a NET_PNP_EVENT structure, which describes the Plug and Play event or Power Management event being indicated to the protocol driver.

Return Value

NdisIMNotifyPnPEvent can return either of the following:

NDIS_STATUS_SUCCESS
The overlying driver succeeded propagated Plug and Play event was succeeded.
NDIS_STATUS_FAILURE
The overlying driver failed the propagated Plug and Play event.
The return value is significant only when the propagated event is a NetEventQueryPower or a NetEventQueryRemove. For all other propagated events, the return value is always NDIS_STATUS_SUCCESS.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

An NDIS intermediate driver calls NdisIMNotifyPnPEvent in the context of the driver's ProtocolPnPEvent function to propagate notification of a Plug and Play or Power Management event to the overlying driver.

If the propagated event is a NetEventQueryPower or a NetEventQueryRemove, the intermediate driver must check the NDIS_STATUS value returned by NdisIMNotifyPnPEvent. If the returned status is NDIS_STATUS_SUCCESS, the intermediate driver should handle the event internally as usual and then return NDIS_STATUS_SUCCESS from its ProtocolPnPEvent function. If the returned status is NDIS_STATUS_FAILURE, the intermediate driver should return NDIS_STATUS_FAILURE from its ProtocolPnPEvent without further processing.

For all other propagated events, NdisIMNotifyPnPEvent always returns NDIS_STATUS_SUCCESS. The intermediate driver's ProtocolPnPEvent function in such cases should propagate the NDIS_STATUS returned by NdisIMNotifyPnPEvent.

How the intermediate driver processes a NetEventSetPower received by its ProtocolPnPEvent function depends on the specified device power state. If the specified device power state is NdisDeviceStateD0, the intermediate driver should handle the event internally as usual and then call NdisIMNotifyPnPEvent. For any other specified device power state, the intermediate driver should first call NdisIMNotifyPnPEvent and then handle the event internally as usual.

An intermediate driver should call NdisIMNotifyPnPEvent to propagate a NetEventReconfigure only if the NetEventReconfigure is indicated on a nonNULL ProtocolBindingContext. If a NetEventReconfigure is indicated on a NULL ProtocolBindingContext, the intermediate driver should not call NdisIMNotifyPnPEvent to propagate the event.

System support for NdisQueryPendingIoCount is available in Windows XP and later OS versions.

System support for NdisIMNotifyPnPEvent is available in Windows XP and later OS versions.

Callers of NdisIMNotifyPnPEvent run at IRQL PASSIVE_LEVEL.

See Also

NET_PNP_EVENT, ProtocolPnPEvent


NdisIMRegisterLayeredMiniport

NdisIMRegisterLayeredMiniport registers an intermediate driver's MiniportXxx entry points and name with the NDIS library when the driver initializes.

NDIS_STATUS
  NdisIMRegisterLayeredMiniport(
    IN NDIS_HANDLE  NdisWrapperHandle,
    IN PNDIS_MINIPORT_CHARACTERISTICS  MiniportCharacteristics,
    IN UINT  CharacteristicsLength,
    OUT PNDIS_HANDLE  DriverHandle
    );

Parameters

NdisWrapperHandle
Specifies the handle returned by NdisMInitializeWrapper.
MiniportCharacteristics
Pointer to an NDISXX_MINIPORT_CHARACTERISTICS structure set up by the caller. The structure at MiniportCharacteristics is defined as follows:
typedef struct _NDIS_MINIPORT_CHARACTERISTICS {
    UCHAR MajorNdisVersion;
    UCHAR MinorNdisVersion;
    UINT Reserved;
    W_CHECK_FOR_HANG_HANDLER CheckForHangHandler;
    W_DISABLE_INTERRUPT_HANDLER DisableInterruptHandler;
    W_ENABLE_INTERRUPT_HANDLER  EnableInterruptHandler;
    W_HALT_HANDLER HaltHandler;
    W_HANDLE_INTERRUPT_HANDLER  HandleInterruptHandler;
    W_INITIALIZE_HANDLER InitializeHandler;
    W_ISR_HANDLER ISRHandler;
    W_QUERY_INFORMATION_HANDLER QueryInformationHandler;
    W_RECONFIGURE_HANDLER ReconfigureHandler;
    W_RESET_HANDLER ResetHandler;
    W_SEND_HANDLER SendHandler;
    W_SET_INFORMATION_HANDLER SetInformationHandler;
    W_TRANSFER_DATA_HANDLER TransferDataHandler;
//
// Version used is V4.0 or V5.0
// with following members
//
    W_RETURN_PACKET_HANDLER ReturnPacketHandler;
    W_SEND_PACKETS_HANDLER SendPacketsHandler;
    W_ALLOCATE_COMPLETE_HANDLER AllocateCompleteHandler;
//
// Version used is V5.0 with the following members
//
    W_CO_CREATE_VC_HANDLER CoCreateVcHandler;
    W_CO_DELETE_VC_HANDLER CoDeleteVcHandler;
    W_CO_ACTIVATE_VC_HANDLER CoActivateVcHandler;
    W_CO_DEACTIVATE_VC_HANDLER CoDeactivateVcHandler;
    W_CO_SEND_PACKETS_HANDLER CoSendPacketsHandler;
    W_CO_REQUEST_HANDLER CoRequestHandler;
//
// Version used is V5.1 with the following members
//
    W_CANCEL_SEND_PACKETS_HANDLER CancelSendPacketsHandler;
    W_MINIPORT_SHUTDOWN_HANDLER AdapterShutdownHandler;
    W_MINIPORT_PNPEVENTNOTIFY_HANDLER AdapterShutdownHandler;
} NDIS_MINIPORT_CHARACTERISTICS, *PNDIS_MINIPORT_CHARACTERISTICS;

An NDIS intermediate driver should initialize this structure with zeros before setting up any of the following members:

MajorNdisVersion
Specifies the major version of the NDIS library the driver is using. The current value is 0x05, although the NDIS library continues to support existing miniport drivers developed for NDIS V4.0.
MinorNdisVersion
Specifies the minor version of the NDIS library the driver is using. The current value is 0x00, although NDIS continues to support existing drivers.
Reserved
This member is reserved for system use.
CheckForHangHandler
Specifies the entry point of the caller's MiniportCheckForHang function, if any, or NULL.
DisableInterruptHandler
Specifies NULL.
EnableInterruptHandler
Specifies NULL.
HaltHandler
Specifies the entry point of the caller's MiniportHalt function.
HandleInterruptHandler
Specifies NULL.
InitializeHandler
Specifies the entry point of the caller's MiniportInitialize function.
ISRHandler
Specifies NULL.
QueryInformationHandler
Specifies the entry point of the caller's MiniportQueryInformation function.
ReconfigureHandler
Specifies NULL.
ResetHandler
Specifies the entry point of the caller's MiniportReset function.
SendHandler
Specifies the entry point of the caller's MiniportSend function, MiniportWanSend function, or NULL if the caller supplies a MiniportSendPackets function.

If the driver supports multipacket sends or media-specific information, it sets the SendPacketsHandler member instead and sets this member to NULL.

SetInformationHandler
Specifies the entry point of the caller's MiniportSetInformation function.
TransferDataHandler
Specifies the entry point of the caller's MiniportTransferData function, if any, or NULL. This miniport driver function is required unless the caller is the driver of a WAN NIC or the caller supports multipacket receives and, therefore, supplies the entry point of its MiniportReturnPacket function at ReturnPacketHandler.
ReturnPacketHandler
Specifies the entry point of the caller's MiniportReturnPacket function, if any, or NULL.
SendPacketsHandler
Specifies the entry point of the caller's MiniportSendPackets function, if any, or NULL.
AllocateCompleteHandler
Specifies NULL.
CoCreateVcHandler
Specifies NULL.
CoDeleteVcHandler
Specifies NULL.
CoActivateVcHandler
Specifies NULL.
CoDeactivateVcHandler
Specifies NULL.
CoSendPacketsHandler
Specifies NULL.
CoRequestHandler
Specifies NULL.
CancelSendPacketsHandler
Specifies the entry point of the caller's MiniportCancelSendPackets function, if any, or NULL. Intermediate drivers that queue send packets for more than one second should register a MiniportCancelSendPackets function.
AdapterShutdownHandler
Specifies the entry point of the caller's MiniportShutdown function, if any, or NULL. NDIS 5.1 intermediate drivers must register a MiniportShutdown function. NDIS 5.1 intermediate drivers should register a MiniportShutdown function by calling NdisIMRegisterLayeredMiniport—not by calling NdisMRegisterAdapterShutdownHandler.
PnPEventNotifyHandler
Specifies the entry point of the caller's MiniportPnPEventNotify function. NDIS 5.1 miniports must register a MiniportPnPEventNotify function. In addition, miniports that can adjust their NIC's power consumption based on the system's current power source and miniports that have a WDM lower edge must register a MiniportPnPEventNotify function.
CharacteristicsLength
Specifies the length in bytes of the caller-supplied characteristics buffer. Depending on the value of MajorNdisVersion, this parameter must be either sizeof(NDIS50_MINIPORT_CHARACTERISTICS) if the driver supplies an NDIS50_MINIPORT_CHARACTERISTICS structure or sizeof(NDIS40_MINIPORT_CHARACTERISTICS) if the driver supplies an NDIS40_MINIPORT_CHARACTERISTICS structure.

If the driver includes the build instruction NDIS50_MINIPORT (or NDIS40_MINIPORT, as appropriate) in its sources or if the driver writer uses the –NDIS50_MINIPORT (or ..40..) compiler switch, this parameter is set when the driver is built.

DriverHandle
Pointer to a variable in which NdisIMRegisterLayeredMiniport, if this call is successful, returns a handle that the caller should save. The caller subsequently must pass this handle to NdisIMInitializeDeviceInstance, usually from its ProtocolBindAdapter function.

Return Value

NdisIMRegisterLayeredMiniport returns NDIS_STATUS_SUCCESS if it registered the caller as a miniport driver, or it can return one of the following status values:

NDIS_STATUS_BAD_CHARACTERISTICS
The CharacteristicsLength is too small for the MajorNdisVersion specified in the buffer at MiniportCharacteristics.
NDIS_STATUS_BAD_VERSION
The MajorNdisVersion or MinorNdisVersion specified in the characteristics structure is invalid.
NDIS_STATUS_RESOURCES
A shortage of resources, possibly memory, prevented the NDIS library from registering the caller as a miniport driver.
NDIS_STATUS_FAILURE
This is a default error status, returned when none of the preceding errors caused the registration to fail. For example, if the NDIS library cannot load the driver's image and lock it into system memory, it returns this error.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Any NDIS intermediate driver that exports both MiniportXxx and ProtocolXxx functions sets up a characteristics structure and calls NdisIMRegisterLayeredMiniport from its DriverEntry function after DriverEntry calls NdisMInitializeWrapper. This structure is copied in the NdisIMRegisterLayeredMiniport request to the NDIS library's internal storage. Thus, once it has registered, such a driver cannot change its handler functions.

After such an NDIS intermediate driver has called NdisIMRegisterLayeredMiniport successfully, it must call NdisRegisterProtocol to register its ProtocolXxx functions with the NDIS library. Such a driver usually has both ProtocolBindAdapter and ProtocolUnbindAdapter functions. Its ProtocolBindAdapter function will be called next when the underlying NIC driver has initialized successfully. ProtocolBindAdapter then can establish a binding to that NIC driver with NdisOpenAdapter.

An NDIS intermediate driver should have a MiniportSendPackets function if an underlying NIC driver might support multipacket sends or consume media-specific information, such as packet priorities, sent down in a packet array from a higher-level protocol. An NDIS intermediate driver should have a MiniportReturnPacket function if an underlying NIC driver might support multipacket receive indications or indicate packet arrays containing media-specific information. The NDIS library handles packet arrays transferred between an underlying NIC driver and higher-level protocol that support only single-packet transfers on behalf of such an intermediate driver.

Callers of NdisIMRegisterLayeredMiniport run at IRQL PASSIVE_LEVEL.

See Also

DriverEntry of NDIS Miniport Drivers, DriverEntry of NDIS Protocol Drivers, MiniportCheckForHang, MiniportHalt, MiniportInitialize, MiniportQueryInformation, MiniportReset, MiniportReturnPacket, MiniportSend, MiniportSendPackets, MiniportSetInformation, MiniportTransferData, MiniportWanSend, NdisIMInitializeDeviceInstance,

NdisMRegisterAdapterShutdownHandler

NdisMRegisterMiniport, NdisOpenAdapter, NdisRegisterProtocol, NdisZeroMemory, ProtocolBindAdapter, ProtocolReceivePacket, ProtocolUnbindAdapter


NdisInitAnsiString

NdisInitAnsiString initializes a counted ANSI string.

VOID
  NdisInitAnsiString(
    IN OUT PANSI_STRING  DestinationString,
    IN PCSTR  SourceString
    );

Parameters

DestinationString
Pointer to a caller-allocated buffer in which this function should store the counted ANSI string.
SourceString
Pointer to a zero-terminated string with which to initialize the counted string.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The DestinationString is initialized to point to the SourceString. The length and maximum length for the DestinationString are initialized to the length of the string at SourceString. If SourceString is NULL, the length is zero.

Callers of NdisInitAnsiString can be running at IRQL <= DISPATCH_LEVEL if the DestinationString buffer is allocated from nonpaged memory. Usually, callers are running at IRQL PASSIVE_LEVEL during driver initialization.

See Also

DriverEntry of NDIS Protocol Drivers, MiniportInitialize, NdisAnsiStringToUnicodeString, NdisInitializeString, NdisInitUnicodeString, NdisUnicodeStringToAnsiString, ProtocolBindAdapter


NDIS_INIT_FUNCTION

NDIS_INIT_FUNCTION is a macro used to mark a driver function to be run once only during initialization.

NDIS_INIT_FUNCTION(FunctionName)

Parameters

FunctionName
The name of the function that is only used during initialization.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Any driver function marked with NDIS_INIT_FUNCTION is discarded when the DriverEntry function returns control.

For example, such a function is declared in the driver source as follows:

NDIS_STATUS DriverEntry(...);
#pragma NDIS_INIT_FUNCTION(DriverEntry)
    ...  //other function declarations
NDIS_STATUS
DriverEntry(...)
{
    ...
}
    ...

NDIS drivers can use this macro on their DriverEntry functions and on internal driver functions that are called only by their DriverEntry functions.

A NIC driver cannot use this macro on its MiniportInitialize function, nor on any internal driver function called by MiniportInitialize, because this function can be called at run time in a Plug-and-Play environment.

See Also

DriverEntry of NDIS Miniport Drivers, DriverEntry of NDIS Protocol Drivers, NDIS_PAGABLE_FUNCTION


NdisInitializeEvent

NdisInitializeEvent sets up an event object during driver initialization to be used subsequently as a synchronization mechanism.

VOID
  NdisInitializeEvent(
    IN PNDIS_EVENT  Event
    );

Parameters

Event
Pointer to caller-supplied storage for the event object, which is opaque to drivers.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The Event pointer passed to NdisInitializeEvent is a required parameter to all other Ndis..Event functions.

While driver functions that run at IRQL <= DISPATCH_LEVEL can call NdisSetEvent and NdisResetEvent, calling NdisWaitEvent from any IRQL > PASSIVE_LEVEL is a fatal error.

Callers of NdisInitializeEvent run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisResetEvent, NdisSetEvent, NdisWaitEvent


NdisInitializeListHead

NdisInitializeListHead initializes a doubly linked, driver-maintained queue.

VOID
  NdisInitializeListHead(
    IN PLIST_ENTRY  ListHead
    );

Parameters

ListHead
Pointer to driver-allocated nonpaged storage for the head of the interlocked queue or list.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisInitializeListHead can be called from a MiniportInitialize function or from a protocol driver's DriverEntry function if the driver queues requests internally. However, miniport drivers seldom set up internal queues because the NDIS library serializes requests and packets sent to miniport drivers.

Any NDIS driver that maintains an internal queue is responsible for synchronizing driver functions' accesses to queued entries. The NdisInterlocked..List functions ensure that only one driver function can access queued entries at any given moment, even if the driver is running on a multiprocessor machine, because the queue is protected by a caller-supplied spin lock.

For an interlocked queue, the driver also must provide nonpaged storage for a spin lock. It must initialize the spin lock with NdisAllocateSpinLock before passing a pointer to that spin lock to any of the NdisInterlocked..List functions.

Callers of NdisInitializeListHead usually run at IRQL PASSIVE_LEVEL, because this function is commonly called at initialization.

See Also

DriverEntry of NDIS Protocol Drivers, MiniportInitialize, NdisAllocateSpinLock, NdisInterlockedInsertHeadList, NdisInterlockedInsertTailList, NdisInterlockedRemoveHeadList


NdisInitializeNPagedLookasideList

NdisInitializeNPagedLookasideList initializes a lookaside list. After a successful initialization, nonpaged fixed-size blocks can be allocated from and freed to the lookaside list.

VOID
  NdisInitializeNPagedLookasideList(
    IN PNPAGED_LOOKASIDE_LIST  Lookaside,
    IN PALLOCATE_FUNCTION  Allocate  OPTIONAL,
    IN PFREE_FUNCTION  Free  OPTIONAL,
    IN ULONG  Flags,
    IN ULONG  Size,
    IN ULONG  Tag,
    IN USHORT  Depth
    );

Parameters

Lookaside
Pointer to the caller-supplied lookaside list head to be initialized. The driver must provide a list head that is resident—that is, in nonpaged system space.
Allocate
Either is NULL or specifies the entry point of a caller-supplied function that will allocate an entry of the specified Size whenever it is called. If Allocate is NULL, NdisAllocateFromNPagedLookasideList subsequently allocates entries on behalf of the caller. If the caller provides an Allocate function, it also must provide a Free function.
Free
Either is NULL or specifies the entry point of a caller-supplied function that will free an entry of the specified Size whenever it is called. If Free is NULL, NdisFreeToNPagedLookasideList subsequently frees entries on behalf of the caller.
Flags
Must be zero. This parameter is reserved for system use.
Size
Specifies the size in bytes of each entry to be subsequently allocated from the lookaside list.
Tag
Specifies a caller-supplied pool tag for lookaside list entries. The Tag is a string of four characters delimited by single quote marks (for example, 'derF'). The characters are usually specified in reverse order so they are easier to read when dumping pool or tracking pool usage in the debugger.
Depth
Must be zero. This parameter is also reserved for system use.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisInitializeNPagedLookasideList initializes the caller-supplied list head but allocates no memory for list entries. The initial entries are allocated on an as-needed basis either with calls to NdisAllocateFromNPagedLookasideList or by the driver-supplied Allocate callback. The list becomes populated as the driver frees entries back to the list with NdisFreeToNPagedLookasideList. Entries collect on the list until a system-determined but dynamically sized limit is reached. Then, any surplus entries in the lookaside list are returned to nonpaged pool, either by NdisFreeToNPagedLookasideList or with calls to the driver-supplied Free callback.

All entries in the lookaside list are of the same size, which is specified when the driver called NdisInitializeNPagedLookasideList. A lookaside list is particularly useful to drivers that must dynamically allocate and free fixed-size context areas in which to maintain runtime state about their outstanding I/O operations. For instance, connection-oriented NDIS drivers are likely to find lookaside lists particularly useful because such drivers usually maintain a dynamic set of context areas to track outgoing and incoming calls.

It is more efficient for a driver to allow the NdisAllocate/Free..LookasideList functions manage the allocation and deallocation of entries. However, a driver that tracks state internally about its memory usage might supply Allocate and Free functions to NdisInitializeNPagedLookasideList.

Callers of NdisInitializeNPagedLookasideList must be running at IRQL <= DISPATCH_LEVEL, but are usually running at PASSIVE_LEVEL.

See Also

ExAllocatePool, ExAllocatePoolWithTag, ExFreePool, NdisAllocateFromNPagedLookasideList, NdisDeleteNPagedLookasideList, NdisFreeToNPagedLookasideList


NdisInitializeReadWriteLock

NdisInitializeReadWriteLock initializes a variable of type NDIS_RW_LOCK. An NDIS_RW_LOCK variable is used to limit write access to shared resources to one nonISR-driver thread at a time. This NDIS_RW_LOCK can allow multiple nonISR-driver threads concurrent read access to those resources. Such read access is not permitted during a write access.

VOID
  NdisInitializeReadWriteLock(
    IN PNDIS_RW_LOCK  Lock
    );

Parameters

Lock
Pointer to an opaque variable that represents a lock. The caller can use this lock to gain write or read access to resources that are shared among nonISR-driver threads.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The Lock pointer that is passed to NdisInitializeReadWriteLock is a required parameter for all other Ndis..ReadWriteLock functions.

Before a driver calls NdisAcquireReadWriteLock to obtain write or read access to a resource, the driver must call NdisInitializeReadWriteLock to initialize the lock that is associated with that resource. The caller must provide nonpaged storage for the variable at Lock.

After calling NdisInitializeReadWriteLock, the driver can call NdisAcquireReadWriteLock to obtain either write or read access to the resource. Only one nonISR-driver thread at a time can obtain write access to the resource. When one nonISR thread has write access, all read and write accesses by other nonISR threads must wait until the write-access holder releases the lock. However, if a nonISR thread has read access, other nonISR threads can concurrently acquire read access.

Initialize and use this type of lock for resources that are frequently accessed for reading and infrequently accessed for writing.

Once resource access is complete, the driver calls NdisReleaseReadWriteLock.

Each lock that a driver initializes does one of the following:

  • protects a discrete set of shared resources from simultaneous write and read access by driver threads that run at IRQL <= DISPATCH_LEVEL.
  • exposes a discrete set of shared resources to simultaneous read access by driver threads that run at IRQL <= DISPATCH_LEVEL

Callers of NdisInitializeReadWriteLock can run at any IRQL. Usually a caller is running at IRQL PASSIVE_LEVEL during initialization.

See Also

NdisAcquireReadWriteLock, NdisReleaseReadWriteLock


NdisInitializeSListHead

NdisInitializeSListHead initializes the head of a sequenced, interlocked, singly linked list.

VOID
  NdisInitializeSListHead(
    IN PSLIST_HEADER  SListHead
    );

Parameters

SListHead
Pointer to the caller-supplied list head to be initialized, which must be in resident memory.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisInitializeSListHead zero-initializes the opaque list head at SListHead and sets the first-entry pointer to NULL.

The sequence number in an S-List is incremented each time an entry is inserted to, or removed from, the list.

All entries in an S-List must be nonpaged.

Any driver that uses an S-List must provide a spin lock to NdisInterlockedPushEntrySList and NdisInterlockedPopEntrySList. Before its initial call to either of these functions, the driver must initialize the spin lock with NdisAllocateSpinLock. To prevent deadlocks, the driver must not be holding this spin lock when it makes subsequent calls to NdisInterlockedPushEntrySList and NdisInterlockedPopEntrySList.

To manage a pool of fixed-size entries from nonpaged memory, consider using a lookaside list instead of an S-List.

Drivers that retry I/O operations should use a doubly linked interlocked queue and the NdisInterlockedInsert/Remove..List functions, rather than an S-List.

Callers of NdisInitializeSListHead should be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisInitializeNPagedLookasideList, NdisInterlockedPopEntrySList, NdisInterlockedPushEntrySList, NdisQueryDepthSList, NdisScheduleWorkItem


NdisInitializeString

NdisInitializeString allocates storage for and initializes a counted string in the system-default character set.

VOID
  NdisInitializeString(
    IN OUT PNDIS_STRING  DestinationString,
    IN PUCHAR  SourceString
    );

Parameters

DestinationString
Specifies NULL when NdisInitializeString is called; on return from this function, points to an NDIS_STRING type that describes an initialized counted string. For Windows 2000 and later, NDIS defines the NDIS_STRING type as a UNICODE_STRING type.
SourceString
Pointer to a zero-terminated string with which to initialize the counted string.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisInitializeString sets the Length and MaximumLength members of NDIS_STRING for the destination string and terminates the destination string with zero. For Windows 2000 and later drivers, NdisInitializeString converts the supplied source string to Unicode characters.

If SourceString is NULL, the lengths are set to zero.

The buffer allocated by NdisInitializeString should be released with NdisFreeString.

Callers of NdisInitializeString run at IRQL PASSIVE_LEVEL.

See Also

ANSI_STRING, DriverEntry of NDIS Protocol Drivers, MiniportInitialize, NdisAnsiStringToUnicodeString, NdisEqualString, NdisFreeString, NdisInitAnsiString, NdisInitUnicodeString, NdisUnicodeStringToAnsiString, UNICODE_STRING


NdisInitializeTimer

NdisInitializeTimer initializes a timer object associated with a driver's timer function.

VOID
  NdisInitializeTimer(
    IN OUT PNDIS_TIMER  Timer,
    IN PNDIS_TIMER_FUNCTION  TimerFunction,
    IN PVOID  FunctionContext
    );

Parameters

Timer
Pointer to caller-supplied, resident storage that receives a timer object.
TimerFunction
Specifies the entry point of a caller-supplied timer function that is called when the timer expires. The following describes the syntax of this timer function:
  VOID
    (*PNDIS_TIMER_FUNCTION)(
      IN PVOID  SystemSpecific1,
      IN PVOID  FunctionContext,
      IN PVOID  SystemSpecific2,
      IN PVOID  SystemSpecific3
      );
FunctionContext
Pointer to a caller-supplied context to be passed to the specified timer function when it is called.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A protocol driver might request that NDIS provide timing services. To request timing services, this protocol driver calls NdisInitializeTimer to set up the driver's timer function. Typically, NdisInitializeTimer is called when a driver initializes. The protocol driver must call NdisInitializeTimer with a caller-supplied pointer to store a timer object, thereby associating a driver-supplied timer function with the timer object. The protocol driver must call NdisInitializeTimer before the driver passes the Timer pointer to any other Ndis..Timer function.

Calls to the NdisSetTimer function insert the timer object in the system timer queue. Calls to NdisCancelTimer dequeue the timer object if it is currently queued. Only one instance of a particular timer object can be queued at any given moment.

After a driver calls NdisSetTimer, the timer object at Timer is queued until the interval specified in the call expires. After the interval expires, the timer object is dequeued and the caller-supplied TimerFunction is run once at IRQL DISPATCH_LEVEL as soon as a processor becomes available.

Callers of NdisInitializeTimer run at IRQL PASSIVE_LEVEL.

See Also

NdisCancelTimer, NdisSetTimer


NdisInitializeWorkItem

NdisInitializeWorkItem initializes a work-queue item with a caller-supplied context and callback routine to be queued for execution when a system worker thread is given control.

VOID
  NdisInitializeWorkItem(
    IN PNDIS_WORK_ITEM  WorkItem,
    IN NDIS_PROC  Routine,
    IN PVOID  Context
    );

Parameters

WorkItem
Pointer to the caller-supplied storage to be initialized. It must be allocated from nonpaged pool.
Routine
Specifies the entry point of a caller-supplied function that processes this work item when it is dequeued. This callback is declared as follows:
VOID
(*NDIS_PROC)(
    IN struct _NDIS_WORK_ITEM *  pWorkItem,
    IN PVOID  Context
);
Context
Pointer to a caller-supplied context area that is passed, uninterpreted, to the callback as its only parameter. This area should be in resident memory and accessible in any arbitrary thread context in which the callback might be run subsequently. In particular, Context cannot point to the stack.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisInitializeWorkItem initializes Item with pointers to Routine and Context and a NULL list pointer.

In general, only higher level drivers queue worker thread items.

A miniport driver that is neither deserialized nor connection-oriented should never call an Ndis..WorkItem function.

The given Routine is responsible for calling NdisFreeMemory to release the storage for Item.

Callers of NdisInitializeWorkItem must be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisFreeMemory, NdisScheduleWorkItem


NdisInitUnicodeString

NdisInitUnicodeString initializes a counted Unicode string.

VOID
  NdisInitUnicodeString(
    IN OUT PNDIS_STRING  DestinationString,
    IN PCWSTR  SourceString
    );

Parameters

DestinationString
Pointer to a caller-allocated NDIS_STRING type in which NdisInitUnicodeString should store the counted Unicode string. For Windows 2000 and later, NDIS defines the NDIS_STRING type as a UNICODE_STRING type.
SourceString
Pointer to a zero-terminated string with which to initialize the counted string.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The DestinationString is initialized to point to the SourceString. The Length and MaximumLength members of NDIS_STRING for the DestinationString are initialized to the length of the string at SourceString. If SourceString is NULL, the length is zero.

Callers of NdisInitUnicodeString can be running at IRQL <= DISPATCH_LEVEL if the DestinationString buffer is allocated from nonpaged memory. Usually, callers are running at IRQL PASSIVE_LEVEL during driver initialization.

See Also

DriverEntry of NDIS Protocol Drivers, MiniportInitialize, NdisAnsiStringToUnicodeString, NdisInitAnsiString, NdisInitializeString, NdisUnicodeStringToAnsiString, ProtocolBindAdapter, UNICODE_STRING


NdisInterlockedAddUlong

NdisInterlockedAddUlong adds an unsigned long value to a given unsigned integer as an atomic operation, using a caller-supplied spin lock to synchronize access to the integer variable.

VOID
  NdisInterlockedAddUlong(
    IN PULONG  Addend,
    IN ULONG  Increment,
    IN PNDIS_SPIN_LOCK  SpinLock
    );

Parameters

Addend
Pointer to the variable for which the value is to be adjusted by the given Increment.
Increment
Specifies the value to be added to that at Addend.
SpinLock
Pointer to a caller-initialized spin lock.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The caller must provide resident storage for the spin lock, which must be initialized with NdisAllocateSpinLock before the initial call to NdisInterlockedAddUlong.

The SpinLock passed to NdisInterlockedAddUlong is used to assure that the addition to the variable at Addend is atomic with respect to any other operations on the same variable that synchronize with the same spin lock.

NdisInterlockedAddUlong raises IRQL to DISPATCH_LEVEL when it acquires the given spin lock and restores the original IRQL before it returns control. Consequently, any driver function that calls NdisInterlockedAddUlong cannot be pageable code.

Callers of NdisInterlockedAddUlong run at IRQL <= DISPATCH_LEVEL.

See Also

NdisAcquireSpinLock, NdisAllocateSpinLock, NdisReleaseSpinLock, NdisRetrieveUlong, NdisStoreUlong


NdisInterlockedDecrement

NdisInterlockedDecrement decrements a caller-supplied variable of type LONG as an atomic operation.

LONG
  NdisInterlockedDecrement(
    IN PLONG  Addend
    );

Parameters

Addend
Pointer to the variable to be decremented.

Return Value

NdisInterlockedDecrement returns the decremented value.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisInterlockedDecrement can safely be used on variables in pageable memory.

NdisInterlockedDecrement is atomic only with respect to other NdisInterlocked Xxx calls.

Callers of NdisInterlockedDecrement can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisInterlockedIncrement


NdisInterlockedIncrement

NdisInterlockedIncrement increments a caller-supplied variable as an atomic operation.

LONG
  NdisInterlockedIncrement(
    IN PLONG  Addend
    );

Parameters

Addend
Pointer to a variable of type LONG.

Return Value

NdisInterlockedIncrement returns the incremented value.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisInterlockedIncrement can safely be used on variables in pageable memory.

NdisInterlockedIncrement is atomic only with respect to other NdisInterlocked Xxx calls.

Callers of NdisInterlockedIncrement can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisInterlockedDecrement


NdisInterlockedInsertHeadList

NdisInterlockedInsertHeadList inserts an entry, usually a packet, at the head of a doubly linked list so that access to the list is synchronized in a multiprocessor-safe way.

PLIST_ENTRY
  NdisInterlockedInsertHeadList(
    IN PLIST_ENTRY  ListHead,
    IN PLIST_ENTRY  ListEntry,
    IN PNDIS_SPIN_LOCK  SpinLock
    );

Parameters

ListHead
Pointer to the head of the doubly linked list into which an entry is to be inserted.
ListEntry
Pointer to the entry to be inserted at the head of the list.
SpinLock
Pointer to a caller-supplied spin lock, used to synchronize access to the list.

Return Value

NdisInterlockedInsertHeadList returns a pointer to the entry that was at the head of the queue before the given entry was inserted. If the queue was empty, it returns NULL.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Before calling NdisInterlockedInsertHeadList, a driver must initialize the variable at ListHead with NdisInitializeListHead and the variable at SpinLock with NdisAllocateSpinLock. The driver also must provide resident storage for these variables and for its internal queue.

The caller-supplied spin lock prevents any other function from accessing the driver's internal queue while NdisInterlockedInsertHeadList is inserting the given entry, even when the driver is running on a multiprocessor machine.

NdisInterlockedInsertHeadList raises IRQL to DISPATCH_LEVEL when it acquires the given spin lock and restores the original IRQL before it returns control. Consequently, any driver function that calls NdisInterlockedInsertHeadList cannot be pageable code.

Most NDIS drivers process packets in FIFO order, so any driver that uses an interlocked queue tends to call NdisInterlockedInsertTailList far more frequently than NdisInterlockedInsertHeadList. Such a driver usually calls NdisInterlockedInsertHeadList only to requeue a packet for a retry operation.

To convert a returned value back to the address of the inserted entry, a driver can use the CONTAINING_RECORD macro.

Callers of NdisInterlockedInsertHeadList run at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocateSpinLock, NdisInitializeListHead, NdisInterlockedInsertTailList, NdisInterlockedRemoveHeadList


NdisInterlockedInsertTailList

NdisInterlockedInsertTailList inserts an entry, usually a packet, at the tail of a doubly linked list so that access to the list is synchronized in a multiprocessor-safe way.

PLIST_ENTRY
  NdisInterlockedInsertTailList(
    IN PLIST_ENTRY  ListHead,
    IN PLIST_ENTRY  ListEntry,
    IN PNDIS_SPIN_LOCK  SpinLock
    );

Parameters

ListHead
Pointer to the head of the doubly linked list into which an entry is to be inserted.
ListEntry
Pointer to the entry to be inserted at the end of the list.
SpinLock
Pointer to a caller-supplied spin lock, used to synchronize access to the list.

Return Value

NdisInterlockedInsertTailList returns a pointer to the entry that was at the tail of the queue before the given entry was inserted. If the queue was empty, it returns NULL.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Before calling NdisInterlockedInsertTailList, a driver must initialize the variable at ListHead with NdisInitializeListHead and the variable at SpinLock with NdisAllocateSpinLock. The driver also must provide resident storage for these variables and for its internal queue.

The caller-supplied spin lock prevents any other function from accessing the driver's internal queue while NdisInterlockedInsertTailList is inserting the given entry, even when the driver is running on a multiprocessor machine.

NdisInterlockedInsertTailList raises IRQL to DISPATCH_LEVEL when it acquires the given spin lock and restores the original IRQL before it returns control. Consequently, any driver function that calls NdisInterlockedInsertTailList cannot be pageable code.

To convert a returned value back to the address of the inserted entry, a driver can use the CONTAINING_RECORD macro.

Callers of NdisInterlockedInsertTailList run at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocateSpinLock, NdisInitializeListHead, NdisInterlockedInsertHeadList, NdisInterlockedRemoveHeadList


NdisInterlockedPopEntrySList

NdisInterlockedPopEntrySList removes the first entry from a sequenced, singly linked list.

PSINGLE_LIST_ENTRY
  NdisInterlockedPopEntrySList(
    IN PSLIST_HEADER  ListHead,
    IN PKSPIN_LOCK  Lock
    );

Parameters

ListHead
Pointer to the head of the already initialized sequenced, singly linked list from which the entry is to be returned.
Lock
Pointer to a caller-supplied spin lock, not currently held by the caller.

Return Value

NdisInterlockedPopEntrySList returns a pointer to the first entry in the list. If the list was empty, this routine returns NULL.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A driver must not be holding the given Lock when it calls NdisInterlockedPopEntrySList. If necessary, the driver should call NdisFreeSpinLock before making this call. NdisInterlockedPopEntrySList itself must acquire this spin lock to remove the first entry in the S-List, if any, in a multiprocessor-safe way.

The caller must provide resident storage for the Lock, which must be initialized with NdisAllocateSpinLock before the initial call to any NdisInterlocked..SList routine.

Callers of NdisInterlockedPopEntrySList can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocateSpinLock, NdisFreeSpinLock, NdisInitializeSListHead, NdisInterlockedPushEntrySList, NdisQueryDepthSList


NdisInterlockedPushEntrySList

NdisInterlockedPushEntrySList inserts an entry at the head of a sequenced, singly linked list.

PSINGLE_LIST_ENTRY
  NdisInterlockedPushEntrySList(
    IN PSLIST_HEADER  ListHead,
    IN PSINGLE_LIST_ENTRY  ListEntry,
    IN PKSPIN_LOCK  Lock
    );

Parameters

ListHead
Pointer to the head of the already initialized sequenced, singly linked list into which the specified entry is to be inserted.
ListEntry
Pointer to the entry to be inserted.
Lock
Pointer to a caller-supplied spin lock, not currently held by the caller.

Return Value

NdisInterlockedPushEntrySList returns a pointer to the previous first entry in the list. If the list was previously empty, it returns NULL.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Before the driver's initial call this function, it must initialize the list head with NdisInitializeSListHead.

A driver must not be holding the given Lock when it calls NdisInterlockedPushEntrySList. If necessary, a driver must call NdisFreeSpinLock before making this call. NdisInterlockedPushEntrySList must acquire this lock itself before it inserts ListEntry at the head of the list to ensure that this operation is handled in a multiprocessor-safe way.

The caller must provide resident storage for the Lock, which must be initialized with NdisAllocateSpinLock before the initial call to any NdisInterlocked..SList routine.

Drivers that retry I/O operations should use a doubly linked interlocked queue and the NdisInterlockedInsert/Remove..List functions, instead of an S-List.

Callers of NdisInterlockedPushEntrySList can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocateSpinLock, NdisFreeSpinLock, NdisInitializeSListHead, NdisInterlockedPopEntrySList, NdisQueryDepthSList


NdisInterlockedRemoveHeadList

NdisInterlockedRemoveHeadList removes an entry, usually a packet, from the head of a doubly linked list so that access to the list is synchronized in a multiprocessor-safe way.

PLIST_ENTRY
  NdisInterlockedRemoveHeadList(
    IN PLIST_ENTRY  ListHead,
    IN PNDIS_SPIN_LOCK  SpinLock
    );

Parameters

ListHead
Pointer to the head of the doubly linked list from which an entry is to be removed.
SpinLock
Pointer to a caller-supplied spin lock, used to synchronize access to the list.

Return Value

NdisInterlockedRemoveHeadList returns a pointer to the dequeued entry. If the list was empty, it returns NULL.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Before calling any NdisInterlocked..List function, a driver must initialize the variable at ListHead with NdisInitializeListHead and the variable at SpinLock with NdisAllocateSpinLock. The driver also must provide resident storage for these variables and for its internal queue.

Before calling NdisInterlockedRemoveHeadList, entries are queued with one or more calls to the NdisInterlockedInsert..List functions.

The caller-supplied spin lock prevents any other function from accessing the driver's internal queue while NdisInterlockedRemoveHeadList is removing an entry, even when the driver is running on a multiprocessor machine.

NdisInterlockedRemoveHeadList raises IRQL to DISPATCH_LEVEL when it acquires the given spin lock and restores the original IRQL before it returns control. Consequently, any driver function that calls NdisInterlockedRemoveHeadList cannot be pageable code.

To convert a returned value back to the address of the inserted entry, a driver can use the CONTAINING_RECORD macro.

Callers of NdisInterlockedRemoveHeadList run at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocateSpinLock, NdisInitializeListHead, NdisInterlockedInsertHeadList, NdisInterlockedInsertTailList


NdisMAllocateMapRegisters

NdisMAllocateMapRegisters reserves system resources during miniport driver initialization for subsequent bus-master DMA operations.

NDIS_STATUS
  NdisMAllocateMapRegisters(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN UINT  DmaChannel,
    IN NDIS_DMA_SIZE  DmaSize,
    IN ULONG  BaseMapRegistersNeeded,
    IN ULONG  MaximumBufferSize
    );

Parameters

MiniportAdapterHandle
Specifies the handle input to MiniportInitialize.
DmaChannel
Specifies the bus-relative DMA channel for an ISA bus-master NIC. If the NIC is on another type of I/O bus, this parameter must be zero.
DmaSize
Specifies the address size that the NIC uses for DMA operations as one of the following:
NDIS_DMA_24BITS
24-bit DMA address
NDIS_DMA_32BITS
32-bit DMA address
NDIS_DMA_64BITS
64-bit DMA address

When NDIS_DMA_64BITS is specified on a system that is running the Microsoft Windows® 2000 and later DataCenter Server operating system with Physical Address Extension (PAE) enabled, the physical addresses of mapped buffers can be greater than 32 bits.

BaseMapRegistersNeeded
Specifies the number of base map registers required by the driver. The driver should request one base map register for each DMA send buffer that it requires. For each requested base map register, NDIS allocates one or more map registers, each of which maps a page of physical memory. NDIS allocates a sufficient number of map registers per requested base register to create a send buffer large enough to contain the specified MaximumBufferSize. NDIS imposes a limit of 64 map registers per miniport driver. If the total number of map registers that NDIS would have to allocate would exceed 64, NdisMAllocateMapRegisters returns NDIS_STATUS_RESOURCES. For more information on specifying BaseMapRegistersNeeded, see the Comments below.
MaximumBufferSize
Specifies the size, in bytes, of the largest send buffer required by the driver for a DMA transfer.

Return Value

NdisMAllocateMapRegisters can return one of the following:

NDIS_STATUS_SUCCESS
NDIS allocated enough map registers per requested base map register to accommodate the specified MaximumBufferSize. If DmaChannel was nonzero, the specified channel has been reserved.
NDIS_STATUS_RESOURCES
One of the following occurred:
  • NDIS could not allocate enough map registers because of system resource constraints.
  • The total number of map registers that NDIS would have to allocate for the requested number of base map registers exceeds 64.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A driver of a bus-master DMA NIC calls NdisMAllocateMapRegisters from its MiniportInitialize function. The driver's MiniportInitialize function must call NdisMSetAttributes or NdisMSetAttributesEx before it calls NdisMAllocateMapRegisters.

If its NIC can use 32-bit or 64-bit addressing for DMA operations, a miniport driver should not set DmaSize to NDIS_DMA_24BITS. A PCI NIC, for example, should always set DmaSize to NDIS_DMA_32BITS or NDIS_DMA_64BITS. System memory below 16MB is a scarce resource. Setting DmaSize to NDIS_DMA_24BITS could therefore cause NdisMAllocateMapRegisters to return NDIS_STATUS_RESOURCES.

To determine how many BaseMapRegistersNeeded the miniport driver should request, consider the following:

  • the number of map registers that NDIS will allocate per requested base map register, based on the MaximumBufferSize
  • the number of send buffers required by the miniport driver for optimum performance
  • the NDIS-imposed limit of 64 map registers per miniport driver

If, for example, a miniport driver for an Ethernet NIC has a maximum send-packet size of 1512 bytes, it should specify a MaximumBufferSize of 1512. Given a page size of 4 Kbytes, a buffer of 1512 bytes can span two physical pages. NDIS therefore allocates two map registers per requested base register. To stay within the limit of 64 map registers, in this case, the miniport driver must request no more than 32 base map registers.

If the miniport driver's MaximumBufferSize is large enough so that NDIS would have to allocate numerous map registers per requested base map register, the miniport driver should call NdisMInitializeScatterGatherDma instead of NdisMAllocateMapRegisters to allocate DMA resources. Otherwise, the miniport driver may not be able to allocate enough send buffers to perform well. For example, a miniport driver that specifies a MaximumBufferSize of 64 Kbytes can request no more than three base registers because NDIS, in this case, will allocate 17 map registers per base register. (With a page size of 4 Kbytes, a 64-Kbyte buffer can span 17 physical pages.) Requesting more than three base registers would cause NdisMAllocateMapRegisters to return NDIS_STATUS_RESOURCES because NDIS would enforce the limit of 64 map registers per miniport driver.

Note that, on systems enabled for Physical Address Extension (PAE), requesting too many base map registers can cause the system to stop responding because not enough map registers are available to satisfy the request. PAE-enabled systems that have more than one NIC are even more likely to stop responding in this situation.

The map registers allocated with NdisMAllocateMapRegisters are implicitly numbered from zero. When calling NdisMStartBufferPhysicalMapping, the driver of a bus-master NIC specifies which map register to use in each call by specifying that map register's zero-based index.

The driver of a bus-master DMA NIC must call NdisMAllocateMapRegisters before it calls NdisMAllocateSharedMemory.

Drivers of NICs that use PIO or the host DMA controller as slave devices do not call NdisMAllocateMapRegisters during initialization.

Callers of NdisMAllocateMapRegisters run at IRQL = PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisMAllocateSharedMemory, NdisMFreeMapRegisters, NdisMInitializeScatterGatherDma NdisMRegisterDmaChannel, NdisMSetAttributes, NdisMSetAttributesEx, NdisMStartBufferPhysicalMapping


NdisMAllocateSharedMemory

NdisMAllocateSharedMemory allocates and maps a host memory range so it is simultaneously accessible from both the system and a bus-master DMA NIC.

VOID
  NdisMAllocateSharedMemory(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN ULONG  Length,
    IN BOOLEAN  Cached,
    OUT PVOID  *VirtualAddress,
    OUT PNDIS_PHYSICAL_ADDRESS  PhysicalAddress
    );

Parameters

MiniportAdapterHandle
Specifies the handle input to MiniportInitialize.
Length
Specifies the number of bytes to allocate.
Cached
Specifies TRUE if the range can be allocated from cached memory.
VirtualAddress
Pointer to a caller-supplied variable in which this function returns the base virtual address of the allocation for use by the miniport driver. If NdisMAllocateSharedMemory cannot satisfy its caller, it returns NULL to indicate that no memory was allocated.
PhysicalAddress
Pointer to a caller-supplied variable in which this function returns a physical address, suitable for use by the NIC, that corresponds to that returned at VirtualAddress, or it returns NULL.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisMAllocateSharedMemory provides both the mapped virtual address range that the driver uses to access the shared memory block and the NDIS_PHYSICAL_ADDRESS-type range that the NIC uses. A value returned at PhysicalAddress can be doubly mapped by the system. That is, a "physical" address range described by the value at PhysicalAddress and Length can be a range of mapped logical addresses that do not match the host physical addresses for the allocation in every possible platform.

NdisMAllocateSharedMemory can be called only from MiniportInitialize. How large an allocation to request depends on how the driver writer, knowing the capabilities and features of the NIC, decides to make the tradeoff between the following performance versus size dilemma:

  • In periods of high network traffic, a miniport driver cannot maintain high I/O throughput if it runs low on shared memory space for device-accessible data buffers.

    For example, the miniport driver could be indicating receive buffers in shared memory faster than such buffers are being returned from bound protocols when a flood of receives come in to its NIC. If all its shared memory space is consumed by outstanding receive buffers, the miniport driver might have to disable receive interrupts on its NIC until it has some shared memory space available for receive buffers.

  • On the other hand, calling NdisMAllocateSharedMemory with a Length chosen to anticipate some maximum transfer demand makes the driver's image larger and its resource usage quite uneconomical, except for rare periods of very high I/O demand. Moreover, NdisMAllocateSharedMemory might not give the driver such a large block if insufficient system memory is available, forcing the driver to fail initialization.

A NIC driver that supplies a MiniportAllocateComplete function has considerably more flexibility in resolving the preceding performance versus size dilemma. MiniportInitialize should allocate only enough shared memory with NdisMAllocateSharedMemory for a moderate demand for network transfer operations through the NIC if the driver has a MiniportAllocateComplete function. Such a miniport driver can call NdisMAllocateSharedMemoryAsync dynamically to allocate more shared memory in periods of heavier transfer demand on its NIC. When the high demand for transfers subsides, such a driver calls NdisMFreeSharedMemory to release the additional memory it allocated.

NdisMAllocateSharedMemory and NdisMAllocateSharedMemoryAsync are the only Ndis Xxx functions that can be called to allocate host memory that is shared between the driver, which uses virtual addresses, and a bus-master NIC, which uses the corresponding logical addresses.

Whenever possible, a NIC driver calls NdisMAllocateSharedMemory with Cached set to TRUE because its request is more likely to succeed. In any platform, noncached memory is always a scarce system resource. Usually, drivers can get larger allocations from cached memory as well. A NIC driver must allocate its shared memory space from noncached memory if either of the following is true:

  • The NIC or miniport driver writes directly into receive buffers before the miniport driver indicates the newly received data.

    For example, a NIC that sets flags in each received frame after it has been transferred must have access to receive buffers in noncached memory. Otherwise, the miniport driver could not determine when it should issue a flush to maintain cache coherency: either the miniport driver would take a performance hit by waiting for a fail-safe interval to flush the cached receive buffer, or the miniport driver would make indications in which the frame flags were randomly set.

  • The NIC transfers some number of received frames sequentially into contiguous physical memory within the shared memory space.

    If such a NIC transferred incoming frames into contiguous cached memory, its driver cannot maintain data integrity for all such frames when any frame might straddle a cache-line boundary. When the miniport driver flushed the range for such a frame, it also might flush the cache space containing some of the next frame if it was already transferred, thereby making that next frame incoherent.

A miniport driver should align the buffers it allocates from shared cached memory on an integral of the host data-cache-line boundary to prevent cache-line tearing during DMA. Cache-line tearing can cause data-integrity problems in the driver or degrade the driver's (and the system's) I/O performance by requiring excessive data-cache flushing to maintain data integrity. MiniportInitialize can call NdisMGetDmaAlignment to determine the alignment boundary in the current platform for device-accessible buffers that the driver will set up within an allocated range of shared memory.

MiniportInitialize also might call NdisSystemProcessorCount before it calls NdisMAllocateSharedMemory if the driver writer decides to allocate a larger shared memory block in multiprocessor machines on the assumption that any SMP machine is likely to be a network server with higher network-transfer demands on the NIC than a workstation.

MiniportInitialize must call NdisMAllocateMapRegisters before it calls NdisMAllocateSharedMemory; otherwise, no memory can be allocated. NDIS allocates an additional map register internally for the shared memory range when it is allocated.

If MiniportInitialize did not specify that the NIC is a bus master when it called NdisMSetAttributes or NdisMSetAttributesEx, NdisMAllocateSharedMemory simply returns control without attempting to make an allocation.

If its call to NdisMAllocateSharedMemory fails, MiniportInitialize can call again requesting a smaller allocation. However, if MiniportInitialize cannot allocate sufficient shared memory for the NIC, it must release all resources it has already allocated and fail initialization.

If the NIC driver subsequently indicates receives with NdisMIndicateReceivePacket, it must allocate some number of buffer descriptors from buffer pool that map the NIC's receive buffers in the shared memory block.

If the allocated memory is cached and, therefore, needs to be flushed on transfers, the miniport driver must call NdisAllocateBuffer to allocate an NDIS_BUFFER-type descriptor for the shared memory range. The NIC driver must call NdisFlushBuffer with this buffer descriptor to perform such a flush. In addition, such a miniport driver should call NdisMUpdateSharedMemory to ensure data integrity on all possible platforms.

Any miniport driver that calls NdisMAllocateSharedMemoryAsync or NdisMAllocateSharedMemory must release all outstanding allocations with one or more calls to NdisMFreeSharedMemory when its NIC is removed, that is, when its MiniportHalt function is called.

Callers of NdisMAllocateSharedMemory run at IRQL PASSIVE_LEVEL.

See Also

MiniportAllocateComplete, MiniportHalt, MiniportInitialize, NdisAllocateBuffer, NdisAllocateBufferPool, NdisCreateLookaheadBufferFromSharedMemory, NdisDestroyLookaheadBufferFromSharedMemory, NdisFlushBuffer, NdisMGetDmaAlignment, NdisMAllocateMapRegisters, NdisMAllocateSharedMemoryAsync, NdisMFreeSharedMemory, NdisMIndicateReceivePacket, NdisMSetAttributes, NdisMSetAttributesEx, NdisMStartBufferPhysicalMapping, NdisMUpdateSharedMemory, NdisSystemProcessorCount


NdisMAllocateSharedMemoryAsync

NdisMAllocateSharedMemoryAsync allocates additional memory shared between a miniport driver and its bus-master DMA NIC, usually when the miniport driver is running low on available NIC receive buffers.

NDIS_STATUS
  NdisMAllocateSharedMemoryAsync(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN ULONG  Length,
    IN BOOLEAN  Cached,
    IN PVOID  Context
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.
Length
Specifies the number of bytes to allocate.
Cached
Specifies TRUE if the memory can be cached.
Context
Pointer to driver-detemined context to be passed to the MiniportAllocateComplete function when it is called.

Return Value

NdisMAllocateSharedMemoryAsync can return one of the following:

NDIS_STATUS_PENDING
The caller's MiniportAllocateComplete function will be called with mapped virtual and device-accessible logical base addresses for the shared memory range, its Length and the Context pointer when the requested memory is allocated. Otherwise, MiniportAllocateComplete will be called with NULL pointers if the attempt to allocate shared memory fails.
NDIS_STATUS_FAILURE
The requested memory could not be allocated at this time. If NdisMAllocateSharedMemoryAsync returns this status, a subsequent call with the same parameters might succeed, depending on whether system resources have become available.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Drivers of bus-master DMA NICs call NdisMAllocateSharedMemoryAsync to dynamically allocate shared memory for transfer operations when high network traffic places excessive demands on the shared memory space that the driver allocated during initialization.

Such a NIC driver usually maintains one or more state variables to track the number of shared memory buffers available for incoming transfers. When the number of available buffers reaches a driver-determined low, the miniport driver calls NdisMAllocateSharedMemoryAsync to allocate more buffer space in shared memory. When the number of available buffers climbs to a driver-determined high, it calls NdisMFreeSharedMemory one or more times to release its preceding dynamic allocation(s).

Usually, such a driver retains the block of shared memory that its MiniportInitialize function allocated with NdisMAllocateSharedMemory until the NIC is removed, when its MiniportHalt function is called. This allocation is sufficient to handle an average demand for transfers through the NIC.

Any miniport driver that calls NdisMAllocateSharedMemoryAsync or NdisMAllocateSharedMemory must release all outstanding allocations with one or more calls to NdisMFreeSharedMemory when its NIC is removed.

Callers of NdisMAllocateSharedMemoryAsync run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportAllocateComplete, MiniportHalt, MiniportInitialize, NdisAllocateBuffer, NdisMAllocateSharedMemory, NdisMFreeSharedMemory


NdisMapFile

NdisMapFile maps an already open file into a caller-accessible buffer if the file is currently unmapped.

VOID
  NdisMapFile(
    OUT PNDIS_STATUS  Status,
    OUT PVOID  *MappedBuffer,
    IN NDIS_HANDLE  FileHandle
    );

Parameters

Status
Pointer to a caller-supplied variable in which this function returns the status of the mapping operation, which can be one of the following:
NDIS_STATUS_SUCCESS
The caller has exclusive access to the file contents until NdisUnmapFile is called.
NDIS_STATUS_ALREADY_MAPPED
The caller cannot access the file contents at this time.
MappedBuffer
Pointer to a caller-supplied variable in which this function returns the base virtual address of the mapped file contents or NULL.
FileHandle
Specifies the handle returned by a preceding call to NdisOpenFile.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisMapFile associates (maps) a virtual address range with an opened file so the driver can access the file contents. NdisMapFile allows only one mapping of a particular file to be outstanding at any time. Consequently, a successful caller is given exclusive access to the file data until NdisUnmapFile or NdisCloseFile is called.

A NIC driver can map and unmap such an open file as necessary, using alternating calls to NdisMapFile and NdisUnmapFile. A call to NdisCloseFile releases the FileHandle and deallocates the buffer containing the file contents.

A NIC driver can call NdisMapFile only during initialization.

Callers of NdisMapFile run at IRQL <= DISPATCH_LEVEL.

See Also

DriverEntry of NDIS Protocol Drivers, MiniportInitialize, NdisCloseFile, NdisOpenFile, NdisUnmapFile


NdisMArcIndicateReceive

NdisMArcIndicateReceive notifies NDIS that an ARCNET packet (or some initial lookahead portion of the packet) has arrived so NDIS can forward the received packet to bound protocols.

VOID
  NdisMArcIndicateReceive(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN PUCHAR  HeaderBuffer,
    IN PUCHAR  DataBuffer,
    IN UINT  Length
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.
HeaderBuffer
Specifies the base virtual address of the packet header. The header buffer includes all bytes preceding the protocol ID.
DataBuffer
Specifies the virtual base virtual address of a buffer containing Length bytes of received packet data.
Length
Specifies the number of bytes in the buffer at DataBuffer.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A serialized miniport driver calls NdisMArcIndicateReceive if it designates its NIC as of type NdisMediumArcnet878_3 or NdisMediumArcnetRaw in response to the OID_GEN_MEDIA_IN_USE query, unless the driver supports multipacket receives. Any miniport driver that supports multipacket receives calls NdisMIndicateReceivePacket with a packet array, rather than calling any of the medium-type-specific NdisM..IndicateReceive functions.

When a miniport driver calls NdisMArcIndicateReceive, NDIS passes a pointer to the header of the packet and a pointer to some or all of the data in the packet to the ProtocolReceive function(s) of bound protocol driver(s). Each protocol that receives such an indication can do the following:

  1. Inspect the header and data in the packet to decide whether the indication is of interest to the protocol's client(s).
  2. If it is, copy as much of the header or data as is visible into protocol-allocated memory, using NdisMoveMemory.
  3. Get the remaining data, if any, for the indication by allocating a packet descriptor with sufficient chained buffer descriptors and calling NdisTransferData. The call to NdisTransferData causes the NIC driver's MiniportTransferData function to copy the data into the protocol-supplied packet.

For any protocol driver that receives an indication through NdisMArcIndicateReceive, the HeaderBuffer and DataBuffer addresses are valid only during the current call to its ProtocolReceive function, and these buffers are read-only. A protocol driver cannot retain a pointer to the indicated packet with these associated buffers nor can it retain any pointers to these buffers for later use. Any data that a protocol driver needs from such a packet must be copied and saved during the receive indication.

The data in the header is the same as that received on the NIC. A miniport driver need not remove any headers or trailers from the data its NIC receives.

The transmitting driver adds padding to any packet that is too short for the requirements of the medium. The receiving miniport driver can include such padding in the data and length it subsequently indicates. Each bound protocol is responsible for detecting any such padding and ignoring it.

Note that only serialized miniport drivers should call NdisMArcIndicateReceive.

Callers of NdisMArcIndicateReceive run at IRQL DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportInitialize, MiniportQueryInformation, MiniportTimer, MiniportTransferData, NdisMArcIndicateReceiveComplete, NdisMIndicateReceivePacket, NdisMoveMemory, NdisTransferData, ProtocolReceive


NdisMArcIndicateReceiveComplete

NdisMArcIndicateReceiveComplete notifies NDIS that an ARCNET packet, identified in a preceding call to NdisMArcIndicateReceive, has been fully transferred by the NIC so that NDIS can notify the appropriate bound protocols.

VOID
  NdisMArcIndicateReceiveComplete(
    IN NDIS_HANDLE  MiniportAdapterHandle
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

After any ARCNET receive indication, a serialized miniport driver eventually must call NdisMArcIndicateReceiveComplete to indicate the end of the transfer operation over the net, even if a particular packet is accepted by no bound protocol.

NdisMArcIndicateReceiveComplete both indicates the completion of a transfer operation for a receive and notifies any bound protocol that has already consumed the initial indication that it can begin postprocessing the received data.

When a miniport driver calls NdisMArcIndicateReceiveComplete, NDIS indicates the completion of the receive operation to each such protocol by calling its ProtocolReceiveComplete function.

ProtocolReceiveComplete functions need not operate under the severe time constraints of the corresponding ProtocolReceive functions. However, another receive indication to the ProtocolReceive function can come in while the ProtocolReceiveComplete function is running.

A miniport driver need not call NdisMArcIndicateReceiveComplete in one-to-one correspondence with its calls to NdisMArcIndicateReceive. That is, a NIC driver can issue a single receive-complete indication for some number of receive indications, particularly when network traffic is high. For example, when a NIC driver is continually indicating receives from the same source, it might call NdisMArcIndicateReceiveComplete once for every ten indications. On the other hand, a miniport driver might call NdisMArcIndicateReceiveComplete once for each indication when network traffic is low so that the driver can regain ownership of the memory it allocated for receives promptly. However, a miniport driver must call NdisMArcIndicateReceiveComplete at least once per batch of packets indicated from its MiniportHandleInterrupt function.

Note that only serialized miniport drivers should call NdisMArcIndicateReceiveComplete.

Callers of NdisMArcIndicateReceiveComplete run at IRQL DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportInitialize, NdisMArcIndicateReceive, ProtocolReceive, ProtocolReceiveComplete


NdisMCancelTimer

NdisMCancelTimer cancels a preceding call to NdisMSetPeriodicTimer or cancels the immediately preceding call to NdisMSetTimer if the interval given to NdisMSetTimer has not yet expired.

VOID
  NdisMCancelTimer(
    IN PNDIS_MINIPORT_TIMER  Timer,
    OUT PBOOLEAN  TimerCancelled
    );

Parameters

Timer
Pointer to a timer object, already initialized with NdisMInitializeTimer and set with NdisMSetPeriodicTimer or NdisMSetTimer.
TimerCancelled
Pointer to a caller-supplied variable, which this function sets to TRUE if the timer was queued and then cancelled, or to FALSE if the timer either was not set or has already fired.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

All NdisM..Timer functions operate on an opaque timer object, for which a NIC driver must supply resident storage. The MiniportInitialize function must call NdisMInitializeTimer with a caller-supplied pointer to this storage, thereby associating a driver-supplied MiniportTimer function with the timer object. MiniportInitialize must call NdisMInitializeTimer before the driver passes the Timer pointer to any other NdisM..Timer function.

Drivers of NICs that do not generate interrupts have a polling MiniportTimer function to monitor the NIC state for incoming receives and for send completions.

Calls to the NdisMSet..Timer functions insert the timer object in the system timer queue. Calls to NdisMCancelTimer dequeue the timer object if it is currently queued. Only one instantiation of a particular timer object can be queued at any given moment.

A call to NdisMCancelTimer while the timer object designated by Timer is queued removes the timer object from the queue, thereby cancelling the execution of the associated MiniportTimer function.

A subsequent call to NdisMSetTimer or NdisMSetPeriodicTimer requeues the timer object so the MiniportTimer function again will be run when the given interval expires.

A call to NdisMCancelTimer can occur just after a timer has fired but before the associated MiniportTimer function is run. Usually, a MiniportTimer function sets a state variable immediately on entry to indicate that it is running. When another miniport driver function calls NdisMCancelTimer, it can check such a TimerCancelled variable on return from this call to determine whether its call to NdisMCancelTimer also cancelled execution of the MiniportTimer function.

A call to NdisMCancelTimer while the MiniportTimer function is running has no effect on the execution of MiniportTimer. It continues to run until it returns control.

Callers of NdisMCancelTimer run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportInitialize, MiniportTimer, NdisMInitializeTimer, NdisMSetPeriodicTimer, NdisMSetTimer


NdisMCloseLog

NdisMCloseLog releases resources that were used for logging.

VOID
  NdisMCloseLog(
      IN NDIS_HANDLE  LogHandle
    );

Parameters

LogHandle
Specifies the handle returned by NdisMCreateLog.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisMCloseLog closes the temporary log file allocated by NdisMCreateLog and releases all resources associated with the driver's logging operations when a NIC driver is unloading.

Callers of NdisMCloseLog run at IRQL PASSIVE_LEVEL.

See Also

MiniportHalt, NdisMCreateLog, NdisMFlushLog, NdisMWriteLogData


NdisMCmActivateVc

NdisMCmActivateVc notifies NDIS that an MCM driver is ready to make transfers on a particular VC.

NDIS_STATUS
  NdisMCmActivateVc(
    IN NDIS_HANDLE  NdisVcHandle,
    IN PCO_CALL_PARAMETERS  CallParameters
    );

Parameters

NdisVcHandle
Specifies the handle identifying the VC.
CallParameters
Pointer to a caller-allocated buffer, formatted as a structure of type CO_CALL_PARAMETERS, containing all the media-specific parameters that the miniport driver uses for the activated VC.

Return Value

When NdisMCmActivateVc returns anything other than NDIS_STATUS_PENDING, the MCM driver should make an internal call to its ProtocolCmActivateVcComplete function. Otherwise, NDIS calls the MCM driver's ProtocolCmActivateVcComplete function when this operation is completed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisMCmActivateVc informs NDIS that an MCM driver has set up call and media parameters on a newly created VC or changed the call parameters on an established VC.

An MCM driver must call NdisMCmActivateVc after establishing a connection on a VC but before any data is sent or received on that VC. This call notifies NDIS that the miniport driver has made its NIC ready for transfers on the VC.

For a client-initiated outgoing call, an MCM driver usually calls NdisMCmActivateVc following the handshake denoting a negotiated agreement with the remote node or successful call-setup at the switch, before it notifies NDIS (and the client) of outgoing call completion with NdisMCmMakeCallComplete. For an incoming call, an MCM driver usually calls NdisMCmActivateVc after it has called NdisMCmCreateVc successfully and before it calls NdisMCmDispatchIncomingCall.

The driver writer determines whether an MCM driver has an (internal) MiniportCoActivateVc function that the driver calls in the context of setting up connections for outgoing and incoming calls.

For the duration of the connection, an MCM driver can modify the call parameters as conditions on the network change and/or whenever the client calls NdisClModifyCallQoS. The MCM driver must update the state that it maintains about call parameters to the new values if it can continue to make transfers on the VC according to the newly modified call parameters. It must call NdisMCmActivateVc to notify NDIS of any changes in the call parameters for the active VC. Otherwise, the MCM driver can do either of the following:

  • Call NdisMCmDeactivateVc after failing the client's request to modify QoS or other call parameters for the VC to such a state that the NIC driver cannot continue to make transfers on the VC.
  • Restore the call parameters to a previously accepted state, notify the client that requested the change, and remain ready to continue transferring data on the VC. In this case, the client has the option of accepting the restored call parameters or rejecting them and initiating a close of the VC.

Only connection-oriented miniport drivers that provide integrated call-management support can call NdisMCmActivateVc. Stand-alone call managers, which register themselves with NDIS as protocols, call NdisCmActivateVc instead.

Callers of NdisMCmActivateVc can be running at IRQL <= DISPATCH_LEVEL.

See Also

CO_CALL_PARAMETERS, MiniportCoActivateVc, NdisClMakeCall, NdisClModifyCallQoS, NdisCmActivateVc, NdisMCmDeactivateVc, NdisMCmDispatchIncomingCall, NdisMCmCreateVc, ProtocolCoCreateVc


NdisMCmAddPartyComplete

NdisMCmAddPartyComplete returns the final status of a client's request, for which the MCM driver previously returned NDIS_STATUS_PENDING, to add a party on an established multipoint VC.

VOID
  NdisMCmAddPartyComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisPartyHandle,
    IN NDIS_HANDLE  CallMgrPartyContext  OPTIONAL,
    IN PCO_CALL_PARAMETERS  CallParameters
    );

Parameters

Status
Specifies the final status of the MCM driver's add-party operation, either NDIS_STATUS_SUCCESS or any NDIS_STATUS_XXX except NDIS_STATUS_PENDING.
NdisPartyHandle
Specifies the handle identifying the party. The MCM driver obtained this handle as input parameter to its ProtocolCmAddParty function.
CallMgrPartyContext
Specifies the handle to a caller-allocated resident context area in which the MCM driver will maintain party-specific state information if the add-party operation succeeded. Otherwise, this parameter can be NULL because it is ignored by NDIS if Status is anything other than NDIS_STATUS_SUCCESS.
CallParameters
Pointer to a structure of type CO_CALL_PARAMETERS that contains the call parameters, originally supplied by the client, for the party to be added.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If an MCM driver's ProtocolCmAddParty function returns NDIS_STATUS_PENDING, the driver must call NdisMCmAddPartyComplete subsequently to notify the client and NDIS that its attempt to add a party on the multipoint VC has completed, whether successfully or with an MCM driver-determined error status.

The underlying network medium determines whether a client can specify per-party traffic parameters on a multipoint VC. For example, traffic parameters on a multipoint VC are identical for all parties on ATM networks.

If the underlying network medium, like ATM, does not support per-party traffic parameters on multipoint VCs, an MCM driver can do one of the following whenever a client attempts to add a party with a specification at CallParameters that does not match the already established traffic parameters for that VC:

  • Reset the traffic parameters to those already established for the multipoint VC when it successfully adds the party on that VC.
  • Change the traffic parameters for every party already on the VC when it successfully adds the new party.
  • Reject the request to add a new party. (This alternative implicitly forces clients to set up their traffic parameters for a multipoint VC with NdisClMakeCall and to specify the same traffic parameters at each subsequent call to NdisClAddParty for the given multipoint VC.)

If the MCM driver sets Status to NDIS_STATUS_SUCCESS, it must supply an explicit handle, which is usually a pointer to the driver-allocated per-party state area, as CallMgrPartyContext when it calls NdisMCmAddPartyComplete.

A call to NdisMCmAddPartyComplete causes NDIS to call the client's ProtocolClAddPartyComplete function.

Only connection-oriented miniport drivers that provide integrated call-management support can call NdisMCmAddPartyComplete. Stand-alone call managers, which register themselves with NDIS as protocols, call NdisCmAddPartyComplete instead.

Callers of NdisMCmAddPartyComplete can be running at IRQL <= DISPATCH_LEVEL.

See Also

CO_CALL_PARAMETERS, NdisAllocateFromNPagedLookasideList, NdisClAddParty, NdisCmAddPartyComplete, NdisMCmDropPartyComplete, ProtocolClAddPartyComplete, ProtocolCmAddParty


NdisMCmCloseAddressFamilyComplete

NdisMCmCloseAddressFamilyComplete returns the final status of a client's request, for which the MCM driver returned NDIS_STATUS_PENDING, to close the AF.

VOID
  NdisMCmCloseAddressFamilyComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisAfHandle
    );

Parameters

Status
The caller sets this to NDIS_STATUS_SUCCESS.
NdisAfHandle
Specifies the NDIS-supplied handle passed to the MCM driver's ProtocolCmOpenAf function when this client originally opened the address family.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

An MCM driver must call NdisMCmCloseAddressFamilyComplete if its ProtocolCmCloseAf function previously returned NDIS_STATUS_PENDING for the given NdisAfHandle. The client, which initiated the pended close-AF operation with a call to NdisClCloseAddressFamily, cannot release the resources it allocated to track communications on the AF until the MCM driver's call to NdisMCmCloseAddressFamilyComplete.

A call to NdisMCmCloseAddressFamilyComplete causes NDIS to call the client's ProtocolClCloseAfComplete function.

The MCM driver cannot subsequently use the NdisAfHandle, which is invalid for the MCM driver when NdisMCmCloseAddressFamilyComplete returns control.

Only connection-oriented miniport drivers that provide integrated call-management support can call NdisMCmCloseAddressFamilyComplete. Stand-alone call managers, which register themselves with NDIS as protocols, call NdisCmCloseAddressFamilyComplete instead.

Callers of NdisMCmOpenAddressFamilyComplete can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisClCloseAddressFamily, NdisCmCloseAddressFamilyComplete, ProtocolClCloseAfComplete, ProtocolCmCloseAf, ProtocolCmOpenAf


NdisMCmCloseCallComplete

NdisMCmCloseCallComplete returns the final status of a client's request, for which the MCM driver previously returned NDIS_STATUS_PENDING, to tear down a call.

VOID
  NdisMCmCloseCallComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisVcHandle,
    IN NDIS_HANDLE  NdisPartyHandle  OPTIONAL
    );

Parameters

Status
Specifies the final status of the client's request that the MCM driver close the connection, either NDIS_STATUS_SUCCESS or any caller-determined NDIS_STATUS_XXX except NDIS_STATUS_PENDING.
NdisVcHandle
Specifies the handle to the VC for the call. This handle was supplied by NDIS when the VC was originally created, whether by the MCM driver with NdisMCmCreateVc or as an input parameter to its ProtocolCoCreateVc function.
NdisPartyHandle
Specifies either NULL if the NdisVcHandle represents a point-to-point VC or the handle to the last remaining party on a multipoint connection, which the MCM driver obtained from its per-party state designated by the CallMgrPartyContext passed as an input parameter to its ProtocolCmCloseCall function.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If an MCM driver's ProtocolCmCloseCall function returns NDIS_STATUS_PENDING, it must call NdisMCmCloseCallComplete subsequently to notify the client and NDIS that its attempt to break the connection has completed, whether successfully or with an error. A call to NdisMCmCloseCallComplete causes NDIS to call the client's ProtocolClCloseCallComplete function.

If it passes NDIS_STATUS_SUCCESS as the Status, the MCM driver should consider the NdisVcHandle (and NdisPartyHandle, if any) unusable for transfers over the network as soon as it calls NdisMCmCloseCallComplete. If the MCM driver originally created the VC, it should call NdisMCmDeleteVc with the same NdisVcHandle that it just passed to NdisMCmCloseCallComplete. If the client created this VC, the MCM driver can expect a call to its ProtocolCoDeleteVc function with the ProtocolVcContext, designating its per-VC state in which it has stored the same NdisVcHandle, as an input parameter.

Only connection-oriented miniport drivers that provide integrated call-management support can call NdisMCmCloseCallComplete. Stand-alone call managers, which register themselves with NDIS as protocols, call NdisCmCloseCallComplete instead.

Callers of NdisMCmCloseCallComplete can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisClCloseCall, NdisCmCloseCallComplete, NdisMCmCreateVc, NdisMCmDeactivateVc, NdisMCmDeleteVc, ProtocolClCloseCallComplete, ProtocolCoDeleteVc


NdisMCmCreateVc

NdisMCmCreateVc sets up a connection endpoint on which an MCM driver can dispatch an incoming-call offer to a client.

NDIS_STATUS
  NdisMCmCreateVc(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN NDIS_HANDLE  NdisAfHandle,
    IN NDIS_HANDLE  MiniportVcContext,
    OUT PNDIS_HANDLE  NdisVcHandle
    );

Parameters

MiniportAdapterHandle
Specifies the NDIS-supplied handle originally input to MiniportInitialize.
NdisAfHandle
Specifies the handle that identifies the client that is the target of an incoming call. The MCM driver obtained this handle as an input parameter to its ProtocolCmOpenAf function.
MiniportVcContext
Specifies the handle to a caller-supplied resident context area in which the MCM driver maintains state for this VC. NDIS passes this handle back to the MCM driver in all subsequent calls concerning this VC if the call to NdisMCmCreateVc succeeds.
NdisVcHandle
Pointer to a caller-supplied variable that must be initialized to NULL before NdisMCmCreateVc is called. On return from a successful call, this variable has been set to a NDIS-supplied handle for the newly created VC. The caller must save this handle for subsequent calls to connection-oriented Ndis Xxx functions concerning this VC.

Return Value

NdisMCmCreateVc can return one of the following:

NDIS_STATUS_SUCCESS
NDIS created the VC successfully.
NDIS_STATUS_RESOURCES
NDIS could not allocate sufficient memory to set up the VC.
NDIS_STATUS_FAILURE
The given NdisAfHandle is invalid.
NDIS_STATUS_XXX
The client failed the creation of the VC for some reason, and NDIS has propagated the error status returned by its ProtocolCoCreateVc function to the MCM driver.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

An MCM driver creates a VC with NdisMCmCreateVc to represent an incoming offer of a connection from a remote node directed to a SAP that has already been registered with the MCM driver.

In the process of VC creation, NDIS supplies an NdisVcHandle to the client and the MCM driver. This handle identifies the virtual connection for the client and miniport driver to which subsequent requests concerning the given VC are directed. Each driver must treat this VC handle as an opaque variable, passing it unmodified and uninterpreted in subsequent calls to certain connection-oriented NDIS library functions.

Usually, callers of NdisMCmCreateVc store the returned NdisVcHandle in the caller-allocated state area at MiniportVcContext. NDIS passes an NdisVcHandle as an input parameter to the ProtocolCoCreateVc function of the appropriate client whenever an MCM driver creates a VC.

When an MCM driver processes the offer of an incoming call directed to one of its registered SAPs, it must call NdisMCmCreateVc first. As a synchronous operation, NDIS calls the client's ProtocolCoCreateVc function before NdisMCmCreateVc returns control. If its call to NdisMCmCreateVc succeeds, the MCM driver can proceed in notifying the appropriate client, passing the returned value at NdisVcHandle to NdisMCmDispatchIncomingCall.

The driver writer determines whether an MCM driver has an (internal) MiniportCoCreateVc function that the driver calls in the context of setting up connections for outgoing and incoming calls.

Only connection-oriented NIC drivers that provide integrated call-management support can call NdisMCmCreateVc. Stand-alone call managers and clients, which register themselves with NDIS as protocols, call NdisCoCreateVc instead.

Callers of NdisMCmCreateVc can be running at IRQL <= DISPATCH_LEVEL.

See Also

MiniportCoCreateVc, NdisAllocateFromNPagedLookasideList, NdisClMakeCall, NdisCoCreateVc, NdisMCmDeleteVc, NdisMCmDispatchIncomingCall, ProtocolCmRegisterSap, ProtocolCoCreateVc


NdisMCmDeactivateVc

NdisMCmDeactivateVc notifies NDIS that there will be no further transfers on a particular active VC.

NDIS_STATUS
  NdisMCmDeactivateVc(
    IN NDIS_HANDLE  NdisVcHandle
    );

Parameter

NdisVcHandle
Specifies the handle identifying the VC. This handle was supplied by NDIS to the MCM driver either when it called NdisMCmCreateVc for an incoming call or when its ProtocolCoCreateVc function set up the VC for a client-initiated outgoing call.

Return Value

NdisMCmDeactivateVc can return one of the following:

NDIS_STATUS_SUCCESS
NDIS marked the VC as inactive.
NDIS_STATUS_NOT_ACCEPTED
The VC is already deactivated, so this call is redundant.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

An MCM driver calls NdisMCmDeactivateVc as an essential step in closing a call, usually after the packet exchange with network components that tears down the connection.

A successful call to NdisMCmDeactivateVc allows the MCM driver to discard the current call parameters for transfers on the VC, possibly reinitializing them to miniport driver-determined default values. However, if the VC is reactivated subsequently for another call, the client will supply new call parameters to the miniport driver.

The NdisVcHandle passed to NdisMCmDeactivateVc remains valid after VC deactivation is completed. The deactivation of any VC allows its creator to reinitialize the VC for reuse or to destroy it:

  • Following VC deactivation and the closing of the call, a client can reuse a VC that it originally created to make another call with NdisClMakeCall, or it can call NdisCoDeleteVc, thereby causing a call to the MCM driver's ProtocolCoDeleteVc function.
  • Following VC deactivation and the closing of the call, an MCM driver can reuse a VC that it originally created to indicate another incoming call to the same client with NdisMCmDispatchIncomingCall, or it can call NdisMCmDeleteVc.

The driver writer determines whether an MCM driver has an (internal) MiniportCoDeactivateVc function that the driver calls in the context of tearing down connections for outgoing and incoming calls.

Only connection-oriented miniport drivers that provide integrated call-managment support can call NdisMCmDeactivateVc. Stand-alone call managers, which register themselves with NDIS as protocols, call NdisCmDeactivateVc instead.

Callers of NdisCmDeactivateVc can be running at IRQL <= DISPATCH_LEVEL.

See Also

MiniportCoDeactivateVc, NdisClCloseCall, NdisClMakeCall, NdisCmDeactivateVc, NdisCoDeleteVc, NdisMCmActivateVc, NdisMCmDeleteVc, NdisMCmDispatchIncomingCall, ProtocolCmCloseCall, ProtocolCoDeleteVc


NdisMCmDeleteVc

NdisMCmDeleteVc destroys a caller-created VC.

NDIS_STATUS
  NdisMCmDeleteVc(
    IN NDIS_HANDLE  NdisVcHandle
    );

Parameters

NdisVcHandle
Specifies the handle identifying the VC to be deleted. The caller originally obtained this handle from NdisMCmCreateVc.

Return Value

NdisMCmDeleteVc can return one of the following:

NDIS_STATUS_SUCCESS
NDIS deleted the VC.
NDIS_STATUS_NOT_ACCEPTED
The VC is still active, so it could not be deleted.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

When an MCM driver calls NdisMCmDeleteVc, there must be no outstanding calls on the given VC and that VC must have been deactivated. To meet these requirements implies that the MCM driver has already called NdisMCmDeactivateVc with the given NdisVcHandle successfully.

Only the driver that created a particular VC can delete that VC. A call to NdisMCmDeleteVc causes NDIS to call the ProtocolCoDeleteVc function of the client with which the caller shares the NdisVcHandle.

When NdisMCmDeleteVc returns control, the NdisVcHandle is no longer valid. The MCM driver can release the resources it allocated to maintain state about the deleted VC or prepare them for reuse in a subsequent incoming-call notification after it calls NdisMCmCreateVc.

The driver writer determines whether an MCM driver has an (internal) MiniportCoDeleteVc function that the driver calls in the context of tearing down connections for outgoing and incoming calls.

Only connection-oriented miniport drivers that provide integrated call-management support can call NdisMCmDeleteVc. Stand-alone call managers and clients, which register themselves with NDIS as protocols, call NdisCoDeleteVc instead.

Callers of NdisMCmDeleteVc can be running at IRQL <= DISPATCH_LEVEL.

See Also

MiniportCoDeleteVc, NdisClCloseCall, NdisCoDeleteVc, NdisMCmDeactivateVc, NdisMCmCreateVc, ProtocolCoDeleteVc


NdisMCmDeregisterSapComplete

NdisMCmDeregisterSapComplete returns the final status of a client's request, for which the MCM driver previously returned NDIS_STATUS_PENDING, to deregister a SAP.

VOID
  NdisMCmDeregisterSapComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisSapHandle
    );

Parameters

Status
Specifies NDIS_STATUS_SUCCESS.
NdisSapHandle
Specifies the handle identifying the SAP.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisMCmDeregisterSapComplete notifies both NDIS and the client that the MCM driver has completed the SAP-deregistration request for which its ProtocolCmDeregisterSap function previously returned NDIS_STATUS_PENDING.

A call to NdisMCmDeregisterSapComplete causes NDIS to call the client's ProtocolClDeregisterSapComplete function.

The MCM driver should consider the NdisSapHandle invalid when NdisMCmDeregisterSapComplete returns control.

Only connection-oriented miniport drivers that provide integrated call-managment support can call NdisMCmDeregisterSapComplete. Stand-alone call managers, which register themselves with NDIS as protocols, call NdisCmDeregisterSapComplete instead.

Callers of NdisMCmDeregisterSapComplete can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisClDeregisterSap, NdisCmDeregisterSapComplete, ProtocolClDeregisterSapComplete, ProtocolCmDeregisterSap


NdisMCmDispatchCallConnected

NdisMCmDispatchCallConnected notifies NDIS and the client that data transfers can begin on a VC that the MCM driver created for an incoming call initiated on a remote node.

VOID
  NdisMCmDispatchCallConnected(
    IN NDIS_HANDLE  NdisVcHandle
    );

Parameter

NdisVcHandle
Specifies the handle to the VC that represents the connection, created with NdisMCmCreateVc when the MCM driver set up the VC for the incoming call.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

An MCM driver's ProtocolCmIncomingCallComplete function calls NdisMCmDispatchCallConnected to complete the final handshake for an incoming call from a remote node, which the local client has already accepted.

A call to NdisMCmDispatchCallConnected causes NDIS to call the client's ProtocolClCallConnected function.

Only connection-oriented miniport drivers that provide integrated call-management support can call NdisMCmDispatchCallConnected. Stand-alone call managers, which register themselves with NDIS as protocols, call NdisCmDispatchCallConnected instead.

Callers of NdisMCmDispatchCallConnected can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisCmDispatchCallConnected, NdisMCmDispatchIncomingCall, NdisMCmCreateVc, ProtocolClCallConnected, ProtocolCmIncomingCallComplete


NdisMCmDispatchIncomingCall

NdisMCmDispatchIncomingCall informs the client of an incoming call on a SAP previously registered by that client with the MCM driver.

NDIS_STATUS
  NdisMCmDispatchIncomingCall(
    IN NDIS_HANDLE  NdisSapHandle,
    IN NDIS_HANDLE  NdisVcHandle,
    IN PCO_CALL_PARAMETERS  CallParameters
    );

Parameters

NdisSapHandle
Specifies the handle identifying the SAP. NDIS set up this handle when the client originally called NdisClRegisterSap, and the MCM driver obtained this handle as an input parameter to its ProtocolCmRegisterSap function.
NdisVcHandle
Specifies the handle identifying the VC, created with NdisMCmCreateVc when the MCM driver processes the incoming call offer directed to this registered SAP.
CallParameters
Pointer to a structure of type CO_CALL_PARAMETERS that specifies the call and media parameters for the VC.

Return Value

When NdisMCmDispatchIncomingCall returns anything other than NDIS_STATUS_PENDING, the MCM driver should make an internal call to its ProtocolCmIncomingCallComplete function. Otherwise, NDIS calls the MCM driver's ProtocolCmIncomingCallComplete function when this operation is completed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Before calling NdisMCmDispatchIncomingCall, an MCM driver has already done the following:

  • Identified the target SAP, previously registered by a particular client, for the call (actually, a request to make a connection) that it received over the network
  • Created a VC for the incoming call with NdisMCmCreateVc
  • Possibly negotiated about acceptable call parameters over the network, or accepted the call parameters sent from the remote node
  • Activated the VC with NdisMCmActivateVc to notify NDIS that it is ready for transfers on the VC in accord with the negotiated or accepted call parameters

The MCM driver's call to NdisMCmDispatchIncomingCall causes NDIS to call the client's ProtocolClIncomingCall function, within which the client either accepts or rejects the requested connection. After deciding whether to accept the connection, the client calls NdisClIncomingCallComplete, which, in turn, calls the MCM driver's ProtocolCmIncomingCallComplete function. If the client accepted the call, the MCM driver next calls NdisMCmDispatchCallConnected. Otherwise, it deactivates (and possibly deletes) the VC it created, after notifying the remote node that the offered call was rejected.

Only connection-oriented miniport drivers that provide integrated call-managment support call NdisMCmDispatchIncomingCall. Stand-alone call managers, which register themselves with NDIS as protocols, call NdisCmDispatchIncomingCall instead.

Callers of NdisMCmDispatchIncomingCall can be running at IRQL <= DISPATCH_LEVEL.

See Also

CO_CALL_PARAMETERS, MiniportHandleInterrupt, NdisClRegisterSap, NdisClIncomingCallComplete, NdisCmDispatchIncomingCall, NdisMCmActivateVc, NdisMCmCreateVc, NdisMCmDeactivateVc, NdisMCmDispatchCallConnected, NdisMCmDeleteVc, ProtocolClIncomingCall, ProtocolCmIncomingCallComplete, ProtocolCmRegisterSap


NdisMCmDispatchIncomingCallQoSChange

NdisMCmDispatchIncomingCallQoSChange notifies a client that a request to change the quality of service on that client's active connection has been received over the network.

VOID
  NdisMCmDispatchIncomingCallQoSChange(
    IN NDIS_HANDLE  NdisVcHandle,
    IN PCO_CALL_PARAMETERS  CallParameters
    );

Parameters

NdisVcHandle
Specifies the handle to the VC for which the change in QoS is being requested. The MCM driver obtained this handle either when it called NdisMCmCreateVc to set up this connection for an incoming call or as an input parameter to its ProtocolCoCreateVc function.
CallParameters
Pointer to a structure of type CO_CALL_PARAMETERS that specifies the new QoS, requested by the client on the remote node, for this connection.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

An MCM driver calls NdisMCmDispatchIncomingCallQoSChange to notify the client that it has received a request to modify the QoS on an active connection. Such an MCM driver supports dynamic QoS changes on active calls, which is a feature like QoS itself that depends on the signalling protocol. For example, ATM networks do not support dynamic QoS changes on active connections.

The MCM driver should call NdisMCmActivateVc whenever it makes changes in the call parameters for an active VC.

A call to NdisMCmDispatchIncomingCallQoSChange causes NDIS to call the client's ProtocolClIncomingQoSChange function. The client accepts the proposed modifications to the call parameters for the VC by doing nothing, except possibly updating any state it maintains about the QoS for the VC, and returning control. Otherwise, the client rejects the proposed QoS change by tearing down the call.

Only connection-oriented miniport drivers that provide integrated call-management support can call NdisMCmDispatchIncomingCallQoSChange. Stand-alone call managers, which register themselves with NDIS as protocols, call NdisCmDispatchIncomingCallQoSChange instead.

Callers of NdisMCmDispatchIncomingCallQoSChange can be running at IRQL <= DISPATCH_LEVEL.

See Also

CO_CALL_PARAMETERS, NdisClCloseCall, NdisClModifyCallQoS, NdisCmDispatchIncomingCallQoSChange, NdisMCmActivateVc, NdisMCmCreateVc, ProtocolClIncomingCallQosChange, ProtocolCoCreateVc


NdisMCmDispatchIncomingCloseCall

NdisMCmDispatchIncomingCloseCall tells a client to tear down an active or offered call, usually because the MCM driver has received a request from the network to close the connection.

VOID
  NdisMCmDispatchIncomingCloseCall(
    IN NDIS_STATUS  CloseStatus,
    IN NDIS_HANDLE  NdisVcHandle,
    IN PVOID  Buffer  OPTIONAL,
    IN UINT  Size
    );

Parameters

CloseStatus
Specifies a caller-determined NDIS_STATUS_XXX, indicating the reason for the disconnect request. During normal network operations, an MCM driver passes NDIS_STATUS_SUCCESS to indicate that it has received a request, initiated by the remote party, to close an active call.
NdisVcHandle
Specifies the handle to the VC of the call being disconnected. This handle was supplied by NDIS when the VC was originally created, whether by the MCM driver with NdisMCmCreateVc or as an input parameter to its ProtocolCoCreateVc function.
Buffer
Pointer to a caller-allocated resident buffer containing additional protocol-specific disconnect data, if any. Depending on the underlying medium, this pointer can be NULL. For example, this parameter is NULL on ATM networks.
Size
Specifies the size in bytes of the buffer, zero if Buffer is NULL.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

In the course of normal network operations, an MCM driver calls NdisMCmDispatchIncomingCloseCall with the CloseStatus set to NDIS_STATUS_SUCCESS because the corresponding client on the remote node has called NdisClCloseCall.

However, an MCM driver also can call NdisMCmDispatchIncomingCloseCall if either of the following occur:

  • The MCM driver has notified a client of an incoming call offer. When the miniport driver's ProtocolCmIncomingCallComplete function is called with the client's acceptance, it validates the input call parameters, which that client has modified. ProtocolCmIncomingCallComplete determines that the client is proposing unsupportable call parameters for the connection, so it calls NdisMCmDispatchIncomingCloseCall.
  • Abormal network conditions force the MCM driver to tear down active calls. For example, if the MCM driver is notified when any link on the connection between this client and the remote party to the connection goes down, the miniport driver would call NdisCmDispatchIncomingCloseCall to prevent the client from attempting (or expecting) further data transfers on such a broken connection.

After the client calls NdisClCloseCall thereby causing the deactivation of the VC, the original creator of the VC is responsible for destroying the VC. Either the client calls NdisCoDeleteVc, which causes NDIS to call the MCM driver's ProtocolCoDeleteVc function, or the MCM driver calls NdisMCmDeleteVc after calling NdisMCmDeactivateVc and releasing any additional resources it had associated with the VC that it created.

A call to NdisMCmDispatchIncomingCloseCall causes NDIS to call the client's ProtocolClIncomingCloseCall function.

Only connection-oriented miniport drivers that provide call-management support can call NdisMCmDispatchIncomingCall. Stand-alone call managers, which register themselves with NDIS as protocols, call NdisCmDispatchIncomingCloseCall instead.

Callers of NdisMCmDispatchIncomingCloseCall can be running at IRQL <= DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, NdisClCloseCall, NdisMCmDispatchIncomingDropParty, NdisMCmDeactivateVc, NdisMCmDeleteVc, NdisMCmDispatchIncomingCall, ProtocolClIncomingCloseCall, ProtocolCoDeleteVc


NdisMCmDispatchIncomingDropParty

NdisMCmDispatchIncomingDropParty notifies a client that it should remove a particular party on a multipoint VC.

VOID
  NdisMCmDispatchIncomingDropParty(
    IN NDIS_STATUS  DropStatus,
    IN NDIS_HANDLE  NdisPartyHandle,
    IN PVOID  Buffer  OPTIONAL,
    IN UINT  Size
    );

Parameters

DropStatus
Indicates the reason this party is being dropped, usually NDIS_STATUS_SUCCESS if the remote party simply requested that its connection be closed.
NdisPartyHandle
Specifies the handle that identifies the party to be dropped from the multipoint VC, which must have other parties that are still connected. The MCM driver originally obtained this handle as an input parameter to its ProtocolCmAddParty function.
Buffer
Pointer to a caller-allocated resident buffer containing additional protocol-specific data received from the remote party, if any. Depending on the underlying medium, this pointer can be NULL. For example, this parameter is NULL on ATM networks.
Size
Specifies the size in bytes of the buffer, zero if Buffer is NULL.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

In the course of normal network operations, an MCM driver calls NdisMCmDispatchIncomingDropParty with the CloseStatus set to NDIS_STATUS_SUCCESS because a remote client on a multipoint connection has called NdisClCloseCall.

However, an MCM driver also can call NdisMCmDispatchIncomingDropParty with a driver-determined CloseStatus at the behest of the network itself if abnormal network conditions occur, such as the failure of a switch on the path between the local client and one or more client(s) on an established multipoint connection.

A call to NdisMCmDispatchIncomingDropParty causes NDIS to call the client's ProtocolClIncomingDropParty function.

If the NdisPartyHandle identifies the last remaining party on the given VC, the MCM driver calls NdisMCmDispatchIncomingCloseCall, rather than NdisMCmDispatchIncomingDropParty.

Only connection-oriented miniport drivers that provide integrated call-management support can call NdisMCmDispatchIncomingDropParty. Stand-alone call managers, which register themselves with NDIS as protocols, call NdisCmDispatchIncomingDropParty instead.

Callers of NdisMCmDispatchIncomingDropParty can be running at IRQL <= DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, NdisClDropParty, NdisCmDispatchIncomingDropParty, NdisMCmDispatchIncomingCloseCall, ProtocolClIncomingDropParty


NdisMCmDropPartyComplete

NdisMCmDropPartyComplete returns the final status of a client's request, for which the MCM driver previously returned NDIS_STATUS_PENDING, to remove a party from a multipoint VC.

VOID
  NdisMCmDropPartyComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisPartyHandle
    );

Parameters

Status
Specifies the final status of the requested operation, either NDIS_STATUS_SUCCESS or any caller-determined NDIS_STATUS_XXX except NDIS_STATUS_PENDING.
NdisPartyHandle
Specifies the handle to the party that the client requested be dropped. The MCM driver obtained this handle from its per-party state area designated by CallMgrPartyContext that was passed as an input parameter to its ProtocolCmDropParty function.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

An MCM driver must call NdisMCmDropPartyComplete if its ProtocolCmDropParty function previously returned NDIS_STATUS_PENDING for the given NdisPartyHandle. Neither NDIS nor the client, which initiated the pended drop-party operation with a call to NdisClDropParty, can release the resources they allocated to maintain per-party state until the MCM driver's call to NdisMCmDropPartyComplete causes a call to that client's ProtocolClDropPartyComplete function.

If it passes NDIS_STATUS_SUCCESS for the Status, the MCM driver must consider the NdisPartyHandle invalid when NdisMCmDropPartyComplete returns control. The MCM driver can release (or reinitialize for reuse) any resources that it allocated to maintain state for this party after NdisMCmDropPartyComplete returns control.

Only connection-oriented miniport drivers that provide integrated call-management support can call NdisMCmDropPartyComplete. Stand-alone call managers, which register themselves with NDIS as protocols, call NdisCmDropPartyComplete instead.

Callers of NdisMCmDropPartyComplete can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisClDropParty, NdisCmDropPartyComplete, ProtocolClDropPartyComplete, ProtocolCmDropParty


NdisMCmMakeCallComplete

NdisMCmMakeCallComplete returns the final status of a client's request, for which the MCM driver previously returned NDIS_STATUS_PENDING, to make an outgoing call.

VOID
  NdisMCmMakeCallComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisVcHandle,
    IN NDIS_HANDLE  NdisPartyHandle  OPTIONAL,
    IN NDIS_HANDLE  CallMgrPartyContext  OPTIONAL,
    IN PCO_CALL_PARAMETERS  CallParameters
    );

Parameters

Status
Specifies the final status of the attempt to make the connection, either NDIS_STATUS_SUCCESS or any caller-determined NDIS_STATUS_XXX except NDIS_STATUS_PENDING.
NdisVcHandle
Specifies the handle to the client-created VC, which the MCM driver obtained as an input parameter to its ProtocolCoCreateVc function and, more recently, from the CallMgrVcContext passed to its ProtocolCmMakeCall function.
NdisPartyHandle
Specifies the handle to the initial party on the client-created multipoint VC, which the MCM driver obtained as an input parameter to its ProtocolCmMakeCall function. If the given NdisVcHandle represented a point-to-point VC, this parameter was NULL.
CallMgrPartyContext
Specifies the handle to a caller-allocated resident context area, in which the MCM driver will maintain per-party state information, or this parameter is NULL if NdisPartyHandle is NULL. For a multipoint VC, NDIS passes this MCM-driver-supplied CallManagerPartyContext handle in all subsequent calls to the ProtocolCmXxx functions that concern this party. If Status is anything other than NDIS_STATUS_SUCCESS, NDIS ignores this parameter.
CallParameters
Pointer to a structure of type CO_CALL_PARAMETERS that specifies the call parameters set up for this connection if Status is NDIS_STATUS_SUCCESS.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

An MCM driver should call NdisMCmMakeCallComplete with NDIS_STATUS_SUCCESS only if it is ready to make data transfers on the VC. That is, the MCM driver has negotiated with the network to establish the call parameters for the VC, set up its NIC for those call parameters, and called NdisMCmActivateVc to notify NDIS of the VC activation.

An MCM driver must call NdisMCmMakeCallComplete if its ProtocolCmMakeCall function previously returned NDIS_STATUS_PENDING for the given NdisVcHandle.The client, which initiated the pending outgoing call, cannot use the VC to make transfers until the miniport driver calls NdisMCmMakeCallComplete with NDIS_STATUS_SUCCESS.

Even if the attempted connection failed, neither NDIS nor the client can release the resources they allocated to maintain state until the MCM driver's call to NdisMCmMakeCallComplete causes a call to that client's ProtocolClMakeCallComplete function. In fact, neglecting to call NdisMCmMakeCallComplete for a failed attempt to set up such a connection causes a memory leak in the MCM driver as well; it prevents the client from tearing down the VC it created for its failed outgoing call, so the MCM driver's ProtocolCoDeleteVc function is not called to release the resources the miniport driver allocated for that VC.

If the MCM driver passes an error, such as NDIS_STATUS_FAILURE, for the Status, it must consider the NdisPartyHandle, if any, invalid when NdisMCmMakeCallComplete returns control. The CM can release (or reinitialize for reuse) any resources that it allocated to maintain state for the given party after NdisMCmMakeCallComplete returns control. The MCM driver's ProtocolCoDeleteVc function will subsequently be called to release any resources that the miniport driver allocated for tracking the state of the client-created VC whenever the MCM driver passes an error status to NdisMCmMakeCallComplete.

In the course of setting up a client-initiated outgoing call, the MCM driver can modify the client-supplied call parameters originally passed in to its ProtocolCmMakeCall function. If it does, the MCM driver must pass its modifications in the buffer at CallParameters when it calls NdisMCmMakeCallComplete. If the client finds these modified call parameters unacceptable, it will then tear down the call, which also causes a call to the MCM driver's ProtocolCoDeleteVc function.

Only connection-oriented miniport drivers that provide integrated call-management support can call NdisMCmMakeCallComplete. Stand-alone call managers, which register themselves with NDIS as protocols, call NdisCmMakeCallComplete instead.

Callers of NdisMCmMakeCallComplete can be running at IRQL <= DISPATCH_LEVEL.

See Also

CO_CALL_PARAMETERS, NdisAllocateFromNPagedLookasideList, NdisClMakeCall, NdisCmMakeCallComplete, ProtocolClMakeCallComplete, ProtocolCmMakeCall, ProtocolCoDeleteVc


NdisMCmModifyCallQoSComplete

NdisMCmModifyCallQoSComplete indicates the completion of the client's request, for which the MCM driver previously returned NDIS_STATUS_PENDING, to modify the quality of service on a VC.

VOID
  NdisMCmModifyCallQoSComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisVcHandle,
    IN PCO_CALL_PARAMETERS  CallParameters
    );

Parameters

Status
Specifies the final status of the client's request to modify the QoS on this VC, either NDIS_STATUS_SUCCESS or any caller-determined NDIS_STATUS_XXX except NDIS_STATUS_PENDING.
NdisVcHandle
Specifies the handle to the VC, obtained from the per-VC state designated by the CallMgrVcContext passed in to the MCM driver's ProtocolCmModifyCallQoS function for this request.
CallParameters
Pointer to a structure of type CO_CALL_PARAMETERS specifying a QoS acceptable to the MCM driver if Status is set to NDIS_STATUS_SUCCESS.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A call to NdisMCmModifyCallQoSComplete causes NDIS to call the client's ProtocolClModifyCallQoSComplete function.

The MCM driver should call NdisMCmActivateVc whenever it makes changes in the call parameters on an active VC.

Because the MCM driver can modify the client-supplied call parameters that were input to its ProtocolCmModifyCallQoS function before it calls NdisMCmModifyCallQoSComplete, the client's ProtocolClModifyCallQoSComplete function examines the QoS to determine whether it is acceptable to the client. ProtocolClModifyCallQoSComplete simply returns control if the client accepts the given call parameters. Otherwise, the client tears down the call.

Only connection-oriented miniport drivers that provide integrated call-management support can call NdisMCmModifyCallQosComplete. Stand-alone call managers, which register themselves with NDIS as protocols, call NdisCmModifyCallQosComplete instead.

Callers of NdisMCmModifyCallQoSComplete can be running at IRQL <= DISPATCH_LEVEL.

See Also

CO_CALL_PARAMETERS, NdisClModifyCallQoS, NdisCmModifyCallQosComplete, NdisMCmActivateVc, ProtocolClModifyCallQoSComplete, ProtocolCmModifyCallQoS


NdisMCmOpenAddressFamilyComplete

NdisMCmOpenAddressFamilyComplete returns the final status of a client's request, for which the MCM driver's ProtocolCmOpenAf function returned NDIS_STATUS_PENDING, to open the MCM driver's address family.

VOID
  NdisMCmOpenAddressFamilyComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisAfHandle,
    IN NDIS_HANDLE  CallMgrAfContext
    );

Parameters

Status
Specifies the final status of the client's request to open the AF, either NDIS_STATUS_SUCCESS or any caller-determined NDIS_STATUS_XXX except NDIS_STATUS_PENDING.
NdisAfHandle
Specifies the NDIS-supplied handle that was input to the MCM driver's ProtocolCmOpenAf function, which returned NDIS_STATUS_PENDING.
CallMgrAfContext
Specifies the handle to a caller-allocated resident context area, in which the MCM driver maintains state about this client's open of the address family, including the NdisAfHandle, if the open succeeded. Otherwise, NDIS ignores this parameter.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

An MCM driver must call NdisMCmOpenAddressFamilyComplete if its ProtocolCmOpenAf function previously returned NDIS_STATUS_PENDING for the given NdisAfHandle. The client, which initiated the pended open-AF operation with a call to NdisClOpenAddressFamily, cannot carry out further connection-oriented operations on the same binding until NdisMCmOpenAddressFamilyComplete causes a call to that client's ProtocolClOpenAfComplete function.

If the caller of NdisMCmOpenAddressFamilyComplete sets Status to NDIS_STATUS_SUCCESS, NDIS subsequently passes the given CallMgrAfContext handle as an input parameter to all MCM driver-supplied ProtocolCmXxx and ProtocolCoXxx functions that concern the client's open of the address family until the client closes the AF. The MCM driver should release or reuse any AF context area that it allocated before it passes a failure status to NdisMCmOpenAddressFamilyComplete.

For a successful open, the NDIS-supplied NdisAfHandle represents an association between the MCM driver and client for the opened AF. Both NDIS drivers must treat NdisAfHandle as an opaque variable to be passed, unmodified and uninterpreted, in subsequent calls to NdisCl/Co/MCm/MCo Xxx functions for which this handle is a required parameter. For a failed open, the MCM driver should consider the NdisAfHandle invalid when NdisMCmOpenAddressFamilyComplete returns control.

Only connection-oriented miniport drivers that provide integrated call-management support can call NdisMCmOpenAddressFamilyComplete. Stand-alone call managers, which register themselves with NDIS as protocols, call NdisCmOpenAddressFamilyComplete instead.

Callers of NdisMCmOpenAddressFamilyComplete can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocateFromNPagedLookasideList, NdisClOpenAddressFamily, NdisCmOpenAddressFamilyComplete, ProtocolClOpenAfComplete, ProtocolCmOpenAf


NdisMCmRegisterAddressFamily

NdisMCmRegisterAddressFamily registers a set of call manager functions for connection-oriented communication over an MCM-driver-specified address family.

NDIS_STATUS
  NdisMCmRegisterAddressFamily(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN PCO_ADDRESS_FAMILY  AddressFamily,
    IN PNDIS_CALL_MANAGER_CHARACTERISTICS  CmCharacteristics,
    IN UINT  SizeOfCmCharacteristics
    );

Parameters

MiniportAdapterHandle
Specifies an NDIS-supplied handle identifying the miniport driver's NIC. This handle is an input parameter to the NIC driver' s MiniportInitialize function, which calls NdisMCmRegisterAddressFamily.
AddressFamily
Pointer to a structure of type CO_ADDRESS_FAMILY identifying the address family the MCM driver supports.

The given AddressFamily becomes an input parameter to the ProtocolCoAfRegisterNotify functions of all clients bound to this MCM driver.

CmCharacteristics
Pointer to an NDIS_CALL_MANAGER_CHARACTERISTICS structure set up by the caller. The structure at CmCharacteristics is defined as follows:
typedef struct _NDIS_CALL_MANAGER_CHARACTERISTICS {
    UCHAR  MajorVersion;
    UCHAR  MinorVersion;
    USHORT  Filler;           // reserved for system use
    UINT    Reserved;         // reserved for system use
    CO_CREATE_VC_HANDLER  CmCreateVcHandler;
    CO_DELETE_VC_HANDLER  CmDeleteVcHandler;
    CM_OPEN_AF_HANDLER  CmOpenAfHandler;
    CM_CLOSE_AF_HANDLER  CmCloseAfHandler;
    CM_REG_SAP_HANDLER  CmRegisterSapHandler;
    CM_DEREG_SAP_HANDLER  CmDeregisterSapHandler;
    CM_MAKE_CALL_HANDLER  CmMakeCallHandler;
    CM_CLOSE_CALL_HANDLER  CmCloseCallHandler;
    CM_INCOMING_CALL_COMPLETE_HANDLER
                             CmIncomingCallCompleteHandler;
    CM_ADD_PARTY_HANDLER  CmAddPartyHandler;
    CM_DROP_PARTY_HANDLER  CmDropPartyHandler;
    CM_ACTIVATE_VC_COMPLETE_HANDLER  CmActivateVcCompleteHandler;
    CM_DEACTIVATE_VC_COMPLETE_HANDLER
                             CmDeactivateVcCompleteHandler;
    CM_MODIFY_CALL_QOS_HANDLER  CmModifyCallQoSHandler;
    CO_REQUEST_HANDLER  CmRequestHandler;
    CO_REQUEST_COMPLETE_HANDLER  CmRequestCompleteHandler;
} NDIS_CALL_MANAGER_CHARACTERISTICS,
                   *PNDIS_CALL_MANAGER_CHARACTERISTICS;

The MCM driver should initialize this structure with zeros before setting up the following members:

MajorVersion
Specifies the major verision of this structure. The current version is 0x05.
MinorVersion
Specifies the minor version of this structure. The current version is 0x00.
Filler and Reserved
The caller should ignore these members after zero-initializing this structure.
CmCreateVcHandler
Specifies the entry point of the caller's ProtocolCoCreateVc function.
CmDeleteVcHandler
Specifies the entry point of the caller's ProtocolCoDeleteVc function.
CmOpenAfHandler
Specifies the entry point of the caller's ProtocolCmOpenAf function.
CmCloseAfHandler
Specifies the entry point of the caller's ProtocolCmCloseAf function.
CmRegisterSapHandler
Specifies the entry point of the caller's ProtocolCmRegisterSap function.
CmDeregisterSapHandler
Specifies the entry point of the caller's ProtocolCmDeregisterSap function.
CmMakeCallHandler
Specifies the entry point of the caller's ProtocolCmMakeCall function.
CmCloseCallHandler
Specifies the entry point of the caller's ProtocolCmCloseCall function.
CmIncomingCallCompleteHandler
Specifies the entry point of the caller's ProtocolCmIncomingCallComplete function.
CmAddPartyHandler
Specifies the entry point of the caller's ProtocolCmAddParty function.
CmDropPartyHandler
Specifies the entry point of the caller's ProtocolCmDropParty function.
CmActivateVcCompleteHandler
Specifies the entry point of the caller's ProtocolCmActivateVcComplete function.
CmDeactivateVcCompleteHandler
Specifies the entry point of the caller's ProtocolCmDeactivateVcComplete function.
CmModifyCallQoSHandler
Specifies the entry point of the caller's ProtocolCmModifyCallQoS function.
CmRequestHandler
Specifies the entry point of the caller's ProtocolCoRequest function.
CmRequestCompleteHandler
Specifies the entry point of the caller's ProtocolCoRequestComplete function.
SizeOfCmCharacteristics
Specifies the size in bytes of the structure at CmCharacteristics.

Return Value

NdisMCmRegisterAddressFamily can return any of the following:

NDIS_STATUS_SUCCESS
The miniport driver has been registered with NDIS as the call manager for the given address family, so NDIS will call the ProtocolCoAfRegisterNotify functions of all clients that bind themselves to this MCM driver.
NDIS_STATUS_RESOURCES
The requested operation failed because NDIS could not allocate sufficient memory or initialize the state it uses to track the MCM driver as a call manager of this address family.
NDIS_STATUS_FAILURE
NDIS failed this call, possibly for one of the following reasons:
  • The caller was not registered as a connection-oriented miniport driver.
  • The caller-supplied invalid or insufficient information at CmCharacteristics.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Drivers that control a connection-oriented NIC for which there is no medium-type-specific stand-alone call manager in the system also call NdisMCmRegisterAddressFamily after calling NdisMRegisterMiniport. The driver of any NIC that has on-board connection-oriented signaling support can register itself as an MCM driver for better performance in managing calls. Registering as an MCM driver displaces any stand-alone call manager with the NIC driver's own call-management support.

For example, because the system provides a stand-alone call manager for all ATM NIC drivers, a NIC driver that reports its medium as NdisMediumAtm is unlikely to call NdisMCmRegisterAddressFamily. However, such an ATM NIC driver might call NdisMCmRegisterAddressFamily if its adapter had on-board connection-oriented signaling support.

An MCM driver calls NdisMCmRegisterAddressFamily from its MiniportInitialize function to register itself as a call manager with NDIS, after it has determined that its NIC is fully operational so the driver can carry out network I/O operations. In effect, such an MCM driver registers itself as a call manager and advertises its specific signaling services for all clients that subsequently bind themselves to the same NIC when MiniportInitialize calls NdisMCmRegisterAddressFamily.

After MiniportInitialize returns control with a successful registration as a call manager, NDIS calls the ProtocolBindAdapter functions of potential clients and, then, the ProtocolCoRegisterAfNotify functions of all clients that bind themselves to the MCM driver's NIC. These clients, in turn, cause NDIS to call the ProtocolCmOpenAf function that the MCM driver just registered for its address family.

The MCM driver must set every Cm Xxx member in the NDIS_CALL_MANAGER_CHARACTERISTICS structure to a caller-supplied ProtocolCm/CoXxx function when it calls NdisMCmRegisterAddressFamily, even if it does not support incoming calls, outgoing calls, or point-to-multipoint connections. For whatever subset of connection-oriented functionality that such an MCM driver does not support, its ProtocolCmXxx functions simply return NDIS_STATUS_NOT_SUPPORTED. For example, NDIS never calls an MCM driver's registered ProtocolCmActivate/DeactivateVcComplete functions, so these can just return NDIS_STATUS_NOT_SUPPORTED but be placeholders in the characteristics structure.

An MCM driver must have ProtocolCoCreateVc and ProtocolCoDeleteVc functions and set their entry points in the NDIS_CALL_MANAGER_CHARACTERISTICS structure passed to NdisMCmRegisterAddressFamily. If the driver previously registered MiniportCoCreate/DeleteVc function(s) when it called NdisMRegisterMiniport, NDIS ignores these entry points after the MCM driver's call to NdisMCmRegisterAddressFamily. Whenever NDIS calls the MCM driver to create or delete a VC subsequently, NDIS passes in an NdisAfHandle as the initial parameter to the miniport driver-supplied ProtocolCoCreate/DeleteVc function, rather than the MiniportAdapterContext handle passed in to the MiniportCoCreate/DeleteVc functions of a stand-alone miniport driver.

An MCM driver cannot set the CmRequestHandler member to its MiniportCoRequest function but must provide a separate ProtocolCoRequest function when it calls NdisMCmRegisterAddressFamily. Even if such a driver already supplied entry points for its MiniportCoRequest, MiniportQueryInformation, and MiniportSetInformation functions when it called NdisMRegisterMiniport, an MCM driver must have a discrete ProtocolCoRequest function to handle CM-specific requests from clients. For MCM drivers, NDIS calls such a set of driver-supplied request handler(s) according to the following policies:

  • When a bound protocol driver calls NdisRequest, NDIS calls the NIC driver's MiniportQueryInformation or MiniportSetInformation function, depending on the given RequestType value, if the NIC driver registered these functions with NdisMRegisterMiniport. Otherwise, NDIS calls the NIC driver's registered MiniportCoRequest function.
  • When a bound protocol driver calls NdisCoRequest with a NULL NdisAfHandle, NDIS calls the NIC driver's registered MiniportCoRequest function. Otherwise, NDIS calls the driver-supplied ProtocolCoRequest function that was set in the CmRequestHandler member when the MCM driver called NdisMCmRegisterAddressFamily.

An MCM driver also must have a ProtocolCoRequestComplete function to handle asynchronous completions of its subsequent calls to NdisMCmRequest.

An MCM driver can support more than one address family on a single NIC to which it is bound. The MCM driver must call NdisCmRegisterAddressFamily once for each address family that it registers on the binding and register the same entry points for each address family on the binding. Only one MCM driver can support a particular type of address family for clients bound to any particular NIC driver.

By contrast to MCM drivers, a stand-alone call manager, which usually provides call-management support to clients that depend on several NIC drivers, would call NdisCmRegisterAddressFamily to register its ProtocolCmXxx and ProtocolCoXxx driver functions with NDIS.

Callers of NdisMCmRegisterAddressFamily usually run at IRQL PASSIVE_LEVEL and in the context of a system thread. NdisMCmRegisterAddressFamily must be called at IRQL < DISPATCH_LEVEL.

See Also

CO_ADDRESS_FAMILY, MiniportCoRequest, MiniportInitialize, MiniportQueryInformation, MiniportSetInformation, NdisCmRegisterAddressFamily, NdisCoRequest, NdisMCmRequest, NdisMRegisterMiniport, NdisOpenAdapter, NdisRequest, NdisZeroMemory, ProtocolBindAdapter, ProtocolCmActivateVcComplete, ProtocolCmAddParty, ProtocolCmCloseAf, ProtocolCmCloseCall, ProtocolCmDeactivateVcComplete, ProtocolCmDeregisterSap, ProtocolCmDropParty, ProtocolCmIncomingCallComplete, ProtocolCmMakeCall, ProtocolCmModifyCallQoS, ProtocolCmOpenAf, ProtocolCmRegisterSap, ProtocolCoAfRegisterNotify, ProtocolCoCreateVc, ProtocolCoDeleteVc, ProtocolCoRequest, ProtocolCoRequestComplete


NdisMCmRegisterSapComplete

NdisMCmRegisterSapComplete returns the final status of a client's request, for which the MCM driver's ProtocolCmRegisterSap function previously returned NDIS_STATUS_PENDING, to register a SAP.

VOID
  NdisMCmRegisterSapComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisSapHandle,
    IN NDIS_HANDLE  CallMgrSapContext
    );

Parameters

Status
Specifies the final status for the client's original request to register the SAP, either NDIS_STATUS_SUCCESS or any caller-determined NDIS_STATUS_XXX except NDIS_STATUS_PENDING.
NdisSapHandle
Specifies the NDIS-supplied handle to the SAP if the registration is successful. The call manager obtained this handle as an input parameter to its ProtocolCmRegisterSap function.
CallMgrSapContext
Specifies the handle to a caller-supplied resident context area in which the MCM driver maintains state for this SAP if the registration is successful. If so, NDIS passes this handle back to the to the MCM driver in all subsequent calls concerning this SAP. If Status is set to something other than NDIS_STATUS_SUCCESS, NDIS ignores this parameter.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

An MCM driver must call NdisMCmRegisterSapComplete if its ProtocolCmRegisterSap function returned NDIS_STATUS_PENDING when it was called with the given NdisSapHandle. The call to NdisMCmRegisterSapComplete causes NDIS to call the client's ProtocolClRegisterSapComplete function.

If the MCM driver sets Status to anything other than NDIS_STATUS_SUCCESS, it should consider the NdisSapHandle invalid when NdisMCmRegisterSapComplete returns control. After failing a SAP registration, the CM can release or reuse the per-SAP context area, if any, that it already allocated. NDIS also releases its context for the SAP if the MCM driver fails the registration.

Only connection-oriented NIC drivers that provide integrated call-management support can call NdisMCmRegisterSapComplete. Stand-alone call managers, which register themselves with NDIS as protocols, call NdisCmRegisterSapComplete instead.

Callers of NdisMCmRegisterSapComplete can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocateFromNPagedLookasideList, NdisClRegisterSap, NdisCmRegisterSapComplete, NdisMCmDispatchIncomingCall, ProtocolClRegisterSapComplete, ProtocolCmRegisterSap


NdisMCmRequest

NdisMCmRequest issues an OID_GEN_CO_XXX request from an MCM driver to a client.

NDIS_STATUS
  NdisMCmRequest(
    IN NDIS_HANDLE  NdisAfHandle ,
    IN NDIS_HANDLE  NdisVcHandle  OPTIONAL,
    IN NDIS_HANDLE  NdisPartyHandle  OPTIONAL,
    IN OUT PNDIS_REQUEST  NdisRequest
    );

Parameters

NdisAfHandle
Specifies the handle identifying the open address family and implicitly the client to which this request is directed. The MCM driver originally obtained this handle as an input parameter to its ProtocolCmOpenAf function.
NdisVcHandle
Specifies the handle identifying the VC for which the caller is requesting or setting information if the request is VC-specific, or this parameter is NULL. For any VC-specific request, the caller originally obtained this handle either when it created the VC with NdisMCmCreateVc, or as an input parameter to its ProtocolCoCreateVc function.
NdisPartyHandle
Specifies the handle identifying the party on a multipoint VC for which the caller is requesting or setting information if the request is party-specific, or this parameter is NULL. For any party-specific request, the MCM driver originally obtained this handle as an input parameter to its ProtocolCmAddParty function.
NdisRequest
Pointer to a caller-allocated resident buffer, formatted as a structure of type NDIS_REQUEST set up by the caller.

Return Value

When NdisMCmRequest returns anything other than NDIS_STATUS_PENDING, the caller should make an internal call to its ProtocolCoRequestComplete function. Otherwise, NDIS calls that driver's ProtocolCoRequestComplete function when this operation is completed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Before it calls NdisMCmRequest, an MCM driver allocates memory for its request and initializes an NDIS_REQUEST structure. Such a driver sets the Oid member of the NDIS_REQUEST structure with a system-defined OID_GEN_CO_XXX code when communicating with its clients.

An MCM driver can call NdisMCmRequest to communicate connection-oriented information, such as a change in addresses to a given client identified by the NdisAfHandle.

If the MCM driver's request is VC-specific or party-specific in nature, the MCM driver also passes an explicit NdisVcHandle or NdisPartyHandle, respectively, to NdisMCmRequest.

For more information about the OID_GEN_CO_XXX defined for use with NdisMCmRequest, see NDIS Object Identifiers.

Callers of NdisMCmRequest can be running at IRQL <= DISPATCH_LEVEL.

See Also

MiniportCoRequest, MiniportQueryInformation, MiniportSetInformation, NdisCoRequest, NdisMCmCreateVc, NdisMCmRequestComplete, NdisMCoRequestComplete, NDIS_REQUEST, NdisRequest, ProtocolCmAddParty, ProtocolCmOpenAf, ProtocolCoCreateVc, ProtocolCoRequest, ProtocolCoRequestComplete


NdisMCmRequestComplete

NdisMCmRequestComplete returns the final status of a client's OID_GEN_CO_XXX request, for which the MCM driver's ProtocolCoRequest function previously returned NDIS_STATUS_PENDING.

VOID
  NdisMCmRequestComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisAfHandle,
    IN NDIS_HANDLE  NdisVcHandle  OPTIONAL,
    IN NDIS_HANDLE  NdisPartyHandle  OPTIONAL,
    IN PNDIS_REQUEST  NdisRequest
    );

Parameters

Status
Specifies the final status of the requested operation, either NDIS_STATUS_SUCCESS or any driver-determined NDIS_STATUS_XXX except NDIS_STATUS_PENDING.
NdisAfHandle
Specifies the AF handle, which implicitly identifies the client that made this request. The MCM driver originally obtained this handle as an input parameter to its ProtocolCmOpenAf function, and, more recently from its per-AF state designated by the ProtocolAfContext that was passed in to its ProtocolCoRequest function.
NdisVcHandle
Specifies the VC handle or NULL if the request is not VC-specific in nature. For a VC-specific request, the MCM driver obtained this handle from its per-VC state designated by the ProtocolVcContext passed in to its ProtocolCoRequest function.
NdisPartyHandle
Specifies the party handle or NULL if the request is not party-specific in nature. For a party-specific request, the MCM driver obtained this handle from its per-party state designated by the ProtocolPartyContext passed in to its ProtocolCoRequest function
NdisRequest
Pointer to a buffer formatted as an NDIS_REQUEST structure, which the client that called NdisCoRequest supplied.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A call to NdisMCmRequestComplete causes a call to the ProtocolCoRequestComplete function of the client that originally called NdisCoRequest with the given handle(s) and NdisRequest pointer.

In response to client-issued requests for which it returns NDIS_STATUS_PENDING, such an MCM driver subsequently must call NdisMCmRequestComplete or NdisMCoRequestComplete depending on whether each such request was routed to the MCM driver's ProtocolCoRequest or MiniportCoRequest function, respectively.

An MCM driver's MiniportQueryInformation and MiniportSetInformation functions, if any, usually handle client requests passed to NdisRequest, such as the OID_GEN_XXX queries commonly issued to miniport drivers during initialization. Otherwise, NDIS calls the MCM driver's MiniportCoRequest function when a bound protocol calls NdisRequest.

For more information about the sets of OIDs defined for use with NdisMCmRequest, NdisCoRequest, and NdisRequest, see NDIS Object Identifiers.

Callers of NdisMCmRequestComplete can be running at IRQL <= DISPATCH_LEVEL.

See Also

MiniportCoRequest, MiniportQueryInformation, MiniportSetInformation, NdisMCmRequest, NdisMCoRequestComplete, NdisRequest, NDIS_REQUEST, ProtocolCoRequest, ProtocolCoRequestComplete


NdisMCoActivateVcComplete

NdisMCoActivateVcComplete notifies NDIS and the call manager that the miniport driver has finished processing a CM-initiated activate-VC request, for which the NIC driver previously returned NDIS_STATUS_PENDING.

VOID
  NdisMCoActivateVcComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisVcHandle,
    IN PCO_CALL_PARAMETERS  CallParameters
    );

Parameters

Status
Specifies the final status of the activate-VC operation, which can be NDIS_STATUS_SUCCESS or any NDIS_STATUS_XXX except NDIS_STATUS_PENDING.
NdisVcHandle
Specifies the handle identifying the VC. The caller obtained this handle from its per-VC state, designated by the MiniportVcContext passed as an input parameter to its MiniportCoActivateVc function.
CallParameters
Pointer to a structure of type CO_CALL_PARAMETERS, supplied by the call manager, specifying the call and media parameters for the VC activation.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A connection-oriented NIC driver must call NdisMCoActivateVcComplete if its MiniportCoActivateVc function previously returned NDIS_STATUS_PENDING in response to a request to activate or reactivate the VC identified by the given NdisVcHandle. The call manager, which initiated the VC activation with a call to NdisCmActivateVc, cannot notify NDIS or its client whether transfers on the VC can be made using the supplied call parameters until the miniport driver calls NdisMCoActivateVcComplete.

If the miniport driver finds the CM-supplied call parameters unacceptable, it fails the VC activation when it calls NdisMCoActivateVcComplete. Failing the initial activation of a VC can cause the protocol that created the VC to tear it down. If the miniport driver fails a request to reactivate an established VC with new call parameters, it must restore the original call parameters established for that VC. Depending on the nature of the network medium, a miniport driver can modify the media parameters if the round-up and/or round-down flag(s) are set before it calls NdisMCoActivateVcComplete.

A call to NdisMCoActivateVcComplete causes NDIS to call the ProtocolCmActivateVcComplete function of the call manager that originally requested the VC activation.

Callers of NdisMCoActivateVcComplete can be running at IRQL <= DISPATCH_LEVEL.

See Also

CO_CALL_PARAMETERS, MiniportCoActivateVc, NdisCmActivateVc, NdisCmDeactivateVc, ProtocolCmActivateVcComplete


NdisMCoDeactivateVcComplete

NdisMCoDeactivateVcComplete notifies NDIS and the call manager that the miniport driver has finished processing a CM-initiated deactivate-VC request, for which the NIC driver previously returned NDIS_STATUS_PENDING.

VOID
  NdisMCoDeactivateVcComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisVcHandle
    );

Parameters

Status
Specifies the final status of the deactivate-VC operation, which can be NDIS_STATUS_SUCCESS or any NDIS_STATUS_XXX except NDIS_STATUS_PENDING.
NdisVcHandle
Specifies the handle identifying the VC. The caller obtained this handle from its per-VC state, designated by the MiniportVcContext passed as an input parameter to its MiniportCoDeactivateVc function.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A connection-oriented NIC driver must call NdisMCoDeactivateVcComplete if its MiniportCoDeactivateVc function previously returned NDIS_STATUS_PENDING in response to a request to deactivate the VC identified by the given NdisVcHandle. The call manager, which initiated the VC deactivation with a call to NdisCmDeactivateVc, cannot notify NDIS or its client whether transfers have been disabled on the VC until the miniport driver calls NdisMCoDeactivateVcComplete.

Before it deactivates a VC, the miniport driver must complete any pending transfers on the VC. That is, the miniport driver must indicate all outstanding receives and transmit all outstanding sends before calling NdisMCoDeactivateVcComplete.

A call to NdisMCoDeactivateVcComplete causes NDIS to call the ProtocolCmDeactivateVcComplete function of the call manager that originally requested the VC deactivation. Following its call to NdisMCoDeactivateVcComplete, the miniport driver can neither indicate receives nor transmit sends on the VC.

Callers of NdisMCoDeactivateVcComplete can be running at IRQL <= DISPATCH_LEVEL.

See Also

MiniportCoDeactivateVc, NdisCmActivateVc, NdisCmDeactivateVc, ProtocolCmDeactivateVcComplete


NdisMCoIndicateReceivePacket

NdisMCoIndicateReceivePacket notifies NDIS that an array of packets on a VC is available to be forwarded to the appropriate client or call manager.

VOID
  NdisMCoIndicateReceivePacket(
    IN NDIS_HANDLE  NdisVcHandle,
    IN PPNDIS_PACKET  PacketArray,
    IN UINT  NumberOfPackets
    );

Parameters

NdisVcHandle
Specifies the handle identifying the VC. The NIC driver originally obtained this handle as an input parameter to its MiniportCoCreateVc function, either when a client set up an outgoing call or when the call manager created a VC for a client-registered SAP on which to indicate an incoming-call notification.
PacketArray
Pointer to an array of packet descriptor pointers, with each descriptor set up by the caller to specify the received data.
NumberOfPackets
Specifies how many pointers are in the array at PacketArray. The value must be at least one.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A call to NdisMCoIndicateReceivePacket causes NDIS to call the ProtocolCoReceivePacket function of the client or call manager that shares the given NdisVcHandle with the connection-oriented NIC driver. Whether a connection-oriented NIC driver makes multipacket or single-packet receive indications is implementation-dependent. However, multipacket indications yield better performance.

Before it calls NdisMCoIndicateReceivePacket, the miniport driver must set up the packet array as follows:

  • Each element at PacketArray is the pointer to a packet descriptor, which the caller allocated from packet pool with NdisAllocatePacket.
  • All buffer descriptors chained to such a packet descriptor were allocated from buffer pool with NdisAllocateBuffer. The miniport driver must call NdisAdjustBufferLength with any buffer descriptor mapping a receive buffer on the NIC that contains less received data than the full range of the receive buffer so that the buffer descriptor will map only the received data for the indication. (The NIC driver must readjust the mapping with NdisAdjustBufferLength when it regains ownership of such a buffer descriptor, as well.)
  • If the miniport driver indicates timestamps for receives, it must set the TimeReceived or TimeSent members in the NDIS_PACKET_OOB_DATA associated with the packet descriptor using the NDIS_SET_PACKET_TIME_RECEIVED and/or NDIS_SET_PACKET_TIME_SENT macros. It can call NdisGetCurrentSystemTime once to get the value to be set as the receive timestamp for all packets of a particular array.
  • The HeaderSize in the out-of-band data block must match the header size of each received packet for the connection-oriented medium.
  • If the driver indicates any additional out-of-band information with receives, it must set the SizeMediaSpecificInfo to the number of bytes of information supplied in the caller-allocated buffer at MediaSpecificInformation in the OOB block. The miniport driver can use the NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO macro to set these values. Otherwise, SizeMediaSpecificInfo should be zero, and MediaSpecificInformation should be NULL.
  • The miniport driver can set the Status member of the out-of-band data block to NDIS_STATUS_RESOURCES if it needs to retain ownership of the packet descriptor(s) and associated buffer descriptor(s) for some packet(s) in a particular indication.

    Setting NDIS_STATUS_RESOURCES forces NDIS to indicate each such packet descriptor, one at a time, to the protocol that shares the NdisVcHandle, thereby forcing that client or call manager to copy the packet data and release each packet descriptor (and the associated buffers) back to the miniport driver. Otherwise, the call to NdisMCoIndicateReceivePacket gives the protocol exclusive, read-only access to the buffers chained to each packet descriptor until the packet descriptor is returned to the miniport driver's MiniportReturnPacket function.

The miniport driver does not have to examine the status of indicated packets on return of NdisMCoIndicateReceivePacket:

  • If the miniport driver set the packet's Status to NDIS_STATUS_SUCCESS before indicating up the packet descriptor, the packet's Status is always NDIS_STATUS_PENDING on return of NdisMCoIndicateReceivePacket. NDIS subsequently returns the packet descriptor to the miniport driver's MiniportReturnPacket function with the packet's Status set to NDIS_STATUS_SUCCESS.
  • If the miniport driver set the packet's Status to NDIS_STATUS_RESOURCES before indicating up the packet descriptor, the packet's Status is always NDIS_STATUS_SUCCESS on return of NdisMCoIndicateReceivePacket.

When the miniport driver regains ownership of an indicated packet descriptor, it can prepare the associated out-of-band data blocks for reuse by passing the pointer returned by NDIS_OOB_DATA_FROM_PACKET to NdisZeroMemory. As an alternative, the miniport driver can simply reset the relevant member(s) at the subsequent receive with the NDIS_SET_PACKET_XXX macro(s) or with the pointer returned by NDIS_OOB_DATA_FROM_PACKET. However, a miniport driver should never pass a packet descriptor pointer to NdisZeroMemory, because doing this destroys the packet descriptor, rendering it unusable for subsequent receive indications.

After some miniport driver-determined number of calls to NdisMCoIndicateReceivePacket from its MiniportHandleInterrupt function, the miniport driver must call NdisMCoReceiveComplete.

If a protocol does not return the miniport driver-allocated resources for a receive indication promptly enough, the NIC driver can call NdisMCoIndicateStatus with NDIS_STATUS_RESOURCES to alert the offending protocol that the NIC driver is running low on available packet or buffer descriptors (or even on NIC receive buffer space) for subsequent receive indications.

Callers of NdisMCoIndicateReceivePacket can be running at IRQL DISPATCH_LEVEL. However, a NIC driver generally makes this call from its MiniportHandleInterrupt function, which always runs at IRQL DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportReturnPacket, NdisAllocateBuffer, NdisAdjustBufferLength, NdisAllocatePacket, NdisChainBufferAtBack, NdisChainBufferAtFront, NdisGetCurrentSystemTime, NDIS_GET_PACKET_STATUS, NdisMAllocateSharedMemoryAsync, NdisMCoIndicateStatus, NDIS_OOB_DATA_FROM_PACKET, NDIS_PACKET, NDIS_PACKET_OOB_DATA, NdisReturnPackets, NDIS_SET_PACKET_TIME_RECEIVED, NDIS_SET_PACKET_TIME_SENT, ProtocolCoReceivePacket, ProtocolReceiveComplete


NdisMCoIndicateStatus

NdisMCoIndicateStatus indicates a change in the status of a connection-oriented NIC to bound protocols, or a change in the status of a particular VC active on the NIC.

VOID
  NdisMCoIndicateStatus(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN NDIS_HANDLE  NdisVcHandle  OPTIONAL,
    IN NDIS_STATUS  GeneralStatus,
    IN PVOID  StatusBuffer  OPTIONAL,
    IN ULONG  StatusBufferSize
    );

Parameters

MiniportAdapterHandle
Specifies the NDIS-supplied handle originally input to MiniportInitialize.
NdisVcHandle
Specifies the handle to the VC for which VC-specific status is being indicated. The miniport driver originally obtained this handle as an input parameter to its MiniportCoCreateVc function. To make a notification of a general status change in the NIC to all bound protocols, this handle should be NULL.
GeneralStatus
Specifies the NDIS_STATUS_XXX value that describes the change in status.
StatusBuffer
Pointer to a caller-allocated buffer containing medium- and status-specific information, if any, supplemental to the value at GeneralStatus. This parameter can be NULL.
StatusBufferSize
Specifies the size in bytes of the buffer at StatusBuffer, zero if StatusBuffer is NULL

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A call to NdisMCoIndicateStatus with a NULL NdisVcHandle causes NDIS to forward the miniport driver's status-change notification to all bound protocols by calling each bound protocol's ProtocolCoStatus function in turn. A call with an explicit NdisVcHandle restricts such a notification only to the client and/or, possibly, call manager, with which the miniport driver shares this VC handle.

In either case, such a notification makes it possible for protocols to log the change in status or to take corrective action. For example, a protocol might call NdisReset, depending on the NDIS_STATUS_XXX indicated by the underlying NIC driver.

When a miniport driver senses that the network connection has been lost, it should call NdisMCoIndicateStatus with NDIS_STATUS_MEDIA_DISCONNECT. When the connection is restored, the miniport driver should call NdisMCoIndicateStatus with NDIS_STATUS_MEDIA_CONNECT.

When a miniport driver calls NdisMCoIndicateStatus to report operational problems in its NIC, NDIS itself can call the MiniportReset function to try restoring the NIC to a working condition. In these circumstances, NDIS calls bound protocols only with NDIS_STATUS_RESET_START and later with NDIS_STATUS_RESET_END, rather that forwarding the GeneralStatus that the miniport driver passed to NdisMCoIndicateStatus.

A miniport driver cannot call NdisMCoIndicateStatus in the context of its MiniportInitialize, MiniportISR, MiniportHalt, or MiniportShutdown function.

Callers of NdisMCoIndicateStatus can be running at IRQL <= DISPATCH_LEVEL.

WAN Miniport Driver Calls to NdisMCoIndicateStatus

A CoNDIS WAN miniport driver indicates VC status with specific status codes and buffer contents. These status indications are generated by a CoNDIS WAN miniport driver. A connection-oriented client (protocol) that shares the VC with such a miniport driver can ignore these indications. However, processing these indications typically results in improved performance for a protocol and miniport driver.

The following types of CoNDIS-WAN-specific indications can be sent to connection-oriented clients with NdisMCoIndicateStatus:

  1. Link parameters
  2. Fragment

NDIS_STATUS_WAN_CO_LINKPARAMS

A CoNDIS WAN miniport driver makes a link-parameters indication whenever parameters for a particular VC that is active on the NIC change.

The status code for the link-parameters indication is NDIS_STATUS_WAN_CO_LINKPARAMS. The buffer at StatusBuffer is formatted as an WAN_CO_LINKPARAMS structure.

NDIS_STATUS_WAN_CO_FRAGMENT

A CoNDIS WAN miniport driver makes a fragment indication whenever it receives a partial packet from the endpoint of a virtual connection. After this indication occurs, a connection-oriented client should send frames to the connection-oriented client at the other end of the VC. These frames will notify the opposite endpoint of this partial-packet situation, rather than waiting for a time-out to occur.

The status code for the fragment indication is NDIS_STATUS_WAN_CO_FRAGMENT. The buffer at StatusBuffer is formatted as an NDIS_WAN_CO_FRAGMENT structure.

NDISWAN monitors dropped packets by counting the number of fragment indications on each link.

See Also

MiniportInitialize, MiniportReset, NdisReset, NDIS_WAN_CO_FRAGMENT, ProtocolCoStatus, WAN_CO_LINKPARAMS


NdisMCompleteBufferPhysicalMapping

NdisMCompleteBufferPhysicalMapping flushes any data remaining in a bus-master NIC's internal cache at the end of a transfer that was set up with NdisMStartBufferPhysicalMapping.

VOID
  NdisMCompleteBufferPhysicalMapping(
    IN NDIS_HANDLE MiniportAdapterHandle,
    IN PNDIS_BUFFER Buffer,
    IN ULONG PhysicalMapRegister
    );

Parameters

MiniportAdapterHandle
Specifies the handle input to MiniportInitialize.
Buffer
Pointer to the buffer descriptor, for a shared memory buffer previously mapped with NdisMStartBufferPhysicalMapping.
PhysicalMapRegister
Specifies the index of the map register used for the mapping. This value is identical to the PhysicalMapRegister index passed with the descriptor at Buffer in the preceding call to NdisMStartBufferPhysicalMapping.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

PhysicalMapRegister is a zero-based value that falls within the index range for the map registers the miniport driver allocated during initialization with NdisMAllocateMapRegisters.

Callers of NdisMCompleteBufferPhysicalMapping run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportInitialize, MiniportSend, MiniportSendPackets, MiniportTimer, MiniportWanSend, NdisMAllocateMapRegisters, NdisMAllocateSharedMemory, NdisMAllocateSharedMemoryAsync, NdisMStartBufferPhysicalMapping


NdisMCompleteDmaTransfer

NdisMCompleteDmaTransfer indicates that a system DMA transfer operation has completed. It resets the system DMA controller in preparation for further DMA transfers.

VOID
  NdisMCompleteDmaTransfer(
    OUT PNDIS_STATUS  Status,
    IN NDIS_HANDLE  MiniportDmaHandle,
    IN PNDIS_BUFFER  Buffer,
    IN ULONG  Offset,
    IN ULONG  Length,
    IN BOOLEAN  WriteToDevice
    );

Parameters

Status
Pointer to a caller-supplied variable in which this function returns the final status of the DMA transfer, which can be one of the following:
NDIS_STATUS_SUCCESS
The data has been transferred and flushed to host memory or to the device to maintain data integrity.
NDIS_STATUS_RESOURCES
The DMA controller was released but the data transfer might be incoherent.
MiniportDmaHandle
Specifies the handle returned when MiniportInitialize called NdisMRegisterDmaChannel.
Buffer
Pointer to the buffer descriptor previously passed to NdisMSetupDmaTransfer.
Offset
Specifies the byte offset at which the transfer began. This value also was passed to NdisMSetupDmaTransfer.
Length
Specifies the length in bytes of the transfer. This value also was passed to NdisMSetupDmaTransfer.
WriteToDevice
Specifies TRUE if the transfer was from the host to the NIC, as, for example, a send operation.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisMCompleteDmaTransfer must be called with WriteToDevice set to TRUE before the transferred data is considered present in the NIC's memory. NdisMCompleteDmaTransfer must be called with WriteToDevice set to FALSE before the transferred data can be read from host memory.

Callers of NdisMCompleteDmaTransfer run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportInitialize, MiniportTimer, NdisMDeregisterDmaChannel, NdisMRegisterDmaChannel, NdisMSetupDmaTransfer


NdisMCoReceiveComplete

NdisMCoReceivePacketComplete notifies NDIS that the processing of one or more preceding receive indications have been fully transferred so that NDIS can notify the appropriate client.

VOID
  NdisMCoReceiveComplete(
    IN NDIS_HANDLE  MiniportAdapterHandle
    );

Parameter

MiniportAdapterHandle
Specifies the NDIS-supplied handle that the miniport driver originally obtained as an input parameter to its MiniportInitialize function.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

After one or more calls to NdisMCoIndicateReceivePacket, a connection-oriented NIC driver must call NdisMCoReceiveComplete to notify NDIS that its preceding indications of incoming transfers over the network have completed. The miniport driver's call to NdisMCoReceiveComplete prompts NDIS to notify the client or stand-alone call manager to which NDIS has recently posted the NIC driver's receive indications so that the protocol can begin postprocessing the received data.

When a miniport driver calls NdisMCoReceiveComplete, NDIS indicates the completion of receive operation(s) by calling the protocol's ProtocolReceiveComplete function. ProtocolReceiveComplete functions do not operate under the severe time constraints of the corresponding ProtocolCoReceivePacket functions. However, another receive indication to the ProtocolCoReceivePacket function can come in while the ProtocolReceiveComplete function is running.

A miniport driver need not call NdisMCoReceiveComplete in one-to-one correspondence with its calls to NdisMCoIndicateReceivePacket. That is, the NIC driver can issue a single receive-complete indication for some number of receive indications on a VC, particularly when network traffic is high. At a minimum, a connection-oriented miniport driver must call NdisMCoReceiveComplete at least once from its MiniportHandleInterrupt function after making one or more receive indications on any particular VC.

Callers of NdisMCoReceiveComplete can be running at IRQL DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportInitialize, MiniportReturnPacket, NdisMCoIndicateReceivePacket, ProtocolCoReceivePacket, ProtocolReceiveComplete


NdisMCoRequestComplete

NdisMCoRequestComplete returns the final status of an OID_GEN_CO_XXX or connection-oriented medium-specific OID_XXX request for which the MiniportCoRequest function previously returned NDIS_STATUS_PENDING.

VOID
  NdisMCoRequestComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN PNDIS_REQUEST  Request
    );

Parameters

Status
Specifies the final status of the requested operation, either NDIS_STATUS_SUCCESS or any driver-determined NDIS_STATUS_XXX except NDIS_STATUS_PENDING.
MiniportAdapterHandle
Specifies the NDIS-supplied handle originally input to MiniportInitialize.
Request
Pointer to a buffer formatted as an NDIS_REQUEST structure. The miniport driver obtained this pointer as an input parameter to its MiniportCoRequest function.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A NIC driver that returns NDIS_STATUS_PENDING from its MiniportCoRequest function must call NdisMCoRequestComplete subsequently when the miniport driver has finished the requested operation.

A call to NdisMCoRequestComplete causes a call to the ProtocolCoRequestComplete function of the protocol that originally called NdisCoRequest with the given NdisRequest pointer.

An MCM driver that returns NDIS_STATUS_PENDING from its ProtocolCoRequest function must call NdisMCmRequestComplete, subsequently, rather than NdisMRequestComplete or NdisMCoRequestComplete.

Callers of NdisMCoRequestComplete can be running at IRQL <= DISPATCH_LEVEL.

See Also

MiniportCoRequest, MiniportQueryInformation, MiniportSetInformation, NdisCoRequest, NdisCoRequestComplete, NdisMCmRequestComplete, NdisRequest, NDIS_REQUEST, ProtocolCoRequest, ProtocolCoRequestComplete


NdisMCoSendComplete

NdisMCoSendComplete returns a packet descriptor and its associated resources to the protocol that requested the send.

VOID
  NdisMCoSendComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisVcHandle,
    IN PNDIS_PACKET  Packet
    );

Parameters

Status
Specifies the status of the send operation, either NDIS_STATUS_SUCCESS or any driver-determined NDIS_STATUS_XXX except NDIS_STATUS_PENDING.
NdisVcHandle
Specifies the handle to the VC on which the given packet data was to be sent. The miniport driver recently obtained this handle from its MiniportVcContext, which was passed an input parameter to its MiniportCoSendPackets function.
Packet
Pointer to the packet descriptor with chained buffer descriptors mapping the buffered protocol-supplied data that was to be sent.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NDIS assumes that any connection-oriented NIC driver is a deserialized miniport driver; that is, NDIS neither serializes nor queues incoming sends for drivers that have a MiniportCoSendPackets function.

Such a connection-oriented NIC driver must call NdisMCoSendComplete with each packet descriptor that NDIS forwards to its MiniportCoSendPackets function eventually, thereby returning the packet descriptor and associated resources to the allocating protocol that initiated the send operation. The miniport driver's call to NdisMCoSendComplete does not necessarily mean that all data associated with a packet descriptor has been transmitted over the network to its destination. Possibly the MiniportCoSendPackets function actually completes each input send packet with NdisMCoSendComplete after copying the protocol-supplied data into the NIC's transmit buffers, or perhaps the miniport driver holds send packets in an internal queue until the packet data has been transmitted over the network before it calls NdisMCoSendComplete.

If the VC identified by NdisVcHandle was activated by the NIC driver's MiniportCoActivateVc function with INDICATE_END_OF_TX set in the Flags member of the CO_MEDIA_PARAMETERS structure, the miniport driver cannot call NdisMCoSendComplete until the transmission of the packet data actually is completed.

In any case, a call to NdisMCoSendComplete causes NDIS to call the ProtocolCoSendComplete function of the driver that originally called NdisCoSendPackets with the packet descriptor at Packet.

With NdisMCoSendComplete, the miniport driver restores ownership of the given packet descriptor and of all resources associated with it to the protocol that originally allocated these resources. The NIC driver can no longer access the packet descriptor, any buffer descriptors chained to the packet descriptor or the buffers they map, and the out-of-band data block associated with the packet descriptor after calling NdisMCoSendComplete.

Callers of NdisMCoSendComplete can be running at IRQL = DISPATCH_LEVEL.

See Also

CO_MEDIA_PARAMETERS, MiniportCoActivateVc, MiniportCoSendPacket s, NdisCoSendPackets, ProtocolCoSendComplete


NdisMCreateLog

NdisMCreateLog allocates and opens a log file in which a miniport driver can write data to be displayed by a driver-dedicated Win32 application.

NDIS_STATUS
  NdisMCreateLog(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN UINT  Size,
    OUT PNDIS_HANDLE  LogHandle
    );

Parameters

MiniportAdapterHandle
Specifies the handle input to MiniportInitialize.
Size
Specifies how many bytes to allocate for the log file. NDIS creates a temporary file that is not stored on disk.
LogHandle
Pointer to a caller-supplied variable in which this function returns a handle to the log file. This handle is a required parameter to the Ndis..Log functions that the miniport driver calls subsequently.

Return Value

NdisMCreateLog can return one of the following:

NDIS_STATUS_SUCCESS
The miniport driver can use the handle returned at LogHandle to write data to the NDIS-allocated log file.
NDIS_STATUS_RESOURCES
A log file of the specified size could not be allocated.
NDIS_STATUS_FAILURE
The driver already called NdisMCreateLog successfully.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A miniport driver can call the NdisM..Log functions to provide any information the driver writer chooses. Whatever the miniport driver logs can be displayed by a driver-dedicated Win32 application. Such an application calls the Win32 function DeviceIoControl with IOCTL_NDIS_GET_LOG_DATA periodically to retrieve whatever the miniport driver has written to the log file. For example, an under-development miniport driver might write test data to be displayed by its corresponding application.

If NdisMCreateLog returns NDIS_STATUS_RESOURCES, the driver can adjust the original Size down and try calling this function again. However, a miniport driver cannot call NdisMCreateLog to create more than one log file after a call succeeds.

Whatever size of log file is allocated, subsequent calls to NdisMWriteLogData store data in this file, which is treated as a circular buffer. That is, a sequence of calls to NdisMWriteLogData eventually overwrites the data originally written to the log file.

Callers of NdisMCreateLog run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisMCloseLog, NdisMFlushLog, NdisMWriteLogData


NdisMDeregisterAdapterShutdownHandler

NdisMDeregisterAdapterShutdownHandler removes a NIC-driver-supplied MiniportShutdown function from the list of registered shut-down handlers to be called.

VOID
  NdisMDeregisterAdapterShutdownHandler(
    IN NDIS_HANDLE  MiniportHandle
    );

Parameters

MiniportHandle
Specifies the handle originally input to MiniportInitialize.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A miniport driver that called NdisMRegisterAdapterShutdownHandler from MiniportInitialize must call NdisMDeregisterAdapterShutdownHandler when it is cleaning up the resources it allocated before being unloaded.

MiniportInitialize also should call NdisMDeregisterAdapterShutdownHandler if the driver has already registered the MiniportShutdown function but MiniportInitialize will fail the initialization.

Callers of NdisMDeregisterAdapterShutdownHandler run at IRQL PASSIVE_LEVEL.

See Also

MiniportHalt, MiniportInitialize, MiniportShutdown, NdisMRegisterAdapterShutdownHandler


NdisMDeregisterDevice

The NdisMDeregisterDevice function removes from the system a device object that was created with NdisMRegisterDevice. NdisMDeregisterDevice also removes the symbolic link that is associated with this device object.

NDIS_STATUS
  NdisMDeregisterDevice(
    IN NDIS_HANDLE  NdisDeviceHandle
    );

Parameters

NdisDeviceHandle
Specifies the handle returned by NdisMRegisterDevice that identifies the device object to be deregistered.

Return Values

NdisMDeregisterDevice returns NDIS_STATUS_SUCCESS if the device object and its associated symbolic link object are deleted.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A driver calls NdisMDeregisterDevice from its Halt or Unload function to deregister a stand-alone device object that it previously created with NdisMRegisterDevice. The driver must call NdisMDeregisterDevice when it is being unloaded or when its DriverEntry routine encounters a fatal initialization error, such as an inability to obtain system resources.

When NdisMRegisterDevice is called, there cannot be any outstanding user-mode open operations on the device object being deleted. If there are, a system error occurs.

Callers of NdisMDeregisterDevice run at IRQL PASSIVE_LEVEL.

See Also

MiniportHalt, NdisMRegisterDevice, NdisMRegisterUnloadHandler


NdisMDeregisterDmaChannel

NdisMDeregisterDmaChannel releases a miniport driver's claim on a DMA channel for its NIC.

VOID
  NdisMDeregisterDmaChannel(
    IN PNDIS_HANDLE  MiniportDmaHandle
    );

Parameters

MiniportDmaHandle
Specifies the handle returned by NdisMRegisterDmaChannel.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The caller should consider MiniportDmaHandle invalid as soon as it is passed to NdisMDeregisterDmaChannel. This function releases the NIC's claim on the DMA channel in the registry.

NdisMDeregisterDmaChannel can be called only from a NIC driver's MiniportInitialize and MiniportHalt functions.

Callers of NdisMDeregisterDmaChannel run at IRQL PASSIVE_LEVEL.

See Also

MiniportHalt, MiniportInitialize, NdisMCompleteDmaTransfer, NdisMRegisterDmaChannel, NdisMSetupDmaTransfer


NdisMDeregisterInterrupt

NdisMDeregisterMiniport releases resources previously allocated with NdisMRegisterInterrupt.

VOID
  NdisMDeregisterInterrupt(
    IN PNDIS_MINIPORT_INTERRUPT  Interrupt
    );

Parameters

Interrupt
Pointer to an interrupt object previously registered with NdisMRegisterInterrupt.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisMDeregisterInterrupt releases the association between the initialized interrupt object at Interrupt and the caller's MiniportISR function. After NdisMRegisterInterrupt returns, NDIS will not call the miniport driver's MiniportISR function or MiniportHandleInterrupt function.

A miniport driver can call NdisMDeregisterInterrupt from its MiniportInitialize or MiniportHalt function only if MiniportInitialize previously made a successful call to NdisMRegisterInterrupt.

The miniport driver should disable its NIC from generating interrupts before it calls NdisMDeregisterInterrupt. After NdisMDeregisterInterrupt returns control, the miniport driver cannot call NdisMSynchronizeWithInterrupt.

Callers of NdisMDeregisterInterrupt run at IRQL PASSIVE_LEVEL.

See Also

MiniportDisableInterrupt, MiniportHalt, MiniportHandleInterrupt, MiniportInitialize, MiniportISR, NdisMRegisterInterrupt, NdisMSynchronizeWithInterrupt


NdisMDeregisterIoPortRange

NdisMDeregisterIoPortRange releases a mapping that was set up with NdisMRegisterIoPortRange during driver initialization.

VOID
  NdisMDeregisterIoPortRange(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN UINT  InitialPort,
    IN UINT  NumberOfPorts,
    IN PVOID  PortOffset
    );

Parameters

MiniportAdapterHandle
Specifies the handle input to MiniportInitialize.
InitialPort
Specifies the bus-relative address of the first port in the range of ports.
NumberOfPorts
Specifies the number of ports in the range.
PortOffset
Specifies the mapped base port address returned by NdisMRegisterIoPortRange.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The miniport driver must pass the same InitialPort and NumberOfPorts to NdisMDeregisterIoPortRange that were passed when MiniportInitialize called NdisMRegisterIoPortRange to get the mapped PortOffset value. That is, a miniport driver cannot call NdisMDeregisterIoPortRange to release a subrange of a mapped port range.

NdisMDeregisterIoPortRange can be called from the MiniportInitialize or MiniportHalt functions only if MiniportInitialize previously made a successful call to NdisMRegisterIoPortRange.

NdisMDeregisterIoPortRange also releases the driver's claim on the I/O port range in the registry.

After it calls NdisMRegisterIoPortRange, the miniport driver can no longer access the NIC's port range with calls to the NdisRaw..Port Xxx functions.

Callers of NdisMDeregisterIoPortRange run at IRQL PASSIVE_LEVEL.

See Also

MiniportHalt, MiniportInitialize, NdisMRegisterIoPortRange


NdisMEthIndicateReceive

NdisMEthIndicateReceive notifies NDIS that an Ethernet packet (or some initial lookahead portion of the packet) has arrived so NDIS can forward the packet to bound protocols.

VOID
  NdisMEthIndicateReceive(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN NDIS_HANDLE  MiniportReceiveContext,
    IN PVOID  HeaderBuffer,
    IN UINT  HeaderBufferSize,
    IN PVOID  LookaheadBuffer,
    IN UINT  LookaheadBufferSize,
    IN UINT  PacketSize
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.
MiniportReceiveContext
Specifies a context handle supplied by the caller. NDIS returns this handle as an input parameter to the MiniportTransferData function if it is called. The miniport driver can use the context area designated by this handle to determine which packet, on which NIC, is being received.
HeaderBuffer
Specifies the base virtual address of the buffered packet header.
HeaderBufferSize
Specifies the size in bytes of the packet header.
LookaheadBuffer
Specifies the base virtual address of a buffer containing the initial LookaheadBufferSize bytes of the data in the packet.
LookaheadBufferSize
Specifies the size in bytes of the lookahead buffer. This value must be at least as large as the lookahead size set when MiniportSetInformation was called with OID_GEN_CURRENT_LOOKAHEAD, or as large as the packet, whichever is smaller. When the packet is smaller than the lookahead size, the lookahead buffer contains the entire frame.

A miniport driver can (and should) set LookaheadBufferSize to something larger than the minimum required if sufficient received data is available on its NIC.

PacketSize
Specifies the size in bytes of the received packet data. This value does not include the HeaderBufferSize.

When PacketSize is larger than the given LookaheadBufferSize, a protocol driver call to NdisTransferData causes a subsequent call to the MiniportTransferData function, which transfers the remaining data in the packet.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A miniport driver calls NdisMEthIndicateReceive if it designates its NIC as of type NdisMedium802_3 or NdisMediumDix in response to the OID_GEN_MEDIA_IN_USE query, unless the miniport driver indicates receives with NdisMIndicateReceivePacket.

When a miniport driver calls NdisMEthIndicateReceive, NDIS passes a pointer to the header of the packet and a pointer to some or all of the data in the packet to the ProtocolReceive function(s) of bound protocol driver(s). Each protocol that receives the indication can do the following:

  1. Inspect the header and data in the packet to decide whether the indication is of interest to the protocol's client(s).
  2. If it is, copy as much of the header or data as is visible into protocol-allocated memory with NdisMoveMemory.
  3. Get the remaining data, if any, for the indication by allocating a packet descriptor with sufficient chained buffer descriptors and calling NdisTransferData. The call to NdisTransferData causes the NIC driver's MiniportTransferData function to copy the data into the protocol-supplied packet.

For any protocol driver that receives an indication through NdisMEthIndicateReceive, the HeaderBuffer and LookaheadBuffer addresses are valid only during the current call to its ProtocolReceive function, and these buffers are read-only. A protocol driver cannot retain a pointer to the indicated packet with these associated buffers nor can it retain any pointers to these buffers for later use. Any data that a protocol driver needs from such a packet must be copied and saved during the receive indication.

The data in the header is the same as that received on the NIC. A miniport driver need not remove any headers or trailers from the data its NIC receives.

The transmitting driver adds padding to any packet that is too short for the requirements of the medium. The receiving miniport driver can include such padding in the data and length it subsequently indicates. Each bound protocol is responsible for detecting any such padding and ignoring it.

Serialized callers of NdisMEthIndicateReceive run at IRQL DISPATCH_LEVEL. Deserialized callers of NdisMEthIndicateReceive can run at <= IRQL DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportInitialize, MiniportQueryInformation, MiniportSetInformation, MiniportTimer, MiniportTransferData, NdisMEthIndicateReceiveComplete, NdisMIndicateReceivePacket, NdisMoveMemory, NdisTransferData, ProtocolReceive


NdisMEthIndicateReceiveComplete

NdisMEthIndicateReceiveComplete notifies NDIS that an Ethernet receive packet, identified in a preceding call to NdisMEthIndicateReceive, has been fully transferred by the NIC so that NDIS can notify the appropriate bound protocols.

VOID
  NdisMEthIndicateReceiveComplete(
    IN NDIS_HANDLE  MiniportAdapterHandle
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

After any Ethernet receive indication, a miniport driver eventually must call NdisMEthIndicateReceiveComplete to indicate the end of the transfer operation over the net, even if a particular packet is accepted by no bound protocol.

NdisMEthIndicateReceiveComplete both indicates the completion of a transfer operation for a receive and notifies any bound protocol that has already consumed the initial indication that it can begin postprocessing the received data.

When a miniport driver calls NdisMEthIndicateReceiveComplete, NDIS indicates the completion of the receive operation to each such protocol by calling its ProtocolReceiveComplete function.

ProtocolReceiveComplete functions need not operate under the severe time constraints of the corresponding ProtocolReceive functions. However, another receive indication to the ProtocolReceive function can come in while the ProtocolReceiveComplete function is running.

A miniport driver need not call NdisMEthIndicateReceiveComplete in one-to-one correspondence with its calls to NdisMEthIndicateReceive. That is, a NIC driver can issue a single receive-complete indication for some number of receive indications, particularly when network traffic is high. For example, when a miniport driver is continually indicating receives from the same source, it might call NdisMEthIndicateReceiveComplete once for every ten indications. On the other hand, a miniport driver might call NdisMEthIndicateReceiveComplete once for each indication when network traffic is low so that the driver can regain ownership of the memory it allocated for receives promptly. However, a miniport driver must call NdisMEthIndicateReceiveComplete at least once per batch of packets indicated from its MiniportHandleInterrupt function.

Serialized callers of NdisMEthIndicateReceiveComplete run at IRQL DISPATCH_LEVEL. Deserialized callers of NdisMEthIndicateReceiveComplete can run at <= IRQL DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportInitialize, NdisMEthIndicateReceive, ProtocolReceive, ProtocolReceiveComplete


NdisMFddiIndicateReceive

NdisMFddiIndicateReceive notifies NDIS that an FDDI packet (or some initial lookahead portion of the packet) has arrived so NDIS can forward the packet to bound protocols.

VOID
  NdisMFddiIndicateReceive(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN NDIS_HANDLE  MiniportReceiveContext,
    IN PVOID  HeaderBuffer,
    IN UINT  HeaderBufferSize,
    IN PVOID  LookaheadBuffer,
    IN UINT  LookaheadBufferSize,
    IN UINT  PacketSize
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.
MiniportReceiveContext
Specifies a context handle supplied by the caller. NDIS returns this handle as an input parameter to the MiniportTransferData function if it is called. The miniport driver can use the context area designated by this handle to determine which packet, on which NIC, is being received.
HeaderBuffer
Specifies the base virtual address of the buffered packet header.
HeaderBufferSize
Specifies the size in bytes of the packet header.
LookaheadBuffer
Specifies the base virtual address of a buffer containing the initial LookaheadBufferSize bytes of the data in the packet.
LookaheadBufferSize
Specifies the size in bytes of the lookahead buffer. This value must be at least as large as the lookahead size set when MiniportSetInformation was called with OID_GEN_CURRENT_LOOKAHEAD, or as large as the packet, whichever is smaller. When the packet is smaller than the lookahead size, the lookahead buffer contains the entire frame.

A miniport driver can (and should) set LookaheadBufferSize to something larger than the minimum required if sufficient received data is available on its NIC.

PacketSize
Specifies the size in bytes of the received packet data. This value does not include the HeaderBufferSize.

When PacketSize is larger than LookaheadBufferSize, a protocol driver call to NdisTransferData causes a subsequent call to the MiniportTransferData function, which transfers the remaining data in the packet.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A miniport driver calls NdisMFddiIndicateReceive if it designates its NIC as of type NdisMediumFddi in response to the OID_GEN_MEDIA_IN_USE query, unless the miniport driver indicates receives with NdisMIndicateReceivePacket.

When a miniport driver calls NdisMFddiIndicateReceive, NDIS passes a pointer to the header of the packet and a pointer to some or all of the data in the packet to the ProtocolReceive function(s) of bound protocol driver(s). Each protocol that receives the indication can do the following:

  1. Inspect the header and data in the packet to decide whether the indication is of interest to the protocol's client(s).
  2. If it is, copy as much of the header or data as is visible into protocol-allocated memory with NdisMoveMemory.
  3. Get the remaining data, if any, for the indication by allocating a packet descriptor with sufficient chained buffer descriptors and calling NdisTransferData. The call to NdisTransferData causes the NIC driver's MiniportTransferData function to copy the data into the protocol-supplied packet.

For any protocol driver that receives an indiation through NdisMFddiIndicateReceive, the HeaderBuffer and LookaheadBuffer addresses are valid only during the current call to its ProtocolReceive function, and these buffers are read-only. A protocol driver cannot retain a pointer to the indicated packet with these associated buffers nor can it retain any pointers to these buffers for later use. Any data that a protocol driver needs from such a packet must be copied and saved during the receive indication.

The data in the header is the same as that received on the NIC. A miniport driver need not remove any headers or trailers from the data its NIC receives.

The transmitting driver adds padding to any packet that is too short for the requirements of the medium. The receiving miniport driver can include such padding in the data and length it subsequently indicates. Each bound protocol is responsible for detecting any such padding and ignoring it.

Serialized callers of NdisMFddiIndicateReceive run at IRQL DISPATCH_LEVEL. Deserialized callers of NdisMFddiIndicateReceive can run at <= IRQL DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportInitialize, MiniportQueryInformation, MiniportSetInformation, MiniportTimer, MiniportTransferData, NdisMFddiIndicateReceiveComplete, NdisMIndicateReceivePacket, NdisTransferData, ProtocolReceive


NdisMFddiIndicateReceiveComplete

NdisMFddiIndicateReceiveComplete notifies NDIS that an FDDI receive packet, identified in a preceding call to NdisMFddiIndicateReceive, has been fully transferred by the NIC so that NDIS can notify the appropriate bound protocol drivers.

VOID
  NdisMFddiIndicateReceiveComplete(
    IN NDIS_HANDLE  MiniportAdapterHandle
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

After any FDDI receive indication, a miniport driver eventually must call NdisMFddiIndicateReceiveComplete to indicate the end of the transfer operation over the net, even if a particular packet is accepted by no bound protocol.

NdisMFddiIndicateReceiveComplete both indicates the completion of a transfer operation for a receive and notifies any bound protocol that has already consumed the initial indication that it can begin postprocessing the received data.

When a miniport driver calls NdisMFddiIndicateReceiveComplete, NDIS indicates the completion of the receive operation to each such protocol by calling its ProtocolReceiveComplete function.

ProtocolReceiveComplete functions need not operate under the severe time constraints of the corresponding ProtocolReceive functions. However, another receive indication to the ProtocolReceive function can come in while the ProtocolReceiveComplete function is running.

A miniport driver need not call NdisMFddiIndicateReceiveComplete in one-to-one correspondence with its calls to NdisMFddiIndicateReceive. That is, a NIC driver can issue a single receive-complete indication for some number of receive indications, particularly when network traffic is high. For example, when a miniport driver is continually indicating receives from the same source, it might call NdisMFddiIndicateReceiveComplete once for every ten indications. On the other hand, a miniport driver might call NdisMFddiIndicateReceiveComplete once for each indication when network traffic is low so that the driver can regain ownership of the memory it allocated for receives promptly. However, a miniport driver must call NdisMFddiIndicateReceiveComplete at least once per batch of packets indicated from its MiniportHandleInterrupt function.

Serialized callers of NdisMFddiIndicateReceiveComplete run at IRQL DISPATCH_LEVEL. Deserialized callers of NdisMFddiIndicateReceiveComplete can run at <= IRQL DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportInitialize, NdisMFddiIndicateReceive, ProtocolReceive, ProtocolReceiveComplete


NdisMFlushLog

NdisMFlushLog clears the log file.

VOID
  NdisMFlushLog(
    IN NDIS_HANDLE  LogHandle
    );

Parameters

LogHandle
Specifies the handle returned by NdisMCreateLog.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisMFlushLog resets the position pointers within the log file to the start of the file.

The driver must release any spin lock it is holding before calling NdisMFlushLog.

Callers of NdisMFlushLog can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisMCloseLog, NdisMCreateLog, NdisMWriteLogData, NdisReleaseSpinLock


NdisMFreeMapRegisters

NdisMFreeMapRegisters releases a set of map registers that were allocated during initialization with NdisMAllocateMapRegisters by a bus-master DMA NIC driver.

VOID
  NdisMFreeMapRegisters(
    IN NDIS_HANDLE  MiniportAdapterHandle
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If it has already made a successful call to NdisMAllocateMapRegisters, the NIC driver of a bus-master DMA device calls NdisMFreeMapRegisters if any of the following occurs:

  • Its MiniportInitialize function is unable to initialize the NIC, so this function must release all existing claims on hardware resources for that NIC before it returns control.
  • The NIC for which the miniport driver allocated the map registers is being removed.
  • The driver is being unloaded, either because the system is shutting down or because the user reconfigured the network components used in the machine.

As soon as it calls NdisMFreeMapRegisters, the driver of a bus-master DMA NIC can no longer use the map registers it previously allocated.

NdisMFreeMapRegisters can be called only from a NIC driver's MiniportInitialize and MiniportHalt functions.

Before calling NdisMFreeMapRegisters, a NIC driver must free any shared memory that it previously allocated. A driver frees shared memory by calling NdisMFreeSharedMemory.

Callers of NdisMFreeMapRegisters run at IRQL PASSIVE_LEVEL.

See Also

MiniportHalt, MiniportInitialize, NdisMAllocateMapRegisters, NdisMFreeSharedMemory


NdisMFreeSharedMemory

NdisMFreeSharedMemory frees memory that was previously allocated by NdisMAllocateSharedMemory or NdisMAllocateSharedMemoryAsync by the driver of a bus-master DMA NIC.

VOID
  NdisMFreeSharedMemory(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN ULONG  Length,
    IN BOOLEAN  Cached,
    IN PVOID  VirtualAddress,
    IN NDIS_PHYSICAL_ADDRESS  PhysicalAddress
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.
Length
Specifies the number of bytes originally allocated.
Cached
Specifies TRUE if the original allocation was cacheable.
VirtualAddress
Specifies the base virtual address returned by NdisMAllocateSharedMemory(Async).
PhysicalAddress
Specifies the corresponding physical address returned by NdisMAllocateSharedMemory(Async).

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If it has already made a successful call to NdisMAllocateSharedMemory or NdisMAllocateSharedMemoryAsync, the NIC driver of a bus-master DMA device calls NdisMFreeSharedMemory if any of the following occurs:

  • Its MiniportInitialize function is unable to initialize the NIC, so this function must release all existing claims on hardware resources for that NIC before it returns control.
  • The NIC for which the miniport driver allocated the memory is being removed.
  • The driver is being unloaded, whether because the system is shutting down or because the user reconfigured the network components used in the machine.
  • The driver allocated additional shared memory with NdisMAllocateSharedMemoryAsync when I/O demand on its NIC was high but network traffic has now subsided to an average level.

A miniport driver cannot call NdisMFreeSharedMemory to free a subrange within an allocated shared memory range. The parameters passed to NdisMFreeSharedMemory must match exactly those that were passed to NdisMAllocateSharedMemory or NdisMAllocateSharedMemoryAsync.

NdisMFreeSharedMemory cannot be called from a MiniportShutdown function.

Before calling NdisMFreeMapRegisters, a miniport driver must free any shared memory that it has allocated.

Callers of NdisMFreeSharedMemory run at IRQL DISPATCH_LEVEL, except when in the context of MiniportHalt or MiniportInitialize (a failed initialization code path), in which case callers of this function must run at at IRQL PASSIVE_LEVEL.

See Also

MiniportAllocateComplete, MiniportHalt, MiniportInitialize, MiniportShutdown, NdisMAllocateSharedMemory, NdisMAllocateSharedMemoryAsync, NdisMFreeMapRegisters


NdisMGetDeviceProperty

NdisMGetDeviceProperty retrieves device objects required to set up communication with a miniport driver through a bus driver.

VOID
  NdisMGetDeviceProperty(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN OUT PDEVICE_OBJECT  *PhysicalDeviceObject  OPTIONAL,
    IN OUT PDEVICE_OBJECT  *FunctionalDeviceObject  OPTIONAL,
    IN OUT PDEVICE_OBJECT  *NextDeviceObject  OPTIONAL,
    IN OUT PCM_RESOURCE_LIST  *AllocatedResources  OPTIONAL,
    IN OUT PCM_RESOURCE_LIST  *AllocatedResourcesTranslated  OPTIONAL
    );

Parameters

MiniportAdapterHandle
Specifies the NDIS handle that identifies the miniport driver's NIC. This handle was originally passed to MiniportInitialize.
PhysicalDeviceObject
Pointer to a caller-allocated buffer. The buffer receives a pointer to a DEVICE_OBJECT structure that represents the physical device for the miniport driver. This pointer is optional.
FunctionalDeviceObject
Pointer to a caller-allocated buffer. The buffer receives a pointer to a DEVICE_OBJECT structure. DEVICE_OBJECT represents the functional device object that NDIS creates for the physical device. This pointer is optional.
NextDeviceObject
Pointer to a caller-allocated buffer. The buffer receives a pointer to a DEVICE_OBJECT structure that represents the next device object. This next device object is preceded in the chain by the functional device object that belongs to the miniport driver. NDIS creates this functional device object for the physical device. For example, the next device object could be the object that is associated with a bus driver or HAL This pointer is optional.
AllocatedResources
Pointer to a caller-allocated buffer thatreceives a pointer to a CM_RESOURCE_LIST structure. CM_RESOURCE_LIST describes a list of hardware resources that the PnP Manager assigns to the physical device. This list contains the resources in raw form, that is, not translated by HAL. This pointer is optional.
AllocatedResourcesTranslated
Pointer to a caller-allocated buffer that receives a pointer to a CM_RESOURCE_LIST structure. CM_RESOURCE_LIST describes a list of hardware resources that the PnP Manager assigns to the physical device. This list contains the resources in translated form, that is, translated by HAL. This pointer is optional.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Miniport drivers must retrieve specific information to set up their communications. Miniport drivers for miniport instances that communicate through bus drivers use NdisMGetDeviceProperty to retrieve this information. For example, miniport driver instances that attach to Universal Serial Bus (USB) or IEEE 1394 buses require miniport drivers that expose a standard NDIS miniport driver interface at their upper edge, and use the class interface for the particular bus at their lower edge. To use the USB or 1394 class interface, a miniport driver creates and submits I/O Request Packets (IRPs). The miniport driver uses the physical and next-device objects that NdisMGetDeviceProperty retrieves to submit IRPs to the class interface for a particular bus. To locate more information on creating and submitting IRPs to bus drivers, see Handling IRPs.

Pointers to DEVICE_OBJECT for the physical, functional, and next device objects that NdisMGetDeviceProperty retrieves are simply handles that are opaque to the miniport driver.

Typically, miniport drivers call the NdisMQueryAdapterResources function and pass a pointer to an NDIS_RESOURCE_LIST structure to obtain a list of hardware resources for their NICs. The NDIS_RESOURCE_LIST structure is equivalent to the CM_PARTIAL_RESOURCE_LIST structure on Windows 2000 and later platforms. Alternatively, miniport drivers can call NdisMGetDeviceProperty to retrieve pointers to "raw" or "translated" resources. Raw resources have not been translated by HAL; translated resources have been. To locate more information on raw and translated resources, see Plug and Play.

Note that if a Microsoft® Windows 95/98/Me miniport driver requests a pointer to either raw or translated resources, NDIS sets the AllocatedResources and AllocatedResourcesTranslated parameters to NULL.

Callers of NdisMGetDeviceProperty run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisMQueryAdapterResources


NdisMGetDmaAlignment

NdisMGetDmaAlignment returns the alignment requirements of the DMA system for a NIC.

ULONG
  NdisMGetDmaAlignment(
    IN NDIS_HANDLE  MiniportAdapterHandle
    );

Parameters

MiniportAdapterHandle
NDIS handle that identifies the miniport driver's NIC. This handle was originally passed to MiniportInitialize.

Return Value

Returns a value that specifies the alignment requirements of the DMA system.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A miniport driver can call the NdisMGetDmaAlignment function to determine alignment requirements for DMA buffers it allocates. A miniport driver might require increasing the returned value because of additional hardware device restrictions. A miniport driver should call the NdisMAllocateMapRegisters or NdisMInitializeScatterGatherDma function before calling NdisMGetDmaAlignment.

System support for NdisMGetDmaAlignment is available in Windows XP and later OS versions. Earlier NT-based OS versions and Windows 98/Me support the NdisGetCacheFillSize function for retrieving alignment requirements.

Callers of NdisMGetDmaAlignment must be running at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisGetCacheFillSize, NdisMAllocateMapRegisters, NdisMInitializeScatterGatherDma


NdisMIndicateReceivePacket

NdisMIndicateReceivePacket notifies NDIS that an array of received packets is available to be forwarded to the appropriate bound protocol driver(s).

VOID
  NdisMIndicateReceivePacket(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN PPNDIS_PACKET  ReceivePackets,
    IN UINT  NumberOfPackets
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.
ReceivePackets
Pointer to an array of packet descriptor pointers, with each descriptor set up by the caller to specify the received data.
NumberOfPackets
Specifies how many pointers are in the array at ReceivePackets. The value must be at least one.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Drivers of bus-master DMA NICs are most likely to show significant gains in performance by making multipacket receive indications with NdisMIndicateReceivePacket. However, drivers that indicate out-of-band data, such as packet priority and/or timestamps, with receive packets can also call this function with a single packet at a time.

When a miniport driver calls NdisMIndicateReceivePacket, NDIS passes each pointer at ReceivePackets separately, in the miniport driver-determined order, to the ProtocolReceivePacket function(s) of bound protocol(s) that export this function. To other bound protocols, NDIS passes each packet pointer to the ProtocolReceive function(s).

If the miniport driver did not designate its NIC's medium as a type for which the system supplies a filter package in response to the OID_GEN_MEDIA_IN_USE query, NDIS forwards that driver's receive indications to all bound protocol drivers that export a ProtocolReceivePackets function. Otherwise, NDIS automatically applies the appropriate filter library to the miniport driver's receive indications.

Any caller of NdisMIndicateReceivePacket must first set up the packet array, as follows:

  • Each element is the pointer to a packet descriptor, which the caller must allocate from packet pool. Each packet descriptor has 4*sizeof(PVOID) in its ProtocolReserved section. On 32-bit systems, four pointer's worth of ProtocolReserved space equals 16 bytes. On 64-bit systems, four pointer's worth of ProtocolReserved space equals 32 bytes.
  • All buffer descriptors chained to such a packet descriptor must be allocated from buffer pool. The miniport driver must call NdisAdjustBufferLength with any buffer descriptor mapping a receive buffer on the NIC that contains less received data than the full range of the receive buffer so that the buffer descriptor will map only the received data for the indication. (The NIC driver must readjust the mapping with NdisAdjustBufferLength when it regains ownership of such a buffer descriptor, as well.)
  • The first buffer in the packet must contain the amount of data specified by the lookahead setting plus the data size of the MAC header. The miniport driver receives the lookahead setting in a set to OID_GEN_CURRENT_LOOKAHEAD. If the total packet size including the MAC header is less than the lookahead setting plus the MAC header size, the first buffer must contain the entire packet.
  • If the miniport driver indicates timestamps for received packets, it must set the TimeReceived and/or TimeSent members in the NDIS_PACKET_OOB_DATA associated with the packet descriptor, using the NDIS_SET_PACKET_TIME_RECEIVED and/or NDIS_SET_PACKET_TIME_SENT macros. It can call NdisGetCurrentSystemTime once to set the receive timestamp for all packets of a particular packet array.
  • The HeaderSize in the out-of-band data block must match the header size of each received packet for the medium. For example, a driver that selects Ethernet as its preferred medium initializes the NDIS_PACKET_OOB_DATA block HeaderSize to 14 when it allocates the packet descriptor. A driver should use the NDIS_SET_PACKET_HEADER_SIZE macro to set the HeaderSize.
  • If the driver indicates additional out-of-band information with receives, it must set the SizeMediaSpecificInfo to the number of bytes of information supplied in the caller-allocated buffer at MediaSpecificInformation. The miniport driver can use the NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO macro to set these values. Otherwise, SizeMediaSpecificInfo should be zero, and MediaSpecificInformation should be NULL.
  • The miniport driver can set the Status member of the out-of-band data block to NDIS_STATUS_RESOURCES if it needs to retain ownership of the packet descriptor and buffer descriptors of some element in a particular indication. Setting NDIS_STATUS_RESOURCES forces NDIS to indicate each such packet, one at a time, to bound protocols' ProtocolReceive functions, thereby forcing each protocol to copy the packet data and release each packet to be returned back to the miniport driver.
  • A deserialized miniport driver must save the Status member of the out-of-band data block in a local variable before indicating up the packet descriptor. As explained in more detail below, when NdisMIndicateReceivePacket returns, a deserialized miniport driver must check the saved packet Status to determine whether it can immediately reclaim the packet descriptor and the associated buffers.

If a serialized miniport driver does not set a packet's Status member to NDIS_STATUS_RESOURCES, the call to NdisMIndicateReceivePacket gives interested protocols exclusive, read-only access to the buffers chained to each packet. The miniport driver regains ownership of the packet descriptor and the associated buffers as follows:

  • If the Status in the out-of-band data block is set to NDIS_STATUS_SUCCESS on return from NdisMIndicateReceivePacket, the miniport driver immediately regains ownership of the packet descriptor and all buffers chained to the packet. It can prepare these descriptors for reuse in subsequent receive indications.
  • If the Status is set to NDIS_STATUS_PENDING on return from NdisMIndicateReceivePacket, the miniport driver regains ownership of the packet descriptor and all buffers chained to the packet when NDIS subsequently calls the miniport driver's MiniportReturnPacket function. It can then prepare these descriptors for reuse in subsequent receive indications.

A serialized miniport driver should use NDIS_GET_PACKET_STATUS to determine whether it has regained ownership of indicated packets when NdisMIndicateReceivePacket returns control.

A deserialized miniport driver must not examine the Status of indicated packets on return of NdisMIndicateReceivePacket. Instead, a deserialized miniport driver must save a packet's Status in a local variable before indicating up the packet descriptor. When NdisMIndicateReceivePacket returns, the miniport driver should check the saved packet Status. If the miniport driver set the packet's Status to NDIS_STATUS_RESOURCES before indicating up the packet descriptor, it should reclaim the packet descriptor immediately after NdisMIndicateReceivePacket returns, preferably by calling its own MiniportReturnPacket function. In this case, NDIS does not call the miniport driver's MiniportReturnPacket function to return the packet descriptor. If the miniport driver set the packet's Status to NDIS_STATUS_SUCCESS before indicating up the packet descriptor, the miniport driver must not reclaim the packet descriptor until NDIS subsequently returns the packet descriptor to the miniport driver's MiniportReturnPacket function.

When the miniport driver regains ownership of an indicated packet descriptor, it can prepare the associated out-of-band data block for reuse by passing the pointer returned by NDIS_OOB_DATA_FROM_PACKET to NdisZeroMemory. As an alternative, the miniport driver can simply reset the relevant member(s) at the subsequent receive with the NDIS_SET_PACKET_XXX macro(s) or with the pointer returned by NDIS_OOB_DATA_FROM_PACKET.

A miniport driver must not pass a packet descriptor pointer to NdisZeroMemory. Doing this destroys the packet descriptor, rendering it unusable for subsequent indications. To clear the associated out-of-band data block, the driver must pass the pointer returned by NDIS_OOB_DATA_FROM_PACKET.

Packet arrays passed to NdisMIndicateReceivePacket can be allocated on the stack, which cannot be paged out in the NDIS library's receive-indication code path.

When NDIS calls the ProtocolReceive function of a driver that exports a ProtocolReceivePacket function, ProtocolReceive can call NdisGetReceivedPacket and NDIS_GET_ORIGINAL_PACKET to retrieve the out-of-band information associated with an incoming packet that was indicated as part of a packet array.

Any miniport driver that calls NdisMIndicateReceivePacket must indicate full packets. Consequently, such a driver has no MiniportTransferData function.

Serialized callers of NdisMIndicateReceivePacket must run at IRQL DISPATCH_LEVEL. Deserialized callers of NdisMIndicateReceivePacket can run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportInitialize, MiniportQueryInformation, MiniportReturnPacket, MiniportTimer, NdisAdjustBufferLength, NdisAllocateBuffer, NdisAllocatePacket, NdisChainBufferAtBack, NdisChainBufferAtFront, NdisGetCurrentSystemTime, NDIS_GET_ORIGINAL_PACKET, NDIS_GET_PACKET_STATUS, NdisGetReceivedPacket, NdisMAllocateSharedMemoryAsync, NDIS_OOB_DATA_FROM_PACKET, NDIS_PACKET, NDIS_PACKET_OOB_DATA, NDIS_SET_PACKET_TIME_RECEIVED, NDIS_SET_PACKET_TIME_SENT, NdisZeroMemory, OID_GEN_CURRENT_LOOKAHEAD, ProtocolReceive, ProtocolReceivePacket


NdisMIndicateStatus

NdisMIndicateStatus indicates changes in the status of a NIC to higher-level NDIS drivers.

VOID
  NdisMIndicateStatus(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN NDIS_STATUS  GeneralStatus,
    IN PVOID  StatusBuffer,
    IN UINT  StatusBufferSize
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.
GeneralStatus
Specifies the NDIS_STATUS_XXX value that indicates the general change in status for the NIC.
StatusBuffer
Pointer to a caller-allocated buffer containing data that is medium-specific and dependent on the value of GeneralStatus. It indicates detailed information about the change in status.
StatusBufferSize
Specifies the size in bytes of the buffer at StatusBuffer.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

When a miniport driver calls NdisMIndicateStatus, NDIS calls each bound protocol's ProtocolStatus function. This allows a bound protocol driver or, possibly, the configuration manager to log the change in status of an underlying NIC or to take corrective action. For example, a protocol might call NdisReset, depending on the NDIS_STATUS_XXX indicated.

When a miniport driver calls NdisMIndicateStatus to report a change in NIC status, NDIS can call the MiniportReset function to try restoring the NIC to a working condition. In these circumstances, NDIS can call bound protocols only with NDIS_STATUS_RESET_START and later with NDIS_STATUS_RESET_END, rather than with the GeneralStatus indicated by the miniport driver.

NdisMIndicateStatus provides two pieces of information:

  • An overall status value indicating the general change in status.
  • A specific reason for the general change, which can be network-specific. For example, ring-insertion failures are particular to Token Ring (802.5) networks, but are irrelevant to Ethernet (802.3) NICs and their drivers.

A miniport driver also can call NdisMIndicateStatus to indicate problems such as cables that have been accidentally removed and then reinserted, or a ring that has temporarily failed. For example, suppose both the following conditions occur:

  • The miniport driver calls NdisMIndicateStatus with NDIS_STATUS_RING_STATUS.
  • The StatusBuffer contains one of the following status values:
    NDIS_RING_LOBE_WIRE_FAULT
    NDIS_RING_HARD_ERROR
    NDIS_RING_SIGNAL_LOSS

After such a change in status has been signaled with an indication, any associated thresholds or statistics counters remain unchanged.

A miniport driver cannot call NdisMIndicateStatus in the context of its MiniportInitialize, MiniportISR, MiniportHalt, or MiniportShutdown function.

Serialized callers of NdisMIndicateStatus run at IRQL DISPATCH_LEVEL. Deserialized callers of NdisMIndicateStatus can run at <= IRQL DISPATCH_LEVEL.

Indicating the Loss and Restoration of a Network Connection

When a miniport driver senses that the network connection has been lost, it should call NdisMIndicateStatus with NDIS_STATUS_MEDIA_DISCONNECT. When the connection is restored, the miniport driver should call NdisMIndicateStatus with NDIS_STATUS_MEDIA_CONNECT.

WAN Miniport Driver Calls to NdisMIndicateStatus

Most WAN NIC drivers indicate status with some special status codes and buffer contents. These status indications are generated by WAN NIC drivers, and NDIS protocol drivers bound to such a miniport driver can ignore these indications. However, processing these indications correctly usually results in improved performance for protocols and for WAN NIC drivers.

The following four types of WAN-specific indications can be sent to bound protocol drivers with NdisMIndicateStatus:

  1. Line up
  2. Line down
  3. Fragment
  4. TAPI line event

NDIS_STATUS_WAN_LINE_UP

A WAN miniport driver makes a line-up indication whenever a new link becomes active. Until this occurs, the NIC will accept frames and let them succeed or fail, but it is unlikely that they will actually be received by any remote node. Until this occurs, protocols should reduce their timers and retry counts so as to quickly fail any outgoing connection attempts.

The WAN miniport driver makes this indication with NdisMIndicateStatus before it returns from the OID_TAPI_GET_ID request.

The status code for the line-up indication is NDIS_STATUS_WAN_LINE_UP. The buffer at StatusBuffer is formatted as an NDIS_MAC_LINE_UP structure.

NDIS_STATUS_WAN_LINE_DOWN

A WAN miniport driver makes a line-down indication whenever a link goes down. When this occurs, bound protocols should reduce their timers and retry counts until the next line-up indication.

The status code for the line-down indication is NDIS_STATUS_WAN_LINE_DOWN. The buffer at StatusBuffer is formatted as an NDIS_MAC_LINE_DOWN structure.

NDIS_STATUS_WAN_FRAGMENT

A WAN miniport driver makes a fragment indication whenever it receives a partial packet from the remote node. When this occurs, a bound protocol should send frames to the remote that will notify it of this situation, rather than waiting for a time-out to occur.

The status code for the fragment indication is NDIS_STATUS_WAN_FRAGMENT. The buffer at StatusBuffer is formatted as an NDIS_MAC_FRAGMENT structure.

NDISWAN monitors dropped packets by counting the number of fragment indications on each link.

NDIS_TAPI_EVENT

A WAN miniport driver must use a GeneralStatus value of NDIS_STATUS_TAPI_INDICATION for TAPI status indications. The buffer at StatusBuffer is formatted as an NDIS_TAPI_EVENT structure.

See Also

MiniportInitialize, MiniportReset, NDIS_MAC_FRAGMENT, NDIS_MAC_LINE_DOWN, NDIS_MAC_LINE_UP, NdisMIndicateStatusComplete, NDIS_TAPI_EVENT, ProtocolStatus


NdisMIndicateStatusComplete

NdisMIndicateStatusComplete notifies NDIS (or NDISWAN) that the NIC driver, which has called NdisMIndicateStatus one or more times to indicate hardware anomalies or run-time state changes in the NIC, is ready to resume normal device I/O operations.

VOID
  NdisMIndicateStatusComplete(
    IN NDIS_HANDLE  MiniportAdapterHandle
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

When a miniport driver calls NdisMIndicateStatusComplete, NDIS calls the ProtocolStatusComplete function(s) of bound protocol(s) that were previously notified of the immediately preceding state change(s) in the underlying NIC with calls to their ProtocolStatus functions.

A miniport driver eventually must call NdisMIndicateStatusComplete after it calls NdisMIndicateStatus. However, a miniport driver need not deliver NdisMIndicateStatusComplete indications in one-to-one correspondence with its NdisMIndicateStatus indications. It can choose to issue a single status-complete indication for several status indications that have occurred, particularly when network traffic is high.

A protocol driver writer should assume that interrupts are enabled on the NIC while the ProtocolStatusComplete function is running. A protocol driver writer also should assume that the ProtocolStatus function is re-entrant while the ProtocolStatusComplete function is running, particularly on an SMP platform.

Serialized callers of NdisMIndicateStatusComplete run at IRQL DISPATCH_LEVEL. Deserialized callers of NdisMIndicateStatusComplete can run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportInitialize, NdisMIndicateStatus, ProtocolStatusComplete


NdisMInitializeScatterGatherDma

NdisMInitializeScatterGatherDma, which is called by miniport drivers that manage bus-master DMA NICs, initializes system resources during miniport driver initialization for use in subsequent DMA operations.

NDIS_STATUS
  NdisMInitializeScatterGatherDma(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN BOOLEAN  Dma64BitAddresses,
    IN ULONG  MaximumPhysicalMapping
    );

Parameters

MiniportAdapterHandle
Specifies the handle input to MiniportInitialize.
Dma64BitAddresses
Specifies TRUE if the NIC can use 64-bit addressing for DMA operations. Specifies FALSE if the NIC can use only 32-bit addressing for DMA operations.
MaximumPhysicalMapping
Specifies the maximum number of bytes that the NIC can transfer as a single DMA operation.

Return Value

NdisMInitializeScatterGatherDma can return one of the following:

NDIS_STATUS_SUCCESS
System resources were successfully allocated for bus-master DMA operations.
NDIS_STATUS_RESOURCES
System resources could not be allocated due to system resource constraints.
NDIS_STATUS_NOT_SUPPORTED
The caller did not register as an NDIS 5.0 or NDIS 5.1 miniport driver when it called NdisMRegisterMiniport or the caller did not specify that its NIC is a bus-master DMA device when it called NdisMSetAttributes or NdisMSetAttributesEx.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A miniport driver that manages a bus-master DMA NIC calls NdisMInitializeScatterGatherDma from its MiniportInitialize function. The miniport driver must call NdisMInitializeScatterGatherDma after calling NdisMSetAttributes or NdisMSetAttributesEx and before calling NdisMAllocateSharedMemory.

NdisMInitializeScatterGatherDma reserves system resources for DMA operations performed by the miniport driver. A miniport driver that calls NdisMInitializeScatterGatherDma does not have to allocate map registers for DMA operations or release such registers on the completion of DMA operations.

If MiniportInitialize did not specify that the NIC is a bus master when it called NdisMSetAttributes or NdisMSetAttributesEx, NdisMInitializeScatterGatherDma simply returns control without attempting to reserve system resources.

NdisMInitializeScatterGatherDma supports only 32-bit and 64-bit DMA addresses. It does not support 24-bit DMA addresses.

A miniport driver that calls NdisMInitializeScatterGatherDma during DMA initialization does the following to obtain the mapped logical address ranges of buffers containing DMA data: for each packet descriptor passed to its MiniportSend or Miniport(Co)SendPackets function, the miniport driver calls NDIS_PER_PACKET_INFO_FROM_PACKET with an InfoType of ScatterGatherListPacketInfo. The miniport driver supplies the obtained logical address ranges to its NIC so that the NIC can perform the DMA transfer.

Callers of NdisMInitializeScatterGatherDma run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisMAllocateSharedMemory, NdisMRegisterMiniport, NdisMSetAttributes, NdisMSetAttributesEx, NdisMStartBufferPhysicalMapping, NDIS_PER_PACKET_INFO_FROM_PACKET, NdisQueryPacket, SCATTER_GATHER_LIST


NdisMInitializeTimer

NdisMInitializeTimer initializes a timer object associated with a driver's MiniportTimer function.

VOID
  NdisMInitializeTimer(
    IN OUT PNDIS_MINIPORT_TIMER  Timer,
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN PNDIS_TIMER_FUNCTION  TimerFunction,
    IN PVOID  FunctionContext
    );

Parameters

Timer
Pointer to caller-supplied, resident storage for a timer object. The timer object is opaque to the caller, but, when it has been initialized, this pointer is a required parameter to the NdisM..Timer functions.
MiniportAdapterHandle
Specifies the handle input to MiniportInitialize.
TimerFunction
Specifies the entry point of a caller-supplied MiniportTimer function.
FunctionContext
Pointer to a caller-supplied context area to be passed to the given MiniportTimer function when it is called.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

After calling NdisMSetAttributes(Ex), a miniport driver's MiniportInitialize function can call NdisMInitializeTimer to set up MiniportTimer function(s). MiniportInitialize must call NdisMInitializeTimer before the driver passes the MiniportTimer pointer to any other NdisM..Timer function.

Drivers of NICs that do not generate interrupts initialize at least one timer object for a polling MiniportTimer function that monitors the NIC state for incoming receives and for send completions.

Calls to the NdisMSet..Timer functions insert the timer object in the system timer queue. Calls to NdisMCancelTimer dequeue the timer object if it is currently queued. Only one instantiation of a particular timer object can be queued at any given moment.

When a driver calls NdisMSetTimer, the timer object at Timer is queued until the interval specified in the call expires. When it does, the timer object is dequeued and the caller-supplied TimerFunction is run once at IRQL DISPATCH_LEVEL as soon as a processor becomes available. When a driver calls NdisMSetPeriodicTimer, the timer object is dequeued and the caller-supplied TimerFunction is run when the given interval expires, but the timer object is automatically requeued for the same fixed interval so the MiniportTimer function runs periodically, also at IRQL DISPATCH_LEVEL.

MiniportInitialize can call NdisMInitializeTimer more than once to initialize more than one timer object, each associated with a distinct MiniportTimer function. For example, a NIC driver might have one MiniportTimer function that polls the NIC state periodically and another that the miniport driver uses only to time-out a particular operation on its NIC. Each such MiniportTimer function has different functionality, and each such function should be associated with a different timer object by calling NdisMInitializeTimer from MiniportInitialize.

Callers of NdisMInitializeTimer run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, MiniportTimer, NdisMCancelTimer, NdisMSetAttributes, NdisMSetAttributesEx, NdisMSetPeriodicTimer, NdisMSetTimer


NdisMInitializeWrapper

NdisMInitializeWrapper notifies NDIS that a new miniport driver is initializing.

VOID
  NdisMInitializeWrapper(
    OUT PNDIS_HANDLE  NdisWrapperHandle,
    IN PVOID  SystemSpecific1,
    IN PVOID  SystemSpecific2,
    IN PVOID  SystemSpecific3
    );

Parameters

NdisWrapperHandle
Pointer to a caller-supplied variable in which NDIS returns a handle that represents itself.
SystemSpecific1
Specifies a pointer of a system-specific type.

For Windows 2000 and later drivers, this is a pointer to an opaque driver object input to the miniport driver's DriverEntry function.

SystemSpecific2
Specifies a pointer of a system-specific type.

For Windows 2000 and later drivers, this is a pointer to an opaque registry path input to the miniport driver's DriverEntry function.

SystemSpecific3
Specifies a pointer of a system-specific type.

For Windows 2000 and later drivers, this pointer should be set to NULL when the miniport driver calls NdisMInitializeWrapper.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A NIC driver or intermediate driver must call NdisMInitializeWrapper before it calls any other Ndis Xxx function. Usually, this call is the initial action of any NIC driver's DriverEntry function, which calls NdisMRegisterMiniport or NdisIMRegisterLayeredMiniport with the returned NdisWrapperHandle next. NDIS intermediate drivers also must call NdisMIntializeWrapper from the DriverEntry function and, then, call NdisMRegisterMiniport or NdisIMRegisterLayeredMiniport with the returned NdisWrapperHandle.

Such a driver's subsequent calls to Ndis Xxx initialization and configuration functions must pass the NdisWrapperHandle as a parameter. Consequently, it is an input parameter to the MiniportInitialize function.

Callers of NdisMInitializeWrapper run at IRQL PASSIVE_LEVEL.

See Also

DriverEntry of NDIS Miniport Drivers, MiniportInitialize, NdisIMRegisterLayeredMiniport, NdisMRegisterMiniport, NdisTerminateWrapper


NdisMMapIoSpace

NdisMMapIoSpace maps a given bus-relative "physical" range of device RAM or registers onto a system-space virtual range.

NDIS_STATUS
  NdisMMapIoSpace(
    OUT PVOID  *VirtualAddress,
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN NDIS_PHYSICAL_ADDRESS  PhysicalAddress,
    IN UINT  Length
    );

Parameters

Virtual Address
Pointer to a caller-supplied variable that is set to the converted virtual address if the call is successful.
MiniportAdapterHandle
Specifies the handle input to MiniportInitialize.
PhysicalAddress
Specifies the bus-relative base physical address of the device memory range to be mapped.
Length
Specifies the number of bytes to be mapped.

Return Value

NdisMMapIoSpace can return any of the following status values:

NDIS_STATUS_SUCCESS
The device memory range was mapped successfully so the value at VirtualAddress is valid and the mapped range has been claimed in the registry for the NIC.
NDIS_STATUS_RESOURCE_CONFLICT
An attempt to claim the device memory range in the registry has failed, possibly because another driver has already claimed the range for its device. NdisMMapIoSpace logs an error if this occurs.
NDIS_STATUS_RESOURCES
The memory could not be mapped or sufficient virtual memory could not be allocated.
NDIS_STATUS_FAILURE
Either the bus type or bus number is out of range or the given PhysicalAddress and Length were invalid (possibly not within the I/O space of the current platform).

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

This function is called by drivers of NICs that have on-board memory or a bank of device registers appearing in the I/O space of the host. For example, the driver of a NIC that uses PIO calls NdisMMapIoSpace.

A successful call to NdisMMapIoSpace claims hardware resources in the registry for the driver's NIC. Consequently, only MiniportInitialize functions call NdisMMapIoSpace.

NdisMMapIoSpace sets the variable at VirtualAddress to NULL if it does not return NDIS_STATUS_SUCCESS.

MiniportInitialize either gets the PhysicalAddress value from the driver's Parameters registry key or by calling a bus-type-specific Ndis Xxx configuration function. The given physical address range must fall within the I/O space of the current platform. It is a programming error to call NdisMMapIoSpace with a host physical memory address.

A miniport driver must call the reciprocal NdisMUnmapIoSpace to release its claim on system resources if MiniportInitialize subsequently fails to initialize the NIC, if its NIC is removed from the machine, and/or when the driver is unloading.

Callers of NdisMMapIoSpace run at IRQL PASSIVE_LEVEL.

See Also

MiniportHalt, MiniportInitialize, NdisMUnmapIoSpace, NdisOpenConfiguration, NdisReadEisaSlotInformation, NdisReadPciSlotInformation, NdisReadRegisterUchar, NdisReadRegisterUlong, NdisReadRegisterUshort, NdisWriteRegisterUchar, NdisWriteRegisterUlong, NdisWriteRegisterUshort


NdisMoveFromMappedMemory

NdisMoveFromMappedMemory copies data from device memory that was mapped during initialization with NdisMMapIoSpace to a system-space buffer.

VOID
  NdisMoveFromMappedMemory(
    OUT PVOID  Destination,
    IN PVOID  Source,
    IN ULONG  Length
    );

Parameters

Destination
Pointer to a system-space buffer into which this function copies data from mapped device memory. This buffer must be at least Length bytes in size.
Source
Specifies the base virtual address within mapped device memory from which to copy the data. This address must fall at least Length bytes from the end of the mapped range.
Length
Specifies the number of bytes to copy.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A NIC driver calls NdisMoveFromMappedMemory to copy data from NIC memory into a buffer in the host, as, for example, when transferring received data into a protocol-supplied buffer or miniport driver-allocated staging buffer.

Both the Source and Destination pointers are virtual addresses. The virtual range specified by Source and Length must fall within a range of device memory that was mapped during initialization with NdisMMapIoSpace.

Callers of NdisMoveFromMappedMemory can run at any IRQL when the given Source and Destination are resident. Otherwise, callers must be running at IRQL < DISPATCH_LEVEL, as, for example if the Destination address is on the stack.

See Also

MiniportInitialize, NdisAllocateMemory, NdisMMapIoSpace, NdisMoveMappedMemory, NdisMoveToMappedMemory, NdisReadRegisterUchar, NdisReadRegisterUlong, NdisReadRegisterUshort, NdisWriteRegisterUchar, NdisWriteRegisterUlong, NdisWriteRegisterUshort


NdisMoveMappedMemory

NdisMoveMappedMemory copies data from one location to another within a device memory range that was mapped during initialization with NdisMMapIoSpace.

VOID
  NdisMoveMappedMemory(
    OUT PVOID  Destination,
    IN PVOID  Source,
    IN ULONG  Length
    );

Parameters

Destination
Specifies the base virtual address within the mapped range at which the data should be copied.
Source
Specifies the base virtual address within the mapped range at which the copy should begin.
Length
Specifies the number of bytes to copy.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Both the Source and Destination pointers are virtual addresses. The virtual ranges specified both by Destination and Length and by Source and Length must fall within the range that was mapped during initialization with NdisMMapIoSpace.

Callers of NdisMoveMappedMemory can run at any IRQL.

See Also

MiniportInitialize, NdisAllocateMemory, NdisMMapIoSpace, NdisMoveFromMappedMemory, NdisMoveMemory, NdisMoveToMappedMemory


NdisMoveMemory

NdisMoveMemory copies a specified number of bytes from one caller-supplied location to another.

VOID
  NdisMoveMemory(
    OUT PVOID  Destination,
    IN PVOID  Source,
    IN ULONG  Length
    );

Parameters

Destination
Pointer to a system-space buffer that is the destination of the move. This buffer must be at least Length bytes in size.
Source
Pointer to a system-space buffer from which this function copies the data to the destination buffer. This buffer must be at least Length bytes in size.
Length
Specifies the number of bytes to copy.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Both Source and Destination are virtual addresses.

If either address falls within a range of device memory that was mapped with NdisMMapIoSpace, a NIC driver should call one of the Ndis..MappedMemory functions instead of NdisMoveMemory.

The range specified by Source and Length cannot overlap the Destination range.

Callers of NdisMoveMemory can run at any IRQL if the given Source and Destination are resident. Otherwise, callers must be running at IRQL < DISPATCH_LEVEL, as, for example if either address is on the stack.

See Also

NdisAllocateMemory, NdisMMapIoSpace, NdisMoveFromMappedMemory, NdisMoveMappedMemory, NdisMoveToMappedMemory


NdisMoveToMappedMemory

NdisMoveToMappedMemory copies data from a system-space buffer to device memory that was mapped during initialization with NdisMMapIoSpace.

VOID
  NdisMoveToMappedMemory(
    OUT PVOID  Destination,
    IN PVOID  Source,
    IN ULONG  Length
    );

Parameters

Destination
Specifies the base virtual address within a mapped device memory range where the copy should begin. This address must fall at least Length bytes from the end of the mapped range.
Source
Pointer to a system-space buffer from which this function copies data to the destination range. This buffer must be at least Length bytes in size.
Length
Specifies the number of bytes to copy.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A NIC driver calls NdisMoveToMappedMemory to copy data from a buffer in the host to mapped device memory, as, for example, when transferring data from a protocol-supplied buffer or miniport driver-allocated staging buffer to the NIC for a transmit.

Both the Source and Destination pointers are virtual addresses. The virtual range specified by Destination and Length must fall within a range that was mapped with NdisMMapIoSpace.

Callers of NdisMoveToMappedMemory can run at any IRQL when the given Source and Destination are resident. Otherwise, callers must be running at IRQL < DISPATCH_LEVEL, as, for example if the Source address is on the stack.

See Also

MiniportInitialize, NdisAllocateMemory, NdisMMapIoSpace, NdisMoveFromMappedMemory, NdisMoveMappedMemory, NdisMoveMemory, NdisReadRegisterUchar, NdisReadRegisterUlong, NdisReadRegisterUshort, NdisWriteRegisterUchar, NdisWriteRegisterUlong, NdisWriteRegisterUshort


NdisMPciAssignResources

This function is obsolete for Windows XP and later. Windows XP supports this function for legacy drivers; however, the Windows XP DDK will not build an NDIS driver that calls this function.

NdisMPciAssignResources returns a list of bus-relative hardware resources, such as IRQ, I/O ports, and device memory ranges, claimed in the registry for a PCI NIC.

NDIS_STATUS
  NdisMPciAssignResources(
    IN NDIS_HANDLE  MiniportHandle,
    IN ULONG  SlotNumber,
    OUT PNDIS_RESOURCE_LIST  *AssignedResources
    );

Parameters

MiniportHandle
Specifies the MiniportAdapterHandle passed in to MiniportInitialize and to most other MiniportXxx functions.
SlotNumber
Reserved. NDIS ignores this parameter.
AssignedResources
Pointer to a caller-supplied variable in which this function returns a pointer to a list of the hardware resources the NIC can use.

Return Value

NdisMPciAssignResources returns NDIS_STATUS_SUCCESS.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisMPciAssignResources claims a set of hardware resources in the registry for a miniport driver's PCI NIC to use, thereby preventing conflicting claims on the same resources from other devices in the machine.

The buffer specified at AssignedResources is formatted as an NDIS_RESOURCE_LIST, which is equivalent to the CM_PARTIAL_RESOURCE_LIST on Windows 2000 and later platforms.

The bus-relative configuration parameters returned in this buffer can be used in the MiniportInitialize function's subsequent calls to Ndis Xxx functions such as NdisMRegisterInterrupt, NdisMMapIoSpace, and/or NdisMRegisterIoPortRange.

NDIS 5.1 miniport drivers must call NdisMQueryAdapterResources instead of NdisMPciAssignResources.

Callers of NdisMPciAssignResources run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisImmediateReadPciSlotInformation, NdisMMapIoSpace, NdisMQueryAdapterResources, NdisMRegisterInterrupt, NdisMRegisterIoPortRange, NdisReadPciSlotInformation


NdisMPromoteMiniport

NdisMPromoteMiniport promotes a secondary miniport driver adapter to the primary role after the primary miniport driver adapter is removed from the system.

NDIS_STATUS
  NdisMPromoteMiniport(
    IN NDIS_HANDLE  MiniportAdapterHandle
    );

Parameters

MiniportAdapterHandle
Specifies the handle to the initialized adapter. The miniport driver previously called the NdisMSetMiniportSecondary function to set this miniport driver adapter to a secondary role.

Return Value

NdisMPromoteMiniport can return either of the following:

NDIS_STATUS_SUCCESS
The secondary miniport driver adapter has been promoted to the primary role.
NDIS_STATUS_FAILURE
An attempt to promote the secondary miniport driver adapter to the primary role failed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A miniport driver can call NdisMPromoteMiniport, after the primary miniport driver adapter is removed from the system, to set a secondary miniport driver adapter to the primary role. In this call, the miniport driver passes the handle to a secondary miniport driver adapter. The miniport driver must have previously called the NdisMSetMiniportSecondary function to set this miniport driver adapter to a secondary role.

A miniport driver uses a bundle of miniport driver adapters to balance the work load that each miniport driver adapter carries and to enable a secondary miniport driver adapter to take over packet transfers and information requests if the primary miniport driver adapter fails. This capability is called load balancing and fail over (LBFO). For example, if the miniport driver's primary adapter fails, the miniport driver can call the NdisMRemoveMiniport function to remove the primary adapter from the system and from the miniport driver's bundle. The miniport driver can then call NdisMPromoteMiniport to promote a secondary adapter to the primary role.

The first miniport driver adapter that the miniport driver initialized is initially the primary miniport driver adapter. The primary miniport driver adapter handles all packet transfers and requests for information. A miniport driver can call NdisMSetMiniportSecondary during the subsequent initialization of several miniport driver adapters to set them all to secondary roles. That is, multiple secondary miniport driver adapters can exist in a bundle.

For information on adding LBFO capability to a miniport driver, see the readme for the passthru driver. This miniport driver is a sample intermediate miniport driver in the Windows DDK.

Callers of NdisMPromoteMiniport run at IRQL <= DISPATCH_LEVEL.

See Also

NdisMRemoveMiniport, NdisMSetMiniportSecondary


NdisMQueryAdapterInstanceName

NdisMQueryAdapterInstanceName retrieves the friendly name of a physical NIC or a virtual adapter.

NDIS_STATUS
  NdisMQueryAdapterInstanceName(
    OUT PNDIS_STRING  AdapterInstanceName,
    IN NDIS_HANDLE  MiniportAdapterHandle
    );

Parameters

AdapterInstanceName
Pointer to a caller-supplied NDIS_STRING type that receives a counted Unicode string. This string specifies the friendly name of the interface for the given miniport driver instance. This interface is either a physical NIC or a virtual adapter. For Windows 2000 and later, NDIS defines the NDIS_STRING type as a UNICODE_STRING type.
MiniportAdapterHandle
Specifies the handle to the miniport driver adapter previously input to MiniportInitialize. This miniport driver adapter identifies a physical NIC or a virtual adapter.

Return Values

Returns NDIS_STATUS_SUCCESS if memory for the string at AdapterInstanceName was successfully allocated; otherwise, it returns NDIS_STATUS_RESOURCES.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A miniport driver uses NdisMQueryAdapterInstanceName to retrieve the friendly name of an interface that the miniport driver controls. This interface is either a physical NIC or a virtual adapter. The miniport driver specifies the handle to such an interface in MiniportAdapterHandle. This handle to the interface is passed to the miniport driver's MiniportInitialize function to set up the interface for network I/O operations.

NdisMQueryAdapterInstanceName allocates memory for the string that specifies the friendly name. After the caller finishes using this memory, the caller must call the NdisFreeMemory function to release the memory.

Friendly names are intended to help the user quickly and accurately identify a physical NIC or virtual adapter—for example, "PCI Ethernet Adapter" and "Virtual Private Networking Adapter" are considered friendly names.

Callers of NdisMQueryAdapterInstanceName run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisFreeMemory, UNICODE_STRING


NdisMQueryAdapterResources

NdisMQueryAdapterResources returns a list of hardware resources for a NIC.

VOID
  NdisMQueryAdapterResources(
    OUT PNDIS_STATUS  Status,
    IN NDIS_HANDLE  WrapperConfigurationContext,
    OUT PNDIS_RESOURCE_LIST  ResourceList,
    IN OUT PUINT  BufferSize
    );

Parameters

Status
Pointer to a caller-supplied variable in which this function returns the status of the call.
WrapperConfigurationContext
Specifies the handle input to MiniportInitialize.
ResourceList
Pointer to a caller-allocated buffer in which this function returns a set of hardware resources for the caller's NIC.
BufferSize
Pointer to a variable that specifies the size in bytes of the caller-allocated buffer on input and the number of bytes of information returned by this call.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

To get bus-configuration hardware configuration parameters for their NICs, drivers can call NdisMQueryAdapterResources from their MiniportInitialize functions.

Callers of NdisMQueryAdapterResources run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisOpenConfiguration, NdisReadConfiguration, NdisWriteConfiguration


NdisMQueryInformationComplete

NdisMQueryInformationComplete indicates that a prior call to MiniportQueryInformation, which returned NDIS_STATUS_PENDING, has completed.

VOID
  NdisMQueryInformationComplete(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN NDIS_STATUS  Status
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.
Status
Specifies the return value for the completed request originally passed to MiniportQueryInformation.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A call to NdisMQueryInformationComplete causes NDIS to return the completed query request to the ProtocolRequestComplete function of the driver that originally called NdisRequest.

Before it calls NdisMQueryInformationComplete, a miniport driver should supply the OID-specific information originally requested from its MiniportQueryInformation function. That is, the driver should set the appropriate values at BytesWritten and/or BytesNeeded and provide as much as possible of the requested data in the buffer at InformationBuffer.

For more information about system-defined OIDs, see NDIS Object Identifiers.

Callers of NdisMQueryInformationComplete run at IRQL DISPATCH_LEVEL.

See Also

MiniportInitialize, MiniportQueryInformation, NDIS_REQUEST, NdisRequest, ProtocolRequestComplete


NdisMReadDmaCounter

NdisMReadDmaCounter returns the current value of the system DMA controller's counter.

ULONG
  NdisMReadDmaCounter(
    IN NDIS_HANDLE  MiniportDmaHandle
    );

Parameters

MiniportDmaHandle
Specifies the handle returned when the miniport driver called NdisMRegisterDmaChannel during initialization.

Return Value

NdisMReadDmaCounter returns the number of bytes remaining in the current DMA transfer on the channel used by the NIC.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NIC drivers of devices that use the system DMA controller's autoinitialize mode can call NdisMReadDmaCounter.

Callers of NdisMReadDmaCounter run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportInitialize, NdisMCompleteDmaTransfer, NdisMDeregisterDmaChannel, NdisMRegisterDmaChannel, NdisMSetAttributes, NdisMSetAttributesEx, NdisMSetupDmaTransfer


NdisMRegisterAdapterShutdownHandler

NdisMRegisterAdapterShutdownHandler registers a NIC-driver-supplied MiniportShutdown function to be called when the system is shutting down.

VOID
  NdisMRegisterAdapterShutdownHandler(
    IN NDIS_HANDLE  MiniportHandle,
    IN PVOID  ShutdownContext,
    IN ADAPTER_SHUTDOWN_HANDLER  ShutdownHandler
    );

Parameters

MiniportHandle
Specifies the handle input to MiniportInitialize.
ShutdownContext
Pointer to a driver-determined context area. This pointer will be passed to the function at ShutdownHandler when it is called.
ShutdownHandler
Specifies the entry point of the caller's MiniportShutdown function.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NDIS 5.0 miniport drivers and intermediate drivers can optionally register a MiniportShutdown function by calling NdisMRegisterAdapterShutdownHandler. NDIS 5.1 miniport drivers and intermediate drivers must register a MiniportShutdown function by calling NdisMRegisterMiniport or NdisIMRegisterLayeredMiniport, respectively.

Whenever an NDIS 5.0 miniport driver's or intermediate driver's MiniportInitialize function successfully initializes a NIC, it calls NdisMRegisterAdapterShutdownHandler, usually just before MiniportInitialize returns NDIS_STATUS_SUCCESS.

Every NDIS 5.0 NIC driver should register a MiniportShutdown function when it initializes. MiniportShutdown is responsible for restoring the NIC to its initial state before the system is shut down.

Callers of NdisMRegisterAdapterShutdownHandler run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, MiniportShutdown, NdisMDeregisterAdapterShutdownHandler, NdisMRegisterMiniport, NdisIMRegisterLayeredMiniport


NdisMRegisterDevice

The NdisMRegisterDevice function creates a named device object and a symbolic link between the device object and a user-visible name for that device.

NDIS_STATUS
  NdisMRegisterDevice(
    IN NDIS_HANDLE  NdisWrapperHandle,
    IN PNDIS_STRING  DeviceName,
    IN PNDIS_STRING  SymbolicName,
    IN PDRIVER_DISPATCH  MajorFunctions[],
    OUT PDEVICE_OBJECT  *pDeviceObject,
    OUT NDIS_HANDLE  *NdisDeviceHandle
    );

Parameters

NdisWrapperHandle
Specifies the handle returned by NdisMInitializeWrapper.
DeviceName
Pointer to an NDIS_STRING type containing a zero-terminated Unicode string that names the device object. The string must be a full-path name—for example, \Device\DeviceName. For Windows 2000 and later, NDIS defines the NDIS_STRING type as a UNICODE_STRING type.
SymbolicName
Pointer to an NDIS_STRING type containing a Unicode string that is the Win32-visible name of the device being registered. Typically, the SymbolicName has the following format: \DosDevices\SymbolicName.
MajorFunctions
Pointer to an array of one or more entry points for the device driver's dispatch routines. A driver must set as many separate dispatch entry points as the IRP_MJ_XXX codes that the driver handles for the device object. Each dispatch routine is declared as follows:
NTSTATUS
(*PDRIVER_DISPATCH) (
    IN PDEVICE_OBJECT Device Object,
    IN PIRP Irp
);

A driver must not supply entry points for Plug and Play or Power Management handlers since the created device object is not for a physical device and therefore does not receive Plug and Play or Power Management IRPs.

pDeviceObject
Pointer to the newly created device object if the call succeeds.
NdisDeviceHandle
Pointer to a caller-supplied variable in which this function, if it succeeds, returns a handle to the device object. This handle is a required parameter to the NdisMDeregisterDevice function that the driver calls subsequently.

Return Values

NdisMRegisterDevice returns STATUS_SUCCESS if it succeeds, NDIS_STATUS_NOT_SUPPORTED if the caller is not an NDIS miniport driver, or a failure code if it fails.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

An intermediate driver or miniport driver may require a separate, stand-alone device object. For example, an intermediate miniport driver might require a stand-alone device object to monitor the status of an underlying NIC when the NIC's miniport driver is not up and running. To obtain the NIC's status in such a case, a user-mode application or environmental subsystem sends an IRP to the device object. The IRP is processed by the intermediate driver. Without the stand-alone device object, the NIC's status is available only when the NIC's miniport driver is up and running.

An intermediate driver or miniport driver creates a device object by calling NdisMRegisterDevice from its DriverEntry function after DriverEntry has called NdisMInitializeWrapper. NdisMRegisterDevice creates a named device object and also a symbolic link between the device object name and a user-visible name for that device. If the call to NdisMRegisterDevice succeeds, the I/O Manager allocates storage in nonpaged pool for the device object itself and for all other data structures associated with the device object, including the driver's device extension. The device extension for an object created with NdisMRegisterDevice is reserved for use by NDIS and cannot be used by the driver.

A device object created with NdisMRegisterDevice functions in the same way as a device object and symbolic link that were created with IoCreateDevice and IoCreateSymbolicLink, respectively. IRPs sent to the device object are processed by the driver that created the device object—not by NDIS. The driver processes IRPs sent to the device object using dispatch routines that it registered when it supplied the MajorFunctions pointer to NdisMRegisterDevice. For more information on device objects, IRPs, and dispatch routines, see Device Objects and Device Stacks, Handling IRPs, and Writing Dispatch Routines.

NDIS drivers should never call IoCreateDevice or IoCreateSymbolicLink. Instead, if an NDIS driver must create a device object, it should call NdisMRegisterDevice.

The device object that is created with NdisMRegisterDevice is not a physical device object and therefore does not receive Plug and Play or Power Management IRPs. Callers of NdisMRegisterDevice must therefore omit entry points for Plug and Play or Power Management handlers in the array that is pointed to by MajorFunctions.

If a driver's call to NdisMRegisterDevice fails, the driver can continue to load or not, depending on how critical the stand-alone device object is for the driver's operation.

Callers of NdisMRegisterDevice run at IRQL PASSIVE_LEVEL.

See Also

DriverEntry, IoCreateDevice, IoCreateSymbolicLink, NdisMDeregisterDevice, NdisMInitializeWrapper, UNICODE_STRING


NdisMRegisterDmaChannel

NdisMRegisterDmaChannel claims a system DMA controller channel during initialization for DMA operations on a slave NIC or on an ISA bus-master NIC.

NDIS_STATUS
  NdisMRegisterDmaChannel(
    OUT PNDIS_HANDLE  MiniportDmaHandle,
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN UINT  DmaChannel,
    IN BOOLEAN  Dma32BitAddresses,
    IN PNDIS_DMA_DESCRIPTION  DmaDescription,
    IN ULONG  MaximumLength
    );

Parameters

MiniportDmaHandle
Pointer to a caller-supplied variable in which this function returns a handle the miniport driver uses in subsequent calls to the NdisM Xxx system DMA functions.
MiniportAdapterHandle
Specifies the handle input to MiniportInitialize.
DmaChannel
Ignored. Set the DMA channel, if any, at DmaDescription.
Dma32BitAddresses
Specifies TRUE if the NIC has 32 address lines.
DmaDescription
Pointer to an NDIS_DMA_DESCRIPTION structure filled in by the caller. This structure is defined as follows:
typedef struct _NDIS_DMA_DESCRIPTION {
    BOOLEAN DemandMode;
    BOOLEAN AutoInitialize;
    BOOLEAN DmaChannelSpecified;
    DMA_WIDTH DmaWidth;
    DMA_SPEED DmaSpeed;
    ULONG DmaPort;
    ULONG DmaChannel;
} NDIS_DMA_DESCRIPTION, *PNDIS_DMA_DESCRIPTION;

The driver should initialize this structure with zeros before filling in the following members:

DemandMode
Specifies TRUE if the slave NIC uses the system DMA controller's demand mode.
AutoInitialize
Specifies TRUE if the slave NIC uses the system DMA controller's autoinitialize mode.
DmaChannelSpecified
Specifies TRUE if DmaChannel is set to the bus-relative value of the system DMA controller channel used by the NIC.
DmaWidth
Specifies the transfer width for DMA operations, one of Width8Bits, Width16Bits, or Width32Bits.
DmaSpeed
Specifies one of Compatible, TypeA, TypeB, or TypeC.
DmaPort
This refers to the MCA bus, which is no longer supported. This member must be zero.
DmaChannel
Specifies the bus-relative number of the system DMA controller channel used by the NIC.
MaximumLength
Specifies the maximum number of bytes the NIC can transfer in a single DMA operation. If the NIC has unlimited transfer capacity,set this parameter to -1.

Return Value

NdisMRegisterDmaChannel can return one of the following status values:

NDIS_STATUS_SUCCESS
NDIS claimed the specified DMA channel in the registry for the caller's NIC and set up necessary resources for subsequentl DMA operations by the miniport driver.
NDIS_STATUS_RESOURCE_CONFLICT
An attempt to claim the DMA channel in the registry has failed, possibly because another driver has already claimed that channel for its device. NdisMRegisterDmaChannel logs an error if this occurs.
NDIS_STATUS_RESOURCES
NDIS could not allocate the system resources it needs to support DMA operations by this NIC driver.
NDIS_STATUS_FAILURE
Either the bus type or bus number is out of range or the driver declared its NIC a bus master on an I/O bus other than ISA.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A driver of a slave-DMA NIC must call NdisMRegisterDmaChannel from its MiniportInitialize function to reserve system resources for subsequent DMA operations and to claim them in the registry.

The driver of an ISA bus-master NIC also must call NdisMRegisterDmaChannel from MiniportInitialize to claim a system DMA controller channel for its NIC in the registry.

MiniportInitialize must call NdisMSetAttributes or NdisMSetAttributesEx before calling NdisMRegisterDmaChannel.

MiniportInitialize obtained the bus-relative values passed to NdisMRegisterDmaChannel either from the registry or by calling a bus-type-specific Ndis Xxx configuration function.

If such a driver cannot allocate the system DMA resources that its device needs, MiniportInitialize should release all resources it already allocated for its NIC and, then, fail initialization for that NIC.

Callers of NdisMRegisterDmaChannel run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisMCompleteDmaTransfer, NdisMDeregisterDmaChannel, NdisMPciAssignResources, NdisMSetAttributes, NdisMSetAttributesEx, NdisMSetupDmaTransfer, NdisOpenConfiguration, NdisReadEisaSlotInformation, NdisReadPciSlotInformation


NdisMRegisterInterrupt

NdisMRegisterInterrupt sets up a mapping between a NIC driver's MiniportISR and MiniportHandleInterrupt functions, already registered with NdisMRegisterMiniport, and the bus-relative vector and level on which its NIC interrupts.

NDIS_STATUS
  NdisMRegisterInterrupt(
    OUT PNDIS_MINIPORT_INTERRUPT  Interrupt,
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN UINT  InterruptVector,
    IN UINT  InterruptLevel,
    IN BOOLEAN  RequestIsr,
    IN BOOLEAN  SharedInterrupt,
    IN NDIS_INTERRUPT_MODE  InterruptMode
    );

Parameters

Interrupt
Pointer to caller-allocated resident memory containing an opaque interrupt object, which NdisMRegisterInterrupt initializes and for which it returns a handle the miniport driver uses in subsequent calls to NdisMSynchronizeWithInterrupt.
MiniportAdapterHandle
Specifies the handle input to MiniportInitialize.
InterruptVector
Specifies the bus-relative vector number used by the NIC.
InterruptLevel
Specifies the bus-relative DIRQL for the interrupt. This value is almost always the same as that of InterruptVector.
RequestIsr
Specifies TRUE if the MiniportISR function should be called each time the NIC interrupts. If the NIC can share an interrupt with other devices on the I/O bus, this parameter must be set to TRUE.
SharedInterrupt
Specifies TRUE if other devices on the I/O bus can use this interrupt line. If this parameter is set to FALSE and another device already claimed the given interrupt vector in the registry, NdisMRegisterInterrupt will fail.
InterruptMode
Specifies the type of interrupt that the NIC generates as one of the following values:
NdisInterruptLatched
Interrupts are triggered by a transition from low to high on the interrupt line.
NdisInterruptLevelSensitive
Interrupts are active as long as the interrupt line is asserted.

Return Value

NdisMRegisterInterrupt can return one of the following:

NDIS_STATUS_SUCCESS
NDIS initialized the interrupt object and returned a valid Interrupt handle, claimed hardware resources in the registry for the NIC, such as the given vector if the NIC does not share an IRQ, and set up the MiniportISR (or MiniportDisableInterrupt) and associated MiniportHandleInterrupt functions to be called when an interrupt occurs as requested in the call to NdisMRegisterInterrupt.
NDIS_STATUS_RESOURCE_CONFLICT
An attempt to claim the vector or level in the registry has failed, possibly because another driver already claimed the interrupt for its device. NdisMRegisterInterrupt logs an error if this occurs.
NDIS_STATUS_RESOURCES
NDIS could not allocate sufficient memory to claim resources in the registry for the NIC.
NDIS_STATUS_FAILURE
The attempt to initialize the interrupt object failed, possibly due to another driver's prior claim on the InterruptVector or InterruptLevel in the registry.

Headers

Declared in Ndis.h. Include Ndis.h.

Declared in Ndis.h. Include Ndis.h.

Declared in Ndis.h. Include Ndis.h.

Comments

A NIC driver must call NdisMRegisterInterrupt from its MiniportInitialize function if its NIC generates interrupts. The driver of a NIC that does not generate interrupts calls NdisMInitializeTimer and NdisMSetPeriodicTimer instead of NdisMRegisterInterrupt.

MiniportInitialize must call NdisMSetAttributes or NdisMSetAttributesEx before calling NdisMRegisterInterrupt.

MiniportInitialize obtained the bus-relative values passed to NdisMRegisterInterrupt either from the registry or by calling a bus-type-specific Ndis Xxx configuration function.

If its call to NdisMRegisterInterrupt fails, MiniportInitialize should release all resources it already allocated for its NIC and, then, fail initialization for that NIC.

NdisMRegisterInterrupt distinguishes between the InterruptVector (the interrupt line that the card asserts to interrupt the system) and the InterruptLevel (the hardware priority, that is, the DIRQL, of that interrupt assigned by the system). Usually, these values can be assumed to be equal, unless the driver writer knows that they are different for a particular NIC or unless the miniport driver controls more than one NIC that share resources in the current platform.

If its NIC can share an IRQ with other devices on the I/O bus, the caller of NdisMRegisterInterrupt must set both the SharedInterrupt and RequestIsr parameters to TRUE. Such a NIC driver's MiniportISR can be called when no interrupt for the NIC is outstanding. In these circumstances, MiniportISR should return FALSE as soon as possible, indicating that the interrupt was not recognized and should leave interrupts enabled on its NIC.

When interrupts are enabled on the NIC, a driver's MiniportISR can be called at any time following a successful call to NdisMRegisterInterrupt, even during initialization. Such a driver's MiniportInitialize function should not call NdisMRegisterInterrupt until it has set up all state the driver needs to handle an interrupt. The MiniportHandleInterrupt function is not queued for subsequent execution if the driver's MiniportInitialize function is currently executing and an interrupt occurs.

For most drivers of NICs that do not share an IRQ, the MiniportISR function seldom runs except, possibly, during driver initialization. Such a miniport driver sets RequestIsr to FALSE when MiniportInitialize calls NdisMRegisterInterrupt, and such a driver has a MiniportDisableInterrupt function and, possibly, a MiniportEnableInterrupt function. The NDIS library then calls the driver's MiniportDisableInterrupt function when an interrupt occurs on the NIC and the driver's MiniportHandleInterrupt function does most of the I/O processing for the interrupt. Before MiniportHandleInterrupt returns control, either NDIS calls MiniportEnableInterrupt or MiniportHandleInterrupt re-enables interrupts on the NIC itself.

Whether a miniport driver with an ISR sets RequestIsr to TRUE when it calls NdisMRegisterInterrupt or not, NDIS acknowledges the interrupt to the operating system so that interrupts from other devices are not blocked.

If a miniport driver sets RequestIsr to TRUE when it calls NdisMRegisterInterrupt, it must dismiss the interrupt on its NIC by setting the state of the network interface card so that the NIC no longer asserts the interrupt. Interrupts can remain enabled on the NIC following the dismissal of the interrupt, or they can be disabled, depending on the design of the driver. The timing of such a dismissal depends on the InterruptMode specified when the driver called NdisMRegisterInterrupt, as follows:

  • For NdisInterruptLevelSensitive interrupts, MiniportISR must dismiss each interrupt as its NIC generates that interrupt. Otherwise, the interrupt is reasserted on the NIC as soon as MiniportISR returns control. If MiniportISR determines that the NIC did not generate a particular interrupt, it should return control with FALSE as soon as possible so that the ISRs for other devices on the same bus can be called promptly to dismiss the interrupt on the device that actually generated that interrupt.
  • For NdisInterruptLatched interrupts, dismissing an interrupt on the NIC is not as time-critical as it is for shared interrupts. If the miniport driver is designed such that each call to MiniportISR causes a subsequent call to the associated MiniportHandleInterrupt function, MiniportHandleInterrupt can dismiss the interrupt on the NIC. As an alternative, such a driver can set RequestIsr to FALSE when it calls NdisMRegisterInterrupt and supply a MiniportDisableInterrupt function, which will be called instead of MiniportISR unless MiniportHalt or MiniportInitialize is currently executing.

When a miniport driver supports full-duplex sends and receives, NDIS serializes calls to its MiniportISR or MiniportDisableInterrupt function for sends. NDIS separately serializes calls to its MiniportISR or MiniportDisableInterrupt function for all other operations that can cause an interrupt. Calls to the MiniportReset function are both synchronized and synchronous; NDIS prevents all other code paths in a full-duplex miniport driver from being entered while a device-reset operation is occurring.

If a miniport driver does not support full-duplex sends and receives, NDIS serializes all calls to the MiniportISR or MiniportDisableInterrupt function for any NIC the miniport driver controls. While such a driver's MiniportISR or MiniportDisableInterrupt function is processing a particular NIC interrupt, it will not be called to handle a second interrupt from the same NIC on another processor in an SMP machine.

However, the ISR (or MiniportDisableInterrupt function) of any driver that controls more than one device can run concurrently in SMP platforms if two of that driver's devices happen to generate interrupts almost simultaneously and interrupts are enabled on the NIC.

If it is possible that an interrupt can occur while another driver function is accessing resources that also can be accessed from MiniportISR or MiniportDisableInterrupt, the other function must call NdisMSynchronizeWithInterrupt to have the driver-supplied MiniportSynchronizeISR function access the shared resources at DIRQL.

Callers of NdisMRegisterInterrupt run at IRQL PASSIVE_LEVEL.

See Also

MiniportDisableInterrupt, MiniportEnableInterrupt, MiniportHandleInterrupt, MiniportInitialize, MiniportISR, MiniportReset, MiniportSynchronizeISR, MiniportTimer, NdisMDeregisterInterrupt, NdisMInitializeTimer, NdisMPciAssignResources, NdisMSetAttributes, NdisMSetAttributesEx, NdisMSetPeriodicTimer, NdisMSynchronizeWithInterrupt, NdisOpenConfiguration, NdisReadEisaSlotInformation, NdisReadPciSlotInformation


NdisMRegisterIoPortRange

NdisMRegisterIoPortRange sets up driver access to device I/O ports with the NdisRawReadPort Xxx and NdisRawWritePort Xxx functions and claims the range of I/O port addresses in the registry for that driver's NIC.

NDIS_STATUS
  NdisMRegisterIoPortRange(
    OUT PVOID  *PortOffset,
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN UINT  InitialPort,
    IN UINT  NumberOfPorts
    );

Parameters

PortOffset
Specifies a caller-supplied variable in which this function returns the mapped base virtual address for the given bus-relative I/O port range specified by InitialPort and NumberOfPorts.
MiniportAdapterHandle
Specifies the handle input to MiniportInitialize.
InitialPort
Specifies the bus-relative base port address for a range of ports to be mapped.
NumberOfPorts
Specifies the number of ports in the range to be mapped.

Return Value

NdisMRegisterIoPortRange can return one of the following:

NDIS_STATUS_SUCCESS
The given range of I/O ports was mapped successfully so the value at PortOffset is valid and the mapped range has been claimed in the registry for the NIC.
NDIS_STATUS_RESOURCE_CONFLICT
An attempt to claim the I/O port range in the registry has failed, possibly because another driver already claimed the range for its device. NdisMRegisterIoPortRange logs an error if this occurs.
NDIS_STATUS_RESOURCES
The port range could not be mapped or NDIS could not allocate resources to check the registry for hardware-resource conflicts.
NDIS_STATUS_FAILURE
Either the bus type or bus number is out of range or the given InitialPort and NumberOfPorts were invalid (possibly not within the I/O port space of the current platform).

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A NIC driver calls NdisMRegisterIoPortRange from its MiniportInitialize function. MiniportInitialize must call NdisMSetAttributes or NdisMSetAttributesEx before calling NdisMRegisterIoPortRange.

NdisMRegisterIoPortRange maps a bus-relative device address range that the miniport driver can use subsequently to access an I/O port range on its NIC by calling the NdisRaw Xxx functions. A successful call claims the specified range of I/O ports in the registry for the caller's NIC.

Because the parameters passed to the NdisRaw Xxx have been mapped, these functions run significantly faster than the corresponding NdisImmediate..Port Xxx. After a successful call to NdisMRegisterIoPortRange, a miniport driver cannot call any of the NdisImmediate..Port Xxx functions with either bus-relative addresses or mapped virtual addresses within such an I/O port range.

If its call to NdisMRegisterIoPortRange fails, MiniportInitialize should release all resources it already allocated for its NIC and, then, fail initialization for that NIC.

Drivers of NICs with device registers in the host memory space call NdisMMapIoSpace and, subsequently, the NdisRead/WriteRegister Xxx functions to access the NIC registers.

Callers of NdisMRegisterIoPortRange run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisMDeregisterIoPortRange, NdisMMapIoSpace, NdisRawReadPortBufferUchar, NdisRawReadPortBufferUlong, NdisRawReadPortBufferUshort, NdisRawReadPortUchar, NdisRawReadPortUlong, NdisRawReadPortUshort, NdisRawWritePortBufferUchar, NdisRawWritePortBufferUlong, NdisRawWritePortBufferUshort, NdisRawWritePortUchar, NdisRawWritePortUlong, NdisRawWritePortUshort, NdisReadRegisterUchar, NdisReadRegisterUlong, NdisReadRegisterUshort, NdisWriteRegisterUchar, NdisWriteRegisterUlong, NdisWriteRegisterUshort


NdisMRegisterMiniport

NdisMRegisterMiniport registers a miniport's MiniportXxx entry points with the NDIS library as the first step in NIC driver initialization.

NDIS_STATUS
  NdisMRegisterMiniport(
    IN NDIS_HANDLE  NdisWrapperHandle,
    IN PNDIS_MINIPORT_CHARACTERISTICS  MiniportCharacteristics,
    IN UINT  CharacteristicsLength
    );

Parameters

NdisWrapperHandle
Specifies the handle returned by NdisMInitializeWrapper.
MiniportCharacteristics
Pointer to an NDIS_MINIPORT_CHARACTERISTICS structure set up by the caller. The structure at MiniportCharacteristics is defined as follows:
typedef struct _NDIS_MINIPORT_CHARACTERISTICS {
    UCHAR MajorNdisVersion;
    UCHAR MinorNdisVersion;
    UINT Reserved;
    W_CHECK_FOR_HANG_HANDLER CheckForHangHandler;
    W_DISABLE_INTERRUPT_HANDLER DisableInterruptHandler;
    W_ENABLE_INTERRUPT_HANDLER  EnableInterruptHandler;
    W_HALT_HANDLER HaltHandler;
    W_HANDLE_INTERRUPT_HANDLER  HandleInterruptHandler;
    W_INITIALIZE_HANDLER InitializeHandler;
    W_ISR_HANDLER ISRHandler;
    W_QUERY_INFORMATION_HANDLER QueryInformationHandler;
    W_RECONFIGURE_HANDLER ReconfigureHandler;
    W_RESET_HANDLER ResetHandler;
    W_SEND_HANDLER SendHandler;
    W_SET_INFORMATION_HANDLER SetInformationHandler;
    W_TRANSFER_DATA_HANDLER TransferDataHandler;
//
// Version used is V4.0 or V5.0
// with following members
//
    W_RETURN_PACKET_HANDLER ReturnPacketHandler;
    W_SEND_PACKETS_HANDLER SendPacketsHandler;
    W_ALLOCATE_COMPLETE_HANDLER AllocateCompleteHandler;
//
// Version used is V5.0 with the following members
//
    W_CO_CREATE_VC_HANDLER CoCreateVcHandler;
    W_CO_DELETE_VC_HANDLER CoDeleteVcHandler;
    W_CO_ACTIVATE_VC_HANDLER CoActivateVcHandler;
    W_CO_DEACTIVATE_VC_HANDLER CoDeactivateVcHandler;
    W_CO_SEND_PACKETS_HANDLER CoSendPacketsHandler;
    W_CO_REQUEST_HANDLER CoRequestHandler;
//
// Version used is V5.1 with the following members
//
    W_CANCEL_SEND_PACKETS_HANDLER CancelSendPacketsHandler;
    W_PNP_EVENT_NOTIFY_HANDLER PnPEventNotifyHandler;
    W_MINIPORT_SHUTDOWN_HANDLER AdapterShutdownHandler;
} NDIS_MINIPORT_CHARACTERISTICS, *PNDIS_MINIPORT_CHARACTERISTICS;The driver should initialize this structure with zeros before setting up any of the following members:
MajorNdisVersion
Specifies the major version of the NDIS library the driver is using. The current value is 0x05, although the NDIS library continues to support existing NIC drivers developed for NDIS V4.0 and V3.0.

This member must be set to 0x05 or 0x04 if the caller sets entry points in any members following TransferDataHandler; it must be set to 0x05 if the caller sets entry points in any members following AllocateCompleteHandler.

MinorNdisVersion
Specifies the minor version of the NDIS library the driver is using. The current value is 0x00.
Reserved
This member is reserved for system use.
CheckForHangHandler
Specifies the entry point of the caller's MiniportCheckForHang function, if any, or NULL.
DisableInterruptHandler
Specifies the entry point of the caller's MiniportDisableInterrupt function, if any.
EnableInterruptHandler
Specifies the entry point of the caller's MiniportEnableInterrupt function, if any.
HaltHandler
Specifies the entry point of the caller's MiniportHalt function.
HandleInterruptHandler
Specifies the entry point of the caller's MiniportHandleInterrupt function, if any.
InitializeHandler
Specifies the entry point of the caller's MiniportInitialize function.
ISRHandler
Specifies the entry point of the caller's MiniportISR function, if any. This miniport driver function is required if the driver later calls NdisMRegisterInterrupt from its MiniportInitialize function.
QueryInformationHandler
Specifies the entry point of the caller's MiniportQueryInformation function, which is optional if the caller supplies a MiniportCoRequest function.
ReconfigureHandler
Specifies the entry point of the caller's MiniportReconfigure function, or NULL.
ResetHandler
Specifies the entry point of the caller's MiniportReset function.
SendHandler
Specifies the entry point of the caller's MiniportSend function, MiniportWanSend function, or NULL if the caller supplies a MiniportSendPackets or MiniportCoSendPackets function.

If the miniport driver supports multipacket sends or controls a connection-oriented NIC, it sets the SendPacketsHandler or CoSendPacketsHandler member, respectively, and sets this member to NULL.

SetInformationHandler
Specifies the entry point of the caller's MiniportSetInformation function, which is optional if the caller supplies a MiniportCoRequest function.
TransferDataHandler
Specifies the entry point of the caller's MiniportTransferData function, if any. This miniport driver function is required unless the caller is the driver of a WAN NIC or the caller supports multipacket receives and, therefore, supplies the entry point of its MiniportReturnPacket function at ReturnPacketHandler. Drivers of connection-oriented NICs must support multipacket receives.
ReturnPacketHandler
Specifies the entry point of the caller's MiniportReturnPacket function, if any.
SendPacketsHandler
Specifies the entry point of the caller's MiniportSendPackets function, if any. If the driver of a connectionless NIC also sets an entry point in the SendHandler member, NDIS always calls its MiniportSendPackets function. The driver of a connection-oriented NIC must set the CoSendPacketsHandler member instead of this member.
AllocateCompleteHandler
Specifies the entry point of the caller's MiniportAllocateComplete function, if any. MiniportCoCreateVc function. If the caller is an integrated call manager and connection-oriented NIC (MCM) driver, this member is set to NULL, because such a driver subsequently registers its ProtocolCoCreateVc function as a call manager with NdisMCmRegisterAddressFamily.
CoDeleteVcHandler
Specifies the entry point of the caller's MiniportCoDeleteVc function. If the caller is an integrated call manager and connection-oriented NIC (MCM) driver, this member is set to NULL, because such a driver subsequently registers its ProtocolCoDeleteVc function as a call manager with NdisMCmRegisterAddressFamily.
CoActivateVcHandler
Specifies the entry point of the caller's MiniportCoActivateVc function.
CoDeactivateVcHandler
Specifies the entry point of the caller's MiniportCoDeactivateVc function.
CoSendPacketsHandler
Specifies the entry point of the caller's MiniportCoSendPackets function. The SendHandler and SendPacketsHandler members should be NULL if the driver supplies a MiniportCoSendPackets function.
CoRequestHandler
Specifies the entry point of the caller's MiniportCoRequest function. If the driver also supplies MiniportQueryInformation and MiniportSetInformation functions, its MiniportCoRequest function handles only OID_GEN_CO_XXX and connection-oriented medium-specific OID_XXX requests. If such a driver sets the QueryInformationHandler and SetInformationHandler members to NULL, its MiniportCoRequest function must respond to all possible OID requests, including the OID_GEN_XXX that all NDIS miniports must handle.
CancelSendPacketsHandler
Specifies the entry point of the caller's MiniportCancelSendPackets function, if any, or NULL. Miniport drivers that queue send packets for more than one second should register a MiniportCancelSendPackets function.
PnPEventNotifyHandler
Specifies the entry point of the caller's MiniportPnPEventNotify function. NDIS 5.1 miniports must register a MiniportPnPEventNotify function. In addition, miniports that can adjust their NIC's power consumption based on the system's current power source and miniports that have a WDM lower edge must register a MiniportPnPEventNotify function.
AdapterShutdownHandler
Specifies the entry point of the caller's MiniportShutdown function, if any, or NULL. NDIS 5.1 miniports must register a MiniportShutdown function. NDIS 5.1 miniports should register a MiniportShutdown function by calling NdisMRegisterMiniport—not by calling NdisMRegisterAdapterShutdownHandler.
CharacteristicsLength
Specifies the size in bytes of the caller-supplied characteristics buffer, which is sizeof(NDIS_MINIPORT_CHARACTERISTICS). The exact buffer size allocated depends on the compiler or build directives set for the miniport driver.

For example, the following shows the appropriate compiler directives to embed at the start of a miniport driver's source code if the driver uses a V5.0 NDIS_MINIPORT_CHARACTERISTICS structure:

#define NDIS_MINIPORT_DRIVER
#define NDIS50_MINIPORT   1
#include <Ndis.h>  // AFTER preceding directives

The inclusion of ndis.h must occur after the NDIS_MINIPORT_DRIVER and NDISXX_MINIPORT directives, where XX can be 40, as well as the 50 shown here. If the NDISXX_MINIPORT directive is omitted, the NDIS_MINIPORT_CHARACTERISTICS structure size defaults to version 3.0.

As an alternative, the same driver could set the following build directive in its sources file, instead of using the preceding compiler directives:

...
C_FLAGS=$(C_FLAGS) -DNDIS_MINIPORT_DRIVER -DNDIS50_MINIPORT_DRIVER
...

As for the corresponding compiler directive, the driver writer can specify a -DNDISXX_MINIPORT_DRIVER directive, where XX can be 40, as well as the 50 shown here.

Setting the appropriate compiler/build directives sets the CharacteristicsLength automatically. The values set in the MajorNdisVersion and MinorNdisVersion members of the characteristics structure must be consistent with the compiler/build directives set for the miniport driver.

Return Value

NdisMRegisterMiniport returns NDIS_STATUS_SUCCESS if it registered the miniport driver, or it can return one of the following status values:

NDIS_STATUS_BAD_CHARACTERISTICS
The CharacteristicsLength is too small for the MajorNdisVersion specified in the buffer at MiniportCharacteristics.
NDIS_STATUS_BAD_VERSION
The MajorNdisVersion or MinorNdisVersion specified in the characteristics structure is invalid.
NDIS_STATUS_RESOURCES
A shortage of resources, possibly memory, prevented the NDIS library from registering the caller.
NDIS_STATUS_FAILURE
This is a default error status, returned when none of the preceding errors caused the registration to fail.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A NIC driver calls NdisMRegisterMiniport from its DriverEntry function, following its call to NdisMInitializeWrapper.

Every NIC driver exports a set of standard MiniportXxx functions by setting up the characteristics structure and calling NdisMRegisterMiniport. This structure is copied in the NdisMRegisterMiniport request to the NDIS library's internal storage. Thus, once it has registered, a miniport driver cannot change its MiniportXxx functions.

After the driver has called NdisMRegisterMiniport and after its DriverEntry function returns control, it should be prepared to be called back at the MiniportInitialize entry point specified in the characteristics structure. In the PnP environment, a NIC driver's call to NdisMRegisterMiniport simply registers the miniport driver's entry points with NDIS, which defers calling the driver's MiniportInitialize function until the PnP Manager sends NDIS a request to start the NIC. For more information about PnP, see Driver Setup, Plug and Play, & Power Management.

The NDIS library currently does not call MiniportReconfigure functions, so such a function in an existing miniport driver is dead code unless the miniport driver makes internal calls to its MiniportReconfigure function from MiniportInitialize.

NDIS intermediate drivers, which export both MiniportXxx and ProtocolXxx functions, must call NdisIMRegisterLayeredMiniport instead of NdisMRegisterMiniport. Connection-oriented MCM drivers, however, which export MiniportXxx and ProtocolCmXxx functions, call NdisMRegisterMiniport.

Callers of NdisMRegisterMiniport run at IRQL PASSIVE_LEVEL.

See Also

DriverEntry of NDIS Miniport Drivers, MiniportAllocateComplete, MiniportCheckForHang, MiniportCoActivateVc, MiniportCoCreateVc, MiniportCoDeactivateVc, MiniportCoDeleteVc, MiniportCoRequest, MiniportCoSendPackets, MiniportDisableInterrupt, MiniportEnableInterrupt, MiniportHalt, MiniportHandleInterrupt, MiniportInitialize, MiniportISR, MiniportQueryInformation, MiniportReconfigure, MiniportReset, MiniportReturnPacket, MiniportSend, MiniportSendPackets, MiniportSetInformation, MiniportTransferData,

MiniportWanSend, NdisIMRegisterLayeredMiniport, NdisMCmRegisterAddressFamily,

NdisMRegisterAdapterShutdownHandler

NdisZeroMemory, ProtocolCoCreateVc, ProtocolCoDeleteVc


NdisMRegisterUnloadHandler

The NdisMRegisterUnloadHandler function registers an unload handler for a driver.

VOID
  NdisMRegisterUnloadHandler(
    IN NDIS_HANDLE  NdisWrapperHandle,
    IN PDRIVER_UNLOAD  UnloadHandler
    );

Parameters

NdisWrapperHandle
Specifies the handle returned by NdisMInitializeWrapper.
UnloadHandler
Specifies the entry point for the driver's unload routine. An unload routine is declared as follows:
VOID
(*PDRIVER_UNLOAD) (
    IN struct _DRIVER_OBJECT *DriverObject
    );

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A driver calls NdisMRegisterUnloadHandler from its DriverEntry function after DriverEntry has called NdisMRegisterMiniport or NdisIMRegisterLayeredMiniport. NdisMRegisterUnloadHandler registers an unload handler for the driver.

The functionality of the unload handler is driver-specific. For example, an intermediate driver should register an unload handler that calls NdisDeregisterProtocol to deregister the protocol portion of the intermediate driver. The unload handler should also perform any necessary cleanup operations, such as deallocating resources used by the protocol portion of the driver.

A miniport driver, such as a load-balancing miniport driver, that monitors more than one miniport driver instance should register an unload handler that cleans up state information and deallocates resources after the miniport driver instances that it monitors are halted. Note that an unload handler differs from a MiniportHalt function: the unload handler has a more global scope, whereas the scope of the MiniportHalt function is restricted to a particular miniport driver instance.

Callers of NdisMRegisterUnloadHandler run at IRQL PASSIVE_LEVEL.

See Also

DriverEntry, MiniportHalt, NdisDeregisterProtocol, NdisIMRegisterLayeredMiniport, NdisMRegisterMiniport


NdisMResetComplete

NdisMResetComplete returns the final status of a reset request for with the NIC driver previously returned NDIS_STATUS_PENDING.

VOID
  NdisMResetComplete(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN NDIS_STATUS  Status,
    IN BOOLEAN  AddressingReset
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.
Status
Specifies the final status of the reset operation just completed
AddressingReset
Specifies TRUE if the reset affected the miniport's network address information so that it needs to be reloaded.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If the MiniportReset function returns NDIS_STATUS_PENDING, the miniport driver must call NdisMResetComplete when it completes the reset operation. This call causes NDIS to forward the completion-status information to the protocol driver, if any, that called NdisReset to initiate the call to MiniportReset.

The NDIS library also can call the MiniportReset function, independent of any reset requests from protocol drivers bound to a particular NIC, when NDIS determines that a sent packet or a request that it submitted to the miniport driver has timed out.

Some NICs lose all multicast address, packet filter, or functional address information when a soft reset is issued. The driver of such a NIC sets AddressingReset to TRUE when it calls NdisMResetComplete, causing NDIS to call its MiniportSetInformation function to restore the addressing state.

An NDIS intermediate driver either sets AddressingReset to TRUE when it calls NdisMResetComplete or restores its own addressing information, such as medium-specific functional, multicast, and/or group addresses.

Callers of NdisMResetComplete run at IRQL DISPATCH_LEVEL.

See Also

MiniportInitialize, MiniportReset, MiniportSetInformation, NdisReset, ProtocolResetComplete


NdisMRemoveMiniport

NdisMRemoveMiniport removes the specified miniport driver adapter that the miniport driver has determined is unrecoverable from the system.

NDIS_STATUS
  NdisMRemoveMiniport(
    IN NDIS_HANDLE  MiniportAdapterHandle
    );

Parameters

MiniportAdapterHandle
Specifies the handle to the initialized adapter that the miniport driver has determined is unrecoverable.

Return Value

NdisMRemoveMiniport can return either of the following:

NDIS_STATUS_SUCCESS
The miniport driver adapter has been removed.
NDIS_STATUS_FAILURE
An attempt to remove the miniport driver adapter failed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If a miniport driver has determined that a particular miniport driver adapter has failed and is unrecoverable, the miniport driver can call NdisMRemoveMiniport to remove the adapter from the system. In this call, the miniport driver passes the handle to the adapter to remove.

A miniport driver can use a bundle of miniport driver adapters to balance the work load that each miniport driver adapter carries and to enable a secondary miniport driver adapter to take over packet transfers and information requests if the primary miniport driver adapter fails. This capability is called load balancing and fail over (LBFO). For example, if the miniport driver's primary adapter fails, the miniport driver can call NdisMRemoveMiniport to remove the primary adapter from the system and from the miniport driver's bundle. The miniport driver can then call the NdisMPromoteMiniport function to promote a secondary adapter to the primary role.

The first miniport driver adapter that the miniport driver initialized is initially the primary miniport driver adapter. The primary miniport driver adapter handles all packet transfers and requests for information. A miniport driver can call the NdisMSetMiniportSecondary function during the subsequent initialization of several miniport driver adapters to set them all to secondary roles. That is, multiple secondary miniport driver adapters can exist in a bundle.

For information on adding LBFO capability to a miniport driver, see the readme for the passthru driver. This miniport driver is a sample intermediate miniport driver in the Windows DDK.

Callers of NdisMRemoveMiniport run at IRQL <= DISPATCH_LEVEL.

See Also

NdisMPromoteMiniport, NdisMSetMiniportSecondary


NdisMSendComplete

NdisMSendComplete returns the packet and final status of a completed send request for which the driver previously returned NDIS_STATUS_PENDING.

VOID
  NdisMSendComplete(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN PNDIS_PACKET  Packet,
    IN NDIS_STATUS  Status
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.
Packet
Pointer to the protocol-allocated packet originally input to MiniportSend.
Status
Specifies the final status of the transmit request that has just been completed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The NDIS library queues incoming send packets on behalf of serialized miniports so that such miniports can deal with one device-transmit operation at a time. (A miniport driver can, however, transmit several packets per operation, depending on the capabilities of its NIC.) NDIS serializes the submission of incoming packet arrays to each serialized miniport's MiniportSendPackets function, and it serializes the submission of packets to each miniport's MiniportSend function. NDIS queues incoming send requests in FIFO order when it cannot pass on each such request immediately because the underlying serialized NIC driver is already busy.

Deserialized miniports, including all connection-oriented miniports, are responsible for accepting all send requests whenever their Miniport(Co)Send(Packets) functions are called. If necessary, a deserialized driver queues incoming send packets until the driver has sufficient resources to transmit the data over the wire. A deserialized miniport driver completes all incoming sends asynchronously with calls to NdisMSendComplete.

If a serialized miniport driver's MiniportSendPackets function sets the Status in the out-of-band data block for a packet to NDIS_STATUS_PENDING or if it's MiniportSend function returns NDIS_STATUS_PENDING for an incoming packet, that miniport driver must eventually call NdisMSendComplete with the original packet to indicate which send request it has completed. While the status of such a send packet is pending, the miniport driver retains ownership of that packet descriptor and all the protocol-allocated resources associated with the packet descriptor.

A call to NdisMSendComplete causes NDIS to call the ProtocolSendComplete function of the driver that initiated the request with its call to NdisCoSendPackets, NdisSendPackets or NdisSend. The underlying miniport's call to NdisMSendComplete releases ownership of the given packet descriptor and associated resources to the protocol driver that originally allocated them.

If the MiniportSend(Packets) function of a serialized driver returns a status other than NDIS_STATUS_PENDING for a given packet, the miniport driver never calls NdisMSendComplete with that packet. The return from MiniportSend(Packets) releases ownership of such a packet. Consequently, a serialized miniport driver must not call NdisMSendComplete with any packet for which its MiniportSend(Packets) function did not return NDIS_STATUS_PENDING. Any send packet for which a serialized NIC driver returns something other than NDIS_STATUS_PENDING should be considered inaccessible by that miniport driver as soon as its MiniportSend(Packets) function returns control.

A miniport's call to NdisMSendComplete does not necessarily mean that a particular packet has been transmitted over the wire. Usually, such a packet has been transmitted except, possibly, by the driver of a NIC in which packets can be queued in the hardware.

Miniport drivers that declared their devices of type NdisMediumWan in response to a preceding OID_GEN_MEDIA_SUPPORTED or OID_GEN_MEDIA_IN_USE request call NdisMWanSendComplete rather than NdisMSendComplete.

Serialized callers of NdisMSendComplete must run at IRQL DISPATCH_LEVEL. Deserialized callers of NdisMSendComplete can run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportInitialize, MiniportSend, MiniportSendPackets, NdisCoSendPackets, NdisMSendResourcesAvailable, NdisMWanSendComplete, NDIS_PACKET, NDIS_PACKET_OOB_DATA, NdisSend, NdisSendPackets, NDIS_SET_PACKET_STATUS, ProtocolSendComplete


NdisMSendResourcesAvailable

NdisMSendResourcesAvailable notifies NDIS that a miniport driver has sufficient internal resources to accept another send request, even though one or more outstanding send packets are pending within the miniport driver.

VOID
  NdisMSendResourcesAvailable(
    IN NDIS_HANDLE  MiniportAdapterHandle
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The NDIS library queues send requests on behalf of miniports so each NIC driver can deal with one device transmit operation at a time, although a miniport driver can transmit several packets per operation, depending on the capabilities of its NIC. NDIS serializes the submission of incoming packet arrays to each miniport's MiniportSendPackets function, and it serializes the submission of packets to each miniport's MiniportSend function. NDIS queues incoming send requests in FIFO order.

Any miniport driver can retains ownership of such a send packet in one of the following ways:

  • Its MiniportSendPackets function sets the Status member in the out-of-band data block for a packet to NDIS_STATUS_PENDING with NDIS_SET_PACKET_STATUS.
  • Its MiniportSend function returns NDIS_STATUS_PENDING.

In either of these circumstances, the NIC driver eventually must call NdisMSendComplete or NdisMWanSendComplete to indicate that it has released ownership of the packet and that the driver has sufficient resources available to accept the next transmit request.

However, before miniport driver calls NdisMSendComplete for a pending packet, it can call NdisMSendResourcesAvailable if the driver and its NIC are capable of accepting another send request immediately, assuming NDIS has one in its queue to submit to that driver. Such a call allows the driver of a high-capacity NIC to optimize transmissions over the network by sending more data at a time.

NdisMSendResourcesAvailable can be called only in the window between the return of NDIS_STATUS_PENDING for a given packet and the miniport's call to NdisMSendComplete with that packet.

If a miniport driver returns any value except NDIS_STATUS_PENDING for a particular packet from MiniportSendPackets or from MiniportSend, it should neither call NdisMSendResourcesAvailable nor NdisMSendComplete. Any send packet for which a NIC driver returns something other than NDIS_STATUS_PENDING should be considered inaccessible by that miniport driver on return from its MiniportSendPackets or MiniportSend function.

A WAN miniport driver cannot call NdisMSendResourcesAvailable.

Callers of NdisMSendResourcesAvailable run at IRQL DISPATCH_LEVEL.

See Also

MiniportInitialize, MiniportSend, MiniportSendPackets, NdisMSendComplete, NdisMWanSendComplete, NDIS_PACKET, NDIS_PACKET_OOB_DATA, NdisSend, NdisSendPackets, NDIS_SET_PACKET_STATUS


NdisMSetAttributes

NdisMSetAttributes informs the NDIS library about significant features of the caller's NIC during initialization.

VOID
  NdisMSetAttributes(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN NDIS_HANDLE  MiniportAdapterContext,
    IN BOOLEAN  BusMaster,
    IN NDIS_INTERFACE_TYPE  AdapterType
    );

Parameters

MiniportAdapterHandle
Specifies the handle input to MiniportInitialize.
MiniportAdapterContext
Specifies a handle for a resident context area allocated by MiniportInitialize.
BusMaster
Specifies TRUE if the caller's NIC is a bus-master DMA device.
AdapterType
Specifies the I/O bus interface type of the caller's NIC, which usually is the type of I/O bus on which the NIC is connected, as one of the following:
NdisInterfaceInternal
Specifies a host-specific internal interface.
NdisInterfaceIsa
Specifies the ISA interface.
NdisInterfaceEisa
Specifies the extended ISA (EISA) interface.
NdisInterfaceMca
This refers to the MCA bus, which is no longer supported.
NdisInterfaceTurboChannel
Specifies the Turbo Channel interface.
NdisInterfacePci
Specifies the Peripheral Component Interconnect (PCI) interface.
NdisInterfacePcMcia
Specifies the Personal Computer Memory Card International Association (PC Card) interface.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A MiniportInitialize function must call NdisMSetAttributes or NdisMSetAttributesEx before calling any other NdisMRegister Xxx or Ndis Xxx function that depends on the information supplied to NdisMSetAttributes(Ex). For example, a call to NdisMAllocateMapRegisters will fail if MiniportInitialize has not yet called NdisMSetAttributes with BusMaster set to TRUE or NdisMSetAttributesEx with NDIS_ATTRIBUTE_BUS_MASTER set in the AttributeFlags.

In general, a NIC driver must call NdisMSetAttributes(Ex) before it calls any Ndis Xxx function that claims hardware resources in the registry for its NIC, because NDIS must have the BusMaster or AttributeFlags value, respectively, before such a call is made and because the driver usually needs the memory at MiniportAdapterContext to store information for these calls. This restriction implies that a NIC driver's MiniportInitialize function cannot call the following Ndis Xxx before it calls NdisMSetAttributes(Ex):

  • NdisMPciAssignResources
  • NdisMAllocateMapRegisters and NdisMAllocateSharedMemory
  • NdisMMapIoSpace and, consequently, the Ndis..Register Xxx functions
  • NdisMRegisterDmaChannel
  • NdisMRegisterInterrupt
  • NdisMRegisterIoPortRange and, consequently, the NdisRaw..Port Xxx functions

However, before calling NdisMSetAttributes(Ex), a NIC driver can call the Ndis..Configuration functions to retrieve configuration information installed in the registry and the NdisImmediate Xxx, such as NdisImmediateReadPciSlotInformation or NdisImmediateReadSharedMemory, as well as the NdisImmediate..Port Xxx functions. MiniportInitialize also can call the bus-type-specific NdisRead Xxx functions, such as NdisReadPciSlotInformation, as long as the installed registry entry for the driver's interface type matches the bus-type-specific NdisRead Xxx MiniportInitialize calls.

The MiniportAdapterContext handle supplied to NdisMSetAttributes(Ex) becomes an input parameter to all MiniportXxx functions that were registered, along with MiniportInitialize, in the call to NdisMRegisterMiniport. Usually, this handle is a pointer to resident memory, allocated by MiniportInitialize, in which the driver maintains NIC-specific run-time state.

Intermediate drivers must call NdisMSetAttributesEx, rather than NdisMSetAttributes. NIC drivers can call either of these functions, but NdisMSetAttributesEx allows a miniport driver to adjust the intervals at which its MiniportCheckForHang and MiniportReset functions are called.

Callers of NdisMSetAttributes run at IRQL PASSIVE_LEVEL.

See Also

MiniportCheckForHang, MiniportInitialize, MiniportReset, NdisAllocateMemory, NdisImmediateReadPciSlotInformation, NdisImmediateReadPortUchar, NdisImmediateReadPortUlong, NdisImmediateReadPortUshort, NdisImmediateReadSharedMemory, NdisIMRegisterLayeredMiniport, NdisMAllocateMapRegisters, NdisMAllocateSharedMemory, NdisMMapIoSpace, NdisMPciAssignResources, NdisMRegisterDmaChannel, NdisMRegisterInterrupt, NdisMRegisterIoPortRange, NdisMRegisterMiniport, NdisMSetAttributesEx, NdisOpenConfiguration, NdisReadEisaSlotInformation, NdisReadEisaSlotInformationEx, NdisReadPciSlotInformation, NdisWritePciSlotInformation


NdisMSetAttributesEx

NdisMSetAttributesEx informs the NDIS library about significant features of the caller's NIC or virtual NIC during initialization.

VOID
  NdisMSetAttributesEx(
    IN NDIS_HANDLE MiniportAdapterHandle,
    IN NDIS_HANDLE MiniportAdapterContext,
    IN UINT  CheckForHangTimeInSeconds  OPTIONAL,
    IN ULONG  AttributeFlags,
    IN NDIS_INTERFACE_TYPE AdapterType
    );

Parameters

MiniportAdapterHandle
Specifies the handle input to MiniportInitialize.
MiniportAdapterContext
Specifies a handle for a resident context area allocated by MiniportInitialize.
CheckForHangTimeInSeconds
Specifies the interval in seconds at which NDIS should call the MiniportCheckForHang function, if any. Specifying zero for this parameter indicates that NDIS should call MiniportCheckForHang at NDIS's default two-second interval and that NDIS should call the MiniportReset function at the default four-second time-out interval for pending sends and requests that NDIS holds queued to the caller subsequently.

Specifying a value greater than two extends both the check-for-hang and time-out intervals. NDIS uses double the specified check-for-hang interval as its time-out interval for the caller.

If the caller sets NDIS_ATTRIBUTE_DESERIALIZE in AttributeFlags, NDIS does not queue pending sends for the miniport driver. Instead, such a deserialized driver must manage its own queuing of subsequent send requests internally whenever it has insufficient resources to transmit an incoming send immediately.

AttributeFlags
Specifies a bitmask that can be set with one or more (ORed) of the following flags:
NDIS_ATTRIBUTE_BUS_MASTER
Set if the caller's NIC is a bus-master DMA device.
NDIS_ATTRIBUTE_DESERIALIZE
Set if the caller is a deserialized miniport driver.
NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT
Set if NDIS should not attempt to time-out pending send packets that it holds queued to the caller. Intermediate drivers should set this flag, but NIC drivers should not.
NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT
Set if NDIS should not attempt to time-out pending query and set requests that it holds queued to the caller. Intermediate drivers should set this flag, but NIC drivers should not.
NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER
Set if the caller is an intermediate driver.
NDIS_ATTRIBUTE_IGNORE_TOKEN_RING_ERRORS
Set if NDIS should not call a Token Ring NIC driver's MiniportReset function if Token Ring errors are indicated.
NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND
Set if NDIS should not call a driver's MiniportHalt function before the system transitions to a low-power (sleeping) state. Drivers that rely on hardware-maintained state should not set this flag.
NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK
Set if the driver can handle removal of its NIC without user notification. Such a driver exports a MiniportPnPEventNotify function. System support for NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK is available in Windows XP and later operating systems.
NDIS_ATTRIBUTE_NOT_CO_NDIS
Set by a driver that can support both connection-oriented and connectionless devices to indicate that the device is a connectionless device. System support for NDIS_ATTRIBUTE_NOT_CO_NDIS is available in Windows XP and later operating systems.
NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS
Set by a driver that uses NdisBufferVirtualAddressSafe, NdisGetFirstBufferFromPacketSafe, and NdisQueryBufferSafe exclusively to access system virtual addresses for send packet buffers. NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS is also set by a driver that exclusively uses physical addresses to access such buffers. Setting NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS can improve performance since the operating system will not have to map send packet buffers to system virtual addresses. System support for NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS is available in Windows XP and later OS versions.
AdapterType
Specifies the I/O bus interface type of the caller's NIC, which usually is the type of I/O bus on which the NIC is connected, as one of the following:
NdisInterfaceInternal
Specifies a host-specific internal interface.
NdisInterfaceIsa
Specifies the ISA interface.
NdisInterfaceEisa
Specifies the extended ISA (EISA) interface.
NdisInterfaceMca
This refers to the MCA bus, which is no longer supported.
NdisInterfaceTurboChannel
Specifies the Turbo Channel interface.
NdisInterfacePci
Specifies the Peripheral Component Interconnect (PCI) interface.
NdisInterfacePcMcia
Specifies the Personal Computer Memory Card International Association (PC Card) interface.
This parameter is irrelevant for intermediate drivers, which should pass zero for this argument to NdisMSetAttributesEx.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A MiniportInitialize function must call NdisMSetAttributesEx (or NdisMSetAttributes) before calling any other NdisMRegister Xxx or Ndis Xxx function that depends on the information supplied to NdisMSetAttributesEx. For example, a NIC driver's call to NdisMAllocateMapRegisters will fail if MiniportInitialize has not yet called NdisMSetAttributesEx with the AttributeFlags set with NDIS_ATTRIBUTE_BUS_MASTER.

Intermediate drivers must call NdisMSetAttributesEx, rather than NdisMSetAttributes, and they must set NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER in the AttributeFlags. Setting this flag causes NDIS to treat an intermediate driver as a full-duplex miniport driver, which prevents rare but intermittent deadlocks from occurring in the intermediate driver. Consequently, every intermediate driver must be capable of handling concurrent sends and indications.

Deserialized drivers also must call NdisMSetAttributesEx, and they must set NDIS_ATTRIBUTE_DESERIALIZE in the AttributeFlags. NDIS does not maintain a send-packet queue for a deserialized driver, nor does NDIS serialize calls to a such a driver's MiniportXxx functions. A deserialized driver makes itself responsible for the following:

  • Accepting all incoming send requests
  • Queuing incoming send packets internally if necessary, as, for example, if a deserialized NIC driver currently has insufficient resources available to transmit an incoming send packet immediately
  • Synchronizing access to its internal queue(s) as necessary among the driver's routines
  • Completing all requested sends asynchronously by subsequently calling NdisMSendComplete with each protocol-supplied packet descriptor passed in to its Miniport(Co)Send(Packets) function

NDIS assumes that all connection-oriented miniports are deserialized drivers, regardless of the AttributeFlags that they pass to NdisMSetAttributesEx. That is, any driver that calls NdisMRegisterMiniport with 0x05 as the MajorNdisVersion must be a deserialized miniport driver.

Serialized NIC drivers can call either of these functions from MiniportInitialize, but NdisMSetAttributes does not allow its caller to adjust the interval at which a NIC driver's MiniportCheckForHang and/or MiniportReset function(s) are called.

The value of CheckForHangTimeInSeconds determines the NDIS library's time-out interval on sends, if any, and requests that it holds queued to the caller. By default, NDIS times out queued sends (only for serialized drivers) and requests at twice the check-for-hang interval, after which it calls the MiniportReset function, unless the driver sets AttributeFlags with NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT and NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT when it calls NdisMSetAttributesEx. Intermediate drivers should set these flags when calling NdisMSetAttributesEx because such a driver cannot determine or control when the underlying NIC driver will process sends and requests.

NIC drivers should not set the NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT and NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT flags, although NDIS will honor such a specification by a serialized NIC driver. However, NIC drivers can adjust the time-out interval at which their MiniportReset functions are called by specifying an explicit CheckForHangTimeInSeconds. For example, a NIC driver that emulates Ethernet over a modem might not complete every packet within the default time-out interval of the NDIS library. Whenever a packet appeared to time out on such a NIC, NDIS would assume that the NIC was no longer operating correctly and call the driver's MiniportReset function. For the driver of such a NIC, calling NdisMSetAttributesEx with a CheckForHangTimeInSeconds set to something greater than two both prevents unnecessary resets and extends the interval at which its MiniportCheckForHang function, if any, is called to test the operational state of the NIC.

An intermediate driver must set the NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND flag. Setting this flag prevents NDIS from halting the driver before the system transitions to a low-power (sleeping) state.

A legacy miniport driver that manages a non-PnP-aware NIC can set the NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND flag to prevent NDIS from halting the driver before the system transitions to a low-power state. If the miniport driver sets this flag, NDIS queries the miniport driver with OID_PNP_CAPABILITIES even though the bus driver for the miniport driver's NIC may have indicated that the NIC is not PM-aware. The miniport driver must succeed the OID_PNP_CAPABILITIES request with NDIS_STATUS_SUCCESS. In the NDIS_PM_WAKE_UP_CAPABILITIES structure returned by this OID, the miniport driver must also specify a device power state of NdisDeviceStateUnspecified for each wake-up capability. When the system transitions to a low-power state, NDIS will not call such a miniport driver's MiniportHalt function. Before the system transitions to the a lower-power state, the miniport driver must save any hardware context that it maintains. On receiving an OID_PNP_SET_POWER request to the D3 state, the miniport driver must set its NIC to the appropriate state for the low-power state. On receiving an OID_PNP_SET_POWER request to the D0 state, the miniport driver must set its NIC to the appropriate state for the working state.

A miniport driver that supports surprise removal of its device (removal without notification through the user interface) must set NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK. Doing so causes NDIS to call the driver's MiniportPnPEventNotify function with PnPEvent set to NdisDevicePnPEventSurpriseRemoved when the miniport's device is removed without notification. In addition, setting NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK suppresses the display of a warning dialog box that asks the user to stop the device before removing it.

A miniport driver that can support both connectionless and connection-oriented devices must set NDIS_ATTRIBUTE_NOT_CO_NDIS if its device is a connectionless device. Otherwise, NDIS will mistakenly assume that its device is connection-oriented since the driver registers connection-oriented miniport driver functions with NdisMRegisterMiniport.

In general, a NIC driver must call NdisMSetAttributesEx before it calls any Ndis Xxx function that claims hardware resources in the registry for its NIC, because NDIS must have the AttributeFlags value before such a call is made and because the driver usually needs the memory at MiniportAdapterContext to store information for these calls. This restriction implies that a NIC driver's MiniportInitialize function cannot call the following Ndis Xxx before it calls NdisMSetAttributesEx:

  • NdisMAllocateMapRegisters and NdisMAllocateSharedMemory
  • NdisMMapIoSpace and, consequently, the NdisReadRegister Xxx and NdisWriteRegister Xxx functions
  • NdisMRegisterDmaChannel
  • NdisMRegisterInterrupt
  • NdisMRegisterIoPortRange and, consequently, the NdisRaw..Port Xxx functions

However, before calling NdisMSetAttributesEx, any driver's MiniportInitialize function can call the Ndis..Configuration functions to retrieve configuration information installed in the registry. MiniportInitialize also can call the bus-type-specific NdisRead Xxx functions, such as NdisReadPciSlotInformation, as long as the installed registry entry for the driver's interface type matches the bus-type-specific NdisRead Xxx MiniportInitialize calls.

The MiniportAdapterContext handle supplied to NdisMSetAttributesEx becomes an input parameter to all MiniportXxx functions that were registered, along with MiniportInitialize, in the call to NdisMRegisterMiniport or NdisIMRegisterLayeredMiniport. Usually, this handle is a pointer to resident memory, allocated by MiniportInitialize, in which the driver maintains NIC-specific run-time state.

Callers of NdisMSetAttributesEx run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, MiniportPnPEventNotify, NdisAllocateMemory, NdisImmediateReadPciSlotInformation, NdisImmediateReadPortUchar, NdisImmediateReadPortUlong, NdisImmediateReadPortUshort, NdisImmediateReadSharedMemory, NdisIMRegisterLayeredMiniport, NdisMAllocateMapRegisters, NdisMAllocateSharedMemory, NdisMMapIoSpace, NdisMPciAssignResources, NdisMRegisterDmaChannel, NdisMRegisterInterrupt, NdisMRegisterIoPortRange, NdisMRegisterMiniport, NdisOpenConfiguration, NdisReadEisaSlotInformation, NdisReadEisaSlotInformationEx


NdisMSetInformationComplete

NdisMSetInformationComplete returns the final status of a completed set-information request for which the driver previously returned NDIS_STATUS_PENDING.

VOID
  NdisMSetInformationComplete(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN NDIS_STATUS  Status
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.
Status
Specifies the final status of the immediately preceding request input to MiniportSetInformation.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A miniport driver calls NdisMSetInformationComplete after it has carried out the operation orginally requested of its MiniportSetInformation function. This call releases the miniport's ownership of all buffer addresses that were passed to MiniportSetInformation.

NdisMSetInformationComplete causes NDIS to return the original request to the ProtocolRequestComplete function of the driver, if any, that initiated the set-information operation when it called NdisRequest. The NDIS library also can call MiniportSetInformation directly with NDIS-initiated set-information requests, particularly during initialization just after MiniportQueryInformation returns control.

All calls to a driver's MiniportSetInformation function are both synchronous and serialized. That is, NDIS never submits another such request until the miniport driver has completed the preceding request.

For more information about the system-defined OIDs that the MiniportSetInformation function handles, see NDIS Object Identifiers.

Callers of NdisMSetInformationComplete run at IRQL DISPATCH_LEVEL.

See Also

MiniportInitialize, MiniportSetInformation, NDIS_REQUEST, NdisRequest, ProtocolRequestComplete


NdisMSetMiniportSecondary

NdisMSetMiniportSecondary sets the specified miniport driver adapter to the secondary role in relation to the primary miniport driver adapter. The primary miniport driver adapter handles all packet transfers and requests for information that are made by protocol drivers. However, NDIS can send specific requests to the secondary miniport driver adapter.

NDIS_STATUS
  NdisMSetMiniportSecondary(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN NDIS_HANDLE  PrimaryMiniportAdapterHandle
    );

Parameters

MiniportAdapterHandle
Specifies the handle to the miniport driver adapter previously input to MiniportInitialize.
PrimaryMiniportAdapterHandle
Specifies the handle to the primary miniport driver adapter that has already been initialized with MiniportInitialize.

Return Value

NdisMSetMiniportSecondary can return either of the following:

NDIS_STATUS_SUCCESS
The miniport driver adapter has been set to the secondary role in relation to the primary miniport driver adapter. The miniport driver can subsequently promote the secondary miniport driver adapter to the primary role.
NDIS_STATUS_FAILURE
An attempt to set the miniport driver adapter that is currently being initialized to the secondary role failed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Protocol drivers can only bind to a miniport driver's primary adapter. All bindings to the miniport driver's secondary adapters are torn down.

A miniport driver can call NdisMSetMiniportSecondary during initialization of the secondary miniport driver adapter, that is from within the miniport driver's MiniportInitialize function. In this call, the miniport driver passes the handle to the miniport driver adapter being initialized in the MiniportAdapterHandle parameter and the handle to the primary miniport driver adapter that has already been initialized in the PrimaryMiniportAdapterHandle parameter. The primary miniport driver adapter handles all packet transfers and requests for information that are made by protocol drivers. However, NDIS can send specific requests to the secondary miniport driver adapter. For example, NDIS might query all miniport driver adapters for their media connectivity. The secondary miniport driver adapter must process and respond to this query.

After initialization of the secondary miniport driver adapter, the miniport driver can subsequently call the NdisMPromoteMiniport function to promote the secondary miniport driver adapter to the primary role.

Before the miniport driver calls NdisMSetMiniportSecondary, it must first determine if the miniport driver adapter being initialized is part of the miniport driver's bundle of miniport driver adapters. A miniport driver uses this bundle to balance the work load that each miniport driver adapter carries and to enable a secondary miniport driver adapter to take over packet transfers and information requests if the primary miniport driver adapter fails. This capability is called load balancing and fail over (LBFO). For example, if the miniport driver's primary adapter fails, the miniport driver can call the NdisMRemoveMiniport function to remove the primary adapter from the system and from the miniport driver's bundle. The miniport driver can then call NdisMPromoteMiniport to promote a secondary adapter to the primary role.

To determine if the miniport driver adapter being initialized is part of the miniport driver's bundle, the miniport driver first calls the NdisOpenConfiguration function to obtain the handle for a registry key in which the miniport driver's configuration parameters are stored. Next, the miniport driver calls the NdisReadConfiguration function to retrieve the string value (REG_SZ) from the BundleIndentifier keyword under the miniport driver's registry key. The miniport driver should copy the string value to the miniport driver's internal structure in which the miniport driver stores information specific to the miniport driver adapter that is currently being initialized. This internal structure is also known as MiniportAdapterContext. The miniport driver's information (INF) file sets BundleIndentifier when the miniport driver is installed.

During initialization, the miniport driver should search through all miniport driver-adapter instances that the driver has already initialized to locate an instance that has an identical bundle-identifier value. To perform this search, the miniport driver inspects each instance's MiniportAdapterContext. If the driver locates a match, it should call NdisMSetMiniportSecondary and pass handles for both primary and secondary miniport driver adapters.

A miniport driver can call NdisMSetMiniportSecondary during the subsequent initialization of several miniport driver adapters to set them all to secondary roles. That is, multiple secondary miniport driver adapters can exist in a bundle. NDIS will only expose the miniport driver's primary adapter to transports. If transports request to send packets to the miniport driver or request to set or query information, NDIS will pass these requests to the miniport driver using the primary adapter. The miniport driver must provide LBFO for these requests as appropriate. The miniport driver only indicates up packets that were received from the network using the handle for the primary adapter.

Only miniport driver-adapter instances that are initialized by the same miniport driver and that belong to the miniport driver's bundle can call NdisMSetMiniportSecondary.

For information on adding LBFO capability to a miniport driver, see the readme for the passthru driver. This miniport driver is a sample intermediate miniport driver in the Windows DDK.

Callers of NdisMSetMiniportSecondary run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisMPromoteMiniport, NdisMRemoveMiniport


NdisMSetPeriodicTimer

NdisMSetPeriodicTimer sets a timer to fire periodically, thereby running an associated MiniportTimer function repeatedly at fixed intervals.

VOID
  NdisMSetPeriodicTimer(
    IN PNDIS_MINIPORT_TIMER Timer,
    IN UINT  MillisecondsPeriod
    );

Parameters

Timer
Pointer to caller-supplied resident storage for a timer object previously initialized with NdisMInitializeTimer.
MillisecondsPeriod
Specifies the interval, in milliseconds, to time out before calling the MiniportTimer function unless the timer is cancelled or this interval is reset.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisMSetPeriodicTimer causes the driver-supplied MiniportTimer function, which was associated with the timer object when MiniportInitialize called NdisMInitializeTimer, to be run repeatedly whenever the given MillisecondsPeriod expires. At the initial call to NdisMSetPeriodicTimer, the timer object is queued until the MillisecondsPeriod expires, when the MiniportTimer function is run and the timer object is automatically requeued for the next interval.

By contrast, NdisMSetTimer causes the driver-supplied function associated with a particular timer object to run only once after the given MillisecondsToDelay expires. That is, execution of the function associated with the Timer passed to NdisMSetTimer is episodic, rather than periodic.

As a general rule, a miniport driver should allocate and initialize two timer objects if it calls both NdisMSetPeriodicTimer and NdisMSetTimer. Such a driver is likely to have two MiniportTimer functions with different functionality, each associated with a particular timer object when it is initialized with NdisMInitializeTimer. For example, a MiniportTimer function that runs periodically might poll device state at regular intervals, while another MiniportTimer function might retry a particular runtime operation only if it times out on the NIC.

If a miniport driver calls NdisMSetPeriodicTimer, NdisMCancelTimer, or NdisMSetTimer with the same Timer pointer originally passed to NdisMSetPeriodicTimer, the current call cancels its preceding call to NdisMSetPeriodicTimer, possibly resetting the MillisecondsPeriod specified originally. Any call to NdisMSet..Timer resets the given timer to expire at the interval specified in the most recent call and causes the associated MiniportTimer function to run when the most recently specified interval has expired.

Timer resolution on the host varies. Consequently, calling NdisMSetPeriodicTimer with very small periods does not necessarily cause the execution of the MiniportTimer function exactly when the specified interval expires. The minimum practicable interval to specify on Windows 2000 and later platforms is ten milliseconds.

Callers of NdisMSetPeriodicTimer run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportInitialize, MiniportTimer, NdisMCancelTimer, NdisMInitializeTimer, NdisMSetTimer


NdisMSetTimer

NdisMSetTimer sets a timer to fire after a specified interval, thereby running an associated MiniportTimer function when the timer fires.

VOID
  NdisMSetTimer(
    IN PNDIS_MINIPORT_TIMER  Timer,
    IN UINT  MillisecondsToDelay
    );

Parameters

Timer
Pointer to caller-supplied resident storage for a timer object previously initialized with NdisMInitializeTimer.
MillisecondsToDelay
Specifies the interval, in milliseconds, to time out before calling the MiniportTimer function.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisMSetTimer causes the driver-supplied MiniportTimer function, which was associated with the timer object when MiniportInitialize called NdisMInitializeTimer, to run once after the given MillisecondsToDelay expires. Execution of the MiniportTimer function associated with the Timer passed to NdisMSetTimer is episodic, rather than periodic. A miniport driver must call NdisMSetTimer each time the associated timer function should be run.

By contrast, NdisMSetPeriodicTimer causes the associated MiniportTimer function to be run repeatedly whenever the given MillisecondsPeriod expires. At the initial call to NdisMSetPeriodicTimer, the timer object is queued until the MillisecondsPeriod expires, when the MiniportTimer function is run and the timer object is automatically requeued for the next interval.

As a general rule, a miniport driver should allocate and initialize two timer objects if it calls both NdisMSetPeriodicTimer and NdisMSetTimer. Such a driver is likely to have two MiniportTimer functions with different functionality, each associated with a particular timer object when it is initialized with NdisMInitializeTimer. For example, a MiniportTimer function that runs periodically might poll device state at regular intervals, while another MiniportTimer function might retry a particular runtime operation only if it times out on the NIC.

If a miniport driver calls NdisMSetTimer, NdisMCancelTimer, or NdisMSetPeriodicTimer with the same Timer pointer originally passed to NdisMSetTimer before the originally specified MillisecondsToDelay has expired, the current call cancels its preceding call to NdisMSetTimer. Any call to NdisMSet..Timer resets the given timer to expire at the interval specified in the most recent call and causes the associated MiniportTimer function to run when the most recently specified interval has expired.

Timer resolution on the host varies. Consequently, calling NdisMSetTimer with very small time-out values does not necessarily cause the execution of the MiniportTimer function exactly when the specified interval expires. The minimum practicable interval to specify on Windows 2000 and later platforms is ten milliseconds.

Callers of NdisMSetTimer run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportInitialize, MiniportTimer, NdisMCancelTimer, NdisMInitializeTimer, NdisMSetPeriodicTimer


NdisMSetupDmaTransfer

NdisMSetupDmaTransfer sets up the host DMA controller for a DMA transfer.

VOID
  NdisMSetupDmaTransfer(
    OUT PNDIS_STATUS  Status,
    IN NDIS_HANDLE  MiniportDmaHandle,
    IN PNDIS_BUFFER  Buffer,
    IN ULONG  Offset,
    IN ULONG  Length,
    IN BOOLEAN  WriteToDevice
    );

Parameters

Status
Pointer to a caller-supplied variable in which this function returns the status of the request, which can be one of the following:
NDIS_STATUS_SUCCESS
The DMA controller has been set up to transfer the specified data, which has been flushed to or from the device to maintain data integrity.
NDIS_STATUS_RESOURCES
An attempt to set up the DMA controller for the transfer has failed, either because the channel designated by MiniportDmaHandle is currently in use transferring data or because the given Length is invalid.
MiniportDmaHandle
Specifies the handle returned by NdisMRegisterDmaChannel during initialization.
Buffer
Pointer to the buffer descriptor mapping the range of host memory from which or into which the data will be transferred.
Offset
Specifies the byte offset within the mapped buffer at which the transfer should start. Zero indicates the transfer should begin at the initial byte of the range specified at Buffer.
Length
Specifies the number of bytes of data to be transferred. The range specified by Offset and Length must be a proper subrange of that specified at Buffer.
WriteToDevice
Specifies TRUE for an outbound transfer from the system through the NIC.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Drivers of slave-DMA NICs call NdisMSetupDmaTransfer in response to incoming send requests, for which the driver sets WriteToDevice to TRUE. They set WriteToDevice to FALSE when they transfer received data from the NIC to host memory.

The caller of NdisMSetupDmaTransfer supplies a buffer descriptor mapping the host memory range that is the target of the transfer or that contains data for a download operation from the host to the NIC. To specify a transfer sized to suit the DMA constraints of its NIC, the caller can set up a subrange to be transferred with the Offset and Length parameters if necessary.

The caller must supply a buffer descriptor that specifies the host range into which received data will be transferred from the NIC when WriteToDevice is FALSE. Otherwise, the buffer descriptor at Buffer was chained to a packet descriptor input to the NIC driver's MiniportSend or MiniportSendPackets function.

To improve performance for small transmit requests, such as a send request of less than 256K in length, a miniport driver can copy the packet data into an internal staging buffer and pass a driver-allocated buffer descriptor mapping that buffer to NdisMSetupDmaTransfer.

On return from NdisMSetupDmaTransfer, the host DMA controller has been programmed for the transfer. The miniport driver then programs its NIC for the transfer operation.

When the transfer is complete, the miniport driver must call NdisMCompleteDmaTransfer.

Callers of NdisMSetupDmaTransfer run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportSend, MiniportSendPackets, MiniportTimer, NdisAllocateBuffer, NdisAllocateBufferPool, NdisAllocateMemory, NdisMCompleteDmaTransfer, NdisMDeregisterDmaChannel, NdisMRegisterDmaChannel


NdisMSleep

NdisMSleep delays execution of the caller for a given interval in microseconds.

VOID
  NdisMSleep(
    IN ULONG  MicrosecondsToSleep
    );

Parameters

MicrosecondsToSleep
Specifies the number of microseconds to delay.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

For the given MicrosecondsToSleep, the caller's thread of execution is put into a wait state, thereby allowing other threads to get work done on the current processor. When the given interval expires, the caller of NdisMSleep resumes execution.

An NDIS driver should always call NdisMSleep in preference to NdisStallExecution unless the driver is running at IRQL >= DISPATCH_LEVEL. NdisMSleep can accept a larger delay interval than NdisStallExecution, which should never be called with an interval greater than 50 microseconds.

NIC drivers can call NdisMSleep from their MiniportInitialize and, possibly, MiniportHalt functions when either function must wait for state changes to occur in the NIC before that function continues its operations.

Both NdisMSleep and NdisStallExecution allow a NIC driver to specify a delay consistently and independently of the clock speed of the host CPU. Neither function involves a timer object used by NdisSet(Periodic)Timer. The resolution of the host system clock varies, so very short delays can take slightly longer than the caller of NdisMSleep or NdisStallExecution specified.

Callers of NdisMSleep run at IRQL < DISPATCH_LEVEL.

See Also

MiniportHalt, MiniportInitialize, MiniportTimer, NdisMSetTimer, NdisMSetPeriodicTimer, NdisStallExecution, NdisWaitEvent


NdisMStartBufferPhysicalMapping

NdisMStartBufferPhysicalMapping sets up a mapping for a bus-master DMA transfer operation.

VOID
  NdisMStartBufferPhysicalMapping(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN PNDIS_BUFFER  Buffer,
    IN ULONG  PhysicalMapRegister,
    IN BOOLEAN  WriteToDevice,
    OUT PNDIS_PHYSICAL_ADDRESS_UNIT  PhysicalAddressArray,
    OUT PUINT  ArraySize
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.
Buffer
Pointer to a buffer descriptor mapping the virtual range for the transfer. This buffer contains the data to be transferred.
PhysicalMapRegister
Specifies the zero-based index of the map register to be used for the transfer. This value must be no greater than one less than the number of map registers that the driver allocated during initialization with NdisMAllocateMapRegisters.
WriteToDevice
Specifies TRUE when the mapping is used for an outbound transfer from the system through the NIC.
PhysicalAddressArray
Pointer to a caller-supplied array of NDIS_PHYSICAL_UNIT structures, in which each element is defined as follows:
typedef struct _NDIS_PHYSICAL_ADDRESS_UNIT {
    NDIS_PHYSICAL_ADDRESS PhysicalAddress;
    UINT Length;
} NDIS_PHYSICAL_ADDRESS_UNIT, *PNDIS_PHYSICAL_ADDRESS_UNIT;

On return from a successful call to NdisMStartBufferPhysicalMapping, elements in this array specify the mapped logical ranges suitable for downloading to the NIC, with the following members in each element:

PhysicalAddress
Specifies the base physical address for the start of a discrete contiguous range of data to be transferred.
Length
Specifies the number of bytes in the mapped range.
ArraySize
Pointer to a caller-supplied variable in which NdisMStartBufferPhysicalMapping returns the number of ranges it mapped in the buffer at PhysicalAddressArray. This value is a count of the elements that contain mappings, so the caller can use this count as a bound on the number of physical address ranges it downloads to the NIC subsequently.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Bus-master NIC drivers call NdisMStartBufferPhysicalMapping in response to send requests originating in protocols bound to the NIC. That is, the buffer descriptor at Buffer usually was chained to a packet input to the NIC driver's MiniportSend or MiniportSendPackets function.

Every protocol driver is responsible for setting up send packets to suit the limits of the underlying NIC. The NIC driver's MiniportQueryInformation function already returned these limits in response to certain OID_GEN_XXX requests. Consequently, a miniport driver need not test incoming send packets for oversized frames or transmit blocks, nor for transmit buffer overflows. For more information about OIDs, see NDIS Object Identifiers.

A caller of NdisMStartBufferPhysicalMapping must ensure that the array at PhysicalAddressArray is large enough to map the given buffer. A miniport driver can call NdisGetBufferPhysicalArraySize to determine how many elements are required to map the virtual range specified in the descriptor at Buffer.

For small transfer requests, such as those up to 256K in length, a miniport driver can achieve higher performance by copying the data to be transmitted into a staging buffer in the shared memory space already allocated with NdisMAllocateSharedMemory or NdisMAllocateSharedMemoryAsync. Because the NIC driver already has mapped virtual and physical addresses for such a shared memory range, it need not call NdisM..BufferPhysicalMapping functions for such small DMA transfers.

Data received by a bus-master NIC is transferred directly into device-accessible buffers within a shared memory block allocated by the miniport driver. Miniports perform explicit bus-master DMA operations only for transmits.

To transfer packet data for a send request, any miniport driver basically does the following:

  1. Maps the virtual range containing the data with NdisMStartBufferPhysicalMapping to get mapped device-accessible range addresses for use by its NIC
  2. Downloads the returned physical addresses to the NIC
  3. Calls NdisFlushBuffer and NdisMUpdateSharedMemory if the driver allocated cached memory
  4. Programs the NIC for the transfer operation
  5. Calls NdisMCompleteBufferPhysicalMapping, usually from the MiniportHandleInterrupt function, when the NIC has completed the transfer, which the NIC indicates by a transmit interrupt or, possibly, by a state change discovered by the NIC driver's polling MiniportTimer function

Any mapping returned by NdisMStartBufferPhysicalMapping is valid only until the miniport driver calls NdisMCompleteBufferPhysicalMapping. When NdisMCompleteBufferPhysicalMapping returns control, the PhysicalMapRegister specified in the preceding call to NdisMStartBufferPhysicalMapping can be reused in a subsequent DMA operation.

Callers of NdisMStartBufferPhysicalMapping run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportInitialize, MiniportQueryInformation, MiniportSend, MiniportSendPackets, MiniportTimer, NdisFlushBuffer, NdisGetBufferPhysicalArraySize, NdisMAllocateMapRegisters, NdisMAllocateSharedMemory, NdisMAllocateSharedMemoryAsync, NdisMCompleteBufferPhysicalMapping, NdisMUpdateSharedMemory


NdisMSynchronizeWithInterrupt

NdisMSynchronizeWithInterrupt synchronizes execution of a miniport driver-supplied function with the MiniportISR or MiniportDisableInterrupt function.

BOOLEAN
  NdisMSynchronizeWithInterrupt(
    IN PNDIS_MINIPORT_INTERRUPT  Interrupt,
    IN PVOID  SynchronizeFunction,
    IN PVOID  SynchronizeContext
    );

Parameters

Interrupt
Pointer to the caller-supplied storage for the interrupt object initialized with NdisMRegisterInterrupt.
SynchronizeFunction
Specifies the entry point of the driver's MiniportSynchronizeISR function.
SynchronizeContext
Pointer to miniport driver-determined context area to be passed to the MiniportSynchronizeISR function when it is called.

Return Value

NdisMSynchronizeWithInterrupt returns the Boolean value returned by MiniportSynchronizeISR.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The value returned by MiniportSynchronizeISR is also returned by NdisMSynchronizeWithInterrupt. This propagated value can be used to provide a status to the caller.

Any miniport driver function that shares resources with any other driver function that runs at DIRQL must use NdisMSynchronizeWithInterrupt to synchronize its access to those resources. The MiniportSynchronizeISR function also runs at DIRQL, and the shared resources are protected by a system-allocated spin lock on multiprocessor platforms. Thus, the shared resources are protected from simultaneous access by the MiniportISR or MiniportDisableInterrupt function and the caller whenever the driver is running on a multiprocessor machine.

NdisMSynchronizeWithInterrupt releases the system spin lock and restores the orginal IRQL of its caller before it returns control.

Callers of NdisMSynchronizeWithInterrupt run at IRQL <= DIRQL.

See Also

MiniportDisableInterrupt, MiniportISR, MiniportSynchronizeISR, NdisMDeregisterInterrupt, NdisMRegisterInterrupt


NdisMTransferDataComplete

NdisMTransferDataComplete returns the packet and completion status for a transfer-data request for which the miniport driver previously returned NDIS_STATUS_PENDING.

VOID
  NdisMTransferDataComplete(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN PNDIS_PACKET  Packet,
    IN NDIS_STATUS  Status,
    IN UINT  BytesTransferred
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.
Packet
Pointer to the protocol-allocated packet for which MiniportTransferData previously returned NDIS_STATUS_PENDING.
Status
Specifies the final NDIS_STATUS_XXX for the just completed transfer-data request.
BytesTransferred
Specifies the number of bytes actually transferred to the packet.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Whenever MiniportTransferData returns NDIS_STATUS_PENDING for a given packet, the driver must call NdisMTransferDataComplete when it has finished copying the requested data into that packet or must fail the request.

A miniport driver that indicates receives with NdisMIndicateReceivePacket never calls NdisMTransferDataComplete because such a driver always indicates full packets up to higher-level drivers.

Miniports that report their NIC's media type as NdisMediumArcnet878_2 also do not call NdisMTransferDataComplete. NDIS copies all packet data such a driver indicates.

Callers of NdisMTransferDataComplete run at IRQL DISPATCH_LEVEL.

See Also

MiniportInitialize, MiniportReturnPacket, MiniportTransferData, NdisAllocatePacket, NdisMIndicateReceivePacket, NdisTransferData, ProtocolReceive, ProtocolReceivePacket


NdisMTrIndicateReceive

NdisMTrIndicateReceive notifies NDIS that a Token Ring packet (or some initial lookahead portion of the packet) has arrived so NDIS can forward the packet to bound protocols.

VOID
  NdisMTrIndicateReceive(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN NDIS_HANDLE  MiniportReceiveContext,
    IN PVOID  HeaderBuffer,
    IN UINT  HeaderBufferSize,
    IN PVOID  LookaheadBuffer,
    IN UINT  LookaheadBufferSize,
    IN UINT  PacketSize
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.
MiniportReceiveContext
Specifies a context handle supplied by the caller. NDIS returns this handle as an input parameter to the MiniportTransferData function if it is called. The miniport driver can use the context area designated by this handle to determine which packet, on which NIC, is being received.
HeaderBuffer
Specifies the base virtual address of the buffered packet header.
HeaderBufferSize
Specifies the size in bytes of the packet header.
LookaheadBuffer
Specifies the base virtual address of a buffer containing the initial LookaheadBufferSize bytes of the data in the packet.
LookaheadBufferSize
Specifies the size in bytes of the lookahead buffer. This value must be at least as large as the lookahead size set when MiniportSetInformation was called with OID_GEN_CURRENT_LOOKAHEAD, or as large as the packet, whichever is smaller. When the packet is smaller than the lookahead size, the lookahead buffer contains the entire frame.

A miniport driver can (and should) set LookaheadBufferSize to something larger than the minimum required if sufficient received data is available on its NIC.

PacketSize
Specifies the size in bytes of the received packet data. This value does not include the HeaderBufferSize.

When PacketSize is larger than LookaheadBufferSize, a protocol driver call to NdisTransferData causes a subsequent call to the MiniportTransferData function, which transfers the remaining data in the packet.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A miniport driver calls NdisMTrIndicateReceive if it designates its NIC as of type NdisMedium802_5 in response to the OID_GEN_MEDIA_IN_USE query, unless the miniport driver indicates receives with NdisMIndicateReceivePacket.

When a miniport driver calls NdisMTrIndicateReceive, NDIS passes a pointer to the header of the packet and a pointer to some or all of the data in the packet to the ProtocolReceive function(s) of bound protocol driver(s). Each protocol that receives the indication can do the following:

  1. Inspect the header and data in the packet to decide whether the indication is of interest to the protocol's client(s).
  2. If it is, copy as much of the header or data as is visible into protocol-allocated memory with NdisMoveMemory.
  3. Get the remaining data, if any, for the indication by allocating a packet descriptor with sufficient chained buffer descriptors and calling NdisTransferData. The call to NdisTransferData causes the NIC driver's MiniportTransferData function to copy the data into the protocol-supplied packet.

For any protocol driver that receives an indication through NdisMTrIndicateReceive, the HeaderBuffer and LookaheadBuffer addresses are valid only during the current call to its ProtocolReceive function, and these buffers are read-only. A protocol driver cannot retain a pointer to the indicated packet with these associated buffers nor can it retain any pointers to these buffers for later use. Any data that a protocol driver needs from such a packet must be copied and saved during the receive indication.

The data in the header is the same as that received on the NIC. A miniport driver need not remove any headers or trailers from the data its NIC receives.

The transmitting driver adds padding to any packet that is too short for the requirements of the medium. The receiving miniport driver can include such padding in the data and length it subsequently indicates. Each bound protocol is responsible for detecting any such padding and ignoring it.

Serialized callers of NdisMTrIndicateReceive run at IRQL DISPATCH_LEVEL. Deserialized callers of NdisMTrIndicateReceive can run at <= IRQL DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportInitialize, MiniportQueryInformation, MiniportSetInformation, MiniportTimer, MiniportTransferData, NdisMTrIndicateReceiveComplete, NdisMIndicateReceivePacket, NdisMoveMemory, NdisTransferData, ProtocolReceive


NdisMTrIndicateReceiveComplete

NdisMTrIndicateReceiveComplete notifies NDIS that a Token Ring receive packet, identified in a preceding call to NdisMTrIndicateReceive, has been fully transferred by the NIC so that NDIS can notify the appropriate bound protocol drivers.

VOID
  NdisMTrIndicateReceiveComplete(
    IN NDIS_HANDLE  MiniportAdapterHandle
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

After any Token Ring receive indication, a miniport driver eventually must call NdisMTrIndicateReceiveComplete to indicate the end of the transfer operation over the net, even if a particular packet is accepted by no bound protocol.

NdisMTrIndicateReceiveComplete both indicates the completion of a transfer operation for a receive and notifies any bound protocol that has already consumed the initial indication that it can begin postprocessing the received data.

When a miniport driver calls NdisMTrIndicateReceiveComplete, NDIS indicates the completion of the receive operation to each such protocol by calling its ProtocolReceiveComplete function.

ProtocolReceiveComplete functions need not operate under the severe time constraints of the corresponding ProtocolReceive functions. However, another receive indication to the ProtocolReceive function can come in while the ProtocolReceiveComplete function is running.

A miniport driver need not call NdisMTrIndicateReceiveComplete in one-to-one correspondence with its calls to NdisMTrIndicateReceive. That is, a NIC driver can issue a single receive-complete indication for some number of receive indications, particularly when network traffic is high. For example, when a miniport driver is continually indicating receives from the same source, it might call NdisMTrIndicateReceiveComplete once for every ten indications. On the other hand, a miniport driver might call NdisMTrIndicateReceiveComplete once for each indication when network traffic is low so that the driver can regain ownership of the memory it allocated for receives promptly. However, a miniport driver must call NdisMTrIndicateReceiveComplete at least once per batch of packets indicated from its MiniportHandleInterrupt function.

Serialized callers of NdisMTrIndicateReceiveComplete run at IRQL DISPATCH_LEVEL. Deserialized callers of NdisMTrIndicateReceiveComplete can run at <= IRQL DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportInitialize, NdisMTrIndicateReceive, ProtocolReceive, ProtocolReceiveComplete


NdisMUnmapIoSpace

NdisMUnmapIoSpace releases a virtual range mapped by an initialization-time call to NdisMMapIoSpace.

VOID
  NdisMUnmapIoSpace(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN PVOID  VirtualAddress,
    IN UINT  Length
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.
VirtualAddress
Specifies the base virtual address for the mapped range that was returned by NdisMMapIoSpace.
Length
Specifies the number of bytes in the range that was mapped with NdisMMapIoSpace.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

When a miniport driver is unloading, any memory range that it mapped during initialization with NdisMMapIoSpace must be released with a call to NdisMUnmapIoSpace.

The Length passed to NdisMUnmapIoSpace must match the Length originally passed to NdisMMapIoSpace.

NdisMUnmapIoSpace can be called only from a NIC driver's MiniportInitialize and MiniportHalt functions.

Callers of NdisMUnmapIoSpace run at IRQL PASSIVE_LEVEL.

See Also

MiniportHalt, MiniportInitialize, NdisMMapIoSpace


NdisMUpdateSharedMemory

NdisMUpdateSharedMemory ensures that data, just transferred from a bus-master NIC, to be read from driver-allocated shared memory is current.

VOID
  NdisMUpdateSharedMemory(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN ULONG  Length,
    IN PVOID  VirtualAddress,
    IN NDIS_PHYSICAL_ADDRESS  PhysicalAddress
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.
Length
Specifies the number of bytes in the range.
VirtualAddress
Specifies the base virtual address within a range returned by NdisMAllocateSharedMemory or NdisMAllocateSharedMemoryAsync.
PhysicalAddress
Specifies the physical address mapped to VirtualAddress.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisMUpdateSharedMemory guarantees that any data written by the NIC is present in host physical memory at the virtual address returned by NdisMAllocateSharedMemory or NdisMAllocateSharedMemoryAsync on certain platforms. On any other platform, a call to NdisMUpdateSharedMemory has no overhead.

Callers of NdisMUpdateSharedMemory run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportInitialize, NdisFlushBuffer, NdisMAllocateMapRegisters, NdisMAllocateSharedMemory, NdisMAllocateSharedMemoryAsync, NdisMFreeSharedMemory, NdisMStartBufferPhysicalMapping


NdisMWanIndicateReceive

NdisMWanIndicateReceive notifies NDISWAN that a packet has been received for an established link to be forwarded to the appropriate bound protocol driver.

VOID
  NdisMWanIndicateReceive(
    OUT PNDIS_STATUS  Status,
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN NDIS_HANDLE  NdisLinkContext,
    IN PUCHAR  PacketBuffer,
    IN UINT  PacketSize
    );

Parameters

Status
Pointer to a caller-supplied variable in which this function returns the status of the indication, which can be one of the following:
NDIS_STATUS_SUCCESS
NDISWAN recognized and accepted the packet.
NDIS_STATUS_NOT_ACCEPTED
NDISWAN did not recognize the frame.

Any other status indicates that NDISWAN recognized the frame, but for some reason was unable to accept it.

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.
NdisLinkContext
Specifies the handle supplied by NDISWAN in the NDIS_MAC_LINE_UP structure at the miniport's initial call to NdisMIndicateStatus for this link.
PacketBuffer
Specifies the base virtual address of the buffer containing the received packet.
PacketSize
Specifies the size in bytes of the received packet data.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

When a miniport driver calls NdisMWanIndicateReceive, NDISWAN indicates the packet by calling the ProtocolReceive functions of bound protocol drivers. The entire packet is available for inspection by protocols, because WAN miniports never indicate partial packets with only a lookahead portion of the packet data.

Consequently, such a protocol will never call NdisTransferData so the underlying miniport driver needs no MiniportTransferData function. The miniport driver always passes up an entire packet due to compression and encryption that might be applied to the packet from the transmitting node. Also, because the link is point-to-point, at least one higher-level protocol accepts each received packet.

For any protocol that receives an indication through NdisMWanIndicateReceive, the buffer at PacketBuffer is valid only during the current call to its ProtocolReceive function. Because the packet might be compressed, the entire packet must be available when this call is made. This buffer should contain the same data and size as the buffer sent by the driver on the remote node.

The data contained in the header is the same as that received on the NIC. A WAN miniport driver need not remove any headers or trailers from the data its NIC receives. The transmitting driver does not add padding to the packet.

Serialized callers of NdisMWanIndicateReceive run at IRQL DISPATCH_LEVEL. Deserialized callers of NdisMWanIndicateReceive can run at <= IRQL DISPATCH_LEVEL.

See Also

MiniportInitialize, MiniportWanSend, NdisMIndicateStatus, NdisMWanIndicateReceiveComplete, ProtocolReceive


NdisMWanIndicateReceiveComplete

NdisMWanIndicateReceiveComplete notifies NDISWAN that one or more receives have been completed for an established link so that NDISWAN can notify the appropriate bound protocol(s).

VOID
  NdisMWanIndicateReceiveComplete(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN NDIS_HANDLE  NdisLinkContext
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.
NdisLinkContext
Specifies the handle supplied by NDISWAN in the NDIS_MAC_LINE_UP structure at the miniport's initial call to NdisMIndicateStatus for this link.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

After any WAN receive indication, a miniport driver must eventually call NdisMWanIndicateReceiveComplete.

NdisMWanIndicateReceiveComplete both indicates the completion of a transfer operation for a receive and notifies any bound protocol that has already consumed the initial indication that it can begin postprocessing the received data.

When a miniport driver calls NdisMWanIndicateReceiveComplete, NDISWAN calls the ProtocolReceiveComplete function(s) of bound protocol driver(s). ProtocolReceiveComplete functions need not operate under the severe time constraints of the corresponding ProtocolReceive functions.

A WAN miniport driver need not call NdisMWanIndicateReceiveComplete in one-to-one correspondence with its calls to NdisMWanIndicateReceive. That is, a NIC driver can issue a single receive-complete indication for some number of receive indications, particularly when a sequence of receives is coming in to its NIC. Such a driver can call NdisMWanIndicateReceiveComplete after several calls to NdisMWanIndicateReceive have occurred, thereby giving bound protocols the opportunity to notify clients of received packets without incurring the overhead of processing one-to-one completion notifications. As a general rule, a miniport driver should call NdisMWanIndicateReceiveComplete once for every ten receive indications when network traffic is high.

On the other hand, a miniport driver might call NdisMWanIndicateReceiveComplete once for each indication when network traffic is low so that the driver can regain ownership of the memory it allocated for receives promptly.

A ProtocolReceive function is re-entrant, and ProtocolReceiveComplete can run concurrently with ProtocolReceive, particularly in SMP machines.

Serialized callers of NdisMWanIndicateReceiveComplete run at IRQL DISPATCH_LEVEL. Deserialized callers of NdisMWanIndicateReceiveComplete can run at <= IRQL DISPATCH_LEVEL.

See Also

MiniportInitialize, NdisMIndicateStatus, NdisMWanIndicateReceive, ProtocolReceive, ProtocolReceiveComplete


NdisMWanSendComplete

NdisMWanSendComplete returns the packet and final status of a completed send request for which the miniport driver previously returned NDIS_STATUS_PENDING.

VOID
  NdisMWanSendComplete(
    IN NDIS_HANDLE  MiniportAdapterHandle,
    IN PNDIS_WAN_PACKET  Packet,
    IN NDIS_STATUS  Status
    );

Parameters

MiniportAdapterHandle
Specifies the handle originally input to MiniportInitialize.
Packet
Pointer to the protocol-supplied packet originally passed in to the MiniportWanSend function.
Status
Specifies the NDIS_STATUS_XXX code describing the outcome of the completed send operation, either NDIS_STATUS_SUCCESS or a miniport driver-determined error status value.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Whenever the MiniportWanSend function returns NDIS_STATUS_PENDING for an incoming packet, the miniport driver must eventually call NdisMWanSendComplete with a pointer to that packet. When MiniportWanSend returns any NDIS_STATUS_XXX except NDIS_STATUS_PENDING for a given packet, that packet is considered completed as soon as MiniportWanSend returns control.

Calling NdisMWanSendComplete does not necessarily imply that the packet has been transmitted over the network, although usually it has before a miniport driver calls this function. However, a miniport driver might call NdisMWanSendComplete as soon as it has successfully programmed its NIC for the transmit operation, particularly if its NIC is a so-called intelligent network card.

NdisMWanSendComplete forwards the completed packet to the ProtocolSendComplete function of the driver that initiated the original send operation. Then, the protocol regains ownership of the packet and all buffers that it allocated for the send.

Serialized callers of NdisMWanSendComplete must run at IRQL DISPATCH_LEVEL. Deserialized callers of NdisMWanSendComplete can run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportInitialize, MiniportWanSend, NdisSend, ProtocolSendComplete


NdisMWriteLogData

NdisMWriteLogData transfers driver-supplied information into the log file for consumption and display by a driver-dedicated Win32 application.

NDIS_STATUS
  NdisMWriteLogData(
    IN NDIS_HANDLE  LogHandle,
    IN PVOID  LogBuffer,
    IN UINT  LogBufferSize
    );

Parameters

LogHandle
Specifies the handle returned by NdisMCreateLog.
LogBuffer
Pointer to a driver-allocated buffer containing the information to be written.
LogBufferSize
Specifies how many bytes of data to copy into the log file.

Return Value

NdisMWriteLogData can return one of the following:

NDIS_STATUS_SUCCESS
The driver-supplied data at LogBuffer has been copied into the log file.
NDIS_STATUS_BUFFER_OVERFLOW
The given LogBufferSize is too large, that is, larger than the log file itself.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If the driver-dedicated application has an outstanding request for log file data, NdisMWriteLogData satisfies that request as soon as it has copied the driver-supplied information into the log file.

The miniport driver can supply a LogBuffer pointer to a location on the kernel stack if it is currently running at IRQL < DISPATCH_LEVEL. Otherwise, LogBuffer must access a buffer that the driver allocated from nonpaged pool.

The driver must release any spin lock it is holding before calling NdisMWriteLogData.

NdisMWriteLogData does not recognize boundaries between log records, nor does the Win32 function, DeviceIoControl, which applications can call with IOCTL_NDIS_GET_LOG_DATA to retrieve data written to an NDIS log file by an NDIS NIC driver. NdisMWriteLogData writes all miniport driver-supplied data at LogBuffer into the log file as a byte stream. DeviceIoControl reads the data from such a log as a byte stream, as well.

Consequently, an application reading an NDIS log must collect retrieved data into records. To aid such an application in collecting variable-length records, any miniport driver writing to such a log can insert a marker at the beginning of each record. Then, the application formatting the retrieved data can search for these markers to determine the start of each record.

Callers of NdisMWriteLogData can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocateMemory, NdisAllocateFromNPagedLookasideList, NdisMCloseLog, NdisMCreateLog, NdisMFlushLog, NdisReleaseSpinLock


NDIS_OOB_DATA_FROM_PACKET

NDIS_OOB_DATA_FROM_PACKET returns a pointer to the out-of-band data block associated with a given packet descriptor.

PNDIS_PACKET_OOB_DATA
  NDIS_OOB_DATA_FROM_PACKET(
    IN PNDIS_PACKET  _Packet
    );

Parameters

Packet
Pointer to a packet descriptor.

Return Value

NDIS_OOB_DATA_FROM_PACKET returns a pointer to the out-of-band data block associated with the given packet descriptor, or it returns NULL if there is no out-of-band information for the packet.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Lower-level NDIS drivers that supply out-of-band information with the packet descriptors they allocate for indications can use NDIS_OOB_DATA_FROM_PACKET to gain access to the out-of-band block associated with a driver-allocated packet descriptor. Such a driver would then set up out-of-band information before indicating a receive packet.

For example, an NDIS intermediate driver might copy the out-of-band information from a received packet into a fresh packet descriptor with NdisMoveMemory before forwarding the indication up to bound protocols. In these circumstances, the intermediate driver calls NdisMoveMemory with the pointers returned by NDIS_OOB_DATA_FROM_PACKET as the Source and Destination pointers and sizeof(NDIS_PACKET_OOB_DATA) as the Length.

Lower-level NDIS drivers also might use this macro when the Status of an indicated packet is returned from NdisMIndicateReceivePacket with NDIS_STATUS_SUCCESS or when MiniportReturnPacket is called with a packet descriptor to be reinitialized for reuse. In these circumstances, the driver can call NdisZeroMemory with the pointer returned by NDIS_OOB_DATA_FROM_PACKET and sizeof(NDIS_PACKET_OOB_DATA) to clear the out-of-band data block associated with the packet descriptor. Alternatively, such a driver can use the appropriate NDIS_SET_PACKET_XXX macros to reinitialize specific members in the out-of-band data block for subsequent indications with the returned packet descriptor.

Higher-level NDIS drivers can use NDIS_OOB_DATA_FROM_PACKET to reinitialize the out-of-band data block associated with the packet descriptors they allocate to specify sends when such a packet descriptor has been returned to the ProtocolSendComplete function. Consequently, drivers underlying such a protocol might use NDIS_OOB_DATA_FROM_PACKET to read the out-of-band information for an incoming send packet.

A driver should never pass a packet descriptor to NdisZeroMemory in an attempt to clear the out-of-band data block associated with a packet descriptor. Doing this destroys the given packet descriptor, renders it useless for subsequent indications or sends, and causes a memory leak. A driver must pass the pointer returned by NDIS_OOB_DATA_FROM_PACKET to zero-(re)initialize the out-of-band data block associated with a driver-allocated packet descriptor.

See Also

MiniportHandleInterrupt, MiniportReturnPacket, MiniportSend, MiniportSendPackets, MiniportTimer, NdisAllocatePacket, NDIS_GET_PACKET_HEADER_SIZE, NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO, NDIS_GET_PACKET_STATUS, NDIS_GET_PACKET_TIME_RECEIVED, NDIS_GET_PACKET_TIME_SENT, NDIS_GET_PACKET_TIME_TO_SEND, NdisMIndicateReceivePacket, NdisMoveMemory, NDIS_PACKET_OOB_DATA, NDIS_SET_PACKET_HEADER_SIZE, NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO, NDIS_SET_PACKET_STATUS, NDIS_SET_PACKET_TIME_RECEIVED, NDIS_SET_PACKET_TIME_SENT, NDIS_SET_PACKET_TIME_TO_SEND, NdisZeroMemory, ProtocolReceive, ProtocolReceivePacket, ProtocolSendComplete


NdisOpenAdapter

NdisOpenAdapter sets up a binding between the calling protocol and a particular underlying NIC driver or NDIS intermediate driver.

VOID
  NdisOpenAdapter(
    OUT PNDIS_STATUS  Status,
    OUT PNDIS_STATUS  OpenErrorStatus,
    OUT PNDIS_HANDLE  NdisBindingHandle,
    OUT PUINT  SelectedMediumIndex,
    IN PNDIS_MEDIUM  MediumArray,
    IN UINT  MediumArraySize,
    IN NDIS_HANDLE  NdisProtocolHandle,
    IN NDIS_HANDLE  ProtocolBindingContext,
    IN PNDIS_STRING  AdapterName,
    IN UINT  OpenOptions,
    IN PSTRING  AddressingInformation  OPTIONAL,
    );

Parameters

Status
Pointer to a caller-supplied variable that can be one of the following values on return from this function:
STATUS_SUCCESS
The requested binding is now set up so the caller can use the values returned at NdisBindingHandle and SelectedMediumIndex in subsequent calls to Ndis Xxx.
NDIS_STATUS_PENDING
The requested operation is being handled asynchronously, and the caller's ProtocolOpenAdapterComplete function will be called when the open is completed.
NDIS_STATUS_RESOURCES
The requested operation failed because NDIS could not allocate sufficient memory or initialize state it uses to track an open binding.
NDIS_STATUS_ADAPTER_NOT_FOUND
The requested operation failed because the name at AdapterName could not be found in the system object namespace.
NDIS_STATUS_UNSUPPORTED_MEDIA
The array at MediumArray did not specify any medium that is supported by NDIS or by the underlying driver.
NDIS_STATUS_CLOSING
Either the caller or the physical or virtual device designated at AdapterName is being closed.
NDIS_STATUS_OPEN_FAILED
The open attempt failed for none of the preceding specific reasons. For example, possibly NDIS could not initialize the filter package for the selected medium.
OpenErrorStatus
Pointer to a caller-supplied variable that can contain an NDIS_STATUS_XXX error supplying more information if NdisOpenAdapter returns an error at Status. For example, the driver of a Token Ring NIC might return a ring error in this variable.
NdisBindingHandle
Pointer to a caller-supplied variable in which NDIS returns a handle representing a successful binding between the caller and the given physical or virtual NIC specified at AdapterName.
SelectedMediumIndex
Pointer to a caller-supplied variable in which NDIS returns the index of the array element that specifies the type of media the underlying NDIS driver uses.
MediumArray
Pointer to an array of NDIS_MEDIUM-type values specifying the types of media the caller can support. Possible elements include any proper subset of the following:
NdisMedium802_3
Specifies an Ethernet (802.3) network.
NdisMedium802_5
Specifies a Token Ring (802.5) network.
NdisMediumFddi
Specifies a Fiber Distributed Data Interface (FDDI) network.
NdisMediumWan
Specifies a wide area network. This type covers various forms of point-to-point and WAN NICs, as well as variant address/header formats that must be negotiated between the protocol driver and the underlying driver after the binding is established.
NdisMediumLocalTalk
Specifies a LocalTalk network.
NdisMediumDix
Specifies an Ethernet network for which the drivers use the DIX Ethernet header format.
NdisMediumArcnetRaw
Specifies an ARCNET network.
NdisMediumArcnet878_2
Specifies an ARCNET (878.2) network.
NdisMediumAtm
Specifies an ATM network. Connection-oriented client protocols can bind themselves to an underlying miniport driver that returns this value. Otherwise, legacy protocols bind themselves to the system-supplied LanE intermediate driver, which reports its medium type as either of NdisMedium802_3 or NdisMedium802_5, depending on how the LanE driver is configured by the network administrator.
NdisMediumWirelessWan
Specifies a wireless network. This type covers various wireless media that do not include the infrared wireless types designated by NdisMediumIrda.
NdisMediumIrda
Specifies an infrared (IrDA) network.
NdisMediumCoWan
Specifies a wide area network in a connection-oriented environment.
NdisMedium1394
Specifies an IEEE 1394 (fire wire) network.
MediumArraySize
Specifies the number of elements at MediumArray.
NdisProtocolHandle
Specifies the handle returned by NdisRegisterProtocol.
ProtocolBindingContext
Specifies the handle for a caller-supplied resident context area in which the protocol maintains state about this binding after it has been established.
AdapterName
Pointer to an NDIS_STRING type containing a counted string, specified in the system-default character set, naming the NIC or the virtual adapter of an underlying NDIS driver. This driver exports a set of upper-edge (MiniportXxx) functions. For Windows 2000 and later drivers, this counted string contains Unicode characters. That is, for Windows 2000 and later, NDIS defines the NDIS_STRING type as a UNICODE_STRING type.
OpenOptions
Specifies a bitmask containing flags the caller passes to the next-lower driver, assumed to be a NIC driver. Currently, this parameter is reserved for system use.
AddressingInformation
Pointer to an optional variable-length counted string containing information specific to the underlying NIC that the NIC driver can use to program the netcard. This pointer can be NULL.

If it is supplied, the addressing information must remain valid until the open operation completes. An underlying NIC driver that supports an asynchronous modem can use this information for dialing.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A protocol driver calls NdisOpenAdapter from its ProtocolBindAdapter function. NDIS no longer supports calling NdisOpenAdapter from the DriverEntry function, which was an option available to legacy (V3.0) protocols. NDIS no longer supports V3.0 protocols. NDIS fails any attempt to call NdisOpenAdapter outside the context of ProtocolBindAdapter.

The string at AdapterName remains valid only until NdisOpenAdapter returns control, even if it returns NDIS_STATUS_PENDING at Status.

The variables at NdisBindingHandle and SelectedMediumIndex should be ignored until the ProtocolOpenAdapterComplete function is called if NdisOpenAdapter returns NDIS_STATUS_PENDING. Because these variables can remain invalid until ProtocolOpenAdapterComplete is called, they cannot be on the stack. Usually, these variables reside in the ProtocolBindingContext area since this handle is an input parameter to ProtocolOpenAdapterComplete.

A protocol driver should keep the handle returned at NdisProtocolHandle. It is a required parameter to other Ndis Xxx functions that the driver calls subsequently. The supplied ProtocolBindingContext is an input parameter to the caller's ProtocolXxx functions, so protocols usually pass an NdisProtocolHandle pointer to a variable somewhere in the caller-allocated context area in their calls to NdisOpenAdapter.

The caller uses the value returned at SelectedMediumIndex in subsequent calls to NdisRequest and/or NdisCoRequest. The OIDs it sets in the request packet depend on the returned NdisMedium Xxx. For example, if NdisMediumAtm is returned at SelectedMediumIndex, the protocol driver calls NdisCoRequest when specifying OID_ATM_XXX or OID_CO_XXX codes, and NdisRequest when specifying OID_GEN_XXX codes.

If NdisMediumWan is returned at SelectedMediumIndex, the protocol driver calls NdisRequest specifying OID_WAN_MEDIUM_SUBTYPE in a query to determine which of the WAN media types the underlying driver uses.

If a previously issued global query of OID_NETWORK_TYPE for wireless media indicates that the driver and underlying NIC support more than one NdisMediumWirelessWan-type medium, the protocol must select one of the supported media as soon as NDIS has set up the binding and before the protocol selects the header format.

For more information about the general and medium-specific OIDs that protocol drivers use to negotiate with a just-bound NDIS driver, see NDIS Object Identifiers.

Callers of NdisOpenAdapter run at IRQL PASSIVE_LEVEL.

See Also

ANSI_STRING, DriverEntry of NDIS Protocol Drivers, MiniportInitialize, MiniportQueryInformation, MiniportSendPackets, MiniportSetInformation, NdisCloseAdapter, NdisClOpenAddressFamily, NdisCoRequest, NdisCmRegisterAddressFamily, NdisIMInitializeDeviceInstance, NdisIMRegisterLayeredMiniport, NdisMIndicateReceivePacket, NDIS_PACKET_OOB_DATA, NdisRegisterProtocol, NdisRequest, NdisSendPackets, ProtocolBindAdapter, ProtocolOpenAdapterComplete, ProtocolReceivePacket, UNICODE_STRING


NdisOpenConfiguration

NdisOpenConfiguration returns a handle for a registry key in which an NDIS NIC driver's advanced configuration parameters are stored.

VOID
  NdisOpenConfiguration(
    OUT PNDIS_STATUS  Status,
    OUT PNDIS_HANDLE  ConfigurationHandle,
    IN NDIS_HANDLE  WrapperConfigurationContext
    );

Parameters

Status
Pointer to a caller-supplied variable in which this function returns the status of its attempt to open the registry key. Possible return values are:
NDIS_STATUS_SUCCESS
NDIS has initialized accessed to the registry key in which the miniport driver's advanced configuration parameters are stored.
NDIS_STATUS_FAILURE
The key could not be opened.
ConfigurationHandle
Pointer to a caller-supplied variable in which this function returns a handle to the registry key in which an NDIS NIC driver's advanced configuration parameters are stored. Value entries under this key were provided by the driver's installation script.
WrapperConfigurationContext
Specifies the handle input to MiniportInitialize.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

With the handle returned by NdisOpenConfiguration, an NDIS miniport driver can call NdisReadConfiguration one or more times to extract information about a NIC's advanced configuration parameters from the registry. A miniport driver can also call NdisReadNetworkAddress with this handle to retrieve software-configurable network address information that was stored in the registry when its NIC was installed in the current machine.

A miniport driver can call NdisOpenConfigurationKeyByName or NdisOpenConfigurationKeyByIndex to open a subkey relative to the key for which NdisOpenConfiguration returned the handle.

A NIC driver should call NdisMSetAttributes or NdisMSetAttributesEx to identify the type of I/O bus on which its NIC is likely to be found before that driver calls any of the bus-type-specific configuration functions.

After a driver has consumed and, possibly, modified the registry configuration information, the driver must call NdisCloseConfiguration to release the handle obtained from NdisOpenConfiguration and to free any temporary storage NDIS allocated in the driver's calls to NdisReadConfiguration, NdisReadNetworkAddress, and/or NdisWriteConfiguration.

Callers of NdisOpenConfiguration run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisCloseConfiguration, NdisIMRegisterLayeredMiniport, NdisMMapIoSpace, NdisMRegisterInterrupt, NdisMRegisterIoPortRange, NdisMRegisterMiniport, NdisMSetAttributes, NdisMSetAttributesEx, NdisOpenConfigurationKeyByIndex, NdisOpenConfigurationKeyByName, NdisOpenProtocolConfiguration, NdisReadConfiguration, NdisReadEisaSlotInformation, NdisReadNetworkAddress, NdisReadPciSlotInformation, NdisRegisterProtocol, NdisWriteConfiguration


NdisOpenConfigurationKeyByIndex

NdisOpenConfigurationKeyByIndex opens a subkey of a given open registry key designated by a caller-supplied handle.

VOID
  NdisOpenConfigurationKeyByIndex(
    OUT PNDIS_STATUS  Status,
    IN NDIS_HANDLE  ConfigurationHandle,
    IN ULONG  Index,
    OUT PNDIS_STRING  KeyName,
    OUT PNDIS_HANDLE  KeyHandle
    );

Parameters

Status
Pointer to a caller-supplied variable in which this function returns the status of its attempt to open the designated registry key. Possible return values are one of the following:
NDIS_STATUS_SUCCESS
NDIS has initialized accessed to the subkey specified by KeyName and Index.
NDIS_STATUS_FAILURE
The key could not be opened.
ConfigurationHandle
The handle to a registry key for which a subkey is to be opened. Usually ConfigurationHandle was returned by NdisOpenConfiguration or NidsOpenProtocolConfiguration.
Index
Specifies the index of the subkey to be opened. This zero-based value designates the subkey to be opened under the key already opened with ConfigurationHandle.
KeyName
Pointer to an NDIS_STRING type containing a caller-supplied buffer in which this functions returns a counted string in the system-default character set. This string specifies the name of the opened subkey if the call succeeds. For Windows 2000 and later drivers, this string contains Unicode characters. That is, for Windows 2000 and later, NDIS defines the NDIS_STRING type as a UNICODE_STRING type.
KeyHandle
Pointer to a caller-supplied variable in which this function returns a handle to the opened subkey if the call succeeds.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisOpenConfigurationKeyByIndex allows a driver to access configuration information that its installation script stored in a registry subkey.

Note that the ConfigurationHandle passed in to NdisOpenConfigurationKeyByIndex can be any valid handle to a registry key already opened by the caller. NdisOpenConfigurationKeyByIndex returns configuration information for subkeys relative to any valid ConfigurationHandle.

Since NdisOpenConfigurationKeyByIndex references a subkey through an index, the driver does not have to specify subkey names. A driver can sequence through a set of registry subkeys by repeatedly calling NdisOpenConfigurationKeyIndex after incrementing the index until the function returns NDIS_STATUS_FAILURE, thereby indicating that there are no more subkeys to open.

After a driver has consumed and, possibly, modified the configuration information stored in the registry, it must call NdisCloseConfiguration to release the handle obtained from NdisOpenConfigurationKeyByIndex. NdisCloseConfiguration also frees any temporary storage NDIS allocated for the driver's calls to NdisReadConfiguration, NdisReadNetworkAddress, and/or NdisWriteConfiguration with the SubKeyHandle returned by NdisOpenConfigurationKeyByIndex.

Callers of NdisOpenConfigurationKeyByIndex run at IRQL< DISPATCH_LEVEL.

See Also

ANSI_STRING, MiniportInitialize, NdisCloseConfiguration, NdisOpenConfiguration, NdisOpenConfigurationKeyByName, NdisOpenProtocolConfiguration, NdisReadConfiguration, NdisWriteConfiguration, ProtocolBindAdapter, UNICODE_STRING


NdisOpenConfigurationKeyByName

NdisOpenConfigurationKeyByName opens a named subkey of a given open registry key designated by a caller-supplied handle.

VOID
  NdisOpenConfigurationKeyByName(
    OUT PNDIS_STATUS  Status,
    IN NDIS_HANDLE  ConfigurationHandle,
    IN PNDIS_STRING  SubKeyName,
    OUT PNDIS_HANDLE  SubKeyHandle
    );

Parameters

Status
Pointer to a caller-supplied variable in which this function returns the status of its attempt to open the registry key. Possible return values are one of the following:
NDIS_STATUS_SUCCESS
NDIS has initialized accessed to the subkey specified by SubKeyName.
NDIS_STATUS_FAILURE
The key could not be opened.
ConfigurationHandle
The handle to a registry key for which a subkey should be opened. Usually, ConfigurationHandle was returned by NdisOpenConfiguration or NidsOpenProtocolConfiguration.
SubKeyName
Pointer to an NDIS_STRING type containing a caller-supplied, counted string in the system-default character set that specifies the name of the registry subkey to open. For Windows 2000 and later drivers, this string contains Unicode characters. That is, for Windows 2000 and later, NDIS defines the NDIS_STRING type as a UNICODE_STRING type.
SubKeyHandle
Pointer to a caller-supplied variable in which this function returns a handle to the opened subkey if this call is successful.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisOpenConfigurationKeyByName allows a driver to access configuration information that is stored in a named subkey in the registry.

Note that the ConfigurationHandle passed in to NdisOpenConfigurationKeyByName can be any valid handle to a registry key already opened by the caller. NdisOpenConfigurationKeyByName returns configuration information for subkeys relative to any valid ConfigurationHandle.

After a driver has consumed and, possibly, modified the registry configuration information, it must call NdisCloseConfiguration to release the handle obtained from NdisOpenConfigurationKeyByName. NdisCloseConfiguration also frees any temporary storage NDIS allocated in the driver's calls to NdisReadConfiguration, NdisReadNetworkAddress, and/or NdisWriteConfiguration with the SubKeyHandle returned by NdisOpenConfigurationKeyByName.

Callers of NdisOpenConfigurationKeyByName run at IRQL < DISPATCH_LEVEL.

See Also

ANSI_STRING, MiniportInitialize, NdisCloseConfiguration, NdisOpenConfiguration, NdisOpenConfigurationKeyByIndex, NdisOpenProtocolConfiguration, NdisReadConfiguration, NdisWriteConfiguration, ProtocolBindAdapter, UNICODE_STRING


NdisOpenFile

NdisOpenFile returns a handle for an opened file.

VOID
  NdisOpenFile(
    OUT PNDIS_STATUS  Status,
    OUT PNDIS_HANDLE  FileHandle,
    OUT PUINT  FileLength,
    IN PNDIS_STRING  FileName,
    IN NDIS_PHYSICAL_ADDRESS  HighestAcceptableAddress
    );

Parameters

Status
Pointer to a caller-supplied variable in which this function returns the status of the open file operation, which can be one of the following:
NDIS_STATUS_SUCCESS
The handle at FileHandle is valid for a subsequent call to NdisMapFile.
NDIS_STATUS_FILE_NOT_FOUND
The given string at FileName did not specify a name found in the system object namespace.
NDIS_STATUS_RESOURCES
NDIS could not allocate the resources it needed to open the file and allocate a buffer for the file contents.
NDIS_STATUS_ERROR_READING_FILE
The specified file's data could not be read into system memory for subsequent access by the caller.
FileHandle
Pointer to a caller-supplied variable in which this function returns the handle of the opened file if the call succeeds.
FileLength
Pointer to a caller-supplied variable in which this function writes the number of bytes of data in the opened file if the call succeeds.
FileName
Pointer to an NDIS_STRING type containing an initialized counted string, in the system-default character set, naming the file to be opened. For Windows 2000 and later drivers, this string contains Unicode characters. That is, for Windows 2000 and later, NDIS defines the NDIS_STRING type as a UNICODE_STRING type.
HighestAcceptableAddress
Specifies the highest physical address in which the file data can be stored, or specifies -1 if the driver places no restrictions.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisOpenFile opens a disk file, typically a file the driver will later download to program an intelligent NIC. NdisOpenFile also allocates storage to hold file contents for the driver's subsequent call to NdisMapFile.

A NIC driver should call NdisOpenFile only from MiniportInitialize.

When NdisOpenFile returns, the NIC driver can access file data by calling NdisMapFile. It can call NdisUnmapFile to page out the file so it does not consume resources unnecessarily while the driver is not accessing the file data. When finished using the file, MiniportInitialize must call NdisCloseFile.

Callers of NdisOpenFile run at IRQL PASSIVE_LEVEL.

See Also

ANSI_STRING, MiniportInitialize, NdisMCreateLog, NdisCloseFile, NdisMapFile, NdisUnmapFile, UNICODE_STRING


NdisOpenProtocolConfiguration

NdisOpenProtocolConfiguration returns a handle for the registry key in which a protocol driver's per-adapter information is stored.

VOID
  NdisOpenProtocolConfiguration(
    OUT PNDIS_STATUS  Status,
    OUT PNDIS_HANDLE  ConfigurationHandle,
    IN PNDIS_STRING  ProtocolSection
    );

Parameters

Status
Pointer to a caller-supplied variable that is set to NDIS_STATUS_SUCCESS or a failure status on return from this function.
ConfigurationHandle
Pointer to a caller-supplied variable in which this function returns the handle to the registry key for the named miniport driver to which the caller will bind itself later. Value entries under this key contain protocol-installed, adapter-specific information.
ProtocolSection
Pointer to a caller-supplied NDIS_STRING type containing a counted string, specified in the system-default character set. This counted string names the NDIS NIC driver, effectively the adapter, for which the per-adapter parameters key in the registry protocol section should be opened. For Windows 2000 and later protocols, this counted string contains Unicode characters. That is, for Windows 2000 and later, NDIS defines the NDIS_STRING type as a UNICODE_STRING type.

This pointer is the SystemSpecific1 input parameter to the caller's ProtocolBindAdapter function.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisOpenProtocolConfiguration returns a handle that the caller can pass subsequently to the Ndis..Configuration functions to retrieve or store information in the registry.

A protocol driver calls NdisOpenProtocolConfiguration to get a registry key handle to be passed subsequently to other Ndis..Configuration functions, such as NdisRead/WriteConfiguration or NdisOpenConfigurationKeyByName/Index, if its installation script stored adapter-specific configuration information in the protocol section of the registry from which the protocol sets up its bindings.

A protocol can call NdisOpenConfigurationKeyByName or NdisOpenConfigurationKeyByIndex to open any subkey of the registry key for which NdisOpenProtocolConfiguration returns the handle.

Windows 2000 and later protocols call kernel-mode support routines to open their own protocol-specific registry keys. For more information about these support routines, see the Summary of Kernel-Mode Support Routines and Power Management Support Routines.

Callers of NdisOpenProtocolConfiguration run at IRQL PASSIVE_LEVEL.

See Also

ANSI_STRING, NdisCloseConfiguration, NdisInitializeString, NdisInitUnicodeString, NdisOpenConfigurationKeyByIndex, NdisOpenConfigurationKeyByName, NdisReadConfiguration, NdisWriteConfiguration, ProtocolBindAdapter, UNICODE_STRING


NDIS_PACKET_EXTENSION_FROM_PACKET

NDIS_PACKET_EXTENSION_FROM_PACKET returns a pointer to the NDIS_PACKET_EXTENSION structure associated with a packet descriptor.

PNDIS_PACKET_EXTENSION
  NDIS_PACKET_EXTENSION_FROM_PACKET(
    IN PNDIS_PACKET  Packet
    );

Parameters

Packet
Pointer to a packet descriptor.

Return Value

NDIS_PACKET_EXTENSION_FROM_PACKET returns a pointer to the NDIS_PACKET_EXTENSION structure associated with the given packet descriptor, or it returns NULL if there is no per-packet information for the packet.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The NDIS_PACKET_EXTENSION structure contains an array of PVOIDS, each of which either points to or contains a specific type of per-packet information. After obtaining the pointer to the NDIS_PACKET_EXTENSION structure, the driver can use the appropriate array index to access a particular type of per-packet information.

A protocol or miniport driver should call this macro when it needs to read and/or write more than one type of per-packet information associated with a packet descriptor. If the driver needs to access just one type of per-packet information, it should call the NDIS_PER_PACKET_INFO_FROM_PACKET macro.

After obtaining the pointer to the NDIS_PACKET_EXTENSION structure returned by NDIS_PACKET_EXTENSION_FROM_PACKET, a driver can use one of the following array indexes to access a particular type of per-packet information:

TcpIpChecksumPacketInfo
Indexes a pointer to an NDIS_TCP_IP_CHECKSUM_PACKET_INFO structure.
IpSecPacketInfo
Indexes a pointer to an NDIS_IPSEC_PACKET_INFO structure.
TcpLargeSendPacketInfo
Indexes a pointer that contains a ULONG value. Before passing a large TCP packet to a miniport driver for segmentation, the TCP/IP transport writes this value with the maximum segment size (MSS), which is the current maximum transmission unit (MTU). Before completing the send of a large TCP packet that it has segmented into smaller packets, a miniport driver writes this value with the total number of user data bytes that it sent in the packets segmented from the large TCP packet.
ClassificationHandlePacketInfo
This is reserved.
ScatterGatherListPacketInfo
Indexes a pointer to a SCATTER_GATHER_LIST structure, which specifies the mapped logical address ranges of buffers containing DMA data for a packet. A miniport driver that reserves system resources for DMA operations by calling NdisMInitializeScatterGatherDma supplies the obtained logical address ranges to its NIC so that the NIC can perform a DMA transfer.
Ieee8021QInfo
Indexes the Value member of an NDIS_PACKET_8021Q_INFO structure, which specifies 802.1p priority and VLAN identifier information. 802.1p priority information is used to establish packet priority in shared-media 802 networks. The bits in the TagHeader.UserPriority member of NDIS_PACKET_8021Q_INFO specify an 802.1p priority value.
For more information, see 802.1p Packet Priority.
OriginalPacketInfo
Indexes a pointer to a NDIS_PACKET structure. This structure specifies a packet descriptor that contains original information that was previously received over the network and indicated up by the lowest-level driver in a stack of NDIS drivers. Each driver in the layered stack can access the out-of-band (OOB) data block that is associated with the packet that is received from the network without requiring that the packet be copied to each layer.

Callers of this macro can be running at any IRQL.

See Also

NdisMInitializeScatterGatherDma, NDIS_PACKET_8021Q_INFO, NDIS_PACKET_EXTENSION, NDIS_PER_PACKET_INFO_FROM_PACKET, NDIS_IPSEC_PACKET_INFO, NDIS_TCP_IP_CHECKSUM_PACKET_INFO, SCATTER_GATHER_LIST


NdisPacketPoolUsage

NdisPacketPoolUsage returns the number of packet descriptors currently allocated from a packet pool.

UINT
  NdisPacketPoolUsage(
    IN NDIS_HANDLE  PoolHandle
    );

Parameters

PoolHandle
Specifies a handle returned by NdisAllocatePacketPool or NdisAllocatePacketPoolEx.

Return Value

NdisPacketPoolUsage returns the number of packet descriptors currently allocated from the given packet pool.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Before allocating packet descriptors for a send or receive indication, an NDIS driver can call NdisPacketPoolUsage to determine whether it has enough spare packet descriptors available for the send/receive, particularly if the driver has allocated more than one packet pool.

An NDIS driver also can call this function to be sure that all descriptors have been returned to the given packet pool before it calls NdisFreePacketPool.

Callers of NdisPacketPoolUsage must be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocatePacket, NdisAllocatePacketPoolEx, NdisDprAllocatePacket, NdisDprAllocatePacketNonInterlocked, NdisFreePacketPool, NDIS_PACKET


NDIS_PAGABLE_FUNCTION

NDIS_PAGABLE_FUNCTION is a macro used to mark a driver function as pageable code.

NDIS_PAGABLE_FUNCTION(FunctionName)

Parameters

FunctionName
Specifies the name of the driver function to be made pageable.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Any driver function marked with NDIS_PAGABLE_FUNCTION can be paged out of memory after it returns control and paged back into memory if it is called subsequently.

For example, such a function is declared in the driver source as follows:

VOID miniportXxx(...);
#pragma NDIS_PAGABLE_FUNCTION(miniportXxx)
    ...  //other function declarations
VOID
miniportXxx(...)
{
    ...
}
    ...

Because Windows 2000 and later versions in-page operations run at IRQL < DISPATCH_LEVEL, any NDIS driver function that can possibly execute at IRQL >= DISPATCH_LEVEL cannot be made pageable. Marking a driver function pageable when it runs at IRQL >= DISPATCH_LEVEL can cause fatal page faults in that driver.

Usually, NIC drivers can use this macro on their MiniportInitialize and MiniportHalt functions. A miniport driver also can use this macro on internal driver functions called only by MiniportInitialize or MiniportHalt, as long as the functions marked pageable never call any of the Ndis Xxx that raise IRQL, such as NdisAcquireSpinLock.

NDIS protocol drivers can use this macro on any driver function that always runs at IRQL < DISPATCH_LEVEL. Such a function is never called at raised IRQL. Such a function cannot call driver or system-supplied functions that run at IRQL >= DISPATCH_LEVEL.

See Also

MiniportHalt, MiniportInitialize, NDIS_INIT_FUNCTION, ProtocolBindAdapter, ProtocolUnbindAdapter


NDIS_PER_PACKET_INFO_FROM_PACKET

NDIS_PER_PACKET_INFO_FROM_PACKET returns a pointer to a specific type of per-packet information associated with a packet descriptor.

PVOID
  NDIS_PER_PACKET_INFO_FROM_PACKET(
    IN/OUT PNDIS_PACKET  Packet,
    IN NDIS_PER_PACKET_INFO  InfoType
    );

Parameters

Packet
Pointer to a packet descriptor.
InfoType
Specifies, as one of the following values, the specific type of per-packet information to which this macro returns a pointer:
TcpIpChecksumPacketInfo
Specifies checksum information used in offloading checksum tasks from the TCP/IP transport to a miniport driver. When this InfoType value is specified, the macro returns a NDIS_TCP_IP_CHECKSUM_PACKET_INFO structure. This structure contains a union that allows the checksum information to be accessed as a single ULONG value or as bit fields.
IpSecPacketInfo
Specifies IP Security information used in offloading IP Security tasks from the TCP/IP transport to a miniport driver. When this InfoType value is specified, the macro returns a pointer to an NDIS_IPSEC_PACKET_INFO structure.
TcpLargeSendPacketInfo
Specifies information used in offloading the segmentation of a large TCP packet from the TCP/IP transport to a miniport driver. When this InfoType is specified, the macro returns a pointer that contains a ULONG value.

Before passing a large TCP packet to a miniport driver for segmentation, the TCP/IP transport writes this value with the maximum segment size (MSS), which is the current maximum transmission unit (MTU). Before completing the send of a large TCP packet that it has segmented into smaller packets, a miniport driver writes this value with the total number of user data bytes that it sent in the packets segmented from the large TCP packet.

ClassificationHandlePacketInfo
This is reserved.
ScatterGatherListPacketInfo
Specifies information used in a DMA operation. When this InfoType is specified, the macro returns a pointer to a SCATTER_GATHER_LIST structure. This structure specifies the mapped logical address ranges of buffers containing DMA data for a packet. A miniport driver that reserves system resources for DMA operations by calling NdisMInitializeScatterGatherDma supplies the obtained logical address ranges to its NIC so that the NIC can perform a DMA transfer.
Ieee8021QInfo
Specifies information about a packet. When this InfoType is specified, the macro returns the Value member of an NDIS_PACKET_8021Q_INFO structure. This structure can specify 802.1p priority and VLAN identifier information. 802.1p priority information is used to establish packet priority in shared-media 802 networks. A driver can use NDIS_PER_PACKET_INFO_FROM_PACKET with this InfoType value to either retrieve an 802.1p priority value from the packet descriptor or insert an 802.1p priority value into the packet descriptor. For more information, see Packet Support for 802.1p Priority.
OriginalPacketInfo
Specifies a packet descriptor that contains original information that was previously received over the network and indicated up by the lowest-level driver in a stack of NDIS drivers. If this InfoType value is specified, the macro returns a pointer to a NDIS_PACKET structure. A driver uses NDIS_PER_PACKET_INFO_FROM_PACKET with this InfoType value to either retrieve or insert this original-packet information. Using this method of inserting or retrieving, each driver in a layered stack of NDIS drivers can access the out-of-band (OOB) data block that is associated with the packet that is received from the network without requiring that the packet be copied to each layer.

Return Value

NDIS_PER_PACKET_INFO_FROM_PACKET returns a pointer to the per-packet information specified by InfoType, or it returns NULL if there is no such per-packet information for the packet.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A protocol or miniport driver should call this macro when it needs to examine and/or set only a single type of per-packet information—such as checksum information or IP Security information—for a packet. If the driver needs to access more than one type of per-packet information for a packet, it can call NDIS_PER_PACKET_INFO_FROM_PACKET once for each type of data it needs to access. Alternatively, drivers can call the NDIS_PACKET_EXTENSION_FROM_PACKET macro to obtain a pointer to the NDIS_PACKET_EXTENSION structure associated with a given packet descriptor.

Callers of this macro can be running at any IRQL.

See Also

NDIS_IPSEC_PACKET_INFO, NdisMInitializeScatterGatherDma, NDIS_PACKET_8021Q_INFO, NDIS_PACKET_EXTENSION, NDIS_PACKET_EXTENSION_FROM_PACKET, NDIS_TCP_IP_CHECKSUM_PACKET_INFO, SCATTER_GATHER_LIST


NDIS_PHYSICAL_ADDRESS_CONST

NDIS_PHYSICAL_ADDRESS_CONST initializes a static constant of type physical address.

VOID
  NDIS_PHYSICAL_ADDRESS_CONST(
    IN ULONG  Low,
    IN LONG  High
    );

Parameters

Low
Specifies the low-order bytes of the physical address.
High
Specifies the high-order bytes of the physical address.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A driver can be running at any IRQL when it uses the NDIS_PHYSICAL_ADDRESS_CONST macro.

See Also

NdisGetPhysicalAddressHigh, NdisGetPhysicalAddressLow, NdisMAllocateSharedMemory, NdisMAllocateSharedMemoryAsync, NdisSetPhysicalAddressHigh, NdisSetPhysicalAddressLow


NDIS_PORT_TO_PORT

This macro is reserved for use by NDIS.


NdisPrintString

NdisPrintString displays a given string on the debugging window.

ULONG
  NdisPrintString(
    NDIS_STRING  String
    );

Parameters

String
An NDIS_STRING type containing a counted string in the system default character set. For Windows 2000 and later, NDIS defines the NDIS_STRING type as a UNICODE_STRING type.

Return Value

NdisPrintString returns the number of characters written to the debugging window.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisPrintString supplies the equivalent of printf debugging support.

For more information about debugging, see the Driver Writer's Guide.

See Also

ANSI_STRING, NdisMCreateLog, NdisInitAnsiString, NdisInitializeString, NdisInitUnicodeString, UNICODE_STRING


NdisQueryAdapterInstanceName

NdisQueryAdapterInstanceName retrieves the friendly name of a physical NIC or a virtual adapter to which the calling protocol is bound.

NDIS_STATUS
  NdisQueryAdapterInstanceName(
    OUT PNDIS_STRING  AdapterInstanceName,
    IN NDIS_HANDLE  NdisBindingHandle
    );

Parameters

AdapterInstanceName
Pointer to a caller-supplied NDIS_STRING type that receives a counted Unicode string. This string specifies the friendly name of the interface to which the binding refers. This interface is either a physical NIC or a virtual adapter. For Windows 2000 and later, NDIS defines the NDIS_STRING type as a UNICODE_STRING type.
NdisBindingHandle
Specifies the handle that identifies the target NIC or the virtual adapter of the next-lower driver to which the caller is bound. Typically, NdisBindingHandle was returned by the NdisOpenAdapter function.

Return Values

NdisQueryAdapterInstanceName returns NDIS_STATUS_SUCCESS if memory for the string at AdapterInstanceName was successfully allocated; otherwise, it returns NDIS_STATUS_RESOURCES.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A protocol driver uses NdisQueryAdapterInstanceName to retrieve the friendly name of a physical NIC or a virtual adapter to which the protocol is bound. The protocol driver specifies the handle to such a NIC or virtual adapter in NdisBindingHandle. The protocol driver can call NdisOpenAdapter to retrieve this handle.

NdisQueryAdapterInstanceName allocates memory for the string that specifies the friendly name. After the caller finishes using this memory, the caller must call the NdisFreeMemory function to release the memory.

Friendly names are intended to help the user quickly and accurately identify a physical NIC or virtual adapter—for example, "PCI Ethernet Adapter" and "Virtual Private Networking Adapter" are considered friendly names.

Callers of NdisQueryAdapterInstanceName run at IRQL PASSIVE_LEVEL.

See Also

NdisFreeMemory, NdisOpenAdapter, UNICODE_STRING


NdisQueryBuffer

NdisQueryBuffer retrieves the size of the range, and optionally the base virtual address, from a buffer descriptor.

VOID
  NdisQueryBuffer(
    IN PNDIS_BUFFER  Buffer,
    OUT PVOID  *VirtualAddress  OPTIONAL,
    OUT PUINT  Length
    );

Parameters

Buffer
Pointer to the buffer descriptor.
VirtualAddress
Pointer to a caller-supplied variable in which this function returns the base virtual address of the range described.
Length
Pointer to to a caller-supplied variable in which this function returns the number of bytes in the virtual range.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Drivers should call NdisQueryBufferSafe instead of NdisQueryBuffer. NDIS 5.1 miniport drivers must call NdisQueryBufferSafe instead of NdisQueryBuffer. Unlike NdisQueryBuffer, NdisQueryBufferSafe does not cause a bug check if system resources are low or exhausted.

NDIS drivers call NdisQueryBuffer to retrieve information from the buffer descriptors chained to incoming packets for subsequent transfer operations.

The driver must release any spin lock it is holding before calling NdisQueryBuffer.

Callers of NdisQueryBuffer run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportSend, MiniportSendPackets, MiniportTimer, MiniportTransferData, MiniportWanSend, NdisAllocateBuffer, NdisGetFirstBufferFromPacket, NdisGetFirstBufferFromPacketSafe, NdisMoveFromMappedMemory, NdisMoveMemory, NdisMoveToMappedMemory, NdisQueryBufferOffset, NdisQueryBufferSafe, NdisQueryPacket, NdisRawReadPortBufferUchar, NdisRawReadPortBufferUlong, NdisRawReadPortBufferUshort, NdisRawWritePortBufferUchar, NdisRawWritePortBufferUlong, NdisRawWritePortBufferUshort, NdisReleaseSpinLock, NdisUnchainBufferAtBack, NdisUnchainBufferAtFront, ProtocolReceive, ProtocolReceivePacket


NdisQueryBufferOffset

NdisQueryBufferOffset returns the offset within a physical page at which a given buffer begins. Usually, the buffer descriptor was part of a packet chain.

VOID
  NdisQueryBufferOffset(
    IN PNDIS_BUFFER  Buffer,
    OUT PUINT  Offset,
    OUT PUINT  Length
    );

Parameters

Buffer
Pointer to the buffer descriptor.
Offset
Pointer to a caller-supplied variable in which this function returns the zero-based byte offset within the physical page containing the buffer.
Length
Pointer to a caller-supplied variable in which this function returns the size in bytes of the given buffer.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisQueryBufferOffset runs faster than NdisQueryBuffer(Safe). NDIS drivers call NdisQueryBufferOffset in situations where they need to constrain packets by certain criteria. For example, NdisQueryBufferOffset can be used to determine if a buffer crosses a page boundary, if it is odd-byte aligned, and so forth.

Callers of NdisQueryBufferOffset run at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocateBuffer, NdisQueryBuffer, NdisQueryBufferSafe, NdisQueryPacket, NdisUnchainBufferAtBack, NdisUnchainBufferAtFront


NdisQueryBufferSafe

NdisQueryBufferSafe retrieves the size of the range, and optionally the base virtual address, from a buffer descriptor.

VOID
  NdisQueryBufferSafe(
    IN PNDIS_BUFFER  Buffer,
    OUT PVOID  *VirtualAddress  OPTIONAL,
    OUT PUINT  Length
    IN MM_PAGE_PRIORITY Priority
    );

Parameters

Buffer
Pointer to the buffer descriptor.
VirtualAddress
Pointer to a caller-supplied variable in which this function returns the base virtual address of the range described, or set to NULL if:
  • System resources are low or exhausted and Priority was set to LowPagePriority or NormalPagePriority
  • System resources are exhausted and Priority was set to HighPagePriority
Length
Pointer to a caller-supplied variable in which this function returns the number of bytes in the virtual range.
Priority
Indicates the priority of the request as one of the following:
LowPagePriority
Specifies a low priority. It is acceptable for NdisQueryBufferSafe to fail if system resources are low.
NormalPagePriority
Specifies a normal priority. It is acceptable for NdisQueryBufferSafe to fail if system resources are low.
HighPagePriority
Specifies a high priority. It is not acceptable for NdisQueryBufferSafe to fail unless system resources are exhausted.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisQueryBufferSafe is the safe version of NdisQueryBuffer. Unlike NdisQueryBuffer, NdisQueryBufferSafe does not cause a bug check if system resources are low or exhausted. Drivers should call NdisQueryBufferSafe instead of NdisQueryBuffer. NDIS 5.1 driver must call NdisQueryBufferSafe instead of NdisQueryBuffer.

NDIS drivers call NdisQueryBufferSafe to retrieve information from the buffer descriptors chained to incoming packets for subsequent transfer operations.

If Priority was set to LowPagePriority or NormalPagePriority, NdisQueryBufferSafe returns NULL if system resources are low or exhausted. If Priority was set to HighPagePriority, NdisQueryBufferSafe returns NULL if system resources are exhausted.

The driver must release any spin lock it is holding before calling NdisQueryBufferSafe.

Callers of NdisQueryBufferSafe run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportSend, MiniportSendPackets, MiniportTimer, MiniportTransferData, MiniportWanSend, NdisAllocateBuffer, NdisGetFirstBufferFromPacket, NdisGetFirstBufferFromPacketSafe, NdisMoveFromMappedMemory, NdisMoveMemory, NdisMoveToMappedMemory, NdisQueryBuffer, NdisQueryBufferOffset, NdisQueryPacket, NdisRawReadPortBufferUchar, NdisRawReadPortBufferUlong, NdisRawReadPortBufferUshort, NdisRawWritePortBufferUchar, NdisRawWritePortBufferUlong, NdisRawWritePortBufferUshort, NdisReleaseSpinLock, NdisUnchainBufferAtBack, NdisUnchainBufferAtFront, ProtocolReceive, ProtocolReceivePacket


NdisQueryDepthSList

NdisQueryDepthSList returns the current number of entries in a given sequenced, singly linked list.

USHORT
  NdisQueryDepthSList(
    IN PSLIST_HEADER  SListHead
    );

Parameters

SListHead
Pointer to the head of the S-List to be queried, which the caller already initialized with NdisInitializeSListHead.

Return Value

NdisQueryDepthSList returns the number of entries currently in the S-List.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Callers of NdisQueryDepthSList can be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisInitializeSListHead, NdisInterlockedPushEntrySList, NdisInterlockedPopEntrySList


NdisQueryPacket

NdisQueryPacket returns information about a given packet.

VOID
  NdisQueryPacket(
    IN PNDIS_PACKET  Packet,
    OUT PUINT  PhysicalBufferCount  OPTIONAL,
    OUT PUINT  BufferCount  OPTIONAL,
    OUT PNDIS_BUFFER  *FirstBuffer  OPTIONAL,
    OUT PUINT  TotalPacketLength  OPTIONAL
    );

Parameters

Packet
Pointer to a packet descriptor.
PhysicalBufferCount
Pointer to a caller-supplied variable in which this function returns the maximum number of physical breaks mapped by the buffer descriptors chained to the given packet. This parameter can be NULL.
BufferCount
Pointer to a caller-supplied variable in which this function returns the number of buffer descriptors chained to the given packet. This parameter can be NULL.
FirstBuffer
Pointer to a caller-supplied variable in which this function returns a pointer to the initial buffer descriptor chained to the given packet. This parameter can be NULL.
TotalPacketLength
Pointer to a caller-supplied variable in which this function returns the number of bytes of packet data mapped by all chained buffer descriptors. This parameter can be NULL.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisQueryPacket returns caller-selected information about a given packet. The caller must specify at least one of the PhysicalBufferCount, BufferCount, FirstBuffer, and TotalPacketLength pointers, along with the Packet parameter. A caller can specify explicit pointers for all parameters.

Specifying an explicit PhysicalBufferCount pointer is equivalent to summing calls to NdisGetBufferPhysicalArraySize for each buffer descriptor in the packet descriptor. A driver can call NdisGetNextBuffer as many times as necessary to retrieve pointers to any subsequent buffer descriptors in the chain, unless the call returns zero indicating the packet descriptor has no data.

If the caller supplies an explicit BufferCount pointer, NdisQueryPacket returns the number of buffer descriptors in the packet chain. The returned value can be used as a loop counter to retrieve buffer descriptors in the chain with either of the NdisUnchainBuffer Xxx functions.

If the caller supplies an explicit FirstBuffer pointer but the packet's buffer chain is empty, NdisQueryPacket returns NULL at FirstBuffer. Otherwise, the caller can use NdisQueryBuffer(Safe) subsequently to get details about the initial buffer descriptor for the packet. As a faster alternative, drivers can call NdisGetFirstBufferFromPacket(Safe) to get a pointer to the initial buffer descriptor.

If the caller supplies an explicit TotalPacketLength pointer, NdisQueryPacket returns the total number of bytes specified by every buffer descriptor chained to the given packet.

Callers of NdisQueryPacket can run at any IRQL.

See Also

MiniportSend, MiniportSendPackets, MiniportTransferData, MiniportWanSend, NdisGetBufferPhysicalArraySize, NdisGetFirstBufferFromPacket, NdisGetFirstBufferFromPacketSafe, NdisGetNextBuffer, NdisQueryBuffer, NdisQueryBufferSafe, NdisUnchainBufferAtBack, NdisUnchainBufferAtFront, ProtocolReceive, ProtocolReceivePacket


NdisQueryPendingIoCount

A protocol driver or intermediate driver calls NdisQueryPendingIoCount to request the number of input and output (I/O) operations that the specified adapter is currently processing.

NDIS_STATUS
  NdisQueryPendingIoCount(
    IN  PVOID  NdisBindingHandle
    OUT PULONG  IoCount
    );

Parameters

NdisBindingHandle
Specifies the handle returned by NdisOpenAdapter that identifies the target NIC or the virtual adapter of the next-lower driver to which the caller is bound.
IoCount
Pointer to a caller-supplied variable into which NDIS writes the number of outstanding I/O operations. I/O operations include sending packets and requests to set or retrieve information maintained by the specified adapter's miniport driver. A zero count indicates that the specified adapter is not processing any I/O operations.

Return Values

Returns one of the following values:

NDIS_STATUS_SUCCESS
The driver successfully returned the number of outstanding I/O operations.
NDIS_STATUS_CLOSING
The binding specified by NdisBindingHandle is being released.
NDIS_STATUS_FAILURE
The binding handle specified by NdisBindingHandle is invalid.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A protocol driver can call NdisQueryPendingIoCount from its ProtocolPnPEvent function when handling a transition to low-power state to determine when the protocol can safely return from its ProtocolPnPEvent function. When the number of outstanding I/O operations drops to zero, the protocol driver can return from its ProtocolPnPEvent function without inadvertently causing any outstanding I/O operations to be aborted.

Note that, during the call to NdisQueryPendingIoCount, the protocol driver must not request that the adapter identified by NdisBindingHandle perform any new I/O operations (sends or information requests).

System support for NdisQueryPendingIoCount is available in Windows XP and later OS versions.

Callers of NdisQueryPendingIoCount run at IRQL <= DISPATCH_LEVEL.

See Also

NET_PNP_EVENT for Protocol Drivers, NdisCompletePnPEvent, ProtocolPnPEvent


NdisQuerySendFlags

Use NdisGetPacketFlags instead.


NdisRawReadPortBufferUchar

NdisRawReadPortBufferUchar reads a specified number of bytes into a caller-supplied buffer.

VOID
  NdisRawReadPortBufferUchar(
    IN ULONG_PTR  Port,
    OUT PUCHAR  Buffer,
    IN ULONG  Length
    );

Parameters

Port
Specifies the I/O port. This address falls in a range that was mapped during initialization with NdisMRegisterIoPortRange.
Buffer
Pointer to a caller-allocated buffer, in resident memory, into which the bytes will be transferred from the NIC's port. The caller must allocate a buffer at least sizeof(Length).
Length
Specifies how many bytes to transfer from the NIC.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisRawReadPortBufferUchar reads each byte, one at a time, from the given I/O port into the given buffer.

Callers of NdisRawReadPortBufferUchar can run at any IRQL.

See Also

MiniportInitialize, NdisMRegisterIoPortRange, NdisRawReadPortBufferUlong, NdisRawReadPortBufferUshort, NdisRawReadPortUchar, NdisRawWritePortBufferUchar


NdisRawReadPortBufferUlong

NdisRawReadPortBufferUlong reads a specified number of ULONGs into a caller-supplied buffer.

VOID
  NdisRawReadPortBufferUlong(
    IN ULONG_PTR  Port,
    OUT PULONG  Buffer,
    IN ULONG  Length
    );

Parameters

Port
Specifies the I/O port. This address falls in a range that was mapped during initialization with NdisMRegisterIoPortRange.
Buffer
Pointer to a caller-allocated buffer, in resident memory, into which the ULONGs will be transferred from the NIC. The caller must allocate a buffer at least (sizeof(ULONG) * Length).
Length
Specifies how many ULONGs to transfer from the NIC.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisRawReadPortBufferUlong reads each ULONG value, one at a time, from the given I/O port into the given buffer.

Callers of NdisRawReadPortBufferUlong can run at any IRQL.

See Also

MiniportInitialize, NdisMRegisterIoPortRange, NdisRawReadPortBufferUchar, NdisRawReadPortBufferUshort, NdisRawReadPortUlong, NdisRawWritePortBufferUlong


NdisRawReadPortBufferUshort

NdisRawReadPortBufferUshort reads a specified number of USHORTs into a caller-supplied buffer.

VOID
  NdisRawReadPortBufferUshort(
    IN ULONG_PTR  Port,
    OUT PUSHORT  Buffer,
    IN ULONG  Length
    );

Parameters

Port
Specifies the I/O port. This address falls in a range that was mapped during initialization with NdisMRegisterIoPortRange.
Buffer
Pointer to a caller-allocated buffer, in resident memory, into which the USHORTs will be transferred from the NIC. The caller must allocate a buffer at least (sizeof(USHORT) * Length).
Length
Specifies how many USHORTs to transfer from the NIC.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisRawReadPortBufferUshort reads each USHORT value, one at a time, from the given I/O port into the given buffer.

Callers of NdisRawReadPortBufferUshort can run at any IRQL.

See Also

MiniportInitialize, NdisMRegisterIoPortRange, NdisRawReadPortBufferUchar, NdisRawReadPortBufferUlong, NdisRawReadPortUshort, NdisRawWritePortBufferUshort


NdisRawReadPortUchar

NdisRawReadPortUchar reads a byte from a given I/O port on the NIC.

VOID
  NdisRawReadPortUchar(
    IN ULONG_PTR  Port,
    OUT PUCHAR  Data
    );

Parameters

Port
Specifies the I/O port. This address falls in a range that was mapped during initialization with NdisMRegisterIoPortRange.
Data
Pointer to a caller-supplied variable in which this function returns a byte read in from the port.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisRawReadPortUchar runs faster than NdisImmediateReadPortUchar because it need not map a bus-relative I/O port address onto a host-dependent logical port address at every call.

Callers of NdisRawReadPortUchar can run at any IRQL.

See Also

MiniportInitialize, NdisMRegisterIoPortRange, NdisRawReadPortBufferUchar, NdisRawReadPortUlong, NdisRawReadPortUshort, NdisRawWritePortUchar


NdisRawReadPortUlong

NdisRawReadPortUlong reads a ULONG value from a given I/O port on the NIC.

VOID
  NdisRawReadPortUlong(
    IN ULONG_PTR  Port,
    OUT PULONG  Data
    );

Parameters

Port
Specifies the I/O port. This address falls in a range that was mapped during initialization with NdisMRegisterIoPortRange.
Data
Pointer to a caller-supplied variable in which this function returns a ULONG value read in from the port.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisRawReadPortUlong runs faster than NdisImmediateReadPortUlong because it need not map a bus-relative I/O port address onto a host-dependent logical port address at every call.

Callers of NdisRawReadPortUlong can run at any IRQL.

See Also

MiniportInitialize, NdisMRegisterIoPortRange, NdisRawReadPortBufferUlong, NdisRawReadPortUchar, NdisRawReadPortUshort, NdisRawWritePortUlong


NdisRawReadPortUshort

NdisRawReadPortUshort reads a USHORT value from a given I/O port on the NIC.

VOID
  NdisRawReadPortUshort(
    IN ULONG_PTR  Port,
    OUT PUSHORT  Data
    );

Parameters

Port
Specifies the I/O port. This address falls in a range that was mapped during initialization with NdisMRegisterIoPortRange.
Data
Pointer to a caller-supplied variable in which this function returns a USHORT value read in from the port.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisRawReadPortUshort runs faster than NdisImmediateReadPortUshort because it need not map a bus-relative I/O port address onto a host-dependent logical port address at every call.

Callers of NdisRawReadPortUshort can run at any IRQL.

See Also

MiniportInitialize, NdisMRegisterIoPortRange, NdisRawReadPortBufferUshort, NdisRawReadPortUchar, NdisRawReadPortUlong, NdisRawWritePortUshort


NdisRawWritePortBufferUchar

NdisRawWritePortBufferUchar writes a specified number of bytes from a caller-supplied buffer to a given I/O port.

VOID
  NdisRawWritePortBufferUchar(
    IN ULONG_PTR  Port,
    IN PUCHAR  Buffer,
    IN ULONG  Length
    );

Parameters

Port
Specifies the I/O port. This address falls in a range that was mapped during initialization with NdisMRegisterIoPortRange.
Buffer
Pointer to a caller-allocated resident buffer containing the bytes to be written.
Length
Specifies the number of bytes to write to the I/O port.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A NIC driver calls NdisRawWritePortBufferUchar to transfer a sequence of bytes, one at a time, to its NIC.

NdisRawWritePortBufferUchar runs significantly faster than NdisImmediateWritePortBufferUchar because it need not map a bus-relative port address onto a host-dependent logical port address at every call.

Callers of NdisRawWritePortBufferUchar can run at any IRQL.

See Also

MiniportInitialize, NdisMRegisterIoPortRange, NdisRawReadPortBufferUchar, NdisRawWritePortBufferUlong, NdisRawWritePortBufferUshort, NdisRawWritePortUchar


NdisRawWritePortBufferUlong

NdisRawWritePortBufferUlong writes a specified number of ULONG values from a caller-supplied buffer to a given I/O port.

VOID
  NdisRawWritePortBufferUlong(
    IN ULONG_PTR  Port,
    IN PULONG  Buffer,
    IN ULONG  Length
    );

Parameters

Port
Specifies the I/O port. This address falls in a range that was mapped during initialization with NdisMRegisterIoPortRange.
Buffer
Pointer to a caller-allocated resident buffer containing the ULONGs to be written.
Length
Specifies the number of ULONGs to write to the I/O port.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A NIC driver calls NdisRawWritePortBufferUlong to transfer a sequence of ULONGs, one at a time, to its NIC.

NdisRawWritePortBufferUlong runs significantly faster than NdisImmediateWritePortBufferUlong because it need not map a bus-relative port address onto a host-dependent logical port address at every call.

Callers of NdisRawWritePortBufferUlong can run at any IRQL.

See Also

MiniportInitialize, NdisMRegisterIoPortRange, NdisRawReadPortBufferUlong, NdisRawWritePortBufferUchar, NdisRawWritePortBufferUshort, NdisRawWritePortUlong


NdisRawWritePortBufferUshort

NdisRawWritePortBufferUshort writes a specified number of USHORT values from a caller-supplied buffer to a given I/O port.

VOID
  NdisRawWritePortBufferUshort(
    IN ULONG_PTR  Port,
    IN PUSHORT  Buffer,
    IN ULONG  Length
    );

Parameters

Port
Specifies the I/O port. This address falls in a range that was mapped during initialization with NdisMRegisterIoPortRange.
Buffer
Pointer to a caller-allocated resident buffer containing the USHORTs to be written.
Length
Specifies the number of USHORTs to write to the I/O port.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A NIC driver calls NdisRawWritePortBufferUshort to transfer a sequence of USHORTs, one at a time, to its NIC.

NdisRawWritePortBufferUshort runs significantly faster than NdisImmediateWritePortBufferUshort because it need not map a bus-relative port address onto a host-dependent logical port address at every call.

Callers of NdisRawWritePortBufferUshort can run at any IRQL.

See Also

MiniportInitialize, NdisMRegisterIoPortRange, NdisRawReadPortBufferUshort, NdisRawWritePortBufferUchar, NdisRawWritePortBufferUlong, NdisRawWritePortUshort


NdisRawWritePortUchar

NdisRawWritePortUchar writes a byte to an I/O port on the NIC.

VOID
  NdisRawWritePortUchar(
    IN ULONG_PTR  Port,
    IN UCHAR  Data
    );

Parameters

Port
Specifies the I/O port. This address falls in a range that was mapped during initialization with NdisMRegisterIoPortRange.
Data
Specifies the byte to be written.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisRawWritePortUchar runs faster than NdisImmediateWritePortUchar because it need not map a bus-relative I/O port address onto a host-dependent logical port address at every call.

Callers of NdisRawWritePortUchar can run at any IRQL.

See Also

MiniportInitialize, NdisMRegisterIoPortRange, NdisRawReadPortUchar, NdisRawWritePortBufferUchar, NdisRawWritePortUlong, NdisRawWritePortUshort


NdisRawWritePortUlong

NdisRawWritePortUlong writes a ULONG value to an I/O port on the NIC.

VOID
  NdisRawWritePortUlong(
    IN ULONG_PTR  Port,
    IN ULONG  Data
    );

Parameters

Port
Specifies the I/O port. This address falls in a range that was mapped during initialization with NdisMRegisterIoPortRange.
Data
Specifies the ULONG to be written.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisRawWritePortUlong runs faster than NdisImmediateWritePortUlong because it need not map a bus-relative I/O port address onto a host-dependent logical port address at every call.

Callers of NdisRawWritePortUlong can run at any IRQL.

See Also

MiniportInitialize, NdisMRegisterIoPortRange, NdisRawReadPortUlong, NdisRawWritePortBufferUlong, NdisRawWritePortUchar, NdisRawWritePortUshort


NdisRawWritePortUshort

NdisRawWritePortUshort writes a USHORT value to an I/O port on the NIC.

VOID
  NdisRawWritePortUshort(
    IN ULONG_PTR  Port,
    IN USHORT  Data
    );

Parameters

Port
Specifies the I/O port. This address falls in a range that was mapped during initialization with NdisMRegisterIoPortRange.
Data
Specifies the USHORT to be written.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisRawWritePortUshort runs faster than NdisImmediateWritePortUshort because it need not map a bus-relative I/O port address onto a host-dependent logical port address at every call.

Callers of NdisRawWritePortUshort can run at any IRQL.

See Also

MiniportInitialize, NdisMRegisterIoPortRange, NdisRawReadPortUshort, NdisRawWritePortBufferUshort, NdisRawWritePortUchar, NdisRawWritePortUlong


NdisReadConfiguration

NdisReadConfiguration returns the value of a named entry of the specified type from the registry, given the handle to an open registry key.

VOID
  NdisReadConfiguration(
    OUT PNDIS_STATUS  Status,
    OUT PNDIS_CONFIGURATION_PARAMETER  *ParameterValue,
    IN NDIS_HANDLE  ConfigurationHandle,
    IN PNDIS_STRING  Keyword,
    IN NDIS_PARAMETER_TYPE  ParameterType
    );

Parameters

Status
Pointer to a caller-supplied variable in which this function returns the status of the call as one of the following:
NDIS_STATUS_SUCCESS
The buffer specified at ParameterValue contains the returned configuration information.
NDIS_STATUS_RESOURCES
NDIS could not allocate resources, usually enough memory, to return the requested information.
NDIS_STATUS_FAILURE
The requested information could not be found under the opened registry key designated by the ConfigurationHandle.
ParameterValue
Pointer to a caller-supplied variable in which a successful call to NdisReadConfiguration returns a pointer to an NDIS_CONFIGURATION_PARAMETER structure, defined as follows:
typedef struct _NDIS_CONFIGURATION_PARAMETER {
    NDIS_PARAMETER_TYPE ParameterType;
    union {
        ULONG IntegerData;
        NDIS_STRING StringData;
    } ParameterData;
} NDIS_CONFIGURATION_PARAMETER, *PNDIS_CONFIGURATION_PARAMETER;

The members of this structure contain the following data:

ParameterType
Matches the value at ParameterType if the call is successful.
ParameterData
Specifies the value of the given named entry. If ParameterType is a string type, this member is an NDIS_STRING type describing a counted string in the system-default character set. For Windows 2000 and later drivers, such a string contains Unicode characters. That is, for Windows 2000 and later, NDIS defines the NDIS_STRING type as a UNICODE_STRING type.
ConfigurationHandle
Specifies the handle to a registry key returned by NdisOpenConfiguration to a NIC driver, by NdisOpenProtocolConfiguration to a protocol driver, or by NdisOpenConfigurationKeyByIndex or NdisOpenConfigurationKeyByName to either type of NDIS driver.
Keyword
Pointer to a caller-supplied NDIS_STRING type describing a counted string, in the system-default character set, specifying the name of the entry under the open registry key for which to return the value.

Alternatively, pointer to a caller-supplied NDIS_STRING_CONSTANT specifying one of the following predefined entry names along with predefined return values:
Predefined Entry Name Predefined Return Values
Environment NdisEnvironmentWindowsNt
NdisEnvironmentWindows
ProcessorType NdisProcessorX86
//
// Following possible only if
// current machine's Environment ==
// NdisEnvironmentWindowsNt
//
NdisProcessorAlpha
// Following possible only if legacy driver
NdisProcessorMips
NdisProcessorPpc
NdisVersion 0x MMMMmmmm
// where MMMM is the major version and
// mmmm the minor version number.
// For example, 0x00050000 indicates that
// the highest NDIS version supported by
// the system is major version 5, minor
// version 0.

ParameterType
Specifies the type of the value entry as one of the following:
NdisParameterInteger
Specifies an integer in decimal notation.
NdisParameterHexInteger
Specifies an integer in hexadecimal notation.
NdisParameterString
Specifies a string of type NDIS_STRING. For Windows 2000 and later drivers, this is a counted Unicode string.
NdisParameterMultiString
Specifies a multistring parameter of the REG_MULTI_SZ type, which is defined in Windows 2000 and later versions.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

In the configuration registry of Windows 2000 and later versions, an NDIS keyword is a synonym for a value entry name. Such a name is a counted sequence of Unicode characters, terminated with a NUL.

Every NDIS driver can set up configuration information in the registry for itself under the driver's Parameters key using an installation script. For example, a protocol driver might store its own name as an entry with a preformatted string value that can be passed in calls to NdisRegisterProtocol.

Each NIC driver also has associated value entries under the driver's Parameters registry key. The value entries for any particular NIC driver can be device-dependent in nature. For example, an Ethernet NIC driver might have keywords such as InterruptNumber, SharedMemoryAddress, and MulticastListSize. The value associated with such an NDIS keyword can be either an integer (ULONG-type) or a string (NDIS_STRING-type). For example, the set of possible values for the already mentioned InterruptNumber entry might be NdisParameterInteger values 2, 3, 4, or 5, or the equivalents in hexadecimal as NdisParameterHexInteger values.

NdisReadConfiguration buffers and copies the caller-supplied string at Keyword and releases the storage it allocates for this copy before it returns control to the caller. The memory it allocates for the NDIS_CONFIGURATION_PARAMETER structure is freed when the driver releases the ConfigurationHandle with NdisCloseConfiguration. The caller of NdisReadConfiguration is responsible for releasing the buffered string at Keyword.

For more information about setup and installation scripts, Device Installation Overview

Callers of NdisReadConfiguration run at IRQL PASSIVE_LEVEL.

See Also

ANSI_STRING, NdisAnsiStringToUnicodeString, NdisCloseConfiguration, NdisFreeString, NdisInitAnsiString, NdisInitializeString, NdisInitUnicodeString, NdisOpenConfiguration, NdisOpenConfigurationKeyByIndex, NdisOpenConfigurationKeyByName, NdisOpenProtocolConfiguration, NdisReadNetworkAddress, NdisUnicodeStringToAnsiString, NdisWriteConfiguration, UNICODE_STRING


NdisReadEisaSlotInformation

This function is obsolete for Windows XP and later, and is no longer supported.

NdisReadEisaSlotInformation returns EISA configuration information for a NIC on an EISA bus.

VOID
  NdisReadEisaSlotInformation(
    OUT PNDIS_STATUS  Status,
    IN NDIS_HANDLE  WrapperConfigurationContext,
    OUT PUINT  SlotNumber,
    OUT PNDIS_EISA_FUNCTION_INFORMATION  EisaData
    );

Parameters

Status
Pointer to a caller-supplied variable in which this function returns the status of the call as one of the following:
NDIS_STATUS_SUCCESS
The NIC driver can examine the buffered configuration data to determine whether a NIC that it supports has been found and, if so, can use the bus-relative configuration values as parameters to certain Ndis Xxx initialization functions.
NDIS_STATUS_RESOURCES
NDIS could not allocate the resources it needs to collect the EISA configuration information.
NDIS_STATUS_FAILURE
This is a default status, returned if no NIC can be found on an EISA bus or if the caller supplied an invalid parameter. For example, if the caller set the AdapterType to something other than NdisInterfaceEisa when it called NdisMSetAttributes(Ex), NdisReadEisaSlotInformation returns this status.
WrapperConfigurationContext
Specifies the handle input to MiniportInitialize.
SlotNumber
Pointer to a variable in which this function returns the slot number of a NIC found on the EISA bus if this call is successful.
EisaData
Pointer to a caller-allocated buffer, which must be at least sizeof(NDIS_EISA_FUNCTION_INFORMATION).

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisReadEisaSlotInformation reads standard EISA bus configuration information for a NIC that it finds on an EISA I/O bus and copies the bus-relative configuration information into a buffer.

If the call to NdisReadEisaSlotInformation succeeds, this function returns information in the caller-supplied buffer at EisaData, formatted as an NDIS_EISA_FUNCTION_INFORMATION structure.

The NDIS_EISA_FUNCTION_INFORMATION structure is defined as follows:

typedef struct _NDIS_EISA_FUNCTION_INFORMATION {
    ULONG CompressedId;
    UCHAR IdSlotFlags1;
    UCHAR IdSlotFlags2;
    UCHAR MinorRevision;
    UCHAR MajorRevision;
    UCHAR Selections[26];
    UCHAR FunctionFlags;
    UCHAR TypeString[80];
    EISA_MEMORY_CONFIGURATION EisaMemory[9];
    EISA_IRQ_CONFIGURATION EisaIrq[7];
    EISA_DMA_CONFIGURATION EisaDma[4];
    EISA_PORT_CONFIGURATION EisaPort[60];
    UCHAR InitializationData[60];
} NDIS_EISA_FUNCTION_INFORMATION, *PNDIS_EISA_FUNCTION_INFORMATION;

The members of this structure correspond to the standard EISA configuration function block, as follows:

Member | Meaning
CompressedId | Specifies the EISA compressed identification for the device.
IdSlotFlags1 | Specifies byte 0 identifier and slot information.
IdSlotFlags2 | Specifies byte 1 identifier and slot information.
MinorRevision | Specifies the .cfg file minor revision level.
MajorRevision | Specifies the .cfg file major revision level.
Selections[26] | Specifies an array for 26 selections.
FunctionFlags | Specifies function flags.
TypeString[80] | Specifies an array for a type and subtype ASCII string.
EisaMemory[9] | Specifies an array in which each element is an EISA_MEMORY_CONFIGURATION structure, defining the bus-relative device memory range.
EisaIrq[7] | Specifies an array in which each element is an EISA_IRQ_CONFIGURATION structure, defining the bus-relative device interrupt.
EisaDma[4] | Specifies an array in which each element is an EISA_DMA_CONFIGURATION structure, defining the bus-relative DMA capacity, timing, and channel number, if any.
EisaPort[60] | Specifies an array in which each element is an EISA_PORT_CONFIGURATION structure, defining the bus-relative I/O port ranges of the device.
InitializationData[60] | Specifies an array of EISA initialization data.

NIC drivers call NdisReadEisaSlotInformation to identify their respective adapters in the current platform. When a particular driver's NIC is found, the bus-relative configuration parameters returned at EisaData are passed in subsequent calls to functions such as NdisMRegisterInterrupt (EisaIrq), NdisMMapIoSpace (EisaMemory), and NdisMRegisterIoPortRange (EisaPort).

After consuming the returned information, the caller of NdisReadEisaSlotInformation is responsible for releasing the memory allocated at EisaData.

Callers of NdisReadEisaSlotInformation run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisFreeMemory, NdisMMapIoSpace, NdisMRegisterInterrupt, NdisMRegisterIoPortRange, NdisMSetAttributes, NdisMSetAttributesEx, NdisOpenConfiguration, NdisReadEisaSlotInformationEx


NdisReadEisaSlotInformationEx

This function is obsolete for Windows XP and later, and is no longer supported.

NdisReadEisaSlotInformationEx returns EISA configuration information for a NIC on an EISA bus.

VOID
  NdisReadEisaSlotInformationEx(
    OUT PNDIS_STATUS  Status,
    IN NDIS_HANDLE  WrapperConfigurationContext,
    OUT PUINT  SlotNumber,
    OUT PNDIS_EISA_FUNCTION_INFORMATION  *EisaData,
    OUT PUINT  NumberOfFunctions
    );

Parameters

Status
Pointer to a caller-supplied variable in which this function returns the status of the call as one of the following:
NDIS_STATUS_SUCCESS
The NIC driver can examine the buffered configuration data to determine whether a NIC that it supports has been found and, if so, can use the bus-relative configuration values as parameters to certain Ndis Xxx initialization functions.
NDIS_STATUS_RESOURCES
NDIS could not allocate a buffer to contain the requested EISA configuration information or could not allocate the resources it needs to collect the configuration information.
NDIS_STATUS_FAILURE
This is a default status, returned if the caller supplied an invalid parameter. For example, if the caller set the AdapterType to something other than NdisInterfaceEisa when the miniport driver called NdisMSetAttributes(Ex), NdisReadEisaSlotInformationEx returns this status.
WrapperConfigurationContext
Specifies the handle input to MiniportInitialize.
SlotNumber
Pointer to a variable in which this function returns the slot number for the NIC on the EISA bus.
EisaData
Pointer to a caller-supplied variable in which this function returns a pointer to the information it collected. A miniport driver should set the variable at EisaData to NULL before it calls NdisReadEisaSlotInformationEx.
NumberOfFunctions
Pointer to a caller-supplied variable in which this function returns the number of EISA functions for which configuration information was gathered.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisReadEisaSlotInformationEx collects more bus-relative configuration information about a NIC on an EISA bus than NdisReadEisaSlotInformation if additional configuration data is available.

If the call to NdisReadEisaSlotInformationEx succeeds, this function returns the same EISA configuration information as NdisReadEisaSlotInformation followed by any additional NDIS_EISA_FUNCTION_INFORMATION-structured data that is available. See NdisReadEisaSlotInformation for more information about the NDIS_EISA_FUNCTION_INFORMATION structure. NdisReadEisaSlotInformationEx allocates a buffer large enough to contain the available configuration data and resets the variable at EisaData to the address of this buffer.

Callers of NdisReadEisaSlotInformationEx run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisMSetAttributes, NdisMSetAttributesEx, NdisReadEisaSlotInformation


NdisReadNetworkAddress

NdisReadNetworkAddress returns the software-configurable network address that was stored in the registry for a NIC when it was installed in the machine.

VOID
  NdisReadNetworkAddress(
    OUT PNDIS_STATUS  Status,
    OUT PVOID  *NetworkAddress,
    OUT PUINT  NetworkAddressLength,
    IN NDIS_HANDLE  ConfigurationHandle
    );

Parameters

Status
Pointer to a caller-supplied variable in which this function returns the status of the call as one of the following:
NDIS_STATUS_SUCCESS
The caller can use the address returned at NetworkAddress for its NIC.
NDIS_STATUS_FAILURE
There was no NIC address information available in the caller's registry Parameters key or the value stored was not a string.
NetworkAddress
Pointer to a caller-supplied variable in which this function returns a pointer to the buffered network address, stored as a sequence of byte integers, if the call is successful.
NetworkAddressLength
Pointer to a caller-supplied variable in which this function returns the number of bytes returned at NetworkAddress.
ConfigurationHandle
Specifies the handle returned by NdisOpenConfiguration.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisReadNetworkAddress searches the registry Parameters key designated by the given ConfigurationHandle for the keyword NetworkAddress, converts the value of this string-type entry into a sequence of byte integers, and stores the requested information internally. The storage that NDIS allocates for such an address remains valid until the NIC driver calls NdisCloseConfiguration, which frees the memory.

The caller cannot use the variable at NetworkAddress as a pointer unless NdisReadNetworkAddress returns NDIS_STATUS_SUCCESS at Status.

The installation program for a NIC that supports software-configurable network addressing should store a value entry named with the NetworkAddress keyword in the HKLM\System\CurrentControlSet\Control\Class\{4d36e972…}\00 xx key of the registry.

A NIC installer usually stores the value of a NetworkAddress entry in the registry as a string of hexadecimal digits. Optionally, an installer can store such an address as a string of paired digits, with each pair separated from the next by a hyphen. NdisReadNetworkAddress discards hyphens and converts each such pair into a single byte.

In either form, NdisReadNetworkAddress converts the address specified as a string, one character at a time, into the equivalent integer until the string is exhausted.

In the registry of Windows 2000 and later versions, such an installed address string contains Unicode characters.

Callers of NdisReadNetworkAddress run at IRQL PASSIVE_LEVEL.

See Also

NdisCloseConfiguration, NdisOpenConfiguration


NdisReadPciSlotInformation

NdisReadPciSlotInformation returns bus-specific PCI configuration information from the PCI configuration space for a device.

ULONG
  NdisReadPciSlotInformation(
    IN NDIS_HANDLE  NdisAdapterHandle,
    IN ULONG  SlotNumber,
    IN ULONG  Offset,
    IN PVOID  Buffer,
    IN ULONG  Length
    );

Parameters

NdisAdapterHandle
Specifies the MiniportAdapterHandle passed in to MiniportInitialize and to most other MiniportXxx functions.
SlotNumber
Reserved. NDIS ignores this parameter
Offset
Specifies the byte offset within the PCI configuration space at which to begin transferring the configuration information.
Buffer
Pointer to a caller-allocated buffer in which to return the requested configuration information.
Length
Specifies the size in bytes of the buffer at Buffer and, therefore, how many bytes of configuration information to return.

Return Value

NdisReadPciSlotInformation returns how many bytes of configuration information it returned at Buffer.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Miniport drivers call this function from their MiniportInitialize functions. When a driver has consumed the configuration information, it is is responsible for releasing the memory at Buffer with NdisFreeMemory.

Callers of NdisReadPciSlotInformation can run at IRQL <= DISPATCH_LEVEL. Usually, callers are running at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisFreeMemory, NdisMMapIoSpace, NdisMQueryAdapterResources, NdisMRegisterInterrupt, NdisMRegisterIoPortRange, NdisMSetAttributes, NdisMSetAttributesEx, NdisOpenConfiguration


NdisReadPcmciaAttributeMemory

NdisReadPcmciaAttributeMemory reads bus-relative configuration parameters for a PC Card NIC from attribute memory.

ULONG
  NdisReadPcmciaAttributeMemory(
    IN NDIS_HANDLE  NdisAdapterHandle,
    IN ULONG  Offset,
    IN PVOID  Buffer,
    IN ULONG  Length
    );

Parameters

NdisAdapterHandle
Specifies the handle that NDIS passed as an input parameter to MiniportInitialize.
Offset
Specifies the byte offset from the beginning of attribute memory, excluding odd-numbered bytes, at which to begin reading.
Buffer
Pointer to a caller-allocated buffer into which this function copies the specified number of bytes from PC Card attribute memory.
Length
Specifies the number of even-numbered bytes to read from attribute memory, beginning at Offset.

Return Value

NdisReadPcmciaAttributeMemory returns how many bytes it read from attribute memory. A return value of zero indicates that the read operation failed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The driver of a PC Card NIC calls NdisReadPcmciaAttributeMemory to read bus-relative configuration parameters for its NIC from PC Card attribute memory. Such a miniport driver usually calls NdisReadPcmciaAttributeMemory from its MiniportInitialize function. A miniport driver can call NdisReadPcmciaAttributeMemory more than once to read non-overlapping sections of attribute memory.

Drivers of PC Card NICs should use NdisReadPcmciaAttributeMemory to maintain binary compatibility across Microsoft operating systems that support Win32. Drivers should never attempt to read attribute memory directly from the bus.

PC Card attribute memory contains significant information only in even-numbered bytes. NdisReadPcmciaAttributeMemory therefore treats attribute memory as if it were compacted, with all odd (meaningless) bytes removed. The Offset and Length parameters refer to compacted memory (memory consisting only of even-numbered bytes). For example, to read a 6-byte Ethernet address from attribute memory at an actual offset of 0xFF0, the caller of NdisWritePcmciaAttributeMemory would specify an Offset of 0x7F8 (0xFF0/2) and a Length of 6.

Callers of NdisWritePcmciaAttributeMemory run at IRQL <= DISPATCH.

See Also

MiniportInitialize, NdisWritePcmciaAttributeMemory


NdisReadPortBufferUchar

NdisReadPortBufferUchar is called by the NIC driver to read a specified number of UCHARs from its NIC into a buffer.

VOID
  NdisReadPortBufferUchar(
    IN NDIS_HANDLE  NdisAdapterHandle,
    IN ULONG  Port,
    OUT PUCHAR  Buffer,
    IN ULONG  Length
    );

Parameters

NdisAdapterHandle
Specifies the handle that the NDIS interface library associates with the network interface card.
Port
Specifies the I/O port.
Buffer
Pointer to the caller-supplied buffer in which this function writes the UCHAR values read from Port.
Length
Specifies the number of pieces of data to read from Port to Buffer.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisReadPortBufferUchar reads sequentially each byte from the port. It determines how the host accesses the I/O port and processes the read request accordingly.

Callers of NdisReadPortBufferUchar can be running at any IRQL.

See Also

NdisRawReadPortBufferUchar, NdisReadPortUchar, NdisWritePortBufferUchar


NdisReadPortBufferUlong

NdisReadPortBufferUlong is called by the NIC driver to read a specified number of ULONGs from its NIC into a buffer.

VOID
  NdisReadPortBufferUlong(
    IN NDIS_HANDLE  NdisAdapterHandle,
    IN ULONG  Port,
    OUT PULONG  Buffer,
    IN ULONG  Length
    );

Parameters

NdisAdapterHandle
Specifies the handle that the NDIS interface library associates with the network interface card.
Port
Specifies the I/O port.
Buffer
Pointer to the caller-supplied buffer in which this function writes the ULONG values read from Port.
Length
Specifies the number of pieces of data to read from Port to Buffer.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisReadPortBufferUlong reads sequentially each ULONG from the port. It determines how the host accesses the I/O port and processes the read request accordingly.

Callers of NdisReadPortBufferUlong can be running at any IRQL.

See Also

NdisRawReadPortBufferUlong, NdisReadPortUlong, NdisWritePortBufferUlong


NdisReadPortBufferUshort

NdisReadPortBufferUshort is called by the NIC driver to read a specified number of USHORTs from its NIC into a buffer.

VOID
  NdisReadPortBufferUshort(
    IN NDIS_HANDLE  NdisAdapterHandle,
    IN ULONG  Port,
    OUT PUSHORT  Buffer,
    IN ULONG  Length
    );

Parameters

NdisAdapterHandle
Specifies the handle that the NDIS interface library associates with the network interface card.
Port
Specifies the I/O port.
Buffer
Pointer to the caller-supplied buffer in which this function writes the USHORT values read from Port.
Length
Specifies the number of pieces of data to read from Port to Buffer.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisReadPortBufferUshort reads sequentially each ULONG from the port. It determines how the host accesses the I/O port and processes the read request accordingly.

Callers of NdisReadPortBufferShort can be running at any IRQL.

See Also

NdisRawReadPortBufferUshort, NdisReadPortUshort, NdisWritePortBufferUshort


NdisReadPortUchar

NdisReadPortUchar is called by the NIC driver to read a UCHAR from its NIC's I/O port.

VOID
  NdisReadPortUchar(
    IN NDIS_HANDLE  NdisAdapterHandle,
    IN ULONG  Port,
    OUT PUCHAR  Data
    );

Parameters

NdisAdapterHandle
Specifies the handle that the NDIS interface library associates with the network interface card.
Port
Specifies the I/O port.
Data
Pointer to the caller-supplied variable in which this function returns the byte read from Port.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Callers of NdisReadPortUchar can be running at any IRQL.

See Also

NdisRawReadPortUchar, NdisReadPortBufferUchar, NdisWritePortUchar


NdisReadPortUlong

NdisReadPortUlong is called by the NIC driver to read a ULONG from its NIC's I/O port.

VOID
  NdisReadPortUlong(
    IN NDIS_HANDLE  NdisAdapterHandle,
    IN ULONG  Port,
    OUT PULONG  Data
    );

Parameters

NdisAdapterHandle
Specifies the handle that the NDIS interface library associates with the network interface card.
Port
Specifies the I/O port.
Data
Pointer to the caller-supplied variable in which this function returns the ULONG read from Port.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Callers of NdisReadPortUlong can be running at any IRQL.

See Also

NdisRawReadPortUlong, NdisReadPortBufferUlong, NdisWritePortUlong


NdisReadPortUshort

NdisReadPortUshort is called by the NIC driver to read a USHORT from its NIC's I/O port.

VOID
  NdisReadPortUshort(
    IN NDIS_HANDLE  NdisAdapterHandle,
    IN ULONG  Port,
    OUT PUSHORT  Data
    );

Parameters

NdisAdapterHandle
Specifies the handle that the NDIS interface library associates with the network interface card.
Port
Specifies the I/O port.
Data
Pointer to the caller-supplied variable in which this function returns the USHORT read from Port.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Callers of NdisReadPortUshort can be running at any IRQL.

See Also

NdisRawReadPortUshort, NdisReadPortBufferUshort, NdisWritePortUshort


NdisReadRegisterUchar

NdisReadRegisterUchar is called by the NIC driver to read a UCHAR from a memory-mapped device register.

VOID
  NdisReadRegisterUchar(
    IN PUCHAR  Register,
    OUT PUCHAR  Data
    );

Parameters

Register
Pointer to the memory-mapped register. This virtual address must fall within a range returned by an initialization-time call to NdisMMapIoSpace.
Data
Pointer to the caller-supplied variable in which this function returns the UCHAR read from Register.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If a driver calls this function, its NIC's device registers must be mapped to noncached memory during driver initialization.

Callers of NdisReadRegisterUchar can be running at any IRQL.

See Also

MiniportInitialize, NdisMMapIoSpace, NdisReadRegisterUlong, NdisReadRegisterUshort, NdisWriteRegisterUchar


NdisReadRegisterUlong

NdisReadRegisterUlong is called by the NIC driver to read a ULONG from a memory-mapped device register.

VOID
  NdisReadRegisterUlong(
    IN PULONG  Register,
    OUT PULONG  Data
    );

Parameters

Register
Pointer to the memory-mapped register. This virtual address must fall within a range returned by an initialization-time call to NdisMMapIoSpace.
Data
Pointer to the caller-supplied variable in which this function returns the ULONG read from Register.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If a driver calls this function, its NIC's device registers must be mapped to noncached memory during driver initialization.

Callers of NdisReadRegisterUlong can be running at any IRQL.

See Also

MiniportInitialize, NdisMMapIoSpace, NdisReadRegisterUchar, NdisReadRegisterUshort, NdisWriteRegisterUlong


NdisReadRegisterUshort

NdisReadRegisterUshort is called by the NIC driver to read a USHORT from a memory-mapped device register.

VOID
  NdisReadRegisterUshort(
    IN PUSHORT  Register,
    OUT PUSHORT  Data
    );

Parameters

Register
Pointer to the memory-mapped register. This virtual address must fall within a range returned by an initialization-time call to NdisMMapIoSpace.
Data
Pointer to the caller-supplied variable in which this function returns the USHORT read from Register.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If a driver calls this function, its NIC's device registers must be mapped to noncached memory during driver initialization.

Callers of NdisReadRegisterUshort can be running at any IRQL.

See Also

MiniportInitialize, NdisMMapIoSpace, NdisReadRegisterUchar, NdisReadRegisterUlong, NdisWriteRegisterUshort


NdisRecalculatePacketCounts

NdisRecalculatePacketCounts resets the valid counts for a given packet.

VOID
  NdisRecalculatePacketCounts(
    IN OUT PNDIS_PACKET  Packet
    );

Parameters

Packet
Pointer to the packet descriptor.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If a driver explicitly modifies a buffer descriptor chain for a packet descriptor, that driver should call NdisRecalculatePacketCounts with the modified packet. In general, any NDIS driver should avoid modifying buffer descriptor chains that it sets up, and any driver must not modify chains set up by other drivers.

This call resets the valid counts for the packet to FALSE, thereby forcing NdisQueryPacket to recalculate the buffer count for the modified packet if it is called subsequently with that packet.

Callers of NdisRecalculatePacketCounts can run at any IRQL.

See Also

NDIS_PACKET, NdisQueryPacket, NdisReinitializePacket


NdisReEnumerateProtocolBindings

NdisReEnumerateProtocolBindings causes NDIS to call the driver's ProtocolBindAdapter function once for each network adapter for which the driver is configured to bind but to which the driver is not currently bound.

VOID
  NdisReEnumerateProtocolBindings(
    IN NDIS_HANDLE  NdisProtocolHandle
    );

Parameters

NdisProtocolHandle
A handle representing the calling protocol driver. The driver obtained this handle with a previous call to NdisRegisterProtocol.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A protocol or an intermediate driver calls NdisReEnumerateProtocolBindings to rebind to one or more adapters.

An intermediate driver should call NdisReEnumerateProtocolBindings after its ProtocolPnPEvent function receives a NetEventReconfigure on a NULL ProtocolBindingContext. NDIS will then call the driver's ProtocolBindAdapter function once for each adapter for which the driver is now configured to bind.

Callers of NdisReEnumerateProtocolBindings run at IRQL PASSIVE_LEVEL.

See Also

MiniportHalt, MiniportInitialize, NdisRegisterProtocol, ProtocolBindAdapter¸ ProtocolPnPEvent


NdisRegisterProtocol

NdisRegisterProtocol registers an NDIS driver's ProtocolXxx entry points and name with the NDIS library when the driver initializes.

VOID
  NdisRegisterProtocol(
    OUT PNDIS_STATUS  Status,
    OUT PNDIS_HANDLE  NdisProtocolHandle,
    IN PNDIS_PROTOCOL_CHARACTERISTICS  ProtocolCharacteristics,
    IN UINT  CharacteristicsLength
    );

Parameters

Status
Pointer to a caller-supplied variable that can be one of the following values on return from this function:
NDIS_STATUS_SUCCESS
The NDIS library registered the caller as a protocol driver.
NDIS_STATUS_BAD_CHARACTERISTICS
The CharacteristicsLength is too small for the MajorNdisVersion specified in the buffer at ProtocolCharacteristics.
NDIS_STATUS_BAD_VERSION
The MajorNdisVersion specified in the buffer at ProtocolCharacteristics is invalid.
NDIS_STATUS_RESOURCES
A shortage of resources, possibly memory, prevented the NDIS library from registering the caller.
NdisProtocolHandle
Pointer to a caller-supplied variable in which this function returns a handle representing the registered driver.
ProtocolCharacteristics
Pointer to an NDIS_PROTOCOL_CHARACTERISTICS structure set up by the caller. The structure at ProtocolCharacteristics is defined as follows:
typedef struct _NDIS_PROTOCOL_CHARACTERISTICS {
    UCHAR MajorNdisVersion;
    UCHAR MinorNdisVersion;
    UINT Reserved;
    OPEN_ADAPTER_COMPLETE_HANDLER OpenAdapterCompleteHandler;
    CLOSE_ADAPTER_COMPLETE_HANDLER CloseAdapterCompleteHandler;
    SEND_COMPLETE_HANDLER SendCompleteHandler;
    TRANSFER_DATA_COMPLETE_HANDLER TransferDataCompleteHandler;
    RESET_COMPLETE_HANDLER ResetCompleteHandler;
    REQUEST_COMPLETE_HANDLER RequestCompleteHandler;
    RECEIVE_HANDLER ReceiveHandler;
    RECEIVE_COMPLETE_HANDLER ReceiveCompleteHandler;
    STATUS_HANDLER StatusHandler;
    STATUS_COMPLETE_HANDLER StatusCompleteHandler;
    NDIS_STRING Name;
//
// MajorNdisVersion must be set to 0x04 or 0x05
// with any of the following members.
//
    RECEIVE_PACKET_HANDLER ReceivePacketHandler;
    BIND_HANDLER BindAdapterHandler;
    UNBIND_HANDLER UnbindAdapterHandler;
    PNP_EVENT_HANDLER PnPEventHandler;
    UNLOAD_PROTOCOL_HANDLER UnloadHandler;
//
// MajorNdisVersion must be set to 0x05
// with any of the following members.
//
    CO_SEND_COMPLETE_HANDLER CoSendCompleteHandler;
    CO_STATUS_HANDLER CoStatusHandler;
    CO_RECEIVE_PACKET_HANDLER CoReceivePacketHandler;
    CO_AF_REGISTER_NOTIFY_HANDLER CoAfRegisterNotifyHandler;
} NDIS_PROTOCOL_CHARACTERISTICS, *PNDIS_PROTOCOL_CHARACTERISTICS;

The driver should initialize this structure with zeros before setting up the following members:

MajorNdisVersion
Specifies the major version of the NDIS library the driver is using. The current value is 0x05, although the NDIS library continues to support existing drivers developed for NDIS V4.0. NDIS no longer supports V3.0 protocols.
MinorNdisVersion
Specifies the minor NDIS version. The current value is 0x00.
Reserved
This member is reserved for system use.
OpenAdapterCompleteHandler
Specifies the entry point of the caller's ProtocolOpenAdapterComplete function.
CloseAdapterCompleteHandler
Specifies the entry point of the caller's ProtocolCloseAdapterComplete function.
SendCompleteHandler
Specifies the entry point of the caller's ProtocolSendComplete function, if any.
TransferDataCompleteHandler
Specifies the entry point of the caller's ProtocolTransferDataComplete function, if any.
ResetCompleteHandler
Specifies the entry point of the caller's ProtocolResetComplete function.
RequestCompleteHandler
Specifies the entry point of the caller's ProtocolRequestComplete function.
ReceiveHandler
Specifies the entry point of the caller's ProtocolReceive function, if any.
ReceiveCompleteHandler
Specifies the entry point of the caller's ProtocolReceiveComplete function.
StatusHandler
Specifies the entry point of the caller's ProtocolStatus function, if any.
StatusCompleteHandler
Specifies the entry point of the caller's ProtocolStatusComplete function.
Name
An NDIS_STRING type containing a caller-initialized counted string, in the system-default character set, naming the driver. For Windows 2000 and later drivers, this string contains Unicode characters. That is, for Windows 2000 and later, NDIS defines the NDIS_STRING type as a UNICODE_STRING type. This string must match that specified in the registery (under Services) when the protocol was installed.

NdisRegisterProtocol converts the supplied string to upper case, so a protocol driver writer cannot assume that changing the case of an already registered protocol name creates a unique name for the driver.

ReceivePacketHandler
Specifies the entry point of the caller's ProtocolReceivePacket function, if any, or NULL. Protocols that bind to any NIC driver that supports multipacket receive indications should supply a ProtocolReceivePacket function to enhance their performance. However, a protocol that binds itself exclusively to connection-oriented miniports also can set this member to NULL.
BindAdapterHandler
Specifies the entry point of the caller's ProtocolBindAdapter function. Callers that set the value in the MajorNdisVersion member to 0x05 or 0x04 must supply a ProtocolBindAdapter function and support Plug and Play. NDIS intermediate drivers also must supply a ProtocolBindAdapter function, which allows those intermediate drivers to call NdisIMRegisterLayeredMiniport and to defer full driver initialization until underlying NIC drivers have initialized.
UnbindAdapterHandler
Specifies the entry point of the caller's ProtocolUnbindAdapter function. NDIS drivers that supply a ProtocolBindAdapter function also must supply a ProtocolUnbindAdapter function.
PnPEventHandler
Specifies the entry point of the caller's ProtocolPnPEvent function, if any.
UnloadHandler
Specifies the entry point of the caller's ProtocolUnbind function, if any, or NULL.
CoSendCompleteHandler
Specifies the entry point of the caller's ProtocolCoSendComplete function, which a connection-oriented client or call manager must supply. A connection-oriented client supplies a ProtocolSendComplete function if it also binds itself to connectionless miniports.
CoStatusHandler
Specifies the entry point of the caller's ProtocolCoStatus function, which a connection-oriented client or call manager must supply. A connection-oriented client supplies a ProtocolStatus function if it also binds itself to connectionless miniports.
CoReceivePacketHandler
Specifies the entry point of the caller's ProtocolCoReceivePacket function, which a connection-oriented client or call manager must supply. A connection-oriented client supplies a ProtocolReceivePacket function and/or ProtocolReceive and ProtocolTransferDataComplete functions if it also binds itself to connectionless miniports.
CoAfRegisterNotifyHandler
Specifies the entry point of the caller's ProtocolAfRegisterNotify function, which a connection-oriented client must supply.
CharacteristicsLength
Specifies the size in bytes of the structure at ProtocolCharacteristics. If the build directive -DNDIS50=1 or -DNDIS40=1 is specified in the sources file ahead of #include Ndis.h, the sizeof(NDIS_PROTOCOL_CHARACTERISTICS) is automatically set to the appropriate value. If neither directive is specified, NDIS assumes the V3.0 characteristics structure is being used.

The values set in the MajorNdisVersion and MinorNdisVersion members of the characteristics structure must be consistent with the build directive, or they must be 0x03 and 0x00, respectively.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A protocol driver must specify an MajorNdisVersion of 0x05 (the current version) or 0x04. NDIS no longer supports V.30 protocols and therefore does not load a protocol that specifies an MajorNdisVersion of 0x03.

All protocols must be Plug-and-Play (PnP) capable. A protocol must therefore specify entry points for BindAdapterHandler and UnbindAdapterHandler. NDIS does not load a protocol that specifies NULL for these handlers.

For the best possible performance, any protocol that will layer itself above a connectionless NIC driver that supports multipacket receives should provide a ProtocolReceivePacket function. Such a protocol driver also must provide a ProtocolReceive function. Any connectionless NIC driver that supports multipacket sends is also likely to indicate multipacket receives.

All connection-oriented protocols, whether clients or call managers, must register a ProtocolCoReceivePacket function. Client protocols that also bind themselves to connectionless NIC drivers provide ProtocolReceivePacket and ProtocolReceive functions as well. Connection-oriented protocols must register additional connection-oriented entry points with NDIS by calling either NdisClOpenAddressFamily for clients or NdisCmRegisterAddressFamily for call managers from their ProtocolBindAdapter functions.

After a successful call to NdisRegisterProtocol, a driver cannot alter the set of ProtocolXxx functions it supplied.

A successfully registered driver should save the handle returned at NdisProtocolHandle. It is a required parameter to other Ndis Xxx functions that the driver calls subsequently.

After a successful call to NdisRegisterProtocol, the DriverEntry function of a PnP-aware or connection-oriented protocol returns control because such a driver's ProtocolBindAdapter function will be called subsequently one or more times to set up bindings to underlying NIC(s). Otherwise, the protocol driver can call NdisOpenAdapter to set up a binding to the underlying NIC driver or to layer itself above any NDIS driver that registered a set of NDIS MiniportXxx functions.

Callers of NdisRegisterProtocol run at IRQL PASSIVE_LEVEL.

See Also

ANSI_STRING, DriverEntry of NDIS Protocol Drivers, NdisClOpenAddressFamily, NdisCmRegisterAddressFamily, NdisDeregisterProtocol, NdisIMRegisterLayeredMiniport, NdisInitializeString, NdisInitUnicodeString, NdisMCmRegisterAddressFamily, NdisOpenAdapter, NdisZeroMemory, ProtocolBindAdapter, ProtocolCloseAdapterComplete, ProtocolCoAfRegisterNotify, ProtocolCoReceivePacket, ProtocolCoSendComplete, ProtocolCoStatus, ProtocolOpenAdapterComplete, ProtocolPnPEvent, ProtocolReceive, ProtocolReceiveComplete, ProtocolReceivePacket, ProtocolRequestComplete, ProtocolResetComplete, ProtocolSendComplete, ProtocolStatus, ProtocolStatusComplete, ProtocolTransferDataComplete, ProtocolUnbindAdapter, UNICODE_STRING


NdisReinitializePacket

NdisReinitializePacket removes any chained buffers from a given packet and reinitializes it for reuse.

VOID
  NdisReinitializePacket(
    IN OUT PNDIS_PACKET  Packet
    );

Parameters

Packet
Pointer to the packet descriptor, allocated by the caller.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisReinitializePacket reinitialize a packet descriptor so the MiniportReserved and ProtocolReserved arrays contain all zeros and the head of the buffer chain is set to NULL.

A driver can call NdisReinitializePacket only with packet descriptors allocated by that driver. For example, a MiniportReturnPacket function is likely to call NdisReinitializePacket to prepare a driver-allocated packet for use in a subsequent receive indication.

Before calling NdisReinitializePacket, a driver must call NdisFreeBuffer or NdisUnchainBufferAt Xxx as many times as necessary to release or to save all buffer descriptors chained to the packet. Otherwise, a call to NdisReinitializePacket causes a memory leak: all memory associated with the buffer descriptor chain cannot be used by NDIS nor by the driver until the system is rebooted.

A driver can call NdisQueryPacket to determine how many buffer descriptors are chained to a given packet and, therefore, how many calls to NdisFreeBuffer or NdisUnchainBufferAt Xxx are required. It can call NdisGetNextBuffer to retrieve each buffer descriptor pointer to pass to NdisFreeBuffer.

A call to NdisReinitializePacket has no effect on the NDIS_PACKET_OOB_DATA block associated with the packet descriptor. To prepare this block for reuse, the allocating driver can either call NdisZeroMemory with the pointer returned by NDIS_OOB_DATA_FROM_PACKET or it can reset the relevant members with the appropriate NDIS_SET_PACKET_XXX macro(s).

Callers of NdisReinitializePacket can run at any IRQL.

See Also

MiniportReturnPacket, NdisAllocatePacket, NdisDprAllocatePacket, NdisFreeBuffer, NdisGetNextBuffer, NDIS_OOB_DATA_FROM_PACKET, NDIS_PACKET, NDIS_PACKET_OOB_DATA, NdisQueryPacket, NDIS_SET_PACKET_HEADER_SIZE, NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO, NDIS_SET_PACKET_STATUS, NDIS_SET_PACKET_TIME_RECEIVED, NDIS_SET_PACKET_TIME_TO_SEND, NdisUnchainBufferAtBack, NdisUnchainBufferAtFront, NdisZeroMemory


NdisReleaseReadWriteLock

NdisReleaseReadWriteLock releases a lock that was acquired in a preceding call to NdisAcquireReadWriteLock.

VOID
  NdisReleaseReadWriteLock(
    IN PNDIS_RW_LOCK  Lock,
    IN PLOCK_STATE  LockState
    );

Parameters

Lock
Pointer to the acquired lock to be released.
LockState
Pointer to an opaque variable that tracks the state of the lock. This variable exists in the interval between the time the caller acquires and releases the lock.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A driver must initialize a lock before calling any other Ndis..ReadWriteLock function used to gain or release read or write access to the resources protected by that lock. The NdisInitializeReadWriteLock function is used to initialize a lock.

A driver must call NdisAcquireReadWriteLock to acquire a lock before the driver can call NdisReleaseReadWriteLock. Each call to NdisAcquireReadWriteLock requires a reciprocal call to NdisReleaseReadWriteLock.

NdisReleaseReadWriteLock restores the original IRQL used by its caller before the call to NdisAcquireReadWriteLock was made.

Callers of NdisReleaseReadWriteLock are running at IRQL DISPATCH_LEVEL.

See Also

NdisAcquireReadWriteLock, NdisInitializeReadWriteLock


NdisReleaseSpinLock

NdisReleaseSpinLock releases a spin lock that was acquired in a preceding call to NdisAcquireSpinLock.

VOID
  NdisReleaseSpinLock(
    IN PNDIS_SPIN_LOCK  SpinLock
    );

Parameters

SpinLock
Pointer to the acquired spin lock to be released.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A driver must initialize its spin lock with NdisAllocateSpinLock before it calls any other Ndis..SpinLock function to access the resources protected by that spin lock.

A driver must call NdisAcquireSpinLock to acquire the spin lock before it can call NdisReleaseSpinLock. Each call to NdisAcquireSpinLock requires a reciprocal call to NdisReleaseSpinLock before the driver can call NdisAcquireSpinLock again.

NdisReleaseSpinLock restores the original IRQL at which its caller was running before the call to NdisAcquireSpinLock.

Any spin lock acquired with NdisAcquireSpinLock must be released with NdisReleaseSpinLock. Any spin lock acquired with NdisDprAcquireSpinLock must be released with NdisDprReleaseSpinLock.

Callers of NdisReleaseSpinLock are running at IRQL DISPATCH_LEVEL.

See Also

NdisAcquireSpinLock, NdisAllocateSpinLock, NdisDprAcquireSpinLock


NdisRequest

NdisRequest forwards a request to the underlying driver that it query the capabilities or status of its NIC or that it set the state of its NIC.

VOID
  NdisRequest(
    OUT PNDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisBindingHandle,
    IN PNDIS_REQUEST  NdisRequest
    );

Parameters

Status
Pointer to a caller-supplied variable that is set on return from this function. The underlying driver determines which NDIS_STATUS_XXX is returned, but it is usually one of the following values:
NDIS_STATUS_SUCCESS
The requested operation completed successfully.
NDIS_STATUS_PENDING
The request is being handled asynchronously, and the caller's ProtocolRequestComplete function will be called when it is completed.
NDIS_STATUS_INVALID_OID
The OID_XXX code specified in the Oid member of the NDIS_REQUEST-structured buffer at NdisRequest is invalid or unsupported by the underlying driver.
NDIS_STATUS_INVALID_LENGTH or NDIS_STATUS_BUFFER_TOO_SHORT
The value specified in the InformationBufferLength member of the NDIS_REQUEST-structured buffer at NdisRequest does not match the requirements for the given OID_XXX code. If the information buffer is too small, the BytesNeeded member contains the correct value for InformationBufferLength on return from NdisRequest.
NDIS_STATUS_INVALID_DATA
The data supplied at InformationBuffer in the given NDIS_REQUEST structure is invalid for the given OID_XXX code.
NDIS_STATUS_NOT_SUPPORTED or NDIS_STATUS_NOT_RECOGNIZED
The underlying driver does not support the requested operation.
NDIS_STATUS_RESOURCES
The request could not be satisfied due to a resource shortage. Usually, this return indicates that an attempt to allocate memory was unsuccessful, but it does not necessarily indicate that the same request, submitted later, will be failed for the same reason.
NDIS_STATUS_NOT_ACCEPTED
The underlying driver attempted the requested operation, usually a set, on its NIC but it was failed by the netcard. For example, an attempt to set too many multicast addresses might cause the return of this value.
NDIS_STATUS_CLOSING or NDIS_STATUS_CLOSING_INDICATING
The underlying driver failed the requested operation because a close is in progress.
NDIS_STATUS_RESET_IN_PROGRESS
The underlying NIC driver cannot satisfy the request at this time because it is currently resetting the netcard. The caller's ProtocolStatus function was or will be called with NDIS_STATUS_RESET_START to indicate that a reset is in progress. This return value does not necessarily indicate that the same request, submitted later, will be failed for the same reason.
NDIS_STATUS_FAILURE
This value usually is a nonspecific default, returned when none of the more specific NDIS_STATUS_XXX caused the underlying driver to fail the request.
NdisBindingHandle
Specifies the handle returned by NdisOpenAdapter that identifies the target NIC or the virtual adapter of the next-lower driver to which the caller is bound.
NdisRequest
Pointer to a buffered structure specifying the operation requested with a given OID_XXX code for either a query or a set.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A protocol driver must allocate sufficient memory for the information buffer associated with the OID_XXX of the operation it will request. The driver also must allocate and set up the buffer at NdisRequest before it calls NdisRequest. Both buffers must be allocated from nonpaged pool because the underlying driver runs at raised IRQL while processing the request.

For callers layered above an intermediate NDIS driver, NdisRequest forwards a request to the next-lower driver that it return information about its own capabilities or directs that driver to handle specific functionality in a caller-determined manner. If the next-lower driver is an NDIS intermediate driver, it can call NdisRequest with an OID-specific request of its own before completing the request originally submitted by the higher-level protocol.

Some errors returned at Status are recoverable, including the following:

NDIS_STATUS_INVALID_OID
NDIS_STATUS_INVALID_LENGTH
NDIS_STATUS_BUFFER_TOO_SHORT
NDIS_STATUS_INVALID_DATA
NDIS_STATUS_RESOURCES
NDIS_STATUS_RESET_IN_PROGRESS

That is, a driver can modify the packet at NdisRequest appropriately to correct the OID_XXX code and/or the size or contents of the buffer at InformationBuffer and resubmit the request packet to NdisRequest. The same packet might be satisfied on resubmission to NdisRequest if the original call indicated a reset in progress or that a resource shortage, which might be temporary, prevented that request from being carried out.

The NDIS library maintains bindings for underlying miniport drivers. NDIS can return information for binding-specific queries if a given OID is associated with a system-defined medium type for which the system provides a filter library.

For more information about the general and media-specific OIDs and their respective associated information buffers, see NDIS Object Identifiers.

Callers of NdisRequest can be running at IRQL <= DISPATCH_LEVEL.

See Also

MiniportQueryInformation, MiniportSetInformation, NdisOpenAdapter, NDIS_REQUEST, ProtocolRequestComplete, ProtocolStatus


NdisReset

NdisReset forwards a reset request to an underlying driver.

VOID
  NdisReset(
    OUT PNDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisBindingHandle
    );

Parameters

Status
Pointer to a caller-supplied variable that is set on return from this function. The underlying driver determines which NDIS_STATUS_XXX is returned, but it is usually one of the following values:
NDIS_STATUS_SUCCESS
The underlying driver reset its NIC (or virtual NIC) to its initial state.
NDIS_STATUS_PENDING
The request is being handled asynchronously, and the caller's ProtocolResetComplete function will be called when it is completed.
NDIS_STATUS_RESET_IN_PROGRESS
The underlying driver is currently resetting its NIC so this request is superfluous. Moreover, the caller's ProtocolStatus function was or will be called with NDIS_STATUS_RESET_START to indicate that a reset is in progress.
NDIS_STATUS_NOT_RESETTABLE
The underlying NIC cannot be reset by software commands.
NDIS_STATUS_ADAPTER_REMOVED or NDIS_STATUS_FAILURE
The caller's binding is already closed so no reset will be attempted for this caller.
NDIS_STATUS_CLOSING
The caller's binding is currently being closed so no reset will be attempted for this caller.
NDIS_STATUS_SOFT_ERRORS
The underlying NIC driver reset the netcard but one or more recoverable hardware errors occurred during this operation. The NIC driver has logged the error(s).
NDIS_STATUS_HARD_ERRORS
The underlying NIC driver attempted to reset the netcard but one or more unrecoverable hardware errors occurred during this operation. The NIC driver has logged the error(s).
NDIS_STATUS_NOT_ACCEPTED
This value usually is a nonspecific default, returned when none of the more specific NDIS_STATUS_XXX caused NDIS or the underlying NIC driver to fail the request.
NdisBindingHandle
Specifies the handle returned by NdisOpenAdapter that identifies the target NIC or the virtual adapter of the next-lower driver to which the caller is bound.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

When a protocol calls NdisReset, the NDIS library does not call the MiniportReset function of the underlying NIC driver until NDIS has completed any internally queued send requests back to the initiating protocol(s). Only after NDIS has cleared its send queue for the underlying driver does it call that driver's MiniportReset function.

If the underlying driver queues send packets internally, it also completes any send packets it is currently holding in its queue before attempting to reset its NIC.

Consequently, all protocol drivers bound above the same NIC should hold on to their outstanding send packets during a reset operation. At the start of a reset, NDIS calls the ProtocolStatus function of each bound protocol with NDIS_STATUS_RESET_START and, then, the corresponding ProtocolStatusComplete function. When the reset operation is done, NDIS calls the ProtocolStatus function of each bound protocol again with NDIS_STATUS_RESET_END and, then, the corresponding ProtocolStatusComplete function.

Like any other driver bound above the same NIC, the ProtocolStatus and ProtocolStatusComplete functions of the driver that called NdisReset receive these notifications. However, if NdisReset returns STATUS_PENDING, only the ProtocolResetComplete function of the original caller is notified when the reset operation is done.

A protocol bound to NDISWAN should never call NdisReset.

Callers of NdisReset run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportReset, MiniportSend, ProtocolResetComplete, ProtocolSendComplete, ProtocolStatus, ProtocolStatusComplete


NdisResetEvent

NdisResetEvent clears the Signaled state of a given event.

VOID
  NdisResetEvent(
    IN PNDIS_EVENT  Event
    );

Parameters

Event
Pointer to an initialized event object for which the caller provided the storage.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisResetEvent explicitly sets the state of the given event to Not-Signaled.

When an event is set to the Signaled state with NdisSetEvent, it remains in that state until an explicit call to NdisResetEvent occurs. While an event remains in the Signaled state, callers of NdisWaitEvent on that Event are dispatched for execution without waiting.

Callers of NdisResetEvent run at IRQL <= DISPATCH_LEVEL.

See Also

NdisInitializeEvent, NdisSetEvent, NdisWaitEvent


NdisReturnPackets

NdisReturnPackets releases ownership of one or more packets after a protocol has consumed the received data.

VOID
  NdisReturnPackets(
    IN PNDIS_PACKET  *PacketsToReturn,
    IN UINT  NumberOfPackets
    );

Parameters

PacketsToReturn
Pointer to an array of pointers to packet descriptors to be returned to the underlying driver that allocated them for a receive indication.
NumberOfPackets
Specifies the number of pointers in the array.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

An NDIS intermediate driver should call NdisReturnPackets as soon as possible after its Protocol(Co)ReceivePacket function has returned control. Otherwise, both the underlying driver that supports multipacket receive indications and the bound protocol driver that processes them suffer a performance degradation.

When an underlying NIC driver runs low on available packet pool for receive indications or when its NIC runs low on empty receive buffers, it sets a packet descriptor's associated OOB block Status to NDIS_STATUS_RESOURCES:

  • If the underlying NIC driver is a connectionless driver, this forces the NDIS library to call every bound protocol driver's ProtocolReceive function with a single packet descriptor at a time until the miniport driver has regained ownership of its packet descriptors and the NIC has receive buffers available for incoming net packets.
  • If the underlying NIC driver is a connection-oriented driver, this forces the NDIS library to call every bound protocol driver's ProtocolCoReceivePacket function with a single packet descriptor at a time until the miniport driver has regained ownership of its packet descriptors and the NIC has receive buffers available for incoming net packets.

A ProtocolReceive function cannot begin postprocessing a packet of received data and forwarding the processed data to clients until the driver's ProtocolReceiveComplete function is called.

For a packet descriptor passed in to a connectionless protocol's ProtocolReceivePacket function or to a connection-oriented protocol's ProtocolCoReceivePacket function with an associated OOB Status of NDIS_STATUS_SUCCESS, a highest level protocol driver can process its copy of received data and forward the processed data to clients immediately because the protocol can control how long it retains ownership of the resources allocated by the indicating driver. Assuming a highest level protocol driver does not massage the data it indicates to its clients, the protocol can even set up the range of data within the receive buffer of interest to its client, and make a receive indication to its client(s) by forwarding the input packet descriptor to those clients.

If an intermediate protocol driver's Protocol(Co)ReceivePacket function returns a nonzero reference count to an input packet descriptor, that driver must call NdisReturnPackets one or more times. When it has called NdisReturnPackets with a particular packet descriptor as many times as the value returned by Protocol(Co)ReceivePacket, the NDIS library returns the packet descriptor to the driver that made the indication. For a highest level protocol that forwards an input packet descriptor to its clients, those clients return the packet descriptor to the NDIS driver that allocated it by making calls to TdiReturnChainedReceives.

A protocol driver can rely on NDIS to manage the reference count for every receive packet passed to the Protocol(Co)ReceivePacket function. When the reference count for a packet descriptor originally set to the return from Protocol(Co)ReceivePacket goes to zero, the NDIS library calls the indicating driver's MiniportReturnPacket function with the released packet descriptor.

NdisReturnPackets cannot be called from a Protocol(Co)ReceivePacket function.

Callers of NdisReturnPackets run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportReturnPacket, NdisAllocatePacket, NdisFreePacket, NdisMIndicateReceivePacket, NDIS_PACKET, NDIS_PACKET_OOB_DATA, ProtocolCoReceivePacket, ProtocolReceivePacket, TdiReturnChainedReceives


NdisSend

NdisSend forwards a send request to the underlying driver.

VOID
  NdisSend(
    OUT PNDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisBindingHandle,
    IN PNDIS_PACKET  Packet
    );

Parameters

Status
Pointer to a caller-supplied variable that is set on return from this function. The underlying driver determines which NDIS_STATUS_XXX is returned, but it is usually one of the following values:
NDIS_STATUS_SUCCESS
The given packet is being transmitted over the network.
NDIS_STATUS_PENDING
The request is being handled asynchronously, and the caller's ProtocolSendComplete function will be called when it is completed.
NDIS_STATUS_INVALID_PACKET
The size of the requested transfer is too large for the NIC, or possibly the NIC indicated an erroneous packet transmission to its driver.
NDIS_STATUS_CLOSING
The underlying driver is closing.
NDIS_STATUS_RESET_IN_PROGRESS
The underlying driver is currently resetting the NIC. The caller's ProtocolStatus function was or will be called with NDIS_STATUS_RESET_START to indicate that a reset is in progress.
NDIS_STATUS_FAILURE
This value usually is a nonspecific default, returned when none of the more specific NDIS_STATUS_XXX caused the underlying driver to fail the request.

The specific NDIS_STATUS_XXX returned for device I/O errors that occur during a transmit operation depends on the nature of the NIC and the discretion of the NIC driver writer. For example, a miniport driver might return NDIS_STATUS_NO_CABLE if its NIC indicates this condition to the driver.

NdisBindingHandle
Specifies the handle returned by NdisOpenAdapter that identifies the target NIC or the virtual adapter of the next-lower driver to which the caller is bound. If the underlying driver is a connection-oriented miniport driver, the protocol must call NdisCoSendPackets, rather than NdisSend.
Packet
Pointer to the caller-supplied packet descriptor, allocated with NdisAllocatePacket, with chained buffer descriptors mapping buffers containing the data that the underlying NIC driver should transmit over the wire.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Before calling NdisSend, a protocol driver can call NdisSetPacketFlags to set the flags in the private header (reserved for use by NDIS) of the packet descriptor it allocated. These flags specify caller-determined information about the requested send operation that is not contained in the packet data. The underlying NIC driver's MiniportSend function is given the send flags as an input parameter. The meaning of the packet flags bits is medium-specific and defined by the pair of collaborating drivers.

However, such a pair of collaborating drivers can use the NDIS_PACKET_OOB_DATA block associated with each packet descriptor to communicate far more information than the packet flags can convey. Before calling NdisSend, a protocol can use the NDIS_SET_PACKET_TIME_TO_SEND and/or NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO macros to set up out-of-band information, if any, relevant to the underlying driver in the NDIS_PACKET_OOB_DATA block associated with the protocol-allocated packet descriptor.

When an underlying driver that is serialized has insufficient resources to transmit a valid send packet, it has two alternatives:

  1. Its MiniportSend function can insert the packet into an internal queue and return NDIS_STATUS_PENDING.

    The driver holds the packet queued until resources become available and sends the packet when they are.

  2. Its MiniportSend function can simply return control with NDIS_STATUS_RESOURCES.

    The NDIS library holds such a returned packet in an internal queue for resubmission to the serialized miniport driver. The miniport driver can indicate its readiness to accept send packets later by calling NdisMSendResourcesAvailable or NdisMSendComplete, whichever call occurs first.

In either of the preceding scenarios, NdisSend returns NDIS_STATUS_PENDING to the caller, and that driver's ProtocolSendComplete function is called when the packet has been transmitted. If the underlying driver is deserialized, every packet passed in calls to NdisSend is returned to the caller's ProtocolSendComplete function when the underlying deserialized miniport driver completes the send operation.

As soon as a protocol calls NdisSend, it relinquishes ownership of the packet descriptor at Packet, of all buffers mapped by buffer descriptors it chained to the packet, and of any out-of-band information it supplied with the packet descriptor. The protocol regains ownership of these resources when the packet is completed with a status other than NDIS_STATUS_PENDING or when its ProtocolSendComplete function is called.

When either occurs, the protocol can call NdisReinitializePacket to prepare the packet for reuse after saving the buffer descriptors chained to the packet descriptor with calls to an NdisUnchainBufferAt Xxx function. Reusing such a packet descriptor yields better performance than returning the packet to driver-allocated packet pool with NdisFreePacket and, then, reallocating it for another send later.

An NDIS intermediate driver must repackage incoming sends from still higher level protocols in fresh packet descriptors before passing such a send request to the underlying miniport driver with NdisSend (or NdisSendPackets).

Callers of NdisSend run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportSend, NdisAllocateBuffer, NdisAllocatePacket, NdisCoSendPackets, NdisFreePacket, NdisGetPacketFlags, NdisMSendResourcesAvailable, NDIS_PACKET, NDIS_PACKET_OOB_DATA, NdisReinitializePacket, NdisSendPackets, NdisSetPacketFlags, NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO, NDIS_SET_PACKET_TIME_TO_SEND, NdisUnchainBufferAtBack, NdisUnchainBufferAtFront, ProtocolSendComplete, ProtocolStatus


NdisSendPackets

NdisSendPackets forwards a multipacket send request, possibly with associated out-of-band information, to the underlying driver.

VOID
  NdisSendPackets(
    IN NDIS_HANDLE  NdisBindingHandle,
    IN PPNDIS_PACKET  PacketArray,
    IN UINT  NumberOfPackets
    );

Parameters

NdisBindingHandle
Specifies the handle returned by NdisOpenAdapter that identifies the target NIC or the virtual adapter of the next-lower driver to which the caller is bound. If the underlying driver is a connection-oriented miniport driver, the protocol must call NdisCoSendPackets, rather than NdisSend.
PacketArray
Pointer to an array of pointers to packet descriptors. Each packet descriptor in the array has chained buffer descriptors mapping buffers containing the data that the underlying NIC driver should transmit over the wire. Each packet descriptor also has an associated NDIS_PACKET_OOB_DATA block, which the caller has already set up with any timestamp and/or medium-specific out-of-band information, such as packet priority, relevant to the underlying driver.
NumberOfPackets
Specifies the number of pointers in the packet array.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Each element in the given array is a pointer to an NDIS_PACKET-type descriptor, and each packet descriptor can have caller-set TimeToSend and/or MediaSpecificInformation and MediaSpecificSize values in its associated NDIS_PACKET_OOB_DATA block. The caller must allocate each such packet descriptor with NdisAllocatePacket.

A protocol can set up this timestamp with the NDIS_SET_PACKET_TIME_TO_SEND and any out-of-band information that accompanies the send request with NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO before it calls NdisSendPackets. The underlying driver retrieves this information with the reciprocal NDIS_GET_PACKET_XXX macros.

If necessary, a protocol also can call NdisSetPacketFlags to set the packet descriptor's flags with information for the underlying driver.

If the underlying NIC driver does not export a MiniportSendPackets handler, the NDIS library makes a sequence of calls, one for each packet in the supplied array, to that driver's MiniportSend function. NDIS submits packets individually to an underlying driver's MiniportSend function in the same order as they arrive in the supplied array.

NDIS submits packet arrays to an underlying driver's MiniportSendPackets function in the same order as they are passed to NdisSendPackets, but an underlying serialized miniport driver can return a subset of packets in any incoming array to NDIS by setting NDIS_STATUS_RESOURCES in the out-of-band data block for a single array element. When this occurs, NDIS queues that packet and all subsequent packets in the array for resubmission to the MiniportSendPackets function later.

For serialized miniports, NDIS always preserves the protocol-determined order of send packets, whether passed in calls to NdisSend or NdisSendPackets, and sees that they are given to the underlying driver in FIFO order. Before a protocol driver calls NdisSendPackets with an array of packet descriptor pointers, the protocol must ensure that the array of pointers has been set up in the same order as the packets should be sent over the wire.

The caller of NdisSendPackets should test the returned status for each packet in such an array individually when its ProtocolSendComplete function is called with the completion Status. While NDIS submits packets for transmission in the FIFO order determined by the sending protocol, underlying drivers might complete such sends in random order.

If the underlying driver is a deserialized miniport driver, it must accept all incoming send packets and queue them internally, if necessary. A deserialized miniport driver should preserve the protocol-determined ordering of packet descriptors that bound protocols submit to NdisSendPackets while they are held in its internal queue. A deserialized driver always completes sends asynchronously. Consequently, protocols bound to a deserialized miniport driver should always consider the Status value passed in to their ProtocolSendComplete functions the final status of the requested send.

As soon as a protocol calls NdisSendPackets, it relinquishes ownership of the following:

  • All packet descriptors at PacketArray
  • All buffers mapped by the buffer descriptors chained to those packet descriptors
  • All out-of-band data blocks associated with the packet descriptors, including any medium-specific buffers specified in the out-of-band data blocks

The protocol regains ownership of these resources, one packet at a time, as its ProtocolSendComplete function is called with each packet descriptor in the array given to NdisSendPackets.

When a packet descriptor is returned to ProtocolSendComplete, it can call NdisReinitializePacket to prepare the packet for reuse after saving the buffer descriptors chained to the packet descriptor with calls to an NdisUnchainBufferAt Xxx function. Reusing such a packet descriptor yields better performance than returning the descriptor to driver-allocated packet pool with NdisFreePacket and, then, reallocating it for another send later.

ProtocolSendComplete also can prepare the out-of-band block associated with the given packet descriptor for reuse if the protocol supplies any out-of-band information. Alternatively, the protocol can explicitly reinitialize the members it uses when setting up the packet descriptor for a subsequent send.

An NDIS intermediate driver must repackage each incoming send from still higher level protocols in fresh packet descriptors before passing such a send request to the underlying miniport driver with NdisSendPackets (or NdisSend).

Callers of NdisSendPackets run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportSend, MiniportSendPackets, NdisAllocateBuffer, NdisAllocatePacket, NdisCoSendPackets, NdisFreePacket, NDIS_PACKET, NDIS_PACKET_OOB_DATA, NdisReinitializePacket, NdisSetPacketFlags, NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO, NDIS_SET_PACKET_TIME_TO_SEND, NdisUnchainBufferAtBack, NdisUnchainBufferAtFront, ProtocolSendComplete


NdisSetEvent

NdisSetEvent sets a given event to the signaled state if it was not already Signaled.

VOID
  NdisSetEvent(
    IN PNDIS_EVENT  Event
    );

Parameters

Event
Pointer to an initialized event object for which the caller provides the storage.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

When an event attains the Signaled state, it causes waits on the event to be satisfied and any waiters to be dispatched for execution.

After a call to NdisSetEvent, the event remains in the Signaled state until the driver calls NdisResetEvent.

Callers of NdisSetEvent run at IRQL <= DISPATCH_LEVEL.

See Also

NdisInitializeEvent, NdisResetEvent, NdisWaitEvent


NDIS_SET_PACKET_CANCEL_ID

NDIS_SET_PACKET_CANCEL_ID marks a packet with a cancellation identifier that a driver can later use to cancel the pending transmission of the packet.

VOID
  NDIS_SET_PACKET_CANCEL_ID(
    IN PNDIS_PACKET  Packet
    IN ULONG_PTR  CancelId
    );

Parameters

Packet
Pointer to an NDIS_PACKET structure that is the descriptor for a packet.
CancelId
A cancellation identifier.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A protocol driver or intermediate driver can call the NDIS_SET_PACKET_CANCEL_ID function for each packet that it passes to lower-level drivers for transmission. The NDIS_SET_PACKET_CANCEL_ID function marks the specified packet with a cancellation identifier.

To cancel the pending transmission of a marked packet, a protocol or intermediate driver passes the packet's cancellation ID to NdisCancelSendPackets. The caller of NDIS_SET_PACKET_CANCEL_ID should therefore store the assigned cancellation ID internally so that it can pass it, as necessary, to NdisCancelSendPackets. A driver can also obtain a packet's cancellation ID by calling NDIS_GET_PACKET_CANCEL_ID.

An intermediate driver should not modify the cancellation ID of packets that it passes to a lower-level driver. However, an intermediate driver can set a cancellation ID for packets that it originates.

Before assigning cancellation IDs to packets, a driver should call NdisGeneratePartialCancelId to obtain the high-order byte of each cancellation ID that it assigns. This ensures that the driver does not duplicate cancellation IDs assigned by other drivers in the system. NdisGeneratePartialCancelId is typically called once from the DriverEntry routine; however, a protocol or intermediate driver can obtain more than one partial cancellation identifier by calling NdisGeneratePartialCancelId more than once.

A protocol driver or intermediate driver might assign cancellation IDs to packets as follows:

  • The driver could mark all packets sent over a connection with the same cancellation identifier.
  • The driver could mark each packet with a unique cancellation identifier.
  • The driver could mark all packets within a subgroup of packets (for example, packets sent on behalf of a single client) with a unique identifier.

If a driver marks all packets with the same cancellation identifier, it can cancel all pending packet transmissions from an adapter with a single call to NdisCancelSendPackets. If a driver marks each packet with a unique cancellation identifier, it can cancel the pending transmission of individual packets from an adapter by calling NdisCancelSendPackets once for each packet. If a driver marks all packets within a subgroup of packets with a unique identifier, it can cancel all pending transmissions of packets within that subgroup with a single call to NdisCancelSendPackets.

After aborting the pending transmission of a packet, the underlying miniport driver calls the NdisMSendComplete, NdisMCoSendComplete, or NdisMWanSendComplete function to return the packet descriptor and a completion status of NDIS_STATUS_ABORTED to the protocol or intermediate driver that requested the transmission. NDIS, in turn, calls the protocol or intermediate driver's ProtocolSendComplete or ProtocolCoSendComplete function.

In its ProtocolSendComplete or ProtocolCoSendComplete function, a protocol driver can call NDIS_SET_PACKET_CANCEL_ID with CancelId set to NULL. This prevents the packet from inadvertently being used again with a stale cancelation ID.

System support for NDIS_SET_PACKET_CANCEL_ID is available in Windows XP and later operating systems.

Callers of NDIS_SET_PACKET_CANCEL_ID run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportCancelSendPackets, NdisAllocatePacket, NdisAllocatePacketPool, NdisAllocatePacketPoolEx, NdisCancelSendPackets, NdisGeneratePartialCancelId, NDIS_GET_PACKET_CANCEL_ID


NdisSetPacketFlags

NdisSetPacketFlags sets caller-determined and medium-specific information in the flags of a given packet descriptor.

VOID
  NdisSetPacketFlags(
    IN PNDIS_PACKET  Packet,
    IN UINT  Flags
    );

Parameters

Packet
Pointer to the packet descriptor in which the flags should be set.
Flags
Specifies the value to be set in the flags, which are in the private portion of the packet descriptor reserved for use by NDIS.

For protocols, the format of this value is specific to the medium that the underlying driver selected when the protocol called NdisOpenAdapter to set up the binding.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Setting the flags in a packet descriptor allows a protocol driver to pass information, usually about about a send request, that is not included in the packet data.

A protocol driver usually calls NdisSetPacketFlags to set the flags in packets sent on any medium that transmits data in an expedited manner. Some types of media include flags information in the packet header contained in buffers chained to the send packet. When a protocol driver is bound to an underlying driver for these types of media, a call to NdisSetPacketFlags is unnecessary.

When a bound protocol calls NdisSetPacketFlags, an underlying driver's MiniportSendPackets function can read these flags only by calling NdisGetPacketFlags. For underlying drivers that have MiniportSend functions, a call to NdisGetPacketFlags is unnecessary because the flags are passed as an input parameter to the MiniportSend function.

All packet descriptors allocated with NdisAllocatePacket are zero-initialized, including the flags. If the value returned by NdisGetPacketFlags is zero, the underlying driver can assume that the packet has no protocol-set flags information.

However, protocols can supply far more media-specific information, such as the packet priority, in the out-of-band data block associated with each packet descriptor than a call to NdisSetPacketFlags with a single packet allows.

Callers of NdisSetPacketFlags run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportSend, MiniportSendPackets, NdisAllocatePacket, NdisGetPacketFlags, NdisOpenAdapter, NDIS_PACKET, NDIS_PACKET_OOB_DATA, NdisSend, NdisSendPackets, NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO, ProtocolSendComplete


NDIS_SET_PACKET_HEADER_SIZE

NDIS_SET_PACKET_HEADER_SIZE sets the HeaderSize value in the out-of-band data block associated with a given packet descriptor for a subsequent receive indication.

NDIS_SET_PACKET_HEADER_SIZE(
  IN PNDIS_PACKET  Packet,
    IN UINT  HdrSize
    );

Parameters

Packet
Pointer to a driver-allocated packet descriptor.
HdrSize
Specifies the medium-specific number of bytes in the net packet header.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The HeaderSize member in the NDIS_PACKET_OOB_DATA block associated with a packet descriptor specifies the number of bytes of medium-specific header in the buffer mapped by the initial buffer descriptor chained to the packet descriptor.

A lower-level driver sets this value with NDIS_SET_PACKET_HEADER_SIZE in the out-of-band data blocks for the receive packets it will subsequently indicate with NdisMIndicateReceivePacket. Typically, a miniport driver sets the HeaderSize once for each packet descriptor it allocates with NdisAllocatePacket for subsequent receive indications, depending on the medium it selected during initialization. If such a driver clears the out-of-band data block with NDIS_OOB_DATA_FROM_PACKET and NdisZeroMemory when it regains ownership of its receive packet descriptors, that driver must call NDIS_SET_PACKET_HEADER_SIZE before it reuses each packet descriptor in a subsequent indication.

When such an indication is made, bound protocols can retrieve this information with the NDIS_GET_PACKET_HEADER_SIZE macro.

Callers of NDIS_SET_PACKET_HEADER_SIZE run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportInitialize, MiniportReturnPacket, MiniportTimer, NdisAllocatePacket, NDIS_GET_PACKET_HEADER_SIZE, NdisMIndicateReceivePacket, NDIS_OOB_DATA_FROM_PACKET, NDIS_PACKET_OOB_DATA, NdisSend, NdisSendPackets, NdisZeroMemory, ProtocolReceive, ProtocolReceivePacket


NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO

NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO sets the MediaSpecificInformation pointer and the SizeMediaSpecificInfo value in the out-of-band data block associated with a given packet descriptor.

NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(
    IN PNDIS_PACKET  Packet,
    IN PVOID  MediaSpecificInfo,
    IN UINT  SizeMediaSpecificInfo
    );

Parameters

Packet
Pointer to a driver-allocated packet descriptor.
MediaSpecificInfo
Specifies a pointer to a caller-supplied buffer containing medium-specific information, such as packet priority, to be set in the MediaSpecificInformation member of the NDIS_PACKET_OOB_DATA block associated with the given packet descriptor. This parameter cannot be NULL.
SizeMediaSpecificInfo
Specifies the number of bytes of information supplied at MediaSpecificInformation. This parameter cannot be zero.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Depending on the medium, an underlying driver might set these members with NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO in the out-of-band data blocks associated with the packet descriptors it allocates for receive indications. When a bound protocol is called with the indication, it would use NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO to access the supplied information.

Depending on the medium of the underlying driver to which it is bound, a protocol might set MediaSpecificInformation and SizeMediaSpecificInfo in the out-of-band blocks associated with the packet descriptors it allocates for sends. The underlying driver would use NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO to access the supplied information.

In either case, while a higher-level protocol is consuming a receive indication or a lower-level miniport driver is processing a send, that driver must have exclusive access to the buffer at MediaSpecificInformation. This restriction implies the following:

  • A miniport driver cannot access the buffer it set up with out-of-band information when NdisMIndicateReceivePacket returns control if NDIS_STATUS_PENDING is set in the Status member of the associated out-of-band block. The driver can use NDIS_GET_PACKET_STATUS to determine whether each packet in the packet array it just indicated has this status set or has been returned with NDIS_STATUS_SUCCESS.
  • A protocol driver cannot access the buffer it set up with out-of-band information for a send, nor anything else in the out-of-band data block associated with a packet descriptor it passes to NdisSendPackets or NdisSend, until the packet descriptor is returned to its ProtocolSendComplete function.

    Because NDIS queues send packets and resubmits them if the MiniportSend function returns NDIS_STATUS_RESOURCES or if the MiniportSendPackets function sets NDIS_STATUS_RESOURCES for the Status of a packet in a submitted array, the final status of each packet in a send (array) is volatile until that packet has been returned to ProtocolSendComplete.

A protocol driver can call NdisGetReceivedPakcet and NDIS_GET_ORIGINAL_PACKET to obtain a copy of the NDIS_PACKET_OOB_DATA block associated with a packet descriptor when its ProtocolReceive function is given an indication. However, these calls are superfluous if the protocol is bound to an underlying driver that does not supply out-of-band information with its indications.

Callers of NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportTimer, NdisAllocatePacket, NDIS_GET_ORIGINAL_PACKET, NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO, NDIS_GET_PACKET_STATUS, NdisGetReceivedPacket, NdisMIndicateReceivePacket, NDIS_OOB_DATA_FROM_PACKET, NDIS_PACKET_OOB_DATA, NdisSend, NdisSendPackets, NDIS_SET_PACKET_STATUS, ProtocolReceive, ProtocolReceivePacket, ProtocolSendComplete


NDIS_SET_PACKET_STATUS

NDIS_SET_PACKET_STATUS sets the Status value in the out-of-band data block associated with a given packet descriptor just before a driver calls NdisMIndicateReceivePacket or before a driver's MiniportSendPackets function returns control.

NDIS_SET_PACKET_STATUS(
  IN PNDIS_PACKET  Packet,
    IN NDIS_STATUS  Status
    );

Parameters

Packet
Pointer to a packet descriptor either allocated by the caller for a receive indication or by a protocol for a send.
Status
Specifies the status to be set.

For packet descriptors used in receive indications, the value can be either of the following:

NDIS_STATUS_SUCCESS
The driver is relinquising ownership of the packet about to be indicated with NdisMIndicateReceivePacket until the packet descriptor is returned to its MiniportReturnPacket function.

Protocols that receive the indication can use the packet descriptor, along with all buffers mapped by buffer descriptors chained to the packet descriptor and any out-of-band information supplied with the packet, to copy the indicated net packet data, possibly forwarding the processed copy to interested clients.

NDIS_STATUS_RESOURCES
The driver is retaining ownership of the packet about to be indicated with NdisMIndicateReceivePacket and of all subsequent packets in the packet array. All these packets will be indicated, one at a time, to the ProtocolReceive functions of bound protocols.

Setting this status forces bound protocols to return ownership of each such packet descriptor, of any medium-specific buffer in the out-of-band data block for each packet descriptor, and of the memory mapped by each packet descriptor's respective chained buffer descriptors to the indicating driver more quickly. The protocols must wait for a call to their ProtocolReceiveComplete functions to begin postprocessing the data they copied from the indication and forwarding the processed data to their clients.

An indicating driver can set this status if it is running low on packet pool or buffer pool. An indicating NIC driver usually sets this status if it is running low on NIC receive buffers due to high network traffic. A bus-master DMA NIC driver might call NdisMAllocateSharedMemoryAsync in these circumstances to get additional NIC receive buffer space.

NDIS assumes that, if this status is set for a packet in an indicated array, it is set for all subsequent packets in that array. Consequently, an indicating driver need not set the status for subsequent packet descriptors in an array after it sets this status in the out-of-band data block for one packet descriptor.

For packet descriptors used in sends, MiniportSendPackets can set one of the following values:

NDIS_STATUS_PENDING
The driver will complete the requested send operation asynchronously.

After MiniportSendPackets returns control, the driver will call NdisMSendComplete with a final completion status for the given packet descriptor, which NDIS propagates to the ProtocolSendComplete function of the driver that allocated the resources specified by the packet descriptor and initiated the send.

NDIS_STATUS_RESOURCES
The driver cannot process all sends specified in a given packet array due to current resource constraints.

NDIS assumes that the Status member for all subsequent packet descriptors in the array given to MiniportSendPackets is set to the same value. NDIS queues these packet descriptors internally in the same order for resubmission to MiniportSendPackets when the driver calls NdisMSendResourcesAvailable or NdisMSendComplete, whichever call occurs first. NDIS reflects this miniport driver-set status value to protocols as NDIS_STATUS_PENDING.

NDIS_STATUS_XXX
MiniportSendPackets is completing a given send request before it returns control.

Whether such a send packet is completed with NDIS_STATUS_SUCCESS or a driver-determined error status, MiniportSendPackets must set the Status member for the given packet descriptor so that NDIS can reflect this status back to the protocol that initiated the send when NDIS calls ProtocolSendComplete with the returned packet descriptor.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Only drivers that indicate receives with NdisMIndicateReceivePacket to bound protocols and/or drivers that have MiniportSendPackets functions use the NDIS_SET_PACKET_STATUS macro.

After such an underlying driver has set the Status for some number of packet descriptors in an array and called NdisMIndicateReceivePacket with the array of pointers to those packet descriptors, it must use the NDIS_GET_PACKET_STATUS macro when NdisMIndicateReceivePacket returns control. The returned Status in the NDIS_PACKET_OOB_DATA block associated with each packet descriptor that the driver indicated with NDIS_STATUS_SUCCESS determines what the indicating driver does next, as follows:

NDIS_STATUS_SUCCESS
If this is set on return from a miniport's call to NdisMIndicateReceivePacket, the miniport driver regains ownership of the following:
  • The packet descriptor
  • The associated out-of-band data block associated with the packet descriptor and of any media-specific information buffer specified in this block
  • All buffers mapped by buffer descriptors chained to the packet descriptor

The driver can prepare these descriptors, the out-of-band block, and media-specific information buffer, if any, for reuse in subsequent receive indications immediately.

NDIS_STATUS_PENDING
If this is set on return from NdisMIndicateReceivePacket, protocols retain ownership of the packet descriptor, of its associated out-of-band data block and of any buffer specified in this block, and of all buffers mapped by buffer descriptors chained to the packet descriptor until the packet descriptor is returned to the indicating driver's MiniportReturnPacket function. However, protocols are given read-only access to these miniport driver-allocated resources.

When the MiniportSendPackets function sets the Status for an incoming send packet to anything other than NDIS_STATUS_PENDING or NDIS_STATUS_RESOURCES, it completes the packet and relinquishes ownership to all resources specified by the associated packet descriptor. NDIS returns the packet descriptor to the ProtocolSendComplete function of the allocating driver and propagates the miniport driver-set status value as an input parameter to ProtocolSendComplete. Otherwise, the underlying driver will call NdisMSendComplete with the packet descriptor and final status when the asynchronous send operation is done.

Protocol drivers should never test the Status value in an associated out-of-band data block on return from NdisSendPackets or NdisSend. NDIS or the underlying driver retains ownership of the packet descriptor, of the associated out-of-band block and any buffers specified in this block, and of all buffers mapped by buffer descriptors chained to the packet descriptor until the ProtocolSendComplete function is called with the packet descriptor.

Callers of NDIS_SET_PACKET_STATUS run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportReturnPacket, MiniportSendPackets, MiniportTimer, NdisAllocatePacket, NDIS_GET_PACKET_STATUS, NdisMAllocateSharedMemoryAsync, NdisMIndicateReceivePacket, NdisMSendComplete, NDIS_OOB_DATA_FROM_PACKET, NDIS_PACKET_OOB_DATA, NdisSend, NdisSendPackets, NDIS_SET_PACKET_HEADER_SIZE, NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO, NDIS_SET_PACKET_TIME_RECEIVED, NDIS_SET_PACKET_TIME_SENT, ProtocolSendComplete


NDIS_SET_PACKET_TIME_RECEIVED

NDIS_SET_PACKET_TIME_RECEIVED sets the TimeReceived value in the out-of-band data block associated with a given packet descriptor.

NDIS_SET_PACKET_TIME_RECEIVED(
  IN PNDIS_PACKET  Packet,
    IN ULONGLONG  TimeReceived
    );

Parameters

Packet
Pointer to a packet descriptor allocated by the caller for receive indications.
TimeReceived
Specifies the system time at which the packet was received from the remote node on the network.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Drivers can use NDIS_SET_PACKET_TIME_RECEIVED to set this timestamp in the out-of-band data block associated with a packet descriptor before calling NdisMIndicateReceivePacket. Miniports that indicate multipacket receives can set the TimeReceived values for each packet in an indicated array to the same value before making an indication, particularly if the NIC has no internal clock, so the NIC driver calls NdisGetCurrentSystemTime.

All timestamps set in the NDIS_PACKET_OOB_DATA blocks associated with packet descriptors are expressed in system time units as the number of 100-nanosecond intervals since January 1, 1601. A driver can call NdisGetCurrentSystemTime to supply the TimeReceived argument to NDIS_SET_PACKET_TIME_RECEIVED.

When a protocol driver's ProtocolReceivePacket function is called with such an indication, it can use NDIS_GET_TIME_RECEIVED to retrieve the TimeReceived timestamp using the Packet pointer it is given on entry.

If the ProtocolReceive function is called with an indicated packet descriptor for which the underlying driver set the TimeReceived timestamp, ProtocolReceive can call NdisGetReceivedPacket and NDIS_GET_ORIGINAL_PACKET to get the packet that contains this timestamp.

Callers of NDIS_SET_PACKET_TIME_RECEIVED run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportTimer, NdisGetCurrentSystemTime, NDIS_GET_ORIGINAL_PACKET, NDIS_GET_PACKET_TIME_RECEIVED, NdisGetReceivedPacket, NdisMIndicateReceivePacket, NDIS_OOB_DATA_FROM_PACKET, NDIS_PACKET_OOB_DATA, NDIS_SET_PACKET_TIME_SENT, ProtocolReceive, ProtocolReceivePacket


NDIS_SET_PACKET_TIME_SENT

NDIS_SET_PACKET_TIME_SENT sets the TimeSent value in the out-of-band data block associated with a given packet descriptor.

NDIS_SET_PACKET_TIME_SENT(
  IN PNDIS_PACKET  Packet,
    IN ULONGLONG  TimeSent
    );

Parameters

Packet
Pointer to a packet descriptor allocated by the caller for receive indications.
TimeSent
Specifies the system time at which the packet was transmitted over the network from a remote node.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Miniports can use NDIS_SET_PACKET_TIME_SENT to set this timestamp in the out-of-band data block associated with a packet descriptor they are about to indicate with NdisMIndicateReceivePacket.

All timestamps set in the NDIS_PACKET_OOB_DATA blocks associated with packets are expressed in system time units as the number of 100-nanosecond intervals since January 1, 1601.

When a protocol driver's ProtocolReceivePacket function is called with such an indication, it can use NDIS_GET_PACKET_TIME_SENT to retrieve the TimeSent timestamp using the Packet pointer it is given on entry.

If the ProtocolReceive function is called with an indicated packet descriptor for which the underlying driver set the TimeSent timestamp, ProtocolReceive can call NdisGetReceivedPacket and NDIS_GET_ORIGINAL_PACKET to get the packet that contains this timestamp.

Callers of NDIS_SET_PACKET_TIME_SENT run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportHandleInterrupt, MiniportTimer, NDIS_GET_ORIGINAL_PACKET, NDIS_GET_PACKET_TIME_SENT, NdisGetReceivedPacket, NdisMIndicateReceivePacket, NDIS_OOB_DATA_FROM_PACKET, NDIS_PACKET_OOB_DATA, NDIS_SET_PACKET_TIME_RECEIVED, ProtocolReceive, ProtocolReceivePacket


NDIS_SET_PACKET_TIME_TO_SEND

NDIS_SET_PACKET_TIME_TO_SEND sets the TimeToSend value in the out-of-band data block associated with a given packet descriptor.

NDIS_SET_PACKET_TIME_TO_SEND(
  IN PNDIS_PACKET  Packet,
    IN ULONGLONG  TimeToSend
    );

Parameters

Packet
Pointer to a packet descriptor allocated by the caller for a send.
TimeToSend
Specifies the system time at which the packet should be transmitted over the network.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Protocols can use NDIS_SET_PACKET_TIME_TO_SEND to set this timestamp in the out-of-band data block associated with a driver-allocated packet descriptor to be passed in a subsequent call to NdisSendPackets or NdisSend.

All timestamps set in the NDIS_PACKET_OOB_DATA blocks associated with packet descriptors are expressed in system time units as the number of 100-nanosecond intervals since January 1, 1601.

A protocol can call NdisGetCurrentSystemTime and add some number of system time units to the returned value in order to supply the TimeToSend argument to NDIS_SET_PACKET_TIME_TO_SEND, unless the client that initiated the send request has already supplied such a timestamp.

Callers of NDIS_SET_PACKET_TIME_TO_SEND run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportSend, MiniportSendPackets, NdisGetCurrentSystemTime, NDIS_GET_PACKET_TIME_SENT, NDIS_GET_PACKET_TIME_TO_SEND, NDIS_OOB_DATA_FROM_PACKET, NDIS_PACKET_OOB_DATA, NdisSend, NdisSendPackets, ProtocolSendComplete


NdisSetPhysicalAddressHigh

NdisSetPhysicalAddressHigh sets the high-order part of a given physical address to a given value.

VOID
  NdisSetPhysicalAddressHigh(
    IN NDIS_PHYSICAL_ADDRESS  PhysicalAddress,
    IN ULONG  Value
    );

Parameters

PhysicalAddress
Specifies a physical address of an OS-dependent size.
Value
Specifies the value to be written into the high-order part of the address.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Callers of NdisSetPhysicalAddressHigh can be running at any IRQL.

See Also

NdisGetPhysicalAddressHigh, NDIS_PHYSICAL_ADDRESS, NdisSetPhysicalAddressLow


NdisSetPhysicalAddressLow

NdisSetPhysicalAddressLow sets the low-order part of a given physical address to a given value.

VOID
  NdisSetPhysicalAddressLow(
    IN NDIS_PHYSICAL_ADDRESS  PhysicalAddress,
    IN ULONG  Value
    );

Parameters

PhysicalAddress
Specifies a physical address of an OS-dependent size.
Value
Specifies the value to be written into the low-order part of the address.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Callers of NdisSetPhysicalAddressLow can be running at any IRQL.

See Also

NdisGetPhysicalAddressLow, NDIS_PHYSICAL_ADDRESS, NdisSetPhysicalAddressHigh


NdisSetSendFlags

Use NdisSetPacketFlags instead.


NdisSetTimer

NdisSetTimer sets a timer object to fire after a specified interval, thereby running an associated timer function after the timer fires.

VOID
  NdisSetTimer(
    IN PNDIS_TIMER  Timer,
    IN UINT  MillisecondsToDelay
    );

Parameters

Timer
Pointer to caller-supplied resident storage for a timer object previously initialized with NdisInitializeTimer.
MillisecondsToDelay
Specifies the interval, in milliseconds, to elapse before NdisSetTimer calls the associated timer function.

Headers

Declared in Ndis.h. Include Ndis.h.

vComments

NdisSetTimer causes the driver-supplied timer function to run once after the given MillisecondsToDelay expires. This timer function becomes associated with the timer object after the protocol driver calls NdisInitializeTimer. Execution of this timer function is episodic, rather than periodic. A protocol must call NdisSetTimer each time the associated timer function should be run.

The following describes the syntax of the driver-supplied timer function:

VOID
  (*PNDIS_TIMER_FUNCTION)(
    IN PVOID  SystemSpecific1,
    IN PVOID  FunctionContext,
    IN PVOID  SystemSpecific2,
    IN PVOID  SystemSpecific3
    );

If a protocol calls NdisSetTimer or the NdisCancelTimer function with the same Timer pointer that was originally passed to another NdisSetTimer call before the originally specified MillisecondsToDelay has expired, the current call cancels the protocol's preceding call to NdisSetTimer. Any call to NdisSetTimer resets the given timer to expire at the interval specified in the most recent call and causes the associated timer function to run when the most recently specified interval has expired.

Timer resolution on the host varies. Consequently, calling NdisSetTimer with small time-interval values does not necessarily cause the execution of the timer function to occur exactly when the specified interval expires. The minimum practicable interval to specify on Windows 2000 and later platforms is ten milliseconds.

Callers of NdisSetTimer run at IRQL <= DISPATCH_LEVEL.

See Also

NdisCancelTimer, NdisInitializeTimer


NdisStallExecution

NdisStallExecution stalls the caller on the current processor for a given interval.

VOID
  NdisStallExecution(
    IN UINT  MicrosecondsToStall
    );

Parameters

MicrosecondsToStall
Specifies the number of microseconds to delay.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

For the given MicrosecondsToStall, the caller's thread of execution stalls on the current processor, consuming CPU cycles. When the given interval expires, the caller resumes execution.

Unless a driver is running at IRQL >= DISPATCH_LEVEL, it should call NdisMSleep, which accepts larger delay intervals without monopolizing a processor for its callers, instead of NdisStallExecution. For example, a NIC driver's MiniportInitialize function should wait for state changes in the NIC with NdisMSleep.

Both NdisMSleep and NdisStallExecution allow a NIC driver to specify a delay consistently and independently of the clock speed of the host CPU. Neither function involves a timer object used by NdisSet(Periodic)Timer. The resolution of the host system clock varies, so very short delays can take slightly longer than the caller of NdisMSleep or NdisStallExecution specified.

A call to NdisStallExecution prevents any other operating system activity on the current processor and prevents system interrupts from occurring during the stall. Therefore, callers should always specify a stall interval of no longer than 50 microseconds.

Callers of NdisStallExecution can run at any IRQL.

See Also

MiniportInitialize, MiniportReset, NdisMSetTimer, NdisMSleep


NdisStoreUlong

NdisStoreUlong stores a ULONG value at a particular address, avoiding alignment faults.

VOID
  NdisStoreUlong(
    IN PULONG  DestinationAddress,
    IN ULONG  Value
    );

Parameters

DestinationAddress
Pointer to a location in which to store a given ULONG value.
Value
Specifies the value to be stored.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Callers of NdisStoreUlong can be running at any IRQL if DestinationAddress points to nonpaged pool. Otherwise, the caller must be running at IRQL < DISPATCH_LEVEL.

See Also

NdisRetrieveUlong


NdisSystemProcessorCount

NdisSystemProcessorCount determines whether its caller is running on a uniprocessor or multiprocessor machine.

CCHAR
  NdisSystemProcessorCount(VOID);

Return Value

NdisSystemProcessorCount returns the number of processors in the machine.

Headers

Declared in Ndis.h. Include Ndis.h.

vComments

An NDIS driver might call this function during initialization before it allocates resources.

For example, suppose NdisSystemProcessorCount returns a value greater than one, which suggests the machine is more likely to be a server than a workstation. When this occurs, the driver could allocate more memory on the assumption that network traffic will be significantly heavier on a server.

Callers of NdisSystemProcessorCount run at IRQL PASSIVE_LEVEL.

See Also

DriverEntry of NDIS Protocol Drivers, MiniportInitialize


NdisTerminateWrapper

NdisTerminateWrapper releases system resources allocated when the NIC driver called NdisMInitializeWrapper.

VOID
  NdisTerminateWrapper(
    IN NDIS_HANDLE  NdisWrapperHandle,
    IN PVOID  SystemSpecific
    );

Parameters

NdisWrapperHandle
Specifies the handle returned by NdisMInitializeWrapper.
SystemSpecific
Pointer to an OS-specific type. For Windows 2000 and later drivers, this parameter should be NULL.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

From its DriverEntry function, a miniport driver calls NdisMInitializeWrapper to notify NDIS that the driver is about to register itself as a miniport driver. After NdisMInitializeWrapper successfully returns, the miniport driver calls either NdisMRegisterMiniport or NdisIMRegisterLayeredMiniport to register its entry points with NDIS.

If a miniport driver's call to NdisMRegisterMiniport or NdisIMRegisterLayeredMiniport does not return NDIS_STATUS_SUCCESS, the miniport driver must call NdisTerminateWrapper. Calling NdisTerminateWrapper causesNDIS to clean up the resources that it allocated when the miniport driver called NdisMInitializeWrapper.

Callers of NdisTerminateWrapper run at IRQL PASSIVE_LEVEL.

See Also

DriverEntry of NDIS Miniport Drivers, MiniportHalt, MiniportInitialize, NdisMInitializeWrapper


NdisTransferData

NdisTransferData forwards a request to copy data received on the underlying NIC into a protocol-supplied packet.

VOID
  NdisTransferData(
    OUT PNDIS_STATUS  Status,
    IN NDIS_HANDLE  NdisBindingHandle,
    IN NDIS_HANDLE  MacReceiveContext,
    IN UINT  ByteOffset,
    IN UINT  BytesToTransfer,
    IN OUT PNDIS_PACKET  Packet,
    OUT PUINT  BytesTransferred
    );

Parameters

Status
Pointer to a caller-supplied variable that can be one of the following values on return from this function:
NDIS_STATUS_SUCCESS
The requested data has been transferred into the packet at Packet.
NDIS_STATUS_PENDING
The request is being handled asynchronously, and the caller's ProtocolTransferComplete function will be called when it is completed.
NDIS_STATUS_RESET_IN_PROGRESS
The underlying driver is currently resetting its NIC or virtual NIC state. The caller's ProtocolStatus function was or will be called with NDIS_STATUS_RESET_START to indicate that a reset is in progress.
NDIS_STATUS_REQUEST_ABORTED
The caller's binding is being closed.
NDIS_STATUS_FAILURE
The given ByteOffset and/or the given BytesToTransfer is too large.
NdisBindingHandle
Specifies the handle returned by NdisOpenAdapter that identifies the target NIC or the virtual adapter of the next-lower driver to which the caller is bound.
MacReceiveContext
Specifies the underlying driver's handle that was passed as an input parameter to the caller's ProtocolReceive function. The protocol driver must consider this handle to be opaque.
ByteOffset
Specifies the offset from the start of the receive network packet at which to begin the transfer.
BytesToTransfer
Specifies the number of bytes to transfer. This value can be zero.
Packet
Pointer to the packet descriptor, provided by the caller, into which the underlying NIC driver is to copy the data.
BytesTransferred
Pointer to a caller-supplied variable in which this function returns the number of bytes actually transferred. The value is invalid if NdisTransferData returns NDIS_STATUS_PENDING at Status.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Several protocols can be bound to a single underlying NIC, and each such protocol driver can receive an indication for the same packet. Such a packet is read-only to protocol drivers. Each such driver's ProtocolReceive function determines whether to make itself a copy of the indicated packet with NdisTransferData.

Before calling NdisTransferData, the protocol must allocate a packet descriptor and chain some number of buffer descriptors mapping protocol-allocated buffers into which the underlying driver will copy the data. The protocol also might set up the ProtocolReserved part of its packet descriptor before calling NdisTransferData.

A protocol driver should always allocate its packet descriptors from the packet pool that the driver set up during initialization.

The range requested in a call to NdisTransferData, specified by ByteOffset and BytesToTransfer, should be suitable to the PacketSize passed in to the caller's ProtocolReceive function. Callers of NdisTransferData usually pass a ByteOffset value calculated from the input parameters to ProtocolReceive as (LookaheadBufferRange + 1). That is, the ProtocolReceive function already consumed the data in the lookahead buffer so it calls NdisTransferData to get the remaining data in the indicated receive packet.

Callers of NdisTransferData run at IRQL <= DISPATCH_LEVEL.

See Also

NdisAllocatePacket, NdisMIndicateReceivePacket, NDIS_PACKET, ProtocolReceive, ProtocolReceivePacket, ProtocolTransferDataComplete


NdisUnchainBufferAtBack

NdisUnchainBufferAtBack removes the buffer descriptor at the end of the chain of buffer descriptors for a given packet.

VOID
  NdisUnchainBufferAtBack(
    IN OUT PNDIS_PACKET  Packet,
    OUT PNDIS_BUFFER  *Buffer
    );

Parameters

Packet
Pointer to the packet descriptor.
Buffer
Pointer to a caller-supplied variable in which this function returns a pointer to the removed buffer descriptor. If no buffer is chained to the given packet, this variable is set to NULL.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisUnchainBufferAtBack returns a pointer to the buffer descriptor it removed from the buffer descriptor chain of the given packet.

It also resets the valid counts for the packet to FALSE, thereby forcing NdisQueryPacket to recalculate information about the given packet if it is called subsequently with that packet.

Callers of NdisUnchainBufferAtBack can run at any IRQL.

See Also

NdisChainBufferAtBack, NdisQueryPacket, NdisUnchainBufferAtFront


NdisUnchainBufferAtFront

NdisUnchainBufferAtFront removes the buffer descriptor at the head of the chain of buffer descriptors for a given packet.

VOID
  NdisUnchainBufferAtFront(
    IN OUT PNDIS_PACKET  Packet,
    OUT PNDIS_BUFFER  *Buffer
    );

Parameters

Packet
Pointer to the packet descriptor.
Buffer
Pointer to a caller-supplied variable in which this function returns a pointer to the removed buffer descriptor. If no buffer is chained to the given packet, this variable is set to NULL.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisUnchainBufferAtFront returns a pointer to the buffer descriptor it removed from the buffer descriptor chain of the given packet.

It also resets the valid counts for the packet to FALSE, thereby forcing NdisQueryPacket to recalculate information about the given packet if it is called subsequently with that packet.

Callers of NdisUnchainBufferAtFront can run at any IRQL.

See Also

NdisChainBufferAtFront, NdisQueryPacket, NdisUnchainBufferAtBack


NdisUnicodeStringToAnsiString

NdisUnicodeStringToAnsiString converts a given counted Unicode string into a counted ANSI string. The translation conforms to the current system locale information.

NDIS_STATUS
  NdisUnicodeStringToAnsiString(
    IN OUT PANSI_STRING  DestinationString,
    IN PUNICODE_STRING  SourceString
    );

Parameters

DestinationString
Pointer to a caller-allocated buffer in which this function should return the converted ANSI string.
SourceString
Pointer to the Unicode string to be converted.

Return Value

NdisUnicodeStringToAnsiString returns NDIS_STATUS_SUCCESS if the conversion succeeds. Otherwise, the contents of the buffer at DestinationString are unaffected.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The caller must allocate storage for both the source and destination strings and release these buffers as soon as the strings are no longer needed. The buffer at SourceString must be at least twice the size of that at DestinationString.

Callers of NdisUnicodeStringToAnsiString run at IRQL PASSIVE_LEVEL.

See Also

ANSI_STRING, DriverEntry of NDIS Protocol Drivers, MiniportInitialize, NdisAnsiStringToUnicodeString, NdisInitAnsiString, NdisInitializeString, NdisInitUnicodeString, ProtocolBindAdapter, UNICODE_STRING


NdisUnmapFile

NdisUnmapFile releases a virtual address mapping of a file previously set up with NdisMapFile.

VOID
  NdisUnmapFile(
    IN NDIS_HANDLE  FileHandle
    );

Parameters

FileHandle
Specifies the handle returned by NdisOpenFile.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

To reduce resource usage, a NIC driver should always call NdisUnmapFile when it no longer needs exclusive access to the contents of a file that it opened. Such a driver can map and unmap the file as necessary, using alternating calls to NdisMapFile and NdisUnmapFile until it releases the file handle with NdisCloseFile.

Callers of NdisUnmapFile run at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisCloseFile, NdisMapFile, NdisOpenFile


NdisUpcaseUnicodeString

NdisUpcaseUnicodeString converts a copy of a given Unicode string to upper case and returns the converted string.

NTSTATUS
  NdisUpcaseUnicodeString(
    OUT PUNICODE_STRING  DestinationString,
    IN PUNICODE_STRING  SourceString
    );

Parameters

DestinationString
Pointer to a caller-allocated buffer in which to return the converted string.
SourceString
Pointer to the source Unicode string to be converted to upper case.

Return Value

NdisUpcaseUnicodeString returns STATUS_SUCCESS if it returned the converted string in the buffer at DestinationString.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Callers of NdisUpcaseUnicodeString must be running at IRQL PASSIVE_LEVEL.

See Also

NdisAnsiStringToUnicodeString, NdisInitializeString, NdisInitUnicodeString, UNICODE_STRING


NdisWaitEvent

NdisWaitEvent puts the caller into a wait state until the given event is set to the Signaled state or the wait times out.

BOOLEAN
  NdisWaitEvent(
    IN PNDIS_EVENT  Event,
    IN UINT  MsToWait
    );

Parameters

Event
Pointer to an initialized event object for which the caller provides the storage.
MsToWait
Specifies the number of milliseconds the caller will wait if the event is not set to the Signaled state within that interval. A value of zero specifies that the caller will wait for the event indefinitely.

Return Value

NdisWaitEvent returns TRUE if the event is in the Signaled state when the wait is satisfied.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisWaitEvent returns control to its caller when the given event is signaled or the specified MsToWait interval expires, whichever is sooner. If the event is currently in the Signaled state when this call occurs, NdisWaitEvent returns control immediately.

A miniport driver typically calls NdisWaitEvent from its MiniportInitialize and MiniportHalt functions. A protocol driver typically calls NdisWaitEvent from its ProtocolBindAdapter and ProtocolUnbindAdapter functions.

Callers of NdisWaitEvent must be running at IRQL PASSIVE_LEVEL.

See Also

DriverEntry of NDIS Protocol Drivers, MiniportHalt, MiniportInitialize, NdisInitializeEvent, NdisResetEvent, NdisSetEvent, ProtocolBindAdapter, ProtocolUnbindAdapter


NdisWriteConfiguration

NdisWriteConfiguration writes a caller-supplied value for a specified entry into the registry.

VOID
  NdisWriteConfiguration(
    OUT PNDIS_STATUS  Status,
    IN NDIS_HANDLE  ConfigurationHandle,
    IN PNDIS_STRING  Keyword,
    IN PNDIS_CONFIGURATION_PARAMETER  ParameterValue
    );

Parameters

Status
Pointer to a caller-supplied variable in which this function returns the status of the call as one of the following:
NDIS_STATUS_SUCCESS
The supplied value at ParameterValue was written into the registry. If this is a new entry, the name at Keyword also was written into the registry.
NDIS_STATUS_NOT_SUPPORTED
The supplied ParameterType is invalid.
NDIS_STATUS_RESOURCES
NDIS could not allocate resources, usually enough memory, to transfer the requested information to the registry.
NDIS_STATUS_FAILURE
The requested information could not be written.
ConfigurationHandle
Specifies the handle to a registry key returned by NdisOpenConfiguration to a NIC driver, by NdisOpenProtocolConfiguration to a protocol driver, or by NdisOpenConfigurationKeyByIndex or NdisOpenConfigurationKeyByName to either type of NDIS driver.
Keyword
Pointer to an NDIS_STRING type describing a caller-supplied counted string, in the system-default character set, specifying the name of an entry for which to write the value. For Windows 2000 and later drivers, this string contains Unicode characters. That is, for Windows 2000 and later, NDIS defines the NDIS_STRING type as a UNICODE_STRING type.
ParameterValue
Pointer to a caller-supplied NDIS_CONFIGURATION_PARAMETER structure, defined as follows:
typedef struct _NDIS_CONFIGURATION_PARAMETER {
    NDIS_PARAMETER_TYPE ParameterType;
    union {
        ULONG IntegerData;
        NDIS_STRING StringData;
    } ParameterData;
} NDIS_CONFIGURATION_PARAMETER, *PNDIS_CONFIGURATION_PARAMETER;

The members of this structure can contain the following data:

ParameterType
Specifies the type of the value entry as one of the following:
NdisParameterInteger
Specifies an integer in decimal notation.
NdisParameterHexInteger
Specifies an integer in hexadecimal notation.
NdisParameterString
Specifies a string of type NDIS_STRING.

For Windows 2000 and later drivers, this is a counted Unicode string.

NdisParameterMultiString
Specifies a multistring parameter of the
defined REG_MULTI_SZ type, which is defined in Windows 2000 and later versions.
ParameterData
Specifies the value of the given named entry in the notation of the specified ParameterType. If ParameterType is a string type, this member is an NDIS_STRING type describing a counted string in the system-default character set.

For Windows 2000 and later drivers, such a string contains Unicode characters.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If an entry of the same name as at Keyword already exists under the opened registry key, NdisWriteConfiguration replaces its current value with the caller-supplied value. Otherwise, NdisWriteConfiguration adds a new value entry with the given name and supplied value to the registry.

In the configuration registry of Windows 2000 and later versions, an NDIS keyword is a synonym for a value entry name. Such a name is a counted sequence of Unicode characters, terminated with a NUL.

NdisWriteConfiguration buffers and copies the caller-supplied string at Keyword and the caller-supplied data specified at ParameterValue. This memory is freed when the driver releases the ConfigurationHandle with NdisCloseConfiguration. The caller of NdisWriteConfiguration is responsible for releasing the buffered string at Keyword and the memory allocated for the NDIS_CONFIGURATION_PARAMETER structure.

As an alternative to calling NdisWriteConfiguration, every NDIS driver can set up configuration information in the registry for itself under the driver's Parameters key using an installation script.

For more information about setup and installation scripts for Windows 2000 and later versions, see Device Installation Overview.

Callers of NdisWriteConfiguration run at IRQL PASSIVE_LEVEL.

See Also

ANSI_STRING, MiniportInitialize, NdisAnsiStringToUnicodeString, NdisCloseConfiguration, NdisFreeMemory, NdisFreeString, NdisInitAnsiString, NdisInitializeString, NdisInitUnicodeString, NdisOpenConfiguration, NdisOpenConfigurationKeyByIndex, NdisOpenConfigurationKeyByName, NdisOpenProtocolConfiguration, NdisReadConfiguration, NdisUnicodeStringToAnsiString, UNICODE_STRING


NdisWriteErrorLogEntry

NdisWriteErrorLogEntry writes an entry to the system I/O error log file.

VOID
  NdisWriteErrorLogEntry(
    IN NDIS_HANDLE  NdisAdapterHandle,
    IN NDIS_ERROR_CODE  ErrorCode,
    IN ULONG  NumberOfErrorValues,
    IN ULONG  ...
    );

Parameters

NdisAdapterHandle
Specifies the handle representing the NIC that is the cause of the I/O error to be logged. This handle is an input parameter to MiniportInitialize.
ErrorCode
Specifies the NDIS_STATUS_XXX code describing the I/O error.
NumberOfErrorValues
Specifies the number of ULONG values to follow this parameter.
...
Specifies a variable-sized array of ULONGs associated with the error to be logged.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisWriteErrorLogEntry allocates an I/O error log record, fills in the record with the supplied information about the error, and then writes the record to the I/O error log file.

The system places a limit on the potential size of an error log record. For Windows 2000 and later versions, the limit is defined as ERROR_LOG_MAXIMUM_SIZE. The NumberOfErrorValues passed to NdisWriteErrorLogEntry therefore has a system-enforced limit, which is considerably less than the maximum possible value for a ULONG.

In practice, few callers of NdisWriteErrorLogEntry even approach the limit for NumberOfErrorValues because supplying many additional NDIS_STATUS_XXX values is not particularly helpful to the user or system administrator who later reads the error log, using the Win32 event viewer. Logging an I/O error at every possible opportunity is not particularly helpful to users either, so a miniport driver should log only critical I/O errors that can help a user or system administrator to debug a network failure for which the NIC is responsible on a particular machine or a configuration resource conflict discovered during driver initialization.

In general, a NIC driver calls NdisWriteErrorLogEntry during initialization from its MiniportInitialize function if it cannot initialize a NIC that it controls or cannot allocate the hardware resources it needs to carry out I/O operations on its NIC. A NIC driver also can call NdisWriteErrorLogEntry when a device-reset operation fails due to unrecoverable hardware error(s). Logging these kinds of I/O errors helps users or system administrators to identify a badly configured NIC or a NIC with failing hardware components.

Callers of NdisWriteErrorLogEntry run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportInitialize, MiniportReset, NdisMSetAttributes, NdisMSetAttributesEx


NdisWriteEventLogEntry

NdisWriteEventLogEntry logs an event to the Win32 event log.

NDIS_STATUS
  NdisWriteEventLogEntry(
    IN PVOID  LogHandle,
    IN NDIS_STATUS  EventCode,
    IN ULONG  UniqueEventValue,
    IN USHORT  NumStrings,
    IN PVOID  StringsList  OPTIONAL,
    IN ULONG  DataSize,
    IN PVOID  Data  OPTIONAL
    );

Parameters

LogHandle
Pointer to the driver object of the protocol that is logging this event.
EventCode
Specifies the NDIS_STATUS_XXX code describing the event.
UniqueEventValue
Identifies this instance of the error message.
NumStrings
Specifies the number of pointers to Unicode strings in the optional StringsList. If StringsList is NULL, NumStrings must be zero.
StringsList
Either NULL or points to buffered Unicode strings. These strings, which describe the event, are inserted into the Win32 event log and can be examined with the Win32 event viewer. Each string must be a NUL-terminated Unicode string.
DataSize
Specifies the number of bytes in the buffer for the binary data at Data. If Data is NULL, DataSize must be zero.
Data
Either NULL or points to buffered binary dump data that is useful for understanding the event. This data can be examined with the Win32 event viewer.

Return Value

NdisWriteEventLogEntry can return one of the following values:

NDIS_STATUS_SUCCESS
The event was successfully logged.
NDIS_STATUS_BUFFER_TOO_SHORT
The optionally supplied Unicode strings and binary dump data exceed the maximum-allowed size (MAX_EVENT_LOG_DATA_SIZE).
NDIS_STATUS_RESOURCES
NDIS was unable to allocate memory for the I/O error log record.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisWriteEventLogEntry allocates an I/O error log record, fills in the record with the supplied information about the event, and then writes the record to the I/O error log file. A user can view the logged event, including an optional description of the event and/or optional binary dump data, with the Win32 event viewer.

The NT error-logging thread uses any strings supplied in the optional StringsList to fill in messages written into the Win32 event log. Each string must be a NUL-terminated Unicode string. The I/O Manager assumes that the initial string is either the name of the driver reporting the error or the name of the device that caused the error.

The Unicode strings supplied by the caller should be read from the registry or should be language-independent (that is, the strings should be the same in any language — for example, the string could be a file name).

Caller-supplied dump data can be any binary data (such as register values) that is useful in understanding the event. The caller does not have to pad the binary data. If necessary, NdisWriteEventLogEntry pads the binary dump data so that the final data size is a multiple integral of sizeof(ULONG).

The system limits the total size of the optional data supplied to NdisWriteEventLogEntry. The combined size of the strings list and the (possibly padded) binary dump must be less than or equal to MAX_EVENT_LOG_DATA_SIZE.

NdisWriteEventLogEntry is called only by protocol drivers. Miniport drivers should call NdisWriteErrorLogEntry to log events and errors.

Callers of NdisWriteEventLogEntry run at IRQL <= DISPATCH_LEVEL.

See Also

MiniportInitialize, MiniportReset, NdisMSetAttributes, NdisMSetAttributesEx, NdisWriteErrorLogEntry


NdisWritePciSlotInformation

NdisWritePciSlotInformation writes a specified number of bytes to the PCI configuration space for a NIC on the PCI bus.

ULONG
  NdisWritePciSlotInformation(
    IN NDIS_HANDLE  NdisAdapterHandle,
    IN ULONG  SlotNumber,
    IN ULONG  Offset,
    IN PVOID  Buffer,
    IN ULONG  Length
    );

Parameters

NdisAdapterHandle
Specifies the MiniportAdapterHandle passed in to MiniportInitialize and to most other MiniportXxx functions.
SlotNumber
Reserved. NDIS ignores this parameter.
Offset
Specifies the byte offset within the PCI configuration space at which to begin transferring the caller-supplied configuration information.
Buffer
Pointer to a caller-allocated buffer containing the PCI configuration information to be written.
Length
Specifies the size in bytes of the buffer at Buffer and, therefore, how many bytes of PCI configuration information to write.

Return Value

NdisWritePciSlotInformation returns how many bytes of caller-supplied data it wrote.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisWritePciSlotInformation writes PCI configuration information for a NIC. However, drivers of NICs on PCI buses call NdisImmediateReadPciSlotInformation, NdisReadPciSlotInformation, or NdisMPciAssignResources far more frequently than this function.

When NIC driver finds its device on a PCI bus with Ndis(Immediate)ReadPciSlotInformation or by retrieving information from the \DriverName\Parameters key in the registry, that driver can call NdisMPciAssignResources to determine the bus-relative configuration parameters it can use in subsequent calls to other Ndis Xxx configuration functions. If NdisMPciAssignResources returns values that require the driver to reconfigure its device on the bus, it can call NdisWritePciSlotInformation.

NdisWritePciSlotInformation transfers the same type of bus-relative PCI configuration information as NdisImmediateWritePciSlotInformation. However, callers of NdisWritePciSlotInformation pass the MiniportAdapterHandle passed in to the MiniportInitialize function, rather than the WrapperConfigurationContext handle.

The caller is responsible for releasing the memory at Buffer when NdisWritePciSlotInformation returns control.

Callers of NdisWritePciSlotInformation can run at IRQL <= DISPATCH_LEVEL. Usually, callers are running at IRQL PASSIVE_LEVEL.

See Also

MiniportInitialize, NdisFreeMemory, NdisImmediateWritePciSlotInformation, NdisMMapIoSpace, NdisMPciAssignResources, NdisMRegisterInterrupt, NdisMRegisterIoPortRange, NdisMSetAttributes, NdisMSetAttributesEx, NdisReadPciSlotInformation


NdisWritePcmciaAttributeMemory

NdisWritePcmciaAttributeMemory writes bus-relative configuration parameters for a PC Card NIC to attribute memory.

ULONG
  NdisWritePcmciaAttributeMemory(
    IN NDIS_HANDLE  NdisAdapterHandle,
    IN ULONG  Offset,
    IN PVOID  Buffer,
    IN ULONG  Length
    );

Parameters

NdisAdapterHandle
Specifies the handle that NDIS passed as an input parameter to MiniportInitialize.
Offset
Specifies the byte offset from the beginning of attribute memory, excluding odd-numbered bytes, at which to begin writing.
Buffer
Pointer to a caller-allocated buffer from which this function copies the specified number of bytes to PC Card attribute memory.
Length
Specifies the number of even-numbered bytes to write to attribute memory, beginning at Offset.

Return Value

NdisWritePcmciaAttributeMemory returns how many bytes it wrote to attribute memory. A return value of zero indicates that the write operation failed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The driver of a PC Card NIC calls NdisWritePcmciaAttributeMemory to write bus-relative configuration parameters for its NIC to PC Card attribute memory. Such a miniport driver usually calls NdisWritePcmciaAttributeMemory from its MiniportInitialize function. A driver can call NdisWritePcmciaAttributeMemory more than once to write non-overlapping sections of attribute memory.

Drivers of PC Card NICs should use NdisWritePcmciaAttributeMemory to maintain binary compatibility across Microsoft operating systems that support Win32. Drivers should never attempt to write directly to attribute memory from the bus.

PC Card attribute memory contains significant information only in even-numbered bytes. NdisWritePcmciaAttributeMemory therefore treats attribute memory as if it were compacted, with all odd (meaningless) bytes removed. The Offset and Length parameters refer to compacted memory (memory consisting only of even-numbered bytes). For example, to write a 6-byte Ethernet address to attribute memory at an actual offset of 0xFF0, the caller of NdisWritePcmciaAttributeMemory would specify an Offset of 0x7F8 (0xFF0/2) and a Length of 6.

Callers of NdisWritePcmciaAttributeMemory run at IRQL <= DISPATCH.

See Also

MiniportInitialize, NdisReadPcmciaAttributeMemory


NdisWritePortBufferUchar

NdisWritePortBufferUchar is called by the NIC driver to write UCHARs from a buffer to its NIC.

VOID
  NdisWritePortBufferUchar(
    IN NDIS_HANDLE  NdisAdapterHandle,
    IN ULONG  Port,
    IN PUCHAR  Buffer,
    IN ULONG  Length
    );

Parameters

NdisAdapterHandle
Specifies the handle that the NDIS interface library associates with the network interface card.
Port
Specifies the I/O port.
Buffer
Pointer to the caller-supplied buffer from which this function writes the UCHAR values to Port.
Length
Specifies the number of UCHARs to write to Port.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisWritePortBufferUchar sequentially writes each UCHAR to the port. It determines how the host accesses the I/O port and processes the write request accordingly.

Callers of NdisWritePortBufferUchar can be running at any IRQL.

See Also

NdisRawWritePortBufferUchar, NdisReadPortBufferUchar, NdisWritePortUchar


NdisWritePortBufferUlong

NdisWritePortBufferUlong is called by the NIC driver to write ULONGs from a buffer to its NIC.

VOID
  NdisWritePortBufferUlong(
    IN NDIS_HANDLE  NdisAdapterHandle,
    IN ULONG  Port,
    IN PULONG  Buffer,
    IN ULONG  Length
    );

Parameters

NdisAdapterHandle
Specifies the handle that the NDIS interface library associates with the network interface card.
Port
Specifies the I/O port.
Buffer
Pointer to the caller-supplied buffer from which this function writes the ULONG values to Port.
Length
Specifies the number of ULONGs to write to Port.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisWritePortBufferUlong sequentially writes each ULONG to the port. It determines how the host accesses the I/O port and processes the write request accordingly.

Callers of NdisWritePortBufferUlong can be running at any IRQL.

See Also

NdisRawWritePortBufferUlong, NdisReadPortBufferUlong, NdisWritePortUlong


NdisWritePortBufferUshort

NdisWritePortBufferUshort is called by the NIC driver to write USHORTs from a buffer to its NIC.

VOID
  NdisWritePortBufferUshort(
    IN NDIS_HANDLE  NdisAdapterHandle,
    IN ULONG  Port,
    IN PUSHORT  Buffer,
    IN ULONG  Length
    );

Parameters

NdisAdapterHandle
Specifies the handle that the NDIS interface library associates with the network interface card.
Port
Specifies the I/O port.
Buffer
Pointer to the caller-supplied buffer from which this function writes the USHORT values to Port.
Length
Specifies the number of USHORTs to write to Port.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisWritePortBufferUshort sequentially writes each USHORT to the port. It determines how the host accesses the I/O port and processes the write request accordingly.

Callers of NdisWritePortBufferUshort can be running at any IRQL.

See Also

NdisRawWritePortBufferUshort, NdisReadPortBufferUshort, NdisWritePortUshort


NdisWritePortUchar

NdisWritePortUchar is called by the NIC driver to write a UCHAR to an I/O port.

VOID
  NdisWritePortUchar(
    IN NDIS_HANDLE  NdisAdapterHandle,
    IN ULONG  Port,
    IN UCHAR  Data
    );

Parameters

NdisAdapterHandle
Specifies the handle that the NDIS interface library associates with the network interface card.
Port
Specifies the I/O port.
Data
Specifies the UCHAR value to write to Port.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Callers of NdisWritePortUchar can be running at any IRQL.

See Also

NdisRawWritePortUchar, NdisReadPortUchar, NdisWritePortBufferUchar


NdisWritePortUlong

NdisWritePortUlong is called by the NIC driver to write a ULONG to an I/O port.

VOID
  NdisWritePortUlong(
    IN NDIS_HANDLE  NdisAdapterHandle,
    IN ULONG  Port,
    IN ULONG  Data
    );

Parameters

NdisAdapterHandle
Specifies the handle that the NDIS interface library associates with the network interface card.
Port
Specifies the I/O port.
Data
Specifies the ULONG value to write to Port.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Callers of NdisWritePortUlong can be running at any IRQL.

See Also

NdisRawWritePortUlong, NdisReadPortUlong, NdisWritePortBufferUlong


NdisWritePortUshort

NdisWritePortUshort is called by the NIC driver to write a USHORT to an I/O port.

VOID
  NdisWritePortUshort(
    IN NDIS_HANDLE  NdisAdapterHandle,
    IN ULONG  Port,
    IN USHORT  Data
    );

Parameters

NdisAdapterHandle
Specifies the handle that the NDIS interface library associates with the network interface card.
Port
Specifies the I/O port.
Data
Specifies the USHORT value to write to Port.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Callers of NdisWritePortUshort can be running at any IRQL.

See Also

NdisRawWritePortUshort, NdisReadPortUshort, NdisWritePortBufferUshort


NdisWriteRegisterUchar

NdisWriteRegisterUchar is called by the NIC driver to write a UCHAR to a memory-mapped device register.

VOID
  NdisWriteRegisterUchar(
    IN PUCHAR  Register,
    IN UCHAR  Data
    );

Parameters

Register
Pointer to the memory-mapped register. This virtual address must fall within a range returned by an initialization-time call to NdisMMapIoSpace.
Data
Specifies the caller-supplied UCHAR that this function transfers to the Register.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If a driver calls this function, its NIC's device registers must be mapped to noncached memory during driver initialization.

Callers of NdisWriteRegisterUchar can be running at any IRQL.

See Also

MiniportInitialize, NdisMMapIoSpace, NdisReadRegisterUchar, NdisWriteRegisterUlong, NdisWriteRegisterUshort


NdisWriteRegisterUlong

NdisWriteRegisterUlong is called by the NIC driver to write a ULONG to a memory-mapped device register.

VOID
  NdisWriteRegisterUlong(
    IN PULONG  Register,
    IN ULONG  Data
    );

Parameters

Register
Pointer to the memory-mapped register. This virtual address must fall within a range returned by an initialization-time call to NdisMMapIoSpace.
Data
Specifies the caller-supplied ULONG that this function transfers to the Register.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If a driver calls this function, its NIC's device registers must be mapped to noncached memory during driver initialization.

Callers of NdisWriteRegisterUlong can be running at any IRQL.

See Also

MiniportInitialize, NdisMMapIoSpace, NdisReadRegisterUlong, NdisWriteRegisterUchar, NdisWriteRegisterUshort


NdisWriteRegisterUshort

NdisWriteRegisterUshort is called by the NIC driver to write a USHORT to a memory-mapped device register.

VOID
  NdisWriteRegisterUshort(
    IN PUSHORT  Register,
    IN USHORT  Data
    );

Parameters

Register
Pointer to the memory-mapped register. This virtual address must fall within a range returned by an initialization-time call to NdisMMapIoSpace.
Data
Specifies the caller-supplied USHORT that this function transfers to the Register.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If a driver calls this function, its NIC's device registers must be mapped to noncached memory during driver initialization.

Callers of NdisWriteRegisterUshort can be running at any IRQL.

See Also

MiniportInitialize, NdisMMapIoSpace, NdisReadRegisterUshort, NdisWriteRegisterUchar, NdisWriteRegisterUlong


NdisZeroMappedMemory

NdisZeroMappedMemory fills a block of memory that was mapped with a preceding call to NdisMMapIoSpace with zeros.

VOID
  NdisZeroMappedMemory(
    IN PVOID  Destination,
    IN ULONG  Length
    );

Parameters

Destination
Specifies the base virtual address of a block of mapped memory.
Length
Specifies the number of bytes to be filled with zeros.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A NIC driver can call NdisZeroMappedMemory to zero-initialize mapped device memory. The given Destination and Length must be a proper subrange of the range specified when the driver called NdisMMapIoSpace.

NdisZeroMappedMemory is optimized, and a NIC driver can call this function any time that it needs to clear a mapped memory range.

Callers of NdisZeroMappedMemory can run at any IRQL.

See Also

MiniportInitialize, NdisMMapIoSpace, NdisZeroMemory


NdisZeroMemory

NdisZeroMemory fills a block of memory with zeros.

VOID
  NdisZeroMemory(
    IN PVOID  Destination,
    IN ULONG  Length
    );

Parameters

Destination
Specifies the base virtual address of a block of memory.
Length
Specifies how many bytes to fill with zeros.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NdisZeroMemory fills the specified range with zeros. The given Destination and Length must be a proper subrange of a caller-accessible memory range.

As long as the given range was allocated from nonpaged pool, the caller can be running at any IRQL. Otherwise, a caller must be running at IRQL < DISPATCH_LEVEL as, for example, when a caller clears a structure it allocated on the stack.

See Also

NdisAllocateMemory, NdisZeroMappedMemory


TR_COMPARE_NETWORK_ADDRESSES

TR_COMPARE_NETWORK_ADDRESSES sets a caller-supplied variable to a value indicating whether a given Token Ring address is greater than, less than, or equal to another given Token Ring address.

VOID
  TR_COMPARE_NETWORK_ADDRESSES(
    IN PCHAR  A,
    IN PCHAR  B,
    OUT PINT  Result
    );

Parameters

A
Pointer to the first network address.
B
Pointer to the second network address.
Result
Pointer to a caller-supplied variable in which this macro returns the result of its comparison as one of the following values:
Result < zero
B is greater than A.
Result > zero
A is greater than B.
Zero
A equals B.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Token Ring network addresses do not have a defined ordering relationship. Consequently, the results of this macro for unequal addresses depend on the argument ordering.

Callers of this macro can be running at any IRQL if all pointer parameters access resident memory.

See Also

TR_COPY_NETWORK_ADDRESS


TR_COPY_NETWORK_ADDRESS

TR_COPY_NETWORK_ADDRESS copies a given Token Ring address to a given location.

VOID
  TR_COPY_NETWORK_ADDRESS(
    OUT PCHAR  D,
    IN PCHAR  S
    );

Parameters

D
Pointer to a caller-supplied varible to which this function copies the source address.
S
Pointer to the source address.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Callers of this macro can be running at any IRQL as long as the source and destination address pointers are resident.

See Also

TR_COMPARE_NETWORK_ADDRESSES


TR_IS_BROADCAST

TR_IS_BROADCAST sets a caller-supplied variable to a Boolean value indicating whether a given Token Ring address is a broadcast address.

VOID
  TR_IS_BROADCAST(
    IN PUCHAR  A,
    OUT PBOOLEAN  R
    );

Parameters

A
Pointer to a network address.
R
Pointer to a caller-supplied variable in which this macro returns TRUE if the address is broadcast.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A broadcast address applies to all stations in the extended network.

Callers of this macro can be running at any IRQL as long as the source address and supplied variable are resident.

See Also

TR_IS_FUNCTIONAL, TR_IS_GROUP, TR_IS_NOT_DIRECTED, TR_IS_SOURCE_ROUTING


TR_IS_FUNCTIONAL

TR_IS_FUNCTIONAL sets a caller-supplied variable to a Boolean value indicating whether a given Token Ring address is a functional address.

VOID
  TR_IS_FUNCTIONAL(
    IN PUCHAR  A,
    OUT PBOOLEAN  R
    );

Parameters

A
Pointer to a network address.
R
Pointer to a caller-supplied variable in which this macro returns TRUE if the address is functional.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Callers of this macro can be running at any IRQL as long as the source address and supplied variable are resident.

See Also

TR_IS_BROADCAST, TR_IS_GROUP, TR_IS_NOT_DIRECTED, TR_IS_SOURCE_ROUTING


TR_IS_GROUP

TR_IS_GROUP sets a caller-supplied variable to a Boolean value indicating whether a given Token Ring address is a group address.

VOID
  TR_IS_GROUP(
    IN PUCHAR  A,
    OUT PBOOLEAN  R
    );

Parameters

A
Pointer to a network address.
R
Pointer to a caller-supplied variable in which this macro returns TRUE if the address is a group address.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Callers of this macro can be running at any IRQL as long as the source address and supplied variable are resident.

See Also

TR_IS_BROADCAST, TR_IS_FUNCTIONAL, TR_IS_NOT_DIRECTED, TR_IS_SOURCE_ROUTING


TR_IS_NOT_DIRECTED

TR_IS_NOT_DIRECTED sets a caller-supplied variable to a Boolean value indicating whether a given Token Ring address is neither a functional nor a group address.

VOID
  TR_IS_NOT_DIRECTED(
    IN PUCHAR  A,
    OUT PBOOLEAN  R
    );

Parameters

A
Pointer to a network address.
R
Pointer to a caller-supplied variable in which this macro returns TRUE if the address is not directed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Callers of this macro can be running at any IRQL as long as the source address and supplied variable are resident.

See Also

TR_IS_BROADCAST, TR_IS_FUNCTIONAL, TR_IS_GROUP, TR_IS_SOURCE_ROUTING


TR_IS_SOURCE_ROUTING

TR_IS_SOURCE_ROUTING sets a caller-supplied variable to a Boolean value indicating whether a given Token Ring address is a source-routing address.

VOID
  TR_IS_SOURCE_ROUTING(
    IN PUCHAR  A,
    OUT PBOOLEAN  R
    );

Parameters

A
Pointer to a network address.
R
Pointer to a caller-supplied variable in which this macro returns TRUE if the address is a source-routing address.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A source routing address has the source-routing bit asserted.

Callers of this macro can be running at any IRQL as long as the source address and supplied variable are resident.

See Also

TR_IS_BROADCAST, TR_IS_FUNCTIONAL, TR_IS_GROUP, TR_IS_NOT_DIRECTED


NDIS Driver Lower-Edge Functions

This describes, in alphabetic order, the system-defined functions implemented in NDIS drivers layered above an underlying NIC driver that exports a set of NDIS upper-edge (Miniport Xxx) functions.

Five types of NDIS drivers have at least some of the functions described here:

  1. NDIS transport protocols that export a set of the Protocol Xxx functions described here and communicate with their clients through the TDI interface described later in Part 3.
  2. NDIS intermediate drivers that export the Protocol Xxx functions described here, along with a set of the Miniport Xxx functions, described earlier in NDIS Driver Upper Edge Functions.

    Intermediate NDIS drivers appear to be miniport drivers to higher-level NDIS drivers that layered themselves above such an intermediate driver by establishing a binding. Intermediate NDIS drivers appear to be protocols to the NDIS drivers below them, including NIC drivers. To the NDIS library, such an intermediate driver appears to be both a protocol and a miniport driver.

  3. Connection-oriented clients that export some of the Protocol Xxx functions, along with the ProtocolCo Xxx and ProtocolCl Xxx functions, described here. Such a client protocol also might communicate with its own clients through the TDI interface described later in Part 3 or, as the lowest component in a transport stack, with its own client(s) through a transport protocol-specific interface.
  4. Connection-oriented, stand-alone call managers that export some of the Protocol Xxx functions, along with the ProtocolCo Xxx and ProtocolCm Xxx functions, described here.
  5. Drivers of connection-oriented NICs with integrated call-management support. Such a miniport driver, sometimes called an MCM driver, exports the ProtocolCm Xxx functions described here, along with a set of the Miniport Xxx and MiniportCo Xxx functions, described earlier in NDIS Driver Upper Edge Functions.

Driver Function Names

All NDIS driver functions with the prefix "Protocol" have been given metanames describing their respective basic functionality in the references that follow.

Except for the DriverEntry function, NDIS-defined driver functions can have any name the driver writer chooses. For easy debugging, most system-supplied protocols simply substitute a driver-specific prefix for the Protocol prefix used in this documentation.

The initial entry point of any kernel-mode driver has the explicit name DriverEntry in order to be loaded automatically by the system. For more information about the general requirements for and functionality of DriverEntry routines, see Writing a DriverEntry Routine.

Calling NdisXxx Functions at Appropriate IRQLs

NDIS lower-edge driver functions run within the following range of IRQLs, shown in order of increasing priority:

PASSIVE_LEVEL < DISPATCH_LEVEL.

Any driver function running at IRQL PASSIVE_LEVEL can be pre-empted by a thread of execution running at a higher priority IRQL. That is, every ProtocolXxx function can be pre-empted by device drivers' ISRs that run at DIRQL when interrupts occur or by a system clock interrupt.

Each of the following DriverEntry and Protocol Xxx descriptions contains information about the possible range of IRQLs at which that function runs. For certain Protocol Xxx functions, the IRQL range effectively restrict the set of Ndis Xxx functions that these Protocol Xxx can call. For example, a call to NdisCopyBuffer from a Protocol Xxx function running at IRQL DISPATCH_LEVEL or while the Protocol Xxx is holding a spin lock can cause a fatal page fault.

Initialization-Only and Pageable Driver Code

NDIS protocols mark their DriverEntry functions as initialization-only code, using the NDIS_INIT_FUNCTION macro.

Other driver functions can be marked as pageable code, using the NDIS_PAGABLE_FUNCTION macro. However, a driver function can be pageable code if and only if it never runs at IRQL >= DISPATCH_LEVEL. This restriction implies the following:

  • A function marked pageable cannot acquire any spin lock and should not call other functions that do.
  • A function marked pageable cannot be called by any function that is holding a spin lock when the call occurs.
  • A function marked pageable must run exclusively at IRQL < DISPATCH_LEVEL.

Most of the Protocol Xxx functions described here except ProtocolBindAdapter, ProtocolOpenAdapterComplete, ProtocolUnbindAdapter, ProtocolCoAfRegisterNotify, and ProtocolCloseAdapterComplete can be called by NDIS at IRQL DISPATCH_LEVEL.


DriverEntry of NDIS Protocol Drivers

The DriverEntry function is required and is the first function that the system calls in any NDIS protocol or intermediate driver, including connection-oriented clients and stand-alone call managers.

NTSTATUS
  DriverEntry(
    IN PDRIVER_OBJECT  DriverObject,
    IN PUNICODE_STRING  RegistryPath
    );

Parameters

DriverObject
Pointer to the driver object representing this driver.
RegistryPath
Pointer to a driver-specific registry path specification set up by the driver's installation script (.inf). For more information about driver installation scripts, see Device Installation Overview.

Return Value

DriverEntry returns STATUS_SUCCESS, or its equivalent NDIS_STATUS_SUCCESS, if the driver registered as an NDIS protocol successfully. If DriverEntry fails initialization by propagating an error status returned by an Ndis Xxx or by a kernel-mode support routine, the driver will not remain loaded. DriverEntry must execute synchronously; that is, it cannot return STATUS_PENDING or its equivalent NDIS_STATUS_PENDING.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The DriverEntry function of every type of NDIS protocol driver must call NdisRegisterProtocol to register the driver's Protocol Xxx entry points with the NDIS library. All types of NDIS protocols should register fully functional ProtocolBindAdapter and ProtocolUnbindAdapter functions to support plug and play. In general, a DriverEntry function should call NdisRegisterProtocol just before it returns control with STATUS_SUCCESS or NDIS_STATUS_SUCCESS.

Any protocol driver that exports a set of standard kernel-mode driver routines in addition to its NDIS-defined ProtocolXxx functions must set the entry points for those driver routines in the given driver object passed in to its DriverEntry function. For more information about the functionality of such a protocol's DriverEntry function, see Writing a DriverEntry Routine. For more information about the TdiDispatch Xxx routines exported by TDI transport protocols, see TDI Transport Driver Dispatch Routines.

If an attempt to allocate resources that the driver needs to carry out network I/O operations fails, DriverEntry should release all resources it already allocated before it returns control with a status other than STATUS_SUCCESS or NDIS_STATUS_SUCCESS.

After calling NdisRegisterProtocol, connection-oriented client protocols subsequently call NdisClOpenAddressFamily from their ProtocolCoAfRegisterNotify functions to register their ProtocolCl Xxx functions with NDIS. Similarly, connection-oriented call managers and MCM drivers subsequently call NdisCmRegisterAddressFamily from their ProtocolBindAdapter functions or NdisMCmRegisterAddressFamily from their MiniportInitialize functions, respectively, to register their ProtocolCm Xxx functions.

An NDIS intermediate driver, such as one that translates an underlying NIC driver's native frame format into another format for higher level protocols, simply passes the input parameters to its DriverEntry function, uninterpreted, to certain Ndis Xxx functions.

Usually, the DriverEntry function of such an NDIS intermediate driver calls the following Ndis Xxx functions in the following order:

  1. NdisMInitializeWrapper to notify the NDIS library that the driver is about to register as a miniport driver
  2. NdisIMRegisterLayeredMiniport to register the driver's Miniport Xxx functions
  3. NdisRegisterProtocol to register the driver's Protocol Xxx functions

    Such an intermediate driver must register ProtocolBindAdapter and ProtocolUnbindAdapter functions with the NDIS library when it calls NdisRegisterProtocol. Its ProtocolBindAdapter function will be called later to complete driver initialization and to bind the intermediate driver to an underlying miniport driver.

In effect, the DriverEntry function of an NDIS intermediate driver can ignore the RegistryPath pointer after passing it to NdisMInitializeWrapper. Such a driver also can ignore the DriverObject pointer after passing it to NdisIMRegisterLayeredMiniport. However, the driver should save the DriverHandle returned by NdisIMRegisterLayeredMiniport and the NdisProtocolHandle returned by NdisRegisterProtocol for subsequent calls to Ndis Xxx functions. The intermediate driver's ProtocolBindAdapter function binds the driver to each underlying NIC driver before its MiniportInitialize function is called to initialize the intermediate driver's virtual NIC, and still higher level protocols subsequently bind themselves to the virtual NIC it creates. This strategy allows an NDIS intermediate driver to allocate resources at the creation of the virtual NIC according to the features of the underlying NIC driver to which it is bound.

DriverEntry runs at IRQL PASSIVE_LEVEL.

See Also

NdisClOpenAddressFamily, NdisCmRegisterAddressFamily, NdisIMRegisterLayeredMiniport, NdisMCmRegisterAddressFamily, NdisMInitializeWrapper, NdisRegisterProtocol, NdisOpenProtocolConfiguration, NdisReadConfiguration, ProtocolBindAdapter, ProtocolUnbindAdapter


ProtocolBindAdapter

The ProtocolBindAdapter function is required to support Plug and Play. All NDIS protocol drivers must export a ProtocolBindAdapter function.

VOID
  ProtocolBindAdapter(
    OUT PNDIS_STATUS Status,
    IN NDIS_HANDLE  BindContext,
    IN PNDIS_STRING  DeviceName,
    IN PVOID  SystemSpecific1,
    IN PVOID  SystemSpecific2
    );

Parameters

Status
Pointer to a variable in which ProtocolBindAdapter returns the status of its operation(s), as one of the following:
NDIS_STATUS_SUCCESS
The driver completed initialization successfully and bound itself to the given NIC driver specified at DeviceName.
NDIS_STATUS_PENDING
The protocol will complete the bind operation asynchronously with a call to NdisCompleteBindAdapter when it is ready to accept receives from the underlying driver and to send transmit, query, and set requests down to the underlying driver.
NDIS_STATUS_XXX or NTSTATUS_XXX
The protocol's attempt to set up a binding failed or the protocol could not allocate the resources it needed to carry out network I/O operations. Usually, such an error status is propagated from an Ndis Xxx function or a kernel-mode support routine.
BindContext
Specifies a handle, supplied by NDIS, that the protocol passes subsequently to NdisCompleteBindAdapter.
DeviceName
Pointer to a buffered Unicode string naming an underlying NIC driver or virtual NIC driver to which ProtocolBindAdapter should bind.
SystemSpecific1
Specifies a registry path pointer that is a required parameter to NdisOpenProtocolConfiguration. The caller cannot use this pointer for any other purpose.
SystemSpecific2
Reserved for system use. The caller cannot use this pointer for any purpose.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

ProtocolBindAdapter performs dynamic binding operations whenever an underlying NIC to which the protocol can bind itself becomes available. In addition, ProtocolBindAdapter continues driver initialization operations deferred from the DriverEntry function to support Plug and Play. ProtocolBindAdapter allocates sufficient memory to maintain per-binding run-time state and calls NdisOpenAdapter with the given BindContext and DeviceName to bind itself to the underlying driver.

If NdisOpenAdapter returns NDIS_STATUS_PENDING, the driver's ProtocolOpenAdapterComplete function will be called subsequently when the binding operation has completed. ProtocolBindAdapter should store the input BindContext handle in the area it allocated for per-binding state; the ProtocolBindContext handle it supplied to NdisOpenAdapter is an input parameter to the driver's ProtocolOpenAdapterComplete function, which must pass the BindContext handle to NdisCompleteBindAdapter subsequently. The underlying NIC driver returns NDIS_STATUS_ADAPTER_NOT_READY for any requests it receives while the open operation is pending. Consequently, ProtocolBindAdapter cannot call Ndis(Co)Request to query the underlying driver if NdisOpenAdapter returns NDIS_STATUS_PENDING.

In these circumstances, ProtocolBindAdapter simply sets Status to NDIS_STATUS_PENDING and returns control, thereby deferring whatever actions the protocol takes to set up binding-specific state and to allocate binding-specific resources to ProtocolOpenAdapterComplete if this function is called with an input Status of NDIS_STATUS_SUCCESS.

Similarly, if NdisOpenAdapter returns an error status, ProtocolBindAdapter sets Status to the returned value, releases any per-binding resources the driver has allocated, and returns control immediately. Otherwise, a successful binding has been established and the protocol can receive indications from the underlying driver to its Protocol(Co)Status, Protocol(Co)ReceivePacket, and/or ProtocolReceive functions.

Consequently, when NdisOpenAdapter returns NDIS_STATUS_SUCCESS, ProtocolBindAdapter allocates the resources the driver needs to carry out network I/O on the binding and sets up whatever binding-specific run-time state the protocol uses to track network I/O operations. If the driver's installation script installed adapter-specific configuration information in the protocol section of the registry, ProtocolBindAdapter calls NdisOpenProtocolConfiguration and NdisReadConfiguration to retrieve this information. For more information about driver installation scripts, see Device Installation Overview.

Depending on the underlying media, ProtocolBindAdapter also can call NdisCoRequest or NdisRequest to query the underlying driver (or NDIS) about the underlying driver's NIC-specific limits, such as its maximum frame size, transmit/receive buffer space, and so forth, to set up appropriate state for the binding.

Any protocol bound to a connection-oriented NIC driver can assume that the underlying miniport driver both supports multipacket sends and indicates full-packet receives.

A protocol bound to a connectionless miniport driver can determine whether the underlying driver indicates full-packet receives by comparing the values that driver returns for the OID_GEN_CURRENT_LOOKAHEAD and OID_GEN_RECEIVE_BLOCK_SIZE queries the protocol passes to NdisRequest. If they are identical, the protocol will make no calls to NdisTransferData on this binding. The protocol can determine whether the underlying driver supports multipacket sends with the OID_GEN_MAXIMUM_SEND_PACKETS query. However, even if the underlying driver returns one, indicating that it does not have a MiniportSendPackets function, the protocol can still call NdisSendPackets on the binding, as long as the protocol does not supply out-of-band information with the packet descriptors it allocates for sends. NDIS handles the submission of packet arrays to such an underlying connectionless NIC driver transparently to bound protocols. The protocol is responsible for ensuring that the underlying driver is capable of handling protocol-supplied out-of-band data, if any.

For more information about general and medium-specific OID requests, see NDIS Object Identifiers.

A driver's Protocol(Co)ReceivePacket or ProtocolReceive function can be called as soon as the protocol sets up a packet filter with OID_GEN_CURRENT_PACKET_FILTER for the binding. For the NULL filter, receive indications are enabled on return from a successful call to NdisOpenAdapter.

Every NDIS protocol driver should allocate sufficient packet pool and buffer pool from which to allocate packet descriptors and buffer descriptors for subsequent network transmits and, possibly, for subsequent transfer-data requests, depending on whether the underlying driver indicates full-packet receives with NdisMIndicateReceivePacket or NdisMCoIndicateReceivePacket.

The ProtocolBindAdapter function of a connection-oriented call manager or MCM driver must call NdisCmRegisterAddressFamily or NdisMCmRegisterAddressFamily, respectively, to register its ProtocolCm Xxx functions and signalling services for this adapter with NDIS. NDIS will advertise the call manager's services to possible client protocols by calling their ProtocolCoAfRegisterNotify functions, which each potential connection-oriented client registered when it called NdisRegisterProtocol from its DriverEntry function.

Note that connection-oriented client protocols cannot call NdisClOpenAddressFamily from their ProtocolBindAdapter functions. Instead, these protocols make this call to register their ProtocolCl Xxx functions with NDIS from their ProtocolCoAfRegisterNotify functions.

The ProtocolBindAdapter function of an NDIS intermediate driver is responsible for prompting the initialization of the driver's virtual NIC by calling NdisIMInitializeDeviceInstanceEx or NdisIMInitializeDeviceInstance, which, in turn, calls the driver's MiniportInitialize function. Such a driver must initialize its virtual NIC after ProtocolBindAdapter (or ProtocolBindAdapterComplete) establishes a binding to the underlying driver specified at DeviceName. Still higher level protocols cannot bind to such an intermediate driver until its virtual NIC has been initialized. If the intermediate driver sets up a device context area with NdisIMInitializeDeviceInstanceEx, higher level protocols that bind themselves to its virtual NIC subsequently can call NdisIMGetBindingContext to query the information that the intermediate driver provided.

If ProtocolBindAdapter cannot allocate the resources it needs to carry out subsequent network I/O operations, it should free all resources it has already allocated, set Status to an appropriate error value, and return control.

If the driver is ready to carry out network I/O on the established binding, ProtocolBindAdapter calls NdisCompleteBindAdapter with NDIS_STATUS_SUCCESS for the Status and OpenStatus arguments.

ProtocolBindAdapter runs at IRQL PASSIVE_LEVEL.

See Also

DriverEntry of NDIS Protocol Drivers, MiniportInitialize, MiniportSendPackets, NdisAllocateBufferPool, NdisAllocateMemory, NdisAllocatePacketPool, NdisClOpenAddressFamily, NdisCmRegisterAddressFamily, NdisCompleteBindAdapter, NdisCoRequest, NdisCoSendPackets, NdisIMGetBindingContext, NdisIMInitializeDeviceInstance, NdisIMInitializeDeviceInstanceEx, NdisInitUnicodeString, NdisMCmRegisterAddressFamily, NdisMCoIndicateReceivePacket, NdisMIndicateReceivePacket, NdisOpenAdapter, NdisOpenProtocolConfiguration, NDIS_PACKET_OOB_DATA, NdisReadConfiguration, NdisRequest, NDIS_REQUEST, ProtocolCoAfRegisterNotify, ProtocolCoReceivePacket, ProtocolCoStatus, ProtocolOpenAdapterComplete, ProtocolReceive, ProtocolReceivePacket, ProtocolStatus, ProtocolUnbindAdapter


ProtocolClAddPartyComplete

The ProtocolClAddPartyComplete function is required for connection-oriented NDIS clients that set up multipoint connections. Such clients must have ProtocolClAddPartyComplete functions to complete the asynchronous operations that they initiate with NdisClAddParty. Otherwise, such a protocol driver's registered ProtocolClAddPartyComplete function can simply return control.

VOID
  ProtocolClAddPartyComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  ProtocolPartyContext,
    IN NDIS_HANDLE  NdisPartyHandle,
    IN PCO_CALL_PARAMETERS  CallParameters
    );

Parameters

Status
Specifies final status of the client-initiated add-party operation, which can be one of the following:
NDIS_STATUS_SUCCESS
The given party was added on the client's active multipoint VC.
NDIS_STATUS_RESOURCES
NDIS could not allocate sufficient resources to track the new party.
NDIS_STATUS_FAILURE
The client passed an invalid NdisVcHandle to NdisClAddParty.
NDIS_STATUS_XXX
The call manager's ProtocolCmAddParty function returned a CM-determined value to indicate why it could not add the party to the VC.
ProtocolPartyContext
Specifies the client-supplied handle originally passed to NdisClAddParty.
NdisPartyHandle
If Status is NDIS_STATUS_SUCCESS, this NDIS-supplied handle represents the association between the call manager and client regarding this party. Otherwise, the attempt to add a party failed and the client should consider this parameter an invalid handle.
CallParameters
Pointer to a structure of type CO_CALL_PARAMETERS, originally set up by the client for its call to NdisClAddParty but possibly modified subsequently by the call manager.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A call to ProtocolClAddPartyComplete indicates completion of the asynchronous operation initiated when the client called NdisClAddParty. If the input Status is set to anything other than NDIS_STATUS_SUCCESS, ProtocolClAddPartyComplete can release or reuse the client-allocated buffers at ProtocolPartyContext and at CallParameters.

If the attempt to add a party succeeded, ProtocolClAddPartyComplete should save the input NdisPartyHandle for subsequent calls to NDIS library functions concerning this party in the client's ProtocolPartyContext area. For example, the client must pass this handle in a subsequent call to NdisClDropParty eventually unless the remote party that it represents closes its connection first.

The structure at CallParameters originally was allocated and initialized by the client, which passed this pointer to NdisClAddParty. However, the call manager might have modified the client-supplied values to reflect the results of the CM's negotiation with the network or with a signaling peer while processing the client's add-party request. To determine whether the call manager made any modifications, ProtocolClAddPartyComplete can check the Flags member of this structure for whether CALL_PARAMETERS_CHANGED is set. If so, ProtocolClAddPartyComplete must update the per-party state that the client maintains for this call at ProtocolPartyContext unless it finds the CM's modifications unacceptable. The particular signalling protocol determines what the client can do in this case. Usually, a client calls NdisClDropParty if it finds the CM-modified call parameters unacceptable.

Depending on the signalling protocol of the call manager, the traffic parameters at CallParameters can be identical for all parties on any particular multipoint connection. That is, as the client of such a call manager adds parties on a multipoint connection that the client originally set up with NdisClMakeCall, it can supply only the target address of each party and leave the traffic parameters as originally set up for the multipoint VC each time it calls NdisClAddParty.

ProtocolClAddPartyComplete must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

CO_CALL_PARAMETERS, NdisClAddParty, NdisClDropParty, NdisClMakeCall, NdisCmAddPartyComplete, NdisMCmAddPartyComplete, ProtocolClIncomingDropParty, ProtocolCmAddParty


ProtocolClCallConnected

The ProtocolClCallConnected function is used by connection-oriented NDIS clients that accept incoming calls. Such clients must have ProtocolClCallConnected functions. Otherwise, such a protocol driver's registered ProtocolClCallConnected function can simply return control.

VOID
  ProtocolClCallConnected(
    IN NDIS_HANDLE  ProtocolVcContext
    );

Parameter

ProtocolVcContext
Specifies the client's handle to its per-VC context area. The client originally returned this handle to NDIS from its ProtocolCoCreateVc function.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

When ProtocolClCallConnected is called, the call manager has successfully completed the final handshake on an incoming call offer previously accepted by the client's ProcolClIncomingCall function, which already set up the call parameters for this connection at ProtocolVcContext.

The call to ProtocolClCallConnected indicates that data transfers, whether incoming or outgoing, now can be done on the VC. ProtocolClCallConnected should ensure that the client is ready to make or accept transfers on the VC before it returns control.

ProtocolClCallConnected must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

NdisCmDispatchCallConnected, NdisCoSendPackets, NdisMCmDispatchCallConnected, ProtocolClIncomingCall, ProtocolCoCreateVc, ProtocolCoReceivePacket


ProtocolClCloseAfComplete

The ProtocolClCloseAfComplete function is used by connection-oriented NDIS clients. All connection-oriented NDIS clients must have ProtocolClCloseAfComplete functions to complete the asynchronous operations that they initiate with NdisClCloseAddressFamily.

VOID
  ProtocolClCloseAfComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  ProtocolAfContext
    );

Parameters

Status
Specifies the final status of the client-initiated request to close the address family, which can be one of the following:
NDIS_STATUS_SUCCESS
The address family was closed. The NdisAfHandle that represented the open address family, which the client stored in its ProtocolAfContext area, is now invalid.
NDIS_STATUS_FAILURE
Either the AF has associated VC(s) and/or registered SAP(s) that the client must release before attempting to close the AF, or the client called NdisClCloseAddressFamily twice because NDIS discovered that the AF state was marked as "closing."
ProtocolAfContext
Specifies the client-supplied handle to its per-AF context area. The client originally set up this context area and passed this handle to NDIS with NdisClOpenAddressFamily.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

After ensuring that it has no outstanding VCs and/or registered SAPs on its open address family, a client calls NdisClCloseAddressFamily to delete the association between itself, a call manager, and a particular underlying NIC. NDIS calls the ProtocolCmCloseAf function for the call manager that this client originally used to open the address family as an asynchronous operation. After calling NdisClCloseAddressFamily, the client should consider the NdisAfHandle invalid.

Consequently, the client must have a ProtocolClCloseAfComplete function, which NDIS calls when the asynchronous close-AF operation is done. If the input Status is NDIS_STATUS_SUCCESS, the client can release its per-AF context area.

ProtocolClCloseAfComplete must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

NdisClCloseAddressFamily, NdisClOpenAddressFamily, NdisFreeMemory, NdisFreeToNPagedLookasideList, ProtocolCmOpenAf, ProtocolCmCloseAf, ProtocolUnbindAdapter


ProtocolClCloseCallComplete

The ProtocolClCloseCallComplete function is used by connection-oriented NDIS clients. All connection-oriented NDIS clients must have ProtocolClCloseCallComplete functions to complete the asynchronous operations that they initiate with NdisClCloseCall.

VOID
  ProtocolClCloseCallComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  ProtocolVcContext,
    IN NDIS_HANDLE  ProtocolPartyContext  OPTIONAL
    );

Parameters

Status
Specifies the final status of the client's request to close this call, which can be one of the following:
NDIS_STATUS_SUCCESS
The call manager has successfully closed the call that existed on the given VC and deactivated the VC.
NDIS_STATUS_XXX
The call manager failed the request to close the call for some CM-determined reason, and NDIS propagated the status returned by its ProtocolCmCloseCall function to the client.
ProtocolVcContext
Specifies the handle to the client's per-VC context area This is the handle that the client originally passed to NDIS with NdisCoCreateVc or returned to NDIS from its ProtocolCoCreateVc function.
ProtocolPartyContext
Specifies the handle to the client's per-party context area for the last remaining party on the client-created VC representing a multipoint connection. Otherwise, this parameter is NULL.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If the given VC was created by the client and Status is NDIS_STATUS_SUCCESS, the client can now do either of the following:

  • Tear down its VC with NdisCoDeleteVc and release or prepare for reuse the context area(s) it allocated.
  • Reinitialize its per-VC context area and reuse its VC to make another connection with NdisClMakeCall.

If the VC was created by the call manager, the client should consider the NdisVcHandle invalid when ProtocolClCloseCallComplete is called. The client must not make any further NdisCl/Co Xxx calls with this NdisVcHandle. After ProtocolClCloseCallComplete returns control, the call manager can delete its VC, thereby causing a call to the client's ProtocolCoDeleteVc function. The call manager can even dispatch another incoming call on the VC that it created, thereby causing a call to the client's ProtocolClIncomingCall function.

ProtocolClCloseCallComplete must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

NdisClCloseCall, NdisClMakeCall, NdisCmCloseCallComplete, NdisCoDeleteVc, NdisMCmCloseCallComplete, ProtocolClIncomingCall, ProtocolCmCloseCall, ProtocolCoDeleteVc


ProtocolClDeregisterSapComplete

The ProtocolClDeregisterSapComplete function is used by connection-oriented NDIS clients. Connection-oriented NDIS clients that accept incoming calls must have ProtocolClDeregisterSapComplete functions to complete the asynchronous operations that they initiate with NdisClDeregisterSap. Otherwise, such a protocol driver's registered ProtocolClDeregisterSapComplete function can simply return control.

VOID
  ProtocolClDeregisterSapComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  ProtocolSapContext
    );

Parameters

Status
Specifies the final status of the client's request to deregister its SAP, which can be one of the following:
NDIS_STATUS_SUCCESS
The SAP was closed. The NdisSapHandle that represented the client's previously registered SAP, which the client stored in its ProtocolSapContext area, is now invalid.
NDIS_STATUS_FAILURE
NDIS had marked the state of the AF as "closing," so the associated SAP represented by the NdisSapHandle was already released when the client's call to NdisClDeregisterSap occurred.
NDIS_STATUS_XXX
The call manager failed the request to close the SAP for some CM-determined reason, and NDIS propagated the status returned by its ProtocolCmDeregisterSap function to the client.
ProtocolSapContext
Specifies the client-supplied handle to its per-SAP context area, originally passed to NDIS with NdisClRegisterSap. After the call manager has successfully deregistered this SAP, the client can release its context area or prepare this context area for reuse.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A call to ProtocolClDeregisterSapComplete indicates that the client's preceding call to NdisClDeregisterSap has been processed by the call manager.

Unless the call manager failed the deregistration for some CM-determined reason, the client should consider the NdisSapHandle invalid when ProtocolClDeregisterSapComplete is called. Consequently, ProtocolClDeregisterSapComplete can release the per-SAP context area that the client allocated or prepare it for reuse in a subsequent call to NdisClRegisterSap.

ProtocolClDeregisterSapComplete must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

NdisClDeregisterSap, NdisClRegisterSap, NdisCmDeregisterSapComplete, NdisFreeMemory, NdisFreeToNPagedLookasideList, NdisMCmDeregisterSapComplete, ProtocolCmDeregisterSap


ProtocolClDropPartyComplete

The ProtocolClDropPartyComplete function is used by connection-oriented NDIS clients that set up multipoint connections. Such clients must have ProtocolClDropPartyComplete functions to complete the asynchronous operations that they initiate with NdisClDropParty. Otherwise, such a protocol driver's registered ProtocolClDropPartyComplete function can simply return control.

VOID
  ProtocolClDropPartyComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  ProtocolPartyContext
    );

Parameters

Status
Specifies the final status of the client-initiated drop-party operation, which can be one of the following:
NDIS_STATUS_SUCCESS
The party has been dropped. The NdisPartyHandle that represented this party, which the client stored in its ProtocolPartyContext area, is now invalid.
NDIS_STATUS_FAILURE
The given party was the last remaining on the client's multipoint VC. Therefore, the client should call NdisClCloseCall to drop this party.
ProtocolPartyContext
Specifies the handle to the client's per-party context area, which the client originally supplied to NDIS either when it called NdisClAddParty or NdisClMakeCall.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A call to ProtocolClDropPartyComplete indicates that the call manager has completed processing of the request initiated by the client's previous call to NdisClDropParty. ProtocolClDropPartyComplete can either release the client-allocated per-party context area or prepare it for reuse in a subsequent call to NdisClAddParty.

If the client is in the process of tearing down a multipoint VC that it created, ProtocolClDropPartyComplete can call NdisClDropParty with any valid NdisPartyHandle to one of the remaining parties on the client's active multipoint VC. If only one more party remains on its multipoint VC, the client should drop that party by passing its NdisPartyHandle to NdisClCloseCall.

ProtocolClDropPartyComplete must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

NdisClAddParty, NdisClCloseCall, NdisClDropParty, NdisClMakeCall, NdisCmDropPartyComplete, NdisFreeMemory, NdisFreeToNPagedLookasideList, NdisMCmDropPartyComplete, ProtocolCmDropParty


ProtocolClIncomingCall

The ProtocolClIncomingCall function is used by connection-oriented clients that accept incoming calls. Such clients must have ProtocolClIncomingCall functions. Otherwise, such a protocol driver's registered ProtocolClIncomingCall function can simply return NDIS_STATUS_NOT_SUPPORTED.

NDIS_STATUS
  ProtocolClIncomingCall(
    IN NDIS_HANDLE  ProtocolSapContext,
    IN NDIS_HANDLE  ProtocolVcContext,
    IN OUT PCO_CALL_PARAMETERS  CallParameters
    );

Parameters

ProtocolSapContext
Specifies the handle that the client originally supplied when it registered the SAP, which the call manager matched to this incoming call offer.
ProtocolVcContext
Specifies the handle to the client's per-VC context area, previously returned to NDIS by its ProtocolCoCreateVc function.
CallParameters
Pointer to a buffer, formatted as a CO_CALL_PARAMETERS structure, that contains the call parameters for this offered call.

Return Value

ProtocolClIncomingCall returns NDIS_STATUS_SUCCESS if the client accepts the incoming call offer. Any other client-determined status indicates its rejection of the offered call.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A call to ProtocolClIncomingCall indicates that the call manager has received a request over the network from a signalling peer to establish a connection with this client. That is, the request to set up such a connection was directed to a SAP previously registered with the call manager by this client.

Depending on the signalling protocol supported by the call manager, ProtocolClIncomingCall can modify the traffic parameters as part of the process of negotiating acceptance of an incoming call offer and/or, if the call manager supports QoS, the quality of service specification at CallParameters. The client should copy any information it will need subsequently from this buffered structure if it accepts the offered call.

Assuming the call manager finds the client's modifications, if any, acceptable, NDIS next calls the client's ProtocolClIncomingCallConnected function when it becomes possible for transfers to occur on the active VC representing the connection to the client on the remote node that originally initiated the call offer. If the client returns modified call parameters that are unacceptable, the call manager can tear down the VC it created for this offer, thereby causing calls to the client's ProtocolClIncomingCloseCall and then ProtocolCoDeleteVc functions instead.

ProtocolClIncomingCall must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

CO_CALL_PARAMETERS, NdisClRegisterSap, NdisCmDispatchIncomingCall, NdisMCmDispatchIncomingCall, ProtocolClCallConnected, ProtocolClIncomingCloseCall, ProtocolCoCreateVc, ProtocolCoDeleteVc


ProtocolClIncomingCallQoSChange

The ProtocolClIncomingCallQosChange function is used by connection-oriented clients on networks that support dynamic quality-of-service. Such clients must have ProtocolClIncomingCallQoSChange functions. Otherwise, such a protocol driver's registered ProtocolClIncomingCallQoSChange function can simply return control.

VOID
  ProtocolClIncomingCallQoSChange(
    IN NDIS_HANDLE  ProtocolVcContext,
    IN PCO_CALL_PARAMETERS  CallParameters
    );

Parameters

ProtocolVcContext
Specifies the handle to the client's per-VC context area for the VC on which a request to modify the quality of service has come in over the network.
CallParameters
Pointer to a buffer, formatted as a CO_CALL_PARAMETERS structure, that contains the new QoS specification.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A call to ProtocolClIncomingCallQoSChange indicates to the client that a remote peer has requested a change in the quality of service on this call. The new quality of service is described at CallParameters. The client can accept the requested change by simply returning control. Otherwise, ProtocolClIncomingCallQosChange should tear down the call with NdisClCloseCall.

ProtocolClIncomingCallQoSChange must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

NdisClCloseCall, NdisClModifyCallQoS, ProtocolCmModifyCallQoS


ProtocolClIncomingCloseCall

The ProtocolClIncomingCloseCall function is used by all connection-oriented NDIS clients. All such clients must have fully functional ProtocolClIncomingCloseCall functions.

VOID
  ProtocolClIncomingCloseCall(
    IN NDIS_STATUS  CloseStatus,
    IN NDIS_HANDLE  ProtocolVcContext,
    IN PVOID  CloseData OPTIONAL,
    IN UINT  Size OPTIONAL
    );

Parameters

CloseStatus
Specifies the status that indicates the cause of the connection teardown, which is usually NDIS_STATUS_SUCCESS to indicate that the remote party to the call requested that the connection be closed. Any other value indicates that problems on the network caused the call manager to terminate the connection.
ProtocolVcContext
Specifies the handle to the client's per-VC context area for the VC on which the connection is being closed. Whatever the value of CloseStatus, the client can neither send nor receive data on the VC designated by the NdisVcHandle that it stored in this context area.
CloseData
Pointer to a buffer containing a protocol-specific close message, possibly one supplied by the remote client that the call manager received over the network, or this parameter can be NULL.

When CloseStatus is NDIS_STATUS_SUCCESS, this parameter is NULL if the underlying network medium does not support transfers of data when closing a connection. However, any particular call manager might define a structure to pass additional diagnostic information to its clients on call teardowns caused by problems on the network.

Size
Specifies the size in bytes of the buffer at CloseData, zero if CloseData is NULL.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A call to ProtocolClIncomingCloseCall indicates that the one of the following has occurred:

  • The call manager has received a request over the network to close an established connection, identified by the NdisVcHandle that the client stored in its per-VC context area at ProtocolVcContext.
  • The call manager has detected that network problems will prevent further data transfers on the established connection.

In either case, ProtocolClIncomingCloseCall should carry out any protocol-determined operations, such as notifying the client's own client(s) that the connection is being broken. For example, if the call to be closed is a multipoint VC created by the client, ProtocolClIncomingCloseCall must call NdisClDropParty one or more times until only a single party remains on its multipoint VC.

Whether the given VC is a single-point or multipoint connection, ProtocolClIncomingCloseCall must call NdisClCloseCall to acknowledge that the client will neither attempt to send nor expect to receive data on this particular VC. If the call manager created this VC, ProtocolClIncomingCloseCall should return control after it calls NdisClCloseCall. It is the responsibility of the call manager to destroy or reuse any VC that it created.

If the client originally created this VC for an outgoing call, ProtocolClIncomingCloseCall can do one of the following after it calls NdisClDropParty as many times as necessary, if any, and NdisClCloseCall:

  • If CloseStatus is NDIS_STATUS_SUCCESS, tear down the VC with NdisCoDeleteVc and either release the client's per-VC context area or prepare it for reuse in a subsequent call to NdisCoCreateVc.
  • If CloseStatus is NDIS_STATUS_SUCCESS, retain the VC that the client created and prepare its per-VC context area for reuse in a subsequent call to NdisClMakeCall.
  • Otherwise, tear down the VC with NdisCoDeleteVc and release its per-VC context area if the call manager indicated that the network has become inoperative.

ProtocolClIncomingCloseCall must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

NdisClCloseCall, NdisClDropParty, NdisClMakeCall, NdisCmDispatchIncomingCloseCall, NdisCoDeleteVc, NdisCoCreateVc, NdisFreeMemory, NdisFreeToNPagedLookasideList, NdisMCmDispatchIncomingCloseCall, ProtocolClDropPartyComplete, ProtocolCoDeleteVc


ProtocolClIncomingDropParty

The ProtocolClIncomingDropParty function is used by connection-oriented NDIS clients that set up multipoint connections. Such clients must have ProtocolClIncomingDropParty functions. Otherwise, such a protocol driver's registered ProtocolClIncomingDropParty function can simply return control.

VOID
  ProtocolClIncomingDropParty(
    IN NDIS_STATUS  DropStatus,
    IN NDIS_HANDLE  ProtocolPartyContext,
    IN PVOID  CloseData  OPTIONAL,
    IN UINT  Size OPTIONAL
    );

Parameters

DropStatus
Indicates the reason for the party to be dropped. Usually, this is NDIS_STATUS_SUCCESS if the party on the remote note initiated a close of its connection, but it could be any CM-determined status if the call manager initiated this drop-party operation due to network problems that it discovered.
ProtocolPartyContext
Specifies the handle to the client's per-party context area for the party to be dropped. The client originally supplied this handle to NDIS when it called NdisClAddParty or NdisClMakeCall.
CloseData
Pointer to a buffer containing a protocol-specific close message, possibly one supplied by the remote client that the call manager received over the network, or this parameter can be NULL.

When DropStatus is NDIS_STATUS_SUCCESS, this parameter is NULL if the underlying network medium does not support transfers of data when closing a connection. However, any particular call manager might define a structure to pass additional diagnostic information to its clients on drop-party operations caused by problems on the network.

Size
Specifies the length, in bytes, of the buffer at CloseData, zero if CloseData is NULL.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A call to ProtocolClIncomingDropParty indicates that the one of the following has occurred:

  • The call manager has received a request over the network to close an established connection, identified by the NdisPartyHandle that the client stored in its per-party context area at ProtocolPartyContext.
  • The call manager has detected that network problems will prevent further data transfers on the established connection.

In either case, ProtocolClIncomingDropParty should carry out any protocol-determined operations for dropping the party from the client's multipoint VC. ProtocolClIncomingDropParty must call NdisClDropParty or, if this is the last remaining party on the client's multipoint VC, NdisClCloseCall.

ProtocolClIncomingDropParty should consider the NdisPartyHandle that the client obtained from NdisClAddParty or NdisClMakeCall invalid. ProtocolClIncomingDropParty can either release the client's per-party context area or prepare it for reuse in a subsequent call to NdisClAddParty.

ProtocolClIncomingDropParty must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

NdisClAddParty, NdisClCloseCall, NdisClDropParty, NdisClMakeCall, NdisCmDispatchIncomingDropParty, NdisFreeMemory, NdisFreeToNPagedLookasideList, NdisMCmDispatchIncomingDropParty


ProtocolClMakeCallComplete

The ProtocolClMakeCallComplete function is used by connection-oriented NDIS clients that make outgoing calls. Such clients must have ProtocolClMakeCallComplete functions to complete the asynchronous operations that they initiate with NdisClMakeCall. Otherwise, such a protocol driver's registered ProtocolClMakeCallComplete function can simply return control.

VOID
  ProtocolClMakeCallComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  ProtocolVcContext,
    IN NDIS_HANDLE  NdisPartyHandle  OPTIONAL,
    IN PCO_CALL_PARAMETERS  CallParameters
    );

Parameters

Status
Specifies the final status of the client's original call to NdisClMakeCall, which can be one of the following:
NDIS_STATUS_SUCCESS
The client's attempt to set up a virtual connection succeded. Consequently, the client can proceed to make transfers on the active VC using the NdisVcHandle returned by NdisCoCreateVc, which the client has stored in its per-VC context area at ProtocolVcContext.
NDIS_STATUS_RESOURCES
NDIS, the call manager, or an underlying driver could not allocate sufficient resources to set up the connection.
NDIS_STATUS_XXX
The call manager or underlying miniport driver failed to establish an active connection and NDIS propagated this driver-determined failure status to the client.
ProtocolVcContext
Specifies the handle to the client's per-VC context area, which the client originally supplied to NDIS when it called NdisCoCreateVc to set up the VC for its outgoing call.
NdisPartyHandle
If Status is NDIS_STATUS_SUCCESS and the client created a multipoint VC by passing an explicit ProtocolPartyContext handle to NdisClMakeCall, this is a valid NdisPartyHandle. Otherwise, this parameter is NULL.

ProtocolClMakeCallComplete must save any valid input NdisPartyHandle, usually in the client's per-party context area. The client must use this handle if (or when) it makes a subsequent call to NdisClDropParty or NdisClCloseCall that refers to this party.

CallParameters
Pointer to a buffered CO_CALL_PARAMETERS structure. The client allocated this buffer and initialized this structure with client-determined data before passing this pointer to NdisClMakeCall. While processing the client's request, the call manager can modify this data to reflect the results of its negotiation with the network or with a signalling peer.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A call to ProtocolClMakeCallComplete indicates that the call manager has completed processing the client's request to establish a virtual connection with NdisClMakeCall.

If the client's attempt to establish an outgoing call is unsuccessful (input Status is anything except NDIS_STATUS_SUCCESS), ProtocolClMakeCallComplete should do the following:

  • Release or prepare for reuse the ProtocolPartyContext area, if any, and the buffer at CallParameters that the client allocated.
  • Tear down the client-created VC with a call to NdisCoDeleteVc and release or prepare for reuse the client-allocated ProtocolVcContext area.

Otherwise, ProtocolClMakeCallComplete should do the following:

  1. Check the Flags member of the structure at CallParameters to see whether CALL_PARAMETERS_CHANGED is set, which indicates that the call manager modified the client-supplied call parameters.
  2. If so, examine the data at CallParameters to determine whether they are acceptable for this connection.

    For example, the client might retain the buffered call parameters for the active VC, save the NdisPartyHandle if this is a multipoint VC, and generally make the client ready for subsequent transfers and other operations on the active VC if it finds the given call parameters satisfactory.

  3. If not, the signalling protocol determines whether the client can attempt to renegotiate for acceptable call parameters with the call manager.

    For example, a particular call manager might allow its clients to call NdisClModifyCallQoS one or more times in these circumstances.

  4. If the CM-modified call parameters are unacceptable and further renegotiation is impossible, ProtocolClMakeCallComplete must tear down the call with NdisClCloseCall.

    In this case, ProtocolClMakeCallComplete should not attempt to release any client-allocated resources on return from NdisClCloseCall but can simply return control. Instead, the client should release the resources it allocated (or prepare them for reuse) within its ProtocolClCloseCallComplete function.

ProtocolClMakeCallComplete must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

CO_CALL_PARAMETERS, NdisClCloseCall, NdisClDropParty, NdisClMakeCall, NdisCmMakeCallComplete, NdisCoCreateVc, NdisCoDeleteVc, NdisFreeMemory, NdisFreeToNPagedLookasideList, NdisMCmMakeCallComplete, ProtocolClCloseCallComplete, ProtocolCmMakeCall


ProtocolClModifyCallQoSComplete

The ProtocolClModifyCallQoSComplete function is used by connection-oriented NDIS clients that can modify the quality of service on a connection dynamically. Such clients must have ProtocolClModifyCallQoSComplete functions to complete the asynchronous operations that they initate with NdisClModifyCallQoS. Otherwise, such a protocol driver's registered ProtocolClModifyCallQoSComplete function can simply return control.

VOID
  ProtocolClModifyCallQoSComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  ProtocolVcContext,
    IN PCO_CALL_PARAMETERS  CallParameters
    );

Parameters

Status
Specifies the final status of the client's asynchronous request to modify the call parameters for this VC as one of the following:
NDIS_STATUS_SUCCESS
The QoS was modified as requested by the client.
NDIS_STATUS_RESOURCES
NDIS or the call manager could not modify the QoS because one of them could not allocate sufficient resources dynamically.
NDIS_STATUS_INVALID_DATA
The call parameters that the client supplied to NdisClModifyCallQoS were invalid.
NDIS_STATUS_FAILURE
The call manager could not change the QoS because of a failure on the network or in another connection-oriented network component.
NDIS_STATUS_XXX
The call manager failed to change the QoS, and NDIS propagated the CM-determined failure status to the client.
ProtocolVcContext
Specifies the handle to the client's per-VC context area, which the client originally supplied to NDIS when it called NdisCoCreateVc to set up the VC for its outgoing call request or from its ProtocolCoCreateVc function if the client accepted an incoming call on this VC.
CallParameters
Pointer to a buffered CO_CALL_PARAMETERS structure containing the client-specified QoS change it requested, or, possibly, the original QoS for this VC established when the connection was activated, which the call manager has restored.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A call to ProtocolClModifyCallQoSComplete indicates that the call manager has completed processing of a client-initiated request to change the quality of service on an active VC. For example, if the underlying network medium supports dynamic QoS changes, a client can request modifications at any time on an active VC.

If the client's call to NdisClModifyCallQoS succeeds, ProtocolClModifyCallQoSComplete can accept the QoS change by simply returning control. Otherwise, ProtocolClModifyCallQoSComplete can engage in further negotiation with the call manager as long as the client's developer places some reasonable limit on the number of possible renegotiations. Alternatively, ProtocolClModifyCallQoSComplete can simply tear down the call with NdisClCloseCall whenever the call manager rejects a request to change the QoS and the previously established QoS has become unacceptable to the client.

ProtocolClModifyCallQoSComplete must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

CO_CALL_PARAMETERS, NdisClCloseCall, NdisClModifyCallQoS, NdisCmModifyCallQoSComplete, NdisMCmModifyCallQoSComplete, ProtocolCmModifyCallQoS, ProtocolCoCreateVc


ProtocolClOpenAfComplete

The ProtocolClOpenAfComplete function is used by all connection-oriented NDIS clients. Such clients must have ProtocolClOpenAfComplete functions to complete the asynchronous operations that they initiate with NdisClOpenAddressFamily.

VOID
  ProtocolClOpenAfComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  ProtocolAfContext,
    IN NDIS_HANDLE  NdisAfHandle
    );

Parameters

Status
Specifies the final status of the client's call to NdisClOpenAddressFamily, which can be any of the following:
NDIS_STATUS_SUCCESS
The address family has been opened, so the client can initialize its state at ProtocolAfContext and use the returned NdisAfHandle in subsequent calls to NDIS functions, such as NdisCoRequest, NdisCoCreateVc, and NdisClRegisterSap.
NDIS_STATUS_RESOURCES
The requested operation failed because NDIS or the call manager could not allocate sufficient memory or initialize the state one of them uses to track the client's open of this address family
NDIS_STATUS_FAILURE
NDIS failed this call, possibly for one of the following reasons:
  • The given address family does not match any AF that was registered for the underlying miniport driver to which the caller is bound.
  • The caller supplied invalid or insufficient information at ClCharacteristics to NdisClOpenAddressFamily.
  • The caller's adapter binding is closing.
  • The call manager that registered the given address family is closing its adapter binding.
ProtocolAfContext
Specifies the client-supplied handle to its per-AF context area for this address family. The client allocated this area and passed this handle to NDIS in its call to NdisClOpenAddressFamily.
NdisAfHandle
If Status is NDIS_STATUS_SUCCESS, specifies an NDIS-supplied valid handle to this address family, effectively representing an association established with NDIS between the client and a particular call manager bound to the same connection-oriented NIC driver. Otherwise, this parameter is NULL. The client must save a valid handle, usually in its ProtocolAfContext area, for subsequent calls to NdisCl/Co Xxx functions.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A call to ProtocolClOpenAfComplete indicates that some or all of the following has occurred:

  • NDIS validated some of the parameters that the client's ProtocolCoAfRegisterNotify function passed to NdisClOpenAddressFamily. If all were valid, NDIS saved the client's ProtocolCl Xxx entry points. Then, NDIS called the ProtocolCmOpenAf function of the call manager that just registered the specified address family with NDIS.
  • The call manager (or MCM driver if the miniport driver controls a NIC with integrated call-management functionality) has examined the specification that the client's ProtocolCoAfRegisterNotify function passed to NdisClOpenAddressFamily at AddressFamily and returned whether it was valid for this call manager to NDIS.

If the client's attempt to open an address family fails, NDIS cleans up its saved state before calling ProtocolClOpenAfComplete, which can release the resources that the client allocated for its call to NdisClOpenAddressFamily or prepare them for reuse.

Otherwise, ProtocolClOpenAfComplete should set up whatever client-determined state the client will need for subsequent operations on the newly opened AF. In particular, the client must save the input NdisAfHandle, usually in the client's ProtocolAfContext area. For example, ProtocolClOpenAfComplete also might call NdisInitializeNPagedLookasideList one or more times in preparation for dynamic allocations and releases of per-SAP, per-VC, and/or per-party context areas that the client will need subsequently.

If it accepts incoming calls, the client might proceed to allocate a per-SAP state area and call NdisClRegisterSap. If it makes outgoing calls, the client might proceed to allocate a per-VC state area and create a VC with NdisCoCreateVc in anticipation of an incoming request from one of its own clients to make an outgoing call to a remote node.

ProtocolClOpenAfComplete must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

NdisAllocateMemoryWithTag, NdisAllocateFromNPagedLookasideList, NdisClOpenAddressFamily, NdisClRegisterSap, NdisCmOpenAddressFamilyComplete, NdisCoCreateVc, NdisFreeMemory, NdisFreeToNPagedLookasideList, NdisInitializeNPagedLookasideList, NdisMCmOpenAddressFamilyComplete, ProtocolCmOpenAf, ProtocolCoAfRegisterNotify


ProtocolCloseAdapterComplete

The ProtocolCloseAdapterComplete function is a required driver function that completes processing for an unbinding operation for which NdisCloseAdapter returned NDIS_STATUS_PENDING.

VOID
  ProtocolCloseAdapterComplete(
    IN NDIS_HANDLE  ProtocolBindingContext,
    IN NDIS_STATUS  Status
    );

Parameters

ProtocolBindingContext
Specifies the handle to a protocol-allocated context area in which the protocol driver maintains per-binding run-time state. The driver supplied this handle when it called NdisOpenAdapter.
Status
Indicates the final status of the close operation in the underlying driver.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NDIS delays calling ProtocolCloseAdapterComplete until every request pending on the binding has completed. When ProtocolCloseAdapterComplete is called, the NdisBindingHandle originally returned by NdisOpenAdapter is no longer valid. ProtocolCloseAdapterComplete cannot call any Ndis Xxx function that requires this handle as a parameter.

ProtocolCloseAdapterComplete releases all resources the driver allocated for per-binding network I/O operations before it returns control.

ProtocolCloseAdapterComplete must call NdisCompleteUnbindAdapter with the UnbindContext handle saved in the ProtocolBindingContext area by ProtocolUnbindAdapter. Consequently, ProtocolCloseAdapterComplete should not release the driver-allocated context area until it has called NdisCompleteUnbindAdapter.

ProtocolCloseAdapterComplete runs at IRQL PASSIVE_LEVEL.

See Also

NdisCloseAdapter, NdisCompleteUnbindAdapter, NdisDeleteNPagedLookasideList, NdisFreeBufferPool, NdisFreeMemory, NdisFreePacketPool, NdisOpenAdapter, ProtocolUnbindAdapter


ProtocolClRegisterSapComplete

Connection-oriented NDIS clients that accept incoming calls must have ProtocolClRegisterSapComplete functions to complete the asynchronous operations that they initiate with NdisClRegisterSap. Otherwise, such a protocol driver's registered ProtocolClRegisterSapComplete function can simply return control.

VOID
  ProtocolClRegisterSapComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  ProtocolSapContext,
    IN PCO_SAP  Sap,
    IN NDIS_HANDLE  NdisSapHandle
    );

Parameters

Status
Specifies the final status of the client's call to NdisClRegisterSap, which can be one of the following:
NDIS_STATUS_SUCCESS
The SAP has been registered both with NDIS and the call manager, which will subsequently call NdisCmDispatchIncomingCall whenever it receives an incoming call offer directed to the given SAP, thereby causing NDIS to call the client's ProtocolClIncomingCall function.
NDIS_STATUS_RESOURCES
NDIS or the call manager could not allocate and/or initialize necessary resources to register and maintain the SAP.
NDIS_STATUS_INVALID_DATA
The client supplied an invalid specification at Sap to NDIS, which it forwarded to the call manager's ProtocolCmRegisterSap function for validation.
NDIS_STATUS_XXX
The call manager encountered an error in attempting to register the given SAP and NDIS propagated this CM-determined failure status to the client.
ProtocolSapContext
Specifies the handle to the client's per-SAP context area, which the client originally supplied to NDIS when it called NdisClRegisterSap. If the registration is successful, NDIS retains this context handle and uses it subsequently in calls to the client's ProtocolClIncomingCall function pertaining to this SAP.
Sap
Pointer to the client-allocated buffer containing the specification for the SAP to be opened. The client originally passed this pointer to NdisClRegisterSap.
NdisSapHandle
If Status is NDIS_STATUS_SUCCESS, specifies an NDIS-supplied valid handle to this registered SAP, effectively an association established with NDIS between the client and a particular call manager for the client-specified SAP. Otherwise, this parameter is NULL. The client must save a valid handle, preferably in its ProtocolSapContext area, for an eventual call to NdisClDeregisterSap.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NDIS calls ProtocolClRegisterSapComplete to indicate that the client's previous call to NdisClRegisterSap has been processed by NDIS and, if NDIS did not fail the call, by the call manager with which the client shares the NdisAfHandle that it passed to NdisClRegisterSap.

To receive incoming calls through a connection-oriented NIC, a client's ProtocolCoAfRegisterNotify or ProtocolClOpenAfComplete function usually registers one or more SAPs with the call manager.

To register each SAP, the client calls NdisClRegisterSap, passing in the NdisAfHandle that identifies the call manager from which the client wants to receive notifications of incoming calls, and NDIS returns the client an NdisSapHandle to the registered SAP if the client's call to NdisClRegisterSap succeeds. ProtocolClRegisterSapComplete must save each valid NdisSapHandle, usually in the client's per-SAP ProtocolSapContext area so it can release the SAP later with NdisClDeregisterSap.

The format of a SAP is specific to the call manager. If the call manager does not recognize the SAP that the client is attempting to register or if the specified SAP is already in use, the call manager can fail the SAP registration. ProtocolClRegisterSapComplete should check the input Status for NDIS_STATUS_SUCCESS before proceding further. If the attempt to register the SAP failed, ProtocolClRegisterSapComplete can either release the per-SAP context area and buffer at Sap that the client allocated or prepare them for reuse in another call to NdisClRegisterSap.

A client can receive incoming calls on a SAP even while SAP registration is still pending, that is, before its ProtocolClRegisterSapComplete function is called.

ProtocolClRegisterSapComplete must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

NdisClDeregisterSap, NdisClRegisterSap, NdisCmDispatchIncomingCall, NdisCmRegisterSapComplete, NdisFreeMemory, NdisFreeToNPagedLookasideList, NdisMCmDispatchIncomingCall, NdisMCmRegisterSapComplete, ProtocolClIncomingCall, ProtocolClOpenAfComplete, ProtocolCmRegisterSap, ProtocolCoAfRegisterNotify


ProtocolCmActivateVcComplete

The ProtocolCmActivateVcComplete function is required. This function indicates to the call manager that a previous call to NdisCoActivateVc has been completed by the miniport driver.

VOID
  ProtocolCmActivateVcComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  CallMgrVcContext,
    IN CO_CALL_PARAMETERS  CallParameters
    );

Parameters

Status
Specifies the final status, as indicated by the miniport driver, of the request by the call manager to activate a VC.
CallMgrVcContext
Specifies the handle to a call manager-allocated context area in which the call manager maintains its per-VC state. The call manager supplied this handle from its ProtocolCoCreateVc function.
CallParameters
Pointer to the call parameters as specified by the call manager in a call to NdisCmActivateVc.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

When other network components have completed their operations for activating a virtual connection, initiated when the call manager called NdisCmActivateVc, NDIS notifies the call manager that the VC has been activated by calling its ProtocolCmActivateVcComplete function. The status of the activation is found in Status. Possible values for Status include, but are not limited to:

NDIS_STATUS_SUCCESS
Indicates that the VC completed successfully and the call manager can continue operations on this VC as required by its media.
NDIS_STATUS_RESOURCES
Indicates that another component in the activation has failed to activate the virtual connection because of a lack of memory or an inability allocate another type of resource.
NDIS_STATUS_NOT_ACCEPTED
Indicates that an activation is currently pending on the virtual connection. Only one activation can be processed at a time for a virtual connection. The request to activate the VC should be tried again at a later time.
NDIS_STATUS_CLOSING
Indicates that a deactivation is pending on the VC and the VC is no longer available for network communication until the deactivation has been completed and a successful activation has taken place.
NDIS_STATUS_INVALID_DATA
Indicates that the miniport driver has rejected the call parameters at CallParamters as invalid for the adapter.

ProtocolCmActivateVcComplete must check the status returned in Status to ensure that the virtual connection has been activated successfully. The call manager must not attempt to communicate over the virtual connection if Status is not NDIS_STATUS_SUCCESS.

Call managers must complete any processing required by their network media to ensure that the virtual connection is ready for data transmission before returning control to NDIS.

If the call manager specified either ROUND_UP_FLOW or ROUND_DOWN_FLOW in the CallParameters->MediaParamters->Flags, the call parameters returned in CallParamters can have been changed by the miniport driver. Call managers should examine the call parameters that were returned to ensure proper operation. If the new call parameters are unsatisfactory, the call manager should either call NdisCmActivateVc again with new call parameters or deactivate the VC with NdisCmDeactivateVc.

ProtocolCmActivateVcComplete must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

NdisCmActivateVc, NdisCmDeactivateVc, ProtocolCmMakeCall


ProtocolCmAddParty

The ProtocolCmAddParty function is a required function. ProtocolCmAddParty sets up the media-specific parameters to add a party to an existing multipoint call, stores state data for the new party, and causes the party to be added to the call.

NDIS_STATUS
  ProtocolCmAddParty(
    IN NDIS_HANDLE  CallMgrVcContext,
    IN OUT PCO_CALL_PARAMETERS  CallParameters,
    IN NDIS_HANDLE  NdisPartyHandle,
    OUT PNDIS_HANDLE  CallMgrPartyContext
    );

Parameters

CallMgrVcContext
Specifies the handle to a call manager-allocated context area in which the call manager maintains its per-VC state. The call manager supplied this handle to NDIS from its ProtocolCoCreateVc function.
CallParameters
Pointer to a CO_CALL_PARAMETERS structure that contains the parameters, specified by a connection-oriented client, for the party that is being added to an existing call.
NdisPartyHandle
Specifies a handle, supplied by NDIS, that uniquely identifies a multipoint party that is to be added to an existing virtual connection. This handle is opaque to the call manager and reserved for NDIS library use.
CallMgrPartyContext
Specifies, on return, a handle to a call manager-supplied context area in which the call manager maintains state about this party for the multipoint call.

Return Value

ProtocolCmAddParty returns the status of its operation(s) as one of the following:

NDIS_STATUS_SUCCESS
Indicates that the call manager successfully allocated the necessary resources to maintain state about the party and successfully added the party to the call.
NDIS_STATUS_PENDING
Indicates that the call manager will complete the request to add a party asynchronously. When the call manager has completed all operations for adding the party, it must call NdisCmAddPartyComplete to signal NDIS that this operation has been completed.
NDIS_STATUS_RESOURCES
Indicates that the call manager was unable to allocate and/or initialize its resources for adding a party to the connection.
NDIS_STATUS_NOT_SUPPORTED
Indicates that the call manager was unable to add the party to the multipoint call because the caller requested invalid or unavailable features in the call parameters at CallParameters or else that the media type supported by this call manager does not support multipoint calls.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

ProtocolCmAddParty performs any necessary allocations of dynamic resources and structures that the call manager requires to maintain state information about the party, specified by NdisPartyHandle, to be added to a multipoint call. Such resources could include, but are not limited to, memory buffers, data structures, events, and other similar resources. Call managers should also initialize relevant per-party structures in this function.

In the per-party state area that the call manager allocates, the call manager must store the handle specified by NdisPartyHandle for reference in future calls. After the call manager has allocated and finish initializing its per-party state area, the address of the state buffer should be set as the CallMgrPartyContext handle before returning control to NDIS. To do this, dereference the handle and store a pointer to the state buffer as the value of the handle. For example:

*CallMgrPartyContext = SomeBuffer;

Call managers perform any necessary communication with their network hardware or other media-specific actors, as necessary, to add the party specified by the call parameters at CallParameters to an existing multipoint call.

ProtocolCmAddParty must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

NdisClAddParty, ProtocolClAddPartyComplete


ProtocolCmCloseAf

The ProtocolCmCloseAf function is a required function that releases per-open resources for an address family that a call manager supports.

NDIS_STATUS
  ProtocolCmCloseAf(
    IN NDIS_HANDLE  CallMgrAfContext
    );

Parameters

CallMgrAfContext
Specifies the handle to the call manager's per-AF context area, originally supplied to NDIS by the call manager's ProtocolCmOpenAf function.

Return Value

ProtocolCmCloseAf returns the status of its operation(s) as one of the following:

NDIS_STATUS_SUCCESS
Indicates that the call manager has successfully released or deactivated any resources that is allocated on behalf of the connection-oriented client that opened this instance of the address family.
NDIS_STATUS_PENDING
Indicates that the request to close the open instance of the address family will be completed asynchronously. The call manager must call NdisCmCloseAddressFamilyComplete when all such operations have been completed.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

ProtocolCmCloseAf releases and/or deactivates any resources that were allocated by the call manager in its ProtocolCmOpenAf function. The call manager also should undo any other actions it took on behalf of the connection-oriented client when the address family was opened by that client.

If there are any outstanding requests or connections still open on an address family stored in the CallMgrAfContext, a call manager can respond to a client's request to close the address family in either of the following ways:

  • The call manager can fail the request with NDIS_STATUS_NOT_ACCEPTED.
  • The call manager can return NDIS_STATUS_PENDING. After the client has closed all calls and deregistered all SAPs, the call manager can then close the address family and call Ndis(M)CmCloseAddressFamilyComplete to notify the client. This is the preferred response.

ProtocolCmCloseAf must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

NdisCmCloseAddressFamilyComplete, ProtocolCmOpenAf


ProtocolCmCloseCall

The ProtocolCmMakeCall function is a required function that terminates an existing call and releases any resources that the call manager allocated for the call.

NDIS_STATUS
  ProtocolCmCloseCall(
    IN NDIS_HANDLE  CallMgrVcContext,
    IN NDIS_HANDLE  CallMgrPartyContext  OPTIONAL,
    IN PVOID  CloseData  OPTIONAL,
    IN UINT  Size  OPTIONAL
    );

Parameters

CallMgrVcContext
Specifies the handle to a call manager-allocated context area in which the call manager maintains its per-VC state. This handle was provided to NDIS from the call managers ProtocolCmMakeCall function.
CallMgrPartyContext
Specifies the handle, if any, to a call manager-allocated context area in which the call manager maintain information about a party on a multipoint VC. This handle is NULL if the call being closed is not a multipoint call.
CloseData
Pointer to a buffer containing connection-oriented client-specified data that should be sent across the connection before the call is terminated. This parameter is NULL if the underlying network medium does not support transfers of data when closing a connection.
Size
Specifies the length, in bytes, of the buffer at CloseData, zero if CloseData is NULL.

Return Value

ProtocolCmCloseCall returns the status of its operation(s) as one of the following:

NDIS_STATUS_SUCCESS
Indicates that the call manager successfully terminated the call.
NDIS_STATUS_PENDING
Indicates that the call manager will complete the request to terminate the call asynchronously. When the call manager has completed all operations required to terminate the connection, it must then call NdisCmCloseCallComplete to signal NDIS that the call has been closed.
NDIS_STATUS_INVALID_DATA
Indicates that CloseData was specified, but the underlying network medium does not support sending data concurrent with terminating a call.
NDIS_STATUS_XXX
Indicates that the call manager could not terminate the call. The actual error returned can be a status propagated from another NDIS library routine.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

ProtocolCmCloseCall communicated with network control devices or other media-specific actors, as necessitated by its media, to terminate a connection between the local node and a remote node. If the call manager is required to communicate with network control devices (e.g. a networking switch) it should use a virtual connection to the network control device that it established in its ProtocolBindAdapter function. Stand-alone call managers communicate to such network devices by calling NdisCoSendPackets. Miniport drivers with integrated call-management support never call NdisCoSendPackets. Instead, they transmit the data directly across the network.

If CloseData is nonNULL and sending data at connection termination is supported by the media that this call manager handles, the call manager should transmit the data specified at CloseData to the remote node before completing the call termination. If sending data concurrent with a connection being terminated is not supported, call managers should return NDIS_STATUS_INVALID_DATA.

If ProtocolCmCloseCall is passed an explicit CallMgrPartyContext, then the call being terminated is a multipoint VC, and the call manager must perform any necessary network communication with its networking hardware, as appropriate to its media type, to terminate the call as a multipoint call. The call manager must also free the memory that it allocated earlier, in ProtocolCmMakeCall, for its per-party state that is pointed to by CallMgrPartyContext. Failure to properly release, de-allocate, or otherwise deactivate those resources causes a memory leak.

After the call has been terminated with the network, any close data has been sent, and any resources at CallMgrPartyContext have been freed, the call manager must call NdisCmDeactivateVc. This notifies NDIS and the underlying miniport driver, if any, to expect no further transfers on the given VC.

ProtocolCmCloseCall must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

NdisClMakeCall, NdisCmDeactivateVc, NdisCoSendPackets, ProtocolCmMakeCall


ProtocolCmDeactivateVcComplete

The ProtocolCmDeactivateVcComplete function is a required function. ProtocolCmDeactivateVcComplete completes the processing of a call-manager-initiated request that the underlying miniport driver (and NDIS) deactivate a VC for which NdisCmDeactivateVc previously returned NDIS_STATUS_PENDING.

VOID
  ProtocolCmDeactivateVcComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  CallMgrVcContext
    );

Parameters

Status
Specifies the final status of the deactivation.
CallMgrVcContext
Specifies the handle to a call manager-allocated context area in which the call manager maintains its per-VC state. The call manager supplied this handle to NDIS from its ProtocolCoCreateVc function.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NDIS usually calls ProtocolCmDeactivateVcComplete in the context of the call manager's closing down a call on behalf of a connection-oriented client. The call manager typically calls NdisCmDeactivateVc from its ProtocolCmCloseCall function. Whenever NdisCmDeactivateVc returns NDIS_STATUS_PENDING, NDIS subsequently calls its ProtocolCmDeactivateVcComplete function.

That is, when the underlying connection-oriented miniport driver has deactivated the VC, NDIS calls ProtocolCmDeactivateVcComplete. The final status of the deactivation is found in Status. Possible values for the final status include, but are not limited to:

NDIS_STATUS_SUCCESS
Indicates that the VC was deactivated successfully.
NDIS_STATUS_NOT_ACCEPTED
Indicates that an activation is pending on this VC. The call manager should attempt to deactivate the VC at a later time.
NDIS_STATUS_CLOSING
Indicates that a deactivation is currently pending on this VC. The call manager need not call NdisCmDeactivateVc again as only one call to NdisCmDeactivateVc is required to deactivate a VC.

ProtocolCmDeactivateVcComplete performs whatever postprocessing is necessary to complete the deactivation of a virtual connection, such as setting flags in its state area to indicate that the connection is inactive or releasing dynamically allocated resources used while the VC is active.

Completion of the deactivation means that all call parameters for the VC used on activation are no longer valid. Any further use of the VC is prohibited except to reactivate it with a new set of call parameters.

Call managers should release any resources that were allocated for the VC activation and return control as quickly as possible. If the call manager previously returned NDIS_STATUS_PENDING from its ProtocolCmCloseCall function and all operations to close the call have been completed, ProtocolCmDeactivateVcComplete should now call NdisCmCloseCallComplete.

ProtocolCmDeactivateVcComplete must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

MiniportCoDeactivateVc, NdisCmCloseCallComplete, NdisCmDeactivateVc, ProtocolCmCloseCall


ProtocolCmDeregisterSap

The ProtocolCmDeregisterSap function is required. This function is called by NDIS to request that a call manager deregister a SAP on behalf of a connection-oriented client.

NDIS_STATUS
  ProtocolCmDeregisterSap(
    IN NDIS_HANDLE  CallMgrSapContext
    );

Parameters

CallMgrSapContext
Specifies the handle to a call-manager allocated context area in which the call manager maintains its per-SAP state information. The call manager supplied this handle to NDIS from its ProtocolCmRegisterSap function.

Return Value

ProtocolCmDeregisterSap returns the status of its operation(s) as one of the following:

NDIS_STATUS_SUCCESS
Indicates that the call manager successfully removed the SAP registration and freed any resources allocated to maintain per-SAP information.
NDIS_STATUS_PENDING
Indicates that the call manager will complete the request to deregister the SAP asynchronously. The call manager must call NdisCmDeregisterSapComplete to signal NDIS when the operation is complete.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

ProtocolCmDeregisterSap communicates with network control devices or other media-specific agents, as necessary, to deregister the SAP on the network. Such actions could include, but are not limited to:

  • Communicating with a switching hardware
  • Communicating with a network control station
  • Communicating with other media-specific network agents

If a call manager is required to communicate with networking control agents, such as a network switch, it should use a virtual connection to the network control agent that it established in its ProtocolBindAdapter function. Stand-alone call managers communicate through the underlying miniport driver by calling NdisCoSendPackets. Miniport drivers that provide integrated call-management support never call NdisCoSendPackets. Instead, they transmit the data directly across the network.

In addition, ProtocolCmDeregisterSap must free any dynamically-allocated resources in its per-SAP area, provided at CallMgrSapContext, as well as freeing the state area itself before returning control to NDIS.

ProtocolCmDeregisterSap must be written such that it can be run at IRQL DISPATCH_LEVEL.

See Also

NdisCmDeregisterSapComplete, NdisCoSendPackets, ProtocolBindAdapter, ProtocolCmRegisterSap


ProtocolCmDropParty

The ProtocolCmDropParty function is required. NDIS calls ProtocolCmDropParty to request that the call manager remove a party from an existing multipoint call.

NDIS_STATUS
  ProtocolCmDropParty(
    IN NDIS_HANDLE  CallMgrPartyContext,
    IN PVOID  CloseData  OPTIONAL,
    IN UINT  Size  OPTIONAL
    );

Parameters

CallMgrPartyContext
Specifies the handle to a call manager-allocated context area in which the call manager maintains its per-party state. This handle was provided to NDIS in the call managers ProtocolCmAddParty function.
CloseData
Pointer to a buffer containing connection-oriented client-specific data that should be sent across the connection before the party is dropped. This parameter is NULL if the underlying network medium does not support transfers of data when closing a connection.
Size
Specifies the length, in bytes, of the buffer at CloseData, zero if CloseData is NULL.

Return Value

ProtocolCmDropParty returns the status of its operation(s) as one of the following values:

NDIS_STATUS_SUCCESS
Indicates that the call manager has successfully dropped the party, sent any close data, and free the resources that were allocated for its context area.
NDIS_STATUS_PENDING
Indicates that the call manager will complete the request to drop the party asynchronously. The call manager must call NdisCmDropPartyComplete when all processing has been finished to notify NDIS and the requesting actor that the party has been dropped.
NDIS_STATUS_INVALID_DATA
Indicates that CloseData was specified to the call manager, but the media type does not support sending data concurrent with connection termination.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

ProtocolCmDropParty communicates with network control devices or other media-specific agents, as necessary for its media, to drop a party from an existing multipoint call. If the call manager is required to communicated with network control agents (e.g. a networking switch) it should use a virtual connection to the network control agents that it established in its ProtocolBindAdapter function.

If CloseData is non-NULL and sending data at connection termination is supported by its media type, the call manager should transmit the data specified at CloseData before completing termination. If sending data concurrent with connection termination is not supported by the media type, the call manager should return control with NDIS_STATUS_INVALID_DATA.

Call managers must also free any per-party resources that it allocated and stored at CallMgrPartyContext. In addition, the call manager must free the buffer stored CallMgrPartyContext itself. Failure to do so will result in a memory leak condition.

ProtocolCmDropParty must be written such that it can be run at IRQL DISPATCH_LEVEL.

See Also

NdisCmDropPartyComplete, ProtocolCmAddParty


ProtocolCmIncomingCallComplete

The ProtocolCmIncomingCallComplete function is required. When NDIS calls this function, ProtocolCmIncomingCallComplete indicates to the call manager that the connection-oriented client has finished processing of an incoming call offer that the call manager previously dispatched through NdisCmDispatchIncomingCall.

VOID
  ProtocolCmIncomingCallComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  CallMgrVcContext,
    IN PCO_CALL_PARAMETERS  CallParameters
    );

Parameters

Status
Indicates the final status of the operation to dispatch an incoming call to a connection-oriented client.
CallMgrVcContext
Specifies the handle to a call manager-allocated context area in which the call manager maintains its per-VC state. The call manager supplied this handle from its ProtocolCoCreateVc function.
CallParameters
Pointer to the call parameters as specified by the call manager in the call to NdisCmDispatchIncomingCall. The signaling protocol determines which call parameters, if any, the call manager can change.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

When the connection-oriented client has completed processing of an incoming connection offer that the call manager dispatched to it, this routine will be called if NdisCmDispatchIncomingCall returned NDIS_STATUS_PENDING. The final status of the incoming call is found in Status. Possible values for Status include, but are not limited to:

NDIS_STATUS_SUCCESS
Indicates that the call manager has accepted the incoming call.
NDIS_STATUS_FAILURE
Indicates that either the address family or the SAP that the call dispatched for is currently in the process of closing.
NDIS_STATUS_RESOURCES
Indicates that the incoming call was not accepted because the connection-oriented client was unable to dynamically allocate resources required for it to process the call.
NDIS_STATUS_INVALID_DATA
Indicates that the connection-oriented client rejected the call because the call parameters specified were invalid.

If the client accepts the incoming call, the call manager should send signaling message(s) to indicate to the calling entity that the call has been accepted. If the client does not accept the call, the call manager should send signaling message(s) to indicate that the call has been rejected.

ProtocolCmIncomingCallComplete must be written so that is can be run at IRQL DISPATCH_LEVEL.

See Also

NdisCmDispatchIncomingCall, ProtocolClIncomingCall, ProtocolCmRegisterSap


ProtocolCmModifyCallQoS

The ProtocolCmModifyCallQoS function is required. ProtocolCmModifyCallQoS is called by NDIS when a connection-oriented client requests that the call parameters be changed for an existing virtual connection (VC). If the underlying network medium does not support QoS, ProtocolCmModifyQoS should simply return NDIS_STATUS_NOT_SUPPORTED.

NDIS_STATUS
  ProtocolCmModifyCallQoS(
    IN NDIS_HANDLE  CallMgrVcContext,
    IN CO_CALL_PARAMETERS  CallParameters
    );

Parameters

CallMgrVcContext
Specifies the handle to a call manager-allocated context area in which the call manager maintains its per-VC state. The call manager supplied this handle to NDIS for its ProtocolCoCreateVc function.
CallParameters
Pointer to a CO_CALL_PARAMETERS structure that contains the new call parameters, as specified by a connection-oriented client, for the VC.

Return Value

ProtocolCmModifyQoS returns the status of its operation(s) as one of the following values:

NDIS_STATUS_SUCCESS
Indicates that the call manager successfully changed the parameters of the call with the network to the call parameters specified at CallParameters.
NDIS_STATUS_PENDING
Indicates that the call manager will complete the request to modify the call parameters asynchronously. When the call manager has completed all operations necessary to modify the call parameters, it must call NdisCmModifyCallQoSComplete.
NDIS_STATUS_RESOURCES
Indicates that the call manager could not change the call parameters of the VC because dynamically allocated resources were not available.
NDIS_STATUS_INVALID_DATA
Indicates that the call manager was unable to change the call parameters of the VC because the call parameters provided at CallParameters were illegal or invalid.
NDIS_STATUS_FAILURE
Indicates that the call parameters could not be set to the call parameters provided because of a failure in the network or in another connection-oriented network component.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

ProtocolCmModifyQoS communicates with network control devices or other media-specific agents, as necessitated by its media, to modify the media-specific call parameters for an established virtual connection. If the call manager is required to communicate with network control agents (in other words, a networking switch) it should use a virtual connection to the network control agents that it established in its ProtocolBindAdapter function. Stand-alone call managers communicated to the network agents by calling NdisCoSendPackets. Miniport drivers with integrated call-management support never call NdisCoSendPackets. Instead, such a driver simply transfers the data over the network to the target network agent.

After communicating with the network and if the changes were successful, the call manager must then call NdisCmActivateVc with the new call parameters. This notifies NDIS and/or the connection-oriented miniport driver that the call parameters have changed and provides the miniport driver with an opportunity to validate those parameters.

If either the network cannot accept the new call parameters or the underlying miniport driver cannot accept the parameters, the call manager must restore the virtual connection to the state that existed before any modifications were attempted, and return NDIS_STATUS_FAILURE.

ProtocolCmModifyQoSComplete must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

NdisCmActivateVc, NdisCmModifyCallQoSComplete, NdisCoSendPackets, ProtocolCoCreateVc


ProtocolCmOpenAf

The ProtocolCmOpenAf function is required. This function allocates per-open resources for a call manager to interact with a connection-oriented NDIS client that is opening the address family.

NDIS_STATUS
  ProtocolCmOpenAf(
    IN NDIS_HANDLE  CallMgrBindingContext,
    IN PCO_ADDRESS_FAMILY  AddressFamily,
    IN NDIS_HANDLE  NdisAfHandle,
    OUT PNDIS_HANDLE   CallMgrAfContext
    );

Parameters

CallMgrBindingContext
Specifies the handle to a call manager-allocated context area in which the call managers maintains its per-binding state information. The call manager supplied this handle when it called NdisOpenAdapter.
AddressFamily
Specifies the address family that a client is opening. This address family was registered by the call manager when it called NdisCmRegisterAddressFamily.
NdisAfHandle
Specifies a handle, supplied by NDIS, that uniquely identifies this address family instance. This handle is opaque to the call manager and reserved for system use.
CallMgrAfContext
Specifies the handle to a call manager-supplied context area in which the call manager maintains state about this open of an address family it provides.

Return Value

ProtocolCmOpenAf returns the status of its operation(s) as one of the following:

NDIS_STATUS_SUCCESS
Indicates that the call manager has successfully allocated and initialized any resources necessary to accept requests from the client to this address family.
NDIS_STATUS_PENDING
Indicates that the requested operation is being handled asynchronously. The call manager must call NdisCmOpenAddressFamilyComplete when it has completed all its open-AF operations to indicate to NDIS (and the client) that the operation(s) has been completed.
NDIS_STATUS_RESOURCES
Indicates that the call manager could not complete its necessary operation(s) because of a lack of available system resources, such as memory.
NDIS_STATUS_XXX
Indicates that the call manager could not set itself into a state where it can accept requests from the client to operate on this address family. This could be an error status propagated from another NDIS library function or any error status determined appropriate by the driver writer.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

ProtocolCmOpenAf performs any required allocations of dynamic resources and structures that the call manager writer deems necessary to perform operations on behalf of the client that is opening an instance of this address family. Such resources include, but are not limited to, memory buffers, data structures, events, and other such similar resources. A call manager should also initialize any relevant per-open data before returning control to NDIS.

When a call manager has allocated its per-open state area, the address of the state area should be set in the CallMgrAfContext handle before returning control to NDIS. To do this, dereference CallMgrAfContext and store a pointer to the data area as the value of the handle. For example:

*CallMgrAfContext = SomeBuffer;

If ProtocolCmOpenAf cannot allocate the per-open resources it needs to carry out subsequent requests on behalf of the client opening this address family, it should free all resources that it allocated for the open and return control to the NDIS with NDIS_STATUS_RESOURCES.

If ProtocolCmOpenAf has completed its required operations and the CM is ready to accept requests from the client, ProtocolCmOpenAf should return control as quickly as possible with a status of NDIS_STATUS_SUCCESS.

ProtocolCmOpenAf must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

NdisClOpenAddressFamily, NdisCmOpenAddressFamilyComplete, NdisCmRegisterAddressFamily, NdisOpenAdapter


ProtocolCmRegisterSap

The ProtocolCmRegisterSap function is a required function that is called by NDIS to request that a call manager register a SAP (service access point) on behalf of a connection-oriented client.

NDIS_STATUS
  ProtocolCmRegSap(
    IN NDIS_HANDLE  CallMgrAfContext,
    IN PCO_SAP  Sap,
    IN NDIS_HANDLE  NdisSapHandle,
    OUT PNDIS_HANDLE  CallMgrSapContext
    );

Parameters

CallMgrAfContext
Specifies the handle to a call-manager allocated context area in which the call manager maintains its per-open AF state. The call manager supplied this handle to NDIS from its ProtocolCmOpenAf function.
Sap
Pointer to a media-specific CO_SAP structure that contains the specific SAP that a connection-oriented client is registering.
NdisSapHandle
Specifies a handle, supplied by NDIS, that uniquely identifies this SAP. This handle is opaque to the call manager and reserved for NDIS library use.
CallMgrSapContext
On return, specifies the handle to a call manager-supplied context area in which the call manager maintains state about this SAP.

Return Value

ProtocolCmRegisterSap returns the status of its operation(s) as one of the following:

NDIS_STATUS_SUCCESS
Indicates that the call manager successfully allocated and/or initialized any necessary resources to register and maintain the SAP. In addition, it also indicates that the SAP was registered successfully as required by the network media that the call manager supports.
NDIS_STATUS_PENDING
Indicates that the call manager will complete the processing of this request asynchronously. Call managers must call NdisCmRegisterSapComplete when all processing has been completed to signal NDIS that the registration is finished.
NDIS_STATUS_RESOURCES
Indicates that the call manager was unable to allocated and/or initialize its resources required to register the SAP on behalf of the connection-oriented client.
NDIS_STATUS_INVALID_DATA
Indicates that the specification provided at Sap is invalid or cannot be supported.
NDIS_STATUS_XXX
Indicates that the call manager encountered an error in attempting to register the SAP for the connection-oriented client. The return code is appropriate to the error and could be a return code propagated from another NDIS library function.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

ProtocolCmMakeCall communicates with network control devices or other media-specific agents, as necessary, to register the SAP, as specified at Sap, on the network for a connection-oriented client. Such actions could include, but are not limited to communicating with switching hardware, communicating with a network control station, or other actions that are appropriate to the network medium.

If a call manager is required to communicate with networking control agents (in other words, a network switch) it should use a virtual connection to the network control agent that it established in its ProtocolBindAdapter function. Stand-alone call managers communicate through the underlying miniport driver by calling NdisCoSendPackets. Miniport drivers with integrated call-management support never call NdisCoSendPackets. Instead, they transmit the data directly across the network.

In addition, ProtocolCmRegisterSap should perform any necessary allocations of dynamic resources and structures that the call manager needs to maintain state information about the SAP on behalf of the connection-oriented client. Such resources include, but are not limited to, memory buffers, data structures, events, and other such similar resources. A call manager must also initialize any resources it allocates before returning control to NDIS. Call managers must store the NDIS-supplied handle identifying the SAP, provided at NdisSapHandle, in their context area for future use.

If ProtocolCmRegisterSap will return NDIS_STATUS_SUCCESS, it should, after allocating the per-SAP state area, set the address of this state area in CallMgrSapContext before returning control to NDIS. To do this, dereference CallMgrSapContext and store a pointer to the data area as the value of the handle. For example:

*CallMgrSapContext = SomeBuffer ;

If the given SAP that is already registered by another connection-oriented client, the call manager must fail the request and return NDIS_STATUS_INVALID_DATA.

After a call manager has registered a SAP on behalf of a connection-oriented client, it notifies that client of an incoming call offer directed to that SAP by calling NdisCmDispatchIncomingCall.

ProtocolCmRegisterSap must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

NdisCmDispatchIncomingCall, NdisCmRegisterSapComplete, NdisCoSendPackets, ProtocolCmDeregisterSap, ProtocolCmOpenAf


ProtocolCoAfRegisterNotify

The ProtocolCoAfRegisterNotify function is used by connection-oriented NDIS clients. All connection-oriented NDIS clients must have fully functional ProtocolCoAfRegisterNotify functions. Stand-alone connection-oriented call managers have registered ProtocolCoAfRegisterNotify functions that simply return control.

VOID
ProtocolCoAfRegisterNotify(
  IN NDIS_HANDLE  ProtocolBindingContext,
  IN PCO_ADDRESS_FAMILY  AddressFamily
  );

Parameters

ProtocolBindingContext
Specifies the handle to the client-allocated context area in which the client protocol maintains per-binding run-time state. The client's ProtocolBindAdapter function supplied this handle when it called NdisOpenAdapter.
AddressFamily
Pointer to a buffer describing the signalling-protocol support provided by a call manager that just registered these services with NDIS by calling NdisCmRegisterAddressFamily or NdisMCmRegisterAddressFamily.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A call to ProtocolCoAfRegisterNotify advertises a particular call manager's or MCM driver's call-management services on an underlying connection-oriented NIC to which the client is bound.

ProtocolCoAfRegisterNotify examines the data at AddressFamily to determine whether the client can use the services of this particular call manager. Whether the client can make modifications in the (M)CM-supplied data at AddressFamily depends on the particular signalling-protocol support of the call manager.

If the client finds the offered call-managment services unacceptable, ProtocolCoAfRegisterNotify returns control, and NDIS might call ProtocolCoAfRegisterNotify again with the same ProtocolBindingContext handle and an AF specification supplied by this or another call manager also bound to the same underlying NIC driver. Otherwise, ProtocolAfRegisterNotify allocates a per-AF context area for the client and calls NdisClOpenAddressFamily with the AddressFamily pointer. If this call succeeds, the client has registered its ProtocolCl Xxx functions with NDIS for subsequent connection-oriented operations using this call manager's services.

For example, ProtocolCoAfRegisterNotify or ProtocolClOpenAfComplete might call NdisInitializeNPagedLookasideList one or more times in preparation for dynamic allocations and releases of per-SAP, per-VC, and/or per-party context areas that the client will need subsequently.

If it accepts incoming calls, a client's ProtocolCoAfRegisterNotify or ProtocolClOpenAfComplete function usually registers one or more SAPs with the call manager. After opening that call manager's AF, the client might proceed to allocate a per-SAP state area and call NdisClRegisterSap one or more times with the NdisAfHandle it obtained from NdisClOpenAddressFamily. If it makes outgoing calls, the client might proceed to allocated a per-VC state area and create a VC with NdisCoCreateVc in anticipation of an incoming request from one of its own clients to make an outgoing call to a remote node.

ProtocolCoAfRegisterNotify runs at IRQL PASSIVE_LEVEL.

See Also

CO_ADDRESS_FAMILY, NdisClOpenAddressFamily, NdisClRegisterSap, NdisCmRegisterAddressFamily, NdisCoCreateVc, NdisInitializeNPagedLookasideList, NdisMCmRegisterAddressFamily, NdisOpenAdapter, ProtocolBindAdapter, ProtocolClOpenAfComplete


ProtocolCoCreateVc

The ProtocolCoCreateVc function is a required function that allocates resources necessary for a call manager or client to activate and maintain a virtual connection (VC).

NDIS_STATUS
  ProtocolCoCreateVc(
    IN NDIS_HANDLE  ProtocolAfContext,
    IN NDIS_HANDLE  NdisVcHandle,
    OUT PNDIS_HANDLE  ProtocolVcContext
    );

Parameters

ProtocolAfContext
Specifies the handle to a protocol-allocated context area in which the call manager or client maintains its per-open state. The call manager supplied this handle from its ProtocolCmOpenAf function. The client supplied this handle when it called NdisClOpenAddressFamily from its ProtocolCoAfRegister function.
NdisVcHandle
Specifies a handle, supplied by NDIS, that uniquely identifies this virtual connection. This handle is opaque to the protocol driver and reserved for NDIS library use. However, the call manager and client must save this handle to pass in subsequent calls to NdisCo/Cl/Cm/MCm Xxx functions that concern this VC.
ProtocolVcContext
Specifies the handle to a protocol-supplied context area in which the call manager or client maintains state about this virtual connection.

Return Value

ProtocolCoCreateVc returns the status of its operation(s) as one of the following values:

NDIS_STATUS_SUCCESS
Indicates that the call manager or client successfully allocated and/or initialized any necessary resources that were needed to establish and maintain a virtual connection.
NDIS_STATUS_RESOURCES
Indicates that the call manager or client was unable to allocate and/or initialize its resources for establishing and maintaining a virtual connection.
NDIS_STATUS_XXX
Indicates that the call manager or client could not set itself into a state where it could establish a virtual connection. This can could be an error return value propagated from another NDIS library routine.

Call managers or clients cannot return NDIS_STATUS_PENDING from their ProtocolCoCreateVc functions. Returning pending will render this virtual connection unusable and the NDIS library will call the client or call manager to delete it.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The ProtocolCoCreateVc function of a call manager or client is called whenever the corresponding client or call manager, respectively, calls NdisCoCreateVc. Clients initiate the creation of VCs in the process of setting up their outgoing calls before they call NdisClMakeCall. A call manager initiates the creation of a VC in the process of notifying its client that the CM received an incoming call offer from a remote node that is directed to a SAP already registered with the CM by that client before the CM calls NdisCmDispatchIncomingCall.

ProtocolCoCreateVc performs any necessary allocations of dynamic resources and structures that the call manager or client requires to perform subsequent operations on a VC that will be activated. Such resources include, but are not limited to, memory buffers, data structures, events, and other such similar resources. Call managers and clients should also initialize any relevant per-VC structures that they will need when a call is established.

Connection-oriented protocols must store the handle for the VC, specified in NdisVcHandle, in their per-VC state area to be used in future operations on this virtual connection. The NdisVcHandle is as required parameter to the NdisCo Xxx, NdisCm Xxx, and/or NdisCl Xxx that such a connection-oriented protocol subsequently calls.

When a call manager or client has allocated memory for its own per-VC data and initialized its state, the address of this data structure should be set in the handle before returning control to NDIS. To do this, dereference the handle and store a pointer to the protocol-allocated data area as the value of the handle. For example:

*ProtocolVcContext = SomeBuffer;

If ProtocolCoCreateVc cannot allocate the resource it needs to carry out subsequent network I/O operations, it should free all resources that were allocated for this VC and return control with a status of NDIS_STATUS_RESOURCES.

If ProtocolCoCreateVc has completed its required operations and has made the call manager or client ready to carry out call initialization for this virtual connection, ProtocolCoCreateVc should return control as quickly as possible with a status of NDIS_STATUS_SUCCESS.

Calls to ProtocolCoCreateVc are inherently synchronous in nature. That is, ProtocolCoCreateVc cannot return NDIS_STATUS_PENDING.

After a call manager's ProtocolCoCreateVc function returns control, the call manager's ProtocolCmMakeCall function will be called to establish a connection to a remote node. Call managers should not take any action in ProtocolCmMakeCall that actually establishes a call because it is possible the VC will be destroyed before a call is established due to an error condition in another component of connection-oriented NDIS.

After a client's ProtocolCoCreateVc function returns control, the client's ProtocolClIncomingCall function will be notified when a remote-initiated request to connect on a SAP previously registered by the client comes in over the network.

ProtocolCoCreateVc must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

NdisClMakeCall, NdisClOpenAddressFamily, NdisCmDispatchIncomingCall, ProtocolClIncomingCall, ProtocolCmMakeCall, ProtocolCmOpenAf, ProtocolCoAfRegisterNotify


ProtocolCoDeleteVc

The ProtocolCoDeleteVc function is required. This function tears down the client's or call manager's state for an established virtual connection that is being closed by the original creator of that VC.

NDIS_STATUS
  ProtocolCoDeleteVc(
    IN NDIS_HANDLE  ProtocolVcContext
    );

Parameter

ProtocolVcContext
Specifies the handle to the client's or call manager's per-VC context area. The protocol originally supplied this handle from its ProtocolCoCreateVc function.

Return Value

ProtocolCoDeleteVc can return one of the following:

NDIS_STATUS_SUCCESS
The protocol has released or prepared for reuse all the resources that it originally allocated for the VC.
NDIS_STATUS_NOT_ACCEPTED
The VC is still active and the protocol has outstanding operations pending on the VC so it could not be destroyed.
NDIS_STATUS_XXX
The protocol failed the VC deletion for a driver-determined reason.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

ProtocolCoDeleteVc is the reciprocal of the driver's ProtocolCoCreateVc function. In general, it releases any dynamic resources and structures that the call manager or client previously allocated to perform operations on the active VC.

When ProtocolCoDeleteVc returns control with NDIS_STATUS_SUCCESS, the NdisVcHandle that its ProtocolCoCreateVc function stored in the area at ProtocolVcContext becomes invalid.

ProtocolCoDeleteVc can return any driver-determined NDIS_STATUS_XXX to fail the deletion of the VC, but it cannot return NDIS_STATUS_PENDING. Calls to ProtocolCoDeleteVc are inherently synchronous in nature.

ProtocolCoDeleteVc must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

NdisClCloseCall, NdisCmDispatchIncomingCloseCall, NdisCoCreateVc, NdisCoDeleteVc, ProtocolCoCreateVc


ProtocolCoReceivePacket

The ProtocolCoReceivePacket function is required. This function processes receive indications made by underlying driver(s) that call NdisMCoIndicateReceivePacket.

UINT
  ProtocolCoReceivePacket(
    IN NDIS_HANDLE  ProtocolBindingContext,
    IN NDIS_HANDLE  ProtocolVcContext,
    IN PNDIS_PACKET  Packet
    );

Parameters

ProtocolBindingContext
Specifies the handle to a protocol-allocated context area in which the protocol driver maintains per-binding run-time state. The driver supplied this handle when it called NdisOpenAdapter.
ProtocolVcContext
Specifies the handle to a protocol-allocated context area in which this driver maintains per-VC run-time state. The client or stand-alone call manager supplied this handle either when it called NdisCoCreateVc or from its ProtocolCoCreateVc function.
Packet
Specifies a pointer to a packet descriptor for the received net packet. NDIS extracted this pointer from an array of packet descriptor pointers that an underlying driver passed to NdisMCoIndicateReceivePacket.

Return Value

ProtocolCoReceivePacket returns a driver-determined value that indicates to NDIS how many times this protocol must call NdisReturnPackets subsequently before NDIS can return the packet resources to the underlying driver that allocated these resources.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Any protocol driver that binds itself to an underlying connection-oriented NIC driver must have a ProtocolCoReceivePacket function. Such an underlying miniport driver always indicates full-packet receives.

ProtocolCoReceivePacket must call the NDIS_GET_PACKET_STATUS macro once for each packet descriptor in the array pointed to by Packet. NDIS_GET_PACKET_STATUS obtains the OOB block Status associated with the packet descriptor.

If the underlying NIC driver, before calling NdisMCoIndicateReceivePacket, set the OOB block Status to NDIS_STATUS_SUCCESS, the NIC driver temporarily relinquished ownership of the resources associated with the packet descriptor. In this case, the protocol (or the TDI clients of a highest level protocol) can hold on to all received data, to which it is given read-only access, specified at Packet if ProtocolCoReceivePacket returns a nonzero value. For a highest level protocol that forwards the input Packet descriptor pointer to some number of interested clients, each client retains read-only access to the indicated data until the client calls TdiReturnChainedReceives. A protocol driver retains ownership of the indicated packet until it calls NdisReturnPackets with Packet as many times as the reference count returned by ProtocolCoReceivePacket.

If ProtocolCoReceivePacket does not call NdisReturnPackets itself, the protocol must pass the input Packet pointer to NdisReturnPackets after ProtocolCoReceivePacket returns control. In this scenario, ProtocolCoReceivePacket should save the input Packet pointer in the ProtocolBindingContext area when it will return a nonzero value.

The NDIS library maintains the reference count for such an indicated packet, and the protocol retains ownership of the packet until it has called NdisReturnPackets with that packet as many times as the value returned by its ProtocolCoReceivePacket function.

ProtocolCoReceivePacket returns zero to relinquish ownership of the given Packet if the protocol has no current clients or bound higher level protocols interested in the indicated network packet or if the ProtocolCoReceivePacket function copies the data from the given packet and associated out-of-band block, if any, to protocol-allocated storage itself. When ProtocolCoReceivePacket returns zero, NDIS either calls another bound protocol with the receive indication or returns the given packet descriptor at Packet to the miniport driver that made the indication.

When an underlying NIC does run short of resources, it sets a packet descriptor's associated OOB block Status to NDIS_STATUS_RESOURCES. This forces ProtocolCoReceivePacket to copy the packet data immediately rather than retaining the NIC-driver-allocated packet resources. ProtocolCoReceivePacket must return zero in such a situation.

If an underlying miniport driver supplies additional out-of-band information for receives, ProtocolCoReceivePacket can retrieve the associated out-of-band information for the given Packet with the appropriate NDIS_GET_PACKET_XXX macro(s).

ProtocolCoReceivePacket must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

NdisAllocatePacket, NDIS_GET_PACKET_HEADER_SIZE, NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO, NDIS_GET_PACKET_TIME_RECEIVED, NDIS_GET_PACKET_TIME_SENT, NdisMIndicateReceivePacket, NDIS_PACKET, NDIS_PACKET_OOB_DATA, NdisReturnPackets, TdiReturnChainedReceives


ProtocolCoRequest

The ProtocolCoRequest function is required. This function handles OID_CO_XXX requests initiated by calls to NdisCoRequest from the corresponding client(s) or stand-alone call manager or initiated by an MCM driver's calls to NdisMCmRequest.

NDIS_STATUS
  ProtocolCoRequest(
    IN NDIS_HANDLE  ProtocolAfContext,
    IN NDIS_HANDLE  ProtocolVcContext  OPTIONAL,
    IN NDIS_HANDLE  ProtocolPartyContext  OPTIONAL,
    IN OUT  PNDIS_REQUEST  NdisRequest
    );

Parameters

ProtocolAfContext
Specifies the handle to the driver's per-AF context area. The client supplied this handle when it called NdisClOpenAddressFamily to connect itself to the call manager. The call manager supplied this handle from its ProtocolCmOpenAf function, so this handle effectively identifies the particular client that issued this request.
ProtocolVcContext
Specifies the handle identifying the active VC for which the client or call manager is requesting or setting information if the request is VC-specific. Otherwise, this parameter is NULL.
ProtocolPartyContext
Specifies the handle identifying the party on a multipoint VC for which the client or call manager is requesting or setting information if the request is party-specific. Otherwise, this parameter is NULL.
NdisRequest
Pointer to a buffer, formatted as an NDIS_REQUEST structure specifying the operation to be carried out by ProtocolCoRequest. The Oid member of the NDIS_REQUEST structure contains the system-defined OID_GEN_CO_XXX code specifying the requested query or set operation, together with a buffer in which the protocol returns the requested information for a query or from which it transfers the given information for a set.

Return Value

ProtocolCoRequest can return one of the following:

NDIS_STATUS_SUCCESS
The client or call manager carried out the requested operation.
NDIS_STATUS_PENDING
The client or call manager is handling this request asynchronously, and it will call NdisCoRequestComplete (or, from a miniport driver with integrated call-management support, NdisMCmRequestComplete) when the requested operation is done.
NDIS_STATUS_INVALID_LENGTH or NDIS_STATUS_BUFFER_TOO_SHORT
The driver is failing this request because the caller of NdisCoRequest or NdisMCmRequest did not supply an adequate InformationBuffer for the given request. The driver set the BytesNeeded member in the buffer at NdisRequest to the Oid-specific value of the InformationBufferLength required to carry out the requested operation.
NDIS_STATUS_XXX
The client or call manager failed the request for some driver-determined reason, such as invalid input data specified for a set.
NDIS_STATUS_NOT_SUPPORTED
The client or call manager failed this request because it did not recognize the OID_GEN_CO_XXX code in the Oid member in the buffer at NdisRequest.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Connection-oriented clients and stand-alone call managers communicate information to each other by specifying an explicit NdisAfHandle when they call NdisCoRequest. Similarly, a connection-oriented miniport driver with integrated call-management support calls NdisMCmRequest with explicit NdisAfHandles to communicate information to its individual clients. Such a call to NdisCoRequest or NdisMCmRequest with an explicit NdisAfHandle causes NDIS to call the ProtocolCoRequest function of the client, stand-alone call manager, or MCM driver that shares the given NdisAfHandle.

If the input NdisVcHandle and NdisPartyHandle are NULL, ProtocolCoRequest can consider the request global in nature. For example, ProtocolCoRequest satisfies any OID_GEN_CO_XXX query for which it is passed only an explicit NdisAfHandle by returning information about all currently active VCs, including any active multipoint VCs, on the given address family.

An explicit NdisVcHandle or NdisPartyHandle indicates that ProtocolCoRequest should satisfy the given request on a per-VC or per-party basis, respectively.

ProtocolCoRequest can assume that the buffer at NdisRequest was allocated from nonpaged pool and is, therefore, accessible at raised IRQL. The caller of NdisCoRequest (or NdisMCmRequest) is responsible for releasing this buffer and the internal buffer at InformationBuffer that it allocated when its request has been completed.

If ProtocolCoRequest returns NDIS_STATUS_PENDING, the driver must make a subsequent call to NdisCoRequestComplete or, for an MCM driver, to NdisMCmRequestComplete when the driver completes its operations to satisfy the given request.

For more information about the sets of OIDs defined for use with NdisCoRequest, NdisMCmRequest, and NdisRequest, see NDIS Object Identifiers.

ProtocolCoRequest must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

NdisClOpenAddressFamily, NdisCoRequest, NdisCoRequestComplete, NdisMCmRequest, NdisMCmRequestComplete, NdisRequest, NDIS_REQUEST, ProtocolCmOpenAf, ProtocolCoRequestComplete


ProtocolCoRequestComplete

The ProtocolCoRequestComplete function is required. This function postprocesses the results of a connection-oriented client's or stand-alone call manager's call to NdisCoRequest or of an MCM driver's call to NdisMCmRequest.

VOID
  ProtocolCoRequestComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  ProtocolAfContext  OPTIONAL,
    IN NDIS_HANDLE  ProtocolVcContext  OPTIONAL,
    IN NDIS_HANDLE  ProtocolPartyContext  OPTIONAL,
    IN OUT  PNDIS_REQUEST  NdisRequest
    );

Parameters

Status
Specifies the final status of the driver-initiated request, either NDIS_STATUS_SUCCESS or a failure NDIS_STATUS_XXX that was set by the corresponding client or call manager that handled this request. This parameter is never NDIS_STATUS_PENDING.
ProtocolAfContext
Specifies the handle to the driver's per-AF context area. The client supplied this handle when it called NdisClOpenAddressFamily to connect itself to the call manager. The call manager supplied this handle from its ProtocolCmOpenAf function, so this handle effectively identifies the particular client to which this request was directed.
ProtocolVcContext
Specifies the handle identifying the active VC for which the client or call manager was requesting or setting information if the request was VC-specific. Otherwise, this parameter is NULL.
ProtocolPartyContext
Specifies the handle identifying the party on a multipoint VC for which the client or call manager was requesting or setting information if the request is party-specific. Otherwise, this parameter is NULL.
NdisRequest
Pointer to the driver-allocated buffer, formatted as an NDIS_REQUEST structure that the driver passed in a preceding call to NdisCoRequest or NdisMCmRequest. The Oid member of the NDIS_REQUEST structure contains the system-defined OID_GEN_CO_XXX code specifying the requested query or set operation, together with a buffer in which the corresponding client or call manager returned the requested information for a query or from which it transferred the given information for a set if Status is NDIS_STATUS_SUCCESS.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

ProtocolCoRequestComplete can use the input Status as follows:

  • If this argument is NDIS_STATUS_SUCCESS, the BytesRead or BytesWritten member of the NDIS_REQUEST structure has been set to specify how much data was transferred into or from the buffer at InformationBuffer.

    If the given OID_GEN_CO_XXX was a query, ProtocolCoRequestComplete can use the data returned at InformationBuffer in any driver-determined way, depending on the value of the Oid member.

    ProtocolCoRequestComplete is responsible for releasing the driver-allocated buffers at NdisRequest and InformationBuffer when the driver completes its postprocessing of this request.

  • If this argument is NDIS_STATUS_INVALID_LENGTH or NDIS_STATUS_BUFFER_TOO_SHORT, the BytesNeeded member specifies the Oid-specific value of the InformationBufferLength required to carry out the requested operation.

    In these circumstances, ProtocolCoRequestComplete can allocate sufficient buffer space for the request, set up another NDIS_REQUEST structure with the required InformationBufferLength and the same Oid value, and retry the driver's call to NdisCoRequest or NdisMCmRequest.

  • If this argument is an NDIS_STATUS_XXX that indicates an unrecoverable error, ProtocolCoRequestComplete should release the buffer at NdisRequest and carry out any driver-determined operations that are necessary. For example, ProtocolCoRequestComplete might tear down the driver-created VC if a returned error status indicates that the driver cannot continue to make transfers on the virtual connection.

Even if a driver's call to NdisCoRequest or NdisMCmRequest returns something other than NDIS_STATUS_PENDING, that driver should use its ProtocolCoRequestComplete function to postprocess completed requests. Making an internal call to the driver's own ProtocolCoRequestComplete function on return from NdisCoRequest or NdisMCmRequest has almost no adverse effect on the driver's performance, makes the driver's image smaller, and makes the driver easier to maintain from one OS release to the next since such a driver has no duplicate code doing status-return checking on driver-initiated requests.

ProtocolCoRequestComplete must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

NdisCoRequest, NdisCoRequestComplete, NdisMCmRequest, NdisMCmRequestComplete, NDIS_REQUEST, ProtocolCoRequest


ProtocolCoSendComplete

The ProtocolCoSendComplete function is a required driver function in connection-oriented protocol drivers. ProtocolCoSendComplete completes the processing of a protocol-initiated send previously passed to NdisCoSendPackets.

VOID
  ProtocolCoSendComplete(
    IN NDIS_STATUS  Status,
    IN NDIS_HANDLE  ProtocolVcContext,
    IN PNDIS_PACKET  Packet
    );

Parameters

Status
Specifies the final status of the send operation, either NDIS_STATUS_SUCCESS or an error status propagated from the underlying driver.
ProtocolVcContext
Specifies the handle to a protocol-allocated context area in which the protocol driver maintains per-VC run-time state. The driver originally supplied this handle either when it called NdisCoCreateVc or from its ProtocolCoCreateVc function. This context area contains the NdisVcHandle that the driver previously passed to NdisCoSendPackets.
Packet
Pointer to the protocol-supplied packet descriptor for the completed send.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

ProtocolCoSendComplete performs whatever postprocessing is necessary for a completed transmit operation, such as notifying the client that originally requested the protocol to send data over the network on the VC.

Completion of a send operation usually implies that the underlying NIC driver actually has transmitted the given packet over the network. However, the driver of a so-called intelligent NIC can consider a send complete as soon as it downloads the net packet to its NIC. The underlying driver's call to NdisMCoSendComplete causes NDIS to call the ProtocolCoSendComplete function.

When ProtocolCoSendComplete is called, the driver regains ownership of the following protocol-allocated resources:

  • The packet descriptor at Packet
  • All buffer descriptors chained to the packet descriptor that map buffers containing the net packet data and any protocol-allocated buffers mapped by these descriptors
  • Any out-of-band block associated with the packet descriptor
  • Any protocol-allocated buffer specified in the out-of-band block at MediaSpecificInformation

Consequently, ProtocolCoSendComplete can either release these resources or prepare them for reuse in a subsequent call to NdisCoSendPackets. As a general rule, reusing such resources yields better performance than releasing them except, possibly, in periods of low network traffic if the protocol previously allocated a surplus of these resources to handle a period of heavy I/O demand.

To prepare the buffer and packet descriptors for reuse, ProtocolCoSendComplete should follow these guidelines:

  • Always call an NdisUnchainBufferAt Xxx function as many times as necessary to save the buffer descriptor pointers before ProtocolCoSendComplete calls NdisReinitializePacket with the descriptor at Packet.

    Otherwise, NdisReinitializePacket sets the head of the buffer chain to NULL so the protocol cannot recover pointers to the buffer descriptors chained to the packet descriptor. Either the protocol loses MDL(s) mapping client-supplied buffer(s) or it loses a set of buffer descriptors the protocol allocated with NdisAllocateBuffer.

  • Always pass the pointer returned by NDIS_OOB_DATA_FROM_PACKET to NdisZeroMemory to clear an associated out-of-band data block, never the Packet pointer.

    Otherwise, NdisZeroMemory destroys the packet descriptor the protocol allocated with NdisAllocatePacket, rendering it unusable for specifying subsequent sends.

    As an alternative to clearing the out-of-band block, the protocol can reinitialize only those members that the protocol normally sets up for sends with the appropriate NDIS_SET_PACKET_XXX macros.

Until ProtocolCoSendComplete is called, the current status of a protocol-initiated send is volatile. A protocol temporarily releases ownership of all resources it allocated for a send when it calls NdisCoSendPackets, even if the protocol supplies out-of-band information with the packet descriptors it allocates for sends. In particular, a protocol should never attempt to examine the Status member of the associated out-of-band data block when NdisCoSendPackets returns control.

Although NDIS always submits protocol-supplied packet arrays to the underlying miniport driver in the protocol-determined order passed in calls to NdisCoSendPackets, the underlying driver can complete the given packets in random order. That is, every bound protocol can rely on NDIS to submit the packets the protocol passes to NdisCoSendPackets in FIFO order to the underlying driver, but no protocol can rely on that underlying driver to call NdisMCoSendComplete with those packets in the same order.

ProtocolCoSendComplete must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

MiniportCoSendPackets, NdisAllocateBuffer, NdisAllocatePacket, NdisCoSendPackets, NdisFreeBuffer, NdisFreePacket, NdisMCoSendComplete, NDIS_OOB_DATA_FROM_PACKET, NDIS_PACKET_OOB_DATA, NdisReinitializePacket, NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO, NDIS_SET_PACKET_TIME_TO_SEND, NdisUnchainBufferAtBack, NdisUnchainBufferAtFront, NdisZeroMemory


ProtocolCoStatus

The ProtocolCoStatus function is required in connection-oriented protocol drivers that handles status-change notifications raised by an underlying driver or by NDIS.

VOID
  ProtocolCoStatus(
    IN NDIS_HANDLE  ProtocolBindingContext,
    IN NDIS_HANDLE  ProtocolVcContext  OPTIONAL,
    IN NDIS_STATUS  GeneralStatus,
    IN PVOID  StatusBuffer,
    IN UINT  StatusBufferSize
    );

Parameters

ProtocolBindingContext
Specifies the handle to a protocol-allocated context area in which the protocol driver maintains per-binding run-time state. The driver supplied this handle when it called NdisOpenAdapter.
ProtocolVcContext
Specifies the handle to a protocol-allocated context area in which the protocol driver maintains per-VC run-time state. This parameter is NULL when ProtocolCoStatus is called if the status-change indication is not VC-specific in nature. Otherwise, the protocol originally supplied this handle either when it called NdisCoCreateVc or from its ProtocolCoCreateVc function.
GeneralStatus
Indicates the general status code, either raised by NDIS or propagated from the underlying driver's call to NdisMCoIndicateStatus.
StatusBuffer
Pointer to a buffer containing medium-specific data that depends on the value of GeneralStatus.

For some NDIS_STATUS_XXX values, this pointer is NULL and StatusBufferSize is set to zero.

StatusBufferSize
Specifies the number of bytes at StatusBuffer.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A call to ProtocolCoStatus notifies the protocol about changes in status of an active VC, of the underlying connection-oriented NIC, or of its driver.

ProtocolCoStatus interprets two basic pieces of information:

  1. A general status code, defined by NDIS as an NDIS_STATUS_XXX value, indicating a change on the VC, on the NIC, or in the underlying driver.

    If NDIS has called the underlying driver's MiniportReset function in an attempt to restore the NIC to an operational state, NDIS can substitute NDIS_STATUS_RESET_START for the GeneralStatus indicated in the miniport driver's call to NdisMCoIndicateStatus.

  2. Depending on the status at GeneralStatus, additional information about the specific reason for the change in status, which can be medium-specific.

NDIS always notifies all bound protocols when an underlying connection-oriented driver is resetting its NIC by calling their ProtocolCoStatus functions, first with NDIS_STATUS_RESET_START and later, when the reset operation is done, with NDIS_STATUS_RESET_END. After each such call to a ProtocolCoStatus function, NDIS also calls the driver's ProtocolStatusComplete function.

Since NDIS will not accept protocol-initiated sends and requests to a miniport driver while a reset is in progress, the NDIS_STATUS_RESET_START notification warns bound protocols to hold off on their calls to NdisCoSendPackets and NdisCoRequest on the binding designated by the respective ProtocolBindingContext given to their ProtocolCoStatus functions until they receive the corresponding NDIS_STATUS_RESET_END notification.

If the protocol itself initiated the reset operation with a call to NdisReset, its ProtocolCoStatus function receives the NDIS_STATUS_RESET_START and NDIS_STATUS_RESET_END notifications like any other protocol bound to the same underlying driver. However, if NdisReset returns NDIS_STATUS_PENDING, only the ProtocolStatusComplete function of the driver that initiated the reset operation is called.

Consequently, every protocol's ProtocolCoStatus function should take whatever action is required to prevent that protocol from submitting sends and requests as soon as ProtocolCoStatus receives the NDIS_STATUS_RESET_START notification and should re-enable subsequent sends and requests when ProtocolCoStatus receives the NDIS_STATUS_RESET_END notification. Usually, ProtocolCoStatus simply sets and clears a ResetInProgress flag in the ProtocolBindingContext area that other driver functions check before they initiate sends or requests on the binding.

When the underlying NIC driver signals a status change, it does not change associated event counters and thresholds.

ProtocolCoStatus must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

MiniportReset, NdisCoCreateVc, NdisCoRequest, NdisMCoIndicateStatus, NdisRequest, NdisReset, NdisCoSendPackets, ProtocolCoCreateVc, ProtocolStatus, ProtocolStatusComplete


ProtocolOpenAdapterComplete

The ProtocolOpenAdapterComplete function is required. This function completes the processing of a binding operation for which NdisOpenAdapter returned NDIS_STATUS_PENDING.

VOID
  ProtocolOpenAdapterComplete(
    IN NDIS_HANDLE  ProtocolBindingContext,
    IN NDIS_STATUS  Status,
    IN NDIS_STATUS  OpenErrorStatus
    );

Parameters

ProtocolBindingContext
Specifies the handle to a protocol-allocated context area in which the protocol driver maintains per-binding run-time state. The driver supplied this handle when it called NdisOpenAdapter.
Status
Specifies the final status of the NIC driver open operation, either NDIS_STATUS_SUCCESS if the binding was established or an error status determined by the underlying driver.

The underlying NIC driver returns NDIS_STATUS_ADAPTER_NOT_READY for any requests it receives while the open operation is pending. After ProtocolOpenAdapterComplete returns control, the underlying driver cannot return this status.

OpenErrorStatus
Specifies additional information about the reason for a failure if the value at Status is not NDIS_STATUS_SUCCESS and if the underlying driver supplied this information. For example, the driver of a Token Ring NIC might return a ring error that NDIS forwards to ProtocolOpenAdapterComplete. This parameter can be NULL.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

When NdisOpenAdapter returns NDIS_STATUS_PENDING to the ProtocolBindAdapter function of an NDIS protocol driver, NDIS calls that driver's ProtocolOpenAdapterComplete function when the asynchronous binding operation is complete.

If the input Status is NDIS_STATUS_SUCCESS, ProtocolOpenAdapterComplete carries out whatever driver-determined per-binding operations its ProtocolBindAdapter function would have done in a synchronous binding operation. Next, ProtocolOpenAdapterComplete calls NdisCompleteBindAdapter with NDIS_STATUS_SUCCESS for the Status and OpenStatus arguments and with the BindContext handle stored at ProtocolBindingContext by the ProtocolBindAdapter function. Then, ProtocolOpenAdapterComplete returns control.

Otherwise, ProtocolOpenAdapterComplete cleans up any per-binding state already set up by ProtocolBindAdapter. After releasing any state set up by ProtocolBindAdapter except for the BindContext handle, it calls NdisCompleteBindAdapter with an appropriate error for Status and the handle before it returns control.

ProtocolOpenAdapterComplete runs at IRQL PASSIVE_LEVEL.

See Also

DriverEntry of NDIS Protocol Drivers, NdisCompleteBindAdapter, NdisFreeMemory, NdisOpenAdapter, ProtocolBindAdapter


ProtocolPnPEvent

The ProtocolPnPEvent function is required in protocol drivers to support Plug and Play and/or Power Management. NDIS calls ProtocolPnPEvent to indicate a Plug and Play event or a Power Management event to a protocol bound to a NIC.

NDIS_STATUS
  ProtocolPnPEvent(
    IN NDIS_HANDLE  ProtocolBindingContext,
    IN PNET_PNP_EVENT  NetPnPEvent
    );

Parameters

ProtocolBindingContext
Specifies the handle to a protocol-allocated context area in which this driver maintains per-binding run-time state. The protocol supplied this handle when it called NdisOpenAdapter. A NetEvent Xxx indicated on a NULL ProtocolBindingContext pertains to all network bindings. NetEventBindList and NetEventBindsComplete are always indicated on a NULL ProtocolBindingContext. NetEventReconfigure can be indicated on a particular ProtocolBindingContext or a NULL ProtocolBindingContext.
NetPnPEvent
Pointer to a NET_PNP_EVENT structure, which describes the Plug and Play event or Power Management event being indicated to the protocol driver.

Return Value

ProtocolPnPEvent can return any of the following:

NDIS_STATUS_SUCCESS
The protocol successfully handled the indicated Plug and Play or Power Management event. The meaning of this status code depends on the NetEvent code in the buffered NET_PNP_EVENT structure at NetPnPEvent:
NetEventSetPower
The device has transitioned to the requested power device power state.
NetEventQueryPower
The device can transition to the requested device power state.
NetEventQueryRemoveDevice
The device can be removed.
NetEventCancelRemoveDevice
The removal of the device has been canceled.
NetEventReconfigure
The protocol has accepted the changed configuration parameter(s).
NetEventBindList
The protocol has conveyed the new binding list to all bound TDI clients that have registered a ClientBinding handler with the protocol.
NetEventBindsComplete
The protocol has acknowledged the indication from NDIS that the protocol has bound to all available NICs.
NetEventPnPCapabilities
The protocol has acknowledged that the wake-up capabilities of the NIC on the specified binding have changed.
NDIS_STATUS_PENDING
The protocol will return its response to the indicated event asynchronously with a call to NdisCompletePnPEvent.
NDIS_STATUS_RESOURCES
The protocol could not obtain the necessary system resources to satisfy the indicated Plug and Play or Power Management event.
NDIS_STATUS_NOT_SUPPORTED
A legacy (non-PnP-aware) protocol can return this status in response to a NetEventSetPower to indicate that NDIS should unbind it from the NIC.
NDIS_STATUS_FAILURE
The protocol failed the indicated Plug and Play or Power Management event. The meaning of this status code depends on the NetEvent code in the buffered NET_PNP_EVENT structure at NetPnPEvent:
NetEventSetPower
The protocol should not fail this event.
NetEventQueryPower
The protocol should not fail this event.
NetEventQueryRemoveDevice
The protocol could not release the device.
NetEventCancelRemoveDevice
The protocol should not fail this event.
NetEventReconfigure
The protocol should not fail this event.
NetEventBindList
The protocol should not fail this event.
NetEventBindsComplete
The protocol should not fail this event
NetEventPnPCapabilities
The protocol should not fail this event

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NDIS calls ProtocolPnPEvent to notify a protocol bound to a network NIC that the operating system has issued a Plug and Play or Power Management event to the device object representing the NIC. NDIS calls the ProtocolPnPEvent function of each protocol bound to the NIC.

The NET_PNP_EVENT structure passed to ProtocolPnPEvent describes the Plug and Play or Power Management event. ProtocolPnPEvent interprets two basic pieces of information in the NET_PNP_EVENT structure:

  • A NetEvent code that describes the Plug and Play or Power Management event.
  • Event-specific information (for example, for a NetEventSetPower, the device power state to which the device is transitioning).

The protocol should save the NetPnPEvent pointer. This pointer is a required input parameter to NdisCompletePnPEvent, which the protocol must subsequently call if ProtocolPnPEvent returns NDIS_STATUS_PENDING.

A protocol should always succeed a NetEventQueryPower. After establishing an active connection, a protocol can call PoRegisterSystemState to register a continuously busy state. As long as the state registration is in effect, the Power Manager does not attempt to put the system to sleep. After the connection becomes inactive, the protocol cancels the state registration by calling PoUnregisterSystemState. A protocol should never try to prevent the system from transitioning to the sleeping state by failing a NetEventQueryRemoveDevice. Note that a NetEventQueryPower is always followed by a NetEventSetPower. A NetEventSetPower to the device's current power state in effect cancels the NetEventQueryPower.

If a protocol cannot release a device (for example, because the device is in use) it must fail a NetEventQueryRemoveDevice by returning NDIS_STATUS_FAILURE.

A protocol should always succeed a NetEventCancelRemoveDevice, a NetEventReconfigure, NetEventBindList¸ NetEventBindsComplete, or NetEventPnPCapabilities by returning NDIS_STATUS_SUCCESS.

A PnP-aware protocol must always succeed a NetEventSetPower. A legacy protocol that does not support power management returns NDIS_STATUS_NOT_SUPPORTED in response to a NetEventSetPower to indicate that NDIS should unbind the protocol from the NIC.

A protocol can return NDIS_STATUS_RESOURCES for any Plug and Play or Power Management event.

ProtocolPnPEvent runs at IRQL PASSIVE_LEVEL.

See Also

NET_PNP_EVENT for Protocol Drivers, NdisCompletePnPEvent


ProtocolReceive

The ProtocolReceive function is a required driver function in NDIS protocols that bind themselves to connectionless NIC drivers. ProtocolReceive determines whether a received network packet is of interest to the protocol's client(s) and, if so, copies the indicated data and, possibly, calls NdisTransferData to retrieve the rest of the indicated packet.

NDIS_STATUS
  ProtocolReceive(
    IN NDIS_HANDLE  ProtocolBindingContext,
    IN NDIS_HANDLE  MacReceiveContext,
    IN PVOID  HeaderBuffer,
    IN UINT  HeaderBufferSize,
    IN PVOID  LookAheadBuffer,
    IN UINT  LookaheadBufferSize,
    IN UINT  PacketSize
    );

Parameters

ProtocolBindingContext
Specifies the handle to a protocol-allocated context area in which the protocol driver maintains per-binding run-time state. The driver supplied this handle when it called NdisOpenAdapter.
MacReceiveContext
Specifies a context handle that the underlying NIC driver associates with the packet received from the network. This handle is opaque to the protocol, reserved for use by the underlying driver that made the indication, and a required parameter to NdisTransferData.
HeaderBuffer
Pointer to the base virtual address of a range containing the buffered packet header. The address is valid only within the current call to ProtocolReceive.
HeaderBufferSize
Specifies the number of bytes in the packet header.
LookAheadBuffer
Pointer to the base virtual address of a range that contains LookaheadBufferSize bytes of buffered network packet data. This address is valid only within the current call to ProtocolReceive.
LookaheadBufferSize
Specifies the number of bytes of network packet data in the lookahead buffer.

The indicating driver ensures this number is at least as large as the size it returned for the protocol's preceding call to NdisRequest with OID_GEN_CURRENT_LOOKAHEAD or the size of the packet, whichever is less.

If PacketSize is less than or equal to the given LookaheadBufferSize, the lookahead buffer contains the entire packet.

PacketSize
Specifies the size, in bytes, of the network packet data. The length of the packet does not include the length of the header.

ProtocolReceive determines whether the protocol must call NdisTransferData by comparing this parameter to the given LookaheadBufferSize.

Return Value

ProtocolReceive can return either of the following:

NDIS_STATUS_NOT_ACCEPTED
The protocol has no use for the indicated packet, that is, it has no current clients interested in the indicated network data.

Returning this status quickly for rejected packets yields higher performance for the protocol and the highest possible network I/O throughput for the system as a whole.

NDIS_STATUS_SUCCESS
ProtocolReceive has processed the header information and accepted the packet, that is, it has copied the indicated network data from the header and lookahead buffers and, possibly, called NdisTransferData to retrieve the remaining data if less than a full network packet was indicated.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

NDIS provides equal packet access for any number of protocol drivers bound above an underlying connectionless miniport driver. NDIS can use the status that ProtocolReceive returns to optimize the order in which bound protocols receive indications for subsequent packets.

When a miniport driver calls a filter-specific NdisM..IndicateReceive function, NDIS calls the ProtocolReceive functions of bound protocols. A call to an NdisM..IndicateReceive function indicates that a network packet, or some initial lookahead portion of it, is available for inspection by bound protocols. Each ProtocolReceive function, in turn, inspects the packet header and data, optionally copies as much of the header and/or data as is made available, and calls NdisTransferData to instruct the NIC driver to copy any remaining data into a protocol-supplied buffer chained to a protocol-allocated packet descriptor if the protocol accepts the packet. ProtocolReceive can call NdisTransferData only once per receive indication.

Before a serialized miniport driver calls NdisMIndicateReceivePacket with a packet array, it can set the Status member of an out-of-band block associated with a packet descriptor in the array to NDIS_STATUS_RESOURCES. This also causes NDIS to call the ProtocolReceive functions of bound protocols with the network packet header and data specified by that packet descriptor and, separately, with the received network packets specified in all subsequent descriptors in the indicated packet array. Each ProtocolReceive function, in turn, inspects the given network packet header and data and each optionally copies the indicated network packet data.

If the underlying miniport driver supplies out-of-band information with the receives it indicates, ProtocolReceive can call NdisGetReceivedPacket or NDIS_GET_ORIGINAL_PACKET to retrieve the out-of-band information for each such packet. Because such an underlying miniport driver always indicates full-packet receives, ProtocolReceive will never call NdisTransferData for a packet indicated with NdisMIndicateReceivePacket.

NDIS calls ProtocolReceive functions sequentially as calls to NdisM..IndicateReceive or NdisMIndicateReceivePacket occur, but it can indicate a packet to bound protocols using separate calls. However, every protocol must be able to handle out-of-order received packets since neither NDIS nor the underlying miniport driver has any control over the network over which packets are transmitted.

A driver writer should minimize the amount of time spent in the ProtocolReceive function so that the protocol does not lose additional incoming packets, particularly from underlying drivers that call the filter-specific NdisM...IndicateReceive functions. ProtocolReceive must either reject an incoming packet or recognize the packet as of interest to its client(s) quickly. If it accepts the packet, ProtocolReceive must find a place to put packet data and copy the data quickly. Shortly after ProtocolReceive returns, when time constraints are not so severe, any underlying miniport driver that made one or more indications with NdisM...IndicateReceive will call the corresponding NdisM..IndicateReceiveComplete. The protocol driver's ProtocolReceiveComplete function then performs any necessary postprocessing for the original indication(s).

The underlying driver does not remove any headers or trailers from the packet data received on its NIC, nor does it remove any received padding. In other words, a packet can include padding in the data and length indicated to protocols. ProtocolReceive is responsible for detecting and ignoring such padding.

The buffers at HeaderBuffer and LookAheadBuffer passed to ProtocolReceive are read-only and valid only until ProtocolReceive returns control. ProtocolReceive must copy all the indicated data that the driver needs into protocol-allocated storage. Whether a Windows® 2000 or later protocol can copy the indication directly depends on the NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA flag returned for the OID_GEN_MAC_OPTIONS query. If this flag was set, ProtocolReceive can use NdisMoveMemory to copy the indicated data to its own storage; otherwise, it should use TdiCopyLookaheadData. However, a Windows® 2000 or later protocol can call TdiCopyLookaheadData even if the underlying driver set the NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA flag.

On a multiprocessor system, this function may execute concurrently on more than one processor. Apply protection (for example, use spinlocks) to critical data structures accessed by this function.

ProtocolReceive runs at IRQL DISPATCH_LEVEL.

See Also

MiniportTransferData, NdisAllocatePacket, NdisGetFirstBufferFromPacket, NdisGetFirstBufferFromPacketSafe, NDIS_GET_ORIGINAL_PACKET, NdisGetReceivedPacket, NdisMArcIndicateReceive, NdisMEthIndicateReceive, NdisMFddiIndicateReceive, NdisMIndicateReceivePacket, NdisMoveMemory, NdisMTrIndicateReceive, NdisMWanIndicateReceive, ProtocolReceiveComplete, ProtocolReceivePacket, ProtocolTransferDataComplete, TdiCopyLookaheadData


ProtocolReceiveComplete

The ProtocolReceiveComplete function is a required driver function in any protocol. ProtocolReceiveComplete completes postprocessing of one or more preceding receive indications from a NIC driver.

VOID
  ProtocolReceiveComplete(
    IN NDIS_HANDLE  ProtocolBindingContext
    );

Parameters

ProtocolBindingContext
Specifies the handle to a protocol-allocated context area in which the protocol driver maintains per-binding run-time state. The driver supplied this handle when it called NdisOpenAdapter.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

ProtocolReceiveComplete performs postprocessing, such as notifying interested clients of processed data received from a remote node, after one or more calls to the driver's ProtocolReceive function.

When an underlying miniport driver calls NdisM...IndicateReceiveComplete, NDIS calls the ProtocolReceiveComplete function(s) of bound protocol(s). NDIS always calls ProtocolReceiveComplete after one or more calls to the driver's ProtocolReceive function, regardless of whether any particular packet(s) are accepted by bound protocols.

An underlying miniport driver need not make calls to NdisM..IndicateReceive in one-to-one correspondence with its calls to NdisM...IndicateReceiveComplete. ProtocolReceiveComplete is re-entrant because the underlying NIC driver sometimes must wait to call NdisM...IndicateReceiveComplete until no receive operations are in progress.

After ProtocolReceiveComplete is called, the underlying NIC driver can make another receive indication before ProtocolReceiveComplete returns control, so ProtocolReceiveComplete can execute concurrently with the driver's ProtocolReceive function in SMP machines.

ProtocolReceiveComplete runs at IRQL PASSIVE_LEVEL.

See Also

NdisMArcIndicateReceiveComplete, NdisMEthIndicateReceiveComplete, NdisMFddiIndicateReceiveComplete, NdisMCoIndicateReceivePacket, NdisMIndicateReceivePacket, NdisMTrIndicateReceiveComplete, NdisMWanIndicateReceiveComplete, ProtocolCoReceivePacket, ProtocolReceive, ProtocolReceivePacket


ProtocolReceivePacket

The ProtocolReceivePacket function is an optional driver function. ProtocolReceivePacket processes receive indications made by underlying connectionless NIC driver(s) that call NdisMIndicateReceivePacket either with packet arrays because the underlying driver supports multipacket receive indications or with individual packets that have associated out-of-band information. A call to ProtocolReceivePacket can also occur as a result of loopback.

Protocols that bind themselves exclusively to underlying connection-oriented miniport drivers must have a fully functional ProtocolCoReceivePacket function, rather than a ProtocolReceivePacket function.

INT
  ProtocolReceivePacket(
    IN NDIS_HANDLE  ProtocolBindingContext,
    IN PNDIS_PACKET  Packet
    );

Parameters

ProtocolBindingContext
Specifies the handle to a protocol-allocated context area in which the protocol driver maintains per-binding run-time state. The driver supplied this handle when it called NdisOpenAdapter.
Packet
Specifies a pointer to a packet descriptor for the received net packet. NDIS extracted this pointer from an array of packet descriptor pointers that an underlying driver passed to NdisMIndicateReceivePacket.

Return Value

ProtocolReceivePacket returns a driver-determined value that tells NDIS how many times the protocol will subsequently call NdisReturnPackets with the given packet, or zero if the protocol is done with or not interested in this packet.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

Any protocol driver that might bind itself to an underlying connectionless NIC driver that supports multipacket receive indications should have a ProtocolReceivePacket function. Such an underlying driver always indicates full-packet receives.

A protocol can achieve better performance if it has a ProtocolReceivePacket function. Such a protocol (or the TDI clients of a highest level Windows 2000 or later protocol) can hold on to all received data, to which it is given read-only access, specified at Packet if ProtocolReceivePacket returns a nonzero value. For a highest level Windows 2000 or later protocol driver, the return value for such an input Packet descriptor pointer can be a reference count of clients the protocol has notified about the received net packet by forwarding the input Packet descriptor. For an intermediate NDIS driver, the return value can be a count of higher level protocols to which it has made a corresponding indication or one if the driver tracks the number of higher level protocols to which it forwards the processed indication. For a highest level Windows 2000 or later protocol that forwards the input Packet descriptor pointer to some number of interested clients, each client retains read-only access to the indicated data until the client calls TdiReturnChainedReceives. An intermediate NDIS driver retains ownership of the indicated packet until it calls NdisReturnPackets with Packet as many times as the reference count returned by ProtocolReceivePacket.

If ProtocolReceivePacket does not call NdisReturnPackets itself, the protocol must pass the input Packet pointer to NdisReturnPackets after ProtocolReceivePacket returns control. In this scenario, ProtocolReceivePacket should save the input Packet pointer in the ProtocolBindingContext area when it will return a nonzero value.

The NDIS library maintains the reference count for such an indicated packet, and the protocol retains ownership of the packet until it has called NdisReturnPackets with that packet as many times as the value returned by its ProtocolReceivePacket function.

ProtocolReceivePacket returns zero to relinquish ownership of the given Packet if the protocol has no current clients or bound higher level protocols interested in the indicated network packet or if the ProtocolReceivePacket function copies the data from the given packet and associated out-of-band block, if any, to protocol-allocated storage itself. When ProtocolReceivePacket returns zero, NDIS either calls another bound protocol with the receive indication or returns the given packet descriptor at Packet to the miniport driver that made the indication.

Any protocol that binds itself to an underlying connectionless NIC driver that supplies out-of-band information for receives must have a ProtocolReceivePacket function to interpret the miniport driver-supplied out-of-band information when processing receive indications. Such a protocol can retrieve the associated out-of-band information for the given Packet with the appropriate NDIS_GET_PACKET_XXX macro(s).

If an incoming packet descriptor has NDIS_STATUS_RESOURCES set for the Status in the associated OOB block, the protocol must not retain the packet descriptor and associated miniport driver-allocated resources. Instead, the ProtocolReceivePacket should copy the received data into protocol-allocated storage and return zero to NDIS as quickly as possible. Such a Status in the OOB block for a miniport driver-allocated packet descriptor indicates that the miniport driver is running low on receive resources.

On a multiprocessor system, this function may execute concurrently on more than one processor. Apply protection (for example, use spinlocks) to critical data structures accessed by this function.

ProtocolReceivePacket runs at IRQL DISPATCH_LEVEL.

See Also

NdisAllocatePacket, NDIS_GET_PACKET_HEADER_SIZE, NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO, NDIS_GET_PACKET_TIME_RECEIVED, NDIS_GET_PACKET_TIME_SENT, NdisMIndicateReceivePacket, NDIS_PACKET, NDIS_PACKET_OOB_DATA, NdisReturnPackets, ProtocolCoReceivePacket, ProtocolReceive, TdiReturnChainedReceives


ProtocolRequestComplete

The ProtocolRequestComplete function is a required driver function. This function completes the processing of a protocol-initiated query or set for which NdisRequest returned NDIS_STATUS_PENDING.

A connection-oriented protocol that calls NdisCoRequest but never NdisRequest must have a fully functional ProtocolCoRequestComplete function, rather than a ProtocolRequestComplete function.

VOID
  ProtocolRequestComplete(
    IN NDIS_HANDLE  ProtocolBindingContext,
    IN PNDIS_REQUEST  NdisRequest,
    IN NDIS_STATUS  Status
    );

Parameters

ProtocolBindingContext
Specifies the handle to a protocol-allocated context area in which the protocol driver maintains per-binding run-time state. The driver supplied this handle when it called NdisOpenAdapter.
NdisRequest
Pointer to the protocol-supplied structure previously passed to NdisRequest.
Status
Specifies the final status of the request set by the underlying driver or by NDIS. This argument determines what ProtocolRequestComplete does with the information at NdisRequest.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

ProtocolRequestComplete uses the input Status as follows:

  • If this argument is NDIS_STATUS_SUCCESS, the BytesRead or BytesWritten member of the NDIS_REQUEST structure has been set by NDIS or the underlying driver to specify how much protocol-supplied information was transferred from the buffer at InformationBuffer to the NIC in a set operation or how much information was returned at InformationBuffer in response to a query operation.

    If the protocol made a query, ProtocolRequestComplete can use the data returned at InformationBuffer in any protocol-determined way, depending on the value of the Oid member.

    For example, if the protocol originally initiated an OID_GEN_MAXIMUM_SEND_PACKETS query, ProtocolRequestComplete might set up state variables in the ProtocolBindingContext area to throttle the number of outstanding sends the driver will set up for subsequent calls to NdisSendPackets.

  • If this argument is NDIS_STATUS_INVALID_LENGTH or NDIS_STATUS_BUFFER_TOO_SHORT, the BytesNeeded member specifies the Oid-specific value of the InformationBufferLength member required to carry out the requested operation.

    In these circumstances, ProtocolRequestComplete can allocate sufficient buffer space for the request, set up another NDIS_REQUEST structure with the required InformationBufferLength and same Oid, and retry the call to NdisRequest.

    ProtocolRequestComplete can retry requests for certain other NDIS_STATUS_XXX arguments, as well, as described in the reference for NdisRequest.

  • If this argument is an NDIS_STATUS_XXX that is an unrecoverable error, ProtocolRequestComplete should release the memory allocated for the NDIS_REQUEST structure and determine whether the driver should call NdisReset, close the binding, or adjust its binding-specific state information to handle continued network I/O operations on the binding.

For global queries and sets, the underlying connectionless miniport driver's call to NdisMQueryInformationComplete or NdisMSetInformationComplete causes NDIS to call the ProtocolRequestComplete function. NDIS forwards the miniport driver-determined Status passed to NdisM..InformationComplete as the input Status to ProtocolRequestComplete.

For binding-specific queries, NDIS calls the ProtocolRequestComplete function itself. Because the NDIS library maintains bindings for all miniport drivers, NDIS can return binding-specific information only about underlying drivers that report their medium-type as one for which the system provides a filter library. NDIS returns NDIS_STATUS_NOT_SUPPORTED for protocol-initiated binding-specific queries to other miniport drivers.

For more information about system-defined OIDs, see NDIS Object Identifiers.

ProtocolRequestComplete can be called before the protocol has had time to inspect the status code that NdisRequest returns at Status.

ProtocolRequestComplete runs at IRQL DISPATCH_LEVEL.

See Also

MiniportQueryInformation, MiniportSetInformation, NdisCoRequest, NdisMQueryInformationComplete, NdisMSetInformationComplete, NDIS_REQUEST, NdisRequest, NdisReset, ProtocolCoRequestComplete


ProtocolResetComplete

The ProtocolResetComplete function is a required driver function. ProtocolResetComplete completes a protocol-initiated reset operation for which NdisReset returned NDIS_STATUS_PENDING.

VOID
  ProtocolResetComplete(
    IN NDIS_HANDLE  ProtocolBindingContext,
    IN NDIS_STATUS  Status
    );

Parameters

ProtocolBindingContext
Specifies the handle to a protocol-allocated context area in which the protocol driver maintains per-binding run-time state. The driver supplied this handle when it called NdisOpenAdapter.
Status
Specifies the final status of the protocol-initiated reset operation.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

ProtocolResetComplete completes processing for an asynchronous reset of the underlying driver's NIC or virtual NIC.

The underlying miniport driver's call to NdisMResetComplete causes NDIS to call the ProtocolResetComplete function. NDIS forwards the miniport driver-determined Status passed to NdisMResetComplete as the input Status to ProtocolStatusComplete.

ProtocolResetComplete can be called before the protocol has had time to inspect the status code that NdisReset returns at Status.

ProtocolResetComplete runs at IRQL DISPATCH_LEVEL.

See Also

MiniportReset, NdisMResetComplete, NdisReset, ProtocolStatus, ProtocolStatusComplete


ProtocolSendComplete

The ProtocolSendComplete function is a required driver function. This function completes the processing of a protocol-initiated send previously passed to NdisSendPackets or NdisSend, which returned NDIS_STATUS_PENDING.

VOID
  ProtocolSendComplete(
    IN NDIS_HANDLE  ProtocolBindingContext,
    IN PNDIS_PACKET  Packet,
    IN NDIS_STATUS Status
    );

A connection-oriented protocol that calls NdisCoSendPackets but never NdisSendPackets (nor NdisSend) must have a fully functional ProtocolCoSendComplete function, rather than a ProtocolSendComplete function.

Parameters

ProtocolBindingContext
Specifies the handle to a protocol-allocated context area in which the protocol driver maintains per-binding run-time state. The driver supplied this handle when it called NdisOpenAdapter.
Packet
Pointer to the protocol-supplied packet descriptor for the completed send.
Status
Specifies the final status of the send operation.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

ProtocolSendComplete performs whatever postprocessing is necessary for a completed transmit operation, such as notifying the client that originally requested the protocol to send data over the network.

Completion of a send operation usually implies that the underlying NIC driver actually has transmitted the given packet over the network. However, the driver of a so-called intelligent NIC can consider a send complete as soon as it downloads the net packet to its NIC. The underlying driver's call to NdisMSendComplete or NdisMWanSendComplete causes NDIS to call the ProtocolSendComplete function.

When ProtocolSendComplete is called, the driver regains ownership of the following protocol-allocated resources:

  • The packet descriptor at Packet
  • All buffer descriptors chained to the packet descriptor that map buffers containing the net packet data and any protocol-allocated buffers mapped by these descriptors
  • Any out-of-band block associated with the packet descriptor
  • Any protocol-allocated buffer specified in the out-of-band block at MediaSpecificInformation

Consequently, ProtocolSendComplete can either release these resources or prepare them for reuse in a subsequent call to NdisSendPackets or NdisSend. As a general rule, reusing such resources yields better performance than releasing them except, possibly, in periods of low network traffic if the protocol previously allocated a surplus of these resources to handle a period of heavy I/O demand.

To prepare the buffer and packet descriptors for reuse, ProtocolSendComplete should follow these guidelines:

  • Always call an NdisUnchainBufferAt Xxx function as many times as necessary to save the buffer descriptor pointers before ProtocolSendComplete calls NdisReinitializePacket with the descriptor at Packet.

    Otherwise, NdisReinitializePacket sets the head of the buffer chain to NULL so the protocol cannot recover pointers to the buffer descriptors chained to the packet descriptor. Either the protocol loses MDL(s) mapping client-supplied buffer(s) or it loses a set of buffer descriptors the protocol allocated with NdisAllocateBuffer.

  • Always pass the pointer returned by NDIS_OOB_DATA_FROM_PACKET to NdisZeroMemory to clear an associated out-of-band data block, never the Packet pointer.

    Otherwise, NdisZeroMemory destroys the packet descriptor the protocol allocated with NdisAllocatePacket, rendering it unusable for specifying subsequent sends.

    As an alternative to clearing the out-of-band block, the protocol can reinitialize only those members that the protocol normally sets up for sends with the appropriate NDIS_SET_PACKET_XXX macros.

Until ProtocolSendComplete is called, the current status of a protocol-initiated send is volatile. A protocol temporarily releases ownership of all resources it allocated for a send when it calls NdisSendPackets or NdisSend, even if the protocol supplies out-of-band information with the packet descriptors it allocates for sends. In particular, a protocol should never attempt to examine the Status member of the associated out-of-band data block when NdisSendPackets or NdisSend returns control.

Although NDIS always submits protocol-supplied packet arrays to the underlying miniport driver in the protocol-determined order passed in calls to NdisSendPackets, the underlying driver can complete the given packets in random order. That is, every bound protocol can rely on NDIS to submit the packets the protocol passes to NdisSendPackets or NdisSend in FIFO order to the underlying driver, but no protocol can rely on that underlying driver to call NdisMSendComplete with those packets in the same order.

ProtocolSendComplete runs at IRQL DISPATCH_LEVEL.

See Also

MiniportSend, MiniportSendPackets, MiniportWanSend, NdisAllocateBuffer, NdisAllocatePacket, NdisCoSendPackets, NdisFreeBuffer, NdisFreePacket, NdisMSendComplete, NDIS_OOB_DATA_FROM_PACKET, NDIS_PACKET_OOB_DATA, NdisReinitializePacket, NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO, NDIS_SET_PACKET_TIME_TO_SEND, NdisUnchainBufferAtBack, NdisUnchainBufferAtFront, NdisZeroMemory, ProtocolCoSendComplete


ProtocolStatus

The ProtocolStatus function is a required driver function that handles status-change notifications raised by an underlying connectionless NIC driver or by NDIS.

An exclusively connection-oriented protocol must have a fully functional ProtocolCoStatus function, rather than a ProtocolStatus function.

VOID
  ProtocolStatus(
    IN NDIS_HANDLE  ProtocolBindingContext,
    IN NDIS_STATUS  GeneralStatus,
    IN PVOID  StatusBuffer,
    IN UINT  StatusBufferSize
    );

Parameters

ProtocolBindingContext
Specifies the handle to a protocol-allocated context area in which the protocol driver maintains per-binding run-time state. The driver supplied this handle when it called NdisOpenAdapter.
GeneralStatus
Indicates the general status code, either raised by NDIS or propagated from the underlying driver's call to NdisMIndicateStatus.
StatusBuffer
Pointer to a buffer containing medium-specific data that depends on the value of GeneralStatus.

For example, if the GeneralStatus argument is NDIS_STATUS_RING_STATUS, this parameter points to a ULONG-sized bitmask and StatusBufferSize is four. As another example, if GeneralStatus is NDIS_STATUS_WAN_LINE_UP, this parameter points to an NDIS_WAN_LINE_UP structure and StatusBufferSize is sizeof(NDIS_STATUS_WAN_LINE_UP).

For some NDIS_STATUS_XXX values, this pointer is NULL and StatusBufferSize is set to zero.

StatusBufferSize
Specifies the number of bytes at StatusBuffer.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A call to ProtocolStatus notifies the protocol about changes in status of the underlying NIC or its driver.

ProtocolStatus interprets two basic pieces of information:

  1. A general status code, defined by NDIS as an NDIS_STATUS_XXX value, indicating a change on the NIC or in the underlying driver

    If NDIS has called the underlying driver's MiniportReset function in an attempt to restore the NIC to an operational state, NDIS can substitute NDIS_STATUS_RESET_START for the GeneralStatus indicated in the miniport driver's call to NdisMIndicateStatus.

  2. Depending on the status at GeneralStatus, additional information about the specific reason for the change in status, which can be medium-specific

    For example, ring-insert failures are specific to Token Ring (802.5) networks and do not apply for Ethernet (802.3) networks.

NDIS notifies all bound protocols when an underlying driver is resetting its NIC by calling their ProtocolStatus functions, first with NDIS_STATUS_RESET_START and later, when the reset operation is done, with NDIS_STATUS_RESET_END. After each such call to a ProtocolStatus function, NDIS also calls the driver's ProtocolStatusComplete function.

Since NDIS will not accept protocol-initiated sends and requests to a miniport driver while a reset is in progress, the NDIS_STATUS_RESET_START notification warns bound protocols to hold off on their calls to NdisSendPackets, NdisSend, and NdisRequest on the binding designated by the respective ProtocolBindingContext given to their ProtocolStatus functions until they receive the corresponding NDIS_STATUS_RESET_END notification.

If the protocol itself initiated the reset operation with a call to NdisReset, its ProtocolStatus function receives the NDIS_STATUS_RESET_START and NDIS_STATUS_RESET_END notifications like any other protocol bound to the same underlying driver. However, if NdisReset returns NDIS_STATUS_PENDING, only the ProtocolStatusComplete function of the driver that initiated the reset operation is called.

Consequently, every protocol's ProtocolStatus function should take whatever action is required to prevent that protocol from submitting sends and requests as soon as ProtocolStatus receives the NDIS_STATUS_RESET_START notification and should re-enable subsequent sends and requests when ProtocolStatus receives the NDIS_STATUS_RESET_END notification. Usually, ProtocolStatus simply sets and clears a ResetInProgress flag in the ProtocolBindingContext area that other driver functions check before they initiate sends or requests on the binding.

As another example, the ProtocolStatus function of any protocol bound above NDISWAN receives a line-up notification whenever the underlying WAN miniport driver is establishing a new link. After such a protocol has traded link-specific context handles with NDISWAN, its ProtocolStatus function can receive additional link-specific line-up, line-down, and fragment indications, which the protocol can use to optimize throughput and/or performance on the link.

When the underlying NIC driver signals a status change, it does not change associated event counters and thresholds.

ProtocolStatus runs at IRQL DISPATCH_LEVEL.

See Also

MiniportReset, NdisMIndicateStatus, NdisRequest, NdisReset, NdisSend, NdisSendPackets, NDIS_WAN_LINE_UP, ProtocolStatusComplete, ProtocolCoStatus


ProtocolStatusComplete

The ProtocolStatusComplete function is a required driver function. ProtocolStatusComplete completes a status-change operation initiated when the underlying driver called NdisMIndicateStatus or NdisMCoIndicateStatus.

VOID
  ProtocolStatusComplete(
    IN NDIS_HANDLE  ProtocolBindingContext
    );

Parameters

ProtocolBindingContext
Specifies the handle to a protocol-allocated context area in which the protocol driver maintains per-binding run-time state. The driver supplied this handle when it called NdisOpenAdapter.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

ProtocolStatusComplete performs whatever postprocessing is necessary after one or more calls to the driver's ProtocolCoStatus or ProtocolStatus function. A call to ProtocolStatusComplete indicates that the protocol can resume normal operations on the binding after taking into account the preceding status change(s) indicated to its Protocol(Co)Status function. For example, if the protocol previously called NdisReset and it returned NDIS_STATUS_PENDING, both ProtocolResetComplete and ProtocolStatusComplete are called when the protocol-initiated reset operation is begun and completed.

The underlying miniport's call to NdisMIndicateStatusComplete causes NDIS to call the ProtocolStatusComplete function. Interrupts are enabled on the underlying NIC when this call occurs. Consequently, the Protocol(Co)ReceivePacket or ProtocolReceive functions can be called to process receive indications while ProtocolStatusComplete is running in SMP machines. In some circumstances, the underlying driver can call NdisMIndicateStatus, thereby causing a call to the ProtocolStatus function while ProtocolStatusComplete is running.

ProtocolStatusComplete runs at IRQL DISPATCH_LEVEL.

See Also

MiniportReset, NdisMCoIndicateStatus, NdisMIndicateStatusComplete, NdisReset, ProtocolCoReceivePacket, ProtocolCoStatus, ProtocolReceive, ProtocolReceivePacket, ProtocolStatus


ProtocolTransferDataComplete

The ProtocolTransferDataComplete function is a required driver function if the protocol might bind itself to an underlying connectionless NIC driver that does not indicate full-packet receives with NdisMIndicateReceivePacket. ProtocolTransferDataComplete completes the processing of a protocol-initiated transfer-data request for which NdisTransferData returned NDIS_STATUS_PENDING.

Exclusively connection-oriented protocols need no ProtocolTransferDataComplete function.

VOID
  ProtocolTransferDataComplete(
    IN NDIS_HANDLE  ProtocolBindingContext,
    IN PNDIS_PACKET  Packet,
    IN NDIS_STATUS  Status,
    IN UINT  BytesTransferred
    );

Parameters

ProtocolBindingContext
Specifies the handle to a protocol-allocated context area in which the protocol driver maintains per-binding run-time state. The driver supplied this handle when it called NdisOpenAdapter.
Packet
Pointer to the protocol-allocated packet descriptor the driver originally passed to NdisTransferData.
Status
Specifies the final status of the transfer-data operation.
BytesTransferred
Specifies the number of bytes of data that the NIC driver transferred into the buffers mapped by buffer descriptors chained to the packet descriptor at Packet. The protocol uses this value to determine whether the miniport driver supplied all the requested data for the originally indicated network packet.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

ProtocolTransferDataComplete can be called before NdisTransferData returns control. If this occurs, the protocol driver has no opportunity to inspect the status code that NdisTransferData returns at Status. The protocol must assume that the given packet descriptor at Packet was pending until ProtocolTransferDataComplete was called.

When the underlying NIC driver calls NdisMTransferDataComplete, NDIS forwards the miniport driver-supplied Packet pointer and Status value to ProtocolTransferDataComplete. When this occurs, the protocol regains ownership of the resources it allocated for a preceding call to NdisTransferData. ProtocolTransferDataComplete can postprocess the miniport driver-supplied data in the buffers the protocol chained to the packet descriptor at Packet, along with the data ProtocolReceive copied in the corresponding indication. Then, ProtocolTransferDataComplete can notify interested clients of the received network data.

ProtocolTransferDataComplete also can either release the resources that the protocol allocated for its call to NdisTransferData or prepare the returned buffer and packet descriptors for reuse in a subsequent call to NdisTransferData. As a general rule, reusing such resources yields better performance than releasing them except, possibly, in periods of low network traffic if the protocol previously allocated a surplus of these resources to handle a period of heavy I/O demand.

To prepare the buffer and packet descriptors for reuse, ProtocolTransferDataComplete should follow these guidelines:

  • Always call an NdisUnchainBufferAt Xxx function as many times as necessary to save the buffer descriptor pointers before ProtocolTransferDataComplete calls NdisReinitializePacket with the descriptor at Packet.

    Otherwise, NdisReinitializePacket sets the head of the buffer chain to NULL so the protocol cannot recover pointers to the buffer descriptors chained to the packet descriptor. In effect, the protocol loses a set of buffer descriptors that the protocol allocated with NdisAllocateBuffer, and possibly loses access to the protocol-allocated buffers mapped by these descriptors as well.

  • Never call NdisZeroMemory with a pointer to a packet descriptor. Use NdisReinitializePacket instead.

    Otherwise, NdisZeroMemory destroys the packet descriptor the protocol allocated with NdisAllocatePacket, rendering it unusable for specifying subsequent data transfers and sends.

ProtocolTransferDataComplete runs at IRQL DISPATCH_LEVEL.

See Also

MiniportTransferData, NdisAllocateBuffer, NdisFreeBuffer, NdisFreeMemory, NdisFreePacket, NdisMIndicateReceivePacket, NdisMTransferDataComplete, NdisReinitializePacket, NdisTransferData, NdisUnchainBufferAtBack, NdisUnchainBufferAtFront, NdisZeroMemory, ProtocolReceive, ProtocolReceivePacket


ProtocolUnbindAdapter

The ProtocolUnbindAdapter function is required to support Plug and Play. All NDIS protocol drivers must export a ProtocolUnBindAdapter function.

VOID
  ProtocolUnbindAdapter(
    OUT PNDIS_STATUS  Status,
    IN NDIS_HANDLE  ProtocolBindingContext,
    IN NDIS_HANDLE  UnbindContext
    );

Parameters

Status
Specifies the status of the unbinding operation as the value returned by NdisCloseAdapter, which can be either of the following:
NDIS_STATUS_SUCCESS
The binding was closed and all resources pertaining to that binding have been released.
NDIS_STATUS_PENDING
The request is being handled asynchronously, and the ProtocolCloseAdapterComplete function will complete the operation.
ProtocolBindingContext
Specifies the handle to a protocol-allocated context area in which the protocol driver maintains per-binding run-time state. The driver supplied this handle when it called NdisOpenAdapter.
UnbindContext
Specifies a handle, supplied by NDIS, that the protocol passes subsequently to NdisCompleteUnbindAdapter.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

As the reciprocal of ProtocolBindAdapter, ProtocolUnbindAdapter releases all resources the driver allocated for per-binding network I/O operations with one possible exception: the driver-allocated context area designated by the ProtocolBindingContext handle.

ProtocolUnbindAdapter must call NdisCloseAdapter, which can, in turn, call the driver's ProtocolCloseAdapterComplete function with the ProtocolBindingContext handle, so ProtocolUnbindAdapter cannot free the memory at ProtocolBindingContext unless NdisCloseAdapter returns NDIS_STATUS_SUCCESS.

Consequently, ProtocolUnbindAdapter should store the input UnbindContext handle in the area at ProtocolBindingContext before it calls NdisCloseAdapter. If this call is completed asynchronously, the ProtocolCloseAdapterComplete function will free all driver-allocated per-binding resources and call NdisCompleteUnbindAdapter with the UnbindContext handle.

If NdisCloseAdapter returns NDIS_STATUS_SUCCESS, ProtocolUnbindAdapter frees all per-binding resources, including the driver-allocated memory at ProtocolBindingContext, and calls NdisCompleteUnbindAdapter itself.

The ProtocolUnbindAdapter function of an NDIS intermediate driver makes a reciprocal call to NdisIMDeinitializeDeviceInstance. Such a driver's MiniportHalt function must release all driver-allocated resources associated with the intermediate driver's NIC before its virtual NIC is removed from the system.

As soon as ProtocolUnbindAdapter calls NdisCloseAdapter, the NdisBindingHandle originally returned by NdisOpenAdapter should be considered invalid. ProtocolUnbindAdapter cannot make any subsequent calls to Ndis Xxx functions with this handle, and the protocol cannot receive any indications from the underlying driver. However, if the underlying NIC is being removed to be reconfigured, NDIS will call the driver's ProtocolBindAdapter function to re-establish the binding when the NIC is available again.

ProtocolUnbindAdapter runs at IRQL PASSIVE_LEVEL.

See Also

NdisCloseAdapter, NdisCompleteUnbindAdapter, NdisDeleteNPagedLookasideList, NdisCoDeleteVc, NdisFreeBufferPool, NdisFreeMemory, NdisFreePacketPool, NdisIMDeinitializeDeviceInstance, ProtocolBindAdapter, ProtocolCloseAdapterComplete


ProtocolUnload

The ProtocolUnload function is optional. ProtocolUnload performs cleanup operations before a protocol is unloaded.

VOID
  ProtocolUnload(
    VOID
    );

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

In response to a user request to uninstall a protocol, NDIS calls a protocol's ProtocolUnload function if the protocol has registered an entry point for this function in the NDIS_PROTOCOL_CHARACTERISTICS structure that it passed to NdisRegisterProtocol. NDIS calls ProtocolUnload after calling the protocol's ProtocolUnbindAdapter function once for each bound adapter.

ProtocolUnload performs driver-determined cleanup operations. For example, ProtocolUnload could request clients to close handles that they have opened to device objects exported by the protocol. Until all such handles are closed, the I/O Manager will not call the DriverUnload function that the protocol registered in the driver object passed to its DriverEntry function. After all the handles are closed, ProtocolUnload could call IoDeleteDevice one or more times to delete device objects created by the protocol.

ProtocolUnload does not have to close a protocol's open bindings. When a protocol's DriverUnload function calls NdisDeregisterProtocol, NDIS calls the protocol's ProtocolUnbindAdapter function once for each binding that the protocol has open. The ProtocolUnbindAdapter function calls NdisCloseAdapter to close the binding.

ProtocolUnload must be written so that it can run at IRQL PASSIVE_LEVEL.

See Also

DriverEntry of NDIS Protocol Drivers, IoDeleteDevice, ProtocolUnbindAdapter


CO_ADDRESS_FAMILY

The CO_ADDRESS_FAMILY structure specifies the type and version of signaling protocol used by a call manager or an MCM driver.

typedef struct {
  NDIS_AF  AddressFamily;
  ULONG  MajorVersion;
  ULONG  MinorVersion;
} CO_ADDRESS_FAMILY, *PCO_ADDRESS_FAMILY;

Members

AddressFamily
Specifies the type of signaling protocol used by a call manager or an MCM driver. The following types are supported:
CO_ADDRESS_FAMILY_Q2931
Specifies the Q.2931 signaling protocol.
CO_ADDRESS_FAMILY_PSCHED
Specifies the Microsoft Packet Scheduling Protocol, which is a policy-based protocol that imposes transmission bandwidth limits on clients. The Microsoft Packet Scheduling Protocol is used over an RSVP (Resource Reservation Protocol) connection.
CO_ADDRESS_FAMILY_L2TP
Specifies the Layer 2 Tunneling Protocol.
CO_ADDRESS_FAMILY_IRDA
Specifies the IrDA signaling protocol.
CO_ADDRESS_FAMILY_1394
Specifies the IEEE 1394 bus signaling protocol.
CO_ADDRESS_FAMILY_PPP
Specifies the Point-to-Point Protocol (PPP).
CO_ADDRESS_FAMILY_TAPI
Specifies the TAPI signaling protocol.
CO_ADDRESS_FAMILY_TAPI_PROXY
Specifies the Microsoft-supplied TAPI proxy, which is a call manager that proxies TAPI calls for a connection-oriented call manager.
MajorVersion
Specifies the major version number of the signaling protocol.
MinorVersion
Specifies the minor version number of the signaling protocol.

Headers

Declared in ndis.h. Include ndis.h.

Comments

When a call manager or MCM driver registers with NDIS by calling Ndis(M)CmRegisterAddressFamily, it passes a CO_ADDRESS_FAMILY structure to NDIS that advertises the call-specific signaling services provided by that call manager. Ndis(M)CmRegisterAddressFamily also passes an NdisBindingHandle that identifies the target NIC or the virtual adapter. An address family is always associated with a particular call manager and a particular NIC.

After a call manager registers an address family, NDIS calls the ProtocolCoRegisterAfNotify function of each client bound to the NIC associated with the address family. In the call to ProtocolCoRegisterAfNotify, NDIS passes the address family in a CO_ADDRESS_FAMILY structure to each client.

Each client's ProtocolCoRegisterAfNotify function checks the input buffer at AddressFamily to determine whether the client recognizes the call manager or MCM driver and the registered address family. If the client recognizes the call manager and the registered address family, it calls NdisClOpenAddressFamily from its ProtocolCoAfRegisterNotify function to register its handlers with NDIS. The call to NdisClOpenAddressFamily also passes the registered address family to the call manager's ProtocolCmOpenAf function in a CO_ADDRESS_FAMILY structure. The ProtocolCmOpenAf function ensures that the client has passed in a valid address family structure.

See Also

MiniportInitialize, NdisClOpenAddressFamily, NdisCmRegisterAddressFamily, NdisMCmRegisterAddressFamily, ProtocolCmOpenAf, ProtocolCoAfRegisterNotify


CO_AF_TAPI_INCOMING_CALL_PARAMETERS

The CO_AF_TAPI_INCOMING_CALL_PARAMETERS structure specifies the TAPI call parameters for an incoming call.

typedef struct _CO_AF_TAPI_INCOMING_CALL_PARAMETERS
{
  IN  ULONG  ulLineID;
  IN  ULONG  ulAddressID;
  IN  ULONG  ulFlags;
  IN  NDIS_VAR_DATA_DESC  LineCallInfo;
} CO_AF_TAPI_INCOMING_CALL_PARAMETERS, *PCO_AF_TAPI_INCOMING_CALL_PARAMETERS;

Members

ulLineID
Specifies a zero-based line identifier. The call manager or MCM driver must set this value to the value of the corresponding ulLineID in the LINE_CALL_INFO structure.
ulAddressID
Specifies a zero-based address identifier on the line specified by ulLineID. The call manager or MCM driver must set this value to the value of the corresponding ulAddressID in the LINE_CALL_INFO structure.
ulFlags
The call manager or MCM driver must set the CO_TAPI_FLAG_INCOMING_CALL bit in ulFlags. All other bits are reserved and must be set to 0.
LineCallInfo
Specifies an NDIS_VAR_DATA_DESC structure that contains an offset from the beginning of the NDIS_VAR_DATA_DESC structure to a LINE_CALL_INFO structure. The NDIS_VAR_DATA_DESC structure also specifies the length of the LINE_CALL_INFO structure. The LINE_CALL_INFO structure specifies the TAPI call parameters for an incoming call. For more information on the LINE_CALL_INFO structure, see the Platform SDK and the ndistapi.h header file.

Headers

Declared in ndis.h. Include ndis.h.

Comments

A call manager or integrated MCM driver that supports the CO_ADDRESS_FAMILY_TAPI_PROXY address family specifies the TAPI parameters of an incoming connection-oriented call in a CO_AF_TAPI_INCOMING_CALL_PARAMETERS structure. The call manager or MCM driver overlays this structure on CO_CALL_PARAMETERS.MediaParameters->MediaSpecific.Parameters[] and sets the Length member of the CO_SPECIFIC_PARAMETERS structure that describes the media-specific parameters to the total length of the Parameters[] array. The call manager or MCM driver passes the encapsulated CO_AF_TAPI_INCOMING_CALL_PARAMETERS structure to Ndis(M)CmActivateVc when activating a VC for an incoming call and to Ndis(M)CmDispatchIncomingCall when indicating the incoming call to a client.

The connection-oriented client to which the incoming call is dispatched (that is, the client that receives the CO_CALL_PARAMETERS structure in its ProtocolClIncomingCall function) should examine only the CO_AF_TAPI_INCOMING_CALL_PARAMETERS structure contained in CO_CALL_PARAMETERS.MediaParameters->MediaSpecific.Parameters[]. No other call parameters are meaningful in this case.

See Also

CO_CALL_PARAMETERS, CO_MEDIA_PARAMETERS, CO_SPECIFIC_PARAMETERS, MiniportCoActivateVc, NdisCmActivateVc, NdisCmDispatchIncomingCall, NdisMCmActivateVc, NdisMCmDispatchIncomingCall, NdisMCoActivateVcComplete, NDIS_VAR_DATA_DESC, ProtocolClIncomingCall, ProtocolCmActivateVcComplete


CO_AF_TAPI_MAKE_CALL_PARAMETERS

The CO_AF_TAPI_MAKE_CALL_PARAMETERS structure specifies the TAPI call parameters for an outgoing call.

typedef struct _CO_AF_TAPI_MAKE_CALL_PARAMETERS
{
  IN  ULONG  ulLineID;
  IN  ULONG  ulAddressID;
  IN  ULONG  ulFlags;
  IN  NDIS_VAR_DATA_DESC  DestAddress;
  IN  NDIS_VAR_DATA_DESC  LineCallParams;
} CO_AF_TAPI_MAKE_CALL_PARAMETERS, *PCO_AF_TAPI_MAKE_CALL_PARAMETERS;

Members

ulLineID
Specifies a zero-based line identifier.
ulAddressID
Specifies a zero-based address identifier on the line specified by ulLineID.
ulFlags
The client must set the CO_TAPI_FLAG_OUTGOING_CALL bit in ulFlags. All other bits are reserved and must be set to 0.
DestAddress
Specifies an NDIS_VAR_DATA_DESC structure that contains an offset from the beginning of the NDIS_VAR_DATA_DESC structure to a destination address formatted as a character array. The NDIS_VAR_DATA_DESC structure also specifies the length of this array. The destination address is the address to which the outgoing call is directed.
LineCallParams
Specifies an NDIS_VAR_DATA_DESC structure that contains an offset from the beginning of the NDIS_VAR_DATA_DESC structure to a LINE_CALL_PARAMS structure. The NDIS_VAR_DATA_DESC structure also specifies the length of the LINE_CALL_PARAMS structure. The LINE_CALL_PARAMS structure specifies the TAPI call parameters for the outgoing call. For more information on this structure, see the Platform SDK and the ndistapi.h header file.

Headers

Declared in ndis.h. Include ndis.h.

Comments

A client that uses the services of a call manager or integrated MCM driver that supports the CO_ADDRESS_FAMILY_TAPI_PROXY address family specifies the TAPI parameters for an outgoing connection-oriented call in an CO_AF_TAPI_MAKE_CALL_PARAMETERS structure. The client overlays this structure on CO_CALL_PARAMETERS.MediaParameters->MediaSpecific.Parameters[] and sets the Length member of the CO_SPECIFIC_PARAMETERS structure that describes the media-specific parameters to the total length of the Parameters[] array. The client passes the encapsulated CO_AF_TAPI_MAKE_CALL_PARAMETERS structure to NdisClMakeCall when making an outgoing call. The call manager or MCM driver passes the encapsulated CO_AF_TAPI_MAKE_CALL_PARAMETERS structure to Ndis(M)CmActivateVc when activating a VC for the outgoing call.

The call manager or MCM driver, which inputs the CO_CALL_PARAMETERS structure in its ProtocolCmMakeCall function, should examine only the CO_AF_TAPI_MAKE_CALL_PARAMETERS structure contained in CO_CALL_PARAMETERS.MediaParameters->MediaSpecific.Parameters[]. No other call parameters are meaningful in this case.

See Also

CO_CALL_PARAMETERS, CO_MEDIA_PARAMETERS, CO_SPECIFIC_PARAMETERS, MiniportCoActivateVc, NdisClMakeCall, NdisCmActivateVc, NdisMCmActivateVc, NdisMCoActivateVcComplete, NDIS_VAR_DATA_DESC, ProtocolCmActivateVcComplete, ProtocolCmMakeCall


CO_AF_TAPI_SAP

The CO_AF_TAPI_SAP structure specifies TAPI service access point (SAP) information.

typedef struct _CO_AF_TAPI_SAP
{
  IN  ULONG  ulLineID;
  IN  ULONG  ulAddressID;
  IN  ULONG  ulMediaModes;
} CO_AF_TAPI_SAP, *PCO_AF_TAPI_SAP;

Members

ulLineID
Specifies a zero-based line identifier. If the call manager or MCM driver does not support per-line capabilities, the client sets ulLineID to CO_TAPI_LINE_ID_UNSPECIFIED.
ulAddressID
Specifies a zero-based address identifier on the line specified by ulLineID. If the call manager or MCM driver does not support per-address capabilities, the client sets ulAddressID to CO_TAPI_ADDRESS_ID_UNSPECIFIED.
ulMediaModes
Specifies the media mode of the information stream of the call as one or more of the following LINEMEDIAMODE_constants:
LINEMEDIAMODE_UNKNOWN
A media stream exists but its mode is currently unknown and may become known later. This corresponds to a call with an unclassified media type. In typical analog telephony environments, the media mode of an incoming call may be unknown until after the call has been answered and the media stream has been filtered to make a determination.

If the LINEMEDIAMODE_UNKNOWN flag is set, other media flags can also be set. This signifies that the media is unknown but that it is likely to be one of the other indicated media modes.

LINEMEDIAMODE_INTERACTIVEVOICE
The presence of voice energy on the call, and the call is treated as an interactive call with humans on both ends.
LINEMEDIAMODE_AUTOMATEDVOICE
The presence of voice energy on the call, and the voice is locally handled by an automated application.
LINEMEDIAMODE_DATAMODEM
A data modem session on the call.
LINEMEDIAMODE_G3FAX
A group 3 fax is being sent or received over the call.
LINEMEDIAMODE_G4FAX
A group 4 fax is being sent or received over the call.
LINEMEDIAMODE_TDD
A TDD (telecommunication device for the deaf) session on the call.
LINEMEDIAMODE_DIGITALDATA
Digital data is being sent or received over the call.
LINEMEDIAMODE_TELETEX
A teletex session on the call. (Teletex is one of the telematic services.)
LINEMEDIAMODE_VIDEOTEX
A videotex session on the call. (Videotex is one the telematic services.)
LINEMEDIAMODE_TELEX
A telex session on the call. (Telex is one of the telematic services.)
LINEMEDIAMODE_MIXED
A mixed session on the call. (Mixed is one of the ISDN telematic services.)
LINEMEDIAMODE_ADSI
An ADSI (Analog Display Services Interface) session on the call.
LINEMEDIAMODE_VOICEVIEW
The media mode of the call is VoiceView.

Headers

Declared in ndis.h. Include ndis.h.

Comments

A client that uses the services of a call manager or integrated MCM driver that supports the CO_ADDRESS_FAMILY_TAPI_PROXY address family specifies TAPI SAP parameters in a CO_AF_TAPI_SAP structure. The client overlays this structure on CO_SAP.Sap[], specifies the SAP type in CO_SAP.SapType, and specifies the length of the Sap[] array in CO_SAP.SapLength. The client passes the CO_SAP structure to NdisClRegisterSap when registering a SAP with a call manager or an MCM driver.

See Also

CO_SAP, CO_SPECIFIC_PARAMETERS, NdisClRegisterSap, ProtocolClRegisterSapComplete, ProtocolCmRegisterSap


CO_CALL_MANAGER_PARAMETERS

The CO_CALL_MANAGER_PARAMETERS structure specifies parameters that a call manager uses to set up an outgoing call and that a connection-oriented client uses to determine whether to accept an incoming call. Connection-oriented clients and call managers can also use CO_CALL_MANAGER_PARAMETERS to request a change of call parameters for a VC. In addition, when adding a party to a multipoint call, a connection-oriented client uses CO_CALL_MANAGER_PARAMETERS to specify the address of the new party.

typedef struct _CO_CALL_MANAGER_PARAMETERS{
  FLOWSPEC  Transmit;
  FLOWSPEC  Receive;
  CO_SPECIFIC_PARAMETERS  CallMgrSpecific;
} CO_CALL_MANAGER_PARAMETERS, *PCO_CALL_MANAGER_PARAMETERS;

Members

Transmit
Pointer to a FLOWSPEC structure that specifies generic quality of service (QoS) parameters such as token rate, latency, and bandwidth, for packet transmission. For more information on the FLOWSPEC structure, see the Platform SDK.
Receive
Pointer to a FLOWSPEC structure that specifies generic QoS parameters such as token rate, latency, and bandwidth, for packet reception. For more information on the FLOWSPEC structure, see the Platform SDK.
CallMgrSpecific
Pointer to a CO_SPECIFIC_PARAMETERS structure that contains information specific to the signaling protocol used by the call manager and that can be specific to the call manager, as well.

Headers

Declared in ndis.h. Include ndis.h.

Comments

The address of a buffered CO_CALL_MANAGER_PARAMETERS structure is a member of a CO_CALL_PARAMETERS structure. The CO_CALL_MANAGER_PARAMETERS structure specifies generic transmit and receive parameters that are of interest to all connection-oriented miniport drivers. The CO_CALL_MANAGER_PARAMETERS structure also contains call manager-specific parameters that are specific to a signaling protocol and possibly to a particular call manager that supports the protocol.

The following sections describe the role of the CO_CALL_MANAGER_PARAMETERS structure in connection-oriented operations:

Making an Outgoing Call

Before making an outgoing call with NdisClMakeCall, a client must fill in the portions of the CO_CALL_MANAGER_PARAMETERS structure that the call manager needs to set up the call. Typically, the client fills in the structures at Transmit and Receive to specify the quality of service (QoS) for the call. The client can also fill in the structure at CallMgrSpecific with any protocol-specific information, such as the destination address, needed to set up the call. The call manager typically interprets values in the buffers at Transmit and Receive to set up any protocol-specific state needed in its call setup messages and to set up media-specific parameters needed to activate the VC after establishing a connection through the network.

The mix of generic and specific parameters that a client supplies to the call manager depends on the requirements and capabilities of both the client and call manager. Note that call manager-specific parameters override any conflicting generic call manager parameters. The client can specify media-specific information at MediaParameters in the CO_CALL_PARAMETERS structure, but the call manager can overwrite these parameters if the call parameters for the call are changed through negotiation.

Indicating an Incoming Call

On an incoming call, the call manager extracts call parameters from a signaling message and maps these values to call-manager parameters at CallMgrParameters and media parameters at MediaParameters of the CO_CALL_PARAMETERS structure. Before calling Ndis(M)CmDispatchIncomingCall, the call manager must fill in the call manager-specific parameters in the CO_CALL_MANAGER_PARAMETERS structure that the client requires to determine whether to accept the call. These parameters might include the destination SAP and the source SAP of the incoming call. The call manager can also supply generic (FLOWSPEC) parameters that the client can inspect to determine whether to accept the call, reject the call, or request a change in QoS, depending on the signaling protocol.

Requesting a Change in Call Parameters for a VC

Before requesting a change in call parameters on a VC by calling NdisClModifyCallQoS, the client must fill in the appropriate generic and/or call manager-specific parameters in the CO_CALL_MANAGER_PARAMETERS structure. The call manager must do the same before calling Ndis(M)CmDispatchIncomingCallQoSChange to indicate an incoming request to change the call parameters on a VC. The signaling protocol determines which parameters, if any, can be changed. The client's and call manager's capabilities determine the possible mix of generic and specific call manager parameters. Note that call manager-specific parameters override any conflicting generic call manager parameters.

Adding a Party to a Multipoint VC

Before calling NdisClAddParty, a client must specify the address of the new party in the call-manager-specific parameters at CallMgrSpecific of the CO_CALL_MANAGER_PARAMETERS structure. The underlying network medium determines whether a client can specify per-party traffic parameters on a multipoint VC for an outgoing call.

See Also

CO_CALL_PARAMETERS, CO_MEDIA_PARAMETERS, CO_SPECIFIC_PARAMETERS, NdisClAddParty, NdisClMakeCall, NdisClModifyCallQoS, NdisCmDispatchIncomingCallQoSChange, NdisMCmDispatchIncomingCallQoSChange


CO_CALL_PARAMETERS

The CO_CALL_PARAMETERS structure contains call parameters used by connection-oriented clients, call managers, MCM drivers, and connection-oriented miniport drivers. The call parameters are used to set up an outgoing call, request quality of service (QoS) for an outgoing call, indicate the QoS for an incoming call, activate a VC for an outgoing or incoming call, negotiate a change of call parameters for a VC, or to add a new party to a multipoint call.

typedef struct _CO_CALL_PARAMETERS{
  ULONG  Flags;
  PCO_CALL_MANAGER_PARAMETERS  CallMgrParameters;
  PCO_MEDIA_PARAMETERS  MediaParameters;
} CO_CALL_PARAMETERS, *PCO_CALL_PARAMETERS;

Members

Flags
The flags can be one or more (ORed) of the following:
PERMANENT_VC
When making an outgoing call, a client sets this flag before calling NdisClMakeCall to indicate to the call manager that it must make the call on a permanent virtual circuit (PVC). If the client does not specify media parameters, the call manager searches its list of configured PVCs for a PVC that is configured with a SAP that matches the destination SAP of the outgoing call. If the client does specify media parameters, the call manager does not search its list of configured PVCs; instead, it uses the PVC specified by the client in the media parameters. If the call manager finds a PVC that meets the requirements of the call, it uses this PVC and returns the PERMANENT_VC flag set in a call to Ndis(M)CmMakeCallComplete. If the call manager is unable to find a suitable PVC, it fails the call attempt with NDIS_STATUS_FAILURE.

Note that if the client does not set the PERMANENT_VC flag and does not specify media parameters, the call manager always searches its list of configured PVCs for one that is configured with a SAP that matches the destination SAP of the outgoing call. If it cannot find such a PVC, the call manager attempts to establish a switched virtual circuit (SVC) for the outgoing call.

On an incoming call, the call manager sets this flag if the VC handle that it passes to the client in the call to Ndis(M)CmDispatchIncomingCall represents a PVC. This indicates that the call manager found a PVC that matches a SAP registered by the client.

CALL_PARAMETERS_CHANGED
Before calling Ndis(M)CmMakeCallComplete, the call manager sets this flag if any value within CO_CALL_PARAMETERS has been changed during the call-setup process as a result of negotiation with the network or a signaling peer. (Whether and when such negotiation occurs during call setup depends on the signaling protocol.) The client must then inspect CO_CALL_PARAMETERS and its substructures to determine which parameters have changed. Depending on the signaling protocol, the client can accept the new call parameters, tear down the call by calling NdisClCloseCall, or attempt to renegotiate the call parameters by calling NdisClModifyCallQoS.
QUERY_CALL_PARAMETERS
This flag is reserved.
BROADCAST_VC
This flag is reserved.
MULTIPOINT_VC
When making an outgoing call, the client can set this flag before calling NdisClMakeCall to indicate that the client is the root of a multipoint connection.

On an incoming call, the call manager can set this flag before calling Ndis(M)CmDispatchIncomingCall to indicate that the client is a leaf of a multipoint connection.

CallMgrParameters
Pointer to a buffered CO_CALL_MANAGER_PARAMETERS structure that specifies the call manager parameters. For a detailed description of this structure, see CO_CALL_MANAGER_PARAMETERS.
MediaParameters
Pointer to a buffered CO_MEDIA_PARAMETERS structure that specifies the media parameters. For a detailed description of this structure, see CO_MEDIA_PARAMETERS.

Headers

Declared in ndis.h. Include ndis.h.

Comments

CO_CALL_PARAMETERS contains call parameters used by connection-oriented clients, call managers or MCM drivers, and connection-oriented miniport drivers. The call parameters are used to set up outgoing calls, to indicate incoming calls, to activate a VC for an outgoing or incoming call, to request a change of call parameters for a VC, and to add a party to a multipoint call.

The flags in CO_CALL_PARAMETERS are of interest to clients and call managers. A client can set flags in CO_CALL_PARAMETERS before calling NdisClMakeCall. Except for CALL_PARAMETERS_CHANGED (which the call manager can set before calling Ndis(M)CmMakeCallComplete to indicate a change in call parameters by a remote entity on the network), the call manager can set flags in CO_CALL_PARAMETERS before calling Ndis(M)CmDispatchIncomingCall.

The call manager parameters pointed to by CO_CALL_PARAMETERS are of interest primarily to clients and call managers. These parameters are contained in a structure of type CO_CALL_MANAGER_PARAMETERS, which can specify generic parameters that apply to all call managers, as well as specific parameters that apply to a specific signaling protocol and possibly to a particular call manager that supports the protocol. CO_CALL_MANAGER_PARAMETERS specifies call parameters that a call manager uses to set up an outgoing call and that a client uses to determine whether to accept an incoming call. In addition, a client uses CO_CALL_MANAGER_PARAMETERS to request a change of call parameters for a VC, and a call manager uses CO_CALL_MANAGER_PARAMETERS to indicate an incoming request to change the call parameters for a VC. Also, when adding a party to multipoint call, the client uses CO_CALL_MANAGER_PARAMETERS to specify the address of the new party.

The media parameters in CO_CALL_PARAMETERS are of interest primarily to miniport drivers. The media parameters are contained in a structure of type CO_MEDIA_PARAMETERS, which can contain generic parameters that apply to all miniport drivers, as well as specific parameters that apply to a specific medium and possibly to a particular miniport driver that controls the medium. Typically, a call manager uses CO_MEDIA_PARAMETERS to specify media parameters to the miniport driver. The miniport driver either reserves resources for the VC or activates the VC with the specified media parameters.

See Also

MiniportCoActivateVc, NdisClAddParty, NdisClIncomingCallComplete, NdisClMakeCall, NdisClModifyCallQoS, NdisCmActivateVc, NdisCmAddPartyComplete, NdisCmDispatchIncomingCall, NdisCmDispatchIncomingCallQoSChange, NdisCmMakeCallComplete, NdisCmModifyCallQoSComplete, NdisMCmActivateVc, NdisMCmAddPartyComplete, NdisMCmDispatchIncomingCall, NdisMCmDispatchIncomingCallQosChange, NdisMCmMakeCallComplete, NdisMCmModifyCallQoSComplete, NdisMCoActivateVcComplete, ProtocolClAddPartyComplete, ProtocolClIncomingCall, ProtocolClIncomingCallQoSChange, ProtocolClMakeCallComplete, ProtocolClModifyCallQoSComplete, ProtocolCmActivateVcComplete, ProtocolCmAddParty, ProtocolCmIncomingCallComplete, ProtocolCmMakeCall, ProtocolCmModifyCallQoS


CO_MEDIA_PARAMETERS

The CO_MEDIA_PARAMETERS structure is typically used by a call manager to specify media parameters to an underlying connection-oriented miniport driver. The miniport drivereither reserves resources for the VC or activates the VC with the specified media parameters.

typedef struct _CO_MEDIA_PARAMETERS{
  ULONG  Flags;
  ULONG  ReceivePriority;
  ULONG  ReceiveSizeHint;
  CO_SPECIFIC_PARAMETERS MediaSpecific;
} CO_MEDIA_PARAMETERS, *PCO_MEDIA_PARAMETERS;

Members

Flags
The flags can be one or more (ORed) of the following:
RECEIVE_TIME_INDICATION
When set, the miniport drivershould use the NDIS_SET_PACKET_TIME_RECEIVED macro to fill in the TimeReceived member in the out-of-band data block for each received packet.
USE_TIME_STAMPS
When set, the miniport driver should use the NDIS_SET_PACKET_TIME_SENT macro to fill in the TimeSent member in the out-of-band data block for each transmitted packet. If the medium does not support time stamps, the miniport driver should ignore this flag.
TRANSMIT_VC
When set, indicates that the VC activated by the miniport driver will be used for transmitting data.
RECEIVE_VC
When set, indicates that the VC activated by the miniport driver will be used for receiving data.
INDICATE_ERRED_PACKETS
When set, the miniport driver should indicate receive packets that contain errors (such as checksum errors) to the client. Otherwise, the miniport driver should discard such packets without notifying the client.
INDICATE_END_OF_TX
When set, the miniport driver should call NdisMCoSendComplete for a packet only after transmission of the packet is finished. Otherwise, the miniport driver can call NdisMCoSendComplete sooner;for example, after transferring the protocol-supplied data into the NIC buffer(s).
RESERVE_RESOURCES_VC
When set, the call manager is requesting that the miniport driver reserve all resources (such as buffers) needed for the VC. The miniport driver should not activate the VC until its MiniportCoActivateVC function is called with this flag cleared.
ROUND_DOWN_FLOW
When set, the miniport driver should round down the value of each media-specific flow parameter (such as bandwidth) to the nearest supported value if the exact value specified cannot be supported. In its call to NdisMCoActivateVcComplete, the miniport driver should return (in the buffer at MediaSpecific parameters) the actual value used for each rounded value.
ROUND_UP_FLOW
When set, the miniport driver should round up the value of each media-specific flow parameter (such as bandwidth) to the nearest supported value if the exact value specified cannot be supported. In its call to NdisMCoActivateVcComplete, the miniport driver should return (in the buffer at MediaSpecific parameters) the actual value used for each rounded value.
ReceivePriority
This is currently reserved.
ReceiveSizeHint
Specifies the size in bytes of incoming packets. This member is commonly set to the maximum SDU size.
MediaSpecific
Pointer to a buffered CO_SPECIFIC_PARAMETERS structure that contains information specific to the particular medium being used.

Headers

Declared in ndis.h. Include ndis.h.

Comments

The address of a buffered CO_MEDIA_PARAMETERS structure is a member of a CO_CALL_PARAMETERS structure. CO_MEDIA_PARAMETERS contains generic media parameters that are of interest to all connection-oriented miniport drivers. CO_MEDIA_PARAMETERS also specifies medium-specific parameters that apply to a specific network medium and possibly to a particular miniport driver that controls the medium.

The following describes the role of media parameters in connection-oriented NDIS operations:

Making an Outgoing Call

Usually a call manager derives the media parameters for an outgoing call from generic call manager parameters provided by a client's call to NdisClMakeCall and passed to the call manager's ProtocolCmMakeCall function. The call manager fills in CO_MEDIA_PARAMETERS and calls Ndis(M)CmActivateVc. The miniport driver receives the CO_MEDIA_PARAMETERS structure in its MiniportCoActivateVC function and uses the media parameters to reserve resources for a VC or to activate a VC.

A client that is aware of the underlying medium can itself fill in CO_MEDIA_PARAMETERS before calling NdisClMakeCall. If the client also sets the PERMANENT_VC bit in CO_CALL_PARAMETERS, the call manager can pass the call parameters uninterpreted to the miniport driver with Ndis(M)CmActivateVc.

Indicating an Incoming Call

When the call manager detects an incoming call on a SAP registered by a client, it maps parameters received in the signaling message to call manager parameters for the client and to media parameters for the miniport driver. The call manager calls Ndis(M)CmActivateVc to pass the media specific parameters to the miniport. The call manager does this before notifying the client of the incoming call with Ndis(M)CmDispatchIncomingCall.

Request to Change Call Parameters for a VC

When a request to change call parameters for a VC is successfully negotiated between the client and a remote entity on the network, the call manager must reactivate the VC for the call. The call manager sends the miniport driver a revised set of media parameters with Ndis(M)CmActivateVc.

Adding a Party to a Call

If the underlying network medium (for example, ATM) does not support per-party traffic parameters on multipoint VCs, the call manager will fail a client's request to change the call parameters for a VC when a adding a party to the call. In this case, adding a party does not involve the media parameters.

If the underlying network medium does support per-party traffic parameters on multipoint VCs, a client can specify new call parameters for any new party it adds. In its call to NdisClAddParty, the client can include generic call manager parameters that the call manager translates to media parameters for the new party, and/or the client can include media parameters for the new party that the call manager passes uninterpreted to the miniport driver.

See Also

CO_CALL_MANAGER_PARAMETERS, CO_CALL_PARAMETERS, CO_SPECIFIC_PARAMETERS,NdisClAddParty, NdisCmActivateVc, NdisCoRequest, NdisMCmActivateVc, NdisMCoSendComplete, NDIS_PACKET_OOB_DATA, NDIS_SET_PACKET_TIME_RECEIVED, NDIS_SET_PACKET_TIME_SENT


CO_SAP

The CO_SAP structure specifies a Service Access Point (SAP) on which a connection-oriented client can receive incoming calls.

typedef struct _CO_SAP{
  ULONG  SapType;
  ULONG  SapLength;
  UCHAR  Sap[1];
} CO_SAP, *PCO_SAP;

Members

SapType
Specifies the format of the SAP address:
NSAP
Specifies an OSI SAP, which is a 20-octet hexadecimal address.
E164
Specifies an E.164 SAP, which is a 0-15-digit decimal address.
AF_TAPI_SAP_TYPE
Specifies a SAP used for TAPI calls.
SapLength
Specifies the size in bytes of the structure at Sap.
Sap
Specifies a variable-length array that contains the SAP information. The number and type of elements is defined by the call manager for the address family opened by the client.

Headers

Declared in ndis.h. Include ndis.h.

Comments

A connection-oriented client registers a SAP with a call manager by passing a CO_SAP structure in a call to NdisClRegisterSap. NDIS forwards the SAP information to the call manager's ProtocolCmRegisterSap function for validation. The SAP format is medium-dependent and specific to the address family supported by the call manager. If the SAP is already in use or if the call manager does not recognize the client-supplied specification at Sap, ProtocolCmRegisterSap fails the call, and NdisClRegisterSap propagates the failure back to the client.

After a client has successfully registered a SAP, the call manager notifies the client of incoming calls on that SAP. A client can register more than one SAP with a call manager.

SapType is meaningful only to the client and to the call manager or integrated miniport driver call manager (MCM) driver with which the client registers the SAP. The client can therefore set SapType to a driver-defined value that is recognized by the call manager or MCM driver.

See Also

NdisClRegisterSap, ProtocolClRegisterSapComplete, ProtocolCmRegisterSap


CO_SPECIFIC_PARAMETERS

Depending on the type of structure that contains it, the CO_SPECIFIC_PARAMETERS structure passes call manager-specific parameters between a connection-oriented client and a call manager (or MCM driver), passes medium-specific parameters between a call manager (or connection-oriented client) and a connection-oriented miniport driver and its NIC, or passes PVC-specific parameters to a call manager from a connection-oriented client.

typedef struct _CO_SPECIFIC_PARAMETERS{
  ULONG  ParamType;
  ULONG  Length;
  UCHAR  Parameters[1];
} CO_SPECIFIC_PARAMETERS, *PCO_SPECIFIC_PARAMETERS;

Members

ParamType
Specifies the type of parameters at Parameters:
CALLMGR_SPECIFIC_Q2931
The buffer at Parameters contains Q.2931 call manager-specific parameters.
ATM_MEDIA_SPECIFIC
The buffer at Parameters contains ATM medium-specific parameters.
Length
Specifies the size in bytes of the buffer at Parameters.
Parameters
Specifies a variable-length array that contains call manager-specific parameters, media-specific parameters, or protocol-specific parameters that describe a PVC. The number and type of elements in the array depend on the particular task for which CO_SPECIFIC_PARAMETERS is being used.

Headers

Declared in ndis.h. Include ndis.h.

Comments

CO_SPECIFIC_PARAMETERS is a variable-sized structure that can be extended with any array that contains protocol-specific parameters. CO_SPECIFIC_PARAMETERS includes type and length members that allow vendors to specify various implementations of the structure.

The address of a buffered CO_SPECIFIC_PARAMETERS structure is a member of the following structures:

  • CO_CALL_MANAGER_PARAMETERS
  • CO_MEDIA_SPECIFIC PARAMETERS
  • CO_PVC

When referenced by a CO_CALL_MANAGER_PARAMETERS structure, the CO_SPECIFIC_PARAMETERS structure contains call manager-specific parameters. For example, the CO_SPECIFIC_PARAMETERS structure could contain parameters specific to the Q.2931 signaling protocol. In this case, the ParamType would be CALLMGR_SPECIFIC_Q2931 and Parameters would be an array that contains Q.2931-specific parameters.

When referenced by a CO_MEDIA_PARAMETERS structure, the CO_SPECIFIC_PARAMETERS structure contains medium-specific parameters. For example, the CO_SPECIFIC_PARAMETERS structure could contain ATM media-specific parameters. In this case, the ParamType would be ATM_MEDIA_SPECIFIC and Parameters would be an array that contains the ATM media-specific parameters.

When referenced by a CO_PVC structure, CO_SPECIFIC_PARAMETERS contains protocol-specific parameters that describe a PVC. A client passes an OID_CO_ADD_PVC and a buffered CO_PVC structure or an OID_CO_DELETE_PVC and a buffered CO_PVC structure with NdisCoRequest. This client call requests that the call manager's ProtocolCoRequest function add the specified PVC to its list of configured PVCs. In this case, the ParamType is ignored, and Parameters is an array that contains the protocol-specific parameters that describe the PVC.

ParamType is meaningful only to a connection-oriented client and to the call manager or integrated miniport call manager (MCM) driver with which the client has opened an address family. A driver can therefore set ParamType to a driver-defined value that is recognized by the call manager or MCM driver.

See Also

CO_CALL_PARAMETERS, CO_CALL_MANAGER_PARAMETERS, CO_MEDIA_PARAMETERS, NdisCoRequest OID_CO_ADD_PVC, OID_CO_DELETE_PVC


NDIS_IPSEC_PACKET_INFO

The NDIS_IPSEC_PACKET_INFO structure specifies information used in offloading IP Security tasks from the TCP/IP transport to a miniport driver. The NDIS_IPSEC_PACKET_INFO structure is part of the per-packet information (extended out-of-band data) associated with a packet descriptor.

typedef struct _NDIS_IPSEC_PACKET_INFO
{
    union
    {
        struct
        {
            NDIS_HANDLE    OffloadHandle;
            NDIS_HANDLE    NextOffloadHandle;
        } Transmit;

        struct
        {
            ULONG    SA_DELETE_REQ:1;
            ULONG    CRYPTO_DONE:1;
            ULONG    NEXT_CRYPTO_DONE:1;
            ULONG    CryptoStatus;
        } Receive;
    };
} NDIS_IPSEC_PACKET_INFO, *PNDIS_IPSEC_PACKET_INFO;

Members

OffloadHandle
Specifies the handle to the outbound security association (SA) for a packet that has just one IP Security payload, regardless of whether that payload is for a transport (end-to-end) connection or a tunnel connection.
NextOffloadHandle
For a packet that has both a transport IP Security payload and a tunnel IP Security payload, NextOffloadHandle specifies the handle to the outbound security association (SA) for the tunnel connection. NextOffloadHandle is specified only if a packet has both tunnel and transport IP Security payloads; otherwise, NextOffloadHandle is set to zero.
SA_DELETE_REQ
When set, indicates that the TCP/IP transport should issue OID_TCP_TASK_IPSEC_DELETE_SA once to delete the inbound security association (SA) over which the packet was received and once again to delete the outbound SA that corresponds to the deleted inbound SA. The miniport driver's NIC must not remove either of these SAs before receiving the corresponding OID_TCP_TASK_IPSEC_DELETE_SA request.
CRYPTO_DONE
When set, indicates that the NIC performed IP Security checking on at least one IP security payload in the receive packet. When cleared, indicates that the NIC did not perform IP Security checking on the packet.
NEXT_CRYPTO_DONE
When set, indicates that the NIC performed IP security checking on both the tunnel and transport portions of the receive packet. CRYPTO_DONE must also be set in this case. NEXT_CRYPTO_DONE is set only if a packet has both tunnel and transport IP Security payloads; otherwise, NEXT_CRYPTO_DONE is set to zero.
CryptoStatus
Specifies, as one of the following values, the result of IP Security checking performed by the NIC on a receive packet:
CRYPTO_SUCCESS
The packet was successfully decrypted, if necessary, and the AH checksum(s) and/or ESP checksum(s) in the packet were validated.
CRYPTO_GENERIC_ERROR
The packet failed the IP Security check for an unspecified reason.
CRYPTO_TRANSPORT_AH_AUTH_FAILED
The AH checksum for the transport portion of the packet was invalid.
CRYPTO_TRANSPORT_ESP_AUTH_FAILED
The ESP checksum for the transport portion of the packet was invalid.
CRYPTO_TUNNEL_AH_AUTH_FAILED
The AH checksum for the tunnel portion of the packet was invalid.
CRYPTO_TUNNEL_ESP_AUTH_FAILED
The ESP checksum for the tunnel portion of the packet was invalid.
CRYPTO_INVALID_PACKET_LENGTH
The receive packet's length is invalid.
CRYPTO_INVALID_PROTOCOL
The IP Security protocol(s) specified in the security association (SA) on which the packet was received do not match the IP Security protocols found in the packet. For example, this error occurs if the SA on which the packet was received specifies the AH protocol but the packet contained only an ESP header.

Headers

Declared in ndis.h. Include ndis.h.

Comments

Before the TCP/IP transport passes to a miniport driver a send packet on which the miniport driver's NIC will perform IP Security tasks, it updates the IP Security information in the NDIS_IPSEC_PACKET_INFO structure associated with the packet descriptor. Specifically, the TCP/IP transport supplies an OffloadHandle in the NDIS_IPSEC_PACKET_INFO structure. The OffloadHandle specifies the handle to the outbound security association (SA) for a packet that has just one IP Security payload, regardless of whether that payload is for a transport (end-to-end) security association or a tunnel security association. The OffloadHandle supplied in the NDIS_IPSEC_PACKET_INFO structure has the same value as the OffloadHandle supplied by the TCP/IP transport when it set OID_TCP_TASK_IPSEC_ADD_SA to request the miniport driver to add the outbound SA to its NIC.

If a packet that has both a transport IP Security payload and a tunnel IP Security payload, NextOffloadHandle specifies the handle to the outbound SA for the tunnel connection. NextOffloadHandle is specified only if a packet has both tunnel and transport IP Security payloads; otherwise, NextOffloadHandle is set to zero.

Before indicating up a receive packet that has one or more IP Security payloads, a miniport driver updates the NDIS_IPSEC_PACKET_INFO structure associated with the packet descriptor:

  • If the miniport driver's NIC performed IP Security checks on at least one IP security payload in the packet, the miniport driver sets the CRYPTO_DONE flag and indicates the results of the checksum validation tests by specifying the appropriate CryptoStatus value.
  • If the miniport driver's NIC performed IP security checking on both the tunnel and transport portions of a receive packet, the miniport driver also sets the NEXT_CRYPTO_DONE flag. The NEXT_CRYPTO_DONE flag is set only if a packet has both tunnel and transport IP security payloads; otherwise, NEXT_CRYPTO_DONE is set to zero.
  • If the miniport driver's NIC did not perform IP Security checks on the packet, the miniport driver does not set the CRYPTO_DONE flag or the NEXT_CRYPTO_DONE flag and does not supply a CryptoStatus value.

To make room for another SA on the NIC, the miniport driver can set SA_DELETE_REQ in the NDIS_IPSEC_PACKET_INFO structure for a receive packet. The TCP/IP transport subsequently issues OID_TCP_TASK_IPSEC_DELETE_SA once to delete the inbound security association (SA) over which the packet was received and once again to delete the outbound SA that corresponds to the deleted inbound SA. The miniport driver's NIC must not remove either of these SAs before receiving the corresponding OID_TCP_TASK_IPSEC_DELETE_SA request. The miniport driver can set SA_DELETE_REQ independently of CRYPTO_DONE.

To obtain a pointer to the NDIS_IPSEC_PACKET_INFO structure, drivers should call the NDIS_PER_PACKET_INFO_FROM_PACKET macro with an InfoType of IpSecNdisTask. Alternatively, drivers can call the NDIS_PACKET_EXTENSION_FROM_PACKET macro to obtain a pointer to the NDIS_PACKET_EXTENSION structure associated with a given packet descriptor. The driver can then use the IpSecNdisTask array index to obtain a pointer that points to the NDIS_IPSEC_PACKET_INFO structure.

See Also

NDIS_PACKET_EXTENSION, NDIS_PACKET_EXTENSION_FROM_PACKET, NDIS_PER_PACKET_INFO_FROM_PACKET, OID_TCP_TASK_IPSEC_ADD_SA, OID_TCP_TASK_IPSEC_DELETE_SA


NDIS_MAC_FRAGMENT

The NDIS_MAC_FRAGMENT structure contains information associated with a fragment indication made by a WAN miniport driver.

typedef struct _NDIS_MAC_FRAGMENT {
  IN NDIS_HANDLE  NdisLinkContext;
  IN ULONG    Errors;
} NDIS_MAC_FRAGMENT, *PNDIS_MAC_FRAGMENT;

Members

NdisLinkContext
Specifies the handle, identifying the link, that the miniport driver set in the line-up indication when the link was established.
Errors
Specifies a bitmask set with one or more of the following system-defined flags (ORed) to indicate why the fragment was received.
WAN_ERROR_CRC
WAN_ERROR_FRAMING
WAN_ERROR_HARDWAREOVERRUN
WAN_ERROR_BUFFEROVERRUN
WAN_ERROR_TIMEOUT
WAN_ERROR_ALIGNMENT

If no direct mapping from the WAN medium error to one of the preceding error flags exists, choose the most appropriate flag or combination of flags.

Headers

Declared in ndis.h. Include ndis.h.

Comments

A WAN NIC driver calls NdisMIndicateStatus with this type of indication when it receives a partial packet from a remote node on the wide area network.

NDISWAN forwards such a fragment indication to the affected protocol(s), formatted as an NDIS_WAN_FRAGMENT structure.

See Also

NDIS_MAC_LINE_UP, NdisMIndicateStatus, NDIS_WAN_FRAGMENT


NDIS_MAC_LINE_DOWN

The NDIS_MAC_LINE_DOWN structure contains information associated with a line-down indication made by a WAN miniport driver.

typedef struct _NDIS_MAC_LINE_DOWN {
  IN NDIS_HANDLE NdisLinkContext;
} NDIS_MAC_LINE_DOWN, *PNDIS_MAC_LINE_DOWN;

Member

NdisLinkContext
Specifies the handle, identifying the link, that the miniport driver set in the line-up indication when the link was established.

Headers

Declared in ndis.h. Include ndis.h.

Comments

A WAN NIC driver calls NdisMIndicateStatus with this type of indication when a link between a local node and a remote node in a wide area network becomes inactive.

NDISWAN forwards such a line-down indication to the affected protocol(s), formatted as an NDIS_WAN_LINE_DOWN structure.

See Also

NDIS_MAC_LINE_UP, NdisMIndicateStatus, NDIS_WAN_LINE_DOWN


NDIS_MAC_LINE_UP

The NDIS_MAC_LINE_UP structure contains information associated with a line-up indication made by a WAN miniport driver.

typedef struct _NDIS_MAC_LINE_UP {
  IN ULONG  LinkSpeed;
  IN NDIS_WAN_QUALITY  Quality;
  IN USHORT  SendWindow;
  IN NDIS_HANDLE  ConnectionWrapperID;
  IN NDIS_HANDLE  NdisLinkHandle;
  IN OUT NDIS_HANDLE  NdisLinkContext;
} NDIS_MAC_LINE_UP, *PNDIS_MAC_LINE_UP;

Members

LinkSpeed
Specifies the speed of the link, in units of 100 bps.

Zero indicates no change from the speed the miniport driver originally returned for the OID_GEN_LINK_SPEED query.

Quality
Specifies the quality of service (QOS) of the new line as returned when the protocol called NdisRequest with OID_WAN_QUALITY_OF_SERVICE.
SendWindow
Specifies the number of send packets the miniport driver (or its NIC) can accept at a time, effectively how many NDIS_WAN_PACKET-type send packets the WAN NIC driver queues internally. Zero indicates that NDISWAN should use the value returned for MaxTransmit in response to the OID_WAN_GET_INFO query.
ConnectionWrapperID
Specifies the handle by which this link (or data channel on a link) will be known to TAPI client(s). This handle must be unique, so the miniport driver uses the htCall handle supplied by NDISTAPI. Before the miniport driver makes the initial line-up indication that establishes such a link (or data channel), it already acquired the NDISTAPI-assigned htCall handle in one of the following ways:
  • For an outbound call, the driver's MiniportQueryInformation function saved the htCall handle that NDISTAPI supplied in a preceding OID_TAPI_MAKE_CALL request.
  • For an incoming call, the miniport driver saved the htCall handle that NDISTAPI returned in ulParam2 of the NDIS_TAPI_EVENT structure that the miniport driver passed to NdisMIndicateStatus with ulMsg set to LINE_NEWCALL.
NdisLinkHandle
Specifies the handle, originally supplied by the NIC driver, that is passed down in subsequent calls, such as to MiniportWanSend, to identify a particular link, or to identify a particular channel on a link capable of handling more than one data stream.
NdisLinkContext
Specifies zero when a WAN NIC driver calls NdisMIndicateStatus with this structure to establish a link. On return from NdisMIndicateStatus, this member contains a handle, supplied by NDISWAN, to be used in future calls, such as to indicate receives, for the established link.

Headers

Declared in ndis.h. Include ndis.h.

Comments

A WAN NIC driver calls NdisMIndicateStatus with this type of indication in either of the following conditions:

  • When a link between a local node and a remote node in a wide area network becomes active in the process of establishing the new link, the MiniportQueryInformation function makes this indication in the context of an OID_TAPI_GET_ID request for which ulSelect is set to LINECALLSELECT_CALL.

    When NdisMIndicateStatus returns, the miniport driver must save the NdisLinkContext handle, supplied by NDISWAN, for subsequent calls to NdisMIndicateStatus and NdisWan Xxx functions affecting the just established link.

    MiniportQueryInformation also must use the returned NdisLinkContext handle as the value returned to NDISTAPI at DeviceID in the NDIS_TAPI_GET_ID structure.

    If it can handle more than one data channel on a link, a WAN NIC driver's MiniportQueryInformation function is called once with OID_TAPI_GET_ID as each such channel on the link is opened. On such a link, NdisLinkContext handles are channel-specific rather than link-specific.

  • After such a link is established, the NIC driver makes this indication with the given NdisLinkContext handle if line characteristics change, or to dynamically change the value of SendWindow specifying the number of outstanding sends the NIC driver accepts for its internal queue. For example, a miniport driver can make a subsequent line-up indication if the originally specified Quality of the line changes.

Typically, a WAN NIC driver provides a pointer to a driver-allocated control block for each link as NdisLinkHandle. This handle is link-specific or, if the driver manages more than one data stream per link, data-channel-specific. In either case, a WAN miniport driver must set up its NdisLinkHandle at the first NDIS_MAC_LINE_UP indication that the miniport driver makes for each link or data channel.

After NDISWAN has submitted the number of packets specified in SendWindow to MiniportWanSend, NDISWAN holds incoming send packets queued until the miniport driver returns a completed send packet or calls NdisMWanSendComplete with a packet for which it previously returned NDIS_STATUS_PENDING, whichever occurs first. Subsequent NDIS_MAC_LINE_UPs can be indicated if the NIC driver needs to change the SendWindow value dynamically.

Whenever subsequent NDIS_MAC_LINE_UP indications are made, whether to change the SendWindow value or for changes in line characteristics, the NdisLinkHandle member must be filled with the value set in the driver's initial line-up call to NdisMIndicateStatus for the same link.

NDISWAN supplies a unique handle at NdisLinkContext for every initial NDIS_MAC_LINE_UP indication that establishes a new link or channel. The miniport driver must supply the given NdisLinkContext handle when it makes any subsequent NDIS_MAC_LINE_UP, NDIS_MAC_LINE_DOWN, and NDIS_MAC_FRAGMENT indications for the same link or channel.

See Also

MiniportQueryInformation, MiniportSetInformation, NDIS_MAC_FRAGMENT, NDIS_MAC_LINE_DOWN, NdisMIndicateStatus, NdisMWanIndicateReceive, NdisRequest, NDIS_TAPI_EVENT, ProtocolStatus


NDIS_PACKET

The NDIS_PACKET structure defines the packet descriptors with chained buffer descriptors for which pointers are passed to many Ndis Xxx, MiniportXxx, and ProtocolXxx functions.

typedef struct _NDIS_PACKET {
    NDIS_PACKET_PRIVATE  Private;
    union {
        struct {
             UCHAR       MiniportReserved[2*sizeof(PVOID)];
             UCHAR       WrapperReserved[2*sizeof(PVOID)];
        };
        struct {
             UCHAR       MiniportReservedEx[3*sizeof(PVOID)];
             UCHAR       WrapperReservedEx[sizeof(PVOID)];
        };
        struct {
             UCHAR       MacReserved[4*sizeof(PVOID)];
        };
    };
    ULONG_PTR            Reserved[2];
    UCHAR                ProtocolReserved[1];
} NDIS_PACKET, *PNDIS_PACKET, **PPNDIS_PACKET;

Members

Private
This is reserved for use exclusively by NDIS. Drivers must call the appropriate Ndis Xxx functions or NDIS-supplied macros to affect the contents of this area.
MiniportReserved
Serialized miniport drivers and NDIS intermediate drivers can use this area for their own purposes.
WrapperReserved
This is reserved for use exclusively by NDIS.
MiniportReservedEx
Deserialized and connection-oriented miniport drivers can use this area for their own purposes.
WrapperReservedEx
This is reserved for use exclusively by NDIS.
Reserved
This is for compatibility with Windows 95/98/Me.
MacReserved
This is reserved for use by legacy drivers.
ProtocolReserved
Highest-level protocol drivers and NDIS intermediate drivers can use this variable-sized area for their own purposes, as long as each such driver is given a fresh packet descriptor.

Headers

Declared in ndis.h. Include ndis.h.

Comments

NDIS drivers must call NdisAllocatePacket(Ex) to allocate all packet descriptors they use to indicate receives to higher-level drivers with NdisMIndicateReceivePacket. NDIS drivers must call NdisAllocatePacket to allocate all packet descriptors they use for sends to underlying drivers with NdisSendPackets or NdisSend, as well as packet descriptors they pass to NdisTransferData.

Chained to each packet descriptor are one or more buffer descriptors mapping buffers that contain network packet data, either received or to be transmitted. NIC drivers and intermediate drivers allocate packet descriptors with four pointer's worth (4*sizeof(PVOID)) of ProtocolReserved space to be used by protocols for receive indications. On 32-bit systems, four pointer's worth of ProtocolReserved space equals 16 bytes. On 64-bit systems, four pointer's worth of ProtocolReserved space equals 32 bytes.

Any buffers allocated by lower-level NDIS drivers must be mapped by buffer descriptors that were allocated from buffer pool with NdisAllocateBuffer. Only highest-level Windows® 2000 and later protocols can use MDLs set up by still higher-level drivers as substitutes for NDIS_BUFFER-type descriptors.

NDIS drivers typically use their respective Xxx Reserved areas to maintain per-packet state about outstanding transfers. For example, a protocol might store a pointer to a protocol-allocated buffer containing lookahead data, which its ProtocolReceive function has already copied, in the ProtocolReserved area of a packet descriptor that the protocol allocates for a call to NdisTransferData.

A single driver can use the MiniportReserved(Ex) area and a single driver can use the ProtocolReserved area while a particular packet descriptor is being used in a transfer operation. Consequently, NDIS intermediate drivers, which have both MiniportXxx and ProtocolXxx functions, cannot use these areas in incoming packet descriptors for their own purposes.

Drivers that supply and consume out-of-band data on network transfers and drivers that support multipacket receives and/or sends must use the member-specific NDIS_GET/SET_XXX macros or the NDIS_OOB_DATA_FROM_PACKET macro to access the NDIS_PACKET_OOB_DATA block associated with each packet descriptor.

When a protocol driver calls Ndis(Co)SendPackets or NdisSend with a packet descriptor, it relinquishes ownership of the following until that packet descriptor is returned to its ProtocolSendComplete function:

  • The protocol-allocated packet descriptor(s)
  • All data buffers mapped by buffer descriptors chained to the packet descriptor(s)
  • All NDIS_PACKET_OOB_DATA blocks associated with each protocol-allocated packet descriptor
  • Any out-of-band data buffer specified in an NDIS_PACKET_OOB_DATA block for an associated buffer descriptor

See Also

MiniportSend, MiniportSendPackets, MiniportTransferData, NdisAllocateBuffer, NdisAllocatePacket, NdisChainBufferAtBack, NdisChainBufferAtFront, NdisCopyFromPacketToPacket, NdisFreePacket, NdisGetFirstBufferFromPacket, NdisGetFirstBufferFromPacketSafe, NdisGetPacketFlags, NdisMSendComplete, NdisMTransferDataComplete, NDIS_PACKET_OOB_DATA, NdisQueryPacket, NdisRecalculatePacketCounts, NdisReinitializePacket, NdisReturnPackets, NdisSend, NdisCoSendPackets, NdisSendPackets, NdisSetPacketFlags, NdisTransferData, NdisUnchainBufferAtBack, NdisUnchainBufferAtFront, ProtocolReceive, ProtocolReceivePacket, ProtocolSendComplete, ProtocolTransferDataComplete


NDIS_PACKET_8021Q_INFO

The NDIS_PACKET_8021Q_INFO structure specifies packet information.

typedef struct _NDIS_PACKET_8021Q_INFO {
    union {
        struct {
            UINT32  UserPriority:3;
            UINT32  CanonicalFormatId:1;
            UINT32  VlanId:12;
            UINT32  Reserved:16;
        } TagHeader;
        PVOID  Value;
    };
} NDIS_PACKET_8021Q_INFO, *PNDIS_PACKET_8021Q_INFO;

Members

TagHeader
Specifies a member in the union contained in NDIS_PACKET_8021Q_INFO that can hold information about a packet in a structure with the following members:
UserPriority
Specifies 802.1p priority information that is used to establish packet priority in shared-media 802 networks. The bits in this member specify an 802.1p priority value.
A driver can use the NDIS_PER_PACKET_INFO_FROM_PACKET macro with the Ieee8021QInfo per-packet information value to either retrieve an 802.1p priority value from a packet descriptor or insert an 802.1p priority value into a packet descriptor. For more information, see Packet Support for 802.1p Priority.
CanonicalFormatId
This member should be set to zero.
VlanId
Specifies VLAN identifier information.
Reserved
This member is reserved and should be set to zero.
Value
Specifies a member in the union contained in NDIS_PACKET_8021Q_INFO that can hold information about a packet in a buffer.

Headers

Defined in Ndis.h. Include Ndis.h.

Comments

When a miniport driver calls the NDIS_PER_PACKET_INFO_FROM_PACKET macro to retrieve or insert information in a packet descriptor, the macro returns this information in the Value member of the union contained in NDIS_PACKET_8021Q_INFO. The miniport driver uses the TagHeader member of the union to modify specific types of information, such as 802.1p priority and VLAN identifier information. For more information, see Packet Support for 802.1p Priority.

See Also

NDIS_PACKET_EXTENSION_FROM_PACKET, NDIS_PER_PACKET_INFO_FROM_PACKET


NDIS_PACKET_EXTENSION

The NDIS_PACKET_EXTENSION structure contains an array of pointers, each of which points to or contains per-packet (out-of-band) information associated with a packet descriptor.

typedef struct _NDIS_PACKET_EXTENSION
{
  PVOID  NdisPacketInfo[MaxPerPacketInfo];
} NDIS_PACKET_EXTENSION, *PNDIS_PACKET_EXTENSION;

Members

NdisPacketInfo[MaxPerPacketInfo]
An array of pointers, each of which points to or contains per-packet information specific to a particular task. The index values for the array are defined as follows:
TcpIpCheckSumPacketInfo
Indexes a pointer that points to or contains an NDIS_TCP_IP_CHECKSUM_PACKET_INFO structure. This structure specifies per-packet information for checksum operations offloaded from the TCP/IP transport to a NIC.
IpSecPacketInfo
Indexes a pointer that points to an NDIS_IPSEC_PACKET_INFO structure. This structure specifies per-packet information for IP Security operations offloaded from the TCP/IP transport to a NIC.
TcpLargeSendPacketInfo
Indexes a pointer that contains a ULONG value. Before passing a large TCP packet to a NIC for segmentation, the TCP/IP transport sets this value to the maximum segment size (MSS), which is equivalent to the current maximum transmission unit (MTU). The MTU is the maximum number of user data bytes that can be included in a packet. The miniport driver uses the MSS value to segment the large TCP packet into shorter packets. Before completing the send operation (for example, with NdisMSendComplete or NdisMCoSendComplete), the miniport driver writes the ULONG value with the total number of user data bytes sent in all packets derived from the large TCP packet.
ClassificationHandlePacketInfo
This is reserved.
HeaderIndexInfo
To be documented later.
ScatterGatherListPacketInfo
Indexes a pointer to a SCATTER_GATHER_LIST structure, which specifies the mapped logical address ranges of buffers containing DMA data for a packet. A miniport driver that reserves system resources for DMA operations by calling NdisMInitializeScatterGatherDma supplies the obtained logical address ranges to its NIC so that the NIC can perform a DMA transfer.
Ieee8021QInfo
Indexes the Value member of an NDIS_PACKET_8021Q_INFO structure, which specifies 802.1p priority and VLAN identifier information. 802.1p priority information is used to establish packet priority in shared-media 802 networks. The bits in the TagHeader.UserPriority member of NDIS_PACKET_8021Q_INFO specify an 802.1p priority value.
For more information, see 802.1P Packet Priority in the Network Drivers Design Guide.
OriginalPacketInfo
Indexes a pointer to a NDIS_PACKET structure. This structure specifies a packet descriptor that contains original information that was previously received over the network and indicated up by the lowest-level driver in a stack of NDIS drivers. Each driver in the layered stack can access the out-of-band (OOB) data block that is associated with the packet that is received from the network without requiring that the packet be copied to each layer.
NdisInternalExtension1
To be documented later.
NdisInternalExtension2
To be documented later.

Headers

Declared in ndis.h. Include ndis.h.

Comments

Every packet descriptor allocated with NdisAllocatePacket has an associated NDIS_PACKET_EXTENSION structure. This structure contains an array of pointers (PVOIDs), each of which points to or contains a particular type of per-packet information associated with a packet descriptor. Per-packet information is out-of-band (OOB) data in addition to that specified by the NDIS_PACKET_OOB_DATA block. The NDIS_PACKET_EXTENSION structure thus extends the OOB data associated with a packet descriptor.

To access per-packet information, drivers should use the NDIS_PER_PACKET_INFO_FROM_PACKET macro, which returns a pointer to the specified type of per-packet information. A driver can call this macro once for each type of per-packet information that it needs to access.

Drivers can also use the NDIS_PACKET_EXTENSION_FROM_PACKET macro, which returns a pointer to the NDIS_PACKET_EXTENSION structure. A driver can call this macro if it needs to access more than one type of per-packet information associated with a packet descriptor. After obtaining the pointer to the NDIS_PACKET_EXTENSION structure, the driver can use the appropriate array index to obtain a pointer to a particular type of per-packet information.

See Also

NdisAllocatePacket, NDIS_IPSEC_PACKET_INFO, NdisMCoSendComplete, NdisMInitializeScatterGatherDma, NdisMSendComplete, NDIS_PACKET_8021Q_INFO, NDIS_PACKET_EXTENSION_FROM_PACKET, NDIS_PACKET_OOB_DATA, NDIS_PER_PACKET_INFO_FROM_PACKET, NDIS_TCP_IP_CHECKSUM_PACKET_INFO, SCATTER_GATHER_LIST


NDIS_PACKET_OOB_DATA

The NDIS_PACKET_OOB_DATA structure specifies out-of-band information associated with a packet descriptor, used by drivers whose media supplies, requires, or accepts out-of-band information, such as information for an ATM NIC, and by drivers that support multipacket receives and/or sends.

typedef struct _NDIS_PACKET_OOB_DATA {
    union {
        ULONGLONG  TimeToSend;
        ULONGLONG  TimeSent;
    };
    ULONGLONG  TimeReceived;
    UINT  HeaderSize;
    UINT  SizeMediaSpecificInfo;
    PVOID  MediaSpecificInformation;
    NDIS_STATUS  Status;
} NDIS_PACKET_OOB_DATA, *PNDIS_PACKET_OOB_DATA;

Members

TimeToSend
Specifies the time, in system time units, at which a given packet should be transmitted over the network.

Protocols can set this timestamp before passing an array of packet descriptor pointers to NdisSendPackets or a packet descriptor pointer to NdisSend.

The MiniportSendPackets or MiniportSend functions of underlying drivers can retrieve the value of this timestamp to determine when the given packet(s) should be transmitted over the network. Usually, only the lowest-level underlying driver retrieves this timestamp.

TimeSent
Specifies the time, in system time units, at which a received packet was transmitted over the network from a remote node.

NIC drivers and, possibly, intermediate drivers that export only a set of MiniportXxx functions set this timestamp before indicating receive packet(s).

The ProtocolReceivePacket functions of drivers bound above such a miniport driver can retrieve the value of this timestamp to determine when any particular packet was transmitted from the remote node. If the ProtocolReceive function is given an indication and the underlying driver sets this timestamp, ProtocolReceive can call NdisGetReceivedPacket and NDIS_GET_ORIGINAL_PACKET to retrieve the packet that contains this timestamp.

TimeReceived
Specifies the time, in system time units, at which a given packet from a remote node on the network was received on the NIC.

NIC drivers and, possibly, intermediate drivers that export only a set of MiniportXxx functions set this timestamp before calling NdisMIndicateReceivePacket with a packet array, which can have one or more pointers to packet descriptors.

The ProtocolReceivePacket functions of drivers bound above any such miniport driver can retrieve the value of this timestamp to determine when the given packet(s) were received. If the ProtocolReceive function is given an indication and the underlying driver sets this timestamp, ProtocolReceive can call NdisGetReceivedPacket and NDIS_GET_ORIGINAL_PACKET to retrieve the packet that contains this timestamp.

HeaderSize
Specifies the size in bytes of the medium-specific header contained in the buffer mapped by the initial buffer descriptor chained to the packet descriptor.

Lower-level drivers set this member for subsequent receive indication(s) according to the medium each driver's MiniportInitialize function elected to support.

The ProtocolReceivePacket functions of drivers bound above such a miniport driver can retrieve the value of this member to determine how to process the medium-specific net packet.

SizeMediaSpecificInfo
Specifies the size in bytes of the buffer at MediaSpecificInformation.

A driver must set this member if it supplies out-of-band information with a packet to be sent or indicated.

MediaSpecificInformation
Specifies the address of a driver-allocated buffer. This buffer contains any out-of-band data, such as information for an ATM NIC, that accompanies the net packet specified with the packet descriptor. The out-of-band data has been set up either by the allocating protocol for a send or by the allocating miniport driver for a receive indication.

Either type of driver can retrieve the address of the out-of-band data buffer and its size to determine how to process or interpret the send or receive specified with the incoming packet descriptor. If the ProtocolReceive function is given an indication and the underlying driver supplies this information, ProtocolReceive can call NdisGetReceivedPacket and NDIS_GET_ORIGINAL_PACKET to retrieve the packet that contains the virtual range of this buffer.

Status
Specifies the current status of the packet descriptor and the ownership of all driver-allocated resources specified with the packet descriptor.

Only lower-level drivers and NDIS set this member.

In the Receive Path

A miniport driver can set this member before it calls NdisMIndicateReceivePacket to indicate how soon it needs to regain ownership of its allocated resources specified in the associated packet descriptor(s). A serialized can retrieve this value on return from NdisMIndicateReceivePacket to determine whether the resources specified with the packet descriptor for its indication can be prepared for reuse immediately. A deserialized or connection-oriented miniport, however, does not have to check this value on return from NdisMCoIndicateReceivePacket.

In the Send Path

A serialized miniport driver can set this member in its MiniportSendPackets function to complete an incoming send immediately, to notify NDIS that it will complete the request asynchronously, or to request that NDIS requeue some or all of the incoming packet array and resubmit those packet descriptor(s) to MiniportSendPackets later.

A protocol cannot retrieve this value to determine the completion status of a send on return from its call to NdisSendPackets or NdisSend.

A deserialized or connection-oriented miniport driver cannot complete a multipacket send synchronously or request (by setting the Status member) that NDIS requeue some or all of an incoming packet array. Instead, a deserialized or connection-oriented miniport driver must queue internally the entire incoming packet array if it cannot send the data immediately and must always complete a multipacket send asynchronously with NdisMSendComplete (or NdisMCoSendComplete) for each packet in the array.

Headers

Declared in ndis.h. Include ndis.h.

Comments

Every packet descriptor allocated with NdisAllocatePacket has an associated NDIS_PACKET_OOB_DATA block. Only drivers that support multipacket sends and/or receives and drivers that supply out-of-band information, such as packet priority, with each network packet to be transferred use the OOB block. Nevertheless, every NDIS driver that allocates packet descriptors for transfers between bound drivers must allocate those packet descriptors with NdisAllocatePacket from the packet pool that each such NDIS driver usually allocates when it initializes.

In general, drivers of high-capacity bus-master DMA NICs are most likely to support multipacket receives and sends because such a NIC driver makes the greatest performance gains by supporting multipacket transfers. Any protocol that binds itself to (or above) such an underlying NIC driver also should support multipacket sends and receives for maximum performance.

If such a protocol also binds itself above another NIC driver without multipacket transfer support, NDIS handles multipacket sends and single-packet receives in a manner transparent to both drivers by always calling the protocol's ProtocolReceive function and by calling that NIC driver's MiniportSend function with a single packet per call. Similarly, if a protocol that does not support multipacket transfers binds itself above a NIC driver that does, NDIS handles multipacket receive indications and single packet sends in a manner transparent to both drivers, although the MiniportSendPackets function of the underlying NIC driver is given only a single send request per call to NdisSend from such a protocol.

Using Timestamps

All timestamps set in the NDIS_PACKET_OOB_DATA blocks associated with packet descriptors are expressed in system time units as the number of 100-nanosecond intervals since 12:00 a.m., January 1, 1601.

NDIS drivers can call NdisGetCurrentSystemTime when they set these timestamps with the NDIS_SET_PACKET_TIME_XXX macros. Still higher-level drivers or system components can convert these timestamps into locale-specific values more meaningful to the end user.

Supplying Out-of-Band Information with Packets

Any out-of-band information specified in the SizeMediaSpecificInfo and MediaSpecificInformation members is medium-type-specific. For example, some types of media require protocols to specify a packet priority for each packet they send and require NIC drivers to specify a packet priority with each receive packet they indicate. Such a NIC driver must call NdisM(Co)IndicateReceivePacket to fulfill the requirements of these types of media.

While NDIS provides support for a range of priority values from zero through seven, some media support only two levels of priority. For these types of media, NDIS drivers should map values zero through three to the medium-specific normal priority value (usually zero for such media types) and values four through seven to the medium-specific high priority value (usually one for such media types).

The structure of individual records within the buffer at MediaSpecificInformation is defined as follows:

typedef struct     MediaSpecificInformation {
  UINT  NextEntryOffset;
  NDIS_CLASS_ID  ClassId;
  UINT  Size;
  UCHAR  ClassInformation[1];
} MEDIA_SPECIFIC_INFORMATION;

The members of this structure contain the following information:

NextEntryOffset
Specifies the byte offset to this member in the next record, if any. Zero indicates this is the last record in the buffer; the values of all remaining members in the last record are also zero. The value of this member must be quad-aligned.
ClassId
Specifies the type of the record. Possible values are one of the following:
NdisClass802_3Priority
This value is no longer used. Per-packet priority is a member of the array that is contained in a NDIS_PACKET_EXTENSION structure. Drivers should use the NDIS_PER_PACKET_INFO_FROM_PACKET macro to access packet priority from a packet descriptor. Alternatively, drivers can use the NDIS_PACKET_EXTENSION_FROM_PACKET macro to access packet priority from a packet descriptor.
NdisClassWirelessWanMbxMailbox
The underlying NIC driver examines the ULONG-sized record at ClassInformation to determine whether the mailbox flag should be set for the associated packet. (1 = set mailbox flag, 0 = do not set mailbox flag)

NdisClassIrdaPacketInfo
An underlying IrDA NIC driver examines the NDIS_IRDA_PACKET_INFO structure at ClassInformation to determine the number of extra Beginning of Frame (BOF) flags that it must add to a frame to be transmitted and the minimum time (in microseconds) that it must wait after receiving a transmission before its NIC can start transmitting.

The NDIS_IRDA_PACKET_INFO structure is defined as follows:

typedef struct _NDIS_IRDA_PACKET_INFO
{
    UINT  ExtraBOFs
    UNIT  MinTurnAroundTime;
} NDIS_IRDA_PACKET_INFO, *PNDIS_IRDA_PACKET_INFO;
NdisClassAtmAALInfo
Before sending a packet to an underlying NDIS driver for an ATM NIC, a protocol driver sets the appropriate information in the ATM_AAL_OOB_INFO structure at ClassInformation.

The ATM_AAL_OOB_INFO structure is defined as follows:

typedef struct _ATM_AAL_OOB_INFO
{
    ATM_AAL_TYPE     AalType;
    union
    {
        struct _ATM_AAL5_INFO
        {
            BOOLEAN  CellLossPriority;
            UCHAR    UserToUserIndication;
            UCHAR    CommonPartIndicator;
        } ATM_AAL5_INFO;

        struct _ATM_AAL0_INFO
        {
            BOOLEAN  CellLossPriority;
            UCHAR    PayLoadTypeIdentifier;
        } ATM_AAL0_INFO;
    };
} ATM_AAL_OOB_INFO, *PATM_AAL_OOB_INFO;

When sending an AAL5 packet, the protocol sets the members of the ATM_AAL5_INFO structure (CellLossPriority, UserToUserIndication, and CommonPartIndicator) to the values to which the miniport driver should set the corresponding fields of the ATM packet header. When sending an AAL0 packet, the protocol sets the members of the ATM_AAL0_INFO structure (CellLossPriority and CommonPartIndicator) to the values to which the miniport driver should set the corresponding fields of the ATM cell header.

The underlying driver examines the ATM_AAL_OOB_INFO structure to obtain values for fields in the AAL5 packet header or the AAL0 cell header.

Size
Specifies the number of bytes in the ClassInformation array, including any padding necessary to align the NextEntryOffset of the next record on a four-byte boundary.
ClassInformation
Specifies the out-of-band information for this record.

The NDIS_CLASS_ID type is an NDIS-defined enumeration. Most common classifications for records will be specified as system-defined values. However, a range of values in this enumeration will be available for vendor-defined experimental classes.

Setting Status Before Making Receive Indications

Only lower-level NDIS drivers use the Status member of this structure for receive indications. Before such a driver calls NdisMIndicateReceivePacket, it sets the Status with NDIS_SET_PACKET_STATUS for one or more packet descriptors in the array to be indicated to either of the following values:

NDIS_STATUS_SUCCESS
Tells NDIS that the driver is relinquishing ownership of the packet about to be indicated with NdisM(Co)IndicateReceivePacket until the packet descriptor is returned to its MiniportReturnPacket function.

Protocols that receive the indication can use the packet descriptor, along with all buffers mapped by buffer descriptors chained to the packet descriptor and any out-of-band information supplied with the packet, to copy the indicated net packet data or, possibly, to forward the indicated data to interested clients.

NDIS_STATUS_RESOURCES
Tells NDIS that the driver is retaining ownership of the packet about to be indicated with NdisM(Co)IndicateReceivePacket. This packet will be indicated to the ProtocolReceive or ProtocolCoReceivePacket functions of bound protocols.

Setting this status forces bound protocols to return ownership of each such packet descriptor, of any medium-specific buffer in the out-of-band data block for each packet descriptor, and of the memory mapped by each packet descriptor's respective chained buffer descriptors to the indicating driver more quickly. The protocols must wait for a call to their ProtocolReceiveComplete functions to begin postprocessing the data they copied from indication(s) and forwarding the data to clients.

An indicating driver can set this status if it is running low on packet pool or buffer pool. An indicating NIC driver can set this status if it is running low on NIC receive buffers due to high network traffic. A bus-master DMA NIC driver might call NdisMAllocateSharedMemoryAsync in these circumstances to get additional NIC receive buffer space.

A deserialized or connection-oriented miniport driver must save the Status member of the out-of-band data block in a local variable before indicating up the packet descriptor. As explained in more detail below, when NdisMIndicateReceivePacket returns, a deserialized miniport driver must check the saved packet Status to determine whether it can immediately reclaim the packet descriptor and the associated buffers.

Getting Status on Return from NdisMIndicateReceivePacket

After a serialized driver has set the Status for some number of packet descriptors and called NdisMIndicateReceivePacket with the array of pointers to the packet descriptors, it must use the NDIS_GET_PACKET_STATUS macro when NdisMIndicateReceivePacket returns control to retrieve the Status set by NDIS.

The returned Status in the NDIS_PACKET_OOB_DATA block associated with each packet descriptor that the serialized driver indicated with NDIS_STATUS_SUCCESS determines what the indicating driver does next, as follows:

NDIS_STATUS_SUCCESS
If this is set on return from a miniport's call to NdisMIndicateReceivePacket, the miniport driver regains ownership of the following:
  • The packet descriptor
  • The associated out-of-band data block associated with the packet descriptor and of any media-specific information buffer specified in this block
  • All buffers mapped by buffer descriptors chained to the packet descriptor

NDIS guarantees that any packet descriptors for which the indicating driver set NDIS_STATUS_RESOURCES, as already described, will be returned from its call to NdisMIndicateReceivePacket with NDIS_STATUS_SUCCESS.

The driver can prepare these descriptors, the out-of-band block, and media-specific information buffer, if any, for reuse in subsequent receive indications immediately.

NDIS_STATUS_PENDING
If this is set on return from NdisMIndicateReceivePacket, protocols retain ownership of the packet descriptor, of its associated out-of-band data block and of any buffer specified in this block, and of all buffers mapped by buffer descriptors chained to the packet descriptor until the packet descriptor is returned to the indicating driver's MiniportReturnPacket function.

A deserialized or connection-oriented miniport driver must not examine the Status of indicated packets on return of NdisMIndicateReceivePacket. Instead, a deserialized miniport driver must save a packet's Status in a local variable before indicating up the packet descriptor. When NdisMIndicateReceivePacket returns, the miniport driver should check the saved packet Status. If the miniport driver set the packet's Status to NDIS_STATUS_RESOURCES before indicating up the packet descriptor, it should reclaim the packet descriptor immediately after NdisMIndicateReceivePacket returns, preferably by calling its own MiniportReturnPacket function. In this case, NDIS does not call the miniport driver's MiniportReturnPacket function to return the packet descriptor. If the miniport driver set the packet's Status to NDIS_STATUS_SUCCESS before indicating up the packet descriptor, the miniport driver must not reclaim the packet descriptor until NDIS subsequently returns the packet descriptor to the miniport driver's MiniportReturnPacket function.

Setting Status in MiniportSendPackets

Only underlying serialized NDIS drivers with MiniportSendPackets functions can use the Status member of this structure for packet descriptors specifying sends. Such a driver's MiniportSendPackets function sets the Status member in the out-of-band data blocks associated with the packet descriptors in the input array as follows:

  • If the driver will complete the send operation asynchronously, MiniportSendPackets sets NDIS_STATUS_PENDING in the Status member for the given packet descriptor.
  • If the driver cannot process all sends in a given packet array due to current resource constraints, MiniportSendPackets sets NDIS_STATUS_RESOURCES in the Status member for one packet descriptor.

    NDIS queues these packet descriptors internally in the same order for resubmission to MiniportSendPackets when the driver calls NdisMSendResourcesAvailable or NdisMSendComplete, whichever occurs first. NDIS reflects this miniport-set status value to protocols as NDIS_STATUS_PENDING.

  • If MiniportSendPackets will complete a given send request before it returns control, it must set the Status member for the given packet descriptor to a driver-determined status value so that NDIS can reflect this status back to the protocol that initiated the send.

Otherwise, such a driver supplies the completion status for each packet when it calls NdisMSendComplete with the packet descriptor. Drivers that have MiniportSend instead of MiniportSendPackets functions return the status for each incoming send packet, so such a driver never sets the Status member of the out-of-band data block for a packet descriptor specifying a send.

Protocols cannot determine the completion status for a protocol-allocated packet descriptor from the Status member of the associated OOB block on return from NdisSendPackets or NdisSend. This value can change dynamically as NDIS submits, requeues, and resubmits send packet(s) to underlying drivers' MiniportSendPackets and/or MiniportSend functions.

A protocol cannot use any NDIS_GET_PACKET_XXX macro nor the NDIS_OOB_DATA_FROM_PACKET macro to access the OOB data block for such a protocol-allocated packet descriptor until its ProtocolSendComplete function is called with the packet descriptor.

See Also

MiniportAllocateComplete, MiniportHandleInterrupt, MiniportReturnPacket, MiniportSend, MiniportSendPackets, MiniportTimer, NdisAllocateBuffer, NdisAllocateBufferPool, NdisAllocatePacket, NdisAllocatePacketPool, NdisGetCurrentSystemTime, NDIS_GET_ORIGINAL_PACKET, NDIS_GET_PACKET_HEADER_SIZE, NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO, NDIS_GET_PACKET_STATUS, NDIS_GET_PACKET_TIME_RECEIVED, NDIS_GET_PACKET_TIME_SENT, NDIS_GET_PACKET_TIME_TO_SEND, NdisGetReceivedPacket, NdisMCoIndicateReceivePacket, NdisMIndicateReceivePacket, NdisMSendComplete, NdisMSendResourcesAvailable, NDIS_OOB_DATA_FROM_PACKET, NDIS_PACKET, NdisSend, NdisSendPackets, NDIS_SET_PACKET_HEADER_SIZE, NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO, NDIS_SET_PACKET_STATUS, NDIS_SET_PACKET_TIME_RECEIVED, NDIS_SET_PACKET_TIME_SENT, NDIS_SET_PACKET_TIME_TO_SEND, ProtocolReceive, ProtocolCoReceivePacket, ProtocolReceivePacket, ProtocolSendComplete


NDIS_PM_PACKET_PATTERN

The NDIS_PM_PACKET_PATTERN structure specifies a wake-up pattern, which, when detected by a NIC that has pattern-match enabled, causes the NIC to signal a power-management wake-up event.

typedef struct _NDIS_PM_PACKET_PATTERN
{
  ULONG  Priority;
  ULONG  Reserved;
  ULONG  MaskSize;
  ULONG  PatternOffset;
  ULONG  PatternSize;
  ULONG  PatternFlags;
} NDIS_PM_PACKET_PATTERN,  *PNDIS_PM_PACKET_PATTERN;

Members

Priority
This member is reserved.
Reserved
This member is reserved.
MaskSize
Specifies the size in bytes of the pattern mask that immediately follows the NDIS_PM_PACKET_PATTERN structure in the InformationBuffer.
PatternOffset
Specifies in bytes the offset from the beginning of the InformationBuffer to the start of the wake-up pattern.
PatternSize
Specifies in bytes the size of the wake-up pattern.
PatternFlags
These flags are reserved.

Headers

Declared in ntddndis.h. Include ntddndis.h.

Comments

NDIS_PM_PACKET_PATTERN is supplied in the InformationBuffer of the NDIS_REQUEST structure for following OIDs:

  • OID_PNP_ADD_WAKE_UP_PATTERN

    A protocol driver sends this OID to a miniport driver to specify a wake-up pattern. The wake-up pattern, along with its mask, is described by an NDIS_PM_PACKET_PATTERN structure.

  • OID_PNP_REMOVE_WAKE_UP_PATTERN

    A protocol driver sends this OID to a miniport driver to delete a wake-up pattern that it previously specified with an OID_PNP_ADD_WAKE_UP_PATTERN request. The wake-up pattern, along with its mask, is described by an NDIS_PM_PACKET_PATTERN structure.

  • OID_PNP_WAKE_UP_PATTERN_LIST

    A protocol uses this OID to request a list of the wake-up patterns currently set for the miniport driver's NIC. Each wake-up pattern, along with its mask, is described by an NDIS_PM_PACKET_PATTERN structure.

See Also

OID_PNP_ADD_WAKE_UP_PATTERN, OID_PNP_REMOVE_WAKE_UP_PATTERN, OID_PNP_WAKE_UP_PATTERN_LIST


NDIS_PHYSICAL_ADDRESS

This type is equivalent to the system-defined LARGE_INTEGER type. For Windows® 2000 drivers, the value is a 64-bit unsigned integer.

See Also

NdisGetPhysicalAddressHigh, NdisGetPhysicalAddressLow


NDIS_REQUEST

The NDIS_REQUEST structure specifies a packet set up by NDIS or by a protocol for a call to NdisRequest. NDIS submits these requests to the underlying driver's MiniportQueryInformation or MiniportSetInformation functions.

typedef struct _NDIS_REQUEST {
    UCHAR             MacReserved[4*sizeof(PVOID)];
    NDIS_REQUEST_TYPE RequestType;
    union _DATA {
        struct QUERY_INFORMATION {
            NDIS_OID  Oid;
            PVOID     InformationBuffer;
            UINT      InformationBufferLength;
            UINT      BytesWritten;
            UINT      BytesNeeded;
        } QUERY_INFORMATION;
        struct SET_INFORMATION {
            NDIS_OID  Oid;
            PVOID     InformationBuffer;
            UINT      InformationBufferLength;
            UINT      BytesRead;
            UINT      BytesNeeded;
        } SET_INFORMATION;
   } DATA;
} NDIS_REQUEST, *PNDIS_REQUEST;

Members

MacReserved[4*sizeof(PVOID)]
Specifies an area reserved for use by the underlying driver. This area can contain up to four pointers' worth of data.
RequestType
Specifies the request type as one of the following:
NdisRequestQueryInformation
Specifies a query-information request. NDIS forwards such a request to the underlying driver's MiniportQueryInformation function.
NdisRequestSetInformation
Specifies a set-information request. NDIS forwards such a request to the underlying driver's MiniportSetInformation function.
NdisRequestQueryStatistics
Specifies a query-statistics request. For most statistics queries, NDIS satisfies the request itself. Otherwise, NDIS forwards such request to the underlying driver's MiniportQueryInformation function. This type of request originates in a user-mode application, never in a protocol driver.

For any of the preceding values, the OID_XXX specified in the Oid member must be compatible with the type of operation requested.

NdisRequestOpen
This type is obsolete. A protocol driver calls NdisOpenAdapter instead.
NdisRequestClose
This type is obsolete. A protocol driver calls NdisCloseAdapter instead.
NdisRequestSend
This type is obsolete. A protocol driver calls NdisSend or NdisSendPackets instead.
NdisRequestTransferData
This type is obsolete. A protocol driver calls NdisTransferData instead.
NdisRequestReset
This type is obsolete. A protocol driver calls NdisReset instead.
NdisRequestGeneric1
Specifies a NIC-driver-specific request.
NdisRequestGeneric2
Specifies a NIC-driver-specific request.
NdisRequestGeneric3
Specifies a NIC-driver-specific request.
NdisRequestGeneric4
Specifies a NIC-driver-specific request.
Oid
Specifies the object identifier of the requested operation. The value is an OID_XXX code.
InformationBuffer
Pointer to a buffer into which the underlying driver or NDIS returns the requested information for queries or from which the underlying driver reads caller-supplied information for sets.
InformationBufferLength
Specifies the size in bytes of the buffer at InformationBuffer. The value at Oid determines the value appropriate to this member.
BytesWritten
Specifies the number of bytes that the underlying driver or NDIS transfers into the buffer at InformationBuffer for query-information requests. If NdisRequest returns NDIS_STATUS_INVALID_LENGTH, the value of this member is meaningless.
BytesRead
Specifies the number of bytes that the underlying driver read from the buffer at InformationBuffer for set-information requests.
BytesNeeded
Specifies the number of bytes needed to return query information or to carry out the set operation requested by the given OID_XXX code.

If NdisRequest returns NDIS_STATUS_SUCCESS, the value of this member is meaningless. If the InformationBufferLength is too small for the given OID_XXX on a query, this member indicates how large a buffer is required to satisfy the request. If the buffer at InformationBuffer does not contain sufficient data for the given OID_XXX on a set, this member indicates how much data is required.

Headers

Declared in ndis.h. Include ndis.h.

Comments

A protocol should allocate nonpaged memory for the buffer at InformationBuffer and for the NDIS_REQUEST packet itself. Passing in a packet or buffer allocated from paged memory can cause fatal page faults because the underlying driver(s) run at IRQL DISPATCH_LEVEL to carry out the requested operation.

NDIS_REQUEST contains a DATA substructure for each type of operation that a protocol driver can request of an underlying driver. Before calling NdisRequest, the protocol fills in the relevant members of the substructure that represents the query or set operation it specified in the Oid member. NDIS or the underlying driver fills in the remaining members before it returns control to the caller.

The NdisRequestGeneric types are available for NIC drivers that create their own internal requests. To indicate a requested operation, a NIC driver sets an internal variable to one of these types.

See Also

MiniportQueryInformation, MiniportSetInformation, NdisCloseAdapter, NdisMQueryInformationComplete, NdisMSetInformationComplete, NdisOpenAdapter, NdisRequest, NdisReset, NdisSend, NdisSendPackets, NdisTransferData, ProtocolRequestComplete


NDIS_TAPI_EVENT

The NDIS_TAPI_EVENT structure is used when reporting spontaneously occurring events on the line or on a call on an established line to TAPI through NDISWAN.

typedef struct _NDIS_TAPI_EVENT {
  IN  HTAPI_LINE  htLine,
  IN  HTAPI_CALL  htCall,
  IN  ULONG  ulMsg,
  IN  ULONG  ulParam1,
  IN  ULONG  ulParam2,
  IN  ULONG  ulParam3
} NDIS_TAPI_EVENT, *PNDIS_TAPI_EVENT;

Members

htLine
Specifies the TAPI handle for the line on which the event occurred.
htCall
Specifies the TAPI handle for the call on which the event occurred if this is a call-related event. For line-related events where there is no call, this parameter should be set to zero.
ulMsg
Specifies what kind of event is being reported. Interpretation of remaining members depends on the context indicated by ulMsg. The values of this parameter are defined in ndistapi.h, and they correspond to the names of the messages themselves, for example, LINE_NEWCALL.
ulParam1
Specifies a parameter for the message.
ulParam2
Specifies a parameter for the message.
ulParam3
Specifies a parameter for the message.

Headers

Declared in ndis.h. Include ndis.h.

Comments

A WAN miniport driver calls NdisMIndicateStatus with this type of indication when a TAPI line or call event occurs, specifying NDIS_STATUS_TAPI_INDICATION as the value for GeneralStatus and supplying a pointer to an initialized structure of type NDIS_TAPI_EVENT.

See Also

NdisMIndicateStatus, ProtocolStatus


NDIS_TASK_IPSEC

When supplied by a miniport driver in response to a query of OID_TCP_TASK_OFFLOAD, the NDIS_TASK_IPSEC structure specifies the miniport driver's NIC's capabilities for performing IP Security tasks on packets. When passed to a miniport driver in a set of OID_TCP_TASK_OFFLOAD, the structure specifies the IP Security capabilities that the TCP/IP transport is enabling for the NIC.

typedef struct _NDIS_TASK_IPSEC
{
  struct
  {
    ULONG   AH_ESP_COMBINED;
    ULONG   TRANSPORT_TUNNEL_COMBINED;
    ULONG   V4_OPTIONS;
    ULONG   RESERVED;
  } Supported;

  struct
  {
    ULONG   MD5:1;
    ULONG   SHA_1:1;
    ULONG   Transport:1;
    ULONG   Tunnel:1;
    ULONG   Send:1;
    ULONG   Receive:1;
  } V4AH;

  struct
  {
    ULONG   DES:1;
    ULONG   RESERVED:1;
    ULONG   TRIPLE_DES:1;
    ULONG   NULL_ESP:1;
    ULONG   Transport:1;
    ULONG   Tunnel:1;
    ULONG   Send:1;
    ULONG   Receive:1;
  } V4ESP;

} NDIS_TASK_IPSEC, *PNDIS_TASK_IPSEC;

Members

AH_ESP_COMBINED
Set by a miniport driver to indicate that its NIC can perform IP Security operations on send and receive packets that contain both an authentication header (AH) security payload and an encapsulating security payload (ESP). A value of zero indicates that the NIC does not support this capability.

Set by the TCP/IP transport to enable this capability.

TRANSPORT_TUNNEL_COMBINED
Set by a miniport driver to indicate that its NIC can process security payloads for both the transport-mode portion and the tunnel-mode portion of send and receive packets. (The transport-mode portion of a packet pertains to an end-to-end connection. The tunnel-mode portion of a packet pertains to a tunnel connection.) A value of zero indicates that the NIC does not support this capability.

Set by the TCP/IP transport to enable this capability.

V4_OPTIONS
Set by a miniport driver to indicate that its NIC can perform IP security operations on IPv4 send and receive packets whose IP header(s) contain IP options. A value of zero indicates that the NIC does not support this capability.

Set by the TCP/IP transport to enable this capability.

RESERVED
This is reserved.
V4AH
MD5
Set by a miniport driver to indicate that its NIC can use the keyed MD5 algorithm for computing and/or validating a cryptographic checksum for an AH payload and/or ESP payload. Set by the TCP/IP transport to enable this capability.
SHA_1
Set by a miniport driver to indicate that its NIC can use the SHA 1 algorithm for computing and/or validating a cryptographic checksum for an AH payload and/or ESP payload. Set by the TCP/IP transport to enable this capability.
Transport
Set by a miniport driver to indicate that its NIC can calculate and/or validate the cryptographic checksum(s) for the portion of a packet that pertains to an end-to-end connection. Set by the TCP/IP transport to enable this capability.
Tunnel
Set by a miniport driver to indicate that its NIC can calculate and/or validate cryptographic checksum(s) for the portion of a packet that pertains to a tunnel connection. Set by the TCP/IP transport to enable this capability.
Send
Set by a miniport driver to indicate that its NIC can calculate cryptographic checksum(s) for send packets. Set by the TCP/IP transport to enable this capability.
Receive
Set by a miniport driver to indicate that its NIC can validate cryptographic checksum(s) for receive packets. Set by the TCP/IP transport to enable this capability.
V4ESP
DES
Set by a miniport driver to indicate that its NIC supports the DES algorithm for encrypting and decrypting ESP payloads. Set by the TCP/IP transport to enable this capability.
RESERVED
This is reserved.
TRIPLE_DES
Set by a miniport driver to indicate that its NIC supports the triple-DES algorithm for encrypting and decrypting ESP payloads. Set by the TCP/IP transport to enable this capability.
NULL_ESP
Set by a miniport driver to indicate that its NIC supports null encryption, which is the ESP payload without encryption but with authentication information. Set by the TCP/IP transport to enable this capability.
Transport
Set by a miniport driver to indicate that its NIC can encrypt and decrypt ESP data for the portion of a packet that pertains to an end-to-end connection. Set by the TCP/IP transport to enable this capability.
Tunnel
Set by a miniport driver to indicate that its NIC can encrypt and decrypt ESP data for the portion of a packet that pertains to a tunnel connection. Set by the TCP/IP transport to enable this capability.
Send
Set by a miniport driver to indicate that its NIC can encrypt and decrypt ESP payloads in send packets. Set by the TCP/IP transport to enable this capability.
Receive
Set by a miniport driver to indicate that its NIC can encrypt and decrypt ESP payloads in receive packets. Set by the TCP/IP transport to enable this capability.

Headers

Declared in ndis.h. Include ndis.h.

Comments

In response to a query of OID_TCP_TASK_OFFLOAD, a miniport driver returns in the InformationBuffer an NDIS_TASK_OFFLOAD_HEADER structure followed by one or NDIS_TASK_OFFLOAD structures. Each NDIS_TASK_OFFLOAD structure specifies a task-offload capability supported by the miniport driver's NIC.

When the Task member of the NDIS_TASK_OFFLOAD structure specifies IpSecNdisTask, the TaskBuffer of the NDIS_TASK_OFFLOAD structure contains an NDIS_TASK_IPSEC structure. When the NDIS_TASK_IPSEC structure is filled in by a miniport driver in response to the TCP/IP transport's query of OID_TCP_TASK_OFFLOAD, it specifies the miniport driver's NIC's capabilities for performing IP Security tasks on packets. When the NDIS_TASK_IPSEC structure is passed to a miniport driver through the TCP/IP transport's set of OID_TCP_TASK_OFFLOAD, it specifies the IP Security capabilities that the transport is enabling.

See Also

OID_TCP_TASK_OFFLOAD, NDIS_TASK_OFFLOAD, NDIS_TASK_OFFLOAD_HEADER


NDIS_TASK_OFFLOAD

When supplied by a miniport driver in response to OID_TCP_TASK_OFFLOAD, the NDIS_TASK_OFFLOAD structure specifies a NIC's capabilities for performing a particular type of task offloaded from the TCP/IP transport. When supplied by the TCP/IP transport in a set of OID_TCP_TASK_OFFLOAD, the NDIS_TASK_OFFLOAD structure specifies an offload task that the TCP/IP transport is enabling.

typedef struct _NDIS_TASK_OFFLOAD
{
  ULONG  Version;
  ULONG  Size;
  NDIS_TASK  Task;
  ULONG  OffsetNextTask;
  ULONG  TaskBufferLength;
  UCHAR  TaskBuffer[1];
} NDIS_TASK_OFFLOAD, *PNDIS_TASK_OFFLOAD;

Members

Version
The version number of this task-offload capability. If the miniport driver's NIC supports more than one version of a particular task-offload capability, each version of the capability should be indicated with a separate NDIS_TASK_OFFLOAD structure. The TCP/IP transport chooses the most suitable version to enable.
Size
Specifies the size in bytes of the NDIS_TASK_OFFLOAD structure. Size is set to sizeof(NDIS_TASK_OFFLOAD) and is used to determine the version of the NDIS_TASK_OFFLOAD structure.
Task
Specifies the type of offload task as one of the following:
TcpIpChecksumNdisTask
Checksum offload. The TaskBuffer contains an NDIS_TASK_TCP_IP_CHECKSUM structure.
IpSecNdisTask
IP Security offload. The TaskBuffer contains an NDIS_TASK_IPSEC structure.
TcpLargeSendNdisTask
Segmentation offload. The TaskBuffer contains an NDIS_TASK_TCP_LARGE_SEND structure.
OffsetNextTask
Specifies in bytes the offset from the beginning of the NDIS_TASK_OFFLOAD_STRUCTURE to the next NDIS_TASK_OFFLOAD structure in the InformationBuffer. If this NDIS_TASK_OFFLOAD structure is the last one in the InformationBuffer, OffsetNextTask is set to 0.
TaskBufferLength
Specifies the size in bytes of the structure at TaskBuffer.
TaskBuffer
Specifies a variable-length array that contains information specific to the offload task indicated by Task. The contents of the TaskBuffer vary according to the Task type:
Task Type | Contents of TaskBuffer
TcpIpChecksumNdisTask | NDIS_TASK_TCP_IP_CHECKSUM structure
IpSecNdisTask | NDIS_TASK_IPSEC structure
TcpLargeSendNdisTask | NDIS_TASK_TCP_LARGE_SEND structure

Headers

Declared in ndis.h. Include ndis.h.

Comments

If a NIC has the appropriate capabilities, the Microsoft TCP/IP transport can offload one or more of the following tasks to a NIC:

  • Calculation and/or validation of IP or TCP checksums
  • IP Security processing
  • Segmentation of large TCP packets into smaller TCP packets

The TCP/IP transport determines a NIC's task-offload capabilities by querying OID_TCP_TASK_OFFLOAD. In response, a miniport driver returns in the InformationBuffer an NDIS_TASK_OFFLOAD_HEADER structure followed by one or more NDIS_TASK_OFFLOAD structures. The TaskBuffer of each NDIS_TASK_OFFLOAD structure contains a task-specific structure (NDIS_TASK_TCP_IP_CHECKSUM, NDIS_TASK_IPSEC, or NDIS_TASK_TCP_LARGE_SEND) that specifies a particular task-offload capability supported by the miniport driver's NIC. If the miniport's NIC supports multiple versions of a particular task-offload capability, it returns one NDIS_TASK_OFFLOAD structure for each version.

After querying a NIC's task-offload capabilities, the TCP/IP transport enables a NIC's task-offload capabilities by setting OID_TCP_TASK_OFFLOAD. In this set operation, the TCP/IP transport supplies in the InformationBuffer an NDIS_TASK_OFFLOAD_HEADER structure followed by an NDIS_TASK_OFFLOAD structure for each offload task that it is enabling. The miniport driver must examine each NDIS_TASK_OFFLOAD structure to determine which offload tasks are being enabled. The miniport driver must also examine the task-specific structure in the TaskBuffer of each NDIS_TASK_OFFLOAD structure to determine which specific capabilities for a particular offload task are being enabled.

See Also

OID_TCP_TASK_OFFLOAD, NDIS_TASK_IPSEC, NDIS_TASK_OFFLOAD_HEADER, NDIS_TASK_TCP_IP_CHECKSUM, NDIS_TASK_TCP_LARGE_SEND


NDIS_TASK_OFFLOAD_HEADER

The NDIS_TASK_OFFLOAD_HEADER structure specifies the encapsulation format for send and receive packets on which a miniport driver may perform tasks offloaded from the TCP/IP transport.

typedef struct _NDIS_TASK_OFFLOAD_HEADER
{
  ULONG  Version;
  ULONG  Size;
  ULONG  Reserved;
  UCHAR  OffsetFirstTask;
  NDIS_ENCAPSULATION_FORMAT  EncapsulationFormat;
} NDIS_TASK_OFFLOAD, *PNDIS_TASK_OFFLOAD;

Members

Version
Specifies the task-offload version supported by the TCP/IP transport. This value is always set to NDIS_TASK_OFFLOAD_VERSION.
Size
Specifies in bytes the size of the NDIS_TASK_OFFLOAD_HEADER structure. Size is set to sizeof(NDIS_TASK_OFFLOAD_HEADER) and is used to determine the version of the NDIS_TASK_OFFLOAD_HEADER structure.
Reserved
This is reserved.
OffsetFirstTask
Specifies in bytes the offset from the beginning of the InformationBuffer to the first NDIS_TASK_OFFLOAD structure. The miniport driver is responsible for setting this value when responding to a query of OID_TCP_TASK_OFFLOAD. The TCP/IP transport is responsible for setting this value when setting OID_TCP_TASK_OFFLOAD. If no NDIS_TASK_OFFLOAD structures are in the InformationBuffer, OffsetFirstTask is set to zero.
EncapsulationFormat
Specifies the encapsulation format for both send and receive packets that are passed to or from the TCP/IP transport through the miniport driver's NIC. This information is formatted as an NDIS_ENCAPSULATION_FORMAT structure, which is defined as follows:
typedef struct _NDIS_ENCAPSULATION_FORMAT
{
   NDIS_ENCAPSULATION  Encapsulation;
   {
      ULONG   FixedHeaderSize:1;
      ULONG   Reserved:31;
   } Flags;
   ULONG     EncapsulationHeaderSize;
} NDIS_ENCAPSULATION_FORMAT,*PNDIS_ENCAPSULATION_FORMAT;

The members of this structure contain the following information:

Encapsulation
Specifies the encapsulation type as one of the following values:

UNSPECIFIED_Encapsulation

An encapsulation type other than those listed below.

NULL_Encapsulation

This is reserved.

IEEE_802_3_Encapsulation

IEEE 802.3 encapsulation (Ethernet_DIX)

IEEE_802_5_Encapsulation

IEEE 802.5 encapsulation

LLC_SNAP_ROUTED_Encapsulation

LLC encapsulation for routed protocols, as described in RFC 1483.
Also used to indicate Ethernet LLC/SNAP encapsulation.

LLC_SNAP_BRIDGE_Encapsulation

This is reserved.

FixedHeaderSize
This is always set to 1 to indicate that the encapsulation header is the same size in each packet.
Reserved
This is reserved.
EncapsulationHeaderSize
Specifies in bytes the size of the encapsulation header. The first IP header in the encapsulated transmit packet starts at this offset from the start of the packet.

Headers

Declared in ndis.h. Include ndis.h.

Comments

When the TCP/IP transport queries OID_TCP_TASK_OFFLOAD, it initializes and passes an NDIS-TASK_OFFLOAD_HEADER structure in the InformationBuffer associated with the query. The miniport driver that receives this query examines the NDIS_TASK_OFFLOAD_HEADER structure to determine the encapsulation format for send and receive packets processed by the TCP/IP transport. The miniport driver or its NIC uses the encapsulation information to determine the format of the encapsulation header, as well as the start of the first IP header, in such packets so that the NIC can perform offload tasks on these packets.

The miniport driver responds to the OID_TCP_TASK_OFFLOAD query by appending one or more NDIS_TASK_OFFLOAD structures to the NDIS_TASK_OFFLOAD_HEADER structure in the InformationBuffer. Each NDIS_TASK_OFFLOAD structure represents an offload task supported by the miniport driver's NIC. The miniport driver sets the OffsetFirstTask member of the NDIS_TASK_OFFLOAD_HEADER structure to the offset in bytes from the start of the InformationBuffer to the first NDIS_TASK_OFFLOAD structure. The miniport driver does not alter any other values in the NDIS_TASK_OFFLOAD_HEADER structure. If the Version, Size, or EncapsulationFormat values specified in the NDIS_TASK_OFFLOAD_HEADER structure are not acceptable to the miniport driver, the miniport driver should fail the OID_TCP_TASK_OFFLOAD query.

To support task offloads for a particular frame type, a miniport driver's NIC must support the appropriate encapsulation type or types. The following table indicates which encapsulation types a miniport driver must support to be able to offload tasks for a given frame type:

Frame Type | Encapsulation Type
Ethernet | IEEE_802_3_Encapsulation
Token Ring | IEEE_802_5_Encapsulation
ATM (CLIP) | LLC_SNAP_ROUTED_Encapsulation
Other | UNSPECIFIED_Encapsulation

A NIC does not have to support the same set of offload tasks for each encapsulation type. For example, an Ethernet NIC can support checksum and IP Security offloads for the IEEE_802_3_Encapsulation type (Ethernet DIX) but only checksum offloads for the LLC_SNAP_ROUTED_Encapsulation type.

A NIC can offload the segmentation of large TCP packets only if

  • It supports the encapsulation format specified by the TCP/IP protocol in the NDIS_TASK_OFFLOAD_HEADER structure
  • Or the specified encapsulation type is UNSPECIFIED_Encapsulation and the EncapsulationHeaderSize is set to the size of the encapsulation header for the media supported by the miniport driver and its NIC

The encapsulation format specified by the TCP/IP transport in the NDIS_TASK_OFFLOAD_HEADER structure applies to both send and receive packets that are passed to or from the TCP/IP transport through the NIC. Only one encapsulation format is supported per NIC at any given time.

To disable all a NIC's task-offload capabilities, the TCP/IP transport sets OID_TCP_TASK_OFFLOAD, passing only an NDIS_TASK_OFFLOAD_HEADER in the InformationBuffer. In this case, the TCP/IP transport sets the OffsetFirstTask member of the NDIS_TASK_OFFLOAD_HEADER to zero.

See Also

NDIS_TASK_OFFLOAD, OID_TCP_TASK_OFFLOAD


NDIS_TASK_TCP_IP_CHECKSUM

When supplied by a miniport driver in response to a query of OID_TCP_TASK_OFFLOAD, the NDIS_TASK_TCP_IP_CHECKSUM structure specifies the miniport driver's NIC's capabilities for calculating IP, TCP, and/or UDP checksums for send packets and validating such checksums for receive packets. When passed to a miniport driver in a set of OID_TCP_TASK_OFFLOAD, the structure specifies the checksum capabilities that the TCP/IP transport is enabling for the NIC.

typedef struct _NDIS_TASK_TCP_IP_CHECKSUM
{
  struct
  {
    ULONG    IpOptionsSupported:1;
    ULONG    TcpOptionsSupported:1;
    ULONG    TcpChecksum:1;
    ULONG    UdpChecksum:1;
    ULONG    IpChecksum:1;
  } V4Transmit;

  struct
  {
    ULONG    IpOptionsSupported:1;
    ULONG    TcpOptionsSupported:1;
    ULONG    TcpChecksum:1;
    ULONG    UdpChecksum:1;
    ULONG    IpChecksum:1;
  } V4Receive;

  struct
  {
    ULONG    IpOptionsSupported:1;
    ULONG    TcpOptionsSupported:1;
    ULONG    TcpChecksum:1;
    ULONG    UdpChecksum:1;
  } V6Transmit;

  struct
  {
    ULONG    IpOptionsSupported:1;
    ULONG    TcpOptionsSupported:1;
    ULONG    TcpChecksum:1;
    ULONG    UdpChecksum:1;
  } V6Receive;
} NDIS_TASK_TCP_IP_CHECKSUM, *PNDIS_TASK_TCP_IP_CHECKSUM;

Members

V4Transmit
IpOptionsSupported
Set by a miniport driver to indicate that its NIC can calculate an IP checksum for an IPv4 send packet that contains IP options.
TcpOptionsSupported
Set by a miniport driver to indicate that its NIC can calculate a TCP checksum for an IPv4 send packet that contains TCP options.
TcpChecksum
Set by a miniport driver to indicate that its NIC can calculate a TCP checksum for an IPv4 send packet. Set by the TCP/IP transport to enable this capability.
UdpChecksum
Set by a miniport driver to indicate that its NIC can calculate a UDP checksum for an IPv4 send packet. Set by the TCP/IP transport to enable this capability.
IpChecksum
Set by a miniport driver to indicate that its NIC can calculate an IP checksum for an IPv4 send packet. Set by the TCP/IP transport to enable this capability.
V4Receive
IpOptionsSupported
Set by a miniport driver to indicate that its NIC can validate an IP checksum for an IPv4 receive packet that contains IP options.
TcpOptionsSupported
Set by a miniport driver to indicate that its NIC can calculate a TCP checksum for an IPv4 receive packet that contains TCP options.
TcpChecksum
Set by a miniport driver to indicate that its NIC can validate the TCP checksum for an IPv4 receive packet. Set by the TCP/IP transport to enable this capability.
UdpChecksum
Set by a miniport driver to indicate that its NIC can validate an IPv4 receive packet's UDP checksum. Set by the TCP/IP transport to enable this capability.
IpChecksum
Set by a miniport driver to indicate that its NIC can validate an IP checksum for an IPv4 receive packet. Set by the TCP/IP transport to enable this capability.
V6Transmit
IpOptionsSupported
Set by a miniport driver to indicate that its NIC can calculate an IP checksum for an IPv6 send packet that contains IP options.
TcpOptionsSupported
Set by a miniport driver to indicate that its NIC can calculate a TCP checksum for an IPv6 send packet that contains TCP options.
TcpChecksum
Set by a miniport driver to indicate that its NIC can calculate a TCP checksum for an IPv6 send packet. Set by the TCP/IP transport to enable this capability.
UdpChecksum
Set by a miniport driver to indicate that its NIC can calculate a UDP checksum for an IPv6 send packet. Set by the TCP/IP transport to enable this capability.
V6Receive
IpOptionsSupported
Set by a miniport driver to indicate that its NIC can validate IP checksum(s) for an IPv6 receive packet whose IP header(s) contains IP options.
TcpOptionsSupported
Set by a miniport driver to indicate that its NIC can calculate a checksum for an IPv6 receive packet whose TCP header contains TCP options.
TcpChecksum
Set by a miniport driver to indicate that its NIC can validate an IPv6 receive packet's TCP checksum. Set by the TCP/IP transport to enable this capability.
UdpChecksum
Set by a miniport driver to indicate that its NIC can validate a UDP checksum for an IPv6 receive packet. Set by the TCP/IP transport to enable this capability.

Headers

Declared in ndis.h. Include ndis.h.

Comments

In response to a query of OID_TCP_TASK_OFFLOAD, a miniport driver returns in the InformationBuffer an NDIS_TASK_OFFLOAD_HEADER structure followed immediately by one or more chained NDIS_TASK_OFFLOAD structures. Each NDIS_TASK_OFFLOAD structure specifies a task-offload capability supported by the miniport driver's NIC.

When the Task member of the NDIS_TASK_OFFLOAD structure specifies TcpIpChecksumNdisTask, the TaskBuffer of the NDIS_TASK_OFFLOAD structure contains an NDIS_TASK_TCP_IP_CHECKSUM structure.

When returned by a miniport driver in response to the TCP/IP transport's query of OID_TCP_TASK_OFFLOAD, the NDIS_TASK_TCP_IP_CHECKSUM structure specifies the miniport driver's capabilities for performing checksum tasks on both send and receive packets. When passed to a miniport driver by the TCP/IP transport's set of OID_TCP_TASK_OFFLOAD, the NDIS_TASK_TCP_IP_CHECKSUM structure specifies the checksum capabilities that the transport is enabling.

The NDIS_TASK_TCP_IP_CHECKSUM structure allows a miniport driver to indicate UDP checksum capabilities. The initial release of Windows® 2000 does not support UDP checksum offloads; however, future service packs and update releases of Windows 2000 may support UDP checksum offloads.

The NDIS_TASK_TCP_IP_CHECKSUM structure also allows a miniport driver to indicate checksum capabilities for IPv6 packets. The TCP/IP transport in the initial release of Windows 2000, however, can process only IPv4 packets and therefore does not enable any IPv6 checksum capabilities reported by a miniport driver. Future versions of the TCP/IP transport may support the processing of IPv6 packets.

See Also

OID_TCP_TASK_OFFLOAD, NDIS_TASK_OFFLOAD, NDIS_TASK_OFFLOAD_HEADER


NDIS_TASK_TCP_LARGE_SEND

When supplied by a miniport driver in response to a query of OID_TCP_TASK_OFFLOAD, the NDIS_TASK_TCP_LARGE_SEND structure specifies the miniport driver's NIC's capabilities for segmenting large TCP packets into smaller packets. When passed to a miniport driver in a set of OID_TCP_TASK_OFFLOAD, the structure specifies the packet-segmentation capabilities that the TCP/IP transport is enabling for the NIC.

typedef struct _NDIS_TASK_TCP_LARGE_SEND
{
  ULONG  Version;
  ULONG  MaxOffLoadSize;
  ULONG  MinSegmentCount;
  BOOLEAN  TcpOptions;
  BOOLEAN  IpOptions;
} NDIS_TASK_TCP_LARGE_SEND, *PNDIS_TASK_TCP_LARGE_SEND;

Members

Version
Miniport drivers should set this to zero.
MaxOffLoadSize
A miniport driver sets this to the maximum bytes of user data that the transport can pass to the miniport driver in a single packet. The transport will not pass a packet to the miniport driver that contains more than MaxOffLoadSize user data bytes. If such a packet must be transmitted, the transport itself segments the packet into smaller packets.
MinSegmentCount
A miniport driver set this to the minimum number of segments that a large TCP packet must be divisible by before the transport can offload it to a NIC for segmentation. The transport will not offload a large packet to the miniport driver for segmentation unless the miniport driver can create at least MinSegmentCount segments from the packet. If a large TCP packet does not meet the minimum-segment requirement, the TCP/IP transport itself segments the packet into smaller packets.
TcpOptions
Set by a miniport driver to indicate that the miniport driver can segment a large TCP packet whose TCP header contains TCP options. Set by the TCP/IP transport to enable this capability.
IpOptions
Set by a miniport driver to indicate that its NIC can segment a large TCP packet whose IP header contains IP options. Set by the TCP/IP transport to enable this capability.

Headers

Declared in ndis.h. Include ndis.h.

Comments

In response to a query of OID_TCP_TASK_OFFLOAD, a miniport driver returns in the InformationBuffer an NDIS_TASK_OFFLOAD_HEADER structure followed immediately by one or more chained NDIS_TASK_OFFLOAD structures. Each NDIS_TASK_OFFLOAD structure specifies a task-offload capability supported by the miniport driver's NIC.

When the Task member of the NDIS_TASK_OFFLOAD structure specifies TcpLargeSendNdisTask, the TaskBuffer of the NDIS_TASK_OFFLOAD structure contains an NDIS_TASK_TCP_LARGE_SEND structure.

When returned by a miniport driver in response to the TCP/IP transport's query of OID_TCP_TASK_OFFLOAD, the NDIS_TASK_TCP_LARGE_SEND structure specifies a NIC's capabilities for segmenting a large TCP packet into smaller TCP packets. When passed to a miniport driver through the TCP/IP transport's set of OID_TCP_TASK_OFFLOAD, the NDIS_TASK_TCP_LARGE_SEND structure specifies the TCP-packet-segmentation capabilities that the transport is enabling.

See Also

OID_TCP_TASK_OFFLOAD, NDIS_TASK_OFFLOAD, NDIS_TASK_OFFLOAD_HEADER


NDIS_TCP_IP_CHECKSUM_PACKET_INFO

The NDIS_TCP_IP_CHECKSUM_PACKET_INFO structure specifies information used in offloading checksum tasks from the TCP/IP transport to a NIC. The NDIS_TCP_IP_CHECKSUM_PACKET_INFO structure is part of the per-packet information (extended out-of-band data) associated with a packet descriptor.

typedef struct _NDIS_TCP_IP_CHECKSUM_PACKET_INFO
{
  union
  {
    struct
    {
      ULONG    NdisPacketChecksumV4:1;
      ULONG    NdisPacketChecksumV6:1;
      ULONG    NdisPacketTcpChecksum:1;
      ULONG    NdisPacketUdpChecksum:1;
      ULONG    NdisPacketIpChecksum:1;
      } Transmit;

    struct
    {
      ULONG   NdisPacketTcpChecksumFailed:1;
      ULONG   NdisPacketUdpChecksumFailed:1;
      ULONG   NdisPacketIpChecksumFailed:1;
      ULONG   NdisPacketTcpChecksumSucceeded:1;
      ULONG   NdisPacketUdpChecksumSucceeded:1;
      ULONG   NdisPacketIpChecksumSucceeded:1;
      ULONG   NdisPacketLoopback:1;
      } Receive;

  ULONG    Value;
  };
} NDIS_TCP_IP_CHECKSUM_PACKET_INFO, *PNDIS_TCP_IP_CHECKSUM_PACKET_INFO;

Members

Transmit
NdisPacketChecksumV4
Set by the TCP/IP transport to indicate that the send packet contains IPv4 addresses. If the transport does not set NdisPacketChecksumV4, the miniport driver should not perform checksum tasks on the packet.
NdisPacketChecksumV6
Set by the TCP/IP transport to indicate that the send packet contains IPv6 addresses. Because the TCP/IP transport in the initial release of Windows 2000 is incapable of processing IPv6 packets, it never sets NdisPacketChecksumV6. Future versions of the TCP/IP transport, however, may support the processing of IPv6 packets.
NdisPacketTcpChecksum
Set by the TCP/IP transport to indicate that that the NIC should calculate the packet's TCP checksum.
NdisPacketUdpChecksum
Set by the TCP/IP transport to indicate that that the NIC should calculate the packet's UDP checksum.
NdisPacketIpChecksum
Set by the TCP/IP transport to indicate that that the NIC should calculate the IP checksum for the first IP header in the packet. If the packet contains both a tunnel IP header and a transport IP header, the NIC should calculate the checksum for the tunnel IP header. The TCP/IP transport calculates the checksum for the transport IP header of such a packet.
Receive
NdisPacketTcpChecksumFailed
Set by the miniport driver to indicate that the TCP checksum calculated by its NIC did not match the checksum in the receive packet's TCP header.
NdisPacketUdpChecksumFailed
Set by the miniport driver to indicate that that the UDP checksum calculated by its NIC did not match the checksum in the receive packet's UDP header. The initial release of Windows 2000 does not support UDP checksum offloads; however, future service packs and update releases of Windows 2000 may support UDP checksum offloads.
NdisPacketIpChecksumFailed
Set by the miniport driver to indicate that the IP checksum calculated by its NIC did not match the checksum in the receive packet's first IP header. If the receive packet contains both a tunnel IP header and a transport IP header, the NIC validates only the checksum for the tunnel IP header. The TCP/IP transport validates the checksum for the transport IP header of such a packet.
NdisPacketTcpChecksumSucceeded
Set by the miniport driver to indicate that the TCP checksum calculated by its NIC matched the checksum in the receive packet's TCP header.
NdisPacketUdpChecksumSucceeded
Set by the miniport driver to indicate that the UDP checksum calculated by its NIC matched the checksum in the receive packet's UDP header.
NdisPacketIpChecksumSucceeded
Set by the miniport driver to indicate that the IP checksum calculated by its NIC matched the checksum in the receive packet's first IP header. If the receive packet contains both a tunnel IP header and a transport IP header, the NIC validates only the checksum for the tunnel IP header. The TCP/IP transport validates the checksum for the transport IP header of such a packet.
NdisPacketLoopback
NDIS uses this bit. The miniport driver must not examine or set this bit; the miniport driver should just ignore this bit.
Value
Checksum value

Headers

Declared in ndis.h. Include ndis.h.

Comments

The NDIS_TCP_IP_CHECKSUM_PACKET_INFO structure specifies information used in offloading checksum tasks from the TCP/IP transport to a NIC. The NDIS_TCP_IP_CHECKSUM_PACKET_INFO structure is part of the per-packet information (extended out-of-band data) associated with a packet descriptor.

Before the TCP/IP transport passes to the miniport driver a packet on which the miniport driver will perform checksum tasks, the TCP/IP transport updates the NDIS_TCP_IP_CHECKSUM_PACKET_INFO structure associated with the packet descriptor. Specifically, the TCP/IP transport sets the NdisPacketChecksumV4 flag to indicate that the send packet contains IPv4 addresses. If the TCP/IP transport does not set this flag, the miniport driver should not perform checksum tasks on the packet. If the TCP/IP transport sets NdisPacketChecksumV4 flag, it also sets NdisPacketTcpChecksum and/or NdisPacketIpChecksum to indicate which checksums the miniport driver should calculate for the packet.

Before indicating up a receive packet on which it performs checksum tasks, a miniport driver sets the appropriate NdisPackeXxxChecksumFailed and/or NdisPacketXxxChecksumSucceeded flags in the NDIS_TCP_IP_CHECKSUM_PACKET_INFO structure.

To obtain a pointer to the NDIS_TCP_IP_CHECKSUM_PACKET_INFO structure, a driver should call the NDIS_PER_PACKET_INFO_FROM_PACKET macro with an InfoType of TcpIpCheckSumPacketInfo. Alternatively, a driver can call the NDIS_PACKET_EXTENSION_FROM_PACKET macro to obtain a pointer to the NDIS_PACKET_EXTENSION structure associated with a given packet descriptor. The miniport driver can then use the TcpIpCheckSumPacketInfo array index to obtain a pointer to the NDIS_TCP_IP_CHECKSUM_PACKET_INFO structure.

See Also

NDIS_PACKET_EXTENSION, NDIS_PACKET_EXTENSION_FROM_PACKET, NDIS_PER_PACKET_INFO_FROM_PACKET


NDIS_WAN_CO_FRAGMENT

The NDIS_WAN_CO_FRAGMENT structure contains information associated with a fragment indication made by a CoNDIS WAN miniport driver.

typedef struct _NDIS_WAN_CO_FRAGMENT {
  IN ULONG  Errors;
} NDIS_WAN_CO_FRAGMENT, *PNDIS_WAN_CO_FRAGMENT;

Members

Errors
A 32-bit value that specifies a bitmask that is set with one or more of the following system-defined values to indicate why the fragment was received. The miniport driver can set a combination of the following values, using the binary OR operator:
WAN_ERROR_CRC
Specifies a CRC error was encountered for a particular VC. CRC errors are caused by the failure of a cyclic redundancy check. A CRC error indicates that one or more bytes in a frame received were found garbled on arrival.
WAN_ERROR_FRAMING
Specifies a framing error was encountered for a particular VC. A framing error occurs when an asynchronous byte is received with an invalid start or stop bit.
WAN_ERROR_HARDWAREOVERRUN
Specifies a hardware overrun was encountered for a particular VC. Hardware overruns occur when the WAN NIC cannot handle the rate at which data is received.
WAN_ERROR_BUFFEROVERRUN
Specifies a buffer overrun was encountered for a particular VC. Buffer overruns occur when the WAN miniport driver cannot handle the rate at which data is received.
WAN_ERROR_TIMEOUT
Specifies a time-out error was encountered for a particular VC. Time-out errors occur when an expected byte is not received in time.
WAN_ERROR_ALIGNMENT
Specifies an alignment error was encountered for a particular VC. Alignment errors occur when a byte received is different from the byte expected. This typically happens when a byte is lost or when a time-out error occurs.

If no direct mapping from the WAN medium error to one of the preceding error flags exists, choose the most appropriate flag or combination of flags.

Headers

Declared in ndis.h. Include ndis.h.

Comments

A CoNDIS WAN miniport driver calls NdisMCoIndicateStatus with this type of indication when it receives a partial packet from an endpoint of a virtual connection on the wide area network.

See Also

NdisMCoIndicateStatus, NDIS_WAN_FRAGMENT


NDIS_WAN_FRAGMENT

The NDIS_WAN_FRAGMENT structure contains information associated with a fragment indication.

typedef struct _NDIS_WAN_FRAGMENT {
  IN UCHAR  RemoteAddress[6];
  IN UCHAR  LocalAddress[6];
} NDIS_WAN_FRAGMENT, *PNDIS_WAN_FRAGMENT;

Members

RemoteAddress
Specifies the address of the remote node in Ethernet-style format, as set up when the link was established in the initial line-up indication.
LocalAddress
Specifies the address of the remote node in Ethernet-style format, as set up when the link was established in the initial line-up indication.

Headers

Declared in ndis.h. Include ndis.h.

Comments

When a WAN miniport driver calls NdisMIndicateStatus with a fragment indication, NDISWAN forwards the indication to interested protocol(s), formatted in this structure.

See Also

NDIS_MAC_FRAGMENT, NdisMIndicateStatus, NDIS_WAN_LINE_DOWN, NDIS_WAN_LINE_UP, ProtocolStatus


NDIS_WAN_LINE_DOWN

The NDIS_WAN_LINE_DOWN structure contains information associated with a line-down indication.

typedef struct _NDIS_WAN_LINE_DOWN {
  IN UCHAR  RemoteAddress[6];
  IN UCHAR  LocalAddress[6];
} NDIS_WAN_LINE_DOWN, *PNDIS_WAN_LINE_DOWN;

Members

RemoteAddress
Specifies the address of the remote node in Ethernet-style format, as set up when the link was established in the initial line-up indication.
LocalAddress
Specifies the address of the remote node in Ethernet-style format, as set up when the link was established in the initial line-up indication.

Headers

Declared in ndis.h. Include ndis.h.

Comments

When a WAN miniport driver calls NdisMIndicateStatus with a line-down indication, NDISWAN forwards the indication to interested protocol(s), formatted in this structure.

See Also

NDIS_MAC_LINE_DOWN, NdisMIndicateStatus, NDIS_WAN_FRAGMENT, NDIS_WAN_LINE_UP, ProtocolStatus


NDIS_WAN_LINE_UP

The NDIS_WAN_LINE_UP structure contains information associated with a line-up indication.

typedef struct _NDIS_WAN_LINE_UP {
  IN ULONG  LinkSpeed;
  IN ULONG  MaximumTotalSize;
  IN NDIS_WAN_QUALITY  Quality;
  IN USHORT  SendWindow;
  IN UCHAR  RemoteAddress[6];
  IN OUT UCHAR  LocalAddress[6];
  IN ULONG  ProtocolBufferLength;
  IN PUCHAR  ProtocolBuffer;
  IN USHORT  ProtocolType;
  IN OUT NDIS_STRING  DeviceName;
} NDIS_WAN_LINE_UP, *PNDIS_WAN_LINE_UP;

Members

LinkSpeed
Specifies the speed of the link, in units of 100 bps. Zero indicates no change from the speed returned when the protocol called NdisRequest with OID_GEN_LINK_SPEED.
MaximumTotalSize
Specifies the maximum number of bytes per packet that the protocol can send over the network. Zero indicates no change from the value returned when the protocol called NdisRequest with OID_GEN_MAXIMUM_TOTAL_SIZE.
Quality
Specifies the quality of service (QOS) of the new line.
SendWindow
Specifies the underlying WAN NIC driver's send window, effectively its limit on outstanding send packets it will handle for this link. After submitting this number of packets to MiniportWanSend, NDISWAN will hold incoming sends queued until the driver completes an outstanding send.
RemoteAddress
Represents the address of the remote node on the link in Ethernet-style format. NDISWAN supplies this value.
LocalAddress
Represents the protocol-determined context for indications on this link in Ethernet-style format. NDISWAN reserves the two high-order bytes for its own use; the protocol should set the remainder to whatever should be the input parameter for this link to its ProtocolReceive and ProtocolStatus functions thereafter.
ProtocolBufferLength
Specifies the number of bytes in the buffer at ProtocolBuffer.
ProtocolBuffer
Pointer to a buffer, allocated by NDISWAN, containing protocol-specific information supplied by a higher-level component that makes connections through NDISWAN to the appropriate protocol(s). For example, this buffer would contain an IP address if the target protocol is IP or an IPX network number if the target protocol is IPX. NDISWAN frees this buffer when the target protocol returns control from the line-up indication.
ProtocolType
Specifies the assigned ether type of the protocol.
DeviceName
Specifies the name of the binding as a counted string in the system-default character set. For Windows® 2000 and later drivers, this string contains Unicode characters. That is, for Windows 2000 and later, NDIS defines the NDIS_STRING type as a UNICODE_STRING type. This string can be at most 64 characters.

Headers

Declared in ndis.h. Include ndis.h.

Comments

When a WAN miniport driver calls NdisMIndicateStatus with a line-up indication, NDISWAN forwards the indication to interested protocol(s), formatted in this structure. At the initial line-up indication for a given link, the protocol should save any necessary state for subsequent communications on the link, including possible line-up, line-down, and fragment indications.

Subsequently, the protocol can use the SendWindow value as its upper bound on the number of calls it makes to NdisSend for this link before the protocol regains ownership of at least one of the packets it sent down to the underlying WAN NIC driver. Some NICs achieve higher throughput if they have several packets to send at once. Others could become unreliable if their drivers are flooded with send packets. NDISWAN also uses the miniport-set SendWindow value in this manner.

NDISWAN uses Ethernet-style address format to communicate with protocols, so the pair of Xxx Address members of this structure are six-byte addresses, used as follows:

  • NDISWAN uses the RemoteAddress to designate a particular link-protocol context. At the initial line-up indication for a link, the protocol should save the RemoteAddress supplied by NDISWAN. Subsequently, the protocol passes the RemoteAddress value to NDISWAN in calls to NdisSend for transmissions on this link.
  • The protocol uses LocalAddress to set up context for itself in the low-order four bytes (&LocalAddress[2]) when it receives the initial line-up indication for a link being established. Subsequently, NDISWAN passes the LocalAddress to the protocol at receive and status indications. In effect, NDISWAN uses the given LocalAddress as the destination for incoming receives and status indications on the link thereafter.

The DeviceName member is used with stacks in which a lower-level protocol has a single binding to NDISWAN but several bindings between it and a higher-level protocol in the stack, and this member might be used to support future PnP scenarios. That is, DeviceName would be used for either of the following:

  • To identify the binding (IN) to which a lower protocol should propagate the line-up indication it is given by NDISWAN
  • In a PnP environment, to report back (OUT) to NDISWAN the name of a newly created binding set up by a lower protocol at a line-up indication

See Also

MiniportQueryInformation, MiniportSetInformation, NDIS_MAC_LINE_UP, NdisMIndicateStatus, NdisRequest, NDIS_WAN_FRAGMENT, NDIS_WAN_LINE_DOWN, ProtocolStatus, UNICODE_STRING


NDIS_WAN_PACKET

The NDIS_WAN_PACKET structure defines the packet passed to the MiniportWanSend functions of WAN drivers.

typedef struct _NDIS_WAN_PACKET {
  LIST_ENTRY  WanPacketQueue;
  PUCHAR  CurrentBuffer;
  ULONG  CurrentLength;
  PUCHAR  StartBuffer;
  PUCHAR  EndBuffer;
  PVOID  ProtocolReserved1;
  PVOID  ProtocolReserved2;
  PVOID  ProtocolReserved3;
  PVOID  ProtocolReserved4;
  PVOID  MacReserved1;
  PVOID  MacReserved2;
  PVOID  MacReserved3;
  PVOID  MacReserved4;
} NDIS_WAN_PACKET, *PNDIS_WAN_PACKET;

Members

WanPacketQueue
Specifies the head of the send packet queue, used by MiniportWanSend while the miniport driver is processing this packet.
CurrentBuffer
Specifies the base virtual address within the given buffer at which the net packet to be transmitted starts.
CurrentLength
Specifies the number of bytes of network packet data.
StartBuffer
Specifies the base virtual address for the given buffer, including padding.
EndBuffer
Specifies the virtual address for the end of the given buffer, including padding.
ProtocolReserved1
Specifies members reserved for use by protocols.
ProtocolReserved2
Specifies members reserved for use by protocols.
ProtocolReserved3
Specifies members reserved for use by protocols.
ProtocolReserved4
Specifies members reserved for use by protocols.
MacReserved1
Specifies members that the miniport driver can use for its own purposes.
MacReserved2
Specifies members that the miniport driver can use for its own purposes.
MacReserved3
Specifies members that the miniport driver can use for its own purposes.
MacReserved4
Specifies members that the miniport driver can use for its own purposes.

Headers

Declared in ndis.h. Include ndis.h.

Comments

When a protocol calls NdisSend with an NDIS_PACKET-type transmit request for an underlying WAN NIC driver, NDISWAN transforms the given packet into a packet formatted as this structure before calling the underlying driver's MiniportWanSend function.

The StartBuffer and EndBuffer pointers specify a discrete virtual range. CurrentBuffer and CurrentLength specify a proper subrange of the range specified by StartBuffer and EndBuffer. Consequently, one of the following formulas yields the number of bytes of header or tail padding, if any, for the buffer passed in this structure to MiniportWanSend:

  • HeaderPadding = CurrentBuffer - StartBuffer
  • TailPadding = EndBuffer - (CurrentBuffer + CurrentLength)

NDISWAN always gives the underlying NIC driver at least as much header and tail padding as the driver returned in response to the OID_WAN_GET_INFO query during initialization.

MiniportWanSend can manipulate the buffer data in any manner. Until it completes a given send packet, either by returning a status other than NDIS_STATUS_PENDING from MiniportWanSend or by calling NdisMWanSendComplete, the NIC driver retains ownership of the given packet and of everything it specifies except the ProtocolReserved X members.

See Also

MiniportQueryInformation, MiniportWanSend, NdisMWanSendComplete, NdisSend


NET_PNP_EVENT for Protocol Drivers

The NET_PNP_EVENT structure describes a Plug and Play event or a Power Management event.

typedef struct _NET_PNP_EVENT {
  NET_PNP_EVENT_CODE  NetEvent;
  PVOID  Buffer;
  ULONG  BufferLength;
  ULONG_PTR  NdisReserved[4];
  ULONG_PTR  TransportReserved[4];
  ULONG_PTR  TdiReserved[4];
  ULONG_PTR  TdiClientReserved[4];
} NET_PNP_EVENT, *PNET_PNP_EVENT;

Members

NetEvent
An event code that describes the Plug and Play or Power Management event as one of the following:
NetEventSetPower
Indicates that the Power Manager has sent a Set Power request, which specifies a transition to a system power state. NDIS translates this state to an appropriate device power state for the device.
NetEventQueryPower
Indicates that the Power Manager has sent a Query Power request, which requests a transition to a system power state. NDIS translates this state to an appropriate device power state for the device.
NetEventQueryRemoveDevice
Indicates that the Plug and Play Manager has sent a Query Remove Device request. The Plug and Play Manager sends this request to query whether a device can be removed without disrupting operations.
NetEventCancelRemoveDevice
Indicates that the Plug and Play Manager has sent a Cancel Remove Device request. The PnP Manager sends this request after sending an a Query Remove Device request to cancel the removal of the device.
NetEventReconfigure
Indicates that the configuration has changed for a network component. For example, if a user, through the Network and Dial-up Connections folder , changes the IP address for TCP/IP, NDIS indicates this event to the TCP/IP protocol with the NetEventReconfigure code.
NetEventBindList
Indicates to a protocol driver that its bind list processing order has been reconfigured. This list indicates a relative order to be applied to the protocol's bindings when processing, for example, a user request that might be routed to one of several bindings. The buffer passed with this event contains a list of device names formatted as NULL-terminated Unicode strings. The format of each device name is identical to the DeviceName parameter passed to a call to ProtocolBindAdapter.
NetEventBindsComplete
Indicates that a protocol driver has bound to all the NICs that it can bind to. NDIS will not indicate any more NICs to the protocol unless a Plug and Play NIC is plugged into the system.
NetEventPnPCapabilities
Indicates whether the wake-up capabilities of the NIC on the specified binding have changed. (The binding is specified by the ProtocolBindingContext passed to ProtocolPnPEvent.)
Buffer
Specifies the address of a buffer that contains information specific to the Plug and Play or Power Management event indicated by NetEvent.
NetEventSetPower
The buffer contains the device power state to which the device is transitioning.

When NDIS calls a protocol's ProtocolPnPEvent function, the device state is an NDIS_DEVICE_POWER_STATE, which can be one of the following values:

NdisDeviceStateUnspecified

The network device does not support power management.

NdisDeviceStateD0

The fully powered state, in which the device delivers full functionality and performance.

NdisDeviceStateD1

A low-power state, in which transmit requests from the host are not honored by the device, data received by the device is not transferred to host memory, and no interrupts can occur. Some device context may be lost. Depending on the capabilities of the NIC and its miniport driver, the device may be able to generate a wake-up signal.

NdisDeviceStateD2

A low-power state similar to NdisDeviceStateD1, except that usually more power and less context are saved, and more time is required to transition to the fully powered state.

NdisDeviceStateD3

The off state, in which power has been fully removed from the device.

As far as a protocol is concerned, NdisDeviceStateD0 means that the NIC is fully powered and is available for sending and receiving packets. Any other device state means that the device is not fully powered and is not available for sending and receiving packets.

NetEventQueryPower
The buffer contains the device power state requested for the device. The device state is an NDIS_DEVICE_POWER_STATE (described above).
NetEventQueryRemoveDevice
The buffer contents are NULL.
NetEventCancelRemoveDevice
The buffer contents are NULL.
NetEventReconfigure
The buffer contents are NULL.
NetEventBindList
The buffer contains a revised binding list for the network component to which the NET_PNP_EVENT structure is being passed. The bind list, which is a series of NULL-terminated Unicode strings, has a REG_MULTI_SZ format. Each of these strings is an adapter name TDI clients bound to a protocol use this bind list to reorder their bindings.
NetEventBindsComplete
The buffer contents are NULL.
NetEventPnPCapbilities
The buffer contains a ULONG that contains the NdisDeviceWakeUpEnable flag. When set to 1, this flag indicates that the wake-up capabilities of the NIC on the specified binding are enabled. (The binding is specified by the ProtocolBindingContext passed to ProtocolPnPEvent.) When set to zero, this flag indicates that the NIC's wake-up capabilities are disabled.
BufferLength
The number of bytes of event-specific information at Buffer.
NdisReserved
An area reserved for used by NDIS.
TransportReserved
An area reserved for used by the transport driver.
TdiReserved
An area reserved for used by TDI.
TdiClientReserved
An area reserved for used by a TDI client.

Headers

Declared in ndis.h. Include ndis.h.

Comments

When the operating system issues a Plug and Play event or a Power Management event to a target device object that represents a NIC, NDIS intercepts the event, translates it into a NET_PNP_EVENT structure, and passes a pointer to this structure to each protocol bound to the NIC by calling the protocol's ProtocolPnPEvent function. The protocol should save this pointer, because the pointer is an input parameter to NdisCompletePnPEvent, which the driver calls to complete the call to ProtocolPnPEvent asynchronously.

NDIS can also call the ProtocolPnPEvent function of a particular protocol driver to notify that driver of a NetEventBindsComplete event. This event indicates to the protocol driver that it has bound to all the NICs that it can bind to in the system.

The NetEvent code in the structure identifies the type of Plug and Play or Power Management event. The Buffer contains information specific to the type of event.

Transports typically use the TransportReserved area to maintain state concerning the Plug and Play event or Power Management event.

See Also

NdisCompletePnPEvent, ProtocolPnPEvent


SCATTER_GATHER_LIST

The SCATTER_GATHER_LIST structure specifies an array of SCATTER_GATHER_ELEMENT structures, each of which specifies the base physical address and length of a contiguous range of DMA data to be transferred.

typedef struct _SCATTER_GATHER_LIST {
  ULONG  NumberOfElements;
  UINT_PTR  Reserved;
  SCATTER_GATHER_ELEMENT  Elements[];
} SCATTER_GATHER_LIST, *PSCATTER_GATHER_LIST;

Members

NumberOfElements
Specifies the number of SCATTER_GATHER_ELEMENT structures in the buffer at Elements.
Reserved
This is reserved.
Elements
Specifies an array of SCATTER_GATHER_ELEMENT structures, in which each element is defined as follows:
typedef struct _SCATTER_GATHER_ELEMENT {
    PHYSICAL_ADDRESS Address;
    ULONG Length;
    UINT_PTR Reserved;
} SCATTER_GATHER_ELEMENT, *PSCATTER_GATHER_ELEMENT;

The members of this structure contain the following information.

Address
Specifies the base physical address of a contiguous range of data to be transferred.
Length
Specifies the number of bytes in the mapped range.
Reserved
This is reserved.

Headers

Declared in ndis.h. Include ndis.h.

Comments

A deserialized or connection-oriented miniport driver that manages a bus-master DMA NIC and that calls NdisMInitializeScatterGatherDma during DMA initialization calls NDIS_PER_PACKET_INFO_FROM_PACKET with an InfoType of ScatterGatherListPacketInfo to obtain the physical addresses of mapped virtual ranges

When a deserialized or connection-oriented miniport driver that manages a bus-master DMA NIC calls NDIS_PER_PACKET_INFO_FROM_PACKET with an InfoType of ScatterGatherListPacketInfo, it is passed a pointer to a SCATTER_GATHER_LIST structure. The SCATTER_GATHER_LIST structure specifies an array of SCATTER_GATHER_ELEMENT structures, each of which specifies the base physical address and length of a contiguous range of DMA data to be transferred. The miniport driver supplies this address and length information to its bus-master DMA NIC so that the NIC can perform a DMA transfer.

The mapping specified by the array of SCATTER_GATHER_ELEMENT structures is valid until the miniport driver calls NdisMSendComplete or NdisMCoSendComplete.

Only deserialized and connection-oriented miniports that call NdisMInitializeScatterGatherDma during DMA initialization obtain the physical addresses of mapped DMA buffers in this way.

See Also

NdisMInitializeScatterGatherDma, NDIS_PACKET_EXTENSION_FROM_PACKET, NDIS_PER_PACKET_INFO_FROM_PACKET


WAN_CO_LINKPARAMS

The WAN_CO_LINKPARAMS structure describes status associated with the virtual connection (VC) on a WAN NIC. This VC status is indicated up to higher-layer drivers by a CoNDIS WAN miniport.

typedef struct _WAN_CO_LINKPARAMS {
  ULONG  TransmitSpeed;
  ULONG  ReceiveSpeed;
  ULONG  SendWindow;
} WAN_CO_LINKPARAMS, *PWAN_CO_LINKPARAMS;

Members

TransmitSpeed
Specifies the speed at which the WAN miniport driver can transmit data over the network on this VC. This speed is in units of bytes per second.

NDISWAN defaults a TransmitSpeed of zero to 28.8 kilobits per second (Kbps).

ReceiveSpeed
Specifies the speed at which the WAN miniport driver can receive data from the network on this VC. This speed is in units of bytes per second.

NDISWAN defaults a ReceiveSpeed of zero to 28.8 Kbps.

SendWindow
Specifies the number of send packets the WAN miniport driver (or its NIC) can accept at a time, effectively how many NDIS_PACKET-type send packets the WAN miniport driver queues internally. Zero indicates that the WAN miniport driver cannot queue any send packets; that is, the "send window" between NDISWAN and the miniport driver is closed. If SendWindow is set to zero, the WAN miniport driver indicates that it cannot accept packets for the particular VC; therefore, NDISWAN must stop sending packets for that VC.

Headers

Declared in ndis.h. Include ndis.h.

Comments

A CoNDIS WAN NIC driver calls NdisMCoIndicateStatus with this type of indication after a VC between two communicating endpoints, such as two connection-oriented clients, in a wide area network becomes active. After such a VC is activated, the NIC driver makes this indication with the handle to the VC if connection characteristics change. For example, a NIC driver can make this indication if the originally specified TransmitSpeed of the connection changes. The NIC driver might also make this indication to dynamically change the value of SendWindow, which specifies the number of outstanding sends the NIC driver accepts for its internal queue.

After NDISWAN has submitted the number of packets specified in SendWindow to MiniportCoSendPackets, NDISWAN holds incoming send packets queued until the miniport driver returns a completed send packet or calls NdisMCoSendComplete with a packet for which it previously returned NDIS_STATUS_PENDING, whichever occurs first. Subsequent WAN_CO_LINKPARAMS structures can be indicated with calls to NdisMCoIndicateStatus if the NIC driver needs to change the SendWindow value dynamically.

Whenever WAN_CO_LINKPARAMS indications are made, whether to change the SendWindow value or for changes in VC characteristics, the NdisVcHandle parameter that is passed to NdisMCoIndicateStatus must be filled with the value that was set in the driver's MiniportCoCreateVc function. The miniport driver must also supply this handle when it makes any subsequent NDIS_WAN_CO_FRAGMENT indications for the same VC.

See Also

MiniportCoCreateVc, MiniportCoSendPackets, MiniportQueryInformation, NdisMCoIndicateStatus, NdisMCoSendComplete, NDIS_WAN_CO_FRAGMENT, OID_WAN_CO_GET_INFO


Structures Used by ATM NDIS Drivers

This section describes NDIS-defined and system-defined structures that are multifunction or alternative structure parameters. That is, either pointers to these structures are passed in calls to more than one Ndis Xxx, MiniportXxx, and/or ProtocolXxx function, or a pointer to more than one of these structures can be passed in calls to the same function.

For more information about structures for which a pointer is passed only to a single Ndis Xxx, MiniportXxx, or ProtocolXxx function, see the documentation for that function.

For more information about OID-specific structures at the InformationBuffer passed to NdisCoRequest, see NDIS Object Identifiers.

The structures described in this section are listed in alphabetic order.


AAL_PARAMETERS_IE

The AAL_PARAMETERS_IE structure specifies the AAL parameters element of an ATM UNI signaling message. The AAL parameters indicate the requested AAL parameter values for a VC.

typedef struct _AAL_PARAMETERS_IE
{
  ATM_AAL_TYPE  AALType;
  union
  {
        AAL1_PARAMETERS  AAL1Parameters;
        AAL34_PARAMETERS  AAL34Parameters;
        AAL5_PARAMETERS  AAL5Parameters;
        AALUSER_PARAMETERS  AALUserParameters;
    } AALSpecificParameters;
} AAL_PARAMETERS_IE, *PAAL_PARAMETERS_IE;

Members

AALType
Specifies the ATM Adaptation Layer (AAL) type as one of the following values:
AAL_TYPE_AAL0
AAL 0
AAL_TYPE_AAL1
AAL 1
AAL_TYPE_AAL34
AAL 3/4
AAL_TYPE_AAL5
AAL 5
AAL1Parameters
AAL1 parameters formatted as an AAL1_PARAMETERS structure. For more information, see AAL1_PARAMETERS.
AAL34Parameters
AAL 3/4 parameters formatted as an AAL34_PARAMETERS structure. For more information, see AAL34_PARAMETERS.
AAL5Parameters
AAL 5 parameters formatted as an AAL5_PARAMETERS structure. For more information, see AAL5_PARAMETERS.
AALUserParameters
User-defined AAL parameters formatted as an AALUSER_PARAMETERS structure. For more information, see AALUSER_PARAMETERS.

Headers

Declared in atm.h. Include atm.h.

Comments

AAL_PARAMETERS_IE is an information element that specifies ATM Adaptation Layer (AAL) parameters. AAL parameters can be included in a set of Q.2931 call manager-specific parameters.

The specified AAL parameters must match the specified AAL type. For example, if AAL_TYPE_AAL5 is specified as the AALType, AAL5Parameters must be specified.

AAL_PARAMETERS_IE is passed at IE in a Q2931_IE structure, which is passed at InfoElements in a Q2931_CALLMGR_PARAMETERS structure.

For more information on AAL parameters, see the User Network Interface (UNI) Specification published by the ATM Forum.

See Also

AAL1_PARAMETERS, AAL34_PARAMETERS, AAL5_PARAMETERS, AALUSER_PARAMETERS, Q2931_IE, Q2931_CALLMGR_PARAMETERS


AAL1_PARAMETERS

The AAL1_PARAMETERS structure specifies AAL 1 parameters.

typedef struct _AAL1_PARAMETERS
{
  UCHAR  Subtype;
  UCHAR  CBRRate;
  USHORT  Multiplier;
  UCHAR  SourceClockRecoveryMethod;
  UCHAR  ErrorCorrectionMethod;
  USHORT  StructuredDataTransferBlocksize;
  UCHAR  PartiallyFilledCellsMethod;
} AAL1_PARAMETERS, *PAAL1_PARAMETERS;

Members

Subtype
Specifies the Subtype
CBRRate
Specifies the CBR Rate
Multiplier
Specifies the Multiplier
SourceClockRecoveryMethod
Specifies the Source Clock Frequency Recovery Method
ErrorCorrectionMethod
Specifies the Error Correction Method
StructuredDataTransferBlocksize
Specifies the Structured Data Transfer Block size
PartiallyFilledCellsMethod
Specifies the Partially Filled Cells Method

Headers

Declared in atm.h. Include atm.h.

Comments

AAL1_PARAMETERS is a member of an AAL_PARAMETERS_IE structure.

For definitions and information on AAL 1 parameters, see the User Network Interface (UNI) Specification published by the ATM Forum.

See Also

AAL_PARAMETERS_IE


AAL34_PARAMETERS

The AAL34_PARAMETERS structure specifies AAL 3/4 parameters.

typedef struct _AAL34_PARAMETERS
{
  USHORT  ForwardMaxCPCSSDUSize;
  USHORT  BackwardMaxCPCSSDUSize;
  USHORT  LowestMID;
  USHORT  HighestMID;
  UCHAR  SSCSType;
} AAL34_PARAMETERS, *PAAL34_PARAMETERS;

Members

ForwardMaxCPCSSDUSize
Specifies in bytes the Forward Maximum CPCS-SDU Size.
BackwardMaxCPCSSDUSize
Specifies in bytes the Backward Maximum CPCS-SDU Size.
LowestMID
Specifies the lowest value of the MID range.
HighestMID
Specifies the highest value of the MID range.
SSCSType
Specifies the SSCS Type.

Headers

Declared in atm.h. Include atm.h.

Comments

AAL34_PARAMETERS is a member of an AAL_PARAMETERS_IE structure.

For definitions and information on the encoding of AAL 1 parameters, see the User Network Interface (UNI) Specification published by the ATM Forum.

See Also

AAL_PARAMETERS_IE


AAL5_PARAMETERS

The AAL5_PARAMETERS structure specifies AAL 5 parameters.

typedef struct _AAL5_PARAMETERS
{
  ULONG  ForwardMaxCPCSSDUSize;
  ULONG  BackwardMaxCPCSSDUSize;
  UCHAR  Mode;
  UCHAR  SSCSType;
} AAL5_PARAMETERS, *PAAL5_PARAMETERS;

Members

ForwardMaxCPCSSDUSize
Specifies in bytes the Forward Maximum CPCS-SDU Size.
BackwardMaxCPCSSDUSize
Specifies in bytes the Backward Maximum CPCS-SDU Size.
Mode
Specifies the AAL 5 mode as one of the following values:
AAL5_MODE_MESSAGING
Messaging mode
AAL5_MODE_STREAMING
Streaming mode
SSCSType
Specifies the Service Specific Convergence Sublayer (SSCS) type as one of the following values:
AAL5_SSCS_NULL
NULL
AAL5_SSCS_SSCOP_ASSURED
Data SSCS based on SSCOP (assured operation)
AAL5_SSCS_SSCOP_NON_ASSURED
Data SSCS based on SSCOP (non-assured operation)
AAL5_SSCS_FRAME_RELAY
Frame relay SSCS

Headers

Declared in atm.h. Include atm.h.

Comments

AAL5_PARAMETERS is a member of an AAL_PARAMETERS_IE structure.

For information on AAL 1 parameters, see the User Network Interface (UNI) Specification published by the ATM Forum.

See Also

AAL_PARAMETERS_IE


AALUSER_PARAMETERS

The AALUSER_PARAMETERS structure specifies user-defined AAL information.

typedef struct _AALUSER_PARAMETERS
{
  ULONG  UserDefined;
} AALUSER_PARAMETERS, *PAALUSER_PARAMETERS;

Members

UserDefined
Specifies user-defined flags.

Headers

Declared in atm.h. Include atm.h.

Comments

AAL_USER_PARAMETERS is a member in an AAL_PARAMETERS_IE structure.

The UserDefined flags are used and encoded according to user-defined requirements.

See Also

AAL_PARAMETERS_IE


ATM_AAL_OOB_INFO

The ATM_AAL_OOB_INFO structure specifies the out-of-band (OOB) information for an ATM packet.

typedef struct _ATM_AAL_OOB_INFO
{
    ATM_AAL_TYPE  AalType;
    union
    {
        struct _ATM_AAL5_INFO
        {
            BOOLEAN  CellLossPriority;
            UCHAR      UserToUserIndication;
            UCHAR      CommonPartIndicator;
        } ATM_AAL5_INFO;

        struct _ATM_AAL0_INFO
        {
            BOOLEAN  CellLossPriority;
            UCHAR      PayLoadTypeIdentifier;
        } ATM_AAL0_INFO;
    };
} ATM_AAL_OOB_INFO, *PATM_AAL_OOB_INFO;

Members

AalType
Specifies the ATM Adaptation Layer (AAL) type as one of the following values:
AAL_TYPE_AAL0
AAL 0
AAL_TYPE_AAL5
AAL 5
CellLossPriority
Specifies the Cell Loss Priority as one of the following values:
FALSE
CLP=0
TRUE
CLP=1
UserToUserIndication
Specifies the User to User Indication
CommonPartIndicator
Specifies the Common Part Indicator
CellLossPriority
Specifies the Cell Lost Priority
PayLoadTypeIdentifier
Specifies the Payload Type Identifier

Headers

Declared in atm.h. Include atm.h.

Comments

ATM_AAL_OOB_INFO specifies out-of-band information for an AAL 5 or an AAL 0 packet.

ATM_AAL_OOB_INFO is passed in a buffer pointed to by the MediaSpecificInformation member of an NDIS_PACKET_OOB_DATA structure. NDIS_PACKET_OOB_DATA specifies out-of-band information associated with a packet descriptor. For more information on OOB data, see NDIS_PACKET_OOB_DATA.

See Also

NDIS_PACKET_OOB_DATA


ATM_ADDRESS

The ATM_ADDRESS structure specifies an ATM address.

typedef struct _ATM_ADDRESS
{
  ATM_ADDRESSTYPE  AddressType;
  ULONG  NumberOfDigits;
  UCHAR  Address[ATM_ADDRESS_LENGTH];
} ATM_ADDRESS, *PATM_ADDRESS;

Members

AddressType
Specifies the format of the ATM address. A value of ATM_NSAP specifies an ATM Endstation Address (NSAP format). A value of ATM_E164 specifies an E.164 address (telephony format).
NumberOfDigits
Indicates the number of digits in the ATM address.
Address[ATM_ADDRESS_LENGTH]
An array that contains the ATM address.

Headers

Declared in atm.h. Include atm.h.

Comments

ATM_ADDRESS is a member of numerous ATM structures, including ATM_CALLING_PARTY_NUMBER_IE, ATM_PVC_SAP, ATM_SAP, Q2931_ADD_PVC, AND Q2931_CALLMGR_PARAMETERS.

ATM_ADDRESS is also passed by OID_ATM_LECS_ADDRESS and OID_ATM_SERVICE_ADDRESS.

See Also

ATM_CALLING_PARTY_NUMBER_IE, ATM_PVC_SAP, ATM_SAP, OID_ATM_LECS_ADDRESS, OID_ATM_SERVICE_ADDRESS, Q2931_ADD_PVC, Q2931_CALLMGR_PARAMETERS


ATM_BHLI_IE

The ATM_BHLI_IE structure specifies broadband high-layer information, which indicates the means that should be used for compatibility checking by an addressed entity (for example, a remote user, an interworking unit, or a high-layer function network node addressed by the calling user).

typedef struct _ATM_BHLI_IE
{
  ULONG  HighLayerInfoType;
  ULONG  HighLayerInfoLength;
  UCHAR  HighLayerInfo[8];
} ATM_BHLI_IE, *PATM_BHLI_IE;

Members

HighLayerInfoType
Specifies the High Layer Information Type as one of the following values:
BHLI_ISO
ISO
BHLI_UserSpecific
User Specific
BHLI_HighLayerProfile
High Layer Profile (only in UNI3.0)
BHLI_VendorSpecificAppId
Vendor Specific Application identifier
HighLayerInfoLength
Specifies the size in bytes of the buffer at HighLayerInfo.
HighLayerInfo[8]
Specifies the High Layer Information. The contents depend on the specified High Layer Information Type.

Headers

Declared in atm.h. Include atm.h.

Comments

ATM_BHLI_IE is a member of an ATM_PVC_SAP structure or an ATM_SAP structure. ATM_PVC_SAP specifies ATM-specific SAP information for a PVC. ATM_SAP specifies ATM-specific SAP information for a switched (SVC).

ATM_BHLI_IE is also used to specify the broadband low layer information element of an ATM UNI signaling message.

For information on the broadband high layer information, see the User Network Interface (UNI) Specification published by the ATM Forum.

See Also

ATM_BLLI_IE, ATM_PVC_SAP, ATM_SAP, Q2931_IE, Q2931_CALLMGR_PARAMETERS


ATM_BLLI_IE

The ATM_BLLI_IE structure specifies broadband low layer information, which indicates the means that should be used for compatibility checking by an addressed entity (for example, a remote user, an interworking unit, or a high-layer function network node addressed by the calling user).

typedef struct _ATM_BLLI_IE
{
  ULONG  Layer2Protocol;
  UCHAR  Layer2Mode;
  UCHAR  Layer2WindowSize;
  ULONG  Layer2UserSpecifiedProtocol;
  ULONG  Layer3Protocol;
  UCHAR  Layer3Mode;
  UCHAR  Layer3DefaultPacketSize;
  UCHAR  Layer3PacketWindowSize;
  ULONG  Layer3UserSpecifiedProtocol;
  ULONG  Layer3IPI;
  UCHAR  SnapId[5];
} ATM_BLLI_IE, *PATM_BLLI_IE;

Members

Layer2Protocol
Specifies the user information layer 2 protocol as one of the following values:
BLLI_L2_ISO_1745
Basic mode ISO 1745
BLLI_L2_Q921
CCITT Recommendation Q.921
BLLI_L2_X25L
CCITT Recommendation X.25, link layer
BLLI_L2_X25M
CCITT Recommendation X.25 multilink
BLLI_L2_ELAPB
Extended LAPB; for half-duplex operation
BLLI_L2_HDLC_NRM
HDLC NRM (ISO 4335)
BLLI_L2_HDLC_ABM
HDLC ABM (ISO 4335)
BLLI_L2_HDLC_ARM
HDLC ARM (ISO 4335)
BLLI_L2_LLC
LAN logical link control (ISO 8802/2)
BLLI_L2_X75
CCITT Recommendation X.75, single link procedure (SLP)
BLLI_L2_Q922
CCITT Recommendation Q.922
BLLI_L2_USER_SPECIFIED
User specified
BLLI_L2_ISO_7776
ISO 7776 DTE-DTE operation
Layer2Mode
Specifies the mode of operation for layer 2.
Layer2WindowSize
Specifies the packet window size for layer 2.
Layer2UserSpecifiedProtocol
User-specified layer 2 protocol information.

This must be a non-NULL value if BLLI_L2_USER_SPECIFIED is specified for Layer2Protocol.

Layer3Protocol
Specifies the user information layer 3 protocol as one of the following values:
BLLI_L3_X25
CCITT Recommendation X.25, packet layer
BLLI_L3_ISO_8208
ISO/IEC 8208 (X.25 packet-level protocol for data terminal equipment)
BLLI_L3_X223
X.223/ISO 8878 (use of ISO/ISO 8208 [41] and ITU-T X.25 to provide the OSI-CONS)
BLLI_L3_SIO_8473
ISO/IEC 8473 (OSI connectionless mode protocol)
BLLI_L3_T70
CCITT Recommendation T.70 minimum network layer
BLLI_L3_ISO_TR9577
ISO/IEC TR 9577 (protocol identification in the network layer)
BLLI_L3_USER_SPECIFIED
User-specified
Layer3Mode
Specifies the mode of operation for layer 3.
Layer3DefaultPacketSize
Specifies the default packet size for layer 3.
Layer3PacketWindowSize
Specifies the packet window size for layer 3.
Layer3UserSpecifiedProtocol
User-specified layer 3 protocol information.

This must be a non-NULL value if BLLI_L3_USER_SPECIFIED is specified for Layer3Protocol,

Layer3IPI
Specifies the Initial Protocol Identifier (IPI) for layer 3 as one of the following values:
BLLI_L3_IPI_SNAP
IEEE 802.1 SNAP identifier
BLLI_L3_IPI_IP
Internet Protocol (IP) identifier
SnapId[5]
Specifies the SNAP ID

Headers

Declared in atm.h. Include atm.h.

Comments

ATM_BLLI_IE is a member of an ATM_PVC_SAP structure or an ATM_SAP structure. ATM_PVC_SAP specifies ATM-specific SAP information for a PVC. ATM_SAP specifies ATM-specific SAP information for a switched VC.

ATM_BLLI_IE is also used to specify the broadband low layer information element of an ATM UNI signaling message.

For information on the broadband low layer information element, see the User Network Interface (UNI) Specification published by the ATM Forum.

See Also

ATM_BHLI_IE, ATM_PVC_SAP, ATM_SAP, Q2931_IE, Q2931_CALLMGR_PARAMETERS


ATM_BROADBAND_BEARER_CAPABILITY_IE

The ATM_BROADBAND_BEARER_CAPABILITY_IE structure specifies the broadband bearer capability element of an ATM UNI signaling message. The broadband bearer capability element indicates a requested broadband connection-oriented bearer service to be provided by the network.

typedef struct _ATM_BROADBAND_BEARER_CAPABILITY_IE
{
  UCHAR  BearerClass;
  UCHAR  TrafficType;
  UCHAR  TimingRequirements;
  UCHAR  ClippingSusceptability;
  UCHAR  UserPlaneConnectionConfig;
} ATM_BROADBAND_BEARER_CAPABILITY_IE, *PATM_BROADBAND_BEARER_CAPABILITY_IE;

Members

BearerClass
Specifies the bearer class as one of the following values:
BCOB_A
Bearer class A
BCOB_C
Bearer class C
BCOB_X
Bearer class X
TrafficType
Specifies the traffic type as one of the following values:
TT_NOIND
No indication of traffic type
TT_CBR
Constant bit rate
TT_VBR
Variable bit rate
TimingRequirements
Specifies the timing requirement as one of the following values:
TR_NOIND
No indication of timing requirements
TR_END_TO_END
End-to-end timing required
TR_NO_END_TO_END
End-to-end timing not required
ClippingSusceptability
Specifies the clipping susceptibility as one of the following values:
CLIP_NOT
Not susceptible to clipping
CLIP_SUS
Susceptible to clipping
UserPlaneConnectionConfig
Specifies the user plane connection configuration as one of the following values:
UP_P2P
Point-to-point connection
UP_P2MP
Point-to-multipoint connection

Headers

Declared in atm.h. Include atm.h.

Comments

ATM_BROADBAND_BEARER_CAPABILITY_IE is an information element that specifies broadband bearer capability parameters. ATM_BROADBAND_BEARER_CAPABILITY_IE can be included in a set of Q.2931 call manager-specific parameters.

ATM_BROADBAND_BEARER_CAPABILITY_IE is passed at IE in a Q2931_IE structure, which is passed at InfoElements in a Q2931_CALLMGR_PARAMETERS structure.

For more information on the broadband bearer capability information element, see the User Network Interface (UNI) Specification published by the ATM Forum.

See Also

Q2931_IE, Q2931_CALLMGR_PARAMETERS


ATM_BROADBAND_SENDING_COMPLETE_IE

The ATM_BROADBAND_SENDING_COMPLETE_IE structure specifies the broadband sending complete information element of an ATM UNI signaling message. The broadband sending complete information element indicates completion of the called party number.

typedef struct _ATM_BROADBAND_SENDING_COMPLETE_IE
{
  UCHAR  SendingComplete;
} ATM_BROADBAND_SENDING_COMPLETE_IE, *PATM_BROADBAND_SENDING_COMPLETE_IE;

Member

SendingComplete
The Broadband Sending Complete Indication

Headers

Declared in atm.h. Include atm.h.

Comments

ATM_BROADBAND_BEARER_CAPABILITY_IE can be included in a set of Q.2931 call manager-specific parameters.

ATM_BROADBAND_BEARER_CAPABILITY_IE is passed at IE in a Q2931_IE structure, which is passed at InfoElements in a Q2931_CALLMGR_PARAMETERS structure.

For more information on the broadband sending complete information element, see the User Network Interface (UNI) Specification published by the ATM Forum.

See Also

Q2931_IE, Q2931_CALLMGR_PARAMETERS


ATM_CALLING_PARTY_NUMBER_IE

The ATM_CALLING_PARTY_NUMBER_IE structure specifies the calling party number information element of an ATM UNI signaling message. The calling party number information element identifies the origin of a call.

typedef struct _ATM_CALLING_PARTY_NUMBER_IE
{
  ATM_ADDRESS  Number;
  UCHAR  PresentationIndication;
  UCHAR  ScreeningIndicator;
} ATM_CALLING_PARTY_NUMBER_IE, *PATM_CALLING_PARTY_NUMBER_IE;

Members

Number
Specifies the ATM address of the calling party, formatted as an ATM_ADDRESS structure. For more information on this structure, see ATM_ADDRESS.
PresentationIndication
Specifies the Presentation Indicator
ScreeningIndicator
Specifies the Screening Indicator

Headers

Declared in atm.h. Include atm.h.

Comments

ATM_CALLING_PARTY_NUMBER_IE can be included in a set of Q.2931 call manager-specific parameters.

ATM_BROADBAND_BEARER_CAPABILITY_IE is passed at IE in a Q2931_IE structure, which is passed at InfoElements in a Q2931_CALLMGR_PARAMETERS structure.

For more information on the calling party number information element, see the User Network Interface (UNI) Specification published by the ATM Forum.

See Also

Q2931_IE, Q2931_CALLMGR_PARAMETERS


ATM_CAUSE_IE

The ATM_CAUSE_IE structure specifies the cause information element of an ATM UNI signaling message. The cause information element describes the reason for generating certain messages, provides diagnostic information in the event of procedural errors, and indicates the location of the cause originator.

typedef struct _ATM_CAUSE_IE
{
  UCHAR  Location;
  UCHAR  Cause;
  UCHAR  DiagnosticsLength;
  UCHAR  Diagnostics[4];
} ATM_CAUSE_IE, *PATM_CAUSE_IE;

Members

Location
Specifies the location as one of the following values:
ATM_CAUSE_LOC_USER
User
ATM_CAUSE_LOC_PRIVATE_LOCAL
Private network serving the local user
ATM_CAUSE_LOC_PUBLIC_LOCAL
Public network serving the local user
ATM_CAUSE_LOC_TRANSIT_NETWORK
Transmit network
ATM_CAUSE_LOC_PUBLIC_REMOTE
Public network serving the remote user
ATM_CAUSE_LOC_PRIVATE_REMOTE
Private network serving the remote user
ATM_CAUSE_LOC_INTERNATIONAL_NETWORK
International network
ATM_CAUSE_LOC_BEYOND_INTERWORKING
Network beyond interworking point
Cause
Specifies the cause as one of the following values:
ATM_CAUSE_UNALLOCATED_NUMBER
Unallocated (unassigned) number
ATM_CAUSE_NO_ROUTE_TO_TRANSIT_NETWORK
No route to specified transit network
ATM_CAUSE_NO_ROUTE_TO_DESTINATION
No route to destination
ATM_CAUSE_VPI_VCI_UNACCEPTABLE
VPI/VCI assignment failure
ATM_CAUSE_NORMAL_CALL_CLEARING
Normal call clearing
ATM_CAUSE_USER_BUSY
User busy
ATM_CAUSE_NO_USER_RESPONDING
No user responding
ATM_CAUSE_CALL_REJECTED
Call was rejected.
ATM_CAUSE_NUMBER_CHANGED
Number changed
ATM_CAUSE_USER_REJECTS_CLIR
User rejects all calls with calling line identification restriction (CLIR).
ATM_CAUSE_DESTINATION_OUT_OF_ORDER
Destination out of order
ATM_CAUSE_INVALID_NUMBER_FORMAT
Invalid number format (address incomplete)
ATM_CAUSE_STATUS_ENQUIRY_RESPONSE
Status inquiry response
ATM_CAUSE_NORMAL_UNSPECIFIED
Normal unspecified
ATM_CAUSE_VPI_VCI_UNAVAILABLE
Requested VPI/VCI not available
ATM_CAUSE_NETWORK_OUT_OF_ORDER
Network out of order
ATM_CAUSE_TEMPORARY_FAILURE
Temporary failure
ATM_CAUSE_ACCESS_INFORMAION_DISCARDED
Access information discarded
ATM_CAUSE_NO_VPI_VCI_AVAILABLE
No VPI/VCI available
ATM_CAUSE_RESOURCE_UNAVAILABLE
Resource unavailable, unspecified
ATM_CAUSE_QOS_UNAVAILABLE
Quality of Service unavailable
ATM_CAUSE_USER_CELL_RATE_UNAVAILABLE
User cell rate not available
ATM_CAUSE_BEARER_CAPABILITY_UNAUTHORIZED
Bearer capability is unauthorized.
ATM_CAUSE_BEARER_CAPABILITY_UNAVAILABLE
Bearer capability not presently available
ATM_CAUSE_OPTION_UNAVAILABLE
Option is unavailable.
ATM_CAUSE_BEARER_CAPABILITY_UNIMPLEMENTED
Bearer capability not implemented
ATM_CAUSE_UNSUPPORTED_TRAFFIC_PARAMETERS
Unsupported combination of traffic parameters
ATM_CAUSE_INVALID_CALL_REFERENCE
Invalid call reference value
ATM_CAUSE_CHANNEL_NONEXISTENT
Identified channel does not exist
ATM_CAUSE_INCOMPATIBLE_DESTINATION
Incompatible destination
ATM_CAUSE_INVALID_ENDPOINT_REFERENCE
Invalid endpoint reference
ATM_CAUSE_INVALID_TRANSIT_NETWORK_SELECTION
Invalid transmit network selection
ATM_CAUSE_TOO_MANY_PENDING_ADD_PARTY
Too many pending add party operations
ATM_CAUSE_AAL_PARAMETERS_UNSUPPORTED
AAL parameters cannot be supported
ATM_CAUSE_MANDATORY_IE_MISSING
Mandatory information element is missing.
ATM_CAUSE_UNIMPLEMENTED_MESSAGE_TYPE
Message type non-existent or not implemented
ATM_CAUSE_UNIMPLEMENTED_IE
Information element non-existent or not implemented
ATM_CAUSE_INVALID_IE_CONTENTS
Invalid information element contents
ATM_CAUSE_INVALID_STATE_FOR_MESSAGE
Message not compatible with call state
ATM_CAUSE_RECOVERY_ON_TIMEOUT
Recovery on timer expiration
ATM_CAUSE_INCORRECT_MESSAGE_LENGTH
Incorrect message length
ATM_CAUSE_PROTOCOL_ERROR
Protocol error, unspecified
DiagnosticsLength
Specifies the length in bytes of the buffer at Diagnostics.
Diagnostics[4]
User-defined diagnostic information.

Headers

Declared in atm.h. Include atm.h.

Comments

ATM_CAUSE_IE can be included in a set of Q.2931 call manager-specific parameters.

ATM_CAUSE_IE is passed at IE in a Q2931_IE structure, which is passed at InfoElements in a Q2931_CALLMGR_PARAMETERS structure.

For more information on the cause information element, see the User Network Interface (UNI) Specification published by the ATM Forum.

See Also

Q2931_IE, Q2931_CALLMGR_PARAMETERS


ATM_FLOW_PARAMETERS

The ATM_FLOW_PARAMETERS structure specifies ATM-specific flow parameters.

typedef struct _ATM_FLOW_PARAMETERS
{
  ATM_SERVICE_CATEGORY  ServiceCategory;
  ULONG  AverageCellRate;
  ULONG  PeakCellRate;
  ULONG  MinimumCellRate;
  ULONG  InitialCellRate;
  ULONG  BurstLengthCells;
  ULONG  MaxSduSize;
  ULONG  TransientBufferExposure;
  ULONG  CumulativeRMFixedRTT;
  UCHAR  RateIncreaseFactor;
  UCHAR  RateDecreaseFactor;
  USHORT  ACRDecreaseTimeFactor;
  UCHAR  MaximumCellsPerForwardRMCell;
  UCHAR  MaximumForwardRMCellInterval;
  UCHAR  CutoffDecreaseFactor;
  UCHAR  Reserved1;
  ULONG  MissingRMCellCount;
  ULONG  Reserved2;
  ULONG  Reserved3;
} ATM_FLOW_PARAMETERS, *PATM_FLOW_PARAMETERS;

Members

ServiceCategory
Specifies the ATM service category as one of the following values:
ATM_SERVICE_CATEGORY_CBR
Constant Bit Rate
ATM_SERVICE_CATEGORY_VBR
Variable Bit Rate
ATM_SERVICE_CATEGORY_UBR
Unspecified Bit Rate
ATM_SERVICE_CATEGORY_ABR
Available Bit Rate
AverageCellRate
Specifies in cells per second the average rate at which cells are to be sent on this connection.
PeakCellRate
Specifies in cells per second the peak rate at which cells are to be sent on this connection.
MinimumCellRate
Specifies in cells per second the minimum cell rate at which cells are to be sent on this connection. This is an ABR service parameter.
InitialCellRate
Specifies in cells per second the initial cell rate at which cells are to be sent on this connection. This is an ABR service parameter.
BurstLengthCells
Specifies the number of consecutive cells sent at the peak cell rate. If AverageCellRate equals PeakCellRate, this parameter can be ignored and the effective burst length is infinite.
MaxSduSize
Specifies in bytes the size of the maximum Service Data Unit that will be sent or received on this VC.
TransientBufferExposure
Specifies the Transient Buffer Exposure, which is the number of cells that can be sent during the startup period before the first RM-cell (Resource Management cell) returns. This is an ABR service parameter.
CumulativeRMFixedRTT
Specifies in microseconds the Fixed Roundtrip Time, which is the sum of the fixed and propagation delays from the source to the furthest destination and back. This is an ABR service parameter.
RateIncreaseFactor
Specifies the Rate Increase Factor, which controls the amount by which the cell transmission rate may increase upon receipt of an RM-cell. AIR =PCR*RIF (Additive Increase Rate = Peak Cell Rate * Rate Increase Factor). RIF is a power of 2, ranging from 1/32768 to 1. This is an ABR service parameter.
RateDecreaseFactor
Specifies the Rate Decrease Factor, which controls the decrease in the cell transmission rate. RDF is a power of 2 from 1/32,768 to 1. This is an ABR service parameter.
ACRDecreaseTimeFactor
Specified ACR Decrease Time Factor, which is the time permitted between sending RM-cells before the rate is decreased to ICR (Initial Cell Rate). The ADTF range is .01 to 10.23 seconds with a granularity of 10 ms. This is an ABR service parameter.
MaximumCellsPerForwardRMCell
Specifies the Nrm, which is the maximum number of cells a source may send for each forward RM-cell. This is an ABR service parameter.
MaximumForwardRMCellInterval
Specifies the Trm, which provides an upper bound on the time between forward RM-cells for an active source. It is 100 times a power of two with a range of 100*2-7 to 100*20. This is an ABR service parameter.
CutoffDecreaseFactor
Specifies the Cutoff Decrease Factor (CDF), which controls the decrease in ACR (Allowed Cell Rate) associated with Cell Rate Margin (CRM). This is an ABR service parameter.
Reserved1
This is reserved.
MissingRMCellCount
Specifies the Cell Rate Margin (CRM), which is the difference between the effective bandwidth allocation and the allocation for sustainable rate in cells per second. This is an ABR service parameter.
Reserved2
This is reserved.
Reserved3
This is reserved.

Headers

Declared in atm.h. Include atm.h.

Comments

The ATM_MEDIA_PARAMETERS structure and the Q2931_ADD_PVC structure each contain two ATM_FLOW_PARAMETERS structures. One of the ATM_FLOW_PARAMETERS structures specifies transmit flow parameters; the other specifies receive flow parameters.

See Also

ATM_MEDIA_PARAMETERS, Q2931_ADD_PVC


ATM_MEDIA_PARAMETERS

The ATM_MEDIA_PARAMETERS structure specifies media-specific parameters used by a miniport driver or MCM driver to reserve resources for or activate a VC.

typedef struct _ATM_MEDIA_PARAMETERS
{
  ATM_VPIVCI      ConnectionId;
  ATM_AAL_TYPE  AALType;
  ULONG  CellDelayVariationCLP0;
  ULONG  CellDelayVariationCLP1;
  ULONG  CellLossRatioCLP0;
  ULONG  CellLossRatioCLP1;
  ULONG  CellTransferDelayCLP0;
  ULONG  CellTransferDelayCLP1;
  ULONG  DefaultCLP;
  ATM_FLOW_PARAMETERS  Transmit;
  ATM_FLOW_PARAMETERS  Receive;
} ATM_MEDIA_PARAMETERS, *PATM_MEDIA_PARAMETERS;

Members

ConnectionId
Specifies the virtual path identifier/virtual channel identifier (VPI/VCI) pair for the VC. The ConnectionId is formatted as an ATM_VPIVCI structure. For more information on this structure, see ATM_VPIVCI.
AALType
Specifies the ATM Adaptation Layer (AAL) type as one of the following values:
AAL_TYPE_AAL0
AAL 0
AAL_TYPE_AAL1
AAL 1
AAL_TYPE_AAL34
AAL 3/4
AAL_TYPE_AAL5
AAL 5
CellDelayVariationCLP0
Specifies the expected cell delay variation for cells with the CLP bit set to 0.
CellDelayVariationCLP1
Specifies the expected cell delay variation for cells with the CLP bit set to 1.
CellLossRatioCLP0
Specifies the desired cell loss ratio for cells with the CLP bit set to 0.
CellLossRatioCLP1
Specifies the desired cell loss ratio for cells with the CLP bit set to 0.
CellTransferDelayCLP0
Specifies the cell transfer delay, in microseconds, for cells with the CLP bit set to 0.
CellTransferDelayCLP1
Specifies the cell transfer delay, in microseconds, for cells with the CLP bit set to 1.
DefaultCLP
Specifies the cell loss priority for all transmit cells. If this parameter is 1, the CLP bit in the headers of cells sent on this VC should be set, indicating that these cells are eligible for discard. The client can override the default CLP on a per-packet basis by setting the appropriate CellLossPriority parameter in the ATM_AAL_OOB_INFO structure.
Transmit
Specifies the transmit flow parameters, formatted as an ATM_FLOW_PARAMETERS structure. For more information, see ATM_FLOW_PARAMETERS.
Receive
Specifies the receive flow parameters, formatted as an ATM_FLOW_PARAMETERS structure. For more information, see ATM_FLOW_PARAMETERS.

Headers

Declared in atm.h. Include atm.h.

Comments

ATM_MEDIA_PARAMETERS is typically constructed by a call manager based on information conveyed by the CO_CALL_MANAGER_PARAMETERS structure. However, a connection-oriented client may override this behavior by specifying media parameters in an ATM_MEDIA_PARAMETERS structure.

ATM_MEDIA_PARAMETERS is passed at Parameters in a CO_SPECIFIC_PARAMETERS structure that is pointed to by a CO_MEDIA_PARAMETERS structure.

See Also

ATM_AAL_OOB_INFO, ATM_FLOW_PARAMETERS, CO_MEDIA_PARAMETERS, CO_SPECIFIC_PARAMETERS


ATM_PVC_SAP

The ATM_PVC_SAP structure specifies ATM medium-specific SAP information for a permanent virtual connection (PVC).

typedef struct _ATM_PVC_SAP
{
  ATM_BLLI_IE  Blli;
  ATM_BHLI_IE  Bhli;
} ATM_PVC_SAP, *PATM_PVC_SAP;

Members

Blli
An ATM_BLLI_IE structure that specifies the broadband low layer information for the SAP. For a detailed description of this structure, see ATM_BLLI_IE.
Bhli
An ATM_BHLI_IE structure that specifies broadband high layer information for the SAP. For a detailed description of this structure, see ATM_BHLI_IE.

Headers

Declared in atm.h. Include atm.h.

Comments

ATM_SAP is a member of a Q2931_ADD_PVC structure, which specifies Q.2931 parameters needed by a call manager or MCM driver to add a permanent virtual connection (PVC) to its list of configured PVCs.

A connection-oriented client supplies a Q2931_ADD_PVC structure (which contains ATM SAP information in an ATM_PVC_SAP structure) when issuing an OID_CO_ADD_PVC to a call manager or MCM driver that supports the Q.2931 signaling protocol.

If a connection-oriented client then registers the SAP configured for the PVC by calling NdisClRegisterSap, the call manager or MCM driver will indicate to that client any incoming calls on that PVC that are addressed to that SAP.

See Also

ATM_BHLI_IE, ATM_BLLI_IE, NdisClRegisterSap, OID_CO_ADD_PVC, ProtocolClRegisterSapComplete, ProtocolCmRegisterSap


ATM_QOS_CLASS_IE

The ATM_QOS_CLASS_IE structure specifies the Quality of Service (QoS) information element of an ATM UNI signaling message. The QoS information element requests and indicates the Quality of Service class for a connection.

typedef struct _ATM_QOS_CLASS_IE
{
  UCHAR  QOSClassForward;
  UCHAR  QOSClassBackward;
} ATM_QOS_CLASS_IE, *PATM_QOS_CLASS_IE;

Members

QOSClassForward
Specifies the forward QoS class as one of the following values:
QOS_CLASS0
QoS class 0
QOS_CLASS1
QoS class 1
QOS_CLASS2
QoS class 2
QOS_CLASS3
QoS class 3
QOS_CLASS4
QoS class 4
QOSClassBackward
Specifies the backward QoS class as one of the following values:
QOS_CLASS0
QoS class 0
QOS_CLASS1
QoS class 1
QOS_CLASS2
QoS class 2
QOS_CLASS3
QoS class 3
QOS_CLASS4
QoS class 4

Headers

Declared in atm.h. Include atm.h.

Comments

ATM_QOS_CLASS_IE can be included in a set of Q.2931 call manager-specific parameters.

ATM_QOS_CLASS_IE is passed at IE in a Q2931_IE structure, which is passed at InfoElements in a Q2931_CALLMGR_PARAMETERS structure.

For more information on the QoS calls information element, see the User Network Interface (UNI) Specification published by the ATM Forum.

See Also

Q2931_IE, Q2931_CALLMGR_PARAMETERS


ATM_RAW_IE

The ATM_RAW_IE structure specifies a user-defined information element of an ATM UNI signaling message. This information element supplies user-defined information in a raw (user-defined) format.

typedef struct _ATM_RAW_IE
{
  ULONG  RawIELength;
  ULONG  RawIEType;
  UCHAR  RawIEValue[1];
} ATM_RAW_IE, *PATM_RAW_IE;

Members

RawIELength
Specifies the size in bytes of the buffer at RawIEValue.
RawIEType
Specifies the type of information in the buffer at RawIEValue. The encoding of RawIEType is user-defined.
RawIEValue[1]
Specifies a variable-length array that contains the user-defined information.

Headers

Declared in atm.h. Include atm.h.

Comments

ATM_RAW_IE can be included in a set of Q.2931 call manager-specific parameters.

ATM_RAW_IE is passed at IE in a Q2931_IE structure, which is passed at InfoElements in a Q2931_CALLMGR_PARAMETERS structure.

See Also

Q2931_IE, Q2931_CALLMGR_PARAMETERS


ATM_SAP

The ATM_SAP structure specifies ATM-specific SAP information for a client. A connection-oriented client specifies this information in a call to NdisClRegisterSap.

typedef struct _ATM_SAP
{
  ATM_BLLI_IE  Blli;
  ATM_BHLI_IE  Bhli;
  ULONG  NumberOfAddresses;
  UCHAR  Addresses[1];
} ATM_SAP, *PATM_SAP;

Members

Blli
An ATM_BLLI_IE structure that specifies the broadband low layer information for the SAPs listed at Addresses. For a detailed description of this structure, see ATM_BLLI_IE.
Bhli
An ATM_BHLI_IE structure that specifies broadband high layer information for the SAPs listed at Addresses. For a detailed description of this structure, see ATM_BHLI_IE.
NumberOfAddresses
Specifies the number of ATM addresses in the variable-length array at Addresses. This value should be either 0 or 1.
Addresses[1]
Specifies a variable-length array that contains one or more SAP addresses, each of which is formatted as structure of type ATM_ADDRESS. For a detailed description of this structure, see ATM_ADDRESS.

Headers

Declared in atm.h. Include atm.h.

Comments

ATM_SAP is passed in the variable-length array at Sap in a CO_SAP structure. A connection-oriented client passes a CO_SAP structure to NdisClRegisterSap when registering a SAP for an SVC with a call manager or MCM driver.

See Also

ATM_ADDRESS, ATM_BHLI_IE, ATM_BLLI_IE, ATM_PVC_SAP, CO_SAP, NdisClRegisterSap, ProtocolClRegisterSapComplete, ProtocolCmRegisterSap


ATM_TRAFFIC_DESCRIPTOR

The ATM_TRAFFIC_DESCRIPTOR structure specifies either forward or backward ATM traffic descriptor parameters in an ATM traffic descriptor information element.

typedef struct _ATM_TRAFFIC_DESCRIPTOR
{
  ULONG  PeakCellRateCLP0;
  ULONG  PeakCellRateCLP01;
  ULONG  SustainableCellRateCLP0;
  ULONG  SustainableCellRateCLP01;
  ULONG  MaximumBurstSizeCLP0;
  ULONG  MaximumBurstSizeCLP01;
  BOOLEAN  BestEffort;
  BOOLEAN  Tagging;
} ATM_TRAFFIC_DESCRIPTOR, *PATM_TRAFFIC_DESCRIPTOR;

Members

PeakCellRateCLP0
Specifies the Peak Cell Rate (CLP=0).
PeakCellRateCLP01
Specifies the Peak Cell Rate (CLP=01).
SustainableCellRateCLP0
Specifies the Sustainable Cell Rate (CLP=0).
SustainableCellRateCLP01
Specifies the Sustainable Cell Rate (CLP=01).
MaximumBurstSizeCLP0
Specifies the Maximum Burst Size (CLP=0).
MaximumBurstSizeCLP01
Specifies the Maximum Burst Size (CLP=01).
BestEffort
Specifies the Best Effort Indication.
Tagging
Specifies the Tagging parameter.

Headers

Declared in atm.h. Include atm.h.

Comments

ATM_TRAFFIC_DESCRIPTOR specifies the traffic descriptor parameters for a single traffic direction: either forward (the direction from the calling user to the called user) or backward (the direction from the called user to the calling user).

ATM_TRAFFIC_DESCRIPTOR is a member of an ATM_TRAFFIC_DESCRIPTOR_IE structure.

For more information on the ATM traffic descriptor parameters, see the User Network Interface (UNI) Specification published by the ATM Forum.

See Also

ATM_TRAFFIC_DESCRIPTOR_IE


ATM_TRAFFIC_DESCRIPTOR_IE

The ATM_TRAFFIC_DESCRIPTOR_IE structure specifies the ATM traffic descriptor information element of an ATM UNI signaling message. This information element specifies the set of traffic parameters, which together specify a traffic-control capacity.

typedef struct _ATM_TRAFFIC_DESCRIPTOR_IE
{
  ATM_TRAFFIC_DESCRIPTOR  ForwardTD;
  ATM_TRAFFIC_DESCRIPTOR  BackwardTD;
} ATM_TRAFFIC_DESCRIPTOR_IE, *PATM_TRAFFIC_DESCRIPTOR_IE;

Members

ForwardTD
Specifies the forward traffic parameters, formatted as an ATM_TRAFFIC_DESCRIPTOR structure. For more information on this structure, see ATM_TRAFFIC_DESCRIPTOR.
BackwardTD
Specifies the backward traffic parameters, formatted as an ATM_TRAFFIC_DESCRIPTOR structure. For more information on this structure, see ATM_TRAFFIC_DESCRIPTOR.

Headers

Declared in atm.h. Include atm.h.

Comments

ATM_TRAFFIC_DESCRIPTOR_IE can be included in a set of Q.2931 call manager-specific parameters.

ATM_TRAFFIC_DESCRIPTOR_IE is passed at IE in a Q2931_IE structure, which is passed at InfoElements in a Q2931_CALLMGR_PARAMETERS structure.

For more information on the ATM traffic descriptor information element, see the User Network Interface (UNI) Specification published by the ATM Forum.

See Also

ATM_TRAFFIC_DESCRIPTOR, Q2931_IE, Q2931_CALLMGR_PARAMETERS


ATM_TRANSIT_NETWORK_SELECTION_IE

The ATM_TRANSIT_NETWORK_SELECTION_IE structure specifies the ATM transit network selection information element of an ATM UNI signaling message. The ATM transit network selection information element identifies one requested transit network.

typedef struct _ATM_TRANSIT_NETWORK_SELECTION_IE
{
  UCHAR  TypeOfNetworkId;
  UCHAR  NetworkIdPlan;
  UCHAR  NetworkIdLength;
  UCHAR  NetworkId[1];
} ATM_TRANSIT_NETWORK_SELECTION_IE, *PATM_TRANSIT_NETWORK_SELECTION_IE;

Members

TypeOfNetworkId
Specifies the Type of Network Identifier as the following:
TNS_TYPE_NATIONAL
National network identification
NetworkIdPlan
Specifies the Network Identification Plan as the following:
TNS_PLAN_CARRIER_ID_CODE
Carrier Identification Code
NetworkIdLength
Specifies the size in bytes of the buffer at NetworkId.
NetworkId[1]
Specifies a variable-length array that contains the Network ID.

Headers

Declared in atm.h. Include atm.h.

Comments

ATM_TRANSIT_NETWORK_SELECTION_IE can be included in a set of Q.2931 call manager-specific parameters.

ATM_TRANSIT_NETWORK_SELECTION_IE is passed at IE in a Q2931_IE structure, which is passed at InfoElements in a Q2931_CALLMGR_PARAMETERS structure.

For more information on the ATM transit network selection information element, see the User Network Interface (UNI) Specification published by the ATM Forum.

See Also

Q2931_IE, Q2931_CALLMGR_PARAMETERS


ATM_VPIVCI

The ATM_VPIVCI structure specifies the VPI and VCI values for a VC.

typedef struct _ATM_VPIVCI {
  ULONG Vpi;
  ULONG Vci;
} ATM_VPIVCI, *PATM_VPIVCI;

Members

Vpi
The Virtual Path Identifier of a virtual connection (VC).
Vci
The Virtual Channel Identifier of a VC.

Headers

Declared in atm.h. Include atm.h.

Comments

ATM_VPIVCI is a member of the following ATM structures:

  • ATM_MEDIA_PARAMETERS

    As a member of this structure, ATM_VPIVCI identifies the VC that a connection-oriented miniport driver must activate or reserve resources for.

  • Q2931_ADD_PVC

    As a member of this structure, ATM_VPIVCI identifies the permanent VC (PVC) that a connection-oriented client is requesting a call manager or MCM driver to add to its list of configured PVCs.

  • Q2931_DELETE_PVC

    As a member of this structure, ATM_VPIVCI identifies the permanent VC (PVC) that a connection-oriented client is requesting a call manager or MCM driver to delete from its list of configured PVCs.

See Also

ATM_MEDIA_PARAMETERS, OID_ATM_ILMI_VPIVCI, OID_ATM_SIGNALING_VPIVCI, Q2931_ADD_PVC, Q2931_DELETE_PVC


Q2931_ADD_PVC

The Q2931_ADD_PVC structure specifies Q.2931 parameters needed by a call manager or MCM driver to add a permanent virtual connection (PVC) to its list of configured PVCs.

typedef struct _Q2931_ADD_PVC
{
  ATM_ADDRESS  CalledParty;
  ATM_ADDRESS  CallingParty;
  ATM_VPIVCI  ConnectionId;
  ATM_AAL_TYPE  AALType;
  ATM_FLOW_PARAMETERS  ForwardFP;
  ATM_FLOW_PARAMETERS  BackwardFP;
  ULONG  Flags;
  ATM_PVC_SAP  LocalSap;
  ATM_PVC_SAP  DestinationSap;
  BOOLEAN  LIJIdPresent;
  ATM_LIJ_CALLID_IE  LIJId;
} Q2931_ADD_PVC, *PQ2931_ADD_PVC;

Members

CalledParty
Specifies the ATM of the called party, formatted as an ATM_ADDRESS structure. For more information on this structure, see ATM_ADDRESS.
CallingParty
Specifies the ATM of the calling party, formatted an ATM_ADDRESS structure. For more information on this structure, see ATM_ADDRESS.
ConnectionId
Specifies the VPI/VCI of the PVC, formatted as an ATM_VPIVCI structure. For more information on this structure, see ATM_VPIVCI.
AALType
Specifies the ATM Adaptation Layer (AAL) type as one of the following values:
AAL_TYPE_AAL0
AAL 0
AAL_TYPE_AAL1
AAL 1
AAL_TYPE_AAL34
AAL 3/4
AAL_TYPE_AAL5
AAL 5
ForwardFP
Specifies the flow parameters for the forward direction (the direction from the calling user to the called user) formatted as an ATM_FLOW_PARAMETERS structure. For more information see, ATM_FLOW_PARAMETERS.
BackwardFP
Specifies the flow parameters for the backward direction (the direction from the called user to the calling user) formatted as an ATM_FLOW_PARAMETERS structure. For more information on this structure see, ATM_FLOW_PARAMETERS.
Flags
The flags can be one of the following:
CO_FLAG_SIGNALING_VC
Specifies that this PVC should now be used by the call manager or MCM driver as the signaling VC (the VC on which the call manager or MCM driver sends and receives signaling messages).
CO_FLAG_NO_DEST_SAP
Specifies that the call manager or MCM driver should use the PVC for an incoming call if a SVC cannot be used for the call. (The call manager or MCM driver can be optimized to not search for PVCs in this case.)
LocalSap
Specifies the SAP of the calling user, formatted as an ATM_PVC_SAP structure. For more information on this structure, see ATM_PVC_SAP.
DestinationSap
Specifies the SAP of the called user, formatted as an ATM_PVC_SAP structure. For more information on this structure, see ATM_PVC_SAP.
LIJIdPresent
Reserved for future use. Clients must set this to FALSE.
LIJId
Reserved for future use.

Headers

Declared in atm.h. Include atm.h.

Comments

Q2931_ADD_PVC is passed in the variable-length array at Parameters in a CO_SPECIFIC_PARAMETERS structure contained in a CO_PVC structure. A connection-oriented client passes a CO_PVC structure when sending an OID_CO_ADD_PVC to a call manager or MCM driver. OID_CO_ADD_PVC adds a permanent virtual connection (PVC) to the call manager's or MCM driver's list of configured PVCs.

See Also

ATM_ADDRESS, ATM_FLOW_PARAMETERS, ATM_PVC_SAP, ATM_VPIVCI, CO_SPECIFIC_PARAMETERS, OID_CO_ADD_PVC, Q2931_DELETE_PVC


Q2931_DELETE_PVC

The Q2931_DELETE_PVC structure specifies a permanent virtual connection (PVC) to be deleted from a call manager's or MCM driver's list of configured PVCs.

typedef struct _Q2931_DELETE_PVC
{
  ATM_VPIVCI  ConnectionId;
} Q2931_DELETE_PVC, *PQ2931_DELETE_PVC;

Members

ConnectionId
Specifies the VPI/VCI of the PVC, formatted as an ATM_VPIVCI structure. For more information on this structure, see ATM_VPIVCI.

Headers

Declared in atm.h. Include atm.h.

Comments

Q2931_DELETE_PVC is passed in the variable-length array at Parameters in a CO_SPECIFIC_PARAMETERS structure contained in a CO_PVC structure. A connection-oriented client passes a CO_PVC structure when sending an OID_CO_DELETE_PVC to a call manager or MCM driver. OID_CO_DELETE_PVC deletes a permanent virtual connection (PVC) from the call manager's or MCM driver's list of configured PVCs.

See Also

ATM_VPIVCI, CO_SPECIFIC_PARAMETERS, OID_CO_DELETE_PVC, Q2931_ADD_PVC


Q2931_IE

The Q2931_IE structure serves as a header for each information element attached to a Q2931_CALLMGR_PARAMETERS structure.

typedef struct _Q2931_IE
{
  Q2931_IE_TYPE      IEType;
  ULONG  IELength;
  UCHAR  IE[1];
} Q2931_IE, *PQ2931_IE;

Members

IEType
Specifies the information element type as one of the following values:
IE_AALParameters
ATM Adaptation layer (AAL) parameters
IE_TrafficDescriptor
Traffic descriptor
IE_BroadbandBearerCapability
Broadband bearer capability
IE_BHLI
Broadband high layer information (BHLI)
IE_BLLI
Broadband low layer information (BLLI)
IE_CalledPartyNumber
Called party number
IE_CalledPartySubaddress
Called party subaddress
IE_CallingPartyNumber
Calling party number
IE_CallingPartySubaddress
Calling party subaddress
IE_Cause
Cause
IE_QOSClass
Quality of Service (QoS) class
IE_TransitNetworkSelection
Transit network selection
IE_BroadbandSendingComplete
Broadband sending complete
IE_LIJCallId
Leaf Initiated Joint (LIJ) Call ID
IE_Raw
Raw (unformatted) user-supplied data
IELength
Specifies the length in bytes of the information element, including the Q2931_IE structure and the variable length array beginning at IE[0].
IE
Specifies a variable-length array that contains an information element of the type specified at IEType.

Headers

Declared in atm.h. Include atm.h.

Comments

A Q2931_IE structure encapsulates and serves as a header for each information element at InfoElements in a Q2931_CALLMGR_PARAMETERS structure. The Q2931_IE structure describes the encapsulated information element.

See Also

AAL_PARAMETERS_IE, ATM_BHLI_IE, ATM_BLLI_IE, ATM_BROADBAND_BEARER_CAPABILITY_IE, ATM_BROADBAND_SENDING_COMPLETE_IE, ATM_CALLING_PARTY_NUMBER_IE, ATM_CAUSE_IE, ATM_QOS_CLASS_IE, ATM_RAW_IE, ATM_TRAFFIC_DESCRIPTOR_IE, ATM_TRANSIT_NETWORK_SELECTION_IE, Q2931_CALLMGR_PARAMETERS


Q2931_CALLMGR_PARAMETERS

The Q2931_CALLMGR_PARAMETERS structure specifies Q.2931 call manager-specific parameters.

typedef struct _Q2931_CALLMGR_PARAMETERS
{
  ATM_ADDRESS  CalledParty;
  ATM_ADDRESS  CallingParty;
  ULONG  InfoElementCount;
  UCHAR  InfoElements[1];
} Q2931_CALLMGR_PARAMETERS, *PQ2931_CALLMGR_PARAMETERS;

Members

CalledParty
The ATM address of the called party, formatted as an ATM_ADDRESS structure. For a detailed description of this structure, see ATM_ADDRESS.
CallingParty
The ATM address of the calling party, formatted as an ATM_ADDRESS structure. For a detailed description of this structure, see ATM_ADDRESS.
InfoElementCount
The number of information elements contained in the buffer at InfoElements.
InfoElements[1]
Specifies a variable-length array that contains one or more information elements.

Headers

Declared in atm.h. Include atm.h.

Comments

A connection-oriented client specifies ATM-specific call manager parameters used by a call manager or MCM driver to do the following:

  • Set up an outgoing or incoming call
  • Add a party to or delete a party from a multipoint call
  • Request a change in Quality of Service (QoS) for an active VC
  • Derive media parameters that a miniport driver uses for VC activation

A call manager or MCM driver specifies call manager-specific parameters for use by a connection-oriented parameter in determining whether to accept an incoming call or whether to accept an incoming request to change the QoS for an active VC.

In addition to identifying the calling party and the called party, Q2931_CALLMGR_PARAMETERS contains information elements defined for ATM UNI signaling messages. Each information element is formatted as an ATM_XXX_IE structure encapsulated by a header formatted as a Q2931_IE structure. (Note that ATM_CALLED_PARTY_NUMBER_IE, ATM_CALLED_PARTY_SUBADDRESS_IE, and ATM_CALLING_PARTY_SUBADDRESS_IE are each formatted as an ATM_ADDRESS_STRUCTURE.)

Q2931_CALLMGR_PARAMETERS specifies the call manager-specific portion of the call manager parameters passed by a connection-oriented client, call manager, or MCM driver. Q2931_CALLMGR_PARAMETERS is passed in the variable-length array at Parameters in a CO_SPECIFIC STRUCTURE, which is pointed to by a CO_CALL_MANAGER_PARAMETERS structure, which is pointed to by a CO_CALL_PARAMETERS structure.

See Also

AAL_PARAMETERS_IE, ATM_BHLI_IE, ATM_BLLI_IE, ATM_BROADBAND_BEARER_CAPABILITY_IE, ATM_BROADBAND_SENDING_COMPLETE_IE, ATM_CALLING_PARTY_NUMBER_IE, ATM_CAUSE_IE, ATM_FLOW_PARAMETERS, ATM_QOS_CLASS_IE, ATM_RAW_IE, ATM_TRAFFIC_DESCRIPTOR_IE, ATM_TRANSIT_NETWORK_SELECTION_IE, CO_CALL_PARAMETERS, CO_CALL_MANAGER_PARAMETERS, CO_SPECIFIC_PARAMETERS, Q2931_IE, Q2931_CALLMGR_PARAMETERS


NDIS Object Identifiers

NDIS object identifiers (OIDs) are a set of system-defined constants that take the form OID_XXX. Higher-level NDIS drivers set these OIDs in an NDIS_REQUEST-type structure for their calls to NdisRequest or NdisCoRequest. This section describes these OIDs.

NDIS OID requests are classified as follows:

  • A query is a call to retrieve information from or about the underlying NDIS driver, usually about the driver's or NIC's overall capabilities or current status.

    An NDIS protocol driver sets NdisRequestQueryInformation for the RequestType parameter to NdisRequest or NdisCoRequest when it makes global queries. Such a request made with NdisRequest is handled by the MiniportQueryInformation function of an underlying NIC driver. Such a request made with NdisCoRequest is handled by the MiniportCoRequest function of an underlying connection-oriented NIC driver or the ProtocolCoRequest function of a connection-oriented client, call manager, or MCM driver, depending on the target of the request.

  • A statistics query is a call to retrieve information about network performance. Such a request always originates in a user-mode application. Protocol drivers never set NdisRequestQueryStatistics for the RequestType parameter to NdisRequest or NdisCoRequest. Such a request made with NdisRequest is handled either by NDIS or by the MiniportQueryInformation function of an underlying NIC driver. Such a request made with NdisCoRequest is handled either by NDIS or by the MiniportCoRequest function an underlying connection-oriented NIC driver.
  • A set is a call with directions for the underlying NDIS driver, such as the header format the protocol wants used for receive indications when the underlying driver offers a choice or which optional features the miniport driver should enable on its NIC.

    An NDIS protocol driver sets NdisRequestSetInformation for the RequestType parameter to NdisRequest or NdisCoRequest when it makes this type of request. Such a request made with NdisRequest is handled by the MiniportSetInformation function of an underlying NIC driver. Such a request made with NdisCoRequest is handled by the MiniportCoRequest function an underlying connection-oriented NIC driver. Such a request made with NdisCoRequest is handled by the MiniportCoRequest function of an underlying connection-oriented NIC driver or the ProtocolCoRequest function of a connection-oriented client, call manager, or MCM driver, depending on the target of the request.

Many system-defined OIDs are valid with more than one of the preceding NdisRequest Xxx values. Associated with each NDIS object identified by an OID_XXX is a data buffer, which varies in size and format depending on the given OID. The caller of NdisRequest supplies a pointer to this data buffer in the InformationBuffer member of the NDIS_REQUEST structure.

OIDs are either general or media-specific in nature. Each defined OID is either an operational OID or a statistics OID. Support for each NDIS-defined OID is either mandatory or optional.

Some of the information about OIDs is presented in charts. For each entry (row), these charts contain the information summarized in the following table.

Column Header | Notation Meaning
Length | By default, the value indicates the number of bytes of data associated with the OID. For counters, a length of 4 indicates a 32-bit counter and 8 indicates a 64-bit counter. The NIC driver cannot reset counters; counters wrap when they reach their maximum. Values expressed in the form Arr(n), indicate an array of elements, each of size n. The underlying driver stores array elements consecutively, with no padding.
Q | An "M" indicates the OID is valid in calls to NdisRequest or NdisCoRequest with RequestType value NdisRequestQueryInformation or, from components other than protocols, NdisRequestQueryStatistics. An "O" indicates the optional OID is valid in the same type of request if the underlying NDIS driver supports the OID.
S | An "M" indicates the OID is valid in calls to NdisRequest or NdisCoRequest with RequestType value NdisRequestSetInformation. An "O" indicates the optional OID is valid in the same type of request if the underlying NDIS driver supports the OID.
Name | The system-defined OID_XXX, followed by a brief explanation of the constant name.

NDIS-defined OID_XXX constants are 4-byte values, encoded as shown in the following chart. However, OIDs of the form OID_TAPI_XXX do not have values that explicitly indicate whether support of each OID is mandatory or optional.

Byte (LSB to MSB) | Code(s) | Definition
1 | 0xN (unique value) | Differentiates each OID from others with the same value in the three high-order bytes.
2 | 0x01 | Mandatory
 | 0x02 | Optional
3 | 0x01 | Operational Characteristics
 | 0x02 | Statistics
4 | 0x00 | General Information
 | 0x01-0xFE | System-defined media-specific information, as follows:
 | 0x01 | Ethernet (802.3)
 | 0x02 | Token Ring (802.5)
 | 0x03 | Fiber Distributed Data Interface (FDDI)
 | 0x05 | LocalTalk
 | 0x06 | ARCNET
 | 0x04 | Wide area network (WAN)
 | 0x07 | TAPI
 | 0x08 | Native ATM
 | 0x09 | Wireless
 | 0x0A | Reserved for infrared (IrDA)
 | 0xFE | Call managers for connection-oriented media
 | 0xFF | Vendor-specific information

For OID-specific reference information, see the following sections:

General Objects (OIDs supported by all drivers)

Ethernet Objects

Token Ring Objects

FDDI Objects

LocalTalk Objects

ARCNET Objects

WAN Objects

TAPI Objects

Wireless WAN Objects

Connection-Oriented Objects

Plug-and-Play and Power-Management Objects

ATM Objects

IrDA Objects

Task Offload Objects

802.11 Wireless LAN Objects


General Objects

This section describes the set of system-defined general object identifiers (OIDs) that all underlying NDIS drivers support. System-defined general OIDs can be used to get or set both the general operational and general statistics characteristics of miniport drivers and their NICs.

The general OIDs are defined in ntddndis.h. When building a driver that supports these OIDs, include ntddndis.h.

This section includes the following topics:

General Operational Characteristics

General Statistics


General Operational Characteristics

The following chart summarizes the OIDs that are used to get or set the general operational characteristics of miniport drivers and their NICs.

Length | Q | S | Name
Arr(4) | M |  | OID_GEN_SUPPORTED_LIST List of supported OIDs
4 | M |  | OID_GEN_HARDWARE_STATUS Hardware status
Arr(4) | M |  | OID_GEN_MEDIA_SUPPORTED Media types supported (encoded)
Arr(4) | M |  | OID_GEN_MEDIA_IN_USE Media types in use (encoded)
4 | M |  | OID_GEN_MAXIMUM_LOOKAHEAD Maximum in bytes, receive lookahead size
4 | M |  | OID_GEN_MAXIMUM_FRAME_SIZE Maximum in bytes, frame size
4 | M |  | OID_GEN_LINK_SPEED Link speed in units of 100 bps
4 | M |  | OID_GEN_TRANSMIT_BUFFER_SPACE Transmit buffer space
4 | M |  | OID_GEN_RECEIVE_BUFFER_SPACE Receive buffer space
4 | M |  | OID_GEN_TRANSMIT_BLOCK_SIZE Minimum amount of storage, in bytes, that a single packet occupies in the transmit buffer space of the NIC
4 | M |  | OID_GEN_RECEIVE_BLOCK_SIZE Amount of storage, in bytes, that a single packet occupies in the receive buffer space of the NIC
4 | M |  | OID_GEN_VENDOR_ID Vendor NIC code
Var. | M |  | OID_GEN_VENDOR_DESCRIPTION Vendor network card description
4 | M |  | OID_GEN_VENDOR_DRIVER_VERSION Vendor-assigned version number of the driver
4 | M | M | OID_GEN_CURRENT_PACKET_FILTER Current packet filter (encoded)
4 | M | M | OID_GEN_CURRENT_LOOKAHEAD Current lookahead size in bytes
2 | M |  | OID_GEN_DRIVER_VERSION NDIS version number used by the driver
4 | M |  | OID_GEN_MAXIMUM_TOTAL_SIZE Maximum total packet length in bytes
4 |  | M | OID_GEN_PROTOCOL_OPTIONS Optional protocol flags (encoded)
4 | M |  | OID_GEN_MAC_OPTIONS Optional NIC flags (encoded)
4 | M |  | OID_GEN_MEDIA_CONNECT_STATUS Whether the NIC is connected to the network
4 | M |  | OID_GEN_MAXIMUM_SEND_PACKETS The maximum number of send packets the driver can accept per call to its MiniportSendPackets function
Arr | O |  | OID_GEN_SUPPORTED_GUIDS The custom GUIDs (Globally Unique Identifier) supported by the miniport driver
Arr |  | O | OID_GEN_NETWORK_LAYER_ADDRESSES List of network-layer addresses associated with the binding between a transport and the driver
4 |  | O | OID_GEN_TRANSPORT_HEADER_OFFSET Size of packets' additional headers
4 | O |  | OID_GEN_PHYSICAL_MEDIUM Physical media supported by the miniport driver (encoded)
Var. |  | O | OID_GEN_MACHINE_NAME The system name.
4 | O | O | OID_GEN_VLAN_ID The VLAN identifier (ID) for a NIC that the miniport driver handles
30 |  | O | OID_GEN_RNDIS_CONFIG_PARAMETER Device-specific configuration parameter (RNDIS only).

The following topics describe the OIDs that are used to get or set general operational characteristics.

OID_GEN_SUPPORTED_LIST

The OID_GEN_SUPPORTED_LIST OID specifies an array of OIDs for objects that the underlying driver or its NIC supports. Objects include general, media-specific, and implementation-specific objects.

The underlying driver should order the OID list it returns in ascending numeric order. NDIS forwards a subset of the returned list to protocols that make this query. That is, NDIS filters any supported statistics OIDs out of the list because protocols never make statistics queries.

OID_GEN_HARDWARE_STATUS

The OID_GEN_HARDWARE_STATUS OID specifies the current hardware status of the underlying NIC as one of the following NDIS_HARDWARE_STATUS-type values:

NdisHardwareStatusReady
Available and capable of sending and receiving data over the wire
NdisHardwareStatusInitializing
Initializing
NdisHardwareStatusReset
Resetting
NdisHardwareStatusClosing
Closing
NdisHardwareStatusNotReady
Not ready

OID_GEN_MEDIA_SUPPORTED

The OID_GEN_MEDIA_SUPPORTED OID specifies the media types that the NIC can support but not necessarily the media types that the NIC currently uses. These media types are listed as a proper subset of the following system-defined values:

NdisMedium802_3
Ethernet (802.3)
NdisMedium802_5
Token Ring (802.5)
NdisMediumFddi
FDDI
NdisMediumWan
WAN
NdisMediumLocalTalk
LocalTalk
NdisMediumDix
DEC/Intel/Xerox (DIX) Ethernet
NdisMediumArcnetRaw
ARCNET (raw)
NdisMediumArcnet878_2
ARCNET (878.2)
NdisMediumAtm
ATM
NdisMediumWirelessWan
Various types of NdisWireless Xxx media
NdisMediumIrda
Infrared (IrDA)
NdisMediumCoWan
Connection-oriented WAN
NdisMedium1394
IEEE 1394 (firewire) bus

A wireless-WAN NIC driver must report its medium type as NdisMediumWirelessWan. However, such a miniport driver also must provide NdisWWDIXEthernetFrames header format to any bound protocol that selects this format. The miniport driver can provide its NIC's native header format as well. To support existing LAN-based protocols, the driver writer can provide an NDIS intermediate driver to "translate" a wireless NIC's native header formats and medium-specific information into a form that is understood by existing protocols.

Note that wireless-WAN and wireless-LAN media are different. A wireless-LAN network transfers packets that appear to the operating system and to NDIS as Ethernet packets. Currently, NDIS drivers should provide support for wireless-LAN networks as Ethernet networks. Such drivers declare their medium as NdisMedium802_3 and emulate Ethernet to higher-level NDIS drivers. For more information, see OID_GEN_PHYSICAL_MEDIUM.

If the underlying miniport driver returns NULL for this query or if an experimental media type is used, the driver must indicate receive operations using the NdisMIndicateReceivePacket function. Any protocol that is bound to such an underlying NIC driver receives all such indications, that is, the protocol cannot filter receive operations with OID_GEN_CURRENT_PACKET_FILTER.

OID_GEN_MEDIA_IN_USE

The OID_GEN_MEDIA_IN_USE OID specifies a complete list of the media types that the NIC currently uses. This list can include some, none (also called "the NULL filter"), or all of the following:

NdisMedium802_3
Ethernet (802.3)
NdisMedium802_5
Token Ring (802.5)
NdisMediumFddi
FDDI
NdisMediumWan
WAN
NdisMediumLocalTalk
LocalTalk
NdisMediumDix
DIX
NdisMediumArcnetRaw
ARCNET (raw)
NdisMediumArcnet878_2
ARCNET (878.2)
NdisMediumAtm
ATM
NdisMediumWirelessWan
Various types of NdisWireless Xxx media
NdisMediumIrda
Infrared (IrDA)
NdisMediumCoWan
Connection-oriented WAN
NdisMedium1394
IEEE 1394 (firewire) bus

If the underlying miniport driver returns a NULL value for this query or if an experimental media type is used, the driver must indicate receive operations using the NdisMIndicateReceivePacket function. Any protocol that is bound to such an underlying NIC driver receives all such indications, that is, the protocol cannot filter receive operations with OID_GEN_CURRENT_PACKET_FILTER.

OID_GEN_MAXIMUM_LOOKAHEAD

The OID_GEN_MAXIMUM_LOOKAHEAD OID specifies the maximum number of bytes that the NIC can provide as lookahead data. This specification does not include a header.

Upper-layer drivers examine lookahead data to determine whether a packet that is associated with the lookahead data is intended for one or more of their clients.

If the underlying driver supports multipacket receive indications, bound protocols are given full net packets on every indication. Consequently, this value is identical to that returned for OID_GEN_RECEIVE_BLOCK_SIZE.

OID_GEN_MAXIMUM_FRAME_SIZE

The OID_GEN_MAXIMUM_FRAME_SIZE OID specifies the maximum network packet size, in bytes, that the NIC supports. This specification does not include a header.

In response to this query from requesting transports, the NIC driver should indicate the maximum frame size that the transports can send, excluding the header. A NIC driver that emulates another medium type for binding to a transport must ensure that the maximum frame size for a protocol-supplied net packet does not exceed the size limitations for the true network medium. The same is true for a NIC driver which supports a NIC that requires inserting fields in frames. For example, to determine the maximum transfer unit (MTU), transports send this query to a NIC. If the NIC driver supports 802.1p packet priority and, based on prior actions, if the NIC driver expects that frames must traverse legacy networks before priority values are removed, that NIC driver might indicate a smaller value in response to this query.

OID_GEN_LINK_SPEED

The OID_GEN_LINK_SPEED OID specifies the maximum speed of the NIC in kbps. The unit of measurement is 100 bps, so a value of 100,000 represents a hardware bit rate of 10 Mbps.

OID_GEN_TRANSMIT_BUFFER_SPACE

The OID_GEN_TRANSMIT_BUFFER_SPACE OID specifies the amount of memory, in bytes, on the NIC that is available for buffering transmit data. A protocol can use this OID as a guide for sizing the amount of transmit data per send.

OID_GEN_RECEIVE_BUFFER_SPACE

The OID_GEN_RECEIVE_BUFFER_SPACE OID specifies the amount of memory on the NIC that is available for buffering receive data. A protocol driver can use this OID as a guide for advertising its receive window after it establishes sessions with remote nodes.

OID_GEN_TRANSMIT_BLOCK_SIZE

The OID_GEN_TRANSMIT_BLOCK_SIZE OID specifies the minimum number of bytes that a single net packet occupies in the transmit buffer space of the NIC.

For example, a NIC that has a transmit space divided into 256-byte pieces would have a transmit block size of 256 bytes. To calculate the total transmit buffer space on such a NIC, its driver multiplies the number of transmit buffers on the NIC by its transmit block size.

For other NICs, the transmit block size is identical to its maximum packet size.

OID_GEN_RECEIVE_BLOCK_SIZE

The OID_GEN_RECEIVE_BLOCK_SIZE OID specifies the amount of storage, in bytes, that a single packet occupies in the receive buffer space of the NIC.

OID_GEN_VENDOR_ID

The OID_GEN_VENDOR_ID OID specifies a three-byte IEEE-registered vendor code, followed by a single byte that the vendor assigns to identify a particular NIC.

The IEEE code uniquely identifies the vendor and is the same as the three bytes appearing at the beginning of the NIC hardware address.

Vendors without an IEEE-registered code should use the value 0xFFFFFF.

OID_GEN_VENDOR_DESCRIPTION

The OID_GEN_VENDOR_DESCRIPTION OID points to a zero-terminated string describing the NIC.

OID_GEN_VENDOR_DRIVER_VERSION

The OID_GEN_VENDOR_DRIVEN_VERSION OID specifies the vendor-assigned version number of the NIC driver.

The low-order half of the return value specifies the minor version; the high-order half specifies the major version.

OID_GEN_CURRENT_PACKET_FILTER

The OID_GEN_CURRENT_PACKET_FILTER OID specifies the types of net packets for which a protocol receives indications from a NIC driver. This NIC driver reports its medium type as one for which the system provides a filter library. The packet filter uses the OR operation to inclusively combine the following types:

NDIS_PACKET_TYPE_ALL_FUNCTIONAL
All functional address packets, not just the ones in the current functional address.
NDIS_PACKET_TYPE_ALL_MULTICAST
All multicast address packets, not just the ones enumerated in the multicast address list.
NDIS_PACKET_TYPE_ALL_LOCAL
All packets sent by installed protocols and all packets indicated by the NIC that is identified by a given NdisBindingHandle.
NDIS_PACKET_TYPE_BROADCAST
Broadcast packets.
NDIS_PACKET_TYPE_DIRECTED
Directed packets. Directed packets contain a destination address equal to the station address of the NIC.
NDIS_PACKET_TYPE_FUNCTIONAL
Functional address packets sent to addresses included in the current functional address.
NDIS_PACKET_TYPE_GROUP
Packets sent to the current group address.
NDIS_PACKET_TYPE_MAC_FRAME
NIC driver frames that a Token Ring NIC receives.
NDIS_PACKET_TYPE_SMT
SMT packets that an FDDI NIC receives.
NDIS_PACKET_TYPE_MULTICAST
Multicast address packets sent to addresses in the multicast address list.

A protocol driver can receive Ethernet (802.3) multicast packets or Token Ring (802.5) functional address packets by specifying the multicast or functional address packet type. Setting the multicast address list or functional address determines which multicast address groups the NIC driver enables.

NDIS_PACKET_TYPE_PROMISCUOUS
Specifies all packets.
NDIS_PACKET_TYPE_SOURCE_ROUTING
All source routing packets. If the protocol driver sets this bit, the NDIS library attempts to act as a source routing bridge.

During a call to NdisOpenAdapter, NDIS disables packet reception, along with multicast and functional addresses.

For a query, NDIS returns the binding filters that are combined using the OR operator.

For a set, the specified packet filter replaces the previous packet filter for the binding. If the NIC driver previously enabled a packet type but the protocol driver does not specify that type in a new filter, the protocol driver will not receive packets of this type.

If the NIC driver does not set a bit for a particular packet type in response to this query, the protocol driver will not receive packets of that type. Consequently, a protocol driver can disable packet reception by calling the NdisRequest or NdisCoRequest function using a filter of zero.

When a miniport driver's MiniportInitialize function is called, the miniport driver's packet filter should be set to zero. When the packet filter is zero, receive indications are disabled. After a miniport driver's MiniportInitialize function has returned, a protocol driver can set OID_GEN_CURRENT_PACKET_FILTER to a non-zero value, thereby enabling the miniport driver to indicate receive packets to that protocol.

If promiscuous mode is enabled with the NDIS_PACKET_TYPE_PROMISCUOUS bit, the protocol driver continues to receive packets even if the sending network node does not direct them to it. NDIS then sends the protocol driver all packets the NIC receives.

Setting a specific packet filter does not alter the packet filter for other protocols that are bound to (or above) the same NIC. For example, if one bound protocol enables promiscuous mode, other bound protocols do not receive packets that they have not specifically requested with their own packet filters.

OID_GEN_CURRENT_LOOKAHEAD

The OID_GEN_CURRENT_LOOKAHEAD OID specifies the number of bytes of received packet data that will be indicated to the protocol driver. This specification does not include the header.

For a query, NDIS returns the largest lookahead size from among all the bindings. A protocol driver can set a suggested value for the number of bytes to be used in its binding; however, the underlying NIC driver is never required to limit its indications to the value set.

If the underlying driver supports multipacket receive indications, bound protocols are given full net packets on every indication. Consequently, this value is identical to that returned for OID_GEN_RECEIVE_BLOCK_SIZE.

OID_GEN_DRIVER_VERSION

The OID_GEN_DRIVER_VERSION OID specifies the NDIS version in use by the NIC driver. The high byte is the major version number; the low byte is the minor version number.

OID_GEN_MAXIMUM_TOTAL_SIZE

The OID_GEN_MAXIMUM_TOTAL_SIZE OID specifies the maximum total packet length, in bytes, the NIC supports. This specification includes the header.

The returned length specifies the largest packet size for the underlying medium. Thus, the returned length depends on the particular medium. A protocol driver might use this returned length as a gauge to determine the maximum size packet that a NIC driver could forward to the protocol driver. If the protocol driver pre-allocates buffers, it allocates buffers accordingly. The returned length also specifies the largest packet a protocol driver can pass to NdisSend or NdisSendPackets.

OID_GEN_PROTOCOL_OPTIONS

The OID_GEN_PROTOCOL_OPTIONS OID specifies a bitmask that defines optional properties of the protocol driver. A protocol informs NDIS of its properties, which can optionally take advantage of them. If the protocol driver does not set its flags on a binding, NDIS assumes they are all clear.

The following flags are currently defined:

NDIS_PROT_OPTION_ESTIMATED_LENGTH
Specifies that packets can be indicated at the worst-case estimate of packet size, instead of an exact value, to this protocol.
NDIS_PROT_OPTION_NO_LOOPBACK
Specifies that the protocol does not require loopback support on the binding.

OID_GEN_MAC_OPTIONS

The OID_GEN_MAC_OPTIONS OID specifies a bitmask that defines optional properties of the underlying driver or its NIC. A protocol that initiates this query can determine which of the flags the underlying driver sets, and can optionally take advantage of them.

The following flags are currently defined:

NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA
The protocol driver is free to access indicated data by any means. Some fast-copy functions have trouble accessing on-board device memory. NIC drivers that indicate data out of mapped device memory should never set this flag. If a NIC driver does set this flag, it relaxes the restriction on fast-copy functions.
NDIS_MAC_OPTION_RECEIVE_SERIALIZED
The NIC driver indicates packets in a serial manner. That is, such a driver does not enter a new receive indication until the previous receive and any associated calls to the driver's MiniportTransferData function, if any, have been completed.
NDIS_MAC_OPTION_TRANSFERS_NOT_PEND
The NIC driver never returns NDIS_STATUS_PENDING from its MiniportTransferData function. The call succeeds or fails immediately in all cases.

A miniport driver that indicates receive operations with the NdisMIndicateReceivePacket function has no MiniportTransferData function. Such a driver should set this flag.

NDIS_MAC_OPTION_NO_LOOPBACK
The NIC has no internal loopback support so NDIS will manage loopbacks on behalf of this driver. A miniport driver cannot provide its own software loopback as efficiently as NDIS, so every miniport driver should set this flag unless its NIC has hardware loopback support. WAN miniport drivers must set this flag.
NDIS_MAC_OPTION_FULL_DUPLEX
The NIC driver supports full-duplex transmits and indications on SMP platforms. NDIS serializes calls to the MiniportSend(Packets) function of such a driver separately from its serialized calls to other MiniportXxx functions. A driver that reports its medium type as NdisMediumWan cannot set this flag, and WAN miniport drivers cannot be full-duplex drivers.
NDIS_MAC_OPTION_8021P_PRIORITY
The NIC and its driver support 802.1p packet priority. For more information, see 802.1P Packet Priority. Packet-priority values are received in NDIS_PACKET structures from higher-layer drivers. The appropriate information is generated in the MAC headers of packets and transmitted over the network. In addition, this NIC and its driver support extracting the appropriate information from the MAC headers of packets received from the network. This information is forwarded in NDIS_PACKET structures to higher-layer drivers.
NDIS_MAC_OPTION_8021Q_VLAN
The NIC driver maintains a configured VLAN identifier (ID) for each NIC that the driver handles. During the driver's MiniportInitialize routine for a particular NIC, the driver initially sets the NIC's VLAN ID to zero. The driver's MiniportInitialize routine then reads the following configuration parameter from the registry, and, if the parameter is present, sets the NIC's VLAN ID to the parameter's value.
VlanId, REG_DWORD

OID_GEN_MEDIA_CONNECT_STATUS

The OID_GEN_MEDIA_CONNECT_STATUS OID requests the miniport driver to return the connection status of the NIC on the network as one of the following system-defined values:

NdisMediaStateConnected
NdisMediaStateDisconnected

When a miniport driver senses that the network connection has been lost, it must also call NdisMIndicateStatus or NdisMCoIndicateStatus with NDIS_STATUS_MEDIA_DISCONNECT. When the connection is restored, it must then call NdisM(Co)IndicateStatus with NDIS_STATUS_MEDIA_CONNECT.

OID_GEN_MAXIMUM_SEND_PACKETS

For Serialized Miniport Drivers

The OID_GEN_MAXIMUM_SEND_PACKETS OID specifies the maximum number of send packet descriptors that a miniport driver's MiniportSendPackets function can accept in the array at its PacketArray parameter. NDIS will not call the miniport driver's MiniportSendPackets function with more than this number of packets in the array at PacketArray.

If the underlying driver has only a MiniportSend function, it should return one for this query. In this case, NDIS will always pass one packet to the array at PacketArray.

Legacy NIC drivers usually return NDIS_STATUS_NOT_SUPPORTED for this query.

If a protocol, when calling NdisSendPackets, sends more packets in the packet array than a miniport driver indicates that it can handle, NDIS breaks the incoming packet array into smaller arrays and then calls the miniport driver's MiniportSendPackets function multiple times. It may be more optimal for the miniport driver to handle this situation—that is, to break down the packet array into smaller packet arrays, thereby eliminating multiple calls to its MiniportSendPackets function.

For Deserialized Miniport Drivers

NDIS ignores any value returned by a deserialized driver in response to a query of OID_GEN_MAXIMUM_SEND_PACKETS. NDIS does not adjust the size of the array of packet descriptors that it supplies to a deserialized miniport's MiniportSendPackets function.

OID_GEN_SUPPORTED_GUIDS

The OID_GEN_SUPPORTED_GUIDS OID requests the miniport driver to return an array of structures of the type NDIS_GUID. Each structure in the array specifies the mapping of a custom GUID (globally unique identifier) to either a custom OID or to an NDIS_STATUS that the miniport driver sends through NdisMIndicateStatus.

The NDIS_QUID structure is defined as follows:

typedef struct _NDIS_GUID {
    GUID             Guid;
    union {
        NDIS_OID     Oid;
        NDIS_STATUS  Status;
    };
    ULONG            Size;
    ULONG            Flags;
} NDIS_GUID, *PNDIS_GUID;

The members of this structure contain the following information:

Guid
Specifies the custom GUID defined for the miniport driver.
Oid
Specifies the custom OID to which Guid maps.
Status
Specifies the NDIS_STATUS to which Guid maps.
Size
Specifies the size in bytes of each data item in the array returned by the miniport driver. If the fNDIS_GUID_ANSI_STRING or fNDIS_GUID_NDIS_STRING flag is set, Size is set to -1. Otherwise, Size specifies the size in bytes of the data item that the GUID represents. This member is specified only when the fNDIS_GUID_ARRAY flag is set.
Flags
The following flags can be combined by the OR operator to indicate whether the GUID maps to an OID or to an NDIS_STATUS string and to indicate the type of data that is supplied for the GUID:
fNDIS_GUID_TO_OID
Indicates that the NDIS_GUID structure maps a GUID to an OID.
fNDIS_GUID_TO_STATUS
Indicates that the NDIS_GUID structure maps a GUID to an NDIS_STATUS string.
fNDIS_GUID_ANSI_STRING
Indicates that a zero-terminated ANSI string is supplied for the GUID.
fNDIS_GUID_UNICODE_STRING
Indicates that a UNICODE string is supplied for the GUID.
fNDIS_GUID_ARRAY
Indicates that an array of data items is supplied for the GUID. The specified Size indicates the length of each data item in the array.
fNDIS_GUID_ALLOW_READ
When set, indicates that all users are allowed to use this GUID to obtain information.
fNDIS_GUID_ALLOW_WRITE
When set, indicates that all users are allowed to use this GUID to set information.

Note By default, custom WMI GUIDs supplied by a miniport driver are only accessible to users with administrator privileges. A user with administrator privileges can always read or write to a custom GUID if the miniport driver supports the read or write operation for that GUID. Set the fNDIS_GUID_ALLOW_READ and fNDIS_GUID_ALLOW_WRITE flags to allow all users to access a custom GUID.

Note that all custom GUIDs registered by a miniport driver must set either fNDIS_GUID_TO_OID or fNDIS_GUID_TO_STATUS (never set both). All other flags may be combined by using the OR operator as applicable.

In the following example, an NDIS_GUID structure maps a GUID to OID_802_3_MULTICAST_LIST:

NDIS_GUID    NdisGuid = {{0x44795701, 0xa61b, 0x11d0, 0x8d, 0xd4,
                          0x00, 0xc0, 0x4f, 0xc3,
                          0x35, 0x8c},
                          OID_802_3_MULTICAST_LIST,
                          6,
                          fNDIS_GUID_TO_OID | fNDIS_GUID_ARRAY};

A GUID is an identifier used by Windows Management Instrumentation (WMI) to obtain or set information. NDIS intercepts a GUID sent by WMI to an NDIS driver, it maps the GUID to an OID, and sends the OID to the driver. The driver returns the data items to NDIS, which then returns the data to WMI.

NDIS also translates changes in NIC status into GUIDs that are recognized by WMI. When a miniport driver reports a change in NIC status using the NdisMIndicateStatus function, NDIS translates the NDIS_STATUS indicated by the miniport driver into a GUID that NDIS sends to WMI.

If a miniport driver supports customs GUIDs, it must support OID_GEN_SUPPORTED_GUIDS. This OID returns to NDIS the mapping of custom GUIDs to custom OIDs or NDIS_STATUS strings. After querying the miniport driver using OID_GEN_SUPPORTED_GUIDS, NDIS registers the miniport driver's custom GUIDs with WMI.

OID_GEN_NETWORK_LAYER_ADDRESSES

The OID_GEN_NETWORK_LAYER_ADDRESSES OID notifies underlying miniport driver and other layered drivers about the list of network-layer addresses that are associated with bound instances. A bound instance is the binding between the calling transport and a driver set up by a call to NdisOpenAdapter. Transports use TRANSPORT_ADDRESS and TA_ADDRESS structures to notify underlying miniport drivers and other layered drivers about the list of network-layer addresses. Miniport drivers and other layered drivers use compatible NETWORK_ADDRESS_LIST and NETWORK_ADDRESS structures, defined as follows, to set the list of network-layer addresses on a bound interface.

typedef struct _NETWORK_ADDRESS_LIST {
  LONG  AddressCount;
  USHORT  AddressType;
  NETWORK_ADDRESS  Address[1];
} NETWORK_ADDRESS_LIST, *PNETWORK_ADDRESS_LIST;

The members of this structure contain the following information:

AddressCount
Specifies the number of network-layer addresses listed in the array in the Address member.
AddressType
Specifies the protocol type that sends this OID. This member is only valid if the AddressCount member is set to zero. The AddressCount member is set to zero to notify a miniport driver or other layered driver to clear the list of network-layer addresses on a bound interface. The protocol can be one of the following values:
NDIS_PROTOCOL_ID_DEFAULT
Default protocol
NDIS_PROTOCOL_ID_TCP_IP
TCP/IP protocol
NDIS_PROTOCOL_ID_IPX
Netware IPX protocol
NDIS_PROTOCOL_ID_NBF
NetBIOS protocol
Address
Array of network-layer addresses of type NETWORK_ADDRESS. The AddressCount member specifies the number of elements in this array.
typedef struct _NETWORK_ADDRESS {
  USHORT  AddressLength;
  USHORT  AddressType;
  UCHAR   Address[1];
} NETWORK_ADDRESS, *PNETWORK_ADDRESS;

The members of this structure contain the following information:

AddressLength
Specifies the size, in bytes, of this network-layer address. The Address member contains the array of bytes that specify this address.
AddressType
Specifies the protocol type that sends this OID and this network-layer address. This member is only valid if the AddressCount member in the NETWORK_ADDRESS_LIST structure is set to a nonzero value. The AddressCount member in NETWORK_ADDRESS_LIST is set to a nonzero value to notify a miniport driver or other layered driver to change the list of network-layer addresses on a bound interface. Protocol types are defined in the preceding list.
Address
Array of bytes that specify this network-layer address. The AddressLength member specifies the number of bytes in this array.

The transport can call the NdisRequest function and can pass an NDIS_REQUEST structure that is filled with the OID_GEN_NETWORK_LAYER_ADDRESSES code. This call notifies a bound instance of a change in the addresses that are associated with that instance. In this call, the transport also passes the bound instance in the NdisBindingHandle parameter. The bound instance is the binding set up between the transport and the underlying miniport driver or other layered driver. For this call, the transport should fill the InformationBuffer member of NDIS_REQUEST with a pointer to a TRANSPORT_ADDRESS structure. TRANSPORT_ADDRESS corresponds to a NETWORK_ADDRESS_LIST structure and should contain the list of network-layer addresses.

Suppose a transport passes addresses through an intermediate driver down to an underlying miniport driver. If the intermediate driver also requires the addresses, it should take note of them before passing them on to the underlying miniport driver. An underlying miniport driver, especially a legacy driver, can return a status value of NDIS_STATUS_NOT_SUPPORTED or NDIS_STATUS_SUCCESS. The underlying miniport driver propagates the status of the operation back up towards the transport. If the intermediate driver must continue receiving address notifications, and if it is necessary, the intermediate driver should change the status to NDIS_STATUS_SUCCESS.Otherwise, the transport might interpret NDIS_STATUS_NOT_SUPPORTED as an indication that the underlying miniport driver does not require that the transport issue additional address updates. If NDIS_STATUS_SUCCESS is returned, transports are obligated to continue notifying underlying drivers of any change in associated addresses, including addition and deletion of addresses.

A protocol can set the AddressCount member of TRANSPORT_ADDRESS to zero to notify a miniport driver or other layered driver to clear the list of network-layer addresses on a bound interface. If AddressCount is set to zero,the AddressType member in NETWORK_ADDRESS_LIST is valid and the AddressType members in NETWORK_ADDRESS structures are not valid. On the other hand, a protocol can set AddressCount to a nonzero value to notify a miniport driver or other layered driver to change the list of network-layer addresses on a bound interface. In this case, the AddressType member in NETWORK_ADDRESS_LIST is not valid and the AddressType members in NETWORK_ADDRESS structures are valid.

OID_GEN_TRANSPORT_HEADER_OFFSET

The OID_GEN_TRANSPORT_HEADER_OFFSET OID indicates the size of additional headers for packets that a particular transport sends and receives. A transport informs miniport drivers and other layered drivers of this header size; these drivers can then use this information when processing packets. For example, a driver could use the sub-layer header size obtained from the transport to locate the beginning of higher layer information in packets, such as the start of the IP header; the driver could then parse and adjust the fields of the IP protocol header as appropriate. Transports use a TRANSPORT_HEADER_OFFSET structure, defined as follows, to indicate this header size.

typedef struct _TRANSPORT_HEADER_OFFSET {
  USHORT  ProtocolType;
  USHORT  HeaderOffset;
} TRANSPORT_HEADER_OFFSET, *PTRANSPORT_HEADER_OFFSET;

The members of this structure contain the following information:

ProtocolType
Specifies the protocol type that sends this OID and that subsequently sends and receives packets using the specified sub-layer header size. The protocol is one of the following values:
NDIS_PROTOCOL_ID_DEFAULT
Default protocol
NDIS_PROTOCOL_ID_TCP_IP
TCP/IP protocol
NDIS_PROTOCOL_ID_IPX
Netware IPX protocol
NDIS_PROTOCOL_ID_NBF
NetBIOS protocol
HeaderOffset
Specifies the size, in bytes, of the sub-layer header that precedes the protocol header for packets that the protocol subsequently sends to or receives from the miniport driver or other layered driver. For example, sizeof(Ethernet header) + sizeof(SNAP header).

Typically, transports calculate the header size of packets from information that is retrieved from miniport drivers. To request the maximum total packet size in bytes that a NIC supports, including the header, transports use OID_GEN_MAXIMUM_TOTAL_SIZE. To request the maximum packet size in bytes that a NIC supports, not including a header, transports use OID_GEN_MAXIMUM_FRAME_SIZE. To calculate the maximum header size, transports subtract the maximum frame size from the maximum total size.

If a transport transmits packets that contain sub-layer header information, the transport must know the sub-layer header size of these packets and must inform underlying miniport drivers and other layered drivers about the size so that the drivers can process the packets. Sending and receiving particular sub-layer header information within a packet may be an option that can be set in the registry for a particular protocol. Transports could then obtain information about sub-layer headers from the registry and pass the header size down to miniport drivers or other layered drivers.

For example, if a transport handles packets from the Fiber Distributed Data Interface (FDDI) medium, the transport must send a set request to underlying miniport drivers and other layered drivers using OID_GEN_TRANSPORT_HEADER_OFFSET to inform those drivers about the size of the packets' sub-layer header. These packets from FDDI could contain Logical Link Control (LLC) information. This LLC information could in turn include an LLC header and other headers such as Sub-Network Access Protocol (SNAP). The transport determines from the registry to use LLC/SNAP and passes the header size of the LLC/SNAP segments of packets to miniport drivers.

This OID is optional for miniport drivers and other layered drivers. Because this OID is optional, drivers are not required to respond to requests that transports make using this OID.

OID_GEN_PHYSICAL_MEDIUM

The OID_GEN_PHYSICAL_MEDIUM OID specifies the types of physical media that the NIC supports. This OID is essentially an extension of OID_GEN_MEDIA_SUPPORTED. NICs use this OID to differentiate their physical media from media that they declared to support in the OID_GEN_MEDIA_SUPPORTED query. These media types are listed as a proper subset of the following system-defined values from the NDIS_PHYSICAL_MEDIUM enumeration:

NdisPhysicalMediumWirelessLan
Packets are transferred over a wireless LAN network.
Includes, for example, IEEE 802.11.
NdisPhysicalMediumCableModem
Packets are transferred over a DOCSIS-based cable network.
NdisPhysicalMediumPhoneLine
Packets are transferred over standard phone lines.
Includes, for example, HomePNA media.
NdisPhysicalMediumPowerLine
Packets are transferred over wiring that is connected to a power distribution system.
NdisPhysicalMediumDSL
Packets are transferred over a Digital Subscriber Line (DSL) network.
Includes, for example, ADSL and UADSL (G.Lite).
NdisPhysicalMediumFibreChannel
Packets are transferred over a Fibre Channel interconnect.
NdisPhysicalMedium1394
Packets are transferred over an IEEE 1394 bus.
NdisPhysicalMediumWirelessWan
Packets are transferred over a Wireless WAN link. Includes, for example, CDPD, CDMA and GPRS.
NdisPhysicalMediumUnspecified
The physical medium is none of the above.

This OID should be implemented in miniport drivers for NICs that support newer networks even though those networks transfer packets that appear to the operating system and to NDIS as standard and well known media types. These newer networks are listed preceding.

It is easier to create miniport drivers using standard media types. Therefore, miniport drivers for NICs that support newer networks should still be written to use standard media types, which are enumerated in OID_GEN_MEDIA_SUPPORTED. For example, miniport drivers that transfer packets that appear like Ethernet and ATM media should declare their support of those media. Miniport drivers declare support of Ethernet and ATM media by specifying media types NdisMedium802_3 and NdisMediumAtm respectively in an OID_GEN_MEDIA_SUPPORTED query. In order for a miniport driver to declare support of standard media types, that miniport driver's MAC layer should conform to characteristics for those standard media types.

Newer networks transfer packets that might appear like standard media but that might have new features or slight differences from the standard. This OID was developed so upper-layer drivers and applications could determine the actual networks to which a NIC connects. After retrieving information about underlying networks, upper-layer drivers and applications could use this information to modify how such drivers and applications behave.

OID_GEN_MACHINE_NAME

The OID_GEN_MACHINE_NAME OID, which is optional, indicates the system name. The information buffer passed in this request contains an array of Unicode characters that represents the system name. The InformationBufferLength supplied to MiniportSetInformation specifies the length of this array in bytes, not including a NULL terminator.

NDIS sets OID_GEN_MACHINE_NAME only once after a miniport driver completes initialization. Under Windows® XP, NDIS does not dynamically notify miniport drivers of a change in the system name. After changing the system name, a user must reboot the system so that NDIS notifies miniport drivers of the new system name.

System support for OID_GEN_MACHINE_NAME is available in Windows XP and later operating systems.

OID_GEN_VLAN_ID

The OID_GEN_VLAN_ID OID, which is optional, specifies the configured VLAN identifier (ID) for a NIC that the miniport driver handles. The information buffer passed in this request contains an NDIS_VLAN_ID data type. This NDIS_VLAN_ID value contains the VLAN ID in the 12 least significant bits per the IEEE 802.1q specification. Higher order bits of the NDIS_VLAN_ID value are reserved and must be set to 0. Note that NDIS defines NDIS_VLAN_ID as a ULONG.

When a transport uses OID_GEN_VLAN_ID in a query, the miniport driver returns the current configured VLAN ID for the NIC. When used in a set, the miniport driver sets the NIC's current configured VLAN ID to the specified value.

During the miniport driver's MiniportInitialize routine for a particular NIC, the driver initially sets the NIC's VLAN ID to zero. The driver's MiniportInitialize routine then reads the following configuration parameter from the registry, and, if the parameter is present, sets the NIC's VLAN ID to the parameter's value.

VlanId, REG_DWORD

Support for OID_GEN_VLAN_ID is available in Windows XP and later versions.

OID_GEN_RNDIS_CONFIG_PARAMETER

The OID_GEN_RNDIS_CONFIG_PARAMETER, which is optional, is used with RNDIS devices, the host uses it to set device-specific parameters. It is not used by miniport drivers. For more information about this OID, see Setting Device-Specific Parameters.


General Statistics

The following chart summarizes the OIDs that are used to get the general statistics for NDIS drivers and NICs.

Length | Q | S | Name
4 or 8 | M |  | OID_GEN_XMIT_OK Frames transmitted without errors
4 or 8 | M |  | OID_GEN_RCV_OK Frames received without errors
4 or 8 | M |  | OID_GEN_XMIT_ERROR Frames not transmitted or transmitted with errors
4 or 8 | M |  | OID_GEN_RCV_ERROR Frames received with errors
4 or 8 | M |  | OID_GEN_RCV_NO_BUFFER Frame missed, no buffers
4 or 8 | O |  | OID_GEN_DIRECTED_BYTES_XMIT Directed bytes transmitted without errors
4 or 8 | O |  | OID_GEN_DIRECTED_FRAMES_XMIT Directed frames transmitted without errors
4 or 8 | O |  | OID_GEN_MULTICAST_BYTES_XMIT Multicast bytes transmitted without errors
4 or 8 | O |  | OID_GEN_MULTICAST_FRAMES_XMIT Multicast frames transmitted without errors
4 or 8 | O |  | OID_GEN_BROADCAST_BYTES_XMIT Broadcast bytes transmitted without errors
4 or 8 | O |  | OID_GEN_BROADCAST_FRAMES_XMIT Broadcast frames transmitted without errors
4 or 8 | O |  | OID_GEN_DIRECTED_BYTES_RCV Directed bytes received without errors
4 or 8 | O |  | OID_GEN_DIRECTED_FRAMES_RCV Directed frames received without errors
4 or 8 | O |  | OID_GEN_MULTICAST_BYTES_RCV Multicast bytes received without errors
4 or 8 | O |  | OID_GEN_MULTICAST_FRAMES_RCV Multicast frames received without errors
4 or 8 | O |  | OID_GEN_BROADCAST_BYTES_RCV Broadcast bytes received without errors
4 or 8 | O |  | OID_GEN_BROADCAST_FRAMES_RCV Broadcast frames received without errors
4 or 8 | O |  | OID_GEN_RCV_CRC_ERROR Frames received with circular redundancy check (CRC) or frame check sequence (FCS) error
4 or 8 | O |  | OID_GEN_TRANSMIT_QUEUE_LENGTH Length of transmit queue

Miniport Driver Support for 64-bit Counters

All one-Gbps and faster miniport driversmust support 64-bit counters for the following statistics OIDs. All 100Mbps and faster miniport drivers should support 64-bit counters for the following statistics OIDs:

OID_GEN_XMIT_OK

OID_GEN_RCV_OK

OID_GEN_DIRECTED_BYTES_XMIT

OID_GEN_DIRECTED_FRAMES_XMIT

OID_GEN_MULTICAST_BYTES_XMIT

OID_GEN_MULTICAST_FRAMES_XMIT

OID_GEN_BROADCAST_BYTES_XMIT

OID_GEN_BROADCAST_FRAMES_XMIT

OID_GEN_DIRECTED_BYTES_RCV

OID_GEN_DIRECTED_FRAMES_RCV

OID_GEN_MULTICAST_BYTES_RCV

OID_GEN_MULTICAST_FRAMES_RCV

OID_GEN_BROADCAST_BYTES_RCV

OID_GEN_BROADCAST_FRAMES_RCV

Miniport drivers can also support 64-bit counters for other statistics OIDs, such as OIDs that indicate transmit or receive errors.

System support for 64-bit counters is available in Windows XP and later operating systems.

OID_GEN_XMIT_OK

The OID_GEN_XMIT_OK OID specifies the number of frames that are transmitted without errors.

OID_GEN_RCV_OK

The OID_GEN_RCV_OK OID specifies the number of frames that the NIC receives without errors and indicates to bound protocols.

OID_GEN_XMIT_ERROR

The OID_GEN_XMIT_ERROR OID specifies the number of frames that a NIC fails to transmit.

OID_GEN_RCV_ERROR

The OID_GEN_RCV_ERROR OID specifies the number of frames that a NIC receives but does not indicate to the protocols due to errors.

OID_GEN_RCV_NO_BUFFER

The OID_GEN_RCV_NO_BUFFER OID specifies the number of frames that the NIC cannot receive due to lack of NIC receive buffer space. Some NICs do not provide the exact number of missed frames; they provide only the number of times at least one frame is missed.

OID_GEN_DIRECTED_BYTES_XMIT

The OID_GEN_DIRECTED_BYTES_XMIT OID specifies the number of bytes in directed packets that are transmitted without errors.

OID_GEN_DIRECTED_FRAMES_XMIT

The OID_GEN_DIRECTED_FRAMES_XMIT OID specifies the number of directed packets that are transmitted without errors.

OID_GEN_MULTICAST_BYTES_XMIT

The OID_GEN_MULTICAST_BYTES_XMIT OID specifies the number of bytes in multicast/functional packets that are transmitted without errors.

OID_GEN_MULTICAST_FRAMES_XMIT

The OID_GEN_MULTICAST_FRAMES_XMIT OID specifies the number of multicast/functional packets that are transmitted without errors.

OID_GEN_BROADCAST_BYTES_XMIT

The OID_GEN_BROADCAST_BYTES_XMIT OID specifies the number of bytes in broadcast packets that are transmitted without errors.

OID_GEN_BROADCAST_FRAMES_XMIT

The OID_GEN_BROADCAST_FRAMES_XMIT OID specifies the number of broadcast packets that are transmitted without errors.

OID_GEN_DIRECTED_BYTES_RCV

The OID_GEN_DIRECTED_BYTES_RCV OID specifies the number of bytes in directed packets that are received without errors.

OID_GEN_DIRECTED_FRAMES_RCV

The OID_GEN_DIRECTED_FRAMES_RCV OID specifies the number of directed packets that are received without errors.

OID_GEN_MULTICAST_BYTES_RCV

The OID_GEN_MULTICAST_BYTES_RCV OID specifies the number of bytes in multicast/functional packets that are received without errors.

OID_GEN_MULTICAST_FRAMES_RCV

The OID_GEN_MULTICAST_FRAMES_RCV OID specifies the number of multicast/functional packets that are received without errors.

OID_GEN_BROADCAST_BYTES_RCV

The OID_GEN_BROADCAST_BYTES_RCV OID specifies the number of bytes in broadcast packets that are received without errors.

OID_GEN_BROADCAST_FRAMES_RCV

The OID_GEN_BROADCAST_FRAMES_RCV OID specifies the number of broadcast packets that are received without errors.

OID_GEN_RCV_CRC_ERROR

The OID_GEN_RCV_CRC_ERROR OID specifies the number of frames that are received with checksum errors.

OID_GEN_TRANSMIT_QUEUE_LENGTH

The OID_GEN_TRANSMIT_QUEUE_LENGTH OID specifies the number of packets that are currently queued for transmission, whether on the NIC or in a driver-internal queue. For queries, the number returned is always the total number of packets currently queued. This number can include unsubmitted send requests queued in the NDIS library.


Ethernet Objects

This section describes the OIDs for Ethernet objects, both operational and statistical types.

The Ethernet OIDs are defined in ntddndis.h. When building a driver that supports these OIDs, include ntddndis.h.

These OIDs are discussed in the following topics:

Ethernet Operational Characteristics

Ethernet Statistics


Ethernet Operational Characteristics

The following chart summarizes the OIDs used to get or set Ethernet operational characteristics for underlying NDIS drivers and their NICs.

Length | Q | S | Name
6 | M |  | OID_802_3_PERMANENT_ADDRESS Permanent station address
6 | M |  | OID_802_3_CURRENT_ADDRESS Current station address
Arr(6) | M | M | OID_802_3_MULTICAST_LIST Current multicast address list
4 | M |  | OID_802_3_MAXIMUM_LIST_SIZE Maximum size of multicast address list
4 | O |  | OID_802_3_MAC_OPTIONS NIC flags (encoded)

The following describes each of the OID_XXX listed in the preceding chart more fully.

OID_802_3_PERMANENT_ADDRESS

The address of the NIC encoded in the hardware.

OID_802_3_CURRENT_ADDRESS

The address the NIC is currently using.

The network management software cannot set the current station address using the NDIS interface library. It must set this address as a configuration parameter.

OID_802_3_MULTICAST_LIST

The multicast address list on the NIC enabled for packet reception.

When a NIC driver initializes, it resets the NIC so the multicast address list is zero. NDIS also initializes the packet filter so it does not allow the protocol driver to receive multicast packets.

To receive a multicast packet, the protocol driver must later set the packet filter to include the NDIS_PACKET_TYPE_MULTICAST flag. At any time, it can disable multicast packet reception by canceling this flag. The order in which the protocol driver enables reception for multicast packets is not important.

The NIC driver can set a limit on the number of multicast addresses bound protocol drivers can enable simultaneously. NDIS returns NDIS_STATUS_MULTICAST_FULL if a protocol driver exceeds this limit or if it specifies an invalid multicast address.

A protocol driver can set the packet filter to enable all multicast packets, and do the filtering itself.

For a query, NDIS returns a list containing the union of all bindings' multicast address lists.

OID_802_3_MAC_OPTIONS

A protocol can use this OID to determine features supported by the underlying driver, which could be emulating Ethernet. The underlying driver returns zero, indicating that it supports no options.

OID_802_3_MAXIMUM_LIST_SIZE

The maximum number of multicast addresses the NIC driver can manage.

This list is global for all protocols bound to (or above) the NIC. Consequently, a protocol can receive NDIS_STATUS_MULTICAST_FULL from the NIC driver when attempting to set the multicast address list, even if the number of elements in the given list is less than the number originally returned for this query.


Ethernet Statistics

The following chart summarizes the OIDs used to get Ethernet statistics for NICs.

Length | Q | S | Name
4 | M |  | OID_802_3_RCV_ERROR_ALIGNMENT Frames received with alignment error
4 | M |  | OID_802_3_XMIT_ONE_COLLISION Frames transmitted with one collision
4 | M |  | OID_802_3_XMIT_MORE_COLLISIONS Frames transmitted with more than one collision
4 | O |  | OID_802_3_XMIT_DEFERRED Frames transmitted after deferral
4 | O |  | OID_802_3_XMIT_MAX_COLLISIONS Frames not transmitted due to collisions
4 | O |  | OID_802_3_RCV_OVERRUN Frames not received due to overrun
4 | O |  | OID_802_3_XMIT_UNDERRUN Frames not transmitted due to underrun
4 | O |  | OID_802_3_XMIT_HEARTBEAT_FAILURE Frames transmitted with heartbeat failure
4 | O |  | OID_802_3_XMIT_TIMES_CRS_LOST Times carrier sense signal lost during transmission
4 | O |  | OID_802_3_XMIT_LATE_COLLISIONS Late collisions detected

The following describes each of the OID_XXX listed in the preceding chart more fully.

OID_802_3_RCV_ERROR_ALIGNMENT

The number of frames received with alignment errors.

OID_802_3_XMIT_ONE_COLLISION

The number of frames successfully transmitted after exactly one collision.

OID_802_3_XMIT_MORE_COLLISIONS

The number of frames successfully transmitted after more than one collision.

OID_802_3_XMIT_DEFERRED

The number of frames successfully transmitted after the NIC defers transmission at least once.

OID_802_3_XMIT_MAX_COLLISIONS

The number of frames not transmitted due to excessive collisions.

OID_802_3_RCV_OVERRUN

The number of frames not received due to overrun errors on the NIC.

OID_802_3_XMIT_UNDERRUN

The number of frames not transmitted due to underrun errors on the NIC.

OID_802_3_XMIT_HEARTBEAT_FAILURE

The number of frames successfully transmitted without detection of the collision-detect heartbeat.

OID_802_3_XMIT_TIMES_CRS_LOST

The number of times the CRS signal has been lost during packet transmission.

OID_802_3_XMIT_LATE_COLLISIONS

The number of collisions detected after the normal window.


Token Ring Objects

This section describes the OIDs for Token Ring objects, both operational and statistical types.

The Token Ring OIDs are defined in ntddndis.h. When building a driver that supports these OIDs, include ntddndis.h.

These OIDs are discussed in the following topics:

Token Ring Operational Characteristics

Token Ring Statistics


Token Ring Operational Characteristics

The following chart summarizes the OIDs used to get or set Token Ring operational characteristics for NDIS drivers and NICs.

Length | Q | S | Name
6 | M |  | OID_802_5_PERMANENT_ADDRESS Permanent station address
6 | M |  | OID_802_5_CURRENT_ADDRESS Current station address
4 | M | M | OID_802_5_CURRENT_FUNCTIONAL Current functional address
4 | M | M | OID_802_5_CURRENT_GROUP Current group address
4 | M |  | OID_802_5_LAST_OPEN_STATUS Last open status
4 | M |  | OID_802_5_CURRENT_RING_STATUS Current ring status
4 | M |  | OID_802_5_CURRENT_RING_STATE Current ring state

The following describes each of the OID_XXX listed in the preceding chart more fully.

OID_802_5_PERMANENT_ADDRESS

The address of the NIC encoded in the hardware.

OID_802_5_CURRENT_ADDRESS

The address the NIC is currently using.

The network management software cannot set the current station address using the NDIS library. It must set the address as a configuration parameter.

OID_802_5_CURRENT_FUNCTIONAL

The functional address enabled on the NIC for packet reception.

When the underlying driver initializes its NIC, it resets the functional address to zero. NDIS also initializes the packet filter so that a protocol does not receive functional address packets.

To receive a functional address packet, a bound protocol must later set the packet filter to include the NDIS_PACKET_TYPE_FUNCTIONAL flag. At any time, it can disable packet reception by canceling this flag. The order in which the protocol enables reception for functional address packets is unimportant.

OID_802_5_CURRENT_GROUP

The group address enabled on the NIC for packet reception.

OID_802_5_LAST_OPEN_STATUS

The last open error status returned for a protocol's call to NdisOpenAdapter.

If the open succeeded, a status code other than NDIS_STATUS_OPEN_FAILED was returned for the most recent open of the target NIC, so the value returned for this query should be zero.

OID_802_5_CURRENT_RING_STATUS

The last ring status indicated with an NDIS_RING_XXX status code, which can be any of the following values:
NDIS_RING_SIGNAL_LOSS
NDIS_RING_HARD_ERROR
NDIS_RING_SOFT_ERROR
NDIS_RING_TRANSMIT_BEACON
NDIS_RING_LOBE_WIRE_FAULT
NDIS_RING_AUTO_REMOVAL_ERROR
NDIS_RING_REMOVE_RECEIVED
NDIS_RING_COUNTER_OVERFLOW
NDIS_RING_SINGLE_STATION
NDIS_RING_RING_RECOVERY

OID_802_5_CURRENT_RING_STATE

The state of the NIC driver with respect to entering the ring, as one of the following:

NdisRingStateOpened
Specifies an open ring.
NdisRingStateClosed
Specifies a closed ring.
NdisRingStateOpening
Specifies a ring that is opening.
NdisRingStateClosing
Specifies a ring that is closing.
NdisRingStateOpenFailure
Specifies a failure of a ring open operation.
NdisRingStateRingFailure
Specifies a failure of the ring.


Token Ring Statistics

The following chart summarizes the OIDs used to get Token Ring statistics for NICs.

Length | Q | S | Name
4 | M |  | OID_802_5_LINE_ERRORS FCS or code violations detected in repeated frame
4 | M |  | OID_802_5_LOST_FRAMES Frames transmitted that have failed to return
4 | O |  | OID_802_5_BURST_ERRORS Number of five half-bit transition absences detected
4 | O |  | OID_802_5_AC_ERRORS Access control (A/C) errors
4 | O |  | OID_802_5_ABORT_DELIMITERS Frames transmitted with abort delimiter
4 | O |  | OID_802_5_FRAME_COPIED_ERRORS Frame copy errors
4 | O |  | OID_802_5_FREQUENCY_ERRORS Frequency errors detected
4 | O |  | OID_802_5_TOKEN_ERRORS Active monitor regenerations
4 | O |  | OID_802_5_INTERNAL_ERRORS Internal errors detected

The following describes each of the OID_XXX listed in the preceding chart more fully.

OID_802_5_LINE_ERRORS

The number of frames with an invalid FCS or a code violation.

OID_802_5_LOST_FRAMES

The number of frames transmitted that have not circled the ring within the maximum ring latency.

OID_802_5_BURST_ERRORS

The number of frames containing five half bits with no transition.

OID_802_5_AC_ERRORS

The number of frames with A/C errors.

OID_802_5_ABORT_DELIMITERS

The number of abort delimiters transmitted.

OID_802_5_FRAME_COPIED_ERRORS

The number of frames addressed to this NIC that another NIC on the ring has also copied.

OID_802_5_FREQUENCY_ERRORS

The number of frequency errors on the ring.

OID_802_5_TOKEN_ERRORS

The number of times the NIC has been the active monitor and has had to recreate.

OID_802_5_INTERNAL_ERRORS

The number of internal errors the NIC has detected.


FDDI Objects

This section describes the mandatory OIDs for FDDI objects, both operational and statistical types.

The FDDI OIDs are defined in ntddndis.h. When building a driver that supports these OIDs, include ntddndis.h.

These OIDs are described in the following topics:

FDDI Operational Characteristics

FDDI Statistics


FDDI Operational Characteristics

The following chart summarizes the mandatory OIDs used to get or set FDDI operational characteristics for NDIS drivers and NICs.

Length | Q | S | Name
6 | M |  | OID_FDDI_LONG_PERMANENT_ADDR Permanent station address
6 | M |  | OID_FDDI_LONG_CURRENT_ADDR Current station address
Arr(6) | M | M | OID_FDDI_LONG_MULTICAST_LIST Multicast list
4 | M |  | OID_FDDI_LONG_MAX_LIST_SIZE Maximum list size
2 | M |  | OID_FDDI_SHORT_PERMANENT_ADDR Permanent station address
2 | M |  | OID_FDDI_SHORT_CURRENT_ADDR Current station address
Arr(2) | M | M | OID_FDDI_SHORT_MULTICAST_LIST Multicast list
4 | M |  | OID_FDDI_SHORT_MAX_LIST_SIZE Maximum list size

The following describes each of the OID_XXX listed in the preceding chart more fully.

OID_FDDI_LONG_PERMANENT_ADDR

The address of the NIC encoded in the hardware.

OID_FDDI_LONG_CURRENT_ADDR

The address the NIC is currently using.

The network management software cannot set the current station address using the NDIS interface library. It must set this address as a configuration parameter.

OID_FDDI_LONG_MULTICAST_LIST

The list of multicast addresses the NIC is currently using.

OID_FDDI_LONG_MAX_LIST_SIZE

The maximum size multicast list the NIC supports.

OID_FDDI_SHORT_PERMANENT_ADDR

The address of the NIC encoded in the hardware.

OID_FDDI_SHORT_CURRENT_ADDR

The address the NIC is currently using.

The network management software cannot set the current station address using the NDIS interface library. It must set this address as a configuration parameter.

OID_FDDI_SHORT_MULTICAST_LIST

The list of multicast addresses the NIC is currently using.

OID_FDDI_SHORT_MAX_LIST_SIZE

The maximum size multicast list the NIC supports.


FDDI Statistics

The following chart summarizes the mandatory OIDs used to get FDDI statistics from underlying NIC drivers (or from NDIS).

Length | Q | S | Name
4 | M |  | OID_FDDI_ATTACHMENT_TYPE The direction of traffic on the ring
6 | M |  | OID_FDDI_UPSTREAM_NODE_LONG The long address of the station above this NIC on the ring
6 | M |  | OID_FDDI_DOWNSTREAM_NODE_LONG The long address of the station below this NIC on the ring
4 | M |  | OID_FDDI_FRAME_ERRORS The number of frames transmitted by this NIC that returned with errors
4 | M |  | OID_FDDI_FRAMES_LOST The number of frames transmitted by this NIC that were not returned within an acceptable interval
4 | M |  | OID_FDDI_RING_MGT_STATE The current state of the ring-management state machine.
4 | M |  | OID_FDDI_LCT_FAILURES The number of times the link confidence test has failed during connection management.
4 | M |  | OID_FDDI_LEM_REJECTS The link error monitor count of the times that a link was rejected.
4 | M |  | OID_FDDI_LCONNECTION_STATE The state of this ports physical connection management state machine.

The following describes each of the OID_XXX listed in the preceding chart more fully.

OID_FDDI_ATTACHMENT_TYPE

Defines the attachment of the NIC to the network as one of the following:

NdisFddiTypeIsolated
NdisFddiTypeLocalA
NdisFddiTypeLocalB
NdisFddiTypeLocalAB
NdisFddiTypeLocalS
NdisFddiTypeWrapA
NdisFddiTypeWrapB
NdisFddiTypeWrapAB
NdisFddiTypeWrapS
NdisFddiTypeCWrapA
NdisFddiTypeCWrapB
NdisFddiTypeCWrapS
NdisFddiTypeThrough

OID_FDDI_UPSTREAM_NODE_LONG

The long address of the station above this NIC on the ring or zero if the address is unknown.

In a dual-ring configuration, the upstream node is the station from which frames are passed to this station on the primary ring.

OID_FDDI_DOWNSTREAM_NODE_LONG

The long address of the station below this NIC on the ring or zero if the address is unknown.

In a dual-ring configuration, the downstream node is the station to which frames are passed from this station on the primary ring.

OID_FDDI_FRAME_ERRORS

The number of frames detected in error by this NIC that have not been detected in error by another device on the ring.

OID_FDDI_FRAMES_LOST

The number of times this NIC detected a format error during frame reception such that the frame was stripped.

OID_FDDI_RING_MGT_STATE

Defines the current state of the Ring Management state machine as one of the following:

NdisFddiRingIsolated
NdisFddiRingNonOperational
NdisFddiRingOperational
NdisFddiRingDetect
NdisFddiRingNonOperationalDup
NdisFddiRingOperationalDup
NdisFddiRingDirected
NdisFddiRingTrace

OID_FDDI_LCT_FAILURES

The count of the consecutive times the link confidence test (LCT) has failed during connection management.

OID_FDDI_LEM_REJECTS

The link error monitor (LEM) count of times that a link was rejected.

OID_FDDI_LCONNECTION_STATE

Defines the state of this port's Physical Connection Management (PCM) state machine as one of the following:

NdisFddiStateOff
NdisFddiStateBreak
NdisFddiStateTrace
NdisFddiStateConnect
NdisFddiStateNext
NdisFddiStateSignal
NdisFddiStateJoin
NdisFddiStateVerify
NdisFddiStateActive
NdisFddiStateMaintenance


LocalTalk Objects

This section describes the OIDs for LocalTalk objects, both operational and statistical types.

The LocalTalk OIDs are defined in ntddndis.h. When building a driver that supports these OIDs, include ntddndis.h.

These OIDs are described in the following topics:

LocalTalk Operational Characteristics

LocalTalk Statistics


LocalTalk Operational Characteristics

The following chart summarizes the OID used to get operational characteristics for NDIS drivers and their NICs on a LocalTalk network.

Length | Q | S | Name
2 | M |  | OID_LTALK_CURRENT_NODE_ID Current station address

The following describes the OID_XXX listed in the preceding chart more fully.

OID_LTALK_CURRENT_NODE_ID

The address the NIC is currently using.

The network-management software cannot set the current station address using the NDIS interface library. It must set this address as a configuration parameter.


LocalTalk Statistics

The following chart summarizes the OIDs used to get LocalTalk statistics.

Length | Q | S | Name
4 | M |  | OID_LTALK_IN_BROADCASTS Broadcasts received
4 | M |  | OID_LTALK_IN_LENGTH_ERRORS Length errors
4 | O |  | OID_LTALK_OUT_NO_HANDLERS No handler
4 | O |  | OID_LTALK_COLLISIONS Collisions
4 | O |  | OID_LTALK_DEFERS Deferrals
4 | O |  | OID_LTALK_NO_DATA_ERRORS No data errors
4 | O |  | OID_LTALK_RANDOM_CTS_ERRORS Random lapCTS errors
4 | O |  | OID_LTALK_FCS_ERRORS FCS errors

The following describes each of the OID_XXX listed in the preceding chart more fully.

OID_LTALK_IN_BROADCASTS

The total number of broadcast packets received on the LocalTalk network.

OID_LTALK_IN_LENGTH_ERRORS

The total number of packets received on the LocalTalk network for which the actual length does not match the length in the header.

OID_LTALK_OUT_NO_HANDLERS

The total number of good packets received on the LocalTalk network that were not accepted by a protocol.

OID_LTALK_COLLISIONS

The total number of collisions assumed on the LocalTalk network due to lack of a lapCTS reply.

OID_LTALK_DEFERS

The total number of times the LocalTalk network has deferred to other packets.

OID_LTALK_NO_DATA_ERRORS

The total number of times the LocalTalk network has received a lapRTS packet when expecting a data packet.

OID_LTALK_RANDOM_CTS_ERRORS

The total number of times the LocalTalk network has received a lapCTS packet that a lapRTS packet has not solicited.

OID_LTALK_FCS_ERRORS

The total number of times the LocalTalk network has received a packet with an FCS error.


ARCNET Objects

This section describes the OIDs for ARCNET objects, both operational and statistical types.

The ARCNET OIDs are defined in ntddndis.h. When building a driver that supports these OIDs, include ntddndis.h.

These OIDs are described in the following topics:

ARCNET Operational Characteristics

ARCNET Statistics

ARCNET Operational Characteristics

The following chart summarizes the OIDs used to get operational characteristics for NDIS drivers and NICs on an ARCNET network.

Length | Q | S | Name
2 | M |  | OID_ARCNET_PERMANENT_ADDRESS Permanent station address
2 | M |  | OID_ARCNET_CURRENT_ADDRESS Current station address

The following describes each of the OID_XXX listed in the preceding chart more fully.

OID_ARCNET_PERMANENT_ADDRESS

The address of the NIC encoded in the hardware.

OID_ARCNET_CURRENT_ADDRESS

The address the NIC is currently using.

ARCNET Statistics

The following chart summarizes the OID used to get ARCNET NIC statistics.

Length | Q | S | Name
4 | O |  | OID_ARCNET_RECONFIGURATIONS Number of reconfigurations

The following describes the OID_XXX listed in the preceding chart more fully.

OID_ARCNET_RECONFIGURATIONS

The OID_ARCNET_RECONFIGURATIONS OID returns the number of network-reconfiguration interrupts received by the NIC driver for an ARCNET card since the system was started.

A reconfiguration takes place every time an ARCNET card is connected to or disconnected from the network. A reconfiguration also takes place every time an ARCNET card is reset. Therefore, each time an ARCNET card is reset on, added to, or removed from the network, every other NIC on the ARCNET network will augment its reconfiguration count.


WAN Objects

This section describes two sets of object identifiers (OIDs) that are used to support WAN miniport drivers in either standard or Connection-oriented NDIS (CoNDIS) environments. If drivers work in a standard WAN environment, they use WAN OIDs for WAN miniport drivers. If drivers work in a CoNDIS WAN environment, they use WAN OIDs for CoNDIS WAN miniport drivers. Standard and CoNDIS WAN OIDs can be used to get or set characteristics of their associated NDIS drivers and WAN NICs.

The WAN OIDs are defined in ntddndis.h. When building a driver that supports these OIDs, include ntddndis.h and ndiswan.h.

Standard and CoNDIS WAN OIDs are described in the following topics:

Standard WAN Objects

CoNDIS WAN Objects


Standard WAN Objects

The following chart summarizes the OIDs used to get or set operational characteristics for standard WAN miniport drivers.

Length | Q | S | Name
6 | M |  | OID_WAN_PERMANENT_ADDRESS Permanent station address
6 | M |  | OID_WAN_CURRENT_ADDRESS Current station
4 | M |  | OID_WAN_QUALITY_OF_SERVICE Quality of service
1 or 6 |  | M | OID_WAN_PROTOCOL_TYPE Protocol type
4 | M |  | OID_WAN_MEDIUM_SUBTYPE Medium subtype
4 |  | M | OID_WAN_HEADER_FORMAT Header format
4 | M |  | OID_WAN_GET_INFO Get information
4 | M |  | OID_WAN_GET_LINK_INFO Get link information
4 |  | M | OID_WAN_SET_LINK_INFO Set link information
4 | M |  | OID_WAN_LINE_COUNT Line count
50 | O |  | OID_WAN_GET_COMP_INFO Get compression information
50 |  | O | OID_WAN_SET_COMP_INFO Set compression information
60 | O |  | OID_WAN_GET_STATS_INFO Get statistics information

The following topics describe the OIDs that are used to get or set operational characteristics for standard WAN miniport drivers.

The OID_WAN_GET_BRIDGE_INFO and OID_WAN_SET_BRIDGE_INFO codes are reserved.


OID_WAN_PERMANENT_ADDRESS

The OID_WAN_PERMANENT_ADDRESS OID requests the miniport driver to return the address encoded in the hardware of the NIC.


OID_WAN_CURRENT_ADDRESS

The OID_WAN_CURRENT_ADDRESS OID requests the miniport driver to return the address that the NIC currently is using.

The miniport driver should return a unique address for the target NIC. NDISWAN presents the returned value, formatted as an Ethernet address, to higher-level protocols. Consequently, the least-significant bit must not be set in such a returned NIC-specific address to prevent it from being interpreted as an Ethernet multicast address.

The driver of a NIC manufactured by a vendor with an assigned Ethernet ID should use that ID as part of the address it returns for this OID. This prevents conflicts with other vendors' assigned Ethernet address ranges.


OID_WAN_QUALITY_OF_SERVICE

The OID_WAN_QUALITY_OF_SERVICE OID requests the miniport driver to return the quality of service that it supports.

The quality of service returned for this query should be a worst-case estimate, specified as one of the following system-defined values:

NdisWanRaw
Specifies a raw binding, in which the NIC driver puts all packets on the network unmodified.
NdisWanErrorControl
Specifies an error control binding.
NdisWanReliable
Specifies a reliable binding.

When a NIC driver calls NdisMIndicateStatus with a line-up indication, it provides QOS information for a specified link.


OID_WAN_PROTOCOL_TYPE

The OID_WAN_PROTOCOL_TYPE OID informs the underlying driver of a bound protocol's type, as a single-byte network-level protocol identifier (NLPID).

Alternatively, a protocol can specify a 6-byte Sub-Network Access Protocol (SNAP) NLPID, with 0x80-0x00-0x00-0x00 for the first four bytes and an Ethertype for the last two bytes.


OID_WAN_MEDIUM_SUBTYPE

The OID_WAN_MEDIUM_SUBTYPE OID requests the miniport driver to return a list of the media subtypes that it can support as a proper subset of the following system-defined values:

NdisWanMediumHub
Specifies a remote access server (RAS) hub.
NdisWanMediumX_25
Specifies an X.25 medium.
NdisWanMediumIsdn
Specifies an ISDN medium.
NdisWanMediumSerial
Specifies a serial line.
NdisWanMediumFrameRelay
Specifies a frame-relay medium.
NdisWanMediumAtm
Specifies an ATM medium.
NdisWanMediumSonet
Specifies a synchronous optical network (Sonet) fiber medium.
NdisWanMediumSW56K
Specifies a switched 56K medium.
NdisWanMediumPPTP
Specifies a Point-to-Point Tunneling Protocol (PPTP) line.
NdisWanMediumL2TP
Specifies a Layer 2 Tunneling Protocol (L2TP) line.
NdisWanMediumIrda
Specifies an IrDA (infrared) medium.
NdisWanMediumParallel
Specifies a parallel line.


OID_WAN_HEADER_FORMAT

The OID_WAN_HEADER_FORMAT OID requests the miniport driver to return or to set the address-header format used, as either of the following system-defined values:

NdisWanHeaderEthernet
Selects Ethernet-emulation format.
NdisWanHeaderNative
Selects the format native to the NdisWanMedium Xxx subtype supported by the underlying driver. NDISWAN always uses Ethernet.

For a query, the miniport driver returns a list of the address formats that the NIC driver supports. For a set, the miniport driver subsequently uses the given type to format headers for this binding.

If an underlying NDIS driver does not support a header format that a protocol recognizes, that protocol's attempt to bind to the underlying driver fails. A NIC driver is not required to support both address types of header format but should if it can.


OID_WAN_GET_INFO

The OID_WAN_GET_INFO OID requests the miniport driver to return information about its or the NIC's capabilities, formatted as an NDIS_WAN_INFO structure, defined as follows:

typedef struct _NDIS_WAN_INFO {
  OUT ULONG  MaxFrameSize;
  OUT ULONG  MaxTransmit;
  OUT ULONG  HeaderPadding;
  OUT ULONG  TailPadding;
  OUT ULONG  Endpoints;
  OUT UINT  MemoryFlags;
  OUT NDIS_PHYSICAL_ADDRESS  HighestAcceptableAddress;
  OUT ULONG  FramingBits;
  OUT ULONG  DesiredACCM;
} NDIS_WAN_INFO, *PNDIS_WAN_INFO;

The members of this structure contain the following information:

MaxFrameSize
Specifies the maximum frame size for any net packet that the NIC driver can send and receive. This value should exclude the driver's own framing overhead and/or the PPP HDLC overhead. Typically this value is around 1500.

However, all WAN miniport drivers should use an internal MaxFrameSize that is 32 bytes larger than the value they return for this OID. For example, a WAN miniport driver that returns 1500 for this OID should internally accept and send up to 1532. Such a miniport driver can readily support future bridging and additional protocols.

MaxTransmit
Specifies the maximum number of outstanding frames that a link on the WAN miniport driver can handle. This member must be set to at least one.

NDISWAN uses the value of this member as a default throttle on how many send requests it submits to the driver's MiniportWanSend function before NDISWAN holds incoming sends. These sends are queued until the miniport driver completes an outstanding send. A miniport driver can adjust this value dynamically and on a per-link basis using the SendWindow member in the NDIS_MAC_LINE_UP structure that the driver passes to NdisMIndicateStatus. NDISWAN uses the current line-up SendWindow value as its throttle on outstanding sends. If the miniport driver sets SendWindow to zero for the initial line-up indication, NDISWAN uses the driver-set MaxTransmit value.

Because a WAN miniport driver must queue packets internally, the value of MaxTransmit is theoretically max(ULONG). However, this driver-determined value should reflect the link speed or hardware capabilities of the NIC. For example, if its NIC always has room for at least four frames, a miniport driver sets MaxTransmit to four so that any incoming packet to MiniportWanSend can be placed on the hardware immediately.

HeaderPadding
Specifies the amount of buffer space, in bytes, required at the beginning of each net packet, considering the current defaults, such as a MaxFrameSize of 1500.

For example, if its NIC requires just a flag byte preceding the frame, the miniport driver would set this member to one.

TailPadding
Specifies the amount of buffer space, in bytes, required at the end of each net packet, considering the current defaults, such as a MaxFrameSize of 1500.

For example, if its NIC requires three bytes at the end of each net packet for the Frame Checksum Sequence (CRC check) and the flag byte, a miniport driver would set this member to three.

Endpoints
Specifies the maximum number of links (sometimes called ports, or point-to-point connections) that the NIC can support at any given time.

For example, a miniport driver would set this member to two for an ISDN card with two channels. It would set this member to ten for an X.25 card that can accept up to ten virtual circuits.

MemoryFlags
If the NIC is not a DMA device, set this member to zero.

Otherwise, set this to the type of memory to be allocated for the NIC, that is, NDIS_MEMORY_NONCACHED and/or NDIS_MEMORY_CONTIGUOUS. Subsequently, memory of the specified type will be allocated for all packets to be transmitted by the WAN adapter.

Note that these flags should be used with caution because they force NDISWAN to allocate memory resources statically during miniport driver initialization.

HighestAcceptableAddress
If the NIC is not a DMA device, set this member with the macro NDIS_PHYSICAL_ADDRESS_CONST(-1,-1).

Otherwise, if the NIC can use 24-bit addresses, set this value to NDIS_PHYSICAL_ADDRESS_CONST (0x1000000, 0). Subsequently, memory within the specified range will be allocated for all packets to be transmitted by the NIC. Thus, memory can just be DMAed directly to the NIC instead of having to be double-buffered through a CPU-memory copy.

FramingBits
Set any bits (ORed) supported by the driver among the following:
RAS_FRAMING
Set only if the driver can detect older RAS framing. Only legacy drivers that supported earlier RAS framing set this flag.
RAS_COMPRESSION
Set only if the driver supports the older RAS compression scheme.
PPP_FRAMING
Should always be set. Indicates the driver can detect and support PPP framing for its medium type.
PPP_COMPRESS_ADDRESS_CONTROL
Set if the driver supports PPP address and control-field compression.

NDISWAN will remove the address and control field if this LCP option is negotiated. Some WAN medium types, such as X.25, do not support this option.

PPP_COMPRESS_PROTOCOL_FIELD
Set if the driver supports PPP protocol field compression.

NDISWAN will remove one byte from the protocol field when applicable if this LCP option is negotiated.

PPP_ACCM_SUPPORTED
Set if the driver supports Asynchronous Control Character Mapping. This bit is only valid for asynchronous media, such as modems. If this bit is set the DesiredACCM member should be valid.
PPP_MULTILINK_FRAMING
Set if the driver supports multilink framing as specified in IETF RFC 1717.
PPP_SHORT_SEQUENCE_HDR_FORMAT
Set if the driver supports header format for multilink framing as specified in IETF RFC 1717.
SLIP_FRAMING
Set if the driver can detect and support SLIP framing (asynchronous drivers only).
SLIP_VJ_COMPRESSION
Set if the driver can support Van Jacobsen TCP/IP header compression for SLIP. NDISWAN supports SLIP_VJ_COMPRESSION (with 16 slots). Asynchronous media (serial drivers) that support SLIP framing should set this bit.

Asynchronous media need not write any code to support VJ header compression. NDISWAN will take care of it.

SLIP_VJ_AUTODETECT
Set if the driver can auto-detect Van Jacobsen TCP/IP header compression for SLIP. NDISWAN will auto-detect VJ header compression. Asynchronous media (serial drivers) should set this bit if they support SLIP framing.
TAPI_PROVIDER
Set if the driver supports the TAPI Service Provider OIDs. Unless this bit is set, TAPI OID calls will not be made to the driver.
MEDIA_NRZ_ENCODING
Set if the driver supports NRZ encoding, the PPP default for some media types such as ISDN. This value is reserved for future use.
MEDIA_NRZI_ENCODING
Set if the driver supports NRZI encoding. This value is reserved for future use.
MEDIA_NLPID
Set if the driver has and can set the NLPID in its frame. This value is reserved for future use.
RFC_1356_FRAMING
Set if the driver supports IETF RFC 1356 X.25 and ISDN framing. This value is reserved for future use.
RFC_1483_FRAMING
Set if the driver supports IETF RFC 1483 ATM adaptation layer-5 encapsulation. This value is reserved for future use.
RFC_1490_FRAMING
Set if the driver supports IETF RFC 1490 Frame Relay framing. This value is reserved for future use.
NBF_PRESERVE_MAC_ADDRESS
Set if the driver supports IETF framing as specified in the draft "The PPP NETBIOS Frames Control Protocol (NBFCP)."
SHIVA_FRAMING
Superseded by NBF_PRESERVE_MAC_ADDRESS.
PASS_THROUGH_MODE
Set if the driver does its own framing. If this flag is set, NDISWAN passes frames, uninterpreted and unmodified.

NIC drivers must be in the default PPP framing mode until each driver receives an NDIS_WAN_SET_LINK_INFO call. The NIC driver must auto-detect any framing that it claims to support.

For example, drivers that support old RAS framing must auto-detect RAS framing from PPP framing. If a driver detects a framing scheme other than the default, that driver should automatically switch its framing into the newly detected framing.

A subsequent query with OID_WAN_GET_LINK_INFO should indicate the detected framing. If no framing is yet detected, the FramingBits should be zero in the returned NDIS_WAN_GET_LINK_INFO information.

If the WAN miniport driver is called subsequently with OID_WAN_SET_LINK_INFO in which the FramingBits member is zero, the driver should attempt to auto-detect the framing upon reception of each frame.

DesiredACCM
The Asynchronous Control Character Map is negotiated. This member is relevant only for asynchronous media types.


OID_WAN_GET_LINK_INFO

The OID_WAN_GET_LINK_INFO OID requests the miniport driver to return information about the current state of a link formatted as an NDIS_WAN_GET_LINK_INFO structure, defined as follows:

typedef struct _NDIS_WAN_GET_LINK_INFO {
  IN  NDIS_HANDLE  NdisLinkHandle;
  OUT ULONG  MaxSendFrameSize;
  OUT ULONG  MaxRecvFrameSize;
  OUT ULONG  HeaderPadding;
  OUT ULONG  TailPadding;
  OUT ULONG  SendFramingBits;
  OUT ULONG  RecvFramingBits;
  OUT ULONG  SendCompressionBits;
  OUT ULONG  RecvCompressionBits;
  OUT ULONG  SendACCM;
  OUT ULONG  RecvACCM;
} NDIS_WAN_GET_LINK_INFO, *PNDIS_WAN_GET_LINK_INFO;

The members of this structure contain the following information:

NdisLinkHandle
Identifies the link. This is the handle that the miniport driver supplied in its initial line-up indication for this link.
MaxSendFrameSize
Specifies the maximum buffer size, in bytes, that the miniport driver can accept for transmission on this link. The driver's MiniportWanSend function can reject any incoming send packet that is larger than this size.
MaxRecvFrameSize
Specifies the largest packet, not including the driver's padding, that will be received on the wire. The driver can drop any packets that are larger.
HeaderPadding
Specifies the number of padding bytes at the head of the frame.
TailPadding
Specifies the number of padding bytes at the tail of the frame.
SendFramingBits
Specifies send-framing bits indicating the type of framing that should be sent. If the miniport driver detects incompatibilities between SendFramingBits and RecvFramingBits, it returns NDIS_STATUS_INVALID_WAN_SETTINGS.

The proper NLPID and framing format should be used based on the framing bits wherever applicable.

RecvFramingBits
Specifies receive-framing bits indicating the type of framing that should be received.
SendCompressionBits
Reserved.
RecvCompressionBits
Reserved.
SendACCM
For asynchronous media types, logical bits 0-31 indicate the respective byte to be byte stuffed. That is, if bit 0 is set to 1, then ASCII character 0x00 should be byte stuffed, and so forth.
RecvACCM
As described for SendACCM.

Possible values for SendFramingBits and RecvFramingBits include any the driver returned in response to the OID_WAN_GET_INFO query.


OID_WAN_SET_LINK_INFO

The OID_WAN_SET_LINK_INFO OID requests the miniport driver to set information for an established link. The protocol-supplied information is formatted as an NDIS_WAN_SET_LINK_INFO structure, defined as follows:

typedef struct _NDIS_WAN_SET_LINK_INFO {
  IN NDIS_HANDLE  NdisLinkHandle;
  IN ULONG  MaxSendFrameSize;
  IN ULONG  MaxRecvFrameSize;
  IN ULONG  HeaderPadding;
  IN ULONG  TailPadding;
  IN ULONG  SendFramingBits;
  IN ULONG  RecvFramingBits;
  IN ULONG  SendCompressionBits;
  IN ULONG  RecvCompressionBits;
  IN ULONG  SendACCM;
  IN ULONG  RecvACCM;
} NDIS_WAN_SET_LINK_INFO, *PNDIS_WAN_SET_LINK_INFO;

The members of this structure contain the following information:

NdisLinkHandle
Identifies the link. This is the handle the miniport driver supplied in its initial line-up indication for this link.
MaxSendFrameSize
Specifies the largest buffer, in bytes, the protocol will send for this link. This value must be less than or equal to that returned by the miniport driver for the OID_WAN_GET_LINK_INFO query.

The driver's MiniportWanSend function can reject any send packets submitted for this link that are larger than this value.

MaxRecvFrameSize
Specifies the largest net packet, not including the driver's padding, that the protocol will receive subsequently. This value must be less than or equal to that returned by the miniport driver for the OID_WAN_GET_LINK_INFO query. The miniport driver can drop any received packets for this link that are larger.
HeaderPadding
Specifies the number of padding bytes at the head of the frame.
TailPadding
Specifies the number of padding bytes at the tail of the frame.
SendFramingBits
Specifies send-framing bits indicating the type of framing that should be sent. If the miniport driver detects incompatibilities between SendFramingBits and RecvFramingBits, it returns NDIS_STATUS_INVALID_WAN_SETTINGS.

The proper NLPID and framing format should be used based on the framing bits wherever applicable.

RecvFramingBits
Specifies receive-framing bits indicating the type of framing that should be received.
SendCompressionBits
Reserved.
RecvCompressionBits
Reserved.
SendACCM
For asynchronous media types, logical bits 0-31 indicate the respective byte to be byte stuffed. That is, if bit 0 is set to one then ASCII character 0x00 should be byte stuffed, and so forth.
RecvACCM
As described for SendACCM.

Possible values for SendFramingBits and RecvFramingBits include any the underlying driver returned in response to the OID_WAN_GET_INFO query.


OID_WAN_LINE_COUNT

The OID_WAN_LINE_COUNT OID requests the miniport driver to return the total number of lines (endpoints) it exposes.


OID_WAN_GET_COMP_INFO

The OID_WAN_GET_COMP_INFO OID requests the miniport driver to return information about the capabilities of the NIC or of its driver, in particular whether either supports compression. If so, the values returned are used to negotiate compression with the Point-to-Point Protocol (PPP) Compression Control Protocol. The protocol subsequently negotiates a compression scheme with an OID_WAN_SET_COMP_INFO request.

Compression information is returned in an NDIS_WAN_GET_COMP_INFO structure, defined as follows:

typedef struct _NDIS_WAN_GET_COMP_INFO {
  IN NDIS_HANDLE  NdisLinkHandle;
  OUT NDIS_WAN_COMPRESS_INFO  SendCapabilities;
  OUT NDIS_WAN_COMPRESS_INFO  RecvCapabilities;
} NDIS_WAN_GET_COMP_INFO, *PNDIS_WAN_GET_COMP_INFO;

The members of this structure contain the following information:

NdisLinkHandle
Identifies the link. This is the handle that the miniport driver supplied in the initial line-up indication for this link.
SendCapabilities
Specifies a structure containing information on compression capabilities for sending data, defined below.
RecvCapabilities
Specifies a structure containing information on compression capabilities for receiving data, defined next.

The NDIS_WAN_COMPRESS_INFO structure is defined as follows:

typedef struct _NDIS_WAN_COMPRESS_INFO {
    UCHAR    SessionKey[8];
    ULONG    MSCompType;

 // Members above reserved to indicate NDISWAN capabilities.
 // Members below indicate NIC-specific capabilities.

    UCHAR    CompType;
    USHORT   CompLength;
    union {
        struct {
            UCHAR    CompOUI[3];
            UCHAR    CompSubType;
            UCHAR    CompValues[32];
        } Proprietary;
        struct {
            UCHAR    CompValues[32];
        } Public;
    };
} NDIS_WAN_COMPRESS_INFO;

The members of this structure contain the following information:

SessionKey
Specifies a reserved variable used by NDISWAN as an encryption key. This variable should be ignored by NDIS drivers.
MSCompType
Specifies what type of compression/encryption capabilities NDISWAN has and what is currently being used. This member also is reserved for use by NDISWAN and should be ignored by NDIS drivers.
CompType
Specifies the compression capabilities of the NIC or its driver as one of the following system-defined values:
COMPTYPE_OUI
Set if the CompOUI and CompSubType members are set.
COMPTYPE_NT31RAS
Only legacy drivers that support the original RAS compression scheme set this value.
COMPTYPE_NONE
Set if compression is unsupported.
CompLength
Specifies the number of bytes in the CompValues member.
CompOUI
Specifies a NIC vendor's IEEE-registered Organization Unique Identifier, which is the most significant three octets of an Ethernet Physical Address, assigned to the vendor by IEEE 802. This identifies the compression type as being proprietary to the vendor.
CompSubType
Specifies a compression specific to the OUI and indicates a compression type for that OUI as described by IETF draft "The PPP Compression Control Protocol (CCP)."
CompValues
Specifies additional data that is specific to the compression protocol.


OID_WAN_SET_COMP_INFO

The OID_WAN_SET_COMP_INFO OID notifies the miniport driver of the compression scheme selected by a protocol to which the miniport driver already returned information in OID_WAN_GET_COMP_INFO.

The protocol supplies a specification for the compression scheme it selected in an NDIS_WAN_SET_COMP_INFO structure, defined as follows:

typedef struct _NDIS_WAN_SET_COMP_INFO {
  IN NDIS_HANDLE  NdisLinkHandle;
  IN NDIS_WAN_COMPRESS_INFO  SendCapabilities;
  IN NDIS_WAN_COMPRESS_INFO  RecvCapabilities;
} NDIS_WAN_SET_COMP_INFO, *PNDIS_WAN_SET_COMP_INFO;

The members of this structure contain the following information:

NdisLinkHandle
Identifies the link. This is the handle that the miniport driver supplied in the initial line-up indication for this link.
SendCapabilities
Specifies a structure containing information on compression capabilities for sending data.
RecvCapabilities
Specifies a structure containing information on compression capabilities for receiving data.

For specifics of the NDIS_WAN_COMPRESS_INFO structure, see the preceding OID_WAN_GET_COMP_INFO.


OID_WAN_GET_STATS_INFO

The OID_WAN_GET_STATS_INFO OID requests the miniport driver to return statistics information. A WAN NIC driver is expected to keep statistics and to return these statistics for this OID in an NDIS_WAN_GET_STATS_INFO structure, defined as follows:

typedef struct _NDIS_WAN_GET_STATS_INFO {
  IN NDIS_HANDLE  NdisLinkHandle;
  OUT ULONG  BytesSent;
  OUT ULONG  BytesRcvd;
  OUT ULONG  FramesSent;
  OUT ULONG  FramesRcvd;
  OUT ULONG  CRCErrors;
  OUT ULONG  TimeoutErrors;
  OUT ULONG  AlignmentErrors;
  OUT ULONG  SerialOverrunErrors;
  OUT ULONG  FramingErrors;
  OUT ULONG  BufferOverrunErrors;
  OUT ULONG  BytesTransmittedUncompressed;
  OUT ULONG  BytesReceivedUncompressed;
  OUT ULONG  BytesTransmittedCompressed;
  OUT ULONG  BytesReceivedCompressed;
} NDIS_WAN_GET_STATS_INFO, *PNDIS_WAN_GET_STATS_INFO;

The members of this structure contain the following information:

NdisLinkHandle
Identifies the link. This is the handle that the miniport driver supplied in the initial line-up indication for this link.
BytesSent
Specifies the number of bytes transmitted.
BytesRcvd
Specifies the number of bytes received.
FramesSent
Specifies the number of frames (WAN packets) sent.
FramesRcvd
Specifies the number of frames received.
CRCErrors
Specifies the number of CRC errors encountered.
TimeoutErrors
Specifies the number of timeout errors encountered.
AlignmentErrors
Specifies the number of alignment errors encountered.
SerialOverrunErrors
Specifies the number of serial overruns encountered.
FramingErrors
Specifies the number of framing errors encountered.
BufferOverrunErrors
Specifies the number of buffer overruns encountered.
BytesTransmittedUncompressed
Specifies the number of bytes of uncompressed data transmitted. A miniport driver returns a nonzero value only if it supports compression.
BytesReceivedUncompressed
Specifies the number of bytes of uncompressed data received. A miniport driver returns a nonzero value only if it supports compression.
BytesTransmittedCompressed
Specifies the number of bytes of compressed data transmitted. A miniport driver returns a nonzero value only if it supports compression.
BytesReceivedCompressed
Specifies the number of bytes of compressed data received. A miniport driver returns a nonzero value only if it supports compression.

If the underlying driver or its NIC does not support compression, the driver returns zero for the Bytes..Uncompressed/Compressed members.


CoNDIS WAN Objects

The following chart summarizes the OIDs used to get or set operational characteristics for CoNDIS WAN miniport drivers.

Length | Q | S | Name
16 | M |  | OID_WAN_CO_GET_INFO Get information about virtual connections (VCs).
32 | M |  | OID_WAN_CO_GET_LINK_INFO Get information about a VC.
32 |  | M | OID_WAN_CO_SET_LINK_INFO Set information for a VC.
80 to 88 | O |  | OID_WAN_CO_GET_COMP_INFO Get compression information for a VC.
80 to 88 |  | O | OID_WAN_CO_SET_COMP_INFO Set compression information for a VC.
56 | O |  | OID_WAN_CO_GET_STATS_INFO Get statistics information for a VC.

The following topics describe the OIDs that are used to get or set operational characteristics for CoNDIS WAN miniport drivers.


OID_WAN_CO_GET_INFO

The OID_WAN_CO_GET_INFO OID requests the miniport driver to return information that applies to all virtual connections (VCs) on its NIC. This information is returned in a NDIS_WAN_CO_INFO structure, defined as follows.

typedef struct _NDIS_WAN_CO_INFO {
    OUT ULONG  MaxFrameSize;
    OUT ULONG  MaxSendWindow;
    OUT ULONG  FramingBits;
    OUT ULONG  DesiredACCM;
} NDIS_WAN_CO_INFO, *PNDIS_WAN_CO_INFO;

The members of this structure contain the following information:

MaxFrameSize
Specifies the maximum frame size for any net packet that the NIC miniport driver can send and receive. This value should exclude the miniport driver's own framing overhead and/or the PPP HDLC overhead. Typically this value is around 1500.

However, all CoNDIS WAN miniport drivers should use an internal MaxFrameSize that is 32 bytes larger than the value they return for this OID. For example, a CoNDIS WAN miniport driver that returns 1500 for this OID should internally accept and send up to 1532. Such a miniport driver can readily support future bridging and additional protocols.

MaxSendWindow
Specifies the maximum number of outstanding packets that the CoNDIS WAN miniport driver can handle on a VC. This member must be set to at least one.

The NDISWAN driver uses the value of this member as a limit on how many packets it submits in send requests to the miniport driver's MiniportCoSendPackets function before NDISWAN holds send packets. These packets are queued until the miniport driver completes an outstanding send. A miniport driver can adjust this value dynamically and on a per-VC basis using the SendWindow member in the WAN_CO_LINKPARAMS structure that the miniport driver passes to NdisMCoIndicateStatus. NDISWAN uses the current SendWindow value as its limit on outstanding sends. If the miniport driver sets SendWindow to zero, NDISWAN must stop sending packets for the particular VC. That is, the miniport driver specifies that the send window is shut down, which, in effect, specifies that it cannot accept any packets from NDISWAN.

Because a CoNDIS WAN miniport driver must queue packets internally, the value of MaxSendWindow is theoretically max(ULONG). However, this driver-determined value should reflect the link speed or hardware capabilities of the NIC. For example, if a miniport driver's NIC always has room for at least four packets, the miniport driver sets MaxSendWindow to four so that any incoming packet to MiniportCoSendPackets can be placed on the hardware immediately.

FramingBits
A 32-bit value that specifies a bitmask specifying the types of framing the miniport driver supports. The miniport driver can specify a combination of the following values, using the binary OR operator:
RAS_FRAMING
Set only if the miniport driver can detect older RAS framing. Only legacy drivers that supported earlier RAS framing set this flag.
RAS_COMPRESSION
Set only if the miniport driver supports the older RAS compression scheme.
PPP_FRAMING
Should always be set. Indicates the miniport driver can detect and support PPP framing for its medium type.
PPP_COMPRESS_ADDRESS_CONTROL
Set if the miniport driver supports PPP address and control-field compression.

NDISWAN will remove the address and control field if this LCP option is negotiated. Some WAN medium types, such as X.25, do not support this option.

PPP_COMPRESS_PROTOCOL_FIELD
Set if the miniport driver supports PPP protocol field compression.

NDISWAN will remove one byte from the protocol field when applicable if this LCP option is negotiated.

PPP_ACCM_SUPPORTED
Set if the miniport driver supports Asynchronous Control Character Mapping. This bit is only valid for asynchronous media, such as modems. If this bit is set the DesiredACCM member should be valid.
PPP_MULTILINK_FRAMING
Set if the miniport driver supports multiple-link framing as specified in IETF RFC 1717.
PPP_SHORT_SEQUENCE_HDR_FORMAT
Set if the miniport driver supports header format for multiple-link framing as specified in IETF RFC 1717.
SLIP_FRAMING
Set if the miniport driver can detect and support SLIP framing (asynchronous miniport drivers only).
SLIP_VJ_COMPRESSION
Set if the miniport driver can support Van Jacobsen TCP/IP header compression for SLIP. NDISWAN supports SLIP_VJ_COMPRESSION (with 16 slots). Asynchronous media (serial miniport drivers) that support SLIP framing should set this bit.

Asynchronous media need not write any code to support VJ header compression. NDISWAN will take care of it.

SLIP_VJ_AUTODETECT
Set if the miniport driver can auto-detect Van Jacobsen TCP/IP header compression for SLIP. NDISWAN will auto-detect VJ header compression. Asynchronous media (serial miniport drivers) should set this bit if they support SLIP framing.
TAPI_PROVIDER
Set if the miniport driver supports the TAPI Service Provider OIDs. Unless this bit is set, TAPI OID calls will not be made to the miniport driver.
MEDIA_NRZ_ENCODING
Set if the miniport driver supports NRZ encoding, the PPP default for some media types such as ISDN. This value is reserved for future use.
MEDIA_NRZI_ENCODING
Set if the miniport driver supports NRZI encoding. This value is reserved for future use.
MEDIA_NLPID
Set if the miniport driver has and can set the NLPID in its frame. This value is reserved for future use.
RFC_1356_FRAMING
Set if the miniport driver supports IETF RFC 1356 X.25 and ISDN framing. This value is reserved for future use.
RFC_1483_FRAMING
Set if the miniport driver supports IETF RFC 1483 ATM adaptation layer-5 encapsulation. This value is reserved for future use.
RFC_1490_FRAMING
Set if the miniport driver supports IETF RFC 1490 Frame Relay framing. This value is reserved for future use.
NBF_PRESERVE_MAC_ADDRESS
Set if the miniport driver supports IETF framing as specified in the draft "The PPP NETBIOS Frames Control Protocol (NBFCP)."
SHIVA_FRAMING
Superseded by NBF_PRESERVE_MAC_ADDRESS.
PASS_THROUGH_MODE
Set if the miniport driver does its own framing. If this flag is set, NDISWAN passes frames, uninterpreted and unmodified.

Miniport drivers must be in the default PPP framing mode until each miniport driver receives an OID_WAN_CO_SET_LINK_INFO request. The miniport driver must auto-detect any framing that it claims to support.

For example, miniport drivers that support old RAS framing must auto-detect RAS framing from PPP framing. If a miniport driver detects a framing scheme other than the default, that miniport driver should automatically switch its framing into the newly detected framing.

A subsequent query with OID_WAN_CO_GET_LINK_INFO should indicate the detected framing. If no framing is yet detected, the FramingBits should be zero in the returned NDIS_WAN_CO_GET_LINK_INFO information.

If the WAN miniport driver is called subsequently with OID_WAN_CO_SET_LINK_INFO in which the FramingBits member is zero, the miniport driver should attempt to auto-detect the framing upon reception of each frame.

DesiredACCM
The Asynchronous Control Character Map is negotiated. This member is relevant only for asynchronous media types.


OID_WAN_CO_GET_LINK_INFO

The OID_WAN_CO_GET_LINK_INFO OID requests the miniport driver to return PPP framing information about the current state of a virtual connection (VC). This information is returned in a NDIS_WAN_CO_GET_LINK_INFO structure, defined as follows.

typedef struct _NDIS_WAN_CO_GET_LINK_INFO {
  OUT ULONG  MaxSendFrameSize;
  OUT ULONG  MaxRecvFrameSize;
  OUT ULONG  SendFramingBits;
  OUT ULONG  RecvFramingBits;
  OUT ULONG  SendCompressionBits;
  OUT ULONG  RecvCompressionBits;
  OUT ULONG  SendACCM;
  OUT ULONG  RecvACCM;
} NDIS_WAN_CO_GET_LINK_INFO, *PNDIS_WAN_CO_GET_LINK_INFO;

The members of this structure contain the following information:

MaxSendFrameSize
Specifies the maximum buffer size, in bytes, that the miniport driver can accept for transmission on this VC. The miniport driver's MiniportCoSendPackets function can reject any incoming send packet that is larger than this size.
MaxRecvFrameSize
Specifies the largest packet that will be received from the network. The miniport driver can drop any packets that are larger.
SendFramingBits
Specifies send-framing bits indicating the type of framing that should be sent. If the miniport driver detects incompatibilities between SendFramingBits and RecvFramingBits, it returns NDIS_STATUS_INVALID_WAN_SETTINGS.

The proper NLPID and framing format should be used based on the framing bits wherever applicable.

RecvFramingBits
Specifies receive-framing bits indicating the type of framing that should be received.
SendCompressionBits
Reserved.
RecvCompressionBits
Reserved.
SendACCM
For asynchronous media types, logical bits 0-31 indicate the respective byte to be byte stuffed. That is, if bit 0 is set to 1, then ASCII character 0x00 should be byte stuffed, and so forth.
RecvACCM
As described for SendACCM.

Possible values for SendFramingBits and RecvFramingBits include any the driver returned in response to the OID_WAN_CO_GET_INFO query.


OID_WAN_CO_SET_LINK_INFO

The OID_WAN_CO_SET_LINK_INFO OID requests the miniport driver to set PPP framing information for a specific virtual connection (VC). A protocol uses a NDIS_WAN_CO_SET_LINK_INFO structure, defined as follows, to indicate this PPP framing information.

typedef struct _NDIS_WAN_CO_SET_LINK_INFO {
  IN ULONG  MaxSendFrameSize;
  IN ULONG  MaxRecvFrameSize;
  IN ULONG  SendFramingBits;
  IN ULONG  RecvFramingBits;
  IN ULONG  SendCompressionBits;
  IN ULONG  RecvCompressionBits;
  IN ULONG  SendACCM;
  IN ULONG  RecvACCM;
} NDIS_WAN_CO_SET_LINK_INFO, *PNDIS_WAN_CO_SET_LINK_INFO;

The members of this structure contain the following information:

MaxSendFrameSize
Specifies the largest buffer, in bytes, the protocol will send for this VC. This value must be less than or equal to that returned by the miniport driver for the OID_WAN_CO_GET_LINK_INFO query.

The miniport driver's MiniportCoSendPackets function can reject any send packets submitted for this link that are larger than this value.

MaxRecvFrameSize
Specifies the largest network packet that the protocol will receive subsequently. This value must be less than or equal to that returned by the miniport driver for the OID_WAN_CO_GET_LINK_INFO query. The miniport driver can drop any received packets for this VC that are larger.
SendFramingBits
Specifies send-framing bits indicating the type of framing that should be sent. If the miniport driver detects incompatibilities between SendFramingBits and RecvFramingBits, it returns NDIS_STATUS_INVALID_WAN_SETTINGS.

The proper NLPID and framing format should be used based on the framing bits wherever applicable.

RecvFramingBits
Specifies receive-framing bits indicating the type of framing that should be received.
SendCompressionBits
Reserved.
RecvCompressionBits
Reserved.
SendACCM
For asynchronous media types, logical bits 0-31 indicate the respective byte to be byte stuffed. That is, if bit 0 is set to one then ASCII character 0x00 should be byte stuffed, and so forth.
RecvACCM
As described for SendACCM.

Possible values for SendFramingBits and RecvFramingBits include any the underlying driver returned in response to the OID_WAN_CO_GET_INFO query.


OID_WAN_CO_GET_COMP_INFO

The OID_WAN_CO_GET_COMP_INFO OID requests the miniport driver to return information about the capabilities of the NIC or of its driver, in particular whether either supports compression. If so, the values returned are used to negotiate compression with the Point-to-Point Protocol (PPP) Compression Control Protocol. The protocol subsequently negotiates a PPP compression scheme with an OID_WAN_CO_SET_COMP_INFOrequest. This compression information is specific to a virtual connection (VC).

Compression information is returned in an NDIS_WAN_CO_GET_COMP_INFO structure, defined as follows:

typedef struct _NDIS_WAN_CO_GET_COMP_INFO {
  OUT NDIS_WAN_COMPRESS_INFO  SendCapabilities;
  OUT NDIS_WAN_COMPRESS_INFO  RecvCapabilities;
} NDIS_WAN_CO_GET_COMP_INFO, *PNDIS_WAN_CO_GET_COMP_INFO;

The members of this structure contain the following information:

SendCapabilities
Specifies a structure containing information on compression capabilities for sending data.
RecvCapabilities
Specifies a structure containing information on compression capabilities for receiving data.

For specifics of the NDIS_WAN_COMPRESS_INFO structure, see OID_WAN_GET_COMP_INFO.


OID_WAN_CO_SET_COMP_INFO

The OID_WAN_CO_SET_COMP_INFO OID notifies the miniport driver of the PPP compression scheme selected by a protocol to which the miniport driver already returned information with a OID_WAN_CO_GET_COMP_INFO query. This PPP compression scheme is specific to a virtual connection (VC).

The protocol supplies a specification for the PPP compression scheme it selected in an NDIS_WAN_CO_SET_COMP_INFO structure, defined as follows:

typedef struct _NDIS_WAN_CO_SET_COMP_INFO {
  IN NDIS_WAN_COMPRESS_INFO  SendCapabilities;
  IN NDIS_WAN_COMPRESS_INFO  RecvCapabilities;
} NDIS_WAN_CO_SET_COMP_INFO, *PNDIS_WAN_CO_SET_COMP_INFO;

The members of this structure contain the following information:

SendCapabilities
Specifies a structure containing information on compression capabilities for sending data.
RecvCapabilities
Specifies a structure containing information on compression capabilities for receiving data.

For specifics of the NDIS_WAN_COMPRESS_INFO structure, see OID_WAN_GET_COMP_INFO.


OID_WAN_CO_GET_STATS_INFO

The OID_WAN_CO_GET_STATS_INFO OID requests the miniport driver to return statistics information that is specific to a virtual connection (VC). A WAN miniport driver is expected to keep statistics and to return these statistics for this OID in an NDIS_WAN_CO_GET_STATS_INFO structure, defined as follows:

typedef struct _NDIS_WAN_CO_GET_STATS_INFO {
  OUT ULONG  BytesSent;
  OUT ULONG  BytesRcvd;
  OUT ULONG  FramesSent;
  OUT ULONG  FramesRcvd;
  OUT ULONG  CRCErrors;
  OUT ULONG  TimeoutErrors;
  OUT ULONG  AlignmentErrors;
  OUT ULONG  SerialOverrunErrors;
  OUT ULONG  FramingErrors;
  OUT ULONG  BufferOverrunErrors;
  OUT ULONG  BytesTransmittedUncompressed;
  OUT ULONG  BytesReceivedUncompressed;
  OUT ULONG  BytesTransmittedCompressed;
  OUT ULONG  BytesReceivedCompressed;
} NDIS_WAN_CO_GET_STATS_INFO, *PNDIS_WAN_CO_GET_STATS_INFO;

The members of this structure contain the following information:

BytesSent
Specifies the number of bytes transmitted.
BytesRcvd
Specifies the number of bytes received.
FramesSent
Specifies the number of frames (WAN packets) sent.
FramesRcvd
Specifies the number of frames received.
CRCErrors
Specifies the number of CRC errors encountered for this VC. CRC errors are caused by the failure of a cyclic redundancy check. A CRC error indicates that one or more bytes in the frame received were found garbled on arrival.
TimeoutErrors
Specifies the number of time-out errors encountered for this VC. Time-out errors occur when an expected byte is not received in time.
AlignmentErrors
Specifies the number of alignment errors encountered for this VC. Alignment errors occur when a byte received is different from the byte expected. This typically happens when a byte is lost or when a time-out error occurs.
SerialOverrunErrors
Specifies the number of serial overruns encountered for this VC. Serial overruns occur when the WAN NIC cannot handle the rate at which data is received.
FramingErrors
Specifies the number of framing errors encountered for this VC. A framing error occurs when an asynchronous byte is received with an invalid start or stop bit.
BufferOverrunErrors
Specifies the number of buffer overruns encountered for this VC. Buffer overruns occur when the WAN miniport driver cannot handle the rate at which data is received.
BytesTransmittedUncompressed
Specifies the number of bytes of uncompressed data transmitted. A miniport driver returns a nonzero value only if it supports compression.
BytesReceivedUncompressed
Specifies the number of bytes of uncompressed data received. A miniport driver returns a nonzero value only if it supports compression.
BytesTransmittedCompressed
Specifies the number of bytes of compressed data transmitted. A miniport driver returns a nonzero value only if it supports compression.
BytesReceivedCompressed
Specifies the number of bytes of compressed data received. A miniport driver returns a nonzero value only if it supports compression.

If the underlying driver or its NIC does not support compression, the driver returns zero for the Bytes..Uncompressed/Compressed members.


TAPI Objects

TAPI objects use a set of associated OIDs to make both query and set information requests. These OIDs define the request interface between user-mode TAPI service providers and underlying WAN miniport drivers. Each such request goes through NDISTAPI and NDISWAN to the target miniport driver. This section defines the OIDs that are associated with TAPI objects.

The TAPI OIDs are defined in ntddndis.h. When building a driver that supports these OIDs, include ntddndis.h and ndistapi.h.

For more information about higher-level TAPI components, especially about user-mode service providers in which these OID requests originate, see the Microsoft® Win32® SDK.

The following chart summarizes the OIDs used to get operational characteristics for NDIS drivers and NICs that support TAPI on a WAN network.

Q | S | Name
 |  | Mandatory OID_TAPI_XXX
 | M | OID_TAPI_ANSWER Answer
 | M | OID_TAPI_CLOSE Close
 | M | OID_TAPI_CLOSE_CALL Close Call
 | M | OID_TAPI_CONDITIONAL_MEDIA_DETECTION Conditional Media Detection
 | M | OID_TAPI_DROP Drop
M |  | OID_TAPI_GET_ADDRESS_CAPS Get Address Capabilities
M |  | OID_TAPI_GET_ADDRESS_ID Get Address ID
M |  | OID_TAPI_GET_ADDRESS_STATUS Get Address Status
M |  | OID_TAPI_GET_CALL_ADDRESS_ID Get Call Address ID
M |  | OID_TAPI_GET_CALL_INFO Get Call Information
M |  | OID_TAPI_GET_CALL_STATUS Get Call Status
M |  | OID_TAPI_GET_DEV_CAPS Get Device Capabilities
M |  | OID_TAPI_GET_ID Get ID
M |  | OID_TAPI_GET_LINE_DEV_STATUS Get Line Device Status
M |  | OID_TAPI_MAKE_CALL Make Call
M |  | OID_TAPI_OPEN Open
M |  | OID_TAPI_PROVIDER_INITIALIZE Provider Initialize
 | M | OID_TAPI_PROVIDER_SHUTDOWN Provider Shutdown
 | M | OID_TAPI_SET_APP_SPECIFIC Set Application Specific Member
 | M | OID_TAPI_SET_CALL_PARAMS Set Call Paramaters
 | M | OID_TAPI_SET_DEFAULT_MEDIA_DETECTION Set Default Media Detection
 | M | OID_TAPI_SET_MEDIA_MODE Set Media Mode
 | M | OID_TAPI_SET_STATUS_MESSAGES Set Status Messages
 |  | Optional OID_TAPI_XXX
 | O | OID_TAPI_ACCEPT Accept
O |  | OID_TAPI_CONFIG_DIALOG Configuration Dialog
O |  | OID_TAPI_DEV_SPECIFIC Device Specific
 | O | OID_TAPI_DIAL Dial Specified Number for Specified Call
O |  | OID_TAPI_GET_DEV_CONFIG Get Device Configuration
O |  | OID_TAPI_GET_EXTENSION_ID Get Extension ID
O |  | OID_TAPI_NEGOTIATE_EXT_VERSION Return Highest Acceptable Version Extension
 | O | OID_TAPI_SET_DEV_CONFIG Set Device Configuration
 | O | OID_TAPI_SECURE_CALL Secure Call
 | O | OID_TAPI_SELECT_EXT_VERSION Select Extension Version
 | O | OID_TAPI_SEND_USER_USER_INFO Send User User Information

In contrast with other OIDs, defined TAPI OID values do not indicate whether each OID is required or optional. The length of the information buffer for TAPI OID requests varies according to the OID-specific structure. Instances of some OID-specific structures also vary in size, in particular for TAPI-defined structures with members of type VAR_STRING, described later.

WAN miniport drivers must support the OIDS labeled as Mandatory in the preceding chart. The extent to which a given miniport driver supports those labeled Optional in the preceding chart depends on the discretion of the driver writer and the capabilities of the NIC.

The functional requirements are quite simple for several of the TAPI OID requests. For example, the OID_TAPI_SET_APP_SPECIFIC request requires a NIC driver only to associate a ULONG value with a specified call instance, which can be retrieved later with an OID_TAPI_GET_CALL_INFO request. Requests that a NIC driver writer chooses to ignore should be completed with the NDIS_STATUS_TAPI_OPERATIONUNAVAIL status code.

A NIC driver can indicate the requests it supports, which might vary over time depending on line, address, or call state, by setting or clearing specific bits in the members of structures for some of the OID_TAPI_GET_XXX requests, such as in the ulAddrCapFlags member in the LINE_ADDRESS_CAPS structure.

For the declaration of LINE_ADDRESS_CAPS and other system-defined structures in which WAN miniport drivers maintain TAPI state, see ndistapi.h. For more information about these structures, see also the Win32 SDK.

TAPI Type VAR_STRING

For several OID_TAPI_XXX, the miniport driver is given an OID-specific structured information buffer. More than one of these TAPI structures have a member of type VAR_STRING, which is also a structured buffer, defined as follows:

typedef struct _VAR_STRING {
  ULONG  ulTotalSize;
  ULONG  ulNeededSize;
  ULONG  ulUsedSize;
  ULONG  ulStringFormat;
  ULONG  ulStringSize;
  ULONG  ulStringOffset;
} VAR_STRING, *PVAR_STRING;

The members of this structure contain the following information:

ulTotalSize
The total size in bytes of the buffer, including the buffered string.
ulNeededSize
The size in bytes of a buffer necessary to contain a particular string. For example, the underlying driver sets this value if a protocol-supplied buffer is too short to contain a requested string.
ulUsedSize
The number of bytes in the given buffer that were actually used.
ulStringFormat
Specifies how the buffered string should be interpreted, as one of the following:
STRINGFORMAT_ASCII
STRINGFORMAT_DBCS
STRINGFORMAT_UNICODE
STRINGFORMAT_BINARY
ulStringSize
The number of bytes in the given buffered string.
ulStringOffset
The offset within this buffer at which the string begins.

The following topics describe the OID_XXX elements listed in the preceding chart. These topics also describe any TAPI structures that may be associated with the OID_XXX elements.

TAPI Query Information Requests

TAPI Set Information Requests


TAPI Query Information Requests

Query-information requests differ from set-information requests in that one or more members in the associated structure, denoted by the "OUT" prefix in the structure definition, are reserved for information the underlying miniport driver should return to the initiator of the request. WAN NIC drivers should treat structure members prefixed with "IN" as read-only.

The first member of all the structures used in query-information requests, ulRequestID, is reserved for future use. Miniport drivers should ignore this member.


OID_TAPI_GET_ADDRESS_CAPS

The OID_TAPI_GET_ADDRESS_CAPS OID requests the WAN NIC driver to return information for the specified address on the specified line about its telephony capabilities.

Support for this request is mandatory.

This request uses an NDIS_TAPI_GET_ADDRESS_CAPS structure, defined as follows, to query the telephony capabilities of a specified address:

typedef struct _NDIS_TAPI_GET_ADDRESS_CAPS {
  IN ULONG  ulRequestID;
  IN ULONG  ulDeviceID;
  IN ULONG  ulAddressID;
  IN ULONG  ulExtVersion;
  OUT LINE_ADDRESS_CAPS  LineAddressCaps;
} NDIS_TAPI_GET_ADDRESS_CAPS, *PNDIS_TAPI_GET_ADDRESS_CAPS;

The members of this structure contain the following information:

ulRequestID
Reserved.
ulDeviceID
Specifies the link or data channel to be queried. This was set up in a preceding OID_TAPI_GET_ID request.
ulAddressID
Specifies the address on the given link for which capabilities should be returned. The value of this member is not validated by NDISTAPI when this request is made.
ulExtVersion
Specifies the version number of the miniport driver-specific extensions to be used. This member is zero if no device-specific extensions are used. Otherwise, the high-order bytes contain the major version number and the low-order bytes contain the minor version number. The value of this member is not validated by NDISTAPI when this request is made.
LineAddressCaps
Specifies the base virtual address of a variable-size structure of type LINE_ADDRESS_CAPS. For more information, see ndistapi.h.

This structure has at least sizeof(LINE_ADDRESS_CAPS) bytes reserved.

Upon successful completion of the request, the miniport driver fills this structure with address capabilities information.

The MiniportQueryInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_INCOMPATIBLEEXTVERSION
NDIS_STATUS_TAPI_INVALADDRESSID
NDIS_STATUS_TAPI_NODRIVER
NDIS_STATUS_FAILURE


OID_TAPI_GET_ADDRESS_ID

The OID_TAPI_GET_ADDRESS_ID OID requests the WAN NIC driver to return the address ID associated with the address in a different format on the specified line.

Support for this request is mandatory.

This request uses an NDIS_TAPI_GET_ADDRESS_ID structure, defined as follows:

typedef struct _NDIS_TAPI_GET_ADDRESS_ID {
  IN ULONG  ulRequestID;
  IN HDRV_LINE  hdLine;
  OUT ULONG  ulAddressID;
  IN ULONG  ulAddressMode;
  IN ULONG  ulAddressSize;
  IN CHAR  szAddress[1];
} NDIS_TAPI_GET_ADDRESS_ID, *PNDIS_TAPI_GET_ADDRESS_ID;

The members of this structure contain the following information:

ulRequestID
Reserved.
hdLine
Specifies the miniport driver's handle to the line for which the address ID should be retrieved. This was set up in a preceding OID_TAPI_OPEN request.
ulAddressID
Specifies the requested address ID. The miniport driver fills in this member with the address ID corresponding to szAddress to complete this request successfully.
ulAddressMode
Specifies the address mode of the address contained in szAddress. This member can have only the following LINEADDRESSMODE flag set:

LINEADDRESSMODE_DIALABLEADDR

ulAddressSize
Specifies the size in bytes of the address in szAddress.
szAddress
Specifies the virtual address of variable-size structure containing an address assigned to the line device. The format of the address is determined by the ulAddressMode member. If it is LINEADDRESSMODE_DIALABLEADDR, szAddress uses the common dialable number format and is zero-terminated.

The MiniportQueryInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_INVALLINEHANDLE
NDIS_STATUS_TAPI_INVALADDRESS
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE


OID_TAPI_GET_ADDRESS_STATUS

The OID_TAPI_GET_ADDRESS_STATUS OID requests the miniport driver to return the current status for the specified address.

Support for this request is mandatory.

This request uses an NDIS_TAPI_GET_ADDRESS_STATUS structure, defined as follows, to query the current status for the specified address:

typedef struct _NDIS_TAPI_GET_ADDRESS_STATUS {
  IN ULONG  ulRequestID;
  IN HDRV_LINE  hdLine;
  IN ULONG  ulAddressID;
  OUT LINE_ADDRESS_STATUS  LineAddressStatus;
} NDIS_TAPI_GET_ADDRESS_STATUS, *PNDIS_TAPI_GET_ADDRESS_STATUS;

The members of this structure contain the following information:

ulRequestID
Reserved.
hdLine
Specifies the miniport driver's handle for the line.
ulAddressID
Specifies an address on the given open line device. This is the address for which the status should be returned. The value of this member is not validated by NDISTAPI when this request is made.
LineAddressStatus
Specifies the virtural address of a variable-size structure of type LINE_ADDRESS_STATUS. For more information, see ndistapi.h.

The miniport driver fills this structure with address status information to complete this request successfully.

The LineAddressStatus member has at least sizeof(LINE_ADDRESS_STATUS) bytes reserved.

The MiniportQueryInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_INVALLINEHANDLE
NDIS_STATUS_TAPI_INVALADDRESSID
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE


OID_TAPI_GET_CALL_ADDRESS_ID

The OID_TAPI_GET_CALL_ADDRESS_ID OID requests the miniport driver to return the address ID for the specified call.

Support for this request is mandatory.

This request uses an NDIS_TAPI_GET_CALL_ADDRESS_ID structure, defined as follows:

typedef struct _NDIS_TAPI_GET_CALL_ADDRESS_ID {
  IN ULONG  ulRequestID;
  IN HDRV_CALL  hdCall;
  OUT ULONG  ulAddressID;
} NDIS_TAPI_GET_CALL_ADDRESS_ID, *PNDIS_TAPI_GET_CALL_ADDRESS_ID;

The members of this structure contain the following information:

ulRequestID
Reserved.
hdCall
Specifies the miniport driver's handle to the call for which the ID should be retrieved. This handle was set up either in a preceding OID_TAPI_MAKE_CALL request or when the miniport driver called NdisMIndicateStatus to report an incoming call.
ulAddressID
Specifies the address ID. The miniport driver fills this member with the corresponding address ID for hdCall to complete this request successfully.

The MiniportQueryInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE


OID_TAPI_GET_CALL_INFO

The OID_TAPI_GET_CALL_INFO OID requests the miniport driver to return detailed information about the specified call.

Support for this request is mandatory.

This request uses an NDIS_TAPI_GET_CALL_INFO structure, defined as follows:

typedef struct _NDIS_TAPI_GET_CALL_INFO {
  ULONG  ulRequestID;
  IN HDRV_CALL  hdCall;
  OUT LINE_CALL_INFO  LineCallInfo;
} NDIS_TAPI_GET_CALL_INFO, *PNDIS_TAPI_GET_CALL_INFO;

The members of this structure contain the following information:

ulRequestID
Reserved.
hdCall
Specifies the miniport driver's handle to the call for which it should return information.
LineCallInfo
Specifies the virtual address variable-size data structure of type LINE_CALL_INFO. For more information, see ndistapi.h.

The miniport driver fills this structure with call-related information to complete this request successfully.

The structure at LineCallInfo has at least sizeof(LINE_CALL_INFO) bytes reserved.

The MiniportQueryInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_INVALCALLHANDLE
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE


OID_TAPI_GET_CALL_STATUS

The OID_TAPI_GET_CALL_STATUS OID requests the miniport driver to return the current status of the specified call.

Support for this request is mandatory.

This request uses an NDIS_TAPI_GET_CALL_STATUS structure, defined as follows:

typedef struct _NDIS_TAPI_GET_CALL_STATUS {
  IN ULONG  ulRequestID;
  IN HDRV_CALL  hdCall;
  OUT LINE_CALL_STATUS  LineCallStatus;
} NDIS_TAPI_GET_CALL_STATUS, *PNDIS_TAPI_GET_CALL_STATUS;

The members of this structure contain the following information:

ulRequestID
Reserved.
hdCall
Specifies the miniport driver's handle to the call for which the current status should be returned.
LineCallStatus
Specifies the virtual address of a variable-size structure of type LINE_CALL_STATUS. For more information, see ndistapi.h.

The miniport driver fills this structure with call status information to complete this request successfully.

The structure at LineCallStatus has at least sizeof(LINE_CALL_STATUS) bytes reserved.

The MiniportQueryInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_INVALCALLHANDLE
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE


OID_TAPI_GET_DEV_CAPS

The OID_TAPI_GET_DEV_CAPS OID requests the miniport driver to return the telephony capabilities of a specified line device. The returned information is valid for all addresses on the given line device.

Support for this request is mandatory.

This request uses an NDIS_TAPI_GET_DEV_CAPS structure, defined as follows:

typedef struct _NDIS_TAPI_GET_DEV_CAPS {
  IN ULONG  ulRequestID;
  IN ULONG  ulDeviceID;
  IN ULONG  ulExtVersion;
  OUT LINE_DEV_CAPS  LineDevCaps;
} NDIS_TAPI_GET_DEV_CAPS, *PNDIS_TAPI_GET_DEV_CAPS;

The members of this structure contain the following information:

ulRequestID
Reserved.
ulDeviceID
Specifies the link or data channel to be queried. This was set up in a preceding OID_TAPI_GET_ID request.
ulExtVersion
Specifies the negotiated extension version number, if any.

The value has already been negotiated for this device through the OID_TAPI_NEGOTIATE_EXT_VERSION request. The value of this member is not validated when this request is made.

LineDevCaps
Specifies the virtual address of a variable-size structure of type LINE_DEV_CAPS. For more information, see ndistapi.h.

The NIC driver fills this structure with line device capabilities information to complete this request successfully.

The structure at LineDevCaps has at least sizeof(LINE_DEV_CAPS) bytes reserved.

The supplied provider information in the dwProviderInfoOffset member of LINE_DEV_CAPS must have the following format:

MediaName\0 ProviderName\0
where
MediaName is ISDN, SW56, FrameRelay, and so forth, as appropriate
and
ProviderName is the name of the manufacturer of the device and the unique name of the device, if any.

For example, the driver of an ISDN device from SomeIHV Inc. would set the dwProviderInfoOffset member with a pointer to the string "ISDN\0SomeIHV\0"

The MiniportQueryInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_NODRIVER
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE


OID_TAPI_GET_DEV_CONFIG

The OID_TAPI_GET_DEV_CONFIG OID requests the miniport driver to return the current configuration of a device associated one-to-one with a particular line.

Support for this request is mandatory.

This request uses an NDIS_TAPI_GET_DEV_CONFIG structure, defined as follows:

typedef struct _NDIS_TAPI_GET_DEV_CONFIG {
  IN ULONG  ulRequestID;
  IN ULONG  ulDeviceID;
  IN ULONG  ulDeviceClassSize;
  IN ULONG  ulDeviceClassOffset;
  OUT VAR_STRING  DeviceConfig;
} NDIS_TAPI_GET_DEV_CONFIG, *PNDIS_TAPI_GET_DEV_CONFIG;

The members of this structure contain the following information:

ulRequestID
Reserved.
ulDeviceID
Specifies the line device to be queried. This value was set up in a preceding OID_TAPI_PROVIDER_INITIALIZE request.
ulDeviceClassSize
Specifies the number of bytes in the device-class string.
ulDeviceClassOffset
Specifies the offset in bytes to the zero-terminated, variable-size counted string specifying the class of the device whose configuration is requested. Valid device class strings are the same as those specified for the OID_TAPI_GET_ID request when it is applied to a "line" device (ulSelect has the value LINECALLSELECT_LINE).
DeviceConfig
Specifies the virtual address of a structure of type VAR_STRING to contain the device configuration information for the associated device.

The ulStringFormat member of the VAR_STRING structure must be set to STRINGFORMAT_BINARY.

The miniport driver fills this structure with the device configuration information to complete this request successfully.

In general, the contents of the NDIS_TAPI_GET_DEV_CONFIG structure are specific to the NIC driver's line and the device class.

The MiniportQueryInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NNDIS_STATUS_TAPI_INVALDEVICECLASS
NDIS_STATUS_TAPI_STRUCTURETOOSMALL
NDIS_STATUS_TAPI_NODRIVER
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE


OID_TAPI_GET_ID

The OID_TAPI_GET_ID OID requests the miniport driver to return a device ID for the specified device class associated with the selected line, address, or call.

Support for this request is mandatory.

This request uses an NDIS_TAPI_GET_ID structure, defined as follows:

typedef struct _NDIS_TAPI_GET_ID {
  IN ULONG  ulRequestID;
  IN HDRV_LINE  hdLine;
  IN ULONG  ulAddressID;
  IN HDRV_CALL  hdCall;
  IN ULONG  ulSelect;
  IN ULONG  ulDeviceClassSize;
  IN ULONG  ulDeviceClassOffset;
  OUT VAR_STRING  DeviceID;
} NDIS_TAPI_GET_ID, *PNDIS_TAPI_GET_ID;

The members of this structure contain the following information:

ulRequestID
Reserved.
hdLine
Specifies the miniport driver's handle to the line.
ulAddressID
Specifies an address on the given open line device. The value of this member is not validated by NDISTAPI when this request is made.
hdCall
Specifies the miniport driver's handle to the call.
ulSelect
Specifies whether the device ID is associated with the line, address, or a single call as one of the following:
LINECALLSELECT_LINE
Selects the specified line device. The hdLine member must contain a valid line handle; hdCall and ulAddressID are unused.
LINECALLSELECT_ADDRESS
Selects the specified address on the line. Both hdLine and ulAddressID must be valid; hdCall is unused.
LINECALLSELECT_CALL
Selects the specified call. The hdCall member must be valid; hdLine and ulAddressID are unused.
ulDeviceClassSize
Specifies the size in bytes of the zero-terminated, variable-size string specifying the device class of the device for which the configuration should be returned.
ulDeviceClassOffset
Specifies the offset in bytes to the device-class string.
DeviceID
Specifies the virtual address of a data structure of type VAR_STRING in which the device ID should be returned.

The miniport driver fills this structure with the device ID to complete this request successfully.

Currently, there are two types of this request that must be supported by WAN NIC drivers:

1. IN DeviceClass = "ndis" // case insensitive
IN ulSelect = LINECALLSELECT_CALL
IN hdCall = ActiveCallHandle
OUT DeviceID = ConnectionWrapperID

DeviceID should be set to the NdisLinkContext handle returned by NDISWAN in the NDIS_MAC_LINE_UP structure for the initial NDIS_STATUS_WAN_LINE_UP indication to establish the link.

The miniport driver must make the initial line-up indication to establish a link (or open a data channel on a line) before returning from this request in order to supply this DeviceID value.

2. IN DeviceClass = "tapi/line"
IN ulSelect = LINECALLSELECT_LINE
IN hdLine = OpenLineHandle
OUT DeviceID = ulDeviceID

DeviceID will be set to the miniport driver-determined DeviceID associated with the line handle.

The MiniportQueryInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_INVALLINEHANDLE
NDIS_STATUS_TAPI_INVALADDRESSID
NDIS_STATUS_TAPI_INVALCALLHANDLE
NDIS_STATUS_TAPI_NODEVICE
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE


OID_TAPI_GET_LINE_DEV_STATUS

The OID_TAPI_GET_LINE_DEV_STATUS OID requests the miniport driver to return the current status for the specified open line device. The returned information is global to all addresses on the line.

Support for this request is mandatory.

This request uses an NDIS_TAPI_GET_LINE_DEV_STATUS structure, defined as follows:

typedef struct _NDIS_TAPI_GET_LINE_DEV_STATUS {
  IN ULONG  ulRequestID;
  IN HDRV_LINE  hdLine;
  OUT LINE_DEV_STATUS  LineDevStatus;
} NDIS_TAPI_GET_LINE_DEV_STATUS, *PNDIS_TAPI_GET_LINE_DEV_STATUS;

The members of this structure contain the following information:

ulRequestID
Reserved.
hdLine
Specifies the miniport driver's handle to the line to be queried.
LineDevStatus
Specifies a variable-sized structure of type LINE_DEV_STATUS. For more information, see ndistapi.h.

The miniport driver fills this structure with the line's current device status to complete this request successfully.

The structure at LineDevStatus has at least sizeof(LINE_DEV_STATUS) bytes reserved.

The MiniportQueryInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_INVALLINEHANDLE
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE


OID_TAPI_MAKE_CALL

The OID_TAPI_MAKE_CALL OID requests the miniport driver to place a call on the specified line to the specified destination address. Optionally, additional call parameters can be specified if the miniport driver is to use something other than default call-setup parameters.

Support for this request is mandatory.

This request uses an NDIS_TAPI_MAKE_CALL structure, defined as follows:

typedef struct _NDIS_TAPI_MAKE_CALL {
  IN ULONG  ulRequestID;
  IN HDRV_LINE  hdLine;
  IN HTAPI_CALL  htCall;
  OUT HDRV_CALL  hdCall;
  IN ULONG  ulDestAddressSize;
  IN ULONG  ulDestAddressOffset;
  IN BOOLEAN  bUseDefaultLineCallParams;
  IN LINE_CALL_PARAMS  LineCallParams;
} NDIS_TAPI_MAKE_CALL, *PNDIS_TAPI_MAKE_CALL;

The members of this structure contain the following information:

ulRequestID
Reserved.
hdLine
Specifies the miniport driver's handle to the line on which the new call is to be originated.
htCall
Specifies NDISTAPI's handle to the call.

The miniport driver must save this handle for use in subsequent notifications, in particular the initial NDIS_MAC_LINE_UP notification to establish a link or data channel.

hdCall
Specifies the miniport driver's handle to the call. The miniport driver must fill this member with its handle for the call before completing this request successfully. This handle is ignored if the miniport driver returns an error status.
ulDestAddressSize
Specifies the size in bytes of the variable-size buffer at ulDestAddressOffset containing the destination address.

This member can be zero for undialed addresses, such as for a hot phone, which always automatically connects to a predefined number, or when dialing will be done subsequently with an OID_TAPI_DIAL request.

ulDestAddressOffset
Specifies the offset in bytes from the beginning of this structure to the destination address. This destination addresss is in standard dialable number format. This member should be zero if ulDestAddressSize is zero.

If dialing will be done subsequently with an OID_TAPI_DIAL request, the driver should allocate an available call appearance on receipt of this request and remain in the dialtone state until dialing begins. Drivers of NICs that have inverse multiplexing capabilities can allow an application to specify many addresses at once.

bUseDefaultLineCallParams
Specifies whether the miniport driver should use the default call-setup parameters or the parameters specified in LineCallParams when making the call. If this member is FALSE, the driver should ignore LineCallParams.
LineCallParams
The LINE_CALL_PARAMS structure at this member specifies how the call should be set up. It selects elements such as the call's bearer mode, data rate, expected media mode, origination address, blocking of caller ID information, and dialing parameters. For more information, see ndistapi.h.

To place a telephony call on a previously opened line, an application supplies a specific destination address and information that specifies how the telephony call should be set up. The NDISWAN driver receives this address and information and passes them down in a NDIS_TAPI_MAKE_CALL structure to a WAN miniport driver in order to place a call on the given line. For example, for an underlying X.25 network, an X.25 WAN miniport driver can access the following information from NDIS_TAPI_MAKE_CALL:

  • The X.25 network address from the ulDestAddressOffset member
  • TRUE from the bUseDefaultLineCallParams member to inform the X.25 WAN miniport driver to use the call parameters in the LineCallParams member
  • X.25-facilities information from the ulDevSpecificOffset member of the LineCallParams member
  • X.25-user information from the ulUserUserInfoOffset member of the LineCallParams member

The MiniportQueryInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_ADDRESSBLOCKED
NDIS_STATUS_TAPI_BEARERMODEUNAVAIL
NDIS_STATUS_TAPI_CALLUNAVAIL
NDIS_STATUS_TAPI_DIALBILLING
NDIS_STATUS_TAPI_DIALQUIET
NDIS_STATUS_TAPI_DIALDIALTONE
NDIS_STATUS_TAPI_DIALPROMPT
NDIS_STATUS_TAPI_INUSE
NDIS_STATUS_TAPI_INVALBEARERMODE
NDIS_STATUS_TAPI_INVALMEDIAMODE
NDIS_STATUS_TAPI_INVALLINESTATE
NDIS_STATUS_TAPI_INVALRATE
NDIS_STATUS_TAPI_INVALLINEHANDLE
NDIS_STATUS_TAPI_INVALADDRESS
NDIS_STATUS_TAPI_INVALADDRESSID
NDIS_STATUS_TAPI_INVALCALLPARAMS
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_TAPI_RATEUNAVAIL
NDIS_STATUS_TAPI_USERUSERINFOTOOBIG
NDIS_STATUS_FAILURE


OID_TAPI_OPEN

The OID_TAPI_OPEN OID requests the miniport driver to open the line device designated by the given device ID and return the NIC driver's handle for the device.

Support for this request is mandatory.

This request uses an NDIS_TAPI_OPEN structure, defined as follows:

typedef struct _NDIS_TAPI_OPEN {
  IN ULONG  ulRequestID;
  IN ULONG  ulDeviceID;
  IN HTAPI_LINE  htLine;
  OUT HDRV_LINE  hdLine;
} NDIS_TAPI_OPEN, *PNDIS_TAPI_OPEN;

The members of this structure contain the following information:

ulRequestID
Reserved.
ulDeviceID
Specifies the line device to be queried. This was set up in a preceding OID_TAPI_PROVIDER_INITIALIZE request.
htLine
Specifies NDISTAPI's handle to the line device to be used in subsequent calls to the LINE_EVENT callback procedure to identify the line
hdLine
Specifies the miniport driver's NIC driver handle to the line device.

The NIC driver must fill this location with its handle for the line device to complete this request successfully. This handle is ignored if the miniport completes the request with an error status.

The MiniportQueryInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_ALLOCATED
NDIS_STATUS_TAPI_INVALMEDIAMODE
NDIS_STATUS_FAILURE

The miniport driver must retain the htLine handle for the device provided by NDISTAPI for use in subsequent NDIS_TAPI_EVENT notifications using the LINE_EVENT structure.


OID_TAPI_PROVIDER_INITIALIZE

The OID_TAPI_PROVIDER_INITIALIZE OID requests that the miniport driver initialize itself as a TAPI provider. The driver should set up whatever internal state it uses to track incoming requests from TAPI.

Support for this request is mandatory.

This request uses an NDIS_TAPI_PROVIDER_INITITIALIZE structure, defined as follows:

typedef struct _NDIS_TAPI_PROVIDER_INITIALIZE {
  IN ULONG  ulRequestID;
  IN ULONG  ulDeviceIDBase;
  OUT ULONG  ulNumLineDevs;
  OUT ULONG  ulProviderID;
} NDIS_TAPI_PROVIDER_INITIALIZE, *PNDIS_TAPI_PROVIDER_INITIALIZE;

The members of this structure contain the following information:

ulRequestID
Reserved.
ulDeviceIDBase
Specifies the lowest device ID for the line devices supported by the miniport driver. Subsequent to this request, the driver uses this value as the zero-based line device identifier value. That is, if ulNumLineDevs is greater than one, the ulDeviceID values subsequently passed in requests such as OID_TAPI_OPEN, contains this value for the first line, this value plus one for the second line, and so forth.
ulNumLineDevs
Specifies the number of line devices supported by the miniport driver to complete this request successfully.
ulProviderID
Specifies an ID for the WAN NIC driver if this request is completed successfully. This value must be unique within the set of WAN drivers that support TAPI; the NdisMiniportContext handle passed in to the MiniportInitialize function can be used to provide a guaranteed unique value.

The MiniportQueryInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE


OID_TAPI_CONFIG_DIALOG

The OID_TAPI_CONFIG_DIALOG OID requests the miniport driver to return the name of a user-mode dynamic-link library that can be loaded and called to configure the specified device.

Such a configuration DLL exports the following function by name:

LONG WINAPI
  ConfigDialog(
    IN  HWND  hwndOwner,
    IN  ULONG  ulDeviceID,
    IN  LPCSTR  lpszDeviceClass
    );

Support for this request is optional. This request is not made by RAS.

The NDIS_TAPI_CONFIG_DIALOG structure, defined as follows, is used with this OID to retrieve the name of a user-mode dynamic link library that can be called to configure the specified device.

typedef struct _NDIS_TAPI_CONFIG_DIALOG {
  IN ULONG  ulRequestID;
  IN ULONG  ulDeviceID;
  IN ULONG  ulDeviceClassSize;
  IN ULONG  ulDeviceClassOffset;
  IN ULONG  ulLibraryNameTotalSize;
  OUT ULONG ulLibraryNameNeededSize;
  OUT CHAR  szLibraryName[1];
} NDIS_TAPI_CONFIG_DIALOG, *PNDIS_TAPI_CONFIG_DIALOG;

The members of this structure contain the following information:

ulRequestID
Reserved.
ulDeviceID
Specifies the line device to be configured. This was set up in a preceding OID_TAPI_PROVIDER_INITIALIZE request.
ulDeviceClassSize
Specifies the size in bytes of the device-class string.
ulDeviceClassOffset
Specifies the offset in bytes to the zero-terminated, variable-size counted string specifying the class of the device whose configuration is requested. Valid device class strings are the same as those specified for the OID_TAPI_GET_ID request when it is applied to a "line" device (ulSelect has the value LINECALLSELECT_LINE).
ulLibraryNameTotalSize
Specifies the size in bytes of the szLibraryName member.
ulLibraryNameNeededSize
Specifies the size in bytes that is needed to hold all the returned information.
szLibraryName
Specifies space for a zero-terminated string naming a configuration DLL for the requested device. Names not containing a complete path or an extension will be subject to the rules used by the Win32 LoadLibrary function for determining default paths and extensions. If the miniport driver determines this buffer is too small to hold all the information, it should specify the necessary size in the ulLibraryNameNeededSize member and return an NDIS_STATUS_TAPI_STRUCTURETOOSMALL error.

The MiniportQueryInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_STRUCTURETOOSMALL
NDIS_STATUS_TAPI_INVALDEVICECLASS
NDIS_STATUS_TAPI_OPERATIONUNAVAIL
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE


OID_TAPI_DEV_SPECIFIC

The OID_TAPI_DEV_SPECIFIC OID requests the miniport driver to provide access to features not accessible through other OID requests. The meaning of the extensions are device-specific, so the application must be fully aware of them to take advantage of these extensions.

Support for this request is optional.

This request uses an NDIS_TAPI_DEV_SPECIFIC structure, defined as follows, to query and provide access to features not specified in other TAPI OID requests:

typedef struct _NDIS_TAPI_DEV_SPECIFIC {
  IN ULONG  ulRequestID;
  IN HDRV_LINE  hdLine;
  IN ULONG  ulAddressID;
  IN HDRV_CALL  hdCall;
  IN OUT ULONG  ulParamsSize;
  IN OUT UCHAR  Params[1];
} NDIS_TAPI_DEV_SPECIFIC, *PNDIS_TAPI_DEV_SPECIFIC;

The members of this structure contain the following device-specific information:

ulRequestID
Reserved.
hdLine
Specifies the miniport driver's handle to the line to be operated on.
ulAddressID
Specifies the address on the specified line to be operated on.
hdCall
Specifies the miniport driver's handle to the call to be operated on. This member can be NULL.
ulParamsSize
Specifies the number of bytes in the following parameter block. On entry, this member will contain the size in bytes of the parameter block passed in to the miniport driver.

If the miniport driver returns information in the parameter block, it should set this member to the size in bytes of the returned information, which cannot exceed the input ulParamsSize. Otherwise, the miniport driver should set this member to zero to indicate that it is returning no information.

Params
Specifies a device-specific parameter block.

The MiniportQueryInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_INVALLINEHANDLE
NDIS_STATUS_TAPI_INVALADDRESSID
NDIS_STATUS_TAPI_OPERATIONUNAVAIL
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE


OID_TAPI_GET_EXTENSION_ID

The OID_TAPI_GET_EXTENSION_ID OID requests the miniport driver to return the extension ID for the specified line device.

Support for this request is optional.

This request uses an NDIS_TAPI_GET_EXTENSION_ID structure, defined as follows:

typedef struct _NDIS_TAPI_GET_EXTENSION_ID {
  IN ULONG  ulRequestID;
  IN ULONG  ulDeviceID;
  OUT LINE_EXTENSION_ID  LineExtensionID;
} NDIS_TAPI_GET_EXTENSION_ID, *PNDIS_TAPI_GET_EXTENSION_ID;

The members of this structure contain the following information:

ulRequestID
Reserved.
ulDeviceID
Specifies the link or data channel to be queried. This was set up in a preceding OID_TAPI_GET_ID request.
LineExtensionID
Pointer to a structure of type LINE_EXTENSION_ID. For more information, see ndistapi.h.

If the miniport driver supports device-specific extensions, it fills this structure with the extension ID of these extensions. Otherwise, it fills this structure with zeros.

For a bound protocol, a valid extension ID cannot consist of all zeros.

The MiniportQueryInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE


OID_TAPI_NEGOTIATE_EXT_VERSION

The OID_TAPI_NEGOTIATE_EXT_VERSION OID requests the miniport driver to return the highest version extension number the miniport driver is willing to operate under for this device, given the range of possible extension versions.

Support for this request is optional.

This request uses an NDIS_TAPI_NEGOTIATE_EXT_VERSION structure, defined as follows:

typedef struct _NDIS_TAPI_NEGOTIATE_EXT_VERSION {
  IN ULONG  ulRequestID;
  IN ULONG  ulDeviceID;
  IN ULONG  ulLowVersion;
  IN ULONG  ulHighVersion;
  OUT ULONG  ulExtVersion;
} NDIS_TAPI_NEGOTIATE_EXT_VERSION, *PNDIS_TAPI_NEGOTIATE_EXT_VERSION;

The members of this structure contain the following information:

ulRequestID
Reserved.
ulDeviceID
Specifies the link or data channel for which the extension version negotiation is to be performed. The value INITIALIZE_NEGOTIATION cannot be used. This was set up in a preceding OID_TAPI_GET_ID request.
ulLowVersion
Specifies the lowest extension version under which NDISTAPI or its client application will operate. The most significant two bytes specify the major version and the least significant two bytes specify the minor version. The value of this member is not validated by NDISTAPI when this request is made.
ulHighVersion
Specifies the highest extension version under which NDISTAPI or its client application will operate. The most significant two bytes specify the major version and the least significant two bytes specify the minor version. The value of this member is not validated by NDISTAPI when this request is made.
ulExtVersion
Specifies the miniport driver's extension version within the range specified by ulLowVersion and ulHighVersion. The most significant two bytes specifiy the major version and the least significant two bytes specify the minor version.

The miniport driver fills this member with the highest extension version number, within the range requested by the caller, under which it is willing to operate to complete this request successfully.

If the requested range specified in ulLowVersion and ulHighVersion does not overlap the range supported by the miniport driver, it returns NDIS_STATUS_TAPI_INCOMPATIBLEEXTVERSION.

The MiniportQueryInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_INCOMPATIBLEEXTVERSION
NDIS_STATUS_TAPI_NODRIVER
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE


TAPI Set Information Requests

WAN miniport drivers return no information for set requests other than the completion status. All OID-specific structures are provided by the protocol driver, and their members are read-only to the underlying WAN miniport driver.


OID_TAPI_ANSWER

The OID_TAPI_ANSWER OID requests the miniport driver to answer the specified call on offer. Optionally, it requests that the miniport driver send the specified user-to-user information to the calling party.

Support for this request is mandatory.

The OID_TAPI_ANSWER request uses an NDIS_TAPI_ANSWER structure, defined as follows:

typedef struct _NDIS_TAPI_ANSWER {
  IN ULONG  ulRequestID;
  IN HDRV_CALL  hdCall;
  IN ULONG  ulUserUserInfoSize;
  IN UCHAR  UserUserInfo[1];
} NDIS_TAPI_ANSWER, *PNDIS_TAPI_ANSWER;

The members of this structure contain the following information:

ulRequestID
Reserved.
hdCall
Specifies the miniport driver's handle to the call to be answered. The driver set this handle up when it called NdisMIndicateStatus with the LINE_EVENT_NEWCALL indication.
ulUserUserInfoSize
Specifies the size in bytes of the user-to-user information in UserUserInfo. If this member is zero, UserUserInfo should be ignored .
UserUserInfo
Specifies a string containing user-to-user information to be sent to the remote party as part of the call accept. User-to-user information is sent only if supported by the underlying network (see OID_TAPI_GET_DEV_CAPS).

The MiniportSetInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_INVALCALLHANDLE
NDIS_STATUS_TAPI_INVALCALLSTATE
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_TAPI_USERUSERINFOTOOBIG
NDIS_STATUS_FAILURE

Upon successful completion of the OID_TAPI_ANSWER request, the miniport driver must be prepared to respond to the OID_TAPI_GET_ID request.

The initiating application must wait for the LINECALLSTATE_CONNECTED indication before actually writing data.


OID_TAPI_CLOSE

The OID_TAPI_CLOSE OID requests the miniport driver to close the specified open line device.

Support for this request is mandatory.

This request uses an NDIS_TAPI_CLOSE structure, defined as follows:

typedef struct _NDIS_TAPI_CLOSE {
  IN ULONG  ulRequestID;
  IN HDRV_LINE  hdLine;
} NDIS_TAPI_CLOSE, *PNDIS_TAPI_CLOSE;

The members of this structure contain the following information:

ulRequestID
Reserved.
hdLine
Specifies the miniport driver's handle to the line to be closed. After the line has been successfully closed, this handle is no longer valid.

The MiniportSetInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING


OID_TAPI_CLOSE_CALL

The OID_TAPI_CLOSE_CALL OID requests the miniport driver to close a specified call after completing or terminating all outstanding asynchronous requests on the call.

Support for this request is mandatory.

This request uses an NDIS_TAPI_CLOSE_CALL structure, defined as follows:

typedef struct _NDIS_TAPI_CLOSE_CALL {
  IN ULONG  ulRequestID;
  IN HDRV_CALL  hdCall;
} NDIS_TAPI_CLOSE_CALL, *PNDIS_TAPI_CLOSE_CALL;

The members of this structure contain the following information:

ulRequestID
Reserved.
hdCall
Specifies the miniport driver's handle to the call to be closed. After the call has been successfully closed this handle is no longer valid.

The MiniportSetInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING


OID_TAPI_CONDITIONAL_MEDIA_DETECTION

NDISTAPI makes this OID request to NDISWAN, which passes it down to WAN miniport drivers, whenever a client application uses LINEMAPPER as the dwDeviceID in the lineOpen function to request that lines be scanned to find one that supports the desired media mode(s) and call parameters.

NDISTAPI scans based on the union of the desired media modes and the other media modes currently being monitored on the line, to give each WAN miniport driver the opportunity to indicate whether it can simultaneously monitor for all of the requested media modes.

Support for this request is mandatory.

This request uses an NDIS_TAPI_CONDITIONAL_MEDIA_DETECTION structure, defined as follows:

typedef struct _NDIS_TAPI_CONDITIONAL_MEDIA_DETECTION {
  IN ULONG  ulRequestID;
  IN HDRV_LINE  hdLine;
  IN ULONG  ulMediaModes;
  IN LINE_CALL_PARAMS  LineCallParams;
} NDIS_TAPI_CONDITIONAL_MEDIA_DETECTION, *PNDIS_TAPI_CONDITIONAL_MEDIA_DETECTION;

The members of this structure contain the following information:

ulRequestID
Reserved.
hdLine
Specifies the miniport driver's handle to the line on which media monitoring and parameter capabilities are to be set.
ulMediaModes
Specifies the media mode(s) currently of interest to the calling application. This parameter uses the LINEMEDIAMODE constants. For more information, see ndistapi.h.
LineCallParams
The LINE_CALL_PARAMS structure specifies information that the line device should provide. The only relevent members for the purpose of this request are the following:

ULONG ulBearerMode;

ULONG ulMinRate;

ULONG ulMaxRate;

ULONG ulMediaMode;

ULONG ulCallParamFlags;

ULONG ulAddressMode;

If the value of ulAddressMode is LINEADDRESSMODE_ADDRESSID, any address on the line is acceptable. Otherwise, the value of ulAddressMode is LINEADDRESSMODE_DIALABLEADDR, indicating either that the miniport driver should search for a specific originating address (phone number), or, if it is a provider-specific extension, the ulOrigAddressSize/Offset and the ulDevSpecificSize/Offset values are also relevant. All other members of the LINE_CALL_PARAMS structure are irrelevant to this OID request.

The MiniportSetInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_INVALLINEHANDLE
NDIS_STATUS_TAPI_NODRIVER
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_TAPI_INVALMEDIAMODE
NDIS_STATUS_FAILURE

If a miniport driver can monitor for the specified set of media modes and support the capabilities specified in CallParams, it completes the request with NDIS_STATUS_SUCCESS, but it leaves the active media monitoring modes for the line unchanged.


OID_TAPI_DROP

The OID_TAPI_DROP OID requests the miniport driver to drop or disconnect the specified call.

User-to-user information can optionally be transmitted as part of the call disconnect. This request can be made by the application at any time.

Support for this request is mandatory.

This request uses an NDIS_TAPI_DROP structure, defined as follows:

typedef struct _NDIS_TAPI_DROP {
  IN ULONG  ulRequestID;
  IN HDRV_CALL  hdCall;
  IN ULONG  ulUserUserInfoSize;
  IN UCHAR  UserUserInfo[1];
} NDIS_TAPI_DROP, *PNDIS_TAPI_DROP;

The members of this structure contain the following information:

ulRequestID
Reserved.
hdCall
Specifies the miniport driver's handle to the call to be dropped.
ulUserUserInfoSize
Specifies the size in bytes of the user-to-user information in UserUserInfo. If this member is zero, the miniport driver should ignore the next member.
UserUserInfo
Specifies a string containing user-to-user information to be sent to the remote party as part of the call drop. User-to-user information is sent only if supported by the underlying network (see OID_TAPI_GET_DEV_CAPS).

The MiniportSetInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_INVALCALLHANDLE
NDIS_STATUS_TAPI_INVALCALLSTATE
NDIS_STATUS_TAPI_USERUSERINFOTOOBIG
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE

When a miniport driver completes this request successfully, the call should be in the idle state. However, the miniport driver can still receive requests, such as statistics queries, specifying the hdCall handle until it completes the OID_TAPI_CLOSE_CALL request for this handle.


OID_TAPI_PROVIDER_SHUTDOWN

The OID_TAPI_PROVIDER_SHUTDOWN OID requests the miniport driver to shut down its TAPI operations when TAPI is cleaning up its state because applications are no longer using TAPI services.

On receipt of this OID, the miniport driver should terminate any activities associated with TAPI that it has in progress, call NdisMIndicateStatus with NDIS_MAC_LINE_DOWN to NDISWAN for any lines currently open, and clean up any state it was using to track TAPI operations.

Support for this request is mandatory.

This request uses an NDIS_TAPI_PROVIDER_SHUTDOWN structure, defined as follows:

typedef struct _NDIS_TAPI_PROVIDER_SHUTDOWN {
  IN ULONG  ulRequestID;
} NDIS_TAPI_PROVIDER_SHUTDOWN, *PNDIS_TAPI_PROVIDER_SHUTDOWN;

The member of this structure contains the following information:

ulRequestID
Reserved.

The MiniportSetInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE


OID_TAPI_SET_APP_SPECIFIC

The OID_TAPI_SET_APP_SPECIFIC OID requests the miniport driver to set the ulAppSpecific member of the specified call's LINECALLINFO structure. For more information about this structure, see ndistapi.h.

Support for this request is mandatory.

This request uses an NDIS_TAPI_SET_APP_SPECIFIC structure, defined as follows:

typedef struct _NDIS_TAPI_SET_APP_SPECIFIC {
  IN ULONG  ulRequestID;
  IN HDRV_CALL  hdCall;
  IN ULONG  ulAppSpecific;
} NDIS_TAPI_SET_APP_SPECIFIC, *PNDIS_TAPI_SET_APP_SPECIFIC;

The members of this structure contain the following information:

ulRequestID
Reserved.
hdCall
Specifies the miniport driver's handle to the call for which the application-specific member is to be set.
ulAppSpecific
Specifies the new content of the ulAppSpecific member for the call's LINECALLINFO structure. This value is uninterpreted by the NIC driver. The value is not validated by NDISTAPI when this request is made.

The MiniportSetInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_INVALCALLHANDLE
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE


OID_TAPI_SET_CALL_PARAMS

The OID_TAPI_SET_CALL_PARAMS OID requests the miniport driver to set certain call parameters for an existing call.

Support for this request is mandatory.

This request uses an NDIS_TAPI_SET_CALL_PARAMS structure, defined as follows:

typedef struct _NDIS_TAPI_SET_CALL_PARAMS {
  IN ULONG  ulRequestID;
  IN HDRV_CALL  hdCall;
  IN ULONG  ulBearerMode;
  IN ULONG  ulMinRate;
  IN ULONG  ulMaxRate;
  IN BOOLEAN  bSetLineDialParams;
  IN LINE_DIAL_PARAMS  LineDialParams;
} NDIS_TAPI_SET_CALL_PARAMS, *PNDIS_TAPI_SET_CALL_PARAMS;

The members of this structure contain the following information:

ulRequestID
Reserved.
hdCall
Specifies the miniport driver's handle to the call for which the following parameters are to be changed.
ulBearerMode
Specifies the new bearer mode for the call. This member can have only one of the following LINEBEARERMODE flags set:

LINEBEARERMODE_VOICE

LINEBEARERMODE_SPEECH

LINEBEARERMODE_MULTIUSE

LINEBEARERMODE_DATA

LINEBEARERMODE_ALTSPEECHDATA

LINEBEARERMODE_NONCALLSIGNALING

ulMinRate
Specifies a lower bound for the call's new data rate. The value of this member is not validated by NDISTAPI before the miniport driver is called.

This value indicates that the caller is willing to accept a new rate as low as this one.

ulMaxRate
Specifies an upper bound for the call's new data rate. The value of this member is not validated by NDISTAPI before the miniport driver is called.

This value indicates the maximum data rate the caller would like.

Equal values for the ulMinRate and ulMaxRate members indicate that the caller requires an exact rate.

bSetLineDialParams
Specifies whether the following dialing parameters should be used for the call. If this member is FALSE, the call's current dialing parameters should be used and the next member should be ignored.
LineDialParams
This structure specifies the new dial parameters for the call. For more information, see ndistapi.h.

The MiniportSetInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_INVALCALLHANDLE
NDIS_STATUS_TAPI_INVALCALLSTATE
NDIS_STATUS_TAPI_INVALBEARERMODE
NDIS_STATUS_TAPI_BEARERMODEUNAVAIL
NDIS_STATUS_TAPI_INVALRATE
NDIS_STATUS_TAPI_RATEUNAVAIL
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE


OID_TAPI_SET_DEFAULT_MEDIA_DETECTION

The OID_TAPI_SET_DEFAULT_MEDIA_DETECTION OID requests the miniport driver to use a new set of media modes to detect for the indicated line, thereby replacing whatever set it was using.

The miniport driver must not notify NDISWAN of an incoming call unless this request has been successfully completed for the incoming call's media mode.

Support for this request is mandatory.

This request uses an NDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION structure, defined as follows:

typedef struct _NDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION {
  IN ULONG  ulRequestID;
  IN HDRV_LINE  hdLine;
  IN ULONG  ulMediaModes;
} NDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION, *PNDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION;

The members of this structure contain the following information:

ulRequestID
Reserved.
hdLine
Specifies the miniport driver's handle to the line for which the default media mode should be set.
ulMediaModes
Specifies the media mode(s) of interest to NDISTAPI. This member is set with one or more of the LINEMEDIAMODE constants. For more information, see ndistapi.h.

The MiniportSetInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_INVALLINEHANDLE
NDIS_STATUS_TAPI_INVALMEDIAMODE
NDIS_STATUS_TAPI_NODRIVER
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE


OID_TAPI_SET_DEV_CONFIG

The OID_TAPI_SET_DEV_CONFIG OID requests the miniport driver to restore the configuration of a device associated one-to-one with the line device from a configuration previously obtained using OID_TAPI_GET_DEV_CONFIG.

The contents of this structure are specific to the miniport driver's line and device class.

Support for this request is mandatory.

This request uses an NDIS_TAPI_SET_DEV_CONFIG structure, defined as follows:

typedef struct _NDIS_TAPI_SET_DEV_CONFIG {
  IN ULONG  ulRequestID;
  IN ULONG  ulDeviceID;
  IN ULONG  ulDeviceClassSize;
  IN ULONG  ulDeviceClassOffset;
  IN ULONG  ulDeviceConfigSize;
  IN UCHAR  DeviceConfig[1];
} NDIS_TAPI_SET_DEV_CONFIG, *PNDIS_TAPI_SET_DEV_CONFIG;

The members of this structure contain the following information:

ulRequestID
Reserved.
ulDeviceID
Specifies the line device to be configured. This value was set up in a preceding OID_TAPI_PROVIDER_INITIALIZE request.
ulDeviceClassSize
Specifies the size in bytes of the device class for the device whose configuration is to be restored. Valid device class strings are the same as those specified for the OID_TAPI_GET_ID request when it is applied to a "line" device (ulSelect has the value LINECALLSELECT_LINE).
ulDeviceClassOffset
Specifies the offset in bytes to the device class of the device whose configuration is to be restored.
ulDeviceConfigSize
Specifies the number of bytes at DeviceConfig. This value was already returned in the ulStringSize member in the VAR_STRING structure returned for a preceding OID_TAPI_GET_DEV_CONFIG request.
DeviceConfig
Specifies data that was returned in the variable portion of the VAR_STRING structure for a preceding OID_TAPI_GET_DEV_CONFIG request.

The MiniportSetInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_INVALDEVICECLASS
NDIS_STATUS_TAPI_INVALPARAM
NDIS_STATUS_TAPI_NODRIVER
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE


OID_TAPI_SET_MEDIA_MODE

The OID_TAPI_SET_MEDIA_MODE OID requests the miniport driver to change a call's media mode as stored in the LINE_CALL_INFO structure for that call. For information about the declaration of LINE_CALL_INFO, see ndistapi.h.

Support for this request is mandatory.

This request uses an NDIS_TAPI_SET_MEDIA_MODE structure, defined as follows:

typedef struct _NDIS_TAPI_SET_MEDIA_MODE {
  IN ULONG  ulRequestID;
  IN HDRV_CALL  hdCall;
  IN ULONG  ulMediaMode;
} NDIS_TAPI_SET_MEDIA_MODE, *PNDIS_TAPI_SET_MEDIA_MODE;

The members of this structure contain the following information:

ulRequestID
Reserved.
hdCall
Specifies the miniport driver's handle to the call for which it should change the media mode.
ulMediaMode
Specifies the new media mode(s) for the call as one or more of the LINEMEDIAMODE_XXX flags.

If the LINEMEDIAMODE_UNKNOWN flag is set, other media mode flags also can be set. Such a combination of flags specifies that the call's media mode is not fully determined, but that it has been narrowed down to a subset of possible media modes. If the LINEMEDIAMODE_UNKNOWN flag is clear, only a single media mode can be specified.

The MiniportSetInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_INVALCALLHANDLE
NDIS_STATUS_TAPI_INVALMEDIAMODE
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE


OID_TAPI_SET_STATUS_MESSAGES

The OID_TAPI_SET_STATUS_MESSAGES OID requests the miniport driver to allow NDISTAPI to specify which notification messages the miniport driver should generate for events related to status changes for the specified line or any of its addresses.

By default, address-status and line-status reporting is initially disabled for a line.

Support for this request is mandatory.

This request uses an NDIS_TAPI_SET_STATUS_MESSAGES structure, defined as follows:

typedef struct _NDIS_TAPI_SET_STATUS_MESSAGES {
  IN ULONG  ulRequestID;
  IN HDRV_LINE  hdLine;
  IN ULONG  ulLineStates;
  IN ULONG  ulAddressStates;
} NDIS_TAPI_SET_STATUS_MESSAGES, *PNDIS_TAPI_SET_STATUS_MESSAGES;

The members of this structure contain the following information:

ulRequestID
Reserved.
hdLine
Specifies the miniport driver's handle to the line device.
ulLineStates
Specifies a bit array that identifies status changes for which messages should be sent to NDISTAPI. This parameter uses the LINEDEVSTATE constants. For more information, see ndistapi.h.
ulAddressStates
Specifies a bit array that identifies which address status changes the miniport driver should monitor to send appropriate notifications to NDISTAPI. The value is an ORed combination of LINEADDRESSSTATE flags. For more information, see ndistapi.h.

The MiniportSetInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_INVALLINEHANDLE
NDIS_STATUS_TAPI_INVALLINESTATE
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE


OID_TAPI_ACCEPT

The OID_TAPI_ACCEPT OID requests the miniport driver to accept the specified call. Optionally, it requests that the miniport driver send the specified user-to-user information to the calling party.

Support for this request is optional.

The request uses an NDIS_TAPI_ACCEPT structure, defined as follows:

typedef struct _NDIS_TAPI_ACCEPT {
  IN ULONG  ulRequestID;
  IN HDRV_CALL  hdCall;
  IN ULONG  ulUserUserInfoSize;
  IN UCHAR  UserUserInfo[1];
} NDIS_TAPI_ACCEPT, *PNDIS_TAPI_ACCEPT;

The members of this structure contain the following information:

ulRequestID
Reserved.
hdCall
Specifies the miniport driver's handle to the call to be accepted. The driver set this handle up when it called NdisMIndicateStatus with the LINE_EVENT_NEWCALL indication.
ulUserUserInfoSize
Specifies the size in bytes of the user-to-user information in UserUserInfo. If this member is zero, the miniport driver should ignore the next member.
UserUserInfo
Specifies a string containing user-to-user information to be sent to the remote party as part of the call-accept operation. User-to-user information is sent only if supported by the underlying network (see OID_TAPI_GET_DEV_CAPS).

The MiniportSetInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_INVALCALLHANDLE
NDIS_STATUS_TAPI_INVALCALLSTATE
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_TAPI_USERUSERINFOTOOBIG
NDIS_STATUS_FAILURE


OID_TAPI_DIAL

The OID_TAPI_DIAL OID requests the miniport driver to dial the specified number on the specified call.

Support for this request is optional.

This request uses an NDIS_TAPI_DIAL structure, defined as follows:

typedef struct _NDIS_TAPI_DIAL {
  IN ULONG  ulRequestID;
  IN HDRV_CALL  hdCall;
  IN ULONG  ulDestAddressSize;
  IN CHAR  szDestAddress[1];
} NDIS_TAPI_DIAL, *PNDIS_TAPI_DIAL;

The members of this structure contain the following information:

ulRequestID
Reserved.
hdCall
Specifies the miniport driver's handle to the call for which it should dial. This handle was set up in a preceding OID_TAPI_MAKE_CALL request.
ulDestAddressSize
Specifies the size in bytes of the address in the next member.
szDestAddress
Specifies the destination to be dialed in standard dialable number format.

The MiniportSetInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_INVALCALLHANDLE
NDIS_STATUS_TAPI_INVALADDRESS
NDIS_STATUS_TAPI_INVALCALLSTATE
NDIS_STATUS_TAPI_ADDRESSBLOCKED
NDIS_STATUS_TAPI_DIALBILLING
NDIS_STATUS_TAPI_DIALQUIET
NDIS_STATUS_TAPI_DIALDIALTONE
NDIS_STATUS_TAPI_DIALPROMPT
NDIS_STATUS_TAPI_OPERATIONUNAVAIL
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE

l


OID_TAPI_SECURE_CALL

The OID_TAPI_SECURE_CALL OID requests the miniport driver to secure a particular call from any interruptions or interference that can affect the call's media stream.

Support for this request is optional.

This request uses an NDIS_TAPI_SECURE_CALL structure, defined as follows:

typedef struct _NDIS_TAPI_SECURE_CALL {
  IN ULONG  ulRequestID;
  IN HDRV_CALL  hdCall;
} NDIS_TAPI_SECURE_CALL, *PNDIS_TAPI_SECURE_CALL;

The members of this structure contain the following information:

ulRequestID
Reserved.
hdCall
Specifies the miniport driver's handle to the call to be secured.

The MiniportSetInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_INVALCALLHANDLE
NDIS_STATUS_TAPI_INVALCALLSTATE
NDIS_STATUS_TAPI_OPERATIONUNAVAIL
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE


OID_TAPI_SELECT_EXT_VERSION

The OID_TAPI_SELECT_EXT_VERSION OID requests the miniport driver to select the indicated extension version for the indicated line device. Subsequent requests on the line operate according to the selected extension version.

Support for this request is optional.

This request uses an NDIS_TAPI_SELECT_EXT_VERSION structure, defined as follows:

typedef struct _NDIS_TAPI_SELECT_EXT_VERSION {
  IN ULONG  ulRequestID;
  IN HDRV_LINE  hdLine;
  IN ULONG  ulExtVersion;
} NDIS_TAPI_SELECT_EXT_VERSION, *PNDIS_TAPI_SELECT_EXT_VERSION;

The members of this structure contain the following information:

ulRequestID
Reserved.
hdLine
Specifies the handle to the line for which the extension version is to be selected.
ulExtVersion
Specifies the extension version to be selected. The most significant two bytes specify the major version number, and the least significant two bytes specify the minor version number. Zero indicates the miniport driver should cancel the current selection.

This version has been negotiated in a preceding OID_TAPI_NEGOTIATE_EXT_VERSION request.

The MiniportSetInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_INCOMPATIBLEEXTVERSION
NDIS_STATUS_TAPI_OPERATIONUNAVAIL
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE


OID_TAPI_SEND_USER_USER_INFO

The OID_TAPI_SEND_USER_INFO OID requests the miniport driver to send user-to-user information to the remote party on the specified call.

Support for this request is optional.

This request uses an NDIS_TAPI_SEND_USER_USER_INFO structure, defined as follows:

typedef struct _NDIS_TAPI_SEND_USER_USER_INFO {
  IN ULONG  ulRequestID;
  IN HDRV_CALL  hdCall;
  IN ULONG  ulUserUserInfoSize;
  IN UCHAR  UserUserInfo[1];
} NDIS_TAPI_SEND_USER_USER_INFO, *PNDIS_TAPI_SEND_USER_USER_INFO;

The members of this structure contain the following information:

ulRequestID
Reserved.
hdCall
Specifies the miniport driver's handle to the call on which to send user-to-user information.
ulUserUserInfoSize
Specifies the size in bytes of the UserUserInfo string.
UserUserInfo
Specifies a string containing user-to-user information to be sent to the remote party as part of a call-accept operation. User-to-user information is sent only if supported by the underlying network (see OID_TAPI_GET_DEV_CAPS).

The MiniportSetInformation function can return one of the following:

NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_TAPI_INVALCALLHANDLE
NDIS_STATUS_TAPI_INVALCALLSTATE
NDIS_STATUS_TAPI_USERUSERINFOTOOBIG
NDIS_STATUS_TAPI_OPERATIONUNAVAIL
NDIS_STATUS_TAPI_RESOURCEUNAVAIL
NDIS_STATUS_FAILURE


Wireless WAN Objects

This section describes the system-defined OIDs for wireless WAN media. These OIDs include a set of general OIDs defined for wireless WAN media, as well as OIDs that are specific to a given medium.

The wireless WAN OIDs are defined in ntddndis.h. When building a driver that supports these OIDs, include ntddndis.h.

This section includes the following topics:

Wireless Operational Characteristics

Network-Dependent Wireless Objects

Currently, there are no defined statistics OIDs for the wireless WAN medium.


Wireless Operational Characteristics

The following chart summarizes the OIDs used to get or set the general operational characteristics of wireless WAN miniport drivers and/or their NICs.

Q | S | Indication | Name
M |  |  | OID_WW_GEN_NETWORK_TYPES_SUPPORTED
M | M | M | OID_WW_GEN_NETWORK_TYPE_IN_USE
M |  |  | OID_WW_GEN_HEADER_FORMATS_SUPPORTED
M | M | M | OID_WW_GEN_HEADER_FORMAT_IN_USE
 | M |  | OID_WW_GEN_INDICATION_REQUEST
M |  |  | OID_WW_GEN_DEVICE_INFO
M | M | M | OID_WW_GEN_OPERATION_MODE
M |  | M | OID_WW_GEN_LOCK_STATUS
M | M | M | OID_WW_GEN_DISABLE_TRANSMITTER
M | M | M | OID_WW_GEN_NETWORK_ID
M |  |  | OID_WW_GEN_PERMANENT_ADDRESS
M | M | M | OID_WW_GEN_CURRENT_ADDRESS
M | M | M | OID_WW_GEN_SUSPEND_DRIVER
M |  | M | OID_WW_GEN_BASESTATION_ID
M |  | M | OID_WW_GEN_CHANNEL_ID
M |  |  | OID_WW_GEN_ENCRYPTION_SUPPORTED
M | M | M | OID_WW_GEN_ENCRYPTION_IN_USE
M | M | M | OID_WW_GEN_ENCRYPTION_STATE
M |  | M | OID_WW_GEN_CHANNEL_QUALITY
M |  | M | OID_WW_GEN_REGISTRATION_STATUS
M |  |  | OID_WW_GEN_RADIO_LINK_SPEED
M |  |  | OID_WW_GEN_LATENCY
M |  | M | OID_WW_GEN_BATTERY_LEVEL
M |  | M | OID_WW_GEN_EXTERNAL_POWER
O | O |  | OID_WW_GEN_PING_ADDRESS
O |  |  | OID_WW_GEN_RSSI
O |  |  | OID_WW_GEN_SIM_STATUS
 | O |  | OID_WW_GEN_ENABLE_SIM_PIN
 | O |  | OID_WW_GEN_CHANGE_SIM_PIN
 | O |  | OID_WW_GEN_SIM_PUK
O |  | O | OID_WW_GEN_SIM_EXCEPTION

The following describes each of the preceding OIDs and their respective associated structures more fully.

References for the set of network-type-dependent OID_WW_XXX follow those for the OID_WW_GEN_XXX.

Unless otherwise specified, the requesting protocol must allocate all buffer space and initialize any structures or pointers necessary to complete OID requests. Underlying NDIS drivers need only copy the data into the supplied buffers.

To account for differences in hardware architectures and structure packing, structure members must be aligned on an 8-byte (NDIS-defined type NDIS_PHYSICAL_ADDRESS) boundary and the sizeof operator in "C" (or an analogous function) must be used to calculate the lengths of structure elements.

Some network devices support external interfaces to configure the device. Therefore, it is possible for some objects to change dynamically, which is outside the control of the underlying miniport driver.


NDIS_VAR_DATA_DESC

Many of these OIDs have associated structures with members of type NDIS_VAR_DATA_DESC, defined as follows:

typedef struct  _NDIS_VAR_DATA_DESC {
  USHORT  Length;  // number of bytes of data in buffer
  USHORT  MaximumLength; // total size of buffer in bytes
  LONG    Offset;  // offset in bytes, relative to struct
} NDIS_VAR_DATA_DESC, *PNDIS_VAR_DATA_DESC;

This structure defines a type used to describe buffer space relative to the base virtual address of the NDIS_VAR_DATA_DESC structure itself. In other words, a pointer to a buffer is not explicitly provided by this type; only the offset to the buffer space is provided. Because this descriptor does not use an actual pointer, a user-mode application can allocate a buffer together with its descriptor of this type and provide an offset to this buffer relative to the base virtual address of the descriptor. This allows structures containing these descriptors to be passed between user mode and kernel mode without address mapping. Note that the buffer and the NDIS_VAR_DATA_DESC structure might or might not be contiguous because the specified offset might point to storage that the protocol or application allocated elsewhere. An Offset specified between zero and sizeof(NDIS_VAR_DATA_DESC) is invalid.

Queries that return information of type NDIS_VAR_DATA_DESC should zero terminate buffers (that is, set the Offset member of this structure to NULL) and return zero as the buffer size if the requested information is unavailable. For example, if the revision number of the software/firmware in the device is unknown, a wireless WAN miniport driver should return zero for the Length and NULL for the Offset at SWVersionNum for an OID_WW_GEN_DEVICE_INFO query.

The definition of each OID_WW_GEN_XXX that follows describes the data type at InformationBuffer in the NDIS_REQUEST structure passed in to the underlying miniport driver.


OID_WW_GEN_NETWORK_TYPES_SUPPORTED

For this OID, a miniport driver returns an array of types supported by the driver and its NIC that has any proper subset of the following system-defined values:

NdisWWGeneric
NdisWWMobitex
NdisWWPinpoint
NdisWWCDPD
NdisWWArdis
NdisWWDataTAC
NdisWWMetricom
NdisWWGSM
NdisWWCDMA
NdisWWTDMA
NdisWWAMPS
NdisWWInmarsat
NdisWWpACT
NdisWWFlex
NdisWWIDEN

Any miniport driver that cannot claim full compliance with any particular type from the preceding list should return NdisWWGeneric for this query. Otherwise, the miniport driver should return a list of the particular type(s) for which it can provide fully compliant support.

Note that the NdisWWArdis type has been subsumed under the NdisWWDataTAC type. That is, if a miniport driver and its NIC support the NdisWWDataTAC type, they also support the NdisWWArdis type.

Sets and indications are irrelevant for this OID.


OID_WW_GEN_NETWORK_TYPE_IN_USE

As a query, the OID_WW_GEN_NETWORK_TYPE_IN_USE OID requests an underlying miniport driver and its NIC to return the current NDIS_WW_NETWORK_TYPE used by the miniport driver and NIC. For more information about the possible values, see OID_WW_GEN_NETWORK_TYPES_SUPPORTED.

As a set, this OID requests that an underlying miniport driver and its NIC set the NIC and itself to use the specified NDIS_WW_NETWORK_TYPE value. If a miniport driver supports only a single type of network, it sets this type as the network default so a bound protocol is unlikely to make this OID request of such a miniport driver.

NdisWWGeneric should be specified in set requests to underlying drivers that do not claim full compliance with any of the enumerated network types in response to a query.

If the underlying miniport driver can support more than one type of network, a bound protocol should make this OID request to set the network type immediately following its successful call to NdisOpenAdapter and prior to calling NdisRequest with OID_WW_GEN_HEADER_FORMAT_IN_USE. Such a protocol should query the current operating network type prior to setting it. If the device is operating in the correct mode, then no further action is required other than using OID_WW_GEN_INDICATION_REQUEST to register to be notified of changes associated with OID_WW_GEN_NETWORK_TYPE_IN_USE.

After a miniport driver completes a set operation requested by this OID, the network type is set for all bound protocols.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) if the network type changes. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.


OID_WW_GEN_HEADER_FORMATS_SUPPORTED

For the OID_WW_GEN_HEADER_FORMATS_SUPPORTED OID, a miniport driver returns an array of header formats that the miniport driver can support as one or more of the following system-defined values:

NdisWWDIXEthernetFrames
NdisWWMPAKFrames
NdisWWRDLAPFrames
NdisWWMDC4800Frames
NdisWWNCLFrames

DIX Ethernet is the default header format. Every wireless WAN miniport driver must support this format. Any miniport driver can support additional formats. However, a miniport driver is likely to support at most one other format that is native to its NIC.

Note that NdisWWRDLAPFrames and NdisWWMDC4800Frames types have been subsumed under the NdisWWNCLFrames type. That is, if a miniport driver and its NIC support NdisWWRDLAPFrames and NdisWWMDC4800Frames types, they also support the NdisWWNCLFrames type.

Sets and indications are irrelevant for this OID.


OID_WW_GEN_HEADER_FORMAT_IN_USE

As a query, the OID_WW_GEN_HEADER_FORMAT_IN_USE OID requests an underlying miniport driver and its NIC to return the current NDIS_WW_HEADER_FORMAT it is using. For the possible values, see OID_WW_GEN_HEADER_FORMATS_SUPPORTED.

As a set, this OID requests an underlying miniport driver and its NIC to use a particular header format that it returned in response to a preceding OID_WW_GEN_HEADER_FORMATS_SUPPORTED request. If no bound protocol requests a set, the miniport driver uses DIX-Ethernet framing by default.

If the underlying miniport driver can support more than one type of header, a bound protocol should make this OID request immediately following its successful call to NdisRequest with OID_WW_GEN_NETWORK_TYPE_IN_USE. A successful set request changes the header format in use for all bound protocols.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) if the header format changes. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.


OID_WW_GEN_INDICATION_REQUEST

The OID_WW_GEN_INDICATION_REQUEST OID notifies the underlying miniport driver to place the specified indication request on its event queue.

This OID allows bound protocols to register themselves to be notified of changes associated with particular wireless OIDs. Such a protocol passes an NDIS_WW_INDICATION_REQUEST structure, defined below, to NdisRequest that specifies an OID_WW_XXX code and, for some OID codes, a trigger value. On return from such an OID_WW_GEN_INDICATION_REQUEST, the current value of the specified OID code will be in the InitialValue member, unless otherwise stated in the definition for the OID_WW_XXX specified in the Oid member.

Because a miniport driver calls NdisMIndicateStatus to indicate status related to an OID to every bound protocol, this miniport driver must maintain its own copy of the NDIS_WW_INDICATION_REQUEST structure for the request. This miniport driver can free this structure after NdisMIndicateStatus returns. A miniport driver maintains its own copy of this structure for the following reason. After a protocol receives notification of an event related to an OID for which the protocol registered, the protocol releases its own indication-request structure. Because the miniport driver has its own copy of this structure, its copy remains valid. Therefore, other bound protocols will also receive valid status related to the OID.

The NDIS_WW_INDICATION_REQUEST structure is defined as follows:

typedef struct _NDIS_WW_INDICATION_REQUEST {
  NDIS_OID  Oid;  // IN
  UINT  uIndicationFlag;  // IN
  UINT  uApplicationToken;  // IN
  HANDLE  hIndicationHandle; // IN OUT
  INT  iPollingInterval;  // IN OUT
  NDIS_VAR_DATA_DESC  InitialValue;  // IN OUT
  NDIS_VAR_DATA_DESC  OIDIndicationValue; // OUT
  NDIS_VAR_DATA_DESC  TriggerValue;  // IN
} NDIS_WW_INDICATION_REQUEST;

The members of this structure contain the following information:

Oid
The OID_WW_XXX code for which the miniport driver should indicate events.

A protocol sets this member.

uIndicationFlag
Specifies a bitmask in which one of the following flags can be set:
OID_INDICATION_REQUEST_ENABLE
The miniport driver should call NdisMIndicateStatus if the event specified in this structure occurs.
OID_INDICATION_REQUEST_CANCEL
The miniport driver should cancel notifications for the specified event. The values supplied in the Oid and hIndicationHandle members must match the values specified in a preceding OID_WW_GEN_INDICATION_REQUEST.

All other bits in uIndicationFlag are reserved for future use.

A protocol sets this member.

uApplicationToken
Specifies an application-defined (or protocol-defined) token that is returned by the miniport driver when it posts the specified event. The miniport driver must copy this member during indication-request operations prior to placing the event on the driver's internal event queue. The miniport driver does so to ensure that the requesting protocol can correctly demulitplex the specified indication event.

The miniport driver ignores this member during cancel operations.

A protocol sets this member.

hIndicationHandle
Specifies a miniport driver-determined handle. The protocol or application will save this handle and possibly use it to cancel this request subsequently (see uIndicationFlag). The miniport driver must initialize this member during indication-request operations prior to placing the event on the driver's internal event queue. The miniport driver does so to ensure that the requesting protocol can correctly demulitplex the specified indication event.

This member is returned by the miniport driver or is set by a protocol to cancel.

iPollingInterval
Specifies an interval, in milliseconds, at which the miniport driver should poll the wireless NIC to monitor the value of the given OID.

If this member is set to -1, the miniport driver should use its own default settings to poll the device. Before returning, the miniport driver must set this member to the actual polling interval, in milliseconds, it will use for this indication. This allows the protocol or application to determine if the miniport driver is sampling the OID too often. The protocol or application can then possibly cancel its original request and make another request that requires the miniport driver to poll the NIC at a more appropriate interval. The returned value may be larger or smaller than the value that the protocol or application specifies.

The miniport driver ignores this member during cancel operations.

This member is set by a protocol and is returned by the miniport driver.

InitialValue
On input, a NDIS_VAR_DATA_DESC-type buffer that can contain information necessary to initialize the requested notification, for instance, as in the case of OID_WW_GEN_CURRENT_ADDRESS. The miniport driver sets information about the current value of the specified OID in this buffer before returning. This same value is also returned by the miniport driver through its call to NdisMIndicateStatus after the actual indication event is triggered.

The miniport driver ignores this member during cancel operations.

This member is set by a protocol and is returned by the miniport driver.

OIDIndicationValue
On input, contains an initialized NDIS_VAR_DATA_DESC-type buffer. The protocol must initialize at least the MaximumLength member of OIDIndicationValue during the indication request so that the miniport driver can determine if its response will fit in the protocol's buffer. Before the miniport driver makes the event notification, it allocates a NDIS_VAR_DATA_DESC-type buffer to contain the value of the specified OID, and fills in its copy of the NDIS_WW_INDICATION_REQUEST structure.

A protocol can reference the miniport-allocated buffer only during the status indication of the event. The allocating driver can deallocate this buffer and release all resources necessary to trigger the event on return from its call to NdisMIndicateStatus with this event.

The miniport driver ignores this member during cancel operations.

Only the MaximumLength member of OIDIndicationValue is verified by the miniport driver at the time of the request. The other members of OIDIndicationValue are assigned by the miniport driver and only valid during the event notification.

TriggerValue
On input, specifies a NDIS_VAR_DATA_DESC-type buffer containing a value that the underlying miniport driver might use to determine when to indicate the specified event. The value of this member can be NULL depending on the specific OID code for which a protocol requests notification. If the value of this member is NULL, the miniport driver can ignore it. For example, the miniport driver can ignore this member for OID codes that trigger on a change in status. For more information, see the descriptions of individual OID_WW_XXX codes. The miniport driver ignores this member during cancel operations.

The miniport driver must fill in the InitialValue and iPollingInterval members in both the protocol's and miniport driver's copy of the given structure with the state of the miniport driver's current information. After the requested OID has reached the trigger value or after status related to the OID changes, the miniport driver fills in the OIDIndicationValue member in its copy of this structure. The protocol that initiates this request cannot access anything in the NDIS_WW_INDICATION_REQUEST structure it allocated until ownership is returned to the protocol. The protocol can easily determine if it again owns this structure by validating that the status that NdisRequest returns is not NDIS_STATUS_PENDING. Also, the status that is returned from OID_WW_GEN_INDICATION_REQUEST only indicates the successful queuing or canceling of the event by the miniport driver and is not indicative of the actual event firing.

After event notifications for a particular OID have been enabled by this request, a wireless WAN miniport driver should fill in the appropriate information and call NdisMIndicateStatus with NDIS_STATUS_WW_INDICATION to notify NDIS, which forwards such a notification to all bound protocols, according to the following guidelines:

  • For OID_WW_GEN_XXX codes that use the TriggerValue:
    • While InitialValue < TriggerValue, the miniport driver continues to monitor for the specified condition. It posts such an event when the present value for the OID becomes >= the given TriggerValue.
    • If InitialValue = TriggerValue, the miniport driver fills in remaining information in the given structure and calls NdisMIndicateStatus to post the event immediately.
    • If InitialValue > TriggerValue, the miniport driver should post the event when the present value for the OID becomes <= TriggerValue.
    • If InitialValue is unknown, an event is posted after the current value of the OID changes to a value other than unknown.
  • For OID_WW_XXX codes that do not use the TriggerValue:

    The miniport driver should post the event when a status change occurs, as described for that OID_WW_XXX.

After a requested event is posted, the calling protocol must submit another indication request to receive another NDIS_STATUS_WW_INDICATION event. Due to the asynchronous nature of calls to NdisRequest, a protocol writer should be aware that the requested event could be posted prior to the return of a call to NdisRequest with OID_WW_GEN_INDICATION_REQUEST. The uApplicationToken member can be used to facilitate demultiplexing of each such event.

Any attempt to cancel an OID_WW_GEN_INDICATION_REQUEST that has already occurred can be ignored by the underlying driver.

Many OID_WW_GEN_INDICATION_REQUESTs can be outstanding for a particular OID. Making several calls to NdisRequest with this OID can establish several trigger points. When one of several OID_WW_GEN_INDICATION_REQUESTs causes an event notification, only that trigger is canceled, but all other OID_WW_GEN_INDICATION_REQUESTs remain enabled.

NDIS delivers a miniport driver's event indications to every protocol that is bound to that underlying driver serially. Consequently, NIC drivers must copy the contents of the indication request. A NIC driver must fill in the hIndicationHandle value prior to scheduling the request on its internal event queue and returning from the call to its set-information routine. This ensures that bound protocol(s) can detect their own respective event notifications when they occur. Consequently, a miniport driver should set a value in hIndicationHandle that is unique each time it processes this request, such as a monotonically increasing 32-bit value (transaction ID), to ensure that collisions do not occur. The value for this member can be reset to zero every time the miniport driver initializes.

When a miniport driver indicates an event for this OID, it must pass a pointer to its copy of the indication request as the Status parameter when it calls NdisMIndicateStatus. Bound protocol drivers that receive the indication must copy the indicated information into their own internal buffer space, assuming any particular protocol determines that the hIndicationHandle value indicates an event of interest to that protocol.

As a general rule, every protocol should check the hIndicationHandle value when an event notification is made and return control as soon as each protocol's ProtocolStatus function determines the indicated event is not of interest. Otherwise, the effect of notifying all bound protocols of miniport driver-indicated events is a degradation in performance for the miniport driver and for all bound protocols.

Event data is guaranteed to be valid only until a ProtocolStatus function returns control. On return from NdisMIndicateStatus, the indicating miniport driver can release all context for the specified event.

Queries and indications are irrelevant for this OID.


OID_WW_GEN_DEVICE_INFO

The OID_WW_GEN_DEVICE_INFO OID requests the miniport driver to return initialization-time information about itself and its NIC.

This request uses a WW_DEVICE_INFO structure, defined as follows:

typedef struct _WW_DEVICE_INFO{
  NDIS_VAR_DATA_DESC  Manufacturer;  // WCHAR buffer
  NDIS_VAR_DATA_DESC  ModelNum;   // WCHAR buffer
  NDIS_VAR_DATA_DESC  SWVersionNum;  // WCHAR buffer
  NDIS_VAR_DATA_DESC  SerialNum;   // WCHAR buffer
} WW_DEVICE_INFO;

The members of this structure contain the following information:

Manufacturer
Describes a buffer containing the name of the NIC's manufacturer in displayable Unicode text.
ModelNum
Describes a buffer containing the manufacturer-assigned model number of the NIC in displayable Unicode text.
SWVersionNum
Describes a buffer containing the manufacturer-assigned version number of the NIC software/firmware in displayable Unicode text.
SerialNum
Describes a buffer containing the manufacturer-assigned serial number of the NIC in displayable Unicode text.

Sets and indications are irrelevant for this OID.


OID_WW_GEN_OPERATION_MODE

As a query, the OID_WW_GEN_OPERATION_MODE OID requests the miniport driver to return information about the NIC's current power saving mode.

As a set, this OID requests the miniport driver to put its NIC into the requested power mode.

In either case, this request uses one of the following values:

Value | Meaning
0 | Normal mode
1 | Power-saving mode
-1 | Mode unknown

The miniport driver should return NDIS_STATUS_INVALID_DATA if the given value at InformationBuffer of NDIS_REQUEST is invalid or -1.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) if the NIC's power mode changes. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.


OID_WW_GEN_LOCK_STATUS

The OID_WW_GEN_LOCK_STATUS OID requests the miniport driver to return information about the NIC's current lock state as one of the following values:

Value | Meaning
0 | Unlocked
1 | Locked
-1 | Lock status unknown

Some wireless devices support external mechanisms to lock the device. If this OID indicates that the device is locked, access to the network is limited in some way.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) if the NIC's lock status changes. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.

A NIC cannot be locked or unlocked with this OID request. That is, sets are irrelevant for this OID.


OID_WW_GEN_DISABLE_TRANSMITTER

As a query, the OID_WW_GEN_DISABLE_TRANSMITTER OID requests the miniport driver to return the NIC's current transmitter status.

As a set, this OID requests the miniport driver to put its NIC's transmitter into the requested state.

In either case, this request uses one of the following values:

Value | Meaning
0 | Transmitter enabled
1 | Transmitter disabled
-1 | Transmitter state unknown

A typical use of this OID is to immediately disable the NIC's transmitter without regard to system or user traffic. The affect of this OID depends on the particular NIC. Some NICs might only disable the physical transmitter, while others might fully shutdown thereby disabling reception as well. The miniport driver should return NDIS_STATUS_INVALID_DATA if the value at InformationBuffer of NDIS_REQUEST for this request is invalid or -1.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) if the NIC's transmitter state changes. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.


OID_WW_GEN_NETWORK_ID

As a query, the OID_WW_GEN_NETWORK_ID OID requests the miniport driver to return the ID of the network with which its NIC is currently configured to communicate.

As a set, this OID requests the miniport driver to reconfigure its NIC to communicate with the network designated by the given ID.

This request uses a WW_NETWORK_ID structure, defined as equivalent to the NDIS_VAR_DATA_DESC structure, which was defined previously. The buffer contains a network-ordered sequence of binary byte values.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) if the network its NIC communicates with changes. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.


OID_WW_GEN_PERMANENT_ADDRESS

The OID_WW_GEN_PERMANENT_ADDRESS OID requests the miniport driver to return its NIC's network address in its native format, whatever the header format the driver is currently using.

This request uses a WW_PERMANENT_ADDRESS structure, defined as equivalent to the NDIS_VAR_DATA_DESC structure, which was defined previously.The buffer contains a network-ordered sequence of binary byte values.

Sets and indications are irrelevant for this OID.


OID_WW_GEN_CURRENT_ADDRESS

As a query, the OID_WW_GEN_CURRENT_ADDRESS OID requests the miniport driver to return the address in use by the NIC in the format specified. At initialization, the miniport driver sets the current address to the value returned for OID_WW_GEN_PERMANENT_ADDRESS.

As a set, this OID requests the miniport driver to change the current address.

The format of the current address depends on the header format, which must be one of the supported header formats listed with OID_WW_GEN_HEADER_FORMATS_SUPPORTED.

This request uses a WW_CURRENT_ADDRESS structure, defined as follows:

typedef struct _WW_CURRENT_ADDRESS {
  NDIS_WW_HEADER_FORMAT  Format;
  NDIS_VAR_DATA_DESC  Address;
} WW_CURRENT_ADDRESS;

The members of this structure contain the following information:

Format
Specifies one of the system-defined NdisWW..Frames values, listed with OID_WW_GEN_HEADER_FORMATS_SUPPORTED.

If an incoming set request supplies anything other than an NdisWW..Frames value or if it supplies any value that the underlying driver does not support, the driver returns NDIS_STATUS_NOT_SUPPORTED.

Address
Describes a buffer containing the station address in use by the NIC. The miniport driver maps this value, which must be compatible with the value of Format, to the address of the NIC in its native format.The buffer contains a network-ordered sequence of binary byte values.

If an incoming set request supplies an invalid address specification, the driver returns NDIS_STATUS_INVALID_DATA.

The current address is identical for all protocols bound to the same NIC miniport driver. A requested change affects all bound protocols.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) if the current address is changed. If the current address is unknown, the miniport driver should set the Length member of the Address member of WW_CURRENT_ADDRESS to zero for the indication. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.


OID_WW_GEN_SUSPEND_DRIVER

As a query, the OID_WW_GEN_SUSPEND_DRIVER OID requests the miniport driver to return its current suspension state.

As a set, this OID requests the miniport driver to change its current suspension state.

In either case, this request uses one of the following values:

Value | Meaning
0 | Driver operational
1 | Driver suspended

When a miniport driver suspends itself, it should release any hardware resources, such as the serial port, it uses in its operational state. This operation can be initiated in the control panel when an end user wants to reassign the hardware resource for other uses, such as sending AT commands to a serial device on the same serial port that the NDIS driver was using.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) if the driver's suspension state changes. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.


OID_WW_GEN_BASESTATION_ID

The OID_WW_GEN_BASESTATION_ID OID requests the miniport driver to return the ID of the base station or ad hoc device last contacted by the NIC.

This request uses a WW_BASESTATION_ID structure, defined as equivalent to the NDIS_VAR_DATA_DESC structure, which was defined previously. The buffer contains a network-ordered sequence of binary byte values.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) if the basestation ID value changes. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.

Sets are irrelevant for this OID.


OID_WW_GEN_CHANNEL_ID

The OID_WW_GEN_CHANNEL_ID OID requests the miniport driver to return the ID of the channel currently in use.

This request uses a WW_CHANNEL_ID structure, defined as equivalent to the NDIS_VAR_DATA_DESC structure, which was defined previously. The buffer contains a network-ordered sequence of binary byte values.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) if the channel ID value changes. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.

Sets are irrelevant for this OID.


OID_WW_GEN_ENCRYPTION_SUPPORTED

The OID_WW_GEN_ENCRYPTION_SUPPORTED OID requests the miniport driver to return the type(s) of encryption supported by the driver and/or the NIC. The following lists the valid encryption types from the NDIS_WW_ENCRYPTION_TYPE enumeration.

NdisWWUnknownEncryption
The driver cannot determine whether support for encryption is available from its NIC.
NdisWWNoEncryption
No support for encryption is available.
NdisWWDefaultEncryption
The NIC supports encryption but the driver cannot determine what type of encryption it supports.
NdisWWDESEncryption
The NIC supports DES encryption.
NdisWWRC2Encryption
The NIC supports RC2 encryption.
NdisWWRC4Encryption
The NIC supports RC4 encryption.
NdisWWRC5Encryption
The NIC supports RC5 encryption.

As additional NDIS_WW_ENCRYPTION_TYPE values are defined, the miniport driver should return an array of values indicating the types of encryption supported.

Sets and indications are irrelevant for this OID.


OID_WW_GEN_ENCRYPTION_IN_USE

As a query, the OID_WW_GEN_ENCRYPTION_IN_USE OID requests the miniport driver to return the type of encryption currently in use. See OID_WW_GEN_ENCRYPTION_SUPPORTED for possible values.

As a set, this OID requests the miniport driver to change the type of encryption in use. The miniport driver should return NDIS_STATUS_INVALID_DATA if NdisWWUnknownEncryption is specified.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) if the encryption type changes. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.


OID_WW_GEN_ENCRYPTION_STATE

As a query, the OID_WW_GEN_ENCRYPTION_STATE OID requests the miniport driver to return FALSE if the currently selected encryption type is disabled.

As a set, this OID requests the miniport driver to enable or disable encryption. TRUE directs the miniport driver to enable encryption.

In either case, the miniport driver should return NDIS_STATUS_NOT_SUPPORTED if it or its NIC does not support encryption.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) if the encryption state changes. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.


OID_WW_GEN_CHANNEL_QUALITY

This OID requests the miniport driver to return information about the quality of the link between its NIC and the network as follows:

Value | Meaning
0 | The wireless NIC is not in contact with the network.
1-100 | The driver can communicate with the base station at the given quality for the link, expressed as a normalized value. 100 designates the highest possible quality for the link. If a NIC indicates only whether it is in or out of network contact, its driver should return zero for out of contact and 100 for in contact.
-1 | Channel quality is unknown.

Any bound protocol that simply monitors the in/out state of network contact by an underlying wireless WAN NIC should either call NdisRequest with OID_GEN_MEDIA_CONNECT_STATUS or wait for an NDIS_STATUS_MEDIA_[DIS]CONNECT indication by the miniport driver.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) according to the TriggerValue that was specified in the OID_WW_GEN_INDICATION_REQUEST.

Sets are irrelevant for this OID.


OID_WW_GEN_REGISTRATION_STATUS

The OID_WW_GEN_REGISTRATION_STATUS OID requests the miniport driver to return the current registration state of its NIC on the network as follows:

Value | Meaning
0 | Registration was denied.
1 | Registration is pending on the network.
2 | Registered on the network. If a particular network does not provide registration information, a miniport driver should always return this value in response to this OID request. A NIC on such a network is considered to be always in the registered state.
-1 | Registration status is unknown.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) if the registration state changes. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.

Sets are irrelevant for this OID.


OID_WW_GEN_RADIO_LINK_SPEED

The OID_WW_GEN_RADIO_SPEED OID requests the miniport driver to return the radio link speed in bps. The return value is of type UINT.

Sets and indications are irrelevant for this OID.


OID_WW_GEN_LATENCY

This OID_WW_GEN_LATENCY OID requests the miniport driver to return its current estimate of the minimum latency, in milliseconds, for sending a net packet of the maximum size permitted by the network from one end point to the other within the wireless network. The return value is of type UINT.

A miniport driver can return a constant value for this query. However, a NIC driver that refines its latency estimates dynamically provides useful information to bound protocols that "autotune" themselves.

Sets and indications are irrelevant for this OID.


OID_WW_GEN_BATTERY_LEVEL

The OID_WW_GEN_BATTERY_LEVEL OID requests the miniport driver to return the current charge of the battery as follows:

Value | Meaning
0-100 | The charge of the battery as a percentage, where 100 means it is fully charged.
-1 | The charge state is unknown.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) according to the TriggerValue that was specified in the OID_WW_GEN_INDICATION_REQUEST.

Sets are irrelevant for this OID.


OID_WW_GEN_EXTERNAL_POWER

The OID_WW_GEN_EXTERNAL_POWER OID requests the miniport driver to return information about any external power source connected to the NIC as follows:

Value | Meaning
0 | No external power source is connected.
1 | External power is connected.
-1 | Unknown.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) if the external power connection state changes. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.

Sets are irrelevant for this OID.


OID_WW_GEN_PING_ADDRESS

As a set, the OID_WW_GEN_PING_ADDRESS OID requests an underlying miniport driver and its NIC to transmit a diagnostic packet for an echo-request operation to the specified node through the currently connected wireless network. The only intent of this OID is to allow protocols and applications to determine if two-way communications can be established to a remote node on the currently attached network. On some networks, additional functionality may be provided to detect if full end-to-end connectivity can be established. This OID is defined as OPTIONAL.

As a query, this OID requests the underlying miniport driver and its NIC to return information about the results of a previous echo-request operation to determine if a remote node was connected to a wireless network.

This request uses a WW_PING_ADDRESS structure, defined as follows:

typedef struct _WW_PING_ADDRESS {
  IN  WW_ADDRESS_FORMAT  Format;
  IN  NDIS_VAR_DATA_DESC  TargetAddress;
  OUT UINT  uTime;
} WW_PING_ADDRESS;

The members of this structure contain the following information:

Format
Address format of the remote node specified by TargetAddress. This address format must be one of the values contained in the WW_ADDRESS_FORMAT enumeration. The following lists the valid values.
WW_IEEE_ADDRESS
A 48-bit IEEE address in network byte order.
WW_MOBITEX_MAN_ADDRESS
A Mobitex access number in network byte order.
WW_DATATAC_RDLAP_ADDRESS
A DataTAC RDLAP address in network byte order.
WW_DATATAC_MDC4800_ADDRESS
A DataTAC MDC 4800 address in network byte order.
WW_DATATAC_RESERVED
Reserved by DataTAC networks.
WW_IPv4_ADDRESS
An IP version 4 address in network byte order.
WW_IPv6_ADDRESS
An IP version 6 address in network byte order.
WW_PROPRIETARY_ADDRESS
Address is specified in a proprietary format. The miniport driver must decode the format in which the address is represented.

If an incoming echo-request operation supplies anything other than one of the preceding values or if it supplies a value that the underlying driver does not support, the underlying driver returns NDIS_STATUS_NOT_SUPPORTED.

TargetAddress
Specifies a NDIS_VAR_DATA_DESC type that describes a buffer containing the station network address in use by the remote node. The miniport driver maps this address, which must be compatible with the value of Format, to a native address of the currently connected wireless network. The address in the buffer is represented in network byte order.

Broadcast or group addresses are invalid for this operation and the miniport driver should return NDIS_STATUS_INVALID_DATA.

uTime
Specifies the length of time in milliseconds for the echo-request operation to complete. This operation requires the miniport driver to transmit a diagnostic packet to the remote node and then receive a response from the remote node. This member specifies the time that elapses between the transmission and response.
A value of –1 represents an unsuccessful echo-request operation.

Indications are irrelevant for this OID.


OID_WW_GEN_RSSI

The OID_WW_GEN_RSSI OID requests an underlying miniport driver to return information that specifies the strength of the signal in decibels (dB) that the miniport driver's NIC receives. This OID requests the raw signal strength versus the normalized value that OID_WW_GEN_CHANNEL_QUALITY returns. Protocols and applications can retrieve this raw signal strength information to assist in technical debugging purposes. This OID is defined as OPTIONAL.

This request uses a WW_RECEIVE_SIGNAL_STRENGTH_INDICATOR structure, defined as follows:

typedef struct _WW_RECEIVE_SIGNAL_STRENGTH_INDICATOR {
  OUT INT  iDecibels;
  OUT INT  iFactor;
} WW_RECEIVE_SIGNAL_STRENGTH_INDICATOR;

The members of this structure contain the following information:

iDecibels
Decibel (dB) value for the raw signal strength measurement.
iFactor
Power to base 10 for the raw signal strength measurement.

If iDecibels is 3 dB and iFactor is 2, the strength of the received signal is
3 * (10^2) = 300 dB.

Sets and indications are irrelevant for this OID.


OID_WW_GEN_SIM_STATUS

The OID_WW_GEN_SIM_STATUS OID requests an underlying miniport driver to return information that specifies if its NIC has an attached Subscriber Information Module (SIM). This OID also requests information about the SIM and if a Personal Identification Number (PIN) is required to be entered for the SIM in order to access the NIC. A PIN is also known as a password. This OID is defined as OPTIONAL.

This request uses a WW_SIM_STATUS structure, defined as follows:

typedef struct _WW_SIM_STATUS {
  OUT BOOLEAN  bHasSIM;
  OUT BOOLEAN  bBlocked;
  OUT BOOLEAN  bLocked;
  OUT BOOLEAN  bInitialized;
  OUT UINT  uCountdown;
} WW_SIM_STATUS;

The members of this structure contain the following information:

bHasSIM
Boolean value that is TRUE if the underlying miniport driver requires a SIM to access the NIC and FALSE if the NIC does not use a SIM.
bBlocked
Boolean value that is TRUE if access to the SIM using a PIN is blocked and FALSE if a PIN can unlock the SIM.
bLocked
Boolean value that is TRUE if the underlying miniport driver requires a PIN to be entered for the SIM in order to access the NIC and FALSE if a PIN is not required.
bInitialized
Boolean value that is TRUE if the SIM has already been initialized with a PIN and FALSE if a PIN has never been set for the SIM.
uCountdown
Specifies the remaining number of attempts that are available to users to enter the correct PIN. If this value is zero and a PIN is required as specified by bLocked, users can no longer enter a PIN. In this case, the NIC's SIM must either be returned for unlocking service or, if implemented, OID_WW_GEN_SIM_PUK must be used to reset uCountDown to enable further attempts for entering the correct PIN.

SIMs are sometimes also referred to as smart cards. SIMs are used in wireless telephones that are based on both Global System for Mobile (GSM) and Code Division Multiple Access (CDMA) communications standards. SIMs identify call plans and other phone information for individuals. Therefore, call plans and other phone information are linked to SIMs and not phones. For example, if an individual buys a new wireless phone and both his new and old wireless phones support compatible SIMs, he is not required to contact his wireless service provider. He simply must remove the SIM from his old phone and insert it into his new phone. His phone number, permissions, and service plans are then transferred to his new phone.

SIMs have a security feature whereby they can lock their associated phones until users enter their PINs on keypads for the phones. This OID was introduced as a solution for devices that do not have keypads such as computer cards. Until this OID was introduced, there was no programmatic mechanism provided to unlock a SIM.

Sets and indications are irrelevant for this OID.


OID_WW_GEN_ENABLE_SIM_PIN

This OID notifies an underlying miniport driver to either enable or disable the PIN security feature of the Subscriber Information Module (SIM). This OID is defined as OPTIONAL.

This request uses a WW_ENABLE_SIM_PIN structure, defined as follows:

typedef struct _WW_ENABLE_SIM_PIN {
  IN  BOOLEAN  bEnabled;
  IN  NDIS_VAR_DATA_DESC  CurrentPIN;
} WW_ENABLE_SIM_PIN;

The members of this structure contain the following information:

bEnabled
Boolean value that is TRUE if the PIN security feature for the SIM is enabled and FALSE if the PIN for the SIM is disabled. A value of TRUE requires protocols and applications to enter the correct PIN for the SIM before access to the NIC's services is granted.
CurrentPIN
Specifies a NDIS_VAR_DATA_DESC type that describes a buffer containing the PIN that was previously programmed into the SIM. For security reasons, the miniport driver should erase any internal copies of the PIN after using the PIN or after determining that a PIN is not required to access the NIC's services.

The PIN security feature of a SIM is used to lock the phone into which it is inserted until the PIN is entered on the keypad for the phone. This OID was introduced as a solution for devices that do not have keypads such as computer cards. Until this OID was introduced, there was no programmatic mechanism provided to unlock a SIM.

If a miniport driver's NIC does not use a SIM, the miniport driver should return an error value of NDIS_STATUS_NOT_SUPPORTED for incoming requests to enable or disable a SIM.

Queries and indications are irrelevant for this OID.


OID_WW_GEN_CHANGE_SIM_PIN

The OID_WW_GEN_CHANGE_SIM_PIN OID notifies the underlying miniport driver to modify the Personal Identification Number (PIN) that is programmed into the Security Identification Module (SIM). This OID is defined as OPTIONAL.

This request uses a WW_CHANGE_SIM_PIN structure, defined as follows:

typedef struct _WW_CHANGE_SIM_PIN {
  IN  NDIS_VAR_DATA_DESC  NewPIN;
  IN  NDIS_VAR_DATA_DESC  OldPIN;
} WW_CHANGE_SIM_PIN;

The members of this structure contain the following information:

NewPIN
Specifies a NDIS_VAR_DATA_DESC type that describes a buffer containing the new PIN that is to be programmed into the SIM.
OldPIN
Specifies a NDIS_VAR_DATA_DESC type that describes a buffer containing the existing PIN that is already programmed into the SIM.

For security reasons, the miniport driver should erase any internal copies of both PINs after using them.

If a miniport driver's NIC does not use a SIM, the miniport driver should return an error value of NDIS_STATUS_NOT_SUPPORTED for incoming requests to modify the PIN that is programmed into the SIM.

Queries and indications are irrelevant for this OID.


OID_WW_GEN_SIM_PUK

The OID_WW_GEN_SIM_PUK OID notifies an underlying miniport driver about the Personal Unblocking Key (PUK) that is programmed into the Security Identification Module (SIM). The miniport driver uses this PUK to reset the number of retry attempts that are available to protocols and applications to enter the correct PIN into the SIM so that the NIC's services can be accessed. For more information, see OID_WW_GEN_SIM_STATUS. This OID is defined as OPTIONAL.

This request uses a WW_ENABLE_SIM_PUK structure, defined as equivalent to the NDIS_VAR_DATA_DESC structure, which was defined previously. The buffer that WW_ENABLE_SIM_PUK describes contains the PUK for the SIM as a network-ordered sequence of binary byte values.

For security reasons, the miniport driver should erase any internal copies of the PUK after using the PUK.

If a miniport driver's NIC does not use a SIM, the miniport driver should return an error value of NDIS_STATUS_NOT_SUPPORTED for incoming PUK notifications.

Queries and indications are irrelevant for this OID.


OID_WW_GEN_SIM_EXCEPTION

The OID_WW_GEN_SIM_EXCEPTION OID requests an underlying miniport driver to return information that specifies status for various SIM-related conditions. The following lists the valid status values from the WW_GEN_SIM_EXCEPTION enumeration. This OID is defined as OPTIONAL.

SIM_STATUS_OK
No known error conditions related to the SIM.
SIM_STATUS_ERROR
General SIM-related failure. A status error of this type indicates that possibly the NIC's SIM should be returned for service.
SIM_STATUS_MISSING
The SIM is not inserted in the NIC but is required to access the NIC's services.
SIM_STATUS_NO_RESPONSE
The SIM is inserted in the NIC but not responding to requests. A status error of this type indicates that possibly the NIC's SIM should be returned for service.
SIM_STATUS_REMOVED
The SIM has been detached from the NIC.
SIM_STATUS_CRYPT_ERROR
The contents of the SIM is corrupt. A status error of this type indicates that possibly the SIM is defective or has been tampered with. The SIM should be returned for service.
SIM_STATUS_AUTH_ERROR
Authentication for the SIM has failed. A status error of this type indicates that possibly the SIM is defective or has been tampered with. The SIM should be returned for service.
SIM_STATUS_NEED_PIN
The SIM requires a PIN before access to the NIC's services is granted.
SIM_STATUS_NEED_PUK
The SIM requires a PUK to reset the number of retry attempts that are available to protocols and applications to enter the correct PIN into the SIM. A status error of this type indicates that entry of a PIN into the SIM has exceeded the available number of attempts. For more information, see OID_WW_GEN_SIM_STATUS and OID_WW_GEN_SIM_PUK.
SIM_STATUS_WRONG
A SIM is inserted in the NIC but is the incorrect SIM for the NIC. That is, this particular type of SIM is not compatible with the NIC.

Queries with this OID return the most recently recorded SIM-related condition. If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) if any SIM operation generates one of the status conditions in the WW_GEN_SIM_EXCEPTION enumeration. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.

Sets are irrelevant for this OID.


Network-Dependent Wireless Objects

This section describes the system-defined OIDs for wireless networks including Metricom, DataTAC, Ardis, CDPD, Pinpoint, and Mobitex. The OIDs for these wireless networks are described in the following topics:

Metricom Wireless OIDs

DataTAC Wireless OIDs

Ardis Wireless OIDs

CDPD Wireless OIDs

Pinpoint Wireless OIDs

Mobitex Wireless OIDs


Metricom Wireless OIDs

The following chart shows the single Metricom-specific wireless OID.

Q | S | Indication | Name
M | M |  | OID_WW_MET_FUNCTION

OID_WW_MET_FUNCTION

As a query, the OID_WW_MET_FUNCTION OID requests the miniport driver return the response to the last latched AT command.

As a set, this OID requests the miniport driver latch a single AT command to be executed. Such a command always begins with the prefix "AT" or "at."

This request is generic for executing AT commands through NDIS driver(s). See the Metricom modem reference manual for information about the AT commands and S registers specific to this device. The data described by this structure is always a NUL-terminated ASCII string.

This request uses a WW_MET_FUNCTION structure, defined as equivalent to the NDIS_VAR_DATA_DESC structure, which was defined previously.

Although a driver must accept all supported commands, the driver writer determines when each AT command is executed in a manner that avoids conflicts with the NIC's normal operations.

Indications are irrelevant for this OID.


DataTAC Wireless OIDs

The following chart summarizes DataTAC-specific wireless OIDs.

Q | S | Indication | Name
M |  |  | OID_WW_TAC_COMPRESSION
M |  |  | OID_WW_TAC_SET_CONFIG
M |  |  | OID_WW_TAC_GET_STATUS
M | M |  | OID_WW_TAC_USER_HEADER
M |  |  | OID_WW_TAC_UNIQUE_SDU_TAG
 | M |  | OID_WW_TAC_SEND_COMMAND
M |  | M | OID_WW_TAC_GET_RESPONSE
M | M | M | OID_WW_TAC_DISABLE_RECEIVER
M | M |  | OID_WW_TAC_ANTENNA_MODE
 | M |  | OID_WW_TAC_FLUSH_DATA
M | M | M | OID_WW_TAC_SHUTDOWN_DEVICE
M |  | M | OID_WW_TAC_DEVICE_EXCEPTION
M |  | M | OID_WW_TAC_RECEIVE_EXCEPTION
M |  | M | OID_WW_TAC_BUFFER_EXCEPTION
M |  | M | OID_WW_TAC_BATTERY_EXCEPTION
M |  | M | OID_WW_TAC_TRANSMITTER_KEYED
M |  |  | OID_WW_TAC_SYSTEM_TABLE
M |  |  | OID_WW_TAC_CHANNEL_TABLE
M |  |  | OID_WW_TAC_DCHANNEL_TABLE
M |  |  | OID_WW_TAC_RECEIVE_QUEUE_COUNT
M |  |  | OID_WW_TAC_STATISTICS


OID_WW_TAC_COMPRESSION

The OID_WW_TAC_COMPRESSION OID requests the miniport driver to return a Boolean indicating whether the miniport driver supports network-layer compression. A value of TRUE indicates network-layer compression is in use. A value of FALSE indicates network-layer compression is not in use.

Sets and indications are irrelevant for this OID.


OID_WW_TAC_SET_CONFIG

Note that this OID is obsolete and should not be used; it is included for informational and historical purposes. Use OID_WW_TAC_SEND_COMMAND and OID_WW_TAC_GET_RESPONSE instead.

This OID requests the miniport driver to return the current configuration of the device.

This OID uses the WW_TAC_SETCONFIG structure, defined as follows:

typedef struct   _WW_TAC_SETCONFIG {
  NDIS_VAR_DATA_DESC  RCV_MODE;
  NDIS_VAR_DATA_DESC  TX_CONTROL;
  NDIS_VAR_DATA_DESC  RX_CONTROL;
  NDIS_VAR_DATA_DESC  FLOW_CONTROL;
  NDIS_VAR_DATA_DESC  RESET_CNF;
  NDIS_VAR_DATA_DESC  READ_CNF;
} WW_TAC_SETCONFIG;

The members of this structure contain the following information:

RCV_MODE
Confirmed or unconfirmed receive mode.
TX_CONTROL
Transmitter enabled or disabled.
RX_CONTROL
Radio modem enabled or disabled.
FLOW_CONTROL
Current flow control uses the DTE and DCE.
RESET_CNF
Whether the device is configured to default settings.
READ_CNF
Reserved.

Each of these members is of type NDIS_VAR_DATA_DESC, described previously.

Support for this OID depends on the RF modem's support for controlling the transmitter, receiver, and flow control.

Sets and indications are irrelevant for this OID.


OID_WW_TAC_GET_STATUS

The OID_WW_TAC_GET_STATUS OID is obsolete and should not be used; it is included for informational and historical purposes. Use OID_WW_TAC_SEND_COMMAND and OID_WW_TAC_GET_RESPONSE instead.

This OID requests the miniport driver to return configuration and status information about the device.

This OID uses the WW_TAC_GETSTATUS structure, defined as follows:

typedef  struct   _WW_TAC_GETSTATUS{
  BOOLEAN  Action;
  NDIS_VAR_DATA_DESC  Command;
  NDIS_VAR_DATA_DESC  Option;
  NDIS_VAR_DATA_DESC  Response;
} WW_TAC_GETSTATUS;

The members of this structure contain the following information:

Action
TRUE indicates the command specified in the buffer at Command should be inspected.
Command
Specifies a command in the native-mode interface between the DTE and DCE. See the hardware reference manual for these chips for specifics.
Option
Specifies an option for the given command.
Response
Returns the response to the given command. This buffer is at most 256 bytes in size.

Several of these members are of type NDIS_VAR_DATA_DESC, described previously.

Protocols or applications might use this OID to request configuration and status information from the RF modem.

Sets and indications are irrelevant for this OID.


OID_WW_TAC_USER_HEADER

As a query, the OID_WW_TAC_USER_HEADER OID requests the miniport driver to return the current user header.

As a set, this OID requests the miniport driver to set the user header that is required by the DataTAC network.

This request uses a WW_TAC_USERHEADER structure, defined as equivalent to the NDIS_VAR_DATA_DESC structure, which was defined previously. At most, the information supplied in this buffer can be 64 bytes in length. The buffer contains a network-ordered sequence of binary byte values.

Indications are irrelevant for this OID.


OID_WW_TAC_UNIQUE_SDU_TAG

The OID_WW_TAC_UNIQUE_SDU_TAG OID requests the miniport driver to return a unique (transaction) token to be used in a subsequent OID_WW_TAC_SEND_COMMAND request. This unique token is returned as an unsigned integer. This token can then be used by the protocol and miniport driver to demultiplex the NIC's command response. For more information, see OID_WW_TAC_GET_RESPONSE.

Sets and indications are irrelevant for this operation.


OID_WW_TAC_SEND_COMMAND

The OID_WW_TAC_SEND_COMMAND OID requests the miniport driver to send a command to the DataTAC NIC using Native Control Language (NCL). The calling protocol formats the NCL command for the Service Data Unit (SDU) as described in DataTAC Open Protocol Specifications Native Control Language Release 1.2. Use of this OID is not recommended if an equivalent OID_WW_TAC_XXX object exists.

This request uses a WW_TAC_SEND_COMMAND structure, defined as equivalent to the NDIS_VAR_DATA_DESC structure, which was defined previously. At most, the information supplied in this buffer can be 2048 bytes in length.

The miniport driver maintains its own copy of the SDU token that was previously returned to the protocol through the OID_WW_TAC_UNIQUE_SDU_TAG request. The miniport driver transfers the NCL command for the SDU to the NIC. Upon completion of the command, the miniport driver then retrieves the response and makes the response available through a subsequent OID_WW_TAC_GET_RESPONSE request.

Queries and indications are irrelevant for this OID.


OID_WW_TAC_GET_RESPONSE

The OID_WW_TAC_GET_RESPONSE OID requests the miniport driver to return a response to a previously issued command. A protocol issued this command using the OID_WW_TAC_SEND_COMMAND request. The miniport driver transferred this command to the NIC. Upon completion of this command, the miniport driver retrieves the response.

This OID uses the WW_TAC_GET_RESPONSE structure, defined as follows:

typedef  struct _WW_TAC_GET_RESPONSE {
  UINT  SDUTag;
  NDIS_VAR_DATA_DESC  Response;
} WW_TAC_GET_RESPONSE;

The members of this structure contain the following information:

SDUTag
The unique token that was previously returned to the protocol using OID_WW_TAC_UNIQUE_SDU_TAG.
Response
Describes a buffer that contains the response information for a previously issued command. For more information, see OID_WW_TAC_SEND_COMMAND. This buffer is at most 2048 bytes in size.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) about the completion status and contents of the specific NCL command. If a protocol enabled an indication request, the protocol must assign an initialized WW_TAC_GET_RESPONSE structure to the InitialValue member of the NDIS_WW_INDICATION_REQUEST structure. The miniport driver interrogates the contents of this initialized WW_TAC_GET_RESPONSE and uses the value in the SDUTag member to demultiplex and indicate the response. The miniport driver can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.

Miniport drivers return NDIS_STATUS_INVALID_DATA if a request is issued with an invalid value in the SDUTag member.

Sets are irrelevant for this OID.


OID_WW_TAC_DISABLE_RECEIVER

As a query, the OID_WW_TAC_DISABLE_RECEIVER OID requests the miniport driver to return information about the NIC's current receiver mode.

As a set, this OID requests the miniport driver to put the NIC's receiver into the specified mode of operation.

This request uses a WW_TAC_DISABLE_RECEIVER data type, defined as equivalent to an INT.

For either a query or a set, this request uses one of the following values:

Value | Meaning
0 | Receiver enabled
1 | Receiver disabled
-1 | State of receiver unknown

Typically, this OID can be used to temporarily disable the NIC's receiver to conserve battery power. During sets, a value of unknown, that is -1, is invalid; the miniport driver should return an error of NDIS_STATUS_INVALID_DATA.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) if the state of the NIC's receiver changes. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.


OID_WW_TAC_ANTENNA_MODE

As a query, the OID_WW_TAC_ANTENNA_MODE OID requests the miniport driver to return the NIC's current antenna-selection algorithm.

As a set, this OID requests the miniport driver to change the NIC's current antenna-selection algorithm.

This request uses a WW_TAC_ANTENNA_MODE data type, defined as equivalent to an INT.

For either a query or a set, this request uses one of the following values:

Value | Meaning
0 | Automatic antenna selection
1 | Always use primary antenna
2 | Always use secondary antenna
-1 | Antenna algorithm currently unknown

Typically, this OID can be used to either temporarily change which antenna the NIC currently uses for debugging purposes or to select an alternate antenna if the antenna that is currently in use fails to operate correctly. During sets, a value of unknown, that is -1, is invalid; the miniport driver should return an error of NDIS_STATUS_INVALID_DATA.

Indications are irrelevant for this OID.


OID_WW_TAC_FLUSH_DATA

The OID_WW_TAC_FLUSH_DATA OID requests the miniport driver to instruct the NIC to immediately transfer any data that the NIC previously queued.

This request uses a WW_TAC_FLUSH_DATA data type, defined as equivalent to an INT, and the following values:

Value | Meaning
1 | Flush buffered data that is destined for the network.
2 | Flush buffered data that was received from the network.
3 | Flush all buffered data.

Typically, this OID can be used to force the NIC to transfer any data that was previously queued before the miniport driver puts its NIC into a power-saving mode. During sets, values other than the preceding values are invalid; the miniport driver should return an error of NDIS_STATUS_INVALID_DATA.

Queries and indications are irrelevant for this OID.


OID_WW_TAC_SHUTDOWN_DEVICE

As a query, the OID_WW_TAC_SHUTDOWN_DEVICE OID requests the miniport driver to return the current state of the NIC.

As a set, this OID requests the miniport driver to set the state of the NIC to the specified mode of operation.

This request uses a WW_TAC_SHUTDOWN_DEVICE data type, defined as equivalent to an INT.

For either a query or a set, this request uses one of the following values:

Value | Meaning
0 | Enabled device. The miniport driver acquires required hardware resources, powers on the NIC, and resumes operation.
1 | Disable device. The miniport driver suspends operation, powers off NIC, and releases all hardware resources.
-1 | State of device unknown

Typically, this OID can be used to disable the NIC and associated hardware to conserve battery power. During sets, a value of unknown, that is -1, is invalid; the miniport driver should return an error of NDIS_STATUS_INVALID_DATA.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) if the state of the NIC changes. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.


OID_WW_TAC_DEVICE_EXCEPTION

The OID_WW_TAC_DEVICE_EXCEPTION OID requests the miniport driver to return various NIC-related device conditions. Protocols can query for these conditions or can request to receive these conditions if device operations occur. Queries receive the most recently recorded conditions.

Return values from this request are limited to the values contained in the WW_TAC_DEV_EXCEPTION enumeration. The following lists the valid values.

DATATAC_DEVX_OK
There are no known NIC-related device conditions.
DATATAC_DEVX_MISSING
The NIC was removed.
DATATAC_DEVX_POST_ERROR
Power On Self Text (POST) of the NIC failed.
DATATAC_DEVX_ERROR
An unspecified device related error occurred. The device should possibly be returned for service.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) that the status of an operation generated a status condition from the preceding list. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.

Sets are irrelevant for this OID.


OID_WW_TAC_RECEIVE_EXCEPTION

The OID_WW_TAC_RECEIVE_EXCEPTION OID requests the miniport driver to return various NIC-related receiver conditions. Protocols can query for these conditions or can request to receive these conditions if receive operations occur. Queries receive the most recently recorded conditions.

Return values from this request are limited to the values contained in the WW_TAC_RCV_EXCEPTION enumeration. The following lists the valid values.

DATATAC_RCVX_OK
No errors occurred during the last receive operation.
DATATAC_RCVX_RECEIVE_ERROR
Unable to acknowledge received data.
DATATAC_RCVX_ERROR
An unspecified receive-related error occurred. The device should possibly be returned for service.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) that the status of a receive operation generated a status condition from the preceding list. Note however, to improve system performance, miniport drivers should only generate indications if a receive operation resulted in a status other then DATATAC_RCVX_OK. The miniport driver can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.

Sets are irrelevant for this OID.


OID_WW_TAC_BUFFER_EXCEPTION

The OID_WW_TAC_BUFFER_EXCEPTION OID requests the miniport driver to return various NIC-related buffer conditions. Protocols can query for these conditions or can request to receive these conditions if operations occur. Queries receive the most recently recorded buffer conditions.

Return values from this request are limited to the values contained in the WW_TAC_BFR_EXCEPTION enumeration. The following lists the valid values.

DATATAC_BFRX_OK
No known buffer-related errors occurred.
DATATAC_BFRX_OVERFLOW
Buffer-overflow error occurred.
DATATAC_BFRX_ERROR
An unspecified buffer-related error occurred. The device should possibly be returned for service.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) that the status of an operation generated a status condition from the preceding list. Note however, to improve system performance, miniport drivers should only generate indications if an operation resulted in a status other then DATATAC_BFRX_OK. The miniport driver can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.

Sets are irrelevant for this OID.


OID_WW_TAC_BATTERY_EXCEPTION

The OID_WW_TAC_BATTERY_EXCEPTION OID requests the miniport driver to return various NIC-related battery conditions. Protocols can query for these conditions or can request to receive these conditions if the status of the battery changes. Queries receive the most recently recorded conditions.

Return values from this request are limited to the values contained in the WW_TAC_BAT_EXCEPTION enumeration. The following lists the valid values.

DATATAC_BATX_OK
No known battery-related errors occurred.
DATATAC_BATX_LOW
Battery level is low; transmitter was disabled.
DATATAC_BATX_ERROR
An unspecified battery-related error occurred. The battery should possibly be returned for service.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) that the status of the battery changed. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.

Sets are irrelevant for this OID.


OID_WW_TAC_TRANSMITTER_KEYED

The OID_WW_TAC_TRANSMITTER_KEYED OID requests the miniport driver to return a Boolean indicating whether the NIC's transmitter is operating. A value of TRUE indicates the NIC's transmitter is currently operating. A value of FALSE indicates it is in a quiescent state.

Typically, this OID can be used to provide users information about the state of the NIC's transmitter. That is, provide users a transmit indicator.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) if the operational state of the NIC's transmitter changes. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.

Sets are irrelevant for this object.


OID_WW_TAC_SYSTEM_TABLE

The OID_WW_TAC_SYSTEM_TABLE OID requests the miniport driver to return the current set of DataTAC systems that are supported by the NIC.

This OID uses the WW_TAC_SYSTEM_TABLE structure, defined as follows:

typedef struct _WW_TAC_SYSTEM_TABLE {
  UINT  SystemCount;
  UCHAR  CountryTable[32];
  UCHAR  PrefixTable[32];
  UCHAR  IDTable[32];
} WW_TAC_SYSTEM_TABLE;

The members of this structure contain the following information:

SystemCount
Number of valid entries in each table.
CountryTable
Array of DataTAC-country/region codes. Maximum length is 32 entries.
PrefixTable
Array of DataTAC-system prefixes. Maximum length is 32 entries.
IDTable
Array of DataTAC-system identifiers. Maximum length is 32 entries.

Protocols use this OID to request the currently configured system table.

Sets and indications are irrelevant for this OID.


OID_WW_TAC_CHANNEL_TABLE

The OID_WW_TAC_CHANNEL_TABLE OID requests the miniport driver to return the DataTAC-channel list that is statically configured in the NIC.

This OID uses the WW_TAC_CHANNEL_TABLE structure, defined as follows:

typedef struct _WW_TAC_CHANNEL_TABLE {
  UINT  ChannelCount;
  UCHAR  ChannelTable[64];
  UCHAR  AttrTable[64];
} WW_TAC_CHANNEL_TABLE;

The members of this structure contain the following information:

ChannelCount
The number of valid entries in the ChannelTable array.
ChannelTable
Array of DataTAC-channel numbers. Maximum length is 64 entries.
AttrTable
Array of DataTAC-channel attributes. Maximum length is 64 entries.

Protocols use this OID to request the statically-configured DataTAC-channel list. The channel-numbering scheme and contents of the channel-attributes array are defined by the DataTAC RD-LAP protocol standard.

Typically, this OID can be used to provide a control panel application with a channel list. The application can then present the list to the user.

Sets and indications are irrelevant for this OID.


OID_WW_TAC_DCHANNEL_TABLE

The OID_WW_TAC_DCHANNEL_TABLE OID requests the miniport driver to return the DataTAC-dynamic-channel list that is currently in use by the NIC.

This OID uses the WW_TAC_CHANNEL_TABLE structure, that was previously defined in OID_WW_TAC_CHANNEL_TABLE.

Protocols use this OID to request the dynamic-DataTAC-channel list. The channel-numbering scheme and contents of the channel-attributes array are defined by the DataTAC RD-LAP protocol standard.

Typically, this OID can be used to provide a control panel application with a channel list. The application can then present the list to the user.

Sets and indications are irrelevant for this OID.


OID_WW_TAC_RECEIVE_QUEUE_COUNT

The OID_WW_TAC_RECEIVE_QUEUE_COUNT OID requests the miniport driver to return the number of frames that have been received and are currently queued by the NIC but not yet delivered to the miniport driver. This number is returned as an unsigned integer.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) according to the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.

Sets are irrelevant for this OID.


OID_WW_TAC_TRANSMIT_QUEUE_COUNT

The OID_WW_TAC_TRANSMIT_QUEUE_COUNT OID requests the miniport driver to return the number of frames that are currently queued by the NIC but not yet delivered to the network. This number is returned as an unsigned integer.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) according to the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.

Sets are irrelevant for this OID.


OID_WW_TAC_STATISTICS

The OID_WW_TAC_STATISTICS OID requests the miniport driver to return DataTAC-specific statistics that the miniport driver retrieved from the NIC.

This request uses a WW_TAC_STATISTICS structure, defined as equivalent to the NDIS_VAR_DATA_DESC structure, which was defined previously. This buffer describes statistical information defined by the DataTAC protocol standard for MDC or RD-LAP statistics, based on the current channel attributes. For example, if the channel attribute is RD-LAP, the buffer contains the statistics report. The buffer contains a network-ordered sequence of binary byte values.

Sets and indications are irrelevant for this OID.


OID_WW_ARD_SNDCP

The OID_WW_ARD_SNDCP OID is obsolete and should not be used; it is included for informational and historical purposes. Use DataTAC wireless OIDs in DataTAC Wireless OIDs instead.

This OID requests the miniport driver to return information about the SNDCP support it provides.

This OID uses a WW_ARD_SNDCP structure, defined as follows:

typedef  struct   _WW_ARD_SNDCP{
  NDIS_VAR_DATA_DESC  Version;
  INT  BlockSize;
  INT  Window;
} WW_ARD_SNDCP;

The members of this structure contain the following information:

Version
The version of the SNDCP protocol supported.
BlockSize
The block size being used for SNDCP.
Window
The window size being used in SNDCP.

The Version member is of type NDIS_VAR_DATA_DESC, which was defined previously. The value is a NUL-terminated ASCII string.

The Subnetwork Dependent Convergence Protocol (SNDCP) is ARDIS-defined.

Sets and indications are irrelevant for this OID.


OID_WW_ARD_TMLY_MSG

The OID_WW_ARD_TMLY_MSG OID is obsolete and should not be used; it is included for informational and historical purposes. Use DataTAC wireless OIDs in DataTAC Wireless OIDs instead.

This OID requests the miniport driver to return the current status of the RF channel as a Boolean value, derived from the RF network.

Sets and indications are irrelevant for this OID.


OID_WW_ARD_DATAGRAM

This OID_WW_ARD_DATAGRAM OID is obsolete and should not be used; it is included for informational and historical purposes. Use DataTAC wireless OIDs in DataTAC Wireless OIDs instead.

This OID requests the miniport driver to return information about the datagram service on the network.

This request uses a WW_ARD_DATAGRAM structure, defined as follows:

typedef  struct   _WW_ARD_DATAGRAM{
  BOOLEAN  LoadLevel;
  INT  SessionTime;
  NDIS_VAR_DATA_DESC  HostAddr;
  NDIS_VAR_DATA_DESC  THostAddr;
} WW_ARD_DATAGRAM;

The members of this structure contain the following information:

LoadLevel
The current load-level status.
SessionTime
Datagram session time remaining.
HostAddr
Specifies the host address.
THostAddr
Specifies the test host address.

The HostAddr and THostAddr members are of type NDIS_VAR_DATA_DESC, which was defined previously. The value of each is a network-ordered byte string.

Sets and indications are irrelevant for this OID.


CDPD Wireless OIDs

The following chart summarizes CDPD-specific wireless OIDs.

Q | S | Indication | Name
M | M |  | OID_WW_CDPD_SPNI
M | M |  | OID_WW_CDPD_WASI
M |  | M | OID_WW_CDPD_AREA_COLOR
M |  | M | OID_WW_CDPD_TX_POWER_LEVEL
M |  |  | OID_WW_CDPD_EID
M | M |  | OID_WW_CDPD_HEADER_COMPRESSION
M | M |  | OID_WW_CDPD_DATA_COMPRESSION
M | M |  | OID_WW_CDPD_CHANNEL_SELECT
M |  | M | OID_WW_CDPD_CHANNEL_STATE
M | M |  | OID_WW_CDPD_NEI
M | M | M | OID_WW_CDPD_NEI_STATE
M | M |  | OID_WW_CDPD_SERVICE_PROVIDER_IDENTIFIER
M | M | M | OID_WW_CDPD_SLEEP_MODE
M | M |  | OID_WW_CDPD_CIRCUIT_SWITCHED
M |  |  | OID_WW_CDPD_TEI
M |  | M | OID_WW_CDPD_RSSI
M | M |  | OID_WW_CDPD_CS_SERVICE_PREFERENCE
M |  |  | OID_WW_CDPD_CS_SERVICE_STATUS
M |  |  | OID_WW_CDPD_CS_INFO
 | M |  | OID_WW_CDPD_CS_SUSPEND
M | M |  | OID_WW_CDPD_CS_DEFAULT_DIAL_CODE
M | M |  | OID_WW_CDPD_CS_CALLBACK
M | M |  | OID_WW_CDPD_CS_SID_LIST
M | M |  | OID_WW_CDPD_CS_CONFIGURATION


OID_WW_CDPD_SPNI

The OID_WW_CDPD_SPNI OID requests the miniport driver either to return or to set up an array of a maximum of ten Service Provider Network Identifiers (SPNIs) and the current operating mode with respect to this array. This OID can specify for the device to be configured to ignore SPNI during channel acquisition, to not acquire a channel if the SPNI of the channel is not in the current list, or to prefer a channel that has an SPNI in the list.

This request uses a WW_CDPD_SPNI structure, defined as follows:

typedef  struct   _WW_CDPD_SPNI {
  UINT  SPNI[10];
  INT  OperatingMode;
} WW_CDPD_SPNI;

The members of this structure contain the following information:

SPNI
Specifies an array of ten UINT values, each a service provider network identifier.
OperatingMode
Specifies how the driver handles SPNI as one of the following values:
Value | Meaning
0 | Ignore SPNI.
1 | SPNI from list is required.
2 | SPNI from list is preferred.
3 | SPNI from list is excluded.

To ensure that the list of SPNI values is maintained, bound protocols should issue a query with this OID before they issue a set request.

Indications are irrelevant for this OID.


OID_WW_CDPD_WASI

The OID_WW_CDPD_WASI OID requests the miniport driver either to return or to set up an array of a maximum of ten Wide Area Network Identifiers (WASIs) and the current operating mode with respect this array. This OID can specify for the device to be configured to ignore WASI during channel acquisition, to not acquire a channel if the WASI of the channel is not in the current list, or to prefer a channel that has a WASI in the list.

This request uses a WW_CDPD_WASI structure, defined as follows:

typedef  struct   _WW_CDPD_WASI {
  UINT  WASI[10];
  INT  OperatingMode;
} WW_CDPD_WASI;

The members of this structure contain the following information:

WASI
Specifies an array of ten UINT values, each a wide-area network identifier.
OperatingMode
Specifies how the driver handles WASI as one of the following values:
Value | Meaning
0 | Ignore WASI.
1 | WASI from list is required.
2 | WASI from list is preferred.
3 | WASI from list is excluded.

To ensure that the list of WASI values is maintained, bound protocols should issue a query with this OID before they issue a set request.

Indications are irrelevant for this OID.


OID_WW_CDPD_AREA_COLOR

The OID_WW_CDPD_AREA_COLOR OID requests the miniport driver to return the current area color code of the acquired channel. An area color code is an integer of type INT that identifies the Mobile Data Intermediate System to which the user's base station is connected.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) if the area color state changes. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.

Sets are irrelevant for this OID.


OID_WW_CDPD_TX_POWER_LEVEL

The OID_WW_CDPD_TX_POWER_LEVEL OID requests the miniport driver to return the current transmit power charge as a normalized percentage of type UINT.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) according to the TriggerValue that was specified in the OID_WW_GEN_INDICATION_REQUEST.

Sets are irrelevant for this OID.


OID_WW_CDPD_EID

The OID_WW_CDPD_EID OID requests the miniport driver to return the unique identifier of the device associated with the subscriber to a network service.

This request uses a WW_CDPD_EID structure, defined as equivalent to the NDIS_VAR_DATA_DESC structure, which was defined previously. The buffer contains a network-ordered sequence of binary byte values.

Sets and indications are irrelevant for this OID.


OID_WW_CDPD_HEADER_COMPRESSION

The OID_WW_CDPD_HEADER_COMPRESSION OID requests the miniport driver either to return the header compression scheme that is currently in use or to set the value that is initially used in negotiating the header compression scheme.

In either case, one of the following designates the header compression scheme:

Value | Meaning
0 | No header compression.
1 | Always compress headers.
2 | Compress headers if the Mobile Data Intermediate System sends a compressed header.
-1 | Unknown. If this value is specified for a set, the miniport driver returns NDIS_STATUS_INVALID_DATA.

Indications are irrelevant for this OID.


OID_WW_CDPD_DATA_COMPRESSION

The OID_WW_CDPD_DATA_COMPRESSION OID requests the miniport driver either to return the data compression scheme that is currently in use or to set the value that is initially used in negotiating the compression scheme.

In either case, one of the following designates the data compression scheme:

Value | Meaning
0 | Data compression disabled.
1 | Data compression enabled.
-1 | Unknown. If this value is specified for a set, the miniport driver returns NDIS_STATUS_INVALID_DATA.

Indications are irrelevant for this OID.


OID_WW_CDPD_CHANNEL_SELECT

As a query, the OID_WW_CDPD_CHANNEL_SELECT OID requests the miniport driver to return the current channel and remaining time from a previously issued set request. The miniport driver should return NDIS_STATUS_INVALID_DATA if a set request has not yet been issued.

As a set, this OID requests the miniport driver to set the given channel number and time, in seconds, that the subscriber unit should lock onto.

This OID can be used specifically for testing and analyzing channel characteristics. It is not intended to be used during normal operation of the subscriber unit. The subscriber unit should attempt typical registration on the given channel.

In either case, this request uses a WW_CDPD_CHANNEL_SELECT structure, defined as follows:

typedef  struct _WW_CDPD_CHANNEL_SELECT {
  UINT  ChannelID;
  UINT  fixedDuration;
} WW_CDPD_CHANNEL_SELECT;

The members of this structure contain the following information:

ChannelID
Specifies the channel number.
fixedDuration
Specifies the connection time, in seconds.

Indications are irrelevant for this OID.


OID_WW_CDPD_CHANNEL_STATE

The OID_WW_CDPD_CHANNEL_STATE OID requests the miniport driver to return the current state of the subscriber unit's radio channel activity as one of the following:

CDPDChannelNotAvail
CDPDChannelScanning
CDPDChannelInitAcquired
CDPDChannelAcquired
CDPDChannelSleeping
CDPDChannelWaking
CDPDChannelCSDialing
CDPDChannelCSRedial
CDPDChannelCSAnswering
CDPDChannelCSConnected
CDPDChannelCSSuspended

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) if the channel state changes. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.

Sets are irrelevant for this OID.


OID_WW_CDPD_NEI

The OID_WW_CDPD_NEI OID requests the miniport driver to return the current list of NEI addresses or to set a maximum of ten IP or CLNP addresses used for station, multicast, or broadcast operation.

In either case, this request uses a WW_CDPD_NEI structure, defined as follows:

typedef struct _WW_CDPD_NEI {
  UINT  uNeiIndex;
  WW_CDPD_NEI_FORMAT  NeiFormat;
  WW_CDPD_NEI_TYPE  NeiType;
  UINT  NeiGmid;
  NDIS_VAR_DATA_DESC  NeiAddress;
} WW_CDPD_NEI;

The members of this structure contain the following information:

uNeiIndex
Specifies the index of this NEI, as a value from zero to nine.
NeiFormat
Specifies the format of this NEI as one of the following:

CDPDNeiIPv4

CDPDNeiCLNP

CDPDNeiIPv6

NeiType
Specifies the address type of this NEI as one of the following:

CDPDNeiIndividual

CDPDNeiMulticast

CDPDNeiBroadcast

NeiGmid
Specifies the group member identifier if NeiType is CDPDNeiMulticast. Otherwise, this member is meaningless.
NeiAddress
Specifies the NEI address in conformance with the preceding members.

The NeiAddress member is of type NDIS_VAR_DATA_DESC, which was defined previously. The buffer contains a network-ordered sequence of binary byte values.

Indications are irrelevant for this OID.


OID_WW_CDPD_NEI_STATE

As a query, the OID_WW_CDPD_NEI_STATE OID requests the miniport driver to return the current registration state and sub-state of a given NEI. The specific NEI is designated by its index within the NEI array.

As a set, this OID requests the miniport driver to set the registration state for the given NEI.

In either case, this request uses a WW_CDPD_NEI_REG_STATE structure, defined as follows:

typedef struct _WW_CDPD_NEI_REG_STATE {
  UINT  uNeiIndex;
  WW_CDPD_NEI_STATE  NeiState;
  WW_CDPD_NEI_SUB_STATE  NeiSubState;
} WW_CDPD_NEI_REG_STATE;

The members of this structure contain the following information:

uNeiIndex
Specifies a value in the range zero through nine that is the index to the NEI within the current array of NEIs.
NeiState
Specifies the registration state of the given NEI as one of the following:

CDPDRegistered

CDPDDeregistered

CDPDUnknown

A miniport driver-set operation should return NDIS_STATUS_INVALID_DATA if this member is set to CDPDUnknown.

NeiSubState
Specifies the current registration sub-state of the currently unregistered NEI as one of the following.
CDPDPending
Specifies registration of the NEI is still pending.
CDPDNoReason
Specifies registration of the NEI was denied categorically.
CDPDMDISNotCapable
Specifies MD-IS was incapable of handling M-ES and denied registration of the NEI.
CDPDNEINotAuthorized
Specifies registration of the NEI was denied due to lack of any authorization.
CDPDInsufficientAuth
Specifies registration of the NEI was denied because M-ES gave insufficient authentication credentials.
CDPDUnsupportedAuth
Specifies registration of the NEI was denied because M-ES gave unsupported authentication credentials.
CDPDUsageExceeded
Specifies registration of the NEI was denied because usage limitations were exceeded.
CDPDDeniedThisNetwork
Specifies registration of the NEI on this network was denied. If NEI cannot be registered on this network, the NEI can possibly be registered with another service provider network.

The value of NeiSubState is irrelevant for set operations. Only miniport driver-query operations set values in NeiSubState.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) if the NeiState value changes for the specified NEI. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.


OID_WW_CDPD_SERVICE_PROVIDER_IDENTIFIER

The OID_WW_CDPD_SERVICE_PROVIDER_IDENTIFIER OID requests the miniport driver either to return or to set up an array of a maximum of ten Service Provider Identifiers (SPIs) and the current operating mode with respect to this array. This OID can specify for the device to be configured to ignore SPI during channel acquisition, to not acquire a channel if the SPI of the channel is not in the current list, or to prefer a channel that has an SPI in the list.

This request uses an WW_CDPD_SERVICE_PROVIDER_ID structure, defined as follows:

typedef  struct   _WW_CDPD_SERVICE_PROVIDER_ID {
  UINT  SPI[10];
  INT  OperatingMode;
} WW_CDPD_SERVICE_PROVIDER_ID;

The members of this structure contain the following information:

SPI
Specifies an array of ten UINT values, each a service provider identifier.
OperatingMode
Specifies how the driver handles SPI as one of the following values:
Value | Meaning
0 | Ignore SPI.
1 | SPI from list is required.
2 | SPI from list is preferred.
3 | SPI from list is excluded.

To ensure that the list of SPI values is maintained, bound protocols should issue a query with this OID before they issue a set request.

Indications are irrelevant for this OID.


OID_WW_CDPD_SLEEP_MODE

As a query, the OID_WW_CDPD_SLEEP_MODE OID requests the miniport driver to return the sleep-idle timer interval for its NIC. The value returned is of type INT. Zero indicates CDPD sleep is disabled.

As a set, this OID requests the miniport driver to negotiate with the network, using the given sleep-idle timer interval for its NIC.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) if the sleep mode changes. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.


OID_WW_CDPD_CIRCUIT_SWITCHED

The OID_WW_CDPD_CIRCUIT_SWITCHED OID is obsolete but is still included for informational and historical purposes and to support existing NDIS drivers. Use one of the following OIDs instead:

  • OID_WW_CDPD_CS_SERVICE_PREFERENCE
  • OID_WW_CDPD_CS_SERVICE_STATUS
  • OID_WW_CDPD_CS_INFO
  • OID_WW_CDPD_CS_SUSPEND
  • OID_WW_CDPD_CS_DEFAULT_DIAL_CODE
  • OID_WW_CDPD_CS_CALLBACK
  • OID_WW_CDPD_CS_SID_LIST
  • OID_WW_CDPD_CS_CONFIGURATION

This OID can be used to query or to set the following device capabilities:

  • Circuit-switched CDPD service connection and channel information
  • Default CDPD service preference and parameters for use in circuit-switched CDPD mode
  • Control of circuit-switched CDPD operation

As a query, this OID requests the miniport driver to return the current state of the circuit-switched CDPD status and settings.

As a set, this OID requests the miniport driver to configure the circuit-switched CDPD parameters.

In either case, this request uses a WW_CDPD_CIRCUIT_SWITCHED structure, defined as follows:

typedef  struct _WW_CDPD_CIRCUIT_SWITCHED {
  INT  service_preference;
  INT  service_status;
  INT  connect_rate;
  NDIS_VAR_DATA_DESC  dial_code[20];
  UINT  sid;
  INT  a_b_side_selection;
  INT  AMPS_channel;
  UINT  action;
  NDIS_VAR_DATA_DESC  default_dial[20];
  NDIS_VAR_DATA_DESC  call_back[20];
  UINT  sid_list[10];
  UINT  inactivity_timer;
  UINT  receive_timer;
  UINT  conn_resp_timer;
  UINT  reconn_resp_timer;
  UINT  disconn_timer;
  UINT  NEI_reg_timer;
  UINT  reconn_retry_timer;
  UINT  link_reset_timer;
  UINT  link_reset_ack_timer;
  UINT  n401_retry_limit;
  UINT  n402_retry_limit;
  UINT  n404_retry_limit;
  UINT  n405_retry_limit;
} WW_CDPD_CIRCUIT_SWITCHED;

The members of this structure contain the following information:

service_preference
Specifies one of the following:
Value | Meaning
0 | Always use packet switched CDPD.
1 | Always use CS CDPD via AMPS.
2 | Always use CS CDPD via PSTN.
3 | Use circuit switched via AMPS only when packet switched is unavailable.
4 | Use packet switched only when circuit switched via AMPS is unavailable.
5 or 6 | Use device-manufacturer-defined service preference.
-1 | Unknown. If this value is specified for a set, the miniport driver returns NDIS_STATUS_INVALID_DATA.

service_status
Specifies one of the following:
Value | Meaning
0 | Packet-switched CDPD.
1 | Circuit-switched CDPD via AMPS.
2 | Circuit-switched CDPD via PSTN.
-1 | Unknown. If this value is specified for a set, the miniport driver returns NDIS_STATUS_INVALID_DATA.

connect_rate
Specifies the circuit-switched connection rate in bits per second. Zero designates no active connection, and -1 indicates the rate is unknown. If -1 is specified for a set, the miniport driver returns NDIS_STATUS_INVALID_DATA.
dial_code
Specifies the dial code last used to dial.
sid
Specifies the current AMPS system ID.
a_b_side_selection
Specifies one of the following:
Value | Meaning
0 | No AMPS service.
1 | AMPS "A" side channels selected.
2 | AMPS "B" side channels selected.
-1 | Unknown. If this value is specified for a set, the miniport driver returns NDIS_STATUS_INVALID_DATA.

AMPS_channel
Specifies the AMPS channel in use as a value in the range 1 to 1023. Zero indicates no AMPS service, and -1 indicates the channel or state of AMPS service is unknown. If -1 is specified for a set, the miniport driver returns NDIS_STATUS_INVALID_DATA.
action
Specifies one of the following:
Value | Meaning
0 | No action
1 | Suspend (hang up)
2 | Dial

default_dial
Specifies the default dial code for circuit-switched CDPD service, encoded as defined for CDPD.
call_back
Specifies the number to be used by the circuit-switched CDPD network to call back the mobile unit. This number is encoded per CDPD.
sid_list
Specifies a set of up to ten 16-bit preferred AMPS system IDs for circuit-switched CDPD.
inactivity_timer
Specifies the time-out limit, in seconds, for inactivity before dropping the call.
receive_timer
Specifies the time-out limit, in seconds, to wait for a receive.
conn_resp_timer
Specifies the time-out limit, in seconds, to wait for a connection response.
reconn_resp_timer
Specifies the time-out limit, in seconds, to wait for a reconnection response.
disconn_timer
Specifies the time-out limit, in seconds, to wait for a disconnection.
NEI_reg_timer
Specifies the time-out limit, in seconds, to wait for an NEI registration.
reconn_retry_timer
Specifies the time-out limit, in seconds, for retrying a reconnection.
link_reset_timer
Specifies the time-out limit, in seconds, for resetting a link.
link_reset_ack_timer
Specifies the time-out limit, in seconds, for receiving a link-reset acknowledgment.
n401_retry_limit
As defined for circuit-switched CSPD.
n402_retry_limit
As defined for circuit-switched CSPD.
n404_retry_limit
As defined for circuit-switched CSPD.
n405_retry_limit
As defined for circuit-switched CSPD.

For all xxx_timer members in the preceding structure, anything in the range from 1 to 65535 seconds is theoretically valid, but see the CS-CDPD documentation for specifics.

The dial_code, default_dial, and call_back members are of type NDIS_VAR_DATA_DESC, which was defined previously. The values are NUL-terminated ASCII strings.

Indications are irrelevant for this OID.


OID_WW_CDPD_TEI

The OID_WW_CDPD_TEI OID requests the miniport driver to return the temporary ID assigned by the network to a data-link connection with a particular M-ES. The returned value is of type ULONG, and is used for diagnostic purposes.

Sets and indications are irrelevant for this OID.


OID_WW_CDPD_RSSI

The OID_WW_CDPD_RSSI OID requests the miniport driver to return the current Received Signal Strength Indication (RSSI) in decibels (dBm). The returned value is of type UINT.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) according to the TriggerValue that was specified in the OID_WW_GEN_INDICATION_REQUEST.

Sets are irrelevant for this OID.


OID_WW_CDPD_CS_SERVICE_PREFERENCE

As a query, the OID_WW_CDPD_CS_SERVICE_PREFERENCE OID requests the miniport driver to return the current state of the CDPD circuit-switched service preference value.

As a set, this OID request the miniport driver to set the current state of the CDPD circuit-switched service preference value. Note that a change in this value can affect the currently established cellular connection if any. The setting value is returned as an integer.

In either case, one of the following designates the service preference value:

Value | Meaning
0 | Always use packet-switched CDPD.
1 | Always use CS-CDPD via AMPS.
2 | Always use CS-CDPD via PSTN.
3 | Use CS-CDPD via AMPS only if packet-switched CDPD is not available.
4 | Use packet-switched CDPD only if CS-CDPD via AMPS is not available.
5 | This service-preference value is defined by the device manufacture.
6 | This service-preference value is defined by the device manufacture.
-1 | Unknown. If this value is specified for a set, the miniport driver returns NDIS_STATUS_INVALID_DATA.

All other values are reserved.

Indications are irrelevant for this OID.


OID_WW_CDPD_CS_SERVICE_STATUS

The OID_WW_CDPD_CS_SERVICE_STATUS OID requests the miniport driver to return which CDPD service is currently in use. The value is returned as an integer.

One of the following values designates which service is currently in use:

Value | Meaning
0 | Packet-switched CDPD
1 | CS-CDPD via AMPS
2 | CS-CDPD via PSTN
-1 | Unknown

All other values are reserved.

Sets and indications are irrelevant for this OID.


OID_WW_CDPD_CS_INFO

The OID_WW_CDPD_CS_INFO OID requests the miniport driver to return current information about circuit-switched CDPD connections.

This request uses a WW_CDPD_CS_INFO structure, defined as follows:

typedef struct _WW_CDPD_CS_INFO {
  INT  ConnectRate;
  NDIS_VAR_DATA_DESC  DialCode;
  UINT  SID;
  INT  ABSideSelection;
  INT  AMPSChannel;
} WW_CDPD_CS_INFO;

The members of this structure contain the following information:

ConnectRate
Specifies circuit-switched bit rate. A value of 0 specifies no active connection. A value of –1 specifies an unknown rate. All other values specify the current rate represented as bits per second.
DialCode
Describes a buffer that contains the last dial code used to establish a CS-CDPD connection.
SID
Specifies the current AMPS system identifier.
ABSideSelection
Specifies the side channel that is currently selected. The following lists valid values.
Value | Meaning
0 | No AMPS service
1 | AMPS "A" side channel selected
2 | AMPS "B" side channel selected
-1 | Unknown

AMPSChannel
Specifies the AMPS-channel number that is currently in use. A value of 0 specifies no AMPS service. A value of 1 through 1023 specifies the current AMPS channel in use. A value of –1 specifies the channel number is unknown. All other values are reserved.

The miniport driver should return a value of NDIS_STATUS_NOT_SUPPORTED if the current mode of operation is via packet-switched CDPD. For more information, see OID_WW_CDPD_CS_SERVICE_STATUS.

Sets and indications are irrelevant for this OID.


OID_WW_CDPD_CS_SUSPEND

The OID_WW_CDPD_CS_SUSPEND OID requests that the miniport driver instruct the NIC to suspend (hang up) the current CS-CDPD connection. The value is represented as an unsigned integer.

The action requested is designated by one of the following values:

Value | Meaning
0 | No operation
1 | Suspend (hang up) current connection

Queries and indications are irrelevant for this OID.


OID_WW_CDPD_CS_DEFAULT_DIAL_CODE

As a query, the OID_WW_CDPD_CS_DEFAULT_DIAL_CODE OID requests the miniport driver to return the current default circuit-switched CDPD dial code for establishing connections.

As a set, this OID requests the miniport driver to set the current default circuit-switch CDPD dial code for establishing connections.

In either case, this request uses a WW_CDPD_CS_DEFAULT_DIAL_CODE structure, defined as equivalent to the NDIS_VAR_DATA_DESC structure. The buffer contains the default dial code for circuit-switched CDPD service. This dial code is encoded per circuit-switched CDPD implementation guidelines. The maximum length of the dial code is 20 bytes.

Indications are irrelevant for this OID.


OID_WW_CDPD_CS_CALLBACK

As a query, the OID_WW_CDPD_CS_CALLBACK OID requests the miniport driver to return the current configuration information of the callback feature for circuit-switched CDPD.

As a set, this OID requests the miniport driver to set the current configuration of the callback feature for circuit-switched CDPD to the stated values.

In either case, this request uses a WW_CDPD_CS_CALLBACK structure, defined as follows:

typedef struct _WW_CDPD_CS_CALLBACK {
  UINT  Enabled;
  NDIS_VAR_DATA_DESC  Number;
} WW_CDPD_CS_CALLBACK;

The members of this structure contain the following information:

Enabled
Specifies one of the following:
Value | Meaning
0 | Callback capability is disabled.
1 | Callback capability is enabled.
-1 | Unknown. If this value is specified for a set, the miniport driver returns NDIS_STATUS_INVALID_DATA.

Number
Describes a buffer that contains the dial code that the circuit-switched CDPD network uses to call back the NIC. This dial code is encoded per circuit-switched CDPD implementation guidelines The maximum length of the dial code is 20 bytes.

The Number member is of type NDIS_VAR_DATA_DESC, which was defined previously. The buffer contains a network-ordered sequence of binary byte values.

Indications are irrelevant for this OID.


OID_WW_CDPD_CS_SID_LIST

As a query, the OID_WW_CDPD_CS_SID_LIST OID requests the miniport driver to return an array of preferred AMPS system identifier values.

As a set, this OID requests the miniport driver to set the list of preferred AMPS system identifier values. The NIC uses this list of values to select the AMPS service for circuit-switched CDPD.

In either case, this request uses a WW_CDPD_CS_SID_LIST structure, defined as follows:

typedef struct _WW_CDPD_CS_SID_LIST {
  UINT  AMPSystemId[10];
} WW_CDPD_CS_SID_LIST;

The member of this structure contains the following information:

AMPSystemId
Specifies an array of UINT values, each an AMPS-system identifier. This array has a maximum of 10 elements.

Indications are irrelevant for this OID.


OID_WW_CDPD_CS_CONFIGURATION

As a query, the OID_WW_CDPD_CS_CONFIGURATION OID requests the miniport driver to return the current values of the specified configuration variables for circuit-switched CDPD.

As a set, this OID requests the miniport driver to modify the specified configuration variables for circuit-switched CDPD to new values.

In either case, this request uses a WW_CDPD_CS_CONFIGURATION structure, defined as follows:

typedef struct _WW_CDPD_CS_CONFIGURATION {
  UINT  InactivityTimer;
  UINT  ReceiveTimer;
  UINT  ConnResTimer;
  UINT  ReconnRespTimer;
  UINT  DisconnTimer;
  UINT  NEIRegTimer;
  UINT  ReconnRetryTimer;
  UINT  LinkResetTimer;
  UINT  LinkResetAckTimer;
  UINT  n401RetryLimit;
  UINT  n402RetryLimit;
  UINT  n404RetryLimit;
  UINT  n405RetryLimit;
} WW_CDPD_CS_CONFIGURATION;

The members of this structure contain the following information:

InactivityTimer
Specifies the number of seconds to wait after last the user payload has been sent or received before dropping the circuit-switched CDPD connection. Value is within the range of 0 and 65535. A value of zero specifies no time-out limit. That is, specifies infinity.
ReceiveTimer
Specifies the time-out limit, in seconds, to wait for a receive.
ConnResTimer
Specifies the time-out limit, in seconds, to wait for a connection response.
ReconnRespTimer
Specifies the time-out limit, in seconds, to wait for a reconnection response.
DisconnTimer
Specifies the time-out limit, in seconds, to wait for a disconnection.
NEIRegTimer
Specifies the time-out limit, in seconds, to wait for an NEI registration.
ReconnRetryTimer
Specifies the time-out limit, in seconds, for retrying a reconnection.
LinkResetTimer
Specifies the time-out limit, in seconds, for resetting a link.
LinkResetAckTimer
Specifies the time-out limit, in seconds, for receiving a link-reset acknowledgment.
n401RetryLimit
As defined for circuit-switched CS-CDPD implementation guidelines.
n402RetryLimit
As defined for circuit-switched CS-CDPD implementation guidelines.
n404RetryLimit
As defined for circuit-switched CS-CDPD implementation guidelines.
n405RetryLimit
As defined for circuit-switched CS-CDPD implementation guidelines.

To ensure that only particular variables are changed, protocols must first submit a query request to record the current state, next modify particular variables as necessary, and then submit a set request.

For all Xxx Timer members in the preceding structure, anything in the range from 1 to 65535 seconds is theoretically valid, but see the CS-CDPD documentation for specifics.

Indications are irrelevant for this OID.


Pinpoint Wireless OIDs

The Pinpoint network and its associated technology are no longer available or in service. Therefore, Pinpoint-specific wireless OIDs are obsolete and should not be used. Definitions for these OIDs are still included for informational and historical purposes.

The following chart summarizes Pinpoint-specific wireless OIDs.

Q | S | Indication | Name
M |  |  | OID_WW_PIN_LOC_AUTHORIZE
M |  |  | OID_WW_PIN_LAST_LOCATION
M |  |  | OID_WW_PIN_LOC_FIX


OID_WW_PIN_LOC_AUTHORIZE

The OID_WW_PIN_LOC_AUTHORIZE OID is obsolete and should not be used; it is included for informational and historical purposes.

This OID requests the miniport driver to return information about whether the device has been authorized to perform location fixes on itself as one of the following:

Value | Meaning
0 | Unauthorized
1 | Authorized
-1 | Unknown

Sets and indications are irrelevant for this OID.


OID_WW_PIN_LAST_LOCATION

The OID_WW_PIN_LAST_LOCATION OID is obsolete and should not be used; it is included for informational and historical purposes.

This OID requests the miniport driver to return information about the last known location of the mobile radio or NULL if the location is unknown. This request does not initiate a location fix by the device.

This request uses a WW_PIN_LOCATION structure, defined as follows:

typedef  struct   _WW_PIN_LOCATION{
  INT  Latitude;
  INT  Longitude;
  INT  Altitude;
  INT  FixTime;
  INT  NetTime;
  INT  LocQuality;
  INT  LatReg;
  INT  LongReg;
  INT  GMTOffset;
} WW_PIN_LOCATION;

The members of this structure contain the following information:

Latitude
Specifies the latitude in hundredths of a second.
Longitude
Specifies the longitude in hundredths of a second.
Altitude
Specifies the altitude in feet.
FixTime
Specifies the local time of the last location fix since midnight of the current day, in tenths of a second.
NetTime
Specifies the local network time since midnight of the current day, in tenths of a second.
LocQuality
Specifies the location quality as a value from 0 to 100, with 100 indicating the highest quality.
LatReg
Specifies the latitude registration offset, in hundredths of a second.
LongReg
Specifies the longitude registration offset, in hundredths of a second.
GMTOffset
Specifies the offset, in minutes, of the local time zone from GMT.

Sets and indications are irrelevant for this OID.


OID_WW_PIN_LOC_FIX

The OID_WW_PIN_LOC_FIX OID is obsolete and should not be used; it is included for informational and historical purposes.

This OID requests the miniport driver to initiate a location fix and to return the information or NULL if it cannot be determined.

This request uses a WW_PIN_LOCATION structure. See OID_WW_PIN_LAST_LOCATION for details.

Sets and indications are irrelevant for this OID.


Mobitex Wireless OIDs

The following chart summarizes Mobitex-specific wireless OIDs.

Q | S | Indication | Name
 | M | M | OID_WW_MBX_SUBADDR
M |  | M | OID_WW_MBX_FLEXLIST
M |  | M | OID_WW_MBX_GROUPLIST
M |  | M | OID_WW_MBX_TRAFFIC_AREA
M |  | M | OID_WW_MBX_LIVE_DIE
 | M |  | OID_WW_MBX_TEMP_DEFAULTLIST


OID_WW_MBX_SUBADDR

The OID_WW_MBX_SUBADDR OID requests the miniport driver to log in or log out a personal subscription address (MAN).

This request uses a WW_MBX_PMAN structure, defined as follows:

typedef  struct   _WW_MBX_PMAN {
  BOOLEAN  ACTION;
  UINT  MAN;
  UCHAR  PASSWORD[8];
} WW_MBX_PMAN;

The members of this structure contain the following information:

ACTION
Specifies 0 if the driver should log in the given PMAN, or 1 if it should log out the given PMAN.
MAN
Specifies the personal network address of the subscriber to be logged in or out.
PASSWORD
Specifies a password of up to eight characters for a log-in or NULL for a log-out operation.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) when a personal MAN is logged in or out on the network. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST. InitialValue should remain NULL. When making an indication, all passwords should be zeroed; they are ignored by all bound protocols.

Queries are irrelevant for this OID.


OID_WW_MBX_FLEXLIST

The OID_WW_MBX_FLEXLIST OID requests the miniport driver to return the current flexlist, which is the set of personal MANs currently logged on to the local wireless device.

This request uses a WW_MBX_FLEXLIST structure, defined as follows:

typedef struct _WW_MBX_FLEXLIST;
  INT  count;
  UINT  MAN[7];
} WW_MBX_FLEXLIST;

The members of this structure contain the following information:

count
Specifies the number of MAN entries in the flexlist. Specifies zero if the flexlist is empty with all elements of MAN set to zero, as well. Otherwise, count is set to -1 if the number is unknown.
MAN
Specifies up to seven personal MAN addresses.

During radio modem startup, this information is sent within an MPAK by the radio modem to the PC. The form of the WW_MBX_FLEXLIST structure mirrors the format of the information within the MPAK.

The miniport driver must track all subsequent log-in and log-out requests for this set of MANs and retain this list so that protocols can query the current list as they bind to the miniport driver.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) when the flexlist changes. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.

Sets are irrelevant for this OID.


OID_WW_MBX_GROUPLIST

The OID_WW_MBX_GROUPLIST OID requests the miniport driver to return the current group list, the set of group MANs to which the local wireless device currently belongs.

This request uses a WW_MBX_GROUPLIST structure, defined as follows:

typedef struct _WW_MBX_GROUPLIST {
  INT  count;
  UINT  MAN[15];
} WW_MBX_GROUPLIST;

The members of this structure contain the following information:

count
Specifies the number of MAN entries in the current group list. Specifies zero if the group list is empty with all elements of MAN set to zero, as well. Otherwise, count is set to -1 if the number is unknown.
MAN
Specifies up to 15 MAN addresses.

This information is sent within an MPAK by the radio modem to the PC whenever the group list changes. The form of the WW_MBX_GROUPLIST structure mirrors the format of the information within the MPAK. The miniport driver maintains the information in this list so that protocols can query the current list as they bind to the miniport driver.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) when the group list changes. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.

Sets are irrelevant for this OID.


OID_WW_MBX_TRAFFIC_AREA

The OID_WW_MBX_TRAFFIC_AREA OID requests the miniport driver to return information about the most recently received traffic-area frame as one of the following:

Value | Meaning
in_traffic_area | Mobile unit has entered a subscribed traffic area.
in _auth_traffic_area | Mobile unit is outside traffic area but is authorized.
unauth_traffic_area | Mobile unit is outside traffic area and is unauthorized.
unknown_traffic_area | The driver has no information about the current traffic area.

The radio modem sends a traffic area frame to the PC whenever the radio changes traffic area. The miniport driver should save the current value indicated in such a frame to support this OID.

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) when the traffic area changes. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.

Sets are irrelevant for this OID.


OID_WW_MBX_LIVE_DIE

The OID_WW_MBX_LIVE_DIE OID requests the miniport driver to return the current live/die state, denoting whether the wireless device is permitted to send data on the network, as follows:

Value |
0 | DIE most recently received, denying device sends
1 | LIVE most recently received, permitting device sends
-1 | LIVE/DIE state is unknown

If any bound protocol has enabled indications with OID_WW_GEN_INDICATION_REQUEST, the miniport driver must call NdisMIndicateStatus to notify such protocol(s) when the live/die state changes. It can ignore the TriggerValue member that was specified in the OID_WW_GEN_INDICATION_REQUEST.

Sets are irrelevant for this OID.


OID_WW_MBX_TEMP_DEFAULTLIST

The OID_WW_MBX_TEMP_DEFAULTLIST OID requests the miniport driver to use the specified temporary default list of radio frequencies for the modem.

This request uses a WW_MBX_TEMPDEFAULTLIST structure, defined as follows:

typedef  struct   _WW_MBX_TEMPDEFAULTLIST {
  UINT  Length;
  WW_MBX_CHANNEL_PAIR  ChannelPair[];
} WW_MBX_TEMPDEFAULTLIST;

The members of this structure contain the following information:

Length
Specifies the number of elements in the ChannelPair array.
ChannelPair
Specifies an array of elements defined as follows:
typedef  struct  _WW_MBX_CHANNEL_PAIR {
    UINT Mobile_Tx; // transmit frequency
    UINT Mobile_Rx; // receive frequency
} WW_MBX_CHANNEL_PAIR;

Queries and indications are irrelevant for this OID.


Connection-Oriented Objects

This section describes the OIDs for connection-oriented objects, both operational and statistics types.

The connection-oriented OIDs are defined in ntddndis.h. When building a driver that supports these OIDs, include ntddndis.h.

These OIDs are described in the following topics:

General Operational Characteristics for Connection-Oriented Miniport Drivers

General Statistics for Connection-Oriented Miniport Drivers

OIDs for Connection-Oriented Call Managers and Clients

TAPI Extensions for Connection-Oriented NDIS


General Operational Characteristics for Connection-Oriented Miniport Drivers

The following chart summarizes the OIDs used to get or set the general operational characteristics of connection-oriented miniport drivers and/or their NICs. Note that a connection-oriented miniport driver handles such requests in its MiniportCoRequest function.

Length | Q | S | Name
Arr(4) | M |  | OID_GEN_CO_SUPPORTED_LIST List of supported OIDs
4 | M |  | OID_GEN_CO_HARDWARE_STATUS Hardware status
Arr(4) | M |  | OID_GEN_CO_MEDIA_SUPPORTED Media types supported (encoded)
Arr(4) | M |  | OID_GEN_CO_MEDIA_IN_USE Media types in use (encoded)
4 | M |  | OID_GEN_CO_LINK_SPEED Transmit and receive link speeds in units of 100 bps
4 | M |  | OID_GEN_CO_VENDOR_ID Vendor NIC code
Var. | M |  | OID_GEN_CO_VENDOR_DESCRIPTION Vendor network card description
4 | M |  | OID_GEN_CO_VENDOR_DRIVER_VERSION Vendor-assigned version number of the driver
2 | M |  | OID_GEN_CO_DRIVER_VERSION NDIS version number used by the driver
4 |  | M | OID_GEN_CO_PROTOCOL_OPTIONS Optional protocol flags (encoded)
4 | M |  | OID_GEN_CO_MAC_OPTIONS This is reserved.
4 | M |  | OID_GEN_CO_MEDIA_CONNECT_STATUS Whether the NIC is connected to the network
4 | M |  | OID_GEN_CO_MINIMUM_LINK_SPEED The minimum speed supported by the link.
Arr | O |  | OID_GEN_CO_SUPPORTED_GUIDS The custom GUIDs (Globally Unique Identifiers) supported by the miniport driver
8 | O |  | OID_GEN_CO_GET_TIME_CAPS The miniport driver's capabilities for reporting a NIC's local time
8 | O |  | OID_GEN_CO_GET_NETCARD_TIME A NIC's local time

The following describes each of the OID_XXX listed in the preceding chart more fully.


OID_GEN_CO_SUPPORTED_LIST

The OID_GEN_CO_SUPPORTED_LIST OID specifies an array of OIDs for objects that the underlying driver or its NIC supports. Objects include general, media-specific, and implementation-specific objects.

The underlying driver should order the OID list it returns in increasing numeric order. NDIS forwards a subset of the returned list to protocols that make this query. That is, NDIS filters any supported statistics OIDs out of the list since protocols never make statistics queries subsequently.


OID_GEN_CO_HARDWARE_STATUS

The OID_GEN_CO_HARDWARE_STATUS OID specifies the current hardware status of the underlying NIC, as one of the following NDIS_HARDWARE_STATUS-type values:

NdisHardwareStatusReady
Available and capable of sending and receiving data over the wire.
NdisHardwareStatusInitializing
Initializing.
NdisHardwareStatusReset
Resetting.
NdisHardwareStatusClosing
Closing.
NdisHardwareStatusNotReady
Not ready.


OID_GEN_CO_MEDIA_SUPPORTED

A complete list of the media types the NIC supports, as a proper subset of the following system-defined values:

NdisMedium802_3
Ethernet (802.3).
NdisMedium802_5
Token Ring (802.5).
NdisMediumFddi
FDDI.
NdisMediumWan
WAN.
NdisMediumLocalTalk
LocalTalk.
NdisMediumDix
DEC/Intel/Xerox (DIX) Ethernet.
NdisMediumArcnetRaw
ARCNET (raw).
NdisMediumArcnet878_2
ARCNET (878.2).
NdisMediumWirelessWan
Various types of NdisWireless Xxx media.
NdisMediumAtm
ATM.
NdisMediumIrda
Reserved for future use on Windows® 2000 and later platforms.

A LAN-emulation driver for ATM networks declares its medium as NdisMedium802_3 or NdisMedium802_5, rather than NdisMediumAtm. Such a driver emulates Ethernet or Token Ring to higher-level NDIS drivers, complies with the ATM Forum's LANE, and provides UNI signaling support.

A wireless-WAN NIC driver must report its medium type as NdisMediumWirelessWan. However, such a miniport driver also must provide NdisWWDIXEthernetFrames header format to any bound protocol that selects this format, and the miniport driver can provide its NIC's native header format as well. To support existing LAN-based protocols, the driver writer can provide an NDIS intermediate driver to "translate" a wireless NIC's native header formats and medium-specific information into a form understood by existing protocols.

If the underlying miniport driver returns NULL for this query or if an experimental media type is used, the driver must indicate receives with NdisMCoIndicateReceivePacket.


OID_GEN_CO_MEDIA_IN_USE

A complete list of the media types the NIC is currently supporting, defined as some, none (also called "the NULL filter"), or all of the following:

NdisMedium802_3
Ethernet (802.3).
NdisMedium802_5
Token Ring (802.5).
NdisMediumFddi
FDDI.
NdisMediumWan
WAN.
NdisMediumLocalTalk
LocalTalk.
NdisMediumDix
DIX.
NdisMediumArcnetRaw
ARCNET (raw).
NdisMediumArcnet878_2
ARCNET (878.2).
NdisMediumWirelessWan
Various types of NdisWireless Xxx media.
NdisMediumAtm
ATM.

If the underlying miniport driver returns NULL for this query or if an experimental media type is used, the driver must indicate receives with NdisMCoIndicateReceivePacket.


OID_GEN_CO_LINK_SPEED

The OID_GEN_CO_LINK_SPEED OID requests the miniport driver to return its current transmit and receive speeds formatted as an NDIS_CO_LINK_SPEED structure, which is defined as follows:

typedef struct _NDIS_CO_LINK_SPEED {
  ULONG  Outbound;
  ULONG  Inbound;
} NDIS_CO_LINK_SPEED, *PNDIS_CO_LINK_SPEED;

The members of this structure contain the following information:

Outbound
The current transmit speed of the NIC. The unit of measurement is 100 bps, so a value of 100,000 represents a hardware bit rate of 10 Mbps.
Inbound
The current receive speed of the NIC. The unit of measurement is 100 bps, so a value of 100,000 represents a hardware bit rate of 10 Mbps.


OID_GEN_CO_VENDOR_ID

A 3-byte IEEE-registered vendor code, followed by a single byte that the vendor assigns to identify a particular NIC.

The IEEE code uniquely identifies the vendor and is the same as the three bytes appearing at the beginning of the NIC hardware address.

Vendors without an IEEE-registered code should use the value 0xFFFFFF.


OID_GEN_CO_VENDOR_DESCRIPTION

Pointer to a null-terminated, counted string describing the NIC.


OID_GEN_CO_VENDOR_DRIVER_VERSION

The vendor-assigned version number of the NIC driver.

The low-order half of the return value specifies the minor version, while the high-order half specifies the major version.


OID_GEN_CO_DRIVER_VERSION

The NDIS version in use by the NIC driver. The high byte is the major version number, and the low byte is the minor version number.


OID_GEN_CO_PROTOCOL_OPTIONS

A bitmask that defines optional properties of the protocol driver. A protocol informs NDIS of its properties, which can optionally take advantage of them. If the protocol driver does not set its flags on a binding, NDIS assumes they are all clear.

The following flags are currently defined:

NDIS_PROT_OPTION_ESTIMATED_LENGTH
Indicates that packets can be indicated at the worst-case estimate of packet size, instead of an exact value, to this protocol.
NDIS_PROT_OPTION_NO_LOOPBACK
The protocol does not require loopback support on the binding.
NDIS_PROT_OPTION_NO_RSVD_ON_RCVPKT
The protocol does not use the ProtocolReserved section of indicated receive packets. This allows NDIS to indicate a receive packet to more than one protocol.


OID_GEN_CO_MAC_OPTIONS

The OID_GEN_CO_MAC_OPTIONS OID is reserved.


OID_GEN_CO_MEDIA_CONNECT_STATUS

The OID_GEN_CO_MEDIA_CONNECT_STATUS OID requests the miniport driver to return the connection status of the NIC on the network as one of the following system-defined values:

NdisMediaStateConnected
NdisMediaStateDisconnected

When a miniport driver senses that the network connection has been lost, it should call NdisMCoIndicateStatus with NDIS_STATUS_MEDIA_DISCONNECT. When the connection is restored, it should call NdisMCoIndicateStatus with NDIS_STATUS_MEDIA_CONNECT.


OID_GEN_CO_MINIMUM_LINK_SPEED

The OID_GEN_CO_MINIMUM_LINK_SPEED OID requests the miniport driver to return its minimum transmit and receive speeds formatted as an NDIS_CO_LINK_SPEED structure, which is defined as follows:

typedef struct _NDIS_CO_LINK_SPEED {
  ULONG  Outbound;
  ULONG  Inbound;
} NDIS_CO_LINK_SPEED, *PNDIS_CO_LINK_SPEED;

The members of this structure contain the following information:

Outbound
The minimum transmit speed of the NIC. The unit of measurement is 100 bps, so a value of 100,000 represents a hardware bit rate of 10 Mbps.
Inbound
The minimum receive speed of the NIC. The unit of measurement is 100 bps, so a value of 100,000 represents a hardware bit rate of 10 Mbps.


OID_GEN_CO_SUPPORTED_GUIDS

The OID_GEN_CO_SUPPORTED_GUIDS OID requests the miniport driver to return an array of structures of the type NDIS_GUID. Each structure in the array specifies the mapping of a custom GUID (globally unique identifier) to either a custom OID or to an NDIS_STATUS that the miniport driver sends through NdisMCoIndicateStatus.

The NDIS_GUID structure is defined as follows:

typedef struct _NDIS_GUID {
    GUID             Guid;
    union {
        NDIS_OID     Oid;
        NDIS_STATUS  Status;
    };
    ULONG            Size;
    ULONG            Flags;
} NDIS_GUID, *PNDIS_GUID;

The members of this structure contain the following information:

Guid
The custom GUID defined for the miniport driver.
Oid
The custom OID to which Guid maps.
Status
The NDIS_STATUS to which Guid maps.
Size
When the fNDIS_GUID_ARRAY flag is set, Size specifies the size in bytes of each data item in the array returned by the miniport driver. If the fNDIS_GUID_ANSI_STRING or fNDIS_GUID_NDIS_STRING flag is set, Size is set to -1. Otherwise, Size specifies the size in bytes of the data item that the GUID represents.
Flags
The following flags can be ORed together to indicate whether the GUID maps to an OID or to an NDIS_STATUS string and to indicate the type of data supplied for the GUID:
fNDIS_GUID_TO_OID
When set, indicates that the NDIS_GUID structure maps a GUID to an OID.
fNDIS_GUID_TO_STATUS
When set, indicates that the NDIS_GUID structure maps a GUID to an NDIS_STATUS string.
fNDIS_GUID_ANSI_STRING
When set, indicates that a zero-terminated ANSI string is supplied for the GUID.
fNDIS_GUID_UNICODE_STRING
When set, indicates that a UNICODE string is supplied for the GUID.
fNDIS_GUID_ARRAY
When set, indicates that an array of data items is supplied for the GUID. The specified Size indicates the length of each data item in the array.
fNDIS_GUID_ALLOW_READ
When set, indicates that all users are allowed to query this GUID.
fNDIS_GUID_ALLOW_WRITE
When set, indicates that all users are allowed to set this GUID.

Note By default, custom WMI GUIDs supplied by a miniport driver are only accessible to users with administrator privileges. A user with administrator privileges can always read or write to a custom GUID if the miniport driver supports the read or write operation for that GUID. Set the fNDIS_GUID_ALLOW_READ and fNDIS_GUID_ALLOW_WRITE flags to allow all users to access a custom GUID.

Note that all custom GUIDs registered by a miniport driver must set either fNDIS_GUID_TO_OID or fNDIS_GUID_TO_STATUS (never set both). All other flags may be combined by using the OR operator as applicable.

In the following example, an NDIS_GUID structure maps a GUID to OID_GEN_CO_RCV_PDUS_NO_BUFFER:

NDIS_GUID NdisGuid =  {{0x0a214809, 0xe35f, 0x11d0, 0x96, 0x92, 0x00,
                       0xc0, 0x4f, 0xc3, 0x35, 0x8c},
                       GUID_NDIS_GEN_CO_RCV_PDUS_NO_BUFFER,
                       OID_GEN_CO_RCV_PDUS_NO_BUFFER,
                       4,
                       fNDIS_GUID_TO_OID};

A GUID is an identifier used by Windows Management Instrumentation (WMI) to obtain or set information. NDIS intercepts a GUID sent by WMI to an NDIS driver, maps the GUID to an OID, and sends the OID to the driver. The driver returns the data item(s) to NDIS, which then returns the data to WMI.

NDIS also translates changes in NIC status into GUIDs recognized by WMI. When a miniport driver reports a change in NIC status with NdisMCoIndicateStatus, NDIS translates the NDIS_STATUS indicated by the miniport driver into a GUID that NDIS sends to WMI.

If a connection-oriented miniport driver supports customs GUIDs, it must support OID_GEN_CO_SUPPORTED_GUIDS, which returns to NDIS the mapping of custom GUIDs to custom OIDs or NDIS_STATUS strings. After querying the miniport driver with OID_GEN_CO_SUPPORTED_GUIDS, NDIS registers the miniport driver's custom GUIDs with WMI.


OID_GEN_CO_GET_TIME_CAPS

The OID_GEN_CO_GET_TIME_CAPS OID requests a miniport driver to return its capabilities for reporting a NIC's local time formatted as a GEN_GET_TIME_CAPS structure, which is defined as follows:

typedef struct _GEN_GET_TIME_CAPS {
  ULONG  Flags;
  ULONG  ClockPrecision;
} GEN_GET_TIME_CAPS, *PGEN_GET_TIME_CAPS;

The members of this structure contain the following information:

Flags
The following flags can be ORed together. All unspecified flags must be set to zero.
READABLE_LOCAL_CLOCK
When set, indicates the presence of a readable clock on the NIC. Even without such a hardware clock, a miniport driver can use the system clock by calling NdisGetCurrentSystemTime, so long as it reports the correct precision in the ClockPrecision member.
CLOCK_NETWORK_DERIVED
When set, indicates that the NIC's local time is derived from the network connection, as opposed to a free-running, onboard clock.
CLOCK_PRECISION
When set, indicates that the ClockPrecision member contains valid information.
RECEIVE_TIME_INDICATION_CAPABLE
When set, indicates that the NIC hardware can note the local time at which it receives the first cell of a received PDU and that the miniport driver propagates this receive time for each PDU when indicating the packet to a protocol.
TIMED_SEND_CAPABLE
When set, indicates that the NIC can schedule a packet for transmission according to its local time. Protocols can use NDIS_SET_PACKET_TIME_TO_SEND to set the TimeToSend timestamp in the out-of-band data block of a packet descriptor.
TIME_STAMP_CAPABLE
When set, indicates that the NIC can stamp (in the appropriate field of the outgoing packet) the time at which the first byte of the packet is transmitted and that the NIC can retrieve this time from the same field of an inbound packet.
ClockPrecision
Specifies the clock precision in parts per million. For this information to be considered valid, the CLOCK_PRECISION flag must be set.

A miniport driver can provide support for certain timing parameters even in the absence of a local or network clock. In particular, a miniport driver can use the system clock for receive time indications, timed sends, and even time stamping. A NIC-based clock is better since it is likely to provide higher precision and to be accessible with lower latencies than the system clock. In all cases, the miniport driver must specify the precision of the clock that it uses. This allows protocols to determine how to best use the miniport driver's timing support.

If the miniport driver reports the presence of a readable clock, it must be prepared to immediately respond to an OID_GEN_GET_NETCARD_TIME query. The miniport driver's response to this call is time-critical and therefore must be synchronous.


OID_GEN_CO_GET_NETCARD_TIME

The OID_GEN_CO_GET_NETCARD_TIME OID requests the miniport driver to return a NIC's local time, as derived from a clock on the NIC or from the network. The time is formatted as a GEN_GET_NETCARD_TIME structure, defined as follows:

typedef struct _GEN_GET_NETCARD_TIME {
  ULONGLONG  ReadTime;
} GEN_GET_NETCARD_TIME, *PGEN_GET_NETCARD_TIME;

The member of this structure contains the following information:

ReadTime
The NIC's local time.

The miniport driver specified the units for its local time in the ClockPrecision element of the GEN_GET_TIME_CAPS structure that the miniport driver returned in response to a previous OID_GEN_CO_GET_TIME_CAPS query.

If the miniport driver set the READABLE_LOCAL_CLOCK flag in its response to an OID_GEN_CO_GET_TIME_CAPS query, the NIC derives its local time from an onboard clock. If the miniport driver set the CLOCK_NETWORK_DERIVED flag in its response to an OID_GEN_CO_GET_TIME_CAPS query, the NIC derives its local time from the network.

If the local time is derived from an onboard clock, the miniport driver should be able to report the clock precision in parts per million. In general, a network-derived clock is preferable, because it is likely to be more precise and can be used to synchronize many machines attached to the same network or switch.

The miniport driver must return its local time synchronously in its response to the OID_GEN_CO_GET_NETCARD_TIME query since this query synchronizes protocol drivers with the NIC's local time. Protocol drivers should send the OID_GEN_CO_GET_NETCARD_TIME query several times in succession to filter out response-time latencies.


General Statistics for Connection-Oriented Miniport Drivers

The following chart summarizes the OIDs used to get or set the general statistics for connection-oriented miniport drivers and NICs.

Length | Q | S | Name
4 or 8 | M |  | OID_GEN_CO_XMIT_PDUS_OK PDUs transmitted without errors
4 or 8 | M |  | OID_GEN_CO_RCV_PDUS_OK PDUs received without errors
4 or 8 | M |  | OID_GEN_CO_XMIT_PDUS_ERROR PDUs not transmitted or transmitted with errors
4 or 8 | M |  | OID_GEN_CO_RCV_PDUS_ERROR PDUs received with errors
4 or 8 | M |  | OID_GEN_CO_RCV_PDUS_NO_BUFFER PDUs missed, no buffers
4 or 8 | O |  | OID_GEN_CO_RCV_CRC_ERROR PDUs received with circular redundancy check (CRC) errors
4 or 8 | O |  | OID_GEN_CO_TRANSMIT_QUEUE_LENGTH Length of transmit queue
4 or 8 | O |  | OID_GEN_CO_BYTES_XMIT Bytes transmitted without errors
4 or 8 | O |  | OID_GEN_CO_BYTES_RCV Bytes received without errors
4 or 8 | O |  | OID_GEN_CO_BYTES_XMIT_OUTSTANDING Bytes awaiting transmission
4 or 8 | O |  | OID_GEN_CO_NETCARD_LOAD The transmit load on a NIC

Miniport Driver Support for 64-bit Counters

All one-Gbps and faster connection-oriented miniport drivers must support 64-bit counters for the following statistics OIDs. All 100Mbps and faster connection-oriented miiniport drivers should support 64-bit counters for the following statistics OIDs:

OID_GEN_CO_XMIT_PDUS_OK

OID_GEN_CO_RCV_PDUS_OK

OID_GEN_CO_BYTES_XMIT

OID_GEN_CO_BYTES_RCV

Such miniport drivers can also support 64-bit counters for other statistics OIDs, such as OIDs that indicate transmit or receive errors.

System support for 64-bit counters is available in Windows XP and later OS versions.

OID_GEN_CO_XMIT_PDUS_OK

The number of PDUs transmitted without errors.

OID_GEN_CO_RCV_PDUS_OK

The number of PDUs the NIC received without errors and indicated to bound protocols.

OID_GEN_CO_XMIT_PDUS_ERROR

The number of PDUs a NIC failed to transmit.

OID_GEN_CO_RCV_PDUS_ERROR

The number of PDUs that a NIC received but did not indicate to bound protocols due to errors.

OID_GEN_CO_RCV_PDUS_NO_BUFFER

The number of PDUs that the NIC could not receive because of a lack of NIC receive buffer space. Instead of providing the exact number, some NICs provide only the number of times that they have missed at least one PDU because of such a problem.

OID_GEN_CO_RCV_CRC_ERROR

The number of PDUs received with cyclic redundancy check (CRC) errors.

OID_GEN_CO_TRANSMIT_QUEUE_LENGTH

The number of PDUs currently queued for transmission, whether on the NIC or in a driver-internal queue. The number returned is always the total number of PDUs currently queued, which can include unsubmitted send requests queued in the NDIS library.

OID_GEN_CO_BYTES_XMIT

The number of bytes in PDUs transmitted without errors.

OID_GEN_CO_BYTES_RCV

The number of bytes in PDUs received without errors.

OID_GEN_CO_BYTES_XMIT_OUTSTANDING

The number of bytes in PDUs that are queued for transmission.

OID_GEN_CO_NETCARD_LOAD

The OID_GEN_CO_NETCARD_LOAD OID returns the relative load on the transmit system of a connection-oriented miniport driver. The miniport driver derives this number by calculating the difference between the amount of data delivered for transmission from protocols and the amount of data actually sent, as indicated by the packets returned to protocols with NdisMCoSendComplete. The result is the amount of outstanding transmit data in the miniport driver at any time.

Because this statistic changes at a very high frequency, the miniport driver port should filter it. The simplest filtering method is to maintain a running average of samples of the outstanding transmit data. For example, each time MiniportCoSendPackets is called, the miniport driver could add the submitted packet size to a miniport driver-defined variable called OutstandingBytes. Each time the miniport driver calls NdisMCoSendComplete, the miniport driver would then subtract the returned packet size from OutstandingBytes. The miniport driver must also maintain a running average, which is the value that the miniport driver should return in response to the OID_GEN_CO_NETCARD_LOAD query. This variable, which could be called RunningAverage, must be updated on each MiniportCoSendPackets, as follows:

RunningAverage = [(RunningAverage * C) + (OutstandingBytes *
(128 - C))]/128

In this case, 1 < C < 128. Larger values of C produce smoother filtering.


OIDs for Connection-Oriented Call Managers and Clients

The following chart summarizes the OIDs that connection-oriented clients can send to call managers or MCM drivers and that call managers or MCM drivers can send to connection-oriented clients.

Length | Q | S | Name
Varies |  | O | OID_CO_ADD_PVC Adds a PVC to the call manager's list of configured PVCs
Varies |  | O | OID_CO_DELETE_PVC Deletes a PVC from the call manager's list of configured PVCs
 |  |  | OID_CO_GET_CALL_INFORMATION Reserved for future use
Varies |  | O | OID_CO_ADD_ADDRESS Supplies an alias host address to the call manager
Varies |  | O | OID_CO_DELETE_ADDRESS Deletes an alias host address from the call manager
Varies | O |  | OID_CO_GET_ADDRESSES Returns a list of addresses from the call manager
0 |  | O | OID_CO_ADDRESS_CHANGE Notifies clients of a change in the call manager's address list
0 |  | O | OID_CO_SIGNALING_ENABLED Notifies clients that the call manager is ready to make calls and dispatch incoming calls
0 |  | O | OID_CO_SIGNALING_DISABLED Notifies clients that the call manager cannot make calls and dispatch incoming calls
0 |  | M | OID_CO_AF_CLOSE Notifies clients that they should close all address families that they have open with the call manager


OID_CO_ADD_PVC

The OID_CO_ADD_PVC OID is sent by a client to a call manager to add a permanent virtual connection (PVC) to the call manager's list of configured PVCs. The PVC is formatted as a CO_PVC structure, defined as follows:

typedef struct _CO_PVC {
  NDIS_HANDLE  NdisAfHandle;
  CO_SPECIFIC_PARAMETERS  PvcParameters;
} CO_PVC,*PCO_PVC;

The members of this structure contain the following information:

NdisAfHandle
Specifies the NDIS-supplied handle returned by NdisClOpenAddressFamily.
PvcParameters
A structure of the type, CO_SPECIFIC_PARAMETERS. This structure contains protocol-specific parameters that describe the PVC.

A PVC is configured manually by an administrator. A client that monitors such activity notifies a call manager of a newly configured PVC by sending this OID to the call manager. Other clients can then use the newly configured PVC.


OID_CO_DELETE_PVC

The OID_CO_DELETE_PVC OID is sent by a client to a call manager to delete a permanent virtual connection (PVC) from the call manager's list of configured PVCs. The PVC is formatted as a CO_PVC structure, defined as follows:

typedef struct _CO_PVC {
  NDIS_HANDLE  NdisAfHandle;
  CO_SPECIFIC_PARAMETERS  PvcParameters;
} CO_PVC,*PCO_PVC;

The members of this structure contain the following information:

NdisAfHandle
Specifies the NDIS-supplied handle returned by NdisClOpenAddressFamily.
PvcParameters
A structure of the type, CO_SPECIFIC_PARAMETERS. This structure contains protocol-specific parameters that describe the PVC.

A PVC is removed manually by an administrator. A client that monitors such activity notifies a call manager of a PVC that has been removed by sending this OID to the call manager.


OID_CO_GET_CALL_INFORMATION

The OID_CO_GET_CALL_INFORMATION OID is reserved for future use.


OID_CO_ADD_ADDRESS

The OID_CO_ADD_ADDRESS OID is sent by a client to a call manager to specify an alias address for a host. The alias address is formatted as a CO_ADDRESS structure, defined as follows:

typedef struct _CO_ADDRESS {
  ULONG  AddressSize;
  UCHAR  Address[1];
} CO_ADDRESS, *PCO_ADDRESS;

The members of this structure contain the following information:

AddressSize
Specifies the size in bytes of the structure at Address.
Address
Specifies a variable-length array that contains the alias address. The address format is specific to the signaling protocol used by the call manager.

This OID is typically used to specify a well-known address at which a host offers a particular service. For example, a client could specify a well-known address for a LAN emulation server. The call manager's response to this OID is specific to the signaling protocol used by the call manager. An ATM call manager, for example, sends a message to the switch that notifies the switch of the alias address.


OID_CO_DELETE_ADDRESS

The OID_CO_DELETE_ADDRESS OID is sent by a client to a call manager to delete an alias address for a host. The alias address is formatted as a CO_ADDRESS structure, defined as follows:

typedef struct _CO_ADDRESS {
  ULONG  AddressSize;
  UCHAR  Address[1];
} CO_ADDRESS, *PCO_ADDRESS;

The members of this structure contain the following information:

AddressSize
Specifies the size in bytes of the structure at Address.
Address
Specifies a variable-length array that contains the alias address. The address format is specific to the signaling protocol used by the call manager.


OID_CO_GET_ADDRESSES

The OID_CO_GET_ADDRESSES OID is used by the client to make a query to the call manager. This query is made in response to the call manager sending an OID_CO_ADDRESS_CHANGE to the client. In response to this query, the call manager sends the client an address list that is formatted as a CO_ADDRESS_LIST structure, defined as follows:

typedef struct _CO_ADDRESS_LIST {
  ULONG  NumberOfAddressesAvailable;
  ULONG  NumberOfAddresses;
  CO_ADDRESS  AddressList;
} CO_ADDRESS_LIST, *PCO_ADDRESS_LIST;

The members of this structure contain the following information:

NumberOfAddressesAvailable
Specifies the maximum number of addresses in the call manager's list of addresses. Regardless of the actual number of addresses that the call manager returns to the client at AddressList, the size of the buffer at AddressList is always NumberOfAddressesAvailable multiplied by the address size, which is a fixed size specific to the call manager.
NumberOfAddresses
Specifies the number of addresses that the call manager has written to AddressList.
AddressList
The alias address is formatted as a CO_ADDRESS structure, defined as follows:
typedef struct _CO_ADDRESS {
  ULONG AddressSize;
  UCHAR Address[1];
} CO_ADDRESS, *PCO_ADDRESS;

The members of this structure contain the following information:

AddressSize
Specifies the size in bytes of the structure at Address.
Address
Specifies a variable-length array that contains the list of addresses. The address format is specific to the signaling protocol used by the call manager.

The AddressList contains network addresses at which the local host can be reached. The AddressList returned to a particular client contains addresses that are common to all clients, as well as any addresses that the client itself has added to call manager's list of addresses with OID_CO_ADD_ADDRESS.


OID_CO_ADDRESS_CHANGE

The OID_CO_ADDRESS_CHANGE OID is sent by the call manager to each client that opened an address family with the call manager. This action is taken in response to a change in the switch address that the call manager uses. For example, the call manager sends this request if someone disconnects the NIC from one switch and plugs it into another switch. Each notified client must send an OID_CO_GET_ADDRESSES query to the call manager to retrieve a list of currently valid addresses.

The call manager also sends OID_CO_ADDRESS_CHANGE to a client immediately after the client opens an address family with the call manager. This ensures that a client that opens an address family after the switch address has changed is notified of the change. The client must then must then send an OID_CO_GET_ADDRESSES query to the call manager.


OID_CO_SIGNALING_ENABLED

The OID_CO_SIGNALING_ENABLED OID is sent by a call manager to indicate that it is ready to make calls and dispatch incoming calls. The call manager sends this OID to each client that has an address family open with the call manager.


OID_CO_SIGNALING_DISABLED

The OID_CO_SIGNALING_DISABLED OID is sent by a call manager to indicate that it cannot make calls or dispatch incoming calls. The call manager sends this OID to each client that has an address family open with the call manager.


OID_CO_AF_CLOSE

The OID_CO_AF_CLOSE OID is sent by a call manager that must unbind itself from an underlying miniport driver. Before unbinding itself from the miniport driver, the call manager sends this OID to each client that has an address family open with the call manager. In response, the client should do the following:

  1. If the client has any active multipoint connections, call NdisClDropParty as many times as necessary until only a single party remains active on each multipoint VC
  2. Call NdisClCloseCall as many times as necessary to close all calls still open with the call manager
  3. Call NdisClDeregisterSap as many times as necessary to deregister all SAPs that the client has registered with the call manager
  4. Call NdisClCloseAddressFamilyDDK_NdisClCloseAddressFamily_NR to close the address family referenced by NdisAfHandle in the request that contained OID_CO_AF_CLOSE


TAPI Extensions for Connection-Oriented NDIS

The following chart summarizes OIDs that allow TAPI calls to be made over connection-oriented media. Connection-oriented clients send these OIDs to call managers or integrated miniport call manager (MCM) drivers.

Length | Q | S | Name
Varies | O |  | OID_CO_TAPI_ADDRESS_CAPS Requests the telephony capabilities for a specified address on a specified line
Sizeof (CO_TAPI_CM_CAPS) | O |  | OID_CO_TAPI_CM_CAPS Requests the telephony capabilities of a call manager's or MCM driver's device
Varies | O |  | OID_CO_TAPI_GET_CALL_DIAGNOSTICS Requests information about a failed call or a call torn down by the remote TAPI party
Varies | O |  | OID_CO_TAPI_LINE_CAPS Requests the telephony capabilities for a specified line and whether addresses on that line have dissimilar telephony capabilities
Varies | O |  | OID_CO_TAPI_TRANSLATE_NDIS_CALL_PARAMS Requests a call manager or MCM driver to translate NDIS call parameters into TAPI call parameters
Varies | O |  | OID_CO_TAPI_TRANSLATE_TAPI_CALL_PARAMS Requests a call manager or MCM driver to translate TAPI call parameters into NDIS call parameters
Varies | O |  | OID_CO_TAPI_TRANSLATE_SAP Requests a call manager or MCM driver to use TAPI call parameters to prepare one or more SAPs

In its call to NdisCoRequest, the client that queries any of the TAPI extension OIDs must specify an NdisAfHandle that identifies the address family to which the request applies. The client can specify an NdisVcHandle that identifies the virtual connection (VC) to which the request applies. From this VC handle, the call manager or MCM driver may be able to derive the particular line and perhaps the address to which the request applies.


OID_CO_TAPI_ADDRESS_CAPS

The OID_CO_TAPI_ADDRESS_CAPS OID requests a call manager or an integrated miniport call manager (MCM) driver to return the telephony capabilities for a specified address on a specified line.

This request uses a CO_TAPI_ADDRESS_CAPS structure, which is defined as follows:

typedef struct _CO_TAPI_ADDRESS_CAPS {
  IN ULONG  ulLineID;
  IN ULONG  ulAddressID;
  OUT ULONG  ulFlags;
  OUT LINE_ADDRESS_CAPS  LineAddressCaps;
} CO_TAPI_ADDRESS_CAPS, *PCO_TAPI_ADDRESS_CAPS;

The members of this structure contain the following information:

ulLineID
Specifies the zero-based line identifier of the line on which the given address is located.
ulAddressID
Specifies the zero-based address identifier on the line for which capabilities should be returned.
ulFlags
These flags are reserved.
LineAddressCaps
Specifies the telephony capabilities of an address, formatted as a LINE_ADDRESS_CAPS structure. For more information on this structure, see the Platform SDK and the ndistapi.h header file.

After querying the line capabilities of a call manager's or MCM driver's device with OID_CO_TAPI_LINE_CAPS, a connection-oriented client queries the capabilities of the address(es) for each line as follows:

  • If the previous query of OID_CO_TAPI_LINE_CAPS indicated that the line supports only one address or that all addresses on the line have the same address capabilities, the client queries OID_CO_TAPI_ADDRESS_CAPS once to determine the capabilities of all the addresses on the line. In this case, the address capabilities returned by the call manager or MCM driver apply to all addresses on the line.
  • If a line supports multiple addresses that have dissimilar capabilities, the client queries OID_CO_TAPI_ADDRESS_CAPS once for each address on the line. In this case, the address capabilities returned by the call manager or MCM driver apply to a specified address on a specified line.

The call manager or MCM driver returns the address capabilities for a specified address in LineAddressCaps.


OID_CO_TAPI_CM_CAPS

The OID_CO_TAPI_CM_CAPS OID requests a call manager or an integrated miniport call manager (MCM) driver to return the number of lines supported by its device (the device for which it provides call management services). This OID also requests the call manager or MCM driver to indicate whether these lines have dissimilar line capabilities.

This request uses a CO_TAPI_CM_CAPS structure, which is defined as follows:

typedef struct _CO_TAPI_CM_CAPS {
  OUT ULONG  ulCoTapiVersion;
  OUT ULONG  ulNumLines;
  OUT ULONG  ulFlags;
} CO_TAPI_CM_CAPS, *PCO_TAPI_CM_CAPS;

The members of this structure contain the following information:

ulCoTapiVersion
Specifies the TAPI version supported by the call manager or MCM driver. The call manager or MCM driver should set this to CO_TAPI_VERSION.
ulNumLines
Specifies the number of lines supported by the device.
ulFlags
If the device supports multiple lines that have dissimilar line capabilities or if the addresses on any of these lines have dissimilar address capabilities, the call manager or MCM driver sets the CO_TAPI_FLAG_PER_LINE_CAPS bit in ulFlags; otherwise, the call manager or MCM driver clears this bit. All undefined bits are reserved for future use and must be set to 0.

A connection-oriented client uses the information returned from this OID to determine how it will query the line capabilities of the call manager's or MCM driver's device with OID_CO_TAPI_LINE_CAPS.


OID_CO_TAPI_GET_CALL_DIAGNOSTICS

The OID_CO_TAPI_GET_CALL_DIAGNOSTICS OID requests a call manager or MCM driver to return diagnostic information about a failed call or a call torn down by the remote TAPI party.

This request uses a CO_TAPI_CALL_DIAGNOSTICS structure, which is defined as follows:

typedef struct _CO_TAPI_CALL_DIAGNOSTICS {
  OUT ULONG  ulOrigin;
  OUT ULONG  ulReason;
  OUT NDIS_VAR_DATA_DESC  DiagInfo;
} CO_TAPI_CALL_DIAGNOSTICS, *PCO_TAPI_CALL_DIAGNOSTICS;
ulOrigin
Specifies the origination of the call as one of the following LINECALLORIGIN_ constants:
LINECALLORIGIN_OUTBOUND
The call is an outgoing call.
LINECALLORIGIN_INTERNAL
The call is incoming and originated internally (on the same PBX, for example).
LINECALLORIGIN_EXTERNAL
The call is incoming and originated externally.
LINECALLORIGIN_UNKNOWN
The call is incoming. Its origin is currently unknown but may become known later.
LINECALLORIGIN_UNAVAIL
The call is incoming. Its origin is not available and will never be known.
LINECALLORIGIN_CONFERENCE
The call handle is for a conference call—that is, for the application's connection to the conference bridge in the switch.
ulReason
Specifies the reason for the call as one of the following LINECALLREASON_ constants:
LINECALLREASON_DIRECT
The call is direct.
LINECALLREASON_FWDBUSY
The call was forwarded from a busy extension.
LINECALLREASON_FWDNOANSWER
The call was forwarded after some number of rings from an unanswered extension.
LINECALLREASON_FWDUNCOND
The call was forwarded unconditionally from another number.
LINECALLREASON_PICKUP
The call was picked up from another extension.
LINECALLREASON_UNPARK
The call was retrieved as a parked call.
LINECALLREASON_REDIRECT
The call was redirected to this station.
LINECALLREASON_CALLCOMPLETION
The call was the result of a call completion request.
LINECALLREASON_TRANSFER
The call was transferred from another number. Party identifier information may indicate who the caller is and from where the call was transferred.
LINECALLREASON_REMINDER
The call is a reminder (or "recall") that the user has a call parked or on hold for a potentially long time.
LINECALLREASON_UNKNOWN
The reason for the call is currently unknown but may become known later.
LINECALLREASON_UNAVAIL
The reason for the call is unavailable and cannot become known later.
DiagInfo
Specifies an NDIS_VAR_DATA_DESC structure that contains an offset to, as well as the length of, optional diagnostic information supplied by the call manager or MCM driver. The content and format of the diagnostic information is driver-determined.


OID_CO_TAPI_LINE_CAPS

The OID_CO_TAPI_LINE_CAPS OID requests a call manager or an integrated miniport call manager (MCM) driver to return the telephony capabilities for a specified line. This OID also requests the call manager or MCM driver to indicate whether addresses on this line have dissimilar telephony capabilities.

This request uses a CO_TAPI_LINE_CAPS structure, defined as follows, to query the telephony capabilities of a specified line:

typedef struct _CO_TAPI_LINE_CAPS {
  IN  ULONG  ulLineID;
  OUT ULONG  ulFlags;
  OUT LINE_DEV_CAPS  LineDevCaps;
} CO_TAPI_LINE_CAPS, *PCO_TAPI_LINE_CAPS;

The members of this structure contain the following information:

ulLineID
Specifies the line for which telephony capabilities should be returned. ulLineID is a zero-based identifier.
ulFlags
If the line supports multiple addresses that have dissimilar telephony capabilities, the call manager or MCM driver sets the CO_TAPI_FLAG_PER_ADDRESS_CAPS bit in ulFlags; otherwise, the call manager or MCM driver clears this bit. All undefined bits are reserved and must be set to 0.
LineDevCaps
Specifies the telephony capabilities of a line, formatted as a LINE_DEV_CAPS structure. For more information on this structure, see the Platform SDK and the ndistapi.h header file.

After querying the telephony capabilities of a call manager's or MCM driver's device with OID_CO_TAPI_CM_CAPS, a connection-oriented client queries the telephony capabilities of the line(s) supported by the device.

  • If all lines supported by the device have the same line capabilities and all the addresses on these lines have the same address capabilities, the client queries OID_CO_TAPI_LINE_CAPS once to obtain the line capabilities of the device. In this case, the line capabilities returned by the call manager or MCM driver apply to all the lines supported by the device.
  • If the device supports multiple lines with dissimilar capabilities, however, and/or if addresses on these lines have dissimilar address capabilities, the client queries OID_CO_TAPI_LINE_CAPS once for each line supported by the device to obtain the capabilities of each line.

The ulFlags setting determines how many times the client subsequently queries the capabilities of the address(es) on the line:

  • If the line supports only one address, or if the line supports multiple addresses that have the same address capabilities, the client queries OID_CO_TAPI_ADDRESS_CAPS once.
  • If the line supports multiple addresses that have dissimilar capabilities, the client must query OID_CO_TAPI_ADDRESS_CAPS once for each address on the line.


OID_CO_TAPI_TRANSLATE_NDIS_CALLPARAMS

The OID_CO_TAPI_TRANSLATE_NDIS_CALLPARAMS OID requests a call manager or MCM driver to translate NDIS call parameters (passed in a CO_CALL_PARAMETERS structure to the client's ProtocolClIncomingCall function) to TAPI call parameters. The client uses the translated TAPI call parameters returned by the call manager or MCM driver to determine whether to accept or reject the incoming call.

This request uses a CO_TAPI_TRANSLATE_NDIS_CALLPARAMS structure, which is defined as follows:

typedef struct _CO_TAPI_TRANSLATE_NDIS_CALLPARAMS {
  IN  ULONG  ulFlags;
  IN  NDIS_VAR_DATA_DESC  NdisCallParams;
  OUT NDIS_VAR_DATA_DESC  LineCallInfo;
} CO_TAPI_TRANSLATE_NDIS_CALLPARAMS, *PCO_TAPI_TRANSLATE_NDIS_CALLPARAMS;

The members of this structure contain the following information:

ulFlags
The client must set the CO_TAPI_FLAG_INCOMING_CALL bit in ulFlags.
NdisCallParams
Specifies an NDIS_VAR_DATA_DESC structure that contains an offset from the beginning of the NDIS_VAR_DATA_DESC structure to a CO_CALL_PARAMETERS structure. The NDIS_VAR_DATA_DESC structure also contains the length of the CO_CALL_PARAMETERS structure. The client fills in the CO_CALL_PARAMETERS structure with the NDIS call parameters to be translated to TAPI call parameters.
LineCallInfo
Specifies an NDIS_VAR_DATA_DESC structure that contains an offset from the beginning of the NDIS_VAR_DATA_DESC structure to a LINE_CALL_INFO structure. The NDIS_VAR_DATA_DESC structure also contains the length of the CO_CALL_PARAMETERS structure. The LINE_CALL_INFO structure specifies the TAPI call parameters into which the given NDIS call parameters have been translated. For more information on the LINE_CALL_INFO structure, see the Platform SDK and the ndistapi.h header file.

If the request is successful, the call manager or MCM driver fills in the LINE_CALL_PARAMS structure referred to by LineCallInfo with the translated TAPI call parameters. The call manager or MCM driver must allocate the LINE_CALL_INFO structure within the flat memory section referred to LineCallInfo. The client writes the total length of the LINE_CALL_INFO structure to LineCallInfo.Length.


OID_CO_TAPI_TRANSLATE_TAPI_CALLPARAMS

The OID_CO_TAPI_TRANSLATE_TAPI_CALLPARAMS OID requests a call manager or integrated call manager miniport (MCM) driver to translate TAPI call parameters to NDIS call parameters. The client that queries this OID uses the returned NDIS call parameters as an input (formatted as a CO_CALL_PARAMETERS structure) to NdisClMakeCall, with which the client places an outgoing call.

This OID uses a CO_TAPI_TRANSLATE_TAPI_CALLPARAMS structure, which is defined as follows:

typedef struct _CO_TAPI_TRANSLATE_TAPI_CALLPARAMS {
  IN  ULONG  ulLineID;
  IN  ULONG  ulAddressID;
  IN  ULONG  ulFlags;
  IN  NDIS_VAR_DATA_DESC  DestAddress;
  IN  NDIS_VAR_DATA_DESC  LineCallParams;
  OUT NDIS_VAR_DATA_DESC  NdisCallParams;
} CO_TAPI_TRANSLATE_TAPI_CALLPARAMS, *PCO_TAPI_TRANSLATE_TAPI_CALLPARAMS;

The members of this structure contain the following information:

ulLineID
Specifies a zero-based line identifier to which the outgoing call will be directed.
ulAddressID
Specifies a zero-based address identifier (on the line specified by ulLineID) to which the outgoing call will be directed..
ulFlags
The client must set the CO_TAPI_FLAG_OUTGOING_CALL bit in ulFlags. The client can optionally set the CO_TAPI_USE_DEFAULT_CALLPARAMS bit in ulFlags to require the call manager or MCM driver to ignore the LineCallParams and return the default NDIS call parameters for the device.
DestAddress
Specifies an NDIS_VAR_DATA_DESC structure that contains an offset from the beginning of the NDIS_VAR_DATA_DESC structure to a destination address formatted as a character array. The NDIS_VAR_DATA_DESC structure also contains the length of the destination address. The destination address is the address to which the outgoing call will be directed.
LineCallParams
Specifies an NDIS_VAR_DATA_DESC structure that contains an offset from the beginning of the NDIS_VAR_DATA_DESC structure to a LINE_CALL_PARAMS structure. The NDIS_VAR_DATA_DESC structure also contains the length of the LINE_CALL_PARAMS structure. The LINE_CALL_PARAMS structure specifies the TAPI call parameters to be translated into NDIS call parameters. For more information on the LINE_CALL_PARAMS structure, see the Platform SDK and the ndistapi.h header file.
NdisCallParams
Specifies an NDIS_VAR_DATA_DESC structure that contains an offset from the beginning of the NDIS_VAR_DATA_DESC structure to a CO_CALL_PARAMETERS structure. The NDIS_VAR_DATA_DESC structure also contains the length of the CO_CALL_PARAMETERS structure. The CO_CALL_PARAMETERS structure specifies the NDIS call parameters into which the given TAPI call parameters have been translated.

If the request is successful, the call manager or MCM driver fills in the CO_CALL_PARAMETERS structure referenced by NdisCallParams with the translated NDIS call parameters. The call manager or MCM driver must allocate the CO_CALL_PARAMETERS structure within the flat memory section referred to by NdisCallParams. The client writes the total length of the CO_CALL_PARAMETERS structure to NdisCallParams.Length.

If the client sets the CO_TAPI_USE_DEFAULT_CALLPARAMS bit in ulFlags, the client does not specify TAPI call parameters. In this case, the call manager or MCM driver should return the default NDIS call parameters for the device. If there are no default NDIS call parameters for the device, the call manager or MCM driver should return NDIS_STATUS_FAILURE.


OID_CO_TAPI_TRANSLATE_SAP

The OID_CO_TAPI_TRANSLATE_SAP OID requests a call manager or integrated MCM driver to prepare one or more SAPs from TAPI call parameters. The client that queries this OID uses an NDIS SAP returned by the call manager or MCM driver as an input (formatted as a CO_SAP structure) to NdisClRegisterSap, which the client calls to register a SAP on which to receive incoming calls.

This request uses a CO_TAPI_TRANSLATE_SAP structure, which is defined as follows:

typedef struct _CO_TAPI_TRANSLATE_SAP {
  IN  ULONG  ulLineID;
  IN  ULONG  ulAddressID;
  IN  ULONG  ulMediaModes;
  IN  ULONG  Reserved;
  OUT ULONG  NumberOfSaps;
  OUT NDIS_VAR_DATA_DESC  NdisSapParams[1];
} CO_AF_TAPI_SAP, *PCO_AF_TAPI_SAP;

The members of this structure contain the following information:

ulLineID
Specifies a zero-based line identifier.
ulAddressID
Specifies a zero-based address identifier on the line specified by ulLineID.
ulMediaModes
Specifies the media mode of the information stream of calls that the client is interested in, as one or more of the following LINEMEDIAMODE_constants:
LINEMEDIAMODE_UNKNOWN
A media stream exists but its mode is currently unknown and may become known later. This corresponds to a call with an unclassified media type. In typical analog telephony environments, the media mode of an incoming call may be unknown until after the call has been answered and the media stream has been filtered to make a determination.

If the LINEMEDIAMODE_UNKNOWN flag is set, other media flags can also be set. This signifies that the media is unknown but that it is likely to be one of the other indicated media modes.

LINEMEDIAMODE_INTERACTIVEVOICE
The presence of voice energy on the call, and the call is treated as an interactive call with humans on both ends.
LINEMEDIAMODE_AUTOMATEDVOICE
The presence of voice energy on the call, and the voice is locally handled by an automated application.
LINEMEDIAMODE_DATAMODEM
A data modem session on the call.
LINEMEDIAMODE_G3FAX
A group 3 fax is being sent or received over the call.
LINEMEDIAMODE_G4FAX
A group 4 fax is being sent or received over the call.
LINEMEDIAMODE_TDD
A TDD (telecommunication device for the deaf) session on the call.
LINEMEDIAMODE_DIGITALDATA
Digital data is being sent or received over the call.
LINEMEDIAMODE_TELETEX
A teletex session on the call. (Teletex is one of the telematic services.)
LINEMEDIAMODE_VIDEOTEX
A videotex session on the call. (Videotex is one the telematic services.)
LINEMEDIAMODE_TELEX
A telex session on the call. (Telex is one of the telematic services.)
LINEMEDIAMODE_MIXED
A mixed session on the call. (Mixed is one of the ISDN telematic services.)
LINEMEDIAMODE_ADSI
An ADSI (Analog Display Service Interfaces) session on the call.
LINEMEDIAMODE_VOICEVIEW
The media mode of the call is VoiceView.
Reserved
This is reserved. The client must set this field to 0.
NumberOfSaps
Specifies the number of NDIS_VAR_DATA_DESC structures contained in the buffer at NdisSapParams.
NdisSapParams
Specifies a variable-length array that contains one or more NDIS_VAR_DATA_DESC structures. Each NDIS_VAR_DATA_DESC structure contains an offset to, as well as the length of, a CO_SAP structure. Each CO_SAP structure specifies a service access point (SAP) on which a connection-oriented client can receive incoming calls.


Plug-and-Play and Power-Management Objects

Previous Next

Plug and Play and Power Management Objects

This section describes the operational and statistical OIDs for Plug and Play and power management objects.

The Plug and Play and power management OIDs are defined in ntddndis.h. When building a driver that supports these OIDs, include ntddndis.h.

These OIDs are described in the following topics:

Operational OIDs

Statistical OIDs


Operational OIDs

The following table summarizes the operational power management OIDs.

Length | Q | S | Name
Arr |  | O | OID_PNP_ADD_WAKE_UP_PATTERN Wake-up pattern that the miniport driver should load into the NIC
Variable | O |  | OID_PNP_CAPABILITIES The NIC's wake-up capabilities
ULONG | O | O | OID_PNP_ENABLE_WAKE_UP The NIC wake-up capabilities that the miniport driver should enable
ULONG | O |  | OID_PNP_QUERY_POWER A query to determine whether the miniport driver can transition the NIC to a specified device power state
Arr |  | O | OID_PNP_REMOVE_WAKE_UP_PATTERN Wake-up pattern that the miniport driver should remove from the NIC
ULONG |  | O | OID_PNP_SET_POWER A command to set the NIC to a specified power state
Arr | O |  | OID_PNP_WAKE_UP_PATTERN_LIST The wake-up pattern currently loaded in the NIC

The following describes each of the OID_XXX listed in the preceding table more fully.


OID_PNP_ADD_WAKE_UP_PATTERN

The OID_PNP_ADD_WAKE_UP_PATTERN OID is sent by a protocol driver to a miniport driver to specify a wake-up pattern. The wake-up pattern, along with its mask, is described by an NDIS_PM_PACKET_PATTERN structure. For more information on this structure, see NDIS_PM_PACKET_PATTERN.

A protocol that enables pattern-match wake-up for a miniport driver (see OID_PNP_ENABLE_WAKE_UP) uses OID_PNP_ADD_WAKE_UP_PATTERN to specify a wake-up pattern. The wake-up pattern can be stored in host memory or on the NIC, depending on the capabilities of the NIC.

The InformationBuffer contains the following:

  • An NDIS_PM_PACKET_PATTERN structure that provides information about the pattern and its mask.
  • A mask that indicates which bytes of an incoming packet should be compared with corresponding bytes in the pattern. The mask starts with the first byte of the packet, excluding token ring source routing information in a token ring packet. The mask immediately follows the NDIS_PM_PACKET_PATTERN structure in the InformationBuffer. For more information on how this mask works, see the Network Device Class Power Management Reference specification, which can be downloaded from http://www.microsoft.com/hwdev/onnow.htm.
  • A wake-up pattern, which begins PatternOffset bytes from the beginning of the InformationBuffer. For more information on wake-up patterns, see the Network Device Class Power Management Reference specification, which can be downloaded from http://www.microsoft.com/hwdev/onnow.htm.

The number of wake-up patterns that the miniport driver can accept from a protocol may depend on the host memory that the miniport driver has allocated for such patterns or the available storage in the NIC.

An intermediate driver whose upper edge receives this OID request must always propagate the request to the underlying miniport driver by calling Ndis(Co)Request.


OID_PNP_CAPABILITIES

The OID_PNP_CAPABILITIES OID requests a miniport driver to return the wake-up capabilities of its NIC or requests an intermediate driver to return the intermediate driver's wake-up capabilities. The wake-up capabilities are formatted as an NDIS_PNP_CAPABILITIES structure, which is defined as follows:

typedef struct _NDIS_PNP_CAPABILITIES {
  ULONG  Flags;
  NDIS_PM_WAKE_UP_CAPABILITIES  WakeUpCapabilities;
} NDIS_PNP_CAPABILITIES,  *PNDIS_PNP_CAPABILITIES;

The members of this structure contain the following information:

Flags
NDIS_DEVICE_WAKE_UP_ENABLE

NDIS sets this flag if the underlying miniport driver supports one or more wake-up capabilities. Protocol drivers can test this flag to determine whether an underlying miniport driver has wake-up capabilities. Miniport drivers should not access this flag.

WakeUpCapabilities
An NDIS_PM_WAKE_UP_CAPABILITIES structure that specifies the wake-up capabilities of the miniport driver's NIC. The NDIS_PM_WAKE_UP_CAPABILITIES structure is defined as follows:
typedef struct _NDIS_PM_WAKE_UP_CAPABILITIES {
  NDIS_DEVICE_POWER_STATE  MinMagicPacketWakeUp;
  NDIS_DEVICE_POWER_STATE  MinPatternWakeUp;
  NDIS_DEVICE_POWER_STATE  MinLinkChangeWakeUp;
} NDIS_PM_WAKE_UP_CAPABILITIES, *PNDIS_PM_WAKE_UP_CAPABILITIES;

The members of this structure contain the following information:

MinMagicPacketWakeUp
Specifies the lowest device power state from which the miniport driver's NIC can signal a wake-up on receipt of a Magic Packet. (A Magic Packet is a packet that contains 16 contiguous copies of the receiving NIC's Ethernet address.) The device power state is specified as one of the following NDIS_DEVICE_POWER_STATE values:
NdisDeviceStateUnspecified
The NIC does not support magic-packet wake-ups.
NdisDeviceStateD0
The NIC can signal a magic-packet wake-up from device power state D0. Because D0 is the fully powered state, this does not cause a wake-up but can be used as a run-time event.
NdisDeviceStateD1
The NIC can signal a magic-packet wake-up from device power states D1 and D0.
NdisDeviceStateD2
The NIC can signal a magic-packet wake-up from device states D2, D1, and D0.
NdisDeviceStateD3
The NIC can signal a magic-packet wake-up from device power states D3, D2, D1, and D0.
MinPatternWakeUp
Specifies the lowest device power state from which the miniport driver's NIC can signal a wake-up event on receipt of a network frame that contains a pattern specified by the protocol driver. The power state is specified as one of the following NDIS_DEVICE_POWER_STATE values:
NdisDeviceStateUnspecified
The NIC does not support pattern-match wake-ups.
NdisDeviceStateD0
The NIC can signal a pattern-match wake-up from device power state D0. Because D0 is the fully powered state, this does not cause a wake-up but can be used as a run-time event.
NdisDeviceStateD1
The NIC can signal a pattern-match wake-up from device power states D1 and D0.
NdisDeviceStateD2
The NIC can signal a pattern-match wake-up from device power states D2, D1, and D0.
NdisDeviceStateD3
The NIC can signal a pattern-match wake-up from device power states D3, D2, D1, and D0.
MinLinkChangeWakeUp
Specifies the lowest device power state from which the miniport driver's NIC can signal a wake-up event in response to a link change (the connection or disconnection of the NIC's network cable). The power state is specified as one of the following NDIS_DEVICE_POWER_STATE values:
NdisDeviceStateUnspecified
The NIC does not support link-change wake-ups.
NdisDeviceStateD0
The NIC can signal a link-change wake-up from device power state D0. Because D0 is the fully-powered state, this does not cause a wake-up but can be used as a run-time event.
NdisDeviceStateD1
The NIC can signal a link-change wake-up from device power states D1 and D0.
NdisDeviceStateD2
The NIC can signal a link-change wake-up from device power states D2, D1, and D0.
NdisDeviceStateD3
The NIC can signal a link-change wake-up from device power states D3, D2, D1, and D0.

For Miniport Drivers

After the miniport driver completes initialization, both the protocol driver and NDIS can query the miniport driver with this OID to determine the following:

  • Whether the miniport driver is PM-aware.
  • The NIC's capabilities of indicating network wake-up events.

If the miniport driver returns NDIS_STATUS_SUCCESS to a query of OID_PNP_CAPABILITIES, NDIS considers the miniport driver to be PM-aware. If the miniport driver returns NDIS_STATUS_NOT_SUPPORTED, NDIS considers the miniport driver to be a legacy miniport driver that is not PM-aware.

When calling NdisMSetAttributesEx, a miniport that does not support wake-up capabilities but that can save and restore its miniport state across a power-state transition can set the NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND flag. Setting this flag prevents NDIS from calling the driver's MiniportHalt function before the system transitions to a low-power (sleeping) state. However, if the miniport driver returns NDIS_STATUS_NOT_SUPPORTED in response to a query OID_PNP_CAPABILITIES, NDIS ignores the NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND flag and halts the miniport if the system goes into a low-power state.

A miniport driver's NIC can support any combination of wake-up events, including no wake-up events. A miniport driver can still support power management even if its NIC cannot not signal wake-up events. In this case, the only power management OIDs that the miniport driver supports in addition to OID_PNP_CAPABILITIES are OID_PNP_QUERY_POWER and OID_PNP_SET_POWER.

If a miniport driver's NIC does not support a particular wake-up event, the miniport driver should indicate an NDIS_DEVICE_POWER_STATE of NdisDeviceStateUnspecified for the wake-up event in the NDIS_PM_WAKE_UP_CAPABILITIES structure.

OID_PNP_CAPABILITIES only indicates the wake-up capabilities of a miniport driver's NIC; it does not enable such capabilities. OID_PNP_ENABLE_WAKE_UP is used to enable a NIC's wake-up capabilities.

For Intermediate Drivers

If the underlying NIC is PM-aware, the intermediate driver should return NDIS_STATUS_SUCCESS to a query of OID_PNP_CAPABILITIES. In the NDIS_PM_WAKE_UP_CAPABILITIES structure returned by this OID, the intermediate driver should specify a device power state of NdisDeviceStateUnspecified for each wake-up capability (MinMagicPacketWakeUp, MinPatternWakeUp, MinLinkChangeWakeUp). Such a response indicates that the intermediate driver is PM-aware but does not manage a physical device.

If the underlying NIC is not PM-aware, the intermediate driver should return NDIS_STATUS_NOT_SUPPORTED to a query of OID_PNP_CAPABILITIES.


OID_PNP_ENABLE_WAKE_UP

The OID_PNP_ENABLE_WAKE_UP OID specifies which wake-up capabilities a miniport driver should enable in its NIC. This OID can also be queried to determine which wake-up capabilities are enabled for a NIC.

The InformationBuffer contains the following flags, which can be bit-wise ORed together to enable a combination of wake-up events:

NDIS_PNP_WAKE_UP_MAGIC_PACKET
When set, specifies that the miniport driver should enable the NIC to signal a wake-up event on receipt of a Magic Packet. (A Magic Packet is a packet that contains 16 contiguous copies of the receiving NIC's Ethernet address.) When cleared, specifies that the miniport driver should disable the NIC from signaling such a wake-up event.
NDIS_PNP_WAKE_UP_PATTERN_MATCH
When set, specifies that the miniport driver should enable the NIC to signal a wake-up event on receipt of a packet that contains a pattern specified by the protocol with OID_PNP_ADD_WAKE_UP_PATTERN. When cleared, specifies that the miniport driver should disable the NIC from signaling such a wake-up event.
NDIS_PNP_WAKE_UP_LINK_CHANGE
When set, specifies that the miniport driver should enable the NIC to signal a wake-up event in response to a link change (the connection or disconnection of the NIC's network cable). When cleared, specifies that the miniport driver should disable the NIC from signaling such a wake-up event.

After querying a miniport driver's wake-up capabilities with an OID_PNP_CAPABILITIES request, a protocol driver can use OID_PNP_ENABLE_WAKE_UP to enable one or more of the NIC's wake-up capabilities. A protocol driver can also query this OID to determine which wake-up capabilities are enabled for a NIC.

NDIS does not immediately enable the wake-up capabilities specified by a protocol. Instead, NDIS keeps track of the wake-up capabilities enabled by the protocol and, just before the miniport driver transitions to a low-power state, sends an OID_PNP_ENABLE_WAKE_UP to the miniport driver to enable the appropriate wake-up events.

Wake up due to a link change is enabled by default, provided that the NIC supports such A wake-up event. A protocol cannot enable or disable a link-change wake-up by setting or clearing the NDIS_PNP_WAKE_UP_LINK_CHANGE flag in OID_PNP_ENABLE_WAKE_UP. NDIS, however, sets or clears this flag to enable or disable link-change wake-up, as described below.

Before the miniport driver transitions to a low-power state (that is, before NDIS sends the miniport driver an OID_PNP_SET_POWER request), NDIS sends the miniport driver an OID_PNP_ENABLE_WAKE_UP request to enable the appropriate wake-up capabilities. There are two basic scenarios:

  • If the system is transitioning from the fully on state to a sleeping state, NDIS disables link-change wake-up. If the protocol previously enabled magic-packet wake-up and or pattern-match wake-up, NDIS also enables enable magic-packet wake-up or pattern-match wake-up. This configuration of enabled/disabled wake-up events prevents a link change from inappropriately waking the system when the system is in a sleeping state but enables the NIC to wake the system in response to a magic packet or a pattern match.
  • If the NIC is transitioning from the fully on state to a sleeping state because of a link change (someone disconnected the cable from the NIC), NDIS enables link-change wake-up. NDIS also disables magic-packet wake-up and pattern-match wake-up. In this case, the connection of the network cable to the NIC will cause the NIC to signal a wake-up.

NDIS never enables all three wake-up events for a NIC. NDIS either enables link-change wake-up and disables magic-packet and pattern-match wake-up or disables link-change wake-up and enables any wake-up capabilities (magic-packet wake-up or pattern-match wake-up) enabled by the protocol.

The miniport driver must take the appropriate device-dependent steps to enable or disable wake-up events on the NIC.

An intermediate driver whose upper edge receives this OID request must always propagate the request to the underlying miniport driver by calling Ndis(Co)Request.


OID_PNP_QUERY_POWER

The OID_PNP_QUERY_POWER OID requests the miniport driver to indicate whether it can transition its NIC to the low-power state specified in the InformationBuffer. The low-power state is specified as one of the following NDIS_DEVICE_POWER_STATE values:

NdisDeviceStateD1
This specifies a device state of D1.
NdisDeviceStateD2
This specifies a device state of D2.
NdisDeviceStateD3
This specifies a device state of D3.

An OID_PNP_QUERY_POWER request is not used to request a transition to a device state of D0. NDIS simply sends an OID_PNP_SET_POWER request that specifies a device state of D0.

By returning NDIS_STATUS_SUCCESS to this OID request, the miniport driver guarantees that it will transition the NIC to the specified device power state on receipt of a subsequent OID_PNP_SET_POWER request. The miniport driver, in this case, must do nothing to jeopardize the transition.

An OID_PNP_QUERY_POWER request is always followed by an OID_PNP_SET_POWER request. The OID_PNP_SET_POWER request may immediately follow the OID_PNP_QUERY_POWER request or may arrive at an unspecified interval after the OID_PNP_QUERY_POWER request. A device state of D0 specified in the OID_PNP_SET_POWER request effectively cancels the OID_PNP_QUERY_POWER request.

An intermediate driver must always return NDIS_STATUS_SUCCESS to a query of OID_PNP_QUERY_POWER. An intermediate driver should never propagate an OID_PNP_QUERY_POWER request to an underlying miniport driver.


OID_PNP_REMOVE_WAKE_UP_PATTERN

The OID_PNP_REMOVE_WAKE_UP_PATTERN OID requests the miniport driver to delete a wake-up pattern that it previously received in an OID_PNP_ADD_WAKE_UP_PATTERN request. The wake-up pattern, along with its mask, is described by an NDIS_PM_PACKET_PATTERN structure. For more information on this structure, see NDIS_PM_PACKET_PATTERN.

The InformationBuffer contains the following:

  • An NDIS_PM_PACKET_PATTERN structure that provides information about the pattern and its mask.
  • A mask that indicates which bytes of an incoming packet should be compared with corresponding bytes in the pattern. The mask starts with the first byte of the packet, excluding token ring source routing information in a token ring packet. The mask immediately follows the NDIS_PM_PACKET_PATTERN structure in the InformationBuffer.
  • A wake-up pattern, which begins PatternOffset bytes from the beginning of the InformationBuffer.

An intermediate driver whose upper edge receives this OID request must always propagate the request to the underlying miniport driver by calling Ndis(Co)Request.


OID_PNP_SET_POWER

The OID_PNP_SET_POWER OID notifies a miniport driver that its NIC will be transitioning to the device power state specified in the InformationBuffer. The device power state is specified as one of the following NDIS_DEVICE_POWER_STATE values:

NdisDeviceStateD0
This specifies a device state of D0.
NdisDeviceStateD1
This specifies a device state of D1.
NdisDeviceStateD2
This specifies a device state of D2.
NdisDeviceStateD3
This specifies a device state of D3.

The miniport driver must always return NDIS_STATUS_SUCCESS to an OID_PNP_SET_POWER request.

An OID_PNP_SET_POWER request may or may not be preceded by an OID_PNP_QUERY_POWER request.

Before a miniport driver returns NDIS_STATUS_SUCCESS, it must fully prepare the NIC hardware for the indicated network device power state. The task performed by the miniport driver to accomplish this are device-dependent.

Before a NIC transitions to the D3 state, its miniport driver must turn-off everything under the miniport driver's control: interrupts must disabled, timers must be canceled, and so forth. A miniport driver cannot access the NIC hardware after the NIC has been set to the D3 state by the bus driver.

An intermediate driver must always return NDIS_STATUS_SUCCESS to a query of OID_PNP_SET_POWER. An intermediate driver should never propagate an OID_PNP_SET_POWER request to an underlying miniport driver.


OID_PNP_WAKE_UP_PATTERN_LIST

The OID_WAKE_UP_PATTERN_LIST OID is used by a protocol to request a list of the wake-up patterns currently set for the miniport driver's NIC. A protocol specifies a wake-up pattern with OID_PNP_ADD_WAKE_UP_PATTERN.

OID_PNP_WAKE_UP_PATTERN_LIST is handled by NDIS rather than the miniport driver.

NDIS returns to the protocol a description of each wake-up pattern set in the miniport driver. Each wake-up pattern, along with its mask, is described by an NDIS_PM_PACKET_PATTERN structure. For more information on this structure, see NDIS_PM_PACKET_PATTERN.

For each wake-up pattern, the InformationBuffer contains the following:

  • An NDIS_PM_PACKET_PATTERN structure that provides information about the pattern and its mask.
  • A mask that indicates which bytes of an incoming packet should be compared with corresponding bytes in the pattern. The mask starts with the first byte of the packet, excluding token ring source routing information in a token ring packet. The mask immediately follows the NDIS_PM_PACKET_PATTERN structure in the InformationBuffer.
  • A wake-up pattern, which begins PatternOffset bytes from the beginning of the InformationBuffer.

An intermediate driver whose upper edge receives this OID request must always propagate the request to the underlying miniport driver by calling Ndis(Co)Request.


Statistical OIDs

The following table summarizes the statistical power management OIDs.

Length | Q | S | Name
 | O |  | OID_PNP_WAKE_UP_ERROR The number of false wake-ups signaled by the NIC
 | O |  | OID_PNP_WAKE_UP_OK The number of valid wake-ups signaled by the NIC

The following describes each of the OID_XXX listed in the preceding table more fully.

OID_PNP_WAKE_UP_ERROR

The number of false wake-ups that are signaled by the miniport driver's NIC. A false wake-up occurs when the NIC wakes up the system when it shouldn't have. For example, the NIC could erroneously wake up the system due to an inexact pattern match.

An intermediate driver whose upper edge receives this OID request must always propagate the request to the underlying miniport driver by calling Ndis(Co)Request.

OID_PNP_WAKE_UP_OK

The number of valid wake-ups that are signaled by the miniport driver's NIC. A valid wake-up occurs when the NIC wakes up the system in response to a valid pattern match or Magic Packet™.

An intermediate driver whose upper edge receives this OID request must always propagate the request to the underlying miniport driver by calling Ndis(Co)Request.


ATM Objects

This section describes the OIDs for ATM objects, both operational and statistical types.

The ATM OIDs are defined in ntddndis.h. When building a driver that supports these OIDs, include ntddndis.h and atm.h.

These OIDs are described in the following topics:

Operational Characteristics for ATM Miniport Drivers

Statistics for ATM Miniport Drivers

ATM OIDs for Call Managers or MCM Drivers


Operational Characteristics for ATM Miniport Drivers

The following chart summarizes the OIDs used to get the operational characteristics of ATM miniport drivers and/or their NICs. Note that an ATM miniport driver handles such requests in its MiniportCoRequest function.

Length | Q | S | Name
4 | O |  | OID_ATM_ASSIGNED_VPI The VPI value (if any) to be used for all cells on the interface.
Var | O |  | OID_ATM_GET_NEAREST_FLOW The nearest supported values of media parameters.
6 | M |  | OID_ATM_HW_CURRENT_ADDRESS The current hardware address of the NIC
8 | O |  | OID_ATM_ILMI_VPIVCI The VPI/VCI (if any) assigned to the Interim Local Management Interface
4 | O |  | OID_ATM_MAX_AAL0_PACKET_SIZE The maximum packet size supported for AAL0
4 | O |  | OID_ATM_MAX_AAL1_PACKET_SIZE The maximum packet size supported for AAL1
4 | 0 |  | OID_ATM_MAX_AAL34_PACKET_SIZE The maximum packet size supported for AAL 3/4
4 | M |  | OID_ATM_MAX_AAL5_PACKET_SIZE The maximum packet size supported for AAL5
4 | M |  | OID_ATM_MAX_ACTIVE_VCI_BITS The number of usable VCI bits
4 | M |  | OID_ATM_MAX_ACTIVE_VPI_BITS The number of usable VPI bits
4 | M |  | OID_ATM_MAX_ACTIVE_VCS The maximum active VCs supported by the miniport driver
8 | O |  | OID_ATM_SIGNALING_VPIVCI The VPI/VCI (if any) assigned to the signaling VC
4 | M |  | OID_ATM_SUPPORTED_AAL_TYPES The supported AAL types
4 | M |  | OID_ATM_SUPPORTED_SERVICE_CATEGORY The supported service categories.
8 | O |  | OID_ATM_SUPPORTED_VC_RATES The minimum and maximum cell transmission rates

The following describes each of the OID_ATM_XXX listed in the preceding chart more fully.


OID_ATM_ASSIGNED_VPI

The OID_ATM_ASSIGNED_VPI OID requests an ATM miniport driver to return an assigned VPI that the miniport driver has acquired (for example, from the registry). In an environment that supports more than one host per ATM switch port, a host may be required to transmit and receive using an assigned VPI. A connection-oriented client or call manager can request the assigned VPI so that it can appropriately specify VCs for outgoing and incoming calls.

If the miniport driver does not have an assigned VPI to return to the call manager, it returns NDIS_STATUS_NOT_SUPPORTED.


OID_ATM_GET_NEAREST_FLOW

The OID_ATM_GET_NEAREST_FLOW OID requests an ATM miniport driver to return the media parameters for a VC as close as possible to specified media parameters. The InformationBuffer passed to MiniportCoRequest contains a CO_CALL_PARAMETERS structure that points to a CO_MEDIA_PARAMETERS structure. The CO_MEDIA_PARAMETERS structure specifies the target media parameters and also contains ROUND_DOWN_FLOW and ROUND_UP_FLOW flags that indicate whether the miniport driver should round the actual media parameter values up or down with respect to the specified target media parameters.

The caller of NdisCoRequest must always specify a VC when passing this OID. If the caller fails to specify a VC, the miniport driver must return NDIS_STATUS_INVALID_DATA.


OID_ATM_HW_CURRENT_ADDRESS

The OID_ATM_HW_CURRENT_ADDRESS OID requests an ATM miniport driver to return the current network address of its NIC.


OID_ATM_ILMI_VPIVCI

The OID_ATM_ILMI_VPIVCI OID requests an ATM miniport driver to return the VPI/VCI for an Interim Local Management Interface as a structure of type ATM_VPIVCI, which is defined as follows:

typedef struct _ATM_VPIVCI {
  ULONG  Vpi;
  ULONG  Vci;
} ATM_VPIVCI, *PATM_VPIVCI;

The members of this structure contain the following information:

Vpi
The VPI of the ILMI VC.
Vci
The VCI of the ILMI VC.

If the miniport driver has an assigned VPI/VCI for the ILMI (acquired, for example, from the registry), it returns the VPI/VCI value. Otherwise, the miniport driver returns NDIS_STATUS_NOT_SUPPORTED.


OID_ATM_MAX_AAL0_PACKET_SIZE

The OID_ATM_MAX_AALO_PACKET_SIZE OID requests an ATM miniport driver that supports the AAL0 type to return the maximum packet size that the miniport driver supports for the AAL0 type. If a miniport driver supports the AAL0 type, it must support this OID.


OID_ATM_MAX_AAL1_PACKET_SIZE

The OID_ATM_MAX_AAL1_PACKET_SIZE OID requests an ATM miniport driver that supports the AAL1 type to return the maximum packet size that the miniport driver supports for the AAL1 type. If a miniport driver supports the AAL1 type, it must support this OID.


OID_ATM_MAX_AAL34_PACKET_SIZE

The OID_ATM_MAX_AAL34_PACKET_SIZE OID requests an ATM miniport driver that supports the AAL34 type to return the maximum packet size that the miniport driver supports for the AAL34 type. If a miniport driver supports the AAL 3/4 type, it must support this OID.


OID_ATM_MAX_AAL5_PACKET_SIZE

The OID_ATM_MAX_AAL5_PACKET_SIZE OID requests an ATM miniport driver that supports the AAL5 type to return the maximum packet size that the miniport driver supports for the AAL5 type. Because an NDIS ATM miniport driver must support the AAL5 type, it must also support this OID.


OID_ATM_MAX_ACTIVE_VCI_BITS

The OID_ATM_MAX_ACTIVE_VCI_BITS OID requests an ATM miniport driver to return the number of usable bits in the VCI field of the cell header.


OID_ATM_MAX_ACTIVE_VPI_BITS

The OID_ATM_MAX_ACTIVE_VPI_BITS OID requests an ATM miniport driver to return the number of usable bits in the VPI field of the cell header.


OID_ATM_MAX_ACTIVE_VCS

The OID_ATM_MAX_ACTIVE_VCS OID requests an ATM miniport driver to return the maximum number of active VCs that the miniport driver can support.


OID_ATM_SIGNALING_VPIVCI

The OID_ATM_SIGNALING_VPIVCI OID requests an ATM miniport driver to return the VPI and VCI to be assigned to the signaling VC as a structure of type ATM_VPIVCI, which is defined as follows:

typedef struct _ATM_VPIVCI {
  ULONG  Vpi;
  ULONG  Vci;
} ATM_VPIVCI, *PATM_VPIVCI;

The members of this structure contain the following information:

Vpi
The VPI of the signaling VC.
Vci
The VCI of the signaling VC.

In an environment that supports more than one host per ATM switch port, a miniport driver may acquire (from the registry, for example) an assigned VPI/VCI for a signaling VC. A signaling VC is a VC that the call manager uses to send and receive signaling messages to and from network control components, such as a switch.

A call manager can request the assigned signaling VPI/VCI so that it can appropriately specify a signaling VC.

If the miniport driver does not have an assigned signaling VC to return to the call manager, it returns NDIS_STATUS_NOT_SUPPORTED.


OID_ATM_SUPPORTED_AAL_TYPES

The OID_ATM_SUPPORTED_AAL_TYPES OID requests an ATM miniport driver to return a list of the AAL types that it supports, as a proper subset of the following system-defined values:

AAL_TYPE_AAL0
AAL0
AAL_TYPE_AAL1
AAL1
AAL_TYPE_AAL34
AAL34
AAL_TYPE_AAL5
AAL5

The returned value is a bitwise OR of all the AAL supported types—for example, AAL_TYPE_AAL0 | AAL_TYPE_AAL5.


OID_ATM_SUPPORTED_SERVICE_CATEGORY

The OID_ATM_SUPPORTED_SERVICE_CATEGORY OID requests an ATM miniport driver to return a list of the ATM service categories that it supports, as a proper subset of the following system-defined values:

ATM_SERVICE_CATEGORY_CBR
Constant Bit Rate
ATM_SERVICE_CATEGORY_VBR
Variable Bit Rate
ATM_SERVICE_CATEGORY_UBR
Unspecified Bit Rate
ATM_SERVICE_CATEGORY_ABR
Available Bit Rate

An ATM miniport driver must support at least the Unspecified Bit Rate service category. The returned value is a bitwise OR of all the supported service categories—for example, ATM_SERVICE_CATEGORY_UBR | ATM_SERVICE_CATEGORY_CBR.


OID_ATM_SUPPORTED_VC_RATES

The OID_ATM_SUPPORTED_VC_RATES OID requests the miniport driver to returns its minimum and maximum cell transmission rates as a structure of type ATM_VC_RATES_SUPPORTED, which is defined as follows:

typedef struct _ATM_VC_RATES_SUPPORTED {
  ULONG  MinCellRate;
  ULONG  MaxCellRate;
} ATM_VC_RATES_SUPPORTED, *PATM_VC_RATES_SUPPORTED;

The members of this structure contain the following information:

MinCellRate
The minimum transmission rate in cells per second.
MaxCellRate
The maximum transmission rate in cells per second.


Statistics for ATM Miniport Drivers

The following chart summarizes the OIDs used to get or set statistics for ATM miniport drivers.

Length | Q | S | Name
4 | O |  | OID_ATM_CELLS_HEC_ERROR Cells received with header error control errors
4 | O |  | OID_ATM_RCV_CELLS_DROPPED Cells received and dropped for any reason
4 | O |  | OID_ATM_RCV_CELLS_OK Cells received without errors
4 | O |  | OID_ATM_RCV_INVALID_VPI_VCI Cells received with an unrecognized VPI and/or VCI
4 | O |  | OID_ATM_RCV_REASSEMBLY_ERROR Received packets that failed reassembly
4 | O |  | OID_ATM_XMIT_CELLS_OK Cells transmitted without error

The following describes each of the OID_ATM_XXX listed in the preceding chart more fully.

OID_ATM_CELLS_HEC_ERROR

The number of cells that were received with a header error control (HEC) error. A HEC error is a checksum error for a cell header.

OID_ATM_RCV_CELLS_DROPPED

The number of received cells that were dropped for any reason.

An ATM miniport driver must support this OID on an per-adapter basis and can optionally support this OID on a per-VC basis.

OID_ATM_RCV_CELLS_OK

The number of cells that were received without errors.

An ATM miniport driver must support this OID on an per-adapter basis and can optionally support this OID on a per-VC basis.

OID_ATM_RCV_REASSEMBLY_ERROR

The number of packet reassembly errors that have occurred. Such an error occurs when a packet reassembled from received cells fails a checksum test or if the reassembly times out (that is, if the NIC receives all but the last cell for a packet and times out waiting for that cell).

OID_ATM_RCV_INVALID_VPI_VCI

The number of cells that were received with unrecognized VPI and/or VCI values.

OID_ATM_XMIT_CELLS_OK

The number of cells that were transmitted without error.

An ATM miniport driver must support this OID on an per-adapter basis and can optionally support this OID on a per-VC basis.


ATM OIDs for Call Managers or MCM Drivers

The following chart summarizes the ATM OIDs that connection-oriented clients send only to call managers or MCM drivers.

Length | Q | S | Name
20 | M |  | OID_ATM_LECS_ADDRESS The LAN Emulation Configuration Server address
Var | M |  | OID_ATM_SERVICE_ADDRESS The address of a specified ATM service

The following describes each of the OID_ATM_XXX listed in the preceding chart more fully.


OID_ATM_LECS_ADDRESS

The OID_ATM_LECS_ADDRESS OID requests a call manager or an MCM driver to return the LAN Emulation Configuration Server (LECS) address. This address is returned as a structure of type ATM_ADDRESS, defined as follows:

typedef struct _ATM_ADDRESS {
  ATM_ADDRESSTYPE  AddressType;
  ULONG  NumberOfDigits;
  UCHAR  Address[ATM_ADDRESS_LENGTH];
} ATM_ADDRESS, *PATM_ADDRESS;

The members of this structure contain the following information:

AddressType
Specifies the format of the ATM address. A value of ATM_NSAP specifies an ATM Endstation Address (NSAP format). A value of ATM_E164 specifies an E.164 address (telephony format).
NumberOfDigits
Indicates the number of digits in the ATM address.
Address
An array that contains the ATM address.


OID_ATM_SERVICE_ADDRESS

The OID_ATM_SERVICE_ADDRESS OID requests a call manager or an MCM driver to return the address of a specified ATM service. The call manager or MCM driver returns an address list formatted as a structure of type ATM_SERVICE_ADDRESS_LIST, which is defined as follows:

typedef struct _ATM_SERVICE_ADDRESS_LIST {
  ATM_SERVICE_REGISTRY_TYPE  ServiceRegistryType;
  ULONG  NumberOfAddressesAvailable;
  ULONG  NumberOfAddressesReturned;
  ATM_ADDRESS  Address[1];
} ATM_SERVICE_ADDRESS_LIST, *PATM_SERVICE_ADDRESS_LIST;

The members of this structure contain the following information:

ServiceRegistryType
Specifies an ATM service registry type. A value of ATM_SERVICE_REGISTRY_LECS specifies a LAN Emulation Configuration Server (LECS) type. A value of ATM_SERVICE_REGISTRY_ANS specifies an ATM Name Server type.
NumberOfAddressesAvailable
Specifies the total number of ATM addresses available for the indicated service. This value is greater than or equal to the number of addresses returned (NumberOfAddressesReturned).
NumberOfAddressesReturned
Specifies the number of addresses that the call manager has written to Address. The call manager computes the space available in this array based on the InformationBufferLength passed in the NDIS_REQUEST structure that contains the ATM_SERVICE_ADDRESS_LIST structure.
Address
Specifies a variable-length array that contains one or more ATM addresses, each of which is formatted as structure of type ATM_ADDRESS, which is defined as follows:
typedef struct _ATM_ADDRESS {
  ATM_ADDRESSTYPE  AddressType;
  ULONG  NumberOfDigits;
  UCHAR  Address[ATM_ADDRESS_LENGTH];
} ATM_ADDRESS, *PATM_ADDRESS;

The members of this structure contain the following information:

AddressType
Specifies the format of the ATM address. A value of ATM_NSAP specifies an ATM Endstation Address (NSAP format). A value of ATM_E164 specifies an E.164 address (telephony format).
NumberOfDigits
Indicates the number of digits in the ATM address.
Address
An array that contains the ATM address.


IrDA Objects

This section describes the OIDs used to query and set the operational characteristics of IrDA (infrared) miniport drivers and/or their NICs. Note that an IrDA miniport driver handles query requests in its MiniportQueryInformation function and set requests in its MiniportSetInformation function.

The IrDA OIDs are defined in ntddndis.h. When building a driver that supports these OIDs, include ntddndis.h.

Length | Q | S | Name
4 | O |  | OID_IRDA_EXTRA_RCV_BOFS Requests the number of extra Beginning of Frame (BOF) flags required by the NIC's transceiver to synchronize on a receive packet.
4 | M | M | OID_IRDA_LINK_SPEED If set, requests the miniport driver to set the transmission speed of outgoing frames and possibly to control the speed at which incoming frames are received. If queried, requests the miniport driver to return the current speed at which it transmits outgoing frames or accepts incoming frames.
4 | O |  | OID_IRDA_MAX_RECEIVE_WINDOW_SIZE Requests the maximum number of incoming frames that the miniport driver's NIC can handle at one time. This number is the maximum receive window size.
4 | O |  | OID_IRDA_MAX_SEND_WINDOW_SIZE Requests the maximum number of outgoing frames that the miniport driver's NIC can handle at one time. This number is the maximum send window size. The infrared link access protocol (IrLAP) uses this number to limit the number of frames it transmits at one time.
4 | O |  | OID_IRDA_MAX_UNICAST_LIST_SIZE Requests the maximum number of entries in the miniport driver's UNICAST list, which is a list of devices from which to accept frames. Supported only by Win9x IrDA miniport drivers.
4 | M | M | OID_IRDA_MEDIA_BUSY If set, requests the miniport driver to monitor for the media-busy condition. If queried, requests the miniport driver to determine if media is currently busy.
4 | O | O | OID_IRDA_RATE_SNIFF If set, requests the miniport driver to accept frames that are transmitted at any speed. If queried, requests the miniport driver to return its current receive speed. Supported only by Win9x IrDA miniport drivers.
4 | O |  | OID_IRDA_REACQUIRE_HW_RESOURCES Requests the miniport driver to begin operating with hardware resources that were specified during its initialization. Supported only by Win9x IrDA miniport drivers.
4 | M |  | OID_IRDA_RECEIVING Requests the miniport driver to indicate whether it is currently receiving a packet. Supported only by Win9x IrDA miniport drivers.
4 | O |  | OID_IRDA_RELEASE_HW_RESOURCES Requests the miniport driver to release the use of its hardware resources. Supported only by Win9x IrDA miniport drivers.
Arr(4) | M |  | OID_IRDA_SUPPORTED_SPEEDS Requests the supported speeds at which the miniport driver can transmit outgoing frames and receive incoming frames. IrLAP sets link speed using OID_IRDA_LINK_SPEED with one of the returned values before transmitting packets.
4 | M |  | OID_IRDA_TURNAROUND_TIME Requests the turnaround time of the NIC's infrared transceiver.
Arr(4) | O | O | OID_IRDA_UNICAST_LIST If set, requests the miniport driver to only accept frames from addresses of devices in a specified list. If queried, requests the miniport driver to return its current list of devices from which to accept frames. Supported only by Win9x IrDA miniport drivers.

The following topics describe the OIDs that are used to query and set the operational characteristics of IrDA (infrared) miniport drivers and/or their NICs.

OID_IRDA_EXTRA_RCV_BOFS

The OID_IRDA_EXTRA_RCV_BOFS OID is optional for some IrDA miniport drivers. Only IrDA miniport drivers that manage NICs that support link speeds from 2400 bps through 115.2 Kbps (SIR encoding speeds) must support this OID.

The infrared signal itself is sometimes used to establish the timing for the reception of frames. The time required to synchronize with the infrared signal can vary according the type of transceiver hardware. Typically, synchronization is established while a transceiver is receiving Beginning of Frame (BOF) flags. More than one BOF flag may be required in a frame to establish synchronization.

At SIR encoding speeds, sometimes a remote infrared transceiver adds extra BOFs to a frame so that the local infrared transceiver receives the frame properly. The IrDA protocol driver queries OID_IRDA_EXTRA_RCV_BOFS to determine how many extra BOFs the NIC's transceiver requires to synchronize on an incoming frame. During negotiation with a remote station, the IrDA protocol driver communicates this value to the remote transceiver so that the remote transceiver adds the correct number of extra BOFs to each frame that it sends to the local NIC's transceiver.

The OID_IRDA_EXTRA_RCV_BOFS value applies to a frame transmitted at 115.2 Kbps. The extra BOFs required for frames transmitted at slower speeds are scaled from that value. The following table indicates, for a given OID_IRDA_EXTRA_RCV_BOFS value, the derived BOF values for link speeds less than 115.2 Kbps.

Speed | Extra BOFs
2400 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9600 | 4 | 2 | 1 | 0 | 0 | 0 | 0 | 0
19200 | 8 | 4 | 2 | 1 | 0 | 0 | 0 | 0
38400 | 16 | 8 | 4 | 2 | 1 | 0 | 0 | 0
57600 | 24 | 12 | 6 | 3 | 1 | 1 | 0 | 0
115200 | 48 | 24 | 12 | 6 | 3 | 2 | 1 | 0

To determine the OID_IRDA_EXTRA_RCV_BOFS value that a miniport driver should indicate to the IrDA protocol:

  1. Find a link speed supported by the NIC's transceiver in the left-most column.
  2. In that row, find the required number of BOFs for the transceiver at that speed.
  3. Go down that column to the row for 115.2 Kbps. The number of BOFs indicated for 115.2 Kbps is the number of BOFs that the miniport driver should indicate to the IrDA protocol.

For example, if the NIC's transceiver requires 8 extra BOFs at 38400 baud, the miniport driver should indicate an OID_IRDA_EXTRA_RCV_BOFS value of 24 to the IrDA protocol.

If the number of extra BOFs required by the NIC's transceiver is between two values in a table row, choose the higher value. For example, if the transceiver requires 8 extra BOFs at 57600 bps, choose 12 instead of 6 in the row for 57600 bps. In this case, the miniport driver should indicate an OID_IRDA_EXTRA_RCV_BOFS value of 24, which is the corresponding number of extra BOFs required for a receiving a frame at 115.2 Kbps.

Note that extra BOFs are never required for frames transmitted at speeds above 115.2 Kbps.

During negotiation with a remote transceiver, the IrDA protocol also determines the extra number of BOFs required by the remote transceiver. For each packet that it sends to the miniport driver for transmission, the IrDA protocol specifies, as out-of-band data, the extra number of receive BOFs that the miniport driver must add to the beginning of the packet. (For more information, see NDIS_PACKET_OOB_DATA). The miniport driver must add the specified number of extra BOFs to the packet before transmitting it.

OID_IRDA_LINK_SPEED

The OID_IRDA_LINK_SPEED OID specifies the link speed of the NIC's transceiver. Link speed indicates the speed that outgoing frames are transmitted and possibly the speed that incoming frames are received. For information on how to set OID_IRDA_LINK_SPEED to control the speed of incoming frames, see the description of OID_IRDA_RATE_SNIFF. Link speed is set to one of the speeds returned by the miniport driver in response to a previous query of OID_IRDA_SUPPORTED_SPEEDS. The link speed is specified in bits per second (bps).

The specified link speed applies to all frames subsequently transmitted by the miniport driver. The miniport driver may still have frames to transmit at the old link speed (the link speed in effect before the set of OID_IRDA_LINK_SPEED). The miniport driver should transmit these frames at the old link speed. The link speed specified by OID_IRDA_LINK_SPEED applies only to frames sent after the miniport driver is notified of the new link speed.

After the miniport driver starts, it must assume a link speed of 9,600 bps, regardless of the value in OID_IRDA_LINK_SPEED.

OID_IRDA_MAX_RECEIVE_WINDOW_SIZE

The OID_IRDA_MAX_RECEIVE_WINDOW_SIZE OID is optional for IrDA miniport drivers.

This OID requests the maximum number of incoming frames that the miniport driver's NIC can handle at one time. This number is the maximum receive window size. IrLAP is limited by this number when it negotiates with a remote station for the number of frames the remote station will transmit to the miniport driver. The miniport driver typically uses this OID as a patch for hardware that cannot keep up with the infrared signal over a full-sized window of 7 frames. The valid values for this OID are 1-7.

OID_IRDA_MAX_SEND_WINDOW_SIZE

The OID_IRDA_MAX_SEND_WINDOW_SIZE OID is optional for IrDA miniport drivers.

This OID requests the maximum number of outgoing frames that the miniport driver's NIC can handle at one time. This number is the maximum send window size. IrLAP uses this number to limit the number of frames it transmits at one time. The miniport driver typically uses this OID as a patch for hardware that cannot keep up with the infrared signal over a full-sized window of 7 frames. The valid values for this OID are 1-7.

OID_IRDA_MAX_UNICAST_LIST_SIZE

The OID_IRDA_MAX_UNICAST_LIST_SIZE OID is optional for most IrDA miniport drivers. Only Windows® 95/98/Me IrDA miniport drivers that maintain a UNICAST list must support this OID.

This OID requests the maximum number of entries in the miniport driver's UNICAST list. A UNICAST list is a list of the miniport driver's devices from which the miniport driver accepts frames. For more information, see the description of OID_IRDA_UNICAST_LIST.

OID_IRDA_MEDIA_BUSY

The OID_IRDA_MEDIA_BUSY OID requests information about whether the media is busy—that is, whether the miniport driver detects packet traffic.

For a set, the miniport driver can start to monitor the media for a busy condition. IrLAP sets the value of OID_IRDA_MEDIA_BUSY to zero to inform the miniport driver to monitor for a media-busy condition. If the miniport driver detects infrared traffic of any kind, it must:

  • Set the value of OID_IRDA_MEDIA_BUSY to nonzero.
  • Call the NdisMIndicateStatus function to indicate that the media is busy. In this call, the miniport driver passes NDIS_STATUS_MEDIA_BUSY in the GeneralStatus parameter.

After the value of OID_IRDA_MEDIA_BUSY is set to nonzero, the miniport driver does not monitor the media for a busy condition again until IrLAP resets OID_IRDA_MEDIA_BUSY to zero.

For a query, the miniport driver determines if media is currently busy. The miniport driver returns a zero value if the media is not busy. The miniport driver returns a nonzero value if the it detects packet traffic.

OID_IRDA_RATE_SNIFF

The OID_IRDA_RATE_SNIFF OID is optional for most IrDA miniport drivers. Only Windows® 95/98/Me IrDA miniport drivers that can accept infrared frames dynamically at any speed must support this OID.

For a set, this OID requests the miniport driver to accept frames transmitted at any speed. If OID_IRDA_RATE_SNIFF has a zero value, the miniport driver should only accept frames transmitted at the speed indicated in OID_IRDA_LINK_SPEED, as set by IrLAP. If OID_IRDA_RATE_SNIFF has a nonzero value, an additional speed parameter must be maintained by the driver. This speed parameter is known as the current receive speed. The miniport driver calls the NdisMIndicateStatus function to indicate a change in its receive speed to IrLAP. In this call, the miniport driver passes NDIS_STATUS_LINK_SPEED_CHANGE in the GeneralStatus parameter and the DWORD for the new speed at which frames are received in the StatusBuffer parameter. After the miniport driver indicates the new receive speed, it does not call NdisMIndicateStatus again until frames arrive at a different speed.

For a query, this OID requests the miniport driver to return its current receive speed.

OID_IRDA_REACQUIRE_HW_RESOURCES

The OID_IRDA_REACQUIRE_HW_RESOURCES OID is optional for IrDA miniport drivers and is supported only by Windows® 95/98/Me IrDA miniport drivers.

This OID requests the miniport driver to begin operating with hardware resources that the miniport driver specifies. After the miniport driver receives this request, it should not make any assumptions about the operating state of its NIC.

The miniport driver should not fail its MiniportInitialize routine solely because it cannot read its configuration. The miniport driver should instead return success and should wait for this request. During initialization, the miniport driver must perform all required initialization other than acquiring its hardware resources.

If the miniport driver is already operating, that is, it already has acquired resources, it should continue using those resources and return NDIS_STATUS_FAILURE for this request.

OID_IRDA_RECEIVING

The OID_IRDA_RECEIVING OID is supported only by Windows® 95/98/Me IrDA miniport drivers.

This OID requests the miniport driver to indicate whether it is currently receiving a frame. If the miniport driver is not currently receiving a frame, it returns a zero to a query of this OID. If the miniport driver is currently receiving a frame, it returns a nonzero value to a query of this OID.

OID_IRDA_RELEASE_HW_RESOURCES

The OID_IRDA_RELEASE_HW_RESOURCES OID is optional for IrDA miniport drivers and is supported only by Windows® 95/98/Me IrDA miniport drivers.

This OID requests the miniport driver to release the use of its hardware resources.

It is the responsibility of the protocol to ensure that there are no outstanding requests or sends to the miniport driver before sending this request. After the protocol sends this request, the miniport driver releases any hardware resources associated with the infrared port and assigns the information to a reply buffer. The miniport driver might also optionally assign a list of hardware ID and compatible identifiers in a PNPID member of the reply buffer. The format of this PNPID member should be a NULL terminated string. For example, a FIR miniport driver that has SHP0001 as an identifier and that also supports running as a COM port might return "SHP0001,*PNP0511" in the PNPID member of the reply buffer.

If the miniport driver has a 16550 compatible mode of operation, it must leave its infrared transceiver in that mode as a result of this request.

If the miniport driver is not operating, that is, it has not already acquired resources, it should return NDIS_STATUS_FAILURE for this request.

OID_IRDA_SUPPORTED_SPEEDS

The OID_IRDA_SUPPORTED_SPEEDS OID requests the miniport driver to return the link speeds that it supports. In response, the miniport driver returns an array of DWORDS, each of which indicates a supported speed at which the miniport driver can transmit outgoing frames and receive incoming frames. IrLAP sets OID_IRDA_LINK_SPEED to one of the supported values before passing send packets to the miniport driver.

OID_IRDA_TURNAROUND_TIME

The OID_IRDA_TURNAROUND_TIME OID requests the miniport driver to return the turnaround time (in microseconds) of its NIC's transceiver. Turnaround time is the time required for the transceiver to recover from a saturated state as the result of transmitting a bit. After the turnaround time has elapsed, the local transceiver can receive a bit transmitted by the remote transceiver.

IrLAP supplies the minimum turnaround time of the local NIC's transceiver to the remote station. After receiving a transmission from the local NIC's transceiver, the transceiver of the remote station must wait the specified minimum turnaround around time before starting a transmission.

OID_IRDA_UNICAST_LIST

The OID_IRDA_UNICAST_LIST OID is optional for most IrDA miniport drivers. Only Windows® 95/98/Me IrDA miniport drivers that maintain a UNICAST list must support this OID.

This OID requests the miniport driver to set or retrieve information in a UNICAST list. A UNICAST list is a list of the miniport driver's devices from which the miniport driver accepts frames. If the miniport driver does not support UNICAST filtering in hardware, it should not support this OID; IrLAP then performs the filtering.

For a set, this OID requests the miniport driver to only accept frames from addresses of devices in the specified UNICAST list.

For a query, this OID requests the miniport driver to return its current list of devices from which to accept frames.

If the UNICAST list is not set or contains zero elements, the miniport driver must accept all valid infrared frames. Because the size of an IrLAP media address is seven bits, the least-significant seven bits of each item in the UNICAST list specifies the address of a device. All other bits are set to zero. If IrLAP attempts to set one or more items in the UNICAST list to values greater than 0x7f, the miniport driver must not use any values in the UNICAST list.


Task Offload Objects

This section describes the OIDs that support TCP/IP task-offload operations. For a description of such operations, see NDIS Object Identifiers.

The fast forwarding path OIDs are defined in ntddndis.h. When building a driver that supports these OIDs, include ntddndis.h.

The following chart summarizes the OIDs described in this section.

Length | Q | S | Name
Arr | M | M | OID_TCP_TASK_OFFLOAD When queried, requests a miniport driver to report the task-offload capabilities of its NIC. When set, requests the miniport driver to enable the specified task-offload capabilities of its NIC.
Arr |  | M | OID_TCP_TASK_IPSEC_ADD_SA Requests a miniport driver to add one or more security associations (SAs) to its NIC.
4 |  | M | OID_TCP_TASK_IPSEC_DELETE_SA Requests a miniport driver to delete an SA from its NIC.

The following describes each of the OID_XXX listed in the preceding chart more fully.


OID_TCP_TASK_OFFLOAD

The OID_TCP_TASK_OFFLOAD OID is queried by the TCP/IP transport to determine the task-offload capabilities of a miniport driver's NIC. After determining which task-offload capabilities a NIC supports, the TCP/IP transport protocol sets this OID to enable the reported capabilities. The TCP/IP protocol can also disable all of a NIC's task-offload capabilities by setting this OID. Only one protocol at a time can enable the task-offload capabilities of a particular NIC.

Querying a NIC's Task-Offload Capabilities

When the TCP/IP transport queries OID_TCP_TASK_OFFLOAD, it supplies in the InformationBuffer an NDIS_TASK_OFFLOAD_HEADER structure. This structure specifies the task-offload version supported by the TCP/IP transport, the encapsulation format for send and receives packets processed by the TCP/IP transport, and the size of the encapsulation header in such packets. With this information, the miniport driver or its NIC can locate the beginning of the first IP header in a transmit packet, which is a prerequisite for performing an offload task.

In response to a query of OID_TCP_TASK_OFFLOAD, a miniport driver returns, in the InformationBuffer, the NDIS_TASK_OFFLOAD_HEADER structure followed immediately by one or more NDIS_TASK_OFFLOAD structures. Each NDIS_TASK_OFFLOAD structure describes a task-offload capability supported by the miniport driver's NIC. If the miniport driver's NIC supports multiple versions of a particular task-offload capability, it should return one NDIS_TASK_OFFLOAD structure for each version.

Each NDIS_TASK_OFFLOAD structure has a Task member that specifies the particular offload task to which the structure applies. Each NDIS_TASK_OFFLOAD structure also has a TaskBuffer that contains information pertinent to the specified offload task. The information in the TaskBuffer is formatted as one of the following structures:

  • NDIS_TASK_TCP_IP_CHECKSUM

    Specifies checksum offload capabilities

  • NDIS_TASK_IPSEC

    Specifies IP Security offload capabilities

  • NDIS_TASK_TCP_LARGE_SEND

    Specifies large-TCP-packet segmentation capabilities

Note If an intermediate driver modifies the contents of TCP packets that it forwards down to an underlying miniport driver such that TCP offload functions cannot be performed on the packets, the intermediate driver should respond to OID_TCP_TASK_OFFLOAD queries with a status of NDIS_STATUS_NOT_SUPPORTED instead of passing the request down to the underlying miniport.

Enabling a NIC's Task-Offload Capabilities

After querying a NIC's task-offload capabilities, the TCP/IP transport enables one or more of these capabilities by setting OID_TCP_TASK_OFFLOAD. When setting OID_TCP_TASK_OFFLOAD, the TCP/IP transport supplies in the InformationBuffer an NDIS_TASK_OFFLOAD_HEADER structure, followed immediately by an NDIS_TASK_OFFLOAD structure for each task-offload capability that the transport is enabling.

The Task in each NDIS_TASK_OFFLOAD structure indicates the offload task that the TCP/IP transport is enabling. The TCP/IP transport also enables capabilities for a particular offload task by setting members of the structure (NDIS_TASK_TCP_IP_CHECKSUM, NDIS_TASK_IPSEC, or NDIS_TASK_TCP_LARGE_SEND) in the TaskBuffer of each NDIS_TASK_OFFLOAD structure.

Changing a NIC's Task-Offload Capabilities

To change which task-offload capabilities are enabled for a NIC, the TCP/IP transport sets OID_TCP_TASK_OFFLOAD. The miniport driver must enable only those task-offload capabilities specified by the most recent set of OID_TCP_TASK_OFFLOAD. The miniport driver must disable all other task-offload capabilities.

Disabling a NIC's Task-Offload Capabilities

To disable all task-offload capabilities supported by a NIC, the TCP/IP transport sets OID_TCP_TASK_OFFLOAD, passing in the InformationBuffer only an NDIS_TASK_OFFLOAD_HEADER structure with the OffsetFirstTask member of this structure set to zero.


OID_TCP_TASK_IPSEC_ADD_SA

The OID_TCP_TASK_IPSEC_ADD_SA OID is set by the transport protocol to request that a miniport driver add one or more security associations (SAs) to its NIC.

The information for each SA is formatted as an OFFLOAD_IPSEC_ADD structure, which is defined as follows:

typedef struct _OFFLOAD_IPSEC_ADD_SA {
  IPAddr  SrcAddr;
  IPMask  SrcMask;
  IPAddr  DestAddr;
  IPMask  DestMask;
  ULONG  Protocol;
  USHORT  SrcPort;
  USHORT  DestPort;
  IPAddr  SrcTunnelAddr;
  IPAddr  DestTunnelAddr;
  USHORT  Flags;
  SHORT  NumSAs;
  OFFLOAD_SECURITY_ASSOCIATION  SecAssoc[OFFLOAD_MAX_SAS];
  NDIS_HANDLE  OffloadHandle;
  ULONG  KeyLen;
  UCHAR  KeyMat[1];
} OFFLOAD_IPSEC_ADD_SA, *POFFLOAD_IPSEC_ADD_SA;

The members of this structure contain the following information:

SrcAddr
Specifies the IP address of the source host (the host sending the packets)
SrcMask
Specifies the subnet mask for the source IP address
DestAddr
Specifies the IP address of the destination host (the host receiving the packets)
DestMask
Specifies the subnet mask for the destination IP address
Protocol
Specifies the IP protocol. Any combination of IP protocol types, such as TCP, UDP, ICMP, can be specified. The encoding of Protocol is identical to that of the Protocol field in an IP header. If Protocol is set to zero, the SA applies to any IP protocol.
SrcPort
Specifies a source TCP or UDP port. If SrcPort is set to zero, the SA applies to any source TCP/UDP port.
DestPort
Specifies a destination TCP or UDP port. If DestPort is set to zero, the SA applies to any source TCP/UDP port.
SrcTunnelAddr
Specifies the IP address for the source endpoint, such as a connector, of a tunnel. The miniport driver uses SrcTunnelAddr as the source address for the tunnel IP header of packets sent on the SA. SrcTunnelAddr is specified only for an SA that applies to the tunnel portion of a packet. SrcTunnelAddr is set to zero for an SA that applies to the transport portion of a packet.
DestTunnelAddr
Specifies the IP address for the destination endpoint, such as a connector, of a tunnel. The miniport driver uses DestTunnelAddr as the destination address for the tunnel IP header of packets sent on the SA. DestTunnelAddr is specified only for an SA that applies to the tunnel portion of a packet. DestTunnelAddr is set to zero for an SA that applies to the transport portion of a packet.
Flags
A bitmask that indicates whether the SA being added is an inbound or outbound SA as follows:
OFFLOAD_INBOUND_SA
Specifies an inbound SA.
OFFLOAD_OUTBOUND_SA
Specifies an outbound SA.
NumSAs
Specifies the number of elements in the SecAssoc array. Each element in the array is an OFFLOAD_SECURITY_ASSOCIATION structure, which is described below.
SecAssoc
Specifies a variable-length array that contains the information on the IP Security operations (AH and/or ESP) for the SA. The information for each IP Security operations is formatted as an OFFLOAD_SECURITY_ASSOCIATION structure, which is described below.

The TCP/IP transport specifies one or two OFFLOAD_SECURITY_ASSOCIATION structures in the buffer at SecAssoc. Each OFFLOAD_SECURITY_ASSOCIATION structure indicates the type of operation—authentication or encryption/decryption— for which the SA specified in the structure is to be used. The order of the OFFLOAD_SECURITY_ASSOCIATION structures in the array indicates the order in which the miniport driver should perform the operations for each SA. Only one combination of operations is supported: encryption/decryption (ESP) followed by authentication (AH).

OffloadHandle
Specifies the handle to the newly created SA. The miniport driver supplies this handle before completing the OID_TCP_TASK_IPSEC_ADD_SA request. The TCP/IP transport must specify this handle in the NDIS_IPSEC_PACKET_INFO structure before passing a send packet to the miniport driver. The TCP/IP transport must also specify this handle when deleting the SA with an OID_TCP_TASK_IPSEC_DELETE_SA request.
KeyLen
Specifies the length in bytes of the buffer at KeyMat.
KeyMat
Specifies a variable-length array that contains key(s) for the SA(s) specified at SecAssoc. If both a confidentiality (encryption/decryption) algorithm and an integrity (authentication) algorithm are specified by the ConfAlgo and IntegrityAlgo of an OFFLOAD_SECURITY_ASSOCIATION structure, the buffer at KeyMat contains key information for the confirmation algorithm first, followed immediately by key information for the integrity algorithm.

The length of each key in the buffer at KeyMat is specified by algoKeyLen in the OFFLOAD_ALGO_INFO structure that specifies the confidentiality or integrity algorithm. (An OFFLOAD_ALGO_INFO structure is a member of an OFFLOAD_SECURITY_ASSOCIATION structure.)

The first seven members of the OFFLOAD_IPSEC_ADD_SA structure (SrcAddr, SrcMask, DestAddr, DestMask, Protocol, SrcPort, and DestPort) constitute a filter that specifies the source and destination, as well as the IP protocol(s), to which the SA(s) apply. This filter pertains to a transport-mode connection—that is, an end-to-end connection between two hosts. If the specified connection is made through a tunnel, the source and destination addresses of the tunnel are specified by SrcTunnelAddr and DestTunnelAddr, respectively.

If a filter parameter is set to zero, that parameter is not used to filter packets for the specified SA(s). For example, if SrcAddr is set to zero, the specified SA(s) can apply to a packet that contains any source address. To take this to the extreme, if all the filter parameters are set to zero, the specified SA(s) apply to any source host sending any type of packet to any destination host.

The TCP/IP transport can specify an IP protocol in the Protocol member to indicate that the specified SA(s) apply only to packets of the specified protocol type. If Protocol is set to zero, the specified SA(s) apply to all packets sent from the specified source to the specified destination.

OFFLOAD_SECURITY_ASSOCIATION structure

An OFFLOAD_SECURITY_ASSOCIATION structure specifies a single security association (SA). The OFFLOAD_SECURITY_ASSOCIATION structure is an element in the SecAssoc variable-length array. SecAssoc contains one or two OFFLOAD_SECURITY_ASSOCIATION structures.

The OFFLOAD_SECURITY_ASSOCIATION structure is defined as follows:

typedef struct _OFFLOAD_SECURITY_ASSOCIATION {
  OFFLOAD_OPERATION_E  Operation;
  SPI_TYPE  SPI;
  OFFLOAD_ALGO_INFO  IntegrityAlgo;
  OFFLOAD_ALGO_INFO  ConfAlgo;
  OFFLOAD_ALGO_INFO  Reserved;
} OFFLOAD_SECURITY_ASSOCIATION, *POFFLOAD_SECURITY_ASSOCIATION;

The members of the OFFLOAD_SECURITY_ASSOCIATION structure contain the following information:

Operation
Specifies the IP security operation for which the SA is to be used. The following operations are supported:
AUTHENTICATE
Specifies that the SA is to be used for authentication (integrity checking).
ENCRYPT
Specifies that the SA is to be used for encryption/decryption (confidentiality).
SPI
Specifies the Security Parameters Index for the SA.
IntegrityAlgo
Specifies the integrity (authentication) algorithm for the SA, formatted as an OFFLOAD_ALGO_INFO structure. The OFFLOAD_ALGO_INFO structure is described below.
ConfAlgo
Specifies the confidentiality (encryption/decryption) algorithm for the SA, formatted as an OFFLOAD_ALGO_INFO structure. The OFFLOAD_ALGO_INFO structure is described below.
Reserved
This is reserved.

An SA specified for use in processing authentication headers (AH) will have an operation type of AUTHENTICATE and will have an IntegrityAlgo (integrity algorithm). The SA will not have an a ConfAlgo (confidentiality algorithm). In this case, ConfAlgo will contain zeros.

An SA specified for use in processing encapsulating security payloads (ESPs) will have an operation type of ENCRYPT and may have an IntegrityAlgo (integrity algorithm) and/or a ConfAlgo (confidentiality algorithm).

OFFLOAD_ALGO_INFO structure

The OFFLOAD_ALGO_INFO structure, which is a member of an OFFLOAD_SECURITY_ASSOCIATION structure, specifies an algorithm used for a security association (SA).

The OFFLOAD_ALGO_INFO structure is defined as follows:

typedef struct _OFFLOAD_ALGO_INFO {
  ULONG  algoIdentifier;
  ULONG  algoKeylen;
  ULONG  Reserved;
} OFFLOAD_ALGO_INFO, *POFFLOAD_ALGO_INFO;

The members of an OFFLOAD_ALGO_INFO structure contain the following information:

algoIdentifier
Specifies the confidentiality or integrity algorithm used for the SA.

If the algorithm is a confidentiality algorithm (that is, if the OFFLOAD_ALGO_INFO structure is specifying a ConfAlgo), algoIdentifier can be any of the following values:

OFFLOAD_IPSEC_CONF_NONE
Specifies no confidentiality algorithm. Used for null encryption—that is, when a packet is not encrypted but its ESP header contains authentication information.
OFFLOAD_IPSEC_CONF_DES
Specifies the DES algorithm.
OFFLOAD_IPSEC_CONF_3_DES
Specifies the triple-DES algorithm.

If the algorithm is an integrity algorithm (that is, if the OFFLOAD_ALGO_INFO structure is specifying an IntegrityAlgo), algoIdentifier can be either of the following values:

OFFLOAD_IPSEC_INTEGRITY_NONE
Specifies no integrity algorithm. Used when the ESP header contains no authentication information.
OFFLOAD_IPSEC_INTEGRITY_MD5
Specifies the keyed MD5 algorithm.
OFFLOAD_IPSEC_INTEGRITY_SHA
Specifies the SHA 1 algorithm.
algoKeylen
Specifies in bytes the length of the key for the algorithm. The key is contained in the buffer at KeyMat¸ which is the variable-length array specified in the OFFLOAD_IPSEC_ADD_SA structure.

If only an integrity algorithm (IntegrityAlgo) is specified in the OFFLOAD_SECURITY_ASSOCIATION structure, algoKeylen indicates the length of the key for the integrity algorithm, starting from the beginning of the buffer at KeyMat.

If both an integrity and a confidentiality algorithm (IntegrityAlgo and ConfAlgo) are specified, algoKeylen for the integrity algorithm indicates the length of the key for the integrity algorithm, starting from the beginning of the buffer at KeyMat. The algoKeylen for the confidentiality algorithm, in this case, indicates the length of the key for the confidentiality algorithm, starting the from the end of the key for the integrity algorithm.

Reserved
This is reserved.


OID_TCP_TASK_IPSEC_DELETE_SA

The OID_TCP_TASK_IPSEC_DELETE_SA OID is set by a transport protocol to request that a miniport driver delete a security association (SA) from its NIC. The SA information is formatted as an OFFLOAD_IPSEC_DELETE structure, which is defined as follows:

typedef struct _OFFLOAD_IPSEC_DELETE_SA {
  ULONG  OffloadHandle;
} OFFLOAD_IPSEC_DELETE_SA, *POFFLOAD_IPSEC_DELETE_SA;

The members of this structure contain the following information:

OffloadHandle
Specifies the handle for the SA to be deleted.

On receiving this request, the miniport driver should delete the specified SA from the NIC and free any system resources allocated for the SA.


802.11 Wireless LAN Objects

The 802.11 wireless LAN (WLAN) object identifiers (OIDs), which are supported by NDIS 5.1, are available through Windows® Management Instrumentation (WMI). Miniport drivers for 802.11 NICs must support all mandatory WLAN OIDs.

The wireless LAN OIDs are defined in ntddndis.h. When building a driver that supports these OIDs, include ntddndis.h.

The following table provides a summary of the WLAN OIDs.

Length | Q | S | Indication | Name
6 | M | M |  | OID_802_11_BSSID
36 | M | M |  | OID_802_11_SSID
4 + Arr(4) | O |  |  | OID_802_11_NETWORK_TYPES_SUPPORTED
4 | M | M |  | OID_802_11_NETWORK_TYPE_IN_USE
4 | O | O |  | OID_802_11_POWER_MODE
4 | O | O |  | OID_802_11_TX_POWER_LEVEL
4 | M |  | M | OID_802_11_RSSI
4 | O | O |  | OID_802_11_RSSI_TRIGGER
4 + Arr(88) | M |  |  | OID_802_11_BSSID_LIST
0 |  | M |  | OID_802_11_BSSID_LIST_SCAN
4 | M | M |  | OID_802_11_INFRASTRUCTURE_MODE
4 | O | O |  | OID_802_11_FRAGMENTATION_THRESHOLD
4 | O | O |  | OID_802_11_RTS_THRESHOLD
4 | O |  |  | OID_802_11_NUMBER_OF_ANTENNAS
4 | O | O |  | OID_802_11_RX_ANTENNA_SELECTED
4 | O | O |  | OID_802_11_TX_ANTENNA_SELECTED
4 + Arr(4) | M |  |  | OID_802_11_SUPPORTED_RATES
4 + Arr(4) | O | O |  | OID_802_11_DESIRED_RATES
16 | M | M |  | OID_802_11_CONFIGURATION
100 | O |  |  | OID_802_11_STATISTICS
12 + Arr(1) |  | M |  | OID_802_11_ADD_WEP
4 | M | M |  | OID_802_11_WEP_STATUS
4 |  | M |  | OID_802_11_REMOVE_WEP
0 |  | M |  | OID_802_11_DISASSOCIATE
4 | M | M |  | OID_802_11_AUTHENTICATION_MODE
4 | O | O |  | OID_802_11_PRIVACY_FILTER
4 |  | M |  | OID_802_11_RELOAD_DEFAULTS

The following topics describe the preceding OIDs and the data structures that are associated with them.


OID_802_11_BSSID

When set, the OID_802_11_BSSID OID requests a miniport driver to set the media access control (MAC) address of the access point associated with the NIC to a specified value.

When queried, this OID requests the miniport driver to return the MAC address of the associated access point. The miniport driver should return an error code of NDIS_STATUS_ADAPTER_NOT_READY if the NIC is not associated with an access point.

This OID uses the NDIS_802_11_MAC_ADDRESS array, which is defined as follows:

typedef UCHAR    NDIS_802_11_MAC_ADDRESS[6];


OID_802_11_SSID

When set, the OID_802_11_SSID OID requests the miniport driver to set its NIC's service set identifier (SSID) to a specified value. The SSID identifies a group of interconnected basic service sets. Setting an SSID results in:

  • disassociating the NIC from any SSID with which it might be associated.
  • turning on the radio if the radio is OFF.
  • setting the SSID with the specified value or setting it to any SSID if the SSID is not specified.
  • attempting to associate the NIC with the new SSID.

When queried, this OID requests the miniport driver to return the with which its NIC is associated. If the NIC is not associated with SSID, the miniport driver returns the value from the last OID_802_11_SSID set or, if that was an empty string, it returns the SSID of the last access point with which the NIC was associated.

This OID uses the NDIS_802_11_SSID structure, which is defined as follows:

typedef UCHAR    NDIS_802_11_SSID;
{
  ULONG      SsidLength;
  UCHAR      Ssid[32];
} NSID_802_11_SSID, *PNDIS_802_11_SSID;

The members of this structure contain the following information:

SsidLength
Specifies the length of the Ssid member in octets.
Ssid
Specifies the SSID. An empty string (that is, a string with the first byte set to zero) requests the 802.11 NIC to associate with any available SSID.


OID_802_11_NETWORK_TYPES_SUPPORTED

The OID_802_11_NETWORK_TYPES_SUPPORTED OID requests the miniport driver to return an array of all physical layer network subtypes that the 802.11 NIC and the driver support.

This OID uses the NDIS_802_11_NETWORK_TYPE_LIST structure, which is defined as follows:

typedef struct _NDIS_802_11_NETWORK_TYPE_LIST {
  ULONG  NumberOfItems;
  NDIS_802_11_NETWORK_TYPE NetworkType [1];
} NDIS_802_11_NETWORK_TYPE_LIST, *PNDIS_802_11_NETWORK_TYPE_LIST;

The members of this structure contain the following information:

NumberOfItems
Specifies the number of items in the in NetworkType array. This array must contain at least one item.
NetworkType
Specifies an array of physical layer network subtypes. The NDIS_802_11_NETWORK_TYPE enumeration defines values to assign to the physical layer network subtypes.

The following network subtypes are defined:

Ndis802_11FH
Indicates the physical layer of the frequency-hopping spread-spectrum radio.
Ndis802_11DS
Indicates the physical layer for the direct sequencing spread-spectrum radio.


OID_802_11_NETWORK_TYPE_IN_USE

When set, the OID_802_11_NETWORK_TYPE_IN_USE OID requests the miniport driver to set type information about the physical layer network used by the 802.11 NIC to a specified value.

When queried, this OID requests the miniport driver to return the type information.

The NDIS_802_11_NETWORK_TYPE enumeration specifies network subtype values for the physical layer. The network subtypes are defined as follows:

Ndis802_11FH
Indicates the physical layer of the frequency hopping spread-spectrum radio.
Ndis802_11DS
Indicates the physical layer of the direct sequencing spread-spectrum radio.


OID_802_11_POWER_MODE

When set, the OID_802_11_POWER_MODE OID requests the miniport driver to set the power mode of the 802.11 NIC to the specified value.

When queried, this OID requests that the miniport driver return the power mode of the 802.11 NIC.

The power modes that can be assigned to the 802.11 NIC are defined in the NDIS_802_11_POWER_MODE enumeration as follows:

Ndis802_11PowerModeCAM
Specifies continuous access mode (CAM). When the power mode is set to CAM, the device is always on.
Ndis802_11PowerModeMAX_PSP
Specifies maximum (MAX) power saving. A power mode of MAX results in the greatest power savings for the 802.11 NIC radio.
Ndis802_11PowerModeFast_PSP
Specifies fast power-saving mode. This power mode provides the best combination of network performance and power usage.


OID_802_11_TX_POWER_LEVEL

When set, the OID_802_11_TX_POWER_LEVEL OID requests the miniport driver to set the transmit power level of the 802.11 NIC to a specified value. The NDIS_802_11_TX_POWER_LEVEL value is specified in milliwatts (mW).

When queried, this OID requests the miniport driver to return the transmit power level of the 802.11 NIC.

The NDIS_802_11_TX_POWER_LEVEL value is defined as follows:

typedef ULONG   NDIS_802_11_TX_POWER_LEVEL;

Note The 802.11 NIC will not exceed regulatory power limits.


OID_802_11_RSSI

The OID_802_11_RSSI OID requests the miniport driver to return the received signal strength indication (RSSI) in response to a query or as a status indication event. The RSSI is measured in dBm and is defined as follows:

typedef LONG  NDIS_802_11_RSSI;

If status indications are enabled with OID_802_11_RSSI_TRIGGER, the miniport driver must call NdisMIndicateStatus to provide notification values according to the RSSI that was specified in the OID_802_11_RSSI_TRIGGER set. Normal values for the RSSI value are between -10 and -200.

For more information about the RSSI value and how an RSSI status indication is triggered, see OID_802_11_RSSI_TRIGGER .


OID_802_11_RSSI_TRIGGER

When set, the OID_802_11_RSSI_TRIGGER OID requests the miniport driver to set the RSSI trigger value. This value determines when an RSSI status indication event will occur.

When queried, this OID requests the miniport driver to return the RSSI trigger setting.

The trigger value contains the RSSI measurement in units of dBm and is defined as follows:

typedef LONG  NDIS_802_11_RSSI;

When a status indication triggers, the miniport driver calls NdisMIndicateStatus with the GeneralStatus parameter set to NDIS_STATUS_MEDIA_SPECIFIC_INDICATION. In addition, the StatusBuffer passed to NdisMIndicateStatus points to an NDIS_802_11_RSSI buffer.

If the trigger value is less than the current RSSI value, the status indication triggers when the current value is less than or equal to the trigger value. If the trigger value is greater than the current value, the indication triggers when the current value is greater than or equal to the trigger value. If the trigger value is equal to the current value, the indication triggers immediately.


OID_802_11_BSSID_LIST

The OID_802_11_BSSID_LIST OID requests the miniport driver to return a list containing all BSSIDs and their attributes, as listed in the 801.11 NIC's database. This list contains all the BSSs that the NIC detected during its most recent survey of BSSs. The miniport driver should respond immediately to this OID.

Note If this OID is called while the NIC is active without a preceding OID_802_11_BSSID_LIST_SCAN, it might return a list of BSSIDs limited to those IDs included in the NIC's current configuration. However, if this OID is called at least six seconds after OID_802_11_BSSID_LIST_SCAN, the list of BSSIDs should contain all the BSSIDs found during the OID_802_11_BSSID_LIST_SCAN.

This OID uses the NDIS_802_11_BSSID_LIST structure, which is defined as follows:

typedef_struct _NDIS_802_11_BSSID_LIST
{
 ULONG  NumberOfItems;
 NDIS_WLAN_BSSID  Bssid[1];
} NDIS_802_11_BSSID_LIST, *PNDIS_802_11_BSSID_LIST;

The members of this structure contain the following information:

NumberOfItems
Specifies the number of items contained in the Bssid array. This array must contain at least one item.
Bssid
Specifies an array of NDIS_WLAN_BSSID structures. An NDIS_WLAN_BSSID structure is defined as follows:
struct _NDIS_WLAN_BSSID
{
 ULONG  Length;
 NDIS_802_11_MAC_ADDRESS  MacAddress;
 Uchar  Reserved[2];
 NDIS_802_11_SSID  Ssid;
 ULONG  Privacy;
 NDIS_802_11_RSSI  Rssi;
 NDIS_802_11_NETWORK_TYPE  NetworkTypeInUse;
 NDIS_802_11_CONFIGURATION  Configuration;
 NDIS_802_11_NETWORK_INFRASTRUCTURE  InfrastructureMode;
 NDIS_802_11_RATES  SupportedRates;
} NDIS_WLAN_BSSID, *PNDIS_WLAN_BSSID;

The members of this structure contain the following information:

Length
Specifies the length of the NDIS_WLAN_BSSID structure in bytes.
MacAddress.
Specifies a media access control (MAC) address. Each access point has a unique MAC address that is the same as the BSSID.
Reserved
Reserved. Do not use. This member maintains the DWORD alignment of the structure.
Ssid
Specifies an SSID as defined in the NDIS_802_11_SSID structure. For more information about this structure, see OID_802_11_SSID.
Privacy
Specifies a WEP encryption requirement.
Rssi
Specifies the Received Signal Strength Indication (RSSI) in dBm.
NetworkTypeInUse
Specifies the network type as defined in the NDIS_802_11_NETWORK_TYPE enumeration. For more information about this enumeration, see OID_802_11_NETWORK_TYPE_IN_USE.
Configuration
Specifies the radio parameter configuration as defined in the NDIS_802_11_CONFIGURATION structure. For more information about this structure, see OID_802_11_CONFIGURATION.
InfrastructureMode
Specifies the infrastructure mode as defined in the NDIS_802_11_NETWORK_INFRASTRUCTURE enumeration. For more information about this enumeration, see OID_802_11_INFRASTRUCTURE_MODE.
SupportedRates
Specifies a set of supported rates defined in an NDIS_802_11_RATES array. For more information about this array, see OID_802_11_SUPPORTED_RATES.


OID_802_11_BSSID_LIST_SCAN

The OID_802_11_BSSID_LIST_SCAN OID requests the miniport driver to direct the 802.11 NIC to request a survey of BSSs. No data is associated with this OID. The NIC will use the following parameters, set as defined in the 802.11 specifications, in its request:

  • BSSType indicates that both the infrastructure BSS and independent BSS are used.
  • BSSID indicates that the BSSID is broadcast.
  • SSID indicates that the SSID is broadcast.
  • ScanType indicates active, passive, or a combination of both passive and active scanning approaches.
  • ChannelList indicates all permitted frequency channels.

The NIC use active or passive scanning methods or a combination of both passive and active scanning methods to perform a scan. It might also refresh the list of BSSIDs in its database.

The NIC should minimize the response time for this OID. Active scanning is preferred, when possible.

The NIC's database includes BSSIDs for all BSS's responding on frequency channels that are permitted in the region in which the NIC is operating.

Note If the NIC is associated with a particular BSSID and SSID that are not contained in the list of BSSIDs generated by this scan, the BSSID description of the currently associated BSSID and SSID should be appended to the list of BSSIDs in the NIC's database.

Note This OID might be called very frequently (for example, every five seconds). Miniport drivers should minimize the performance impact of servicing this OID. A query of this OID should not cause the NIC to associate with a different access point.


OID_802_11_INFRASTRUCTURE_MODE

When set, the OID_802_11_INFRASTRUCTURE_MODE OID requests the miniport driver to set the 802.11 NIC's infrastructure mode to a specified value. The infrastructure mode determines how the 802.11 NIC connects to the network. Setting the infrastructure mode resets the network association algorithm.

When queried, this OID requests the miniport driver to return the 802.11 NIC's infrastructure mode setting.

This OID uses the NDIS_802_11_NETWORK_INFRASTRUCTURE enumeration, which is defined as follows:

Ndis802_11IBSS
Specifies the independent basic service set (IBSS) mode. This mode is also known as ad hoc mode.
Ndis802_11Infrastructure
Specifies the infrastructure mode.
Ndis802_11AutoUnknown
Specifies an automatic mode. In this mode, the 802.11 NIC can switch between ad hoc and infrastructure modes as required.


OID_802_11_FRAGMENTATION_THRESHOLD

When set, the OID_802_11_FRAGMENTATION_THRESHOLD OID requests that the miniport driver set the NIC's packet fragmentation threshold to a specified value. The fragmentation threshold, which is specified in bytes, determines whether packets will be fragmented and at what size. On an 802.11 wireless LAN, packets that are larger than the fragmentation threshold are fragmented. Packets that are smaller than the specified fragmentation threshold value are not fragmented. A fragmentation threshold of zero indicates that the NIC should not fragment packets.

When queried, this OID requests the miniport driver to return the fragmentation threshold setting.

The fragmentation threshold is defined as follows:

typedef  ULONG   NDIS_802_11_FRAGMENTATION_THRESHOLD;


OID_802_11_RTS_THRESHOLD

When set, the OID_11_RTS_THRESHOLD OID requests the miniport driver to set the Request To Send (RTS) threshold to a specified value. This value, which is specified in bytes, specifies the packet size beyond which the 802.11 wireless LAN invokes its RTS/CTS mechanism. Packets that exceed the specified RTS threshold trigger the RTS/CTS mechanism. The NIC transmits smaller packets without using RTS/CTS. An RTS threshold value of zero indicates that the NIC should transmit all packets using RTS/CTS.

When queried, this OID requests the miniport driver to return its NIC's RTS threshold setting.

The RTS threshold is defined as follows:

typedef  ULONG   NDIS_802_11_RTS_THRESHOLD;


OID_802_11_NUMBER_OF_ANTENNAS

The OID_802_11_NUMBER_OF_ANTENNAS OID requests the miniport driver to return the number of antennas on the NIC's radio. The number of antennas is returned in a value of type ULONG.


OID_802_11_RX_ANTENNA_SELECTED

When set, the OID_802_11_RX_ANTENNA_SELECTED OID requests the miniport driver to set, to a specified value, the antenna number that identifies the currently selected receive (RX) antenna. A value of 0xffffffff indicates that all antennas are selected. In other words, a value of 0xffffffff indicates that the wireless LAN is in a state of "diversity."

When queried, this OID requests the miniport driver to return the antenna number that identifies the currently selected receive antenna.

The antenna number is defined as follows:

typedef  ULONG   NDIS_802_11_ANTENNA;


OID_802_11_TX_ANTENNA_SELECTED

When set, the OID_802_11_TX_ANTENNA_SELECTED OID requests the miniport driver to set, to a specified value, the antenna number that identifies the currently selected transmit (TX) antenna. A value of 0xffffffff indicates that all TX antennas are selected. In other words, a value of 0xffffffff indicates that the wireless LAN is in a state of "diversity."

When queried, this OID requests the miniport driver to return the antenna number that identifies the currently selected transmit antenna.

The antenna value is defined as follows:

typedef  ULONG   NDIS_802_11_ANTENNA;


OID_802_11_SUPPORTED_RATES

The OID_802_11_SUPPORTED_RATES OID requests the miniport driver to return its NIC's data rate set, which includes the data rates that the NIC's radio supports.

Data rate sets are encoded as eight octets; each of which describes a single rate in units of 0.5 Mbps. Rates from the 802.11 BSSBasicRateSet that are included in the supported rates are used for control and broadcast frames.

Each supported rate from the BSSBasicRateSet is encoded as an octet with the most significant bit (bit 7) set to 1. For example, a 1 Mbps rate in the BSSBasicRateSet is encoded as 0x82.

Rates that are not included in the BSSBasicRateSet are encoded with the most significant bit set to zero. For example, a 2 Mbps rate that does not belong to the BSSBasicRateSet is encoded as 0x04.

This OID uses the NDIS_802_11_RATES array, which is defined as follows:

typedef  UCHAR   NDIS_802_11_RATES[8];

The rates array contains a set of eight octets. Each octet contains a desired data rate in units of .5 Mbps.


OID_802_11_DESIRED_RATES

When set, the OID_802_11_DESIRED_RATES OID requests the miniport driver to set its NIC's set of data transmission rates to the values specified in an array. This array specifies the rates that are desirable for operation within the current wireless network.

When queried, this OID requests the miniport driver to return its NIC's set of data transmission rates.

This OID uses the NDIS_802_11_RATES array. This array is defined as follows:

typedef  UCHAR   NDIS_802_11_RATES[8];

This array contains a set of 8 octets. Each octet specifies a desired data rate in units of 0.5 Mbps.

The 802.11 network might transmit packets at rates other than the basic rates. The NIC can receive data at rates other than the rates included in the BSSBasicRateSet. For a description of the supported rates, see OID_802_11_SUPPORTED_RATES.


OID_802_11_CONFIGURATION

When set, the OID_802_11_CONFIGURATION OID requests the miniport driver to set the NIC's radio configuration parameters to specified values.

When queried, this OID requests the miniport driver to return the NIC's current radio configuration.

This OID uses an NDIS_802_11_CONFIGURATION structure, which describes the configuration of a radio. This structure is defined as follows:

typedef struct _NDIS_802_11_CONFIGURATION {
 ULONG Length;
 ULONG BeaconPeriod;
 ULONG ATIMWindow;
 ULONG DSConfig;
 NDIS_802_11_CONFIGURATION_FH FHConfig;
} NDIS_802_11_CONFIGURATION, *PNDIS_802_11_CONFIGURATION;

The members of this structure contain the following information:

Length
Specifies the length of the NDIS_802_11_CONFIGURATION structure in bytes.
BeaconPeriod
Specifies the interval between beacon message transmissions. This value is specified in Kμsec (1024 μsec).
ATIMWindow

Specifies the announcement traffic information message (ATIM) window in Kμsec (1024 μsec). The ATIM window is a short time period immediately after the transmission of each beacon in an IBSS configuration. During the ATIM window, any station can indicate the need to transfer data to another station during the following data-transmission window.

DSConfig
Specifies the frequency of the selected channel in kHz.
FHConfig
Specifies the frequency hopping configuration in an NDIS_802_11_CONFIGURATION_FH structure.

The NDIS_802_11_CONFIGURATION_FH structure is defined as follows:

typedef struct _NDIS_802_11_CONFIGURATION_FH {
 ULONG Length;
 ULONG HopPattern;
 ULONG HopSet;
 ULONG DwellTime;
} NDIS_802_11_CONFIGURATION_FH, *PNDIS_802_11_CONFIGURATION_FH;

The members of this structure contain the following information:

Length
Specifies the length of the NDIS_802_11_CONFIGURATION_FH structure in bytes.
HopPattern
Specifies the hop pattern used to determine the hop sequence. As defined by the 802.11 standard, the layer management entity (LME) of the physical layer uses a hop pattern to determine the hop sequence.
HopSet
Specifies a set of patterns. The LME of the physical layer uses these patterns to determine the hop sequence.
DwellTime
Specifies the maximum period of time during which the transmitter should remain fixed on a channel. This interval is described in Kμsec (1024 μsec).


OID_802_11_STATISTICS

The OID_802_11_STATISTICS OID requests the miniport driver to return the current statistics for the 802.11 interface. These statistics are described by an NDIS_802_11_STATISTICS structure, defined as follows:

typedef struct _NDIS_802_11_STATISTICS
{
 ULONG Length;
 LARGE_INTEGER TransmittedFragmentCount;
 LARGE_INTEGER MulticastTransmittedFrameCount;
 LARGE_INTEGER FailedCount;
 LARGE_INTEGER RetryCount;
 LARGE_INTEGER MultipleRetryCount;
 LARGE_INTEGER RTSSuccessCount;
 LARGE_INTEGER RTSFailureCount;
 LARGE_INTEGER ACKFailureCount;
 LARGE_INTEGER FrameDuplicateCount;
 LARGE_INTEGER ReceivedFragmentCount;
 LARGE_INTEGER MulticastReceivedFrameCount;
 LARGE_INTEGER FCSErrorCount;
} NDIS_802_11_STATISTICS, *PNDIS_802_11_STATISTICS;

The members of this structure contain the following information:

Length
Specifies the length of the NDIS_802_11_STATISTICS structure in bytes.
TransmittedFragmentCount
Indicates the number of data and management fragments that the NIC has successfully transmitted.
MulticastTransmittedFrameCount
Indicates the number of frames that the NIC has transmitted by multicast or broadcast. This count is incremented each time that the multicast/broadcast bit is set in the destination MAC address of a transmitted frame.
FailedCount
Indicates the number of NIC frame transmissions that failed after exceeding either the short frame or the long frame retry limits.
RetryCount
Indicates the number of frames that the NIC successfully retransmitted after one or more retransmission attempts.
MultipleRetryCount
Indicates the number of frames that the NIC successfully retransmitted after more than one retransmission attempt.
RTSSuccessCount
Indicates the number of times that the NIC received a CTS in response to an RTS.
RTSFailureCount
Indicates the number of times that the NIC did not receive a CTS in response to an RTS.
ACKFailureCount
Indicates the number of times that the NIC expected an ACK that was not received.
FrameDuplicateCount
Indicates the number of duplicate frames that were received. The sequence control field in the frameidentifies duplicate frames.
ReceivedFragmentCount
Indicates the number of data and management fragments that the NIC has successfully received. This count is incremented each time that either a data fragment or a management fragment is received.
MulticastReceivedFrameCount
Indicates the number of received frames that were set to multicast or broadcast. This count is incremented each time the NIC receives a frame with the multicast/broadcast bit set in the destination MAC address.
FCSErrorCount
Indicates the number of frames the NIC received that contained FCS errors.


OID_802_11_ADD_WEP

The OID_802_11_ADD_WEP OID requests the miniport driver to set an 802.11 wired equivalent privacy (WEP) key to a specified value. A WEP key can be a "pre-shared" key (a key that is provided to the NICs before use) for authentication, encryption, or both.

There are two types of WEP keys:

per-client key
A per-client key is used by the client to send information to the access point.
global key
A global key is used to send broadcast and multicast packets to all clients that are communicating with an access point. A global key can also be used to send unicast packets to and from the client. There must be a minimum of four global keys supported by the NIC.

A WEP key is described by the NDIS_802_11_WEP structure, which is defined as follows:

typedef struct _NDIS_802_11_WEP
{
 ULONG Length;
 ULONG KeyIndex;
 ULONG KeyLength;
 UCHAR KeyMaterial [1];
} NDIS_802_11_WEP, *PNDIS_802_11_WEP;

The members of this structure contain the following information:

Length
Specifies the length of the NDIS_802_11_WEP structure in bytes.
KeyIndex
Specifies which key to add or remove. The global keys are represented by values of zero to n. When the most significant bit is set to 1, it indicates the key used to transmit to the access point.
KeyLength
Specifies the length of the KeyMaterial character array in bytes.
KeyMaterial
Specifies an arraythat identifies the WEP key. The length of this array is variable and depends upon the value of the KeyLength member.

Note When this OID sets the same index twice, the miniport driver should overwrite the previous WEP key at that index.

Note The underlying miniport driver and its NIC should not maintain WEP keys in permanent storage (disk, registry, flash or other). WEP keys should be discarded immediately after any of the following events:

  • after the NIC disassociates itself from all basic service set identifiers (BSSIDs)
  • if shared key authentication using the WEP key fails
  • when the driver is unloaded


OID_802_11_REMOVE_WEP

The OID_802_11_REMOVE_WEP OID requests the miniport driver to remove the wired equivalent privacy (WEP) key at the specified key index. The key index is defined as follows:

typedef  ULONG    NDIS_802_11_KEY_INDEX;

For more information about the WEP key, see OID_802_11_ADD_WEP.


OID_802_11_WEP_STATUS

When set, the OID_802_11_WEP_STATUS OID requests the miniport driver to set its NIC's 802.11 WEP status to enabled or disabled. The NIC must have the WEP key for MPDU transmission with encryption before it can set the WEP status. If the NIC cannot set the WEP status, the miniport driver should return an NDIS_STATUS value of NDIS_STATUS_NOT_ACCEPTED.

When queried, this OID requests the miniport driver to return its NIC's 802.11 WEP status indication. In response to this query, the miniport driver can indicate that WEP status is enabled or disabled, that the WEP key is absent, or that WEP is not supported:

  • A response indicating that WEP is enabled or disabled implies that the WEP key is available for the NIC to encrypt data. In other words, the WEP key is available for MPDU transmission with encryption.
  • A response indicating that WEP is not supported implies that the NIC does not support the desired WEP. In other words, the NIC is not capable of encrypting data and WEP cannot be enabled or disabled.
  • A response indicating that the WEP key is absent implies that the WEP key is not available for the NIC to encrypt data and, therefore, that WEP cannot be enabled or disabled. This implies that, while one or more WEP keys may be available, the NIC does not have a WEP key for MPDU transmission with encryption.

The NDIS_802_NDIS_802_11_WEP_STATUS enumeration defines the WEP status values as follows:

Ndis802_11WEPEnabled
Indicates that WEP is enabled.
Ndis802_11WEPDisabled
Indicates that WEP is disabled.
Ndis802_11WEPKeyAbsent
Indicates that the WEP key is absent.
Ndis802_11WEPNotSupported
Indicates that the WEP key is not supported.


OID_802_11_DISASSOCIATE

The OID_802_11_DISASSOCIATE OID requests the miniport driver to command its NIC to disassociate from the current service set and turn off the radio. No data is associated with this OID.

If the NIC is associated with an access point when the miniport driver receives this OID, then the miniport driver should indicate a disconnect event upon a successful disassociation.

The miniport driver should maintain a list of the current service set Ids (SSIDs). Once a NIC has disassociated from an SSID, it should not use it again until it has associated with all other SSIDs or until OID_802_11_INFRASTRUCTURE_MODE has been set. If the NIC is not associated with an access point, the miniport driver should return an error code of NDIS_STATUS_ADAPTER_NOT_READY in response to OID_802_11_DISASSOCIATE.


OID_802_11_AUTHENTICATION_MODE

When set, the OID_802_11_AUTHENTICATION_MODE OID requests the miniport driver to set its NIC's 802.11 authentication mode to a specified value.

When queried, this OID requests the miniport driver to return its NIC's 802.11 authentication mode.

The NDIS_802_11_AUTHENTICATION_MODE enumeration defines the authentication modes as follows:

Ndis802_11AuthModeOpen
Specifies 802.11 open authentication mode. There are no checks when accepting clients in this mode.
Ndis802_11AuthModeShared
Specifies 802.11 shared authentication that uses a pre-shared wired equivalent privacy (WEP) key.
Ndis802_11AuthModeAutoSwitch
Specifies auto-switch mode. When using auto-switch mode, the NIC tries 802.11 shared authentication mode first. If shared mode fails, the NIC attempts to use 802.11 open authentication mode.


OID_802_11_PRIVACY_FILTER

When set, the OID_802_11_PRIVACY_FILTER OID requests the miniport driver to set its NIC's 802.1X privacy filter mode to a specified value.

When queried, this OID requests the miniport driver to return the setting of its NIC's 802.1X privacy filter mode.

The NDIS_802_11_PRIVACY_FILTER enumeration defines the authentication modes as follows:

Ndis802_11PrivFilterAcceptAll
Specifies an open mode. In this mode, the NIC accepts any packet if the packet is not encrypted or if the NIC successfully decrypts it.
Ndis802_11PrivFilter8021xWEP
Specifies a filtering mode. In the 802.1X filtering mode, 802.1X packets are accepted even if they are not encrypted. However, the NIC accepts nothing else unless it is encrypted using WEP.


OID_802_11_RELOAD_DEFAULTS

The OID_802_11_RELOAD_DEFAULTS OID requests the miniport driver to reload the available defaults of a specified type.

For example, when the reload defaults value is set to Ndis802_11ReloadWEPKeys, the miniport driver should reload the available default WEP key settings from permanent storage. (Permanent storage may be a Windows registry key or flash settings on the NIC device.) This ensures that the WEP key settings in the NIC's running configuration return to the same values as those loaded from permanent storage during the initialization of the NIC from power on.

The NDIS_802_11_RELOAD_DEFAULTS enumeration defines the available reload options as follows:

Ndis802_11ReloadWEPKeys
Specifies that the driver should reload available default WEP keys from permanent storage.


TDI Transport Driver Dispatch Routines

Like any other standard kernel-mode intermediate driver, a TDI transport driver can have several Dispatch routines, up to one for each system-defined IRP_MJ_XXX code that the driver must handle.

This section describes the set of I/O requests for which every transport driver that supports the TDI interface must provide one or more TdiDispatchXxx routines, and it describes the relevant members of each such IRP input to those routines.

For more information about the architecture of standard kernel-mode intermediate drivers and the functionality of their Dispatch routines, see Kernel-Mode Driver Components.

The following TdiDispatchXxx routines are described in alphabetic order. For your convenience, this section describes a separate TdiDispatchXxx routine for each IRP_MJ_XXX that any transport driver must handle in order to support the TDI interface.


TdiDispatchCleanup

The TdiDispatchCleanup routine completes any outstanding IRPs for an address, connection endpoint, or control channel that is about to be closed.

NTSTATUS
  TdiDispatchCleanup(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Pointer to the device object created by the TDI transport.
Irp
Pointer to an IRP with IRP_MJ_CLEANUP set as the MajorFunctionCode in the I/O stack location of the transport driver.

A transport calls IoGetCurrentIrpStackLocation with the given Irp to get a pointer to its own stack location in the IRP, shown in the following list as IrpSp. TdiDispatchCleanup can use the information set in the following members of the IRP in processing a cleanup request:

IoStatus.Status
Specifies the final status of the cleanup operation. The transport sets this member to the same value that will be returned by TdiDispatchCleanup. (IoStatus.Information is set to zero.)
IrpSp->MajorFunction
Specifies IRP_MJ_CLEANUP. The transport can ignore this member if it exports a TdiDispatchCleanup routine that handles only cleanup requests.
IrpSp->FileObject
Pointer to the open file object representing an address, connection endpoint, or control channel. The transport driver uses the values of the FsContext and possibly FsContext2 fields in this file object to access the state that TdiDispatchCreate originally set up for the address, connection endpoint, or control channel when the file object was opened by the client.

Return Value

TdiDispatchCleanup returns STATUS_SUCCESS when its cleanup operation is done and the transport has completed any pending IRPs it was holding queued for the address, connection endpoint, or control channel.

Comments

TdiDispatchCleanup runs when the I/O Manager is closing the last handle to an open file object representing an address, connection endpoint, or control channel. TdiDispatchCleanup is responsible for completing any IRPs currently held in the transport that reference the open file object.

When the I/O Manager is removing its last reference to such a file object handle, it calls TdiDispatchClose. In other words, the I/O Manager always submits an IRP_MJ_CLEANUP request to a transport before it submits an IRP_MJ_CLOSE request for a particular file object.

Cleaning up for an address, connection endpoint, or control channel is an inherently synchronous operation. TdiDispatchCleanup can block waiting for internal driver functions to handle particular cleanup subtasks, but TdiDispatchCleanup must complete the input cleanup IRP itself.

Closing the handle to a file object that represents an address cancels the use of a transport address previously opened by a client. On receipt of a cleanup request for which the FileObject represents an address, the transport does the following:

  • Completes any pending requests directed to the address
  • Deregisters any client event handlers registered on the address
  • Optionally releases the driver-allocated state set up to track the address, unless the transport defers resource deallocation to TdiDispatchClose

On return from TdiDispatchCleanup, the transport holds no outstanding IRPs queued for the address, but the driver can have outstanding references of its own to the file object representing that address, particularly if TdiDispatchCleanup did not release the driver-allocated context at FsContext and FsContext2 in the file object.

TdiDispatchCleanup can be called to close a connection endpoint even if the client has not made a request to disassociate the connection from the previously associated address. On receipt of a cleanup request for which the FileObject represents a connection endpoint, the transport does the following:

  • Cancels any active connection associated with the endpoint
  • If necessary, simulates the effects of a disassociation between the connection endpoint and the associated address
  • Deregisters any client event handlers registered on the address associated with the connection
  • Completes any pending requests directed to the connection
  • Optionally releases the driver-allocated state set up to track the connection, unless the transport defers resource deallocation to TdiDispatchClose

On return from TdiDispatchCleanup, the transport holds no outstanding sends or receives queued for the connection endpoint, but the driver can have outstanding references of its own to the file object representing that connection, particularly if TdiDispatchCleanup did not release the driver-allocated context at FsContext and FsContext2 in the file object.

On receipt of a cleanup request for which the FileObject represents a control channel, the transport completes any outstanding requests on the control channel. Such a request has no effect on addresses and connection endpoints open in the TDI driver.

How a transport handles pending IRPs when it receives a cleanup request is driver-determined. Usually, a transport sets STATUS_CANCELLED in the I/O status block and, then, calls IoCompleteRequest with each pending IRP. As an alternative, a transport might complete pending operations and complete each IRP when the requested operation was done; that is, return any resources allocated by the next-lower driver for pending receives and transmit all pending sends for an address or connection endpoint, and collect a set of current statistics for a control channel before completing the corresponding IRPs.

In whatever manner a given transport handles pending IRPs for an address, connection endpoint, or control channel that is being closed, TdiDispatchCleanup cannot complete the cleanup IRP and return control until there are no outstanding IRPs that reference the FileObject in the given cleanup IRP.

TdiDispatchCleanup runs at IRQL=PASSIVE_LEVEL.

See Also

TdiDispatchClose, TdiDispatchCreate


TdiDispatchClose

The TdiDispatchClose routine closes an address, connection endpoint, or control channel.

NTSTATUS
  TdiDispatchClose(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Pointer to the device object created by the TDI transport.
Irp
Pointer to the IRP with IRP_MJ_CLOSE set as the MajorFunctionCode in the I/O stack location of the transport driver.

A transport calls IoGetCurrentIrpStackLocation with the given Irp to get a pointer to its own stack location in the IRP, shown in the following list as IrpSp. The transport can use the information set in the following members of the IRP in processing a close request:

IoStatus.Status
Specifies the final status of the close operation. The transport sets this member to the same value that will be returned by TdiDispatchClose. (IoStatus.Information is set to zero.)
IrpSp->MajorFunction
Specifies IRP_MJ_CLOSE. The transport can ignore this member if it exports a TdiDispatchClose routine that handles only close requests.
IrpSp->FileObject
Pointer to the file object representing an address, connection endpoint, or control channel. The transport driver uses the values of the FsContext and possibly FsContext2 fields in this file object to access any remaining driver-allocated state that TdiDispatchCleanup did not release already.

Return Value

TdiDispatchClose returns STATUS_SUCCESS when it has carried out any driver-determined operations, such as releasing resources allocated to track the given address, connection endpoint, or control channel, for the file object being closed.

Comments

TdiDispatchClose runs when the I/O Manager is releasing its last reference to the handle of the file object representing an address, connection endpoint, or control channel. Such a file object is deallocated when this last reference to the file handle has been released.

When the I/O Manager is closing the last handle to an open file object that represents an address, connection endpoint, or control channel, it calls TdiDispatchCleanup. In other words, the I/O Manager always submits an IRP_MJ_CLEANUP request to a transport before it submits an IRP_MJ_CLOSE request for a particular file object.

Closing an address, connection endpoint, or control channel is an inherently synchronous operation. TdiDispatchClose can block waiting for internal driver functions to handle particular subtasks, but TdiDispatchClose must complete the input close IRP itself.

TdiDispatchClose is responsible for releasing any driver-allocated resources associated with the given file object, unless all such resources were already released by TdiDispatchCleanup.

TdiDispatchClose runs at IRQL=PASSIVE_LEVEL.

See Also

TdiDispatchCleanup


TdiDispatchCreate

The TdiDispatchCreate routine opens a file object that represents an address, connection endpoint, or control channel, setting up driver-allocated state to track subsequent I/O operations on the open file object.

NTSTATUS
  TdiDispatchCreate(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Pointer to the device object created by the TDI transport.
Irp
Pointer to the IRP with IRP_MJ_CREATE set as the MajorFunctionCode in the I/O stack location of the transport driver.

A transport calls IoGetCurrentIrpStackLocation with the given Irp to get a pointer to its own stack location in the IRP, shown in the following list as IrpSp. The transport can use the information set in the following members of the IRP in processing a create request:

IoStatus.Status
Specifies the final status of the create/open operation. The transport sets this member to the same value that will be returned by TdiDispatchCreate. (IoStatus.Information is set to zero.)
IrpSp->MajorFunction
Specifies IRP_MJ_CREATE. The transport can ignore this member if it exports a TdiDispatchCreate routine that handles only create requests.
IrpSp->FileObject
Pointer to a file object that the I/O Manager creates to represent the address, connection endpoint, or control channel. The transport driver sets the FsContext and possibly FsContext2 fieldss in this file object to access driver-allocated context areas set up in TdiDispatchCreate to track subsequent I/O requests on the address, connection endpoint, or control channel.
Irp->AssociatedIrp.SystemBuffer
Pointer to a FILE_FULL_EA_INFORMATION-structured buffer if the file object represents an address or a connection endpoint to be opened.

For an address, the EaName member is set to the system-defined constant TdiTransportAddress and the EA value following the EaName array is of type TRANSPORT_ADDRESS, set up by the client to specify the address to be opened. For some transports, this value can be a symbolic netBIOS or DNS name to be translated by the transport.

For a connection endpoint, the EaName member is set to the system-defined constant TdiConnectionContext and the EA value following the EaName array is a client-supplied handle, opaque to the transport driver. The transport must save this handle and subsequently pass it back to the client's registered event handlers for this connection.

If the given file object represents a control channel, this member is NULL.

IrpSp->Parameters.Create.EaLength
Specifies the size in bytes of the buffer at Irp->AssociatedIrp.SystemBuffer. If the given file object represents a control channel, specifies zero.
IrpSp->Parameters.Create.ShareAccess
If the given file object represents an address, specifies whether the client has requested an exclusive open of the file object. If the initial client to open an address sets either of FILE_SHARE_READ or FILE_SHARE_WRITE in the ShareAccess parameter to ZwCreateFile, the same address can be opened by other clients subsequently.
IrpSp->Parameters.Create.SecurityContext->AccessState
If the given file object represents a shareable address, defines the requested access to that address. The initial client to open a file object representing a particular address sets the access control list for that address. A TDI transport driver calls Security Reference Monitor (Se Xxx) routines to check this member against the original ACL assigned to the corresponding file object when subsequent open-address requests occur. The transport fails subsequent open requests if the requested access is incompatible with the access rights granted in the original ACL.

Return Value

TdiDispatchCreate returns STATUS_SUCCESS if the create/open operation succeeds and the transport has set up whatever state it uses to track subsequent I/O operations for the address, connection endpoint, or control channel. Otherwise, it can return any driver-determined status, such as one of the following:

STATUS_INVALID_PARAMETER
A transport might return this value if it found EaName entries set with both TdiTransportAddress and TdiConnectionContext in the buffer at Irp->AssociatedIrp.SystemBuffer.
STATUS_SHARING_VIOLATION
A transport might return this value if an attempt is made to open a file object representing an address that has already been opened for exclusive access.
STATUS_NONEXISTENT_EA_ENTRY
A transport might return this value if an entry's EaName array is not followed by a valid address value of the given EaValueLength in the buffer at Irp->AssociatedIrp.SystemBuffer.
STATUS_INSUFFICIENT_RESOURCES
A transport might return this status if it could not allocate sufficient memory in which to maintain state information about the address, connection endpoint, or control channel.
STATUS_INVALID_DEVICE_REQUEST
A transport might return this status as a default error return or if the next lower driver's device currently is being closed.

Comments

Opening an address, connection endpoint, or control channel object is an inherently synchronous operation. TdiDispatchCreate can block waiting for internal driver functions to handle particular subtasks, such as initializing structures in driver-allocated context areas or checking the ACL for an address. However, TdiDispatchCreate should either set IoStatus.Status in the IRP to STATUS_SUCCESS or to an appropriate error status before it returns control.

A transport driver should fail any create/open request in which the buffer at Irp->AssociatedIrp.SystemBuffer contains EaName members set with both TdiTransportAddress and TdiConnectionContext. Clients must make separate calls to ZwCreateFile to open an address and a connection endpoint because a single file object cannot represent a combined address and connection endpoint.

A client opens a file object representing an address to indicate its transport address to the TDI driver. The first client to open such a file object can specify that it be either exclusive or shared. If the initial client specifies an exclusively opened file object, the transport driver fails all subsequent client requests to open that address. If the initial client specifies a shared file object, the transport driver also fails all subsequent client requests for an exclusive open of that address. Otherwise, any number of clients can open the same file object for shared access of the same address.

Depending on the transport, a client can specify a transport address to be opened or allow the transport driver to select an address. For example, a client might specify a TDI driver's broadcast address to receive datagrams in connectionless mode.

Opening a connection endpoint defines a client's end of a network connection. When TdiDispatchCreate processes such a request, it sets up the connection endpoint in an idle state. The client must eventually associate the open connection endpoint with an opened file object representing an address. That is, a transport does no I/O on an opened connection endpoint until it has been associated with an open address.

Opening a control channel sets up a control channel between a client and the TDI transport driver. A client can use an open control channel to query and set information not specifically tied to an address or connection endpoint. For example, a client might use an opened control channel to query the transport driver's broadcast address (used to receive broadcast datagrams) or to query performance statistics maintained in the transport.

TdiDispatchCreate runs at IRQL=PASSIVE_LEVEL.

See Also

TdiDispatchCleanup, TdiDispatchDeviceControl, TdiDispatchInternalDeviceControl, TRANSPORT_ADDRESS


TdiDispatchDeviceControl

The TdiDispatchDeviceControl routine processes IRPs that are set with the major function code IRP_MJ_DEVICE_CONTROL.

NTSTATUS
  TdiDispatchDeviceControl(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp,
    IN PIO_STACK  IrpSp
    );

Parameters

DeviceObject
Pointer to the device object created by the TDI driver.
Irp
Pointer to the IRP.
IrpSp
Pointer to the I/O stack location of the transport driver in the given IRP.

Return Value

TdiDispatchDeviceControl returns STATUS_SUCCESS if it satisfied the given request. Otherwise, it returns a driver-determined error status, depending on the given IOCTL_XXX minor function code in the IRP.

Comments

Usually, TdiDispatchDeviceControl calls TdiMapUserRequest and, if it returns STATUS_SUCCESS, calls the transport's TdiDispatchInternalDeviceControl function with the input DeviceObject and Irp pointers. If TdiMapUserRequest returns an error indicating that the given IOCTL_XXX in the Irp did not match any of the system-defined IOCTL_TDI_XXX codes, most transports simply complete the IRP with a driver-determined error status, such as STATUS_INVALID_DEVICE_REQUEST or STATUS_NOT_SUPPORTED.

However, if a transport supports any driver-defined "private" IOCTLs that a transport-dedicated application uses to communicate with the transport, its TdiDispatchDeviceControl performs a switch operation on these IOCTL_XXX and calls internal driver functions to process them, as well as calling TdiDispatchInternalDeviceControl when TdiMapUserRequest returns STATUS_SUCCESS.

For more information about driver-defined IOCTL codes, see IRP Function Codes and IOCTLs.

TdiDispatchDeviceControl runs at IRQL PASSIVE_LEVEL or IRQL DISPATCH_LEVEL.

See Also

TdiDispatchFastDeviceControl, TdiDispatchInternalDeviceControl, TdiMapUserRequest


TdiDispatchFastDeviceControl

The TdiDispatchFastDeviceControl routine is an optional TDI transport driver function that usually returns data already buffered internally by the transport.

BOOLEAN
  TdiDispatchFastDeviceControl(
    IN STRUCT FILE_OBJECT  *FileObject,
    IN BOOLEAN  Wait,
    IN PVOID  InputBuffer,
    IN ULONG  InputBufferLength,
    IN OUT PVOID  OutputBuffer,
    IN ULONG  OutputBufferLength,
    IN ULONG  IoControlCode,
    OUT PIO_STATUS_BLOCK  IoStatus
    );

Parameters

FileObject
Pointer to the file object representing the open address, connection endpoint, or control channel.
Wait
Specifies TRUE if the driver can wait in the context of the call to TdiDispatchFastDeviceControl.
InputBuffer
Optionally points to the input buffer, containing caller-supplied information required by the given IoControlCode.
InputBufferLength
Specifies the size in bytes of the input buffer.
OutputBuffer
Optionally points to the output buffer in which the transport returns any data requested.
OutputBufferLength
Specifies the size in bytes of the output buffer.
IoControlCode
Specifies the IOCTL_TDI_XXX code for the requested operation. This value must be one of the codes defined in ntddtdi.h.

The set of valid IOCTL_TDI_XXX codes depends on the fast I/O support, if any, provided by an individual transport and on what that transport currently holds in its internal buffers. In general, transports are most likely to buffer read-ahead data to satisfy anticipated IOCTL_TDI_RECEIVE requests and, possibly, data used to satisfy IOCTL_TDI_QUERY_INFORMATION requests.

The afd.sys driver, which provides support for Windows Sockets to communicate with underlying transports, also provides read-ahead fast I/O support for system transports that do not provide a fast I/O path for received data.

IoStatus
Pointer to a caller-supplied variable in which TdiDispatchFastDeviceControl returns the completion status, formatted as an IO_STATUS_BLOCK structure. TdiDispatchFastDeviceControl fills in the Status and Information members as appropriate for the given IoControlCode.

Return Value

TdiDispatchFastDeviceControl returns TRUE only if it satisfies or completes the kernel-mode client's request before returning control.

Comments

When preparing a fast I/O request, a client neither allocates an IRP nor uses an IRP passed in from a higher network layer.

When the I/O Manager calls TdiDispatchFastDeviceControl, a given OutputBuffer usually corresponds to the buffer at Irp->MdlAddress in a client-supplied IRP. The InputBuffer contains any client-supplied information for the request, depending on the IoControlCode. This request is different from other kernel requests in that system-defined user-mode IOCTLs identify the requests, as opposed to the TDI_XXX minor function codes listed with TdiBuildInternalDeviceControlIrp.

For example, for IOCTL_TDI_SEND, InputBuffer contains a client-supplied TDI_REQUEST_SEND structure, and OutputBuffer contains the actual data to be sent over the network. For IOCTL_TDI_RECEIVE, InputBuffer contains a TDI_REQUEST_RECEIVE structure, and the transport driver copies the receive data to OutputBuffer.

The definition of each IOCTL_TDI_XXX code in ntddtdi.h determines how buffers should be set up. For an explanation of how to interpret IOCTL_XXX codes, see Defining I/O Control Codes.

When the buffer parameters have been set up for the transport, the client calls IoCallDriver to deliver the request to TdiDispatchFastDeviceControl if the transport exports this routine. If the transport cannot complete a fast I/O client request immediately, TdiDispatchFastDeviceControl returns FALSE and the I/O Manager repackages the given request into an IRP_MJ_DEVICE_CONTROL IRP and submits the IRP to the transport driver's TdiDispatchDeviceControl routine. Otherwise, TdiDispatchFastDeviceControl satisfies the request itself, possibly by calling an internal driver function to process the request, or it fails the request. When TdiDispatchFastDeviceControl returns TRUE, the transport relinquishes ownership of the original buffers to the client.

At initialization, a TDI transport driver enables its fast I/O path by setting the FastIoDispatch field in the input driver object to the address of a driver-allocated FAST_IO_DISPATCH structure. The transport must fill in the SizeOfFastIoDispatch member and set FastIoDeviceControl to the entry point of the transport's TdiDispatchFastDeviceControl function; all other members of the FAST_IO_DISPATCH structure must be set to NULL. For more information about driver objects, see Introduction to Driver Objects.

TdiDispatchFastDeviceControl runs at IRQL PASSIVE_LEVEL or IRQL DISPATCH_LEVEL.

See Also

TdiBuildInternalDeviceControlIrp, TdiDispatchDeviceControl, TDI_QUERY_INFORMATION, TDI_RECEIVE, TDI_SEND


TdiDispatchInternalDeviceControl

The TdiDispatchInternalDeviceControl routine handles TDI_XXX device-control requests from kernel-mode clients.

NTSTATUS
  TdiDispatchInternalDeviceControl(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Pointer to the device object created by the TDI driver.
Irp
Pointer to the IRP.

A transport calls IoGetCurrentIrpStackLocation with the given Irp to get a pointer to its own I/O stack location in the IRP, shown in the following list as IrpSp. The transport can use the information set in the following members of the IRP in processing an internal device-control request:

IoStatus.Status
Specifies the final status of the operation. The transport sets this member to the same value that will be returned by TdiDispatchInternalDeviceControl.
IoStatus.Information
Usually, this member is initialized to zero. Depending on the IrpSp->MinorFunction value, the transport resets this member to the number of bytes of data it is returning to the client or to the number of bytes of data it transferred before the transport completes this IRP.
IrpSp->MajorFunction
Specifies IRP_MJ_INTERNAL_DEVICE_CONTROL. The transport can ignore this member if it exports a TdiDispatchInternalDeviceControl routine that handles only these requests.
IrpSp->MinorFunction
Specifies the TDI_XXX code for the operation to be carried out.
IrpSp->FileObject
Pointer to the file object representing an address, connection endpoint, or control channel. The transport driver uses the values of the FsContext and possibly FsContext2 fields in this file object to access any driver-allocated state for operations on the address, connection endpoint, or control channel.

Return Value

TdiDispatchInternalDeviceControl returns STATUS_SUCCESS if it completed the requested operation successfully. Otherwise, it returns a driver-determined error status, such as STATUS_INVALID_DEVICE_REQUEST or STATUS_INVALID_DEVICE_STATE.

Comments

When preparing a request, a kernel-mode client either allocates an IRP with TdiBuildInternalDeviceControlIrp or uses an IRP passed in from a higher network layer. The client calls a TdiBuild Xxx macro to set up the IRP for the underlying transport with the corresponding TDI_XXX as the MinorFunction code and IRP_MJ_INTERNAL_DEVICE_CONTROL as the MajorFunction code in the IRP. When it has set up the IRP, the client calls IoCallDriver to submit the request to the underlying transport's TdiDispatchInternalDeviceControl routine.

Usually, a transport's TdiDispatchInternalDeviceControl routine determines whether the given file object at IrpSp->FileObject represents an address, connection endpoint, or control channel, because certain TDI_XXX are relevant only to addresses, others are relevant only to connection endpoints, and a subset of TDI_XXX codes are relevant to both and to control channels. The following summarizes which TDI_XXX codes are likely to be processed for each:

FileObject represents an address
TDI_SEND_DATAGRAM
TDI_RECEIVE_DATAGRAM
TDI_SET_EVENT_HANDLER
FileObject represents a connection endpoint
TDI_SEND
TDI_RECEIVE
TDI_ASSOCIATE_ADDRESS
TDI_DISASSOCIATE_ADDRESS
TDI_CONNECT
TDI_DISCONNECT
TDI_LISTEN
TDI_ACCEPT
FileObject represents an address, connection endpoint, or control channel
TDI_QUERY_INFORMATION
TDI_SET_INFORMATION
TDI_ACTION

For each TDI_XXX the transport handles, its TdiDispatchInternalDeviceControl routine usually calls an internal driver function to carry out the requested operation. Possibly, the internal driver function also complete the IRP, particularly if that function transfers data because it then can set IoStatus.Information to the appropriate value, leaving TdiDispatchInternalDeviceControl to complete IRPs in which this member is set to zero. Each such internal function usually returns an NTSTATUS-type value, which TdiDispatchInternalDeviceControl propagates when it returns control.

For more information about each of the TDI_XXX mentioned here, see TDI IOCTLs for Transport Drivers, next.

TdiDispatchInternalDeviceControl runs at IRQL PASSIVE_LEVEL or IRQL DISPATCH_LEVEL.

See Also

TdiBuildInternalDeviceControlIrp, TdiDispatchDeviceControl


TDI IOCTLs for Transport Drivers

TDI transport drivers respond to the TDI_XXX IOCTL requests issued by their kernel-mode clients that are described here. Each IRP submitted to such a driver's TdiDispatchInternalDeviceControl routine has the MinorFunctionCode member of the transport's I/O stack location set with one of these TDI_XXX codes.

Typically, a transport's TdiDispatchInternalDeviceControl routine performs a switch operation on the TDI_XXX code to route each incoming client request to an internal driver function for further processing.

Some structures mentioned in the TDI_XXX references that follow are described in TDI Structures. For more information about the internal structure of IRPs and accessible fields within the file objects referenced in this section, see Handling IRPs.

The TDI_XXX codes described in this section are in alphabetic order.


TDI_ACCEPT

When a kernel-mode client makes a TDI_ACCEPT request, it asks the underlying TDI transport driver to accept an incoming connection offer from a remote-node peer and, thereby, to enable network data transfers on the endpoint-to-endpoint connection between that local-node client and its remote-node peer.

IRP

The transport calls IoGetCurrentIrpStackLocation with the given Irp to get a pointer to its own I/O stack location in the IRP, shown in the following list as IrpSp. The pointer to the IRP is shown in the following list as Irp. IRP members relevant to this request include the following:

Irp->IoStatus.Status
Specifies the final status of the accept request. The transport sets this member before it completes the IRP, possibly to one of the following:

STATUS_SUCCESS
STATUS_INVALID_CONNECTION

IrpSp->MajorFunction
Specifies IRP_MJ_INTERNAL_DEVICE_CONTROL. The transport can ignore this member if it exports a TdiDispatchInternalDeviceControl routine that handles only TDI_XXX requests.
IrpSp->MinorFunction
Specifies TDI_ACCEPT.
IrpSp->FileObject
Pointer to an open file object representing the connection endpoint at which a listen request has completed. The transport uses the FsContext and, possibly, FsContext2 fields to access the state it maintains about this connection.
IrpSp->Parameters
Specifies a TDI_REQUEST_KERNEL_ACCEPT structure, defined as follows:
struct _TDI_REQUEST_KERNEL_ACCEPT {
    PTDI_CONNECTION_INFORMATION RequestConnectionInformation;
    PTDI_CONNECTION_INFORMATION ReturnConnectionInformation;
} TDI_REQUEST_KERNEL_ACCEPT, *PTDI_REQUEST_KERNEL_ACCEPT;

The transport uses the members of this structure as follows:

RequestConnectionInformation
Pointer to a TDI_CONNECTION_INFORMATION structure, possibly containing connection information supplied by the client. This information can include a pointer (in the UserData member) to a buffer of client-supplied accept data to be sent to the remote node when the transport notifies the remote-node transport that the offered connection is accepted.
ReturnConnectionInformation
Pointer to a client-supplied variable of type TDI_CONNECTION_INFORMATION in which the transport returns connection information, if any, to the client. This member is NULL if the transport does not return information for delayed-connection acceptances.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

In normal operation, a client submits an accept request in response to a return from a preceding listen request in which it set the TDI_QUERY_ACCEPT flag. If the client did not set this flag in its TDI_LISTEN request for this connection, the transport should fail this accept request.

The transport can call already registered ClientEvent(Chained)Receive(Expedited) handlerbecause with incoming receives from the remote node on this connection before the I/O Manager formally completes its processing of the client's accept IRP.

Most TDI transport drivers have a time-out feature to prevent communication sequences from hanging when a remote node is not responding. Therefore, a TDI client must either accept or reject a connection as soon as possible after completion of its listen request. As a general rule, a transport-determined time-out interval between client notification of an offered connection and the local-node client's connection acceptance or rejection should be less than one second.

TdiBuildAccept is the macro a client uses to fill in this IRP.

See Also

ClientEventChainedReceive, ClientEventChainedReceiveExpedited, ClientEventReceive, ClientEventReceiveExpedited, TdiBuildAccept, TDI_CONNECTION_INFORMATION, TdiDispatchInternalDeviceControl, TDI_LISTEN, TDI_RECEIVE


TDI_ACTION

When a kernel-mode client makes a TDI_ACTION request, it asks the underlying TDI transport driver to make transport-specific extensions available to that client.

IRP

The transport calls IoGetCurrentIrpStackLocation with the given Irp to get a pointer to its own stack location in the IRP, shown in the following list as IrpSp. The pointer to the IRP is shown in the following list as Irp. IRP members relevant to this request include the following:

Irp->IoStatus.Status
Specifies the final status of the action request. The transport sets this member before it completes the IRP, possibly to one of the following:

STATUS_SUCCESS
STATUS_PENDING
STATUS_INVALID_CONNECTION
STATUS_INVALID_PARAMETER
STATUS_INVALID_HANDLE
STATUS_BUFFER_TOO_SMALL
STATUS_INSUFFICIENT_RESOURCES
STATUS_NOT_SUPPORTED
STATUS_NOT_IMPLEMENTED

Irp->IoStatus.Information
Specifies how many bytes of data were transferred for this request. The transport sets this member of the I/O status block before it completes the IRP.
IrpSp->MajorFunction
Specifies IRP_MJ_INTERNAL_DEVICE_CONTROL. The transport can ignore this member if it exports a TdiDispatchInternalDeviceControl routine that handles only TDI_XXX requests.
IrpSp->MinorFunction
Specifies TDI_ACTION.
IrpSp->FileObject
Pointer to an open file object representing an address, connection endpoint, or control channel. The transport uses the FsContext and, possibly, FsContext2 fields to access the state it maintains about this address, connection, or control channel.
Irp->MdlAddress
Pointer to an MDL, possibly the initial MDL in a chain, mapping a buffer containing the client-supplied action parameter block. The initial part of this buffer always contains a system-defined TDI_ACTION_HEADER structure, followed by whatever transport-defined contents are required to carry out the action request.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

The successful completion of any client's action request makes the transport-provided extension applicable to that client but not to any other TDI clients or drivers. The set of possible actions is defined by the transport at the discretion of the TDI transport driver writer.

Such a client makes an action request for transport-defined extensions related to an address, a connection, or a control channel. The client supplies a buffer containing all information concerning the requested action in the parameter block mapped at MdlAddress.

Every action parameter block begins with a TDI_ACTION_HEADER containing a transport identifier and an action code. On receipt of such a request, the transport uses the value of TransportId in this header to validate the request. The ActionCode member specifies the transport-defined operation to carry out and determines the transport-required contents for the remainder of the parameter block.

TdiBuildAction is the macro a client uses to fill in this IRP.

See Also

TDI_ACTION_HEADER, TdiBuildAction, TdiDispatchInternalDeviceControl


TDI_ASSOCIATE_ADDRESS

When a kernel-mode client makes a TDI_ASSOCIATE_ADDRESS request, it asks the underlying TDI transport driver to make an association between a particular open local-node address and an open connection endpoint.

IRP

The transport calls IoGetCurrentIrpStackLocation with the given Irp to get a pointer to its own I/O stack location in the IRP, shown in the following list as IrpSp. The pointer to the IRP is shown in the following list as Irp. IRP members relevant to this request include the following:

Irp->IoStatus.Status
Specifies the final status of the associate-address request. The transport sets this member before it completes the IRP, possibly to one of the following:

STATUS_SUCCESS
STATUS_CONNECTION_ESTABLISHED
STATUS_INVALID_CONNECTION
STATUS_INVALID_HANDLE
STATUS_INVALID_PARAMETER

The IoStatus.Information member is zero because this request transfers no data.

IrpSp->MajorFunction
Specifies IRP_MJ_INTERNAL_DEVICE_CONTROL. The transport can ignore this member if it exports a TdiDispatchInternalDeviceControl routine that handles only TDI_XXX requests.
IrpSp->MinorFunction
Specifies TDI_ASSOCIATE_ADDRESS.
IrpSp->FileObject
Pointer to an open file object representing the connection endpoint to be associated with the address specified at IrpSp->Parameters. The transport uses the FsContext and, possibly, FsContext2 fields to access the state it maintains about the connection.
IrpSp->Parameters
Pointer to a TDI_REQUEST_KERNEL_ASSOCIATE structure, defined as follows:
struct _TDI_REQUEST_KERNEL_ASSOCIATE {
    HANDLE  AddressHandle;
} TDI_REQUEST_KERNEL_ASSOCIATE, *PTDI_REQUEST_KERNEL_ASSOCIATE;

The transport uses the member of this structure as follows:

AddressHandle
Specifies a client-supplied handle to the file object representing the address.

The transport can call ObReferenceObjectByHandle to convert this handle into a pointer to the file object, which produces a reference to the file object representing the local-node address to be associated with the connection endpoint. The transport uses the FsContext and, possibly, FsContext2 fields of this file object to access the state it maintains about this address.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

A kernel-mode client must make an associate-address request before it makes an endpoint-to-endpoint connection to the remote node either with a TDI_LISTEN request, optionally followed by a TDI_ACCEPT request, to the transport driver or with a TDI_CONNECT request to the transport driver. The client can get or set information about the connection with TDI_QUERY_INFORMATION or TDI_SET_INFORMATION requests before making an associate-address request.

After the connection endpoint has been associated with the address, the client can make any other TDI_XXX requests to the transport on the connection with one exception: it cannot make a TDI_ASSOCIATE_ADDRESS request again for the specific endpoint until it makes a successful TDI_DISASSOCIATE_ADDRESS request to the transport.

For example, a client might register one or more ClientEvent(Chained)Receive(Expedited) handlers on the address by submitting one or more TDI_SET_EVENT_HANDLER requests if its subsequent TDI_LISTEN request will be satisfied as soon as a remote-node peer offers a connection. On the other hand, a client that sets up a listen for a delayed-connection acceptance might defer registering receive-event handlers until just before it submits a TDI_ACCEPT for an offered connection.

TdiBuildAssociateAddress is the macro a client uses to fill in this IRP.

See Also

ClientEventChainedReceive, ClientEventChainedReceiveExpedited, ClientEventReceive, ClientEventReceiveExpedited, TDI_ACCEPT, TdiBuildAssociateAddress, TDI_CONNECT, TDI_DISASSOCIATE_ADDRESS, TdiDispatchInternalDeviceControl, TDI_LISTEN, TDI_QUERY_INFORMATION, TDI_SET_EVENT_HANDLER, TDI_SET_INFORMATION


TDI_CONNECT

When a kernel-mode client makes a TDI_CONNECT request, it asks the underlying TDI transport driver to offer a connection on a particular local-node connection endpoint to a remote-node peer.

IRP

The transport calls IoGetCurrentIrpStackLocation with the given Irp to get a pointer to its own I/O stack location in the IRP, shown in the following list as IrpSp. The pointer to the IRP is shown in the following list as Irp. IRP members relevant to this request include the following:

Irp->IoStatus.Status
Specifies the final status of the connection request. The transport sets this member before it completes the IRP, possibly to one of the following:

STATUS_SUCCESS
STATUS_PENDING
STATUS_BAD_NETWORK_PATH
STATUS_INVALID_CONNECTION
STATUS_REMOTE_NOT_LISTENING
STATUS_INSUFFICIENT_RESOURCES
STATUS_REQUEST_TIMED_OUT

IrpSp->MajorFunction
Specifies IRP_MJ_INTERNAL_DEVICE_CONTROL. The transport can ignore this member if it exports a TdiDispatchInternalDeviceControl routine that handles only TDI_XXX requests.
IrpSp->MinorFunction
Specifies TDI_CONNECT.
IrpSp->FileObject
Pointer to an open file object representing the connection endpoint already associated with a local-node address. The transport uses the FsContext and, possibly, FsContext2 fields to access the state it maintains about this connection.
IrpSp->Parameters
Pointer to a TDI_REQUEST_KERNEL_CONNECT structure, equivalent to the TDI_REQUEST_KERNEL structure.

The RequestFlags member is irrelevant for connect requests. The transport uses the client-supplied information, such as the remote-node address to which the connection should be offered, in the buffer at RequestConnectionInformation. The transport returns information to the client-supplied buffer at ReturnConnectionInformation. Each of these buffers is formatted as a TDI_CONNECTION_INFORMATION structure.

IrpSp->Parameters.RequestSpecific
Pointer to a LARGE_INTEGER variable specifying the time-out value for the connection offer or is NULL. An explicit time out is specified as the negative of the number of 100-nanosecond units, relative to the current system time, for the time-out interval. If this member is NULL, the transport must choose an appropriate time-out interval, usually something less than one second.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

For a local-node client to establish an endpoint-to-endpoint connection with a remote-node peer, it must associate an idle local connection endpoint with an open transport address before making a TDI_CONNECT request. If the specified local endpoint is active or nonexistent, the transport fails the connect request.

For a TDI_CONNECT request to succeed, the remote-node client must have an open TDI_LISTEN request or have registered its ClientEventConnect handler to receive connection offers indicated by the underlying transport on the remote node.

TdiBuildConnect is the macro a client uses to fill in the IRP.

See Also

ClientEventConnect, TdiBuildConnect, TDI_CONNECTION_INFORMATION, TdiDispatchInternalDeviceControl, TDI_LISTEN, TDI_REQUEST_KERNEL


TDI_DISASSOCIATE_ADDRESS

When a kernel-mode client makes a TDI_DISASSOCIATE_ADDRESS request, it asks the underlying TDI transport driver to break an established association between a particular local-node address and a connection endpoint.

IRP

The transport calls IoGetCurrentIrpStackLocation with the given Irp to get a pointer to its own I/O stack location in the IRP, shown in the following list as IrpSp. The pointer to the IRP is shown in the following list as Irp. IRP members relevant to this request include the following:

Irp->IoStatus.Status
Specifies the final status of the disassociate-address request. The transport sets this member before it completes the IRP, possibly to one of the following:

STATUS_SUCCESS
STATUS_INVALID_CONNECTION

IrpSp->MajorFunction
Specifies IRP_MJ_INTERNAL_DEVICE_CONTROL. The transport can ignore this member if it exports a TdiDispatchInternalDeviceControl routine that handles only TDI_XXX requests.
IrpSp->MinorFunction
Specifies TDI_DISASSOCIATE_ADDRESS.
IrpSp->FileObject
Pointer to an open file object representing the connection endpoint to be disassociated from a local-node address. The transport uses the FsContext and, possibly, FsContext2 fields to access the state it maintains about the connection.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

A client makes this request to disassociate a connection endpoint for an inactive connection from the associated local-node address, whether that client initiated the disconnection from its remote-node peer or vice versa.

After the address has been disassociated, the client can reassociate it with another connection endpoint or reassociate the connection endpoint with another open local-node address by making another TDI_ASSOCIATE_ADDRESS request. Consequently, the transport cannot assume that the file objects representing such an address and connection endpoint will be closed following the completion of the TDI_DISASSOCIATE_ADDRESS request.

TdiBuildDisassociateAddress is the macro a client uses to fill in this IRP.

See Also

TDI_ASSOCIATE_ADDRESS, TdiBuildDisassociateAddress, TDI_DISCONNECT, TdiDispatchInternalDeviceControl


TDI_DISCONNECT

When a kernel-mode client makes a TDI_DISCONNECT request, it asks the underlying TDI transport driver to make a disconnect indication to the remote node, to acknowledge a disconnect indication from the remote node for an established endpoint-to-endpoint connection, or to reject an offered connection by a remote-node peer.

IRP

The transport calls IoGetCurrentIrpStackLocation with the given Irp to get a pointer to its own I/O stack location in the IRP, shown in the following list as IrpSp. The pointer to the IRP is shown in the following list as Irp. IRP members relevant to this request include the following:

Irp->IoStatus.Status
Specifies the final status of the disconnect request. The transport sets this member before it completes the IRP, possibly to one of the following:

STATUS_SUCCESS
STATUS_PENDING
STATUS_INVALID_CONNECTION
STATUS_REQUEST_TIMED_OUT

IrpSp->MajorFunction
Specifies IRP_MJ_INTERNAL_DEVICE_CONTROL. The transport can ignore this member if it exports a TdiDispatchInternalDeviceControl routine that handles only TDI_XXX requests.
IrpSp->MinorFunction
Specifies TDI_DISCONNECT.
IrpSp->FileObject
Pointer to an open file object representing the connection endpoint. The transport uses the FsContext and, possibly, FsContext2 fields to access the state it maintains about this connection.
IrpSp->Parameters
Pointer to a TDI_REQUEST_KERNEL_DISCONNECT structure, equivalent to the TDI_REQUEST_KERNEL structure.

Some transport drivers simply terminate all activity on the given connection immediately. Others use the client-supplied value of the RequestFlags member to support controlled disconnects. For such a transport, RequestFlags can be set to either of the following:

TDI_DISCONNECT_ABORT
Specifies that the transport should close the connection immediately without completing its pending operations on the connection. This is the default behavior expected of all transports, including transports that do not support controlled disconnects. In effect, this value for RequestFlags directs the transport to do the same things as if RequestFlags were zero: the transport should refuse any incoming requests for the connection, stop all activity at the specified connection endpoint, and cancel any outstanding requests it is holding queued internally for the connection.

When a preceding disconnect request made with TDI_DISCONNECT_RELEASE remains pending on the connection, the client can issue another disconnect request with TDI_DISCONNECT_ABORT, thereby forcing the underlying transport to close the connection immediately.

TDI_DISCONNECT_RELEASE
Specifies that the transport should initiate a controlled disconnect or confirms a controlled disconnect that was initiated from the remote node, as described later (see Comments).

The tranport can use client-supplied information in the buffer at RequestConnectionInformation to supply disconnection data, possibly supplemented with transport-provided status information, to the transport on the remote node. This buffer is formatted as a TDI_CONNECTION_INFORMATION structure.

The transport can return disconnect data and any status information supplied by the transport on the remote node in the client-supplied buffer at ReturnConnectionInformation. This buffer is formatted as a TDI_CONNECTION_INFORMATION structure. The contents of this buffer remain valid only until the client reuses the connection in a subsequent TDI_LISTEN or TDI_CONNECT request.

The TDI_DISCONNECT_WAIT flag is unused.

IrpSp->Parameters.RequestSpecific
Pointer to a LARGE_INTEGER variable specifying the time-out interval for the disconnect operation or is NULL. An explicit time out is specified as the negative of the number of 100-nanosecond units, relative to the current system time, for the time-out interval. If this member is NULL, the transport must choose an appropriate time-out value, usually something less than one second.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

During a disconnect operation, the underlying transport driver usually refuses any incoming requests for an established connection and stops all activity at the specified connection endpoint, unless the transport supports controlled disconnects. That is, the completion of a client's disconnect request usually implies cessation of all activity, including receive indications, on the given connection.

By default, TDI_DISCONNECT requests the disconnection of an endpoint-to-endpoint connection that is not a controlled-disconnect operation: the transport need not complete outstanding I/O requests on the connection before it completes the disconnect request and returns control. For such a disconnect operation, the transport typically cancels all outstanding requests on the given connection, and the corresponding remote-node transport need not have its client confirm the disconnection before the local-node transport can complete its client's disconnect request and return control.

Clients on an endpoint-to-endpoint connection can request a controlled disconnect if their underlying TDI transports support this. If so, the client that initiates the disconnect operation with a TDI_DISCONNECT request causes both transports to coordinate their operations so the remote-node peer is informed that its endpoint-to-endpoint connection is closing. In these circumstances, the remote-node client must confirm the disconnect before the underlying transport can return from the initiating (local-node) client's disconnect request.

The following summarizes the sequence of operations for a controlled disconnect:

  1. The local-node client initiates a disconnection by making a disconnect request with TDI_DISCONNECT_RELEASE set in RequestFlags. Subsequently, this client can no longer send data on the connection, but it can continue to receive data from its remote-node peer. When such a local-node client makes its disconnect request, the underlying transport transmits the data for any pending send requests it is currently holding and completes these requests back to its client, but it notifies the remote-node transport that a disconnect is occurring.
  2. The transport on the remote node performs the usual operations for any pending receive requests made by its client. Then, the remote-node transport notifies its client of the pending disconnect, either by calling ClientEventDisconnect if the remote-node client has registered this handler or by returning an error code on an outstanding request made by its client. After such a notification, the remote-node client can no longer receive data on the connection, but it can continue to send data until it makes a TDI_DISCONNECT request with TDI_DISCONNECT_RELEASE set in the RequestFlags.
  3. When the remote-node client has finished sending data, it makes a disconnect request to its underlying transport with TDI_DISCONNECT_RELEASE set in RequestFlags. The transport completes all outstanding sends on the connection normally before completing its client's disconnect request. When the transport completes this disconnect request, the connection is closed from the point of view of its remote-node client. However, the connection endpoint is still valid and that client can reuse it later.
  4. The remote-node transport notifies the local-node transport to confirm disconnect completion on the remote node. At this point, the original disconnect request is completed by the local-node transport and the connection is closed from the point of view of the local-node client that initiated the staged disconnection. However, the connection endpoint is still valid and the client can reuse it.

If the underlying transport supports delayed-connection acceptances, its clients also can submit TDI_DISCONNECT requests to reject incoming connection offers from remote nodes. Such a client is responding to a completed TDI_LISTEN request in which the client set the TDI_QUERY_ACCEPT flag or to a offer relayed by the transport to that client's registered ClientEventConnect handler.

TdiBuildDisconnect is the macro a client uses to fill in this IRP.

See Also

ClientEventConnect, TdiBuildDisconnect, TDI_CONNECTION_INFORMATION, TdiDispatchInternalDeviceControl, TDI_LISTEN, TDI_REQUEST_KERNEL


TDI_LISTEN

When a kernel-mode client makes a TDI_LISTEN request, it asks the underlying TDI transport driver to listen for an offer to make an endpoint-to-endpoint connection from a remote node.

IRP

The transport calls IoGetCurrentIrpStackLocation with the given Irp to get a pointer to its own I/O stack location in the IRP, shown in the following list as IrpSp. The pointer to the IRP is shown in the following list as Irp. IRP members relevant to this request include the following:

Irp->IoStatus.Status
Specifies the final status of the listen request. The transport sets this member before it completes the IRP, possibly to one of the following:

STATUS_SUCCESS
STATUS_PENDING
STATUS_INSUFFICIENT_RESOURCES
STATUS_INVALID_CONNECTION

IrpSp->MajorFunction
Specifies IRP_MJ_INTERNAL_DEVICE_CONTROL. The transport can ignore this member if it exports a TdiDispatchInternalDeviceControl routine that handles only TDI_XXX requests.
IrpSp->MinorFunction
Specifies TDI_LISTEN.
IrpSp->FileObject
Pointer to an open file object representing the connection endpoint. The transport uses the FsContext and, possibly, FsContext2 fields to access the state it maintains about this connection.

This connection endpoint was previously associated with a local-node address when the client made a successful TDI_ASSOCIATE_ADDRESS request to the transport.

IrpSp->Parameters
Pointer to a TDI_REQUEST_KERNEL_LISTEN structure, equivalent to the TDI_REQUEST_KERNEL structure.

A client can set the RequestFlags member with TDI_QUERY_ACCEPT, directing the transport to make a delayed-connection acceptance: that is, to complete this listen request to the client when an appropriate connection offer, as specified by RequestConnectionInformation, comes in from the remote node so the client can determine whether to accept the connection by issuing a TDI_ACCEPT request or to reject the remote-node connection offer with a TDI_DISCONNECT request.

Otherwise, when RequestFlags is zero, the underlying transport should accept any appropriate incoming connection offer immediately. If TDI_QUERY_ACCEPT is set but the transport does not support delayed-connection acceptances, the transport fails this listen request.

The client supplies information in the TDI_CONNECTION_INFORMATION-type buffer at RequestConnectionInformation that the transport subsequently uses to determine whether to accept a connection offer from a remote node, as follows:

UserData
Pointer to a buffer of client-supplied data for the tranport to transmit to the remote node that requests a connection. This member is NULL if the transport supports delayed-connection acceptances and the client set RequestFlags with TDI_QUERY_ACCEPT.
UserDataLength
Specifies the size in bytes of the buffer at UserData, zero if UserData is NULL.
Options
Matches the value set in the RequestFlags member of the TDI_REQUEST_KERNEL_LISTEN structure.
OptionsLength
Should be set to sizeof(ULONG); irrelevant if TDI_QUERY_ACCEPT is not set in RequestFlags.
RemoteAddress
Pointer to a buffer specifying the remote-node address for which the local-node client listens in anticipation of a connection offer. This specification can be a partial address if the underlying transport defines the conventions and syntax for specifying partial addresses. This member also can be NULL, indicating that the client will accept an endpoint-to-endpoint connection offer from any remote node.
RemoteAddressLength
Specifies the size in bytes of the buffer at RemoteAddress. Zero indicates that a connection offer from any remote node is acceptable to this client.

The client-supplied buffer at ReturnConnectionInformation in the TDI_REQUEST_KERNEL structure is also formatted as a TDI_CONNECTION_INFORMATION structure. The transport returns information about the connection offer from the remote node in this buffer on completion of this listen request.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

Depending on whether TDI_QUERY_ACCEPT is set in the RequestFlags, the transport completes the listen request either by accepting an offered remote-node connection on behalf of its local-node client or by deferring acceptance or rejection of such an offer to that client.

To initiate a listen request successfully, the local-node client must have its transport address already associated with an idle connection endpoint. That is, the transport has previously satisfied a TDI_ASSOCIATE_ADDRESS request for the file object at IrpSp->FileObject that represents the connection. Part of the context that each transport maintains at FsContext or FsContext2 for a connection endpoint is a pointer to the file object that represents the associated address, which the transport sets up when it makes the association.

After issuing a successful TDI_ASSOCIATE_ADDRESS request, a client can then issue any number of TDI_LISTEN requests, which the transport driver should process in FIFO order until the client accepts an offered connection.

The transport can process requests coming in from all its clients in any driver-determined order.

If a client registered its ClientEvent(Chained)Receive and/or ClientEvent(Chained)ReceiveExpedited handlers on the address associated with the connection endpoint before making its TDI_LISTEN request, receives can come in for that client as soon as the transport accepts the connection from a remote node, even before the transport has completed the client's listen request. Such a client must be prepared for an endpoint-to-endpoint connection to be established as soon as it makes a listen request, and the tranport must be prepared to indicate receives to that client concurrently with completion of the listen request.

In general, a TDI transport driver cannot call a registered ClientEventConnect handler as long as a listen request is pending on the client's open file object that represents the associated local-node address. However, the driver can call ClientEventConnect when such a listen is pending if the transport determines that the remote-address acceptance criteria supplied at IrpSp->Parameters.RequestConnectionInformation will prevent the listen operation from being completed.

Client-supplied remote-node addressing information acts as a filter that the transport applies before checking the RequestFlags for a pending listen request. When an incoming connection offer comes from a remote-node address that does not match the address specified in the listen IRP, the transport cannot complete the listen for its client. When an incoming connection offer from a remote node satisfies the given address-acceptance criteria, the transport can satisfy the client's listen request in either of the following ways:

  • If TDI_QUERY_ACCEPT is not set in the RequestFlags or if the driver does not support delayed-connection acceptance, the transport sends an acceptance to the remote node, sets up the buffer at IrpSp->Parameters.ReturnConectionInformation with appropriate data, as well as setting the status block of the IRP, and returns control.
  • If TDI_QUERY_ACCEPT is set in the RequestFlags, the transport sets up the buffer at IrpSp->Parameters.ReturnConnectionInformation and sets the status block of the IRP, sets up a time-out interval for waiting on the client's acceptance or rejection of the offered connection, and returns control. The local-node client must either accept or reject the offered connection within the time-out interval; otherwise, the tranport must send a rejection to the remote node.

TDI drivers vary in how they handle partial addresses. Because the syntax of a transport address is TDI-driver-specific, the mechanism for specifying a partial address is also specific to each transport driver.

In addition to supporting partial-address specifications on listens, TDI transports can support quality-of-service (QOS) specifications by their clients. For example, a transport might allow its clients to specify QOS using a variable-length counted string with TDI-driver-specific syntax and semantics.

TdiBuildListen is the macro a client uses to fill in this IRP.

See Also

ClientEventConnect, ClientEventChainedReceive, ClientEventChainedReceiveExpedited, ClientEventReceive, ClientEventReceiveExpedited, TDI_ACCEPT, TDI_ASSOCIATE_ADDRESS, TdiBuildListen, TDI_CONNECTION_INFORMATION, TDI_DISCONNECT, TdiDispatchInternalDeviceControl, TDI_REQUEST_KERNEL, TDI_SET_EVENT_HANDLER


TDI_QUERY_INFORMATION

When a kernel-mode client makes a TDI_QUERY_INFORMATION request, it asks the underlying TDI transport driver to return information of a client-specified type, such as a broadcast address, the transport's capabilities, or its current statistics for I/O on a particular connection.

IRP

The transport calls IoGetCurrentIrpStackLocation with the given Irp to get a pointer to its own I/O stack location in the IRP, shown in the following list as IrpSp. The pointer to the IRP is shown in the following list as Irp. IRP members relevant to this request include the following:

Irp->IoStatus.Status
Specifies the final status of the query-information request. The transport sets this member before it completes the IRP, possibly to one of the following:

STATUS_SUCCESS
STATUS_BUFFER_OVERFLOW
STATUS_INSUFFICIENT_RESOURCES
STATUS_INVALID_CONNECTION
STATUS_INVALID_DEVICE_REQUEST
STATUS_NOT_IMPLEMENTED

Irp->IoStatus.Information
Specifies the number of bytes of information the transport is returning to its client.
IrpSp->MajorFunction
Specifies IRP_MJ_INTERNAL_DEVICE_CONTROL. The transport can ignore this member if it exports a TdiDispatchInternalDeviceControl routine that handles only TDI_XXX requests.
IrpSp->MinorFunction
Specifies TDI_QUERY_INFORMATION.
IrpSp->FileObject
Pointer to an open file object representing an address, connection endpoint, or control channel. The transport uses the FsContext and, possibly, FsContext2 fields to access the state it maintains about this address, connection endpoint, or control channel.
IrpSp->Parameters
Pointer to a TDI_REQUEST_KERNEL_QUERY_INFORMATION structure, defined as follows:
struct _TDI_REQUEST_KERNEL_QUERY_INFO {
    LONG QueryType;
    PTDI_CONNECTION_INFORMATION RequestConnectionInformation;
} TDI_REQUEST_KERNEL_QUERY_INFORMATION, *PTDI_REQUEST_KERNEL_QUERY_INFORMATION;

A transport can typically ignore the RequestConnectionInformation member because it is typically NULL. NetBIOS transports might require this member, as described later (see Comments). The transport checks the QueryType member to determine what information the client requested, which also determines the format of the information to be returned and, sometimes the client-supplied contents, of the buffer mapped at Irp->MdlAddress.

For every TDI transport, QueryType can be set to one of the following system-defined values:

TDI_QUERY_ADDRESS_INFO
Requests the transport to return information about a particular local-node address, formatted as a TDI_ADDRESS_INFO structure, in the client-supplied buffer mapped at MdlAddress.

IrpSp->FileObject must point to a file object representing the address or to a connection endpoint already associated with the address for which to return the information.

TDI_QUERY_CONNECTION_INFO
Requests the transport to return information about a particular connection, formatted as a TDI_CONNECTION_INFO structure, in the client-supplied buffer mapped at MdlAddress.

IrpSp->FileObject must point to a file object representing the connection for which to return the information.

TDI_QUERY_BROADCAST_ADDRESS
Requests the transport to return a broadcast address, formatted as a TRANSPORT_ADDRESS structure, in the client-supplied buffer mapped at MdlAddress.

IrpSp->FileObject must point to a file object representing a control channel.

TDI_QUERY_NETWORK_ADDRESS
Requests the transport to return a local-node address, formatted as a TRANSPORT_ADDRESS structure, in the client-supplied buffer mapped at MdlAddress.

IrpSp->FileObject must point to a file object representing a control channel.

TDI_QUERY_DATA_LINK_ADDRESS
Requests the transport to return the datalink address, formatted as a TRANSPORT_ADDRESS structure, in the client-supplied buffer mapped at MdlAddress.

IrpSp->FileObject must point to a file object representing a control channel.

TDI_QUERY_PROVIDER_INFO or TDI_QUERY_PROVIDER_INFORMATION
Requests the transport to return information about its own capabilities, formatted as a TDI_PROVIDER_INFO structure, in the client-supplied buffer mapped at MdlAddress.

IrpSp->FileObject must point to a file object representing a control channel.

TDI_QUERY_PROVIDER_STATISTICS
Requests the transport to return information about its resource usage, formatted as a TDI_PROVIDER_STATISTICS structure, in the client-supplied buffer mapped at MdlAddress.

IrpSp->FileObject must point to a file object representing a control channel.

TDI_QUERY_DATAGRAM_INFO
Requests the transport to return information about its limits on size and number of datagrams, formatted as a TDI_DATAGRAM_INFO structure, in the client-supplied buffer mapped at MdlAddress.

IrpSp->FileObject must point to a file object representing a control channel. A transport also can support this query on open transport addresses at the discretion of the transport writer.

TDI_QUERY_MAX_DATAGRAM_INFO
Requests the transport to return information about its limit on datagram size, formatted as a TDI_MAX_DATAGRAM_INFO structure, in the client-supplied buffer mapped at MdlAddress.

IrpSp->FileObject must point to a file object representing a control channel. A transport also can support this query on open transport addresses at the discretion of the transport writer.

In addition to the preceding queries, which every TDI transport must support, a particular transport might support others. For example, NetBIOS transports also must respond to three additional system-defined TDI_QUERY_XXX, as described later (see Comments).

Irp->MdlAddress
Pointer to an MDL, possibly the initial MDL in a chain of MDLs, mapping a client-supplied buffer containing whatever client-supplied contents are required to carry out the request. The input contents and format of this buffer depend on the given QueryType.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

For any NetBIOS transport, QueryType also can specify one of the following:

TDI_QUERY_FIND_NAME
Requests the NetBIOS transport to return the information, formatted as FIND_NAME_HEADER followed by FIND_NAME_BUFFER structures, in the client-supplied buffer mapped at MdlAddress. For this query type, RequestConnectionInformation must point to a valid TDI_CONNECTION_INFORMATION structure.
TDI_QUERY_SESSION_STATUS
Requests the transport to return the information, formatted as SESSION_HEADER followed by SESSION_BUFFER structures, in the client-supplied buffer mapped at MdlAddress.
TDI_QUERY_ADAPTER_STATUS
Requests the transport to return the information, formatted as an ADAPTER_STATUS structure, in the client-supplied buffer mapped at MdlAddress.

For more information about the preceding NetBIOS-specific structures, see the Platform SDK.

In most cases, TdiBuildQueryInformation is the macro a client uses to fill in this IRP.

Because the TdiBuildQueryInformation macro sets the RequestConnectionInformation member of the TDI_REQUEST_KERNEL_QUERY_INFORMATION structure to NULL, a client of a NetBIOS transport cannot use TdiBuildQueryInformation with query type TDI_QUERY_FIND_NAME. To set up an IRP for a TDI_QUERY_INFORMATION request using TDI_QUERY_FIND_NAME, a client of a NetBIOS transport can use code similar to the code for TdiBuildQueryInformation but must specify a pointer to a TDI_CONNECTION_INFORMATION structure for RequestConnectionInformation.

See Also

TDI_ADDRESS_INFO, TDI_CONNECTION_INFO, TDI_CONNECTION_INFORMATION, TDI_DATAGRAM_INFO, TdiDispatchInternalDeviceControl, TDI_MAX_DATAGRAM_INFO, TDI_PROVIDER_INFO, TDI_PROVIDER_STATISTICS, TdiBuildQueryInformation, TRANSPORT_ADDRESS


TDI_RECEIVE

When a kernel-mode client makes a TDI_RECEIVE request, it asks the underlying TDI transport driver to indicate a normal or expedited TSDU on an established endpoint-to-endpoint connection.

IRP

The transport calls IoGetCurrentIrpStackLocation with the given Irp to get a pointer to its own I/O stack location in the IRP, shown in the following list as IrpSp. The pointer to the IRP is shown in the following list as Irp. IRP members relevant to this request include the following:

Irp->IoStatus.Status
Specifies the final status of the receive request. The transport sets this member before it completes the IRP, possibly to one of the following:

STATUS_PENDING
STATUS_INSUFFICIENT_RESOURCES
STATUS_INVALID_CONNECTION
STATUS_BUFFER_OVERFLOW

Irp->IoStatus.Information
Specifies the number of bytes of received data the transport is returning in the client-supplied buffer.
IrpSp->MajorFunction
Specifies IRP_MJ_INTERNAL_DEVICE_CONTROL. The transport can ignore this member if it exports a TdiDispatchInternalDeviceControl routine that handles only TDI_XXX requests.
IrpSp->MinorFunction
Specifies TDI_RECEIVE.
IrpSp->FileObject
Pointer to an open file object representing the connection endpoint. The transport uses the FsContext and, possibly, FsContext2 fields to access the state it maintains about this connection.

This client already established an endpoint-to-endpoint connection with a remote-node peer on this connection endpoint.

IrpSp->Parameters
Pointer to a TDI_REQUEST_KERNEL_RECEIVE structure, defined as follows:
struct _TDI_REQUEST_KERNEL_RECEIVE {
    ULONG ReceiveLength;
    ULONG ReceiveFlags;
} TDI_REQUEST_KERNEL_RECEIVE, *PTDI_REQUEST_KERNEL_RECEIVE;

The transport uses the members of this structure as follows:

ReceiveLength
Specifies the size in bytes of the client-supplied buffer mapped at Irp->MdlAddress.
ReceiveFlags
Specifies the type of receive this client is requesting, as described later (see Comments).
Irp->MdlAddress
Pointer to an MDL, possibly the initial MDL in a chain, mapping a client-supplied buffer in which the transport returns the received data.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

When a client calls TdiBuildReceive to set up this IRP, it can specify the type of receive it wants. The transport finds this information at IrpSp->Parameters in the ReceiveFlags member. On input, ReceiveFlags can be zero or set with any combination (ORed) of the following flags:

TDI_RECEIVE_NORMAL
The transport should return a normal TSDU to this client.
TDI_RECEIVE_EXPEDITED
The transport should return an expedited TSDU to this client.
TDI_RECEIVE_PEEK
The transport should return any available received data that it has buffered internally at once, even if it is only a partial TSDU, to this client.

If ReceiveFlags is zero or set with both (ORed) TDI_RECEIVE_NORMAL and TDI_RECEIVE_EXPEDITED on input, either normal or expedited data is acceptable to the client. If only one of these flags is set, the transport should return only the type of TSDU requested. If TDI_RECEIVE_PEEK is set, the transport should return any received data it has buffered internally and retain the data in its internal buffer awaiting a subsequent receive request for the remainder of the TSDU from this client. Some transports, such as TCP/IP and SPX/IPX, do not buffer data internally. However, transport clients, such as Windows Sockets applications, get buffering support for nonbuffering transports from the system AFD driver.

Typically, a transport receives normal data until it fills the receive buffer or it receives an end-of-record indication from the remote node. However, if the transport is receiving normal data and expedited data arrives, the transport must pre-empt its normal receive operation, completing the IRP for the normal receive immediately with any normal data it has already transferred into the client's buffer. Then, the transport must satisfy the client's receive requests for the expedited data. When the transport has indicated all the expedited data to the client, the transport resumes indicating normal receives when the next receive request is submitted by that client.

If the client has registered any ClientEventReceive, ClientEventReceiveExpedited, ClientEventChainedReceive, and/or ClientEventChainedReceiveExpedited handlers for receives on the given connection endpoint, the transport stops indicating receives to the ClientEvent(Chained)Receive(Expedited) routines until the transport has satisfied the receive IRP.

When it calls ClientEventReceive or ClientEventReceiveExpedited, the transport supplies information about the type of receive event it is indicating, which the client can use to set up the ReceiveFlags for a subsequent TDI_RECEIVE request if it is not given the full TSDU. The transport supplies this information to its client by setting the ReceiveFlags parameter to ClientEventReceive(Expedited) with one or more (ORed) of the following flags:

TDI_RECEIVE_NORMAL
The transport is receiving a normal TSDU from the remote node.
TDI_RECEIVE_EXPEDITED
The transport is receiving an expedited TSDU from the remote node.
TDI_RECEIVE_ENTIRE_MESSAGE
If this flag is set, the transport already has a full TSDU available for receipt by the client. When this flag is set, ClientEventReceive is expected to copy the full net packet into an internal buffer and return control without postprocessing the received data, deferring any necessary postprocessing until later.

If this flag remains clear, it is equivalent to setting the (obsolete, but possibly still set by legacy transports) TDI_RECEIVE_PARTIAL flag to indicate that only the initial part of a TSDU is currently available from the transport.

TDI_RECEIVE_COPY_LOOKAHEAD
The transport has received only the lookahead buffer for an indication from the underlying NIC driver, so it sets BytesAvailable to something less than BytesIndicated when the transport calls ClientEventReceive(Expedited) with these parameters. The client should copy the BytesAvailable into an internal buffer (see TdiCopyLookaheadData) and, then, submit one or more receive requests to obtain the remaining data in the TSDU.
TDI_RECEIVE_PEEK
The transport has buffered some receive data internally, but not yet the full TSDU. The client handles such an indication in a similar manner to one in which TDI_RECEIVE_COPY_LOOKAHEAD is set.
TDI_RECEIVE_TRUNCATED
The transport received a TSDU that was truncated.
TDI_RECEIVE_FRAGMENT
The transport received a TSDU that is fragmented.
TDI_RECEIVE_AT_DISPATCH_LEVEL
The transport received the TSDU at IRQL DISPATCH_LEVEL. This flag restricts the set of support routines that the client can call in processing the receive indication. For example, the client cannot call TdiBuildInternalDeviceControlIrp, which can be called only at IRQL PASSIVE_LEVEL, in the context of this receive indication.

When the transport ORs TDI_RECEIVE_ENTIRE_MESSAGE with TDI_RECEIVE_NORMAL and calls the ClientEventChainedReceive handler, the client is given direct read-only access to a full TSDU in the underlying NIC's receive buffers until that client calls TdiReturnChainedReceives with the input TsduDescriptor. For such an indication, the client has no need to issue a TDI_RECEIVE request. In effect, such a transport forwards receive indications from the underlying NDIS miniport driver directly to its client with only the minimal overhead of setting up the parameters to ClientEventChainedReceive, as follows:

  • The transport uses the NDIS_PACKET-type descriptor input to the ProtocolReceivePacket function at the bottom of the transport stack as the TsduDescriptor passed to ClientEventChainedReceive. For each client to which the transport forwards the receive indication, the transport augments the value to be returned by ProtocolReceivePacket by one.
  • The transport retrieves the buffer containing the indicated data from the packet descriptor supplied by the underlying NDIS miniport driver, possibly by calling NdisGetFirstBufferFromPacket(Safe). The transport uses the pointer to this NDIS_BUFFER-type (equivalent to the MDL type) chain as the Tsdu for ClientEventChainedReceive.
  • From the full range of receive data indicated by the underlying NDIS miniport driver, the transport selects the subrange of interest to its client. The driver uses this subrange as the StartingOffset and ReceiveLength for ClientEventChainedReceive.

In a similar manner, such a TDI transport gives ClientEventChainedReceiveExpedited direct read-only access to a full TSDU when TDI_RECEIVE_ENTIRE_MESSAGE is ORed with TDI_RECEIVE_EXPEDITED in the input RequestFlags.

For a TSDU indicated to a ClientEventChainedReceive(Expedited) handler, the client retains control of all miniport driver-allocated resources for the receive indication until it calls TdiReturnChainedReceives with the TsduDescriptor. As each client that received the indication calls TdiReturnChainedReceives, the NDIS library decrements the counter it maintains for the packet descriptor, which was set originally to the value returned by the ProtocolReceivePacket function at the bottom of the transport stack. When all clients that received the indication have called TdiReturnChainedReceives, NDIS returns control of all resources specified by that packet descriptor to the NDIS miniport driver that allocated these resources.

When such a transport is called at its ProtocolReceive function with a full-packet indication made by the underlying NDIS miniport driver, the TDI transport must not call a registered ClientEventChainedReceive or ClientEventChainedReceiveExpedited handler with the indication. Instead, it should copy the indicated data for its client into a transport-allocated buffer and call the ClientEventReceive(Expedited) handler. An NDIS call to the ProtocolReceive function at the bottom of the transport stack implies that the underlying miniport driver expects all higher level network drivers to copy the receive data it is indicating and to return its packet descriptor (and all the miniport driver's resources that it describes) as quickly as possible because the miniport driver is short on NIC receive buffer space.

See Also

ClientEventChainedReceive, ClientEventChainedReceiveExpedited, ClientEventReceive, ClientEventReceiveExpedited, NdisGetFirstBufferFromPacket, NdisGetFirstBufferFromPacketSafe, NDIS_PACKET, ProtocolReceive, ProtocolReceivePacket, TdiBuildReceive, TdiCopyLookaheadData, TdiDispatchInternalDeviceControl, TdiReturnChainedReceives


TDI_RECEIVE_DATAGRAM

When a kernel-mode client makes a TDI_RECEIVE_DATAGRAM request, it asks the underlying TDI transport driver to indicate a TSDU, as a datagram, on a specified address.

IRP

The transport calls IoGetCurrentIrpStackLocation with the given Irp to get a pointer to its own I/O stack location in the IRP, shown in the following list as IrpSp. The pointer to the IRP is shown in the following list as Irp. IRP members relevant to this request include the following:

Irp->IoStatus.Status
Specifies the final status of the receive-datagram request. The transport sets this member before it completes the IRP, possibly to one of the following:

STATUS_PENDING
STATUS_INSUFFICIENT_RESOURCES
STATUS_INVALID_ADDRESS
STATUS_BUFFER_OVERFLOW
STATUS_BUFFER_TOO_SMALL

Irp->IoStatus.Information
Specifies the number of bytes of received data the transport is returning in the client-supplied buffer.
IrpSp->MajorFunction
Specifies IRP_MJ_INTERNAL_DEVICE_CONTROL. The transport can ignore this member if it exports a TdiDispatchInternalDeviceControl routine that handles only TDI_XXX requests.
IrpSp->MinorFunction
Specifies TDI_RECEIVE_DATAGRAM.
IrpSp->FileObject
Pointer to an open file object representing the local-node address. The transport uses the FsContext and, possibly, FsContext2 fields to access the state it maintains about this address.
IrpSp->Parameters
Pointer to a TDI_REQUEST_KERNEL_RECEIVEDG structure, defined as follows:
struct _TDI_REQUEST_KERNEL_RECEIVEDG {
    ULONG ReceiveLength;
    PTDI_CONNECTION_INFORMATION ReceiveDatagramInformation;
    PTDI_CONNECTION_INFORMATION ReturnInformation;
    ULONG ReceiveFlags;
} TDI_REQUEST_KERNEL_RECEIVEDG, *PTDI_REQUEST_KERNEL_RECEIVEDG;

The transport uses the members of this structure as follows:

ReceiveLength
Specifies the maximum size in bytes of the client-supplied receive buffer. If this member is zero, the transport can use the full buffer mapped at Irp->MdlAddress.
ReceiveDatagramInformation
Pointer to a TDI_CONNECTION_INFORMATION structure, specifying either the remote address from which the client expects to receive a datagram or zero in the RemoteAddressLength member if a datagram from any remote node is acceptable to this client.
ReturnInformation
Pointer to a caller-supplied buffer, formatted as a TDI_CONNECTION_INFORMATION structure, in which the transport returns the remote-node address from which the returned datagram was received.
ReceiveFlags
Specifies the type of datagram the client expects as none (zero), one, or a combination (ORed) of the following flags:

TDI_RECEIVE_NORMAL – return normal datagram

TDI_RECEIVE_PEEK – return any available portion of datagram

Irp->MdlAddress
Pointer to an MDL, possibly the initial MDL in a chain, mapping a client-supplied buffer in which the transport returns the received datagram.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

Because a datagram is never associated with an endpoint-to-endpoint connection, the transport must return the address of the remote-node client to the receiving client along with each datagram.

TDI transports do not fragment datagrams. Consequently, a client makes a single receive-datagram request for a full datagram, unless it sets the TDI_RECEIVE_PEEK flag. When a TDI transport driver receives a datagram from a remote node, it completes a client's receive-datagram request if both of the following are true:

  • The just received datagram has a destination address that matches the local-node address represented by the file object at IrpSp->FileObject.
  • The just received datagram has a source address that either matches the value specified in RemoteAddress at IrpSp->Parameters or RemoteAddressLength is zero and RemoteAddress is NULL.

If the received datagram is too large for the client-supplied buffer mapped at Irp->MdlAddress, the transport fills this buffer with ReceiveLength bytes and completes the client's receive-datagram IRP. In effect, a client receives a truncated datagram if that client does not provide a large enough buffer with its receive-datagram request.

A local-node client can also receive datagrams by issuing TDI_SET_EVENT_HANDLER requests to register its ClientEventReceiveDatagram and/or ClientEventChainedReceiveDatagram handlers for a particular address. The transport supplies this information to its client by setting the ReceiveDatagramFlags parameter to ClientEvent(Chained)ReceiveDatagram with any of the flags listed in the reference for TDI_RECEIVE, except TDI_RECEIVE_EXPEDITED. In addition, for datagram indications, the ReceiveDatagramFlags can be set with either of the following:

TDI_RECEIVE_BROADCAST
The received TSDU was broadcast.
TDI_RECEIVE_MULTICAST
The received TSDU was multicast.

A TDI client can receive a broadcast datagram by opening a file object that represents the underlying transport's broadcast address. Any broadcast address has a driver-specific format, which the client can obtain by issuing a TDI_QUERY_INFORMATION request to the underlying transport. A transport does not allow its clients to send datagrams from a broadcast address, and the transport fails any client-issued TDI_ASSOCIATE_ADDRESS requests that specify its broadcast address.

TdiBuildReceiveDatagram is the macro a client uses to fill in the IRP.

See Also

ClientEventChainedReceiveDatagram, ClientEventReceiveDatagram, TdiBuildReceiveDatagram, TDI_CONNECTION_INFORMATION, TdiDispatchInternalDeviceControl, TDI_QUERY_INFORMATION, TDI_SET_EVENT_HANDLER


TDI_SEND

When a kernel-mode client makes a TDI_SEND request, it asks the underlying TDI transport driver to transmit a normal or expedited TSDU on a specified connection endpoint to its remote-node peer.

IRP

The transport calls IoGetCurrentIrpStackLocation with the given Irp to get a pointer to its own I/O stack location in the IRP, shown in the following list as IrpSp. The pointer to the IRP is shown in the following list as Irp. IRP members relevant to this request include the following:

Irp->IoStatus.Status
Specifies the final status of the send request. The transport sets this member before it completes the IRP, possibly to one of the following:

STATUS_SUCCESS
STATUS_PENDING
STATUS_INVALID_CONNECTION
STATUS_INVALID_PARAMETER
STATUS_DEVICE_NOT_READY

Irp->IoStatus.Information
Specifies the number of bytes of client-supplied data the driver transferred from the client-supplied buffer mapped at Irp->MdlAddress.
IrpSp->MajorFunction
Specifies IRP_MJ_INTERNAL_DEVICE_CONTROL. The transport can ignore this member if it exports a TdiDispatchInternalDeviceControl routine that handles only TDI_XXX requests.
IrpSp->MinorFunction
Specifies TDI_SEND.
IrpSp->FileObject
Pointer to an open file object representing the connection endpoint. The transport uses the FsContext and, possibly, FsContext2 fields to access the state it maintains about this connection.

The client already established an endpoint-to-endpoint connection with a remote-node peer on this connection endpoint.

IrpSp->Parameters
Pointer to a TDI_REQUEST_KERNEL_SEND structure, defined as follows:
struct _TDI_REQUEST_KERNEL_SEND {
    ULONG SendLength;
    ULONG SendFlags;
} TDI_REQUEST_KERNEL_SEND, *PTDI_REQUEST_KERNEL_SEND;

The transport uses the members of this structure as follows:

SendLength
Specifies the number of bytes of data to be sent in the buffer mapped at Irp->MdlAddress.
SendFlags
Specifies the type of TSDU the client expects to be sent as none (zero), one, or a combination (ORed) of TDI_SEND_XXX flags (see Comments).
Irp->MdlAddress
Pointer to an MDL, possibly the initial MDL in a chain, mapping a client-supplied buffer containing the data to be sent.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

When a client calls TdiBuildSend to set up this IRP, it can specify the type of send it wants. The transport finds this information at IrpSp->Parameters in the SendFlags member. On input, SendFlags can be zero or set with any combination (ORed) of the following flags:

TDI_SEND_EXPEDITED
The given data should be sent ahead of any normal send requests the transport is currently holding queued for transmission on this endpoint-to-endpoint connection. If the transport does not support expedited transfers, it can ignore this flag.
TDI_SEND_PARTIAL
The given data is not a complete message-mode TSDU. The client will send the remaining data for the TSDU later. This flag is irrelevant to stream-mode transports.

If this flag is clear in a send submitted to a message-mode transport, the driver inserts an end-of-record mark in the line flow after sending all data supplied in the client's buffer.

TDI_SEND_NO_RESPONSE_EXPECTED
The caller is giving a hint to the underlying transport that it does not expect a response to this send from its remote-node peer. This flag should disable piggybacking of the TSDU acknowledgment by the remote-node transport.
TDI_SEND_NON_BLOCKING
If the underlying transport currently has no internal buffer space available for the given data, it should just complete the IRP with STATUS_DEVICE_NOT_READY. If the transport has some buffer space available, it should copy as much data as it can from the client-supplied buffer, set the IoStatus.Information member to the number of bytes it copied, and complete the IRP with STATUS_SUCCESS.

This flag is irrelevant to transports that do not buffer sends internally.

Each local-node client send request is associated with exactly one of the following:

  • A receive request issued by the remote-node client to its underlying transport
  • A remote-node transport's call to its client's registered ClientEventReceive, ClientEventReceiveExpedited, ClientEventChainedReceive, or ClientEventChainedReceiveExpedited handler

The local-node TDI transport driver can queue any number of send requests on a particular connection, but it must process them in FIFO order, unless the client issues an expedited send. Each expedited send request must be queued and transmitted ahead of any normal send requests the transport is holding queued, and each expedited send also must be transmitted in FIFO order for the client.

The transport must complete each send IRP in a timely manner, whether with a success or error status. The driver should determine a reasonable time-out based on its knowledge of underlying network conditions.

Depending on the underlying transport, clients can send stream-mode or message-mode TSDUs, the latter with one or more send requests. For stream-mode transports, the client does not delimit messages and the TDI_SEND_PARTIAL flag is irrelevant. For message-mode transports, the client can send a TSDU as a sequence of send requests, each specifying the TDI_SEND_PARTIAL flag. If this flag is clear in a submitted send request, a message-mode transport considers the data to be the end of such a sequence or a complete TSDU. The remote-node TDI transport notifies the receiving client of partial TSDUs through receive indicators passed in the corresponding receive indications.

In its send request, the sending client provides a buffer containing the TSDU. The client can provide a buffer of any size up to the transport-determined limit. The transport is given ownership of this client-supplied buffer until it completes the send. The transport fails any send request for which a client specifies a SendLength larger than the transport supports.

Clients can determine their underlying transports' send-size limits by submitting TDI_QUERY_PROVIDER_INFO-type queries.

If the transport buffers client-supplied send data internally, the client can request a nonblocking send by setting the TDI_SEND_NON_BLOCKING flag. When such a transport is given a send request with this flag set, it completes the IRP with STATUS_DEVICE_NOT_READY if it cannot copy the given data into its internal buffer space. Such a transport returns STATUS_SUCCESS if it buffers only a part of the given TSDU internally, but it must set IoStatus.Information in such an IRP to the number of bytes it buffered internally so its client can submit a subsequent send for the remaining data in the original send request.

Any client that submits nonblocking send requests usually registers a ClientEventSendPossible handler. The underlying transport calls this handler after it has rejected a send request with STATUS_DEVICE_NOT_READY as soon as that transport has internal buffer space available for holding send data.

A transport also can support zero-length send requests. A zero-length send in which the TDI_SEND_PARTIAL flag is clear actually forces protocol flow. The client of such a transport can issue zero-length send to satisfy a receive request. If the driver does not support zero-length sends, it should return an error when its clients submit zero-length send requests.

TdiBuildSend is the macro a client uses to fill in the IRP.

See Also

ClientEventChainedReceive, ClientEventChainedReceiveExpedited, ClientEventReceive, ClientEventReceiveExpedited, ClientEventSendPossible, TdiBuildSend, TdiDispatchInternalDeviceControl, TDI_QUERY_INFORMATION, TDI_RECEIVE


TDI_SEND_DATAGRAM

When a kernel-mode client makes a TDI_SEND_DATAGRAM request, it asks the underlying TDI transport driver to transmit a TSDU, as a datagram, to a specified remote-node address.

IRP

The transport calls IoGetCurrentIrpStackLocation with the given Irp to get a pointer to its own I/O stack location in the IRP, shown in the following list as IrpSp. The pointer to the IRP is shown in the following list as Irp. IRP members relevant to this request include the following:

Irp->IoStatus.Status
Specifies the final status of the send-datagram request. The transport sets this member before it completes the IRP, possibly to one of the following:

STATUS_PENDING
STATUS_INSUFFICIENT_RESOURCES
STATUS_INVALID_ADDRESS
STATUS_INVALID_PARAMETER

Irp->IoStatus.Information
Specifies the number of bytes of client-supplied data the driver transferred from the client-supplied buffer mapped at Irp->MdlAddress.
IrpSp->MajorFunction
Specifies IRP_MJ_INTERNAL_DEVICE_CONTROL. The transport can ignore this member if it exports a TdiDispatchInternalDeviceControl routine that handles only TDI_XXX requests.
IrpSp->MinorFunction
Specifies TDI_SEND_DATAGRAM.
IrpSp->FileObject
Pointer to an open file object representing the local-node address. The transport uses the FsContext and, possibly, FsContext2 fields to access the state it maintains about this address.
IrpSp->Parameters
Pointer to a TDI_REQUEST_KERNEL_SENDDG structure, defined as follows:
struct _TDI_REQUEST_KERNEL_SENDDG {
    ULONG SendLength;
    PTDI_CONNECTION_INFORMATION SendDatagramInformation;
} TDI_REQUEST_KERNEL_SENDDG, *PTDI_REQUEST_KERNEL_SENDDG;

The transport uses the members of this structure as follows:

SendLength
Specifies the number of bytes in the datagram to send.
SendDatagramInformation
Pointer to a TDI_CONNECTION_INFORMATION structure specifying the remote-node address to which the local-node client wants the datagram to be sent.
Irp->MdlAddress
Pointer to an MDL, possibly the initial MDL in a chain, mapping a client-supplied buffer containing the datagram to be sent.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

A TDI transport does not send fragmented datagrams. Consequently, its client makes one send-datagram request to send each datagram, which is associated only with the particular request for a connectionless data transfer operation.

In its send-datagram request, the sending client provides a buffer containing the TSDU. The client can provide a buffer of any size up to the transport-determined limit. The transport is given ownership of this client-supplied buffer until it completes the send-datagram IRP. The transport fails any send-datagram request for which a client specifies a SendLength larger than the transport supports.

Clients can determine their underlying transports' send-size limits by submitting query-information requests with QueryType set to any of TDI_QUERY_PROVIDER_INFO, TDI_QUERY_DATAGRAM_INFO, or TDI_QUERY_MAX_DATAGRAM_INFO.

A transport can allow its clients to send zero-length datagrams. For example, a zero-length send-datagram request might force protocol flow.

Some transports allow clients to direct datagrams to remote-node multicast and/or broadcast addresses. The syntax of such a multicast or broadcast address is transport-specific.

As a connectionless transfer, a datagram-send is inherently unreliable. The transport can drop or duplicate a datagram at the discretion of the driver writer. The transport must complete each send-datagram IRP in a timely manner, whether with a success or error status. The driver should determine a reasonable time-out based on its knowledge of underlying network conditions.

If it queues datagrams internally, the transport must process send-datagram requests in FIFO order. Send-datagram requests should be queued separately from endpoint-to-endpoint send requests.

TdiBuildSendDatagram is the macro a client uses to fill in this IRP.

See Also

TdiBuildSendDatagram, TDI_CONNECTION_INFORMATION, TdiDispatchInternalDeviceControl, TDI_QUERY_INFORMATION, TDI_RECEIVE_DATAGRAM


TDI_SET_EVENT_HANDLER

When a kernel-mode client makes a TDI_SET_EVENT_HANDLER request, it asks the underlying TDI transport driver to call the specified ClientEventXxx routine whenever the corresponding network event occurs.

IRP

The transport calls IoGetCurrentIrpStackLocation with the given Irp to get a pointer to its own I/O stack location in the IRP, shown in the following list as IrpSp. The pointer to the IRP is shown in the following list as Irp. IRP members relevant to this request include the following:

Irp->IoStatus.Status
Specifies the final status of the set-event-handler request. The transport sets this member before it completes the IRP, possibly to one of the following:

STATUS_SUCCESS
STATUS_INVALID_ADDRESS_COMPONENT
STATUS_INVALID_PARAMETER

The IoStatus.Information member is zero because no data is transferred for this request.

IrpSp->MajorFunction
Specifies IRP_MJ_INTERNAL_DEVICE_CONTROL. The transport can ignore this member if it exports a TdiDispatchInternalDeviceControl routine that handles only TDI_XXX requests.
IrpSp->MinorFunction
Specifies TDI_SET_EVENT_HANDLER.
IrpSp->FileObject
Pointer to an open file object representing a local-node address. The transport uses the FsContext and, possibly, FsContext2 fields to access the state it maintains about this address.

Depending on the type of ClientEventXxx handler to be registered, this address might be or become associated with an established endpoint-to-endpoint connection made by this client.

IrpSp->Parameters
Pointer to a TDI_REQUEST_KERNEL_SET_EVENT structure, defined as follows:
struct _TDI_REQUEST_KERNEL_SET_EVENT {
    LONG EventType;
    PVOID EventHandler;
    PVOID EventContext;
} TDI_REQUEST_KERNEL_SET_EVENT, *PTDI_REQUEST_KERNEL_SET_EVENT;

The transport uses the members of this structure as follows:

EventType
Specifies the type of ClientEventXxx handler to be registered (see Comments).
EventHandler
Specifies the entry point of the ClientEventXxx routine to be called when this type of event occurs. This member can be NULL if the client is deregistering a previously registered event handler.
EventContext
Specifies a pointer to be passed, uninterpreted by the transport, to the given ClientEventXxx routine whenever it is called. This member is NULL if EventHandler is NULL.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

When its client first opens a file object that represents an address, a TDI transport initializes all event handlers associated with that address to NULL for the client.

Subsequently when the client calls TdiBuildSetEventHandler to set up this IRP, it specifies the type of handler to be registered. The transport finds this information at IrpSp->Parameters in the EventType member. On input, EventType can be one of the following system-defined values:

TDI_EVENT_CONNECT
Register the given ClientEventConnect handler to be called when an endpoint-to-endpoint connection is offered by a remote-node peer.
TDI_EVENT_DISCONNECT
Register the given ClientEventDisconnect handler to be called when an established endpoint-to-endpoint connection is being closed by the remote-node peer.
TDI_EVENT_RECEIVE
Register the given ClientEventReceive handler to be called when a normal receive comes in on an endpoint-to-endpoint connection from the remote node and the transport will give the client the opportunity to copy all or part of the buffered TSDU.
TDI_EVENT_CHAINED_RECEIVE
Register the given ClientEventChainedReceive handler to be called when a normal receive comes in on an endpoint-to-endpoint connection from the remote node and the transport can give this client read-only access to the buffered full TSDU until the client calls TdiReturnChainedReceives with the TsduDescriptor.
TDI_EVENT_RECEIVE_EXPEDITED
Register the given ClientEventReceiveExpedited handler to be called when an expedited receive comes in on an endpoint-to-endpoint connection from the remote node and the transport will give this client the opportunity to copy all or part of the buffered TSDU.
TDI_EVENT_CHAINED_RECEIVE_EXPEDITED
Register the given ClientEventChainedReceiveExpedited handler to be called when an expedited receive comes in on an endpoint-to-endpoint connection from the remote node and the transport can give this client read-only access to the buffered full TSDU until the client calls TdiReturnChainedReceives with the TsduDescriptor.
TDI_EVENT_RECEIVE_DATAGRAM
Register the given ClientEventReceive handler to be called when a datagram comes in from a remote node and the transport will give this client the opportunity to copy all or part of the buffered TSDU.
TDI_EVENT_CHAINED_RECEIVE_DATAGRAM
Register the given ClientEventChainedReceiveDatagram handler to be called when a datagram comes in from a remote node and the transport can give this client read-only access to the buffered full TSDU until the client calls TdiReturnChainedReceives with the TsduDescriptor.
TDI_EVENT_SEND_POSSIBLE
Register the given ClientEventSendPossible handler to be called when the underlying transport, which previously returned a submitted send request with STATUS_DEVICE_NOT_READY, next has internal buffer space available into which it can copy the resubmitted client-supplied data to be sent.
TDI_EVENT_ERROR
Register the given ClientEventError handler to be called if an error occurs in the transport or in an underlying driver such that network I/O on this local-node address has become unreliable or impossible.
TDI_EVENT_ERROR_EX
Register the given ClientEventErrorEx handler to be called if an error occurs in the transport or in an underlying driver such that network I/O on this local-node address has become unreliable or impossible.

In addition to the preceding system-defined events, a transport can extend this interface at the discretion of the driver writer to support notifications of transport-specific events to kernel-mode clients. Such a transport must define TDI_EVENT_XXX codes in which the most significant bit is set.

A TDI transport can indicate an event to a client while an event of the same kind is in progress. In other words, ClientEventXxx handlers are re-entrant.

A TDI transport can call a client-supplied ClientEvent(Chained)ReceiveXxx handler immediately if it is receiving data from the remote node, even before the transport completes the set-event-handler IRP that provided this client entry point.

In general, a transport calls ClientEventChainedReceiveXxx handlers when the ProtocolReceivePacket function at the bottom of the transport stack is called with a receive indication. A call to ProtocolReceivePacket implies that the underlying NDIS miniport driver is temporarily relinquishing ownership of all its resources for the indication specified by the input NDIS_PACKET-type descriptor until that packet descriptor is returned to this underlying NDIS miniport driver.

The transport must set up such an indication as previously described (see TDI_RECEIVE), passing the NDIS_PACKET-type descriptor as the TsduDescriptor input to its clients' ClientEventChainedReceiveXxx handlers. The clients' subsequent calls to TdiReturnChainedReceives returns the TsduDescriptor and all resources it describes directly to NDIS, which returns these resources to the indicating miniport driver underlying the transport when all such clients have consumed the received data.

On the other hand, a transport calls ClientEventReceiveXxx handlers when the transport's ProtocolReceive function is called with a receive indication. A call to ProtocolReceive implies that the underlying NDIS driver expects all higher level network components to copy the indicated data and return as quickly as possible so the lower driver can regain control of the resources it used to make the receive indication.

A client can disable an already registered event handler by making a subsequent TDI_SET_EVENT_HANDLER request in which the EventType member specifies the type of handler but the EventHandler and EventContext members are NULL.

TdiBuildSetEventHandler is the macro a client uses to fill in the IRP.

See Also

ClientEventChainedReceive, ClientEventChainedReceiveDatagram, ClientEventChainedReceiveExpedited, ClientEventConnect, ClientEventDisconnect, ClientEventError, ClientEventErrorEx, ClientEventReceive, ClientEventReceiveDatagram, ClientEventReceiveExpedited, ClientEventSendPossible, ProtocolReceive, ProtocolReceivePacket, TdiBuildSetEventHandler, TdiDispatchInternalDeviceControl, TDI_RECEIVE, TdiReturnChainedReceives


TDI_SET_INFORMATION

When a kernel-mode client makes a TDI_SET_INFORMATION request, it asks the underlying TDI transport driver to set information of a client-specified type on a particular address, connection, or control channel.

IRP

The transport calls IoGetCurrentIrpStackLocation with the given Irp to get a pointer to its own I/O stack location in the IRP, shown in the following list as IrpSp. The pointer to the IRP is shown in the following list as Irp. IRP members relevant to this request include the following:

Irp->IoStatus.Status
Specifies the final status of the set-information request. The transport sets this member before it completes the IRP, possibly to one of the following:

STATUS_SUCCESS
STATUS_INVALID_ADDRESS_COMPONENT
STATUS_INVALID_CONNECTION
STATUS_INVALID_DEVICE_REQUEST
STATUS_INVALID_PARAMETER
STATUS_INSUFFICIENT_RESOURCES
STATUS_NOT_IMPLEMENTED

Irp->IoStatus.Information
Specifies the number of bytes of client-supplied data the driver used from the buffer mapped at Irp->MdlAddress.
IrpSp->MajorFunction
Specifies IRP_MJ_INTERNAL_DEVICE_CONTROL. The transport can ignore this member if it exports a TdiDispatchInternalDeviceControl routine that handles only TDI_XXX requests.
IrpSp->MinorFunction
Specifies TDI_SET_INFORMATION.
IrpSp->FileObject
Pointer to an open file object representing a local-node address, connection endpoint, or control channel. The transport uses the FsContext and, possibly, FsContext2 fields to access the state it maintains about this address, connection, or control channel.
IrpSp->Parameters
Pointer to a TDI_REQUEST_KERNEL_SET_INFORMATION structure, defined as follows:
struct _TDI_REQUEST_KERNEL_SET_INFO {
    LONG SetType;
    PTDI_CONNECTION_INFORMATION RequestConnectionInformation;
} TDI_REQUEST_KERNEL_SET_INFORMATION, *PTDI_REQUEST_KERNEL_SET_INFORMATION;

The transport uses the members of this structure as follows:

SetType
Specifies the type of set operation to carry out (see Comments).
RequestConnectionInformation
Pointer to a TDI_CONNECTION_INFORMATION structure containing input connection information if the given file object represents a connection. Otherwise, this member is NULL.
Irp->MdlAddress
Pointer to an MDL mapping a client-supplied buffer containing the data to be set. The format and contents of this buffer depend on the value of SetType.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

When a client calls TdiBuildSetInformation to set up this IRP, it must specify the type of set operation it wants done and must provide a buffer containing appropriate data. The transport finds this information at IrpSp->Parameters in the SetType member. On input, SetType can be any of the following subset of the system-defined TDI_QUERY_XXX:

TDI_QUERY_ADDRESS_INFO
Set information for an address. The client-supplied buffer mapped at MdlAddress contains data formatted as a TDI_ADDRESS_INFO structure.
TDI_QUERY_CONNECTION_INFO
Set information for a connection endpoint. The client-supplied buffer mapped at MdlAddress contains data formatted as a TDI_CONNECTION_INFO structure.
TDI_QUERY_PROVIDER_INFO
Set information for a control channel. The client-supplied buffer mapped at MdlAddress contains data formatted as a TDI_PROVIDER_INFO structure.
TDI_QUERY_PROVIDER_STATISTICS
Set statistics information for a control channel. The client-supplied buffer mapped at MdlAddress contains data formatted as a TDI_PROVIDER_STATISTICS structure.

A transport can extend this interface at the discretion of the driver writer to support additional set operations for its clients. Such a transport must define TDI_QUERY_XXX codes in which the most significant bit is set.

The transport must fail any set-information request in which the given file object is inappropriate to the specified SetType.

The transport also can fail any set-information request for which the client supplies values that exceed a driver-determined limit. For example, most transports do not allow their clients to reset the MaxDatagramSize or MaxSendSize with TDI_QUERY_PROVIDER_INFO-type set-information requests.

TdiBuildSetInformation is the macro a client uses to fill in this IRP.

See Also

TDI_ADDRESS_INFO, TDI_CONNECTION_INFO, TDI_CONNECTION_INFORMATION, TdiBuildSetInformation, TdiDispatchInternalDeviceControl, TDI_PROVIDER_INFO, TDI_PROVIDER_STATISTICS


TDI Functions

This describes system-supplied Tdi Xxx functions that are called by transport drivers or by their kernel-mode clients.

The functions described here are in alphabetic order. For quick reference, the following summarizes which of these Tdi Xxx functions can be called by TDI transports, by their clients, or by both.

TdiXxx Function | Called by
TdiCompleteRequest | Transports
TdiCopyBufferToMdl | Transports and clients
TdiCopyMdlToBuffer | Transports and clients
TdiCopyMdlChainToMDLChain | Transports and clients
TdiCopyLookaheadData | NDIS protocol drivers (lower edge of transports)
TdiInitialize | Transports
TdiMapUserRequest | Transports
TdiMatchPdoWithChainedReceiveContext | Transports
TdiReturnChainedReceives | Clients
TdiRegisterPnPHandlers | Clients of PnP-aware transports
TdiDeregisterPnPHandlers | Clients of PnP-aware transports
TdiRegisterProvider | PnP-aware transports
TdiProviderReady | PnP-aware transports
TdiDeregisterProvider | PnP-aware transports
TdiRegisterDeviceObject | PnP-aware transports
TdiDeregisterDeviceObject | PnP-aware transports
TdiRegisterNetAddress | PnP-aware transports
TdiDeregisterNetAddress | PnP-aware transports
TdiEnumerateAddresses | Clients of PnP-aware transports
TdiPnPPowerRequest | PnP-aware transports (and NDIS)
TdiPnPPowerComplete | Clients of PnP-aware transports


TdiCompleteRequest

The TdiCompleteRequest function completes a given IRP with a transport-supplied status.

VOID
  TdiCompleteRequest(
    IN PIRP  Irp,
    IN NTSTATUS  Status
    );

Parameters

Irp
Pointer to the IRP to be completed.
Status
Specifies the final status of the request.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

TdiCompleteRequest sets the given Status value in the IoStatus.Status member of the given IRP and completes the IRP with the system-defined IO_NETWORK_INCREMENT priority boost to the thread that originally made the I/O request. Consequently, transports usually call TdiCompleteRequest with STATUS_SUCCESS, because IRPs to be failed with an error status should be completed with IO_NO_INCREMENT as the PriorityBoost passed to IoCompleteRequest.

Only transports call TdiCompleteRequest.

Callers of TdiCompleteRequest run at IRQL <= DISPATCH_LEVEL.

See Also

TdiDispatchCleanup, TdiDispatchClose, TdiDispatchCreate, TdiDispatchDeviceControl, TdiDispatchInternalDeviceControl


TdiCopyBufferToMdl

The TdiCopyBufferToMdl function copies data from a buffer range into a set of one or more destination buffers mapped by a given MDL chain.

NTSTATUS
  TdiCopyBufferToMdl(
    IN PVOID  SourceBuffer,
    IN ULONG  SourceOffset,
    IN ULONG  SourceBytesToCopy,
    IN PMDL  DestinationMdlChain,
    IN ULONG  DestinationOffset,
    IN PULONG  BytesCopied
    );

Parameters

SourceBuffer
Specifies the base virtual address of the source buffer containing the data to be copied.
SourceOffset
Specifies the byte offset within the source buffer at which to begin the copy.
SourceBytesToCopy
Specifies the number of bytes to copy from SourceBuffer to the buffer mapped by the given MDL.
DestinationMdlChain
Pointer to the initial MDL in a chain of linked MDLs mapping the destination buffers into which to copy the data.
DestinationOffset
Specifies the byte offset within the destination buffers at which to begin the copy. Effectively, this is the number of bytes mapped by the given MDLs to skip before beginning the copy operation.
BytesCopied
Pointer to a caller-supplied variable in which TdiCopyBufferToMdl returns the number of bytes copied from the source to the destination buffer.

Return Value

TdiCopyBufferToMdl returns STATUS_SUCCESS if it copied SourceBytesToCopy into the mapped destination buffers. Otherwise, it returns STATUS_BUFFER_OVERFLOW if SourceBytesToCopy was too large to fit into the destination buffer space available from the given DestinationOffset.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

TdiCopyBufferToMdl always copies as much data as possible from the source buffer to the destination buffers, even if it returns STATUS_BUFFER_OVERFLOW. At most, the return value of BytesCopied is equal to the given SourceBytesToCopy.

Both transports and their kernel-mode clients can call TdiCopyBufferToMdl.

Callers of TdiCopyBufferToMdl must be running at IRQL <= DISPATCH_LEVEL if the source and destination buffers are resident. If either is pageable, the caller must be running at IRQL < DISPATCH_LEVEL.

See Also

TdiCopyLookaheadData, TdiCopyMdlToBuffer


TdiCopyLookaheadData

The TdiCopyLookaheadData function safely copies receive data indicated in a lookahead buffer to the transport protocol by the underlying NDIS driver.

VOID
  TdiCopyLookaheadData(
    IN PVOID  Destination,
    IN PVOID  Source,
    IN ULONG  Length,
    IN ULONG  ReceiveFlags
    );

Parameters

Destination
Pointer to a caller-supplied buffer into which to copy the data.
Source
Pointer to the source buffer from which to copy the data.
Length
Specifies how many bytes of data to copy.
ReceiveFlags
Specifies a combination (ORed) of TDI_RECEIVE_XXX flags of which only the following is pertinent to this call:
TDI_RECEIVE_COPY_LOOKAHEAD
Must be set if the underlying NIC driver set the NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA flag in response to the protocol's binding-time call to NdisRequest with the OID_GEN_MAC_OPTIONS query. Otherwise, this flag must be clear in the given ReceiveFlags.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

TdiCopyLookaheadData can be called by a transport's ProtocolReceive function to copy receive data from a lookahead buffer that was indicated up by the underlying NIC driver. In particular, TdiCopyLookaheadData must be called if the underlying NIC driver did not set the NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA flag in response to the transport's OID_GEN_MAC_OPTIONS query.However, TdiCopyLookaheadData can be called by any NDIS driver's ProtocolReceive function, whatever the nature of the receive buffers on the underlying NIC.

Any driver that exports a ProtocolReceive function can call TdiCopyLookaheadData.

Callers of TdiCopyLookaheadData can be running at any IRQL if the buffer at Destination was allocated from nonpaged pool. Otherwise, a caller must be running at IRQL < DISPATCH_LEVEL.

See Also

NdisRequest, ProtocolReceive


TdiCopyMdlChainToMdlChain

The TdiCopyMdlChainToMdlChain function copies data from a set of buffers mapped by a given source MDL chain into the given destination MDL chain.

NTSTATUS
  TdiCopyMdlChainToMdlChain (
    IN PMDL  SourceMdlChain,
    IN ULONG  SourceOffset,
    IN PMDL DestinationMdlChain,
    IN ULONG DestinationOffset,
    OUT PULONG  BytesCopied
    );

Parameters

SourceMdlChain
Pointer to the initial MDL in a chain of MDLs mapping buffers that contain the data to be copied.
SourceOffset
Specifies the byte offset within the mapped source buffers at which to begin the copy. Effectively, this is the number of mapped source bytes to skip before beginning the copy.
DestinationMdlChain
Pointer to the initial MDL in a chain of MDLs mapping buffers into which the data is to be copied.
DestinationOffset
Specifies the byte offset within the mapped destination buffers at which to begin the copy. Effectively, this is the number of mapped destination bytes to skip before beginning the copy.
BytesCopied
Pointer to a caller–supplied variable in which TdiCopyMdlChainToMdlChain returns the number of bytes it copied.

Return Value

If successful, TdiCopyMdlChainToMdlChain returns STATUS_SUCCESS and *BytesCopied contains the number of bytes copied.

If there is not sufficient space in the destination MDL chain or either of the offsets does not lie within the corresponding MDL chains, it returns STATUS_BUFFER_OVERFLOW.

If TDI fails to get the system address for any of the MDLs in the source or destination chains, it returns STATUS_INSUFFICIENT_RESOURCES.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

TdiCopyMdlChainToMdlChain copies data from SourceMdlChain to DestinationMdlChain. SourceOffset indicates the zero-based offset, from the beginning of the data pointed to by SourceMdlChain, at which data source copying starts. DestinationOffset indicates the zero-based offset, from the beginning of data pointed to by DestinationMdlChain, at which TdiCopyMdlChainToMdlChain writes the copied data.

The caller must pass in valid MDL pointers for SourceMdlChain and DestinationMdlChain.

Both transports and their kernel-mode clients can call TdiCopyMdlChainToMdlChain.

Callers of TdiCopyMdlChainToMdlChain must be running at IRQL <= DISPATCH_LEVEL if the source and destination buffers are resident. If either is pageable, the caller must be running at IRQL < DISPATCH_LEVEL.

See Also

TdiCopyMdlToBuffer,MmGetSystemAddressForMdlSafe


TdiCopyMdlToBuffer

The TdiCopyMdlToBuffer function copies data from a set of buffers mapped by a given MDL chain into a caller-supplied destination buffer range.

NTSTATUS
  TdiCopyMdlToBuffer(
    IN PMDL  SourceMdlChain,
    IN ULONG  SourceOffset,
    IN PVOID  DestinationBuffer,
    IN ULONG  DestinationOffset,
    IN ULONG  DestinationBufferSize,
    OUT PULONG  BytesCopied
    );

Parameters

SourceMdlChain
Pointer to the initial MDL in a chain of MDLs mapping buffers containing the data to be copied.
SourceOffset
Specifies the byte offset within the mapped source buffers at which to begin the copy. Effectively, this is the number of mapped source bytes to skip before beginning the copy.
DestinationBuffer
Pointer to the caller-supplied destination buffer.
DestinationOffset
Specifies the byte offset within the destination buffer at which to begin copying the data from the source buffers.
DestinationBufferSize
Specifies the size in bytes of the buffer at DestinationBuffer.
BytesCopied
Pointer to a caller–supplied variable in which TdiCopyMdlToBuffer returns the number of bytes it copied.

Return Value

TdiCopyMdlToBuffer returns STATUS_SUCCESS if it copied (DestinationBufferSize - DestinationOffset) bytes into the destination buffer. Otherwise, it returns STATUS_BUFFER_OVERFLOW if the given SourceMdlChain, starting at SourceOffset, maps more data than the range (DestinationBufferSize - DestinationOffset) can contain.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

TdiCopyMdlToBuffer always copies as much data as possible from the given mapped source buffers into the given destination buffer range, even if it returns STATUS_BUFFER_OVERFLOW.

At most, the return value of BytesCopied can be the given DestinationBufferSize if DestinationOffset is zero.

Both transports and their kernel-mode clients can call TdiCopyMdlToBuffer.

Callers of TdiCopyMdlToBuffer must be running at IRQL <= DISPATCH_LEVEL if the source and destination buffers are resident. If either is pageable, the caller must be running at IRQL < DISPATCH_LEVEL.

See Also

TdiCopyLookaheadData, TdiCopyBufferToMdl


TdiDeregisterAddressChangeHandler

The TdiDeregisterAddressChangeHandler function is obsolete. See TdiDeregisterPnPHandlers.


TdiDeregisterDeviceObject

The TdiDeregisterDeviceObject function is the reciprocal of TdiRegisterDeviceObject. It removes a transport-created device object, previously registered with TDI, as a valid target for clients' network I/O requests.

NTSTATUS
  TdiDeregisterDeviceObject(
    IN HANDLE  DevRegistrationHandle
    );

Parameter

DevRegistrationHandle
Specifies the handle returned by a preceding call to TdiRegisterDeviceObject.

Return Value

TdiDeregisterDeviceObject returns STATUS_SUCCESS if the registration was released and all bound clients were notified. Otherwise, it can return STATUS_INSUFFICIENT_RESOURCES. (Because the availability of system resources is dynamic, a subsequent call from the same transport can succeed.)

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

A transport driver calls TdiDeregisterDeviceObject as a consequence of an NDIS call to the ProtocolUnbindAdapter function at the bottom of the transport stack. Such a call to ProtocolUnbindAdapter indicates that an underlying NIC to which the transport is bound is being removed or disabled. Consequently, the TDI transport driver will destroy a device object that it previously created for its binding to that NIC.

If the transport previously registered this device object with TDI, it must call TdiDeregisterDeviceObject before it deletes its device object from the system. Before it deregisters its device object, the transport also must make one or more calls to TdiDeregisterNetAddress with each network address that it currently has registered with TDI on the binding. That is, the transport calls TdiDeregisterDeviceObject just after it has torn down its binding to the NIC.

TdiDeregisterDeviceObject notifies the calling transport's clients that the transport's device object is no longer a valid target for those clients' I/O requests. When this call occurs, TDI calls the ClientPnPBindingChange routines of those clients that registered themselves with TdiRegisterPnPHandlers to receive these notifications with the input PnPOpcode argument TDI_PNP_OP_DEL.

If TdiDeregisterDeviceObject returns STATUS_INSUFFICIENT_RESOURCES, the transport should fail any subsequent incoming client requests directed to its still registered device object. When convenient, the transport should call TdiDeregisterDeviceObject again because a temporary shortage of available system memory might have caused its original call to fail.

Callers of TdiDeregisterDeviceObject must be running at IRQL < DISPATCH_LEVEL.

See Also

ClientPnPBindingChange, ProtocolUnbindAdapter, TdiDeregisterNetAddress, TdiRegisterDeviceObject, TdiRegisterPnPHandlers


TdiDeregisterNetAddress

The TdiDeregisterNetAddress function is the reciprocal of TdiRegisterNetAddress. It removes a transport-supplied network address from the list of valid network addresses registered with TDI.

NTSTATUS
  TdiDeregisterNetAddress(
    IN HANDLE  AddrRegistrationHandle
    );

Parameter

AddrRegistrationHandle
Specifies the handle returned by a preceding call to TdiRegisterNetAddress.

Return Value

TdiDeregisterNetAddress returns STATUS_SUCCESS if the registration was released and all bound clients were notified. Otherwise, it can return STATUS_INSUFFICIENT_RESOURCES. (Because the availability of system resources is dynamic, a subsequent call from the same transport can succeed.)

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

A TDI transport calls TdiDeregisterNetAddress when a disconnection from a remote node on the network occurs, whether the disconnection was initiated at the remote node or because the transport itself initiated this operation, possibly because it is tearing down a binding to the underlying NIC. In either case, the transport must tear down the state it was maintaining about the network address that it previously registered with TdiRegisterNetAddress.

TdiDeregisterNetAddress notifies the calling transport's clients that they can no longer send data to nor expect to receive data from the formerly registered network address. When this call occurs, TDI calls the ClientPnPDelNetAddress functions of all clients that have registered themselves with TdiRegisterPnPHandlers to receive these notifications. If a client has the given address open when this call to ClientPnPDelNetAddress occurs, it must close that address.

If TdiDeregisterNetAddress returns STATUS_INSUFFICIENT_RESOURCES, the transport should fail any subsequent incoming client sends directed to its still registered network address. When convenient, the transport should call TdiDeregisterNetAddress again because a temporary shortage of available system memory might have caused its original call to fail.

Callers of TdiDeregisterNetAddress must be running at IRQL < DISPATCH_LEVEL.

See Also

ClientPnPDelNetAddress, TdiRegisterNetAddress, TdiRegisterPnPHandlers


TdiDeregisterNotificationHandler

This function is obsolete. See TdiDeregisterPnPHandlers.


TdiDeregisterPnPHandlers

The TdiDeregisterPnPHandlers function is the reciprocal of TdiRegisterPnPHandlers. It disables further PnP and power-state notifications to a set of ClientPnPXxx previously registered on a particular transport-to-NIC binding.

NTSTATUS
  TdiDeregisterPnPHandlers(
    IN HANDLE  BindingHandle
    );

Parameter

BindingHandle
Specifies the handle returned by the client's preceding call to TdiRegisterPnPHandlers.

Return Value

TdiDeregisterPnPHandlers returns STATUS_SUCCESS if the registration was released. Otherwise, it can return either of the following:

STATUS_INSUFFICIENT_RESOURCES
TDI could not allocate the resources it needed to complete this request at this time. Because the availability of system resources is dynamic, a subsequent call from the same client can succeed.
STATUS_NETWORK_BUSY
TDI failed the call to prevent a potential deadlock because a ClientPnPXxx routine is currently running. A subsequent call from the same client can succeed.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

A successful call to TdiDeregisterPnPHandlers stops further PnP/power, bind, unbind, and net-address-change notifications from being sent as calls to the ClientPnPXxx routines that were previously registered with TdiRegisterPnPHandlers on a particular transport-to-NIC binding.

When TdiDeregisterPnPHandlers returns STATUS_SUCCESS, the caller should release any resources that it allocated to maintain state for the given binding. For example, the client should release any memory it allocated to maintain per-binding state and all other per-binding resources that it allocated, such as its internal list for currently registered network addresses on this binding that were maintained by its ClientPnPAddNetAddress and ClientPnPDelNetAddress routines.

Callers of TdiDeregisterPnPHandlers must be running at IRQL < DISPATCH_LEVEL.

See Also

ClientPnPAddNetAddress, ClientPnPBindingChange, ClientPnPDelNetAddress, ClientPnPPowerChange, TdiRegisterPnPHandlers


TdiDeregisterProvider

The TdiDeregisterProvider function is the reciprocal of TdiRegisterProvider. PnP-supporting tranports call TdiDeregisterProvider when they are being unloaded.

NTSTATUS
  TdiDeregisterProvider(
    IN HANDLE  ProviderHandle
    );

Parameter

ProviderHandle
Specifies the handle obtained from TdiRegisterProvider.

Return Value

TdiDeregisterProvider returns STATUS_SUCCESS if the registration was released and all the clients of that transport were notified. Otherwise, it can return STATUS_INSUFFICIENT_RESOURCES, although it is highly unlikely to ever return this status to a transport that is currently unloading itself.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

Before a transport returns control from its Unload routine, it must call TdiDeregisterProvider if it made an initialization-time call to TdiRegisterProvider.

The transport must free all the TDI-associated resources it has allocated before it calls TdiDeregisterProvider. In general, the transport has already called TdiDeregisterAddress with any network addresses and TdiDeregisterDeviceObject with any per-binding device objects that it registered with TDI when it tore down its bindings to the underlying NICs. However, an unloading transport also should destroy the device objects it created with IoDeleteDevice and release any collateral resources it allocated to maintain state about its TDI clients before calling TdiDeregisterProvider. (For more information, see IoDeleteDevice.)

Callers of TdiDeregisterProvider must be running at IRQL < DISPATCH_LEVEL.

See Also

TdiProviderReady, TdiRegisterProvider


TdiEnumerateAddresses

The TdiEnumerateAddresses function provides information to a client about the currently registered network addresses on a particular transport-to-NIC binding.

NTSTATUS
  TdiEnumerateAddresses(
    IN HANDLE  BindingHandle
    );

Parameters

BindingHandle
Specifies the handle returned by a preceding call to TdiRegisterPnPHandlers.

Return Value

TdiEnumerateAddresses returns STATUS_SUCCESS when the caller has been notified of all currently registered network addresses on the given binding. Otherwise, it can return STATUS_INSUFFICIENT_RESOURCES.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

A client's call to TdiEnumerateAddresses initiates a sequence of calls to its own ClientPnPAddNetAddress routine, which the client previously registered with TdiRegisterPnPHandlers. Each such call to the ClientPnPAddNetAddress routine supplies a currently active network address provided and registered with TDI by the underlying transport.

Rather than suffering the runtime performance penalty of this call, most TDI clients never call TdiEnumerateAddresses, except possibly to verify the validity of a client's own internal list of per-binding network addresses if its list might have been corrupted.

Instead, a TDI client sets up its own internal list for binding-specific and transport-registered network addresses when it establishes the binding, and TDI makes a sequence of binding-time calls to the registered ClientPnPAddNetAddress routine so the client can initialize its internal list with the network addresses currently registered on that binding.

After setting up and initializing such an internal list, the client's own ClientPnPAddNetAddress and ClientPnPDelNetAddress routines update this internal list of per-binding valid network addresses dynamically. Before the client releases the binding, it must clean up such an internal list, whether for reuse with a subsequent binding or to release all allocated resources associated with its list.

Callers of TdiEnumerateAddresses must be running at IRQL < DISPATCH_LEVEL.

See Also

ClientPnPAddNetAddress, ClientPnPDelNetAddress, TdiRegisterNetAddress, TdiDeregisterNetAddress, TdiRegisterPnPHandlers


TdiInitialize

The TdiInitialize function is used by TDI transport providers to initialize TDI's data structures.

VOID
  TdiInitialize(
    VOID
    );

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

TDI's data structures are initialized on the first call to TdiInitialize. All subsequent calls to TdiInitialize do nothing. A transport provider might be loaded before TDI loads. If the transport provider calls TdiInitialize immediately, the component is guaranteed that TDI will have been loaded and initialized after TdiInitialize returns.

Calling this function ensures that TDI's global variables are initialized. A TDI transport provider should call this function in its DriverEntry procedure before calling any other TDI function

TdiInitialize must be called at IRQL==PASSIVE_LEVEL.

See Also

DriverEntry


TdiMapBuffer

The TdiMapBuffer function is obsolete. It simply returns control.


TdiMapUserRequest

The TdiMapUserRequest function converts a given IRP in which MajorFunction is set to IRP_MJ_DEVICE_CONTROL into an IRP_MJ_INTERNAL_DEVICE_CONTROL request if it recognizes the IOCTL_TDI_XXX code specified in the input IRP.

NTSTATUS
  TdiMapUserRequest(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp,
    IN PIO_STACK_LOCATION  IrpSp
    );

Parameters

DeviceObject
Pointer to the device object created by the transport driver.
Irp
Pointer to the user IOCTL_XXX request to be converted.
IrpSp
Pointer to the I/O stack location to be converted.

The transport's TdiDispatchDeviceControl routine already called IoGetCurrentIrpStackLocation to obtain this pointer.

Return Value

TdiMapUserRequest returns STATUS_SUCCESS if it converted the given IOCTL_TDI_XXX device-control request into a TDI_XXX internal device-control request. Otherwise, it can return either of the following:

STATUS_INVALID_PARAMETER
If IOCTL_TDI_SET_EVENT_HANDLER is specified in the given I/O stack location of the input IRP
STATUS_NOT_IMPLEMENTED
If TdiMapUserRequest does not recognize the IOCTL_XXX code specified in the given I/O stack location of the input IRP

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

For the majority of system-defined IOCTL_TDI_XXX codes that can be set in IRPs passed to a transport's TdiDispatchDeviceControl routine, TdiMapUserRequest converts the current I/O stack location into the format of the corresponding kernel-mode TDI_XXX request.

For example, if IrpSp->Parameters.DeviceIoControl.IoControlCode is set to IOCTL_TDI_LISTEN in the input IRP, TdiMapUserRequest reformats the I/O stack location as follows:

  • Resets MajorFunction to IRP_MJ_INTERNAL_DEVICE_CONTROL
  • Sets MinorFunction to TDI_LISTEN
  • If the input Irp->AssociatedIrp.SystemBuffer is not NULL, sets IrpSp->Parameters to the address of a TDI_REQUEST_KERNEL_LISTEN structure, which it sets up with the caller-supplied information

TdiDispatchDeviceControl can call TdiDispatchInternalDeviceControl with such a converted IRP, thereby saving the transport from having duplicate code paths for processing system-defined IOCTL_TDI_XXX and the corresponding TDI_XXX requests.

While the kernel-mode TDI_REGISTER_EVENT_HANDLER has a corresponding user IOCTL_TDI_REGISTER_EVENT_HANDLER, TdiMapUserRequest fails any attempt to map such an input IRP. Only kernel-mode clients can register event handlers with a TDI transport, so a transport's TdiDispatchDeviceControl routine cannot be called with a valid request to set up an event handler.

If a transport defines any private IOCTL_XXX codes to be used by a transport-dedicated Win32 application for communication with the transport, its TdiDispatchDeviceControl routine can process such a request whenever TdiMapUserRequest returns STATUS_NOT_SUPPORTED. For more information about defining driver-specific, private IOCTLs, see IRP Function Codes and IOCTLs.

Callers of TdiMapUserRequest run at IRQL PASSIVE_LEVEL.

See Also

TdiDispatchDeviceControl, TdiDispatchInternalDeviceControl


TdiMatchPdoWithChainedReceiveContext

The TdiMatchPdoWithChainedReceiveContext function determines if the given packet descriptor originated from the physical device object (for the NDIS miniport driver).

BOOLEAN
  TdiMatchPdoWithChainedReceiveContext(
    IN PVOID TsduDescriptor,
    IN PVOID PDO
    );

Parameters

TsduDescriptor
Pointer to a descriptor of type NDIS_PACKET.
PDO
Physical device object.

Return Value

TdiMatchPdoWithChainedReceiveContext returns TRUE if the packet passed into this function at TsduDescriptor originated from the physical device object passed into this function at PDO. Otherwise, it returns FALSE.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

TdiMatchPdoWithChainedReceiveContext returns TRUE if the indicated packet originated from the physical device object.

See Also

NDIS_PACKET


TdiPnPPowerComplete

The TdiPnPPowerComplete function indicates the client has completed the processing of a power-state-change notification for which the client originally returned STATUS_PENDING to TDI.

VOID
  TdiPnPPowerComplete(
    IN HANDLE  BindingHandle,
    IN PNET_PNP_EVENT  PowerEvent,
    IN NTSTATUS  Status
    );

Parameters

BindingHandle
Specifies the handle returned by a preceding call to TdiRegisterPnPHandlers.
PowerEvent
Specifies the pointer, passed as an input parameter to the ClientPnPPowerChange routine, to the NET_PNP_EVENT structure.
Status
Specifies the final status of the power-state-change operation for which the client previously returned STATUS_PENDING.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

If the input Status is anything other than STATUS_SUCCESS, TdiPnPPowerComplete notifies the transport that its attempt to change the power state has failed. A TDI client returns an error status, such as STATUS_FILES_OPEN or STATUS_UNSUCCESSFUL, for Status when one of its own (application) clients rejects a proposed power-state change for a valid reason. For example, such a failure from an application to the TDI client might mean that the application had sent a popup to the end user warning that a device removal would compromise ongoing network transfers to which the user responded by canceling the removal of the underlying NIC.

It is a programming error for a caller of TdiPnPPowerComplete to return STATUS_PENDING.

Callers of TdiPnPPowerComplete must be running at IRQL < DISPATCH_LEVEL.

See Also

ClientPnPPowerChange, NET_PNP_EVENT for Protocol Drivers, TdiPnPPowerRequest


TdiPnPPowerRequest

The TdiPnPPowerRequest function forwards a power-state change notification from the transport to all its clients on a particular transport-to-NIC binding.

NTSTATUS
  TdiPnPPowerRequest(
    IN PUNICODE_STRING  DeviceName,
    IN PNET_PNP_EVENT  PowerEvent,
    IN PTDI_PNP_CONTEXT  Context1,
    IN PTDI_PNP_CONTEXT  Context2,
    IN ProviderPnPPowerComplete  ProtocolCompletionHandler
    );

Parameters

DeviceName
Pointer to a caller-supplied buffered Unicode string identifying the transport-created device object that represents this transport-to-NIC binding. The transport previously registered this device object with TDI, using this name, when it called TdiRegisterDeviceObject.
PowerEvent
Pointer to a NET_PNP_EVENT structure, supplied by NDIS when it indicated this power-state event to the ProtocolPnPEvent function of the (monolithic) transport or of the lowest driver in the (multidriver) transport stack. The NetEvent member of this structure is set to one of the following NDIS-defined NET_PNP_EVENT_CODE values:

NetEventSetPower

NetEventQueryPower

NetEventQueryRemoveDevice

NetEventCancelRemoveDevice

Context1
Pointer to a transport-determined context associated with this type of power-state indication. This transport-supplied context information is protocol-specific in nature and intended to give clients a hint about how to interpret and handle the indication.

For example, TCP/IP passes a pointer to a list of addresses associated with the context of this notification.

Context2
Pointer to a transport-determined context associated with this type of power-state indication.

For example, TCP/IP passes a pointer to the PDO representing the physical device on which or for which this notification was generated.

ProtocolCompletionHandler
Specifies the entry point of the transport-supplied completion routine, which TDI calls if any client handles this notification asynchronously and later returns something other than STATUS_SUCCESS for this indication. This TDI-defined handler can be declared as follows:
VOID
    MyPnPPowerCompletionCallback(
        IN PNET_PNP_EVENT  NetEvent,
        IN NTSTATUS  FinalStatus
        );

Return Value

TdiPnPPowerRequest returns STATUS_SUCCESS if all notified clients both handled this notification synchronously and returned STATUS_SUCCESS to indicate their acceptance of the power-state change. Otherwise, it can return one of the following:

STATUS_PENDING
At least one client will handle this notification asynchronously. TDI will call the transport-supplied routine at ProtocolCompletionHandler when all clients have completed their processing of this notification.
STATUS_INSUFFICIENT_RESOURCES
TDI currently cannot allocate sufficient resources to notify all clients of this power-state change. Because the availability of system resources is dynamic, a subsequent call from the same transport can succeed.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

When NDIS notifies a transport of a power-state-change event with a call to the ProtocolPnPEvent function at the lower edge of the transport driver or transport stack, the transport is responsible for notifying its higher level clients of any power-state changes that might affect their current network operations with a call to TdiPnPPowerRequest.

Note that the transport does not make this call with certain PnP-type events, in particular the NDIS-defined types NetEventReconfigure and NetEventBindingList. Instead, NDIS calls TDI with these notifications and TDI, in turn, calls the registered ClientPnPBindingChange functions of all TDI clients. Depending on the status returned by each client, NDIS calls the ProtocolBindAdapter or ProtocolUnbindAdapter functions of those transports affected by such a PnP event notification.

Such a transport might call other Tdi Xxx routines as a consequence of these notifications from NDIS through TDI to registered clients. For example, the transport might call TdiRegisterDeviceObject and TdiRegisterNetAddress as a consequence of a NetEventBindingList-type notification, which originates with a change by the end user in the Connections folder.

A transport calls TdiProviderReady during system setup as a consequence of the NetEventBindsComplete-type notification from NDIS to the ProtocolBindAdapter function at the lower edge of the transport stack.

Callers of TdiPnPPowerRequest must be running at IRQL < DISPATCH_LEVEL.

See Also

ClientPnPPowerChange, NET_PNP_EVENT, ProtocolBindAdapter, ProtocolPnPEvent, ProtocolUnbindAdapter, TdiPnPPowerComplete, TdiProviderReady, TdiRegisterDeviceObject, TdiRegisterNetAddress


TdiProviderReady

The TdiProviderReady function notifies TDI clients that a particular transport has established bindings to one or more underlying NICs and is now available to send and receive data over the network.

NTSTATUS
  TdiProviderReady(
    IN HANDLE  ProviderHandle
    );

Parameter

ProviderHandle
Specifies the handle that the transport obtained from TdiRegisterProvider.

Return Value

TdiProviderReady returns STATUS_SUCCESS when it has notified all currently bound clients of the transport's readiness to transfer data over the network. Otherwise, it can return STATUS_INSUFFICIENT_RESOURCES. (Because the availability of system resources is dynamic, a subsequent call from the same transport can succeed.)

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

A TDI transport calls TdiProviderReady after all of the following operations are complete:

  • The ProtocolBindAdapter function of the lowest driver in the transport stack (or of the monolithic transport) has successfully established a binding to one or more underlying NDIS miniport drivers, so these miniport drivers' NICs are initialized and capable of transferring data over the network.
  • NDIS has called the ProtocolPnPEvent function at the bottom of the transport stack with an input NET_PNP_EVENT of type NetEventBindsComplete.
  • Any intermediate drivers in the transport stack have allocated and initialized whatever state they need to track network transfers on these newly established transport-to-NIC bindings.
  • The TDI transport driver also has allocated and initialized whatever state it needs to track its clients' network transfers on these newly established transport-to-NIC bindings. For example, the transport has called TdiRegisterDeviceObject one or more times with the name of the device object that it created to represent the target of its clients' network I/O operations on each such binding. The transport also might have called TdiRegisterNetAddress one or more times on its just established bindings.

The transport's call to TdiProviderReady accomplishes one or both of the following:

  • TDI calls the registered ClientPnPBindingChange routines of this transport's clients with the input PnPOpcode value TDI_PNP_OP_PROVIDERREADY, thereby notifying its clients that the underlying transport stack is ready to send and/or receive data over the network through this newly established transport-to-NIC binding.
  • TDI calls the registered ClientPnPBindingChange routines of every transports' clients if this is the last possible transport-to-NIC binding to be established and the last possible transport-ready indication given to TDI, according to the network configuration information stored in the registry on this machine. In effect, TDI notifies all registered clients when system initialization-time binding operations are done by calling each registered ClientPnPBindingChange routine with a NULL DeviceName pointer and the PnPOpcode value TDI_PNP_OP_NETREADY.

For more information about how to create device objects with IoCreateDevice.

Callers of TdiProviderReader must be running at IRQL < DISPATCH_LEVEL.

See Also

ClientPnPBindingChange, ProtocolBindAdapter, TdiRegisterDeviceObject, TdiRegisterNetAddress, TdiRegisterProvider


TdiRegisterAddressChangeHandler

This function is obsolete. Use TdiRegisterPnPHandlers.


TdiRegisterDeviceObject

The TdiRegisterDeviceObject function notifies a transport's clients that the transport has created a new device object to represent the target of its clients' network I/O requests on a particular transport-to-NIC binding.

NTSTATUS
  TdiRegisterDeviceObject(
    IN PUNICODE_STRING  DeviceName,
    OUT HANDLE  *DevRegistrationHandle
    );

Parameters

DeviceName
Pointer to a caller-allocated buffer that contains a Unicode string identifying the transport-created device object.
DevRegistrationHandle
Specifies the caller-supplied location of a variable in which TdiRegisterDeviceObject returns an opaque handle if this call succeeds.

Return Value

TdiRegisterDeviceObject returns STATUS_SUCCESS when it has notified all the transport's clients of the registration. Otherwise, it can return STATUS_INSUFFICIENT_RESOURCES. (Because the availability of system resources is dynamic, a subsequent call from the same transport can succeed.)

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

After the transport stack is bound to an underlying NDIS miniport driver, a TDI transport must create a named device object with IoCreateDevice to represent the target for its own clients' network I/O requests on the newly established transport-to-NIC binding. Then, the transport must call TdiRegisterDeviceObject. This causes TDI to call all registered ClientPnPBindingChange routines of the transport's clients with the given DeviceName pointer and with the input PnPOpcode value TDI_PNP_OPCODE_ADD.

A successful caller of TdiRegisterDeviceObject should save the returned value at *DevRegistrationHandle for a subsequent and reciprocal call to TdiDeregisterDeviceObject when the transport tears down the binding. The transport also should save the buffered string at DeviceObject for subsquent calls to TdiRegisterNetAddress and TdiPnPPowerRequest.

For the specifics of calls to IoCreateDevice.

Callers of TdiRegisterDeviceObject must be running at IRQL < DISPATCH_LEVEL.

See Also

ClientPnPBindingChange, TdiDeregisterDeviceObject, TdiPnPPowerRequest, TdiRegisterNetAddress


TdiRegisterNetAddress

The TdiRegisterNetAddress function notifies a transport's clients that it has just established a connection to a remote node with a particular network address or that the transport has just created a new network address for the computer on which it is running.

NTSTATUS
  TdiRegisterNetAddress(
    IN PTA_ADDRESS  Address,
    IN PUNICODE_STRING  DeviceName,
    IN PTDI_PNP_CONTEXT  Context,
    OUT HANDLE  *AddrRegistrationHandle
    );

Parameters

Address
Pointer to a caller-allocated buffer, formatted as a TA_ADDRESS structure, that contains the protocol-type-specific TDI_ADDRESS_XXX address specification.
DeviceName
Pointer to a caller-supplied buffered Unicode string identifying the transport-created device object that represents this transport-to-NIC binding. The transport previously registered this device object with TDI when it called TdiRegisterDeviceObject. In effect, this string identifies the transport-to-NIC binding on which this network address is being registered.
Context
Pointer to a transport-determined context associated with this address.

For example, TCP/IP returns a pointer to the PDO of the physical device on which this address arrived.

AddrRegistrationHandle
Specifies the caller-supplied location of a variable in which TdiRegisterNetAddress returns an opaque handle if this call succeeds.

Return Value

TdiRegisterNetAddress returns STATUS_SUCCESS when it has notified all the transport's clients of the registration. Otherwise, it can return STATUS_INSUFFICIENT_RESOURCES. (Because the availability of system resources is dynamic, a subsequent call from the same transport can succeed.)

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

Before it calls TdiRegisterNetAddress, the transport allocates a buffer, which can be pageable, to contain the specification of the new network address. The transport should zero-initialize this buffer first and then set up the members of the TA_ADDRESS structure. When it makes this call, a transport must provide only the new network address in the remainder of the buffer starting at Address. That is, if any additional members are defined for collateral information in the transport's protocol-type-specific TDI_ADDRESS_XXX substructure, those members should be zero when the transport calls TdiRegisterNetAddress.

TdiRegisterNetAddress makes copies of the transport-supplied device name and context data, but it makes no attempt to interpret this caller-supplied information. At the discretion of the tranport developer, the input Context pointer can be NULL, or it can be used to pass any additional protocol-specific information about each newly registered network address from the transport to its clients. When it notifies each client, TdiRegisterNetAddress calls each registered ClientPnPAddNetAddress function with pointers to its copied device name and context information.

Each ClientPnPAddNetAddress function can use whatever context information the underlying transport supplied at Context and, possibly, the device name, to determine whether the new address is of interest to that client. The input Context pointer remains valid until the transport calls TdiDeregisterNetAddress, thereby causing a call to the ClientPnpDelNetAddress routine. The input DeviceName pointer remains valid until the transport calls TdiDeregisterDeviceObject, thereby causing a call to the ClientPnPBindingChange routine with the PnPOpcode TDI_PNP_OP_DEL. However, every client must treat this TDI state as read-only information.

A successful caller of TdiRegisterNetAddress should save the returned value at *AddrRegistrationHandle for a subsequent and reciprocal call to TdiDeregisterNetAddress.

Callers of TdiRegisterNetAddress must be running at IRQL < DISPATCH_LEVEL.

See Also

ClientPnPAddNetAddress, TA_ADDRESS, TdiDeregisterDeviceObject, TdiDeregisterNetAddress, TDI_PNP_CONTEXT


TdiRegisterNotificationHandler

This function is obsolete. Use TdiRegisterPnPHandlers.


TdiRegisterPnPHandlers

The TdiRegisterPnPHandlers function registers a set of client-supplied ClientPnPXxx routines to receive subsequent notifications of dynamic PnP events, such as the discovery of a new NIC in the machine or the removal of an existing NIC from the machine, system power-state changes, and/or the arrival and departure of network addresses registered and deregistered by the underlying transports.

NTSTATUS
  TdiRegisterPnPHandlers(
    IN PTDI_CLIENT_INTERFACE_INFO  ClientInterfaceInfo,
    IN ULONG  InterfaceInfoSize,
    OUT HANDLE  *BindingHandle
    );

Parameters

ClientInterfaceInfo
Pointer to a caller-allocated and zero-initialized buffer, formatted as follows, or to this structure on the stack:
typedef struct _TDI20_CLIENT_INTERFACE_INFO {
    union {
        struct {
            UCHAR MajorTdiVersion; // currently 2
            UCHAR MinorTdiVersion; // currently 0
        };
        // do not use following (obsolete transports)
        USHORT TdiVersion;
    };
    USHORT Unused;
    PUNICODE_STRING ClientName;
    TDI_PNP_POWER_HANDLER  PnPPowerHandler;
    union {
        TDI_BINDING_HANDLER BindingHandler;
        // do not use following (obsolete transports)
        struct {
            TDI_BIND_HANDLER BindHandler;
            TDI_UNBIND_HANDLER UnBindHandler;
        };
    };
    union {
        struct {
            TDI_ADD_ADDRESS_HANDLER_V2 AddAddressHandlerV2;
            TDI_DEL_ADDRESS_HANDLER_V2 DelAddressHandlerV2;
        };
        // do not use following (obsolete transports)
        struct {
            TDI_ADD_ADDRESS_HANDLER AddAddressHandler;
            TDI_DEL_ADDRESS_HANDLER DelAddressHandler;
        };
    };
} TDI20_CLIENT_INTERFACE_INFO, *PTDI20_CLIENT_INTERFACE_INFO;

typedef TDI20_CLIENT_INTERFACE_INFO TDI_CLIENT_INTERFACE_INFO;
InterfaceInfoSize
Specifies the size in bytes of the buffer at ClientInterfaceInfo.
BindingHandle
Specifies the address of a caller-supplied variable in which TdiRegisterPnPHandlers returns a TDI-supplied opaque handle if the call succeeds. The caller should save this handle for a subsequent call TdiDeregisterPnPHandlers or, possibly but very rarely, to TdiEnumerateAddresses.

Return Value

TdiRegisterPnPHandlers returns STATUS_SUCCESS if the supplied ClientPnPXxx routines will be notified of subsequent PnP and power-state-change events. Otherwise, it can return one of the following:

TDI_STATUS_BAD_VERSION
If the caller set the version members in the structure at ClientInterfaceInfo to something greater than TDI_CURRENT_VERSION. The caller should not propagate this return value to higher level network components.
TDI_STATUS_BAD_CHARACTERISTICS
The given InterfaceInfoSize value is less than sizeof(TDI_CLIENT_INTERFACE_INFO). The caller should not propagate this return value to higher level network components.
STATUS_INSUFFICIENT_RESOURCES
TDI could not allocate the buffers it needed to maintain state for this client's notifications or, perhaps, other resources necessary to process this registration request. (Possibly, a subsequent call to TdiRegisterPnPHandlers will not fail for this reason if resources currently in use are released.)

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

The caller must supply the following information at ClientInterfaceInfo to receive subsequent notifications of PnP/power-state changes, binding changes, and network address changes:

  • MajorTdiVersion set to 2 or TDI_CURRENT_MAJOR_VERSION.
  • MinorTdiVersion set to 0 or TDI_CURRENT_MINOR_VERSION.
  • ClientName set to the address of a buffered Unicode string specifying the client's named key in the registry HKLM\System\CCS\Services tree.
  • PnPPowerHandler set to the entry point of the caller's ClientPnPPowerChange routine.
  • BindingHandler set to the entry point of the caller's ClientPnPBindingChange routine.
  • AddAddressHandlerV2 set to the entry point of the caller's ClientPnPAddNetAddress routine.
  • DelAddressHandlerV2 set to the entry point of the caller's ClientPnPDelNetAddress routine.

On return from a successful call to TdiRegisterPnPHandlers, the ClientPnPBindingChange and ClientPnPAddNetAddress routines have been called one or more times with all the system-setup-time information currently available to TDI about transports and their already registered network addresses. That is, TDI has made the following initialization-time calls to the client's just registered PnP routines:

  • ClientPnPBindingChange has been called one or more times with the PnPOpcode TDI_PNP_OP_ADD and the buffered name of a device object created to represent an established transport-to-NIC binding by any transport already registered with TDI. ClientPnPBindingChange also could have been called one or more times with the PnPOpcode TDI_PNP_OP_PROVIDERREADY and the buffered name of any TDI transport driver that has declared itself ready to carry out network I/O operations on its respective transport-to-NIC bindings.

    At each call to ClientPnPBindingChange with the PnPOpcode TDI_PNP_OP_ADD, this routine determines whether to bind itself to the underlying transport-to-NIC binding with a call to ZwCreateFile.

  • ClientPnPAddNetAddress has been called one or more times with each network address that these transports have already registered on their established bindings with calls to TdiRegisterNetworkAddress.

    At each such call to ClientPnPAddNetAddress, this routine examines the AddressType member of the structure at the input Address to determine whether it recognizes this network protocol and returns control promptly if it does not. Otherwise, ClientPnPAddNetAddress examines the buffered string at DeviceName to determine whether the client has already bound itself to this transport. If so, ClientPnpAddNetAddress uses the input protocol-specific address information to add entries to the client-allocated internal list of valid and registered network addresses. The client might use such a registered network address for subsequent network I/O requests after opening it, again with a call to ZwCreateFile.

Note that ClientPnPBindingChange can be called with the PnPOpcode TDI_PNP_OP_ADD and TDI_PNP_OP_PROVIDERREADY subsequently during system startup if another transport-to-NIC binding is established and the transport makes successful calls to TdiRegisterDeviceObject, possibly also to TdiRegisterNetworkAddress (thereby causing one or more calls to ClientPnPAddNetAddress), and to TdiProviderReady.

In addition, when TDI determines that all possible transport-to-NIC bindings configured for the computer have been established and that every transport has indicated its readiness to transfer network data, TDI calls every registered ClientPnPBindingChange routine once more with the PnPOpcode TDI_PNP_OP_NETREADY and a NULL DeviceName pointer. This last initialization-time call to ClientPnPBindingChange indicates that the system initialization phase of setting up network communications is now done.

Following system startup, TDI makes dyanamic calls to these registered ClientPnPXxx routines as the transports to which the client is bound make runtime calls to TdiRegisterDeviceObject, TdiDeregisterDeviceObject, TdiRegisterNetAddress, TdiDeregisterNetAddress, and TdiPnPPowerRequest until the client makes a reciprocal call to TdiDeregisterPnPHandlers with the returned handle at *BindingHandle.

Callers of TdiRegisterPnPHandlers must be running at IRQL < DISPATCH_LEVEL.

See Also

ClientPnPAddNetAddress, ClientPnPBindingChange, ClientPnPDelNetAddress, ClientPnPPowerChange, TdiDeregisterDeviceObject, TdiDeregisterNetAddress, TdiDeregisterPnPHandlers, TdiEnumerateAddresses, TdiRegisterDeviceObject, TdiRegisterNetAddress, TdiPnPPowerRequest


TdiRegisterProvider

The TdiRegisterProvider function notifies TDI that a PnP-supporting transport driver is initializing and that the transport will make a subsequent call to TdiProviderReady when it has established its bindings to one or more underlying NDIS miniport drivers and is ready to carry out network I/O operations.

NTSTATUS
  TdiRegisterProvider(
    IN PUNICODE_STRING  ProviderName,
    OUT HANDLE  *ProviderHandle
    );

Parameters

ProviderName
Pointer to a buffered Unicode string that is a generic name for the transport, such as \device\tcp_{GUID_for_tcp}, \device\nwlinkipx, and so forth.
ProviderHandle
Specifies the caller-supplied location of a variable in which TdiRegisterProvider returns an opaque handle if this call succeeds.

Return Value

TdiRegisterProvider returns STATUS_SUCCESS when TDI has set up whatever interenal state it maintains to track this transport and notified its potential clients of this transport's existence. Otherwise, it can return STATUS_INSUFFICIENT_RESOURCES, although it is highly unlikely to ever return this status to a transport that is initializing itself during system startup.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

TDI transport drivers call TdiRegisterProvider from their DriverEntry routines.

The handle returned by a successful call to TdiRegisterProvider must be saved for a subsequent call to TdiProviderReady and for a reciprocal call to TdiDeregisterProvider from the transport driver's Unload routine.

Callers of TdiRegisterProvider can run at IRQL < DISPATCH_LEVEL.

See Also

TdiDeregisterProvider, TdiProviderReady


TdiReturnChainedReceives

The TdiReturnChainedReceives function returns an array of TSDU descriptors for one or more chained receive indications previously forwarded to a transport's client, which returned STATUS_PENDING for each such chained receive indication.

VOID
  TdiReturnChainedReceives(
    IN PVOID  *TsduDescriptors,
    IN ULONG  NumberOfTsdus
    );

Parameters

TsduDescriptors
Pointer to an array of descriptors of type NDIS_PACKET.
NumberOfTsdus
Specifies the number of elements in the array at TsduDescriptors.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

For faster network throughput, a TDI transport can pass to its clients direct (but read-only) access to a chain of NDIS miniport driver-allocated buffers containing a full received network packet, subject to the following conditions:

  • The NDIS protocol driver at the bottom of the transport stack (or the monolithic transport) registered a ProtocolReceivePacket function with NdisRegisterProtocol, so it can receive indications that permit direct, read-only access to the contents of the underlying NDIS miniport driver's receive buffers. If the transport is bound directly to the driver of a physical NIC, its ProtocolReceivePacket function is given read-only access to the NIC's receive buffers.
  • The underlying NIC driver calls NdisMIndicateReceivePacket to make receive indications, thereby allowing any bound protocol that supplies a ProtocolReceivePacket function to retain read-only access to the received data in the NIC driver's receive buffers until it is consumed, possibly by one or more clients of the TDI driver at the top of the transport stack. Such a receive indication is always a full network packet, mapped by the buffer descriptors (MDLs) chained to each indicated NDIS_PACKET-type TSDU descriptor.
  • The client has registered its handler for TDI_EVENT_CHAINED_RECEIVE or TDI_EVENT_RECEIVE_DATAGRAM events with the transport.

When such a transport's ProtocolReceivePacket function is called, it can forward the receive indication up the transport stack to the TDI driver. The TDI driver indicates the receive to the appropriate ClientEventReceive(Datagram) function, thereby giving the client the opportunity to process the indicated TSDU without the overhead of double buffering such a received packet in the transport. If the ClientEventReceive(Datagram) callback returns STATUS_PENDING, the client retains exclusive read-only access to the indicated packet until that client calls TdiReturnChainedReceives with the TSDU descriptors.

A TDI client's call to TdiReturnChainedReceives returns the indicated packet descriptors and all the associated resources directly to NDIS, bypassing the indicating TDI driver and any lower drivers in its transport stack. This allows NDIS to return the packet descriptors and associated resources more quickly to the underlying NDIS miniport driver (or NDIS intermediate driver, if any) that originally allocated the packet descriptors and chained buffer descriptors, possibly after NDIS indicates this chained receive to any other transports that also bound themselves to the same NDIS miniport driver.

Packets indicated by the underlying NDIS driver to the transport's ProtocolReceive function should be buffered internally in the transport, but they must be indicated to such a client's ClientEventReceive, ClientEventReceiveExpedited, or ClientEventReceiveDatagram function. Calls to these client event handlers direct the client to make a copy of the indicated data as quickly as possible, and ClientEventReceive(Expedited/Datagram) relinquishes the client's access to the buffers containing the indicated data when the event handler returns control.

Only kernel-mode clients with registered ClientEventChainedReceive, ClientEventChainedReceiveExpedited, and/or ClientEventChainedReceiveDatagram handlers call TdiReturnChainedReceives.

Callers of TdiReturnChainedReceives run at IRQL <= DISPATCH_LEVEL.

See Also

ClientEventChainedReceive, ClientEventChainedReceiveDatagram, ClientEventChainedReceiveExpedited, ClientEventReceive, ClientEventReceiveDatagram, ClientEventReceiveExpedited, NdisMIndicateReceivePacket, NDIS_PACKET, NdisReturnPackets, ProtocolReceive, ProtocolReceivePacket


TdiUnmapBuffer

The TdiUnmapBuffer function is obsolete. It simply returns control to the caller.


TdiBuildXxx Macros and Functions

This section describes the system-supplied TdiBuild Xxx macros, used by kernel-mode clients to set up the TDI_XXX internal device control IRPs they subsequently submit to underlying TDI transport drivers with IoCallDriver.

Parameters to these macros always include pointers or handles to file objects representing addresses, connection endpoints, or control channels already opened with calls to ZwCreateFile. A successful call to ZwCreateFile returns a handle to an open file object, from which the client can obtain a pointer to that file object by calling ObReferenceObjectByHandle.

This section also describes some TdiBuild Xxx functions that only kernel-mode clients might call:

  • TdiBuildInternalDeviceControlIrp to allocate an IRP to be passed to a TdiBuild Xxx macro and, then, to IoCallDriver when a kernel-mode client makes a request to its underlying transport on its own behalf
  • TdiBuildNetbiosAddressEa to set up a buffered EA describing an address with which the client of a NetBIOS transport can subsequently call ZwCreateFile to open that NetBIOS address
  • TdiBuildNetbiosAddress to set up a NetBIOS address for the client of a NetBIOS transport

For more information about how transport drivers handle the TDI_XXX requests set up by the build-IRP macros, see TDI IOCTLs for Transport Drivers. For more information about the kernel-mode support routines referenced in this section (such as IoCallDriver, ZwCreateFile, and ObReferenceObjectByHandle), see Summary of Kernel-Mode Support Routines .

For more information about ClientPnPXxx handlers and how to register them for Plug-and-Play and power-state-change notifications, see TDI Client Event and PnP Notification Handlers and TDI Functions sections,respectively.


TdiBuildAccept

TdiBuildAccept sets up an internal device control IRP for a TDI_ACCEPT request to the underlying transport in which a local-node client has already opened a connection endpoint and associated it with a local-node address and to which the client has already issued a TDI_LISTEN request.

VOID
  TdiBuildAccept(
    IN PIRP  Irp,
    IN PDEVICE_OBJECT  DevObj,
    IN PFILE_OBJECT  FileObj,
    IN PVOID  CompRoutine,
    IN PVOID  Contxt,
    IN PTDI_CONNECTION_INFORMATION  RequestConnectionInfo,
    OUT PTDI_CONNECTION_INFORMATION  ReturnConnectionInfo
    );

Parameters

Irp
Pointer to a client-supplied IRP, either originating in a higher level network component or allocated with TdiBuildInternalDeviceControlIrp.
DevObj
Pointer to the device object created by the next lower TDI transport driver.
FileObj
Pointer to a file object representing a connection endpoint. The client previously made a successful request, set up with TdiBuildAssociateAddress, to the transport to set up an association between this connection and a local-node address. When the association was established, the client also issued a listen request, set up with TdiBuildListen, to the transport.
CompRoutine
Specifies the entry point of a client-supplied IoCompletion routine or NULL. The I/O Manager calls this routine when the given IRP is completed, unless the client sets this parameter to NULL.
Contxt
Pointer to a client-determined context. This client-supplied pointer is passed in to the IoCompletion routine when it is called with the completed IRP. Contxt is NULL if CompRoutine is NULL.
RequestConnectionInfo
Pointer to a caller-supplied buffer containing a TDI_CONNECTION_INFORMATION structure, set up to specify a valid remote-node client address from which the caller, a local-node client, can accept a connection. The local-node client also can provide buffered accept data, specified at UserData in this structure, that the underlying transport should send to the remote node when it transmits acceptance of the offered connection (see TdiBuildListen for details).
ReturnConnectionInfo
Pointer to a caller-supplied buffer in which the transport returns the remote-node client's address with which it has established an endpoint-to-endpoint connection for the local-node client. This buffer is also formatted as a TDI_CONNECTION_INFORMATION structure. If the underlying transport does not provide this information, this parameter should be NULL.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

TdiBuildAccept sets IRP_MJ_INTERNAL_DEVICE_CONTROL as the MajorFunction and TDI_ACCEPT as the MinorFunction codes in the transport's I/O stack location of the given IRP.

When a kernel-mode client issues a TDI_ACCEPT request, it asks the underlying transport to accept an incoming request to connect from a remote-node client and, thereby, to enable network data reception on an established endpoint-to-endpoint connection.

Usually, a client sends an accept request in response to a return from its preceding listen request, set up with TdiBuildListen with the TDI_QUERY_ACCEPT option selected. If a client did not set this value in the Flags for its listen request, its accept request fails because the underlying transport has already established an endpoint-to-endpoint connection when the listen request completes.

Most TDI transports have a time-out feature that prevents attempts to establish endpoint-to-endpoint connections from hanging when a remote node does not respond. Therefore, a client must either accept or reject a connection as soon as possible after completion of its listen request. The interval between client notification of a remote-node peer connection offer and that local client's connection acceptance or rejection is subject to a transport-determined time-out limit, usually something less than one second.

A client indicates its acceptances of a connection to the remote-node peer by submitting a request set up by TdiBuildAccept to the underlying transport. It indicates its rejection of a connection offer by submitting an IRP set up with TdiBuildDisconnect.

The local client's registered ClientEvent(Chained)Receive(Expedited) handler(s) can be called before the I/O Manager formally completes its processing of the accept IRP. That is, the remote-node peer can start sending data to the local client as soon as the remote node receives an acceptance of the offered connection.

See Also

ClientEventChainedReceive, ClientEventChainedReceiveExpedited, ClientEventConnect, ClientEventReceive, ClientEventReceiveExpedited, TDI_ACCEPT, TdiBuildDisconnect, TdiBuildInternalDeviceControlIrp, TdiBuildListen, TDI_CONNECTION_INFORMATION


TdiBuildAction

TdiBuildAction sets up an internal device control IRP for a TDI_ACTION request to the underlying transport in which a local-node client has already opened an address, connection endpoint, or control channel to which the requested action applies.

VOID
  TdiBuildAction(
    IN PIRP  Irp,
    IN PDEVICE_OBJECT  DevObj,
    IN PFILE_OBJECT  FileObj,
    IN PVOID  CompRoutine,
    IN PVOID  Contxt,
    IN PMDL  MdlAddr
    );

Parameters

Irp
Pointer to a client-supplied IRP, either originating in a higher level network component or allocated with TdiBuildInternalDeviceControlIrp.
DevObj
Pointer to the device object created by the underlying TDI transport driver.
FileObj
Pointer to a file object representing an address, connection endpoint, or control channel.
CompRoutine
Specifies the entry point of a client-supplied IoCompletion routine or NULL. The I/O Manager calls this routine when the given IRP is completed, unless the client sets this parameter to NULL.
Contxt
Pointer to a client-determined context. This client-supplied pointer is passed in to the IoCompletion routine when it is called with the completed IRP. Contxt is NULL if CompRoutine is NULL.
MdlAddr
Pointer to an MDL, possibly the head of an MDL chain, mapping a client-supplied buffer containing the action parameter block set up by the client. This buffer contains a system-defined header, followed by whatever transport-determined information is necessary to carry out the action request.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

TdiBuildAction sets IRP_MJ_INTERNAL_DEVICE_CONTROL as the MajorFunction and TDI_ACTION as the MinorFunction codes in the transport's I/O stack location of the given IRP.

A client can make an action request for transport-provided extensions pertaining to an address, a connection, or a control channel. The client supplies a buffer containing all transport-required information concerning such a request in an action parameter block.

Every action parameter block begins with a system-defined TDI_ACTION_HEADER structure containing a transport identifier and an action code. On receipt of such a request, the transport uses the value of TransportId in this header to validate the request. The ActionCode member specifies the transport-defined operation to carry out and determines the transport-required contents for the remainder of the parameter block. The underlying transport defines the set of possible action codes and the required formats of the remaining parameter block for each such action.

The successful completion of any client's action request makes the transport-provided extension applicable to that client but not to any other TDI clients or drivers.

See Also

TDI_ACTION, TDI_ACTION_HEADER, TdiBuildInternalDeviceControlIrp


TdiBuildAssociateAddress

TdiBuildAssociateAddress sets up an internal device control IRP for a TDI_ASSOCIATE_ADDRESS request to the underlying transport in which a local-node client has already opened an address and a connection endpoint.

VOID
  TdiBuildAssociateAddress(
    IN PIRP  Irp,
    IN PDEVICE_OBJECT  DevObj,
    IN PFILE_OBJECT  FileObj,
    IN PVOID  CompRoutine,
    IN PVOID  Contxt,
    IN HANDLE  AddrHandle
    );

Parameters

Irp
Pointer to a client-supplied IRP, either originating in a higher level network component or allocated with TdiBuildInternalDeviceControlIrp.
DevObj
Pointer to the device object created by the underlying TDI transport driver.
FileObj
Pointer to a file object representing the connection endpoint.
CompRoutine
Specifies the entry point of a client-supplied IoCompletion routine or NULL. The I/O Manager calls this routine when the given IRP is completed, unless the client sets this parameter to NULL.
Contxt
Pointer to a client-determined context. This client-supplied pointer is passed in to the IoCompletion routine when it is called with the completed IRP. Contxt is NULL if CompRoutine is NULL.
AddrHandle
Specifies a handle to a file object representing a local-node address.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

TdiBuildAssociateAddress sets IRP_MJ_INTERNAL_DEVICE_CONTROL as the MajorFunction and TDI_ASSOCIATE_ADDRESS as the MinorFunction codes in the transport's I/O stack location of the given IRP.

A kernel-mode client must open both a connection endpoint and an address with successful calls to ZwCreateFile before it calls TdiBuildAssociateAddress. The client must make the associate-address request before it makes a connection to the remote node either with a request set up with TdiBuildListen, optionally followed by one set up with TdiBuildAccept, to the transport driver or with a request set up with TdiBuildConnect to the transport driver.

However, a client can get and/or set information about the open connection or address with one or more requests set up with TdiBuildQueryInformation and/or TdiBuildSetInformation before making the associate-address request.

After the client associates the connection endpoint with the address, it can make any other TDI_XXX requests to the transport on the just-associated connection with one exception: it cannot make a TDI_ASSOCIATE_ADDRESS request again for the specific endpoint until it makes a successful TDI_DISASSOCIATE_ADDRESS request to the transport.

See Also

TDI_ASSOCIATE_ADDRESS, TdiBuildAccept, TdiBuildConnect, TdiBuildDisassociateAddress, TdiBuildInternalDeviceControlIrp, TdiBuildListen, TdiBuildQueryInformation, TdiBuildSetInformation


TdiBuildConnect

TdiBuildConnect sets up an internal device control IRP for a TDI_CONNECT request to the underlying transport in which a local-node client has already associated an address and a connection endpoint.

VOID
  TdiBuildConnect(
    IN PIRP  Irp,
    IN PDEVICE_OBJECT  DevObj,
    IN PFILE_OBJECT  FileObj,
    IN PVOID  CompRoutine,
    IN PVOID  Contxt,
    IN PLARGE_INTEGER  Time,
    IN PTDI_CONNECTION_INFORMATION  RequestConnectionInfo,
    OUT PTDI_CONNECTION_INFORMATION  ReturnConnectionInfo
    );

Parameters

Irp
Pointer to a client-supplied IRP, either originating in a higher level network component or allocated with TdiBuildInternalDeviceControlIrp.
DevObj
Pointer to the device object created by the underlying TDI transport driver.
FileObj
Pointer to a file object representing the connection endpoint.
CompRoutine
Specifies the entry point of a client-supplied IoCompletion routine or NULL. The I/O Manager calls this routine when the given IRP is completed, unless the client sets this parameter to NULL.
Contxt
Pointer to a client-determined context. This client-supplied pointer is passed in to the IoCompletion routine when it is called with the completed IRP. Contxt is NULL if CompRoutine is NULL.
Time
Pointer to a variable specifying a system-relative time-out interval that the transport is to use for the connection attempt, or this parameter can be NULL.

An explicit time-out must be specified as the negative of the number of 100-nanosecond intervals, relative to the current system time, that its connection attempt is allowed to remain pending before the transport fails this connect request. If this pointer is NULL, the transport uses its own default time-out interval for establishing a connection with any remote node.

RequestConnectionInfo
Pointer to a caller-supplied buffer containing a TDI_CONNECTION_INFORMATION structure that specifies the remote-node client address to which the local-node client is requesting an endpoint-to-endpoint connection.
ReturnConnectionInfo
Pointer to a caller-supplied buffer in which the transport returns the remote-node client address with which it has established a connection. This buffer is also formatted as TDI_CONNECTION_INFORMATION structure. If a local-node client requires no output information or if the underlying transport does not return such information, this parameter should be NULL.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

TdiBuildConnect sets IRP_MJ_INTERNAL_DEVICE_CONTROL as the MajorFunction and TDI_CONNECT as the MinorFunction codes in the transport's I/O stack location of the given IRP.

If the specified endpoint is inactive or nonexistent, the transport fails the connect request. If the specified endpoint has not been associated with a local-node address, the transport also fails the connect request.

For a local-node client to establish an endpoint-to-endpoint connection with a remote-node peer process, it must first associate an idle local connection endpoint with a local-node address. A client cannot initiate a connection attempt to a remote-node peer until it has made a successful TDI_ASSOCIATE_ADDRESS request, which it set up with TdiBuildAsociateAddress, to its underlying transport.

For a local-node client's connect request to succeed, the remote-node client must have an open listen request or a registered ClientEventConnect routine that can receive notification from its underlying transport of connection offers.

See Also

ClientEventConnect, TdiBuildAssociateAddress, TdiBuildInternalDeviceControlIrp, TdiBuildListen, TdiBuildSetEventHandler, TDI_CONNECT, TDI_CONNECTION_INFORMATION


TdiBuildDisassociateAddress

TdiBuildDisassociateAddress sets up an internal device control IRP for a TDI_DISASSOCIATE_ADDRESS request to the underlying transport in which a local-node client has already associated an address and a connection endpoint.

VOID
  TdiBuildDisassociateAddress(
    IN PIRP  Irp,
    IN PDEVICE_OBJECT  DevObj,
    IN PFILE_OBJECT  FileObj,
    IN PVOID  CompRoutine,
    IN PVOID  Contxt
    );

Parameters

Irp
Pointer to a client-supplied IRP, either originating in a higher level network component or allocated with TdiBuildInternalDeviceControlIrp.
DevObj
Pointer to the device object created by the underlying TDI transport driver.
FileObj
Pointer to a file object representing the connection endpoint. The client previously made a successful request, set up with TdiBuildAssociateAddress, to the transport to set up an association between this connection and a local-node address.
CompRoutine
Specifies the entry point of a client-supplied IoCompletion routine or NULL. The I/O Manager calls this routine when the given IRP is completed, unless the client sets this parameter to NULL.
Contxt
Pointer to a client-determined context. This client-supplied pointer is passed in to the IoCompletion routine when it is called with the completed IRP. Contxt is NULL if CompRoutine is NULL.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

TdiBuildDisassociateAddress sets IRP_MJ_INTERNAL_DEVICE_CONTROL as the MajorFunction and TDI_DISASSOCIATE_ADDRESS as the MinorFunction codes in the transport's I/O stack location of the given IRP.

A kernel-mode client makes this request to disassociate a connection endpoint for an inactive connection from the associated address object, whether that client initiated the disconnection from its remote-node peer or vice versa.

If this request is successful, the client can reassociate the connection endpoint with another local-node address or the local-node address with another connection endpoint by setting up another IRP for the underlying transport with TdiBuildAssociateAddress.

See Also

TdiBuildAssociateAddress, TdiBuildDisconnect, TdiBuildInternalDeviceControlIrp, TDI_DISASSOCIATE_ADDRESS


TdiBuildDisconnect

TdiBuildDisconnect sets up an internal device control IRP for a TDI_DISCONNECT request to the underlying transport through which a local-node client has already established an endpoint-to-endpoint connection with a remote-node peer or to which that client previously made a listen request in anticipation of establishing such a connection.

VOID
  TdiBuildDisconnect(
    IN PIRP  Irp,
    IN PDEVICE_OBJECT  DevObj,
    IN PFILE_OBJECT  FileObj,
    IN PVOID  CompRoutine,
    IN PVOID  Contxt,
    IN PLARGE_INTEGER  Time,
    IN ULONG  Flags,
    IN PTDI_CONNECTION_INFORMATION  RequestConnectionInfo,
    OUT PTDI_CONNECTION_INFORMATION  ReturnConnectionInfo
    );

Parameters

Irp
Pointer to a client-supplied IRP, either originating in a higher level network component or allocated with TdiBuildInternalDeviceControlIrp.
DevObj
Pointer to the device object created by the underlying TDI transport driver.
FileObj
Pointer to a file object representing the connection endpoint.

The client previously made a successful request, set up with TdiBuildAssociateAddress, to the transport to set up an association between this connection endpoint and a local-node address. In addition, the client previously did one of the following:

  • Made a successful request, set up with TdiBuildConnect, to establish an endpoint-to-endpoint connection with a remote-node peer
  • Accepted this connection offer from its remote-node peer, which initiated the TDI_CONNECT request
  • Submitted a successful request, set up with TdiBuildListen, that has just been satisfied by a connection offer from a remote-node peer
CompRoutine
Specifies the entry point of a client-supplied IoCompletion routine or NULL. The I/O Manager calls this routine when the given IRP is completed, unless the client sets this parameter to NULL.
Contxt
Pointer to a client-determined context. This client-supplied pointer is passed in to the IoCompletion routine when it is called with the completed IRP. Contxt is NULL if CompRoutine is NULL.
Time
Pointer to a variable specifying a system-relative time-out interval that the transport is to use for the disconnection attempt, or this parameter can be NULL.

An explicit time-out must be specified as the negative of the number of 100-nanosecond intervals, relative to the current system time, that its disconnection attempt is allowed to remain pending before the transport fails this disconnect request. If this pointer is NULL, the transport uses its own default time-out interval for disconnecting from any remote node.

Flags
Specifies zero if the underlying transport does not support controlled disconnects. If the underlying transport does support controlled disconnects, specifies either of the following:
TDI_DISCONNECT_ABORT
Specifies that the underlying transport should close the connection immediately without attempting to complete any pending requests. This value is the default, equivalent to setting Flags to zero.

A client can make a disconnect request with TDI_DISCONNECT_ABORT at any time its connection is not idle. For example, such a client might want to cancel a pending connect or listen request that it made previously. As another example, a client can force the underlying transport to close an endpoint-to-endpoint connection by issuing a second disconnect request with TDI_DISCONNECT_ABORT when its preceding disconnect request with TDI_DISCONNECT_RELEASE remains pending.

TDI_DISCONNECT_RELEASE
Specifies that the underlying transport should initiate a controlled disconnect, as described later (see Comments). The remote-node client also issues a disconnect request with this value to confirm a controlled disconnect.

The TDI_DISCONNECT_WAIT flag is not used.

Clients can set only one of the preceding options in a disconnect request. The transport will fail any attempt to set more than one of these options.

RequestConnectionInfo
Pointer to a client-supplied buffer containing a TDI_CONNECTION_INFORMATION structure, possibly containing disconnection data if the client sends any when initiating an endpoint-to-endpoint controlled disconnection. This parameter should be NULL unless the caller initiated a disconnection with TDI_DISCONNECT_RELEASE.
ReturnConnectionInfo
Pointer to a caller-supplied buffer, also formatted as TDI_CONNECTION_INFORMATION structure, in which the transport returns any disconnect data it received from the remote node, assuming the remote-node client initiated a controlled disconnection. This parameter should be NULL unless the caller is acknowledging a disconnection with TDI_DISCONNECT_RELEASE. The local-node client cannot retrieve any returned disconnect data after it reuses the connection in a request set up with TdiBuildListen or TdiBuildConnect.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

TdiBuildDisconnect sets IRP_MJ_INTERNAL_DEVICE_CONTROL as the MajorFunction and TDI_DISCONNECT as the MinorFunction codes in the transport's I/O stack location of the given IRP. This IRP requests that an already established endpoint-to-endpoint connection with a remote-node peer be broken.

A client also can issue a disconnect request to reject an incoming request to connect that was initiated by a remote-node peer. In this case, the client is responding to a completed TDI_LISTEN request that it made previously with the TDI_QUERY_ACCEPT option selected, or the client is rejecting an offered connection from its ClientEventConnect function. Such a client calls TdiBuildDisconnect either with zero or with TDI_DISCONNECT_ABORT at Flags.

While an established endpoint-to-endpoint connection is being disconnected, the underlying transport driver usually refuses any incoming requests for the connection and stops all activity at the specified connection endpoint. However, that connection endpoint remains valid for reuse by the client when the disconnect operation is done.

Because any disconnection operation takes time to complete, the client can receive additional TSDUs on an established endpoint-to-endpoint connection before its disconnect IRP is fully completed. Therefore, a client can assume that the context it maintains for such a connection remains valid until it is notified of disconnect completion, for example, by a call to the IoCompletion routine it supplied to TdiBuildDisconnect. Disconnect-completion notification implies the cessation of all activity, including receive indications, on the connection.

Unless a client requests a controlled disconnect with TDI_DISCONNECT_RELEASE, the transport completes no outstanding I/O requests on the connection and does not confirm that the remote-node peer has been notified of the disconnection before it returns control from a disconnect request. For such a disconnect request, the underlying transport simply cancels all outstanding requests on the given connection, completes its client's disconnect request, and returns control.

Either client on an established endpoint-to-endpoint connection can request a controlled disconnect if the underlying TDI transports support this. If so, the client that initiates the disconnection operation with a TDI_DISCONNECT request causes both transports to coordinate their operations so the remote-node peer is informed that the connection is closing and both transports complete any pending transfers on the connection before it is broken. In these circumstances, the remote-node client must confirm the disconnect before the underlying transport can return from the initiating (local-node) client's disconnect request.

The following summarizes the sequence of operations for a controlled disconnect:

  1. The local-node client initiates a disconnection by making a disconnect request in which TDI_DISCONNECT_RELEASE was set at Flags. Subsequently, this client can no longer send data on the connection, but it can continue to receive data from its remote-node peer. The underlying transport carries out any pending send operations and completes the pending send requests it is currently holding when such a local-node client makes its disconnect request.
  2. The transport on the remote node completes any pending receive requests its client has made. Then, the remote-node transport notifies its client of the pending disconnect, either by calling ClientEventDisconnect if the remote-node client has registered this event handler or by returning an error code on an outstanding request made by its client. After such a notification, the remote-node client can no longer receive data on the connection, but it can continue to send data until it submits a disconnect request with the TDI_DISCONNECT_RELEASE option to the underlying transport.
  3. When the remote-node client has finished sending data, it makes a disconnect request to its underlying transport with the TDI_DISCONNECT_RELEASE option selected. The underlying transport completes all outstanding sends on the connection normally before completing its client's disconnect request. When this transport returns from the disconnect, the connection has been closed from the point of view of its remote-node client. However, the connection endpoint is still valid and that client can reuse it later.
  4. The remote-node transport notifies the local-node transport to confirm disconnect-completion at the remote node. At this point, the original controlled disconnect request is completed by the local-node transport and the connection has been closed from the point of view of the local-node client. However, the connection endpoint is still valid and that client can reuse it later.

See Also

ClientEventDisconnect, TdiBuildConnect, TdiBuildListen, TdiBuildInternalDeviceControlIrp, TDI_CONNECTION_INFORMATION, TDI_DISCONNECT


TdiBuildInternalDeviceControlIrp

TdiBuildInternalDeviceControlIrp allocates an IRP for a client-initiated internal device control request. After it returns, the client calls another TdiBuild Xxx macro with the returned IRP to set up the I/O stack location of the underlying transport driver before making the request with IoCallDriver.

PIRP
  TdiBuildInternalDeviceControlIrp(
    IN CCHAR  IrpSubFunction,
    IN PDEVICE_OBJECT  DeviceObject,
    IN PFILE_OBJECT  FileObject,
    IN PKEVENT  Event,
    IN PIO_STATUS_BLOCK  IoStatusBlock
    );

Parameters

IrpSubFunction
Specifies the TDI_XXX code that will be set in a subsequent call to a TdiBuild Xxx macro as the MinorFunction for the returned IRP. This parameter can be one of the following:
TDI_ASSOCIATE_ADDRESS
The caller will pass the returned IRP to TdiBuildAssociateAddress.
TDI_DISASSOCIATE_ADDRESS
The caller will pass the returned IRP to TdiBuildDisassociateAddress.
TDI_CONNECT
The caller will pass the returned IRP to TdiBuildConnect.
TDI_LISTEN
The caller will pass the returned IRP to TdiBuildListen.
TDI_ACCEPT
The caller will pass the returned IRP to TdiBuildAccept.
TDI_DISCONNECT
The caller will pass the returned IRP to TdiBuildDisconnect.
TDI_SEND
The caller will pass the returned IRP to TdiBuildSend.
TDI_RECEIVE
The caller will pass the returned IRP to TdiBuildReceive.
TDI_SEND_DATAGRAM
The caller will pass the returned IRP to TdiBuildSendDatagram.
TDI_RECEIVE_DATAGRAM
The caller will pass the returned IRP to TdiBuildReceiveDatagram.
TDI_SET_EVENT_HANDLER
The caller will pass the returned IRP to TdiBuildSetEventHandler.
TDI_QUERY_INFORMATION
The caller will pass the returned IRP to TdiBuildQueryInformation.
TDI_SET_INFORMATION
The caller will pass the returned IRP to TdiBuildSetInformation.
TDI_ACTION
The caller will pass the returned IRP to TdiBuildAction.
DeviceObject
Pointer to the device object created by the underlying TDI transport driver.
FileObject
Pointer to a file object representing an address, connection endpoint, or control channel, depending on the given IrpSubFunction.
Event
Pointer to an initialized event object for which the caller provides the storage.
IoStatusBlock
Pointer to a caller-supplied variable of type IO_STATUS_BLOCK.

Return Value

TdiBuildInternalDeviceControlIrp returns a pointer to the IRP it allocated, or it returns NULL if the allocation attempt failed.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

Kernel-mode clients of TDI transports frequently pass IRPs sent down by still higher level network components directly to TdiBuild Xxx macros without calling TdiBuildInternalDeviceControlIrp.

However, such a client should never hijack an incoming IRP and reuse it to make an internal device control request to the underlying transport on its own behalf. Instead the client can call TdiBuildInternalDeviceControlIrp to get an IRP of its own with which to make such requests.

After TdiBuildInternalDeviceControlIrp returns a pointer to an IRP, the client must pass the IRP to the appropriate TdiBuild Xxx macro, along with the additional parameters the TDI_XXX requires, before it passes the IRP on to the transport with IoCallDriver. TdiBuildInternalDeviceControlIrp partially sets up the I/O stack location of the underlying transport in the IRP it allocates. However, it does not format the I/O stack location according to a TDI transport's expectations for a TDI_XXX request as the TdiBuild Xxx macros do.

See IoCallDriver for more information.

If the client supplies an Event pointer when it calls TdiBuildInternalDeviceControlIrp, the I/O Manager will set the event to the Signaled state when the IRP is completed by lower drivers. However, the client cannot wait on that event for completion of its IRP unless it waits at IRQL PASSIVE_LEVEL in an appropriate thread context, either that of a client-created thread or, possibly, that of the thread in which it was executing when it made this call.

Callers of TdiBuildInternalDeviceControlIrp must be running at IRQL PASSIVE_LEVEL. Consequently, a client should preallocate a few IRPs with this function so the client can use them to submit TDI_XXX requests when it is running at a higher IRQL.


TdiBuildListen

TdiBuildListen sets up an internal device control IRP for a TDI_LISTEN request to the underlying transport in which the local-node client has already associated an address and a connection endpoint.

VOID
  TdiBuildListen(
    IN PIRP  Irp,
    IN PDEVICE_OBJECT  DevObj,
    IN PFILE_OBJECT  FileObj,
    IN PVOID  CompRoutine,
    IN PVOID  Contxt,
    IN ULONG  Flags,
    IN PTDI_CONNECTION_INFORMATION  RequestConnectionInfo,
    OUT PTDI_CONNECTION_INFORMATION  ReturnConnectionInfo
    );

Parameters

Irp
Pointer to a client-supplied IRP, either originating in a higher level network component or allocated with TdiBuildInternalDeviceControlIrp.
DevObj
Pointer to the device object created by the underlying TDI transport driver.
FileObj
Pointer to a file object representing the connection endpoint. The client previously made a successful request, set up with TdiBuildAssociateAddress, to the transport to set up an association between this connection and a local-node address.
CompRoutine
Specifies the entry point of a client-supplied IoCompletion routine or NULL. The I/O Manager calls this routine when the given IRP is completed, unless the client sets this parameter to NULL.
Contxt
Pointer to a client-determined context. This client-supplied pointer is passed in to the client's IoCompletion routine when it is called with the completed IRP. Contxt is NULL if CompRoutine is NULL.
Flags
Specifies zero or, possibly, TDI_QUERY_ACCEPT if the underlying transport supports delayed-connection acceptances.

If Flags is zero, the underlying transport accepts the connection from the remote node as soon as it is offered. The client can assume the endpoint-to-endpoint connection is fully operational when its listen request completes. In fact, receives on the connection endpoint can occur even before this listen IRP is fully completed back to the client.

If the transport supports delayed-connection acceptances and its client sets TDI_QUERY_ACCEPT, that client must either accept or reject the offered connection as quickly as possible when the listen request completes. That is, on completion of this IRP, the client must set up another request to the transport with either TdiBuildAccept or TdiBuildDisconnect, respectively.

RequestConnectionInfo
Pointer to a client-supplied buffer containing a TDI_CONNECTION_INFORMATION structure that specifies the remote-node client address from which the local-node client expects an endpoint-to-endpoint connection offer.

Depending on the value of Flags, the client also provides additional information in the following members of this structure:

UserData
Pointer to a buffer of data the client wants sent with its acceptance of the connection offer from the remote node if Flags is zero.

A client sets this member to NULL if the underlying transport supports delayed-connection acceptances and the client sets Flags to TDI_QUERY_ACCEPT. Such a client can provide accept data when it subsequently accepts an offered connection, assuming it does.

UserDataLength
Specifies the size in bytes of the buffer at UserData. This member is zero if UserData is NULL.
Options
Set to the same value as Flags.
OptionsLength
Set to sizeof(ULONG).
RemoteAddress
Pointer to a buffer specifying the remote-node address from which the local-node client expects a connection offer that the local-node client will accept. This member can be NULL if an offered connection from any remote node is acceptable to the client.

For some transports, a local-node client can specify a partial address. However, TDI drivers vary in their ability to handle partial addresses. Because the syntax of any such address is protocol-specific, the underlying TDI transport defines the conventions for specifying a partial address if it supports partial-address specifications.

RemoteAddressLength
Specifies the size in bytes of the buffer at RemoteAddress. This member should be set to zero if RemoteAddress is NULL.
ReturnConnectionInfo
Pointer to a caller-supplied buffer in which the transport returns the remote-node address from which a connection offer was made. This buffer is also formatted as TDI_CONNECTION_INFORMATION structure.

If the local-node client set Flags to TDI_QUERY_ACCEPT, it examines the returned information to determine whether to accept or reject the connection when this listen request completes.

If the client requires no output information or if the underlying transport does not return such information, this parameter should be NULL.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

TdiBuildListen sets IRP_MJ_INTERNAL_DEVICE_CONTROL as the MajorFunction and TDI_LISTEN as the MinorFunction codes in the transport's I/O stack location of the given IRP.

Before it calls the underlying transport with the IRP set up by TdiBuildListen, a client must make a preceding associate-address request, set up with TdiBuildAssociateAddress, that succeeded in associating an idle connection endpoint with a local-node address. After this association is established, a client can issue numerous listen requests until it accepts an offered endpoint-to-endpoint connection.

The underlying transport usually processes each client's listen requests in FIFO order unless it supports quality-of-service (QOS) for its clients and, therefore, prioritizes incoming listen requests. However, a client cannot make assumptions about the order in which the underlying transport processes requests from all its current clients.

Client-supplied addressing information at RequestConnectionInfo acts as a filter that the underlying transport driver applies, before checking whether the client set TDI_QUERY_ACCEPT if the transport supports delayed-connection acceptances. If an incoming connection offer does not match an address specified in the client's listen request, the transport cannot complete the listen request for the client. Otherwise, when an incoming connection offer is made from a specified remote-node address, the local-node client's listen request is completed in one of the following ways:

  • If the client set Flags to TDI_QUERY_ACCEPT indicating delayed-connection acceptance, the transport completes the listen request, and the client must either accept or reject the offered endpoint-to-endpoint connection by issuing a TDI_ACCEPT or TDI_DISCONNECT request to the transport immediately.
  • If the client set Flags to zero, possibly because the underlying transport does not support delayed-connection acceptances, the transport transmits an acceptance, along with any accept data the client supplied, to the remote node and completes the listen request.

Before making a listen request, a client can set up one or more IRPs with TdiBuildSetEventHandler and register its ClientEvent(Chained)Receive(Expedited) handler(s) for the local address associated with the connection endpoint. If it does this, the ClientEvent(Chained)Receive(Expedited) routine(s) can receive TSDUs before the client's listen request completes. Such a client must be prepared to accept an immediate connection when it makes a listen request.

While a listen for a client's connection endpoint is pending on a particular local-node address, that client's ClientEventConnect function cannot be called except under special circumstances. That is, the underlying transport can call ClientEventConnect if a listen operation is pending and the transport determines that the remote address acceptance criteria would prevent the listen operation from being completed.

As mentioned previously, some transports support the specification of remote-node partial addresses on listens. A transport also might support the specification of QOS options. For example, such a TDI transport's clients might specify the QOS for a listen using a variable-length counted string with transport-defined syntax and semantics.

See Also

ClientEventChainedReceive, ClientEventChainedReceiveExpedited, ClientEventConnect, ClientEventReceive, ClientEventReceiveExpedited, TdiBuildAccept, TdiBuildDisconnect, TdiBuildInternalDeviceControlIrp, TdiBuildSetEventHandler, TDI_LISTEN, TDI_CONNECTION_INFORMATION


TdiBuildNetbiosAddress

TdiBuildNetbiosAddress sets up a TA_NETBIOS_ADDRESS structure for the caller.

VOID
  TdiBuildNetbiosAddress(
    IN PUCHAR  NetbiosName,
    IN BOOLEAN  IsGroupName,
    IN OUT PTA_NETBIOS_ADDRESS  NetworkName
    );

Parameters

NetbiosName
Pointer to 16-byte buffer containing a NetBIOS name.
IsGroupName
Specifies TRUE if the given name is a group address.
NetworkName
Pointer to a caller-supplied buffer, which must be at least sizeof(TA_NETBIOS_ADDRESS) bytes in length.

TdiBuildNetbiosAddress fills in the members of this structure.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

See Also

TA_NETBIOS_ADDRESS, TdiBuildNetbiosAddressEa


TdiBuildNetbiosAddressEa

TdiBuildNetbiosAddressEa sets up a buffered NetBIOS address that the caller can pass subsequently to ZwCreateFile as the EaBuffer parameter.

NTSTATUS
  TdiBuildNetbiosAddressEa(
    IN PUCHAR  Buffer,
    IN BOOLEAN  IsGroupName,
    IN PUCHAR  NetbiosName
    );

Parameters

Buffer
Pointer to a caller-supplied buffer, which must be at least 40 bytes in length.
IsGroupName
Specifies TRUE if the address to be set up is a group address.
NetbiosName
Pointer to 16-byte buffer containing a NetBIOS name.

Return Value

TdiBuildNetbiosAddressEa returns STATUS_SUCCESS if it set up the given EA buffer. Otherwise, it can return STATUS_UNSUCCESSFUL if the given buffer is too small or, possibly, a propagated error status if attempting to access the given parameters raised an exception.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

TdiBuildNetbiosAddressEa sets up the buffer in a manner suitable for calling ZwCreateFile to open a NetBIOS address, with a TA_NETBIOS_ADDRESS structure as the EA value.

For more information, see ZwCreateFile.

See Also

TA_NETBIOS_ADDRESS, TdiBuildNetbiosAddress


TdiBuildQueryInformation

TdiBuildQueryInformation sets up an internal device control IRP for a TDI_QUERY_INFORMATION request to the underlying transport in which the local-node client has already opened a file object representing an address, a connection endpoint, or a control channel.

VOID
  TdiBuildQueryInformation(
    IN PIRP  Irp,
    IN PDEVICE_OBJECT  DevObj,
    IN PFILE_OBJECT  FileObj,
    IN PVOID  CompRoutine,
    IN PVOID  Contxt,
    IN UINT  QType,
    IN PMDL  MdlAddr
    );

Parameters

Irp
Pointer to a client-supplied IRP, either originating in a higher level network component or allocated with TdiBuildInternalDeviceControlIrp.
DevObj
Pointer to the device object created by the underlying TDI transport driver.
FileObj
Pointer to a file object representing an address, connection endpoint, or control channel.
CompRoutine
Specifies the entry point of a client-supplied IoCompletion routine or NULL. The I/O Manager calls this routine when the given IRP is completed, unless the client sets this parameter to NULL.
Contxt
Pointer to a client-determined context. This client-supplied pointer is passed in to the IoCompletion routine when it is called with the completed IRP. Contxt is NULL if CompRoutine is NULL.
QType
Specifies what the client is querying. This parameter can be transport-defined or one of the following system-defined values, for which all transports support queries:
TDI_QUERY_ADDRESS_INFO
Specifies that the transport should return the information, formatted as a TDI_ADDRESS_INFO structure, in the client-supplied buffer mapped at MdlAddr.

FileObj must point to an open file object representing a transport address or a connection endpoint already associated with a transport address.

TDI_QUERY_CONNECTION_INFO
Specifies that the transport should return the information, formatted as a TDI_CONNECTION_INFO structure, in the client-supplied buffer mapped at MdlAddr.

FileObj must point to an open file object representing a connection endpoint.

TDI_QUERY_BROADCAST_ADDRESS
Specifies that the transport should return the information, formatted as a TRANSPORT_ADDRESS structure, in the client-supplied buffer mapped at MdlAddr.

FileObject must point to an open file object representing a control channel.

TDI_QUERY_NETWORK_ADDRESS
Specifies that the transport should return the information, formatted as a TRANSPORT_ADDRESS structure, in the client-supplied buffer mapped at MdlAddr.

FileObj must point to an open file object representing a control channel.

TDI_QUERY_DATA_LINK_ADDRESS
Specifies that the transport should return the information, formatted as a TRANSPORT_ADDRESS structure, in the client-supplied buffer mapped at MdlAddr.

FileObj must point to an open file object representing a control channel.

TDI_QUERY_PROVIDER_INFO or TDI_QUERY_PROVIDER_INFORMATION
Specifies that the transport should return the information, formatted as a TDI_PROVIDER_INFO structure, in the client-supplied buffer mapped at MdlAddr.

FileObj must point to an open file object representing a control channel.

TDI_QUERY_PROVIDER_STATISTICS
Specifies that the transport should return the information, formatted as a TDI_PROVIDER_STATISTICS structure, in the client-supplied buffer mapped at MdlAddr.

FileObj must point to an open file object representing a control channel.

TDI_QUERY_DATAGRAM_INFO
Specifies that the transport should return the information, formatted as a TDI_DATAGRAM_INFO structure, in the client-supplied buffer mapped at MdlAddr.

FileObj usually points to an open file object representing a control channel. If the underlying transport supports it, FileObj can point to an open file object representing an address.

TDI_QUERY_MAX_DATAGRAM_INFO
Specifies that the transport should return the information, formatted as a TDI_MAX_DATAGRAM_INFO structure, in the client-supplied buffer mapped at MdlAddr.

FileObj usually points to an open file object representing a control channel. If the underlying transport supports it, FileObj can point to an open file object representing an address.

The underlying transport can support additional types of query-information requests at the discretion of the driver writer. Such a transport must define TDI_QUERY_XXX codes in which the most significant bit is set.

In addition to the preceding, clients of a NetBIOS transport can specify the following for QType:

TDI_QUERY_SESSION_STATUS
Specifies that the transport should return the information, formatted as SESSION_HEADER followed by SESSION_BUFFER structures, in the client-supplied buffer mapped at MdlAddr.

FileObj must point to an open file object representing a control channel.

TDI_QUERY_ADAPTER_STATUS
Specifies that the transport should return the information, formatted as an ADAPTER_STATUS structure, in the client-supplied buffer mapped at MdlAddr.

FileObj must point to an open file object representing a control channel.

For more information about the preceding structures, see the Platform SDK.

MdlAddr
Pointer to an MDL mapping a client-supplied buffer containing any necessary request-specific information set up by the client. The transport returns the requested information in this buffer, formatted according to the given QType.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

TdiBuildQueryInformation sets IRP_MJ_INTERNAL_DEVICE_CONTROL as the MajorFunction and TDI_QUERY_INFORMATION as the MinorFunction codes in the transport's I/O stack location of the given IRP.

A TDI client can use the query request to ask its underlying transport for information, such as connection-status information, a broadcast address it can use, or the features of the transport such as its size limits for sends, datagrams, and user-connect data.

The client can query information about an address, a connection endpoint, or a control channel, depending on the specified QType. The client must supply a FileObj pointer to TdiBuildQueryInformation to an open file object that is appropriate to the given QType. Otherwise, the underlying transport cannot satisfy its query request.

Because TdiBuildQueryInformation sets the RequestConnectionInformation member of the TDI_REQUEST_KERNEL_QUERY_INFORMATION structure to NULL, a client of a NetBIOS transport cannot use TdiBuildQueryInformation with query type TDI_QUERY_FIND_NAME. To set up an IRP for a TDI_QUERY_INFORMATION request using TDI_QUERY_FIND_NAME, a client of a NetBIOS transport can use code similar to the code for TdiBuildQueryInformation but must specify a pointer to a TDI_CONNECTION_INFORMATION structure for RequestConnectionInformation.

See Also

TDI_ADDRESS_INFO, TdiBuildInternalDeviceControlIrp, TDI_CONNECTION_INFO, TDI_DATAGRAM_INFO, TDI_MAX_DATAGRAM_INFO, TDI_PROVIDER_INFO, TDI_PROVIDER_STATISTICS, TDI_QUERY_INFORMATION, TRANSPORT_ADDRESS


TdiBuildReceive

TdiBuildReceive sets up an internal device control IRP for a TDI_RECEIVE request to the underlying transport in which the local-node client has established an endpoint-to-endpoint connection with a remote-node peer.

VOID
  TdiBuildReceive(
    IN PIRP  Irp,
    IN PDEVICE_OBJECT  DevObj,
    IN PFILE_OBJECT  FileObj,
    IN PVOID  CompRoutine,
    IN PVOID  Contxt,
    IN PMDL  MdlAddr,
    IN ULONG  InFlags,
    IN ULONG  ReceiveLen
    );

Parameters

Irp
Pointer to a client-supplied IRP, either originating in a higher level network component or allocated with TdiBuildInternalDeviceControlIrp.
DevObj
Pointer to the device object created by the underlying TDI transport driver.
FileObj
Pointer to a file object representing a connection endpoint.

The caller previously made a successful request, set up with TdiBuildAssociateAddress, to the transport to set up an association between this connection endpoint and a local-node address. When the association was established, the caller also established an endpoint-to-endpoint connection with a remote-node peer, by issuing a successful request set up with TdiBuildConnect or TdiBuildListen, the latter possibly followed by a successful request set up with TdiBuildAccept.

CompRoutine
Specifies the entry point of a client-supplied IoCompletion routine or NULL. The I/O Manager calls this routine when the given IRP is completed, unless the client sets this parameter to NULL.
Contxt
Pointer to a client-determined context. This client-supplied pointer is passed in to the IoCompletion routine when it is called with the completed IRP. Contxt is NULL if CompRoutine is NULL.
MdlAddr
Pointer to an MDL, possibly the initial MDL in a chain of MDLs, mapping a client-supplied buffer into which the transport is to transfer the received TSDU according to the given InFlags.
InFlags
Specifies the type of receive to be returned by the transport as one or more (Ored) of the following:
TDI_RECEIVE_NORMAL
Return a normal TSDU to the client-supplied buffer.
TDI_RECEIVE_EXPEDITED
Return an expedited TSDU to the client-supplied buffer.

If both TDI_RECEIVE_NORMAL and TDI_RECEIVE_EXPEDITED are set or if neither is set, the underlying transport will indicate either type of TSDU for this receive request.

TDI_RECEIVE_PEEK
Return indicated data as soon as a receive arrives from the remote node, even if it is a partial TSDU, and the client will request another receive for the remainder of the TSDU to be transferred into this buffer if the packet is of interest to this client.

This flag is valid only if the underlying transport buffers received data internally. In general, clients that go through the system AFD driver, which buffers data internally for nonbuffering transports, can use this flag.

ReceiveLen
Specifies the size in bytes of the client-supplied receive buffer.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

TdiBuildReceive sets IRP_MJ_INTERNAL_DEVICE_CONTROL as the MajorFunction and TDI_RECEIVE as the MinorFunction codes in the transport's I/O stack location of the given IRP.

If the client has registered any of its ClientEvent(Chained)Receive(Expedited) handler(s) for the given connection endpoint, issuing a receive request suppresses calls to ClientEvent(Chained)Receive(Expedited) until the receive IRP is satisfied. Then, the transport resumes indicating receives to the appropriate ClientEvent(Chained)Receive(Expedited) handler(s).

Unless the TDI_RECEIVE_PEEK flag is set, the underlying transport fills the given buffer with received data until the client's buffer is full or the transport receives an end-of-record indication from the remote node. If this flag is set, the client must issue subsequent receive request(s) when this IRP is satisfied to obtain the full TSDU.

If the underlying transport is receiving normal data and expedited data arrives from the remote node, the transport pre-empts its normal receive operation and returns immediately to the client with any normal data it has already transferred into the client-supplied buffer. When this occurs, the client must make as many receive requests as necessary to receive the expedited TSDU. When the client has retrieved all the arriving expedited data, it issues another receive request to resume receiving normal data.

While a client also can receive normal TSDUs on an endpoint-to-endpoint connection by calling ZwReadFile, the client cannot receive expedited data in this manner because the transport has no way to indicate receive flags. In addition, a call to ZwReadFile does not tell the client whether the underlying transport has received an end-of-record indication.

For more information, see ZwReadFile.

See Also

ClientEventChainedReceive, ClientEventChainedReceiveExpedited, ClientEventReceive, ClientEventReceiveExpedited, TdiBuildAccept, TdiBuildConnect, TdiBuildInternalDeviceControlIrp, TdiBuildListen, TdiBuildReceiveDatagram, TdiBuildSend, TdiBuildSetEventHandler, TDI_RECEIVE


TdiBuildReceiveDatagram

TdiBuildReceiveDatagram sets up an internal device control IRP for a TDI_RECEIVE_DATAGRAM request to the underlying transport in which the local-node client has already opened a file object representing an address.

VOID
  TdiBuildReceiveDatagram(
    IN PIRP  Irp,
    IN PDEVICE_OBJECT  DevObj,
    IN PFILE_OBJECT  FileObj,
    IN PVOID  CompRoutine,
    IN PVOID  Contxt,
    IN PMDL  MdlAddr,
    IN ULONG  ReceiveLen,
    IN PTDI_CONNECTION_INFORMATION  ReceiveDatagramInfo,
    OUT PTDI_CONNECTION_INFORMATION  ReturnInfo,
    ULONG  InFlags
    );

Parameters

Irp
Pointer to a client-supplied IRP, either originating in a higher level network component or allocated with TdiBuildInternalDeviceControlIrp.
DevObj
Pointer to the device object created by the underlying TDI transport driver.
FileObj
Pointer to a file object representing an address.
CompRoutine
Specifies the entry point of a client-supplied IoCompletion routine or NULL. The I/O Manager calls this routine when the given IRP is completed, unless the client sets this parameter to NULL.
Contxt
Pointer to a client-determined context. This client-supplied pointer is passed in to the IoCompletion routine when it is called with the completed IRP. Contxt is NULL if CompRoutine is NULL.
MdlAddr
Pointer to an MDL, possibly the initial MDL in a chain of MDLs, mapping a client-supplied buffer into which the transport is to transfer the received datagram.
ReceiveLen
Specifies the maximum size in bytes of the datagram to return in the buffer mapped at MdlAddr. If this parameter is zero, the transport can use the whole buffer mapped at MdlAddr.
ReceiveDatagramInfo
Pointer to a TDI_CONNECTION_INFORMATION structure specifying a particular remote-node address from which this local-node client will accept a datagram. If the RemoteAddressLength member is zero, a datagram from any remote node is acceptable to this client. A RemoteAddressLength of zero implies a RemoteAddress set to NULL.
ReturnInfo
Pointer to caller-supplied buffer in which the transport is to return the source address of the received datagram, formatted as a TDI_CONNECTION_INFORMATION structure.
InFlags
Specifies the type of receive to be returned by the transport as one or more (Ored) of the following:
TDI_RECEIVE_NORMAL
Return a normal TSDU to the client-supplied buffer.
TDI_RECEIVE_PEEK
Return an indicated datagram as soon as it arrives from a remote node, even if it is a partial TSDU, and the client will request another receive for the remainder of the datagram if it is of interest to this client.

This flag is valied only if the underlying transport buffers received datagrams internally. In general, clients that go through the system AFD driver, which buffers data internally for nonbuffering transports, can use this flag.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

TdiBuildReceiveDatagram sets IRP_MJ_INTERNAL_DEVICE_CONTROL as the MajorFunction and TDI_RECEIVE_DATAGRAM as the MinorFunction codes in the transport's I/O stack location of the given IRP.

Because a datagram is not associated with an established connection, the TDI driver returns the transport address of the remote-node sender to the receiving client along with the datagram.

The transport satisfies this IRP when it receives a datagram directed to the local-node address represented by the client's open file object and a source address matching the client's specification at ReceiveDatagramInfo. If such a received datagram is too large for the client-supplied buffer, the underlying transport truncates the datagram, discarding any superfluous data, and completes the client's receive-datagram request.

TDI transports never fragment datagrams. Consequently, their clients make one receive-datagram request to receive each datagram. To determine the maximum possible value for ReceiveLen, the client usually issued a preceding query-information request, set up with TdiBuildQueryInformation for any of the QType values TDI_QUERY_PROVIDER_INFO, TDI_QUERY_DATAGRAM_INFO, or TDI_QUERY_MAX_DATAGRAM_INFO.

A client can receive a broadcast datagram by opening a broadcast address that has a transport-specific format, which can be obtained with a query-information request. However, such a client cannot send a datagram from the broadcast address, nor can it establish an association between a connection of its own and that broadcast address.

A client also can receive datagrams by registering its ClientEventReceiveDatagram and/or ClientEventChainedReceiveDatagram handler(s) on a particular address.

See Also

ClientEventChainedReceiveDatagram, ClientEventReceiveDatagram, TdiBuildInternalDeviceControlIrp, TdiBuildQueryInformation, TdiBuildSendDatagram, TdiBuildSetEventHandler, TDI_CONNECTION_INFORMATION, TDI_RECEIVE_DATAGRAM


TdiBuildSend

TdiBuildSend sets up an internal device control IRP for a TDI_SEND request to the underlying transport in which the local-node client has already opened a file object representing a connection endpoint and established an endpoint-to-endpoint connection with a remote-node peer.

VOID
  TdiBuildSend(
    IN PIRP  Irp,
    IN PDEVICE_OBJECT  DevObj,
    IN PFILE_OBJECT  FileObj,
    IN PVOID  CompRoutine,
    IN PVOID  Contxt,
    IN PMDL  MdlAddr,
    IN ULONG  InFlags,
    IN ULONG  SendLen
    );

Parameters

Irp
Pointer to a client-supplied IRP, either originating in a higher level network component or allocated with TdiBuildInternalDeviceControlIrp.
DevObj
Pointer to the device object created by the underlying TDI transport driver.
FileObj
Pointer to a file object representing a connection endpoint.

The caller previously made a successful request, set up with TdiBuildAssociateAddress, to the transport to set up an association between this connection endpoint and a local-node address. When the association was established, the caller also established an endpoint-to-endpoint connection with a remote-node peer by issuing a successful request set up with TdiBuildConnect or TdiBuildListen, the latter possibly followed by a successful request set up with TdiBuildAccept.

CompRoutine
Specifies the entry point of a client-supplied IoCompletion routine or NULL. The I/O Manager calls this routine when the given IRP is completed, unless the client sets this parameter to NULL.
Contxt
Pointer to a client-determined context. This client-supplied pointer is passed in to the IoCompletion routine when it is called with the completed IRP. Contxt is NULL if CompRoutine is NULL.
MdlAddr
Pointer to an MDL, possibly the initial MDL in a chain of MDLs, mapping a client-supplied buffer from which the transport is to transfer the data to be sent.
InFlags
Specifies how the data should be transmitted. If this parameter is zero, the transport should send the given data as a normal TSDU. Otherwise, this parameter can be one or a combination (Ored) of the following flags:
TDI_SEND_EXPEDITED
The given data should be sent ahead of any normal send requests the transport is currently holding queued for transmission on this endpoint-to-endpoint connection, assuming the underlying transport supports expedited transfers.
TDI_SEND_PARTIAL
The given data is terminated by an end-of-record but is not a complete message-mode TSDU. The client will send the additional data later. This flag is irrelevant to clients of stream-mode transports.
TDI_SEND_NO_RESPONSE_EXPECTED
The caller is giving a hint to the underlying transport that it does not expect a response to this send from its remote-node peer. A client uses this flag to disable piggybacking of the TSDU acknowledgment by the remote-node transport, assuming both transports support this optimization. Otherwise, its underlying transport might time out, waiting for a piggybacked acknowledgment of the send from the remote node.
TDI_SEND_NON_BLOCKING
If the underlying transport currently has no internal buffer space available for the given data, it should fail this send request with STATUS_DEVICE_NOT_READY, rather than blocking until it can buffer the given data internally. The transport should call the ClientEventSendPossible handler when it again has internal buffer space available for sends. This flag is irrelevant to clients of transports that do no internal buffering.
SendLen
Specifies the size in bytes of the buffer mapped at MdlAddr. The maximum for this parameter depends on the underlying transport. Whether zero is valid also depends on the underlying transport. (See Comments.)

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

TdiBuildSend sets IRP_MJ_INTERNAL_DEVICE_CONTROL as the MajorFunction and TDI_SEND as the MinorFunction codes in the transport's I/O stack location of the given IRP.

In each send request set up with TdiBuildSend, the caller provides a buffer containing the TSDU to be sent to its remote-node peer, or part of a TSDU if the underlying transports support message-mode transfers. A client can send any amount of data up to the maximum size the TDI driver allows. To obtain the transport-specific maximum size for sends, the client can make a TDI_QUERY_PROVIDER_INFO request, set up with TdiBuildQueryInformation.

After the caller of TdiBuildSend passes the send IRP to the underlying transport with IoCallDriver, the client-supplied buffer at MdlAddress is inaccessible to that client until the send operation is completed. The client must not attempt to modify or use its send buffer until the IRP is returned to the client's IoCompletion routine or the client is certain (through protocol semantics) that its underlying transport has completed send operations for the data in that buffer.

The local-node transport can queue several send requests internally, but it always transmits them in FIFO order. If the transport supports expedited sends, it queues incoming expedited-send requests in FIFO order ahead of any normal sends it is currently holding. The transport is responsible for completing incoming sends in a timely manner with either a success or error status. The transport can complete a send with a time-out error based on a driver-determined estimate of a reasonable time-out interval for current network conditions.

Each local-node client's send request on an endpoint-to-endpoint connection corresponds to one of the following:

  • One receive request issued by the remote-node client to its underlying TDI transport
  • One call to the remote-node client's registered ClientEventReceive, ClientEventReceiveExpedited, ClientEventChainedReceive, or ClientEventChainedReceiveExpedited handler by its underlying TDI transport

If the underlying transport supports message-mode sends, its client can send a TSDU in pieces as a sequence of send requests, each except the last specifying the TDI_SEND_PARTIAL flag. When this flag is clear, a message-mode transport considers such a sequence of partial sends to be at an end. In this transfer scenario, the transport on the remote node notifies the receiving client of partial TSDUs by leaving the TDI_RECEIVE_ENTIRE_MESSAGE flag clear in the corresponding receive indications until it indicates the last receive in such a sequence.

The caller of TdiBuildSend can request a nonblocking send by setting the TDI_SEND_NON_BLOCKING flag if the underlying transport has internal buffers into which it copies its clients' send data. Depending on the amount of internal buffer space available, the underlying transport handles such a send request as follows:

  • If it currently has sufficient internal buffer space, the transport copies the data from the client-supplied buffer and completes the send IRP with STATUS_SUCCESS.
  • If it currently has insufficient buffer space for the given SendLength, the transport copies as much data as possible from the client's buffer and returns STATUS_SUCCESS.
  • If the driver currently has no internal buffer space, the transport completes the send IRP with STATUS_DEVICE_NOT_READY.

    The client of such a transport registers a ClientEventSendPossible handler, which the transport will call when it again has internal buffer space available for the rejected send.

When its send is completed with STATUS_SUCCESS, the client of such a transport can determine how much data the transport has buffered for transmission by checking the IoStatus.Information member of the completed IRP. If necessary, the client's IoCompletion routine can resubmit another send request for the remaining data to be sent.

Some transports allow their clients to issue zero-length send requests. For such a transport, a zero-length send actually forces protocol flow, as long as the TDI_SEND_PARTIAL flag is clear. The client of such a transport can issue such a zero-length send as a message that satisfies a receive request. Transports that do not support this feature return an error when a client issues a zero-length send request.

A TDI client also can send a normal TSDU on an endpoint-to-endpoint connection with a call to ZwWriteFile. Because this routine does not allow the specification of TDI_SEND_XXX flags, client-supplied data given to ZwWriteFile is transmitted by the underlying transport as if it were packaged as a TdiBuildSend request with both TDI_SEND_PARTIAL and TDI_SEND_EXPEDITED clear in the SendFlags. The transport assumes that all the data in the buffer at MdlAddr should be sent, and the caller's ByteOffset and Key arguments to ZwWriteFile are ignored.

For more information, see ZwWriteFile and IoCallDriver.

See Also

ClientEventChainedReceive, ClientEventChainedReceiveExpedited, ClientEventReceive, ClientEventReceiveExpedited, ClientEventSendPossible, TdiBuildAccept, TdiBuildAssociateAddress, TdiBuildConnect, TdiBuildInternalDeviceControlIrp, TdiBuildListen, TdiBuildReceive, TdiBuildSetEventHandler, TDI_SEND


TdiBuildSendDatagram

TdiBuildSendDatagram sets up an internal device control IRP for a TDI_SEND_DATAGRAM request to the underlying transport in which the local-node client has already opened a file object representing an address.

VOID
  TdiBuildSendDatagram(
    IN PIRP  Irp,
    IN PDEVICE_OBJECT  DevObj,
    IN PFILE_OBJECT  FileObj,
    IN PVOID  CompRoutine,
    IN PVOID  Contxt,
    IN PMDL  MdlAddr,
    IN ULONG  SendLen,
    IN PTDI_CONNECTION_INFORMATION  SendDatagramInfo
    );

Parameters

Irp
Pointer to a client-supplied IRP, either originating in a higher level network component or allocated with TdiBuildInternalDeviceControlIrp.
DevObj
Pointer to the device object created by the underlying TDI transport driver.
FileObj
Pointer to a file object representing an address.
CompRoutine
Specifies the entry point of a client-supplied IoCompletion routine or NULL. The I/O Manager calls this routine when the given IRP is completed, unless the client sets this parameter to NULL.
Contxt
Pointer to a client-determined context. This client-supplied pointer is passed in to the IoCompletion routine when it is called with the completed IRP. Contxt is NULL if CompRoutine is NULL.
MdlAddr
Pointer to an MDL, possibly the initial MDL in a chain of MDLs, mapping a client-supplied buffer from which the transport is to transfer the datagram to be sent.
SendLen
Specifies the size in bytes of the buffer mapped at MdlAddr. The maximum datagram size depends on the underlying transport. Whether zero is valid also depends on the underlying transport.
SendDatagramInfo
Pointer to a TDI_CONNECTION_INFORMATION structure specifying the remote-node address to which the caller-supplied datagram is to be sent.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

TdiBuildSendDatagram sets IRP_MJ_INTERNAL_DEVICE_CONTROL as the MajorFunction and TDI_SEND_DATAGRAM as the MinorFunction codes in the transport's I/O stack location of the given IRP.

TDI transports never fragment datagrams. Consequently, their clients make one send-datagram request to transmit each datagram, which is associated only with the particular request for a connectionless data transfer to the given destination address. To determine the maximum possible value for SendLen, the client usually issued a preceding query-information request, set up with TdiBuildQueryInformation for any of the QType values TDI_QUERY_PROVIDER_INFO, TDI_QUERY_DATAGRAM_INFO, or TDI_QUERY_MAX_DATAGRAM_INFO.

Any connectionless transfer is inherently unreliable. The underlying transport can lose or duplicate any given datagram at the discretion of the transport driver writer.

When a client issues send-datagram request, the transport can queue the request internally. Such transports process send-datagram requests in FIFO order. They queue send-datagram requests separately from endpoint-to-endpoint send requests from the same client.

See Also

ClientEventChainedReceiveDatagram, ClientEventReceiveDatagram, TdiBuildInternalDeviceControlIrp, TdiBuildQueryInformation, TdiBuildReceiveDatagram, TdiBuildSend, TDI_CONNECTION_INFORMATION, TDI_SEND_DATAGRAM


TdiBuildSetEventHandler

TdiBuildSetEventHandler sets up an internal device control IRP for a TDI_SET_EVENT_HANDLER request to the underlying transport in which the local-node client has already opened a file object representing an address.

VOID
  TdiBuildSetEventHandler(
    IN PIRP  Irp,
    IN PDEVICE_OBJECT  DevObj,
    IN PFILE_OBJECT  FileObj,
    IN PVOID  CompRoutine,
    IN PVOID  Contxt,
    IN LONG  InEventType,
    IN PVOID  InEventHandler,
    IN PVOID  InEventContext
    );

Parameters

Irp
Pointer to a client-supplied IRP, either originating in a higher level network component or, more commonly, allocated with TdiBuildInternalDeviceControlIrp.
DevObj
Pointer to the device object created by the underlying TDI transport driver.
FileObj
Pointer to a file object representing an address.
CompRoutine
Specifies the entry point of a client-supplied IoCompletion routine or NULL. The I/O Manager calls this routine when the given IRP is completed, unless the client sets this parameter to NULL.
Contxt
Pointer to a client-determined context. This client-supplied pointer is passed in to the IoCompletion routine when it is called with the completed IRP. Contxt is NULL if CompRoutine is NULL.
InEventType
Specifies the type of event handler being registered as one of the following:
TDI_EVENT_CONNECT
Register the given ClientEventConnect handler to be called when an endpoint-to-endpoint connection is offered by a remote-node peer.
TDI_EVENT_DISCONNECT
Register the given ClientEventDisconnect handler to be called when an established endpoint-to-endpoint connection is being closed by the remote-node peer.
TDI_EVENT_RECEIVE
Register the given ClientEventReceive handler to be called when a normal receive comes in on an endpoint-to-endpoint connection from the remote node and the client will be given the opportunity to copy all or part of the buffered TSDU.
TDI_EVENT_CHAINED_RECEIVE
Register the given ClientEventChainedReceive handler to be called when a normal receive comes in on an endpoint-to-endpoint connection from the remote node and the client will be given read-only access to the buffered full TSDU until it calls TdiReturnChainedReceives.
TDI_EVENT_RECEIVE_EXPEDITED
Register the given ClientEventReceiveExpedited handler to be called when an expedited receive comes in on an endpoint-to-endpoint connection from the remote node and the client will be given the opportunity to copy all or part of the buffered TSDU.
TDI_EVENT_CHAINED_RECEIVE_EXPEDITED
Register the given ClientEventChainedReceiveExpedited handler to be called when an expedited receive comes in on an endpoint-to-endpoint connection from the remote node and the client will be given read-only access to the buffered full TSDU until it calls TdiReturnChainedReceives.
TDI_EVENT_RECEIVE_DATAGRAM
Register the given ClientEventReceiveDatagram handler to be called when a datagram comes in from a remote node and the client will be given the opportunity to copy all or part of the buffered TSDU.
TDI_EVENT_CHAINED_RECEIVE_DATAGRAM
Register the given ClientEventChainedReceiveDatagram handler to be called when a datagram comes in from a remote node and the client will be given read-only access to the buffered full TSDU until it calls TdiReturnChainedReceives.
TDI_EVENT_SEND_POSSIBLE
Register the given ClientEventSendPossible handler to be called when the underlying transport, which previously returned a submitted send request with STATUS_DEVICE_NOT_READY, again has internal buffer space available into which it can copy the resubmitted client-supplied data to be sent.
TDI_EVENT_ERROR
Register the given ClientEventError handler to be called if an error occurs in an underlying driver such that network I/O on this local-node address has become unreliable or impossible.
TDI_EVENT_ERROR_EX
Register the given ClientEventErrorEx handler to be called if an error occurs such that network I/O on this local-node address has become unreliable or impossible. If it supports these indications, the underlying transport supplies additional buffered information about such an error to ClientEventErrorEx than to ClientEventError.

In addition to the preceding system-defined events, a transport can extend this interface to support transport-specific notifications of events to its clients. Such a transport must define TDI_EVENT_XXX codes in which the most significant bit is set.

InEventHandler
Specifies the entry point of the ClientEventXxx handler being registered. The client can set this parameter to NULL to disable notifications to a previously registered event handler.
InEventContext
Pointer to caller-determined context to be passed in to the ClientEventXxx routine when it is called by the transport. This parameter must be NULL if InEventHandler is NULL.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

When its client first opens a file object that represents an address, the underlying transport initializes all event handlers to NULL.

TdiBuildSetEventHandler sets IRP_MJ_INTERNAL_DEVICE_CONTROL as the MajorFunction and TDI_SET_EVENT_HANDLER as the MinorFunction codes in the transport's I/O stack location of the given IRP.

With each IRP set up by TdiBuildSetEventHandler and submitted to the underlying transport with IoCallDriver, the client registers one event handler for a given event type that can occur on a particular transport address. Indications from lower level NDIS drivers that are forwarded by the transport to ClientEventXxx routines usually occur at IRQL DISPATCH_LEVEL. For these client-supplied event handlers, the caller should allocate the area at InEventContext from nonpaged pool.

A client can register its ClientEvent(Chained)ReceiveDatagram and ClientEventError(Ex) handlers as soon as it has opened a file object representing an address with a successful call to ZwCreateFile. It can register its ClientEventConnect handler as soon as it has opened file objects representing an address and a connection endpoint and made a successful associate-address request to the underlying transport.

For some InEventType values, the address represented by the given file object should be associated with a connection endpoint by the client before it registers certain ClientEventXxx handlers. In particular, a client should associate a connection endpoint with a local-node address before it registers its ClientEvent(Chained)Receive(Expedited), ClientEventDisconnect, and/or ClientEventSendPossible handlers for network transfers that are made on a connection-specific basis. Unless its transport supports delayed-connection acceptances, the client should assume that an endpoint-to-endpoint connection, already associated with the open file object representing the address, is active when it makes the set-event-handler request to register any of these event handlers.

Only clients of transports that buffer send data internally can register a ClientEventSendPossible handler.

In general, a TDI transport can indicate an event to a client while an event of the same kind is in progress. In other words, ClientEventXxx handlers are re-entrant. The transport also can call ClientEvent(Chained)Receive(Expedited) or ClientEvent(Chained)Receive(Datagram) before the client's set-event-handler IRP to register one of these routines is fully completed. Consequently, the client must be prepared to handle receives as soon as it requests the registration of a ClientEvent(Chained)Receive(Xxx) handler.

Calls to registered ClientEvent(Chained)Receive(Xxx) handlers are disabled whenever the client submits a receive or receive-datagram IRP set up with TdiBuildReceive or TdiBuildReceiveDatagram to the underlying transport. After it is called with such an IRP, the underlying transport carries out all operations necessary to complete that IRP before it resumes calling registered ClientEvent(Chained)Receive(Xxx) routine(s) with incoming receive indications.

A client can disable any registered event handler by making another set-event-handler request with the same InEventType but specifying NULL as the InEventHandler and InEventContext parameters to TdiBuildSetEventHandler.

To register its ClientPnPXxx handlers for Plug-and-Play and power-state-change notifications, a client calls TdiRegisterPnPHandlers rather than TdiBuildSetEventHandler followed by IoCallDriver.

See Also

ClientEventConnect, ClientEventChainedReceive, ClientEventChainedReceiveDatagram, ClientEventChainedReceiveExpedited, ClientEventDisconnect, ClientEventError, ClientEventErrorEx, ClientEventReceive, ClientEventReceiveDatagram, ClientEventReceiveExpedited, ClientEventSendPossible, TdiBuildAccept, TdiBuildAssociateAddress, TdiBuildConnect, TdiBuildDisconnect, TdiBuildListen, TdiBuildInternalDeviceControlIrp, TdiBuildReceive, TdiBuildReceiveDatagram, TdiRegisterPnPHandlers, TDI_SET_EVENT_HANDLER, TdiReturnChainedReceives


TdiBuildSetInformation

TdiBuildSetInformation sets up an internal device control IRP for a TDI_SET_INFORMATION request to the underlying transport in which the local-node client has already opened a file object representing an address, connection endpoint, or control channel.

VOID
  TdiBuildSetInformation(
    IN PIRP  Irp,
    IN PDEVICE_OBJECT  DevObj,
    IN PFILE_OBJECT  FileObj,
    IN PVOID  CompRoutine,
    IN PVOID  Contxt,
    IN UINT  SType,
    IN PMDL  MdlAddr
    );

Parameters

Irp
Pointer to a client-supplied IRP, usually one allocated with TdiBuildInternalDeviceControlIrp.
DevObj
Pointer to the device object created by the underlying TDI transport driver.
FileObj
Pointer to a file object representing an address, connection endpoint, or control channel. This file object must be appropriate to the given SType.
CompRoutine
Specifies the entry point of a client-supplied IoCompletion routine or NULL. The I/O Manager calls this routine when the given IRP is completed, unless the client sets this parameter to NULL.
Contxt
Pointer to a client-determined context. This client-supplied pointer is passed in to the IoCompletion routine when it is called with the completed IRP. Contxt is NULL if CompRoutine is NULL.
SType
Specifies the type of information the client wants to be set. This parameter can be transport-defined or one of the following system-defined values:
TDI_QUERY_ADDRESS_INFO
Set the supplied information for an address. The buffer mapped at MdlAddr is formatted as a TDI_ADDRESS_INFO structure.
TDI_QUERY_CONNECTION_INFO
Set the supplied information for a connection endpoint. The buffer mapped at MdlAddr is formatted as a TDI_CONNECTION_INFO structure.
TDI_QUERY_PROVIDER_INFO
Set the supplied information for a control channel. The buffer mapped at MdlAddr is formatted as a TDI_PROVIDER_INFO structure. However, a client cannot reset a transport's provider information to anything that is not actually supported by the transport.
TDI_QUERY_PROVIDER_STATISTICS
Set the supplied information for a control channel. The buffer mapped at MdlAddr is formatted as a TDI_PROVIDER_STATISTICS structure. However, a client cannot reset a transport's statistics, which is global state rather than per-client state, to anything that is not actually maintained by the transport.

The underlying transport can support additional types of set-information requests at the discretion of the driver writer. Such a transport must define TDI_QUERY_XXX codes in which the most significant bit is set.

MdlAddr
Pointer to an MDL mapping the client-supplied buffer containing the data to be set. The format and contents of this buffer depend on the given SType.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

TdiBuildSetInformation sets IRP_MJ_INTERNAL_DEVICE_CONTROL as the MajorFunction and TDI_SET_INFORMATION as the MinorFunction codes in the transport's I/O stack location of the given IRP.

A client can set information about an address, a connection, or a control channel, depending on the SType it passes to TdiBuildSetInformation. The given file object must be appropriate to the given SType or the transport will fail the request.

The underlying transport also can refuse to reset anything for which the client supplies an inappropriate value in the buffer at MdlAddr. For example, a client cannot force the underlying transport to extend its MaxSendSize or MaxDatagramSize beyond the transport-determined limit by issuing a set-information request that attempts to reset these members of the TDI_PROVIDER_INFO structure returned by the transport in a preceding query-information request.

See Also

TDI_ADDRESS_INFO, TdiBuildInternalDeviceControlIrp, TdiBuildQueryInformation, TDI_CONNECTION_INFO, TDI_PROVIDER_INFO, TDI_PROVIDER_STATISTICS, TDI_SET_INFORMATION


TDI Client Event and PnP Notification Handlers

This section describes the system-defined ClientEventXxx callback routines and ClientPnPXxx notification routines that can be implemented in kernel-mode clients of TDI transports. A client registers each such ClientEventXxx callback by setting up an IRP for the underlying transport driver with TdiBuildSetEventHandler, to contain the IOCTL TDI_SET_EVENT_HANDLER code, and calling IoCallDriver with the IRP. It registers each such ClientPnPXxx notification routine with TdiRegisterPnPHandlers.

The names of these client-supplied callback routines and PnP notification routines in this reference are metanames, chosen to describe their basic functionality. Because any client passes only the entry points for these event handlers in calls to TdiBuildSetEventHandler and/or TdiRegisterPnPHandlers, their names actually can be anything the writer of each client chooses.

The following ClientEventXxx and ClientPnPXxx routine references are in alphabetic order.


ClientEventChainedReceive

The ClientEventChainedReceive routine is an event handler that the underlying TDI transport calls in response to an incoming receive from a remote node with which the client has an established endpoint-to-endpoint connection.

The transport calls this handler, rather than ClientEventReceive, when it is forwarding a full TSDU indicated to the transport by an NDIS miniport driver and the client can be given direct read-only access to the buffered TSDU until the client has consumed the data.

NTSTATUS
  ClientEventChainedReceive(
    IN PVOID  TdiEventContext,
    IN CONNECTION_CONTEXT  ConnectionContext,
    IN ULONG  ReceiveFlags,
    IN ULONG  ReceiveLength,
    IN ULONG  StartingOffset,
    IN PMDL  Tsdu,
    IN PVOID  TsduDescriptor
    );

Parameters

TdiEventContext
Pointer to the client-supplied context provided in the IRP that was set up with TdiBuildSetEventHandler when ClientEventChainedReceive was registered with the underlying transport.
ConnectionContext
Pointer to the client's context area for this connection endpoint. The client previously supplied this value to its underlying transport when its ClientEventConnect handler accepted a connection offer from the remote-node peer and/or when it opened the connection endpoint with ZwCreateFile.
ReceiveFlags
Specifies the nature of the receive indication as a combination (ORed) of the following flags:
TDI_RECEIVE_NORMAL
The buffer mapped at Tsdu contains normal data received from the client's remote-node peer. This flag and TDI_RECEIVE_EXPEDITED are mutually exclusive.
TDI_RECEIVE_EXPEDITED
The buffer mapped at Tsdu contains expedited data received from the client's remote-node peer. This flag can be set only if the client did not register either or both ClientEventChainedReceiveExpedited and/or ClientEventReceiveExpedited handler(s) and if the underlying transports support expedited transfers.
TDI_RECEIVE_ENTIRE_MESSAGE
The buffer mapped at Tsdu contains a full TSDU, and the client retains read-only access to this buffer until the client consumes the indicated data if ClientEventChainedReceive returns STATUS_PENDING. This flag is always set when ClientEventChainedReceive is called.
ReceiveLength
Specifies the number of bytes of client data in the buffer mapped at Tsdu.
StartingOffset
Specifies the byte offset at which the client data starts within the buffer mapped at Tsdu.
Tsdu
Pointer to an MDL, possibly the initial MDL in a chain, mapping the buffer containing the received TSDU.
TsduDescriptor
Pointer to a descriptor for the received TSDU. The client must call TdiReturnChainedReceives with this pointer subsequently if it returns STATUS_PENDING for this receive indication. This pointer should be treated as a handle to an opaque variable, to be used by the client only as a parameter to TdiReturnChainedReceives if ClientEventChainedReceive returns STATUS_PENDING.

Return Value

ClientEventChainedReceive can return one of the following:

STATUS_SUCCESS
Indicates the client consumed all the data in the given TSDU and is returning ownership of the buffer (and TsduDescriptor) immediately.
STATUS_PENDING
Indicates the client is retaining ownership of the buffer containing the given TSDU until it calls TdiReturnChainedReceives with the given TsduDescriptor.
STATUS_DATA_NOT_ACCEPTED
Indicates the client is not interested in the TSDU.

If the underlying transport buffers receives internally, the client might retrieve the data with a TDI_RECEIVE request, unless the transport discards buffered data indicated to ClientEventChainedReceive(Xxx) handlers.

Comments

A call to ClientEventChainedReceive gives the client read-only access to the indicated TSDU for the range within the buffer specified by the input StartingOffset and ReceiveLength. If the indicated data is of interest to the client, ClientEventChainedReceive either copies the indicated range of TSDU data into a client-allocated internal buffer and returns STATUS_SUCCESS immediately or retains control of the buffer by returning STATUS_PENDING. If it returns STATUS_PENDING, the client must call TdiReturnChainedReceives subsequently with the input TsduDescriptor to relinquish control of the buffer after the client has consumed the data.

In general, such a call to TdiReturnChainedReceives should occur as quickly as possible. Holding on to a buffer passed to ClientEventChainedReceive for any extended period constrains I/O throughput in underlying driver(s), because the NDIS miniport driver that allocated the buffer cannot reuse this resource for subsequent receive indications until TdiReturnChainedReceives is called.

Because calls to ClientEventChainedReceive always indicate the availability of a full TSDU, the client never has to set up TDI_RECEIVE requests for such an indication, as the corresponding ClientEventReceive handler sometimes must to obtain a full TSDU. Consequently, receive indications made to ClientEventChainedReceive increase network I/O throughput and performance by decreasing call overhead for the client, for its underlying transport, and for the system overall.

If the client has registered only ClientEventChainedReceive and ClientEventReceive handlers for the endpoint-to-endpoint connection, ClientEventChainedReceive can determine whether the TSDU is normal or expedited data by checking the ReceiveFlags, assuming both transports support expedited sends and receives. A transport never calls the corresponding ClientEventReceive handler with the same indication it makes to ClientEventChainedReceive.

The transport does not call ClientEvent(Chained)Receive while the client has an outstanding normal receive request or has rejected previously indicated data for a particular incoming normal receive until that receive is done. However, a transport that supports expedited data can call ClientEvent(Chained)Receive(Expedited) in the process of indicating a normal TSDU if an expedited TSDU comes in from the remote-node peer.

When ClientEventChainedReceive returns control with either STATUS_SUCCESS or STATUS_DATA_NOT_ACCEPTED, the underlying transport assumes the client is done with this receive indication. If the client returns STATUS_PENDING, the transport assumes it has no way of tracking completion of this receive indication because the client is responsible for calling TdiReturnChainedReceives when it has consumed the indicated TSDU.

ClientEventChainedReceive must be capable of carrying out its operations at IRQL DISPATCH_LEVEL.

See Also

ClientEventChainedReceiveExpedited, ClientEventReceive, TdiBuildReceive, TdiBuildSetEventHandler, TdiReturnChainedReceives


ClientEventChainedReceiveDatagram

The ClientEventChainedReceiveDatagram routine is an event handler that the underlying TDI transport calls in response to an incoming receive from a remote node that was directed to a local-node transport address opened by the client.

The transport calls this handler, rather than ClientEventReceiveDatagram, when it is forwarding a full TSDU indicated to the transport by an NDIS miniport driver and the client can be given direct read-only access to the buffered TSDU until the client has consumed the data.

NTSTATUS
  ClientEventChainedReceiveDatagram(
    IN PVOID  TdiEventContext,
    IN LONG  SourceAddressLength,
    IN PVOID  SourceAddress,
    IN LONG  OptionsLength,
    IN PVOID  Options,
    IN ULONG  ReceiveDatagramFlags,
    IN ULONG  ReceiveDatagramLength,
    IN ULONG  StartingOffset,
    IN PMDL  Tsdu,
    IN PVOID  TsduDescriptor
    );

Parameters

TdiEventContext
Pointer to the client-supplied context provided in the IRP that was set up with TdiBuildSetEventHandler when ClientEventChainedReceiveDatagram was registered with the underlying transport.
SourceAddressLength
Specifies the size in bytes of the buffer at SourceAddress.
SourceAddress
Pointer to a buffer specifying the remote-node transport address from which the datagram was sent.
OptionsLength
Specifies the size in bytes of the buffer at Options. Zero implies no option string is available. Options is NULL if this parameter is zero.
Options
Pointer to a buffer specifying a string of transport-specific options sent with the datagram. This pointer is NULL if OptionsLength is zero.
ReceiveDatagramFlags
Specifies the nature of the receive-datagram indication as a combination (ORed) of the following flags:
TDI_RECEIVE_ENTIRE_MESSAGE
The buffer mapped at Tsdu contains a full TSDU, and the client retains read-only access to this buffer until the client consumes the indicated data if ClientEventChainedReceiveDatagram returns STATUS_PENDING. This flag is always set when ClientEventChainedReceiveDatagram is called.
TDI_RECEIVE_BROADCAST
The receive was broadcast.
TDI_RECEIVE_MULTICAST
The receive was multicast.
ReceiveDatagramLength
Specifies the number of bytes of client data in the buffer mapped at Tsdu.
StartingOffset
Specifies the byte offset at which the client data starts within the buffer mapped at Tsdu.
Tsdu
Pointer to an MDL, possibly the initial MDL in a chain, mapping the buffer containing the received TSDU.
TsduDescriptor
Pointer to a descriptor for the received TSDU. The client must call TdiReturnChainedReceives with this pointer subsequently if ClientEventChainedReceiveDatagram returns STATUS_PENDING for this receive indication. This pointer should be treated as a handle to an opaque variable, to be used by the client only as a parameter to TdiReturnChainedReceives if ClientEventChainedReceiveDatagram returns STATUS_PENDING.

Return Value

ClientEventChainedReceiveDatagram can return one of the following:

STATUS_SUCCESS
Indicates the client consumed all the data in the given TSDU and is returning ownership of the buffer to the underlying driver immediately.
STATUS_PENDING
Indicates the client is retaining ownership of the buffer containing the given TSDU until it calls TdiReturnChainedReceives with the given TsduDescriptor.
STATUS_DATA_NOT_ACCEPTED
Indicates the client is not interested in the TSDU.

Comments

When a datagram arrives from a remote node, the transport calls the registered ClientEvent(Chained)ReceiveDatagram handlers for each client with an open file object representing an address that matches the destination address of the datagram. Because a datagram is not associated with an established connection, the TDI driver passes the transport address of the remote-node sender at SourceAddress to the receiving client along with the datagram.

A call to ClientEventChainedReceiveDatagram gives the client read-only access to the indicated TSDU for the range within the buffer specified by the input StartingOffset and ReceiveLength. If the indicated data is of interest to the client, ClientEventChainedReceiveDatagram either copies the indicated range of TSDU data into a client-allocated internal buffer and returns STATUS_SUCCESS immediately or retains control of the buffer by returning STATUS_PENDING. If it returns STATUS_PENDING, the client must call TdiReturnChainedReceives subsequently with the input TsduDescriptor to relinquish control of the buffer after the client has consumed the data.

In general, such a call to TdiReturnChainedReceives should occur as quickly as possible. Holding on to a buffer passed to ClientEventChainedReceiveDatagram for any extended period constrains I/O throughput in underlying driver(s), because the NDIS miniport driver that allocated the buffer cannot reuse this resource for subsequent receive indications until TdiReturnChainedReceives is called.

Because calls to ClientEventChainedReceiveDatagram always indicate the availability of a full TSDU, the client never has to set up TDI_RECEIVE_DATAGRAM requests for such an indication, as the corresponding ClientEventReceiveDatagram handler sometimes must to obtain a full TSDU. Consequently, receive indications made to ClientEventChainedReceiveDatagram increase network I/O throughput and performance by decreasing call overhead for the client, for its underlying transport, and for the system overall. A transport never calls the corresponding ClientEventReceiveDatagram handler with the same indication it makes to ClientEventChainedReceiveDatagram.

When ClientEventChainedReceiveDatagram returns control with either STATUS_SUCCESS or STATUS_DATA_NOT_ACCEPTED, the underlying transport assumes the client is done with this receive indication. If the client returns STATUS_PENDING, the transport assumes it has no way of tracking completion of this receive indication because the client is responsible for calling TdiReturnChainedReceives when it has consumed the indicated TSDU.

The underlying TDI transport does not call ClientEventChainedReceiveDatagram if the client has an outstanding receive or receive-datagram request on the local transport address that is the target of an incoming datagram.

To receive indications for broadcast datagrams that the TDI driver receives on the network, the client must open the broadcast address of its underlying transport and register its ClientEvent(Chained)ReceiveDatagram handler(s).

ClientEventChainedReceiveDatagram must be capable of carrying out its operations at IRQL DISPATCH_LEVEL.

See Also

ClientEventReceiveDatagram, TdiBuildSetEventHandler, TdiReturnChainedReceives, TA_ADDRESS


ClientEventChainedReceiveExpedited

The ClientEventChainedReceiveExpedited routine is an event handler that the underlying TDI transport calls in response to an incoming expedited receive from a remote node with which the client has an established endpoint-to-endpoint connection.

The transport calls this handler, rather than ClientEventReceiveExpedited, when it is forwarding a full TSDU indicated to the transport by an NDIS miniport driver and the client can be given direct read-only access to the buffered TSDU until the client has consumed the data.

NTSTATUS
  ClientEventChainedReceiveExpedited(
    IN PVOID  TdiEventContext,
    IN CONNECTION_CONTEXT  ConnectionContext,
    IN ULONG  ReceiveFlags,
    IN ULONG  ReceiveLength,
    IN ULONG  StartingOffset,
    IN PMDL  Tsdu,
    IN PVOID  TsduDescriptor
    );

Parameters

TdiEventContext
Pointer to the context the client provided in the IRP it previously set up with TdiBuildSetEventHandler to register ClientEventChainedReceiveExpedited.
ConnectionContext
Pointer to the client's context area for this connection endpoint. The client previously supplied this value to its underlying transport when its ClientEventConnect handler accepted a connection offer from the remote-node peer and/or when it opened the connection endpoint with ZwCreateFile.
ReceiveFlags
Specifies the nature of the receive indication as a combination (ORed) of the following flags:
TDI_RECEIVE_EXPEDITED
The buffer mapped at Tsdu contains expedited data received from the client's remote-node peer. This flag is always set when ClientEventChainedReceiveExpedited is called.
TDI_RECEIVE_ENTIRE_MESSAGE
The buffer mapped at Tsdu contains a full TSDU, and the client retains read-only access to this buffer until the client consumes the indicated data if ClientEventChainedReceiveExpedited returns STATUS_PENDING. This flag is always set when ClientEventChainedReceiveExpedited is called.
ReceiveLength
Specifies the number of bytes of client data in the buffer mapped at Tsdu.
StartingOffset
Specifies the byte offset at which the client data starts within the buffer mapped at Tsdu.
Tsdu
Pointer to an MDL, possibly the initial MDL in a chain, mapping the buffer containing the received TSDU.
TsduDescriptor
Pointer to a descriptor for the received TSDU. The client must call TdiReturnChainedReceives with this pointer subsequently if ClientEventChainedReceiveExpedited returns STATUS_PENDING for this receive indication. This pointer should be treated as a handle to an opaque variable, to be used by the client only as a parameter to TdiReturnChainedReceives if ClientEventChainedReceiveExpedited returns STATUS_PENDING.

Return Value

ClientEventChainedReceiveExpedited can return one of the following:

STATUS_SUCCESS
Indicates the client consumed all the data in the given TSDU and is returning ownership of the buffer immediately.
STATUS_PENDING
Indicates the client is retaining ownership of the buffer containing the given TSDU until it calls TdiReturnChainedReceives with the given TsduDescriptor.
STATUS_DATA_NOT_ACCEPTED
Indicates the client is not interested in the TSDU.

If the underlying transport buffers receives internally, the client might retrieve the data with a TDI_RECEIVE request, unless the transport discards buffered data indicated to ClientEventChainedReceive(Xxx) handlers.

Comments

A call to ClientEventChainedReceiveExpedited gives the client read-only access to the indicated TSDU for the range within the buffer specified by the input StartingOffset and ReceiveLength. If the indicated data is of interest to the client, ClientEventChainedReceiveExpedited either copies the indicated range of TSDU data into a client-allocated internal buffer and returns STATUS_SUCCESS immediately or retains control of the buffer by returning STATUS_PENDING. If it returns STATUS_PENDING, the client must call TdiReturnChainedReceives subsequently with the input TsduDescriptor to relinquish control of the buffer after the client has consumed the data.

In general, such a call to TdiReturnChainedReceives should occur as quickly as possible. Holding on to a buffer passed to ClientEventChainedReceiveExpedited for any extended period constrains I/O throughput in underlying driver(s), because the NDIS miniport driver that allocated the buffer cannot reuse this resource for subsequent receive indications until TdiReturnChainedReceives is called.

Because calls to ClientEventChainedReceiveExpedited always indicate the availability of a full TSDU, the client never has to set up TDI_RECEIVE requests for such an indication, as the corresponding ClientEventReceiveExpedited handler sometimes must to obtain a full TSDU. Consequently, receive indications made to ClientEventChainedReceiveExpedited increase network I/O throughput and performance by decreasing call overhead for the client, for its underlying transport, and for the system overall. A transport never calls the corresponding ClientEventReceiveExpedited handler with the same indication it makes to ClientEventChainedReceiveExpedited.

When ClientEventChainedReceiveExpedited returns control with either STATUS_SUCCESS or STATUS_DATA_NOT_ACCEPTED, the underlying transport assumes the client is done with this receive indication. If the client returns STATUS_PENDING, the transport assumes it has no way of tracking completion of this receive indication because the client is responsible for calling TdiReturnChainedReceives when it has consumed the indicated TSDU.

ClientEventChainedReceiveExpedited must be capable of carrying out its operations at IRQL DISPATCH_LEVEL.

See Also

ClientEventChainedReceive, ClientEventReceiveExpedited, TdiBuildSetEventHandler, TdiReturnChainedReceives


ClientEventConnect

The ClientEventConnect routine is an event handler the TDI driver calls in response to an incoming endpoint-to-endpoint connection offer from a remote node.

NTSTATUS
  ClientEventConnect(
    IN PVOID  TdiEventContext,
    IN LONG  RemoteAddressLength,
    IN PVOID  RemoteAddress,
    IN LONG  UserDataLength,
    IN PVOID  UserData,
    IN LONG  OptionsLength,
    IN PVOID  Options,
    OUT CONNECTION_CONTEXT  *ConnectionContext,
    OUT PIRP  *AcceptIrp
    );

Parameters

TdiEventContext
Pointer to the client-supplied context provided in the IRP that was set up with TdiBuildSetEventHandler when ClientEventConnect was registered with the underlying transport.
RemoteAddressLength
Specifies the size in bytes of the buffer at RemoteAddress.
RemoteAddress
Pointer to a buffer containing the transport address of the remote-node client that offered this connection.
UserDataLength
Specifies the size in bytes of the buffer at UserData. Zero indicates either that no data is available or that the underlying transport(s) do not support sending data with an offered connection. UserData is NULL if this parameter is zero.
UserData
Pointer to a buffer containing connect data provided by the remote-node client with its connection offer. This parameter is NULL if UserDataLength is zero.
OptionsLength
Specifies the size in bytes of the buffer at Options. Zero implies no option string. Options is NULL if this parameter is zero.
Options
Pointer to a buffer containing options for the connection in a transport-specific format. This parameter is NULL if OptionsLength is zero.
ConnectionContext
Pointer to a caller–supplied variable in which ClientEventConnect returns a pointer to the client's context area in which it maintains client-determined state for this connection endpoint. Usually, the specified address is identical to the value that the client set for the value at EaBuffer when it originally called ZwCreateFile to open the local connection endpoint. If ClientEventConnect rejects the offered connection, the value it returns is NULL.
AcceptIrp
Pointer to a caller-supplied variable in which ClientEventConnect returns a pointer to an IRP, set up by ClientEventConnect with TdiBuildAccept. The transport completes this IRP if it is supplied as it does any normal accept request. If ClientEventConnect rejects the connection offer, this parameter is NULL.

Return Value

ClientEventConnect can return one of the following:

STATUS_MORE_PROCESSING_REQUIRED
ClientEventConnect is accepting the offered connection and has supplied an accept request at AcceptIrp.

Some transports assume the connection offer is being rejected if ClientEventConnect returns anything other than this value.

STATUS_CONNECTION_REFUSED
ClientEventConnect is rejecting the offered connection.
STATUS_INSUFFICIENT_RESOURCES
ClientEventConnect could not allocate sufficient resources to accept the offered connection. The transport will send a rejection to the remote node.

Comments

This call notifies the local-node client of an incoming connection offer from a remote-node peer process. The local-node ClientEventConnect handler inspects the transport-supplied address information identifying the remote-node client and any data at UserData and/or Options to determine whether to accept this connection offer.

To accept an offered endpoint-to-endpoint connection, ClientEventConnect must set up the buffer at ConnectionContext, together with a TDI_ACCEPT request, and, then, return STATUS_MORE_PROCESSING_REQUIRED. The local-node transport notifies the remote node of the acceptance, transmitting any connect data that its client supplied in the accept IRP, and completes the TDI_ACCEPT request normally.

A client should preallocate the IRP it will use to accept a connection offer before its ClientEventConnect handler is called. In general, any client should preallocate a few IRPs for the TDI_XXX IOCTL requests it might subsequently submit to the underlying transport while running at IRQL DISPATCH_LEVEL. Client calls to TdiBuildInternalDeviceControlIrp can occur at IRQL PASSIVE_LEVEL.

When ClientEventConnect returns control with STATUS_MORE_PROCESSING_REQUIRED, the underlying transport can indicate incoming receives on the endpoint-to-endpoint connection to the client's registered ClientEvent(Chained)Receive(Expedited) handler(s), even before the transport completes the given accept IRP back to its local-node client. A client must be prepared to accept received data as soon as it agrees to accept an endpoint-to-endpoint connection offer from a remote-node peer.

To reject an offered endpoint-to-endpoint connection, ClientEventConnect can simply return STATUS_CONNECTION_REFUSED. For this return status, the local-node transport notifies the remote-node transport that the connection offer has been rejected.

If the client either does not have or cannot allocate sufficient resources to accept the connection offer, ClientEventConnect returns STATUS_INSUFFICIENT_RESOURCES. For this return status, the TDI transport either sends a rejection of the remote-node client's connection offer to the corresponding transport on the remote node or simply drops the connection offer.

ClientEventConnect must be capable of carrying out its operations at IRQL DISPATCH_LEVEL.

See Also

ClientEventChainedReceive, ClientEventChainedReceiveExpedited, ClientEventReceive, ClientEventReceiveExpedited, TDI_ACCEPT, TdiBuildAccept, TdiBuildInternalDeviceControlIrp, TdiBuildListen, TdiBuildSetEventHandler, TdiDispatchCreate, TA_ADDRESS


ClientEventDisconnect

The ClientEventDisconnect routine is an event handler that the underlying TDI transport calls in response to an incoming disconnection notification from a remote node.

NTSTATUS
  ClientEventDisconnect(
    IN PVOID  TdiEventContext,
    IN CONNECTION_CONTEXT  ConnectionContext,
    IN LONG  DisconnectDataLength,
    IN PVOID  DisconnectData,
    IN LONG  DisconnectInformationLength,
    IN PVOID  DisconnectInformation,
    IN ULONG  DisconnectFlags
    );

Parameters

TdiEventContext
Pointer to the client-supplied context provided in the IRP that was set up with TdiBuildSetEventHandler when ClientEventDisconnect was registered with the underlying transport.
ConnectionContext
Pointer to the client's context area for this connection endpoint. The client previously supplied this value to its underlying transport when its ClientEventConnect handler accepted a connection offer from the remote-node peer and/or when it opened the connection endpoint with ZwCreateFile.
DisconnectDataLength
Specifies the size in bytes of the buffer at DisconnectData. Zero indicates that no disconnect data was transmitted from the remote node.
DisconnectData
Pointer to a buffer containing disconnect data received from the remote node by the underlying transport. This pointer is NULL if DisconnectDataLength is zero.
DisconnectInformationLength
Specifies the size in bytes of the buffer at DisconnectInformation. Zero indicates that no additional disconnect information was transmitted from the remote node.
DisconnectInformation
Pointer to a buffer containing any additional transport-specific disconnect information. This pointer is NULL if DisconnectInformationLength is zero.
DisconnectFlags
Specifies the nature of the disconnection operation as zero or as one of the following flags:
TDI_DISCONNECT_ABORT
The transport is closing the endpoint-to-endpoint connection immediately without completing any pending operations on the connection. In effect, this flag is equivalent to a DisconnectFlags of zero.
TDI_DISCONNECT_RELEASE
The transport is engaged in a controlled disconnect operation with the remote node.

Return Value

ClientEventDisconnect can return STATUS_SUCCESS.

Comments

A call to ClientEventDisconnect notifies the local-node client that its remote-node peer is closing their established endpoint-to-endpoint connection. Depending on the input DisconnectFlags, the disconnect can be either controlled or uncontrolled. ClientEventDisconnect is the last event handler the TDI driver calls on an endpoint-to-endpoint connection.

If TDI_DISCONNECT_RELEASE is set in the DisconnectFlags, both transports are coordinating a controlled disconnection. (For more information, see TDI_DISCONNECT.)

A call to ClientEventDisconnect notifies the local-node client that endpoint-to-endpoint activity has ceased or is ceasing on the connection endpoint opened by that client. However, the connection endpoint is still valid after the endpoint-to-endpoint connection has been broken. The local-node client can reuse its open connection endpoint in a subsequent operation after ClientEventDisconnect returns control.

ClientEventDisconnect must be capable of carrying out its operations at IRQL DISPATCH_LEVEL.

See Also

TdiBuildDisconnect, TdiBuildSetEventHandler, TDI_DISCONNECT


ClientEventError

The ClientEventError routine is an event handler that the underlying TDI transport calls in response to an error, either in the transport itself or in a still lower network driver, that makes I/O on a particular local transport address unreliable or impossible.

NTSTATUS
  ClientEventError(
    IN PVOID  TdiEventContext,
    IN NTSTATUS  Status
    );

Parameters

TdiEventContext
Pointer to the client-supplied context provided in the IRP that was set up with TdiBuildSetEventHandler when ClientEventError was registered with the underlying transport.
Status
Specifies an NTSTATUS value that provides information about the condition that caused this call to ClientEventError.

Return Value

ClientEventError can return STATUS_SUCCESS.

Comments

A call to ClientEventError notifies the local-node client of an error condition in the underlying TDI transport, in one of the lower protocol layers of the transport stack, or in the underlying NDIS NIC driver to which the transport stack is bound. If such an error occurs, the TDI transport calls all currently registered ClientEventError handlers for each client on every open address that depends on the underlying driver that encountered the error condition.

A call to ClientEventError can indicate a catastrophic failure. After such a call, the client should cease to use, and in some cases close, the file object representing the transport address associated with this notification. If this address is associated with an endpoint-to-endpoint connection, ClientEventError can assume the connection is broken as well.

Consequently, a ClientEventError handler usually cleans up any state it was maintaining for the address and for all connection endpoints it has associated with that address. That is, the client notifies higher level components for which it is handling pending operations on the address of the failure. Then, the client releases all resources it previously allocated that are relevant to those operations.

ClientEventError must be capable of carrying out its operations at IRQL DISPATCH_LEVEL.

See Also

ClientEventErrorEx, TdiBuildSetEventHandler


ClientEventErrorEx

The ClientEventErrorEx routine is an event handler that the underlying TDI transport calls in response to an error, either in the transport itself or in a still lower network driver, that makes I/O on a particular local transport address unreliable or impossible.

NTSTATUS
  ClientEventErrorEx(
    IN PVOID  TdiEventContext,
    IN NTSTATUS  Status,
    IN PVOID  Buffer
    );

Parameters

TdiEventContext
Pointer to the client-supplied context provided in the IRP that was set up with TdiBuildSetEventHandler when ClientEventErrorEx was registered with the underlying transport.
Status
Specifies an NTSTATUS value that provides information about the condition that caused this call to ClientEventErrorEx.
Buffer
Pointer to a buffer containing additional transport-supplied information about the error. For example, the system TCP/IP transport can supply information that identifies the port when it indicates that a destination port is unreachable.

Return Value

ClientEventErrorEx can return STATUS_SUCCESS.

Comments

A call to ClientEventErrorEx notifies the local-node client of an error condition in the underlying TDI transport, in one of the lower protocol layers of the transport stack, or in the underlying NDIS NIC driver to which the transport stack is bound. If such an error occurs, the TDI transport calls all currently registered ClientEventErrorEx handlers for each client on every open address that depends on the underlying driver that encountered the error condition.

A call to ClientEventErrorEx can indicate a catastrophic failure. After such a call, the client should cease to use, and in some cases close, the file object representing the transport address associated with this notification. If this address is associated with an endpoint-to-endpoint connection, ClientEventErrorEx can assume the connection is broken as well. However, such a call does not necessarily indicate a fatal error. For example, the TCP/IP notification of an "unreachable port" is not a catastrophic error. The client might set a timer and make another attempt to connect to the port when its timer expires.

When notified of a catastropich error, the ClientEventErrorEx handler usually cleans up any state it was maintaining for the address and for all connection endpoints it has associated with that address. That is, the client notifies higher level components for which it is handling pending operations on the address of the failure. For example, the client might forward such an indication to a Windows Sockets application that was using a particular port. Then, the client releases all resources it previously allocated that are relevant to those operations.

ClientEventErrorEx must be capable of carrying out its operations at IRQL DISPATCH_LEVEL.

See Also

ClientEventError, TdiBuildSetEventHandler


ClientEventReceive

The ClientEventReceive routine is an event handler that the underlying TDI transport calls in response to an incoming receive from a remote node with which the client has an established endpoint-to-endpoint connection. Usually, this is a normal TSDU unless the client has not registered a ClientEventReceiveExpedited handler.

NTSTATUS
  ClientEventReceive(
    IN PVOID  TdiEventContext,
    IN CONNECTION_CONTEXT  ConnectionContext,
    IN ULONG  ReceiveFlags,
    IN ULONG  BytesIndicated,
    IN ULONG  BytesAvailable,
    OUT ULONG  *BytesTaken,
    IN PVOID  Tsdu,
    OUT PIRP  *IoRequestPacket
    );

Parameters

TdiEventContext
Pointer to the client-supplied context provided in the IRP that was set up with TdiBuildSetEventHandler when ClientEventReceive was registered with the underlying transport.
ConnectionContext
Pointer to the client's context area for this connection endpoint. The client previously supplied this value to its underlying transport when its ClientEventConnect handler accepted a connection offer from the remote-node peer and/or when it opened the connection endpoint with ZwCreateFile.
ReceiveFlags
Specifies the nature of the receive indication as a combination (ORed) of one or more of the following flags:
TDI_RECEIVE_NORMAL
The buffer at Tsdu contains normal data received from the client's remote-node peer. This flag and TDI_RECEIVE_EXPEDITED are mutually exclusive.
TDI_RECEIVE_EXPEDITED
The buffer at Tsdu contains expedited data received from the client's remote-node peer. This flag can be set only if the client did not register a ClientEventReceiveExpedited and/or ClientEventChainedReceiveExpedited handler.
TDI_RECEIVE_ENTIRE_MESSAGE
The buffer at Tsdu contains a full TSDU. The client should return control as quickly as possible after copying the indicated data into an internal buffer if it accepts the TSDU.

If this flag is clear, ClientEventReceive must check the BytesIndicated and BytesAvailable parameters to determine how much of the TSDU has been provided. Although legacy TDI transports continue to set the TDI_RECEIVE_PARTIAL flag, newer transports leave clear the TDI_RECEIVE_ENTIRE_MESSAGE flag to indicate partial TSDUs to their clients.

TDI_RECEIVE_COPY_LOOKAHEAD
Unless TDI_RECEIVE_ENTIRE_MESSAGE is set, BytesIndicated is something less than BytesAvailable, and ClientEventReceive should copy the number of indicated bytes into an internal buffer, set the variable at BytesTaken, and return control. The client will subsequently submit one or more TDI_RECEIVE requests to get the remainder of the TSDU or ClientEventReceive will be called again to copy the remainder of the TSDU.
TDI_RECEIVE_FRAGMENT
The buffer at Tsdu contains a fragmented TSDU.
TDI_RECEIVE_PEEK
The transport has buffered some receive data internally, but not yet the full TSDU. The client can examine the buffer at Tsdu to decide whether to submit a TDI_RECEIVE request for the TSDU.
BytesIndicated
Specifies the number of bytes of message-mode or stream-mode data in the buffer at Tsdu. This parameter is always less than or equal to the value of BytesAvailable. A TDI transport provides at least 128 bytes of data in a receive indication to its client, unless the received message or stream segment is less than 128 bytes in length. If BytesAvailable is greater than BytesIndicated, the transport has received data that it does not make available when it calls ClientEventReceive.
BytesAvailable
Specifies the total number of bytes in the received TSDU.
BytesTaken
Pointer to a caller-supplied variable in which ClientEventReceive returns the number of bytes of data it copies from the TSDU.
Tsdu
Pointer to a buffer containing the received TSDU data.
IoRequestPacket
Pointer to a variable in which ClientEventReceive returns a pointer to a caller-allocated IRP that was set up with TdiBuildReceive. If this variable is set to NULL, the client will not be making a receive request for the remainder of the TSDU.

Return Value

ClientEventReceive can return one of the following:

STATUS_SUCCESS
Indicates either that the client copied all the data in the given TSDU or that the client set BytesTaken to BytesAvailable and returned control immediately (effectively "tossing" the indication).
STATUS_MORE_PROCESSING_REQUIRED
Indicates the client has supplied an IRP requesting the remainder of the TSDU, usually after copying BytesIndicated into an internal buffer.
STATUS_DATA_NOT_ACCEPTED
Indicates this client is not interested in the TSDU.

Comments

ClientEventReceive accepts or rejects a TSDU that its underlying TDI driver has received on an established endpoint-to-endpoint connection. The TSDU consists of stream-mode or message-mode data that represents a segment of a data stream, an entire message, or a piece of a message. The transport has removed the transport-layer header from the TSDU before it calls ClientEventReceive.

ClientEventReceive copies normal data the TDI driver receives over the network. The transport does not call ClientEvent(Chained)Receive while the client has an outstanding normal receive request or has rejected previously indicated data for a particular incoming normal receive until that receive is done. However, a transport that supports expedited data can call ClientEvent(Chained)ReceiveExpedited in the process of indicating a normal TSDU if an expedited TSDU comes in from the remote-node peer.

A message-mode transport delimits messages using end-of-record marks. Such a transport can make a sequence of separate receive indications for each block of data terminated with an end-of-record mark within a particular received TSDU. Such a receive usually indicates that the remote-node client issued a sequence of sends to transmit the TSDU.

When ClientEventReceive is called, it can do one of the following:

  • Reject the indicated TSDU if it has no use for the data by returning STATUS_DATA_NOT_ACCEPTED
  • Copy all of the data into an internal buffer if TDI_RECEIVE_ENTIRE_MESSAGE is set in the ReceiveFlags and return STATUS_SUCCESS
  • If TDI_RECEIVE_ENTIRE_MESSAGE is clear (or TDI_RECEIVE_PARTIAL is set), copy some or all of the indicated data and return either of the following, depending on which operation it carries out:

    STATUS_MORE_PROCESSING_REQUIRED if the client is supplying a TDI_RECEIVE request at IoRequestPacket to obtain the remaining TSDU data

    STATUS_SUCCESS if the transport is expected to call ClientEventReceive again with the remaining TSDU data

When it has finished copying receive data, ClientEventReceive sets the variable at BytesTaken to the number of bytes of data accepted before it returns control.

If ClientEventReceive supplies a TDI_RECEIVE request at IoRequestPacket for the underlying driver, the transport retrieves the data that it has not yet delivered to the client, along with any new data that is available. Retrieval continues until the client-supplied buffer in the IRP is full or the transport encounters an end-of-record mark. The transport always completes the given IRP before it issues a subsequent call to ClientEvent(Chained)Receive handler for this client. In effect, a client processes each normal TSDU received to completion before the transport will indicate a subsequent normal receive to the client. This allows each client to synchronize receive data correctly.

If ClientEventReceive returns STATUS_DATA_NOT_ACCEPTED after the client has accepted some data from a TSDU, the TDI driver proceeds according to the amount of indicated data the client has accepted and the availability of additional data, as follows:

  • If the driver has passed all indicated data and no more data was available at the time of the indication, the driver calls ClientEventReceive again when it receives more data for the TSDU from the network.
  • If the driver has not passed all indicated data to the client, or if it has additional data available that it did not make available in the preceding call to ClientEventReceive, the transport assumes that its client has no internal buffer space for the data and makes no further indications until the client issues an explicit TDI_RECEIVE request.

    In these circumstances, a transport can optionally initiate protocol-flow-control action to prevent retransmissions of data from the remote-node transport until the local-node client makes the receive request.

A TDI transport is not required to correlate data reception from the network with TDI_EVENT_RECEIVE indications. If the driver provides internal buffering, it can acknowledge data at any time and make receive indications as necessary, for instance, when it has received a certain amount of data or when its internal buffers are nearly full. A buffering driver should retain any data that its client does not accept in an indication until that client notifies the transport that the client's receive request is satisfied. A transport that does not support internal data buffering can acknowledge received data after its client has accepted the data from ClientEventReceive or after the driver has transferred the received data into a client-supplied IRP.

A received TSDU can be any length up to a transport-specific limit, which the client can find by submitting a request set up with TdiBuildQueryInformation for the QType TDI_QUERY_CONNECTION_INFO and examining the value returned for ReceiveBufferSize if the transport buffers received data internally. However, ClientEventReceive does not necessarily receive an entire TSDU, or even the available portion of a TSDU, each time this handler is called. Each TDI transport can set its own limits on the minimum and maximum amounts of data it will indicate at each receive to its clients, as long as its minimum is at least 128 bytes. The client can find these limits by submitting another query-information request for the QType TDI_QUERY_PROVIDER_INFO and examining the values returned for MinimumLookaheadData and MaximumLookaheadData.

ClientEventReceive must be capable of carrying out its operations at IRQL DISPATCH_LEVEL.

See Also

ClientEventChainedReceive, ClientEventReceiveExpedited, ClientEventReceiveDatagram, TdiBuildInternalDeviceControlIrp, TdiBuildQueryInformation, TdiBuildReceive, TdiBuildSetEventHandler


ClientEventReceiveDatagram

The ClientEventReceiveDatagram routine is an event handler that the underlying TDI transport calls in response to an incoming receive from a remote node that was directed to a local-node transport address that the client has opened.

NTSTATUS
  ClientEventReceiveDatagram(
    IN PVOID  TdiEventContext,
    IN LONG  SourceAddressLength,
    IN PVOID  SourceAddress,
    IN LONG  OptionsLength,
    IN PVOID  Options,
    IN ULONG  ReceiveDatagramFlags,
    IN ULONG  BytesIndicated,
    IN ULONG  BytesAvailable,
    OUT ULONG  *BytesTaken,
    IN PVOID  Tsdu,
    OUT PIRP  *IoRequestPacket
    );

Parameters

TdiEventContext
Pointer to the client-supplied context provided in the IRP that was set up with TdiBuildSetEventHandler when ClientEventReceiveDatagram was registered with the underlying transport.
SourceAddressLength
Specifies the size in bytes of the buffer at SourceAddress.
SourceAddress
Pointer to a buffer specifying the remote-node transport address from which the datagram was sent.
OptionsLength
Specifies the size in bytes of the buffer at Options. Zero implies no option string is available. Options is NULL if this parameter is zero.
Options
Pointer to a buffer specifying a string of transport-specific options sent with the datagram. This pointer is NULL if OptionsLength is zero.
ReceiveDatagramFlags
Specifies the nature of the receive-datagram indication as a combination (ORed) of the following flags:
TDI_RECEIVE_ENTIRE_MESSAGE
The buffer at Tsdu contains a full TSDU. The client should return control as quickly as possible after copying the indicated data into an internal buffer if it accepts the TSDU.

If this flag is clear (or if TDI_RECEIVE_PARTIAL is set by a legacy transport), ClientEventReceiveDatagram must check the BytesAvailable and BytesIndicated parameters to determine how much of the TSDU has been provided. Although legacy transports continue to set the TDI_RECEIVE_PARTIAL flag, newer transports leave clear the TDI_RECEIVE_ENTIRE_MESSAGE flag to indicate partial TSDUs to their clients.

TDI_RECEIVE_COPY_LOOKAHEAD
Unless TDI_RECEIVE_ENTIRE_MESSAGE is set, BytesAvailable is something less than BytesIndicated, and ClientEventReceiveDatagram should copy the number of bytes available into an internal buffer, set the variable at BytesTaken, and return control. The client will subsequently submit one or more TDI_RECEIVE_DATAGRAM requests to get the remainder of the TSDU.
TDI_RECEIVE_BROADCAST
The receive was broadcast.
TDI_RECEIVE_MULTICAST
The receive was multicast.
TDI_RECEIVE_PEEK
The transport has buffered some receive data internally, but not yet the full TSDU. The client can examine the buffer at Tsdu to decide whether to submit a TDI_RECEIVE_DATAGRAM request for the TSDU.
BytesIndicated
Specifies the number of bytes of data in the buffer at Tsdu. This parameter is always less than or equal to the value of BytesAvailable. A TDI transport provides at least 128 bytes of data in a receive indication to its client, unless the received datagram is less than 128 bytes in length. If BytesAvailable is greater than BytesIndicated, the transport has received data that it does not present when it calls ClientEventReceiveDatagram.
BytesAvailable
Specifies the total number of bytes in the received TSDU.
BytesTaken
Pointer to a caller-supplied variable in which ClientEventReceiveDatagram returns the number of bytes of data it copied from the datagram.
Tsdu
Pointer to a buffer containing the received TSDU data.
IoRequestPacket
Pointer to a caller-supplied variable in which ClientEventReceiveDatagram returns a pointer to an IRP that it set up with TdiBuildReceiveDatagram. If this parameter is NULL, the client will not be making a receive request for the remainder of the TSDU.

Return Value

ClientEventReceiveDatagram can return one of the following:

STATUS_SUCCESS
Indicates the client copied all the data in the given TSDU and set the variable at BytesTaken to the value at BytesIndicated.
STATUS_MORE_PROCESSING_REQUIRED
Indicates the client has supplied an IRP requesting the remainder of the TSDU, usually after copying BytesIndicated into an internal buffer.
STATUS_DATA_NOT_ACCEPTED
Indicates this client is not interested in the TSDU.

Comments

When a datagram arrives from a remote node, the transport calls the registered ClientEvent(Chained)ReceiveDatagram handlers for each client with an open file object representing an address that matches the destination address of the datagram. Because a datagram is not associated with an established connection, the TDI driver passes the transport address of the remote-node sender at SourceAddress to the receiving client along with the datagram.

ClientEventReceiveDatagram accepts or rejects a TSDU that the TDI driver has received on a particular transport address that the client opened with a preceding call to ZwCreateFile. A datagram TSDU is discrete. Unlike a normal or expedited TSDU, it cannot be transmitted as a sequence of records. In other words, a full datagram is available to the TDI transport, although the driver might not pass all of it in a single call to ClientEventReceiveDatagram.

The transport has removed the transport-layer header from the TSDU before it calls ClientEventReceiveDatagram.

The driver does not call ClientEventReceiveDatagram if the client has an outstanding receive or receive-datagram request on the local transport address that is the target of an incoming datagram.

When ClientEventReceiveDatagram is called, it can do one of the following:

  • Reject the indicated TSDU if it has no use for the data by returning STATUS_DATA_NOT_ACCEPTED
  • Copy all of the data into an internal buffer if TDI_RECEIVE_ENTIRE_MESSAGE is set in the ReceiveFlags and return STATUS_SUCCESS

    When it has finished copying receive data, ClientEventReceiveDatagram sets the variable at BytesTaken to the number of bytes of data accepted before it returns control.

  • If TDI_RECEIVE_ENTIRE_MESSAGE is clear (or TDI_RECEIVE_PARTIAL is set), copy all of the indicated data, set up an IRP for a TDI_RECEIVE_DATAGRAM request, and return STATUS_MORE_PROCESSING_REQUIRED

    If the ClientEventReceiveDatagram issues a receive-datagram request, the transport retrieves any data that ClientEventReceiveDatagram did not receive, along with any new data the TDI transport has available. If the client does not make such a receive-datagram request, it loses this data.

Any TDI transport driver that supports internal buffering should retain a datagram during its clients' receive-datagram operations to satisfy any subsequent receive-datagram requests. The client of such a TDI driver can determine the total amount of buffer space it allocates for received datagrams by submitting a request, set up with TdiBuildQueryInformation for the QType TDI_QUERY_DATAGRAM_INFO or TDI_QUERY_MAX_DATAGRAM_INFO. Usually, such a transport's buffer space for datagrams is around four kilobytes.

To receive indications for broadcast datagrams that the TDI driver receives on the network, the client must open the local-node broadcast address of its underlying transport and register a ClientEvent(Chained)ReceiveDatagram handler on the address.

ClientEventReceiveDatagram must be capable of carrying out its operations at IRQL DISPATCH_LEVEL.

See Also

ClientEventChainedReceiveDatagram, ClientEventReceive, TdiBuildInternalDeviceControlIrp, TdiBuildReceiveDatagram, TdiBuildSetEventHandler, TA_ADDRESS


ClientEventReceiveExpedited

The ClientEventReceiveExpedited routine is an event handler that the underlying TDI transport calls in response to an incoming expedited receive from a remote node with which the client has an established endpoint-to-endpoint connection.

NTSTATUS
  ClientEventReceiveExpedited(
    IN PVOID  TdiEventContext,
    IN CONNECTION_CONTEXT  ConnectionContext,
    IN ULONG  ReceiveFlags,
    IN ULONG  BytesIndicated,
    IN ULONG  BytesAvailable,
    OUT ULONG  *BytesTaken,
    IN PVOID  Tsdu,
    OUT PIRP  *IoRequestPacket
    );

Parameters

TdiEventContext
Pointer to the client-supplied context provided in the IRP that was set up with TdiBuildSetEventHandler when ClientEventReceiveExpedited was registered with the underlying transport.
ConnectionContext
Pointer to the client's context area for this connection endpoint. The client previously supplied this value to its underlying transport when its ClientEventConnect handler accepted a connection offer from the remote-node peer and/or when it opened the connection endpoint with ZwCreateFile.
ReceiveFlags
Specifies the nature of the receive indication as a combination (ORed) of the following flags:
TDI_RECEIVE_EXPEDITED
The buffer at Tsdu contains expedited data received from the client's remote-node peer. This flag is always set when ClientEventReceiveExpedited is called.
TDI_RECEIVE_ENTIRE_MESSAGE
The buffer at Tsdu contains a full TSDU. ClientEventReceiveExpedited should return control as quickly as possible after copying the indicated data into an internal buffer if it accepts the TSDU.

If this flag is clear (or TDI_RECEIVE_PARTIAL is set by a legacy transport), ClientEventReceiveExpedited must check the BytesIndicated and BytesAvailable parameters to determine how much of the TSDU has been provided. Although legacy transports continue to set the TDI_RECEIVE_PARTIAL flag, newer transports leave clear the TDI_RECEIVE_ENTIRE_MESSAGE flag to indicate partial TSDUs to their clients.

TDI_RECEIVE_COPY_LOOKAHEAD
Unless TDI_RECEIVE_ENTIRE_MESSAGE is set, BytesIndicated is something less than BytesAvailable, and ClientEventReceiveExpedited should copy the number of indicated bytes into an internal buffer, set the variable at BytesTaken, and return control. The client will subsequently submit one or more TDI_RECEIVE requests to get the remainder of the TSDU or ClientEventReceiveExpedited will be called again to copy the remainder of the TSDU.
TDI_RECEIVE_FRAGMENT
The buffer at Tsdu contains a fragmented TSDU.
TDI_RECEIVE_PEEK
The transport has buffered some receive data internally, but not yet the full TSDU. The client can examine the buffer at Tsdu to decide whether to submit a TDI_RECEIVE request for the TSDU.
BytesIndicated
Specifies the number of bytes of expedited data in the buffer at Tsdu. This parameter is always less than or equal to the value of BytesAvailable. A TDI transport provides at least 128 bytes of data in a receive indication to its client, unless the received message or stream segment is less than 128 bytes in length. If BytesAvailable is greater than BytesIndicated, the transport has received data that it does not make available when it calls ClientEventReceiveExpedited.
BytesAvailable
Specifies the total number of bytes in the received TSDU.
BytesTaken
Pointer to a caller-supplied variable in which ClientEventReceiveExpedited returns the number of bytes of data it copies from the TSDU.
Tsdu
Pointer to a buffer containing the received TSDU data.
IoRequestPacket
Pointer to a variable in which ClientEventReceiveExpedited returns a pointer to an IRP that was set up with TdiBuildReceive. If this parameter is NULL, the client will not be making a receive request for the remainder of the TSDU.

Return Value

ClientEventReceiveExpedited can return one of the following:

STATUS_SUCCESS
Indicates the client copied all the data in the given TSDU.
STATUS_MORE_PROCESSING_REQUIRED
Indicates the client has supplied an IRP requesting the remainder of the TSDU, after copying BytesIndicated into an internal buffer.
STATUS_DATA_NOT_ACCEPTED
Indicates this client is not interested in the TSDU.

Comments

ClientEventReceiveExpedited accepts or rejects an expedited TSDU that the TDI driver has received on an established endpoint-to-endpoint connection. This handler is almost identical to ClientEventReceive, except that expedited data flow supersedes normal data flow.

Consequently, the underlying transport can call ClientEventReceiveExpedited on a connection while a normal receive operation or an indication to ClientEventReceive (or ClientEventChainedReceive) is in progress. If this occurs, normal data flow does not resume until ClientEventReceiveExpedited has returned and the client has received all the expedited data for the TSDU. If ClientEventReceiveExpedited provides a TDI_RECEIVE request at IoRequestPacket, this request also has priority over any client-issued request for nonexpedited data.

When ClientEventReceiveExpedited is called, it can do one of the following:

  • Reject the indicated TSDU if it has no use for the data by returning STATUS_DATA_NOT_ACCEPTED
  • Copy all of the data into an internal buffer if TDI_RECEIVE_ENTIRE_MESSAGE is set in the ReceiveFlags and return STATUS_SUCCESS
  • If TDI_RECEIVE_ENTIRE_MESSAGE is clear (or TDI_RECEIVE_PARTIAL is set), copy some or all of the indicated data and return either of the following, depending on which operation it carries out:

    STATUS_MORE_PROCESSING_REQUIRED if the client is supplying a TDI_RECEIVE request at IoRequestPacket to obtain the remaining TSDU data

    STATUS_SUCCESS if the transport is expected to call ClientEventReceiveExpedited again with the remaining TSDU data

When it has finished copying receive data, ClientEventReceiveExpedited sets the variable at BytesTaken to the number of bytes of data accepted before it returns control.

ClientEventReceiveExpedited must be capable of carrying out its operations at IRQL DISPATCH_LEVEL.

See Also

ClientEventChainedReceiveExpedited, ClientEventReceive, TdiBuildInternalDeviceControlIrp, TdiBuildReceive, TdiBuildSetEventHandler


ClientEventSendPossible

The ClientEventSendPossible routine is an event handler that the underlying TDI transport, which buffers sends internally but returned STATUS_DEVICE_NOT_READY for this client's preceding TDI_SEND request, calls when the transport has internal buffer space available to accept a resubmitted send request from the client.

NTSTATUS
  ClientEventSendPossible(
    IN PVOID  TdiEventContext,
    IN PVOID  ConnectionContext,
    IN ULONG  BytesAvailable
    );

Parameters

TdiEventContext
Pointer to the client-supplied context provided in the IRP that was set up with TdiBuildSetEventHandler when ClientEventSendPossible was registered with the underlying transport.
ConnectionContext
Pointer to the client's context area for this connection endpoint. The client previously supplied this value to its underlying transport when its ClientEventConnect handler accepted a connection offer from the remote-node peer and/or when it opened the connection endpoint with ZwCreateFile.
BytesAvailable
Specifies the number of bytes currently available in the TDI driver for buffering client-supplied send data.

Return Value

ClientEventSendPossible can return STATUS_SUCCESS.

Comments

A call to ClientEventSendPossible indicates that its underlying transport now has buffer space available for sends and how much buffer space it has when the transport makes this call.

However, ClientEventSendPossible cannot necessarily submit a successful nonblocking TDI_SEND request for the full BytesAvailable. For example, another client of the same transport might submit a send that uses the transport's available buffer space before this client's send request reaches the transport.

ClientEventSendPossible must be capable of carrying out its operations at IRQL DISPATCH_LEVEL.

See Also

TdiBuildSend, TdiBuildSetEventHandler, TDI_SEND


ClientPnPAddNetAddress

The ClientPnPAddNetAddress routine is initially called by TDI as a consequence of the client's own call to TdiRegisterPnPHandlers. Subsequently, TDI calls ClientPnPAddNetAddress as a consequence of any transport's call to TdiRegisterNetAddress or, possibly but very rarely, as the consequences of the client's own call to TdiEnumerateAddresses.

VOID
  ClientPnPAddNetAddress(
    IN PTA_ADDRESS  Address,
    IN PUNICODE_STRING  DeviceName,
    IN PTDI_PNP_CONTEXT  Context
    );

Parameters

Address
Pointer to a buffered network address, formatted as a TA_ADDRESS structure. The contents and layout of this buffer are protocol-specific in nature with the information supplied at Address dependent on the AddressType and AddressLength members as set by the underlying transport.
DeviceName
Pointer to a buffered Unicode string, which effectively identifies the transport on which the given network address is being registered with TDI. Typically, this is the name of the transport-created device object originally passed in to the ClientPnPBindingChange routine when the client was offered this binding.
Context
Pointer to a transport-supplied context associated with this address.

For example, TCP/IP passes in a pointer to the PDO representing the device on which this new address has just arrived.

Comments

A client must register its ClientPnPAddNetAddress routine with a call to TdiRegisterPnPHandlers to be called to initialize whatever state the client maintains about currently registered network addresses. For maximum performance, the client should set up and maintain an internal list of valid network addresses for any transport to which it binds itself with a call to ZwCreateFile.

Subsequent to the sequence of system-startup-time calls to ClientPnPAddNetAddress, TDI calls this routine whenever a PnP-supporting transport registers a new network address with TDI. That is, ClientPnPAddNetAddress can be called at runtime with a new address supplied by any transport, even a transport to which it is not bound. Consequently, ClientPnPAddNetAddress should return control promptly if the client does not recognize the protocol-specific type of the input address. A check on the AddressType member of the TA_ADDRESS structure is more efficient than doing a string comparison on the buffered contents at DeviceName.

The format and contents of the buffer at Address depend on the value of the AddressType member in the TA_ADDRESS structure.The underlying transport is responsible for providing only the specification of the new network address. If the TA_ADDRESS structure of a particular type also contains a Socket identifier or any other such collateral member(s), those member(s) should be ignored by ClientPnPAddNetAddress.

For the input Context parameter, the value of the ContextType member in the TDI_PNP_CONTEXT structure provides a hint about how to interpret this transport-supplied and protocol-determined context information. The Context pointer can be NULL if the underlying transport does not provide context information when it calls TdiRegisterNetAddress.

A reciprocal call to TdiDeregisterPnPHandlers disables calls to ClientPnPAddNetAddress.

A client's call to TdiEnumerateAddresses causes a sequence of calls to its ClientPnPAddNetAddress routine, one for each currently valid network address that a particular transport to which the client is bound has already registered with TDI. Consequently, most clients never call TdiEnumerateAddresses to avoid incurring the performance penalty of the resulting sequence of calls to ClientPnPAddNetAddress. However, a client could make this call to restore the integrity of its internal list of binding-specific valid network addresses if that list might have become corrupted.

TDI calls ClientPnPAddNetAddress at IRQL < DISPATCH_LEVEL.

See Also

TA_ADDRESS, TdiDeregisterPnPHandlers, TdiEnumerateAddresses, TDI_PNP_CONTEXT, TdiRegisterNetAddress, TdiRegisterPnPHandlers


ClientPnPBindingChange

The ClientPnPBindingChange routing is initially called by TDI as a consequence of the client's own call to TdiRegisterPnPHandlers. At system startup, TDI calls ClientPnPBindingChange as a consequence of underlying transports' calls to TdiRegisterDeviceObject, TdiProviderReady, and TdiDeregisterDeviceObject. Subsequent to system startup, TDI calls ClientPnPBindingChange whenever a transport to which the client is bound calls TdiRegisterDeviceObject and TdiDeregisterDeviceObject.

VOID
  ClientPnPBindingChange(
    IN TDI_PNP_OPCODE  PnPOpcode,
    IN PUNICODE_STRING  DeviceName,
    IN PWSTR  MultiSZBindList
    );

Parameters

PnPOpcode
Specifies one of the following values:
TDI_PNP_OP_ADD
During system startup, this value indicates an established transport-to-NIC binding and a transport-created, named device object registered with TDI to represent the binding to at least one underlying NIC. The ClientPnPBindingChange routine can pass a pointer to the name of the transport's registered device object (available at DeviceName) as a parameter to ZwCreateFile to bind itself to this transport, and subsequently, the client can use the corresponding device object pointer in client-allocated IRPs.

Following system startup, a runtime call to ClientPnPBindingChange with TDI_PNP_OP_ADD can occur because the PnP Manager notified NDIS that a new NIC was added to the system. NDIS, in turn, notified the lowest driver in the transport stack (or lower edge of the monolithic transport) by calling its ProtocolBindAdapter function so the transport is established a binding to the new NIC and registered a device object for that transport-to-NIC binding with TDI.

TDI_PNP_OP_DEL
This value indicates that a transport to which the client is bound has just deregistered and deleted a device object for an established binding to an underlying NIC.

This call to ClientPnPBindingChange can occur because the PnP Manager notified NDIS that a NIC was removed from the system. NDIS, in turn, notified the lowest driver in the transport stack (or lower edge of the monolithic transport) by calling its ProtocolUnbindAdapter function so the transport is tearing down its binding to the NIC.

TDI_PNP_OP_PROVIDERREADY
During system startup, this value indicates that a particular transport is ready to carry out network I/O operations on its established binding(s).

This occurs when an initializing transport calls TdiProviderReady. The buffer at DeviceName specifies the generic name of this transport, which the transport previously supplied when it called TdiRegisterProvider.

Such a transport has already done the following:

  • Established one or more bindings to appropriate NICs in the machine and created named device objects to represent each of its transport-to-NIC bindings.
  • Registered its named device object(s) with TDI, thereby causing one or more calls to ClientPnPBindingChange with the PnPOpcode TDI_PNP_OP_ADD.
  • Registered any network addresses known to the transport on those bindings with TDI, thereby causing one or more calls to the client's just registered ClientPnPAddNetAddress routine.
  • Set up whatever internal state the transport uses to track network I/O through its transport-to-NIC binding(s).
  • Received a NET_PNP_EVENT notification from NDIS of type NetEventBindsComplete in a call to the ProtocolPnPEvent function of the (monolithic) transport driver or of the lowest driver in the (multidriver) transport stack, which forwards this PnP-event notification up to the TDI transport driver at the top.

    The transport's call to TdiProviderReady indicates that this transport has attempted to established bindings to one or more NICs, as configured in the registry of the current machine, has succeeded in establishing at least one such transport-to-NIC binding, and has succeeded in initializing itself to a state of readiness to carry out network I/O operations on its established binding(s).

    A client bound to this transport could now make a network I/O request of this transport, or it can set up any additional transport-specific state it will need for tracking runtime network I/O and defer its initial network I/O request until ClientPnPBindingChange is called again with PnPOpcode TDI_PNP_NETREADY.

TDI_PNP_OP_NETREADY
During system startup, this value indicates that all transport-to-NIC bindings configured on the current computer are ready to carry out network I/O operations for potential clients.

This occurs when all the transports have registered themselves with TDI by calling TdiProviderReady. The DeviceName and BindingList pointers are NULL when ClientPnPBindingChange is called.

Clients usually wait for this notification to make their initial network I/O requests, thereby avoiding potential conflict for CPU cycles with the system network setup code. For example, any client that binds itself to more than one transport during system startup has a choice of transports available sooner if it defers its initial network I/O request until ClientPnPBindingChange is called with TDI_PNP_OP_NETREADY.

DeviceName
Pointer to a buffered Unicode string that is usually the name of the transport-created device object either representing the transport in general as the target for its clients' network I/O or representing the target for its clients' network I/O through a particular transport-to-NIC binding. Depending on the given PnPOpcode, this input parameter can be one of the following:
  • A pointer to buffered Unicode string that is the transport's generic name, such as "\device\nwlinkipx," for the PnPOpcode TDI_PNP_OP_PROVIDERREADY
  • A pointer to a buffered Unicode string that is the name of a particular interface, such as "\device\tcpip_{interfaceGUID}" if the transport supports more than one device interface but creates a single device object

    (In this case, the name of the device object actually opened by a client would omit the "_{interfaceGUID}" suffix.)

  • NULL for the PnPOpcode TDI_PNP_OP_NETREADY
MultiSZBindList
Subsequent to system startup, points to a buffered binding-order list if PnPOpcode is TDI_PNP_OP_ADD or TDI_PNP_OP_DEL. Otherwise, this parameter is NULL.

Comments

At system setup, a client must register its ClientPnPBindingChange routine with a call to TdiRegisterPnPHandlers to initialize whatever state the client maintains about its binding(s) to particular transport(s). A successful call to TdiRegisterPnPHandlers causes a sequence of calls to ClientPnPBindingChange to occur, as follows:

  1. TDI calls ClientPnpBindingChange zero or more times with the PnPOpcode TDI_PNP_OP_ADD, passing in the buffered name of a transport-created device object, identified at DeviceName, that is already registered with TDI for an established transport-to-NIC binding. At each such call, ClientPnPBindingChange determines whether to bind itself to this transport, either calling ZwCreateFile or rejecting the binding offer by promptly returning control to TDI.
  2. TDI calls ClientPnPBindingChange zero or more times with the PnPOpcode TDI_PNP_OP_PROVIDERREADY, passing in the buffered name of a registered transport that has already declared its readiness to perform network I/O operations on at least one established transport-to-NIC binding at DeviceName. Each such transport has already called TdiProviderReady because it is done with its initialization and binding-time operations.
  3. TDI continues to call ClientPnPBinding change as already described during system startup whenever subsequently initialized transports, if any, call TdiRegisterDeviceObject and TdiProviderReady.
  4. TDI makes one more system-startup-time call to ClientPnPBinding change with the PnPOpcode TDI_PNP_OP_NETREADY when the last registered TDI transport driver configured in the current computer calls TdiProviderReady. At this stage of system startup, the client usually begins its initial network I/O operations, such as contacting a DC to log on to the network.

Subsequently, TDI notifies the client when a transport to which it is bound creates a new binding or tears down an established binding. The ClientPnPPowerChange handler also is called if a user-initiated network connection or disconnection causes a binding change.

After system startup, ClientPnPBindingChange is called to add or delete a binding only for a transport to which it is bound. When ClientPnPBindingChange is called with a binding offer, the transport has already created the device object identified at DeviceName before it called TdiRegisterDeviceObject. When ClientPnPBindingChange is called to delete an existing binding, the transport will destroy the device object identified at DeviceName as soon as TdiDeregisterDeviceObject returns control to the transport.

Consequently, when ClientPnPBindingChange is called to add a binding, it can allocate per-binding resources, initialize the client's per-binding state, and call ZwCreateFile to bind itself to the new transport-to-NIC stack. The client also can call ZwCreateFile again with any of the network addresses that the transport registers with TDI on the newly established binding as soon as its ClientPnpAddNetAddress routine is called.

Conversely, when ClientPnPBindingChange is called to delete a binding, it must begin the unbinding process and release any per-binding resources that the client allocated. The client can assume that its ClientPnPDelNetAddress routine has been called one or more times because the transport deregisters its addresses when tearing down a binding before it calls TdiDeregisterDeviceObject. However, ClientPnPBindingChange must make a reciprocal call to ZwClose with the handle to the device object that it obtained from ZwCreateFile.

In either case, the information at MultiSzBindList reflects the new binding order for the client when a binding is added or deleted at runtime.

For more information, see ZwCreateFile and ZwClose.

A reciprocal call to TdiDeregisterPnPHandlers disables subsequent calls to ClientPnPBindingChange.

TDI calls ClientPnPBindingChange at IRQL < DISPATCH_LEVEL.

See Also

ClientPnPAddNetAddress, ClientPnPDelNetAddress, ClientPnPPowerChange, NET_PNP_EVENT, ProtocolPnPEvent, TdiDeregisterDeviceObject, TdiDeregisterPnPHandlers, TdiProviderReady, TdiRegisterDeviceObject, TdiRegisterPnPHandlers, TdiRegisterProvider


ClientPnPDelNetAddress

The ClientPnPDelNetAddress routine is called by TDI as a consequence of a transport's call to TdiDeregisterNetAddress.

VOID
  ClientPnPDelNetAddress(
    IN PTA_ADDRESS  Address,
    IN PUNICODE_STRING  DeviceName,
    IN PTDI_PNP_CONTEXT  Context
    );

Parameters

Address
Pointer to a buffered network address. The contents and layout of this buffer are protocol-specific in nature with the information supplied at Address depending on the AddressType and AddressLength members as set by the underlying transport.
DeviceName
Pointer to a buffered Unicode string, which effectively identifies the transport from which the given network address is being deregistered. Typically, this contains the name of the transport-created device object originally passed in to the ClientPnPBindingChange routine when the client was offered this binding.
Context
Pointer to a transport-supplied context associated with this address.

For example, TCP/IP passes a pointer to the PDO representing the device on which the connection to the given address has just been broken.

Comments

A client must register its ClientPnPDelNetAddress routine with a call to TdiRegisterPnPHandlers to begin receiving these notifications whenever any PnP-supporting transport is about to delete an existing net address.

Subsequent to the sequence of initialization-time calls to ClientPnPAddNetAddress, TDI calls ClientPnPDelNetAddress whenever a PnP-supporting transport deregisters a network address with TDI. That is, ClientPnPDelNetAddress can be called with an address supplied by any transport, even a transport to which it is not bound. Consequently, ClientPnPDelNetAddress should return control promptly if the client does not recognize the protocol-specific type of the input address. For better client performance, a check on the AddressType member of the TA_ADDRESS structure is more efficient than doing a string comparison on the buffered contents at DeviceName.

The format and contents of the buffer at Address depend on the value of the AddressType member in the TA_ADDRESS structure.The underlying transport is responsible for providing only the specification of the network address. If the TA_ADDRESS structure of a particular type also contains a Socket identifier or any other such collateral member(s), those member(s) should be ignored by ClientPnPDelNetAddress.

For the input Context parameter, the value of the ContextType member in the TDI_PNP_CONTEXT structure provides a hint about how to interpret this transport-supplied and protocol-determined context information. The Context pointer can be NULL if the underlying transport does not provide context information when it calls TdiDeregisterNetAddress.

In conjunction with ClientPnPAddNetAddress, ClientPnPDelNetAddress maintains the client's internal list(s) of per-binding valid network addresses. When ClientPnPDelNetAddress is called to remove an address from such an internal list, it also notifies any of its own clients that might be using the address of the just-broken network connection.

A reciprocal call to TdiDeregisterPnPHandlers disables calls to ClientPnPDelNetAddress.

TDI calls ClientPnPDelNetAddress at IRQL < DISPATCH_LEVEL.

See Also

ClientPnPAddNetAddress, TA_ADDRESS, TdiDeregisterNetAddress, TdiDeregisterPnPHandlers


ClientPnPPowerChange

The ClientPnPPowerChange routine is called by TDI as a consequence of a transport's call to TdiPnPPowerRequest or, for a user-initiated network reconfiguration, as a consequence of a call by NDIS.

NTSTATUS
  ClientPnPPowerChange(
    IN PUNICODE_STRING  DeviceName,
    IN PNET_PNP_EVENT  PowerEvent,
    IN PTDI_PNP_CONTEXT  Context1,
    IN PTDI_PNP_CONTEXT  Context2
    );

Parameters

DeviceName
Pointer to a buffered Unicode string that typically identifies the transport-created device object representing the target for a client's network I/O through a particular transport or transport-to-NIC binding.
PowerEvent
Pointer to a NET_PNP_EVENT-type structure indicating the type of notification, which can be either of the following types of notifications:
  • The NetEvent member of this structure has been set by the underlying transport to NetEventSetPower, NetEventQueryPower, NetEventQueryRemoveDevice, or NetEventCancelRemoveDevice (subsequent to the failure of a NetEventQueryRemoveDevice).
  • The NetEvent member of this structure has been set by NDIS to NetEventBindList or NetEventReconfigure. That is, a runtime call to ClientPnPPowerChange from TDI can occur as a consequence of an end-user-initiated change in the Connections folder.
Context1
Pointer to protocol-determined context associated with this notification if the underlying transport called TdiPnPPowerRequest. For example, TCP/IP passes a pointer to a list of addresses associated with the context of this notification.

Otherwise, this points to a context supplied by NDIS to TDI as a result of a user-initiated change in the network configuration. For example, when the user reconfigures the network in the Connections folder, thereby requesting a change in existing network bindings, NDIS must notify all currently registered TDI clients affected by such a binding change to give them the opportunity to register or deregister their ClientPnPXxx handlers.

Context2
Pointer to protocol-determined context associated with this notification. For example, TCP/IP returns a pointer to the PDO of the physical device on which this notification was generated.

Otherwise, this points to a context supplied by NDIS to TDI as a result of a user-initiated change in the network configuration, such as a pointer to the PDO of the underlying NIC to be reconfigured.

Return Value

ClientPnPPowerChange can return STATUS_PENDING if the client must notify its own clients of a power-state, query-device-removal, or device-removal event. Otherwise, it should return either STATUS_SUCCESS or a client-determined failure status, such as STATUS_FILES_OPEN or STATUS_UNSUCCESSFUL, to reject a NetEventSetPowerDevice-type or NetEventQueryRemoveDevice-type request if one of its own clients currently is depending on the underlying NIC in question.

ClientPnPPowerChange can return STATUS_SUCCESS when it is called with NetEventBindList or NetEventReconfigure notifications, because these are inherently synchronous operations.

Comments

A client must register its ClientPnPPowerChange routine with a call to TdiRegisterPnPHandlers to begin receiving these notifications whenever any PnP-supporting transport or NDIS calls TdiPnPPowerRequest. That is, ClientPnPPowerChange can be called with a DeviceName pointer supplied by any transport, even a transport to which it is not bound. Consequently, ClientPnPPowerChange should return control promptly if the client does not recognize the transport identified at DeviceName or, when notified about a user-initiated network reconfiguration, if the client determines that it has no reason to establish a new or release an existing transport-to-NIC binding.

On the other hand, if the client decides to register or deregister its PnP handlers on a transport as the consequence of a NetEventBindingList or NetEventReconfigure notification from NDIS, the given transport will subsequently be called to bind itself to a new NIC or even to unbind itself from a NIC to which it is currently bound. That is, NDIS calls the ProtocolBindAdapter or ProtocolUnbindAdapter function at the lower edge of the transport stack on behalf of this client. The transport's subsequent call to TdiRegisterDeviceObject or TdiDeregisterDeviceObject, in turn, causes a call to the ClientPnPBindingChange function of the client.

If ClientPnPPowerChange returns STATUS_SUCCESS for a call with the input PowerEvent of type NetEventQueryRemoveDevice, the client can expect a subsequent call to its ClientPnPBindingChange routine with the PnPOpcode TDI_PNP_OP_DEL if all other clients bound to the same transport-to-NIC stack also succeed this notification. Otherwise, the client can expect another call to ClientPnPPowerChange with the input PowerEvent of type NetEventCancelRemoveDevice.

In general, ClientPnPPowerChange must decide whether to notify its own clients when it receives NetEventQueryPowerDevice and NetEventSetPowerDevice notifications. For example, on set-power notifications that indicate the underlying NIC might be powered down into a hibernating state, ClientPnPPowerChange might return STATUS_PENDING in order to check with its own clients about their anticipated needs to carry out network I/O operations on the given binding. However, the NetEventSetPowerDevice-type of notification occurs after a system-determined period of no network I/O demand on a particular NIC, so the client usually can assume that its own clients have no need for notifications of this type.

If ClientPnPPowerChange returns STATUS_PENDING, the client must call TdiPnPPowerComplete as soon as it has complete the operations it initiated at this notification.

A reciprocal call to TdiDeregisterPnPHandlers disables subsequent calls to ClientPnPPowerChange.

TDI calls ClientPnPPowerChange at IRQL < DISPATCH_LEVEL.

See Also

ClientPnPBindingChange, NET_PNP_EVENT, ProtocolBindAdapter, ProtocolUnbindAdapter, TdiDeregisterDeviceObject, TdiDeregisterPnPHandlers, TdiPnPPowerComplete, TdiPnPPowerRequest, TdiRegisterDeviceObject, TdiRegisterPnPHandlers


TDI Structures

This section describes structures that are used by TDI transport drivers and their kernel-mode clients.

The structures described in this section are listed in alphabetic order.


TA_ADDRESS

The TA_ADDRESS structure defines a single transport address of a specific type, for example, NetBIOS.

typedef struct _TA_ADDRESS {
  USHORT  AddressLength;
  USHORT  AddressType;
  UCHAR   Address[1];
} TA_ADDRESS, *PTA_ADDRESS;

Members

AddressLength
Specifies the number of bytes in an address of the specified AddressType.

For example, each NetBIOS-type address is TDI_ADDRESS_LENGTH_NETBIOS bytes in length.

AddressType
Specifies the type of the transport address. The system defines symbolic constants for possible address types, some corresponding to Windows Sockets values and some extensions defined by TDI. Defined address types include the following:
TDI_ADDRESS_TYPE_IP
Internetwork: UDP, TCP, and so on
TDI_ADDRESS_TYPE_APPLETALK
AppleTalk address.
TDI_ADDRESS_TYPE_NETBIOS
NetBIOS address.
TDI_ADDRESS_TYPE_NETBIOS_EX
Extended NetBIOS address.
TDI_ADDRESS_TYPE_IPX
Netware IPX.
TDI_ADDRESS_TYPE_VNS
Banyan VINES IP address.
TDI_ADDRESS_TYPE_8022
802.2 netcard–level address; TDI only.
TDI_ADDRESS_TYPE_NETONE
Net/One address. TDI only.
TDI_ADDRESS_TYPE_NS
Xerox NS protocols.
TDI_ADDRESS_TYPE_OSI_TSAP
OSI, TSAP address; TDI only.

The following are defined for future use:

TDI_ADDRESS_TYPE_IMPLINK
Arpanet implink address.
TDI_ADDRESS_TYPE_PUP
Pup protocols, such as BSP.
TDI_ADDRESS_TYPE_CHAOS
MIT CHAOS protocols.
TDI_ADDRESS_TYPE_NBS
NBS protocols.
TDI_ADDRESS_TYPE_ECMA
European computer manufacturers association protocols.
TDI_ADDRESS_TYPE_DATAKIT
Datakit protocols.
TDI_ADDRESS_TYPE_CCITT
CCITT protocols.
TDI_ADDRESS_TYPE_SNA
IBM SNA.
TDI_ADDRESS_TYPE_DECnet
DECnet.
TDI_ADDRESS_TYPE_DLI
Direct data-link interface (DLC).
TDI_ADDRESS_TYPE_LAT
LAT.
TDI_ADDRESS_TYPE_HYLINK
NSC Hyperchannel.
TDI_ADDRESS_TYPE_UNIX
Local to host, for pipes, portals, and so on
TDI_ADDRESS_TYPE_UNSPEC
Unspecified type.
Address
Specifies a variable-sized array containing the transport address. The structure of the contents depends on the specified AddressType.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

A TRANSPORT_ADDRESS structure contains a specified number of elements of type TA_ADDRESS.

For certain TDI_ADDRESS_TYPE_XXX values, transports and their kernel-mode clients can use system-defined substructures for Address and corresponding TDI_ADDRESS_LENGTH_XXX constants for AddressLength.

For convenience, TDI defines TA_ADDRESS_XXX structures that specify a single address of certain TDI_ADDRESS_TYPE_XXX types.

See Also

TDI_ADDRESS_8022, TDI_ADDRESS_APPLETALK, TDI_ADDRESS_IP, TDI_ADDRESS_IPX, TDI_ADDRESS_NETBIOS, TDI_ADDRESS_NETBIOS_EX, TDI_ADDRESS_NETONE, TDI_ADDRESS_NS, TDI_ADDRESS_OSI_TSAP, TDI_ADDRESS_VNS, TRANSPORT_ADDRESS


TA_APPLETALK_ADDR

The TA_APPLETALK_ADDR structure contains a single AppleTalk transport address, suitable for use as a TRANSPORT_ADDRESS.

typedef struct _TA_APPLETALK_ADDR {
  LONG  TAAddressCount;
  struct  _AddrAtalk {
    USHORT  AddressLength;
    USHORT  AddressType;
    TDI_ADDRESS_APPLETALK  Address[1];
  } Address [1];
} TA_APPLETALK_ADDRESS, *PTA_APPLETALK_ADDRESS;

Members

TAAddressCount
Specifies one.
AddressLength
Specifies the length (4 bytes) of an AppleTalk address.
AddressType
Specifies TDI_ADDRESS_TYPE_APPLETALK.
Address
Specifies a single address of type TDI_ADDRESS_APPLETALK.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

TDI defines this structure for convenience in situations requiring a single TDI_ADDRESS of type TDI_ADDRESS_TYPE_APPLETALK.

See Also

TA_ADDRESS, TDI_ADDRESS_APPLETALK, TRANSPORT_ADDRESS


TA_IP_ADDRESS

The TA_IP_ADDRESS structure contains a single IP transport address, suitable for use as a TRANSPORT_ADDRESS.

typedef struct _TA_ADDRESS_IP {
    LONG  TAAddressCount;
    struct  _AddrIp {
        USHORT          AddressLength;
        USHORT          AddressType;
        TDI_ADDRESS_IP  Address[1];
    } Address [1];
} TA_IP_ADDRESS, *PTA_IP_ADDRESS;

Members

TAAddressCount
Specifies one.
Address
Specifies a single address of a structure with the following members:
AddressLength
Specifies the length (14 bytes) of an IP address.
AddressType
Specifies TDI_ADDRESS_TYPE_IP.
Address
Specifies a single address of type TDI_ADDRESS_IP.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

TDI defines this structure for convenience in situations requiring a single TDI_ADDRESS of type TDI_ADDRESS_TYPE_IP.

See Also

TA_ADDRESS, TDI_ADDRESS_IP, TRANSPORT_ADDRESS


TA_IPX_ADDRESS

The TA_IPX_ADDRESS structure contains a single IPX transport address, suitable for use as a TRANSPORT_ADDRESS.

typedef struct _TA_ADDRESS_IPX {
    LONG  TAAddressCount;
    struct  _AddrIpx {
        USHORT           AddressLength;
        USHORT           AddressType;
        TDI_ADDRESS_IPX  Address[1];
    } Address [1];
} TA_IPX_ADDRESS, *PTA_IPX_ADDRESS;

Members

TAAddressCount
Specifies one.
Address
Specifies a single address of a structure with the following members:
AddressLength
Specifies the length (12 bytes) of an IPX address.
AddressType
Specifies TDI_ADDRESS_TYPE_IPX.
Address
Specifies a single address of type TDI_ADDRESS_IPX.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

TDI defines this structure for convenience in situations requiring a single TDI_ADDRESS of type TDI_ADDRESS_TYPE_IPX.

See Also

TA_ADDRESS, TDI_ADDRESS_IPX, TRANSPORT_ADDRESS


TA_NETBIOS_ADDRESS

The TA_NETBIOS_ADDRESS structure contains a single NetBIOS transport address, suitable for use as a TRANSPORT_ADDRESS.

typedef struct _TA_NETBIOS_ADDRESS {
    LONG  TAAddressCount;
    struct _Addr{
        USHORT               AddressLength;
        USHORT               AddressType;
        TDI_ADDRESS_NETBIOS  Address[1];
    } Address [1];
} TA_NETBIOS_ADDRESS, *PTA_NETBIOS_ADDRESS;

Members

TAAddressCount
Specifies one.
Address
Specifies a single address of a structure with the following members:
AddressLength
Specifies the length (18 bytes) of a NetBIOS address.
AddressType
Specifies TDI_ADDRESS_TYPE_NETBIOS.
Address
Specifies a single address of type TDI_ADDRESS_NETBIOS.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

TDI defines this structure for convenience in situations requiring a single TDI_ADDRESS of type TDI_ADDRESS_TYPE_NETBIOS.

See Also

TA_ADDRESS, TDI_ADDRESS_NETBIOS, TRANSPORT_ADDRESS


TA_NS_ADDRESS

The TA_NS_ADDRESS structure contains a single (X)NS transport address, suitable for use as a TRANSPORT_ADDRESS.

typedef struct _TA_ADDRESS_NS {
    LONG  TAAddressCount;
    struct  _AddrNs {
        USHORT          AddressLength;
        USHORT          AddressType;
        TDI_ADDRESS_NS  Address[1];
    } Address [1];
} TA_NS_ADDRESS, *PTA_NS_ADDRESS;

Members

TAAddressCount
Specifies one.
Address
Specifies a single address of a structure with the following members:
AddressLength
Specifies the length (12 bytes) of an NS address.
AddressType
Specifies TDI_ADDRESS_TYPE_NS.
Address
Specifies a single address of type TDI_ADDRESS_NS.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

TDI defines this structure for convenience in situations requiring a single TDI_ADDRESS of type TDI_ADDRESS_TYPE_NS.

See Also

TA_ADDRESS, TDI_ADDRESS_NS, TRANSPORT_ADDRESS


TA_VNS_ADDRESS

The TA_VNS_ADDRESS structure contains a single VNS transport address, suitable for use as a TRANSPORT_ADDRESS.

typedef struct _TA_ADDRESS_VNS {
    LONG  TAAddressCount;
    struct  _AddrVns {
        USHORT           AddressLength;
        USHORT           AddressType;
        TDI_ADDRESS_VNS  Address[1];
    } Address [1];
} TA_VNS_ADDRESS, *PTA_VNS_ADDRESS;

Members

TAAddressCount
Specifies one.
Address
Specifies a single address of a structure with the following members:
AddressLength
Specifies the length (14 bytes) of a VNS address.
AddressType
Specifies TDI_ADDRESS_TYPE_VNS.
Address
Specifies a single address of type TDI_ADDRESS_VNS.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

TDI defines this structure for convenience in situations requiring a single TDI_ADDRESS of type TDI_ADDRESS_TYPE_VNS.

See Also

TA_ADDRESS, TDI_ADDRESS_VNS, TRANSPORT_ADDRESS


TDI_ACTION_HEADER

The TDI_ACTION_HEADER structure is the initial structure in any client-supplied action parameter block passed in a TDI_ACTION request to the underlying transport driver.

typedef struct _TDI_ACTION_HEADER {
  ULONG  TransportId;
  USHORT  ActionCode;
  USHORT  Reserved;
} TDI_ACTION_HEADER, *PTDI_ACTION_HEADER;

Members

TransportId
Specifies a value identifying the TDI transport.

Any Microsoft-supplied transport defines an identifier as a 4-character string beginning with the letter "M." By convention, other transport vendors define their respective identifiers to begin with another letter.

ActionCode
Specifies the transport-defined action code, which must be unique to the transport driver designated by TransportId.
Reserved
Specifies a reserved member that must be set to zero.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

The remainder of an action parameter block is a transport-specific extension to the TDI interface. That is, the transport driver defines the structure and required contents for the remainder of the buffer that its kernel-mode clients must supply in each TDI_ACTION request.

See Also

TDI_ACTION, TdiBuildAction


TDI_ADDRESS_8022

The TDI_ADDRESS_8022 structure contains an 802.2 netcard–level address, packed and aligned correctly.

typedef struct _TDI_ADDRESS_8022 {
  UCHAR  MACAddress[6];
} TDI_ADDRESS_8022, *PTDI_ADDRESS_8022;

Members

MACAddress
Specifies a character array containing the address.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

A TRANSPORT_ADDRESS structure contains a specified number of elements of type TA_ADDRESS. TDI_ADDRESS_8022 defines the Address member of a TA_ADDRESS structure in which the AddressType is set to TDI_ADDRESS_TYPE_8022.

The AddressLength member(s) of the TA_ADDRESS substructure(s) can be set to the system-defined constant TDI_ADDRESS_LENGTH_8022.

See Also

TA_ADDRESS, TRANSPORT_ADDRESS


TDI_ADDRESS_APPLETALK

The DI_ADDRESS_APPLETALK structure contains an AppleTalk address, packed and aligned correctly.

typedef struct _TDI_ADDRESS_APPLETALK {
  USHORT  Network;
  UCHAR  Node;
  UCHAR  Socket;
} TDI_ADDRESS_APPLETALK, *PTDI_ADDRESS_APPLETALK;

Members

Network
Specifies the AppleTalk network identifier.
Node
Specifies the AppleTalk node identifier.
Socket
Specifies the AppleTalk socket identifier.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

A TRANSPORT_ADDRESS structure contains a specified number of elements of type TA_ADDRESS. TDI_ADDRESS_APPLETALK defines the Address member of a TA_ADDRESS structure in which the AddressType is set to TDI_ADDRESS_TYPE_APPLETALK.

The AddressLength member(s) of the TA_ADDRESS substructure(s) can be set to the system-defined constant TDI_ADDRESS_LENGTH_APPLETALK.

See Also

TA_ADDRESS, TA_APPLETALK_ADDR, TRANSPORT_ADDRESS


TDI_ADDRESS_INFO

The TDI_ADDRESS_INFO structure defines the structure of the information returned for a TDI_QUERY_INFORMATION request in which the IrpSp->Parameters.QueryType is set to TDI_QUERY_ADDRESS_INFO.

typedef struct _TDI_ADDRESS_INFO {
  ULONG  ActivityCount;
  TRANSPORT_ADDRESS  Address;
} TDI_ADDRESS_INFO, *PTDI_ADDRESS_INFO;

Members

ActivityCount
Specifies the number of kernel-mode clients that currently have open file objects representing the given transport address.
Address
Specifies a TRANSPORT_ADDRESS structure containing the transport address associated with a particular open file object.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

Each client process that calls ZwCreateFile successfully to open a particular transport address is given a handle to its own file object representing that address. Thus, a single transport address can have many associated file objects at any particular time.

Any kernel-mode client that has opened a particular transport address can make a query to determine how many other clients are currently using the same transport address. Such a client sets up an IRP with TdiBuildQueryInformation, passing in the QType TDI_QUERY_ADDRESS_INFO, and submits the IRP to the underlying transport to get this information.

TDI_ADDRESS_INFO defines the format in which the transport returns the requested information for such a query.

See Also

TdiBuildQueryInformation, TdiDispatchInternalDeviceControl, TDI_QUERY_INFORMATION, TRANSPORT_ADDRESS


TDI_ADDRESS_IP

The TDI_ADDRESS_IP structure contains an IP address, packed and aligned correctly.

typedef struct _TDI_ADDRESS_IP {
  USHORT  sin_port;
  ULONG  in_addr;
  UCHAR  sin_zero[8];
} TDI_ADDRESS_IP, *PTDI_ADDRESS_IP;

Members

sin_port
Specifies a TCP or UDP port number.
in_addr
Specifies the IP address.
sin_zero
Specifies an array filled with zeros.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

A TRANSPORT_ADDRESS structure contains a specified number of elements of type TA_ADDRESS. TDI_ADDRESS_IP defines the Address member of a TA_ADDRESS structure in which the AddressType is set to TDI_ADDRESS_TYPE_IP.

The AddressLength member(s) of the TA_ADDRESS substructure(s) can be set to the system-defined constant TDI_ADDRESS_LENGTH_IP.

See Also

TA_ADDRESS, TA_IP_ADDRESS, TRANSPORT_ADDRESS


TDI_ADDRESS_IPX

The TDI_ADDRESS_IPX structure contains an IPX address, packed and aligned correctly.

typedef struct _TDI_ADDRESS_IPX {
  ULONG  NetworkAddress;
  UCHAR  NodeAddress[6];
  USHORT  Socket;
} TDI_ADDRESS_IPX, *PTDI_ADDRESS_IPX;

Members

NetworkAddress
Specifies the IPX network address.
NodeAddress
Specifies the IPX node address.
Socket
Specifies the IPX socket identifier.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

A TRANSPORT_ADDRESS structure contains a specified number of elements of type TA_ADDRESS. TDI_ADDRESS_IPX defines the Address member of a TA_ADDRESS structure in which the AddressType is set to TDI_ADDRESS_TYPE_IPX.

The AddressLength member(s) of the TA_ADDRESS substructure(s) can be set to the system-defined constant TDI_ADDRESS_LENGTH_IPX.

See Also

TA_ADDRESS, TA_IPX_ADDRESS, TRANSPORT_ADDRESS


TDI_ADDRESS_NETBIOS

The TDI_ADDRESS_NETBIOS structure contains a NetBIOS address, packed and aligned correctly.

typedef struct _TDI_ADDRESS_NETBIOS {
  USHORT  NetbiosNameType;
  UCHAR  NetbiosName[16];
} TDI_ADDRESS_NETBIOS, *PTDI_ADDRESS_NETBIOS

Members

NetbiosNameType
Specifies a NetBIOS name type. A TDI transport uses this member only when a file object representing an address is opened. Otherwise, the transport can ignore this member. This member can be one of the following values:
TDI_NETBIOS_TYPE_UNIQUE
The value at NetbiosName is unique.
TDI_NETBIOS_TYPE_GROUP
The value at NetbiosName is a group name.
TDI_NETBIOS_TYPE_QUICK_UNIQUE
The value at NetbiosName is unique. The transport adds this name to its name table without checking for conflicts on the network.
TDI_NETBIOS_TYPE_QUICK_GROUP
The value at NetbiosName is a group name. The transport adds this name to its name table without checking for conflicts on the network.
NetbiosName
Specifies the NetBIOS name.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

A TRANSPORT_ADDRESS structure contains a specified number of elements of type TA_ADDRESS. TDI_ADDRESS_NETBIOS defines the Address member of a TA_ADDRESS structure in which the AddressType is set to TDI_ADDRESS_TYPE_NETBIOS.

The AddressLength member(s) of the TA_ADDRESS substructure(s) can be set to the system-defined constant TDI_ADDRESS_LENGTH_NETBIOS.

See Also

TA_ADDRESS, TA_NETBIOS_ADDRESS, TDI_ADDRESS_NETBIOS_EX, TdiDispatchCreate, TRANSPORT_ADDRESS


TDI_ADDRESS_NETBIOS_EX

The TDI_ADDRESS_NETBIOS_EX structure contains an extended NetBIOS address, packed and aligned correctly.

typedef struct _TDI_ADDRESS_NETBIOS_EX {
  UCHAR  EndpointName[16];
  TDI_ADDRESS_NETBIOS  NetbiosAddress;
} TDI_ADDRESS_NETBIOS_EX, *PTDI_ADDRESS_NETBIOS_EX;

Members

EndpointName
Specifies the name to be presented to the destination machine in the NETBIOS session-setup request packet.
NetbiosAddress
Specifies a NetBIOS address from which the local-node transport derives the transport address of the target remote node.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

A TRANSPORT_ADDRESS structure contains a specified number of elements of type TA_ADDRESS. TDI_ADDRESS_NETBIOS_EX defines the Address member of a TA_ADDRESS structure in which the AddressType is set to TDI_ADDRESS_TYPE_NETBIOS_EX.

The AddressLength member(s) of the TA_ADDRESS substructure(s) can be set to the system-defined constant TDI_ADDRESS_LENGTH_NETBIOS_EX.

This structure can be used by a kernel-mode client connecting to a NETBIOS service on a remote machine, assuming the underlying TDI transport supports this operation.

For example, suppose the registered name for the NETBIOS service on a remote machine is "FooService" and the DNS name for the remote machine is something like "MyRemoteMachine.Microsoft.com." Such a client could use a TDI_ADDRESS_NETBIOS_EX structure in which EndpointName was set to FooService and NetbiosAddress was set to MyRemoteMachine.Microsoft.com when the client issued the TDI_CONNECT request to its underlying transport.

The system-supplied NETBT (NetBIOS over TCP/IP) transport uses the TDI_ADDRESS_NETBIOS_EX structure in this manner to support the SMB file server/redirector.

See Also

TA_ADDRESS, TA_NETBIOS_ADDRESS, TDI_ADDRESS_NETBIOS, TRANSPORT_ADDRESS


TDI_ADDRESS_NETONE

The TDI_ADDRESS_NETONE structure contains a Net/One address, packed and aligned correctly.

typedef struct _TDI_ADDRESS_NETONE {
  USHORT  NetoneNameType;
  UCHAR  NetoneName[20];
} TDI_ADDRESS_NETONE, *PTDI_ADDRESS_NETONE;

Members

NetoneNameType
Specifies a Net/One name type as one of the following:
TDI_ADDRESS_NETONE_TYPE_UNIQUE
A unique name.
TDI_ADDRESS_NETONE_TYPE_ROTORED
A rotored name.
NetoneName
Specifies the Net/One name.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

A TRANSPORT_ADDRESS structure contains a specified number of elements of type TA_ADDRESS. TDI_ADDRESS_NETONE defines the Address member of a TA_ADDRESS structure in which the AddressType is set to TDI_ADDRESS_TYPE_NETONE.

The AddressLength member(s) of the TA_ADDRESS substructure(s) can be set to the system-defined constant TDI_ADDRESS_LENGTH_NETONE.

See Also

TA_ADDRESS, TRANSPORT_ADDRESS


TDI_ADDRESS_NS

The TDI_ADDRESS_NS structure contains a XEROX (X)NS address, packed and aligned correctly.

typedef struct _TDI_ADDRESS_NS {
  ULONG  NetworkAddress;
  UCHAR  NodeAddress[6];
  USHORT  Socket;
} TDI_ADDRESS_NS, *PTDI_ADDRESS_NS;

Members

NetworkAddress
Specifies the NS network address.
NodeAddress
Specifies the NS node address.
Socket
Specifies the NS socket identifier.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

A TRANSPORT_ADDRESS structure contains a specified number of elements of type TA_ADDRESS. TDI_ADDRESS_NS defines the Address member of a TA_ADDRESS structure in which the AddressType is set to TDI_ADDRESS_TYPE_NS.

The AddressLength member(s) of the TA_ADDRESS substructure(s) can be set to the system-defined constant TDI_ADDRESS_LENGTH_NS.

See Also

TA_ADDRESS, TA_NS_ADDRESS, TRANSPORT_ADDRESS


TDI_ADDRESS_OSI_TSAP

The TDI_ADDRESS_OSI_TSAP structure contains an ISO TP4-compliant TSAP address, packed and aligned correctly.

tyepdef struct _TDI_ADDRESS_OSI_TSAP {
  USHORT  tp_addr_type;
  USHORT  tp_taddr_len;
  USHORT  tp_tsel_len;
  UCHAR  tp_addr[ISO_MAX_ADDR_LENGTH];
} TDI_ADDRESS_OSI_TSAP, *PTDI_ADDRESS_OSI_TSAP;

Members

tp_addr_type
Specifies the type of the address, as one of the following:
ISO_HIERARCHICAL
The tp_addr contains both the transport selector and the network address.
ISO_NON_HIERARCHICAL
The tp_addr contains only the transport address. Such a specification must be translated into the transport selector and network address.
tp_taddr_len
Specifies the size in bytes of the transport address, which is <= 52 if tp_addr_type is ISO_NON_HIERARCHICAL or <= 32 otherwise.
tp_tsel_len
Specifies the size in bytes of the transport selector (<= 32) if tp_addr_type is ISO_HIERARCHICAL. Otherwise, this member is zero.
tp_addr
Specifies the address according to the given tp_addr_type. This member can be at most 64 bytes in length.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

A TRANSPORT_ADDRESS structure contains a specified number of elements of type TA_ADDRESS. TDI_ADDRESS_OSI_TSAP defines the Address member of a TA_ADDRESS structure in which the AddressType is set to TDI_ADDRESS_TYPE_OSI_TSAP.

The AddressLength member(s) of the TA_ADDRESS substructure(s) can be set to the system-defined constant TDI_ADDRESS_LENGTH_OSI_TSAP.

See Also

TA_ADDRESS, TRANSPORT_ADDRESS


TDI_ADDRESS_VNS

The TDI_ADDRESS_VNS structure contains a Banyan VINES IP address, packed and aligned correctly.

tyepdef struct _TDI_ADDRESS_VNS {
  UCHAR  net_address[4];
  UCHAR  subnet_addr[2];
  UCHAR  port[2];
  UCHAR  hops;
  UCHAR  filler[5];
} TDI_ADDRESS_VNS, *PTDI_ADDRESS_VNS;

Members

net_address
Specifies the network address, which is static.
subnet_addr
Specifies the subnet address, which is dynamic.
port
Specifies the port number.
hops
Specifies the limit on hops for broadcasts.
filler
Filled with zeros.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

A TRANSPORT_ADDRESS structure contains a specified number of elements of type TA_ADDRESS. TDI_ADDRESS_VNS defines the Address member of a TA_ADDRESS structure in which the AddressType is set to TDI_ADDRESS_TYPE_VNS.

The AddressLength member(s) of the TA_ADDRESS substructure(s) can be set to the system-defined constant TDI_ADDRESS_LENGTH_VNS.

See Also

TA_ADDRESS, TA_VNS_ADDRESS, TRANSPORT_ADDRESS


TDI_CONNECTION_INFO

The TDI_CONNECTION_INFO structure defines the structure of the information returned for a TDI_QUERY_INFORMATION request in which IrpSp->Parameters is cast to a pointer to a TDI_REQUEST_KERNEL_QUERY_INFORMATION structure. The request sets the QueryType member of TDI_REQUEST_KERNEL_QUERY_INFORMATION to the TDI_QUERY_CONNECTION_INFO query type.

typedef struct _TDI_CONNECTION_INFO {
  ULONG  State;
  ULONG  Event;
  ULONG  TransmittedTsdus;
  ULONG  ReceivedTsdus;
  ULONG  TransmissionErrors;
  ULONG  ReceiveErrors;
  LARGE_INTEGER  Throughput;
  LARGE_INTEGER  Delay;
  ULONG  SendBufferSize;
  ULONG  ReceiveBufferSize;
  BOOLEAN  Unreliable;
} TDI_CONNECTION_INFO, *PTDI_CONNECTION_INFO;

Members

State
Specifies the current state of the connection on the network.
Event
Specifies the type of event the TDI driver most recently indicated to the client. The value is expressed as a TDI_EVENT_XXX code.
TransmittedTsdus
Specifies the number of TSDUs transmitted on the connection endpoint.
ReceivedTsdus
Specifies the number of TSDUs received on the connection endpoint.
TransmissionErrors
Specifies the number of TSDUs that have had an error during transmission on the connection endpoint.
ReceiveErrors
Specifies the number of TSDUs that have had an error during reception on the connection endpoint.
Throughput
Specifies the estimated throughput on the connection, expressed in bytes per second, for sends and receives. Zero indicates that the driver cannot calculate the throughput.
Delay
Specifies the estimated delay on the connection, expressed as a negative value. Delay, which is essentially constant regardless of packet size, affects the transmission time of each TSDU sent to the remote node.
SendBufferSize
If the transport buffers sends internally, specifies the size in bytes of its send buffer. Otherwise, this member is zero.
ReceiveBufferSize
If the transport buffers receives internally, specifies the size in bytes of its receive buffer. Otherwise, this member is zero.
Unreliable
Specifies TRUE if the transport determines that the connection has become unreliable. The transport is likely to send a disconnection event to its client if this member is TRUE, and sends or receives on this connection are likely to fail.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

A kernel-mode client that has opened a file object representing a connection with ZwCreateFile can make a query to determine the current state of its local connection. Such a client sets up an IRP with TdiBuildQueryInformation, passing in the QType TDI_QUERY_CONNECTION_INFO, and submits the IRP to the underlying transport to get this information.

TDI_CONNECTION_INFO defines the format in which the transport returns the requested information for such a query.

Until a client has established an endpoint-to-endpoint connection with a remote-node peer, only a subset of this information is potentially useful to the client, such as the SendBufferSize and ReceiveBufferSize of an underlying transport that supports internal buffering. A TDI transport can simply return its default or initialization values for members that are not yet relevant or even fail the query-information request if an endpoint-to-endpoint connection is not yet established.

Consequently, kernel-mode clients usually submit this request to their transports after making an endpoint-to-endpoint connection with a remote-node peer. For example, the client can estimate the transmission time for sends over the network using the Delay and Throughput values returned for this query, assuming the underlying transport does not return a zero for either. The estimated time to transmit a TSDU of size n bytes can be calculated as SendTime = Delay + (n * Throughput).

See Also

TdiBuildQueryInformation, TdiDispatchInternalDeviceControl, TDI_QUERY_INFORMATION


TDI_CONNECTION_INFORMATION

The TDI_CONNECTION_INFORMATION structure defines the structure of information that a kernel-mode client passes to or receives from the underlying transport for a subset of the TDI_XXX internal-device-control requests, particularly those relevant to endpoint-to-endpoint connections.

typedef struct _TDI_CONNECTION_INFORMATION {
  LONG  UserDataLength;
  PVOID  UserData;
  LONG  OptionsLength;
  PVOID  Options;
  LONG  RemoteAddressLength;
  PVOID  RemoteAddress;
} TDI_CONNECTION_INFORMATION, *PTDI_CONNECTION_INFORMATION;

Members

UserDataLength
Specifies the size in bytes of the buffer at UserData or zero if UserData is NULL.
UserData
Pointer to client-supplied buffer for user data, generally sent or received when an endpoint-to-endpoint connection is being established or, possibly, disconnected.
OptionsLength
Specifies the size in bytes of the buffer at Options.
Options
Pointer to a client-supplied buffer, either containing client-supplied data or awaiting transport-returned data for the given IOCTL request.
RemoteAddressLength
Specifies the size in bytes of the buffer at RemoteAddress.
RemoteAddress
Pointer to a buffer containing a remote-node transport address either specified by the client or returned by the transport to the client. The syntax of this address depends on the type of network and/or the underlying transport (see TA_ADDRESS).

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

While several TdiBuild Xxx macros and the corresponding TDI_XXX IOCTL requests use this structure to pass information between TDI transports and their clients, each does not use every member of the TDI_CONNECTION_INFORMATION structure.

As a general rule, a transport does not return any information in this structure if it returns STATUS_PENDING for a given IOCTL request. Instead, the driver defers setting the data in this structure until just before it completes the IRP.

Supplying and Receiving UserData

After an endpoint-to-endpoint connection is established, a local-node client can send TSDUs to its remote-node peer by submitting TDI_SEND requests to the underlying transport. The local-node client can either receive TSDUs from its remote-node peer by submitting TDI_RECEIVE requests or through calls to its registered ClientEvent(Chained)Receive(Expedited) handlers.

However, until such a connection is established, two TDI clients in the process of establishing an endpoint-to-endpoint connection can send data to each other by supplying it in a buffer at UserData with their TDI_CONNECT, TDI_LISTEN, and, possibly, TDI_ACCEPT requests to their respective underlying transports. In a similar manner, two such clients also can supply disconnection data to each other in the process of controlled-disconnect operation, assuming their respective transports support controlled disconnections.

A client can determine the transport-specific limit on the amount of user data by submitting a query-information request, set up with TdiBuildQueryInformation for the QType TDI_QUERY_PROVIDER_INFO.

When the client can send user data with a particular TDI IOCTL request, a UserDataLength set to zero implies that the client has provided no user data in its request to the transport. When the client can receive user data with a particular TDI IOCTL request, a UserDataLength set to zero implies that the transport returned no data in the buffer at UserData. Otherwise, the transport sets UserDataLength to the number of bytes of data it received for the client.

If the client specifies a nonzero UserDataLength and the transport receives more data from the remote node than it can fit into the client-supplied buffer, the transport returns as much data as it can in the client's buffer. In this case, the transport completes the operation normally but returns a status indicating data truncation to its client.

UserDataLength must be zero and UserData must NULL for the following TDI_XXX IOCTL requests:

TDI_RECEIVE_DATAGRAM and TDI_SEND_DATAGRAM
The TDI_CONNECTION_INFORMATION structure is used only to specify the remote-node address for these requests.
TDI_LISTEN if the client requests a delayed-connection acceptance
Such a client can supply any necessary user data with its subsequent TDI_ACCEPT request when it accepts a connection offer from a remote-node peer.

When the transport does not allow its clients to supply user data for a particular TDI IOCTL request, the transport fails all such requests in which a client specifies a nonzero UserDataLength.

Using Options and OptionsLength

For a TDI_LISTEN request, the OptionsLength is either zero or sizeof(ULONG) if the client set TDI_QUERY_ACCEPT in the Flags parameter to TdiBuildListen, and Options is either NULL or the buffer contains TDI_QUERY_ACCEPT.

Except for the TDI_LISTEN request, the transport defines the syntax and semantics of any additional options it supports for its clients, usually along the following lines:

  • When a client can supply transport-specific information at Options, setting OptionsLength to zero implies that the underlying driver can use its default values for options. When the transport can return information at Options, setting OptionsLength to zero implies that the client would not use the returned data so the transport should ignore Options.
  • If such a client sets OptionsLength to a nonzero value, but the transport receives an option string too large for the client-supplied buffer, the transport truncates the options string and completes the client's request normally with a status that indicates data truncation occurred.
  • When the client of such a transport uses Options to specify option values for the driver to transfer, the values the driver actually writes can be different from the client-specified values.

Using RemoteAddress and RemoteAddressLength

Use of these members depends on the TDI_XXX IOCTL and on the size of the transport-specific address. In general, a local-node client uses RemoteAddress to specify the target remote-node address when it initiates network-transfer operations, such as connection offers and sends. The transport returns information to RemoteAddress when such an operation was initiated at the remote node, such as to satisfy listen and receive requests.

If the client specifies zero for RemoteAddressLength, the transport assumes RemoteAddress is NULL. If the client specifies a nonzero value for RemoteAddressLength but the transport has received an address too long for the client-supplied buffer, the driver function truncates the address to fit in the client's buffer. In this case, the transport completes the operation normally but returns a status code indicating data truncation to the client.

See Also

TA_ADDRESS, TDI_ACCEPT, TdiBuildQueryInformation, TDI_CONNECT, TDI_DISCONNECT, TDI_LISTEN, TDI_RECEIVE_DATAGRAM, TDI_SEND_DATAGRAM, TDI_SET_INFORMATION


TDI_DATAGRAM_INFO

The TDI_DATAGRAM_INFO structure defines the structure of the information returned for a TDI_QUERY_INFORMATION request in which IrpSp->Parameters is cast to a pointer to a TDI_REQUEST_KERNEL_QUERY_INFORMATION structure. The request sets the QueryType member of TDI_REQUEST_KERNEL_QUERY_INFORMATION to the TDI_QUERY_DATAGRAM_INFO query type.

typedef struct _TDI_DATAGRAM_INFO {
  ULONG  MaximumDatagramBytes;
  ULONG  MaximumDatagramCount;
} TDI_DATAGRAM_INFO, *PTDI_DATAGRAM_INFO;

Members

MaximumDatagramBytes
Specifies the maximum size in bytes for a datagram.
MaximumDatagramCount
Specifies the maximum number of active datagrams.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

Any kernel-mode client that has opened a control channel can make a query to determine the transport's limits on datagram size and activity. Such a client sets up an IRP with TdiBuildQueryInformation, passing in the QType TDI_QUERY_DATAGRAM_INFO, and submits the IRP to the underlying transport to get this information.

A transport also can support this query on open transport addresses at the discretion of the transport writer.

TDI_DATAGRAM_INFO defines the format in which the transport returns the requested information for such a query.

See Also

TdiBuildQueryInformation, TdiDispatchInternalDeviceControl, TDI_MAX_DATAGRAM_INFO, TDI_QUERY_INFORMATION, TDI_PROVIDER_INFO, TRANSPORT_ADDRESS


TDI_MAX_DATAGRAM_INFO

The TDI_MAX_DATAGRAM_INFO structure defines the structure of the information returned for a TDI_QUERY_INFORMATION request in which IrpSp->Parameters is cast to a pointer to a TDI_REQUEST_KERNEL_QUERY_INFORMATION structure. The request sets the QueryType member of TDI_REQUEST_KERNEL_QUERY_INFORMATION to the TDI_QUERY_MAX_DATAGRAM_INFO query type.

typedef struct _TDI_DATAGRAM_INFO {
  ULONG  MaxDatagramSize;
} TDI_DATAGRAM_INFO, *PTDI_DATAGRAM_INFO;

Member

MaxDatagramSize
Specifies the maximum number of bytes for a datagram.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

Any kernel-mode client that has opened a control channel can make a query to determine the transport's limits on datagram size. Such a client sets up an IRP with TdiBuildQueryInformation, passing in the QType TDI_QUERY_MAX_DATAGRAM_INFO, and submits the IRP to the underlying transport to get this information.

A transport also can support this query on open transport addresses at the discretion of the transport writer.

TDI_MAX_DATAGRAM_INFO defines the format in which the transport returns the requested information for such a query.

See Also

TdiBuildQueryInformation, TdiDispatchInternalDeviceControl, TDI_DATAGRAM_INFO, TDI_QUERY_INFORMATION, TDI_PROVIDER_INFO, TRANSPORT_ADDRESS


TDI_PNP_CONTEXT

The TDI_PNP_CONTEXT structure defines the structure of buffered information passed to transport clients that register themselves with TdiRegisterPnPHandlers to receive notifications of PnP (binding) and power-state changes, as well as dynamic notifications of net address additions and deletions.

struct _TDI_PNP_CONTEXT {
  USHORT  ContextSize;
  USHORT  ContextType;
  UCHAR  ContextData[1];
} TDI_PNP_CONTEXT, *PTDI_PNP_CONTEXT;

Members

ContextSize
Specifies the size in bytes of the buffered data, including the variable-sized array of bytes at ContextData.
ContextType
Specifies the type of information at ContextData as one of the following values:
TDI_PNP_CONTEXT_TYPE_IF_NAME
The buffered data is a protocol-supplied device (or interface) name, such as the name of an underlying device object on which a new network address just arrived or was closed.
TDI_PNP_CONTEXT_TYPE_IF_ADDRESS
The buffered data is a protocol-supplied address, such as a list of net addresses associated with the underlying device to which both the transport and client are bound.
TDI_PNP_CONTEXT_TYPE_PDO
The buffered data is a protocol-supplied pointer to the physical device object representing the underlying NIC to which both the transport and client are bound.
TDI_PNP_CONTEXT_TYPE_FIRST_OR_LAST_IF
The buffered data is any protocol-supplied information for an adapter that supports the transport. In effect, the client is indifferent to the specifics of the transport interface(s), as long as the transport to which the client is bound is supported by at least one underlying NIC.
ContextData
Contains the buffered data for this notification to the client.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

The information passed in this structure is both context-dependent, as indicated by the ContextType value, and protocol-dependent. For example, when TCP/IP notifies its clients of new net addresses by calling TdiRegisterNetAddress, it passes a pointer to a TDI_PNP_CONTEXT_TYPE_PDO record as the Context argument. However, the registered ClientAddNetAddress functions of clients bound to any other transport stack are not necessarily called with an input Context pointer to the same type of TDI_PNP_CONTEXT record.

See Also

ClientPnPAddNetAddress, ClientPnPDelNetAddress, ClientPnPBindingChange, ClientPnPPowerChange, NET_PNP_EVENT, TdiPnPPowerRequest, TdiRegisterNetAddress


TDI_PROVIDER_INFO

The TDI_PROVIDER_INFO structure defines the structure of the information returned for a TDI_QUERY_INFORMATION request in which IrpSp->Parameters is cast to a pointer to a TDI_REQUEST_KERNEL_QUERY_INFORMATION structure. The request sets the QueryType member of TDI_REQUEST_KERNEL_QUERY_INFORMATION to the TDI_QUERY_PROVIDER_INFO or TDI_QUERY_PROVIDER_INFORMATION query type.

struct _TDI_PROVIDER_INFO {
  ULONG  Version;
  ULONG  MaxSendSize;
  ULONG  MaxConnectionUserData;
  ULONG  MaxDatagramSize;
  ULONG  ServiceFlags;
  ULONG  MinimumLookaheadData;
  ULONG  MaximumLookaheadData;
  ULONG  NumberOfResources;
  LARGE_INTEGER  StartTime;
} TDI_PROVIDER_INFO, *PTDI_PROVIDER_INFO;

Members

Version
Specifies the TDI version number. The low-order bytes specify the minor version number, and the high-order bytes the major version number.

For the current release of TDI, the version number is 0x0200.

MaxSendSize
Specifies the maximum number of bytes a client can provide per TDI_SEND request.
MaxConnectionUserData
Specifies the maximum number of bytes a client can provide as user data in a TDI_CONNECT, TDI_LISTEN, or TDI_ACCEPT request.
MaxDatagramSize
Specifies the maximum size, in bytes, of a datagram a client can send (or receive).
ServiceFlags
Specifies features that the transport offers as a combination (Ored) of the following flags:
TDI_SERVICE_CONNECTION_MODE
This transport supports connection-oriented traffic (endpoint-to-endpoint transfers).
TDI_SERVICE_CONNECTIONLESS_MODE
This transport supports connectionless traffic (datagram sends and receives).
TDI_SERVICE_BROADCAST_SUPPORTED
This transport supports broadcast datagrams.
TDI_SERVICE_MULTICAST_SUPPORTED
This transport supports multicast datagrams.
TDI_SERVICE_ROUTE_DIRECTED
This transport supports directed packets, which can reach remote nodes that datagrams cannot reach.
TDI_SERVICE_ORDERLY_RELEASE
This transport supports controlled disconnects.
TDI_SERVICE_DELAYED_ACCEPTANCE
This transport supports delayed-connection acceptances of incoming connection offers from remote nodes.
TDI_SERVICE_EXPEDITED_DATA
This transport supports expedited sends and receives.
TDI_SERVICE_INTERNAL_BUFFERING
This transport buffers TSDUs internally.
TDI_SERVICE_MESSAGE_MODE
This transport supports message-mode sends and receives.
TDI_SERVICE_NO_ZERO_LENGTH
This transport does not support zero-length sends.
TDI_SERVICE_ERROR_FREE_DELIVERY
This transport supports error-free delivery.
TDI_SERVICE_POINT_TO_POINT
This transport is bound to an underlying point-to-point WAN NIC driver of type NdisMediumWan.
TDI_SERVICE_SECURITY_LEVEL
This transport supports a security validator.
TDI_SERVICE_HALF_DUPLEX
This transport supports controlled disconnect operations such that after receiving a disconnect request from the remote node, it continues to indicate receives to the local-node client until its client also acknowledges the disconnection.
TDI_SERVICE_DGRAM_CONNECTION
This transport supports pseudo-datagram connections to handle QoS, GPC, and so forth.
MinimumLookaheadData
Specifies the lower limit on the number of bytes this transport guarantees to indicate as lookahead data for receive and receive-datagram events.
MaximumLookaheadData
Specifies the upper limit on the number of bytes this transport guarantees to indicate as lookhead data for receive and receive-datagram events. If the underlying NIC driver supports multipacket receive indications, this value can be the maximum packet size supported by the network.
NumberOfResources
Specifies the number of TDI_PROVIDER_RESOURCE_STATS structures (resources) this transport returns if a client submits a query-information request of the type TDI_QUERY_PROVIDER_STATISTICS.
StartTime
Specifies the current system time at which the TDI driver became active.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

Any kernel-mode client that has opened a control channel can make a query to determine the supported features and limits of its underlying transport. Such a client sets up an IRP with TdiBuildQueryInformation, passing in the QType TDI_QUERY_PROVIDER_INFO, and submits the IRP to the underlying transport to get this information.

TDI_PROVIDER_INFO defines the format in which the transport returns the requested information for such a query.

For example, a client might use the values returned in the Xxx LookaheadData and NumberOfResources members to size client-allocated buffers for subsequent client requests to the transport or to allocate buffers of an appropriate size before it registers ClientEvent(Chained)Receive and/or ClientEvent(Chained)ReceiveDatagram handlers.

See Also

ClientEventChainedReceive, ClientEventChainedReceiveDatagram, ClientEventChainedReceiveExpedited, ClientEventReceive, ClientEventReceiveDatagram, ClientEventReceiveExpedited, TdiBuildQueryInformation, TdiBuildSetEventHandler, TDI_ACCEPT, TDI_CONNECT, TDI_LISTEN, TDI_QUERY_INFORMATION, TDI_PROVIDER_STATISTICS


TDI_PROVIDER_STATISTICS

The TDI_PROVIDER_STATISTICS structure defines the structure of the information returned for a TDI_QUERY_INFORMATION request in which IrpSp->Parameters is cast to a pointer to a TDI_REQUEST_KERNEL_QUERY_INFORMATION structure. The request sets the QueryType member of TDI_REQUEST_KERNEL_QUERY_INFORMATION to the TDI_QUERY_PROVIDER_STATISTICS query type.

struct _TDI_PROVIDER_STATISTICS {
  ULONG  Version;
  ULONG  OpenConnections;
  ULONG  ConnectionsAfterNoRetry;
  ULONG  ConnectionsAfterRetry;
  ULONG  LocalDisconnects;
  ULONG  RemoteDisconnects;
  ULONG  LinkFailures;
  ULONG  AdapterFailures;
  ULONG  SessionTimeouts;
  ULONG  CancelledConnections;
  ULONG  RemoteResourceFailures;
  ULONG  LocalResourceFailures;
  ULONG  NotFoundFailures;
  ULONG  NoListenFailures;
  ULONG  DatagramsSent;
  LARGE_INTEGER  DatagramBytesSent;
  ULONG  DatagramsReceived;
  LARGE_INTEGER  DatagramBytesReceived;
  ULONG  PacketsSent;
  ULONG  PacketsReceived;
  ULONG  DataFramesSent;
  LARGE_INTEGER  DataFrameBytesSent;
  ULONG  DataFramesReceived;
  LARGE_INTEGER  DataFrameBytesReceived;
  ULONG  DataFramesResent;
  LARGE_INTEGER  DataFrameBytesResent;
  ULONG  DataFramesRejected;
  LARGE_INTEGER  DataFrameBytesRejected;
  ULONG  ResponseTimerExpirations;
  ULONG  AckTimerExpirations;
  ULONG  MaximumSendWindow;
  ULONG  AverageSendWindow;
  ULONG  PiggybackAckQueued;
  ULONG  PiggybackAckTimeouts;
  LARGE_INTEGER  WastedPacketSpace;
  ULONG  WastedSpacePackets;
  ULONG  NumberOfResources;
  TDI_PROVIDER_RESOURCE_STATS  Resources[1];
} TDI_PROVIDER_STATISTICS, *PTDI_PROVIDER_STATISTICS;

Members

Version
Specifies the TDI version number. The low-order bytes specify the minor version number, and the high-order bytes the major version number.
OpenConnections
Specifies the number of open connection endpoints in the transport.
ConnectionsAfterNoRetry
Specifies the number of connections the transport has established with remote-node clients without doing frame retransmissions.
ConnectionsAfterRetry
Specifies the number of connections the transport has established with remote node clients after doing some frame retransmissions.
LocalDisconnects
Specifies the number of endpoint-to-endpoint connections that the transport's local-node clients have closed.
RemoteDisconnects
Specifies the number of endpoint-to-endpoint connections that remote-node clients have closed.
LinkFailures
Specifies the number of connections lost due to link-level failures.
AdapterFailures
Specifies the number of connections lost due to problems in the underlying NIC driver.
SessionTimeouts
Specifies the number of connections lost due to session-level time-outs.
CancelledConnections
Specifies the number of rejected connection offers.
RemoteResourceFailures
Specifies the number of connections that have failed due to resource problems at a remote node.
LocalResourceFailures
Specifies the number of connections that have failed due to local-node resource problems.
NotFoundFailures
Specifies the number of connection attempts that have failed because the transport could not find the specified remote node on the network.
NoListenFailures
Specifies the number of incoming connection offers failed because local-node clients were not listening for incoming connections.
DatagramsSent
Specifies the number of datagrams the TDI transport has sent.
DatagramBytesSent
Specifies the number of bytes in all datagrams the transport has sent.
DatagramsReceived
Specifies the number of datagrams the TDI transport has received.
DatagramBytesReceived
Specifies the number of bytes in all datagrams the transport has received.
PacketsSent
Specifies the number of packets, including control, data, and other frames, the transport has sent through NDIS to the physical medium.
PacketsReceived
Specifies the number of packets, including control, data, and other frames, the transport has received from the physical medium through NDIS.
DataFramesSent
Specifies the number of data frames the underlying NDIS NIC driver has sent.
DataFrameBytesSent
Specifies the number of bytes of frame data the underlying NDIS NIC driver has sent.
DataFramesReceived
Specifies the number of data frames the underlying NDIS NIC driver has received.
DataFrameBytesReceived
Specifies the number of bytes of frame data the underlying NDIS NIC driver has received.
DataFramesResent
Specifies the number of data frames the underlying NDIS NIC driver has re-sent.
DataFrameBytesResent
Specifies the number of bytes of frame data the underlying NDIS NIC driver has re-sent.
DataFramesRejected
Specifies the number of data frames the underlying NDIS NIC driver has received but rejected.
DataFrameBytesRejected
Specifies the number of bytes of frame data the underlying NDIS NIC driver has received but rejected.
ResponseTimerExpirations
Specifies the number of times the response timer (for example, T1 for NetBIOS) has expired.
AckTimerExpirations
Specifies the number of times the acknowledgment timer (for example, T2 for NetBIOS) has expired.
MaximumSendWindow
Specifies the maximum send window, in bytes, of the transport.
AverageSendWindow
Specifies the average send window, in bytes, of the transport.
PiggybackAckQueued
Specifies the number of times the transport has started a timer waiting for reverse traffic on which it can piggyback a data acknowledgment to a remote node.
PiggybackAckTimeouts
Specifies the number of times a piggyback acknowledgment timer has expired before the transport could send reverse traffic to a remote node.
WastedPacketSpace
Specifies the total number of bytes of wasted buffer space for transferred packets.
WastedSpacePackets
Specifies how many packets contributed to the value of WastedPacketSpace.
NumberOfResources
Specifies the number of elements of type TDI_PROVIDER_RESOURCE_STATS in the array at Resources.
Resources
Specifies an array of TDI_PROVIDER_RESOURCE_STATS structures, each defined as follows:
struct _TDI_PROVIDER_RESOURCE_STATS {
    ULONG ResourceId;
    ULONG MaximumResourceUsed;
    ULONG AverageResourceUsed;
    ULONG ResourceExhausted;
} TDI_PROVIDER_RESOURCE_STATS, *PTDI_PROVIDER_RESOURCE_STATS;
ResourceId
Specifies a transport-specific value identifying a resource.
MaximumResourceUsed
Specifies the maximum number of resources of the specified type the transport can use concurrently.
AverageResourceUsed
Specifies the average number of resources of the specified type the transport uses overall.
ResourceExhausted
Specifies the number of times the transport has failed to allocate the specified resource.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

Any kernel-mode client that has opened a control channel can make a query to determine the current statistics maintained by its underlying transport. Such a client sets up an IRP with TdiBuildQueryInformation, passing in the QType TDI_QUERY_PROVIDER_STATISTICS, and submits the IRP to the underlying transport to get this information.

TDI_PROVIDER_STATISTICS defines the format in which the transport returns the requested information for such a query.

See Also

TdiBuildQueryInformation, TDI_QUERY_INFORMATION, TDI_PROVIDER_INFO


TDI_REQUEST

The TDI_REQUEST structure contains information common to most TDI requests. This structure can be used by transport drivers to pass request-specific information between internal driver routines.

typedef struct _TDI_REQUEST {
    union {
        HANDLE              AddressHandle;
        CONNECTION_CONTEXT  ConnectionContext;
        HANDLE              ControlChannel;
    } Handle;
    PVOID      RequestNotifyObject;
    PVOID      RequestContext;
    TDI_STATUS TdiStatus;
} TDI_REQUEST, *PTDI_REQUEST;

Members

AddressHandle
Specifies the handle to an open file object representing an address.
ConnectionContext
Specifies the client-supplied context associated with an open file object representing a connection endpoint.
ControlChannel
Specifies the handle to an open file object representing a control channel.
RequestNotifyObject
Pointer to a client-supplied IoCompletion routine, if any. A value of REQNOTIFY_NULL (a system-specific manifest) implies that request is synchronous.
RequestContext
Pointer to a client-supplied context for its IoCompletion routine, if any. This value is passed, uninterpreted by the system or the transport, to the IoCompletion routine when it is called on completion of this request.
TdiStatus
Specifies the final completion status of this request. If the request is synchronous, this is set to the value returned by the transport routine that handles this request.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

See Also

TDI_REQUEST_KERNEL


TDI_REQUEST_KERNEL

The TDI_REQUEST_KERNEL structure defines a parameter format common to certain kernel-mode TDI_XXX IOCTL requests.

typedef struct _TDI_REQUEST_KERNEL {
  ULONG  RequestFlags;
  PTDI_CONNECTION_INFORMATION  RequestConnectionInformation;
  PTDI_CONNECTION_INFORMATION  ReturnConnectionInformation;
  PVOID  RequestSpecific;
} TDI_REQUEST_KERNEL, *PTDI_REQUEST_KERNEL;

Members

RequestFlags
Specifies a flag or combination of flags for certain TDI_XXX IOCTLs.
RequestConnectionInformation
Pointer to a TDI_CONNECTION_INFORMATION structure containing client-supplied data.
ReturnConnectionInformation
Pointer to a caller-supplied buffer in which the transport returns data, formatted as TDI_CONNECTION_INFORMATION structure.
RequestSpecific
Pointer to a caller-supplied value of a request-specific nature, used only for IOCTL requests that need additional parameters, such as a time-out value.

Headers

Declared in TdiKrnl.h. Include TdiKrnl.h.

Comments

Although not all members of the TDI_REQUEST_KERNEL structure are relevant to each such TDI_XXX IOCTL code, this structure is used as the common format at IrpSp->Parameters in the following TDI_XXX IOCTL requests to TDI transport drivers:

  • For TDI_CONNECT requests, the client supplies a remote-node address to which a connection should be offered, and possibly user connect data, at RequestConnectionInformation. The client can supply a time-out for its connection offer at RequestSpecific, or this member can be NULL, which directs the transport to use its own default time-out for the connection operation. The transport returns connection acceptance information at ReturnConnectionInformation.
  • For TDI_DISCONNECT requests, the client can set RequestFlags if the transport supports controlled disconnects; otherwise, this member is zero. The client can supply a time-out for the disconnection at RequestSpecific, or this member can be NULL, which directs the transport to use its own default time-out for the disconnection operation. The transport returns any disconnect data and status information supplied by the corresponding remote-node transport at ReturnConnectionInformation.
  • For TDI_LISTEN requests, the client can set RequestFlags with TDI_QUERY_ACCEPT if the transport supports delayed-connection acceptances; otherwise, this member is zero, which directs the transport to immediately accept any appropriate connection offer that comes in from a remote node. The client can specify a remote-node address from which a connection offer should be accepted and, if RequestFlags is zero, also some connect data to be transmitted to the remote node when the connection offer is accepted at RequestConnectionInformation. The transport returns any connect data transmitted from the remote node, as well as the remote-node address, at ReturnConnectionInformation when it accepts an endpoint-to-endpoint connection for its client, thereby satisfying its client's listen request.

Kernel-mode clients use the TdiBuild Xxx macros to set up Parameters in the transport's I/O stack location of a given IRP with the TDI_KERNEL_REQUEST structure for the preceding kernel-mode IOCTL requests. For TDI_DISASSOCIATE_ADDRESS requests, neither the client nor the transport pass any information in this structure.

The format at Parameters is request-specific for all other TDI_XXX. For more information about these structures, see TDI_XXX references in the TDI IOCTLs for Transport Drivers.

See Also

TdiBuildConnect, TdiBuildDisconnect, TdiBuildListen, TDI_CONNECT, TDI_CONNECTION_INFORMATION, TDI_DISCONNECT, TDI_LISTEN


TDI_REQUEST_STATUS

The TDI_REQUEST_STATUS structure contains status information a TDI driver function sets when it completes its operation.This structure can be used by transport drivers to pass request-specific information between internal driver routines.

typedef struct _TDI_REQUEST_STATUS {
  TDI_STATUS  Status;
  PVOID  RequestContext;
  ULONG  BytesTransferred;
} TDI_REQUEST_STATUS, *PTDI_REQUEST_STATUS;

Members

Status
Specifies the final completion status of the function. For a synchronous function, this member contains the return value.
RequestContext
Pointer to the handle the client passes to the driver function in a TDI_REQUEST structure.
BytesTransferred
Specifies the number of bytes of data the function transfers. For an asynchronous receive operation, for example, this member contains the number of bytes of data the client receives when the transport completes the IRP.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

See Also

TDI_REQUEST


TRANSPORT_ADDRESS

The TRANSPORT_ADDRESS structure defines the general format for an array of TDI driver-specific transport addresses.

typedef struct _TRANSPORT_ADDRESS {
  LONG  TAAddressCount;
  TA_ADDRESS  Address[1];
} TRANSPORT_ADDRESS, *PTRANSPORT_ADDRESS;

Members

TAAddressCount
Specifies the number of elements in the array at Address.
Address
Specifies an array of one or more TA_ADDRESS structures each specifying a transport address of a particular TDI_ADDRESS_TYPE_XXX.

Headers

Declared in Tdi.h. Include Tdi.h or TdiKrnl.h.

Comments

Although any address specified in a TRANSPORT_ADDRESS structure is always driver-specific, all transports of a particular protocol type (for example, all NetBIOS transports or all IPX transports) use the same address format.

When it is given a TRANSPORT_ADDRESS structure, the transport uses the first recognizable address in the array at Address. For instance, if its client passes in several TDI_ADDRESS_TYPE_NETBIOS addresses, a NetBIOS transport would use only the first such address. If a transport can use some number of TDI_ADDRESS_TYPE_XXX addresses and it is given an array of mixed types, it uses only the first valid address of each such type.

A transport returns an error if it is given a TRANSPORT_ADDRESS structure containing elements of a type it is unable to parse. If the transport is given an address of a recognizable type that it cannot use, the transport can search the array elements for a usable address and return an error if it finds no valid address.

See Also

TA_ADDRESS, TA_APPLETALK_ADDR, TA_IP_ADDRESS, TA_IPX_ADDRESS, TA_NETBIOS_ADDRESS, TA_NS_ADDRESS, TA_VNS_ADDRESS


Notify Object Reference

The following sections document the COM interfaces that are implemented by a notify object for a network component and the COM interfaces used by those notify objects. Network components use notify objects to control networking setup and configuration, and to create custom property pages used for modifying a component's properties. Notify objects also make use of numerous data types to control the network configuration.

Note IUnknown methods are common to all COM interfaces. COM interfaces support the AddRef, QueryInterface, and Release methods. See the Platform SDK documentation for more information on IUnknown interface methods.

Notify object interfaces and data types are described in the following sections:

Notify Object Interfaces

Network Configuration Interfaces

Network Configuration Structure and Enumeration


Notify Object Interfaces

A notify object for a network component implements the following interfaces to control networking setup and configuration, and to create custom property pages used for modifying a component's properties:

INetCfgComponentControl initializes a component's notify object. (Required)

INetCfgComponentSetup performs operations for installing and removing a component. (Optional)

INetCfgComponentPropertyUi displays custom property pages for a component. (Optional)

INetCfgComponentNotifyBinding evaluates changes to how the network configuration subsystem binds a component to other network components. (Optional)

INetCfgComponentNotifyGlobal evaluates changes to network configuration that might affect a component. (Optional)


INetCfgComponentControl

The INetCfgComponentControl interface is a required interface which provides methods that are called by the network configuration subsystem to initialize the notify object of the network component and to apply changes to the component.

The interface identifier (IID) for this interface is IID_INetCfgComponentControl.

When to Implement

The methods of this interface must be implemented so that the network configuration subsystem can initialize the notify object of the network component and can apply changes to the component. This interface is required.

When to Use

The network configuration subsystem calls the methods of INetCfgComponentControl to initialize the notify object of the network component and to apply changes to the component.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments the reference count.
Release | Decrements the reference count.

INetCfgComponentControl method | Description
Initialize | Initializes the network component's notify object.
ApplyRegistryChanges | Applies changes made to the network component's configuration to the registry.
ApplyPnpChanges | Informs the notify object of the network component that it can configure its component's driver.
CancelChanges | Disregards proposed changes for the network component's configuration.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

E_NOTIMPL is not a valid return type for any of the INetCfgComponentControl interface's methods.


INetCfgComponentControl::Initialize

The Initialize method initializes the notify object of the network component and provides access to the component and to all aspects of network configuration.

HRESULT
  Initialize
    IN INetCfgComponent  *pnccItem,
    IN INetCfg  *pNetCfg,
    IN BOOL  fInstalling
    );

Parameters

pnccItem
Pointer to the INetCfgComponent interface for accessing the network component that owns the notify object.
pNetCfg
Pointer to the INetCfg interface for accessing all aspects of network configuration.
fInstalling
Boolean value that is TRUE if the operating system currently installs the network component and FALSE if the component is already installed.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

The notify object can use the pNetCfg pointer to the INetCfg interface to access information for the current networking configuration.

The notify object can use the pnccItem pointer to the INetCfgComponent interface to access information for the network component that owns the notify object. For example, the notify object can call the QueryInterface method of INetCfgComponent to obtain a pointer to the INetCfgComponentBindings interface for the network component. The notify object can use this interface to control binding and to retrieve binding information for the network component.

See Also

INetCfg, INetCfgComponent, INetCfgComponentBindings


INetCfgComponentControl::ApplyRegistryChanges

The ApplyRegistryChanges method directs the notify object of the network component to apply proposed changes for the component's network configuration state to the operating system.

HRESULT
  ApplyRegistryChanges(
    void
    );

Parameters

None

Return Value

Returns zero (S_OK) if successful, indicating that the changes were applied; returns S_FALSE if no changes were made; and returns NETCFG_S_REBOOT if the applied changes require a system reboot. If the INetCfg interface for the current networking configuration was not granted the write lock, ApplyRegistryChanges returns NETCFG_E_NO_WRITE_LOCK. ApplyRegistryChanges might also return other nonzero error codes.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

The ApplyRegistryChanges method can make changes to the registry to apply the component's network configuration state to the operating system. If the network configuration subsystem previously called the INetCfgComponentSetup::Removing method, ApplyRegistryChanges removes information about the network component from the registry. If the network configuration subsystem previously called the INetCfgComponentSetup::Install method, ApplyRegistryChanges sets information about the network component in the registry. If a user previously entered new parameter information on the component's property page, ApplyRegistryChanges modifies the parameter information in the registry.

See Also

INetCfg, INetCfgComponentSetup::Install, INetCfgComponentSetup::Removing


INetCfgComponentControl::ApplyPnpChanges

The ApplyPnpChanges method informs the notify object of the network component that it can send configuration information to the component's driver.

HRESULT
  ApplyPnpChanges(
    IN INetCfgPnpReconfigCallback  *pICallback
    );

Parameters

pICallback
Pointer to the INetCfgPnpReconfigCallback interface for configuring the driver of the network component that owns the notify object.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

The network configuration subsystem calls ApplyPnpChanges after calling the INetCfgComponentControl::ApplyRegistryChanges method and after drivers and services for a network component have started. The component's notify object can use the INetCfgPnpReconfigCallback interface that ApplyPnpChanges provides to send configuration information to the component's driver. This driver must be either a TDI provider or an NDIS miniport driver. Using INetCfgPnpReconfigCallback is optional but recommended to avoid requiring a user to reboot the operating system to implement changes to the configuration.

For example, if a user changes a parameter on a property page that is supplied by the component's notify object, ApplyPnpChanges should send the change to the component's driver. The format of the data that is sent depends entirely on driver requirements.

Because ApplyPnpChanges is the only method that is called after drivers and services have started, all operations that configure the component's driver should be performed within ApplyPnpChanges. The INetCfgPnpReconfigCallback interface simply provides the notify object with a mechanism to send data to the driver. Alternatively, ApplyPnpChanges can call the Win32® DeviceIoControl function to send configuration information directly to the component's driver.

See Also

INetCfgComponentControl::ApplyRegistryChanges, INetCfgPnpReconfigCallback


INetCfgComponentControl::CancelChanges

The CancelChanges method directs the notify object of the network component to disregard any proposed changes for the component's network configuration state.

HRESULT
  CancelChanges(
    void
    );

Parameters

None

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

The CancelChanges method resets any proposed changes to the network configuration state of the component.


INetCfgComponentSetup

The INetCfgComponentSetup interface is an optional interface which provides methods that inform the notify object of the network component that the network configuration subsystem must install or remove the component.

The interface identifier (IID) for this interface is IID_INetCfgComponentSetup.

When to Implement

Implement the methods of this interface to perform operations required to install, upgrade, and remove a network component. This interface is optional.

When to Use

The network configuration subsystem calls the methods of INetCfgComponentSetup to install and remove a network component.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments the reference count.
Release | Decrements the reference count.

INetCfgComponentSetup method | Description
Install | Performs operations required to install the network component that owns the notify object.
Upgrade | Modifies the network component, if required, when the operating system upgrades.
ReadAnswerFile | Retrieves parameters from a file to configure the network component.
Removing | Performs operations required to remove the network component that owns the notify object.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

A network component can use the INetCfgComponentSetup interface to examine a file for unattended setup and determine what section contains the component's parameters.

E_NOTIMPL is not a valid return type for any of this interface's methods.


INetCfgComponentSetup::Install

The Install method directs the notify object of the network component to perform operations required to install the component.

HRESULT
  Install(
    IN DWORD  dwSetupFlags
    );

Parameters

dwSetupFlags
A 32-bit value that specifies a mask enumerating the type of installation and the type of operating system from which to install. A notify object can support a combination of values. The bitmask can contain values from the following NETWORK_INSTALL_TIME enumeration:
Value | Description
NSF_PRIMARYINSTALL | Operating system installation
NSF_POSTSYSINSTALL | Network installation on an operating system that previously did not have networking

The bitmask can also contain values from the following NETWORK_UPGRADE_TYPE enumeration:
Value | Description
NSF_WIN95_UPGRADE | Upgrade from Windows 95, 98, or Me.
NSF_WINNT_WKS_UPGRADE | Upgrade from Windows NT 4.0 Workstation.
NSF_WINNT_SVR_UPGRADE | Upgrade from Windows NT 4.0 Server.
NSF_WINNT_SBS_UPGRADE | Upgrade from Windows NT 4.0 Small Business Server.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

Install should not modify the registry. Only the INetCfgComponentControl::ApplyRegistryChanges method should make changes to the registry. The network configuration subsystem first calls Install to perform operations required to install the component and to set a variable that specifies that the action the notify object performs is to install. The network configuration subsystem then calls ApplyRegistryChanges to set information about the network component in the registry.

See Also

INetCfgComponentControl::ApplyRegistryChanges


INetCfgComponentSetup::Upgrade

The Upgrade method directs the notify object of the network component to perform the operations required when the operating system changes to a new, improved, or different version.

HRESULT
  Upgrade(
    IN DWORD  dwSetupFlags,
    IN DWORD  dwUpgradeFromBuildNo
    );

Parameters

dwSetupFlags
A 32-bit value that specifies the type of operating system from which to upgrade. This value can be one of the following types from the NETWORK_UPGRADE_TYPE enumeration:
Value | Description
NSF_WIN95_UPGRADE | Upgrade from Windows 95, 98, or Me.
NSF_WINNT_WKS_UPGRADE | Upgrade from Windows NT 4.0 Workstation.
NSF_WINNT_SVR_UPGRADE | Upgrade from Windows NT 4.0 Server.
NSF_WINNT_SBS_UPGRADE | Upgrade from Windows NT 4.0 Small Business Server.

dwUpgradeFromBuildNo
If the dwSetupFlags parameter contains NSF_WINNT_WKS_UPGRADE, NSF_WINNT_SVR_UPGRADE, or NSF_WINNT_SBS_UPGRADE, this parameter identifies the build number from which to upgrade.
If the dwSetupFlags parameter contains NSF_WIN95_UPGRADE, this parameter is ignored.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.


INetCfgComponentSetup::ReadAnswerFile

The ReadAnswerFile method directs the notify object of the network component to open a specific file for unattended setup and retrieve the parameters required to configure the network component.

HRESULT
  ReadAnswerFile(
    IN LPCWSTR  pszwAnswerFile,
    IN LPCWSTR  pszwAnswerSections
    );

Parameters

pszwAnswerFile
Pointer to a constant null-terminated string of 16-bit Unicode characters containing the full path and name of the file for unattended setup to open.
pszwAnswerSections
Pointer to a constant null-terminated string of 16-bit Unicode characters containing a comma-separated list of section names in the file for unattended setup from which to retrieve parameters for the network component.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

To open and retrieve information from a file for unattended setup, ReadAnswerFile uses the Setup API.

To open the file for unattended setup and retrieve a handle to the file, ReadAnswerFile calls the SetupOpenInfFile function of the Setup API and passes the name of the file. To retrieve parameter information stored in a section of the file, ReadAnswerFile calls the SetupGetLineText function of the Setup API and passes the file handle, section name, and key of the required parameter. The ReadAnswerFile method stores the retrieved parameter information in data members of its notify object. After ReadAnswerFile retrieves and stores all the parameters required to configure the network component, it calls the SetupCloseInfFile function of the Setup API to close the file.

ReadAnswerFile should not set values in the registry. Only the INetCfgComponentControl::ApplyRegistryChanges method should make changes to the registry.

See Also

INetCfgComponentControl::ApplyRegistryChanges


INetCfgComponentSetup::Removing

The Removing method directs the notify object of the network component to perform operations required for the component's removal.

HRESULT
  Removing(
    void
    );

Parameters

None

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

The Removing method performs cleanup operations to prepare for the network component's removal.

Removing should not modify the registry. Only the INetCfgComponentControl::ApplyRegistryChanges method should make changes to the registry. The network configuration subsystem first calls Removing to set the action for the network component to remove and then calls ApplyRegistryChanges to remove information about the network component from the registry.

See Also

INetCfgComponentControl::ApplyRegistryChanges


INetCfgComponentPropertyUi

The INetCfgComponentPropertyUi interface provides methods that inform a notify object of a user's request to display the properties of the network component that owns the object. These methods also inform the notify object that the network configuration subsystem must apply changes to the component's properties.

The interface identifier (IID) for this interface is IID_INetCfgComponentPropertyUi.

When to Implement

Implement the methods of this interface to display custom property pages for the network component that owns this notify object. This interface is optional.

When to Use

The network configuration subsystem calls the methods of INetCfgComponentPropertyUi to inform a notify object of a user's request to display properties of the network component that owns the object, and if the network configuration subsystem must apply changes to the component's properties.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments the reference count.
Release | Decrements the reference count.

INetCfgComponentPropertyUi method | Description
QueryPropertyUi | Determines if the given context is appropriate for displaying properties for the component that owns the notify object.
SetContext | Directs the component's notify object to display the component's properties in the context of a particular binding path or adapter.
MergePropPages | Creates custom property pages and merges them into the component's default set.
ValidateProperties | Checks proposed changes for the component's properties.
ApplyProperties | Stores, in memory, proposed changes for the component's properties.
CancelProperties | Disregards proposed changes for the component's properties.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

If a network component does not supply custom property pages that users can use to modify the component's properties, the INetCfgComponentPropertyUi interface does not need to be implemented for the component's notify object.

E_NOTIMPL is not a valid return type for any of the methods of INetCfgComponentPropertyUi.


INetCfgComponentPropertyUi::QueryPropertyUi

The QueryPropertyUi method determines if the given context is the appropriate context in which to display properties for the network component that owns the notify object.

HRESULT
  QueryPropertyUi(
    IN IUnknown  *pUnk
    );

Parameters

pUnk
Pointer to the IUnknown interface. QueryPropertyUi retrieves from the IUnknown interface the interface of the context for displaying properties for the network component that owns the notify object.

Return Value

Returns zero (S_OK) if successful, indicating that the network configuration subsystem can subsequently call any other method of the notify object's INetCfgComponentPropertyUi interface such as SetContext and MergePropPages; returns S_FALSE if users should not be able to display properties for the network component in the given context; and otherwise returns a nonzero error code.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

The network configuration subsystem calls QueryPropertyUi before calling any other method of the INetCfgComponentPropertyUi interface.

The network configuration subsystem calls QueryPropertyUi and passes a context to determine if users should be able to display properties for the network component to which the notify object belongs in that context.

Implementations of QueryPropertyUi might simply return S_OK to indicate that subsequent calls to SetContext and MergePropPages are permitted.

See Also

INetCfgComponentPropertyUi::MergePropPages, INetCfgComponentPropertyUi::SetContext


INetCfgComponentPropertyUi::SetContext

The SetContext method directs the notify object of the network component to display the component's properties in the context of a particular binding path or adapter.

HRESULT
  SetContext(
    IN IUnknown  *pUnk
    );

Parameters

pUnk
Pointer to the IUnknown interface. SetContext retrieves from the IUnknown interface the interface of a particular binding path or network adapter in which to display properties for the network component that owns the notify object. When the network configuration subsystem releases the interface, it calls SetContext and passes a NULL value.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

The network configuration subsystem can only call SetContext if its call to the notify object's INetCfgComponentPropertyUi::QueryPropertyUi method returned S_OK.

SetContext is called before the notify object's INetCfgComponentPropertyUi::MergePropPages method to inform the notify object of the specific context in which to create and merge custom property pages.

If the network configuration subsystem calls SetContext, it calls SetContext once to complete each of the following tasks:

  • To provide the notify object information it requires to identify either a binding path or an adapter. In this case, SetContext is called and the context that was previously passed to QueryPropertyUi is passed. The notify object subsequently displays properties for the network component that owns the object through either the identified binding path or adapter.
  • To release the context that the network configuration subsystem previously provided. In this case, SetContext is called and NULL is passed.

SetContext calls the QueryInterface method on the supplied IUnknown interface to determine if the network configuration subsystem supplied an interface for a specific object.

For example, the network configuration subsystem can supply the INetLanConnectionUiInfo interface when it calls SetContext. SetContext can use the GetDeviceGuid method of INetLanConnectionUiInfo to retrieve the GUID of a LAN device. The notify object can subsequently display properties for its network component in the context of this LAN device. For example, the notify object for the TCP/IP protocol can display an IP address that is associated with a particular LAN adapter in the context of that adapter. Doing so enables users to specify an IP address for that adapter.

The notify object can also use the retrieved LAN-device GUID to open a registry key under the registry key for the network component that owns the notify object. The notify object can use this newly opened key to store configuration information that is specific to the LAN device.

See Also

INetCfgComponentPropertyUi::MergePropPages, INetCfgComponentPropertyUi::QueryPropertyUi, INetLanConnectionUiInfo, INetLanConnectionUiInfo::GetDeviceGuid


INetCfgComponentPropertyUi::MergePropPages

The MergePropPages method informs the notify object of the network component that the default property pages for the component are in the process of displaying. When the default property pages display, the object can create and merge custom property pages into the default set.

HRESULT
  MergePropPages(
    IN/OUT DWORD  *pdwDefPages,
    OUT BYTE  **pahpspPrivate,
    OUT INT  *pcPages,
    IN HWND  hwndParent,
    IN LPCWSTR  *pszStartPage
    );

Parameters

pdwDefPages
Pointer to a 32-bit variable that represents the number of default property pages that the network configuration subsystem displays. A notify object can modify the number passed by the network configuration subsystem to display a different number of default pages than originally intended. If the network configuration subsystem should not display any default property pages, the notify object sets this number to zero.
pahpspPrivate
Pointer to a buffer that receives an array of handles to custom property sheet pages. A notify object creates these custom property sheet pages for the network component that owns the object.
pcPages
Pointer to a buffer that receives the number of entries in the array to which pahpspPrivate points.
hwndParent
Handle to the currently active window that owns the custom property pages created by the notify object. The network configuration subsystem provides this handle so that the notify object can display any required user interface before merging property pages that the object creates. This parameter can be a NULL value if the custom property pages will not have an owner.
pszStartPage
Pointer to a buffer that contains the name of the initial property page that displays after MergePropPages creates a property sheet dialog box. This parameter can specify either the identifier of a string resource or the pointer to a string that specifies the name. If this parameter is passed in as a NULL value, a start page is not required for the notify object. If this parameter is passed in as nonNULL, the MergePropPages implementation must provide a start page.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

The MergePropPages method calls the COM CoTaskMemAlloc function to allocate the buffer required for pahpspPrivate. If CoTaskMemAlloc returns a NULL value, MergePropPages returns E_INVALIDARG.


INetCfgComponentPropertyUi::ValidateProperties

The ValidateProperties method directs the notify object of the network component to validate any proposed changes for the component's properties.

HRESULT
  ValidateProperties(
    IN HWND  hwndSheet
    );

Parameters

hwndSheet
Handle to the custom property sheet created by the notify object for the network component that owns the object. The notify object validates any proposed changes for the component's properties within the pages of this property sheet.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code. If the return value is anything other than S_OK, the notify object can stop the property sheet from closing.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

The network configuration subsystem calls ValidateProperties after a user clicks either OK or Apply on a custom property sheet. If ValidateProperties finds problems with any proposed changes for the component's properties, it informs the user.

An individual custom property page loses focus as the user activates another page. As a page loses focus it receives property sheet messages for validation. Each page's dialog box procedure processes these messages before the network configuration subsystem calls ValidateProperties.

After the network configuration subsystem calls ValidateProperties, the notify object validates any dependencies that arise between custom property pages.


INetCfgComponentPropertyUi::ApplyProperties

The ApplyProperties method directs the notify object of the network component to store, in memory, proposed changes for the component's network configuration state.

HRESULT
  ApplyProperties(
    void
    );

Parameters

None

Return Value

Returns zero (S_OK) if successful, indicating that the proposed changes were applied. Returns S_FALSE if no changes were made. ApplyProperties might return nonzero error codes.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

The network configuration subsystem calls ApplyProperties after a user clicks either OK or Apply on a custom property sheet. The ApplyProperties method stores the proposed changes in memory, but does not write the changes to the registry. Only the INetCfgComponentControl::ApplyRegistryChanges method makes changes permanent by writing them to the registry.

Note the following:

  • An individual custom property page loses focus as the user activates another page. As a page loses focus it receives property sheet messages to apply changes. Each page's dialog box procedure processes these messages before the network configuration subsystem calls ApplyProperties. It is the responsibility of each individual property page to set the changed flag for the property sheet. Each page's dialog box procedure can call the PropSheet_Changed macro to set the property sheet's changed flag after the procedure receives a message for an event that causes a change to occur. In this call, the dialog box procedure passes handles to the property sheet and the page that has changed. To retrieve the handle to the property sheet, the procedure can call the Win32® GetParent function and pass the handle to the property page. The following example informs a property sheet that information in one of its pages has changed.
    PropSheet_Changed(GetParent(hWndPage), hWndPage)

    For more information, see the documentation for property sheets in the Platform SDK.

  • The network configuration subsystem must call the INetCfgComponentPropertyUi::ValidateProperties method before calling ApplyProperties.
  • If the INetCfg interface for the current networking configuration was not granted the write lock, the network configuration subsystem will not call ApplyProperties.

See Also

INetCfg, INetCfgComponentControl::ApplyRegistryChanges, INetCfgComponentPropertyUi::ValidateProperties


INetCfgComponentPropertyUi::CancelProperties

The CancelProperties method directs the notify object of the network component to disregard any proposed changes for the component's network configuration state.

HRESULT
  CancelProperties(
    void
    );

Parameters

None

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

The network configuration subsystem calls CancelProperties after a user clicks Cancel on a custom property sheet. The CancelProperties method resets any proposed changes to the network configuration state of the component.

If a custom property sheet fails to display, the network configuration subsystem also calls CancelProperties to perform any required clean up.


INetCfgComponentNotifyBinding

The INetCfgComponentNotifyBinding interface provides methods that inform a notify object about changes in binding that affect its network component. These changes relate to how the network configuration subsystem binds other network components to the notify object's network component.

The interface identifier (IID) for this interface is IID_INetCfgComponentNotifyBinding.

When to Implement

Implement the methods of this interface so that the notify object can accept, reject, or process changes in binding that affect its network component. These changes relate to how the network configuration subsystem binds the network component that owns this notify object to other network components. This interface is optional.

When to Use

The network configuration subsystem calls the methods of INetCfgComponentNotifyBinding to inform a notify object about changes to the way the subsystem binds other network components to the network component that owns this notify object.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments the reference count.
Release | Decrements the reference count.

INetCfgComponentNotifyBinding method | Description
QueryBindingPath | Evaluates a pending change in the binding path to which the notify object's component belongs.
NotifyBindingPath | Performs operations resulting from a change in the binding path to which the notify object's component belongs.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

If a notify object does not need to accept, reject, or process changes to the way the network component that owns it binds to other network components, the INetCfgComponentNotifyBinding interface does not need to be implemented for that notify object.

E_NOTIMPL is not a valid return type for any of the methods of INetCfgComponentNotifyBinding.


INetCfgComponentNotifyBinding::QueryBindingPath

The QueryBindingPath method informs the notify object that a binding path is about to be added to its network component. This method directs the notify object to evaluate the change and to accept or reject it.

HRESULT
  QueryBindingPath(
    IN DWORD  dwChangeFlag,
    IN INetCfgBindingPath  *pncbpItem
    );

Parameters

dwChangeFlag
A 32-bit value that specifies a mask enumerating the types of binding-path changes that are about to occur. This value can contain a combination of the following types from the BIND_FLAGS1 enumeration:
Value | Description
NCN_ADD | Add the binding path.
NCN_ENABLE | Enable the binding path.
NCN_DISABLE | Disable the binding path.

pncbpItem
Pointer to the INetCfgBindingPath interface of the binding path that is about to be added.

Return Value

Returns zero (S_OK) if successful, indicating the notify object accepts the proposed change. Returns NETCFG_S_DISABLE_QUERY if the notify object accepts the proposed binding path but specifies that the network configuration subsystem must disable the binding path. Otherwise returns a nonzero error code.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

The notify object can use the provided binding path to obtain binding interfaces and network components that belong to the binding path as follows:

  • Call the INetCfgBindingPath::EnumBindingInterfaces method to obtain the binding path's collection of binding interfaces.
  • Call methods of the IEnumNetCfgBindingInterface interface to enumerate the INetCfgBindingInterface interfaces.
  • Call INetCfgBindingInterface::GetUpperComponent and INetCfgBindingInterface::GetLowerComponent methods to obtain components that are attached to the binding interface.

See Also

IEnumNetCfgBindingInterface, INetCfgBindingInterface, INetCfgBindingPath


INetCfgComponentNotifyBinding::NotifyBindingPath

The NotifyBindingPath method informs the notify object that a change occurred to the binding path of its network component. This method directs the notify object to perform operations related to the change.

HRESULT
  NotifyBindingPath(
    IN DWORD  dwChangeFlag,
    IN INetCfgBindingPath  *pncbpItem
    );

Parameters

dwChangeFlag
A 32-bit value that specifies a mask enumerating the types of binding-path changes that occurred. This value can contain a combination of the following types from the BIND_FLAGS1 enumeration.
Value | Description
NCN_ADD | Adds the binding path
NCN_REMOVE | Removes the binding path
NCN_UPDATE | Updates the binding path
NCN_ENABLE | Enables the binding path
NCN_DISABLE | Disables the binding path

pncbpItem
Pointer to the INetCfgBindingPath interface of the item involved in the specified change.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

If the network configuration subsystem adds a binding path to the network component that owns the notify object, the subsystem first calls the notify object's INetCfgComponentNotifyBinding::QueryBindingPath method. For other operations that require notifications, such as enabling and disabling, or removing and updating a binding path for the network component that owns the notify object, the subsystem only calls NotifyBindingPath.

A notify object can use the provided binding path to obtain binding interfaces and network components that belong to the binding path.

See Also

INetCfgBindingPath, INetCfgComponentNotifyBinding::QueryBindingPath


INetCfgComponentNotifyGlobal

The INetCfgComponentNotifyGlobal interface is an optional interface which provides methods that inform a network component's notify object about changes to network configuration that it must accept, reject, or process.

The interface identifier (IID) for this interface is IID_INetCfgComponentNotifyGlobal.

When to Implement

Implement the methods of this interface so that the network component's notify object will be informed about changes to network configuration that it must accept, reject, or process. This interface is optional.

When to Use

The network configuration subsystem calls the methods of INetCfgComponentNotifyGlobal to inform a network component's notify object about changes to network configuration that might affect the component.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces
AddRef | Increments the reference count
Release | Decrements the reference count

INetCfgComponentNotifyGlobal method | Description
GetSupportedNotifications | Retrieves the types of notifications required by a notify object.
SysQueryBindingPath | Evaluates a pending binding-path change.
SysNotifyBindingPath | Performs operations resulting from a binding-path change.
SysNotifyComponent | Performs operations resulting from a component change.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

If a notify object does not need to accept, reject, or process changes to network configuration that might affect its network component, the INetCfgComponentNotifyGlobal interface does not need to be implemented for the object. Changes to network configuration that might affect a network component include, for example, changing how network components other than the network component that owns the notify object are bound together.

E_NOTIMPL is not a valid return type for any of the methods of INetCfgComponentNotifyGlobal.


INetCfgComponentNotifyGlobal::GetSupportedNotifications

The GetSupportedNotifications method retrieves the types of notifications that the notify object of the network component requires from the network configuration subsystem.

HRESULT
  GetSupportedNotifications(
    OUT DWORD  *pdwNotifications
    );

Parameters

pdwNotifications
Pointer to a 32-bit variable that receives a mask enumerating the notifications that the notify object of the network component requires from the network configuration subsystem. A notify object can require a combination of the following notification types from the BIND_FLAGS1 enumeration:
Value | Description
NCN_ADD | Notifies if adding components.
NCN_REMOVE | Notifies if removing components.
NCN_UPDATE | Notifies if updating components.
NCN_ENABLE | Notifies if enabling components.
NCN_DISABLE | Notifies if disabling components.
NCN_BINDING_PATH | Notifies if binding paths change.
NCN_PROPERTYCHANGE | Notifies if a component's properties change.
NCN_NET | Notifies if network cards change
NCN_NETTRANS | Notifies if transports change.
NCN_NETCLIENT | Notifies if clients change.
NCN_NETSERVICE | Notifies if network services change.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

The network configuration subsystem calls GetSupportedNotifications immediately after the subsystem creates an instance of the notify object of the network component and probably before the subsystem calls any other interface methods implemented for the notify object. After the network configuration subsystem creates an instance of the network component's notify object, the object's INetCfgComponentControl::Initialize method prepares the object for a GetSupportedNotifications call.

See Also

INetCfgComponentControl::Initialize


INetCfgComponentNotifyGlobal::SysQueryBindingPath

The SysQueryBindingPath method informs the notify object of the network component that the addition of a binding path is about to occur. This method also directs the object to evaluate the change and to accept or reject it.

HRESULT
  SysQueryBindingPath(
    IN DWORD  dwChangeFlag,
    IN INetCfgBindingPath  *pncbpItem
    );

Parameters

dwChangeFlag
A 32-bit value that specifies a mask enumerating the types of binding-path changes that are about to occur. This value can contain a combination of the following types from the BIND_FLAGS1 enumeration:
Value | Description
NCN_ADD | Add the binding path.
NCN_ENABLE | Enable the binding path.
NCN_DISABLE | Disable the binding path.

pncbpItem
Pointer to the INetCfgBindingPath interface of the binding path that is about to be added.

Return Value

Returns zero (S_OK) if successful, indicating the notify object accepts the proposed change. Returns NETCFG_S_DISABLE_QUERY if the notify object accepts the proposed binding path but specifies that the network configuration subsystem must disable the binding path. Otherwise returns a nonzero error code.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

The notify object can use the provided binding path to obtain binding interfaces and network components that belong to the binding path.

See Also

INetCfgBindingPath


INetCfgComponentNotifyGlobal::SysNotifyBindingPath

The SysNotifyBindingPath method informs the notify object of the network component that a binding-path change occurred. This method directs the notify object to perform operations related to the change.

HRESULT
  SysNotifyBindingPath(
    IN DWORD  dwChangeFlag,
    IN INetCfgBindingPath  *pncbpItem
    );

Parameters

dwChangeFlag
A 32-bit value that specifies a mask enumerating the types of binding-path changes that occurred. This value can contain a combination of the following types from the BIND_FLAGS1 enumeration:
Value | Description
NCN_ADD | Adds the binding path
NCN_REMOVE | Removes the binding path
NCN_UPDATE | Updates the binding path
NCN_ENABLE | Enables the binding path
NCN_DISABLE | Disables the binding path

pncbpItem
Pointer to the INetCfgBindingPath interface of the item involved in the specified change.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

If the network configuration subsystem adds a binding path, the subsystem first calls the INetCfgComponentNotifyGlobal::SysQueryBindingPath method. For other operations that require notifications, such as enabling and disabling, or removing and updating a binding path, the subsystem only calls SysNotifyBindingPath.

A notify object can use the provided binding path to obtain binding interfaces and network components that belong to the binding path.

See Also

INetCfgBindingPath, INetCfgComponentNotifyGlobal::SysQueryBindingPath


INetCfgComponentNotifyGlobal::SysNotifyComponent

The SysNotifyComponent method informs the notify object of the network component that another component has been installed or removed. This method directs the notify object to perform operations related to the change.

HRESULT
  SysNotifyComponent(
    IN DWORD  dwChangeFlag,
    IN INetCfgComponent  *pnccItem
    );

Parameters

dwChangeFlag
A 32-bit value that specifies a mask enumerating the types of component changes that occurred. This value can contain a combination of the following types from the BIND_FLAGS1 enumeration:
Value | Description
NCN_ADD | Adds the component
NCN_REMOVE | Removes the component
NCN_UPDATE | Updates the component
NCN_NET | Adds, removes, or updates a network card.
NCN_NETTRANS | Adds, removes, or updates a protocol.
NCN_NETCLIENT | Adds, removes, or updates a client.
NCN_NETSERVICE | Adds, removes, or updates a service.

pnccItem
Pointer to the INetCfgComponent interface of the item involved in the specified change.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

See Also

INetCfgComponent


Network Configuration Interfaces

The following sections document the interfaces that a notify object for a network component can use to control networking setup and configuration. Most of these interfaces provide access to the network configuration subsystem.

The network configuration interfaces are described in the following topics:

INetCfg

INetCfgLock

INetCfgClass

INetCfgClassSetup

INetCfgBindingPath

INetCfgBindingInterface

INetCfgComponent

INetCfgComponentBindings

INetCfgPnpReconfigCallback

IEnumNetCfgComponent

IEnumNetCfgBindingInterface

IEnumNetCfgBindingPath

INetLanConnectionUiInfo

The INetLanConnectionUiInfo interface does not provide access to the network configuration subsystem. A notify object can use this interface to retrieve the context in which to display properties for the network component that owns the object.


INetCfg

The INetCfg interface is the root of all networking configuration and installation. The INetCfg interface provides methods that load into memory basic networking information, apply changes to network configuration, and retrieve network components and binding paths.

The interface identifier (IID) for this interface is IID_INetCfg.

When to Implement

It is not necessary to implement the methods of this interface. They are implemented in Netcfgx.dll.

When to Use

Use this interface to retrieve network components and binding paths.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments the reference count.
Release | Decrements the reference count.

INetCfg method | Description
Initialize | Initializes network configuration by loading into memory all basic networking information.
Uninitialize | Unloads from memory all basic networking information.
Apply | Applies all changes made to the configuration state of the network to the registry.
Cancel | Disregards any proposed changes to the configuration state of the network.
EnumComponents | Retrieves an enumeration containing a collection of network components of a particular type.
FindComponent | Retrieves the first network component that matches the specified component identifier.
QueryNetCfgClass | Retrieves a pointer to a specific class of network component.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

The INetCfg interface is the only network configuration interface that applications can receive after they call the COM CoCreateInstance function to create a network configuration object. Applications must obtain all other network configuration interfaces from INetCfg by either enumerating the interfaces or by calling methods that return the interfaces.

When notify objects initialize, they receive a pointer to INetCfg that represents the current networking configuration. Notify objects can use INetCfg to access all aspects of networking configuration.

After an application creates a network configuration object, the application should call Initialize to initialize network configuration. After the application finishes with the network configuration object, the application should call Uninitialize before releasing the network configuration object.

Example

The following example creates a network configuration object, accesses a specific network component, and, finally, releases the network configuration object. This example shows a typical sequence of operations.

INetCfg *pnetcfg = NULL;
INetCfgLock *pncfglock = NULL;
INetCfgComponent *pncfgcomp = NULL;
HRESULT hr = S_OK;
LPWSTR *ppszwrClient = NULL;

hr = CoCreateInstance( CLSID_NetCfg, NULL, CLSCTX_SERVER,
                       IID_INetCfg, (LPVOID*)&pnetcfg);
hr = pnetcfg->QueryInterface(IID_INetCfgLock, (LPVOID*)&pncfglock);
hr = pncfglock->AcquireWriteLock(5, TEXT("MY CLIENT"), &ppszwrClient);
hr = pnetcfg->Initialize(NULL);

hr = pnetcfg->FindComponent(TEXT("MS_TCPIP"), &pncfgcomp);
// Call various methods on pncfgcomp here.
pncfgcomp->Release();

hr = pnetcfg->Apply();
hr = pnetcfg->Uninitialize();
hr = pncfglock->ReleaseWriteLock();
pnetcfg->Release();


INetCfg::Initialize

The Initialize method initializes the network configuration by loading into memory all basic networking information for the operating system. This basic information includes installed network components and current network binding paths and interfaces.

HRESULT
  Initialize(
    IN PVOID  pvReserved
    );

Parameters

pvReserved
Pointer to a buffer that contains basic networking information.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

If a particular object has already successfully called Initialize, then another call to Initialize returns NETCFG_E_ALREADY_INITIALIZED.

See Also

INetCfg::Uninitialize


INetCfg::Uninitialize

The Uninitialize method unloads from memory all basic networking information for the operating system.

HRESULT
  Uninitialize(
    void
    );

Parameters

None

Return Value

Returns zero (S_OK) if successful; returns NETCFG_E_NOTINITIALIZED if the INetCfg interface was not previously initialized; and otherwise returns a nonzero error code if the network configuration fails to unload properly.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

The Uninitialize method is the last INetCfg method an application should call before calling the inherited Release method of INetCfg to release the network configuration object.

See Also

INetCfg::Initialize


INetCfg::Apply

The Apply method applies all changes that are made to the network configuration to the operating system.

HRESULT
  Apply(
    void
    );

Parameters

None

Return Value

Returns zero (S_OK) if successful, indicating changes were applied; returns NETCFG_S_REBOOT if the applied changes required a system reboot. If the INetCfg interface was not granted the write lock, Apply returns NETCFG_E_NO_WRITE_LOCK. Apply might also return other nonzero error codes.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

The Apply method calls the INetCfgComponentControl::ApplyRegistryChanges method for each component's notify object.

See Also

INetCfgComponentControl::ApplyRegistryChanges


INetCfg::Cancel

The Cancel method disregards any proposed changes for the network configuration state.

HRESULT
  Cancel(
    void
    );

Parameters

None

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

The Cancel method calls the INetCfgComponentControl::CancelChanges method for each component's notify object.

See Also

INetCfgComponentControl::CancelChanges


INetCfg::EnumComponents

The EnumComponents method retrieves an enumeration containing a collection of unordered network components of a particular type that are installed on the operating system.

HRESULT
  EnumComponents(
    IN const GUID  *pguidClass,
    OUT IEnumNetCfgComponent  **ppenumComponent
    );

Parameters

pguidClass
Pointer to GUID representing a specific class of network components. EnumComponents returns an enumeration containing this class of network components. Possible values are GUID_DEVCLASS_NET, GUID_DEVCLASS_NETTRANS, GUID_DEVCLASS_NETSERVICE, and GUID_DEVCLASS_NETCLIENT.
ppenumComponent
Pointer to a buffer that receives a pointer to the IEnumNetCfgComponent interface. This interface enumerates the INetCfgComponent interfaces for network components of a particular type that are installed on the operating system.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

The IEnumNetCfgComponent interface is a standard COM enumerator. To locate more information on COM enumerators and their methods, see the IEnumXXXX topic in the Platform SDK.

See Also

IEnumNetCfgComponent, INetCfgComponent


INetCfg::FindComponent

The FindComponent method retrieves the first network component that matches the specified component identifier.

HRESULT
  FindComponent(
    IN LPCWSTR  pszwComponentId,
    OUT INetCfgComponent  **ppComponent
    );

Parameters

pszwComponentId
Pointer to a constant null-terminated string of 16-bit Unicode characters containing the identifier of the component to find.
ppComponent
Pointer to a buffer that receives a pointer to the INetCfgComponent interface of the first network component that matches the component identifier contained in pszwComponentId.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

See Also

INetCfgComponent


INetCfg::QueryNetCfgClass

The QueryNetCfgClass method retrieves a pointer to a network configuration interface that represents a specific class of network component.

HRESULT
  QueryNetCfgClass(
    IN const GUID  *pguidClass,
    IN REFIID  riid,
    OUT void  **ppvObject
    );

Parameters

pguidClass
Pointer to GUID representing a specific class of network components. Possible values are GUID_DEVCLASS_NET, GUID_DEVCLASS_NETTRANS, GUID_DEVCLASS_NETSERVICE, and GUID_DEVCLASS_NETCLIENT.
riid
Reference pointer to the identifier of the interface being requested.
ppvObject
Pointer to a buffer that receives the interface pointer requested in the riid parameter. Upon successful return, *ppvObject contains the requested interface pointer to the class of components represented by the pguidClass parameter.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

Notify objects can call QueryNetCfgClass to query for any INetCfgClass interface that implements a specific class of network component. Notify objects can then call the INetCfgClass::EnumComponents method to obtain the collection of network components that currently belong to the class. In this way, notify objects can obtain the running state of changed components belonging to the class.

See Also

INetCfgClass, INetCfgClass::EnumComponents


INetCfgLock

The INetCfgLock interface provides methods that are used to obtain a lock on network configuration so that a client can safely configure network components and binding paths.

The interface identifier (IID) for this interface is IID_INetCfgLock.

When to Implement

It is not necessary to implement the methods of this interface. They are implemented in Netcfgx.dll.

When to Use

Use this interface to obtain an operating system-wide lock on network configuration.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments the reference count.
Release | Decrements the reference count.

INetCfgLock method | Description
AcquireWriteLock | Requests a lock on network configuration for a particular client.
ReleaseWriteLock | Releases a previously obtained lock on network configuration.
IsWriteLocked | Indicates the name of the client that currently controls network configuration.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

There can only be one write lock per operating system.

Applications call the QueryInterface method of the INetCfg interface to obtain a pointer to INetCfgLock.

See Also

INetCfg


INetCfgLock::AcquireWriteLock

The AcquireWriteLock method requests that the operating system grant a lock on network configuration so that a particular client can configure network components and binding paths.

HRESULT
  AcquireWriteLock(
    IN DWORD  cmsTimeout,
    IN LPCWSTR  pszwClientDescription,
    OUT LPWSTR  *ppszwClientDescription
    );

Parameters

cmsTimeout
Time, in milliseconds, to wait for the operating system to grant the lock on network configuration before timing out.
pszwClientDescription
Pointer to a constant null-terminated string of 16-bit Unicode characters containing the name of the client that requests control over network configuration.
ppszwClientDescription
Pointer to a buffer that receives a constant null-terminated string of 16-bit Unicode characters containing the name of the client that currently controls network configuration if the operating system refused to grant the lock.

Return Value

Returns zero (S_OK) if successful, indicating that the operating system granted the lock; returns S_FALSE if the wait time, cmsTimeout, elapsed before the operating system granted the lock, and otherwise returns a nonzero error code.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

Applications can only call AcquireWriteLock either before they call the INetCfg::Initialize method, or after they call the INetCfg::Uninitialize method. In all other cases, calls to AcquireWriteLock return NETCFG_E_ALREADY_INITIALIZED. If the current user is not an administrator of the local computer, calls to AcquireWriteLock return E_ACCESSDENIED.

Calls to notify objects typically occur after the network configuration subsystem has called AcquireWriteLock to obtain control and INetCfg::Initialize to initialize itself. For this reason, notify objects should rarely, if ever, call AcquireWriteLock to request control over network configuration.

When an application calls AcquireWriteLock to request control over network configuration, it identifies the client requesting control by passing the client's name in the pszwClientDescription parameter. If the application subsequently requests control for a different client, the network configuration subsystem refuses and might display a message stating the name of the client that already has control.

See Also

INetCfg::Initialize, INetCfg::Uninitialize


INetCfgLock::ReleaseWriteLock

The ReleaseWriteLock method releases a lock on network configuration that the operating system previously granted.

HRESULT
  ReleaseWriteLock(
    void
    );

Parameters

None

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

Notify objects can only call ReleaseWriteLock either before they call the INetCfg::Initialize method or after they call the INetCfg::Uninitialize method. In all other cases, calls to ReleaseWriteLock return NETCFG_E_ALREADY_INITIALIZED.

See Also

INetCfg::Initialize, INetCfg::Uninitialize


INetCfgLock::IsWriteLocked

The IsWriteLocked method indicates whether network configuration is currently locked. If so, IsWriteLocked returns the name of the client that currently controls network configuration.

HRESULT
  IsWriteLocked(
    OUT LPWSTR  *ppszwClientDescription
    );

Parameters

ppszwClientDescription
Pointer to a buffer that receives a constant null-terminated string of 16-bit Unicode characters. If the operating system previously granted the lock on network configuration, this parameter points to the name of the client that currently controls network configuration. If the operating system has not granted the lock on network configuration, this parameter points to a NULL value.

Return Value

Returns zero (S_OK) if successful, indicating that the operating system granted the lock to another client; returns S_FALSE if the operating system has not granted the lock to any clients; and otherwise returns a nonzero error code.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.


INetCfgClass

The INetCfgClass interface provides methods that retrieve network components from a group containing a specified type of network component.

The interface identifier (IID) for this interface is IID_INetCfgClass.

When to Implement

It is not necessary to implement the methods of this interface. They are implemented in Netcfgx.dll.

When to Use

Use this interface to retrieve a network component of a specific type.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments reference count.
Release | Decrements reference count.

INetCfgClass method | Description
FindComponent | Retrieves a network component belonging to a particular type.
EnumComponents | Retrieves an enumeration containing a collection of network components of a particular type.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

Notify objects call the INetCfg::QueryNetCfgClass method to obtain a pointer to a INetCfgClass interface.

The classes of network components that notify objects can obtain are:

Class | Represented by
Network cards | GUID_DEVCLASS_NET
Transports | GUID_DEVCLASS_NETTRANS
Network services | GUID_DEVCLASS_NETSERVICE
Network clients | GUID_DEVCLASS_NETCLIENT

See Also

INetCfg::QueryNetCfgClass


INetCfgClass::FindComponent

The FindComponent method retrieves a network component that belongs to this network component class and matches the specified component identifier.

HRESULT
  FindComponent(
    IN LPCWSTR  pszwComponentId,
    OUT INetCfgComponent  **ppComponent
    );

Parameters

pszwComponentId
Pointer to a constant null-terminated string of 16-bit Unicode characters containing the identifier of the component to find.
ppComponent
Pointer to a buffer that receives a pointer to the INetCfgComponent interface of the network component that matches the component identifier contained in pszwComponentId. This parameter is a NULL value if the component is not found.

Return Value

Returns zero (S_OK) if successful, indicating a component with the specified identifier was found; returns S_FALSE if the component was not found; and otherwise returns a nonzero error code.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

See Also

INetCfgComponent


INetCfgClass::EnumComponents

The EnumComponents method retrieves an enumeration containing a collection of unordered network components that belong to this network component class installed on the operating system.

HRESULT
  EnumComponents(
    OUT IEnumNetCfgComponent  **ppenumComponent
    );

Parameters

ppenumComponent
Pointer to a buffer that receives a pointer to the IEnumNetCfgComponent interface. This interface enumerates the INetCfgComponent interfaces for network components of a particular type that are installed on the operating system.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

The IEnumNetCfgComponent interface is a standard COM enumerator. To locate more information on COM enumerators and their methods, see the IEnumXXXX topic in the Platform SDK.

See Also

IEnumNetCfgComponent, INetCfgComponent


INetCfgClassSetup

The INetCfgClassSetup interface provides methods that prepare to automatically or manually install or remove network components of a specified type.

The interface identifier (IID) for this interface is IID_INetCfgClassSetup.

When to Implement

It is not necessary to implement the methods of this interface. They are implemented in Netcfgx.dll.

When to Use

Use this interface to prepare to either install or remove network components.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments the reference count.
Release | Decrements the reference count.

INetCfgClassSetup method | Description
SelectAndInstall | Displays a dialog that a user can use to select a network component of a particular class to install.
Install | Informs a class of network components to install the component specified by an identifier.
DeInstall | Removes the specified network component from the registry.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

If an application did not already call INetCfgLock::AcquireWriteLock to provide a client control over network configuration, the methods of INetCfgClassSetup return NETCFG_E_NO_WRITE_LOCK.

Calls to any methods of INetCfgClassSetup within a notify object's implementations of any methods of the following interfaces could return E_FAIL:

INetCfgComponentControl

INetCfgComponentNotifyGlobal

INetCfgComponentPropertyUI

INetCfgComponentNotifyBinding

These methods of INetCfgClassSetup return E_FAIL if an implemented method of one of the interfaces in the preceding list is not also passed change flags that include one of the following values:

  • NCF_ADD
  • NCF_REMOVE
  • NCF_UPDATE

Notify objects call the QueryInterface method of the INetCfgClass interface to obtain a pointer to INetCfgClassSetup.

See Also

INetCfgClass, INetCfgComponentControl, INetCfgComponentNotifyBinding, INetCfgComponentNotifyGlobal, INetCfgComponentPropertyUI, INetCfgLock::AcquireWriteLock


INetCfgClassSetup::SelectAndInstall

The SelectAndInstall method displays a dialog that lets a user select a network component of a particular class to install.

HRESULT
  SelectAndInstall(
    IN HWND  hwndParent,
    IN OBO_TOKEN  *pOboToken,
    OUT INetCfgComponent  **ppComponent
    );

Parameters

hwndParent
Handle to the window that owns the dialog for selecting a network component of the particular class to install.
pOboToken
Pointer to a OBO_TOKEN structure that describes an entity that requires the installation of a network component. This entity can be the user, another network component, or a software component that is not a network component. If this entity is another network component or a software component, to operate properly it requires the network component. If the entity is the user, the network component is being installed simply as a convenience to the user.
ppComponent
Pointer to a buffer that receives a pointer to the INetCfgComponent interface of the network component selected to install. This parameter is a NULL value if a user does not select a component.

Return Value

Returns zero (S_OK) if successful, indicating a user selected a component to install; returns HRESULT_FROM_WIN32(ERROR_CANCELLED) if the user canceled the dialog for selecting a network component; and otherwise returns a nonzero error code.

The Win32® HRESULT_FROM_WIN32 macro maps a Win32® error value into an HRESULT.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

If there are no setup information (INF) files for the particular class of network components, SelectAndInstall returns a nonzero error code along with the following message string:
"The specified path does not contain any applicable device INFs."
The dialog displays this message to the user.

The network configuration subsystem does not install the component until INetCfg::Apply is called.

The class GUID_DEVCLASS_NET used to obtain network card components does not support SelectAndInstall. If notify objects call SelectAndInstall for this class, it returns E_INVALIDARG. Users should select network card components to install through the hardware wizard.

See Also

INetCfg::Apply, INetCfgComponent, OBO_TOKEN


INetCfgClassSetup::Install

The Install method informs a class of network components to install the network component specified by a component identifier.

HRESULT
  Install (
    IN LPCWSTR  pszwComponentId,
    IN OBO_TOKEN  *pOboToken,
    IN DWORD  dwSetupFlags,
    IN DWORD  dwUpgradeFromBuildNo,
    IN LPCWSTR  pszwAnswerFile,
    IN LPCWSTR  pszwAnswerSections,
    OUT INetCfgComponent  **ppComponent
    );

Parameters

pszwComponentId
Pointer to a constant null-terminated string of 16-bit Unicode characters containing the identifier of the component to install.
pOboToken
Pointer to a OBO_TOKEN structure that describes an entity that requires the installation of the specified network component. If the component to install is of the class GUID_DEVCLASS_NET, this parameter is optional and set to a NULL value, otherwise this parameter is mandatory. The network configuration subsystem only installs one instance of the component. When networking initially installs and with subsequent networking installs, Install increments the component's reference count on behalf of the specified token.
dwSetupFlags
A 32-bit value that specifies a mask enumerating the type of installation and the type of operating system from which to install. A notify object can support a combination of values. The bitmask can contain values from the following NETWORK_INSTALL_TIME enumeration:
Value | Description
NSF_PRIMARYINSTALL | Operating system installation.
NSF_POSTSYSINSTALL | Network installation on an operating system that previously did not have networking.

The bitmask also can contain values from the following NETWORK_UPGRADE_TYPE enumeration:
Value | Description
NSF_WIN95_UPGRADE | Upgrading Windows 95, 98, or Me.
NSF_WINNT_WKS_UPGRADE | Upgrading NT 4.0 Workstation.
NSF_WINNT_SVR_UPGRADE | Upgrading Windows NT 4.0 Server.
NSF_WINNT_SBS_UPGRADE | Upgrading Windows NT 4.0 Small Business Server.

dwUpgradeFromBuildNo
If the dwSetupFlags parameter contains NSF_WINNT_WKS_UPGRADE, NSF_WINNT_SVR_UPGRADE, or NSF_WINNT_SBS_UPGRADE, this parameter identifies the build number from which to upgrade.
If the dwSetupFlags parameter contains NSF_WIN95_UPGRADE, this parameter is ignored.
pszwAnswerFile
Pointer to a constant null-terminated string of 16-bit Unicode characters containing the full path and name of the file for unattended setup to open.
pszwAnswerSections
Pointer to a constant null-terminated string of 16-bit Unicode characters containing a comma-separated list of section names in the file for unattended setup. This list is used to retrieve parameters for the network component.
ppComponent
Pointer to a buffer that receives a pointer to the INetCfgComponent interface of the network component that the Install method installed.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

The network configuration subsystem calls Install during an upgrade to the operating system or during the install of networking on an operating system that previously did not have networking.

The network configuration subsystem does not actually install the component until INetCfg::Apply is called.

See Also

INetCfg::Apply, INetCfgComponent, OBO_TOKEN


INetCfgClassSetup::DeInstall

The DeInstall method removes the specified network component from the operating system.

HRESULT
  DeInstall(
    IN INetCfgComponent  *pComponent,
    IN OBO_TOKEN  *pOboToken,
    OUT LPWSTR  *pmszwRefs,
    );

Parameters

pComponent
Pointer to the INetCfgComponent interface of the network component to remove.
pOboToken
Pointer to an OBO_TOKEN structure that describes an entity that requires the removal of the specified network component. If the component to remove is of the class GUID_DEVCLASS_NET, this parameter is optional and set to a NULL value; otherwise, this parameter is mandatory. After a notify object passes this parameter, DeInstall decrements the component's reference count on behalf of this token. If the component's reference count on behalf of all tokens becomes zero, the network configuration subsystem removes the component.
pmszwRefs
Pointer to a buffer that receives a constant null-terminated string of 16-bit Unicode characters containing the component's modified reference count.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

Before removing the specified network component, DeInstall first unbinds any other network components bound to the specified component.

See Also

INetCfgComponent, OBO_TOKEN


INetCfgBindingPath

The INetCfgBindingPath interface provides methods that control and retrieve information about a binding path.

The interface identifier (IID) for this interface is IID_INetCfgBindingPath.

When to Implement

It is not necessary to implement the methods of this interface. They are implemented in Netcfgx.dll.

When to Use

Use this interface to control and retrieve information about a binding path.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments the reference count.
Release | Decrements the reference count.

INetCfgBindingPath method | Description
IsSamePathAs | Verifies if the specified binding path is the same as this binding path.
IsSubPathOf | Verifies if this binding path is a sub-path of the specified binding path.
IsEnabled | Retrieves the current state of a binding path.
Enable | Sets the state of a binding path to enabled or disabled.
GetPathToken | Retrieves the identifier of a binding path that is unique across operating system reboots.
GetOwner | Retrieves the network component that owns a binding path.
GetDepth | Retrieves the number of binding interfaces contained in a binding path.
EnumBindingInterfaces | Retrieves an enumeration of a collection of binding interfaces contained in a binding path.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

A binding path consists of a string of network components that are connected together by binding interfaces. The component at the top of the binding path owns the path.


INetCfgBindingPath::IsSamePathAs

The IsSamePathAs method verifies if the specified binding path is the same as the binding path associated with this object.

HRESULT
  IsSamePathAs(
    IN INetCfgBindingPath  *pPath
    );

Parameters

pPath
Pointer to the INetCfgBindingPath interface of the binding path to verify.

Return Value

Returns zero (S_OK) if successful, indicating the binding paths are the same; returns S_FALSE if the binding paths are different; and otherwise returns a nonzero error code. If the specified binding path is NULL, IsSamePathAs returns E_POINTER.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

See Also

INetCfgBindingPath


INetCfgBindingPath::IsSubPathOf

The IsSubPathOf method verifies if this binding path is a sub-path of the specified binding path.

HRESULT
  IsSubPathOf(
    IN INetCfgBindingPath  *pPath
    );

Parameters

pPath
Pointer to the INetCfgBindingPath interface of the binding path that is used to verify if this binding path is a sub-path.

Return Value

Returns zero (S_OK) if successful, indicating this binding path is a sub-path of the specified binding path; and returns S_FALSE if this binding path is not a sub-path of the specified binding path. Otherwise returns a nonzero error code. If the specified binding path is NULL, IsSubPathOf returns E_POINTER.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

See Also

INetCfgBindingPath


INetCfgBindingPath::IsEnabled

The IsEnabled method retrieves the current state of a binding path.

HRESULT
  IsEnabled(
    void
    );

Parameters

None

Return Value

Returns zero (S_OK) if successful, indicating the binding path is enabled; returns S_FALSE if the binding path is disabled; and otherwise returns a nonzero error code. Returns NETCFG_E_NOT_INITIALIZED if the binding path has not been initialized.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.


INetCfgBindingPath::Enable

The Enable method sets the state of a binding path to be enabled or disabled.

HRESULT
  Enable(
    IN BOOL  fEnable
    );

Parameters

fEnable
Boolean value that is TRUE for the Enable method to enable the binding path and is FALSE for Enable to disable the binding path.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

If the INetCfg interface for the current networking configuration was not granted the write lock, Enable returns NETCFG_E_NO_WRITE_LOCK.

See Also

INetCfg


INetCfgBindingPath::GetPathToken

The GetPathToken method retrieves the identifier of a binding path that is unique across operating system reboots.

HRESULT
  GetPathToken(
    OUT LPWSTR  *ppszwPathToken
    );

Parameters

ppszwPathToken
Pointer to a buffer that receives a constant null-terminated string of 16-bit Unicode characters which contain the binding path's identifier. This identifier is unique across operating system reboots.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code. If the returned pointer points to NULL, GetPathToken returns E_POINTER.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

After notify objects call GetPathToken to retrieve the identifier of a binding path, GetPathToken allocates the memory required to store the string that contains the identifier. After notify objects finish with the identifier, they must call the COM CoTaskMemFree function to release the memory. For more information on CoTaskMemFree, see the Platform SDK.

See Also

INetCfgBindingPath


INetCfgBindingPath::GetOwner

The GetOwner method retrieves the network component that owns a binding path.

HRESULT
  GetOwner(
    OUT INetCfgComponent  **ppComponent
    );

Parameters

ppComponent
Pointer to a buffer that receives a pointer to the INetCfgComponent interface. This INetCfgComponent can access the network component that owns this binding path.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code. If the returned pointer points to NULL, GetOwner returns E_POINTER.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

The network component at the top of a binding path is the component that owns the binding path.

See Also

INetCfgComponent


INetCfgBindingPath::GetDepth

The GetDepth method retrieves the number of binding interfaces contained in a binding path.

HRESULT
  GetDepth(
    OUT ULONG  *pcInterfaces
    );

Parameters

pcInterfaces
Pointer to a 32-bit variable that receives the number of binding interfaces contained in a binding path.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code. If the returned pointer points to NULL, GetDepth returns E_POINTER.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

The number of binding interfaces contained in a binding path is one less than the number of network components that make up the binding path.


INetCfgBindingPath::EnumBindingInterfaces

The EnumBindingInterfaces method retrieves an enumeration of a collection of binding interfaces contained in a binding path.

HRESULT
  EnumBindingInterfaces(
    OUT IEnumNetCfgBindingInterface  **ppenumInterface
    );

Parameters

ppenumInterface
Pointer to a buffer that receives a pointer to the IEnumNetCfgBindingInterface interface. IEnumNetCtgBindingInterface enumerates the INetCfgBindingInterface interfaces that are contained in a binding path.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code. If the returned pointer points to NULL, EnumBindingInterfaces returns E_POINTER.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

The IEnumNetCfgBindingInterface interface is a standard COM enumerator. To locate more information on COM enumerators and their methods, see the IEnumXXXX topic in the Platform SDK.

See Also

IEnumNetCfgBindingInterface, INetCfgBindingInterface


INetCfgBindingInterface

The INetCfgBindingInterface interface provides methods that retrieve information about a binding interface.

The interface identifier (IID) for this interface is IID_INetCfgBindingInterface.

When to Implement

It is not necessary to implement the methods of this interface. They are implemented in Netcfgx.dll.

When to Use

Use this interface to retrieve information about a binding interface.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments the reference count.
Release | Decrements the reference count.

INetCfgBindingInterface method | Description
GetName | Retrieves the name of a binding interface.
GetUpperComponent | Retrieves the network component connected to the upper part of a binding interface.
GetLowerComponent | Retrieves the network component connected to the lower part of a binding interface.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

A binding interface binds two network components together. The components communicate through this binding interface. Binding interfaces include, for example, TDI and NDIS5.


INetCfgBindingInterface::GetName

The GetName method retrieves the name of a binding interface.

HRESULT
  GetName(
    OUT LPWSTR  *ppszwInterfaceName
    );

Parameters

ppszwInterfaceName
Pointer to a buffer that receives a constant null-terminated string of 16-bit Unicode characters that contains the name of a binding interface.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code. If the returned pointer points to NULL, GetName returns E_POINTER.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

After notify objects call GetName to retrieve the name of a binding interface, GetName allocates the memory required to store the string that contains the name. After notify objects finish with the name, they must call the COM CoTaskMemFree function to release the memory. For more information on CoTaskMemFree, see the Platform SDK.

Names of binding interfaces include, for example, TDI and NDIS5.

The network configuration subsystem compares registry strings of the lower range of the interface's upper component, with registry strings of the upper range of the interface's lower component, to determine the interface's name. If the compared strings are identical, they contain this name.


INetCfgBindingInterface::GetUpperComponent

The GetUpperComponent method retrieves the network component that connects to the upper part of a binding interface.

HRESULT
  GetUpperComponent(
    OUT INetCfgComponent  **ppnccItem
    );

Parameters

ppnccItem
Pointer to a buffer that receives a pointer to the INetCfgComponent interface. This INetCfgComponent can access the network component that connects to the upper part of a binding interface.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code. If the returned pointer points to NULL, GetUpperComponent returns E_POINTER.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

For binding purposes, a component closer to the wire, that is, the actual network, is considered as a lower component; a component closer to the application layer is considered as an upper component. In other words, network components have the following binding order:

Application > Client > Service > Transport > Card > Network

See Also

INetCfgComponent


INetCfgBindingInterface::GetLowerComponent

The GetLowerComponent method retrieves the network component that connects to the lower part of a binding interface.

HRESULT
  GetLowerComponent(
    OUT INetCfgComponent  **ppnccItem
    );

Parameters

ppnccItem
Pointer to a buffer that receives a pointer to the INetCfgComponent interface. This INetCfgComponent can access the network component that connects to the lower part of a binding interface.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code. If the returned pointer points to NULL, GetLowerComponent returns E_POINTER.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

For binding purposes, a component closer to the actual network is considered as a lower component; a component closer to the application layer is considered as an upper component. In other words, network components have the following binding order:

Application > Client > Service > Transport > Card > Network

See Also

INetCfgComponent


INetCfgComponent

The INetCfgComponent interface provides methods that control and retrieve information about a network component.

The interface identifier (IID) for this interface is IID_INetCfgComponent.

When to Implement

It is not necessary to implement the methods of this interface. They are implemented in Netcfgx.dll.

When to Use

Use this interface to control and retrieve information about a network component.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments the reference count.
Release | Decrements the reference count.

INetCfgComponent method | Description
GetDisplayName | Retrieves the name of a component that displays in a network connection's property sheet.
SetDisplayName | Sets the name of a component that displays in a network connection's property sheet.
GetHelpText | Retrieves a component's description that displays in a network connection's property sheet.
GetId | Retrieves a component's identifier.
GetCharacteristics | Retrieves a component's characteristics.
GetInstanceGuid | Retrieves a component's instance GUID.
GetPnpDevNodeId | Retrieves the identifier of a component's Plug and Play device node.
GetClassGuid | Retrieves the class GUID for a component's type.
GetBindName | Retrieves a component's description for binding operations.
GetDeviceStatus | Retrieves the status of a network card.
OpenParamKey | Opens and retrieves the registry key that contains parameters for a network component.
RaisePropertyUi | Displays a component's property sheet so that users can modify the component's properties.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

When notify objects initialize, they receive a pointer to INetCfgComponent. Notify objects use this pointer to access and configure the network components that own them.

A notify object can call the QueryInterface method of INetCfgComponent to obtain a pointer to the INetCfgComponentBindings interface for the network component. The notify object can use this interface to control binding and to retrieve binding information for the network component.

A notify object can call the following methods to retrieve binding paths to which the network component belongs:

  • INetCfgComponentBindings::EnumBindingPaths
  • Methods of the IEnumNetCfgBindingPath interface that enumerate the INetCfgBindingPath interfaces

See Also

IEnumNetCfgBindingPath, INetCfgBindingPath, INetCfgComponentBindings


INetCfgComponent::GetDisplayName

The GetDisplayName method retrieves the name of a network component that the network configuration subsystem displays in the property sheet dialog box for a network connection.

HRESULT
  GetDisplayName(
    OUT LPWSTR  *ppszwDisplayName
    );

Parameters

ppszwDisplayName
Pointer to a buffer that receives a constant null-terminated string of 16-bit Unicode characters containing the display name of a network component.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code. If the returned pointer points to NULL, GetDisplayName returns E_POINTER.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

After notify objects call GetDisplayName to retrieve the display name of a network component, GetDisplayName allocates the memory required to store the string containing the name. After notify objects finish with the name, they must call the COM CoTaskMemFree function to release the memory. For more information on CoTaskMemFree, see the Platform SDK.

Names that the network configuration subsystem displays for network components include, for example, "TCP/IP Protocol" and "AppleTalk Protocol."


INetCfgComponent::SetDisplayName

The SetDisplayName method assigns a name to a network component. The network configuration subsystem displays this name in the properties dialog for a network connection.

HRESULT
  SetDisplayName(
    IN LPCWSTR  pszwDisplayName
    );

Parameters

pszwDisplayName
Pointer to a constant null-terminated string of 16-bit Unicode characters containing the display name of a network component.

Return Value

Returns zero (S_OK) if successful; and returns E_NOTIMPL if the component is not a network card, that is, if the component is not a member of network class GUID_DEVCLASS_NET. SetDisplayName might also return other nonzero error codes.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

If the INetCfg interface for the current networking configuration was not granted the write lock, SetDisplayName returns NETCFG_E_NO_WRITE_LOCK.

SetDisplayName is only valid for components that are members of network class GUID_DEVCLASS_NET. SetDisplayName returns E_NOTIMPL if called for components of other types which include the following:

  • Transports represented by GUID_DEVCLASS_NETTRANS
  • Network services represented by GUID_DEVCLASS_NETSERVICE
  • Network clients represented by GUID_DEVCLASS_NETCLIENT

See Also

INetCfg


INetCfgComponent::GetHelpText

The GetHelpText method retrieves the description of a network component that the network configuration subsystem displays in the properties dialog for a network connection.

HRESULT
  GetHelpText(
    OUT LPWSTR  *ppszwHelpText
    );

Parameters

ppszwHelpText
Pointer to a buffer that receives a constant null-terminated string of 16-bit Unicode characters containing the description of a network component.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code. If the returned pointer points to NULL, GetHelpText returns E_POINTER.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

After notify objects call GetHelpText to retrieve the description of a network component, GetHelpText allocates the memory required to store the string containing the description. After notify objects finish with the description, they must call the COM CoTaskMemFree function to release the memory. For more information on CoTaskMemFree, see the Platform SDK.


INetCfgComponent::GetId

The GetId method retrieves the identifier of a network component.

HRESULT
  GetId(
    OUT LPWSTR  *ppszwId
    );

Parameters

ppszwId
Pointer to a buffer that receives a constant null-terminated string of 16-bit Unicode characters containing the identifier of a network component.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code. If the returned pointer points to NULL, GetId returns E_POINTER.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

After notify objects call GetId to retrieve the identifier of a network component, GetId allocates the memory required to store the string containing the identifier. After notify objects finish with the identifier, they must call the COM CoTaskMemFree function to release the memory. For more information on CoTaskMemFree, see the Platform SDK.

The GetId method locates a component identifier in the component's INF file. Component identifiers include, for example, MS_TCPIP and NDISWAN.


INetCfgComponent::GetCharacteristics

The GetCharacteristics method retrieves the characteristics that describe a network component and that restrict a user's actions on the component.

HRESULT
  GetCharacteristics(
    OUT DWORD  *pdwCharacteristics
    );

Parameters

pdwCharacteristics
Pointer to a 32-bit variable that receives a mask enumerating the characteristics of a network component. A network component can have a combination of the following characteristics from the COMPONENT_CHARACTERISTICS enumeration:
Value | Description
NCF_VIRTUAL | Emulates a physical network card.
NCF_SOFTWARE_ENUMERATED | Software enumerated component.
NCF_PHYSICAL | Physical network card.
NCF_HIDDEN | Hidden from the view of a user, that is, does not appear in any user interface.
NCF_NO_SERVICE | No associated network service.
NCF_NOT_USER_REMOVABLE | A user cannot remove, for example, from the Control Panel, Device Manager, or Hardware Wizard.
NCF_MULTIPORT_INSTANCED_ADAPTER | Network card with separate miniport driver instances for each adapter port.
NCF_HAS_UI | Has a property sheet for displaying and changing properties.
NCF_FILTER | Filter component whose bindings are treated differently.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code. If the returned pointer points to NULL, GetCharacteristics returns E_POINTER.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

The network characteristics NCF_VIRTUAL, NCF_SOFTWARE_ENUMERATED, and NCF_PHYSICAL are mutually exclusive.

A network component that has the characteristics of NCF_VIRTUAL, NCF_SOFTWARE_ENUMERATED, or NCF_PHYSICAL cannot also have the NCF_NO_SERVICE characteristic.


INetCfgComponent::GetInstanceGuid

The GetInstanceGuid method retrieves the instance GUID of a network component.

HRESULT
  GetInstanceGuid(
    OUT GUID  *pGuid
    );

Parameters

pGuid
Pointer to a 32-bit variable that receives a GUID for the instance GUID of a network component.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code. If the returned pointer points to NULL, GetInstanceGuid returns E_POINTER.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

The instance GUID of a network component represents the component in the registry.


INetCfgComponent::GetPnpDevNodeId

The GetPnpDevNodeId method retrieves the identifier of a network component's Pug and Play device node.

HRESULT
  GetPnpDevNodeId(
    OUT LPWSTR  *ppszwDevNodeId
    );

Parameters

ppszwDevNodeId
Pointer to a buffer that receives a constant null-terminated string of 16-bit Unicode characters containing the identifier of a network component's plug and play device node.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code. If the returned pointer points to NULL, GetPnpDevNodeId returns E_POINTER. If the component is not a network card, that is, if the component is not a member of network class GUID_DEVCLASS_NET, GetPnpDevNodeId returns E_NOTIMPL.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

After notify objects call GetPnpDevNodeId to retrieve the identifier of a network component's Plug and Play device node, GetPnpDevNodeId allocates the memory required to store the string containing the identifier. After notify objects finish with the identifier, they must call the COM CoTaskMemFree function to release the memory. For more information on CoTaskMemFree, see the Platform SDK.

The form of the identifier of a network component's Plug and Play device node is <enumerator>\<Device ID>\<Instance ID>.

GetPnpDevNodeId is only valid for components that are members of network class GUID_DEVCLASS_NET. GetPnpDevNodeId returns E_NOTIMPL if called for components of other types which include the following:

  • Transports represented by GUID_DEVCLASS_NETTRANS
  • Network services represented by GUID_DEVCLASS_NETSERVICE
  • Network clients represented by GUID_DEVCLASS_NETCLIENT


INetCfgComponent::GetClassGuid

The GetClassGuid method retrieves the class GUID for the type of network component that a component is.

HRESULT
  GetClassGuid(
    OUT GUID  *pGuid
    );

Parameters

pGuid
Pointer to a 32-bit variable that receives a class GUID that indicates a type of network component.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code. If the returned pointer points to NULL, GetClassGuid returns E_POINTER.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

A class GUID indicates a type of network component. Types of network components are network cards, protocols, services, and clients. The Devguid.h header file currently defines the following network class GUIDs:

Value | Description
GUID_DEVCLASS_NET | Network card
GUID_DEVCLASS_NETTRANS | Network protocol
GUID_DEVCLASS_NETCLIENT | Network client
GUID_DEVCLASS_NETSERVICE | Network service


INetCfgComponent::GetBindName

The GetBindName method retrieves the description of a network component that the network configuration subsystem uses for binding operations.

HRESULT
  GetBindName(
    OUT LPWSTR  *ppszwBindName
    );

Parameters

ppszwBindName
Pointer to a buffer that receives a constant null-terminated string of 16-bit Unicode characters containing the description of a network component used for binding operations.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code. If the returned pointer points to NULL, GetBindName returns E_POINTER.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

After notify objects call GetBindName to retrieve the description of a network component used for binding operations, GetBindName allocates the memory required to store the string containing the description. After notify objects finish with the description, they must call the COM CoTaskMemFree function to release the memory. For more information on CoTaskMemFree, see the Platform SDK.

A notify object might call the following methods to retrieve and traverse bindings in search of a network component with a specific bind name:

  • QueryInterface method of INetCfgComponent to obtain a pointer to INetCfgComponentBindings
  • INetCfgComponentBindings::EnumBindingPaths
  • Methods of the IEnumNetCfgBindingPath interface that enumerate the INetCfgBindingPath interfaces
  • INetCfgBindingPath::EnumBindingInterfaces
  • Methods of the IEnumNetCfgBindingInterface interface that enumerate the INetCfgBindingInterface interfaces.
  • INetCfgBindingInterface::GetUpperComponent and INetCfgBindingInterface::GetLowerComponent
  • GetBindName to retrieve the component's bind name

Strings that contain descriptions of network components used for binding operations can include, for example, "tcpip", "netbios", and "ndiswanipout."

See Also

IEnumNetCfgBindingInterface, IEnumNetCfgBindingPath, INetCfgBindingInterface, INetCfgBindingInterface::GetLowerComponent, INetCfgBindingInterface::GetUpperComponent, INetCfgBindingPath, INetCfgBindingPath::EnumBindingInterfaces, INetCfgComponentBindings::EnumBindingPaths


INetCfgComponent::GetDeviceStatus

The GetDeviceStatus method retrieves the status of a network card.

HRESULT
  GetDeviceStatus(
    OUT ULONG  *pStatus
    );

Parameters

pStatus
Pointer to a 32-bit variable that receives the status of a network card.

Return Value

Returns zero (S_OK) if successful; and returns E_NOTIMPL if the component is not a network card, that is, if the component is not a member of network class GUID_DEVCLASS_NET. GetDeviceStatus might also return other nonzero error codes.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

The GetDeviceStatus method retrieves the status of a network card from the configuration manager for Plug and Play.

GetDeviceStatus is only valid for components that are members of network class GUID_DEVCLASS_NET. GetDeviceStatus returns E_NOTIMPL if called for components of other types which can include:

  • Transports represented by GUID_DEVCLASS_NETTRANS
  • Network services represented by GUID_DEVCLASS_NETSERVICE
  • Network clients represented by GUID_DEVCLASS_NETCLIENT


INetCfgComponent::OpenParamKey

The OpenParamKey method opens and retrieves the registry key that contains parameters for a network component.

HRESULT
  OpenParamKey(
    OUT HKEY  *phkey
    );

Parameters

phkey
Pointer to a registry key handle that receives the open registry key for a network component.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

Notify objects that call OpenParamKey to retrieve a component's registry key must call the Win32® RegCloseKey function to close the key after they finish with it.


INetCfgComponent::RaisePropertyUi

The RaisePropertyUi method either determines if a network component supports a property sheet or displays the component's property sheet allowing users to modify the component's properties.

HRESULT
  RaisePropertyUi(
    IN HWND  hwndParent,
    IN DWORD  dwFlags,
    IN IUnknown  *pUnk
    );

Parameters

hwndParent
Handle to the currently active window that owns the property sheet for a network component that RaisePropertyUi displays.
dwFlags
A 32-bit value that specifies either to determine if the component supports a property sheet or to display the component's property sheet. This value can be one of the following values from the NCRP_FLAGS enumeration:
Value | Description
NCRP_QUERY_PROPERTY_UI | Determine if the component supports a property sheet.
NCRP_SHOW_PROPERTY_UI | If the component supports a property sheet, display it.

pUnk
Pointer to the IUnknown interface. RaisePropertyUi retrieves from IUnknown the interface of the context in which to display a network component's property sheet. RaisePropertyUi uses this interface to restrict the display of the property sheet to the context of a connection.

Return Value

If the NCRP_QUERY_PROPERTY_UI flag is specified:
Returns zero (S_OK) if successful, indicating that the component supports a property sheet; returns S_FALSE if the component does not support a property sheet; and otherwise returns a nonzero error code.
If the NCRP_SHOW_PROPERTY_UI flag is specified:
Returns zero (S_OK) if successful, indicating that changes were applied to the component's properties; returns S_FALSE if no changes were made; and otherwise returns a nonzero error code.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

The RaisePropertyUi method calls the notify object of the network component to set the appearance of the component's property sheet and to control the notify object's behavior. For example, RaisePropertyUi calls the following sequence of interface methods of the notify object:

  1. INetCfgComponentPropertyUi::QueryPropertyUi

    Determines if the given context is an appropriate context in which to display properties for the component.

  2. INetCfgComponentPropertyUi::SetContext

    Directs the component's notify object to display the component's properties in the given context.

  3. INetCfgComponentPropertyUi::MergePropPages

    Creates pages for the component's property sheet.

  4. INetCfgComponentPropertyUi::ApplyProperties

    Stores, in memory, changes to the component's network configuration that a user enters on the page.

  5. INetCfgComponentControl::ApplyRegistryChanges

    Applies the component's changes to the registry.

See Also

INetCfgComponentControl::ApplyRegistryChanges, INetCfgComponentPropertyUi::ApplyProperties, INetCfgComponentPropertyUi::MergePropPages, INetCfgComponentPropertyUi::QueryPropertyUi, INetCfgComponentPropertyUi::SetContext


INetCfgComponentBindings

The INetCfgComponentBindings interface provides methods that control and retrieve information about how the network configuration subsystem binds a network component with other network components.

The interface identifier (IID) for this interface is IID_INetCfgComponentBindings.

When to Implement

It is not necessary to implement the methods of this interface. They are implemented in Netcfgx.dll.

When to Use

Use this interface to control binding and to retrieve binding information for a network component.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces
AddRef | Increments the reference count
Release | Decrements the reference count

INetCfgComponentBindings method | Description
BindTo | Activates all binding paths that are shared with a specific component
UnbindFrom | Inactivates all binding paths that are shared with a specific component
SupportsBindingInterface | Verifies whether a component supports either an upper or lower edge binding interface
IsBoundTo | Verifies whether at least one binding path shared with a specific component is activate
IsBindableTo | Verifies whether at least one binding path shared with a specific component exists
EnumBindingPaths | Retrieves an enumeration of a collection of the component's binding paths
MoveBefore | Sets the order of two binding paths so that one comes before the other
MoveAfter | Sets the order of two binding paths so that one comes after the other.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

Notify objects call the QueryInterface method of the INetCfgComponent interface to obtain a pointer to INetCfgComponentBindings.

See Also

INetCfgComponent


INetCfgComponentBindings::UnbindFrom

The UnbindFrom method inactivates all binding paths that a network component shares with another specified network component.

HRESULT
  UnbindFrom(
    IN INetCfgComponent  *pnccItem
    );

Parameters

pnccItem
Pointer to the INetCfgComponent interface for the network component that UnbindFrom uses to inactivate binding paths.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

See Also

INetCfgComponent


INetCfgComponentBindings::SupportsBindingInterface

The SupportsBindingInterface method verifies whether a network component supports either an upper or lower edge binding interface with the specified name.

HRESULT
  SupportsBindingInterface(
    IN DWORD  dwFlags,
    IN LPCWSTR  pszwInterfaceName
    );

Parameters

dwFlags
A 32-bit value that specifies the type of binding interface for which to verify support. This value can be one of the following types from the SUPPORTS_BINDING_INTERFACE_FLAGS enumeration:
Value | Description
NCF_LOWER | Supports the binding interface on the lower edge.
NCF_UPPER | Supports the binding interface on the upper edge.

pszwInterfaceName
Pointer to a constant null-terminated string of 16-bit Unicode characters containing the name of the binding interface for which to verify support.

Return Value

Returns zero (S_OK) if successful, indicating the network component supports the binding interface; and returns S_FALSE if the network component does not support the binding interface. Otherwise returns a nonzero error code.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

Supporting a binding interface only indicates that the network component's information (INF) file lists the name of the binding interface as supported. It has nothing to do with whether the binding interface actually binds the component to other network components.

Names of binding interfaces include, for example, TDI and NDIS5.


INetCfgComponentBindings::IsBoundTo

The IsBoundTo method verifies whether at least one binding path is activated between a network component and another specified network component.

HRESULT
  IsBoundTo(
    IN INetCfgComponent  *pnccItem
    );

Parameters

pnccItem
Pointer to the INetCfgComponent interface for the network component that IsBoundTo uses to verify active binding paths.

Return Value

Returns zero (S_OK) if successful, indicating that at least one binding path binds a network component to another specified network component; and returns S_FALSE if no binding paths bind a network component to another specified network component. Otherwise returns a nonzero error code.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

See Also

INetCfgComponent


INetCfgComponentBindings::IsBindableTo

The IsBindableTo method verifies whether at least one binding path exists between a network component and another specified network component.

HRESULT
  IsBindableTo(
    IN INetCfgComponent  *pnccItem
    );

Parameters

pnccItem
Pointer to the INetCfgComponent interface for the network component that IsBindableTo uses to verify whether any binding paths exist.

Return Value

Returns zero (S_OK) if successful, indicating that at least one binding path exists and therefore can bind a network component to another specified network component. Returns S_FALSE if no binding paths exist. Otherwise returns a nonzero error code.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

The IsBindableTo method verifies whether a binding path exists but not whether the binding path is active or inactive.

See Also

INetCfgComponent


INetCfgComponentBindings::EnumBindingPaths

The EnumBindingPaths method retrieves an enumeration of a collection of binding paths that contain a network component.

HRESULT
  EnumBindingPaths(
    IN DWORD  dwFlags,
    OUT IEnumNetCfgBindingPath  **ppenumBinding
    );

Parameters

dwFlags
A 32-bit value that specifies that the retrieved collection of binding paths either start at or are below a network component. This value can be one of the following types from the ENUM_BINDING_PATHS_FLAGS enumeration:
Value | Description
EBP_ABOVE | The collection of binding paths contain a network component but do not start at the component.
EBP_BELOW | The collection of binding paths start at a network component.

ppenumBinding
Pointer to a buffer that receives a pointer to the IEnumNetCfgBindingPath interface. IEnumNetCfgBindingPath enumerates the INetCfgBindingPath interfaces for binding paths that contain a network component.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

The IEnumNetCfgBindingPath interface is a standard COM enumerator. To locate more information on COM enumerators and their methods, see the IEnumXXXX topic in the Platform SDK.

See Also

IEnumNetCfgBindingPath, INetCfgBindingPath


INetCfgComponentBindings::MoveBefore

The MoveBefore method sets the order of two binding paths so that one binding path comes before another reference binding path.

HRESULT
  MoveBefore(
    IN INetCfgBindingPath  *pncbItemSrc,
    IN INetCfgBindingPath  *pncbItemDest
    );

Parameters

pncbItemSrc
Pointer to the INetCfgBindingPath interface of the binding path to move.
pncbItemDest
Pointer to the INetCfgBindingPath interface of the reference binding path. MoveBefore places pncbItemSrc before pncbItemDest in the binding order. If this parameter is a NULL value, MoveBefore places pncbItemSrc at the beginning of the binding order.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

If the INetCfg interface for the current networking configuration was not granted the write lock, MoveBefore returns NETCFG_E_NO_WRITE_LOCK.

See Also

INetCfg, INetCfgBindingPath


INetCfgComponentBindings::MoveAfter

The MoveAfter method sets the order of two binding paths so that one binding path follows another reference binding path.

HRESULT
  MoveAfter(
    IN INetCfgBindingPath  *pncbItemSrc,
    IN INetCfgBindingPath  *pncbItemDest
    );

Parameters

pncbItemSrc
Pointer to the INetCfgBindingPath interface of the binding path to move.
pncbItemDest
Pointer to the INetCfgBindingPath interface of the reference binding path. MoveAfter places pncbItemSrc after pncbItemDest in the binding order. If this parameter is a NULL value, MoveAfter places pncbItemSrc at the end of the binding order.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

If the INetCfg interface for the current networking configuration was not granted the write lock, MoveAfter returns NETCFG_E_NO_WRITE_LOCK.

See Also

INetCfg, INetCfgBindingPath


INetCfgPnpReconfigCallback

The INetCfgPnpReconfigCallback interface provides a method that sends configuration information to the driver of the network component that owns a notify object.

The interface identifier (IID) for this interface is IID_INetCfgPnpReconfigCallback.

When to Implement

It is not necessary to implement the method of this interface. It is implemented in Netcfgx.dll.

When to Use

The network configuration subsystem supplies INetCfgPnpReconfigCallback to a notify object when the subsystem calls the object's INetCfgComponentControl::ApplyPnpChanges method. ApplyPnpChanges can use the method of INetCfgPnpReconfigCallback to send configuration information to the driver of the network component that owns the object. A notify object is not required to use INetCfgPnpReconfigCallback.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments the reference count.
Release | Decrements the reference count.

INetCfgPnpReconfigCallback method | Description
SendPnpReconfig | Sends configuration information to the driver of the network component that owns a notify object.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

The network configuration subsystem calls ApplyPnpChanges after calling the INetCfgComponentControl::ApplyRegistryChanges method and after drivers and services for a network component have started. The component's notify object can use the INetCfgPnpReconfigCallback interface that ApplyPnpChanges provides to send configuration information to the component's driver. This driver must be either a TDI provider or an NDIS miniport driver. Using INetCfgPnpReconfigCallback is optional but recommended to avoid requiring a user to reboot the operating system to implement changes to the configuration.

See Also

INetCfgComponentControl::ApplyPnpChanges, INetCfgComponentControl::ApplyRegistryChanges


INetCfgPnpReconfigCallback::SendPnpReconfig

The SendPnpReconfig method sends configuration information to the driver of the network component that owns a notify object.

HRESULT
  SendPnpReconfig(
    IN NCPNP_RECONFIG_LAYER  Layer,
    IN LPCWSTR  pszwUpper,
    IN LPCWSTR  pszwLower,
    IN PVOID  pvData,
    IN DWORD  dwSizeOfData
    );

Parameters

Layer
NCPNP_RECONFIG_LAYER enumeration value that specifies the type of driver to send configuration information. The following table lists and describes valid values:
Value | Description
NCRL_NDIS | The driver is an NDIS intermediate driver.
NCRL_TDI | The driver is a TDI provider driver.

pszwUpper
Pointer to a constant null-terminated string of 16-bit Unicode characters containing the full path and service name of either a protocol driver or the protocol edge of an intermediate driver. This service name is identical to the name that was specified in the AddService directive of the driver's INF file.
pszwLower
Pointer to a constant null-terminated string of 16-bit Unicode characters containing the bindname of the adapter to which the protocol driver or the intermediate driver, whose service name is at pszwUpper, is bound. Bindnames are names of network components that are used for binding operations and can include, for example, "tcpip", "netbios", and "ndiswanipout."
pvData
Pointer to an input buffer supplied by the notify object. This buffer contains the data to transfer to the target driver.
dwSizeOfData
Size, in bytes, of the input buffer at pvData.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

A notify object can call SendPnpReconfig within its implementation of the INetCfgComponentControl::ApplyPnpChanges method to send configuration information to the driver of the network component that owns the object. SendPnpReconfig provides the notify object with a possible mechanism to send data to the driver. Calling SendPnpReconfig is optional for the notify object but recommended to avoid requiring a user to reboot the operating system to implement changes to the configuration.

A call to SendPnpReconfig triggers a call to the ProtocolPnPEvent handler of either the protocol driver or the protocol edge of the intermediate driver. In this ProtocolPnPEvent call, the NetEvent member (NET_PNP_EVENT_CODE enumeration) of the NET_PNP_EVENT structure is set to NetEventReconfigure.

In the Windows DDK, the NET_PNP_EVENT description specifies that the contents of the Buffer member are NULL if the event code in the NetEvent member is NetEventReconfigure. However, if SendPnpReconfig triggers the event, the Buffer member is not NULL but contains whatever the caller of SendPnpReconfig passed in the pvData parameter.

See Also

INetCfgComponentControl::ApplyPnpChanges, NET_PNP_EVENT for Protocol Drivers, ProtocolPnPEvent


IEnumNetCfgComponent

The IEnumNetCfgComponent interface provides methods that enumerate the INetCfgComponent interfaces for network components of a particular type installed on the operating system. Types of network components include network cards, protocols, services, and clients.

The interface identifier (IID) for this interface is IID_IEnumNetCfgComponent.

When to Implement

It is not necessary to implement the methods of this interface. They are implemented in Netcfgx.dll.

When to Use

Use this interface to retrieve the INetCfgComponent interfaces for network components of a particular type.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces
AddRef | Increments the reference count
Release | Decrements the reference count

IEnumNetCfgComponent method | Description
Next | Retrieves the next specified number of items in the enumeration sequence
Skip | Skips over the next specified number of items in the enumeration sequence
Reset | Resets the enumeration sequence to the beginning item
Clone | Creates another enumerator that contains the same enumeration state as the current one

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

The IEnumNetCfgComponent interface is a standard COM enumerator. To locate more information on COM enumerators and their methods, see the IEnumXXXX topic in the Platform SDK.

Notify objects call the INetCfgClass::EnumComponents method to obtain a pointer to IEnumNetCfgComponent.

See Also

INetCfgClass::EnumComponents, INetCfgComponent


IEnumNetCfgComponent::Clone

The Clone method creates another IEnumNetCfgComponent interface that contains the same enumeration state as the current IEnumNetCfgComponent interface.

HRESULT
  Clone(
    OUT IEnumNetCfgComponent  **ppEnum
    );

Parameters

ppEnum
Pointer to a buffer that receives a pointer to the new IEnumNetCfgComponent interface.

Return Value

Returns one of the following values:

S_OK
The method succeeded.
E_POINTER
The ppEnum parameter is not a valid pointer.
E_OUTOFMEMORY
Insufficient memory exists to perform the operation.
E_UNEXPECTED
The method failed for unknown reasons.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

See Also

INetCfgComponent


IEnumNetCfgComponent::Next

The Next method retrieves the next specified number of INetCfgComponent interfaces in the enumeration sequence.

HRESULT
  Next(
    IN ULONG  celt,
    OUT INetCfgComponent  **ppElements,
    OUT ULONG  *pceltFetched
    );

Parameters

celt
Number of INetCfgComponent interfaces requested.
ppElements
Pointer to a buffer that receives a pointer to the requested INetCfgComponent interfaces.
pceltFetched
Pointer to a variable that receives the number of INetCfgComponent interfaces actually supplied. May be NULL if celt is one.

Return Value

Returns one of the following values:

S_OK
The method returned celt number of elements.
S_FALSE
The number of elements remaining in the sequence was less than celt.
E_POINTER
The ppElements parameter is not a valid pointer.
E_OUTOFMEMORY
Insufficient memory exists to perform the operation.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

See Also

INetCfgComponent


IEnumNetCfgComponent::Reset

The Reset method resets the enumeration sequence to the beginning element in the sequence.

HRESULT
  Reset(
    void
    );

Parameters

None

Return Value

Returns one of the following values:

S_OK
The method succeeded.
E_OUTOFMEMORY
Insufficient memory exists to perform the operation.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

See Also

INetCfgComponent


IEnumNetCfgComponent::Skip

The Skip method skips over the next specified number of elements in the enumeration sequence.

HRESULT
  Skip(
    IN ULONG  celt
    );

Parameters

celt
Number of elements to skip.

Return Value

Returns one of the following values:

S_OK
The number of elements skipped was celt.
S_FALSE
The number of elements skipped was not celt.
E_OUTOFMEMORY
Insufficient memory exists to perform the operation.

See Also

INetCfgComponent


IEnumNetCfgBindingInterface

The IEnumNetCfgBindingInterface interface provides methods that enumerate the INetCfgBindingInterface interfaces for binding interfaces contained in a particular binding path. Names of binding interfaces include, for example, TDI and NDIS5.

The interface identifier (IID) for this interface is IID_IEnumNetCfgBindingInterface.

When to Implement

It is not necessary to implement the methods of this interface. They are implemented in Netcfgx.dll.

When to Use

Use this interface to retrieve the INetCfgBindingInterface interfaces for binding interfaces contained in a particular binding path.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces
AddRef | Increments the reference count
Release | Decrements the reference count

IEnumNetCfgBindingInterface method | Description
Next | Retrieves the next specified number of items in the enumeration sequence
Skip | Skips over the next specified number of items in the enumeration sequence
Reset | Resets the enumeration sequence to the beginning item
Clone | Creates another enumerator that contains the same enumeration state as the current one

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

The IEnumNetCfgBindingInterface interface is a standard COM enumerator. To locate more information on COM enumerators and their methods, see the IEnumXXXX topic in the Platform SDK.

Notify objects call the INetCfgBindingPath::EnumBindingInterfaces method to obtain a pointer to IEnumNetCfgBindingInterface.

See Also

INetCfgBindingInterface, INetCfgBindingPath::EnumBindingInterfaces


IEnumNetCfgBindingInterface::Clone

The Clone method creates another IEnumNetCfgBindingInterface interface that contains the same enumeration state as the current IEnumNetCfgBindingInterface interface.

HRESULT
  Clone(
    OUT IEnumNetCfgBindingInterface  **ppEnum
    );

Parameters

ppEnum
Pointer to a buffer that receives a pointer to the new IEnumNetCfgBindingInterface interface.

Return Value

Returns one of the following values:

S_OK
The method succeeded.
E_POINTER
The ppEnum parameter is not a valid pointer.
E_OUTOFMEMORY
Insufficient memory exists to perform the operation.
E_UNEXPECTED
The method failed for unknown reasons.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

See Also

INetCfgBindingInterface


IEnumNetCfgBindingInterface::Next

The Next method retrieves the next specified number of INetCfgBindingInterface interfaces in the enumeration sequence.

HRESULT
  Next(
    IN  ULONG  celt,
    OUT INetCfgBindingInterface  **ppElements,
    OUT ULONG  *pceltFetched
    );

Parameters

celt
Number of INetCfgBindingInterface interfaces requested.
ppElements
Pointer to a buffer that receives a pointer to the requested INetCfgBindingInterface interfaces.
pceltFetched
Pointer to a variable that receives the number of INetCfgBindingInterface interfaces actually supplied. May be NULL if celt is one.

Return Value

Returns one of the following values:

S_OK
The method returned celt number of elements.
S_FALSE
The number of elements remaining in the sequence was less than celt.
E_POINTER
The ppElements parameter is not a valid pointer.
E_OUTOFMEMORY
Insufficient memory exists to perform the operation.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

See Also

INetCfgBindingInterface


IEnumNetCfgBindingInterface::Reset

The Reset method resets the enumeration sequence to the beginning element in the sequence.

HRESULT
  Reset(
    void
    );

Parameters

None

Return Value

Returns one of the following values:

S_OK
The method succeeded.
E_OUTOFMEMORY
Insufficient memory exists to perform the operation.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

See Also

INetCfgBindingInterface


IEnumNetCfgBindingInterface::Skip

The Skip method skips over the next specified number of elements in the enumeration sequence.

HRESULT
  Skip(
    IN ULONG  celt
    );

Parameters

celt
Number of elements to skip.

Return Value

Returns one of the following values:

S_OK
Number of elements skipped was celt.
S_FALSE
Number of elements skipped was not celt.
E_OUTOFMEMORY
Insufficient memory exists to perform the operation.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

See Also

INetCfgBindingInterface


IEnumNetCfgBindingPath

The IEnumNetCfgBindingPath interface provides methods that enumerate the INetCfgBindingPath interfaces for binding paths that contain a particular network component.

The interface identifier (IID) for this interface is IID_IEnumNetCfgBindingPath.

When to Implement

It is not necessary to implement the methods of this interface. They are implemented in Netcfgx.dll.

When to Use

Use this interface to retrieve the INetCfgBindingPath interfaces for binding paths that contain a particular network component.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments reference count.
Release | Decrements reference count.

IEnumNetCfgBindingPath method | Description
Next | Retrieves the next specified number of items in the enumeration sequence
Skip | Skips over the next specified number of items in the enumeration sequence
Reset | Resets the enumeration sequence to the beginning item
Clone | Creates another enumerator that contains the same enumeration state as the current one

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

The IEnumNetCfgBindingPath interface is a standard COM enumerator. To locate more information on COM enumerators and their methods, see the IEnumXXXX topic in the Platform SDK.

To obtain a pointer to IEnumNetCfgBindingPath, notify objects call the INetCfgComponentBindings::EnumBindingPaths method.

See Also

INetCfgBindingPath, INetCfgComponentBindings::EnumBindingPaths


IEnumNetCfgBindingPath::Clone

The Clone method creates another IEnumNetCfgBindingPath interface that contains the same enumeration state as the current IEnumNetCfgBindingPath interface.

HRESULT
  Clone(
    OUT IEnumNetCfgBindingPath  **ppEnum
    );

Parameters

ppEnum
Pointer to a buffer that receives a pointer to the new IEnumNetCfgBindingPath interface.

Return Value

Returns one of the following values:

S_OK
Method succeeded.
E_POINTER
The ppEnum parameter is not a valid pointer.
E_OUTOFMEMORY
Insufficient memory exists to perform the operation.
E_UNEXPECTED
Failed for unknown reasons.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

See Also

INetCfgBindingPath


IEnumNetCfgBindingPath::Next

The Next method retrieves the next specified number of INetCfgBindingPath interfaces in the enumeration sequence.

HRESULT
  Next(
    IN  ULONG  celt,
    OUT INetCfgBindingPath **ppElements,
    OUT ULONG  *pceltFetched
    );

Parameters

celt
Number of INetCfgBindingPath interfaces requested.
ppElements
Pointer to a buffer that receives a pointer to the requested INetCfgBindingPath interfaces.
pceltFetched
Pointer to a variable that receives the number of INetCfgBindingPath interfaces actually supplied. May be NULL if celt is one.

Return Value

Returns one of the following values:

S_OK
The method returned celt number of elements.
S_FALSE
The number of elements remaining in the sequence was less than celt.
E_POINTER
The ppElements parameter is not a valid pointer.
E_OUTOFMEMORY
Insufficient memory exists to perform the operation.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

See Also

INetCfgBindingPath


IEnumNetCfgBindingPath::Reset

The Reset method resets the enumeration sequence to the beginning element in the sequence.

HRESULT
  Reset(
    void
    );

Parameters

None

Return Value

Returns one of the following values:

S_OK
The method succeeded.
E_OUTOFMEMORY
Insufficient memory exists to perform the operation.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

See Also

INetCfgBindingPath


IEnumNetCfgBindingPath::Skip

The Skip method skips over the next specified number of elements in the enumeration sequence.

HRESULT
  Skip(
    IN ULONG  celt
    );

Parameters

celt
Number of elements to skip.

Return Value

Returns one of the following values:

S_OK
The number of elements skipped was celt.
S_FALSE
The number of elements skipped was not celt.
E_OUTOFMEMORY
Insufficient memory exists to perform the operation.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

See Also

INetCfgBindingPath


INetLanConnectionUiInfo

The INetLanConnectionUiInfo interface provides a method that retrieves the context in which to display properties for the network component that owns a notify object.

The interface identifier (IID) for this interface is IID_INetLanConnectionUiInfo.

When to Implement

It is not necessary to implement the method of this interface. It is implemented in Netcfgx.dll.

When to Use

The network configuration subsystem can supply INetLanConnectionUiInfo to a notify object when the subsystem calls the object's INetCfgComponentPropertyUi::SetContext method. The network configuration subsystem supplies INetLanConnectionUiInfo as a pointer to an IUnknown interface. The notify object can call the QueryInterface method to determine if the supplied IUnknown supports INetLanConnectionUiInfo. SetContext can use the method of INetLanConnectionUiInfo to retrieve the context in which to display properties for the network component that owns the notify object.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments reference count.
Release | Decrements reference count.

INetLanConnectionUiInfo method | Description
GetDeviceGuid | Retrieves a pointer to the GUID for a LAN device.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

See Also

INetCfgComponentPropertyUi::SetContext


INetLanConnectionUiInfo::GetDeviceGuid

The GetDeviceGuid method retrieves the identity of a LAN device in which to display the properties of the network component that owns a notify object.

HRESULT
  GetDeviceGuid(
    OUT GUID*  pguid
    );

Parameters

pguid
Pointer to a buffer that receives a GUID representing a specific LAN device.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgn.h. Include Netcfgn.h.

Comments

A notify object can call GetDeviceGuid within its implementation of the INetCfgComponentPropertyUi::SetContext method to retrieve the GUID that represents a LAN device. SetContext directs a network component's notify object to display the component's properties in the context of that LAN device.

See Also

INetCfgComponentPropertyUi::SetContext


Network Configuration Structure and Enumeration

The enumeration and structure discussed in this section might be required to create a notify object for a network component. The enumeration and structure are as follows:

OBO_TOKEN

OBO_TOKEN_TYPE


OBO_TOKEN

The OBO_TOKEN structure contains information that describes an entity that requires the installation of a network component. This entity can be the user, another network component, or a software component that is not a network component. If this entity is another network component or a software component, to operate properly, it requires the network component. If the entity is the user, the network component is being installed simply as a convenience to the user.

typedef struct tagOBO_TOKEN {
  OBO_TOKEN_TYPE  Type;
  INetCfgComponent  *pncc;
  LPCWSTR  pszwManufacturer;
  LPCWSTR  pszwProduct;
  LPCWSTR  pszwDisplayName;
  BOOL  fRegistered;
} OBO_TOKEN;

Members

Type
Type of entity that requires the installation of a network component. Also specifies whether a user can remove the network component. Type can be one of the values contained in the OBO_TOKEN_TYPE enumeration.
pncc
Pointer to a INetCfgComponent interface that represents the network configuration of the component that requires the installation of another network component. Set this member to a pointer to a INetCfgComponent interface only if the Type member will be set to OBO_COMPONENT. If the Type member is not OBO_COMPONENT, this member is a NULL value.
pszwManufacturer
Pointer to a constant null-terminated string of 16-bit Unicode characters containing the name of the manufacturer that identifies the entity that requires the installation of a network component. This entity is a software component but not a network component. Set this member to a pointer to a string only if the Type member will be set to OBO_SOFTWARE. If the Type member is not OBO_SOFTWARE, this member is a NULL value.
pszwProduct
Pointer to a constant null-terminated string of 16-bit Unicode characters containing the name of the product that identifies the entity that requires the installation of a network component. This entity is a software component but not a network component. Set this member to a pointer to a string only if the Type member will be set to OBO_SOFTWARE. If the Type member is not OBO_SOFTWARE, this member is a NULL value.
pszwDisplayName
Pointer to a constant null-terminated string of 16-bit Unicode characters containing the name displayed to users that identifies the entity that requires the installation of a network component. This entity is a software component but not a network component. Set this member to a pointer to a string only if the Type member will be set to OBO_SOFTWARE. If the Type member is not OBO_SOFTWARE, this member is a NULL value.
fRegistered
Boolean value that is TRUE if a network component is set in the registry as installed and FALSE otherwise. This network component is installed on behalf of the entity specified by the Type member. This member should initially be set to FALSE before the network component installs; the network configuration subsystem sets the component as installed in the registry.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

See Also

INetCfgComponent, OBO_TOKEN_TYPE


OBO_TOKEN_TYPE

The OBO_TOKEN_TYPE enumeration contains values that specify the type of entity that requires the installation of a network component. The values in this enumeration also specify whether a user can remove the network component.

typedef enum tagOBO_TOKEN_TYPE {
  OBO_USER  = 1,
  OBO_COMPONENT  = 2,
  OBO_SOFTWARE  = 3,
} OBO_TOKEN_TYPE;

Elements

OBO_USER
A network component is installed on behalf of the user. If a network component is installed as a convenience for the user, the user can remove the network component.
OBO_COMPONENT
A network component is installed on behalf of another network component. If one network component is installed because a second network component depends on the first for proper operation, a user cannot remove the first component.
OBO_SOFTWARE
A network component is installed on behalf of a software component that is not another network component. If a network component is installed because the software component depends on the network component for proper operation, a user cannot remove the network component.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.


Filter-Hook Driver Reference

This section documents the callback function that is implemented by a filter-hook driver and the I/O control (IOCTL) that the filter-hook driver uses to register such a callback function. The filter-hook driver's callback function is also known as a filter hook. The Internet Protocol (IP) filter driver that is supplied with the system uses a filter hook to determine whether to either forward or drop incoming and outgoing packets.

A filter-hook driver supplies the symbolic address of its filter hook to register the filter hook's entry point with the system-supplied IP filter driver. The filter hook is defined by the PacketFilterExtensionPtr data type. Because a filter-hook driver supplies the address, and not the name, of its filter hook entry point, driver developers are free to name the filter hook whatever they wish.

This section includes the following topics:

PacketFilterExtensionPtr

IOCTL_PF_SET_EXTENSION_POINTER


PacketFilterExtensionPtr

The PacketFilterExtensionPtr data type points to a filter-hook callback function. This function processes packets that are passed to it and determines whether to forward or drop the packets or to allow the IP filter driver to further process the packets.

typedef  PF_FORWARD_ACTION
  (*PacketFilterExtensionPtr)(
    IN unsigned char  *PacketHeader,
    IN unsigned char  *Packet,
    IN unsigned int  PacketLength,
    IN unsigned int  RecvInterfaceIndex,
    IN unsigned int  SendInterfaceIndex,
    IN IPAddr  RecvLinkNextHop,
    IN IPAddr  SendLinkNextHop
    );

Parameters

PacketHeader
Pointer to the IP header of the packet. The filter hook can cast the information to which PacketHeader points to an IPHeader structure.
Packet
Pointer to a buffer that contains the information in the packet that the filter hook receives. This buffer does not include the IP header pointed to by PacketHeader.
PacketLength
Size, in bytes, of the information in the IP packet. This size does not include the size of the IP header.
RecvInterfaceIndex
For a received packet, index number for the network interface controller (NIC) over which the packet arrived. The filter hook uses this index number to identify the particular NIC that received the packet.
For transmitted packets, this parameter is set to INVALID_PF_IF_INDEX and the information in RecvLinkNextHop is meaningless.
SendInterfaceIndex
For a transmitted packet, index number for the NIC over which the packet will be transmitted. To obtain information about the specified NIC, the filter hook can query the routing table through Simple Network Management Protocol (SNMP).
For received packets, this parameter is set to INVALID_PF_IF_INDEX and the information in SendLinkNextHop is meaningless.
RecvLinkNextHop
IP address for the NIC that received the packet if the NIC is a point to multiple-point interface; otherwise this parameter is set to ZERO_PF_IP_ADDR.
SendLinkNextHop
IP address for the NIC that will transmit the packet if the NIC is a point-to-multiple-point interface; otherwise this parameter is set to ZERO_PF_IP_ADDR.

Return Values

Returns one of the following values from the PF_FORWARD_ACTION enumeration:

PF_FORWARD
Specifies for the IP filter driver to immediately return the forward response to the IP stack. IP forwards the packet up the stack for a local packet or routes the packet if the packet's destination is another computer and routing is enabled.
PF_DROP
Specifies for the IP filter driver to immediately return the drop response to the IP stack. IP should drop the packet.
PF_PASS
Specifies for the IP filter driver to process the packet and return the resulting response to the IP stack. The filter hook returns the pass response if it determined that it should not process the packet.

Headers

Defined in Pfhook.h. Include Pfhook.h.

Comments

If the filter hook returns the pass response, the IP filter driver processes the packet. In this case, a user-mode application can control packet filtering through the Packet Filtering API (iphlpapi.lib). This API can be used to create and manage input and output filters for IP packets. Each NIC can have one or more filters associated with it. Filters can include source and destination addresses, address mask and port, and protocol identifier. For more information on this API, refer to the Platform SDK.

The IP filter driver can pass IP header information for a packet in an IPHeader structure. The following section describes IPHeader.

IPHeader

The structure of information to which the PacketHeader parameter points is typically defined as an IPHeader structure. IPHeader provides details about the packet. IPHeader is defined as follows:

typedef struct IPHeader {
  UCHAR  iph_verlen;  // Version and length
  UCHAR  iph_tos;  // Type of service
  USHORT  iph_length;  // Total datagram length
  USHORT  iph_id;  // Identification
  USHORT  iph_offset;  // Flags, fragment offset
  UCHAR  iph_ttl;  // Time to live
  UCHAR  iph_protocol;  // Protocol
  USHORT  iph_xsum;  // Header checksum
  ULONG  iph_src;  // Source address
  ULONG  iph_dest;  // Destination address
} IPHeader;

The members of this structure contain the following information:

iph_verlen
Specifies the version and length for the packet.
iph_tos
Specifies the type of service for the packet.
iph_length
Size, in bytes, of the packet.
iph_id
Specifies the identity of the packet.
iph_offset
Specifies flags and fragment offset for the packet.
iph_ttl
Specifies the time to live (TTL) for the packet. TTL is a value in the range 0 through 255 that defines the scope within which packets should be sent over a network using IP. The scope is defined in terms of how local or remote a packet's destination is. Each router decrements the TTL by one. When the TTL reaches a predefined lower limit, the router throws the packet away.
iph_protocol
Specifies the protocol for the packet.
iph_xsum
Specifies the header checksum for the packet.
iph_src
Specifies the IP address of a computer that is the source for the packet.
iph_dest
Specifies the IP address of a computer that is the destination for the packet.

Headers

Defined in Pfhook.h. Include Pfhook.h.

See Also

IOCTL_PF_SET_EXTENSION_POINTER


IOCTL_PF_SET_EXTENSION_POINTER

The filter-hook driver uses this IOCTL to set up an IRP that the filter-hook driver submits to the IP filter driver. The filter-hook driver passes this IOCTL along with related parameters in the IoBuildDeviceIoControlRequest function to set up the IRP.

Operation

IOCTL_PF_SET_EXTENSION_POINTER registers filter-hook callback functions to the IP filter driver to inform the IP filter driver to call those filter hook callbacks for every IP packet that is received or transmitted. Also, IOCTL_PF_SET_EXTENSION_POINTER clears filter-hook callback functions from the IP filter driver.

Parameters

IoControlCode
IOCTL_PF_SET_EXTENSION_POINTER.
DeviceObject
Pointer to the device object for the IP filter driver.
InputBuffer
Pointer to a buffer that contains a PF_SET_EXTENSION_HOOK_INFO structure. To register the filter-hook callback function, this structure holds the address of the filter-hook callback function. To clear the filter-hook callback function, this structure holds a NULL value.
InputBufferLength
Size, in bytes, of the PF_SET_EXTENSION_HOOK_INFO structure.
OutputBuffer
NULL.
OutputBufferLength
Zero.
InternalDeviceIoControl
FALSE.
Event
NULL.
IoStatusBlock
Pointer to a buffer that is to receive an I/O status block. The I/O status is set after the IP filter driver completes the I/O request.

Headers

Defined in Pfhook.h. Include Pfhook.h.

Comments

To set up an IRP, the filter-hook driver calls the IoBuildDeviceIoControlRequest function. In this call, the filter-hook driver passes parameters specifying the IOCTL_PF_SET_EXTENSION_POINTER IOCTL request; the pointer to the device object for the IP filter driver; and an input buffer containing a PF_SET_EXTENSION_HOOK_INFO structure. To retrieve the device object for the IP filter driver, the filter-hook driver calls the IoGetDeviceObjectPointer function. In this call, the filter-hook driver passes parameters specifying the name of the device object for the IP filter driver, along with SYNCHRONIZE, GENERIC_READ, and GENERIC_WRITE. These values specify that synchronous, read, and write access to the driver must be provided. In the IoGetDeviceObjectPointer call, the filter-hook driver also passes pointers to buffers to hold the returned file and device objects for the IP filter driver. The Unicode string that contains the name of the device object for the IP filter driver is \\Device\Ipfilterdriver.

To submit the IRP, the filter-hook driver calls the IoCallDriver function.

The PF_SET_EXTENSION_HOOK_INFO structure is defined in the following section.

PF_SET_EXTENSION_HOOK_INFO

The PF_SET_EXTENSION_HOOK_INFO structure contains information that describes a filter-hook callback function.

typedef struct _PF_SET_EXTENSION_HOOK_INFO {
    PacketFilterExtensionPtr  ExtensionPointer;
} PF_SET_EXTENSION_HOOK_INFO, *PPF_SET_EXTENSION_HOOK_INFO;

The member of this structure contains the following information:

ExtensionPointer
Specifies a PacketFilterExtensionPtr data type that points to a filter-hook callback function to register the function with the IP filter driver. If ExtensionPointer is a NULL value, the previously registered function is cleared from the IP filter driver.

Headers

Defined in Pfhook.h. Include Pfhook.h.

See Also

PacketFilterExtensionPtr


Network Upgrade Functions

This section describes network upgrade functions that a network migration DLL can either call or export. These functions are listed in alphabetical order.


DoPostUpgradeProcessing

If a network migration DLL is called during the GUI-mode phase of the operating system upgrade, it must supply a DoPreUpgradeProcessing function.

The DoPostUpgradeProcessing function can:

  • Read a network component's pre-upgrade parameter values from the AnswerFile
  • Display a user interface that lets users specify parameter values, and
  • Write a network component's pre-upgrade parameter values to the registry of the upgraded operating system.
  DoPostUpgradeProcessing(
    IN HWND  hParentWindow,
    IN HKEY  hkeyParams,
    IN PCWSTR  szPreNT5Instance,
    IN PCWSTR  szNT5InfId,
    IN HINF  hinfAnswerFile,
    IN PCWSTR  szSectionName,
    OUT VENDORINFO*  pviVendorInfo,
    IN LPVOID  pvReserved
    );

Parameters

hParentWindow
Handle to the parent window for any user interface displayed by the network migration DLL. If hParentWindow is NULL, then NetSetup is running in unattended mode and the DLL cannot display a user interface.
hkeyParams
Handle to the registry key that contains the parameters of the network component being upgraded. For example, if TCP/IP is the component being upgraded, this function returns a handle to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Service\Tcpip.
szPreNT5Instance
Component's service (device driver) name. For a component that is a not network adapter, szPreNT5Instance is the component's service (device driver) name. For a network adapter, SzPreNT5Instance is the adapter's service name followed by an instance number as the suffix. Multiple instances of the same adapter are differentiated by unique instance numbers. For example, a value of adapter1 specifies the adapter driver's service name (adapter) and the instance (1) of the adapter.
szNT5InfId
Windows 2000 or later hw-id (also known as the device, hardware, or component ID) for the network component to be upgraded. The hw-id is specified in the Models section of the component's INF file for Windows 2000 or later operating systems.
hinfAnswerFile
Handle to the opened AnswerFile.
szSectionName
Name of the network component's OEM-section in the AnswerFile. This section contains the pre-upgrade parameter values of the network component being upgraded. The szSectionName parameter has the following format:

params.postupgrade-ID.OemSection

where

postupgrade-ID is the Windows 2000 or later hw-id of the network component to be upgraded.

pviVendorInfo
Vendor-specific information, formatted as a VENDORINFO structure, which is defined as follows:
typedef struct {
    WCHAR szCompanyName[256];
    WCHAR szSupportNumber[256];
    WCHAR szSupportUrl[256];
    WCHAR szInstructionsToUser[1024];
} VENDORINFO;

The members of the VENDORINFO structure contain the following data:

szCompanyName
Name of the vendor.
szSupportNumber
Telephone number for technical support.
szSupportUrl
URL for a Web site that provides technical support.
szInstructionsToUser
Additional instructions that pertain to the network migration DLL.
pvReserved
Reserved.

Return Value

The DoPostUpgradeProcessing function can return either of the following:

ERROR_SUCCESS
DoPostUpgradeProcessing succeeded.
ERROR_XXX
A Microsoft Win32® error code that specifies the cause of the failure and which causes NetSetup to display an error message, clean up the network migration DLL files, and prompt the user to quit the upgrade of the operating system.

Headers

Declared in OemUpGex.h. Include OemUpGex.h.

Comments

If a network migration DLL's DoPreUpgradeProcessing function sets the NUA_LOAD_POST_UPGRADE flag, NetSetup calls the migration DLL during the GUI mode portion of the upgrade process, which runs on the upgraded operating system.

During the GUI mode phase, the migration DLL can

  • Input, for each network component being upgraded, user-specified parameter values
  • Read pre-upgrade parameter values from the AnswerFile (winnt.sif)
  • Write parameter values to the registry key for which hkeyParams is the handle

NetSetup uses the AnswerFile during the operating system upgrade to migrate network components to the upgraded operating system.

If a network migration DLL is called by NetSetup during the GUI mode phase of the upgrade process, it must export a DoPostUpgradeProcessing function and also a PostUpgradeInitialize function. After NetSetup calls PostUpgradeInitialize, it calls DoPostUpgradeProcessing once for each network component to be upgraded.

The szPreNT5Instance and szNT5InfId supplied by NetSetup to DoPostUpgradeProcessing identify the component that is being upgraded. If the migration DLL is not running in unattended mode, it can display a user interface under the parent window specified by hParentWindow.

The DoPostUpgradeProcessing function reads the AnswerFile section specified by szSectionName to obtain the pre-upgrade parameter values for the component being upgraded. DoPostUpgradeProcessing uses the handle to the AnswerFile supplied at hinfAnswerFile to access the AnswerFile. DoPostUpgradeProcessing uses Setup Xxx functions to access the AnswerFile. For more information on Setup Xxx functions, see the Platform SDK documentation.

From the specified section of the AnswerFile, DoPostUpgradeProcessing reads component-specific parameter values that the migration DLL's DoPreUpgradeProcessing function wrote during the Winnt32 phase of the upgrade process. DoPreUpgradeProcessing calls the appropriate SetupGet XXX function to read the parameter values from the specified AnswerFile section.

The DoPostUpgradeProcessing function writes the parameters obtained from the AnswerFile, as well as any parameter values supplied by the user, to the upgraded component's Parameters registry key, for which hkeyParams is the handle.

DoPostUpgradeProcessing passes a pointer (pviVendorInfo) to NetSetup that points to vendor information formatted as a VENDORINFO structure. NetSetup displays this information if DoPostUpgradeProcessing returns a Win32 error code.

See Also

DoPreUpgradeProcessing, DoPreUpgradeProcessing, PostUpgradeInitialize, PreUpgradeInitialize


DoPreUpgradeProcessing

A network migration DLL must supply a DoPreUpgradeProcessing function. The DoPreUpgradeProcessing function assists in migrating a network component's pre-upgrade parameter values to upgraded operating system.

LONG __stdcall
  DoPreUpgradeProcessing(
    IN HWND  hParentWindow,
    IN HKEY  hkeyParams,
    IN PCWSTR  szPreNT5InfId,
    IN PCWSTR  szNT5InfId,
    IN PCWSTR  szSectionName,
    OUT VENDORINFO*  pviVendorInfo,
    OUT DWORD*  pdwFlags,
    IN LPVOID  pvReserved
    );

Parameters

hParentWindow
Handle to the parent window for any user interface displayed by the network migration DLL. If hParentWindow is NULL, then NetSetup is running in unattended mode and the DLL cannot display a user interface.
hkeyParams
Handle to the registry key that contains the pre-upgrade parameters of the network component being upgraded. For example, if TCP/IP is the component being upgraded, this function returns a handle to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Service\Tcpip.
szPreNT5InfId
Pre-upgrade ID for the network component to be upgraded. szPreNT5InfId is the component's ID in the component's Microsoft Windows NT® version 3.1 or Windows NT version 4.0 INF file.
szPreNT5Instance
Component's service (device driver) name. For a component that is a not network adapter, szPreNT5Instance is the component's service (device driver) name. For a network adapter, SzPreNT5Instance is the adapter's service name followed by an instance number as the suffix. Multiple instances of the same adapter are differentiated by unique instance numbers. For example, a value of adapter1 specifies the adapter driver's service name (adapter) and the instance (1) of the adapter.
szNT5InfId
Windows 2000 or later hw-id (also known as the device, hardware, or component ID) for the network component to be upgraded. The hw-id is specified in the Models section of the component's INF file for Windows 2000 or later operating systems.
szSectionName
Name of the network component's OEM-section in the AnswerFile. The szSectionName parameter has the following format:

params.post-upgrade-ID.OemSection

where

post-upgrade ID is the Windows 2000 or later hw-id of the network component to be upgraded.

The network migration DLL writes component-specific information to this section.

pviVendorInfo
Vendor-specific information, formatted as a VENDORINFO structure, which is defined as follows:
typedef struct {
    WCHAR szCompanyName[256];
    WCHAR szSupportNumber[256];
    WCHAR szSupportUrl[256];
    WCHAR szInstructionsToUser[1024];
} VENDORINFO;

The members of the VENDORINFO structure contain the following data:

szCompanyName
Name of the vendor.
szSupportNumber
Telephone number for technical support.
szSupportUrl
URL for a Web site that provides technical support.
szInstructionsToUser
Additional instructions that pertain to the network migration DLL.
pdwFlags
Specifies zero or requests NetSetup to take a specified action:
Value | Request
Zero | None
NUA_LOAD_POST_UPGRADE | Call the upgrade DLL during GUI mode setup
NUA_REQUEST_ABORT_UPGRADE | Display a message box that prompts the user to either quit or continue the upgrade

pvReserved
Reserved.

Return Value

The DoPreUpgradeProcessing function can return either:

ERROR_SUCCESS
DoPreUpgradeProcessing succeeded.
ERROR_XXX
A Win32 error code that specifies the cause of the failure, and which causes NetSetup to display an error message, clean up the network migration DLL files, and prompt the user to abort the upgrade of the operating system.

Headers

Declared in OemUpGex.h. Include OemUpGex.h.

Comments

After calling a network migration DLL's PreUpgradeInitialize function during the Winnt32 phase of the network upgrade process, NetSetup calls DoPreUpgradeProcessing once for each network component that is being upgraded. DoPreUpgradeProcessing is called before the operating system is installed on the system that is being upgraded.

The DoPreUpgradeProcessing function can perform any of the following actions:

  • Read a network component's pre-upgrade parameter values from the registry.
  • Display a user interface, if not running in unattended mode, to obtain user input.
  • Write the network component's pre-upgrade parameters, along with other component-specific information, to the AnswerFile (winnt.sif).

    NetSetup uses the AnswerFile during the operating system upgrade to migrate network components to the upgraded operating system.

  • Migrate binary data associated with the network component by making appropriate entries in the AnswerFile.

The DoPreUpgradeProcessing function uses the szPreNT5Instance and szNT5InfId parameters supplied by NetSetup to identify the component that is being upgraded.

The DoPreUpgradeProcessing function typically obtains a network component's pre-upgrade parameter values by reading them from the registry. The DoPreUpgradeProcessing function finds these values under the key for which hkeyParams is the handle.

If the migration DLL is not running in unattended mode, it can display a user interface on the pre-upgrade system under the parent window specified by hParentWindow. Through this interface, a user can specify component-specific parameters that the network migration DLL will migrate to the upgraded component.

The DoPreUpgradeProcessing function typically writes a network component's pre-upgrade parameter values to the AnswerFile.

The DoPreUpgradeProcessing function calls NetUpgradeAddSection to add an OEM-section for the component, as well as other component-specific sections, to the AnswerFile. DoPreUpgradeProcessing must use the OEM-section name (szSectionName) specified by NetSetup. DoPreUpgradeProcessing calls NetUpgradeAddLineToSection as many times as required to add entries to sections in the AnswerFile. The information written by the network migration DLL to the AnswerFile must be readable by the Setup Xxx functions of the upgraded operating system. For more information on the Setup Xxx functions, see the Platform SDK documentation.

If a network migration DLL will be loaded during the GUI-mode phase of the network upgrade process, DoPreUpgradeProcessing must set the NUA_LOAD_POST_UPGRADE flag. This flag causes NetSetup to load the migration DLL during the GUI-mode phase.

The DoPreUpgradeProcessing function can set the NUA_REQUEST_ABORT_UPGRADE flag to cause NetSetup to display a message box that prompts the user to stop the upgrade. The user can override this request and continue the upgrade. Typically, DoPreUpgradeProcessing sets this flag to request termination of the upgrade in response to a non-error condition.

If an error condition occurs, DoPreUpgradeProcessing should return a Win32 error code that specifies the cause of the failure. This causes NetSetup to display an error message and clean up the network migration DLL files.

The DoPreUpgradeProcessing function passes a pointer (pviVendorInfo) to NetSetup that points to vendor information formatted as a VENDORINFO structure. NetSetup displays this information if DoPostUpgradeProcessing returns a Win32 error code.

See Also

DoPostUpgradeProcessing, PostUpgradeInitialize, PreUpgradeInitialize


HrGetInstanceGuidOfPreNT5NetCardInstance

The HrGetInstanceGuidOfPreNT5NetCardInstance function supplies a network migration DLL with the globally unique identifier (GUID) of a network adapter.

LONG __stdcall
  HrGetInstanceGuidOfPreNT5NetCardInstance(
    IN PCWSTR  szPreNt5NetCardInstance,
    OUT LPGUID  pguid
    );

Parameters

szPreNt5NetCardInstance
The pre-upgrade instance of the service (device driver) for an adapter. szPreNt5NetCardInstance typically consists of the service name followed by an instance number as a suffix.
pguid
If szPreNt5NetCardInstance existed before the upgrade and could be mapped to its post-upgrade instance, pguid points to the post-upgrade instance GUID for the adapter. Otherwise, pguid is zero.

Return Value

The HrGetInstanceGuidOfPreNT5NetCardInstance function can return either:

ERROR_SUCCESS
HrGetInstanceGuidOfPreNT5NetCardInstance returned a valid pguid value.
ERROR_INVALID_PARAMETER
szPreNt5NetCardInstance is invalid.

Any other return values indicate that the szPreNt5NetCardInstance could not be mapped to its Windows 2000 or later instance GUID.

Headers

Declared in OemUpGex.h. Include OemUpGex.h.

Comments

A network migration DLL must call HrGetInstanceGuidOfPreNT5NetCardInstance in the context of the DLL's DoPostUpgradeProcessing function.

If the miniport driver for a network adapter required the adapter's instance ID before the operating system upgrade, it will probably require the adapter's instance ID after the upgrade. A network migration DLL calls HrGetInstanceGuidOfPreNT5NetCardInstance to obtain the Windows 2000 or later instance GUID for a network adapter.

See Also

DoPostUpgradeProcessing


NetUpgradeAddLineToSection

NetUpgradeAddLineToSection adds a line to a specified section of the AnswerFile.

LONG __stdcall
  NetUpgradeAddLineToSection(
    IN PCWSTR  szSectionName,
    IN PCWSTR  szLine
    );

Parameters

szSectionName
AnswerFile section to which the line is to be added.
szLine
Line to add to the specified AnswerFile section.

Return Value

The NetUpgradeAddLineToSection function can return one of the following:

ERROR_SUCCESS
The specified line was added to the specified section of the AnswerFile.
ERROR_INVALID_PARAMETER
The szSectionName is invalid.
ERROR_INVALID_PARAMETER
The szSectionName was not found in the AnswerFile.
Any other return value indicates a fatal error.

Headers

Declared in OemUpGex.h. Include OemUpGex.h.

Comments

A network migration DLL calls NetUpgradeAddLineToSection in the context of its DoPreUpgradeProcessing function to add a line to a section in the AnswerFile (winnt.sif). NetSetup uses the AnswerFile during the operating system upgrade to migrate network components to the upgraded operating system.

After creating a section in the AnswerFile by calling NetUpgradeAddSection, a network migration DLL calls NetUpgradeAddLineToSection one or more times to add entries to this section. Each call to NetUpgradeAddLineToSection adds a single entry.

A network migration DLL can optionally write either or both of the following keys to a component's OEM-section ([params.component_name.OemSection]) in the AnswerFile:

InfToRunBeforeInstall
Specifies an INF file and an INF file section. NetSetup loads the specified INF file from the temporary directory that contains the network migration DLL. NetSetup executes the commands in the specified INF file section before the upgrade operating system is installed.

This key has the following format:

InfToRunBeforeInstall=INF-filename,section-name

One possible use of this key is to specify a section that contains a DelFile command that deletes the pre-upgrade version of a network driver file. If the pre-upgrade and upgrade versions of such a file have different names, NetSetup does not delete the pre-upgrade version unless directed to do so by a DelFile command.

The following example of an InfToRunBeforeInstall key specifies a section that contains a DelFile command:

InfToRunBeforeInstall=xyz.inf,DeleteFile
InfToRunAfterInstall
Specifies an optional INF file and a section that contains INF commands. If INF-filename is specified, NetSetup looks for the section-name in the specified INF file. NetSetup loads the INF file from the temporary directory that contains the network migration DLL. If a pair of quotation marks ("") is specified for INF-filename, NetSetup looks for the specified section-name in the AnswerFile. NetSetup executes the commands in section-name after the upgrade operating system is installed.

This key has the following format:

InfToRunAfterInstall=INF-filename,section-name

A network migration DLL can call NetUpgradeAddLineToSection to add other types of entries to other sections in the AnswerFile. For example, after adding an Add-registry-section to the AnswerFile, the DLL can add keys and values that NetSetup writes to the registry. The following example shows ISDN keys and values written by the DLL to the AnswerFile:

[adapter2.SectionToRun.AddReg] ; //AddReg section created by DLL
HKR,0\0,IsdnPhoneNumber,0,"111-1111" ; //AddReg entries written by DLL
HKR,0\1,IsdnPhoneNumber,0,"222-2222"
HKR,0\0,IsdnSpid,0,"111"
HKR,0\1,IsdnSpid,0,"222"
HKR,0,IsdnSwitchType,0x00010001,1

See Also

NetUpgradeAddSection


NetUpgradeAddSection

NetUpgradeAddSection adds a section to the AnswerFile.

LONG __stdcall
  NetUpgradeAddSection(
    IN PCWSTR  szSectionName
    );

Parameters

szSectionName
Name of the section to add to the AnswerFile.

Return Value

NetUpgradeAddSection can return one of the following:

ERROR_SUCCESS
Specified section was added to the AnswerFile.
ERROR_INVALID_PARAMETER
Parameter szSectionName is invalid.

Any other return value indicates a fatal error.

Headers

Declared in OemUpGex.h. Include OemUpGex.h.

Comments

A network migration DLL calls NetUpgradeAddSection in the context of its DoPreUpgradeProcessing function to add a section name to the AnswerFile (winnt.sif). NetSetup uses the AnswerFile during the operating system upgrade to migrate network components to upgraded operating system.

Typically, a network migration DLL calls NetUpgradeAddSection to add a component OEM-section to the AnswerFile. A component OEM-section has the following format:

params.post-upgrade-ID.OemSection

where

post-upgrade-ID is the Windows 2000 or later hw-id of the network component to be upgraded.

A network migration DLL can add other sections to the AnswerFile. For example, the DLL can add a section to be run by NetSetup after the upgrade operating system is installed. This section could contain an AddReg directive that references an Add-registry-section added by the network migration DLL.

To add an entry to an AnswerFile section that it has created, the network migration DLL calls NetUpgradeAddLineToSection.

See Also

DoPreUpgradeProcessing, NetUpgradeAddLineToSection


PostUpgradeInitialize

If a network migration DLL is called during the GUI-mode phase of the operating system upgrade, it must supply a PostUpgradeInitialize function. PostUpgradeInitialize supplies the DLL with information about the upgrade environment. PostUpgradeInitialize also supplies NetSetup with vendor information.

LONG __stdcall
  PostUpgradeInitialize(
    IN PCWSTR  swWorkingDir,
    IN NetUpgradeInfo*  pNetUpgradeInfo,
    OUT VENDORINFO*  pviVendorInfo,
    OUT LPVOID  pvReserved
    );

Parameters

swWorkingDir
Complete path of the directory in which the network migration DLL stored temporary files during the Winnt32 phase of the operating system upgrade and which NetSetup supplied to the DLL's PreUpgradeInitialize function.
pNetUpgradeInfo
Source and target operating systems involved in the upgrade. This information is formatted as a NetUpgradeInfo structure, which is defined as follows:
typedef struct NetUpgradeInfo {
    ProductInfo From;
    ProductInfo To;
};

The members of the NetUpgradeInfo structure contain the following data:

From
Operating system from which the component is being upgraded. This information is formatted as a ProductInfo structure, which is defined as follows:
typedef struct ProductInfo {
    PRODUCTTYPE  ProductType;
    DWORD        dwBuildNumber;
};

The members of the ProductInfo structure contain the following data:

ProductType

Operating system from which the component is being upgraded as one of the following:

NT_SERVER

Microsoft Windows NT Server

NT_WORKSTATION

Microsoft Windows NT Workstation

UNKNOWN

Unknown product type

dwBuildNumber

Build number of the operating system from which the component is being upgraded as either of the following:

1057

Microsoft Windows NT version 3.51

1381

Microsoft Windows NT version 4.0

To
Operating system to which the component is being upgraded. This information is formatted as a ProductInfo structure, which is defined as follows:
typedef struct ProductInfo {
    PRODUCTTYPE  ProductType;
    DWORD        dwBuildNumber;
};

The members of the ProductInfo structure contain the following data:

ProductType

Operating system to which the component is being upgraded as one of the following:

NT_SERVER

Microsoft Windows NT Server

NT_WORKSTATION

Microsoft Windows NT Workstation

UNKNOWN

Unknown product type

dwBuildNumber

Build number of the operating system to which the component is being upgraded as either of the following:

2195

Microsoft Windows 2000

2416 or later

Microsoft Windows XP

pviVendorInfo
Vendor information formatted as a VENDORINFO structure, which is defined as follows:
typedef struct {
    WCHAR szCompanyName[256];
    WCHAR szSupportNumber[256];
    WCHAR szSupportUrl[256];
    WCHAR szInstructionsToUser[1024];
} VENDORINFO;

The members of the VENDORINFO structure contain the following data:

szCompanyName
Name of the vendor.
szSupportNumber
Vendor's telephone number for technical support.
szSupportUrl
URL for the vendor's web site that provides technical support.
szInstructionsToUser
Additional instructions that pertain to the upgrade DLL.
pvReserved
Reserved.

Return Value

PostUpgradeInitialize can return one of the following:

ERROR_SUCCESS
The migration DLL found one or more installed components.
ERROR_XXX
A Win32 error code that causes NetSetup to display an error message, clean up the network migration DLL files, and prompt the user to quit the upgrade of the operating system.

Headers

Declared in OemUpGex.h. Include OemUpGex.h.

Comments

NetSetup calls a network migration DLL's PreUpgradeInitialize function once during the GUI-mode phase of the operating system upgrade. NetSetup calls PreUpgradeInitialize before calling the DLL's DoPostUpgradeProcessing function.

The PostUpgradeInitialize function supplies the network migration DLL with information about the source operating system and the target operating system. Specifically, the PostUpgradeInitialize function specifies the product type (Microsoft Windows NT Workstation or Microsoft Windows NT Server) and build number of:

  • The product type and build number of the operating system being upgraded
  • The product type and build number of the operating system being installed

The PostUpgradeInitialize function also supplies the complete path to the directory in which the network migration DLL stored temporary files during the Winnt32 phase of the operating system upgrade.

The PostUpgradeInitialize function passes a pointer (pviVendorInfo) to NetSetup that points to vendor information formatted as a VENDORINFO structure. NetSetup displays this information if PostUpgradeInitialize returns a Win32 error code.

If an error occurs, PostUpgradeInitialize returns a Win32 error code. NetSetup reports the error to the user, cleans up the upgrade DLL files, and asks the user to quit or continue the installation of the operating system.

See Also

DoPostUpgradeProcessing, DoPreUpgradeProcessing, PreUpgradeInitialize


PreUpgradeInitialize

A network migration DLL must supply a PreUpgradeInitialize function. PreUpgradeInitialize supplies the DLL with information about the upgrade environment. The PreUpgradeInitialize function also supplies NetSetup with vendor information and can cause NetSetup to display a message that prompts the user to abort the upgrade of the operating system.

LONG __stdcall
  PreUpgradeInitialize(
    IN PCWSTR  swWorkingDir,
    IN NetUpgradeInfo*  pNetUpgradeInfo,
    OUT VENDORINFO*  pviVendorInfo,
    OUT DWORD*  pdwFlags,
    OUT NetUpgradeData*  pNetUpgradeData
    );

Parameters

swWorkingDir
Complete path of the directory in which the network migration DLL must store temporary files. The DLL will be able to access this directory when the DLL runs in the GUI-mode phase of the upgrade.
pNetUpgradeInfo
Source and target operating systems involved in the upgrade. This information is formatted as a NetUpgradeInfo structure, which is defined as follows
typedef struct NetUpgradeInfo {
    ProductInfo From;
    ProductInfo To;
};

The members of the NetUpgradeInfo structure contain the following data:

From
Operating system from which the component is being upgraded. This information is formatted as a ProductInfo structure, which is defined as follows:
typedef struct ProductInfo {
    PRODUCTTYPE  ProductType;
    DWORD        dwBuildNumber;
};

The members of the ProductInfo structure contain the following data:

ProductType

Operating system from which the component is being upgraded as one of the following:

NT_SERVER

Microsoft Windows NT Server

NT_WORKSTATION

Microsoft Windows NT Workstation

UNKNOWN

Unknown product type

dwBuildNumber

Build number of the operating system from which the component is being upgraded as either of the following:

1057

Microsoft Windows NT version 3.51

1381

Microsoft Windows NT version 4.0

To
Operating system to which the component is being upgraded. This information is formatted as a ProductInfo structure, which is defined as follows:
typedef struct ProductInfo {
    PRODUCTTYPE  ProductType;
    DWORD        dwBuildNumber;
};

The members of the ProductInfo structure contain the following data:

ProductType

Operating system to which the component is being upgraded as one of the following:

NT_SERVER

Microsoft Windows NT Server

NT_WORKSTATION

Microsoft Windows NT Workstation

UNKNOWN

Unknown product type

dwBuildNumber

Build number of the operating system to which the component is being upgraded as either of the following:

2195

Microsoft Windows 2000

2416 or later

Microsoft Windows XP

pviVendorInfo
Information about the vendor formatted as a VENDORINFO structure, which is defined as follows:
typedef struct {
    WCHAR szCompanyName[256];
    WCHAR szSupportNumber[256];
    WCHAR szSupportUrl[256];
    WCHAR szInstructionsToUser[1024];
} VENDORINFO;

The members of the VENDORINFO structure contain the following data:

szCompanyName
Name of the vendor.
szSupportNumber
Vendor's telephone number for technical support.
szSupportUrl
URL for the vendor's web site that provides technical support.
szInstructionsToUser

Additional instructions that pertain to the upgrade DLL.

pdwFlags
Specifies zero or requests NetSetup to take a specified action:
Value | Request
Zero | None
NUA_REQUEST_ABORT_UPGRADE | Display a message box that prompts the user to quit the upgrade of the operating system.

pNetUpgradeData
Services that NetSetup should not delete before upgrading the operating system. This information is formatted as a NetUpgradeDataTag structure, which is defined as follows:
typedef struct NetUpgradeDataTag{
    LPTSTR  mszServicesNotToBeDeleted;
} NetUpgradeData;

The member of the NetUpgradeDataTag structure contains the following data:

mszServicesNotToBeDeleted
A MULTI_SZ value that specifies a list of services. Each entry in this list specifies a service that should not be deleted by NetSetup during the upgrade process. All other services (those not listed in mszServicesNotToBeDeleted) will be deleted and then reinstalled by NetSetup during the upgrade process.

Return Value

The PreUpgradeInitialize function can return either:

ERROR_SUCCESS
Migration DLL found one or more installed components.
ERROR_XXX
A Win32 error code that causes NetSetup to display an error message, clean up the network migration DLL files, and prompt the user to quit the upgrade of the operating system.

Headers

Declared in OemUpGex.h. Include OemUpGex.h.

Comments

NetSetup calls a network migration DLL's PreUpgradeInitialize function once during the Winnt32 phase of the operating system upgrade. NetSetup calls PreUpgradeInitialize before calling the DLL's DoPreUpgradeProcessing function.

PreUpgradeInitialize supplies the network migration DLL with information about the source operating system and the target operating system. Specifically, the PreUpgradeInitialize function specifies the product type (Microsoft Windows NT Workstation or Microsoft Windows NT Server) and build number of:

  • The operating system being upgraded
  • The operating system being installed

The PreUpgradeInitialize function passes a pointer (pviVendorInfo) to NetSetup that points to vendor information formatted as a VENDORINFO structure. NetSetup displays this information if PreUpgradeInitialize returns a Win32 error code.

If an error occurs, PreUpgradeInitialize returns a Win32 error code. NetSetup reports the error to the user, cleans up the upgrade DLL files, and asks the user to quit or continue the installation of the operating system.

See Also

DoPreUpgradeProcessing, PostUpgradeInitialize, DoPostUpgradeProcessing


Windows Sockets Support Reference

The Windows Sockets Support Reference documents functions that are implemented in user-mode dynamic-link libraries (DLLs) to support communications between specific transports and clients of the Windows Sockets interface.

There are two types of functions specified in the DLLs:

  • Direct reference functions allow Windows Sockets applications that use TCP/IP to benefit from using a system area network (SAN) without modification. A SAN service provider DLL must implement these functions and provide them to the Windows Sockets switch. Windows Sockets Direct is part of:
    • Microsoft® Windows® 2000 Datacenter Server
    • Microsoft® Windows® 2000 Advanced Server SP2
    • Microsoft® Windows® 2000 Server Applicance Kit SP2
    • Microsoft® Windows® .NET Server
  • Helper functions are system-defined WSHXxx functions that make up the interface for a Windows Sockets Helper DLL. This interface is implemented for a specific transport and provides the support required for Windows Sockets applications to use that transport.

This information is described in the following sections:

Windows Sockets Direct Reference

Windows Sockets Helper Functions


Windows Sockets Direct Reference

A SAN service provider DLL implements the Windows Sockets Direct functions to create a Windows Sockets service provider that services a system area network (SAN). A SAN service provider lets Windows Sockets applications that use TCP/IP use a SAN transparently. Windows Sockets Direct is part of:

  • Microsoft® Windows® 2000 Datacenter Server
  • Microsoft® Windows® 2000 Advanced Server SP2
  • Microsoft® Windows® 2000 Server Applicance Kit SP2
  • Microsoft® Windows® .NET Server

The Windows Sockets Direct Reference elements consist of:

  • Functions of the Windows Sockets service provider interface (SPI) that a SAN service provider implements.
  • Functions that extend Windows Sockets SPI for use with a SAN.
  • Structures used by SAN service providers.

These API elements are described in the following sections:

Windows Sockets Direct SPI Reference

Windows Sockets Direct Extensions

Windows Sockets Direct Structures

For an overview of how Windows Sockets Direct provides performance benefits between two endpoints that exist on the same SAN, and for information on creating a SAN service provider DLL, see the Windows Sockets Direct.


Windows Sockets Direct SPI Reference

This reference section documents the subset of the Windows Sockets service provider interface (SPI) functions that are exported by a SAN service provider.

Note These SPI functions are defined in Ws2spi.h and require Windows Sockets version 2.0., except for the WSPStartupEx function, which is defined in Ws2san.h and requires Windows Sockets version 2.2.

The complete set of Windows SPI functions is documented in the Platform SDK documentation, however, it does not include SAN-specific information. Writers of SAN service providers should refer to the Windows Sockets Direct SPI Reference instead.

A SAN service provider must export all of the Windows Sockets Direct SPI functions described in the Windows Sockets Direct SPI Reference. If a SAN service provider does not support quality of service (QOS), its WSPGetQOSByName function must return the error WSAEOPNOTSUPP.

The following topics provide more information about the Windows Sockets Direct SPI functions:

WSPAccept

WSPBind

WSPCleanup

WSPCloseSocket

WSPConnect

WSPDuplicateSocket

WSPEnumNetworkEvents

WSPEventSelect

WSPGetOverlappedResult

WSPGetQOSByName

WSPGetSockOpt

WSPIoctl

WSPListen

WSPRecv

WSPSend

WSPSetSockOpt

WSPSocket

WSPStartupEx


WSPAccept

WSPAccept conditionally accepts a connection, based on the return value of a condition function.

SOCKET
  WSPAccept(
    IN SOCKET  s,
    OUT struct sockaddr FAR  *addr,
    IN/OUT LPINT  addrlen,
    IN LPCONDITIONPROC  lpfnCondition,
    IN DWORD  dwCallbackData,
    OUT LPINT  lpErrno
    );

Parameters

s
Descriptor that identifies a socket which is listening for connections as a result of a call to the SAN service provider's WSPListen function.
addr
Pointer to a buffer into which the SAN service provider copies the IP address of the remote connecting entity.
addrlen
Pointer to a variable that receives the size, in bytes, of the buffer at addr.
lpfnCondition
Pointer to a condition function supplied by the Windows Sockets switch. The SAN service provider calls this condition function to accept or reject a connection. The condition function is defined as:
int CALLBACK
  ConditionFunc(
    IN LPWSABUF  lpCallerId,
    IN LPWSABUF  lpCallerData,
    IN/OUT LPQOS  lpSQOS,
    IN/OUT LPQOS  lpGQOS,
    IN/OUT LPWSABUF  lpCalleeId,
    IN/OUT LPWSABUF  lpCalleeData,
    OUT GROUP FAR  *g,
    IN DWORD  dwCallbackData
    );

The parameters of this function are defined as:

lpCallerId
Pointer to a WSABUF structure that contains the address of the remote connecting entity.
lpCallerData
Pointer to a WSABUF structure that contains any user data that was included with the incoming connection request.
lpSQOS
Pointer to a QOS structure that contains flow specifications for socket s supplied to the WSPAccept function. For more information about QOS, see the Platform SDK documentation.
lpGQOS
Reserved.
lpCalleeId
Pointer to a WSABUF structure into which the switch copies the identifier for the user data at lpCalleeData.
lpCalleeData
Pointer to a WSABUF structure that can contain user data that the SAN service provider must pass back to the remote connecting entity.
g
Reserved.
dwCallbackData
Context information related to the connection/acceptance request.
dwCallbackData
Callback data to be passed back to the Windows Socket switch as the value of the condition function's dwCallbackData parameter. The SAN service provider does not interpret this parameter.
lpErrno
Pointer to a variable that receives the error code.

Return Value

Returns a value of type SOCKET that is a descriptor for the accepted socket, if successful; otherwise, returns INVALID_SOCKET and, at lpErrno, one of the following error codes:

WSAECONNREFUSED
Connection request was forcefully rejected as indicated by CF_REJECT.
WSAENETDOWN
Network subsystem failure.
WSAEFAULT
Value of addrlen parameter is too small, or the condition function to which lpfnCondition points is not part of the user address space.
WSAEINVAL
Indicates one of the following: the WSPListen function was not called prior to calling WSPAccept, parameter g specified in the condition function is not a valid value, the return value of the condition function is not valid, or any case where the specified socket is in an invalid state.
WSAEMFILE
Queue is nonempty upon entry to WSPAccept; no socket descriptors available.
WSAENOBUFS
No buffer space available.
WSAENOTSOCK
Descriptor does not describe a socket.
WSAEOPNOTSUPP
Referenced socket is not a type that supports connection-oriented service.
WSATRY_AGAIN
Acceptance of the connection request was deferred as indicated in the return value of the condition function (CF_DEFER).
WSAEWOULDBLOCK
No connections are present to be accepted.
WSAEACCES
Connection request withdrawn or timed out.

Headers

Defined in Ws2spi.h. Include Ws2spi.h. Requires Windows Sockets version 2.0.

Comments

In response to a SAN service provider's signaling a network event object, the Windows Sockets switch calls the SAN service provider's WSPEnumNetworkEvents function to receive event codes. The event code for an incoming connection request that previously arrived on the listening local socket is FD_ACCEPT. Upon receiving the FD_ACCEPT event code, the switch calls the SAN service provider's WSPAccept function to accept or reject an incoming connection request. After the switch calls WSPAccept, the SAN service provider resets the event object so that the SAN service provider can again signal an event.

WSPAccept extracts the first connection request on the listening socket's queue of pending connection requests. To accept or reject the connection request, the SAN service provider must call the condition function that the switch passes to WSPAccept. The condition function must be executed in the same thread as WSPAccept.

If the switch's condition function returns CF_REJECT to reject the connection request, or if some other problem prevents the connection from being fully established, the SAN service provider should return the appropriate error code.

If the switch's condition function returns CF_DEFER to indicate that an accept or reject decision cannot be made immediately, the SAN service provider returns the WSATRY_AGAIN error code and does not reset the event object. When the switch is ready to take action on the connection request, it calls the SAN service provider's WSPAccept function again and returns either CF_ACCEPT or CF_REJECT as a return value from its condition function.

If the switch calls WSPAccept when no pending connections are present on the listening socket's queue, WSPAccept returns the error code WSAEWOULDBLOCK.

If the switch's condition function returns CF_ACCEPT to accept the connection request, WSPAccept creates a new socket. This socket has the same properties as the original local socket. As described in Accepting Connection Requests, a SAN service provider must call the WPUCreateSocketHandle function to allocate a descriptor for the new socket. The switch intercepts this up call and returns a socket descriptor. The SAN service provider must store this descriptor in its internal data structure for the new socket. Finally, the SAN service provider returns its own descriptor for the socket to complete the WSPAccept call. The switch must supply the SAN service provider's internal descriptor for the new socket when calling the SAN service provider's functions, while the SAN service provider must supply the switch's socket descriptor in up calls (calls prefixed with WPU) to the switch.

The SAN service provider uses the return value of the switch's condition function to indicate to the remote connecting entity whether it accepts or refuses the connection request. If the switch's condition function returns CF_DEFER, the SAN service provider should indicate that it accepts the connection request and should keep the connection request in its queue of connection requests. After the switch later calls the SAN service provider's WSPAccept function to accept or reject the deferred connection request, the switch's condition function can return either the CF_ACCEPT or CF_REJECT value. If the switch's condition function returns CF_REJECT, the SAN service provider should tear down the already established connection.

If the connection request is accepted, the switch cannot use the new accepted socket to accept more connections. Also if the connection request is accepted, the SAN service provider passes the IP address of the remote connecting entity to the switch. The original socket remains open and in listening mode.

The SAN service provider must supply the address of the remote connecting entity and any user data that was sent along with the incoming connection request at the lpCallerId and lpCallerData parameters of the condition function. If no caller identifier or caller data is available, the SAN service provider sets the corresponding parameter to NULL.

If the SAN service provider supports quality of service (QOS), it specifies flow parameters for socket s. The SAN service specifies flow parameters for both transmission and reception, and specifies any additional provider-specific parameters at the lpSQOS parameter of the condition function. A SAN service provider specifies a NULL value for lpSQOS to indicate that no QOS negotiation is possible. A non-NULL lpSQOS pointer indicates that a QOS negotiation will occur or that the SAN service provider is prepared to accept the QOS request without negotiation.

The switch uses the lpCalleeData parameter of the condition function to supply user data back to the remote connecting entity. The SAN service provider must allocate a WSABUF structure to provide storage for this data.

If the SAN service provider does not support passing user data back to the remote connecting entity, it sets the len member of this WSABUF structure to zero.

If the SAN service provider supports passing user data back to the remote connecting entity, it allocates a buffer to which the buf member of WSABUF points and sets the len member of WSABUF to the maximum number of bytes of data that the condition function can copy into the buffer. After the condition function copies the data, it updates the len member of WSABUF to indicate the actual number of bytes copied.

If the condition function does not pass any user data back to the connecting entity, it sets the len member of WSABUF to zero.

The SAN service provider passes the value that the switch passed as the dwCallbackData parameter in the original WSPAccept call to the dwCallbackData parameter for the condition function. This value is interpreted only by the Windows Sockets switch. The switch can pass context information from the WSPAccept call to the condition function to provide the condition function with any additional information required to determine whether to accept the connection. A typical usage of this functionality is to pass a (suitably cast) pointer to a data structure containing references to application-defined objects with which this socket is associated.

See Also

WSABUF, WSPEnumNetworkEvents, WSPListen, WSPRecv


WSPBind

WSPBind associates the local IP address, or name, of a network interface with a socket. This network interface is serviced by the SAN service provider.

int
  WSPBind(
    IN SOCKET  s,
    IN const struct sockaddr FAR  *name,
    IN int  namelen,
    OUT LPINT  lpErrno
    );

Parameters

s
Descriptor that identifies an unbound socket.
name
Pointer to a sockaddr structure that contains the address to assign to the socket. The sockaddr structure is defined as:
sockaddr {
    short     sa_family;
    char      sa_data[14];
    };

Except for the sa_family member, the contents of sockaddr are expressed in network byte order. The SAN service provider does not strictly interpret the name parameter as a pointer to a sockaddr structure. The name parameter is cast this way for Windows Sockets compatibility. The SAN service provider interprets the actual structure as a sockaddr_in structure, which is used with the TCP/IP protocol. The sockaddr_in structure is defined as:

struct sockaddr_in {
    short   sin_family;
    u_short sin_port;
    struct  in_addr sin_addr;
    char    sin_zero[8];
    };
namelen
Size, in bytes, of the buffer at name.
lpErrno
Pointer to a variable that receives the error code.

Return Value

Returns zero if successful; otherwise, returns SOCKET_ERROR and, at lpErrno, one of the following error codes:

WSAENETDOWN
Network subsystem failed.
WSAEADDRNOTAVAIL
Specified address is not a valid address for the computer.
WSAEFAULT
The name or namelen parameter is not a valid part of the user address space, the namelen parameter is too small, the name parameter contains incorrect address format for the associated address family, or the first two bytes of the memory block specified by name do not match the address family associated with the socket descriptor s.
WSAEINVAL
Socket is already bound to an address.
WSAENOBUFS
Not enough buffers available, too many connections.
WSAENOTSOCK
Descriptor is not a socket.

Note that a SAN service provider does not support the following error codes for WSPBind:

WSAEINPROGRESS
The Windows Sockets switch never issues cancel blocking calls to a SAN service provider.
WSAEADDRINUSE
The Windows Sockets switch, in conjunction with the TCP/IP provider, handles address reuse.

Headers

Defined in Ws2spi.h. Include Ws2spi.h. Requires Windows Sockets version 2.0.

Comments

The Windows Sockets switch calls a SAN service provider's WSPBind function to assign a name to an unnamed socket, thereby establishing a local association for the socket. The switch previously called the WSPSocket function to create the unnamed socket. The switch calls the WSPBind function before calling the WSPConnect or WSPListen functions.

The SAN service provider must interpret the information to which name points as a sockaddr_in structure, which is used with the TCP/IP protocol. The sin_family member of sockaddr_in must contain the AF_INET address family that was used to create the socket. Otherwise, the SAN service provider returns the WSAEFAULT error code.

In most cases, the switch passes a name that is associated with one of the network interface cards (NICs) serviced by the SAN service provider. This name is fully qualified; that is, the sin_port and sin_addr members of its sockaddr_in structure are both set to nonzero values. The switch obtains the IP address of one of the SAN service provider's NICs from the TCP/IP provider.

If the switch requires a socket to listen for connection requests on all NICs serviced by the SAN service provider, the switch passes the wildcard IP address. The wildcard IP address has the sin_addr member of its sockaddr_in structure set to zero. If the wildcard IP address is specified using the Internet standard ".'' (dotted) notation, it is 0.0.0.0.

The switch can call WSPBind to bind more than one socket to the same local name; that is, to the same port. The switch can use sockets that are bound to the same port to initiate multiple connections from that port. Each of these connections are independent from the other. Note that if more than one socket is listening on the same port, only one should receive connection requests.

See Also

WSPConnect, WSPListen, WSPSocket


WSPCleanup

WSPCleanup terminates use of the SAN service provider.

int
  WSPCleanup(
    OUT LPINT  lpErrno
    );

Parameters

lpErrno
Pointer to a variable that receives the error code.

Return Value

Returns zero if successful; otherwise, returns SOCKET_ERROR and, in lpErrno, one of the following error codes:

WSANOTINITIALISED
Successful WSPStartupEx call did not occur before the WSPCleanup call.
WSAENETDOWN
Network subsystem failed.

Note that a SAN service provider does not support the WSAEINVAL error code for WSPCleanup.

Headers

Defined in Ws2spi.h. Include Ws2spi.h. Requires Windows Sockets version 2.0.

Comments

The Windows Sockets switch must call a SAN service provider's WSPStartupEx function before it can start using that SAN service provider. After the switch no longer requires a SAN service provider, it calls the WSPCleanup function to terminate use of the SAN service provider and to allow the SAN service provider to release any resources that the SAN service provider allocated for operations requested by the switch.

The switch can call a SAN service provider's WSPStartupEx function more than once. For each WSPStartupEx call, the switch must issue a corresponding WSPCleanup call. The SAN service provider must keep an internal reference count of the number of its open instances. Calls to the SAN service provider's WSPCleanup function decrement this internal reference count. Only the final WSPCleanup call does the actual cleanup (that is, when the internal reference count reaches zero).

During cleanup, the SAN service provider releases resources that it previously allocated and cancels any pending calls or uncompleted asynchronous operations.

To cancel a pending call that the switch initiated or forwarded

  1. A SAN service provider calls the WPUCompleteOverlappedRequest function to complete the overlapped operation that is related to that pending call.
  2. In this call, the SAN service provider passes a pointer to a WSAOVERLAPPED structure for the overlapped operation, and also passes the WSA_OPERATION_ABORTED error code to specify that the overlapped operation was canceled.
  3. Before calling the WPUCompleteOverlappedRequest function to cancel an overlapped operation, the SAN service provider should release any memory associated with that operation.

During cleanup, the SAN service provider does not signal event objects to post notification messages. For example, during cleanup, the SAN service provider does not post notification messages that indicate the arrival of an incoming connection (FD_ACCEPT) or the completion of a connection operation (FD_CONNECT).

Any sockets that are open during a final WSPCleanup call are reset and automatically released as if the WSPClosesocket function was called.

A SAN service provider must ensure that its WSPCleanup function leaves the operating environment in a state in which the switch can immediately call the SAN service provider's WSPStartupEx function to re-establish usage.

See Also

WSPCloseSocket, WSPStartupEx


WSPCloseSocket

The WSPCloseSocket function closes a socket.

int
  WSPCloseSocket(
    IN SOCKET  s,
    OUT LPINT  lpErrno
    );

Parameters

s
Descriptor that identifies a socket.
lpErrno
Pointer to a variable that receives the error code.

Return Value

Returns zero if successful; otherwise, returns SOCKET_ERROR and, at lpErrno, one of the following error codes:

WSAENETDOWN
Network subsystem failed.
WSAENOTSOCK
Descriptor is not a socket.

Note that a SAN service provider does not support the following error codes for WSPCloseSocket:

WSAEINPROGRESS
The Windows Sockets switch never issues cancel blocking calls to a SAN service provider.
WSAEWOULDBLOCK
The Windows Sockets switch handles graceful disconnect.

Headers

Defined in Ws2spi.h. Include Ws2spi.h. Requires Windows Sockets version 2.0.

Comments

The Windows Sockets switch calls a SAN service provider's WSPCloseSocket function to release a socket. After the WSPCloseSocket completes, the SAN service provider should fail further references to the closed socket with the error WSAENOTSOCK.

If the WSPCloseSocket function releases the last reference to an underlying socket, the SAN service provider discards the associated naming information and queued data. The SAN service provider cancels any pending calls or asynchronous operations for the socket.

To cancel a pending call

  1. A SAN service provider calls the WPUCompleteOverlappedRequest function to complete the overlapped operation that is related to that pending call.
  2. In this call, the SAN service provider passes a pointer to a WSAOVERLAPPED structure for the overlapped operation. It also passes the WSA_OPERATION_ABORTED error code to specify that the overlapped operation was canceled because the socket was closed.
  3. Before the SAN service provider completes overlapped operations, it should release any memory associated with those overlapped operations

During socket closure, the SAN service provider does not signal event objects on that socket to post notification messages. For example, the SAN service provider does not post notification messages that indicate the arrival of an incoming connection (FD_ACCEPT) or the completion of a connection operation (FD_CONNECT).

The Windows Sockets switch fully implements the semantics required by graceful disconnect and associated socket options such as SO_LINGER, SO_DONTLINGER, and nonblocking close. The switch calls the SAN service provider's WSPCloseSocket function only for a hard close on the socket--that is, to close the socket's connection and cancel all outstanding requests on the socket. Any subsequent WSPRecv call from the remote peer of the connection fails with WSAECONNRESET.

For more information on the procedure that a SAN service provider performs to close a socket, see Closing a SAN Socket.

See Also

WSPRecv, WSPSocket


WSPConnect

WSPConnect establishes the connection of a socket to a peer, exchanges connect data, and specifies required quality of service based on the supplied flow specification.

int
  WSPConnect(
    IN SOCKET  s,
    IN const struct sockaddr FAR  *name,
    IN int  namelen,
    IN LPWSABUF  lpCallerData,
    OUT LPWSABUF  lpCalleeData,
    IN LPQOS  lpSQOS,
    IN LPQOS  lpGQOS,
    OUT LPINT  lpErrno
    );

Parameters

s
Descriptor that identifies an unconnected socket.
name
Pointer to a sockaddr structure that contains the address of the remote peer to which the socket connects. The sockaddr structure is defined as:
sockaddr {
    short     sa_family;
    char      sa_data[14];
    };

Except for the sa_family member, contents of sockaddr are expressed in network byte order. The SAN service provider does not strictly interpret the name parameter as a pointer to a sockaddr structure. The name parameter is cast this way for Windows Sockets compatibility. The SAN service provider interprets the actual structure as a sockaddr_in structure, which is used with the TCP/IP protocol. The sockaddr_in structure is defined as:

struct sockaddr_in {
    short   sin_family;
    u_short sin_port;
    struct  in_addr sin_addr;
    char    sin_zero[8];
    };
namelen
Size, in bytes, of the buffer at name.
lpCallerData
Pointer to a WSABUF structure that contains any user data that the SAN service provider transmits to the remote peer during connection establishment.
lpCalleeData
Pointer to a WSABUF structure that receives any user data that the SAN service provider receives from the remote peer during connection establishment.
lpSQOS
Pointer to a QOS structure that contains flow specifications for socket s, one for each direction. For information about QOS, see the Platform SDK documentation.
lpGQOS
Reserved.
lpErrno
Pointer to a variable that receives the error code.

Return Value

Returns zero if successful; otherwise, returns SOCKET_ERROR and, at lpErrno, one of the following error codes:

WSAENETDOWN
Network subsystem failed.
WSAEALREADY
Nonblocking WSPConnect call is in progress on the specified socket.

Note In order to preserve backward compatibility, this error is reported as WSAEINVAL to Windows Sockets version 1.1 applications that link to either Winsock.dll or Wsock32.dll.

WSAEADDRNOTAVAIL
Remote address is not a valid address (for example, ADDR_ANY).
WSAECONNREFUSED
Attempt to connect was rejected. The switch does not attempt to use the TCP/IP service provider to establish the connection.
WSAECONNRESET
Remote host not set up to listen for connections. The switch does not attempt to use the TCP/IP service provider to establish the connection.
WSAEHOSTUNREACH
Remote host does not exist on the SAN subnet. The switch does not attempt to use the TCP/IP service provider to establish the connection.
WSAEFAULT
The name or namelen parameter is not a valid part of the user address space, the namelen parameter is too small, the buffer length for the lpCalleeData, lpSQOS, or lpGQOS parameter is too small, or the buffer length for lpCallerData parameter is too large.
WSAEINVAL
Parameter s identifies a listening socket.
WSAEISCONN
Socket is already connected.
WSAENETUNREACH
Network cannot currently be reached from host.
WSAENOBUFS
No buffer space available; the socket cannot be connected.
WSAENOTSOCK
Descriptor is not a socket.
WSAEOPNOTSUPP
Flow specifications specified in the lpSQOS parameter cannot be satisfied.
WSAEPROTONOSUPPORT
SAN service provider does not support the lpCallerData parameter.
WSAETIMEDOUT
Attempt to connect timed out without establishing a connection.
WSAEWOULDBLOCK
Socket is marked as nonblocking and the connection cannot be completed immediately.

Note that a SAN service provider does not support the following error codes for WSPConnect:

WSAEADDRINUSE
The local socket is always bound to a local IP address that is fully qualified before WSPConnect is called. That is, not a wildcard address.
WSAEINTR
The Windows Sockets switch never issues cancel blocking calls to a SAN service provider.
WSAEINPROGRESS
The Windows Sockets switch never issues cancel blocking calls to a SAN service provider.
WSAEAFNOSUPPORT
All addresses in the AF_INET address family can be used with this socket.
WSAEACCES
The current version of Windows Sockets Direct does not support SAN service providers handling sockets that receive datagrams. Also, broadcast addresses are not supported.

Headers

Defined in Ws2spi.h. Include Ws2spi.h. Requires Windows Sockets version 2.0.

Comments

The Windows Sockets switch calls a SAN service provider's WSPConnnect function to create a connection from a local socket to the specified destination address and to perform other ancillary operations that occur at connect time. Before calling the WSPConnect function, the switch always calls the SAN service provider's WSPBind function to bind the local socket to a local IP address that is associated with one of the network interface cards (NICs) serviced by the SAN service provider. This IP address is fully qualified; that is, the sin_port and sin_addr members of its sockaddr_in structure are both set to nonzero values.

To establish the connection from a local socket to a remote peer, WSPConnnect requires that the name parameter point to a fully qualified IP address that specifies the address of that remote peer (that is, the name of that remote peer). After the WSPConnnect call completes successfully, the switch can use the socket to send and receive data. If the switch calls WSPConnnect to reconnect a socket that is already connected to a peer, the call fails and returns the WSAEISCONN error code.

The Windows Sockets switch always requests a connection to a local socket in nonblocking mode. To inform the SAN service provider that any subsequent WSPConnect call executes in nonblocking mode and to request notification of connection events, the switch calls the SAN service provider's WSPEventSelect function and passes the FD_CONNECT code and the event object to be associated with that code.

If the SAN service provider's WSPConnect function cannot complete a connection request immediately, the SAN service provider's connection operation proceeds; however, WSPConnect returns with the error WSAEWOULDBLOCK to indicate that the socket is marked as nonblocking and that the connection operation cannot be completed immediately. After the connection operation completes, the SAN service provider can call the Win32® SetEvent function to signal the event object that was previously registered in the WSPEventSelect call. The switch then calls the SAN service provider's WSPEnumNetworkEvents function to obtain the result of the connection operation. To indicate success or the reason for failure of the connection operation, the SAN service provider returns a WSANETWORKEVENTS structure that contains an FD_CONNECT event and possibly an error code associated with FD_CONNECT.

The switch is responsible for allocating memory that is directly or indirectly pointed to by any of the parameters that it specifies.

A SAN service provider can optionally support the following:

Passing user data for the connection to and from the peer. The exact format of the user data is specific to the AF_INET address family and/or the applications involved. If the lpCallerData parameter is NULL, the SAN service provider does not send any user data to the peer. The lpCalleeData parameter points to a WSABUF structure that contains user data that the peer supplied to establish the connection. The switch initially sets the len member of WSABUF to the maximum number of bytes of data that the SAN service provider can copy into the buffer to which the buf member of WSABUF points. If the SAN service provider does not receive any user data from the peer, it sets the len member of this WSABUF structure to zero. The information to which lpCalleeData points is valid after the connection operation completes. The FD_CONNECT code notifies that a connection operation completed.

Quality of service (QOS). If a SAN service provider supports QOS, the switch can use QOS parameters in a connection request to override any previous QOS specification made for the socket through the WSPIoctl function with either the SIO_SET_QOS or SIO_SET_GROUP_QOS codes.

The lpSQOS parameter specifies the flow specifications for socket s, one for each direction, followed by any additional provider-specific parameters. If either the SAN service provider in general or the socket in particular cannot honor the QOS request, the SAN service provider returns the WSAEOPNOTSUPP error code. The sending or receiving flow specification values are ignored, respectively, for any unidirectional sockets. If the switch does not supply provider-specific parameters, it sets the buf and len members of the ProviderSpecific member of the QOS structure to which the lpSQOS points to NULL and zero, respectively. The switch sets the lpSQOS parameter to NULL if it does not supply or forward QOS information.

If a SAN service provider fails the connection request, the switch attempts to use the TCP/IP provider to establish the connection unless the SAN service provider returned one of the following error codes as the result of its connection operation:

WSAECONNRESET
Indicates that no application is listening on the specified port at the destination address
WSAECONNREFUSED
Indicates that the remote application actively refused the connection request
WSAEHOSTUNREACH
Indicates that the destination address does not exist on the SAN subnet

See Also

WSABUF, WSPBind, WSPEnumNetworkEvents, WSPEventSelect, WSPIoctl, WSPRecv, WSPSocket


WSPDuplicateSocket

WSPDuplicateSocket retrieves a WSAPROTOCOL_INFOW structure that can be used to create a new socket descriptor for a shared socket in the context of another process.

int
  WSPDuplicateSocket(
    IN SOCKET  s,
    IN DWORD  dwProcessId,
    OUT LPWSAPROTOCOL_INFOW  lpProtocolInfo,
    OUT LPINT  lpErrno
    );

Parameters

s
Descriptor that identifies a shared socket.
dwProcessId
Identifier of the target process that is to use the shared socket.
lpProtocolInfo
Pointer to a WSAPROTOCOL_INFOW structure that receives the protocol information that can be used to create a descriptor for the shared socket.
lpErrno
Pointer to a variable that receives the error code.

Return Value

Returns zero if successful; otherwise, returns SOCKET_ERROR and, at lpErrno, one of the following error codes:

WSAENETDOWN
Network subsystem failed.
WSAEINVAL
One of the specified parameters was invalid.
WSAEMFILE
No more socket descriptors available.
WSAENOBUFS
No buffer space is available; socket cannot be created.
WSAENOTSOCK
Descriptor is not a socket.

Note that a SAN service provider does not support the WSAEINPROGRESS error code for WSPDuplicateSocket because the switch never issues cancel blocking calls to a SAN service provider.

Headers

Defined in Ws2spi.h. Include Ws2spi.h. Requires Windows Sockets version 2.0.

Comments

The Windows Sockets switch that resides in a source process calls the SAN service provider's WSPDuplicateSocket function to obtain a special WSAPROTOCOL_INFOW structure. The switch uses some interprocess communications (IPC) mechanism to pass the contents of the special WSAPROTOCOL_INFOW to an application that resides in a destination process. The switch in this destination process in turn calls the SAN service provider's WSPSocket function and passes the special WSAPROTOCOL_INFOW to obtain a duplicate descriptor for the shared underlying socket. Note that the switch in the destination process can only use the special WSAPROTOCOL_INFOW once.

The SAN service provider in the source process context must create a WSAPROTOCOL_INFOW structure that a call to the SAN service provider's WSPSocket function in the destination process context can use successfully. The SAN service provider's WSPDuplicateSocket function must return a WSAPROTOCOL_INFOW that defines characteristics of the common underlying socket. The SAN service provider can use the dwProviderReserved member of WSAPROTOCOL_INFOW to store any useful context information, including a duplicate handle.

The switch in a destination process calls the SAN service provider's WSPSocket function to create a duplicate descriptor for the shared underlying socket. The SAN service provider must call the switch's WPUCreateSocketHandle function to allocate a descriptor for the new socket. The SAN service provider must store the descriptor returned by the switch in the SAN service provider's internal data structure for the new socket. Finally, the SAN service provider returns its own descriptor for the socket to complete the WSPSocket call. The application in the destination process must supply the SAN service provider's internal descriptor for the new socket when calling the SAN service provider's functions, while the SAN service provider must supply the switch's socket descriptor in up calls.

The following table illustrates a typical scenario for establishing and using a shared socket.

Source Process | Destination Process
1) WSPSocket, WSPConnect |
2) Request destination process ID |
 | 3) Receive process ID request and respond
4) Receive process ID |
5) Call WSPDuplicateSocket to get special WSAPROTOCOL_INFOW |
6) Send WSAPROTOCOL_INFOW to destination |
 | 7) Receive WSAPROTOCOL_INFOW
 | 8) Call WSPSocket to create descriptor for shared socket
 | 9) Use shared socket for data exchange
 | 10)Call WSPDuplicateSocket back to the original process
 | 11) Send WSAPROTOCOL_INFOW back to source
13) Receive WSAPROTOCOL_INFOW | 12) Call WSPCloseSocket to close shared socket descriptor (but not the socket itself)
14) Call WSPSocket to transfer socket access control back and possibly create new SAN provider socket descriptor |
15) Call WSPClosesocket to close the original socket descriptor if different from the new one |
16) Gracefully terminate the session |
17) Call WSPClosesocket to finally close the socket and associated connection |

Note Although instances of the switch running in different processes can independently use their own descriptors that reference a shared socket for I/O data exchange, these instances of the switch cannot concurrently access the shared socket. The switch implements an access control mechanism. This mechanism ensures that after the switch calls the WSPDuplicateSocket function, the switch does not access the shared socket again until the switch calls the WSPSocket function to explicitly create again a descriptor for the shared socket. Note that a typical scenario for using a shared socket is for a controlling process to create that socket and establish connections to that socket. The controlling process then hands off that socket to other processes that perform I/O data exchange. Such a scenario typically involves the following two socket-duplication operations:

  1. A controlling process duplicates a socket to pass the socket handle to a target process for data exchange
  2. The target process duplicates the socket to return the socket handle to the controlling process for graceful connection closure.

Because socket descriptors are duplicated, and not the underlying shared socket, all of the state associated with a socket is held in common across all duplicate descriptors. For example, if an option value on a descriptor for a shared socket is set in a WSPSetSockOpt call, that option value is subsequently visible from each duplicate descriptor using a WSPGetSockOpt call. A process can call WSPCloseSocket on a duplicate socket descriptor in order to release that descriptor. However, the underlying shared socket remains open until WSPCloseSocket is called on the last remaining descriptor.

See Also

WSAPROTOCOL_INFOW, WSPCloseSocket, WSPConnect, WSPGetSockOpt, WSPSetSockOpt, WSPSocket


WSPEnumNetworkEvents

WSPEnumNetworkEvents reports occurrences of network events for a socket.

int
  WSPEnumNetworkEvents(
    IN SOCKET  s,
    IN WSAEVENT  hEventObject,
    OUT LPWSANETWORKEVENTS  lpNetworkEvents,
    OUT LPINT  lpErrno
    );

Parameters

s
Descriptor that identifies the socket.
hEventObject
Handle to the event object that the SAN service provider subsequently resets.
lpNetworkEvents
Pointer to a WSANETWORKEVENTS structure that receives a record of network events that occurred and any associated error codes. The WSANETWORKEVENTS structure is defined as:
typedef struct _WSANETWORKEVENTS {
    long lNetworkEvents;
    int iErrorCode[FD_MAX_EVENTS];
} WSANETWORKEVENTS, FAR * LPWSANETWORKEVENTS;

The members of this structure contain the following information:

lNetworkEvent
Bitmask that specifies the combination of FD_XXX network events that occurred.
iErrorCode
Array of error codes that are associated with network events in lNetworkEvent. The index of each array element corresponds to the bit position of its associated network event in lNetworkEvent.
lpErrno
Pointer to a variable that receives the error code.

Return Value

Returns zero if successful; otherwise, returns SOCKET_ERROR and, in lpErrno, one of the following error codes:

WSAENETDOWN
Network subsystem failed.
WSAEINVAL
Indicates that one of the specified parameters was invalid.
WSAENOTSOCK
Descriptor is not a socket.

Note that a SAN service provider does not support the WSAEINPROGRESS error code for WSPEnumNetworkEvents because the switch never issues cancel blocking calls to a SAN service provider.

Headers

Defined in Ws2spi.h. Include Ws2spi.h. Requires Windows Sockets version 2.0.

Comments

The Windows Sockets switch calls a SAN service provider's WSPEnumNetworkEvents function to obtain a report of network events that have occurred since the switch's last WSPEnumNetworkEvents call. Because the switch previously called the SAN service provider's WSPEventSelect function to register the occurrence of incoming-connection (FD_ACCEPT) and connection-completed (FD_CONNECT) events with a specific event object, only those events are reported to the switch.

After one or more of the registered events occurs, the SAN service provider can call the Win32® SetEvent function to signal the event object. The switch then calls the SAN service provider's WSPEnumNetworkEvents function to determine the type of events that occurred. The SAN service provider supplies the event information in a WSANETWORKEVENTS structure. The SAN service provider indicates event types in the lNetworkEvents member and any associated error codes in the iErrorCode array member. The index of an element in the error code array corresponds to the position of event bits in the lNetworkEvents member. That is, network events such as FD_CONNECT and FD_ACCEPT can be used to index the error code array. Note that only elements of the error code array that correspond to the bits set in lNetworkEvents are set; other elements are not modified.

The SAN service provider must internally record network events for a socket in a WSANETWORKEVENTS structure. Immediately after completing a WSPEnumNetworkEvents call, the SAN service provider must clear the previously recorded network events from WSANETWORKEVENTS. The SAN service provider can also call the Win32 ResetEvent function to reset the previously signaled event object. In other words, the SAN service provider performs the following operations in the following order to guarantee that subsequent occurrences of network events cause the event object to become signaled:

Records network events

Clears network events after WSPEnumNetworkEvents call

Resets the associated event object

If WSPEnumNetworkEvents fails for some reason (returns SOCKET_ERROR), the SAN service provider neither clears the previously recorded network events from WSANETWORKEVENTS nor resets the previously signaled event object.

The following error codes can be returned along with the corresponding network event:

FD_CONNECT
WSAECONNREFUSED
Attempt to connect was forcefully rejected by the peer.
WSAENETUNREACH
Network cannot be currently reached from this host.
WSAENOBUFS
No buffer space available; socket cannot be connected.
WSAETIMEDOUT
Attempt to connect timed out without establishing a connection.
FD_ACCEPT
WSAENETDOWN
Network subsystem failed.

See Also

WSPEventSelect


WSPEventSelect

WSPEventSelect associates an event object with a socket and a set of network events.

int
  WSPEventSelect(
    IN SOCKET  s,
    IN WSAEVENT  hEventObject,
    IN long  lNetworkEvents,
    OUT LPINT  lpErrno
    );

Parameters

s
Descriptor that identifies the socket.
hEventObject
Handle to the event object that becomes associated with the supplied set of network events.
lNetworkEvents
Bitmask that specifies the combination of FD_XXX network events for the SAN service provider.
lpErrno
Pointer to a variable that receives the error code.

Return Value

Returns zero if successful; otherwise, returns SOCKET_ERROR and, at lpErrno, one of the following error codes:

WSAENETDOWN
Network subsystem failed.
WSAEINVAL
Indicates that one of the specified parameters was invalid, or the specified socket is in an invalid state.
WSAENOTSOCK
Descriptor is not a socket.

Note that a SAN service provider does not support the WSAEINPROGRESS error code for WSPEventSelect because the switch never issues cancel blocking calls to a SAN service provider.

Headers

Defined in Ws2spi.h. Include Ws2spi.h. Requires Windows Sockets version 2.0.

Comments

The Windows Sockets switch calls a SAN service provider's WSPEventSelect function to associate an event object with a socket and a set of network events on which the switch requires notification. The switch specifies that it requires notification only when incoming-connection (FD_ACCEPT) and connection completed (FD_CONNECT) events occur. That is, the switch uses the bitwise OR operator to combine the FD_ACCEPT and FD_CONNECT events before passing them to WSPEventSelect.

The SAN service provider must internally record the occurrence of the specified network events in a WSANETWORKEVENTS structure. After the SAN service provider calls the Win32® SetEvent function to signal the event object indicating that one or more network events occurred, the switch calls the WSPEnumNetworkEvents function to retrieve the contents of WSANETWORKEVENTS and thereby determine which network events occurred.

The WSPEventSelect function automatically sets the specified socket to nonblocking mode.

Note After the SAN service provider successfully records the occurrence of a network event and signals the associated event object, the switch retrieves the state of that network event. After the SAN service provider clears that network event, the SAN service provider takes no further actions related to that network event until the switch implicitly re-enables the setting of that network event and the signaling of the associated event object. To re-enable the settings for the following network events, the switch makes the following function calls:

Network Event | Re-enabling function
FD_ACCEPT | The WSPAccept function, unless the error code returned is WSATRY_AGAIN, indicating that the condition function returned CF_DEFER
FD_CONNECT | NONE

Any call to the re-enabling routine—even one that fails—results in operations that cause the SAN service provider to record the relevant network event and signal the associated event object.

For the FD_ACCEPT network event, network event recording and event-object resetting are level triggered. Level triggered means that if the re-enabling routine is called and the relevant network condition is still valid after the call, the network event is recorded and the associated event object is reset. Using this approach, the switch is event driven rather than concerned with the amount of data that arrives at any given time.

If a network event occurred before the switch calls WSPEventSelect or the re-enabling function, the SAN service provider still records the occurrence of that network event and signals the associated event object, as appropriate. For example, consider the following sequence:

  1. The switch calls the WSPListen function.
  2. An incoming-connection event is received but not yet accepted.
  3. The switch calls the WSPEventSelect function, specifying that it requires notification on incoming-connection (FD_ACCEPT) events for the specified socket. The SAN service provider records the previous FD_ACCEPT event and signals the associated event object immediately.

See Also

WSPAccept, WSPEnumNetworkEvents, WSPListen


WSPGetQOSByName

WSPGetQOSByName initializes a QOS structure based on a named template, or retrieves an enumeration of the available template names.

BOOL
  WSPGetQOSByName(
    IN SOCKET  s,
    IN/OUT LPWSABUF  lpQOSName,
    OUT LPQOS  lpQOS,
    OUT LPINT  lpErrno
    );

Parameters

s
Descriptor that identifies a socket.
lpQOSName
Pointer to a WSABUF structure that either contains the template name or receives an enumeration of the available template names.
lpQOS
Pointer to a QOS structure that receives quality of service (QOS) information. For information about QOS, see the Platform SDK documentation.
lpErrno
Pointer to a variable that receives the error code.

Return Value

Returns TRUE if successful; otherwise, returns FALSE and, at lpErrno, one of the following error codes:

WSAENETDOWN
Network subsystem failed.
WSAENOTSOCK
Descriptor is not a socket.
WSAEFAULT
The lpQOS parameter is not a valid part of the user address space, or the buffer length for lpQOS is too small.
WSAEINVAL
Specified QOS template name is invalid.
WSAEOPNOTSUPP
The SAN service provider does not support QOS.

Headers

Defined in Ws2spi.h. Include Ws2spi.h. Requires Windows Sockets version 2.0.

Comments

The Windows Sockets switch can call a SAN service provider's WSPGetQOSByName function to initialize a quality of service (QOS) structure to a set of values that are appropriate for the SAN. The SAN service provider stores these values in a template that is referenced by a name that is well known to applications and therefore the switch. To retrieve these values, the switch sets the buf member of the WSABUF structure to which lpQOSName points to a Unicode string of nonzero length that contains the template name. In this case, the switch uses lpQOSName as an input (IN) parameter only, and receives QOS values in a QOS structure at the lpQOS output (OUT) parameter.

Alternatively, the switch can call a SAN service provider's WSPGetQOSByName function to retrieve an enumeration of available template names. To retrieve available template names, the switch sets the buf member of the WSABUF structure to which lpQOSName points to a zero-length null-terminated Unicode string. In this case, the SAN service provider overwrites the buffer indicated by buf with a sequence of as many null-terminated Unicode template name strings as are available up to the size of that buffer. The len member of the WSABUF structure to which lpQOSName points indicates the size of the buffer. The list of names itself is terminated by a zero-length Unicode name string. If the switch calls WSPGetQOSByName to retrieve template names, the SAN service provider ignores lpQOS.

A SAN service provider is not required to support QOS, but if it does, it implements full functionality for WSPGetQOSByName. If it does not support QOS, its WSPGetQOSByName function must at least return the WSAEOPNOTSUPP error code.

See Also

WSABUF, WSPIoctl


WSPGetSockOpt

WSPGetSockOpt retrieves the current value of a socket option.

int
  WSPGetSockOpt(
    IN SOCKET  s,
    IN int  level,
    IN int  optname,
    OUT char FAR  *optval,
    IN/OUT LPINT  optlen,
    OUT LPINT  lpErrno
    );

Parameters

s
Descriptor that identifies a socket.
level
Level at which the option is defined; the only supported level is SOL_SOCKET.
optname
Socket option for which the value is to be retrieved.
optval
Pointer to a buffer that receives the current value for the socket option that is specified in optname.
optlen
Pointer to a variable that receives the size of the value at optval.
lpErrno
Pointer to a variable that receives the error code.

Return Value

Returns zero if successful; otherwise, returns SOCKET_ERROR and, at lpErrno, one of the following error codes:

WSAENETDOWN
Network subsystem failed.
WSAEFAULT
The optval or optlen parameter is not a valid part of the user address space, or the optlen parameter is too small.
WSAEINVAL
The level is unknown or invalid.
WSAENOPROTOOPT
Option is unknown or unsupported by the socket's address family.
WSAENOTSOCK
Descriptor is not a socket.

Note that a SAN service provider does not support the WSAEINPROGRESS error code for WSPGetSockOpt.

Headers

Defined in Ws2spi.h. Include Ws2spi.h. Requires Windows Sockets version 2.0.

Comments

The Windows Sockets switch calls a SAN service provider's WSPGetSockOpt function to retrieve the current value of an option for a socket, in any state. Options affect socket operations, such as the amount of data that the switch can transfer on the socket for each data transfer operation.

The switch originally sets the integer value at optlen to the size of the buffer at optval. The WSPGetSockOpt function stores the current value for the specified socket option in the buffer at optval and the size, in bytes, of this value at optlen. For most socket options, the size of the option value is the size of an integer.

The switch must allocate any memory space pointed to directly or indirectly by any parameters it specifies.

The only supported level at which options are defined is the SOL_SOCKET level.

If the switch never called the SAN service provider's WSPSetSockOpt function to assign a value to an option, the SAN service provider's WSPGetSockOpt function returns default values for options. These default values, along with data types for supported options, are described in the following table. A SAN service provider supports only the options described in this table.

Option | Value | Description
SO_DEBUG | FALSE | Debugging is enabled. Type is BOOL.
SO_GROUP_ID | NULL | Identifier of the socket's group. Type is GROUP.
SO_GROUP_ PRIORITY | 0 | Relative priority for the socket in its group. Type is Integer.
SO_MAX_MSG_ SIZE | Varies | Maximum outbound (send) size of a message for message-oriented socket types. No specified maximum inbound message size. Not applicable to stream-oriented sockets. Type is unsigned integer.
SO_MAX_RDMA_ SIZE | Varies | Maximum size of a RDMA transfer request. Type is unsigned integer.
SO_RDMA_ THRESHOLD_SIZE | Varies | Minimum size of a RDMA transfer request. Type is unsigned integer.

If the switch calls the SAN service provider's WSPGetSockOpt function with an unsupported option, the SAN service provider returns the WSAENOPROTOOPT error code.

The following list describes additional information for supported options.

SO_DEBUG
SAN service providers are encouraged, but not required, to supply output debug information if applications set the SO_DEBUG option. The mechanism for generating the debug information, and the form it takes, are beyond the scope of this chapter.
SO_GROUP_ID
This option is reserved for future use with socket groups. The switch currently ignores it. This option supplies the identifier of the group to which this socket belongs. Note that socket group identifiers are unique across all processes that use a SAN service provider. If this socket is not a group socket, the value of the option is NULL.
SO_GROUP_PRIORITY
This option is reserved for future use with socket groups. The switch currently ignores it. Group priority indicates the priority of the socket relative to other sockets within the group. Values are non-negative integers, with zero corresponding to the highest priority. Priority values are a hint to the SAN service provider about how to allocate potentially scarce resources. For example, whenever two or more sockets are both ready to transmit data, the highest priority socket (lowest value for SO_GROUP_PRIORITY) should be serviced first, with the remainder serviced in turn according to their relative priorities.

A SAN service provider returns the WSAENOPROTOOPT error code for non-group sockets or if the SAN service provider does not support group sockets.

SO_MAX_MSG_SIZE
A socket option that indicates the maximum size of an outbound (send) message for message-oriented socket types as implemented by the SAN service provider. The switch does not pass send requests to the SAN service provider that exceed the size that the SAN service provider returns for the value of this option.

This option has no meaning for byte-stream oriented sockets where the switch assumes that the SAN service provider can send messages of any size.

There is no provision to determine the maximum inbound message size.

SO_MAX_RDMA_SIZE
A socket option that indicates the maximum size of RDMA transfer requests (read or write) as implemented by the SAN service provider. The switch does not pass RDMA transfer requests to the SAN service provider that exceed the size that the SAN service provider returns for the value of this option.
SO_RDMA_THRESHOLD_SIZE
A socket option that indicates the preferred minimum size of RDMA transfer requests (read or write). The switch can set the actual threshold to a value different from the value returned by the SAN service provider. The switch subsequently uses RDMA to transfer data blocks that exceed the size of this threshold and messages to transfer data blocks that are less than or equal to the size of this threshold.

See Also

WSPSetSockOpt, WSPSocket


WSPIoctl

WSPIoctl sets or retrieves operating parameters associated with a socket.

int
  WSPIoctl(
    IN SOCKET  s,
    IN DWORD  dwIoControlCode,
    IN LPVOID  lpvInBuffer,
    IN DWORD  cbInBuffer,
    OUT LPVOID  lpvOutBuffer,
    IN DWORD  cbOutBuffer,
    OUT LPDWORD  lpcbBytesReturned,
    IN LPWSAOVERLAPPED  lpOverlapped,
    IN LPWSAOVERLAPPED_COMPLETION_ROUTINE  lpCompletionRoutine,
    IN LPWSATHREADID  lpThreadId,
    OUT LPINT  lpErrno
    );

Parameters

s
Descriptor that identifies a socket.
dwIoControlCode
Control code of the operation to perform.
lpvInBuffer
Pointer to an input buffer that contains information for the SAN service provider.
cbInBuffer
Size, in bytes, of the input buffer at lpvInBuffer.
lpvOutBuffer
Pointer to an output buffer that receives information from the SAN service provider.
cbOutBuffer
Size, in bytes, of the output buffer at lpvOutBuffer.
lpcbBytesReturned
Pointer to a variable that receives the size, in bytes, of the output buffer at lpvOutBuffer on return.
lpOverlapped
Pointer to a WSAOVERLAPPED structure. Ignored for non-overlapped sockets.
lpCompletionRoutine
Pointer to the completion routine that the SAN service provider might initiate after the operation completes. Ignored for non-overlapped sockets. This completion routine is defined as:
void CALLBACK
  CompletionRoutine(
    IN DWORD  dwError,
    IN DWORD  cbTransferred,
    IN LPWSAOVERLAPPED  lpOverlapped,
    IN DWORD  dwFlags
    );

The parameters of this completion routine are defined as:

dwError
Completion status for the overlapped operation at lpOverlapped.
cbTransferred
Number of bytes transferred during the overlapped operation.
lpOverlapped
Pointer to the WSAOVERLAPPED structure that the switch passed for the overlapped operation.
dwFlags
Set of flags for the overlapped operation. Currently none are defined.
lpThreadId
Pointer to a WSATHREADID structure that the SAN service provider uses in a subsequent call to the WPUQueueApc function to arrange for the execution of the completion routine at lpCompletionRoutine. A WSATHREADID structure identifies a thread. The SAN service provider should store the referenced WSATHREADID structure (not the pointer to same) until after WPUQueueApc returns.
lpErrno
Pointer to a variable that receives the error code.

Return Value

Returns zero if successful and the operation completed immediately; otherwise returns SOCKET_ERROR and, at lpErrno, one of the following error codes:

WSAENETDOWN
Network subsystem failed.
WSAEFAULT
Either the parameter lpvInBuffer, lpvOutBuffer or lpcbBytesReturned is not totally contained in a valid part of the user address space, or the cbInBuffer or cbOutBuffer parameter is too small.
WSAEINVAL
Control code in dwIoControlCode is not a valid code, a supplied input parameter is not acceptable, or the control code is not applicable to the type of socket supplied.
WSAENOTSOCK
Descriptor is not a socket.
WSAEOPNOTSUPP
Operation specified by the control code in dwIoControlCode cannot be realized. For example, a SAN service provider returns this error if it does not support the flow specifications specified in the QOS structure at lpvInBuffer for the SIO_SET_QOS control code.
WSAENOPROTOOPT
Operation or feature is unsupported by the SAN service provider.
WSA_IO_PENDING
SAN service provider successfully initiated an overlapped operation and will indicate completion at a later time.
WSAEWOULDBLOCK
Socket is marked as nonblocking and the requested operation cannot be completed immediately (that is, the operation would block and must be performed asynchronously).

Note that a SAN service provider does not support the WSAEINPROGRESS error code for WSPIoctl because the switch never issues cancel blocking calls to a SAN service provider.

Note that if WSPIoctl returns zero and the operation completed immediately the completion routine, if specified, will have already been queued.

Headers

Defined in Ws2spi.h. Include Ws2spi.h. Requires Windows Sockets version 2.0.

Comments

The Windows Sockets switch calls a SAN service provider's WSPIoctl function to set or retrieve operating parameters associated with a socket.

A call to WSPIoctl using any supported input/output control (IOCTL) code might block indefinitely, depending on the SAN service provider's implementation. Because the switch cannot tolerate blocking in some WSPIoctl calls, it uses overlapped I/O for IOCTL codes that are especially likely to block, including the following supported IOCTL codes:

SIO_GET_QOS

SIO_GET_GROUP_QOS

SIO_SET_QOS

SIO_SET_GROUP_QOS

Note If socket s is in nonblocking mode, WSPIoctl returns the WSAEWOULDBLOCK error code if the SAN service provider cannot finish the specified operation immediately. In this case, the Windows Sockets switch must change the socket to blocking mode and reissue the request.

Because IOCTL codes are 32-bit entities, the following encoding scheme partitions the identifier space for each IOCTL code so that vendors can add new IOCTL codes. Each column in the following table specifies the number of bits in each partition of an IOCTL-code.

I | O | V | T | Vendor/address family | IOCTL code
1 | 1 | 1 | 2 | 11 | 16 maximum

I
A single-bit quantity that is set if the input buffer is valid for the IOCTL code, as with IOC_IN.
O
A single-bit quantity that is set if the output buffer is valid for the IOCTL code, as with IOC_OUT.
V
A single-bit quantity that is set if there are no parameters for the IOCTL code, as with IOC_VOID.
T
A two-bit quantity that defines the type of IOCTL code. The following values are defined:
00
The IOCTL code is a standard Unix IOCTL code, as with FIONREAD, FIONBIO, and so on.
01
The IOCTL code is a generic Windows Sockets 2 IOCTL code. New IOCTL codes defined for Windows Sockets 2 have T==01.
10
The IOCTL code applies only to a specific address family.
11
The IOCTL code applies only to a specific SAN service provider. This type allows vendors to be assigned a number that appears in the Vendor/address family field. With a vendor number assigned, the vendor has the flexibility and privacy to define new IOCTL codes without having to register those IOCTL codes with a clearinghouse.
Vendor/address family
An 11-bit quantity that defines the vendor who owns the code (if T == 3) or that contains the address family to which the code applies (if T == 2). If the IOCTL code is a standard Unix IOCTL code (T == 0), this field has the same value as the code on Unix. If this is a generic Windows Sockets 2 IOCTL code (T == 1), this field can be used as an extension of the IOCTL-code field to provide additional code values.
IOCTL code
The specific IOCTL code for the operation. The IOCTL code can be up to a 16-bit quantity.

Note IOCTL codes that set both I and O partitions indicate both input and output buffers are valid.

Supported IOCTL Codes for SAN Service Providers

SAN service providers support the following Windows Sockets IOCTL codes. The Windows Sockets switch issues these IOCTL codes either for its own internal purposes or on behalf of an application.

SIO_GET_EXTENSION_FUNCTION_POINTER
Partition settings: O==1(set), I==1(set), T==01

Retrieves a pointer to an extension function that a SAN service provider must support. For more information on extension functions, see Windows Sockets SPI Extensions for SANs. The input buffer of the WSPIoctl call contains the GUID whose value identifies the specified extension function. The SAN service provider returns the pointer to the requested function in the WSPIoctl function's output buffer. The following table contains GUIDs for extension functions that a SAN service provider can support:
Extension function | GUID
WSPRegisterMemory | {C0B422F5-F58C-11d1-AD6C-00C04FA34A2D}
WSPDeregisterMemory | {C0B422F6-F58C-11d1-AD6C-00C04FA34A2D}
WSPRegisterRdmaMemory | {C0B422F7-F58C-11d1-AD6C-00C04FA34A2D}
WSPDeregisterRdmaMemory | {C0B422F8-F58C-11d1-AD6C-00C04FA34A2D}
WSPRdmaWrite | {C0B422F9-F58C-11d1-AD6C-00C04FA34A2D}
WSPRdmaRead | {C0B422FA-F58C-11d1-AD6C-00C04FA34A2D}
WSPMemoryRegistrationCacheCallback | {E5DA4AF8-D824-48CD-A799-6337A98ED2AF}

SIO_GET_QOS
Partition settings: O==1(set), I==1(set), T==01

If a SAN service provider supports quality of service (QOS), retrieves the QOS structure associated with the socket. The input buffer is optional. Some protocols, such as RSVP, require the input buffer to qualify a QOS request. The SAN service provider copies the QOS structure into the output buffer. The switch must allocate enough space for the output buffer to hold the full QOS structure.

The SAN service provider returns the WSAENOPROTOOPT error code if it does not support QOS.

SIO_GET_GROUP_QOS
Partition settings: O==1(set), I==1(set), T==01

This IOCTL code is reserved for future use with socket groups. The switch currently ignores it.

If a SAN service provider supports QOS, retrieves the QOS structure associated with the socket group to which this socket belongs. The input buffer is optional. Some protocols, such as RSVP, require the input buffer to qualify a QOS request. The SAN service provider copies the QOS structure into the output buffer. If the socket that was specified in the WSPIoctl call does not belong to an appropriate socket group, the SAN service provider sets the SendingFlowspec and ReceivingFlowspec members of the QOS structure to NULL.

The SAN service provider returns the WSAENOPROTOOPT error code if it does not support QOS.

SIO_SET_QOS
Partition settings: O==0(not set), I==1(set), T==01

If a SAN service provider supports QOS, associates the supplied QOS structure with the socket. The switch does not require an output buffer; the SAN service provider retrieves the QOS structure from the input buffer.

The SAN service provider returns the WSAENOPROTOOPT error code if it does not support QOS.

SIO_SET_GROUP_QOS
Partition settings: O==0(not set), I==1(set), T==01

This IOCTL code is reserved for future use with socket groups. The switch currently ignores it.

If a SAN service provider supports QOS, establishes the supplied QOS structure with the socket group to which this socket belongs. The switch does not require an output buffer; the SAN service provider retrieves the QOS structure from the input buffer.

The SAN service provider returns the WSAENOPROTOOPT error code if it does not support QOS or if the specified socket descriptor is not the creator of the associated socket group.

SIO_ADDRESS_LIST_QUERY
Partition settings: O==1(set), I==1(set), T==01

Retrieves a list of local IP addresses that are assigned to the network interface cards (NICs) that the SAN service provider services. The SAN service provider uses a SOCKET_ADDRESS_LIST structure, defined as follows, to return the list in the output buffer.

typedef struct _SOCKET_ADDRESS_LIST {
    INT             iAddressCount;
    SOCKET_ADDRESS  Address[1];
} SOCKET_ADDRESS_LIST, FAR * LPSOCKET_ADDRESS_LIST;

The members of this structure contain the following information:

iAddressCount
Specifies the number of address structures in the list.
Address
Array of IP address structures.

The switch uses this IOCTL code internally to decide whether to use a given SAN service provider to execute an application's requests to make connections or to listen for incoming connections. The switch only forwards actual application requests for the list of local IP addresses to the TCP/IP provider. The switch also uses the SIO_ADDRESS_LIST_CHANGE IOCTL code with the TCP/IP service provider to detect changes in address lists that all SAN service providers service. After TCP/IP reports a change, through either overlapped I/O or the FD_ADDRESS_LIST_CHANGE event, the switch uses the SIO_ADDRESS_LIST_QUERY IOCTL code to query all SAN service providers to refresh their lists.

If the output buffer is not large enough to contain the address list, the SAN service provider returns SOCKET_ERROR and, at lpErrno, the WSAEFAULT error code. The SAN service provider also returns the size of the output buffer that it requires in the variable at lpcbBytesReturned.

The switch always makes a blocking WSPIoctl call using the SIO_GET_EXTENSION_POINTER and SIO_ADDRESS_LIST_QUERY IOCTL codes. That is, the switch does not use overlapped I/O. However, the switch makes a nonblocking WSPIoctl call using the SIO_GET_QOS and SIO_SET_QOS IOCTL codes and any completion method that the overlying application specifies. The following paragraphs discuss SAN service provider requirements regarding completion of overlapped WSPIoctl calls.

Overlapped Socket I/O

If the switch specifies NULL for a completion routine, the SAN service provider should call the WPUCompleteOverlappedRequest function in the context of an arbitrary thread to complete the request. Either the switch or the Windows Sockets DLL can intercept the WPUCompleteOverlappedRequest call. After intercepting this call, the intercepting entity uses the notification mechanism that was requested by the application to signal completion of the request. This notification mechanism can be an event and/or a completion port. The switch specifies an overlapped structure and NULL for a completion routine to issue most requests. However, requests from applications for the switch to forward QOS information directly to a SAN service provider can use any completion notification mechanism. If a SAN service provider does not support QOS, this situation should never arise.

If the low order bit of the hEvent member in the WSAOVERLAPPED structure is set, an application or the switch specifically requests to not be notified with a completion port. If the remainder of hEvent is NULL as well, excluding the low order bit, the SAN service provider can assume that the I/O request requires no completion notification. In this case, the calling entity calls the WSPGetOverlappedResult function to poll for completion. For more information, see the CreateIoCompletionPort and GetQueuedCompletionStatus functions in the Platform SDK documentation.

If the switch specifies a non-NULL completion routine, the SAN service provider ignores the hEvent member in the WSAOVERLAPPED structure. Therefore, the switch can use hEvent to pass context information to the completion routine. An application that initiates a request with a non-NULL completion routine and later calls the WSAGetOverlappedResult function for that request cannot specify that the WSAGetOverlappedResult call wait for the request to complete. That is, the application cannot specify TRUE for the fWait parameter in the WSAGetOverlappedResult call. In this case, usage of hEvent is undefined, and attempting to wait on hEvent produces unpredictable results.

If the switch forwards a request, along with a non-NULL completion routine, in the WSPIoctl call, the SAN service provider must initiate the completion routine after the request completes. Because the completion routine must be executed in the context of the same thread that initiated the request, the SAN service provider cannot directly call the completion routine. The Windows Sockets interface offers an asynchronous procedure call (APC) mechanism to facilitate invocation of completion routines. This APC mechanism is the WPUQueueApc function. A SAN service provider calls WPUQueueApc to arrange for the execution of a completion routine in the proper thread and process context. The SAN service provider can call WPUQueueApc from any process and thread context, even a context different from the thread and process used to initiate the request.

The SAN service provider passes to WPUQueueApc the pointer to the WSATHREADID structure that the switch supplied in the WSPIoctl call. The SAN service provider also passes to WPUQueueApc a pointer to an APC function to be invoked and a 32-bit context value that is subsequently passed to the APC function. Because only a single 32-bit context value is available, the APC function cannot be the original completion routine. Rather, the SAN service provider must supply a pointer to its own APC function. This APC function uses the supplied context value to access the required result information for the original request and then calls the original completion routine.

See Also

WSAOVERLAPPED, WSATHREADID, WSPDeregisterMemory, WSPDeregisterRdmaMemory, WSPGetOverlappedResult, WSPRdmaRead, WSPRdmaWrite, WSPRegisterMemory, WSPRegisterRdmaMemory, WSPSocket


WSPListen

WSPListen establishes a socket to listen for incoming connections.

int
  WSPListen(
    IN SOCKET  s,
    IN int  backlog,
    OUT LPINT  lpErrno
    );

Parameters

s
Descriptor that identifies a bound, unconnected socket.
backlog
Maximum length to which the queue of pending connections can grow. If set to SOMAXCONN, the SAN service provider should set its pending-connection queue to a reasonable maximum length. If the SAN service provider sets the backlog, there is no standard provision for the switch to determine the backlog.
lpErrno
Pointer to a variable that receives the error code.

Return Value

Returns zero if successful; otherwise, returns SOCKET_ERROR and, at lpErrno, one of the following error codes:

WSAENETDOWN
Network subsystem failed.
WSAEINVAL
The switch did not previously call the SAN service provider's WSPBind function to bind the socket.
WSAEISCONN
Socket already connected.
WSAEMFILE
No more socket descriptors available.
WSAENOBUFS
No buffer space available.
WSAENOTSOCK
Descriptor is not a socket.

Note that a SAN service provider does not support the following error codes for WSPListen:

WSAEADDRINUSE
The Windows Sockets switch, in conjunction with the TCP/IP provider, handles address reuse.
WSAEINPROGRESS
The Windows Sockets switch never issues cancel blocking calls to a SAN service provider.
WSAEOPNOTSUPP
The socket is the appropriate type. That is, SOCK_STREAM.

Headers

Defined in Ws2spi.h. Include Ws2spi.h. Requires Windows Sockets version 2.0.

Comments

The Windows Sockets switch calls a SAN service provider's WSPListen function to set a socket to acknowledge and queue incoming connection requests until the switch accepts them.

To accept incoming connection requests, the switch first calls the SAN service provider's WSPSocket function to create a socket and then calls the SAN service provider's WSPBind function to bind the socket to a local IP address. The switch can bind a socket to either the IP address of one of the network interface cards (NICs) serviced by the SAN service provider or to the wildcard IP address (0.0.0.0). The wildcard IP address implies that the SAN service provider should accept incoming connection requests from all NICs it controls. The switch next calls the WSPListen function to set the socket to passive mode, in which the SAN service provider acknowledges and queues incoming connection requests. In this call, the switch specifies the maximum size of the queue. The switch subsequently calls the WSPAccept function to accept connection requests in the queue.

Typically, servers might receive more than one connection request at a time. The Windows Sockets switch on such a server calls the SAN service provider's WSPListen function to queue incoming-connection requests. Remote clients establish connections with those servers. The Windows Sockets switch on such a remote client calls the SAN service provider's WSPConnect function to initiate a connection operation. If a connection request arrives on the server and the SAN service provider's incoming-connection queue is full, the SAN service provider should immediately indicate to the remote client that it refuses the connection request. The SAN service provider on the remote client must then fail its connection operation with the WSAECONNREFUSED error code.

The WSPListen function should continue to function even if socket descriptors are not available. It should accept connections until the queue is emptied. If descriptors become available, a subsequent call to WSPListen or WSPAccept refills the queue to the current or most recent backlog, if possible, and resumes listening for incoming connections.

The switch can call the WSPListen function more than once on the same socket. Doing so updates the current backlog for the listening socket. If the number of incoming connection requests in the queue exceeds the specified maximum size for the queue, the SAN service provider resets and drops excess connection requests.

Note The SAN service provider silently limits the maximum size of the queue of incoming connection requests to a reasonable value. If the switch passes an invalid value for this maximum queue size, the SAN service provider replaces the invalid value with the nearest valid value. There is no standard provision that the switch can use to determine the actual maximum queue size that the SAN service provider uses.

See Also

WSPAccept, WSPBind, WSPConnect, WSPSocket


WSPRecv

WSPRecv receives data on a connected socket.

int
  WSPRecv(
    IN SOCKET  s,
    IN/OUT LPWSABUF  lpBuffers,
    IN DWORD  dwBufferCount,
    OUT LPDWORD  lpNumberOfBytesRecvd,
    IN/OUT LPDWORD  lpFlags,
    IN LPWSAOVERLAPPED  lpOverlapped,
    IN LPWSAOVERLAPPED_COMPLETION_ROUTINE  lpCompletionRoutine,
    IN LPWSATHREADID  lpThreadId,
    OUT LPINT  lpErrno
    );

Parameters

s
Descriptor that identifies a connected socket.
lpBuffers
Pointer to an array of WSABUF structures. Each WSABUF structure describes a buffer. The switch registered each buffer in a previous call to the WSPRegisterMemory function.
dwBufferCount
Number of WSABUF structures at lpBuffers.
lpNumberOfBytesRecvd
Pointer to a variable that receives the number of bytes that WSPRecv received.
lpFlags
Pointer to a set of flags.
lpOverlapped
Pointer to a WSAOVERLAPPED structure that provides a communication medium between the initiation of an overlapped I/O operation and its subsequent completion. Ignored for non-overlapped sockets.
lpCompletionRoutine
Pointer to the completion routine that the SAN service provider might initiate after the receive operation completes. Ignored for non-overlapped sockets. The switch specifies NULL for a completion routine.
lpThreadId
Pointer to a WSATHREADID structure that the SAN service provider might use in a subsequent call to the WPUQueueApc function to arrange for the execution of the completion routine at lpCompletionRoutine. A WSATHREADID structure identifies a thread. Because the switch specifies NULL for a completion routine, the SAN service provider does not use lpThreadId.
lpErrno
Pointer to a variable that receives the error code.

Return Value

Returns zero if successful and the receive operation completed immediately; otherwise returns SOCKET_ERROR and, at lpErrno, one of the following error codes:

WSAENETDOWN
Network subsystem failed.
WSAENOTCONN
Socket is not connected.
WSAENETRESET
Connection has been broken due to keep-alive activity detecting a failure while the operation was in progress.
WSAEFAULT
The lpBuffers parameter is not totally contained in a valid part of the user address space.
WSAENOTSOCK
Descriptor is not a socket.
WSAESHUTDOWN
Socket has been shut down; it is not possible for the WSPRecv function to receive data on a socket after the socket has been shut down.
WSAEINVAL
The switch either did not create the socket with the overlapped flag or did not call the WSPBind function to bind the socket.
WSAECONNABORTED
The connection to the remote peer was terminated due to a time-out or other failure.
WSAECONNRESET
The connection was reset by the remote peer.
WSAEDISCON
The connection was gracefully closed by the remote peer.
WSA_IO_PENDING
The SAN service provider successfully initiated an overlapped receive operation and will indicate completion at a later time.
WSA_OPERATION_ABORTED
The overlapped operation was canceled because the socket was closed.

Note that a SAN service provider does not support the following error codes for WSPRecv:

WSAEINTR
The Windows Sockets switch never issues cancel blocking calls to a SAN service provider.
WSAEINPROGRESS
The Windows Sockets switch never issues cancel blocking calls to a SAN service provider.
WSAEOPNOTSUPP
The socket is the appropriate type.
WSAEWOULDBLOCK
The Windows Sockets switch uses overlapped sockets.
WSAEMSGSIZE
The current version of Windows Sockets Direct does not support SAN service providers handling sockets that receive datagrams. Also, broadcast addresses are not supported.

Headers

Defined in Ws2spi.h. Include Ws2spi.h. Requires Windows Sockets version 2.0.

Comments

The Windows Sockets switch calls a SAN service provider's WSPRecv function to receive data on a connected socket. Before calling WSPRecv, the switch must have previously called the SAN service provider's WSPBind function to assign a local IP address to the specified socket. A SAN service provider receives WSPRecv requests from the switch—never directly from an application.

Typically during connection setup time, the switch calls the SAN service provider's WSPRegisterMemory extension function to pre-register all memory for the buffer array that receives the incoming data.

The switch specifies an overlapped structure and NULL for a completion routine if the switch calls the SAN service provider's WSPRecv function in an overlapped manner. The switch calls the WSPRecv function to post one or more buffers that receive incoming data as the data becomes available. If the data reception operation cannot complete immediately, the operation proceeds, but WSPRecv returns with the WSA_IO_PENDING error code. The switch later calls the SAN service provider's WSPGetOverlappedResult function and passes a pointer to the overlapped structure to retrieve the final completion status.

The buffer array that the switch supplies in a WSPRecv call is a pointer to an array of WSABUF structures. The SAN service provider fills buffers in the order in which they appear in the buffer array and must pack buffers so as not to create holes in those buffers. The buffer array is transient. That is, if the WSPRecv call returns without completing the data reception operation, the SAN service provider must capture the pointer to the array of WSABUF structures before returning from WSPRecv. This requirement enables the switch to build stack-based buffer arrays.

The SAN service provider places incoming data into buffers until the SAN service provider fills those buffers, the switch closes the connection, or the SAN service provider exhausts internally buffered data. Regardless of whether the incoming data fills all the buffers, the SAN service provider signals a completion event for overlapped sockets.

If WSPRecv returns the WSAECONNRESET error code, the remote peer performed a hard close of the connection.

Overlapped socket I/O

If the data reception operation completes immediately, the SAN service provider returns from WSPRecv with a value of zero and specifies the number of bytes received at lpNumberOfBytesRecvd. If the SAN service provider successfully initiated the data reception operation and will indicate completion at a later time, the SAN service provider returns from WSPRecv with a value of SOCKET_ERROR and specifies the WSA_IO_PENDING error code at lpErrno. Note that in this case, a value is not specified at lpNumberOfBytesRecvd and flags at lpFlags are not updated. After the data reception operation completes, the switch calls the SAN service provider's WSPGetOverlappedResult function and passes pointers to variables to hold data reception information and completion flags. The SAN service provider specifies the number of bytes received and completion flags in these pointers.

The overlapped structure at lpOverlapped must be valid for the duration of the data reception operation. If multiple data reception operations are outstanding simultaneously, each must reference a separate overlapped structure.

As mentioned previously, the switch always specifies an event in an overlapped structure and NULL for a completion routine if the switch calls the SAN service provider's WSPRecv function in an overlapped manner. The SAN service provider should call the WPUCompleteOverlappedRequest function in the context of an arbitrary thread to complete the data reception operation. If the low order bit of the hEvent member in the WSAOVERLAPPED structure is set, the switch specifically requests to not be notified upon completion of the data reception operation. Therefore, the SAN service provider is not required to call the WPUCompleteOverlappedRequest function to complete the I/O request. In this case, the switch calls the WSPGetOverlappedResult function to poll for completion. For more information, see the GetQueuedCompletionStatus function in the Platform SDK documentation.

The SAN service provider can deliver completion notifications in any order; the SAN service provider is not required to deliver notifications in the same order that overlapped operations are completed. However, the SAN service provider fills posted buffers with incoming data in the same order in which the switch supplies them.

See Also

WSABUF, WSAOVERLAPPED, WSPBind, WSPGetOverlappedResult, WSPRegisterMemory, WSPSocket


WSPSend

WSPSend sends data on a connected socket.

int
  WSPSend(
    IN SOCKET  s,
    IN LPWSABUF  lpBuffers,
    IN DWORD  dwBufferCount,
    OUT LPDWORD  lpNumberOfBytesSent,
    IN DWORD  dwFlags,
    IN LPWSAOVERLAPPED  lpOverlapped,
    IN LPWSAOVERLAPPED_COMPLETION_ROUTINE  lpCompletionRoutine,
    IN LPWSATHREADID  lpThreadId,
    OUT LPINT  lpErrno
    );

Parameters

s
Descriptor that identifies a connected socket.
lpBuffers
Pointer to an array of WSABUF structures. This array must remain valid for the duration of the send operation. Each WSABUF structure describes a buffer. The switch registered each buffer in a previous call to the WSPRegisterMemory function.
dwBufferCount
Number of WSABUF structures at lpBuffers.
lpNumberOfBytesSent
Pointer to a variable that receives the number of bytes that WSPSend sent.
dwFlags
Set of flags that specify the way in which the call is made.
lpOverlapped
Pointer to a WSAOVERLAPPED structure that provides a communication medium between the initiation of an overlapped I/O operation and its subsequent completion. Ignored for non-overlapped sockets.
lpCompletionRoutine
Pointer to the completion routine that the SAN service provider might initiate after the send operation completes. Ignored for non-overlapped sockets. The switch specifies NULL for a completion routine.
lpThreadId
Pointer to a WSATHREADID structure that the SAN service provider might use in a subsequent call to the WPUQueueApc function to arrange for the execution of the completion routine at lpCompletionRoutine. A WSATHREADID structure identifies a thread. Because the switch specifies NULL for a completion routine, the SAN service provider does not use lpThreadId.
lpErrno
Pointer to a variable that receives the error code.

Return Value

Returns zero if successful and the send operation completed immediately; otherwise returns SOCKET_ERROR and, at lpErrno, one of the following error codes:

WSAENETDOWN
Network subsystem failed.
WSAEFAULT
The lpBuffers parameter is not totally contained in a valid part of the user address space.
WSAENOBUFS
SAN service provider reports a buffer deadlock.
WSAENOTCONN
Socket is not connected.
WSAENOTSOCK
Descriptor is not a socket.
WSAESHUTDOWN
Socket has been shut down; it is not possible for the WSPSend function to send data on a socket after the socket has been shut down.
WSAEINVAL
The switch did not either create the socket with the overlapped flag or previously call the WSPBind function to bind the socket.
WSAECONNABORTED
The connection to the remote peer was terminated due to a time-out or other failure.
WSAECONNRESET
The connection was reset by the remote peer.
WSA_IO_PENDING
The SAN service provider successfully initiated an overlapped send operation and will indicate completion at a later time.
WSA_OPERATION_ABORTED
The overlapped operation was canceled because the socket was closed.

Note that a SAN service provider does not support the following error codes for WSPSend:

WSAEACCES
Broadcast addresses are not supported.
WSAEINPROGRESS
The Windows Sockets switch never issues cancel blocking calls to a SAN service provider.
WSAENETRESET
Detecting a broken connection from the remote host resetting is not supported.
WSAEOPNOTSUPP
The socket is the appropriate type.
WSAEWOULDBLOCK
The Windows Sockets switch uses overlapped sockets.
WSAEMSGSIZE
The current version of Windows Sockets Direct does not support SAN service providers handling sockets that send datagrams.

Headers

Defined in Ws2spi.h. Include Ws2spi.h. Requires Windows Sockets version 2.0.

Comments

The Windows Sockets switch calls a SAN service provider's WSPSend function to transmit data on a connected socket. A SAN service provider receives WSPSend requests from the switch, never directly from an application.

Typically during connection setup time, the switch calls the SAN service provider's WSPRegisterMemory extension function to pre-register all memory for the buffer array that is the source of the outgoing data.

The switch specifies an overlapped structure and NULL for a completion routine if the switch calls the SAN service provider's WSPSend function in an overlapped manner. The switch calls WSPSend to post one or more buffers of data for transmission over the network. If the data-transmission operation cannot complete immediately, the operation proceeds, but WSPSend returns with the WSA_IO_PENDING error code. The switch later calls the SAN service provider's WSPGetOverlappedResult function and passes a pointer to the overlapped structure to retrieve the final completion status.

The buffer array that the switch supplies in a WSPSend call is a pointer to an array of WSABUF structures. The SAN service provider must transmit data in buffers in the order in which those buffers appear in the buffer array. The buffer array is transient. That is, if the WSPSend call returns without completing the data-transmission operation, the SAN service provider must capture the pointer to the array of WSABUF structures before returning from WSPSend. This requirement enables the switch to build stack-based buffer arrays.

The switch does not pass send message requests to the SAN service provider that exceed the size that the SAN service provider returns in WSPGetSockOpt calls for the value of the SO_MAX_MSG_SIZE socket option.

Note that the successful completion of a WSPSend call does not indicate that the SAN service provider successfully finished delivering data in the buffer array to the destination.

Overlapped socket I/O

If the data transmission operation completes immediately, the SAN service provider returns from WSPSend with a value of zero and specifies the number of bytes transmitted at lpNumberOfBytesSent. If the SAN service provider successfully initiated the data transmission operation and will indicate completion at a later time, the SAN service provider returns from WSPSend with a value of SOCKET_ERROR and specifies the WSA_IO_PENDING error code at lpErrno. Note that in this case, a value is not specified at lpNumberOfBytesSent. After the data transmission operation completes, the switch calls the SAN service provider's WSPGetOverlappedResult function and passes a pointer to a variable to hold data transmission information. The SAN service provider specifies the number of bytes transmitted in this pointer.

The overlapped structure at lpOverlapped must be valid for the duration of the data transmission operation. If multiple data transmission operations are outstanding simultaneously, each must reference a separate overlapped structure.

As mentioned previously, the switch always specifies an event in an overlapped structure and NULL for a completion routine if the switch calls the SAN service provider's WSPSend function in an overlapped manner. The SAN service provider should call the WPUCompleteOverlappedRequest function in the context of an arbitrary thread to complete the data transmission operation. If the low order bit of the hEvent member in the WSAOVERLAPPED structure is set, the switch specifically requests to not be notified upon completion of the data transmission operation. Therefore, the SAN service provider is not required to call the WPUCompleteOverlappedRequest function to complete the I/O request. In this case, the switch calls the WSPGetOverlappedResult function to poll for completion. For more information, see the GetQueuedCompletionStatus function in the Platform SDK documentation.

The SAN service provider can deliver completion notifications in any order; the SAN service provider is not required to deliver notifications in the same order that overlapped operations are completed. However, the SAN service provider transmits data from posted buffers in the same order in which the switch supplies them.

See Also

WSABUF, WSAOVERLAPPED, WSPGetOverlappedResult, WSPGetSockOpt, WSPRegisterMemory, WSPSocket


WSPSetSockOpt

WSPSetSockOpt sets the value of an option for a socket.

int
  WSPSetSockOpt(
    IN SOCKET  s,
    IN int  level,
    IN int  optname,
    IN const char FAR  *optval,
    IN int  optlen,
    OUT LPINT  lpErrno
    );

Parameters

s
Descriptor that identifies a socket.
level
Level at which the option is defined; the only supported level is SOL_SOCKET.
optname
Socket option for which the value is to be set.
optval
Pointer to a buffer that contains the value for the socket option that is specified in optname.
optlen
Size, in bytes, of the value at optval.
lpErrno
Pointer to a variable that receives the error code.

Return Value

Returns zero if successful; otherwise, returns SOCKET_ERROR and, at lpErrno, one of the following error codes:

WSAENETDOWN
Network subsystem failed.
WSAEFAULT
The optval parameter is not in a valid part of the process address space or the optlen parameter is too small.
WSAEINVAL
The level parameter is not valid, or the information in the optval parameter is not valid.
WSAENETRESET
Connection has been broken due to keep-alive activity detecting a failure while the operation was in progress.
WSAENOPROTOOPT
The option is unknown or unsupported for the SAN service provider.
WSAENOTCONN
The connection of the socket to the peer was reset.
WSAENOTSOCK
Descriptor is not a socket.

Note that a SAN service provider does not support the WSAEINPROGRESS error code for WSPSetSockOpt because the switch never issues cancel blocking calls to a SAN service provider.

Headers

Defined in Ws2spi.h. Include Ws2spi.h. Requires Windows Sockets version 2.0.

Comments

The Windows Sockets switch calls a SAN service provider's WSPSetSockOpt function to assign a value to an option for a socket.

The only supported level at which options for sockets are defined is the SOL_SOCKET level.

A SAN service provider supports assigning values to options in the following table. The following table also describes data types for supported options.

Option | Type | Description
SO_DEBUG | BOOL | Debugging is either enabled or disabled. If set, SAN service providers should supply output debug information. However, they are not required to supply debug information.
SO_GROUP_PRIORITY | Integer | The relative priority for the socket in its group. Reserved for future use with socket groups.

The switch currently ignores the SO_GROUP_PRIORITY option. Group priority indicates the priority of the socket relative to other sockets within the group. Values are non-negative integers, with zero corresponding to the highest priority. Priority values represent a hint to the SAN service provider about how to allocate potentially scarce resources. For example, whenever two or more sockets are both ready to transmit data, the highest priority socket (lowest value for SO_GROUP_PRIORITY) should be serviced first, with the remainder serviced in turn according to their relative priorities.

If the switch calls the SAN service provider's WSPSetSockOpt function with an unsupported option, or if if the SAN service provider does not support group sockets, then the WSAENOPROTOOPT error code is returned.

See Also

WSPGetSockOpt, WSPIoctl, WSPSocket


WSPSocket

WSPSocket function creates a socket.

SOCKET
  WSPSocket(
    IN int  af,
    IN int  type,
    IN int  protocol,
    IN LPWSAPROTOCOL_INFOW  lpProtocolInfo,
    IN GROUP  g,
    IN DWORD  dwFlags,
    OUT LPINT  lpErrno
    );

Parameters

af
Address family specification for the new socket.
type
Type specification for the new socket.
protocol
Protocol to be used with the new socket that is specific to the address family in af.
lpProtocolInfo
Pointer to a WSAPROTOCOL_INFOW structure that specifies the characteristics of the socket to be created.
g
Reserved.
dwFlags
Set of flags that specify supplementary information about the socket.
lpErrno
Pointer to a variable that receives the error code.

Return Value

Returns a value of type SOCKET that is a descriptor for the new socket, if successful; otherwise, returns INVALID_SOCKET and, at lpErrno, one of the following error codes:

WSAENETDOWN
Network subsystem failed.
WSAEAFNOSUPPORT
The specified address family is not supported.
WSAEMFILE
No more socket descriptors available.
WSAENOBUFS
No buffer space is available; socket cannot be created.
WSAEPROTONOSUPPORT
Specified protocol is not supported.
WSAEPROTOTYPE
Specified protocol is the wrong type for this socket.
WSAESOCKTNOSUPPORT
Specified socket type is not supported in the address family in af.
WSAEINVAL
The g parameter is not valid.

Headers

Defined in Ws2spi.h. Include Ws2spi.h. Requires Windows Sockets version 2.0.

Comments

The Windows Sockets switch calls a SAN service provider's WSPSocket function to allocate a socket descriptor and any related resources for that socket descriptor. In this call, the switch always passes the WSA_FLAG_OVERLAPPED flag to specify that the created socket can use asynchronous (overlapped) data transfer.

In the WSPSocket call, the switch also specifies values for address family, socket type, and protocol type that an application supplies in corresponding socket or WSASocket function calls. In the current version of Windows Sockets Direct, the switch only creates sockets with the following values for address family, socket type, and protocol type.

AF_INET for the standard Internet address family

SOCK_STREAM for a socket type specification that provides sequenced, reliable, two-way, connection-based byte streams and uses TCP for the Internet address family

IPPROTO_TCP for the TCP/IP protocol

In the WSPSocket call, the switch also passes a pointer to a WSAPROTOCOL_INFOW structure that specifies TCP/IP protocol information and characteristics of the socket.

A SAN service provider creates socket descriptors that are not installable file system (IFS) objects; that is, it is a provider of non-IFS socket descriptors. On the other hand, the TCP/IP provider is a provider of IFS socket descriptors. Applications that are Windows Sockets SPI clients can call only standard Win32® I/O functions, such as ReadFile and WriteFile, using IFS socket descriptors.

A SAN service provider must call the WPUCreateSocketHandle function to acquire a unique socket descriptor from the switch prior to returning from WSPSocket. The SAN service provider must store the switch's descriptor in the SAN service provider's internal data structure for the new socket. The SAN service provider returns its own descriptor for the socket to complete the WSPSocket call. The switch must supply the SAN service provider's internal descriptor for the new socket when calling the SAN service provider's functions, while the SAN service provider must supply the switch's socket descriptor in up calls to the switch.

The switch specifies only the WSA_FLAG_OVERLAPPED flag in the dwFlags parameter in a WSPSocket call. This flag causes a SAN service provider to create an overlapped socket. The switch can call the SAN service provider's WSPRecv, WSPRdmaRead, WSPSend, WSPRdmaWrite, and WSPIoctl functions using an overlapped socket to start multiple overlapped operations on that socket that run simultaneously. All these functions that allow overlapped operation also support non-overlapped usage on an overlapped socket if the values for parameters related to overlapped operation are set to NULL. Functions that perform operations in a non-overlapped manner block further processing. That is, those functions do not return until their associated operations complete.

SAN sockets, which are SOCK_STREAM socket types, provide full-duplex connections--that is, two-way communication that takes place in both directions simultaneously can occur on SAN sockets. Before receiving or sending any data on a SAN socket, the switch can call the SAN service provider's WSPConnect function to connect such a SAN socket to a peer. After connected, the switch can call the SAN service provider's WSPSend, WSPRdmaWrite, WSPRecv and WSPRdmaRead functions to transfer data. After a data transfer session completes, the switch must call the SAN service provider's WSPCloseSocket function to close the socket.

SAN transports that are used to transfer data reliably ensure that data is not lost or duplicated. If data (for which the remote peer has buffer space) cannot be successfully transmitted within a reasonable length of time, the connection is considered broken and subsequent calls fail with the error code set to WSAETIMEDOUT.

The switch, running in a controlling process, calls the SAN service provider's WSPDuplicateSocket function to obtain a special WSAPROTOCOL_INFOW structure. The switch, running in another process, in turn, calls the SAN service provider's WSPSocket function and passes this WSAPROTOCOL_INFOW structure to create a socket descriptor for a shared underlying socket. Applications running in two or more processes can use this shared socket but not simultaneously. In this WSPSocket call, the SAN service provider ignores socket group and flags parameters. In addition, the dwProviderReserved member of the WSAPROTOCOL_INFOW structure that specifies protocol information should be set to the same value that WSPDuplicateSocket returned. For more information, see Duplicating Socket Handles for a SAN.

See Also

WSAPROTOCOL_INFOW, WSPAccept, WSPBind, WSPCloseSocket, WSPConnect, WSPDuplicateSocket, WSPGetSockOpt, WSPIoctl, WSPListen, WSPRdmaRead, WSPRdmaWrite, WSPRecv, WSPSend, WSPSetSockOpt


Windows Sockets Direct Extensions

A SAN service provider DLL implements the Windows Sockets Direct extension functions to extend Windows Sockets SPI for use with a system area network (SAN).

Note These Windows Sockets Direct extension functions are defined in Ws2san.h and require Windows Sockets version 2.2.

To support the Windows Sockets switch, a SAN service provider must implement all of these extension functions (except the optional WSPRdmaRead and WSPMemoryRegistrationCacheCallback functions). If a SAN service provider does not support either the WSPRdmaRead or WSPMemoryRegistrationCacheCallback extension function, its WSPIoctl function must return the WSAEOPNOTSUPP error code after the switch requests a pointer to WSPRdmaRead or WSPMemoryRegistrationCacheCallback.

See the following topics for more information about the Windows Sockets Direct extension functions:

WSPDeregisterMemory

WSPDeregisterRdmaMemory

WSPMemoryRegistrationCacheCallback

WSPRdmaRead

WSPRdmaWrite

WSPRegisterMemory

WSPRegisterRdmaMemory


WSPDeregisterMemory

WSPDeregisterMemory releases a buffer that was registered by a previous call to the WSPRegisterMemory function.

int
  WSPDeregisterMemory(
    IN SOCKET  s,
    IN HANDLE  Handle,
    OUT LPINT  lpErrno
    );

Parameters

s
Descriptor that identifies a connected socket.
Handle
Handle to the memory buffer that was previously registered.
lpErrno
Pointer to a variable that receives the error code.

Return Value

Returns zero if successful; otherwise, returns SOCKET_ERROR and, at lpErrno, the following error code:

WSAEINVAL
The specified handle to the memory buffer does not represent a previously registered memory buffer, or the SAN service provider cannot release the memory because the memory is currently being used in a data transfer operation.

Headers

Defined in Ws2san.h. Include Ws2san.h. Requires Windows Sockets version 2.2.

Comments

The Windows Sockets switch calls the WSPDeregisterMemory function to release a memory buffer that it previously registered in a call to the WSPRegisterMemory function. In the call to WSPDeregisterMemory, the switch passes the same socket descriptor that it supplied to the WSPRegisterMemory function.

A SAN service provider is not required to return a different handle to a memory buffer when the switch makes an additional call to the WSPRegisterMemory function to register that memory buffer for use by another socket. However, the SAN service provider should maintain an internal reference count of the number of registered instances of that memory buffer. Each time that it is called, the WSPDeregisterMemory function should decrement this internal reference count. Only the final call to the WSPDeregisterMemory function, which causes the function to decrement the internal reference count for the buffer to zero, releases all resources that the SAN service provider used to register the memory buffer.

See Also

WSPMemoryRegistrationCacheCallback, WSPRegisterMemory


WSPDeregisterRdmaMemory

WSPDeregisterRdmaMemory releases an RDMA buffer that was registered by a previous call to the WSPRegisterRdmaMemory function.

int
  WSPDeregisterRdmaMemory(
    IN SOCKET  s,
    IN LPVOID  lpRdmaBufferDescriptor,
    IN DWORD  dwDescriptorLength,
    OUT LPINT  lpErrno
    );

Parameters

s
Descriptor that identifies a connected socket.
lpRdmaBufferDescriptor
Pointer to a memory block that contains a descriptor. This descriptor identifies the RDMA buffer that was previously registered.
dwDescriptorLength
Size, in bytes, of the memory block at lpRdmaBufferDescriptor.
lpErrno
Pointer to a variable that receives the error code.

Return Value

Returns zero if successful; otherwise, returns SOCKET_ERROR and, at lpErrno, the following error code:

WSAEINVAL
The specified pointer to the descriptor for the RDMA buffer does not represent a previously registered RDMA buffer, or the SAN service provider cannot release the RDMA buffer because the RDMA buffer is currently being used in an RDMA data transfer operation.

Headers

Defined in Ws2san.h. Include Ws2san.h. Requires Windows Sockets version 2.2.

Comments

The Windows Sockets switch calls the WSPDeregisterRdmaMemory function to release an RDMA buffer that it previously registered in a call to the WSPRegisterRdmaMemory function. In the call to the WSPDeregisterRdmaMemory function, the switch passes the same socket descriptor that it passed to the WSPRegisterRdmaMemory function.

A SAN service provider is not required to return a different RDMA-buffer descriptor when the switch makes an additional call to WSPRegisterRdmaMemory to register that RDMA buffer for use by another socket. However, the SAN service provider should maintain an internal reference count of the number of registered instances of that RDMA buffer. Calls to the SAN service provider's WSPDeregisterRdmaMemory entry point decrement this internal reference count. Only the final WSPDeregisterRdmaMemory call, which decrements the internal reference count to zero, releases all resources that the SAN service provider consumed to register the RDMA buffer.

See Also

WSPMemoryRegistrationCacheCallback, WSPRegisterRdmaMemory


WSPMemoryRegistrationCacheCallback

WSPMemoryRegistrationCacheCallback releases the SAN service provider's ownership of an application's buffer and the lock between the buffer and physical memory, removes the buffer from the SAN service provider's cache, and removes the buffer registration from the SAN NIC.

int
  WSPMemoryRegistrationCacheCallback(
    IN PVOID  lpvAddress,
    IN SIZE_T  Size,
    OUT LPINT  lpErrno
    );

Parameters

lpvAddress
Pointer to a memory block that contains the starting address of a memory buffer, of which the SAN service provider previously secured ownership. An application that is releasing this buffer triggers the Windows Sockets switch to pass the pointer to this buffer in the WSPMemoryRegistrationCacheCallback call.
Size
Size, in bytes, of the secured memory buffer at lpvAddress, which an application is currently releasing.
lpErrno
Pointer to a variable that receives the error code.

Return Value

Returns zero if successful; otherwise, returns SOCKET_ERROR and, at lpErrno, one of the following error codes:

WSAEFAULT
SAN service provider previously cached the memory buffer but is unable to either release the buffer from physical memory or remove the registration of the buffer with the SAN NIC.
WSAEINVAL
SAN service provider was previously unable to cache the memory buffer.

Headers

Defined in Ws2san.h. Include Ws2san.h. Requires Windows Sockets version 2.2.

Comments

A SAN service provider can cache memory buffer registrations without actually removing the buffer registration from the SAN NIC, to improve the performance of applications that reuse buffers for data transfers. If a SAN service provider caches memory buffer registrations, it must provide a WSPMemoryRegistrationCacheCallback function. For more information about caching buffers, see Caching Registered Memory.

A SAN service provider caches memory buffer registrations based on virtual addresses. When the SAN service provider caches a buffer's registration, the SAN service provider's proxy driver must secure possession of that registered buffer, so that the operating system notifies the switch if the buffer is released. Before the virtual-to-physical mappings of the registered buffer subsequently change, the switch calls each SAN service provider's WSPMemoryRegistrationCacheCallback function. Each SAN service provider's proxy driver, in turn, must release ownership of the buffer. In addition, each SAN service provider must remove the buffer from the cache and must remove the buffer registration from the SAN NIC. For more information about how a proxy driver secures and releases buffers, see Securing and Releasing Ownership of Virtual Addresses.

Because an application can use the same buffer for data transfers over different sockets and at different times, a SAN service provider can register that buffer with multiple sockets. When the switch calls the SAN service provider's WSPMemoryRegistrationCacheCallback function, the SAN service provider must take this fact into account and remove the buffer registration from each SAN NIC associated with each socket.

See Also

MmSecureVirtualMemory, MmUnsecureVirtualMemory, WSPDeregisterMemory, WSPDeregisterRdmaMemory, WSPRegisterMemory , WSPRegisterRdmaMemory


WSPRdmaRead

WSPRdmaRead transfers data from an RDMA buffer in an address space accessible by a socket's remote peer to a buffer in an address space accessible only by the local socket.

int
  WSPRdmaRead(
    IN SOCKET  s,
    IN LPWSABUFEX  lpBuffers,
    IN DWORD  dwBufferCount,
    IN LPVOID  lpTargetBufferDescriptor,
    IN DWORD  dwTargetDescriptorLength,
    IN DWORD  dwTargetBufferOffset,
    OUT LPDWORD  lpdwNumberOfBytesRead,
    IN DWORD  dwFlags,
    IN LPWSAOVERLAPPED  lpOverlapped,
    IN LPWSAOVERLAPPED_COMPLETION_ROUTINE  lpCompletionRoutine,
    IN LPWSATHREADID  lpThreadId,
    OUT LPINT  lpErrno
    );

Parameters

s
Descriptor that identifies a connected socket.
lpBuffers
Pointer to an array of WSABUFEX structures. Each WSABUFEX structure contains members that describe a previously registered buffer in the buffer array. This buffer array receives transferred data. Each buffer was registered in a call to the WSPRegisterMemory function.
dwBufferCount
Number of WSABUFEX structures at lpBuffers.
lpTargetBufferDescriptor
Pointer to a memory block that contains a descriptor. This descriptor identifies an RDMA buffer in the address space accessible by the socket's remote peer. This descriptor was returned from a previous call to the WSPRegisterRdmaMemory function. Data is transferred from this RDMA buffer to the buffer at lpBuffers.
dwTargetDescriptorLength
Size, in bytes, of the memory block at lpTargetBufferDescriptor.
dwTargetBufferOffset
Offset, in bytes, into the RDMA buffer at which to begin the data transfer. The descriptor at lpTargetBufferDescriptor identifies this RDMA buffer. Data is transferred from this RDMA buffer to the buffer at lpBuffers.
lpdwNumberOfBytesRead
Pointer to a variable that receives the number of bytes that WSPRdmaRead transfers from the RDMA buffer to the buffer at lpBuffers.
dwFlags
Set of flags that specify how the call is made.
lpOverlapped
Pointer to a WSAOVERLAPPED structure that provides a communication medium between the initiation of an overlapped I/O operation and its subsequent completion. Ignored for non-overlapped sockets.
lpCompletionRoutine
Pointer to the completion routine that the SAN service provider might initiate after the data transfer operation completes. Ignored for non-overlapped sockets. The switch specifies NULL for a completion routine.
lpThreadId
Pointer to a WSATHREADID structure that the SAN service provider might use in a subsequent call to the WPUQueueApc function to arrange for the execution of the completion routine at lpCompletionRoutine. A WSATHREADID structure identifies a thread. Because the switch specifies NULL for a completion routine, the SAN service provider does not use lpThreadId.
lpErrno
Pointer to a variable that receives the error code.

Return Value

Returns zero if successful and the data transfer operation completed immediately; otherwise returns SOCKET_ERROR and, at lpErrno, one of the following error codes:

WSAENETDOWN
Network subsystem failed.
WSANOBUFS
No memory resources available.
WSAEFAULT
Either the receiving buffer at lpBuffers or the RDMA buffer identified by the descriptor at lpTargetBufferDescriptor is not contained completely within a valid part of the user address space.
WSAEINVAL
Invalid flags specified.
WSAENOTCONN
Socket not connected (connection-oriented sockets only).
WSAENOTSOCK
Descriptor at s is not a socket.
WSAECONNABORTED
Connection to the remote peer was terminated because of a time out or other failure.
WSAECONNRESET
Remote peer terminated the connection.
WSA_IO_PENDING
SAN service provider successfully initiated an overlapped data-transfer operation and will indicate completion at a later time.
WSA_OPERATION_ABORTED
Overlapped operation canceled because socket was closed.

Headers

Defined in Ws2san.h. Include Ws2san.h. Requires Windows Sockets version 2.2.

Comments

The Windows Sockets switch calls WSPRdmaRead to transfer data from the RDMA buffer that is identified by the descriptor at lpTargetBufferDescriptor to the buffer at lpBuffers on the local computer. This RDMA buffer is in the address space for the remote peer connection. The switch at the remote peer connection calls the WSPRegisterRdmaMemory function to register this RDMA buffer for read access. The switch at the remote peer connection then calls the WSPSend function to send to the local switch a control message that indicates the location of this RDMA buffer. The local switch can then call the WSPRdmaRead function to transfer data to a receiving buffer at lpBuffers.

A SAN service provider receives WSPRdmaRead requests only from the switch, never directly from an application. The switch always calls the SAN service provider's WSPRdmaRead function in an overlapped manner. In this call, the switch always specifies an overlapped structure and NULL for a completion routine. In the call to the WSPRdmaRead function, the switch posts RDMA and receiving buffers for the data transfer operation. If the data transfer operation cannot complete immediately, the operation proceeds, but WSPRdmaRead returns with the WSA_IO_PENDING error code. The switch later calls the SAN service provider's WSPGetOverlappedResult function and passes a pointer to the overlapped structure to retrieve the final completion status.

The array of WSABUFEX structures at lpBuffers is transient. If the data transfer operation completes in an overlapped manner, the SAN service provider must capture these WSABUFEX structures before it returns from the WSPRdmaRead function with the WSA_IO_PENDING error code. This requirement enables applications to build stack-based WSABUFEX arrays.

Overlapped socket I/O

If the data transfer operation completes immediately, the SAN service provider returns from the WSPRdmaRead function with a value of zero and specifies the number of bytes transferred from RDMA to receiving buffers at lpdwNumberOfBytesRead. If the SAN service provider successfully initiated the data transfer operation and will indicate completion at a later time, it returns from WSPRdmaRead with a value of SOCKET_ERROR and specifies the WSA_IO_PENDING error code at lpErrno. Note that, in this case, the SAN service provider does not specify a value at lpdwNumberOfBytesRead. After the data transfer operation completes, the switch calls the SAN service provider's WSPGetOverlappedResult function and passes a pointer to a variable in which the SAN service provider specifies the number of bytes transferred from RDMA to receiving buffers.

The overlapped structure at lpOverlapped must be valid for the duration of the data transfer operation. If multiple data transfer operations are outstanding simultaneously, each must reference a separate overlapped structure.

As mentioned previously, the switch always specifies an overlapped structure and NULL for a completion routine whenever it calls the SAN service provider's WSPRdmaRead function in an overlapped manner. Because the switch specifies NULL for a completion routine, the SAN service provider must call the WPUCompleteOverlappedRequest function in the context of an arbitrary thread to complete the request. If the low order bit of the hEvent member in the WSAOVERLAPPED structure is set, the switch specifically requests to not be notified upon completion of the I/O request. Therefore, the SAN service provider is not required to call the WPUCompleteOverlappedRequest function to complete the I/O request. In this case, the switch calls the WSPGetOverlappedResult function to poll for completion. For more information, see the GetQueuedCompletionStatus function in the Platform SDK documentation.

Completion indications can be delivered in any order and not necessarily in the same order that the overlapped operations are completed.

See Also

WSABUFEX, WSAOVERLAPPED, WSPRegisterMemory, WSPRegisterRdmaMemory, WSPRdmaWrite


WSPRdmaWrite

WSPRdmaWrite transfers data from a source buffer in an address space that is accessible only by a local socket to a target buffer in an address space that is accessible by the socket's remote peer.

int
  WSPRdmaWrite(
    IN SOCKET  s,
    IN LPWSABUFEX  lpBuffers,
    IN DWORD  dwBufferCount,
    IN LPVOID  lpTargetBufferDescriptor,
    IN DWORD  dwTargetDescriptorLength,
    IN DWORD  dwTargetBufferOffset,
    OUT LPDWORD  lpdwNumberOfBytesWritten,
    IN DWORD  dwFlags,
    IN LPWSAOVERLAPPED  lpOverlapped,
    IN LPWSAOVERLAPPED_COMPLETION_ROUTINE  lpCompletionRoutine,
    IN LPWSATHREADID  lpThreadId,
    OUT LPINT  lpErrno
    );

Parameters

s
Descriptor that identifies a connected socket.
lpBuffers
Pointer to an array of WSABUFEX structures. Each WSABUFEX structure contains members that describe a previously registered buffer in the source buffer array. Each buffer was registered in a call to the WSPRegisterMemory function.
dwBufferCount
Number of WSABUFEX structures at lpBuffers.
lpTargetBufferDescriptor
Pointer to a memory block that contains a descriptor. This descriptor identifies the target RDMA buffer in the address space that is accessible by the socket's remote peer. This descriptor was returned from a previous call to the WSPRegisterRdmaMemory function.
dwTargetDescriptorLength
Size, in bytes, of the memory block at lpTargetBufferDescriptor.
dwTargetBufferOffset
Offset, in bytes, into the target RDMA buffer at which to begin the data transfer. The descriptor at lpTargetBufferDescriptor identifies this target RDMA buffer.
lpdwNumberOfBytesWritten
Pointer to a variable that receives the number of bytes that WSPRdmaWrite transfers from source to target buffers.
dwFlags
Set of flags that specify how the call is made.
lpOverlapped
Pointer to a WSAOVERLAPPED structure that provides a communication medium between the initiation of an overlapped I/O operation and its subsequent completion. Ignored for non-overlapped sockets.
lpCompletionRoutine
Pointer to the completion routine that the SAN service provider might initiate after the data transfer operation completes. Ignored for non-overlapped sockets. The switch specifies NULL for a completion routine.
lpThreadId
Pointer to a WSATHREADID structure that the SAN service provider might use in a subsequent call to the WPUQueueApc function to arrange for the execution of the completion routine at lpCompletionRoutine. A WSATHREADID structure identifies a thread. Because the switch specifies NULL for a completion routine, the SAN service provider does not use lpThreadId.
lpErrno
Pointer to a variable that receives the error code.

Return Value

Returns zero if successful and the data transfer operation completed immediately; otherwise, returns SOCKET_ERROR and, at lpErrno, one of the following error codes:

WSAENETDOWN
Network subsystem failed.
WSANOBUFS
No memory resources available.
WSAEFAULT
Either the source buffer at lpBuffers or the target buffer identified by the descriptor at lpTargetBufferDescriptor is not contained completely within a valid part of the user address space.
WSAEINVAL
Invalid flags specified.
WSAENOTCONN
Socket not connected.
WSAENOTSOCK
Descriptor at s is not a socket.
WSAECONNABORTED
Connection to the remote peer was terminated because of a time out or other failure.
WSAECONNRESET
Remote peer terminated the connection.
WSA_IO_PENDING
SAN service provider successfully initiated an overlapped data-transfer operation and will indicate completion at a later time.
WSA_OPERATION_ABORTED
Overlapped operation was canceled because socket was closed.

Headers

Defined in Ws2san.h. Include Ws2san.h. Requires Windows Sockets version 2.2.

Comments

The Windows Sockets switch calls the WSPRdmaWrite function to transfer data from the source buffer at lpBuffers on the local computer to the target buffer that is identified by the descriptor at lpTargetBufferDescriptor. This target buffer is in the address space for the remote peer connection. The switch at the remote peer connection calls the WSPRegisterRdmaMemory function to register the target buffer for write access. The switch at the remote peer connection then calls the WSPSend function to send to the local switch a control message that indicates the location of this target buffer. The local switch can then call the WSPRdmaWrite function to transfer data to the target buffer.

A SAN service provider receives WSPRdmaWrite requests only from the switch, never directly from an application. The switch calls the SAN service provider's WSPRdmaWrite function only in an overlapped manner. In this call, the switch always specifies an overlapped structure and NULL for a completion routine. In the call to the WSPRdmaWrite function, the switch posts source and target buffers for the data transfer operation. If the data transfer operation cannot complete immediately, the operation proceeds, but WSPRdmaWrite returns with the WSA_IO_PENDING error code. The switch later calls the SAN service provider's WSPGetOverlappedResult function and passes a pointer to the overlapped structure to retrieve the final completion status.

The array of WSABUFEX structures at lpBuffers is transient. If the data transfer operation completes in an overlapped manner, the SAN service provider must capture these WSABUFEX structures before it returns from WSPRdmaWrite with the WSA_IO_PENDING error code. This requirement enables applications to build stack-based WSABUFEX arrays.

Overlapped socket I/O

If the data transfer operation completes immediately, the SAN service provider returns from the WSPRdmaWrite function with a value of zero and, at lpdwNumberOfBytesWritten, specifies the number of bytes transferred from source to target buffers. If the SAN service provider successfully initiated the data transfer operation and will indicate completion at a later time, the SAN service provider returns from the WSPRdmaWrite function with a value of SOCKET_ERROR and specifies the WSA_IO_PENDING error code at lpErrno. Note that, in this case, the SAN service provider does not specify a value at lpdwNumberOfBytesWritten. After the data transfer operation completes, the switch calls the SAN service provider's WSPGetOverlappedResult function and passes a pointer to a variable that holds data transfer information. In this variable, the SAN service provider specifies the number of bytes transferred from source to target buffers.

The overlapped structure at lpOverlapped must be valid for the duration of the data transfer operation. If multiple data transfer operations are outstanding simultaneously, each must reference a separate overlapped structure.

As mentioned previously, the switch always specifies an overlapped structure and NULL for a completion routine whenever the switch calls the SAN service provider's WSPRdmaWrite function in an overlapped manner. Because the switch specifies NULL for a completion routine, the SAN service provider must call the WPUCompleteOverlappedRequest function in the context of an arbitrary thread to complete the request. If the low order bit of the hEvent member in the WSAOVERLAPPED structure is set, the switch specifically requests to not be notified upon completion of the I/O request. Therefore, the SAN service provider is not required to call the WPUCompleteOverlappedRequest function to complete the I/O request. In this case, the switch calls the WSPGetOverlappedResult function to poll for completion. For more information, see the GetQueuedCompletionStatus function in the Platform SDK documentation.

Completion indications can be delivered in any order and not necessarily in the same order that the overlapped operations are completed.

See Also

WSABUFEX, WSAOVERLAPPED, WSPRegisterMemory, WSPRegisterRdmaMemory


WSPRegisterMemory

WSPRegisterMemory registers a buffer that a socket can use as either the local source or the local target of a data transfer operation. A socket can use this buffer as the source in WSPRdmaWrite and WSPSend calls and the receiving buffer in WSPRdmaRead and WSPRecv calls.

HANDLE
  WSPRegisterMemory(
    IN SOCKET  s,
    IN PVOID  lpBuffer,
    IN DWORD  dwBufferLength,
    IN DWORD  dwFlags,
    OUT LPINT  lpErrno
    );

Parameters

s
Descriptor that identifies a connected socket.
lpBuffer
Pointer to the memory buffer to register.
dwBufferLength
Size, in bytes, of the memory buffer at lpBuffer.
dwFlags
Set of flags that specify supplementary information about the memory buffer and registration options.
lpErrno
Pointer to a variable that receives the error code.

Return Value

Returns a valid handle to the memory buffer if successful; otherwise, returns NULL for the handle and, at lpErrno, one of the following error codes:

WSANOBUFS
No memory resources available.
WSAEFAULT
lpBuffer is not contained completely within a valid part of the user-address space.
WSAEINVAL
Invalid flags specified.
WSAENOTCONN
Socket not connected (connection-oriented sockets only).

Headers

Defined in Ws2san.h. Include Ws2san.h. Requires Windows Sockets version 2.2.

Comments

The Windows Sockets switch calls the WSPRegisterMemory function to register a memory buffer for use by a specific socket. The returned handle to the memory buffer is valid only in the context of the socket for which it was registered.

The switch can call the WSPRegisterMemory function more than once to register the same buffer for use with any number of sockets. A SAN service provider is not required to return a different handle to a memory buffer when the switch registers that memory buffer for use by another socket. However, the SAN service provider should maintain an internal reference count of the number of registered instances of that memory buffer. Calls to the SAN service provider's WSPDeregisterMemory function decrement this internal reference count. Only during the final call to WSPDeregisterMemory (when the SAN service provider's internal reference count for that buffer reaches zero) should the SAN service provider release all the resources that it used to register the buffer.

The switch specifies how the registered memory is to be accessed in dwFlags by specifying one of the following flags:

MEM_READ
Read access
MEM_WRITE
Write access
MEM_READWRITE
Both read and write access

The SAN service provider must obtain memory that can be accessed as specified in dwFlags.

The switch requires that the registered memory have read access if the switch subsequently calls the SAN service provider's WSPRdmaWrite and WSPSend functions. The switch requires that the registered memory buffer have write access if the switch subsequently calls the SAN service provider's WSPRdmaRead and WSPRecv functions.

Even though the switch registers memory buffers that it uses in all data transfer operations, the switch only explicitly uses handles to those memory buffers in RDMA data transfer operations. That is, the switch specifies such handles when calling a SAN service provider's WSPRdmaWrite and WSPRdmaRead functions for RDMA transfers. However, the switch does not specify such handles when calling a SAN service provider's WSPSend and WSPRecv functions for message-oriented transfers. SAN service provider must maintain its own mapping of memory buffers to handles for message-oriented transfers.

A SAN service provider must prevent unauthorized access to memory that the switch registered for local access. Only the process that called WSPRegisterMemory to register memory should be allowed to access such memory. A SAN service provider must ensure that it does not inadvertently make such memory accessible to other processes running on the same computer or on other computers on the SAN.

See Also

WSPDeregisterMemory, WSPMemoryRegistrationCacheCallback, WSPRdmaRead, WSPRdmaWrite


WSPRegisterRdmaMemory

WSPRegisterRdmaMemory registers an RDMA buffer that can be used as either the target buffer in a WSPRdmaWrite call or the source buffer in a WSPRdmaRead call.

int
  WSPRegisterRdmaMemory(
    IN SOCKET  s,
    IN PVOID  lpBuffer,
    IN DWORD  dwBufferLength,
    IN DWORD  dwFlags,
    OUT LPVOID  lpRdmaBufferDescriptor,
    IN/OUT LPDWORD  lpdwDescriptorLength,
    OUT LPINT  lpErrno
    );

Parameters

s
Descriptor that identifies a connected socket.
lpBuffer
Pointer to the RDMA buffer to register.
dwBufferLength
Size, in bytes, of the RDMA buffer at lpBuffer.
dwFlags
Set of flags that specify supplementary information about the RDMA buffer and registration options.
lpRdmaBufferDescriptor
Pointer to a memory block that receives a descriptor that identifies the RDMA buffer at lpBuffer.
lpdwDescriptorLength
Pointer to a variable that contains the size, in bytes, of the memory block at lpRdmaBufferDescriptor. The switch allocates this memory block to receive the RDMA-buffer descriptor and specifies the initial size of the memory block. The SAN service provider returns either the size of the descriptor that it actually stored or the size that it requires.
lpErrno
Pointer to a variable that receives the error code.

Return Value

Returns zero if successful; otherwise, returns SOCKET_ERROR and, at lpErrno, one of the following error codes:

WSANOBUFS
No memory resources available.
WSAEFAULT
lpBuffer is not contained completely within a valid part of the user address space, or the size of lpRdmaDescriptorBuffer is insufficient to contain the descriptor. Note that if lpRdmaDescriptorBuffer is insufficient to contain the descriptor, the SAN service provider must store the required size at lpdwDescriptorLength. If lpBuffer is not contained completely within a valid part of the user address space, the SAN service provider must not overwrite the initial value that the switch supplied.
WSAEINVAL
Invalid flags specified.
WSAENOTCONN
Socket not connected (connection-oriented sockets only).

Headers

Defined in Ws2san.h. Include Ws2san.h. Requires Windows Sockets version 2.2.

Comments

The Windows Sockets switch calls WSPRegisterRdmaMemory to register an RDMA buffer that a specific socket and the remote peer connected to that socket can access. The returned descriptor for the RDMA buffer is valid for RDMA data transfer operations that the remote peer initiates in the context of the peer's connection to the socket.

The switch can call the WSPRegisterRdmaMemory function more than once to register the same RDMA buffer for use by any number of sockets. When this occurs, a SAN service provider is not required to return a different descriptor for the RDMA buffer. However, the SAN service provider should maintain an internal reference count of the number of registered instances of that RDMA buffer. Each time that a SAN service provider's WSPDeregisterRdmaMemory function is called, it should decrement this internal reference count. Only the final WSPDeregisterRdmaMemory call, which decrements the internal reference count to zero, releases all resources that the SAN service provider consumed to register the RDMA buffer.

The switch specifies one of the following dwFlags to indicate how the registered memory is to be accessed.

MEM_READ
Read access
MEM_WRITE
Write access
MEM_READWRITE
Both read and write access

The SAN service provider must obtain memory that can be accessed as specified in dwFlags.

The local switch requires that memory that it registers with a WSPRegisterRdmaMemory call has write access if the switch at the remote peer connection subsequently uses this memory as the target in a call to the SAN service provider's WSPRdmaWrite function; read access is required for memory that is used as the source in a WSPRdmaRead call.

If the switch did not specify a sufficient size at lpdwDescriptorLength for the memory block at lpRdmaBufferDescriptor, the SAN service provider must return the WSAEFAULT error code at lpErrno and store the required size at lpdwDescriptorLength. The switch allocates the memory block at lpRdmaBufferDescriptor to receive the descriptor that identifies the memory buffer.

A SAN service provider must prevent unauthorized access to an RDMA buffer. Only the connection (process) on which that RDMA buffer is registered can have access, as either the process that called WSPRegisterRdmaMemory to register memory, or the process for the remote peer connection to the socket.

Memory that supports both local and remote access must be accessible only when registered and while the connection is established. A SAN service provider must ensure that it does not inadvertently make such memory accessible to other processes running on the same computer, on the remote peer's computer, or on other computers on the SAN. Memory registered only for remote read access must not be available for remote write access. Memory registered only for remote write access must not be available for remote read access.

See Also

WSPDeregisterRdmaMemory, WSPMemoryRegistrationCacheCallback, WSPRdmaRead, WSPRdmaWrite


Windows Sockets Direct Structures

This section describes the structures that a SAN service provider uses. These structures are as follows:

WSABUF

WSABUFEX

WSAOVERLAPPED

WSAPROTOCOLCHAIN

WSAPROTOCOL_INFOW

WSATHREADID

WSPDATA

WSPPROC_TABLE


WSABUF

The WSABUF structure contains information for a Windows Sockets buffer.

typedef struct _WSABUF {
  u_long  len;
  char FAR  *buf;
} WSABUF, FAR * LPWSABUF;

Members

len
Size, in bytes, of the buffer at buf.
buf
Pointer to the buffer.

Headers

Defined in Winsock2.h. Include Winsock2.h. Requires Windows Sockets version 2.0.

See Also

WSPAccept, WSPConnect, WSPGetQOSByName, WSPIoctl, WSPRecv, WSPSend


WSABUFEX

The WSABUFEX structure contains information for a Windows Sockets extended buffer.

typedef struct _WSABUFEX {
  u_long  len;
  char FAR *  buf;
  HANDLE  handle;
} WSABUFEX, FAR * LPWSABUFEX;

Members

len
Size, in bytes, of the buffer at buf.
buf
Pointer to the buffer.
handle
Handle to the buffer. This handle was returned from the WSPRegisterMemory call.

Headers

Defined in Ws2san.h. Include Ws2san.h. Requires Windows Sockets version 2.2.

See Also

WSPRdmaRead, WSPRdmaWrite


WSAOVERLAPPED

The Windows Sockets WSAOVERLAPPED structure provides a communication medium from the initiation of an overlapped I/O operation to its subsequent completion. Windows Sockets defines the WSAOVERLAPPED structure as equivalent to the Win32® OVERLAPPED structure.

typedef struct _WSAOVERLAPPED {
  DWORD  Internal;
  DWORD  InternalHigh;
  DWORD  Offset;
  DWORD  OffsetHigh;
  WSAEVENT  hEvent;
} WSAOVERLAPPED, FAR * LPWSAOVERLAPPED;

Members

Internal
Reserved.
InternalHigh
Reserved.
Offset
Reserved.
OffsetHigh
Reserved.
hEvent
Handle to a WSAEVENT object that represents an event.

Headers

Defined in Winsock2.h. Include Winsock2.h. Requires Windows Sockets version 2.0.

Comments

The SAN service provider exclusively controls only the Offset and OffsetHigh members of the WSAOVERLAPPED structure even though the SAN service provider's WSPGetOverlappedResult function must retrieve three values (byte count, flags, and error) from the structure. A SAN service provider can retrieve these three values any way it chooses as long as it interacts with the behavior of the WPUCompleteOverlappedRequest function properly. The following sequence outlines a typical implementation of WSPGetOverlappedResult:

  1. At the start of an I/O operation, the SAN service provider sets the Internal member of the WSAOVERLAPPED structure to WSS_OPERATION_IN_PROGRESS.
  2. After the I/O operation is complete, the SAN service provider performs the following actions:

    Sets OffsetHigh to the Windows Sockets error code resulting from the I/O operation

    Sets Offset to the flags resulting from the I/O operation

    Calls WPUCompleteOverlappedRequest and passes the number of bytes transferred.

  3. WPUCompleteOverlappedRequest eventually sets the InternalHigh member of the WSAOVERLAPPED structure to the number of bytes transferred and then sets Internal to a value other than WSS_OPERATION_IN_PROGRESS.
  4. After the switch calls the SAN service provider's WSPGetOverlappedResult function, the SAN service provider checks the value in Internal. If the value is WSS_OPERATION_IN_PROGRESS, the SAN service provider waits for the event object (hEvent member) to be set to the signaled state or returns an error, based on the value that the switch passed to the fWait parameter of WSPGetOverlappedResult. If the value is not WSS_OPERATION_IN_PROGRESS, or after the operating system signals the event object, the SAN service provider returns the number of bytes transferred, operation result error code, and flags in the InternalHigh, OffsetHigh, and Offset members, respectively.

See Also

WSPIoctl, WSPRdmaRead, WSPRdmaWrite, WSPRecv, WSPSend


WSAPROTOCOLCHAIN

The Windows Sockets WSAPROTOCOLCHAIN structure contains a counted list of Catalog Entry identifiers that comprise a protocol chain. This structure is defined as:

typedef struct _WSAPROTOCOLCHAIN {
  int  ChainLen;
  DWORD  ChainEntries[MAX_PROTOCOL_CHAIN];
} WSAPROTOCOLCHAIN, *LPWSAPROTOCOLCHAIN;

Members

ChainLen
Length of the chain. The following settings for ChainLen apply:
Setting | Description
0 | Indicates a layered protocol, such as the Windows Socket switch.
1 | Indicates a base protocol, such as a SAN service provider.
>1 | Indicates a protocol chain.

ChainEntries
Array of protocol chain entries.

Headers

Defined in Winsock2.h. Include Winsock2.h. Requires Windows Sockets version 2.0.

Comments

If the length of the chain is greater than one, this structure represents a protocol chain that consists of one or more layered protocols on top of a base protocol. The corresponding Catalog Entry IDs are in the ChainEntries array member, starting with the layered protocol at the top (the zero element in the ChainEntries array) and ending with the base protocol. Refer to the Windows Sockets 2 Service Provider Interface in the Windows Platform SDK documentation for more information on protocol chains.

See Also

WSPSocket, WSPStartupEx


WSAPROTOCOL_INFOW

The Windows Sockets WSAPROTOCOL_INFOW structure is used to store or retrieve complete information for a given protocol.

typedef struct _WSAPROTOCOL_INFO {
  DWORD  dwServiceFlags1;
  DWORD  dwServiceFlags2;
  DWORD  dwServiceFlags3;
  DWORD  dwServiceFlags4;
  DWORD  dwProviderFlags;
  GUID  ProviderId;
  DWORD  dwCatalogEntryId;
  WSAPROTOCOLCHAIN  ProtocolChain;
  int  iVersion;
  int  iAddressFamily;
  int  iMaxSockAddr;
  int  iMinSockAddr;
  int  iSocketType;
  int  iProtocol;
  int  iProtocolMaxOffset;
  int  iNetworkByteOrder;
  int  iSecurityScheme;
  DWORD  dwMessageSize;
  DWORD  dwProviderReserved;
  TCHAR  szProtocol[WSAPROTOCOL_LEN+1];
} WSAPROTOCOL_INFO, *LPWSAPROTOCOL_INFO;

Members

dwServiceFlags1
Bitmask describing the services provided by the protocol. The bitmask can be set with one or more (ORed) of the following flags:
XP1_CONNECTIONLESS
Protocol provides connectionless (datagram) service. This flag is not set by a SAN service provider because it only provides connection-oriented data transfers.
XP1_GUARANTEED_DELIVERY
Protocol guarantees that all data that it sends reaches the intended destination.
XP1_GUARANTEED_ORDER
Protocol guarantees that data arrives in the order in which the protocol sent it and that it is not duplicated. The protocol does not guarantee that the data was delivered.
XP1_MESSAGE_ORIENTED
Protocol honors message boundaries, as opposed to a stream-oriented protocol, which does not honor message boundaries.
XP1_PSEUDO_STREAM
Although the protocol is message-oriented, it ignores message boundaries for all receives. This is convenient when an application does not require that the protocol frame messages.
XP1_GRACEFUL_CLOSE
Protocol supports two-phase (graceful) socket closures. If not set, the protocol performs only abortive closures.
XP1_EXPEDITED_DATA
Protocol supports expedited (urgent) data.
XP1_CONNECT_DATA
Protocol supports data related to a connection request.
XP1_DISCONNECT_DATA
Protocol supports data related to a connection shutdown.
XP1_SUPPORT_BROADCAST
Protocol supports a broadcast mechanism.
XP1_SUPPORT_MULTIPOINT
Protocol supports a multipoint or multicast mechanism. Control and data plane attributes are indicated in the following values.
XP1_MULTIPOINT_CONTROL_PLANE
Indicates whether the control plane is rooted (value = 1) or nonrooted (value = 0).
XP1_MULTIPOINT_DATA_PLANE
Indicates whether the data plane is rooted (value = 1) or nonrooted (value = 0).
XP1_QOS_SUPPORTED
Set by a SAN service provider if it supports quality of service requests.
XP1_RESERVED
Reserved.
XP1_UNI_SEND
Protocol is unidirectional in the send direction.
XP1_UNI_RECV
Protocol is unidirectional in the receive direction.
XP1_IFS_HANDLES
Socket descriptors returned by the provider are handles to installable file system (IFS) objects. This flag is not set by a SAN service provider because the socket descriptors it returns are not handles to IFS objects.
XP1_PARTIAL_MESSAGE
The MSG_PARTIAL flag is supported in WSPSend.

Note that XP1_UNI_SEND and XP1_UNI_RECV are mutually exclusive. The switch sets neither bit for SAN service providers to indicate that the protocol is bidirectional.

dwServiceFlags2
Reserved for additional protocol-defined attributes.
dwServiceFlags3
Reserved for additional protocol-defined attributes.
dwServiceFlags4
Reserved for additional protocol-defined attributes.
dwProviderFlags
Provide information about how this protocol is represented in the protocol catalog. The following flag values are possible:
PFL_MULTIPLE_PROTO_ENTRIES
Indicates that this is one of two or more entries for a single protocol (from a given provider) that is capable of implementing multiple behaviors. An example of this is SPX, which, on the receiving side, can behave either as a message-oriented or a stream-oriented protocol.
PFL_RECOMMENDED_PROTO_ENTRY
Indicates that this is the recommended or most frequently used entry for a protocol that is capable of implementing multiple behaviors.
PFL_HIDDEN
Set by a SAN service provider to indicate that it is only indirectly exposed to applications through the Windows Sockets switch.
PFL_MATCHES_PROTOCOL_ZERO
Indicates that a value of zero in the protocol parameter of WSPSocket matches this protocol entry.
ProviderId
Unique identifier assigned to the SAN service provider by the SAN NIC vendor. This value is useful when more than one service provider is able to implement a particular protocol. An application can use the ProviderId value to distinguish between providers that might otherwise be indistinguishable.
dwCatalogEntryId
Unique identifier assigned by the Windows Sockets interface (Ws2_32.dll) for each WSAPROTOCOL_INFOW structure.
ProtocolChain
A WSAPROTOCOLCHAIN structure that contains a numbered list of Catalog Entry IDs which comprise a protocol chain.

If the length of the chain is 0, this WSAPROTOCOL_INFOW entry represents a layered protocol that has Windows Sockets 2 SPI as both its top and bottom edges (for example, the Windows Sockets switch). If the length of the chain equals 1, this entry represents a base protocol whose Catalog Entry identifier is in the dwCatalogEntryId member of the WSAPROTOCOL_INFOW structure. If the length of the chain is larger than 1, this entry represents a protocol chain that consists of one or more layered protocols on top of a base protocol. The corresponding Catalog Entry identifiers are in the ProtocolChain.ChainEntries array starting with the layered protocol at the top (the zero element in the ProtocolChain.ChainEntries array) and ending with the base protocol. Refer to the Windows Sockets 2 Service Provider Interface specification for more information on protocol chains.

iVersion
Protocol version identifier.
iAddressFamily
Value to pass as the address family parameter to the WSPSocket function to open a socket for this protocol. This value also uniquely defines the structure of protocol addresses (sockaddr structure) used by the protocol--for example, the sockaddr_in structure for TCP/IP.
iMaxSockAddr
Maximum address length, in bytes.
iMinSockAddr
Minimum address length, in bytes.
iSocketType
Value to pass as the socket type parameter to the socket function to open a socket for this protocol.
iProtocol
Value to pass as the protocol parameter to the WSPSocket function to open a socket for this protocol.
iProtocolMaxOffset
Maximum value that may be added to iProtocol when supplying a value for the protocol parameter to the WSPSocket function. Not all protocols allow a range of values. When this is the case, iProtocolMaxOffset is zero.
iNetworkByteOrder
Currently these values are manifest constants (BIGENDIAN and LITTLEENDIAN) that indicate either big-endian or little-endian with the values zero and one, respectively.
iSecurityScheme
Type of security scheme employed, if any. A value of SECURITY_PROTOCOL_NONE is used for protocols that do not incorporate security provisions.
dwMessageSize
Maximum message size supported by the protocol. This is the maximum size that can be sent from any of the host's local interfaces. For protocols that do not support message framing, the actual maximum that can be sent to a given address may be less. There is no standard provision to determine the maximum inbound message size. The following special values are defined:
0
Protocol is stream-oriented; therefore message size is irrelevant.
0x1
Maximum outbound (send) message size is dependent on the underlying network MTU (maximum transmission unit) and therefore cannot be known until after a socket is bound. The switch should use the WSPGetSockOpt function to retrieve the value of SO_MAX_MSG_SIZE after the socket has been bound to a local address.
0xFFFFFFFF
Protocol is message-oriented, but there is no maximum limit to the size of messages that may be transmitted.
dwProviderReserved
Reserved for use by service providers.
szProtocol
Array of characters that contains a human-readable name that identifies the protocol, for example, "TCP". The maximum number of characters allowed is WSAPROTOCOL_LEN, which is defined to be 256.

Headers

Defined in Winsock2.h. Include Winsock2.h. Requires Windows Sockets version 2.0.

See Also

WSAPROTOCOLCHAIN, WSPSocket, WSPStartupEx


WSATHREADID

The WSATHREADID structure enables a SAN service provider to identify a thread on which asynchronous procedure calls (APCs) can be queued with the WPUQueueApc function.

typedef struct _WSATHREADID {
  HANDLE  ThreadHandle;
  DWORD  Reserved;
} WSATHREADID, *LPWSATHREADID;

Members

ThreadHandle
Handle to the thread ID.
Reserved
Reserved.

Headers

Defined in Ws2spi.h. Include Ws2spi.h. Requires Windows Sockets version 2.0.

See Also

WSPIoctl


WSPDATA

The WSPDATA structure contains information that describes a SAN service provider.

typedef struct WSPDATA {
  WORD  wVersion;
  WORD  wHighVersion;
  WCHAR  szDescription[WSPDESCRIPTION_LEN+1];
} WSPDATA, FAR * LPWSPDATA;

Members

wVersion
Version of Windows Sockets SPI that the SAN service provider expects the switch to use.
wHighVersion
Not used.
szDescription
Null-terminated Unicode string into which the SAN service provider copies a description of itself. The text (up to 256 characters in length) can contain any characters except control and formatting characters.

The switch might use szDescription to display a description of the SAN service provider, possibly truncated, in a status message.

Headers

Defined in Ws2spi.h. Include Ws2spi.h. Requires Windows Sockets version 2.0.

See Also

WSPStartupEx


WSPPROC_TABLE

The Windows Sockets WSPPROC_TABLE structure is used to retrieve a table of pointers to a SAN service provider's entry point functions.

typedef struct _WSPPROC_TABLE {
  LPWSPACCEPT  lpWSPAccept;
  LPWSPADDRESSTOSTRING  lpWSPAddressToString;
  LPWSPASYNCSELECT  lpWSPAsyncSelect;
  LPWSPBIND  lpWSPBind;
  LPWSPCANCELBLOCKINGCALL  lpWSPCancelBlockingCall;
  LPWSPCLEANUP  lpWSPCleanup;
  LPWSPCLOSESOCKET  lpWSPCloseSocket;
  LPWSPCONNECT  lpWSPConnect;
  LPWSPDUPLICATESOCKET  lpWSPDuplicateSocket;
  LPWSPENUMNETWORKEVENTS  lpWSPEnumNetworkEvents;
  LPWSPEVENTSELECT  lpWSPEventSelect;
  LPWSPGETOVERLAPPEDRESULT  lpWSPGetOverlappedResult;
  LPWSPGETPEERNAME  lpWSPGetPeerName;
  LPWSPGETSOCKNAME  lpWSPGetSockName;
  LPWSPGETSOCKOPT  lpWSPGetSockOpt;
  LPWSPGETQOSBYNAME  lpWSPGetQOSByName;
  LPWSPIOCTL  lpWSPIoctl;
  LPWSPJOINLEAF  lpWSPJoinLeaf;
  LPWSPLISTEN  lpWSPListen;
  LPWSPRECV  lpWSPRecv;
  LPWSPRECVDISCONNECT  lpWSPRecvDisconnect;
  LPWSPRECVFROM  lpWSPRecvFrom;
  LPWSPSELECT  lpWSPSelect;
  LPWSPSEND  lpWSPSend;
  LPWSPSENDDISCONNECT  lpWSPSendDisconnect;
  LPWSPSENDTO  lpWSPSendTo;
  LPWSPSETSOCKOPT  lpWSPSetSockOpt;
  LPWSPSHUTDOWN  lpWSPShutdown;
  LPWSPSOCKET  lpWSPSocket;
  LPWSPSTRINGTOADDRESS  lpWSPStringToAddress;
} WSPPROC_TABLE, FAR * LPWSPPROC_TABLE;

Members

lpWSPAccept
Pointer to the SAN service provider's WSPAccept function.
lpWSPAddressToString
Set to NULL.
lpWSPAsyncSelect
Set to NULL.
lpWSPBind
Pointer to the SAN service provider's WSPBind function.
lpWSPCancelBlockingCall
Set to NULL.
lpWSPCleanup
Pointer to the SAN service provider's WSPCleanup function.
lpWSPCloseSocket
Pointer to the SAN service provider's WSPCloseSocket function.
lpWSPConnect
Pointer to the SAN service provider's WSPConnect function.
lpWSPDuplicateSocket
Pointer to the SAN service provider's WSPDuplicateSocket function.
lpWSPEnumNetworkEvents
Pointer to the SAN service provider's WSPEnumNetworkEvents function.
lpWSPEventSelect
Pointer to the SAN service provider's WSPEventSelect function.
lpWSPGetOverlappedResult
Pointer to the SAN service provider's WSPGetOverlappedResult function.
lpWSPGetPeerName
Set to NULL.
lpWSPGetSockName
Set to NULL.
lpWSPGetSockOpt
Pointer to the SAN service provider's WSPGetSockOpt function.
lpWSPGetQOSByName
Pointer to the SAN service provider's WSPGetQOSByName function.
lpWSPIoctl
Pointer to the SAN service provider's WSPIoctl function.
lpWSPJoinLeaf
Set to NULL.
lpWSPListen
Pointer to the SAN service provider's WSPListen function.
lpWSPRecv
Pointer to the SAN service provider's WSPRecv function.
lpWSPRecvDisconnect
Set to NULL.
lpWSPRecvFrom
Set to NULL.
lpWSPSelect
Set to NULL.
lpWSPSend
Pointer to the SAN service provider's WSPSend function.
lpWSPSendDisconnect
Set to NULL.
lpWSPSendTo
Set to NULL.
lpWSPSetSockOpt
Pointer to the SAN service provider's WSPSetSockOpt function.
lpWSPShutdown
Set to NULL.
lpWSPSocket
Pointer to the SAN service provider's WSPSocket function.
lpWSPStringToAddress
Set to NULL.

Headers

Defined in Ws2spi.h. Include Ws2spi.h. Requires Windows Sockets version 2.0.

Comments

The members of WSPPROC_TABLE that a SAN service provider sets to NULL represent functions that are never called by the switch; therefore, the SAN service provider does not implement those functions. For more information, see Windows Sockets SPI Functions Not Required for SANs.

See Also

WSPStartupEx


Windows Sockets Helper Functions

This section describes the system-defined WSHXxx functions that a transport driver provides in a user-mode dynamic-link library (DLL) to support the Windows Sockets 2.0 interface.

For an overview of the relationship between a transport driver's Windows Sockets helper DLL and higher layers of the Windows Sockets interface, see Windows Sockets Helper DLL Architecture. For more information about the Windows Sockets 2.0 interface to applications, see the Platform SDK.

The functions described in this section are listed in alphabetical order.


WSHAddressToString

The WSHAddressToString function returns a logical string representation of a socket address that is generally used for display purposes.

INT
  WSHAddressToString(
    IN LPSOCKADDR  Address,
    IN INT  AddressLength,
    IN LPWSAPROTOCOL_INFOW  ProtocolInfo,  OPTIONAL
    OUT LPWSTR  AddressString,
    IN OUT LPDWORD  AddressStringLength
    );

Parameters

Address
Pointer to a SOCKADDR to convert.
AddressLength
Specifies the number of bytes at Address.
ProtocolInfo
Pointer to a WSAPROTOCOL_INFOW structure passed in a user-mode call to WSAAddressToString, or is NULL.
AddressString
Pointer to a caller-provided buffer into which the helper DLL should copy the logical string representation of the address.
AddressStringLength
On input, points to a variable specifying the length in bytes of the buffer provided at AddressString. The helper DLL should reset the value to the number of bytes it actually copied into the buffer at AddressString before it returns control.

Return Value

WSHAddressToString either returns zero to indicate success or one of the following:

WSAEFAULT
The buffer specified at AddressString is too small to copy the logical representation of the address.
WSAEINVAL
The address specified at Address is not a valid address to be translated.

Headers

Declared in wsahelp.h. Include wsahelp.h.

See Also

WSHStringToAddress


WSHEnumProtocols

The WSHEnumProtocols function returns a set of PROTOCOL_INFO structures that inform the caller of the Win32 function EnumProtocols about protocols supported by this helper DLL.

INT
  WSHEnumProtocols(
    IN LPINT  lpiProtocols,  OPTIONAL
    IN LPWSTR  lpTransportKeyName,
    IN OUT LPVOID  lpProtocolBuffer,
    IN OUT LPDWORD  lpdwBufferLength
    );

Parameters

lpiProtocols
Optionally specifies a filter that selects information to be returned about the protocols supported by the helper DLL. If this is NULL, the helper DLL should return information for all protocols it supports.

Otherwise, lpiProtocols points to a zero-terminated array of protocol ID numbers. WSHEnumProtocols should return information only on protocols whose ID appears in the lpiProtocols array. Protocol ID numbers are the third parameter to the socket call (for example, IPPROTO_TCP).

lpTransportKeyName
Pointer to a buffer that contains the name of the registry key that Windows Sockets uses to access this helper DLL. This parameter can be irrelevant; it is useful only if the helper DLL supports protocols that set up several registry keys.
lpProtocolBuffer
Pointer to the output buffer in which WSHEnumProtocols returns the requested set of PROTOCOL_INFO structures. The PROTOCOL_INFO structures must be copied into this buffer as a contiguous array starting at the beginning of the buffer. Variable-length data, such as the protocol name pointed to by the PROTOCOL_INFO structure's lpProtocol member must be written at the end of the buffer.
lpdwBufferLength
On input, points to a variable specifying the total length in bytes of the buffer at lpProtocolBuffer. On output, this variable is set to the number of bytes of information returned or available from WSHEnumProtocols for this call. If the given input buffer is too small, WSHEnumProtocols sets the value at lpdwBufferLength to the number of bytes of available information before it returns control.

Return Value

WSHEnumProtocols either returns a count of PROTOCOL_INFO structures written to the buffer at lpProtocolBuffer, or it returns SOCKET_ERROR if there was an error. If -1 is returned, WSHEnumProtocols must call SetLastError to set the Windows Sockets error code of the error which occurred.

Headers

Declared in wsahelp.h. Include wsahelp.h.


WSHGetBroadcastSockaddr

The WSHGetBroadcastSockaddr function obtains a valid broadcast address for a socket.

INT
  WSHGetBroadcastSockaddr(
    IN PVOID  HelperDllSocketContext,
    OUT PSOCKADDR  Sockaddr,
    OUT PINT  SockaddrLength
    );

Parameters

HelperDllSocketContext
Pointer to a per-socket context area, allocated and initialized by the WSH DLL WSHOpenSocket2 function.
Sockaddr
Pointer to a buffer in which WSHGetBroadcasrSockaddr returns a valid broadcast address, formatted as a SOCKADDR structure.
SockaddrLength
Pointer to a variable in which WSHGetBroadcastSockaddr returns the number of bytes it set in the SOCKADDR structure.

Return Value

WSHGetBroadcastSockaddr returns NO_ERROR to indicate success, or WSAEFAULT to indicate that the buffer at Sockaddr is insufficient in size to contain a full SOCKADDR structure.

Headers

Declared in wsahelp.h. Include wsahelp.h.


WSHGetProviderGuid

The WSHGetProviderGuid function returns the GUID that identifies the protocols supported by the helper DLL. This function is called only during setup of the WSH DLL.

INT
  WSHGetProviderGuid(
    IN LPWSTR  ProviderName,
    OUT LPGUID  ProviderGuid
    );

Parameters

ProviderName
Pointer to a zero-terminated string specifying the name of the provider.
ProviderGuid
Pointer to a variable in which WSHGetProviderGuid returns the GUID that identifies the protocols supported by the helper DLL. A GUID can be generated with UUIDGEN.EXE. For more information about this utility, see the Platform SDK.

Return Value

WSHGetProviderGuid returns NO_ERROR for success or WSAEINVAL if the string at ProviderName does not designate this helper DLL.

Headers

Declared in wsahelp.h. Include wsahelp.h.


WSHGetSockaddrType

The WSHGetSockaddrType function parses a socket address and returns information about it to Windows Sockets.

INT
  WSHGetSockaddrType(
    IN PSOCKADDR  Sockaddr,
    IN DWORD  SockaddrLength,
    OUT PSOCKADDR_INFO  SockaddrInfo
    );

Parameters

Sockaddr
Pointer to the SOCKADDR structure to be evaluated.
SockaddrLength
Specifies the length, in bytes, of the structure at Sockaddr.
SockaddrInfo
Pointer to a buffer in which the helper DLL returns information about the socket address, formatted as a SOCKADDR_INFO structure.

Return Value

WSHGetSockaddrType returns zero if the given socket address is valid for the address family supported by this helper DLL. Otherwise, it returns a Windows Sockets error code.

Headers

Declared in wsahelp.h. Include wsahelp.h.

Comments

Windows Sockets calls WSHGetSockaddrType when it needs information about a SOCKADDR. The helper DLL evaluates both the machine address and endpoint portions of the SOCKADDR. The machine-address portion specifies a particular machine, for example, the IP address in an internet address. The endpoint specifies a particular service on a machine, corresponding to the port number in an internet address.

The SOCKADDR_INFO structure is defined as follows:

typedef struct _SOCKADDR_INFO {
    SOCKADDR_ADDRESS_INFO AddressInfo;
    SOCKADDR_ENDPOINT_INFO EndpointInfo;
} SOCKADDR_INFO, *PSOCKADDR_INFO;

SOCKADDR_ADDRESS_INFO is an enumerated type, with the following possible values:

SockaddrAddressInfoNormal
The address portion of the SOCKADDR has no unusual characteristics.
SockaddrAddressInfoWildcard
The address portion of the SOCKADDR is a "wildcard," meaning that it does not specify a particular address. For example, this corresponds to INADDR_ANY (0.0.0.0) for IP addresses, which an application passes to bind when it has no particular requirements for the IP address used for a socket.
SockaddrAddressInfoBroadcast
The address portion of the SOCKADDR refers to the address family's broadcast address. For example, in IP addresses, this is INADDR_BROADCAST (255.255.255.255).
SockaddrAddressInfoLoopback
The address portion of the SOCKADDR refers to the address family's loopback address. For example, in internet addresses, this is INADDR_LOOPBACK (127.0.0.1).

SOCKADDR_ENDPOINT_INFO also is an enumerated type, with the following possible values:

SockaddrEndpointInfoNormal
The endpoint portion of the SOCKADDR has no unusual characteristics.
SockaddrEndpointInfoWildcard
The endpoint portion of the SOCKADDR is a wildcard, meaning that it could refer to any endpoint. An application, typically a client, can pass a wildcard endpoint to bind when it has no particular requirements for the endpoint assigned. For example, in IP addresses, a port set to zero is a wildcard endpoint.
SockaddrEndpointInfoReserved
The endpoint of the SOCKADDR is reserved, meaning that special privilege is required to bind to it. For example, in internet addresses, a port with a value less than IPPORT_RESERVED (1024) is a reserved endpoint.


WSHGetSocketInformation

The WSHGetSocketInformation function is called when getsockopt is passed an option that Windows Sockets does not explicitly handle.

INT
  WSHGetSocketInformation(
    IN PVOID  HelperDllSocketContext,
    IN SOCKET  SocketHandle,
    IN HANDLE  TdiAddressObjectHandle,
    IN HANDLE  TdiConnectionObjectHandle,
    IN INT  Level,
    IN INT  OptionName,
    OUT PCHAR  OptionValue,
    OUT INT  OptionLength
    );

Parameters

HelperDllSocketContext
Pointer to a per-socket context area, allocated and initialized by the WSH DLL WSHOpenSocket or WSHOpenSocket2 function.
SocketHandle
Specifies the handle to the socket returned by socket or accept.
TdiAddressObjectHandle
Specifies the file object handle representing an open transport address associated with the socket, or NULL if the socket is not yet bound to an address. A nonNULL handle allows the WSH DLL to perform operations directly with the transport through the use of this handle.
TdiConnectionObjectHandle
Specifies the file object handle representing an open connection endpoint associated with the socket, or NULL if the socket is a datagram socket or is not yet connected. A nonNULL handle allows the helper DLL to perform operations directly with the transport through the use of this handle.
Level
Specifies the level passed in the getsockopt call.
OptionName
Specifies the optname passed in the getsockopt call. If this is NULL, the Windows Sockets DLL is simply querying the length of the helper DLL's context information for the socket.
OptionValue
Pointer to a buffer in which WSHGetSocketInformation returns the requested information.
OptionLength
Pointer to a variable in which WSHGetSocketInformation returns the number of bytes transferred into the buffer at OptionValue.

Return Value

WSHGetSocketInformation returns zero if it successfully interprets the given option and carries out whatever operation it requires. Otherwise it returns a Windows Sockets error code, the getsockopt call is failed, and its return is set to the error returned by this helper DLL function.

Headers

Declared in wsahelp.h. Include wsahelp.h.

Comments

WSHGetSocketInformation can provide support for arbitrary options beyond those defined by Windows Sockets. Certain defined options also are passed to the helper DLL because of the different ways in which transport drivers provide support for these options, in particular for the SO_KEEPALIVE and SO_DONTROUTE options.

Any option passed in an application call to getsockopt that the Windows Sockets DLL does not recognize is forwarded to WSHGetSocketInformation. The Windows Sockets DLL relies on each helper DLL to fail calls for which the given option is invalid or unsupported by the helper DLL.

WSHGetSocketInformation and WSHSetSocketInformation are also used to support socket handles shared between separate processes. However, the context information maintained by a helper DLL is not automatically shared between processes because virtual memory in a process is private to that process unless both processes set up shared memory.

To support shared socket handles, the Windows Sockets DLL calls WSHGetSocketInformation with the Level SOL_INTERNAL and the OptionName SO_CONTEXT. If necessary, the Windows Sockets DLL calls WSHGetSocketInformation twice: first to determine how large a buffer to allocate for context information and again to get the context information.

Windows Sockets allocates a buffer of the size of the helper DLL's context for the socket before it calls WSHGetSocketInformation with a pointer to the allocated buffer at OptionValue. This call requests WSHGetSocketInformation to retrieve all context information the helper DLL has for the socket. The helper DLL copies its context information into the buffer at OptionValue and returns.

When a socket handle is valid in a new process, either by inheritance of the handle or a call to the Win32® function DuplicateHandle, Windows Sockets first calls WSHOpenSocket or WSHOpenSocket2 in the normal manner to inform the helper DLL that a new socket is being opened. Next Windows Sockets calls WSHSetSocketInformation with the OptionLevel SOL_INTERNAL, the OptionName SO_CONTEXT, and the context information returned by WSHGetSocketInformation in the OptionValue buffer. WSHSetSocketInformation uses the supplied context information to recreate the socket context for the new process.

See Also

WSHOpenSocket, WSHOpenSocket2, WSHSetSocketInformation


WSHGetWildcardSockaddr

The WSHGetWildcardSockaddr function returns a socket address that can be used to bind a socket to an arbitrary or wildcard address.

INT
  WSHGetWildcardSockaddr(
    IN PVOID  HelperDllSocketContext,
    OUT PSOCKADDR  Sockaddr,
    OUT PINT  SockaddrLength
    );

Parameters

HelperDllSocketContext
Pointer to a per-socket context area, allocated and initialized by the WSH DLL WSHOpenSocket or WSHOpenSocket2 function.
Sockaddr
Pointer to a buffer in which the helper DLL returns the socket address, formatted in a SOCKADDR structure.
SockaddrLength
Specifies the length in bytes of the buffer at Sockaddr.

Return Value

WSHGetWildcardSockaddr returns zero if it returned an address at Sockaddr. If it could not determine a value for the wildcard address, it returns a WSAXXX error code.

Headers

Declared in wsahelp.h. Include wsahelp.h.

Comments

Windows Sockets calls WSHGetWildcardSockaddr when it needs to perform an automatic bind of a socket. Such a bind is necessary when an application, typically a client-side application, requests an operation that requires a handle to a file object representing a transport address but that application has not bound the socket to an address.

For example, an application that calls either connect or sendto without having called bind causes a call to WSHGetWildcardSockAddr because the Windows Sockets DLL must bind the socket to an arbitrary local address. In these circumstances, WSHGetWildcardSockaddr returns any address that can be used for this bind, while Windows Sockets uses the returned address.

If a transport does not support automatic binds to an arbitrary address, the helper DLL's WSHGetWildcardSockaddr either can fail all calls or the helper DLL can simply not export this function. Such a tranport requires Windows Sockets applications running over that transport to always bind before making any calls to Windows Sockets functions that require a bound socket.


WSHGetWinsockMapping

The WSHGetWinSockMapping function returns information about the address family, socket type, and protocol parameter triples supported by this helper DLL.

DWORD
  WSHGetWinsockMapping(
    OUT PWINSOCK_MAPPING  Mapping,
    IN DWORD  MappingLength
    );

Parameters

Mapping
Pointer to a WINSOCK_MAPPING-structured buffer in which WSHGetWinsockMapping returns information that describes the parameters supported by this helper DLL.
MappingLength
Specifies the size in bytes of the buffer at Mapping.

Return Value

WSHGetWinsockMapping returns the number of bytes of WINSOCK_MAPPING information used by this helper DLL. If the given MappingLength is too small, the return value indicates how large a buffer is necessary to contain the helper DLL's WINSOCK_MAPPING information.

Headers

Declared in wsahelp.h. Include wsahelp.h.

Comments

WSHGetWinsockMapping returns information about the types of sockets supported by this helper DLL. The WINSOCK_MAPPING structure is defined as follows:

typedef struct WINSOCK_MAPPING {
    DWORD Rows;
    DWORD Columns;
    struct {
        DWORD AddressFamily;
        DWORD SocketType;
        DWORD Protocol;
    } Mapping[1];
} WINSOCK_MAPPING, *PWINSOCK_MAPPING;

Members of this structure contain the following information:

Rows
Specifies the number of entries in the Mapping array.
Columns
Specifies three.
Mapping
Is an array with Rows elements, each of which specifies an address family, socket type, and protocol triple supported by the helper DLL.

The Mapping returned should be exactly the same as the value stored under the transport driver's ..Parameters\Winsock registry key for Mapping. The setup utility routines mentioned in the Network Driver Design Guide actually call WSHGetWinsockMapping to obtain the mapping information to be written into the registry.


WSHGetWSAProtocolInfo

The WSHGetWSAProtocolInfo function returns a pointer to a WSAPROTOCOL_INFOW structure, which describes the characteristics of the protocol(s) supported by this helper DLL. This function is only called during setup of the WSH DLL.

INT
  WSHGetWSAProtocolInfo(
    IN LPWSTR  ProviderName,
    OUT LPWSAPROTOCOL_INFOW  *ProtocolInfo,
    OUT LPDWORD  ProtocolInfoEntries
    );

Parameters

ProviderName
Pointer to a buffered zero-terminated string specifying the name of the provider.
ProtocolInfo
Pointer to a buffer in which WSHGetWSAProtocolInfo returns the characteristics of the protocol, formatted as a WSAPROTOCOL_INFOW structure.
ProtocolInfoEntries
Pointer to a variable in which WSHGetWSAProtocolInfo returns the number of entries in the array returned at ProtocolInfo.

Return Value

WSHGetWSAProtocolInfo returns zero if the operation was successful. Otherwise, WSHGetWSAProtocolInfo returns WSAEFAULT to indicate a problem with the input buffer parameters.

Headers

Declared in wsahelp.h. Include wsahelp.h.


WSHIoctl

The WSHIoctl function returns information or carries out a particular operation specified by the given IoControlCode.

INT
  WSHIoctl(
    IN PVOID  HelperDllSocketContext,
    IN SOCKET  SocketHandle,
    IN HANDLE  TdiAddressObjectHandle,
    IN HANDLE  TdiConnectionObjectHandle,
    IN DWORD  IoControlCode,
    IN LPVOID  InputBuffer,
    IN DWORD  InputBufferLength,
    IN LPVOID  OutputBuffer,
    IN DWORD  OutputBufferLength,
    OUT LPDWORD  NumberOfBytesReturned,
    IN LPWSAOVERLAPPED  Overlapped,
    IN LPWSAOVERLAPPED_COMPLETION_ROUTINE  CompletionRoutine,
    OUT LPBOOL  NeedsCompletion
    );

Parameters

HelperDllSocketContext
Pointer to a per-socket context area, allocated and initialized by the WSH DLL WSHOpenSocket or WSHOpenSocket2 function.
SocketHandle
Specifies a handle to the socket that is the target of the requested operation.
TdiAddressObjectHandle
Specifies the handle to a file object representing the open transport address for the socket. If the socket is not currently bound to an address, this parameter is NULL.
TdiConnectionObjectHandle
Specifies the handle to a file object representing the connection endpoint associated with the socket. If the socket is not currently connected, this parameter is NULL.
IoControlCode
Specifies an SIO_XXX code requesting a specific operation. The following are possible system-defined IoControlCodes:
SIO_FIND_ROUTE
Requests that the route to this socket be determined. InputBuffer will be NULL. However, OutputBuffer must not be null.
SIO_FLUSH
Requests that the current contents of the send queue for the socket be flushed. InputBuffer and OutputBuffer will be NULL.
SIO_MULTIPOINT_LOOPBACK
Requests that, whenever data is sent on a multipoint session socket, the data also be sent to the socket on the local host if the data in InputBuffer is TRUE. Otherwise, the socket is requested to terminate that behavior.
SIO_MULTICAST_SCOPE
Sets, for the socket specified, wheter data sent on a multipoint sessions socket will cross routers. If the InputBuffer contains zero, no data should be sent except to multipoint session members on the local host. The value one indicates that no routers should be crossed. Values greater than one indicate that n-1 routers may be crossed when data is sent.

A helper DLL also can define its own codes.

InputBuffer
Pointer to an input buffer for the operation requested by the given IoControlCode.
InputBufferLength
Specifies the length in bytes of the buffer at InputBuffer.
OutputBuffer
Pointer to an output buffer for the operation requested by the given IoControlCode. This buffer is used to return information or query results to the caller.
OutputBufferLength
Specifies the length in bytes of the buffer at OutputBuffer.
NumberOfBytesReturned
On return, specifies the number of bytes copied into the buffer at OutputBuffer.
Overlapped
Specifies a pointer to a WSAOVERLAPPED structure to facilitate asynchronous I/O.
CompletionRoutine
Specifies a pointer to a WSAOVERLAPPED_COMPLETION_ROUTINE provided by the caller.
NeedsCompletion
On output, specifies whether the service provider should perform I/O completion operations for overlapped requests.

Return Value

WSHIoctl returns zero to indicate successful operation. Otherwise, it returns a Winsock Error code, as outlined in the following:

WSAENETDOWN
Specifies that the network has failed.
WSAEFAULT
Specifies that one or more of the buffers at InputBuffer or OutputBuffer are too small for successful operation.
WSAEINVAL
Specifies that the IoControlCode is not a valid command or that a supplied parameter is invalid.
WSAEINPROGRESS
Specifies that WSHIoctl was called while there was a completion routine callback in progress. This error can be returned only if the helper DLL handles I/O completion of overlapped requests itself.
WSAEOPNOTSUPP
Specifies that a normally valid IoControlCode is inappropriate to this socket. This generally indicates that the requested operation is not supported by the underlying protocol.
WSA_IO_PENDING
Specifies that the request is still in progress and will be completed at a later time. This error code can be returned only if overlapped information has been supplied at Overlapped or OverlappedRoutine.
WSAEWOULDBLOCK
Specifies that this operation would block the socket but the socket has been marked as a non-blocking socket.

Headers

Declared in wsahelp.h. Include wsahelp.h.

Comments

WSHIoctl is called by the service provider to satisfy several types of requests. In addition, it is possible for a helper DLL to support operations designated by privately defined I/O control codes specific to a protocol that the helper DLL supports. Such privately defined codes will be transmitted to the helper DLL by WSAIoctl. For more information on WSAIoctl or custom control codes, see the Platform SDK.

Because some operations that are normally requested through WSHIoctl can require a significant amount of time to complete, an overlapped I/O mechanism is provided. A caller either specifies a WSAOVERLAPPED structure in Overlapped or specifies a callback routine in OverlappedRoutine.

When such an I/O operation is completed, the helper DLL can either handle I/O completion in the overlapped manner itself, or allow the service provider to handle such operations. This is controlled by the NeedsCompletion parameter.

If the helper DLL chooses to handle the I/O completion itself, the following guidelines apply:

  • If a completion routine is specified in OverlappedRoutine, the structure provided at Overlapped should be ignored.
  • If a completion routine is not specified, then the Overlapped parameter is used. The event handle provided in this structure should be signalled to indicate to the caller that the I/O has completed.
  • When calling a completion routine provided at OverlappedRoutine, the number of bytes transferred, normally returned in NumberOfBytesReturned and an error code (zero indicating success) must be passed as the defined parameters to this caller-supplied I/O completion routine.


WSHJoinLeaf

The WSHJoinLeaf function performs any protocol-specific actions that must be taken to add a socket to a multipoint session as a leaf node.

INT
  WSHJoinLeaf(
    IN PVOID  HelperDllSocketContext,
    IN SOCKET  SocketHandle,
    IN HANDLE  TdiAddressObjectHandle,
    IN HANDLE  TdiConnectionObjectHandle,
    IN PVOID  LeafHelperDllSocketContext,
    IN SOCKET  LeafSocketHandle,
    IN PSOCKADDR  Sockaddr,
    IN DWORD  SockaddrLength,
    IN LPWSABUF  CallerData,
    IN LPWSABUF  CalleeData,
    IN LPQOS  SocketQOS,
    IN LPQOS  GroupQOS,
    IN DWORD  Flags
    );

Parameters

HelperDllSocketContext
Pointer to a per-socket context area, allocated and initialized by the WSH DLL WSHOpenSocket or WSHOpenSocket2 function.
SocketHandle
Specifies the handle to the socket that was used to establish a multipoint session.
TdiAddressObjectHandle
Specifies the handle to a file object representing the open transport address for the socket.
TdiConnectionObjectHandle
Specifies the handle to a file object representing the connection endpoint associated with the socket. If the socket is not currently connected, this parameter is NULL.
LeafHelperDllSocketContext
Pointer to a helper DLL-defined socket context for a newly created socket (created by WSHOpenSocket2) that is being added as a new leaf node on the multipoint session.
LeafSocketHandle
Specifies the handle to the newly created socket that is being added to the multipoint session.
Sockaddr
Pointer to the value from WSAJoinLeaf for the name of the peer socket with which the leaf will be merged.
SockaddrLength
Specifies the length in bytes at Sockaddr.
CallerData
Pointer to a buffer containing data that should be transmitted to the peer socket when the sockets are joined.
CalleeData
Pointer to a buffer in which WSAJoinLeaf returns any data transmitted by the peer socket when the sockets are joined.
SocketQOS
Pointer to a quality-of-service flow specification for the multipoint session of the original socket as specified by the given SocketHandle. This parameter specifies quality of service for each direction of data.
GroupQOS
Pointer to a quality-of-service flow specification for the socket group. This specification cannot be used to change the QOS of the socket group, but can be used to modify the newly joined socket's QOS as part of that group.
Flags
Specifies whether the socket being created as a new leaf node acts as a sender, receiver, or both as one of the following:
JL_SENDER_ONLY
The new leaf node will act as a sender of data only.
JL_RECEIVER_ONLY
The new leaf node will act as a receiver of data only
JL_BOTH
The new leaf node will act as both a sender and receiver of data.

Return Value

WSHJoinLeaf returns zero if the input parameters are valid and the function successful. Otherwise, it returns a nonzero value corresponding to a Windows Sockets error code, defined in winsock2.h.

Headers

Declared in wsahelp.h. Include wsahelp.h.

Comments

WSHJoinLeaf is responsible for performing any protocol-specific actions required to add a new socket to a multipoint session, including verifying parameters for applicability to the protocol being supported. WSHJoinLeaf must verify all parameters because no parameter checking is done between the call to WSAJoinLeaf and WSHJoinLeaf.

When the multipoint session is established, the helper DLL should transmit any data specified at CallerData to the peer-level socket when the connection is made. Any data returned by the peer socket should be copied into the buffer at CalleeData. If the protocol does not support the transmission of caller-supplied data and CallerData is nonNULL, the helper DLL should return WSAEPROTONOSUPPORT.

If the buffer sizes for CalleeData, SocketQOS, or GroupQOS are too small, then the error WSAEFAULT should be returned.

If a quality-of-service specification is provided at SocketQOS or GroupQOS but quality of service is not supported by the protocol, WSAEOPNOTSUPP should be returned. This error should also be returned if the given quality of service specification(s) cannot be met.

If an attempt to allocate memory to complete the join request fails, WSHJoinLeaf should return WSAENOBUFS to indicate that a low memory condition exists.

See Also

WSHOpenSocket2


WSHNotify

The WSHNotify function is called by the Windows Sockets DLL when a socket-state transition occurs for which the helper DLL's WSHOpenSocket or WSHOpenSocket2 function already requested notifications.

INT
  WSHNotify(
    IN PVOID  HelperDllSocketContext,
    IN SOCKET  SocketHandle,
    IN HANDLE  TdiAddressObjectHandle,
    IN HANDLE  TdiConnectionObjectHandle,
    IN DWORD  NotifyEvent
    );

Parameters

HelperDllSocketContext
Pointer to a per-socket context area, allocated and initialized by the WSH DLL WSHOpenSocket or WSHOpenSocket2 function.
SocketHandle
Specifies the handle to the socket returned by socket or accept.
TdiAddressObjectHandle
Specifies the handle to a file object representing the open transport address for the socket. If the socket is not currently bound to an address, this parameter is NULL.
TdiConnectionObjectHandle
Specifies the handle to a file object representing the connection endpoint associated with the socket. If the socket is not currently connected, this parameter is NULL.
NotifyEvent
Specifies the state change that just occurred. Exactly one bit of the WSH_NOTIFY_XXX values, defined in wsahelp.h, is set in this parameter at each call to WSHNotify. The WSH_NOTIFY_XXX values include the following:
WSH_NOTIFY_BIND
A successful call to bind occurred.
WSH_NOTIFY_LISTEN
A successful call to listen occurred.
WSH_NOTIFY_ACCEPT
A socket handle is being returned from a call to accept.
WSH_NOTIFY_CONNECT
A successful call to connect occurred.
WSH_NOTIFY_SHUTDOWN_RECEIVE
A successful call to shutdown for the receive side of the socket occurred.
WSH_NOTIFY_SHUTDOWN_SEND
A successful call to shutdown for the send side of the socket occurred.
WSH_NOTIFY_SHUTDOWN_ALL
A successful call to shutdown for both sides of the socket occurred.
WSH_NOTIFY_CLOSE
The socket is being closed.
WSH_NOTIFY_CONNECT_ERROR
A failed call to WSAConnect or connect.

The helper DLL's WSHOpenSocket(2) function already selected the set of possible events for which WSHNotify will be called from the preceding values.

Return Value

WSHNotify returns zero to confirm that the specified state-transition occurred. Otherwise, it returns a Windows Sockets error code. When the return value is nonzero, the application's call to the socket function that would cause a state transition fails and the error is set to the value returned by WSHNotify.

Because WSHNotify is called after all other aspects of a particular state-change succeeded, the socket can be left in a state where the only valid operation is to close the socket when WSHNotify returns an error.

Headers

Declared in wsahelp.h. Include wsahelp.h.

Comments

WSHNotify serves two purposes:

  1. To allow a helper DLL to track the state of a socket
  2. To give a helper DLL an opportunity to support options requiring the socket to be in a specific state

For example, the Windows Sockets helper DLL for TCP/IP uses this routine to set a reminder to enable its keep-alive option when an application calls setsockopt before the socket is connected. In these circumstances, no TDI connection object exists when the keep-alive reminder is set, but the helper DLL can actually set the option as soon as the socket becomes connected.

Whenever a helper DLL's WSHNotify function receives a WSH_NOTIFY_CLOSE event, it can free any context it has set up for the socket. After a successful call to WSHNotify with this event, the Windows Sockets DLL never again calls the helper DLL with the same HelperDllSocketContext unless that helper DLL reuses the context areas it allocates. That is, the helper DLL returns the same value from a subsequent call to WSHOpenSocket or WSHOpenSocket2.

See Also

WSHOpenSocket, WSHOpenSocket2


WSHOpenSocket

The WSHOpenSocket function is called by the Windows Sockets DLL when opening a socket.

INT
  WSHOpenSocket(
    IN OUT PINT  AddressFamily,
    IN OUT PINT  SocketType,
    IN OUT PINT  Protocol,
    OUT PUNICODE_STRING  TransportDeviceName,
    OUT PVOID  HelperDllSocketContext,
    OUT PDWORD  NotificationEvents
    );

Parameters

AddressFamily
On input, propagates the address family specified in the call to socket. WSHOpenSocket resets this to the canonicalized value for the address family.

For example, if this is AF_UNSPEC on input, socket type is SOCK_STREAM, and protocol is IPPROTO_TCP, WSHOpenSocket resets this parameter to AF_INET.

SocketType
On input, propagates the socket type specified in the call to socket. WSHOpenSocket resets this to the canonicalized value for the socket type.

For example, if this is zero on input, address family is AF_INET, and protocol is IPPROTO_TCP, WSHOpenSocket resets this parameter to SOCK_STREAM.

Protocol
On input, this is set to the value specified in the call to socket. WSHOpenSocket resets this to the canonicalized value for the protocol.

For example, if this is zero on input, address family is AF_INET, and socket type is SOCK_STREAM, WSHOpenSocket resets this parameter to IPPROTO_TCP.

TransportDeviceName
Pointer to a Unicode counted string, specifying the name of the TDI transport that will handle the socket.
HelperDllSocketContext
Pointer to a variable that the helper DLL sets to a pointer to a context area that the helper DLL allocates. The Windows Sockets DLL treats this as a handle, passing it uninterpreted to the helper DLL in all subsequent calls to WSH Xxx functions involving the socket currently being opened. The helper DLL uses its context area to maintain state for tracking operations on the open socket.
NotificationEvents
Pointer to a bitmask variable that the helper DLL sets to specify the state-change events for which the Windows Sockets DLL should call the helper DLL's WSHNotify function. A helper DLL can request notifications by setting this variable to a combination (ORed) of the following, as defined in wsahelp.h:
WSH_NOTIFY_BIND
Call WSHNotify on a successful call to bind.
WSH_NOTIFY_LISTEN
Call WSHNotify on a successful call to listen.
WSH_NOTIFY_ACCEPT
Call WSHNotify when a socket handle is being returned from the accept function.
WSH_NOTIFY_CONNECT
Call WSHNotify on a successful call to connect.
WSH_NOTIFY_SHUTDOWN_RECEIVE
Call WSHNotify on a successful call to shutdown for the receive side of the socket.
WSH_NOTIFY_SHUTDOWN_SEND
Call WSHNotify on a successful call to shutdown for the send side of the socket.
WSH_NOTIFY_SHUTDOWN_ALL
Call WSHNotify on a successful call to shutdown for both sides of the socket.
WSH_NOTIFY_CLOSE
Call WSHNotify when the socket is being closed.
WSH_NOTIFY_CONNECT_ERROR
Call WSHNotify when on a failed called to connect occurred.

Return Value

WSHOpenSocket returns zero if the given parameters are valid. Otherwise, it returns a Windows Sockets error code. If its return value is nonzero, the socket or accept call fails and the error is set to the value returned by WSHOpenSocket.

Headers

Declared in wsahelp.h. Include wsahelp.h.

Comments

The Windows Sockets DLL calls WSHOpenSocket whenever it is creating a new socket, either when an application calls socket or when a newly connected socket is being created by the accept function. If the helper DLL exports WSHOpenSocket2, it supersedes WSHOpenSocket.

WSHOpenSocket verifies and canonicalizes the address family, socket type, and protocol parameters so that the Windows Sockets DLL can depend on a unique triple for each type of socket.

WSHOpenSocket also allocates any necessary context structure to track subsequent operations on the open socket, and, through the NotificationEvents parameter, indicates to the Windows Sockets DLL the state-transition events at which the helper DLL does additional processing.

A WSH DLL must set NotificationEvents with WSH_NOTIFY_CLOSE if it allocates memory for per-socket context and returns a pointer at HelperDllSocketContext. Otherwise, a memory leak can occur.

See Also

WSHNotify, WSHOpenSocket2


WSHOpenSocket2

The WSHOpenSocket2 function is called by the MSAFD support DLL in response to an application call to WSASocket.

INT
  WSHOpenSocket2(
    IN OUT PINT  AddressFamily,
    IN OUT PINT  SocketType,
    IN OUT PINT  Protocol,
    IN GROUP  Group,
    IN DWORD  Flags,
    OUT PUNICODE_STRING  TransportDeviceName,
    OUT PVOID  *HelperDllSocketContext,
    OUT PDWORD  NotificationEvents
    );

Parameters

AddressFamily
On input, points to a variable that is set to the address family as specified in the WSASocket call. On output, the variable should be set to the canonicalized value for the address family.
SocketType
On input, points to a variable that is set to the socket type as specified in the WSASocket call. On output, the variable should be set to the canonicalized value for the socket type.
Protocol
On input, points to a variable that is set to the protocol as specified in the WSASocket call. On output, the variable should be set to the canonicalized value for the protocol.
Group
Identifies the group to which the socket that is being opened should belong if nonzero. (For more information about socket grouping, see the Win32 SDK.) Alternatively, this can be one of the following constants to create a new group of sockets.
SG_UNCONSTRAINED_GROUP
Create an new unconstrained group of sockets and have this socket become the first member of that group.
SG_CONSTRAINED_GROUP
Create a new constrained group of sockets and have this socket become the first member of that group.

MSAFD will handle all group mechanisms. The group number, if specified instead of one of the preceding flags, is provided for informational purposes.

Flags
Specifies attributes for the new socket that is to be created. (For more information about Windows Sockets 2 multipoint and root/leaf sockets, see the Platform SDK.) The following lists valid flags that can be specified:
WSA_FLAG_OVERLAPPED
Indicates that a socket capable of handing overlapped I/O should be created. If this flag is set, overlapped I/O can be further utilized on calls to WSASend, WSASendTo, WSARecv, WSARecvFrom and WSAIoctl.
WSA_FLAG_MULTIPOINT_C_ROOT
Indicates that the socket should be created as a c_root in a multipoint session.
WSA_FLAG_MULTIPOINT_C_LEAF
Indicates that the socket should be created as a c_leaf in a multipoint session.
WSA_FLAG_MULTIPOINT_D_ROOT
Indicates that the socket should be created as a d_root in a multipoint session.
WSA_FLAG_MULTIPOINT_D_LEAD
Indicates that the socket should be created as a d_leaf in a multipoint session.
TransportDeviceName
Pointer to a buffered Unicode string that specifies the device name of the transport driver that will support this socket type. Storage for the UNICODE_STRING structure is allocated by the caller, and the string initialized with the transport device name, such as \\Device\\Tcp.
HelperDllSocketContext
Pointer to a variable in which WSHOpenSocket2 returns the address of a memory block that can be dynamically allocated. The returned pointer is passed to the helper DLL in all subsequent calls regarding the newly created socket. The helper DLL can use this block of memory to maintain per-socket information.
NotificationEvents
Pointer to a bitmask variable that the helper DLL sets to specify the state-change events for which the Windows Sockets DLL should call the helper DLL's WSHNotify function. A helper DLL can request notifications by setting this variable to a combination (ORed) of the following, as defined in wsahelp.h:
WSH_NOTIFY_BIND
Call WSHNotify on a successful call to bind.
WSH_NOTIFY_LISTEN
Call WSHNotify on a successful call to listen.
WSH_NOTIFY_ACCEPT
Call WSHNotify when a socket handle is being returned from the WSAAccept or accept function.
WSH_NOTIFY_CONNECT
Call WSHNotify on a successful call to WSAConnect or connect.
WSH_NOTIFY_SHUTDOWN_RECEIVE
Call WSHNotify on a successful call to shutdown for the receive side of the socket.
WSH_NOTIFY_SHUTDOWN_SEND
Call WSHNotify on a successful call to shutdown for the send side of the socket.
WSH_NOTIFY_SHUTDOWN_ALL
Call WSHNotify on a successful call to shutdown for both sides of the socket.
WSH_NOTIFY_CLOSE
Call WSHNotify when the socket is being closed.
WSH_NOTIFY_CONNECT_ERROR
Call WSHNotify when a socket fails a call to WSAConnect or connect occurred.

Return Value

WSHOpenSocket2 returns zero to indicate a successful creation of a socket. If this function returns a nonzero value, the corresponding call to WSASocket or WSAAccept fails. If so, the helper DLL should return an appropriate Windows Sockets error code as defined in winsock2.h.

Headers

Declared in wsahelp.h. Include wsahelp.h.

Comments

WSHOpenSocket2 is called by the sockets service provider, such as MSAFD.DLL, to create a new socket. A new socket will be created by a call to WSASocket or by WSAAccept.

The helper DLL should canonicalize and verify the input parameters so that Windows Sockets 2 can rely on a unique triple for each type of socket. The parameters for creating a root or leaf depend on the underlying protocol.

Before it returns control, WSHOpenSocket2 should allocate necessary memory for a socket-specific context structure, set a notification bitmask, and set the name of the transport driver that handles this socket.

A WSH DLL must set NotificationEvents with WSH_NOTIFY_CLOSE if it allocates memory for per-socket context and returns a pointer at HelperDllSocketContext. Otherwise, a memory leak can occur.

See Also

WSHNotify


WSHSetSocketInformation

The WSHSetSocketInformation function is called by the Windows Sockets DLL whenever an application calls setsockopt with an option that Windows Sockets does not explicitly handle.

INT
  WSHSetSocketInformation(
    IN PVOID  HelperDllSocketContext,
    IN SOCKET  SocketHandle,
    IN HANDLE  TdiAddressObjectHandle,
    IN HANDLE  TdiConnectionObjectHandle,
    IN INT  Level,
    IN INT  OptionName,
    IN PCHAR  OptionValue,
    IN INT  OptionLength
    );

Parameters

HelperDllSocketContext
Pointer to a per-socket context area, allocated and initialized by the WSH DLL WSHOpenSocket or WSHOpenSocket2 function.
SocketHandle
Specifies the handle of the socket returned by socket or accept.
TdiAddressObjectHandle
Specifies the handle to a file object representing the open transport address for the socket. If the socket is not currently bound to an address, this parameter is NULL.
TdiConnectionObjectHandle
Specifies the handle to a file object representing the connection endpoint associated with the socket. If the socket is not currently connected, this parameter is NULL.
Level
Specifies the level passed in the setsockopt call.
OptionName
Specifies the optname passed in the setsockopt call.
OptionValue
Pointer to a buffer passed as the optval argument to setsockopt. This buffer contains caller-supplied data for the set operation.
OptionLength
Specifies the size in bytes of the buffer at OptionValue.

Return Value

WSHSetSocketInformation returns zero if it successfully interprets the given option and carries out whatever operation it requires. Otherwise it returns a Windows Sockets error code. If the return value is nonzero, the setsockopt call fails and the error is set to the value returned by WSHSetSocketInformation.

Headers

Declared in wsahelp.h. Include wsahelp.h.

Comments

WSHSetSocketInformation can provide support for arbitrary options beyond those defined by Windows Sockets. Certain defined options also are passed to the helper DLL because of the different ways in which transport drivers provide support for these options, in particular for the SO_KEEPALIVE and SO_DONTROUTE options.

Any option passed in an application call to setsockopt that the Windows Sockets DLL does not explicitly support is forwarded to WSHSetSocketInformation. The Windows Sockets DLL relies on each helper DLL to fail calls for which the given option is invalid or unsupported by the helper DLL or underlying transport.

See Also

WSHGetSocketInformation


WSHStringToAddress

The WSHStringToAddress function converts a logical string representation of a socket address into a SOCKADDR structure.

INT
  WSHStringToAddress(
    IN LPWSTR  AddressString,
    IN DWORD  AddressFamily,
    IN LPWSAPROTOCOL_INFOW  ProtocolInfo,  OPTIONAL
    OUT LPSOCKADDR  Address,
    IN OUT LPDWORD  AddressStringLength
    );

Parameters

AddressString
Pointer to a buffer containing the logical string representation of a socket address.
AddressFamily
Specifies the address family that AddressString belongs to.
ProtocolInfo
Pointer to a structure that contains protocol information or is NULL.
Address
Pointer to a buffer in which WSHStringToAddress returns the completed SOCKADDR structure that the AddressString represented.
AddressStringLength
On input, points to a variable containing the size of bytes of the buffer provided at Address. WSHStringToAddress resets the value to the number of bytes actually copied into Address.

Return Value

WSHStringToAddress returns zero if the function successfuly translated the given string into a SOCKADDR structure. Otherwise, WSHStringToAddress returns one of the following:

WSAEFAULT
The buffer provided at Address is too small to hold the translated SOCKADDR structure.
WSAEINVAL
The function was given a string it was unable to translate into a SOCKADDR structure.

Headers

Declared in wsahelp.h. Include wsahelp.h.

Comments

WSHStringToAddress should make a best-effort attempt to convert any missing components of the supplied address string. For example, a missing port number could be interpreted as being a zero for certain protocols. If WSHStringToAddress cannot make a reasonable translation of the string, it returns WSAEINVAL.

See Also

WSHAddressToString


Remote NDIS Control Messages

The following Remote NDIS control messages must be supported by an Ethernet 802.3 connectionless device:

REMOTE_NDIS_INITIALIZE_MSG

REMOTE_NDIS_INITIALIZE_CMPLT

REMOTE_NDIS_HALT_MSG

REMOTE_NDIS_QUERY_MSG

REMOTE_NDIS_QUERY_CMPLT

REMOTE_NDIS_SET_MSG

REMOTE_NDIS_SET_CMPLT

REMOTE_NDIS_RESET_MSG

REMOTE_NDIS_RESET_CMPLT

REMOTE_NDIS_INDICATE_STATUS_MSG

REMOTE_NDIS_KEEPALIVE_MSG

REMOTE_NDIS_KEEPALIVE_CMPLT


REMOTE_NDIS_INITIALIZE_MSG

This message is sent by the host to a Remote NDIS device to initialize the network connection. It is sent through the control channel and only when the device is not in the rndis-initialized state.

Offset | Size | Field | Description
0 | 4 | MessageType | Specifies the type of message being sent. Set to 0x00000002.
4 | 4 | MessageLength | Specifies in bytes the total length of this message, from the beginning of the message.
8 | 4 | RequestId | Specifies the Remote NDIS message ID value. This value is used to match messages sent by the host with device responses.
12 | 4 | MajorVersion | Specifies the Remote NDIS protocol version implemented by the host. The current specification uses RNDIS_MAJOR_VERSION = 1.
16 | 4 | MinorVersion | Specifies the Remote NDIS protocol version implemented by the host. The current specification uses RNDIS_MINOR_VERSION = 0.
20 | 4 | MaxTransferSize | Specifies the maximum size, in bytes, of any single bus data transfer that the host expects to receive from the device. Typically, each bus data transfer accommodates a single RNDIS message. However, the device may bundle several RNDIS messages containing data packets into a single transfer (see REMOTE_NDIS_PACKET_MSG).

Headers

Defined in rndis.h. Include rndis.h.


REMOTE_NDIS_INITIALIZE_CMPLT

The REMOTE_NDIS_INITIALIZE_CMPLT message is sent by the Remote NDIS device to the host in response to a REMOTE_NDIS_INITIALIZE_MSG message. In the REMOTE_NDIS_INITIALIZE_CMPLT message, the device reports its medium type, Remote NDIS version numbers, and its type (connectionless or connection-oriented or both).

Offset | Size | Field | Description
0 | 4 | MessageType | Specifies the type of message being sent. Set to 0x80000002.
4 | 4 | MessageLength | Specifies in bytes the total length of this message, from the beginning of the message.
8 | 4 | RequestId | Specifies the Remote NDIS message ID value. This value is used to match messages sent by the host with device responses.
12 | 4 | Status | Specifies RNDIS_STATUS_SUCCESS if the device initialized successfully; otherwise, it specifies an error code indicating the failure.
16 | 4 | MajorVersion | Specifies the highest Remote NDIS major protocol version supported by the device.
20 | 4 | MinorVersion | Specifies the highest Remote NDIS minor protocol version supported by the device.
24 | 4 | DeviceFlags | Specifies the miniport driver type as either connectionless or connection-oriented. This value can be one of the following: RNDIS_DF_CONNECTIONLESS 0x00000001 RNDIS_DF_CONNECTION_ORIENTED 0x00000002
28 | 4 | Medium | Specifies the medium supported by the device. Set to RNDIS_MEDIUM_802_3 (0x00000000)
32 | 4 | MaxPacketsPerMessage | Specifies the maximum number of RNDIS data messages that the device can handle in a single transfer to it. This value should be at least one.
36 | 4 | MaxTransferSize | Specifies the maximum size, in bytes, of any single bus data transfer that the device expects to receive from the host.
40 | 4 | PacketAlignmentFactor | Specifies the byte alignment the device expects for each RNDIS message that is part of a multimessage transfer to it. This value is specified in powers of 2. For example, this value is set to three to indicate 8-byte alignment. This value has a maximum setting of seven which specifies 128-byte alignment.
44 | 4 | AFListOffset | Reserved for connection-oriented devices. Set value to zero.
48 | 4 | AFListSize | Reserved for connection-oriented devices. Set value to zero.

Headers

Defined in rndis.h. Include rndis.h.

Comments

The Status field should be set to RNDIS_STATUS_SUCCESS if the device initialized successfully; otherwise, it is set to an error code indicating the failure. The device should return the highest Remote NDIS protocol version that it can support, in MajorVersion and MinorVersion — the combined version number should be less than or equal to the version number specified by the host in the REMOTE_NDIS_INITIALIZE_MSG message.

The AFListSize and AFListOffset fields are only relevant for connection-oriented devices that include a call manager. Connectionless devices should set these fields to zero.


REMOTE_NDIS_HALT_MSG

This message is sent by the host in order to terminate the network connection. Unlike with the other host-initiated control messages, the device does not respond to REMOTE_NDIS_HALT_MSG.

Offset | Size | Field | Description
0 | 4 | MessageType | Specifies the type of message being sent. Set to 0x00000003.
4 | 4 | MessageLength | Specifies, in bytes, the total length of this message, from the beginning of the message.
8 | 4 | RequestId | Specifies the Remote NDIS message ID value. This value is used to match messages sent by the host with device responses.

Headers

Defined in rndis.h. Include rndis.h.

Comments

It is optional for the device to implement REMOTE_NDIS_HALT_MSG. If implemented, the device sends this message to the host through the control channel only when the device is in the rndis-initialized or rndis-data-initialized state. The device must terminate all communication immediately after sending this message. Sending this message causes the device to enter the rndis-uninitialized state.


REMOTE_NDIS_QUERY_MSG

This message is sent to a Remote NDIS device from a host when it needs to query the device for its characteristics, statistics information, or status. The parameter or statistics counter being queried for is identified by means of an NDIS Object Identifier (OID). The host may send REMOTE_NDIS_QUERY_MSG to the device through the control channel at any time that the device is in either the rndis-initialized or rndis-data-initialized state. The Remote NDIS device will respond to this message by sending a REMOTE_NDIS_QUERY_CMPLT to the host.

Offset | Size | Field | Description
0 | 4 | MessageType | Specifies the type of message being sent. Set to 0x00000004.
4 | 4 | MessageLength | Specifies, in bytes, the total length of this message, from the beginning of the message.
8 | 4 | RequestId | Specifies the Remote NDIS message ID value. This value is used to match messages sent by the host with device responses.
12 | 4 | Oid | Specifies the NDIS OID that identifies the parameter being queried.
16 | 4 | InformationBufferLength | Specifies, in bytes, the length of the input data for the query. Set to zero when there is no OID input buffer.
20 | 4 | InformationBufferOffset | Specifies the byte offset, from the beginning of the RequestId field, at which input data for the query is located. Set to zero if there is no OID input buffer.
24 | 4 | DeviceVcHandle | Reserved for connection-oriented devices. Set to zero.

Headers

Defined in rndis.h. Include rndis.h.


REMOTE_NDIS_QUERY_CMPLT

A Remote NDIS device will respond to a REMOTE_NDIS_QUERY_MSG message with a REMOTE_NDIS_QUERY_CMPLT message. This message is used to relay the result of a query for a device parameter or statistics counter to the host. The Remote NDIS device also returns the requested information to the host in this message.

Offset | Size | Field | Description
0 | 4 | MessageType | Specifies the type of message being sent. Set to 0x80000004.
4 | 4 | MessageLength | Specifies, in bytes, the total length of this message, from the beginning of the message.
8 | 4 | RequestId | Specifies the Remote NDIS message ID value. This value is copied from the REMOTE_NDIS_QUERY_MSG being responded to.
12 | 4 | Status | Specifies the status of processing the OID query request.
16 | 4 | InformationBufferLength | Specifies, in bytes, the length of the response data for the query. Set to zero when there is no OID result buffer.
20 | 4 | InformationBufferOffset | Specifies the byte offset, from the beginning of the RequestId field, at which response data for the query is located. Set to zero if there is no response data.

Headers

Defined in rndis.h. Include rndis.h.


REMOTE_NDIS_SET_MSG

This message is sent to a Remote NDIS device from a host, when it requires to set the value of some operational parameter on the device. The specific parameter being set is identified by means of an Object Identifier (OID), and the value it is to be set to is contained in an information buffer sent along with the message. The host may send REMOTE_NDIS_SET_MSG to the device through the control channel at any time that the device is in either the rndis-initialized or rndis-data-initialized state. The Remote NDIS device will respond to this message by sending a REMOTE_NDIS_SET_CMPLT to the host.

Offset | Size | Field | Description
0 | 4 | MessageType | Specifies the type of message being sent. Set to 0x00000005.
4 | 4 | MessageLength | Specifies, in bytes, the total length of this message, from the beginning of the message.
8 | 4 | RequestId | Specifies the Remote NDIS message ID value. This value is used to match messages sent by the host with device responses.
12 | 4 | Oid | Specifies the NDIS OID that identifies the parameter being set.
16 | 4 | InformationBufferLength | Specifies, in bytes, the length of the input data for the request.
20 | 4 | InformationBufferOffset | Specifies the byte offset, from the beginning of the RequestId field, at which input data for the request is located.
24 | 4 | DeviceVcHandle | Reserved for connection-oriented devices. Set to zero.

Headers

Defined in rndis.h. Include rndis.h.


REMOTE_NDIS_SET_CMPLT

A Remote NDIS device will respond to a REMOTE_NDIS_SET_MSG message with a REMOTE_NDIS_SET_CMPLT message. This message is used to relay the result of setting the value of a device operational parameter to the host.

Offset | Size | Field | Description
0 | 4 | MessageType | Specifies the type of message being sent. Set to 0x80000005.
4 | 4 | MessageLength | Specifies, in bytes, the total length of this message, from the beginning of the message.
8 | 4 | RequestId | Specifies the Remote NDIS message ID value. This value is copied from the REMOTE_NDIS_SET_MSG being responded to.
12 | 4 | Status | Specifies the status of processing the OID Set request.

Headers

Defined in rndis.h. Include rndis.h.


REMOTE_NDIS_RESET_MSG

This message is sent to a Remote NDIS device from a host to reset the device and return status. The host may send REMOTE_NDIS_RESET_MSG to the device through the control channel at any time that the device is in either the rndis-initialized or rndis-data-initialized state. The Remote NDIS device will respond to this message by sending a REMOTE_NDIS_RESET_CMPLT to the host.

Offset | Size | Field | Description
0 | 4 | MessageType | Specifies the type of message being sent. Set to 0x00000006.
4 | 4 | MessageLength | Specifies, in bytes, the total length of this message, from the beginning of the message.
8 | 4 | Reserved | Reserved. Set to zero.

Headers

Defined in rndis.h. Include rndis.h.


REMOTE_NDIS_RESET_CMPLT

A Remote NDIS device will respond to a REMOTE_NDIS_RESET_MSG message from the host by resetting the device and returning the status of the request in the REMOTE_NDIS_RESET_CMPLT message.

Offset | Size | Field | Description
0 | 4 | MessageType | Specifies the type of message being sent. Set to 0x80000006.
4 | 4 | MessageLength | Specifies, in bytes, the total length of this message, from the beginning of the message.
8 | 4 | Status | Specifies the status of processing the Reset request.
12 | 4 | AddressingReset | Indicates if addressing information (multicast address list, packet filter) has been lost during the concluded reset operation. If the device requires the host to resend addressing information, set this field to one; otherwise set it to zero.

Headers

Defined in rndis.h. Include rndis.h.


REMOTE_NDIS_INDICATE_STATUS_MSG

This message is sent from a Remote NDIS device to a host to indicate a change in the status of the device. A REMOTE_NDIS_INDICATE_STATUS_MSG message can also be used to indicate an error event, such as an unrecognized message. The Remote NDIS device may send this message at any time that it is in the rndis-initialized or rndis-data-initialized state. There is no response to this message.

Offset | Size | Field | Description
0 | 4 | MessageType | Specifies the type of message being sent. Set to 0x00000007.
4 | 4 | MessageLength | Specifies, in bytes, the total length of this message, from the beginning of the message.
8 | 4 | Status | Specifies the current status of the host request.
12 | 4 | StatusBufferLength | Specifies the length of the status data, in bytes.
16 | 4 | StatusBufferOffset | Specifies the byte offset, from the beginning of this message, at which Rndis_Diagnostic_Info status data for the device indication is located.

Headers

Defined in rndis.h. Include rndis.h.

Comments

The most common use of REMOTE_NDIS_INDICATE_STATUS_MSG is to indicate the state of the link for an 802.3 device. A status value of RNDIS_STATUS_MEDIA_CONNECT indicates a transition from disconnected (for example no 802.3 link pulse) to connected state (802.3 link pulse detected). A status value of RNDIS_STATUS_MEDIA_DISCONNECT indicates a transition from connected to disconnected state. The device must send REMOTE_NDIS_INDICATE_STATUS_MSG with one of these values every time the 802.3 link state changes. No status buffer is required to return these two common indications.

In the specific case where this message is sent in response to a host message that the device could not handle, the Status field must be set to RNDIS_STATUS_INVALID_DATA, and the Rndis_Diagnostic_Info status buffer is formatted as follows.

Offset | Size | Field | Description
0 | 4 | DiagStatus | Contains status information about the error itself (for example, RNDIS_STATUS_NOT_SUPPORTED)
4 | 4 | ErrorOffset | Specifies the zero-based byte offset in the original message at which the error was detected.

If the error condition was caused by an RNDIS message (for example, the device can't recognize a particular RNDIS message), then the device should append the original message at the end of the status message defined above.

This message is used to report an error condition only in circumstances where the device is not able to generate a response message with appropriate status. Examples of appropriate usage are:

  • On receiving a message with unsupported message type.
  • On receiving a REMOTE_NDIS_PACKET_MSG with unacceptable contents.


REMOTE_NDIS_KEEPALIVE_MSG

The host sends this message periodically when there has been no other control or data traffic from the device to the host for the bus defined KeepAliveTimeoutPeriod. This message is sent by the host at least every RNDIS_KEEPALIVE_TIMEOUT seconds, in the absence of other message traffic, to detect the state of the remote device. The remote device may use the same message in the reverse direction, but it is not required.

Offset | Size | Field | Description
0 | 4 | MessageType | Specifies the type of message being sent. Set to 0x00000008.
4 | 4 | MessageLength | Specifies, in bytes, the total length of this message, from the beginning of the message.
8 | 4 | RequestId | Specifies the Remote NDIS message ID value. This value is used to match messages sent by the host with device responses.

Headers

Defined in rndis.h. Include rndis.h.

Comments

The host will not send a REMOTE_NDIS_KEEPALIVE_MSG message until RNDIS_KEEPALIVE_TIMEOUT seconds have elapsed since the last message received from the remote device. This avoids unnecessary exchange of keep-alive messages when the communication channel is active.

The device can optionally send this message to the host as well. For example, the device may use this message to trigger a response from the host for the purpose of computing round-trip delay time. If implemented, the device must send REMOTE_NDIS_KEEPALIVE_MSG through the control channel and only when the device is in the rndis-initialized or rndis-data-initialized state.


REMOTE_NDIS_KEEPALIVE_CMPLT

A Remote NDIS device will respond to a REMOTE_NDIS_KEEPALIVE_MSG message from the host by sending back a REMOTE_NDIS_KEEPALIVE_CMPLT response message. If the returned Status is not RNDIS_STATUS_SUCCESS, the host will send REMOTE_NDIS_RE/SET_MSG to reset the device.

Offset | Size | Field | Description
0 | 4 | MessageType | Specifies the type of message being sent. Set to 0x80000008.
4 | 4 | MessageLength | Specifies, in bytes, the total length of this message, from the beginning of the message.
8 | 4 | RequestId | Specifies the Remote NDIS message ID value. This value is used to match messages sent by the host with device responses.
12 | 4 | Status | Specifies the current status of the device. If the returned Status is not RNDIS_STATUS_SUCCESS, the host will send an REMOTE_NDIS_RESET_MSG message to reset the device.

Headers

Defined in rndis.h. Include rndis.h.

Comments

If the device implements the option of sending REMOTE_NDIS_KEEPALIVE_MSG, the host will respond with REMOTE_NDIS_KEEPALIVE_CMPLT through the control channel.


Remote NDIS Data Message

A Remote NDIS device encapsulates NDIS packets to transfer them across the data channel. Data messages are used to do this because they can contain out-of-band (OOB) data or per-packet information.

The data message that is used to encapsulate data for transfer across the data channel is described in the following topic:

REMOTE_NDIS_PACKET_MSG


REMOTE_NDIS_PACKET_MSG

REMOTE_NDIS_PACKET_MSG encapsulates NDIS data packets to form a single data message.

Concatenating multiple REMOTE_NDIS_PACKET_MSG elements forms a multi-packet message. Each individual REMOTE_NDIS_PACKET_MSG component is constructed as described below. The difference from the single-packet message is that the MessageLength field in each REMOTE_NDIS_PACKET_MSG header includes some additional padding bytes. These padding bytes are appended to all but the last REMOTE_NDIS_PACKET_MSG such that the succeeding REMOTE_NDIS_PACKET_MSG starts at an appropriate byte boundary. For messages sent from the device to the host, this padding should result in each REMOTE_NDIS_PACKET_MSG starting at a byte offset that is a multiple of 8 bytes starting from the beginning of the multi-packet message. When the host sends a multi-packet message to the device, it will adhere to the PacketAlignmentFactor specified by the device.

The REMOTE_NDIS_PACKET_MSG format is defined in the following table.

Offset | Size | Field | Description
0 | 4 | MessageType | Specifies the type of message being sent. Set to 0x1.
4 | 4 | MessageLength | Message length in bytes, including appended packet data, OOB data, per-packet information data, and both internal and external padding.
8 | 4 | DataOffset | Specifies the offset in bytes from the start of the DataOffset field of this message to the start of the data. This is an integer multiple of 4.
12 | 4 | DataLength | Specifies the number of bytes in the data content of this message.
16 | 4 | OOBDataOffset | Specifies the offset in bytes of the first OOB data record from the start of the DataOffset field of this message. Set to zero if there is no OOB data. Otherwise this is an integer multiple of 4.
20 | 4 | OOBDataLength | Specifies, in bytes, the total length of the OOB data.
24 | 4 | NumOOBDataElements | Specifies the number of OOB records in this message.
28 | 4 | PerPacketInfoOffset | Specifies, in bytes, the offset from the beginning of the DataOffset field in the REMOTE_NDIS_PACKET_MSG data message to the start of the first per-packetinformation data record. Set to zero if there is no per-packet data. Otherwise this is an integer multiple of 4.
32 | 4 | PerPacketInfoLength | Specifies, in bytes, the total length of the per-packet information contained in this message.
36 | 4 | VcHandle | Reserved for connection-oriented devices. Set to zero.
40 | 4 | Reserved | Reserved. Set to zero.

The format of a single OOB data record is indicated in the following table.

Offset | Size | Field | Description
0 | 4 | Size | Length, in bytes, of this OOB header and appended OOB data and padding. This is an integer multiple of 4.
4 | 4 | Type | None defined for 802.3 devices.
8 | 4 | ClassInformationOffset | The byte offset from the beginning of this OOB data record to the beginning of the OOB data.
(N) | ... | OOB Data | OOB Data, consult Windows DDK documentation for more information.

Note (N) is equal to the value of ClassInformationOffset.

The following table defines the format of a per-packet information data record.

Offset | Size | Field | Description
0 | 4 | Size | Length, in bytes, of this per-packet header and appended per-packet data and padding. This value is an integer multiple of 4.
4 | 4 | Type | Set to one of the legal values for NDIS_PER_PACKET_INFO_FROM_PACKET, as described in the Windows 2000 DDK.
8 | 4 | PerPacketInformationOffset | The byte offset from the beginning of this per-packet information data record to the beginning of the per-packet information data.
(N) | ... | Per-Packet Data | Per-Packet Data, consult Windows 2000 DDK documentation for more information.

Note (N) is equal to the value of PerPacketInformationOffset.

Headers

Defined in rndis.h. Include rndis.h.

Comments

Each REMOTE_NDIS_PACKET_MSG may contain one or more OOB data records. NumOOBDataElements indicates the number of OOB data records in this message. The OOB data records must appear in sequence. The OOBDataLength field indicates the length, in bytes, of the entire OOB data block. The OOBDataOffset field indicates the byte offset from the beginning of the DataOffset field to the beginning of the OOB data block. See the NDIS specification in the Windows 2000 DDK for more information about OOB packet data.

If there are multiple OOB data blocks attached to a REMOTE_NDIS_PACKET_MSG message, each subsequent OOB data record must immediately follow the previous OOB record's data.

There is no OOB information currently defined for 802.3 devices.

Each REMOTE_NDIS_PACKET_MSG may contain one or more per-packet-info data records. Per-packet-info is used to convey packet metadata, such as TCP checksum. The PerPacketInfoOffset field indicates the byte offset from the beginning of the DataOffset field to the beginning of the per-packet information data record. The OOBDataLength field indicates the byte length of the per-packet information data record. See the Windows 2000 DDK for more information about per-packet information data. The following table defines the format of a per-packet information data record.

If there are multiple per-packet information data blocks, each subsequent per-packet information data record must immediately follow the previous per-packet information record's data.


Obsolete NdisXxx Functions and Macros

This section lists NdisXxx functions and macros that are obsolete for Windows® XP and later operating systems, for Windows® 2000 and later operating systems, and for Windows® Me and later operating systems.

This section includes the following topics:

Obsolete NDISXxx Functions and Macros for Windows 2000 and Later, and for Windows Me and Later

Obsolete NDISXxx Functions for Windows XP and Later


Obsolete NDISXxx Functions and Macros for Windows 2000 and Later, and for Windows Me and Later

NDIS V4.0 and V5.0 drivers, as well as NDIS V3.0 miniport drivers, should never call any of the following functions and macros.. NDIS Library Functions contains For descriptions of Ndis Xxx and filter-specific functions and macros useful to NDIS miniport, intermediate, and protocol drivers written or revised to run on the current operating system, see NDIS Library Functions.

The following Ndis Xxx and filter-package functions and macros exist only to support legacy NDIS V3.0 drivers, and are, therefore, obsolete:

EthChangeFilterAddresses

EthCreateFilter

EthDeleteFilter

EthDeleteFilterOpenAdapter

EthFilterAdjust

EthFilterIndicateReceive

EthFilterIndicateReceiveComplete

EthNoteFilterOpenAdapter

ETH_NUMBER_OF_GLOBAL_FILTER_ADDRESSES

EthNumberOfOpenFilterAddresses

EthQueryGlobalFilterAddresses

ETH_QUERY_FILTER_CLASSES

EthQueryOpenFilterAddresses

ETH_QUERY_PACKET_FILTER

EthShouldAddressLoopBack

FDDI_COMPARE_NETWORK_ADDRESSES

FddiChangeFilterLongAddresses

FddiChangeFilterShortAddresses

FddiCreateFilter

FddiDeleteFilter

FddiDeleteFilterOpenAdapter

FddiFilterAdjust

FddiFilterIndicateReceive

FddiFilterIndicateReceiveComplete

FddiNoteFilterOpenAdapter

FDDI_NUMBER_OF_GLOBAL_FILTER_LONG_ADDRESSES

FDDI_NUMBER_OF_GLOBAL_FILTER_SHORT_ADDRESSES

FddiNumberOfOpenFilterLongAddresses

FddiNumberOfOpenFilterShortAddresses

FDDI_QUERY_FILTER_CLASSES

FddiQueryGlobalFilterLongAddresses

FddiQueryGlobalFilterShortAddresses

FddiQueryOpenFilterLongAddresses

FddiQueryOpenFilterShortAddresses

FDDI_QUERY_PACKET_FILTER

FddiShouldAddressLoopBack

NdisAllocateDmaChannel

NdisAllocateSharedMemory

NdisCompleteBufferPhysicalMapping

NdisCompleteCloseAdapter

NdisCompleteDmaTransfer

NdisCompleteOpenAdapter

NdisCompleteQueryStatistics

NdisCompleteRequest

NdisCompleteReset

NdisCompleteSend

NdisCompleteTransferData

NdisDeregisterAdapter

NdisDeregisterAdapterShutdownHandler

NdisDeregisterMac

NdisFreeDmaChannel

NdisFreeSharedMemory

NdisIMQueueMiniportCallback

NdisIMRevertBack

NdisIMSwitchToMiniport

NdisIndicateReceive

NdisIndicateReceiveComplete

NdisIndicateStatus

NdisIndicateStatusComplete

NdisInitializeInterrupt

NdisInitializeWrapper

NdisMapIoSpace

NdisOverrideBusNumber

NdisPciAssignResources

NdisQueryMapRegisterCount

NdisQueryReceiveInformation

NdisReadBindingInformation

NdisReadDmaCounter

NdisRegisterAdapter

NdisRegisterAdapterShutdownHandler

NdisRegisterMac

NdisReleaseAdapterResources

NdisRemoveInterrupt

NdisReadMcaPosInformation

NdisSetupDmaTransfer

NdisStartBufferPhysicalMapping

NdisSynchronizeWithInterrupt

NdisUnmapIoSpace

NdisUpdateSharedMemory

TrChangeFunctionalAddress

TrChangeGroupAddress

TrCreateFilter

TrDeleteFilter

TrDeleteFilterOpenAdapter

TrFilterAdjust

TrFilterIndicateReceive

TrFilterIndicateReceiveComplete

TrNoteFilterOpenAdapter

TR_QUERY_FILTER_ADDRESSES

TR_QUERY_FILTER_BINDING_ADDRESS

TR_QUERY_FILTER_BINDING_GROUP

TR_QUERY_FILTER_CLASSES

TR_QUERY_FILTER_GROUP

TR_QUERY_PACKET_FILTER

TrShouldAddressLoopBack


Obsolete NDISXxx Functions for Windows XP and Later

NDIS V5.1 drivers should never call any of the following functions. These functions exist only to support legacy NDIS V5.0 and V 4.0 drivers and are, therefore, obsolete:

NdisGetCacheFillSize

NdisImmediateReadPciSlotInformation

NdisImmediateReadPortUchar

NdisImmediateReadPortUlong

NdisImmediateReadPortUshort

NdisImmediateReadSharedMemory

NdisImmediateWritePciSlotInformation

NdisImmediateWritePortUchar

NdisImmediateWritePortUlong

NdisImmediateWritePortUshort

NdisImmediateWriteSharedMemory

NdisMPciAssignResources

NdisReadEisaSlotInformation

NdisReadEisaSlotInformation(Ex)

NDIS drivers should not call the following function. This function is not supported in Windows XP and later operating systems:

NdisQueryMapRegisterCount


Introduction to Parallel Ports and Devices

This section describes the following topics about the support that Microsoft® Windows® provides for parallel ports and devices:

Physical Configuration of Parallel Ports

Physical Configuration of Devices Attached to a Parallel Port

A parallel port is typically a multimode communication port that supports the following:

  • Byte and nibble (read) modes
  • IEEE 1284-compatibility mode
  • Extended Capabilities Port mode
  • Enhanced Parallel Port mode

For information about parallel port and device standards, see the following specifications:

  • IEEE Std 1284-1994, IEEE Standard Signaling Method for a Bidirectional Parallel Peripheral Interface for Personal Computers
  • IEEE P1284.3, Standard for Interface and Protocol Extensions to IEEE 1284-1994 Compliant Peripherals and Host Adapters, Draft D6.00, December 3, 1998

For more information about Windows support for parallel ports and devices, see:

System-Supplied Parallel Drivers

Vendor-Supplied Parallel Drivers

Client Interfaces to System-Supplied Parallel Drivers

Note Windows Me uses the Windows 95 Virtual Communication Driver model to support parallel ports. For more information about Windows Me support for parallel ports, see the information about virtual communications drivers in the Windows 95 Documentation section of the Windows DDK.


Physical Configuration of Parallel Ports

This section describes typical physical configurations of parallel ports.

The following figure shows two typical parallel port configurations.

Left Figure: Parallel Port on a Multifunction Peripheral Bus Card

Right Figure: Parallel Port Integrated into a PCI/ISA Bridge

A parallel port can be one device on a multifunction peripheral bus card or a device attached to a system bus.


Physical Configuration of Devices Attached to a Parallel Port

This section describes typical physical configurations of devices attached to a parallel port.

The following figure shows a parallel device attached a parallel port.

Parallel Device Connected to a Parallel Port

Microsoft® Windows® supports one parallel device attached to a parallel port, which can be a legacy device or a Plug and Play device that complies with the IEEE 1284 standard.

The following figure shows IEEE 1284.3 devices and an end-of-chain IEEE 1284 device simultaneously attached to a parallel port.

IEEE 1284.3 Daisy-chain Devices Connected to a Parallel Port

The IEEE 1284.3 standard specifies that up to four daisy-chain devices and an end-of-chain device can be simultaneously attached to a parallel port.

The following table specifies the number of IEEE 1284.3 devices supported by each version of Windows.

Windows version | Maximum number of daisy-chain devices | IEEE 1284.3 Device IDs | Comments
Windows Me | zero | N/A | Not supported by system-supplied drivers.
Windows 2000 | four | from 0 through 3 | To insure reliable operation, Microsoft recommends at most two devices.
Windows XP and later | two | 0 or 1 |

For more information about supporting IEEE 1284.3 devices, see:

Parallel Device Interfaces, Internal Names, and Symbolic Links

Selecting and Deselecting an IEEE 1284 Device Attached to a Parallel Port


System-Supplied Parallel Drivers

This section describes the following about the system-supplied parallel drivers for parallel ports and devices attached to parallel ports.

Features of System-Supplied Parallel Drivers

Device Stacks for Parallel Ports and Devices

Parallel Device Interfaces, Internal Names, and Symbolic Links

IOCTL and Callback Support for Parallel Ports and Devices

For more information about support for parallel ports and devices, see:

Introduction to Parallel Ports and Devices

Vendor-Supplied Parallel Drivers

Client Interfaces to System-Supplied Parallel Drivers

Note Microsoft® Windows® Me uses the Windows 95 Virtual Communication Driver model to support parallel ports. For more information about Windows Me support for parallel ports, see the information about virtual communications drivers in the Windows 95 Documentation section of the Windows DDK.


Features of System-Supplied Parallel Drivers

This section describes the features of the system-supplied parallel drivers for parallel ports and devices attached to parallel ports.

Except for 64-bit versions of Microsoft® Windows®, Windows 2000 and later provides a parallel port function driver and a parallel port bus driver for Plug and Play devices attached to a parallel port. Microsoft does not provide parallel drivers for 64-bit versions of Windows.

Windows 2000 includes the following drivers:

  • Parclass is the parallel port bus driver for devices attached to parallel ports. The executable image of Parclass is parallel.sys.
  • Parport is the parallel port function driver. The executable image of Parport is parport.sys.

The operation of Parclass and Parport is closely connected through internal device control requests for parallel ports and parallel port callback routines.

In Windows XP and later, Parclass is removed, and Parport provides the function of both the parallel port function driver and the parallel port bus driver. The executable image of Parport in Windows XP is parport.sys.

The system-supplied function driver for parallel ports creates a functional device object (FDO) that represents each parallel port enumerated in the system. The system-supplied bus driver for parallel ports creates a physical device object (PDO) that represents each parallel device that the bus driver enumerates on a port. Clients, for example vendor-supplied parallel drivers, operate a parallel device through the interfaces provided by a parallel device's PDO and the FDO of the device's parent port.

Except for minor operational differences described throughout the parallel documentation, the client interfaces to system-supplied parallel drivers is the same in Windows 2000 as in Windows XP and later.

The system-supplied parallel drivers support:

  • Legacy parallel ports, standard parallel port devices, IEEE 1284-compatible devices, IEEE 1284-compliant devices, and IEEE 1284.3 daisy-chain devices
  • Most communication modes, including Centronics mode, IEEE 1284 modes, extended capabilities port (ECP) mode, and enhanced parallel port (EPP) mode
  • Plug and Play, power management, and Windows Management Instrumentation (WMI)
  • Shared access to all the parallel ports installed on the system
  • Raw access to all parallel devices
  • IOCTLs and callbacks to operate parallel ports and devices — see IOCTL and Callback Support for Parallel Ports and Devices

The system-supplied parallel drivers provide the following partial support for IEEE 1284.3 devices:

  • A combination of device control requests and callback routines that is functionally equivalent to the Service Provider Interface. See Service Provider Interface (SPI) in the IEEE P1284.3 specification.
  • The selection and operation of more than one IEEE 1284.3 daisy-chain device and an end-of-chain device, as defined in the Daisy Chaining clause of the IEEE P1284.3 specification.
  • Basic services to support the data link layer, as specified in the Data link layer clause of the IEEE P1284.3 specification — see Connecting to an IEEE 1284.3 Data Link Device.

The system-supplied parallel drivers do not support the following IEEE 1284.3 specifications:

  • Multiplexors, as specified in the Multiplexor clause of the IEEE P1284.3 specification.

    There are no plans to support this feature in future releases of Windows.

  • Interrupts for IEEE 1284.3 daisy-chain devices.

The system-supplied parallel drivers create:

  • Device objects, interfaces, and unprotected symbolic links, as described in Device Stacks for Parallel Ports and Devices.
  • A work queue for each parallel port.

    The system-supplied function driver for parallel ports queues I/O requests to allocate a parallel port and to select an IEEE 1284.3 device attached to a parallel port.

  • A worker thread and work queue for each parallel device.

    The system-supplied bus driver for parallel ports queues the following I/O requests if it can not immediately complete them: read, write, device control, and internal device control.

For more information about how to operate parallel ports and devices attached to parallel ports, see:

Introduction to Parallel Ports and Devices

Vendor-Supplied Parallel Drivers

Client Interfaces to System-Supplied Parallel Drivers

Sample Parallel Drivers

For information about parallel port and device standards, see the following specifications:

  • IEEE Std 1284-1994, IEEE Standard Signaling Method for a Bidirectional Parallel Peripheral Interface for Personal Computers
  • IEEE P1284.3, Standard for Interface and Protocol Extensions to IEEE 1284-1994 Compliant Peripherals and Host Adapters, Draft D6.00, December 3, 1998


Device Stacks for Parallel Ports and Devices

This section describes the device stacks created by the system-supplied parallel drivers for parallel ports and devices attached to parallel ports.

The following figure shows the type of device stacks that the system-supplied parallel drivers create for parallel ports and devices attached to parallel ports.

Windows Device and Driver Stacks for Parallel Ports and Devices

Vendor-supplied function drivers for parallel devices attached to parallel ports are optional. The system-supplied parallel drivers provide extensive support for directly controlling a parallel device as a raw device, and for controlling a device's parent parallel port.

For more information about how to operate parallel ports and devices attached to parallel ports, see:

Parallel Device Interfaces, Internal Names, and Symbolic Links

IOCTL and Callback Support for Parallel Ports and Devices

Operating a Parallel Port

Operating a Parallel Device Attached to a Parallel Port

Client Interfaces to System-Supplied Parallel Drivers


Parallel Device Interfaces, Internal Names, and Symbolic Links

This section describes the device interfaces, internal names, and symbolic links created by the system-supplied parallel drivers for parallel ports and devices attached to parallel ports.

For each parallel port enumerated in the system and for each parallel device enumerated on a parallel port, the parallel drivers create device objects, interfaces, internal names, and unprotected symbolic links as follows.

Device type | Device object | Device interface | Internal name | Symbolic link
Parallel Port | FDO | GUID_PARALLEL_DEVICE | "\Device\ParallelPortm", m >= 0 | None
Raw parallel device | PDO | GUID_PARCLASS_DEVICE | "\Device\Parallelm", m >= 0 | "LPTn", n = m + 1
IEEE 1284.3 device | PDO |  | "\Device\Parallelm.x", m >= 0, Windows 2000: x = 0 to 3 Windows XP and later: x = 0 or 1 | "LPTn.x", n = m +1
IEEE 1284 end-of-chain device | PDO |  | "\Device\Parallelm.4" m >= 0 | "LPTn.4" n = m +1

For example, the following device names and symbolic links are assigned to "\Device\ParallelPort0", which has two IEEE 1284.3 daisy-chain devices and an IEEE 1284 end-of-chain device attached to it.

Device type | Device object | Internal name | Symbolic link
Parallel Port | FDO | "\Device\ParallelPort0" | None
IEEE 1284.3 device | PDO | "\Device\Parallel0.0" | "LPT1.0"
IEEE 1284.3 device | PDO | "\Device\Parallel0.1" | "LPT1.1"
IEEE 1284 end-of-chain device | PDO | "\Device\Parallel0.4" | "LPT1.4"


IOCTL and Callback Support for Parallel Ports and Devices

This section describes the types of IOCTLs and callbacks that the system-supplied parallel drivers support to operate parallel ports and devices attached to parallel ports.

Vendor function drivers for parallel devices attached to parallel ports are optional. The system-supplied parallel drivers provide extensive support for directly controlling a parallel device as a raw device, and for operating a device's parent parallel port.

The system-supplied function driver supports the following types of IOCTLs and callbacks that clients use to operate a parallel port:

Obtaining Information about a Parallel Port

Synchronizing the Use of a Parallel Port

Selecting and Deselecting an IEEE 1284 Device Attached to a Parallel Port

Setting and Clearing the Communication Mode on a Parallel Port

Connecting to an IEEE 1284.3 Data Link Device

The system-supplied bus driver supports the following types of IOCTLs and callbacks that clients use to operate a parallel device attached to a parallel port:

Opening and Using a Parallel Device

Connecting to a Parallel Device

Obtaining Information about a Parallel Device

Locking and Unlocking a Parallel Port for Use by a Parallel Device

Setting and Clearing a Communication Mode for a Parallel Device

Setting Attributes on a Parallel Device

Reading and Writing a Parallel Device

For more information about how to operate parallel ports and devices attached to parallel ports, see:

Operating a Parallel Port

Operating a Parallel Device Attached to a Parallel Port

Client Interfaces To System-Supplied Parallel Drivers


Vendor-Supplied Parallel Drivers

This section describes the following topics about how to operate and install parallel ports and devices in Microsoft® Windows®:

Requirements for Vendor-Supplied Parallel Drivers

Operating a Parallel Port

Operating a Parallel Device Attached to a Parallel Port

Installing Parallel Ports and Devices

For more information about Windows support for parallel ports and devices, see:

Introduction to Parallel Ports and Devices

System-Supplied Parallel Drivers

Client Interfaces to System-Supplied Parallel Drivers

Sample Parallel Drivers

Note Windows Me uses the Windows 95 Virtual Communication Driver model to support parallel ports. For more information about Windows Me support for parallel ports, see the information about virtual communications drivers in the Windows 95 Documentation section of the Windows DDK.


Requirements for Vendor-Supplied Parallel Drivers

This section describes Microsoft® Windows® requirements for vendor-supplied drivers for parallel ports and devices attached to parallel ports.

Vendor-supplied function drivers and bus drivers for parallel ports are not required because the system-supplied parallel drivers provide these functions. The system-supplied parallel drivers provide extensive support for operating parallel ports and devices attached to parallel ports.

Vendor-supplied function drivers for parallel devices attached to parallel ports are optional. The system-supplied parallel drivers provide extensive support for directly controlling a parallel device as a raw device, and for operating a device's parent parallel port.

If a vendor provides a function driver for a parallel device, the driver must support Plug and Play and power management. Microsoft recommends that the driver be a WDM driver.

The following topics describe how a vendor-supplied function driver for a parallel device operates a device and the device's parent parallel port:

Operating a Parallel Port

Operating a Parallel Device Attached to a Parallel Port


Operating a Parallel Port

This section describes how a client, in particular, a vendor-supplied function driver for a parallel device, operates a parallel port.

The system-supplied function driver for parallel ports creates a functional device object (FDO) for each parallel port enumerated in the system. The following topics describe how a client operates a parallel port by using the interface provided by the port's FDO:

Creating and Starting a Parallel Port

Opening and Closing a Parallel Port

Obtaining Information about a Parallel Port

Synchronizing the Use of a Parallel Port

Selecting and Deselecting an IEEE 1284 Device Attached to a Parallel Port

Setting and Clearing the Communication Mode on a Parallel Port

Connecting to an IEEE 1284.3 Data Link Device

Connecting an Interrupt Service Routine to a Parallel Port

For more information about system support for parallel ports, see:

Introduction to Parallel Ports and Devices

System-Supplied Parallel Drivers

Client Interfaces to System-Supplied Parallel Drivers

Sample Parallel Drivers


Creating and Starting a Parallel Port

The Plug and Play manager uses the Plug and Play support of the system-supplied function driver for parallel ports to create and start a function device object (FDO) that represents a parallel port.

The parallel port function driver does the following:

• Creates a named FDO

The format of the device name for the parallel port is "\Device\ParallelPortx", where x is an integer value for the port number. The parallel port function driver uses the PortName entry value (REG_SZ) under the Plug and Play registry key for the parallel port to determine the port number. Note that if PortName has the format "LPTn", where n is the number of the port, then x in "ParallePortx" is set to the value of (n -1). For example, "ParallelPort0" is associated with "LPT1". If PortName does not have the correct format, a device object is not created.

Note that a "ParallelPortx" device name is not guaranteed. Microsoft recommends using IoRegisterPlugPlayNotification to be notified of the arrival of a GUID_PARALLEL_DEVICE device interface.

  • Registers and enables a GUID_PARALLEL_DEVICE interface for the parallel port
  • Validates the resources sent by the Plug and Play Manager
  • Initializes 1284.3 devices attached to the parallel port

    The parallel port function driver counts the number of daisy-chain devices, and assigns a daisy chain ID to each device. In Microsoft® Windows® 2000, the driver assigns IDs from 0 to 3. In Windows XP, the driver assigns an ID of 0 or 1. The device IDs are assigned to the devices in ascending order, beginning with the device physically closest to the parallel port.

  • Registers the FDO and the associated WMI data blocks and callbacks with the WDM provider

    The parallel port function driver logs the number of times a parallel port is allocated and freed.

  • Determines the communication modes supported by the parallel port hardware

    The hardware must be at least IEEE 1284-compatible. The parallel port function driver checks to see if the hardware supports BYTE, EPP, and ECP modes. Note that EPP is only supported on a small subset of machines.

  • Creates a work queue (FIFO) for the parallel port

    Each parallel port has its own work queue. The parallel port function driver queues only allocate and select device requests. If the port is already allocated when the parallel port function driver receives a new allocate request or select request, it queues the request.


Opening and Closing a Parallel Port

Clients can share a parallel port. A client must open a file on a parallel port before the client can use other I/O requests or use the parallel port callback routines. A client must not attempt to communicate with a parallel port after the client has closed its file on the port.

Note that in a Plug and Play environment, a device can be removed or added whenever there are no open files on it. In general, every time a parallel port is added, Plug and Play assigns a different location and resources.


Obtaining Information About a Parallel Port

Before a client uses a parallel port, it can obtain information about the following:

  • Resources used by the parallel port
  • Hardware capabilities of the parallel port
  • Parallel port callback routines that a kernel-mode driver can use

A client uses the following internal device control requests to obtain the above information:

IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO

IOCTL_INTERNAL_GET_MORE_PARALLEL_PORT_INFO

IOCTL_INTERNAL_GET_PARALLEL_PNP_INFO

A client releases parallel port information by using an IOCTL_INTERNAL_RELEASE_PARALLEL_PORT_INFO request.


Synchronizing the Use of a Parallel Port

Clients must synchronize their use of a parallel port by allocating a parallel port before using it and freeing the port after they are done using it.

Alternatively, a client can select and deselect an IEEE 1284.3 device (which automatically allocates and frees a parallel port) – see Selecting and Deselecting an IEEE 1284 Device Attached to a Parallel Port.

A client uses the following device control requests to allocate and free a parallel port:

IOCTL_INTERNAL_PARALLEL_PORT_ALLOCATE

IOCTL_INTERNAL_PARALLEL_PORT_FREE

A kernel-mode client can also use the following parallel port callback routines:

TryAllocatePort

QueryNumWaiters

FreePort

The IOCTL_INTERNAL_PARALLEL_PORT_ALLOCATE request requires the least handling by a client because the system-supplied function driver for parallel ports queues the request for the client if the parallel port is already allocated. The function driver completes an allocate request with a status of STATUS_SUCCESS after it allocates the port to a client. A client can cancel a pending allocate request at any time because of an unacceptable timeout delay or some other device-specific condition.

The TryAllocatePort routine returns immediately (is non-blocking). If a client uses only TryAllocatePort to attempt to allocate a parallel port for which other clients are contending, the parallel port function driver might never allocate the port to the client. To ensure success, a client must use an IOCTL_INTERNAL_PARALLEL_PORT_ALLOCATE request.

The parallel port function driver queues, and subsequently processes, IOCTL_INTERNAL_ALLOCATE_PORT and IOCTL_INTERNAL_SELECT_DEVICE requests in the order in which the requests are received.

After the parallel port function driver allocates a parallel port to a client, the client has exclusive access to the port. The client must call FreePort to free the port. After the client frees the port, the parallel port function driver removes the next request (an IOCTL_INTERNAL_ALLOCATE_PORT or IOCTL_INTERNAL_SELECT_DEVICE request), if any, from the port's work queue and completes the request.

A client should use QueryNumWaiters to determine if there are other clients waiting for a parallel port. A client that needs to allocate a port for an extended period of time should periodically call QueryNumWaiters to determine if other clients are waiting to acquire the port, and, if clients are waiting, free the port as soon as possible.


Selecting and Deselecting an IEEE 1284 Device Attached to a Parallel Port

A client can select and deselect an IEEE 1284.3 device attached to a parallel port by using the following internal device control requests:

IOCTL_INTERNAL_SELECT_DEVICE

IOCTL_INTERNAL_DESELECT_DEVICE

A kernel-mode driver can also use the following parallel port callback routines:

TrySelectDevice

DeselectDevice

The select requests require the least handling by the client because the system-supplied function driver for parallel ports queues the select request for the client if the parallel port is allocated by another client. After the parallel port function driver dequeues the select request, it attempts to allocate the port and to select the IEEE 1284.3 device. The client can cancel a select request at any time because of an acceptable timeout delay or some other device-specific condition.

The TrySelectDevice routine returns immediately (is non-blocking). If a client uses only TrySelectDevice to attempt to allocate a parallel port for which other clients are contending, the parallel port function driver might never allocate the port to the client. To ensure success, a client must use a select device request.

The parallel port function driver queues, and subsequently processes, port allocate requests and device select requests in the order in which the requests are received.

After the parallel port function driver selects an IEEE 1284.3 device for a client, the client has exclusive access to the port and the selected IEEE 1284.3 device. The client must call DeselectDevice to free the port and deselect the IEEE 1284.3 device. After a client frees the port, the parallel port function driver dequeues a pending request, if any, and processes the request.

Microsoft® Windows® 2000 supports four daisy-chain devices per port; however, Microsoft recommends using at most two daisy-chain devices per port. Windows XP supports at most two daisy-chain devices per port.


Connecting to an IEEE 1284.3 Data Link Device

The system-supplied function driver for parallel ports does not provide full support for the IEEE 1284.3 data link layer services; however, it does provide internal device control requests that an upper-level driver can use to connect, disconnect, reset, and signal an IEEE 1284.3 data link device. These services are under development and are intended to support new devices that are not generally available. See the sample code \src\kernel\parport in the Windows DDK for more information about support for IEEE 1284.3 data link services.


Connecting an Interrupt Service Routine to a Parallel Port

A kernel-mode client can use a IOCTL_INTERNAL_PARALLEL_CONNECT_INTERRUPT request to connect an interrupt service routine and a deferred port check routine to the operation of the parallel port function driver.

Note Microsoft does not recommend using a client-supplied interrupt routine. The use of interrupts might cause system instability. By default, the IOCTL_INTERNAL_PARALLEL_CONNECT_INTERRUPT request is disabled.

To facilitate the porting and development of drivers for parallel devices, the system-supplied function driver for parallel ports supports a registry flag that kernel-mode clients can use to enable and disable connect interrupt request. The connect interrupt request is enabled by the registry entry value EnableConnectInterruptIoctl under the Plug and Play registry key for the parallel port. The entry value has type REG_DWORD and the default value is 0x0 (disabled). A value not equal to 0x0 enables the connect interrupt request.

The connect interrupt request returns a pointer to the parallel port's interrupt object and pointers to the following callback routines:

TryAllocatePortAtInterruptLevel is a non-blocking callback routine that a kernel-mode driver can use in an ISR to allocate a parallel port.

FreePortFromInterruptLevel is a non-blocking callback routine that a kernel-mode driver can use in an ISR to free a parallel port.

The interrupt service routine is called at IRQL DIRQL after a hardware interrupt on the parallel port. If a driver connects an interrupt service routine and has an Unload routine, the driver must send an IOCTL_INTERNAL_PARALLEL_DISCONNECT_INTERRUPT request in its Unload routine.

The deferred port check routine is called after the parallel port is freed, and there are no pending requests to allocate the port or select an IEEE 1284.3 device. A driver can use the deferred port check routine to enable interrupts.

If a client's interrupt service routine is called when the client does not have port allocated, the client can attempt to quickly allocate the port by calling the TryAllocatePortAtInterruptLevel routine. The client can also use the FreePortFromInterruptLevel routine to free the port.

Because a parallel port is shared by drivers, the parallel port function driver maintains a list of interrupt service routines and deferred port check routines connected to a parallel port. The parallel port function driver calls all connected interrupt routines and deferred port check routines in the order they were connected.


Operating a Parallel Device Attached to a Parallel Port

This section describes how a client, in particular, a vendor-supplied function driver for a parallel device, operates a parallel device attached to a parallel port.

The system-supplied bus driver for parallel ports creates a physical device object (PDO) for each parallel device enumerated on a parallel port. The following topics describe how a client operates a parallel device by using the interface provided by the device's PDO:

Opening and Using a Parallel Device

Connecting to a Parallel Device

Obtaining Information about a Parallel Device

Locking and Unlocking a Parallel Port for Use by a Parallel Device

Setting and Clearing a Communication Mode for a Parallel Device

Setting Attributes on a Parallel Device

Reading and Writing a Parallel Device

For more information about support for parallel devices attached to a parallel port, see:

Introduction to Parallel Ports and Devices

System-Supplied Parallel Drivers

Client Interfaces to System-Supplied Parallel Drivers

Sample Parallel Drivers


Opening and Using a Parallel Device

The system-supplied bus driver for parallel ports enforces exclusive access to a parallel device attached to a parallel port. If a parallel device is open, the parallel port bus driver fails any subsequent IRP_MJ_CREATE requests for the device until the device has been closed. A client must open a parallel device before it sends other I/O requests to the device or calls the parallel device callback routines. A client must not attempt to communicate with a parallel device after the client has closed its file on a device. A client must close a device to allow other clients to access the device.

A client usually does the following:

  • Opens a parallel device
  • Connects to a parallel device – see Connecting to a Parallel Device
  • Obtains information about the parallel device – see Obtaining Information about a Parallel Device
  • Locks the device – see Locking and Unlocking a Parallel Port for Use by a Parallel Device
  • Does a sequence of operations on the device
  • Disconnects from a parallel device – see Connecting to a Parallel Device
  • Unlocks the device – see Locking and Unlocking a Parallel Port for Use by a Parallel Device
  • Closes the device

Note that in a Plug and Play environment, a device can be removed or added whenever there are no open files on it. In general, every time a parallel device is added, Plug and Play assigns a different location and resources.


Connecting to a Parallel Device

A client uses the IOCTL_INTERNAL_PARCLASS_CONNECT request to obtain a PARCLASS_INFORMATION structure that contains:

  • I/O resources allocated to the parallel port
  • Hardware capabilities of the parallel port
  • Pointers to callback routines that a kernel-mode driver can use to set the IEEE 1284 operating modes for a parallel device – see Setting and Clearing a Communication Mode for a Parallel Device
  • Pointers to callback routines that a kernel-mode driver can use to read and write a parallel device – see Reading and Writing a Parallel Device.

The callback routines provide functionality that a typical function driver needs. Using the callback routines is more efficient than using equivalent device control requests.

A client disconnects from a device by using a IOCTL_INTERNAL_PARCLASS_DISCONNECT request.


Obtaining Information about a Parallel Device

In addition to connecting to a parallel device, a client can use the following device control requests to obtain additional information about a parallel device:

IOCTL_IEEE1284_GET_MODE

IOCTL_PAR_GET_DEFAULT_MODES

IOCTL_PAR_GET_DEVICE_CAPS

IOCTL_PAR_IS_PORT_FREE

IOCTL_PAR_QUERY_DEVICE_ID_SIZE

IOCTL_PAR_QUERY_DEVICE_ID

IOCTL_PAR_QUERY_INFORMATION

IOCTL_PAR_QUERY_LOCATION

IOCTL_PAR_QUERY_RAW_DEVICE_ID

IOCTL_SERIAL_GET_TIMEOUTS


Locking and Unlocking a Parallel Port for Use by a Parallel Device

To execute an uninterrupted sequence of operations on a parallel device, a client must allocate the parallel port and select the IEEE 1284.3 device on the port. A sequence of operations can include completing I/O requests and executing the callback routines provided by the parallel port bus driver. After completing a sequence of operations, a client must deselect the IEEE 1284.3 device and then free the parent parallel port.

The system-supplied bus driver for parallel ports supports the following internal device control requests to lock and unlock a parallel port:

IOCTL_INTERNAL_LOCK_PORT

IOCTL_INTERNAL_LOCK_PORT_NO_SELECT

IOCTL_INTERNAL_UNLOCK_PORT

IOCTL_INTERNAL_UNLOCK_PORT_NO_DESELECT

Microsoft recommends that clients use the lock port and unlock port requests if the devices can be operated by only using the functionality that these requests provide. Otherwise, clients can use the lock port no select and lock port no deselect requests. This provides a client additional flexibility to operate a device that uses a selection and deselection mechanism that does not conform to the IEEE 1284.3 daisy-chain specifications. A client can use the lock port no select request to allocate the port, and then operate the device by using device control requests for parallel devices and parallel device callback routines.

Clients can send individual I/O requests to parallel devices without the need to lock and unlock a parallel port because the parallel port bus driver administers port sharing among clients. The parallel port bus driver automatically allocates the parallel port immediately before it processes an I/O request and, if there are clients waiting for the port, frees the port immediately after completing the I/O request.

If the parallel port bus driver can allocate the port to the parallel device within a set timeout period, the device's worker thread completes the request. Otherwise, the parallel port bus driver completes the pending request with a status of STATUS_DEVICE_BUSY.


Setting Attributes on a Parallel Device

A client uses following device control requests to set the indicated operations of a parallel device:

  • IOCTL_PAR_SET_INFORMATION initializes a parallel device.
  • IOCTL_SERIAL_SET_TIMEOUTS sets timeouts for a parallel device.
  • IOCTL_PAR_SET_READ_ADDRESS sets an ECP or EPP read address (channel) for a parallel device.
  • IOCTL_PAR_SET_WRITE_ADDRESS sets an ECP or EPP write address (channel) for a parallel device.


Reading and Writing a Parallel Device

A client reads and writes a parallel device by using IRP_MJ_READ and IRP_MJ_WRITE requests. A kernel-mode driver can also use the parallel device callback routines ParallelRead and ParallelWrite.

If a client uses read and write I/O requests, the parallel port bus driver queues the requests on the work queue of the parallel device. A client of a parallel device does not have to lock a parallel port before reading and writing a device because the system-supplied bus driver for parallel ports automatically locks and unlocks the port for the client.


Installing Parallel Ports and Devices

This section describes device-specific information about installing parallel ports and devices in Microsoft® Windows®.

There are no special requirements associated with installing parallel ports and devices.

For more information about device installation, see:

Requirements for Vendor-Supplied Parallel Drivers

Device Installation Overview

For more information about system support for parallel ports and devices attached to parallel ports, see:

Introduction to Parallel Ports and Devices

System-Supplied Parallel Drivers

Client Interfaces to System-Supplied Parallel Drivers

Sample Parallel Drivers


Sample Parallel Drivers

This section identifies the sample parallel drivers included with the Microsoft® Windows® DDK.

The Windows DDK includes the source code for the Parport system driver supplied by Windows XP and later. Parport is the parallel port function driver and the parallel port bus driver. See the sample code in the \src\kernel\parport directory of the Windows DDK.

For more information about Windows support for parallel ports and Parport operation, see:

Introduction to Parallel Ports and Devices

System-Supplied Parallel Drivers

Client Interfaces to System-Supplied Parallel Drivers


Client Interfaces to System-Supplied Parallel Drivers

This section describes the client interface that the system-supplied parallel drivers provide for operating parallel ports and devices attached to parallel ports. In particular, vendor-supplied parallel drivers use this interface to operate parallel devices attached to parallel ports.

The system-supplied function driver for parallel ports supports an interface consisting of the following components:

I/O Requests for Parallel Ports

Internal Device Control Requests for Parallel Ports

Parallel Port Callback Routines

Parallel Port Data Types

The system-supplied bus driver for parallel ports supports an interface consisting of the following components:

I/O Requests for Parallel Devices

Device Control Requests for Parallel Devices

Internal Device Control Requests for Parallel Devices

Parallel Device Callback Routines

Parallel Device Data Types

For more information about Windows support for parallel ports and devices attached to parallel ports, see:

Introduction to Parallel Ports and Devices

System-Supplied Parallel Drivers

Vendor-Supplied Parallel Drivers

Sample Parallel Drivers

Note This documentation does not apply to Microsoft® Windows® Me. Windows Me uses the Windows 95 Virtual Communication Driver model to support parallel ports. For more information about Windows Me support for parallel ports, see information about virtual communications drivers in the Windows 95 Documentation section of the Windows DDK.


I/O Requests for Parallel Ports

This section describes the device-specific operations that the system-supplied function driver for parallel ports does for the following I/O requests:

IRP_MJ_CREATE

IRP_MJ_INTERNAL_DEVICE_CONTROL

If the parallel port function driver does not support an I/O request, it returns an I/O status of STATUS_NOT_SUPPORTED.

See the following topics for more information on how the parallel port function driver generally handles major I/O requests:

Sample Parallel Drivers

IRP Function Codes and IOCTLs

Plug and Play IRPs

Power Management

WMI IRPs


IRP_MJ_CREATE

The IRP_MJ_CREATE request opens a parallel port.

When Sent

A client must open a parallel port before it can access the port or a device connected to the port.

Input Parameters

None

Output Parameters

None

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the following values:

STATUS_SUCCESS
The parallel port was successfully opened.
STATUS_DELETE_PENDING
The device is in the process of being removed by the Plug and Play manager.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Operation

A parallel port is a shared device. When the system-supplied function driver for parallel ports receives an open request for an parallel port, it simply increments the count of open files on the parallel port.


IRP_MJ_INTERNAL_DEVICE_CONTROL

To operate a parallel port, a client uses internal device control requests for parallel ports.

When Sent

A client sends an internal device control request to do the following types of operations:

  • Obtain information about the port
  • Allocate the port or select a device on the port
  • Set the communication mode

Input Parameters

The input is request specific.

Output Parameters

The output is request specific.

I/O Status Block

The Information member is request specific.

The Status member is set to a request specific value or to one of the following generic status values:

Generic Status Values Returned by Internal Device Control Requests for Parallel Ports

STATUS_SUCCESS
The request was completed successfully.
STATUS_CANCELLED
The request was cancelled.
STATUS_DELETE_PENDING
The drive is in the process of being removed.
STATUS_INVALID_PARAMETER
The system-supplied function driver for parallel ports does not support the request.
STATUS_PENDING
The request is pending.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Operation

The operation is request-specific.


Internal Device Control Requests for Parallel Ports

This section describes how the system-supplied function driver for parallel ports handles the following internal device control requests:

IOCTL_INTERNAL_DESELECT_DEVICE

IOCTL_INTERNAL_GET_MORE_PARALLEL_PORT_INFO

IOCTL_INTERNAL_GET_PARALLEL_PNP_INFO

IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO

IOCTL_INTERNAL_INIT_1284_3_BUS

IOCTL_INTERNAL_PARALLEL_CLEAR_CHIP_MODE

IOCTL_INTERNAL_PARALLEL_CONNECT_INTERRUPT

IOCTL_INTERNAL_PARALLEL_DISCONNECT_INTERRUPT

IOCTL_INTERNAL_PARALLEL_PORT_ALLOCATE

IOCTL_INTERNAL_PARALLEL_PORT_FREE

IOCTL_INTERNAL_PARALLEL_SET_CHIP_MODE

IOCTL_INTERNAL_RELEASE_PARALLEL_PORT_INFO

IOCTL_INTERNAL_SELECT_DEVICE

The system-supplied function driver does not support any other internal device control requests.


IOCTL_INTERNAL_DESELECT_DEVICE

Operation

The IOCTL_INTERNAL_DESELECT_DEVICE request deselects an IEEE 1284.3 daisy-chain device or an IEEE 1284 end-of-chain device attached to a parallel port.

For more information, see Selecting and Deselecting an IEEE 1284 Device Attached to a Parallel Port.

Input

The AssociatedIrp.SystemBuffer member points to a PARALLEL_1284_COMMAND structure that the client allocates to input IEEE 1284.3 command information. The client can free the parallel port by not setting the PAR_HAVE_PORT_KEEP_PORT flag in the CommandFlags member.

The Parameters.DeviceIoControl.InputBufferLength member specifies the size, in bytes, of the PARALLEL_1284_COMMAND structure.

Output

None

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values returned by internal device control requests for parallel ports or to one of the following values:

STATUS_BUFFER_TOO_SMALL
The value of the Parameters.DeviceIoControl.InputBufferLength member is less than the size, in bytes, of a PARALLEL_1284_COMMAND structure.
STATUS_INVALID_PARAMETER
The specified device is not flagged internally as an end-of-chain device, and the specified ID value is greater than the number of existing daisy-chain devices.

Headers

Defined in parallel.h. Include parallel.h.

See Also

IOCTL_INTERNAL_SELECT_DEVICE,PARALLEL_1284_COMMAND


IOCTL_INTERNAL_GET_MORE_PARALLEL_PORT_INFO

Operation

The IOCTL_INTERNAL_GET_MORE_PARALLEL_PORT_INFO request returns information about a parallel port. This information supplements the information that a client obtains by using an IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO request. The additional information about the parallel port includes the type of system interface, the bus number, and the interrupt resources used by the port.

For more information, see Obtaining Information About a Parallel Port.

Input

The Parameters.DeviceIoControl.OutputBufferLength member is set to the size, in bytes, of a MORE_PARALLEL_PORT_INFORMATION structure.

Output

The AssociatedIrp.SystemBuffer member points to a MORE_PARALLEL_PORT_INFORMATION structure that the client allocates to output parallel port information.

I/O Status Block

If the request succeeds, the Information member is set to the size, in bytes, of the MORE_PARALLEL_PORT_INFORMATION structure. Otherwise; the Information member is set to zero.

The Status member is set to one of the generic status values returned by internal device control requests for parallel ports or to the following value:
STATUS_BUFFER_TOO_SMALL
The value of the Parameters.DeviceIoControl.OutputBufferLength member is less than the size, in bytes, of a MORE_PARALLEL_PORT_INFORMATION structure.

Headers

Defined in parallel.h. Include parallel.h.

See Also

IOCTL_INTERNAL_GET_PARALLEL_PNP_INFO, MORE_PARALLEL_PORT_INFORMATION, IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO


IOCTL_INTERNAL_GET_PARALLEL_PNP_INFO

Operation

The IOCTL_INTERNAL_GET_PARALLEL_PNP_INFO request returns Plug and Play information about a parallel port.

For more information, see Obtaining Information About a Parallel Port.

Input

The Parameters.DeviceIoControl.OutputBufferLength member is set to the size, in bytes, of a PARALLEL_PNP_INFORMATION structure.

Output

The AssociatedIrp.SystemBuffer member points to a PARALLEL_PNP_INFORMATION structure that the client allocates to output Plug and Play information.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values returned by internal device control requests for parallel ports or to the following value:

STATUS_BUFFER_TOO_SMALL
The value of Parameters.DeviceIoControl.OutputBufferLength is less than the size, in bytes, of a PARALLEL_PNP_INFORMATION structure.

Headers

Defined in parallel.h. Include parallel.h.

See Also

IOCTL_INTERNAL_GET_MORE_PARALLEL_PORT_INFO, IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO, PARALLEL_PNP_INFORMATION


IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO

Operation

The IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO request returns information about a parallel port. The information specifies the resources assigned to the parallel port, the capabilities of the port, and pointers to Parallel Port Callback Routines.

For more information, see Obtaining Information About a Parallel Port.

Input

The Parameters.DeviceIoControl.OutputBufferLength member is set to the size, in bytes, of a PARALLEL_PORT_INFORMATION structure.

Output

The AssociatedIrp.SystemBuffer member points to a PARALLEL_PORT_INFORMATION structure that the client allocates to output the parallel port information.

I/O Status Block

If this request succeeds, the Information member is set to the size, in bytes, of a PARALLEL_PORT_INFORMATION structure. Otherwise, the Information member is set to zero.

The Status member is set to one of the generic status values returned by internal device control requests for parallel ports or to the following value:
STATUS_BUFFER_TOO_SMALL
The value of the Parameters.DeviceIoControl.OutputBufferLength member is less than the size, in bytes, of a PARALLEL_PORT_INFORMATION structure.

Headers

Defined in parallel.h. Include parallel.h.

See Also

IOCTL_INTERNAL_GET_MORE_PARALLEL_PORT_INFO, IOCTL_INTERNAL_GET_PARALLEL_PNP_INFO,PARALLEL_PORT_INFORMATION


IOCTL_INTERNAL_INIT_1284_3_BUS

Operation

The IOCTL_INTERNAL_INIT_1284_3_BUS request initializes and assigns an IEEE 1284.3 device ID to all the 1284.3 daisy chain devices that are attached to a parallel port.

Windows 2000 supports from zero to four daisy-chain devices and an end-of-chain device simultaneously attached to a parallel port. Windows XP supports from zero to two daisy-chain devices and an end-of-chain device simultaneously attached to a parallel port.

Note This request is included primarily for test purposes, and Microsoft does not recommend using it during the normal operation of a parallel port.

For more information, see Device Stacks for Parallel Ports and Devices.

Input

None

Output

None

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values returned by internal device control requests for parallel ports.

Headers

Defined in parallel.h. Include parallel.h.

See Also

IOCTL_INTERNAL_SELECT_DEVICE, IOCTL_INTERNAL_DESELECT_DEVICE


IOCTL_INTERNAL_PARALLEL_CLEAR_CHIP_MODE

Operation

The IOCTL_INTERNAL_PARALLEL_CLEAR_CHIP_MODE request clears the operating mode of a parallel port.

For more information see, Setting and Clearing the Communication Mode on a Parallel Port.

Input

The AssociatedIrp.SystemBuffer member points to a PARALLEL_CHIP_MODE structure that the client allocates to input chip mode information. The client sets the ModeFlags member to the current operating mode.

The request sets the Parameters.DeviceIoControl.InputBufferLength member to the size, in bytes, of a PARALLEL_CHIP_MODE structure.

Output

None

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values returned by internal device control requests for parallel ports or to one of the following values:

STATUS_BUFFER_TOO_SMALL
The value of the Parameters.DeviceIoControl.InputBufferLength member is less than the size, in bytes, of a PARALLEL_CHIP_MODE structure.
STATUS_INVALID_DEVICE_STATE
The specified operating mode is not the same as the current operating mode of the parallel port.

Headers

Defined in parallel.h. Include parallel.h.

See Also

IOCTL_INTERNAL_PARALLEL_SET_CHIP_MODE, PARALLEL_CHIP_MODE


IOCTL_INTERNAL_PARALLEL_CONNECT_INTERRUPT

Operation

The IOCTL_INTERNAL_PARALLEL_CONNECT_INTERRUPT request connects an optional interrupt service routine and an optional deferred port check routine to a parallel port. Only kernel-mode drivers can use this request.

The connect interrupt request returns information that the driver can use in the context of a driver-specific ISR. The information includes a pointer to the interrupt object and pointers to callback routines that allocate and free the parallel port at IRQL DIRQL.

Note Microsoft does not recommend using a client-supplied interrupt routine. The use of interrupts might cause system instability. By default, the connect interrupt request is disabled. For more information, see Connecting an Interrupt Service Routine to a Parallel Port.

Input

The AssociatedIrp.SystemBuffer member points to a PARALLEL_INTERRUPT_SERVICE_ROUTINE structure that the client allocates to input interrupt service information. The system-supplied function driver for parallel ports uses the same memory buffer, but casts it to a different data type to output information.

The Parameters.DeviceIoControl.InputBufferLength member is set to the size, in bytes, of a PARALLEL_INTERRUPT_SERVICE_ROUTINE structure.

The Parameters.DeviceIoControl.OutputBufferLength member is set to the size, in bytes, of a PARALLEL_INTERRUPT_INFORMATION structure.

Output

The AssociatedIrp.SystemBuffer member points to a PARALLEL_INTERRUPT_INFORMATION structure that the parallel port function driver uses to output parallel interrupt information.

I/O Status Block

If the request is successful, the Information member is set to the size, in bytes, of a PARALLEL_INTERRUPT_INFORMATION structure. Otherwise, the Information member is set to zero.

The Status member is set to one of the generic status values returned by internal device control requests for parallel ports or to one of the following values:

STATUS_BUFFER_TOO_SMALL
At least one of the following is true:

The value of the Parameters.DeviceIoControl.InputBufferLength member is less than the size, in bytes, of a PARALLEL_INTERRUPT_SERVICE_ROUTINE structure.

The value of the Parameters.DeviceIoControl.OuputBufferLength member is less than the size, in bytes, of a PARALLEL_INTERRUPT_INFORMATION structure.

STATUS_INSUFFICIENT_RESOURCES
The parallel port function driver could not allocate a dynamic data structure.
STATUS_UNSUCCESSFUL
The connect interrupt request is disabled.

Headers

Defined in parallel.h. Include parallel.h.

See Also

IOCTL_INTERNAL_PARALLEL_DISCONNECT_INTERRUPT, PARALLEL_INTERRUPT_INFORMATION, PARALLEL_INTERRUPT_SERVICE_ROUTINE


IOCTL_INTERNAL_PARALLEL_DISCONNECT_INTERRUPT

Operation

The IOCTL_INTERNAL_PARALLEL_DISCONNECT_INTERRUPT request disconnects an interrupt service routine (and an optional deferred port check service routine) that was connected by using an IOCTL_INTERNAL_PARALLEL_CONNECT_INTERRUPT request. Only kernel-mode drivers can connect and disconnect an interrupt routine.

Note Microsoft does not recommend using a client-supplied interrupt routine. The use of interrupts might cause system instability. By default, the connect interrupt request is disabled. For more information, see Connecting an Interrupt Service Routine to a Parallel Port.

Input

The AssociatedIrp.SystemBuffer member points to a PARALLEL_INTERRUPT_SERVICE_ROUTINE structure that the client allocates for the input of interrupt service information.

The Parameters.DeviceIoControl.InputBufferLength member is set to the size, in bytes, of a PARALLEL_INTERRUPT_SERVICE_ROUTINE structure.

Output

None

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values returned by internal device control requests for parallel ports or to one of the following values:

STATUS_BUFFER_TOO_SMALL
The value of the Parameters.DeviceIoControl.InputBufferLength member is less than the size, in bytes, of a PARALLEL_INTERRUPT_SERVICE_ROUTINE structure.
STATUS_INVALID_PARAMETER
The specified interrupt service routine is not connected.

Headers

Defined in parallel.h. Include parallel.h.

See Also

IOCTL_INTERNAL_PARALLEL_CONNECT_INTERRUPT, PARALLEL_INTERRUPT_INFORMATION, PARALLEL_INTERRUPT_SERVICE_ROUTINE


IOCTL_INTERNAL_PARALLEL_PORT_ALLOCATE

Operation

The IOCTL_INTERNAL_PARALLEL_PORT_ALLOCATE request allocates a parallel port for exclusive access by a client. Before accessing port hardware, a client must first allocate it.

For more information, see Synchronizing the Use of a Parallel Port.

Input

None

Output

None

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values returned by internal device control requests for parallel ports.

Headers

Defined in parallel.h. Include parallel.h.

See Also

IOCTL_INTERNAL_PARALLEL_PORT_FREE


IOCTL_INTERNAL_PARALLEL_PORT_FREE

Operation

The IOCTL_INTERNAL_PARALLEL_PORT_FREE request frees a parallel port. After using a parallel port, a client must free it. Microsoft recommends using the FreePort callback to free a parallel port because there is no functional advantage to using the port free request.

For more information, see Synchronizing the Use of a Parallel Port.

Input

None

Output

None

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values returned by internal device control requests for parallel ports.

Headers

Defined in parallel.h. Include parallel.h.

See Also

IOCTL_INTERNAL_PARALLEL_PORT_ALLOCATE


IOCTL_INTERNAL_PARALLEL_SET_CHIP_MODE

Operation

The IOCTL_INTERNAL_PARALLEL_SET_CHIP_MODE request sets the operating mode of a parallel port.

For more information, see Setting and Clearing the Communication Mode on a Parallel Port.

Input

The AssociatedIrp.SystemBuffer member points to a PARALLEL_CHIP_MODE structure that the client allocates to input chip mode information. The client sets the ChipMode member to the requested operating mode.

The Parameters.DeviceIoControl.InputBufferLength member is set to the size, in bytes, of a PARALLEL_CHIP_MODE structure.

Output

None

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values returned by internal device control requests for parallel ports or to one of the following values:

STATUS_BUFFER_TOO_SMALL
The value of the Parameters.DeviceIoControl.InputBufferLength member is less than the size, in bytes, of a PARALLEL_CHIP_MODE structure.
STATUS_INVALID_DEVICE_STATE
The mode is not cleared.
STATUS_NO_SUCH_DEVICE
The requested operating mode is not valid.

Headers

Defined in parallel.h. Include parallel.h.

See Also

IOCTL_INTERNAL_PARALLEL_CLEAR_CHIP_MODE, PARALLEL_CHIP_MODE


IOCTL_INTERNAL_RELEASE_PARALLEL_PORT_INFO

Operation

The IOCTL_INTERNAL_RELEASE_PARALLEL_PORT_INFO request returns STATUS_SUCCESS.

Note The intended purpose of this IOCTL is to make it possible to page the callback routines supported by the system-supplied function driver for parallel ports. However, this capability is not yet implemented.

Input

None

Output

None

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values returned by internal device control requests for parallel ports.

Headers

Defined in parallel.h. Include parallel.h.

See Also

IOCTL_INTERNAL_GET_MORE_PARALLEL_PORT_INFO, IOCTL_INTERNAL_GET_PARALLEL_PNP_INFO, IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO


IOCTL_INTERNAL_SELECT_DEVICE

Operation

The IOCTL_INTERNAL_SELECT_DEVICE request:

  • Allocates the parallel port

    The system-supplied function driver for parallel ports allocates the parallel port if the client does not set the PAR_HAVE_PORT_KEEP_PORT flag in the CommandFlags member of the input PARALLEL_1284_COMMAND structure. Otherwise, the parallel port function driver does not allocate the parallel port.

  • Selects an IEEE 1284.3 daisy-chain parallel device or an end-of-chain device attached to the parallel port

    Although a client can select an end-of-chain device using a select device request, Microsoft recommends using an IOCTL_INTERNAL_PARALLEL_PORT_ALLOCATE request instead. The parallel port function driver selects the end-of-chain device before it allocates the parallel port to a client.

For more information, see Selecting and Deselecting an IEEE 1284 Device Attached to a Parallel Port.

Input

The AssociatedIrp.SystemBuffer points to a PARALLEL_1284_COMMAND structure that the client allocates to input the select device information.

The Parameters.DeviceIoControl.InputBufferLength member specifies the size, in bytes, of a PARALLEL_1284_COMMAND structure.

Output

None

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values returned by internal device control requests for parallel ports or to one of the following values:

STATUS_BUFFER_TOO_SMALL
The value of the Parameters.DeviceIoControl.InputBufferLength member is less than the size, in bytes, of a PARALLEL_1284_COMMAND structure.
STATUS_INVALID_PARAMETER
The specified device is not flagged internally as an end-of-chain device and the value of the ID member of the input structure is greater than the number of existing daisy-chain devices.

Headers

Defined in parallel.h. Include parallel.h.

See Also

IOCTL_INTERNAL_DESELECT_DEVICE, PARALLEL_1284_COMMAND


Parallel Port Callback Routines

This section describes the callback routines supported by the system-supplied function driver for parallel ports.

A kernel-mode driver can use these callbacks to operate a parallel port. Some of the callback routines have equivalent device control requests, which are preferred over using the following callback routines:

ClearChipMode

DeselectDevice

FreePort

FreePortFromInterruptLevel

QueryNumWaiters

TryAllocatePort

TryAllocatePortAtInterruptLevel

TrySelectDevice

TrySetChipMode


ClearChipMode

ClearChipMode clears the operating mode of a parallel port by resetting the communication mode of the host chipset to IEEE 1284-compatibility mode.

NTSTATUS
  *ClearChipMode(
    IN PDEVICE_EXTENSION  Extension,
    IN UCHAR  ChipMode
    )

Parameters

Extension
Pointer to the device extension of a parallel port's function device object (FDO).
ChipMode
Specifies the current operating mode of the parallel port.

For more information on operating modes, see the modes defined for the enhanced capabilities register (ECR) in parallel.h of the Microsoft Windows DDK.

Return Value

STATUS_SUCCESS
The operating mode was set to IEEE 1284-compatibility mode.
STATUS_INVALID_DEVICE_STATE
The specified mode does not match the current mode.

Headers

Defined in parallel.h. Include parallel.h.

Comments

A kernel-mode driver uses an IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO request to obtain the ClearChipMode pointer.

A caller uses ClearChipMode in conjunction with TrySetChipMode.

To set a mode, a caller must first clear the current mode.

ClearChipMode runs in the caller's thread at IRQL <= DISPATCH_LEVEL.

For more information, see Setting and Clearing the Communication Mode on a Parallel Port.

See Also

IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO, IOCTL_INTERNAL_PARALLEL_CLEAR_CHIP_MODE, IOCTL_INTERNAL_PARALLEL_SET_CHIP_MODE, TrySetChipMode


DeselectDevice

DeselectDevice deselects an IEEE 1284.3 daisy-chain device or an IEEE 1284 end-of-chain device attached to a parallel port.

NTSTATUS
  *DeselectDevice(
    IN PVOID Context,
    IN PVOID DeselectCommand
    )

Parameters

Context
Pointer to the device extension of a functional device object (FDO) that represents a parallel port.
DeselectCommand
Pointer to a PARALLEL_1284_COMMAND structure. The caller specifies the following members:
ID
Specifies the 1284.3 device ID (zero or one).
CommandFlags
Specifies a bitwise OR of zero or more of the following flags:
Value | Description
PAR_END_OF_CHAIN_DEVICE | Specifies an end-of-chain device.
PAR_HAVE_PORT_KEEP_PORT | Specifies that the port be kept allocated.

Return Value

STATUS_SUCCESS
The device was deselected.
STATUS_INVALID_PARAMETER
The specified device ID is invalid.
STATUS_UNSUCCESSFUL
The system-supplied function driver for parallel ports could not deselect the device.

Headers

Defined in parallel.h. Include parallel.h.

Comments

A kernel-mode driver uses an IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO request to obtain the DeselectDevice pointer.

A kernel-mode driver can use an IOCTL_INTERNAL_DESELECT_DEVICE request or a DeselectDevice call to deselect a device on a parallel port represented by a parallel port. To deselect a device, a caller should have the parallel port allocated. If the caller does not set the PAR_HAVE_PORT_KEEP_PORT flag, the system-supplied function driver for parallel ports frees the parallel port after deselecting the device.

DeselectDevice runs in the caller's thread at IRQL <= DISPATCH_LEVEL.

For more information, see Selecting and Deselecting an IEEE 1284 Device Attached to a Parallel Port.

See Also

IOCTL_INTERNAL_SELECT_DEVICE, TrySelectDevice


FreePort

FreePort frees a parallel port.

VOID
  *FreePort(
    IN PVOID Context
    )

Parameters

Context
Pointer to the device extension of a parallel port's function device object (FDO).

Return Value

None

Headers

Defined in parallel.h. Include parallel.h.

Comments

A kernel-mode driver uses an IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO request to obtain the FreePort pointer.

The driver should allocate a parallel port before freeing it. A driver can use QueryNumWaiters to determine the number of clients that are waiting to allocate the parallel port, and TryAllocatePort to try to allocate the parallel port.

FreePort runs in the caller's thread at IRQL <= DISPATCH_LEVEL.

For more information, see Synchronizing the Use of a Parallel Port.

See Also

QueryNumWaiters, TryAllocatePort


FreePortFromInterruptLevel

FreePortFromInterruptLevel frees a parallel port at IRQL DIRQL.

VOID
  *FreePortFromInterruptLevel(
    IN PVOID Context
    )

Parameters

Context
Pointer to the device extension of a functional device object (FDO) that represents a parallel port.

Return Value

None

Headers

Defined in parallel.h. Include parallel.h.

Comments

A kernel-mode driver connects an interrupt service routine by using an IOCTL_INTERNAL_PARALLEL_CONNECT_INTERRUPT to obtain a FreePortFromInterruptLevel pointer.

The driver should allocate a parallel port before freeing it. A driver can use TryAllocatePortAtInterruptLevel to try to allocate the parallel port at IRQL DIRQL.

If there are no requests on the work queue, FreePortFromInterruptLevel immediately frees the parallel port; otherwise, it queues a deferred procedure call that frees the port at a later time.

FreePortFromInterruptLevel runs at IRQL=DIRQL.

Note FreePortFromInterruptLevel is untested. Microsoft does not recommend using a client-supplied interrupt routine. The use of interrupts might cause system instability. By default, the IOCTL_INTERNAL_PARALLEL_CONNECT_INTERRUPT request is disabled. For more information, see Connecting an Interrupt Service Routine to a Parallel Port.

See Also

FreePort, IOCTL_INTERNAL_PARALLEL_CONNECT_INTERRUPT, IOCTL_INTERNAL_PARALLEL_DISCONNECT_INTERRUPT, QueryNumWaiters, TryAllocatePort, TryAllocatePortAtInterruptLevel


QueryNumWaiters

QueryNumWaiters returns the number of IOCTL_INTERNAL_PARALLEL_PORT_ALLOCATE and IOCTL_INTERNAL_SELECT_DEVICE requests that are queued on the work queue of a parallel port.

ULONG
  *QueryNumWaiters(
    IN PVOID Extension
    )

Parameters

Extension
Pointer to the device extension of a functional device object (FDO) that represents a parallel port.

Return Value

The number of requests that are queued on the work queue of the parallel port.

Headers

Defined in parallel.h. Include parallel.h.

Comments

A kernel-mode driver uses an IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO request to obtain the QueryNumWaiters pointer.

A driver can use QueryNumWaiters to adjust its use of the parallel port based on the number of other clients that are waiting for access to the parallel port. The system-supplied function driver for parallel ports queues only allocate and select requests.

QueryNumWaiters runs in the caller's thread at an IRQL <= DISPATCH_LEVEL.

For more information, see Synchronizing the Use of a Parallel Port.

See Also

FreePort, IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO, IOCTL_INTERNAL_PARALLEL_PORT_ALLOCATE, IOCTL_INTERNAL_PARALLEL_PORT_FREE, TryAllocatePort


TryAllocatePort

TryAllocatePort is a non-blocking routine that tries to allocate a parallel port.

BOOLEAN
  *TryAllocatePort(
    IN PVOID Context
    )

Parameters

Context
Pointer to the device extension of a parallel port's function device object (FDO).

Return Value

TRUE
The port was allocated.
FALSE
The port was not allocated.

Headers

Defined in parallel.h. Include parallel.h.

Comments

A kernel-mode driver sends an IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO request to obtain the TryAllocatePort pointer.

A driver can use TryAllocatePort to allocate a parallel port instead of using an IOCTL_INTERNAL_PARALLEL_PORT_ALLOCATE request. TryAllocatePort is non-blocking, does not queue a port allocate request, and returns immediately.

If a client uses only TryAllocatePort to attempt to allocate a parallel port for which other clients are contending, the system-supplied function driver for parallel ports might never allocate the port to the client. To ensure success, a client must use a port allocate request.

The parallel port function driver queues, and subsequently processes, port allocate requests and device select requests in the order in which the requests are received.

TryAllocatePort runs in the caller's thread at an IRQL <= DISPATCH_LEVEL.

See Also

FreePort, IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO, IOCTL_INTERNAL_PARALLEL_PORT_ALLOCATE, IOCTL_INTERNAL_PARALLEL_PORT_FREE, QueryNumWaiters


TryAllocatePortAtInterruptLevel

TryAllocatePortAtInterruptLevel allocates a parallel port at IRQL=DIRQL.

BOOLEAN
  *TryAllocatePortAtInterruptLevel(
    IN PVOID Context
    )

Parameters

Context
Pointer to the device extension of a functional device object that represents a parallel port.

Return Value

TRUE
The parallel port was allocated.
FALSE
The parallel port was not allocated.

Headers

Defined in parallel.h. Include parallel.h.

Comments

A kernel-mode driver sends an IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO request to obtain the TryAllocatePortAtInterruptLevel pointer.

TryAllocatePortAtInterruptLevel is nonblocking, does not queue an allocate request, and returns immediately.

A driver uses TryAllocatePortAtInterruptLevel in conjunction with an ISR. If the driver does not have a parallel port allocated when the driver's ISR is called, the driver can use TryAllocatePortAtInterruptLevel.

Note TryAllocatePortAtInterruptLevel is untested. Microsoft does not recommend using a client-supplied interrupt routine. The use of interrupts might cause system instability. By default, the IOCTL_INTERNAL_PARALLEL_CONNECT_INTERRUPT request is disabled. For more information, see Connecting an Interrupt Service Routine to a Parallel Port.

See Also

FreePort, FreePortFromInterruptLevel, IOCTL_INTERNAL_PARALLEL_CONNECT_INTERRUPT, IOCTL_INTERNAL_PARALLEL_DISCONNECT_INTERRUPT, IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO, IOCTL_INTERNAL_PARALLEL_PORT_ALLOCATE, IOCTL_INTERNAL_PARALLEL_PORT_FREE, TryAllocatePort


TrySelectDevice

TrySelectDevice selects an IEEE 1284.3 daisy-chain device or an IEEE 1284 end-of-chain device attached to a parallel port.

NTSTATUS
  *TrySelectDevice(
    IN PVOID Context,
    IN PVOID TrySelectCommand
    )

Parameters

Context
Pointer to the device extension of a parallel port's function device object (FDO).
TrySelectCommand
Pointer to a PARALLEL_1284_COMMAND structure. The caller specifies the following members:
ID
Specifies the 1284.3 device ID.
CommandFlags
Specifies a bitwise OR of zero or more of the following flags:
Value | Description
PAR_END_OF_CHAIN_DEVICE | Specifies an end-of-chain device.
PAR_HAVE_PORT_KEEP_PORT | Specifies that the caller has the port allocated and to keep the port allocated.

Return Value

STATUS_SUCCESS
The device was selected.
STATUS_INVALID_PARAMETER
The device ID is not valid.
STATUS_PENDING
The caller did not specify PAR_HAVE_PORT_KEEP_PORT, and the parallel port is already allocated.
STATUS_UNSUCCESSFUL
The caller has allocated the parallel port, but the system-supplied function driver for parallel ports could not select the specified parallel device.

Headers

Defined in parallel.h. Include parallel.h.

Comments

A kernel-mode driver uses an IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO request to obtain the TrySelectDevice pointer.

A kernel-mode driver can use an IOCTL_INTERNAL_SELECT_DEVICE request or TrySelectDevice to select a parallel device on a parallel port. The parallel port function driver queues a select request if the parallel port is already allocated. However, TrySelectDevice does not queue a select request, and the routine returns immediately if the port cannot be allocated.

If a client uses only TrySelectDevice to attempt to select a parallel device, and other clients are contending for the parallel port, the system-supplied function driver for parallel ports might never allocate the port to the client. To ensure success, a client must use a select device request.

The parallel port function driver queues, and subsequently processes, port allocate requests and device select requests in the order in which the requests are received.

TrySelectDevice runs in the caller's thread at IRQL <= DISPATCH_LEVEL

For more information, see Selecting and Deselecting an IEEE 1284 Device Attached to a Parallel Port.

See Also

DeselectDevice, IOCTL_INTERNAL_DESELECT_DEVICE, IOCTL_INTERNAL_SELECT_DEVICE


TrySetChipMode

TrySetChipMode sets the operating mode of a parallel port.

NTSTATUS
  *TrySetChipMode(
    IN PDEVICE_EXTENSION Extension,
    IN UCHAR ChipMode
    )

Members

Extension
Pointer to the device extension of a parallel port's function device object (FDO).
ChipMode
Specifies the operating mode of a parallel port. (For more information on operating modes, see the modes defined for the enhanced capabilities register (ECR) in parallel.h of the Windows DDK.)

Return Value

STATUS_SUCCESS
The specified operating mode was set.
STATUS_INVALID_DEVICE_STATE
The mode is not cleared.
STATUS_NO_SUCH_DEVICE
The specified operating mode is not valid.

Headers

Defined in parallel.h. Include parallel.h.

Comments

A kernel-mode driver uses an IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO request to obtain the TrySetChipMode pointer.

The TrySetChipMode callback routine sets the operating mode of a parallel port. A caller uses TrySetChipMode in conjunction with ClearChipMode.

To set a new mode, a caller must first clear the current mode.

TrySetChipMode runs in the caller's thread at IRQL <= DISPATCH_LEVEL.

For more information, see Setting and Clearing the Communication Mode on a Parallel Port.

See Also

ClearChipMode, IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO, IOCTL_INTERNAL_PARALLEL_CLEAR_CHIP_MODE, IOCTL_INTERNAL_PARALLEL_SET_CHIP_MODE


Parallel Port Data Types

This section describes the following data types that the system-supplied function driver for parallel ports uses to input and output information about a parallel port:

MORE_PARALLEL_PORT_INFORMATION

PARALLEL_1284_COMMAND

PARALLEL_CHIP_MODE

PARALLEL_INTERRUPT_INFORMATION

PARALLEL_INTERRUPT_SERVICE_ROUTINE

PARALLEL_PNP_INFORMATION

PARALLEL_PORT_INFORMATION

PAR_QUERY_INFORMATION

PAR_SET_INFORMATION


MORE_PARALLEL_PORT_INFORMATION

The MORE_PARALLEL_PORT_INFORMATION structure specifies information about the system interface that supports the operation of a parallel port.

typedef struct _MORE_PARALLEL_PORT_INFORMATION {
  INTERFACE_TYPE  InterfaceType;
  ULONG  BusNumber;
  ULONG  InterruptLevel;
  ULONG  InterruptVector;
  KAFFINITY  InterruptAffinity;
  KINTERRUPT_MODE InterruptMode;
} MORE_PARALLEL_PORT_INFORMATION, *PMORE_PARALLEL_PORT_INFORMATION;

Members

InterfaceType
Specifies the interface type associated with a parallel port.
BusNumber
Specifies the bus number for the interface.
InterruptLevel
Specifies the interrupt level for the parallel port.
InterruptVector
Specifies the interrupt vector for the parallel port.
InterruptAffinity
Specifies the interrupt affinity value.
InterruptMode
Specifies the interrupt mode.

Headers

Defined in parallel.h. Include parallel.h.

Comments

An IRP_MN_START_DEVICE request from the Plug and Play Manager passes a translated resource list that contains the information in a MORE_PARALLEL_PORT_INFORMATION structure. The system-supplied function driver for parallel ports saves the information in the device extension of the parallel port FDO, and returns the information in response to an IOCTL_INTERNAL_GET_MORE_PARALLEL_PORT_INFO request.

For more information, see Obtaining Information About a Parallel Port.

See Also

IOCTL_INTERNAL_GET_MORE_PARALLEL_PORT_INFO, IOCTL_INTERNAL_GET_PARALLEL_PNP_INFO, IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO, PARALLEL_PORT_INFORMATION, PARALLEL_PNP_INFORMATION


PARALLEL_1284_COMMAND

The PARALLEL_1284_COMMAND structure specifies information that a client uses to select and deselect an IEEE 1284.3 daisy-chain device or an IEEE 1284 end-of-chain device.

typedef struct _PARALLEL_1284_COMMAND {
  UCHAR  ID;
  UCHAR  Port;
  ULONG  CommandFlags;
} PARALLEL_1284_COMMAND, *PPARALLEL_1284_COMMAND;

Members

ID
Specifies the IEEE 1284.3 device ID.
Port
Reserved (set to zero).
CommandFlags
Specifies a bitwise OR of zero or more of the following flags:
PAR_END_OF_CHAIN_DEVICE
Specifies an end-of-chain device.
PAR_HAVE_PORT_KEEP_PORT
Specifies that the client has the parallel port allocated, and makes a request to keep the port allocated.

Headers

Defined in parallel.h. Include parallel.h.

Comments

The system-supplied function driver for parallel ports supports the simultaneous connection of zero to two IEEE 1284.3 daisy-chain devices and an IEEE 1284 end-of-chain device. In Windows XP, the parallel port function driver supports the simultaneous connection of zero to four IEEE 1284.3 daisy-chain devices and an IEEE 1284 end-of-chain device. The end-of-chain device must be an IEEE 1284 device, but does not have to be an IEEE 1284.3 device.

For more information, see Selecting and Deselecting an IEEE 1284 Device Attached to a Parallel Port.

See Also

DeselectDevice, IOCTL_INTERNAL_DESELECT_DEVICE, IOCTL_INTERNAL_SELECT_DEVICE, TrySelectDevice


PARALLEL_CHIP_MODE

The PARALLEL_CHIP_MODE structure specifies the operating mode of a parallel port.

typedef struct _PARALLEL_CHIP_MODE {
  UCHAR  ModeFlags;
  BOOLEAN  success;
} PARALLEL_CHIP_MODE, *PPARALLEL_CHIP_MODE;

Members

ModeFlags
Specifies an operating mode of a parallel port, either an enhanced parallel port (EPP) mode or an extended capabilities port (ECP) mode.
success
Not used.

Headers

Defined in parallel.h. Include parallel.h.

Comments

A client uses a PARALLEL_CHIP_MODE structure with internal device control requests to set and clear the operating mode of a parallel port.

Note Microsoft does not recommend using a client-supplied interrupt routine. The use of interrupts might cause system instability. By default, the IOCTL_INTERNAL_PARALLEL_CONNECT_INTERRUPT request is disabled. For more information, see Connecting an Interrupt Service Routine to a Parallel Port.

See Also

ClearChipMode, IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO, IOCTL_INTERNAL_PARALLEL_CLEAR_CHIP_MODE, IOCTL_INTERNAL_PARALLEL_SET_CHIP_MODE, TrySetChipMode


PARALLEL_INTERRUPT_INFORMATION

The PARALLEL_INTERRUPT_INFORMATION structure specifies information that a kernel-mode driver can use in the context of an ISR that the driver connects to a parallel port.

typedef struct _PARALLEL_INTERRUPT_INFORMATION {
  PKINTERRUPT  InterruptObject;
  PPARALLEL_TRY_ALLOCATE_ROUTINE  TryAllocatePortAtInterruptLevel;
  PPARALLEL_FREE_ROUTINE  FreePortFromInterruptLevel;
  PVOID  Context;
} PARALLEL_INTERRUPT_INFORMATION, *PPARALLEL_INTERRUPT_INFORMATION;

Members

InterruptObject
Pointer to the parallel port interrupt object.
TryAllocatePortAtInterruptLevel
Pointer to a callback routine that a kernel-mode driver can use to try to allocate the parallel port at IRQL DIRQL.
FreePortFromInterruptLevel
Pointer to a callback routine that a kernel-mode driver can use to free the parallel port at IRQL DIRQL.
Context
Pointer to the device extension of a functional device object that represents the parallel port.

Headers

Defined in parallel.h. Include parallel.h.

Comments

A kernel-mode driver can use the parallel interrupt information in the context of an interrupt service routine (ISR). A driver connects an ISR using an IOCTL_INTERNAL_PARALLEL_CONNECT_INTERRUPT request.

Note Microsoft does not recommend using a client-supplied interrupt routine. The use of interrupts might cause system instability. By default, the IOCTL_INTERNAL_PARALLEL_CONNECT_INTERRUPT request is disabled. For more information, see Connecting an Interrupt Service Routine to a Parallel Port.

See Also

FreePortFromInterruptLevel, IOCTL_INTERNAL_PARALLEL_CONNECT_INTERRUPT, IOCTL_INTERNAL_PARALLEL_DISCONNECT_INTERRUPT, PARALLEL_INTERRUPT_SERVICE_ROUTINE, TryAllocatePortAtInterruptLevel


PARALLEL_INTERRUPT_SERVICE_ROUTINE

The PARALLEL_INTERRUPT_SERVICE_ROUTINE structure specifies interrupt services that a kernel-mode driver can connect to the operation of a parallel port.

typedef struct _PARALLEL_INTERRUPT_SERVICE_ROUTINE {
  PKSERVICE_ROUTINE  InterruptServiceRoutine;
  PVOID  InterruptServiceContext;
  PPARALLEL_DEFERRED_ROUTINE  DeferredPortCheckRoutine;
  PVOID  DeferredPortCheckContext;
} PARALLEL_INTERRUPT_SERVICE_ROUTINE, *PPARALLEL_INTERRUPT_SERVICE_ROUTINE;

Members

InterruptServiceRoutine
Pointer to an interrupt service routine.
InterruptServiceContext
Pointer to a context for the interrupt service routine.
DeferredPortCheckRoutine
Pointer to an optional deferred port check routine:
VOID
(*DeferredPortCheckRoutine) (
    IN PVOID DeferredContext
);

Parameters

DeferredContext
Pointer to a context for the deferred port check routine.
DeferredPortCheckContext
Pointer to an optional context for the deferred port check routine.

Headers

Defined in parallel.h. Include parallel.h.

Comments

A kernel-mode driver can connect a device-specific interrupt service routine and a deferred port check routine to the parallel port.

Note Microsoft does not recommend using a client-supplied interrupt routine. The use of interrupts might cause system instability. By default, the IOCTL_INTERNAL_PARALLEL_CONNECT_INTERRUPT request is disabled. For more information, see Connecting an Interrupt Service Routine to a Parallel Port.

See Also

FreePortFromInterruptLevel, IOCTL_INTERNAL_PARALLEL_CONNECT_INTERRUPT, IOCTL_INTERNAL_PARALLEL_DISCONNECT_INTERRUPT, PARALLEL_INTERRUPT_INFORMATION, TryAllocatePortAtInterruptLevel


PARALLEL_PNP_INFORMATION

The PARALLEL_PNP_INFORMATION structure specifies information about the capabilities of a parallel port.

typedef struct _PARALLEL_PNP_INFORMATION {
  PHYSICAL_ADDRESS  OriginalEcpController;
  PUCHAR  EcpController;
  ULONG  SpanOfEcpController;
  ULONG  PortNumber;
  ULONG  HardwareCapabilities;
  PPARALLEL_SET_CHIP_MODE  TrySetChipMode;
  PPARALLEL_CLEAR_CHIP_MODE  ClearChipMode;
  ULONG  FifoDepth;
  ULONG  FifoWidth;
  PHYSICAL_ADDRESS  EppControllerPhysicalAddress;
  ULONG  SpanOfEppController;
  ULONG  Ieee1284_3DeviceCount;
  PPARALLEL_TRY_SELECT_ROUTINE  TrySelectDevice;
  PPARALLEL_DESELECT_ROUTINE  DeselectDevice;
  PVOID  Context;
  ULONG  CurrentMode;
  PWSTR  PortName;
} PARALLEL_PNP_INFORMATION, *PPARALLEL_PNP_INFORMATION;

Members

OriginalEcpController
Specifies the base physical address that the system-supplied function driver for parallel ports uses to control the ECP operation of the parallel port.
EcpController
Pointer to the I/O port resource that is used to control the port in ECP mode.
SpanOfEcpController
Specifies the size, in bytes, of the I/O port resource.
PortNumber
Not used.
HardwareCapabilities
Specifies the hardware capabilities of the parallel port. The following capabilities can be set using a bitwise OR of the following constants:
PPT_1284_3_PRESENT
PPT_BYTE_PRESENT
PPT_ECP_PRESENT
PPT_EPP_32_PRESENT
PPT_EPP_PRESENT
PT_NO_HARDWARE_PRESENT
TrySetChipMode
Pointer to a callback routine that a kernel-mode driver can use to change the operating mode of the parallel port.
ClearChipMode
Pointer to a callback routine that a kernel-mode driver can use to clear the operating mode of the parallel port.
FifoDepth
Specifies the size, in words, of the hardware first in/first out (FIFO) buffer. The FIFO word size, in bits, is the value of FifoWidth.
FifoWidth
Specifies the FIFO word size, in bits, which is the number of bits handled in parallel.
EppControllerPhysicalAddress
Not used.
SpanOfEppController
Not used.
Ieee1284_3DeviceCount
Specifies the number of daisy-chain devices currently attached to a parallel port. In Microsoft® Windows® XP, from zero to two devices can be simultaneously connected to a parallel port. In Windows 2000, from zero to four devices can be simultaneously connected to a parallel port.
TrySelectDevice
Pointer to a callback routine that a kernel-mode driver can use to try to select an IEEE 1284.3 device.
DeselectDevice
Pointer to a callback routine that a kernel-mode driver can use to deselect an IEEE 1284.3 device.
Context
Pointer to the device extension of a parallel port's function device object (FDO).
CurrentMode
The current operating mode of the parallel port.
PortName
The symbolic link name of the parallel port.

Headers

Defined in parallel.h. Include parallel.h.

Comments

For more information, see Obtaining Information About a Parallel Port.

See Also

IOCTL_INTERNAL_GET_MORE_PARALLEL_PORT_INFO, IOCTL_INTERNAL_GET_PARALLEL_PNP_INFO, IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO, MORE PARALLEL_PORT_INFORMATION, PARALLEL_PORT_INFORMATION


PARALLEL_PORT_INFORMATION

The PARALLEL_PORT_INFORMATION structure specifies information about the resources assigned to a parallel port, the capabilities of the parallel port, and pointers to callback routines that a kernel-mode driver can use to operate the parallel port.

typedef struct _PARALLEL_PORT_INFORMATION {
  PHYSICAL_ADDRESS  OriginalController;
  PUCHAR  Controller;
  ULONG  SpanOfController;
  PPARALLEL_TRY_ALLOCATE_ROUTINE  TryAllocatePort
  PPARALLEL_FREE_ROUTINE  FreePort
  PPARALLEL_QUERY_WAITERS_ROUTINE  QueryNumWaiters
  PVOID  Context
} PARALLEL_PORT_INFORMATION, *PPARALLEL_PORT_INFORMATION;

Members

OriginalController
Specifies the bus relative base I/O address of the parallel port registers.
Controller
Pointer to the system-mapped base I/O location of the parallel port registers.
SpanOfController
Specifies the size, in bytes, of the I/O space, allocated to the parallel port.
TryAllocatePort
Pointer to a callback routine that a kernel-mode driver can use to try to allocate the parallel port.
FreePort
Pointer to a callback routine that a kernel-mode driver can use to free the parallel port.
QueryNumWaiters
Pointer to a callback routine that a kernel-mode driver can use to determine the number of requests on the work queue of the parallel port.
Context
Pointer to the device extension of parallel port.

Headers

Defined in parallel.h. Include parallel.h.

Comments

An IRP_MN_START_DEVICE request from the Plug and Play Manager passes a translated resource list that contains the port information in a PARALLEL_PORT_INFORMATION structure. The system-supplied function driver for parallel ports saves the information in the extension of the parallel port and returns the information in response to an IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO request.

For more information, see Obtaining Information About a Parallel Port.

See Also

IOCTL_INTERNAL_GET_MORE_PARALLEL_PORT_INFO, IOCTL_INTERNAL_GET_PARALLEL_PNP_INFO, IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO, MORE PARALLEL_PORT_INFORMATION, PARALLEL_PNP_INFORMATION


PAR_QUERY_INFORMATION

The PAR_QUERY_INFORMATION structure specifies the operating status of a parallel port.

typedef struct _PAR_QUERY_INFORMATION{
  UCHAR Status;
} PAR_QUERY_INFORMATION, *PPAR_QUERY_INFORMATION;

Members

Status
Specifies the operating status of a parallel port. The value of Status is a bitwise OR of one or more of the following flags:
PARALLEL_INIT
PARALLEL_AUTOFEED
PARALLEL_PAPER_EMPTY
PARALLEL_OFF_LINE
PARALLEL_POWER_OFF
PARALLEL_NOT_CONNECTED
PARALLEL_BUSY
PARALLEL_SELECTED

Headers

Defined in ntddpar.h. Include ntddpar.h.

Comments

This structure is used with an IOCTL_PAR_QUERY_INFORMATION request.

See Also

IOCTL_PAR_QUERY_INFORMATION, IOCTL_PAR_SET_INFORMATION, PAR_SET_INFORMATION


PAR_SET_INFORMATION

The PAR_SET_INFORMATION structure specifies the initial operating status of a parallel port.

typedef struct _PAR_SET_INFORMATION {
  UCHAR Init;
} PAR_SET_INFORMATION, *PPAR_SET_INFORMATION;

Members

Init
Specifies the operating status of the parallel port. Must be set to PARALLEL_INIT.

Headers

Defined in ntddpar.h. Include ntddpar.h.

Comments

This structure is used with an IOCTL_PAR_SET_INFORMATION request.

See Also

IOCTL_PAR_QUERY_INFORMATION, IOCTL_PAR_SET_INFORMATION, PAR_QUERY_INFORMATION


I/O Requests for Parallel Devices

This section describes the device-specific operations that the system-supplied bus driver for parallel ports does for the following I/O requests:

IRP_MJ_CREATE

IRP_MJ_DEVICE_CONTROL

IRP_MJ_INTERNAL_DEVICE_CONTROL

IRP_MJ_QUERY_INFORMATION

IRP_MJ_READ

IRP_MJ_WRITE

If an I/O request is not supported, the parallel port bus driver returns the status STATUS_NOT_SUPPORTED.

See the following for more information on how Windows generically handles major I/O requests:

Sample Parallel Drivers

IRP Function Codes and IOCTLs

Plug and Play IRPs

Power Management

WMI IRPs


IRP_MJ_CREATE

An IRP_MJ_CREATE request opens a parallel device.

When Sent

A client must open a parallel device before it can access the device.

Input Parameters

None

Output Parameters

None

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the following values:

STATUS_SUCCESS
The device was opened successfully.
STATUS_ACCESS_DENIED
The device is already open.
STATUS_DELETE_PENDING
The device is in a Plug and Play surprised-removed state.
STATUS_DEVICE_REMOVED
The device has been removed.
STATUS_INVALID_DEVICE_REQUEST
There is no hardware present.
STATUS_NOT_A_DIRECTORY
The device is not a directory.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Operation

A parallel device is an exclusive device. If a parallel device is open, the system-supplied bus driver for parallel ports fails any subsequent IRP_MJ_CREATE requests for the device until the device has been closed. A client must open a parallel device before it sends other I/O requests to the device or calls the parallel device callback routines.

For more information, see Opening and Using a Parallel Device.


IRP_MJ_DEVICE_CONTROL

A client uses device control requests for parallel devices to operate a parallel device.

When Sent

A client uses device control requests for the following types of operations:

  • Obtain information about a device
  • Set the operating mode of the device

Input Parameters

Request-specific

Output Parameters

Request-specific

I/O Status Block

The Information member is request-specific.

The Status member is set to a request-specific value or to one of following generic status values:

Generic Status Values Returned by Device Control Requests for Parallel Devices

STATUS_SUCCESS
The request completed successfully.
STATUS_CANCELLED
The request was cancelled.
STATUS_DELETE_PENDING
The device is in the process of being removed.
STATUS_DEVICE_REMOVED
The device has been removed.
STATUS_INVALID_PARAMETER
The system-supplied bus driver for parallel ports does not support the request.
STATUS_PENDING
The request is pending.
STATUS_UNSUCCESSFUL
The request did not complete successfully.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Operation

The operation is request-specific.

See Also

IRP_MJ_INTERNAL_DEVICE_CONTROL


IRP_MJ_INTERNAL_DEVICE_CONTROL

A client uses internal device control requests for parallel devices to operate a parallel device.

When Sent

A client uses internal device control requests for the following types of operations:

  • Set the parallel port's communication mode to IEEE 1284-compatible
  • Obtain connection information about a parallel port
  • Lock and unlock a parallel port for exclusive use by the device

Input Parameters

Request specific

Output Parameters

Request specific

I/O Status Block

The Information member is request specific.

The Status member is set to a request specific value or to one of following generic status values:

Generic Status Values Returned by Internal Device Control Requests for Parallel Devices

STATUS_SUCCESS
The request completed successfully.
STATUS_CANCELLED
The request was cancelled.
STATUS_DELETE_PENDING
The device is in the process of being removed.
STATUS_DEVICE_REMOVED
The device has been removed.
STATUS_INVALID_PARAMETER
The parallel bus driver does not support the request.
STATUS_PENDING
The request is pending.
STATUS_UNSUCCESSFUL
The request did not complete successfully.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Operation

The operation is request-specific.

See Also

IRP_MJ_DEVICE_CONTROL


IRP_MJ_QUERY_INFORMATION

The IRP_MJ_QUERY_INFORMATION request returns file information for a parallel device.

When Sent

A client sends a query information request to determine the file size or current byte offset of the file pointer.

Input Parameters

The Parameters.QueryFile.FileInformationClass member is set to FileStandardInformation or FilePositionInformation.

FileStandardInformation request
The AssociatedIrp.SystemBuffer member points to a FILE_STANDARD_INFORMATION structure that the client allocates for output of file information.

The Parameters.QueryFile.Length member is set to the size, in bytes, of a FILE_STANDARD_INFORMATION structure.

FilePositionInformation request
AssociatedIrp.SystemBuffer points to a FILE_POSITION_INFORMATION structure that the client allocates for output of file information.

The Parameters.SetFile.Length member is set to the size, in bytes, of a FILE_POSITION_INFORMATION structure.

Output Parameters

AssociatedIrp.SystemBuffer points to the requested information.

FileStandardInformation request type
Sets the following members in the FILE_STANDARD_INFORMATION structure:

AllocationSize.QuadPart set to zero.

EndOfFile is set to the value of the AllocationSize member.

NumberOfLinks is set to zero.

DeletePending is set to FALSE.

Directory is set to FALSE.

FilePositionInformation request type
Sets the CurrentByteOffset.QuadPart member of a FILE_POSITION_INFORMATION structure to zero.

I/O Status Block

If the request succeeds, the Information member is set to the size, in bytes, of the structure associated with the type of request. Otherwise, the Information member is set to zero.

The Status member is set to one of the following status values:
STATUS_SUCCESS
The request completed successfully.
STATUS_BUFFER_TOO_SMALL
The size, in bytes, of the structure, specified by the input parameter, is less than the size, in bytes, of the structure associated with the request type.
STATUS_DEVICE_REMOVED
The device has been removed.
STATUS_INVALID_PARAMETER
The specified type of information is not valid.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Operation

The system-supplied bus driver for parallel ports supports queries for the following types of information:

  • FileStandardInformation
  • FilePositionInformation


IRP_MJ_READ

A client used an IRP_MJ_READ request to transfer input data from a parallel device to the client.

When Sent

A client uses a read request whenever it requires input from a device.

Input Parameters

The Parameters.Read.Length member points to the number of bytes to read from the parallel device.

Output Parameters

The AssociatedIrp.SystemBuffer member points to a read buffer that the client allocates for the read data. The buffer must be large enough to hold the requested number of bytes.

I/O Status Block

The Information member is set to the number of bytes actually read from the parallel device.

The Status member is set to one of the following status values:

STATUS_SUCCESS
The request completed successfully.
STATUS_DELETE_PENDING
The device is in the process of being removed.
STATUS_CANCELLED
The request was cancelled.
STATUS_PENDING
The request is queued on a work queue for the parallel device.
STATUS_INVALID_PARAMETER
The Parameters.Write.ByteOffset member is not zero. Note that both read and write requests use this member.
STATUS_DEVICE_REMOVED
The device has been removed.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Operation

The system-supplied bus driver for parallel ports uses the read protocol set for the parallel device. The default read protocol is NIBBLE_MODE. A client can negotiate a read protocol by using an IOCTL_IEEE1284_NEGOTIATE request.

The parallel port bus driver sets a cancel routine for the read request, marks the read request as pending, and queues the read request on a work queue. The read request is held in the work queue in a state that can be canceled until the read request is either completed or canceled by the client.

For more information, see Reading and Writing a Parallel Device.

See Also

IRP_MJ_WRITE, ParallelRead, ParallelWrite, IOCTL_IEEE1284_NEGOTIATE


IRP_MJ_WRITE

A client used an IRP_MJ_WRITE request to transfer output data from the client to a parallel device.

When Sent

A client uses a write request whenever it transfers output data to a device.

Input Parameters

The AssociatedIrp.SystemBuffer points to a write buffer that the client allocates for write data. The buffer must be large enough to hold the requested number of bytes to write to the parallel device.

The Parameters.Write.Length member points to the number of bytes to write to the parallel device.

Output Parameters

None

I/O Status Block

The Information member is set to the number of bytes actually written to the parallel device.

The Status member is set to one of the following values:

STATUS_SUCCESS
The request completed successfully.
STATUS_DELETE_PENDING
The device is in the process of being removed.
STATUS_CANCELLED
The request was cancelled.
STATUS_PENDING
The request is queued on a work queue for the parallel device.
STATUS_INVALID_PARAMETER
The Parameters.Write.ByteOffset member is not zero.
STATUS_DEVICE_REMOVED
The device has been removed.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Operation

The system-supplied bus driver for parallel ports transfers data by using the write protocol that is set for the parallel device. The default write protocol is CENTRONICS_MODE. A client can negotiate a write protocol by using an IOCTL_IEEE1284_NEGOTIATE request.

The parallel port bus driver sets a cancel routine for the write request, marks the write request as pending, and queues the write request on a work queue. The write request is held in a state that can be canceled until the request is either completed or canceled.

For more information, see Reading and Writing a Parallel Device.

See Also

IRP_MJ_READ, ParallelRead, ParallelWrite


Device Control Requests for Parallel Devices

This section describes how the system-supplied bus driver for parallel ports handles the following device control requests:

IOCTL_IEEE1284_GET_MODE

IOCTL_IEEE1284_NEGOTIATE

IOCTL_PAR_GET_DEFAULT_MODES

IOCTL_PAR_GET_DEVICE_CAPS

IOCTL_PAR_IS_PORT_FREE

IOCTL_PAR_QUERY_DEVICE_ID

IOCTL_PAR_QUERY_DEVICE_ID_SIZE

IOCTL_PAR_QUERY_INFORMATION

IOCTL_PAR_QUERY_LOCATION

IOCTL_PAR_QUERY_RAW_DEVICE_ID

IOCTL_PAR_SET_INFORMATION

IOCTL_PAR_SET_READ_ADDRESS

IOCTL_PAR_SET_WRITE_ADDRESS

IOCTL_SERIAL_GET_TIMEOUTS

IOCTL_SERIAL_SET_TIMEOUTS

The system-supplied bus driver does not support any other device control requests.


IOCTL_IEEE1284_GET_MODE

Operation

The IOCTL_IEEE1284_GET_MODE request returns the IEEE 1284 read and write protocols that are currently set for a parallel device. This request does not require that the parallel port, to which the parallel device is attached, be locked.

For more information, see Setting and Clearing a Communication Mode for a Parallel Device.

Input

The Parameters.DeviceIoControl.OutputBufferLength member is set to the size, in bytes, of a PARCLASS_NEGOTIATION_MASK structure.

Output

The AssociatedIrp.SystemBuffer member points to a PARCLASS_NEGOTIATION_MASK structure that the client allocates to output mode information. The system-supplied bus driver for parallel ports specifies the read (reverse) protocol in the usReadMask member and the write (forward) protocol in the usWriteMask member.

I/O Status Block

If the request is successful, the Information member is set to the size, in bytes, of a PARCLASS_NEGOTIATION_MASK. Otherwise, the Information member is set to zero.

The Status member is set to one of the generic status values returned by device control requests for parallel devices or to the following value:

STATUS_BUFFER_TOO_SMALL
The value of Parameters.DeviceIoControl.OutputBufferLength is less than the size, in bytes, of a PARCLASS_NEGOTIATION_MASK structure.

Headers

Defined in ntddpar.h. Include ntddpar.h.

See Also

IOCTL_IEEE1284_NEGOTIATE, IOCTL_PAR_GET_DEFAULT_MODES, IOCTL_PAR_GET_DEVICE_CAPS, PARCLASS_NEGOTIATION_MASK


IOCTL_IEEE1284_NEGOTIATE

Operation

The IOCTL_IEEE1284_NEGOTIATE request sets the read and write protocols that are used for a parallel device. This request requires that the parallel port, to which the parallel device is attached, be locked and the parallel device be selected. The system-supplied bus driver for parallel ports negotiates with the parallel device to determine the fastest modes that are supported by both the host chipset and the parallel device from among the modes that are specified by the client. The parallel port bus driver sets the default read and write modes to the negotiated modes.

For more information, see Setting and Clearing a Communication Mode for a Parallel Device.

Input

The AssociatedIrp.SystemBuffer member points to a PARCLASS_NEGOTIATION_MASK structure that the client allocates for the input and output of mode information. The client sets the usReadMask and usWriteMask members.

The Parameters.DeviceIoControl.InputBufferLength member is set to the size, in bytes, of a PARCLASS_NEGOTIATION_MASK structure.

Output

The AssociatedIrp.SystemBuffer points to the PARCLASS_NEGOTIATION_MASK structure that the system-supplied bus driver for parallel ports uses to output mode information. The parallel port bus driver sets the usReadMask and usWriteMask members to the negotiated modes.

I/O Status Block

If request is successful, the Information member is set to the size, in bytes, of a PARCLASS_NEGOTIATION_MASK structure. Otherwise the Information member is set to zero.

The Status member is set to one of the generic status values returned by device control requests for parallel devices or to the following value:

STATUS_INVALID_PARAMETER
The value of the Parameters.DeviceIoControl.InputBufferLength member is less than the size, in bytes, of a PARCLASS_NEGOTIATION_MASK.

Headers

Defined in ntddpar.h. Include ntddpar.h.

See Also

IOCTL_IEEE1284_GET_MODE, IOCTL_PAR_GET_DEFAULT_MODES, IOCTL_PAR_GET_DEVICE_CAPS


IOCTL_PAR_GET_DEFAULT_MODES

Operation

The IOCTL_PAR_GET_DEFAULT_MODES request returns the default write (forward) and read (reverse) IEEE 1284 protocols that the system-supplied bus driver for parallel ports uses. The default write protocol is CENTRONICS_MODE; the default read protocol is NIBBLE.

For more information, see Setting and Clearing a Communication Mode for a Parallel Device.

Input

The value of the Parameters.DeviceIoControl.OutputBufferLength member is set to the size, in bytes, of a PARCLASS_NEGOTIATION_MASK structure.

Output

The AssociatedIrp.SystemBuffer member points to a PARCLASS_NEGOTIATION_MASK structure that the client allocates to output mode information. The system-supplied bus driver for parallel ports sets the usReadMask member and the usWriteMask member. The default write mode is CENTRONICS_MODE; the default read mode is NIBBLE.

I/O Status Block

If the request is successful, the Information member is set to the size, in bytes, of a PARCLASS_NEGOTIATION_MASK structure. Otherwise, Information is set to zero.

The Status member is set to one of the generic status values returned by device control requests for parallel devices or to the following value:

STATUS_BUFFER_TOO_SMALL
The value of the Parameters.DeviceIoControl.OutputBufferLength is less than the size, in bytes, of a PARCLASS_NEGOTIATION_MASK structure.

Headers

Defined in ntddpar.h. Include ntddpar.h.

See Also

IOCTL_IEEE1284_GET_MODE, IOCTL_IEEE1284_NEGOTIATE, IOCTL_PAR_GET_DEVICE_CAPS


IOCTL_PAR_GET_DEVICE_CAPS

Operation

The IOCTL_PAR_GET_DEVICE_CAPS request does the following:

  • Specifies the protocols that the system-supplied bus driver for parallel ports must not use with a parallel device
  • Returns the operating protocols that the parallel device supports

For more information, see Setting and Clearing a Communication Mode for a Parallel Device.

Input

The AssociatedIrp.SystemBuffer member points to a USHORT buffer that the client allocates to input and output mode information. The request sets the input buffer to a bitwise OR of the modes that the parallel port bus driver must not use with a parallel device.

The Parameters.DeviceIoControl.OutputBufferLength member is set to the size, in bytes, of a USHORT.

Output

AssociatedIrp.SystemBuffer points to the USHORT buffer that the parallel port bus driver uses to output mode information. The parallel port bus driver sets the buffer to indicate which operating protocols the parallel device supports.

I/O Status Block

The Information member is set to the size, in bytes, of a USHORT.

The Status member is set to one of the generic status values returned by device control requests for parallel devices or to the following value:

STATUS_BUFFER_TOO_SMALL
The Parameters.DeviceIoControl.OutputBufferLength member is less than the size, in bytes, of a USHORT.

Headers

Defined in ntddpar.h. Include ntddpar.h.

See Also

IOCTL_IEEE1284_GET_MODE, IOCTL_IEEE1284_NEGOTIATE


IOCTL_PAR_IS_PORT_FREE

Operation

The IOCTL_PAR_IS_PORT_FREE request determines if a parallel device's parent parallel port is free at the time the system-supplied bus driver for parallel ports processes the request. This request is provided primarily for user-mode clients.

This request is processed immediately after the I/O Manager calls the parallel port bus driver's dispatch routine for device control requests. Note, however, that the status of the parallel port can change between the time that the parallel port bus driver completes the request and the time that control returns to a user-mode client.

Kernel-mode clients can directly determine if a parallel port is free by calling the TryAllocatePort callback routine provided by the system-supplied function driver for parallel ports.

For more information, see Locking and Unlocking a Parallel Port for Use by a Parallel Device.

Input

None

Output

The AssociatedIrp.SystemBuffer member points to a BOOLEAN buffer that the client allocates to output the status of the parallel port. If the parallel port is free, The system-supplied function driver for parallel ports sets the buffer to TRUE, otherwise it sets the buffer to FALSE.

I/O Status Block

The Information member is set to the size, in bytes, of a BOOLEAN.

The Status member is set to one of the generic status values returned by device control requests for parallel devices or to the following value:

STATUS_BUFFER_TOO_SMALL
The Parameters.DeviceIoControl.OutputBufferLength member is less than the size, in bytes, of a BOOLEAN.

Headers

Defined in ntddpar.h. Include ntddpar.h.

See Also

IOCTL_INTERNAL_PARALLEL_PORT_FREE, IOCTL_INTERNAL_LOCK_PORT


IOCTL_PAR_QUERY_DEVICE_ID

Operation

The IOCTL_PAR_QUERY_DEVICE_ID request returns the IEEE 1284 device ID of a parallel device assigned by the system-supplied function driver for parallel ports.

Input

The Parameters.DeviceIoControl.OutputBufferLength member specifies the size, in bytes, of the output buffer that can hold both the device ID and a NULL terminator. A client can use an IOCTL_PAR_QUERY_DEVICE_ID_SIZE request to determine the required buffer size. A device ID can be up to 64 KB in size.

Output

The AssociatedIrp.SystemBuffer member points to a buffer that the client allocates to output the device ID. The buffer contains the device ID and a NULL terminator.

I/O Status Block

If the request is successful, the Information member is set to the size, in bytes, of a buffer that holds both the device ID and a NULL terminator. Otherwise, the Information member is set to zero.

The Status member is set to one of the generic status values returned by device control requests for parallel devices or to one of the following values:

STATUS_BUFFER_TOO_SMALL
The output buffer that AssociatedIrp.SystemBuffer points to is less than the size, in bytes, of the device ID and a NULL terminator.
STATUS_IO_DEVICE_ERROR
A device I/O error occurred.

Headers

Defined in ntddpar.h. Include ntddpar.h.

See Also

IOCTL_PAR_QUERY_DEVICE_ID_SIZE


IOCTL_PAR_QUERY_DEVICE_ID_SIZE

Operation

The IOCTL_PAR_QUERY_DEVICE_ID_SIZE request returns the size, in bytes, of a buffer that can hold a device's IEEE 1284 device ID and a NULL terminator.

Input

None

Output

The AssociatedIrp.SystemBuffer member points to a PAR_DEVICE_ID_SIZE_INFORMATION structure that the client allocates to output the device ID size information. The system-supplied bus driver for parallel ports sets the DeviceIdSize member of the output structure to the size, in bytes, of a buffer that can hold the device ID and a NULL terminator.

I/O Status Block

If the request is successful, the Information member is set to the size, in bytes, of a PAR_DEVICE_ID_SIZE_INFORMATION structure. Otherwise, the Information member is set to zero.

The Status member is set to one of the generic status values returned by device control requests for parallel devices or to STATUS_IO_DEVICE_ERROR

Headers

Defined in ntddpar.h. Include ntddpar.h.

See Also

IOCTL_PAR_QUERY_DEVICE_ID, PAR_DEVICE_ID_SIZE_INFORMATION


IOCTL_PAR_QUERY_INFORMATION

Operation

The IOCTL_PAR_QUERY_INFORMATION request returns the status of an IEEE 1284 end-of-chain device.

Input

The Parameters.DeviceIoControl.OutputBufferLength member is set to the size, in bytes, of a PAR_QUERY_INFORMATION structure.

Output

The AssociatedIrp.SystemBuffer member points to a PAR_QUERY_INFORMATION structure that the client allocates to output status information. The system-supplied bus driver for parallel ports sets the Status member to a bitwise OR of one or more of the following operating conditions:

PARALLEL_BUSY
PARALLEL_NOT_CONNECTED
PARALLEL_OFF_LINE
PARALLEL_PAPER_EMPTY
PARALLEL_POWER_OFF
PARALLEL_SELECTED

I/O Status Block

If the request is successful, the Information member is set to the size, in bytes, of a PAR_QUERY_INFORMATION structure. Otherwise, the Information is set to zero.

The Status member is set to one of the generic status values returned by device control requests for parallel devices or to the following value:

STATUS_BUFFER_TOO_SMALL
The value of the Parameters.DeviceIoControl.OutputBufferLength member is less than the size, in bytes, of a PAR_QUERY_INFORMATION structure.

Headers

Defined in ntddpar.h. Include ntddpar.h.

See Also

IOCTL_PAR_QUERY_LOCATION, PAR_QUERY_INFORMATION


IOCTL_PAR_QUERY_LOCATION

Operation

The IOCTL_PAR_QUERY_LOCATION request returns the "LPTn" or "LPTn.m" symbolic link name associated with a parallel device. This request is only supported by Windows XP and later.

For more information, see Device Stacks for Parallel Ports and Devices and Parallel Device Interfaces, Internal Names, and Symbolic Links.

Input

The client sets the AssociatedIrp.SystemBuffer member to a pointer to a character buffer for the location information.

The client sets the Parameters.DeviceIoControl.OutputBufferLength member to the length of the output buffer that the system-supplied bus driver for parallel ports uses to output the device location information.

Output

The parallel port bus driver outputs the location information in the buffer pointed to by AssociatedIrp.SystemBuffer as a NULL-terminated character string.

I/O Status Block

If the request succeeds, the Information member is set to the length, in bytes, of the symbolic link name plus the NULL terminator. Otherwise, Information is set to zero.

The Status member is set to one of the generic status values returned by device control requests for parallel devices or to the following value:

STATUS_BUFFER_TOO_SMALL
The Parameters.DeviceIoControl.OutputBufferLength member is less than size, in bytes, of the location information and the NULL terminator.

Headers

Defined in ntddpar.h. Include ntddpar.h.

See Also

IOCTL_PAR_QUERY_DEVICE_ID


IOCTL_PAR_QUERY_RAW_DEVICE_ID

Operation

The IOCTL_PAR_QUERY_RAW_DEVICE_ID request returns a raw device ID, which includes the following: a two-byte prefix that specifies the size, in bytes, of the device's IEEE 1284 device ID; the IEEE 1284 device ID; and a NULL terminator.

Input

The Parameters.DeviceIoControl.OutputBufferLength member specifies the size, in bytes, of the output buffer that can hold the following: a two-byte prefix that specifies the size, in bytes, of the device's IEEE 1284 device ID; the device ID; and a NULL terminator. An IEEE 1284 device ID can be up to 64 KB in size.

Output

The AssociatedIrp.SystemBuffer member points to a buffer that the client allocates to output a raw device ID. The buffer contains the following contiguous sequence of information: a two-byte prefix that specifies the size, in bytes, of the device's IEEE 1284 device ID; the device ID; and a NULL terminator.

I/O Status Block

If the request is successful, the Information member is set to the size, in bytes, of the information returned in the output buffer. Otherwise, the Information member is set to zero.

The Status member is set to one of the generic status values returned by device control requests for parallel devices or to one of the following values:

STATUS_BUFFER_TOO_SMALL
The output buffer that AssociatedIrp.SystemBuffer points to is less than the size, in bytes, of a two-byte prefix, the IEEE 1284 device ID, and a NULL terminator.
STATUS_IO_DEVICE_ERROR
A device I/O error occurred.

Headers

Defined in ntddpar.h. Include ntddpar.h.

See Also

IOCTL_PAR_QUERY_DEVICE_ID, IOCTL_PAR_QUERY_DEVICE_ID_SIZE


IOCTL_PAR_SET_INFORMATION

Operation

The IOCTL_PAR_SET_INFORMATION request resets and initializes a parallel device.

Input

The AssociatedIrp.SystemBuffer member points to a PAR_SET_INFORMATION structure that the client allocates to input set information. The client sets the Init member to PARALLEL_INIT.

The Parameters.DeviceIoControl.InputBufferLength member is set to the size, in bytes, of a PAR_SET_INFORMATION structure.

Output

None

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values returned by device control requests for parallel devices or to one of the following values:

STATUS_BUFFER_TOO_SMALL
Parameters.DeviceIoControl.InputBufferLength is less than the size, in bytes, of a PAR_SET_INFORMATION structure.
STATUS_DEVICE_NOT_CONNECTED
The device is not connected.
STATUS_DEVICE_OFF_LINE
The device is offline.
STATUS_DEVICE_PAPER_EMPTY
The device is out of paper.
STATUS_DEVICE_POWERED_OFF
The device is not turned on.

Headers

Defined in ntddpar.h. Include ntddpar.h.

See Also

IOCTL_PAR_QUERY_INFORMATION


IOCTL_PAR_SET_READ_ADDRESS

Operation

The IOCTL_PAR_SET_READ_ADDRESS request sets an extended capabilities port (ECP) or enhanced parallel port (EPP) read address (channel) for a parallel device.

Input

The AssociatedIrp.SystemBuffer member points to a UCHAR buffer that the client allocates to input a read address. The request sets the buffer to an ECP or EPP read address.

Parameters.DeviceIoControl.InputBufferLength member is set to the size, in bytes, of a UCHAR.

Output

None

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values returned by device control requests for parallel devices or to the following value:

STATUS_INVALID_PARAMETER
Parameters.DeviceIoControl.InputBufferLength is less than the size, in bytes, of a UCHAR.

Headers

Defined in ntddpar.h. Include ntddpar.h.

See Also

IOCTL_PAR_SET_WRITE_ADDRESS


IOCTL_PAR_SET_WRITE_ADDRESS

The IOCTL_PAR_SET_WRITE_ADDRESS request sets an extended capabilities port (ECP) or enhanced parallel port (EPP) write address (channel) for a parallel device. The parallel port bus driver queues this request on a work queue for the parallel device.

Input

The AssociatedIrp.SystemBuffer member points to a UCHAR buffer that the client allocates to input a write address. The client sets the buffer to an ECP or EPP write address.

Parameters.DeviceIoControl.InputBufferLength member is set to the size, in bytes, of a UCHAR.

Output

None

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values returned by device control requests for parallel devices or to the following value:

STATUS_INVALID_PARAMETER
Parameters.DeviceIoControl.InputBufferLength is less than the size, in bytes, of a UCHAR.

Headers

Defined in ntddpar.h. Include ntddpar.h.

See Also

IOCTL_PAR_SET_READ_ADDRESS


IOCTL_SERIAL_GET_TIMEOUTS

Operation

The IOCTL_SERIAL_GET_TIMEOUTS request returns the current setting of the timeout value that the system-supplied bus driver for parallel ports uses with write requests. The parallel port bus driver does not queue a get timeouts request. The write timeout value is used with SPP and SW_ECP modes.

A client uses an IOCTL_SERIAL_SET_TIMEOUTS request to set timeout values.

Input

The Parameters.DeviceIoControl.OutputBufferLength member is set to the size, in bytes, of a SERIAL_TIMEOUTS structure.

Output

The AssociatedIrp.SystemBuffer points to a SERIAL_TIMEOUTS structure that the client allocates to output timeout information. The parallel port bus driver sets the WriteTotalTimeoutConstant member to the timeout value in milliseconds.

I/O Status Block

If the request is successful, the Information member is set to the size, in bytes, of a SERIAL_TIMEOUTS structure. Otherwise, the Information member is set to zero.

The Status member is set to one of the generic status values returned by device control requests for parallel devices or to the following value:

STATUS_BUFFER_TOO_SMALL
The value of the Parameters.DeviceIoControl.OutputBufferLength member is less than the size, in bytes, of a SERIAL_TIMEOUTS structure.

Headers

Defined in ntddser.h. Include ntddser.h.

See Also

IOCTL_SERIAL_SET_TIMEOUTS


IOCTL_SERIAL_SET_TIMEOUTS

Operation

An IOCTL_SERIAL_SET_TIMEOUTS request resets the timeout value that the system-supplied bus driver for parallel ports uses with write requests. The write timeout value is used with SPP and SW_ECP modes. The parallel port bus driver queues a set timeout request on a work queue for the parallel device.

A client uses an IOCTL_SERIAL_GET_TIMEOUTS to obtain the timeout values.

Input

The AssociatedIrp.SystemBuffer points to a SERIAL_TIMEOUTS structure that the client allocates to input timeout information. The client sets the WriteTotalTimeoutConstant member to a value in milliseconds.

The Parameters.DeviceIoControl.OutputBufferLength member is set to the size, in bytes, of a SERIAL_TIMEOUTS structure.

Output

None

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values returned by device control requests for parallel devices or to one of the following values:

STATUS_BUFFER_TOO_SMALL
The value of the Parameters.DeviceIoControl.InputBufferLength member is less than the size, in bytes, of a SERIAL_TIMEOUTS structure.
STATUS_INVALID_PARAMETER
The requested timeout value is less than two seconds.

Headers

Defined in ntddser.h. Include ntddser.h.

See Also

IOCTL_SERIAL_GET_TIMEOUTS


Internal Device Control Requests for Parallel Devices

This section describes how the system-supplied bus driver for parallel ports handles the following internal device control requests:

IOCTL_INTERNAL_DISCONNECT_IDLE

IOCTL_INTERNAL_LOCK_PORT

IOCTL_INTERNAL_LOCK_PORT_NO_SELECT

IOCTL_INTERNAL_PARCLASS_CONNECT

IOCTL_INTERNAL_PARCLASS_DISCONNECT

IOCTL_INTERNAL_UNLOCK_PORT

IOCTL_INTERNAL_UNLOCK_PORT_NO_DESELECT

The system-supplied bus driver does not support any other internal device control requests.


IOCTL_INTERNAL_DISCONNECT_IDLE

Operation

The IOCTL_INTERNAL_DISCONNECT_IDLE request disconnects the IEEE 1284 operating modes that are set for a parallel device. The system-supplied bus driver for parallel ports sets the default operating mode to IEEE 1284-compatible.

For more information, see Setting and Clearing a Communication Mode for a Parallel Device.

Input

None

Output

None

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values returned by internal device control requests for parallel devices.

Headers

Defined in parallel.h. Defined in parallel.h.

See Also

IOCTL_IEEE1284_GET_MODE, IOCTL_IEEE1284_NEGOTIATE, IOCTL_PAR_GET_DEFAULT_MODES, IOCTL_PAR_GET_DEVICE_CAPS


IOCTL_INTERNAL_LOCK_PORT

Operation

The IOCTL_INTERNAL_LOCK_PORT request allocates the parallel device's parent parallel port and selects the parallel device on the port.

For more information, see Locking and Unlocking a Parallel Port for Use by a Parallel Device.

Input

None

Output

None

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values returned by internal device control requests for parallel devices.

Headers

Defined in parallel.h. Defined in parallel.h.

See Also

IOCTL_INTERNAL_LOCK_PORT_NO_SELECT, IOCTL_INTERNAL_UNLOCK_PORT, IOCTL_INTERNAL_UNLOCK_PORT_NO_DESELECT


IOCTL_INTERNAL_LOCK_PORT_NO_SELECT

Operation

The IOCTL_INTERNAL_LOCK_PORT_NO_SELECT request allocates the parallel device's parent parallel port, but does not select the parallel device.

This request is only supported in Windows XP and later.

For more information, see Locking and Unlocking a Parallel Port for Use by a Parallel Device.

Input

None

Output

None

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values returned by internal device control requests for parallel devices.

Headers

Defined in parallel.h. Defined in parallel.h.

See Also

IOCTL_INTERNAL_LOCK_PORT, IOCTL_INTERNAL_UNOCK_PORT, IOCTL_INTERNAL_UNLOCK_PORT_NO_DESELECT


IOCTL_INTERNAL_PARCLASS_CONNECT

Operation

The IOCTL_INTERNAL_PARCLASS_CONNECT request returns information about a parallel port and the callback routines that the system-supplied bus driver for parallel ports provides to operate the parallel port.

For more information, see Connecting to a Parallel Device.

Input

The value of the Parameters.DeviceIoControl.OutputBufferLength member is set to the size, in bytes, of a PARCLASS_INFORMATION structure.

Output

The AssociatedIrp.SystemBuffer member points to a PARCLASS_INFORMATION structure that the client allocates to output information.

I/O Status Block

If the request is successful, the Information member is set to the size, in bytes, of a PARCLASS_INFORMATION structure. Otherwise, the Information member is set to zero.

The Status member is set to one of the generic status values returned by internal device control requests for parallel devices or to the following value:

STATUS_BUFFER_TOO_SMALL
The value of the Parameters.DeviceIoControl.OutputBufferLength member is less than the size, in bytes, of a PARCLASS_INFORMATION structure.

Headers

Defined in parallel.h. Defined in parallel.h.

See Also

IOCTL_INTERNAL_PARCLASS_DISCONNECT, PARCLASS_INFORMATION


IOCTL_INTERNAL_PARCLASS_DISCONNECT

Operation

The IOCTL_INTERNAL_PARCLASS_DISCONNECT request disconnects a client from a parallel device. After disconnecting from a parallel device, a client must not use any information obtained from a previous IOCTL_INTERNAL_PARCLASS_CONNECT request.

For more information, see Connecting to a Parallel Device.

Input

None

Output

None

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values returned by internal device control requests for parallel devices.

Headers

Defined in parallel.h. Defined in parallel.h.

See Also

IOCTL_INTERNAL_PARCLASS_CONNECT


IOCTL_INTERNAL_UNLOCK_PORT

Operation

The IOCTL_INTERNAL_UNLOCK_PORT request deselects a parallel device and frees the parallel device's parent parallel port.

For more information, see Locking and Unlocking a Parallel Port for Use by a Parallel Device.

Input

None

Output

None

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values returned by internal device control requests for parallel devices.

Headers

Defined in parallel.h. Defined in parallel.h.

See Also

IOCTL_INTERNAL_LOCK_PORT, IOCTL_INTERNAL_LOCK_PORT_NO_SELECT, IOCTL_INTERNAL_UNLOCK_PORT_NO_DESELECT


IOCTL_INTERNAL_UNLOCK_PORT_NO_DESELECT

Operation

The IOCTL_INTERNAL_UNLOCK_PORT_NO_DESELECT_DEVICE request frees a parallel device's parent parallel port. The request does not deselect the parallel device on the parallel port.

This request is only supported in Windows XP and later.

For more information, see Locking and Unlocking a Parallel Port for Use by a Parallel Device.

Input

None

Output

None

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values returned by internal device control requests for parallel devices.

Headers

Defined in parallel.h. Defined in parallel.h.

See Also

IOCTL_INTERNAL_LOCK_PORT, IOCTL_INTERNAL_LOCK_PORT_NO_SELECT, IOCTL_INTERNAL_UNLOCK_PORT


Parallel Device Callback Routines

This section describes the callback routines supported by the system-supplied bus driver for parallel ports. A client can use these callbacks to operate a parallel device attached to a parallel port. Note that some of the callback routines have equivalent device control requests, which are preferred over using the following callback routines:

DetermineIeeeModes

IeeeFwdToRevMode

IeeeRevToFwdMode

NegotiateIeeeMode

ParallelRead

ParallelWrite

TerminateIeeeMode


DetermineIeeeModes

DetermineIeeeModes determines which IEEE 1284 protocols that a parallel device supports.

USHORT
  *DetermineIeeeModes(
    IN PDEVICE_EXTENSION Extension
    )

Parameters

Extension
Pointer to a device extension of a parallel device's physical device object (PDO).

Return Value

The return value indicates which protocols a parallel device supports. The return value is a bitwise OR of one or more of the following constants:

BOUNDED_ECP
ECP_HW_NOIRQ
EPP_HW
EPP_SW
ECP_SW
IEEE_COMPATIBILITY
CENTRONICS
NONE

These constants represent the protocols that the system-supplied bus driver for parallel ports supports. The protocols are listed in order of decreasing data transfer rate.

Headers

Defined in parallel.h. Include parallel.h.

Comments

The DetermineIeeeModes callback routine runs in the caller's thread at the IRQL of the caller.

See Also

IOCTL_IEEE1284_GET_MODE, IOCTL_IEEE1284_NEGOTIATE, IOCTL_PAR_GET_DEFAULT_MODES, IeeeRevToFwdMode, IeeeRevToFwdMode, NegotiateIeeeMode, TerminateIeeeMode


IeeeFwdToRevMode

IeeeFwdToRevMode changes the transfer mode from forward to reverse.

NTSTATUS
  *IeeeFwdToRevMode(
    IN PDEVICE_EXTENSION Extension
    )

Parameters

Extension
Pointer to a device extension of a parallel device's physical device object (PDO).

Return Value

STATUS_SUCCESS
The transfer mode was changed from forward to reverse.
STATUS_Xxx
An internal operation resulted in an NTSTATUS error.

Headers

Defined in parallel.h. Include parallel.h.

Comments

If the device is connected and in the reverse mode, the IeeeFwdToRevMode returns without further processing. Otherwise, IeeeFwdToRevMode puts the parallel device into reverse mode and connects a previously negotiated reverse protocol. NegotiateIeeeMode can be used to negotiate the reverse protocol.

IeeeFwdToRevMode runs in the caller's thread at the IRQL of the caller.

See Also

DetermineIeeeModes, IOCTL_IEEE1284_GET_MODE, IOCTL_IEEE1284_NEGOTIATE, IOCTL_PAR_GET_DEFAULT_MODES, IeeeRevToFwdMode, NegotiateIeeeMode, TerminateIeeeMode


IeeeRevToFwdMode

IeeeRevToFwdMode changes the transfer mode from reverse to forward.

NTSTATUS
  *IeeeRevToFwdMode(
    IN PDEVICE_EXTENSION Extension
    )

Parameters

Extension
Pointer to a device extension of a parallel device's physical device object (PDO).

Return Value

STATUS_SUCCESS
The transfer mode was changed from reverse to forward.
STATUS_Xxx
An internal operation resulted in an NTSTATUS error.

Headers

Defined in parallel.h. Include parallel.h.

Comments

If the device is connected and is in the forward mode, IeeeRevToFwdMode returns without further processing. Otherwise, IeeeRevToFwdMode puts a parallel device in the forward mode and connects a previously negotiated forward protocol. NegotiateIeeeMode can be used to negotiate a forward protocol.

IeeeRevToFwdMode runs in the caller's thread at the IRQL of the caller.

See Also

DetermineIeeeModes, IOCTL_IEEE1284_GET_MODE, IOCTL_IEEE1284_NEGOTIATE, IOCTL_PAR_GET_DEFAULT_MODES, IeeeFwdToRevMode, NegotiateIeeeMode, TerminateIeeeMode


NegotiateIeeeMode

NegotiateIeeeMode selects the fastest forward and reverse protocols that the system-supplied bus driver for parallel ports supports from among those specified by the caller.

NTSTATUS
  *NegotiateIeeeMode(
    IN PDEVICE_EXTENSION Extension,
    IN USHORT ModeMaskFwd,
    IN USHORT ModeMaskRev,
    IN PARALLEL_SAFETY ModeSafety,
    IN BOOLEAN IsForward
    )

Parameters

Extension
Pointer to the device extension of a parallel device's physical device object (PDO).
ModeMaskFwd
Specifies the forward protocols. ModeMaskFwd is a bitwise OR of the constants that represent the protocols that the parallel port bus driver supports.
ModeMaskRev
Specifies the reverse protocols. ModeMaskRev is a bitwise OR of the constants that represent the protocols that the parallel port bus driver supports.
ModeSafety
Specifies the safety mode. Must be set to SAFE_MODE.
IsForward
Specifies whether to connect the forward or the reverse protocol that the routine negotiates. If IsForward is TRUE, the forward protocol is connected. Otherwise, the reverse protocol is connected.

Return Value

STATUS_SUCCESSFUL
The IEEE mode was successfully negotiated.
STATUS_DEVICE_PROTOCOL_ERROR
An IEEE mode is already set on the device.
STATUS_Xxx
An internal operation resulted in an NTSTATUS error.

Headers

Defined in parallel.h. Include parallel.h.

Comments

NegotiateIeeeMode runs in the caller's thread at the IRQL of the caller.

See Also

DetermineIeeeModes, IOCTL_IEEE1284_GET_MODE, IOCTL_IEEE1284_NEGOTIATE, IOCTL_PAR_GET_DEFAULT_MODES, IeeeFwdToRevMode, IeeeRevToFwdMode, TerminateIeeeMode


ParallelRead

ParallelRead reads data from a parallel device.

NTSTATUS
  *ParallelRead(
    IN PDEVICE_EXTENSION Extension,
    IN PVOID Buffer,
    IN ULONG NumBytesToRead,
    OUT PULONG NumBytesRead,
    IN UCHAR Channel
    )

Parameters

Extension
Pointer to the device extension of a parallel device's physical device object (PDO).
Buffer
Pointer to a read buffer that the caller allocates.
NumBytesToRead
Specifies the number of bytes to read.
NumBytesRead
Specifies the number of bytes that were actually copied from the parallel device to the caller's read buffer.
Channel
Not used.

Return Value

STATUS_SUCCESS
The requested data was successfully transferred from the device.
STATUS_Xxx
An internal operation resulted in an NTSTATUS error.

Headers

Defined in parallel.h. Include parallel.h.

Comments

A client can only use this routine if it has a lock on a parallel port. A client obtains a lock on a parallel port by using an IOCTL_INTERNAL_LOCK_PORT request.

ParallelRead runs in the caller's thread at the IRQL of the caller.

See Also

ParallelWrite, IOCTL_INTERNAL_LOCK_PORT


ParallelWrite

ParallelWrite writes data to a parallel device.

NTSTATUS
  *ParallelWrite(
    IN PDEVICE_EXTENSION Extension,
    OUT PVOID Buffer,
    IN ULONG NumBytesToWrite,
    OUT PULONG NumBytesWritten,
    IN UCHAR Channel
    )

Parameters

Extension
Pointer to the device extension of a parallel device's physical device object (PDO).
Buffer
Pointer to a write buffer that the caller allocates.
NumBytesToWrite
Specifies the number of bytes to copy from the write buffer to the parallel device.
NumBytesWritten
Specifies the number of bytes that were actually copied from the caller's write buffer to the parallel device.
Channel
Not used.

Return Value

STATUS_SUCCESS
The caller-supplied data was successfully transferred to the device.
STATUS_Xxx
An internal operation resulted in an NTSTATUS error.

Headers

Defined in parallel.h. Include parallel.h.

Comments

A client can only use this routine if it has a lock on a parallel port. A client obtains a lock on a parallel port by using an IOCTL_INTERNAL_LOCK_PORT request.

ParallelWrite runs in the caller's thread at the IRQL of the caller.

See Also

ParallelRead, IOCTL_INTERNAL_LOCK_PORT


TerminateIeeeMode

TerminateIeeeModes terminates the current IEEE operating mode and sets the mode to IEEE 1284-compatible.

NTSTATUS
  *TerminateIeeeMode(
    IN PDEVICE_EXTENSION Extension
    )

Parameters

Extension
Pointer to the device extension of a parallel device's physical device object (PDO).

Return Value

STATUS_SUCCESS
The operating mode was set to IEEE 1284-compatible mode.

Headers

Defined in parallel.h. Include parallel.h.

Comments

TerminateIeeeModes runs in the caller's thread at the IRQL of the caller.

For more information, see Setting and Clearing a Communication Mode for a Parallel Device.

See Also

DetermineIeeeModes, IOCTL_IEEE1284_GET_MODE, IOCTL_IEEE1284_NEGOTIATE, IOCTL_PAR_GET_DEFAULT_MODES, IeeeFwdToRevMode, IeeeRevToFwdMode, NegotiateIeeeMode


Parallel Device Data Types

This section describes the following data types that the system-supplied bus driver for parallel ports uses to input and output information for a parallel device attached to a parallel port:

PAR_DEVICE_ID_SIZE_INFORMATION

PARCLASS_INFORMATION

PARCLASS_NEGOTIATION_MASK


PAR_DEVICE_ID_SIZE_INFORMATION

The PAR_DEVICE_ID_SIZE_INFORMATION structure specifies the size, in bytes, of a buffer that can hold the IEEE 1284 device ID of a parallel device and a NULL terminator.

typedef struct _PAR_DEVICE_ID_SIZE_INFORMATION {
  ULONG  DeviceIdSize;
} PAR_DEVICE_ID_SIZE_INFORMATION, *PPAR_DEVICE_ID_SIZE_INFORMATION;

Members

DeviceIdSize
Specifies the size, in bytes, of a buffer that can hold the IEEE 1284 device ID of a parallel device and a NULL terminator.

Headers

Defined in ntddpar.h. Include ntddpar.h.

See Also

IOCTL_PAR_QUERY_DEVICE_ID, IOCTL_PAR_QUERY_DEVICE_ID_SIZE


PARCLASS_INFORMATION

The PARCLASS_INFORMATION structure specifies information about a parallel port, pointers to callback routines to operate a parallel port, and pointers to callback routines to read and write to a parallel device.

typedef struct _PARCLASS_INFORMATION {
  PUCHAR  Controller;
  ULONG  SpanOfController;
  PDETERMINE_IEEE_MODES  DetermineIeeeModes;
  PNEGOTIATE_IEEE_MODE  NegotiateIeeeMode;
  PTERMINATE_IEEE_MODE  TerminateIeeeMode;
  PPARALLEL_IEEE_FWD_TO_REV  IeeeFwdToRevMode;
  PPARALLEL_IEEE_REV_TO_FWD  IeeeRevToFwdMode;
  PPARALLEL_READ  ParallelRead;
  PPARALLEL_WRITE  ParallelWrite;
  PVOID  ParclassContext;
  ULONG  HardwareCapabilities;
  ULONG  FifoDepth;
  ULONG  FifoWidth;
} PARCLASS_INFORMATION, *PPARCLASS_INFORMATION;

Members

Controller
Specifies the base I/O address allocated to a parallel port.
SpanOfController
Specifies the range in bytes of I/O address space allocated to a parallel port.
DetermineIeeeModes
Pointer to a callback routine that determines which IEEE protocols a parallel device supports.
NegotiateIeeeMode
Pointer to a callback routine that negotiates the fastest protocol that the system-supplied bus driver for parallel ports supports from among those specified by the caller.
TerminateIeeeMode
Pointer to a callback routine that terminates the current IEEE mode and sets the mode to IEEE_COMPATIBILITY.
IeeeFwdToRevMode
Pointer to a callback routine that changes the transfer mode from forward to reverse.
IeeeRevToFwdMode
Pointer to a callback routine that changes the transfer mode from reverse to forward.
ParallelRead
Pointer to a callback routine that a client can use to read from a parallel device.
ParallelWrite
Pointer to a callback routine that a client can use to write to a parallel device.
ParclassContext
Pointer to the device extension of a parallel device's physical device object (PDO).
HardwareCapabilities
Specifies which hardware capabilities are present. HardwareCapabilities is a bitwise OR of one or more of the following flags:
PPT_NO_HARDWARE_PRESENT
PPT_ECP_PRESENT
PPT_EPP_PRESENT
PPT_EPP_32_PRESENT
32-bit reads and writes are supported.
PPT_BYTE_PRESENT
PPT_BIDI_PRESENT
PPT_1284_3_PRESENT
FifoDepth
Specifies the size, in words, of the ECP FIFO. The ECP FIFO word size, in bits, is the value of FifoWidth.
FifoWidth
Specifies the ECP FIFO word size, in bits, which is the number of bits handled in parallel.

Headers

Defined in parallel.h. Include parallel.h.

Comments

A kernel-mode driver can obtain this information from the system-supplied bus driver for parallel ports using an IOCTL_INTERNAL_PARCLASS_CONNECT request. A client uses this information to operate a parallel port and to read and write a parallel device. The callback routines can only be used by a driver that holds a lock on the parent parallel port. A driver obtains a lock by using an IOCTL_INTERNAL_LOCK_PORT request.

For more information, see Connecting to a Parallel Device.

See Also

IOCTL_INTERNAL_PARCLASS_CONNECT, IOCTL_INTERNAL_LOCK_PORT


PARCLASS_NEGOTIATION_MASK

The PARCLASS_NEGOTIATION_MASK structure specifies the read and write protocols that a driver selects for a parallel device.

typedef struct _PARCLASS_NEGOTIATION_MASK {
  USHORT  usReadMask;
  USHORT  usWriteMask;
} PARCLASS_NEGOTIATION_MASK, *PPARCLASS_NEGOTIATION_MASK;

Members

usReadMask
Specifies the read protocols.
usWriteMask
Specifies the write protocols.

Headers

Defined in ntddpar.h. Include ntddpar.h.

Comments

A client specifies a set of requested protocols by setting a bitwise OR of the constants that represent each protocol. The system-supplied bus driver for parallel ports selects the fastest protocol that it supports from among those specified by the client.

For more information, see Setting and Clearing a Communication Mode for a Parallel Device.

See Also

DetermineIeeeModes, IOCTL_IEEE1284_GET_MODE, IOCTL_IEEE1284_NEGOTIATE, IOCTL_PAR_GET_DEFAULT_MODES, NegotiateIeeeMode


Serial Devices and Drivers

This chapter includes the following topics about Serial and Serenum, the Microsoft® Windows® 2000 and later system drivers for serial devices:

Features of Serial and Serenum

Configuration of Serial Devices and Drivers

Operation of Serial and Serenum

Registry Settings for Serial

Registry Settings for Serenum

See the following topics for more information on the operation of Serial and Serenum:

  • Serial Driver Reference
  • Serenum Driver Reference
  • Sample code in the directories %user install directory%\src\kernel\serial and %user install directory%\src\kernel\serenum in the Windows 2000 DDK
  • Data definitions in the include file %install directory%\inc\ntddser.h in the Windows 2000 DDK
  • Microsoft Win32® Communications API

    The documentation of the Win32 Communications API in the Platform SDK describes the highlevel operation of COM ports.


Features of Serial and Serenum

This section describes the features of Serial and Serenum, the Microsoft® Windows® 2000 and later system drivers for serial devices.

Serial implements the Serial service, and its executable image is serial.sys.

Serial is used as:

  • A function driver for legacy COM and Plug and Play COM ports

    Note that a COM port provides a 16550 UART-compatible interface.

  • A lower-level device filter driver for a Plug and Play serial device that requires a 16550 UART-compatible interface

    An example of this configuration is a serial device on a PCMCIA card.

    Serial's operation as a filter driver is identical to its operation as a function driver.

Serial features the following:

  • Plug and Play, power management, and Windows Management Instrumentation (WMI)
  • Power policy owner for a serial device stack that includes Serial
  • Supports an unlimited number of standalone COM ports and multiport boards
  • Controls interrupts and communication with device hardware

Serenum implements the Serenum service, and its executable image is serenum.sys.

Serenum is an upper-level device filter driver that is used with serial port function drivers to enumerate the following serial devices on an RS-232 port:

  • Plug and Play serial devices that comply with Plug and Play External COM Device Specification, Version 1.00, February 28, 1995
  • Pointer devices that comply with legacy mouse detection in Microsoft Windows NT® 4.0 and earlier versions

The combined operation of Serial and Serenum provides the function of a Plug and Play bus driver for an RS-232 port.

Serenum supports Plug and Play and power management.

Serenum does not support the Windows Driver Model, and should only be used with Windows 2000.

Windows 2000 provides Serenum to support Serial and other serial port function drivers that need to enumerate an RS-232 port. Hardware vendors do not have to create their own enumerator for RS-232 ports. For example, a device driver can use Serenum to enumerate the serial devices that are attached to the individual RS-232 ports on a multiport device.


Configuration of Serial Devices and Drivers

This section describes the following configurations of devices and drivers that Serial and Serenum support:

A non-Plug and Play serial device is connected to an RS-232 port.

A Plug and Play serial device is connected to an RS-232 port.

A Plug and Play serial device that requires a 16550 UART-compatible interface is not connected to an RS-232 port.

A Plug and Play serial device that requires a 16550 UART-compatible interface is one device on a multi-function device, and is not connected to an RS-232 port.


Non-Plug and Play Serial Device Connected to an RS-232 Port

This section describes the typical configuration of hardware, drivers, and device stacks for legacy serial devices that are connected to an RS-232 port.

The following figure shows the typical configuration for a non-Plug and Play Toaster device.

Left Figure: Hardware Configuration for a Non-Plug and Play Toaster Device Connected to an RS-232 Port

Right Figure: Configuration of Drivers and Device Stacks for a Non-Plug and Play Toaster Device Connected to an RS-232 Port

Serenum is not used to install a non-Plug and Play serial device. The installation of the Toaster device stack is device-specific. To communicate with the Toaster device, the Toaster driver opens the COM port that is associated with an RS-232 port.


Plug and Play Serial Device Connected to an RS-232 Port

This section describes the typical configuration of hardware, drivers, and device stacks for Plug and Play serial devices and legacy pointer devices that are connected to an RS-232 port. This configuration can be used to support serial devices such as: mouse devices, pointing devices, graphic tablets, modems, and digital cameras.

The following figure shows the typical configuration for a Toaster device.

Left Figure: Hardware Configuration for a Plug and Play Toaster Device Connected to an RS-232 Port

Right Figure: Configuration of Drivers and Device Stacks for a Plug and Play Toaster Device Connected to an RS-232 Port

Serial and Serenum are used in this configuration. Serial creates and attaches a function device object (FDO) to the RS-232 port stack. Serenum creates and attaches an upper-level filter DO to the RS-232 port stack. Serenum enumerates the device attached to the RS-232 port after the Plug and Play Manager sends an IRP_MN_QUERY_RELATIONS request of type BusRelations to the RS-232 device stack.

After Serenum detects a supported device, it creates a physical device object (PDO) for the device and reports the device to the Plug and Play Manager. The Configuration Manager uses the INF file and installers for the Toaster device to complete the installation of the Toaster device. A Toaster driver creates an FDO and attaches it to the Toaster device stack. Filter DOs can also be added to the Toaster device stack.


Plug and Play Serial Device that Requires a 16550 UART-Compatible Interface

This section describes the typical configuration of hardware, drivers, and device stacks that is used for serial devices that:

  • Support Plug and Play
  • Require a 16550 UART-compatible interface
  • Are not connected to an RS-232 port

An example is a PCMCIA card with a modem.

The following figure shows the typical configuration for a Toaster device.

Left Figure: Hardware Configuration for a Plug and Play Toaster Device on a PCMCIA Card

Right Figure: Configuration of Drivers and Device Stacks for a Plug and Play Toaster Device on a PCMCIA Card

In this configuration, the Toaster device is a child device on a PCMCIA bus. The PCMCIA bus driver creates a PDO for the Toaster device when it enumerates the PCMCIA card. The INF file for the Toaster device specifies Serial as a lower-level device filter driver. Serial provides a 16550 UART-compatible interface to the hardware device. The Toaster driver creates and attaches an FDO to the Toaster device stack.


Plug and Play Serial Device on a Multifunction Device that Requires a 16550 UART-Compatible Interface

This section describes the configuration of hardware, drivers, and device stacks for multifunction serial devices that:

  • Support Plug and Play
  • Require a 16550 UART-compatible interface
  • Are not connected to an RS-232 port

An example is a PCMCIA card with a modem and a LAN adapter.

The following figure shows the typical configuration for an example Toaster device and an example Blender device.

Left Figure: Hardware Configuration for a Toaster device on a Multifunction PC Card

Right Figure: Configuration of Drivers and Device Stacks for a Toaster device and a Blender Device

In this configuration the Toaster device is a child device on the multifunction device, and the multifunction device is a child device on a PCMCIA bus.

The INF file and installers for the Toaster device install the Serial driver as lower-level device filter driver to provide a 16550 UART-compatible interface for the Toaster device. The Toaster driver creates and attaches an FDO to the Serial driver filter DO.


Operation of Serial and Serenum

This section describes the following topics about the operation of Serenum and Serial:

Serenum Filtering of I/O Requests

Serenum Device Enumeration

Enumeration of Legacy COM Ports

COM Port Interfaces

Open and Initialize a COM Port

Open and Initialize a 16550 UART-Compatible Interface

COM Port Interrupt Sharing

COM Port Power Up

Read and Write Timeouts for a COM Port

Removal of a Plug and Play Serial Device on an RS-232 Port

Removal of a Plug and Play RS-232 Port

Serial Device Control Requests

See the following for more information on the operation of Serenum and Serial:

  • Serial Driver Reference
  • Serenum Driver Reference
  • Sample code in the directories %user install directory%\src\kernel\serial and %user install directory%\src\kernel\serenum in the Microsoft® Windows® 2000 DDK
  • Microsoft Win32® Communications API

    The documentation of the Win32 Communications API in the Platform SDK describes the high-level operation of COM ports.


Serenum Filtering of I/O Requests

Serenum filters I/O requests that are directed to a filter DO in the following way:

  • Handles bus-related operations that are associated with Plug and Play and power requests:
    • Removes a PDO, if one exists, when the filter DO is removed.
    • Enumerates the RS-232 port in response to an IRP_MN_QUERY_DEVICE_RELATIONS request of type BusRelations.
  • Completes Serenum-specific device control requests that return information about the RS-232 port.

Serenum filters I/O requests that are directed to a PDO in the following way (the PDO represents a child device attached to an RS-232 port):

  • Completes all Plug and Play and power requests.
  • Reroutes device control requests to the filter DO associated with the PDO.
  • Completes a Serenum-specific internal device control request that invalidates the bus relations on an RS-232 port.

For more information, see the following:

  • Serenum Driver Reference
  • Sample code in the %install directory%\src\kernel\serenum directory in the Windows 2000 DDK


Serenum Device Enumeration

This section describes the following topics associated with Serenum's enumeration of Plug and Play serial devices attached to serial ports.

  • Enumerating High-Capacity Multiport Adapters
  • Opening a Serial Port for Enumeration

Enumerating High-Capacity Multiport Adapters

In Microsoft® Windows® 2000, boot time can be significantly delayed by the time it takes to automatically enumerate high-capacity multiport adapters (containing 16 or more ports). To address this issue, Windows XP and later supports the following two enhancements:

  1. Compared to Windows 2000, the time Serenum requires to automatically enumerate high-capacity multiport adapters is substantially reduced.
  2. Serenum supports an optional SkipEnumerations registry entry value for each serial port installed in a system. A vendor can use this entry value to control whether or not Serenum enumerates a port (whether initiated by a system boot or by a user through the Device Manager or Hardware Wizard).

Windows does not support a single registry setting that globally controls the enumeration of all serial ports.

Windows 2000 does not support controlling a serial port's enumeration by setting a SkipEnumerations registry entry value.

For a description about how to set a serial port's SkipEnumerations entry value in Windows XP, see Serenum SkipEnumerations Entry Value.

Opening a Serial Port for Enumeration

Serenum must open a serial port to enumerate it. Devices that keep a port open indefinitely should not use Serenum.


Enumeration of Legacy COM Ports

Serial currently enumerates legacy COM ports. Most legacy ports that Serial enumerates are on multiport boards that do not have a microcontroller. The following applies to COM ports that are specified in the registry. Note that the enumeration function will be removed from Serial and included as part of setup in a future release.

Serial does the following:

  • Checks for COM ports identified by subkeys under the driver service registry key ..\Services\Serial\Parameters\<Device subkey>.

    For each device subkey, Serial obtains the legacy registry information described in Registry Settings for a Legacy COM Port.

  • Determines if Serial previously detected the COM port.

    Serial uses a COM port's LegacyDiscovered entry value (REG_DWORD). If LegacyDiscovered is zero, Serial did not previously detect the port. If LegacyDiscovered is 0x00000001, Serial previously detected the port.

  • If Serial did not previously detect the COM port, it reports the COM port to the Plug and Play Manager.

    The Plug and Play Manager returns a PDO. The Plug and Play Manager creates an entry for the COM port in its device tree.

  • If Serial previously detected the COM port, it skips the port.

    The Plug and Play Manager adds and starts the legacy port.

  • If the device has a device ID, Serial skips the device.

    The device is enumerated by a Plug and Play bus driver.

  • Creates an FDO for each detected COM port and attaches it to the device stack.
  • Sets COM port information under the Plug and Play registry key for the COM port.

    Serial uses a subset of the information read from the registry for the legacy COM port. For more information, see Registry Settings for a Plug and Play COM port.

  • Starts the COM port.


COM Port Interfaces

The SerialSkipExternalNaming entry value controls whether or not Serial creates external interfaces for the port. Most ports provide external interfaces. If the SerialSkipExternalNaming value does not exist or is set to 0x00000000, Serial does the following:

  • Creates a symbolic link between \DosDevices\<Port Name> and the internal device name for the COM port.

    Port Name is the value of the PortName (or Identifier) entry value for the COM port. Port names are typically set to COM<n>, where n is the number of the COM port. There is no limit to the number of COM ports that Windows supports. User-mode clients can open a COM port by using the symbolic link.

  • Writes an entry value under the \Registry\Machine\Hardware\DeviceMap\SERIALCOMM key.

    The name of the entry value is \Device\Serial<n>, where n is the number of the serial device. The value of \Device\Serial<n> is set to the value of PortName.

  • Registers an interface of type GUID_CLASS_COMPORT for the COM port.

    Clients can register to be notified of the arrival of COM port interfaces, or can obtain the symbolic link names of all registered interfaces of a specified type.

Serial port drivers other than Serial can create COM<n> symbolic links. If the serial port driver supports Plug and Play, the driver must create a GUID_CLASS_COMPORT interface.

For more information about the entry values, see Registry Settings for Serial.


Open and Initialize a COM Port

When Serial is used as a function driver, the following considerations apply to opening and initializing a COM port:

  • Serial supports only one open at a time on a COM port.
  • A port is in an undefined state when it is opened. A client should initialize a port to a known state before using the port. A user-mode client must use the Win32 Communications API. A kernel-mode client can use the IOCTL_SERIAL_SET_Xxx and the IOCTL_SERIAL_INTERNAL_Xxx requests.
  • All clients must open a COM port when they need it, and they should close the port immediately after they are through with the port.
  • Serenum must open an RS-232 port to enumerate the port. Clients that hold an RS-232 port open indefinitely should not use Serenum.


Open and Initialize a 16550 UART-Compatible Interface

When Serial is used as a lower-level device filter driver, the following considerations apply to opening and initializing the interface:

  • Serial supports only one open at a time on the interface.
  • The interface is in an undefined state when it is open.

    A client should initialize the interface to a known state before using the interface. A user-mode client can use the IOCTL_SERIAL_SET_Xxx requests. Note, however, that a Win32-compliant application must only use the Win32 Communications API. A kernel-mode client can use the IOCTL_SERIAL_Xxx and the IOCTL_SERIAL_INTERNAL_Xxx requests.


COM Port Interrupt Sharing

Legacy COM ports on the same multiport board share a single interrupt. COM ports on a multiport board are identified by an index or a mask that is used to associate a port with its corresponding device object.

Standalone COM ports can share interrupts. However, a shared interrupt can only be used by one port at a time. When a port is opened, Serial allocates the port's interrupt to the port. When a port is closed, the driver releases the port's interrupt for use by another port.


COM Port Power Up

A COM port must be powered-up (in the device power state PowerDeviceD0) for Serial to communicate with the device hardware. If the port is not powered-up, Serial attempts to power-up the port before the driver completes a request.


Read and Write Timeouts for a COM port

A client can use an IOCTL_SERIAL_SET_TIMEOUTS request to set time-out values that Serial uses for read and write requests. Serial continues to transfer bytes until the requested number of bytes are transferred or a time-out event occurs.

Serial's time-out operation is compliant with the user-mode operation of COM ports that the Win32 Communications API provides.

Note that the time-out operation is not applied to a pending request while it is queued. The time-out operation is applied to a request after the request becomes current (that is, Serial starts to process the request).

For more information on the read and write time-outs, see the following:

  • SetCommTimeouts function and the COMMTIMEOUTS structure in the Platform SDK documentation
  • SERIAL_TIMEOUTS structure in the include file %install directory%\inc\ntddser.h in the Windows 2000 DDK


Removal of a Plug and Play Serial Device on an RS-232 Port

The Plug and Play Manager removes a serial device by sending a remove request to the top of a serial device stack. After Serenum receives a remove request for the serial device, it removes the device's PDO and completes the request. Serenum does not pass the request on to the RS-232 port stack because the RS-232 port is the parent device for the serial device that is removed.


Removal of a Plug and Play RS-232 Port

The Plug and Play Manager removes an RS-232 port by sending a remove request to the top of the RS-232 port stack. Serenum passes the request down the device stack, removes the filter DO in the port stack, and removes an associated PDO, if one exists. Removal of the RS-232 port also removes the serial device attached to the port.


Serial Device Control Requests

Serial provides device control requests to control the operation of a COM port or a 16550 UART-compatible interface.

Serial supports IOCTL_SERIAL_Xxx requests that a client can use to do the following:

  • Get and set control registers and control signals
  • Get and set line control and modem control
  • Set FIFO control
  • Get and set handshake and flow control operation and parameters
  • Get and set wait events
  • Purge internal buffers, set the receive buffer size, and reset the device
  • Get and set timeouts that are used for read and write requests
  • Get and clear performance statistics
  • Get status information
  • Get properties of the device

Serial supports IOCTL_SERIAL_INTERNAL_Xxx requests that a trusted kernel-mode client can use to do the following:

  • Set basic settings on a device, and restore previous settings
  • Disable and enable the wait/wake operation of a device

For more information about the highlevel operation of COM ports, see the Win32 Communications API.

For more information about Serial I/O requests, see Serial Driver Reference.


Registry Settings for Serial

This section describes the registry settings that Serial uses to configure a COM port.

Serial uses the registry settings described in this section to configure a COM port in the following way:

  • If a device-specific entry value is present, Serial uses the device-specific entry value.
  • If a device-specific entry value is not present, but there is a corresponding Serial service entry value, Serial uses the value of the service entry value.
  • If a device-specific entry value is not present and there is no corresponding Serial service entry value, Serial uses a default service value that is statically defined in serial.sys.

For more information on the registry settings that Serial uses, see the following topics:

Registry Settings for the Serial Service

Registry Settings for a Plug and Play COM Port

Registry Settings for a Legacy COM Port


Registry Settings for the Serial Service

This section describes the registry settings that Serial applies to all serial devices for which Serial is the function driver or a lower-level device filter driver.

Serial queries the service entry values after it is loaded. If an entry value is not present, Serial adds the service entry value. Serial sets the value of the entry value to the default value that is statically defined in serial.sys. If a service entry value is changed after Serial is loaded, the new value is used the next time Serial is loaded.

Serial uses the following service entry values that are under the ..\Services\Serial registry key:

ForceFifoEnable
The ForceFifoEnable entry value is a Boolean flag that specifies whether or not to force Serial to use FIFOs. If ForceFifofEnable is nonzero, FIFOs are used, regardless of whether or not Serial can detect the presence of FIFOs. Otherwise, FIFOs are only used if Serial can detect them. ForceFifoEnable is a REG_DWORD and the default value is nonzero. If the entry value is not present, Serial sets a ForceFifoEnable entry value to the default value. For more information on the method of detection, see the sample code in %user install directory%\src\kernel\serial in the Windows 2000 DDK.
RxFIFO
The RxFIFO entry value specifies the number of bytes in the receive FIFO that triggers a port interrupt. For valid values, see the constants defined in serial.h. RxFIFO is a REG_DWORD and the default value is eight bytes. If the entry value is not present, Serial sets a RxFIFO entry value to the default value.
TxFIFO
The TxFIFO entry value specifies the number of bytes in the transmit FIFO that triggers a port interrupt. For valid values, see the constants defined in serial.h. TxFIFO is a REG_DWORD and the default value is 14 bytes. If the entry value is not present, Serial sets a TxFIFO entry value to the default value.
PermitShare
The PermitShare entry value is a Boolean flag that specifies whether or not to permit the system to share the interrupt that a port uses. If PermitShare is nonzero, the interrupt can be shared. Otherwise, the interrupt can not be shared. PermitShare is a REG_DWORD and the default value is set to 0x00000000. If the entry value is not present, Serial sets a PermitShare entry value to the default value.
BreakOnEntry, DebugLevel, and LogFifo
These entry values are used for debugging. For more information on these entry values, see the sample code.


Registry Settings for a Plug and Play COM Port

This section describes the registry settings that Serial uses as a function driver for a Plug and Play COM port. Serial also uses these settings as a lower-level device filter driver for a serial device that requires a 16550 UART-compatible interface.

Serial queries these registry entry values when it adds the device. If a device-specific entry value is not present, Serial uses a Serial service value.

All the following registry settings are under the Plug and Play registry key for a COM port.

PortName
The PortName entry value specifies the name of the COM port. The name of a COM port is typically COM<n>. However, a COM port name can be set to any non-NULL string. Serial uses the port name to create a symbolic link to the COM port that is visible in user-mode. PortName is a REG_SZ and the default value is an empty string.
Identifier
The Identifier entry value specifies the name of the COM port. The support for an Identifier entry value is provided for compatibility with some legacy PCMCIA devices. The use of Identifier is obsolete and should not be used with new Microsoft® Windows® 2000 drivers. For a description, see the PortName entry value.
MultiportDevice
The MultiportDevice entry value is a Boolean flag that specifies whether or not a COM port is a device on a multiport device. If MultiportDevice is 0x00000000, the COM port is a standalone device. Otherwise, the COM port is on a multiport device. MultiportDevice is a REG_DWORD and the default value is 0x00000000.
PortIndex
The PortIndex entry value specifies the index number of a COM port on a multiport device. The Indexed entry value specifies whether or not a port is bitmapped or indexed. PortIndex is a REG_DWORD and the default value is zero.
ClockRate
The ClockRate entry value specifies the UART clock rate. ClockRate is a REG_DWORD and the default value is 1843200 Hertz.
Indexed
The Indexed entry value is a Boolean flag that specifies whether or not a port on a multiport device is bitmapped or indexed. If Indexed is nonzero, the port is indexed. Otherwise, the port is bitmapped. Indexed is used in conjunction with the PortIndex entry value. Indexed is a REG_DWORD and the default value is 0x00000000.
DisablePort
The DisablePort entry value is a Boolean flag that specifies whether or not to disable the COM port. If DisablePort is nonzero, Serial disables the COM port. Otherwise, the COM port is enabled. Use of the DisablePort entry value is obsolete and should not be used with new Windows 2000 drivers. Windows 2000 provides a generic manual method through the GUI of the Device Manager to enable and disable devices. DisablePort is a REG_DWORD and the default value is 0x00000000. Note that flagging a port as disabled does not mean that the port does not exist. Serial still attempts to detect the presence of a disabled port. If the port is specified as disabled, Serial returns STATUS_NO_SUCH_DEVICE in response to an IRP_MN_START_DEVICE request. After the start request fails, the Plug and Play Manager sends a remove request.
ForceFifoEnable
The ForceFifoEnable entry value is a Boolean flag that specifies whether or not to force Serial to use FIFOs. If ForceFifoEnable is nonzero, FIFOs are used, regardless of whether or not Serial can detect the presence of FIFOs. Otherwise, FIFOs are only used if Serial can detect them. ForceFifoEnable is a REG_DWORD and the default value is the value set for the Serial service. (The default value for the Serial service is 0x00000001.)
RxFIFO
The RxFIFO entry value specifies the number of bytes in the receive FIFO that triggers a COM port interrupt. For valid values, see the constants defined in serial.h. RxFIFO is a REG_DWORD and the default value is the value set for the Serial service. (The default value for the Serial service is eight bytes.)
TxFIFO
The TxFIFO entry value specifies the number of bytes in the transmit FIFO that triggers a COM port interrupt. For valid values, see the constants defined in serial.h. TxFIFO is a REG_DWORD and the default value is the value set for the Serial service. (The default value for the Serial service is fourteen bytes.)
MaskInverted
The MaskInverted entry value is a Boolean flag that specifies whether or not the COM port hardware inverts the contents of the interrupt status register. If MaskInverted is nonzero, the interrupt status register is inverted. Otherwise, the interrupt status register is not inverted. MaskInverted is a REG_DWORD and the default value is 0x00000000.
SerialSkipExternalNaming
The SerialSkipExternalNaming entry value is a Boolean flag that specifies whether or not Serial creates external interfaces. If SerialSkipExternalNaming is nonzero, Serial does not create external interfaces. Otherwise, Serial does create external interfaces. SerialSkipExternalNaming is a REG_DWORD and the default value is 0x00000000. For more information on the external interfaces that Serial creates, see COM Port Interfaces.
SerialRelinquishPowerPolicy
The SerialRelinquishPowerPolicy entry value is a Boolean flag that specifies whether or not Serial is the power policy owner for a serial device stack. If SerialRelinquishPowerPolicy is zero, Serial is the power policy owner, otherwise Serial is not the power policy owner. SerialRelinquishPowerPolicy is a REG_DWORD and the default value is 0x00000000.
Share System Interrupt
The Share System Interrupt entry value is a Boolean flag that specifies whether or not to permit the system to share the interrupt that the COM port uses. If Share System Interrupt is nonzero, the interrupt can be shared. Otherwise, the interrupt can not be shared. Share System Interrupt is a REG_DWORD and the default value is the value set for the PermitShare entry value for the Serial service. (The default service value for PermitShare is 0x00000000.)
SerialIoResourcesIndex
The SerialIoResourceIndex entry value specifies the index of the partial resource descriptor that Serial uses to determine the I/O addresses of the serial register set for the serial device. SerialIoResourceIndex is a REG_DWORD and the default value is zero.


Registry Settings for a Legacy COM Port

This section describes the registry settings that Serial uses with legacy COM ports.

Serial queries these entry values when it enumerates a legacy COM port. If a device-specific entry value is not present, Serial uses a Serial service value.

The registry settings for a legacy COM port are under a corresponding legacy COM port subkey that is under the ..\Services\Serial\Parameters key.

The following entry values are the same as described for a Plug and Play COM port:

ClockRate

PortIndex, Indexed

RxFIFO, TxFIFO

MaskInverted

DisablePort

ForceFifoEnable

The following additional entry values are used with legacy COM ports:

PortAddress
The PortAddress entry value specifies the untranslated base I/O address for the COM port control registers. Serial reads this value. The value can not be zero. PortAddress is a REG_DWORD and the default value, set internally by Serial, is zero.
Interrupt
The Interrupt entry value specifies the untranslated interrupt vector, as appropriate for the bus type. Serial reads this value. The value can not be zero. Interrupt is a REG_DWORD and the default value, internally set by Serial, is zero.
DosDevices
The DosDevices entry value specifies the name of the COM port. The name of a COM port is typically COM<n>. However, a COM port name can be set to any nonNULL string. Serial uses the port name to create a symbolic link to the COM port that is visible in user-mode. DosDevices is a REG_SZ and the default value, set by Serial for the device, is a NULL string.
InterruptStatus
The InterruptStatus entry value specifies the raw I/O address for the interrupt status register. Serial reads this value. The value is omitted if the port is a standalone port. The value can not be zero if the port is on multiport device. InterruptStatus is a REG_DWORD and the default value, set internally by Serial, is zero.
BusNumber
The BusNumber entry value specifies the system-wide bus number for the bus type. Serial reads this value. BusNumber is a REG_DWORD and the default value is zero.
BusType
The BusType entry value specifies the bus type. Serial reads this value. BusType is a REG_DWORD and the default value is determined by Serial during driver initialization.
InterruptMode
The InterruptMode entry value specifies the interrupt mode. Serial reads this value. InterruptMode is a REG_DWORD and the default value is CM_RESOURCE_INTERRUPT_LATCHED.
InterruptLevel
The InterruptLevel entry value specifies a raw interrupt level value, appropriate for the bus type. Serial reads this value. InterruptLevel is a REG_DWORD and the default value is zero.
PnPDeviceID
The PnPDeviceID entry value specifies a Plug and Play device ID for a Plug and Play device. Serial reads this value. PnPDeviceID is a REG_SZ and the default value is a NULL string.
LegacyDiscovered
The LegacyDiscovered entry value is a Boolean flag that indicates whether or not Serial has previously reported the device to the Plug and Play Manager. Serial reads and sets this value. If LegacyDiscovered is nonzero, Serial has previously reported the device. Serial does not report the device again. Otherwise, Serial reports the device and sets the entry value to 0x00000001. LegacyDiscovered is a REG_DWORD.


Registry Settings for Serenum

This section describes the entry values that Serenum uses for a serial port in Microsoft® Windows® 2000 and later.

The following registry entry values are under the Plug and Play hardware device registry key for a serial port:

Serenum PortName Entry Value

Serenum Identifer Entry Value

Serenum SkipEnumerations Entry Value


Serenum PortName Entry Value

The PortName registry entry value is located under a serial port's Plug and Play hardware device key.

PortName entry value (REG_SZ)
Specifies the name of a serial port. Serenum reads this value and returns the port name in response to an IOCTL_SERENUM_GET_PORT_NAME request.


Serenum Identifer Entry Value

The Identifier registry entry value is located under a serial port's Plug and Play hardware device key.

Identifier entry value (REG_SZ)
Specifies the name of a serial port. Serenum reads this value. Support for the Identifer entry value is provided only for compatibility with some legacy PCMCIA devices. The use of the Identifer entry value is obsolete and should not be implemented with new drivers in Windows 2000 and later. Serenum returns the port name in response to an IOCTL_SERENUM_GET_PORT_NAME request.


Serenum SkipEnumerations Entry Value

The SkipEnumerations registry entry value is located under a serial port's Plug and Play hardware device key.

SkipEnumerations entry value (REG_DWORD)
In Windows XP and later, this entry value controls when Serenum enumerates a port in response to an IRP_MN_QUERY_DEVICE_RELATIONS request for BusRelations. This entry value is not supported by Windows 2000.

Every time the system builds a serial port device stack, Serenum sets the enumeration mode that it uses to enumerate a serial port. During the initialization of a port's device stack, Serenum's AddDevice routine reads the port's SkipEnumerations entry value, and sets the enumeration mode as described in the following table.
Enumeration Mode | SkipEnumerations Value | Description
Enumerate normally 0x00000000

(or the value entry is not present)

 Serenum enumerates a serial port in response to all BusRelations requests (whether initiated by a system boot or by the user through the Device Manager or the Hardware Wizard).
Skip a specified number of enumerations. | A value from 0x00000001 to 0xFFFFFFE | Serenum skips the specified number of enumerations and subsequently enumerates normally as long as the port remains enabled.
Skip all enumerations. | 0xFFFFFFFF | Serenum never enumerates a port. A device attached to the port must be manually installed.

For example, if a serial port's SkipEnumerations entry value is set to three when the system builds a port device stack, Serenum will skip the first three BusRelations requests it receives for the port. Serenum will subsequently enumerate the port in a normal manner as long as the port remains enabled.


Serial Driver Reference

This section describes Serial, the function driver for COM ports in Microsoft® Windows® 2000 and later operating systems.

Serial is a function driver for legacy COM ports and Plug and Play COM ports. Serial is also a lower-level device filter driver for Plug and Play devices that require a 16550 UART-compatible interface, but are not attached to a COM port.

Serial implements the Serial service, and its executable image is serial.sys.

The Serial function driver is described in the following topics.

Serial Major I/O Requests

Serial Device Control Requests

Serial Internal Device Control Requests

For more information about the operation of the Serial driver, see the following:

Serial Devices and Drivers

Data definitions in the include file ntddser.h in the Windows DDK

Sample code in the \src\kernel\serial directory in the Windows DDK

Microsoft Win32® Communications API

Notes

  1. This section describes Serial's operation as a function driver for COM ports. Serial's operation as a lower-level device filter driver is identical to its operation as a function driver.
  2. Serial supports interfaces that are compatible with a 16550 UART. The device control signals and registers that are specified in this chapter are compatible with a 16550 UART interface. Examples of these device control signals and registers include: the ready to send control signal, the clear to send control signal, the line control register, and the modem status register.
  3. This chapter does not duplicate the extensive information provided in the Microsoft Platform SDK about operating a COM port. For more information about the operation of Serial device control requests, see the corresponding documentation for the Win32 Communications API in the Platform SDK.


Serial Major I/O Requests

This section describes the Serial-specific operation of the following major I/O requests that Serial supports:

IRP_MJ_CLEANUP

IRP_MJ_CLOSE

IRP_MJ_CREATE

IRP_MJ_DEVICE_CONTROL

IRP_MJ_FLUSH_BUFFERS

IRP_MJ_INTERNAL_DEVICE_CONTROL

IRP_MJ_PNP

IRP_MJ_POWER

IRP_MJ_QUERY_INFORMATION

IRP_MJ_READ

IRP_MJ_SET_INFORMATION

IRP_MJ_SYSTEM_CONTROL

IRP_MJ_WRITE

This section does not describe the driver-generic operation of these requests. See the following for more information on Serial's generic handling of these requests:

  • IRP Function Codes and IOCTLs
  • Sample code in the \src\kernel\serial directory in the Windows DDK


IRP_MJ_CREATE

Operation

The IRP_MJ_CREATE request opens a COM port. A COM port must be opened before it can be used. Only one client can have a COM port open at the same time.

I/O Status Block

The Information field is set to zero.

The Status field is set to one of the following values:

STATUS_SUCCESS
STATUS_ACCESS_DENIED
The device is already open.
STATUS_DELETE_PENDING
Serial is in the process of removing the device.
STATUS_INSUFFICIENT_RESOURCES
The device is not in a Plug and Play Started state, or the driver could not allocate an internal data structure.
STATUS_NOT_A_DIRECTORY
STATUS_PENDING
Serial queued the request for later processing.
STATUS_SHARED_IRQ_BUSY
The interrupt assigned to the device is in use by another open device.


IRP_MJ_DEVICE_CONTROL

Operation

Serial supports the following device control requests:

IOCTL_SERIAL_CLEAR_STATS

IOCTL_SERIAL_CLR_DTR

IOCTL_SERIAL_CLR_RTS

IOCTL_SERIAL_CONFIG_SIZE

IOCTL_SERIAL_GET_BAUD_RATE

IOCTL_SERIAL_GET_CHARS

IOCTL_SERIAL_GET_COMMSTATUS

IOCTL_SERIAL_GET_DTRRTS

IOCTL_SERIAL_GET_HANDFLOW

IOCTL_SERIAL_GET_LINE_CONTROL

IOCTL_SERIAL_GET_MODEM_CONTROL

IOCTL_SERIAL_GET_MODEMSTATUS

IOCTL_SERIAL_GET_PROPERTIES

IOCTL_SERIAL_GET_STATS

IOCTL_SERIAL_GET_TIMEOUTS

IOCTL_SERIAL_GET_WAIT_MASK

IOCTL_SERIAL_IMMEDIATE_CHAR

IOCTL_SERIAL_LSRMST_INSERT

IOCTL_SERIAL_PURGE

IOCTL_SERIAL_RESET_DEVICE

IOCTL_SERIAL_SET_BAUD_RATE

IOCTL_SERIAL_SET_BREAK_OFF

IOCTL_SERIAL_SET_BREAK_ON

IOCTL_SERIAL_SET_CHARS

IOCTL_SERIAL_SET_DTR

IOCTL_SERIAL_SET_FIFO_CONTROL

IOCTL_SERIAL_SET_HANDFLOW

IOCTL_SERIAL_SET_LINE_CONTROL

IOCTL_SERIAL_SET_MODEM_CONTROL

IOCTL_SERIAL_SET_QUEUE_SIZE

IOCTL_SERIAL_SET_RTS

IOCTL_SERIAL_SET_TIMEOUTS

IOCTL_SERIAL_SET_WAIT_MASK

IOCTL_SERIAL_SET_XOFF

IOCTL_SERIAL_SET_XON

IOCTL_SERIAL_WAIT_ON_MASK

IOCTL_SERIAL_XOFF_COUNTER

No other device control requests are supported.

For a description of the device control requests, see Serial Device Control Requests.


IRP_MJ_FLUSH_BUFFERS

Operation

The IRP_MJ_FLUSH_BUFFER request flushes the internal write buffer.

Serial queues and starts processing write and flush requests in the order in which the requests are received. Serial completes a flush request after it calls IoCompleteRequest for all write requests that it received before a flush request. However, completion of the flush request does not indicate that all the previously started write requests are completed by other drivers in the device stack. For example, a filter driver might still be processing a write request. A client must check that a write request is completed by all drivers in the device stack before the client attempts to free or reuse a write request's IRP.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the following status values:

STATUS_SUCCESS
STATUS_CANCELLED
A client canceled the request. Serial also cancels a request if a device error occurs and Serial is configured to cancel a request if there is a device error.
STATUS_DELETE_PENDING
The driver is in the process of removing the device.
STATUS_PENDING
Serial queued the request for later processing.


IRP_MJ_INTERNAL_DEVICE_CONTROL

Serial supports the following internal device control requests:

IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS

IOCTL_SERIAL_INTERNAL_CANCEL_WAIT_WAKE

IOCTL_SERIAL_INTERNAL_DO_WAIT_WAKE

IOCTL_SERIAL_INTERNAL_RESTORE_SETTINGS

No other internal device control requests are supported.

For a description of the internal device control requests, see Serial Internal Device Control Requests.


IRP_MJ_PNP

Serial supports the following Plug and Play requests:

IRP_MN_CANCEL_REMOVE_DEVICE

IRP_MN_CANCEL_STOP_DEVICE

IRP_MN_FILTER_RESOURCE_REQUIREMENTS

IRP_MN_QUERY_CAPABILITIES

IRP_MN_QUERY_DEVICE_RELATIONS

IRP_MN_QUERY_ID

IRP_MN_QUERY_PNP_DEVICE_STATE

IRP_MN_QUERY_REMOVE_DEVICE

IRP_MN_QUERY_RESOURCE_REQUIREMENTS

IRP_MN_QUERY_STOP_DEVICE

IRP_MN_REMOVE_DEVICE

IRP_MN_START_DEVICE

IRP_MN_STOP_DEVICE

IRP_MN_SURPRISE_REMOVAL

Serial sends all other Plug and Play requests down the device stack without further processing.

Serial performs the following Serial-specific processing for Plug and Play requests:

IRP_MN_QUERY_ID (type BusQueryHardwardIDs)
If a COM port is on a multiport ISA card, Serial appends L"*PNP0502" to the string of hardware IDs.
IRP_MN_FILTER_RESOURCE_REQUIREMENTS
COM ports on a multiport ISA card share the same interrupt status register and the same interrupt.

For a description of the generic operation of Plug and Play requests, see Plug and Play IRPs.


IRP_MJ_POWER

Serial supports the following power requests:

  • IRP_MN_QUERY_POWER
  • IRP_MN_SET_POWER

Serial sends all other power requests down the device stack to be completed by a lower-level driver.

Serial is the default power policy owner for a serial device stack that uses Serial as a function driver or a lower-level filter driver.

For more information on the generic operation of these requests, see Rules for Handling Power IRPs.


IRP_MJ_QUERY_INFORMATION

Operation

The IRP_MJ_QUERY_INFORMATION request queries the end-of-file information for a COM port. Serial supports requests of type FileStandardInformation and FilePositionInformation.

The standard file information is always set to zero or FALSE, as appropriate. The position information is always set to zero.

Input

The Parameters.QueryFile.FileInformationClass is set to FileStandardInformation or FilePositionInformation.

Output

FileStandardInformation
The AssociatedIrp.SystemBuffer member points to a client-allocated FILE_STANDARD_INFORMATION structure that Serial uses to output standard information.
FilePositionInformation
The AssociatedIrp.SystemBuffer member points to a client-allocated FILE_POSITION_INFORMATION structure that Serial uses to output position information.

I/O Status Block

If the request is successful, the Information member is set to zero.

The Status member is set to one of the following status values:

STATUS_SUCCESS
STATUS_CANCELLED
A client canceled the request. Serial also cancels a request if a device error occurs and Serial is configured to cancel a request if there is a device error.
STATUS_DELETE_PENDING
Serial is in the process of removing the device.
STATUS_INVALID_PARAMETER
The requested information is not supported.
STATUS_PENDING
Serial queued the request for later processing.


IRP_MJ_READ

Operation

The IRP_MJ_READ request copies bytes from a COM port to a client-allocated output buffer.

A client can use timeout events to terminate a read request. Note, however, that when a COM port is opened, the timeout settings for the device are undefined. A kernel-mode client can use an IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS to set timeout parameters to zero (no timeout events are used). User-mode and kernel-mode clients can use an IOCTL_SERIAL_SET_TIMEOUTS request to set timeout parameters.

For more information on read and write timeouts, see Read and Write Timeouts for a COM Port.

Input

The Parameters.Read.Length member is set to the number of bytes to copy to the client's output buffer.

Output

The AssociatedIrp.SystemBuffer member points to a client-allocated buffer that Serial uses to output data.

I/O Status Block

The Information member is set to the number of bytes copied to the client's output buffer.

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_CANCELLED
A client canceled the request. Serial also cancels a request if a device error occurs and Serial is configured to cancel a request if there is a device error.
STATUS_DELETE_PENDING
Serial is in the process of removing the device.
STATUS_PENDING
Serial queued the request for later processing.
STATUS_TIMEOUT
The time to complete the request exceeded the total timeout value or the interval timeout value.


IRP_MJ_SET_INFORMATION

Operation

The IRP_MJ_SET_INFORMATION request sets the end-of-file information on a COM port. Serial supports requests of type FileEndOfFileInformation and FileAllocationInformation.

A client can not set file information.

Input

The Parameters.SetFile.FileInformationClass member is set to FileEndOfFileInformation or FileAllocationInformation.

I/O Status Block

If the request is successful, the Information member is set to zero.

The Status member is set to one of the following status values:

STATUS_SUCCESS
STATUS_CANCELLED
A client canceled the request. Serial also cancels a request if a device error occurs and Serial is configured to cancel a request if there is a device error.
STATUS_DELETE_PENDING
Serial is in the process of removing the device.
STATUS_INVALID_PARAMETER
The specified end-of-file information is not supported.
STATUS_PENDING
Serial queued the request for later processing.


IRP_MJ_SYSTEM_CONTROL

Operation

Serial uses WmiSystemControl to handle WMI system control requests. Serial registers the following types of WMI library callback routines, which WmiSystemControl calls to handle WMI requests sent to a device:

DpWmiQueryReginfo

DpWmiQueryDataBlock

DpWmiSetDataBlock

DpWmiSetDataItem

Serial does not support any other system control requests. For non-WMI requests, Serial skips the current stack location, and sends the request down the device stack.

Serial registers the WMI GUIDS described in the following table.

Serial WMI GUID | Associated Data Structure
SERIAL_PORT_WMI_NAME_GUID | USHORT followed by a WCSTR
SERIAL_PORT_WMI_COMM_GUID | SERIAL_WMI_COMM_DATA
SERIAL_PORT_WMI_HW_GUID | SERIAL_WMI_HW_DATA
SERIAL_PORT_WMI_PERF_GUID | SERIAL_WMI_PERF_DATA
SERIAL_PORT_WMI_PROPERTIES_GUID | WMI_SERIAL_PORT_PROPERTIES

The WMI name of a serial port is its COM port name, which is the value of the entry value PortName under the Plug and Play registry key for the device.

I/O Status Block

For WMI requests, Serial sets the Status field to one of the following values:

STATUS_SUCCESS
The request completed successfully.
STATUS_BUFFER_TOO_SMALL
The size, in bytes, of the output buffer is less than the required size of the requested information.
STATUS_INSUFFICIENT_RESOURCES
There were insufficient system resources to save the serial port name.
STATUS_INVALID_DEVICE_REQUEST
The request is not valid.
STATUS_WMI_GUID_NOT_FOUND
The WMI GUID is not supported.


IRP_MJ_WRITE

Operation

The IRP_MJ_WRITE request copies data to a COM port from a client-provided input buffer.

A client can use timeout events to terminate a write request. Note, however, that when a COM port is opened, the timeout events set on a device are undefined. A kernel-mode client can use an IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS to set timeout parameters to zero (no timeout events are used) and an IOCTL_SERIAL_SET_TIMEOUTS request to set timeout parameters. For more information on read and write timeouts, see Read and Write Timeouts for a COM port.

Input

The Parameters.Write.Length member is set to the number of bytes to copy from a client-allocated input buffer to a COM port.

The AssociatedIrp.SystemBuffer member points to a client-allocated input buffer from which Serial copies data to the COM port.

I/O Status Block

The Information member is set to the number of bytes actually copied from the client's input buffer to the COM port.

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_CANCELLED
A client canceled the request. Serial also cancels a request if a device error occurs and Serial is configured to cancel a request if there is a device error.
STATUS_DELETE_PENDING
Serial is in the process of removing the device.
STATUS_PENDING
Serial queued the request for later processing.
STATUS_TIMEOUT
The total time allowed for the write request was exceeded.


Serial Device Control Requests

This section describes the following device control requests that Serial supports:

IOCTL_SERIAL_CLEAR_STATS

IOCTL_SERIAL_CLR_DTR

IOCTL_SERIAL_CLR_RTS

IOCTL_SERIAL_CONFIG_SIZE

IOCTL_SERIAL_GET_BAUD_RATE

IOCTL_SERIAL_GET_CHARS

IOCTL_SERIAL_GET_COMMSTATUS

IOCTL_SERIAL_GET_DTRRTS

IOCTL_SERIAL_GET_HANDFLOW

IOCTL_SERIAL_GET_LINE_CONTROL

IOCTL_SERIAL_GET_MODEM_CONTROL

IOCTL_SERIAL_GET_MODEMSTATUS

IOCTL_SERIAL_GET_PROPERTIES

IOCTL_SERIAL_GET_STATS

IOCTL_SERIAL_GET_TIMEOUTS

IOCTL_SERIAL_GET_WAIT_MASK

IOCTL_SERIAL_IMMEDIATE_CHAR

IOCTL_SERIAL_LSRMST_INSERT

IOCTL_SERIAL_PURGE

IOCTL_SERIAL_RESET_DEVICE

IOCTL_SERIAL_SET_BAUD_RATE

IOCTL_SERIAL_SET_BREAK_OFF

IOCTL_SERIAL_SET_BREAK_ON

IOCTL_SERIAL_SET_CHARS

IOCTL_SERIAL_SET_DTR

IOCTL_SERIAL_SET_FIFO_CONTROL

IOCTL_SERIAL_SET_HANDFLOW

IOCTL_SERIAL_SET_LINE_CONTROL

IOCTL_SERIAL_SET_MODEM_CONTROL

IOCTL_SERIAL_SET_QUEUE_SIZE

IOCTL_SERIAL_SET_RTS

IOCTL_SERIAL_SET_TIMEOUTS

IOCTL_SERIAL_SET_WAIT_MASK

IOCTL_SERIAL_SET_XOFF

IOCTL_SERIAL_SET_XON

IOCTL_SERIAL_WAIT_ON_MASK

IOCTL_SERIAL_XOFF_COUNTER

No other device control codes are supported.

I/O Status Block

The Information member is set to a request-specific value or to zero.

The Status member is set to a request-specific status value or to one of the following generic status values:

STATUS_SUCCESS
STATUS_BUFFER_SIZE_TOO_SMALL
The input or the output buffer is too small to hold the required information.
STATUS_CANCELLED
The client canceled the request. For all control codes other than IOCTL_SERIAL_GET_COMMSTATUS, Serial also cancels a request if a device error occurs and Serial is configured to cancel a request if there is a device error.
STATUS_DELETE_PENDING
There was an unrecoverable hardware error, or a Plug and Play remove or surprise remove operation is in progress.
STATUS_INVALID_DEVICE_REQUEST
The COM port is not open.
STATUS_INVALID_PARAMETER
The request parameters are not valid.
STATUS_PENDING
Serial queued the request for later processing.
STATUS_Xxx
An internal operation returned an NTSTATUS error status value.

If Serial does not support a device control request, it sets the Information member to zero and the Status member to STATUS_INVALID_PARAMETER.


IOCTL_SERIAL_CLEAR_STATS

Operation

The IOCTL_SERIAL_CLEAR_STATS request clears the performance statistics for a COM port.

To obtain the performance statistics, a client can use an IOCTL_SERIAL_GET_STATS request.

I/O Status Block

The Information field is set to zero.

The Status field is set to one of the generic status values.


IOCTL_SERIAL_CLR_DTR

Operation

The IOCTL_SERIAL_CLR_DTR request clears the data terminal ready control signal (DTR).

If the handshake flow control of the device is configured to automatically use DTR, a client can not clear or set DTR.

To set DTR, a client can use an IOCTL_SERIAL_SET_DTR request.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values. A status of STATUS_INVALID_PARAMETER indicates that the handshake flow control of the device is set to automatically use DTR.


IOCTL_SERIAL_CLR_RTS

Operation

The IOCTL_SERIAL_CLR_RTS request clears the request to send control signal (RTS).

If the handshake flow control of the device is configured to automatically use RTS, a client can not clear or set RTS.

To set RTS, a client can use an IOCTL_SERIAL_SET_RTS request.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values. A status of STATUS_INVALID_PARAMETER indicates that the handshake flow control of the device is set to automatically use RTS.


IOCTL_SERIAL_CONFIG_SIZE

Operation

The IOCTL_SERIAL_CONFIG_SIZE request returns information about configuration size.

Serial always returns zero.

This request is obsolete and should not be used by new drivers for Microsoft® Windows® 2000 and later.

Input

The Parameters.DeviceIoControl.OutputBufferLength is set to the size in bytes of a ULONG.

Output

The AssociatedIrp.SystemBuffer member points to a client-allocated ULONG buffer that Serial uses to output configuration size information.

I/O Status Block

The Information member is set to the size in bytes of a ULONG.

The Status member is set to one of the generic status values.


IOCTL_SERIAL_GET_BAUD_RATE

Operation

The IOCTL_SERIAL_GET_BAUD_RATE request returns the baud rate that is currently set for a COM port.

To set the baud rate, a client can use an IOCTL_SERIAL_SET_BAUD_RATE request.

For more information on the baud rates that the driver supports, see the baud rate constants SERIAL_BAUD_075 through SERIAL_BAUD_115200, which are defined in the include file ntddser.h in the Windows DDK.

Input

The Parameters.DeviceIoControl.OutputBufferLength member is set to the size in bytes of a SERIAL_BAUD_RATE structure.

Output

The AssociatedIrp.SystemBuffer member points to a client-allocated SERIAL_BAUD_RATE structure that Serial uses to output the baud rate information.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of a SERIAL_BAUD_RATE structure. Otherwise, the Information member is set to zero.

The Status member is set to one of the generic status values.


IOCTL_SERIAL_GET_CHARS

Operation

The IOCTL_SERIAL_GET_CHARS request returns the special characters that Serial uses with handshake flow control.

To set special characters, a client can use an IOCTL_SERIAL_SET_CHARS request.

Input

The Parameters.DeviceIoControl.OutputBufferLength member is set to the size in bytes of a SERIAL_CHARS structure.

Output

The AssociatedIrp.SystemBuffer member points to a client-allocated SERIAL_CHARS structure that Serial uses to output the special characters.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of SERIAL_CHARS. Otherwise, the Information member is set to zero.

The Status member is set to one of the generic status values.


IOCTL_SERIAL_GET_COMMSTATUS

Operation

The IOCTL_SERIAL_GET_COMMSTATUS request returns information about the communication status of a COM port.

Input

The Parameters.DeviceIoControl.OutputBufferLength is set to the size in bytes of a SERIAL_STATUS structure.

Output

The AssociatedIrp.SystemBuffer points to a client-allocated SERIAL_STATUS structure that Serial uses to output communication status information.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of a SERIAL_STATUS structure. Otherwise, the Information member is set to zero.

The Status member is set to one of the generic status values.


IOCTL_SERIAL_GET_DTRRTS

Operation

The IOCTL_SERIAL_GET_DTRRTS request returns information about the data terminal ready control signal (DTR) and the request to send control signal (RTS).

Input

The Parameters.DeviceIoControl.OutputBufferLength member is set to the size in bytes of a ULONG.

Output

The AssociatedIrp.SystemBuffer points to a client-allocated ULONG buffer that Serial uses to output information about the DTR and RTS. The ULONG buffer is set to a logical OR of zero or more of the following flags:

SERIAL_DTR_STATE
Indicates that DTR is set.
SERIAL_RTS_STATE
Indicates that RTS is set.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of a ULONG. Otherwise, the Information member is set to zero.

The Status member is set to one of the generic status values.


IOCTL_SERIAL_GET_HANDFLOW

Operation

The IOCTL_SERIAL_GET_HANDFLOW request returns information about the configuration of the handshake flow control set for a COM port.

To set the configuration of the handshake flow control, a client can use an IOCTL_SERIAL_SET_HANDFLOW request.

For more information on settings for handshake flow control, see the handshake flow control parameters SERIAL_DTR_MASK through SERIAL_FLOW_INVALID, which are defined in the include file ntddser.h in the Windows DDK.

Input

The Parameters.DeviceIoControl.OutputBufferLength is set to the size in bytes of a SERIAL_HANDFLOW structure.

Output

The AssociatedIrp.SystemBuffer points to a client-allocated SERIAL_HANDFLOW structure that Serial uses to output information about the configuration of handshake flow control.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of a SERIAL_HANDFLOW structure. Otherwise, the Information member is set to zero.

The Status member is set to one of the generic status values.


IOCTL_SERIAL_GET_LINE_CONTROL

Operation

The IOCTL_SERIAL_GET_LINE_CONTROL request returns information about the line control set for a COM port. The line control parameters include the number of stop bits, the number of data bits, and the parity.

To configure the line control, a client can use an IOCTL_SERIAL_SET_LINE_CONTROL request.

For information on valid line control register settings, see the constants SERIAL_5_DATA through SERIAL_PARITY_MASK, which are defined in the include file \src\kernel\serial.h in the Windows DDK.

Input

The Parameters.DeviceIoControl.OutputBufferLength is set to the size in bytes of a SERIAL_LINE_CONTROL structure.

Output

The AssociatedIrp.SystemBuffer points to a client-allocated SERIAL_LINE_CONTROL structure that Serial uses to output information about the line control configuration.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of a SERIAL_LINE_CONTROL structure. Otherwise, the Information member is set to zero.

The Status member is set to one of the generic status values.


IOCTL_SERIAL_GET_MODEM_CONTROL

Operation

The IOCTL_SERIAL_GET_MODEM_CONTROL request returns the value of the modem control register.

To set the modem control register, a client can use an IOCTL_SERIAL_SET_MODEM_CONTROL request.

For information on modem control register settings, see the constants SERIAL_MCR_DTR through SERIAL_MCR_LOOP, which are defined in the include file \src\kernel\serial\serial.h in the Windows DDK.

Input

The Parameters.DeviceIoControl.OutputBufferLength is set to the size in bytes of a ULONG.

Output

The AssociatedIrp.SystemBuffer points to a client-allocated ULONG buffer that Serial uses to output the value of the modem control register.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of a ULONG. Otherwise, the Information member is set to zero.

The Status member is set to one of the generic status values.


IOCTL_SERIAL_GET_MODEMSTATUS

Operation

The IOCTL_SERIAL_GET_MODEMSTATUS request updates the modem status, and returns the value of the modem status register before the update.

Input

The Parameters.DeviceIoControl.OutputBufferLength is set to the size in bytes of a ULONG.

Output

The AssociatedIrp.SystemBuffer points to a client-allocated ULONG buffer that Serial uses to output the value of the modem status register.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of a ULONG. Otherwise, the Information member is set to zero.

The Status member is set to one of the generic status values.


IOCTL_SERIAL_GET_PROPERTIES

Operation

The IOCTL_SERIAL_GET_PROPERTIES request returns information about the capabilities of a COM port.

Input

The Parameters.DeviceIoControl.OutputBufferLength is set to the size in bytes of a SERIAL_COMMPROP structure.

Output

The AssociatedIrp.SystemBuffer points to a client-allocated SERIAL_COMMPROP structure that Serial uses to output information about the capabilities of the COM port.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of a SERIAL_COMMPROP structure. Otherwise, the Information member is set to zero.

The Status member is set to one of the generic status values.


IOCTL_SERIAL_GET_STATS

Operation

The IOCTL_SERIAL_GET_STATS request returns information about the performance of a COM port. The statistics include the number of characters transmitted, the number of characters received, and useful error statistics. The driver continuously increments performance values.

To reset the performance values to zero, a client can use an IOCTL_SERIAL_CLEAR_STATS request.

Input

The Parameters.DeviceIoControl.OutputBufferLength member is set to the size in bytes of a SERIALPERF_STATS structure.

Output

The AssociatedIrp.SystemBuffer member points to a client-allocated SERIALPERF_STATS structure that Serial uses to output performance information.

I/O Status Block

If the request succeeds, the Information member is set to the size in bytes of a SERIALPERF_STATS structure. Otherwise, the Information member is set to zero.

The Status member is set to one of the generic status values.


IOCTL_SERIAL_GET_TIMEOUTS

Operation

The IOCTL_SERIAL_GET_TIMEOUTS request returns the timeout values that Serial uses with read and write requests.

To set timeouts, a client can use an IOCTL_SERIAL_SET_TIMEOUTS request.

For more information on timeouts, see Read and Write Timeouts for a COM Port.

Input

The Parameters.DeviceIoControl.OutputBufferLength is set to the size in bytes of a SERIAL_TIMEOUTS structure.

Output

The AssociatedIrp.SystemBuffer points to a client-allocated SERIAL_TIMEOUTS structure that Serial uses to output information about read and write timeout values.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of a SERIAL_TIMEOUTS structure. Otherwise, the Information member is set to zero.

The Status member is set to one of the generic status values.


IOCTL_SERIAL_GET_WAIT_MASK

Operation

The IOCTL_SERIAL_GET_WAIT_MASK request returns the event wait mask that is currently set on a COM port.

A client can wait on the wait events SERIAL_EV_RXCHAR through SERIAL_EV_EVENT2 that are defined in the include file ntddser.h in the Windows DDK.

To set an event wait mask, a client can use an IOCTL_SERIAL_SET_WAIT_MASK request. To wait for the occurrence of a wait event, a client uses an IOCTL_SERIAL_WAIT_ON_MASK request.

Input

The Parameters.DeviceIoControl.OutputBufferLength is set to the size in bytes of a ULONG.

Output

The AssociatedIrp.SystemBuffer points to a client-allocated ULONG buffer that Serial uses to output the wait mask. The wait mask is zero or a logical OR of one or more of the wait events SERIAL_EV_RXCHAR through SERIAL_EV_EVENT2 that are defined in the include file ntddser.h in the Windows DDK.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of a ULONG. Otherwise, the Information member is set to zero.

The Status member is set to one of the generic status values.


IOCTL_SERIAL_IMMEDIATE_CHAR

Operation

The IOCTL_SERIAL_IMMEDIATE_CHAR request causes a specified character to be transmitted as soon as possible. The immediate character request completes immediately after any other write that might be in progress. Only one immediate character request can be pending at a time.

Input

The AssociatedIrp.SystemBuffer points to the UCHAR value to transmit immediately.

The Parameters.DeviceIoControl.InputBufferLength is set to the size in bytes of an UCHAR.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of a UCHAR. Otherwise, Information is set to zero.

The Status member is set to one of generic status values. A status of STATUS_INVALID_PARAMETER indicates that a previous immediate character request is pending.


IOCTL_SERIAL_LSRMST_INSERT

Operation

The IOCTL_SERIAL_LSRMST_INSERT request enables or disables the insertion of information about line status and modem status in the receive data stream. If LSRMST insertion is enabled, the driver inserts event information for the supported event types. The event information includes an event header followed by event-specific data. The event header contains a client-specified escape character and a flag that identifies the event. The driver supports the following event types:

SERIAL_LSRMST_LSR_DATA
A change occurred in the line status. Serial inserts an event header followed by the event-specific data, which is the value of the line status register followed by the character present in the receive hardware when the line-status change was processed.
SERIAL_LSRMST_LSR_NODATA
A line status change occurred, but no data was available in the receive buffer. Serial inserts an event header followed by the event-specific data, which is the value of the line status register when the line status change was processed.
SERIAL_LSRMST_MST
A change occurred in the modem status. Serial inserts an event header followed by the event-specific data, which is the value of the modem status register when the modem-status change was processed.
SERIAL_LSRMST_ESCAPE
Indicates that the next character in the receive data stream, which was received from the device, is identical to the client-specified escape character. Serial inserts an event header. There is no event-specific data.

Input

The AssociatedIrp.SystemBuffer member points to a client-allocated UCHAR that is used to input an escape character. If the escape character is nonNULL, insertion is enabled, and the serial driver uses the specified escape character. Otherwise, insertion is disabled.

The Parameters.DeviceIoControl.InputBufferLength is set to the size in bytes of an UCHAR.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of a UCHAR. Otherwise, Information is set to zero.

The Status member is set to one of the generic status values. A status of STATUS_INVALID_PARAMETER indicates that the specified escape character is the same as the XON or the XOFF character, or that error replacement is enabled with handshake flow control.


IOCTL_SERIAL_PURGE

Operation

The IOCTL_SERIAL_PURGE request cancels the specified requests and deletes data from the specified buffers. The purge request can be used to cancel all read requests and write requests and to delete all data from the read buffer and the write buffer.

The completion of the purge request does not indicate that the requests cancelled by the purge request are completed. A client must verify that the purged requests are completed before the client frees or reuses the corresponding IRPs.

Input

The AssociatedIrp.SystemBuffer member points to a client-allocated ULONG that is used to input a purge mask. The client sets the purge mask to a logical OR of one or more of the following purge flags:

SERIAL_PURGE_RXABORT
Purges all read requests.
SERIAL_PURGE_RXCLEAR
Purges the receive buffer, if one exists.
SERIAL_PURGE_TXABORT
Purges all write requests.
SERIAL_PURGE_TXCLEAR
Purges the write buffer, if one exists.

The Parameters.DeviceIoControl.InputBufferLength is set to the size in bytes of a ULONG.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of a ULONG. Otherwise, the Information member is set to zero.

The Status member is set to one of the generic status values. A status of STATUS_INVALID_PARAMETER indicates that the purge mask is not valid.


IOCTL_SERIAL_RESET_DEVICE

Operation

The IOCTL_SERIAL_RESET_DEVICE request resets a COM port.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values.


IOCTL_SERIAL_SET_BAUD_RATE

Operation

The IOCTL_SERIAL_SET_BAUD_RATE request sets the baud rate on a COM port. Serial verifies the specified baud rate.

To obtain the baud rate, a client can use an IOCTL_SERIAL_GET_BAUD_RATE request.

For more information on the baud rates that the driver supports, see the baud rate constants SERIAL_BAUD_075 through SERIAL_BAUD_115200, which are defined in the include file ntddser.h in the Windows DDK.

Input

The AssociatedIrp.SystemBuffer member points to a SERIAL_BAUD_RATE structure that a client allocates and sets to input the baud rate.

The Parameters.DeviceIoControl.InputBufferLength member is set to the size in bytes of a SERIAL_BAUD_RATE structure.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values.


IOCTL_SERIAL_SET_BREAK_OFF

Operation

The IOCTL_SERIAL_SET_BREAK_OFF request sets the line control break signal inactive.

To set the line control break signal active, a client can use an IOCTL_SERIAL_SET_BREAK_ON request.

I/O Status Block

The Information member is set to zero.

The Status member is to one of the generic status values.


IOCTL_SERIAL_SET_BREAK_ON

Operation

The IOCTL_SERIAL_SET_BREAK_ON request sets the line control break signal active.

To set the line control break signal inactive, a client can use an IOCTL_SERIAL_SET_BREAK_OFF request.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values.


IOCTL_SERIAL_SET_CHARS

Operation

The IOCTL_SERIAL_GET_CHARS request sets the special characters that Serial uses for handshake flow control. Serial verifies the specified special characters.

To obtain the special characters, a client can use an IOCTL_SERIAL_GET_CHARS request.

Input

The AssociatedIrp.SystemBuffer member points to a client-allocated SERIAL_CHARS structure that is used to input special characters.

The Parameters.DeviceIoControl.InputBufferLength member is set to the size in bytes of a SERIAL_CHARS structure.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic values. A status of STATUS_INVALID_PARAMETER indicates that XoffChar equals XonChar, or that one of them equals the handshake flow control escape character.


IOCTL_SERIAL_SET_DTR

Operation

The IOCTL_SERIAL_SET_DTR request sets DTR (data terminal ready).

If the handshake flow control of the device is configured to automatically use DTR, a client can not clear or set DTR.

To clear DTR, a client can use an IOCTL_SERIAL_CLR_DTR request.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic values. A status of STATUS_INVALID_PARAMETER indicates that the handshake flow control of the device is set to automatically use DTR.


IOCTL_SERIAL_SET_FIFO_CONTROL

Operation

The IOCTL_SERIAL_SET_INFO_CONTROL request sets the FIFO control register (FCR). Serial does not verify the specified FIFO control information.

Input

The AssociatedIrp.SystemBuffer member points to a client-allocated ULONG that is used to input FIFO control information.

The Parameters.DeviceIoControl.InputBufferLength is set to the size in bytes of a ULONG.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values.


IOCTL_SERIAL_SET_HANDFLOW

Operation

The IOCTL_SERIAL_SET_HANDFLOW request sets the configuration of handshake flow control. Serial verifies the specified handshake flow control information.

To obtain handshake flow control information, a client can use an IOCTL_SERIAL_GET_HANDFLOW request.

For more information on settings for handshake flow control, see the handshake flow control parameters SERIAL_DTR_MASK through SERIAL_FLOW_INVALID, which are defined in the include file ntddser.h in the Windows DDK.

Input

The AssociatedIrp.SystemBuffer points to a client-allocated SERIAL_HANDFLOW structure that is used to input the handshake flow control information.

The Parameters.DeviceIoControl.InputBufferLength is set to the size in bytes of a SERIAL_HANDFLOW structure.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic values. A status of STATUS_INVALID_PARAMETER indicates the specified handshake flow control is not valid.


IOCTL_SERIAL_SET_LINE_CONTROL

Operation

The IOCTL_SERIAL_SET_LINE_CONTROL request sets the line control register (LCR). The line control register controls the data size, the number of stop bits, and the parity.

To obtain the value of the line control register, a client can use an IOCTL_SERIAL_GET_LINE_CONTROL request.

For information on valid line control register settings, see the constants SERIAL_5_DATA through SERIAL_PARITY_MASK, which are defined in the include file \src\kernel\serial.h in the Windows DDK.

Input

The AssociatedIrp.SystemBuffer points to a client-allocated SERIAL_LINE_CONTROL structure that is used to input line control information.

The Parameters.DeviceIoControl.InputBufferLength is set to the size in bytes of a SERIAL_LINE_CONTROL structure.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values. A status of STATUS_INVALID_PARAMETER indicates that the specified line control information is not valid.


IOCTL_SERIAL_SET_MODEM_CONTROL

Operation

The IOCTL_SERIAL_SET_MODEM_CONTROL request sets the modem control register. Parameter checking is not done.

To obtain the value of the modem control register, a client can use an IOCTL_SERIAL_GET_MODEM_CONTROL request.

For information on modem control register settings, see the constants SERIAL_MCR_DTR through SERIAL_MCR_LOOP, which are defined in the include file \src\kernel\serial\serial.h in the Windows DDK.

Input

The AssociatedIrp.SystemBuffer points to a client-allocated ULONG that is used to input modem control information.

The Parameters.DeviceIoControl.InputBufferLength is set to the size in bytes of a ULONG.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values.


IOCTL_SERIAL_SET_QUEUE_SIZE

Operation

The IOCTL_SERIAL_SET_QUEUE_SIZE request sets the size of the internal receive buffer. If the requested size is greater than the current receive buffer size, a new receive buffer is created. Otherwise, the receive buffer is not changed.

Input

The AssociatedIrp.SystemBuffer points to a client-allocated SERIAL_QUEUE_SIZE structure that is used to input a receive buffer size.

The Parameters.DeviceIoControl.InputBufferLength is set to the size in bytes of a SERIAL_QUEUE_SIZE structure.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values.


IOCTL_SERIAL_SET_RTS

Operation

The IOCTL_SERIAL_SET_RTS request sets RTS (request to send).

If a handshake flow control of the device is configured to automatically use RTS, a client can not clear or set RTS.

A client can use an IOCTL_SERIAL_CLR_RTS request to clear RTS.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values. A status of STATUS_INVALID_PARAMETER indicates that the handshake flow control of the device is set to automatically use RTS.


IOCTL_SERIAL_SET_TIMEOUTS

Operation

The IOCTL_SERIAL_SET_TIMEOUTS request sets the timeout values that the driver uses with read and write requests.

To obtain the timeout values, a client can use an IOCTL_SERIAL_GET_TIMEOUTS request.

For more information on timeouts, see Read and Write Timeouts for a COM Port.

Input

The AssociatedIrp.SystemBuffer points to a client-allocated SERIAL_TIMEOUTS structure that is used to input read and write timeout values.

The Parameters.DeviceIoControl.OutputBufferLength is set to the size in bytes of a SERIAL_TIMEOUTS structure.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values. A status of STATUS_INVALID_PARAMETER indicates that the read timeout values exceed the maximum permitted values.


IOCTL_SERIAL_SET_WAIT_MASK

Operation

The IOCTL_SERIAL_SET_WAIT_MASK request configures Serial to notify a client after the occurrence of any one of a specified set of wait events.

A client can wait on the events SERIAL_EV_RXCHAR through SERIAL_EV_EVENT2, which are defined in the include file ntddser.h in the Windows DDK. A client specifies wait events by setting an input event wait mask to a logical OR of one or more of the event flags. A client can clear all wait events by setting the input event wait mask to zero.

A client uses an IOCTL_SERIAL_WAIT_ON_MASK request to wait for the occurrence of a wait event. If a wait-on-mask request is already pending when a set-wait-mask request is processed, the pending wait-on-event request is completed with a status of STATUS_SUCCESS and the output wait event mask is set to zero.

Input

The AssociatedIrp.SystemBuffer points to a ULONG buffer that the client allocates and sets to an event wait mask. The wait mask is set to zero or a logical OR of one or more of the event flags.

The Parameters.DeviceIoControl.InputBufferLength is set to the size in bytes of a ULONG.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values. A status of STATUS_INVALID_PARAMETER indicates that the input wait mask is not valid.


IOCTL_SERIAL_SET_XOFF

Operation

The IOCTL_SERIAL_SET_XOFF request emulates the reception of an XOFF character. The request stops reception of data. If automatic XON/XOFF flow control is not set, then a client must use a subsequent IOCTL_SERIAL_SET_XON request to restart reception of data.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values.


IOCTL_SERIAL_SET_XON

Operation

The IOCTL_SERIAL_SET_XON request emulates the reception of a XON character, which restarts reception of data.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values.


IOCTL_SERIAL_WAIT_ON_MASK

Operation

The IOCTL_SERIAL_WAIT_ON_MASK request is used to wait for the occurrence of any wait event specified by using an IOCTL_SERIAL_SET_WAIT_MASK request. A wait-on-mask request is completed after one of the following events occurs:

  • A wait event occurs that was specified by the most recent set-wait-mask request.
  • An IOCTL_SERIAL_SET_WAIT_MASK request is received while a wait-on-mask request is pending. The driver completes the pending wait-on-mask request with a status of STATUS_SUCCESS and the output wait mask is set to zero.

A client can wait on the events SERIAL_EV_RXCHAR through SERIAL_EV_EVENT2, which are defined in the include file ntddser.h in the Windows DDK.

Input

The Parameters.DeviceIoControl.OutputBufferLength member is set to the size in bytes of a ULONG.

Output

AssociatedIrp.System buffer points to a ULONG buffer that holds an event wait mask. The event wait mask indicates which wait events occurred. The event wait mask is set to zero or a logical OR of one or more of the wait mask flags.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values. A status of STATUS_INVALID_PARAMETER indicates that no wait events are set, or a wait-on-mask request is already pending.


IOCTL_SERIAL_XOFF_COUNTER

Operation

The IOCTL_SERIAL_XOFF_COUNTER request sets an XOFF counter. An XOFF counter request supports clients that use software to emulate hardware handshake flow control.

An XOFF counter request is synchronized with write requests. The driver sends a specified XOFF character, and completes the request after one of the following events occurs:

  • A write request is received.
  • A timer expires (a timeout value is specified by the XOFF counter request).
  • Serial receives a number of characters that is greater than or equal to a count specified by the XOFF counter request.

For more information about the operation of an XOFF counter, see the description of the SERIAL_XOFF_COUNTER structure in the include file ntddser.h in the Windows DDK.

Input

The AssociatedIrp.SystemBuffer points to a client-allocated SERIAL_XOFF_COUNTER structure that is used to input XOFF counter information.

The Parameters.DeviceIoControl.InputBufferLength is set to the size in bytes of a SERIAL_XOFF_COUNTER structure.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the generic status values or to one of the following request-specific values:

STATUS_INVALID_PARAMETER
The count value specified for the XOFF counter request is less than zero.
STATUS_SERIAL_MORE_WRITES
A write request was received.
STATUS_SERIAL_COUNTER_TIMEOUT


Serial Internal Device Control Requests

This section describes the following internal device control requests that Serial supports:

IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS

IOCTL_SERIAL_INTERNAL_CANCEL_WAIT_WAKE

IOCTL_SERIAL_INTERNAL_DO_WAIT_WAKE

IOCTL_SERIAL_INTERNAL_RESTORE_SETTINGS

No other internal device control requests are supported.

These requests are provided for trusted kernel-mode drivers.

I/O Status Block

The setting of the I/O Status Block members is request-specific. If Serial does not support the request, it sets the Information member to zero and the Status member to STATUS_INVALID_PARAMETER.


IOCTL_SERIAL_INTERNAL_CANCEL_WAIT_WAKE

Operation

The IOCTL_SERIAL_INTERNAL_CANCEL_WAIT_WAKE request disables the wait/wake operation of a COM port.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the following status values:

STATUS_SUCCESS
STATUS_CANCELLED
STATUS_DELETE_PENDING
STATUS_PENDING


IOCTL_SERIAL_INTERNAL_DO_WAIT_WAKE

Operation

The IOCTL_SERIAL_INTERNAL_DO_WAIT_WAKE request enables the wait/wake operation of a COM port.

I/O Status Block

The Information member is set to zero.

The Status member is set to one of the following status values:

STATUS_SUCCESS
STATUS_CANCELLED
STATUS_DELETE_PENDING
STATUS_PENDING


IOCTL_SERIAL_INTERNAL_RESTORE_SETTINGS

Operation

The IOCTL_SERIAL_INTERNAL_RESTORE_SETTINGS request restores the specified operating mode of a COM port. The specified operating mode should be a mode that was returned by an IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS request. The operating mode settings should be treated as opaque. Serial does not verify the settings when the settings are restored. Note also that a replacement for Serial might implement a different set of parameters.

Input

The AssociatedIrp.SystemBuffer points to a client-allocated SERIAL_BASIC_SETTINGS structure that is used to input operating mode settings. The client should use settings that were returned by an IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS request.

The Parameters.DeviceIoControl.OutputBufferLength is set to the size in bytes of a SERIAL_BASIC_SETTINGS structure.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of SERIAL_BASIC_SETTINGS structure. Otherwise, the Information member is set to zero.

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_BUFFER_TOO_SMALL
The Parameters.DeviceIoControl.InputLength is less than the size in bytes of a SERIAL_BASIC_SETTINGS structure.
STATUS_CANCELLED
STATUS_DELETE_PENDING
STATUS_PENDING


Serenum Driver Reference

This section describes the following topics about Serenum, a Microsoft® Windows® 2000 and later system filter driver for RS-232 ports.

Serenum is a Plug and Play upper-level device filter driver that enumerates the following device types:

  • Plug and Play serial devices that comply with Plug and Play External COM Device Specification, Version 1.00, February 28, 1995
  • Pointer devices that comply with legacy mouse detection in Windows NT® 4.0 and earlier versions

Serenum is used with Serial, the Windows 2000 system function driver for COM ports. The combined operation of Serial and Serenum acts as a Plug and Play bus driver for a RS-232 port. Serenum can also be used with other RS-232 port drivers.

Serenum implements the Serenum service, and its executable image is serenum.sys.

The following topics describe the Serenum filter driver:

Serenum Device Control Requests

Serenum Internal Device Control Requests

For more information about Serenum operation, see the following:

Serial Devices and Drivers

Data definitions in the include file %install directory%\inc\ntddkser.h in the Windows 2000 DDK

Sample code in the %user install directory%\src\kernel\serenum directory in the Windows 2000 DDK

Include file %install directory%\src\kernel\serial\serial.h in the Windows 2000 DDK


Serenum Device Control Requests

This section describes the following device control requests that Serenum supports for a filter device object, or filter DO:

IOCTL_SERENUM_PORT_DESC

IOCTL_SERENUM_GET_PORT_NAME

For all other device control requests, Serenum skips the current IRP stack location, and sends the request down the device stack without further processing.

If Serenum receives a device control request for a physical device object, it routes the request to the filter DO.


IOCTL_SERENUM_PORT_DESC

Operation

The IOCTL_SERENUM_PORT_DESC request returns a description of the RS-232 port associated with a filter DO.

Input

Parameters.DeviceIoControl.InputBufferLength and Parameters.DeviceIoControl.OutputBufferLength are set to the size in bytes of a SERENUM_PORT_DESC structure.

The AssociatedIrp.SystemBuffer member is set to a pointer to a client-allocated buffer that is used to input and output a SERENUM_PORT_DESC structure. The client must set the Size member of the input structure to the size in bytes of a SERENUM_PORT_DESC structure.

Output

The AssociatedIrp.SystemBuffer member points to the client-allocated buffer that Serenum uses to output a SERENUM_PORT_DESC structure. Serenum sets the following members:

PortHandle
Specifies a pointer to the filter DO.
PortAddress
Specifies the base physical address of the RS-232 port.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of a SERENUM_PORT_DESC structure.

The Status member is set to one of the following values:

STATUS_SUCCESSSTATUS_DELETE_PENDING
STATUS_INVALID_PARAMETER
Parameters.DeviceIoControl.InputBufferLength, Parameters.DeviceIoControl.OutputBufferLength, or the Size member of the input structure is not equal to the size in bytes of a SERENUM_PORT_DESC structure.


IOCTL_SERENUM_GET_PORT_NAME

Operation

The IOCTL_SERENUM_GET_PORT_NAME request returns the value of the PortName (or Identifer) entry value for the RS-232 port.

Input

The Parameters.DeviceIoControl.OutputBufferLength member is set to the size in bytes of a client-allocated output buffer.

Output

The AssociatedIrp.SystemBuffer member points to a client-allocated buffer that Serenum uses to output the port name. The port name is a zero-terminated Unicode string.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of the zero-terminated Unicode string that is returned in the client's output buffer.

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_BUFFER_TOO_SMALL
The output buffer is too small to hold the port name string.
STATUS_UNSUCCESSFUL
An error occurred when opening the registry key for the device or reading the PortName (or Identifier) entry value.


Serenum Internal Device Control Requests

This section describes the following internal device control requests that Serenum supports for a physical device object, or PDO:

IOCTL_INTERNAL_SERENUM_REMOVE_SELF

Serenum sends all other internal device control requests down the device stack of the filter DO associated with the PDO. Serenum performs no further processing of the request. The request is completed by a lower-level driver in the device stack of the filter DO.

If Serenum receives an internal device control request for a filter DO, Serenum sends the request down the device stack of the filter DO without further processing.


IOCTL_INTERNAL_SERENUM_REMOVE_SELF

Operation

The IOCTL_INTERNAL_SERENUM_REMOVE_SELF request invalidates the bus relations of the filter DO that are associated with a target PDO. (Physically, this request invalidates the bus relations of the RS-232 port to which the target device is attached.)

I/O Status Block

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_DELETE_PENDING


Smart Card Drivers Overview

This overview describes the development of WDM and VxD smart card drivers. It describes:

  • The IOCTL interface for a smart card driver
  • The development of WDM and VxD smart card drivers
  • The use of the WDM and VxD smart card driver libraries

The following topics are covered:

Smart Card Driver Environment

Smart Card Driver IOCTL Codes

Smart Card Driver Data Structures

Smart Card Driver Libraries

WDM Smart Card Driver Registry Entries

VxD Smart Card Driver Registry Entries

Smart Card Driver Device Names

Smart Card Driver Debugging


Smart Card Driver Environment

The following figure illustrates the standard environment for a smart card driver. The driver resides in kernel space and is only called by the smart card resource manager that resides in user space. The interface used by the resource manager and the driver is based on IOCTL calls.


Smart Card Driver IOCTL Codes

This section describes the various IOCTL codes that are used to communicate with a smart card reader/card system.

VxD Note The smart card resource manager can communicate with WDM and VxD drivers. To have consistent error values from both drivers, use the NTSTATUS status values that are described in this document (the smart card libraries work with NTSTATUS status values, not with Win32® error values). The MapNtStatusToWinError (VxD) function can be used to map NTSTATUS status values to Win32 error values.

Usually, all parameters that come from a Win32 call to the driver are passed in a DIOCPARAMETERS structure. These parameters are transferred by the library to the internal structures of the SMARTCARD_EXTENSION structure. Use this structure to access all parameters.

For information on how to use the smart card driver libraries see:

WDM Smart Card Driver Library

VxD Smart Card Driver Library

These libraries provides support functions that simplify the development of smart card drivers.


Win32 IOCTL Calls

Use DeviceIoControl to call a driver from the Win32 environment.

BOOL
  DeviceIoControl(
    HANDLE  hDevice,
    DWORD  dwIoControlCode,
    LPVOID  lpInBuffer,
    DWORD  nInBufferSize,
    LPVOID  lpOutBuffer,
    DWORD  nOutBufferSize,
    LPDWORD  lpBytesReturned,
    LPOVERLAPPED  lpOverlapped
    );

Parameters

dwIoControlCode
Contains one of the control codes referred to in this document.
lpInBuffer
Contains either a minor I/O control code or data to be sent to a smart card.
nInBufferSize
The number of bytes to be sent to the card.
lpOutBuffer
Receives the result from the smart card.
nOutBufferSize
The size of the buffer.
lpBytesReturned
The number of bytes returned by this particular call.

Refer to the Platform SDK for more information and descriptions of the remaining parameters.


IOCTL Codes

The following table lists the available smart card IOCTL codes. With the exception of IOCTL_SMARTCARD_GET_LAST_ERROR, these codes apply to both WDM and VxD drivers.

IOCTL Code | Description
IOCTL_SMARTCARD_EJECT | Ejects the currently inserted smart card from the smart card reader.
IOCTL_SMARTCARD_GET_ATTRIBUTE | Queries smart card and smart card reader attributes.
IOCTL_SMARTCARD_GET_LAST_ERROR | VxD drivers only. Retrieves the error code of the last operation.
IOCTL_SMARTCARD_GET_STATE | Gets the current status of the smart card reader.
IOCTL_SMARTCARD_IS_ABSENT | Either returns immediately if no card is currently inserted, or installs an event handler to track card removals.
IOCTL_SMARTCARD_IS_PRESENT | Either returns immediately if no card is currently inserted, or installs an event handler to track card insertions.
IOCTL_SMARTCARD_POWER | Either powers down or warm resets the card.
IOCTL_SMARTCARD_SET_ATTRIBUTE | Sets various attributes in the driver.
IOCTL_SMARTCARD_SET_PROTOCOL | Sets the protocol to be used with the currently inserted card.
IOCTL_SMARTCARD_SWALLOW | Causes the reader to swallow the card.
IOCTL_SMARTCARD_TRANSMIT | Transmits data to and receives data from the currently inserted smart card.


Smart Card Driver Data Structures

The following table lists the data structures you can use to hold driver internal data. These structures are mandatory for the WDM and VxD Smart Card Driver Libraries.

Data Structure | Description
SCARD_CARD_CAPABILITIES | Holds all information about the currently inserted smart card.
SCARD_READER_CAPABILITIES | Holds state information about the reader.
T1_DATA | Used by the smart card driver library for processing T1 I/O.
SCARD_VENDOR_ATTR | Holds all information about the reader.
SMARTCARD_EXTENSION | Used by the driver to access all the previously listed data structures, and additional information. This structure is passed to all callback functions.

For information on how to use the smart card driver libraries see:

WDM Smart Card Driver Library

VxD Smart Card Driver Library


Smart Card Driver Libraries

The smart card driver libraries supports a driver in performing the following actions:

  • Creation of device names needed by the smart card resource manager
  • Parameter checking and error detection for IOCTL calls
  • ATR parsing and parameter conversion
  • Support for the ISO protocols T=0 and T=1
  • Support for inverse convention
  • Event logging
  • Synchronizing access to the driver

The smart card driver library consists of the following files.

File | Description
smclib.h | Contains driver-specific definitions.
smcnt.h | Contains operating-specific definitions for WDM drivers.
smcvxd.h | Contains operating-specific definitions for VxD drivers.
winsmcrd.h | Global include file for drivers and applications.
smclib.sys | The smart card driver library for WDM drivers.
smclib.vxd | The smart card driver library for VxD drivers.

For information on a specific library, see:

WDM Smart Card Driver Library

VxD Smart Card Driver Library


WDM Smart Card Driver Library

Every WDM driver needs the following routines:

  • DriverEntry
  • DriverUnload
  • Create and Close
  • Cleanup
  • DeviceControl

The DriverEntry routine creates a device that is used to talk to the reader and uses the support functions SmartcardLogError_(WDM) and SmartcardCreateLink (WDM). The DriverUnload function removes the driver from the system. The resource manager calls Create to establish a connection to the reader, and Cleanup is used to cancel pending I/O requests.

DeviceControl is the main entry point for smart card requests. If the driver is a lowest-level driver, it should also have a StartIo routine.

DeviceControl should immediately call the smart card driver library. If the library is unable to handle the call because this IOCTL call is driver-specific, the driver's callback for unknown IOCTL codes is called.

A driver's IOCTL function usually looks like the following:

NTSTATUS
DriverDeviceControl(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp
    )
{
    PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;

    return SmartcardDeviceControl(
        &(deviceExtension->SmartcardExtension),
        Irp
        );
}


VxD Smart Card Driver Library

The smart card driver library supports a driver in performing the following actions:

  • Creation of device names needed by the smart card resource manager
  • Card insertion and removal notification
  • Parameter checking and error detection for IOCTL calls
  • ATR parsing and parameter conversion
  • Support for the ISO protocols T=0 and T=1
  • Support for inverse convention
  • Event logging (future version of the library)
  • Synchronizing access to the driver

The smart card driver library is implemented as a single VxD. To call the library functions, use the interface that is implemented in the smcvxd.h header file.

Every driver needs the DriverName_DeviceIoControl VxD routine; it is the main entry point for smart card requests.

The library offers functionality that is common for all smart card drivers. The principle of the library is based on callbacks. This means when the driver's DriverName_DeviceIoControl routine is called, it calls the library function SmartcardDeviceControl (VxD) using VxDCall. This routine does parameter checking and returns either if the call is invalid or if the library can handle the call without the driver. Otherwise, it calls back one of the driver's functions.


Smart Card Driver IOCTL Calling Scheme

The following figure shows the calling scheme of an IOCTL call:

Smart Card Driver IOCTL Calling Scheme

This is the process that takes place in the calling scheme:

The resource manager calls the driver (1). The driver calls the library (2). The library checks the parameters of this call. If the driver's help is not needed to satisfy the call, the library returns the requested data, or an error code, to the caller (3a). If the driver's help is needed to satisfy the call, for example if I/O is required or if this is a vendor-specific call, the library calls the driver with all parameters set up correctly (3b). The driver performs I/O and uses support functions of the library (4 and 5). The driver then completes the request and returns the call to the resource manager (6).

The smart card library synchronizes access to your driver. No two callback functions will be called at the same time. However, card insertion and removal event handling must be processed asynchronously.


Smart Card Driver Library Function Reference

The following table lists the smart card driver library functions.

Function | Description
MapNtStatusToWinError (VxD) | Maps an NTSTATUS status code to a Win32® error code. Not available for WDM drivers.
SmartcardCompleteCardTracking (VxD) | Informs the caller of a card insertion or removal event. Not available for WDM drivers.
SmartcardCompleteRequest (VxD) | Informs the caller of the completion of a request, unlocks memory, and enables further calls to the smart card library. Not available for WDM drivers.
SmartcardCreateLink (WDM) -or- SmartcardCreateLink (VxD) | WDM: Creates a DOS device name that the smart card resource manager uses to access the driver. VxD: Creates a registry entry that is used by the smart card resource manager to access a device.
SmartcardDeleteLink (WDM) -or- SmartcardDeleteLink (VXD) | Deletes the link that was created with SmartcardCreateLink.
SmartcardDeviceControl (WDM) -or- SmartcardDeviceControl (VxD) | The main entry function for the smart card driver library. Performs parameter checking and completes calls that do not require I/O with the reader.
SmartcardExit (WDM) -or- SmartcardExit (VxD) | Frees buffers that were allocated during a call to SmartcardInitialize.
SmartcardInitialize (WDM) -or- SmartcardInitialize (VxD) | Allocates internal buffers for the library.
SmartcardLogError (WDM) | Writes an error message to the event log. Not available for VxD drivers.
SmartcardRawReply (WDM) -or- SmartcardRawReply (VxD) | Transfers the data received from the card to the user buffer.
SmartcardRawRequest (WDM) -or- SmartcardRawRequest (VxD) | Copies data from the user buffer to a send buffer.
SmartcardT0Reply (WDM) -or- SmartcardT0Reply (VxD) | Transfers the data received from the card to the user buffer.
SmartcardT0Request (WDM) -or- SmartcardT0Request (VxD) | Copies data from the user buffer to a send buffer.
SmartcardT1Reply (WDM) -or- SmartcardT1Reply (VxD) | Copies data from the user buffer to a send buffer and checks the T=1 protocol status.
SmartcardT1Request (WDM) -or- SmartcardT1Request (VxD) | Copies data from the user buffer to a send buffer and checks the T=1 protocol status.
SmartcardUpdateCardCapabilities_(WDM) -or- SmartcardUpdateCardCapabilities (VxD) | Translates an ATR string into the SCARD_CARD_CAPABILITIES structure that can be used by the driver.
VxD_CreateDevice (VxD) | Creates a new instance of a device. Not available for WDM drivers.
VxD_DeleteDevice (VxD) | Deletes a device that was created using VxD_CreateDevice. Not available for WDM drivers.


Smart Card Driver Library Callback Function Reference

The driver can set up several callback functions in the SMARTCARD_EXTENSION structure. The member ReaderFunction is an array of function pointers. Each array member is used for a specific callback. To set up one of these members, the driver has to assign a function pointer to the desired array member. For example:

SmartcardExtension->ReaderFunction[RDF_CARD_POWER] =
DriverCardPower;

This sets up a callback for the card power request. When the library receives such an IOCTL code, it sets up all parameters and then calls this function. If a member function is NULL, the driver will return STATUS_NOT_SUPPORTED to the caller. This is useful, for example, if your driver does not support card ejecting or card swallowing. If you do not set up a function for these calls, the library simply returns STATUS_NOT_SUPPORTED.


Smart Card Callback Parameters

Before the library calls a member function, it sets up the following members in the SMARTCARD_EXTENSION structure for every control request, except IOCTL_SMARTCARD_IS_ABSENT and IOCTL_SMARTCARD_IS_PRESENT.

Members | Description
IoRequest.RequestBuffer | Points to the user buffer that contains the user data to be sent to the card.
IoRequest.RequestBufferLength | The length of the user buffer.
IoRequest.ReplyBuffer | Points to the buffer that receives the data returned by the smart card.
IoRequest.ReplyBufferLength | The size of the reply buffer.
IoRequest.Information | Points to a ULONG that receives the number of bytes actually received from the card.
MajorIoControlCode | Contains the major I/O control code of this call.
MinorIoControlCode | Contains the minor I/O control code of this call (if any).

WDM Note In addition, the structure SmartcardExtension->OsData will be set up as follows:

Member | Description
CurrentIrp | Receives a pointer to the requesting IRP for every control request, except IOCTL_SMARTCARD_IS_ABSENT and IOCTL_SMARTCARD_IS_PRESENT.
NotificationIrp | Receives a pointer to the requesting IRP for the control request IOCTL_SMARTCARD_IS_ABSENT or IOCTL_SMARTCARD_IS_PRESENT.

The following table lists the callback function available from both libraries. Some functions are mandatory and others are optional. The driver needs to set up only mandatory functions. Every function that has not been set up will return STATUS_NOT_SUPPORTED to the smart card resource manager.

Callback Function | Description
RDF_CARD_POWER | Resets or powers down an inserted smart card.
RDF_CARD_EJECT | Ejects an inserted smart card.
RDF_CARD_TRACKING | Installs an event handler to track card insertions and removals.
RDF_IOCTL_VENDOR | Performs vendor-specific IOCTL operations.
RDF_READER_SWALLOW | Does a mechanical swallow.
RDF_SET_PROTOCOL | Selects a transmission protocol for the currently inserted card.
RDF_TRANSMIT | Performs data transmissions.

When calling these functions, the driver should retrieve calling parameters from the members described under Input Values. It should store data to the members described under Output Values in each reference page.

VxD Note If your driver returns STATUS_PENDING to any of the callbacks except RDF_CARD_TRACKING, the smart card library will refuse any further call to the driver and will return STATUS_DEVICE_BUSY. Call SmartcardCompleteRequest to finish a call that returned STATUS_PENDING. This function informs the caller of the completion and unlocks memory that had been locked by the smart card driver library. It also enables further requests to your driver.

If you do not call SmartcardCompleteRequest, the library will block any further call to your driver.


WDM Smart Card Driver Registry Entries

Each device driver needs several entries in the registry to make the driver visible to the device manager and to enable event logging.


Registering the Driver

To make the driver visible to the device manager, a driver needs to have the following entries in the registry under a specific path:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\SmartCardDriver

Start
DWORD:0x0000002

A value of 2 makes the driver start automatically. During development, it is recommended to use a Start value of 3, which makes the driver start manually.

Type
DWORD:0x0000001

A value of 1 identifies the driver as a kernel-mode driver.

Group
"Smart Card Reader"

Every driver has to be a member of the Group "Smart Card Reader", since the smart card resource manager waits for this group to start.

ErrorControl
DWORD:0x0000001

A value of 1 lets the system continue to boot even if the driver fails, but it shows an error message if the driver fails to load.


Enabling Smart Card Event Logging

Every driver must write event messages to the system event logger to give the system administrator enough information about why a driver is unable to work properly.

The event log needs an additional entry in the registry under:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\EventLog\System\SmartCardDriver

EventMessageFile
%SystemRoot%\System32\SmartCardDriver.sys

Note The registry path names never contain the extension of the file name. The EventMessageFile needs that extension.

TypesSupported
DWORD:0x00000007

For more information about specifying these registry entries, see INF AddService Directive.


VxD Smart Card Driver Registry Entries

To enable the smart card resource manager to access your device, a symbolic link is created in the registry under:

HKLM\System\CurrentControlSet\VxD\Scmlib\Devices

Each entry has the form:

SCReaderN=Driver.vxd

When you call SmartcardCreateLink (VxD), this entry is generated automatically. SmartcardDeleteLink (VxD) removes the entry.

The name that your driver supplies to SmartcardCreateLink must be either the full name of the driver, including the VXD extension, or the name that has been used in a call to VxD_CreateDevice (VxD).


Smart Card Driver Device Names

Every WDM and VxD device driver has two names. WDM device drivers use kernel device name and DOS device name while VxD device drivers use driver device name and link name.

WDM Device Driver Names

For WDM device drivers the kernel device name is the device name that is known only in the name space of the kernel. The DOS device name is the name that a Win32® application uses to communicate with the driver.

Kernel Device Name: The name that is known only in the kernel name space can be chosen by the driver developer, but it should follow the NT-based operating system's device name naming conventions, in which a device name looks like this:

\Device\DeviceName[Unit]

where DeviceName is a name that reflects the type of driver and Unit is the zero-based unit number of that driver. The unit number is used to distinguish the device if more than one device of that type is installed in a system.

DOS Device Name: Since every driver must communicate with the smart card resource manager, it must have a specific name for the Win32 name space. This name must be:

\DosDevices\SCReader[Unit]

The unit number does not need to be the same as the one for the kernel name space. It should be the first available unit number. Use SmartcardCreateLink (WDM) to generate the DOS device name. The smart card driver library is able to create such a name automatically.

VxD Device Driver Names

For VxD device drivers use the driver device name and the link name.

Driver Device Name: The driver device name is specific to the driver. As with every other VxD name, an application that needs to access a device needs to know the driver name in order to open the device. A device name usually looks like DEVICE.VXD.

Link Name: Since every driver must communicate with the smart card resource manager, the resource manager needs a way to map a generic name to a specific driver name. This mapping is done through the registry. The registry contains the generic name as the key to the specific driver name:

SCReader[Unit]

The smart card driver library is able to create such a name automatically.


Smart Card Driver Debugging

Both libraries supports several debugging features. These debugging features let you see what the library does internally and let you write debugging output to a connected debugger. For information on setting up a remote debugging session, see Debugging Tools for NT-Based Operating Systems. The header file smclib.h defines the following constants used for debugging:

#define DEBUG_IOCTL     ((ULONG) 0x00000001)
#define DEBUG_ATR       ((ULONG) 0x00000002)
#define DEBUG_PROTOCOL  ((ULONG) 0x00000004)
#define DEBUG_DRIVER    ((ULONG) 0x00000008)
#define DEBUG_TRACE     ((ULONG) 0x00000010)
#define DEBUG_ERROR     ((ULONG) 0x00000020)
#define DEBUG_BREAK     ((ULONG) 0x80000000)
#define DEBUG_ALL       ((ULONG) 0x7FFFFFFF)

These can be used to select the level of debugging that you want. You can either use the function,

SmartcardSetDebugLevel(
    ULONG DebugLevel
);

in your driver and provide a mask of constants that are combined with the bitwise OR operator to select the level of debugging that you want, or you can use the smart card driver test program scdrvtst that comes with the smart card DDK. Note that you must have installed the checked version of the operating system and the checked version of the driver to get debugging messages.

To write your own driver debugging messages, it is recommended that you use the function,

SmartcardDebug(
    ULONG DebugLevel,
    PCHAR Message
);

This lets you write messages to the remote debugger. To write error messages, use the constant DEBUG_ERROR for the DebugLevel. To write standard driver messages, use the constant DEBUG_DRIVER. To write trace messages, such as when entering and exiting a function, use DEBUG_TRACE as the DebugLevel.

It is recommended during development of your driver that you use the checked version of the smart card driver library and set the debugging level to the maximum using SmartcardSetDebugLevel(DEBUG_ALL) in your DriverEntry routine.


VxD Smart Card Driver Functions

This section describes the VxD Smart Card driver library functions you can use when developing a VxD Smart Card driver.

For a list of the functions that can be used when developing a WDM driver, see WDM Smart Card Driver Functions.


SmartcardCompleteCardTracking (VxD)

The SmartcardCompleteCardTracking function informs the caller of a card insertion or removal event.

VOID
  SmartcardCompleteCardTracking(
    IN PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Pointer to the smart card structure of the driver.

Return Value

None

Comments

Use this function to inform the caller that a smart card has been either inserted or removed. This function automatically unlocks memory that was locked before the callback function RDF_CARD_TRACKING was called. Use this function when your driver detects that a card has been inserted or removed and the structure member SmartcardExtension->OsData->NotificationOverlappedData is not NULL.

This function is not available when developing WDM drivers. For a list of the functions that can be used, see WDM Smart Card Driver Functions.


SmartcardCompleteRequest (VxD)

The SmartcardCompleteRequest function informs the caller of the completion of a request, unlocks memory, and enables further calls to the smart card library.

VOID
  SmartcardCompleteRequest(
    IN PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Pointer to the smart card structure of the driver.

Return Value

None

Comments

Use this function to inform the caller and the smart card library that a pending smart card I/O has been finished. If your driver is unable to satisfy a request immediately and one of your callbacks returns STATUS_PENDING, you must call this function at the end of the I/O with the reader. Use the structure member SmartcardExtension->IoRequest when you want to access the caller's memory area. This function automatically unlocks memory that was locked before the callback function was called. The following simplified example illustrates the use of this function:

DriverTransmitCallback(
    PSMARTCARD_EXTENSION SmartcardExtension
    )
{
    // Write data to the reader
    WriteDataToReader();

    // The reader will interrupt when data is available
    return STATUS_PENDING;
}

DriverInterrupt(..)
{
    // store incoming data into SmartcardExtension->IoRequest->ReplyBuffer
    ReadDataFromReader();

    // Now we're done with this request and can complete it.
    SmartcardCompleteRequest(SmartcardExtension);
}

This function is not available when developing WDM drivers. For a list of the functions that can be used, see WDM Smart Card Driver Functions.


SmartcardCreateLink (VxD)

The SmartcardCreateLink function creates a registry entry that is used by the smart card resource manager to access a device.

NTSTATUS
  SmartcardCreateLink(
    IN OUT PSTR  LinkName,
    IN PSTR  DeviceName
    );

Parameters

LinkName
Pointer to a 64-byte area that receives the result.
DeviceName
Pointer to the name of the device (the name of your VxD) for which the link should be created.

Comments

This function creates an entry in the registry that the smart card resource manager uses to access the device. The name is usually a string like SCReaderN, where N is a zero-based reader number. This function does not allocate a buffer to hold the link name. It is the responsibility of the driver to provide this 64-byte buffer.

It is strongly recommended that you use this function to create the link to your driver. Otherwise, the smart card resource manager will not be able to access your driver.

For information on the SmartcardCreateLink function for WDM drivers, see SmartcardCreateLink (WDM).


SmartcardDeleteLink (VxD)

The SmartcardDeleteLink function deletes the link that was created with SmartcardCreateLink (VxD).

NTSTATUS
  SmartcardDeleteLink(
    IN PSTR  LinkName
    );

Parameters

LinkName
Pointer to the name to be removed from the registry.

Comments

Use this function to remove the link to the driver from the registry when a dynamically loaded driver unloads.

This function is not available when developing WDM drivers. For a list of the functions that can be used, see WDM Smart Card Driver Functions.


SmartcardDeviceControl (VxD)

The SmartcardDeviceControl function is the main entry function for the smart card driver library. It checks parameters and completes calls that do not require I/O with the reader.

NTSTATUS
  SmartcardDeviceControl(
    IN PSMARTCARD_EXTENSION  SmartcardExtension,
    IN LPDIOC  DiocParams
    );

Parameters

SmartcardExtension
Pointer to the smart card structure of the driver.
DiocParams
Pointer to the requesting DIOCPARAMETERS structure.

Return Values

SmartcardDeviceControl returns the NTSTATUS value of the called routine.

Comments

The driver's DeviceControl routine must call this function to let the library check parameters and complete calls that do not need to do I/O with the reader.

The smart card driver library checks the version of the SMARTCARD_EXTENSION structure. Before calling SmartcardDeviceControl, the driver must assign the Version member of SMARTCARD_EXTENSION the value SMCLIB_VERSION. This is usually done in the DriverEntry routine.

A DeviceControl function should look like the following:

DWORD
DriverName_DeviceIoControl(
  DWORD  dwService,
  DWORD  dwDDB,
  DWORD  hDevice,
  LPDIOC lpDiocParms)
)
{
    NTSTATUS status;

    // Let the library check parameters
    // If the library requires the help of the driver it'll call
    // the driver using a call back mechanism
    status = SmartcardDeviceControl(
        &SmartcardExtension,
        lpDiocParams
        );

    return MapNtStatusToWinError(status);
}

For information on the SmartcardDeviceControl function for WDM drivers, see SmartcardDeviceControl (WDM).


SmartcardExit (VxD)

The SmartcardExit function frees buffers that were allocated during a call to SmartcardInitialize (VxD).

VOID
  SmartcardExit(
    IN PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Pointer to the smart card extension of the device.

Return Value

None

Comments

The library allocates internal buffers during a call to SmartcardInitialize (VxD). SmartcardExit frees these buffers.

SmartcardExit functions the same for WDM and VxD drivers.


SmartcardInitialize (VxD)

The SmartcardInitialize function allocates internal buffers for the library.

NTSTATUS
  SmartcardInitialize(
    IN PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Pointer to the smart card extension of the device.
SmartcardExtension->SmartcardRequest.BufferSize
This value must be set to the number of bytes to be allocated for the request buffer. The minimum size for this buffer is MIN_BUFFER_SIZE. If this value is smaller, MIN_BUFFER_SIZE will be allocated automatically.
SmartcardExtension->SmartcardReply.BufferSize
This value must be set to the number of bytes to be allocated for the receive buffer. The minimum size for this buffer is MIN_BUFFER_SIZE. If this value is smaller, MIN_BUFFER_SIZE will be allocated automatically.

Return Values

SmartcardInitialize returns an NTSTATUS value.

Value | Meaning
STATUS_INSUFFICIENT_RESOURCES | Out of memory

Comments

The library uses internal buffers for sending SmartcardExtension->SmartcardRequest.Buffer and receiving SmartcardExtension->SmartcardReply.Buffer data. SmartcardInitialize allocates these buffers. Call SmartcardExit_(VxD) in your DriverUnload routine to free these internal buffers. Your driver should use those buffers for transferring data to and from the card.

The smart card driver library checks the version of the SMARTCARD_EXTENSION structure. Before calling SmartcardInitialize, the driver must assign to the Version member of SMARTCARD_EXTENSION the value SMCLIB_VERSION. This is usually done in the DriverEntry routine.

SmartcardInitialize functions the same for WDM and VxD drivers.


SmartcardInvertData(VxD)

Previous Next

SmartcardInvertData (VxD)

The SmartCardInvertData function converts the passed buffer from inverse to direct or vice-versa.

This function performs the same for WDM and VxD drivers.

VOID
  SmartcardInvertData(
    PUCHAR  Buffer,
    ULONG  Length
    );

Parameters

Buffer
Pointer to the buffer for which the data will be inverted.
Length
Length of the buffer in characters.

Return Value

None


SmartcardRawReply (VxD)

The SmartcardRawReply function transfers the data received from the card to the user buffer.

NTSTATUS
  SmartcardRawReply(
    PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Pointer to the smart card extension of the device.

Return Values

SmartcardRawReply returns an NTSTATUS value. Possible values are the following.

Value | Meaning
STATUS_SUCCESS | Transmission successful.
STATUS_BUFFER_TOO_SMALL | The user buffer is too small to hold the data.

Comments

The driver must store the data coming from the reader into SmartcardExtension->SmartcardReply.Buffer and store the number of bytes returned from the card into SmartcardExtension->SmartcardReply.BufferLength. SmartcardRawReply then checks the validity of the data and copies the buffer back to the user buffer, including the protocol header.

SmartcardRawReply functions the same for WDM and VxD drivers.


SmartcardRawRequest (VxD)

The SmartcardRawRequest function copies data from the user buffer to the send buffer that the driver uses to transmit data to the reader.

NTSTATUS
  SmartcardRawRequest(
    PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Pointer to the smart card extension of the device.

Return Values

SmartcardRawRequest returns an NTSTATUS value. Possible values are the following.

Value | Meaning
STATUS_SUCCESS | Buffer successfully set up.
STATUS_BUFFER_OVERFLOW | The internal buffer is too small to hold the data to send to the smart card. To fix this error, allocate a larger send buffer. See SmartcardInitialize (VxD) for details.
STATUS_BUFFER_TOO_SMALL | The user buffer is too small to hold the data.

Comments

This function copies data from the user buffer to SmartcardExtension->SmartcardRequest.Buffer and adjusts SmartcardExtension->SmartcardRequest.BufferLength to the number of bytes to be transmitted to the smart card. The driver then simply writes this buffer to the card and reads the bytes coming from the card into SmartcardExtension->SmartcardReply.Buffer, as described in SmartcardRawReply (WDM).

For information on the SmartcardRawRequest function for VxD drivers, see SmartcardRawRequest (VxD).


SmartcardT0Reply (VxD)

The SmartcardT0Reply function transfers the data received from the card to the user buffer.

NTSTATUS
  SmartcardT0Reply(
    PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Pointer to the smart card extension of the device.

Return Values

SmartcardT0Reply returns an NTSTATUS value. Possible values are the following.

Value | Meaning
STATUS_SUCCESS | Transmission successful.
STATUS_DEVICE_PROTOCOL_ERROR | The card did not return a T=0 status word.
STATUS_BUFFER_TOO_SMALL | The user buffer is too small to hold the data.

Comments

The driver must store the data coming from the reader into SmartcardExtension->SmartcardReply.Buffer and store the number of bytes returned from the card into SmartcardExtension->SmartcardReply.BufferLength. SmartcardT0Reply then checks the validity of the data and copies the buffer back to the user buffer, including the protocol header. See SmartcardT0Request (VxD) for sample code.

SmartcardT0Reply functions the same for WDM and VxD drivers.


SmartcardT0Request (VxD)

The SmartcardT0Request function copies data from the user buffer to the send buffer that the driver uses to transmit data to the reader.

NTSTATUS
  SmartcardT0Request(
    PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Pointer to the smart card extension of the device.

Return Values

SmartcardT0Request returns an NTSTATUS value. Possible values are the following.

Value | Meaning
STATUS_SUCCESS | Buffer successfully set up.
STATUS_BUFFER_OVERFLOW | The internal buffer is too small to hold the data to send to the smart card. To fix this error, allocate a larger send buffer. See SmartcardInitialize for details.

Comments

This function copies data from the user buffer to SmartcardExtension->SmartcardRequest.Buffer and adjusts SmartcardExtension->SmartcardRequest.BufferLength to the number of bytes to be transmitted to the smart card. The driver then simply writes this buffer to the card and reads the bytes coming from the card into SmartcardExtension->SmartcardReply.Buffer, as described in SmartcardT0Reply (VxD).

If your driver needs to send header data to the reader before the actual T=0 data, set SmartcardExtension->SmartcardRequest.BufferLength to the number of bytes you need for your header before you call this function. The packet will look like this:

You can copy your header data to the buffer either before or after a call to SmartcardT0Request, depending on which is easier to do in your driver.

A usual T=0 transmission can be done in the following way:

// Copy data from user buffer to SmartcardExtension->SmartcardRequest.Buffer
status = SmartcardT0Request(
        SmartcardExtension
        );
if (status != STATUS_SUCCESS)
    return status;

// Transmit SmartcardExtension->SmartcardRequest.Buffer to smart card
status = DriverSendDataToSmartcard(…);
if (status != STATUS_SUCCESS)
return status;

// Receive data from smart card into SmartcardExtension->SmartcardReply.Buffer
status = DriverReceiveDataFromSmartcard(…);
if (status != STATUS_SUCCESS)
    return status;

// Copy data from SmartcardExtension->SmartcardReply.Buffer back to user buffer
// and return to caller
return SmartcardT0Reply(
SmartcardExtension
);

SmartcardT0Reply does not handle the T=0 protocol data exchange for VxD drivers. Refer to the driver example scrcp8t.c, which is part of the DDK, or refer to ISO 7816 part 3, section 8.

For information on the SmartcardT0Request function for WDM drivers, see SmartcardT0Request (WDM).


SmartcardT1Reply (VxD)

The SmartcardT1Reply function copies data from the receive buffer to the user buffer and checks the T=1 protocol status.

NTSTATUS
  SmartcardT1Reply(
    PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Pointer to the smart card extension of the device.

Return Values

SmartcardT1Reply returns an NTSTATUS value. Possible values are the following.

Value | Meaning
STATUS_SUCCESS | Transmission successful.
STATUS_DEVICE_PROTOCOL_ERROR | Too many transmission errors.
STATUS_BUFFER_TOO_SMALL | The user buffer is too small to hold the data.
STATUS_MORE_PROCESSING_REQUIRED | The protocol requires additional transmissions.

Comments

SmartcardT1Reply must be called after the driver has received data coming from the smart card. The driver must store received smart card data in SmartcardExtension->SmartcardReply.Buffer and the number of received bytes in SmartcardExtension->SmartcardReply.BufferLength. SmartcardT1Reply checks the protocol status and copies any smart card data to the user buffer. If the transmission is not yet finished, SmartcardT1Reply returns STATUS_MORE_PROCESSING_REQUIRED, indicating the necessity to call SmartcardT1Request (VxD) again, which sets up a new buffer to be sent to the smart card.

SmartcardT1Reply functions the same for WDM and VxD drivers.


SmartcardT1Request (VxD)

The SmartcardT1Request function copies data from the user buffer to a send buffer and checks the T=1 protocol status.

NTSTATUS
  SmartcardT1Request(
    PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Pointer to the smart card extension of the device.

Return Values

SmartcardT1Request returns an NTSTATUS value. Possible values are the following.

Value | Meaning
STATUS_SUCCESS | Buffer successfully set up.

Comments

Do not change any members of the T1_DATA structure. They will be initialized automatically. The only member that can be safely modified is the NAD value. Changing any member might lead to protocol errors.

SmartcardT1Request copies the data from the user buffer to SmartcardExtension->SmartcardRequest.Buffer embedded in a T=1 protocol frame and adjusts SmartcardExtension->SmartcardRequest.BufferLength. The driver must send this buffer to the smart card and read the answer of the card into SmartcardExtension->SmartcardReply.Buffer. The driver must then call SmartcardT1Reply (VxD), which checks the incoming protocol frame.

You can copy your header data to the buffer either before or after a call to SmartcardT1Request, depending on which is easier to do in your driver. If your driver needs to send header data to the reader before the actual T=1 data, you should set SmartcardExtension->SmartcardRequest.BufferLength to the number of bytes you need for your header before you call this function. The packet will look like this:

A usual T=1 transmission can be done in the following way:

// Run this loop as long as the protocol requires to send data
do {
    // Copy data to SmartcardExtension->SmartcardRequest.Buffer
    // embedded in a T=1 frame
    status = SmartcardT1Request(SmartcardExtension);
    if (status != STATUS_SUCCESS)
        return status;

    // Send T=1 frame to smart card
    status = DriverSendDataToSmartcard(…);
    if (status != STATUS_SUCCESS)
        return status;

// Now set appropiate timeout (This example calculates. the time-out in ms)
// Timeout = SmartcardExtension->CardCapabilities.T1.BWT *
//    (SmartcardExtension->T1.Wtx ? SmartcardExtension->T1.Wtx : 1);

    // receive T=1 frame from smart card
    status = DriverReceiveDataFromSmartcard(…);
    if (status != STATUS_SUCCESS)
        return status;

    // Check T=1 protocol status and copy any data back to user buffer
    status = SmartcardT1Reply(SmartcardExtension);

} while (status == STATUS_MORE_PROCESSING_REQUIRED);

return status;

SmartcardT1Request functions the same for WDM and VxD drivers.


SmartcardUpdateCardCapabilities (VxD)

The SmartcardUpdateCardCapabilities function translates an ATR string into the SCARD_CARD_CAPABILITIES structure that can be used by the driver.

NTSTATUS
  SmartcardUpdateCardCapabilities(
    PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Pointer to the smart card extension of the device.

Return Values

SmartcardUpdateCardCapabilities returns an NTSTATUS value. Possible values are the following.

Value | Meaning
STATUS_SUCCESS | ATR successfully translated.
STATUS_UNRECOGNIZED_MEDIA | The ATR neither starts with 0x3B nor 0x3F. It is also possible that the ATR contains non-ISO-conforming values for Fl or Dl, or the ATR checksum for T=1 is wrong.

Comments

This function should be called by the driver just after the driver has read the ATR into the ATR member of the SCARD_CARD_CAPABILITIES structure. The ATR bytes must be stored in Buffer, and Length must be adjusted to the actual length of the ATR returned by the card.

This function can handle only T=0 and T=1 cards.

//
// Answer To Reset string returned by card.
//
struct {
    UCHAR Buffer[64];
    UCHAR Length;
} ATR;

The function converts the ATR string into the values defined by ISO 7816-3. These values are all stored in the SCARD_CARD_CAPABILITIES structure. All time values in that structure are in microseconds, not in seconds.

SmartcardUpdateCardCapabilities functions the same for WDM and VxD drivers.


MapNtStatusToWinError (VxD)

The MapNtStatusToWinError function maps a NT status code to a Win32® error code.

ULONG
  MapNtStatusToWinError(
    NTSTATUS  Status
    );

Parameters

Status
The NT status value that is to be translated into a Win32 error code.

Return Values

MapNtStatusToWinError returns the translated Win32 error code.

Comments

Internally, your driver should work with NT status values and not with Win32 error codes. The smart card resource manager, however, needs Win32 error codes. You can use this function in your device I/O control routine to map the NT status value to a Win32 error code. Following is an example:

DWORD
DriverName_DeviceIoControl(
  DWORD  dwService,
  DWORD  dwDDB,
  DWORD  hDevice,
  LPDIOC lpDiocParms)
)
{
    NTSTATUS status;

    // Let the library do parameter checking
    // If the library requires the help of the driver it'll call
    // the driver using a call back mechanism
    status = SmartcardDeviceControl(
        &SmartcardExtension,
        lpDiocParams
        );

    return MapNtStatusToWinError(status);
}

This function is not available when developing WDM drivers. For a list of the functions that can be used, see WDM Smart Card Driver Functions.


VxD_CreateDevice (VxD)

The VxD_CreateDevice function creates a new instance of a device. This function can be used if your driver supports multiple devices of the same type (for example, serial smart card reader).

PVMMDDB VXDINLINE
  VxD_CreateDevice(
    char  *Device,
    void  (*ControlProc)(void)
    );

Parameters

Device
The name of the device to be created. Should not exceed eight characters.
ControlProc
The address of your driver's control procedure (usually located in an assembly language module). Do not confuse this with the driver's DeviceIoControl procedure.

Return Values

VxD_CreateDevice returns a pointer to a device description block.

Comments

Store the returned device description block in the operating-system-dependent data structure of your device extension. You can use this value in your DeviceIoControl routine to distinguish the device instance, since you should usually use the same DeviceIoControl routine for all your instances.

This function is not available when developing WDM drivers. For a list of the functions that can be used, see WDM Smart Card Driver Functions.


VxD_DeleteDevice (VxD)

The VxD_DeleteDevice function deletes a device that was created using VxD_CreateDevice (VxD).

BOOL VXDINLINE
  VxD_DeleteDevice(
    PVMMDDB  DDB
    );

Parameters

DDB
The device description block that was returned by a call to VxD_CreateDevice.

Return Values

VxD_DeleteDevice returns TRUE if the device has been successfully deleted.

Comments

Use this function only in your driver's exit routine to delete all additional device instances.

This function is not available when developing WDM drivers. For a list of the functions that can be used, see WDM Smart Card Driver Functions.


WDM Smart Card Driver Functions

This section describes the WDM Smart Card driver library functions you can use when developing a WDM Smart Card driver.

For a list of the functions that can be used when developing a VxD driver, see VxD Smart Card Driver Functions.


SmartcardAcquireRemoveLock(WDM)

SmartcardAcquireRemoveLock is used to increment a reference count to the driver.

NTSTATUS
  SmartcardAcquireRemoveLock(
    IN PSMARTCARD_EXTENSION  SmartcardExtension
    );

Comments

The function returns STATUS_SUCCESS if the lock has been successfully acquired. The function returns STATUS_DELETE_PENDING if the driver is about to unload. In this case, no further code should be executed. Instead, the function that called SmartcardAcquireRemoveLock should return immediately. SmartcardAcquireRemoveLock should be called whenever an entry point function to the driver is called (e.g. DeviceIoControl). This function ensures that the driver does not unload while some other driver code is being executed.


SmartcardCreateLink (WDM)

The SmartcardCreateLink function creates a DOS device name that the smart card resource manager uses to access the device.

NTSTATUS
  SmartcardCreateLink(
    IN OUT PUNICODE_STRING  LinkName,
    IN PUNICODE_STRING  DeviceName
    );

Parameters

LinkName
Pointer to an uninitialized UNICODE_STRING that receives the result.
DeviceName
Pointer to an existing device name for which the link should be created.

Comments

SmartcardCreateLink creates a DOS device name and a symbolic link that the smart card resource manager can access. The name is usually a string like \DosDevices\SCReaderN, where N is a zero-based reader number. This function allocates a buffer that is large enough to hold the DOS device name. It is not necessary to provide a buffer. When the driver unloads the buffer, LinkName->Buffer must be freed. This function is commonly used in the DriverEntry routine.

For information on the SmartcardCreateLink function for VxD drivers, see SmartcardCreateLink (VxD).


SmartcardDeleteLink (WDM)

The SmartcardDeleteLink function deletes the link that was created with SmartcardCreateLink (WDM).

NTSTATUS
  SmartcardDeleteLink(
    IN PUNICODE_STRING  LinkName
    );

Parameters

LinkName
Pointer to the name to be removed from the registry.

Comments

Use this function to remove the link to the driver from the registry when a dynamically loaded driver unloads.

For information on the SmartcardDeleteLink function for VxD drivers, see SmartcardDeleteLink (VxD).


SmartcardDeviceControl (WDM)

The SmartcardDeviceControl function is the main entry function for the smart card driver library. It performs parameter checking and completes calls that do not require I/O with the reader.

NTSTATUS
  SmartcardDeviceControl(
    IN PSMARTCARD_EXTENSION  SmartcardExtension,
    IN PIRP  Irp
    );

Parameters

SmartcardExtension
Pointer to the smart card structure of the driver.
Irp
Pointer to the requesting IRP.

Return Values

SmartcardDeviceControl returns the NTSTATUS value of the called routine.

Comments

The driver's DeviceControl routine must call this function to let the library check parameters and complete calls that do not need to do I/O with the reader.

The smart card driver library checks the version of the SMARTCARD_EXTENSION structure. Before calling SmartcardDeviceControl, the driver must assign to the Version member of SMARTCARD_EXTENSION the value SMCLIB_VERSION. This is usually done in the DriverEntry routine.

A DeviceControl function should look like the following:

NTSTATUS
DeviceControl(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp
    )
{
    PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;

    // Let the library check parameters
    // If the library requires the help of the driver it'll call
    // the driver using a call back mechanism
    return SmartcardDeviceControl(
        &(deviceExtension->SmartcardExtension),
        Irp
        );
}

For information on the SmartcardDeviceControl function for VxD drivers, see SmartcardDeviceControl (VxD).


SmartcardExit (WDM)

The SmartcardExit function frees buffers that were allocated during a call to SmartcardInitialize (WDM).

VOID
  SmartcardExit(
    IN PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Pointer to the smart card extension of the device.

Return Values

None

Comments

The library allocates internal buffers during a call to SmartcardInitialize (WDM). SmartcardExit frees these buffers.

SmartcardExit functions the same for WDM and VxD drivers.


SmartcardInitialize (WDM)

The SmartcardInitialize function allocates internal buffers for the library.

NTSTATUS
  SmartcardInitialize(
    IN PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Pointer to the smart card extension of the device.
SmartcardExtension->SmartcardRequest.BufferSize
This value must be set to the number of bytes to be allocated for the request buffer. The minimum size for this buffer is MIN_BUFFER_SIZE. If this value is smaller, MIN_BUFFER_SIZE will be allocated automatically.
SmartcardExtension->SmartcardReply.BufferSize
This value must be set to the number of bytes to be allocated for the receive buffer. The minimum size for this buffer is MIN_BUFFER_SIZE. If this value is smaller, MIN_BUFFER_SIZE will be allocated automatically.

Return Values

SmartcardInitialize returns an NTSTATUS value.

Value | Meaning
STATUS_INSUFFICIENT_RESOURCES | Out of memory

Comments

The library uses internal buffers for sending SmartcardExtension->SmartcardRequest.Buffer and receiving SmartcardExtension->SmartcardReply.Buffer data. SmartcardInitialize allocates these buffers. Call SmartcardExit_(WDM) in your DriverUnload routine to free these internal buffers. Your driver should use those buffers for transferring data to and from the card.

The smart card driver library checks the version of the SMARTCARD_EXTENSION structure. Before calling SmartcardInitialize, the driver must assign to the Version member of SMARTCARD_EXTENSION the value SMCLIB_VERSION. This is usually done in the DriverEntry routine.

SmartcardInitialize functions the same for WDM and VxD drivers.


SmartcardLogError (WDM)

The SmartcardLogError function writes an error message to the event log.

VOID
  SmartcardLogError(
    IN PVOID  Object,
    IN NTSTATUS  ErrorCode,
    IN PUNICODE_STRING  Insertion,
    IN ULONG  DumpData
    );

Parameters

Object
Pointer either to the driver object, before you have created a device object, or to your device object.
ErrorCode
Error code of a function.
Insertion
An insertion string to be written to the event log. Your message file must have a place holder for the insertion. For example, serial port %2 is either not available or used by another device. In this example, %2 will be replaced by the insertion string. Note that %1 is reserved for the file name.
DumpData
A ULONG that appears in the data window of the event log.

Comments

SmartcardLogError provides a convenient way to write error messages to the system event log. Refer to Enabling Smart Card Event Logging for information on how to set up event logging.

This function is not available when developing VxD drivers. For a list of the functions that can be used, see VxD Smart Card Driver Functions.


SmartcardRawReply (WDM)

The SmartcardRawReply function transfers the data received from the card to the user buffer.

NTSTATUS
  SmartcardRawReply(
    PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Pointer to the smart card extension of the device.

Return Values

SmartcardRawReply returns an NTSTATUS value. Possible values are the following.

Value | Meaning
STATUS_SUCCESS | Transmission successful.
STATUS_BUFFER_TOO_SMALL | The user buffer is too small to hold the data.

Comments

The driver must store the data coming from the reader into SmartcardExtension->SmartcardReply.Buffer and store the number of bytes returned from the card into SmartcardExtension->SmartcardReply.BufferLength. SmartcardRawReply then checks the validity of the data and copies the buffer back to the user buffer, including the protocol header.

SmartcardRawReply functions the same for WDM and VxD drivers.


SmartcardRawRequest (WDM)

The SmartcardRawRequest function copies data from the user buffer to the send buffer that the driver uses to transmit data to the reader.

NTSTATUS
  SmartcardRawRequest(
    PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Pointer to the smart card extension of the device.

Return Values

SmartcardRawRequest returns an NTSTATUS value. Possible values are the following.

Value | Meaning
STATUS_SUCCESS | Buffer successfully set up.
STATUS_BUFFER_OVERFLOW | The internal buffer is too small to hold the data to send to the smart card. To fix this error, allocate a larger send buffer. See SmartcardInitialize (WDM) for details.
STATUS_BUFFER_TOO_SMALL | The user buffer is too small to hold the data.

Comments

This function copies data from the user buffer to SmartcardExtension->SmartcardRequest.Buffer and adjusts SmartcardExtension->SmartcardRequest.BufferLength to the number of bytes to be transmitted to the smart card. The driver then simply writes this buffer to the card and reads the bytes coming from the card into SmartcardExtension->SmartcardReply.Buffer, as described in SmartcardRawReply (WDM).

For information on the SmartcardRawRequest function for VxD drivers, see SmartcardRawRequest (VxD).


SmartcardReleaseRemoveLock (WDM)

SmartcardReleaseRemoveLock is the inverse function to SmartcardAcquireRemoveLock. It should be called whenever a function returns that was previously entered with a call to SmartcardAcquireRemoveLock.

VOID
  SmartcardReleaseRemoveLock(
    PSMARTCARD_EXTENSION  SmartcardExtension
    );


SmartcardReleaseRemoveLockAndWait (WDM)

SmartcardReleaseRemoveLockAndWait ensures that no unload code is executed as long as some other driver code is active.

VOID
  SmartcardReleaseRemoveLockAndWait(
    PSMARTCARD_EXTENSION  SmartcardExtension
    );

Comments

This function should be called from the driver unload function. This function waits as long as other code of the driver is active (SmartcardAcquireRemoveLock was called without a call to SmartcardReleaseRemoveLock.)


SmartcardT0Reply (WDM)

The SmartcardT0Reply function transfers the data received from the card to the user buffer.

NTSTATUS
  SmartcardT0Reply(
    PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Pointer to the smart card extension of the device.

Return Values

SmartcardT0Reply returns an NTSTATUS value. Possible values are the following.

Value | Meaning
STATUS_SUCCESS | Transmission successful.
STATUS_DEVICE_PROTOCOL_ERROR | The card did not return a T=0 status word.
STATUS_BUFFER_TOO_SMALL | The user buffer is too small to hold the data.

Comments

The driver must store the data coming from the reader into SmartcardExtension->SmartcardReply.Buffer and store the number of bytes returned from the card into SmartcardExtension->SmartcardReply.BufferLength. SmartcardT0Reply then checks the validity of the data and copies the buffer back to the user buffer, including the protocol header. See SmartcardT0Request (WDM) for sample code.

SmartcardT0Reply functions the same for WDM and VxD drivers.


SmartcardT0Request (WDM)

The SmartcardT0Request function copies data from the user buffer to the send buffer that the driver uses to transmit data to the reader.

NTSTATUS
  SmartcardT0Request(
    PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Pointer to the smart card extension of the device.

Return Values

SmartcardT0Request returns an NTSTATUS value. Possible values are the following.

Value | Meaning
STATUS_SUCCESS | Buffer successfully set up.
STATUS_BUFFER_OVERFLOW | The internal buffer is too small to hold the data to send to the smart card. To fix this error, allocate a larger send buffer. See SmartcardInitialize (WDM) for details.
STATUS_BUFFER_TOO_SMALL | The user buffer is too small to hold the data.

Comments

This function copies data from the user buffer to SmartcardExtension->SmartcardRequest.Buffer and adjusts SmartcardExtension->SmartcardRequest.BufferLength to the number of bytes to be transmitted to the smart card. The driver then simply writes this buffer to the card and reads the bytes coming from the card into SmartcardExtension->SmartcardReply.Buffer, as described in SmartcardT0Reply (WDM).

If your driver needs to send header data to the reader before the actual T=0 data, you should set SmartcardExtension->SmartcardRequest.BufferLength to the number of bytes you need for your header before you call this function. The packet will look like this:

A usual T=0 transmission can be done in the following way:

// Copy data from user buffer to
// SmartcardExtension->SmartcardRequest.Buffer
status = SmartcardT0Request(
        SmartcardExtension
        );
if (status != STATUS_SUCCESS)
    return status;

// Transmit SmartcardExtension->SmartcardRequest.Buffer to smart card
status = DriverSendDataToSmartcard(…);
if (status != STATUS_SUCCESS)
return status;

// Receive data from smart card into
SmartcardExtension->SmartcardReply.Buffer
status = DriverReceiveDataFromSmartcard(…);
if (status != STATUS_SUCCESS)
    return status;

// Copy data from SmartcardExtension->SmartcardReply.Buffer back to user buffer
// and return to caller
return SmartcardT0Reply(
SmartcardExtension
);

For information on the SmartcardT0Request function for VxD drivers, see SmartcardT0Request (VxD).


SmartcardT1Reply (WDM)

The SmartcardT1Reply function copies data from the receive buffer to the user buffer and checks the T=1 protocol status.

NTSTATUS
  SmartcardT1Reply(
    PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Pointer to the smart card extension of the device.

Return Values

SmartcardT1Reply returns an NTSTATUS value. Possible values are the following.

Value | Meaning
STATUS_SUCCESS | Transmission successful.
STATUS_DEVICE_PROTOCOL_ERROR | Too many transmission errors.
STATUS_BUFFER_TOO_SMALL | The user buffer is too small to hold the data.
STATUS_MORE_PROCESSING_REQUIRED | The protocol requires additional transmissions.

Comments

SmartcardT1Reply must be called after the driver has received data coming from the smart card. The driver must store received smart card data in SmartcardExtension->SmartcardReply.Buffer and the number of received bytes in SmartcardExtension->SmartcardReply.BufferLength. SmartcardT1Reply checks the protocol status and copies any smart card data to the user buffer. If the transmission is not yet finished, SmartcardT1Reply returns STATUS_MORE_PROCESSING_REQUIRED, indicating the necessity to call SmartcardT1Request (WDM) again, which sets up a new buffer to be sent to the smart card.

SmartcardT1Reply functions the same for WDM and VxD drivers.


SmartcardT1Request (WDM)

The SmartcardT1Request function copies data from the user buffer to a send buffer and checks the T=1 protocol status.

NTSTATUS
  SmartcardT1Request(
    PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Pointer to the smart card extension of the device.

Return Values

SmartcardT1Request returns an NTSTATUS value.

Value | Meaning
STATUS_SUCCESS | Buffer successfully set up.

Comments

Do not change any members of the T1_DATA structure. They will be initialized automatically. The only member that can be safely modified is the NAD value. Changing of any member might lead to protocol errors.

SmartcardT1Request copies the data from the user buffer to SmartcardExtension->SmartcardRequest.Buffer embedded in a T=1 protocol frame and adjusts SmartcardExtension->SmartcardRequest.BufferLength. The driver must send this buffer to the smart card and read the answer of the card into SmartcardExtension->SmartcardReply.Buffer. The driver must then call SmartcardT1Reply (WDM), which checks the incoming protocol frame.

You can copy your header data to the buffer either before or after a call to SmartcardT1Request, depending on which is easier to do in your driver. If your driver needs to send header data to the reader before the actual T=1 data, you should set SmartcardExtension->SmartcardRequest.BufferLength to the number of bytes you need for your header before you call this function. The packet will look like this:

A usual T=1 transmission can be done in the following way:

// Run this loop as long as the protocol requires to send data
do {
    // Copy data to SmartcardExtension->SmartcardRequest.Buffer
    // embedded in a T=1 frame
    status = SmartcardT1Request(SmartcardExtension);
    if (status != STATUS_SUCCESS)
        return status;

    // Send T=1 frame to smart card
    status = DriverSendDataToSmartcard(…);
    if (status != STATUS_SUCCESS)
        return status;

// Now set appropiate timeout (This example calculates. the time-out in ms)
// Timeout = SmartcardExtension->CardCapabilities.T1.BWT *
//    (SmartcardExtension->T1.Wtx ? SmartcardExtension->T1.Wtx : 1);

    // receive T=1 frame from smart card
    status = DriverReceiveDataFromSmartcard(…);
    if (status != STATUS_SUCCESS)
        return status;

    // Check T=1 protocol status and copy any data back to user buffer
    status = SmartcardT1Reply(SmartcardExtension);

} while (status == STATUS_MORE_PROCESSING_REQUIRED);

return status;

SmartcardT1Request functions the same for WDM and VxD drivers.


SmartcardUpdateCardCapabilities (WDM)

The SmartcardUpdateCardCapabilities function translates an ATR string into the SCARD_CARD_CAPABILITIES structure that can be used by the driver.

NTSTATUS
  SmartcardUpdateCardCapabilities(
    PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Pointer to the smart card extension of the device.

Return Values

SmartcardUpdateCardCapabilities returns an NTSTATUS value. Possible values are the following.

Value | Meaning
STATUS_SUCCESS | ATR successfully translated.
STATUS_UNRECOGNIZED_MEDIA | The ATR neither starts with 0x3B nor 0x3F. It is also possible that the ATR contains non-ISO-conforming values for Fl or Dl, or the ATR checksum for T=1 is wrong.

Comments

This function should be called by the driver just after the driver has read the ATR into the ATR member of the SCARD_CARD_CAPABILITIES structure. The ATR bytes must be stored in Buffer, and Length must be adjusted to the actual length of the ATR returned by the card.

This function can handle only T=0 and T=1 cards.

//
// Answer To Reset string returned by card.
//
struct {
    UCHAR Buffer[64];
    UCHAR Length;
} ATR;

The function converts the ATR string into the values defined by ISO 7816-3. These values are all stored in the SCARD_CARD_CAPABILITIES structure. All time values in that structure are in microseconds, not in seconds.

SmartcardUpdateCardCapabilities functions the same for WDM and VxD drivers.


Smart Card Driver Callbacks

This section summarizes callback functions that a Smart Card driver can implement. The Smart Card Resource Manager calls these callback functions.


RDF_ATR_PARSE (Optional)

The RDF_ATR_PARSE callback function is called when the function SmartcardUpdateCardCapabilities is called and the ATR of the currently inserted smart card is not recognized and cannot be parsed by the internal parser.

NTSTATUS
  (*ReaderFunction[RDF_ATR_PARSE])(
    PSMARTCARD_EXTENSION  SmartcardExtension
    );


RDF_CARD_POWER (Mandatory)

The RDF_CARD_POWER callback function resets or powers down an inserted smart card.

NTSTATUS
  (*ReaderFunction[RDF_CARD_POWER])(
    PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Points to the smart card extension of the device.

Input Values

SmartcardExtension->MajorIoControlCode
Contains IOCTL_SMARTCARD_POWER.
SmartcardExtension->MinorIoControlCode
Contains one of the following minor codes, depending on the function to be performed.
Minor Code | Meaning
SCARD_COLD_RESET | Performs a cold reset of the card.
SCARD_WARM_RESET | Performs a warm reset of the card.
SCARD_POWER_DOWN | Switches off card power.

SmartcardExtension->IoRequest.ReplyBufferLength
Contains the length of the reply buffer.

Output Values

SmartcardExtension->IoRequest.ReplyBuffer
This buffer receives the ATR returned by the card. In addition, you must transfer the ATR to SmartcardExtension->CardCapabilities.ATR.Buffer to let the library parse the ATR.
SmartcardExtension->IoRequest.Information
Receives the actual length of the ATR. In addition you must transfer the length of the ATR to SmartcardExtension->CardCapabilities.ATR.Length.

Return Values

This function returns an NTSTATUS value. Possible values are the following.

Value | Meaning
STATUS_SUCCESS | Function successfully executed.
STATUS_NO_MEDIA | No card is in the reader.
STATUS_IO_TIMEOUT | The request has timed out.
STATUS_BUFFER_TOO_SMALL | The user buffer is not large enough to hold the ATR.


RDF_CARD_EJECT (Optional)

The RDF_CARD_EJECT callback function ejects an inserted smart card.

NTSTATUS
  (*ReaderFunction[RDF_CARD_EJECT])(
    PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Points to the smart card extension of the device.

Input Values

SmartcardExtension->MajorIoControlCode
Contains IOCTL_SMARTCARD_EJECT.

Return Values

This function returns an NTSTATUS value. Possible values are the following.

Value | Meaning
STATUS_SUCCESS | Function successfully executed.
STATUS_NO_MEDIA | No card is in the reader.
STATUS_IO_TIMEOUT | The request has timed out.


RDF_CARD_TRACKING (Mandatory)

WDM driver version:

The RDF_CARD_TRACKING callback function installs an event handler to track card insertions and removals.

NTSTATUS
  (*ReaderFunction[RDF_CARD_TRACKING])(
    PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Points to the smart card extension of the device.

Input Values for WDM Device Drivers

SmartcardExtension->OsData->NotificationIrp
Contains the IRP that is to be informed of the insertion/removal event.

Input Values for VxD device Drivers

SmartcardExtension->OsData->NotificationOverlappedData
Points to the overlapped structure of the caller to be informed of the insertion/removal event.

Return Values

This function returns an NTSTATUS value. Possible values for WDM and VxD device drivers are the following.

Value | Meaning
STATUS_PENDING | Card tracking has been started.
STATUS_INVALID_DEVICE_STATE | The device cannot accept the request.
STATUS_SUCCESS | Card status matches the requested tracking call.
STATUS_DEVICE_BUSY | A card tracking event is already pending.

Remarks for WDM Device Drivers

Before the library calls RDF_CARD_TRACKING, it checks if the status already matches the current card status. (That is, a card is inserted and the caller sends an IOCTL_SMARTCARD_IS_PRESENT code.) In this case, the library returns STATUS_SUCCESS without calling this function.

Otherwise, the driver will be called and it should start card tracking. The smart card library fills SmartcardExtension->OsData->NotificationIrp in its extension because this is the IRP that will be informed of insertions or removals. Usually, the driver returns STATUS_PENDING to this call since the current card status does not match the status to check for. The driver must complete this call as soon as it detects the insertion or removal. This is done by a call to IoCompleteRequest. After the call to IoCompleteRequest, you must set the member NotificationIrp back to NULL. This tells the smart card library that your driver can accept further card-tracking requests.

Note It is important to mark this IRP as cancelable, because this call can be of an indefinite duration and the caller can terminate before this call can be satisfied.

Remarks for VxD Device Drivers

Before the library calls RDF_CARD_TRACKING, it checks if the status already matches the current card status. (That is, a card is inserted and the caller sends an IOCTL_SMARTCARD_IS_PRESENT code.) In this case, the library returns STATUS_SUCCESS without calling this function. Otherwise, the driver will be called and it should start card tracking.

Note Since this function will be called only when the current card status is the opposite of the status the caller wants to be informed of, your driver only needs to return STATUS_PENDING. In your driver function that is used to supervise the card, use the structure member OsData->NotificationOverlappedData and check it for a non-NULL value. If the value is non-NULL, call SmartcardCompleteCardTracking (VxD) to inform the caller of the card insertion/removal event.

Following is some sample code:

MyDriverCardSupervision(
SmartcardExtension,
OtherParameters)
//
//    This function is called whenever the card status changes
//    For example, card has been inserted or card has been removed
//
{
    //
    // Do some other tasks here
    //
    if (SmartcardExtension->OsData->NotificationOverlappedData != NULL){

        SmartcardCompleteCardTracking(SmartcardExtension);
    }
    //
    // Do additional tasks
    //
}


RDF_IOCTL_VENDOR (Optional)

The RDF_IOCTL_VENDOR callback function performs vendor-specific IOCTL operations.

NTSTATUS
  (*ReaderFunction[RDF_IOCTL_VENDOR])(
    PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Points to the smart card extension of the device.

Input Values

SmartcardExtension->MajorIoControlCode
Contains a vendor-specific IOCTL code. Refer to the macro SCARD_CTL_CODE in winsmcrd.h for information on how to define a vendor-specific IOCTL code. Note that the code must be between 2048 and 4095.
SmartcardExtension->IoRequest.RequestBuffer
Points to the user's input buffer.
SmartcardExtension->IoRequest.RequestBufferLength
The size of the user's input buffer.
SmartcardExtension->IoRequest.ReplyBuffer
Points to the user's output buffer.
SmartcardExtension->IoRequest.ReplyBufferLength
The size of the user's output buffer.

Output Values

SmartcardExtension->IoRequest.Information
Must be set to the number of bytes returned.

Return Values

This function returns an NTSTATUS value. The value returned depends upon the function performed, since RDF_IOCTL_VENDOR is a vendor-defined IOCTL call. Possible values are the following.

Value | Meaning
STATUS_SUCCESS | Function successfully executed.
STATUS_NO_MEDIA | No card is in the reader.
STATUS_IO_TIMEOUT | The request has timed out.
STATUS_BUFFER_TOO_SMALL | The user's reply buffer is too small.
STATUS_INVALID_DEVICE_REQUEST | The request is not valid for this IOCTL.
STATUS_PENDING | The operation is pending.


RDF_READER_SWALLOW (Optional)

The RDF_READER_SWALLOW callback function does a mechanical swallow.

NTSTATUS
  (*ReaderFunction[RDF_READER_SWALLOW])(
    PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Points to the smart card extension of the device.

Input Values

SmartcardExtension->MajorIoControlCode
Contains IOCTL_SMARTCARD_SWALLOW.

Return Values

This function returns an NTSTATUS value. Possible values are the following.

Value | Meaning
STATUS_SUCCESS | Function successfully executed.
STATUS_NO_MEDIA | No card is in the reader.
STATUS_IO_TIMEOUT | The request has timed out.


RDF_SET_PROTOCOL (Mandatory)

The RDF_SET_PROTOCOL callback function selects a transmission protocol for the currently inserted card.

NTSTATUS
  (*ReaderFunction[RDF_SET_PROTOCOL])(
    PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Points to the smart card extension of the device.

Input Values

SmartcardExtension->MajorIoControlCode
Contains IOCTL_SMARTCARD_SET_PROTOCOL.
SmartcardExtension->MinorIoControlCode
Contains a mask of protocols combined with the bitwise OR operator that the caller accepts for further transmissions. Note that this value can be a mask of protocols. It is the decision of the driver to select a protocol that the currently inserted card supports. It is recommended that T=1 takes precedence over T=0.
Value | Meaning
SCARD_PROTOCOL_RAW | Selects raw protocol.
SCARD_PROTOCOL_T0 | Selects the ISO T=0 protocol.
SCARD_PROTOCOL_T1 | Selects the ISO T=1 protocol.

SmartcardExtension->IoRequest.ReplyBufferLength
Contains the length of the reply buffer.
SmartcardExtension->CardCapabilities.PtsData
Contains the required parameters to perform the PTS request. See PTS_DATA.

Output Values

SmartcardExtension->IoRequest.ReplyBuffer
This buffer receives the selected protocol.
SmartcardExtension->IoRequest.Information
Set to sizeof(ULONG).

Remarks

The caller can supply a mask of protocols that it accepts. It is the driver's decision to select one protocol out of the mask. After the driver has selected a protocol, it must return the selected protocol in SmartcardExtension->IoRequest.ReplyBuffer.

Return Values

This function returns an NTSTATUS value. Possible values are the following.

Value | Meaning
STATUS_SUCCESS | A protocol was successfully selected.
STATUS_NO_MEDIA | No card is in the reader.
STATUS_IO_TIMEOUT | The request has timed out.
STATUS_BUFFER_TOO_SMALL | The user buffer is not large enough to hold a ULONG.
STATUS_INVALID_DEVICE_STATE | The reader is not in the correct state to select a protocol. This is the case when a card is inserted, but not reset.
STATUS_INVALID_DEVICE_REQUEST | The mask contains an unknown protocol.


RDF_TRANSMIT (Mandatory)

The RDF_TRANSMIT callback function performs data transmissions.

NTSTATUS
  (*ReaderFunction[RDF_TRANSMIT])(
    PSMARTCARD_EXTENSION  SmartcardExtension
    );

Parameters

SmartcardExtension
Points to the smart card extension of the device.

Input Values

SmartcardExtension->MajorIoControlCode
Contains IOCTL_SMARTCARD_TRANSMIT.
SmartcardExtension->IoRequest.RequestBuffer
Points to an SCARD_IO_REQUEST structure followed by data to be transmitted to the card.
SmartcardExtension->IoRequest.RequestBufferLength
The number of bytes to be transmitted to the card.
SmartcardExtension->IoRequest.ReplyBufferLength
The size of the reply buffer.

Output Values

SmartcardExtension->IoRequest.ReplyBuffer
Points to the buffer that receives the SCARD_IO_REQUEST structure, plus the result of the card.
SmartcardExtension->IoRequest.Information
Receives the actual number of bytes returned by the card, plus the size of SCARD_IO_REQUEST structure.

Remarks

When this function is called, SmartcardExtension->IoRequest.RequestBuffer points to a SCARD_IO_REQUEST structure followed by data to be transmitted:

typedef struct _SCARD_IO_REQUEST{
    DWORD dwProtocol;   // Protocol identifier
    DWORD cbPciLength;  // Protocol Control Information Length
} SCARD_IO_REQUEST, *PSCARD_IO_REQUEST, *LPSCARD_IO_REQUEST;

The dwProtocol member must contain the protocol identifier that was returned by a call to IOCTL_SMARTCARD_SET_PROTOCOL.

The cbPciLength member contains the size of this structure, which is usually eight. This structure will be used mainly for future implementations.

The structure is followed by (protocol) data to be transmitted to the card. Depending on the protocol to be used for this transmission, the library offers several support functions. See SmartcardT0Request (WDM), SmartcardT0Request (VxD), and SmartcardT1Request (WDM), SmartcardT1Request (VxD).

Note RequestBuffer and ReplyBuffer point to the same system buffer. If you use the library function SmartcardxxRequest and SmartcardxxReply, you do not have to worry that you might overwrite the input buffer. If you do not use these functions, make a copy of the RequestBuffer before you start transmissions.

The implementation requires you to copy the SCARD_IO_REQUEST structure to the ReplyBuffer, followed by the data received from the card. Again, if you use the SmartcardxxRequest and SmartcardxxReply functions, you do not need to copy the structure because the library does this.

Return Values

This function returns an NTSTATUS value. Possible values are the following.

Value | Meaning
STATUS_SUCCESS | Transmission successful.
STATUS_NO_MEDIA | No card is in the reader.
STATUS_IO_TIMEOUT | The request has timed out.
STATUS_INVALID_DEVICE_REQUEST | The protocol defined by dwProtocol is invalid.


Smart Card Driver Structures

This section describes Smart Card driver-related structures.


SCARD_CARD_CAPABILITIES

The SCARD_CARD_CAPABILITIES structure holds all information about the currently inserted smart card.

typedef struct _SCARD_CARD_CAPABILITIES{

  // Flag that indicates that the current card uses inverse convention
  BOOLEAN   InversConvention;

  // Calculated etu
  ULONG    etu;

  // Answer To Reset string returned by card.
  struct {
         UCHAR Buffer[64];
         UCHAR Length;
         } ATR;

  struct {
         UCHAR Buffer[16];
         UCHAR Length;
         } HistoricalChars;

  //  !!! DO NOT MODIFY ANY OF THE FOLLOWING VALUES
  //  OTHERWISE THE LIBRARY WON'T WORK PROPERLY

  // The following 2 tables are provided to give
  // the driver access to the ISO definitions

  PCLOCK_RATE_CONVERSION   ClockRateConversion;
  PBIT_RATE_ADJUSTMENT     BitRateAdjustment;

  // Clock rate conversion
  UCHAR Fl;

  // Bit rate adjustment
  UCHAR Dl;

  // Maximum programming current
  UCHAR II;

  // Programming voltage in .1 Volts
  UCHAR P;

  // Extra guard time in etu
  UCHAR N;

  // Calculated guard time in micro seconds
  ULONG GT;

  struct {
         ULONG Supported;  // Bit mask of the supported protocols
         ULONG Selected;   // The currently selected protocol
         } Protocol;

  // T=0 specific data
  struct {
         UCHAR WI;         // Waiting integer
         ULONG WT;         // Waiting time in micro seconds
        } T0;

  // T=1 specific data
  struct {
         UCHAR IFSC;       // Information field size of card
         UCHAR CWI;        // Character waiting integer
         UCHAR BWI;        // Block waiting integer
         UCHAR EDC;        // Error detection code
         ULONG CWT;        // Character waiting time in micro seconds
         ULONG BWT;        // Block waiting time in micro seconds
         ULONG BGT;        // Block guarding time in micro seconds
         } T1;

  PTS_DATA PtsData;

  UCHAR Reserved[100 - sizeof(PTS_DATA)];
} SCARD_CARD_CAPABILITIES, *PSCARD_CARD_CAPABILITIES;

Members

The following members must be maintained by the driver:

ATR.Buffer
Receives the ATR bytes after a warm or cold reset.
ATR.Length
Receives the actual length of the ATR.

The following members should be used by the driver:

GT
The guard time, in microseconds (including the extra guard time). This is the minimum delay between two consecutive characters.
T0.WT
The T=0 work waiting time, in microseconds. This is the maximum delay between two consecutive characters.
T1.BWT
The T=1 block waiting time, in microseconds. This is the maximum delay between the end of a block and the start of the next block sent in the opposite direction.
T1.CWT
The T=1 character waiting time, in microseconds. This is the maximum delay between two consecutive characters.
T1.BGT
The T=1 block guarding time, in microseconds. This is the minimum delay between the end of a block and the start of the next block sent in the opposite direction.
PtsData
The PTS_DATA structure that contains all the necessary information to perform a PTS (protocol type selection) request with the currently inserted smart card.

Comments

SCARD_CARD_CAPABILITIES holds information about the currently inserted smart card. If the driver uses the Smart Card Driver Library, then ATR is the only member that the driver must fill in. Fill ATR.Buffer with the ATR characters and ATR.Length with the number of ATR bytes returned by the card. The Smart Card Driver Library will automatically update all other fields when a call is made to IOCTL_SMARTCARD_SET_PROTOCOL.


SCARD_READER_CAPABILITIES

The SCARD_READER_CAPABILITIES structure holds state information about the reader. It must be completely maintained by the driver.

typedef struct _SCARD_READER_CAPABILITIES {

  // Supported protocol by the reader/driver
  struct {
         ULONG    Async;
         ULONG     Sync;
         } SupportedProtocols;

  // Type of reader (Serial/USB/PCMCIA/Keyboard etc.)
  ULONG    ReaderType;

  ULONG    Reserved;

  // Mechanical characteristics like SCARD_READER_SWALLOWS etc.
  ULONG    MechProperties;

  // Current state of reader (card present/removed/activated).
  // Use OsData->SpinLock to access CurrentState (mandatory)
  ULONG    CurrentState;

  // The channel ID the reader uses based on one of the
  // following reader types:
  //   - Port number for serial reader
  //   - Port number for par reader
  //   - Scsi id for scsi reader
  //   - 0 for keyboard reader
  //   - device number for USB
  ULONG    Channel;

  // Clock rates in KHz encoded as little endian
  // (I.e. 3.58MHz is encoded as 3580).
  struct {
         ULONG Default;
         ULONG Max;
         } CLKFrequency;

  // Data rates in bps encoded as little endian (mandatory).
  struct {
         ULONG Default;
         ULONG Max;
         } DataRate;

  // Maximum IFSD supported by IFD.
  ULONG   MaxIFSD;

  // Type of power management the card supports
  // (0 = IFD does not support power management).
  ULONG   PowerMgmtSupport;

  // Boolean that indicates that the card has been confiscated.
  ULONG CardConfiscated;

  // A list of data rates supported by the ifd. If this list
  // is empty, the DataRate struct will be taken (optional).
  struct _DataRatesSupported {
                             PULONG List;
                             UCHAR  Entries;
                             } DataRatesSupported;

  // A list of supported clock frequencies. If this list is
  // empty, the CLKFrequency struct will be taken (optional).
  struct _CLKFrequenciesSupported {
                                  PULONG List;
                                  UCHAR  Entries;
                                  } CLKFrequenciesSupported;

  // Reserved, do not use
  UCHAR Reserved1[
        100 -
        sizeof(ULONG) -
        sizeof(struct _DataRatesSupported) -
        sizeof(struct _CLKFrequenciesSupported)
        ];

} SCARD_READER_CAPABILITIES, *PSCARD_READER_CAPABILITIES;

Members

The following members must be maintained by the driver:

SupportedProtocols
Mandatory. Must be set to a bit mask that reflects the protocols that this driver/reader supports (in hardware and software).
ReaderType
Mandatory. The type of this reader.
Type | Meaning
SCARD_READER_TYPE_SERIAL | Serial reader.
SCARD_READER_TYPE_PCMCIA | PCMCIA reader.
SCARD_READER_TYPE_KEYBOARD | Keyboard attached reader.
SCARD_READER_TYPE_USB | USB reader.

CurrentState
Mandatory. Contains the status of the card.
Status | Meaning
SCARD_UNKNOWN | The reader does not know the status.
SCARD_ABSENT | No card is currently inserted.
SCARD_PRESENT | A card is inserted.
SCARD_SWALLOWED | A card is inserted and the reader has swallowed it.
SCARD_POWERED | The card is powered, but the reader does not know its mode.
SCARD_NEGOTIABLE | A card is inserted and awaits protocol negotiation.
SCARD_SPECIFIC | A card is inserted and a protocol has been selected.

MechProperties
Optional. Contains a mask of reader properties combined with the bitwise OR operator:
Property | Meaning
SCARD_READER_SWALLOWS | Reader has a swallowing mechanism.
SCARD_READER_EJECTS | Reader is able to eject the card.
SCARD_READER_CONFISCATES | Reader is able to capture the card.

Channel
Mandatory. Contains the logical channel number according to Part 3 of the Interoperability Specification for ICCs and Personal Computer Systems (see Documents at http://www.smartcardsys.com/).
ClkFrequency.Default
Mandatory. This is the standard clock frequency that the reader runs at, in KHz.
ClkFrequency.Max
Mandatory. This is the maximum clock frequency that the reader can run at, in KHz.
DataRate.Default
Mandatory. This is the standard data rate of the reader, in bps.
DataRate.Max
Mandatory. This is the maximum data rate of the reader, in bps.
MaxIFSD
Mandatory. This is the maximum buffer size of the reader. This value is used to inform the smart card at the beginning of a T=1 transmission about the maximum number of bytes that can be received in one packet.
DataRatesSupported.List
Optional. Contains a list of data rates (in BPS) supported by the reader. This structure is used for the PTS request. The driver usually sets this member to point to a static array of unsigned long values containing the supported data rates.

If the reader does not support different data rates, leave this structure empty.

DataRatesSupported.Entries
Optional. Contains the number of array entries of DataRatesSupported.List.
CLKFrequenciesSupported.List
Optional. Contains a list of clock frequencies (in KHz) supported by the reader. This structure is also used for the PTS request. The driver usually sets this member to point to a static array of unsigned long values containing the supported clock frequencies.

If the reader does not support different clock frequencies, leave this structure empty.

CLKFrequenciesSupported.Entries
Optional. Contains the number of array entries of CLKFrquenciesSupported.List.


T1_DATA

The T1_DATA structure is used by the Smart Card Driver Library for processing T1 I/O. It should not be directly modified by a driver.

typedef struct _T1_DATA {
  // Current information field size that can be transmitted
  UCHAR    InfSize;

  // Number of bytes already received from smart card
  ULONG    BytesReceived;

  // Number of bytes already sent to the card;
  ULONG    BytesSent;

  // Total number of bytes still to send
  ULONG    BytesToSend;

  // T1 error code of last received block
  UCHAR    LastError;

  // This is the node address byte to be sent to the card
  UCHAR     NAD;

  // State before error occurred
  ULONG    PrevState;

  // Resend counter
  UCHAR    Resend;

  // Resync counter
  UCHAR    Resynch;

  // The Send Sequence Number (SSN) is either 0 or 1 as defined in
  // ISO 7816-3.
  UCHAR    SSN;

  // Current state of protocol
  ULONG    State;

  // Waiting time extension requested by the smart card. This value
  // should be used by the driver to extend block waiting time.
  UCHAR    Wtx;

  //Pointer to result buffer
  PUCHAR ReplyData;

  BOOLEAN WaitForReply;
} T1_DATA, *PT1_DATA;

Members

The following member is important for the driver:

Wtx
Contains the waiting time extension for a T=1 transmission. If nonzero, this is a multiplier for the block waiting time. Usually, the driver should time out if the block waiting time expires. Several smart card operations need longer time, so the smart card answers with a waiting time extension, and therefore the block waiting time must be multiplied with the Wtx value. Note that this value only applies as a waiting extension if the value is nonzero.


SCARD_VENDOR_ATTR

The SCARD_VENDOR_ATTR structure holds all information about the reader. The driver is responsible for filling in all members.

typedef struct _VENDOR_ATTR {

  // Manufacturer name (mandatory)
  struct {
         USHORT Length;
         UCHAR  Buffer[MAXIMUM_ATTR_STRING_LENGTH];
         } VendorName;

  // Name (designation) of reader (mandatory)
  struct {
         USHORT Length;
         UCHAR  Buffer[MAXIMUM_ATTR_STRING_LENGTH];
         } IfdType;

  // If more than one reader of the same type are installed,
  // this unit number is used to distinguish these readers
  // (mandatory).
  ULONG  UnitNo;

  // IFD Version number (optional).
  struct {
         USHORT  BuildNumber;
         UCHAR   VersionMinor;
         UCHAR   VersionMajor;
         } IfdVersion;

  // IFD Serial number (optional)
  struct {
         USHORT Length;
         UCHAR  Buffer[MAXIMUM_ATTR_STRING_LENGTH];
         } IfdSerialNo;

  // Reserved, do not use
  ULONG   Reserved[25];

} VENDOR_ATTR, *PVENDOR_ATTR;

Members

The following members must be maintained by the driver:

VendorName
Mandatory. Contains the ANSI-coded name of the vendor. Since a length field is provided, no terminating NULL character is necessary.
IfdType
Mandatory. Contains the ANSI-coded designation of the reader (that is, the reader name).
UnitNo
Mandatory. This is the zero-based number of this unit. Since it is possible to have more than one reader of this type installed in a system, UnitNo is used to distinguish the readers.
IfdVersion
Optional. The version number of the reader. This member can be used for support purposes. It should be maintained only if the reader allows the value to be queried.
IfdSerialNumber
Optional. The serial number of the connected reader. This field should only be maintained if the reader allows the serial number to be queried.


SMARTCARD_EXTENSION

The SMARTCARD_EXTENSION structure is used by the driver to access all the other smart card data structures, and additional information. This structure is passed to all callback functions.

typedef struct _SMARTCARD_EXTENSION {

  // Version of this structure.
  ULONG           Version;

  // Mandatory reader info.
  VENDOR_ATTR     VendorAttr;

  // Array of callback reader functions.
  NTSTATUS (*ReaderFunction[16])(PSMARTCARD_EXTENSION);

  // Capabilities of the current inserted card.
  SCARD_CARD_CAPABILITIES    CardCapabilities;

  // Stores the last error of an overlapped operation
  // (Used only for Win9x VxDs).
  ULONG LastError;

  // Holds the data of the users IO request.
  struct {
         PULONG  Information;         // Number of bytes returned
         PUCHAR  RequestBuffer;       // Pointer to data to send to card
         ULONG   RequestBufferLength; // Number of bytes to send
         PUCHAR    ReplyBuffer;       // Pointer to buffer that receives the answer
         ULONG    ReplyBufferLength;  // Size of reply buffer
         } IoRequest;

  // Major and minor IO control code for current request.
  ULONG    MajorIoControlCode;
  ULONG    MinorIoControlCode;

  // OS dependent data.
  POS_DEP_DATA    OsData;

  // Capabilities of the keyboard-reader.
  SCARD_READER_CAPABILITIES    ReaderCapabilities;

  // Reader specific data.
  PREADER_EXTENSION    ReaderExtension;

  // The reader stores all replies from the card here. This can
  // be used by the driver for data coming from the reader.
  SMARTCARD_REPLY      SmartcardReply;

  // Current command that will be sent to the smart card. This can
  // be used by the driver to for sending data to the reader.
  SMARTCARD_REQUEST    SmartcardRequest;

  // Data for T=0.
  T0_DATA    T0;

  // Data for T=1.
  T1_DATA    T1;

  // Reserved, do not use.
  ULONG   Reserved[25];

} SMARTCARD_EXTENSION, *PSMARTCARD_EXTENSION;

Members

OsData
This structure contains information dependent on the driver type.
WDM driver version:
typedef struct _OS_DEP_DATA {

// Pointer to the device object (Must be set by the driver).
PDEVICE_OBJECT DeviceObject;

// Current Irp to be processed. Use Osdata->SpinLock to
// access CurrentIrp.
PIRP CurrentIrp;

// Irp to be notified of card insertion/removal. Use
// Osdata->SpinLock to access NotificationIrp.
PIRP NotificationIrp;

// Used to synchronize access to the driver.
KMUTANT Mutex;

// Used to access protected members (see smclib.h).
KSPIN_LOCK SpinLock;

} OS_DEP_DATA, *POS_DEP_DATA;

This structure will be allocated by a call to SmartcardInitialize (WDM). After this call, copy the pointer of your device object to DeviceObject. Otherwise, the Smart Card Driver Library will not work. You cannot use this structure to store driver-dependent information. However, when one of your callback functions is called, CurrentIrp is set to the requesting Irp for every request, except card-tracking requests. For card-tracking requests, NotificationIrp is set to the requesting Irp. See RDF_CARD_TRACKING for more information about card tracking.

VxD driver version:
typedef struct _OS_DEP_DATA {

// Pointer to the smartcard extension.
PSMARTCARD_EXTENSION SmartcardExtension;

// Current DiocParams to be processed.
PDIOCPARAMETERS CurrentDiocParams;

// This overlapped is used for card tracking completion.
OVERLAPPED *NotificationOverlappedData;

// Used to synchronize access to the driver.
PVMMMUTEX Mutex;

} OS_DEP_DATA, *POS_DEP_DATA;

This structure will be allocated by a call to SmartcardInitialize (VxD). You cannot use this structure to store driver-dependent information. However, when one of your callback functions is called, CurrentDiocParams is set to the requesting parameters for every request, except card-tracking requests. For card-tracking requests, NotificationOverlappedData is set to the overlapped structure of the caller.


PTS_DATA

The PTS_DATA structure is used for protocol type selection (PTS).

//
typedef struct _PTS_DATA {
  UCHAR Type;
  UCHAR Fl;            // Fl value for PTS
  UCHAR Dl;            // Dl value for PTS
  ULONG CLKFrequency;  // New clock frequency
  ULONG DataRate;      // New baud rate to be used after pts
  UCHAR StopBits;      // New stop bits to be used after pts
} PTS_DATA, *PPTS_DATA;

Members

Type
Controls how the remaining members of this structure will be calculated. This member can be one of the following.
Type | Meaning
PTS_TYPE_DEFAULT | Calculates standard parameters for PTS.
PTS_TYPE_OPTIMAL | Calculates the best possible parameters for PTS.
PTS_TYPE_USER | Calculates user defined parameters for PTS.

The remaining members of this structure will be filled after a call to SmartcardUpdateCardCapabilities(). This member is usually set by the smart card library. However, it can also be set by the driver in the callback for set protocol if a PTS request with optimal parameters failed. In this case, the driver sets the type to PTS_TYPE_DEFAULT and calls SmartcardUpdateCardCapabilities() again.

Fl
The Fl value to be used as part of PTS1 for the PTS request.
Dl
The Dl value to be used as part of PTS1 for the PTS request.
CLKFrequency
Contains the new clock frequency. Some smart card readers need to be programmed with the new clock frequency to be used after the PTS request.
DataRate
Contains the new data rate. Some smart card readers (for example, serial readers) need to be set to the new data rate to be used after a PTS request.
StopBits
Contains the number of stop bits to be used with the currently inserted card.

Comments

This structure will be filled by the smart card library before it calls the callback function to set the protocol. The library takes into account the parameters of the currently inserted smart card and the supported clock frequencies and data rates of the reader.


Smart Card Driver IOCTLs

This section describes system-defined Smart Card driver IOCTLs.


IOCTL_SMARTCARD_EJECT

WDM driver version:

The IOCTL_SMARTCARD_EJECT DeviceIoControl operation ejects the currently inserted smart card from the smart card reader.

I/O Status Block

Information is set to zero. Status can be:

Status | Meaning
STATUS_SUCCESS | Card successfully ejected.
STATUS_NO_MEDIA | No card in reader.
STATUS_NOT_SUPPORTED | Reader does not support card eject.
STATUS_IO_TIMEOUT | Operation has timed out.

VxD driver version:

The IOCTL_SMARTCARD_EJECT DeviceIoControl operation ejects the currently inserted smart card from the smart card reader.

Return Values

Following are possible return values.

Value | Meaning
STATUS_SUCCESS | Card successfully ejected.
STATUS_NO_MEDIA | No card in reader.
STATUS_NOT_SUPPORTED | Reader does not support card eject.
STATUS_IO_TIMEOUT | Operation has timed out.


IOCTL_SMARTCARD_GET_ATTRIBUTE

WDM driver version:

The IOCTL_SMARTCARD_GET_ATTRIBUTE DeviceIoControl operation queries smart card and smart card reader attributes. For a list of all defined attributes, refer to Part 3 of the Interoperability Specification for ICCs and Personal Computer Systems (see Documents at http://www.smartcardsys.com/).

Input

Irp->AssociatedIrp.SystemBuffer
Contains a tag value describing the data to be retrieved.
Parameters.DeviceIoControl.InputBufferLength
Must be sizeof(ULONG).
Parameters.DeviceIoControl.OutputBufferLength
The size of the output buffer, which receives the result. The size depends on the type of attribute to be retrieved.

Output

Irp->AssociatedIrp.SystemBuffer
Receives the data.

I/O Status

Information must be set to the number of bytes returned. The trailing null byte should not be included in strings. Since these calls are all mandatory for all drivers, Status must be set to STATUS_SUCCESS. However, if a driver does not support a particular attribute, the driver must set Status to STATUS_NOT_SUPPORTED.

VxD driver version:

The IOCTL_SMARTCARD_GET_ATTRIBUTE DeviceIoControl operation queries smart card and smart card reader attributes. For a list of all defined attributes, refer to Part 3 of the Interoperability Specification for ICCs and Personal Computer Systems (see Documents at http://www.smartcardsys.com/).

Input

DiocParams->lpvInBuffer
Contains a tag value describing the data to be retrieved.
DiocParams->cbInBuffer
Must be sizeof(ULONG).
DiocParams->cbOutBuffer
The size of the output buffer, which receives the result. The size depends on the type of attribute to be retrieved.

Output

DiocParams->lpvOutBuffer
Receives the data.
DiocParams->lpcbBytesReturned
Must be set to the number of bytes returned. The trailing null byte should not be included in strings.

Return Values

Since these calls are all mandatory for all drivers, status must be set to STATUS_SUCCESS. However, if a driver does not support a particular attribute, the driver must set status to STATUS_NOT_SUPPORTED.


IOCTL_SMARTCARD_GET_LAST_ERROR

WDM driver version:

None.

VxD driver version:

There is no option to return an error code on completing an overlapped operation. Use IOCTL_SMARTCARD_GET_LAST_ERROR to get the error code of the last operation.

Input

DiocParams->cbOutBuffer
The size of the output buffer. Must be at least sizeof(ULONG).

Output

DiocParams->lpvOutBuffer
Receives the error code.
DiocParams->lpcbBytesReturned
Must be set to sizeof(ULONG).

Return Values

This call must return STATUS_SUCCESS.

Note When your driver uses the smart card driver library, you should store the result of the last overlapped operation in the smart card extension. The library will answer this call automatically using your stored value.


IOCTL_SMARTCARD_GET_STATE

WDM driver version:

The IOCTL_SMARTCARD_GET_STATE DeviceIoControl operation gets the current status of the smart card reader.

Input

Parameters.DeviceIoControl.OutputBufferLength
The size of the output buffer. Must be at least sizeof(ULONG).

Output

Irp->AssociatedIrp.SystemBuffer
Receives the status of the card. The status can be:
Status | Meaning
SCARD_UNKNOWN | The reader does not know the status.
SCARD_ABSENT | No card is currently inserted.
SCARD_PRESENT | A card is inserted.
SCARD_SWALLOWED | A card is inserted and the reader has swallowed it.
SCARD_POWERED | The card is powered but the reader does not know its mode.
SCARD_NEGOTIABLE | A card is inserted and awaits protocol negotiation.
SCARD_SPECIFIC | A card is inserted and a protocol has been selected.

I/O Status

Information must be set to sizeof(ULONG). Status must be STATUS_SUCCESS.

VxD driver version:

The IOCTL_SMARTCARD_GET_STATE DeviceIoControl operation gets the current status of the smart card reader.

Input

DiocParams->cbOutBuffer
The size of the output buffer. Must be at least sizeof(ULONG).

Output

DiocParams->lpvOutBuffer
Receives the status of the reader. The status can be:
Value | Meaning
SCARD_UNKNOWN | The reader does not know the status.
SCARD_ABSENT | No card is currently inserted.
SCARD_PRESENT | A card is inserted.
SCARD_SWALLOWED | A card is inserted and the reader has swallowed it. If the reader does not support swallowing, it should go to this status after card insertion.
SCARD_POWERED | The card is powered, but the reader does not know its mode.
SCARD_NEGOTIABLE | A card is inserted and awaits protocol negotiation.
SCARD_SPECIFIC | A card is inserted and a protocol has been selected.

DiocParams->lpcbBytesReturned
Must be set to sizeof(ULONG).

Return Values

The return value must be set to STATUS_SUCCESS.


IOCTL_SMARTCARD_IS_ABSENT

WDM driver version:

The IOCTL_SMARTCARD_IS_ABSENT DeviceIoControl operation either returns immediately if no card is currently inserted, or it installs an event handler to track card removals.

The operation either returns immediately with STATUS_SUCCESS, which indicates that no card is in the reader, or it returns with STATUS_PENDING. This indicates that a card is currently in the reader and the driver will inform the caller of card removal through an I/O completion. Waiting for I/O completion can be accomplished with the following code fragment:

success = GetOverlappedResult(
    hDevice,
    &lpOverlapped,
    &lpBytesReturned,
    TRUE
    );

Completing the call in the driver can be accomplished with the following code fragment:

IoCompleteRequest(
    Irp,
    IO_NO_INCREMENT
    );

return STATUS_SUCCESS;

I/O Status

Information must be set to zero. Status can be:

Status | Meaning
STATUS_SUCCESS | A smart card is inserted.
STATUS_PENDING | The driver is waiting for a card to be inserted.
STATUS_DEVICE_BUSY | Event tracking is already active.
STATUS_INVALID_DEVICE_STATE | The device cannot accept the request.

VxD driver version:

The IOCTL_SMARTCARD_IS_ABSENT DeviceIoControl operation either returns immediately if no card is currently inserted, or it installs an event handler to track card removals.

The operation either returns immediately with STATUS_SUCCESS, which indicates that no card is in the reader, or it returns with STATUS_PENDING. This indicates that a card is currently in the reader and the driver will inform the caller of card removal through an I/O completion. Waiting for I/O completion can be accomplished with the following code fragment:

success = GetOverlappedResult(
    hDevice,
    &lpOverlapped,
    &lpBytesReturned,
    TRUE
    );

Completing the call in the driver can be accomplished with the following code fragment:

SmartcardCompleteCardTracking(
  SmartcardExtension
);

Return Values

Following are possible return values.

Value | Meaning
STATUS_SUCCESS | A smart card is inserted.
STATUS_PENDING | The driver is waiting for a card to be inserted.
STATUS_DEVICE_BUSY | Event tracking is already active.
STATUS_INVALID_DEVICE_STATE | The device cannot accept the request.


IOCTL_SMARTCARD_IS_PRESENT

WDM driver version:

The IOCTL_SMARTCARD_IS_PRESENT DeviceIoControl operation either returns immediately if no card is currently inserted, or it installs an event handler to track card insertions.

The operation either returns immediately with STATUS_SUCCESS, which indicates that a card is already in the reader, or it returns with STATUS_PENDING, which indicates that no card is currently in the reader. In this case, the driver then informs the caller of card insertion through an I/O completion. Waiting for I/O completion can be accomplished with the following code fragment:

success = GetOverlappedResult(
    hDevice,
    &lpOverlapped,
    &lpBytesReturned,
    TRUE);

I/O Status

Information must be set to zero. Status can be:

Status | Meaning
STATUS_SUCCESS | No smart card is currently inserted.
STATUS_PENDING | The driver is waiting for a card to be removed.
STATUS_DEVICE_BUSY | Event tracking is already active.
STATUS_INVALID_DEVICE_STATE | The device cannot accept the request.

VxD driver version:

The IOCTL_SMARTCARD_IS_PRESENT DeviceIoControl operation either returns immediately if no card is currently inserted, or it installs an event handler to track card insertions.

The operation either returns immediately with STATUS_SUCCESS, which indicates that a card is already in the reader, or it returns with STATUS_PENDING, which indicates that no card is currently in the reader. In this case, the driver then informs the caller of card insertion through an I/O completion. Waiting for I/O completion can be accomplished with the following code fragment:

success = GetOverlappedResult(
    hDevice,
    &lpOverlapped,
    &lpBytesReturned,
    TRUE);

Completing the call in the driver can be accomplished with the following code fragment:

SmartcardCompleteCardTracking(
  SmartcardExtension
);

Return Values

Following are possible return values.

Value | Meaning
STATUS_SUCCESS | No smart card is currently inserted.
STATUS_PENDING | The driver is waiting for a card to be removed.
STATUS_DEVICE_BUSY | Event tracking is already active.
STATUS_INVALID_DEVICE_STATE | The device cannot accept the request.


IOCTL_SMARTCARD_POWER

WDM driver version:

The IOCTL_SMARTCARD_POWER DeviceIoControl operation consists of three minor IOCTL codes. This code can be:

Code | Meaning
SCARD_COLD_RESET | Power down the card and power it up again.
SCARD_WARM_RESET | Perform a warm reset of the card.
SCARD_POWER_DOWN | Switch off the card power.

Input

Irp->AssociatedIrp.SystemBuffer
Contains the minor IOCTL code.
Parameters.DeviceIoControl.OutputBufferLength
The size of the output buffer. Must be at least 33 bytes to hold a complete ATR. (Does not apply to power down code.)

Output

Irp->AssociatedIrp.SystemBuffer
Used by SCARD_COLD_RESET and SCARD_WARM_RESET to store the ATR coming from the card.

I/O Status Block

Information is set to the length of the ATR returned by the card. Status is set to:

Status | Meaning
STATUS_SUCCESS | Successful operation.
STATUS_UNRECOGNIZED_MEDIA | Unknown or unsupported card inserted.
STATUS_NO_MEDIA | No card in reader.
STATUS_IO_TIMEOUT | The operation has timed out.

VxD driver version:

The IOCTL_SMARTCARD_POWER DeviceIoControl operation consists of three minor IOCTL codes. This code can be:

Code | Meaning
SCARD_COLD_RESET | Power down the card and power it up again.
SCARD_WARM_RESET | Perform a warm reset of the card.
SCARD_POWER_DOWN | Switch off the card power.

Input

DiocParams->lpvInBuffer
Contains the minor IOCTL code.
DiocParams->cbOutBuffer
The size of the output buffer. Must be at least 33 bytes to hold a complete ATR.

Output

DiocParams->lpvOutBuffer
Used by SCARD_COLD_RESET and SCARD_WARM_RESET to store the ATR coming from the card.
DiocParams->lpcbBytesReturned
Must be set to the length of the ATR returned by the card. (Does not apply to power down code.)

Return Values

Following are possible return values.

Value | Meaning
STATUS_SUCCESS | Successful operation.
STATUS_UNRECOGNIZED_MEDIA | Unknown or unsupported card inserted.
STATUS_NO_MEDIA | No card in reader.
STATUS_IO_TIMEOUT | The operation has timed out.


IOCTL_SMARTCARD_SET_ATTRIBUTE

WDM driver version:

The IOCTL_SMARTCARD_SET_ATTRIBUTE DeviceIoControl operation sets various attributes in the driver. For a list of all defined attributes, refer to Part 3 of the Interoperability Specification for ICCs and Personal Computer Systems (see Documents at http://www.smartcardsys.com/).

Input

Irp->AssociatedIrp.SystemBuffer
Contains the tag and value to be set.
Parameters.DeviceIoControl.InputBufferLength
Contains the length of the whole TLV structure.

I/O Status

Information must be set to sizeof(ULONG). Status can be:

Status | Meaning
STATUS_SUCCESS | The attribute has been set successfully.
STATUS_NOT_SUPPORTED | The attribute is not supported.
STATUS_INVALID_PARAMETER | The attribute to be set is in the wrong format.

VxD driver version:

The IOCTL_SMARTCARD_SET_ATTRIBUTE DeviceIoControl operation sets various attributes in the driver. For a list of all defined attributes, refer to Part 3 of the Interoperability Specification for ICCs and Personal Computer Systems (see Documents at http://www.smartcardsys.com/).

Input

DiocParams->lpvInBuffer
Contains the tag and value to be set.
DiocParams->cbInBuffer
Contains the length of the whole TLV structure.

Following are possible return values.

Value | Meaning
STATUS_SUCCESS | The attribute has been set successfully.
STATUS_NOT_SUPPORTED | The attribute is not supported.
STATUS_INVALID_PARAMETER | The attribute to be set is in the wrong format.


IOCTL_SMARTCARD_SET_PROTOCOL

WDM driver version:

The IOCTL_SMARTCARD_SET_PROTOCOL DeviceIoControl operation sets the protocol to be used with the currently inserted card.

Input

Irp->AssociatedIrp.SystemBuffer
Contains a mask of protocols that are acceptable for the following transmissions. This mask can be any of the following, which can be combined by using the bitwise OR operator:
  • SCARD_PROTOCOL_RAW
  • SCARD_PROTOCOL_T0
  • SCARD_PROTOCOL_T1
  • SCARD_PROTOCOL_DEFAULT
  • SCARD_PROTOCOL_OPTIMAL

The last two values are additional bit definitions telling the driver either to explicitly perform PTS selection (SCARD_PROTOCOL_OPTIMAL) with the best possible communication parameters or to use the implicit protocol of the card (SCARD_PROTOCOL_DEFAULT) with standard parameters. If the card supports only one protocol with one set of communication parameters, these bits are ignored.

Parameters.DeviceIoControl.InputBufferLength
Must be set to sizeof(ULONG). The driver decides which protocol out of the mask to use with the currently inserted card.
Parameters.DeviceIoControl.OutputBufferLength
Must be sizeof(ULONG).

Output

Irp->AssociatedIrp.SystemBuffer
The driver stores the selected protocol here. Only one bit out of the mask can be set.

I/O Status

Information must be set to sizeof(ULONG). Status can be:

Status | Meaning
STATUS_SUCCESS | One protocol has been successfully selected.
STATUS_NO_MEDIA | No card in reader.
STATUS_IO_TIMEOUT | The operation has timed out.
STATUS_NOT_SUPPORTED | The card does not support any of the requested protocols.
STATUS_INVALID_DEVICE_REQUEST | The mask contains no known protocol.

VxD driver version:

The IOCTL_SMARTCARD_SET_PROTOCOL DeviceIoControl operation sets the protocol to be used with the currently inserted card.

Input

DiocParams->lpvInBuffer
Contains a mask of protocols that are acceptable for the following transmissions. This mask can be any of the following, which can be combined by using the bitwise OR operator:
  • SCARD_PROTOCOL_RAW
  • SCARD_PROTOCOL_T0
  • SCARD_PROTOCOL_T1
  • SCARD_PROTOCOL_DEFAULT
  • SCARD_PROTOCOL_OPTIMAL

The last two values are additional bit definitions telling the driver either to explicitly perform PTS selection (SCARD_PROTOCOL_OPTIMAL) with the best possible communication parameters or to use the implicit protocol of the card (SCARD_PROTOCOL_DEFAULT) with standard parameters. If the card supports only one protocol with one set of communication parameters, these bits are ignored.

DiocParams->cbInBuffer
Must be set to sizeof(ULONG). The driver decides which protocol out of the mask to use with the currently inserted card.
DiocParams->cbOutBuffer
Must be sizeof(ULONG).

Output

DiocParams->lpvInBuffer
The driver stores the selected protocol here. Only one bit out of the mask can be set.
DiocParams->lpcbBytesReturned
Must be set to sizeof(ULONG).

Return Values

Following are possible return values.

Value | Meaning
STATUS_SUCCESS | One protocol has been successfully selected.
STATUS_NO_MEDIA | No card in reader.
STATUS_IO_TIMEOUT | The operation has timed out.
STATUS_NOT_SUPPORTED | The card does not support any of the requested protocols.
STATUS_INVALID_DEVICE_REQUEST | The mask contains no known protocol.


IOCTL_SMARTCARD_SWALLOW

WDM driver version:

The IOCTL_SMARTCARD_SWALLOW DeviceIoControl operation causes the reader to swallow the card.

I/O Status

Information must be set to zero. Status can be:

Status | Meaning
STATUS_SUCCESS | The card was swallowed.
STATUS_NO_MEDIA | No card in reader.
STATUS_IO_TIMEOUT | The operation has timed out.
STATUS_NOT_SUPPORTED | The reader does not support swallowing.

VxD driver version:

The IOCTL_SMARTCARD_SWALLOW DeviceIoControl operation causes the reader to swallow the card.

Return Values

Following are possible return values.

Value | Meaning
STATUS_SUCCESS | The card was swallowed.
STATUS_NO_MEDIA | No card in reader.
STATUS_IO_TIMEOUT | The operation has timed out.
STATUS_NOT_SUPPORTED | The reader does not support swallowing.


IOCTL_SMARTCARD_TRANSMIT

WDM driver version:

The IOCTL_SMARTCARD_TRANSMIT DeviceIoControl operation transmits data to and receives data from the currently inserted smart card.

Input

Irp->AssociatedIrp.SystemBuffer
Points to an SCARD_IO_REQUEST structure followed by the data to be transmitted. An SCARD_IO_REQUEST structure has the following definition:
typedef struct _SCARD_IO_REQUEST{
    DWORD dwProtocol;   // Protocol identifier
    DWORD cbPciLength;  // Protocol Control Information Length
} SCARD_IO_REQUEST, *PSCARD_IO_REQUEST, *LPSCARD_IO_REQUEST;
Irp->AssociatedIrp.SystemBuffer
Contains the data to be transmitted to the currently inserted smart card.
Parameters.DeviceIoControl.InputBufferLength
Contains the size of the structure plus the length of trailing data bytes (if any). The member dwProtocol must be set to the previously selected protocol, and cbPciLength must be set to the size of the SCARD_IO_REQUEST structure itself (usually eight). The structure will be used for future protocols. Any data that is to be transmitted to the card must immediately follow this structure.
Parameters.DeviceIoControl.OutputBufferLength
Contains the length of the output buffer.

Output

Irp->AssociatedIrp.SystemBuffer
Receives the result of the transmission. This buffer must also begin with an SCARD_IO_REQUEST structure. Any data that was received from the card must be stored immediately after the structure.

Since the input buffer and the output buffer are pointing to the same memory area, it is the driver's responsibility to avoid overwriting the input data. Use the Smart Card Driver Library to ensure that the input data is not overwritten.

I/O Status

Information receives the size of the SCARD_IO_REQUEST structure plus the number of bytes received from the card. Status can be:

Status | Meaning
STATUS_SUCCESS | The transmission was successful.
STATUS_NO_MEDIA | No card in reader.
STATUS_IO_TIMEOUT | The operation has timed out.
STATUS_INVALID_DEVICE_STATE | The protocol in the header does not match the previously selected card protocol.

VxD driver version:

The IOCTL_SMARTCARD_TRANSMIT DeviceIoControl operation transmits data to and receives data from the currently inserted smart card.

Input

DiocParams->lpvInBuffer
Points to an SCARD_IO_REQUEST structure, which has the following definition:
typedef struct _SCARD_IO_REQUEST{
    DWORD dwProtocol;   // Protocol identifier
    DWORD cbPciLength;  // Protocol Control Information Length
} SCARD_IO_REQUEST, *PSCARD_IO_REQUEST, *LPSCARD_IO_REQUEST;
DiocParams->cbInBuffer
Contains the size of the structure plus the length of trailing data bytes (if any). The member dwProtocol must be set to the previously selected protocol, and cbPciLength must be set to the size of the SCARD_IO_REQUEST structure itself (usually eight). The structure will be used for future protocols. Any data that is to be transmitted to the card must immediately follow this structure.
DiocParams->cbOutBuffer
Contains the length of the output buffer.

Output

DiocParams->lpvOutBuffer
Receives the result of the transmission. This buffer must also begin with an SCARD_IO_REQUEST structure. Any data that was received from the card must be stored immediately after the structure.
DiocParams->lpcbBytesReturned
Receives the size of the SCARD_IO_REQUEST structure plus the number of bytes received from the card.

Return Values

Following are possible return values.

Value | Meaning
STATUS_SUCCESS | The transmission was successful.
STATUS_NO_MEDIA | No card in reader.
STATUS_IO_TIMEOUT | The operation has timed out.
STATUS_INVALID_DEVICE_STATE | The protocol in the header does not match the previously selected card protocol.


Vendor-specific IOCTL Calls

For information on vendor-specific IOCTL operations, see RDF_IOCTL_VENDOR.


Windows Image Acquisition Drivers

This section describes the Microsoft Windows Image Acquisition (WIA) architecture and provides guidelines for developing WIA minidrivers. The WIA architecture allows imaging applications to communicate with imaging devices such as digital cameras and scanners.

WIA is built upon the Microsoft Still Image Architecture (STI). WIA minidrivers must be compliant with STI's User-Mode Driver (USD) model.

See the Platform SDK documentation for more information on the API for imaging applications.

This section contains the following sections:

Introduction to WIA

WIA Components

WIA/Still Image Core Components

Application Items and Driver Items

About Contexts

WIA DDI Interfaces

Sample WIA Driver Components

Creating a WIA Minidriver

Calling Order for Minidriver Functions

Installing a WIA Minidriver

WIA Microdriver

Picture Transfer Protocol Driver

TWAIN Compatibility

Support for TWAIN-Compatible Applications

Recommended Development Plan


Introduction to WIA

The WIA architecture enables imaging applications running in user mode to communicate with and receive data from imaging devices, such as digital cameras and scanners. The WIA architecture consists of the following major components:

  • A system-supplied WIA service through which imaging applications can monitor, communicate with, and receive data from imaging devices. The WIA service routes requests from applications to the appropriate imaging devices and notifies applications when device events, such as data transfer-ready events, occur.
  • Vendor-supplied WIA minidrivers that communicate with both imaging devices and the WIA service through WIA interfaces. Minidrivers communicate with imaging devices through system-supplied or vendor-supplied kernel I/O device drivers. Minidrivers communicate with imaging applications through the WIA service.
  • A system-supplied services library containing helper functions that assist in the development of a minidriver.

Since imaging applications reside in separate processes from imaging device drivers, instability in an application does not adversely affect device operation, and instability in a device does not affect applications.

The following sections provide more information on these and other WIA components.


WIA Components

The following diagram illustrates the software components that compose the WIA interface. Following the diagram is a component list:

WIA Components

Imaging Applications

Imaging applications communicate with the WIA service through the WIA Application Programming Interface (WIA API) to access images and acquire data from WIA devices. These applications can use a common, system-supplied user interface or a vendor-supplied user interface. For more information on the WIA API for imaging applications, see the Platform SDK documentation.

WIA Service

The WIA service is a system-supplied component that communicates with imaging applications and WIA minidrivers. It is a collection of the interfaces listed in the following table, all of which are described in the Platform SDK documentation. The WIA service executes in a separate process from applications and in the same process as WIA minidrivers. Applications direct device requests to the WIA service, which in turn directs the requests to the appropriate minidriver through the WIA Device Driver Interface (WIA DDI) to perform the following:

Interface | Description
IEnumWIA_DEV_CAPS | Enumerates the capabilities of the WIA hardware device. Device capabilities include commands and events that the device supports.
IEnumWIA_DEV_INFO | Enumerates the WIA hardware devices and their properties. Device information properties describe the installation and configuration of WIA hardware devices.
IEnumWIA_FORMAT_INFO | Enumerates the format and media type information for a device.
IEnumWiaItem | Enumerates IWiaItem objects in the current folder of a tree. The WIA run-time system represents every WIA hardware device to an application as a hierarchical tree of IWiaItem objects.
IWiaDataCallback | Provides an application callback mechanism during data transfers from WIA hardware devices to applications.
IWiaDataTransfer | Supports a shared memory window to transfer data from the device object to the application, and eliminates unnecessary data copies during marshalling.
IWiaDevMgr | Is used by applications to create and manage image acquisition devices. They also use it to register to receive device events.
IWiaEventCallback | Is used by applications to receive notification of WIA hardware device events.
IWiaItem | Enables applications to query devices for their capabilities. It also provides access to data transfer interfaces and item properties. In addition, this interface provides methods to enable applications to control the device.
IWiaPropertyStorage | Provides access to information about an IWiaItem object's properties.

WIA Driver Services Library

The WIA driver services library is a system-supplied component that provides helper functions for WIA minidrivers. A minidriver can call helper functions to perform tasks such as the following:

  • Initialize the WIA driver item tree
  • Read, write and validate device properties
  • Transfer data

Alternatively, a minidriver can perform such tasks itself. By taking advantage of the helper functions, you can reduce development time and the size of a WIA minidriver, while still having the flexibility to develop individual solutions.

WIA Utility Library

The WIA Utility Library includes a collection of debugging functions (wiauDbgXxx), a collection of general utility helper functions, and three classes: the CWiauDbgFn class, the CWiauFormatConverter class, and the CWiauPropertyList class.

WIA Log Interface

The WIA log interface is a system-provided component that enabes a minidriver to write to a diagnostic device such as a file or console. You can use the log interface to generate notification messages when a minidriver entry and exit point has been called and to generate diagnostic error messages.

WIA Minidrivers

WIA minidrivers are vendor-supplied, user-mode components that direct WIA property changes and commands to an imaging device. A minidriver implements the WIA DDI, which is called by the WIA service to communicate with the minidriver.

A WIA minidriver provides a device-specific, user-mode interface to a kernel-mode still image driver, which drives the imaging device through a driver such as a USB driver. A minidriver communicates with the kernel-mode drivers by calling the CreateFile, ReadFile, WriteFile, and DeviceIoControl Win32 functions (described in the Platform SDK documentation).

Kernel I/O Drivers

Kernel-mode still image drivers are system- or IHV-supplied components that package data for delivery to still image devices, and for transfer from still image devices. A kernel-mode still image driver is bus-specific.

Microsoft provides WDM-based kernel-mode still image drivers for the USB, SCSI, and IEEE 1394 buses (see Accessing Kernel-Mode Drivers for Still Image Devices for more information.)

A vendor needs to provide a kernel-mode still image driver only if its imaging device is incompatible with Microsoft-supplied kernel-mode I/O drivers.


WIA/Still Image Core Components

The WIA/Still Image core components differ in the various operating system versions covered in this DDK documentation, which are Microsoft® Windows® 98/Me, Microsoft® Windows® 2000 and Microsoft® Windows® XP. The Windows 98 core components are similar to those in Windows 2000. The Windows XP core components are identical to those in Windows Me, both of which are discussed in Windows XP/Windows Me Core Components.

The last topic in this section is Starting and Stopping the Still Image Service.


Windows 98 Core Components

On Windows 98, the Still Image core components are as shown in the following figure.

Windows 98 Core Components

On the server side, three core components communicate with sti.dll: stimon.exe, sti_ci.dll, and sticpl.cpl. These components are, respectively, the still image event monitor, the class installer, and the Scanners and Cameras Control Panel application. Sti_ci.dll is invoked only when a new still image device is installed or removed, and sticpl.cpl is invoked only to do configuration chores.

Stimon.exe processes events and communicates with sti.dll, which in turn communicates with one or more user-mode still image drivers (USDs), which are labeled USD1, USD2, and USD3 on the left side of this figure. Each of the user-mode drivers communicates with one type of kernel-mode driver, depending on the device's bus connection. For a USB device, the user-mode still image driver communicates with usbscan.sys; for a SCSI device, the user-mode driver communicates with both scsiscan.sys and scsimap.sys.

On the client application side, an IHV must supply a TWAIN data source, which is shown in the preceding figure as vendor.ds, a generic name for this component. The TWAIN data source is a component of the TWAIN Scanning architecture, and communicates with an instance of sti.dll on the client side. In turn, sti.dll communicates with a user-mode still image driver (USD1 in the figure), which communicates with one of the kernel-mode drivers discussed earlier.


Windows 2000 Core Components

The still image core components on Windows 2000 are shown in the following figure.

Windows 2000 Core Components

The still image core components on Windows 2000 are almost identical to the Windows 98 core components. The three differences between these operating systems are the following:

  1. Stisvc.exe replaces the Windows 98 stimon.exe component.
  2. The system provides a serial port kernel-mode driver, serscan.sys.
  3. Scsimap.dll does not exist for Windows 2000 and later.


Windows XP/Windows Me Core Components

The still image components for Windows XP and Windows Me are shown in the following figure.

Windows XP/Windows Me Core Components

The still image components in Windows XP and Windows Me differ considerably from those in Windows 98 and Windows 2000. On the service side (which is called server in Windows 98/Windows 2000), svchost.exe (called stimon.exe on Windows Me) acts as a generic host for the service, and communicates with wiaservc.dll, which operates on a more detailed level. Wiaservc.dll communicates with one or more user-mode still image drivers (labeled USD1, USD2, and USD3 in the figure), each of which communicates with a particular type of kernel-mode driver. As does Windows 2000, Windows XP and Windows Me provide three types of bus abstraction: USB, SCSI, and serial, represented by usbscan.sys, scsiscan.sys, and serscan.sys.

On the client side, an application can be either a TWAIN-compatible application (see Support for TWAIN-Compatible Applications) or a WIA application. A TWAIN application calls into the Data Source Manager, which in turn calls into wiadss.dll, a translation component that communicates with an instance of sti.dll (not shown in preceding figure). Sti.dll is a stub that communicates with the WIA service. In contrast, a WIA application makes calls directly to sti.dll.


Starting and Stopping the Still Image Service

Users do not ordinarily need to start or stop the Still Image service, but developers must start or stop this service when they install or uninstall drivers. You can start and stop the Still Image service in either of two different ways:

  1. Issue commands in a command window.

    To start the Still Image service, issue this command:

    net start stisvc

    To stop the Still Image service, issue this command:

    net stop stisvc
  2. Use the Microsoft Management Console (MMC).

    Under Services, select Still Image Services. To start the service, right-click, and then click Start from the menu that appears.

    To stop the service, right-click, and then click Stop from the menu that appears.


Application Items and Driver Items

Imaging applications see a WIA device as a hierarchical tree of items, with the root item representing the device itself and any child items representing actual images or folders that contain images. The tree that an application sees, however, is separate from the tree that is created and maintained by a WIA minidriver. When a minidriver creates a tree of items, the WIA service automatically creates an identical tree that can be viewed by imaging applications. Items in such a tree are called application items. Items in the tree created by a minidriver are called driver items.

More than one imaging application can use a single imaging device at the same time. Each application's view of an item object in a device tree must therefore be independent of another application's view. This is accomplished as follows:

  • A minidriver creates an item tree of IWiaDrvItem objects using the IWiaMiniDrv interface and the WIA driver services library functions. The items in this driver item tree are global objects that the minidriver uses to represent the device's items.
  • When an imaging application requests access to an item in the tree, the WIA service returns an item object that is a copy of the driver item. When an application acquires an application IWiaItem item object (also called an application item), this object is linked to the minidriver's corresponding IWiaDrvItem object in the driver item tree. The IWiaItem interface is defined in the Platform SDK documentation.

Applications typically use the IWiaItem object to read, validate and write item properties and to request item data.

The following figure shows the relationship of application items to driver items.

Application and Driver Items

The remainder of this section contains the following topics:

WIA Driver Item Tree

WIA Camera Tree

WIA Scanner Tree

Common, Camera, and Scanner Properties


WIA Driver Item Tree

In WIA, an imaging device is represented logically as a hierarchical tree of WIA items as shown in the following figure.

WIA Driver Item Tree

The root item represents the actual device. Child items represent images or folders. Folders can contain images or other folders. Items have properties that can be queried or set by the minidriver.

Going through the WIA service, an application uses an item to perform such tasks as getting and setting device information, controlling the device, and starting driver item enumeration.

Applications can call the IWiaMiniDrv::DrvAcquireItemData method to acquire data from an item by requesting a data transfer from the item.


WIA Camera Tree

The following figure shows a sample driver item tree for a camera.

Sample Camera Tree

The root item, which is the camera itself, consists of common device properties (properties that are common to both cameras and scanners), and camera-specific device properties. Similarly, each child item consists of properties common to both camera and scanner items, as well as properties that are specific to camera items.

Through the WIA service, an application can perform the following tasks from a camera item:

  • Query camera capabilities
  • Set camera device properties
  • Request a data transfer

In the preceding figure, the camera root item has three child items: two pictures and one folder. The folder has two child items that are both pictures. Camera items might also represent sound data or any other data on the camera that the device is to present to the application.


WIA Scanner Tree

The following figure shows a sample driver item tree for a scanner.

Sample Scanner Tree

The root item, which is the scanner itself, consists of common device properties (properties that are common to both cameras and scanners), and scanner-specific device properties. Similarly, each child item consists of properties common to both camera and scanner items, as well as properties that are specific to scanner items.

Through the WIA service, an application can request the following from a scanner item:

  • Query scanner capabilities
  • Set scanner device properties
  • Request a data transfer

Directly below the root item, a typical scanner object has a single item, the scanner item, which represents the data-collecting functionality of the device. An application sets up a scan by setting the properties of the scanner item. The scan is executed when data from the item is requested by the application through the WIA service.

Applications typically expect flatbed scanners, including those with automatic document feeders (ADFs), to be represented by two items — a root item and a single child. All data transfers are performed from the child item. A driver may choose to create other items for its private use, and these items can be made transfer-capable. (To do so, set the WiaItemTypeTransfer bit of the item type flag in a call to wiasCreateChildAppItem. This constant is documented in the Platform SDK documentation.) However, applications generally do not know about these private items, and do not know how to manipulate them. For a scanner with an ADF, the ADF functionality is exposed and controlled through the addition of the WIA_DPS_DOCUMENT_HANDLING_XXX properties (described in the Platform SDK documentation) to the root item, rather than by additional items.

If a device has a flatbed, and an ADF, and can do DUPLEX scans, the driver would report the WIA_DPS_DOCUMENT_HANDLING_CAPABILITIES property as (FEED | FLAT | DUP). Make sure that the valid values for WIA_DPS_DOCUMENT_HANDLING_SELECT are set correctly.

As an example, suppose an application intends to perform a DUPLEX scan of three pages from the ADF. To accomplish this, the application would set the WIA_DPS_DOCUMENT_HANDLING_SELECT property to (FEEDER | DUPLEX), and would set the WIA_DPS_PAGES property to 3. If the application wants to scan the front of the page first, it should set the WIA_DPS_DOCUMENT_HANDLING_SELECT property to (FEEDER | DUPLEX | FRONT_FIRST). After this is done, the application would navigate to the first child item, from which it would request a data transfer. The minidriver would report the front of the first page in the ADF as page 1, the back of that page as page 2, and the front of the second page in the ADF as page 3.


Common, Camera, and Scanner Properties

WIA properties are attributes of either a device (the root) or an item (a child). Device properties contain information about the device, such as the manufacturer's name, a description of the device, its type (scanner or camera), among others. Item properties contain information about a particular item, such as the item's name, when it was captured, and so on. Device properties are identified by the WIA_D naming convention; item properties are identified by the WIA_I naming convention.

The three-letter acronym in the middle of a WIA property name encodes information about the type of property: whether it is a generic device information property (DIP), a device property (DPA, DPC, or DPS), or an item property (IPA, IPC, or IPS). Device and item properties can be common to both types of devices (DPA and IPA), can be specific to cameras (DPC or IPC), or can be specific to scanners (DPS and IPS). The following table lists the various WIA property types, and gives examples of each type.

Property Type | Meaning
WIA_DIP_XXX | Device Information Property - setup and installation information common to both scanner and camera devices. These properties are provided by the WIA service. A minidriver does not need to provide them.
WIA_DPA_XXX | Device Property, All - information that is common to both scanner and camera devices, such as connection status and device time.
WIA_IPA_XXX | Item Property, All - information that is common to both camera and scanner items, such as the item's name, and the type of image.
WIA_DPC_XXX | Device Property, Camera - information that is specific to camera devices, such as the number of pictures taken.
WIA_IPC_XXX | Item Property, Camera - information that is specific to camera items, such as width and height of thumbnail images.
WIA_DPS_XXX | Device Property, Scanner - information that is specific to scanner devices, such as bed size.
WIA_IPS_XXX | Item Property, Scanner - information that it is specific to scanner items, such as horizontal and vertical resolution.

See the Platform SDK documentation for a complete list of all WIA common, camera-specific, and scanner-specific properties.


About Contexts

Much of the information that is passed between the WIA service, a WIA minidriver, and a WIA device is in the form of a context of one kind or another. These can be WIA service contexts (also known as application item contexts), property contexts, transfer contexts, or device-specific contexts. Each type of context is discussed in this topic.

Application item contexts

Property contexts

Transfer contexts

Device-specific contexts


Application Item Contexts

An application item context, also known as a WIA service context, is a reference to a root or child item that the WIA service passes to the minidriver in a call to one of several IWiaMiniDrv interface methods. The minidriver then uses this reference when it calls certain WIA Service Library functions. The application item context for the item indicates which item is to be processed in the method. The minidriver should not attempt to directly access the application item context. A minidriver can determine whether the item is a root item or a child item by calling the driver services library function, wiasGetItemType.

When an application requests a data transfer from the device to a WIA item it created, it calls on the WIA service to initiate such a transfer. The WIA service passes the application item's context to a minidriver entry point such as the MiniDrv::drvAcquireItemData method. Subsequently, when the minidriver uses a WIA service library function such as wiasReadPropLong, and passes in the application item context, the WIA service reads the specified property from the property storage associated with that application item.


Property Contexts

A property context provides a convenient way for a minidriver to identify a number of properties in which it is interested during validation of those properties. Using a property context, a minidriver can quickly determine whether any of the identified properties are being changed. The minidriver then passes the property context to one of the WIA service library functions (wiasGetChangedValueFloat, for example), which use the context to determine whether an application is changing a property's value.

The WIA approach to validation is that when an application changes a property, any dependent properties should also be updated. If, however, the application is also changing dependent properties, simply check the top-level property to determine whether its new value is valid. The WIA service library functions that are concerned with property validation use this precept to decide when they should update dependent properties, and when they should just check for validity.

Context for a set of properties is maintained in a WIA_PROPERTY_CONTEXT structure, which contains three members: the number of properties in the property context, a pointer to an array of property identifiers (PROPIDs), and a pointer to an array of BOOL values. The arrays are maintained in parallel; that is, the property whose property identifier is at index N in the property identifier array is associated with the BOOL value at the same index in the BOOL array.

The minidriver calls the WIA service library function, wiasCreatePropContext, to allocate memory and fill in the values for a property context. Other WIA service library functions, such as wiasGetChangedValueFloat, use a property context to determine when a property's values should be updated.


Transfer Contexts

A transfer context is a collection of information that describes a data transfer from the minidriver to an application. Information about the transfer is stored in a MINIDRV_TRANSFER_CONTEXT structure. A transfer context includes members that contain information about the image that is to be transferred: its size, resolution, color depth (number of bytes per pixel), type of compression, image format, and so on. The WIA service obtains these values from the relevant WIA item properties before it calls the IWiaMiniDrv::drvAcquireItemData method. The values are then stored in a MINIDRV_TRANSFER_CONTEXT structure and handed down to the driver for convenient access. This eliminates the need for the driver to use the WIA service library routines to read these values from the application item context (the WIA service context).

A transfer context also includes information about the type of transfer: whether it is a file data transfer or a memory-callback transfer (see Transferring Data to an Application). For file data transfers, one member contains a handle to the file that will be written. It is recommended that minidrivers not touch this handle. The WIA service opens the handle before the transfer occurs, and closes it upon completion of the transfer. For memory-callback data transfers (and for file data transfers where the application is to receive updates from the minidriver), a member contains the address of the minidriver's callback routine.

Other members contain such information as the total size of all buffers used in the transfer, and whether they were allocated by the minidriver or by the WIA service. See MINIDRV_TRANSFER_CONTEXT for a complete list of members of this structure.

The minidriver, together with the wiasGetImageInformation function, sets many of the transfer context items that describe the image itself, such as its width in pixels, the number of lines, and so on. The WIA service sets many of the transfer context items that are concerned with the data transfer, such as the file handle (when applicable), the type of transfer, and others.


Device-Specific Contexts

Minidrivers can optionally make use of a private context for storing device-specific information. This device-specific context can reduce the number of times that a minidriver must call the device to obtain device information. There can be only one device-specific context for each driver item of a particular minidriver. When the driver item is no longer needed, the WIA service calls the minidriver's IWiaMiniDrv::drvFreeDrvItemContext method to free all resources attached to the device-specific context.

For example, when a serial port camera driver retrieves thumbnail data from the device, it usually caches the data in the driver context associated with the appropriate driver item. Note that the actual freeing of the context itself is done by the WIA service. The driver's responsibility is simply to free any resources held by their context. If the thumbnail data of the previous example was stored in memory allocated on the device-specific context, the memory holding that cached data should be freed here, but not the context itself.


WIA DDI Interfaces

The WIA DDI supplies the following interfaces and functions to developers of WIA minidrivers:

  • IWiaMiniDrv COM interface, which provides the minidriver communication methods. These methods are the entry points for all communication between the WIA service and the minidriver. These methods enable the WIA service to control the device.
  • WIA driver services library (wias Xxx functions), which provide helper functions for WIA minidrivers. You can use these functions to perform many common tasks for which you would otherwise have to write custom functions.
  • WIA utility library, which provides additional helper functions and three classes that can be used by WIA minidrivers.
  • IWiaMiniDrvCallBack COM interface, which provides a callback method for WIA minidrivers to use during a callback data transfer.
  • IWiaDrvItem COM interface, which provides methods for a minidriver to maintain the device's tree of IWiaDrvItem objects.
  • User Interface Extensions, which allow IHVs to supply features for their devices that are not available through the default WIA user interfaces.
  • IWiaLog COM interface, which provides methods and macros that enable WIA minidrivers to log messages to a diagnostic log file.


IWiaMiniDrv COM Interface

Imaging applications make requests to the WIA service, which in turn communicates with the device minidriver through the minidriver writer-implemented IWiaMiniDrv interface. Applications typically make requests to do the following:

Create the item tree

Delete an item in a device tree

Enumerate device capabilities

Enumerate device image formats

Issue device commands

Lock or unlock a device

Notify a device of an event

Obtain device error strings

Read or write item properties

Transfer data from an imaging device

Applications make requests to the WIA service through the WIA API. See the Platform SDK documentation for more information on this interface.

The IWiaMiniDrv interface provides the entry points shown in the following tables for the WIA service to control the device. A WIA minidriver must implement every IWiaMiniDrv method. These entry points are defined through the following IWiaMiniDrv methods:

Creating and Initializing Items

Method | Description
IWiaMiniDrv::drvAnalyzeItem | Inspects an item, and, if necessary, creates subitems.
IWiaMiniDrv::drvInitializeWia | Initializes the WIA minidriver.
IWiaMiniDrv::drvInitItemProperties | Initializes driver item properties for each item in an application item tree.

Deleting Items

Method | Description
IWiaMiniDrv::drvDeleteItem | Deletes a driver item.
IWiaMiniDrv::drvFreeDrvItemContext | Frees a device-specific context.
IWiaMiniDrv::drvUnInitializeWia | Releases device resources associated with an application item tree.

Enumerating Device Capabilities

Method | Description
IWiaMiniDrv::drvGetCapabilities | Reports the events notifications and commands supported by a WIA minidriver.

Enumerating Image Formats

Method | Description
IWiaMiniDrv::drvGetWiaFormatInfo | Gets supported device formats and media types.

Issuing Device Commands

Method | Description
IWiaMiniDrv::drvDeviceCommand | Issues a command to an imaging device.

Locking and Unlocking a Device

Method | Description
IWiaMiniDrv::drvLockWiaDevice | Locks access to an imaging device.
IWiaMiniDrv::drvUnLockWiaDevice | Unlocks access to an imaging device.

Notifying a Device of an Event

Method | Description
IWiaMiniDrv::drvNotifyPnpEvent | Indicates a WIA minidriver's response to a PnP event.

Obtaining Device Error Strings

Method | Description
IWiaMiniDrv::drvGetDeviceErrorStr | Maps a device error value to a string.

Reading and Storing Item Properties

Method | Description
IWiaMiniDrv::drvReadItemProperties | Reads driver item properties.
IWiaMiniDrv::drvValidateItemProperties | Validates driver item properties.
IWiaMiniDrv::drvWriteItemProperties | Writes driver item properties to the device (if needed).

Transferring Data

Method | Description
IWiaMiniDrv::drvAcquireItemData | Transfers data from a driver item to the WIA service.


Error Reporting

All methods in the IWiaMiniDrv interface return a COM HRESULT value. If the method succeeds, the minidriver returns S_OK and clears the device error value pointed to by the method parameter plDevErrVal. If the method fails, the minidriver returns a standard COM error code and sets *plDevErrVal with a device-specific error code. The WIA service can call the IWiaMiniDrv::drvGetDeviceErrorStr method to obtain the error message string associated with the value pointed to by plDevErrVal. See the Platform SDK for more information on COM error values.


WIA Driver Services Library

The WIA driver services library contains functions that a WIA minidriver can call for assistance in performing the following tasks:

Building and maintaining an item tree

Logging error and trace messages

Reading and storing an item's properties

Updating and transferring data

A WIA minidriver calls most of these functions from its IWiaMiniDrv interface methods as needed. Each WIA minidriver, however, must call the wiasCreateDrvItem function in the IWiaMiniDrv::drvInitializeWia method to create driver items. Each successful call to a wiasCreateDrvItem function creates an IWiaDrvItem item object, which is used in the minidriver's item tree. Several IWiaDrvItem interface methods have a parameter of type IWiaDrvItem, including the IWiaDrvItem::AddItemToFolder, IWiaDrvItem::GetFirstChildItem, IWiaDrvItem::GetNextSiblingItem, IWiaDrvItem::GetParentItem, and other methods. Also, the wiasGetDrvItem function has a parameter of this type.

The driver services library provides the following functions:

Building and Maintaining an Item Tree

Function | Description
wiasCreateChildAppItem | Creates a new application item and inserts it as a child of the specified (parent) item.
wiasCreateDrvItem | Creates an IWiaDrvItem object.
wiasGetChildrenContexts | Retrieves an array of item contexts belonging to the current item's children.
wiasGetContextFromName | Retrieves the item context for an item name.
wiasGetDrvItem | Retrieves a driver item.
wiasGetRootItem | Retrieves the root item context of a specified WIA item.

Logging Error and Trace Messages

Function | Description
wiasCreateLogInstance | Creates an instance of a logging object.
wiasDebugError | Prints a debug error string in the device manager debug console. The output color is always red. This function is provided for compatibility only. Writers of new WIA drivers are encouraged to use WIAS_LERROR instead.
wiasDebugTrace | Prints a debug trace string in the device manager debug console. This function is provided for compatibility only. Writers of new WIA drivers are encouraged to use WIAS_LTRACE instead.
wiasFormatArgs | Formats an argument list into a packaged string for logging.
wiasPrintDebugHResult | Prints an HRESULT string on the device manager debug console. This function is provided for compatibility only. Writers of new WIA drivers are encouraged to use WIAS_LHRESULT instead.

Reading and Storing an Item's Properties

Function | Description
wiasCreatePropContext | Allocates a property context to indicate which of an item's properties are changing.
wiasFreePropContext | Releases the memory occupied by a WIA_PROPERTY_CONTEXT structure.
wiasGetChangedValueFloat | Determines whether a property with a floating point value has been changed by an application.
wiasGetChangedValueGuid | Determines whether a property with a GUID value has been changed by an application.
wiasGetChangedValueLong | Determines whether a property with a long integer value has been changed by an application.
wiasGetChangedValueStr | Determines whether a property with a string value has been changed by an application.
wiasGetItemType | Indicates a root or child item.
wiasGetPropertyAttributes | Retrieves the access flags and valid values for a set of properties.
wiasIsPropChanged | Tests whether the specified property has been changed by an application.
wiasReadMultiple | Reads multiple properties from a WIA item.
wiasReadPropBin | Reads a single binary property from a WIA item.
wiasReadPropFloat | Retrieves a floating point property value from a WIA item.
wiasReadPropGuid | Retrieves a GUID property value from a WIA item.
wiasReadPropLong | Retrieves a long integer property value from a WIA item.
wiasReadPropStr | Retrieves a string property value from a WIA item.
wiasSetItemPropAttribs | Sets the access flags and valid values for an item's set of properties.
wiasSetItemPropNames | Writes property names to item properties.
wiasSetPropChanged | Modifies a property context to indicate that a property is being changed.
wiasSetPropertyAttributes | Sets the access flags and property values of an item's properties.
wiasSetValidFlag | Sets the valid values for a WIA_PROP_FLAG property.
wiasSetValidListFloat | Sets the valid values for a WIA_PROP_LIST property of type sub-VT_R4.
wiasSetValidListGuid | Sets the valid values for a WIA_PROP_LIST property of sub-type VT_CLSID.
wiasSetValidListLong | Sets the valid values for a WIA_PROP_LIST property of type sub-VT_I4.
wiasSetValidListStr | Sets the valid values for a WIA_PROP_LIST property of type sub-VT_BSTR.
wiasSetValidRangeFloat | Specifies the range of valid values for a WIA_PROP_RANGE property of sub-type VT_R4.
wiasSetValidRangeLong | Specifies the range of valid values for a WIA_PROP_RANGE property of sub-type VT_I4.
wiasUpdateValidFormat | Updates the valid format of the property context for the current minidriver.
wiasValidateItemProperties | Validates a list of simple item properties against their current valid values.
wiasWriteMultiple | Writes multiple property values to a WIA item (the properties may be of different types).
wiasWritePropBin | Writes a single binary property value to a WIA item.
wiasWritePropFloat | Writes a floating point property value to a WIA item.
wiasWritePropGuid | Writes a GUID property value to a WIA item.
wiasWritePropLong | Writes a long integer property value to a WIA item.
wiasWritePropStr | Writes a string property value to a WIA item.

Updating and Transferring Data

Function | Description
wiasDownSampleBuffer | Takes in a buffer of pixel data and downsamples it to the specified size.
wiasGetImageInformation | Retrieves transfer context information from an item.
wiasParseEndorserString | Parses an endorser string, replacing WIA service-defined and vendor-defined tokens in the string with values associated with the tokens.
wiasSendEndOfPage | Calls the client callback routine during a data transfer, sending the current total page count.
wiasUpdateScanRect | Updates the scanning area sizes of the scanning device.
wiasWriteBufToFile | Writes the contents of a temporary page buffer to an image file.
wiasWritePageBufToFile | Writes the contents of a temporary page buffer to an image file. Use this function to write a page to a multipage TIFF file.


WIA Utility Library

The WIA Utility Library is a collection of helper functions and classes that a WIA minidriver can use to carry out often-performed tasks. The wiauDbg Xxx functions can be used to log trace messages, warning messages, and error messages when you are developing your WIA minidriver. Other functions in this library can be used for such purposes as getting data from the system registry, copying /converting strings in either ANSI or Unicode format, and calculating the dimensions of an image.

WIA Functions for Debugging

General WIA Utility Functions

CWiauDbgFn Class

CWiauFormatConverter Class

CWiauPropertyList Class


WIA Functions for Debugging

Function | Description
wiauDbgDump | Logs a message containing one or more data values.
wiauDbgError | Logs an error message.
wiauDbgErrorHr | Logs a message containing an HRESULT and its error message string.
wiauDbgFlags | Determines whether a particular debugging flag is set.
wiauDbgHelper | Formats a message and writes it to a log file and/or the debugger.
wiauDbgHelper2 |
wiauDbgInit | Initializes WIA debugging.
wiauDbgLegacyError | Logs an error message.
wiauDbgLegacyError2 | Logs an error message.
wiauDbgLegacyHresult2 |
wiauDbgLegacyTrace | Logs a trace message.
wiauDbgLegacyTrace2 |
wiauDbgLegacyWarning |
wiauDbgSetFlags | Sets debugging flags.
wiauDbgTrace | Logs a trace message.
wiauDbgWarning | Logs a warning message.


General WIA Utility Functions

The functions listed in this section can be used for such purposes as getting the driver item context, getting information from the system registry, and copying a string.

Function | Description
wiauGetDrvItemContext | Gets the driver item context, and optionally, the driver item.
wiauGetResourceString | Gets a resource string, storing it as a BSTR.
wiauGetValidFormats | Calls the IWiaMiniDrv::drvGetWiaFormatInfo method and makes a list of valid formats, using a specified tymed value.
wiauPropInPropSpec | Determines whether a specified property specification ID is contained in an array of such values. The function optionally gets the index at which the property specification ID was found.
wiauPropsInPropSpec | Determines whether any of a list of property specification IDs is contained within an array of such values.
wiauRegGetDword | Gets a DWORD value from the DeviceData section of the registry.
wiauRegGetStr | Gets a string value from the DeviceData section of the registry.
wiauRegOpenData | Opens the DeviceData registry key.
wiauSetImageItemSize | Calculates the size and width, in bytes, for an image, based on the current WIA_IPA_FORMAT setting (defined in the Platform SDK documentation), and writes the new values to the appropriate properties.
wiauStrC2C | Copies an ANSI character string to another ANSI character string.
wiauStrC2W | Converts an ANSI character string to a Unicode string.
wiauStrW2C | Converts a Unicode string to an ANSI character string.
wiauStrW2W | Copies a Unicode string to another Unicode string.


WIA Utility Classes

This section describes the three helper classes that are part of the WIA Utility Library:

CWiauDbgFn class

CWiauFormatConverter class

CWiauPropertyList class

CWiauDbgFn Class

The CWiauDbgFn class is a helper class for function or method entry/exit point tracing.

Method | Description
CWiauDbgFn::CWiauDbgFn | Class constructor
CWiauDbgFn::~CWiauDbgFn | Class destructor

CWiauFormatConverter Class

The CWiauFormatConverter class is a helper class for converting images to BMP format.

Method | Description
CWiauFormatConverter::CWiauFormatConverter | Class constructor
CWiauFormatConverter::~CWiauFormatConverter | Class destructor
CWiauFormatConverter::ConvertToBmp | Converts an image to BMP format.
CWiauFormatConverter::Init | Initializes the class and GDI+ for converting images.
CWiauFormatConverter::IsFormatSupported | Verifies that GDI+ supports the image format that is to be converted.

CWiauPropertyList Class

The CWiauPropertyList class is a helper class for defining and initializing WIA property lists.

Method | Description
CWiauPropertyList::CWiauPropertyList | Class constructor
CWiauPropertyList::~CWiauPropertyList | Class destructor
CWiauPropertyList::DefineProperty | Adds a property definition to the property list object.
CWiauPropertyList::GetPropId | Gets the property ID for a property at a specified index.
CWiauPropertyList::Init | Initializes the property list object.
CWiauPropertyList::LookupPropId | Gets the property index for a property with a specified property ID.
CWiauPropertyList::SendToWia | Calls the WIA service to define all of the properties currently contained in a property list object.
CWiauPropertyList::SetAccessSubType | Resets the access and subtype of a property.
CWiauPropertyList::SetCurrentValue(BYTE*) | Sets the value of a property whose type is of BYTE array.
CWiauPropertyList::SetCurrentValue(BSTR) | Sets the value of a property whose type is BSTR.
CWiauPropertyList::SetCurrentValue(CLSID) | Sets the value of a property whose type is CLSID.
CWiauPropertyList::SetCurrentValue(FLOAT) | Sets the value of a property whose type is FLOAT.
CWiauPropertyList::SetCurrentValue(LONG) | Sets the value of a property whose type is LONG.
CWiauPropertyList::SetCurrentValue(SYSTEMTIME) | Sets the value of a property whose type is SYSTEMTIME (described in the Platform SDK documentation).
CWiauPropertyList::SetValidValues(BSTR, list) | Sets the type, as well as the default, current, and valid values of a list of BSTR values.
CWiauPropertyList::SetValidValues(CLSID, list) | Sets the type, as well as the default, current, and valid values of a list of CLSID values.
CWiauPropertyList::SetValidValues(flag) | Sets the type, as well as the default, current, and valid values of a property whose values are determined by flag settings.
CWiauPropertyList::SetValidValues(FLOAT, list) | Sets the type, as well as the default, current, and valid values of a list of FLOAT values.
CWiauPropertyList::SetValidValues(FLOAT, range) | Sets the type, as well as the default, current, and valid values of a range of FLOAT values.
CWiauPropertyList::SetValidValues(LONG, list) | Sets the type, as well as the default, current, and valid values of a list of LONG values.
CWiauPropertyList::SetValidValues(LONG, range) | Sets the type, as well as the default, current, and valid values of a range of LONG values.


IWiaMiniDrvCallback COM Interface

The IWiaMiniDrvCallBack interface provides one link in a communication chain between a minidriver and an application. Since a minidriver cannot communicate directly with an application, and vice versa, any communication between the two must go through an intermediary: the WIA service. To enable this communication, the application implements the IWiaDataCallback interface (described in the Platform SDK documentation). This interface includes the IWiaDataCallback::BandedDataCallback method, which the WIA service can call. If an application provides this callback routine, the WIA service creates another callback, the IWiaMiniDrvCallBack::MiniDrvCallback method, which it provides for use by the minidriver.

When the minidriver intends to send image data from the imaging device or to transfer status messages (the percentage of data transferred, for example), it calls the WIA service's IWiaMiniDrvCallBack::MiniDrvCallback. The WIA service then passes the data or messages along to the application when it calls the application's callback.


IWiaDrvItem COM Interface

The IWiaDrvItem interface provides methods that a WIA minidriver uses to manage a tree of IWiaDrvItem items. These methods allow a WIA minidriver to manipulateIWiaDrvItem objects. The IWiaDrvItem interface supplies the following methods:

Method | Description
IWiaDrvItem::AddItemToFolder | Adds the IWiaDrvItem object into a folder.
IWiaDrvItem::DumpItemData | Dumps private driver item data.
IWiaDrvItem::FindChildItemByName | Locates a child item by full item name.
IWiaDrvItem::FindItemByName | Locates an item by full item name.
IWiaDrvItem::GetDeviceSpecContext | Retrieves a pointer to a device-specific context.
IWiaDrvItem::GetFirstChildItem | Returns the first child of this folder item.
IWiaDrvItem::GetFullItemName | Retrieves full item name and hierarchy information.
IWiaDrvItem::GetItemFlags | Returns WIA item flags.
IWiaDrvItem::GetItemName | Retrieves the item name.
IWiaDrvItem::GetNextSiblingItem | Finds the next sibling of this item.
IWiaDrvItem::GetParentItem | Retrieves the parent item of this item.
IWiaDrvItem::RemoveItemFromFolder | Removes an item from parent folder.
IWiaDrvItem::UnlinkItemTree | Unlinks the driver item tree.


IWiaLog COM Interface

The IWiaLog interface provides methods that assist a WIA minidriver in message logging. The methods in this interface allow a minidriver to write error, trace, and warning messages to a log. The IWiaLog interface provides the following methods:

Method | Description
IWiaLog::InitializeLog | Initialize the logging utility
IWiaLog::Log | Log a message to a file or other target.
IWiaLog::hResult | Translate an HRESULT into a string.

The IWiaLog interface is provided for backward compatibility only. For new WIA drivers, driver writers are encouraged to use the following macros. Three of these macros can be used to write a logging statement with, respectively, a specified type of error, trace, or warning. The fourth macro can be used to translate an HRESULT into a descriptive string.

Macro | Description
WIAS_LERROR | Writes a log statement of type ERROR to the specified target.
WIAS_LHRESULT | Translates an HRESULT value into a string and writes the string to the diagnostic log file.
WIAS_LTRACE | Writes a log statement of type TRACE to the specified target.
WIAS_LWARNING | Writes a log statement of type WARNING to the specified target.

See IWiaLog Interface and Diagnostic Log Macros for more information.


WIA Logging Configuration Tool

WIA provides the executable Wialogcfg.exe, which can be used to set logging settings for WIA components and to view the WIA log file. When it is first started, the tool shows two entries under Select a Module. The first is STICLI, which is the class installer; the second is STIMON, the event monitor. You should use the Add a NEW Module button to add WIASERVC and the name of your minidriver DLL, without the file extension (for example, WIATSCAN for the sample scanner).

Use the Select Logging Type area to select the type of messages that are written to the log: trace, warning, or error messages. The choices under Select a TRACE Logging Detail LEVEL can be used to further refine which trace messages are written. In your minidriver, you can use the trace levels in any manner you desire, but for the WIA components and the samples a convention has been set:

Level | Description
1 | Log entry and exit messages for important functions.
2 | Log all trace messages for important functions.
3 | Log entry and exit messages for less important functions (for example, helpers).
4 | Log all trace messages for less important functions.

Select Additional Information allows you to select the information to write for each message, time, module name, and/or thread ID.

The three settings, logging type, additional information, and trace level, are kept on a per-module basis. Each module can have its own settings for each area. After altering the settings for a module, you must use the Write Settings button to write the settings to the registry.

Select Optional Features provides some special options for logging. You can set the Truncate on BOOT or Clear Log File on BOOT options only for the WIASERVC module. Log to Debugger writes the messages to your debugger window. This is useful when you want to see a dynamic display of the messages. The View Log button does not provide a dynamically updated view of the log. However, the log file is useful for catching race conditions where the debugger output might alter the timing too much.

The View Log button brings up a window displaying the log file. You can select Color Code Log Viewer Text to apply a different color to each of the different types of messages for easy identification, although it takes longer to display the log.

Changes to the settings do not take affect immediately. You must stop the WIA service ("c:\windows\system\stimon –q") and restart it ("c:\windows\system\stimon").


Sample WIA Driver Components

This DDK provides the following subdirectories that contain sample code for support of WIA devices:

\wiascanr
Source code for a user-mode WIA minidriver for a flatbed scanner with an attached document feeder. This sample simulates scanning by producing a test pattern image.
\wiascroll
Source code for a user-mode WIA minidriver for a scanner with a scroll-fed document feeder. This sample simulates scanning by producing a test pattern image.
\extend
Source code for a WIA user interface (UI) extension. This sample shows how to write a WIA UI extension. The sample extends the UI of the sample WIA minidriver for a camera.
\microdrv
Source code for a WIA scanner microdriver.
\wiacam
Source code for a WIA camera minidriver.
\microcam
Source code for a sample camera microdriver that works with the wiacam sample.


Creating A WIA Minidriver

A WIA minidriver should be able to do the following:

Provide a COM interface

Provide an IStiUSD interface

Initialize itself

Build a driver item tree

Initialize item properties

Read, validate, and write item properties

Keep properties up-to-date

Delete items from a driver tree

Disconnect an Application from a WIA Device

Inform an application of item tree changes

Transfer data to an application

Enumerate device formats

Provide event notification

Issue commands to a device

Enumerate capabilities of a device

Get device error messages

Access kernel-mode drivers

Implement Image Color Management

The following sections describe how a WIA minidriver performs these tasks.


Providing a COM Interface

In order for a minidriver to be recognized and loaded by the WIA service, the minidriver must be able to recognize the following COM interfaces identifiers:

  • IID_IWiaMiniDrv - IWiaMiniDrv interface identifier
  • IID_IStiUSD - IStiUSD interface identifier
  • IID_IUnknown - COM IUnknown interface (defined in the Platform SDK documentation) identifier

The minidriver exports these interface identifiers in response to the WIA service calling the minidriver's QueryInterface method. See the wiacam camera sample minidriver files IWiaMiniDrv.cpp and IStiUSD.cpp for examples of how these interfaces are implemented.


Providing an IStiUSD Interface

WIA builds on STI. In order to ensure the integration of a WIA minidriver with STI, the minidriver must implement an interface derived from the IStiUSD interface methods. This interface must be present in a WIA minidriver. The IStiUSD interface is the means by which the IStiDevice interface communicates with still image devices. A minidriver must fully implement an interface derived from the IStiUSD::Initialize method in order to be loaded by the WIA service.

Typically, IStiUSD interface methods are called by similarly named methods defined by the IStiDevice interface. Minidrivers typically implement IStiUSD interface methods by calling the appropriate kernel-mode driver. Each minidriver must define all interface methods, but if a method is not needed it can return STIERR_UNSUPPORTED.

See the wiacam camera sample minidriver file, IStiUSD.cpp, for an example of how a minidriver implements the IStiUSD interface.

The following table lists and describes all of the methods defined by the IStiUSD interface. Methods that must be implemented or conditionally implemented by WIA minidrivers are identified.

Method | Description
IStiUSD::DeviceReset | Resets a still image device to a known initialized state.
IStiUSD::Diagnostic | Runs diagnostic tests on a still image device. A WIA minidriver must implement this method.
IStiUSD::Escape | Performs a vendor-specific I/O operation on a still image device.
IStiUSD::GetCapabilities | Returns a still image device's capabilities.
IStiUSD::GetLastErrorInfo | Returns information about the last known error associated with a still image device.
IStiUSD::GetNotificationData | Returns a description of the most recent event that occurred on a still image device.
IStiUSD::GetStatus | Returns the status of a still image device. A WIA minidriver must implement this method if its device has objects, such as buttons, that can generate events.
IStiUSD::Initialize | Initializes an instance of the COM object that defines the IStiUSD interface. A WIA minidriver must implement this method.
IStiUSD::LockDevice | Locks a device for exclusive use by the caller. A WIA minidriver must implement this method.
IStiUSD::RawReadCommand | Reads command information from a still image device.
IStiUSD::RawReadData | Reads data from a still image device.
IStiUSD::RawWriteCommand | Writes command information to a still image device.
IStiUSD::RawWriteData | Writes data to a still image device.
IStiUSD::SetNotificationHandle | Specifies an event handle that the minidriver should use to inform the caller of device events. A WIA minidriver must implement this method if its device has objects, such as buttons, that can generate events.
IStiUSD::UnlockDevice | Closes the device port. A WIA minidriver must implement this method.


Initializing the WIA Minidriver

The first step in implementing the IWiaMiniDrv interface is to initialize the minidriver and create a hierarchical tree of driver items. To do this, the WIA service calls the IWiaMiniDrv::drvInitializeWia method each time a client application intends to use the device. If two or more applications are simultaneously using the device, the WIA service calls this method for each application. In this method, the minidriver typically does the following:

  1. Initializes parameters passed in from the WIA service.
  2. Saves the STI device interface pointed to by pStiDevice. This is done so that the IStiDevice::LockDevice and IStiDevice::UnlockDevice methods can be used to lock or unlock the WIA device.
  3. Caches bstrDeviceID and bstrRootFullItemName in member variables so that they can be used by other methods.
  4. Opens a handle to the device. (This step is recommended for non-shared ports such as USB, SCSI, and 1394).
  5. Builds the item tree, as described in Creating the WIA Driver Item Tree.

The IWiaMiniDrv::drvInitializeWia method also can be used to create and initialize dynamic arrays and structures that the driver uses. For example, an array of commands and events the driver supports can be created for later use by the IWiaMiniDrv::drvGetCapabilities method.

Note: The IWiaMiniDrv::drvGetCapabilities method might be called before IWiaMiniDrv::drvInitializeWia is called. This can happen when the WIA service needs to query for event information before an application exists to use the device. The IWiaMiniDrv::drvInitializeWia method is called only when an application signals its intent to use the device.

Keeping Track of Application Connections

As stated previously, when an application intends to communicate with a WIA device, the WIA service calls the appropriate driver's IWiaMiniDrv::drvInitializeWia method. When the application is finished with the device and releases all WIA references to it, the WIA service calls the appropriate driver's IWiaMiniDrv::drvUnInitializeWia method. Note that WIA supports multiple, simultaneous application connections. This means that two or more applications can request a WIA interface associated with the same device. It does not mean, though, that the driver must handle simultaneous requests; the WIA service ensures that only one request is sent to the driver at a time. However, the WIA service can call the IWiaMiniDrv::drvInitializeWia method multiple times before it calls the IWiaMiniDrv::drvUnInitializeWia method.

Why is this information useful? Often there are resources that drivers might need when applications are using them, such as the WIA driver item tree, image filtering libraries, and others. Because these resources can take up a large amount of memory, it is best to unload them when they are not needed.

Note: The IWiaMiniDrv::drvInitializeWia and IWiaMiniDrv::drvUnInitializeWia methods are used to inform drivers of application connections only. The WIA service can call other driver methods without first calling IWiaMiniDrv::drvInitializeWia, which means that the WIA service does not necessarily call IWiaMiniDrv::drvUnInitializeWia when it is done. The methods called are informational methods that do not require WIA items, such as IWiaMiniDrv::drvGetCapabilities and IWiaMiniDrv::drvGetWiaFormatInfo.

The following example demonstrates how the IWiaMiniDrv::drvInitializeWia method should be written to keep track of application connections.

/******************************************************************\
* drvInitializeWia
*
*  Initialize the WIA minidriver. This function is called each time
*  an application creates a device (that is, calls
*  IWiaDevMgr->CreateDevice - see the Platform SDK documentation).
*  The application then receives a WIA item pointer that it uses
*  to control the device, set properties, transfer data,
*  send device commands, and so on.
*  The first time this method is called, it creates the
*  driver item tree and performs other initialization.
\******************************************************************/

HRESULT CWiaDevice::drvInitializeWia(
  BYTE        *pWiasContext,
  LONG         lFlags,
  BSTR         bstrDeviceID,
  BSTR         bstrRootFullItemName,
  IUnknown    *pStiDevice,
  IUnknown    *pIUnknownOuter,
  IWiaDrvItem **ppIDrvItemRoot,
  IUnknown    **ppIUnknownInner,
  LONG        *plDevErrVal)
{
  DBG_FN("CWiaDevice::drvInitializeWia");
  HRESULT hr = S_OK;

  *plDevErrVal        = 0;
  *ppIDrvItemRoot     = NULL;
  *ppIUnknownInner    = NULL;

  // Count the number of applications connected so that resources
  // can be freed when the number reaches zero.
  //
  m_iConnectedApps++;

  wiauDbgTrace("drvInitializeWia",
      "Number of connected apps is now %d", m_iConnectedApps);

  if (m_iConnectedApps == 1)
  {
    //
    // Build the item tree, grab any needed resources, etc. Note: the
    // item tree is created at this time, but the item properties
    // are filled in only during subsequent drvInitItemProperties
    // calls. Therefore, there is no need to obtain all of this
    // information at this time. The driver can be made
    // much more responsive if it postpones getting this information
    // until it is really needed.
    //
     .
     .
     .
  }

    // In case the call fails, do not count this as another
    // connection, since the WIA service returns the failure
    // to the caller. The method incremented m_iConnectedApps
    // at the beginning of this method, so it should be
    // decremented if a failure is returned.
  if (FAILED(hr))
    m_iConnectedApps--;
  return hr;
}


Creating the WIA Driver Item Tree

After the minidriver is initialized, it must create the driver item tree in the IWiaMiniDrv::drvInitializeWia method by:

  1. Creating the driver item tree if it does not already exist. The minidriver sets the root item flags and creates the root item by calling the driver services library function wiasCreateDrvItem. The minidriver stores the returned pointer to the root item in a private member variable.
  2. Creating child items for each item on the device using the wiasCreateDrvItem function. This function creates a device-specific context where the minidriver can store information about the item.
  3. Calling the IWiaDrvItem::AddItemToFolder method on each child item to add the item to the driver item tree.


Initializing Item Properties

The IWiaMiniDrv::drvInitItemProperties method initializes the driver item properties. The WIA service calls this method once for every item in the application item tree. The item context, pointed to by the pWiasContext parameter, indicates which item is being used.

The method is used to initialize the following root and child item property information:

  • Property name
  • Default values
  • Property access
  • Property type
  • Valid property values

See the Platform SDK documentation for more information on WIA properties.

This method should define the appropriate properties for the item based on whether it is the root item or a child item. A minidriver can use the driver services library function wiasGetDrvItem to determine whether the item is the root item or a child item.

Three driver services library functions are useful for setting up properties: wiasSetItemPropNames, wiasWriteMultiple, and wiasSetItemPropAttribs. The wiasSetItemPropNames function can be used to set the names for the properties. The wiasWriteMultiple function is used to set the values for a batch of properties, which is more efficient than setting property values one at a time. The wiasSetItemPropAttribs function can be used to set property access and valid value information.

A property's access can be either WIA_PROP_READ (read-only), or WIA_PROP_RW (read/write). Valid value information for read-only properties is limited to the WIA_PROP_NONE subtype. Valid value information for read/write properties can be one of WIA_PROP_LIST (when the valid values are specified by a list of values), WIA_PROP_RANGE (when the valid values are specified by a range of values), or WIA_PROP_FLAG (when the valid values are specified by a bitset of flags), or WIA_PROP_NONE. For properties whose values do not change over time, the minidriver can set WIA_PROP_CACHEABLE on the property. This flag indicates that the WIA service can cache the property value. The WIA_PROP_XXX constants are described in the Platform SDK documentation, which also contains a list of pre-defined properties.

Custom Properties

If vendors want to define their own custom properties, they should use values based on WIA_PRIVATE_DEVPROP for custom root item properties, and on WIA_PRIVATE_ITEMPROP for custom child item properties. These constants are defined in wiadef.h.

The following example code shows definitions for three custom root item properties. The pattern can be continued if additional custom root item properties are needed.

#define CUSTOM_ROOT_PROP_1 WIA_PRIVATE_DEVPROP
#define CUSTOM_ROOT_PROP_2 (WIA_PRIVATE_DEVPROP + 1)
#define CUSTOM_ROOT_PROP_3 (WIA_PRIVATE_DEVPROP + 2)

The next example shows definitions for three custom child item properties. As before, the pattern can be continued if more of these custom child item properties are needed.

#define CUSTOM_CHILD_PROP_1 WIA_PRIVATE_ITEMPROP
#define CUSTOM_CHILD_PROP_2 (WIA_PRIVATE_ITEMPROP + 1)
#define CUSTOM_CHILD_PROP_3 (WIA_PRIVATE_ITEMPROP + 2)


Reading, Validating, and Writing Item Properties

To keep a device's properties up to date, applications make requests to read and write such properties. Applications make such requests to the WIA service, which in turn communicates with the minidriver by calling the IWiaMiniDrv::drvReadItemProperties method to read properties, and by calling the IWiaMiniDrv::drvValidateItemProperties method to validate properties. The WIA service calls the IWiaMiniDrv::drvWriteItemProperties method to write properties to the device. This method is typically called before data acquisition to set the device to the appropriate state for the correct data transfer (for example, to set the dpi on the scanner).

The WIA driver services library contains helper functions for assisting with property storage. These functions can be used as needed by the minidriver:

To read properties:

wiasReadPropStr

wiasReadPropLong

wiasReadPropBin

wiasReadPropFloat

wiasReadPropGuid

wiasReadMultiple

To write properties:

wiasWritePropStr

wiasWritePropLong

wiasWritePropBin

wiasWritePropFloat

wiasWritePropGuid

wiasWriteMultiple

To validate properties:

wiasValidateItemProperties

Refer to WIA Driver Services Library for a complete list of WIA property helper functions.


Reading Item Properties

When an application makes a request to read a device's properties, the WIA service calls the IWiaMiniDrv::drvReadItemProperties method. A minidriver can communicate property changes back to the application using either of two techniques:

  1. If the device is capable of sending information asynchronously when properties change, the minidriver can store the new values and update the WIA properties with the new values when IWiaMiniDrv::drvReadItemProperties is called.
  2. The minidriver can communicate with the device to read new values whenever IWiaMiniDrv::drvReadItemProperties is called.

A minidriver typically implements different logic in IWiaMiniDrv::drvReadItemProperties depending on whether the item is the root item or a child item. For this reason, the first operation in an implementation of this method is to call wiasGetItemType. The minidriver then uses other WIA service library functions (such as wiasWriteMultiple and wiasWriteProp Xxx) to update the requested properties with either locally stored values or values obtained directly from the device.

It is sometimes necessary for a minidriver to read a property from one item when it is currently at another item. In such cases, the minidriver must first move to the correct item, and then read its property. For example, if the minidriver has just completed a data transfer from a child item, and intends to read the WIA_DPS_DOCUMENT_HANDLING_SELECT property (described in the Platform SDK documentation) on the root item, it must move to the root item before reading this property. The following sample code uses wiasGetRootItem to move to the root item, and wiasReadPropLong to read the property. In the call to wiasGetRootItem, pWiasContext is the child item's application item context. When the function returns, pRootItemCtx points to the context for the root item. This sample code also uses the WIAS_LWARNING, WIAS_LERROR, and WIAS_LHRESULT macros for warning and error logging.

// Get a pointer to the root item, for property access.
BYTE *pRootItemCtx = NULL;
HRESULT hr = wiasGetRootItem(pWiasContext, &pRootItemCtx);
if (FAILED(hr)) {
    WIAS_LWARNING(m_pIWiaLog,WIALOG_NO_RESOURCE_ID,
                  ("Could not get root item!"));
    return hr;
}

// Get the current document handling select property,
// which will be stored in lSelect.
LONG lSelect = 0;
hr = wiasReadPropLong(pRootItemCtx,
                      WIA_DPS_DOCUMENT_HANDLING_SELECT,
                      &lSelect,
                      NULL,
                      TRUE);
if (hr != S_OK) {
    WIAS_LERROR(m_pIWiaLog, WIALOG_NO_RESOURCE_ID,
                ("Failed to read document handling select Property."));
    WIAS_LHRESULT(m_pIWiaLog, hr);
}

Instead of getting a pointer to the root item using wiasGetRootItem, as shown in the preceding code sample, the following code sample shows how to move from any child item directly to the root item (or any other item in the item tree) using wiasGetContextFromName. In this example, it is assumed that the driver has named the root item "XXXXX\Root", and that pChildWiasContext contains the address of the child item. If the call to wiasGetContextFromName succeeds, pRootCtx contains the address of the root item.

BYTE* pRootCtx;
BSTR bstrFullNameToSearchFor = SysAllocString(L"XXXXX\Root");

if (bstrFullNameToSearchFor)
    return E_OUTOFMEMORY;
hr = wiasGetContextFromName(pChildWiasContext,
                            0,
                            bstrFullNameToSearchFor,
                            &pRootCtx);
if (hr == S_OK) {
//   pRootCtx now contains the address of the root item
}


Validating Item Properties

The WIA service calls the IWiaMiniDrv::drvValidateItemProperties method to check whether new property values are valid for a device. The minidriver can update valid values in this method, and also change existing property values when a new property value causes another existing property value to become invalid. If the IWiaMiniDrv::drvValidateItemProperties method returns a failure, the WIA service resets any modified properties to their previous values.

The rules for WIA property validation are as follows:

  • Determine that the property values passed from the application are valid for the item.
  • If a property value is invalid because an application changed another property value, a minidriver must change the invalid property value to a proper value.
  • If necessary, update specific properties based on the new property values.
  • If the application wrote a property value, that value should not be changed by the minidriver. Instead, after all the dependent properties and valid values have been updated, the application-requested property value should be checked against its valid values, and a failure returned if it does not match.

A minidriver's implementation of the IWiaMiniDrv::drvValidateItemProperties method for a camera differs from that for a scanner. The steps involved in implementing this method for each type of device are shown next.

Implementing IWiaMiniDrv::drvValidateItemProperties for a Camera

  1. Call wiasValidateItemProperties to verify that the new values requested by the application are valid.
  2. Call wiasGetItemType to determine whether the item is the root item or a child item.
    • Root item validation depends on the specific device. Dependencies between properties should all be validated; where necessary, dependent properties should be updated or verified. All updated properties should be written to the device.
    • For child items, the value of the WIA_IPA_TYMED common item property can affect which formats are available. A driver can call wiasUpdateValidFormat to automatically update the format property. If the current format changes, the image size, width in bytes, and file extension should be updated.

Implementing IWiaMiniDrv::drvValidateItemProperties for a Scanner

A scanner minidriver's implementation of this method should avoid writing property values to the device, because it needs to write them again in IWiaMiniDrv::drvWriteItemProperties. The reason that property validation should be separated from property value writing is to enable multiple applications to manipulate properties without interfering with each other.


Writing Item Properties

The WIA service calls the IWiaMiniDrv::drvWriteItemProperties method immediately before it acquires an image, in order to send updated property values to the device. If the write operation is unsuccessful, the method reports a hardware failure code through the device error value parameter, plDevErrVal.

How a WIA minidriver implements the IWiaMiniDrv::drvWriteItemProperties method depends on whether the minidriver is for a camera or a scanner. A camera minidriver's implementation of this method should do nothing more than return S_OK.

A scanner's implementation should perform the following two tasks:

  1. Call either the wiasReadMultiple function or the appropriate wiasReadProp Xxx functions (such as wiasReadPropStr and others) to retrieve the updated property values.
  2. Call a device-specific function that writes the property values to the device.


Keeping Properties Up-to-date

Applications continually read and write properties. Because the values of certain properties change often, their values must be updated every time the properties are read from the device. Other property values are more stable, and the driver updates them as needed (for example, during item initialization or validation). Such properties already contain the correct values when an application attempts to read them.

The WIA service calls the IWiaMiniDrv::drvReadItemProperties method when an application must acquire one or more property values. This is an opportunity for the driver to update any values that have changed since the properties were first set in the IWiaMiniDrv::drvInitItemProperties method.

Most properties do not change once they have been set. For example, after the dimensions of a picture saved on a camera have been read and saved into the appropriate WIA properties, there is no need to update them.

An example of a property that changes is the device time property. On the root item, this represents the time on the device's internal clock. Instead of polling the device periodically for its new time value, simply query the device for its current time when it is needed. The following sample implementation of IWiaMiniDrv::drvReadItemProperties shows how this can be done.

/******************************************************************\
* drvReadItemProperties
*
*  Read the device item properties. When a client application tries
*  to read a WIA Item's properties, the WIA service first notifies
*  the driver by calling this method.
*
\******************************************************************/

HRESULT
  CWiaDevice::drvReadItemProperties(
      BYTE  *pWiasContext,
      LONG  lFlags,
      ULONG  nPropSpec,
      const PROPSPEC  *pPropSpec,
      LONG  *plDevErrVal)
{
  CWiaLogProc WIAS_LOGPROC(m_pIWiaLog,
                           WIALOG_NO_RESOURCE_ID,
                           WIALOG_LEVEL1,
                          "CWiaDevice::drvReadItemProperties");
  HRESULT hr = S_OK;
  LONG lItemType;

 *plDevErrVal = 0;
  hr = wiasGetItemType(pWiasContext, &lItemType);
  REQUIRE_SUCCESS(hr, "drvReadItemProperties",
                  "wiasGetItemType failed");

  // We are interested in the WIA_IPA_ITEM_TIME property, but
  // only on the root item. The WIA_IPA_ITEM_TIME property
  // on image items indicates when the picture was taken.
  // Since the root item represents the device, this property
  // on the root item represents the device's internal clock.

  if (lItemType & WiaItemTypeRoot)
  {
  // Is the item time being read?
     if (wiauPropInPropSpec (lNumPropSpecs,
                             pPropSpecs,
                             WIA_IPA_ITEM_TIME))
     {

  // If this is the device time property, ask the device for
  // its time, convert to SYSTEMTIME and write to WIA.
        if (propId == WIA_DPA_DEVICE_TIME)
        {
           MY_DEVICE_TIME_STRUCT devTime;
           hr = m_pDeviceApi->GetDeviceTime(&devTime);
           if (FAILED(hr))
           {
              wiauDbgError("drvReadItemProperties",
                           "GetDeviceTime failed");
              return hr;
           }
           SYSTEMTIME sysTime;
           hr = MyDeviceTimeToSystemTime(&devTime, &sysTime);
           if (FAILED(hr))
           {
              wiauDbgError("drvReadItemProperties",
                           "MyDeviceTimeToSystemTime failed");
              return hr;
           }

  // Put the time into a PROPVARIANT so it can be written.
           PROPVARIANT pv;
           pv.vt = VT_UI2 | VT_VECTOR;
           pv.caui.cElems = sizeof(SYSTEMTIME) / sizeof(WORD);
           pv.caui.pElems = (USHORT *) &st;

           PROPSPEC ps;
           ps.ulKind = PRSPEC_PROPID;
           ps.propid = propId;

           hr = wiasWriteMultiple(pWiasContext, 1, &ps, &pv);

  // If the write was successful, the WIA_IPA_TIME property's
  // new value has been written.
           if (FAILED(hr))
           {
              wiauDbgError("drvReadItemProperties",
                           "wiasWriteMultiple failed, "
                           "could not write WIA_IPA_TIME");
              return hr;
           }
        }
     }  // WIA_IPA_TIME is not being read on the root
        // Look for other properties to update
        .
        .
        .
  }
  else
  {
     // The item is not root item. Do similar processing for any
     // child item properties that must be updated
        .
        .
        .
  }

  return hr;
}


Deleting an Item from the Driver Tree

In order to delete a driver item, the WIA service calls the minidriver entry point IWiaMiniDrv::drvDeleteItem. In this method, the minidriver attempts to delete the item pointed to by the WIA service context parameter, pWiasContext. If the item is successfully deleted, the method returns S_OK and sets the device error value parameter, plDevErrVal, to zero. If a device error occurs, the method returns FAILED and a device-specific error value in plDevErrVal. The minidriver should call the wiasQueueEvent function to inform all connected applications that an item has been deleted.

After the root item has been deleted, the WIA service calls IWiaMiniDrv::drvFreeDrvItemContext to free the resources used by the driver-specific context. The WIA service then deletes the item and the driver-specific context.


Disconnecting an Application from a WIA Device

When an application has no further need of a WIA device, the WIA service calls the minidriver's IWiaMiniDrv::drvUnInitializeWia method. A WIA minidriver uses this method primarily to manage resources associated with an application's item tree. When the application closes, the resources associated with the application's item tree are no longer needed.

For a device with multiple applications running, the WIA service calls the IWiaMiniDrv::drvUnInitializeWia method each time an application releases its references to the WIA service. If applications are still connected, this method should do nothing. Freeing resources at this point can cause problems for the other connected applications. When the last remaining application closes its connection to the WIA service, this method should free all of the application item tree resources.

It is important to note that the IWiaMiniDrv::drvUnInitializeWia method does not unload the driver. The driver is still alive and may be called again to process events, or when an application intends to communicate with it.

The following example implementation of the IWiaMiniDrv::drvUnInitializeWia method shows how the minidriver can determine if applications are still connected. If the application that is closing is the last one connected to the device, this method calls the FreeResources method, implemented by the minidriver, to carry out such tasks as deleting the item tree, freeing storage used by strings, and so on.

/******************************************************************\
* drvUnInitializeWia
*
*  Terminate a client connection.
*
\******************************************************************/

HRESULT
  CWiaCameraDevice::drvUnInitializeWia(BYTE *pWiasContext)
{
  DBG_FN("CWiaCameraDevice::drvUnInitializeWia");
  HRESULT hr = S_OK;
  //
  // Check that this is the last connection, before
  // freeing resources.
  //

  m_iConnectedApps--;
  if (m_iConnectedApps == 0)
  {
     hr = FreeResources();
     if (FAILED(hr))
         wiauDbgErrorHr(hr, "drvUnInitializeWia",
              "FreeResources failed, continuing...");
      //
      // Do not delete the device object here, because it is
      // not being unloaded.
      //
  }
  return hr;
}


Informing an Application of Item Tree Changes

A minidriver for a WIA device must be able to inform applications associated with WIA devices of any changes to the device's item tree. For example, if an application displays a user interface showing thumbnails of the pictures on a camera, a WIA minidriver should be able to notify an application's user interface to not display thumbnails of pictures that the user has already deleted.

The following sample implementation of the IWiaMiniDrv::drvDeviceCommand method shows how a WIA minidriver can respond to a command sent to it by the WIA service, and pass the command on to the device. After the WIA minidriver issues the command to the device, the minidriver informs applications that the device item tree has changed. In this implementation, the method determines that the WIA service has issued the "Take Picture" command (WIA_CMD_TAKE_PICTURE). The method calls the TakePicture method on the root item (the item for the device), and informs any connected applications that the item tree now contains the new picture. (Both WIA_CMD_TAKE_PICTURE and TakePicture are described in the Platform SDK documentation.) The minidriver does this by calling the wiasQueueEvent function.

Note that when the minidriver sends out the event that indicates that the tree has been updated, all listening applications are informed of the change, not just the caller. For example, if a user has the Explorer view of the camera open, and uses Microsoft Paint to acquire a new picture, the Explorer window also shows the new picture when it arrives, because it listens for such events.

/******************************************************************\
* drvDeviceCommand - Issue a command to the device.
\******************************************************************/

HRESULT _stdcall
  CWiaMiniDriver::drvDeviceCommand(
    BYTE        *pWiasContext,
    LONG         lFlags,
    const GUID  *pCommandGuid,
    IWiaDrvItem **ppDrvItem,
    LONG        *plDevErrVal)
{
  DBG_FN("CWiaMiniDriver::drvDeviceCommand");
  HRESULT hr = S_OK;
  BSTR bstrItemFullName = NULL;

  *ppDrvItem = NULL;
  *plDevErrVal = DEVERR_OK;

  // This example implementation responds only to the
  // WIA_CMD_TAKE_PICTURE command sent by the WIA service.
  // A full implementation of this method should be able
  // to respond to several more commands.
  //
  if (*pCommandGuid == WIA_CMD_TAKE_PICTURE)
  {
     LONG ItemType = 0;
     hr = wiasGetItemType(pWiasContext, &ItemType);
     if (FAILED(hr))
     {
        wiauDbgError("drvDeviceCommand", "wiasGetItemType failed");
        return hr;
     }

     // TakePicture works only on the root

     if (WiaItemTypeRoot & ItemType)
     {
        // Tell the device to take a picture. Notice that the
        // TakePicture helper function takes a ppDrvItem parameter.
        // After taking the picture, this method creates
        // a driver item to represent the new picture, and
        // returns its address in *ppDrvItem. It also assigns the new
        // name to the item, and returns it in *bstrItemFullName.
        // We can use this value to queue the appropriate event.

        hr = TakePicture(pWiasContext, ppDrvItem, &bstrItemFullName);
        if (FAILED(hr))
        {
           wiauDbgError("drvDeviceCommand", "TakePicture failed");
           return hr;
        }

         // We succeeded in taking the picture and updating
         // the item tree, now inform the application that the tree
         // has changed by queuing a WIA_EVENT_ITEM_CREATED event.
         //
         hr = wiasQueueEvent(m_bstrDeviceId, &WIA_EVENT_ITEM_CREATED,
                             bstrItemFullName);

         // Free the item name string, because it is no longer needed.
         SysFreeString(bstrItemFullName);

         // Check whether wiasQueueEvent failed.
         if (FAILED(hr))
         {
            wiauDbgError("drvDeviceCommand", "wiasQueueEvent failed");
            return hr;
         }
     }
     else  // TakePicture command was sent to a non-root item.
     {
        wiauDbgError("drvDeviceCommand",
              "Take picture command sent to a non-root item");
        return E_INVALIDARG;
     }
  }
  else if (......)
  {
     // Code to handle other WIA_CMD_XXX commands
      .
      .
      .
  }
  else
  {
     // The method is unable to carry out the command.
     hr = E_NOTIMPL;
  }

  return hr;
}


Transferring Data to an Application

Data transfer is the process by which the minidriver transfers data on the device to the client application by way of the WIA service. In order for the transfer to take place, the properties must already have been written to the device (see Writing Item Properties) and the device should be ready for the transfer.

The WIA service requests that the minidriver lock the device by calling the IWiaMiniDrv::drvLockWiaDevice method. The WIA service then requests that the minidriver write the properties to the device by calling the IWiaMiniDrv::drvWriteItemProperties method. The actual transfer of data from the device takes place in the IWiaMiniDrv::drvAcquireItemData method. The data is read from the device by the minidriver through the appropriate kernel I/O driver. The minidriver determines whether the data is to be transferred as a memory-callback transfer or as a file-buffered transfer. The minidriver calls the WIA service-provided IWiaMiniDrvCallBack::MiniDrvCallback method for a memory-callback transfer or for data placed in a buffer for a file-buffered transfer. After the transfer is complete, the WIA service requests that the device be unlocked by calling the IWiaMiniDrv::drvUnLockWiaDevice method.

Bitmap Transfers and Vertical Flipping

If a transfer involves vertical flipping, it should be done using a file transfer. To vertically flip a banded bitmap in a memory transfer, set the height of the bitmap to its negative. That is, change the sign of the biHeight member of the BITMAPINFOHEADER structure (defined in the Platform SDK documentation), making it negative. The viewing component then flips the data when all of the bands have been assembled.

Virtually all image file formats store image data from the top down. The bitmap format is a notable exception, with image data stored from the bottom up, unless the height in the image header is negative.

The majority of scanners scan an image from the top down, and store the image data the same way, which is in accord with most image file formats, but the opposite from file bitmaps. If an image is scanned into the bitmap format, the image height is made negative. If this were not done, the image would appear upside-down when printed.

Although many applications can cope with file bitmaps with either positive or negative heights, there are some that are unable to handle negative heights in file bitmaps. To solve this problem, the minidriver must flip the image and change the image height to a positive value.


Locking the Device

The IWiaMiniDrv::drvLockWiaDevice method is used to lock access to the device. This method is typically called by the WIA service before properties are written to the device prior to a data transfer.

The minidriver's implementation of the IWiaMiniDrv::drvLockWiaDevice method should use STI's lock device method, IStiDevice::LockDevice.


Acquiring Item Data

The IWiaMiniDrv::drvAcquireItemData method is called when the WIA service requests a data transfer from the minidriver. The properties should already have been written to the device by the IWiaMiniDrv:drvWriteItemProperties method, and the device should be ready for the transfer. The actual transfer of data from the device occurs in this method. The WIA service passes a transfer context to the minidriver, which can use this context to:

  • Determine the type of transfer (memory-callback or file-buffered).
  • Obtain a pointer to the transfer buffer.
  • Determine whether the minidriver or the WIA service is responsible for allocating the transfer buffer.
  • Transfer other related information (for example, a callback function).

In this method, a minidriver typically:

  1. Initializes the pointer to the error value, plDevErrVal, to zero.
  2. Calls wiasGetImageInformation to fetch image format-specific information. This information is based on the item's property settings, but wiasGetImageInformation does not have to be called (the minidriver can calculate this information if necessary).
  3. Checks the return status from wiasGetImageInformation if it was called. If the return status is not S_OK, execute any error handling and exit the method (if it used wiasGetImageInformation).
  4. Determines whether this is to be a memory-callback or file-buffered data transfer. This is accomplished by checking the TYMED value in the transfer context. If this value is TYMED_CALLBACK or TYMED_MULTIPAGE_CALLBACK, use a device-specific callback routine for the transfer (see Calling the Callback Routine for an example of how to use a callback routine). If the value is TYMED_FILE or TYMED_MULTIPAGE_FILE, use a device-specific buffered function to transfer the data. The TYMED_XXX constants are described in the Platform SDK documentation.
  5. Returns the status and the parameter plDevErrVal when the transfer is complete. If plDevErrVal is nonzero, it points to a device-specific error code.


Calling the Callback Routine

The following code example shows how a minidriver would call IWiaMiniDrvCallBack::MiniDrvCallback to update a client application about the status of a memory-callback transfer or a file-buffered transfer. In this code sample, it is assumed that pTransCtx contains the address of a MINIDRV_TRANSFER_CONTEXT and that ScanLineWidth is set to the number of bytes making up a scan line.

Before the transfer takes place, several variables must be initialized. The variable lBytesRemaining is initialized to the total size, in bytes, of the data to be transferred. The pointer variables psrc and pdst are initialized to the addresses of the source and destination buffers, respectively.

The data transfer takes place in a do ... while loop that continues to operate as long as there is more data to transfer and no error has occurred. During each iteration of the loop, a block of data is transferred, and a call is made to IWiaMiniDrvCallBack::MiniDrvCallback to update the client application on the status of the transfer. In the sample code, the callback routine's parameters indicate that the transfer buffer contains a block of data (IT_MSG_DATA), and that the data is being transferred from the minidriver to the WIA service (IT_STATUS_TRANSFER_TO_CLIENT).

After the call to the callback routine, the return value is checked to see if an error occurred or the function returned S_FALSE (due to the user canceling the operation). If not, the pointers to the two buffers are adjusted, and lBytesRemaining is decremented by the number of bytes just transferred, and the loop begins another iteration. Notice the difference between file transfers and memory-callback transfers when the buffer pointers are updated. For file transfers, pdst is incremented by lTransferSize. For memory-callback transfers, however, pdst is updated to the value in pTransCtx—>pTransferBuffer, and lTransferSize is updated to the value in pTransCtx—>lBufferSize.

// Initialize lBytesRemaining to the total number of bytes in this
// transfer. In this case, we are performing a memory callback
// transfer with WiaImgFmt_MEMORYBMP (defined in wiadef.h),
// i.e., an in-memory bitmap.
// The total number of bytes in this transfer is:
// Header size (bytes) + Image size (bytes)
//   = Header size (bytes) + (bytes / scanline * No. of scanlines)
//   = lBmiSize + ScanLineWidth * HeightInPixels
// Here, lBmiSize is the size, in bytes, of a BITMAPINFO structure
// (see the Platform SDK documentation), and pbmi points to such a
// structure. The bitmap height is given by pbmi->bmiHeader.biHeight.

LONG lBytesRemaining =
        lBmiSize + ScanLineWidth * pbmi->bmiHeader.biHeight;

// Initialize pointers to destination and source buffers
PBYTE pdst = pTransCtx->pTransferBuffer;
PBYTE psrc = (PBYTE)pbmi;

LONG  lTransferSize;
LONG  lPercentComplete;

// Callback loop
do {
      // transfer up to entire buffer size
    lTransferSize = lBytesRemaining;

    if (lBytesRemaining > pTransCtx->lBufferSize) {
        lTransferSize = pTransCtx->lBufferSize;
    }

      // Copy data
    memcpy(pdst, psrc, lTransferSize);

    lPercentComplete = 100 * (pTransCtx->cbOffset +
                       lTransferSize);
    lPercentComplete /= pTransCtx->cbTotalTransferSize;

      // Make callback
    hr = pTransCtx->pIWiaMiniDrvCallBack->MiniDrvCallback(
                  IT_MSG_DATA,
                  IT_STATUS_TRANSFER_TO_CLIENT,
                  lPercentComplete,
                  pTransCtx->cbOffset,
                  lTransferSize,
                  0,
                  0);
      // Terminate the loop if an error occurred
      // or the operation has been cancelled.
    if (FAILED(hr) || hr == S_FALSE) {
        break;
    }

      // For callback transfers, update pdst
      // using pTransCtx->pTransferBuffer,
      // update lTransferSize using pTransCtx->lBufferSize
    if (pTransCtx->tymed == TYMED_CALLBACK ||
        pTransCtx->tymed == TYMED_MULTIPAGE_CALLBACK) {
        pdst = pTransCtx->pTransferBuffer;
        lTransferSize = pTransCtx->lBufferSize;
    }
      // For file transfers, increment pdst
      // by lTransferSize
    else if (pTransCtx->tymed == TYMED_FILE ||
             pTransCtx->tymed == TYMED_MULTIPAGE_FILE) {
        pdst += lTransferSize;
    }
    else {
        break;
    }
    psrc +=                lTransferSize;
    pTransCtx->cbOffset += lTransferSize;
    lBytesRemaining -=     lTransferSize;

} while (lBytesRemaining > 0);


Unlocking the Device

The method IWiaMiniDrv::drvUnLockWiaDevice is used to allow access to the device after the lock is no longer needed. It is typically called by the WIA service after properties are written to the device or after a data transfer.

The minidriver's implementation of the IWiaMiniDrv::drvUnLockWiaDevice method should use STI's unlock device method, IStiDevice::UnLockDevice.


Enumerating Device Formats

When an application requests the type of image formats and media types supported by the device, the WIA service calls the IWiaMiniDrv::drvGetWiaFormatInfo method. In response to this call, a WIA minidriver returns a pointer to an array of type WIA_FORMAT_INFO (a structure defined in the Platform SDK documentation). The values in this array indicate the media types of TYMED_CALLBACK and TYMED_FILE (described in the Platform SDK documentation) and the image formats, such as JPEG or bitmap, supported by the device. The image format GUIDs are defined in wiadef.h.

If the minidriver is capable, all formats should be marked as either TYMED_CALLBACK or TYMED_FILE. If the minidriver can write only certain formats to a file, it should mark those formats as TYMED_FILE. Other formats should be marked TYMED_CALLBACK. For example, if a minidriver supports the JPEG format only for file transfer, the entries in the WIA_FORMAT_INFO structure describing this format would be the following:

{WiaImgFmt_JPEG, TYMED_FILE}

Note that WHQL requires that the bitmap and memory bitmap file formats be marked as TYMED_FILE and TYMED_CALLBACK, respectively. In other words, WIA_FORMAT_INFO structures for these formats would have the following entries:

{WiaImgFmt_BMP, TYMED_FILE}
{WiaImgFmt_MEMORYBMP, TYMED_CALLBACK}

See the Platform SDK documentation of the WIA_FORMAT_INFO structure for a list of file formats.


Providing Event Notification

The WIA service notifies a WIA minidriver of a supported device event by calling the IWiaMiniDrv::drvNotifyPnpEvent method. In this method, the minidriver implements the device-specific functionality needed to respond to the event. The WIA service calls the IWiaMiniDrv::drvNotifyPnpEvent method only for an event the minidriver has indicated the device can support in the IWiaMiniDrv::drvGetCapabilities method.

The minidriver initiates an event either through the STI event mechanism, or by using wiasQueueEvent to add an event notification from this device to the event queue.

Asynchronous Behavior: Power Management and I/O Cancellation

In most cases, the WIA service ensures that only one call is made down to the driver at a time. However, some methods are inherently asynchronous and re-entrant in nature. A good example of this is the IWiaMiniDrv::drvNotifyPnPEvent method.

The WIA service uses this method to notify the driver of events that may require immediate action. For example, when the WIA service receives an event from PnP indicating that the device has been removed, it informs the driver immediately. Other examples include power management events and I/O cancellation requests from applications.

The following sample implementation of the IWiaMiniDrv::drvNotifyPnPEvent method illustrates how it should respond to various kinds of events.

/******************************************************************\
* drvNotifyPnpEvent
*
*  This method is called when the WIA service wants to inform the
*  driver of an event. Often, these are PnP events such as
*  device connect and disconnect, but could also be power
*  management events, or general notifications such as
*  I/O cancellation.
*
* Parameters:
*  pEventGUID   - Points to GUID identifying which event the WIA
*                     service is notifying us of.
*  bstrDeviceID - The DeviceID handed down during drvInitializeWIA
*                     time. Generally, this is not used.
*  ulReserved   - Reserved for system use. Set to 0 by the WIA
*                     service.
\******************************************************************/

HRESULT _stdcall
  CWiaDevice::drvNotifyPnpEvent(
    const GUID  *pEventGUID,
    BSTR         bstrDeviceID,
    ULONG        ulReserved)
{
  CWiaLogProc
    WIAS_LOGPROC(m_pIWiaLog,
                 WIALOG_NO_RESOURCE_ID,
                 WIALOG_LEVEL1,
                 "CWiaDevice::drvNotifyPnpEvent");
  HRESULT hr = S_OK;

  //
  // Check whether WIA is informing us of a power management
  // or PnP event:
  // - Going into a power-down state (when user or system
  //   initiates standby), make sure that we do
  //   not hold any resources that would prevent such a
  //   state change.
  //   Note that the driver is NOT going to be unloaded, so a complete
  //   uninitialization is unnecessary.
  //   Also, this is a useful time to inform the device to power
  //   itself down. (For example, tell the scanner to turn its
  //   lamp off).
  // - Waking up from a powered-down state, we need to reopen
  //    any resources that we might need, and possibly wake the
  //    device.
  // - If we are receiving a disconnect event, it means our device
  //    has been hot-unplugged, and we should try not to make any
  //    more calls that touch our hardware.
  //    Notice that we will soon be unloaded after receiving this.
  //    In this example case, we are going to immediately disable
  //    our device API class, so it will no longer make calls down
  //    to the device.
  //
  if (*pEventGUID == WIA_EVENT_POWER_SUSPEND)
  {
    WIAS_LTRACE(m_pIWiaLog,
         WIALOG_NO_RESOURCE_ID,
         WIALOG_LEVEL1,
         ("drvNotifyPnpEvent, (WIA_EVENT_POWER_SUSPEND)"));
    //
    // Release any resources that may prevent standby. For example,
    // some buses, such as DOT4, require all user-mode handles to be
    // closed before allowing standby. This is also a good time to
    // let the device know that it can power down.
    //

    ReleaseMyResources();
    hr = m_pDeviceApi->PowerDown();
  }
  else if (*pEventGUID == WIA_EVENT_POWER_RESUME)
  {
     WIAS_LTRACE(m_pIWiaLog,
          WIALOG_NO_RESOURCE_ID,
          WIALOG_LEVEL1,
          ("drvNotifyPnpEvent, (WIA_EVENT_POWER_RESUME)"));
     //
     // Reopen any needed resources. For example, we might reopen a
     // handle to DOT4 so we can receive event notifications.
     // This might also be a good time to inform the device to wake
     // up.
     //
     ReopenMyResources();
     hr = m_pDeviceApi->WakeUp();
  }
  else if (*pEventGUID == WIA_EVENT_DEVICE_DISCONNECTED)
  {
     WIAS_LTRACE(m_pIWiaLog,
          WIALOG_NO_RESOURCE_ID,
          WIALOG_LEVEL1,
          ("drvNotifyPnpEvent, (WIA_EVENT_DEVICE_DISCONNECTED)"));
     //
     // The device has been hot-unplugged, so immediately mark it as
     // disabled, so any API calls will not even attempt to touch
     // the device hardware.
     // Soon after this, the driver will be unloaded.
     //
     hr = m_pDeviceApi->DisableDevice();
  }
  else if (.....)
  {
     //
     //  Etc.
     //
      .
      .
      .
  }
  return hr;
}


Issuing Commands to a Device

The communication method IWiaMiniDrv::drvDeviceCommand is called by the WIA service to issue a WIA service command or application-generated command to the device. The WIA service calls the IWiaMiniDrv::drvDeviceCommand method only for a command the minidriver has indicated the device can support in the method IWiaMiniDrv::drvGetCapabilities.

The following is a list of WIA service device commands that can be issued to a minidriver:

Command | Meaning
WIA_CMD_CHANGE_DOCUMENT | Change to the next document (issued to multi-document scanners only).
WIA_CMD_DELETE_ALL_ITEMS | Delete the driver item tree.
WIA_CMD_SYNCHRONIZE | Rebuild the driver item tree.
WIA_CMD_TAKE_PICTURE | Take a picture (issued to cameras only).
WIA_CMD_UNLOAD_DOCUMENT | Unload the current document (issued to multi-document scanners only).

You can include your own custom list of commands.


Enumerating Capabilities of a Device

The WIA service calls the minidriver method IWiaMiniDrv::drvGetCapabilities to obtain a list of hardware device event and command capabilities. In response to this call, a minidriver returns an array of GUIDs, each of which corresponds to an event notification or a device command supported by the imaging device. The minidriver can return an array of supported event notifications, an array of device commands, or an array of both event notifications and device commands.

Currently, there are two values defined for the lFlags parameter of the IWiaMiniDrv::drvGetCapabilities method: WIA_DEVICE_EVENTS and WIA_DEVICE_COMMANDS. It is possible, however, that new flags might be defined in the future. In order to ensure that currently-written WIA minidrivers continue to work correctly in the future, an implementation of the IWiaMiniDrv::drvGetCapabilities method should treat the contents of the lFlags parameter as a set of bits rather than as a number. That is, instead of comparing lFlags for equality to a particular value, the individual bits in lFlags should be examined, as in the following code:

if (lFlags & WIA_DEVICE_EVENTS) {
  // Add events to returned capability array
}
if (lFlags & WIA_DEVICE_COMMANDS) {
  // Add commands to returned capability array
}


Getting Device Error Messages

To obtain an error string that describes a device-specific minidriver-generated error value, the WIA service calls the IWiaMiniDrv::drvGetDeviceErrorStr method. In response to this call, the minidriver should return a localized UNICODE string that corresponds to the error code passed to the minidriver.


Accessing Kernel-Mode Drivers for Still Image Devices

Microsoft provides WDM-based kernel-mode drivers to support still image devices connected to SCSI and USB buses. Both drivers support Plug and Play devices and provide services for adding, removing, starting, stopping, and creating registry entries for Plug and Play devices. Additionally, both drivers provide suspend and resume operations for devices that support power management.

User-mode still image minidrivers can access these kernel-mode drivers by calling CreateFile, ReadFile, WriteFile, and DeviceIoControl (described in the Platform SDK documentation). ReadFile and WriteFile are used for block data transfers. Specifically, ReadFile is called to obtain image data, and WriteFile is used for sending commands to devices that accept commands as data streams.

Before calling ReadFile, Writefile or DeviceIoControl, the minidriver must call IStiDeviceControl::GetMyDevicePortName to obtain the device's port name and then use that port name as a parameter to CreateFile.

SCSI Driver

USB Driver


SCSI Driver

The kernel-mode still image driver for SCSI buses supports ReadFile by creating a command descriptor block (CDB) that includes a SCSI Read command. It supports WriteFile by creating a CDB that includes a SCSI Write command. User-mode minidrivers can specify customized CDBs by calling DeviceIoControl. For more information, see SCSI Still Image I/O Control Codes. See the Platform SDK documentation for descriptions of ReadFile and WriteFile.


USB Driver

The kernel-mode still image driver for USB buses supports a single control endpoint, along with multiple interrupt, bulk IN, and bulk OUT endpoints. The control and interrupt endpoints are accessible using I/O control codes and DeviceIoControl. The bulk endpoints are accessible using ReadFile and WriteFile.

Before calling DeviceIoControl, ReadFile, or WriteFile, you must call CreateFile (all described in the Platform SDK documentation) to obtain a device handle. For devices that support no more than one of each endpoint type (control, interrupt, bulk IN, bulk OUT), a single call to CreateFile opens transfer pipes to each endpoint.

For devices that support multiple interrupt or bulk endpoints, a single call to CreateFile opens transfer pipes to the highest-numbered endpoint of each type. If you want to use a different endpoint, you must do the following:

  1. Call DeviceIoControl, specifying an I/O control code of IOCTL_GET_PIPE_CONFIGURATION, to determine a port's endpoint index numbers (that is, indexes into the returned USBSCAN_PIPE_INFORMATION structure array). Note that these index numbers are not the endpoint numbers described in the Universal Serial Bus Specification.
  2. Append a backslash and the endpoint's index number to the port name returned by IStiDeviceControl::GetMyDevicePortName when calling CreateFile.

For example, suppose a device (with a port name of "usbscan0") has two endpoints of each type (interrupt, bulk IN, bulk OUT), with index numbers as follows:

Index | Type | Endpoint#
0 | Interrupt | 0x01
1 | Bulk IN | 0x82
2 | Bulk IN | 0x83
3 | Bulk OUT | 0x04
4 | Bulk OUT | 0x05
5 | Interrupt | 0x06

If you call CreateFile with a port name of "usbscan0", the function opens transfer pipes to endpoints with index values of 2, 4, and 5, plus the control endpoint.

If you call CreateFile with a port name of "usbscan0\1", the function opens transfer pipes to endpoints with index values of 1, 4, and 5, plus the control endpoint.

For this device, if you want to use interrupt endpoint 0, bulk IN endpoint 1, and bulk OUT endpoint 3, you have to call CreateFile three times, specifying port names of "usbscan0\0", "usbscan0\1", and "usbscan0\3". This creates three device handles. Whenever a subsequent call to DeviceIoControl, ReadFile, or WriteFile is made, the device handle associated with the desired pipe should be specified.

Because only one control endpoint is supported, specifying any I/O control code that uses the control pipe causes the driver to use the proper endpoint, regardless of which endpoint (if any) was specified to CreateFile.

For descriptions of all I/O control codes, see USB Still Image I/O Control Codes.

The kernel-mode USB driver does not implement a package or message protocol. Read operations do not require any particular packet alignment, but better performance can be achieved if read requests are aligned to maximum packet size boundaries. The maximum packet size can be obtained using the IOCTL_GET_CHANNEL_ALIGN_RQST I/O control code.


Implementing Image Color Management

WIA relies on the Image Color Management (ICM) system provided in Microsoft Windows. ICM is documented in the Platform SDK documentation.

For best application compatibility, all minidrivers are expected to return data in the sRGB color space. If a device natively produces data in a different color space, the minidriver should use the ICM functions to map its output to sRGB. Some applications implement ICM and may want to retrieve data in the native color space. Minidrivers can allow this functionality by specifying the native color space in the INF file and specifying a valid value of 1 for the WIA_IPA_APP_COLOR_MAPPING property (described in the Platform SDK documentation).

When the application sets the property to 1, the minidriver should stop mapping to sRGB and allow the application to handle the mapping. The application uses the current value of the WIA_IPA_ICM_PROFILE_NAME property (described in the Platform SDK documentation) as the profile for the data from the device. That property is set by the user via system dialogs and should not be changed by the minidriver.


Calling Order for Minidriver Functions

When a minidriver is started, it calls some of the older STI entry points, such as IStiUSD::Initialize, and IStiUSD::GetStatus. As soon as the first application attempts to communicate with the device, the WIA service calls IWiaMiniDrv::drvInitializeWia. It is in this function that the minidriver should construct the item tree.

The WIA service next calls IWiaMiniDrv::drvInitItemProperties for each item in the tree. The minidriver should create all the properties relevant to the item. In some situations, it might be wise to create an empty property and fill in its data later. For example, for better performance, image thumbnails on cameras should be read in only when the WIA service specifically asks for them, as described below.

The next function to be called depends on the application and device type. Typically, an application's most common operation is transferring data. For scanners, the application first sets up the properties (for example, data type and extent) that define the image it wants to get from the device. The WIA service calls IWiaMiniDrv::drvValidateItemProperties when the application changes any properties. The minidriver should check that the properties are valid, communicating with the device, if necessary. The minidriver should generally avoid setting the properties in that function, because another application could set the properties to different values before the data transfer takes place.

To transfer data, the WIA service calls IWiaMiniDrv::drvLockWiaDevice, IWiaMiniDrv::drvWriteItemProperties, IWiaMiniDrv::drvAcquireItemData, and IWiaMiniDrv::drvUnLockWiaDevice, in that order. The calls to lock and unlock the device guarantee that no other application accesses the device during the transfer. For scanners, IWiaMiniDrv::drvWriteItemProperties should send properties such as position, extent, and resolution to the device. Camera drivers typically do not need to send any properties to the device. IWiaMiniDrv::drvAcquireItemData should retrieve the image data from the device and send it back to the application via the WIA service, using the IWiaMiniDrvCallBack COM interface.

For cameras, if an application wants to display thumbnails for the images, the WIA service calls IWiaMiniDrv::drvReadItemProperties on each image. The minidriver should read the thumbnail at that point and cache it in the driver item context. It is important to cache the thumbnail, because multiple applications may ask for the thumbnail, resulting in multiple calls to IWiaMiniDrv::drvReadItemProperties. If the minidriver reads the thumbnail each time an application asks for it, performance suffers.

One other special consideration for cameras is root item properties that affect settings on the camera (shutter speed, for example). When the application changes these properties, the WIA service calls IWiaMiniDrv::drvValidateItemProperties. The minidriver can communicate with the camera, if necessary, to validate the property settings. This function, however, is not the best place to change settings on the camera, because another application also can change the properties. The minidriver should update all of the camera settings from the root item properties when the IWiaMiniDrv::drvDeviceCommand function is called to capture a new image.


Installing a WIA Minidriver

This section provides the following topics on the installation of a WIA minidriver:

Registry Entries for Still Image Drivers

INF Files for WIA Devices

Installing Scanning Functionality in an MFP with a Single PDO


Registry Entries for Still Image Drivers

STI makes use of several registry entries, some of which can be modified by vendor-supplied components.

Vendor-Modifiable Registry Values

The following table lists predefined registry value names and their meanings. Constants are defined in stireg.h. A value must be set to "TwainDS" if the device supports the Still Image push model. Values for the other names are optional.

Constant | Value Name String | Definition
STI_DEVICE_VALUE_ICM_PROFILE | "ICMProfile" | REG_MULTI_SZ type containing names of ICM profiles for the device.
STI_DEVICE_VALUE_TWAIN_NAME | "TwainDS" | REG_SZ type containing the displayable name of the device's TWAIN data source, such as "HP PictureScan 3.0".
STI_DEVICE_VALUE_ISIS_NAME | "ISISDriverName" | REG_SZ type containing the device's ISIS driver name, such as "epson.pwx".
STI_DEVICE_VALUE_TIMEOUT | "PollTimeout" | REG_DWORD type representing the time-out value, in milliseconds, that should be used when polling the device. The default value is 1000 (1 second).

Clients of the IStillImage COM interface should call IStillImage::SetDeviceValue and IStillImage::GetDeviceValue to reference the registry. Still Image minidrivers can call the Win32 registry API, specifying the registry key received by the minidriver's IStiUSD::Initialize method. Values for predefined registry entries also can be set from within INF files for WIA devices.

Customized Registry Values

Still image applications and minidrivers also can store customized, device-specific values in the registry. For example, user selections obtained from customized property sheet pages could be stored under a "UserSettings" subkey.

Additionally, values for customized registry entries can be set from within INF files for WIA devices by including a DeviceData section.

Non-Modifiable Registry Entries

The following table lists registry entries that must not be modified by vendor software.

Registry Key | Definition
HKLM\SYSTEM\CurrentControlSet\Control\StillImage\Logging\STICLI | Specifies which vendor-generated messages are written to the still image log file. Can be any combination of the following values: 0x1 informational messages 0x2 warning messages 0x4 error messages
HKLM\SYSTEM\CurrentControlSet\Control\StillImage\Logging\STIMON | Specifies which Event Monitor messages are written to the still image log file. Can be any combination of the following values: 0x1 informational messages 0x2 warning messages 0x4 error messages
HKLM\SYSTEM\CurrentControlSet\Control\Class\{6BDD1FC6-810F-11D0-BEC7-08002BE2092F} | Contains information about installed still image devices.
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\StillImage\Registered Applications | List of registered imaging applications.


INF Files for WIA Devices

The default class installer for still image devices, sti_ci.dll, recognizes a special set of INF file entries. Within an INF file, these entries must be placed within a device's INF DDInstall section. The entries are described in the following table.

INF File Entry | Value | Comments
SubClass | StillImage | Required
DeviceType | 1 for scanners 2 for cameras 3 for streaming video | Required
DeviceSubType | Vendor-defined value | Optional
Connection | For non-PnP devices connected to serial or parallel ports, this can be Serial or Parallel to limit the user's choice of ports during installation. | Optional If not specified, the user can select any serial or parallel port.
Capabilities | Specifies a number that is converted to bit flags identifying device capabilities. These flags are stored in the registry and are available to STI components by means of the STI_DEV_CAPS structure. Bit 0 – Sets/clears STI_GENCAP_NOTIFICATIONS in STI_DEV_CAPS. Bit 1 – Sets/clears STI_GENCAP_POLLING_NEEDED in STI_DEV_CAPS. Bit 2 – Sets/clears STI_GENCAP_GENERATE_ARRIVALEVENT in STI_DEV_CAPS. Bit 3 – Sets/clears STI_GENCAP_AUTO_PORTSELECT in STI_DEV_CAPS. Bit 4 - Sets/clears STI_GENCAP_WIA in STI_DEV_CAPS. Bit 5 - Sets/clears STI_GENCAP_SUBSET in STI_DEV_CAPS. | Optional Bit 5 is currently not used.
PropertyPages | Identifies the name and entry point of a DLL that creates customized property sheet pages for still image devices. | Optional
DeviceData | Identifies a vendor-supplied data section containing information to be stored in the registry, under the DeviceData key. For TWAIN-supported devices, the data section must contain a "TwainDS" entry (see Registry Entries for Still Image Drivers.) | Optional
Events | Identifies a vendor-supplied data section listing still image device events. Each entry in this section must have the following format: EventName="String",{GUID},App EventName is the event's internal name, String is the event's display string, GUID is the event's GUID and App specifies the imaging application to be launched when the event occurs. To launch the currently registered application, use an asterisk (*) for App. | Optional
PortSelect | If the device installation does not require a port selection page, a value of "no" causes that page to be skipped. This value also causes the CreateFileName entry value (see note following table) to be automatically set to "AUTO". A value of "Message1" causes a system-supplied message to be displayed, and sets the CreateFileName entry value to "AUTO". Applies to both scanners and cameras that require manual installation. | Optional Note that for Plug and Play devices, PortSelect is ignored, but the device still must have the CreateFileName entry value set to "AUTO" in order for WIA to load the device. Use the INF AddReg directive to add this entry to the INF DDInstall section of the device's INF file.

Note on CreateFileName and PortSelect In order to communicate with a device, a user-mode client (a minidriver) must ask the WIA service for the device's file name, a string that specifies the name of the object to create or open. (The file name does not have to be the name of a disk file.) Responding to such a query, the WIA service obtains the device's file name from the CreateFileName registry entry. (The usbscan.sys and scsiscan.sys kernel-mode drivers create this entry, as does the class installer.) The minidriver receives this file name by calling the IStiDeviceControl::GetMyDevicePortName method. The minidriver can then use this file name when it calls the CreateFile function (described in the Platform SDK documentation) to open a handle to the device.

If the device is installed manually, the class installer creates the CreateFileName entry, setting its value to one that depends on the user's selection on the port selection page: COMX, LPTX, or AUTO. Some devices (network scanners, for example) that are installed manually do not require a port. In such cases, the resulting port selection dialog can confuse users. You can prevent this dialog from appearing by adding the following entry in the INF DDInstall section of your device's INF file:

     PortSelect=NO

A side effect of this entry value is that the CreateFileName entry is set to "AUTO". Be advised that if the minidriver receives "AUTO" for the file name, it must be able to determine on its own which device it should communicate with.

Additional INF File Entries

The entries in the following table must be placed within the section pointed to by the device's INF AddReg directive:

INF File Entry | Value | Comments
HardwareConfig | Indicates the type of connection the device is using. 1,1 — generic WDM device 1,2 — SCSI device 1,4 — USB device 1,8 — serial device 1,16 — parallel device | Optional
USDClass | Indicates the GUID for the minidriver. | Optional. The GUID in the USDClass and CLSID entries must match the GUID that is used in the DllGetClassObject function (described in the Platform SDK documentation) of the minidriver. If you are writing a microdriver, the value should be BB6CF8E2-1511-40bd-91BA-80D43C53064E. Otherwise, you must generate a new GUID, using, for example, genguid.exe.
CLSID | Indicates the GUID for the minidriver. | Optional. See Comments for the USDClass entry.

The default class installer for still image devices supports the standard INF CopyFiles directive.

The default INF file for still image devices, sti.inf, defines two installation sections for each device type, as follows:

  • An INF DDInstall section, which must be referenced within the DDInstall section of the vendor-supplied INF file, as shown in the following table.
Device Type | Include | Needs
IEEE 1394/SBP2 | Include=sti.inf | Needs=STI.SBP2Section
USB | Include=sti.inf | Needs=STI.USBSection
SCSI | Include=sti.inf | Needs=STI.SCSISection
Serial | Include=sti.inf | Needs=STI.SerialSection

  • An INF DDInstall Services section, which must be referenced within the DDInstall.Services section of the vendor-supplied INF file, as shown in the following table.
Device Type | Include | Needs
1394/SBP2 | Include=sti.inf | Needs=STI.SBP2Section.Services
USB | Include=sti.inf | Needs=STI.USBSection.Services
SCSI | Include=sti.inf | Needs=STI.SCSISection.Services
Serial | Include=sti.inf | Needs=STI.SerialSection.Services

For additional guidance in creating INF files for still image devices, you can look at any INF file provided with Windows 2000 and later that contains the entry "SubClass=StillImage".

To designate the device as a WIA device, the minidriver INF file must contain the following values placed within the DeviceData section of the vendor-supplied INF file.

INF File Entry | Value | Comments
Server | local | Designates the device as a local device. This is optional for Windows XP and later. If a vendor does not specify an entry value, the device is assumed to be local. That is, the WIA_DIP_SERVER_NAME property is set to "Local".
MicroDriver | Vendor-supplied .dll file name | This entry should be set to the name of the vendor-supplied DLL that implements the WIA Microdriver.
UI DLL | Vendor-supplied .dll file name | Obsolete and never used. Formerly, this entry indicated the name of the vendor-supplied user interface DLL file.
UI Class ID | Vendor-supplied device class identifier | Indicates the device class the vendor-supplied user interface is capable of supporting. This is optional for Windows XP and later. If a vendor does not specify an entry value, WIA sets the WIA_DIP_UI_CLSID property to GUID_NULL and the default WIA UI is used.
ICMProfiles | Vendor-supplied color profile value | Specifies a value to put in the WIA_IPA_ICM_PROFILE_NAME property (described in the Platform SDK documentation). If no value is specified the standard sRGB profile "sRGB Color Space Profile.icm" is used.

The MicroDriver entry is required only if the vendor supplies a WIA microdriver.

The user interface (UI) entries are required only if the vendor supplies a custom user interface for the imaging device.


Installing Scanning Functionality in an MFP with a Single PDO

A special procedure is required to install scanning functionality in multifunction printers having only a single physical device object (PDO). If the device identifies itself as a printer, the printer's INF file can call the WIA coinstaller in order to install the scanning functionality.

Note that Microsoft recommends that each logical function of a multifunction printer should have its own PDO, if at all possible. Associating multiple functions of a device with a single PDO should be avoided.

If you register the WIA coinstaller as the coinstaller of your device, Setup always calls the WIA coinstaller to process the installation before and after the Printer class installer. The WIA coinstaller creates an Image class device interface on the printer's PDO, and stores all required information in the device interface registry key. The current location in the registry of this key is:

HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{6bdd1fc6-810f-11d0-bec7-08002be2092f}\<device symbolic link>

This key is not guaranteed to remain in this location In future operating system versions. To open this key, call SetupDiOpenDeviceInterfaceRegKey.

The WIA service enumerates all Image class PDOs and device interfaces. Therefore, the newly created device interface will be enumerated as a WIA device.

The Windows DDK ships with an example INF that installs scanning functionality in a multifunction printer with only a single PDO. The name of this file is mfpoemprn.inf, and it is located in the \src\print\infs directory.

To install scanning functionality in an MFP

  1. Specify "sti_ci.dll" as the entry value for the CoInstallerEntry entry.

    The INF for your device must have an INF DDInstall.CoInstallers section to be able to register the coinstaller for device installation. This section should appear similar to the following:

    [OEMMFP.GPD.CoInstallers]
AddReg=WIA.CoInstallers.AddReg

[WIA.CoInstallers.AddReg]
HKR,,CoInstallers32,0x00010000,"sti_ci.dll, CoInstallerEntry"
  2. Include a WIASection entry in the INF DDInstall section that refers to the section containing all of the WIA-related settings. The section containing the WIA-related settings must appear in the same INF file.
    [OEMMFP.GPD]
CopyFiles=@OEMMFP.DLL,@OEMPRT1.DLL,@OEMUI.DLL,OEMMFP.GPD.WIA.CopyFiles
WIASection=OEMMFP.GPD.WIA

[OEMMFP.GPD.WIA]
Description=%OEM_MFP_SCANNER%
SubClass=StillImage
DeviceType=1
Capabilities=0x00000011
AddReg=OEMMFP.GPD.WIA.AddReg
DeviceData=OEMMFP.GPD.WIA.DeviceData
ICMProfiles="sRGB Color Space Profile.icm"
USDClass="{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"

    By including a WIASection entry, the Image class installer does not create a devnode for the device, but instead creates an additional device interface. Accordingly, it uses the previously mentioned device interface registry key to store STI-/WIA-related information.

  3. Make sure that the INF DDInstall section copies all required files.

    Alternatively, you can list the files to copy in the WIASection, but they will not be listed in the Device Manager.

Notes The Include and Needs entries cannot be used in the WIASection section.

All kernel-mode portions must be installed by the original INF DDInstall section.

If the device is hot-pluggable, and requires its own kernel-mode component, it must create and enable an Image class device interface (in addition to any other class device interfaces such as the Print class device interface). The kernel-mode component enables an Image class device interface on the device's devnode by means of a call to the IoSetDeviceInterfaceState function. When the Image class device interface is enabled, a Plug and Play event is fired, notifying the WIA service that the device is connected.


WIA Microdriver

Many flatbed scanners are controlled in a similar manner. The common behavior between models has been abstracted into a Microsoft-provided common driver called the WIA Flatbed Driver. This driver calls a DLL, called a microdriver, provided by the scanner vendor, that implements any needed device-specific behavior. The WIA Flatbed Driver together with the microdriver can then be used as a WIA minidriver. The advantage of using a microdriver is that it is very easy to implement and debug. Not all scanners can be supported by a microdriver. It is most appropriate for simple devices or when a base functionality driver is desired.

The following diagram shows the components in the WIA microdriver architecture.

WIA Microdriver Architecture

The WIA Flatbed Driver handles requests from the WIA service by calling the WIA microdriver functions in the microdriver. The microdriver must implement each of these functions. A SCANINFO structure is passed to the microdriver to store and communicate scanning parameters such as the scan window and resolution. The WIA Flatbed Driver reads values from the SCANINFO structure, but never writes them. It is the microdriver's responsibility to set the SCANINFO members.

The microdriver should not store any parameters for a scan, but should rely on the values stored in the SCANINFO structure. This is important for supporting multiple application access to the device. If two applications are setting up a scan on the same device at the same time, there is only one copy of the microdriver running. In this situation the microdriver is called with one of two different SCANINFO structures depending on which application is trying to access the device.


Microdriver Functions

The WIA Flatbed Driver responds to requests from the WIA service by calling the WIA microdriver functions. These functions must be implemented by every vendor-supplied microdriver and consist of the following:

Function | Description
MicroEntry | Responds to commands sent by the WIA Flatbed Driver.
Scan | Reads data from the device and returns the data to the WIA Flatbed Driver.
SetPixelWindow | Sets the area to be scanned.


WIA Flatbed Driver

The system-supplied WIA Flatbed Driver and the vendor-supplied microdriver combine to make a WIA minidriver. The WIA Flatbed Driver receives requests from the WIA service and routes the requests to the WIA microdriver through the microdriver functions. The WIA Flatbed Driver sends requests to the WIA microdriver, which sends responses back to the WIA Flatbed Driver. The WIA Flatbed Driver then sends these responses to the WIA service.

The following is a description of the capabilities of the WIA Flatbed Driver:

Minimum WHQL WIA properties

The WIA Flatbed Driver implements only a subset of the available properties and does not allow for any extensions by the vendor. It implements only those properties required by the WHQL specification. See the WHQL requirement specification for details.

Supported Data types

The following data types are supported:

  • 1-bit black/white
  • 8-bit grayscale
  • 24-bit color

The microdriver can exclude data types not supported by the device.

File Formats

Only the bitmap (BMP) file type is supported.

Supported Transfer Types

Both the file transfer and callback transfer types are supported.

Resolution

The following resolutions are supported: 75, 100, 150, 200, 300, and 600 dpi.

ADF

Only simple Automatic Document Feeder (ADF) control is supported.


INF File Entries

Using a microdriver for your device requires additional entries in the INF file. First, there must be an entry called "MicroDriver" in the DeviceData section of the INF file. (See INF Files for WIA Devices for more information.) This entry should be set to the name of the DLL that implements the microdriver.

In the AddReg directive where your WIA minidriver normally would be referenced, it should list wiafbdrv.dll as the driver. This is the component that implements the WIA Flatbed Driver.

Be sure that the CopyFiles directive includes both your microdriver and wiafbdrv.dll, which is copied from the Windows CAB files. The rest of the INF file is the same as for other WIA devices.


User Interface Extensions

Many camera and scanner vendors may supply features on their devices that are not accessible through the default WIA user interfaces (UI). Such features could include manipulation of images stored in proprietary formats, specialized device operations such as "self test" or "zoom", and so on. In order to accommodate UI for non-standard features and for specialized devices and user groups, WIA provides a UI extension capability. This capability allows vendors to extend the context menu, property sheet, and image application dialog of the system-supplied UI.

Context Menu Extensions

Property Sheet Extensions

Image Application Dialog Extensions

User Interface Extension Registry Entries


Context Menu Extensions

In both the Scanners and Cameras control panel folder for devices (root items), and in the My Computer folder, the user can choose various actions to perform on a selected item, based on the verbs exposed on its context menu. To find these verbs, the user right-clicks the thumbnail or icon of the given image.

A way to add to the verbs on the context menu is to implement the IContextMenu interface (see the Platform SDK documentation). A vendor can provide an in-process server that implements the IContextMenu interface for IWiaItem (see the Platform SDK documentation) items provided by the device. Whenever WIA queries for the context menu of an image, the vendor-supplied UI extension in turn calls IContextMenu::QueryContextMenu from the handlers registered for the given imaging device. Calls to IContextMenu::InvokeCommand for items not handled by the default UI are passed in turn to the appropriate vendor-supplied extension.


Property Sheet Extensions

The Properties context menu item provides access to scanner or camera property sheets in either the Scanners and Cameras control panel folder for devices (root items) or the My Computer folder.

Property sheet extensions for cameras and scanners also can provide a user interface for specific image acquisition sessions; that is, non-root IWiaItem objects (see the Platform SDK documentation) that are active when the user is using the default scanning dialog. These extensions are accessed through an advanced properties or advanced settings link on the image acquisition dialog. When the properties verb is chosen from the context menu, WIA constructs the property sheet using the vendor-supplied implementation of the IShellExtInit and IShellPropSheetExt interfaces (see the Platform SDK documentation).

For both property sheet and context menu UI extensions, the IDataObject interface (described in the Platform SDK documentation) describing the selected items uses either the "WIAItemNames" format, or the "WIAItemPointer" format. These formats and their format names are defined in wiadevd.h.

The "WIAItemNames" format, whose format name is CFSTR_WIAITEMNAMES, returns an HGLOBAL pointing to a double-null-terminated list of IWiaItem identifiers. Each identifier is of the form "<device id>::<full path name>". For root items, the full path name portion is empty.

The "WIAItemPointer" format is supported in versions of Windows XP after Beta 2. The format name for this format is CFSTR_WIAITEMPTR. The "WIAItemPointer" format returns an STGMEDIUM structure (defined in the Platform SDK documentation) whose tymed member is set to TYMED_ISTREAM. This format can be used when the user selects only a single item. The property sheet or context extension can call CoUnmarshalInterface on the IStream object stored in the STGMEDIUM structure to get back an IWiaItem interface. (See the Platform SDK documentation for descriptions of the CoUnmarshalInterface function, and the IStream and IWiaItem interfaces.) Using this format, every page on the property sheet can share a properly marshaled IWiaItem interface, which is important during scans.


Image Application Dialog Extensions

There are three mechanisms for extending WIA image application dialogs. They are:

  1. Supplying a device icon to be used in place of the system-provided icon in any place where an icon needs to be displayed for the device. To do this, implement the IWiaUIExtension::GetDeviceIcon method.
  2. Providing property sheet extensions that extend the system-provided property pages, which are displayed when the user views the advanced settings or properties for a device in the common WIA acquisition dialog or in the Explorer. To do this, implement the IShellExtInit and IShellPropSheetExt interfaces (see the Platform SDK documentation).
  3. Providing a complete replacement for the system-provided dialogs displayed in response to a call to IWiaItem::DeviceDlg (see the Platform SDK documentation). To do this, implement the IWiaUIExtension::DeviceDialog method.


IWiaUIExtension COM Interface

If you implement the IWiaUIExtension interface, you can implement none, some, or all of the IWiaUIExtension methods. If a particular method returns E_NOTIMPL, the system-provided alternative, if one is available, is used instead.

The methods provided by the IWiaUIExtension interface consist of the following:

Method | Description
IWiaUIExtension::DeviceDialog | Provides a custom user interface that replaces the default system user interface.
IWiaUIExtension::GetDeviceBitmapLogo | Gets a custom bitmap logo for the device.
IWiaUIExtension::GetDeviceIcon | Gets a custom device icon.

IWiaUIExtension::DeviceDialog accepts a pointer to a DEVICEDIALOGDATA structure defined in wiadevd.h, which contains all of the data needed to implement the device dialog.

The device dialog must be implemented as a modal Win32 dialog with the following four constraints:

  1. The array of items returned in pDeviceDialogData—>ppWiaItems must be allocated using CoTaskMemAlloc, and is freed by the application using CoTaskMemFree (see the Platform SDK documentation for both functions).
  2. You must not destroy or release the root item stored in pDeviceDialogData—>pIWiaItemRoot. You also must not cause the root item to become invalid. For instance, you must not call the WIA_CMD_SYNCHRONIZE device command. (See Issuing Device Commands.)
  3. Return S_OK to indicate that the user requested a data transfer, and S_FALSE to indicate that the user cancelled the transfer.
  4. Take care to ensure memory or resource leaks are not introduced in this component, because it runs in-process in the application.

IWiaUIExtension::GetDeviceIcon allows the application to use a driver-specified icon. To avoid resource leaks, this icon should be loaded with LoadImage using the LR_SHARED flag (see the Platform SDK documentation).

IWiaUIExtension::GetDeviceBitmapLogo allows the application to present device and vendor logos as appropriate. Currently, no system components use this method. The bitmap should be a DIB-allocated bitmap using CreateDIBSection or loaded using LoadImage with the LR_CREATEDIBSECTION flag (see the Platform SDK documentation for more information). This allows the application to extract any palette information and adapt to the current or changing display color depths.


User Interface Extension Registry Entries

You must provide the COM server class ID for each extension. Note that the class ID of the COM server for each extension is listed as a registry key (not a value) under CLSID\{WIA_DIP_UI_CLSID}\shellex, where WIA_DIP_UI_CLSID is the actual GUID returned when the application requests this property. It is used by the application as part of the lookup key in the registry. Each extensibility interface can refer to a different class ID. There is no requirement that the same object implement them all. List only those extensions that are implemented. It is not required to list all four.

Registry Key | Definition
CLSID\{WIA_DIP_UI_CLSID}\shellex\ContextMenuHandlers\<CLSID of COM in-process server> | Vendor-supplied COM DLL that implements context menu UI extensions.
CLSID\{WIA_DIP_UI_CLSID}\shellex\PropertySheetHandlers\<CLSID of COM in-process server> | Vendor-supplied COM DLL that implements property sheet UI extensions.
CLSID\{WIA_DIP_UI_CLSID}\shellex\WiaDialogExtensionHandlers\<CLSID of COM in-process server> | Vendor-supplied COM DLL that implements application dialog UI extensions.
CLSID\<CLSID of the COM in-process server>\InProcServer32\Default Value | REG_SZ type containing the name of the vendor-supplied COM server implementing the extensibility interfaces.
CLSID\<CLSID of the COM in-process server>\InProcServer32\ThreadingModel | REG_SZ type containing the name of the threading model of the vendor-supplied COM server. Set this key to "Apartment".


Picture Transfer Protocol Driver

The Picture Transfer Protocol (PTP) driver enables PTP devices to support the WIA driver model. This driver is written using the WIA architecture, and adheres to the PIMA 15740:2000 standard, First Edition, and Revision 1.0 of the USB Still Image Capture Device Definition (USB SICDD).

Several terms used in the PIMA 15740:2000, First Edition standard are used in this documentation: StorageInfo dataset, ObjectInfo dataset, and DeviceInfo dataset. Please refer to the PIMA 15740 standard for definitions of these structures.

Four areas of the driver are documented:

Using the PTP driver

Mapping PTP to WIA

Vendor-extended features of a PTP device

Restrictions imposed on PTP drivers


Using the PTP Driver

For Windows Me and Windows XP, the PTP driver is loaded only for specific hardware IDs. To use the driver, an INF file must be written that maps the hardware ID to the PTP driver. Use the DC15740 section in the kdk2x0.inf file from Windows Me or Windows XP as an example of how to write an INF that is appropriate for a PTP driver. Note that the INF file includes sections from the sti.inf file. This allows Microsoft to make future updates to sti.inf when needed without affecting your INF file.

The USB Device Working Group has assigned class ID 0x06 for still image cameras. In future Windows releases, Microsoft will ship an INF file that loads the PTP driver for this class ID as a "compatible ID" match. This means that vendors can still load a custom driver by shipping an INF file that contains the hardware ID. The Windows installer places a higher priority on matching the hardware ID than on matching the class ID. If the INF file with the hardware ID is not shipped in Windows, the vendor driver is not loaded automatically. However, the autorun program for the CD can call UpdateDriverForPlugAndPlayDevices to easily update to the vendor driver.


Mapping PTP to WIA

This section discusses how PTP objects are related to their WIA counterparts: PTP objects versus WIA items; PTP format codes versus WIA format GUIDs; PTP associations versus WIA folders. Other topics in this section discuss related matters: PTP events, recovery from errors; PTP error codes; and canceling a transfer request.

Mapping PTP Objects to WIA Items

Mapping PTP Format Codes to WIA Format GUIDs

Mapping PTP Associations to WIA Folders

PTP Events

Error Recovery

PTP Error Codes

Transfer Cancel


Mapping PTP Objects to WIA Items

A WIA item is created for each PTP object present on a device. Objects should be reported in the same hierarchy as they should be displayed in by the driver. For example, if all of the objects are reported under a folder named "XYZ", the pictures are displayed in Explorer under a folder named "XYZ".

One exception to this rule is for devices that report their FilesystemType as DCF in the StorageInfo dataset. In that case the top level folder called "DCIM" (if it exists) and the next level of folders down are hidden by the driver. All of the objects in the subfolders are promoted to the top level.

Filename extensions (for example, .JPG) are stripped from the object name before sending them to WIA.


Mapping PTP Format Codes to WIA Format GUIDs

The format of an object is exposed through the WIA_IPA_FORMAT property as a GUID. The mapping between PTP format codes and WIA GUIDs is shown in the following table:

PTP Format Code | Object Type | WIA GUID
0x3000 | Undefined | Not applicable
0x3001 | Association | See Mapping PTP Associations to WIA Folders.
0x3002 | Script | DATAFMT_SCRIPT
0x3003 | Executable | DATAFMT_EXEC
0x3004 | Text | DATAFMT_UNICODE16
0x3005 | HTML | DATAFMT_HTML
0x3006 | DPOF | DATAFMT_DPOF
0x3007 | AIFF | AUDFMT_AIFF
0x3008 | WAV | AUDFMT_WAV
0x3009 | MP3 | AUDFMT_MP3
0x300A | AVI | VIDFMT_AVI
0x300B | MPEG | VIDFMT_MPEG
0x300C | ASF | VIDFMT_ASF
0x3800 | Undefined image | Not applicable
0x3801 | EXIF/JPEG | WiaImgFmt_JPEG
0x3802 | TIFF/EP | WiaImgFmt_TIFF
0x3803 | FlashPix | WiaImgFmt_FLASHPIX
0x3804 | BMP | WiaImgFmt_BMP
0x3805 | CIFF | WiaImgFmt_CIFF
0x3806 | Undefined (Reserved) | Not applicable
0x3807 | GIF | WiaImgFmt_GIF
0x3808 | JFIF | WiaImgFmt_JPEG
0x3809 | PCD (PhotoCD Image Pac) | WiaImgFmt_PHOTOCD
0x380A | PICT | WiaImgFmt_PICT
0x380B | PNG | WiaImgFmt_PNG
0x380C | Undefined (Reserved) | Not applicable
0x380D | TIFF | WiaImgFmt_TIFF
0x380E | TIFF/IT | WiaImgFmt_TIFF
0x380F | JPEG2000 Baseline | WiaImgFmt_JPEG2K
0x3810 | JPEG2000 Extended | WiaImgFmt_JPEG2KX

(The WiaImgFmt_XXX GUIDs are defined in wiadef.h.)


Mapping PTP Associations to WIA Folders

For most object associations, the PTP driver creates a WIA folder item. The WIA_IPA_ITEM_FLAGS property has different flags set depending on the association type, as shown in this table:

PTP Association Code | Association Type | WIA Item Type Flags (described in the Platform SDK documentation)
0x0000 | Undefined | WiaItemTypeFolder
0x0001 | GenericFolder | WiaItemTypeFolder
0x0002 | Album | WiaItemTypeFolder
0x0003 | TimeSequence | WiaItemTypeFolder | WiaItemTypeBurst
0x0004 | HorizontalPanoramic | WiaItemTypeFolder | WiaItemTypeHPanorama
0x0005 | VerticalPanoramic | WiaItemTypeFolder | WiaItemTypeVPanorama
0x0006 | 2DPanoramic | WiaItemTypeFolder
0x0007 | AncillaryData | See accompanying text.

The SequenceNumber field of the ObjectInfo dataset is put into the WIA_IPC_SEQUENCE property. The WIA_IPC_XCOORDINATE and WIA_IPC_YCOORDINATE properties are not currently used by the PTP driver. The AssociationDesc member of the ObjectInfo dataset is currently not used.

The following figure shows an example AncillaryData association as stored on the camera. This association consists of an image together with associated audio and text.

PTP Tree for an Image with Ancillary Data

When an AncillaryData association is mapped to a WIA folder, the non-image objects become children of the image object, as depicted in the following figure. The image object has the WiaItemTypeHasAttachments flag set in WIA_IPA_ITEM_FLAGS.

WIA Item with Attachments


PTP Events

When an object is added or removed, including in response to the StoreAdded or StoreRemoved events (described in the PIMA 15740 standard), a WIA event is triggered. The WIA_EVENT_ITEM_CREATED event is fired when an object is added and the WIA_EVENT_ITEM_DELETED event is fired when an object is removed. (See the Platform SDK documentation for a description of these and other WIA event identifiers.) The other PTP events are used by the PTP driver to update internal structures, but are not reported to applications. Note that the driver is monitoring for events only while an application has the device open.


Error Recovery

During initialization of the WIA driver (that is, on initial retrieval of the DeviceInfo and ObjectInfo datasets, and the property descriptions), any error is treated as a catastrophic failure, and the driver fails to initialize.

During later processing (for example, while retrieving an image), when an unrecognized error occurs, the driver first attempts to send the Get Device Status USB class-specific request (described in the USB Still Image Capture Device Definition). If that request succeeds, the driver clears any stalled endpoints and then continue.

If the Get Device Status request fails, the driver attempts to reset the device using the Device Reset class-specific request (described in the USB Still Image Capture Device Definition). If this succeeds, the function returns S_FALSE instead of S_OK. If resetting the device fails, the function returns an error code.


PTP Error Codes

When the WIA PTP driver detects an error, it passes a non-success response code to WIA. If the device returns a response other than 0x2001 (OK), the driver returns the response code wrapped in an HRESULT error code. The format of the error code is 0x8004XXXX, where XXXX represents the four hexadecimal digits of the response code.


Transfer Cancel

In the USB SICDD the device is allowed to cancel an operation at any time by returning less data than the host is expecting. Currently, the driver does not handle this cancel mechanism. Instead, it treats cancellation of an operation as an error.

The driver also does not use the cancel mechanism from the host side. If the user cancels an operation on the host, the driver reads the remainder of the data from the device and then discard it.


Vendor-Extended Features

A PTP device can support vendor-extended properties, vendor-extended events, and vendor-extended commands.

Vendor-extended properties and events are listed in the DeviceData INF file entry (see INF Files for WIA Devices for more information), so that the driver knows how to handle them. An entry listing the vendor extension ID is required. This must match the VendorExtensionID field in the DeviceInfo dataset. An example of the other entries is shown here and described in the following sections.

[DeviceData]
VendorExtID=0x12345678
PropCode="0xD001,0xD002,0xD003"
PropCodeD001="0x00009802,Vendor property 1"
PropCodeD002="0x00009803,Vendor property 2"
PropCodeD003="0x00009804,Vendor property 3"
EventCode="0xC001,0xC002"
EventCodeC001={191D9AE7-EE8C-443c-B3E8-A3F87E0CF3CC}
EventCodeC002={8162F5ED-62B7-42c5-9C2B-B1625AC0DB93}


Vendor-Extended Properties

A PropCode entry in the DeviceData INF file entry (see the example in Vendor-Extended Features) lists all of the vendor-extended property codes, in uppercase hexadecimal and separated by commas. For each property code, an entry of the form PropCodeXXXX should exist, where XXXX is the code value in uppercase hexadecimal. The entry should list the WIA property code and text description (which does not need to be localized), enclosed in quotes. The WIA property codes should be between 0x9802 and 0x11802, which is the area defined for vendor-defined WIA device properties. The properties can be accessed through the IWiaPropertyStorage::GetPropertyStream and IWiaPropertyStorage::SetPropertyStream methods, which are described in the Platform SDK documentation.


Vendor-Extended Events

Vendor-extended events are defined in the DeviceData INF file entry in a way similar to vendor-extended properties (see the example in Vendor-Extended Features). An EventCode entry lists all of the event codes, in uppercase hexadecimal and separated by commas. For each event code an entry of the form EventCode XXXX should exist, where XXXX is the code value in uppercase hexadecimal. The entry should list the WIA event code to send when the event code is received by the driver. An application can use the IWiaDevMgr::RegisterEventCallback Xxx methods (described in the Platform SDK documentation) to receive the events. Currently, the parameters from the event cannot be passed to the application.


Vendor-Extended Commands

An application can send an arbitrary command to the device through the IWiaItemExtras::Escape method, which is described in the Platform SDK documentation. By calling QueryInterface on the root item, you can retrieve a pointer to the IWiaItemExtras interface. The application can then construct a PTP command using any opcode and parameters, and send this command to the device. The application also can send data to or receive data from the device. The device informs the application of the outcome of the operation when the IWiaItemExtras::Escape method returns, filling in a response code and response parameters in a PTP_VENDOR_DATA_OUT structure. The SessionId and TransactionId members of the PTP_VENDOR_DATA_IN structure are ignored. The driver supplies correct values for these.

If a vendor-defined command creates or deletes an object on the device, a special flag, ESCAPE_PTP_VENDOR_COMMAND, must be ORed with the command used in the IWiaItemExtras::Escape method so that the driver can add or remove the object from its internal structures and generate a WIA event. The handle for the added/removed objects must be in one of the command or response parameters. The special flag is not necessary when using SendObjectInfo or SendObject (both described in the PIMA 15740:2000 standard). The driver handles these commands automatically. All other standard commands should be issued through the appropriate WIA interface.

The first parameter to IWiaItemExtras::Escape is the ORed combination of one or more of the following flags:

Escape Code | Meaning
ESCAPE_PTP_ADD_OBJ_CMD | An object is being added and the handle for the object is in one of the command parameters.
ESCAPE_PTP_REM_OBJ_CMD | An object is being removed and the handle for the object is in one of the command parameters.
ESCAPE_PTP_ADD_OBJ_RESP | An object is being added and the handle for the object is in one of the response parameters.
ESCAPE_PTP_REM_OBJ_RESP | An object is being added and the handle for the object is in one of the response parameters.
ESCAPE_PTP_ADDREM_PARM1 | The handle for the added or removed object is in the first parameter of the command or response.
ESCAPE_PTP_ADDREM_PARM2 | The handle for the added or removed object is in the second parameter of the command or response.
ESCAPE_PTP_ADDREM_PARM3 | The handle for the added or removed object is in the third parameter of the command or response.
ESCAPE_PTP_ADDREM_PARM4 | The handle for the added or removed object is in the fourth parameter of the command or response.
ESCAPE_PTP_ADDREM_PARM5 | The handle for the added or removed object is in the fifth parameter of the command or response.
ESCAPE_PTP_CLEAR_STALLS | Clear any error conditions caused by a vendor-extended command. See note following table for details.
ESCAPE_PTP_VENDOR_COMMAND | The command is a vendor-extended command.

Note: When an application calls IWiaItemExtras::Escape with the ESCAPE_PTP_CLEAR_STALL flag set in this method's first parameter, the driver issues the PTP Get Device Status request to determine whether any endpoints are in STALL condition. If the Get Device Status command succeeds, the driver issues the IOCTL_RESET_PIPE USB control code for each such endpoint. If the Get Device Status command fails, the driver issues a PTP Device Reset request. (Get Device Status and Device Reset are described in the USB Still Image Capture Device Definition.)

The following sample code illustrates using the vendor-extended command interface. Be sure that your code includes the ptpusd.h header, since it contains the definitions of the escape codes and other constants, and the PTP_VENDOR_DATA_IN and PTP_VENDOR_DATA_OUT structures. The IWiaItemExtras interface is obtained using a call to QueryInterface on the root item. Here pIWiaRootItem is a pointer to a root item, obtained by, for example, a call to IWiaDevMgr::SelectDeviceDlg (described in the Platform SDK documentation).

//
// Test IWiaItemExtras::Escape method
//
HRESULT hr = S_OK;
IWiaItemExtras *pIWiaItemExtras = NULL;

hr = pIWiaRootItem->QueryInterface(IID_IWiaItemExtras,
                                   (VOID **) &pIWiaItemExtras);
if (FAILED(hr)) {
    MessageBox("QueryInterface for IWiaItemExtras failed");
    return;
}

PTP_VENDOR_DATA_IN *pDataIn = NULL;
PTP_VENDOR_DATA_OUT *pDataOut = NULL;
DWORD dwDataInSize = SIZEOF_REQUIRED_VENDOR_DATA_IN;
DWORD dwDataOutSize = SIZEOF_REQUIRED_VENDOR_DATA_OUT + 0x1000;
DWORD dwActualDataOutSize = 0;

pDataIn = (PTP_VENDOR_DATA_IN *) CoTaskMemAlloc(dwDataInSize);
pDataOut = (PTP_VENDOR_DATA_OUT *) CoTaskMemAlloc(dwDataOutSize);
if (!pDataIn || !pDataOut) {
    MessageBox("CoTaskMemAlloc failed");
    return;
}
ZeroMemory(pDataIn, dwDataInSize);
ZeroMemory(pDataOut, dwDataOutSize);

pDataIn->OpCode = 0x1001;
pDataIn->SessionId = 0;     // This will be filled in by the driver.
pDataIn->TransactionId = 0; // This will be filled in by the driver.
pDataIn->NumParams = 0;

//
// pDataIn->NextPhase informs the PTP driver whether to
// read data from the device (as shown), or
// write data to the device (use PTP_NEXTPHASE_WRITE_DATA),
// to neither read nor write data (use PTP_NEXTPHASE_NO_DATA).
//
pDataIn->NextPhase = PTP_NEXTPHASE_READ_DATA;

hr = pIWiaItemExtras->Escape(ESCAPE_PTP_VENDOR_COMMAND,
                             (BYTE *) pDataIn, dwDataInSize,
                             (BYTE *) pDataOut, dwDataOutSize,
                             &dwActualDataOutSize);

if (FAILED(hr)) {
    MessageBox("Escape failed");
    return;
}

//
// Data returned from device is located at pDataOut->VendorReadData.
//


Restrictions Imposed on PTP Drivers

Several restrictions are imposed on PTP devices in order to simplify the driver.

Object Handle and Event Order

When the PTP driver issues the GetObjectHandles command (see the PIMA 15740 standard), the device must return the object handles in a particular order for the driver to build the WIA item tree correctly. Objects that have child objects must appear in the list before their children. The numerical order of the handles does not matter. As an example, if object 5 has child objects 4, 6 and 7, the list should be ordered 5, 4, 6, 7. The ordering 4, 5, 6, 7 will not work. Also, for ancillary associations, the image object must be located in the object handle list ahead of the other objects in the association.

ObjectRemoved events (see the PIMA 15740 standard) must occur in a bottom-up order. In other words, an ObjectRemoved event for an object should not occur until all of its children have been removed as a result of ObjectRemoved events. If the image inside an ancillary association is to be removed, the other objects in the association must be removed in response to ObjectRemoved events before the image itself is removed.

Automatically Generated Object Names

If the Filename field of the ObjectInfo dataset is blank, the PTP driver creates a name based on the ObjectFormat and ObjectHandle fields. For example, an image with an ObjectHandle value of 5 will be called "Image5" on the English version of Windows.

Object Size

The ObjectCompressedSize field of the ObjectInfo dataset is optional in the PIMA 15740 standard, but the PTP driver requires this field to be non-zero.

Image Geometry Properties

The ImgPixHeight and ImgPixWidth image geometry properties (see the PIMA 15740 standard) are optional in PTP. For devices that do not implement these properties, the PTP class driver downloads the entire image to calculate the correct values for these properties. You can prevent this from occurring by implementing these optional PTP properties.


References

PIMA 15740:2000, Photography – Electronic still picture imaging – Picture Transfer Protocol (PTP) for Digital Still Photography Devices, First Edition, July 5, 2000, http://www.pima.net/standards/it10/PIMA15740/.

Universal Serial Bus Still Image Capture Device Definition, Revision 1.0, July 11, 2000, http://www.usb.org/developers/devclass.html.


Supported Scanner Paper Sizes

Although two WIA user interface components are able to display a list of page sizes to the user, there is no easy way for a WIA driver to know what page sizes a scanner supports.

Page Size in WIA Applications

There are no WIA properties that allow WIA drivers to report supported page sizes, nor to allow applications to specify page size directly. To communicate page size settings to a driver, an application must calculate the required size in scanner units (DPI) and adjust the origin of the scan to conform with the registration requirements of the device.

Page Size in the Common Scanner Dialog and in the Scanner and Camera Wizard

Both the Common Scanner Dialog and the Scanner and Camera Wizard have a static table of supported page sizes in which each page size is described by its horizontal width and vertical height, both in increments of 0.001 inch. These page sizes are currently displayed only when the scanner is in document feeder mode.

The largest page size (by area) that a driver supports in page feed mode, as determined by the maximum bed size, is considered the default page size. Paper sizes that do not fit on the feeder or bed of the device are not offered to the user.


TWAIN Compatibility

WIA minidrivers can support both WIA and other imaging architectures such as TWAIN. When a minidriver is developed to support both WIA and TWAIN, care must be taken in the following areas:

  • If the TWAIN driver and the WIA driver use different locking mechanisms:

    When someone is using the device through WIA, you should not be able to access the device through TWAIN at the same time. This could lead to corrupted images or failed transfers, for example, depending on the device.

  • For vendor-supplied application software:

    Make sure that the first item is adhered to. This ensures that when WIA is polling the device, transferring data, and so forth, it does not interrupt another transfer (for example, through TWAIN), and vice versa. Make sure that only one system gets a specified event; that is, if you push the button on a scanner, WIA does not initiate the registered WIA application, and at the same time, the vendor-supplied software is initiating its own application.

  • Make sure that the drivers are compatible:

    Make sure that if more than one driver can exist for the same device, the drivers are thoroughly tested for compatibility when coexisting on the same system. In other words, if one driver leaves the device in a bad state (such as not sending the close session message in some protocol), when the other driver tries to talk to the same device, it might fail. This situation happens often with serial devices.

Multi-page Scanning and TWAIN

Starting with Windows XP, the TWAIN compatibility layer supports multi-page scanning from scroll-fed devices, provided that each scanned page is of the same length. This restriction is due to the fact that TWAIN obtains information from the calling application about page length only on the first page. TWAIN does not require the calling application to ask for image information between pages, but instead uses the information it received from the application for all pages.

Raw RGB Format

When an application transfers an image whose format GUID is WiaImgFmt_RAWRGB (defined in wiadef.h), the following properties on the image must contain the correct values for the image:

  • WIA_IPA_CHANNELS_PER_PIXEL
  • WIA_IPA_BITS_PER_CHANNEL
  • WIA_IPA_PIXELS_PER_LINE
  • WIA_IPA_NUMBER_OF_LINES
  • WIA_IPS_XRES
  • WIA_IPS_YRES

Furthermore, the WIA_IPA_DATATYPE property should be set to WIA_DATA_COLOR and the WIA_IPA_DEPTH property should be set to 24 or higher. For more information about these properties, see the Platform SDK documentation.

Any data in the raw RGB format that is to be transferred must be:

  • uncompressed
  • in RGB byte order
  • DWORD aligned

The data must be transferred with no image header. Only the image bits are sent via the IWiaDataCallback::BandedDataCallback method (described in the Platform SDK documentation).

The TWAIN compatibility layer (see Support for TWAIN-Compatible Applications) supports the WiaImgFmt_RAWRGB format GUID, thereby enabling TWAIN applications to transfer images with pixel depths greater than 32 bits, using a memory-callback transfer.


Support for TWAIN-Compatible Applications

In order to support existing or legacy TWAIN applications with private capabilities, WIA drivers can use a technique known as pass-through functionality. The pass-through mechanism refers to the way a TWAIN-compatible application communicates with a WIA driver, using the Data Source Manager and the TWAIN compatibility layer as intermediaries.

All communication between a TWAIN-compatible application and the WIA driver goes first to the Data Source Manager (twain_32.dll), which in turn calls into the TWAIN compatibility layer (wiadss.dll). The TWAIN compatibility layer then calls the WIA driver's IStiUSD::Escape method, passing either of two different escape codes.

When the TWAIN application requests the WIA driver's private capability list, the TWAIN compatibility layer calls the driver's IStiUSD::Escape method, passing ESC_TWAIN_PRIVATE_SUPPORTED_CAPS in the call. If the driver does not support pass-through functionality, it returns the TWAIN compatibility layer's static (default) capability list. Otherwise, the driver returns a list of supported private capabilities to the TWAIN compatibility layer.

When the TWAIN application sends a capability operation that is not already in the TWAIN compatibility layer's default list, the TWAIN compatibility layer calls the driver's IStiUSD::Escape method, this time passing ESC_TWAIN_CAPABILITIES in the call.

The foregoing explanation is somewhat oversimplified. When the TWAIN application asks for the driver's private capabilities list, the TWAIN compatibility layer actually makes two calls to the driver's IStiUSD::Escape method. In the first call, the TWAIN compatibility layer asks the WIA driver how much memory is needed to store the capability list. The TWAIN compatibility layer then allocates that amount of memory for the WIA driver to use. In the second call, the TWAIN compatibility layer asks the WIA driver for the capability list, which the WIA driver copies into the previously-mentioned memory. The TWAIN compatibility layer is responsible for allocating and freeing all memory used in TWAIN-WIA transactions. This arrangement prevents the WIA driver from freeing memory used by the TWAIN compatibility layer.

The TWAIN compatibility layer also calls the driver's IStiUSD::Escape method twice when ESC_TWAIN_CAPABILITIES is passed and for which the intent is to GET a capability. The first call asks the WIA driver how much memory it needs to store the capability, and the second call returns the capability. Note that SET capability operations require only a single call to IStiUSD::Escape, because no memory needs to be allocated.

The code samples in the following sections illustrate the use of pass-though functionality, supporting TWAIN applications with private capabilities. The code samples use two escape codes that are defined in wiatwcmp.h, ESC_TWAIN_PRIVATE_SUPPORTED_CAPS and ESC_TWAIN_CAPABILITY.

The following topics are discussed in this section:

Enabling TWAIN Capability Pass-Through in a WIA Driver

The ESC_TWAIN_PRIVATE_SUPPORTED_CAPS Escape Code

The ESC_TWAIN_CAPABILITY Escape Code

Note: The purpose of TWAIN pass-through functionality is to provide support to driver writers who are making the transition from TWAIN drivers to WIA drivers. It is not intended for the purpose of adding TWAIN features to a WIA driver. If your WIA driver does not require support for TWAIN, you should not add this functionality to your driver.


Enabling TWAIN Capability Pass-Through in a WIA Driver

To enable support for TWAIN capability pass-through, add the WiaItemTypeTwainCapabilityPassThrough flag to the WIA_IPA_ITEM_FLAGS property on the root item. This flag is defined in wiatwcmp.h.

The following example is taken from the wiascanr sample and demonstrates the use of the WiaItemTypeTwainCapabilityPassThrough flag.

// Initialize WIA_IPA_ITEM_FLAGS
  m_pszRootItemDefaults[PropIndex] = WIA_IPA_ITEM_FLAGS_STR;
  m_piRootItemDefaults[PropIndex] = WIA_IPA_ITEM_FLAGS;
// Next assignment adds the WiaItemTypeTwainCapabilityPassThrough flag.
  m_pvRootItemDefaults[PropIndex].lVal =
     WiaItemTypeRoot|WiaItemTypeFolder |
     WiaItemTypeDevice| WiaItemTypeTwainCapabilityPassThrough;
  m_pvRootItemDefaults[PropIndex].vt = VT_I4;
  m_psRootItemDefaults[PropIndex].ulKind = PRSPEC_PROPID;
  m_psRootItemDefaults[PropIndex].propid =
     m_piRootItemDefaults[PropIndex];
  m_wpiRootItemDefaults[PropIndex].lAccessFlags =
     WIA_PROP_READ | WIA_PROP_FLAG;
  m_wpiRootItemDefaults[PropIndex].vt =
     m_pvRootItemDefaults [PropIndex].vt;
  m_wpiRootItemDefaults[PropIndex].ValidVal.Flag.Nom =
     m_pvRootItemDefaults [PropIndex].lVal;
  m_wpiRootItemDefaults[PropIndex].ValidVal.Flag.ValidBits =
     WiaItemTypeRoot | WiaItemTypeFolder|WiaItemTypeDevice;


The ESC_TWAIN_PRIVATE_SUPPORTED_CAPS Escape Code

In order to find out about private TWAIN-supported capabilities, a TWAIN application notifies the TWAIN compatibility layer, which sends the ESC_TWAIN_PRIVATE_SUPPORTED_CAPS escape code to the WIA driver's IStiUSD::Escape method. The following pseudocode implementation of the Escape method demonstrates how it should respond to the ESC_TWAIN_PRIVATE_SUPPORTED_CAPS escape code to report private TWAIN-support capabilities.

// The number of private supported capabilities
#define NUM_PRIVATE_TWAIN_CAPS  5

STDMETHODIMP CWIAScannerDevice::Escape(
  STI_RAW_CONTROL_CODE  EscapeFunction,
  LPVOID                pInData,
  DWORD                 cbInDataSize,
  LPVOID                pOutData,
  DWORD                 cbOutDataSize,
  LPDWORD               pcbActualData)
{
  switch(EscapeFunction)
  {
    case ESC_TWAIN_PRIVATE_SUPPORTED_CAPS:
    {
      // Check the pInData buffer for the number of bytes
      // of the capability array.
      //
      // 1. Create variable of type LONG*, initializing it
      //    to the value in pInData.
      // 2. Dereference this variable to obtain the size, in
      //    bytes, of the private TWAIN capability array.

       LONG *pSupportedCapsSize = NULL;
       pSupportedCapsSize = (LONG*)pInData;

       if (pSupportedCapsSize)
       {
         LONG lNumBytes = *pSupportedCapsSize;

         // lNumBytes determines the operation to perform.

         if (lNumBytes == 0)
         {
          // If lNumBytes is zero:
          //  a. Create a variable of type LONG*, and initialize
          //     it to the value in pOutData.
          //  b. Dereference this variable, and set the size,
          //     in bytes, of the private TWAIN capability array.
          //  c. Set *pchActualData to sizeof(LONG).
          //  d. Set the HRESULT to S_OK, and return.

            LONG *pCapArraySize = (LONG*)pOutData;
           *pCapArraySize = (NUM_PRIVATE_TWAIN_CAPS * sizeof(LONG));
           *pcbActualData = sizeof(LONG);
            hr = S_OK;
         } // if(lNumBytes == 0)

         else if (lNumBytes > 0)
         {
          // If lNumBytes is positive:
          //  a. Create a variable of type LONG*, and initialize
          //     it to the value in pOutData.
          //  b. Dereference this variable, and set each
          //     capability ID of the private TWAIN capability
          //     array.
          //  c. Set *pchActualData to the size, in bytes, of
          //     the total capability array.
          //  d. Set the HRESULT to S_OK, and return.

           LONG *pCapArray = (LONG*)pOutData;
           pCapArray[0] = ICAP_MY_PRIVATE_CAP1;
           pCapArray[1] = ICAP_MY_PRIVATE_CAP2;
           pCapArray[2] = ICAP_MY_PRIVATE_CAP3;
           pCapArray[3] = ICAP_MY_PRIVATE_CAP4;
           pCapArray[4] = ICAP_MY_PRIVATE_CAP5;
          *pcbActualData = (NUM_PRIVATE_TWAIN_CAPS * sizeof(LONG));
           hr = S_OK;
         } // if (lNumBytes > 0)
       } // if (pSupportedCapsSize)
       break;
    } // case ESC_TWAIN_PRIVATE_SUPPORTED_CAPS
    Other escape code cases
      .
      .
      .
  } // end of switch
}


The ESC_TWAIN_CAPABILITY Escape Code

To carry out a capability operation on a private TWAIN capability, a TWAIN application notifies the TWAIN compatibility layer, which calls the WIA driver's IStiUSD::Escape method, passing the ESC_TWAIN_CAPABILITY escape code. The pseudocode in the following example demonstrates how the Escape method should respond to this escape code.

Note: The Escape method of this example is the same as the one shown in the previous section, although the focus of each sample is a different escape code.

STDMETHODIMP CWIAScannerDevice::Escape(
  STI_RAW_CONTROL_CODE  EscapeFunction,
  LPVOID                pInData,
  DWORD                 cbInDataSize,
  LPVOID                pOutData,
  DWORD                 cbOutDataSize,
  LPDWORD               pcbActualData)
{
  switch(EscapeFunction)
  {
    case ESC_TWAIN_CAPABILITY:
    {
       // Collect the pInData and pOutData headers.
       //
       // 1. Create two TWAIN_CAPABILITY pointers in which
       //    to store the addresses in pInData and pOutData.
       // 2. Set these local pointers to the addresses in pInData
       //    and pOutData.
       // 3. Use these local pointers to access the
       //    members of the TWAIN_CAPABILITY structures.

       TWAIN_CAPABILITY *pInHeader  = NULL;
       TWAIN_CAPABILITY *pOutHeader = NULL;

       pInHeader = (TWAIN_CAPABILITY*)pInData;
       pOutHeader = (TWAIN_CAPABILITY*)pOutData;

       if (pInHeader && pOutHeader)
       {
          // Check the headers to determine the operation to perform.

         switch(pInHeader->lCapID)
         {
            case ICAP_MY_PRIVATE_CAP1:
            {
                // Check lMSG, to determine which TWAIN
                // message/operation is being requested.
               switch(pInHeader->lMSG)
               {
                  case MSG_GETCURRENT:    // Return the current value.
                  case MSG_GETDEFAULT:    // Return the default value.
                  case MSG_GET:           // Return the valid values.
                  {
                     // Check lDataSize to determine
                     // which operation to perform.
                    if (pInHeader->lDataSize == 0)
                    {
                      // If lDataSize is zero:
                      // a. Set pOutHeader->lDataSize to the size
                      //    in bytes needed to store the entire
                      //    TWAIN capability data.
                      // b. Set *pchActualData to the size of
                      //    a TWAIN_CAPABILITY header.
                      // c. Set the TWAIN return codes,
                      //    pOutHeader->lRC and pOutHeader->lCC.
                      // d. Set the HRESULT to S_OK, and return.

                        pOutHeader->lDataSize =
                             sizeof(TW_ENUMERATION) +
                             (sizeof(TW_UINT32) * 3);
                       *pcbActualData = sizeof(TWAIN_CAPABILITY);
                        pOutHeader->lRC = TWRC_SUCCESS;
                        pOutHeader->lCC = TWCC_SUCCESS;
                        hr = S_OK;
                    }
                    else if (pInHeader->lDataSize > 0)
                    {
                     // If lDataSize is positive:
                     //   a. Fill the pOutHeader->Data member with
                     //      the TWAIN capability data.
                     //      (This is the container and data only).
                     //   b. Set pOutHeader->lConType to the type of
                     //      TWAIN container used.
                     //   c. Set pOutHeader->lDataSize to
                     //      (size of the TWAIN container + size of
                     //      the TWAIN container data).
                     //   d. Set *pchActualData to
                     //      (size of the TWAIN container + size of
                     //      the TWAIN container data +
                     //      size of the TWAIN_CAPABILITY header).
                     //   e. Set the TWAIN return codes,
                     //      pOutHeader->lRC and pOutHeader->lCC.
                     //   f. Set the HRESULT to S_OK, and return.
                        pEnumeration =
                             (TW_ENUMERATION*)pOutHeader->Data;
                        if (pEnumeration)
                        {
                          pEnumeration->ItemType = TWTY_UINT32;
                          pEnumeration->NumItems = 3;
                          pEnumeration->CurrentIndex = 0;
                          pEnumeration->DefaultIndex = 1;

                          TW_UINT32 *pData =
                                (TW_UINT32*)pEnumeration->ItemList;
                          pData[0] = 123;
                          pData[1] = 456;
                          pData[2] = 789;

                          pOutHeader->lConType = TWON_ENUMERATION;
                          pOutHeader->lDataSize =
                                sizeof(TW_ENUMERATION) +
                                (sizeof(TW_UINT32) * 3);
                         *pcbActualData = sizeof(TWAIN_CAPABILITY) +
                                sizeof(TW_ENUMERATION) +
                                (sizeof(TW_UINT32) * 3);

                          pOutHeader->lRC = TWRC_SUCCESS;
                          pOutHeader->lCC = TWCC_SUCCESS;

                          hr = S_OK;
                        } // if (Enumeration)
                    } // if (pInHeader->lDataSize > 0)
                    break;
                  } // case MSG_GET

                  case MSG_SET:  // Set the incoming value.
                  {
                     // Check the TWAIN container type, and use
                     // the contained values.
                     //
                     // 1. Create a pointer to a TWAIN container
                     //    of the desired type.
                     // 2. Set the pointer of the previous step to
                     //    the address in pInHeader->Data.
                     // 3. Access the values in the TWAIN container.
                     // 4. Carry out any private operations
                     //    with those values.
                     // 5. Set *pchActualData to the size of a
                     //    TWAIN_CAPABILITY header.
                     // 6. Set the TWAIN return codes,
                     //    pOutHeader->lRC and pOutHeader->lCC.
                     // 7. Set the HRESULT to S_OK, and return.

                    switch (pInHeader->lConType)
                    {
                       case TWON_ONEVALUE:
                       {
                         pOneValue = (TW_ONEVALUE*)pInHeader->Data;
                         if(pOneValue)
                         {
                            if(pOneValue->ItemType == TWTY_UINT32)
                            {
                               WriteMyPrivateTWAINValue(
                                   (TW_UINT32)pOneValue->Item);
                            }
                           *pcbActualData = sizeof(TWAIN_CAPABILITY);
                            pOutHeader->lRC = TWRC_SUCCESS;
                            pOutHeader->lCC = TWCC_SUCCESS;
                            hr = S_OK;
                         } // if(pOneValue)
                         break;
                       } // case TWON_ONEVALUE:

                       default:
                         break;
                    } // End switch(pInHeader->lConType)
                    break;
                  } // case MSG_SET
                  case MSG_RESET:   // reset TWAIN capability
                  {
                      .                      .
                      .
                     break;
                  }
                  default:
                  {
                     // Messages other than MSG_GETCURRENT,
                     // MSG_GETDEFAULT, MSG_GET, MSG_SET
                      .
                      .
                      .
                     break;
                  }
               } // switch(pInHeader->lMSG)
            } // case ICAP_MY_PRIVATE1
            case ICAP_MY_PRIVATE2:
            {
              .
              .
              .
              break;
            }

            Cases for other private capabilities...

            default:
            {
              // Unknown capability - set TWAIN failure codes.
              pOutHeader->lRC = TWRC_FAILURE;
              pOutHeader->lCC = TWCC_BADCAP;
              break;
            }
         } // End switch(pInHeader->lCapID)
       } // End if (pInHeader && pOutHeader)
    } // case ESC_TWAIN_CAPABILITY

    Cases for other escape codes...

  } // End switch(EscapeFunction)
} // End Escape


Recommended Development Plan

This section suggests a plan for developing a WIA minidriver. The suggested plan focuses on the WIA DDI interface methods that a WIA minidriver must provide in order to communicate with imaging applications. While the long-term development objective is to enable a WIA minidriver to respond to any WIA service request, the most immediate need is to communicate with imaging applications.

This plan suggests the order in which WIA DDI minidriver communication interface methods should be developed:

  • Phases 1, 2, and 3 of the plan specify the implementation of the most essential methods. After these three phases are completed, the minidriver is ready to work with most WIA applications.
  • Phases 4 and 5 specify methods that enable the minidriver to respond to additional WIA service requests.

    WIA Minidriver Development: Phase 1

    WIA Minidriver Development: Phase 2

    WIA Minidriver Development: Phase 3

    WIA Minidriver Development: Phase 4

    WIA Minidriver Development: Phase 5


Wia Minidriver Development: Phase 1

Implement the following minidriver communication interface methods:

Method | Description
IWiaMiniDrv::drvInitializeWia | Initialize the minidriver, set up an optional private interface, and build the driver item tree that represents the device.
IWiaMiniDrv::drvInitItemProperties | Initialize a WIA item's properties. (in this case they are the application items)
IWiaMiniDrv::drvLockWiaDevice | Lock the WIA hardware device so that only the current application can access it.
IWiaMiniDrv::drvUnLockWiaDevice | Unlock the WIA hardware device so that any application can access it.
IWiaMiniDrv::drvFreeDrvItemContext | Prompt a minidriver to free resources allocated by the minidriver to a device-specific context. This entry point is called by the WIA service before the service frees the item memory allocated in the wiasCreateDrvItem function call.

The IWiaMiniDrv::drvInitializeWia and IWiaMiniDrv::drvInitItemProperties methods must be implemented first. After those methods are implemented, the IWiaMiniDrv::drvLockWiaDevice, IWiaMiniDrv::drvUnLockWiaDevice, and IWiaMiniDrv::drvFreeDrvItemContext methods can then be implemented in any order.


WIA Minidriver Development: Phase 2

Implement the following methods:

Method | Description
IWiaMiniDrv::drvReadItemProperties | Read the driver item properties.
IWiaMiniDrv::drvWriteItemProperties | Read the current settings of an item's properties and write these properties to the device.
IWiaMiniDrv::drvAcquireItemData | Transfer data from an item to the WIA service.
IWiaMiniDrv::drvGetWiaFormatInfo | Find the formats and media types that the WIA hardware device supports.


WIA Minidriver Development: Phase 3

Implement the following method:

Method | Description
IWiaMiniDrv::drvValidateItemProperties | Validate an item's properties against the set of valid values for each property.


WIA Minidriver Development: Phase 4

Phase 4 involves implementing the following communication interface methods:

Method | Description
IWiaMiniDrv::drvDeleteItem | Delete the specified driver item.
IWiaMiniDrv::drvNotifyPnpEvent | Respond to a WIA device event notification. This method is required if the minidriver returns a list of device events in the IWiaMiniDrv::drvGetCapabilities method.
IWiaMiniDrv::drvGetCapabilities | Obtain the supported device commands and events.


WIA Minidriver Development: Phase 5

Phase 5 involves implementing methods that respond to device commands and return device-specific error message for a given error code:

Method | Description
IWiaMiniDrv::drvDeviceCommand | Issue a command to a WIA device.
IWiaMiniDrv::drvGetDeviceErrorStr | Convert an error code to a UNICODE string.


WIA Minidriver Troubleshooting

By default, the WIA service logs errors to a file named wiadebug.log in the %windir% directory. The information that the WIA service places in this file can be very helpful during driver development. The following example depicts a typical problem, and how the information in the wiadebug.log file can be used to find a solution to the problem.

A developer writes an application to test a scanner driver that is under development. As one of the tests, the developer attempts to set the scanner's DPI to 1200, but notices that this action produces an error. A look at the wiadebug.log file shows the following:

wiasGetChangedValueLong, validate prop 6147 failed hr: 0x80070057
wiasUpdateScanRect, CheckXResAndUpdate failed (0x80070057)
CDrvWrap::WIA_drvValidateItemProperties, Error calling driver:
drvValidateItemProperties with hr = 0x80070057 (This is normal if the app wrote an invalid value)

These log entries indicate that the driver is reporting that the application wrote an invalid value. It is not clear from this information what the exact problem is. If the developer increases the WIA logging level to report warnings as well as the errors, wiadebug.log produces output similar to the following:

    wiasValidateItemProperties, invalid LIST value for :
        (propID) Horizontal Resolution, value = 1200
    Valid values are:
        75
        100
        150
        200
        300
        600
    wiasGetChangedValueLong, validate prop 6147 failed hr: 0x80070057
    wiasUpdateScanRect, CheckXResAndUpdate failed (0x80070057)
        CDrvWrap::WIA_drvValidateItemProperties, Error calling driver:
        drvValidateItemProperties with hr = 0x80070057 (This is normal if the app wrote an invalid value)

The output shows that the Horizontal Resolution property is causing the failure. The application is attempting to set the resolution to 1200, but the list of supported resolutions does not include 1200; therefore the WIA service validation helper wiasValidateItemProperties rejects the request to set this value.

Now that the problem is identified, it is up to the developer to determine whether it is the driver or the application that must be revised. If the scanner's specifications allow it to support all resolutions between 100 and 1400 dpi, the driver should be able to handle a request for 1200 DPI. If the scanner does not support this setting, the application should be changed so that it does not attempt to set the Horizontal Resolution to a value that is not valid for this property. In this case, the application should check that a value is valid before attempting to set a property to this value.

The logging level is controlled by an entry in the registry. For WIA, this key resides in:

HKLM\System\CurrentControlSet\Control\StillImage\Debug\MODULE_NAME\DebugFlags

Here MODULE_NAME is the name of the appropriate binary module. For the WIA service, this is wiaservc.dll. The value in DebugFlags controls the logging level. Three of the settings are given in the following table:

Value | Meaning
0x00000001 | Display error messages.
0x00000002 | Display warning messages.
0x00000004 | Display trace messages.

The value in DebugFlags is a flag value; that is, different settings may be ORed together. To turn on logging for errors, warnings, and traces all at once, set DebugFlags to 0x0000007.

In order for a change in value of DebugFlags to take effect, the WIA service (stisvc) must be stopped, and then restarted. See Starting and Stopping the Still Image Service for details.

Note  Excessive logging can lead to a significant decrease in performance. Increase the logging level only to attempt to solve a particular problem. After you have corrected the problem, set logging to its original level.


WIA Minidriver Debugging

WIA drivers execute inside the WIA service process. Therefore, in order to perform user-mode debugging of these drivers, you must connect the debugger to the WIA service. There are several different ways to do this; this topic presents two of them. (See Debugging Services in the Platform SDK documentation for further information).

Your debugger can be started in either of two ways:

  1. By automatically starting the WIA Service under a debugger.
  2. By attaching the debugger to the appropriate process at run-time.

Here are two points to keep in mind:

  • If you require network access to symbols and other files from within the debugger, then these may not be visible if you automatically start the WIA service under the debugger. WIA runs as a LocalSystem service, and does not have the appropriate privileges to access the network. So, even though your machine can "see" everything on your network, the debugger running the service may not be able to.
  • If a problem occurs during driver loading or initialization of the STI portion of the driver (for example, during IStiUsd::Initialize), then by the time you attach a debugger, the error has already occurred, and it is too late to get useful information. A common symptom of this problem is that the device does not show up in the My Computer folder, but does show up in the Device Manager folder.

Starting the WIA Service under a Debugger

When the WIA service is started, the Service Control Manager (SCM) looks at the entry in the service control database, and launches the executable pointed to by that entry. A simple way to start the WIA service under a debugger is to replace that entry with one that includes your debugger. The entry can be found in the registry under:

HKLM\System\CurrentControlSet\Services\StiSvc\ImagePath

Initially, the ImagePath key is set to the following string value:

"%SystemRoot%\System32\svchost.exe -k imgsvc"

To run the WIA service under NTSD, for example, modify the preceding value as follows:

"ntsd -g -G %SystemRoot%\System32\svchost.exe -k imgsvc"

With this change, the WIA service always starts under NTSD. Note that if the service is already running, it must be stopped and restarted before this change takes effect. See Starting and Stopping the Still Image Service for details.

To make the debugger's window visible, there is another registry key you need to change. The path to this registry key is:

HKLM\System\CurrentControlSet\Services\StiSvc\Type

The initial value of the Type key, 0X20, prevents the debugger window from being displayed. Change the value of the Type key to the DWORD value 0X120.

Attaching the Debugger at Run-time

Most debuggers require the PID of the running process in order to attach to it after the process has already started. Since WIA runs under a generic hosting process called svchost.exe, finding the correct instance of svchost.exe is essential.

If you downloaded the debugger package from the Microsoft site (www.microsoft.com), it includes a utility program named tlist.exe. Tlist.exe displays all running processes. If you execute tlist.exe using the "s" switch, this utility also shows which processes are hosting which services. For example, running tlist.exe -s produces output similar to the following:

   0 System Process
   4 System
 160 smss.exe
 216 csrss.exe       Title:
 208 winlogon.exe    Title: NetDDE Agent
 268 services.exe    Svcs:  Eventlog,PlugPlay
 280 lsass.exe       Svcs:  Netlogon,PolicyAgent,ProtectedStorage,SamSs
 416 svchost.exe     Svcs:  RpcSs
 444 svchost.exe     Svcs:  AudioSrv,CryptSvc,Dhcp,EventSystem,FastUserSwitching,CompatibilityServices,helpsvc,Irmon,lanmanserver,lanmanworkstation,Netman,Nla,Schedule,SENS,ShellHWDetection,srservice,TapiSrv,TermService,ThemeService,uploadmgr,W32Time,winmgmt,WmdmPmSp
 504 svchost.exe     Svcs:  Dnscache
 372 svchost.exe     Svcs:  LmHosts,Messenger,RemoteRegistry,SSDPSRV,WebClient
 616 spoolsv.exe     Svcs:  Spooler
 680 inojobsv.exe    Svcs:  Cheyenne InocuLAN Anti-Virus Server
 700 emsvc.exe       Svcs:  EMSVC
 912 fxssvc.exe      Svcs:  Fax
 192 explorer.exe    Title: Program Manager
1076 svchost.exe     Svcs:  stisvc
22824 tlist.exe

In the preceding example, five instances of svchost.exe are running. The WIA service, StiSvc (for Still Image service), is running under the svchost.exe instance whose PID is 1076. Attach the debugger to process 1076 to start debugging.

Instead of using a utility program such as tlist.exe to identify a single instance of multiple svchost.exe instances, you can make a copy of svchost.exe and rename it (for example, to stisvc.exe). Then, change the service control entry's ImagePath value to use this copy of svchost.exe (the one whose name is now stisvc.exe). For example, you can set the key whose path is

HKLM\System\CurrentControlSet\Control\Services\Stisvc\ImagePath

to the following string value:

"%SystemRoot%\System32\stisvc.exe -k imgsvc"

Now, when the WIA service starts, it runs under stisvc.exe instead of svchost.exe. Finding this process is simpler, because there is only a single instance of stisvc.exe. You do not have to look for the PID to find it. So, for example, if you are developing the driver using Microsoft Visual Studio, you can go to the Start Debug menu item under the Build menu, click Attach to Process..., and select stisvc.exe in the list.


WIA Minidriver Best Practices

This page consists of recommended tips for WIA minidriver writers.

Scanner Brightness, Intensity, and Threshold Properties

A WIA scanner minidriver defines the set of valid values for the brightness, intensity, and threshold properties (the WIA_IPS_BRIGHTNESS, WIA_IPS_INTENSITY, and WIA_IPS_THRESHOLD properties are described in the Platform SDK documentation). In order for the UI controls to work predictably, you should define reasonable ranges for these properties. A reasonable range includes at least 100 uniformly distributed values. If the range includes negative numbers, there should be about the same number of negative valid values as positive.

Some examples of reasonable ranges for these properties include: -100...100, 0...256, -128...127, and 0...1000. If your scanner does not require such fine-grained control for these properties, you can use list values to specify the set of valid values. In this case, the list values should have some sort of relationship to a meaningful range as previously described.

Any properties that have no effect should be either marked read-only (required properties), or removed (all others).


Still Image Drivers

The Windows DDK update ships a new architecture called Windows Image Acquisition (WIA). WIA is built on the foundation of the Microsoft® Still Image architecture (Microsoft STI), thus drivers built on STI easily migrate to WIA. See Windows Image Acquisition Drivers for details.

This section is provided for legacy drivers developed on Microsoft STI. It describes the COM interfaces that are defined by Microsoft STI and available to vendors of such still image hardware as flatbed scanners and digital still image cameras. The COM interfaces described in this section are called by, or defined by, the following vendor-supplied software:

  • Device-specific components of image acquisition API software, such as the TWAIN data sources that are required so the TWAIN API can support specific still image devices.
  • User-mode still image minidrivers, which provide a communications path from image acquisition software to lower-level device and bus drivers.

The section contains the following sections:

Overview of Microsoft STI and Microsoft WIA

Introduction to Microsoft STI

Microsoft STI Components

Still Image COM Interfaces

Creating Push-Model Aware Applications

Creating Device-Specific Components for Image Acquisition APIs

Creating a User-Mode Still Image Minidriver

Installing and Configuring Still Image Components

Debugging Still Image Components


Overview of Microsoft STI and Microsoft WIA

The imaging architecture in Windows 2000 and Windows 95/98 consists of a low-level hardware abstraction, STI, and a high-level set of APIs known as TWAIN. In the Windows XP and Windows Me operating system versions, Microsoft introduces Windows Imaging Architecture (WIA), an imaging architecture that builds on STI.

Microsoft Imaging Architectures: TWAIN/STI and WIA

As shown in the preceding figure, the TWAIN/STI architecture includes TWAIN, a high-level set of image acquisition APIs, together with STI, a low-level hardware abstraction. The WIA architecture incorporates STI as a foundation to provide a complete solution to imaging device IHVs.

Differences Between STI and WIA

  • A WIA driver does not have to expose STI interfaces, since these are already part of WIA; an imaging driver that is intended to run on Windows 2000, or on Windows 95/98, or that ships TWAIN data sources must expose STI interfaces.
  • STI runs in both the client application process and the system service process; WIA runs in the system service process only.
  • STI, being a low-level hardware abstraction, must have detailed information about the device in order to operate; WIA can operate without such detailed device information.
  • STI is not a complete imaging interface; WIA, which is built on top of STI, is a full solution for imaging IHVs.

The following links provide more information of interest to developers writing STI drivers:

Microsoft STI Components

WIA/Still Image Core Components

Still Image COM Interfaces

Installing and Configuring Still Image Components

The following links provide information of interest to developers writing WIA drivers:

Windows Image Acquisition Drivers

Introduction to Microsoft STI

WIA/Still Image Core Components

TWAIN Compatibility

Installing a WIA Minidriver

Recommended Development Plan


Introduction to Microsoft STI

Microsoft STI is made up of the following primary components:

  • A Still Image Event Monitor, which monitors all installed still image devices and receives notification when still image device events occur. An event typically indicates that a device is ready to transmit image data. The Event Monitor also keeps track of all registered applications and can start an application when an event is detected.
  • A set of vendor-supplied, user-mode still image minidrivers that can detect device activity and notify the Still Image Event Monitor of that activity through still image device events. These minidrivers also pass image data from kernel-mode drivers to upper level software.
  • A Scanners and Cameras Control Panel, which allows users to assign specific still image device events to specific applications. In this way, the Event Monitor will know which application to start when it detects an event. The Control Panel also lets users test still image devices.

An imaging application can register itself as push-model aware, meaning it can be activated by the Event Monitor when a still image device is ready to transmit an image.

Imaging applications typically read image data streams by calling a high-level image acquisition API, such as TWAIN. Device-specific sub-components of the image acquisition API, such as TWAIN data sources, use an interface into the user-mode still image minidrivers to perform I/O operations.

Microsoft STI defines several Still Image COM interfaces that allow STI components to communicate with each other.

The next section provides more information about these and other Microsoft STI components.


Microsoft STI Components

The following diagram illustrates the software components that compose Microsoft STI. Following the diagram is a component list.

Imaging Application

Imaging applications typically receive, display, and allow editing of captured still images. They obtain images by calling an image acquisition API, such as TWAIN. They must register themselves with the Still Image Event Monitor, through the IStillImage COM interface. For more information, see Creating Push-Model Aware Applications.

Image Acquisition API

TWAIN, ISIS, and Adobe Systems' Acquire are examples of image acquisition APIs. The diagram illustrates TWAIN. Vendor-supplied TWAIN data sources are device-specific, Operating System-specific components that communicate with still image devices.

Under Microsoft STI, TWAIN data sources call methods supplied by the IStillImage COM interface and the IStiDevice COM interface. For more information, see Creating Device-Specific Components for Image Acquisition APIs.

Scanners and Cameras Control Panel

The Scanners and Cameras Control Panel enables users to perform the following operations:

  • View a list of installed still image devices.
  • Test still image devices.
  • View and modify information provided by vendor-supplied, device-specific property sheet pages for still image devices.
  • Assign still image device events to specific applications.

Still Image Event Monitor

The Still Image Event Monitor resides in the Still Image server process. It maintains a database of all still image devices (both Plug and Play-compatible devices and those installed through the Add Hardware Wizard). It also maintains databases of registered applications and still image device events.

The Event Monitor waits for still image device events. (For devices supported by older drivers that do not generate still image device events, the Event Monitor creates a polling thread.) When an event is detected, the Event Monitor starts the application previously assigned to the event by the user (by means of the Scanners and Cameras Control Panel). If the user has assigned the event to several applications, the Event Monitor asks the user which application to start. If the event has not been assigned to any application, it is ignored.

For more information about the Still Image Event Monitor, see Still Image in the Platform SDK documentation.

COM Interfaces for Still Image

Microsoft STI defines a set of COM interfaces that provide communications paths among the various Microsoft STI components. The following COM interfaces are defined:

IStillImage COM Interface
IStiDevice COM Interface
IStiUSD COM Interface
IStiDeviceControl COM Interface

User-Mode Still Image Minidrivers

User-mode still image minidrivers are vendor-supplied components that provide a device-specific, user-mode interface to an appropriate kernel-mode driver. Each of these user-mode drivers must implement the IStiUSD COM interface. They communicate with kernel-mode drivers by calling the CreateFile, ReadFile, WriteFile, and DeviceIoControl Win32® functions (described in the Platform SDK documentation). For more information, see Creating a User-Mode Still Image Minidriver.

Kernel-Mode Still Image Drivers

Kernel-mode still image drivers package data for delivery to still image devices connected to specific bus types. Microsoft provides WDM-based kernel-mode still image drivers for the USB and SCSI buses. For more information, see Accessing Kernel-Mode Drivers for Still Image Devices.

For still image devices connected to other buses, the user-mode minidriver communicates with the kernel-mode bus driver stack directly.

A vendor only needs to provide a kernel-mode still image driver if a device is incompatible with Microsoft-supplied drivers.

Kernel-Mode Bus Driver Stacks

Microsoft supports still image devices connected to SCSI, USB, parallel, IEEE 1394-compatible, and serial buses, along with devices connected to infra-red interfaces, as follows:

Devices connected to SCSI and USB buses
User-mode drivers call bus-specific kernel-mode drivers for still image devices.
Devices connected to a parallel port
Extended capabilities port (ECP) and enhanced parallel port (EPP) modes are supported. A vendor-supplied, kernel-mode filter driver can be added between the user-mode still image driver and the kernel-mode bus driver stack. (For more information about parallel port drivers, see the Parallel Ports and Devices node of this Windows DDK documentation. For more information about filter drivers, see Filter Drivers.)
Devices connected to an IEEE 1394 bus
For devices that support the SBP-2 protocol, user-mode drivers can call Microsoft's SBP-2 interface. Otherwise, a vendor-supplied filter driver is required.
Devices connected to a serial port
The standard serial port driver is used. (For more information, see Serial Devices and Drivers.)
Devices connected to an infrared interface
Drivers can call the IrSock software interface (described in the SDK documentation).

A vendor only needs to provide bus drivers for buses that are not supported by Microsoft drivers.


Still Image COM Interfaces

Microsoft STI defines the following four COM interfaces:

IStillImage COM Interface – Provides access to the Still Image Event Monitor.

IStiDevice COM Interface – Provides access to still image data streams and device events.

IStiUSD COM Interface – Provides access to user-mode still image minidrivers.

IStiDeviceControl COM Interface – Provides utility operations to minidrivers.


IStillImage COM Interface

The IStillImage COM interface provides access to the Still Image Event Monitor so applications can register themselves as "push-model aware". Applications can use this interface to obtain information about the system's still image devices.

The interface provides some application management functions, such as enabling event notification and starting an application, for use by customized application control software.

Additionally, the IStillImage interface provides access to the IStiDevice COM interface, which allows applications to perform I/O operations on still image devices.

The following table lists and describes all of the IStillImage interface's methods. The table indicates the types of clients that typically must call each method.

Method | Description | Typical Callers
IStillImage::CreateDevice
 | Creates an instance of the COM object that defines the IStiDevice interface, and returns a pointer to the interface. | Image Acquisition APIs
IStillImage::EnableHwNotifications
 | Enables or disables the notification of applications when still image device events occur for a specified device. | Still Image Event Monitor
IStillImage::GetDeviceInfo
 | Returns hardware characteristics for a specified still image device. | Image Acquisition APIs
IStillImage::GetDeviceList
 | Returns hardware characteristics for all installed still image devices. | Scanners and Cameras Control Panel, Image Acquisition APIs
IStillImage::GetDeviceValue
 | Returns registry information associated with a specified still image device. | Image Acquisition APIs, Scanners and Cameras Control Panel
IStillImage::GetHwNotificationState
 | Indicates whether applications will be notified when still image device events occur on a specified device. | Still Image Event Monitor
IStillImage::GetSTILaunchInformation
 | Returns the reason the calling Still Image application was started, if it was started by the Still Image Event Monitor. | Push-model aware applications
IStillImage::Initialize
 | Initializes the object instance. | Not called directly
IStillImage::LaunchApplicationForDevice
 | Starts a specified application for a specified still image device. | Still Image Event Monitor
IStillImage::RegisterLaunchApplication
 | Adds an application to the Still Image Event Monitor's list of push-model aware applications. | Push-model aware applications or their installers
IStillImage::Release
 | Closes the object instance and removes access to the IStillImage interface. | All IStillImage interface clients
IStillImage::SetDeviceValue
 | Sets registry information for a specified still image device. | Scanners and Cameras Control Panel
IStillImage::SetupDeviceParameters
 | Allows clients of the IStillImage interface to modify a still image device's stored characteristics. | Scanners and Cameras Control Panel
IStillImage::StiCreateInstance
 | Creates an instance of the COM object that defines the IStillImage interface, and returns a pointer to the interface. | All IStillImage interface clients
IStillImage::UnRegisterLaunchApplication
 | Removes an application from the Still Image Event Monitor's list of push-model aware applications. | Push-model aware applications or their installers
IStillImage::WriteToErrorLog
 | Writes a message to the Still Image error log. | All IStillImage interface clients


IStiDevice COM Interface

The IStiDevice COM interface provides applications with the ability to communicate with still image devices. Interface methods allow applications to send and receive data and commands, to run diagnostic tests, to receive notifications of still image device events, and to obtain device capabilities and status information.

Access to the IStiDevice interface is obtained by calling the CreateDevice method of the IStillImage COM interface. Many of the IStiDevice interface's methods are implemented by calling like-named methods defined by the IStiUSD COM interface.

The following table lists and describes all of the methods supplied by the IStiDevice interface. The table indicates the types of clients that typically must call each method.

Method | Description | Typical Callers
IStiDevice::DeviceReset
 | Resets a still image device to a known state. | Image Acquisition APIs
IStiDevice::Diagnostic
 | Executes diagnostic tests on a still image device. | Scanners and Cameras Control Panel
IStiDevice::Escape
 | Sends a request for a vendor-specific I/O operation to a still image device. | Image Acquisition APIs
IStiDevice::GetCapabilities
 | Returns a still image device's capabilities. | Still Image Event Monitor
IStiDevice::GetLastErrorInfo
 | Returns information about the last known error associated with a still image device. | Image Acquisition APIs
IStiDevice::GetLastNotificationData
 | Returns a description of the most recent event that occurred on a still image device. | Image Acquisition APIs
IStiDevice::GetStatus
 | Returns a still image device's status information. | Image Acquisition APIs, Still Image Event Monitor
IStiDevice::Initialize
 | Initializes an object instance. | Not called directly
IStiDevice::LockDevice
 | Locks a device for exclusive use by the caller. | All IStiDevice interface clients
IStiDevice::RawReadCommand
 | Reads command information from a still image device. | Image Acquisition APIs
IStiDevice::RawReadData
 | Reads data from a still image device. | Image Acquisition APIs
IStiDevice::RawWriteCommand
 | Sends command information to a still image device. | Image Acquisition APIs
IStiDevice::RawWriteData
 | Writes data to a still image device. | Image Acquisition APIs
IStiDevice::Release
 | Closes an object instance and removes access to the IStiDevice interface. | All IStiDevice interface clients
IStiDevice::Subscribe
 | Registers the caller to receive notifications of device events. | Image Acquisition APIs
IStiDevice::UnlockDevice
 | Unlocks a device. | All IStiDevice interface clients
IStiDevice::Unsubscribe
 | Removes the caller from the list of applications registered to receive notification of device events. | Image Acquisition APIs


IStiUSD COM Interface

The IStiUSD COM interface is the means by which the IStiDevice COM interface communicates with still image devices. The IStiUSD interface's methods are implemented by each vendor-supplied user-mode still image minidriver.

Typically, IStiUSD interface methods are called by similarly named methods defined by the IStiDevice interface. Still image minidrivers typically implement IStiUSD interface methods by calling the appropriate kernel-mode driver. Each minidriver must define all interface methods, but if a method is not needed it can return STIERR_UNSUPPORTED.

The following table lists and describes all of the methods defined by the IStiUSD interface.

Method | Description
IStiUSD::DeviceReset
 | Resets a still image device to a known, initialized state.
IStiUSD::Diagnostic
 | Runs diagnostic tests on a still image device.
IStiUSD::Escape
 | Performs a vendor-specific I/O operation on a still image device.
IStiUSD::GetCapabilities
 | Returns a still image device's capabilities.
IStiUSD::GetLastErrorInfo
 | Returns information about the last known error associated with a still image device.
IStiUSD::GetNotificationData
 | Returns a description of the most recent event that occurred on a still image device.
IStiUSD::GetStatus
 | Returns the status of a still image device.
IStiUSD::Initialize
 | Initializes an instance of the COM object that defines the IStiUSD interface.
IStiUSD::LockDevice
 | Locks a device for exclusive use by the caller.
IStiUSD::RawReadCommand
 | Reads command information from a still image device.
IStiUSD::RawReadData
 | Reads data from a still image device.
IStiUSD::RawWriteCommand
 | Writes command information to a still image device.
IStiUSD::RawWriteData
 | Writes data to a still image device.
IStiUSD::SetNotificationHandle
 | Specifies an event handle that the minidriver should use to inform the caller of device events. Typically called by the Still Image Event Monitor.
IStiUSD::UnlockDevice
 | Unlocks a device.


IStiDeviceControl COM Interface

The IStiDeviceControl COM interface provides user-mode still image minidrivers with access to information stored within the Still Image Event Monitor. It also allows minidrivers to write information into the still image error log.

The following table lists and describes all of the methods defined by the IStiDeviceControl interface.

Method | Description
IStiDeviceControl::AddRef
 | Increments the IStiDeviceControl interface's reference count.
IStiDeviceControl::GetMyDeviceOpenMode
 | Allows a still image minidriver to obtain the transfer mode that an application specified when it created an instance of a still image device.
IStiDeviceControl::GetMyDevicePortName
 | Allows a still image minidriver to obtain a device's port name.
IStiDeviceControl::Release
 | Closes an instance COM object that defines the IStiDeviceControl interface, and removes access to the interface.
IStiDeviceControl::WriteToErrorLog
 | Allows a still image minidriver to write a message into the Still Image error log.


Creating Push-Model Aware Applications

A push-model aware application is one that has registered itself with Microsoft STI so that it can be automatically activated when a still image device event has occurred. An application can be made push-model aware by either of the following two methods:

  • Calling IStillImage::RegisterLaunchApplication. The call can be made by the application or by its installation program.
  • Including an entry in the application's INF file. The entry should be referenced by an AddReg directive in the INF file. The syntax of the entry is illustrated in the following example:
    ; Register Application "Imaging" as a push-model aware application for use with Still Image Event Monitor
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\StillImage\Registered Applications",Imaging,,"%25%\KodakImg.Exe /StiDevice:%%1 /StiEvent:%%2"

    Two INF file entries are required for devices that support push-model aware applications: DeviceData and Events. For more informatio, see INF Files for Still Image Devices.

Either of these methods causes the application to be registered with the Still Image Event Monitor.

If an application is registered as push-model aware, a user can assign still image device events to the application with the Scanners and Cameras Control Panel. Additionally, vendors can provide an initial assignment of device events to applications by including application names within a device driver's INF file, as illustrated in the sample INF file provided with the sample still image code. A user can change this initial assignment with the Scanners and Cameras Control Panel.

After device events have been assigned to an application, the Event Monitor will start the application when it detects an occurrence of an assigned device event.

When a push-model aware application is activated, it should call IStillImage::GetSTILaunchInformation to determine the event and the device for which it was started. It can then call IStillImage::GetDeviceInfo to obtain more information about the device.

The application must handle the event, or it must create a user display explaining why it cannot handle the event. Presumably, the user will then use the control panel to associate the device event with some other application.

Handling the event typically means reading in an image. To do this, the application typically calls an image acquisition API, such as TWAIN.

If an application has been started because an event occurred, but an image acquisition API has not opened the device in data mode (see Transfer Modes), the Event Monitor will start another instance of the application if another event is detected. The application must be implemented so that it either allows multiple instances or (preferably) recognizes when it is not the first instance, sends a message to the first instance identifying the event, and exits.


Creating Device-Specific Components for Image Acquisition APIs

Image acquisition APIs, such as TWAIN, typically require device-specific components, such as TWAIN data sources. These device-specific components should use the IStillImage COM interface and the IStiDevice COM interface to communicate with user-mode still image device drivers and the Event Monitor.

Image acquisition APIs can call IStillImage::GetDeviceValue and IStillImage::SetDeviceValue to read and write registry entries for still image devices. For example, the name of each still image device's TWAIN data source is stored in the registry.

Because the TWAIN API does not allow an application to specify the active device when calling a data source, the data source will typically call IStillImage::GetDeviceList to obtain a list of all still image devices, and then will search the list to find the correct device, usually based on the manufacturer and model names. The manufacturer and model text names are obtained from the INF file. Because TWAIN has a 32-character limit for data source names, and because WIA appends "WIA-" to strings to construct the compatible names, the text in the INF file should not be longer than 28 characters. Otherwise, TWAIN-compatible applications that perform a comparison on the entire string, and not just the first 32 characters, might not be able to automatically find the device that caused the application to launch.

To access a device, image acquisition software calls IStillImage::CreateDevice to create an instance of the COM object that defines the IStiDevice interface. The IStiDevice interface provides several methods for performing device I/O operations. When creating the object instance, image acquisition software should specify the "data" transfer mode.

Image acquisition software can call IStiDevice::Subscribe to request the Event Monitor to deliver notification of still image device events. Once notification is received, IStiDevice::GetLastNotificationData can be called to determine the type of event. IStiDevice::Unsubscribe should be called when notifications are no longer needed.

When the image acquisition software has finished using the IStiDevice interface, it must call IStiDevice::Release.


Creating a User-Mode Still Image Minidriver

All user-mode still image minidrivers must implement the interface methods defined by IStiUSD COM interface. This implementation is relatively easy, using the following steps:

  1. Obtain a GUID for the interface, and include it in a header file and an INF file, as illustrated in the sampusd.h and sampusd.inf files for the Sample Still Image Code.
  2. Make a copy of the sample file named sampusd.cpp. Replace all instances of the string "sampusd" with another string that is unique for your device.
  3. Create a customized class definition, using IStiUSD as an inherited class, based on the UsdSampDevice class defined in sampusd.h. For compatibility with your edited version of sampusd.cpp, modify the class name using the same replacement string used in your edited version of sampusd.cpp. Modify the class constructor and destructor functions contained in the file, as needed for your implementation.
  4. Implement all of the methods that have been defined for the IStiUSD COM interface. If a method is not needed, it must return STIERR_UNSUPPORTED.

This section provides information about the following topics:

Still Image Device Events

Transfer Modes

Security Issues for Still Image Drivers


Still Image Device Events

A still image device event is a device-level occurrence that upper-level software should be notified about, if that software has requested such notification. The user-mode minidriver is responsible for defining most device events and delivering notifications when an event occurs. In general, events indicate that upper-level software is going to be required to perform some action.

A typical still image device event is the detection of a push button being pressed. For example, a scanner might provide a user with separate buttons to initiate scanning text and photographs. When a button is pressed, upper-level software will be needed in order to display or store the image. The Still Image Event Monitor detects that the event has occurred (using the IStiDevice COM interface) and can call a still image application that was previously registered (using the IStillImage COM interface).

Still image device events are represented by GUIDs. In sti.h, Microsoft defines the following still image device events:

Event GUID | Purpose
GUID_DeviceArrivedLaunch | A still image device has just been attached to the system.
GUID_ScanImage | An image should be scanned into the computer.
GUID_ScanFaxImage | An image should be scanned into the computer and then faxed.
GUID_ScanPrintImage | An image should be scanned into the computer and then printed.
GUID_STIUserDefined1 | A user-definable button has been pressed.
GUID_STIUserDefined2 | A user-definable button has been pressed.
GUID_STIUserDefined3 | A user-definable button has been pressed.

Developers of user-mode minidrivers should use these predefined event GUIDs whenever possible. If these GUIDs are not appropriate, GUIDs for device-specific events must be defined.

To define a still image device event, you must:

  • Specify a GUID for each event, using the DEFINE_GUID macro, as illustrated in sampusd.h in the Sample Still Image Code.
  • Include each GUID in the user-mode driver's INF file, as illustrated in sampusd.inf.

Within the driver's INF file, each GUID specification must include either an asterisk (meaning "all applications") or a list of specific applications, indicating which applications should be started when the event occurs. The Still Image Event Monitor uses this list to provide default assignments of applications to events. The user can modify these assignments with the Scanners and Cameras Control Panel.

Event Notification

The driver must monitor the device (using either asynchronous I/O or polling) to determine when the event associated with each GUID occurs. Depending on device capabilities, the driver can notify clients of the occurrence of device events either asynchronously or by responding to a request to poll the device. All drivers that are capable of delivering notification of device events (by either method) must set the STI_GENCAP_NOTIFICATIONS flag in the device's STI_DEV_CAPS structure. Drivers that support polling, and not asynchronous notification, must also set the STI_GENCAP_POLLING_NEEDED flag in the same structure. (These capabilities must also be indicated using the Capabilities keyword in INF files for still image devices.)

If a driver supports asynchronous notification of events, the Event Monitor calls IStiUSD::SetNotificationHandle to request notifications and to supply an event handle. When a device event occurs, the driver must notify the Event Monitor by calling SetEvent (see the Platform SDK documentation), using the event handle as an argument. The client can then call IStiUSD::GetNotificationData to obtain the event's GUID.

If polling is required, the Event Monitor calls IStiUSD::GetStatus to poll the driver, which must in turn poll the device and return results in an STI_DEVICE_STATUS structure.


Transfer Modes

The Still Image interfaces define two transfer modes – status mode and data mode. When a client of the IStillImage COM interface calls IStillImage::CreateDevice to obtain access to a still image device, it specifies one (or both) of the transfer modes. Multiple clients can open a device in status mode, but only one client at a time is allowed to open a device in data mode.

The Still Image Event Monitor opens devices in status mode. Typically, but not always, image acquisition APIs open devices in data mode.

Once a client has opened a device in data mode, the Event Monitor stores subsequent still image device events in an internal queue. If the client calls IStiDevice::Subscribe, it can read events from the queue by calling IStiDevice::GetLastNotificationData. After the client closes the device, subsequently received events cause the Event Monitor to again try to start a registered application.

The meanings of the two transfer modes are entirely dependent on the device's user-mode minidriver. The IStillImage and IStiDevice interfaces allow all methods to be called in either mode.

A minidriver can determine the mode in which it was opened by calling IStiDeviceControl::GetMyDeviceOpenMode. Minidrivers should prohibit a client from performing data transfers if the client requested only status mode when obtaining access to the device.

It is important to note that devices are typically opened in status mode for a relatively long time (for example, the Event Monitor watches for device events), while they are opened in data mode for a relatively short time (for example, to read in an image). Although the Still Image architecture allows only one client at a time to open a device in data mode, it might be necessary for a driver to place further restrictions on device access.

For instance, if you are writing a driver for a device connected to a serial port, you might want to call CreateFile from within the driver's IStiUSD::LockDevice method if the device was opened in status mode. This will prohibit other applications from using the port (which might be supporting other devices) while status information is being obtained from the device.

For devices connected to dedicated ports, such as SCSI or USB bus devices, it is typically allowable to call CreateFile from within IStiUSD:Initialize if status mode is specified, because the device and port will always be dedicated to one client.

When a device is opened in data mode, CreateFile is typically called from within IStiUSD:Initialize, independent of the bus type.


Security Issues for Still Image Drivers

It is important to remember that a user-mode minidriver can be called either from an application (through an image acquisition API), or from the Still Image Event Monitor (which is implemented as a Windows® 2000 service). There are security implications associated with these multiple calling sources. For example, if a user-mode minidriver creates a mutex using the default security descriptor (by specifying a NULL security descriptor), one mutex cannot be shared between an instance of the minidriver called from the Event Monitor and one called from an image acquisition API.


Installing and Configuring Still Image Components

This section provides the following topics:

Property Sheet Pages for Still Image Devices

Registry Entries for Still Image Devices

INF Files for Still Image Devices

Still Image Device Installers

Color Management for Still Image Devices


Property Sheet Pages for Still Image Devices

You can provide a DLL that creates device-specific property sheet pages. The Scanners and Cameras Control Panel calls the DLL's entry point when a user attempts to view the device's property sheet.

To cause this DLL to be installed and used, you must include a PropertyPages entry in your INF file. This entry contains the DLL's filename and entry point name. For more information, see INF Files for Still Image Devices.


Registry Entries for Still Image Devices

Microsoft STI makes use of several registry entries, some of which can be modified by vendor-supplied components.

Vendor-Modifiable Registry Values

The following table lists predefined registry value names and their meanings. Constants are defined in stireg.h. A value must be assigned to "TwainDS" if the device supports the Still Image push model. Values for the other names are optional.

Constant | Value Name String | Definition
STI_DEVICE_VALUE_ICM_PROFILE
 | "ICMProfile" | REG_MULTI_SZ type containing names of ICM profiles for the device.
STI_DEVICE_VALUE_ISIS_NAME
 | "ISISDriverName" | REG_SZ type containing the device's ISIS driver name, such as "epson.pwx".
STI_DEVICE_VALUE_TIMEOUT
 | "PollTimeout" | REG_DWORD type representing the time-out value, in milliseconds, that should be used when polling the device. The default value is 1000 (1 second).
STI_DEVICE_VALUE_TWAIN_NAME
 | "TwainDS" | REG_SZ type containing the displayable name of the device's TWAIN data source, such as "HP PictureScan 3.0".

Clients of the StillImage COM interface should call IStillImage::SetDeviceValue and IStillImage::GetDeviceValue to reference the registry. Still Image minidrivers can call the Win32® registry API, specifying the registry key received by the minidriver's IStiUSD::Initialize method. Values for predefined registry entries can also be set from within INF files for still image devices.

Customized Registry Values

Still image applications and minidrivers can also store customized, device-specific values in the registry. For example, user selections obtained from customized property sheet pages could be stored under a "UserSettings" subkey.

Additionally, values for customized registry entries can be set from within INF files for still image devices by including a DeviceData entry.

Non-Modifiable Registry Entries

The following table lists registry entries that should not be modified by vendor software.

Registry Key | Definition
HKLM\SYSTEM\CurrentControlSet\Control\StillImage\Logging\STICLI
 | Specifies which vendor-generated messages are written to the still image log file. Can be any combination of the following bit masks: 0x1 informational messages 0x2 warning messages 0x4 error messages See IStillImage::WriteToErrorLog.
HKLM\SYSTEM\CurrentControlSet\Control\StillImage\Logging\STIMON
 | Specifies which Event Monitor messages are written to the still image log file. Can be any combination of the following bit masks: 0x1 informational messages 0x2 warning messages 0x4 error messages
HKLM\SYSTEM\CurrentControlSet\Control\Class\{6BDD1FC6-810F-11D0-BEC7-08002BE2092F}
 | Contains information about installed still image devices.
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\StillImage\Registered Applications
 | Contains a list of registered imaging applications.
HKLM\SYSTEM\CurrentControlSet\Control\DeviceClass\{6bdd1fc6-810f-11d0-bec7-08002be2092f}
 | Contains information about installed still image device interfaces.


INF Files for Still Image Devices

The default class installer for still image devices, sti_ci.dll, recognizes a special set of .inf file entries. Within an .inf file, these entries must be placed within a device's INF DDInstall section. The entries are described in the following table.

INF File Entry | Value | Comments
SubClass
 | StillImage | Required
DeviceType
 | 1 for scanners, 2 for cameras | Required
DeviceSubType
 | Vendor-defined value. | Optional
Connection
 | For non-PnP devices connected to serial or parallel ports, this can be Serial or Parallel to limit the user's choice of ports during installation. | Optional. If not specified, the user can select any serial or parallel port.
Capabilities
 | Specifies a number that is converted to bit flags identifying device capabilities. These flags are stored in the registry and are available to Microsoft STI components by means of the STI_DEV_CAPS structure. Bit 0 – Sets/clears STI_GENCAP_NOTIFICATIONS in STI_DEV_CAPS. Bit 1 – Sets/clears STI_GENCAP_POLLING_NEEDED in STI_DEV_CAPS. Bit 2 – Sets/clears STI_GENCAP_GENERATE_ARRIVALEVENT in STI_DEV_CAPS. Bit 3 – Sets/clears STI_GENCAP_AUTO_PORTSELECT in STI_DEV_CAPS. | Optional
PropertyPages
 | Identifies the name and entry point of a DLL that creates customized property sheet pages for still image devices. | Optional
DeviceData
 | Identifies a vendor-supplied data section containing information to be stored in the registry, under the DeviceData key. For TWAIN-supported devices, the data section must contain a TwainDS entry (see Vendor-Modifiable Registry Values). | Optional. This entry is required for push-model aware applications, however.
Events
 | Identifies a vendor-supplied data section listing still image device events. Each entry in this section must have the following format: EventName="String",{GUID},App EventName is the event's internal name, String is the event's display string, GUID is the event's GUID (see Still Image Device Events), and App specifies the imaging application to be launched when the event occurs. To launch the currently registered application, use an asterisk (*) for App. | Optional. This entry is required for push-model aware applications, however.
UninstallSection
 | Points to an INF section typically containing INF DelFiles directives and INF DelReg directives. An entry in this section has the following format: UninstallSection=UninstallSectionName UninstallSectionName is the name of the section containing Delfiles or DelReg directives. Note that Windows File Protection (WFP) might prohibit a user from deleting some files, even though they are specified using DelFiles directives. | Optional

The default class installer for still image devices supports the standard INF CopyFiles directive. The installer uses an internal reference counter for component files, so files shared by several devices are not removed prematurely during an uninstall operation.

The default .inf file for still image devices, sti.inf, defines two installation sections for each device type, as follows:

  • An INF DDInstall section, which must be referenced within the DDInstall section of the vendor-supplied .inf file, as shown in the following table.
For USB devices For SCSI devices For serial devices
Include=sti.inf
Needs=STI.USBSection

Include=sti.inf
Needs=STI.SCSISection

Include=sti.inf
Needs=STI.SerialSection

  • An INF DDInstall.Services section, which must be referenced within the DDInstall.Services section of the vendor-supplied .inf file, as shown in the following table.
For USB devices For SCSI devices For serial devices
Include=sti.inf
Needs=STI.USBSection.Services

Include=sti.inf
Needs=STI.SCSISection.Services

Include=sti.inf
Needs=STI.SerialSection.Services

The sample still image code includes sampusd.inf, which is an .inf file template for installing a user-mode still image minidriver. Comments within the .inf file indicate how the file should be modified.

If you are also creating device-specific components for image acquisition APIs, you will typically include the filenames for these components in the .inf file . This is also illustrated in the sample .inf file.

For additional guidance in creating .inf files for still image devices, you can look at any .inf file provided with Windows 2000 or later that contains the entry "Subclass=StillImage".


Still Image Device Installers

Microsoft provides a class installer for still image devices, with the following features:

  • WDM PnP detection when a device is installed.
  • Installation wizard for legacy devices connected to parallel and serial ports.
  • Support for special .inf file entries (see INF Files for Still Image Devices).
  • Support for vendor-supplied co-installer extensions. For more information, see Writing a Co-installer.

If necessary, vendors can provide customized installation programs that can be used instead of the Microsoft-supplied class installer.


Color Management for Still Image Devices

Vendors should provide one or more color profiles for each still image device. Color profile filenames should be included in the vendor-supplied INF file. If your device generates sRGB data, you can specify the system-supplied standard color profile, sRGB Color Space Profile.icm, as shown in the sample INF file. The installer copies the supplied filenames to one of the registry entries for still image devices.

If the device generates images using another color space, you will need to use a different color profile. Whether your device generates sRGB data or data in another color space, you will obtain the best results if you use a single color space consistently.

A still-image device must be made aware of the color space it sends its data to. For example, suppose that a user resets the gamma level (on a system that allows modification of the data source). The application will not be aware of this change.

For more information about color management, see the Platform SDK documentation.


Debugging Still Image Components

To aid the debugging of vendor-supplied still image components, the Still Image Event Monitor's behavior can be modified with command line options, using the Run option of the Start menu. The following options are available:

Command Line Option | Definition
stimon /h | Hides the message window.
stimon /r | Refreshes the Event Monitor's device list.
stimon /t number | Modifies the polling interval to the number of seconds specified by number. Typically used for increasing the polling interval.
stimon /v | Makes a window visible that displays Event Monitor messages.

The Event Monitor can be stopped and started by using the Windows 2000 Computer Management window. The Event Monitor is listed as the "Still Image Service".


IWiaMiniDrv Interface

The IWiaMiniDrv interface provides the methods that are the entry points for all communication between the minidriver and the WIA service. These methods allow the WIA service to control the device.

A WIA minidriver writer must implement each method in this interface, although the implementations are not required to do anything more than return E_NOTIMPL (for IWiaMiniDrv::drvAnalyzeItem and IWiaMiniDrv::drvGetDeviceErrorStr) or S_OK (for the other methods in this interface).

Method prototypes are defined in wiamindr.h.


IWiaMiniDrv::drvAcquireItemData

The IWiaMiniDrv::drvAcquireItemData method is called by the WIA service to transfer data from the device to an application.

HRESULT
  drvAcquireItemData(
    IN BYTE  *pWiasContext,
    IN LONG  lFlags,
    IN OUT PMINIDRV_TRANSFER_CONTEXT  pmdtc,
    OUT LONG  *plDevErrVal
    );

Parameters

pWiasContext
Points to a WIA service context.
lFlags
Is currently unused.
pmdtc
Points to a MINIDRV_TRANSFER_CONTEXT structure containing the device transfer context. The MINIDRV_TRANSFER_CONTEXT structure contains parameters that pertain to the data to be transferred.
plDevErrVal
Points to a memory location that will receive a status code for this method. If this method returns S_OK, the value stored will be zero. Otherwise, a minidriver-specific error code will be stored at the location pointed to by this parameter.

Return Value

On success, the method should return S_OK and clear the device error value pointed to by plDevErrVal. If the transfer was cancelled, the method should return S_FALSE. If the method fails, it should return a standard COM error code and fill in a minidriver-specific error code value in the memory pointed to by plDevErrVal. The Comments section has additional return-value information that applies to ADF scanning.

The value pointed to by plDevErrVal can be converted to a string by calling IWiaMiniDrv::drvGetDeviceErrorStr.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

For information on the processing that a minidriver typically performs during this method see Acquiring Item Data.

There are two main types of transfer: memory-based, and file-based. The WIA service indicates which type is to be performed by the setting of pmdtc—>tymed, which will be TYMED_CALLBACK or TYMED_MULTIPAGE_CALLBACK for memory-based transfers, and TYMED_FILE or TYMED_MULTIPAGE_FILE for file transfers. These constants are described in the Platform SDK documentation.

  • For memory-based transfers, a buffer may or may not have already been allocated, as indicated by the value in pmdtc—>bClassDrvAllocBuf. The WIA service can pass up to two buffers to the minidriver, but typically passes only one. The number of buffers is specified by the value in pmdtc—>lNumBuffers. If memory for the buffer is not already allocated, the minidriver should allocate it using any of the usual means, such as CoTaskMemAlloc, (described in the Platform SDK documentation), or new. If the minidriver allocates a buffer, it also has the responsibility of freeing the buffer.
  • For file transfers, the minidriver should first write the data to the buffer passed in the WIA service's call to this method, and then call wiasWritePageBufToFile to write the buffer data to the file involved. The minidriver should not attempt to use the file handle specified in pmdtc—>hFile to write the data to the file.

Periodically, the minidriver should call the IWiaMiniDrvCallBack::MiniDrvCallBack method in the COM interface point to by pmdtc—>pIWiaMiniDrvCallBack to update the status of the transfer. For memory-based transfers, this function is used to pass the data back to the application. How often this function should be called is left to the minidriver, but it should be called about ten times, or roughly once per second during the transfer, whichever is more often.

Other transfer parameters that the WIA service provides include the following:

  • pmdtc—>guidFormatID - the data format
  • pmdtc—>lCompression - the type of compression used

A potential problem for ADF-equipped scanners is running out of paper during a scan operation. The HRESULT that your implementation of IWiaMiniDrv::drvAcquireItemData returns depends on the current setting of the scanner's WIA_DPS_PAGES property, and whether all pages were properly scanned. Use the following rules to guide you in determining the appropriate HRESULT to return in this method.

Situation | HRESULT Value
The WIA_DPS_PAGES property was set to 0, and the scanner emptied its ADF with no errors. The WIA_DPS_PAGES property was set to N (where N > 0), and the scanner processed N pages with no errors. | S_OK
The WIA_DPS_PAGES property was set to N, and the scanner processed at least one page but ran out of paper before processing all N pages. | WIA_STATUS_END_OF_MEDIA
The scanner ran out of paper on the first scan, regardless of the setting of the WIA_DPS_PAGES property. A paper jam or other error occurred during the scan operation. | Other error code

This method is available in Windows Me and in Windows XP and later.

See Also

wiasGetImageInformation, IWiaMiniDrv::drvGetDeviceErrorStr, MINIDRV_TRANSFER_CONTEXT


IWiaMiniDrv::drvAnalyzeItem

The IWiaMiniDrv::drvAnalyzeItem method inspects an item, and creates subitems, if necessary.

HRESULT
  drvAnalyzeItem(
    IN BYTE  *pWiasContext,
    IN LONG  lFlags,
    IN LONG  *plDevErrVal
    );

Parameters

pWiasContext
Points to a WIA service context.
lFlags
Is currently unused.
plDevErrVal
Points to a memory location that will receive a status code for this method. If this method returns S_OK, the value stored will be zero. Otherwise, a minidriver-specific error code will be stored at the location pointed to by this parameter.

Return Value

On success, the method should return S_OK and clear the device error value pointed to by plDevErrVal. If the method is not fully implemented, it can return E_NOTIMPL. If the method fails, it should return a standard COM error code and place a minidriver-specific error code value in the memory pointed to by plDevErrVal.

The value pointed to by plDevErrVal can be converted to a string by calling IWiaMiniDrv::drvGetDeviceErrorStr.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

This method is available in Windows Me and in Windows XP and later.

See Also

IWiaMiniDrv::drvGetDeviceErrorStr


IWiaMiniDrv::drvDeleteItem

The IWiaMiniDrv::drvDeleteItem method deletes the current driver item.

HRESULT
  drvDeleteItem(
    IN BYTE  *pWiasContext,
    IN LONG  lFlags,
    OUT LONG  *plDevErrVal
    );

Parameters

pWiasContext
Points to a WIA service context.
lFlags
Is currently unused.
plDevErrVal
Points to a memory location that will receive a status code for this method. If this method returns S_OK, the value stored will be zero. Otherwise, a minidriver-specific error code will be stored at the location pointed to by this parameter.

Return Value

On success, the method should return S_OK and clear the device error value pointed to by plDevErrVal. If the method fails, it should return a standard COM error code and place a minidriver-specific error code value in the memory pointed to by plDevErrVal. The value pointed to by plDevErrVal can be converted to a string by calling IWiaMiniDrv::drvGetDeviceErrorStr.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

In order to delete a driver item, the WIA service will call the minidriver method IWiaMiniDrv::drvDeleteItem. In this method, the minidriver will attempt to delete the item pointed to by the WIA service context parameter pWiasContext. If the item is successfully deleted, the method returns S_OK and sets the device error value parameter plDevErrVal to zero. If a device error occurs, the method returns E_FAIL and a device-specific error value in the device error value parameter plDevErrVal.

Before the WIA service calls this method, it verifies the following:

  • The item is not the root item.
  • If the item is a folder, it does not have any children.
  • The item's access rights allow deletion.

Since the WIA service verifies these conditions, it is not necessary for the minidriver to also verify them.

This method is available in Windows Me and in Windows XP and later.

See Also

IWiaMiniDrv::drvGetDeviceErrorStr


IWiaMiniDrv::drvDeviceCommand

The IWiaMiniDrv::drvDeviceCommand method issues a command to a WIA device.

HRESULT
  drvDeviceCommand(
    IN BYTE  *pWiasContext,
    IN LONG  lFlags,
    IN const GUID  *plCommand,
    OUT IWiaDrvItem  **ppWiaDrvItem,
    OUT LONG  *plDevErrVal
    );

Parameters

pWiasContext
Points to a WIA service context.
lFlags
Is currently unused.
plCommand
Points to a WIA command GUID.
ppWiaDrvItem
Points to a memory location that can receive a pointer to an IWiaDrvItem interface. See Comments.
plDevErrVal
Points to a memory location that will receive a status code for this method. If this method returns S_OK, the value stored will be zero. Otherwise, a minidriver-specific error code will be stored at the location pointed to by this parameter.

Return Value

On success, the method should return S_OK and clear the device error value pointed to by plDevErrVal. If the method fails, it should return a standard COM error code and place a minidriver-specific error code value in the memory pointed to by plDevErrVal.

The value pointed to by plDevErrVal can be converted to a string by calling IWiaMiniDrv::drvGetDeviceErrorStr.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

The method IWiaMiniDrv::drvDeviceCommand is called by the WIA service to issue a WIA service or application generated command to the device. The WIA service only calls the IWiaMiniDrv::drvDeviceCommand method for a command that the device can support in the method IWiaMiniDrv::drvGetCapabilities.

The ppWiaDrvItem parameter should be considered to be optional, since the minidriver does not normally set the memory location it points to. For certain commands, however, the minidriver places the address of a newly created item in the location pointed to by this parameter. For example, if the command to take a picture is issued (plCommand is set to WIA_CMD_TAKE_PICTURE), the device produces a new image, causing the minidriver to create a new item in the driver item tree, and sets *ppWiaDrvItem to the address of the new item. This informs the WIA service that a new item was created.

For a list of WIA service device commands that can be issued to a minidriver see Issuing Commands to a Device.

The minidriver may include a list of custom commands the device can support in the method IWiaMiniDrv::drvGetCapabilities.

The WIA service does not write any properties before calling this method. If the command relies on property settings, the minidriver should call IWiaMiniDrv::drvWriteItemProperties before issuing the command. For example, the command to take a picture, WIA_CMD_TAKE_PICTURE, might rely on shutter speed and aperture settings, which need to be written to the device before the command is issued.

This method is available in Windows Me and in Windows XP and later.

See Also

IWiaMiniDrv::drvGetCapabilities, IWiaMiniDrv::drvWriteItemProperties


IWiaMiniDrv::drvFreeDrvItemContext

The IWiaMiniDrv::drvFreeDrvItemContext method frees a device-specific context.

HRESULT
  drvFreeDrvItemContext(
    IN LONG  lFlags,
    IN BYTE  *pSpecContext,
    OUT LONG  *plDevErrVal
    );

Parameters

lFlags
Is currently unused.
pSpecContext
Points to a device-specific context.
plDevErrVal
Points to a memory location that will receive a status code for this method. If this method returns S_OK, the value stored will be zero. Otherwise, a minidriver-specific error code will be stored at the location pointed to by this parameter.

Return Value

On success, the method should return S_OK and clear the device error value pointed to by plDevErrVal. If the method fails, it should return a standard COM error code and place a minidriver-specific error code in the memory pointed to by plDevErrVal.

The value pointed to by plDevErrVal can be converted to a string by calling IWiaMiniDrv::drvGetDeviceErrorStr.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

When a driver item is deleted, the WIA service frees the driver item context. This method informs the minidriver that the context is ready to be freed. The minidriver should free any memory that it allocated for the context. For example, in IWiaMiniDrv::drvReadItemProperties, a camera minidriver might allocate a cache to store the thumbnail for an item, and store a pointer to this cache in the driver item context. The minidriver would then free the cache in this method.

This method is available in Windows Me and in Windows XP and later.

See Also

IWiaMiniDrv::drvGetDeviceErrorStr, IWiaMiniDrv::drvReadItemProperties


IWiaMiniDrv::drvGetCapabilities

The IWiaMiniDrv::drvGetCapabilities method returns an array of events and commands that a device supports.

HRESULT
  drvGetCapabilities(
    IN BYTE  *pWiasContext,
    IN LONG  lFlags,
    OUT LONG  *pcelt,
    OUT WIA_DEV_CAP_DRV  **ppCapabilities,
    OUT LONG  *plDevErrVal
    );

Parameters

pWiasContext
Points to a WIA service context.
lFlags
Specifies whether the array pointed to by ppCapabilites consists of commands, or events, or both. This parameter can be either of the following flags or an ORed combination of both of them.
Flag | Meaning
WIA_DEVICE_COMMANDS | The array consists of device commands.
WIA_DEVICE_EVENTS | The array consists of device events.

pcelt
Points to a memory location that will receive the number of elements in the array pointed to by the ppCapabilities parameter.
ppCapabilities
Points to a memory location that will receive the address of the first element of an array of WIA_DEV_CAP_DRV structures that contain the GUIDs of events and commands that the device supports.
plDevErrVal
Points to a memory location that will receive a status code for this method. If this method returns S_OK, the value stored will be zero. Otherwise, a minidriver-specific error code will be stored at the location pointed to by this parameter.

Return Value

On success, the method should return S_OK and clear the device error value pointed to by plDevErrVal. If the method fails, it should return a standard COM error code and place a minidriver-specific error code value in the memory pointed to by plDevErrVal.

The value pointed to by plDevErrVal can be converted to a string by calling IWiaMiniDrv::drvGetDeviceErrorStr.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

The WIA service calls the minidriver method IWiaMiniDrv::drvGetCapabilities to obtain a list of hardware command capabilities and/or device events. In response to this call, a minidriver sets ppCapabilities with the address of an array of pointers to GUID data. Each GUID corresponds to an event notification or a device command supported by the imaging device. When the lFlags parameter is set to WIA_DEVICE_COMMANDS, the array of GUIDs contains device commands. When lFlags is set to WIA_DEVICE_EVENTS, the array of GUIDs contains events. If lFlags is set to WIA_DEVICE_COMMANDS | WIA_DEVICE_EVENTS, the array of GUIDs contains both events and commands, listed in that order.

The wiadef.h header lists several predefined commands and events.

This method is available in Windows Me and in Windows XP and later.

See Also

IWiaMiniDrv::drvGetDeviceErrorStr, WIA_DEV_CAP_DRV


IWiaMiniDrv::drvGetDeviceErrorStr

The IWiaMiniDrv::drvGetDeviceErrorStr method maps an error code to a UNICODE string that describes the error.

HRESULT
  drvGetDeviceErrorStr(
    IN LONG  lFlags,
    IN LONG  lDevErrVal,
    OUT LPOLESTR  *ppszDevErrStr,
    OUT LONG  *plDevErr
    );

Parameters

lFlags
Is currently unused.
lDevErrVal
Specifies the device error value to be mapped to a string. A value of zero indicates that no error occurred.
ppszDevErrStr
Points to a memory location that will receive the address of a string describing the error.
plDevErr
Points to a memory location that will receive a status code for this method. If this method returns S_OK, the value stored will be zero. Otherwise, a minidriver-specific error code will be stored at the location pointed to by this parameter.

Return Value

On success, the method should return S_OK and clear the device error value pointed to by plDevErrVal. If the minidriver does not fully implement this method, the method should return E_NOTIMPL. If the minidriver does not recognize the error value passed to this method, the method should return E_INVALIDARG. If the method fails, it should return a standard COM error code and place a minidriver-specific error code value in the memory pointed to by plDevErrVal.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

To obtain an error string that describes a device-specific minidriver-generated error value, the WIA service calls the IWiaMiniDrv::drvGetDeviceErrorStr method. In response to this call, the minidriver should use CoTaskMemAlloc (described in the Platform SDK documentation) to allocate memory that will contain a localized UNICODE string corresponding to the error code passed to the minidriver. The WIA service (or an application) will free the memory. It is likely that an application will display the string, so it should be meaningful to an end user. The string should be loaded from a resource file, so that it can be localized into a variety of languages.

This method is available in Windows Me and in Windows XP and later.


IWiaMiniDrv::drvGetWiaFormatInfo

The IWiaMiniDrv::drvGetWiaFormatInfo method finds the image formats and media types that the WIA hardware device supports.

HRESULT
  drvGetWiaFormatInfo(
    IN BYTE  *pWiasContext,
    IN LONG  lFlags,
    OUT LONG  *pcelt,
    OUT WIA_FORMAT_INFO  **ppwfi,
    OUT LONG  *plDevErrVal
    );

Parameters

pWiasContext
Points to a WIA service context.
lFlags
Is currently unused.
pcelt
Points to a memory location that will receive the number of items in the array pointed to by ppwfi.
ppwfi
Points to a memory location that will receive the address of the first element of an array of WIA_FORMAT_INFO structures (described in the Platform SDK documentation).
plDevErrVal
Points to a memory location that will receive a status code for this method. If this method returns S_OK, the value stored will be zero. Otherwise, a minidriver-specific error code will be stored at the location pointed to by this parameter.

Return Value

On success, the method should return S_OK and clear the device error value pointed to by plDevErrVal. If this method is called for items that do not contain any data, it should return E_INVALIDARG. If the method fails, it should return a standard COM error code and place a minidriver-specific error code value in the memory pointed to by plDevErrVal.

The value pointed to by plDevErrVal can be converted to a string by calling IWiaMiniDrv::drvGetDeviceErrorStr.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

This method creates an array of WIA_FORMAT_INFO structures (defined in the Platform SDK documentation) that describe the media types and image formats that the WIA hardware device supports. The values in this array will indicate the media types of TYMED_CALLBACK and TYMED_FILE (constants defined in the Platform SDK documentation) and the image formats such as WiaImgFmt_JPEG and WiaImgFmt_BMP (also defined in the Platform SDK documentation).

The minidriver can define a global array to hold the WIA_FORMAT_INFO structures, or it can allocate memory for the array. The WIA service will not free the allocated memory, so the minidriver should store a pointer to that memory in the driver item context. The minidriver can then free this memory in a call to IWiaMiniDrv::drvFreeDrvItemContext.

This method is available in Windows Me and in Windows XP and later.

See Also

IWiaMiniDrv::drvGetDeviceErrorStr, IWiaMiniDrv::drvFreeDrvItemContext


IWiaMiniDrv::drvInitializeWia

The IWiaMiniDrv::drvInitializeWia method initializes the minidriver and builds the driver item tree representing the device.

HRESULT
  drvInitializeWia(
    IN BYTE  *pWiasContext,
    IN LONG  lFlags,
    IN BSTR  bstrDeviceID,
    IN BSTR  bstrRootFullItemName,
    IN IUnknown  *pStiDevice,
    IN IUnknown  *pIUnknownOuter,
    OUT IWiaDrvItem  **ppIDrvItemRoot,
    OUT IUnknown  **ppIUnknownInner,
    OUT LONG  *plDevErrVal
    );

Parameters

pWiasContext
Points to a WIA service context.
lFlags
Is reserved. Set to zero.
bstrDeviceID
Specifies a string containing the device's unique identifier.
bstrRootFullItemName
Specifies a string containing the full name of the root item.
pStiDevice
Points to an IStiDevice interface.
pIUnknownOuter
(Optional) Points to a memory location that can receive the address of an IUnknown interface.
ppIDrvItemRoot
Points to a memory location that will receive the address of a IWiaDrvItem interface, the interface of the root item.
ppIUnknownInner
(Optional) Points to a memory location that can receive the address of an IUnknown interface. If the minidriver has functionality that is not accessible through the IWiaMiniDrv interface, the vendor can create a separate interface on the minidriver. This parameter provides access to that functionality.
plDevErrVal
Points to a memory location that will receive a status code for this method. If this method returns S_OK, the value stored will be zero. Otherwise, a minidriver-specific error code will be stored at the location pointed to by this parameter.

Return Value

On success, the method should return S_OK and clear the device error value pointed to by plDevErrVal. If the method fails, it should return a standard COM error code and place a minidriver-specific error code value in the memory pointed to by plDevErrVal.

The value pointed to by plDevErrVal can be converted to a string by calling IWiaMiniDrv::drvGetDeviceErrorStr.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

This method should initialize any private structures and create the driver item tree. For detailed information on the steps that minidrivers typically perform in this method, see Initializing the WIA Minidriver and Creating the WIA Driver Item Tree.

The WIA service calls the IWiaMiniDrv::drvInitializeWia method in response to a client's call to CreateDevice (described in the Platform SDK documentation), which means that this method is called once for each new client connection.

For example, if the user right-clicks a WIA scanner icon in My Computer, the shell calls CreateDevice, which generates a call to the minidriver's IWiaMiniDrv::drvInitializeWia method. If the user then runs the WIA Acquisition Wizard, it also calls CreateDevice. Each time that CreateDevice is called, there is a corresponding call to the IWiaMiniDrv::drvInitializeWia method on the minidriver.

This method is available in Windows Me and in Windows XP and later.

See Also

wiasCreateDrvItem, IWiaDrvItem::AddItemToFolder, IWiaMiniDrv::drvGetDeviceErrorStr, IWiaMiniDrv::drvUnInitializeWia


IWiaMiniDrv::drvInitItemProperties

The IWiaMiniDrv::drvInitItemProperties method initializes WIA driver item properties for each item in an application item tree.

HRESULT
  drvInitItemProperties(
    IN BYTE  *pWiasContext,
    IN LONG  lFlags,
    OUT LONG  *plDevErrVal
    );

Parameters

pWiasContext
Points to a WIA service context.
lFlags
Is reserved. Set to zero.
plDevErrVal
Points to a memory location that will receive a status code for this method. If this method returns S_OK, the value stored will be zero. Otherwise, a minidriver-specific error code will be stored at the location pointed to by this parameter.

Return Value

On success, the method should return S_OK and clear the device error value pointed to by plDevErrVal. If the method fails, it should return a standard COM error code and place a minidriver-specific error code value in the memory pointed to by plDevErrVal.

The value pointed to by plDevErrVal can be converted to a string by calling IWiaMiniDrv::drvGetDeviceErrorStr.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

For information on the steps that minidrivers typically perform during this method, see Initializing Item Properties.

The IWiaMiniDrv::drvInitItemProperties method is called once per application for each item in the item tree.

This method is available in Windows Me and in Windows XP and later.

See Also

wiasGetDrvItem, wiasSetItemPropNames, wiasWriteMultiple, wiasSetItemPropAttribs, IWiaMiniDrv::drvGetDeviceErrorStr


IWiaMiniDrv::drvLockWiaDevice

The IWiaMiniDrv::drvLockWiaDevice method locks the WIA hardware device so that only the current minidriver can access it.

HRESULT
  drvLockWiaDevice(
    IN BYTE  *pWiasContext,
    IN LONG  lFlags,
    OUT LONG  *plDevErrVal
    );

Parameters

pWiasContext
Points to a WIA service context.
lFlags
Is currently unused.
plDevErrVal
Points to a memory location that will receive a status code for this method. If this method returns S_OK, the value stored will be zero. Otherwise, a minidriver-specific error code will be stored at the location pointed to by this parameter.

Return Value

On success, the method should return S_OK and clear the device error value pointed to by plDevErrVal. If the method fails, it should return a standard COM error code and place a minidriver-specific error code value in the memory pointed to by plDevErrVal.

The value pointed to by plDevErrVal can be converted to a string by calling IWiaMiniDrv::drvGetDeviceErrorStr.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

The IWiaMiniDrv::drvLockWiaDevice method is used to lock access to the device. This is typically done before properties are written to the device or before a data transfer. The IWiaMiniDrv::drvLockWiaDevice method should be implemented using the IStiDevice interface's lock device method, IStiDevice::LockDevice.

This method is available in Windows Me and in Windows XP and later.

See Also

IWiaMiniDrv::drvUnLockWiaDevice, IWiaMiniDrv::drvGetDeviceErrorStr


IWiaMiniDrv::drvNotifyPnpEvent

The IWiaMiniDrv::drvNotifyPnpEvent method responds to the event received from the WIA service.

HRESULT
  drvNotifyPnpEvent(
    IN const GUID  *pEventGuid,
    IN BSTR  bstrDeviceID,
    IN ULONG  ulReserved
    );

Parameters

pEventGuid
Points to a GUID identifying the event.
bstrDeviceID
Specifies a string containing the device's unique identifier.
ulReserved
Is reserved for system use.

Return Value

On success, the method should return S_OK. If the method fails, it should return a standard COM error code.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

The WIA service notifies a WIA minidriver of a supported device event by calling the IWiaMiniDrv::drvNotifyPnpEvent method. In this method the minidriver implements the device-specific functionality needed to respond to the event.

If this method is called with *pEventGuid set to WIA_EVENT_CANCEL_IO device event (described in the Platform SDK documentation), it should cancel all current I/O operations as soon as possible.

This method is available in Windows Me and in Windows XP and later.

See Also

IWiaMiniDrv::drvGetCapabilities


IWiaMiniDrv::drvReadItemProperties

The IWiaMiniDrv::drvReadItemProperties method reads the driver item properties that need to be updated.

HRESULT
  drvReadItemProperties(
    IN BYTE  *pWiasContext,
    IN LONG  lFlags,
    IN ULONG  nPropSpec,
    IN const PROPSPEC *pPropSpec,
    OUT LONG  *plDevErrVal
    );

Parameters

pWiasContext
Points to a WIA service context.
lFlags
Is reserved. Set to zero.
nPropSpec
Indicates the number of items in the pPropSpec array.
pPropSpec
Points to the first element of an array of PROPSPEC structures (defined in the Platform SDK documentation).
plDevErrVal
Points to a memory location that will receive a status code for this method. If this method returns S_OK, the value stored will be zero. Otherwise, a minidriver-specific error code will be stored at the location pointed to by this parameter.

Return Value

On success, the method should return S_OK and clear the device error value pointed to by plDevErrVal. If the method fails, it should return a standard COM error code and place a minidriver-specific error code value in the memory pointed to by plDevErrVal.

The value pointed to by plDevErrVal can be converted to a string by calling IWiaMiniDrv::drvGetDeviceErrorStr.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

In this method, the minidriver should read the requested properties from the device. For more information about the steps that minidrivers typically perform during this method, see Reading Item Properties.

This method is available in Windows Me and in Windows XP and later.

See Also

wiasWritePropStr, wiasWritePropLong, wiasWritePropBin, wiasWritePropFloat, wiasWritePropGuid, wiasWriteMultiple, IWiaMiniDrv::drvGetDeviceErrorStr, IWiaMiniDrv::drvWriteItemProperties


IWiaMiniDrv::drvUnInitializeWia

The IWiaMiniDrv::drvUnInitializeWia method releases resources held by the minidriver.

HRESULT
  drvUnInitializeWia(
    IN BYTE  *pWiasContext
    );

Parameters

pWiasContext
Points to a WIA service context.

Return Value

On success, the method should return S_OK If the method fails, it should return a standard COM error code.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

The WIA service calls the IWiaMiniDrv::drvUnInitializeWia method when the resources associated with an application item tree are no longer needed. The minidriver can then unload any DLLs and free any allocated memory.

This method is available in Windows Me and in Windows XP and later.

See Also

IWiaMiniDrv::drvInitializeWia


IWiaMiniDrv::drvUnLockWiaDevice

The IWiaMiniDrv::drvUnLockWiaDevice method unlocks the WIA hardware device so that any minidriver can access it.

HRESULT
  drvUnLockWiaDevice(
    IN BYTE  *pWiasContext,
    IN LONG  lFlags,
    OUT LONG  *plDevErrVal
    );

Parameters

pWiasContext
Points to a WIA service context.
lFlags
Is currently unused.
plDevErrVal
Points to a memory location that will receive a status code for this method. If this method returns S_OK, the value stored will be zero. Otherwise, a minidriver-specific error code will be stored at the location pointed to by this parameter.

Return Value

On success, the method should return S_OK and clear the device error value pointed to by plDevErrVal. If the method fails, it should return a standard COM error code and place a minidriver-specific error code value in the memory pointed to by plDevErrVal.

The value pointed to by plDevErrVal can be converted to a string by calling IWiaMiniDrv::drvGetDeviceErrorStr.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

The method IWiaMiniDrv::drvUnLockWiaDevice is used to allow access to the device after the lock is no longer needed. It is typically called by the WIA service after properties are written to the device or after a data transfer.

The minidriver's implementation of the IWiaMiniDrv::drvUnLockWiaDevice method should use the STI unlock device method IStiDevice::UnLockDevice.

This method is available in Windows Me and in Windows XP and later.

See Also

IWiaMiniDrv::drvGetDeviceErrorStr, IWiaMiniDrv::drvLockWiaDevice


IWiaMiniDrv::drvValidateItemProperties

The IWiaMiniDrv::drvValidateItemProperties method validates an item's properties against the set of valid values for each property and will update those properties if necessary.

HRESULT
  drvValidateItemProperties(
    IN BYTE  *pWiasContext,
    IN LONG  lFlags,
    IN ULONG  nPropSpec,
    IN const PROPSPEC  *pPropSpec,
    OUT LONG  *plDevErrVal
    );

Parameters

pWiasContext
Points to a WIA service context.
lFlags
Is reserved. Set to zero.
nPropSpec
Indicates the number of items n the pPropSpec array.
pPropSpec
Points to the first element of an array of PROPSPEC structures (defined in the Platform SDK documentation).
plDevErrVal
Points to a memory location that will receive a status code for this method. If this method returns S_OK, the value stored will be zero. Otherwise, a minidriver-specific error code will be stored at the location pointed to by this parameter.

Return Value

On success, the method should return S_OK and clear the device error value pointed to by plDevErrVal. If the method fails, it should return a standard COM error code and place a minidriver-specific error code value in the memory pointed to by plDevErrVal.

The value pointed to by plDevErrVal can be converted to a string by calling IWiaMiniDrv::drvGetDeviceErrorStr.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

For more information on the WIA service and property validation, see Validating Item Properties.

This method is available in Windows Me and in Windows XP and later.

See Also

wiasGetItemType, wiasValidateItemProperties, IWiaMiniDrv::drvGetDeviceErrorStr


IWiaMiniDrv::drvWriteItemProperties

The IWiaMiniDrv::drvWriteItemProperties method writes driver item properties to a WIA hardware device.

HRESULT
  drvWriteItemProperties(
    IN BYTE  *pWiasContext,
    IN LONG  lFlags,
    IN PMINIDRV_TRANSFER_CONTEXT  pmdtc,
    OUT LONG  *plDevErrVal
    );

Parameters

pWiasContext
Points to a WIA service context.
lFlags
Is currently unused.
pmdtc
Points to a MINIDRV_TRANSFER_CONTEXT structure containing the device transfer context.
plDevErrVal
Points to a memory location that will receive a status code for this method. If this method returns S_OK, the value stored will be zero. Otherwise, a minidriver-specific error code will be stored at the location pointed to by this parameter.

Return Value

On success, the method should return S_OK and clear the device error value pointed to by plDevErrVal. If the method fails, it should return a standard COM error code and place a minidriver-specific error code value in the memory pointed to by plDevErrVal.

The value pointed to by plDevErrVal can be converted to a string by calling IWiaMiniDrv::drvGetDeviceErrorStr.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

For more information, see Writing Item Properties.

This method is available in Windows Me and in Windows XP and later.

See Also

wiasGetRootItem, wiasReadPropStr, wiasReadPropLong, wiasReadPropBin, wiasReadPropFloat, wiasReadPropGuid, wiasReadMultiple, IWiaMiniDrv::drvGetDeviceErrorStr, IWiaMiniDrv::drvReadItemProperties, MINIDRV_TRANSFER_CONTEXT


WIA Driver Services Library Functions

The Windows Image Acquisition (WIA) driver services library is a system-supplied component that provides helper functions for WIA minidrivers. A minidriver can call driver services library helper functions to perform tasks such as the following:

  • Creating a device item
  • Reading, writing and validating item properties
  • Transferring data

Function prototypes are defined in wiamdef.h.


wiasCreateChildAppItem

The wiasCreateChildAppItem function creates a new application item and inserts it as a child of the specified (parent) item. Note that this item will not have any properties in its property sets until the driver or application actually fills them in.

HRESULT
  wiasCreateChildAppItem(
    BYTE  *pParentWiasContext,
    LONG  lFlags,
    BSTR  bstrItemName,
    BSTR  bstrFullItemName,
    BYTE  **ppWiasChildContext
    );

Parameters

pParentWiasContext
Pointer to the item context to which the child will be added.
lFlags
Is reserved for system use.
bstrItemName
Specifies a string that contains the item name without path information.
bstrFullItemName
Specifies a string that contains the item name including path information.
ppWiasChildContext
Pointer to a memory location that receives the address of the newly created child item's context.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.

See Also

wiasCreateDrvItem


wiasCreateDrvItem

The wiasCreateDrvItem function creates an IWiaDrvItem object.

HRESULT
  wiasCreateDrvItem(
    LONG  lObjectFlags,
    BSTR  bstrItemName,
    BSTR  bstrFullItemName,
    IWiaMiniDrv  *pIMiniDrv,
    LONG  cbDevSpecContext,
    BYTE  **ppDevSpecContext,
    IWiaDrvItem  **ppIWiaDrvItem
    );

Parameters

lObjectFlags
Specifies the object item type, which must be WiaItemTypeFolder or WiaItemTypeFile (possibly the bitwise OR of these). These flags are described in the Platform SDK documentation.
bstrItemName
Specifies a string that contains the item name without path information.
bstrFullItemName
Specifies a string that contains the item name with path information.
pIMiniDrv
Pointer to the IWiaMiniDrv interface of the current minidriver.
cbDevSpecContext
Specifies the size in bytes of the device specific context.
ppDevSpecContext
Pointer to a memory location that receives the address of the device specific context. Set this to NULL if the information is not needed.
ppIWiaDrvItem
Pointer to a memory location that receives the address of an IWiaDrvItem interface for the newly created IWiaDrvItem object.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function creates and initializes an IWiaDrvItem object with the specified name and attributes. It also creates a context for the IWiaDrvItem object. Minidrivers typically use this function to build a tree of device items.

This function is available in Windows Me and in Windows XP and later.

See Also

wiasCreateChildAppItem


wiasCreateLogInstance

The wiasCreateLogInstance function creates an instance of a logging object.

HRESULT
  wiasCreateLogInstance(
    BYTE  *pModuleHandle,
    IWiaLogEx  **ppIWiaLogEx
    );

Parameters

pModuleHandle
Pointer to the module handle, which is used to filter output.
ppIWiaLogEx
Pointer to a memory location that receives the address of the logging interface.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.


wiasCreatePropContext

The wiasCreatePropContext function allocates a property context to indicate which of an item's properties are changing.

HRESULT
  wiasCreatePropContext(
    ULONG  cPropSpec,
    PROPSPEC  *pPropSpec,
    ULONG  cProps,
    PROPID  *pProps,
    WIA_PROPERTY_CONTEXT  *pContext
    );

Parameters

cPropSpec
Specifies the total number of PROPSPEC structures in the pPropSpec array.
pPropSpec
Pointer to the first element of an array of PROPSPEC structures identifying which properties are changing.
cProps
Specifies the number of property identifiers stored in this context.
pProps
Pointer to the first element of an array of property identifiers that indicate the properties to put into this property context.
pContext
Pointer to a WIA_PROPERTY_CONTEXT structure that contains a property context.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function allocates a property context and fills in its values. Entries in the property context are property identifiers of properties that either have dependents, or are themselves dependent on other properties. A context is used to mark which properties are being changed. The properties that are being written to by an application are specified by the pPropSpec array. This function is generally used in wiasValidateItemProperties where the properties written by the application are validated.

When the property context is no longer needed, it should be freed by a call to wiasFreePropContext.

The PROPSPEC structure is defined in the Platform SDK documentation.

This function is available in Windows Me and in Windows XP and later.

See Also

wiasValidateItemProperties, wiasFreePropContext, WIA_PROPERTY_CONTEXT


wiasDebugError

The wiasDebugError function prints a debug error string in the device manager debug console. The output color is always red.

VOID __cdecl
  wiasDebugError(
    HINSTANCE  hInstance,
    (LPCSTR  pszFormat, ...)
    );

Parameters

hInstance
Is the module handle of calling module.
pszFormat, ...
Specifies a variable argument list, which starts with an ANSI format string containing the message and any format specifiers. The ellipsis (...) specifies a variable number of arguments that are to be output.

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

WIA device driver writers should use the WIAS_LERROR macro, rather than this function.

This function is available in Windows Me and in Windows XP and later.

See Also

WIAS_LERROR


wiasDebugTrace

The wiasDebugTrace function prints a debug trace string in the device manager debug console.

VOID __cdecl
  wiasDebugTrace(
    HINSTANCE  hInstance,
    (LPCSTR  pszFormat, ...)
    );

Parameters

hInstance
Is the module handle of calling module.
pszFormat, ...
Specifies a variable argument list, which starts with an ANSI format string containing the message and any format specifiers. The ellipsis (...) specifies a variable number of arguments that are to be output.

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

WIA device driver writers should to use the WIAS_LTRACE macro, rather than this function.

This function is available in Windows Me and in Windows XP and later.

See Also

WIAS_LTRACE


wiasDownSampleBuffer

The wiasDownSampleBuffer function takes in a buffer of DWORD-aligned pixel data and downsamples it (produces image data of lower resolution) to the specified size and resolution.

HRESULT
  wiasDownSampleBuffer(
    LONG  lFlags,
    WIAS_DOWN_SAMPLE_INFO  *pInfo
    );

Parameters

lFlags
Specifies a set of flags that determine the behavior of this function. Currently, only the following flag is defined.
Flag | Meaning
WIAS_GET_DOWNSAMPLED_SIZE_ONLY | Do not copy the downsampled data to the destination buffer. Instead, set the following members of the WIAS_DOWN_SAMPLE_INFO structure: ulDownSampledHeight, ulDownSampleWidth, ulAlignedHeight, ulAlignedWidth.

pInfo
Pointer to the WIAS_DOWN_SAMPLE_INFO structure that contains all of the information needed for the downsampling operation.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

The wiasDownSampleBuffer function can be used in either of the following two ways:

  1. The caller specifies the downsampled (that is, output) width and height by setting the ulDownSampledWidth and ulDownSampledHeight members of the WIA_DOWN_SAMPLE_INFO structure.
  2. The caller sets the ulDownSampledWidth and ulDownSampledHeight members of the WIA_DOWN_SAMPLE_INFO structure to zero, indicating that the function should choose the output width and height.

    To see what output width and height values the function chooses, call this function with the lFlags parameter set to WIAS_GET_DOWNSAMPLED_SIZE_ONLY. On return, the ulDownSampledWidth and ulDownSampledHeight members are set to their new values. No downsampling is performed in this case.

The caller of this function is required to fill in the following members of the WIA_DOWN_SAMPLE_INFO structure:

  • ulOriginalWidth
  • ulOriginal Height
  • ulBitsPerPixel
  • ulXRes
  • ulYRes
  • pSrcBuffer

Note: This function expects ulBitsPerPixel to be 1, 8, or 24, corresponding to 1-, 8-, and 24-bit-per-pixel data.

The caller can also specify the size of the downsampled data, by filling in the following WIA_DOWN_SAMPLE_INFO structure members:

  • ulDownSampledWidth
  • ulDownSampledHeight

If the buffer that receives the downsampled data has already been allocated, the caller should fill in these WIA_DOWN_SAMPLE_INFO structure members:

  • ulDestBufSize
  • ulSrcBufSize
  • pDestBuffer

If the caller sets pDestBuffer to NULL, the destination buffer is allocated by the WIA service. On return from this function, pDestBuffer points to the destination buffer. The caller is responsible for freeing this memory when the operation is finished, and does this by calling CoTaskMemFree (described in the Platform SDK documentation) on the buffer.

This function is available in Windows Me and in Windows XP and later.

See Also

WIAS_DOWN_SAMPLE_INFO


wiasFormatArgs

The wiasFormatArgs function formats an argument list into a packaged string for logging.

BSTR __cdecl
  wiasFormatArgs(
    (LPCSTR lpszFormat, ...)
    );

Parameters

lpszFormat, ...
Specifies a variable argument list, which starts with an ANSI format string containing the message and any format specifiers. The ellipsis (...) specifies a variable number of arguments that follow the format string.

Return Value

This function returns a BSTR containing the format string, the arguments following the format string, and a format signature.

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.


wiasFreePropContext

The wiasFreePropContext function releases the memory occupied by a WIA_PROPERTY_CONTEXT structure.

HRESULT
  wiasFreePropContext(
    WIA_PROPERTY_CONTEXT  *pContext
    );

Parameters

pContext
Pointer to a WIA_PROPERTY_CONTEXT structure that contains a property context.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.

See Also

WIA_PROPERTY_CONTEXT, wiasCreatePropContext


wiasGetChangedValueFloat

The wiasGetChangedValueFloat function determines whether a property with a floating point value has been changed by an application.

HRESULT
  wiasGetChangedValueFloat(
    BYTE  *pWiasContext,
    WIA_PROPERTY_CONTEXT  *pContext,
    BOOL  bNoValidation,
    PROPID  propID,
    WIAS_CHANGED_VALUE_INFO  *pValInfo
    );

Parameters

pWiasContext
Pointer to a WIA service context.
pContext
Pointer to a WIA_PROPERTY_CONTEXT structure that contains the current property context.
bNoValidation
Indicates whether the property's current value should be validated against its set of valid values. If this parameter is set to TRUE, the function does not perform validation on the property. If it is FALSE, the function performs data validation.
propID
Specifies the property identifier of the property being tested.
pValInfo
Pointer to a WIAS_CHANGED_VALUE_INFO structure that contains the current and previous values of the property.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

Validation of the property should be done only after its values have been updated.

This function is available in Windows Me and in Windows XP and later.

See Also

wiasGetChangedValueGuid, wiasGetChangedValueLong, wiasGetChangedValueStr, WIA_PROPERTY_CONTEXT, WIAS_CHANGED_VALUE_INFO


wiasGetChangedValueGuid

The wiasGetChangedValueGuid function determines whether a property with a GUID value has been changed by an application.

HRESULT
  wiasGetChangedValueGuid(
    BYTE  *pWiasContext,
    WIA_PROPERTY_CONTEXT  *pContext,
    BOOL  bNoValidation,
    PROPID  propID,
    WIAS_CHANGED_VALUE_INFO  *pValInfo
    );

Parameters

pWiasContext
Pointer to a WIA service context.
pContext
Pointer to a WIA_PROPERTY_CONTEXT structure that contains the current property context.
bNoValidation
Indicates whether the property's current value should be validated against its set of valid values. If this parameter is set to TRUE, the function does not perform validation on the property. If it is FALSE, the function performs data validation.
propID
Specifies the property identifier of the property being tested.
pValInfo
Pointer to a WIAS_CHANGED_VALUE_INFO structure that contains the current and previous values of the property.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

Validation of the property should be done only after its values have been updated.

This function is available in Windows Me and in Windows XP and later.

See Also

wiasGetChangedValueFloat, wiasGetChangedValueLong, wiasGetChangedValueStr, WIA_PROPERTY_CONTEXT, WIAS_CHANGED_VALUE_INFO


wiasGetChangedValueLong

The wiasGetChangedValueLong function determines whether a property with a long integer value has been changed by an application.

HRESULT
  wiasGetChangedValueLong(
    BYTE  *pWiasContext,
    WIA_PROPERTY_CONTEXT  *pContext,
    BOOL  bNoValidation,
    PROPID  propID,
    WIAS_CHANGED_VALUE_INFO  *pValInfo
    );

Parameters

pWiasContext
Pointer to a WIA service context.
pContext
Pointer to a WIA_PROPERTY_CONTEXT structure that contains the current property context.
bNoValidation
Indicates whether the property's current value should be validated against its set of valid values. If this parameter is set to TRUE, the function does not perform validation on the property. If it is FALSE, the function performs data validation.
propID
Specifies the property identifier of the property being tested.
pValInfo
Pointer to a WIAS_CHANGED_VALUE_INFO structure that contains the current and previous values of the property.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

Validation of the property should be done only after its values have been updated.

This function is available in Windows Me and in Windows XP and later.

See Also

wiasGetChangedValueFloat, wiasGetChangedValueGuid, wiasGetChangedValueStr, WIA_PROPERTY_CONTEXT, WIAS_CHANGED_VALUE_INFO


wiasGetChangedValueStr

The wiasGetChangedValueStr function determines whether a property with a string value has been changed by an application.

HRESULT
  wiasGetChangedValueStr(
    BYTE  *pWiasContext,
    WIA_PROPERTY_CONTEXT  *pContext,
    BOOL  bNoValidation,
    PROPID  propID,
    WIAS_CHANGED_VALUE_INFO  *pValInfo
    );

Parameters

pWiasContext
Pointer to a WIA service context.
pContext
Pointer to a WIA_PROPERTY_CONTEXT structure that contains the current property context.
bNoValidation
Indicates whether the property's current value should be validated against its set of valid values. If this parameter is set to TRUE, the function does not perform validation on the property. If it is FALSE, the function performs data validation.
propID
Specifies the property identifier of the property being tested.
pValInfo
Pointer to a WIAS_CHANGED_VALUE_INFO structure that contains the current and previous values of the property.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

Validation of the property should be done only after its values have been updated.

This function is available in Windows Me and in Windows XP and later.

See Also

wiasGetChangedValueFloat, wiasGetChangedValueGuid, wiasGetChangedValueLong, WIA_PROPERTY_CONTEXT, WIAS_CHANGED_VALUE_INFO


wiasGetChildrenContexts

The wiasGetChildrenContexts function retrieves an array of item contexts belonging to the current item's children.

HRESULT
  wiasGetChildrenContexts(
    BYTE  *pParentContext,
    ULONG  *pulNumChildren,
    BYTE  ***pppChildren
    );

Parameters

pParentContext
Pointer to the parent item.
pulNumChildren
Pointer to a memory location that receives the number of children contexts.
pppChildren
Pointer to a memory location that points to an array whose elements are addresses of IWiaItem objects (described in the Platform SDK documentation). Each IWiaItem object represents one child context.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.


wiasGetContextFromName

The wiasGetContextFromName function retrieves the item context for an item name.

HRESULT
  wiasGetContextFromName(
    BYTE  *pWiasContext,
    LONG  lFlags,
    BSTR  bstrName,
    BYTE  **ppWiasContext
    );

Parameters

pWiasContext
Pointer to a WIA item context.
lFlags
Is a set of operational flags.
bstrName
Specifies the name of the context that is being searched for.
ppWiasContext
Pointer to a memory location that receives the address of the WIA item context.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function searches for item contexts whose WIA_IPA_FULL_ITEM_NAME property matches bstrName. Note that this property is different from WIA_IPA_ITEM_NAME, which does not contain path information.

This function should be used by minidrivers when they need to move from one application item context to another, given the item's name. The names of the application items come from their corresponding driver items, which the minidriver creates and names.

This function is available in Windows Me and in Windows XP and later.

See Also

wiasGetRootItem


wiasGetDrvItem

The wiasGetDrvItem function retrieves a driver item.

HRESULT
  wiasGetDrvItem(
    BYTE  *pWiasContext,
    IWiaDrvItem  **ppDrvItem
    );

Parameters

pWiasContext
Pointer to a WIA service context.
ppDrvItem
Pointer to a memory location that receives the address of an IWiaDrvItem interface.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.

See Also

wiasGetRootItem, wiasCreateDrvItem


wiasGetImageInformation

The wiasGetImageInformation function retrieves transfer context information from an item.

HRESULT
  wiasGetImageInformation(
    BYTE  *pWiasContext,
    LONG  lFlags,
    PMINIDRV_TRANSFER_CONTEXT  pmdtc
    );

Parameters

pWiasContext
Pointer to a WIA service context.
lFlags
Specifies operational flags. Currently, only the following flag is defined:
Flag | Meaning
WIA_INIT_CONTEXT | Initialize the MINIDRV_TRANSFER_CONTEXT structure.

pmdtc
Pointer to a MINIDRV_TRANSFER_CONTEXT structure. Upon return, this structure contains the requested image item information.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function uses a MINIDRV_TRANSFER_CONTEXT structure to calculate item image and item header sizes. In addition, it can optionally fill in an image header if the image format requires a data header. The header will be copied to the buffer if the pTransferBuffer member of the MINIDRV_TRANSFER_CONTEXT structure is not NULL. When using image formats (such as JPEG) that do not have a header, the header size in the lHeaderSize member of the MINIDRV_TRANSFER_CONTEXT structure is reported as zero.

For image formats where the actual final size of the image is not known until after data acquisition, as with multi-page TIFF and compressed formats, the lItemSize member of the MINIDRV_TRANSFER_CONTEXT structure is reported as zero. The lImageSize member is reported as the size, in bytes, of the uncompressed image in a single page.

If WIAS_INIT_CONTEXT is specified in the lFlags parameter, the MINIDRV_TRANSFER_CONTEXT structure pointed to by the pmdtc parameter is filled in with information derived from the item's image properties. This flag should be used when a minidriver has allocated a new context.

This function is available in Windows Me and in Windows XP and later.

See Also

MINIDRV_TRANSFER_CONTEXT


wiasGetItemType

The wiasGetItemType function indicates the item type.

HRESULT
  wiasGetItemType(
    BYTE  *pWiasContext,
    LONG  *plItemType
    );

Parameters

pWiasContext
Pointer to a WIA service context.
plItemType
Points to a memory location that receives a value indicating the type of the item. See the Platform SDK documentation for a list of the WIA item type flags.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.


wiasGetPropertyAttributes

The wiasGetPropertyAttributes function retrieves the access flags and valid values for a set of properties.

HRESULT
  wiasGetPropertyAttributes(
    BYTE  *pWiasContext,
    LONG  cPropSpec,
    PROPSPEC  *pPropSpec,
    ULONG  *pulAccessFlags,
    PROPVARIANT  *pPropVar
    );

Parameters

pWiasContext
Pointer to a WIA service context.
cPropSpec
Specifies the number of properties.
pPropSpec
Pointer to a PROPSPEC structure (defined in the Platform SDK documentation) indicating the properties for which to get valid values and access flags.
pulAccessFlags
Pointer to an array that contains the access flags for the properties.
pPropVar
Pointer to an array of PROPVARIANT structures (defined in the Platform SDK documentation) that contains the valid values for the properties.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function fills each element of the pPropVar array with a PROPVARIANT structure that specifies the valid values for the corresponding property. Properties with the access rights flag WIA_PROP_NONE have no valid values for that property. The data type for the valid values of these properties is VT_EMPTY.

One or more of the WIA_PROP_Xxx property attributes and access flags can be returned in each element of the pulAccessFlags array. The property attribute constants are described in the Platform SDK documentation.

If the property has a range of valid values, the values can be determined through the pPropVar parameter upon completion of this function. The pPropVar parameter specifies an array of PROPVARIANT structures.

Valid integer and floating point values in a range are accessed using the following index constants:

Valid Value Index | Description
WIA_RANGE_MIN | Minimum value
WIA_RANGE_NOM | Nominal value
WIA_RANGE_MAX | Maximum value
WIA_RANGE_STEP | Increment value

Valid list values are accessed using the following index constants:

Valid Value Index | Description
WIA_LIST_COUNT | Count of valid list values, not counting the nominal value
WIA_LIST_NOM | Nominal value
WIA_LIST_VALUES | Index to first valid value

Valid bitwise flag values are accessed using the following index constants:

Valid Value Index | Description
WIA_FLAG_NOM | Nominal value
WIA_FLAG_VALUE | All valid flags are ORed together

The PROPSPEC and PROPVARIANT structures are defined in the Platform SDK documentation.

This function is available in Windows Me and in Windows XP and later.


wiasGetRootItem

The wiasGetRootItem function retrieves the root item context of a specified WIA item.

HRESULT
  wiasGetRootItem(
    BYTE  *pWiasContext,
    BYTE  **ppWiasContext
    );

Parameters

pWiasContext
Pointer to the context of the WIA item.
ppWiasContext
Pointer to a memory location that receives the address of the WIA item's root item context.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.

See Also

wiasGetDrvItem


wiasIsPropChanged

The wiasIsPropChanged function tests whether a specified property has been changed by an application.

HRESULT
  wiasIsPropChanged(
    PROPID  props,
    WIA_PROPERTY_CONTEXT  *pContext,
    BOOL  *pbChanged
    );

Parameters

props
Specifies the property identifier of the property to be checked.
pContext
Pointer to a WIA_PROPERTY_CONTEXT structure that contains the current property context.
pbChanged
Pointer to a memory location that receives a BOOL value. The BOOL value is TRUE if the property changed, and FALSE if the property did not change.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function determines whether a property is being changed by looking at the bChanged member value in the property's WIA_PROPERTY_CONTEXT structure. Minidrivers typically use this function to check when an independent property has been changed so that its dependents can be updated.

This function is available in Windows Me and in Windows XP and later.

See Also

WIA_PROPERTY_CONTEXT, wiasGetChangedValueFloat, wiasGetChangedValueGuid, wiasGetChangedValueLong, wiasGetChangedValueStr


wiasParseEndorserString

The wiasParseEndorserString function parses an endorser string, replacing WIA service-defined and vendor-defined tokens in the string with values associated with those tokens.

HRESULT
  wiasParseEndorserString(
    BYTE  *pWiasContext,
    LONG  lFlags,
    WIAS_ENDORSER_INFO  *pInfo,
    BSTR  *pOutputString
    );

Parameters

pWiasContext
Pointer to the context of the item containing the WIA_DPS_ENDORSER_STRING property (described in the Platform SDK documentation).
lFlags
Specifies a set of operational flags.
pInfo
Pointer to a WIAS_ENDORSER_INFO structure containing the page count and a list of custom token/value pairs. Can be NULL.
pOutputString
Pointer to a memory location that receives the address of the parsed endorser string. If *pOutputString is nonNULL on entry, then the function assumes that the caller allocated the buffer; otherwise the WIA service will allocate it. Note that the WIA service assumes the maximum resultant endorser string is MAX_PATH (defined in stdlib.h) characters long. If the driver expects the string to be longer, it should allocate the buffer itself. If the caller allocates the buffer, it must initialize the contents of the buffer to zero before using this function.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

An application sets the WIA_DPS_ENDORSER_STRING property to a string that can contain the WIA service-defined tokens $DATE$, $TIME$, $PAGE_COUNT$, $DAY$, $MONTH$, and $YEAR$, as well as vendor-defined tokens. After a driver calls wiasParseEndorserString, the string pointed to by pOutputString contains a copy of the string in WIA_DPS_ENDORSER_STRING property, but with any tokens replaced by the values the tokens represent. For example, if the application set the endorser string to "This page was scanned on $DATE$", and the current date was October 1, 2000, the resulting output string would be "This page was scanned on 2000/10/1".

The list of standard WIA endorser tokens can be found in wiadef.h.

Drivers can request that wiasParseEndorserString substitute values for vendor-defined tokens by filling out a WIAS_ENDORSER_VALUE structure for each token/value pair, and packaging all of these structures in a WIAS_ENDORSER_INFO structure. The following example shows how this function can be used.

HRESULT hr  = S_OK;
BSTR  bstrResultingEndorser   = NULL;
WIAS_ENDORSER_VALUE  aMyTokens[] = {L"$MY_TOKEN$", L"My value"};
WIAS_ENDORSER_INFO  Info     = {0, 1, aMyTokens};
hr = wiasParseEndorserString(pWiasContext, 0,
                             &Info, &bstrResultingEndorser);

Assuming that the WIA_DPS_ENDORSER_STRING property contains "This is $MY_TOKEN$", and that the call to wiasParseEndorserString was successful, bstrResultingEndorser will now contain "This is My value".

This function is available in Windows Me and in Windows XP and later.

See Also

WIAS_ENDORSER_INFO, WIAS_ENDORSER_VALUE


wiasPrintDebugHResult

The wiasPrintDebugHResult function prints an HRESULT string on the device manager debug console.

VOID __stdcall
  wiasPrintDebugHResult(
    HINSTANCE hInstance,
    HRESULT hr
    );

Parameters

hInstance
Is the module handle of the calling module.
hr
Specifies the HRESULT to be printed.

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

WIA driver writers should to use the WIAS_LHRESULT macro, rather than this function.

This function is available in Windows Me and in Windows XP and later.

See Also

WIAS_LHRESULT


wiasQueueEvent

The wiasQueueEvent function informs the service that the device generated an event.

HRESULT
  wiasQueueEvent(
    BSTR  bstrDeviceId,
    const GUID  *pEventGUID,
    BSTR  bstrFullItemName
    );

Parameters

bstrDeviceId
Specifies the device ID. This is the value passed to the minidriver in the call to the IWiaMiniDrv::drvInitializeWia method.
pEventGUID
Pointer to a buffer that contains the GUID for the event.
bstrFullItemName
Specifies the full item name, including path information.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This method should be used whenever the device must signal that an event of some type occurred. The device does this by placing the event on the event queue. For example, when a camera takes a new picture, it should generate a WIA_EVENT_ITEM_CREATED event after adding a new driver item to its tree. The camera can place this event on the event queue in this way:

hr = wiasQueueEvent(bstrMyDeviceId,
                    &WIA_EVENT_ITEM_CREATED,
                    bstrDescriptionString);

See the Platform SDK documentation for a complete list of WIA event identifiers.

This function is available in Windows Me and in Windows XP and later.

See Also

IWiaMiniDrv::drvInitializeWia


wiasReadPropBin

The wiasReadPropBin function retrieves a binary-data property value from a WIA item.

HRESULT
  wiasReadPropBin(
    BYTE  *pWiasContext,
    PROPID  propid,
    BYTE  **ppbVal,
    BYTE  **ppbValOld,
    BOOL  bMustExist
    );

Parameters

pWiasContext
Pointer to a WIA service context.
propid
Specifies the property identifier.
ppbVal
Pointer to a memory location that receives the address of a buffer allocated by this function. Upon return, the buffer contains the property's binary data.
ppbValOld
Pointer to a memory location that receives the address of a buffer allocated by the minidriver. Upon return, the buffer contains the previous value of the property's binary data. If this information is not needed, this parameter can be set to NULL.
bMustExist
Indicates whether the property must exist. If set to TRUE, the property must exist; if set to FALSE, the property does not have to exist.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function allocates a buffer and stores its address in the ppbVal parameter. The minidriver must free the buffer by calling CoTaskMemFree (described in the Platform SDK documentation).

This function is available in Windows Me and in Windows XP and later.

See Also

wiasReadPropFloat, wiasReadPropGuid, wiasReadPropLong, wiasReadPropStr, wiasWritePropBin


wiasReadPropFloat

The wiasReadPropFloat function retrieves a floating point property value from a WIA item.

HRESULT
  wiasReadPropFloat(
    BYTE  *pWiasContext,
    PROPID  propid,
    FLOAT  *pfVal,
    FLOAT  *pfValOld,
    BOOL  bMustExist
    );

Parameters

pWiasContext
Pointer to a WIA service context.
propid
Specifies the property identifier.
pfVal
Pointer to a memory location that receives the floating point value of the property.
pfValOld
Pointer to a memory location that receives the former floating point value of the property. If this information is not needed, set this parameter to NULL.
bMustExist
Indicates whether the property must exist. If set to TRUE, the property must exist; if set to FALSE, it does not have to exist.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.

See Also

wiasReadPropBin, wiasReadPropGuid, wiasReadPropLong, wiasReadPropStr, wiasWritePropFloat


wiasReadPropGuid

The wiasReadPropGuid function retrieves a GUID property value from a WIA item.

HRESULT
  wiasReadPropGuid(
    BYTE  *pWiasContext,
    PROPID  propid,
    GUID  *pgVal,
    GUID  *pgValOld,
    BOOL  bMustExist
    );

Parameters

pWiasContext
Pointer to a WIA service context.
propid
Specifies the property identifier.
pgVal
Pointer to a memory location that receives the GUID property value.
pgValOld
Pointer to a memory location that receives the previous value of the GUID property data. If this information is not needed, this parameter can be set to NULL.
bMustExist
Indicates whether the property must exist. If set to TRUE, the property must exist; if set to FALSE, the property does not have to exist.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.

See Also

wiasReadPropBin, wiasReadPropFloat, wiasReadPropLong, wiasReadPropStr, wiasWritePropGuid


wiasReadPropLong

The wiasReadPropLong function retrieves a long integer property value from a WIA item.

HRESULT
  wiasReadPropLong(
    BYTE  *pWiasContext,
    PROPID  propid,
    LONG  *plVal,
    LONG  *plValOld,
    BOOL  bMustExist
    );

Parameters

pWiasContext
Pointer to a WIA service context.
propid
Specifies the property identifier.
plVal
Pointer to a memory location that receives the value of the property.
plValOld
Pointer to a memory location that receives the property's previous value. If this information is not needed, set this parameter to NULL.
bMustExist
Indicates whether the property must exist. If set to TRUE, the property must exist, if set to FALSE, the property does not have to exist.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.

See Also

wiasReadPropBin, wiasReadPropFloat, wiasReadPropGuid, wiasReadPropStr, wiasWritePropLong


wiasReadPropStr

The wiasReadPropStr function retrieves a string property value from a WIA item.

HRESULT
  wiasReadPropStr(
    BYTE  *pWiasContext,
    PROPID  propid,
    BSTR  *pbstr,
    BSTR  *pbstrOld,
    BOOL  bMustExist
    );

Parameters

pWiasContext
Pointer to a WIA service context.
propid
Specifies the property identifier.
pbstr
Pointer to a memory location that receives the first byte of the property's string value.
pbstrOld
Pointer to a memory location that receives the first byte of the property's previous value. If this information is not needed, set this parameter to NULL.
bMustExist
Indicates whether the property must exist. If set to TRUE, the property must exist; if set to FALSE, the property does not have to exist.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

When the minidriver has completed using the string it received from this function, it must deallocate the memory used for the string.

This function is available in Windows Me and in Windows XP and later.

See Also

wiasReadPropBin, wiasReadPropFloat, wiasReadPropGuid, wiasReadPropLong, wiasWritePropStr


wiasSendEndOfPage

The wiasSendEndOfPage function calls the client callback routine during a data transfer, sending the current total page count.

HRESULT
  wiasSendEndOfPage(
    BYTE  *pWiasContext,
    LONG  lPageCount,
    PMINIDRV_TRANSFER_CONTEXT  pmdtc
    );

Parameters

pWiasContext
Pointer to a WIA service context.
lPageCount
Specifies the total page count.
pmdtc
Pointer to a MINIDRV_TRANSFER_CONTEXT structure.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.

See Also

MINIDRV_TRANSFER_CONTEXT


wiasSetItemPropAttribs

The wiasSetItemPropAttribs function sets the access flags and valid values for an item's set of properties.

HRESULT
  wiasSetItemPropAttribs(
    BYTE  *pWiasContext,
    LONG  cPropSpec,
    PROPSPEC  *pPropSpec,
    PWIA_PROPERTY_INFO  pwpi
    );

Parameters

pWiasContext
Pointer to a WIA service context.
cPropSpec
Specifies the number of properties.
pPropSpec
Pointer to the first element of an array of PROPSPEC structures (defined in the Platform SDK documentation) indicating the properties for which to set valid values and access flags.
pwpi
Pointer to the first element of an array of WIA_PROPERTY_INFO structures that contain the property values to be written.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

Minidrivers should use this function to initialize groups of simple properties. The groups of properties can be bitsets, ranges of values, or lists of values. The supported simple types, grouped by attribute are:

Attributes | Supported Types
WIA_PROP_FLAG | VT_UI1, VT_UI2, VT_UI4, VT_UI8, VT_I1, VT_I2, VT_I4, VT_I8
WIA_PROP_RANGE | VT_UI1, VT_UI2, VT_UI4, VT_UI8, VT_I1, VT_I2, VT_I4, ,VT_I8, VT_R4, VT_R8
WIA_PROP_LIST | VT_UI1, VT_UI2, VT_UI4, VT_UI8, VT_I1, VT_I2, VT_I4, ,VT_I8, VT_R4, VT_R8, VT_BSTR

Minidrivers should initialize complex properties using the wiasSetPropertyAttributes function.

The minidriver can set the WIA_PROP_CACHEABLE flag on a property that does not change over time. By setting this flag on a property, the minidriver indicates that the WIA service can cache the property value. See the Platform SDK documentation for a list of all property attributes.

This function is available in Windows Me and in Windows XP and later.

See Also

wiasSetPropertyAttributes, wiasSetItemPropNames, WIA_PROPERTY_INFO


wiasSetItemPropNames

The wiasSetItemPropNames function writes property names to item properties.

HRESULT
  wiasSetItemPropNames(
    BYTE  *pWiasContext,
    LONG  cItemProps,
    PROPID  *ppId,
    LPOLESTR  *ppSzNames
    );

Parameters

pWiasContext
Pointer to a WIA service context.
cItemProps
Specifies the number of property names to write.
ppId
Pointer to the first element of a caller-allocated array of property identifiers (PROPIDs).
ppSzNames
Pointer to the first element of a caller-allocated array of property names to write.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

Minidrivers typically use this function when initializing item properties. The order of property identifiers in ppId must match the order of property names in ppSzNames.

This function is available in Windows Me and in Windows XP and later.

See Also

wiasSetItemPropAttribs


wiasSetPropChanged

The wiasSetPropChanged function modifies a property context to indicate that a property is being changed.

HRESULT
  wiasSetPropChanged(
    PROPID  propid,
    WIA_PROPERTY_CONTEXT  *pContext,
    BOOL  bChanged
    );

Parameters

propid
Specifies the property identifier of the property being changed.
pContext
Pointer to a WIA_PROPERTY_CONTEXT structure that contains the current property context.
bChanged
Specifies the BOOL value that is used to set a particular element in the array pointed to by the pChanged member of a WIA_PROPERTY_CONTEXT structure. See the Comments section for more details.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

The pChanged member of the WIA_PROPERTY_CONTEXT structure points to an array of BOOL values that indicate whether a particular property will be changed. This function sets one element in that array for the specified property in the property context. This function should be used whenever a driver changes a property that has dependent properties in validation. For example, by changing "Current Intent", the "Horizontal Resolution" is changed and should be marked as changed, so that validation of XResolution and its dependents still takes place.

This function is available in Windows Me and in Windows XP and later.

See Also

WIA_PROPERTY_CONTEXT, wiasIsPropChanged


wiasSetPropertyAttributes

The wiasSetPropertyAttributes function sets the access flags and valid values for a set of properties.

HRESULT
  wiasSetPropertyAttributes(
    BYTE  *pWiasContext,
    LONG  cPropSpec,
    PROPSPEC  *pPropSpec,
    ULONG  *pulAccessFlags,
    PROPVARIANT  *pPropVar
    );

Parameters

pWiasContext
Pointer to a WIA service context.
cPropSpec
Specifies the number of properties.
pPropSpec
Pointer to a PROPSPEC structure indicating the properties for which to set valid values and access flags.
pulAccessFlags
Pointer to an array that contains the access flags to be written.
pPropVar
Pointer to an array of PROPVARIANT structures that contains the valid values to be written.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

Minidrivers should use the function wiasSetItemPropAttribs to initialize groups of simple properties.

The minidriver can set the WIA_PROP_CACHEABLE flag on a property that does not change over time. By setting this flag on a property, the minidriver indicates that the WIA service can cache the property value. See the Platform SDK documentation for a list of all property attributes.

The PROPSPEC and PROPVARIANT structures are defined in the Platform SDK documentation.

This function is available in Windows Me and in Windows XP and later.

See Also

wiasSetItemPropAttribs


wiasSetValidFlag

The wiasSetValidFlag function sets the valid values for a WIA_PROP_FLAG property.

HRESULT
  wiasSetValidFlag(
    BYTE  *pWiasContext,
    PROPID  propid,
    ULONG  ulNom,
    ULONG  ulValidBits
    );

Parameters

pWiasContext
Pointer to a WIA service context.
propid
Specifies the identifier of the property to be updated.
ulNom
Specifies the property's nominal value.
ulValidBits
Specifies the valid bits that can be used for the WIA_PROP_FLAG property.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.

See Also

wiasSetValidListFloat, wiasSetValidListGuid, wiasSetValidListLong, wiasSetValidListStr, wiasSetValidRangeFloat, wiasSetValidRangeLong


wiasSetValidListFloat

The wiasSetValidListFloat function sets valid values for a WIA_PROP_LIST property of type VT_R4.

HRESULT
  wiasSetValidListLong(
    BYTE  *pWiasContext,
    PROPID  propid,
    ULONG  ulCount,
    FLOAT  fNom,
    FLOAT  *pfValues
    );

Parameters

pWiasContext
Pointer to a WIA service context.
propid
Specifies the identifier of the property to be updated.
ulCount
Specifies the number of items in the plValues array.
fNom
Specifies the property's nominal value.
pfValues
Pointer to the first element of an array of valid property values.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.

See Also

wiasSetValidListGuid, wiasSetValidListLong, wiasSetValidListStr, wiasSetValidFlag, wiasSetValidRangeFloat, wiasSetValidRangeLong


wiasSetValidListGuid

The wiasSetValidListGuid function sets valid values for a WIA_PROP_LIST property of type VT_CLSID.

HRESULT
  wiasSetValidListGuid(
    BYTE  *pWiasContext,
    PROPID  propid,
    ULONG  ulCount,
    GUID  gNom,
    GUID  *pgValues
    );

Parameters

pWiasContext
Pointer to a WIA service context.
propid
Specifies the identifier of the property to be updated.
ulCount
Specifies the number of items in the pgValues array.
gNom
Specifies the property's nominal value.
pgValues
Pointer to the first element of an array of valid property values.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.

See Also

wiasSetValidListFloat, wiasSetValidListLong, wiasSetValidListStr, wiasSetValidFlag, wiasSetValidRangeFloat, wiasSetValidRangeLong


wiasSetValidListLong

The wiasSetValidListLong function sets the valid values for a WIA_PROP_LIST property of type VT_I4

HRESULT
  wiasSetValidListLong(
    BYTE  *pWiasContext,
    PROPID  propid,
    ULONG  ulCount,
    LONG  lNom,
    LONG  *plValues
    );

Parameters

pWiasContext
Pointer to a WIA service context.
propid
Specifies the identifier of the property to be updated.
ulCount
Specifies the number of items in the plValues array.
lNom
Specifies the property's nominal value.
plValues
Pointer to the first element of an array of valid property values.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.

See Also

wiasSetValidListFloat, wiasSetValidListGuid, wiasSetValidListStr, wiasSetValidFlag, wiasSetValidRangeFloat, wiasSetValidRangeLong


wiasSetValidListStr

The wiasSetValidListStr function sets the valid values for a WIA_PROP_LIST property of type VT_BSTR.

HRESULT
  wiasSetValidListStr(
    BYTE  *pWiasContext,
    PROPID  propid,
    ULONG  ulCount,
    BSTR  bstrNom,
    BSTR  *pbstrValues
    );

Parameters

pWiasContext
Pointer to a WIA service context.
propid
Specifies the identifier of the property to be updated.
ulCount
Specifies the number of items in the pbstrValues array.
bstrNom
Specifies the nominal value of the property.
pbstrValues
Pointer to the first element of an array of valid property values.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.

See Also

wiasSetValidListFloat, wiasSetValidListGuid, wiasSetValidListLong, wiasSetValidFlag, wiasSetValidRangeFloat, wiasSetValidRangeLong


wiasSetValidRangeFloat

The wiasSetValidRangeFloat function specifies the range of valid values for a WIA_PROP_RANGE property of type VT_R4.

HRESULT
  wiasSetValidRangeFloat(
    BYTE  *pWiasContext,
    PROPID  propid,
    FLOAT  fMin,
    FLOAT  fNom,
    FLOAT  fMax,
    FLOAT  fStep
    );

Parameters

pWiasContext
Pointer to a WIA service context.
propid
Specifies the identifier of the property to be updated.
fMin
Specifies the minimum value of the valid range.
fNom
Specifies the property's nominal value.
fMax
Specifies the maximum value of the valid range.
fStep
Specifies the increment between each valid value in the range.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.

See Also

wiasSetValidListFloat, wiasSetValidListGuid, wiasSetValidListLong, wiasSetValidListStr, wiasSetValidFlag, wiasSetValidRangeLong


wiasSetValidRangeLong

The wiasSetValidRangeLong function specifies the range of valid values for a WIA_PROP_RANGE property of type VT_I4.

HRESULT
  wiasSetValidRangeLong(
    BYTE  *pWiasContext,
    PROPID  propid,
    LONG  lMin,
    LONG  lNom,
    LONG  lMax,
    LONG  lStep
    );

Parameters

pWiasContext
Pointer to a WIA service context.
propid
Specifies the identifier of the property to be updated.
lMin
Specifies the minimum value of the valid range.
lNom
Specifies the property's nominal value.
lMax
Specifies the maximum value of the valid range.
lStep
Specifies the increment between each valid value in the range.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.

See Also

wiasSetValidListFloat, wiasSetValidListGuid, wiasSetValidListLong, wiasSetValidListStr, wiasSetValidFlag, wiasSetValidRangeFloat


wiasUpdateValidFormat

The wiasUpdateValidFormat function updates the valid format of the property context for the current minidriver.

HRESULT
  wiasUpdateValidFormat(
    BYTE  *pWiasContext,
    WIA_PROPERTY_CONTEXT  *pContext
    IWiaMiniDrv  *pIMiniDrv
    );

Parameters

pWiasContext
Pointer to a WIA service context.
pContext
Pointer to a WIA_PROPERTY_CONTEXT structure containing a property context.
pIMiniDrv
Pointer to the IWiaMiniDrv interface of the current minidriver.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.

See Also

WIA_PROPERTY_CONTEXT


wiasUpdateScanRect

The wiasUpdateScanRect function updates the scanning area sizes of the scanning device.

HRESULT
  wiasUpdateScanRect(
    BYTE  *pWiasContext,
    WIA_PROPERTY_CONTEXT  *pContext,
    LONG  lWidth,
    LONG  lHeight
    );

Parameters

pWiasContext
Pointer to a WIA service context.
pContext
Pointer to a WIA_PROPERTY_CONTEXT structure containing the property context, created by a prior call to wiasCreatePropContext.
lWidth
Specifies the horizontal width of the scanning area of the scanning device, in units of thousandths of an inch. Normally, this is the horizontal bed size.
lHeight
Specifies the vertical height of the scanning area of the scanning device, in units of thousandths of an inch. Normally, this is the vertical bed size.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This helper method is called to update the properties making up the scan rectangle. The appropriate changes are made to the properties that are dependent on those that make up the scan rectangle. For example, a change in horizontal resolution affects the horizontal extent. This function assumes that the valid values for the vertical and horizontal extents, and vertical and horizontal positions have not yet been updated.

This function is available in Windows Me and in Windows XP and later.

See Also

WIA_PROPERTY_CONTEXT, wiasCreatePropContext


wiasValidateItemProperties

The wiasValidateItemProperties function validates a list of simple item properties against their current valid values.

HRESULT
  wiasValidateItemProperties(
    BYTE  *pWiasContext,
    ULONG  nPropSpec,
    const PROPSPEC  *pPropSpec
    );

Parameters

pWiasContext
Pointer to a WIA service context.
nPropSpec
Specifies the number of properties to validate.
pPropSpec
Pointer to the first element of an array of PROPSPEC structures indicating the properties to validate.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function validates simple property values of the following types grouped by attribute:

Attributes | Supported Types
WIA_PROP_FLAG | VT_UI1, VT_UI2, VT_UI4, VT_UI8, VT_I1, VT_I2, VT_I4
WIA_PROP_RANGE | VT_UI1, VT_UI2, VT_UI4, VT_UI8, VT_I1, VT_I2, VT_I4, VT_R4, VT_R8
WIA_PROP_LIST | VT_UI1, VT_UI2, VT_UI4, VT_UI8, VT_I1, VT_I2, VT_I4, VT_R4, VT_R8, VT_BSTR

The PROPSPEC structure is defined in the Platform SDK documentation.

This function is available in Windows Me and in Windows XP and later.


wiasWriteMultiple

The wiasWriteMultiple function writes multiple property values to a WIA item.

HRESULT
  wiasWriteMultiple(
    BYTE  *pWiasContext,
    ULONG  ulCount,
    const PROPSPEC  *ps,
    const PROPVARIANT  *pv
    );

Parameters

pWiasContext
Pointer to a WIA service context.
ulCount
Specifies the total number of properties to write.
ps
Pointer to the first element of an array of PROPSPEC structures that indicate the properties to write.
pv
Pointer to the first element of an array of PROPVARIANT structures that contain the values to write to the item.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function operates in a similar manner to IPropertyStorage::WriteMultiple, which is described in the Platform SDK documentation. The PROPSPEC and PROPVARIANT structures are also described in the Platform SDK documentation.

This function is available in Windows Me and in Windows XP and later.

See Also

wiasReadMultiple


wiasWriteBufToFile

The wiasWriteBufToFile function writes from a specified buffer to an image file.

HRESULT
  wiasWriteBufToFile(
    LONG  lFlags,
    PMINIDRV_TRANSFER_CONTEXT  pmdtc
    );

Parameters

lFlags
Specifies a set of operation flags. This parameter should be set to 0.
pmdtc
Pointer to a MINIDRV_TRANSFER_CONTEXT structure.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

A WIA minidriver uses this function to write a buffer to any type of image file. A driver that intends to write a page of purely image data to a multipage TIFF file, delegating the addition of the appropriate tags, image file directory (IFD) entries, and other non-image data to the WIA service, should use wiasWritePageBufToFile.

This function is available in Windows Me and in Windows XP and later.

See Also

MINIDRV_TRANSFER_CONTEXT, wiasWritePageBufToFile


wiasWritePageBufToFile

The wiasWritePageBufToFile function writes the contents of a temporary page buffer to an image file.

HRESULT
  wiasWritePageBufToFile(
    PMINIDRV_TRANSFER_CONTEXT  pmdtc
    );

Parameters

pmdtc
Pointer to a MINIDRV_TRANSFER_CONTEXT structure.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

The function writes data from a minidriver-allocated temporary page buffer to the image file opened by the WIA service. Minidrivers typically call this function after acquiring a page of data for which the minidriver allocated a temporary buffer.

This function is similar to wiasWriteBufToFile, which can be used to write a buffer of image data to any type of image file. If a WIA minidriver intends to write a page of image data to a multipage TIFF file, including all appropriate tags, image file directory (IFD) entries, and other non-image data, it should call this function, rather than wiasWriteBufToFile.

This function is available in Windows Me and in Windows XP and later.

See Also

MINIDRV_TRANSFER_CONTEXT, wiasWriteBufToFile


wiasWritePropBin

The wiasWritePropBin function writes a single binary-data property value to a WIA item.

HRESULT
  wiasWritePropBin(
    BYTE  *pWiasContext,
    PROPID  propid,
    LONG  cbVal,
    BYTE  *pbVal
    );

Parameters

pWiasContext
Pointer to a WIA service context.
propid
Specifies the property identifier.
cbVal
Specifies the total number of bytes to write to the item.
pbVal
Pointer to the first byte of an array of bytes to be written to the item.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.

See Also

wiasWritePropFloat, wiasWritePropGuid, wiasWritePropLong, wiasWritePropStr, wiasReadPropBin


wiasWritePropFloat

The wiasWritePropFloat function writes a single floating point property value to a WIA item.

HRESULT
  wiasWritePropFloat(
    BYTE  *pWiasContext,
    PROPID  propid,
    FLOAT  fVal
    );

Parameters

pWiasContext
A pointer to a WIA service context.
propid
Specifies the property identifier.
fVal
Specifies the floating point property value to write to the item.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.

See Also

wiasWritePropBin, wiasWritePropGuid, wiasWritePropLong, wiasWritePropStr, wiasReadPropFloat


wiasWritePropGuid

The wiasWritePropGuid function writes a single GUID property value to a WIA item.

HRESULT
  wiasWritePropGuid(
    BYTE  *pWiasContext,
    PROPID  propid,
    GUID  gVal
    );

Parameters

pWiasContext
Pointer to a WIA service context.
propid
Specifies the property identifier.
gVal
Specifies a GUID property value to write to the item.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.

See Also

wiasWritePropBin, wiasWritePropFloat, wiasWritePropLong, wiasWritePropStr, wiasReadPropGuid


wiasWritePropLong

The wiasWritePropLong function writes a single long integer property value to a WIA item.

HRESULT
  wiasWritePropLong(
    BYTE  *pWiasContext,
    PROPID  propid,
    LONG  lVal
    );

Parameters

pWiasContext
Pointer to a WIA service context.
propid
Specifies the property identifier.
lVal
Specifies the long integer property value to write to the item.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.

See Also

wiasWritePropBin, wiasWritePropFloat, wiasWritePropGuid, wiasWritePropStr, wiasReadPropLong


wiasWritePropStr

The wiasWritePropStr function writes a single string property value to a WIA item.

HRESULT
  wiasWritePropStr(
    BYTE  *pWiasContext,
    PROPID  propid,
    BSTR  bstr
    );

Parameters

pWiasContext
Pointer to a WIA service context.
propid
Specifies the property identifier.
bstr
Specifies the string property value to write to the item.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function is available in Windows Me and in Windows XP and later.

See Also

wiasWritePropBin, wiasWritePropFloat, wiasWritePropGuid, wiasWritePropLong, wiasReadPropStr


WIA Utility Library Functions and Classes

The WIA Utility Library is a collection of helper functions and classes provided for use by WIA minidrivers.

WIA Debugging Functions

WIA General Utility Functions

CWiauDbgFn Class

CWiauFormatConverter Class

CWiauPropertyList Class


WIA Debugging Functions

The WIA debugging functions, whose names have the form wiauDbgXxx, can be used during WIA minidriver debugging to log messages to a log file, to the debugger, or to both.


wiauDbgDump

The wiauDbgDump function logs a message containing one or more data values.

inline void __stdcall
  wiauDbgDump(
    LPCSTR  fname,
    (LPCSTR  fmt, ...)
    );

Parameters

fname
Points to a string containing the name of the function or method into which the call to wiauDbgDump is inserted.
fmt, ...
Points to a format string that specifies a variable argument list, which starts with an ANSI format string containing the message and any conversion specifiers. The ellipsis (...) specifies a variable number of arguments that are to be output.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

The wiauDbgDump function typically is used to log a message along with one or more data values, as in the following example.

wiauDbgDump("SetBuffer", "Buffer size set to %d bytes.", size);

This example, which would be placed in a function named SetBuffer, causes the function name and a string describing the size of a buffer to be logged.

See Also

wiauDbgError, wiauDbgErrorHr, wiauDbgTrace, wiauDbgWarning


wiauDbgError

The wiauDbgError function logs an error message.

inline void __stdcall
  wiauDbgError(
    LPCSTR  fname,
    (LPCSTR  fmt, ...)
    );

Parameters

fname
Points to a string containing the name of the function or method into which the call to wiauDbgError is inserted.
fmt, ...
Points to a format string that specifies a variable argument list, which starts with an ANSI format string containing the message and any conversion specifiers. The ellipsis (...) specifies a variable number of arguments that are to be output.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

The wiauDbgError typically is used to display an error message with no data, such as in the following example.

wiauDbgError("Read", "Attempting to read past end of buffer");

See Also

wiauDbgDump, wiauDbgErrorHr, wiauDbgTrace, wiauDbgWarning


wiauDbgErrorHr

The wiauDbgErrorHr function logs a message containing an HRESULT and its error message string.

inline void __stdcall
  wiauDbgErrorHr(
    HRESULT  hr,
    LPCSTR  fname,
    (LPCSTR  fmt, ...)
    );

Parameters

hr
Specifies the HRESULT that is to be logged.
fname
Points to a string containing the name of the function or method into which the call to wiauDbgErrorHr is inserted.
fmt, ...
Points to a format string that specifies a variable argument list, which starts with an ANSI format string containing the message and any conversion specifiers. The ellipsis (...) specifies a variable number of arguments that are to be output.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

The wiauDbgErrorHr function typically logs two lines to the log file, or debugger, or both. The first line contains the text of the fmt parameter, including data, if provided. The second line contains the HRESULT and the message string associated with that HRESULT. The following example shows how this function might be called:

wiauDbgErrorHr(hr, "AllocateBuffer", "Buffer size is %d bytes", size);

See Also

wiauDbgDump, wiauDbgError, wiauDbgTrace, wiauDbgWarning


wiauDbgFlags

The wiauDbgFlags function determines whether a particular debugging flag is set.

inline void __stdcall
  wiauDbgFlags(
    DWORD  flags,
    LPCSTR  prefix,
    LPCSTR  fname,
    (LPCSTR  fmt, ...)
    );

Parameters

flags
Is a set of flags that control which information is placed in the log file or displayed in the debugger. See the flags parameter of wiauDbgSetFlags for a list of the flag values.
prefix
Points to a string containing a prefix (such as "ERROR " or "WARN ").
fname
Points to a string containing the name of the function or method into which the call to wiauDbgFlags is inserted.
fmt, ...
Points to a format string that specifies a variable argument list, which starts with an ANSI format string describing the message and any conversion specifiers. The ellipsis (...) specifies a variable number of arguments that are to be output. The text should be prefixed with the full name of the method or function generating the message in the format of "class::method, message-text".

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

If message logging to log file, or debugger, or both is enabled and the particular flag in the flags parameter is enabled, this function logs a message containing the strings pointed to by the prefix, fname, and fmt parameters.

See Also

wiauDbgSetFlags


wiauDbgHelper

The wiauDbgHelper function formats a message and writes it to a log file, or debugger, or both.

void __stdcall
  wiauDbgHelper(
    LPCSTR  prefix,
    LPCSTR  fname,
    LPCSTR  fmt,
    va_list  marker
    );

Parameters

prefix
Points to a string containing a prefix (such as "ERROR " or "WARN ") associated with the message.
fname
Points to a string containing the name of the function or method into which the call to wiauDbgHelper is inserted.
fmt
Points to a string that controls how an item or items in a variable argument list is to be formatted.
marker
Marks the beginning of a variable argument list.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

The wiauDbgHelper function is a general-purpose function that is used internally by many of the other wiauDbgXxx functions. While it can be used in WIA minidrivers, there are other limited-purpose functions provided that are more convenient to use.

See Also

wiauDbgDump, wiauDbgError, wiauDbgErrorHr, wiauDbgTrace, wiauDbgWarning


wiauDbgHelper2

The wiauDbgHelper2 function writes a message to a log file, or debugger, or both.

void __stdcall
  wiauDbgHelper2(
    LPCSTR  prefix,
    LPCSTR  fname,
    (LPCSTR  fmt, ...)
    );

Parameters

prefix
Points to a string containing a prefix (such as "ERROR " or "WARN ") associated with the message.
fname
Points to a string containing the name of the function or method into which the call to wiauDbgHelper2 is inserted.
fmt, ...
Points to a format string that specifies a variable argument list, which starts with an ANSI format string containing the message and any conversion specifiers. The ellipsis (...) specifies a variable number of arguments that are to be output. The text should be prefixed with the full name of the method or function generating the message in the format of "class::method, message-text".

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

The wiauDbgHelper2 function enables those using it to write printf-style messages, with variable argument lists, to a log file or debugger. The following example demonstrates how this function might be used.

wiauDbgHelper2("ERROR", "MyFunc", "Buffer size too small - %d bytes", BufSize);

See Also

wiauDbgDump, wiauDbgError, wiauDbgErrorHr, wiauDbgTrace, wiauDbgWarning, wiauDbgHelper


wiauDbgInit

The wiauDbgInit function initializes WIA debugging.

void __stdcall
  wiauDbgInit(
    HINSTANCE  hInstance
    );

Parameters

hInstance
Is the handle to the DLL instance.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

If the wiauDbgInit function not called, all DLLs loaded by a process inherit the debug flags of that process.


wiauDbgLegacyError

The wiauDbgLegacyError function logs an error message.

inline void __stdcall
  wiauDbgLegacyError(
    (LPCSTR  fmt, ...)
    );

Parameters

fmt, ...
Points to a format string that specifies a variable argument list, which starts with an ANSI format string containing the message and any conversion specifiers. The ellipsis (...) specifies a variable number of arguments that are to be output.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

The wiauDbgLegacyError function is identical to the wiauDbgError function except that the latter function has an additional parameter used to identify the function or method that is active when the function is called.

See Also

wiauDbgError


wiauDbgLegacyError2

The wiauDbgLegacyError2 function logs an error message.

inline void __stdcall
  wiauDbgLegacyError2(
    HINSTANCE  hInstance,
    (LPCSTR  fmt, ...)
    );

Parameters

hInstance
Specifies the handle to the DLL instance.
fmt, ...
Points to a format string that specifies a variable argument list, which starts with an ANSI format string containing the message and any conversion specifiers.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

The wiauDbgLegacyError2 function is identical to the wiauDbgError function except that the former has a parameter that specifies the handle to the DLL instance and the latter has a parameter used to identify the function or method that is active when the function is called.

See Also

wiauDbgError


wiauDbgLegacyHresult2

The wiauDbgLegacyHresult2 function logs a default message containing an HRESULT.

inline void __stdcall
  wiauDbgLegacyHresult2(
    HINSTANCE  hInstance,
    HRESULT  hr
    );

Parameters

hInstance
Specifies the handle to the DLL instance.
hr
Specifies the HRESULT to be logged.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

A call to the wiauDbgLegacyHresult2 function is equivalent to the following call to the wiauDbgErrorHr function:

wiauDbgErrorHr(hr, "", "");

That is, only one line is output to the log file and/or debugger. The line has the following form:

ERROR HRESULT = HRESULT value, Error text for HRESULT

See Also

wiauDbgErrorHr


wiauDbgLegacyTrace

The wiauDbgLegacyTrace function logs a trace message.

inline void __stdcall
  wiauDbgLegacyTrace(
    (LPCSTR  fmt, ...)
    );

Parameters

fmt, ...
Points to a format string that specifies a variable argument list, which starts with an ANSI format string containing the message and any conversion specifiers. The ellipsis (...) specifies a variable number of arguments that are to be output.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

The wiauDbgLegacyTrace function is identical to the wiauDbgTrace function except that the latter has a parameter used to identify the function or method that is active when the function is called.

See Also

wiauDbgTrace


wiauDbgLegacyTrace2

The wiauDbgLegacyTrace2 function logs a trace message.

inline void __stdcall
  wiauDbgLegacyTrace2(
    HINSTANCE  hInstance,
    (LPCSTR  fmt, ...)
    );

Parameters

hInstance
Specifies the handle to the DLL instance.
fmt, ...
Points to a format string that specifies a variable argument list, which starts with an ANSI format string containing the message and any conversion specifiers. The ellipsis (...) specifies a variable number of arguments that are to be output.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

The wiauDbgLegacyTrace2 function is identical to the wiauDbgTrace function except that the former has a parameter that specifies the handle to the DLL instance and the latter has a parameter used to identify the function or method that is active when the function is called.

See Also

wiauDbgTrace


wiauDbgLegacyWarning

The wiauDbgLegacyWarning function logs a warning message.

inline void __stdcall
  wiauDbgLegacyWarning(
    (LPCSTR  fmt, ...)
    );

Parameters

fmt, ...
Points to a format string that specifies a variable argument list, which starts with an ANSI format string containing the message and any conversion specifiers. The ellipsis (...) specifies a variable number of arguments that are to be output.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

The wiauDbgLegacyWarning function is identical to the wiauDbgWarning function except that the latter has a parameter used to identify the function or method that is active when the function is called.

See Also

wiauDbgWarning


wiauDbgSetFlags

The wiauDbgSetFlags function sets debugging flags.

inline DWORD __stdcall
  wiauDbgSetFlags(
    DWORD  flags
    );

Parameters

flags
Is a set of flags that control message logging. This parameter can be set to a combination of the following values:
Value | Meaning
WIAUDBG_BREAK_ON_ERRORS | Call DebugBreak (described in the Platform SDK documentation) when an error occurs.
WIAUDBG_DONT_LOG | Do not log to either log file or debugger.
WIAUDBG_DONT_LOG_TO_DEBUGGER | Do not log to debugger.
WIAUDBG_DONT_LOG_TO_FILE | Do not log to log file.
WIAUDBG_DUMP | Log data.
WIAUDBG_ERRORS | Log error messages.
WIAUDBG_FNS | Log function entries and exits.
WIAUDBG_PRINT_INFO | Log thread, file, and line number.
WIAUDBG_PRINT_TIME | Log current time.
WIAUDBG_TRACES | Log trace messages.
WIAUDBG_WARNINGS | Log warning messages.

Return Value

The wiauDbgSetFlags function returns a value containing the flags that were in effect before the call to this function.

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

See Also

wiauDbgFlags


wiauDbgTrace

The wiauDbgTrace function logs a trace message.

inline void __stdcall
  wiauDbgTrace(
    LPCSTR  fname,
    (LPCSTR  fmt, ...)
    );

Parameters

fname
Points to a string containing the name of the function or method into which the call to wiauDbgTrace is inserted.
fmt, ...
Points to a format string that specifies a variable argument list, which starts with an ANSI format string containing the trace message and any conversion specifiers. The ellipsis (...) specifies a variable number of arguments that are to be output.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

See Also

wiauDbgDump, wiauDbgError, wiauDbgErrorHr, wiauDbgWarning


wiauDbgWarning

The wiauDbgWarning function logs a warning message.

inline void __stdcall
  wiauDbgWarning(
    LPCSTR  fname,
    (LPCSTR  fmt, ...)
    );

Parameters

fname
Points to a string containing the name of the function or method into which the call to wiauDbgWarning is inserted.
fmt, ...
Points to a format string that specifies a variable argument list, which starts with an ANSI format string containing the warning message and any conversion specifiers. The ellipsis (...) specifies a variable number of arguments that are to be output.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

See Also

wiauDbgDump, wiauDbgError, wiauDbgErrorHr, wiauDbgTrace


WIA General Utility Functions

The WIA utility functions are a collection of functions that carry out common tasks. One group of functions in this collection, the wiauReg Xxx functions, can be used to work with the system registry. A second group, the wiauStr Xxx functions, can be used to copy ANSI or Unicode strings, or to convert strings from one of these formats to the other.


wiauGetDrvItemContext

The wiauGetDrvItemContext function gets the driver item context, and optionally, the driver item.

HRESULT
  wiauGetDrvItemContext(
    BYTE  *pWiasContext,
    VOID  **ppItemCtx,
    IWiaDrvItem  **ppDrvItem = NULL
    );

Parameters

pWiasContext
Points to the item context.
ppItemCtx
Points to a memory location that receives a pointer to the driver item context.
ppDrvItem
Optional. Points to a memory location that receives a pointer to a driver item. The default value of this parameter is NULL, which means that when this function returns, no change is made to this parameter.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error.

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.


wiauGetResourceString

The wiauGetResourceString function gets a resource string, storing it as a BSTR.

HRESULT
  wiauGetResourceString(
    HINSTANCE  hInst,
    LONG  lResourceID,
    BSTR  *pbstrStr
    );

Parameters

hInst
Specifies the handle of the module instance.
lResourceID
Specifies the resource ID of the target BSTR value.
pbstrStr
Points to the memory location that receives the retrieved string. The caller of this function must free this string by calling SysFreeString (described in the Platform SDK documentation).

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error.

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.


wiauGetValidFormats

The wiauGetValidFormats function calls the IWiaMiniDrv::drvGetWiaFormatInfo method and makes a list of valid formats, using a specified tymed value.

HRESULT
  wiauGetValidFormats(
    IWiaMiniDrv  *pDrv,
    BYTE  *pWiasContext,
    LONG  TymedValue,
    int  *pNumFormats,
    GUID  **ppFormatArray
    );

Parameters

pDrv
Points to the WIA minidriver object. This parameter should be set to this.
pWiasContext
Points to the WIA service context.
TymedValue
Specifies the tymed value to search for.
pNumFormats
Points to a memory location that receives the number of formats.
ppFormatArray
Points to a memory location that receives the address of the array of format GUIDs.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error.

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

The caller of this function is responsible for freeing the format array, using the delete [ ] operator.


wiauPropInPropSpec

The wiauPropInPropSpec function determines whether a specified property specification ID is contained in an array of such values. The function optionally gets the index at which the property specification ID was found.

BOOL
  wiauPropInPropSpec(
    LONG  NumPropSpecs,
    const PROPSPEC  *pPropSpecs,
    PROPID  PropId,
    int  *pIdx = NULL
    );

Parameters

NumPropSpecs
Specifies the number of property specification IDs in the array pointed to by pPropSpecs.
pPropSpecs
Points to the first element of the property specification ID array.
PropId
Specifies the property specification ID to search for in the array pointed to by pPropSpecs.
pIdx
Optional. Points to a memory location that receives the index of the property specification ID in the property specification ID array. The default value of this parameter is NULL, in which case the function does not use it.

Return Value

This function returns TRUE if it found the property specification ID in the property specification ID array. Otherwise it returns FALSE.

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

The wiauPropInPropSpec function finds a single property specification ID within an array of property specification IDs. A related function, wiauPropsInPropSpec can be used to determine whether any of a specified list of property specification IDs is found in another array of property specification IDs.

See Also

wiauPropsInPropSpec


wiauPropsInPropSpec

The wiauPropsInPropSpec function determines whether any of a list of property specification IDs is contained within an array of such values.

BOOL
  wiauPropsInPropSpec(
    LONG  NumPropSpecs,
    const PROPSPEC  *pPropSpecs,
    int  NumProps,
    PROPID  *pProps
    );

Parameters

NumPropSpecs
Specifies the number of property specification IDs in the array pointed to by the pPropSpecs parameter.
pPropSpecs
Points to the first element of the array of property specification IDs.
NumProps
Specifies the number of property specification IDs to search for.
pProps
Points to the first element of the array containing the property specification IDs to search for.

Return Value

This function returns TRUE as soon as it finds one of the property specification IDs given in the pProps array in the pPropSpecs array. If the function is unable to find any of the listed property specification IDs in that array, it returns FALSE.

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

The wiauPropsInPropSpec function finds one or more property specification IDs within an array of property specification IDs. A related function, wiauPropInPropSpec, can be used to find a single property specification ID within such an array.

See Also

wiauPropInPropSpec


wiauRegGetDword

The wiauRegGetDword function gets a DWORD value from the DeviceData section of the registry.

HRESULT
  wiauRegGetDword(
    HKEY  hkKey,
    PCWSTR  pwszValueName,
    DWORD  *pdwValue
    );

Parameters

hkKey
Specifies the registry key handle. This parameter should be set to the value pointed to by the phkeyDeviceData parameter when wiauRegOpenData returns.
pwszValueName
Points to the first byte of a Unicode string containing the name of the registry entry.
pdwValue
Points to a memory location that receives the returned DWORD value.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error.

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

See Also

wiauRegOpenData, wiauRegGetStr


wiauRegGetStr

The wiauRegGetStr function gets a string value from the DeviceData section of the registry.

HRESULT
  wiauRegGetStr(
    HKEY  hkKey,
    PCWSTR  pwszValueName,
    PWSTR  pwszValue,
    DWORD  *pdwLength
    );

Parameters

hkKey
Specifies the registry key handle. This parameter should be set to the value pointed to by the phkeyDeviceData parameter when wiauRegOpenData returns.
pwszValueName
Points to the first character of a Unicode string containing the name of the registry entry.
pwszValue
Points to a memory location that receives the string value, including a terminating null character.
pdwLength
Points to a memory location that receives the length, in bytes, of the string value pointed to by the pwszValue parameter. The length includes the terminating null character.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error.

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

See Also

wiauRegOpenData, wiauRegGetDword


wiauRegOpenData

The wiauRegOpenData function opens the DeviceData registry key.

HRESULT
  wiauRegOpenData(
    HKEY  hkeyAncestor,
    HKEY  *phkeyDeviceData
    );

Parameters

hkeyAncestor
Specifies the key handle of the parent. This parameter should be set to the value used in the call to the IStiUSD::Initialize method.
phkeyDeviceData
Points to a memory location that receives the opened key handle.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error.

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

Call this function only in the STI IStiUSD::Initialize method. Call RegCloseKey (described in the Platform SDK documentation) when you are finished with the registry.

See Also

IStiUSD::Initialize


wiauSetImageItemSize

The wiauSetImageItemSize function calculates the size and width, in bytes, for an image, based on the current WIA_IPA_FORMAT setting (described in the Platform SDK documentation), and writes the new values to the appropriate properties.

HRESULT
  wiauSetImageItemSize(
    BYTE  *pWiasContext,
    LONG  lWidth,
    LONG  lHeight,
    LONG  lDepth,
    LONG  lSize,
    PWSTR  pwszExt = NULL
    );

Parameters

pWiasContext
Points to the item context for the image item.
lWidth
Specifies the width of the image, in pixels.
lHeight
Specifies the height of the image, in pixels.
lDepth
Specifies the depth of the image, in bits.
lSize
Specifies the size of the image as stored on the device.
pwszExt
Optional. Points to a memory location containing a three-character file extension for the item's native format. If this parameter is NULL, the item's extension property, WIA_IPA_FILENAME_EXTENSION (described in the Platform SDK documentation), is not updated.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error.

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

If the format is not BMP, this function assumes that the value passed in the lSize parameter is correct for the current format.


wiauStrC2C

The wiauStrC2C function copies an ANSI character string to another ANSI character string.

HRESULT
  wiauStrC2C(
    CHAR  *pszSrc,
    CHAR  *pszDst,
    INT  iSize
    );

Parameters

pszSrc
Points to the ANSI string to be copied.
pszDst
Points to a memory location that receives the copied string
iSize
Specifies the size, in bytes, of the buffer pointed to by pszDst.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error.

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

See Also

wiauStrC2W, wiauStrW2C, wiauStrW2W


wiauStrC2W

The wiauStrC2W function converts an ANSI character string to a Unicode string.

HRESULT
  wiauStrC2W(
    CHAR  *pszSrc,
    WCHAR  *pwszDst,
    INT  iSize
    );

Parameters

pszSrc
Points to the ANSI string to convert.
pwszDst
Points to a memory location that receives the converted Unicode string.
iSize
Specifies the size, in bytes, of the buffer pointed to by pwszDst.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error.

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

See Also

wiauStrC2C, wiauStrW2C, wiauStrW2W


wiauStrW2C

The wiauStrW2C function converts a Unicode string to an ANSI character string.

HRESULT
  wiauStrW2C(
    WCHAR  *pwszSrc,
    CHAR  *pszDst,
    INT  iSize
    );

Parameters

pwszSrc
Points to the Unicode string to be converted.
pszDst
Points to a memory location that receives the converted ANSI string.
iSize
Specifies the size, in bytes, of the buffer pointed to by pszDst.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error.

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

See Also

wiauStrC2C, wiauStrC2W, wiauStrW2W


wiauStrW2W

The wiauStrW2W function copies a Unicode string to another Unicode string.

HRESULT
  wiauStrW2W(
    WCHAR  *pwszSrc,
    WCHAR  *pwszDst,
    INT  iSize
    );

Parameters

pwszSrc
Points to the Unicode string to be copied.
pwszDst
Points to a memory location that receives the copied string.
iSize
Specifies the size, in bytes, of the buffer pointed to by pwszDst.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error.

Headers

Declared in wiautil.h. Include wiautil.h.

Comments

This function is available in Windows XP and later.

See Also

wiauStrC2C, wiauStrC2W, wiauStrW2C


CWiauDbgFn Class

The CWiauDbgFn class is a helper class that is used for tracing function or method entry and exit points.


CWiauDbgFn::CWiauDbgFn

The CWiauDbgFn::CWiauDbgFn method is used for tracing when a function or method is entered.

CWiauDbgFn(
  LPCSTR  fname
  );

Parameters

fname
Specifies the name of the function or method being entered.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

See Also

CWiauDbgFn::~CWiauDbgFn


CWiauDbgFn::~CWiauDbgFn

The CWiauDbgFn::~CWiauDbgFn destructor is called when the function or method being traced by CWiauDbgFn::CWiauDbgFn is exited.

~CWiauDbgFn();

Parameters

None

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

See Also

CWiauDbgFn::CWiauDbgFn


CWiauFormatConverter Class

The CWiauFormatConverter class is a helper class for converting images to BMP format.


CWiauFormatConverter::CWiauFormatConverter

The CWiauFormatConverter::CWiauFormatConverter method is the constructor for the CWiauFormatConverter class.

CWiauFormatConverter();

Parameters

None

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

See Also

CWiauFormatConverter::~CWiauFormatConverter


CWiauFormatConverter::~CWiauFormatConverter

The CWiauFormatConverter::~CWiauFormatConverter method is the destructor for the CWiauFormatConverter class.

~CWiauFormatConverter();

Parameters

None

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

See Also

CWiauFormatConverter::CWiauFormatConverter


CWiauFormatConverter::ConvertToBmp

The CWiauFormatConverter::ConvertToBmp method converts an image to BMP format.

HRESULT
  ConvertToBmp(
    BYTE  *pSource,
    INT  iSourceSize,
    BYTE  **ppDest,
    INT  *piDestSize,
    BMP_IMAGE_INFO  *pBmpImageInfo,
    SKIP_AMOUNT  iSkipAmt = SKIP_OFF
    );

Parameters

pSource
Points to the memory location containing the first byte of the source image.
iSourceSize
Specifies the size, in bytes, of the source image.
ppDest
Points to a memory location that receives the address of the resulting image.
piDestSize
Points to a memory location that receives the size, in bytes, of the resulting image.
pBmpImageInfo
Points to a BMP_IMAGE_INFO structure that receives information about the resulting image.
iSkipAmt
Optional. Specifies the amount of the BMP header to skip. The default value of this parameter denotes that none of the BMP header is skipped.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error.

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

The caller of this method can pass a result buffer in ppDest and the size in piDestSize. Alternatively, the caller can set *ppDest to NULL and *piDestSize to zero in the call to indicate that this method should allocate the memory. The caller is responsible for freeing the memory using the delete [] operator.

See Also

BMP_IMAGE_INFO, SKIP_AMOUNT, CWiauFormatConverter::IsFormatSupported


CWiauFormatConverter::Init

The CWiauFormatConverter::Init method initializes the CWiauFormatConverter class and GDI+ for converting images. This method should be called only once.

HRESULT
  Init();

Parameters

None

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error.

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.


CWiauFormatConverter::IsFormatSupported

The CWiauFormatConverter::IsFormatSupported method verifies that GDI+ supports the image format that is to be converted.

BOOL
  IsFormatSupported(
    const GUID  *pguidFormat
    );

Parameters

pguidFormat
Points to the GUID of the format. The format GUIDs are defined in gdiplusimaging.h.

Return Value

The method returns TRUE if the format indicated by the format GUID is supported, and FALSE if it is not supported.

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

See Also

CWiauFormatConverter::ConvertToBmp


CWiauPropertyList Class

The CWiauPropertyList class can be used to create and maintain a list of properties for a device. This section lists the public methods of the CWiauPropertyList class.


CWiauPropertyList::CWiauPropertyList

The CWiauPropertyList::CWiauPropertyList method is the constructor for the CWiauPropertyList class.

CWiauPropertyList();

Parameters

None

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

The CWiauPropertyList constructor initializes all data members of a property list object to either NULL or zero. Use the CWiauPropertyList::Init method to reserve memory for properties. Use the CWiauPropertyList::DefineProperty method once per property to add it to the property list object.

See Also

CWiauPropertyList::~CWiauPropertyList, CWiauPropertyList::Init, CWiauPropertyList::DefineProperty


CWiauPropertyList::~CWiauPropertyList

The CWiauPropertyList::~CWiauPropertyList method is the destructor for the CWiauPropertyList class.

~CWiauPropertyList();

Parameters

None

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

See Also

CWiauPropertyList::CWiauPropertyList


CWiauPropertyList::DefineProperty

The CWiauPropertyList::DefineProperty method adds a property definition to a property list object.

HRESULT
  DefineProperty(
    int  *pIdx,
    PROPID  PropId,
    LPOLESTR  PropName,
    ULONG  Access,
    ULONG  SubType
    );

Parameters

pIdx
Points to a memory location that receives the index for the newly added property. Many other methods in this class use a property's index in order to identify the property.
PropId
Specifies a property ID constant.
PropName
Points to a name string for the property.
Access
Specifies the type of access for the property, usually either WIA_PROP_READ (read-only) or WIA_PROP_RW (read/write).
SubType
Specifies the property subtype, one of WIA_PROP_FLAG, WIA_PROP_LIST, WIA_PROP_RANGE, or WIA_PROP_NONE. The first three constants indicate, respectively, that a property is a set of flag values, a list of values, or a range of values. The fourth constant indicates that a property is none of these.

Return Value

This method returns S_OK if it is able to define a property successfully. If the property list does not have enough room for an additional property, the method returns E_FAIL.

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

The WIA_PROP_XXX constants are defined in the Platform SDK documentation.

Before a property can be added to a property list, the property list must be initialized. Do this by calling the CWiauPropertyList::Init method.

See Also

CWiauPropertyList::Init


CWiauPropertyList::GetPropId

The CWiauPropertyList::GetPropId method finds the property ID for a property, given its index in the property list.

PROPID
  GetPropId(
    INT index
    );

Parameters

index
Specifies the index of the property within the property list.

Return Value

The CWiauPropertyList::GetPropId method returns the property ID for the property.

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

See Also

CWiauPropertyList::LookupPropId


CWiauPropertyList::Init

The CWiauPropertyList::Init method initializes a property list object.

HRESULT
  Init(
    INT  NumProps
    );

Parameters

NumProps
Specifies the number of properties within the property list for which to reserve space. This number can be larger than the actual number of properties in the property list, but it cannot be smaller.

Return Value

On success, the CWiauPropertyList::Init method returns S_OK. If the method has already been called on a given property list, the method returns E_FAIL.

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

See Also

CWiauPropertyList::CWiauPropertyList, CWiauPropertyList::DefineProperty


CWiauPropertyList::LookupPropId

The CWiauPropertyList::LookupPropId method finds a property's index, given its property ID.

INT
  LookupPropId(
    PROPID  PropId
    );

Parameters

PropId
Specifies the property ID for the property.

Return Value

On success, the method returns the index of the property within the property list. If it is unable to find the property, the method returns -1.

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

See Also

CWiauPropertyList::GetPropId


CWiauPropertyList::SendToWia

The CWiauPropertyList::SendToWia method calls the WIA service to define all of the properties currently contained in the property list object.

HRESULT
  SendToWia(
    BYTE  *pWiasContext
    );

Parameters

pWiasContext
Points to the context that previously was passed in a call to the IWiaMiniDrv::drvInitItemProperties method.

Return Value

On success, the CWiauPropertyList::SendToWia method returns S_OK. If the property list contains no properties, the method returns E_FAIL.

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

The CWiauPropertyList::SendToWia method should be called only after all properties have been defined and their values set.

See Also

IWiaMiniDrv::drvInitItemProperties


CWiauPropertyList::SetCurrentValue(BSTR)

The CWiauPropertyList::SetCurrentValue(BSTR) method sets the current value of a property of type BSTR, and sets its type to VT_BSTR.

VOID
  SetCurrentValue(
    INT  index,
    BSTR  value
    );

Parameters

index
Specifies the property index. Set this parameter to the value in *pIdx when the CWiauPropertyList::DefineProperty method returns.
value
Points to a memory location containing the value that is written to the device property in the property list. This pointer must remain valid until the CWiauPropertyList::SendToWia method is called.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

See Also

CWiauPropertyList::DefineProperty, CWiauPropertyList::SendToWia


CWiauPropertyList::SetCurrentValue(BYTE*)

The CWiauPropertyList::SetCurrentValue(BYTE*) method sets the current value of a property consisting of an array of bytes, and sets its type to VT_UI1 | VT_VECTOR.

VOID
  SetCurrentValue(
    INT  index,
    BYTE  *value,
    INT  size
    );

Parameters

index
Specifies the property index. Set this parameter to the value in *pIdx when the CWiauPropertyList::DefineProperty method returns.
value
Points to a memory location containing the value that is written to the device property in the property list. This pointer must remain valid until the CWiauPropertyList::SendToWia method is called.
size
Specifies the number of elements in the array of bytes.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

See Also

CWiauPropertyList::DefineProperty, CWiauPropertyList::SendToWia


CWiauPropertyList::SetCurrentValue(CLSID)

The CWiauPropertyList::SetCurrentValue(CLSID) method sets the current value of a property of type CLSID, and sets its type to VT_CLSID.

VOID
  SetCurrentValue(
    INT  index,
    CLSID  *pValue
    );

Parameters

index
Specifies the property index. Set this parameter to the value in *pIdx when the CWiauPropertyList::DefineProperty method returns.
pValue
Points to a memory location containing the value that is written to the device property in the property list. This pointer must remain valid until the CWiauPropertyList::SendToWia method is called.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

See Also

CWiauPropertyList::DefineProperty, CWiauPropertyList::SendToWia


CWiauPropertyList::SetCurrentValue(FLOAT)

The CWiauPropertyList::SetCurrentValue(FLOAT) method sets the current value of a property of type FLOAT, and sets its type to VT_R4.

VOID
  SetCurrentValue(
    INT  index,
    FLOAT  value
    );

Parameters

index
Specifies the property index. Set this parameter to the value in *pIdx when the CWiauPropertyList::DefineProperty method returns.
value
Specifies the value that is written to the device property in the property list.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

See Also

CWiauPropertyList::DefineProperty


CWiauPropertyList::SetCurrentValue(LONG)

The CWiauPropertyList::SetCurrentValue(LONG) method sets the current value of a property of type LONG, and sets its type to VT_I4.

VOID
  SetCurrentValue(
    INT  index,
    LONG  value
    );

Parameters

index
Specifies the property index. Set this parameter to the value in *pIdx when the CWiauPropertyList::DefineProperty method returns.
value
Specifies the value that is written to the device property in the property list.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

See Also

CWiauPropertyList::DefineProperty


CWiauPropertyList::SetCurrentValue(SYSTEMTIME)

The CWiauPropertyList::SetCurrentValue(SYSTEMTIME) method sets the current value of a property of type SYSTEMTIME, and sets its type to VT_UI2 | VT_VECTOR.

VOID
  SetCurrentValue(
    INT  index,
    PSYSTEMTIME  value
    );

Parameters

index
Specifies the property index. Set this parameter to the value in *pIdx when the CWiauPropertyList::DefineProperty method returns.
value
Points to a memory location containing the value that is written to the device property in the property list. This pointer must remain valid until the CWiauPropertyList::SendToWia method is called.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

The SYSTEMTIME structure is described in the Platform SDK documentation.

Comments

This method is available in Windows XP and later.

See Also

CWiauPropertyList::DefineProperty, CWiauPropertyList::SendToWia


CWiauPropertyList::SetValidValues(BSTR, list)

The CWiauPropertyList::SetValidValues(BSTR, list) method sets the type, as well as default, current, and valid values for a BSTR property associated with a list of values. The method also sets the property type to VT_BSTR and subtype to WIA_PROP_LIST (defined in the Platform SDK documentation).

VOID
  SetValidValues(
    INT  index,
    BSTR  defaultValue,
    BSTR  currentValue,
    INT  numValues,
    BSTR  *pValues
    );

Parameters

index
Specifies the property index. Set this parameter to the value in *pIdx when the CWiauPropertyList::DefineProperty method returns.
defaultValue
Specifies the default setting of the property on the device.
currentValue
Specifies the current setting of the property on the device.
numValues
Specifies the number of values in the property list.
pValues
Points to the first property in the property list. This pointer must remain valid until the CWiauPropertyList::SendToWia method is called.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

See Also

CWiauPropertyList::DefineProperty, CWiauPropertyList::SendToWia


CWiauPropertyList::SetValidValues(CLSID, list)

The CWiauPropertyList::SetValidValues(CLSID, list) method sets the type, as well as default, current, and valid values for a CLSID property associated with a list of values. The method also sets the property type to VT_CLSID and subtype to WIA_PROP_LIST (defined in the Platform SDK documentation).

VOID
  SetValidValues(
    INT  index,
    CLSID  *defaultValue,
    CLSID  *currentValue,
    INT  numValues,
    CLSID  **pValues
    );

Parameters

index
Specifies the property index. Set this parameter to the value in *pIdx when the CWiauPropertyList::DefineProperty method returns.
defaultValue
Specifies the default setting of the property on the device.
currentValue
Specifies the current setting of the property on the device.
numValues
Specifies the number of values in the property list.
pValues
Points to a memory location that contains the address of the first property in the property list. This pointer must remain valid until the CWiauPropertyList::SendToWia method is called.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

See Also

CWiauPropertyList::DefineProperty, CWiauPropertyList::SendToWia


CWiauPropertyList::SetValidValues(flag)

The CWiauPropertyList::SetValidValues(flag) method sets the type, as well as default, current, and valid values for a property whose values are defined by a flag. The method also sets the property type to VT_I4 and subtype to WIA_PROP_FLAG (defined in the Platform SDK documentation).

VOID
  SetValidValues(
    INT  index,
    LONG  defaultValue,
    LONG  currentValue,
    LONG  validFlags
    );

Parameters

index
Specifies the property index. Set this parameter to the value in *pIdx when the CWiauPropertyList::DefineProperty method returns.
defaultValue
Specifies the default setting of the property on the device.
currentValue
Specifies the current setting of the property on the device.
validFlags
Specifies a value containing all of the valid flags.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

See Also

CWiauPropertyList::DefineProperty, CWiauPropertyList::SendToWia


CWiauPropertyList::SetValidValues(FLOAT, list)

The CWiauPropertyList::SetValidValues(FLOAT, list) method sets the type, as well as default, current, and valid values for a FLOAT property associated with a list of values. The method also sets the property type to VT_R4 and subtype to WIA_PROP_LIST (defined in the Platform SDK documentation).

VOID
  SetValidValues(
    INT  index,
    FLOAT  defaultValue,
    FLOAT  currentValue,
    INT  numValues,
    PFLOAT  pValues
    );

Parameters

index
Specifies the property index. Set this parameter to the value in *pIdx when the CWiauPropertyList::DefineProperty method returns.
defaultValue
Specifies the default setting of the property on the device.
currentValue
Specifies the current setting of the property on the device.
numValues
Specifies the number of values in the property list.
pValues
Points to the first property in the property list. This pointer must remain valid until the CWiauPropertyList::SendToWia method is called.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

See Also

CWiauPropertyList::DefineProperty, CWiauPropertyList::SendToWia, CWiauPropertyList::SetValidValues(FLOAT, range)


CWiauPropertyList::SetValidValues(FLOAT, range)

The CWiauPropertyList::SetValidValues(FLOAT, range) method sets the type, as well as default, current, and valid values for a FLOAT property associated with a range of values. The method also sets the property type to VT_R4 and subtype to WIA_PROP_RANGE (defined in the Platform SDK documentation).

VOID
  SetValidValues(
    INT  index,
    FLOAT  defaultValue,
    FLOAT  currentValue,
    FLOAT  minValue,
    FLOAT  maxValue,
    FLOAT  stepValue
    );

Parameters

index
Specifies the property index. Set this parameter to the value in *pIdx when the CWiauPropertyList::DefineProperty method returns.
defaultValue
Specifies the default setting of the property on the device.
currentValue
Specifies the current setting of the property on the device.
minValue
Specifies the minimum value in the range of values.
maxValue
Specifies the maximum value in the range of values.
stepValue
Specifies the increment between two successive values in the range of values.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

See Also

CWiauPropertyList::DefineProperty, CWiauPropertyList::SendToWia, CWiauPropertyList::SetValidValues(FLOAT, list)


CWiauPropertyList::SetValidValues(LONG, list)

The CWiauPropertyList::SetValidValues(LONG, list) method sets the type, as well as default, current, and valid values for a LONG property associated with a list of values. The method also sets the property type to VT_I4 and subtype to WIA_PROP_LIST (defined in the Platform SDK documentation).

VOID
  SetValidValues(
    INT  index,
    LONG  defaultValue,
    LONG  currentValue,
    INT  numValues,
    PLONG  pValues
    );

Parameters

index
Specifies the property index. Set this parameter to the value in *pIdx when the CWiauPropertyList::DefineProperty method returns.
defaultValue
Specifies the default setting of the property on the device.
currentValue
Specifies the current setting of the property on the device.
numValues
Specifies the number of values in the property list.
pValues
Points to the first property in the property list. This pointer must remain valid until the CWiauPropertyList::SendToWia method is called.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

See Also

CWiauPropertyList::DefineProperty, CWiauPropertyList::SendToWia, CWiauPropertyList::SetValidValues(LONG, range)


CWiauPropertyList::SetValidValues(LONG, range)

The CWiauPropertyList::SetValidValues(LONG, range) method sets the type, as well as default, current, and valid values for a LONG property associated with a range of values. The method also sets the property type to VT_I4 and subtype to WIA_PROP_RANGE (defined in the Platform SDK documentation).

VOID
  SetValidValues(
    INT  index,
    LONG  defaultValue,
    LONG  currentValue,
    LONG  minValue,
    LONG  maxValue,
    LONG  stepValue
    );

Parameters

index
Specifies the property index. Set this parameter to the value in *pIdx when the CWiauPropertyList::DefineProperty method returns.
defaultValue
Specifies the default setting of the property on the device.
currentValue
Specifies the current setting of the property on the device.
minValue
Specifies the minimum value in the range of values.
maxValue
Specifies the maximum value in the range of values.
stepValue
Specifies the increment between two successive values in the range of values.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

See Also

CWiauPropertyList::DefineProperty, CWiauPropertyList::SendToWia, CWiauPropertyList::SetValidValues(LONG, list)


WIA Utility Library Structures and Enumerations

This section contains descriptions of the structures and enumerations used by the functions and class methods of the WIA Utility Library.


BMP_IMAGE_INFO

The BMP_IMAGE_INFO structure contains information about a BMP image.

typedef struct _BMP_IMAGE_INFO {
  INT  Width;
  INT  Height;
  INT  ByteWidth;
  INT  Size;
} BMP_IMAGE_INFO, *PBMP_IMAGE_INFO;

Members

Width
Specifies the width of the image, in pixels.
Height
Specifies the height of the image, in lines.
ByteWidth
Specifies the width of the image, in bytes.
Size
Specifies the total size of the image, including headers, in bytes.

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This structure is available in Windows XP and later.


SKIP_AMOUNT

The SKIP_AMOUNT enumeration is used to indicate whether the file and info headers of an image should be skipped over.

typedef enum {
  SKIP_OFF,
  SKIP_FILEHDR,
  SKIP_BOTHHDR
} SKIP_AMOUNT;

Enumerators

SKIP_OFF
Do not skip over either header.
SKIP_FILEHDR
Skip over the file header.
SKIP_BOTHHDR
Skip over both the file and info headers.

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This enumeration is available in Windows XP and later.

See Also

CWiauFormatConverter::ConvertToBmp


IWiaMiniDrvCallBack Interface

The IWiaMiniDrvCallBack interface provides the MiniDrvCallback method, which enables minidrivers to transfer image header data and image data from the imaging device to the WIA service. This method can also convey status information, such as the percentage of data transferred.

The method prototype is defined in wiamindr.h.


IWiaMiniDrvCallBack::MiniDrvCallback

The IWiaMiniDrvCallBack::MiniDrvCallback method provides a callback method for WIA minidrivers to use during a callback data transfer.

HRESULT
  MiniDrvCallback(
    IN LONG  lReason,
    IN LONG  lStatus,
    IN LONG  lPercentComplete,
    IN LONG  lOffset,
    IN LONG  lLength,
    IN PMINIDRV_TRANSFER_CONTEXT  pTranCtx,
    IN LONG  lReserved
    );

Parameters

lReason
Specifies a constant value that designates a callback status message. This value is used to determine the purpose of the callback, and can be one of the following values:
Message | Definition
IT_MSG_STATUS | Callback contains only status information.
IT_MSG_DATA_HEADER | Received before any data transfers. Indicates that the transfer buffer points to a WIA_DATA_CALLBACK_HEADER structure (defined in the Platform SDK documentation) that defines elements of the data transfer.
IT_MSG_DATA | Indicates that the transfer buffer contains a block of data.
IT_MSG_NEW_PAGE | Indicates that the data transfer of a page is complete.
IT_MSG_TERMINATION | Indicates that the data transfer is complete.

lStatus
Specifies the status of the transfer. This parameter is a bitwise OR of the following values:
Status | Definition
IT_STATUS_TRANSFER_FROM_DEVICE | Transferring data from device.
IT_STATUS_PROCESSING_DATA | Device and/or minidriver are processing the data.
IT_STATUS_TRANSFER_TO_CLIENT | Transferring data from the minidriver to the WIA service.

lPercentComplete
Specifies the current percentage of data transferred.
lOffset
Specifies the current offset into the transfer buffer from the beginning of the buffer.
lLength
Specifies the number of bytes contained in the transfer.
pTranCtx
Points to a MINIDRV_TRANSFER_CONTEXT structure containing the data transfer values.
lReserved
Reserved. Set to zero.

Return Value

If the method succeeds, it returns S_OK. If the callback is cancelled by the client application, the method returns S_FALSE. If the method fails, it returns a standard COM error code.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

This method is available in Windows Me and in Windows XP and later.

See Also

MINIDRV_TRANSFER_CONTEXT


IWiaDrvItem Interface

The IWiaDrvItem interface provides methods that a WIA minidriver can use to manage a tree of IWiaDrvItem items.

Method prototypes are defined in wiamindr.h.


IWiaDrvItem::AddItemToFolder

The IWiaDrvItem::AddItemToFolder method adds an IWiaDrvItem item to a folder in a driver item tree.

HRESULT
  AddItemToFolder(
    IN IWiaDrvItem  *pIParent
  );

Parameters

pIParent
Points to the IWiaDrvItem parent folder item.

Return Value

If the method succeeds, it returns S_OK. If the method fails because an invalid pIParent parameter is passed, it returns E_INVALIDARG. If the method fails for another reason, it returns a standard COM error code.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

Minidrivers typically use the IWiaDrvItem::AddItemToFolder method to add an item to a parent folder item in a driver item tree. The parent folder item is pointed to by the parameter pIParent. The item pointed to by pIParent must be a folder.

This method is available in Windows Me and in Windows XP and later.

See Also

IWiaDrvItem::RemoveItemFromFolder


IWiaDrvItem::DumpItemData

The IWiaDrvItem::DumpItemData method dumps private data associated with an IWiaDrvItem item into an allocated private buffer.

HRESULT
  DumpItemData(
    OUT BSTR  *bstrDrvItemData
    );

Parameters

bstrDrvItemData
Points to an allocated buffer that will receive the IWiaDrvItem data.

Return Value

If the method succeeds, it returns S_OK. If the method fails the buffer allocation, it returns E_OUTOFMEMORY. If the method fails for another reason, it returns a standard COM error code.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

This method is provided for Microsoft internal debugging only. It will return E_NOTIMPL on the release operating system.

This method is available in Windows Me and in Windows XP and later.


IWiaDrvItem::FindChildItemByName

The IWiaDrvItem::FindChildItemByName method searches the driver item tree for a specific child item.

HRESULT
  FindChildItemByName(
    IN BSTR  bstrChildItemName,
    OUT IWiaDrvItem  **ppIChildItem
    );

Parameters

bstrChildItemName
Specifies a string containing the name with path information of the child item to find.
ppIChildItem
Points to a memory location that will receive the address of the found IWiaDrvItem child item.

Return Value

If the method succeeds, it stores a pointer to the found child item in ppIChildItem and returns S_OK. If the method fails to find the child item, it returns S_FALSE. If the method fails for another reason, it returns a standard COM error code.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

Minidrivers typically use this method to search a driver item tree for a specific child item when the child item's name is known. The child item's full name is obtained in the method IWiaDrvItem::GetFullItemName.

This method is available in Windows Me and in Windows XP and later.

See Also

IWiaDrvItem::GetFullItemName, IWiaDrvItem::FindItemByName


IWiaDrvItem::FindItemByName

The IWiaDrvItem::FindItemByName method locates an item in a driver item tree by the item's full name.

HRESULT
  FindItemByName(
    IN LONG lFlags,
    IN BSTR bstrFullItemName,
    OUT IWiaDrvItem **ppItem
    );

Parameters

lFlags
Reserved. Set to zero.
bstrFullItemName
Specifies the full name of the item to find.
ppItem
Points to a memory location that will receive the address of the found IWiaDrvItem item.

Return Value

If the method succeeds, it stores a pointer to the found item in ppItem and returns S_OK. If the method fails, it places NULL in ppItem and returns S_FALSE. If this method doesn't find the required item, it returns S_FALSE. If an error occurred during the search, a standard COM error code will be returned.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

Minidrivers call this method to find an item in a driver item tree when the item's full name is known. The item's full name is obtained in the method IWiaDrvItem::GetFullItemName.

This method starts the search for the specified item at the root item in the driver item tree.

This method is available in Windows Me and in Windows XP and later.

See Also

IWiaDrvItem::FindChildItemByName, IWiaDrvItem::GetFullItemName


IWiaDrvItem::GetDeviceSpecContext

The IWiaDrvItem::GetDeviceSpecContext method gets a device-specific context.

HRESULT
  GetDeviceSpecContext(
    OUT BYTE  **ppSpecContext
    );

Parameters

ppSpecContext
Points to a memory location that will receive the address of a device-specific context.

Return Value

If the method succeeds, it stores a pointer to the device-specific context in ppSpecContext and returns S_OK. If the method fails because the parameter ppSpecContext specifies an invalid pointer, the method returns E_INVALIDARG. If the method fails for another reason, it returns a standard COM error code.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

Minidrivers typically use this method to obtain a pointer to a device-specific context associated with an IWiaDrvItem item. The device-specific context is associated with the item when the item is created using the driver services library function wiasCreateDrvItem.

This method is available in Windows Me and in Windows XP and later.

See Also

wiasCreateDrvItem


IWiaDrvItem::GetFirstChildItem

The IWiaDrvItem::GetFirstChildItem method gets the first child item in an IWiaDrvItem folder item.

HRESULT
  GetFirstChildItem(
    OUT IWiaDrvItem  **ppIChildItem
    );

Parameters

ppIChildItem
Points to a memory location that will receive the address of an IWiaDrvItem child item.

Return Value

If the method succeeds, it stores a pointer to the first child item in ppIChildItem and returns S_OK. If a child item cannot be found, the method returns S_FALSE. If the item being searched is not a folder, the method returns E_INVALIDARG. If the method fails for another reason, it returns a standard COM error code.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

Minidrivers typically use this method to retrieve the first child item in a driver item folder. The item being searched must be a folder item.

This method is available in Windows Me and in Windows XP and later.

See Also

IWiaDrvItem::GetNextSiblingItem, IWiaDrvItem::GetParentItem


IWiaDrvItem::GetFullItemName

The IWiaDrvItem::GetFullItemName method gets the item's full name, including path information.

HRESULT
  GetFullItemName(
    OUT BSTR  *pbstrFullItemName
    );

Parameters

pbstrFullItemName
Points to a memory location that will receive the address of a string containing the item's full name.

Return Value

If the method succeeds, it stores a pointer to the item's full name, including path information, in pbstrFullItemName and returns S_OK. If the method fails to allocate the string due to insufficient memory, it returns E_OUTOFMEMORY. If the parameter pbstrFullItemName is invalid, the method returns E_INVALIDARG. If the method fails for another reason, it returns a standard COM error code.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

If there is enough memory available, this method allocates a string containing the current item's full name including path information. The method returns a pointer to the string in pbstrFullItemName. The minidriver must deallocate the memory used by the string by calling the SysFreeString function, which is documented in the Platform SDK documentation.

The name returned in pbstrFullItemName is the name associated with the item when the item was first created by the driver services library function wiasCreateDrvItem.

This method is available in Windows Me and in Windows XP and later.

See Also

wiasCreateDrvItem


IWiaDrvItem::GetItemFlags

The IWiaDrvItem::GetItemFlags method gets the item flags of the current IWiaDrvItem item.

HRESULT
  GetItemFlags(
    OUT LONG  *plFlags
    );

Parameters

plFlags
Points to a memory location that will receive the item flags.

Return Value

If the method succeeds, it places the item flag values in the location pointed to by plFlags and returns S_OK. If the pointer plFlags is invalid, the method returns E_INVALIDARG. If the method fails for another reason, it returns a standard COM error code.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

The method places the current IWiaDrvItem item's flag values in the location pointed to by pIFlags. The item's flag values were set when the item was created by the driver services library function wiasCreateDrvItem.

This method is available in Windows Me and in Windows XP and later.

See Also

wiasCreateDrvItem


IWiaDrvItem::GetItemName

The IWiaDrvItem::GetItemName method gets the current IWiaDrvItem item name, not including path information.

HRESULT
  GetItemName(
    OUT BSTR  *pbstrItemName
    );

Parameters

pbstrItemName
Points to a memory location that will receive the address of the string containing the item name.

Return Value

If the method succeeds, it stores a pointer to the item's name (path information is not included) in pbstrItemName and returns S_OK. If the method fails to allocate the string due to insufficient memory, it returns E_OUTOFMEMORY. If the parameter pbstrItemName is invalid, the method returns E_INVALIDARG.If the method fails for another reason, it returns a standard COM error code.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

If there is enough memory available, the method allocates a string containing the current item's name, excluding path information. The method returns a pointer to the string in pbstrItemName. The minidriver must deallocate the memory used by the string by calling the SysFreeString function, which is documented in the Platform SDK.

This method is available in Windows Me and in Windows XP and later.

See Also

IWiaDrvItem::GetFullItemName


IWiaDrvItem::GetNextSiblingItem

The IWiaDrvItem::GetNextSiblingItem method gets the next sibling of the current item in an IWiaDrvItem folder.

HRESULT
  GetNextSiblingItem(
    OUT IWiaDrvItem  **ppISiblingItem
    );

Parameters

ppISiblingItem
Points to a memory location that will receive the address of the IWiaDrvItem object representing the next sibling item in a folder.

Return Value

If the method succeeds, it stores a pointer to the next sibling item in ppISiblingItem and returns S_OK. If there are no more items in the folder, the method returns S_FALSE. If the method fails, it returns a standard COM error code.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

Minidrivers obtain a pointer to the first child item in a folder by calling IWiaDrvItem::GetFirstChildItem. Minidrivers can then obtain the sibling items of this child item in the folder by making successive calls to IWiaDrvItem::GetNextSiblingItem.

This method is available in Windows Me and in Windows XP and later.

See Also

IWiaDrvItem::GetFirstChildItem, IWiaDrvItem::GetParentItem


IWiaDrvItem::GetParentItem

The IWiaDrvItem::GetParentItem gets the parent item of the current item.

HRESULT
  GetParentItem(
    OUT IWiaDrvItem  **ppIParentItem
    );

Parameters

ppIParentItem
Returns a pointer to the parent item of the current item.

Return Value

If the method succeeds, it stores a pointer to the parent item in pplParentItem and returns S_OK. If the parent item is the root item, the method returns S_FALSE. If the method fails, it returns a standard COM error code.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

Minidrivers typically use this method to obtain a pointer to the non-root parent item of the current item.

This method is available in Windows Me and in Windows XP and later.

See Also

IWiaDrvItem::GetFirstChildItem, IWiaDrvItem::GetNextSiblingItem


IWiaDrvItem::RemoveItemFromFolder

The IWiaDrvItem::RemoveItemFromFolder method removes an item from a parent folder.

HRESULT
  RemoveItemFromFolder(
    IN LONG  lReason
    );

Parameters

lReason
Specifies the reason for the removal of the item from the folder. This parameter can be set to one of the following values:
Value | Meaning
WiaItemTypeDeleted | The item is marked as deleted.
WiaItemTypeDisconnected | The item is a disconnected device.

Return Value

If the method succeeds, it returns S_OK. If the item to be removed is a folder and the folder is not empty, the method returns E_INVALIDARG. If lReason contains an invalid reason, the method returns E_INVALIDARG. If the method fails for another reason, it returns a standard COM error code.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

After the item has been removed from the folder, it can no longer be used for device access.

This method is available in Windows Me and in Windows XP and later.

See Also

IWiaDrvItem::AddItemToFolder


IWiaDrvItem::UnlinkItemTree

The IWiaDrvItem::UnlinkItemTree method unlinks the driver item tree and releases all items in the tree.

HRESULT
  UnlinkItemTree(
    IN LONG  lFlags
    );

Parameters

lFlags
Indicates how the driver item tree should be unlinked. This parameter must be set to one of the following values. See the Platform SDK documentation for a description of the WIA item type flags.
Value | Meaning
WiaItemTypeDeleted | The item is marked as deleted from the tree.
WiaItemTypeDisconnected | The item represents a disconnected device.

Return Value

If the method succeeds, it returns S_OK. If the method is called on a non-root item, it returns E_INVALIDARG. If the method fails for another reason, it returns a standard COM error code.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

Minidrivers must call this method on the root item in the driver item tree when they want to invalidate the tree. This is typically done when the driver is being unloaded or when the minidriver needs to rebuild the driver item tree.

This method is available in Windows Me and in Windows XP and later.


IWiaLog Interface and Diagnostic Log Macros

This section discusses WIA's diagnostic logging capabilities. It includes the following topics:

IWiaLog Interface

Diagnostic Log Macros


IWiaLog Interface

The IWiaLog interface provides methods to enable minidrivers to log trace, error, and warning messages to the diagnostic log file wiaservc.log. The prototypes for the methods appear in wia.h. The diagnostic log file wiaservc.log is found in the Windows directory, or in the directory returned by the GetWindowsDirectory system API call, which is described in the Platform SDK documentation.


IWiaLog::InitializeLog

The IWiaLog::InitializeLog method initializes the lWiaLog interface.

HRESULT
  InitializeLog(
    LONG  hInstance
    );

Parameters

hInstance
Specifies the module handle. This parameter indicates which module is calling the method.

Return Value

If the method succeeds, it returns S_OK. If the method fails, it returns a standard COM error code.

Headers

Declared in wia.h. Include wia.h.

Comments

The minidriver should use CoCreateInstance or CoCreateInstanceEx (documented in the Platform SDK documentation) to obtain the IWiaLog interface.

This method is available in Windows Me and in Windows XP and later.


IWiaLog::hResult

The IWiaLog::hResult method translates an HRESULT value into a string and writes the string to wiaservc.log.

HRESULT
  hResult(
    HRESULT  hResult
    );

Parameters

hResult
Specifies the HRESULT value to translate into a string.

Return Value

If the method succeeds, it returns S_OK. If the method fails, it returns a standard COM error code.

Headers

Declared in wia.h. Include wia.h.

Comments

This method is available in Windows Me and in Windows XP and later.


IWiaLog::Log

The IWiaLog::Log method writes a diagnostic log message to wiaservc.log.

HRESULT
  Log(
    LONG  lFlags,
    LONG  lResId,
    LONG  lDetail,
    BSTR  bstrText
    );

Parameters

lFlags
Specifies the type of diagnostic message. This parameter can be WIA_WARNING, WIA_TRACE or WIA_ERROR.
lResId
Specifies the resource id. This parameter should be set to WIALOG_NO_RESOURCE_ID.
lDetail
Specifies the diagnostic detail level of the message. This parameter can be one of the following values:
Level | Description
WIALOG_LEVEL1 | Log entry and exit points for all WIA methods and functions.
WIALOG_LEVEL2 | Log additional details for WIALOG_LEVEL1.
WIALOG_LEVEL3 | Log entry and exit points for all WIA methods and functions and additional vendor-supplied functions.
WIALOG_LEVEL4 | Log additional details for WIALOG_LEVEL3.
WIALOG_LEVELXXX | User-defined log levels.

bstrText
Specifies the error text. The error text should be prefixed with the full name of the method or function generating the message in the format of "class::method, error-text".

Return Value

If the method succeeds, it returns S_OK. If the method fails, it returns a standard COM error code.

Headers

Declared in wia.h. Include wia.h.

Comments

This method is available in Windows Me and in Windows XP and later.


Diagnostic Log Macros

In addition to the IWiaLog interface, WIA provides macros to enable minidrivers to log trace, error, and warning messages to the diagnostic log file wiaservc.log.


WIAS_LERROR

The WIAS_LERROR macro writes a diagnostic WIA_ERROR message to the log file.

WIAS_LERROR(
  IWiaLog  *pIWiaLog,
  LONG  lResId,
  (CONST CHAR  *format_string, ...)
  );

Parameters

pIWiaLog
Points to an IWiaLog interface.
lResId
Specifies the resource id. This value should be set to WIALOG_NO_RESOURCE_ID.
format_string, ...
Specifies a variable argument list, which starts with an ANSI format string describing the message and any format identifiers. The ... specifies a variable number of arguments that need to be output. The error text should be prefixed with the full name of the method or function generating the message in the format of "class::method, error-text".

Headers

Declared in wia.h. Include wia.h.

Comments

The following is an example of how the macro would be used:

WIAS_LERROR(g_pIWiaLog, WIALOG_NO_RESOURCE_ID,
    ("MyClass::MyMethod, This is my text and my lValue = %d", lValue));

This macro is available in Windows Me and in Windows XP and later.


WIAS_LHRESULT

The WIAS_LHRESULT macro translates an HRESULT value into a string and writes the string to the diagnostic log file.

WIAS_LHRESULT(
  IWiaLog  *pIWiaLog,
  HRESULT  hr
  );

Parameters

pIWiaLog
Points to an IWiaLog interface.
hr
Specifies the HRESULT value to be translated into a string.

Headers

Declared in wia.h. Include wia.h.

Comments

The following is an example of how the macro would be used:

hr = wiasFreePropContext(*pContext);
if (hr != S_OK)
   WIAS_LHRESULT(g_pIWiaLog, hr);

This macro is available in Windows Me and in Windows XP and later.


WIAS_LTRACE

The WIAS_LTRACE macro writes a diagnostic WIA_TRACE message to the log file.

WIAS_LTRACE(
  IWiaLog  *pIWiaLog,
  INT  ResourceID,
  INT  DetailLevel,
  (CONST CHAR *format_string, ...)
  );

Parameters

pIWiaLog
Points to an IWiaLog interface.
ResourceID
Specifies the resource id. This value should be set to WIALOG_NO_RESOURCE_ID.
DetailLevel
Specifies the diagnostic detail level of the message. This parameter can be one of the following values:
Level | Description
WIALOG_LEVEL1 | Log entry and exit points for all WIA methods and functions.
WIALOG_LEVEL2 | Log additional details for WIALOG_LEVEL1.
WIALOG_LEVEL3 | Log entry and exit points for all WIA methods and functions and additional vendor-supplied functions.
WIALOG_LEVEL4 | Log additional details for WIALOG_LEVEL3.
WIALOG_LEVELXXX | User-defined log levels.

format_string, ...
Specifies a variable argument list, which starts with an ANSI format string describing the message and any format identifiers. The ... specifies a variable number of arguments that need to be output. The error text should be prefixed with the full name of the method or function generating the message in the format of "class::method, error-text".

Headers

Declared in wia.h. Include wia.h.

Comments

The following is an example of how the macro would be used:

WIAS_LTRACE(g_pIWiaLog, WIALOG_NO_RESOURCE_ID, WIALOG_LEVEL2,
  ("MyClass::MyMethod, This is my text and my lValue = %d", lValue));

This macro is available in Windows Me and in Windows XP and later.


WIAS_LWARNING

The WIAS_LWARNING macro writes a diagnostic WIA_WARNING message to the log file.

WIAS_LWARNING(
  IWiaLog  *pIWiaLog,
  LONG  lResId,
  (CONST CHAR  *format_string, ...)
  );

Parameters

pIWiaLog
Points to an IWiaLog interface.
lResId
Specifies the resource id. This value should be set to WIALOG_NO_RESOURCE_ID.
format_string, ...
Specifies a variable argument list, which starts with an ANSI format string describing the message and any format identifiers. The ... specifies a variable number of arguments that need to be output. The error text should be prefixed with the full name of the method or function generating the message in the format of "class::method, error-text".

Headers

Declared in wia.h. Include wia.h.

Comments

The following is an example of how the macro would be used:

WIAS_LWARNING(g_pIWiaLog, WIALOG_NO_RESOURCE_ID,
  ("MyClass::MyMethod, This is my text and my lValue = %d", lValue));

This method is available in Windows Me and in Windows XP and later.


WIA Microdriver Functions, Structures, and Commands

This section describes Windows Image Acquisition (WIA) microdriver functions, structures, and commands, and WIA User Interface functions and structures. It contains the following sections:

WIA Microdriver Functions

WIA Microdriver Structures

WIA Microdriver Commands


WIA Microdriver Functions

The WIA Flatbed Driver handles requests from the WIA service by calling the WIA microdriver functions implemented in the microdriver. The microdriver must implement each of these functions.


MicroEntry

The MicroEntry function responds to commands sent by the WIA Flatbed driver.

HRESULT
  MicroEntry(
    LONG  lCommand,
    PVAL  pValue
    );

Parameters

lCommand
Specifies a command issued to the microdriver by the WIA Flatbed driver.
pValue
Points to a VAL structure that is used to pass information between the WIA Flatbed driver and the microdriver.

Return Value

If the function succeeds, it returns S_OK. If a passed command is not supported, the function returns E_NOTIMPL. For any error, error information must be put in the lVal member of the VAL structure pointed to by pValue.

Headers

Declared in wiamicro.h. Include wiamicro.h.

Comments

This function performs many different tasks depending on the command passed in the lCommand parameter. See the WIA Microdriver Commands reference section for a list of these commands.

Two structures are passed to the function. A VAL structure is passed in the pValue pointer, and the pScanInfo member of the VAL structure points to a SCANINFO structure. The VAL structure is used to pass information between the WIA Flatbed Driver and the microdriver. The SCANINFO structure is used to store and communicate parameters of a scan data acquisition. Many of the commands passed to this function set values in the SCANINFO structure.

This function is available in Windows Me and in Windows XP and later.

See Also

VAL, SCANINFO, WIA Microdriver Commands, WIA Microdriver Structures


Scan

The Scan function reads data from the device and returns the data to the WIA Flatbed driver.

HRESULT
  Scan(
    PSCANINFO  pScanInfo,
    LONG  lPhase,
    PBYTE  pBuffer,
    LONG  lLength,
    LONG  *pReceived
    );

Parameters

pScanInfo
Specifies the SCANINFO structure that represents the microdriver's settings. This is stored by the WIA Flatbed driver to guarantee that the settings between the microdriver and the WIA Flatbed driver are synchronized.
lPhase
Specifies the scan phase requested. This parameter can be set to one of the following values:
Value | Meaning
SCAN_FIRST | This signals the first phase of the scan. The microdriver performs three tasks: it initializes the device, it uses the data in the SCANINFO structure to set up the scan (for example, set the resolution, the start position, the width and the height on the device), and it starts the scan. Data must be returned from this call. Data must be put into the buffer pointed to by pBuffer and the pRecieved parameter must be set to the amount of data put in the buffer.
SCAN_NEXT | This will be repeatedly called during the data transfer. Data should be put into the buffer pointed to by pBuffer and the pRecieved parameter must be set to the amount of data put in the buffer.
SCAN_FINISHED This will be called at the end of the scan to terminate the scanning process. No data should be transferred. SCAN_FINISHED will always be called even if the user cancels the scan. The microdriver should stop transferring data and the scanner should be reset so that it is ready for the next scan.

The data returned from this function should be in raw format without any header. The data can be either packed or planar, aligned or unaligned, and in RGB or BGR order. Set the RawDataFormat, RawPixelOrder, and bNeedDataAlignment members of the SCANINFO structure appropriately in response to the CMD_INITIALIZE command.

pBuffer
Specifies the buffer that will be filled with scanned data by the microdriver. This buffer is allocated by the WIA Flatbed Driver and is guaranteed to be at least lLength bytes in length.
lLength
Specifies the requested amount of data that will be scanned. The microdriver must never overfill the buffer pointed to by pBuffer.
pReceived
Specifies the amount of data actually scanned into pBuffer. This value should never exceed the value of lLength, but can be less.

Return Value

If the function succeeds, it returns S_OK. If the function fails, it returns a standard COM error code.

Headers

Declared in wiamicro.h. Include wiamicro.h.

Comments

This function is available in Windows Me and in Windows XP and later.

See Also

SCANINFO, WIA Microdriver Commands, WIA Microdriver Structures


SetPixelWindow

The SetPixelWindow function sets the image area to be scanned.

HRESULT
  SetPixelWindow(
    PSCANINFO  pScanInfo,
    LONG  x,
    LONG  y,
    LONG  xExtent,
    LONG  yExtent
    );

Parameters

pScanInfo
Points to a SCANINFO structure that represents the current state of the device. This is stored by the WIA Flatbed driver to guarantee synchronized settings between the microdriver and the WIA Flatbed driver.
x
Specifies the horizontal position value for the left side of the selection rectangle in pixels.
y
Specifies the vertical position value for the top of the selection rectangle in pixels.
xExtent
Specifies the width of the selection rectangle in pixels.
yExtent
Specifies the height of the selection rectangle in pixels.

Return Value

If the function succeeds, it returns S_OK. If the function fails, it returns a standard COM error code.

Headers

Declared in wiamicro.h. Include wiamicro.h.

Comments

In this function, the microdriver should set up the Window member of the SCANINFO structure, making any device-specific adjustments that are necessary.

This function is available in Windows Me and in Windows XP and later.

See Also

SCANINFO, WIA Microdriver Structures


WIA Microdriver Structures

The WIA microdriver structures consist of the following:

RANGEVALUE

SCANINFO

SCANWINDOW

VAL


RANGEVALUE

The RANGEVALUE structure is used by a microdriver to communicate to the WIA Flatbed driver the legal values for a microdriver function parameter.

typedef struct _RANGEVALUE {
  LONG  lMin;
  LONG  lMax;
  LONG  lStep;
} RANGEVALUE, *PRANGEVALUE;

Members

lMin
Specifies the minimum value for a parameter.
lMax
Specifies the maximum value for a parameter.
lStep
Specifies the step value for a parameter.

Headers

Declared in wiamicro.h. Include wiamicro.h.

Comments

This structure is available in Windows Me and in Windows XP and later.


SCANINFO

The SCANINFO structure is used to store and communicate information about a scan acquisition. The WIA Flatbed Driver reads values from the SCANINFO structure, but never writes values. It is the microdriver's responsibility to set values for the SCANINFO members.

typedef struct _SCANINFO {
  LONG  ADF;
  LONG  TPA;
  LONG  Endorser;
  LONG  OpticalXResolution;
  LONG  OpticalYResolution;
  LONG  BedWidth;
  LONG  BedHeight;
  RANGEVALUE  IntensityRange;
  RANGEVALUE  ContrastRange;
  LONG  SupportedCompressionType;
  LONG  SupportedDataTypes;
  LONG  WidthPixels;
  LONG  WidthBytes;
  LONG  Lines;
  LONG  DataType;
  LONG  PixelBits;
  LONG  Intensity;
  LONG  Contrast;
  LONG  Xresolution;
  LONG  Yresolution;
  SCANWINDOW  Window;
  LONG  DitherPattern;
  LONG  Negative;
  LONG  Mirror;
  LONG  AutoBack;
  LONG  ColorDitherPattern;
  LONG  ToneMap;
  LONG  Compression;
  LONG  RawDataFormat;
  LONG  RawPixelOrder;
  LONG  bNeedDataAlignment;
  LONG  DelayBetweenRead;
  LONG  MaxBufferSize;
  HANDLE  DeviceIOHandles[MAX_IO_HANDLES];
  LONG  lReserved[MAX_RESERVED];
  VOID  *pMicroDriverContext;
} SCANINFO, *PSCANINFO;

Members

ADF
Indicates whether the scanner supports an Automatic Document Feeder (ADF). This member can be one of the following values:
Value | Meaning
0 | The scanner does not support an ADF.
1 | The scanner supports an ADF.
2 | The scanner supports an ADF with duplex capability.

TPA
Indicates whether the scanner supports TPA (TransParency Adapter). The value can be:

0 - not supported

1 - supported

Endorser
Indicates whether the scanner has endorser capabilities. The value can be:

0 - not supported

1 - supported

OpticalXResolution
Specifies the horizontal dpi setting of the scanner optics.
OpticalYResolution
Specifies the vertical dpi setting of the scanner optics.
BedWidth
Specifies the bed width of the scanner in thousandths of an inch.
BedHeight
Specifies the bed height of the scanner in thousandths of an inch.
IntensityRange
Specifies the intensity/brightness range values of the scanner.
ContrastRange
Specifies the contrast range values of the scanner.
SupportedCompressionType
Specifies a mask value of supported compression types. A value of zero indicates that no compression types are supported.
SupportedDataTypes
Specifies a mask value of supported data types. A value of zero indicates that no data types are supported. This member can be the bitwise OR of the following:
Value | Meaning
SUPPORT_BW | The image is 1 bit-per-pixel black and white.
SUPPORT_COLOR | The image is 24 bits-per-pixel color.
SUPPORT_GRAYSCALE | The image is 8 bits-per-pixel grayscale.

WidthPixels
Specifies the width of the current image in pixels.
WidthBytes
Specifies the width of the current image in bytes.
Lines
Specifies the height of the current image in pixels.
DataType
Specifies the current data type set of the current image. This member can be set to one of the following:
Value | Meaning
WIA_DATA_COLOR | The driver supports 24 bit-per-pixel color.
WIA_DATA_COLOR_DITHER | This value is not supported in the WIA Flatbed driver.
WIA_DATA_COLOR_THRESHOLD | This value is not supported in the WIA Flatbed driver.
WIA_DATA_DITHER | This value is not supported in the WIA Flatbed driver.
WIA_DATA_GRAYSCALE | The driver supports 8 bit-per-pixel grayscale.
WIA_DATA_THRESHOLD | The driver supports 1 bit-per-pixel black and white.

PixelBits
Specifies the current bit depth setting of the current image.
Intensity
Specifies the current intensity/brightness setting of the scanner.
Contrast
Specifies the current contrast setting of the scanner.
Xresolution
Specifies the current horizontal resolution setting of the scanner.
Yresolution
Specifies the current vertical resolution setting of the scanner.
Window
Specifies the current scanner window settings.
DitherPattern
Specifies the dither pattern of the scanner.
Negative
Specifies whether negative is on or off. The value can be:

0 - off

1 - on

Mirror
Specifies whether mirror is on or off. The value can be:

0 - off

1 - on

AutoBack
Specifies whether AutoBack is on or off. The value can be:

0 - off

1 - on

ColorDitherPattern
Reserved. Set to zero.
ToneMap
Reserved. Set to zero.
Compression
Specifies whether compression is on or off for the scanner. The value can be:

0 - off

1 - on

RawDataFormat
Specifies the raw data format for the scanner. The value can be:

0 - packed data

1 - planar data

RawPixelOrder
Specifies the pixel order for the scanner. The value can be:

0 - RGB

1 - BGR

bNeedDataAlignment
Specifies whether data alignment is needed for the scanner. The value can be:

0 - false

1 - true

DelayBetweenRead
Specifies the time delay in milliseconds between Scan function calls that the scanner can support.
MaxBufferSize
Specifies the maximum buffer size in the scanner.
DeviceIOHandles
Specifies an array of device IO handles needed for device communication.
lReserved
Specifies an array of reserved bits.
pMicroDriverContext
Points to the microdriver's context. This member is defined only for Microsoft® Windows® XP and later. The microdriver allocates the buffer pointed to by this member. The buffer should be allocated in CMD_INITIALIZE, and freed in CMD_UNINITIALIZE. (See Required Commands.) The WIA Flatbed driver knows nothing of this pointer, hence will not alter the memory pointed to by this member.

Headers

Declared in wiamicro.h. Include wiamicro.h.

Comments

This structure is used as a parameter in the microdriver's SetPixelWindow, and Scan functions.

This structure is available in Windows Me and in Windows XP and later.

See Also

SetPixelWindow, Scan


SCANWINDOW

The SCANWINDOW structure is used by the WIA Flatbed driver to tell the microdriver what image area to scan.

typedef struct _SCANWINDOW {
  LONG  xPos;
  LONG  yPos;
  LONG  xExtent;
  LONG  yExtent;
} SCANWINDOW, *PSCANWINDOW;

Members

xPos
Specifies the horizontal position of the left edge of the scan window in pixels.
yPos
Specifies the vertical position of the top edge of the scan window in pixels.
xExtent
Specifies the width of the scan window in pixels.
yExtent
Specifies the height of the scan window in pixels.

Headers

Declared in wiamicro.h. Include wiamicro.h.

Comments

This structure is available in Windows Me and in Windows XP and later.


VAL

The VAL structure is used by the microdriver and WIA Flatbed driver to pass information between each other.

typedef struct _VAL {
  LONG  lVal;
  DOUBLE  dblVal;
  GUID  *pGuid;
  PSCANINFO  pScanInfo;
  HGLOBAL  handle;
  WCHAR  **ppButtonNames;
  HANDLE  *pHandle;
  LONG  lReserved;
  CHAR szVal[MAX_ANSI_CHAR];
} VAL, *PVAL;

Members

lVal
Specifies a command value to return to the WIA Flatbed driver. See WIA Microdriver Commands for a list of available commands for this parameter.
dblVal
Specifies a command value to return to the WIA Flatbed driver. See WIA Microdriver Commands for a list of available commands for this parameter.
pGuid
Points to the GUID of the pressed button. If no button was pressed, this member points to GUID_NULL.
pScanInfo
Points to a SCANINFO structure.
handle
Specifies a handle of a ShutDownEvent that is signaled when the device is shut down or unloaded.
ppButtonNames
Specifies the address of a pointer to an array of button names.
pHandle
Points to an event handle.
lReserved
Reserved. Do not use.
szVal
Specifies the device name in ASCII form. If needed for interrupt checking, the microdriver can use this name to pass to CreateFile (described in the Platform SDK documentation) in order to obtain a file handle to the device.

Headers

Declared in wiamicro.h. Include wiamicro.h.

Comments

This structure is available in Windows Me and in Windows XP and later.


WIA Microdriver Commands

The following set of constants form the set of WIA microdriver commands. The commands are passed to the microdriver from the WIA Flatbed driver in the lCommand parameter of the MicroEntry function. The commands are grouped into the following categories:

  • Automatic Document Feeder Commands

    Commands for microdrivers that support an Automatic Document Feeder (ADF).

  • Event Commands

    Commands for microdriver event support.

  • Required Commands

    Commands that must be implemented by the microdriver.

  • Optional Commands

    Commands that can be implemented by the microdriver as enhancements to its basic operation.

These commands are defined in wiamicro.h, and are available in Windows Me and in Windows XP and later.


Automatic Document Feeder Commands

The commands in this section are for microdrivers that support an Automatic Document Feeder (ADF). To report that your microdriver supports an Automatic Document Feeder, set the ADF member in the SCANINFO structure to 1 during the CMD_INITIALIZE command. This will cause the WIA Flatbed driver to add the needed properties for ADF control and use the commands in this section.

CMD_LOAD_ADF
Called by the WIA Flatbed driver to load a page into the ADF. If this command does not apply to the device, return E_NOTIMPL.
CMD_UNLOAD_ADF
Called by the WIA Flatbed driver to unload a page from the ADF. If this command does not apply to the device, return E_NOTIMPL.
CMD_GETADFAVAILABLE
Called by the WIA Flatbed driver to determine whether an ADF is available for use. If an ADF is available, return S_OK. If this command does not apply to the device, return E_NOTIMPL.
CMD_GETADFHASPAPER
Called by the WIA Flatbed driver to get the paper status of the device's ADF. Set the lVal member of the passed VAL structure to the appropriate status value. (See CMD_ADFGETSTATUS for possible status values.)
CMD_GETADFOPEN
Same as CMD_GETADFREADY. This command is not currently used by the WIA Flatbed Driver.
CMD_GETADFSTATUS
Called by the WIA Flatbed driver to get the status of the ADF attached to the device. Set the lVal member of the passed VAL structure to the appropriate status value. Possible status values are:
Status | Meaning
MCRO_ERROR_GENERAL_ERROR | General error
MCRO_ERROR_OFFLINE | The ADF or device is offline.
MCRO_ERROR_PAPER_EMPTY | The ADF has no paper.
MCRO_ERROR_PAPER_JAM | The ADF has a paper jam.
MCRO_ERROR_PAPER_PROBLEM | The ADF has a paper problem.
MCRO_ERROR_USER_INTERVENTION | The user needs to interact with the device.
MCRO_STATUS_OK | There is no error to report.

CMD_GETADFUNLOADREADY
Called by the WIA Flatbed Driver to determine whether the ADF is ready for a page to be unloaded. If so, return S_OK. If this command does not apply to the device, return E_NOTIMPL.


Event Commands

The commands in this section are used by the microdriver for device event support.

CMD_GET_INTERRUPT_EVENT
Called by the WIA Flatbed Driver in a separate thread to monitor the status of button events that use interrupts from the device (that is, for USB devices that report events via the interrupt pipe). If your device only supports polling, this command does not need to be implemented, and E_NOTIMPL should be returned.

Two event handles are passed to the microdriver. The lVal member of the VAL structure holds an event handle that should be signaled by the microdriver using the SetEvent function when a button event occurs. The handle member of the VAL structure holds an event handle that will be signaled by the WIA Flatbed Driver when the driver is being unloaded or shut down.

The pGuid member of the VAL structure should be set to point to the GUID of the button that was pushed. If no button was pressed, it should be set to GUID_NULL.

CMD_STI_GETSTATUS
Called by the WIA Flatbed Driver to get the online status of the device and if the device has push buttons, to get the button status.

Set the lVal member of the passed VAL structure to 1 if your device is online, and functioning properly. If lVal is set to any value other than 1, the device is considered offline, and it will fail the device test in the control panel.

If the device supports buttons that do not use interrupts from the device and a button was pressed, the pGuid member of the passed VAL structure should be set to the GUID of the button event. If no buttons were pressed, point pGuid to the value GUID_NULL. This signals that there are no events pending.


Required Commands

The following set of required commands must be implemented by every microdriver.

CMD_GETCAPABILITIES
Called by the WIA Flatbed Driver to get button event information. Three members of the passed VAL structure should be filled in: lVal should be set to the number of buttons; pGuid should be set to an array of event GUIDs; ppButtonNames can optionally be set to a WCHAR* array that contains the button names in the same order as they are in pGuid (for example, "Scan Button" or "Fax Button"). If ppButtonNames is set to NULL, the WIA Flatbed Driver will create generic button names. The arrays can be allocated in response to CMD_INITIALIZE, and freed in CMD_UNINITIALIZE.
CMD_INITIALIZE
Called by the WIA Flatbed Driver to initialize the microdriver and set device IO handles to valid values. This command will be sent to the microdriver when the WIA service calls the method IWiaMiniDrv::drvInitializeWia on the WIA Flatbed Driver.

The WIA Flatbed Driver will automatically create one device IO handle and put it in the DeviceIOHandles array member of the passed SCANINFO structure at index 0. The microdriver should use this handle when it needs to communicate with the device. If the microdriver needs additional device handles (for example, to use multiple bulk USB pipes), they can be created and stored in the DeviceIOHandles array up to a maximum number of MAX_IO_HANDLES. The WIA Flatbed Driver will automatically close the handle at index 0, because it created that handle during initialization. The other handles must be closed by the microdriver in response to CMD_UNINITIALIZE.

As part of this command, the microdriver should also initialize all of the values in the SCANINFO structure. The microdriver should set the SupportedDataTypes, IntensityRange, ContrastRange, BedWidth, and BedHeight members of the SCANINFO structure, so that the WIA Flatbed Driver can automatically validate these values against the legal ranges for the device.

CMD_RESETSCANNER
Called by the WIA Flatbed Driver to reset the device in response to a WIA service request. The microdriver should set the device to its power-on state.
CMD_SETDATATYPE
Called by the WIA Flatbed Driver to set the data type for the scan. One of the following values is passed in the lVal member of the passed VAL structure:

WIA_DATA_THRESHOLD - 1-bit black/white

WIA_DATA_GRAYSCALE - 8-bit grayscale

WIA_DATA_COLOR - 24-bit color

The microdriver should store the value in the DataType member of the passed SCANINFO structure.

CMD_SETCONTRAST
Called by the WIA Flatbed Driver to set the contrast value for the scan. The desired contrast value is passed in the lVal member of the passed VAL structure. –1000 should be interpreted as the lowest contrast value, 0 nominal, and 1000 the device's maximum contrast. The microdriver should store the value in the Contrast member of the passed SCANINFO structure.
CMD_SETINTENSITY
Called by the WIA Flatbed Driver to set the intensity or brightness value for the scan. The desired intensity value is passed in the lVal member of the passed VAL structure. –1000 should be interpreted as the lowest brightness value, 0 nominal, and 1000 the device's maximum brightness. The microdriver should store the value in the Intensity member of the passed SCANINFO structure.
CMD_SETXRESOLUTION
Called by the WIA Flatbed Driver to set the horizontal scan resolution. The desired resolution in pixels is passed in the lVal member of the passed VAL structure. The microdriver should store the value in the XResolution member of the passed SCANINFO structure.
CMD_SETYRESOLUTION
Called by the WIA Flatbed Driver to set the vertical scan resolution. The desired resolution in pixels is passed in the lVal member of the passed VAL structure. The microdriver should store the value in the YResolution member of the passed SCANINFO structure.
CMD_STI_DEVICERESET
Called by the WIA Flatbed Driver to reset the device in response to a Still Image (STI) request. This command is typically called only once, during initialization.
CMD_STI_DIAGNOSTIC
Called by the WIA Flatbed Driver when the user requests a test of the device.
CMD_UNINITIALIZE
Uninitialize the microdriver and close Device IO handles. The WIA Flatbed Driver will automatically close the device IO handle in the DeviceIOHandles array member of the SCANINFO structure, at index 0. This command will be sent to the microdriver when the WIA Flatbed driver is unloading.


Optional Commands

The following commands can be implemented by the microdriver, but it is not required to do so.

CMD_GETSUPPORTEDFILEFORMATS
Called by the WIA Flatbed Driver to get the number of additional file formats. Two members of the passed VAL structure should be filled in: lVal should be set to the number of additional file formats; pGuid should point to an array of image format GUIDs. The memory allocated for this array is owned by the microdriver and should only be freed by it.

Image formats are listed in wiadef.h or can be defined as custom formats. Note that because the BMP (file) and MEMORYBMP (memory) formats are required formats, the WIA Flatbed Driver automatically adds them. The microdriver should not add them to its extended list.

CMD_GETSUPPORTEDMEMORYFORMATS
Called by the WIA Flatbed Driver to get the number of additional memory formats. Two members of the passed VAL structure should be filled in: lVal should be set to the number of additional memory formats; pGuid should point to an array of image format GUIDs. The memory allocated for this array is owned by the microdriver and should only be freed by it.

Image formats are listed in wiadef.h or can be defined as custom formats. Note that because the BMP (file) and MEMORYBMP (memory) formats are required formats, the WIA Flatbed Driver automatically adds them. The microdriver should not add them to its extended list.

CMD_SETSCANMODE
Called by the WIA Flatbed Driver to set the scan mode —preview or final — of the microdriver's device. The lVal member of the VAL structure will contain one of the following values, both of which are defined in wiamicro.h:

SCANMODE_PREVIEWSCAN - Preview scan mode

SCANMODE_FINALSCAN - Final scan mode

CMD_SETSTIDEVICEHKEY
Called by the WIA Flatbed Driver to allow the microdriver to read registry entries in the installed registry section. This command provides the STI device's installed registry HKEY to the microdriver, so that it can access private registry values for its device. The pHandle member of the VAL structure will contain a pointer to the HKEY given to the WIA Flatbed Driver during STI's IStiUSD::Initialize method. This is the top-level HKEY of the installed device section. The DeviceData key can be opened directly using this HKEY. See INF Files for WIA Devices for more information.

Note: This key is opened and closed only by the WIA Flatbed Driver. It is also valid only during this command and CMD_INITIALIZE (see Required Commands). After those commands return, the key is no longer valid. The HKEY value must not be cached.


WIA User Interface Extensions

This section describes WIA user interface extensions, which are provided so that device vendors can provide custom user interfaces for their devices.

Method prototypes and structure definitions can be found in wiadevd.h.

IWiaUIExtension Interface

WIA User Interface Extension Structures


IWiaUIExtension Interface

The IWiaUIExtension interface provides methods that replace the default system user interface, provide a custom device bitmap logo, and provide a custom device icon.

This interface includes the following methods:

IWiaUIExtension::DeviceDialog

IWiaUIExtension::GetDeviceBitmapLogo

IWiaUIExtension::GetDeviceIcon


IWiaUIExtension::DeviceDialog

The IWiaUIExtension::DeviceDialog method provides a custom user interface that replaces the default system user interface.

HRESULT
  DeviceDialog(
    IN PDEVICEDIALOGDATA  pDeviceDialogData
    ) PURE;

Parameters

pDeviceDialogData
Points to a DEVICEDIALOGDATA structure that contains all of the data needed to implement the device dialog.

Return Value

If the method succeeds, it returns S_OK. If the user cancels the dialog, the method returns S_FALSE. If the method is not implemented, it returns E_NOTIMPL. If the method fails, it returns a standard COM error code.

Headers

Declared in wiadevd.h. Include wiadevd.h.

Comments

If you implement the IWiaUIExtension interface and do not wish to replace the system user interface, this method must still be implemented, but it should do nothing more than return E_NOTIMPL.

This method is available in Windows Me and in Windows XP and later.

See Also

DEVICEDIALOGDATA


IWiaUIExtension::GetDeviceBitmapLogo

The IWiaUIExtension::GetDeviceBitmapLogo method gets a custom bitmap logo for the device.

HRESULT
  GetDeviceBitmapLogo(
    THIS_
    IN BSTR  bstrDeviceId,
    OUT HBITMAP  *phBitmap,
    IN ULONG  nMaxWidth,
    IN ULONG  nMaxHeight
    ) PURE;

Parameters

bstrDeviceId
Specifies the device ID of the device that is to obtain the bitmap logo.
phBitmap
Points to a memory location that will receive a handle for the bitmap logo for the device.
nMaxWidth
Specifies the desired width of the bitmap.
nMaxHeight
Specifies the desired height of the bitmap.

Return Value

If the method succeeds, it returns S_OK. If the method fails, it returns a standard COM error code.

Headers

Declared in wiadevd.h. Include wiadevd.h.

Comments

This method is available in Windows Me and in Windows XP and later.


IWiaUIExtension::GetDeviceIcon

The IWiaUIExtension::GetDeviceIcon method gets a custom device icon.

HRESULT
  GetDeviceIcon(
    THIS_
    IN BSTR  bstrDeviceId,
    OUT HICON  *phIcon,
    IN ULONG  nSize
    ) PURE;

Parameters

bstrDeviceId
Specifies the device ID of the device that will obtain the icon.
phIcon
Points to a memory location that will receive a handle for the icon for the device.
nSize
Specifies the desired icon size, in pixels.

Return Value

If the method succeeds, it returns S_OK. If the method fails, it returns a standard COM error code.

Headers

Declared in wiadevd.h. Include wiadevd.h.

Comments

The application can supply any icon size for the nSize parameter. The driver can do any of the following, listed from most to least desirable:

  • Use LoadImage to load an icon of the size requested in the nSize parameter.
  • Refuse to provide the size indicated in the nSize parameter by returning E_NOTIMPL.
  • Provide a standard-sized icon and ignore the nSize parameter.

After you load the icon, use CopyIcon to make a copy of the icon, and place the copy's handle in *phIcon. Doing this ensures that the icon resource remains valid after the DLL containing the resource is unloaded. It is the responsibility of the caller of the IWiaUIExtension::GetDeviceIcon method to release the copied icon using DestroyIcon.

The LoadImage, CopyIcon, and DestroyIcon functions are described in the Platform SDK documentation.

This method is available in Windows Me and in Windows XP and later.


WIA User Interface Extension Structures

This section describes the structures used with WIA user interface extensions.

DEVICEDIALOGDATA


DEVICEDIALOGDATA

The DEVICEDIALOGDATA structure contains all the data needed to implement a custom device dialog. This structure is used by the IWiaUIExtension::DeviceDialog method.

typedef struct _DEVICEDIALOGDATA {
  DWORD  cbSize;
  HWND  hwndParent;
  IWiaItem  *pIWiaItemRoot;
  DWORD  dwFlags;
  LONG  lIntent;
  LONG  lItemCount;
  IWiaItem  **ppIWiaItems;
} DEVICEDIALOGDATA, *LPDEVICEDIALOGDATA, *PDEVICEDIALOGDATA;

Members

cbSize
Specifies the size of this structure in bytes.
hwndParent
Specifies the handle to the parent window of the dialog.
pIWiaItemRoot
Points to an IWiaItem interface (defined in the Platform SDK documentation) that represents the valid root item in the application item tree.
dwFlags
Specifies the flags passed to IWiaItem::DeviceDlg and IWiaDevMgr::GetImageDlg by the calling program. These methods are described in the Platform SDK documentation. The possible values for this member are WIA_DEVICE_DIALOG_SINGLE_IMAGE and WIA_DEVICE_DIALOG_USE_COMMON_UI (defined in wiadef.h).
lIntent
Specifies the intents passed to IWiaItem::DeviceDlg and IWiaDevMgr::GetImageDlg by the calling program (see the Platform SDK documentation).
lItemCount
Specifies the number of items in the array to which ppIWiaItems points.
ppIWiaItems
Points to an array of IWiaItem interface pointers. The IWiaItem interface is defined in the Platform SDK documentation.

Headers

Declared in wiadevd.h. Include wiadevd.h.

Comments

The array specified in ppIWiaItems must be allocated using CoTaskMemAlloc. All interface pointers indicated in the array must be initialized using the AddRef COM method. See the Platform SDK documentation for descriptions of these funtions.

This structure is available in Windows Me and in Windows XP and later.

See Also

IWiaUIExtension::DeviceDialog


WIA Structures

This section describes the structures used with driver-level WIA methods and functions. These structures are defined in wiamindr.h and ptpusd.h.


MINIDRV_TRANSFER_CONTEXT

The MINIDRV_TRANSFER_CONTEXT structure is used to store image and other information needed for a memory-callback data transfer or a file data transfer.

typedef struct _MINIDRV_TRANSFER_CONTEXT {
  LONG  lSize;
  LONG  lWidthInPixels;
  LONG  lLines;
  LONG  lDepth;
  LONG  lXRes;
  LONG  lYRes;
  LONG  lCompression;
  GUID  guidFormatID;
  LONG  tymed;
  LONG  hFile;
  LONG  cbOffset;
  LONG  lBufferSize;
  LONG  lActiveBuffer;
  LONG  lNumBuffers;
  BYTE  *pBaseBuffer;
  BYTE  *pTransferBuffer;
  BOOL  bTransferDataCB;
  BOOL  bClassDrvAllocBuf;
  LONG  lClientAddress;
  IWiaMiniDrvCallBack  *pIWiaMiniDrvCallBack;
  LONG  lImageSize;
  LONG  lHeaderSize;
  LONG  lItemSize;
  LONG  cbWidthInBytes;
  LONG  lPage;
  LONG  lCurIfdOffset;
  LONG  lPrevIfdOffset;
} MINIDRV_TRANSFER_CONTEXT, *PMINIDRV_TRANSFER_CONTEXT;

Members

lSize
Specifies the size in bytes of this MINIDRV_TRANSFER_CONTEXT structure.
lWidthInPixels
Specifies the width in pixels of the current image. The value of this member is derived from the WIA_IPA_PIXELS_PER_LINE common item property, which is documented in the Platform SDK documentation.
lLines
Specifies the total number of lines (the number of horizontal rows of pixels) in the current image. The value of this member is derived from the WIA_IPA_LINES common item property (see the Platform SDK documentation).
lDepth
Specifies the color depth value of the current image in bits per pixel. The value of this member is derived from the WIA_IPA_DEPTH common item property (see the Platform SDK documentation).
lXRes
Specifies the current horizontal resolution of the image in pixels per inch. The value of this member is derived from the WIA_IPS_XRES scanner item property (see the Platform SDK documentation).
lYRes
Specifies the current vertical resolution of the image in pixels per inch. The value of this member is derived from the WIA_IPS_YRES scanner item property (see the Platform SDK documentation).
lCompression
Specifies the type of compression used by the device. The value of this member is derived from the WIA_IPA_COMPRESSION common item property (see the Platform SDK documentation).
guidFormatID
Specifies a GUID that indicates the data format for the device. The value of this member is derived from the WIA_IPA_FORMAT common item property (see the Platform SDK documentation).
tymed
Specifies the type of data transfer. The data transfer specified can be either a memory-callback transfer (TYMED_CALLBACK or TYMED_MULTIPAGE_CALLBACK) or file transfer (TYMED_FILE or TYMED_MULTIPAGE_FILE). The value of this member is derived from the WIA_IPA_TYMED common item property. See the Platform SDK documentation for more information about the TYMED_XXX constants and the WIA_IPA_TYMED property.

This member conveys information related to that in the bTransferDataCB member. See Comments for more information.

hFile
Specifies the handle to the open file used during file transfers. The minidriver should not use this member. See Comments for more information.
cbOffset
Specifies the current offset in bytes of the next buffer location used during this transfer.
lBufferSize
Specifies the total size of the transfer buffer.
lActiveBuffer
Specifies which buffer is used for the current transfer. The value of this member must be in the range of 1 through lNumBuffers.
lNumBuffers
Specifies the number of buffers available for data transfer. This value can currently be either 1 or 2.
pBaseBuffer
Points to the start of the base transfer buffer.
pTransferBuffer
Points to the start of the current transfer buffer. For a callback transfer in which double buffering is used, this member alternates between the two buffers, pointing to the beginning of the first buffer, and then to the beginning of the second, and so on.
bTransferDataCB
Specifies whether a data transfer is a memory-callback transfer or a file transfer. This member is set to TRUE if the transfer is a memory-callback transfer, and FALSE if the transfer is a file transfer. For file transfers, the WIA service usually provides a callback routine, which enables the application to receive updates from the minidriver about the status of the file transfer. (The WIA service provides a callback routine if the application provides its own callback routine. See IWiaMiniDrvCallback COM Interface for details.) For file transfers, a minidriver should check the value stored in the pIWiaMiniDrvCallBack member. If that member is NULL, the WIA service does not provide a callback routine, so the driver must not attempt to call it. For memory-callback transfers, the WIA service always provides a callback.

This member conveys information related to that in the tymed member. See Comments for more information.

bClassDrvAllocBuf
Specifies whether the WIA service has allocated the transfer buffer. This value is TRUE if the WIA service allocated the buffer, and FALSE if not. In that case, it is the minidriver's responsibility to allocate the transfer buffer.
lClientAddress
Specifies the address, in the client's address space, of the transfer. The minidriver must not change this value.
pIWiaMiniDrvCallBack
Points to an IWiaMiniDrvCallBack interface used for data or status callback transfer.
lImageSize
Specifies the size, in bytes, of uncompressed bits in a single page.
lHeaderSize
Specifies the size, in bytes, of image header data in a single page.
lItemSize
Specifies the size, in bytes, of bits and header. This value can be zero if the item size is unknown before acquisition.
cbWidthInBytes
Specifies the size, in bytes, of an image line.
lPage
Specifies the page number of the current page when scanning a multi-page TIFF image. Page numbering begins with zero.
lCurIfdOffset
Specifies the image file directory (IFD) offset in the current page of a multi-page TIFF image.
lPrevIfdOffset
Specifies the image file directory (IFD) offset in the previous page of a multi-page TIFF image.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

The WIA service sets most of the members of this structure before it calls the minidriver's IWiaMiniDrv::drvAcquireItemData method. If the minidriver calls wiasGetImageInformation, then that function fills in the remaining members of the MINIDRV_TRANSFER_CONTEXT passed to it.

Because the WIA service currently uses only the TYMED_FILE and TYMED_CALLBACK constants, the tymed and bTransferDataCB members store essentially the same information. For file transfers, when bTransferDataCB is set to FALSE, tymed is set to either TYMED_FILE or TYMED_MULTIPAGE_FILE. For memory-callback transfers, when bTransferDataCB is set to TRUE, tymed is set to either TYMED_CALLBACK or TYMED_MULTIPAGE_CALLBACK.

The hFile member is reserved for use solely by the WIA service. Rather than using this member for file transfers, the minidriver should instead write the data to a buffer, and then call wiasWritePageBufToFile to complete the file transfer.

The minidriver obtains values from specific common or scanner item properties to set the members shown in the following table:

Member | Common or Scanner Item Property Used to Set this Member
lWidthInPixels | WIA_IPA_PIXELS_PER_LINE
lLines | WIA_IPA_NUMBER_OF_LINES
lDepth | WIA_IPA_DEPTH
lXRes | WIA_IPS_XRES
lYRes | WIA_IPS_YRES
lCompression | WIA_IPA_COMPRESSION
guidFormatID | WIA_IPA_FORMAT
tymed | WIA_IPA_TYMED

Usually, the minidriver sets the preceding structure members directly from the values of the item properties. An application or the minidriver will have set the item properties earlier. The WIA service fills in its service context, using the property values. The driver can use the values stored in this context for quick reference.

The WIA service sets the following structure members:

  • hFile
  • bTransferDataCB
  • bClassDrvAllocBuf

Either the minidriver or the wiasGetImageInformation service library function sets the following structure members:

  • lImageSize
  • lHeaderSize
  • lItemSize
  • cbWidthInBytes

The following members of this structure are used in data transfer callbacks. The WIA service or the minidriver sets these members. In several cases, the value stored in bClassDrvAllocBuf determines whether the WIA service or the minidriver sets the member.

Member | Set by?
cbOffset | Minidriver
lBufferSize | WIA service or minidriver If bClassDrvAllocBuf is TRUE, the WIA service sets this member; otherwise, the minidriver sets it.
lActiveBuffer | WIA service The minidriver must not modify this member.
lNumBuffers | WIA service The minidriver must not modify this member.
pBaseBuffer | WIA service or minidriver If bClassDrvAllocBuf is TRUE, the WIA service sets this member; otherwise, the minidriver sets it.
pTransferBuffer | WIA service or minidriver If bClassDrvAllocBuf is TRUE, the WIA service sets this member; otherwise, the minidriver sets it.
lClientAddress | WIA service The minidriver must not modify this member.
pIWiaMiniDrvCallBack | WIA service

This structure is available in Windows Me and in Windows XP and later.

See Also

IWiaMiniDrvCallBack::MiniDrvCallback, IWiaMiniDrv::drvAcquireItemData, wiasGetImageInformation, wiasWritePageBufToFile


PTP_VENDOR_DATA_IN

The PTP_VENDOR_DATA_IN structure contains information about an arbitrary command that an application issues to the device.

typedef struct _PTP_VENDOR_DATA_IN {
  WORD  OpCode;
  DWORD  SessionId;
  DWORD  TransactionId;
  DWORD  Params[PTP_MAX_PARAMS];
  DWORD  NumParams;
  DWORD  NextPhase;
  BYTE  VendorWriteData[1];
} PTP_VENDOR_DATA_IN, *PPTP_VENDOR_DATA_IN;

Members

OpCode
Specifies the command opcode. These codes are defined in the PIMA 15740:2000 standard.
SessionId
Specifies the session ID. This member is not currently used by the PTP driver and should be set to 0.
TransactionId
Specifies the transaction ID. This member is not currently used by the PTP driver and should be set to 0.
Params
Is an array consisting of PTP_MAX_PARAMS (defined in ptpusd.h) elements, representing the parameters of the command.
NumParams
Specifies the actual number of elements in the Params array.
NextPhase
Indicates whether to read data from the device, write data to the device, or neither. This member can be set to one of the following values:
Value | Meaning
PTP_NEXTPHASE_NO_DATA | No data is to be read from or written to the device.
PTP_NEXTPHASE_READ_DATA | Read data from the device.
PTP_NEXTPHASE_WRITE_DATA | Write data to the device.

VendorWriteData
Is an array containing an (optional) first byte to write to the device.

Headers

Declared in ptpusd.h. Include ptpusd.h.

Comments

See Vendor-Extended Commands for more information and example code that uses this structure.

For more information about the opcodes used in the OpCode member, see PIMA 15740:2000, Photography – Electronic still picture imaging – Picture Transfer Protocol (PTP) for Digital Still Photography Devices, First Edition, July 5, 2000, http://www.pima.net/standards/it10/PIMA15740/.

This structure is available in Windows Me and in Windows XP and later.

See Also

PTP_VENDOR_DATA_OUT


PTP_VENDOR_DATA_OUT

The PTP_VENDOR_DATA_OUT structure contains information that the device sends to an application, in response to a command the application issued to the device.

typedef struct _PTP_VENDOR_DATA_OUT {
  WORD  ResponseCode;
  DWORD  SessionId;
  DWORD  TransactionId;
  DWORD  Params[PTP_MAX_PARAMS];
  BYTE  VendorReadData[1];
}PTP_VENDOR_DATA_OUT, *PPTP_VENDOR_DATA_OUT;

Members

ResponseCode
Specifies the response code. These codes are defined in the PIMA 15740:2000 standard.
SessionId
Specifies the session ID. This member is not currently used by the PTP driver and should be set to 0.
TransactionId
Specifies the transaction ID. This member is not currently used by the PTP driver and should be set to 0.
Params
Is an array consisting of PTP_MAX_PARAMS (defined in ptpusd.h) elements, representing the parameters of the response.
VendorReadData
Is an array containing an (optional) first byte to read from the device.

Headers

Declared in ptpusd.h. Include ptpusd.h.

Comments

See Vendor-Extended Commands for more information and example code that uses this structure.

For more information about the response codes used in the ResponseCode member, see PIMA 15740:2000, Photography – Electronic still picture imaging – Picture Transfer Protocol (PTP) for Digital Still Photography Devices, First Edition, July 5, 2000, http://www.pima.net/standards/it10/PIMA15740/.

This structure is available in Windows Me and in Windows XP and later.

See Also

PTP_VENDOR_DATA_IN


TWAIN_CAPABILITY

The TWAIN_CAPABILITY structure holds information used when a TWAIN-compatible application communicates with a WIA driver.

typedef struct _TWAIN_CAPABILITY {
  LONG  lSize;
  LONG  lMSG;
  LONG  lCapID;
  LONG  lConType;
  LONG  lRC;
  LONG  lCC;
  LONG  lDataSize;
  BYTE  Data[1];
} TWAIN_CAPABILITY,*PTWAIN_CAPABILITY;

Members

lSize
Specifies the size, in bytes, of the TWAIN_CAPABILITY structure.
lMSG
Specifies the particular TWAIN message, which can be one of the following values:
Value | Meaning
MSG_GET | Get a capability.
MSG_GETCURRENT | Get the current capability.
MSG_GETDEFAULT | Get the default capability.
MSG_RESET | Reset the capability.
MSG_SET | Set a capability.

lCapID
Specifies the ID of the capability to set or get.
lConType
Specifies the capability's container type.
lRC
Specifies the TWAIN return code. This value can be on of the following:
Value | Meaning
TWRC_FAILURE | The capability specified by the lCapID member is not supported.
TWRC_SUCCESS | The capability specified by the lCapID member is supported.
Other TWRC_XXX return code | See the Comments section.

lCC
Specifies the TWAIN condition code. This value can be one of the following:
Value | Meaning
TWCC_BUMMER | The operation failed for an unknown reason.
TWCC_SUCCESS | The operation was successful.
TWCC_XXX | See the Comments section.

lDataSize
Specifies the size, in bytes of the data in the Data array.
Data
Is an array that contains the capability data. The actual size, in bytes, of the array is indicated by the lDataSize member.

Headers

Declared in wiatwcmp.h. Include wiatwcmp.h.

Comments

A TWAIN-capable application communicates with a WIA driver by way of the TWAIN compatibility later to find out whether the driver has any private capabilities, and if so, what they are. A TWAIN_CAPABILITY structure is used in this communication. For more information, see Support for TWAIN-Compatible Applications.

The TWAIN return codes and control codes are defined in twain.h, which can be obtained from the TWAIN Working Group (http://www.twain.org).

This structure is available in Windows Me and in Windows XP and later.


WIA_DEV_CAP_DRV

The WIA_DEV_CAP_DRV structure is used to enumerate device capabilities. A device capability is defined by an event or command that the device supports.

typedef struct _WIA_DEV_CAP_DRV {
  GUID  *guid;
  ULONG  ulFlags;
  LPOLESTR  wszName;
  LPOLESTR  wszDescription;
  LPOSESTR  wszIcon;
} WIA_DEV_CAP_DRV,*PWIA_DEV_CAP_DRV;

Members

guid
Points to a GUID that identifies the device capability. This member can be set to any of the values specified for WIA device commands (WIA_CMD_XXX commands) or WIA event identifiers (WIA_EVENT_XXX event identifiers). See the Platform SDK documentation for more information.

The driver can define its own capability GUID that it can send down to the device. An application would need to have specific knowledge about that capability in order for it to be able to respond to the new capability, however. An application normally recognizes only the standard WIA command and event GUIDs (WIA_CMD_XXX and WIA_EVENT_XXX).

ulFlags
Specifies the type of event. This member can be set to one of the following:
Flag Meaning
WIA_ACTION_EVENT
WIA_NOTIFICATION_EVENT

wszName
Specifies a string that contains a short version of the capability name.
wszDescription
Specifies a string containing the version of the capability name that can be displayed to the user.
wszIcon
Specifies a string containing the name of the icon for this capability. The icon can be displayed to the user .

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

The WIA service calls the minidriver's IWiaMiniDrv::drvGetCapabilities function to fill in the members of a WIA_DEV_CAP_DRV structure.

This structure is available in Windows Me and in Windows XP and later.

See Also

IWiaMiniDrv::drvGetCapabilities


WIA_PROPERTY_CONTEXT

The WIA_PROPERTY_CONTEXT structure stores property identifiers and their context.

typedef struct _WIA_PROPERTY_CONTEXT {
  ULONG  cProps;
  PROPID  *pProps;
  BOOL  *pChanged;
} WIA_PROPERTY_CONTEXT, *PWIA_PROPERTY_CONTEXT;

Members

cProps
Specifies the number of property identifiers stored in this structure.
pProps
Is an array of property identifiers that indicate the properties being written.
pChanged
Is an array of Boolean values indicating which properties are changing. A member of this array is TRUE if the corresponding property is changing, and FALSE if the corresponding property is not changing. That is, if pChanged[n] is TRUE, pProps[n] will be changed, and if pChanged[n] is FALSE, pProps[n] will not be changed.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

The Boolean values indicate whether the corresponding property is being written (changed) by an application calling IPropertyStorage::WriteMultiple, which is described in the Platform SDK documentation.

Several WIA service library functions use the WIA_PROPERTY_CONTEXT structure. The wiasCreatePropContext and wiasFreePropContext functions use it when a property context is created or freed. The wiasIsPropChanged and wiasSetPropChanged use this structure to determine whether a property changed, and to modify a property context when the property does change. The wiasGetChangedValue Xxx functions use this structure to determine whether a property of a certain type has changed. The wiasUpdateValidFormat and wiasUpdateScanRect use it to, respectively, update a property context and to update the scanning area sizes for a scanning device.

This structure is available in Windows Me and in Windows XP and later.

See Also

wiasCreatePropContext, wiasFreePropContext, wiasIsPropChanged, wiasSetPropChanged, wiasGetChangedValueFloat, wiasGetChangedValueGuid, wiasGetChangedValueLong, wiasGetChangedValueStr, wiasUpdateValidFormat, wiasUpdateScanRect


WIA_PROPERTY_INFO

The WIA_PROPERTY_INFO structure is used to store default access and valid value information for an item property of arbitrary type.

typedef struct _WIA_PROPERTY_INFO {
  ULONG  lAccessFlags;
  VARTYPE  vt;
  union {
    struct {
        LONG  Min;
        LONG  Nom;
        LONG  Max;
        LONG  Inc;
    } Range;
    struct {
        DOUBLE  Min;
        DOUBLE  Nom;
        DOUBLE  Max;
        DOUBLE  Inc;
    } RangeFloat;
    struct {
       LONG  cNumList;
       LONG  Nom;
       BYTE  *pList;
    } List;
    struct {
       LONG  cNumList;
       DOUBLE  Nom;
       BYTE  *pList;
    } ListFloat;
    struct {
       LONG  cNumList;
       GUID  Nom;
       GUID  *pList;
    } ListGuid;
    struct {
       LONG  cNumList;
       BSTR  Nom;
       BSTR  *pList;
    } ListBStr;
    struct {
       LONG  Nom;
       LONG  ValidBits;
    } Flag;
    struct {
      LONG  Dummy;
    } None;
  } ValidVal;
} WIA_PROPERTY_INFO, *PWIA_PROPERTY_INFO;

Members

lAccessFlags
Specifies the access and property attribute flags for a property. See the Platform SDK documentation for a list of WIA property attribute flags.
vt
Specifies the variant data type for the property. This member, which can be one of the following, controls which structure member of the ValidVal union is valid:

VT_UI1

VT_UI2

VT_UI4

VT_I2

VT_I4

VT_R4

VT_R8

VT_CLSID

VT_BSTR

See PROPVARIANT in the Platform SDK documentation for more information.

Range
Is a structure that is filled when the property's valid values are specified by a range of integer values. This structure contains the following members:

Min, which indicates the minimum value of the property.

Max, which indicates the maximum value of the property.

Nom, which indicates the property's nominal value.

Inc, which indicates the increment value that can be used.

RangeFloat
Is a structure that is filled when the property's valid values are specified by a range of floating point values and the property type is a float or double. This structure contains the following members:

Min, which indicates the minimum value of the property.

Max, which indicates the maximum value of the property.

Nom, which indicates the property's nominal value.

Inc, which indicates the increment value that can be used.

List
Is a structure that is filled when the property's valid values are specified by a list of integer values. This structure contains the following members:

cNumList, which indicates the number of elements in the array of valid values to which pList points.

Nom, which indicates the nominal value of the property.

pList, which is an array of valid values the property can be set to.

ListFloat
Is a structure that is filled when the property's valid values are specified by a list of floating point values. This structure contains the following members:

cNumList, which indicates the number of elements in the array of valid values to which pList points.

Nom, which indicates the nominal value of the property.

pList, which is an array of valid values the property can be set to.

ListGuid
Is a structure that is filled when the property's valid values are specified by a list of GUIDs. This structure contains the following members:

cNumList, which indicates the number of elements in the array of valid values to which pList points.

Nom, which indicates the nominal value of the property.

pList, which is an array of valid values the property can be set to.

ListBStr
Is a structure that is filled when the property's valid values are specified by a list of strings. This structure contains the following members:

cNumList, which indicates the number of elements in the array of valid values to which pList points.

Nom, which indicates the nominal value of the property.

pList, which is an array of valid values the property can be set to.

Flag
Is a structure that is filled when the property's valid values are specified by a bitset of flags. This structure contains the following members:

Nom, which indicates the nominal value of the property.

ValidBits, which is a mask indicating which bit values can be set. This member should be a bit-wise OR of all possible user-defined flag values.

None
Is a structure that is filled when the property's valid values are not given in a list, range, or bitset. This structure contains a member named Dummy, which indicates the property is of type NONE.
ValidVal
Is a union of the preceding structures. Its members are: Range, RangeFloat, List, ListFloat, ListGuid, ListBStr, Flag, and None.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

The WIA_PROPERTY_INFO is used by the minidriver to store information about a property of arbitrary type. This structure is also used by the wiasSetItemPropAttribs to set a property's valid values. The lAccessFlags member controls whether access to a property is read-only or read/write. This member also conveys information about the set of valid values for a property when they are defined by a list of values, a range of values, or a bitset of flags. The vt member contains information about the type of the property. Both members should be used to determine which member of the ValidVal union can be accessed.

For example, for a read/write property of type long, whose valid values are integers in the range -128 to 127, and whose nominal value is 0, lAccessFlags would be set to WIA_PROP_RW | WIA_PROP_RANGE, and vt would be set to VT_I4. Range.Min would be set to -128, Range.Max would be set to 127, and Range.Inc would be set to 1. Range.Nom would be set to 0.

For a different property whose valid values are defined by a list of three GUID values, lAccessFlags would have its WIA_PROP_LIST bit set, and vt would be set to VT_CLSID. ListGuid.cNumList would be set to 3, and the three GUIDs are ListGuid.pList[0], ListGuid.pList[1], and ListGuid.pList[2].

A property whose valid values are defined by a bitset of the values 0x01, 0x02, 0x04, and 0x08 would have the WIA_PROP_FLAG bit set in lAccessFlags, and vt would be set to VT_UI4. For such a property, the value stored in Flag.ValidBits would be 0x0F, the bitwise OR of the four flag values previously mentioned.

This structure is available in Windows Me and in Windows XP and later.

See Also

wiasSetItemPropAttribs


WIAS_CHANGED_VALUE_INFO

The WIAS_CHANGED_VALUE_INFO structure is used to store the current and previous values of a property.

typedef struct _WIAS_CHANGED_VALUE_INFO {
  BOOL  bChanged;
  LONG  vt;
  union {
    LONG  lVal;
    FLOAT fltVal;
    BSTR  bstrVal;
    GUID  guidVal;
  } Old;
  union {
    LONG  lVal;
    FLOAT fltVal;
    BSTR  bstrVal;
    GUID  guidVal;
  } Current;
} WIAS_CHANGED_VALUE_INFO, *PWIAS_CHANGED_VALUE_INFO;

Members

bChanged
Is a Boolean that indicates whether a property has changed. That is, if the property's current value is different from its value before IWiaMiniDrv::drvValidateItemProperties was called. Upon return from one of the wiasGetChangedValue Xxx functions, this member is TRUE if the property changed, and FALSE if the property did not change.
vt
Specifies the variant data type for the property. This member can be one of the following:

VT_UI1

VT_UI2

VT_UI4

VT_I2

VT_I4

VT_R4

VT_R8

VT_CLSID

VT_BSTR

See the PROPVARIANT structure in the Platform SDK documentation for more information.

Old
Specifies the previous value of the property. This member is a union consisting of the following members. The particular union member used must be consistent with the type specified in the vt member.

lVal - the property type is LONG.

fltVal - the property type is a floating point type.

bstrVal - the property type is BSTR.

guidVal - the property type is GUID.

Current
Specifies the current value of the property. This member is a union consisting of the following members. The particular union member used must be consistent with the type specified in the vt member.

lVal - the property type is LONG.

fltVal - the property type is a floating point type.

bstrVal - the property type is BSTR.

guidVal - the property type is GUID.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

The wiasGetChangedValue Xxx functions, use this structure to determine whether a property of a certain type has been changed by an application. These functions are used when the minidriver performs property validation, which occurs within the body of IWiaMiniDrv::drvValidateItemProperties.

This structure is available in Windows Me and in Windows XP and later.

See Also

IWiaMiniDrv::drvValidateItemProperties, wiasGetChangedValueFloat, wiasGetChangedValueGuid, wiasGetChangedValueLong, wiasGetChangedValueStr


WIAS_DOWN_SAMPLE_INFO

The WIAS_DOWN_SAMPLE_INFO structure stores information used by the downsampling helper function, wiasDownSampleBuffer.

typedef struct _WIAS_DOWN_SAMPLE_INFO {
    ULONG  ulOriginalWidth;
    ULONG  ulOriginalHeight;
    ULONG  ulBitsPerPixel;
    ULONG  ulXRes;
    ULONG  ulYRes;
    ULONG  ulDownSampledWidth;
    ULONG  ulDownSampledHeight;
    ULONG  ulActualSize;
    ULONG  ulDestBufSize;
    ULONG  ulSrcBufSize;
    BYTE  *pSrcBuffer;
    BYTE  *pDestBuffer;
} WIAS_DOWN_SAMPLE_INFO, *PWIAS_DOWN_SAMPLE_INFO;

Members

ulOriginalWidth
Specifies the width, in pixels, of the input data.
ulOriginalHeight
Specifies the height, in pixels, of the input data.
ulBitsPerPixel
Specifies the number of bits per pixel of the input data.
ulXRes
Specifies the horizontal resolution of the input data.
ulYRes
Specifies the vertical resolution of the input data.
ulDownSampledWidth
Specifies the width, in pixels, of the output data.
ulDownSampledHeight
Specifies the width, in pixels, of the output data.
ulActualSize
Specifies the number of bytes placed in the destination buffer.
ulDestBufSize
Specifies the size, in bytes, of the destination buffer.
ulSrcBufSize
Specifies the size, in bytes, of the source buffer.
pSrcBuffer
Points to the source buffer.
pDestBuffer
Points to the destination buffer.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

This structure is available in Windows Me and in Windows XP and later.

See Also

wiasDownSampleBuffer


WIAS_ENDORSER_INFO

The WIAS_ENDORSER_INFO structure holds custom endorser token/value pairs.

typedef struct _WIAS_ENDORSER_INFO {
  ULONG  ulPageCount;
  ULONG  ulNumEndorserValues;
  WIAS_ENDORSER_VALUE  *pEndorserValues;
} WIAS_ENDORSER_INFO, *PWIAS_ENDORSER_INFO;

Members

ulPageCount
Specifies the value that will replace the $PAGE_COUNT$ token, provided that the endorser string contains that token.
ulNumEndorserValues
Specifies the number of token/value pairs. This member will be 0 if there are no custom token/value pairs.
pEndorserValues
Points to an array of WIAS_ENDORSER_VALUE structures, holding custom token/value pairs. If the value of the ulNumEndorserValues member is 0, this member should be NULL.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

Currently, wiasParseEndorserString recognizes three endorser tokens: $DATE$, $TIME$, $PAGE_COUNT$, $DAY$, $MONTH$, and $YEAR$. (See wiamdef.h.) Any other tokens and their values must be specified in the pEndorserValues member of this structure.

This structure is available in Windows Me and in Windows XP and later.

See Also

wiasParseEndorserString, WIAS_ENDORSER_VALUE


WIAS_ENDORSER_VALUE

The WIAS_ENDORSER_VALUE structure stores token/value pairs for endorser strings.

typedef struct _WIAS_ENDORSER_VALUE {
  LPWSTR  wszTokenName;
  LPWSTR  wszValue;
} WIAS_ENDORSER_VALUE, *PWIAS_ENDORSER_VALUE;

Members

wszTokenName
Specifies a string value that represents the token name. Endorser token names begin and end with the $ character (for example, L"$MY_TOKEN_NAME$").
wszValue
Specifies the value with which to replace the token.

Headers

Declared in wiamindr.h. Include wiamindr.h.

Comments

This structure is used indirectly by the wiasParseEndorserString function. One of the parameters of this function is a WIAS_ENDORSER_INFO structure, which has a WIAS_ENDORSER_VALUE structure as one of its members.

This structure is available in Windows Me and in Windows XP and later.

See Also

wiasParseEndorserString, WIAS_ENDORSER_INFO


Still Image Interfaces

This section includes the following sections:

IStillImage Interface Methods

IStiDevice Interface Methods

IStiUSD Interface Methods

IStiDeviceControl Interface Methods

Still Image Structures

Still Image Data Types

SCSI Still Image I/O Control Codes

SCSI Still Image Structures

USB Still Image I/O Control Codes

USB Still Image Structures

USB Still Image Data Types


IStillImage Interface Methods

This section describes the methods defined for the IStillImage COM interface. Method prototypes are contained in sti.h.


IStillImage::CreateDevice

The IStillImage::CreateDevice method creates an instance of the COM object that defines the IStiDevice COM interface, and returns a pointer to the interface.

HRESULT
  CreateDevice(
    LPWSTR  pwszDeviceName,
    DWORD  dwMode,
    PSTIDEVICE  *pDevice,
    LPUNKNOWN  punkOuter
    );

Parameters

pwszDeviceName
Caller-supplied pointer to a string representing an internal device name, obtained by calling IStillImage::GetSTILaunchInformation or IStillImage::GetDeviceList.
dwMode
Caller-supplied constant value indicating the transfer mode in which the device is to be used. The following values are valid.
Mode | Description
STI_DEVICE_CREATE_BOTH | The device is being opened for both obtaining status and transferring data.
STI_DEVICE_CREATE_DATA | The device is being opened only for data transfers.
STI_DEVICE_CREATE_STATUS | The device is being opened only for obtaining status information.

pDevice
Receives a pointer to the IStiDevice COM interface.
punkOuter
Optional, caller-supplied pointer to the "controlling unknown" for object aggregation. See the following Comments section.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

For an application to use the IStiDevice interface, it must first call IStillImage::StiCreateInstance to get a pointer to the IStillImage interface, then call IStillImage::CreateDevice to get a pointer to the IStiDevice interface. The pointer received in pDevice is used subsequently when calling IStiDevice methods, as illustrated in the sample still image code, to obtain access to the specified device.

If you want to create an aggregate COM object that includes IStiDevice, you must supply a pointer to the "controlling unknown" in punkOuter. In most cases you will not be creating an aggregate object, so punkOuter should be NULL. Object aggregation and the controlling unknown are described in the Platform SDK documentation and in the Component Object Model Specification.

See Also

IStiDevice::Release


IStillImage::EnableHwNotifications

The IStillImage::EnableHwNotifications method requests the Still Image Event Monitor to enable or disable the notification of applications when still image device events occur for a specified device.

HRESULT
  EnableHwNotifications(
    LPCWSTR  pwszDeviceName,
    BOOL  bNewState
    );

Parameters

pwszDeviceName
Caller-supplied pointer to a string representing an internal device name, obtained by calling IStillImage::GetSTILaunchInformation or IStillImage::GetDeviceList.
bNewState
Caller-supplied value, set to TRUE to enable notifications and FALSE to disable them.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

The IStillImage::EnableHwNotifications method enables or disables notifications of still image device events for all applications, not just for the calling application. Event notifications are enabled by default. This method is meant for use by applications that intercept events from devices and re-route them.

Before calling IStillImage::EnableHwNotifications, clients of the IStillImage COM interface must call IStillImage::StiCreateInstance to obtain an IStillImage interface pointer.

See Also

IStillImage::LaunchApplicationForDevice


IStillImage::GetDeviceInfo

The IStillImage::GetDeviceInfo method returns hardware characteristics for a specified still image device.

HRESULT
  GetDeviceInfo(
    LPWSTR  pwszDeviceName,
    LPVOID  *ppBuffer
    );

Parameters

pwszDeviceName
Caller-supplied pointer to a string representing an internal device name, obtained by calling IStillImage::GetSTILaunchInformation or IStillImage::GetDeviceList.
ppBuffer
Receives a handle to an STI_DEVICE_INFORMATION structure.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

The IStillImage::GetDeviceInfo method returns an STI_DEVICE_INFORMATION structure for the specified still-image device. Structure contents are typically used for creating user interface displays.

Before calling IStillImage::GetDeviceInfo, clients of the IStillImage COM interface must call IStillImage::StiCreateInstance to obtain an IStillImage interface pointer.

When the caller has finished using the STI_DEVICE_INFORMATION structure referenced by ppBuffer, it must de-allocate the buffer by calling LocalFree (described in the Platform SDK documentation).

See Also

IStillImage::GetDeviceList


IStillImage::GetDeviceList

The IStillImage::GetDeviceList method returns hardware characteristics for all installed still image devices.

HRESULT
  GetDeviceList(
    DWORD  dwType,
    DWORD  dwFlags,
    DWORD  *pdwItemsReturned,
    LPVOID  *ppBuffer
    );

Parameters

dwType
Reserved parameter, use NULL.
dwFlags
Reserved parameter, use NULL.
pdwItemsReturned
Receives the number of STI_DEVICE_INFORMATION structures supplied in the buffer referenced by ppBuffer.
ppBuffer
Receives a handle to an STI-allocated buffer. This buffer will contain an array of STI_DEVICE_INFORMATION structures.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

The IStillImage::GetDeviceList method returns an STI_DEVICE_INFORMATION structure for each installed still-image device. Structure contents are typically used for creating user interface displays and for finding a device's internal name.

Before calling IStillImage::GetDeviceList, clients of the IStillImage COM interface must call IStillImage::StiCreateInstance to obtain an IStillImage interface pointer.

When the caller has finished using the array of STI_DEVICE_INFORMATION structures referenced by ppBuffer, it must de-allocate the array by calling LocalFree (described in the Platform SDK documentation).

See Also

IStillImage::GetDeviceInfo


IStillImage::GetDeviceValue

The IStillImage::GetDeviceValue method returns registry information associated with a specified still image device.

HRESULT
  GetDeviceValue(
    LPWSTR  pwszDeviceName,
    LPWSTR  pValueName,
    LPDWORD  pType,
    LPBYTE  pData,
    LPDWORD  cbData
    );

Parameters

pwszDeviceName
Caller-supplied pointer to a string representing an internal device name, obtained by calling IStillImage::GetSTILaunchInformation or IStillImage::GetDeviceList.
pValueName
Caller-supplied pointer to a string representing a registry value name.
pType
Receives a constant representing the data type of the returned registry value.
pData
Caller-supplied pointer to a buffer to receive a returned value.
cbData
Caller-supplied size, in bytes, of the buffer pointed to by pData. The method modifies this value to represent the size of the returned data. If the specified buffer size is too small, the method supplies the required buffer size and returns an error code.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

The purpose of the IStillImage::GetDeviceValue method is to return the values currently assigned to device-specific registry entries for still image devices. The method calls RegQueryValueEx (described in the Platform SDK documentation).

Before calling IStillImage::GetDeviceValue, clients of the IStillImage COM interface must call IStillImage::StiCreateInstance to obtain an IStillImage interface pointer.

See Also

IStillImage::SetDeviceValue


IStillImage::GetHwNotificationState

The IStillImage::GetHwNotificationState method indicates whether applications will be notified when still image device events occur on a specified device.

HRESULT
  RegisterLaunchApplication(
    LPCWSTR  pwszDeviceName,
    BOOL  *pbCurrentState
    );

Parameters

pwszDeviceName
Caller-supplied pointer to a string representing an internal device name, obtained by calling IStillImage::GetSTILaunchInformation or IStillImage::GetDeviceList.
pbCurrentState
Receives TRUE if event notification is enabled, or FALSE otherwise.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

Before calling IStillImage::GetHwNotificationState, clients of the IStillImage COM interface must call IStillImage::StiCreateInstance to obtain an IStillImage interface pointer.

See Also

IStillImage::EnableHwNotifications


IStillImage::GetSTILaunchInformation

The IStillImage::GetSTILaunchInformation method returns the reason the calling still image application was started, if it was started by the Still Image Event Monitor.

HRESULT
  GetSTILaunchInformation(
    LPWSTR  pwszDeviceName,
    DWORD  *pdwEventCode,
    LPWSTR  pwszEventName
    );

Parameters

pwszDeviceName
Caller-supplied pointer to a buffer, STI_MAX_INTERNAL_NAME_LENGTH bytes in length, to receive the internal device name of the still image device for which the application was started.
pdwEventCode
Reserved for future use.
pwszEventName
Caller-supplied pointer to a buffer that is large enough to receive a string representation of a GUID. The GUID represents the still image device event for which the application was started.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

If the application was started by the Still Image Event Monitor, the pwszDeviceName and pwszEventName values identify the /StiDevice and /StiEvent command line arguments (see the description of IStillImage::RegisterLaunchApplication). If the application was not started by the Event Monitor, the method returns STIERR_GENERIC.

Before calling IStillImage::GetSTILaunchInformation, clients of the IStillImage COM interface must call IStillImage::StiCreateInstance to obtain an IStillImage interface pointer.


IStillImage::Initialize

The IStillImage::Initialize method initializes an instance of the COM object that defines the IStillImage COM interface. This method is for internal system use only.

HRESULT
  Initialize(
    HINSTANCE  hinst,
    DWORD  dwVersion
    );

Parameters

hinst
Caller-supplied instance handle of the calling process. This handle is obtained by calling GetModuleName(NULL).
dwVersion
Caller-supplied STI version number. This value must be STI_VERSION, defined in sti.h.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

The IStillImage::Initialize method initializes the COM object instance that was created by calling IStillImage::StiCreateInstance.

Because IStillImage::Initialize is called by IStillImage::StiCreateInstance, clients of the IStillImage COM interface do not typically call this method directly.


IStillImage::LaunchApplicationForDevice

The IStillImage::LaunchApplicationForDevice method starts a specified application for a specified still image device.

HRESULT
  LaunchApplicationForDevice(
    LPWSTR  pwszDeviceName,
    LPWSTR  pwszAppName,
    LPSTINOTIFY  pStiNotify
    );

Parameters

pwszDeviceName
Caller-supplied pointer to a string representing an internal device name, obtained by calling IStillImage::GetSTILaunchInformation or IStillImage::GetDeviceList.
pwszAppName
Caller-supplied pointer to a string representing the short name of an application that was registered by calling IStillImage::RegisterLaunchApplication.
pStiNotify
Caller-supplied pointer to an STINOTIFY structure describing a device event. Typically, the event's GUID is obtained by calling IStiDevice::GetLastNotificationData.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

The IStillImage::LaunchApplicationForDevice method can only start applications that have registered themselves by calling IStillImage::RegisterLaunchApplication. The specified event must be one that the specified device supports. The method mimics the occurrence of a device event, and is useful for applications that intercept events from devices and re-route them. (When a user starts the scanner, such an application might, for example, ask the user whether she wants to store the scanned image, make a copy, or send a fax.)

Before calling IStillImage::LaunchApplicationForDevice, clients of the IStillImage COM interface must call IStillImage::StiCreateInstance to obtain an IStillImage interface pointer.

Code Example

HRESULT hRes;
hRes = pStiDevice->GetLastNotificationData(&pNotify);
if (!SUCCEEDED(hRes))
{
    DisplayOutput("->GetLastNotificationData returned %xh %u",
        hReturn,hReturn);
}

// Process or filter events here

// Send event on to app
hRes = pSti->LaunchApplicationForDevice(pStiInfoPtr->szDeviceInternalName,
     L"AppName",
     pNotify);
if (!SUCCEEDED(hRes))
{
    DisplayOutput("->LaunchApplicationForDevice on %S returned %xh %u",
        pStiInfoPtr->szDeviceInternalName,hReturn,hReturn);
}


IStillImage::RegisterLaunchApplication

The IStillImage::RegisterLaunchApplication method adds an application to the Still Image Event Monitor's list of push-model aware applications.

HRESULT
  RegisterLaunchApplication(
    LPWSTR  pwszAppName,
    LPWSTR  pwszCommandLine
    );

Parameters

pwszAppName
Caller-supplied pointer to a string representing the application's "short name", which will be displayed by the Scanners and Cameras Control Panel's property sheet.
pwszCommandLine
Caller-supplied pointer to a string representing the command line required to start the application, including the full path to the application's executable file. The current path can be obtained by calling GetModuleFileName (described in the Platform SDK documentation). For more information, see the following Comments section.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

An application (or the application's installer) must call IStillImage::RegisterLaunchApplication so the Still Image Event Monitor will know of its existence. Users associate still image device events with registered applications by using the Control Panel's property sheet interface. After a user has associated a device event with the application, the Event Monitor will start the application when the event occurs.

The method writes the application's load path in the registry. Therefore, the method should be called each time the application runs, because the user might have moved the file and GetModuleFileName always returns the current file location.

You can include command arguments in the application's command line. When starting a registered application, the Event Monitor appends the following two arguments to the command line:

/StiDevice:InternalDeviceName | InternalDeviceName is the internal device name of the device for which the application is being started.
/StiEvent:EventGUID | EventGUID is the string representation of the GUID for the device event that has occurred.

The application can obtain the values specified for these arguments by calling IStillImage::GetStiLaunchInformation.

Before calling IStillImage::RegisterLaunchApplication, clients of the IStillImage COM interface must call IStillImage::StiCreateInstance to obtain an IStillImage interface pointer.


IStillImage::Release

The IStillImage::Release method closes the instance of the COM object that was created by a previous call to IStillImage::StiCreateInstance, and removes access to the object's interface.

HRESULT
  Release(
    VOID
    );

Parameters

None

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

Before calling IStillImage::Release, clients of the IStillImage COM interface must call IStillImage::StiCreateInstance to obtain an IStillImage interface pointer.


IStillImage::SetDeviceValue

The IStillImage::SetDeviceValue method sets registry information for a specified still image device.

HRESULT
  SetDeviceValue(
    LPWSTR  pwszDeviceName,
    LPWSTR  pValueName,
    DWORD  Type,
    LPBYTE  pData,
    DWORD  cbData
    );

Parameters

pwszDeviceName
Caller-supplied pointer to a string representing an internal device name, obtained by calling IStillImage::GetSTILaunchInformation or IStillImage::GetDeviceList.
pValueName
Caller-supplied pointer to a string representing a registry value name.
Type
Caller-supplied REG_-prefixed registry value type. For more information, see RegSetValueEx in the Platform SDK documentation.
pData
Caller-supplied pointer to the data to be stored.
cbData
Caller-supplied size, in bytes, of the data pointed to by pData. For NULL-terminated strings, include the NULL character.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

The purpose of the IStillImage::SetDeviceValue method is to set values for device-specific registry entries for still image devices. The method calls RegSetValueEx (described in the Platform SDK documentation).

Before calling IStillImage::SetDeviceValue, clients of the IStillImage COM interface must call IStillImage::StiCreateInstance to obtain an IStillImage interface pointer.

See Also

IStillImage::GetDeviceValue


IStillImage::SetupDeviceParameters

The IStillImage::SetupDeviceParameters method allows clients of the IStillImage COM interface to modify a still image device's stored characteristics, if the device's bus type is unknown.

HRESULT
  SetupDeviceParameters(
    PSTI_DEVICE_INFORMATION  pDevInfo
    );

Parameters

pDevInfo
Caller-supplied pointer to an STI_DEVICE_INFORMATION structure describing a still image device.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

The IStillImage::SetupDeviceParameters method only allows modification of device parameters associated with still image devices for which a bus has not been identified. For such devices, the Still Image server sets the dwHardwareConfiguration member of the device's STI_DEVICE_INFORMATION structure to STI_HW_CONFIG_UNKNOWN when IStillImage::GetDeviceInfo is called.

Currently, the only device parameter that can be modified is the device's port name. When calling this method to modify the port name, the dwSize, szDeviceInternalName, and pszPortName members of the STI_DEVICE_INFORMATION must be specified. All other members are ignored.

Before calling IStillImage::SetupDeviceParameters, clients of the IStillImage COM interface must call IStillImage::StiCreateInstance to obtain an IStillImage interface pointer.


IStillImage::StiCreateInstance

The IStillImage::StiCreateInstance method creates an instance of the COM object that defines the IStillImage interface, and returns a pointer to the interface.

HRESULT
  StiCreateInstance(
    HINSTANCE  hinst,
    DWORD  dwVer,
    PSTI  *ppSti,
    LPUNKNOWN  punkOuter
    );

Parameters

hinst
Caller-supplied instance handle of the calling process. This handle is obtained by calling GetModuleHandle(NULL).
dwVer
Caller-supplied STI version number. This value must be STI_VERSION, defined in sti.h.
ppSti
Receives a pointer to the IStillImage interface.
punkOuter
Optional, caller-supplied pointer to the "controlling unknown" for object aggregation. See the following Comments section.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

For an application to use the IStillImage interface, it must first call IStillImage::StiCreateInstance to get a pointer to the interface. The pointer received in ppSti is used subsequently when calling IStillImage methods, as illustrated in the following example:

PSTI pSti = NULL;
DWORD dwStiTotal = 0;     // total number of STI devices found
PVOID pStiInfo = NULL;    // STI device info buffer
HRESULT hres = StiCreateInstance(GetModuleHandle(NULL), STI_VERSION, &pSti, NULL);
...
hhes = pSti->GetDeviceList(0, 0, &dwStiTotal, &pStiInfo);

If you want to create an aggregate COM object that includes IStillImage, you must supply a pointer to the "controlling unknown" in punkOuter. In most cases you will not be creating an aggregate object, so punkOuter should be NULL. Object aggregation and the controlling unknown are described in the Platform SDK documentation and in the Component Object Model Specification.

See Also

IStillImage::Release


IStillImage::UnregisterLaunchApplication

The IStillImage::UnregisterLaunchApplication method removes an application from the Still Image Event Monitor's list of push-model aware applications.

HRESULT
  UnregisterLaunchApplication(
    LPWSTR  pwszAppName
    );

Parameters

pwszAppName
Caller-supplied pointer to the application's "short name".

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

The IStillImage::UnRegisterLaunchApplication method should be called as part of the process of un-installing a push-model aware application. The method can be un-installed either by the application itself or by other un-installing software.

Before calling IStillImage::UnRegisterLaunchApplication, clients of the IStillImage COM interface must call IStillImage::StiCreateInstance to obtain an IStillImage interface pointer.

See Also

IStillImage::RegisterLaunchApplication


IStillImage::WriteToErrorLog

The IStillImage::WriteToErrorLog method writes a message to the Still Image error log.

HRESULT
  WriteToErrorLog(
    DWORD  dwMessageType,
    LPCWSTR  pszMessage
    );

Parameters

dwMessageType
Caller-supplied constant value representing the message type. The following values are defined in sti.h:

STI_TRACE_INFORMATION
STI_TRACE_WARNING
STI_TRACE_ERROR

pszMessage
Caller-supplied pointer to the message string to be written to the log file.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

The Still Image error log file is named sti_trace.log and is located in the Windows directory. Registry values determine which still image error types (informational, warning, or error) are written to the error log (see Non-Modifiable Registry Entries).

Error messages should be reserved for critical error conditions, such as device hardware failures. Informational messages can be used for your own debugging purposes. Logged messages aren't visible to users, but they might be used by a support engineer to help debug a user's problems.

Before calling IStillImage::WriteToErrorLog, clients of the IStillImage COM interface must call IStillImage::StiCreateInstance to obtain an IStillImage interface pointer.


IStiDevice Interface Methods

This section describes the methods defined for the IStiDevice COM interface. Method prototypes are contained in sti.h.


IStiDevice::DeviceReset

The IStiDevice::DeviceReset method resets a still image device to a known state.

HRESULT
  DeviceReset(
    VOID
    );

Parameters

None

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

The IStiDevice::DeviceReset method resets the device by calling IStiUSD::DeviceReset, which is exported by vendor-supplied minidrivers.

Before calling IStiDevice::DeviceReset, clients of the IStiDevice COM interface must call IStillImage::CreateDevice to obtain an IStiDevice interface pointer, which provides access to a specified device.

A call to IStiDevice::DeviceReset must be preceded by a call to IStiDevice::LockDevice and followed by a call to IStiDevice::UnLockDevice.


IStiDevice::Diagnostic

The IStiDevice::Diagnostic method executes diagnostic tests on a still image device.

HRESULT
  Diagnostic(
    LPSTI_DIAG  pBuffer
    );

Parameters

pBuffer
Caller-supplied pointer to an STI_DIAG structure specifying the type of tests to be run. On return, the structure contains status information.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

The IStiDevice::Diagnostic method calls IStiUSD::Diagnostic, which is exported by vendor-supplied minidrivers. The Scanners and Cameras Control Panel calls IStiDevice::Diagnostic when a user presses the Test button.

Before calling IStiDevice::Diagnostic, clients of the IStiDevice COM interface must call IStillImage::CreateDevice to obtain an IStiDevice interface pointer, which provides access to a specified device.

A call to IStiDevice::Diagnostic must be preceded by a call to IStiDevice::LockDevice and followed by a call to IStiDevice::UnLockDevice.


IStiDevice::Escape

The IStiDevice::Escape method sends a request for a vendor-specific I/O operation to a still image device.

HRESULT
  Escape(
    STI_RAW_CONTROL_CODE EscapeFunction,
    LPVOID  lpInData,
    DWORD  cbInDataSize,
    LPVOID  pOutData,
    DWORD  dwOutDataSize,
    LPDWORD  pdwActualData
    );

Parameters

EscapeFunction
Caller-supplied, vendor-defined, DWORD-sized value representing an I/O operation. This value must be recognized by the device's minidriver (which must export an IStiUSD interface). Vendor-defined values must be greater than STI_RAW_RESERVED, which is defined in sti.h.
lpInData
Caller-supplied pointer to a buffer containing data to be sent to the device.
cbInDataSize
Caller-supplied length, in bytes, of the data contained in the buffer pointed to by lpInData.
pOutData
Caller-supplied pointer to a memory buffer to receive data from the device.
dwOutDataSize
Caller-supplied length, in bytes, of the buffer pointed to by lpOutData.
pdwActualData
Receives the number of bytes actually written to pOutData.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

The IStiDevice::Escape method calls IStiUSD::Escape, which is exported by vendor-supplied minidrivers. Method parameter usage is defined by the device's minidriver.

Before calling IStiDevice::Escape, clients of the IStiDevice COM interface must call IStillImage::CreateDevice to obtain an IStiDevice interface pointer, which provides access to a specified device.

A call to IStiDevice::Escape must be preceded by a call to IStiDevice::LockDevice and followed by a call to IStiDevice::UnLockDevice.


IStiDevice::GetCapabilities

The IStiDevice::GetCapabilities method returns a still image device's capabilities.

HRESULT
  GetCapabilities(
    PSTI_DEV_CAPS  pDevCaps
    );

Parameters

pDevCaps
Caller-supplied pointer to an empty STI_DEV_CAPS structure.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

The IStiDevice::GetCapabilities method returns device capability flags in the caller-supplied STI_DEV_CAPS structure.

Before calling IStiDevice::GetCapabilities, clients of the IStiDevice COM interface must call IStillImage::CreateDevice to obtain an IStiDevice interface pointer, which provides access to a specified device.


IStiDevice::GetLastError

The IStiDevice::GetLastError method returns the last known error associated with a still image device.

HRESULT
  GetLastError(
    LPDWORD  pdwLastDeviceError
    );

Parameters

pdwLastDeviceError
Caller-supplied pointer to a buffer in which the error code will be stored.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

Before calling IStiDevice::GetLastError, clients of the IStiDevice COM interface must call IStillImage::CreateDevice to obtain an IStiDevice interface pointer, which provides access to a specified device.


IStiDevice::GetLastErrorInfo

The IStiDevice::GetLastErrorInfo method returns information about the last known error associated with a still image device.

HRESULT
  GetLastErrorInfo(
    STI_ERROR_INFO  *pLastErrorInf
    );

Parameters

pLastErrorInf
Caller-supplied pointer to an STI_ERROR_INFO structure to receive error information.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

The IStiDevice::GetLastErrorInfo method returns information about the most recent error by filling in the caller-supplied STI_ERROR_INFO structure. The method calls IStiUSD::GetLastErrorInfo, which is exported by vendor-supplied minidrivers.

Before calling IStiDevice::GetLastErrorInfo, clients of the IStiDevice COM interface must call IStillImage::CreateDevice to obtain an IStiDevice interface pointer, which provides access to a specified device.


IStiDevice::GetLastNotificationData

The IStiDevice::GetLastNotificationData method returns a description of the most recent event that occurred on a still image device.

HRESULT
  GetLastNotificationData(
    LPSTINOTIFY  lpNotify
    );

Parameters

lpNotify
Caller-supplied pointer to an STINOTIFY structure to receive event information.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

Each time a still image device event occurs, the Still Image Event Monitor calls IStiUSD::GetNotificationData (exported by a vendor-supplied minidriver) to obtain an event description. These descriptions are added to a linked list. If a client of the IStiDevice COM interface has called IStiDevice::Subscribe, it is notified each time a device event occurs. It can then call IStiDevice::GetLastNotificationData to obtain the most recent addition to the linked list of events.

Before calling IStiDevice::GetLastNotificationData, clients of the IStiDevice COM interface must call IStillImage::CreateDevice to obtain an IStiDevice interface pointer, which provides access to a specified device.


IStiDevice::GetStatus

The IStiDevice::GetStatus method returns a still image device's status information.

HRESULT
  GetStatus(
    PSTI_DEVICE_STATUS  pDevStatus
    );

Parameters

pDevStatus
Caller-supplied pointer to an STI_DEVICE_STATUS structure. The caller must set the dwSize and StatusMask members.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

The IStiDevice::GetStatus method returns device status information in the caller-supplied STI_DEVICE_STATUS structure. It obtains the status by calling IStiUSD::GetStatus, which is exported by vendor-supplied minidrivers.

Before calling IStiDevice::GetStatus, clients of the IStiDevice COM interface must call IStillImage::CreateDevice to obtain an IStiDevice interface pointer, which provides access to a specified device.

A call to IStiDevice::GetStatus must be preceded by a call to IStiDevice::LockDevice and followed by a call to IStiDevice::UnLockDevice.


IStiDevice::Initialize

The IStiDevice::Initialize method initializes an instance of the COM object that defines the IStiDevice interface. This method is for internal use only.

HRESULT
  Initialize(
    HINSTANCE  hinst,
    LPCWSTR  pwszDeviceName,
    DWORD  dwVersion,
    DWORD  dwMode
    );

Parameters

hinst
Caller-supplied instance handle of the calling process. This handle is obtained by calling GetModuleName(NULL).
pwszDeviceName
Caller-supplied pointer to a string representing an internal device name, obtained by calling IStillImage::GetSTILaunchInformation.
dwVersion
Caller-supplied STI version number. This value must be STI_VERSION, defined in sti.h.
dwMode
Caller-supplied constant value indicating the transfer mode in which the device is to be used. The following values are valid.
Mode | Description
STI_DEVICE_CREATE_BOTH | The device is being opened for both obtaining status and transferring data.
STI_DEVICE_CREATE_DATA | The device is being opened only for data transfers.
STI_DEVICE_CREATE_STATUS | The device is being opened only for obtaining status information.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

The IStiDevice::Initialize method initializes the COM object instance that was created by calling IStillImage::CreateDevice.

Because IStiDevice::Initialize is called by IStillImage::CreateDevice, clients of the IStiDevice interface do not typically call this method directly.


IStiDevice::LockDevice

The IStiDevice::LockDevice method locks a device for exclusive use by the caller.

HRESULT
  LockDevice(
    DWORD  dwTimeOut
    );

Parameters

dwTimeOut
Caller-supplied time-out value, in milliseconds. If the lock is not obtained in this time period, an error is returned.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

Clients of the IStiDevice COM interface must call IStiDevice::LockDevice before calling the following methods:

IStiDevice::DeviceReset
IStiDevice::Diagnostic
IStiDevice::Escape
IStiDevice::GetStatus
IStiDevice::RawReadCommand
IStiDevice::RawReadData
IStiDevice::RawWriteCommand
IStiDevice::RawWriteData

If the IStiDevice::LockDevice method is able to obtain an IStiDevice-level lock on the device within the specified time-out period, it then calls IStiUSD::LockDevice in the appropriate vendor-supplied minidriver.

Each call to IStiDevice::LockDevice must be paired with a call to IStiDevice::UnLockDevice.

Before calling IStiDevice::LockDevice, clients of the IStiDevice COM interface must call IStillImage::CreateDevice to obtain an IStiDevice interface pointer, which provides access to a specified device.


IStiDevice::RawReadCommand

The IStiDevice::RawReadCommand method reads command information from a still image device.

HRESULT
  RawReadCommand(
    LPVOID  lpBuffer,
    LPDWORD  lpdwNumberOfBytes,
    LPOVERLAPPED  lpOverlapped
    );

Parameters

lpBuffer
Caller-supplied pointer to a buffer to receive data read from the device.
lpdwNumberOfBytes
Caller-supplied pointer to a DWORD. The caller must load the DWORD with the number of bytes in the buffer pointed to by lpBuffer. On return, it will contain the number of bytes actually read.
lpOverlapped
Optional, caller-supplied pointer to an OVERLAPPED structure (described in the Platform SDK documentation).

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

The IStiDevice::RawReadCommand method calls IStiUSD::RawReadCommand, which is exported by vendor-supplied minidrivers. The meaning of buffer contents are vendor-defined.

It is only necessary to call IStiDevice::RawReadCommand if command and data information are read from a device by different methods. For other devices, IStiDevice::RawReadData can be used for both commands and data.

Before calling IStiDevice::RawReadCommand, clients of the IStiDevice COM interface must call IStillImage::CreateDevice to obtain an IStiDevice interface pointer, which provides access to a specified device.

A call to IStiDevice::RawReadCommand must be preceded by a call to IStiDevice::LockDevice and followed by a call to IStiDevice::UnLockDevice.


IStiDevice::RawReadData

The IStiDevice::RawReadData method reads data from a still image device.

HRESULT
  RawReadData(
    LPVOID  lpBuffer,
    LPDWORD  lpdwNumberOfBytes,
    LPOVERLAPPED  lpOverlapped
    );

Parameters

lpBuffer
Caller-supplied pointer to a buffer to receive data read from the device.
lpdwNumberOfBytes
Caller-supplied pointer to a DWORD. The caller must load the DWORD with the number of bytes in the buffer pointed to by lpBuffer. On return, it will contain the number of bytes actually read.
lpOverlapped
Optional, caller-supplied pointer to an OVERLAPPED structure (described in the Platform SDK documentation).

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

The IStiDevice::RawReadData method calls IStiUSD::RawReadData, which is exported by vendor-supplied minidrivers.

Before calling IStiDevice::RawReadData, clients of the IStiDevice COM interface must call IStillImage::CreateDevice to obtain an IStiDevice interface pointer, which provides access to a specified device.

A call to IStiDevice::RawReadData must be preceded by a call to IStiDevice::LockDevice and followed by a call to IStiDevice::UnLockDevice.

See Also

IStiDevice::RawReadCommand


IStiDevice::RawWriteCommand

The IStiDevice::RawWriteCommand method sends command information to a still image device.

HRESULT
  RawWriteCommand(
    LPVOID  lpBuffer,
    DWORD  nNumberOfBytes,
    LPOVERLAPPED  lpOverlapped
    );

Parameters

lpBuffer
Caller-supplied pointer to a buffer containing data to be sent to the device.
nNumberOfBytes
Caller-supplied number of bytes to be written. This is the number of bytes in the buffer pointed to by lpBuffer.
lpOverlapped
Optional, caller-supplied pointer to an OVERLAPPED structure (described in the Platform SDK documentation).

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

The IStiDevice::RawWriteCommand method calls IStiUSD::RawWriteCommand, which is exported by vendor-supplied minidrivers. The meaning of buffer contents are vendor-defined.

It is only necessary to call IStiDevice::RawWriteCommand if commands and data are written to a device by different methods. For other devices, IStiDevice::RawWriteData can be used for both commands and data.

Before calling IStiDevice::RawWriteCommand, clients of the IStiDevice COM interface must call IStillImage::CreateDevice to obtain an IStiDevice interface pointer, which provides access to a specified device.

A call to IStiDevice::RawWriteCommand must be preceded by a call to IStiDevice::LockDevice and followed by a call to IStiDevice::UnLockDevice.


IStiDevice::RawWriteData

The IStiDevice::RawWriteData method writes data to a still image device.

HRESULT
  RawWriteData(
    LPVOID  lpBuffer,
    DWORD  nNumberOfBytes,
    LPOVERLAPPED  lpOverlapped
    );

Parameters

lpBuffer
Caller-supplied pointer to a buffer containing data to be sent to the device.
nNumberOfBytes
Caller-supplied number of bytes to be written. This is the number of bytes in the buffer pointed to by lpBuffer.
lpOverlapped
Optional, caller-supplied pointer to an OVERLAPPED structure (described in the Platform SDK documentation).

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

The IStiDevice::RawWriteData method calls IStiUSD::RawWriteData, which is exported by vendor-supplied minidrivers.

Before calling IStiDevice::RawWriteData, clients of the IStiDevice COM interface must call IStillImage::CreateDevice to obtain an IStiDevice interface pointer, which provides access to a specified device.

A call to IStiDevice::RawWriteData must be preceded by a call to IStiDevice::LockDevice and followed by a call to IStiDevice::UnLockDevice.

See Also

IStiDevice::RawWriteCommand


IStiDevice::Release

The IStiDevice::Release method closes the instance of the COM object that was created by a previous call to IStillImage::CreateDevice, and removes access to the object's interface.

HRESULT
  Release(
    VOID
    );

Parameters

None

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.


IStiDevice::Subscribe

The IStiDevice::Subscribe method registers the caller to receive notifications of device events.

HRESULT
  Subscribe(
    LPSTISUBSCRIBE  lpSubscribe
    );

Parameters

lpSubscribe
Caller-supplied pointer to an STISUBSCRIBE structure containing subscription parameter values.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

The IStiDevice::Subscribe method is typically called by applications that intercept events from devices and re-route them. The method allows these applications to be notified of still image device events so they can then dispatch control to appropriate display applications.

Based on contents supplied in the STISUBSCRIBE structure, the caller can request to be notified of device events by Windows messages or by Win32® events (by means of SetEvent calls).

When the application receives notification of an event, it can call IStiDevice::GetLastNotificationData to find out which event occurred.

Before calling IStiDevice::Subscribe, clients of the IStiDevice COM interface must call IStillImage::CreateDevice to obtain an IStiDevice interface pointer, which provides access to a specified device.

See Also

IStiDevice::UnSubscribe
IStillImage::LaunchApplicationForDevice


IStiDevice::UnLockDevice

The IStiDevice::UnLockDevice method unlocks a device that was locked by a previous call to IStiDevice::LockDevice.

HRESULT
  UnLockDevice(
    VOID
    );

Parameters

None

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

Before the IStiDevice::UnLockDevice method releases the IStiDevice-level lock on the device, it calls IStiUSD::UnLockDevice in the appropriate vendor-supplied minidriver.

Before calling IStiDevice::UnLockDevice, clients of the IStiDevice COM interface must call IStillImage::CreateDevice to obtain an IStiDevice interface pointer, which provides access to a specified device.


IStiDevice::UnSubscribe

The IStiDevice::UnSubscribe method removes the caller from the list of applications registered to receive notification of device events.

HRESULT
  UnSubscribe(
    VOID
    );

Parameters

None

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in sti.h. Include sti.h.

Comments

Before calling IStiDevice::UnSubscribe, clients of the IStiDevice COM interface must call IStillImage::CreateDevice to obtain an IStiDevice interface pointer, which provides access to a specified device.

See Also

IStiDevice::Subscribe


IStiUSD Interface Methods

This section describes the methods defined for the IStiUSD COM interface. Method prototypes are contained in stiusd.h.


IStiUSD::DeviceReset

A still image minidriver's IStiUSD::DeviceReset method resets a still image device to a known, initialized state.

STDMETHODIMP
  DeviceReset(
    VOID
    );

Parameters

None

Return Value

If the operation succeeds, the method should return S_OK. Otherwise, it should return one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in stiusd.h. Include stiusd.h.

See Also

IStiDevice::DeviceReset


IStiUSD::Diagnostic

A still image minidriver's IStiUSD::Diagnostic method runs diagnostic tests on a still image device.

STDMETHODIMP
  Diagnostic(
    LPSTI_DIAG  pBuffer
    );

Parameters

pBuffer
Caller-supplied pointer to an STI_DIAG structure to receive testing status information.

Return Value

If the operation succeeds, the method should return S_OK. Otherwise, it should return one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in stiusd.h. Include stiusd.h.

Comments

The IStiUSD::Diagnostic method is called when a user clicks on the Scanners and Cameras Control Panel's Test button. The method should execute tests to confirm that the device is fully operational. For a scanner, these tests might include turning the light on and off, and moving the scanning arm. For a camera, they might include execution of built-in diagnostic functions, or manipulation of device settings. The return value should indicate success or failure of the diagnostic tests.

See Also

IStiDevice::Diagnostic


IStiUSD::Escape

A still image minidriver's IStiUSD::Escape method performs a vendor-specific I/O operation on a still image device.

STDMETHODIMP
  Escape(
    STI_RAW_CONTROL_CODE  EscapeFunction,
    LPVOID  lpInData,
    DWORD  cbInDataSize,
    LPVOID  pOutData,
    DWORD  dwOutDataSize,
    LPDWORD  pdwActualData
    );

Parameters

EscapeFunction
Caller-supplied, vendor-defined, DWORD-sized value representing an I/O operation. Vendor-defined values must be greater than STI_RAW_RESERVED, which is defined in sti.h.
lpInData
Caller-supplied pointer to a buffer containing data sent to the device.
cbInDataSize
Caller-supplied length, in bytes, of the buffer pointed to by lpInData.
pOutData
Caller-supplied pointer to a memory buffer to receive data from the device.
dwOutDataSize
Caller-supplied length, in bytes, of the buffer pointed to by lpOutData.
pdwActualData
Receives the number of bytes actually written to pOutData.

Return Value

If the operation succeeds, the method should return S_OK. Otherwise, it should return one of the STIERR-prefixed error codes defined in stierr.h. If the method is not implemented, it should return STIERR_UNSUPPORTED.

Headers

Declared in stiusd.h. Include stiusd.h.

Comments

A still image minidriver only needs to implement IStiUSD::Escape if I/O operations are required that cannot be implemented within IStiUSD::RawReadData, IStiUSD::RawWriteData, IStiUSD::RawReadCommand, or IStiUSD::RawWriteCommand methods. Parameter usage for IStiUSD::Escape is defined by the minidriver.

See Also

IStiDevice::Escape


IStiUSD::GetCapabilities

A still image minidriver's IStiUSD::GetCapabilities method returns a still image device's capabilities.

STDMETHODIMP
  GetCapabilities(
    PSTI_USD_CAPS  pUsdCaps
    );

Parameters

pUsdCaps
Caller-supplied pointer to an empty STI_USD_CAPS structure.

Return Value

If the operation succeeds, the method should return S_OK. Otherwise, it should return one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in stiusd.h. Include stiusd.h.

Comments

The IStiUSD::GetCapabilities method should set appropriate device capability flags in the caller-supplied STI_USD_CAPS structure. It should also set the version number to STI_VERSION.

See Also

IStiDevice::GetCapabilities


IStiUSD::GetLastErrorInfo

A still image minidriver's IStiUSD::GetLastErrorInfo method returns information about the last known error associated with a still image device.

STDMETHODIMP
  GetLastErrorInfo(
    STI_ERROR_INFO  *pLastErrorInfo
    );

Parameters

pLastErrorInfo
Caller-supplied pointer to an STI_ERROR_INFO structure to receive error information.

Return Value

If the operation succeeds, the method should return S_OK. Otherwise, it should return one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in stiusd.h. Include stiusd.h.

Comments

The method should fill in the received STI_ERROR_INFO structure.

See Also

IStiDevice::GetLastErrorInfo


IStiUSD::GetNotificationData

A still image minidriver's IStiUSD::GetNotificationData method returns a description of the most recent event that occurred on a still image device.

STDMETHODIMP
  GetNotificationData(
    LPSTINOTIFY  pBuffer
    );

Parameters

pBuffer
Caller-supplied pointer to an STINOTIFY structure to receive event information.

Return Value

If the operation succeeds, the method should return S_OK. Otherwise, it should return one of the STIERR-prefixed error codes defined in stierr.h. If no events have occurred since the last time the method was called, the method should return STIERR_NOEVENTS.

Headers

Declared in stiusd.h. Include stiusd.h.

Comments

Each time a device event occurs, the Still Image Event Monitor calls IStiUSD::GetNotificationData to obtain an event description. These descriptions are added to a linked list and when an application calls IStiDevice::GetLastNotificationData, the most recent addition to the list is returned.


IStiUSD::GetStatus

A still image minidriver's IStiUSD::GetStatus method returns the status of a still image device.

STDMETHODIMP
  GetStatus(
    PSTI_DEVICE_STATUS  pDevStatus
    );

Parameters

pDevStatus
Caller-supplied pointer to an STI_DEVICE_STATUS structure.

Return Value

If the operation succeeds, the method should return S_OK. Otherwise, it should return one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in stiusd.h. Include stiusd.h.

Comments

The caller supplies values for the dwSize and StatusMask members of the STI_DEVICE_STATUS structure, and the minidriver must supply values for the rest of the structure members.

If the driver has previously set the STI_GENCAP_POLLING_NEEDED flag in the device's STI_DEV_CAPS structure, the minidriver's IStiUSD::GetStatus method is the means by which the Event Monitor determines if a still image device event has occurred. The Event Monitor will call the method, specifying STI_DEVSTATUS_EVENT_STATE in the supplied STI_DEVICE_STATUS structure. The driver must poll the device and set STI_EVENTHANDLING_PENDING if an event has occurred.

If the caller specifies STI_DEVSTATUS_ONLINE_STATE in the supplied STI_DEVICE_STATUS structure, the minidriver should set the appropriate flag in the structure's dwOnlineState member.

See Also

IStiDevice::GetStatus


IStiUSD::Initialize

A still image minidriver's IStiUSD::Initialize method initializes an instance of the COM object that defines the IStiUSD interface.

STDMETHODIMP
  Initialize(
    PSTIDEVICECONTROL  pDcb,
    DWORD  dwStiVersion,
    HKEY  hParametersKey
    );

Parameters

pDcb
Caller-supplied pointer to the IStiDeviceControl COM interface.
dwStiVersion
Caller-supplied STI version number. This value is defined by STI_VERSION in sti.h.
hParametersKey
Caller-supplied handle to the registry key under which device-specific information is to be stored.

Return Value

If the operation succeeds, the method should return S_OK. Otherwise, it should return one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in stiusd.h. Include stiusd.h.

Comments

The IStiUSD::Initialize method, which is exported by still image minidrivers, is the first IStiUSD method called after a minidriver has been loaded. The method must initialize the driver and device.

The method should store the received IStiDeviceControl COM interface pointer, and it should call that interface's IStiDeviceControl::AddRef method.

For devices connected to dedicated ports (such as SCSI devices), the method typically creates a read/write path to the device by calling CreateFile (described in the Platform SDK documentation), using a device port name obtained by calling IStiDeviceControl::GetMyDevicePortName.

For devices on shared ports (such as serial port devices), opening the port in the IStiUSD::Initialize method is not recommended, because access to other devices on the port will be locked out. For such devices, it is better to call CreateFile from within the IStiUSD::LockDevice method.

If the device being opened is one for which multiple calls to CreateFile are not allowed (such as devices connected to a serial port), the driver typically does not call CreateFile unless the caller has opened the device for data transfers, as illustrated in the following Code Example.

The IStiUSD::Initialize method should validate the received STI version number and return an error if the received version does not match the driver's version.

Code Example

The following example opens a device port only if a call to IStiDeviceControl::GetMyDeviceOpenMode indicates an application has opened the device for data transfers. Such code might be used for a device that cannot support multiple CreateFile calls, such as a serial port device.

STDMETHODIMP MyUSDDevice::Initialize(
    PSTIDEVICECONTROL pDcb,
    DWORD             dwStiVersion,
    HKEY              hParametersKey)
{
    HRESULT hres = STI_OK;
    DWORD   dwMode = 0;
    if (!pDcb)
    {
        hres = STIERR_INVALID_PARAM;
    }
    else
    {
        // Store IStiDeviceControl object pointer
        m_pDcb = pDcb;
        m_pDcb->AddRef();
        // If we opened in data mode - should open device right now,
        // otherwise postpone open till lock
        m_pDcb->GetMyDeviceOpenMode(&dwMode);
        if (dwMode & STI_DEVICE_CREATE_DATA)
            hres = OpenMyPort();
    }
    return hres;
}


IStiUSD::LockDevice

A still image minidriver's IStiUSD::LockDevice method locks a device for exclusive use by the caller.

STDMETHODIMP
  LockDevice(
    VOID
    );

Parameters

None

Return Value

If the operation succeeds, the method should return S_OK. Otherwise, it should return one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in stiusd.h. Include stiusd.h.

Comments

If you are writing a driver for a device connected to a serial port, you might want to call CreateFile from within the driver's IStiUSD::LockDevice method if the device was opened in status mode. This will prohibit other applications from using the port (which might be supporting other devices) while status information is being obtained. For more information, see Transfer Modes.

See Also

IStiDevice::LockDevice


IStiUSD::RawReadCommand

A still image minidriver's IStiUSD::RawReadCommand method reads command information from a still image device.

STDMETHODIMP
  RawReadCommand(
    LPVOID  lpBuffer,
    LPDWORD  lpdwNumberOfBytes,
    LPOVERLAPPED  lpOverlapped
    );

Parameters

lpBuffer
Caller-supplied pointer to a buffer to receive data read from the device.
lpdwNumberOfBytes
Caller-supplied pointer to a DWORD. The caller loads the DWORD with the number of bytes in the buffer pointed to by lpBuffer. The driver must replace this value with the number of bytes actually read.
lpOverlapped
Optional, caller-supplied pointer to an OVERLAPPED structure (described in the Platform SDK documentation).

Return Value

If the operation succeeds, the method should return S_OK. Otherwise, it should return one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in stiusd.h. Include stiusd.h.

Comments

It is only necessary to implement IStiUSD::RawReadCommand if command and data information are read from a device by different methods. For other devices, IStiUSD::RawReadData can be used for both commands and data. If the call is not implemented, it must return STIERR_UNSUPPORTED.

Implementation of this method, along with the meaning of buffer contents, are vendor-defined.

See Also

IStiDevice::RawReadCommand


IStiUSD::RawReadData

A still image minidriver's IStiUSD::RawReadData method reads data from a still image device.

STDMETHODIMP
  RawReadData(
    LPVOID  lpBuffer,
    LPDWORD  lpdwNumberOfBytes,
    LPOVERLAPPED  lpOverlapped
    );

Parameters

lpBuffer
Caller-supplied pointer to a buffer to receive data read from the device.
lpdwNumberOfBytes
Caller-supplied pointer to a DWORD. The caller loads the DWORD with the number of bytes in the buffer pointed to by lpBuffer. The driver must replace this value with the number of bytes actually read.
lpOverlapped
Optional, caller-supplied pointer to an OVERLAPPED structure (described in the Platform SDK documentation).

Return Value

If the operation succeeds, the method should return S_OK. Otherwise, it should return one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in stiusd.h. Include stiusd.h.

Comments

A still image minidriver typically implements this method by calling ReadFile (described in the Platform SDK documentation).

For USB devices, better performance can be achieved if read requests are aligned to maximum packet size boundaries. Maximum packet sizes can be obtained by calling DeviceIoControl, specifying the IOCTL_GET_CHANNEL_ALIGN_RQST I/O control code.

See Also

IStiDevice::RawReadData


IStiUSD::RawWriteCommand

A still image minidriver's IStiDevice::RawWriteCommand method sends command information to a still image device.

STDMETHODIMP
  RawWriteCommand(
    LPVOID  lpBuffer,
    DWORD  nNumberOfBytes,
    LPOVERLAPPED  lpOverlapped
    );

Parameters

lpBuffer
Caller-supplied pointer to a buffer containing data to be sent to the device.
nNumberOfBytes
Caller-supplied number of bytes to be written. This is the number of bytes in the buffer pointed to by lpBuffer.
lpOverlapped
Optional, caller-supplied pointer to an OVERLAPPED structure (described in the Platform SDK documentation).

Return Value

If the operation succeeds, the method should return S_OK. Otherwise, it should return one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in stiusd.h. Include stiusd.h.

Comments

It is only necessary to call IStiUSD::RawWriteCommand if commands and data are written to a device by different methods. For other devices, IStiUSD::RawWriteData can be used for both commands and data. If the call is not implemented, it must return STIERR_UNSUPPORTED.

Implementation of this method, along with the meaning of buffer contents, are vendor-defined.

See Also

IStiDevice::RawWriteCommand


IStiUSD::RawWriteData

A still image minidriver's IStiUSD::RawWriteData method writes data to a still image device.

STDMETHODIMP
  RawWriteData(
    LPVOID  lpBuffer,
    DWORD  dwNumberOfBytes,
    LPOVERLAPPED  lpOverlapped
    );

Parameters

lpBuffer
Caller-supplied pointer to a buffer containing data to be sent to the device.
dwNumberOfBytes
Caller-supplied number of bytes to be written. This is the number of bytes in the buffer pointed to by lpBuffer.
lpOverlapped
Optional, caller-supplied pointer to an OVERLAPPED structure (described in the Platform SDK documentation).

Return Value

If the operation succeeds, the method should return S_OK. Otherwise, it should return one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in stiusd.h. Include stiusd.h.

Comments

A still image minidriver typically implements this method by calling WriteFile (described in the Platform SDK documentation).

See Also

IStiDevice::RawWriteData


IStiUSD::SetNotificationHandle

A still image minidriver's IStiUSD::SetNotificationHandle method specifies an event handle that the minidriver should use to inform the caller of device events.

STDMETHODIMP
  SetNotificationHandle(
    HANDLE  hEvent
    );

Parameters

hEvent
Caller-supplied handle to a Win32 event, created by calling CreateEvent.

Return Value

If the operation succeeds, the method should return S_OK. Otherwise, it should return one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in stiusd.h. Include stiusd.h.

Comments

If the driver (and device) supports asynchronous notification of still image device events, the minidriver's IStiUSD::SetNotificationHandle method is the means by which the Event Monitor requests the driver to notify it when an event occurs.

If hEvent is an event handle, the IStiUSD::SetNotificationHandle method should store the handle and use it as an input argument to SetEvent (described in the Platform SDK documentation). The driver should call SetEvent each time a device event is detected, to notify the Event Monitor that an event has occurred.

If hEvent is NULL, the method should disable notification of device events.


IStiDeviceControl Interface Methods

This section describes the methods defined for the IStiDeviceControl COM interface. Method prototypes are contained in stiusd.h.


IStiDeviceControl::AddRef

The IStiDeviceControl::AddRef method increments the reference count for the IStiDeviceControl interface.

HRESULT
  AddRef(
    VOID
    );

Parameters

None

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in stiusd.h. Include stiusd.h.

Comments

The IStiDeviceControl::AddRef method should be called from within a user-mode still image minidriver's IStiUSD::Initialize method.

A still image minidriver receives an IStiDeviceControl interface pointer as an input argument to its IStiUSD::Initialize method.

See Also

IStiDeviceControl::Release


IStiDeviceControl::GetMyDeviceOpenMode

The IStiDeviceControl::GetMyDeviceOpenMode method allows a still image minidriver to obtain the transfer mode that an application specified when it created an instance of a still image device.

HRESULT
  GetMyDeviceOpenMode(
    LPDWORD  pdwOpenMode
    );

Parameters

pdwOpenMode
Receives the mode flag that an application previously specified as the dwMode argument to IStillImage::CreateDevice.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in stiusd.h. Include stiusd.h.

Comments

A still image minidriver receives an IStiDeviceControl interface pointer as an input argument to its IStiUSD::Initialize method.


IStiDeviceControl::GetMyDevicePortName

The IStiDeviceControl::GetMyDevicePortName method allows a user-mode still image minidriver to obtain a device's port name.

HRESULT
  GetMyDevicePortName(
    LPWSTR  lpszDevicePath,
    DWORD  cwDevicePathSize
    );

Parameters

lpszDevicePath
Caller-supplied pointer to a buffer to receive the device's port name.
cwDevicePathSize
Caller-supplied number of characters (of type TCHAR) in the buffer pointed to by lpszDevicePath.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in stiusd.h. Include stiusd.h.

Comments

The path name that a still image minidriver receives by calling IStiDeviceControl::GetMyDevicePortName can be used as an input argument to CreateFile (described in the Platform SDK documentation).

A still image minidriver receives an IStiDeviceControl interface pointer as an input argument to its IStiUSD::Initialize method.


IStiDeviceControl::Release

The IStiDeviceControl::Release method closes the instance of the COM object that was created when a minidriver client called IStiUSD::Initialize.

HRESULT
  Release(
    VOID
    );

Parameters

None

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in stiusd.h. Include stiusd.h.

Comments

The IStiDeviceControl::Release method should be called from within the destructor function of a user-mode still image minidriver's IStiUSD interface. (For more information, see Creating a User-Mode Still Image Minidriver.)

A still image minidriver receives an IStiDeviceControl interface pointer as input to its IStiUSD::Initialize method.

See Also

IStiDeviceControl::AddRef


IStiDeviceControl::WriteToErrorLog

The IStiDeviceControl::WriteToErrorLog method allows a user-mode still image minidriver to write a message into the Still Image error log.

HRESULT
  WriteToErrorLog(
    DWORD  dwMessageType,
    LPCWSTR  pszMessage,
    DWORD  dwErrorCode
    );

Parameters

dwMessageType
Caller-supplied constant value representing the message type. The following values are defined in sti.h:

STI_TRACE_INFORMATION
STI_TRACE_WARNING
STI_TRACE_ERROR

pszMessage
Caller-supplied pointer to a message string to be written to the log file.
dwErrorCode
Not used.

Return Value

If the operation succeeds, the method returns S_OK. Otherwise, it returns one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in stiusd.h. Include stiusd.h.

Comments

The Still Image error log file is named sti_trace.log and is located in the Windows directory. The Control Panel allows a user to select which still image error types (informational, warning, or error) are written to the error log (see Non-Modifiable Registry Entries).

Error messages should be reserved for critical error conditions, such as device hardware failures. Informational messages can be used for your own debugging purposes. Logged messages aren't visible to users, but they might be used by a support engineer to help debug a user's problems.

A still image minidriver receives an IStiDeviceControl interface pointer as input to its IStiUSD::Initialize method.


Still Image Structures

This section describes the structures used with the Still Image COM interfaces. Structure definitions are contained in sti.h and stiusd.h.


STI_DEV_CAPS

The STI_DEV_CAPS structure is used as a parameter to the IStiDevice::GetCapabilities method. It is also a member of the STI_DEVICE_INFORMATION and STI_WIA_DEVICE_INFORMATION structures.

typedef struct _STI_DEV_CAPS {
  DWORD  dwGeneric;
} STI_DEV_CAPS, *PSTI_DEV_CAPS;

Members

dwGeneric
Contains bit flags identifying device capabilities. The following flags are defined.
Flag Definition
STI_GENCAP_AUTO_PORTSELECT
The driver is capable of determining which LPT or COM port the device is connected to. If this flag is set, the user can select "Auto" for the port during device installations, and the driver must determine the port.
STI_GENCAP_GENERATE_ARRIVALEVENT
The still image server will generate a GUID_DeviceArrivedLaunch event when the device is successfully initialized, typically in response to PnP arrival. (Events are not generated on initial enumeration by the server, to avoid end-user confusion.)
STI_GENCAP_NOTIFICATIONS
The device supports event notifications (either asynchronously or through polling), and the device can be subscribed to (see IStiDevice::Subscribe).
STI_GENCAP_POLLING_NEEDED
The device is not capable of issuing asynchronous notifications; polling of the device is required (see IStiDevice::GetStatus).
STI_GENCAP_SUBSET
A driver with more features exists. An IHV driver with a full set of features should not have this bit set.
STI_GENCAP_WIA
The user-mode still image driver is WIA-capable.

The values assigned to these flags are based on registry contents and are supplied by the Capabilities entry for the device's .inf file. See INF Files for Still Image Devices.

Headers

Declared in sti.h. Include sti.h.


STI_DEVICE_INFORMATION

The STI_DEVICE_INFORMATION structure is used as an output parameter for the IStillImage::GetDeviceList and IStillImage::GetDeviceInfo functions. It is used as an input parameter for IStillImage::SetupDeviceParameters.

typedef struct _STI_DEVICE_INFORMATION {
  DWORD  dwSize;
  STI_DEVICE_TYPE  DeviceType;
  WCHAR  szDeviceInternalName[STI_MAX_INTERNAL_NAME_LENGTH];
  STI_DEV_CAPS  DeviceCapabilities;
  DWORD  dwHardwareConfiguration;
  LPWSTR  pszVendorDescription;
  LPWSTR  pszDeviceDescription;
  LPWSTR  pszPortName;
  LPWSTR  pszPropProvider;
  LPWSTR  pszLocalName;
} STI_DEVICE_INFORMATION, *PSTI_DEVICE_INFORMATION;

Members

dwSize
Caller-supplied size, in bytes, of the STI_DEVICE_INFORMATION structure.
DeviceType
An STI_DEVICE_TYPE-typed value identifying the still image device type.
szDeviceInternalName
Character array containing the device's internal name string. The string can have at most STI_MAX_INTERNAL_NAME_LENGTH characters, including the terminating null character. STI_MAX_INTERNAL_NAME_LENGTH is defined in sti.h.
DeviceCapabilities
Structure of type STI_DEV_CAPS.
dwHardwareConfiguration
Type of bus connection. The following constants are defined in sti.h:

STI_HW_CONFIG_PARALLEL
STI_HW_CONFIG_SCSI
STI_HW_CONFIG_SERIAL
STI_HW_CONFIG_USB
STI_HW_CONFIG_UNKNOWN

pszVendorDescription
Pointer to a vendor identification string, obtained from the INF Manufacturer section of the device's INF file.
pszDeviceDescription
Pointer to a device description string, obtained from the INF Models section of the device's INF file.
pszPortName
Pointer to a string identifying the device's port.
pszPropProvider
Pointer to a string containing the filename and entry point of a DLL for adding device-specific property sheet pages to the control panel. Obtained from the PropertyPages entry in the device's INF file.
pszLocalName
Pointer to the local device name supplied by the user during installation, for use in displays.

Headers

Declared in sti.h. Include sti.h.


STI_DEVICE_STATUS

The STI_DEVICE_STATUS structure is used as a parameter to the IStiDevice::GetStatus and IStiUSD::GetStatus methods.

typedef struct _STI_DEVICE_STATUS {
  DWORD  dwSize;
  DWORD  StatusMask;
  DWORD  dwOnlineState;
  DWORD  dwHardwareStatusCode;
  DWORD  dwEventHandlingState;
  DWORD  dwPollingInterval;
} STI_DEVICE_STATUS, *PSTI_DEVICE_STATUS;

Members

dwSize
Caller-supplied size, in bytes, of the STI_DEVICE_STATUS structure.
StatusMask
One or more caller-supplied bit flags, indicating the type of status information being requested. The following flags are defined:
Flag | Definition
STI_DEVSTATUS_EVENTS_STATE | The driver should fill in the dwEventHandlingState member.
STI_DEVSTATUS_ONLINE_STATE | The driver should fill in the dwOnlineState member.

dwOnlineState
Bit flags indicating the device's current status. Flags are listed in the following table, and defined in sti.h.

Currently use of STI_ONLINESTATE_OPERATIONAL is required, while use of all other flags is optional. (Currently, STI_ONLINESTATE_OPERATIONAL is the only flag that is checked by the Still Image server.)
Flag Definition
STI_ONLINESTATE_BUSY
The device is busy.
STI_ONLINESTATE_ERROR
The device has reported an error.
STI_ONLINESTATE_INITIALIZING
The device is being initialized.
STI_ONLINESTATE_IO_ACTIVE
The device is active but not accepting commands.
STI_ONLINESTATE_OFFLINE
The device is off-line.
STI_ONLINESTATE_OPERATIONAL
The device is online and ready. If set, the Control Panel indicates the device is ready. Otherwise, it indicates the device is off-line.
STI_ONLINESTATE_PAPER_JAM
The device has reported a paper jam.
STI_ONLINESTATE_PAPER_PROBLEM
The device has reported an unspecified paper problem.
STI_ONLINESTATE_PAUSED
The device is paused.
STI_ONLINESTATE_PENDING
I/O operations are pending.
STI_ONLINESTATE_POWER_SAVE
The device is in power save mode.
STI_ONLINESTATE_TRANSFERRING
The device is transferring data.
STI_ONLINESTATE_USER_INTERVENTION
The device requires user intervention.
STI_ONLINESTATE_WARMING_UP
The device is warming up.

dwHardwareStatusCode
Optional device-specific, vendor-defined value.
dwEventHandlingState
Contains bit flags indicating event status. The following flags are defined in sti.h.
Flag Definition
STI_EVENTHANDLING_ENABLED
Not used.
STI_EVENTHANDLING_PENDING
A device event has occurred.
STI_EVENTHANDLING_POLLING
Not used.

dwPollingInterval
Time value, in milliseconds, indicating how often the device should be polled, if polling is required.

Headers

Declared in sti.h. Include sti.h.


STI_DIAG

The STI_DIAG structure is used as a parameter to the IStiDevice::Diagnostic and IStiUSD::Diagnostic methods.

typedef struct _STI_DIAG {
  DWORD  dwSize;
  DWORD  dwBasicDiagCode;
  DWORD  dwVendorDiagCode;
  DWORD  dwStatusMask;
  STI_ERROR_INFO  sErrorInfo;
} STI_DIAG, *LPSTI_DIAG;

Members

dwSize
Caller-supplied size, in bytes, of the STI_DIAG structure.
dwBasicDiagCode
Bit flag indicating the type of test to be performed. Currently this must be STI_DIAGCODE_HWPRESENCE.
dwVendorDiagCode
Optional, vendor-defined diagnostic request code.
dwStatusMask
Reserved for future use.
sErrorInfo
Structure of type STI_ERROR_INFO.

Headers

Declared in sti.h. Include sti.h.


STI_ERROR_INFO

The STI_ERROR_INFO structure is used as a parameter for the IstiDevice::GetLastErrorInfo and IstiUSD::GetLastErrorInfo methods. It is also used as a member of the STI_DIAG structure.

typedef struct _ERROR_INFO {
  DWORD  dwSize;
  DWORD  dwGenericError;
  DWORD  dwVendorError;
  WCHAR  szExtendedErrorText[255];
} STI_ERROR_INFO, *PSTI_ERROR_INFO;

Members

dwSize
Caller-supplied size, in bytes, of the STI_ERROR_INFO structure.
dwGenericError
Win32 error code.
dwVendorError
Optional, vendor-specific error code.
szExtendedErrorText
Optional character array containing a text string describing the error.

Headers

Declared in sti.h. Include sti.h.


STI_USD_CAPS

The STI_USD_CAPS structure is used as a parameter for the IStiUSD::GetCapabilities method.

typedef struct _STI_USD_CAPS {
  DWORD  dwVersion;
  DWORD  dwGenericCaps;
} STI_USD_CAPS,*PSTI_USD_CAPS;

Members

dwVersion
STI version number. This value must be STI_VERSION, defined in sti.h.
dwGenericCaps
Bit flags indicating driver capabilities. The following flags are defined in stiusd.h.
Flag Definition
STI_USD_GENCAP_NATIVE_PUSHSUPPORT
The driver supports asynchronous device notifications.
STI_USD_GENCAP_OPEN_DEVICE_FOR_ME
Not used.

Headers

Declared in stiusd.h. Include stiusd.h.


STI_WIA_DEVICE_INFORMATION

The STI_WIA_DEVICE_INFORMATION structure contains device information is used

typedef struct _STI_WIA_DEVICE_INFORMATION {
  DWORD  dwSize;
  STI_DEVICE_TYPE  DeviceType;
  WCHAR  szDeviceInternalName[STI_MAX_INTERNAL_NAME_LENGTH];
  STI_DEV_CAPS  DeviceCapabilities;
  DWORD  dwHardwareConfiguration;
  LPWSTR  pszVendorDescription;
  LPWSTR  pszDeviceDescription;
  LPWSTR  pszPortName;
  LPWSTR  pszPropProvider;
  LPWSTR  pszLocalName;
  LPWSTR  pszUiDll;
  LPWSTR  pszServer;
} STI_WIA_DEVICE_INFORMATION, *PSTI_WIA_DEVICE_INFORMATION;

Members

dwSize
Caller-supplied size, in bytes, of the STI_WIA_DEVICE_INFORMATION structure.
DeviceType
A value of type STI_DEVICE_TYPE that identifies the type of the hardware imaging device.
szDeviceInternalName
Character array containing the device's internal name string, used for reference when the device object is created. The string can have at most STI_MAX_INTERNAL_NAME_LENGTH characters, including the terminating null character. STI_MAX_INTERNAL_NAME_LENGTH is defined in sti.h.
DeviceCapabilities
A structure of type STI_DEV_CAPS.
dwHardwareConfiguration
Type of bus connection. This value can be one of the following constants, which are defined in sti.h:

STI_HW_CONFIG_PARALLEL
STI_HW_CONFIG_SCSI
STI_HW_CONFIG_SERIAL
STI_HW_CONFIG_USB
STI_HW_CONFIG_UNKNOWN

pszVendorDescription
Pointer to a vendor identification string, obtained from the INF Manufacturer section of the device's INF file.
pszDeviceDescription
Pointer to a vendor-provided device description string, obtained from the INF Models section of the device's INF file.
pszPortName
Pointer to a string identifying the device's port.
pszPropProvider
Pointer to a string containing the filename and entry point of a DLL for adding device-specific property sheet pages to the control panel. Obtained from the PropertyPages entry in the device's INF file.
pszLocalName
Pointer to a string containing the local device name (the "friendly" name). This string is supplied by the user during installation, typically for use in user interface displays.
pszUiDll
Pointer to the WIA user interface DLL.
pszServer
Pointer to the WIA server.

Headers

Declared in sti.h. Include sti.h.


STINOTIFY

The STINOTIFY structure is used as a parameter to the IStillImage::LaunchApplicationForDevice, IStiDevice::GetLastNotificationData, and IStiUSD::GetNotificationData methods.

typedef struct _STINOTIFY {
  DWORD  dwSize;
  GUID  guidNotificationCode;
  BYTE  abNotificationData[MAX_NOTIFICATION_DATA];
} STINOTIFY,*LPSTINOTIFY;

Members

dwSize
Caller-supplied size, in bytes, of the STINOTIFY structure.
guidNotificationCode
GUID of the event. For more information, see Still Image Device Events.
abNotificationData
Byte array containing optional, vendor-defined information.

Headers

Declared in sti.h. Include sti.h.


STISUBSCRIBE

The STISUBSCRIBE structure is used as a parameter for the IStiDevice::Subscribe method.

typedef struct _STISUBSCRIBE {
  DWORD  dwSize;
  DWORD  dwFlags;
  DWORD  dwFilter;
  HWND  hWndNotify;
  HANDLE  hEvent;
  UINT  uiNotificationMessage;
} STISUBSCRIBE,*LPSTISUBSCRIBE;

Members

dwSize
Caller-supplied size, in bytes, of the STISUBSCRIBE structure.
dwFlags
One of the following bit flags, defined in sti.h.
Flag Definition
STI_SUBSCRIBE_FLAG_EVENT
Event notifications should be delivered to the application by calls to SetEvent. The hEvent member contains a Win32 event handle.
STI_SUBSCRIBE_FLAG_WINDOW
Event notifications should be delivered to the application using Window messages. The dwWndNotify member contains a window handle and uiNotificationMessage contains a Window message.

dwFilter
Reserved for system use.
hWndNotify
Handle to an application window that should receive the message specified by uiNotificationMessage when an event occurs. Used only if STI_SUBSCRIBE_FLAG_WINDOW is set in dwFlags.
hEvent
Handle to a Win32 event created with CreateEvent, which the Event Monitor will use with SetEvent when an event occurs and which the application can wait on.
uiNotificationMessage
Windows message that should be passed to the dwWndNotify window when an event occurs.

Headers

Declared in sti.h. Include sti.h.


Still Image Data Types

This section describes the data types used with the Still Image COM interfaces. Type definitions are contained in sti.h.


STI_DEVICE_TYPE

The STI_DEVICE_TYPE type identifies the device type of a still image device.

typedef DWORD STI_DEVICE_TYPE;

Headers

Declared in sti.h. Include sti.h.

Comments

The DWORD is divided into a HIWORD containing the major device type, and a LOWORD containing a vendor-defined subtype.

The following constants are defined for the major device type:

typedef enum _STI_DEVICE_MJ_TYPE
{
  StiDeviceTypeDefault          = 0,
  StiDeviceTypeScanner          = 1,
  StiDeviceTypeDigitalCamera    = 2,
  StiDeviceTypeStreamingVideo   = 3
} STI_DEVICE_MJ_TYPE;

The following macros are used to extract the major device type and subtype:

GET_STIDEVICE_TYPE(dwDevType)
GET_STIDEVICE_SUBTYPE(dwDevType)


SCSI Still Image I/O Control Codes

This section describes the I/O control codes recognized by the kernel-mode still image driver for SCSI buses. The codes are defined in scsiscan.h.


IOCTL_SCSISCAN_CMD

Creates a customized SCSI control descriptor block (CDB) and sends it to the kernel-mode still image driver for SCSI buses.

DeviceIoControl Parameters

hDevice
Device handle.
dwIoControlCode
IOCTL_SCSISCAN_CMD
lpInBuffer
Pointer to a SCSISCAN_CMD structure.
nInBufferSize
Size of the input buffer.
lpOutBuffer
Pointer to a data buffer. Depending on the type of I/O operation, this buffer might supply or receive data. See the following Comments section.
nOutBufferSize
Size of the output buffer.
lpBytesReturned
Pointer to a location to receive the number of bytes returned.
lpOverlapped
Optional pointer to an OVERLAPPED structure (described in the Platform SDK documentation).

Headers

Declared in scsiscan.h. Include scsiscan.h.

Comments

When the DeviceloControl function is called with the IOCTL_SCSISCAN_CMD I/O control code, the caller must specify the address of a SCSISCAN_CMD structure as the function's lpInBuffer parameter. This structure specifies the type of operation being requested. The kernel-mode driver constructs a SCSI Request Block (SRB) from the SCSISCAN_CMD structure's contents.

For SCSI commands that involve data transfers, the DeviceIoControl function's lpOutBuffer must point to a data buffer. For read operations, this buffer will receive data read from the device. For write operations, the buffer must contain the data to be written.

For more information, see Accessing Kernel-Mode Drivers for Still Image Devices.

Code Example

SCSISCAN_CMD  Cmd;
UCHAR         SrbStatus;

// Construct the SCSISCAN_CMD structure and
// clear out the sense buffer.
memset(&Cmd, 0, sizeof(Cmd));
memset(SenseBuffer,0, sizeof(SenseBuffer));

Cmd.Size = sizeof(SCSISCAN_CMD);
Cmd.SrbFlags = SRB_FLAGS_DATA_OUT;
Cmd.CdbLength = 6;
Cmd.SenseLength = 18;
Cmd.TransferLength = len;
Cmd.pSrbStatus = &SrbStatus;
Cmd.pSenseBuffer = SenseBuffer;

Cmd.Cdb[0] = 0x0A;
Cmd.Cdb[4] = ((PFOUR_BYTE)&len) -> Byte0;
Cmd.Cdb[3] = ((PFOUR_BYTE)&len) -> Byte1;
Cmd.Cdb[2] = ((PFOUR_BYTE)&len) -> Byte2;
Cmd.Cdb[5] = 0;

DeviceIoControl(
           gb_Scan_Handle,
           (DWORD) IOCTL_SCSISCAN_CMD,
           &Cmd,
           sizeof(Cmd),
           buf,
           len,
           amount_written_ptr,
           NULL
           );

if (SRB_STATUS_SUCCESS != SRB_STATUS(SrbStatus))
{
  fprintf(stderr, "WriteScanner error.\n");
  if (SRB_STATUS_DATA_OVERRUN == SrbStatus)
  {
    fprintf(stderr, "Data over/under run. This is ok.\n");
  }
  else if ((SenseBuffer[2] & 0xf) == SCSI_SENSE_UNIT_ATTENTION)
  {
    fprintf(stderr, "Unit attention.  Retrying request....\n");
    memset(SenseBuffer,0, sizeof(SenseBuffer));
    SrbStatus = 0;
    DeviceIoControl(
      gb_Scan_Handle,
      (DWORD) IOCTL_SCSISCAN_CMD,
      &Cmd,
      sizeof(Cmd),
      buf,
      len,
      amount_written_ptr,
      NULL
      );
    }
  }
}


IOCTL_SCSISCAN_GET_INFO

Returns device information.

DeviceIoControl Parameters

hDevice
Device handle.
dwIoControlCode
IOCTL_SCSISCAN_GET_INFO
lpInBuffer
NULL.
nInBufferSize
Zero.
lpOutBuffer
Pointer to a SCSISCAN_INFO structure.
nOutBufferSize
Size of the buffer pointed to by lpOutBuffer.
lpBytesReturned
Pointer to a location to receive the number of bytes returned.
lpOverlapped
Optional pointer to an OVERLAPPED structure (described in the Platform SDK documentation).

Headers

Declared in scsiscan.h. Include scsiscan.h.

Comments

When the DeviceloControl function is called with the IOCTL_SCSISCAN_GET_INFO I/O control code, the caller must specify the address of a SCSISCAN_INFO structure as the function's lpOutbuffer parameter. The kernel-mode driver fills in the structure.


IOCTL_SCSISCAN_LOCKDEVICE

Reserved for use by Microsoft.


IOCTL_SCSISCAN_SET_TIMEOUT

Modifies the time-out value used by the kernel-mode still image driver for SCSI buses when it accesses a device.

DeviceIoControl Parameters

hDevice
Device handle.
dwIoControlCode
IOCTL_SCSISCAN_SET_TIMEOUT
lpInBuffer
Pointer to a location containing a time-out value, in half seconds.
nInBufferSize
Size of the input buffer.
lpOutBuffer
NULL.
nOutBufferSize
Zero.
lpBytesReturned
Pointer to a location to receive the number of bytes returned.
lpOverlapped
Optional pointer to an OVERLAPPED structure (described in the Platform SDK documentation).

Headers

Declared in scsiscan.h. Include scsiscan.h.

Comments

When the kernel-mode SCSI still image driver sends a SCSI command to a device, by default the driver waits 30 seconds before timing out the operation. You can change the time-out value for a device by calling the DeviceloControl function with the IOCTL_SCSISCAN_CMD I/O control code. The specified time-out value stays in effect until the device is closed.

Time-out values are specified in half seconds. Thus a specified value of 100 causes the driver to wait 50 seconds before timing out the device.

For more information, see Accessing Kernel-Mode Drivers for Still Image Devices.

Code Example

ULONG timeout = 240;
fRet = DeviceIoControl( m_DeviceDataHandle,
        (DWORD)IOCTL_SCSISCAN_SET_TIMEOUT,
        &timeout,
        sizeof(ULONG),
        NULL, NULL, &dwBytesReturned, NULL);


IOCTL_SCSISCAN_UNLOCKDEVICE

Reserved for use by Microsoft.


SCSI Still Image Structures

This section describes the structures associated with I/O control codes that are recognized by the kernel-mode still image driver for SCSI buses. The structures are defined in scsiscan.h.


SCSISCAN_CMD

The SCSISCAN_CMD structure is used as a parameter to DeviceIoControl, when the specified I/O control code is IOCTL_SCSISCAN_CMD.

typedef struct _SCSISCAN_CMD {
  ULONG  Reserved1;
  ULONG  Size;
  ULONG  SrbFlags;
  UCHAR  CdbLength;
  UCHAR  SenseLength;
  UCHAR  Reserved2;
  UCHAR  Reserved3;
  ULONG  TransferLength;
  UCHAR  Cdb[16];
  PUCHAR  pSrbStatus;
  PUCHAR  pSenseBuffer;
} SCSISCAN_CMD, *PSCSISCAN_CMD;

Members

Reserved1
Reserved. Do not use.
Size
Caller-supplied size, in bytes, of the SCSISCAN_CMD structure.
SrbFlags
Caller-supplied SRB_FLAGS-prefixed bit flag specifying the requested operation. Flags are defined in srb.h.
CdbLength
Length, in bytes, of the CDB contained in the Cdb member.
SenseLength
Length, in bytes, of the sense buffer pointed to by the pSenseBuffer member.
Reserved2
Reserved. Do not use.
Reserved3
Reserved. Do not use.
TransferLength
Length, in bytes, of the buffer to be transferred. This should match the value specified for the DeviceIoControl function's nOutBufferSize parameter.
Cdb
Caller-supplied CDB data. (The CDB structure is declared in scsi.h.)
pSrbStatus
Caller-supplied pointer that will receive one of the SRB_STATUS-prefixed status values defined in srb.h.
pSenseBuffer
Caller-supplied pointer to a request-sense buffer, to be filled in by the kernel-mode driver.

Headers

Declared in scsiscan.h. Include scsiscan.h, srb.h, and scsi.h.


SCSISCAN_INFO

The SCSISCAN_INFO structure is used as a parameter to DeviceIoControl (described in the Platform SDK documentation), when the specified I/O control code is IOCTL_SCSISCAN_GET_INFO.

typedef struct _SCSISCAN_INFO {
  ULONG  Size;
  ULONG  Flags;
  UCHAR  PortNumber;
  UCHAR  PathId;
  UCHAR  TargetId;
  UCHAR  Lun;
  UCHAR  AdapterName[MAX_STRING];
  ULONG  Reserved;
} SCSISCAN_INFO, *PSCSISCAN_INFO;

Members

Size
Size, in bytes, of the SCSISCAN_INFO structure.
Flags
Not used, must be zero.
PortNumber
SCSI adapter number.
PathId
Host SCSI ID.
TargetId
Target SCSI ID.
Lun
Target logical unit number (LUN).
AdapterName
For internal use only.
Reserved
For internal use only.

Headers

Declared in scsiscan.h. Include scsiscan.h.


USB Still Image I/O Control Codes

This section describes the I/O control codes recognized by the kernel-mode still image driver for USB buses. The codes are defined in usbscan.h.


IOCTL_CANCEL_IO

Cancels activity on the specified USB transfer pipe that is associated with the specified device handle.

DeviceIoControl Parameters

hDevice
Device handle, obtained by calling CreateFile.
dwIoControlCode
IOCTL_CANCEL_IO
lpInBuffer
Pointer to a location containing a PIPE_TYPE-typed value.
nInBufferSize
Size of the input buffer.
lpOutBuffer
NULL
nOutBufferSize
Zero.
lpBytesReturned
Pointer to a location to receive the number of bytes returned.
lpOverlapped
Optional pointer to an OVERLAPPED structure (described in the Platform SDK documentation).

Headers

Declared in usbscan.h. Include usbscan.h.

Comments

When the DeviceloControl function is called with the IOCTL_CANCEL_IO I/O control code, the caller must specify one of the PIPE_TYPE-typed values as the function's lpInBuffer parameter. This value indicates on which of the transfer pipes (interrupt, bulk IN, bulk OUT) the operation should be performed. For more information, see Accessing Kernel-Mode Drivers for Still Image Devices.

Code Example

BOOL bState = FALSE;
DWORD cbRet = 0;
OVERLAPPED overlapped;

memset(&overlapped, 0, sizeof(OVERLAPPED));
overlapped.hEvent =
    CreateEvent(NULL, // pointer to security attributes
               FALSE, // automatic reset
               FALSE, // initialize to nosignaled
               NULL); // pointer to the event-object name
bState =
    DeviceIoControl(hdlDevice,
                    (DWORD) IOCTL_CANCEL_IO,
                    (LPVOID)&pipeType,
                    sizeof(PIPE_TYPE),
                    NULL,
                    0,
                    &cbRet,
                    &overlapped);


IOCTL_GET_CHANNEL_ALIGN_RQST

Returns a USB device's maximum packet size for the read, write, and interrupt transfer pipes associated with the specified device handle.

DeviceIoControl Parameters

hDevice
Device handle, obtained by calling CreateFile.
dwIoControlCode
IOCTL_GET_CHANNEL_ALIGN_RQST
lpInBuffer
NULL.
nInBufferSize
Zero.
lpOutBuffer
Pointer to a CHANNEL_INFO structure.
nOutBufferSize
Size of the output buffer.
lpBytesReturned
Pointer to a location to receive the number of bytes returned.
lpOverlapped
Optional pointer to an OVERLAPPED structure (described in the Platform SDK documentation).

Headers

Declared in usbscan.h. Include usbscan.h.

Comments

When the DeviceloControl function is called with the IOCTL_GET_CHANNEL_ALIGN_RQST I/O control code, the caller must specify the address of a CHANNEL_INFO structure as the function's lpOutBuffer parameter. The kernel-mode driver fills in the structure.

For more information, see Accessing Kernel-Mode Drivers for Still Image Devices.

Code Example

DWORD           cbRet;
CHANNEL_INFO    channelInfo = {0,0,0};
OVERLAPPED      overlapped;
BOOL            bRet;
memset(&overlapped, 0, sizeof(OVERLAPPED));
overlapped.hEvent =
    CreateEvent(
                NULL, // pointer to security attributes
                FALSE, // automatic reset
                FALSE, // initialize to not signaled
                NULL); // pointer to the event-object name
bRet = DeviceIoControl(DeviceHandle,
                       (DWORD) IOCTL_GET_CHANNEL_ALIGN_RQST,
                       NULL,
                       0,
                       &channelInfo,
                       sizeof(CHANNEL_INFO),
                       &cbRet,
                       &overlapped);


IOCTL_GET_DEVICE_DESCRIPTOR

Returns vendor and device identifiers.

DeviceIoControl Parameters

hDevice
Device handle, obtained by calling CreateFile.
dwIoControlCode
IOCTL_GET_DEVICE_DESCRIPTOR
lpInBuffer
Pointer to a DEVICE_DESCRIPTOR structure.
nInBufferSize
Size of the input buffer.
lpOutBuffer
Pointer to a DEVICE_DESCRIPTOR structure (same as lpInbuffer).
nOutBufferSize
Size of the output buffer.
lpBytesReturned
Pointer to a location to receive the number of bytes returned.
lpOverlapped
Optional pointer to an OVERLAPPED structure (described in the Platform SDK documentation).

Headers

Declared in usbscan.h. Include usbscan.h.

Comments

When the DeviceloControl function is called with the IOCTL_GET_USB_DESCRIPTOR I/O control code, the caller must specify the address of a DEVICE_DESCRIPTOR structure as the function's lpOutbuffer parameter. The kernel-mode driver fills in the structure.

For more information, see Accessing Kernel-Mode Drivers for Still Image Devices.


IOCTL_GET_PIPE_CONFIGURATION

Returns a description of every transfer pipe supported for a device.

DeviceIoControl Parameters

hDevice
Device handle, obtained by calling CreateFile.
dwIoControlCode
IOCTL_GET_PIPE_CONFIGURATION
lpInBuffer
NULL.
nInBufferSize
Zero.
lpOutBuffer
Pointer to a USBSCAN_PIPE_CONFIGURATION structure.
nOutBufferSize
Size of the output buffer.
lpBytesReturned
Pointer to a location to receive the number of bytes returned.
lpOverlapped
Optional pointer to an OVERLAPPED structure (described in the Platform SDK documentation).

Headers

Declared in usbscan.h. Include usbscan.h.

Comments

When the DeviceloControl function is called with the IOCTL_GET_PIPE_CONFIGURATION I/O control code, the caller must specify the address of a USBSCAN_PIPE_CONFIGURATION structure as the function's lpOutbuffer parameter. The kernel-mode driver fills in the structure.

For more information, see Accessing Kernel-Mode Drivers for Still Image Devices.


IOCTL_GET_USB_DESCRIPTOR

Returns a specified USB Descriptor.

DeviceIoControl Parameters

hDevice
Device handle, obtained by calling CreateFile.
dwIoControlCode
IOCTL_GET_USB_DESCRIPTOR
lpInBuffer
Pointer to a USBSCAN_GET_DESCRIPTOR structure.
nInBufferSize
Size of the input buffer.
lpOutBuffer
Pointer to a USB_DEVICE_DESCRIPTOR, USB_STRING_DESCRIPTOR, or USB_CONFIGURATION_DESCRIPTOR structure.
nOutBufferSize
Size of the output buffer.
lpBytesReturned
Pointer to a location to receive the number of bytes returned.
lpOverlapped
Optional pointer to an OVERLAPPED structure (described in the Platform SDK documentation).

Headers

Declared in usbscan.h. Include usbscan.h.

Comments

When the DeviceloControl function is called with the IOCTL_GET_USB_DESCRIPTOR I/O control code, the caller must specify the address of a USBSCAN_GET_DESCRIPTOR structure as the function's lpInBuffer parameter. Depending on the value specified for the DescriptorType member of the USBSCAN_GET_DESCRIPTOR structure, the function's lpOutbuffer parameter must point to either a USB_DEVICE_DESCRIPTOR, USB_STRING_DESCRIPTOR, or USB_CONFIGURATION_DESCRIPTOR structure.

The kernel-mode driver obtains a USB descriptor by calling UsbBuildGetDescriptorRequest.

For more information, see Accessing Kernel-Mode Drivers for Still Image Devices.

For more information about USB descriptors, see the Universal Serial Bus Specification.


IOCTL_GET_VERSION

Returns the version number of the driver.

DeviceIoControl Parameters

hDevice
Device handle, obtained by calling CreateFile.
dwIoControlCode
IOCTL_GET_VERSION
lpInBuffer
NULL
nInBufferSize
Zero.
lpOutBuffer
Pointer to a DRV_VERSION structure.
nOutBufferSize
Size of the output buffer.
lpBytesReturned
Pointer to a location to receive the number of bytes returned.
lpOverlapped
Optional pointer to an OVERLAPPED structure (described in the Platform SDK documentation).

Headers

Declared in usbscan.h. Include usbscan.h.

Comments

When the DeviceloControl function is called with the IOCTL_GET_VERSION I/O control code, the caller must specify the address of a DRV_VERSION structure as the function's lpOutBuffer parameter. The kernel-mode driver fills in the structure members.

For more information, see Accessing Kernel-Mode Drivers for Still Image Devices.

Code Example

DRV_VERSION        drvVersion = {0, 0, 0};
DWORD              cbRet;
OVERLAPPED         overlapped;
BOOL               bRet;

memset(&overlapped, 0, sizeof(OVERLAPPED));
overlapped.hEvent = CreateEvent(NULL, FALSE,  FALSE, NULL);
bRet = DeviceIoControl( DeviceHandle,
                        (DWORD) IOCTL_GET_VERSION,
                        NULL,
                        0,
                        &drvVersion,
                        sizeof(DRV_VERSION),
                        &cbRet,
                        &overlapped);

if( bRet == TRUE )
    WaitForSingleObject(overlapped.hEvent, INFINITE);

CloseHandle(overlapped.hEvent);


IOCTL_READ_REGISTERS

Reads from USB device registers, using the control pipe.

DeviceIoControl Parameters

hDevice
Device handle, obtained by calling CreateFile.
dwIoControlCode
IOCTL_READ_REGISTERS
lpInBuffer
Pointer to an IO_BLOCK structure.
nInBufferSize
Size of the input buffer.
lpOutBuffer
Pointer to a buffer to receive register contents.
nOutBufferSize
Size of the output buffer. The value must match the contents of the uLength member of the IO_BLOCK structure.
lpBytesReturned
Pointer to a location to receive the number of bytes returned.
lpOverlapped
Optional pointer to an OVERLAPPED structure (described in the Platform SDK documentation).

Headers

Declared in usbscan.h. Include usbscan.h.

Comments

When the DeviceloControl function is called with the IOCTL_READ_REGISTERS I/O control code, the caller must specify the address of an IO_BLOCK structure as the function's lpInBuffer parameter.

Using the IO_BLOCK contents, the kernel-mode driver creates a URB that contains a _URB_CONTROL_VENDOR_OR_CLASS_REQUEST structure.

The following table indicates the values assigned to _URB_CONTROL_VENDOR_OR_CLASS_REQUEST structure members.

Structure Member | Value Assigned
TransferFlags | 1
TransferBufferLength | pIoBlock->uLength
TransferBuffer | DeviceIoControl's lpOutBuffer argument.
TransferBufferMDL | NULL
RequestTypeReservedBits | 0xC0
Request | (pIoBlock->uLength > 1) ? 0x04 : 0x0C
Value | (SHORT)pIoBlock->uOffset
Index | pIoBlock->uIndex

For more information, see Accessing Kernel-Mode Drivers for Still Image Devices.

Code Example

DWORD           cbRet;
BOOL            bRet;
IO_BLOCK        IoBlock;
OVERLAPPED      overlapped;
BOOL            bRet ;

IoBlock.uOffset = (BYTE)byOffset;
IoBlock.uLength = (BYTE)byNbOfReg;
IoBlock.pbyData = pbyData;

memset(&overlapped, 0, sizeof(OVERLAPPED));
overlapped.hEvent = CreateEvent(
        NULL,         // pointer to security attributes,
                      // WIN95 ignores this parameter
        FALSE,        // automatic reset
        FALSE,        // initialize to not signaled
        NULL);        // pointer to the event-object name

bRet = DeviceIoControl( DeviceHandle,
                        (DWORD) IOCTL_READ_REGISTERS,
                        (PVOID)&IoBlock,
                        (DWORD)sizeof(IO_BLOCK),
                        (PVOID)pbyData,
                        (DWORD)byNbOfReg*sizeof(BYTE),
                        &cbRet,
                        &overlapped);

if( bRet == TRUE )
{
   WaitForSingleObject(overlapped.hEvent, INFINITE);
   // we do not the test, the result is zero
}

CloseHandle(overlapped.hEvent);


IOCTL_RESET_PIPE

Resets the specified USB transfer pipe that is associated with the specified device handle.

DeviceIoControl Parameters

hDevice
Device handle, obtained by calling CreateFile.
dwIoControlCode
IOCTL_RESET_PIPE
lpInBuffer
NULL
nInBufferSize
Zero.
lpOutBuffer
Pointer to a location containing a PIPE_TYPE-typed value.
nOutBufferSize
Size of the output buffer.
lpBytesReturned
Pointer to a location to receive the number of bytes returned.
lpOverlapped
Optional pointer to an OVERLAPPED structure (described in the Platform SDK documentation).

Headers

Declared in usbscan.h. Include usbscan.h.

Comments

When the DeviceloControl function is called with the IOCTL_RESET_PIPE I/O control code, the caller must specify one of the PIPE_TYPE-typed values as the function's lpInBuffer parameter. This value indicates on which of the transfer pipes (interrupt, bulk IN, bulk OUT) the operation should be performed. For more information, see Accessing Kernel-Mode Drivers for Still Image Devices.


IOCTL_SEND_USB_REQUEST

Sends a vendor-defined request to a USB device, using the control pipe, and optionally sends or receives additional data.

DeviceIoControl Parameters

hDevice
Device handle, obtained by calling CreateFile.
dwIoControlCode
IOCTL_SEND_USB_REQUEST
lpInBuffer
Pointer to an IO_BLOCK_EX structure.
nInBufferSize
Size of the input buffer.
lpOutBuffer
Pointer to the same buffer identified by the pbyData member of the IO_BLOCK_EX structure, or NULL if a data transfer is not being requested.
nOutBufferSize
Size of the output buffer, or zero if a data transfer is not being requested.
lpBytesReturned
Pointer to a location to receive the number of bytes returned.
lpOverlapped
Optional pointer to an OVERLAPPED structure (described in the Platform SDK documentation).

Headers

Declared in usbscan.h. Include usbscan.h.

Comments

When the DeviceloControl function is called with the IOCTL_SEND_USB_REQUEST control code, the caller must specify the address of an IO_BLOCK_EX structure as the function's lpInBuffer parameter. The type of request specified with this I/O control code is device-specific and vendor-defined, as are the type and size of any information that might be sent or received.

The following table shows how input arguments should be specified.

Argument | Read Operation | Write Operation | No Data Transfer
lpInBuffer | IO_BLOCK_EX pointer. | IO_BLOCK_EX pointer. | IO_BLOCK_EX pointer.
lpOutBuffer | Pointer to buffer that will receive data to be read. | Pointer to buffer containing data to be written. | NULL
lpOutBufferSize | Size of buffer. | Size of buffer. | Zero
bRequest member of IO_BLOCK_EX structure | Device-specific request code. | Device-specific request code. | Device-specific request code.
pbyData member of IO_BLOCK_EX structure | Same pointer as lpOutBuffer. | Same pointer as lpOutBuffer. | NULL
uLength member of IO_BLOCK_EX structure | Same value as lpOutBufferSize. | Same value as lpOutBufferSize. | Zero
fTransferDirectionIn member of IO_BLOCK_EX structure | TRUE | FALSE | FALSE

Note that the bmRequestType member of the IO_BLOCK_EX structure is not used with IOCTL_SEND_USB_REQUEST.

Using the IO_BLOCK_EX structure contents, the kernel-mode driver creates a URB that contains a _URB_CONTROL_VENDOR_OR_CLASS_REQUEST structure.

The following table indicates the values assigned to _URB_CONTROL_VENDOR_OR_CLASS_REQUEST structure members.

Structure Member | Value Assigned
TransferFlags | 0
TransferBufferLength | pIoBlockEx->uLength
TransferBuffer | lpOutBuffer (read) or pIoBlockEx->pbyData (write)
TransferBufferMDL | NULL
RequestTypeReservedBits | 0xC0 (read) or 0x40 (write)
Request | pIoBlockEx->bRequest
Value | (SHORT)pIoBlockEx->uOffset
Index | pIoBlockEx->uIndex

For more information, see Accessing Kernel-Mode Drivers for Still Image Devices.


IOCTL_SET_TIMEOUT

Sets the timeout value for USB bulk IN, bulk OUT, or interrupt pipe access.

DeviceIoControl Parameters

hDevice
Device handle, obtained by calling CreateFile.
dwIoControlCode
IOCTL_SET_TIMEOUT
lpInBuffer
Pointer to a USBSCAN_TIMEOUT structure.
nInBufferSize
Size of the input buffer.
lpOutBuffer
NULL.
nOutBufferSize
Zero.
lpBytesReturned
Pointer to a location to receive the number of bytes written.
lpOverlapped
Optional pointer to an OVERLAPPED structure (described in the Platform SDK documentation).

Headers

Declared in usbscan.h. Include usbscan.h.

Comments

When the DeviceloControl function is called with the IOCTL_SET_TIMEOUT I/O control code, the caller must specify the address of a USBSCAN_TIMEOUT structure as the function's lpInBuffer parameter.

Using the USBSCAN_TIMEOUT structure's contents, the kernel-mode driver resets the timeout value for each type of operation: bulk IN read, bulk OUT write, or interrupt.

For more information, see Accessing Kernel-Mode Drivers for Still Image Devices.

Code Example

USBSCAN_TIMEOUT TimeOut;
DWORD BytesReturned = 0;
HANDLE hUSB = (HANDLE)INVALID_HANDLE_VALUE;

hUSB = CreateFile(DevicePortName,                  // file name
                 GENERIC_READ | GENERIC_WRITE,     // desired access
                 0,                 // sharing mode
                 NULL,              // security descriptor
                 OPEN_EXISTING,     // creation disposition
                 0,                 // file attributes
                 NULL               // template file
                 );

if (hUSB != INVALID_HANDLE_VALUE)
{
  TimeOut.TimeoutRead = 20;       // Read Timeout 20 sec
  TimeOut.TimeoutWrite = 20;  // Write Timeout 20 sec
  TimeOut.TimeoutEvent = 0;       // 0 = No Timeout
  if (!DeviceIoControl(m_hUSB,
                       IOCTL_SET_TIMEOUT,
                       &TimeOut,
                       sizeof(TimeOut),
                       NULL,
                       0,
                       &BytesReturned,
                       NULL))
  {
     hr = HRESULT_FROM_WIN32(::GetLastError());
     return hr;
  }
}


IOCTL_WAIT_ON_DEVICE_EVENT

Returns information about an event occurring on a USB interrupt pipe.

DeviceIoControl Parameters

hDevice
Device handle, obtained by calling CreateFile.
dwIoControlCode
IOCTL_WAIT_ON_DEVICE_EVENT
lpInBuffer
NULL
nInBufferSize
Zero.
lpOutBuffer
Pointer to a buffer that is large enough to receive the largest packet the device is capable of sending on the interrupt pipe.
nOutBufferSize
Size of the output buffer.
lpBytesReturned
Pointer to a location to receive the number of bytes returned.
lpOverlapped
Optional pointer to an OVERLAPPED structure (described in the Platform SDK documentation).

Headers

Declared in usbscan.h. Include usbscan.h.

Comments

When the DeviceloControl function is called with the IOCTL_WAIT_ON_DEVICE_EVENT control code, the caller must specify a buffer pointer as the function's lpOutBuffer parameter. The buffer must be large enough to hold the largest packet the device can send on its interrupt pipe.

The type and size of information returned are device-specific. For example, a still image device might issue an interrupt when a user presses one of its buttons, and the return packet might indicate which button was pressed.

For more information, see Accessing Kernel-Mode Drivers for Still Image Devices.

Code Example

HANDLE  IntDeviceHdle = INVALID_HANDLE_VALUE;
DWORD   dwError;
UINT    uStatus = 0;
DWORD   dwByteCount;
DWORD   dwIndex = 0;
BOOL    bRet = TRUE;

GetArrayInteruptEvent(ArrayHdleEvent, &nbEventHdl);

// Initialize interrupt register with the current value.
while(TRUE)
{
    if (IntDeviceHdle != INVALID_HANDLE_VALUE)
    {
        bRet = DeviceIoControl( (HANDLE)IntDeviceHdle,
           (DWORD) IOCTL_WAIT_ON_DEVICE_EVENT,
            NULL,
            0,
            interInfo[dwIndex].byInterruptData,
            sizeof(BYTE)*PACKET_SIZE,
            &dwError,
            &interInfo[dwIndex].overlapped);
    }
    if ((bRet) || (!bRet && GetLastError()==ERROR_IO_PENDING))
    {
        dwIndex = WaitForMultipleObjects(nbEventHdl,
            ArrayHdleEvent,
            FALSE,
            INFINITE);
        // the event came from a device
        if ((dwIndex >= 0) & (dwIndex < nbEventHdl-1))
        {
            IntDeviceHdle = GetInterruptDeviceHdle(ArrayHdleEvent[dwIndex]);
            if (IntDeviceHdle != INVALID_HANDLE_VALUE)
            {
                GetOverlappedResult(IntDeviceHdle, &interInfo[dwIndex].overlapped, &dwByteCount, FALSE);
                Debugs(temp, "We received an interrupt from 0x%lX", IntDeviceHdle);
                ExecuteActionOnInterrupt(IntDeviceHdle, interInfo[dwIndex].byInterruptData);
            }
            else
            {
                Debugs(temp, "This Event does not have a valid device handle");
                // we just update the event array
                GetArrayInteruptEvent(ArrayHdleEvent, &nbEventHdl);
                bRet = TRUE;
            }
            // reset the device event
            ResetEvent((HANDLE)ArrayHdleEvent[dwIndex]);
        }
        // the event come the stop event
        else if (dwIndex - WAIT_OBJECT_0 == (nbEventHdl-1))
        {
            Debugs(temp, "The interrupt thread is stopped, we init a new scanner");
            ResetEvent((HANDLE)ArrayHdleEvent[dwIndex]);
            InitNewDeviceInterrupt(&IntDeviceHdle, &dwIndex);
            bRet = TRUE;
        }
    }
    else
   {
        dwError = GetLastError();
        Debugs(fail, "FAIL, DeviceIoControl() Error code : 0x%X", dwError);
        break;
    }
}


IOCTL_WRITE_REGISTERS

Writes to USB device registers, using the control pipe.

DeviceIoControl Parameters

hDevice
Device handle, obtained by calling CreateFile.
dwIoControlCode
IOCTL_WRITE_REGISTERS
lpInBuffer
Pointer to an IO_BLOCK structure.
nInBufferSize
Size of the input buffer.
lpOutBuffer
NULL.
nOutBufferSize
Zero.
lpBytesReturned
Pointer to a location to receive the number of bytes written.
lpOverlapped
Optional pointer to an OVERLAPPED structure (described in the Platform SDK documentation).

Headers

Declared in usbscan.h. Include usbscan.h.

Comments

When the DeviceloControl function is called with the IOCTL_WRITE_REGISTERS I/O control code, the caller must specify the address of an IO_BLOCK structure as the function's lpInBuffer parameter.

Using the IO_BLOCK contents, the kernel-mode driver creates a URB that contains a _URB_CONTROL_VENDOR_OR_CLASS_REQUEST structure.

The following table indicates the values assigned to _URB_CONTROL_VENDOR_OR_CLASS_REQUEST structure members.

Structure Member | Value Assigned
TransferFlags | 0
TransferBufferLength | pIoBlock->uLength
TransferBuffer | pIoBlock->pbyData
TransferBufferMDL | NULL
RequestTypeReservedBits | 0x40
Request | (pIoBlock->uLength > 1) ? 0x04 : 0x0C
Value | (SHORT)pIoBlock->uOffset
Index | pIoBlock->uIndex

For more information, see Accessing Kernel-Mode Drivers for Still Image Devices.

Code Example

DWORD             cbRet;
BOOL              bRet;
IO_BLOCK          IoBlock;
OVERLAPPED        overlapped;

IoBlock.uOffset = (BYTE)byOffset;
IoBlock.uLength = (BYTE)byNbOfReg;
IoBlock.pbyData = pbyData;

memset(&overlapped, 0, sizeof(OVERLAPPED));
overlapped.hEvent =
    CreateEvent(NULL,    // pointer to security attributes
                         // WIN95 ignores this parameter
                FALSE,   // automatic reset
                FALSE,   // initialize to not signaled
                NULL);   // pointer to the event-object name

bRet = DeviceIoControl( DeviceHandle,
                        (DWORD) IOCTL_WRITE_REGISTERS,
                        &IoBlock,
                        sizeof(IO_BLOCK),
                        NULL,
                        0,
                        &cbRet,
                        &overlapped);

if( bRet == TRUE )
{
    WaitForSingleObject(overlapped.hEvent, INFINITE);
    // we do not the test, the result is zero
}

CloseHandle(overlapped.hEvent);


USB Still Image Structures

This section describes the structures associated with I/O control codes that are recognized by the kernel-mode still image driver for USB buses. The structures are defined in usbscan.h.

If you are developing still image drivers for Windows 98, Windows 98 SE, or Windows Me, be sure to specify that the structures defined in usbscan.h are packed on 8-byte boundaries. This alignment is required for Windows 98/Me, and is the default for DDK builds. You can change the packing alignment using the /Zp compiler switch or with a "#pragma pack" preprocessor directive. (See the Platform SDK documentation for more information about compiler switches and #pragma directives.)


CHANNEL_INFO

The CHANNEL_INFO structure is used as a parameter to DeviceIoControl, when the specified I/O control code is IOCTL_GET_CHANNEL_ALIGN_RQST.

typedef struct _CHANNEL_INFO {
  OUT unsigned  EventChannelSize;
  OUT unsigned  uReadDataAlignment;
  OUT unsigned  uWriteDataAlignment;
}CHANNEL_INFO, *PCHANNEL_INFO;

Members

EventChannelSize
Maximum packet size for the interrupt transfer pipe.
uReadDataAlignment
Maximum packet size for the bulk IN transfer pipe.
uWriteDataAlignment
Maximum packet size for the bulk OUT transfer pipe.

Headers

Declared in usbscan.h. Include usbscan.h.


DEVICE_DESCRIPTOR

The DEVICE_DESCRIPTOR structure is used as a parameter to DeviceIoControl, when the specified I/O control code is IOCTL_GET_DEVICE_DESCRIPTOR.

typedef struct _DEVICE_DESCRIPTOR {
  OUT USHORT  usVendorId;
  OUT USHORT  usProductId;
  OUT USHORT  usBcdDevice;
  OUT USHORT  usLanguageId;
} DEVICE_DESCRIPTOR, *PDEVICE_DESCRIPTOR;

Members

usVendorId
Vendor identifer.
usProductId
Device product identifier.
usBcdDevice
BCD-encoded device version number.
usLanguageId
Not used.

Headers

Declared in usbscan.h. Include usbscan.h.


DRV_VERSION

The DRV_VERSION structure is used as a parameter to DeviceIoControl, when the specified I/O control code is IOCTL_GET_VERSION.

typedef struct _DRV_VERSION {
  OUT unsigned  major;
  OUT unsigned  minor;
  OUT unsigned internal;
} DRV_VERSION, *PDRV_VERSION;

Members

major
Major version number.
minor
Minor version number.
internal
Internal, vendor-specific version number.

Headers

Declared in usbscan.h. Include usbscan.h.


IO_BLOCK

The IO_BLOCK structure is used as a parameter to DeviceIoControl, when the specified I/O control code is IOCTL_READ_REGISTERS or IOCTL_WRITE_REGISTERS. Values contained in structure members are used to create a USB Device Request (described in the Universal Serial Bus Specification).

typedef struct _IO_BLOCK {
  IN     unsigned  uOffset;
  IN     unsigned  uLength;
  IN OUT PUCHAR  pbyData;
  IN     unsigned  uIndex;
} IO_BLOCK, *PIO_BLOCK;

Members

uOffset
Used as the Value field of a USB Device Request.
uLength
Length of the buffer to transfer.
pbyData
Pointer to a data buffer with a length of uLength.
uIndex
Used as the Index field of a USB Device Request.

Headers

Declared in usbscan.h. Include usbscan.h.


IO_BLOCK_EX

The IO_BLOCK_EX structure is used as a parameter to DeviceIoControl, when the specified I/O control code is IOCTL_SEND_USB_REQUEST. Values contained in structure members are used to create a USB Device Request (described in the Universal Serial Bus Specification).

typedef struct _IO_BLOCK_EX {
  IN     unsigned  uOffset;
  IN     unsigned  uLength;
  IN OUT PUCHAR  pbyData;
  IN     unsigned  uIndex;
  IN     UCHAR  bRequest;
  IN     UCHAR  bmRequestType;
  IN     UCHAR  fTransferDirectionIn;
} IO_BLOCK_EX, *PIO_BLOCK_EX;

Members

uOffset
Used as the Value field of a USB Device Request.
uLength
Length of the buffer to transfer.
pbyData
Pointer to a data buffer with a length of uLength.
uIndex
Used as the Index field of a USB Device Request.
bRequest
Used as the bRequest field of a USB Device Request.
bmRequestType
Used as the bmRequestType field of a USB Device Request.
fTransferDirectionIn
TRUE for transfers from device to host; FALSE for transfers from host to device.

Headers

Declared in usbscan.h. Include usbscan.h.


USBSCAN_GET_DESCRIPTOR

The USBSCAN_GET_DESCRIPTOR structure is used as a parameter to DeviceIoControl, when the specified I/O control code is IOCTL_GET_USB_DESCRIPTOR.

typedef struct _USBSCAN_GET_DESCRIPTOR {
  IN UCHAR  DescriptorType;
  IN UCHAR  Index;
  IN USHORT  LanguageId;
} USBSCAN_GET_DESCRIPTOR, *PUSBSCAN_GET_DESCRIPTOR;

Members

DescriptorType
Same as the DescriptorType parameter to UsbBuildGetDescriptorRequest.
Index
Same as the Index parameter to UsbBuildGetDescriptorRequest.
LanguageId
Same as the LanguageId parameter to UsbBuildGetDescriptorRequest.

Headers

Declared in usbscan.h. Include usbscan.h.


USBSCAN_PIPE_CONFIGURATION

The USBSCAN_PIPE_CONFIGURATION structure is used as a parameter to DeviceIoControl, when the specified I/O control code is IOCTL_GET_PIPE_CONFIGURATION.

typedef struct _USBSCAN_PIPE_CONFIGURATION {
  OUT ULONG  NumberOfPipes;
  OUT USBSCAN_PIPE_INFORMATION  PipeInfo[MAX_NUM_PIPES];
} USBSCAN_PIPE_CONFIGURATION, *PUSBSCAN_PIPE_CONFIGURATION;

Members

NumberOfPipes
The number of transfer pipes supported for the device.
PipeInfo
Pointer to a NumberOfPipes-sized array of USBSCAN_PIPE_INFORMATION structures.

Headers

Declared in usbscan.h. Include usbscan.h.


USBSCAN_PIPE_INFORMATION

The USBSCAN_PIPE_INFORMATION structure is used to describe a USB transfer pipe for a still image device. An array of USBSCAN_PIPE_INFORMATION structures is supplied within a USBSCAN_PIPE_CONFIGURATION structure.

typedef struct _USBSCAN_PIPE_INFORMATION {
  USHORT  MaximumPacketSize;
  UCHAR  EndpointAddress;
  UCHAR  Interval;
  RAW_PIPE_TYPE  PipeType;
} USBSCAN_PIPE_INFORMATION, *PUSBSCAN_PIPE_INFORMATION;

Members

MaximumPacketSize
Maximum packet size for the transfer pipe.
EndpointAddress
The address of the pipe's endpoint. The address is encoded as follows:
Bits | Definition
0..3 | Endpoint number.
4..6 | Reserved, set to 0.
7 Direction, ignored for control endpoints:
0 - OUT endpoint
1 - IN endpoint

For more information, see the Universal Serial Bus Specification.

Interval
Polling interval, in milliseconds, for interrupt pipes. For more information, see the Universal Serial Bus Specification.
PipeType
A RAW_PIPE_TYPE-typed value identifying the pipe type.

Headers

Declared in usbscan.h. Include usbscan.h.

See Also

USBSCAN_PIPE_CONFIGURATION, RAW_PIPE_TYPE


USBSCAN_TIMEOUT

The USBSCAN_TIMEOUT structure stores timeout values for USB bulk IN and bulk OUT operations, and interrupts.

typedef struct _USBSCAN_TIMEOUT {
  IN ULONG  TimeoutRead;
  IN ULONG  TimeoutWrite;
  IN ULONG  TimeoutEvent;
} USBSCAN_TIMEOUT, *PUSBSCAN_TIMEOUT;

Members

TimeoutRead
Specifies the number of seconds to wait for a read operation to time out.
TimeoutWrite
Specifies the number of seconds to wait for a write operation to time out.
TimeoutEvent
Specifies the number of seconds to wait for an interrupt to occur.

Headers

Declared in usbscan.h. Include usbscan.h.

Comments

A value of zero means to wait forever for the read or write operation or interrupt.

The USBSCAN_TIMEOUT structure is used as a parameter to DeviceIoControl, when the specified I/O control code is IOCTL_SET_TIMEOUT.

See Also

IOCTL_SET_TIMEOUT


USB Still Image Data Types

This section describes the data types associated with I/O control codes that are recognized by the kernel-mode still image driver for USB buses. The codes are defined in usbscan.h.


PIPE_TYPE

The PIPE_TYPE data type is used as input to the DeviceIoControl function, if the I/O control code is IOCTL_CANCEL_IO or IOCTL_RESET_PIPE. An interrupt pipe, a bulk IN pipe, and a bulk OUT pipe are associated with each device handle supplied to DeviceIoControl. The specified PIPE_TYPE value indicates on which of these pipes the operation should be performed, as indicated in the following table.

typedef enum {
   EVENT_PIPE,
   READ_DATA_PIPE,
   WRITE_DATA_PIPE,
   ALL_PIPE
} PIPE_TYPE;
PIPE_TYPE Value | Definition
EVENT_PIPE | The operation should be performed on the interrupt pipe.
READ_DATA_PIPE | The operation should be performed on the bulk IN pipe.
WRITE_DATA_PIPE | The operation should be performed on the bulk OUT pipe.
ALL_PIPE | The operation should be performed on all transfer pipes (not just the pipes associated with the device handle supplied to DeviceIoControl).

Headers

Declared in usbscan.h. Include usbscan.h.


RAW_PIPE_TYPE

The RAW_PIPE_TYPE data type is used to specify the type of a USB pipe. The values are defined as follows:

typedef enum _RAW_PIPE_TYPE {
    USBSCAN_PIPE_CONTROL,
    USBSCAN_PIPE_ISOCHRONOUS,
    USBSCAN_PIPE_BULK,
    USBSCAN_PIPE_INTERRUPT
} RAW_PIPE_TYPE;
RAW_PIPE_TYPE Value | Definition
USBSCAN_PIPE_CONTROL | Identifies the control pipe.
USBSCAN_PIPE_ISOCHRONOUS | Identifies an isochronous pipe.
USBSCAN_PIPE_BULK | Identifies a bulk IN or bulk OUT pipe.
USBSCAN_PIPE_INTERRUPT | Identifies an interrupt pipe.

Headers

Declared in usbscan.h. Include usbscan.h.


Storage Drivers

This chapter contains the following information:

Storage Driver Architecture

Storage Drivers and Device Objects

System Header Files for Storage Drivers

Restrictions on Storage Drivers in the Paging Path

Subsequent chapters contain guidelines for designing the following kinds of Windows NT® kernel-mode storage drivers:

  • An operating system-independent miniport driver for a vendor-specific SCSI HBA (see SCSI Miniport Drivers)
  • A miniport driver for a non-SCSI storage adapter (see SCSI Miniport Drivers)
  • A class driver for a new type of peripheral device (see Storage Class Drivers)
  • An operating system-independent tape miniclass driver for a vendor-specific tape device (see Tape Miniclass Drivers)
  • A changer miniclass driver for a vendor-specific medium changer device (see Changer Drivers)
  • A filter driver for a peripheral device of a type that already has a class driver (see Storage Filter Drivers)


Storage Driver Architecture

NT-based operating system class and filter drivers for peripheral storage devices act as an interface between any intermediate or highest level drivers layered above the class or filter driver and a system-supplied port driver.

I/O requests from a user application or kernel component reach storage class drivers through I/O System Services and one or more intermediate or highest level drivers, such as a file system driver. Storage class drivers translate the standard IRPs they get into IRPs with system-defined SCSI request blocks (SRBs) containing SCSI-2 command descriptor blocks (CDBs) before sending each IRP on to the next lower driver. A storage port driver translates SRBs from class drivers into bus-specific commands which it sends to the storage HBA, through an I/O bus driver and possibly one or more filter drivers.

The following figure shows the layered architecture of NT-based operating system storage drivers.

NT-based Operating System Storage Driver Architecture

Starting from the bottom of the figure, the following describes each type of storage driver:

  1. A storage port driver defines an interface to all Windows NT storage class drivers, including the system-supplied disk, tape, CDROM, DVD, and changer class drivers. This port/class interface insulates class drivers from adapter-specific requirements of the host bus adapter to which their respective devices are connected. A storage port driver also synchronizes access to the bus for all drivers of devices on the corresponding HBA. The system supplies storage port drivers for SCSI, IDE, and IEEE 1394 adapters.

    A storage port driver receives SRBs from the next higher driver (a storage class driver or intervening filter driver) and processes them as follows:

    • The storage port driver for a SCSI bus passes SRBs with CDBs on to an operating system-independent, HBA-specific SCSI miniport driver, which is dynamically linked to the SCSI port driver and provides hardware-specific support for a particular SCSI HBA. For information about implementing a SCSI miniport driver, see SCSI Miniport Drivers.
    • The storage port driver for an IDE/ATAPI or IEEE 1394 bus translates the SRBs received from the storage class driver into the format required by the underlying adapter—for example, repackaging CDBs according to a bus-specific transport protocol, or translating them into a different format, thereby insulating upper level drivers from peculiarities of the underlying bus.
  2. An upper or lower storage filter driver supports device-specific functionality not provided by a system-supplied storage class driver. A lower filter storage driver monitors SRBs and/or IRPs issued by a storage class driver and modifies them as needed before passing them to the next lower driver (a storage port driver or another storage filter driver).

    For information about implementing a storage filter driver, see Storage Fileter Drivers.

  3. A storage class driver uses the well-established SCSI port/class interface to control a device of its type on any bus for which the system provides a storage port driver. A class driver is specific to a particular class of device—for example, one class driver can run all CD-ROM devices on any supported bus; another can control all disk devices. The storage class driver handles I/O requests from user applications or higher level drivers by building SRBs containing CDBs and issuing those SRBs to the next lower driver (a storage port driver or intervening filter driver), just as if the device were a SCSI device.

    The implementation of a storage class driver is transparent to upper level drivers. A class driver for a tape or medium changer device is implemented as a device-specific miniclass driver that links to a system-supplied class driver. System-supplied class drivers for other storage devices, such as disk and CD-ROM/DVD, are implemented as single monolithic drivers.

    For information about implementing a storage class driver, see Storage Class Drivers. For information about implementing a tape or changer miniclass driver, see Tape Miniclass Drivers and Changer Drivers, respectively.

  4. An upper filter storage driver intercepts IRPs from user applications and still higher level drivers and might modify them before passing them to the next lower driver (a storage class driver or another storage filter driver), or might monitor performance of the underlying device.

The type of bus to which a device is attached and the implementation of its storage port driver are transparent to upper level drivers. A storage port driver might be implemented according to the port/miniport architecture, like the SCSI port driver; as a monolithic driver that controls a single, standard piece of hardware, such as the IDE/ATAPI port driver; or as a filter driver that translates SRBs into the format required by a different driver stack, such as the IEEE 1394 port driver.

The system-supplied SCSI port driver can also act as an interface between a storage class driver and a SCSI miniport that controls a nonSCSI storage device of the same type. For example, rather than writing a standard Windows NT driver for a new disk-array controller, a driver writer can save considerable design, development, and debugging effort by writing a pseudoSCSI miniport driver that links to the system SCSI port driver and uses the interface it provides. Such a miniport is required to translate incoming SCSI commands into device-specific commands and support higher level Windows NT drivers as if it were a SCSI HBA miniport. On the other hand, the system-supplied port and class drivers handle much necessary work on such a pseudo SCSI miniport's behalf, including registry accesses during initialization, all resource and object allocations, synchronization, presizing requested transfers to suit the capabilities of the miniport's device, and retrying requests.

For more detailed information about SRBs, see the Kernel-Mode Driver Architecture Reference. For device-type-specific information about CDBs, consult the ANSI X3.131-199X SCSI-2 standard.


Storage Drivers and Device Objects

The storage device stack consists of a tree of device objects created by the drivers that are involved in handling I/O to storage devices on the system. The root of this tree is a functional device object (FDO) for a storage adapter or for another driver stack integrated with the storage stack. The leaves of this tree are device objects for use by file systems and user-mode applications.

Like any PnP driver, a storage class or storage filter driver adds itself to the tree in its AddDevice routine by creating a device object with IoCreateDevice and attaching it to the device stack with IoAttachDeviceToDeviceStack, using the pointer to the device object passed to the driver's AddDevice routine by the PnP Manager at initialization. IoAttachDeviceToDeviceStack attaches the new device object to the current top of the device stack.

A tape miniclass, medium changer miniclass, or SCSI miniport driver is not required to create a device object and attach it to the device stack. Instead, the system-supplied tape class, changer class, or SCSI port driver handles these tasks on behalf of the miniclass/miniport, calling miniclass/miniport routines to gather the data needed to create the device object.

For information about designing PnP drivers, see the PnP Driver Design Guidelines. For information about PnP-related Io Xxx routines, see the Plug and Play Routines.


Device Object Example for a SCSI HBA

The following figure shows the device objects that are created for system with a PCI IEEE 1394 controller and a PCI SCSI adapter with a CD-ROM and partitionable disk device attached. Objects for devices attached to the IEEE 1394 controller are shown and described in Device Object Example for an IEEE 1394 Controller.

Device Object Tree for CD-ROM and Disk Devices on a SCSI HBA

Starting from the bottom of the figure, the following describes each device object and its associated driver:

  1. The storage bus driver creates the FDO for the storage bus and attaches it to the storage bus PDO created by the PnP Manager (not shown in this figure). The structure of the device object tree below the storage bus FDO depends on the storage bus and how it is integrated into the system. Storage drivers above the port driver level do not interact with any of these lower objects.

    This figure shows the storage bus FDO created by the PCI bus driver for a system with a PCI bus.

  2. The PCI bus driver enumerates and creates a PDO for each storage adapter on its bus. The corresponding storage port driver creates an FDO and attaches it to the PDO for its adapter.

    This figure shows two adapter PDOs: one for an IEEE 1394 controller (described in Device Object Example for an IEEE 1394 Controller) and another for a SCSI HBA. The SCSI port driver and an associated miniport create an FDO and attach it to the SCSI adapter PDO.

  3. The storage port driver virtualizes target devices by creating a PDO for each target device attached to its adapter. This figure shows two such PDOs created by the SCSI port/miniport drivers: one for a hard drive and one for a CD-ROM.
  4. One or more filter drivers can attach a filter device object (filter DO) to a target device PDO exported by a storage port driver. Such a filter driver can intercept and alter requests sent by the class driver to the target device, for example, to work around device-specific problems without requiring hardware-specific changes to the generic class or port drivers.

    This figure shows a filter DO attached by a CD audio filter driver to the CD-ROM's PDO.

  5. A storage class driver creates an FDO and attaches it to next lower device object, which is either a target device PDO exported by a storage port driver or a filter DO attached to the stack by an intervening filter driver. The class driver issues all subsequent requests to the storage device through the lower driver's device object.

    This figure shows two such FDOs: one that represents a CD-ROM device, and one that represents Partition 0 of a hard drive. Partition 0 represents the entire raw disk, and always exists whether the drive is partitioned or not.

  6. A class driver can also act as a bus driver, returning a list of PDOs when the PnP Manager queries for its child devices (IRP_MN_QUERY_DEVICE_RELATIONS with BusRelations). For example, a driver of a partitioned media device such as a removable disk might return a list of PDOs representing its partitions. Higher level drivers attach FDOs to these PDOs.

    This figure shows three such PDOs, each representing a disk partition that can be addressed as a target device.

    In the case of a fixed disk, the partition manager attaches to the FDO that represents Partition 0 and handles PnP operations on behalf of all partitions. The activities of the partition manager are transparent to the disk class driver and any upper level filter drivers.

  7. One or more filter drivers can be attached above a class driver. Unlike a lower level filter driver, an upper level filter driver intercepts IRPs sent to the class driver, and can alter them before forwarding them to next lower device object. The filter driver can intercept any read-write requests and transform the data as necessary, as well as define additional I/O control codes (IOCTLs), for example, to enable a user application to supply passwords or other related information.

    This figure shows a filter DO created by a disk-encryption filter driver and attached to the disk PDO for partition 1.


Device Object Example for an IEEE 1394 Controller

The following figure shows the device objects that are created for system with a PCI IEEE 1394 controller with an IEEE 1394 CD-ROM attached. Device objects for devices attached to the SCSI adapter are described in Device Object Example for a SCSI HBA.

Device Object Tree for a CD-ROM Device on an IEEE 1394 Controller

Starting from the bottom of the figure, the following describes each device object and its corresponding driver:

  1. For a description of the device tree from the storage bus FDO up to the adapter PDOs, see Device Object Example for a SCSI HBA.
  2. The highest driver in the IEEE 1394 driver stack creates an SBP2 disk device PDO. The IEEE 1394 driver stack ultimately issues SBP2 commands to the target CD-ROM device on the IEEE 1394 bus.
  3. The system-supplied IEEE 1394 storage port driver is implemented as a filter driver that creates a filter DO and attaches it to the SBP2 disk device PDO. The IEEE 1394 storage port driver translates SRBs from the CD-ROM class driver into SBP2 commands which are issued to the underlying IEEE 1394 driver stack. The interface this driver presents to higher level storage drivers is identical to that presented by the SCSI port/miniport driver described in Device Object Example for a SCSI HBA.
  4. The CD-ROM class driver creates an FDO and attaches it to the next lower device object, which is either the SBP2 port filter DO or another filter DO attached to the stack by an intervening filter driver. The class driver issues all subsequent requests to the device through the lower driver's device object.


Device Object Example for a PCI IDE Controller

The following figure shows the device objects that are created for a system using a PCI IDE controller that has two IDE disks attached to one channel and an IDE CD-ROM attached to the other.

Device Object Tree for CD-ROM and Disk Devices on an IDE controller

Starting from the bottom of the figure, the following describes each device object and its associated driver:

  1. The PCI bus driver creates an FDO for the PCI bus and attaches it to the PCI bus PDO that was created by the PnP Manager (not shown in this figure).
  2. The PCI bus driver enumerates the adapters and controllers on its bus, including all the IDE controllers, and creates a PDO for each one.
  3. The IDE controller driver, together with its IDE controller minidriver, create an FDO and attach it to the PDO for the controller.
  4. The IDE controller driver "enumerates" the controller's channels. In effect, this means that it creates two PDOs, one for each of the controller's channels, and that it attaches both channel PDOs to the controller FDO.
  5. The IDE channel driver creates an FDO and attaches it to the PDO for the channel.
  6. The IDE channel driver enumerates the devices on its channel and creates a PDO for each device. The figure showing a device object tree for a CD-ROM device on an IEEE 1394 controller illustrates three such PDOs that were created by the IDE channel driver: two hard drive PDOs that were created by the channel driver for the controller's first channel, and a CD-ROM PDO that was created by the channel driver for the controller's second channel.
  7. The disk class driver creates an FDO and attaches it to the associated disk PDO, exactly as in the case of the SCSI, and the CD-ROM driver creates an FDO and attaches it to the associated CD-ROM PDO. As in the case of the SCSI, a filter driver DO can be inserted between the device PDO and the device FDO. The figure showing a device object tree for a CD-ROM device on an IEEE 1394 controller illustrates this using a CD Audio Filter DO that can be optionally placed just above the CD-ROM PDO.


Device Object Example for a USB Mass Storage Device

The following figure shows the device objects that are created for a composite USB mass storage device containing both a Smart Media slot and a Compact Flash slot.

Device Object Tree for a Composite USB Mass Storage Device

Starting from the bottom of the figure, the following list describes each device object or device object stack and its associated driver:

  1. The PCI bus driver enumerates the USB host controller. The system loads the port driver, usbport.sys, and its accompanying miniports (not shown in the figure). Then, usbport.sys creates an FDO for the host controller.
  2. The port driver enumerates the USB hubs in the system, starting with the root hub. The usbhub.sys driver manages all USB hubs. The figure only shows one level of hub device objects, but USB allows daisy-chaining of hub devices, so there could potentially be many more hub device objects in the tree. The hub driver detects and enumerates the USB mass storage device and creates a PDO for it.
  3. Windows® supplies a USB storage port driver, usbstor.sys, that serves as an interface between the USB stack and the native Windows storage class drivers. The USB storage port driver creates its own functional device object (FDO). The USB storage port driver can divide the physical storage device into as many as 16 logical units. In the example depicted in the figure, the USB storage device contains separate slots for a Compact Flash device and a Smart Media device. Therefore, in this example, the USB storage port driver creates two separate PDOs, one for the Compact Flash device and another for the Smart Media device.
  4. The stack above the USB storage port driver is managed in the usual way by the native disk class driver. The disk class driver creates a PDO and an FDO for the disk as a whole (partition zero), and PDOs for each partition on the disk.
  5. The partition manager creates an FDO for each disk partition.


System Header Files for Storage Drivers

The system-supplied storage drivers include the header file scsi.h, which contains SCSI-2-compliant definitions for CDBs and other structures used by most SCSI-2-compliant drivers. This header file includes srb.h, which defines the interfaces provided by the system-supplied port drivers to higher level storage class and filter drivers.

System-supplied class and filter drivers also can include the header file classpnp.h so they can call the ClassXxx routines provided by classpnp.c. The DDK for Windows® 2000 and later operating systems provides classpnp.h and classpnp.c as sample source code. However, classpnp.c should not be considered a system-supplied library for all future storage class drivers. Both classpnp.h and classpnp.c are subject to change without notice.

Operating system-independent SCSI miniport drivers, which can be designed to run both with all platforms of NT-based operating systems and with x86-only Microsoft Windows systems, include the system-supplied header files miniport.h and scsi.h, which includes srb.h.

Tape miniclass drivers include minitape.h.

Medium changer miniclass drivers include mcd.h.


Restrictions on Storage Drivers in Paging Path

A driver is in the "paging path" if it participates in I/O operations on the paging file. To prevent deadlock, the I/O routines of such drivers (DispatchRead, DispatchWrite, and DeviceControl routines) must not contain pageable code, and they must never attempt to access pageable memory.

In the case of storage drivers, I/O and DeviceControl routines must never contain pageable code, even if the storage driver is not in the paging path. This is because I/O and DeviceControl routines can be called at IRQL > PASSIVE_LEVEL, and the in-paging I/O that services a page fault takes place at IRQL = APC_LEVEL.

By default, the code for kernel-mode drivers is not pageable, nor is the global memory used by kernel-mode drivers pageable. If a driver routine does no I/O and runs at IRQL = PASSIVE_LEVEL, as is the case with routines such as DriverEntry, Reinitialize, and Unload, then its code can be made pageable by means of the #pragma_alloc_text() compiler directive. It can then be locked and unlocked dynamically at run-time by calling memory manager routines MmLockPagableCodeSection() and MmUnlockPagableImageSection() (See MmLockPagableCodeSection and MmUnlockPagableImageSection for a discussion of these routines and for a discussion of the #pragma_alloc_text() directive).


Storage Class Drivers

This chapter explains how to write storage class drivers and contains the following sections:

Introduction to Storage Class Drivers

Storage Class Driver's General Functionality

Storage Class Driver's Support of I/O Requests

Handling PnP Initialization in a Storage Class Driver

Handling PnP Start in a Storage Class Driver

Setting up a Storage Class Driver's Device Extension

Storage Class Driver's Standard Driver Routines

Handling Requests to Storage Peripherals

Storage Class Driver's Internal Routines

Converting an Existing SCSI Class Driver for Plug and Play

Supporting Mount Manager Requests in a Storage Class Driver


Introduction to Storage Class Drivers

A storage class driver is a class driver for a SCSI or nonSCSI storage device. It uses the well-established SCSI class/port interface to control a mass-storage device of its type on any bus for which the system supplies a storage port driver (currently SCSI, IDE, and IEEE 1394). The particular bus to which a storage device is connected is transparent to the storage class driver.

Any storage class driver handles I/O requests from user applications or higher-level drivers by building SCSI request blocks (SRBs) containing command desciptor blocks (CDBs) and sending them, through any intervening filter drivers, to the underlying storage port driver.

A storage class driver does not provide addressing information in the SRB. Instead, the port driver (or a still-lower driver) is responsible for any addressing required. The storage port driver translates the SRBs into the format required by the underlying host bus adapter (HBA), which might be a SCSI or 1394 host bus adapter, IDE controller, or other such hardware, and issues commands to the device. In this DDK, the term "HBA" stands for any such underlying adapter or controller.

To the I/O Manager and any higher-level drivers layered above a storage class driver, most storage class drivers are standard kernel-mode intermediate drivers. Thus every class driver must have a DriverEntry routine, an AddDevice routine, an Unload routine, one or more IoCompletion routines, plus DispatchPnP and DispatchPower routines to handle Plug and Play and power IRPs.

A storage class driver must also have a DispatchSystemControl routine to handle system-control IRPs, and can have any other standard higher-level driver routine, such as a StartIo routine, as determined by the driver designer. For more information about system-control and standard kernel-mode driver routines, see Standard Driver Routines.

To the PnP Manager, a storage class driver is a function driver, that is, one that drives an individual device. A storage class driver can also act as a bus driver, enumerating child devices of its devices. For example, the class driver for a partitioned media device such as a disk returns a list of PDOs representing its partitions. Each such PDO can be addressed as a target device and be serviced by its own class driver.

Note A driver for a SCSI device such as a printer or a scanner should be implemented as described in this chapter. A driver for such a SCSI device utilizes the same SCSI class/port interface to control its device and has the same responsibilities to handle IRPs, build SRBs, and send them to the underlying port driver as does a driver for a storage device.


Storage Class Driver's General Functionality

To a storage port driver, a storage class driver is a higher-level driver with built-in, device-type-specific functionality. In general, every storage class driver is responsible for the following:

  • Claiming each device represented by a physical device object (PDO) passed to its AddDevice routine by the PnP Manager
  • For each such PDO, creating a functional device object (FDO) and attaching it to the device stack
  • If the driver controls a partitionable device, creating physical device objects (PDOs) to represent each partition and responding to enumeration requests
  • Interpreting system I/O requests (IRPs)
  • Mapping IRPs to SCSI class/port interface requests (SRBs with SCSI-2 CDBs)
  • Establishing time-out values for requests
  • Limiting the size of data transfers to suit the limits of the underlying HBA
  • Handling error conditions that are not already handled by the storage port driver, such as check-condition status or bus resets


Storage Class Driver's Support of I/O Requests

The designer of a class driver for an entirely new type of storage device must determine an appropriate set of I/O requests for the driver to support, depending on the nature of the device. The set of requests to be supported generally includes at least the following:

IRP_MJ_CREATE and, for some device types or for symmetry, IRP_MJ_CLOSE

IRP_MJ_DEVICE_CONTROL

IRP_MJ_READ, IRP_MJ_WRITE, or both

IRP_MJ_PNP

IRP_MJ_POWER

IRP_MJ_SYSTEM_CONTROL


Handling PnP Initialization in a Storage Class Driver

Initialization of a storage class driver is much the same as initialization of any PnP driver.

Storage class driver initialization begins when the PnP Manager calls the driver's DriverEntry routine to load and initialize the driver. Then the PnP Manager calls the storage class driver's AddDevice routine, passing a pointer to a physical device object (PDO) that represents the target device.

In its AddDevice routine, the class driver calls IoGetAttachedDeviceReference and issues an SRB_FUNCTION_CLAIM_DEVICE command (see SCSI_REQUEST_BLOCK) to the device object returned, to prevent legacy class drivers from claiming the device. The class driver must send no other commands to the device during this phase of initialization.

If the class driver successfully claims the device, it creates a functional device object (FDO) and attaches it to the device stack by calling IoAttachDeviceToDeviceStack with the input PDO. When AddDevice returns, the driver must be ready to handle a PnP start request (IRP_MJ_PNP with an IRP_MN_START_DEVICE). After the PnP Manager has finished constructing the driver stack (which might include one or more filter drivers layered above and below the class driver) it issues a start request to the topmost driver in the driver stack for the target device.

If the class driver cannot successfully claim the device, it must not attempt to attach an FDO to the device stack, and should simply return a success status from its AddDevice routine. Such a driver will not receive a PnP start request for the device, although the PnP Manager might call its AddDevice routine again for the same or a different device.

For more information about initializing storage class drivers, see the following:

Storage Class Driver's DriverEntry Routine

Storage Class Driver's AddDevice Routine

Also see Plug and Play.


Handling PnP Start in a Storage Class Driver

A storage class driver performs device-specific initialization when the PnP Manager calls the class driver's DispatchPnP routine with a start request (IRP_MJ_PNP with IRP_MN_START_DEVICE). The storage class driver's DispatchPnP routine either calls an internal StartDevice routine or implements the same functionality inline. Because start requests sent to an FDO must be handled first by the lowest driver in the stack, the storage class driver's DispatchPnP routine forwards the request to the next-lower driver with IoCallDriver before calling StartDevice. If the request was sent to a PDO, the driver need not forward the request before handling it.

A storage class driver's internal StartDevice routine sets up the device extension of its FDO with driver-determined data to manage I/O requests for the device. For more information, see Setting up a Storage Class Driver's Device Extension.

A StartDevice routine should enable any device interfaces that the driver registered in its AddDevice routine. (See Device Interface Classes.) It might also create a symbolic link for its device object.

After the start of the lower device has completed, the driver can assume that the device is in the D0 power state (fully on and operational) for most purposes. If the device is not completely powered up, the port driver will queue requests until the device is ready. However, if the driver's StartDevice routine needs to perform any operations that require inrush current — for example, to spin up a disk drive — the driver must send a D0 power request to the next-lower driver before performing the operation.

A driver of a device of type FILE_DEVICE_DISK or FILE_DEVICE_MASS_STORAGE can register for idle detection and use the standard power policy timeouts for the device class by specifying conservation and performance timeout values of –1 in its PoRegisterDeviceforIdleDetection call.

For more information about a storage class driver's DispatchPnP routine, see Handling PnP Requests to Storage Peripherals. For more information about handling PnP start requests, see Starting a Device.


Setting up a Storage Class Driver's Device Extension

In the device extension of each device object created by a storage class driver, that driver provides storage for whatever driver-determined data it uses to manage I/O requests for the device, such as the pointer to the PDO passed to AddDevice, the pointer to the device object returned by IoAttachDeviceToDeviceStack, a back pointer to its own device object, and so forth.

Most storage class drivers also provide storage for the following information:

  • A device-type-specific time-out value

    The class driver can pass the time-out value in SRBs it sends to the port driver, which times SRB_FUNCTION_EXECUTE_SCSI requests (see SCSI_REQUEST_BLOCK) on behalf of each class driver. The port driver returns an SRB with its SrbStatus member set to SRB_STATUS_TIMEOUT if the interval between when the port driver sends the request to the underlying driver and when the request completes exceeds the specified time-out value.

  • A pointer to the class driver's error-handling routine

    See Storage Class Driver's IoCompletion Routines for more information about error-handling in storage class drivers.

  • A count that the driver maintains of bus protocol errors on the device
  • A pointer to a driver-allocated buffer for sense data

    A class driver must allocate memory for returned sense data from cache-aligned, nonpaged pool. For more information about allocating memory for driver buffers, see Allocating System-Space Memory.

  • A driver-determined default value for SrbFlags that the class driver sets in SRBs
  • A pointer to a lookaside list header if the driver sets up a lookaside list for the SRBs it allocates

    See Using Lookaside Lists for more information.

  • Pointers to an IRP and an SRB allocated and held in reserve for requests that must succeed even in low memory conditions, for paging operations as well as error recovery operations (such as those performed by a storage class driver's ReleaseQueue routine)
  • A pointer to the STORAGE_ADAPTER_DESCRIPTOR and STORAGE_DEVICE_DESCRIPTOR data that the port driver collected from the HBA

    For information about how class drivers get and use this data, see Storage Class Driver's GetDescriptor Routine.

  • Flags that indicate the previous and current PnP state, to manage transitions between states on the device
  • A flag that indicates the current device power state, to avoid extra work in handling redundant power requests
  • A count of system paging files, if any, on the device, based on paging-notification requests received by the driver (IRP_MJ_PNP with IRP_MN_DEVICE_USAGE_NOTIFICATION)

A storage class driver cannot send requests to its device through the storage port driver without using the device object pointer that was returned by IoAttachDeviceToDeviceStack and stored in the device extension by the driver's AddDevice routine.


Storage Class Driver's Standard Driver Routines

This section describes how to implement standard driver routines in storage class drivers. It contains the following topics:

Storage Class Driver's DriverEntry Routine

Storage Class Driver's AddDevice Routine

Storage Class Driver's Dispatch Routines

Storage Class Driver's IoCompletion Routines


Storage Class Driver's DriverEntry Routine

Like any other Windows NT kernel-mode higher-level driver, the DriverEntry routine of a storage class driver must do the following:

  1. Allocate a driver object extension of appropriate size by calling IoAllocateDriverObjectExtension.
  2. Copy the input registry path into the driver extension for later use (if necessary) and initialize the driver extension.
  3. Define its dispatch entry points in the input driver object.

For more information about a PnP driver's DriverEntry routine, see Writing a DriverEntry Routine.


Storage Class Driver's AddDevice Routine

The PnP Manager calls a storage class driver's AddDevice routine when it detects a device controlled by that driver. A storage class driver's AddDevice routine:

  • Claims the device as described in Storage Class Driver's ClaimDevice Routine, or, if the driver is unable to claim the device, returns STATUS_SUCCESS.
  • If the driver successfully claims the device, creates a device object (FDO).
  • Registers device interfaces that applications and other system devices can use. The class driver enables such interfaces when it receives a PnP start request.
  • Prepares the device object to handle a start request as described in Writing an AddDevice Routine.
  • Attaches the device object to the device stack by calling IoAttachDeviceToDeviceStack with the input PDO.
  • If the device starts in a known power state, calls PoSetPowerState.
  • Clears the DO_DEVICE_INITIALIZING flag on the new device object.

A storage class driver stores the pointer returned by IoAttachDeviceToDeviceStack in the device extension of its own device object (FDO) that represents the newly claimed device, and must use this pointer in all subsequent requests that the class driver sends to the next-lower driver. The driver also stores the pointer to the input PDO in the device extension, but after IoAttachDeviceToDeviceStack returns the driver must use the pointer to the input PDO only in calls to PnP Io Xxx routines that take such a pointer as a parameter.

For more information, see Writing an AddDevice Routine.


Storage Class Driver's Dispatch Routines

Class driver DispatchCreate and DispatchClose routines usually have no device-specific requirements. Most storage class drivers are intermediate drivers; their dispatch routines just return STATUS_SUCCESS to indicate that a given device object exists so that higher-level drivers and, indirectly, user-mode applications can open the device for I/O and close the device afterward.

Class driver DispatchDeviceControl and DispatchInternalDeviceControl routines must be resident; that is, they cannot be pageable nor part of a driver's pageable-image section. Depending on the IOCTL of a given request, such a dispatch routine might call a paged routine or wait on a synchronization or notification object (thereby blocking the executing thread), but the dispatch routine must be able to pass an unknown IOCTL through at DISPATCH_LEVEL.

A storage class driver must have a DispatchPnP routine for requests to start, stop, and remove the device and respond to other PnP requests such as notification that the device is on the paging path. For details about handling a PnP start request, see Handling PnP Start in a Storage Class Driver. For details about handling other PnP requests, see Handling PnP Requests to Storage Peripherals.

A storage class driver must also have a DispatchPower routine for requests to set the power state of its device. For details, see Handling Power Requests to Storage Peripherals.

A storage class driver must have a DispatchShutdown routine and possibly a DispatchFlushBuffers routine if its device caches data internally, if its device might be attached to a bus driven by an HBA that caches data internally, or if a file system is layered above the class driver. To maintain data integrity, such a cache should be flushed to the device before the system is shut down.

See also Writing Dispatch Routines for more information about general requirements for dispatch routines.


Storage Class Driver's IoCompletion Routines

A storage class driver must have one or more IoCompletion routines, unless the driver synchronously waits on the completion of every IRP it sends to the port driver, retries requests as necessary, then releases memory for SRBs from within a dispatch or BuildRequest routine. Note that handling every IRP synchronously will degrade the class driver's performance. Furthermore, storage class drivers for devices that might hold the system page file must handle all transfer requests asynchronously and thus must have an IoCompletion routine for read/write requests.

As described in Storage Class Driver's BuildRequest Routine, storage class drivers are responsible for freeing the memory they allocate for SRBs, whether back to a lookaside list or to nonpaged pool. Like any other higher-level kernel-mode driver, they are also responsible for releasing any IRPs that they allocate, such as an IRP to split up a transfer request as described in Storage Class Driver's SplitTransferRequest Routine.

A class driver's IoCompletion routine is ultimately responsible for ensuring that the I/O status block is set and for completing the original IRP. Note that completing an IRP can include translating an error returned in the SRB's ScsiStatus member or SenseInfoBuffer member into an NTSTATUS-type value and/or logging an error, as described in Completing IRPs in Dispatch Routines.

When certain kinds of errors occur in processing a request, a storage port driver freezes its internal queue for the target logical unit (LU) and sets SRB_STATUS_QUEUE_FROZEN on completion of the request. Consequently, class drivers usually have internal routines to change the status of the queue for their device I/O requests. For more information, see Storage Class Driver's ReleaseQueue Routine.

If the driver's BuildRequest routine requested that the port driver return request-sense information for a request, its IoCompletion routine either calls an internal InterpretRequestSense routine or implements the same functionality inline. For more information, see Storage Class Driver's InterpretRequest Routine.

Storage class drivers are responsible for retrying requests that fail due to target controller errors, bus resets, or request time-outs. When the port driver returns a particular request with its SrbStatus set to indicate such an error, the class driver can call a RetryRequest routine from its IoCompletion routine or, possibly, from its InterpretRequestSense routine. For more information, see Storage Class Driver's RetryRequest Routine.

For general information about IoCompletion routines, see Completing IRPs.


Handling Requests to Storage Peripherals

For all requests that require the storage port driver to execute a request over an underlying bus, the class driver must set up an IRP with a SCSI request block (SRB) containing a SCSI command descriptor block (CDB). Consequently, most storage class drivers have one or more internal BuildRequest routines to build SRBs. For more information about such routines, see Storage Class Driver's BuildRequest Routine.

Storage class drivers also pass on IRP_MJ_INTERNAL_DEVICE_CONTROL requests to the underlying storage port driver. Such a request can originate from a storage filter driver. For IOCTL_SCSI_PASS_THROUGH requests, described in Handling SCSI Pass-Through Requests, the class driver is responsible for setting the MinorFunction code to IRP_MN_SCSI_CLASS in the port driver's I/O stack location of the IRP before passing the IRP_MJ_INTERNAL_DEVICE_CONTROL request on to the port driver with IoCallDriver.

Every storage class driver is responsible for splitting up transfer requests (IRP_MJ_READ and/or IRP_MJ_WRITE) that exceed the underlying HBA's capabilities. Consequently, most class drivers also call an internal SplitTransferRequest routine, described in Storage Class Driver's SplitTransferRequest Routine, or implement the same functionality in their dispatch routines for read and write requests.

For additional information about handling requests to storage peripherals, see the following topics:

Handling SCSI Pass-Through Requests

Handling PnP Requests to Storage Peripherals

Handling Power Requests to Storage Peripherals

Queueing Storage Requests


Handling SCSI Pass-Through Requests

A storage class driver does not necessarily set up an SRB when it sets up an IRP_MJ_DEVICE_CONTROL request for an I/O control code supported by the port driver, such as IOCTL_SCSI_PASS_THROUGH or IOCTL_SCSI_PASS_THROUGH_DIRECT.

A class driver that generates such a request is responsible for the following:

  • Setting the length of the user buffer at Parameters.DeviceIoControl.InputBufferLength to at least sizeof(SCSI_PASS_THROUGH) or sizeof(SCSI_PASS_THROUGH_DIRECT)
  • Setting up the storage port driver's I/O stack location as usual
  • Setting the MinorFunction in the IRP to IRP_MN_SCSI_CLASS, which marks the request as having been processed by a storage class driver.

On receipt of an IOCTL_SCSI_PASS_THROUGH or IOCTL_SCSI_PASS_THROUGH_DIRECT request from a higher-level driver, a storage class driver's DispatchDeviceControl routine is responsible for checking the validity of the embedded SCSI command (CDB) and, if the command is valid for its device, sending the request to the storage port driver.

If the port driver's I/O stack location for an IOCTL_SCSI_PASS_THROUGH or IOCTL_SCSI_PASS_THROUGH_DIRECT request does not have its MinorFunction field set with IRP_MN_SCSI_CLASS, the port driver assumes the request came directly from an application and that no class driver exists for the target device type. It is an application error to send such a request directly to the port driver for a device that has been claimed by a storage class driver.

The port driver does not check the validity of the SCSI command embedded in such a pass-through request.


Handling PnP Requests to Storage Peripherals

A storage class driver is responsible for the following in response to PnP requests:

  • Starting its device in response to a start request (IRP_MJ_PNP with IRP_MN_START_DEVICE). See Handling PnP Start_in a Storage Class Driver.
  • Removing its device in response to a remove request (IRP_MJ_PNP with IRP_MN_REMOVE_DEVICE). See Storage Class Driver's RemoveDevice Routine.
  • If its device can contain the system paging file, maintaining a count of paging path notifications in its device extension in response to a paging-notification request (IRP_MJ_PNP with IRP_MN_DEVICE_USAGE_NOTIFICATION) and forwarding the request to the next-lower driver.
  • Handling query-remove and query-stop requests and, if the device contains the system paging file or hibernation file, failing such requests. A driver might also fail a query-remove request if its device is claimed for crash dump, because removing such a device disables crash dump.

The storage class driver forwards PnP query, cancel, and stop requests (except for failed query requests) to the next-lower driver.


Handling Power Requests to Storage Peripherals

A storage class driver is responsible for issuing device-specific commands to handle power requests. Most commonly, a storage class driver:

  • Blocks I/O to its device in response to a query-power request (IRP_MJ_POWER with IRP_MN_QUERY_POWER) if handling such I/O might prevent the driver from succeeding a set-power request in a reasonable amount of time
  • Sets the power state of its device in response to a set-power request (IRP_MJ_POWER with IRP_MN_SET_POWER)
  • Restarts I/O to its device in response to a set-power request to power up the device
  • Forwards power requests to the next-lower driver.

Note that a driver must call PoStartNextPowerIrp and PoCallDriver, not IoCallDriver, to send power requests.

Unless the storage class driver has a StartIo routine, it should lock the storage port driver's LU-specific queue (IRP_MJ_SCSI with SRB_FUNCTION_LOCK_QUEUE) before setting the device's power state, to block unsynchronized operations until the power operation (which may involve several steps) is complete. Any SRBs issued to handle the power operation should set SRB_FLAGS_BYPASS_LOCKED_QUEUE to make sure they reach the port driver. After the driver finishes setting the power state, it should unlock the queue (IRP_MJ_SCSI with SRB_FUNCTION_UNLOCK_QUEUE and SRB_FLAGS_BYPASS_LOCKED_QUEUE) so that the port driver can resume sending queued IRPs to the device once it has been powered up.

If a storage class driver has a StartIo routine, that routine handles synchronization so the class driver does not have to explicitly lock and unlock the port driver's LU-specific queue.

A class driver should not attempt to bypass a queue locked by another driver.


Queueing Storage Requests

Although it is possible for a storage class driver to set up internal queues for IRPs, it is seldom necessary to do so and likely to degrade the driver's performance as well, because the storage port driver already maintains driver-created, LU-specific device queues for IRPs. Whether or not a particular HBA supports multiple outstanding commands (for example, SCSI-2 tagged queuing), storage class drivers can send every request to their devices as each IRP comes in and rely on the system-supplied port driver or the HBA to handle queued requests expeditiously.

When certain SCSI errors occur, the system port driver freezes the appropriate LU-specific queue and notifies the class driver. For more information about handling errors and releasing frozen request queues, see the following:

Storage Class Driver's ReleaseQueue Routine

Storage Class Driver's InterpretRequestSense Routine

Storage Class Driver's RetryRequest Routine

If an HBA supports command queuing, as indicated in the returned STORAGE_ADAPTER_DESCRIPTOR data, the class driver sets SRB_FLAGS_QUEUE_ENABLE and uses the QueueAction member of the SRBs it creates to control how its requests are queued.


Storage Class Driver's Internal Routines

This section describes internal routines that a writer of a storage class driver typically might want to define. The section contains the following topics:

Storage Class Driver's ClaimDevice Routine

Storage Class Driver's BuildRequest Routine

Storage Class Driver's SplitTransferRequest Routine

Storage Class Driver's ReleaseQueue Routine

Storage Class Driver's InterpretRequestSense Routine

Storage Class Driver's RetryRequest Routine

Storage Class Driver's RemoveDevice Routine


Storage Class Driver's ClaimDevice Routine

The ClaimDevice routine, which claims a storage device, is typically called from a storage class driver's AddDevice routine.

To claim a storage device, a class driver gets a reference to a device object by calling IoGetAttachedDeviceReference with the PDO passed to the class driver in the AddDevice call, then either calls an internal ClaimDevice routine from its AddDevice routine or implements the same functionality inline. A ClaimDevice routine sets up an SRB with the Function value SRB_FUNCTION_CLAIM_DEVICE and sends it to the device object returned by the class driver's call to IoGetAttachedDeviceReference.

The ClaimDevice routine allocates an IRP with IoBuildDeviceIoControlRequest, setting up the port driver's I/O stack location with the I/O control code IOCTL_SCSI_EXECUTE_NONE and a pointer to the SRB at Parameters.Scsi.Srb. ClaimDevice also must set up an event object with KeInitializeEvent so it can wait on the completion of the IRP. Then, it sends the IRP on to the next-lower driver with IoCallDriver.

When the IRP completes, ClaimDevice should release the reference to the device object returned by IoGetAttachedDeviceReference.

A ClaimDevice routine can serve double duty as a routine to be called from a class driver's RemoveDevice routine, or from AddDevice if the driver succeeds in claiming the device but cannot create a device object. In such cases, ClaimDevice sends an SRB with the Function value SRB_FUNCTION_RELEASE_DEVICE.


Storage Class Driver's GetDescriptor Routine

For data transfer operations, storage class drivers need configuration information about each HBA driving a bus to which their devices are attached. To get this information, a class driver either calls an internal GetDescriptor routine or implements the same functionality in its StartDevice routine. (For information about StartDevice, see Handling PnP Start in a Storage Class Driver.)

A GetDescriptor routine builds and sets up query-property requests (IRP_MJ_DEVICE_CONTROL with IOCTL_STORAGE_QUERY_PROPERTY) for the port driver to retrieve device and adapter descriptors which the class driver stores in its device extension. The class driver might also set driver-writer-determined flags in the device extension according to the returned descriptor data.

The class driver inspects the returned STORAGE_DEVICE_DESCRIPTOR data to determine device capabilities (SCSI inquiry data or the nonSCSI equivalent) such as the SCSI-2 device type, whether the device's media (if any) is removable (RemovableMedia), whether the device supports multiple outstanding commands (CommandQueueing), and various ID strings. The class driver inspects the returned STORAGE_ADAPTER_DESCRIPTOR data to determine adapter capabilities, including:

  • The maximum number of bytes a particular HBA can transfer in a single operation (MaximumTransferLength).
  • If the HBA can transfer buffered data backed by noncontiguous physical pages (i.e., supports scatter/gather), how many noncontiguous physical pages per buffer it can manage, per transfer operation (MaximumPhysicalPages).
  • The HBA's alignment requirements for transfers so the class driver can properly set the AlignmentRequirement field in its device objects. (AlignmentMask).

    Applications that send IOCTL_SCSI_PASS_THROUGH requests also might use this field.

For more information about setting up AlignmentRequirement in device objects, see Initializing a Device Object.

  • Whether the HBA supports SCSI-2 tagged queuing and/or per-logical-unit internal queues (CommandQueueing).
  • Whether the HBA supports synchronous transfers (AcceleratedTransfer).
  • Whether the HBA caches data internally (CachesData).

The class driver should store this information in the FDO's device extension so its dispatch routines can ensure that all requests sent to the storage port driver conform to the size, number of physical breaks, and alignment requirements of the underlying HBA. For more information about class driver dispatch routines, see Storage Class Driver's Dispatch Routines. For more information about setting up device extensions, see Setting up a Storage Class Driver's Device Extension.


Storage Class Driver's BuildRequest Routine

Like all higher-level kernel-mode drivers, a storage class driver must set up the IRP's I/O stack location for the next-lower driver when handling requests to storage peripherals. In IRPs that the class driver sets up with SRBs for the system-supplied port driver, the port driver's I/O stack location is set with the following:

  • MajorFunction contains IRP_MJ_SCSI
  • Parameters.Scsi.Srb contains a pointer to the SRB

Each class driver is responsible for allocating memory for SRBs as well as for setting them up with CDBs for the underlying storage port driver. The class driver can either set up a lookaside list for its SRBs with ExInitializeNPageLookasideList or call ExAllocatePool for nonpaged memory. See Using Lookaside Lists for more information about using lookaside lists and nonpaged pool.

Whether it allocates memory from pool or from a driver-created lookaside list, every storage class driver is responsible for freeing the memory it allocates for SRBs. Storage class drivers' IoCompletion routines, described in Storage Class Driver's IoCompletion Routines, usually release the memory allocated for SRBs back to a lookaside list.

A class driver's BuildRequest routine must set appropriate values in the SRB members, including the length of the CDB it has set up to communicate with its device. For requests that return request-sense information and/or that the driver might need to retry, it sets an IoCompletion routine in the IRP. For read or write requests, it ORs the SrbFlags with the appropriate transfer direction, SRB_FLAGS_DATA_IN or SRB_FLAGS_DATA_OUT, respectively.

A BuildRequest routine might share the responsibility for setting up an SRB with a pair of SendSrbSynchronous and SendSrbAsynchronous routines. That is, the BuildRequest routine could set up the SRB members that are commonly set up for all requests, while the SendSrbXxx routines each set SRB values pertinent only to each type of request. When an IRP is passed down to the port driver from a SendSrbAsynchronous routine, the IRP must be set up with a driver-supplied IoCompletion routine.

After the class driver has loaded, it sets up most SRBs with the Function member set to SRB_FUNCTION_EXECUTE_SCSI, indicating a device I/O request to be sent over the bus.

For more information about the system-defined SRB members and their values, see SCSI_REQUEST_BLOCK.

Setting Up SRBs for Request Sense

A class driver can request that the port driver return SCSI-2 request-sense or equivalent information when the target controller returns a check condition. To do this, the class driver sets up the SenseInfoBuffer pointer and SenseInfoBufferLength in the SRB, so the port driver can return the request-sense information if a check condition occurs. The port driver indicates that it returned request-sense information by setting the SrbStatus member with SRB_STATUS_AUTOSENSE_VALID when it returns the IRP. For more information about InterpretSenseInfo routines, see Storage Class Driver's InterpretRequestSense Routine.

Retries

Storage class drivers are responsible for retrying requests that fail due to target/controller errors, bus resets, or request time-outs. Consequently, many class drivers maintain a retry count in their own I/O stack location of the IRP. Such a class driver's BuildRequest routine also might initialize the retry limit for a given request before it sets up its IoCompletion routine and sends the IRP to the port driver. For more information about RetryRequest routines, see Storage Class Driver's RetryRequest Routine.


Storage Class Driver's SplitTransferRequest Routine

The STORAGE_ADAPTER_DESCRIPTOR data returned to the GetDescriptor routine indicates the transfer capabilities of a given HBA to the class driver. In particular, this data indicates the MaximumTransferLength in bytes and the MaximumPhysicalPages: that is, how many noncontiguous pages the HBA can manage in the physical memory backing a system buffer (i.e., the extent of its scatter/gather support).

Most class drivers store a pointer to this configuration data in the device extension of each device object because storage class drivers are responsible for splitting all transfer requests that exceed the HBA's capability to transfer data. In other words, a class driver's DispatchReadWrite routine must determine whether each IRP requests a transfer that is more than the HBA can handle in a single transfer operation.

For example, such a DispatchReadWrite routine could have code similar to the following:

PSTORAGE_ADAPTER_DESCRIPTOR adapterDescriptor =
    commonExtension->PartitionZeroExtension->AdapterDescriptor;
ULONG transferPages;
ULONG maximumTransferLength =
    adapterDescriptor->MaximumTransferLength;
    :        :
//
// Calculate number of pages in this transfer
//
transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
                    MmGetMdlVirtualAddress(Irp->MdlAddress),
                        currentIrpStack->Parameters.Read.Length);
//
// Check whether requested length is greater than the maximum number
// of bytes that can be transferred in a single operation
//
if (currentIrpStack->Parameters.Read.Length > maximumTransferLength ||
        transferPages > adapterDescriptor->MaximumPhysicalPages) {
    transferPages = adapterDescriptor->MaximumPhysicalPages - 1;
    if (maximumTransferLength > transferPages << PAGE_SHIFT) {
        maximumTransferLength = transferPages << PAGE_SHIFT;
    }
    IoMarkIrpPending(Irp);
    SplitTransferRequest(DeviceObject,
                            Irp,
                            maximumTransferLength);
    return STATUS_PENDING;
}
    :        :

The class driver cannot tell how many physical breaks the buffer will have once it has been mapped, so it must assume that each page in the transfer is discontiguous and compare the number of pages against the number of physical breaks allowed.

Note that such a driver's DispatchReadWrite routine calls IoMarkIrpPending and returns STATUS_PENDING immediately after a call to its SplitTransferRequest routine with the original IRP.

To carry out the original transfer request, the driver's SplitTransferRequest routine creates one or more IRPs to handle sub-buffers that are sized to suit the HBA's capabilities. For each such IRP, the SplitTransferRequest routine:

  • Sets up an SRB, usually by calling an internal BuildRequest routine (see Storage Class Driver's BuildRequest Routine)
  • Copies the MDL address from the original IRP to the new IRP
  • Sets the DataBuffer in the SRB to an offset in bytes into the MDL for this piece of the transfer
  • Sets up its IoCompletion routine before sending the IRP on to the port driver with IoCallDriver

To track each piece of the transfer, SplitTransferRequest registers an IoCompletion routine for each driver-allocated IRP it sends to the next-lower driver. The IoCompletion routine maintains a count of completed partial transfer requests in the original IRP, using InterlockedIncrement and InterlockedDecrement to ensure that the count is accurate.

Such an IoCompletion routine must free any IRPs and/or SRBs the driver has allocated and must complete the original IRP when all requested data has been transferred or when the class driver has exhausted retries of the IRP and must fail it due to device transfer errors.


Storage Class Driver's ReleaseQueue Routine

Unless a storage class driver ORs the SrbFlags for a given request with SRB_FLAGS_NO_QUEUE_FREEZE, the system port driver freezes a queue for a given logical unit after any of the following:

  • A bus reset occurred while the logical unit was executing a request.
  • The logical unit returned SCSISTAT_CHECK_CONDITION or SCSISTAT_COMMAND_TERMINATED, which the class driver can find in the SRB's ScsiStatus member.
  • A request was timed out.
  • A request was terminated by a bus message command such as SCSIMESS_ABORT.

The port driver indicates that an LU-specific queue has been frozen by returning a request with SRB_STATUS_QUEUE_FROZEN in the SrbStatus member. New requests from the class driver can be inserted into the queue, but only autosense requests are sent to the logical unit as long as its queue is frozen.

Freezing the queue under these conditions gives each storage class driver an opportunity to analyze an error before other queued jobs are executed. For example, queued jobs might need to be cancelled if the media has changed. To flush the queue, the driver can send a request with the SrbFlags ORed with SRB_FLAGS_BYPASS_FROZEN_QUEUE.

A ReleaseQueue routine allocates and sets up an IRP and an SRB to either release or flush a frozen queue. The Function member of the SRB must be set to SRB_FUNCTION_RELEASE_QUEUE or SRB_FUNCTION_FLUSH_QUEUE, which both releases a frozen queue and cancels all currently queued requests for the target logical unit. The port driver completes all requests in a flushed queue with their SrbStatus members set to SRB_STATUS_FLUSHED.

Failing to release a frozen queue makes the device inaccessible, so a driver's ReleaseQueue routine should be designed to succeed even in low memory conditions. A ReleaseQueue routine should first attempt to allocate memory for an SRB by calling ExAllocatePool with the NonPagedPool memory type and, if that allocation fails, use an SRB that was pre-allocated during driver initialization. If the driver allocates an SRB to hold in reserve when it initializes its device extension, as described in Setting up a Storage Class Driver's Device Extension, its ReleaseQueue can use that SRB if the memory pool is low, with an appropriate synchronization mechanism in case multiple concurrent release operations might be needed.

Note that a class driver's ReleaseQueue routine is called asynchronously, generally from its IoCompletion routine. A class driver's IoCompletion routine cannot call ReleaseQueue to flush a queue that is not frozen. However, it can call ReleaseQueue to release an unfrozen queue, and the port driver simply ignores such a request.


Storage Class Driver's InterpretRequestSense Routine

An InterpretRequestSense routine interprets the data returned in the SRB's SenseInfoBuffer, determines whether the request should be retried, and, if not, maps the error to an NTSTATUS value for the IRP's I/O status block.

The system port driver indicates whether request-sense information is available by setting SRB_STATUS_AUTOSENSE_VALID or SRB_STATUS_REQUEST_SENSE_FAILED in SrbStatus.

If no request-sense information is available, InterpretRequestSense should check the SrbStatus value to determine whether to retry a given request or to determine an appropriate mapping to an NTSTATUS value.

The InterpretRequestSense routine might call a driver-supplied error-logging routine, as well. Whenever a storage class driver logs an I/O error, it should include the PathId, TargetId, Lun, and SrbStatus values set by the storage port driver in the SRB, and, if possible, pertinent request-sense information as part of the error log entry's DumpData. Note that a storage class driver must not use the PathId, TargetId, and Lun from such SRBs to address other requests.

For more information about logging I/O errors, see Logging Errors.


Storage Class Driver's RetryRequest Routine

The underlying storage port driver is responsible for retrying requests if device errors occur that involve transmission of data on the bus, including bus-parity errors, selection time-outs, and target/controller-busy errors. If retry attempts fail, the storage port driver completes the request with an appropriate error and logs the I/O error, as well.

A storage class driver should never attempt to retry a request that the port driver has already failed due to any of the preceding errors.

A storage class driver is responsible for retrying requests that fail due to device-specific errors, target/controller errors other than target/controller-busy, bus resets, or request time-outs. In general, a RetryRequest routine can resubmit such an IRP to the next-lower driver and direct that the SRB be placed at the head of the port driver's LU-specific queue.

In particular, a RetryRequest routine should do the following:

  1. Ensure that a partial transfer request has the correct values set for the starting address and length.
  2. Zero the SrbStatus and ScsiStatus members of the SRB.
  3. Set up the SrbFlags member, as necessary for the device.
  4. Set up the I/O stack location for the port driver in the IRP as already described in Storage Class Driver's Dispatch Routines through Storage Class Driver's SplitTransferRequest Routine.
  5. Call IoSetCompletionRoutine for the IRP, because the driver's IoCompletion routine must free the SRB before the IRP returns. The IoCompletion routine might also need to retry the request more than once, or to call the driver's InterpretRequestSense or ReleaseQueue routine.
  6. Pass the request on to the next-lower driver with IoCallDriver.


Storage Class Driver's RemoveDevice Routine

When a device is about to be removed, the PnP Manager first calls the class driver's DispatchPnP routine with a PnP query-remove request (IRP_MJ_PNP with IRP_MN_QUERY_REMOVE_DEVICE. The storage class driver should fail the query-remove request in any of the following cases:

  • The device contains the system paging file or hibernation file.
  • The driver is running a long operation which should not be cancelled (for example, rewinding or formatting a tape).
  • There are outstanding handles to the device (CREATEs).

The storage class driver might also fail a query-remove request if the device is claimed for crash dump, because removing such a device disables crash dump.

If the storage class driver returns STATUS_SUCCESS in response to a query-remove request, the PnP Manager then calls the class driver's DispatchPnP routine with a PnP remove request (IRP_MJ_PNP with IRP_MN_REMOVE_DEVICE). The storage class driver's DispatchPnP routine either calls an internal RemoveDevice routine or implements the same functionality inline.

A storage class driver's RemoveDevice routine must do the following:

  • Release any outstanding resources, such as memory or events, allocated by the driver.
  • Delete symbolic links, if any, created by the driver.
  • Delete the device object (FDO).
  • Forward the request to the next-lower driver.

If the storage class driver created PDOs at startup (for example, to represent partitions on a partitioned media device), such PDOs have already been removed when the PnP Manager sends the remove request to the storage class driver.

Even after a device object has been deleted, if it has a non-zero reference count the device object persists in the system until its reference count reaches zero, then disappears silently. A storage class driver must not attempt to use the device object pointer after the device object has been deleted.

For more information about handling a remove request, see Removing a Device.


Converting an Existing SCSI Class Driver for Plug and Play

To run successfully as a PnP driver, an existing SCSI class driver must be modified as follows:

  • Driver initialization code must follow the rules for initialization of a Plug and Play driver. Functionality in the DriverEntry routine of an existing SCSI driver is divided among the DriverEntry, AddDevice, and DispatchPnP routines of a storage class driver, as described in Storage Class Driver's DriverEntry Routine, Storage Class Driver's AddDevice Routine, and Handling PnP Start in a Storage Class Driver.
  • Code that builds SRBs must not set PathId, TargetId, and Lun fields to a target device address, and should initialize these fields to 0xFF. The device address is implicit in the PDO that represents a device and the driver must communicate only with such a device object, so it is unnecessary for the class driver to provide the device address.
  • Code that gets SCSI inquiry and capabilities data by issuing IOCTL_SCSI_GET_INQUIRY_DATA and IOCTL_SCSI_GET_CAPABILITIES requests should issue IOCTL_STORAGE_QUERY_PROPERTY requests to retrieve device and adapter descriptors instead.
  • The driver must handle PnP requests to start, stop, and remove the device, and must have a mechanism to fail such a request if handling it would interfere with data transfers or system operations. For example, a driver should fail a query-remove, query-stop, or stop request if its device contains a system page file. Such a driver should handle paging notification requests (IRP_MJ_PNP with IRP_MN_DEVICE_USAGE_NOTIFICATION and notification type of DeviceUsageTypePaging) to maintain the count of page files on its device.
  • The driver must handle requests to change the power state of the device (IRP_MJ_POWER with IRP_MN_QUERY_POWER and IRP_MN_SET_POWER), and must block I/O to the device during power state transitions.


Supporting Mount Manager Requests in a Storage Class Driver

The Mount Manager (MM) is responsible for managing volume names. For each volume, it stores a name that is unique and is permanently identified with the volume, even after the volume has been removed from the system. It also manages less permanent names, like drive letters, that persist across reboots, but whose assignments can change as volumes are added to or removed from the system.

The Mount Manager provides a unique interface to each volume in the system by creating a symbolic link to the volume's device object. Since the symbolic links themselves and the device objects they target do not persist when the system restarts, the Mount Manager preserves the name of the symbolic link in a persistent name database in the registry.

This symbolic link name is called a unique volume name. Like a traditional volume label, it persists when the system restarts, but like a drive letter, and unlike a volume label, it is unique. The format for unique volume names is:

"\??\Volume{GUID}\

where GUID is a globally unique identifier that identifies the volume

Mount Manager's persistent name database is located in the MountedDevices registry key of the SYSTEM hive (HKLM/SYSTEM/MountedDevices) of the registry. In addition to unique volume names, the Mount Manager also stores mount point names in its persistent name database. Mount point names can be further subdivided into two categories: Win32-style pathnames that serve as the root directory of the mounted volume's file system, and drive letters.

Each persistent symbolic link name in the database appears as the name of a registry value under the MountedDevices key accompanied by a unique id. The unique id is another unique identifier of a volume (different from the unique volume name). It helps identify which of the potentially numerous persistent symbolic link names refer to the same volume.

For instance, a single volume with a unique volume name of "\\?\Volume{7603f260-142a-11d4-ac67-806d6172696f }\" might have an accompanying drive letter "\DosDevices\D:" and two mount points "\DosDevices\C:\mymount" and "\DosDevices\E:\FilesysD\mnt". This would produce four entries in Mount Manager's persistent symbolic link name database: one for the unique volume name, one for the drive letter, and two for the two mount point names. All four entries would share the same unique id. Thus someone viewing the MountedDevices registry key would be able to detect that all four persistent names point to the same volume.

The following figure illustrates how persistent names appear in the MountedDevices registry key.

MountedDevices Registry Key

The Mount Manager relies on the Plug and Play device interface notification mechanism to alert it of volume arrival and removal. Therefore every client (that is, every volume driver, usually a class driver) must create an interface in the MOUNTDEV_MOUNTED_DEVICE_GUID interface class by calling IoRegisterDeviceInterface to notify the Mount Manager of the arrival in the system of the volume it manages. The MOUNTDEV_MOUNTED_DEVICE_GUID interface class GUID is defined in mountmgr.h.

Upon receiving a Plug and Play notification of the arrival of a volume interface, Mount Manager sends the client three device control IRPs:

IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME

In response to these three IOCTLs the client should return the volume's nonpersistent device object name (or target name) located in the Device directory of the system object tree (for example: "\Device\HarddiskVolume1"), the unique volume ID, and a suggested persistent symbolic link name for the volume, respectively. Although clients may elect to ignore the first and third of these three IOCTLs, they are required to provide a unique volume ID upon receiving IOCTL_MOUNTDEV_QUERY_UNIQUE_ID. The Mount Manager relies entirely upon the client to provide the unique volume ID, and if the client does not provide it, then the Mount Manager is not able to assign mount points, such as drive letters, to the volume.

For more information on these IOCTLs, see I/O Control Codes Sent by the Mount Manager.

If a client alerts the Mount Manager of the arrival of its volume but fails to provide a unique ID for the volume when queried, the volume is placed on a dead mounted device list. When this occurs, clients can send an IOCTL_MOUNTMGR_CHECK_UNPROCESSED_VOLUMES IOCTL to the Mount Manager to request that the Mount Manager rescan its dead mounted device list and make another attempt to query the clients on the list for the unique IDs of their respective volumes. For more information on the IOCTL_MOUNTMGR_xxx IOCTLs, see I/O Control Codes Sent by Mount Manager Clients

Once the Mount Manager receives a unique volume ID for a newly introduced volume, then it searches its database for all of the persistent names assigned to that unique ID and creates symbolic links to the volume for each persistent symbolic link name.

If the Mount Manager discovers that the volume does not have a unique volume name, it constructs one and stores it in the database.

When the Mount Manager detects that a volume has gone off line then it deletes the symbolic links pointing to the device object without deleting the corresponding symbolic link names in the Mount Manager's database.

For information on how Mount Manager clients create persistent symbolic names see IOCTL_MOUNTMGR_CREATE_POINT.


Tape Miniclass Drivers

This chapter contains the following information:

Using the Tape Class Driver

Required and Optional Tape Miniclass Routines

Storing Tape Miniclass Context in Optional Extensions

Processing Tape Device Control Requests

NT-based operating systems provide a generic tape class driver that handles operating system-specific and device-independent tape tasks. The tape class driver is provided as a kernel-mode DLL. To support a new tape device or family of tape devices, a driver writer creates a device-specific tape miniclass driver that links dynamically to the system-supplied tape class driver.

If a tape miniclass driver calls only routines in the tape class driver, the miniclass driver can be portable across Microsoft operating systems that support Win32® applications and provide a tape class driver that uses the tape miniclass interface. A tape miniclass driver includes the header file minitape.h.

An existing tape miniclass driver must be modified to support one new entry point, TapeMiniGetMediaTypes, in order to build and run under Windows 2000 and later operating systems. No other modifications are required. The system-supplied tape class driver, together with the system-supplied storage port driver, handles Plug and Play and power management requests on behalf of a tape miniclass driver.

This chapter describes the support provided by the operating system-specific tape class driver and provides guidelines for writing a new tape miniclass driver. See Tape Class Driver Routines and Tape Miniclass Driver Routines for details on the routines in the tape class and tape miniclass drivers. See Device Configurations and Layered Drivers of this Guide for a description of the storage device driver layers.


Using the Tape Class Driver

The system-supplied tape class driver implements device-independent, operating system-specific tape support and exports support routines for device-specific tape miniclass drivers.

The tape class driver:

  • Initializes the tape miniclass driver using device-specific information provided by the miniclass driver's DriverEntry routine, including allocating and initializing operating system resources for the miniclass driver and the devices it supports, creating a device object (FDO) to represent the device and attaching it to the device stack, and starting the device on receipt of a start request from the PnP Manager.
  • Exports memory allocation and initialization routines.
  • Splits transfer requests when necessary to fit within the maximum transfer size for the HBA.
  • Handles IRP_MJ_CREATE, IRP_MJ_READ, and IRP_MJ_WRITE, IRP_MJ_PNP, and IRP_MJ_POWER requests.
  • Performs device-independent preprocessing for IRP_MJ_DEVICE_CONTROL requests and dispatches to the corresponding device-specific routines in the tape miniclass drivers.
  • Allocates SRBs and sends them to the underlying storage port driver after the tape miniclass driver has filled in the CDB and any other SRB members appropriate to the request.
  • Translates between Windows NT status codes and tape status codes, provides device-independent tape-specific error handing, and calls the tape miniclass driver's device-specific error handling routines.
  • Allocates driver context areas for tape miniclass drivers (minitape extension and command extension).

See Tape Class Driver Routines for descriptions of the TapeClass Xxx routines that can be called by a tape miniclass driver.


Required and Optional Tape Miniclass Routines

A tape miniclass driver must have the following routines:

  • DriverEntry provides driver-specific entry points and constants that the tape class driver uses to initialize the miniclass driver.

    The tape miniclass driver's DriverEntry routine allocates a TAPE_INIT_DATA_EX structure, sets driver-specific constants and entry points in the structure, and calls TapeClassInitialize in the tape class driver.

  • Routines that implement device-specific processing for device-control requests, such as TapeMiniGetPosition and TapeMiniGetMediaTypes.

    The tape class driver calls such routines from its device-control dispatch routine. For more information, see Processing Tape Device Control Requests.

A tape miniclass driver can have the following optional routines:

  • TapeMiniExtensionInit initializes the optional minitape extension.

    See Storing Tape Miniclass Context in Optional Extensions for information on minitape extensions.

  • TapeMiniTapeError supplements the error handling of the tape class driver.

    For most devices, the tape class driver can return an appropriate status value when an error occurs without input from the tape miniclass driver. For some devices, however, the tape class driver requires device-specific information from the tape miniclass driver to return the appropriate status. For example, the miniclass driver for 4mm DAT tape drives can determine that, in certain situations, a TAPE_STATUS_BUS_RESET status is actually due to no media in the drive. The 4mm DAT miniclass driver's TapeMiniTapeError routine identifies these situations and changes the status that is returned to TAPE_ERROR_NO_MEDIA.

The tape miniclass driver's DriverEntry routine must use that name exactly in order to be loaded automatically by the operating system. TapeMiniXxx routines can be named as the driver writer chooses, as long as the entry points of the routines are set in the TAPE_INIT_DATA_EX structure. To aid in debugging, a miniclass driver should prefix the TapeMiniXxx routines with some characters to identify itself and should ensure the rest of the characters in the name reflect what the routine does.

See also the description of tape miniclass routines in Tape Miniclass Driver Routines.


Storing Tape Miniclass Context in Optional Extensions

A tape miniclass driver can store context in two optional extensions:

  1. A driver-specific minitape extension

    When used, this extension typically stores information about device capabilities (SCSI inquiry data or equivalent). A driver that supports several devices can store details about each device, rather than repeatedly querying the devices.

    A miniclass driver specifies the size of the minitape extension in the MinitapeExtensionSize member of the TAPE_INIT_DATA_EX structure it passes to TapeClassInitialize from its DriverEntry routine. The tape class driver allocates the requested storage on behalf of the miniclass driver. The miniclass driver initializes the optional extension with a TapeMiniExtensionInit routine. The minitape extension remains valid until the driver is unloaded.

  2. A command-specific command extension

    When used, this extension stores command-specific context between calls to a tape miniclass routine that might be called more than once to process a single request. For example, a tape miniclass driver's TapeMiniGetStatus routine might store the status from a TEST_UNIT_READY command in the command extension while it determines whether the tape drive also requires cleaning.

    A miniclass driver specifies the size of the command extension in the CommandExtensionSize member of the TAPE_INIT_DATA_EX structure it passes to TapeClassInitialize from its DriverEntry routine.

    All tape miniclass routines that handle device-specific aspects of device-control requests are given a pointer to the command extension when they are called. The tape class driver allocates storage for the command extension before calling such a miniclass routine. The miniclass routine initializes the command extension on the first call to process a given request; that is, when the CallNumber parameter to the routine equals zero. The command extension remains valid until the tape miniclass routine returns either TAPE_STATUS_SUCCESS or an error status.


Processing Tape Device Control Requests

Processing a single tape device-control request can require multiple SRBs and thus several calls from the tape class driver to a given tape miniclass routine. For example, to partition a tape, the miniclass driver must first rewind the tape and then partition it; the miniclass driver's TapeMiniPartition routine must therefore be called twice to process a partition request completely.

When such a miniclass routine is called by the tape class driver, the miniclass driver uses the return status to indicate whether the request is complete or whether the routine should be called again. The tape class driver maintains a zero-based count of the number of times the miniclass routine has been called for a given request and passes that count to the routine as the CallNumber parameter.

A miniclass routine returns one of the following status values to indicate that the routine should be called again:

  • TAPE_STATUS_SEND_SRB_AND_CALLBACK

    This return directs the tape class driver to send the SRB to the device. A tape miniclass routine usually returns this status after filling in the SRB passed by the tape class driver. If the operation is successful, the class driver increments CallNumber and calls the miniclass routine again. If the SRB fails, the class driver calls the miniclass routine again depending on the value of RetryFlags.

  • TAPE_STATUS_CHECK_TEST_UNIT_READY

    This return directs the tape class driver to create an SRB for the TEST UNIT READY command and to send the SRB to the device.

  • TAPE_STATUS_CALLBACK

    This return directs the tape class driver to increment CallNumber without sending an SRB to the device. This streamlines case statements that support several devices. For example, suppose that most of the tape devices supported by a particular miniclass driver require three SRBs to process a certain request. One device, however, requires only the first and third SRBs. For the unique device the tape miniclass driver can return TAPE_STATUS_CALLBACK to skip the second SRB, allowing the driver to use the same code to process the request for all the devices it supports.

  • TAPE_STATUS_REQUIRES_CLEANING

    If a tape device supports cleaning notification in sense data rather than as an error, a tape miniclass driver's TapeMiniGetStatus routine returns this status to indicate to the tape class driver that the drive needs cleaning.

When the miniclass routine finishes processing a request—either successfully or with an error after retries are exhausted—it returns to the tape class driver with a TAPE_STATUS_XXX that indicates the success or failure of the request.


Changer Drivers

This section contains the following information:

System-Supplied Changer Drivers

Vendor-Supplied Changer Drivers

Storing Device-Specific Information in the Changer's Device Extension

Processing Changer Device-Control Requests

A changer driver controls the elements of a media library, or changer (sometimes called an autoloader, autochanger, or jukebox). In NT-based operating systems, a driver for a changer consists of the following:

  • A system-supplied changer class driver provided as a library, mcd.lib, that provides functionality common to all changer drivers
  • A device-specific miniclass driver, statically linked to mcd.lib, that provides routines called by the changer class driver to support a particular type of changer

This section contains guidelines for writing a new changer miniclass driver.


System-Supplied Changer Drivers

This section describes the system-supplied components of the changer driver model.

This section includes information on:

The Changer Driver Model

The Changer Class Driver

Differences in Changer Class Driver Versions

For a discussion of vendor-supplied changer drivers, see Vendor-Supplied Changer Drivers.


The Changer Driver Model

The following figure shows the relationship between a changer driver, user-mode applications and services, mass-storage and port drivers, and a changer device.

Changer Driver Model

As shown in this figure, transfers of user data are handled by the appropriate mass-storage driver for changer's drives, using the same Microsoft® Win32® requests as for a standalone drive. However, a mass-storage driver must handle the IOCTL_STORAGE_GET_MEDIA_TYPES_EX I/O request in order to control changer's drives.

User-mode applications access changer's elements through a user-mode service called the Removable Storage Manager (RSM). RSM is the only client of a changer driver and it reserves the changer for exclusive use. RSM sends requests involving changer's elements (for example, to mount a piece of media in a drive) to the changer driver. User-mode applications cannot send requests directly to the changer driver. For details on RSM, see the Platform SDK documentation.

The elements of a changer include:

  • Transport element

    The robotic component that moves media between other elements in the changer. Most changers have a single transport element with either one or two pickers that hold the media being moved. A high-end, fault-tolerant changer might have more than one transport element.

  • Data transfer elements

    The drives from which the data is read and written to media. For example, magnetic or optical disk, tape, CD-ROM, or DVD. Typically, a changer contains only one kind of drive.

  • Storage elements

    The slots in which media are stored when not mounted in drives.

A changer might also have either one or both of the following elements:

  • Import/export(IEport)

    An element where an operator can insert or remove one or more, but not all, media in the changer.

  • Door

    Provides access to all media in the changer at one time. A changer's door can be a physical door that an operator opens, or a single magazine that holds all media.

A changer miniclass driver reports the type and number of a changer's elements in a GET_CHANGER_PARAMETERS structure when requested by the changer class driver. In particular, the miniclass driver must report IEports and doors according to these definitions, regardless of the elements' physical appearance, so that an application can issue appropriate requests to those elements.


The Changer Class Driver

The changer class driver performs operating system-specific, device-independent services for a changer miniclass driver provided by the hardware vendor. For more information on the changer miniclass driver, see Vendor-Supplied Changer Drivers.

The changer class driver:

  • Provides memory allocation routines that a miniclass driver calls to allocate and free pool memory.
  • Provides an operating system-independent means of sending synchronous SRBs to the port driver in Microsoft® Windows® XP and later operating systems (see Differences in Changer Class Driver Versions for an explanation of the differences between Windows 2000 and Windows XP).
  • Helps initialize the class/miniclass driver pair.
  • Calls Changer Xxx miniclass driver routines to determine the amount of space to allocate for device-specific information and to prepare the changer to receive other requests.
  • Performs device-independent preprocessing for IRP_MJ_DEVICE_CONTROL requests, calls the appropriate Changer Xxx miniclass routines, and completes the requests.
  • Performs device-independent preprocessing for errors and calls the miniclass driver's ChangerError routine for device-specific processing.
  • Calls Changer Xxx miniclass driver routines to get product data, change element status, or query inquiry or volume tags data.


Differences in Changer Class Driver Versions

There are three key differences between the implementation of the changer class/miniclass driver pair in Windows XP and in Windows 2000:

  1. Different use of a DriverEntry routine in the miniclass driver.

    In Windows 2000, the changer class driver's DriverEntry routine performs various driver initialization tasks, including the initialization of entry points for I/O requests. In Windows XP and later operating systems, initialization takes place in the DriverEntry routine of the miniclass driver. See Required Changer Miniclass Routines for further information on the tasks that a miniclass driver's DriverEntry routine is required to perform.

  2. Different means of accessing classpnp.sys library routines.

    Class drivers for disk, tape, CD-ROM, and changer devices make use of the classpnp.sys library, a system-supplied DLL that contains a collection of operating system-specific, device-independent routines.

    Most system-supplied storage class drivers provide a set of key routines similar to routines found in the classpnp.sys library. This is done so that their miniclass drivers can call class driver routines instead of making direct calls to classpnp.sys. This shields the miniclass drivers from changes to the classpnp.sys DDI.

    Windows 2000 changer miniclass drivers are an exception to this rule, because in Windows 2000 the changer class driver does not provide miniclass drivers with a facility for calling the classpnp.sys routines indirectly. Thus, in Windows 2000, changer miniclass drivers must either call the classpnp.sys routines directly or call equivalent routines in line. Miniclass drivers that call classpnp.sys routines directly must link to the classpnp.sys library statically, swelling the size of the driver. If a driver dynamically links to classpnp.sys, changes to this library in subsequent releases might cause the driver to malfunction.

    In Windows XP and later operating systems, several of the most important services formerly provided by direct calls to the classpnp.sys library are provided by the changer class driver. Therefore, in Windows XP and later operating systems, it is usually unnecessary for changer miniclass drivers to call classpnp.sys library routines directly.

  3. The Windows XP changer class driver provides routines not available in Windows 2000. The discussion that follows examines this difference.

In Windows 2000, the changer class driver provides the following routines for the miniclass driver to call:

  • ChangerClassAllocatePool — allocates pool memory.
  • ChangerClassFreePool — frees pool memory.
  • ChangerClassDebugPrint — prints debugging information.

In Windows XP and later operating systems, the changer class driver provides, two additional routines in addition to the routines previously listed.

  • ChangerClassInitialize — The changer miniclass driver calls ChangerClassInitialize from within its DriverEntry routine to initialize the driver. ChangerClassInitialize performs many tasks formerly performed by the Windows 2000 changer class driver's DriverEntry routine.
  • ChangerClassSendSrbSynchronous — initializes and synchronously sends an SRB to an indicated target device.


Vendor-Supplied Changer Drivers

This section contains the following information:

Introduction to Changer Miniclass Drivers

Required Changer Miniclass Routines

Installing Changer Miniclass Drivers

Sample Changer Miniclass Drivers


Introduction to Changer Miniclass Drivers

To support a new changer, a driver writer implements a changer miniclass driver that links to the system-supplied changer class driver. A new changer miniclass driver must be written only to support a changer for which the system does not already provide a driver.

Before starting to implement a new miniclass driver, you should ensure that:

  • The device is a true changer and not a serial access stacker. A changer permits media to be mounted in its drives in random order, rather than a fixed sequence, as in a stacker.
  • The device's drives are not write-once optical drives such as WORM, CD-R, or DVD-R.
  • The device's drives are all the same type, not a mix of types such as CD-ROM and CD-R.

Microsoft operating systems do not support write-once optical drives or changers with more than one type of drive.


Required Changer Miniclass Routines

A changer miniclass driver must have the following routines, which are called by the changer class driver:

  • DriverEntry — In Windows XP and later operating systems, the changer miniclass driver's DriverEntry routine calls the changer class driver's ChangerClassInitialize routine to initialize the driver. See Differences in Changer Class Driver Versions for more information. Changer miniclass drivers do not have a DriverEntry routine in Windows 2000.
  • ChangerAdditionalExtensionSize indicates the number of bytes of additional space the miniclass driver requires in the changer's device extension for device-specific information.
  • ChangerInitialize prepares the changer to receive other requests.
  • ChangerError performs device-specific error processing after the changer class driver has performed any device-independent error processing.
  • ChangerExchangeMedium and ChangerMoveMedium move media between elements in a changer.
  • ChangerReinitializeUnit, ChangerSetAccess, and ChangerSetPosition position elements and control access to them.
  • ChangerGetElementStatus, ChangerGetParameters, ChangerGetProductData, ChangerGetStatus, ChangerInitializeElementStatus, and ChangerQueryVolumeTags get and, in the case of ChangerQueryVolumeTags, set various kinds of changer information.

Changer miniclass driver routines typically build SCSI request blocks (SRB) with command descriptor blocks (CDB) for the appropriate command, and send the SRBs to the system port driver.

If a changer does not support the functionality implied by a given routine, its driver must implement the routine so that it returns STATUS_INVALID_DEVICE_REQUEST.

For more information about the required Changer Xxx routines for changer miniclass drivers, see Changer Miniclass Driver Routines. For more information about the changer-specific I/O control codes for device control requests, see Changer I/O Control Codes.


Installing Changer Miniclass Drivers

This section provides installation information, specific to changer miniclass drivers in Windows 2000 and later operating systems.

Vendors supplying their own controller minidriver should make that minidriver a member of the MediumChanger setup class in the INF Version Section of the driver's INF file. For example:

[version]
Signature="$WINDOWS NT$"
Class=MediumChanger
ClassGuid={CE5939AE-EBDE-11d0-B181-0000F8753EC4}

There are no other special requirements associated with installing changer miniclass drivers.

For more installation information, see the INF files supplied with the media changer samples shipped with the Windows DDK.

For general information on device installation in Windows 2000 and later operating systems, see Device Installation Overview.


Sample Changer Miniclass Drivers

This section identifies the sample changer drivers included with the Windows DDK. These samples only function on Windows 2000 and later operating systems.

The Windows DDK includes the source code for the mcd.sys changer class driver and the following miniclass drivers:

  • adicsc.sys, the ADIC Scalar changer miniclass driver sample..
  • ddsmc.sys, the DDS 4mm changer miniclass driver sample.
  • elmsmc.sys, the Elms changer miniclass driver sample.
  • exabyte.sys, the Exabyte changer miniclass driver sample.
  • hpmc.sys, the Hewlett-Packard changer miniclass driver sample.
  • nsmmc.sys, the NSM changer miniclass driver sample.
  • sonymc.sys, the Sony changer miniclass driver sample.

Source code for all changer driver samples is located in the \src\storage directory of the Windows DDK.


Storing Device-Specific Information in the Changer's Device Extension

A changer miniclass driver specifies the storage it requires for device-specific data in its ChangerAdditionalExtensionSize routine. The changer class driver allocates the requested storage on behalf of the changer miniclass driver, then calls the miniclass driver's ChangerInitialize routine.

Whether the changer miniclass driver stores data in the device extension and what data it stores, is up to the driver designer. It typically includes SCSI inquiry data or the non-SCSI equivalent for changer devices.

The device extension might also include data that the miniclass driver uses to translate between device-specific element addresses and the zero-based element addresses passed in requests. In requests, elements are addressed by element type, starting with zero for the first element of a given type. Device-specific addresses typically do not follow this element addressing scheme, so the changer miniclass driver must translate the zero-based element addresses it receives into device-specific element addresses.

It does not matter how a miniclass driver translates element addresses as long as the addresses are translated. To optimize the process, a miniclass driver might store data that facilitates translation in the device extension. For example, at initialization, the driver could obtain device-specific element addresses from the SCSI element address assignment page or non-SCSI equivalent, map them to offsets that can be used to reconstruct the device-specific addresses, and store the offsets in the device extension. Then, when the changer miniclass driver receives a request that contains a zero-based element address, it could use the offset stored in the device extension to translate the zero-based address to a device-specific equivalent. The changer miniclass driver can use these device-specific addresses in the SRBs it sends to the system port driver.


Processing Changer Device-Control Requests

A changer miniclass driver does not process IOCTLs directly. Instead, it has a routine that corresponds to each IOCTL handled by the changer class driver.

When the class driver receives a request, it checks parameters and performs a certain amount of preprocessing. It then calls the corresponding changer miniclass driver routine, passing a pointer to the changer device object and to the IRP it received.

The changer miniclass driver performs any device-specific verification that might be required and builds one or more SRBs to send to the system port driver.

If the SRB succeeds, the miniclass driver routine fills in the output parameters involved in the request. Whether the SRB succeeds or fails, the miniclass driver routine typically returns the status it receives from the port driver to the changer class driver.


Storage Filter Drivers

This chapter contains the following information

Storage Filter Driver's Support of I/O Requests

Storage Filter Driver's Device-Type-Specific Functionality

Storage Filter Driver's DriverEntry Routine

Storage Filter Driver's AddDevice Routine

Handling PnP Start in a Storage Filter Driver

Storage Filter Driver's Dispatch Routines

Storage Filter Driver's IoCompletion Routines

Handling PnP Paging Requests

If an NT-based operating system storage class driver already exists for a particular type of device, it might be unnecessary to write a driver for a new device of the same type. Each system-supplied storage class driver is designed to support peripheral devices of a given type and is tested against a number of vendors' devices. Thus, any system-supplied storage class driver might provide all the support another device of its type needs.

If an existing storage class driver does not fully support a new device of its type, a new driver can be written as a storage filter driver (SFD) layered over or under an existing system-supplied class driver. An SFD might transform data in read-write requests, define additional I/O control codes (IOCTLs) that enable a user application to take advantage of additional features of a particular device, or work around device-specific problems without requiring hardware-specific changes to the generic class or port drivers.

Unless a new device requires that every request be handled in a device-specific manner, a storage filter driver can be developed in far less time than a new storage class driver.


Storage Filter Driver's Support of I/O Requests

A higher level SFD intercepts IRPs from user applications and higher level drivers and modifies them as needed before passing them to the next lower driver (a storage class driver or another filter driver). Such an SFD supplies device-specific support for requests that require special handling, such as translating data sent to or returned from the device in a nonstandard format, or programming the device in response to an IRP_MJ_DEVICE_CONTROL request.

A lower level SFD monitors SRBs and/or IRPs issued by a storage class driver and modifies them as needed before passing them to the next lower driver (a storage port driver or another filter driver).

Both higher and lower level SFDs can let the lower drivers process all I/O requests that require no special handling.

Like a storage class driver, an SFD has the following requirements common to all higher level kernel-mode drivers:

  • It must supply a set of Dispatch routines to which the I/O Manager and/or still higher level drivers can send IRPs for appropriate I/O operations. An SFD must support the same set of IRP_MJ_XXX as the storage class driver for its type of device.
  • For IRP_MJ_DEVICE_CONTROL requests, it must support as many of the class-driver-supported I/O control codes as its physical device can handle, and, if possible, emulate support for any remaining I/O control codes in the driver.
  • It must have a DriverEntry routine, an AddDevice routine, an Unload routine, and Dispatch routines to handle PnP and power IRPs, and can have any other standard higher level driver routine, such as IoCompletion routines, as necessary.
  • It must follow the rules for processing PnP, power management, and system control IRPs.

If its device has special features, an SFD can support a set of driver-defined I/O control codes in addition to the system-required set of device-type-specific I/O control codes for IRP_MJ_DEVICE_CONTROL requests.


Storage Filter Driver's Device-Type-Specific Functionality

Depending on the nature of its device, an SFD might be responsible for the following device-type-specific functionality:

  • Translating data from or into a device-specific format before or after sending a transfer request to lower driver(s) if the device processes data in a nonstandard format
  • Setting up IRPs with SRBs for port-driver-supported I/O control requests, for driver-defined I/O control requests, or for pass-through requests, as necessary for its device, and sending those IRPs to the next lower driver
  • Modifying class-driver-supplied SRBs as necessary for its device
  • Establishing time-out values for requests
  • Supplying one or more IoCompletion routines and, like the corresponding storage class driver, handling certain error conditions and retries for device-specific requests that require special handling

In general, an SFD has the same responsibilities as a storage class driver for those requests that require device-specific handling. For a discussion of the functionality required of storage class drivers, see Storage Class Drivers.


Storage Filter Driver's DriverEntry Routine

Like any other kernel-mode driver, the DriverEntry routine of an SFD must define its Dispatch and other entry points in the input driver object. If necessary, an SFD can allocate a driver object extension of appropriate size by calling IoAllocateDriverObjectExtension, copy the input registry path into the driver extension for later use, and initialize the driver extension with other driver-determined data, if any.

For more information about a PnP driver's DriverEntry routine, see Plug and Play.


Storage Filter Driver's AddDevice Routine

The PnP Manager calls the AddDevice routine of a storage filter driver when it detects a device controlled by that driver. The AddDevice routine of an SFD is similar to that of a storage class driver, except that it must not attempt to claim the device (SRB_FUNCTION_CLAIM_DEVICE).

For information about a storage class driver's AddDevice routine, see Storage Class Drivers. For general information about a PnP driver's AddDevice routine, see Plug and Play.


Handling PnP Start in a Storage Filter Driver

A storage filter driver performs device-specific initialization and sets up its device extension when the PnP Manager calls its DispatchPnP routine with a start request (IRP_MJ_PNP with IRP_MN_START_DEVICE). An SFD handles a start request in much the same way as does a storage class driver.

For information about how a storage class driver handles a start request and sets up its device extension, see Storage Class Drivers. For general information about handling a PnP start request, see Plug and Play.


Storage Filter Driver's Dispatch Routines

Like any other higher level kernel-mode driver, a storage filter driver must have one or more Dispatch routines to handle every IRP_MJ_XXX request for which the underlying storage driver supplies a Dispatch entry point. Depending on the nature of its device, the Dispatch entry point of an SFD might do one of the following for any given request:

  • For a request that requires no special handling, set up the I/O stack location in the IRP for the next lower driver, possibly call IoSetCompletionRoutine to set up its IoCompletion routine for the IRP, and pass the IRP on for further processing by lower drivers with IoCallDriver
  • For a request already handled by a storage class driver, modify the SRB in the I/O stack location of the IRP before setting up the I/O stack location, possibly set an IoCompletion routine, and pass the IRP to the next lower driver with IoCallDriver
  • Set up a new IRP with an SRB and CDB for its device, call IoSetCompletionRoutine so the SRB (and the IRP if the driver calls IoAllocateIrp or IoBuildAsynchronousFsdRequest) can be freed, and pass the IRP on with IoCallDriver

    An SFD is most likely to set up new IRPs with the major function code IRP_MJ_INTERNAL_DEVICE_CONTROL.

For requests that require no special handling, the Dispatch routine of an SFD usually calls IoSkipCurrentIrpStackLocation with an input IRP and then calls IoCallDriver with pointers to the class driver's device object and the IRP. Note that an SFD seldom sets its IoCompletion routine in IRPs that require no special handling both because a call to the IoCompletion routine is unnecessary and because it degrades I/O throughput for the driver's device(s). If an SFD does set an IoCompletion routine, it calls IoCopyCurrentIrpStackLocationToNext instead of IoSkipCurrentIrpStackLocation and then calls IoSetCompletionRoutine before calling IoCallDriver.

For requests that do require special handling, the SFD can do the following:

  1. Create a new IRP with IoBuildDeviceIoControlRequest, IoAllocateIrp, IoBuildSynchronousFsdRequest, or IoBuildAsynchronousFsdRequest, usually specifying an I/O stack location for itself.
  2. Check the returned IRP pointer for NULL and return STATUS_INSUFFICIENT_RESOURCES if an IRP could not be allocated.
  3. If the driver-created IRP includes an I/O stack location for the SFD, call IoSetNextIrpStackLocation to set up the IRP stack location pointer. Then, call IoGetCurrentIrpStackLocation to get a pointer to its own I/O stack location in the driver-created IRP and set up it up with state to be used by its own IoCompletion routine.
  4. Call IoGetNextIrpStackLocation to get a pointer to the next lower driver's I/O stack location in the driver-created IRP and set it up with the major function code IRP_MJ_SCSI and an SRB (see Storage Class Drivers).
  5. Translate data to be transferred to the device into a device-specific, nonstandard format if necessary.
  6. Call IoSetCompletionRoutine if the driver allocated any memory, such as memory for an SRB, SCSI request-sense buffer, MDL, and/or IRP with a call to IoAllocateIrp or IoBuildAsynchronousFsdRequest, or if the driver must translate data transferred from the device in a device-specific, nonstandard format.
  7. Pass the driver-created IRP to (and through) the next lower driver with IoCallDriver.

Like a storage class driver, an SFD might have BuildRequest or SplitTransferRequest routines to be called from the driver's Dispatch routine(s), or might implement the same functionality inline.

For more information about BuildRequest and SplitTransferRequest routines, see Storage Class Drivers. For more information about general requirements for Dispatch routines, see Writing Dispatch Routines.


Storage Filter Driver's IoCompletion Routines

A storage filter driver's IoCompletion routine is called when lower level drivers (port, class, and additional filter drivers, if any) have called IoCompleteRequest. The IoCompletion routine of an SFD should return STATUS_MORE_PROCESSING_REQUIRED to prevent completion processing of a driver-allocated IRP, or to retain an original IRP if the SFD will reuse the IRP before completing it.

Like any other higher level driver, the IoCompletion routine of an SFD is responsible for calling IoFreeIrp to release any IRP the driver's Dispatch routine(s) created with IoAllocateIrp or IoBuildAsynchronousFsdRequest.

Depending on its device, an SFD might supply an IoCompletion routine for IRPs it sends to the next lower driver from its Dispatch routines. In particular, a device that retrieves and processes data in a nonstandard format might require the SFD to have a TranslateDataIn routine called from its IoCompletion routine for transfer requests from such a device to system memory.

Note that such a TranslateDataIn routine would be called at IRQL DISPATCH_LEVEL and in an arbitrary thread context. Therefore, the buffer into which the driver returns data either must be located in nonpaged pool or must be locked down and accessible using mapped, nonpaged system-space virtual addresses. For more information about safely accessing user-supplied buffers at raised IRQL, see Methods for Accessing Data Buffers.

In general, a storage filter driver should supply an IoCompletion routine with the same functionality as a class driver's IoCompletion routine for IRPs that the filter driver sets up with SRBs and CDBs. Consequently, a storage filter driver might have any or all of the ReleaseQueue, InterpretRequestSense, or RetryRequest routines that can be called from a storage class driver's IoCompletion routine(s).

For more information about InterpretRequestSense, RetryRequest, and ReleaseQueue routines, see Storage Class Drivers. For more information about general requirements for IoCompletion routines, see Using IoCompletion Routines.


Handling PnP Paging Requests

A storage filter driver must handle PnP paging requests (IRP_MJ_PNP with IRP_MN_DEVICE_USAGE_NOTIFICATION and Parameters.UsageNotification.Type set to DeviceUsageTypePaging) if the function driver it is filtering handles this IRP.

The following items must be added to the DeviceExtension of the Filter DO

ULONG PagingCount;

KEVENT PagingCountEvent;

Upon receiving PnP paging requests a storage filter driver must update both the PagingCount and the setting of the DO_POWER_PAGABLE bit in the Filter DO. The timing of the update of the DO_POWER_PAGABLE bit depends on whether the bit is being set or cleared. If the IRP indicates that the bit should be set, then the filter driver must set it before forwarding the IRP down the driver stack. But if the IRP indicates that the bit should be cleared, then the filter driver should not clear the bit right away. It must first forward the IRP then wait on status from the lower drivers and clear the bit only if the lower drivers return STATUS_SUCCESS.

The following traces the flow of actions taken by the storage filter driver. Please refer to the pseudo code sample immediately beneath the outline to see a representation in C code of this outline:

  1. Verify that the device has been started. If not, fail with STATUS_DEVICE_NOT_READY.
  2. Synchronize on the PagingCountEvent (KeWaitForSingleObject( PagingCountEvent, …)).
  3. If removing the last paging device ( (! Parameters.UsageNotification.InPath) &&
    (PagingCount == 1) ) then
    1. Set a local boolean to TRUE, and
    2. If the DO_POWER_INRUSH bit is not set in the Filter DO, then set the DO_POWER_PAGABLE bit.

      Note on why the DO_POWER_PAGABLE bit must be set on the way down and not on the way up:

      The Power requirements state that if any lower device object sets the DO_POWER_PAGABLE bit, all higher-level drivers must do the same. If the filter driver fails to set the DO_POWER_PAGABLE bit prior to sending the paging request IRP down the stack, it could violate this condition as follows:

      Suppose the filter driver does not set the DO_POWER_PAGABLE bit in its Filter DO before forwarding the paging request IRP to the drivers beneath it in the driver stack. Next suppose that a lower driver sets the DO_POWER_PAGABLE bit in its own DO. Finally, suppose that prior to the completion of the IRP by the filter driver a power IRP occurs. At that point, the DO_POWER_PAGABLE bit would be cleared in the Filter DO but would be set in the DO of the lower-level driver, causing a system crash.

      It is safe to set the DO_POWER_PAGABLE bit before forwarding a paging request down the stack, because there is no longer an active paging file on the filter driver's device, and therefore no more paging I/O will occur on it. If the request to remove this paging file succeeds, the filter driver will be done. If the request fails, the filter driver can restore the original state of its flags by simply clearing the DO_POWER_PAGABLE bit prior to completing the IRP. Since the paging file requests are serialized, there is no danger that some other thread will have modified this bit since the filter driver last altered it.

  4. Synchronously forward the IRP to the lower drivers.
  5. If the IRP completes successfully, then
    1. Call IoAdjustPagingPathCount(&PagingCount, Parameters.UsageNotification.InPath) to increment or decrement the PagingCount. IoAdjustPagingPathCount does an InterlockedIncrement or InterlockedDecrement of the PagingCount depending on the value in Parameters.UsageNotification.InPath. A value of TRUE indicates that a paging file is being added, so increment the PagingCount; a value of FALSE indicates that a paging file is being removed, so decrement the PagingCount.
    2. If Parameters.UsageNotification.InPath is TRUE, a paging file is being added, so clear the DO_POWER_PAGABLE bit.
  6. Else if the IRP fails, then
    1. Check the local boolean to see if DO_POWER_PAGABLE was set in the Filter DO on the way down
    2. If DO_POWER_PAGABLE was set on the way down, clear it.
  7. End Synchronization (KeSetEvent(PagingCountEvent, …))

Pseudo code Example

The sections marked by letters (//A, //B, etc.) in the following code sample map to the letters of the outline above.

case DeviceUsageTypePaging: {
    BOOLEAN setPageable = FALSE;
    BOOLEAN addPageFile = irpStack ->
                          Parameters.UsageNotification.InPath;

    // A
    if((addPageFile) &&
        (extension -> CurrentPnpState !=
        IRP_MN_START_DEVICE)) {
            status = STATUS_DEVICE_NOT_READY;
            break;
        }
    // B
    KeWaitForSingleObject(&commonExtension -> PagingCountEvent,
                                    Executive, KernelMode,
                                    FALSE, NULL);
    // C
    if (!addPageFile && commonExtension -> PagingCount == 1 ) {
        // The last paging file is no longer active.
        // Set the DO_POWER_PAGABLE bit before
        // forwarding the paging request down the
        // stack.
        if (!(DeviceObject->Flags & DO_POWER_INRUSH)) {
            DeviceObject->Flags |=             DO_POWER_PAGABLE;
            setPageable = TRUE;
        )
    )
    // D
        status = ForwardIrpSynchronous(commonExtension, Irp);
    // E
        if (NT_SUCCESS(status)) {
            IoAdjustPagingPathCount(&commonExtension -> PagingCount,
                                    addPageFile);
        if (addPageFile && commonExtension -> PagingCount == 1) {
            // Once the lower device objects have
            // succeeded the addition of the paging
            // file, it is illegal to fail the
            // request. It is also the time to
            // clear the Filter DO's
            //DO_POWER_PAGABLE flag.

            DeviceObject->Flags &= ~DO_POWER_PAGABLE;
            }
        } else {
    // F
        if (setPageable == TRUE) {
            DeviceObject->Flags &= ~DO_POWER_PAGABLE;
            setPageable = FALSE;
        }
    }
    // G
        KeSetEvent(&commonExtension->PagingCountEvent,
                                    IO_NO_INCREMENT, FALSE);
                                    break;
    }


ScsiPort Routines

An OS-specific SCSI port driver provides ScsiPort Xxx routines to support OS-independent SCSI miniport drivers that are linked with a Microsoft-supplied, OS-specific SCSI port driver.

The SCSI port driver is a kernel-mode dynamic-link library.

References for the ScsiPort Xxx routines are in alphabetical order.


ScsiPortCompleteRequest

ScsiPortCompleteRequest completes all of the active requests for the given SCSI bus, controller, or LU, including a request being processed by the calling miniport routine.

VOID
  ScsiPortCompleteRequest(
    IN PVOID  HwDeviceExtension,
    IN UCHAR  PathId,
    IN UCHAR  TargetId,
    IN UCHAR  Lun,
    IN UCHAR  SrbStatus
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-HBA storage area.
PathId
Identifies the SCSI bus; SP_UNTAGGED indicates all buses controlled by the HBA.
TargetId
Identifies the target controller or device on the given bus(es); SP_UNTAGGED indicates all targets on the bus.
Lun
Identifies the logical unit for the given target controller or device; SP_UNTAGGED indicates all logical units for the given target controller(s) on the given bus(es).
SrbStatus
Specifies the completion status to be set in the SrbStatus member of each SRB.

Return Value

None

Comments

ScsiPortCompleteRequest can be called to complete outstanding requests after a bus reset, a device reset, or an abort, rather than calling ScsiPortNotification for each outstanding request individually. After calling ScsiPortCompleteRequest, do not doubly complete by also calling ScsiPortNotification individually for each request.

See Also

SCSI_REQUEST_BLOCK, ScsiPortNotification


ScsiPortConvertPhysicalAddressToUlong

ScsiPortConvertPhysicalAddressToUlong truncates a SCSI_PHYSICAL_ADDRESS to a ULONG.

ULONG
  ScsiPortConvertPhysicalAddressToUlong(
    IN SCSI_PHYSICAL_ADDRESS  Address
    );

Parameters

Address
Specifies a value of type SCSI_PHYSICAL_ADDRESS.

Return Value

ScsiPortConvertPhysicalAddressToUlong returns the low-order part of the given SCSI_PHYSICAL_ADDRESS value.

A miniport driver cannot call this routine to truncate a 64-bit physical address. Such addresses should be used as quadword values, which contain all 64 bits.

See Also

ACCESS_RANGE, ScsiPortGetDeviceBase, ScsiPortGetPhysicalAddress


ScsiPortConvertUlongToPhysicalAddress

ScsiPortConvertUlongToPhysicalAddress extends a given ULONG address into a value of type SCSI_PHYSICAL_ADDRESS.

SCSI_PHYSICAL_ADDRESS
  ScsiPortConvertUlongToPhysicalAddress(
    IN ULONG  UlongAddress
    );

Parameters

UlongAddress
Specifies a value of type ULONG.

Return Value

ScsiPortConvertUlongToPhysicalAddress returns the converted SCSI_PHYSICAL_ADDRESS.

See Also

ACCESS_RANGE, ScsiPortGetDeviceBase, ScsiPortGetVirtualAddress


ScsiPortFlushDma

ScsiPortFlushDma flushes any data cached in the system DMA controller at the end of a transfer or terminates a system DMA transfer.

VOID
  ScsiPortFlushDma(
    IN PVOID  DeviceExtension
    );

Parameters

DeviceExtension
Points to the miniport driver's per-HBA storage area.

Return Value

None

Comments

Only miniport drivers of slave HBAs that use a system DMA controller call this routine.

ScsiPortFlushDma must be called after a slave DMA transfer operation is completed but before the SRB is completed or the next call is made to ScsiPortIoMapTransfer for the current buffer.

ScsiPortFlushDma also must be called after ScsiPortIoMapTransfer to cancel a DMA operation, even if no transfer has occurred and the driver's HwScsiDmaStarted routine has not yet been called.

See Also

HwScsiDmaStarted, ScsiPortIoMapTransfer


ScsiPortFreeDeviceBase

ScsiPortFreeDeviceBase frees a range of device I/O or memory space addresses previously mapped into the system address space with ScsiPortGetDeviceBase.

VOID
  ScsiPortFreeDeviceBase(
    IN PVOID  HwDeviceExtension,
    IN PVOID  MappedAddress
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-HBA storage area.
MappedAddress
Points to the base address of the range to be freed. This address must be the same as that returned by ScsiPortGetDeviceBase.

Return Value

None

Comments

If a miniport driver's HwScsiFindAdapter routine determines that the driver does not need a particular mapped base address for an adapter, it must release the mapping by calling this routine. For example, when a miniport determines there are no supported HBAs on a particular I/O bus, it must call ScsiPortFreeDeviceBase with each mapped address returned by ScsiPortGetDeviceBase, if any calls to this routine were made.

ScsiPortFreeDeviceBase can be called only from miniport driver's HwScsiFindAdapter routine. Calls from other miniport routines will result in system failure or incorrect operation for the caller.

See Also

HwScsiFindAdapter, ScsiPortGetDeviceBase


ScsiPortGetBusData

ScsiPortGetBusData returns bus-type-specific configuration information that a miniport's HwScsiFindAdapter routine might use to determine whether it supports a particular adapter on a particular I/O bus, and to configure the HBA if it does.

ULONG
  ScsiPortGetBusData(
    IN PVOID  DeviceExtension,
    IN ULONG  BusDataType,
    IN ULONG  SystemIoBusNumber,
    IN ULONG  SlotNumber,
    IN PVOID  Buffer,
    IN ULONG  Length
    );

Parameters

DeviceExtension
Points to the miniport driver's per-HBA storage area.
BusDataType
Specifies the type of bus-specific configuration data to be returned. Currently, this value can be one of the following: Cmos, EisaConfiguration, Pos, or PCIConfiguration. However, additional types of bus configuration will be supported in the future. The upper bound on the types supported is always MaximumBusDataType.
SystemIoBusNumber
Specifies the system-assigned number of the I/O bus. The miniport driver's HwScsiFindAdapter routine obtains this value from the input PORT_CONFIGURATION_INFORMATION SystemIoBusNumber member.
SlotNumber
Specifies the logical slot number or location of the device.

If PCIConfiguration is specified as the BusDataType, this parameter must be specified as a PCI_SLOT_NUMBER-type value.

Buffer
Points to a buffer or area to which the configuration data is returned or, if the given Length is zero, points to a location to which the OS-specific port driver returns a pointer to a buffer that it allocates.
Length
Specifies the maximum number of bytes to return at Buffer, or zero if the caller requires the OS-specific port driver to allocate a buffer to contain the data.

Return Value

ScsiPortGetBusData returns the number of bytes of configuration information it stored in the buffer.

When the input BusDataType is PCIConfiguration, ScsiPortGetBusData can return either of the following values to indicate an error:

Value | Meaning
0 (zero) | The PCI bus does not exist.
2 | The PCI bus exists, but there is no device at the given PCI SlotNumber. The Buffer contains the value PCI_INVALID_VENDOR_ID at the PCI_COMMON_CONFIG VendorId member.

Comments

ScsiPortGetBusData can be called only from a miniport driver's HwScsiFindAdapter routine or from HwScsiAdapterControl when the control type is ScsiSetRunningConfig. Calls from other miniport routines will result in system failure or incorrect operation for the caller.

Configuration data returned by ScsiPortGetBusData is valid only until the miniport calls ScsiPortGetBusData again. As soon as the caller's HwScsiFindAdapter routine returns control, any returned configuration data becomes invalid.

See Also

PCI_COMMON_CONFIG, PCI_SLOT_NUMBER, PORT_CONFIGURATION_INFORMATION, HwScsiFindAdapter


ScsiPortGetDeviceBase

ScsiPortGetDeviceBase returns a mapped, logical base address that can be used to communicate with an HBA. Every miniport driver must pass mapped, logical access range addresses to the ScsiPort..Port Xxx and ScsiPort..Register Xxx routines to communicate with its HBA(s).

PVOID
  ScsiPortGetDeviceBase(
    IN PVOID  HwDeviceExtension,
    IN INTERFACE_TYPE  BusType,
    IN ULONG  SystemIoBusNumber,
    IN SCSI_PHYSICAL_ADDRESS  IoAddress,
    IN ULONG  NumberOfBytes,
    IN BOOLEAN  InIoSpace,
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-HBA storage area. Miniports usually store their mapped access ranges addresses for the HBA in this extension.
BusType
Specifies the interface type of the I/O bus on which the HBA is connected. The miniport's HwScsiFindAdapter routine obtains the value for this parameter from the AdapterInterfaceType member of the input PORT_CONFIGURATION_INFORMATION.
SystemIoBusNumber
Specifies the system-assigned number of the I/O bus on which the HBA is connected. The HwScsiFindAdapter routine obtains the value for this parameter from the SystemIoBusNumber member of the input PORT_CONFIGURATION_INFORMATION.
IoAddress
Specifies the bus-relative base address of a range used by the HBA. The HwScsiFindAdapter routine obtains the value for this parameter from one of the AccessRanges elements in the PORT_CONFIGURATION_INFORMATION if the port driver supplies range-configuration information. Otherwise, this address can be a value returned by ScsiPortGetBusData or a miniport-supplied default value. Avoid using a base address of zero because its successful return status can conflict with the error status (NULL).
NumberOfBytes
Specifies the size in bytes of the range that the mapping should cover. The HwScsiFindAdapter routine obtains the value of this parameter from the same AccessRanges element as IoAddress if the port driver supplies range configuration information. Otherwise, this value can be returned by ScsiPortGetBusData or a miniport-supplied default. In any case, the driver must not access the hardware outside of the returned, mapped range.
InIoSpace
TRUE indicates the range to be mapped is in I/O space, and the miniport will pass mapped addresses in this range to the ScsiPort...Port Xxx to communicate with the HBA. The HwScsiFindAdapter routine obtains the value of this parameter from the same AccessRanges element as IoAddress. Note that a miniport driver must invert the value of the InMemorySpace member in an ACCESS_RANGE-type element before it is passed to ScsiPortGetDeviceBase as the InIoSpace argument.

Return Value

ScsiPortGetDeviceBase returns a mapped logical base address for the given IoAddress if it successfully mapped the given range from IoAddress to NumberOfBytes. If a given range cannot be mapped, ScsiPortGetDeviceBase returns NULL.

Comments

NT-based operating system platforms can have several types of I/O buses and several I/O buses of the same type. Moreover, the HAL can map I/O space to memory in some platforms.

Consequently, a miniport driver cannot use bus-relative access range addresses to communicate with its HBA. To maintain miniport driver portability across CISC- and RISC-based machines, the addresses they use to access HBAs must be translated with ScsiPortGetDeviceBase.

Every miniport driver must use system-space logical range addresses, mapped by ScsiPortGetDeviceBase, to communicate with its HBA(s). Calls to the ScsiPort...Port/Register Xxx routines require these mapped, logical addresses.

ScsiPortGetDeviceBase can be called several times, depending on how many HBAs the miniport driver supports and how many access ranges each HBA requires. Each mapped range corresponds to a range of bus-relative device addresses specified in an ACCESS_RANGE-type element of the AccessRanges array.

ScsiPortGetDeviceBase can be called only from a miniport driver's HwScsiFindAdapter routine or from HwScsiAdapterControl when the control type is ScsiSetRunningConfig. Calls from other miniport routines will result in system failure or in incorrect operation for the caller.

Follow these guidelines for calling ScsiPortGetDeviceBase:

  • If HwScsiFindAdapter is using a miniport-supplied set of default bus-relative access ranges or values returned by ScsiPortGetBusData, it should call ScsiPortValidateRange before attempting to call ScsiPortGetDeviceBase.
  • If HwScsiFindAdapter determines that a particular HBA is not one that the miniport supports, it must call ScsiPortFreeDeviceBase to release the mapping(s) it set up to communicate with that HBA.

The logical address returned by ScsiPortGetDeviceBase should be used for all subsequent references made to the hardware but should not be added to any AccessRanges specification in the PORT_CONFIGURATION_INFORMATION. Miniport driver writers should make no assumptions about how many bits are used in the logical base address returned by ScsiPortGetDeviceBase.

See Also

ACCESS_RANGE, HwScsiFindAdapter, ScsiPortFreeDeviceBase, ScsiPortGetBusData, ScsiPortRead Xxx, ScsiPortValidateRange, ScsiPortWrite Xxx, PORT_CONFIGURATION_INFORMATION


ScsiPortGetLogicalUnit

ScsiPortGetLogicalUnit returns a pointer to the miniport's per-LU storage area for a given peripheral.

PVOID
  ScsiPortGetLogicalUnit(
    IN PVOID  HwDeviceExtension,
    IN UCHAR  PathId,
    IN UCHAR  TargetId,
    IN UCHAR  Lun
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-HBA storage area.
PathId
Identifies the SCSI bus.
TargetId
Identifies the target controller or device on the bus.
Lun
Identifies the logical unit number of the target device, for which the miniport wants access to its per-LU storage area.

Return Value

ScsiPortGetLogicalUnit returns a pointer to the miniport's storage area for the requested logical unit. If the OS-specific port driver considers this logical unit to be nonexistent, it returns NULL.

Comments

ScsiPortGetLogicalUnit is irrelevant if the miniport's DriverEntry routine specified zero for the LuExtensionSize in the HW_INITIALIZATION_DATA when it called ScsiPortInitialize. Otherwise, the OS-specific port driver allocates and initializes with zeros a set of LU extensions of the specified size for the miniport driver to use.

Per-LU storage can be used to store data relevant to a particular peripheral, such as saved data pointers. To access this area, the miniport calls ScsiPortGetLogicalUnit when the driver is maintaining information about the state of or current operation for any particular peripheral.

The OS-specific port driver can consider a logical unit to be nonexistent if there is no active request for that logical unit and the device has never been successfully selected.

See Also

DriverEntry, HW_INITIALIZATION_DATA, ScsiPortInitialize, ScsiPortMoveMemory


ScsiPortGetPhysicalAddress

ScsiPortGetPhysicalAddress converts a given virtual address range to a physical address range for a DMA operation.

SCSI_PHYSICAL_ADDRESS
  ScsiPortGetPhysicalAddress(
    IN PVOID  HwDeviceExtension,
    IN PSCSI_REQUEST_BLOCK  Srb  OPTIONAL,
    IN PVOID  VirtualAddress,
    OUT ULONG  *Length
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-HBA storage area.
Srb
Points to the SCSI request block if the VirtualAddress to be converted comes from that SRB's DataBuffer member or, possibly, from the SenseInfoBuffer. Otherwise, this parameter must be NULL.
VirtualAddress
Points to the base virtual address to be converted. If this virtual address falls within the range for an SRB-supplied DataBuffer, the caller also must provide the Srb pointer.
Length
Returns the number of bytes mapped, starting at the returned physical address.

Return Value

ScsiPortGetPhysicalAddress returns the corresponding physical address for a given VirtualAddress. If the given address cannot be converted, it returns NULL.

Comments

Miniport drivers of busmaster HBAs call ScsiPortGetPhysicalAddress to get mapped physical address ranges to be used during DMA operations. For example, ScsiPortGetPhysicalAddress can be used to build a scatter/gather list for data transfers that span pages. Note that the Length returned can be greater than the size of the DataBuffer in a given SRB.

If a nonNULL Srb is passed, the VirtualAddress either must be within the range of the DataBuffer of the SRB or must be a pointer from the SenseInfoBuffer. Otherwise, the given VirtualAddress must be in the miniport's uncached extension, the SrbExtension, or the SenseInfoBuffer.

A miniport driver can call ScsiPortGetPhysicalAddress to translate an extension address only if that miniport's DriverEntry routine set NeedPhysicalAddresses to TRUE in the HW_INITIALIZATION_DATA when it called ScsiPortInitialize.

Due to constraints on some buses, such as ISA, the address returned by this routine is not guaranteed to match the address returned by an analogous outside routine (such as MmGetPhysicalAddress). A miniport driver should call only ScsiPort Xxx routines to be portable.

See Also

HW_INITIALIZATION_DATA, DriverEntry, ScsiPortGetUncachedExtension, ScsiPortGetVirtualAddress, SCSI_REQUEST_BLOCK


ScsiPortGetSrb

ScsiPortGetSrb returns a pointer to an active SCSI request for a particular logical unit.

PSCSI_REQUEST_BLOCK
  ScsiPortGetSrb(
    IN PVOID  DeviceExtension,
    IN UCHAR  PathId,
    IN UCHAR  TargetId,
    IN UCHAR  Lun,
    IN LONG  QueueTag
    );

Parameters

DeviceExtension
Points to the miniport driver's per-HBA storage area.
PathId
Identifies the SCSI bus.
TargetId
Identifies the target controller or device on the bus.
Lun
Identifies the logical unit number of the target device.
QueueTag
Specifies the queue tag if the miniport handles tagged requests; SP_UNTAGGED indicates that the request is not tagged.

Return Value

ScsiPortGetSrb returns a pointer to a request for the specified logical unit. If there is no outstanding request for the given peripheral or if the QueueTag value is invalid, it returns NULL.

See Also

SCSI_REQUEST_BLOCK


ScsiPortGetUncachedExtension

ScsiPortGetUncachedExtension allocates memory that can be used by both the CPU and a busmaster HBA for DMA or for shared data.

PVOID
  ScsiPortGetUncachedExtension(
    IN PVOID  HwDeviceExtension,
    IN PPORT_CONFIGURATION_INFORMATION  ConfigInfo,
    IN ULONG  NumberOfBytes
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-HBA storage area.
ConfigInfo
Specifies information about the HBA's DMA capabilities. The following members must be filled in: DmaChannel or DmaPort, DmaWidth, DmaSpeed, MaximumTransferLength, ScatterGather, Master set to TRUE, NumberOfPhysicalBreaks, AdapterInterfaceType, Dma32BitAddresses, SystemIoBusNumber, AutoRequestSense, and SrbExtensionSize.

Members that are not pertinent to the HBA, such as DmaChannel for an EISA busmaster adapter, must be left as is.

NumberOfBytes
Indicates the size in bytes of the uncached extension to be allocated.

Return Value

ScsiPortGetUncachedExtension returns a virtual address pointer to the uncached extension. If it cannot allocate the requested memory, it returns NULL.

Comments

ScsiPortGetUncachedExtension can be called only from miniport driver's HwScsiFindAdapter routine and only for a busmaster HBA. Calls from other miniport driver routines will result in system failure or incorrect operation for the caller.

Because high-end machines have caches and large memories, any memory to be shared between an HBA and the CPU must be specially allocated. Mailboxes or I/O request queues in system memory are examples of this type of shared memory.

A miniport must set SrbExtensionSize before calling ScsiPortGetUncachedExtension to change the size of its per-request storage based on NumberOfPhysicalBreaks.

The HwScsiFindAdapter routine can call ScsiPortGetUncachedExtension only once for each busmaster HBA the miniport driver supports.

To obtain the physical address for the uncached extension that the HBA can use, call ScsiPortGetPhysicalAddress.

See Also

PORT_CONFIGURATION_INFORMATION, HwScsiFindAdapter, ScsiPortGetPhysicalAddress


ScsiPortGetVirtualAddress

ScsiPortGetVirtualAddress returns a virtual address associated with a physical address if the physical address was obtained by a call to ScsiPortGetPhysicalAddress.

PVOID
  ScsiPortGetVirtualAddress(
    IN PVOID  HwDeviceExtension,
    IN SCSI_PHYSICAL_ADDRESS  PhysicalAddress
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-HBA storage area.
PhysicalAddress
Specifies the physical address to be mapped. This value must have been returned by ScsiPortGetPhysicalAddress and must be from an uncached device extension or SRB extension.

Return Value

ScsiPortGetVirtualAddress returns a mapped pointer for the given input address. If the PhysicalAddress value is invalid, it returns NULL.

See Also

ScsiPortGetUncachedExtension, ScsiPortGetPhysicalAddress


ScsiPortInitialize

For a legacy (nonPlug and Play) miniport driver, ScsiPortInitialize sets up the PORT_CONFIGURATION_INFORMATION structure and calls the miniport driver's HwScsiFindAdapter routine. ScsiPortInitialize also sets up system objects and resources on behalf of miniport drivers. For a Plug and Play miniport driver, ScsiPortInitialize stores the miniport's initialization data for future use.

ULONG
  ScsiPortInitialize(
    IN PVOID  Argument1,
    IN PVOID  Argument2,
    IN struct _HW_INITIALIZATION_DATA  *HwInitializationData,
    IN PVOID  HwContext  OPTIONAL
    );

Parameters

Argument1
Is the first pointer with which the operating system called the miniport's DriverEntry routine.
Argument2
Is the second pointer with which the operating system called DriverEntry.
HwInitializationData
Points to the initialization and configuration information supplied by DriverEntry.
HwContext
Is the address of a context value to be passed to the miniport's HwScsiFindAdapter routine. Only legacy miniport drivers that scan the bus for HBAs rather than receiving configuration information from the port driver can use this parameter to store state between calls to HwScsiFindAdapter.

Return Value

ScsiPortInitialize returns a status value that is used as the return value from the miniport's DriverEntry routine.

Comments

Every miniport driver's DriverEntry routine must call ScsiPortInitialize after the miniport has first zeroed and then set up the HW_INITIALIZATION_DATA.

If a miniport driver can support HBAs on different types of I/O buses, such as both Isa and MicroChannel type I/O buses, the miniport should call ScsiPortInitialize for each supported interface type.

A miniport driver that calls ScsiPortInitialize more than once should check the value returned by ScsiPortInitialize at each call and save the lowest value for all its calls. The DriverEntry routine must return the lowest value when it returns control to the system. Miniport driver writers can make no assumptions about the values returned by ScsiPortInitialize.

See Also

DriverEntry, HW_INITIALIZATION_DATA, HwScsiFindAdapter


ScsiPortIoMapTransfer

ScsiPortIoMapTransfer sets up the system DMA controller for a miniport driver to transfer data through a slave HBA.

VOID
  ScsiPortIoMapTransfer(
    IN PVOID  HwDeviceExtension,
    IN PSCSI_REQUEST_BLOCK  Srb,
    IN ULONG  LogicalAddress,
    IN ULONG  Length
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-HBA storage area.
Srb
Point to the SCSI request block for the DMA transfer.
LogicalAddress
Specifies the starting address for the transfer operation. This value can be the base address of a buffer into which or from which data is to be transferred. This value can be an offset within such a buffer.
Length
Specifies the number of bytes to be transferred.

Return Value

None

Comments

Only miniport drivers of HBAs that use a system DMA controller (slave DMA) call ScsiPortIoMapTransfer. This routine must be called before such a miniport sets up its HBA to transfer data. The range specified by the LogicalAddress and Length must be within the buffer described by the given SRB.

After the OS-specific port driver programs the system DMA controller, it calls the miniport driver's HwScsiDmaStarted routine. HwScsiDmaStarted should program the HBA to begin the data transfer. Note that an HBA can interrupt between the miniport's call to ScsiPortIoMapTransfer and the OS-specific port driver's call to the miniport's HwScsiDmaStarted routine.

See Also

HwScsiDmaStarted, ScsiPortFlushDma


ScsiPortLogError

ScsiPortLogError logs errors to the system event log when a miniport driver or its HBA detects a SCSI error condition.

VOID
  ScsiPortLogError(
    IN PVOID  HwDeviceExtension,
    IN PSCSI_REQUEST_BLOCK  Srb  OPTIONAL,
    IN UCHAR  PathId,
    IN UCHAR  TargetId,
    IN UCHAR  Lun,
    IN ULONG  ErrorCode,
    IN ULONG  UniqueId
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-HBA storage area.
Srb
Points to a SCSI request block if one is associated with the error. Otherwise, this parameter is NULL.
PathId
Identifies the SCSI bus.
TargetId
Identifies the target controller or device on the bus.
Lun
Identifies the logical unit number of the target device.
ErrorCode
Specifies an error code indicating one of the following values as the type of error:
Value | Meaning
SP_BAD_FW_ERROR | Indicates the driver has detected bad or old firmware. The device will not be used.
SP_BAD_FW_WARNING | Indicates the driver has detected a card with old or bad firmware, which can result in reduced performance or functionality.
SP_BUS_PARITY_ERROR | Indicates a SCSI bus parity error was detected.
SP_BUS_TIME_OUT | Indicates a SCSI bus connection to a logical unit timed out.
SP_INTERNAL_ADAPTER_ERROR | Indicates an internal HBA error was detected.
SP_INVALID_RESELECTION | Indicates a logical unit reselected unexpectedly or with an invalid queue tag.
SP_IRQ_NOT_RESPONDING | Indicates the HBA is not interrupting when expected.
SP_PROTOCOL_ERROR | Indicates the miniport driver detected a SCSI bus protocol error.
SP_REQUEST_TIMEOUT | Indicates an operation to the controller has timed out.
SP_UNEXPECTED_DISCONNECT | Indicates that a target disconnected unexpectedly.

UniqueId
Specifies a unique identifier for the error. This value differentiates the current error from other errors with the same ErrorCode. For some miniport drivers, this identifies the line of code where the error was detected. For others, it is additional information returned by the HBA.

Return Value

None

Comments

A miniport driver should log all real hardware errors. However, it should not log common operational errors, such as selection time outs or bus resets.

See Also

ScsiPortNotification


ScsiPortMoveMemory

ScsiPortMoveMemory copies data from one location to another.

VOID
  ScsiPortMoveMemory(
    IN PVOID  WriteBuffer,
    IN PVOID  ReadBuffer,
    IN ULONG  Length
    );

Parameters

WriteBuffer
Points to the destination buffer.
ReadBuffer
Points to the source buffer.
Length
Specifies how many bytes to transfer from ReadBuffer to WriteBuffer.

Return Value

None

Comments

ScsiPortMoveMemory can be called if a miniport driver needs to copy data from one system-allocated area to another. For example, a miniport might call ScsiPortMoveMemory to copy pertinent SRB values into the driver's SRB extension.

Each of the given buffer areas must be at least sizeof(Length).


ScsiPortNotification

ScsiPortNotification tells the OS-specific port driver of certain events, such as when a miniport driver completes a request or is ready to start another SRB, as well as when the HBA indicates certain SCSI error conditions that occurred during an operation.

VOID
  ScsiPortNotification(
    IN SCSI_NOTIFICATION_TYPE  NotificationType,
    IN PVOID  HwDeviceExtension,
      /* Additional parameters, as required by the given NotificationType */
    /* for RequestComplete  add: */
      IN PSCSI_REQUEST_BLOCK  Srb,
    /* for NextLuRequest  add: */
      IN UCHAR  PathId,
      IN UCHAR  TargetId,
      IN UCHAR  Lun,
    /* for CallEnableInterrupts or CallDisableInterrupts add: */
      IN PHW_INTERRUPT  HwScsiXxxInterruptsCallback,
    /* for RequestTimerCall add: */
      IN PHW_TIMER  HwScsiTimer,
      IN ULONG  MiniportTimerValue,
    /* for BusChangeDetected add: */
      IN UCHAR  PathId
    /* for WMIEvent add: */
      IN PVOID  WMIEvent,
      IN UCHAR  PathID,
      /* if PathId != 0xFF also add: */
        IN UCHAR  TargetId,
        IN UCHAR  Lun,
    /* for WMIReregister, add: */
      IN UCHAR  PathId,
      /* if PathId != 0xFF also add: */
        IN UCHAR  TargetId,
        IN UCHAR  Lun,
    );

Parameters

NotificationType
Specifies the type of notification, which can be one of the following:
Notification Type | Description
RequestComplete | Indicates the given Srb has finished. If this value is set, ScsiPortNotification requires one additional parameter: the address of the SRB. After this notification, the OS-specific port driver owns the request. The miniport driver must not access the Srb, and it must not pass the Srb to another routine (such as ScsiPortLogError).
NextRequest | Indicates the miniport driver is ready for another request to a target that is not currently busy. This notification should be sent by the miniport as soon as the driver is ready for another request. Usually, this notification is sent from the HwScsiStartIo routine but, sometimes, from the HwScsiInterrupt (or HwScsiEnableInterruptsCallback) routine.
NextLuRequest | Indicates that the HBA is ready for another request for the specified logical unit. If this value is set, ScsiPortNotification requires three additional parameters: (1) the path ID, (2) the target ID, and (3) the logical unit number. This value should be used only if the HBA can queue multiple requests and support auto request sense or tagged queuing.
ResetDetected | Indicates that the HBA has detected a reset on the SCSI bus. After this notification, the miniport driver is still responsible for completing any active requests. The SCSI port driver will manage all required bus-reset delays.
CallEnableInterrupts | Indicates that the miniport driver requires the OS-specific port driver to call the miniport's HwScsiEnableInterruptsCallback routine. If this value is set, ScsiPortNotification requires an additional parameter: the entry point for the HwScsiEnableInterruptsCallback. The miniport's HwScsiInterrupt routine makes this call, after disabling interrupts on the HBA, to defer some interrupt-driven I/O processing if the HBA requires polling or stalling in the ISR. While the callback runs, system interrupts remain enabled but the miniport driver's HwScsiInterrupt routine will not be called. The HwScsiEnableInterruptsCallback is responsible for completing the deferred I/O processing and for calling ScsiPortNotification again with CallDisableInterrupts and the miniport's HwScsiDisableInterruptsCallback entry point.
CallDisableInterrupts | Indicates that the miniport driver requires the OS-specific port driver to call the miniport's HwScsiDisableInterruptsCallback routine. If this value is set, ScsiPortNotification requires an additional parameter: the entry point for the HwScsiDisableInterruptsCallback. While this callback runs, it cannot be preempted by an interrupt except from a device with a higher priority interrupt than the HBA. In this callback, the miniport re-enables interrupts on the HBA.
RequestTimerCall | Indicates that the miniport requires the OS-specific port driver to call the miniport's HwScsiTimer routine in the requested number of microseconds. If this value is set, ScsiPortNotification requires two additional parameters: (1) the entry point for the miniport's HwScsiTimer routine, and (2) a MiniportTimerValue interval, in microseconds. Note that the resolution of the system timer is approximately 10 milliseconds.
BusChangeDetected | Indicates that a target device might have been added or removed from a dynamic bus. If this value is set, ScsiPortNotification requires an additional parameter: the path ID of the bus on which the change was detected. After this notification, the port driver re-enumerates the bus by issuing INQUIRY commands. Bus enumeration is timeconsuming and ties up the bus, so a miniport should not send this notification unnecessarily
WMIEvent | Indicates that the miniport has detected an event for which one or more WMI data consumers is registered. If this value is set, ScsiPortNotification requires at least three additional arguments: (1) a pointer to a WMI event structure, (2) the size of the event structure, and (3) the path ID of the target device if the event originated from a device, or 0xFF if the event originated from the adapter. If (3) is a path ID, ScsiPortNotification requires two additional arguments: (4) the target ID, and (5) the logical unit number (LUN) of the target device.
WMIReregister | Indicates that the miniport has changed the data items or the number of instances of a given data block previously registered by calling IoWMIRegistrationControl. If WMIReregister is set, ScsiPortNotification requires at least two additional arguments: (1) the path ID of the target device to reregister that device, or 0xFF to reregister the adapter. If (1) is a path ID, ScsiPortNotification requires two additional arguments: (2) the target ID, and (3) the logical unit number (LUN) of the target device.

HwDeviceExtension
Points to the miniport driver's per-HBA storage area.

Return Value

None

Comments

Every miniport driver must call ScsiPortNotification twice for each call to the miniport's HwScsiStartIo routine with an SRB that the miniport completes successfully. First, the miniport calls ScsiPortNotification with the NotificationType NextRequest or with NextLuRequest if the miniport supports tagged queuing or multiple requests per LU. Then, the miniport calls ScsiPortNotification with the NotificationType RequestComplete and the request that it has just satisfied.

A miniport's HwScsiInterrupt routine is most likely to call ScsiPortNotification with the NotificationType ResetDetected.

If an HBA requires the miniport to use more than a millisecond processing interrupt-driven I/O operations, its HwScsiInterrupt routine should disable interrupts on the HBA and call ScsiPortNotification with CallEnableInterrupts and a driver-supplied HwScsiEnableInterruptsCallback routine. This routine, in turn, calls ScsiPortNotification with CallDisableInterrupts and the corresponding driver-supplied HwScsiDisableInterruptsCallback.

A miniport that is registered as a WMI data provider can call ScsiPortNotification with WMIEvent to post an event for which it has previously received an enable request. The port driver queues the event in the interrupt data area of the miniport's device extension for later processing at a lower IRQL. Since only a limited number of events can be queued at one time, the miniport driver should use WMIEvent to signal exceptional rather than routine conditions, and it should give the port driver time to get back to DPC level between postings, to prevent events from being lost.

See Also

HwScsiTimer, HwScsiDisableInterruptsCallback, HwScsiEnableInterruptsCallback, ScsiPortCompleteRequest, IoWMIRegistrationControl


ScsiPortQuerySystemTime

ScsiPortQuerySystemTime obtains the current system time.

VOID
  ScsiPortQuerySystemTime(
    OUT PLARGE_INTEGER  CurrentTime
    );

Parameters

CurrentTime
Pointer to the current time, on return.

Return Value

None

Headers

Declared in srb.h. Include srb.h.

Comments

The system time returned in CurrentTime is the number of 100-nanosecond intervals that have elapsed since January 1, 1601. System time is typically updated approximately every ten milliseconds. This value is computed for the GMT time zone. Callers of ScsiPortQuerySystemTime can be running at any IRQL.


ScsiPortReadPortBufferUchar

ScsiPortReadPortBufferUchar transfers a given number of unsigned byte values from the HBA to a buffer.

VOID
  ScsiPortReadPortBufferUchar(
    IN PUCHAR  Port,
    IN PUCHAR  Buffer,
    IN ULONG  Count
    );

Parameters

Port
Points to the I/O port. The given Port must be in a mapped I/O-space range returned by ScsiPortGetDeviceBase.
Buffer
Points to the buffer.
Count
Specifies the number of bytes to be read from the HBA.

Return Value

None

Comments

ScsiPortReadPortBufferUchar ensures that the data is transferred correctly.

See Also

ScsiPortGetDeviceBase


ScsiPortReadPortBufferUlong

ScsiPortReadPortBufferUlong transfers a given number of ULONG values from the HBA to a buffer.

VOID
  ScsiPortReadPortBufferUlong(
    IN PULONG  Port,
    IN PULONG  Buffer,
    IN ULONG  Count
    );

Parameters

Port
Points to the I/O port. The given Port must be in a mapped I/O-space range returned by ScsiPortGetDeviceBase.
Buffer
Points to the buffer.
Count
Specifies the number of ULONG values to read from the HBA.

Return Value

None

Comments

ScsiPortReadPortBufferUlong ensures that the data is transferred correctly.

See Also

ScsiPortGetDeviceBase


ScsiPortReadPortBufferUshort

ScsiPortReadPortBufferUshort transfers a given number of USHORT values from the HBA to a buffer.

VOID
  ScsiPortReadPortBufferUshort(
    IN PUSHORT  Port,
    IN PUSHORT  Buffer,
    IN ULONG  Count
    );

Parameters

Port
Points to the I/O port. The given Port must be in a mapped I/O-space range returned by ScsiPortGetDeviceBase.
Buffer
Points to the buffer.
Count
Specifies the number of USHORT values to read from the HBA.

Return Value

None

Comments

ScsiPortReadPortBufferUshort ensures that the data is transferred correctly.

See Also

ScsiPortGetDeviceBase


ScsiPortReadPortUchar

ScsiPortReadPortUchar reads an unsigned byte value from the HBA.

UCHAR
  ScsiPortReadPortUchar(
    IN PUCHAR  Port
    );

Parameters

Port
Points to the I/O port. The given Port must be in a mapped I/O-space range returned by ScsiPortGetDeviceBase.

Return Value

ScsiPortReadPortUchar returns an unsigned byte from the HBA's I/O port.

Comments

ScsiPortReadPortUchar ensures that the data is transferred correctly.

See Also

ScsiPortGetDeviceBase


ScsiPortReadPortUlong

ScsiPortReadPortUlong reads a ULONG value from the HBA.

ULONG
  ScsiPortReadPortUlong(
    IN PULONG  Port
    );

Parameters

Port
Points to the I/O port. The given Port must be in a mapped I/O-space range returned by ScsiPortGetDeviceBase.

Return Value

ScsiPortReadPortUlong returns a ULONG value from the HBA's I/O port.

Comments

ScsiPortReadPortUlong ensures that the data is transferred correctly.

See Also

ScsiPortGetDeviceBase


ScsiPortReadPortUshort

ScsiPortReadPortUshort reads a USHORT value from the HBA.

USHORT
  ScsiPortReadPortUshort(
    IN PUSHORT  Port
    );

Parameters

Port
Points to the I/O port. The given Port must be in a mapped I/O-space range returned by ScsiPortGetDeviceBase.

Return Value

ScsiPortReadPortUshort returns a USHORT value from the HBA's I/O port.

Comments

ScsiPortReadPortUshort ensures that the data is transferred correctly.

See Also

ScsiPortGetDeviceBase


ScsiPortReadRegisterBufferUchar

ScsiPortReadRegisterBufferUchar transfers a specified number of unsigned bytes from the HBA to a buffer.

VOID
  ScsiPortReadRegisterBufferUchar(
    IN PUCHAR  Register,
    IN PUCHAR  Buffer,
    IN ULONG  Count
    );

Parameters

Register
Points to the register. The given Register must be in a mapped memory-space range returned by ScsiPortGetDeviceBase.
Buffer
Points to the buffer.
Count
Specifies the number of bytes to be read from the HBA.

Return Value

None

Comments

ScsiPortReadRegisterBufferUchar ensures that the data is transferred correctly.

See Also

ScsiPortGetDeviceBase


ScsiPortReadRegisterBufferUlong

ScsiPortReadRegisterBufferUlong transfers a specified number of ULONG values from the HBA to a buffer.

VOID
  ScsiPortReadRegisterBufferUlong(
    IN PULONG  Register,
    IN PULONG  Buffer,
    IN ULONG  Count
    );

Parameters

Register
Points to the register. The given Register must be in a mapped memory-space range returned by ScsiPortGetDeviceBase.
Buffer
Points to the buffer.
Count
Specifies the number of ULONG values to be read from the HBA.

Return Value

None

Comments

ScsiPortReadRegisterBufferUlong ensures that the data is transferred correctly.

See Also

ScsiPortGetDeviceBase


ScsiPortReadRegisterBufferUshort

ScsiPortReadRegisterBufferUshort transfers a specified number of USHORT values from the HBA to a buffer.

VOID
  ScsiPortReadRegisterBufferUshort(
    IN PUSHORT  Register,
    IN PUSHORT  Buffer,
    IN ULONG  Count
    );

Parameters

Register
Points to the register. The given Register must be in a mapped memory-space range returned by ScsiPortGetDeviceBase.
Buffer
Points to the buffer.
Count
Specifies the number of USHORT values to be read from the HBA.

Return Value

None

Comments

ScsiPortReadRegisterBufferUshort ensures that the data has been transferred correctly.

See Also

ScsiPortGetDeviceBase


ScsiPortReadRegisterUchar

ScsiPortReadRegisterUchar reads an unsigned byte value from the HBA.

UCHAR
  ScsiPortReadRegisterUchar(
    IN PUCHAR  Register
    );

Parameters

Register
Points to the register. The given Register must be in a mapped memory-space range returned by ScsiPortGetDeviceBase.

Return Value

ScsiPortReadRegisterUchar returns an unsigned byte from the HBA's register.

Comments

ScsiPortReadRegisterUchar ensures that the data is transferred correctly.

See Also

ScsiPortGetDeviceBase


ScsiPortReadRegisterUlong

ScsiPortReadRegisterUlong reads a ULONG value from the HBA.

ULONG
  ScsiPortReadRegisterUlong(
    IN PULONG  Register
    );

Parameters

Register
Points to the register. The given Register must be in a mapped memory-space range returned by ScsiPortGetDeviceBase.

Return Value

ScsiPortReadRegisterUlong returns a ULONG value from the HBA's register.

Comments

ScsiPortReadRegisterUlong ensures that data is transferred correctly.

See Also

ScsiPortGetDeviceBase


ScsiPortReadRegisterUshort

ScsiPortReadRegisterUshort reads a USHORT value from the HBA.

USHORT
  ScsiPortReadRegisterUshort(
    IN PUSHORT  Register
    );

Parameters

Register
Points to the register. The given Register must be in a mapped memory-space range returned by ScsiPortGetDeviceBase.

Return Value

ScsiPortReadRegisterUshort returns a USHORT value from the HBA's register.

Comments

ScsiPortReadRegisterUshort ensures that the data is transferred correctly.

See Also

ScsiPortGetDeviceBase


ScsiPortSetBusDataByOffset

ScsiPortSetBusDataByOffset sets bus-configuration data for an adapter on a dynamically configurable I/O bus with a published, standard interface.

ULONG
  ScsiPortSetBusDataByOffset(
    IN PVOID  DeviceExtension,
    IN ULONG  BusDataType,
    IN ULONG  SystemIoBusNumber,
    IN ULONG  SlotNumber,
    IN PVOID  Buffer,
    IN ULONG  Offset,
    IN ULONG  Length
    );

Parameters

DeviceExtension
Points to the miniport driver's device extension.
BusDataType
Specifies the type of bus data to be set. Currently, its value can be PCIConfiguration. However, additional types of standardized, dynamically configurable buses will be supported in future. The upper bound on the bus types supported is always MaximumBusDataType.
SystemIoBusNumber
Specifies the system-assigned number of the I/O bus on which the HBA is connected. The miniport driver's HwScsiFindAdapter routine obtains this value from the input PORT_CONFIGURATION_INFORMATION SystemIoBusNumber member.
SlotNumber
Specifies the logical slot number of the HBA.

When PCIConfiguration is specified as the BusDataType, this parameter must be specified as a PCI_SLOT_NUMBER-type value.

Buffer
Points to a caller-supplied storage area with configuration information specific to BusDataType.

When PCIConfiguration is specified, the buffer contains some or all of the PCI_COMMON_CONFIG information for the given SlotNumber. The specified Offset and Length determine how much information is supplied.

Offset
Specifies the byte offset within the PCI_COMMON_CONFIG structure at which the caller-supplied configuration values begin. A miniport driver can use PCI_COMMON_HDR_LENGTH to specify the offset of the device-specific area in PCI_COMMON_CONFIG.
Length
Specifies the number of bytes in the storage area at Buffer.

Return Value

ScsiPortSetBusDataByOffset returns the number of bytes of data successfully set for the given SlotNumber. If the given BusDataType is not valid for the current platform or if the supplied information is invalid, ScsiPortSetBusDataByOffset returns zero.

Comments

Miniport drivers of HBAs on a PCI bus seldom call ScsiPortSetBusDataByOffset unless unusual circumstances or the nature of a particular driver's HBA requires such a call. For example, a miniport driver might call ScsiPortSetBusDataByOffset to clear a bit in the PCI status register if its HBA signals a target abort during initialization or to set device-specific configuration data for the HBA.

ScsiPortSetBusDataByOffset can be called only from the miniport's HwScsiFindAdapter routine or from HwScsiAdapterControl when the control type is ScsiSetRunningConfig.

See Also

HalSetBusDataByOffset, HwScsiFindAdapter, PCI_COMMON_CONFIG, PCI_SLOT_NUMBER, PORT_CONFIGURATION_INFORMATION,, ScsiPortGetBusData


ScsiPortStallExecution

ScsiPortStallExecution stalls in the miniport driver.

VOID
  ScsiPortStallExecution(
    IN ULONG  Delay
    );

Parameters

Delay
Specifies the delay interval in microseconds. The given value must be less than a full millisecond.

Return Value

None

Comments

ScsiPortStallExecution should be called as seldom as possible and the total stall time in a miniport driver routine must be less than one millisecond. This call ties up a processor, doing no useful work while stalling in the driver.

In general, a miniport should call ScsiPortStallExecution only if the driver must wait for a state change on the HBA that cannot cause an interrupt, or if the driver must delay for a very short interval between accesses to the HBA.

If a miniport's HwScsiInterrupt routine must stall between accesses to the HBA and the total delay time in the ISR might be more than one millisecond, HwScsiInterrupt should call ScsiPortNotification with the NotificationType CallEnableInterrupts instead of calling ScsiPortStallExecution. Such a miniport has a pair of HwScsi..InterruptsCallback routines to manage its interrupt-driven I/O processing without tying up a processor and degrading the I/O performance of other HBAs that miniport driver might support in the same machine.

A miniport-supplied HwScsiTimer routine also can be passed in calls to ScsiPortNotification with a specified interval that is not limited to one millisecond.

See Also

HwScsiTimer, HwScsiDisableInterruptsCallback, HwScsiEnableInterruptsCallback, HwScsiInterrupt, ScsiPortNotification


ScsiPortValidateRange

ScsiPortValidateRange indicates whether the specified access range values have already been claimed in the registry by another driver.

BOOLEAN
  ScsiPortValidateRange(
    IN PVOID  HwDeviceExtension,
    IN INTERFACE_TYPE  BusType,
    IN ULONG  SystemIoBusNumber,
    IN SCSI_PHYSICAL_ADDRESS  IoAddress,
    IN ULONG  NumberOfBytes,
    IN BOOLEAN  InIoSpace
    );

Parameters

HwDeviceExtension
Points to the per-HBA storage the OS-specific port driver allocated, initialized with zeros, and passed in to the miniport's HwScsiFindAdapter routine.
BusType
Is the value of the AdapterInterfaceType member in the PORT_CONFIGURATION_INFORMATION structure when HwScsiFindAdapter is called.
SystemIoBusNumber
Is the value of the SystemIoBusNumber member in the configuration information when HwScsiFindAdapter is called.
IoAddress
Is a bus-relative base address for the range of ports or device memory to be validated before the miniport's HwScsiFindAdapter routine attempts to map the access range for the adapter at that address.
NumberOfBytes
Specifies the size in bytes or number of elements in the range.
InIoSpace
TRUE indicates the range is in I/O space, rather than in memory.

Return Value

ScsiPortValidateRange returns TRUE if the HwScsiFindAdapter routine can safely map and use the mapped range to access the adapter. ScsiPortValidateRange returns FALSE if the specified access range values have already been claimed in the registry by another driver.

Comments

ScsiPortValidateRange can be called only from a miniport driver's HwScsiFindAdapter routine. Calls from other miniport driver routines will result in system failure or incorrect operation for the caller.

If the OS-specific port driver initializes any AccessRanges element of the PORT_CONFIGURATION_INFORMATION structure before it calls the miniport's HwScsiFindAdapter routine, the miniport must pass the supplied values to ScsiPortGetDeviceBase and use the mapped logical addresses for the range to determine whether an HBA is one that it supports.

The port driver either fills an ACCESS_RANGE-type element with a complete description of a bus-relative address range for an adapter, or the port driver zeros all members of the element.

For input AccessRanges elements set with default zeros, the HwScsiFindAdapter routine can attempt to locate an adapter it supports on the given I/O bus. In these circumstances, a miniport driver usually has a set of driver-determined default addresses for its type(s) of HBA. However, a previously loaded driver might already be using an initialized adapter at one of this miniport's default address ranges, particularly in x86-only systems in which some devices are initialized in x86 real mode. To prevent such a device from being inadvertently reprogrammed, each miniport driver's HwScsiFindAdapter routine should call ScsiPortValidateRange before it maps any driver-supplied addresses with ScsiPortGetDeviceBase and then uses the mapped logical addresses to interrogate adapters on an I/O bus.

If ScsiPortValidateRange returns FALSE, HwScsiFindAdapter must not attempt to map the input range addresses because another driver has already claimed the range in the registry.

If ScsiPortValidateRange returns TRUE, HwScsiFindAdapter can safely do the following:

  1. Map the bus-relative range addresses to system-space logical range addresses with ScsiPortGetDeviceBase.
  2. Use the mapped logical addresses with the ScsiPortRead/Write Xxx to determine whether the adapter actually is an HBA that the driver supports.

If a miniport uses a range successfully passed to ScsiPortValidateRange for an HBA it supports, that driver must invert the InIoSpace value when it sets the RangeInMemory member of an AccessRanges element in the PORT_CONFIGURATION_INFORMATION.

See Also

ACCESS_RANGE, HwScsiFindAdapter, PORT_CONFIGURATION_INFORMATION, ScsiPortGetDeviceBase, ScsiPortInitialize, ScsiPortRead Xxx, ScsiPortWrite Xxx


ScsiPortWmiDispatchFunction

ScsiPortWmiDispatchFunction is a dispatch routine for miniports that support WMI.

BOOLEAN
  ScsiPortWmiDispatchFunction(
    IN PSCSI_WMILIB_CONTEXT  WmiLibInfo,
    IN UCHAR  MinorFunction,
    IN PVOID  DeviceContext,
    IN PSCSIWMI_REQUEST_CONTEXT  RequestContext,
    IN PVOID  DataPath,
    IN ULONG  BufferSize,
    IN PVOID  Buffer
    );

Parameters

WmiLibInfo
Points to a SCSI_WMILIB_CONTEXT structure that contains registration information for a miniport's data blocks and event blocks and defines entry points for the miniport's WMI library callback routines.
MinorFunction
Indicates the WMI action to perform. The miniport sets MinorFunction to Srb->WmiSubFunction from the input SRB.
DeviceContext
Points to a miniport-defined context value. The port driver will pass DeviceContext to the miniport's HwScsiWmiXxx callback routine. This value would typically point to a HW_DEVICE_EXTENSION structure.
RequestContext
Points to a SCSIWMI_REQUEST_CONTEXT structure that contains context information for the WMI SRB. If the SRB can pend, the miniport must allocate this structure from the SRB extension because the request context must remain valid until after ScsiPortWmiPostProcess returns with the final SRB return status and buffer size. ScsiPortWmiDispatchFunction will pass RequestContext to the miniport's callback routine that processes this request.
DataPath
Points to a GUID that represents the data block associated with the request. The miniport sets DataPath to Srb->DataPath from the input SRB.
BufferSize
Specifies the size in bytes of the data buffer. The miniport sets BufferSize to Srb->DataTransferLength from the input SRB.
Buffer
Points to the data buffer. The miniport sets Buffer to Srb->DataBuffer from the input SRB.

Return Value

ScsiPortWmiDispatchFunction returns TRUE if the request is pending, or FALSE if the request was completed.

Comments

When a miniport driver receives an SRB in which the Function member is set to SRB_FUNCTION_WMI, it calls ScsiPortWmiDispatchFunction with request parameters, including a pointer to an initialized SCSI_WMILIB_CONTEXT structure. This structure contains information about the miniport's data blocks and event blocks and defines entry points for the miniport's HwScsiWmiXxx callback routines.

ScsiPortWmiDispatchFunction confirms that the SRB is a WMI request and determines whether the block specified by the request is valid for the miniport. If these conditions are met, ScsiPortWmiDispatchFunction processes the SRB by calling the appropriate HwScsiWmiXxx entry point in the miniport's SCSI_WMILIB_CONTEXT structure. If the miniport does not define an entry point for an optional HwScsiWmiXxx routine, the port driver handles the request.

In either case, after ScsiPortWmiDispatchFunction returns, the miniport should do the following for requests that it does not pend:

  • Set Srb->DataTransferLength to the value returned by ScsiPortWmiGetReturnSize
  • Set Srb->SrbStatus to the value returned by ScsiPortWmiGetReturnStatus
  • Call ScsiPortNotification with RequestComplete and again with NextRequest

See Also

SCSI_WMILIB_CONTEXT, ScsiPortNotification, ScsiPortWmiGetReturnSize, ScsiPortWmiGetReturnStatus, ScsiPortWmiPostProcess, SCSIWMI_REQUEST_CONTEXT


ScsiPortWmiFireLogicalUnitEvent

ScsiPortWmiFireLogicalUnitEvent sends an event associated with a logical unit to the port driver for delivery to WMI data consumers that have requested notification of the event.

VOID
  ScsiPortWmiFireLogicalUnitEvent(
    IN PVOID  HwDeviceExtension,
    IN UCHAR  PathId,
    IN UCHAR  TargetId,
    IN UCHAR  Lun,
    IN LPGUID  Guid,
    IN ULONG  InstanceIndex,
    IN ULONG  EventDataSize,
    IN PVOID  EventData
    );

Parameters

HwDeviceExtension
Points to the miniport's device extension.
PathId
Identifies the SCSI bus; SP_UNTAGGED indicates all buses controlled by the HBA.
TargetId
Identifies the target controller or device on the given bus(es); SP_UNTAGGED indicates all targets on the bus.
Lun
Identifies the logical unit for the given target controller or device; SP_UNTAGGED indicates all logical units for the given target controller(s) on the given bus(es).
Guid
Points to the GUID that represents the event block.
InstanceIndex
If the event block has multiple instances, specifies the index of the instance.
EventDataSize
Specifies the number of bytes of data at EventData, not including pad bytes at the beginning of the event data buffer. If no data is generated for an event, EventDataSize should be set to zero.
EventData
Points to a miniport-allocated buffer containing data generated by the miniport for the event. The buffer must be at least the size of the event data plus 0x40 pad bytes at the beginning of the buffer.

Return Value

None

Comments

A miniport calls ScsiPortWmiFireLogicalUnitEvent to send an event associated with an adapter or logical unit to all data consumers that have requested notification of the event.

The miniport sends an event only if it has been previously enabled by the miniport's HwScsiWmiFunctionControl routine.

The driver should write event data to the buffer pointed to by EventData at offset 0x40. The first 0x40 bytes are used by SCSI WMI. If no data is passed back with the event then EventData should be 0x40 bytes in length.

See Also

HwScsiWmiFunctionControl


ScsiPortWmiGetReturnSize

ScsiPortWmiGetReturnSize indicates the number of bytes of data to be returned by a miniport for a WMI SRB.

ULONG
  ScsiPortWmiGetReturnSize(
    PSCSIWMI_REQUEST_CONTEXT  RequestContext
    );

Parameters

RequestContext
Points to the request context for this SRB.

Return Value

The return value represents the data transfer length for the SRB. The miniport should set Srb->DataTransferLength to the value returned by ScsiPortWmiGetReturnSize before completing the SRB.

Comments

A miniport must call ScsiPortWmiGetReturnSize to obtain the value to put into Srb->DataTransferLength before completing the SRB. ScsiPortWmiGetReturnSize should be called sometime after the miniport calls ScsiWmiPostProcess.

See Also

ScsiPortWmiGetReturnStatus, ScsiPortWmiPostProcess, SCSIWMI_REQUEST_CONTEXT


ScsiPortWmiGetReturnStatus

ScsiPortWmiGetReturnStatus returns the status of a WMI SRB.

UCHAR
  ScsiPortWmiGetReturnStatus(
    PSCSIWMI_REQUEST_CONTEXT  RequestContext
    );

Parameters

RequestContext
Points to the request context for this SRB.

Return Value

The return value represents the return status for the SRB. The miniport should set Srb->SrbStatus to the value returned by ScsiPortWmiGetReturnStatus before completing the SRB.

Comments

A miniport must call ScsiPortWmiGetReturnStatus to obtain the value to put into Srb->SrbStatus. ScsiPortWmiGetReturnStatus should be called sometime after the miniport calls ScsiPortWmiPostProcess.

See Also

ScsiPortWmiGetReturnSize, ScsiPortWmiPostProcess, SCSIWMI_REQUEST_CONTEXT


ScsiPortWmiPostProcess

ScsiPortWmiPostProcess updates a request context for a WMI SRB.

VOID
  ScsiPortWmiPostProcess(
    IN PSCSIWMI_REQUEST_CONTEXT  RequestContext,
    IN UCHAR  SrbStatus,
    IN ULONG  BufferUsed
    );

Parameters

RequestContext
Points to the request context for this SRB.
SrbStatus
Specifies any valid SRB status. If the output buffer passed to the miniport was too small to contain all of the data from a request, the miniport sets SrbStatus to SRB_STATUS_DATA_OVERRUN.
BufferUsed
If SrbStatus indicates success, the miniport sets BufferUsed to the number of bytes of data written to the buffer. If SrbStatus is SRB_STATUS_DATA_OVERRUN, the miniport sets BufferUsed to the number of bytes required to complete the SRB successfully.

Return Value

None

Comments

A miniport must call ScsiPortWmiPostProcess when the WMI SRB request is done and ready to be completed.

For synchronous SRBs, ScsiPortWmiPostProcess is called in the callback.

For pending SRBs, ScsiPortWmiPostProcess is called when the SRB is done and before completing the SRB.

See Also

ScsiPortWmiDispatchFunction, ScsiPortWmiGetReturnSize, ScsiPortWmiGetReturnStatus, SCSIWMI_REQUEST_CONTEXT


ScsiPortWritePortBufferUchar

ScsiPortWritePortBufferUchar transfers a given number of unsigned bytes from a buffer to the HBA.

VOID
  ScsiPortWritePortBufferUchar(
    IN PUCHAR  Port,
    IN PUCHAR  Buffer,
    IN ULONG  Count
    );

Parameters

Port
Points to the I/O port. The given Port must be in a mapped I/O-space range returned by ScsiPortGetDeviceBase.
Buffer
Points to a buffer.
Count
Specifies the number of bytes to be written to the HBA.

Return Value

None

See Also

ScsiPortGetDeviceBase


ScsiPortWritePortBufferUlong

ScsiPortWritePortBufferUlong transfers a given number of ULONG values from a buffer to the HBA.

VOID
  ScsiPortWritePortBufferUlong(
    IN PULONG  Port,
    IN PULONG  Buffer,
    IN ULONG  Count
    );

Parameters

Port
Points to the I/O port. The given Port must be in a mapped I/O-space range returned by ScsiPortGetDeviceBase.
Buffer
Points to the buffer.
Count
Specifies the number of ULONG values to be written to the HBA.

Return Value

None

See Also

ScsiPortGetDeviceBase


ScsiPortWritePortBufferUshort

ScsiPortWritePortBufferUshort transfers a given number of USHORT values from a buffer to the HBA.

VOID
  ScsiPortWritePortBufferUshort(
    IN PUSHORT  Port,
    IN PUSHORT  Buffer,
    IN ULONG  Count
    );

Parameters

Port
Points to the I/O port. The given Port must be in a mapped I/O-space range returned by ScsiPortGetDeviceBase.
Buffer
Points to the buffer.
Count
Specifies the number of USHORT values to be written to the HBA.

Return Value

None

See Also

ScsiPortGetDeviceBase


ScsiPortWritePortUchar

ScsiPortWritePortUchar transfers an unsigned byte to the HBA.

VOID
  ScsiPortWritePortUchar(
    IN PUCHAR  Port,
    IN UCHAR  Value
    );

Parameters

Port
Points to the I/O port. The given Port must be in a mapped I/O-space range returned by ScsiPortGetDeviceBase.
Value
Specifies the value to be written to the HBA's I/O port.

Return Value

None

See Also

ScsiPortGetDeviceBase


ScsiPortWritePortUlong

ScsiPortWritePortUlong transfers a ULONG value to the HBA.

VOID
  ScsiPortWritePortUlong(
    IN PULONG  Port,
    IN ULONG  Value
    );

Parameters

Port
Points to the I/O port. The given Port must be in a mapped I/O-space range returned by ScsiPortGetDeviceBase.
Value
Specifies the value to be written to the HBA's I/O port.

Return Value

None

See Also

ScsiPortGetDeviceBase


ScsiPortWritePortUshort

ScsiPortWritePortUshort transfers a USHORT value to the HBA.

VOID
  ScsiPortWritePortUshort(
    IN PUSHORT  Port,
    IN USHORT  Value
    );

Parameters

Port
Points to the I/O port. The given Port must be in a mapped I/O-space range returned by ScsiPortGetDeviceBase.
Value
Specifies the value to be written to the HBA's I/O port.

Return Value

None

See Also

ScsiPortGetDeviceBase


ScsiPortWriteRegisterBufferUchar

ScsiPortWriteRegisterBufferUchar transfers a given number of unsigned bytes from a buffer to the HBA.

VOID
  ScsiPortWriteRegisterBufferUchar(
    IN PUCHAR  Register,
    IN PUCHAR  Buffer,
    IN ULONG  Count
    );

Parameters

Register
Points to the register. The given Register must be in a mapped memory-space range returned by ScsiPortGetDeviceBase.
Buffer
Points to a buffer containing the data to be written.
Count
Specifies the number of bytes to be transferred to the HBA.

Return Value

None

See Also

ScsiPortGetDeviceBase


ScsiPortWriteRegisterBufferUlong

ScsiPortWriteRegisterBufferUlong transfers a given number of ULONG values from a buffer to the HBA.

VOID
  ScsiPortWriteRegisterBufferUlong(
    IN PULONG  Register,
    IN PULONG  Buffer,
    IN ULONG  Count
    );

Parameters

Register
Points to the register. The given Register must be in a mapped memory-space range returned by ScsiPortGetDeviceBase.
Buffer
Points to a buffer containing the data to be written.
Count
Specifies the number of ULONG values to be transferred to the HBA.

Return Value

None

See Also

ScsiPortGetDeviceBase


ScsiPortWriteRegisterBufferUshort

ScsiPortWriteRegisterBufferUshort transfers a given number of USHORT values from a buffer to the HBA.

VOID
  ScsiPortWriteRegisterBufferUshort(
    IN PUSHORT  Register,
    IN PUSHORT  Buffer,
    IN ULONG  Count
    );

Parameters

Register
Points to the register. The given Register must be in a mapped memory-space range returned by ScsiPortGetDeviceBase.
Buffer
Points to a buffer containing the data to be written.
Count
Specifies the number of USHORT values to be transferred to the HBA.

Return Value

None

See Also

ScsiPortGetDeviceBase


ScsiPortWriteRegisterUchar

ScsiPortWriteRegisterUchar transfers a unsigned byte value to the HBA.

VOID
  ScsiPortWriteRegisterUchar(
    IN PUCHAR  Register,
    IN ULONG  Value
    );

Parameters

Register
Points to the register. The given Register must be in a mapped memory-space range returned by ScsiPortGetDeviceBase.
Value
Specifies the value to be written to the HBA's register.

Return Value

None

See Also

ScsiPortGetDeviceBase


ScsiPortWriteRegisterUlong

ScsiPortWriteRegisterUlong transfers a ULONG value to the HBA.

VOID
  ScsiPortWriteRegisterUlong(
    IN PULONG  Register,
    IN ULONG  Value
    );

Parameters

Register
Points to the register. The given Register must be in a mapped memory-space range returned by ScsiPortGetDeviceBase.
Value
Specifies the value to be written to the HBA's register.

Return Value

None

See Also

ScsiPortGetDeviceBase


ScsiPortWriteRegisterUshort

ScsiPortWriteRegisterUshort transfers a USHORT value to the HBA.

VOID
  ScsiPortWriteRegisterUshort(
    IN PUSHORT  Register,
    IN USHORT  Value
    );

Parameters

Register
Points to the register. The given Register must be in a mapped memory-space range returned by ScsiPortGetDeviceBase.
Value
Specifies the value to be written to the HBA's register.

Return Value

None

See Also

ScsiPortGetDeviceBase


Tape Class Driver Routines

The system-supplied tape class driver handles generic tape operations and provides OS-specific support to individual tape miniclass drivers.

This chapter describes the routines exported by the tape class driver for use by tape miniclass drivers. The routines are listed in alphabetical order.

These routines are defined in minitape.h.


TapeClassAllocateSrbBuffer

TapeClassAllocateSrbBuffer allocates an Srb->DataBuffer.

BOOLEAN
  TapeClassAllocateSrbBuffer(
    IN OUT PSCSI_REQUEST_BLOCK  Srb,
    IN ULONG  SrbBufferSize
    );

Parameters

Srb
Points to the SRB.
SrbBufferSize
Specifies the size, in bytes, of the DataBuffer to be allocated.

Return Value

TapeClassAllocateSrbBuffer returns TRUE if the DataBuffer was allocated successfully.

Comments

TapeClassAllocateSrbBuffer allocates an Srb->DataBuffer from nonpaged memory and initializes the members to zero. If the buffer already exists from an earlier call, it is freed and a new buffer allocated. A tape miniclass driver calls this routine to allocate a DataBuffer in a portable way.


TapeClassCompareMemory

TapeClassCompareMemory compares two memory buffers and returns the number of bytes that are equivalent.

ULONG
  TapeClassCompareMemory(
    IN OUT PVOID  Source1,
    IN OUT PVOID  Source2,
    IN ULONG  Length
    );

Parameters

Source1
Points to the first buffer to be compared.
Source2
Points to the second buffer to be compared.
Length
Specifies the number of bytes to be compared.

Return Value

TapeClassCompareMemory returns the number of bytes that are equivalent.

Comments

A tape miniclass driver uses TapeClassCompareMemory to compare memory in a portable way. For example, a miniclass driver uses TapeClassCompareMemory in its TapeMiniVerifyInquiry routine to determine whether a given product ID matches one of the devices the driver supports.

See Also

TapeMiniVerifyInquiry


TapeClassInitialize

TapeClassInitialize performs much of the driver and device initialization on behalf of a miniclass driver. TapeClassInitialize loads the tape class driver entry points for tape I/O requests into the miniclass driver data structure, locates and claims unclaimed tape devices that the miniclass driver supports, and allocates and initializes the OS resources for the miniclass driver and its devices. TapeClassInitialize uses miniclass-driver-specific information supplied in TapeInitData and calls back to the tape miniclass driver for driver-specific operations.

ULONG
  TapeClassInitialize(
    IN PVOID  Argument1,
    IN PVOID  Argument2,
    IN PTAPE_INIT_DATA_EX  TapeInitData
    );

Parameters

Argument1
Points to driver context information that was passed to the tape miniclass driver's DriverEntry routine. The format of the information is OS-specific and must not be interpreted by a tape miniclass driver.
Argument2
Points to the second driver context structure that was passed to the tape miniclass driver's DriverEntry routine. The format of the information is OS-specific and must not be interpreted by a tape miniclass driver.
TapeInitData
Points to a TAPE_INIT_DATA_EX structure containing driver-specific information such as the entry points for the tape miniclass driver's command processing routines.

Return Value

TapeClassInitialize returns a value indicating the success or failure of the driver initialization. The tape miniclass driver passes this value, uninterpreted, as the return value from its DriverEntry routine.

Comments

A tape miniclass driver calls TapeClassInitialize from its DriverEntry routine and passes driver-specific information in TapeInitData. TapeClassInitialize performs a large part of the driver initialization on behalf of the miniclass driver and insulates the miniclass driver from OS-specific details.

TapeClassInitialize calls the tape miniclass driver for driver-specific activities required during initialization. For example, TapeClassInitialize calls the tape miniclass driver's TapeMiniVerifyInquiry routine to determine whether the driver supports a given tape device. TapeClassInitialize also calls the tape miniclass driver's TapeMiniExtensionInit routine to initialize the minitape extension, if the miniclass driver requested one.

A tape miniclass driver allocates a TAPE_INIT_DATA_EX structure on the stack, clears it with TapeClassZeroMemory, fills in all the appropriate members, and passes it to TapeClassInitialize.

See Also

TAPE_INIT_DATA_EX, DriverEntry of Tape Miniclass Driver


TapeClassLogicalBlockToPhysicalBlock

TapeClassLogicalBlockToPhysicalBlock translates a pseudological block address to a physical block address. This routine is for SCSI-1 devices.

TAPE_PHYS_POSITION
  TapeClassLogicalBlockToPhysicalBlock(
    IN UCHAR  DensityCode,
    IN ULONG  LogicalBlockAddress,
    IN ULONG  BlockLength,
    IN BOOLEAN  FromBOT
    );

Parameters

DensityCode
Specifies the tape media density code. This routine supports tapes with the following density codes: QIC_24, QIC_120, QIC_150, QIC_525, QIC_1000, QIC_2GB, QIC_1350, and QIC_2100.
LogicalBlockAddress
Specifies a pseudological block address.
BlockLength
Specifies the logical block size, in bytes.
FromBOT
TRUE indicates that the physical block calculation should start at the beginning of the tape and account for the physical device header. FALSE indicates that the tape has two partitions, that the block address is on the directory partition, and therefore no physical device header needs to be factored into the calculation.

Return Value

TapeClassLogicalBlockToPhysicalBlock returns a structure containing the physical block address:

typedef struct _TAPE_PHYS_POSITION {
    ULONG SeekBlockAddress;
    ULONG SpaceBlockCount;
} TAPE_PHYS_POSITION, PTAPE_PHYS_POSITION;

Comments

A tape miniclass driver calls TapeClassLogicalBlockToPhysicalBlock to translate a logical block address from an application to a physical block address for a tape device. TapeClassLogicalBlockToPhysicalBlock is not necessary for SCSI-2 drivers because SCSI-2 devices support logical block addressing.

To position a tape to the physical block address returned by this routine, a tape miniclass driver issues two SCSI commands: a LOCATE command to position the tape to the SeekBlockAddress, and then a SPACE command to advance the tape SpaceBlockCount. The SpaceBlockCount value is necessary if the pseudological blocks on the tape are smaller than the physical blocks; in that case, the logical block boundary might not align with a physical block boundary.

If a tape miniclass driver calls this routine with an unsupported tape density code, TapeClassLogicalBlockToPhysicalBlock does not perform any translation. It returns the logical block address in SeekBlockAddress and returns zero in SpaceBlockCount.

See Also

TapeClassPhysicalBlockToLogicalBlock


TapeClassPhysicalBlockToLogicalBlock

TapeClassPhysicalBlockToLogicalBlock translates a physical block address to a pseudological block address. This routine is for SCSI-1 devices.

ULONG
  TapeClassPhysicalBlockToLogicalBlock(
    IN UCHAR  DensityCode,
    IN ULONG  PhysicalBlockAddress,
    IN ULONG  BlockLength,
    IN BOOLEAN  FromBOT
    );

Parameters

DensityCode
Specifies the tape media density code. This routine supports tapes with the following density codes: QIC_24, QIC_120, QIC_150, QIC_525, QIC_1000, QIC_2GB, QIC_1350, and QIC_2100.
PhysicalBlockAddress
Specifies the physical block address obtained by a SCSI READ POSITION command.
BlockLength
Specifies the logical block size, in bytes.
FromBOT
TRUE indicates that the logical block calculation should start at the beginning of the tape and account for the physical device header. FALSE indicates that the tape has two partitions, that the block address is on the directory partition, and therefore no physical device header needs to be factored into the calculation.

Return Value

TapeClassPhysicalBlockToLogicalBlock returns the logical block address.

Comments

A tape miniclass driver calls TapeClassPhysicalBlockToLogicalBlock to translate a physical block address from a tape device to a logical block address for an application. TapeClassPhysicalBlockToLogicalBlock is not necessary for SCSI-2 drivers because SCSI-2 devices support logical block addressing.

If a tape miniclass driver calls this routine with an unsupported tape density code, TapeClassPhysicalBlockToLogicalBlock returns the physical block address in the return value, without performing any translation.

See Also

TapeClassLogicalBlockToPhysicalBlock


TapeClassZeroMemory

TapeClassZeroMemory fills a buffer with zeros.

VOID
  TapeClassZeroMemory(
    IN OUT PVOID  Buffer,
    IN ULONG  BufferSize
    );

Parameters

Buffer
Points to the buffer that needs to be cleared.
BufferSize
Specifies the size of the buffer, in bytes.

Return Value

None

Comments

A tape miniclass driver calls TapeClassZeroMemory to zero a buffer in a portable way. A miniclass driver must use TapeClassZeroMemory to clear the TAPE_INIT_DATA_EX structure and CDBs before it uses them.

See Also

DriverEntry of Tape Miniclass Driver


Tape Miniclass Driver Routines

References for the required and OPTIONAL routines in a tape miniclass driver are listed in alphabetical order.

DriverEntry is a required name. A tape miniclass driver's other routines can have any name chosen by the driver writer. In this reference, such routines are prefixed with "TapeMini" to identify the routines as belonging to a tape miniclass driver. All tape miniclass routines with the exception of DriverEntry are called only by the tape class driver.

The routines, structures, and constants required by a tape miniclass driver are declared in minitape.h.

For information about the tape class/miniclass architecture and designing a tape miniclass driver, see Tape Miniclass Drivers. For a description of Microsoft® Win32® tape functions provided for user-mode applications to control a tape device, see the Platform SDK documentation.


DriverEntry of Tape Miniclass Driver

DriverEntry initializes a tape miniclass driver. This routine is required.

ULONG
  DriverEntry(
    IN PVOID  Argument1,
    IN PVOID  Argument2
    );

Parameters

Argument1
Points to a driver context that a tape miniclass driver passes to TapeClassInitialize. The format of the context information is OS-specific and must not be interpreted by portable tape miniclass drivers.
Argument2
Points to a second context structure that a tape miniclass driver passes to TapeClassInitialize. The format of the context information is OS-specific and must not be interpreted by portable tape miniclass drivers.

Return Value

DriverEntry returns the value returned by its call to TapeClassInitialize.

Comments

DriverEntry is the initial entry point for a tape miniclass driver.

Since TapeClassInitialize performs most of the required driver initialization, the primary task of a tape miniclass driver's DriverEntry routine is to allocate and fill in a TAPE_INIT_DATA_EX structure with driver-specific constants and entry points.

DriverEntry first must call TapeClassZeroMemory to clear the TAPE_INIT_DATA_EX structure. DriverEntry then sets the values and pointers in the structure.

DriverEntry calls TapeClassInitialize and passes the address of TAPE_INIT_DATA_EX and the two pointers that were passed to DriverEntry (Argument1 and Argument2). TapeClassInitialize completes driver initialization and returns status to the tape miniclass driver's DriverEntry routine. DriverEntry returns the status that it received from TapeClassInitialize.

See Also

TAPE_INIT_DATA_EX, TapeClassInitialize, TapeClassZeroMemory


TapeMiniCreatePartition

TapeMiniCreatePartition handles the device-specific aspects of an IOCTL_TAPE_CREATE_PARTITION request. This routine is required.

TAPE_STATUS
  TapeMiniCreatePartition(
    IN OUT PVOID  MinitapeExtension  OPTIONAL,
    IN OUT PVOID  CommandExtension  OPTIONAL,
    IN OUT PVOID  CommandParameters,
    IN OUT PSCSI_REQUEST_BLOCK  Srb,
    IN ULONG  CallNumber,
    IN TAPE_STATUS  StatusOfLastCommand  OPTIONAL,
    IN OUT PULONG  RetryFlags  OPTIONAL
    );

Parameters

MinitapeExtension
Points to the driver-specific minitape extension. This is NULL if the miniclass driver did not request a minitape extension when it initialized.
CommandExtension
Points to the command extension. This is NULL if the miniclass driver did not request a command extension when it initialized.
CommandParameters
Points to a buffer containing a TAPE_CREATE_PARTITION structure, which is defined as follows:
typedef struct _TAPE_CREATE_PARTITION {
    ULONG Method;
    ULONG Count;
    ULONG Size;
} TAPE_CREATE_PARTITION, *PTAPE_CREATE_PARTITION;
Method
The method used to create the partitions. This member can be one of the following:

TAPE_FIXED_PARTITIONS
TAPE_SELECT_PARTITIONS
TAPE_INITIATOR_PARTITIONS

Count
The number of partitions to create.
Size
The size of each partition, in bytes.
Srb
Points to an SRB allocated and partially filled in by the tape class driver. TapeMiniCreatePartition must fill in the CDB in the SRB. TapeMiniCreatePartition might fill in other SRB members, depending on the requirements of its device(s).
CallNumber
Specifies the number of times TapeMiniCreatePartition has been called to process a given tape command. CallNumber is zero the first time this routine is called and is incremented for each subsequent call until the miniclass driver returns a TAPE_STATUS_XXX that indicates the command is complete.
StatusOfLastCommand
Specifies the status of the last command. In the first call to TapeMiniCreatePartition to process a given request, StatusOfLastCommand is TAPE_STATUS_SUCCESS. In subsequent calls, StatusOfLastCommand is either TAPE_STATUS_SUCCESS or an error status if an error occurred and the tape miniclass driver set RETURN_ERRORS in RetryFlags in the previous call.
RetryFlags
Points to a variable that specifies what action the tape class driver should take when a tape device reports an error.

The low-order word specifies the number of retries to perform in the event of a SCSI command failure. The default is zero (no retries).

The high-order word contains flags that specify how the tape class driver should return control if an error occurs:

  • If RETURN_ERRORS and IGNORE_ERRORS are clear (the default) the tape class driver returns a failure status to the original requester.
  • If the miniclass driver sets RETURN_ERRORS, the tape class driver calls TapeMiniCreatePartition with StatusOfLastCommand set to a failure status.
  • If the miniclass driver sets IGNORE_ERRORS, the tape class driver converts a failure status to success and calls TapeMiniCreatePartition with StatusOfLastCommand set to success.

Return Value

TAPE_STATUS_SEND_SRB_AND_CALLBACK
Indicates to the tape class driver that the SRB has been filled in and is ready to be sent to the target device. By default, the tape class driver calls TapeMiniCreatePartition again only if the SRB succeeds. A miniclass driver can modify the default behavior by setting RetryFlags before returning from TapeMiniCreatePartition.

TAPE_STATUS_CALLBACK
Directs the tape class driver to increment CallNumber and call TapeMiniCreatePartition again without sending an SRB to the tape device.

TAPE_STATUS_CHECK_TEST_UNIT_READY
Directs the tape class driver to fill in an SRB for the TEST UNIT READY command and send the SRB to the device.

TAPE_STATUS_XXX
Any other return code indicates to the tape class driver that the command is complete and indicates success, failure, or warning. Possible completion return values for this routine include, but are not limited to:

TAPE_STATUS_SUCCESS
TAPE_STATUS_INSUFFICIENT_RESOURCES
TAPE_STATUS_INVALID_DEVICE_REQUEST
TAPE_STATUS_INVALID_PARAMETER
TAPE_STATUS_IO_DEVICE_ERROR
TAPE_STATUS_MEDIA_WRITE_PROTECTED
TAPE_STATUS_NOT_IMPLEMENTED

Comments

TapeMiniCreatePartition creates a partition on a tape by filling in the CDB in an SRB passed by the tape class driver. Creating a partition typically requires a series of SRBs to complete the operation. After TapeMiniCreatePartition fills in a given SRB and returns, the tape class driver sends the SRB to the target device and, depending on the result of the SRB and the value of RetryFlags, calls TapeMiniCreatePartition again.

TapeMiniCreatePartition must fill in the following members in the SRB before returning to the tape class driver:

  • Cdb – Points to the SCSI CDB for the command. Clear the CDB with TapeClassZeroMemory before filling it in.
  • CdbLength – Specifies the number of bytes in the CDB.

TapeMiniCreatePartition might also fill in the following members in the SRB:

  • DataBuffer – Points to the data buffer to be transferred. Use TapeClassAllocateSrbBuffer to allocate a DataBuffer of length greater than or equal to DataTransferLength.
  • DataTransferLength – Specifies the number of bytes to be transferred in the SRB. This member is set by TapeClassAllocateSrbBuffer.
  • TimeOutValue – Specifies a timeout value for this command, overriding the default timeout value from the tape class driver's device extension.
  • SrbFlags – Specifies a flag for this command. The tape miniclass driver must set SRB_FLAGS_DATA_OUT if the SRB is sending data to the tape drive. This member can be zero if the SRB is requesting data from the tape drive or if no data is being transferred by the command.

If the tape miniclass driver stores partition information in the minitape extension, TapeMiniCreatePartition updates the extension before returning to the tape class driver with TAPE_STATUS_SUCCESS.

See Also

SCSI_REQUEST_BLOCK, TapeClassAllocateSrbBuffer, TapeClassZeroMemory


TapeMiniErase

TapeMiniErase handles the device-specific aspects of an IOCTL_TAPE_ERASE request. This routine is required.

TAPE_STATUS
  TapeMiniErase(
    IN OUT PVOID  MinitapeExtension  OPTIONAL,
    IN OUT PVOID  CommandExtension  OPTIONAL,
    IN OUT PVOID  CommandParameters,
    IN OUT PSCSI_REQUEST_BLOCK  Srb,
    IN ULONG  CallNumber,
    IN TAPE_STATUS  StatusOfLastCommand  OPTIONAL,
    IN OUT PULONG  RetryFlags  OPTIONAL
    );

Parameters

MinitapeExtension
Points to the driver-specific minitape extension. This is NULL if the miniclass driver did not request a minitape extension when it initialized.
CommandExtension
Points to the command extension. This is NULL if the miniclass driver did not request a command extension when it initialized.
CommandParameters
Points to a buffer that contains a TAPE_ERASE structure, which is defined as follows:
typedef struct _TAPE_ERASE {
    ULONG Type;
    BOOLEAN Immediate;
} TAPE_ERASE, *PTAPE_ERASE;
Type
The type of erasure to perform. This member can be TAPE_ERASE_SHORT or TAPE_ERASE_LONG.
Immediate
TRUE if the target device should return status immediately, or FALSE if the device should return status after the operation is complete.
Srb
Points to an SRB allocated and partially filled in by the tape class driver. TapeMiniErase must fill in the CDB in the SRB. TapeMiniErase might fill in other SRB members, depending on the requirements of its device(s).
CallNumber
Specifies the number of times the routine has been called to process a given tape command. CallNumber is zero the first time this routine is called and is incremented for each subsequent call until the miniclass driver returns a TAPE_STATUS_XXX that indicates the command is complete.
StatusOfLastCommand
Specifies the status of the last command. In the first call to TapeMiniErase to process a given request, StatusOfLastCommand is TAPE_STATUS_SUCCESS. In subsequent calls, StatusOfLastCommand is either TAPE_STATUS_SUCCESS or an error status if an error occurred and the tape miniclass driver set RETURN_ERRORS in RetryFlags in the previous call.
RetryFlags
Points to a variable that specifies what action the tape class driver should take when a tape device reports an error.

The low-order word specifies the number of retries to perform in the event of a SCSI command failure. The default is zero (no retries).

The high-order word contains flags that specify how the tape class driver should return control if an error occurs:

  • If RETURN_ERRORS and IGNORE_ERRORS are clear (the default) the tape class driver returns a failure status to the original requester.
  • If the miniclass driver sets RETURN_ERRORS, the tape class driver calls TapeMiniErase with StatusOfLastCommand set to a failure status.
  • If the miniclass driver sets IGNORE_ERRORS, the tape class driver converts a failure status to success and calls TapeMiniErase with StatusOfLastCommand set to success.

Return Value

TAPE_STATUS_SEND_SRB_AND_CALLBACK
Indicates to the tape class driver that the SRB has been filled in and is ready to be sent to the target device. By default, the tape class driver calls TapeMiniErase again only if the SRB succeeds. A miniclass driver can modify the default behavior by setting RetryFlags before returning from TapeMiniErase.

TAPE_STATUS_CALLBACK
Directs the tape class driver to increment CallNumber and call TapeMiniErase again without sending an SRB to the tape device.

TAPE_STATUS_CHECK_TEST_UNIT_READY
Directs the tape class driver to fill in an SRB for the TEST UNIT READY command and send the SRB to the device.

TAPE_STATUS_XXX
Any other return code indicates to the tape class driver that the command is complete and indicates success, failure, or warning. Possible completion return values for this routine include, but are not limited to:

TAPE_STATUS_SUCCESS
TAPE_STATUS_NOT_IMPLEMENTED

Comments

TapeMiniErase erases a tape by filling in the CDB in an SRB passed by the tape class driver. Erasing a tape typically requires one SRB to complete the operation. After TapeMiniErase fills in the SRB and returns, the tape class driver sends the SRB to the device and, depending on the result of the SRB and the value of RetryFlags, calls TapeMiniErase again. TapeMiniErase then returns TAPE_STATUS_SUCCESS.

TapeMiniErase must fill in the following members in the SRB before returning to the tape class driver:

  • Cdb – Points to the SCSI CDB for the command. Clear the CDB with TapeClassZeroMemory before filling it in.
  • CdbLength – Specifies the number of bytes in the CDB.

TapeMiniErase might also fill in the following members in the SRB:

  • DataBuffer – Points to the data buffer to be transferred. Use TapeClassAllocateSrbBuffer to allocate a DataBuffer of length greater than or equal to DataTransferLength.
  • DataTransferLength – Specifies the number of bytes to be transferred by the SRB. This member is set by TapeClassAllocateSrbBuffer.
  • TimeOutValue – Specifies a timeout value for this command, overriding the default timeout value from the tape class driver's device extension.
  • SrbFlags – Specifies a flag for this command. The tape miniclass driver must set SRB_FLAGS_DATA_OUT if the SRB is sending data to the tape drive. This member can be zero if the SRB is requesting data from the tape drive or if no data is being transferred by the command.

See Also

SCSI_REQUEST_BLOCK, TapeClassAllocateSrbBuffer, TapeClassZeroMemory


TapeMiniExtensionInit

TapeMiniExtensionInit initializes an OPTIONAL, driver-specific context area. This routine is called by TapeClassInitialize when the tape miniclass driver is loaded. This routine is OPTIONAL.

VOID
  TapeMiniExtensionInit(
    IN OUT PVOID  MinitapeExtension,
    IN PINQUIRYDATA  InquiryData,
    IN PMODE_CAPABILITIES_PAGE  ModeCapabilitiesPage  OPTIONAL
    );

Parameters

MinitapeExtension
Points to a buffer of the size requested by the tape miniclass driver when it initialized.
InquiryData
Points to the SCSI inquiry data for the tape device.
ModeCapabilitiesPage
Points to a buffer that contains low-level information for the tape device. The format of this page is defined by the QIC 157 standard and is subject to change. This is NULL if the device does not support a mode capabilities page.

Return Value

None

Comments

A tape miniclass driver requests a minitape extension by specifying a nonzero value for MinitapeExtensionSize in the TAPE_INIT_DATA_EX structure it passes to TapeClassInitialize from its DriverEntry routine. A miniclass driver defines the structure and contents of the minitape extension and typically uses it to store inquiry data for the devices it supports.

The tape class driver allocates the minitape extension and supplies it subsequently in calls to to the tape miniclass driver's routines that handle the device-specific aspects of device-control requests and to the miniclass driver's OPTIONAL TapeMiniTapeError routine.

TapeMiniExtensionInit initializes the minitape extension, and the miniclass driver uses this area to maintain runtime state for its device. The tape class driver passes InquiryData and a ModeCapabilitiesPage to this routine because those structures contain information that a tape miniclass driver might want to store in the minitape extension.

See Also

DriverEntry of Tape Miniclass Driver, TAPE_INIT_DATA_EX, TapeClassInitialize


TapeMiniGetDriveParameters

TapeMiniGetDriveParameters handles the device-specific aspects of an IOCTL_TAPE_GET_DRIVE_PARAMS request. This routine is required.

TAPE_STATUS
  TapeMiniGetDriveParameters(
    IN OUT PVOID  MinitapeExtension  OPTIONAL,
    IN OUT PVOID  CommandExtension   OPTIONAL,
    IN OUT PVOID  CommandParameters,
    IN OUT PSCSI_REQUEST_BLOCK  Srb,
    IN ULONG  CallNumber,
    IN TAPE_STATUS  StatusOfLastCommand  OPTIONAL,
    IN OUT PULONG  RetryFlags  OPTIONAL
    );

Parameters

MinitapeExtension
Points to the driver-specific minitape extension. This is NULL if the miniclass driver did not request a minitape extension when it initialized.
CommandExtension
Points to the command extension. This is NULL if the miniclass driver did not request a command extension when it initialized.
CommandParameters
Points to a caller-allocated buffer for a TAPE_GET_DRIVE_PARAMETERS structure which the miniclass driver fills in before returning TAPE_STATUS_SUCCESS. This structure is defined as follows:
typedef struct _TAPE_GET_DRIVE_PARAMETERS {
    BOOLEAN ECC;
    BOOLEAN Compression;
    BOOLEAN DataPadding;
    BOOLEAN ReportSetmarks;
    ULONG DefaultBlockSize;
    ULONG MaximumBlockSize;
    ULONG MinimumBlockSize;
    ULONG MaximumPartitionCount;
    ULONG FeaturesLow;
    ULONG FeaturesHigh;
    ULONG EOTWarningZoneSize;
} TAPE_GET_DRIVE_PARAMETERS, *PTAPE_GET_DRIVE_PARAMETERS;
ECC
TRUE if the device uses hardware error correction.
Compression
TRUE if compression is enabled on a device that supports it. When compression is enabled, the device compresses data prior to writing it.
DataPadding
TRUE if data padding is enabled on a device that supports it. When padding is enabled, the device pads data with zeroes to keep the tape streaming until data is ready.
ReportSetmarks
TRUE if reporting setmarks is enabled on a device that supports it. The device reports setmarks encountered during read or space operations.
DefaultBlockSize
The default block size, in bytes.
MaximumBlockSize
The maximum block size, in bytes, of either the tape device or the underlying HBA, whichever is less.
MinimumBlockSize
The minimum block size, in bytes.
MaximumPartitionCount
The maximum number of partitions the device supports.
FeaturesLow
Features supported by this drive. The miniport sets TAPE_DRIVE_XXX flags for features supported by the drive and clears flags for features not supported. Callers can use the TAPE_DRIVE_XXX masks defined in minitape.h to determine whether a drive supports a particular feature.
FeaturesHigh
Additional features supported by this drive if TAPE_DRIVE_HIGH_FEATURES is set in FeaturesLow. The miniport sets TAPE_DRIVE_XXX flags for features supported by the drive and clears flags for features not supported. Callers can use the TAPE_DRIVE_XXX masks defined in minitape.h to determine whether a drive supports a particular feature.
EOTWarningZoneSize
The size of the early warning zone toward the end of the tape in which the device returns a check condition when it enters the zone.
Srb
Points to an SRB allocated and partially filled in by the tape class driver. TapeMiniGetDriveParameters must fill in the CDB in the SRB. TapeMiniGetDriveParameters might fill in other SRB members, depending on the requirements of its device(s).
CallNumber
Specifies the number of times the routine has been called to process a given tape command. CallNumber is zero the first time this routine is called and is incremented until the miniclass driver returns a TAPE_STATUS_XXX that indicates the command is complete.
StatusOfLastCommand
Specifies the status of the last command. In the first call to TapeMiniCreatePartition to process a given request, StatusOfLastCommand is TAPE_STATUS_SUCCESS. In subsequent calls, StatusOfLastCommand is either TAPE_STATUS_SUCCESS or an error status if an error occurred and the tape miniclass driver set RETURN_ERRORS in RetryFlags in the previous call.
RetryFlags
Points to a variable that specifies what action the tape class driver should take when a tape device reports an error.

The low-order word specifies the number of retries to perform in the event of a SCSI command failure. The default is zero (no retries).

The high-order word contains flags that specify how the tape class driver should return control if an error occurs:

  • If RETURN_ERRORS and IGNORE_ERRORS are clear (the default), the tape class driver returns a failure status to the original requester.
  • If the miniclass driver sets RETURN_ERRORS, the tape class driver calls TapeMiniGetDriveParameters with StatusOfLastCommand set to a failure status.
  • If the miniclass driver sets IGNORE_ERRORS, the tape class driver converts a failure status to success and calls TapeMiniGetDriveParameters with StatusOfLastCommand set to success.

Return Value

TAPE_STATUS_SEND_SRB_AND_CALLBACK
Indicates to the tape class driver that the SRB has been filled in and is ready to be sent to the target device. By default, the tape class driver TapeMiniGetDriveParameters again only if the SRB succeeds. A miniclass driver can modify the default behavior by setting RetryFlags before returning from TapeMiniGetDriveParameters.

TAPE_STATUS_CALLBACK
Directs the tape class driver to increment CallNumber and call TapeMiniGetDriveParameters again without sending an SRB to the tape device.

TAPE_STATUS_CHECK_TEST_UNIT_READY
Directs the tape class driver to fill in an SRB for the TEST UNIT READY command and send the SRB to the device.

TAPE_STATUS_XXX
Any other return code indicates to the tape class driver that the command is complete and indicates success, failure, or warning. Possible completion return values for this routine include, but are not limited to:

TAPE_STATUS_SUCCESS
TAPE_STATUS_INSUFFICIENT_RESOURCES

Comments

TapeMiniGetDriveParameters gets tape drive parameters by filling in the CDB in an SRB passed by the tape class driver. Getting drive parameters typically requires a series of SRBs to complete the operation. After TapeMiniGetDriveParameters fills in a given SRB and returns, the tape class driver sends the SRB to the target device and, depending on the result of the SRB and the value of RetryFlags, calls TapeMiniGetDriveParameters again.

TapeMiniGetDriveParameters must fill in the following members in the SRB before returning to the tape class driver:

  • Cdb – Points to the SCSI CDB for the command. Clear the CDB with TapeClassZeroMemory before filling it in.
  • CdbLength – Specifies the number of bytes in the CDB.

TapeMiniGetDriveParameters might also fill in the following members in the SRB:

  • DataBuffer – Points to the data buffer to be transferred. Use TapeClassAllocateSrbBuffer to allocate a DataBuffer of length greater than or equal to DataTransferLength.
  • DataTransferLength – Specifies the number of bytes to be transferred by this SRB. This member is set by TapeClassAllocateSrbBuffer.
  • TimeOutValue – Specifies a timeout value for this command, overriding the default timeout value from the tape class driver's device extension.
  • SrbFlags – Specifies a flag for this command. The tape miniclass driver must set SRB_FLAGS_DATA_OUT if the SRB is sending data to the tape drive. This member can be zero if the SRB is requesting data from the tape drive or if no data is being transferred by the command.

See Also

SCSI_REQUEST_BLOCK, TapeClassAllocateSrbBuffer, TapeClassZeroMemory


TapeMiniGetMediaParameters

TapeMiniGetMediaParameters handles the device-specific aspects of an IOCTL_TAPE_GET_MEDIA_PARAMS request. This routine is required.

TAPE_STATUS
  TapeMiniGetMediaParameters(
    IN OUT PVOID  MinitapeExtension  OPTIONAL,
    IN OUT PVOID  CommandExtension  OPTIONAL,
    IN OUT PVOID  CommandParameters,
    IN OUT PSCSI_REQUEST_BLOCK  Srb,
    IN ULONG  CallNumber,
    IN TAPE_STATUS  StatusOfLastCommand  OPTIONAL,
    IN OUT PULONG  RetryFlags  OPTIONAL
    );

Parameters

MinitapeExtension
Points to the driver-specific minitape extension. This is NULL if the miniclass driver did not request a minitape extension when it initialized.
CommandExtension
Points to the command extension. This is NULL if the miniclass driver did not request a command extension when it initialized.
CommandParameters
Points to a caller-allocated buffer for a TAPE_GET_MEDIA_PARAMETERS structure which the miniclass driver fills in before returning TAPE_STATUS_SUCCESS. This structure is defined as follows:
typedef struct _TAPE_GET_MEDIA_PARAMETERS {
    LARGE_INTEGER Capacity;
    LARGE_INTEGER Remaining;
    ULONG BlockSize;
    ULONG PartitionCount;
    BOOLEAN WriteProtected;
} TAPE_GET_MEDIA_PARAMETERS, *PTAPE_GET_MEDIA_PARAMETERS;
Capacity
The total number of bytes of user data the tape can hold.
Remaining
The number of bytes from the current position to the end of the tape.
BlockSize
The block size, in bytes, or zero if the drive is using variable block size.
PartitionCount
The number of partitions on the tape. If the tape is not partitioned, PartitionCount is 1.
WriteProtected
TRUE if the tape is write-protected.
Srb
Points to an SRB allocated and partially filled in by the tape class driver. TapeMiniGetMediaParameters must fill in the CDB in the SRB. TapeMiniGetMediaParameters might fill in other SRB members, depending on the requirements of its device(s).
CallNumber
Specifies the number of times the routine has been called to process a given tape command. CallNumber is zero the first time this routine is called and is incremented for each subsequent call until the miniclass driver returns a TAPE_STATUS_XXX that indicates the command is complete.
StatusOfLastCommand
Specifies the status of the last command. In the first call to TapeMiniCreatePartition to process a given request, StatusOfLastCommand is TAPE_STATUS_SUCCESS. In subsequent calls, StatusOfLastCommand is either TAPE_STATUS_SUCCESS or an error status if an error occurred and the tape miniclass driver set RETURN_ERRORS in RetryFlags in the previous call.
RetryFlags
Points to a variable that specifies what action the tape class driver should take when a tape device reports an error.

The low-order word specifies the number of retries to perform in the event of a SCSI command failure. The default is zero (no retries).

The high-order word contains flags that specify how the tape class driver should return control if an error occurs:

  • If RETURN_ERRORS and IGNORE_ERRORS are clear (the default), the tape class driver returns a failure status to the original requester.
  • If the miniclass driver sets RETURN_ERRORS, the tape class driver calls TapeMiniGetMediaParameters with StatusOfLastCommand set to a failure status.
  • If the miniclass driver sets IGNORE_ERRORS, the tape class driver converts a failure status to success and calls TapeMiniGetMediaParameters with StatusOfLastCommand set to success.

Return Value

TAPE_STATUS_SEND_SRB_AND_CALLBACK
Indicates to the tape class driver that the SRB has been filled in and is ready to be sent to the target device. By default, the tape class driver calls TapeMiniGetMediaParameters again only if the SRB succeeds. A miniclass driver can modify the default behavior by setting RetryFlags before returning from TapeMiniGetMediaParameters.

TAPE_STATUS_CALLBACK
Directs the tape class driver to increment CallNumber and call TapeMiniGetMediaParameters again without sending an SRB to the tape device.

TAPE_STATUS_CHECK_TEST_UNIT_READY
Directs the tape class driver to fill in an SRB for the TEST UNIT READY command and send the SRB to the device.

TAPE_STATUS_XXX
Any other return code indicates to the tape class driver that the command is complete and indicates success, failure, or warning. Possible completion return values for this routine include, but are not limited to:

TAPE_STATUS_SUCCESS
TAPE_STATUS_DATA_OVERRUN
TAPE_STATUS_INSUFFICIENT_RESOURCES

Comments

TapeMiniGetMediaParameters gets tape media parameters by filling in the CDB in an SRB passed by the tape class driver. Getting media parameters typically requires more than one SRB to complete the operation, starting with a test unit ready which the miniclass driver requests by returning TAPE_STATUS_CHECK_TEST_UNIT_READY the first time the tape class driver calls the routine.

After TapeMiniGetMediaParameters fills in a given SRB and returns, the tape class driver sends the SRB to the device and, depending on the result of the SRB and the value of RetryFlags, calls TapeMiniGetMediaParameters again.

TapeMiniGetMediaParameters must fill in the following members in the SRB before returning to the tape class driver:

  • Cdb – Points to the SCSI CDB for the command. Clear the CDB with TapeClassZeroMemory before filling it in.
  • CdbLength – Specifies the number of bytes in the CDB.

TapeMiniGetMediaParameters might also fill in the following members in the SRB:

  • DataBuffer – Points to the data buffer to be transferred. Use TapeClassAllocateSrbBuffer to allocate a DataBuffer of length greater than or equal to DataTransferLength.
  • DataTransferLength – Specifies the number of bytes to be transferred in the SRB. This member is set by TapeClassAllocateSrbBuffer.
  • TimeOutValue – Specifies a timeout value for this command, overriding the default timeout value from the tape class driver's device extension.
  • SrbFlags – Specifies a flag for this command. The tape miniclass driver must set SRB_FLAGS_DATA_OUT if the SRB is sending data to the tape drive. This member can be zero if the SRB is requesting data from the tape drive or if no data is being transferred by the command.

See Also

SCSI_REQUEST_BLOCK, TapeClassAllocateSrbBuffer, TapeClassZeroMemory


TapeMiniGetMediaTypes

TapeMiniGetMediaTypes handles the device-specific aspects of an IOCTL_STORAGE_GET_MEDIA_TYPES_EX request. This routine is required.

TAPE_STATUS
  TapeMiniGetMediaTypes(
    IN OUT PVOID  MinitapeExtension  OPTIONAL,
    IN OUT PVOID  CommandExtension  OPTIONAL,
    IN OUT PVOID  CommandParameters,
    IN OUT PSCSI_REQUEST_BLOCK  Srb,
    IN ULONG  CallNumber,
    IN TAPE_STATUS  StatusOfLastCommand  OPTIONAL,
    IN OUT PULONG  RetryFlags  OPTIONAL
    );

Parameters

MinitapeExtension
Points to the driver-specific minitape extension. This is NULL if the miniclass driver did not request a minitape extension when it initialized.
CommandExtension
Points to the command extension. This is NULL if the miniclass driver did not request a command extension when it initialized.
CommandParameters
Points to a caller-allocated buffer for a GET_MEDIA_TYPES structure which the miniclass driver fills in with the device type, the number of media types supported by the device, and an array of one DEVICE_MEDIA_INFO structure for each supported media type before returning TAPE_STATUS_SUCCESS. The tape class driver validates the buffer size before calling TapeMiniGetMediaTypes, using the value of MediaTypesSupported set by the miniclass driver in the TAPE_INIT_DATA_EX structure when it initialized.
Srb
Points to an SRB allocated and partially filled in by the tape class driver. TapeMiniGetMediaTypes must fill in the CDB in the SRB. TapeMiniGetMediaTypes might fill in other SRB members, depending on the requirements of its device(s).
CallNumber
Specifies the number of times the routine has been called to process a given tape command. CallNumber is zero the first time this routine is called and is incremented for each subsequent call until the miniclass driver returns a TAPE_STATUS_XXX that indicates the command is complete.
StatusOfLastCommand
Specifies the status of the last command. In the first call to TapeMiniCreatePartition to process a given request, StatusOfLastCommand is TAPE_STATUS_SUCCESS. In subsequent calls, StatusOfLastCommand is either TAPE_STATUS_SUCCESS or an error status if an error occurred and the tape miniclass driver set RETURN_ERRORS in RetryFlags in the previous call.
RetryFlags
Points to a variable that specifies what action the tape class driver should take when a tape device reports an error.

The low-order word specifies the number of retries to perform in the event of a SCSI command failure. The default is zero (no retries).

The high-order word contains flags that specify how the tape class driver should return control if an error occurs:

  • If RETURN_ERRORS and IGNORE_ERRORS are clear (the default), the tape class driver returns a failure status to the original requester.
  • If the miniclass driver sets RETURN_ERRORS, the tape class driver calls TapeMiniGetMediaTypes with StatusOfLastCommand set to a failure status.
  • If the miniclass driver sets IGNORE_ERRORS, the tape class driver converts a failure status to success and calls TapeMiniGetMediaTypes with StatusOfLastCommand set to success.

Return Value

TAPE_STATUS_SEND_SRB_AND_CALLBACK
Indicates to the tape class driver that the SRB has been filled in and is ready to be sent to the target device. By default, the tape class driver calls TapeMiniGetMediaTypes again only if the SRB succeeds. A miniclass driver can modify the default behavior by setting RetryFlags before returning from TapeMiniGetMediaTypes.

TAPE_STATUS_CALLBACK
Directs the tape class driver to increment CallNumber and call TapeMiniGetMediaTypes again without sending an SRB to the tape device.

TAPE_STATUS_CHECK_TEST_UNIT_READY
Directs the tape class driver to fill in an SRB for the TEST UNIT READY command and send the SRB to the device.

TAPE_STATUS_XXX
Any other return code indicates to the tape class driver that the command is complete and indicates success, failure, or warning. Possible completion return values for this routine include, but are not limited to:

TAPE_STATUS_SUCCESS
TAPE_STATUS_DATA_OVERRUN
TAPE_STATUS_INSUFFICIENT_RESOURCES

Comments

TapeMiniGetMediaTypes gets information about the media types supported by a tape device by filling in the CDB in an SRB passed by the tape class driver. Getting media types typically requires more than one SRB to complete the operation, starting with a test unit ready which the miniclass driver requests by returning TAPE_STATUS_CHECK_TEST_UNIT_READY the first time the tape class driver calls the routine.

TapeMiniGetMediaTypes must fill in the following members in an SRB before returning to the tape class driver:

  • Cdb – Points to the CDB for the command.
  • CdbLength – Specifies the number of bytes in the CDB.

TapeMiniGetMediaTypes might also fill in the following members in the SRB:

  • DataBuffer – Points to the data buffer to be transferred. Use TapeClassAllocateSrbBuffer to allocate a DataBuffer of length greater than or equal to DataTransferLength.
  • DataTransferLength – Specifies the number of bytes to be transferred in the SRB. This member is set by TapeClassAllocateSrbBuffer.
  • TimeOutValue – Specifies a timeout value for this command, overriding the default timeout value from the tape class driver's device extension.
  • SrbFlags – Specifies a flag for this command. The tape miniclass driver must set SRB_FLAGS_DATA_OUT if the SRB is sending data to the tape drive. This member can be zero if the SRB is requesting data from the tape drive or if no data is being transferred by the command.

See Also

DEVICE_MEDIA_INFO, SCSI_REQUEST_BLOCK, TAPE_INIT_DATA_EX, TapeClassAllocateSrbBuffer, TapeClassInitialize, TapeClassZeroMemory


TapeMiniGetPosition

TapeMiniGetPosition handles the device-specific aspects of an IOCTL_TAPE_GET_POSITION request. This routine is required.

TAPE_STATUS
  TapeMiniGetPosition(
    IN OUT PVOID  MinitapeExtension  OPTIONAL,
    IN OUT PVOID  CommandExtension  OPTIONAL,
    IN OUT PVOID  CommandParameters,
    IN OUT PSCSI_REQUEST_BLOCK  Srb,
    IN ULONG  CallNumber,
    IN TAPE_STATUS  StatusOfLastCommand  OPTIONAL,
    IN OUT PULONG  RetryFlags  OPTIONAL
    );

Parameters

MinitapeExtension
Points to the driver-specific minitape extension. This is NULL if the miniclass driver did not request a minitape extension when it initialized.
CommandExtension
Points to the command extension. This is NULL if the miniclass driver did not request a command extension when it initialized.
CommandParameters
Points to a caller-allocated buffer that contains a TAPE_GET_POSITION structure in which Type is filled in by the caller. The miniclass driver fills in Partition and Offset before returning TAPE_STATUS_SUCCESS. This structure is defined as follows:
typedef struct _TAPE_GET_POSITION {
    ULONG Type;
    ULONG Partition;
    LARGE_INTEGER Offset;
} TAPE_GET_POSITION, *PTAPE_GET_POSITION;
Type
The type of position requested. This member can be TAPE_ABSOLUTE_POSITION, TAPE_LOGICAL_POSITION, or TAPE_PSEUDO_LOGICAL_POSITION.
Partition
The number of the partition where the current position is located.
Offset
The number of bytes from the beginning of the partition to the current position.
Srb
Points to an SRB allocated and partially filled in by the tape class driver. TapeMiniGetPosition must fill in the CDB in the SRB. TapeMiniGetPosition might fill in other SRB members, depending on the requirements of its device(s).
CallNumber
Specifies the number of times the routine has been called to process a given tape command. CallNumber is zero the first time this routine is called and is incremented for each subsequent call until the miniclass driver returns a TAPE_STATUS_XXX that indicates the command is complete.
StatusOfLastCommand
Specifies the status of the last command. In the first call to TapeMiniCreatePartition to process a given request, StatusOfLastCommand is TAPE_STATUS_SUCCESS. In subsequent calls, StatusOfLastCommand is either TAPE_STATUS_SUCCESS or an error status if an error occurred and the tape miniclass driver set RETURN_ERRORS in RetryFlags in the previous call.
RetryFlags
Points to a variable that specifies what action the tape class driver should take when a tape device reports an error.

The low-order word specifies the number of retries to perform in the event of a SCSI command failure. The default is zero (no retries).

The high-order word contains flags that specify how the tape class driver should return control if an error occurs:

  • If RETURN_ERRORS and IGNORE_ERRORS are clear (the default), the tape class driver returns a failure status to the original requester.
  • If the miniclass driver sets RETURN_ERRORS, the tape class driver calls TapeMiniGetPosition with StatusOfLastCommand set to a failure status.
  • If the miniclass driver sets IGNORE_ERRORS, the tape class driver converts a failure status to success and calls TapeMiniGetPosition with StatusOfLastCommand set to success.

Return Value

TAPE_STATUS_SEND_SRB_AND_CALLBACK
Indicates to the tape class driver that the SRB has been filled in and is ready to be sent to the target device. By default, the tape class driver calls TapeMiniGetPosition again only if the SRB succeeds. A miniclass driver can modify the default behavior by setting RetryFlags before returning from TapeMiniGetPosition.

TAPE_STATUS_CALLBACK
Directs the tape class driver to increment CallNumber and call TapeMiniGetPosition again without sending an SRB to the tape device.

TAPE_STATUS_CHECK_TEST_UNIT_READY
Directs the tape class driver to fill in an SRB for the TEST UNIT READY command and send the SRB to the device.

TAPE_STATUS_XXX
Any other return code indicates to the tape class driver that the command is complete and indicates success, failure, or warning. Possible completion return values for this routine include, but are not limited to:

TAPE_STATUS_SUCCESS
TAPE_STATUS_INSUFFICIENT_RESOURCES
TAPE_STATUS_INVALID_DEVICE_REQUEST
TAPE_STATUS_NOT_IMPLEMENTED

Comments

TapeMiniGetPosition reads the position of a tape by filling in the CDB in an SRB passed by the tape class driver. Reading tape position typically requires more than one SRB to complete the operation, often starting with a test unit ready which the miniclass driver requests by returning TAPE_STATUS_CHECK_TEST_UNIT_READY the first time the tape class driver calls the routine.

TapeMiniGetPosition must fill in the following members in the SRB before returning to the tape class driver:

  • Cdb – Points to the SCSI CDB for the command. Clear the CDB with TapeClassZeroMemory before filling it in.
  • CdbLength – Specifies the number of bytes in the CDB.

TapeMiniGetPosition might also fill in the following members in the SRB:

  • DataBuffer – Points to the data buffer to be transferred. Use TapeClassAllocateSrbBuffer to allocate a DataBuffer of length greater than or equal to DataTransferLength.
  • DataTransferLength – Specifies the number of bytes to be transferred in the SRB. This member is set by TapeClassAllocateSrbBuffer.
  • TimeOutValue – Specifies a timeout value for this command, overriding the default timeout value from the tape class driver's device extension.
  • SrbFlags – Specifies a flag for this command. The tape miniclass driver must set SRB_FLAGS_DATA_OUT if the SRB is sending data to the tape drive. This member can be zero if the SRB is requesting data from the tape drive or if no data is being transferred by the command.

See Also

SCSI_REQUEST_BLOCK, TapeClassAllocateSrbBuffer, TapeClassZeroMemory


TapeMiniGetStatus

TapeMiniGetStatus handles the device-specific aspects of an IOCTL_TAPE_GET_STATUS request. This routine is required.

TAPE_STATUS
  TapeMiniGetStatus(
    IN OUT PVOID  MinitapeExtension  OPTIONAL,
    IN OUT PVOID  CommandExtension  OPTIONAL,
    IN OUT PVOID  CommandParameters,
    IN OUT PSCSI_REQUEST_BLOCK  Srb,
    IN ULONG  CallNumber,
    IN TAPE_STATUS  StatusOfLastCommand  OPTIONAL,
    IN OUT PULONG  RetryFlags  OPTIONAL
    );

Parameters

MinitapeExtension
Points to the driver-specific minitape extension. This is NULL if the miniclass driver did not request a minitape extension when it initialized.
CommandExtension
Points to the command extension. This is NULL if the miniclass driver did not request a command extension when it initialized.
CommandParameters
NULL for this routine.
Srb
Points to an SRB allocated and partially filled in by the tape class driver. If it uses the SRB, TapeMiniGetStatus must fill in the CDB in the SRB. TapeMiniGetStatus might fill in other SRB members, depending on the requirements of its device(s).
CallNumber
Specifies the number of times the routine has been called to process a given tape command. CallNumber is zero the first time this routine is called and is incremented for each subsequent call until the miniclass driver returns a TAPE_STATUS_XXX that indicates the command is complete.
StatusOfLastCommand
Specifies the status of the last command. In the first call to TapeMiniCreatePartition to process a given request, StatusOfLastCommand is TAPE_STATUS_SUCCESS. In subsequent calls, StatusOfLastCommand is either TAPE_STATUS_SUCCESS or an error status if an error occurred and the tape miniclass driver set RETURN_ERRORS in RetryFlags in the previous call.
RetryFlags
Points to a variable that specifies what action the tape class driver should take when a tape device reports an error.

The low-order word specifies the number of retries to perform in the event of a SCSI command failure. The default is zero (no retries).

The high-order word contains flags that specify how the tape class driver should return control if an error occurs:

  • If RETURN_ERRORS and IGNORE_ERRORS are clear (the default), the tape class driver returns a failure status to the original requester.
  • If the miniclass driver sets RETURN_ERRORS, the tape class driver calls TapeMiniGetStatus with StatusOfLastCommand set to a failure status.
  • If the miniclass driver set IGNORE_ERRORS, the tape class driver converts a failure status to success and calls TapeMiniGetStatus with StatusOfLastCommand set to success.

Return Value

TAPE_STATUS_SEND_SRB_AND_CALLBACK
Indicates to the tape class driver that the SRB has been filled in and is ready to be sent to the target device. By default, the tape class driver calls TapeMiniGetStatus again only if the SRB succeeds. A miniclass driver can modify the default behavior by setting RetryFlags before returning from TapeMiniGetStatus.

TAPE_STATUS_CALLBACK
Directs the tape class driver to increment CallNumber and call TapeMiniGetStatus again without sending an SRB to the tape device.

TAPE_STATUS_CHECK_TEST_UNIT_READY
Directs the tape class driver to fill in an SRB for the TEST UNIT READY command and send the SRB to the device.

TAPE_STATUS_REQUIRES_CLEANING
Indicates to the tape class driver that the drive requires cleaning. A tape miniclass driver would return this status for a device that indicates the need for cleaning in sense data rather than as an error.

TAPE_STATUS_XXX
Any other return code indicates to the tape class driver that the command is complete and indicates success, failure, or warning. Possible completion return values for this routine include, but are not limited to:

TAPE_STATUS_SUCCESS

Comments

TapeMiniGetStatus reads the status of a tape device, typically by directing the tape class driver to issue a test unit ready command.

If a device indicates whether a drive needs cleaning in sense data (as opposed to reporting the need for cleaning as an error, which a miniclass driver would handle in its TapeMiniTapeError routine), TapeMiniGetStatus fills in the CDB in the SRB passed by the tape class driver to obtain the sense data and, if necessary, returns TAPE_STATUS_REQUIRES_CLEANING.

TapeMiniGetStatus must fill in the following members in the SRB before returning to the tape class driver:

  • Cdb – Points to the SCSI CDB for the command. Clear the CDB with TapeClassZeroMemory before filling it in.
  • CdbLength – Specifies the number of bytes in the CDB.

TapeMiniGetStatus might also fill in the following members in the SRB:

  • DataBuffer – Points to the data buffer to be transferred. Use TapeClassAllocateSrbBuffer to allocate a DataBuffer of length greater than or equal to DataTransferLength.
  • DataTransferLength – Specifies the number of bytes to be transferred in the SRB. This member is set by TapeClassAllocateSrbBuffer.
  • TimeOutValue – Specifies a timeout value for this command, overriding the default timeout value from the tape class driver's device extension.
  • SrbFlags – Specifies a flag for this command. The tape miniclass driver must set SRB_FLAGS_DATA_OUT if the SRB is sending data to the tape drive. This member can be zero if the SRB is requesting data from the tape drive or if no data is being transferred by the command.

See Also

SCSI_REQUEST_BLOCK, TapeClassAllocateSrbBuffer, TapeClassZeroMemory


TapeMiniPrepare

TapeMiniPrepare handles the device-specific aspects of an IOCTL_TAPE_PREPARE request. This routine is required.

TAPE_STATUS
  TapeMiniPrepare(
    IN OUT PVOID  MinitapeExtension  OPTIONAL,
    IN OUT PVOID  CommandExtension  OPTIONAL,
    IN OUT PVOID  CommandParameters,
    IN OUT PSCSI_REQUEST_BLOCK  Srb,
    IN ULONG  CallNumber,
    IN TAPE_STATUS  StatusOfLastCommand  OPTIONAL,
    IN OUT PULONG  RetryFlags  OPTIONAL
    );

Parameters

MinitapeExtension
Points to the driver-specific minitape extension. This is NULL if the miniclass driver did not request a minitape extension when it initialized.
CommandExtension
Points to the command extension. This is NULL if the miniclass driver did not request a command extension when it initialized.
CommandParameters
Points to a buffer that contains a TAPE_PREPARE structure, which is defined as follows:
typedef struct _TAPE_PREPARE {
    ULONG Operation;
    BOOLEAN Immediate;
} TAPE_PREPARE, *PTAPE_PREPARE;
Operation
The type of operation to perform. This member can be one of the following:

TAPE_LOAD
TAPE_UNLOAD
TAPE_TENSION
TAPE_LOCK
TAPE_UNLOCK
TAPE_FORMAT

Immediate
TRUE if the target device should return status immediately, or FALSE if the device should return status after the operation is complete.
Srb
Points to an SRB allocated and partially filled in by the tape class driver. TapeMiniPrepare must fill in the CDB in the SRB. TapeMiniPrepare might fill in other SRB members, depending on the requirements of its device(s).
CallNumber
Specifies the number of times the routine has been called to process a given tape command. CallNumber is zero the first time this routine is called and is incremented for each subsequent call until the miniclass driver returns a TAPE_STATUS_XXX that indicates the command is complete.
StatusOfLastCommand
Specifies the status of the last command. In the first call to TapeMiniCreatePartition to process a given request, StatusOfLastCommand is TAPE_STATUS_SUCCESS. In subsequent calls, StatusOfLastCommand is either TAPE_STATUS_SUCCESS or an error status if an error occurred and the tape miniclass driver set RETURN_ERRORS in RetryFlags in the previous call.
RetryFlags
Points to a variable that specifies what action the tape class driver should take when a tape device reports an error.

The low-order word specifies the number of retries to perform in the event of a SCSI command failure. The default is zero (no retries).

The high-order word contains flags that specify how the tape class driver should return control if an error occurs:

  • If RETURN_ERRORS and IGNORE_ERRORS are clear (the default), the tape class driver returns a failure status to the original requester.
  • If the miniclass driver sets RETURN_ERRORS, the tape class driver calls TapeMiniPrepare with StatusOfLastCommand set to a failure status.
  • If the miniclass driver sets IGNORE_ERRORS, the tape class driver converts a failure status to success and calls TapeMiniPrepare with StatusOfLastCommand set to success.

Return Value

TAPE_STATUS_SEND_SRB_AND_CALLBACK
Indicates to the tape class driver that the SRB has been filled in and is ready to be sent to the target device. By default, the tape class driver calls TapeMiniPrepare again only if the SRB succeeds. A miniclass driver can modify the default behavior by setting RetryFlags before returning from TapeMiniPrepare.

TAPE_STATUS_CALLBACK
Directs the tape class driver to increment CallNumber and call TapeMiniPrepare again without sending an SRB to the tape device.

TAPE_STATUS_CHECK_TEST_UNIT_READY
Directs the tape class driver to fill in an SRB for the TEST UNIT READY command and send the SRB to the device.

TAPE_STATUS_XXX
Any other return code indicates to the tape class driver that the command is complete and indicates success, failure, or warning. Possible completion return values for this routine include, but are not limited to:

TAPE_STATUS_SUCCESS
TAPE_STATUS_NOT_IMPLEMENTED

Comments

TapeMiniPrepare prepares a tape by filling in the CDB in an SRB passed by the tape class driver. If the device supports the requested operation, preparing a tape typically requires one SRB. After TapeMiniPrepare fills in the SRB and returns, the tape class driver sends the SRB to the device and, depending on the result of the SRB and the value of RetryFlags, calls TapeMiniPrepare again.

TapeMiniPrepare must fill in the following members in the SRB before returning to the tape class driver:

  • Cdb – Points to the SCSI CDB for the command. Clear the CDB with TapeClassZeroMemory before filling it in.
  • CdbLength – Specifies the number of bytes in the CDB.

TapeMiniPrepare might also fill in the following members in the SRB:

  • DataBuffer – Points to the data buffer to be transferred. Use TapeClassAllocateSrbBuffer to allocate a DataBuffer of length greater than or equal to DataTransferLength.
  • DataTransferLength – Specifies the number of bytes to be transferred by this SRB. This member is set by TapeClassAllocateSrbBuffer.
  • TimeOutValue – Specifies a timeout value for this command, overriding the default timeout value from the tape class driver's device extension.
  • SrbFlags – Specifies a flag for this command. The tape miniclass driver must set SRB_FLAGS_DATA_OUT if the SRB is sending data to the tape drive. This member can be zero if the SRB is requesting data from the tape drive or if no data is being transferred by the command.

See Also

SCSI_REQUEST_BLOCK, TapeClassAllocateSrbBuffer, TapeClassZeroMemory


TapeMiniPreProcessReadWrite

TapeMiniPreProcessReadWrite is an OPTIONAL, special-purpose routine that performs any device-specific operations required before read and write operations. Most tape miniclass drivers do not need this routine.

TAPE_STATUS
  TapeMiniPreProcessReadWrite(
    IN OUT PVOID  MinitapeExtension  OPTIONAL,
    IN OUT PVOID  CommandExtension,
    IN OUT PVOID  CommandParameters,
    IN OUT PSCSI_REQUEST_BLOCK  Srb,
    IN ULONG  CallNumber,
    IN TAPE_STATUS  StatusOfLastCommand,
    IN OUT PULONG  RetryFlags
    );

Parameters

MinitapeExtension
Points to the driver-specific minitape extension. This is NULL if the miniclass driver did not request a minitape extension when it initialized.
CommandExtension
Not used.
CommandParameters
Not used.
Srb
Points to the SRB for the read or write operation. TapeMiniPreProcessReadWrite should not modify this SRB.
CallNumber
Not used.
StatusOfLastCommand
Not used.
RetryFlags
Not used.

Return Value

TapeMiniPreProcessReadWrite can return any TAPE_STATUS_XXX value. The tape class driver ignores the return value.

Comments

The activities of the TapeMiniPreProcessReadWrite routine are device specific. The routine can use the information passed to it by the class driver to implement special preprocessing for reads and writes. If a drive has limited capabilities, the driver may need this routine to maintain coherent state, for example.

If a tape miniclass driver sets a nonNULL entry point for this routine in the TAPE_INIT_DATA_EX structure it passes to TapeClassInitialize from its DriverEntry routine, the tape class driver calls it before each read and write operation on the tape device. The class driver does not expect any information back from this routine.

See Also

DriverEntry of Tape Miniclass Driver, TAPE_INIT_DATA_EX, TapeClassInitialize


TapeMiniSetDriveParameters

TapeMiniSetDriveParameters handles the device-specific aspects of an IOCTL_TAPE_SET_DRIVE_PARAMS request. This routine is required.

TAPE_STATUS
  TapeMiniSetDriveParameters(
    IN OUT PVOID  MinitapeExtension  OPTIONAL,
    IN OUT PVOID  CommandExtension  OPTIONAL,
    IN OUT PVOID  CommandParameters,
    IN OUT PSCSI_REQUEST_BLOCK  Srb,
    IN ULONG  CallNumber,
    IN TAPE_STATUS  StatusOfLastCommand  OPTIONAL,
    IN OUT PULONG  RetryFlags  OPTIONAL
    );

Parameters

MinitapeExtension
Points to the driver-specific minitape extension. This is NULL if the miniclass driver did not request a minitape extension when it initialized.
CommandExtension
Points to the command extension. This is NULL if the miniclass driver did not request a command extension when it initialized.
CommandParameters
Points to a buffer that contains a TAPE_SET_DRIVE_PARAMETERS structure that indicates the requested parameter settings. This structure is defined as follows:
typedef struct _TAPE_SET_DRIVE_PARAMETERS {
    BOOLEAN ECC;
    BOOLEAN Compression;
    BOOLEAN DataPadding;
    BOOLEAN ReportSetmarks;
    ULONG EOTWarningZoneSize;
} TAPE_SET_DRIVE_PARAMETERS, *PTAPE_SET_DRIVE_PARAMETERS;

The miniclass driver can ignore parameters its device does not support. The calling application is responsible for determining whether a device supports a particular feature before attempting to set it.

ECC
TRUE to use hardware error correction.
Compression
TRUE to compress data prior to writing it. If a drive must be at beginning of partition before it can set compression (TAPE_DRIVE_SET_CMP_BOP_ONLY), the caller is responsible for positioning the drive before attempting to set compression.
DataPadding
TRUE to pad data with zeroes to keep the tape streaming until data is ready.
ReportSetmarks
TRUE to report setmarks encountered during read or space operations.
EOTWarningZoneSize
The size of the early warning zone toward the end of the tape in which the drive returns a check condition when it enters the zone.
Srb
Points to an SRB allocated and partially filled in by the tape class driver. TapeMiniSetDriveParameters must fill in the CDB in the SRB. TapeMiniSetDriveParameters might fill in other SRB members, depending on the requirements of its device(s).
CallNumber
Specifies the number of times the routine has been called to process a given tape command. CallNumber is zero the first time this routine is called and is incremented for each subsequent call until the miniclass driver returns a TAPE_STATUS_XXX that indicates the command is complete.
StatusOfLastCommand
Specifies the status of the last command. In the first call to TapeMiniCreatePartition to process a given request, StatusOfLastCommand is TAPE_STATUS_SUCCESS. In subsequent calls, StatusOfLastCommand is either TAPE_STATUS_SUCCESS or an error status if an error occurred and the tape miniclass driver set RETURN_ERRORS in RetryFlags in the previous call.
RetryFlags
Points to a variable that specifies what action the tape class driver should take when a tape device reports an error.

The low-order word specifies the number of retries to perform in the event of a SCSI command failure. The default is zero (no retries).

The high-order word contains flags that specify how the tape class driver should return control if an error occurs:

  • If RETURN_ERRORS and IGNORE_ERRORS are clear (the default) the tape class driver returns a failure status to the original requester.
  • If the miniclass driver sets RETURN_ERRORS, the tape class driver calls TapeMiniSetDriveParameters with StatusOfLastCommand set to a failure status.
  • If the miniclass driver sets IGNORE_ERRORS, the tape class driver converts a failure status to success and calls TapeMiniSetDriveParameters with StatusOfLastCommand set to success.

Return Value

TAPE_STATUS_SEND_SRB_AND_CALLBACK
Indicates to the tape class driver that the SRB has been filled in and is ready to be sent to the target device. By default, the tape class driver calls TapeMiniSetDriveParameters again only if the SRB succeeds. A miniclass driver can modify the default behavior by setting RetryFlags before returning from TapeMiniSetDriveParameters.

TAPE_STATUS_CALLBACK
Directs the tape class driver to increment CallNumber and call TapeMiniSetDriveParameters again without sending an SRB to the tape device.

TAPE_STATUS_CHECK_TEST_UNIT_READY
Directs the tape class driver to fill in an SRB for the TEST UNIT READY command and send the SRB to the device.

TAPE_STATUS_XXX
Any other return code indicates to the tape class driver that the command is complete and indicates success, failure, or warning. Possible completion return values for this routine include, but are not limited to:

TAPE_STATUS_SUCCESS
TAPE_STATUS_INSUFFICIENT_RESOURCES
TAPE_STATUS_NOT_IMPLEMENTED

Comments

TapeMiniSetDriveParameters sets parameters for a tape device by filling in the CDB in an SRB passed by the tape class driver. Setting parameters typically involves a series of SRBs to complete the operation. After TapeMiniSetDriveParameters fills in a given SRB and returns, the tape class driver sends the SRB to the device and, depending on the result of the SRB and the value of RetryFlags, calls TapeMiniSetDriveParameters again.

TapeMiniSetDriveParameters must fill in the following members in the SRB before returning to the tape class driver:

  • Cdb – Points to the SCSI CDB for the command. Clear the CDB with TapeClassZeroMemory before filling it in.
  • CdbLength – Specifies the number of bytes in the CDB.

TapeMiniSetDriveParameters might also fill in the following members in the SRB:

  • DataBuffer – Points to the data buffer to be transferred. Use TapeClassAllocateSrbBuffer to allocate a DataBuffer of length greater than or equal to DataTransferLength.
  • DataTransferLength – Specifies the number of bytes to be transferred in the SRB. This member is set by TapeClassAllocateSrbBuffer.
  • TimeOutValue – Specifies a timeout value for this command, overriding the default timeout value from the tape class driver's device extension.
  • SrbFlags – Specifies a flag for this command. The tape miniclass driver must set SRB_FLAGS_DATA_OUT if the SRB is sending data to the tape drive. This member can be zero if the SRB is requesting data from the tape drive or if no data is being transferred by the command.

See Also

SCSI_REQUEST_BLOCK, TapeClassAllocateSrbBuffer, TapeClassZeroMemory, TapeMiniGetDriveParameters


TapeMiniSetMediaParameters

TapeMiniSetMediaParameters handles the device-specific aspects of an IOCTL_TAPE_SET_MEDIA_PARAMS request. This routine is required.

TAPE_STATUS
  TapeMiniSetMediaParameters(
    IN OUT PVOID  MinitapeExtension  OPTIONAL,
    IN OUT PVOID  CommandExtension  OPTIONAL,
    IN OUT PVOID  CommandParameters,
    IN OUT PSCSI_REQUEST_BLOCK  Srb,
    IN ULONG  CallNumber,
    IN TAPE_STATUS  StatusOfLastCommand  OPTIONAL,
    IN OUT PULONG  RetryFlags  OPTIONAL
    );

Parameters

MinitapeExtension
Points to the driver-specific minitape extension. This is NULL if the miniclass driver did not request a minitape extension when it initialized.
CommandExtension
Points to the command extension. This is NULL if the miniclass driver did not request a command extension when it initialized.
CommandParameters
Points to a buffer that contains a TAPE_SET_MEDIA_PARAMETERS structure, which is defined as follows:
typedef struct _TAPE_SET_MEDIA_PARAMETERS {
    ULONG BlockSize;
} TAPE_SET_MEDIA_PARAMETERS, *PTAPE_SET_MEDIA_PARAMETERS;
BlockSize
The requested block size, in bytes, or zero for variable block size in a drive that supports it.
Srb
Points to an SRB allocated and partially filled in by the tape class driver. TapeMiniSetMediaParameters must fill in the CDB in the SRB. TapeMiniSetMediaParameters might fill in other SRB members, depending on the requirements of its device(s).
CallNumber
Specifies the number of times the routine has been called to process a given tape command. CallNumber is zero the first time this routine is called and is incremented for each subsequent call until the miniclass driver returns a TAPE_STATUS_XXX that indicates the command is complete.
StatusOfLastCommand
Specifies the status of the last command. In the first call to TapeMiniCreatePartition to process a given request, StatusOfLastCommand is TAPE_STATUS_SUCCESS. In subsequent calls, StatusOfLastCommand is either TAPE_STATUS_SUCCESS or an error status if an error occurred and the tape miniclass driver set RETURN_ERRORS in RetryFlags in the previous call.
RetryFlags
Points to a variable that specifies what action the tape class driver should take when a tape device reports an error.

The low-order word specifies the number of retries to perform in the event of a SCSI command failure. The default is zero (no retries).

The high-order word contains flags that specify how the tape class driver should return control if an error occurs:

  • If RETURN_ERRORS and IGNORE_ERRORS are clear (the default) the tape class driver returns a failure status to the original requester.
  • If the miniclass driver sets RETURN_ERRORS, the tape class driver calls TapeMiniSetDriveParameters with StatusOfLastCommand set to a failure status.
  • If the miniclass driver sets IGNORE_ERRORS, the tape class driver converts a failure status to success and calls TapeMiniSetDriveParameters with StatusOfLastCommand set to success.

Return Value

TAPE_STATUS_SEND_SRB_AND_CALLBACK
Indicates to the tape class driver that the SRB has been filled in and is ready to be sent to the target device. By default, the tape class driver calls TapeMiniSetMediaParameters again only if the SRB succeeds. A miniclass driver can modify the default behavior by setting RetryFlags before returning from TapeMiniSetMediaParameters.

TAPE_STATUS_CALLBACK
Directs the tape class driver to increment CallNumber and call TapeMiniSetMediaParameters again without sending an SRB to the tape device.

TAPE_STATUS_CHECK_TEST_UNIT_READY
Directs the tape class driver to fill in an SRB for the TEST UNIT READY command and send the SRB to the device.

TAPE_STATUS_XXX
Any other return code indicates to the tape class driver that the command is complete and indicates success, failure, or warning. Possible completion return values for this routine include, but are not limited to:

TAPE_STATUS_SUCCESS
TAPE_STATUS_INSUFFICIENT_RESOURCES
TAPE_STATUS_NOT_IMPLEMENTED

Comments

TapeMiniSetMediaParameters sets the block size of a tape by filling in the CDB in an SRB passed by the tape class driver. Setting the block size typically requires more than one SRB to complete the operation, starting with a test unit ready which the miniclass driver requests by returning TAPE_STATUS_CHECK_TEST_UNIT_READY the first time the tape class driver calls the routine.

After TapeMiniSetMediaParameters fills in a given SRB and returns, the tape class driver sends the SRB to the device and, depending on the result of the SRB and the value of RetryFlags, calls TapeMiniSetMediaParameters again.

TapeMiniSetMediaParameters must fill in the following members in the SRB before returning to the tape class driver:

  • Cdb – Points to the SCSI CDB for the command. Clear the CDB with TapeClassZeroMemory before filling it in.
  • CdbLength – Specifies the number of bytes in the CDB.

TapeMiniSetMediaParameters might also fill in the following members in the SRB:

  • DataBuffer – Points to the data buffer to be transferred. Use TapeClassAllocateSrbBuffer to allocate a DataBuffer of length greater than or equal to DataTransferLength.
  • DataTransferLength – Specifies the number of bytes to be transferred in the SRB. This member is set by TapeClassAllocateSrbBuffer.
  • TimeOutValue – Specifies a timeout value for this command, overriding the default timeout value from the tape class driver's device extension.
  • SrbFlags – Specifies a flag for this command. The tape miniclass driver must set SRB_FLAGS_DATA_OUT if the SRB is sending data to the tape drive. This member can be zero if the SRB is requesting data from the tape drive or if no data is being transferred by the command.

See Also

SCSI_REQUEST_BLOCK, TapeClassAllocateSrbBuffer, TapeClassZeroMemory


TapeMiniSetPosition

TapeMiniSetPosition handles the device-specific aspects of an IOCTL_TAPE_SET_POSITION request. This routine is required.

TAPE_STATUS
  TapeMiniSetPosition(
    IN OUT PVOID  MinitapeExtension  OPTIONAL,
    IN OUT PVOID  CommandExtension  OPTIONAL,
    IN OUT PVOID  CommandParameters,
    IN OUT PSCSI_REQUEST_BLOCK  Srb,
    IN ULONG  CallNumber,
    IN TAPE_STATUS  StatusOfLastCommand  OPTIONAL,
    IN OUT PULONG  RetryFlags  OPTIONAL
    );

Parameters

MinitapeExtension
Points to the driver-specific minitape extension. This is NULL if the miniclass driver did not request a minitape extension when it initialized.
CommandExtension
Points to the command extension. This is NULL if the miniclass driver did not request a command extension when it initialized.
CommandParameters
Points to a buffer that contains a TAPE_SET_POSITION structure, which is defined as follows:
typedef struct _TAPE_SET_POSITION {
    ULONG Method;
    ULONG Partition;
    LARGE_INTEGER Offset;
    BOOLEAN Immediate;
} TAPE_SET_POSITION, *PTAPE_SET_POSITION;
Method
The method to set the position. This member can be one of the following:

TAPE_REWIND
Positions the tape to the beginning of the media.

TAPE_ABSOLUTE_BLOCK
TAPE_LOGICAL_BLOCK
TAPE_PSEUDO_LOGICAL_BLOCK
Positions the tape to the absolute, logical, or pseudological block address specified by Offset in the partition specified by Partition.

TAPE_SPACE_END_OF_DATA
Starting from the current position, positions the tape immediately after the end of data.

TAPE_SPACE_RELATIVE_BLOCKS
TAPE_SPACE_FILEMARKS
TAPE_SPACE_SEQUENTIAL_FMKS
TAPE_SPACE_SETMARKS
TAPE_SPACE_SEQUENTIAL_SMKS
Starting from the current position, positions the tape immediately after the number of blocks, filemarks, or setmarks specified by Offset in the partition specified by Partition.

Partition
The partition in which to set the tape's position. If the media is not partitioned, this member is zero.
Offset
If the specified method positions the tape to a block address, Offset specifies the byte offset into the specified partition. If the specified method is to skip blocks, filemarks, or setmarks, Offset specifies the number to skip. If Offset is zero, the tape is positioned at the beginning of the partition.
Immediate
TRUE if the target device should return status immediately or FALSE if the device should return status after the operation is complete.
Srb
Points to an SRB allocated and partially filled in by the tape class driver. TapeMiniSetPosition must fill in the CDB in the SRB. TapeMiniSetPosition might fill in other SRB members, depending on the requirements of its device(s).
CallNumber
Specifies the number of times the routine has been called to process a given tape command. CallNumber is zero the first time this routine is called and is incremented for each subsequent call until the miniclass driver returns a TAPE_STATUS_XXX that indicates the command is complete.
StatusOfLastCommand
Specifies the status of the last command. In the first call to TapeMiniCreatePartition to process a given request, StatusOfLastCommand is TAPE_STATUS_SUCCESS. In subsequent calls, StatusOfLastCommand is either TAPE_STATUS_SUCCESS or an error status if an error occurred and the tape miniclass driver set RETURN_ERRORS in RetryFlags in the previous call.
RetryFlags
Points to a variable that specifies what action the tape class driver should take when a tape device reports an error.

The low-order word specifies the number of retries to perform in the event of a SCSI command failure. The default is zero (no retries).

The high-order word contains flags that specify how the tape class driver should return control if an error occurs:

  • If RETURN_ERRORS and IGNORE_ERRORS are clear (the default) the tape class driver returns a failure status to the original requester.
  • If the miniclass driver sets RETURN_ERRORS, the tape class driver calls TapeMiniSetDriveParameters with StatusOfLastCommand set to a failure status.
  • If the miniclass driver sets IGNORE_ERRORS, the tape class driver converts a failure status to success and calls TapeMiniSetDriveParameters with StatusOfLastCommand set to success.

Return Value

TAPE_STATUS_SEND_SRB_AND_CALLBACK
Indicates to the tape class driver that the SRB has been filled in and is ready to be sent to the target device. By default, the tape class driver calls TapeMiniSetPosition again only if the SRB succeeds. A miniclass driver can modify the default behavior by setting RetryFlags before returning from TapeMiniSetPosition.

TAPE_STATUS_CALLBACK
Directs the tape class driver to increment CallNumber and call TapeMiniSetPosition again without sending an SRB to the tape device.

TAPE_STATUS_CHECK_TEST_UNIT_READY
Directs the tape class driver to fill in an SRB for the TEST UNIT READY command and send the SRB to the device.

TAPE_STATUS_XXX
Any other return code indicates to the tape class driver that the command is complete and indicates success, failure, or warning. Possible completion return values for this routine include, but are not limited to:

TAPE_STATUS_SUCCESS
TAPE_STATUS_INVALID_DEVICE_REQUEST
TAPE_STATUS_NOT_IMPLEMENTED

Comments

TapeMiniSetPosition sets the position of a tape by filling in the CDB in an SRB passed by the tape class driver. Setting the position typically requires one SRB. After TapeMiniSetPosition fills in the SRB and returns, the tape class driver sends the SRB to the device and, depending on the result of the SRB and the value of RetryFlags, calls TapeMiniSetPosition again. TapeMiniSetPosition then returns TAPE_STATUS_SUCCESS.

TapeMiniSetPosition must fill in the following members in the SRB before returning to the tape class driver:

  • Cdb – Points to the SCSI CDB for the command. Clear the CDB with TapeClassZeroMemory before filling it in.
  • CdbLength – Specifies the number of bytes in the CDB.

TapeMiniSetPosition might also fill in the following members in the SRB:

  • DataBuffer – Points to the data buffer to be transferred. Use TapeClassAllocateSrbBuffer to allocate a DataBuffer of length greater than or equal to DataTransferLength.
  • DataTransferLength – Specifies the number of bytes to be transferred in the SRB. This member is set by TapeClassAllocateSrbBuffer.
  • TimeOutValue – Specifies a timeout value for this command, overriding the default timeout value from the tape class driver's device extension.
  • SrbFlags – Specifies a flag for this command. The tape miniclass driver must set SRB_FLAGS_DATA_OUT if the SRB is sending data to the tape drive. This member can be zero if the SRB is requesting data from the tape drive or if no data is being transferred by the command.

If the tape miniclass driver stores the current partition in the minitape extension, TapeMiniSetPosition updates the extension before returning to the tape class driver with STATUS_SUCCESS.

See Also

SCSI_REQUEST_BLOCK, TapeClassAllocateSrbBuffer, TapeClassZeroMemory


TapeMiniTapeError

TapeMiniTapeError provides device-specific error handling when an SRB is completed with an error status. This routine is OPTIONAL.

VOID
  TapeMiniTapeError(
    IN PVOID  MinitapeExtension  OPTIONAL,
    IN PSCSI_REQUEST_BLOCK  Srb,
    IN OUT PTAPE_STATUS  TapeStatus
    );

Parameters

MinitapeExtension
Points to the driver-specific minitape extension. This is NULL if the miniclass driver did not request a minitape extension when it initialized.
Srb
Points to the SRB for the operation that failed.
TapeStatus
Points to the TAPE_STATUS set by the tape class driver. The tape miniclass driver can change the TAPE_STATUS or leave it unchanged.

Comments

Most tape miniclass drivers do not provide a TapeMiniTapeError routine because the TAPE_STATUS codes set by the tape class driver are appropriate.

For some devices, however, a tape miniclass driver can identify a more appropriate error code than the tape class driver. For example, if the tape class driver returns TAPE_STATUS_BUS_RESET, the tape miniclass driver might be able to determine that the real problem is more accurately represented by TAPE_STATUS_NO_MEDIA for some devices.

A tape miniclass driver OPTIONALly specifies an entry point for its TapeMiniTapeError routine in the TAPE_INIT_DATA_EX structure it passes to TapeClassInitialize from its DriverEntry routine. For such a miniclass driver, when an error occurs during a read, write, or device-control command, the tape class driver sets an appropriate TAPE_STATUS code and calls the miniclass driver's TapeMiniTapeError routine with the minitape extension, the failed SRB, and the TAPE_STATUS code that would be returned.

TapeMiniTapeError determines whether to alter the status provided by the tape class driver based on the input parameters and its knowledge of the device. If the SRB_STATUS_AUTOSENSE_VALID bit is set in Srb->SrbStatus, then the SRB contains SCSI sense information at SenseInfoBuffer. The length of the buffer is SenseInfoBufferLength. The TapeMiniTapeError routine should examine this information along with the SrbStatus and ScsiStatus in the SRB to determine whether or not to change the TAPE_STATUS returned.

See Also

DriverEntry of Tape Miniclass Driver, SCSI_REQUEST_BLOCK, TAPE_INIT_DATA_EX, TapeClassInitialize


TapeMiniVerifyInquiry

TapeMiniVerifyInquiry determines whether the tape miniclass driver recognizes and supports a given device. This routine is required.

BOOLEAN
  TapeMiniVerifyInquiry(
    IN PINQUIRYDATA  InquiryData,
    IN PMODE_CAPABILITIES_PAGE  ModeCapabilitiesPage  OPTIONAL
    );

Parameters

InquiryData
Points to SCSI inquiry data for the device.
ModeCapabilitiesPage
Points to a MODE_CAPABILITIES_PAGE structure that contains low-level information about the device. The format of this structure is defined by the QIC 157 standard and is subject to change. The pointer is NULL if the tape device does not support a mode capabilities page.

Return Value

TapeMiniVerifyInquiry returns TRUE if the miniclass driver supports the device.

Comments

TapeMiniVerifyInquiry examines the InquiryData, particularly the VendorId and ProductId members, to determine whether the tape miniclass driver supports the tape device. TapeMiniVerifyInquiry uses TapeClassCompareMemory to compare ID strings against values the tape miniclass driver supports.

See Also

TapeClassCompareMemory


TapeMiniWriteMarks

TapeMiniWriteMarks handles the device-specific aspects of an IOCTL_TAPE_WRITE_MARKS request. This routine is required.

TAPE_STATUS
  TapeMiniWriteMarks(
    IN OUT PVOID  MinitapeExtension  OPTIONAL,
    IN OUT PVOID  CommandExtension  OPTIONAL,
    IN OUT PVOID  CommandParameters,
    IN OUT PSCSI_REQUEST_BLOCK  Srb,
    IN ULONG  CallNumber,
    IN TAPE_STATUS  StatusOfLastCommand  OPTIONAL,
    IN OUT PULONG  RetryFlags  OPTIONAL
    );

Parameters

MinitapeExtension
Points to the driver-specific minitape extension. This is NULL if the miniclass driver did not request a minitape extension when it initialized.
CommandExtension
Points to the command extension. This is NULL if the miniclass driver did not request a command extension when it initialized.
CommandParameters
Points to a buffer containing a TAPE_WRITE_MARKS structure, which is defined as follows:
typedef struct _TAPE_WRITE_MARKS {
    ULONG Type;
    ULONG Count;
    BOOLEAN Immediate;
} TAPE_WRITE_MARKS, *PTAPE_WRITE_MARKS;
Type
The type of mark to write. This member can be one of the following:

TAPE_SETMARKS
TAPE_FILEMARKS
TAPE_SHORT_FILEMARKS
TAPE_LONG_FILEMARKS

Count
The number of marks to write.
Immediate
TRUE if the target device should return status immediately or FALSE if the device should return status after the operation is complete.
Srb
Points to an SRB allocated and partially filled in by the tape class driver. TapeMiniWriteMarks must fill in the CDB in the SRB. TapeMiniWriteMarks might fill in other SRB members, depending on the requirements of its device(s).
CallNumber
Specifies the number of times the routine has been called to process a given tape command. CallNumber is zero the first time this routine is called and is incremented for each subsequent call until the miniclass driver returns a TAPE_STATUS_XXX that indicates the command is complete.
StatusOfLastCommand
Specifies the status of the last command. In the first call to TapeMiniCreatePartition to process a given request, StatusOfLastCommand is TAPE_STATUS_SUCCESS. In subsequent calls, StatusOfLastCommand is either TAPE_STATUS_SUCCESS or an error status if an error occurred and the tape miniclass driver set RETURN_ERRORS in RetryFlags in the previous call.
RetryFlags
Points to a variable that specifies what action the tape class driver should take when a tape device reports an error.

The low-order word specifies the number of retries to perform in the event of a SCSI command failure. The default is zero (no retries).

The high-order word contains flags that specify how the tape class driver should return control if an error occurs:

  • If RETURN_ERRORS and IGNORE_ERRORS are clear (the default) the tape class driver returns a failure status to the original requester.
  • If the miniclass driver sets RETURN_ERRORS, the tape class driver calls TapeMiniSetDriveParameters with StatusOfLastCommand set to a failure status.
  • If the miniclass driver sets IGNORE_ERRORS, the tape class driver converts a failure status to success and calls TapeMiniSetDriveParameters with StatusOfLastCommand set to success.

Return Value

TAPE_STATUS_SEND_SRB_AND_CALLBACK
Indicates to the tape class driver that the SRB has been filled in and is ready to be sent to the target device. By default, the tape class driver calls TapeMiniWriteMarks again only if the SRB succeeds. A miniclass driver can modify the default behavior by setting RetryFlags before returning from TapeMiniWriteMarks.

TAPE_STATUS_CALLBACK
Directs the tape class driver to increment CallNumber and call TapeMiniWriteMarks again without sending an SRB to the tape device.

TAPE_STATUS_CHECK_TEST_UNIT_READY
Directs the tape class driver to fill in an SRB for the TEST UNIT READY command and send the SRB to the device.

TAPE_STATUS_XXX
Any other return code indicates to the tape class driver that the command is complete and indicates success, failure, or warning. Possible completion return values for this routine include, but are not limited to:

TAPE_STATUS_SUCCESS
TAPE_STATUS_NOT_IMPLEMENTED

Comments

TapeMiniWriteMarks writes marks to a tape by filling in the CDB in an SRB passed by the tape class driver. Writing marks typically takes one SRB to complete the operation. After TapeMiniWriteMarks fills in the SRB and returns, the tape class driver sends the SRB to the device and, depending on the result of the SRB and the value of RetryFlags, calls TapeMiniWriteMarks again. TapeMiniWriteMarks then returns TAPE_STATUS_SUCCESS.

TapeMiniWriteMarks must fill in the following members in the SRB before returning to the tape class driver:

  • Cdb – Points to the SCSI CDB for the command. Clear the CDB with TapeClassZeroMemory before filling it in.
  • CdbLength – Specifies the number of bytes in the CDB.

TapeMiniWriteMarks might also fill in the following members in the SRB:

  • DataBuffer – Points to the data buffer to be transferred. Use TapeClassAllocateSrbBuffer to allocate a DataBuffer of length greater than or equal to DataTransferLength.
  • DataTransferLength – Specifies the number of bytes to be transferred in the SRB. This member is set by TapeClassAllocateSrbBuffer.
  • TimeOutValue – Specifies a timeout value for this command, overriding the default timeout value from the tape class driver's device extension.
  • SrbFlags – Specifies a flag for this command. The tape miniclass driver must set SRB_FLAGS_DATA_OUT if the SRB is sending data to the tape drive. This member can be zero if the SRB is requesting data from the tape drive or if no data is being transferred by the command.

See Also

SCSI_REQUEST_BLOCK, TapeClassAllocateSrbBuffer, TapeClassZeroMemory


TapeMiniWMIControl

TapeMiniWMIControl is the common entry point for all WMI calls from the tape class driver.

TAPE_STATUS
  TapeWMIControl(
    IN OUT  PVOID  MinitapeExtension,
    IN OUT  PVOID  CommandExtension,
    IN OUT  PTAPE_WMI_OPERATIONS  CommandParameters,
    IN OUT  PSCSI_REQUEST_BLOCK  Srb,
    IN ULONG  CallNumber,
    IN TAPE_STATUS  LastError,
    IN OUT  PULONG  RetryFlags
    )

Parameters

MinitapeExtension
Pointer to the minidriver's device extension.
CommandExtension
Pointer to the minidriver's command extension.
CommandParameters
Pointer to TAPE_WMI_OPERATIONS structure.
Srb
SCSI Request block.
CallNumber
Call sequence number.
LastError
Last command error.
RetryFlags
Bit mask for retrying commands.

Return Value

TAPE_STATUS_SUCCESS or appropriate error code.

Headers

Include ntddchgr.h.

Comments

A minidrivers that supports WMI should set the function pointer member, TapeWMIOperations, in the structure TAPE_INIT_DATA_EX to point to the minidriver's TapeMiniWMIControl routine. The minidriver should do this in its DriverEntry routine before calling TapeClassInitialize. If a minidriver does not support WMI operations, it should set TapeWMIOperations field to NULL.

The tape class driver assigns values to the members of TAPE_WMI_OPERATIONS structure, and passes this structure to minidriver's TapeMiniWMIControl routine in the CommandParameters parameter. As with other minidriver routines, TapeMiniWMIControl fills, creates, and initializes the SCSI request blocks (SRB) and the command descriptor blocks (CDB) required to implement the indicated WMI method, and returns control to tape class driver. The tape class driver then calls the port driver to execute the request.

The minidriver returns the WMI data in the buffer pointed to by the DataBuffer member of the TAPE_WMI_OPERATIONS structure.

See Also

TAPE_INIT_DATA_EX, TAPE_WMI_OPERATIONS


Changer Class Driver Routines

This section describes the changer class driver routines that a changer miniclass driver can call. The routines are listed in alphabetical order.

The changer class driver routines are declared in mcd.h. The structures and constants required by a changer class driver are declared in ntddchgr.h.

For information about the changer class/miniclass architecture, see Changer Drivers.


ChangerClassAllocatePool

The ChangerClassAllocatePool function allocates pool memory.

PVOID
  ChangerClassAllocatePool(
    IN POOL_TYPE  PoolType,
    IN ULONG  NumberOfBytes
    );

Parameters

PoolType
Indicates the type of pool memory to allocate. See POOL_TYPE for a list of types.
NumberOfBytes
Indicates number of bytes to allocate.

Return Value

None

Headers

Declared in mcd.h. Include mcd.h.

See Also

POOL_TYPE


ChangerClassDebugPrint

The ChangerClassDebugPrint function prints debugging information.

VOID
  ChangerClassDebugPrint(
    ULONG  DebugPrintLevel,
    PCCHAR  DebugMessage
    );

Parameters

DebugPrintLevel
Indicates how verbose debug information should be. Caller must assign this parameter an integer value between zero and three, where three specifies the highest level of verbosity and zero the lowest.
DebugMessage
Caller can specify a message to be included with the debugging information that is printed by assigning a printable ASCII character string to this parameter.

Return Value

None

Headers

Declared in mcd.h. Include mcd.h.


ChangerClassFreePool

The ChangerClassFreePool routine frees pool memory previously allocated using ChangerClassAllocatePool.

VOID
  ChangerClassFreePool(
    IN PVOID  PoolToFree
    );

Parameters

PoolToFree
Pointer to the block of memory to be freed.

Return Value

None

Headers

Declared in mcd.h. Include mcd.h.

See Also

ChangerClassAllocatePool


ChangerClassInitialize

The ChangerClassInitialize routine initializes the driver.

NTSTATUS
  ChangerClassInitialize(
    IN PDRIVER_OBJECT  DriverObject,
    IN PUNICODE_STRING  RegistryPath,
    IN PMCD_INIT_DATA  MCDInitData
    );

Parameters

DriverObject
Pointer to the changer miniclass driver object. This is passed as a parameter to the miniclass driver's DriverEntry routine. The format of this object is operating system-specific and should not be interpreted by the miniclass driver.
RegistryPath
Pointerto the registry path for changer miniclass driver. This is also passed as a parameter to the miniclass driver's DriverEntry routine. The format of this is operating system-specific and should not be interpreted by the miniclass driver.
MCDInitData
Pointerto an MCD_INIT_DATA structure containing miniclass driver-specific information such as the entry points for the changer miniclass driver's command processing routines.

Return Value

ChangerClassInitialize returns a value indicating the success or failure of the driver initialization. If initialization is successful, ChangerClassInitialize returns STATUS_SUCCESS. Otherwise, ChangerClassInitialize returns an appropriate error message. Minidrivers should not interpret this error value, but should just return this value from their DriverEntry routine.

Headers

Declared in mcd.h. Include mcd.h.

Comments

ChangerClassInitialize is a changer class driver routine that miniclass drivers can call in Microsoft® Windows® XP and later operating systems.

Changer miniclass drivers call ChangerClassInitialize from within their DriverEntry routines to initialize the driver. ChangerClassInitialize performs many tasks formerly performed by the changer class driver's DriverEntry routine such as registering the miniclass driver's dispatch routines. It allocates a driver object extension and copies the data contained in MCDInitData into the driver object extension along with other initialization data such as the driver's registry path and pointers to certain changer class driver routines that are operating system-specific.

Changer miniclass drivers must allocate an MCD_INIT_DATA structure, zero the structure by calling RtlZeroMemory, and then assign values to the appropriate members, before passing the structure's address to ChangerClassInitialize by means of the MCDInitData parameter.

See Also

MCD_INIT_DATA, RtlZeroMemory


ChangerClassSendSrbSynchronous

The ChangerClassSendSrbSynchronous routine synchronously sends an SRB to a specified device.

NTSTATUS
  ChangerClassSendSrbSynchronous(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PSCSI_REQUEST_BLOCK  Srb,
    IN PVOID  Buffer,
    IN ULONG  BufferSize,
    IN BOOLEAN  WriteToDevice
    );

Parameters

DeviceObject
Pointer to the functional device object of the target device.
Srb
Pointer to a partially intialized SCSI request block (SRB) to be sent to the target device.
Buffer
Specifies address of the buffer that Srb->DataBuffer should point to. ChangerClassSendSrbSynchronous creates an MDL for this buffer and passes it to the target device driver in the SRB IRP.
BufferSize
Specifies length, in bytes, of the buffer.
WriteToDevice
Indicates a write operation when TRUE and read operation when FALSE.

Return Value

Returns STATUS_SUCCESS if the SRB is transmitted successfully or the appropriate error code if the SRB fails or can not be sent for some reason.

Headers

Declared in mcd.h. Include mcd.h.

Comments

Changer miniclass drivers can call this class driver routine in WIndows XP and later operating systems. Miniclass drivers should use this routine to send an SRB to the port driver instead of calling the classpnp.sys library routine ClassSendSrbSynchronous directly. Although classpnp.sys is shipped with the DDK, it is not a supported API and drivers that call this library's routines directly might not function properly in future releases.

ChangerClassSendSrbSynchronous finishes the initialization of the partially initialized SRB, setting the SRB's flags with the values indicated in the target's device object. ChangerClassSendSrbSynchronous creates the IRP that is used to convey the SRB to the target device, sends the IRP, then handles the IRP's completion.

If the IRP fails and the sense request data indicates that the IRP should be retried, ChangerClassSendSrbSynchronous will resend the IRP.

See Also

SCSI_REQUEST_BLOCK


Changer Miniclass Driver Routines

This section describes the required and optional routines in a changer miniclass driver. The routines are listed in alphabetical order.

The changer class driver calls changer miniclass driver routines to complete device-specific processing for requests from library-management applications such as the Removable Storage Manager (RSM). For details about RSM, see the Platform SDK documentation.

File I/O on a changer's data transfer elements (tape, disk, or CD-ROM drives, for example) is handled by the appropriate mass-storage driver for those drives. The mass-storage driver is responsible for all transfers of user data to and from media in a changer's drives. The changer driver is responsible only for controlling the movement of media between drives and other elements in the changer.

The routines required for a changer miniclass driver are declared in mcd.h. The structures and constants required by a changer miniclass driver are declared in ntddchgr.h.

For information about the changer class/miniclass architecture, see Changer Drivers.


ChangerAdditionalExtensionSize

ChangerAdditionalExtensionSize indicates the number of bytes the changer miniclass driver requires to store device-specific information in the device extension.

ULONG
  ChangerAdditionalExtensionSize(
    VOID
    );

Return Value

ChangerAdditionalExtensionSize returns the size, in bytes, of the additional device extension space required by the changer miniclass driver.

Headers

Declared in mcd.h. Include mcd.h.

Comments

The changer class driver calls ChangerAdditionalExtensionSize to determine the number of bytes the miniclass driver requires in the device extension for a particular changer before creating the device object to represent that changer.

The device-specific information stored by a changer miniclass driver is determined by the driver. It typically includes zero-based offsets that other miniclass driver routines can use to translate between device-specific element addresses and the zero-based element addresses used by the system. It can also include SCSI inquiry data or the non-SCSI equivalent.

The changer class driver calls ChangerAdditionalExtensionSize at IRQL = PASSIVE_LEVEL.

See Also

ChangerInitialize


ChangerError

ChangerError performs device-specific error handling.

VOID
  ChangerError(
    PDEVICE_OBJECT  DeviceObject,
    PSCSI_REQUEST_BLOCK  Srb,
    NTSTATUS  *Status,
    BOOLEAN  *Retry
    );

Parameters

DeviceObject
Pointer to the device object that represents the changer.
Srb
Pointer to the SCSI request block for the operation that failed.
Status
Specifies the address of the STATUS_XXX code set by the system. The changer miniclass driver can change the status or leave it as is.
Retry
Pointer to a flag that indicates whether to retry the request. The changer miniclass driver can set this flag or leave it as is.

Return Value

None

Headers

Declared in mcd.h. Include mcd.h.

Comments

This routine is required.

If an SRB fails with a SCSI status of CHECK CONDITION, the SCSI class driver calls the changer class driver's ChangerClassError routine. ChangerClassError performs device-independent error handling and calls the changer miniclass driver's ChangerError routine.

ChangerError first checks Srb->SrbStatus with SRB_STATUS_AUTOSENSE_VALID to make sure the sense data buffer is valid. If so, it checks the sense data in Srb->SenseInfoBuffer to determine whether to update *Status with a more accurate STATUS_XXX code and/or set the Retry flag before returning to the changer class driver. The changer class driver's retry count determines whether the SRB is actually retried.

The changer class driver calls ChangerError at IRQL=PASSIVE_LEVEL.


ChangerExchangeMedium

ChangerExchangeMedium handles the device-specific aspects of a device-control IRP with the IOCTL code IOCTL_CHANGER_EXCHANGE_MEDIUM.

NTSTATUS
  ChangerExchangeMedium(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Pointer to the device object that represents the changer.
Irp
Pointer to the IRP.

Return Value

If the changer supports exchanging media, ChangerExchangeMedium returns the status returned by the system port driver, or one of the following values:

STATUS_SUCCESS
STATUS_DESTINATION_ELEMENT_FULL
STATUS_INVALID_ELEMENT_ADDRESS
STATUS_SOURCE_ELEMENT_EMPTY

If the changer does not support exchanging media, ChangerExchangeMedium returns STATUS_INVALID_DEVICE_REQUEST.

Headers

Declared in mcd.h. Include mcd.h.

Comments

This routine is required.

ChangerExchangeMedium moves a piece of media from a source element to one destination and from that destination to another destination. The source and second destination are often the same, resulting in a simple exchange of media.

The CHANGER_EXCHANGE_MEDIA flag in Features0 of the GET_CHANGER_PARAMETERS structure indicates whether the changer supports this functionality. A changer that supports exchanging media typically has two picker mechanisms on a single transport element, or at least two transport elements. A changer that has a single picker mechanism might support exchanging medium through emulation of the command.

The changer class driver checks the input buffer length in the I/O stack location before calling a miniclass driver's ChangerExchangeMedium routine. Irp->SystemBuffer points to a CHANGER_EXCHANGE_MEDIUM structure as an input parameter that indicates the transport element and the destination to set. The CHANGER_EXCHANGE_MEDIUM structure is defined as follows:

typedef struct _CHANGER_EXCHANGE_MEDIUM {
  CHANGER_ELEMENT  Transport;
  CHANGER_ELEMENT  Source;
  CHANGER_ELEMENT  Destination1;
  CHANGER_ELEMENT  Destination2;
  BOOLEAN  Flip1;
  BOOLEAN  Flip2;
}CHANGER_EXCHANGE_MEDIUM, *PCHANGER_EXCHANGE_MEDIUM;
Transport
Indicates which transport element to use for the exchange operation. ElementType in Transport must be ChangerTransport.
Source
Indicates the element that contains the piece of media to be moved to Destination1.
Destination1
Indicates the destination of the piece of media originally at Source
Destination2
Indicates the destination of the piece of media originally at Destination1.
Flip1
Indicates whether the piece of media moved to Destination1 should be flipped. This member is valid only if CHANGER_MEDIUM_FLIP is set in Features0 of GET_CHANGER_PARAMETERS.
Flip2
Indicates whether the medium moved to Destination2 should be flipped. This member is valid only if CHANGER_MEDIUM_FLIP is set in Features0 of GET_CHANGER_PARAMETERS.

ChangerExchangeMedium first verifies that the transport, source, and destination element addresses are valid, then converts zero-based element addresses to device-specific element addresses. It then builds an SRB with a CDB to exchange the media and sends it to the system port driver.

The changer class driver calls ChangerExchangeMedium at IRQL = PASSIVE_LEVEL.

See Also

CHANGER_ELEMENT, ChangerMoveMedium, GET_CHANGER_PARAMETERS


ChangerGetElementStatus

ChangerGetElementStatus handles the device-specific aspects of a device-control IRP with the IOCTL code IOCTL_CHANGER_GET_ELEMENT_STATUS.

NTSTATUS
  ChangerGetElementStatus(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Pointer to the device object that represents the changer.
Irp
Pointer to the IRP.

Return Value

ChangerGetElementStatus returns the status returned by the system port driver or one of the following values:

STATUS_SUCCESS
STATUS_INFO_LENGTH_MISMATCH
STATUS_INSUFFICIENT_RESOURCES
STATUS_INVALID_DEVICE_REQUEST
STATUS_INVALID_ELEMENT_ADDRESS

If VolumeTagInfo is set for a changer that does not support volume tag information, ChangerGetElementStatus returns STATUS_INVALID_PARAMETER.

Headers

Declared in mcd.h. Include mcd.h.

Comments

This routine is required.

ChangerGetElementStatus returns the status and, optionally, volume tag information for all elements in a changer, or the status of a specific number of elements of a particular type.

The changer class driver checks the input and output buffer lengths in the I/O stack location before calling ChangerGetElementStatus.

Irp->SystemBuffer points to a CHANGER_READ_ELEMENT_STATUS structure as an input parameter that indicates the elements for which to report status and whether to report volume tag information. The CHANGER_READ_ELEMENT_STATUS structure is defined as follows:

typedef struct _CHANGER_READ_ELEMENT_STATUS {
  CHANGER_ELEMENT_LIST  ElementList;
  BOOLEAN  VolumeTagInfo;
} CHANGER_READ_ELEMENT_STATUS, *PCHANGER_READ_ELEMENT_STATUS;
ElementList
Specifies the element type and the number of elements of that type for which to report status. The ElementType can be ChangerDrive, ChangerSlot, ChangerTransport, ChangerIEPort, or AllElements.
VolumeTagInfo
Indicates whether to report volume tag information in addition to element status. A volume tag can be a bar code or an application-defined value assigned using ChangerQueryVolumeTags. This member is applicable only if either CHANGER_BAR_CODE_SCANNER_INSTALLED or CHANGER_VOLUME_IDENTIFICATION is set in Features0 of GET_CHANGER_PARAMETERS.

ChangerGetElementStatus first builds an SRB with a CDB to read element status command and sends it to the system port driver to retrieve the status of the changer's elements. For most element types, ChangerGetElementStatus then fills in a CHANGER_ELEMENT_STATUS structure at Irp->AssociatedIrp.SystemBuffer for each element for which it reports status. However, some elements of type ChangerDrive return product information data. If the device provides product information, the miniclass driver must report the element status data in a structure of type CHANGER_ELEMENT_STATUS_EX instead of using CHANGER_ELEMENT_STATUS. ChangerGetElementStatus must indicate that product information is present by setting ELEMENT_STATUS_PRODUCT_DATA in the Flags member of the structure.

ChangerGetElementStatus sets the Information field in the I/O status block to the number of bytes returned before returning to the changer class driver.

The changer class driver calls ChangerGetElementStatus at IRQL = PASSIVE_LEVEL.

See Also

CHANGER_ELEMENT_LIST, CHANGER_ELEMENT_STATUS, CHANGER_ELEMENT_STATUS_EX, CHANGER_ELEMENT, ChangerGetStatus, ChangerInitializeElementStatus, ChangerQueryVolumeTags, IOCTL_CHANGER_GET_ELEMENT_STATUS


ChangerGetParameters

ChangerGetParameters handles the device-specific aspects of a device-control IRP with the IOCTL code IOCTL_CHANGER_GET_PARAMETERS.

NTSTATUS
  ChangerGetParameters(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Pointer to the device object that represents the changer.
Irp
Pointer to the IRP.

Return Value

ChangerGetParameters returns the STATUS_XXX value returned by the system port driver or one of the following values:

STATUS_SUCCESS
STATUS_INFO_LENGTH_MISMATCH
STATUS_INSUFFICIENT_RESOURCES

Headers

Declared in mcd.h. Include mcd.h.

Comments

This routine is required.

ChangerGetParameters returns the parameters of a changer, including the number and type of its elements and the functionality it supports.

The changer class driver checks the output buffer length in the I/O stack location before calling ChangerGetParameters. If the output buffer length is smaller than sizeof(GET_CHANGER_PARAMETERS) the changer class driver returns with a value of STATUS_INFO_LENGTH_MISMATCH.

ChangerGetParameters retrieves parameter data from the device by building SRBs with CDBs to get the SCSI parameter header page, the element address page, the transport geometry page, and the device capabilities page, or the non-SCSI equivalent of this data.

ChangerGetParameters then fills in a GET_CHANGER_PARAMETERS structure at Irp->AssociatedIrp.SystemBuffer before returning to the changer class driver.

The changer class driver calls ChangerGetParameters at IRQL = PASSIVE_LEVEL.

See Also

GET_CHANGER_PARAMETERS


ChangerGetProductData

ChangerGetProductData handles the device-specific aspects of a device-control IRP with the IOCTL code IOCTL_CHANGER_GET_PRODUCT_DATA.

NTSTATUS
  ChangerGetProductData(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Pointer to the device object that represents the changer.
Irp
Pointer to the IRP.

Return Value

ChangerGetProductData always returns STATUS_SUCCESS.

Headers

Declared in mcd.h. Include mcd.h.

Comments

This routine is required.

ChangerGetProductData returns product data for a changer.

The changer class driver checks the output buffer length in the I/O stack location before calling ChangerGetProductData. If output buffer length is smaller than sizeof(CHANGER_PRODUCT_DATA) then the changer class driver returns with a value of STATUS_INFO_LENGTH_MISMATCH

ChangerGetProductData fills in a CHANGER_PRODUCT_DATA structure at Irp->AssociatedIrp.SystemBuffer before returning to the changer class driver. If the miniclass driver cached inquiry data in the changer's device extension before returning from ChangerInitialize, all members except DeviceType can be filled in from this data.

The CHANGER_PRODUCT_DATA structure is defined as follows:

typedef  struct _CHANGER_PRODUCT_DATA {
  UCHAR  VendorId[VENDOR_ID_LENGTH];
  UCHAR  ProductId[PRODUCT_ID_LENGTH];
  UCHAR  Revision[REVISION_LENGTH];
  UCHAR  SerialNumber[SERIAL_NUMBER_LENGTH];
  UCHAR  DeviceType;
} CHANGER_PRODUCT_DATA, *PCHANGER_PRODUCT_DATA;
VendorId
Specifies the device manufacturer's name.
ProductId
Specifies the product identification as defined by the vendor.
Revision
Specifies the product revision as defined by the vendor.
SerialNumber
Specifies the value defined by the vendor to identify this device. Serial numbers are unique for all changers of a given type, but are not necessarily unique across vendor and product lines. For a SCSI changer, this value might be from Vital Product Data. If SerialNumber is not unique, the miniclass driver should not set the CHANGER_SERIAL_NUMBER_VALID flag in Features0 of GET_CHANGER_PARAMETERS.
DeviceType
Specifies the device type of the changer. This member must be MEDIUM_CHANGER.

The changer class driver calls ChangerGetProductData at IRQL = PASSIVE_LEVEL.

See Also

ChangerInitialize


ChangerGetStatus

ChangerGetStatus handles the device-specific aspects of a device-control IRP with the IOCTL code IOCTL_CHANGER_GET_STATUS.

NTSTATUS
  ChangerGetStatus(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Pointer to the device object that represents the changer.
Irp
Pointer to the IRP.

Return Value

ChangerGetStatus returns the STATUS_XXX value returned by the system port driver. If there is not enough memory to process the request or to process the STATUS_XXX value returned by the system port driver ChangerGetStatus returns STATUS_INSUFFICIENT_RESOURCES.

Headers

Declared in mcd.h. Include mcd.h.

Comments

This routine is required.

ChangerGetStatus indicates whether the changer is able to accept requests.

ChangerGetStatus builds an SRB with a CDB to get the changer's status (using the SCSI command TEST UNIT READY or non-SCSI equivalent) and sends it to the system port driver to obtain status of the changer.

The changer class driver calls ChangerGetStatus at IRQL=PASSIVE_LEVEL.

See Also

ChangerGetElementStatus


ChangerInitialize

ChangerInitialize readies the changer to receive other requests.

NTSTATUS
  ChangerInitialize(
    IN PDEVICE_OBJECT  DeviceObject
    );

Parameters

DeviceObject
Pointer to the device object created by the changer class driver to represent this changer.

Return Value

ChangerInitialize returns the STATUS_XXX value returned by the system port driver or one of the following values:

STATUS_SUCCESS
STATUS_INSUFFICIENT_RESOURCES

Headers

Declared in mcd.h. Include mcd.h.

Comments

The changer class driver calls ChangerInitialize during driver initialization, after creating a device object to represent a changer.

ChangerInitialize performs any device-specific processing required to get the changer ready to receive requests. It also typically stores device-specific information in the device extension, such as SCSI inquiry data or the non-SCSI equivalent and offsets to generate zero-based element addresses, which are used by the system to refer to changer elements.

After ChangerInitialize returns, the changer miniclass driver and the changer should be able to handle any other request.

The changer class driver calls ChangerInitialize at IRQL = PASSIVE_LEVEL.

See Also

ChangerAdditionalExtensionSize


ChangerInitializeElementStatus

ChangerInitializeElementStatus handles the device-specific aspects of a device-control IRP with the IOCTL code IOCTL_CHANGER_INITIALIZE_ELEMENT_STATUS.

NTSTATUS
  ChangerInitializeElementStatus(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Pointer to the device object that represents the changer.
Irp
Pointer to the IRP.

Return Value

ChangerInitializeElementStatus returns the status returned by the system port driver or one of the following values:

STATUS_SUCCESS
STATUS_INVALID_PARAMETER
STATUS_INSUFFICIENT_RESOURCES

If the changer does not support initializing a range of elements of a particular type and ChangerInitializeElementStatus is called with an element type other than AllElements, it returns STATUS_INVALID_PARAMETER.

Headers

Declared in mcd.h. Include mcd.h.

Comments

This routine is required.

ChangerInitializeElementStatus updates the changer's internal memory with current information about its elements.

The changer class driver checks the input buffer length in the I/O stack location before calling ChangerInitializeElementStatus.

Irp->SystemBuffer points to a CHANGER_INITIALIZE_ELEMENT_STATUS structure as an input parameter that indicates the elements for which to initialize status and whether to initialize element status with data obtained from bar code labels. The CHANGER_INITIALIZE_ELEMENT_STATUS structure is defined as follows:

typedef struct _CHANGER_INITIALIZE_ELEMENT_STATUS {
  CHANGER_ELEMENT_LIST  ElementList;
  BOOLEAN  BarCodeScan;
} CHANGER_INITIALIZE_ELEMENT_STATUS, *PCHANGER_INITIALIZE_ELEMENT_STATUS;
ElementList
Specifies an element type and number of elements to initialize. If the changer supports initializing a range of elements, as indicated by CHANGER_INIT_ELEM_STAT_WITH_RANGE in Features0 of GET_CHANGER_PARAMETERS, the element type can be ChangerTransport, ChangerSlot, ChangerDrive, or ChangerIEPort and ElementList can specify a number of elements to initialize. Otherwise, the element type must be AllElements and the number of elements is ignored.
BarCodeScan
Indicates whether to initialize elements by scanning bar codes. This member is applicable only if CHANGER_BAR_CODE_SCANNER_INSTALLED is set in Features0 of GET_CHANGER_PARAMETERS. If the changer has nonvolatile RAM, a bar-code scan can serve as an optimization.

For a SCSI changer, ChangerInitializeElementStatus builds an SRB with a CDB to initialize element status, translates zero-based element addresses to device-specific addresses, and sends the SRB to the system port driver.

ChangerInitializeElementStatus sets the Information field in the I/O status block to sizeof(CHANGER_INITIALIZE_ELEMENT_STATUS) before returning to the changer class driver.

The changer class driver calls ChangerInitializeElementStatus at IRQL = PASSIVE_LEVEL.

See Also

ChangerGetElementStatus, CHANGER_ELEMENT_LIST


ChangerMoveMedium

ChangerMoveMedium handles the device-specific aspects of a device-control IRP with the IOCTL code IOCTL_CHANGER_MOVE_MEDIUM.

NTSTATUS
  ChangerMoveMedium(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Pointer to the device object that represents the changer.
Irp
Pointer to the IRP.

Return Value

ChangerMoveMedium returns the status returned by the system port driver, or one of the following values:

STATUS_SUCCESS
STATUS_DESTINATION_ELEMENT_FULL
STATUS_INVALID_ELEMENT_ADDRESS
STATUS_INVALID_DEVICE_REQUEST
STATUS_INVALID_PARAMETER
STATUS_INSUFFICIENT_RESOURCES
STATUS_SOURCE_ELEMENT_EMPTY

Headers

Declared in mcd.h. Include mcd.h.

Comments

This routine is required.

ChangerMoveMedium moves a piece of media from one element to another.

The changer class driver checks the input buffer length in the I/O stack location before calling ChangerMoveMedium. Irp->SystemBuffer points to a CHANGER_MOVE_MEDIUM structure that indicates the transport element, the source, the destination, and whether to flip the medium. The CHANGER_MOVE_MEDIUM structure is defined as follows:

typedef struct _CHANGER_MOVE_MEDIUM {
  CHANGER_ELEMENT  Transport;
  CHANGER_ELEMENT  Source;
  CHANGER_ELEMENT  Destination;
  BOOLEAN Flip;
}CHANGER_MOVE_MEDIUM, *PCHANGER_MOVE_MEDIUM;
Transport
Indicates which transport element to use for the move operation. The ElementType must be ChangerTransport.
Source
Indicates the element that contains the piece of media to be moved to Destination. The ElementType must be ChangerDrive, ChangerTransport, ChangerSlot, or ChangerIEPort.
Destination
Indicates the destination of the piece of media originally at Source. The ElementType must be ChangerDrive, ChangerTransport, ChangerSlot, or ChangerIEPort.
Flip
Indicates whether the piece of media should be flipped. This member is valid only if CHANGER_MEDIUM_FLIP is set in Features0 of GET_CHANGER_PARAMETERS.

ChangerMoveMedium first verifies that the transport, source, and destination element addresses are valid and then converts zero-based element addresses to device-specific addresses. It then builds an SRB with a CDB to move the piece of media and sends it to the system port driver.

ChangerMoveMedium sets the Information field in the I/O status block to sizeof(CHANGER_MOVE_MEDIUM) before returning to the changer class driver.

The changer class driver calls ChangerMoveMedium at IRQL = PASSIVE_LEVEL.

See Also

CHANGER_ELEMENT, ChangerExchangeMedium


ChangerQueryVolumeTags

ChangerQueryVolumeTags handles the device-specific aspects of a device-control IRP with the IOCTL code of IOCTL_CHANGER_QUERY_VOLUME_TAGS.

NTSTATUS
  ChangerQueryVolumeTags(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Pointer to the device object that represents the changer.
Irp
Pointer to the IRP.

Return Value

If the changer supports retrieval of volume tag information, ChangerQueryVolumeTags returns the STATUS_XXX value returned by the system port driver, or one of the following values:

STATUS_SUCCESS
STATUS_INVALID_ELEMENT_ADDRESS
STATUS_INSUFFICIENT_RESOURCES

If the changer does not support retrieval of volume tag information, ChangerQueryVolumeTags returns STATUS_INVALID_DEVICE_REQUEST.

Headers

Declared in mcd.h. Include mcd.h.

Comments

This routine combines the functionality of two SCSI commands: SEND VOLUME TAGS and REQUEST VOLUME ELEMENT ADDRESS. This routine is required.

ChangerQueryVolumeTags retrieves volume tag information for specified elements. It can also be used to define or clear volume tag information if the changer supports these operations. The CHANGER_VOLUME_IDENTIFICATION flag in the Features0 member of the GET_CHANGER_PARAMETERS structure indicates whether the changer supports this functionality.

The changer class driver checks the input and output buffer lengths in the I/O stack location before calling ChangerQueryVolumeTags. Irp->SystemBuffer points to a CHANGER_SEND_VOLUME_TAG_INFORMATION structure that indicates the elements, the operation to perform, and a template that specifies the volume ID to search for or to set.

ChangerQueryVolumeTags first checks the action code for unsupported operations, and returns STATUS_INVALID_DEVICE_REQUEST for those it does not support. Next, it builds an SRB with a CDB to indicate the device-specific address of the starting element and sends it to the system port driver, passing the volume ID template as a parameter. (For a SCSI changer, the miniclass driver uses the SCSI command SEND VOLUME TAG.)

If the first SRB succeeds, ChangerQueryVolumeTags builds a second SRB with a CDB to transfer the results of the previous SRB. (For a SCSI changer, the miniclass driver uses the SCSI command REQUEST VOLUME ELEMENT ADDRESS.)

ChangerQueryVolumeTags then fills in a READ_ELEMENT_ADDRESS_INFO structure at Irp->AssociatedIrp.SystemBuffer that indicates the number of elements for which volume tag information was transferred, and the information for each element.

After filling in the system buffer, ChangerQueryVolumeTags sets the Information field in the I/O status block to the number of bytes written to the buffer before returning to the changer class driver.

The changer class driver calls ChangerQueryVolumeTags at IRQL = PASSIVE_LEVEL.

See Also

CHANGER_ELEMENT, CHANGER_ELEMENT_STATUS, ChangerGetElementStatus, READ_ELEMENT_ADDRESS_INFO


ChangerReinitializeUnit

ChangerReinitializeUnit handles the device-specific aspects of a device-control IRP with the IOCTL code IOCTL_CHANGER_REINITIALIZE_TRANSPORT.

NTSTATUS
  ChangerReinitializeUnit(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Pointer to the device object that represents the changer.
Irp
Pointer to the IRP.

Return Value

If the changer supports recalibrating a transport element, ChangerReinitializeUnit returns the STATUS_XXX value returned by the system port driver, or one of the following values:

STATUS_SUCCESS
STATUS_INVALID_ELEMENT_ADDRESS
STATUS_INVALID_PARAMETER
STATUS_INSUFFICIENT_RESOURCES

If the changer does not support recalibrating a transport element, ChangerReinitializeUnit returns STATUS_INVALID_DEVICE_REQUEST.

Headers

Declared in mcd.h. Include mcd.h.

Comments

This routine is required.

ChangerReinitializeUnit causes the changer to recalibrate its transport element. Depending on the changer, this may return the transport to a "home" position. The changer class driver typically calls ChangerReinitializeUnit after the changer has been powered on or a calling application has initiated a recovery operation. The CHANGER_DEVICE_REINITIALIZE_CAPABLE flag in Features0 of GET_CHANGER_PARAMETERS indicates whether the changer's transport supports recalibration in those circumstances.

The changer class driver checks the input buffer length in the I/O stack location before calling ChangerReinitializeUnit. Irp->SystemBuffer points to a CHANGER_ELEMENT structure that indicates the element to recalibrate.

ChangerReinitializeUnit builds an SRB with a CDB to position the transport element and sends it to the system port driver.

ChangerReinitializeUnit sets the Information field in the I/O status block to sizeof(CHANGER_ELEMENT) before returning to the changer class driver.

The changer class driver calls ChangerReinitializeUnit at IRQL = PASSIVE_LEVEL.

See Also

CHANGER_ELEMENT, GET_CHANGER_PARAMETERS


ChangerSetAccess

ChangerSetAccess handles the device-specific aspects of a device-control IRP with the IOCTL code IOCTL_CHANGER_SET_ACCESS.

NTSTATUS
  ChangerSetAccess(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Pointer to the device object that represents the changer.
Irp
Pointer to the IRP.

Return Value

If the changer supports setting access, ChangerSetAccess returns the STATUS_XXX value returned by the system port driver or one of the following values:

STATUS_SUCCESS
STATUS_INSUFFICIENT_RESOURCES
STATUS_INVALID_PARAMETER

If the changer does not support setting access, ChangerSetAccess returns STATUS_INVALID_DEVICE_REQUEST.

Headers

Declared in mcd.h. Include mcd.h.

Comments

This routine is required.

ChangerSetAccess locks or unlocks a changer's IEport, door, or keypad, and extends or retracts an IEport.

The changer class driver checks the input buffer length in the I/O stack location before calling ChangerSetAccess. Irp->SystemBuffer points to a CHANGER_SET_ACCESS structure as an input parameter that indicates the element to set and the operation to perform. The CHANGER_SET_ACCESS structure is defined as follows:

typedef struct _CHANGER_SET_ACCESS {
  CHANGER_ELEMENT  Element;
  ULONG  Control;
} CHANGER_SET_ACCESS, *PCHANGER_SET_ACCESS;
Element
Specifies the element type and the zero-based address of the element to set. This member can be one of the following values:

ChangerIEPort
ChangerDoor
ChangerKeypad

Control
Specifies the operation to perform on the element. The Features0 member of GET_CHANGER_PARAMETERS indicates whether the changer supports a particular category of operation.
LOCK_ELEMENT
Lock the door, IEport, or keypad. Valid only if CHANGER_LOCK_UNLOCK is set.
UNLOCK_ELEMENT
Unlock the door, IEport, or keypad. Valid only if CHANGER_LOCK_UNLOCK is set.
EXTEND_IEPORT
Extend the IEport. Valid only if CHANGER_OPEN_IEPORT is set.
RETRACT_IEPORT
Retract the IEport. Valid only if CHANGER_CLOSE_IEPORT is set.

ChangerSetAccess first checks for unsupported elements and operations, and returns the appropriate status code for those it doesn't support.

Next, ChangerSetAccess translates the zero-based element address passed by the system to the device-specific element address required by the changer.

Finally, ChangerSetAccess builds an SRB with a CDB for the given operation on the given element and sends it to the system port driver. The command to use depends on the changer. For example, the Exabyte miniclass driver uses the SCSI command PREVENT ALLOW MEDIUM REMOVAL to lock or unlock a changer door and MOVE MEDIUM to extend or retract an IEport.

The changer class driver calls ChangerSetAccess at IRQL = PASSIVE_LEVEL.

See Also

GET_CHANGER_PARAMETERS


ChangerSetPosition

ChangerSetPosition handles the device-specific aspects of a device-control IRP with the IOCTL code IOCTL_CHANGER_SET_POSITION.

NTSTATUS
  ChangerSetPosition(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Pointer to the device object that represents the changer.
Irp
Pointer to the IRP.

Return Value

If the changer supports setting the position of the transport element, ChangerSetPosition returns the status returned by the system port driver, or one of the following values:

STATUS_SUCCESS
STATUS_INFO_LENGTH_MISMATCH
STATUS_INVALID_PARAMETER
STATUS_INSUFFICIENT_RESOURCES

If the changer does not support setting the position of the transport element, ChangerSetPosition returns STATUS_INVALID_DEVICE_REQUEST.

Headers

Declared in mcd.h. Include mcd.h.

Comments

This routine is required.

ChangerSetPosition sets the changer's robotic transport mechanism to the specified destination, typically to optimize moving or exchanging media by first positioning the transport.

The CHANGER_POSITION_TO_ELEMENT flag in Features0 of GET_CHANGER_PARAMETERS indicates whether the changer supports this functionality.

The changer class driver checks the input buffer length in the I/O stack location before calling ChangerSetPosition. Irp->SystemBuffer points to a CHANGER_SET_POSITION structure as an input parameter that indicates the transport element and the destination to set. The CHANGER_SET_POSITION structure is defined as follows:

typedef struct _CHANGER_SET_POSITION {
  CHANGER_ELEMENT  Transport;
  CHANGER_ELEMENT  Destination;
  BOOLEAN  Flip;
}CHANGER_SET_POSITION, *PCHANGER_SET_POSITION;
Transport
Indicates the transport element to move. ElementType must be ChangerTransport.
Destination
Indicates the final destination of the transport element. ElementType must be ChangerSlot, ChangerDrive, or ChangerIEPort.
Flip
Indicates whether Transport should be flipped. This member is applicable only if CHANGER_MEDIUM_FLIP is set in Features0 of GET_CHANGER_PARAMETERS.

ChangerSetPosition first verifies that the transport and destination element addresses are valid and converts zero-based element addresses to device-specific addresses. It then builds an SRB with a CDB to position the element and sends it to the system port driver.

ChangerSetPosition sets the Information field in the I/O status block to sizeof(CHANGER_SET_POSITION) before returning to the changer class driver.

The changer class driver calls ChangerSetPosition at IRQL = PASSIVE_LEVEL.

See Also

CHANGER_ELEMENT


ChangerPerformDiagnostics

ChangerPerformDiagnostics performs diagnostic tests on the changer device.

NTSTATUS
  ChangerPerformDiagnostics(
    IN PDEVICE_OBJECT  DeviceObject,
    OUT PWMI_CHANGER_PROBLEM_DEVICE_ERROR
        ChangerDeviceError
    );

Parameters

DeviceObject
Pointer to the device object that represents the changer.
ChangerDeviceError
Pointer to the buffer of type WMI_CHANGER_PROBLEM_DEVICE_ERROR in which the minidriver returns the diagnostic information.

Return Value

ChangerPerformDiagnostics returns the status returned by the system port driver or one of the following values:

STATUS_SUCCESS

STATUS_INSUFFICIENT_RESOURCES

STATUS_BUFFER_TOO_SMALL

Headers

Declared in mcd.h. Include mcd.h.

Comments

ChangerPerformDiagnostics routine performs diagnostic tests on the changer device, and reports the problem to the caller. The kind of tests performed depends on the diagnostics support provided by the device.

See Also

WMI_CHANGER_PROBLEM_DEVICE_ERROR, CHANGER_DEVICE_PROBLEM_TYPE


DriverEntry of Changer Miniclass Drivers

In Windows 2000, changer miniclass drivers do not have a DriverEntry routine, but in Windows XP and later operating systems a miniclass driver must have a DriverEntry routine with the following characteristics.

NTSTATUS
DriverEntry(
 IN PVOID Argument1,
 IN PVOID Argument2
);

Parameters

Argument1
Pointer to operating system-specific information.
Argument2
Pointer to operating system-specific information.

Return Value

The miniclass driver's DriverEntry routine must return the value returned by the ChangerClassInitialize routine.

Headers

Declared in mcd.h. Include mcd.h.

Comments

Parameters Argument1 and Argument2 point to operating system-specific information. A Miniclass driver should not attempt to interpret these parameters. Instead, it should pass these parameters to the ChangerClassInitialize routine.

ChangerClassInitialize performs most of the initialization required by the miniclass driver. The principal task of the minidriver in its DriverEntry routine is to load the entry points to its command processing routines into an MCD_INIT_DATA structure and pass the address of this structure to the ChangerClassInitialize routine.

See Also

ChangerClassInitialize, MCD_INIT_DATA


Storage Structures

This section describes structures used by storage drivers on NT-based operating systems, including class, miniclass, and filter drivers. It also describes structures used by SCSI miniport drivers, independent of operating system, that are linked with a Microsoft-supplied, operating-system-specific SCSI port driver.

Structures described in this section are in alphabetical order.


ACCESS_RANGE

An ACCESS_RANGE describes a memory or I/O port range used by an HBA.

typedef struct _ACCESS_RANGE {
  SCSI_PHYSICAL_ADDRESS  RangeStart;
  ULONG  RangeLength;
  BOOLEAN  RangeInMemory;
} ACCESS_RANGE, *PACCESS_RANGE;

Members

RangeStart
Specifies the bus-relative base address of the range. This is an address that can be passed into ScsiPortGetDeviceBase.
RangeLength
Specifies the size in bytes or number of ports in the range. A miniport driver must ensure that this value matches the range actually decoded by the adapter. For example, if the HBA uses seven registers but responds to eight, this member should be set to eight.
RangeInMemory
TRUE indicates the range is in memory, rather than in I/O space.

Headers

Declared in srb.h. Include srb.h.

Comments

Each ACCESS_RANGE is an AccessRanges array element within the PORT_CONFIGURATION_INFORMATION structure that is passed to a miniport driver's HwScsiFindAdapter routine.

If possible, the OS-specific port driver sets up each access range element with a bus-relative HBA range for the miniport driver before calling the miniport's HwScsiFindAdapter routine. Otherwise, the port driver zeros range elements for which it cannot supply configuration information.

If the port driver does supply a range, the miniport's HwScsiFindAdapter routine should use only the supplied addresses and should never attempt to find other HBAs on the same bus using addresses of its own devising. Attempting to access other bus-relative port or memory ranges when the port driver has supplied range information, particularly in x86-only systems in which some devices are initialized in x86 real mode, can cause other devices on the bus to fail initialization or even cause the system to fail the boot process.

Each miniport driver should have a set of bus-relative default ranges to try if the OS-specific port driver cannot supply the information. A miniport driver must call ScsiPortValidateRange to check the safety of any miniport-supplied access range before it attempts to map such a range with ScsiPortGetDeviceBase and use the returned logical addresses to access an adapter, particularly if one of its HBAs has a BIOS.

Any access range that a miniport driver fills in for the OS-specific port driver in the PORT_CONFIGURATION_INFORMATION must have the RangeStart member set to a bus-relative address, such as a value returned by ScsiPortGetBusData.

The corresponding base logical address returned by ScsiPortGetDeviceBase should be stored, usually in the miniport's device extension, as the RangeStart address for a mapped range of I/O ports or memory addresses used to call the ScsiPortRead Xxx and ScsiPortWrite Xxx routines.

See Also

HwScsiFindAdapter, PORT_CONFIGURATION_INFORMATION, ScsiPortConvertUlongToPhysicalAddress, ScsiPortGetBusData, ScsiPortGetDeviceBase, ScsiPortRead Xxx, ScsiPortValidateRange, ScsiPortWrite Xxx


CDROM_DISK_DATA

Device control IRPs with a control code of IOCTL_CDROM_DISK_TYPE return their output data in this structure.

typedef struct _CDROM_DISK_DATA {
  ULONG  DiskData;
} CDROM_DISK_DATA, *PCDROM_DISK_DATA;

Members

DiskData
Disk flags that indicate whether the CD-ROM has audio data, computer data, or both, as follows. These flags can be bitwise ORed.
Value Meaning
CDROM_DISK_AUDIO_TRACK
Device has audio data.
CDROM_DISK_DATA_TRACK
Device has computer data.

Headers

Declared in ntddcdrm.h. Include ntddcdrm.h.

Comments

DiskData indicates whether the device has audio data, computer data, or both.

See Also

IOCTL_CDROM_DISK_TYPE


CDROM_PLAY_AUDIO_MSF

Device control IRPs with a control code of IOCTL_CDROM_PLAY_AUDIO_MSF use this structure to play an audio CD.

typedef struct _CDROM_PLAY_AUDIO_MSF {
  UCHAR  StartingM;
  UCHAR  StartingS;
  UCHAR  StartingF;
  UCHAR  EndingM;
  UCHAR  EndingS;
  UCHAR  EndingF;
} CDROM_PLAY_AUDIO_MSF, *PCDROM_PLAY_AUDIO_MSF;

Members

StartingM
Starting minute.
StartingS
Starting second.
StartingF
Starting frame.
EndingM
Ending minute.
EndingS
Ending second.
EndingF
Ending frame.

Headers

Declared in ntddcdrm.h. Include ntddcdrm.h.

Comments

Device control IRPs with a control code of IOCTL_CDROM_PLAY_AUDIO_MSF use this structure to play an audio CD and to indicate where to begin playing and where to stop. Starting and ending points are indicated in terms of minutes, seconds, and frames.

See Also

IOCTL_CDROM_PLAY_AUDIO_MSF


CDROM_READ_TOC_EX

When drivers query a target CD-ROM device with IOCTL_CDROM_READ_TOC_EX they must define the query with this structure.

typedef struct _CDROM_READ_TOC_EX {
  UCHAR Format : 4;
  UCHAR Reserved1 : 3;
  UCHAR Msf : 1;
  UCHAR SessionTrack;
  UCHAR Reserved2;
  UCHAR Reserved3;
} CDROM_READ_TOC_EX, *PCDROM_READ_TOC_EX;

Members

Format
Specifies table of contents read operation, as follows:
Value Meaning
CDROM_READ_TOC_EX_FORMAT_TOC
Query the device for the table of contents for the specified session(s). The SessionTrack member of the structure specifies the starting track number of the session for which the data will be returned. For multisession CD-ROMs, this command will return the table of contents data for all sessions. For track number 0xAA, it returns the lead-out area of the last complete session. The output data is reported in a CDROM_TOC structure.
CDROM_READ_TOC_EX_FORMAT_SESSION
Query the device for the first complete session number, the last complete session number, and the last complete session starting address. The output data is reported in a CDROM_TOC_SESSION_DATA structure. With this format, the SessionTrack member is reserved and must be set to zero. This format provides the initiator with quick access to the last finalized session starting address.
CDROM_READ_TOC_EX_FORMAT_FULL_TOC
Query the device for all Q subcode data in the lead-in table of contents areas starting from the session number specified in the SessionTrack member. The output data is reported in a header structure, CDROM_TOC_FULL_TOC_DATA, followed by a series of track descriptors defined in CDROM_TOC_FULL_TOC_DATA_BLOCK. In this format, logical block addressing (LBA) is not defined, and the Msf member must be set to one.
CDROM_READ_TOC_EX_FORMAT_PMA
Query the device for all Q subcode data in the program memory area (PMA). The output data is reported in a CDROM_TOC_PMA_DATA structure. In this format, the SessionTrack member is reserved and must be set to zero. Logical block addressing (LBA) is not defined, and the Msf member must be set to one.
CDROM_READ_TOC_EX_FORMAT_ATIP
Query the device for absolute time in pre-groove (ATIP) data. The output data is reported in the CDROM_TOC_ATIP_DATA structure. In this format, the SessionTrack member is reserved and must be set to zero. Logical block addressing (LBA) is not defined, and the Msf member must be set to one.
CDROM_READ_TOC_EX_FORMAT_CDTEXT
Query the device for CD-TEXT information that is recorded in the lead-in area as R-W subchannel data. The output data is reported in a CDROM_TOC_CD_TEXT_DATA structure with an appended array of CDROM_TOC_CD_TEXT_DATA_BLOCK structures.

Reserved1
Reserved.
Msf
Minute-second-frame bit. This bit specifies whether to use MSF(1) or LBA(0) addressing in the resulting data.
SessionTrack
Depending on the value of the Format member, SessionTrack either specifies the starting track number for which the data will be returned, the session for which the command is targeted, or it is a reserved field that drivers should set to zero.

Headers

Declared in ntddcdrm.h. Include ntddcdrm.h.

Comments

For further information and definitions of terms used in this reference page and in the reference pages of related structures, see specification T10/1363-D Revision-02A, by National Committee for Information Technology Standards (NCITS).

See Also

IOCTL_CDROM_READ_TOC_EX


CDROM_SEEK_AUDIO_MSF

The CDROM_SEEK_AUDIO_MSF structure contains the minute, second, and frame that the device must seek to upon receipt of a device control IRP with a control code of IOCTL_CDROM_SEEK_AUDIO_MSF.

typedef struct _CDROM_SEEK_AUDIO_MSF {
  UCHAR  M;
  UCHAR  S;
  UCHAR  F;
} CDROM_SEEK_AUDIO_MSF, *PCDROM_SEEK_AUDIO_MSF;

Members

M
Indicates the minute to seek to.
S
Indicates the second to seek to.
F
Indicates the frame to seek to.

Headers

Declared in ntddcdrm.h. Include ntddcdrm.h.

See Also

IOCTL_CDROM_SEEK_AUDIO_MSF


CDROM_SUB_Q_DATA_FORMAT

The CDROM_SUB_Q_DATA_FORMAT structure is used with device control IRPs of type IOCTL_CDROM_READ_Q_CHANNEL.

typedef struct _CDROM_SUB_Q_DATA_FORMAT {
    UCHAR Format;
    UCHAR Track;
} CDROM_SUB_Q_DATA_FORMAT, *PCDROM_SUB_Q_DATA_FORMAT;

Members

Format
Specifies which subset of the Q data the read operation should return, as follows:
Value Meaning
IOCTL_CDROM_CURRENT_POSITION
Indicates that the read operation should return position information such as the track number, the index number, the absolute address, and the track relative address. If the IOCTL_CDROM_Q_CHANNEL device control IRP specifies this format, the information is returned in the SUB_Q_CURRENT_POSITION member of the SUB_Q_CHANNEL_DATA structure.
IOCTL_CDROM_MEDIA_CATALOG
Indicates that the read operation should return the media catalog number. If the IOCTL_CDROM_Q_CHANNEL device control IRP specifies this format, the information is returned in the SUB_Q_MEDIA_CATALOG_NUMBER member of the SUB_Q_CHANNEL_DATA structure.
IOCTL_CDROM_TRACK_ISRC
Indicates that the read operation should return the ISO/IEC 3901 Track International Standard Recording Code (ISRC). This code gives a unique number to an audio track. If the IOCTL_CDROM_Q_CHANNEL device control IRP specifies this format, the information is returned in the SUB_Q_TRACK_ISRC member of the SUB_Q_CHANNEL_DATA structure.

Track
Indicates the track number where the CD-ROM driver must read the Q subchannel data. If Format is set to IOCTL_CDROM_MEDIA_CATALOG, then the Track member must be set to zero.

Headers

Declared in ntddcdrm.h. Include ntddcdrm.h.

Comments

The CDROM_SUB_Q_DATA_FORMAT structure indicates the track from which to read the Q part of the subchannel data and the format of the read.

See Also

IOCTL_CDROM_READ_Q_CHANNEL, SUB_Q_CHANNEL_DATA, SUB_Q_CURRENT_POSITION, SUB_Q_MEDIA_CATALOG_NUMBER, SUB_Q_TRACK_ISRC


CDROM_TOC

Device control IRPs with a control code of IOCTL_CDROM_READ_TOC_EX and a format of CDROM_READ_TOC_EX_FORMAT_TOC return their output data in this structure followed by a series of TRACK_DATA structures.

typedef struct _CDROM_TOC {
  UCHAR  Length[2];
  UCHAR  FirstTrack;
  UCHAR  LastTrack;
  TRACK_DATA  TrackData[MAXIMUM_NUMBER_TRACKS];
} CDROM_TOC, *PCDROM_TOC;

Members

Length
Indicates the length, in bytes, of the table of contents data. This length value does not include the length of the Length member itself.
FirstTrack
Indicates the first track number of the table of contents of the first complete session.
LastTrack
Indicates the last track number of the table of contents of the last complete session.
TrackData
Points to an array of structures of type TRACK_DATA that contain table of contents information for all the sessions on the disk.

Headers

Declared in ntddcdrm.h. Include ntddcdrm.h.

Comments

The output data contains table of contents information for one or more of the specified sessions.

See Also

IOCTL_CDROM_READ_TOC_EX, CDROM_READ_TOC_EX, TRACK_DATA


CDROM_TOC_ATIP_DATA

Device control IRPs with a control code of IOCTL_CDROM_READ_TOC_EX and a format of CDROM_READ_TOC_EX_FORMAT_ATIP return their output data in this header structure followed by a series of descriptors of type CDROM_TOC_ATIP_DATA_BLOCK.

typedef struct _CDROM_TOC_ATIP_DATA {
  UCHAR  Length[2];
  UCHAR  Reserved1;
  UCHAR  Reserved2;
  CDROM_TOC_ATIP_DATA_BLOCK  Descriptors[0];
} CDROM_TOC_ATIP_DATA, *PCDROM_TOC_ATIP_DATA;

Members

Length
Indicates the number of bytes to be transferred in response to the command. This length value does not include the length of the Length member itself.
Reserved1
Reserved.
Reserved2
Reserved.
Descriptors
Zero or more ATIP data block descriptors of type CDROM_TOC_ATIP_DATA_BLOCK.

Headers

Declared in ntddcdrm.h. Include ntddcdrm.h.

See Also

IOCTL_CDROM_READ_TOC_EX, CDROM_READ_TOC_EX, CDROM_TOC_ATIP_DATA_BLOCK


CDROM_TOC_ATIP_DATA_BLOCK

Device control IRPs with a control code of IOCTL_CDROM_READ_TOC_EX and a format of CDROM_READ_TOC_EX_FORMAT_ATIP return their output data in a header structure of type CDROM_TOC_ATIP_DATA followed by a series of ATIP data block descriptors defined by CDROM_TOC_ATIP_DATA_BLOCK.

typedef struct _CDROM_TOC_ATIP_DATA_BLOCK {
  UCHAR  CdrwReferenceSpeed : 3;
  UCHAR  Reserved3          : 1;
  UCHAR  WritePower         : 3;
  UCHAR  True1              : 1;
  UCHAR  Reserved4       : 6;
  UCHAR  UnrestrictedUse : 1;
  UCHAR  Reserved5       : 1;
  UCHAR  A3Valid   : 1;
  UCHAR  A2Valid   : 1;
  UCHAR  A1Valid   : 1;
  UCHAR  Reserved6 : 3;
  UCHAR  IsCdrw    : 1;
  UCHAR  True2     : 1;
  UCHAR  Reserved7;
  UCHAR  LeadInMsf[3];
  UCHAR  Reserved8;
  UCHAR  LeadOutMsf[3];
  UCHAR  Reserved9;
  UCHAR  A1Values[3];
  UCHAR  Reserved10;
  UCHAR  A2Values[3];
  UCHAR  Reserved11;
  UCHAR  A3Values[3];
  UCHAR  Reserved12;
} CDROM_TOC_ATIP_DATA_BLOCK, *PCDROM_TOC_ATIP_DATA_BLOCK;

Members

CdrwReferenceSpeed
Recommended write speed for the media. Only valid for rewritable CD (CD-RW), recordable double density CD (DDCD-R), or rewritable double density CD media (DDCD-RW).
Reserved3
Reserved.
WritePower
Indicates media's recommended initial laser power setting.
True1
Must be set to one.
Reserved4
Reserved.
UnrestrictedUse
When the Unrestricted Use Disc (URU) bit recorded in the UnrestrictedUse member is set to one, this indicates that the mounted disc is defined for unrestricted use.
Reserved5
Reserved.
A3Valid
When set to one, indicates that bytes 16-18 (bytes 12-14 of the ATIP descriptor) are valid.
A2Valid
When set to one, indicates that A2 values field is valid.
A1Valid
When set to one, indicates that A3 values field is valid.
DiscSubType
Must be set to zero.
IsCdrw
When set to one, indicates the media is rewritable (CD-RW). When set to zero, indicates the media is write-once (CD-R).
True2
Must be set to one.
Reserved7
Reserved.
LeadInMsf
ATIP start time of lead-in terms of minutes, seconds, and frames.
Reserved8
Reserved.
LeadOutMsf
ATIP last possible start time of lead-out in terms of minutes, seconds, and frames.
Reserved9
Reserved.
A1Values
For information on the permissible values for this member, see specification T10/1363-D Revision-02A, by National Committee for Information Technology Standards (NCITS).
Reserved10
Reserved.
A2Values
Reserved.
Reserved11
Reserved.
A3Values
Reserved.
Reserved12
Reserved.

Headers

Declared in ntddcdrm.h. Include ntddcdrm.h.

See Also

IOCTL_CDROM_READ_TOC_EX, CDROM_READ_TOC_EX, CDROM_TOC_ATIP_DATA


CDROM_TOC_CD_TEXT_DATA_BLOCK

This structure contains CD text descriptor data used in conjunction with the data in the CDROM_TOC_CD_TEXT_DATA structure.

typedef struct _CDROM_TOC_CD_TEXT_DATA_BLOCK {
  UCHAR  PackType;
  UCHAR  TrackNumber:7;
  UCHAR  ExtensionFlag:1;
  UCHAR  SequenceNumber;
  UCHAR  CharacterPosition:4;
  UCHAR  BlockNumber:3;
  UCHAR  Unicode:1;
  union {
    UCHAR  Text[12];
    WCHAR  WText[6];
  };
  UCHAR  CRC[2];
} CDROM_TOC_CD_TEXT_DATA_BLOCK, *PCDROM_TOC_CD_TEXT_DATA_BLOCK;

Members

PackType
Indicates the type of pack data, as follows:
Value Meaning
CDROM_CD_TEXT_PACK_ALBUM_NAME
Title of album or track.
CDROM_CD_TEXT_PACK_PERFORMER
Names of the performers (in ASCII).
CDROM_CD_TEXT_PACK_SONGWRITER
Names of the songwriters (in ASCII).
CDROM_CD_TEXT_PACK_COMPOSER
Names of the composers (in ASCII).
CDROM_CD_TEXT_PACK_ARRANGER
Names of the arrangers (in ASCII).
CDROM_CD_TEXT_PACK_MESSAGES
Messages from content provider and/or artist (in ASCII).
CDROM_CD_TEXT_PACK_DISC_ID
Disc identification information.
CDROM_CD_TEXT_PACK_GENRE
Genre identification and information.
CDROM_CD_TEXT_PACK_TOC_INFO
Table of contents information.
CDROM_CD_TEXT_PACK_TOC_INFO2
Second table of contents information.
CDROM_CD_TEXT_PACK_UPC_EAN
UPC/EAN code of the album and ISRC code of each track.
CDROM_CD_TEXT_PACK_SIZE_INFO
Size information for the block.

TrackNumber
For information on the permissible values for this member, see specification T10/1363-D Revision-02A, by National Committee for Information Technology Standards (NCITS).
ExtensionFlag
Must be set to zero.
SequenceNumber
For information on the permissible values for this member, see specification T10/1363-D Revision-02A, by National Committee for Information Technology Standards (NCITS).
CharacterPosition
For information on the permissible values for this member, see specification T10/1363-D Revision-02A, by National Committee for Information Technology Standards (NCITS).
BlockNumber
For information on the permissible values for this member, see specification T10/1363-D Revision-02A, by National Committee for Information Technology Standards (NCITS).
Unicode
Indicates whether text is stored in Unicode format.
Text
Text data in the form of 8-bit characters.
WText
Text data in the form of 16-bit (wide) characters.
CRC
Cyclic redundancy check.

Headers

Declared in ntddcdrm.h. Include ntddcdrm.h.

See Also

IOCTL_CDROM_READ_TOC_EX, CDROM_READ_TOC_EX, CDROM_TOC_CD_TEXT_DATA


CDROM_TOC_FULL_TOC_DATA

Device control IRPs with a control code of IOCTL_CDROM_READ_TOC_EX and a format of CDROM_READ_TOC_EX_FORMAT_FULL_TOC return their output data in this structure optionally followed by a series of descriptors of type CDROM_TOC_FULL_TOC_DATA_BLOCK.

typedef struct _CDROM_TOC_FULL_TOC_DATA {
  UCHAR  Length[2];
  UCHAR  FirstCompleteSession;
  UCHAR  LastCompleteSession;
  CDROM_TOC_FULL_TOC_DATA_BLOCK  Descriptors[0];
} CDROM_TOC_FULL_TOC_DATA, *PCDROM_TOC_FULL_TOC_DATA;

Members

Length
Indicates the length, in bytes, of the table of contents data. This length value does not include the length of the Length member itself.
FirstCompleteSession
First complete session number.
LastCompleteSession
Last complete session number.
Descriptors
Zero or more track descriptors. See CDROM_TOC_FULL_TOC_DATA_BLOCK for a description of the track descriptor.

Headers

Declared in ntddcdrm.h. Include ntddcdrm.h.

See Also

IOCTL_CDROM_READ_TOC_EX, CDROM_READ_TOC_EX, CDROM_TOC_FULL_TOC_DATA_BLOCK


CDROM_TOC_FULL_TOC_DATA_BLOCK

The CDROM_TOC_FULL_TOC_DATA_BLOCK structure contains track descriptor data used in conjunction with the data from the CDROM_TOC_FULL_TOC_DATA structure.

typedef struct _CDROM_TOC_FULL_TOC_DATA_BLOCK {
  UCHAR  SessionNumber;
  UCHAR  Control:4;
  UCHAR  Adr:4;
  UCHAR  Reserved1;
  UCHAR  Point;
  UCHAR  MsfExtra[3];
  UCHAR  Zero;
  UCHAR  Msf[3];
} CDROM_TOC_FULL_TOC_DATA_BLOCK, *PCDROM_TOC_FULL_TOC_DATA_BLOCK;

Members

SessionNumber
Session number for the track.
Control
Indicates the attributes of the track.
Adr
Indicates the type of information encoded in the Q subchannel of the block where this table of contents entry was found.
Value Meaning
ADR_NO_MODE_INFORMATION
Q subchannel mode information not supplied.
ADR_ENCODES_CURRENT_POSITION
Q subchannel encodes current position data
(that is, track, index, absolute address, relative address).
ADR_ENCODES_MEDIA_CATALOG
Q subchannel encodes media catalog number.
ADR_ENCODES_ISRC
Q subchannel encodes ISRC.

Reserved1
Reserved.
Point
Defines various types of information within the table of contents lead-in area. For information on the permissible values for this member, see specification T10/1363-D Revision-02A, by National Committee for Information Technology Standards (NCITS).
MsfExtra
For information on the permissible values for this member, see specification T10/1363-D Revision-02A, by National Committee for Information Technology Standards (NCITS).
Zero
Zero bit.
Msf
Minute, second, and frame. Msf[0] contains the minutes field. Msf[1] contains the seconds field, and Msf[2] contains the frames field. MSF is a format similar to logical block addressing.

Headers

Declared in ntddcdrm.h. Include ntddcdrm.h.

See Also

IOCTL_CDROM_READ_TOC_EX, CDROM_READ_TOC_EX, CDROM_TOC_FULL_TOC_DATA


CDROM_TOC_PMA_DATA

Device control IRPs with a control code of IOCTL_CDROM_READ_TOC_EX and a format of CDROM_READ_TOC_EX_FORMAT_PMA return their output data in this structure optionally followed by a series of descriptors of type CDROM_TOC_FULL_TOC_DATA_BLOCK.

typedef struct _CDROM_TOC_PMA_DATA {
  UCHAR  Length[2];
  UCHAR  Reserved1;
  UCHAR  Reserved2;
  CDROM_TOC_FULL_TOC_DATA_BLOCK  Descriptors[0];
} CDROM_TOC_PMA_DATA, *PCDROM_TOC_PMA_DATA;

Members

Length
Indicates the length, in bytes, of the table of contents data. This length value does not include the length of the Length member itself.
Reserved1
Reserved.
Reserved2
Reserved.
Descriptors
Zero or more track descriptors. See CDROM_TOC_FULL_TOC_DATA_BLOCK for a description of the track descriptor.

Headers

Declared in ntddcdrm.h. Include ntddcdrm.h.

See Also

IOCTL_CDROM_READ_TOC_EX, CDROM_READ_TOC_EX, CDROM_TOC_FULL_TOC_DATA_BLOCK


CDROM_TOC_SESSION_DATA

Device control IRPs with a control code of IOCTL_CDROM_READ_TOC_EX and a format of CDROM_READ_TOC_EX_FORMAT_SESSION return their output data in this structure followed by a series of TRACK_DATA structures.

typedef struct _CDROM_TOC_SESSION_DATA {
  UCHAR  Length[2];
  UCHAR  FirstCompleteSession;
  UCHAR  LastCompleteSession;
  TRACK_DATA  TrackData[1];
} CDROM_TOC_SESSION_DATA, CDROM_TOC_SESSION_DATA;

Members

Length
Indicates the length, in bytes, of the table of contents data. This length value does not include the length of the Length member itself.
FirstCompleteSession
First complete session number.
LastCompleteSession
Last complete session number.
TrackData
Data for the first track of the last finished session. This data includes the starting address and number of the track.

Headers

Declared in ntddcdrm.h. Include ntddcdrm.h.

See Also

IOCTL_CDROM_READ_TOC_EX, CDROM_READ_TOC_EX, TRACK_DATA


CHANGER_DEVICE_PROBLEM_TYPE

The CHANGER_DEVICE_PROBLEM_TYPE data type contains the values returned by the ChangerPerformDiagnostics routine.

typedef enum _CHANGER_DEVICE_PROBLEM_TYPE {
  DeviceProblemNone,
  DeviceProblemHardware,
  DeviceProblemCHMError,
  DeviceProblemDoorOpen,
  DeviceProblemCalibrationError,
  DeviceProblemTargetFailure,
  DeviceProblemCHMMoveError,
  DeviceProblemCHMZeroError,
  DeviceProblemCartridgeInsertError,
  DeviceProblemPositionError,
  DeviceProblemSensorError,
  DeviceProblemCartridgeEjectError,
  DeviceProblemGripperError,
  DeviceProblemDriveError
} CHANGER_DEVICE_PROBLEM_TYPE, *PCHANGER_DEVICE_PROBLEM_TYPE;

Enumerators

DeviceProblemNone
The device has no problem.
DeviceProblemHardware
The device has had a hardware error.
DeviceProblemCHMError
The Cartridge Handling Mechanism (CHM) has some problem.
DeviceProblemDoorOpen
The changer's door is open.
DeviceProblemCalibrationError
The changer has a calibration problem.
DeviceProblemTargetFailure
A target failure has occurred.
DeviceProblemCHMMoveError
The CHM is blocked and is cannot move.
DeviceProblemCHMZeroError
The CHM could not define zero on one or more of its axis.
DeviceProblemCartridgeInsertError
An error occurred while loading a cartridge in the drive.
DeviceProblemPositionError
The CHM has a problem positioning itself to some point.
DeviceProblemSensorError
The device's sensors are malfunctioning.
DeviceProblemCartridgeEjectError
An error occurred while unloading a cartridge.
DeviceProblemGripperError
The media gripper has a problem.
DeviceProblemDriveError
The changer's drive is malfunctioning.

Headers

Declared in ntddchgr. Include ntddchgr.h.

See Also

ChangerPerformDiagnostics, WMI_CHANGER_PROBLEM_DEVICE_ERROR


CHANGER_ELEMENT

The CHANGER_ELEMENT structure contains a description of a changer element.

typedef struct _CHANGER_ELEMENT {
  ELEMENT_TYPE  ElementType;
  ULONG  ElementAddress;
} CHANGER_ELEMENT, *PCHANGER_ELEMENT;

Members

ElementType
Indicates the type of element. Can be one of the following values:
Value Meaning
AllElements
All elements of a changer, including its robotic transport, drives, slots, and IEport. AllElements is valid only in a ChangerGetElementStatus or ChangerInitializeElementStatus call.
ChangerTransport
The changer's robotic transport element, which is used to move media between IEports, slots, and drives.
ChangerSlot
A storage element, which is a slot in the changer in which media is stored when not mounted in a drive.
ChangerIEPort
An import/export element (IEport), which is a single or multiple-cartridge access port in some changers. An element is an IEport only if it is possible to move a piece of media from a slot to the IEport.
ChangerDrive
A data transfer element where data can be read from and written to media.
ChangerDoor
A mechanism that provides access to all media in a changer at one time (as compared to an IEport that provides access to one or more, but not all, media). For example, a large front door or a magazine that contains all media in the changer are elements of this type. ChangerDoor is valid only in a ChangerSetAccess call.
ChangerKeypad
The keypad or other input control on the front panel of a changer. ChangerKeypad is valid only in a ChangerSetAccess call.

ElementAddress
The element's zero-based address used by the system. A changer miniclass driver is responsible for translating this address to the device-specific address used by the changer.

Headers

Declared in ntddchgr.h. Include ntddchgr.h.

Comments

CHANGER_ELEMENT is used by both the changer class driver and a changer miniclass driver to describe a changer element.

On input, a changer miniclass driver must translate the zero-based address in ElementAddress to a device-specific address before accessing the element. On output, the driver must translate a device-specific address to the zero-based equivalent before filling in ElementAddress.

See Also

CHANGER_ELEMENT_LIST, CHANGER_ELEMENT_STATUS


CHANGER_ELEMENT_LIST

The CHANGER_ELEMENT_LIST structure indicates a range of elements of a single type.

typedef struct _CHANGER_ELEMENT_LIST {
  CHANGER_ELEMENT  Element;
  ULONG  NumberOfElements;
} CHANGER_ELEMENT_LIST, *PCHANGER_ELEMENT_LIST;

Members

Element
Describes the first element in a range NumberOfElements long.
NumberOfElements
Specifies the number of elements in the range.

Headers

Declared in ntddchgr. Include ntddchgr.h.

Comments

A changer class driver uses CHANGER_ELEMENT_LIST to indicate a range of elements of a single type, typically for an operation such as getting or initializing the status of multiple elements.

See Also

CHANGER_ELEMENT, ChangerGetElementStatus, ChangerInitializeElementStatus


CHANGER_ELEMENT_STATUS

The ChangerGetElementStatus routine returns status information in this structure.

typedef struct _CHANGER_ELEMENT_STATUS {
  CHANGER_ELEMENT  Element;
  CHANGER_ELEMENT  SrcElementAddress;
  ULONG  Flags;
  ULONG  ExceptionCode;
  UCHAR  TargetId;
  UCHAR  Lun;
  USHORT  Reserved;
  UCHAR  PrimaryVolumeID[MAX_VOLUME_ID_SIZE];
  UCHAR  AlternateVolumeID[MAX_VOLUME_ID_SIZE];
} CHANGER_ELEMENT_STATUS, *PCHANGER_ELEMENT_STATUS;

Members

Element
Specifies the element to which this structure refers.
SrcElementAddress
Specifies the element from which the media currently in this element was most recently moved. This member is valid only if ELEMENT_STATUS_SVALID is also set in Flags. This value must be a zero-based offset from the device-unique value
Flags
Indicates the status of the element, which can be one or more of the following values:
Value Meaning
ELEMENT_STATUS_FULL
The element contains a piece of media. This flag is valid if ElementType in the Element member is ChangerDrive, ChangerSlot, or ChangerTransport. If ElementType is ChangerIEPort, this flag is valid only if CHANGER_REPORT_IEPORT_STATE is also set in Features0 of GET_CHANGER_PARAMETERS.
ELEMENT_STATUS_IMPEXP
The media in this element was placed there by an operator. This flag is valid only if ElementType in the Element member is ChangerIEPort.
ELEMENT_STATUS_EXCEPT
The element is in an abnormal state. Check the ExceptionCode member for more information.
ELEMENT_STATUS_ACCESS
The changer's transport element can access the piece of media in this element. The miniclass driver clears this flag to indicate that the media is not accessible for one of the following reasons: If ElementType in the Element member is ChangerSlot, the slot is not present in the changer (for example, the magazine containing the slot has been physically removed). If ElementType is ChangerDrive, the drive is broken or has been removed. If ElementType is ChangerIEPort, the IEport is extended.
ELEMENT_STATUS_EXENAB
The element supports export of media through the changer's IEport.
ELEMENT_STATUS_INENAB
The element supports import of media through the changer's IEport.
ELEMENT_STATUS_LUN_VALID
The logical unit number in the Lun member is valid. This flag is valid only if ElementType in the Element member is ChangerDrive.
ELEMENT_STATUS_ID_VALID
The SCSI target ID in the TargetID member is valid. This flag is valid only if ElementType in the Element member is ChangerDrive.
ELEMENT_STATUS_NOT_BUS
The drive at the address indicated by Lun and TargetID is on a different SCSI bus than the changer itself.
ELEMENT_STATUS_INVERT
The media in the element was flipped. This flag is valid only if the ELEMENT_STATUS_SVALID flag is also set.
ELEMENT_STATUS_SVALID
The SourceElement member and ELEMENT_STATUS_INVERT flag are both valid.
ELEMENT_STATUS_PVOLTAG
Primary volume information in the PrimaryVolumeID member is valid.
ELEMENT_STATUS_AVOLTAG
Alternate volume information in the AlternateVolumeID member is valid.

ExceptionCode
Indicates that the element is in an abnormal state. This member is valid only if ELEMENT_STATUS_EXCEPT is set in Flags. ExceptionCode can be set to one of the following values.
Value Meaning
ERROR_LABEL_UNREADABLE
The changer's bar-code reader could not read the bar code label on the piece of media in this element, because the media is missing, damaged, improperly positioned, or upside down.
ERROR_LABEL_QUESTIONABLE
The label might be invalid due to a unit attention condition.
ERROR_SLOT_NOT_PRESENT
The slot at this element address is currently not installed in the changer. A miniclass driver sets this code for each slot in a removable magazine to indicate that the magazine has been removed. .
ERROR_DRIVE_NOT_INSTALLED
The drive at this element address is absent. If a changer can continue to operate without the drive, its miniclass driver sets ERROR_DRIVE_NOT_INSTALLED for the drive.
ERROR_TRAY_MALFUNCTION
The drive at this element address has a tray that must be extended to load or remove media, and the tray is not extending as required.
ERROR_UNHANDLED_ERROR
Unknown error condition.

TargetId
For a SCSI changer, specifies the SCSI target ID of the drive at this element address. This member is valid only if ElementType in the Element member is ChangerDrive and ELEMENT_STATUS_ID_VALID is set in Flags.
Lun
Specifies the SCSI logical unit number of the drive at this element address. This member is valid only if ElementType in the Element member is ChangerDrive and ELEMENT_STATUS_LUN_VALID is set in Flags.
Reserved
Reserved for future use. The value of this member must be zero.
PrimaryVolumeID
Specifies the primary volume identifier for the media. If the changer supports a bar-code reader and the reader is installed (as indicated by CHANGER_BAR_CODE_SCANNER_INSTALLED in Features0 of GET_CHANGER_PARAMETERS), the miniclass driver must set PrimaryVolumeID to the bar code of the media. If the changer does not support a bar-code reader, the miniclass driver should set PrimaryVolumeID to the value previously assigned to the media using the ChangerQueryVolumeTags routine with an ASSERT_PRIMARY or REPLACE_PRIMARY action. This member is valid only if ELEMENT_STATUS_PVOLTAG is also set in Flags. If the volume identifier is missing or unreadable, the miniclass driver should clear this flag and set the appropriate error status.
AlternateVolumeID
Specifies alternate volume identification for the media. This member is valid for two-sided media only, and pertains to the ID of the inverted side. It never represents a bar code. The miniclass driver must set AlternateVolumeID to the value previously assigned to the media using the ChangerQueryVolumeTags routine with an ASSERT_ALTERNATE or REPLACE_ALTERNATE action. This member is valid only if ELEMENT_STATUS_AVOLTAG is also set in Flags.

Headers

Declared in ntddchgr. Include ntddchgr.h.

Comments

For most element types, changer miniclass drivers use CHANGER_ELEMENT_STATUS to report the status of specified elements to the changer class driver. Some elements of type ChangerDrive, however, return product information data. If the device provides product information, the miniclass driver will report the element status data in a structure of type CHANGER_ELEMENT_STATUS_EX instead of using CHANGER_ELEMENT_STATUS. The miniclass driver indicates that product information is present by setting ELEMENT_STATUS_PRODUCT_DATA in the Flags member of the structure.

See Also

CHANGER_ELEMENT, ChangerGetElementStatus, ChangerQueryVolumeTags, CHANGER_ELEMENT_STATUS_EX, IOCTL_CHANGER_GET_ELEMENT_STATUS


CHANGER_ELEMENT_STATUS_EX

The ChangerGetElementStatus routine returns status information in this structure.

typedef  struct _CHANGER_ELEMENT_STATUS_EX {
  CHANGER_ELEMENT  Element;
  CHANGER_ELEMENT  SrcElementAddress;
  ULONG  Flags;
  ULONG  ExceptionCode;
  UCHAR  TargetId;
  UCHAR  Lun;
  USHORT  Reserved;
  UCHAR  PrimaryVolumeID[MAX_VOLUME_ID_SIZE];
  UCHAR  AlternateVolumeID[MAX_VOLUME_ID_SIZE];
  UCHAR  VendorIdentification[VENDOR_ID_LENGTH];
  UCHAR  ProductIdentification[PRODUCT_ID_LENGTH];
  UCHAR  SerialNumber[SERIAL_NUMBER_LENGTH];
} CHANGER_ELEMENT_STATUS_EX, *PCHANGER_ELEMENT_STATUS_EX;

Members

This structure has the same members as CHANGER_ELEMENT_STATUS plus three extra members:
VendorIdentification
Vendor ID
ProductIdentification
Product ID
SerialNumber
Serial number

Headers

Declared in ntddchgr. Include ntddchgr.h.

Comments

The ChangerGetElementStatus routine returns status information in this structure if vendor, product, or serial number information is needed. Otherwise, ChangerGetElementStatus returns status information in the CHANGER_ELEMENT_STATUS structure.

See Also

CHANGER_ELEMENT_STATUS, ChangerGetElementStatus, CHANGER_ELEMENT, IOCTL_CHANGER_GET_ELEMENT_STATUS


CHANGER_SEND_VOLUME_TAG_INFORMATION

This structure is passed to the ChangerQueryVolumeTags routine and is used to specify a search criterion for retrieving changer elements.

typedef struct _CHANGER_SEND_VOLUME_TAG_INFORMATION {
  CHANGER_ELEMENT StartingElement;
  ULONG  ActionCode;
  UCHAR  VolumeIDTemplate[MAX_VOLUME_TEMPLATE_SIZE];
} CHANGER_SEND_VOLUME_TAG_INFORMATION, *PCHANGER_SEND_VOLUME_TAG_INFORMATION;

Members

StartingElement
Describes the first element of the range to search for or to set.
ActionCode
Indicates the operation to perform. The Features0 member of GET_CHANGER_PARAMETERS indicates whether the changer supports a particular category of operation:
  • Translate operations, also known as "searching operations", request that the target device search its volume tag information for elements that match the template passed to the device. Valid only if Features0 is set to CHANGER_VOLUME_SEARCH.
  • Assert operations define volume tag information for a single element. Valid only if Features0 is set to CHANGER_VOLUME_ASSERT.
  • Replace operations define volume tag information for a single element, overwriting any information previously defined. Valid only if Features0 is set to CHANGER_VOLUME_REPLACE.
  • Undefined operations clear previously defined volume tag information for a single element. Valid only if Features0 is set to CHANGER_VOLUME_UNDEFINE.

ActionCode can have one of the following values:
Value | Meaning
SEARCH_ALL | Search all defined volume tags
SEARCH_PRIMARY | Search only primary volume tags
SEARCH_ALTERNATE | Search only alternate volume tags
SEARCH_ALL_NO_SEQ | Search all defined volume tags but ignore sequence numbers
SEARCH_PRI_NO_SEQ | Search only primary volume tags but ignore sequence numbers
SEARCH_ALT_NO_SEQ | Search only alternate volume tags but ignore sequence numbers
ASSERT_PRIMARY | Define the primary volume tag for a volume that currently has none defined
ASSERT_ALTERNATE | Define the alternate volume tag for a volume that currently has none defined
REPLACE_PRIMARY | Replace the existing primary volume tag with a new tag
REPLACE_ALTERNATE | Replace the alternate volume tag with a new tag
UNDEFINE_PRIMARY | Clear the primary volume tag
UNDEFINE_ALTERNATE | Clear the alternate volume tag

VolumeIDTemplate
Specifies the template to be used by the device to search for volume IDs. For a translate operation, the template can include the wildcard characters, asterisk (*) and question mark (?), to search for volumes that match the template. For other operations, the template specifies a single volume.

Headers

Declared in ntddchgr.h. Include ntddchgr.h.

See Also

READ_ELEMENT_ADDRESS_INFO, GET_CHANGER_PARAMETERS, ChangerQueryVolumeTags


CREATE_DISK

The CREATE_DISK structure is used with the IOCTL IOCTL_DISK_CREATE_DISK to initialize a virgin disk with an empty GPT partition table.

typedef struct _CREATE_DISK {
  PARTITION_STYLE  PartitionStyle;
  union {
    CREATE_DISK_MBR  Mbr;
    CREATE_DISK_GPT  Gpt;
  };
} CREATE_DISK, *PCREATE_DISK;

Members

PartitionStyle
Takes a PARTITION_STYLE enumerated value that specifies the type of partition table to use when formatting the disk.
Mbr
Contains the signature used to initialize an MBR-style disk partition for the first time. This member is valid when PartitionStyle is PARTITION_STYLE_MBR. For more information, see CREATE_DISK_MBR.
Gpt
Contains data used to initialize a GPT-style disk partition for the first time. This member is valid when PartitionStyle is PARTITION_STYLE_GPT. For more information, see CREATE_DISK_GPT.

Headers

Declared in ntdddisk.h. Include ntdddisk.h.

See Also

IOCTL_DISK_CREATE_DISK, CREATE_DISK_MBR, CREATE_DISK_GPT, PARTITION_STYLE


CREATE_DISK_GPT

The CREATE_DISK_GPT structure is used with the IOCTL IOCTL_DISK_CREATE_DISK to initialize a virgin disk with an empty GPT partition table.

typedef struct _CREATE_DISK_GPT {
  GUID  DiskId;
  ULONG  MaxPartitionCount;
} CREATE_DISK_GPT, *PCREATE_DISK_GPT;

Members

DiskId
Specifies the GUID that uniquely identifies the disk.
MaxPartitionCount
Specifies the maximum number of partitions allowed on the disk.

Headers

Declared in ntdddisk.h. Include ntdddisk.h.

See Also

CREATE_DISK, IOCTL_DISK_CREATE_DISK


CREATE_DISK_MBR

The CREATE_DISK_MBR structure is used with the IOCTL IOCTL_DISK_CREATE_DISK to initialize a virgin disk with an empty MBR partition table.

typedef struct _CREATE_DISK_MBR {
  ULONG  Signature;
} CREATE_DISK_MBR, *PCREATE_DISK_MBR;

Members

Signature
Specifies the disk signature value, which uniquely identifies the disk.

Headers

Declared in ntdddisk.h. Include ntdddisk.h.

See Also

CREATE_DISK, IOCTL_DISK_CREATE_DISK


DETECTION_TYPE

The DETECTION_TYPE enumeration type is used in conjunction with the IOCTL_DISK_GET_DRIVE_GEOMETRY_EX request and the DISK_GEOMETRY_EX structure to determine the type of formatting used by the BIOS to record the disk geometry.

typedef enum _DETECTION_TYPE {
  DetectNone,
  DetectInt13,
  DetectExInt13;
} DETECTION_TYPE;

Enumerators

DetectNone
Indicates that the disk contains neither an INT 13 partition nor an extended INT 13 partition.
DetectInt13
Indicates that the disk has a standard INT 13 partition.
DetectExInt13
Indicates that the disk contains an extended INT 13 partition.

Headers

Declared in ntddk.h and ntdddisk.h. Include ntddk.h or ntdddisk.h.

Comments

Possible formatting types are the standard INT 13 partition format or the extended INT 13 partition format.

See Also

DISK_DETECTION_INFO


DEVICE_MEDIA_INFO

A storage class driver returns an array of DEVICE_MEDIA_INFO structures, embedded in a GET_MEDIA_TYPES structure, in response to an IOCTL_STORAGE_GET_MEDIA_TYPES_EX device-control request.

typedef struct _DEVICE_MEDIA_INFO {
  union {
    struct {
      LARGE_INTEGER Cylinders;
      STORAGE_MEDIA_TYPE MediaType;
      ULONG TracksPerCylinder;
      ULONG SectorsPerTrack;
      ULONG BytesPerSector;
      ULONG NumberMediaSides;
      ULONG MediaCharacteristics;
    } DiskInfo;
    struct {
      LARGE_INTEGER Cylinders;
      STORAGE_MEDIA_TYPE MediaType;
      ULONG TracksPerCylinder;
      ULONG SectorsPerTrack;
      ULONG BytesPerSector;
      ULONG NumberMediaSides;
      ULONG MediaCharacteristics;
    } RemovableDiskInfo;
    struct {
      STORAGE_MEDIA_TYPE MediaType;
      ULONG   MediaCharacteristics;
      ULONG   CurrentBlockSize;
      STORAGE_BUS_TYPE BusType;
      union {
        struct {
          UCHAR MediumType;
          UCHAR DensityCode;
        } ScsiInformation;
      } BusSpecificData;
    } TapeInfo;
  } DeviceSpecific;
} DEVICE_MEDIA_INFO, *PDEVICE_MEDIA_INFO;

Members

DeviceSpecific.DiskInfo
Describes a nonremovable (fixed) disk.
Cylinders
Specifies the number of cylinders on this disk.
MediaType
Specifies a MEDIA_TYPE of FixedMedia. MEDIA_TYPE values are defined in winioctl.h.
TracksPerCylinder
Specifies the number of tracks per cylinder.
SectorsPerTrack
Specifies the number of sectors per track.
BytesPerSector
Specifies the number of bytes per sector.
NumberMediaSides
Specifies the number of sides of the disk that can contain data: either 1 for one-sided media or 2 for two-sided media.
MediaCharacteristics
Specifies characteristics of the disk indicated by one or more of the following flags, ORed together:

MEDIA_ERASEABLE

MEDIA_WRITE_ONCE

MEDIA_READ_ONLY

MEDIA_READ_WRITE

MEDIA_WRITE_PROTECTED

MEDIA_CURRENTLY_MOUNTED

DeviceSpecific.RemovableDiskInfo
Describes a removable (nonfixed) disk.
Cylinders
Specifies the number of cylinders on this disk.
MediaType
Specifies a MEDIA_TYPE or STORAGE_MEDIA_TYPE value that indicates the type of removable disk. MEDIA_TYPE and STORAGE_MEDIA_TYPE values are defined in winioctl.h.
TracksPerCylinder
Specifies the number of tracks per cylinder.
SectorsPerTrack
Specifies the number of sectors per track.
BytesPerSector
Specifies the number of bytes per sector.
NumberMediaSides
Specifies the number of sides of the disk that can contain data: 1 for one-sided media or 2 for two-sided media.
MediaCharacteristics
Specifies characteristics of the disk, indicated by MEDIA_XXX flags ORed together. For a list of MEDIA_XXX flags, see DeviceSpecific.DiskInfo.MediaCharacteristics member of the DeviceSpecific.DiskInfo structure.
DeviceSpecific.TapeInfo
Describes a tape.
MediaType
Specifies a STORAGE_MEDIA_TYPE value that indicates the type of tape described in this structure. STORAGE_MEDIA_TYPE values are defined in winioctl.h.
MediaCharacteristics
Specifies characteristics of the tape, indicated by MEDIA_XXX flags ORed together. For a list of MEDIA_XXX flags, see the MediaCharacteristics member of the DeviceSpecific.DiskInfo structure.
CurrentBlockSize
Specifies the current block size, in bytes.
BusType
Specifies the type of bus to which the tape drive is connected. Can be one of the following: BusTypeScsi, BusTypeAtapi, BusTypeAta, BusType1394, BusTypeSsa, BusTypeFibre, BusTypeUSB, or BusTypeUnknown for a bus that is not listed.
BusSpecificData.ScsiInformation
Specifies bus-specific information from mode page data that describes the medium supported by the tape drive. Values for other bus types are TBD.
BusSpecificData.ScsiInformation.MediumType
Specifies the SCSI-specific medium type.
BusSpecificData.ScsiInformation.DensityCode
Specifies the SCSI-specific current operating density for read/write operations.

Headers

Declared in ntddstor.h. Include ntddstor.h.

Comments

This structure is used by a storage driver to indicate the types of media supported by a device and which type is currently mounted, if any. A driver must provide this information if it might control drives in a media library or changer or if its device might be accessed by the Removable Storage Manager (RSM).

The driver fills in an array of DEVICE_MEDIA_INFO structures, one for each medium type supported by the device, embedded in a GET_MEDIA_TYPES structure.

See Also

TapeMiniGetMediaTypes


DISK_CONTROLLER_NUMBER

DISK_CONTROLLER_NUMBER is used with IOCTL_DISK_CONTROLLER_NUMBER to retrieve the controller number and disk number of an IDE disk.

typedef struct _DISK_CONTROLLER_NUMBER {
  ULONG  ControllerNumber;
  ULONG  DiskNumber;
} DISK_CONTROLLER_NUMBER, *PDISK_CONTROLLER_NUMBER;

Members

ControllerNumber
Number of the IDE controller for the disk.
DiskNumber
Number of the disk.

Headers

Declared in ntddk.h and ntdddisk.h. Include ntddk.h or ntdddisk.h.

Comments

After DISK_CONTROLLER_NUMBER receives the controller number and the disk number, these values can be used to determine whether the disk is attached to the primary or to the secondary IDE controller.

See Also

IOCTL_DISK_CONTROLLER_NUMBER


DISK_DETECTION_INFO

The DISK_DETECTION_INFO structure contains the detected drive parameters that are supplied by an x86 PC BIOS on boot.

typedef struct _DISK_DETECTION_INFO {
  ULONG  SizeOfDetectInfo;
  DETECTION_TYPE  DetectionType;
  union {
    struct {
      DISK_INT13_INFO  Int13;
      DISK_EX_INT13_INFO  ExInt13;
    };
  };
} DISK_DETECTION_INFO, *PDISK_DETECTION_INFO;

Members

SizeOfDetectInfo
Quantity, in bytes, of retrieved detect information.
DetectionType
Indicates one of three possible detection types:
  1. DetectNone
  2. DetectInt13
  3. DetectExInt13

See the structure DETECTION_TYPE for further information.

Int13
Contains disk parameters for INT 13 type partitions. This member is used if DetectionType == DetectInt13.
ExInt13
Contains disk parameters for extended INT 13 type partitions. This member is used if DetectionType == DetectExInt13.

Headers

Declared in ntddk.h and ntdddisk.h. Include ntddk.h or ntdddisk.h.

Comments

The BIOS returns the detected drive information in two formats. If the partition has a standard INT 13 format, the BIOS returns the drive parameters defined by the structure DISK_INT13_INFO:

typedef struct _DISK_INT13_INFO {
  USHORT DriveSelect;
  ULONG MaxCylinders;
  USHORT SectorsPerTrack;
  USHORT MaxHeads;
  USHORT NumberDrives;
} DISK_INT13_INFO, *PDISK_INT13_INFO;

If the partition has an extended INT 13 format, the BIOS returns the drive parameters defined by the structure DISK_INT13_INFO:

typedef struct _DISK_EX_INT13_INFO {
  USHORT ExBufferSize;
  USHORT ExFlags;
  ULONG ExCylinders;
  ULONG ExHeads;
  ULONG ExSectorsPerTrack;
  ULONG64 ExSectorsPerDrive;
  USHORT ExSectorSize;
  USHORT ExReserved;
} DISK_EX_INT13_INFO, *PDISK_EX_INT13_INFO;

Readers should consult BIOS documentation for the definition of the members of these two structures.

See Also

DISK_GEOMETRY_EX


DISK_GEOMETRY

The DISK_GEOMETRY structure is obsolete and provided only to support existing drivers. New drivers must use DISK_GEOMETRY_EX. DISK_GEOMETRY is used in conjunction with the IOCTL_DISK_GET_DRIVE_GEOMETRY and the IOCTL_DISK_GET_MEDIA_TYPES IOCTLs, in order to retrieve information about the physical disk's geometry (media type, number of cylinders, tracks per cylinder, sectors per track, and bytes per sector). IOCTL_DISK_GET_MEDIA_TYPES causes an array of these structures to be returned.

typedef struct _DISK_GEOMETRY {
  LARGE_INTEGER  Cylinders;
  MEDIA_TYPE  MediaType;
  ULONG  TracksPerCylinder;
  ULONG  SectorsPerTrack;
  ULONG  BytesPerSector;
} DISK_GEOMETRY, *PDISK_GEOMETRY;

Headers

Declared in ntddk.h and ntdddisk.h. Include ntddk.h or ntdddisk.h.

Comments

DISK_GEOMETRY_EX must be used with new drivers, in order to accommodate GUID Partition Table (GPT) partitions. The DISK_GEOMETRY structure is nested within the DISK_GEOMETRY_EX structure.

See Also

DISK_GEOMETRY_EX, IOCTL_DISK_GET_DRIVE_GEOMETRY, IOCTL_DISK_GET_MEDIA_TYPES


DISK_GEOMETRY_EX

The DISK_GEOMETRY_EX structure is a variable-length structure composed of a DISK_GEOMETRY structure followed by a DISK_PARTITION_INFO structure followed, in turn, by a DISK_DETECTION_INFO structure.

typedef struct _DISK_GEOMETRY_EX {
  DISK_GEOMETRY  Geometry;
  LARGE_INTEGER  DiskSize;
  UCHAR  Data[1];
} DISK_GEOMETRY_EX, *PDISK_GEOMETRY_EX;

Headers

Declared in ntddk.h and ntdddisk.h. Include ntddk.h or ntdddisk.h.

Comments

DISK_GEOMETRY_EX is used in conjunction with the IOCTL_DISK_GET_DRIVE_GEOMETRY_EX and the IOCTL_DISK_GET_MEDIA_TYPES IOCTLs, in order to retrieve information about the physical disk's geometry (media type, number of cylinders, tracks per cylinder, sectors per track, and bytes per sector).

Since the partition and detect information are not at fixed locations within the DISK_GEOMETRY_EX structure, htdddisk.h provides two macros for accessing this information. Both macros take a pointer to a structure of type DISK_GEOMETRY_EX as an argument:

#define DiskGeometryGetPartition(Geometry)\
   ((PDISK_PARTITION_INFO)((Geometry)+1))

#define DiskGeometryGetDetect(Geometry)\
 ((PDISK_DETECTION_INFO)(((PBYTE)DiskGeometryGetPartition(Geometry) + DiskGeometryGetPartition(Geometry) -> SizeOfPartitionInfo)))

See Also

DISK_GEOMETRY, DISK_GEOMETRY_EX, DISK_PARTITION_INFO, DISK_DETECTION_INFO


DISK_PARTITION_INFO

The DISK_PARTITION_INFO structure is used to report information on the disk's partition table.

typedef struct _DISK_PARTITION_INFO {
  ULONG  SizeOfPartitionInfo;
  PARTITION_STYLE  PartitionStyle;
  union {
    struct {
      ULONG  Signature;
      ULONG  CheckSum;
    } Mbr;
    struct {
      GUID  DiskId;
    } Gpt;
  };
} DISK_PARTITION_INFO, *PDISK_PARTITION_INFO;

Members

SizeOfPartitionInfo
Size of the partition.
PartitionStyle
Takes a PARTITION_STYLE enumerated value that specifies the type of partition table the disk contains.
Mbr
A structure that specifies the disk signature data for a disk formatted with a Master Boot Record (MBR) format partition table. This member is valid when PartitionStyle is PARTITION_STYLE_MBR. The structure has the following members:
Signature
Specifies the signature value, which uniquely identifies the disk.
CheckSum
Specifies the checksum for the master boot record.
Gpt
A structure that specifies the disk signature data for a disk formatted with a GUID Partition Table (GPT) format partition table. This member is valid when PartitionStyle is PARTITION_STYLE_GPT. The structure has the following members:
DiskId
Specifies the GUID that uniquely identifies the disk.

Headers

Declared in ntdddisk.h. Include ntdddisk.h.

See Also

DISK_GEOMETRY_EX


DISK_PERFORMANCE

The DISK_PERFORMANCE structure is used in conjunction with the IOCTL_DISK_PERFORMANCE request to collect summary disk statistics for purposes of measuring disk performance.

typedef struct _DISK_PERFORMANCE {
  LARGE_INTEGER  BytesRead;
  LARGE_INTEGER  BytesWritten;
  LARGE_INTEGER  ReadTime;
  LARGE_INTEGER  WriteTime;
  LARGE_INTEGER  IdleTime;
  ULONG  ReadCount;
  ULONG  WriteCount;
  ULONG  QueueDepth;
  ULONG  SplitCount;
  LARGE_INTEGER  QueryTime;
  ULONG  StorageDeviceNumber;
  WCHAR  StorageManagerName[8];
} DISK_PERFORMANCE, *PDISK_PERFORMANCE;

Members

BytesRead
Cumulative count of bytes read from the disk since the performance counters were enabled.
BytesWritten
Cumulative count of bytes written to the disk since the performance counters were enabled.
ReadTime
Cumulative time, expressed in increments of 100 nanoseconds, spent on disk reads since the performance counters were enabled.
WriteTime
Cumulative time, expressed in increments of 100 nanoseconds, spent on disk reads since the performance counters were enabled.
IdleTime
Cumulative time, expressed in increments of 100 nanoseconds, since the performance counters were enabled in which there was no disk activity.
ReadCount
Number of disk accesses for reads since the performance counters were enabled.
WriteCount
Number of disk accesses for writes since the performance counters were enabled.
QueueDepth
Snapshot of the number of queued disk I/O requests at the time that the query for performance statistics was performed.
SplitCount
Number of disk accesses by means of an associated IRP since the performance counters were enabled.
QueryTime
A timestamp indicating when the query took place.
StorageDeviceNumber
Unique number assigned to every disk or volume across a particular storage type. The storage types are disk.sys, ftdisk.sys, and dmio.sys.
StorageManagerName
Eight character string that indicates which device driver provided the performance statistics. In Windows® 2000, this can be either "LogiDisk" for the driver logidisk.sys or "PhysDisk" for the driver physdisk.sys. These drivers collect performance statistics for logical units and physical disks respectively. In Windows XP and later operating systems, this can be any of the following three strings: "FTDISK" for the driver ftdisk.sys, "DMIO" for the driver dmio.sys, or PARTMGR" for the driver partmgr.sys. These three drivers collect performance statistics for basic disk volumes, dynamic disk volumes, and physical disks respectively. Note that these strings are eight character case-sensitive strings with blank fill. For example, in the case of the string "FTDISK", the StorageManagerName character array should contain two trailing blanks ("FTDISK<b><b>"), and in the case of the string "DMIO", the arrary should contain four trailing blanks ("DMIO<b><b><b><b>").

Headers

Declared in ntdddisk.h. Include ntdddisk.h.

Comments

Counting halts whenever the performance counters are disabled, but the counters are not reset, so the cumulative values assigned to the structure members might potentially reflect disk activity across several enablings and disablings of the counters.

See Also

IOCTL_DISK_PERFORMANCE, IOCTL_DISK_PERFORMANCE_OFF


DISK_SIGNATURE

DISK_SIGNATURE contains the disk signature information for a disk's partition table.

typedef struct _DISK_SIGNATURE {
  ULONG PartitionStyle;
  union {
    struct {
      ULONG Signature;
      ULONG CheckSum;
    } Mbr;

    struct {
      GUID DiskId;
    } Gpt;
  };
} DISK_SIGNATURE, *PDISK_SIGNATURE;

Members

PartitionStyle
Specifies the type of partition. See PARTITION_STYLE for a description of the possible values.
Mbr
A structure that specifies the disk signature data for a disk formatted with a Master Boot Record (MBR) format partition table. This member is valid when PartitionStyle is PARTITION_STYLE_MBR. The structure has the following members:
Signature
Specifies the signature value, which uniquely identifies the disk.
CheckSum
Specifies the checksum for the master boot record.
Gpt
A structure that specifies the disk signature data for a disk formatted with a GUID Partition Table (GPT) format partition table. This member is valid when PartitionStyle is PARTITION_STYLE_GPT. The structure has the following members:
DiskId
Specifies the GUID that uniquely identifies the disk.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

This structure is only available on Windows XP and later.

See Also

IoReadDiskSignature


DRIVE_LAYOUT_INFORMATION

The DRIVE_LAYOUT_INFORMATION structure is obsolete and is provided only to support existing drivers. New drivers must use DRIVE_LAYOUT_INFORMATION_EX.

The DRIVE_LAYOUT_INFORMATION structure is used to report information about a disk drive and its partitions. It is also used to write new drive layout information to the disk.

typedef struct _DRIVE_LAYOUT_INFORMATION {
    ULONG PartitionCount;
    ULONG Signature;
    PARTITION_INFORMATION PartitionEntry[1];
} DRIVE_LAYOUT_INFORMATION, *PDRIVE_LAYOUT_INFORMATION;

Members

PartitionCount
Number of partitions on the drive.
Signature
The disk signature.
PartitionEntry
Points to an array of PARTITION_INFORMATION structures, one for each partition on the drive.

Headers

Declared in ntdddisk.h. Include ntdddisk.h.

Comments

In Windows 2000 and later operating systems, disk drivers should use structures DRIVE_LAYOUT_INFORMATION_EX and PARTITION_INFORMATION_EX along with routines IoReadPartitionTableEx and IoSetPartitionInformationEx to read and alter partition information on the disk.

See Also

IOCTL_DISK_GET_PARTITION_INFO, IOCTL_DISK_GET_DRIVE_LAYOUT, IOCTL_DISK_SET_DRIVE_LAYOUT, IoReadPartitionTable, IoSetPartitionInformation, IoWritePartitionTable


DRIVE_LAYOUT_INFORMATION_EX

The DRIVE_LAYOUT_INFORMATION_EX structure is used to report information about the driver layout.

typedef struct _DRIVE_LAYOUT_INFORMATION_EX {
  ULONG  PartitionStyle;
  ULONG  PartitionCount;
  union {
    DRIVE_LAYOUT_INFORMATION_MBR Mbr;
    DRIVE_LAYOUT_INFORMATION_GPT Gpt;
  };
  PARTITION_INFORMATION_EX  PartitionEntry[1];
} DRIVE_LAYOUT_INFORMATION_EX, *PDRIVE_LAYOUT_INFORMATION_EX;

Members

PartitionStyle
Takes a PARTITION_STYLE enumerated value that specifies the type of partition table the disk contains.
PartitionCount
Indicates the number of partitions detected on the disk.
Mbr
Drive layout information for a disk with a Master Boot Record. This member is valid when PartitionStyle is PARTITION_STYLE_MBR. See the definition of DRIVE_LAYOUT_INFORMATION_MBR for more information.
Gpt
Drive layout information for a disk with a GUID Partition Table. This member is valid when PartitionStyle is PARTITION_STYLE_GPT. See definition of DRIVE_LAYOUT_INFORMATION_GPT for more information.
PartitionEntry
Points to an array of PARTITION_INFORMATION_EX structures, one for each partition on the drive.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

This structure is used for both reading and writing disk partition information. It is used with IoReadPartitionTableEx and IoWritePartitionTableEx and replaces the obsolete structure DRIVE_LAYOUT_INFORMATION that was used with IoReadPartitionTable and IoWritePartitionTable. The principal difference is that the new structures and routines support both Master Boot Record (MBR) partitions and GUID Partition Table (GPT) partitions, whereas the older routines and structures are only used with MBR partitions.

See Also

IoReadPartitionTableEx, IoWritePartitionTableEx, DRIVE_LAYOUT_INFORMATION_MBR, DRIVE_LAYOUT_INFORMATION_GPT, PARTITION_STYLE


DRIVE_LAYOUT_INFORMATION_MBR

The DRIVE_LAYOUT_INFORMATION_MBR structure reports the drive signature for a Master Boot Record partition.

typedef struct _DRIVE_LAYOUT_INFORMATION_MBR {
    ULONG  Signature;
} DRIVE_LAYOUT_INFORMATION_MBR, *PDRIVE_LAYOUT_INFORMATION_MBR;

Members

Signature
Specifies the disk signature value, which uniquely identifies the disk.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

This structure contains the drive layout information that is specific to a drive with a Master Boot Record partition. It is contained within the DRIVE_LAYOUT_INFORMATION_EX structure.

See Also

DRIVE_LAYOUT_INFORMATION_EX, IoReadPartitionTable, IoWritePartitionTable


DRIVE_LAYOUT_INFORMATION_GPT

The DRIVE_LAYOUT_INFORMATION_GPT structure reports the drive signature for a GUID Partition Table partition.

typedef struct _DRIVE_LAYOUT_INFORMATION_GPT {
  GUID  DiskId;
  LARGE_INTEGER  StartingUsableOffset;
  LARGE_INTEGER  UsableLength;
  ULONG  MaxPartitionCount;
} DRIVE_LAYOUT_INFORMATION_GPT, *PDRIVE_LAYOUT_INFORMATION_GPT;

Members

DiskId
A GUID that uniquely identifies the drive.
StartingUsableOffset
An offset to the location immediately following the primary partition table. This offset begins the region on the drive where partitions reside, but partition one is not necessarily located precisely at this offset.
UsableLength
Total usable space available on the drive.
MaxPartitionCount
Maximum number of partitions allowed on the drive.

Headers

Declared in ntddk.h. Include ntddk.h.

Comments

This structure contains the drive layout information that is specific to a drive with a GUID Partition Table partition. It is encapsulated within the DRIVE_LAYOUT_INFORMATION_EX structure. For further information see Intel's Extensible Firmware Interface specification.

See Also

DRIVE_LAYOUT_INFORMATION_EX, IoReadPartitionTable, IoWritePartitionTable


FORMAT_EX_PARAMETERS

The FORMAT_EX_PARAMETERS structure is used in conjunction with the IOCTL_DISK_FORMAT_TRACKS_EX request to format the specified set of contiguous tracks on the disk.

typedef struct _FORMAT_EX_PARAMETERS {
  MEDIA_TYPE  MediaType;
  ULONG  StartCylinderNumber;
  ULONG  EndCylinderNumber;
  ULONG  StartHeadNumber;
  ULONG  EndHeadNumber;
  USHORT  FormatGapLength;
  USHORT  SectorsPerTrack;
  USHORT  SectorNumber[1];
} FORMAT_EX_PARAMETERS, *PFORMAT_EX_PARAMETERS;

Members

MediaType
Indicates format information, such as the disk size and the number of bytes per sector. For a list of the values that can be assigned to this member, see MEDIA_TYPE.
StartCylinderNumber
Number of the cylinder where the formatting should begin.
EndCylinderNumber
Number of the cylinder where the formatting should end.
StartHeadNumber
Number of the head where the formatting should begin.
EndHeadNumber
Number of the head where the formatting should end.
FormatGapLength
Length of a format gap.
SectorsPerTrack
Number of sectors per track.
SectorNumber
Number of sector where the formatting should begin.

Headers

Declared in ntdddisk.h. Include ntdddisk.h.

See Also

IOCTL_DISK_FORMAT_TRACKS_EX, IOCTL_DISK_FORMAT_TRACKS, FORMAT_PARAMETERS


FORMAT_PARAMETERS

The FORMAT_PARAMETERS structure is used in conjunction with the IOCTL_DISK_FORMAT_TRACKS request to format the specified set of contiguous tracks on the disk.

typedef struct _FORMAT_PARAMETERS {
  MEDIA_TYPE  MediaType;
  ULONG  StartCylinderNumber;
  ULONG  EndCylinderNumber;
  ULONG  StartHeadNumber;
  ULONG  EndHeadNumber;
} FORMAT_PARAMETERS, *PFORMAT_PARAMETERS;

Members

MediaType
Indicates format information, such as the disk size and the number of bytes per sector. For a list of the values that can be assigned to this member, see MEDIA_TYPE.
StartCylinderNumber
Number of the cylinder where the formatting should begin.
EndCylinderNumber
Number of the cylinder where the formatting should end.
StartHeadNumber
Number of the head where the formatting should begin.
EndHeadNumber
Number of the head where the formatting should end.

Headers

Declared in ntdddisk.h. Include ntdddisk.h.

See Also

IOCTL_DISK_FORMAT_TRACKS, MEDIA_TYPE


GET_CHANGER_PARAMETERS

Retrieves characteristics of changer.

typedef struct _GET_CHANGER_PARAMETERS {
  ULONG  Size;
  USHORT  NumberTransportElements;
  USHORT  NumberStorageElements;
  USHORT  NumberCleanerSlots;
  USHORT  NumberIEElements;
  USHORT  NumberDataTransferElements;
  USHORT  NumberOfDoors;
  USHORT  FirstSlotNumber;
  USHORT  FirstDriveNumber;
  USHORT  FirstTransportNumber;
  USHORT  FirstIEPortNumber;
  USHORT  FirstCleanerSlotAddress;
  USHORT  MagazineSize;
  ULONG  DriveCleanTimeout;
  ULONG  Features0;
  ULONG  Features1;
  UCHAR  MoveFromTransport;
  UCHAR  MoveFromSlot;
  UCHAR  MoveFromIePort;
  UCHAR  MoveFromDrive;
  UCHAR  ExchangeFromTransport;
  UCHAR  ExchangeFromSlot;
  UCHAR  ExchangeFromIePort;
  UCHAR  ExchangeFromDrive;
  UCHAR  LockUnlockCapabilities;
  UCHAR  PositionCapabilities;
  UCHAR  Reserved1[2];
  ULONG  Reserved2[2];
} GET_CHANGER_PARAMETERS, * PGET_CHANGER_PARAMETERS;

Members

Size
Specifies the size of this structure, in bytes, as returned by sizeof(). In effect, this member indicates the version of this structure being used by the miniclass driver.
NumberTransportElements
Indicates the number of transport elements in the changer. For a SCSI changer, this is defined in the element address page. This value is almost always 1, because most changers have a single transport element, which can have one or two picker mechanisms. A changer that has two picker mechanisms on its transport must not be represented as having two transports, because pickers cannot be addressed individually. High-end media libraries can have dual and multiple transport elements for fault tolerance.
NumberStorageElements
Indicates the number of storage elements (slots) in the changer. For a SCSI changer, this is defined in the element address page. This value represents the maximum number of slots available for this changer, including those in removable magazines, whether or not the magazines are installed. If NumberCleanerSlots is 1, then NumberStorageElements is 1 less than the maximum number of slots in the changer.
NumberCleanerSlots
Indicates the number of storage elements (slots) for cleaner cartridges in the changer. For a SCSI changer, this value is not reported in mode sense data, so the miniclass driver must provide it. The miniclass driver should set NumberCleanerSlots to 1 only if the operator's guide for the changer identifies a specific slot as a cleaner slot. If NumberCleanerSlots is 1, then FirstCleanerSlotAddress indicates the zero-based address of the slot in which a drive cleaner should be inserted. If the changer does not support drive cleaning by programmatically moving the cleaner cartridge from its slot to a drive, the miniclass driver must set NumberCleanerSlots to 0. NumberCleanerSlots must not be greater than 1.
NumberIEElements
Indicates the number of IEport elements the changer has for inserting and ejecting of media. For a SCSI changer, this is defined in the element address page. An IEport element must not be part of the storage element (slot) space, and it must be possible to transport media between the IEport and a slot using a MOVE MEDIUM SCSI command. If the changer has a door and not a true IEport, the miniclass driver must set NumberIEElements to 0.
NumberDataTransferElements
Indicates the number of data transfer elements (drives) in the changer. For a SCSI changer, this is defined in the element address page. Unlike NumberStorageElements, which indicates the total number of possible slots whether or not the slots are actually present, NumberDataTransferElements indicates the number of drives that are actually present in the changer.
NumberOfDoors
Indicates the number of doors the changer has. For a SCSI changer, this value is not reported in mode sense data, so the miniclass driver must provide it. A door provides access to all media in the changer at once, unlike an IEport which provides access to one or more, but not all, media. A changer's door can be a physical front door or a single magazine that contains all media. If a changer supports only an IEport for inserting and ejecting media, the NumberOfDoors must be 0.
FirstSlotNumber
Indicates the number used by the changer vendor to identify the first storage element (slot) in the changer to the end user, either by marking a magazine or by defining a slot numbering scheme in the changer's operators guide. FirstSlotNumber is typically 0 or 1, but it can be the first address in a consecutive range of slot addresses defined by the vendor.
FirstDriveNumber
Indicates the number used by the changer vendor to identify the first data transfer element (drive) in the changer to the end user. FirstDriveNumber is typically 0 or 1, but it can be the first address in a consecutive range of drive addresses defined by the vendor.
FirstTransportNumber
Indicates the number used by the changer vendor to identify the first (and usually only) transport element in the changer to the end user. FirstTransportNumber is typically 0 or 1, but it can be the first address in a consecutive range of transport addresses defined by the vendor.
FirstIEPortNumber
Indicates the number used by the changer vendor to identify the first (and usually only) IEport in the changer to the end user. FirstIEPortNumber is typically 0 or 1, but it can be the first address in a consecutive range of IEport addresses defined by the vendor. If NumberIEElements is 0, FirstIEPortNumber must also be 0.
FirstCleanerSlotAddress
Indicates the number used by the changer vendor to identify the first (and only) slot address assigned to a drive cleaner cartridge to the end user. This must be the value defined by the vendor in the changer's operators guide. For example, if a changer has 8 slots numbered 1 through 8 and its operator's guide designates slot 8 as the drive cleaner slot, FirstSlotNumber would be 1 and FirstCleanerSlotAddress would be 8. If the same 8 slots were numbered 0 through 7, FirstSlotNumber would be 0 and FirstCleanerSlotAddress would be 7. If NumberCleanerSlots is 0, FirstCleanerSlotAddress must be 0.
MagazineSize
Indicates the number of slots in the removable magazines in the changer. This member is valid only if CHANGER_CARTRIDGE_MAGAZINE is set in Features0.
DriveCleanTimeout
Indicates twice the maximum number of seconds a cleaning is expected to take. The changer's drives should be cleaned by its cleaner cartridge in half the time specified by DriveCleanTimeout. For example, if a drive is typically cleaned in 300 seconds (5 minutes), DriveCleanTimeout should be set to 600.
Features0
Indicates the features supported by the changer. This member can have one or more of the following values:
Value Meaning
CHANGER_BAR_CODE_SCANNER_INSTALLED
The changer supports a bar-code reader and the reader is installed. A miniclass driver must not hardcode this flag unless the changer's bar-code reader is always installed. If the bar-code reader is optional, the miniclass driver must determine whether the reader is actually installed and set the flag accordingly.
CHANGER_INIT_ELEM_STAT_WITH_RANGE
The changer can initialize elements within a specified range. For a SCSI changer, this flag indicates whether the changer supports the INITIALIZE ELEMENT STATUS WITH RANGE SCSI command.
CHANGER_CLOSE_IEPORT
The changer has an Ieport and can retract the IEport programmatically
CHANGER_OPEN_IEPORT
The changer has an Ieport and can extend the IEport programmatically.
CHANGER_STATUS_NON_VOLATILE
The changer uses nonvolatile memory for element status information.
CHANGER_EXCHANGE_MEDIA
Supports EXCHANGE MEDIUM SCSI command either by handling two volumes at a time or by using other changer elements to emulate this capability.
CHANGER_CLEANER_SLOT
Indicates that the changer has a specific slot designated for a cleaner cartridge. If this flag is set, NumberCleanerSlots must be one and FirstCleanerSlotAddress must specify the address of the cleaner slot. This bit can only be set if CHANGER_DRIVE_CLEANING_REQUIRED is set and CHANGER_CLEANER_OPS_NOT_SUPPORTED is reset.
CHANGER_LOCK_UNLOCK
The changer's door, Ieport, or keypad can be locked or unlocked programmatically. If this flag is set, LockUnlockCapabilities indicates which elements can be locked or unlocked.
CHANGER_CARTRIDGE_MAGAZINE
The changer uses removable cartridge magazines for some or all storage slots.
CHANGER_MEDIUM_FLIP
The changer's transport element supports flipping (rotating) media. For a SCSI changer, this flag reflects the rotate bit in the transport geometry parameters page.
CHANGER_POSITION_TO_ELEMENT
The changer can position the transport to a particular destination. For a SCSI changer, this flag indicates whether the changer supports the POSITION TO ELEMENT SCSI command. If this flag is set, PositionCapabilities indicates the elements to which the transport can be positioned.
CHANGER_REPORT_IEPORT_STATE
The changer can report whether media is present in the IEport. Such a changer must have a sensor in the IEport to detect the presence or absence of media.
CHANGER_STORAGE_DRIVE
The changer can use a drive as an independent storage element; that is, it can store media in the drive without reading it. For a SCSI changer, this flag reflects the state of the DT bit in the device capabilities page.
CHANGER_STORAGE_IEPORT
The changer can use an IEport as an independent storage element. For a SCSI changer, this flag reflects the state of the I/E bit in the device capabilities page.
CHANGER_STORAGE_TRANSPORT
The changer can use a transport as an independent storage element. For a SCSI changer, this flag reflects the state of the MT bit in the device capabilities page.
CHANGER_DRIVE_CLEANING_REQUIRED
Indicates that the changer's drives might periodically report sense codes that indicate that the drive requires cleaning.
CHANGER_PREDISMOUNT_EJECT_REQUIRED
The changer requires an explicit command issued through a mass-storage driver (tape, disk, or CDROM, for example) to eject media from a drive before the changer can move the media from a drive to a slot. If the changer ejects media automatically, the miniclass driver should clear this flag.
CHANGER_CLEANER_ACCESS_NOT_VALID
The ELEMENT_STATUS_ACCESS flag in a CHANGER_ELEMENT_STATUS structure for a data transport element is invalid when the transport element contains a cleaning cartridge.
CHANGER_DRIVE_EMPTY_ON_DOOR_ACCESS
The changer requires all drives to be empty (dismounted) before they can be accessed through its door. The miniclass driver should set this flag if the changer has static-sensitive drives that could be affected by an operator gaining access to the inside of the changer, or if the changer automatically ejects media from its drives when the operator attempts to physically open the door.
CHANGER_VOLUME_IDENTIFICATION
The changer supports volume identification. For a SCSI changer, this flag indicates whether the changer supports the SEND VOLUME TAG and REQUEST VOLUME ELEMENT ADDRESS SCSI commands.
CHANGER_VOLUME_SEARCH
The changer can search for volume information. For a SCSI changer, this flag indicates whether the changer supports the supports the SEND VOLUME TAG SCSI SCSI command with a send action code of TRANSLATE.
CHANGER_VOLUME_ASSERT
The changer can verify volume information. For a SCSI changer, this flag indicates whether the changer supports the SEND VOLUME TAG SCSI command with a send action code of ASSERT.
CHANGER_VOLUME_REPLACE
The changer can replace volume information. For a SCSI changer, this flag indicates whether the changer supports the SEND VOLUME TAG SCSI command with a send action code of REPLACE.
CHANGER_VOLUME_UNDEFINE
The changer can clear existing volume information. For a SCSI changer, this flag indicates whether the changer supports the supports the SEND VOLUME TAG SCSI command with a send action code of UNDEFINE.
CHANGER_SERIAL_NUMBER_VALID
The serial number reported by GetProductData is valid and unique for all changers of this type. Serial numbers are not guaranteed to be unique across vendor and product lines. If the changer's serial number is unique according to this definition, the miniclass driver should set this flag and set SerialNumber in CHANGER_PRODUCT_DATA to the serial number.
CHANGER_PREMOUNT_EJECT_REQUIRED
The changer requires an explicit command issued through a mass storage driver to eject a drive mechanism before the changer can move media from a slot to the drive. For example, a changer with CD-ROM drives might require the tray to be presented to the robotic transport so a piece of media could be loaded onto the tray during a mount operation. If the changer ejects the mechanism automatically, the miniclass driver should clear this flag.
CHANGER_DEVICE_REINITIALIZE_CAPABLE
The changer can recalibrate its transport element in response to an explicit command. The changer class driver calls ChangerReinitializeUnit to initiate recalibration.
CHANGER_KEYPAD_ENABLE_DISABLE
The changer keypad can be enabled and disabled programmatically.
CHANGER_RESERVED_BIT
Reserved to indicate Features1 flags.

Features1
Indicates additional features supported by the changer. This member can have one or more of the following values:
Value Meaning
CHANGER_PREDISMOUNT_ALIGN_TO_SLOT
Indicates that the transport must be moved to the destination slot before moving the media from a drive to the slot. The bit CHANGER_PREDISMOUNT_ALIGN_TO_DRIVE must be reset if this is set.
CHANGER_PREDISMOUNT_ALIGN_TO_DRIVE
Indicates that the transport must be moved to the drive before moving media from the drive to a slot. The bit CHANGER_PREDISMOUNT_ALIGN_TO_SLOT must be reset if this is set.
CHANGER_CLEANER_AUTODISMOUNT
Indicates that the changer will move the cleaning cartridge back to its original slot automatically, after cleaning is finished. This bit can only be set if CHANGER_DRIVE_CLEANING_REQUIRED is set and CHANGER_CLEANER_OPS_NOT_SUPPORTED is reset.
CHANGER_TRUE_EXCHANGE_CAPABLE
Device can manipulate two volumes at a time without using additional changer elements.
CHANGER_SLOTS_USE_TRAYS
The changer uses removable trays in its slots, which require the media to be placed in a tray and the tray moved to the desired position.
CHANGER_RTN_MEDIA_TO_ORIGINAL_ADDR
Indicates that when moving volume from drive to slot, volume must go back into the same slot from which it was previously moved to the drive.
CHANGER_CLEANER_OPS_NOT_SUPPORTED
Indicates that the changer's transport cannot be programmatically commanded by software above the changer driver to move a cleaning cartridge to a dirty drive . This bit can be set only if the CHANGER_DRIVE_CLEANING_REQUIRED bit is set. If this bit is set then both CHANGER_CLEANER_AUTODISMOUNT and CHANGER_CLEANER_SLOT must be reset.
CHANGER_IEPORT_USER_CONTROL_OPEN
The changer requires the user to manually open a closed IEport.
CHANGER_IEPORT_USER_CONTROL_CLOSE
The changer requires the user to manually close an open IEport.
CHANGER_MOVE_EXTENDS_IEPORT
The changer will extend the tray automatically whenever a command is issued to move media to an IEport.
CHANGER_MOVE_RETRACTS_IEPORT
The changer will retract the tray automatically whenever a command is issued to move media from an IEport.

MoveFromTransport
Indicates whether the changer supports moving a piece of media from a transport element to another transport element, a storage slot, an IEport, or a drive. For a SCSI changer, this is defined in the device capabilities page. The transport is not typically the source or destination for moving or exchanging media.

Callers can use the following masks to determine whether the changer can move media to a given element:
Value Meaning
CHANGER_TO_TRANSPORT
The changer can carry out the operation from the specified element to a transport.
CHANGER_TO_SLOT
The changer can carry out the operation from the specified element to a storage slot.
CHANGER_TO_IEPORT
The changer can carry out the operation from the specified element to an IEport.
CHANGER_TO_DRIVE
The changer can carry out the operation from the specified element to a drive.

MoveFromSlot
Indicates whether the changer supports moving medium from a storage slot to a transport element, another storage slot, an IEport, or a drive. Callers can use the masks described under MoveFromTransport to determine whether the changer supports the move.
MoveFromIePort
Indicates whether the changer supports moving medium from an IEport to a transport element, a storage slot, another IEport, or a drive. For a SCSI changer, this is defined in the device capabilities page. Callers can use the masks described under MoveFromTransport to determine whether the changer supports the move
MoveFromDrive
Indicates whether the changer supports moving medium from a drive to a transport element, a storage slot, an IEport, or another drive. Callers can use the masks described under MoveFromTransport to determine whether the changer supports the move.
ExchangeFromTransport
Indicates whether the changer supports exchanging medium between a transport element and another transport element, a storage slot, an IEport, or a drive. Callers can use the masks described under MoveFromTransport to determine whether the changer supports the exchange.
ExchangeFromSlot
Indicates whether the changer supports exchanging medium between a storage slot and a transport element, another storage slot, an IEport, or a drive. Callers can use the masks described under MoveFromTransport to determine whether the changer supports the exchange.
ExchangeFromIePort
Indicates whether the changer supports exchanging medium between an IEport and a transport element, a storage slot, another IEport, or a drive. Callers can use the masks described under MoveFromTransport to determine whether the changer supports the exchange.
ExchangeFromDrive
Indicates whether the changer supports exchanging medium between a drive and a transport element, a storage slot, an IEport, or another drive. Callers can use the masks described under MoveFromTransport to determine whether the changer supports the exchange.
LockUnlockCapabilities
Indicates which elements of a changer can be locked or unlocked programmatically. This member is valid only if CHANGER_LOCK_UNLOCK is set in Features0.

Callers can use the following masks to determine whether the changer can lock or unlock a particular element:

LOCK_UNLOCK_IEPORT
The changer can lock or unlock its IEport(s).
LOCK_UNLOCK_DOOR
The changer can lock or unlock its door.
LOCK_UNLOCK_KEYPAD
The changer can lock or unlock its keypad.
PositionCapabilities
Indicates the elements to which a changer can position its transport. Callers can use the masks described under MoveFromTransport to determine whether the changer supports positioning the transport to a particular element. This member is valid only if CHANGER_POSITION_TO_ELEMENT is set in Features0.
Reserved1
Reserved for future use.
Reserved2
Reserved for future use.

Headers

Declared in ntddchgr.h. Include ntddchgr.h.

Comments

GET_CHANGER_PARAMETERS contains the parameters of a changer. The changer miniclass driver allocates and fills in this structure when requested by the changer class driver.

See Also

ChangerGetParameters


GET_LENGTH_INFORMATION

The GET_LENGTH_INFORMATION structure is used with the IOCTL_DISK_GET_LENGTH_INFO to obtain the length, in bytes, of a disk, partition, or volume.

typedef struct _GET_LENGTH_INFORMATION {
  LARGE_INTEGER  Length;
} GET_LENGTH_INFORMATION, *PGET_LENGTH_INFORMATION;

Members

Length
Length, in bytes, of a disk, partition, or volume.

Headers

Declared in ntdddisk.h. Include ntdddisk.h.

See Also

IOCTL_DISK_GET_LENGTH_INFO


GET_MEDIA_TYPES

The GET_MEDIA_TYPES structure is used in conjunction with the IOCTL_STORAGE_GET_MEDIA_TYPES_EX request to retrieve information about the types of media supported by a device.

typedef struct _GET_MEDIA_TYPES {
  ULONG  DeviceType;
  ULONG  MediaInfoCount;
  DEVICE_MEDIA_INFO  MediaInfo[1];
} GET_MEDIA_TYPES, *PGET_MEDIA_TYPES;

Members

DeviceType
Specifies one of the system-defined FILE_DEVICE_XXX constants indicating the type of device (such as FILE_DEVICE_DISK, FILE_DEVICE_KEYBOARD, and so forth) or a vendor-defined value for a new type of device. For more information, see Specifying Device Types.
MediaInfoCount
The number of DEVICE_MEDIA_INFO structures in the array starting at MediaInfo.
MediaInfo
The address of the first DEVICE_MEDIA_INFO structure in the array.

Headers

Declared in ntddstor.h. Include ntddstor.h.

Comments

A storage class driver must handle the IOCTL_STORAGE_GET_MEDIA_TYPES_EX request to support any device that the Removable Storage Manager (RSM) accesses, whether the device is a stand-alone device or a data transfer element (drive) in a media library or changer.

See Also

IOCTL_STORAGE_GET_MEDIA_TYPES_EX, DEVICE_MEDIA_INFO


HW_INITIALIZATION_DATA (SCSI)

Each SCSI miniport's DriverEntry routine must initialize with zeros and, then, fill in the relevant HW_INITIALIZATION_DATA information for the OS-specific port driver.

typedef struct HW_INITIALIZATION_DATA {
  ULONG  HwInitializationDataSize;
  INTERFACE_TYPE  AdapterInterfaceType;
  PHW_INITIALIZE  HwInitialize;
  PHW_STARTIO  HwStartIo;
  PHW_INTERRUPT  HwInterrupt;
  PHW_FIND_ADAPTER  HwFindAdapter;
  PHW_RESET_BUS_BUS  HwResetBus;
  PHW_DMA_STARTED  HwDmaStarted;
  PHW_ADAPTER_STATE  HwAdapterState;
  ULONG  DeviceExtensionSize;
  ULONG  SpecificLuExtensionSize;
  ULONG  SrbExtensionSize;
  ULONG  NumberOfAccessRanges;
  PVOID  Reserved;
  BOOLEAN  MapBuffers;
  BOOLEAN  NeedPhysicalAddresses;
  BOOLEAN  TaggedQueueing;
  BOOLEAN  AutoRequestSense;
  BOOLEAN  MultipleRequestPerLu;
  BOOLEAN  ReceiveEvent;
  USHORT  VendorIdLength;
  PVOID  VendorId;
  USHORT  ReservedUshort;
  USHORT  DeviceIdLength;
  PVOID  DeviceId;
  PHW_STOP_ADAPTER  HwAdapterControl;
} HW_INITIALIZATION_DATA, *PHW_INITIALIZATION_DATA;

Members

HwInitializationDataSize
Specifies the size of this structure in bytes, as returned by sizeof(). In effect, this member indicates the version of this structure being used by the miniport driver. A miniport's DriverEntry routine should set this member's value for the port driver.
AdapterInterfaceType
Specifies the type of I/O bus to which the HBA is connected, which can be one of the following: Internal, Isa, Eisa, MicroChannel, TurboChannel, or PCIBus. However, additional types of buses will be supported in future. The upper bound on the types of buses supported is always MaximumInterfaceType.

If this is set to PCIBus, the miniport driver must supply values for the VendorIdLength, VendorId, DeviceIdLength, and DeviceId members, described later.

HwInitialize
Points to the miniport's HwScsiInitialize routine, which is a required entry point for all miniport drivers.
HwStartIo
Points to the miniport's HwScsiStartIo routine, which is a required entry point for all miniport drivers.
HwInterrupt
Points to the miniport's HwScsiInterrupt routine, which is a required entry point for any miniport driver of an HBA that generates interrupts. Set this to NULL if the miniport needs no ISR.
HwFindAdapter
Points to the miniport's HwScsiFindAdapter routine, which is a required entry point for all miniport drivers.
HwResetBus
Points to the miniport's HwScsiResetBus routine, which is a required entry point for all miniport drivers.
HwDmaStarted
Points to the miniport's HwScsiDmaStarted routine if its HBA uses system DMA, that is, a system DMA controller. Set this to NULL if the HBA is a busmaster or uses PIO.
HwAdapterState
Points to the miniport's HwScsiAdapterState routine, which is a required entry point for miniport drivers of HBAs with BIOSes that are linked with an OS-dependent, x86-platform-only port driver that must switch between x86 protected and real processor modes. If the miniport needs no HwScsiAdapterState routine, set this member to NULL. A miniport for an HBA that has a BIOS must have a HwScsiAdapterState routine in order to be compatible with the x86-only port driver and portable to an x86-only OS environment.
DeviceExtensionSize
Specifies the size in bytes required by the miniport driver for its per-HBA device extension. A miniport uses its device extension as storage for driver-determined HBA information. The OS-specific port driver initializes each device extension it allocates with zeros, and passes a pointer to the HBA-specific device extension in every call to a miniport driver except to its DriverEntry routine. The given size does not include any miniport-requested per-logical-unit storage, described next.
SpecificLuExtensionSize
Specifies the size in bytes required by the miniport driver for its per-logical-unit storage, if any. A miniport can use its LU extensions as storage for driver-determined logical-unit information about SCSI peripherals on the bus. The OS-specific port driver initializes each LU extension it allocates with zeros. Leave this member set to zero if the miniport does not maintain per-LU information for which it requires storage. This value is based on the assumption that the HBA is able to receive 32-bit addresses, regardless of what the controller can actually support. If additional space is needed in the LUN or SRB extensions to handle 64-bit addresses, then appropriate adjustments must be made to this value before using it with routines such as ScsiPortGetUncachedExtension.
SrbExtensionSize
Specifies the size in bytes required by the miniport driver for its per-request storage, if any. A miniport can use SRB extensions as storage for driver-determined, request-specific information, such as data necessary to process a particular request. The OS-specific port driver does not initialize SRB extensions, but sets a pointer to this storage in each SRB it sends to the miniport driver. An SRB extension can be safely accessed by the HBA hardware. Leave this member set to zero if the miniport driver does not maintain per-SRB information for which it requires storage. This value is based on the assumption that the HBA is able to receive 32-bit addresses, regardless of what the controller can actually support. If additional space is needed in the LUN or SRB extensions to handle 64-bit addresses, then appropriate adjustments must be made to this value before using it with routines such as ScsiPortGetUncachedExtension.
NumberOfAccessRanges
Specifies how many access ranges the adapter uses. Each is a range either of memory addresses or I/O port addresses. A typical HBA uses two ranges, one for its I/O ports and another for its device memory range.
Reserved
This member is reserved for system use and not available for use by miniport drivers.
MapBuffers
TRUE indicates that all data buffer addresses must be mapped to virtual addresses for access by the miniport driver.
NeedPhysicalAddresses
TRUE indicates that the miniport driver needs to translate its device, any per-LU, and any per-SRB extension addresses, as well as SRB buffer addresses, to physical addresses, as required by the HBA.
TaggedQueueing
TRUE indicates that miniport driver can support SCSI-2 tagged queuing.
AutoRequestSense
TRUE indicates that the HBA can perform a request-sense operation without requiring an explicit request to do so. Only miniports driving HBAs with built-in firmware to perform request-sense operations should set this member to TRUE.
MultipleRequestPerLu
TRUE indicates that the miniport driver can queue multiple requests per logical unit, in particular, within the HBA. Note that an HBA must support auto request sense for its miniport to enable this functionality. If a miniport driver sets this member to TRUE, it must use each SRB QueueTag member for requests of this type, but the SRB_FLAGS_QUEUE_ACTION_ENABLE is not set in the SrbFlags member of the SCSI_REQUEST_BLOCK structure.
ReceiveEvent
TRUE indicates the miniport drives an HBA that can support the receive-event SRB for SCSI-2 asynchronous events.
VendorIdLength
Specifies the size in bytes of the VendorId string, described next.
VendorId
Points to an ASCII byte string identifying the manufacturer of the HBA. This member is irrelevant for Plug and Play drivers.

If the given AdapterInterfaceType is PCIBus, the vendor ID is a USHORT value allocated by the PCI SIG, which must be converted into a byte string by the miniport driver. For example, if the assigned PCI vendor ID value is 1001, the miniport-supplied VendorId string would be ('1', '0', '0', '1').

ReservedUshort
This member is reserved for system use and is not available for use by miniport drivers.
DeviceIdLength
Specifies the size in bytes of the DeviceId string, described next.
DeviceId
Points to an ASCII byte string identifying the HBA model(s) supported by the miniport driver. This member is irrelevant for Plug and Play drivers.

If the given AdapterInterfaceType is PCIBus, a device ID is a USHORT value assigned by the manufacturer of the HBA. The miniport must convert any PCI device ID value(s) for the HBA(s) it can support into DeviceId byte string(s), as for the VendorId member. For example, if a miniport can support HBAs with the PCI device IDs 8040 and 8050, it might set DeviceId with a pointer to the byte string ('8', '0').

HwAdapterControl
Points to the miniport's HwScsiAdapterControl routine, which is a required entry point for all PnP miniport drivers. Set this to NULL if the miniport does not support Plug and Play.

Headers

Declared in srb.h. Include srb.h.

Comments

Each miniport driver must initialize the HW_INITIALIZATION_DATA structure with zeros before it sets the values of relevant members in this structure and calls ScsiPortInitialize.

The Dma64BitAddresses member of HW_INITIALIZATION_DATA has been eliminated in Windows® 2000 (See the discussion under PORT_CONFIGURATION_DATA for further details).

Both HW_INITIALIZATION_DATA and PORT_CONFIGURATION_INFORMATION have a pair of members called SpecificLuExtensionSize and SrbExtensionSize whose values are handled differently than they were prior to Windows 2000. The miniport must calculate the initial values of SpecificLuExtensionSize and SrbExtensionSize in HW_INITIALIZATION_DATA based on the assumption that the HBA is capable of handling 32-bit addresses, regardless of what the controller can actually support (See the discussion under PORT_CONFIGURATION_DATA for further details).

See Also

DriverEntry, HwScsiInitialize, SCSI_REQUEST_BLOCK, ScsiPortInitialize


IDE_CONTROLLER_PROPERTIES

IDE_CONTROLLER_PROPERTIES contains configuration information for an IDE controller.

typedef struct _IDE_CONTROLLER_PROPERTIES {
  ULONG  Size;
  ULONG  ExtensionSize;
  ULONG  SupportedTransferMode[MAX_IDE_CHANNEL][MAX_IDE_DEVICE];
  PCIIDE_CHANNEL_ENABLED  PciIdeChannelEnabled;
  PCIIDE_SYNC_ACCESS_REQUIRED  PciIdeSyncAccessRequired;
  PCIIDE_TRANSFER_MODE_SELECT_FUNC  PciIdeTransferModeSelect;
  BOOLEAN  IgnoreActiveBitForAtaDevice;
  BOOLEAN  AlwaysClearBusMasterInterrupt;
  PCIIDE_USEDMA_FUNC  PciIdeUseDma;
  ULONG AlignmentRequirement;
  ULONG DefaultPIO;
  PCIIDE_UDMA_MODES_SUPPORTED PciIdeUdmaModesSupported;
} IDE_CONTROLLER_PROPERTIES, *PIDE_CONTROLLER_PROPERTIES;

Members

Size
Specifies the size of this structure in bytes, as returned by sizeof(). In effect, this member indicates the version of this structure used by the port driver.
ExtensionSize
Specifies the amount of memory needed by the PCI IDE controller minidriver for its private data.
SupportedTransferMode
Furnishes an array of bitmaps indicating the data transfer modes supported by the PCI IDE controller. See PCIIDE_TRANSFER_MODE_SELECT for a detailed definition of these bitmaps.
PciIdeChannelEnabled
Points to a callback routine used to query whether an IDE channel is enabled.
PciIdeSyncAccessRequired
Points to a callback routine used to query whether the controller's two IDE channels can be used simultaneously or must be used one at a time.
PciIdeTransferModeSelect
Points to a callback routine used to select the proper transfer modes for the given devices.
IgnoreActiveBitForAtaDevice
Indicates whether the controller's busmaster-active bit should be ignored. Setting this flag equal to TRUE indicates that the IDE controller does not properly clear its busmaster-active bit upon the completion of a busmaster interrupt. Under normal circumstances, this bit is set equal to FALSE.
AlwaysClearBusMasterInterrupt
Indicates that the PCI IDE controller minidriver must clear the busmaster interrupt on every interrupt generated by the device. Under normal circumstances, this bit is set equal to FALSE.
PciIdeUseDma
Points to a callback routine that determines whether DMA should be used or not. This routine should be called before every I/O operation.
AlignmentRequirement
Specifies an alignment requirement value to be stored in the device object. See Initializing a Device Object for further information on defining a device object's alignment requirement.
DefaultPIO
When set to one by the controller minidriver, this member indicates to the operating system that devices connected to the minidriver's controller are restricted by default to PIO. However, users can request by means of the device manager that DMA be performed on individual devices.
PciIdeUdmaModesSupported
Points to a callback routine that is optionally implemented by the controller minidriver. This routine checks a device's identify data and determines the current ultra DMA transfer mode for that device. This allows the IDE port driver, atapi.sys, to query the controller minidriver for newly supported transfer modes without having to interpret a device's identify data.

Headers

Declared in ide.h. Include ide.h.

Comments

This structure is returned by the IDE controller minidriver's HwIdeXGetControllerProperties callback routine. Some of the information in this structure is obtained directly from the device extension; all information not obtained from the device extension is obtained from PCI configuration space by means of a call to the controller minidriver callback routine, HwIdeXGetBusData.

See Also

HwIdeXGetControllerProperties, PCIIDE_TRANSFER_MODE_SELECT, HwIdeXTransferModeSelect


MCD_INIT_DATA

The changer miniclass driver fills the MCD_INIT_DATA structure with pointers to its internal command processing routines and passes them to the changer class driver.

typedef struct _MCD_INIT_DATA {
  ULONG  InitDataSize;
  CHANGER_EXTENSION_SIZE  ChangerAdditionalExtensionSize;
  CHANGER_INITIALIZE  ChangerInitialize;
  CHANGER_ERROR_ROUTINE  ChangerError;
  CHANGER_PERFORM_DIAGNOSTICS  ChangerPerformDiagnostics;
  CHANGER_COMMAND_ROUTINE  ChangerGetParameters;
  CHANGER_COMMAND_ROUTINE  ChangerGetStatus;
  CHANGER_COMMAND_ROUTINE  ChangerGetProductData;
  CHANGER_COMMAND_ROUTINE  ChangerSetAccess;
  CHANGER_COMMAND_ROUTINE  ChangerGetElementStatus;
  CHANGER_COMMAND_ROUTINE  ChangerInitializeElementStatus;
  CHANGER_COMMAND_ROUTINE  ChangerSetPosition;
  CHANGER_COMMAND_ROUTINE  ChangerExchangeMedium;
  CHANGER_COMMAND_ROUTINE  ChangerMoveMedium;
  CHANGER_COMMAND_ROUTINE  ChangerReinitializeUnit;
  CHANGER_COMMAND_ROUTINE  ChangerQueryVolumeTags;
} MCD_INIT_DATA, *PMCD_INIT_DATA;

Members

InitDataSize
Size of this structure in bytes.
ChangerAdditionalExtensionSize
Pointer to changer miniclass driver routine that returns the number of bytes the changer miniclass driver requires to store device-specific information in the device extension.
ChangerInitialize
Pointer to changer miniclass driver routine that does miniclass driver-specific initialization and readies the changer to receive other requests.
ChangerError
Pointer to changer miniclass driver routine that does device-specific error processing.
ChangerPerformDiagnostics
Pointer to changer miniclass driver routine that performs diagnostic tests on the device.
ChangerGetParameters
Pointer to changer miniclass driver routine that handles the device-specific aspects of a device-control IRP with the IOCTL code IOCTL_CHANGER_GET_PARAMETERS.
ChangerGetStatus
Pointer to changer miniclass driver routine that handles the device-specific aspects of a device-control IRP with the IOCTL code IOCTL_CHANGER_GET_STATUS.
ChangerGetProductData
Pointer to a changer miniclass driver routine that handles the device-specific aspects of a device-control IRP with the IOCTL code IOCTL_CHANGER_GET_PRODUCT_DATA.
ChangerSetAccess
Pointer to a changer miniclass driver routine that handles the device-specific aspects of a device-control IRP with the IOCTL code IOCTL_CHANGER_SET_ACCESS.
ChangerGetElementStatus
Pointer to a changer miniclass driver routine that handles the device-specific aspects of a device-control IRP with the IOCTL code IOCTL_CHANGER_GET_ELEMENT_STATUS.
ChangerInitializeElementStatus
Pointer to a changer miniclass driver routine that handles the device-specific aspects of a device-control IRP with the IOCTL code IOCTL_CHANGER_INITIALIZE_ELEMENT_STATUS.
ChangerSetPosition
Pointer to a changer miniclass driver routine that handles the device-specific aspects of a device-control IRP with the IOCTL code IOCTL_CHANGER_SET_POSITION.
ChangerExchangeMedium
Pointer to a changer miniclass driver routine that handles the device-specific aspects of a device-control IRP with the IOCTL code IOCTL_CHANGER_EXCHANGE_MEDIUM.
ChangerMoveMedium
Pointer to a changer miniclass driver routine that handles the device-specific aspects of a device-control IRP with the IOCTL code IOCTL_CHANGER_MOVE_MEDIUM.
ChangerReinitializeUnit
Pointer to a changer miniclass driver routine that handles the device-specific aspects of a device-control IRP with the IOCTL code IOCTL_CHANGER_REINITIALIZE_TRANSPORT.
ChangerQueryVolumeTags
Pointer to a changer miniclass driver routine that handles the device-specific aspects of a device-control IRP with the IOCTL code of IOCTL_CHANGER_QUERY_VOLUME_TAGS.

Headers

Declared in mcd.h. Include mcd.h.

Comments

This structure is used by the changer driver in Windows XP and later operating systems only.

See Also

ChangerAdditionalExtensionSize, ChangerInitialize, ChangerError, ChangerPerformDiagnostics, ChangerGetParameters, ChangerGetStatus, ChangerGetProductData, ChangerSetAccess, ChangerGetElementStatus, ChangerInitializeElementStatus, ChangerSetPosition, ChangerExchangeMedium, ChangerMoveMedium, ChangerReinitializeUnit, ChangerQueryVolumeTags, IOCTL_CHANGER_GET_PARAMETERS, IOCTL_CHANGER_GET_STATUS, IOCTL_CHANGER_GET_PRODUCT_DATA, IOCTL_CHANGER_SET_ACCESS, IOCTL_CHANGER_GET_ELEMENT_STATUS, IOCTL_CHANGER_INITIALIZE_ELEMENT_STATUS, IOCTL_CHANGER_SET_POSITION, IOCTL_CHANGER_EXCHANGE_MEDIUM, IOCTL_CHANGER_MOVE_MEDIUM


MEDIA_TYPE

The MEDIA_TYPE enumerators are used in conjunction with the IOCTL_DISK_FORMAT_TRACKS request to format the specified set of contiguous tracks on the disk.

typedef enum _MEDIA_TYPE {
  Unknown,
  F5_1Pt2_512,
  F3_1Pt44_512,
  F3_2Pt88_512,
  F3_20Pt8_512,
  F3_720_512,
  F5_360_512,
  F5_320_512,
  F5_320_1024,
  F5_180_512,
  F5_160_512,
  RemovableMedia,
  FixedMedia,
  F3_120M_512,
  F3_640_512,
  F5_640_512,
  F5_720_512,
  F3_1Pt2_512,
  F3_1Pt23_1024,
  F5_1Pt23_1024,
  F3_128Mb_512,
  F3_230Mb_512,
  F8_256_128
} MEDIA_TYPE, *PMEDIA_TYPE;

Enumerators

Unknown
Format is unknown.
F5_1Pt2_512
5.25", 1.2 Megabyte, 512 bytes/sector.
F3_1Pt44_512
3.5", 1.44 Megabyte, 512 bytes/sector.
F3_2Pt88_512
3.5", 2.88 Megabyte, 512 bytes/sector.
F3_20Pt8_512
3.5", 20.8 Megabyte, 512 bytes/sector.
F3_720_512
3.5", 720 Kilobyte, 512 bytes/sector.
F5_360_512
5.25", 360 Kilobyte, 512 bytes/sector.
F5_320_512
5.25", 320 Kilobyte, 512 bytes/sector.
F5_320_1024
5.25", 320 Kilobyte, 1024 bytes/sector.
F5_180_512
5.25", 180 Kilobyte, 512 bytes/sector.
F5_160_512
5.25", 160 Kilobyte, 512 bytes/sector.
RemovableMedia
Removable media other than a floppy disk.
FixedMedia
Fixed hard disk media.
F3_120M_512
3.5", 120 Megabyte.
F3_640_512
3.5" , 640 Kilobyte, 512 bytes/sector.
F5_640_512
5.25", 640 Kilobyte, 512 bytes/sector.
F5_720_512
5.25", 720 Kilobyte, 512 bytes/sector.
F3_1Pt2_512
3.5" , 1.2 Megabyte, 512 bytes/sector.
F3_1Pt23_1024
3.5" , 1.23 Megabyte, 1024 bytes/sector.
F5_1Pt23_1024
5.25", 1.23 Megabyte, 1024 bytes/sector.
F3_128Mb_512
3.5" Magneto-optical (MO) 128 Megabyte 512 bytes/sector.
F3_230Mb_512
3.5" Magneto-optical (MO) 230 Megabyte 512 bytes/sector.
F8_256_128
8", 256 Kilobyte, 128 bytes/sector.

Headers

Declared in ntdddisk.h. Include ntdddisk.h.

Comments

The caller of the IOCTL_DISK_FORMAT_TRACK request indicates the disk size and number of bytes per sector, along with other formatting information, by specifying one of these values in the MediaType member of the FORMAT_PARAMETERS structure.

Removable disks include zip drivers, jaz drives, magneto optical (MO) drives, and LS-120 floppies and as well as regular floppies.

See Also

IOCTL_DISK_FORMAT_TRACKS, FORMAT_PARAMETERS


MOUNTDEV_NAME

The MOUNTDEV_NAME structure holds the name of a device mount point.

typedef struct _MOUNTDEV_NAME {
  USHORT  NameLength;
  WCHAR  Name[1];
} MOUNTDEV_NAME, *PMOUNTDEV_NAME;

Members

NameLength
Length of the name.
Name
Name of the device mount point.

Headers

Declared in mountmgr.h. Include mountmgr.h.

See Also

IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, IOCTL_MOUNTDEV_LINK_CREATED, IOCTL_MOUNTDEV_LINK_DELETED


MOUNTDEV_SUGGESTED_LINK_NAME

Mount Manager clients that are able to keep track of their drive letters use this structure to request that the mount manager assign them a particular link name.

typedef struct _MOUNTDEV_SUGGESTED_LINK_NAME {
  BOOLEAN  UseOnlyIfThereAreNoOtherLinks;
  USHORT  NameLength;
  WCHAR  Name[1];
} MOUNTDEV_SUGGESTED_LINK_NAME, *PMOUNTDEV_SUGGESTED_LINK_NAME;

Members

UseOnlyIfThereAreNoOtherLinks
Indicates that the Mount Manager should use the suggested link name only if there are no other persistent links assigned to the client.
NameLength
Length of the suggested name.
Name
Name of the suggested link in wide characters.

Headers

Declared in mountmgr.h. Include mountmgr.h.

See Also

IOCTL_MOUNTDEV_QUERY_UNIQUE_ID


MOUNTDEV_UNIQUE_ID

The MOUNTDEV_UNIQUE_ID structure contains a unique volume ID that a mount manager client provides to the mount manager in response to a IOCTL_MOUNTDEV_QUERY_UNIQUE_ID request.

typedef struct _MOUNTDEV_UNIQUE_ID {
  USHORT  UniqueIdLength;
  UCHAR  UniqueId[1];
} MOUNTDEV_UNIQUE_ID, *PMOUNTDEV_UNIQUE_ID;

Members

UniqueIdLength
Length of unique volume ID.
UniqueId
Unique volume ID.

Headers

Declared in mountmgr.h. Include mountmgr.h.

Comments

For a discussion of unique volume IDs and how the mount manager uses them, see Supporting Mount Manager Requests in a Storage Class Driver.

See Also

IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY


MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT

The MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT structure holds a unique volume ID that a mount manager client provides to the mount manager in response to a IOCTL_MOUNTDEV_QUERY_UNIQUE_ID request.

typedef struct _MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT {
  ULONG  Size;
  USHORT  OldUniqueIdOffset;
  USHORT  OldUniqueIdLength;
  USHORT  NewUniqueIdOffset;
  USHORT  NewUniqueIdLength;
} MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT

Members

Size
Size of the buffer that follows this header.
OldUniqueIdOffset
Offset into the output buffer where the old unique ID is stored.
OldUniqueIdLength
Length of the old unique ID.
NewUniqueIdOffset
Offset into the output buffer where the old unique ID is stored.
NewUniqueIdLength
Length of the new unique ID.

Headers

Declared in mountmgr.h. Include mountmgr.h.

Comments

The mount manager can prompt a client with a IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY request to give the client a chance to change its unique ID name. If the client returns a new ID to the mount manager, it must prepend the ID information in the output buffer with the header defined in the MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT structure.

For a discussion of unique volume IDs and how the mount manager uses them, see Supporting Mount Manager Requests in a Storage Class Driver.

See Also

IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY


MOUNTMGR_CHANGE_NOTIFY_INFO

The MOUNTMGR_CHANGE_NOTIFY_INFO structure is used by the mount manager to send epic numbers to its clients and vice versa.

typedef struct _MOUNTMGR_CHANGE_NOTIFY_INFO {
  ULONG  EpicNumber;
} MOUNTMGR_CHANGE_NOTIFY_INFO, *PMOUNTMGR_CHANGE_NOTIFY_INFO;

Members

EpicNumber
A counter used by the mount manager to determine if a client has up-to-date information concerning changes in mount manager's persistent ID database.

Headers

Declared in mountmgr.h. Include mountmgr.h.

Comments

For a general discussion of the mount manager and how it communicates with its clients, see Supporting Mount Manager Requests in a Storage Class Driver.

See Also

IOCTL_MOUNTMGR_CHANGE_NOTIFY


MOUNTMGR_CREATE_POINT_INPUT

The MOUNTMGR_CREATE_POINT_INPUT structure is used by the mount manager to send a symbolic link name to a client that has requested symbolic link name by means of a IOCTL_MOUNTMGR_CREATE_POINT request.

typedef struct _MOUNTMGR_CREATE_POINT_INPUT {
  USHORT  SymbolicLinkNameOffset;
  USHORT  SymbolicLinkNameLength;
  USHORT  DeviceNameOffset;
  USHORT  DeviceNameLength;
} MOUNTMGR_CREATE_POINT_INPUT, *PMOUNTMGR_CREATE_POINT_INPUT;

Members

SymbolicLinkNameOffset
Offset into the output buffer where the symbolic link name is located.
SymbolicLinkNameLength
Length of the symbolic link name stored in the output buffer.
DeviceNameOffset
Offset into the output buffer where the non-persistent (target) device name is located.
DeviceNameLength
Length of the non-persistent (target) device name.

Headers

Declared in mountmgr.h. Include mountmgr.h.

Comments

For a discussion of the difference between symbolic link names and non-persistent target device names, see Supporting Mount Manager Requests in a Storage Class Driver.

See Also

IOCTL_MOUNTMGR_CREATE_POINT


MOUNTMGR_DRIVE_LETTER_INFORMATION

The MOUNTMGR_DRIVE_LETTER_INFORMATION structure is used by the mount manager to furnish a drive letter to a client that has requested a driver letter by means of a IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER request.

typedef struct _MOUNTMGR_DRIVE_LETTER_INFORMATION {
  BOOLEAN  DriveLetterWasAssigned;
  UCHAR  CurrentDriveLetter;
} MOUNTMGR_DRIVE_LETTER_INFORMATION, *PMOUNTMGR_DRIVE_LETTER_INFORMATION;

Members

DriveLetterWasAssigned
If TRUE, indicates that member CurrentDriveLetter contains a drive letter.
CurrentDriveLetter
If DriveLetterWasAssigned is TRUE, this member contains either an existing or a newly assigned drive letter.

Headers

Declared in mountmgr.h. Include mountmgr.h.

Comments

For a general discussion of the mount manager and how it communicates with its clients, see Supporting Mount Manager Requests in a Storage Class Driver.

See Also

IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER


MOUNTMGR_DRIVE_LETTER_TARGET

The MOUNTMGR_DRIVE_LETTER_TARGET structure is used by a mount manager client with a IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER request to furnish a non-persistent target device name to the mount manager.

typedef struct _MOUNTMGR_DRIVE_LETTER_TARGET {
  USHORT  DeviceNameLength;
  WCHAR  DeviceName[1];
} MOUNTMGR_DRIVE_LETTER_TARGET, *PMOUNTMGR_DRIVE_LETTER_TARGET;

Members

DeviceNameLength
Length of device name.
DeviceName
Non-persistent target device name.

Headers

Declared in mountmgr.h. Include mountmgr.h.

Comments

The mount manager responds to the IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER request by furnishing the client with a drive letter for the target device.

For a discussion of the difference between drive letters and non-persistent target device names, see Supporting Mount Manager Requests in a Storage Class Driver.

See Also

IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER


MOUNTMGR_MOUNT_POINT

The MOUNTMGR_MOUNT_POINT structure is used by mount manager clients in conjunction with a IOCTL_MOUNTMGR_QUERY_POINTS request to query the mount manager for all of the mount points (symbolic links) associated with a device. The mount manager responds by sending an array of MOUNTMGR_MOUNT_POINT structures containing the mount points.

typedef struct _MOUNTMGR_MOUNT_POINT {
  ULONG  SymbolicLinkNameOffset;
  USHORT  SymbolicLinkNameLength;
  ULONG  UniqueIdOffset;
  USHORT  UniqueIdLength;
  ULONG  DeviceNameOffset;
  USHORT  DeviceNameLength;
} MOUNTMGR_MOUNT_POINT, *PMOUNTMGR_MOUNT_POINT;

Members

SymbolicLinkNameOffset
An offset into the output buffer where the symbolic link is located.
SymbolicLinkNameLength
The length of the symbolic link.
UniqueIdOffset
An offset into the output buffer where the unique ID is located.
UniqueIdLength
The length of the unique ID.
DeviceNameOffset
An offset into the output buffer where the non-persistent device name is located.
DeviceNameLength
The length of the non-persistent device name.

Headers

Declared in mountmgr.h. Include mountmgr.h.

Comments

For a discussion of the different between symbolic links, unique IDs, and non-persistent device names, see Supporting Mount Manager Requests in a Storage Class Driver.

See Also

IOCTL_MOUNTMGR_QUERY_POINTS


MOUNTMGR_MOUNT_POINTS

The MOUNTMGR_MOUNT_POINTS structure is used by mount manager to send a client the list of mount points associated with a device.

typedef struct _MOUNTMGR_MOUNT_POINTS {
  ULONG  Size;
  ULONG  NumberOfMountPoints;
  MOUNTMGR_MOUNT_POINT  MountPoints[1];
} MOUNTMGR_MOUNT_POINTS, *PMOUNTMGR_MOUNT_POINTS;

Members

Size
The size of the output buffer.
NumberOfMountPoints
The number of mount points that the mount manager is returning.

Headers

Declared in mountmgr.h. Include mountmgr.h.

Comments

For a discussion of the different between symbolic links, unique IDs, and non-persistent device names, see Supporting Mount Manager Requests in a Storage Class Driver.

See Also

IOCTL_MOUNTMGR_QUERY_POINTS


MOUNTMGR_TARGET_NAME

The MOUNTMGR_TARGET_NAME structure contains the non-persistent target device name for a device and is used by mount manager clients with the IOCTL_MOUNTMGR_KEEP_LINKS_WHEN_OFFLINE request to tell the mount manager to keep the symbolic link for a device active even after the device has gone offline.

typedef struct _MOUNTMGR_TARGET_NAME {
  USHORT  DeviceNameLength;
  WCHAR  DeviceName[1];
} MOUNTMGR_TARGET_NAME, *PMOUNTMGR_TARGET_NAME;

Members

DeviceNameLength
Length of the device name.
DeviceName
Non-persistent target device name.

Headers

Declared in mountmgr.h. Include mountmgr.h.

Comments

For a discussion of the different between symbolic links, unique IDs, and non-persistent device names, see Supporting Mount Manager Requests in a Storage Class Driver.

See Also

IOCTL_MOUNTMGR_KEEP_LINKS_WHEN_OFFLINE


MOUNTMGR_VOLUME_MOUNT_POINT

The MOUNTMGR_VOLUME_MOUNT_POINT structure is used in conjunction with the IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED request to inform the mount manager that a volume mount point has been created.

typedef struct _MOUNTMGR_VOLUME_MOUNT_POINT {
  USHORT  SourceVolumeNameOffset;
  USHORT  SourceVolumeNameLength;
  USHORT  TargetVolumeNameOffset;
  USHORT  TargetVolumeNameLength;
} MOUNTMGR_VOLUME_MOUNT_POINT, *PMOUNTMGR_VOLUME_MOUNT_POINT;

Members

SourceVolumeNameOffset
Offset into the output buffer where the name of the mount point is located.
SourceVolumeNameLength
Length of the mount point name.
TargetVolumeNameOffset
Offset into the output buffer where the unique (persistent) volume name of the target device is located.
TargetVolumeNameLength
Length of the target name.

Headers

Declared in mountmgr.h. Include mountmgr.h.

Comments

For an explanation of unique volume names and how the mount manager uses them, see Supporting Mount Manager Requests in a Storage Class Driver.

See Also

IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED


PARTITION_INFORMATION

The PARTITION_INFORMATION structure contains partition information for a partition with a traditional AT-style Master Boot Record (MBR).

typedef struct _PARTITION_INFORMATION {
  LARGE_INTEGER  StartingOffset;
  LARGE_INTEGER  PartitionLength;
  DWORD  HiddenSectors;
  DWORD  PartitionNumber;
  BYTE  PartitionType;
  BOOLEAN  BootIndicator;
  BOOLEAN  RecognizedPartition;
  BOOLEAN  RewritePartition;
} PARTITION_INFORMATION, *PPARTITION_INFORMATION;

Members

StartingOffset
Specifies the offset on drive where the partition begins.
PartitionLength
Specifies the length of the partition.
HiddenSectors
Specifies the number of hidden sectors.
PartitionNumber
Specifies the number of the partition.
PartitionType
Indicates the system-defined MBR partition type. Possible values are as follows:
Partition Type | Meaning
PARTITION_ENTRY_UNUSED | Unused entry.
PARTITION_FAT_12 | Specifies a partition with 12-bit FAT entries.
PARTITION_XENIX_1 | Specifies a XENIX® Type 1 partition.
PARTITION_XENIX_2 | Specifies a XENIX Type 2 partition.
PARTITION_FAT_16 | Specifies a partition with 16-bit FAT entries.
PARTITION_EXTENDED | Specifies an MS-DOS® V4 extended partition.
PARTITION_HUGE | Specifies an MS-DOS V4 huge partition.
PARTITION_IFS | Specifies an IFS partition.
PARTITION_FAT32 | Specifies a FAT32 partition.
PARTITION_FAT32_XINT13 | Windows 95/98: Specifies a partition that uses extended INT 13 services.
PARTITION_XINT13_EXTENDED | Windows 95/98: Same as PARTITION_EXTENDED, but uses extended INT 13 services.
PARTITION_PREP | Specifies a PowerPC Reference Platform partition.
PARTITION_LDM | Specifies a logical disk manager partition.
PARTITION_UNIX | Specifies a UNIX partition.
PARTITION_NTFT | Specifies an NTFT partition. This value is used in combination (that is bitwise logically ORed) with the other values in this table.

BootIndicator
Indicates whether this partition is a bootable (active) partition for this device. This member is set according to the partition list entry boot indicator returned by IoReadPartitionTable.
RecognizedPartition
Indicates whether the system recognized the type of the partition.
RewritePartition
Indicates whether the partition information has changed. This member has a value of TRUE when the partition has changed as a result of an IOCTL_DISK_SET_DRIVE_LAYOUT IOCTL. This informs the system that the partition information needs to be rewritten.

Headers

Declared in ntdddisk.h. Include ntdddisk.h.

Comments

The partition entry data in PARTITION_INFORMATION forms part of the drive layout information reported by the legacy routine IoReadPartitionTable in the DRIVE_LAYOUT_INFORMATION structure. DRIVE_LAYOUT_INFORMATION contains an array of PARTITION_INFORMATION structures pointed to by its PartitionEntry member. Each partition entry contains information for a partition on the drive. PARTITION_INFORMATION is also used with the legacy routine IoSetPartitionInformation to change the properties of the partition, such as its type, recorded on the disk.

In Windows® 2000 and later operating systems, disk drivers should use structures DRIVE_LAYOUT_INFORMATION_EX and PARTITION_INFORMATION_EX along with routines IoReadPartitionTableEx and IoSetPartitionInformationEx to read and alter partition information on the disk.

See Also

IoReadPartitionTable, IoSetPartitionInformation, IoReadPartitionTableEx, IoSetPartitionInformationEx, DRIVE_LAYOUT_INFORMATION, DRIVE_LAYOUT_INFORMATION_EX, PARTITION_INFORMATION_EX


PARTITION_INFORMATION_EX

PARTITION_INFORMATION_EX is the extended version of the PARTITION_INFORMATION structure. It holds information both for partitions with a Master Boot Record and for partitions with a GUID Partition Table.

typedef struct _PARTITION_INFORMATION_EX {
  PARTITION_STYLE  PartitionStyle;
  LARGE_INTEGER  StartingOffset;
  LARGE_INTEGER  PartitionLength;
  ULONG  PartitionNumber;
  BOOLEAN  RewritePartition;
  union {
    PARTITION_INFORMATION_MBR  Mbr;
    PARTITION_INFORMATION_GPT  Gpt;
  };
} PARTITION_INFORMATION_EX, *PPARTITION_INFORMATION_EX;

Members

PartitionStyle
Takes a PARTITION_STYLE enumerated value that specifies the type of partition table that contains the partition.
StartingOffset
Specifies the offset on drive where the partition begins.
PartitionLength
Specifies the length of the partition.
PartitionNumber
Specifies the number of the partition.
RewritePartition
Indicates whether the partition information has changed. This member has a value of TRUE when the partition has changed as a result of an IOCTL_DISK_SET_DRIVE_LAYOUT IOCTL. This informs the system that the partition information needs to be rewritten.
Mbr
A structure of type PARTITION_INFORMATION_MBR containing information specific to a partition with a PartitionStyle member of PARTITION_STYLE_MBR.
Gpt
A structure of type PARTITION_INFORMATION_GPT containing information specific to a partition with a PartitionStyle member of PARTITION_STYLE_GPT.

Headers

Declared in ntdddisk.h. Include ntdddisk.h.

Comments

This is the extended version of the partition information structure, PARTITION_INFORMATION. IoReadPartitionTableEx and IoWritePartitionTableEx operate on an array of PARTITON_INFORMATION_EX structures contained within the extended drive layout structure, DRIVE_LAYOUT_INFORMATION_EX. PARTITION_INFORMATION_EX replaces the structure PARTITION_INFORMATION that was used with IoReadPartitionTable and IoWritePartitionTable. The principal difference is that the new structures and routines support both Master Boot Record (MBR) partitions and GUID Partition Table (GPT) partitions, whereas the older routines and structures are only used with MBR partitions.

See Also

PARTITION_INFORMATION_MBR, PARTITION_INFORMATION_GPT, IoReadPartitionTable, IoWritePartitionTable


PARTITION_INFORMATION_MBR

PARTITION_INFORMATION_MBR contains information for a Master Boot Record partition that is not held in common with a GUID Partition Table partition.

typedef struct _PARTITION_INFORMATION_MBR {
  UCHAR  PartitionType;
  BOOLEAN  BootIndicator;
  BOOLEAN  RecognizedPartition;
  ULONG  HiddenSectors;
} PARTITION_INFORMATION_MBR, *PPARTITION_INFORMATION_MBR;

Members

PartitionType
Specifies the partition type. See PARTITION_INFORMATION for a list of system-defined partition types.
BootIndicator
Indicates whether the partition is bootable.
RecognizedPartition
Indicates a partition with a recognized partition type.
HiddenSectors
Number of hidden sectors in the partition.

Headers

Declared in ntddk.h and ntdddisk.h. Include ntddk.h or ntdddisk.h.

See Also

PARTITION_INFORMATION_EX, PARTITION_INFORMATION_GPT, IoReadPartitionTable


PARTITION_INFORMATION_GPT

PARTITION_INFORMATION_GPT contains information for a GUID Partition Table partition that is not held in common with a Master Boot Record partition.

typedef struct _PARTITION_INFORMATION_GPT {
  GUID  PartitionType;
  GUID  PartitionId;
  ULONG64  Attributes;
  WCHAR Name  [36];
} PARTITION_INFORMATION_GPT, *PPARTITION_INFORMATION_GPT;

Members

PartitionType
Specifies a GUID that uniquely identifies the partition type.
PartitionId
Specifies a GUID that uniquely identifies the partition.
Attributes
Specifies the partition entry attributes used for diagnostics, recovery tools, and other firmware essential to the operation of the device. See Intel's Extensible Firmware Interface specification for further information.
Name
Specifies the partition name in Unicode.

Headers

Declared in ntdddisk.h. Include ntdddisk.h.

See Also

PARTITION_INFORMATION_EX, IoReadPartitionTableEx


PARTITION_STYLE

The PARTITION_STYLE enumeration type indicates the type of partition table for a disk.

typedef enum _PARTITION_STYLE {
  PARTITION_STYLE_MBR,
  PARTITION_STYLE_GPT
} PARTITION_STYLE;

Enumerators

PARTITION_STYLE_MBR
Specifies the traditional, AT-style Master Boot Record, type of partition table.
PARTITION_STYLE_GPT
Specifies the GUID Partition Table type of partition table.

Headers

Declared in ntdddisk.h. Include ntdddisk.h.

Comments

This enumeration is only defined for Windows XP and later.

The GUID Partition Table format conforms to the Extensible Firmware Interface (EFI) standard developed by Intel. For further information, see Intel's Extensible Firmware Interface specification.


PCIIDE_TRANSFER_MODE_SELECT

PCIIDE_TRANSFER_MODE_SELECT contains transfer mode information for all devices attached to a channel of an IDE controller.

typedef struct _PCIIDE_TRANSFER_MODE_SELECT {
  ULONG  Channel;
  BOOLEAN  DevicePresent[MAX_IDE_DEVICE];
  BOOLEAN  FixedDisk[MAX_IDE_DEVICE];
  BOOLEAN  IoReadySupported[MAX_IDE_DEVICE];
  ULONG  DeviceTransferModeSupported[MAX_IDE_DEVICE];
  ULONG  BestPioCycleTime[MAX_IDE_DEVICE];
  ULONG  BestSwDmaCycleTime[MAX_IDE_DEVICE];
  ULONG  BestMwDmaCycleTime[MAX_IDE_DEVICE];
  ULONG  BestUDmaCycleTime[MAX_IDE_DEVICE];
  ULONG  DeviceTransferModeCurrent[MAX_IDE_DEVICE];
  ULONG  DeviceTransferModeSelected[MAX_IDE_DEVICE];
} PCIIDE_TRANSFER_MODE_SELECT, *PPCIIDE_TRANSFER_MODE_SELECT;

Members

Channel
Contains the IDE channel number (0 or 1) of the devices for which a transfer mode is requested. All devices for which information is requested must be attached to the same channel.
DevicePresent
Indicates for each array entry whether the corresponding device is currently present in the system. All of the member arrays of PCIIDE_TRANSFER_MODE_SELECT contain entries for up to MAX_IDE_DEVICE devices, but for any given entry n, DevicePresent[n] must be consulted to determine if the nth device is actually present in the system. If the nth device is present, then DevicePresent[n] = TRUE.
FixedDisk
Indicates whether each device is an ATA harddisk.
IoReadySupported
Indicates whether each device supports IO Ready.
DeviceTransferModeSupported
Furnishes a bitmap indicating the data transfer modes that each attached device supports.
BestPioCycleTime
Indicates each device's best PIO cycle time.
BestSwDmaCycleTime
Indicates each device's best Single-word DMA cycle time.
BestMwDmaCycleTime
Indicates each device's best Multi-word DMA cycle time.
BestUDmaCycleTime
Indicates each device's best Ultra DMA cycle time.
DeviceTransferModeCurrent
Furnishes a bitmap indicating the data transfer modes each device is currently programmed for.
DeviceTransferModeSelected
Furnishes a bitmap indicating the data transfer modes selected by the PCI mini driver for each device.

Headers

Declared in ide.h. Include ide.h.

Comments

Member arrays DeviceTransferModeSupported, DeviceTransferModeCurrent, and DeviceTransferModeSelected are arrays of ULONG bitmaps indicating combinations of PIO and DMA transfer modes. Each bitmap corresponds to the transfer modes of a single device. The bitmaps are defined as follows:

// PIO Modes
#define PIO_MODE0 (1 << 0)
#define PIO_MODE1 (1 << 1)
#define PIO_MODE2 (1 << 2)
#define PIO_MODE3 (1 << 3)
#define PIO_MODE4 (1 << 4)

// Single-word DMA Modes
#define SWDMA_MODE0 (1 << 5)
#define SWDMA_MODE1 (1 << 6)
#define SWDMA_MODE2 (1 << 7)

// Multi-word DMA Modes
#define MWDMA_MODE0 (1 << 8)
#define MWDMA_MODE1 (1 << 9)
#define MWDMA_MODE2 (1 << 10)

// Ultra DMA Modes
#define UDMA_MODE0 (1 << 11)
#define UDMA_MODE1 (1 << 12)
#define UDMA_MODE2 (1 << 13)
#define UDMA_MODE3 (1 << 14)
#define UDMA_MODE4 (1 << 15)

See Also

HwIdeXTransferModeSelect, HwIdeXGetControllerProperties, IDE_CONTROLLER_PROPERTIES


PORT_CONFIGURATION_INFORMATION

PORT_CONFIGURATION_INFORMATION contains configuration information for an HBA. The OS-specific port driver allocates and initializes this structure, supplies as much HBA-specific configuration information as possible, and passes the structure to the miniport driver's HwScsiFindAdapter routine. The port driver gets some of the information for this structure from the miniport's HW_INITIALIZATION_DATA structure. The miniport's HwScsiFindAdapter routine is responsible for determining whether the miniport driver can support the HBA and, if so, for filling in the pertinent remaining information in the PORT_CONFIGURATION_INFORMATION structure.

typedef struct _PORT_CONFIGURATION_INFORMATION {
  ULONG  Length;
  ULONG  SystemIoBusNumber;
  INTERFACE_TYPE  AdapterInterfaceType;
  ULONG  BusInterruptLevel;
  ULONG  BusInterruptVector;
  KINTERRUPT_MODE  InterruptMode;
  ULONG  MaximumTransferLength;
  ULONG  NumberOfPhysicalBreaks;
  ULONG  DmaChannel;
  ULONG  DmaPort;
  DMA_WIDTH  DmaWidth;
  DMA_SPEED  DmaSpeed;
  ULONG  AlignmentMask;
  ULONG  NumberOfAccessRanges;
  ACCESS_RANGE  (*AccessRanges)[];
  PVOID  Reserved;
  UCHAR  NumberOfBuses;
  UCHAR  InitiatorBusId[8];
  BOOLEAN  ScatterGather;
  BOOLEAN  Master;
  BOOLEAN  CachesData;
  BOOLEAN  AdapterScansDown;
  BOOLEAN  AtdiskPrimaryClaimed;
  BOOLEAN  AtdiskSecondaryClaimed;
  BOOLEAN  Dma32BitAddresses;
  BOOLEAN  DemandMode;
  BOOLEAN  MapBuffers;
  BOOLEAN  NeedPhysicalAddresses;
  BOOLEAN  TaggedQueueing;
  BOOLEAN  AutoRequestSense;
  BOOLEAN  MultipleRequestPerLu;
  BOOLEAN  ReceiveEvent;
  BOOLEAN  RealModeInitialized;
  BOOLEAN  BufferAccessScsiPortControlled;
  UCHAR  MaximumNumberOfTargets;
  UCHAR  ReservedUchars[2];
  ULONG  SlotNumber;
  ULONG  BusInterruptLevel2;
  ULONG  BusInterruptVector2;
  KINTERRUPT_MODE  InterruptMode2;
  ULONG  DmaChannel2;
  ULONG  DmaPort2;
  DMA_WIDTH  DmaWidth2;
  DMA_SPEED  DmaSpeed2;
  ULONG  DeviceExtensionSize;
  ULONG  SpecificLuExtensionSize;
  ULONG  SrbExtensionSize;
  UCHAR  Dma64BitAddresses;
  BOOLEAN  ResetTargetSupported;
  UCHAR  MaximumNumberOfLogicalUnits;
  BOOLEAN  WmiDataProvider;
} PORT_CONFIGURATION_INFORMATION,
  *PPORT_CONFIGURATION_INFORMATION;

Members

Length
Specifies the size of this structure in bytes, as returned by sizeof(). In effect, this member, which is always initialized by the OS-specific port driver, indicates the version of this structure used by the port driver.
SystemIoBusNumber
Specifies the system-assigned number of the I/O bus to which the HBA is connected. The OS-specific port driver always initializes this member. Its value is system-assigned because the platform might have several I/O buses of the given AdapterInterfaceType.
AdapterInterfaceType
Identifies the I/O bus interface. The OS-specific port driver always sets this member to the value specified by the miniport driver in the HW_INITIALIZATION_DATA structure.
BusInterruptLevel
Specifies the bus-relative interrupt request level. The OS-specific port driver makes no assumptions about the HBA's interrupt usage, so the default value is zero. Depending on the given AdapterInterfaceType and HBA, the value set for this member can correspond to the IRQL for the bus, such as for Isa and MicroChannel type buses. Drivers of Eisa HBAs must set this value to the bus-relative IRQL for the HBA if the adapter is configured for level-sensitive interrupts.
BusInterruptVector
Specifies the bus-relative vector returned by the HBA. The OS-specific port driver makes no assumptions about the HBA's interrupt usage, so the default value is zero. This member is irrelevant to drivers that set up the BusInterruptLevel member for their HBAs. It is pertinent for HBAs on types of I/O buses that use interrupt vectors, such as PCIBus.
InterruptMode
Specifies whether the HBA uses LevelSensitive or Latched (sometimes called "edge-triggered") interrupts. The OS-specific port driver initializes this member to an appropriate value for the bus and the device—for example, LevelSensitive for PCIBus. Drivers of Eisa HBAs must reset this value if the adapter is configured for level-sensitive interrupts, as must drivers of HBAs on I/O buses that use level-sensitive interrupts, such as MicroChannel type buses.
MaximumTransferLength
Specifies the maximum number of bytes the HBA can transfer in a single transfer operation. By default, the value of this member is SP_UNINITIALIZED_VALUE, which indicates an unlimited maximum transfer size. If its HBA has more limited transfer support, a miniport driver must reset this member according to the HBA's transfer capacity. If a miniport's HwScsiInterrupt routine cannot disable interrupts on the HBA, this member can be adjusted during driver development to ensure that time spent in that miniport's ISR does not cause the mouse to "jump" or serial/parallel throughput to drop to a user-noticeable level.
NumberOfPhysicalBreaks
Specifies the maximum number of breaks between address ranges that a data buffer can have if the HBA supports scatter/gather. In other words, the number of scatter/gather lists minus one. By default, the value of this member is SP_UNINITIALIZED_VALUE, which indicates the HBA can support an unlimited number of physical discontiguities. If the port driver sets a value for this member, the miniport driver can adjust the value lower but no higher. If this member is SP_UNINITIALIZED_VALUE, the miniport driver must reset this member according to the HBA's scatter/gather capacity, with zero representing no scatter/gather support.
DmaChannel
Specifies the DMA channel used by a slave HBA. By default, the value of this member is SP_UNINITIALIZED_VALUE. If the HBA uses a system DMA controller and the given AdapterInterfaceType is any value except MicroChannel, the miniport driver must reset this member.
DmaPort
Specifies the DMA port used by a slave HBA. By default, the value of this member is SP_UNINITIALIZED_VALUE. If the HBA uses a system DMA controller and the given AdapterInterfaceType is MicroChannel, the miniport driver must reset this member.
DmaWidth
Specifies the width of DMA transfers if the HBA uses DMA. By default, the value of this member is zero. If its HBA does DMA, the miniport must reset this member to one of the following: Width8Bits, Width16Bits, or Width32Bits.
DmaSpeed
Specifies the DMA data-transfer speed for Eisa HBAs. By default, the value of this member specifies compatibility timing. Acceptable values for this member are any of the following: Compatible, TypeA, TypeB, or TypeC.
AlignmentMask
Is a mask indicating the alignment boundary for buffers required by the HBA for transfer operations. A miniport driver should set this mask to indicate any alignment restrictions on scatter/gather buffer pointers if the HBA supports scatter/gather. For example, the value 0x00000001 indicates (two-byte) word alignment.
NumberOfAccessRanges
Specifies the number of AccessRanges elements in the array, described next. The OS-specific port driver always sets this member to the value passed in the HW_INITIALIZATION_DATA structure when the miniport driver called ScsiPortInitialize.
AccessRanges
Points to an array of ACCESS_RANGE-type elements. The given NumberOfAccessRanges determines how many elements must be configured with bus-relative range values. The AccessRanges pointer must be NULL if NumberOfAccessRanges is zero. If possible, the OS-specific port driver initializes this member's elements, possibly from the registry or possibly by interrogating an I/O bus, for an HBA it found by using the miniport's specified HW_INITIALIZATION_DATA. Otherwise, the port driver initializes all values within array elements to zero.

If any access range element is set to nonzero values on entry to the miniport's HwScsiFindAdapter routine, the miniport must map the supplied addresses with ScsiPortGetDeviceBase and use the corresponding logical addresses to verify whether that HBA is one it supports. If the input AccessRanges have nonzero values supplied, a miniport should never attempt to scan the I/O bus for HBAs it supports using a set of driver-devised port/memory addresses that its HBA(s) might use.

Reserved
Reserved for system use and not available for use by miniport drivers.
NumberOfBuses
Specifies the number of SCSI buses controlled by the HBA. By default, the value of this member is zero.
InitiatorBusId
If the input InitiatorBusId[0] has the value zero, the miniport can assign a default value if its HBA does not require the use of particular value(s) determined by querying the HBA. Otherwise, the miniport should use any nonzero value assigned by the port driver if possible. Every miniport must update InitiatorBusId specifications to match what its HBA uses, if necessary querying the HBA to determine the appropriate values(s).

A miniport driver must set an entry for each SCSI bus supported by the HBA, as indicated by the value of NumberOfBuses.

ScatterGather
TRUE indicates the HBA supports scatter/gather. By default, the value of this member is FALSE.
Master
TRUE indicates the HBA is a busmaster. By default, the value of this member is FALSE.
CachesData
TRUE indicates the HBA caches data or maintains cached state on the peripherals. By default, the value of this member is FALSE. If this is reset to TRUE, the OS-specific port driver notifies the miniport driver when certain system events occur, such as file system cache flushes and system shutdown. For example, if a controller on the bus mirrors two disks, the miniport driver would normally set this member to TRUE.
AdapterScansDown
TRUE indicates the BIOS for the HBA scans for SCSI bus targets from seven to zero. By default, the value of this member is FALSE.
AtdiskPrimaryClaimed
TRUE indicates that the primary "AT" (WD1003-compatible) disk address range, 0x1F0 to 0x1FF, has been claimed in the registry by another driver for its device. The OS-specific port driver always initializes this member. If the input value of this member is TRUE, a miniport driver should assume that an already loaded driver has claimed the device range. If the input value is FALSE, a miniport driver can claim the address range for an HBA that emulates an "AT" disk controller and reset this member to TRUE, thereby preventing access to this range by the "AT" disk driver or subsequently loaded miniport drivers.
AtdiskSecondaryClaimed
TRUE indicates that the secondary AT disk address range, 0x170 to 0x17F has been claimed in the registry by another driver for its device. The OS-specific port driver always initializes this member. Miniport drivers should treat this member as for AtdiskPrimaryClaimed.
Dma32BitAddresses
TRUE indicates that the HBA has 32 address lines and can access memory with physical addresses greater than 0x00FFFFFF. By default, the value of this member is FALSE. If the miniport sets Dma64BitAddresses, this member must be FALSE.
DemandMode
TRUE indicates the system DMA controller should be programmed for demand-mode rather than single-cycle operations. If the HBA is not a slave device, this member should be FALSE.
MapBuffers
TRUE indicates data buffers must be mapped to system virtual address ranges. The OS-specific port driver always sets this member to the value passed in the HW_INITIALIZATION_DATA structure when the miniport driver called ScsiPortInitialize. A miniport driver can reset this value for any particular HBA it controls. If FALSE, the miniport must not access Srb.DataBuffer directly.
NeedPhysicalAddresses
TRUE indicates the miniport driver must translate virtual addresses to physical addresses, as required by the HBA. The OS-specific port driver always sets this member to the value passed in the HW_INITIALIZATION_DATA structure when the miniport driver called ScsiPortInitialize. A miniport driver can reset this value for any particular HBA it controls.
TaggedQueueing
TRUE indicates the HBA supports queuing of multiple requests with SCSI-2 tags. The OS-specific port driver always sets this member to the value passed in the HW_INITIALIZATION_DATA structure when the miniport driver called ScsiPortInitialize. A miniport driver can reset this value for any particular HBA it controls.
AutoRequestSense
TRUE indicates the HBA supports auto request sense. The OS-specific port driver always sets this member to the value passed in the HW_INITIALIZATION_DATA structure when the miniport driver called ScsiPortInitialize. A miniport driver can reset this value for any particular HBA it controls. This member must be set to TRUE before the driver of a busmaster HBA calls ScsiPortGetUncachedExtension.
MultipleRequestPerLu
TRUE indicates the HBA supports multiple requests per logical unit. The mechanism by which the adapter caches the requests is adapter-defined. The OS-specific port driver always sets this member to the value passed in the HW_INITIALIZATION_DATA structure when the miniport driver called ScsiPortInitialize. A miniport driver can reset this value for any particular HBA it controls.
ReceiveEvent
TRUE indicates the HBA supports SCSI receive-event operations. The OS-specific port driver always sets this member to the value passed in the HW_INITIALIZATION_DATA structure when the miniport driver called ScsiPortInitialize. A miniport driver can reset this value for any particular HBA it controls.
RealModeInitialized
TRUE indicates an (x86-only) real-mode driver has already initialized the HBA. The OS-dependent port driver always initializes this member. If this is set to TRUE, the miniport driver must not initialize its HBA if the driver's initialization sequence is identical to real-mode HBA initialization; not reinitializing the HBA in these circumstances makes the miniport driver load much faster. The value of this member is irrelevant to any miniport that always initializes its HBA while running in protected mode on x86-based platforms and to all miniports for which it is immaterial whether they are running on a CISC- or RISC-based platform.
BufferAccessScsiPortControlled
TRUE indicates that the miniport always calls ScsiPort Xxx to access data buffers and/or request-sense information in SRBs, thereby allowing the OS-specific port driver to optimize I/O request processing. Setting this member to FALSE can degrade the I/O performance of the HBA. Calling routines other than the ScsiPort Xxx makes a miniport driver nonportable across Microsoft operating systems.
MaximumNumberOfTargets
Specifies the number of target peripherals the HBA can control. By default, the value of this member is SCSI_MAXIMUM_TARGETS, according to the SCSI-2 standard. A miniport can reset this member to a lesser value if the HBA has more limited capabilities or to a greater value, indicating that the HBA has wide-SCSI or FibreChannel capabilities.
ReservedUchars
Reserved for system use and not available for use by miniport drivers.
SlotNumber
Specifies the slot number of an HBA with matching values to the VendorId and DeviceId that were specified in the HW_INITIALIZATION_DATA structure when the miniport driver called ScsiPortInitialize.
BusInterruptLevel2
Reserved for system use and not available for use by miniport drivers.
BusInterruptVector2
Reserved for system use and not available for use by miniport drivers.
InterruptMode2
Reserved for system use and not available for use by miniport drivers.
DmaChannel2
Reserved for system use and not available for use by miniport drivers.
DmaPort2
Reserved for system use and not available for use by miniport drivers.
DmaWidth2
Reserved for system use and not available for use by miniport drivers.
DmaSpeed2
Reserved for system use and not available for use by miniport drivers.
DeviceExtensionSize
Specifies the size in bytes required by a miniport driver for its per-HBA device extension to handle data transfers larger than 64K, which might require larger scatter/gather lists than the size defined in the registry for this driver.
SpecificLuExtensionSize
Specifies the size in bytes required by the miniport driver for its per-logical-unit-storage, if any, to handle data transfers larger than 64K. Leave this member set to zero if the miniport does not maintain per-LU information for which it requires storage. This value is based on the assumption that the HBA is able to receive 32-bit addresses, regardless of what the controller can actually support. If additional space is needed in the LUN or SRB extensions to handle 64-bit addresses, then appropriate adjustments must be made to this value before using it with routines such as ScsiPortGetUncachedExtension.
SrbExtensionSize
Specifies the size in bytes required by the miniport driver for its per-request storage, if any, to handle data transfers larger than 64K. Set this member before calling ScsiPortGetUncachedExtension to change the size of per-request storage based on NumberOfPhysicalBreaks. Leave this member set to zero if the miniport driver does not maintain per-SRB information for which it requires storage. This value is based on the assumption that the HBA is able to receive 32-bit addresses, regardless of what the controller can actually support. If additional space is needed in the LUN or SRB extensions to handle 64-bit addresses, then appropriate adjustments must be made to this value before using it with routines such as ScsiPortGetUncachedExtension.
Dma64BitAddresses
A value of SCSI_DMA64_MINIPORT_SUPPORTED indicates that the HBA is able to access addresses greater than 4GB, or 0x0FFFFFFFF. Prior to Windows 2000 the ScsiPort set this value based on the contents of HW_INITIALIZATION_DATA. This is no longer the case. In Windows 2000 the value of Dma64BitAddresses is determined by the miniport callback HwScsiFindAdapter alone. If the HBA described by PORT_CONFIGURATION_INFORMATION supports address spaces greater than 32-bits then the port/miniport driver is required to support full 64-bit addressing, and the miniport's callback HwScsiFindAdapter indicates this by assigning a value of SCSI_DMA64_MINIPORT_SUPPORTED to Dma64BitAddresses, writing over any previous value assigned by the port driver. The correct value must be assigned to the Dma64BitAddresses member before the miniport calls ScsiPortGetUncachedExtension.
ResetTargetSupported
TRUE indicates that the miniport driver has the ability to reset a target device in response to an SRB_FUNCTION_RESET_DEVICE request from the port driver. By default, the value of this member is FALSE.
MaximumNumberOfLogicalUnits
Specifies the maximum number of logical units per target the HBA can control. By default, the value of this member is SCSI_MAXIMUM_LOGICAL_UNITS. A miniport can reset this member to a lesser value if the HBA has more limited capabilities or to a greater value, indicating that the HBA has SCSI-3 capabilities.
WmiDataProvider
TRUE indicates that the miniport responds to Windows Management Instrumentation (WMI) requests. By default, the value of this member is FALSE.

Headers

Declared in srb.h. Include srb.h.

Comments

The specific members initialized depend on the HBA miniport driver and on the configuration information available to the OS-specific port driver. The OS-specific port driver sets default values in all members for which it cannot supply configuration information to the miniport's HwScsiFindAdapter routine.

All HBA miniport drivers should have at least one set of defaults to use for relevant members if the OS-specific port driver does not pass in all initialized values.

The HwScsiFindAdapter routine must update all members relevant to an HBA that the driver supports.

Windows NT storage class drivers, which load later than miniport drivers, depend on the information supplied by each miniport's HwScsiFindAdapter routine to set up their subsequent I/O requests. For example, the MaximumTransferLength and NumberOfPhysicalBreaks values supplied by each miniport driver control whether a class driver must split large transfer requests into a set of partial transfers to suit the limits of the HBA.

Prior to Windows 2000 both the PORT_CONFIGURATION_INFORMATION and the HW_INITIALIZATION_DATA structures had a member called Dma64BitAddresses. In Windows 2000, Dma64BitAddresses has been eliminated from the HW_INITIALIZATION_DATA structure, and its definition has changed somewhat in PORT_CONFIGURATION_INFORMATION. The port driver no longer consults HW_INITIALIZATION_DATA in order to initialize Dma64BitAddresses in PORT_CONFIGURATION_INFORMATION.

The Dma64BitAddresses member of PORT_CONFIGURATION_INFORMATION should no longer be thought of as a BOOLEAN value. A value of SCSI_DMA64_SYSTEM_SUPPORTED indicates that the port/miniport driver is required to support 64-bit addressing, but the ScsiPortGetUncachedExtension routine still interprets any non-zero value of Dma64BitAddresses as indicating that 64-bit support is required. This means that ScsiPortGetUncachedExtension still functions properly when called by a legacy driver that assigns BOOLEAN values to Dma64BitAddresses.

In addition to Dma64BitAddresses, both PORT_CONFIGURATION_INFORMATION and HW_INITIALIZATION_DATA have a pair of members called SpecificLuExtensionSize and SrbExtensionSize whose values must now be handled differently. The miniport must calculate the initial values of SpecificLuExtensionSize and SrbExtensionSize in HW_INITIALIZATION_DATA based on the assumption that the HBA is capable of receiving 32-bit addresses, regardless of what the controller can actually support. The default values for SpecificLuExtensionSize and SrbExtensionSize in PORT_CONFIGURATION_INFORMATION will also be based on an assumption of 32-bit addressing, since the values in PORT_CONFIGURATION_INFORMATION are derived from the values in HW_INITIALIZATION_DATA.

This means that if the miniport needs additional space in either the LUN extension or the SRB extension in order to handle 64 bit physical addresses, it must modify the values for SpecificLuExtensionSize and SrbExtensionSize in PORT_CONFIGURATION_INFORMATION to account for this before passing PORT_CONFIGURATION_INFORMATION to ScsiPortGetUncachedExtension.

See Also

ACCESS_RANGE, DriverEntry, HW_INITIALIZATION_DATA, HwScsiFindAdapter, ScsiPortGetDeviceBase, ScsiPortGetUncachedExtension, ScsiPortInitialize, ScsiPortValidateRange


READ_ELEMENT_ADDRESS_INFO

This structure is to retrieve changer elements based on a search criterion specified in a call to the ChangerQueryVolumeTags routine

typedef struct READ_ELEMENT_ADDRESS_INFO {
  ULONG  NumberOfElements;
  CHANGER_ELEMENT_STATUS  ElementStatus[1];
} READ_ELEMENT_ADDRESS_INFO, *PREAD_ELEMENT_ADDRESS_INFO;

Members

NumberOfElements
Indicates the number of elements that matched the criteria specified by ActionCode and VolumeTemplateID in the CHANGER_SEND_VOLUME_TAG_INFORMATION structure passed to the driver. If no element matches the criteria, this member is zero.
ElementStatus
The first CHANGER_ELEMENT_STATUS structure that matched the criteria in the CHANGER_SEND_VOLUME_TAG_INFORMATION structure passed to the driver.

Headers

Declared in ntddchgr.h. Include ntddchgr.h.

See Also

CHANGER_SEND_VOLUME_TAG_INFORMATION, GET_CHANGER_PARAMETERS, CHANGER_ELEMENT_STATUS, ChangerQueryVolumeTags


REASSIGN_BLOCKS

The REASSIGN_BLOCKS structure is used in conjunction with the IOCTL_DISK_REASSIGN_BLOCKS request to instruct a disk device to reassign the block numbers of the indicated bad blocks to good blocks.

typedef struct _REASSIGN_BLOCKS {
  WORD  Reserved;
  WORD  Count;
  DWORD  BlockNumber[1];
} REASSIGN_BLOCKS, *PREASSIGN_BLOCKS;

Members

Reserved
Reserved for system use.
Count
Number of blocks to reassign.
BlockNumber
Array of block numbers corresponding to damaged blocks. These numbers will be reassigned to good blocks taken from the device's spare block pool.

Headers

Declared in ntdddisk.h. Include ntdddisk.h.

See Also

IOCTL_DISK_REASSIGN_BLOCKS


SCSI_PASS_THROUGH

The SCSI_PASS_THROUGH structure is used in conjunction with an IOCTL_SCSI_PASS_THROUGH request to instruct the port driver to send an embedded SCSI command to the target device.

typedef struct _SCSI_PASS_THROUGH {
  USHORT  Length;
  UCHAR  ScsiStatus;
  UCHAR  PathId;
  UCHAR  TargetId;
  UCHAR  Lun;
  UCHAR  CdbLength;
  UCHAR  SenseInfoLength;
  UCHAR  DataIn;
  ULONG  DataTransferLength;
  ULONG  TimeOutValue;
  ULONG_ PTR DataBufferOffset;
  ULONG  SenseInfoOffset;
  UCHAR  Cdb[16];
}SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;

Members

Length
Sum of the length of the SCSI_PASS_THROUGH structure and the lengths of the accompanying data and request sense buffers.
ScsiStatus
Reports the SCSI status that was returned by the HBA or the target device.
PathId
Indicates the SCSI port or bus for the request.
TargetId
Indicates the target controller or device on the bus.
Lun
Indicates the logical unit number of the device.
CdbLength
Indicates the size in bytes of the SCSI command descriptor block.
SenseInfoLength
Indicates the size in bytes of the request-sense buffer.
DataIn
Indicates whether the SCSI command will read or write data. This field must have one of three values:
Data Transfer Type | Meaning
SCSI_IOCTL_DATA_IN | Write data to the device.
SCSI_IOCTL_DATA_OUT | Read data from the device.
SCSI_IOCTL_DATA_UNSPECIFIED | Direction of data transfer unspecified.

DataTransferLength
Indicates the size in bytes of the data buffer. If an underrun occurs, the miniport must update this member to the number of bytes actually transferred.
TimeOutValue
Indicates the interval in seconds that the request can execute before the OS-specific port driver might consider it timed out.
DataBufferOffset
Offset from the beginning of this structure to the data buffer.
SenseInfoOffset
Offset from the beginning of this structure to the request-sense buffer.
Cdb
Specifies the SCSI-2 command descriptor block to be sent to the target device.

Headers

Declared in ntddscsi.h. Include ntddscsi.h.

Comments

The SCSI_PASS_THROUGH structure is used with IOCTL_SCSI_PASS_THROUGH, which is a buffered device control request. To bypass buffering in system memory, callers should use IOCTL_SCSI_PASS_THROUGH_DIRECT. When handling an IOCTL_SCSI_PASS_THROUGH_DIRECT request, the system locks down the buffer in user memory and the device accesses this memory directly.

The members of SCSI_PASS_THROUGH correspond roughly to the members of a SCSI_REQUEST_BLOCK structure. The values of the DataIn member correspond to the SCSI_IOCTL_DATA_IN, SCSI_IOCTL_DATA_OUT, and SCSI_IOCTL_DATA_UNSPECIFIED flags assigned to SrbFlags member of SCSI_REQUEST_BLOCK.

See Also

SCSI_PASS_THROUGH_DIRECT, SCSI_REQUEST_BLOCK, IOCTL_SCSI_PASS_THROUGH, IOCTL_SCSI_PASS_THROUGH_DIRECT


SCSI_PASS_THROUGH_DIRECT

The SCSI_PASS_THROUGH structure is used in conjunction with an IOCTL_SCSI_PASS_THROUGH_DIRECT request to instruct the port driver to send an embedded SCSI command to the target device.

typedef struct _SCSI_PASS_THROUGH_DIRECT {
  USHORT  Length;
  UCHAR  ScsiStatus;
  UCHAR  PathId;
  UCHAR  TargetId;
  UCHAR  Lun;
  UCHAR  CdbLength;
  UCHAR  SenseInfoLength;
  UCHAR  DataIn;
  ULONG  DataTransferLength;
  ULONG  TimeOutValue;
  PVOID  DataBuffer;
  ULONG  SenseInfoOffset;
  UCHAR  Cdb[16];
}SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT;

Members

Length
Sum of the length of the SCSI_PASS_THROUGH structure and the lengths of the accompanying data and request sense buffers.
ScsiStatus
Reports the SCSI status that was returned by the HBA or the target device.
PathId
Indicates the SCSI port or bus for the request.
TargetId
Indicates the target controller or device on the bus.
Lun
Indicates the logical unit number of the device.
CdbLength
Indicates the size in bytes of the SCSI command descriptor block.
SenseInfoLength
Indicates the size in bytes of the request-sense buffer.
DataIn
Indicates whether the SCSI command will read or write data. This field must have one of three values:
Data Transfer Type | Meaning
SCSI_IOCTL_DATA_IN | Write data to the device.
SCSI_IOCTL_DATA_OUT | Read data from the device.
SCSI_IOCTL_DATA_UNSPECIFIED | Direction of data transfer unspecified.

DataTransferLength
Indicates the size in bytes of the data buffer. If an underrun occurs, the miniport must update this member to the number of bytes actually transferred.
TimeOutValue
Indicates the interval in seconds that the request can execute before the OS-specific port driver might consider it timed out.
DataBuffer
Pointer to the data buffer.
SenseInfoOffset
Offset from the beginning of this structure to the request-sense buffer.
Cdb
Specifies the SCSI-2 command descriptor block to be sent to the target device.

Headers

Declared in ntddscsi.h. Include ntddscsi.h.

Comments

The SCSI_PASS_THROUGH_DIRECT structure is used with IOCTL_SCSI_PASS_THROUGH_DIRECT. With this request, the system locks down the buffer in user memory and the device accesses this memory directly. For a double-buffered equivalent of this device control request see IOCTL_SCSI_PASS_THROUGH and SCSI_PASS_THROUGH.

The members of SCSI_PASS_THROUGH_DIRECT correspond roughly to the members of a SCSI_REQUEST_BLOCK structure. The values of the DataIn member correspond to the SCSI_IOCTL_DATA_IN, SCSI_IOCTL_DATA_OUT, and SCSI_IOCTL_DATA_UNSPECIFIED flags assigned to SrbFlags member of SCSI_REQUEST_BLOCK.

See Also

SCSI_PASS_THROUGH, SCSI_REQUEST_BLOCK, IOCTL_SCSI_PASS_THROUGH, IOCTL_SCSI_PASS_THROUGH_DIRECT


SCSI_REQUEST_BLOCK

typedef struct _SCSI_REQUEST_BLOCK {
  USHORT  Length;
  UCHAR  Function;
  UCHAR  SrbStatus;
  UCHAR  ScsiStatus;
  UCHAR  PathId;
  UCHAR  TargetId;
  UCHAR  Lun;
  UCHAR  QueueTag;
  UCHAR  QueueAction;
  UCHAR  CdbLength;
  UCHAR  SenseInfoBufferLength;
  ULONG  SrbFlags;
  ULONG  DataTransferLength;
  ULONG  TimeOutValue;
  PVOID  DataBuffer;
  PVOID  SenseInfoBuffer;
  struct _SCSI_REQUEST_BLOCK  *NextSrb;
  PVOID  OriginalRequest;
  PVOID  SrbExtension;
  union {
      ULONG  InternalStatus;
      ULONG  QueueSortKey;
  };
  UCHAR  Cdb[16];
} SCSI_REQUEST_BLOCK, *PSCSI_REQUEST_BLOCK;

Members

Length
Specifies the size in bytes of this structure.
Function
Specifies the operation to be performed, which can be one of the following values:
Operation Meaning
SRB_FUNCTION_EXECUTE_SCSI
A SCSI device I/O request should be executed on the target logical unit.
SRB_FUNCTION_ABORT_COMMAND
A SCSIMESS_ABORT message should be sent to cancel the request pointed to by the NextSrb member. If this is a tagged-queue request, a SCSIMESS_ABORT_WITH_TAG message should be used instead. If the indicated request has been completed, this request should be completed normally. Only the SRB Function, PathId, TargetId, Lun, and NextSrb members are valid.
SRB_FUNCTION_RESET_DEVICE
The SCSI target controller should be reset using the SCSIMESS_BUS_DEVICE_RESET message. The miniport driver should complete any active requests for the target controller. Only the SRB Function, TargetId, and PathId members are valid.
SRB_FUNCTION_RESET_BUS
The SCSI bus should be reset using the SCSIMESS_BUS_DEVICE_RESET message. A miniport driver receives this request only if a given request has timed out and a subsequent request to abort the timed-out request also has timed out. Only the SRB Function and PathId members are valid.
SRB_FUNCTION_TERMINATE_IO
A SCSIMESS_TERMINATE_IO_PROCESS message should be sent to cancel the request pointed to by the NextSrb member. If the indicated request has already completed, this request should be completed normally. Only the SRB Function, PathId, TargetId, Lun, and NextSrb members are valid.
SRB_FUNCTION_RELEASE_RECOVERY
A SCSIMESS_RELEASE_RECOVERY message should be sent to the target controller. Only the SRB Function, PathId, TargetId, and Lun members are valid.
SRB_FUNCTION_RECEIVE_EVENT
The HBA should be prepared to receive an asynchronous event notification from the addressed target. The SRB DataBuffer member indicates where the data should be placed.
SRB_FUNCTION_SHUTDOWN
The system is being shut down. This request is sent to a miniport driver only if it set CachesData to TRUE in the PORT_CONFIGURATION_INFORMATION for the HBA. Such a miniport driver can receive several of these notifications before all system activity actually stops. However, the last shutdown notification will occur after the last start I/O. Only the SRB Function, PathId, TargetId, and Lun members are valid.
SRB_FUNCTION_FLUSH
The miniport should flush any cached data for the target device. This request is sent to the miniport driver only if it set CachesData to TRUE in the PORT_CONFIGURATION_INFORMATION for the HBA. Only the SRB Function, PathId, TargetId, and Lun members are valid.
SRB_FUNCTION_IO_CONTROL
The request is an I/O control request, originating in a user-mode application with a dedicated HBA. The SRB DataBuffer points to an SRB_IO_CONTROL header followed by the data area. The value in DataBuffer can be used by the driver, regardless of the value of MapBuffers. Only the SRB Function, SrbFlags, TimeOutValue, DataBuffer, and DataTransferLength members are valid, along with the SrbExtension member if the miniport driver requested SRB extensions when it initialized. If a miniport driver controls an application-dedicated HBA so it supports this request, the miniport should execute the request and notify the OS-specific port driver when the SRB has completed, using the normal mechanism of calls to ScsiPortNotification with RequestComplete and NextRequest.
SRB_FUNCTION_LOCK_QUEUE
Holds requests queued by the port driver for a particular logical unit, typically while a power request is being processed. Only the SRB Length, Function, SrbFlags, and OriginalRequest members are valid. When the queue is locked, only requests with SrbFlags ORed with SRB_FLAGS_BYPASS_LOCKED_QUEUE will be processed. SCSI miniport drivers do not process SRB_FUNCTION_LOCK_QUEUE requests.
SRB_FUNCTION_UNLOCK_QUEUE
Releases the port driver's queue for a logical unit that was previously locked with SRB_FUNCTION_LOCK_QUEUE. The SrbFlags of the unlock request must be ORed with SRB_FLAGS_BYPASS_LOCKED_QUEUE. Only the SRB Length, Function, SrbFlags, and OriginalRequest members are valid. SCSI miniport drivers do not process SRB_FUNCTION_UNLOCK_QUEUE requests.

SrbStatus
Returns the status of the completed request. This member should be set by the miniport driver before it notifies the OS-specific driver that the request has completed by calling ScsiPortNotification with RequestComplete. The value of this member can be one of the following:
Status Meaning
SRB_STATUS_PENDING
Indicates the request is in progress. The OS-specific port driver initializes SrbStatus to this value. A miniport driver should never set the SrbStatus member to this value.
SRB_STATUS_SUCCESS
Indicates the request was completed successfully.
SRB_STATUS_ABORTED
Indicates the request was aborted as directed by the port driver. A miniport driver sets this status in the NextSrb for a successful SRB_FUNCTION_ABORT_COMMAND request.
SRB_STATUS_ABORT_FAILED
Indicates an attempt to abort the request failed. Return this status for an SRB_FUNCTION_ABORT_COMMAND request when the specified request cannot be located.
SRB_STATUS_ERROR
Indicates the request was completed with an error in the SCSI bus status.
SRB_STATUS_BUSY
Indicates the miniport or target device could not accept the request at this time. The OS-specific port driver will resubmit the request later.
SRB_STATUS_INTERNAL_ERROR
Indicates that the ScsiPort driver could not deliver the request to the miniport or target device. In such cases, status is recorded in InternalStatus.
SRB_STATUS_INVALID_REQUEST
Indicates the miniport driver does not support the given request.
SRB_STATUS_NO_DEVICE
Indicates the device did not respond.
SRB_STATUS_TIMEOUT
Indicates the request timed out.
SRB_STATUS_SELECTION_TIMEOUT
Indicates the SCSI device selection timed out.
SRB_STATUS_COMMAND_TIMEOUT
Indicates the target did not complete the command within the time limit.
SRB_STATUS_MESSAGE_REJECTED
Indicates the target rejected a message. This is normally returned only for such message-type requests as SRB_FUNCTION_TERMINATE_IO.
SRB_STATUS_BUS_RESET
Indicates a bus reset occurred while this request was being executed.
SRB_STATUS_PARITY_ERROR
Indicates a parity error occurred on the SCSI bus and that a retry failed.
SRB_STATUS_REQUEST_SENSE_FAILED
Indicates the request-sense command failed. This is returned only if the HBA performs auto request sense and the miniport driver set AutoRequestSense to TRUE in the PORT_CONFIGURATION_INFORMATION for this HBA.
SRB_STATUS_NO_HBA
Indicates the HBA does not respond.
SRB_STATUS_DATA_OVERRUN
Indicates that a data overrun or underrun error occurred. The miniport also must update the SRB's DataTransferLength member to indicate how much data actually was transferred if an underrun occurs.
SRB_STATUS_UNEXPECTED_BUS_FREE
Indicates the target disconnected unexpectedly.
SRB_STATUS_PHASE_SEQUENCE_FAILURE
Indicates the HBA detected an illegal phase sequence failure error.
SRB_STATUS_REQUEST_FLUSHED
Indicates the request for status was stopped.
SRB_STATUS_BAD_FUNCTION
Indicates the SRB Function code is not supported.
SRB_STATUS_INVALID_PATH_ID
Indicates the PathId specified in the SRB does not exist.
SRB_STATUS_INVALID_TARGET_ID
Indicates the TargetID value in the SRB is invalid.
SRB_STATUS_INVALID_LUN
Indicates the Lun value in the SRB is invalid.
SRB_STATUS_ERROR_RECOVERY
Indicates the request was completed with an error in the SCSI bus status and that the SCSI INITIATE RECOVERY message was received.
SRB_STATUS_AUTOSENSE_VALID
Indicates information returned in the SenseInfoBuffer is valid.
SRB_STATUS_QUEUE_FROZEN
A miniport driver should never set the SrbStatus member to this value. The Windows NT port driver can set this value to inform a storage class driver that its queue of requests for a particular peripheral has been frozen.

ScsiStatus
Returns the SCSI status that was returned by the HBA or target device. If the status is not SUCCESS, the miniport driver should set the SrbStatus member to SRB_STATUS_ERROR.
PathId
Indicates the SCSI port or bus for the request. This value is zero-based.
TargetId
Indicates the target controller or device on the bus.
Lun
Indicates the logical unit number of the device.
QueueTag
Is the queue-tag value assigned by the OS-specific port driver. If this member is used for tagged queuing, the HBA supports internal queuing of requests to LUs and the miniport driver set TaggedQueueing to TRUE in the PORT_CONFIGURATION_INFORMATION for this HBA.
QueueAction
Indicates the tagged-queuing message to be used when the SRB_FLAGS_QUEUE_ACTION_ENABLE flag is set. The value can be one of the following: SRB_SIMPLE_TAG_REQUEST, SRB_HEAD_OF_QUEUE_TAG_REQUEST, or SRB_ORDERED_QUEUE_TAG_REQUEST, as defined according to the SCSI-2 specification.
CdbLength
Indicates the size in bytes of the SCSI command descriptor block.
SenseInfoBufferLength
Indicates the size in bytes of the request-sense buffer.
SrbFlags
Indicates various parameters and options about the request. SrbFlags is read-only, except when SRB_FLAGS_UNSPECIFIED_DIRECTION is set and miniport drivers of slave DMA adapters are required to update SRB_FLAGS_DATA_IN or SRB_FLAGS_DATA_OUT. This member can have one or more of the following flags set:
Value Meaning
SRB_FLAGS_QUEUE_ACTION_ENABLE
Indicates tagged-queue actions are to be enabled.
SRB_FLAGS_DISABLE_AUTOSENSE
Indicates that request-sense information should not be returned.
SRB_FLAGS_DATA_IN
Indicates data will be transferred from the device to the system.
SRB_FLAGS_DATA_OUT
Indicates data will be transferred from the system to the device.
SRB_FLAGS_UNSPECIFIED_DIRECTION
Defined for backward compatibility with the ASPI/CAM SCSI interfaces, this flag indicates that the transfer direction could be either of the preceding because both of the preceding flags are set. If this flag is set, a miniport driver should determine the transfer direction by examining the data phase for the target on the SCSI bus. If its HBA is a slave DMA device, such a miniport must update SRB_FLAGS_DATA_OUT or SRB_FLAGS_DATA_IN to the correct value before it calls ScsiPortIoMapTransfer.
SRB_FLAGS_NO_DATA_TRANSFER
Indicates no data transfer with this request. If this is set, the flags SRB_FLAGS_DATA_OUT, SRB_FLAGS_DATA_IN, and SRB_FLAGS_UNSPECIFIED_DIRECTION are clear.
SRB_FLAGS_DISABLE_SYNCH_TRANSFER
Indicates the HBA, if possible, should perform asynchronous I/O for this transfer request. If synchronous I/O was negotiated previously, the HBA must renegotiate for asynchronous I/O before performing the transfer.
SRB_FLAGS_DISABLE_DISCONNECT
Indicates the HBA should not allow the target to disconnect from the SCSI bus during processing of this request.
SRB_FLAGS_BYPASS_FROZEN_QUEUE
Is irrelevant to miniport drivers.
SRB_FLAGS_NO_QUEUE_FREEZE
Is irrelevant to miniport drivers.
SRB_FLAGS_IS_ACTIVE
Is irrelevant to miniport drivers.
SRB_FLAGS_ALLOCATED_FROM_ZONE
Is irrelevant to miniport drivers and is obsolete to new Windows NT class drivers. To a Windows NT legacy class driver, this indicates whether the SRB was allocated from a zone buffer. If this flag is set, the class driver must call ExInterlockedFreeToZone to release the SRB; otherwise, it must call ExFreePool. New class drivers should use lookaside lists rather than zone buffers.
SRB_FLAGS_SGLIST_FROM_POOL
Is irrelevant to miniport drivers. To a Windows NT class driver, this indicates that memory for a scatter/gather list was allocated from nonpaged pool. If this flag is set, the class driver must call ExFreePool to release the memory after the SRB is completed.
SRB_FLAGS_BYPASS_LOCKED_QUEUE
Is irrelevant to miniport drivers. To the port driver, this flag indicates that the request should be processed whether or not the logical-unit queue is locked. A higher-level driver must set this flag to send an SRB_FUNCTION_UNLOCK_QUEUE request.
SRB_FLAGS_NO_POWER
Is irrelevant to miniport drivers. A Windows NT class driver uses this flag to indicate to the port driver to report idle rather than powering up the device to handle this request.

DataTransferLength
Indicates the size in bytes of the data buffer. If an underrun occurs, the miniport must update this member to the number of bytes actually transferred.
TimeOutValue
Indicates the interval in seconds that the request can execute before the OS-specific port driver might consider it timed out. Miniport drivers are not required to time requests because the port driver already does.
DataBuffer
Points to the data buffer. Miniport drivers should not use this value as a data pointer unless the miniport set MapBuffers to TRUE in the PORT_CONFIGURATION_INFORMATION for the HBA. In the case of SRB_FUNCTION_IO_CONTROL requests, however, miniport drivers can use this value as a data pointer regardless of the value of MapBuffers.
SenseInfoBuffer
Points to the request-sense buffer. A miniport driver is not required to provide request-sense data after a CHECK CONDITION.
NextSrb
Indicates the SCSI_REQUEST_BLOCK to which this request applies. Only a small subset of requests use a second SRB, for example SRB_FUNCTION_ABORT_COMMAND.
OriginalRequest
Points to the IRP for this request. This member is irrelevant to miniport drivers
SrbExtension
Points to the Srb extension. A miniport must not use this member if it set SrbExtensionSize to zero in the SCSI_HW_INITIALIZATION_DATA. The memory at SrbExtension is not initialized by the OS-specific port driver, and the miniport-determined data can be accessed directly by the HBA. The corresponding physical address can be obtained by calling ScsiPortGetPhysicalAddress with the SrbExtension pointer.
InternalStatus
Used by the ScsiPort driver, instead of SrbStatus, to report the status of the completed request whenever the request can not be delivered to the miniport driver. In such cases, SrbStatus is set to SRB_STATUS_INTERNAL_ERROR. This member is used exclusively for communication between the ScsiPort and the class driver and should not be used by miniport drivers.
QueueSortKey
Specifies the offset from the start of the media or zero, depending on the type of the target device.
Cdb
Specifies the SCSI-2 command descriptor block to be sent to the target device.

Headers

Declared in srb.h. Include srb.h.

Comments

Windows NT storage class and filter drivers can send SRBs with the following Function values to the system port driver:

  • SRB_FUNCTION_CLAIM_DEVICE to indicate that the class driver supports a peripheral identified in the SRB by the PathId, TargetId, and Lun members.
  • SRB_ATTACH_DEVICE to indicate that a filter driver, layered above a class driver, wants requests for a particular peripheral to be routed first to the filter driver.
  • SRB_FUNCTION_RELEASE_DEVICE to indicate that a class driver is releasing its claim on a particular peripheral.
  • SRB_FUNCTION_FLUSH_QUEUE to request cancellation of any requests currently queued in the port driver to a particular peripheral.
  • SRB_FUNCTION_RELEASE_QUEUE to request that the port driver release a frozen queue of requests to a particular peripheral.

The preceding SRB_FUNCTION_XXX are never set in SRBs sent to SCSI miniport drivers. SRB_FUNCTION_REMOVE_DEVICE is defined for use in future versions of the system. It, too, is never set in SRBs sent to SCSI miniport drivers. SRB_FUNCTION_WMI_REQUEST is valid only in SCSI_WMI_REQUEST_BLOCK. A storage class or filter driver uses this to send WMI requests to the port driver.

See Also

ExFreePool, ExInterlockedFreeToZone, HW_INITIALIZATION_DATA, PORT_CONFIGURATION_INFORMATION, SCSI_WMI_REQUEST_BLOCK, ScsiPortGetPhysicalAddress, ScsiPortGetSrb, ScsiPortIoMapTransfer, ScsiPortNotification, SRB_IO_CONTROL


SCSIWMIGUIDREGINFO

The SCSIWMIGUIDREGINFO structure contains information about a given data or event block supported by a SCSI miniport driver.

typedef struct {
  LPCGUID  Guid;
  ULONG  InstanceCount;
  ULONG  Flags;
} SCSIWMIGUIDREGINFO, *PSCSIWMIGUIDREGINFO;

Members

Guid
Points to the GUID that identifies the block.
InstanceCount
Specifies the number of instances defined for the block.
Flags
Indicates characteristics of the block. The SCSI port driver sets all but the following WMIREG_FLAG_XXX on behalf of the miniport. A miniport might set one or more of the following flags:
WMIREG_FLAG_EVENT_ONLY_GUID
The block can be enabled or disabled as an event only, and cannot be queried or set. If this flag is clear, the block can also be queried or set.
WMIREG_FLAG_EXPENSIVE
Requests the port driver send an enable-collection SRB the first time a data consumer opens the data block and a disable-collection SRB when the last data consumer closes the data block. This is recommended if collecting such data affects performance. A miniport need not collect the data until a data consumer explicitly requests it by opening the block.
WMIREG_FLAG_REMOVE_GUID
If set, removes support for a previously registered block.

Headers

Declared in scsiwmi.h. Include scsiwmi.h.

Comments

The miniport passes a pointer to a SCSI_WMILIB_CONTEXT which contains a SCSIWMIREGGUID array in the WmiLibInfo parameter of ScsiPortWmiDispatchFunction. The miniport passes this information each time it calls ScsiPortWmiDispatchFunction. Each SCSIWMIREGGUID structure in the array represents one of the miniport's data or event blocks.

A miniport's SCSIWMIREGGUID array should include any standard data blocks defined in wmicore.mof for its device type, and might include miniport-defined data and event blocks. A miniport defines custom data and event blocks in a MOF file, which is compiled as a resource attached to the miniport's binary image and specified in the MofResourceName parameter of the miniport's HwScsiWmiQueryReginfo routine.

For more information about defining blocks, Windows Management Instrumentation.

See Also

HwScsiWmiQueryReginfo, ScsiPortWmiDispatchFunction, SCSI_WMILIB_CONTEXT


SCSI_WMILIB_CONTEXT

A SCSI_WMILIB_CONTEXT structure provides registration information for a miniport's data and event blocks and defines entry points for the miniport's HwScsiWmiXxx callback routines.

typedef struct _SCSIWMILIB_CONTEXT {
  ULONG  GuidCount;
  PSCSIWMIGUIDREGINFO  GuidList;
  PSCSIWMI_QUERY_REGINFO  QueryWmiRegInfo;
  PSCSIWMI_QUERY_DATABLOCK  QueryWmiDataBlock;
  PSCSIWMI_SET_DATABLOCK  SetWmiDataBlock;
  PSCSIWMI_SET_DATAITEM  SetWmiDataItem;
  PSCSIWMI_EXECUTE_METHOD  ExecuteWmiMethod;
  PSCSIWMI_FUNCTION_CONTROL  WmiFunctionControl;
} SCSI_WMILIB_CONTEXT, *PSCSI_WMILIB_CONTEXT;

Members

GuidCount
Specifies the number of structures in the SCSIWMIGUIDREGINFO array at GuidList.
GuidList
Points to an array of GuidCount SCSIWMIGUIDREGINFO structures that contain registration information for each block.
QueryWmiRegInfo
Points to the driver's HwScsiWmiQueryReginfo routine, which is a required entry point for miniport drivers that support WMI.
QueryWmiDataBlock
Points to the driver's HwScsiWmiQueryDataBlock routine, which is a required entry point for miniport drivers that support WMI.
SetWmiDataBlock
Points to the driver's HwScsiWmiSetDataBlock routine, which is an optional entry point for miniport drivers that support WMI. If the miniport does not implement this routine, it must set this member to NULL
SetWmiDataItem
Points to the driver's HwScsiWmiSetDataItem routine, which is an optional entry point for miniport drivers that support WMI. If the miniport does not implement this routine, it must set this member to NULL.
ExecuteWmiMethod
Points to the driver's HwScsiWmiExecuteMethod routine, which is an optional entry point for miniport drivers that support WMI. If the miniport does not implement this routine, it must set this member to NULL
WmiFunctionControl
Points to the driver's HwScsiWmiFunctionControl routine, which is an optional entry point for miniport drivers that support WMI. If the miniport does not implement this routine, it must set this member to NULL.

Headers

Declared in scsiwmi.h. Include scsiwmi.h.

Comments

A SCSI miniport driver that supports WMI stores an initialized SCSI_WMILIB_CONTEXT structure (or a pointer to such a structure) in its device extension. A miniport can use the same SCSI_WMILIB_CONTEXT structure for multiple device objects if each device object supplies the same set of data blocks.

When the miniport receives an SRB in which the Function member is set to SRB_FUNCTION_WMI, it calls ScsiPortWmiDispatchFunction with request parameters, including a pointer to an initialized SCSI_WMILIB_CONTEXT structure. ScsiPortWmiDispatchFunction handles the request by calling the miniport's appropriate HwScsiWmiXxx routine.

If the miniport does not implement an optional HwScsiWmiXxx routine, the port driver returns an appropriate status to the caller.

See Also

HwScsiWmiExecuteMethod, HwScsiWmiFunctionControl, HwScsiWmiQueryReginfo, HwScsiWmiQueryDataBlock, HwScsiWmiSetDataBlock, HwScsiWmiSetDataItem, ScsiPortWmiDispatchFunction, SCSIWMIGUIDREGINFO


SCSI_WMI_REQUEST_BLOCK

This structure is a special version of a SCSI_REQUEST_BLOCK for use with WMI commands.

typedef struct _SCSI_WMI_REQUEST_BLOCK {
  USHORT  Length;
  UCHAR  Function;
  UCHAR  SrbStatus;
  UCHAR  WMISubFunction;
  UCHAR  PathId;
  UCHAR  TargetId;
  UCHAR  Lun;
  UCHAR  Reserved1;
  UCHAR  WMIFlags;
  UCHAR  Reserved2[2];
  ULONG  SrbFlags;
  ULONG  DataTransferLength;
  ULONG  TimeOutValue;
  PVOID  DataBuffer;
  PVOID  DataPath;
  PVOID  Reserved3;
  PVOID  OriginalRequest;
  PVOID  SrbExtension;
  ULONG  Reserved4;
  UCHAR  Reserved5[16];
} SCSI_WMI_REQUEST_BLOCK, *PSCSI_WMI_REQUEST_BLOCK;

Members

Length
Specifies the size in bytes of this structure.
Function
SRB_FUNCTION_WMI, which specifies that the request is a WMI request. If this member is not set to SRB_FUNCTION_WMI, the miniport should fail the request.
SrbStatus
Returns the status of the completed request. This member should be set by the miniport driver before it notifies the OS-specific driver that the request has completed by calling ScsiPortNotification with RequestComplete. The value of this member can be any value listed for SrbStatus in SCSI_REQUEST_BLOCK.
WMISubFunction
Indicates the WMI action to be performed. A miniport calls ScsiPortWmiDispatchFunction with MinorParameter set to this value.
PathId
Indicates the SCSI port or bus for the request. This value is zero-based. If SRB_WMI_FLAGS_ADAPTER_REQUEST is set in WMIFlags, this member is reserved.
TargetId
Indicates the target controller or device on the bus. If SRB_WMI_FLAGS_ADAPTER_REQUEST is set in WMIFlags, this member is reserved.
Lun
Indicates the logical unit number of the device. If SRB_WMI_FLAGS_ADAPTER_REQUEST is set in WMIFlags, this member is reserved.
Reserved1
Reserved for system use and not available for use by miniport drivers.
WMIFlags
If SRB_WMI_FLAGS_ADAPTER_REQUEST is set then the WMI request is for the adapter and PathId, TargetId, and Lun are reserved. Otherwise, WMIFlags will be NULL, indicating that the request is for the device specified by PathId, TargetId, and Lun.
Reserved2
Reserved for system use and not available for use by miniport drivers.
SrbFlags
Indicates various parameters and options about the request. SrbFlags is read-only. This member will be set to one or more of the following flags ORed together:
Value Meaning
SRB_FLAGS_DATA_IN
Indicates data will be transferred from the device to the system.
SRB_FLAGS_DATA_OUT
Indicates data will be transferred from the system to the device.
SRB_FLAGS_NO_DATA_TRANSFER
Indicates no data transfer with this request. If this is set, the flags SRB_FLAGS_DATA_OUT, SRB_FLAGS_DATA_IN, and SRB_FLAGS_UNSPECIFIED_DIRECTION are clear.
SRB_FLAGS_DISABLE_SYNCH_TRANSFER
Indicates the HBA, if possible, should perform asynchronous I/O for this transfer request. If synchronous I/O was negotiated previously, the HBA must renegotiate for asynchronous I/O before performing the transfer.
SRB_FLAGS_DISABLE_DISCONNECT
Indicates the HBA should not allow the target to disconnect from the SCSI bus during processing of this request.

DataTransferLength
Indicates the size in bytes of the data buffer. A miniport calls ScsiPortWmiDispatchFunction with BufferSize set to this value. If an underrun occurs, the miniport must update this member to the number of bytes actually transferred.
TimeOutValue
Indicates the interval in seconds that the request can execute before the OS-specific port driver might consider it timed out. Miniport drivers are not required to time requests because the port driver already does.
DataBuffer
Points to the data buffer. A miniport calls ScsiPortWmiDispatchFunction with Buffer set to this value. Miniport drivers can use this value as a data pointer regardless of the value of MapBuffers in the PORT_CONFIGURATION_INFORMATION for the HBA. A miniport driver cannot transfer data directly into the buffer using DMA.
DataPath
Specifies the WMI data path for this request. A miniport driver calls ScsiPortWmiDispatchFunction with DataPath set to this value.
Reserved3
Reserved for system use and not available for use by miniport drivers.
OriginalRequest
Points to the IRP for this request. This member is irrelevant to miniport drivers.
SrbExtension
Points to the Srb extension. A miniport must not use this member if it set SrbExtensionSize to zero in the HW_INITIALIZATION_DATA. The memory at SrbExtension is not initialized by the OS-specific port driver, and the miniport-determined data can be accessed directly by the HBA. The corresponding physical address can be obtained by calling ScsiPortGetPhysicalAddress with the SrbExtension pointer.
Reserved4
Reserved for system use and not available for use by miniport drivers.
Reserved5
Reserved for system use and not available for use by miniport drivers.

Headers

Declared in scsiwmi.h. Include scsiwmi.h.

Comments

Windows NT storage class and filter drivers can send WMI SRBs to the system port driver. The system port driver will handle certain WMI requests on behalf of miniport drivers. If the port driver cannot handle a WMI request, it forwards the request to the miniport driver.

A miniport receives WMI requests from the port driver only if the miniport set WmiDataProvider in the PORT_CONFIGURATION_INFORMATION structure. If the miniport supports a request, it should process it and complete the request by calling ScsiPortNotification twice, first with RequestComplete and then with NextRequest (or NextLuRequest).

For information about supporting WMI in miniport drivers, see the Windows Management Instrumentation.

See Also

HW_INITIALIZATION_DATA, PORT_CONFIGURATION_INFORMATION, SCSI_REQUEST_BLOCK, ScsiPortNotification, ScsiPortWmiDispatchFunction


SCSIWMI_REQUEST_CONTEXT

A SCSIWMI_REQUEST_CONTEXT structure contains context information for a WMI SRB.

typedef struct {
  PVOID  UserContext;
  ULONG  BufferSize;
  PUCHAR  Buffer;
  UCHAR  MinorFunction;
  UCHAR  ReturnStatus;
  ULONG  ReturnSize;
} SCSIWMI_REQUEST_CONTEXT, *PSCSIWMI_REQUEST_CONTEXT;

Members

UserContext
Points to a miniport buffer that contains any data the miniport requires to process the SRB. This can be a pointer to the miniport's HW_DEVICE_EXTENSION structure or some other buffer.
BufferSize
Reserved for system use and not available for use by miniport drivers.
Buffer
Reserved for system use and not available for use by miniport drivers.
MinorFunction
Reserved for system use and not available for use by miniport drivers.
ReturnStatus
Indicates the return status of the SRB. This member is not valid until after the miniport has called ScsiPortWmiPostProcess to update the request context.
ReturnSize
Indicates the number of bytes of data transferred for the SRB. This member is not valid until after the miniport has called ScsiPortWmiPostProcess to update the request context.

Headers

Declared in scsiwmi.h. Include scsiwmi.h.

Comments

When the miniport receives an SRB in which the Function member is set to SRB_FUNCTION_WMI, it calls ScsiPortWmiDispatchFunction with request parameters, including a pointer to a request context. ScsiPortWmiDispatchFunction passes the request context to the miniport's appropriate HwScsiWmiXxx routine.

When the miniport is done processing the SRB and prior to completing the SRB, the miniport should call ScsiPortWmiPostProcess to update the ReturnStatus and ReturnSize members of the request context. The miniport updates the SRB's data transfer length and status to these values by calling ScsiPortWmiGetReturnSize and ScsiPortWmiGetReturnStatus. respectively.

A request context must remain valid throughout the processing of an SRB. If the SRB can pend, the miniport must allocate the SCSIWMI_REQUEST_CONTEXT structure from the SRB extension so it remains valid until the SRB completes. For non-pending SRBs the structure can be allocated from a stack frame that does not go out of scope.

See Also

ScsiPortWmiDispatchFunction, ScsiPortWmiGetReturnSize, ScsiPortWmiGetReturnStatus, ScsiPortWmiPostProcess


SET_PARTITION_INFORMATION

SET_PARTITION_INFORMATION is used with IOCTL_DISK_SET_PARTITION_INFO to change the partition type of a specified Master Boot Record (MBR) disk partition.

typedef struct _SET_PARTITION_INFORMATION {
  UCHAR  PartitionType;
} SET_PARTITION_INFORMATION, *PSET_PARTITION_INFORMATION;

Members

PartitionType
IOCTL_DISK_SET_PARTITION_INFO sets the partition type to the value contained in this member. See PARTITION_INFORMATION for a list of system-defined GPT partition types.

Headers

Declared in ntdddisk.h. Include ntdddisk.h.

Comments

The single byte unsigned value, PartitionType, contained in this structure defines a traditional AT Master Boot Record style of partition and can not be used to define an Extensible Firmware Interface partition (also known as a GUID Partition Table partition). GPT partitions use a GUID to indicate the partition type.

See Also

SET_PARTITION_INFORMATION_EX, SET_PARTITION_INFORMATION_MBR, SET_PARTITION_INFORMATION_GPT, IOCTL_DISK_SET_PARTITION_INFO, IoReadPartitionTable


SET_PARTITION_INFORMATION_EX

SET_PARTITION_INFORMATION_EX is used with the IOCTL IOCTL_DISK_SET_PARTITION_INFO_EX to set information about a specific partition.

typedef struct _SET_PARTITION_INFORMATION_EX {
  PARTITION_STYLE  PartitionStyle;
  union {
    SET_PARTITION_INFORMATION_MBR  Mbr;
    SET_PARTITION_INFORMATION_GPT  Gpt;
  };
} SET_PARTITION_INFORMATION_EX, *PSET_PARTITION_INFORMATION_EX;

Members

PartitionStyle
Takes a PARTITION_STYLE enumerated value that specifies the type of partition table that contains the partition.
Mbr
Contains the information for a Master Boot Record partition that is not held in common with a GUID Partition Table partition. This member is valid when PartitionStyle member is set to PARTITION_STYLE_MBR. For a definition of this structure, see SET_PARTITION_INFORMATION_MBR.
Gpt
Contains the information for a GUID Partition Table partition that is not held in common with a Master Boot Record partition. This member is valid when PartitionStyle member is set to PARTITION_STYLE_GPT. For a definition of this structure, see SET_PARTITION_INFORMATION_GPT.

Headers

Declared in ntdddisk.h. Include ntdddisk.h.

Comments

In the case of GPT partitions, any value that can be retrieved from the partition can also be set. In the MBR case, only the partition signature can be set.

See Also

SET_PARTITION_INFORMATION_MBR, SET_PARTITION_INFORMATION_GPT, IOCTL_DISK_SET_PARTITION_INFO_EX


SET_PARTITION_INFORMATION_GPT

The SET_PARTITION_INFORMATION_GPT structure defines the information in a GPT partition that is not common to both GPT and MBR partitions.

typedef PARTITION_INFORMATION_GPT SET_PARTITION_INFORMATION_MBR;

Headers

Declared in ntddk.h and ntdddisk.h. Include ntddk.h or ntdddisk.h.

Comments

This structure is actually equivalent to the structure PARTITION_INFORMATION_GPT.

See Also

PARTITION_INFORMATION_GPT, SET_PARTITION_INFORMATION_MBR, IOCTL_DISK_SET_PARTITION_INFO_EX


SET_PARTITION_INFORMATION_MBR

The SET_PARTITION_INFORMATION_MBR structure defines the information in a Master Boot Record (MBR) partition that is not common to both GUID Table Partition (GPT) and MBR partitions.

typedef SET_PARTITION_INFORMATION SET_PARTITION_INFORMATION_MBR;

Headers

Declared in ntddk.h and ntdddisk.h. Include ntddk.h or ntdddisk.h.

Comments

The SET_PARTITION_INFORMATION_MBR structure is actually equivalent to the SET_PARTITION_INFORMATION structure.

Headers

Declared in ntddk.h and ntdddisk.h. Include ntddk.h or ntdddisk.h.

See Also

SET_PARTITION_INFORMATION, SET_PARTITION_INFORMATION_EX, IOCTL_DISK_SET_PARTITION_INFO_EX


SRB_IO_CONTROL

typedef struct _SRB_IO_CONTROL {
  ULONG  HeaderLength;
  UCHAR  Signature[8];
  ULONG  Timeout;
  ULONG  ControlCode;
  ULONG  ReturnCode;
  ULONG  Length;
} SRB_IO_CONTROL, *PSRB_IO_CONTROL;

Members

HeaderLength
Is sizeof(SRB_IO_CONTROL).
Signature
Identifies the application-dedicated, target HBA for this request. This signature is used to prevent conflicts in ControlCode values between vendors. It should be a string of ASCII characters. If a miniport driver does not recognize the input Signature value, it must complete the request with a status of SRB_STATUS_INVALID_REQUEST.
Timeout
Indicates the interval in seconds that the request can execute before the OS-specific port driver might consider it timed out. Miniport drivers are not required to time requests because the port driver does.
ControlCode
Indicates the operation to be performed. There are no system-defined operations. Values must be defined by the driver as a set of private I/O control codes with which the application can make requests by calling the Win32® DeviceIoControl function. For more information about defining private I/O control codes for device control requests, see also IRP Function Codes and IOCTLs.
ReturnCode
Returns a status code for examination by the requesting application.
Length
Indicates the size in bytes of the immediately following data area. This area can be divided for the particular operation into input and output areas. For input requests, the contents of the DataBuffer will be copied to the requester up to the returned value of DataTransferLength.

Headers

Declared in ntddscsi.h. Include ntddscsi.h.

Comments

This structure is used by applications to send requests directly to an application-dedicated HBA. Note that such an application also must set up requests to program its dedicated HBA.

See Also

IOCTL_SCSI_PASS_THROUGH, IOCTL_SCSI_PASS_THROUGH_DIRECT, SCSI_REQUEST_BLOCK


STORAGE_ADAPTER_DESCRIPTOR

The STORAGE_ADAPTER_DESCRIPTOR structure is used in conjunction with the IOCTL_STORAGE_QUERY_PROPERTY request to retrieve the storage adapter descriptor data for a device.

typedef struct _STORAGE_ADAPTER_DESCRIPTOR {
  ULONG  Version;
  ULONG  Size;
  ULONG  MaximumTransferLength;
  ULONG  MaximumPhysicalPages;
  ULONG  AlignmentMask;
  BOOLEAN  AdapterUsesPio;
  BOOLEAN  AdapterScansDown;
  BOOLEAN  CommandQueueing;
  BOOLEAN  AcceleratedTransfer;
  STORAGE_BUS_TYPE  BusType;
  USHORT  BusMajorVersion;
  USHORT  BusMinorVersion;
} STORAGE_ADAPTER_DESCRIPTOR, *PSTORAGE_ADAPTER_DESCRIPTOR;

Members

Version
Is sizeof(STORAGE_ADAPTER_DESCRIPTOR). The value of this member will change as members are added to the structure.
Size
Specifies the total size of the descriptor in bytes.
MaximumTransferLength
Specifies the maximum number of bytes the HBA can transfer in a single operation.
MaximumPhysicalPages
Specifies the maximum number of discontiguous physical pages the HBA can manage in a single transfer (i.e., the extent of its scatter/gather support).
AlignmentMask
Specifies the HBA's alignment requirements for transfers. A storage class driver sets the AlignmentRequirement field in its device objects to this value.
AdapterUsesPio
TRUE if the HBA uses PIO and requires the use of system-space virtual addresses mapped to physical memory for data buffers.
AdapterScansDown
TRUE if the HBA scans down for BIOS devices, that is, the HBA begins scanning with the highest device number rather than the lowest. This member is reserved for legacy miniports.
CommandQueueing
TRUE if the HBA supports SCSI-2 tagged queuing and/or per-logical-unit internal queues, or the nonSCSI equivalent.
AcceleratedTransfer
TRUE if the HBA supports synchronous transfers as a way of speeding up I/O.
BusType
Specifies the type of bus to which the device is connected. BusType can be one of the following: BusTypeScsi, BusTypeAtapi, BusTypeAta, BusType1394, BusTypeSsa, BusTypeFibre, BusTypeUsb, or BusTypeUnknown for a type of bus not listed.
BusMajorVersion
Specifies the major version number, if any, of the HBA.
BusMinorVersion
Specifies the minor version number, if any, of the HBA.

Headers

Declared in ntddstor.h. Include ntddstor.h.

Comments

Storage class drivers issue a device-control request with the I/O control code IOCTL_STORAGE_QUERY_PROPERTY to retrieve this structure, which contains configuration information from the HBA for data transfer operations. The structure can be retrieved either from the device object for the bus or from an FDO, which forwards the request to the underlying bus.

If excessive protocol errors occur on an HBA that supports synchronous transfers (AcceleratedTransfer is TRUE), the storage class driver can disable synchronous transfers by setting SRB_FLAGS_DISABLE_SYNCH_TRANSFER in SRBs.

See Also

IoBuildDeviceIoControlRequest, STORAGE_DEVICE_DESCRIPTOR, IOCTL_STORAGE_QUERY_PROPERTY, STORAGE_DESCRIPTOR_HEADER, STORAGE_DEVICE_ID_DESCRIPTOR, STORAGE_ADAPTER_DESCRIPTOR


STORAGE_BUS_RESET_REQUEST

The STORAGE_BUS_RESET_REQUEST structure is used in conjunction with the IOCTL_STORAGE_RESET_BUS request to specify the path of the bus to be reset.

typedef struct _STORAGE_BUS_RESET_REQUEST {
  UCHAR  PathId;
} STORAGE_BUS_RESET_REQUEST, *PSTORAGE_BUS_RESET_REQUEST;

Members

PathId
Path of the bus to be reset.

Headers

Declared in ntddstor.h. Include ntddstor.h.

See Also

IOCTL_STORAGE_RESET_BUS


STORAGE_DESCRIPTOR_HEADER

The STORAGE_DESCRIPTOR_HEADER structure is used in conjunction with the IOCTL_STORAGE_QUERY_PROPERTY request to retrieve the properties of a storage device or adapter.

typedef struct _STORAGE_DESCRIPTOR_HEADER {
  ULONG  Version;
  ULONG  Size;
} STORAGE_DESCRIPTOR_HEADER, *PSTORAGE_DESCRIPTOR_HEADER;

Members

Version
Version of the data reported.
Size
Quantity of data reported, in bytes.

Headers

Declared ntddstor.h. Include ntddstor.h.

Comments

The data retrieved by IOCTL_STORAGE_QUERY_PROPERTY is reported in the buffer immediately following this structure.

The IOCTL_STORAGE_QUERY_PROPERTY request reports one of three types of properties: a device descriptor, an adapter descriptor, or a set of device IDs taken from the device's SCSI-2 vital product data pages. Device descriptors are reported in a structure of type STORAGE_DEVICE_DESCRIPTOR. Adapter descriptors are reported in a structure of type STORAGE_ADAPTER_DESCRIPTOR. Vital product page device IDs are reported in a structure of type STORAGE_DEVICE_ID_DESCRIPTOR.

See Also

IOCTL_STORAGE_QUERY_PROPERTY, STORAGE_PROPERTY_QUERY


STORAGE_DEVICE_DESCRIPTOR

The STORAGE_DEVICE_DESCRIPTOR structure is used in conjunction with the IOCTL_STORAGE_QUERY_PROPERTY request to retrieve the storage device descriptor data for a device.

typedef struct _STORAGE_DEVICE_DESCRIPTOR {
  ULONG  Version;
  ULONG  Size;
  UCHAR  DeviceType;
  UCHAR  DeviceTypeModifier;
  BOOLEAN  RemovableMedia;
  BOOLEAN  CommandQueueing;
  ULONG  VendorIdOffset;
  ULONG  ProductIdOffset;
  ULONG  ProductRevisionOffset;
  ULONG  SerialNumberOffset;
..STORAGE_BUS_TYPE  BusType;
..ULONG  RawPropertiesLength;
..UCHAR  RawDeviceProperties[1];
} STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR;

Members

Version
Is sizeof(STORAGE_DEVICE_DESCRIPTOR). The value of this member will change as members are added to the structure.
Size
Specifies the total size of the descriptor in bytes, including ID strings which are appended to the structure.
DeviceType
Specifies the device type as defined by SCSI-2.
DeviceTypeModifier
Specifies the device type modifier, if any, as defined by SCSI-2. If no device type modifier exists, this member is zero.
RemovableMedia
TRUE if the device's media (if any) is removable. If the device has no media, this member should be ignored.
CommandQueueing
TRUE if the device supports multiple outstanding commands (SCSI-2 tagged queuing or equivalent). The storage port driver is responsible for synchronizing the commands.
VendorIdOffset
Specifies the byte offset from the beginning of the structure to a NUL-terminated ASCII string that contains the device's vendor ID. If the device has no vendor ID, this member is zero.
ProductIdOffset
Specifies the byte offset from the beginning of the structure to a NUL-terminated ASCII string that contains the device's product ID. If the device has no product ID, this member is zero.
ProductRevisionOffset
Specifies the byte offset from the beginning of the structure to a NUL-terminated ASCII string that contains the device's product revision string. If the device has no product revision string, this member is zero.
SerialNumberOffset
Specifies the byte offset from the beginning of the structure to a NUL-terminated ASCII string that contains the device's serial number. If the device has no serial number, this member is zero.
BusType
Specifies the type of bus to which the device is connected. BusType can be one of the following: BusTypeScsi, BusTypeAtapi, BusTypeAta, BusType1394, BusTypeSsa, BusTypeFibre, BusTypeUsb, or BusTypeUnknown for a type of bus not listed. This should be used to interpret the raw device properties at the end of this structure (if any).
RawPropertiesLength
The number of bytes of bus-specific data that have been appended to this descriptor.
RawDeviceProperties
Place holder for the first byte of the bus specific property data.

Headers

Declared in ntddstor.h. Include ntddstor.h.

Comments

Applications and storage class drivers issue a device-control request with the I/O control code IOCTL_STORAGE_QUERY_PROPERTY to retrieve this structure, which contains information about a target device. The structure can be retrieved only from an FDO; attempting to retrieve device properties from an adapter causes an error.

An application or driver can determine the required buffer size by casting the retrieved STORAGE_DEVICE_DESCRIPTOR structure to a STORAGE_DESCRIPTOR_HEADER, which contains only Version and Size.

See Also

IoBuildDeviceIoControlRequest, STORAGE_ADAPTER_DESCRIPTOR, IOCTL_STORAGE_QUERY_PROPERTY, STORAGE_DESCRIPTOR_HEADER, STORAGE_DEVICE_DESCRIPTOR, STORAGE_DEVICE_ID_DESCRIPTOR


STORAGE_DEVICE_ID_DESCRIPTOR

The STORAGE_DEVICE_ID_DESCRIPTOR structure is used in conjunction with the IOCTL_STORAGE_QUERY_PROPERTY request to retrieve the device ID descriptor data for a device.

typedef struct _STORAGE_DEVICE_ID_DESCRIPTOR {
  ULONG  Version;
  ULONG  Size;
  ULONG  NumberOfIdentifiers;
  UCHAR  Identifiers[1];
} STORAGE_DEVICE_ID_DESCRIPTOR, *PSTORAGE_DEVICE_ID_DESCRIPTOR;

Members

Version
The version of the descriptor.
Size
The size of the descriptor.
NumberOfIdentifiers
The number of identifiers reported by the device.
Identifiers
A variable-length array of identification descriptors.

Headers

Declared in ntddstor.h. Include ntddstor.h.

Comments

The device descriptor consists of an array of device IDs taken from the SCSI-2 vital product page data that was retrieved during discovery.

See Also

IOCTL_STORAGE_QUERY_PROPERTY, STORAGE_DESCRIPTOR_HEADER, STORAGE_DEVICE_DESCRIPTOR, STORAGE_ADAPTER_DESCRIPTOR


STORAGE_DEVICE_NUMBER

The STORAGE_DEVICE_NUMBER structure is used in conjunction with the IOCTL_STORAGE_GET_DEVICE_NUMBER request to retrieve the FILE_DEVICE_XXX device type, the device number, and, for a device that can be partitioned, the partition number assigned to a device by the driver when the device is started.

typedef struct _STORAGE_DEVICE_NUMBER {
  DEVICE_TYPE  DeviceType;
  ULONG  DeviceNumber;
  ULONG  PartitionNumber;
} STORAGE_DEVICE_NUMBER, *PSTORAGE_DEVICE_NUMBER;

Members

DeviceType
Specifies one of the system-defined FILE_DEVICE_XXX constants indicating the type of device (such as FILE_DEVICE_DISK, FILE_DEVICE_KEYBOARD, and so forth) or a vendor-defined value for a new type of device. For more information, see Specifying Device Types.
DeviceNumber
The number of this device.
PartitionNumber
If the device can be partitioned, the partition number of the device is returned in this member. Otherwise, -1 is returned.

Headers

Declared in ntddstor.h. Include ntddstor.h.

Comments

The IOCTL_STORAGE_GET_DEVICE_NUMBER request is usually issued by a fault-tolerant disk driver.

The values in the STORAGE_DEVICE_NUMBER structure are guaranteed to remain unchanged until the system is rebooted. They are not guaranteed to be persistent across boots.

See Also

IOCTL_STORAGE_GET_DEVICE_NUMBER


STORAGE_PREDICT_FAILURE

The STORAGE_PREDICT_FAILURE structure is used in conjunction with IOCTL_STORAGE_PREDICT_FAILURE to report whether a device supports failure prediction technology, such as IDE self-monitoring analysis and reporting technology (SMART).

typedef struct _STORAGE_PREDICT_FAILURE {
  ULONG  PredictFailure;
  UCHAR  VendorSpecific[512];
} STORAGE_PREDICT_FAILURE, *PSTORAGE_PREDICT_FAILURE;

Members

PredictFailure
If this member is nonzero, the device supports failure prediction.
VendorSpecific
If the device supports failure prediction, this field will contain 512 bytes of vendor-specific information.

Headers

Declared in ntddstor.h. Include ntddstor.h.

Comments

Upon receiving an IOCTL_STORAGE_PREDICT_FAILURE device control request, the disk class driver attempts to verify if an IDE drive supports SMART. If the drive is a SCSI drive, the class driver attempts to verify if the SCSI disk supports the equivalent IDE SMART technology: Information Exception Control Page, X3T10/94-190 Rev 4.

The disk class driver returns the results of this test in a STORAGE_PREDICT_FAILURE structure.

See Also

IOCTL_STORAGE_PREDICT_FAILURE


STORAGE_PROPERTY_ID

The STORAGE_PROPERTY_ID enumerator values are used in conjunction with the IOCTL_STORAGE_QUERY_PROPERTY request to retrieve the properties of a storage device or adapter.

typedef enum _STORAGE_PROPERTY_ID {
  StorageDeviceProperty = 0,
  StorageAdapterProperty,
  StorageDeviceIdProperty
} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID;

Enumerators

StorageDeviceProperty
Indicates that the caller is querying for the device descriptor.
StorageAdapterProperty
Indicates that the caller is querying for the adapter descriptor.
StorageDeviceIdProperty
Indicates that the caller is querying for the device identifiers provided with the SCSI-2 vital product data pages.

Headers

Declared ntddstor.h. Include ntddstor.h.

Comments

Enumerators indicate which properties the caller is querying for.

Caller defines the exact nature of an IOCTL_STORAGE_QUERY_PROPERTY request by specifying the query type together with the property ID. See STORAGE_PROPERTY_QUERY for an explanation of how these two values are combined to define the query.

See Also

IOCTL_STORAGE_QUERY_PROPERTY, STORAGE_PROPERTY_QUERY, STORAGE_QUERY_TYPE


STORAGE_PROPERTY_QUERY

The STORAGE_PROPERTY_QUERY structure is used in conjunction with the IOCTL_STORAGE_QUERY_PROPERTY request to retrieve the properties of a storage device or adapter.

typedef struct _STORAGE_PROPERTY_QUERY {
  STORAGE_PROPERTY_ID  PropertyId;
  STORAGE_QUERY_TYPE  QueryType;
  UCHAR  AdditionalParameters[1];
} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY;

Members

PropertyId
Indicates whether the caller is requesting a device descriptor, an adapter descriptor, or the device identifiers provided in the device's SCSI-2 vital product data page. For a list of the property IDs that can be assigned to this member, see STORAGE_PROPERTY_ID.
QueryType
Flags indicating the type of query to be performed. For a list of the various query types that can be assigned to this member, see STORAGE_QUERY_TYPE.
AdditionalParameters
Space that can be used whenever needed for additional parameters for specific queries.

Headers

Declared in ntddstor.h. Include ntddstor.h.

Comments

STORAGE_PROPERTY_QUERY indicates the sort of query that the caller is requesting.

A caller that passes this structure as input with IOCTL_STORAGE_QUERY_PROPERTY can request a device descriptor, defined by the STORAGE_DEVICE_DESCRIPTOR structure by specifying a query of type PropertyStandardQuery and a property ID of type StorageDeviceProperty. The caller can request an adapter descriptor, defined by the STORAGE_ADAPTER_DESCRIPTOR structure by specifying a query of type PropertyStandardQuery and a property ID of type StorageAdapterProperty. The caller can test to see if a certain property ID is supported by specifying a query of type PropertyExistsQuery instead of PropertyStandardQuery.

See Also

IOCTL_STORAGE_QUERY_PROPERTY, STORAGE_DESCRIPTOR_HEADER, STORAGE_QUERY_TYPE, STORAGE_DEVICE_DESCRIPTOR, STORAGE_ADAPTER_DESCRIPTOR, STORAGE_PROPERTY_ID


STORAGE_QUERY_TYPE

The STORAGE_QUERY_TYPE enumeration type is used in conjunction with the IOCTL_STORAGE_QUERY_PROPERTY request to retrieve the properties of a storage device or adapter.

typedef enum _STORAGE_QUERY_TYPE {
  PropertyStandardQuery = 0,
  PropertyExistsQuery,
  PropertyMaskQuery,
  PropertyQueryMaxDefined
} STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE;

Enumerators

PropertyStandardQuery
Retrieves a device or adapter descriptor.
PropertyExistsQuery
Used to test whether the descriptor is supported.
PropertyMaskQuery
Not currently supported. Do not use.
PropertyQueryMaxDefined
Used to validate the value. Currently this is not supported.

Headers

Declared in ntddstor.h. Include ntddstor.h.

Comments

Caller specifies the type of query by choosing one of the enumerators.

Caller defines the exact nature of a IOCTL_STORAGE_QUERY_PROPERTY request by specifying the query type together with the property ID. See STORAGE_PROPERTY_QUERY for an explanation of how these two values are combined to define the query.

See Also

IOCTL_STORAGE_QUERY_PROPERTY, STORAGE_PROPERTY_QUERY, STORAGE_PROPERTY_ID


SUB_Q_CHANNEL_DATA

Device control IRPs with a control code of IOCTL_CDROM_READ_Q_CHANNEL return their output data in this union.

typedef union _SUB_Q_CHANNEL_DATA {
  SUB_Q_CURRENT_POSITION  CurrentPosition;
  SUB_Q_MEDIA_CATALOG_NUMBER  MediaCatalog;
  SUB_Q_TRACK_ISRC  TrackIsrc;
} SUB_Q_CHANNEL_DATA, *PSUB_Q_CHANNEL_DATA;

Members

CurrentPosition
Contains position information, such as the absolute and relative addresses.
MediaCatalog
Contains the media catalog number.
TrackIsrc
Contains the TrackIsrc code.

Headers

Declared in ntddcdrm.h. Include ntddcdrm.h.

Comments

The value of the Format member of the CDROM_SUB_Q_DATA_FORMAT structure that is passed as input with IOCTL_CDROM_READ_Q_CHANNEL determines which member of this union is used to return the output data. See CDROM_SUB_Q_DATA_FORMAT for a detailed explanation.

See Also

IOCTL_CDROM_READ_Q_CHANNEL, CDROM_SUB_Q_DATA_FORMAT


SUB_Q_CURRENT_POSITION

The SUB_Q_CURRENT_POSITION structure contains position information and is used in conjunction with SUB_Q_CHANNEL_DATA .

typedef struct _SUB_Q_CURRENT_POSITION {
  SUB_Q_HEADER  Header;
  UCHAR  FormatCode;
  UCHAR  Control : 4;
  UCHAR  ADR : 4;
  UCHAR  TrackNumber;
  UCHAR  IndexNumber;
  UCHAR  AbsoluteAddress[4];
  UCHAR  TrackRelativeAddress[4];
} SUB_Q_CURRENT_POSITION, *PSUB_Q_CURRENT_POSITION;

Members

Header
Indicates, among other things, the length of the Q subchannel data that was retrieved. See SUB_Q_HEADER for more details.
FormatCode
This member should have a value of IOCTL_CDROM_CURRENT_POSITION.
Control
Defines various types of information within the table of contents lead-in area. For more information on the permissible values for this member, see specification T10/1363-D Revision-02A, by National Committee for Information Technology Standards (NCITS).
ADR
Indicates the type of information encoded in the Q subchannel of the block. For information on the permissible values for this member, see specification T10/1363-D Revision-02A, by National Committee for Information Technology Standards (NCITS).
TrackNumber
Contains the current track number.
IndexNumber
Contains the current index number.
AbsoluteAddress
Gives the current location relative to the logical beginning of the media.
TrackRelativeAddress
Gives the current location relative to the logical beginning of the current track.

Headers

Declared in ntddcdrm.h. Include ntddcdrm.h.

See Also

IOCTL_CDROM_READ_Q_CHANNEL, CDROM_SUB_Q_DATA_FORMAT, SUB_Q_CHANNEL_DATA


SUB_Q_HEADER

The SUB_Q_HEADER structure contains audio status information and the length of the Q subchannel data being returned. This structure is used in conjunction with SUB_Q_CHANNEL_DATA.

typedef struct _SUB_Q_HEADER {
  UCHAR  Reserved;
  UCHAR  AudioStatus;
  UCHAR  DataLength[2];
} SUB_Q_HEADER, *PSUB_Q_HEADER;

Members

Reserved
Reserved.
AudioStatus
Reports the audio status as follows:
Value Meaning
AUDIO_STATUS_NOT_SUPPORTED
Audio status byte not supported or not valid.
AUDIO_STATUS_IN_PROGRESS
Audio play operation is in progress.
AUDIO_STATUS_PAUSED
Audio play operation is paused.
AUDIO_STATUS_PLAY_COMPLETE
Audio play operation completed successfully.
AUDIO_STATUS_PLAY_ERROR
Audio play operation stopped due to error.
AUDIO_STATUS_NO_STATUS
No current audio status to return.

DataLength
Length of Q subchannel data that follows this header structure.

Headers

Declared in ntddcdrm.h. Include ntddcdrm.h.

See Also

IOCTL_CDROM_READ_Q_CHANNEL, CDROM_SUB_Q_DATA_FORMAT, SUB_Q_CHANNEL_DATA


SUB_Q_MEDIA_CATALOG_NUMBER

The SUB_Q_MEDIA_CATALOG_NUMBER structure contains position information and is used in conjunction with the SUB_Q_CHANNEL_DATA structure.

typedef struct _SUB_Q_MEDIA_CATALOG_NUMBER {
  SUB_Q_HEADER  Header;
  UCHAR  FormatCode;
  UCHAR  Reserved[3];
  UCHAR  Reserved1 : 7;
  UCHAR  Mcval :1;
  UCHAR  MediaCatalog[15];
} SUB_Q_MEDIA_CATALOG_NUMBER, *PSUB_Q_MEDIA_CATALOG_NUMBER;

Members

Header
Indicates, among other things, the length of the Q subchannel data that was retrieved. See SUB_Q_HEADER for further details.
FormatCode
This member should have a value of IOCTL_CDROM_MEDIA_CATALOG.
Reserved
Reserved
Reserved1
Reserved
Mcval
Set to one if media catalog number (MCN) data is valid; set to zero otherwise.
MediaCatalog
Contains the catalog number if Mcval is set to one.

Headers

Declared in ntddcdrm.h. Include ntddcdrm.h.

See Also

IOCTL_CDROM_READ_Q_CHANNEL, CDROM_SUB_Q_DATA_FORMAT, SUB_Q_CHANNEL_DATA


SUB_Q_TRACK_ISRC

The SUB_Q_TRACK_ISC contains position information and is used in conjunction with the SUB_Q_CHANNEL_DATA structure.

typedef struct _SUB_Q_TRACK_ISRC {
  SUB_Q_HEADER  Header;
  UCHAR  FormatCode;
  UCHAR  Reserved0;
  UCHAR  Track;
  UCHAR  Reserved1;
  UCHAR  Reserved2 : 7;
  UCHAR  Tcval : 1;
  UCHAR  TrackIsrc[15];
} SUB_Q_TRACK_ISRC, *PSUB_Q_TRACK_ISRC;

Members

Header
Indicates, among other things, the length of the Q subchannel data that was retrieved.
FormatCode
This member should have a value of IOCTL_CDROM_TRACK_ISRC.
Reserved0
Reserved.
Track
Contains the number for the track for which the ISRC value was requested.
Reserved1
Reserved.
Reserved2
Reserved.
Tcval
If ISRC data is detected, the Tcval member is set to one. Otherwise, Tcval is set to zero and indicates that TrackIsrc is invalid.
TrackIsrc
Tracking ISRC data.

Headers

Declared in ntddcdrm.h. Include ntddcdrm.h.

See Also

IOCTL_CDROM_READ_Q_CHANNEL, CDROM_SUB_Q_DATA_FORMAT, SUB_Q_CHANNEL_DATA


TAPE_DRIVE_PROBLEM_TYPE

The TAPE_DRIVE_PROBLEM_TYPE structure is used to report problems with the tape drive.

typedef enum _TAPE_DRIVE_PROBLEM_TYPE {
  TapeDriveProblemNone,
  TapeDriveReadWriteWarning,
  TapeDriveReadWriteError,
  TapeDriveReadWarning,
  TapeDriveWriteWarning,
  TapeDriveReadError,
  TapeDriveWriteError,
  TapeDriveHardwareError,
  TapeDriveUnsupportedMedia,
  TapeDriveScsiConnectionError,
  TapeDriveTimetoClean,
  TapeDriveCleanDriveNow,
  TapeDriveMediaLifeExpired,
  TapeDriveSnappedTape
} TAPE_DRIVE_PROBLEM_TYPE;

Members

TapeDriveProblemNone
No tape drive problem.
TapeDriveReadWriteWarning
Tape drive is having problems doing reads or writes. This is a warning.
TapeDriveReadWriteError
Tape drive is having problems doing reads or writes. This is severe error.
TapeDriveReadWarning
Tape drive is having problems doing reads. This is a warning.
TapeDriveWriteWarning
Tape drive is having problems doing writes. This is a warning.
TapeDriveReadError
Tape drive is having problems doing reads. This is a severe error.
TapeDriveWriteError
Tape drive is having problems doing writes. This is a severe error.
TapeDriveHardwareError
Tape drive had a hardware error.
TapeDriveUnsupportedMedia
Media format is not supported.
TapeDriveScsiConnectionError
SCSI cable or connection error.
TapeDriveTimetoClean
Tape drive requires cleaning.
TapeDriveCleanDriveNow
Tape drive requires cleaning.
TapeDriveMediaLifeExpired
Media life has expired. Media needs to be replaced.
TapeDriveSnappedTape
Tape has snapped.

Headers

Declared in ntddchgr. Include ntddchgr.h.

See Also

TAPE_WMI_OPERATIONS, TapeMiniWMIControl


TAPE_INIT_DATA

TAPE_INIT_DATA is used only by legacy tape miniclass drivers. Use TAPE_INIT_DATA_EX instead.

typedef struct _TAPE_INIT_DATA {
  TAPE_VERIFY_INQUIRY_ROUTINE     VerifyInquiry;   /* not required */
  BOOLEAN                         QueryModeCapabilitiesPage;
  ULONG                           MinitapeExtensionSize;
  TAPE_EXTENSION_INIT_ROUTINE     ExtensionInit;       /* optional */
  ULONG                           DefaultTimeOutValue; /* optional */
  TAPE_ERROR_ROUTINE              TapeError;           /* optional */
  ULONG                           CommandExtensionSize;
  TAPE_PROCESS_COMMAND_ROUTINE    CreatePartition;
  TAPE_PROCESS_COMMAND_ROUTINE    Erase;
  TAPE_PROCESS_COMMAND_ROUTINE    GetDriveParameters;
  TAPE_PROCESS_COMMAND_ROUTINE    GetMediaParameters;
  TAPE_PROCESS_COMMAND_ROUTINE    GetPosition;
  TAPE_PROCESS_COMMAND_ROUTINE    GetStatus;
  TAPE_PROCESS_COMMAND_ROUTINE    Prepare;
  TAPE_PROCESS_COMMAND_ROUTINE    SetDriveParameters;
  TAPE_PROCESS_COMMAND_ROUTINE    SetMediaParameters;
  TAPE_PROCESS_COMMAND_ROUTINE    SetPosition;
  TAPE_PROCESS_COMMAND_ROUTINE    WriteMarks;
  TAPE_PROCESS_COMMAND_ROUTINE    PreProcessReadWrite; /* optional */
} TAPE_INIT_DATA, *PTAPE_INIT_DATA;


TAPE_INIT_DATA_EX

TAPE_INIT_DATA_EX defines values and routines that are specific to a Windows® 2000 tape miniclass driver. The tape miniclass DriverEntry routine passes this information to the tape class driver to complete miniclass driver initialization.

typedef struct _TAPE_INIT_DATA_EX {
  TAPE_VERIFY_INQUIRY_ROUTINE  VerifyInquiry   /* not required */;
  BOOLEAN  QueryModeCapabilitiesPage;
  ULONG  MinitapeExtensionSize;
  TAPE_EXTENSION_INIT_ROUTINE  ExtensionInit; /* optional */
  ULONG  DefaultTimeOutValue; /* optional */
  TAPE_ERROR_ROUTINE  TapeError; /* optional */
  ULONG  CommandExtensionSize;
  TAPE_PROCESS_COMMAND_ROUTINE  CreatePartition;
  TAPE_PROCESS_COMMAND_ROUTINE  Erase;
  TAPE_PROCESS_COMMAND_ROUTINE  GetDriveParameters;
  TAPE_PROCESS_COMMAND_ROUTINE  GetMediaParameters;
  TAPE_PROCESS_COMMAND_ROUTINE  GetPosition;
  TAPE_PROCESS_COMMAND_ROUTINE  GetStatus;
  TAPE_PROCESS_COMMAND_ROUTINE  Prepare;
  TAPE_PROCESS_COMMAND_ROUTINE  SetDriveParameters;
  TAPE_PROCESS_COMMAND_ROUTINE  SetMediaParameters;
  TAPE_PROCESS_COMMAND_ROUTINE  SetPosition;
  TAPE_PROCESS_COMMAND_ROUTINE  WriteMarks;
  TAPE_PROCESS_COMMAND_ROUTINE  PreProcessReadWrite; /* optional */
  TAPE_PROCESS_COMMAND_ROUTINE  TapeGetMediaTypes;
  ULONG  MediaTypesSupported;
  TAPE_PROCESS_COMMAND_ROUTINE  TapeWMIOperations;
  ULONG  Reserved[2];
} TAPE_INIT_DATA_EX, *PTAPE_INIT_DATA_EX;

Members

VerifyInquiry
Specifies the entry point of the tape miniclass driver's TapeMiniVerifyInquiry routine, which determines whether the driver supports a given device. This routine is required.
QueryModeCapabilitiesPage
TRUE directs the tape class driver to pass a mode capabilities page to the tape miniclass driver's TapeMiniVerifyInquiry and TapeMiniExtensionInit routines.
MinitapeExtensionSize
Specifies the size, in bytes, of a driver-specific context area. If this member is nonzero, ExtensionInit must not be NULL. This value is optional and must be set to zero if not used.
ExtensionInit
Specifies the entry point of the tape miniclass driver's TapeMiniExtensionInit routine, which initializes an optional minitape extension, if any. If MiniTapeExtensionSize is zero, ExtensionInit must be NULL.
DefaultTimeOutValue
Specifies the number of seconds that the tape class driver waits for an SRB request before canceling it. If this value is zero, the tape class driver sets an appropriate default value. The tape class driver always uses the default timeout value for read and write requests. The routines contained in the TAPE_INIT_DATA_EX structure can override the default timeout value for device control requests by setting TimeOutValue in an SRB.
TapeError
Specifies the entry point of the tape miniclass driver's TapeMiniTapeError routine, which augments the error-handling activities of the tape class driver. This routine is optional. If one is not used TapeError must be set to NULL.
CommandExtensionSize
Specifies the size, in bytes, of a command extension to be allocated before the start of each tape command. A tape miniclass driver uses the command extension to store context during the processing of tape commands. Its size and internal structure are defined by the tape miniclass driver. A command extension is optional. If one is not used CommandExtensionSize must be set to zero.
CreatePartition
Specifies the entry point of the tape miniclass driver's TapeMiniCreatePartition routine, which creates a partition on a tape. This routine is required.
Erase
Specifies the entry point of the tape miniclass driver's TapeMiniErase routine, which erases a tape. This routine is required.
GetDriveParameters
Specifies the entry point of the tape miniclass driver's TapeMiniGetDriveParameters routine, which handles requests to get drive parameters. This routine is required.
GetMediaParameters
Specifies the entry point of the tape miniclass driver's TapeMiniGetMediaParameters routine, which handles requests to get media parameters. This routine is required.
GetPosition
Specifies the entry point of the tape miniclass driver's TapeMiniGetPosition routine, which handles requests to get the position of a tape. This routine is required.
GetStatus
Specifies the entry point of the tape miniclass driver's TapeMiniGetStatus routine, which handles requests for status. This routine is required.
Prepare
Specifies the entry point of the tape miniclass driver's TapeMiniPrepare routine, which prepares a tape device. This routine is required.
SetDriveParameters
Specifies the entry point of the tape miniclass driver's TapeMiniSetDriveParameters routine, which sets drive parameters. This routine is required.
SetMediaParameters
Specifies the entry point of the tape minclass driver's TapeMiniSetMediaParameters routine, which sets media parameters. This routine is required.
SetPosition
Specifies the entry point of the tape miniclass driver's TapeMiniSetPosition routine, which positions a tape. This routine is required.
WriteMarks
Specifies the entry point of the tape miniclass driver's TapeMiniWriteMarks routine, which writes marks to tape. This routine is required.
PreProcessReadWrite
Specifies the entry point of the tape miniclass driver's TapeMiniPreProcessReadWrite routine, which executes device-specific operations before all reads and writes. This routine is optional and is not needed by most drivers. If one is not used, PreProcessReadWrite must be NULL.
TapeGetMediaTypes
Specifies the entry point of the tape miniclass driver's TapeMiniGetMediaTypes routine, which gets a description of each media type supported by a tape device. This routine is required.
MediaTypesSupported
Indicates the number of media types supported by the device.
TapeWMIOperations
This field holds the address of the TapeMiniWMIControl routine.
Reserved
Reserved.

Headers

Declared in minitape.h. Include minitape.h.

Comments

A tape miniclass driver's DriverEntry routine calls TapeClassZeroMemory to clear TAPE_INIT_DATA_EX, fills in the required members and any appropriate optional members, and TapeClassInitialize with a pointer to this structure.

See Also

DriverEntry of Tape Miniclass Driver, TapeClassInitialize, TapeClassZeroMemory, TapeMiniCreatePartition, TapeMiniErase, TapeMiniExtensionInit, TapeMiniGetDriveParameters, TapeMiniGetMediaParameters, TapeMiniGetMediaTypes, TapeMiniGetPosition, TapeMiniGetStatus, TapeMiniPrepare, TapeMiniSetDriveParameters, TapeMiniSetMediaParameters, TapeMiniSetPosition, TapeMiniTapeError, TapeMiniVerifyInquiry, TapeMiniWriteMarks


TAPE_WMI_OPERATIONS

The tape miniclass driver passes this structure to its TapeMiniWMIControl routine to indicate which WMI operation must be performed by the device.

typedef struct _TAPE_WMI_OPERATIONS {
  ULONG  Method;
  ULONG  DataBufferSize;
  PVOID  DataBuffer;
} TAPE_WMI_OPERATIONS, *PTAPE_WMI_OPERATIONS;

Members

Method
Operation to be performed by the tape device. The operations allowed are as follows:
Value Meaning
TAPE_CHECK_FOR_DRIVE_PROBLEM
If the tape drive supports commands to return specific device errors, such as tape alerts, the minidriver's TapeMiniWMIControl routine should execute the TAPE_QUERY_DEVICE_ERROR_DATA method Otherwise, it should execute the TAPE_QUERY_IO_ERROR_DATA method.
TAPE_QUERY_DEVICE_ERROR_DATA
Returns specific device errors, such as tape alerts. Not all tape drives support this method.
TAPE_QUERY_IO_ERROR_DATA
Returns general I/O error data, such as read/write errors, based on the IO error count. All tape drives support this method.
DataBufferSize
Size of the buffer in which the tape minidriver returns the results of the operation.
DataBuffer
Buffer in which the tape minidriver returns the results of the operation. The first sizeof(ULONG) bytes of DataBuffer contain a value of type TAPE_DRIVE_PROBLEM_TYPE, followed by DataBufferSize - sizeof(ULONG) bytes of tape data.

Headers

Declared in ntddchgr.h. Include ntddchgr.h.

See Also

TapeMiniWMIControl, TAPE_DRIVE_PROBLEM_TYPE


TRACK_DATA

Track descriptor is used in conjunction with CDROM_TOC and CDROM_TOC_SESSION_DATA.

typedef struct _TRACK_DATA {
  UCHAR  Reserved;
  UCHAR  Control : 4;
  UCHAR  Adr : 4;
  UCHAR  TrackNumber;
  UCHAR  Reserved1;
  UCHAR  Address[4];
} TRACK_DATA, *PTRACK_DATA;

Members

Reserved
Reserved.
Control
Indicates the attributes of the track. For information on the permissible values for this member, see specification T10/1363-D Revision-02A, by National Committee for Information Technology Standards (NCITS).
Adr
Indicates the type of information encoded in the Q subchannel of the track where this table of contents entry was found. For information on the permissible values for this member, see specification T10/1363-D Revision-02A, by National Committee for Information Technology Standards (NCITS).
TrackNumber
Number of the track.
Reserved1
Reserved.
Address
Starting address of the track.

Headers

Declared in ntddcdrm.h. Include ntddcdrm.h.

Comments

This structure contains table of contents information for a track.

See Also

CDROM_TOC, CDROM_TOC_SESSION_DATA


VERIFY_INFORMATION

The VERIFY_INFORMATION structure provides information used to logically format a disk extent.

typedef struct _VERIFY_INFORMATION {
  LARGE_INTEGER  StartingOffset;
  DWORD  Length;
} VERIFY_INFORMATION, *PVERIFY_INFORMATION;

Members

StartingOffset
Specifies the starting offset of the disk extent.
Length
Length, in bytes, of the disk extent.

Headers

Declared in ntdddisk.h. Include ntdddisk.h.

Comments

VERIFY_INFORMATION is the output buffer for the IOCTL_DISK_VERIFY control code.

See Also

IOCTL_DISK_VERIFY


VOLUME_LOGICAL_OFFSET

The VOLUME_LOGICAL_OFFSET structure contains a logical offset into a volume.

typedef struct _VOLUME_LOGICAL_OFFSET {
  LONGLONG  LogicalOffset;
} VOLUME_LOGICAL_OFFSET, *PVOLUME_LOGICAL_OFFSET;

Members

LogicalOffset
Logical offset into a volume.

Headers

Declared in ntddvol.h. Include ntddvol.h.

Comments

The VOLUME_LOGICAL_OFFSET structure is used with IOCTL_VOLUME_PHYSICAL_TO_LOGICAL and IOCTL_VOLUME_LOGICAL_TO_PHYSICAL to request a logical offset equivalent of a physical offset or a physical offset equivalent of a logical offset, respectively.

See Also

IOCTL_VOLUME_LOGICAL_TO_PHYSICAL, IOCTL_VOLUME_PHYSICAL_TO_LOGICAL


VOLUME_PHYSICAL_OFFSET

The VOLUME_PHYSICAL_OFFSET structure contains a physical offset into a volume and its accompanying physical disk number and is used with IOCTL_VOLUME_PHYSICAL_TO_LOGICAL and IOCTL_VOLUME_LOGICAL_TO_PHYSICAL to request a logical offset equivalent of a physical offset or a physical offset equivalent of a logical offset, respectively.

typedef struct _VOLUME_PHYSICAL_OFFSET {
  ULONG  DiskNumber;
  LONGLONG  Offset;
} VOLUME_PHYSICAL_OFFSET, *PVOLUME_PHYSICAL_OFFSET;

Members

DiskNumber
Number of the physical disk.
Offset
Physical offset of the data on the disk.

Headers

Declared in ntddvol.h. Include ntddvol.h.

See Also

IOCTL_VOLUME_LOGICAL_TO_PHYSICAL, IOCTL_VOLUME_PHYSICAL_TO_LOGICAL


VOLUME_PHYSICAL_OFFSETS

The VOLUME_PHYSICAL_OFFSETS structure contains an array of physical offsets and accompanying physical disk numbers and is used with IOCTL_VOLUME_LOGICAL_TO_PHYSICAL to request a series of pairs of physical offsets and disk numbers that correspond to a single logical offset.

typedef struct _VOLUME_PHYSICAL_OFFSETS {
  ULONG  NumberOfPhysicalOffsets;
  VOLUME_PHYSICAL_OFFSET  PhysicalOffset[1];
} VOLUME_PHYSICAL_OFFSETS, *PVOLUME_PHYSICAL_OFFSETS;

Members

NumberOfPhysicalOffsets
Returns the number of pairs of physical offsets and accompanying physical disk numbers <disk number, disk offset>.
PhysicalOffset
Returns the array of pairs of physical offsets and accompanying physical disk numbers <disk number, disk offset>.

Headers

Declared in ntddvol.h. Include ntddvol.h.

See Also

IOCTL_VOLUME_LOGICAL_TO_PHYSICAL, IOCTL_VOLUME_PHYSICAL_TO_LOGICAL, VOLUME_PHYSICAL_OFFSET


VOLUME_READ_PLEX_INPUT

This structure is used in conjunction with IOCTL_VOLUME_READ_PLEX to read data from a specific plex in a volume.

typedef struct _VOLUME_READ_PLEX_INPUT {
  LARGE_INTEGER  ByteOffset;
  ULONG  Length;
  ULONG  PlexNumber;
} VOLUME_READ_PLEX_INPUT, *PVOLUME_READ_PLEX_INPUT;

Members

ByteOffset
Supplies the start offset, in bytes, relative to the beginning of the volume. This member must be aligned on a 512 byte boundary.
Length
Supplies the length, in bytes, of the block to be read. This member must be an integer multiple of 512 bytes.
PlexNumber
Supplies the zero-based plex number.

Headers

Declared in ntddvol.h. Include ntddvol.h.

See Also

IOCTL_VOLUME_READ_PLEX


WMI_CHANGER_PROBLEM_DEVICE_ERROR

When the ChangerPerformDiagnostics routine performs diagnostic tests on a changer device it returns the results in a WMI_CHANGER_PROBLEM_DEVICE_ERROR structure.

typedef struct _WMI_CHANGER_PROBLEM_DEVICE_ERROR
{
    ULONG  ChangerProblemType;
} WMI_CHANGER_PROBLEM_DEVICE_ERROR, *PWMI_CHANGER_PROBLEM_DEVICE_ERROR;

Members

ChangerProblemType
The minidriver sets ChangerProblemType to one of the enumeration values defined for the CHANGER_DEVICE_PROBLEM_TYPE enumeration data type.

Headers

Declared in ntddchgr. Include ntddchgr.

See Also

ChangerPerformDiagnostics, CHANGER_DEVICE_PROBLEM_TYPE


I/O Requests for Mass-storage Drivers

This section contains the following information:

Storage I/O Requests

Mass-storage Device I/O Control Codes

Disk I/O Control Codes

CD-ROM I/O Control Codes

DVD I/O Control Codes

Tape I/O Control Codes

Changer I/O Control Codes

SCSI Port I/O Control Codes

Mount Manager I/O Control Codes

Volume Manager I/O Control Codes

This chapter describes the basic set of I/O requests sent to drivers of storage devices and to intermediate drivers layered above them. It describes the system-defined I/O control codes that must be handled by all storage devices and those that must be handled by a particular type of device.

This chapter also describes the system-defined I/O control codes that storage class drivers can use in IRPs that they allocate and send to the system SCSI port driver.


Storage I/O Requests

Any driver that sets up device objects of type FILE_DEVICE_DISK, FILE_DEVICE_CD_ROM, FILE_DEVICE_DVD, FILE_DEVICE_TAPE, or FILE_DEVICE_CHANGER must handle certain requests as appropriate for a particular type of device.

A storage class driver can optionally handle IRP_MJ_INTERNAL_DEVICE_CONTROL at the discretion of the driver writer. For details about this I/O request, see IRP Function Codes and IOCTLs.

IRP_MJ_CLOSE

All mass-storage drivers must handle this request.

Operation

Returns STATUS_SUCCESS, indicating that the driver has completed the request.

When Called

The handle of the file object that represents the target device object has been released.

I/O Status Block

Returns STATUS_SUCCESS in the Status field and zero in the Information field.

IRP_MJ_CREATE

All mass-storage drivers must handle this request.

Operation

Returns STATUS_SUCCESS, indicating that the device or partition exists. For a disk or CD-ROM device, this request opens the device as the target of I/O requests from the caller.

When Called

A higher-level driver is attempting to connect or attach one of its device objects to the target device object, or a user-mode process has attempted to open a file stored on the physical device, thereby causing a file system to carry out a mount operation.

I/O Status Block

Returns STATUS_SUCCESS in the Status field and zero in the Information field.

IRP_MJ_DEVICE_CONTROL

All mass-storage drivers must handle this request.

Operation

Determined by the I/O control code set at Parameters.DeviceIoControl.IoControlCode in the driver's I/O stack location of the IRP.

When Called

A Win32 application has called DeviceIoControl, or a higher-level driver has set up such a request.

I/O Status Block

Also determined by the operation, either STATUS_SUCCESS or an appropriate STATUS_XXX value. For most operations, the set of possible STATUS_XXX values includes those propagated from a call to a support routine or lower-level driver and/or those chosen by the driver designer. In general, the Information field of the I/O status block is set to the number of bytes returned or transferred when the device driver completes the IRP.

IRP_MJ_FLUSH_BUFFERS

Drivers of devices with internal caches for data and drivers that maintain internal buffers for data must handle this request.

Operation

Transfers any data cached in the device or in the driver's internal buffer(s) to system memory or out to the device. If the device or driver supports caching or buffering data, the driver must handle this request.

When Called

A file system or DTP application makes this request to ensure data integrity.

I/O Status Block

The Status field is set to STATUS_SUCCESS when the data has been transferred.

IRP_MJ_PNP

Storage drivers that support Plug and Play must handle this request.

Operation

Determined by the minor function code set in the I/O stack location of the IRP.

When Called

The Plug and Play Manager sends this request to initiate a plug and play operation such as starting or stopping a device.

I/O Status Block

Also determined by the operation, either STATUS_SUCCESS or an appropriate STATUS_XXX value. For most operations, the set of possible STATUS_XXX values includes those propagated from a call to a support routine or lower-level driver and/or those chosen by the driver designer. In general, the Information field of the I/O status block is set to the number of bytes transferred when the device driver completes the IRP.

IRP_MJ_POWER

Storage drivers that support power management must handle this request. For more information, see IRP_MJ_POWER.

IRP_MJ_READ

Disk, CD-ROM, DVD, and tape drivers must handle this request.

Operation

Transfers data from the device to system memory.

Output

Drivers of disk, CD-ROM, DVD, and tape devices generally use direct I/O, so the lowest-level driver transfers data using DMA or PIO into the buffer described by the MDL at Irp->MdlAddress.

When Called

A user-mode application that has a handle for an opened file or a handle for the opened file object that represents the device has requested data. This request can also be issued by a higher-level driver.

I/O Status Block

The Information field is set to the number of bytes transferred, whatever the Status field's value. In addition to STATUS_SUCCESS, possible values are any of the following:

STATUS_INSUFFICIENT_RESOURCES

Device Errors

STATUS_INVALID_DEVICE_REQUEST
STATUS_NO_SUCH_DEVICE
STATUS_IO_TIMEOUT
STATUS_DEVICE_NOT_CONNECTED
STATUS_IO_DEVICE_ERROR
STATUS_DEVICE_NOT_READY
STATUS_DEVICE_BUSY

Sector/Data Errors

STATUS_DEVICE_DATA_ERROR
STATUS_CRC_ERROR

and, by drivers of removable-media devices:

STATUS_NO_MEDIA_IN_DEVICE
STATUS_VERIFY_REQUIRED

IRP_MJ_SHUTDOWN

Disk and tape drivers must handle this request.

Operation

Transfers any data cached in the device or in the driver's internal buffer(s) to system memory or out to the device before the system is shut down. If the device or driver supports caching or buffering data, the driver must handle this request.

When Called

The user has decided to shut down the system.

I/O Status Block

The Status field is set to STATUS_SUCCESS when the data has been transferred.

IRP_MJ_SYSTEM_CONTROL

All storage drivers must support this request. For more information, see IRP_MJ_SYSTEM_CONTROL.

IRP_MJ_WRITE

Disk and tape drivers must handle this request.

Operation

Transfers data from system memory to the underlying device.

Input

Drivers of disk and tape devices generally use direct I/O, so the lowest-level driver transfers data using DMA or PIO from the buffer described by the MDL at Irp->MdlAddress.

When Called

A user-mode application that has a handle for an opened file or a handle for the opened file object that represents the device has requested data be written to the device. This request can also be issued by a higher-level driver.

I/O Status Block

The Information field is set to the number of bytes transferred, whatever the Status field's value. Possible values are any of those returned for read requests, STATUS_MEDIA_WRITE_PROTECTED returned by drivers of removable-media devices, and STATUS_NOT_SUPPORTED returns by the system for drivers that have no DispatchWrite routine.


Mass-storage Device I/O Control Codes

Storage class drivers are required to handle some or all of the I/O control codes for IRP_MJ_DEVICE_CONTROL described in this section, depending on the type of storage device, in addition to those requests that other drivers for the same type of device handle.

See the preceding section about the other IRP_MJ_XXX I/O requests sent to disk, CD-ROM, DVD, tape, and changer drivers, for information about the basic requirements for all drivers of these types of devices.

The IOCTL_STORAGE_XXX control codes replace the IOCTL_DeviceType_XXX control codes, where DeviceType was DISK, TAPE, or CDROM. For example, IOCTL_STORAGE_RESERVE replaces IOCTL_DISK_RESERVE, IOCTL_TAPE_RESERVE, and IOCTL_CDROM_RESERVE. The storage control codes have identical values for function code, transfer method, and required access as the previous disk, tape, and CD-ROM codes. The only difference is the device type. Drivers that pass unrecognized IOCTLs to a storage class driver need not make any changes for these new IOCTLs.


IOCTL_STORAGE_CHECK_VERIFY

Operation

Determines whether the media has changed on a removable-media device which the caller has opened for read or write access. If read or write access to the device is not necessary, the caller can improve performance by opening the device with FILE_READ_ATTRIBUTES and issuing an IOCTL_STORAGE_CHECK_VERIFY2 request instead.

For more information, see Supporting Removable Media.

Input

Optionally, for disk and CD-ROM devices, Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of a buffer, which must be >= sizeof(ULONG). This field is zero if the optional buffer is not specified.

Otherwise, this request has no input.

Output

Optionally, for disk and CD-ROM devices, Irp->AssociatedIrp.SystemBuffer points to a buffer to receive the media change count. The driver fills this buffer only if Parameters.DeviceIoControl.OutputBufferLength was nonzero and the return value is STATUS_SUCCESS. The media change count is a ULONG indicating how many times the media has changed since the driver started.

Otherwise, this request has no output.

I/O Status Block

If a disk or CD-ROM driver has no indication that the media has changed, the driver sets the Status field to STATUS_SUCCESS. In addition, if the optional media change buffer was specified, the driver returns the media change count in the buffer at Irp->AssociatedIrp.SystemBuffer and sets the Information field to sizeof(ULONG). If the optional media change buffer was not specified, the driver sets Information to zero.

If the driver detects that the media has changed and the volume is mounted (VPB_MOUNTED is set in the VPB), it must:

  1. Set Information to zero.
  2. Set Status to STATUS_VERIFY_REQUIRED
  3. Set the DO_VERIFY_VOLUME flag in the DeviceObject.
  4. Call IoCompleteRequest with the input IRP.

If the driver detects that the media has changed, but the volume is not mounted, the driver must not set the DO_VERIFY_VOLUME bit. Instead, it should do the following:

  1. Set Status to STATUS_IO_DEVICE_ERROR.
  2. Set Information to zero.
  3. Call IoCompleteRequest with the IRP.

If the driver detects an error such as STATUS_BUFFER_TOO_SMALL, STATUS_INSUFFICIENT_RESOURCES, or a device error, it sets Information to zero and sets the appropriate error value in the Status field.

For a tape driver, the Information field is set to zero and the Status field is set to STATUS_SUCCESS or possibly to STATUS_VERIFY_REQUIRED.

Headers

Defined in ntddstor.h; Include ntddstor.h.


IOCTL_STORAGE_CHECK_VERIFY2

Operation

Determines whether the media has changed on a removable-media device which the caller has opened with FILE_READ_ATTRIBUTES. Because no file system is mounted when a device is opened in this way, this request can be processed much more quickly than an IOCTL_STORAGE_CHECK_VERIFY request.

Input

Input is identical to the input for IOCTL_STORAGE_CHECK_VERIFY.

Output

Output is identical to the output for IOCTL_STORAGE_CHECK_VERIFY.

I/O Status Block

I/O status is identical to the I/O status for IOCTL_STORAGE_CHECK_VERIFY.

Headers

Defined in ntddstor.h; Include ntddstor.h.


IOCTL_STORAGE_EJECT_MEDIA

Operation

If the device supports it, ejects the media.

Input

None

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS or possibly to STATUS_NO_MEDIA_IN_DEVICE or STATUS_INVALID_DEVICE_REQUEST.

Headers

Defined in ntddstor.h; Include ntddstor.h.


IOCTL_STORAGE_EJECTION_CONTROL

Operation

If the driver can prevent the media from being removed while the drive is in use, the driver disables or enables the mechanism that ejects media, thereby locking the drive. A caller must open the device with FILE_READ_ATTRIBUTES to send this request.

Unlike IOCTL_STORAGE_MEDIA_REMOVAL, the driver tracks IOCTL_STORAGE_EJECTION_CONTROL requests by caller and ignores unlock requests for which it has not received a lock request from the same caller, thereby preventing other callers from unlocking the drive.

A driver for a removable media device which can support this IOCTL must do the following:

  1. Keep a lock count, tagged by caller, in the device object extension.
  2. Keep the lock count per physical device.
  3. When called with this IOCTL, if the flag to prevent removing the media is set, increment the count; if the flag is clear and the driver has previously received a lock request from the same caller, decrement the count.
  4. Prevent removal of the media unless all lock counts are zero.

Input, output, and I/O status block values for IOCTL_STORAGE_EJECTION_CONTROL are identical to those for IOCTL_STORAGE_MEDIA_REMOVAL.

Headers

Defined in ntddstor.h; Include ntddstor.h.


IOCTL_STORAGE_FIND_NEW_DEVICES

Operation

Determines whether another device that the driver supports has been connected to the I/O bus, either since the system was booted or since the driver last processed this request.

This IOCTL is obsolete in the Plug and Play environment. Plug and Play class drivers handle this request by calling IoInvalidateDeviceRelations with the device relations type BusRelations. If a new device is found, the class driver's AddDevice routine will be called.

Legacy class drivers can continue to handle this IOCTL without modifications. If a new device is found, the driver sets up any necessary system objects and resources to handle I/O requests for its new device. It also initializes the device on receipt of this request dynamically: that is, without requiring the machine to be rebooted. Such a driver is assumed to support devices connected on a dynamically configurable I/O bus.

Input

None

Output

None

I/O Status Block

The Information field is set to zero. The Status field can be set to STATUS_SUCCESS or to any other value returned by a Plug and Play driver's IoInvalidateDeviceRelations call or a legacy driver's (re)initialization code.

Headers

Defined in ntddstor.h; Include ntddstor.h.


IOCTL_STORAGE_GET_DEVICE_NUMBER

Operation

Returns the FILE_DEVICE_XXX type, device number, and, for a partitionable device, the partition number assigned to a device by the driver when the device is started. This request is usually issued by a fault-tolerant disk driver.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location indicates the size in bytes of the parameter buffer, which must be >= sizeof(STORAGE_DEVICE_NUMBER).

Output

The driver returns the STORAGE_DEVICE_NUMBER data in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the number of bytes returned. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INSUFFICIENT_RESOURCES.

Headers

Defined in ntddstor.h; Include ntddstor.h.

See Also

STORAGE_DEVICE_NUMBER


IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER

To be documented in a future release of the DDK.


IOCTL_STORAGE_GET_MEDIA_TYPES

Operation

Returns information about the geometry of floppy drives.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the buffer, which must be at least (NumberOfSupportedMediaTypes * sizeof(DISK_GEOMETRY)).

Output

The driver returns an array of DISK_GEOMETRY records for the types of media it supports in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the size in bytes of the returned data. The Status field can be set to STATUS_SUCCESS, or possibly to STATUS_INVALID_DEVICE_REQUEST, STATUS_BUFFER_TOO_SMALL, or STATUS_BUFFER_OVERFLOW.

Headers

Defined in ntddstor.h; Include ntddstor.h.

See Also

DISK_GEOMETRY


IOCTL_STORAGE_GET_MEDIA_TYPES_EX

Operation

Returns information about the types of media supported by a device. A storage class driver must handle this IOCTL to control devices to be accessed by the Removable Storage Manager (RSM) either as stand-alone devices or as data transfer elements (drives) in a media library or changer device.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location indicates the size in bytes of the parameter buffer, which must be >= sizeof(GET_MEDIA_TYPES) plus additional device-type-specific data, if any.

Output

The driver returns an array of DEVICE_MEDIA_INFO structures, one for each media type supported by the device, embedded in a GET_MEDIA_TYPES structure in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the number of bytes returned. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INFO_LENGTH_MISMATCH or STATUS_INSUFFICIENT_RESOURCES.

Headers

Defined in ntddstor.h; Include ntddstor.h.

See Also

DEVICE_MEDIA_INFO, GET_MEDIA_TYPES


IOCTL_STORAGE_LOAD_MEDIA

Operation

Causes media to be loaded in a device which the caller has opened for read or write access. If read or write access to the device is not necessary, the caller can improve performance by opening the device with FILE_READ_ATTRIBUTES and issuing an IOCTL_STORAGE_LOAD_MEDIA2 request instead.

Input

None

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INVALID_DEVICE_REQUEST, STATUS_NO_MEDIA_IN_DEVICE, STATUS_BUFFER_TOO_SMALL, or STATUS_DEVICE_NOT_CONNECTED.

Headers

Defined in ntddstor.h; Include ntddstor.h.


IOCTL_STORAGE_LOAD_MEDIA2

Causes media to be loaded in a device which the caller has opened with FILE_READ_ATTRIBUTES. Because no file system is mounted when a device is opened in this way, this request can be processed much more quickly than an IOCTL_STORAGE_LOAD_MEDIA request.

Input, output, and I/O status block values for IOCTL_STORAGE_LOAD_MEDIA2 are identical to those for IOCTL_STORAGE_LOAD_MEDIA.


IOCTL_STORAGE_MCN_CONTROL

Operation

Temporarily enables or disables delivery of the custom PnP events GUID_IO_MEDIA_ARRIVAL and GUID_IO_MEDIA_REMOVAL on a removable-media device. This, in turn, enables or disables media change detection (AutoPlay) for the device if the caller has opened the device with FILE_READ_ATTRIBUTES access and if the device has AutoPlay enabled in the registry. The caller must not open the device for read or write access or the IOCTL operation will fail. This IOCTL has no effect on the AutoPlay setting in the registry per se.

A driver for such a removable-media device must do the following:

  1. Keep a count of disable requests, per physical device, in the device object extension.
  2. When called with this IOCTL, if the flag to disable media change detection is set, increment the count; if the flag is clear, decrement the count.
  3. Set the media change event for the device when the media state is changed only if the disable request count is zero.

When the IRP_MJ_DEVICE_CONTROL IRP that contains this IOCTL is passed to the SCSI class driver the FileObject member of the current IO_STACK_LOCATION must point to a valid file object. The SCSI class driver requires a file object for cases where a user-mode application that is disabling or enabling AutoPlay terminates unexpectedly. In such cases the SCSI class driver uses the file object to re-enable media change detection. Since the file object is necessary for proper clean-up, the SCSI class driver will cause the IRP to fail with an error message of STATUS_INVALID_PARAMETER if the FileObject member of IO_STACK_LOCATION does not point to a valid file object. If a user-mode application opens the device, then the I/O Manager initializes this member, but kernel-mode driver writers should not assume that FileObject will be properly initialized when the IRP is generated by a user-mode application. If, for instance, a user-mode application mistakenly opens the device for either read or write access before sending the IOCTL, then the device control IRP will be routed through the file system, preventing the SCSI class driver and the device driver from directly accessing the device's file object.

Input

The buffer at Irp->AssociatedIrp.SystemBuffer contains a Boolean value, with TRUE indicating that the driver should disable media change detection.

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS or possibly to STATUS_BUFFER_TOO_SMALL, STATUS_INVALID_PARAMETER or STATUS_INVALID_DEVICE_STATE.

Headers

Defined in ntddstor.h; Include ntddstor.h.


IOCTL_STORAGE_MEDIA_REMOVAL

Operation

If the driver can prevent the media from being removed while the drive is in use, it disables or enables the mechanism that ejects media on a device which the caller has opened for read or write access.

Unlike IOCTL_STORAGE_EJECTION_CONTROL, for which the driver tracks requests by caller, the driver ignores IOCTL_STORAGE_MEDIA_REMOVAL unlock requests only if its lock count is already zero, thereby allowing any caller to unlock the drive.

A driver for such a removable media device which can support this IOCTL must do the following:

  1. Keep a lock count in the device object extension.
  2. Keep the lock count per physical device.
  3. When called with this IOCTL, if the flag to prevent removing the media is set, increment the count; if the flag is clear, decrement the count.
  4. Prevent removal of the media unless all lock counts are zero.

Input

The buffer at Irp->AssociatedIrp.SystemBuffer contains a Boolean value, with TRUE indicating that the driver should lock the media in the drive.

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INVALID_DEVICE_REQUEST, STATUS_NO_MEDIA_IN_DEVICE, or STATUS_DEVICE_NOT_CONNECTED.

Headers

Defined in ntddstor.h; Include ntddstor.h.


IOCTL_STORAGE_PREDICT_FAILURE

Operation

Upon receiving this IOCTL, the disk class driver attempts to verify if an IDE drive supports self-monitoring analysis and reporting technology (SMART). If the drive is a SCSI drive, the class driver attempts to verify if the SCSI disk supports the equivalent IDE SMART technology: Information Exception Control Page, X3T10/94-190 Rev 4.

The caller should cast the structure returned to STORAGE_PREDICT_FAILURE. If the PredictFailure member of this structure is nonzero, the drive supports failure prediction technology. If the value is zero, the drive does not support failure prediction.

If the device supports failure prediction, 512 bytes of vendor-specific information is returned in the VendorSpecific member.

Input

Parameters.DeviceIoControl.OutputBufferLength indicates the size, in bytes, of the buffer at Irp->AssociatedIrp.SystemBuffer which must be greater or equal to the sizeof(STORAGE_PREDICT_FAILURE).

Output

The driver returns failure prediction data in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to sizeof(STORAGE_PREDICT_FAILURE). The Status field is set to STATUS_SUCCESS or, if the buffer at Irp->AssociatedIrp.SystemBuffer is too small, to STATUS_BUFFER_TOO_SMALL.

Headers

Defined in ntddstor.h. Include ntddstor.h.

See Also

STORAGE_PREDICT_FAILURE


IOCTL_STORAGE_QUERY_PROPERTY

Operation

Returns properties of a storage device or adapter. The request indicates the kind of information to retrieve, such as inquiry data for a device or capabilities and limitations of an adapter. IOCTL_STORAGE_QUERY_PROPERTY can also be used to determine whether the port driver supports a particular property, or which fields in the property descriptor can be modified with a subsequent change-property request.

Usually, the caller is a storage class driver, but the caller can be an application that makes requests directly to the port driver when no storage class driver exists for the target device.

Only Plug and Play drivers can issue IOCTL_STORAGE_QUERY_PROPERTY requests. Legacy drivers should use IOCTL_SCSI_GET_INQUIRY_DATA and IOCTL_SCSI_GET_CAPABILITIES to get inquiry and capabilities data.

Input

Parameters.DeviceIoControl.InputBufferLength indicates the size in bytes of the parameter buffer at Irp->AssociatedIrp.SystemBuffer, which must be >= sizeof(STORAGE_PROPERTY_QUERY).

Irp->AssociatedIrp.SystemBuffer contains STORAGE_PROPERTY_QUERY data that specifies whether to query the device or the adapter, the type of query to perform, and any additional parameters required for the query, such as the page code for a particular SCSI mode sense page. Device properties must be retrieved only from a device; attempting to retrieve device properties from an adapter will cause an error.

Parameters.DeviceIoControl.OutputBufferLength indicates the number of bytes that can be written to Irp->AssociatedIrp.SystemBuffer. OutputBufferLength can be zero to determine whether a property exists without retrieving its data.

Output

The driver returns query data to the buffer at Irp->AssociatedIrp.SystemBuffer. Varying amounts of bus-specific data can be appended to the structure. Cast the structure returned to a STORAGE_DESCRIPTOR_HEADER and check its Size member to determine the number of bytes the structure actually requires.

I/O Status Block

The Information field is set to the number of bytes returned. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INVALID_DEVICE_REQUEST, STATUS_INVALID_PARAMETER or STATUS_NOT_SUPPORTED.

Headers

Defined in ntddstor.h; Include ntddstor.h.


IOCTL_STORAGE_RELEASE

Operation

Releases a device previously reserved for the exclusive use of the caller on a bus that supports multiple initiators and the concept of reserving a device, such as a SCSI bus.

Input

None

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INVALID_DEVICE_REQUEST.

Headers

Defined in ntddstor.h; Include ntddstor.h.


IOCTL_STORAGE_RESERVE

Operation

Claims a device for the exclusive use of the caller on a bus that supports multiple initiators and the concept of reserving a device, such as a SCSI bus.

Input

None

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INVALID_DEVICE_REQUEST, STATUS_DEVICE_NOT_CONNECTED, or STATUS_IO_TIMEOUT.

Headers

Defined in ntddstor.h; Include ntddstor.h.


IOCTL_STORAGE_RESET_BUS

Operation

Resets an I/O bus and, indirectly, each device on the bus. Resetting the bus clears all device reservations and transfer speed settings, which must then be re-negotiated, making it a time-consuming operation that should be used very rarely. The caller requires only read access to issue a bus reset.

The SrbStatus flag of pending SRBs is set to SRB_STATUS_BUS_RESET.

Input

The buffer at Irp->AssociatedIrp.SystemBuffer contains a STORAGE_BUS_RESET_REQUEST structure that specifies the path ID of the bus to reset.

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INSUFFICIENT_RESOURCES, STATUS_NOT_IMPLEMENTED, or STATUS_INVALID_DEVICE_REQUEST.

Headers

Defined in ntddstor.h; Include ntddstor.h.


IOCTL_STORAGE_RESET_DEVICE

Operation

If possible, resets a nonSCSI storage device without affecting other devices on the bus. Device reset for SCSI devices is not supported. The caller requires only read access to issue a device reset, and the device must be capable of responding to I/O requests (that is, not hung) in order to comply. If the device reset succeeds, pending I/O requests are cancelled.

Input

None

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INSUFFICIENT_RESOURCES, STATUS_NOT_IMPLEMENTED, or STATUS_INVALID_DEVICE_REQUEST.

Headers

Defined in ntddstor.h; Include ntddstor.h.


Disk I/O Control Codes

The following summarizes the public I/O control codes that disk-type drivers support. However, each device driver is required to handle only those I/O control codes that its particular device(s) support.

For example, only a floppy driver would handle IOCTL_STORAGE_GET_MEDIA_TYPES requests; it would not handle IOCTL_DISK_GET/SET_PARTITION_INFO or IOCTL_GET/SET_DRIVE_LAYOUT requests. As another example, a filter driver like the system-supplied diskperf driver that monitors disk performance statistics would handle IOCTL_DISK_PERFORMANCE requests from a corresponding (user-mode) application; it would simply pass down other IOCTL_DISK_XXX requests to the underlying disk device driver.

All public I/O control codes for drivers of disk-type devices use buffered I/O. Consequently, the input or output data buffer for these requests is at Irp->AssociatedIrp.SystemBuffer.

Class drivers for storage devices handle additional public I/O control codes, along with those described in this section. See Mass Storage Device I/O Control Codes for more information about requirements for storage class drivers.

The IOCTL_INTERNAL_DISK_XXXXX codes can be used for communication between two kernel-mode drivers.


IOCTL_DISK_CHECK_VERIFY

Operation

This IOCTL is replaced by IOCTL_STORAGE_CHECK_VERIFY. The only difference between the two IOCTLs is the base value.


IOCTL_DISK_CREATE_DISK

Operation

This request creates an empty partition for the device object. It can operate on either an EFI disk or an MBR disk. The parameters necessary to create an empty disk depend on the type of partition table that will be put onto the disk. See CREATE_DISK for more information.

Disk drivers enumerate partitions as though they were child devices. Thus, upon creating the new partition, the disk class driver notifies the PnP Manager by means of a call to IoInvalidateDeviceRelations that the disk device has a new child device (partition).

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the buffer made available to the driver, which must be >= sizeof(CREATE_DISK). Otherwise, the driver returns with an error status of STATUS_INFO_LENGTH_MISMATCH.

The buffer at Irp->AssociatedIrp.SystemBuffer contains the CREATE_DISK data.

Output

None

Status Block

The Status field is set to STATUS_SUCCESS or possibly to STATUS_INSUFFICIENT_RESOURCES.

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS if the operation was successful. Other possible status values are STATUS_NOT_SUPPORTED if the partition style requested is not supported, STATUS_DEVICE_NOT_READY if the class driver failed to retrieve the disk geometry and STATUS_INSUFFICIENT_RESOURCES if the class driver failed to obtain a necessary resource, such as heap memory.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.


IOCTL_DISK_DELETE_DRIVE_LAYOUT

Operation

Will remove the boot signature from the master boot record, so that the disk will be formatted from sector zero to the end of the disk. Partition information will no longer be stored in sector zero. This operation can be used to generate so-called "superfloppies" which contain a file system starting at the first sector of the disk rather than in a partition on the disk.

Input

None

Output

None

Status Block

The Status field is set to STATUS_SUCCESS or possibly to STATUS_INSUFFICIENT_RESOURCES.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.


IOCTL_DISK_FIND_NEW_DEVICES

Operation

This IOCTL is replaced by IOCTL_STORAGE_FIND_NEW_DEVICES. The only difference between the two IOCTLs is the base value.


IOCTL_DISK_FORMAT_TRACKS

Operation

Formats the specified set of contiguous tracks on the disk.

Input

The buffer at Irp->AssociatedIrp.SystemBuffer contains the FORMAT_PARAMETERS data. Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the buffer.

Output

The device driver returns an array of BAD_TRACK_NUMBER values to the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the size of the returned bad-track array when the Status field is set to STATUS_SUCCESS. Otherwise, the Information field is zero, and the Status field possibly can be set to STATUS_INVALID_PARAMETER or STATUS_MEDIA_WRITE_PROTECTED if the media is removable.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.


IOCTL_DISK_FORMAT_TRACKS_EX

Operation

This IOCTL is similar to IOCTL_DISK_FORMAT_TRACKS except that it allows the caller to specify several more parameters. The additional extended parameters are the format gap length, the number of sectors per track, and an array whose element size is equal to the number of sectors per track. This array represents the track layout.

Input

The buffer at Irp->AssociatedIrp.SystemBuffer contains the FORMAT_EX_PARAMETERS data. Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the buffer.

Output

The device driver returns an array of BAD_TRACK_NUMBER values to the buffer at Irp->AssociatedIrp.SystemBuffer. BAD_TRACK_NUMBER is currently defined as a WORD on 32-bit systems.

Status Block

The driver sets the Status field to STATUS_SUCCESS. Otherwise, the driver sets the Status field to INVALID_PARAMETER if the input buffer length is < sizeof(FORMAT_EX_PARAMETERS), or if the format parameters supplied by the caller won't work on the drive to be formatted.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.


IOCTL_DISK_GET_CACHE_INFORMATION

Operation

Returns disk cache configuration data.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the buffer made available to the driver, which must be >= sizeof(DISK_CACHE_INFORMATION). Otherwise, the driver returns with an error status of STATUS_INFO_LENGTH_MISMATCH.

Output

The device driver returns the DISK_CACHE_INFORMATION in the buffer at Irp->AssociatedIrp.SystemBuffer. The structure is defined as follows:

typedef struct _DISK_CACHE_INFORMATION {
    BOOLEAN  ParametersSavable;
    BOOLEAN  ReadCacheEnabled;
    BOOLEAN  WriteCacheEnabled;
    DISK_CACHE_RETENTION_PRIORITY  ReadRetentionPriority;
    DISK_CACHE_RETENTION_PRIORITY  WriteRetentionPriority;
    USHORT  DisablePrefetchTransferLength;
    BOOLEAN  PrefetchScalar;
    union {
        struct {
            USHORT  Minimum;
            USHORT  Maximum;
            USHORT  MaximumBlocks;
        } ScalarPrefetch;
        struct {
            USHORT  Minimum;
            USHORT  Maximum;
        } BlockPrefetch;
    };
} DISK_CACHE_INFORMATION, *PDISK_CACHE_INFORMATION;

Members

ParametersSavable
Indicates whether the device is capable of saving any parameters in non-volatile storage.
ReadCacheEnabled
Indicates whether the read cache is enabled.
WriteCacheEnabled
Indicates whether the write cache is enabled.
ReadRetentionPriority
The value given this property determines the likelihood of various types of data remaining in the cache. By means of this value, for instance, data cached from a READ or WRITE operation might be given a different priority than that given data which is cached under other circumstances, such as prefetch operations. Thus a value of EqualPriority indicates that no data is held in the cache on a preferential basis. When ReadRetentionPriority is set to EqualPriority, then all types of data have equal access to cache memory. On the other hand, a value of KeepPrefetchedData indicates that a preference is to be given to prefetched data while a value of KeepReadData indicates that a preference is to be given to data cached from a READ operation.
WriteRetentionPriority
(See discussion under ReadRetentionPriority).
DisablePrefetchTransferLength
Prefetching might be disabled whenever the number of blocks requested exceeds the value in DisablePrefetchTransferLength. When zero, prefetching is disabled no matter what the size of the block request.
PrefetchScalar
If TRUE, then ScalarPrefetch.Maximum will be used together with the transfer length to calculate the amount of data that can be prefetched. If FALSE, then BlockPrefetch.Maximum will be maximum amount of data as an absolute number of disk blocks that can be prefetched.
ScalarPrefetch.Maximum
When PrefetchScalar is TRUE, this value will be a scalar multiplier of the transfer length of the request. When multiplied by the transfer length, it will yield the maximum amount of data that can be prefetched into the cache on a disk operation.
ScalarPrefetch.Minimum
When PrefetchScalar is TRUE, this value will be a scalar multiplier of the transfer length of the request. When multiplied by the transfer length, it will yield the minimum amount of data that can be prefetched into the cache on a disk operation.
BlockPrefetch.Maximum
When PrefetchScalar is FALSE, this value will indicate the maximum amount of data, as an absolute number of disk blocks, that can be prefetched into the cache on a disk operation.
BlockPrefetch.Minimum
When PrefetchScalar is FALSE, this value will indicate the minimum amount of data, as an absolute number of disk blocks, that can be prefetched into the cache on a disk operation.

Status Block

The Information field is set to the size of the block of status information being returned, sizeof(DISK_CACHE_INFORMATION). The Status field is set to STATUS_SUCCESS or possibly to STATUS_DEVICE_NOT_READY, STATUS_BUFFER_TOO_SMALL, STATUS_INSUFFICIENT_RESOURCES, STATUS_IO_DEVICE_ERROR, or STATUS_NOT_SUPPORTED.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.


IOCTL_DISK_GET_DRIVE_GEOMETRY

Operation

Returns information about the physical disk's geometry (media type, number of cylinders, tracks per cylinder, sectors per track, and bytes per sector).

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the buffer, which must be >= sizeof(DISK_GEOMETRY).

Output

The driver returns the DISK_GEOMETRY data in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the size in bytes of the returned data. The Status field can be set to STATUS_SUCCESS, or possibly to STATUS_UNRECOGNIZED_MEDIA, STATUS_INVALID_PARAMETER, STATUS_INVALID_DEVICE_REQUEST, STATUS_INFO_LENGTH_MISMATCH, STATUS_INSUFFICIENT_RESOURCES, or STATUS_BUFFER_TOO_SMALL.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.


IOCTL_DISK_GET_DRIVE_GEOMETRY_EX

Operation

Returns information about the physical disk's geometry (media type, number of cylinders, tracks per cylinder, sectors per track, and bytes per sector).

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the buffer, which must be >= sizeof(DISK_GEOMETRY_EX).

Output

The driver returns the DISK_GEOMETRY_EX data in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the size in bytes of the returned data. The Status field can be set to STATUS_SUCCESS, or possibly to STATUS_UNRECOGNIZED_MEDIA, STATUS_INVALID_PARAMETER, STATUS_INVALID_DEVICE_REQUEST, STATUS_INFO_LENGTH_MISMATCH, STATUS_INSUFFICIENT_RESOURCES, or STATUS_BUFFER_TOO_SMALL.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.


IOCTL_DISK_GET_DRIVE_LAYOUT

Operation

Returns information about the number of partitions, disk signature, and features of each partition on a disk. (Floppy drivers need not handle this request.)

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the buffer, which must be >= sizeof(DRIVE_LAYOUT_INFORMATION). Note that this structure contains a variable-sized array of PARTITION_INFORMATION elements.

Output

The driver returns the DRIVE_LAYOUT_INFORMATION data in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the size in bytes of the returned data. The Status field can be set to STATUS_SUCCESS, or possibly to STATUS_INFO_LENGTH_MISMATCH, STATUS_INSUFFICIENT_RESOURCES, or STATUS_BUFFER_TOO_SMALL.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.


IOCTL_DISK_GET_DRIVE_LAYOUT_EX

Operation

Returns information about the number of partitions, disk signature, and features of each partition on a disk. (Floppy drivers need not handle this request.)

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the buffer, which must be >= sizeof(DRIVE_LAYOUT_INFORMATION_EX). Note that this structure contains a variable-sized array of PARTITION_INFORMATION_EX elements.

Output

The driver returns the DRIVE_LAYOUT_INFORMATION data in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the size in bytes of the returned data. The Status field can be set to STATUS_SUCCESS, or possibly to STATUS_INFO_LENGTH_MISMATCH, STATUS_INSUFFICIENT_RESOURCES, or STATUS_BUFFER_TOO_SMALL.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.


IOCTL_DISK_GET_DRIVE_LETTERS

Operation

None. This IOCTL is obsolete.


IOCTL_DISK_GET_LENGTH_INFO

Operation

Returns the length, in bytes, of a disk, partition, or volume.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the buffer, which must be >= sizeof(GET_LENGTH_INFORMATION).

Output

The driver returns the GET_LENGTH_INFORMATION data in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the size in bytes of the returned data. The Status field can be set to STATUS_SUCCESS, or to STATUS_BUFFER_TOO_SMALL if the buffer supplied by the caller is inadequate.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.

See Also

GET_LENGTH_INFORMATION


IOCTL_DISK_GET_MEDIA_TYPES

Operation

This IOCTL is replaced by IOCTL_STORAGE_GET_MEDIA_TYPES. The only difference between the two IOCTLs is the base value.


IOCTL_DISK_GET_PARTITION_INFO

Operation

Returns information about the type, size, and nature of a disk partition. (Floppy drivers need not handle this request.)

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the buffer, which must be >= sizeof(PARTITION_INFORMATION).

Output

The driver returns the PARTITION_INFORMATION data in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the size in bytes of the returned data. The Status field can be set to STATUS_SUCCESS, or possibly to STATUS_INVALID_PARAMETER, STATUS_INFO_LENGTH_MISMATCH, STATUS_INSUFFICIENT_RESOURCES, STATUS_INVALID_DEVICE_REQUEST, or STATUS_BUFFER_TOO_SMALL.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.


IOCTL_DISK_GET_PARTITION_INFO_EX

Operation

Returns information about the type, size, and nature of a disk partition. (Floppy drivers need not handle this request.)

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the buffer, which must be >= sizeof(PARTITION_INFORMATION_EX).

Output

The driver returns the PARTITION_INFORMATION_EX data in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the size in bytes of the returned data. The Status field can be set to STATUS_SUCCESS, or possibly to STATUS_INVALID_PARAMETER, STATUS_INFO_LENGTH_MISMATCH, STATUS_INSUFFICIENT_RESOURCES, STATUS_INVALID_DEVICE_REQUEST, or STATUS_BUFFER_TOO_SMALL.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.


IOCTL_DISK_GROW_PARTITION

Operation

Used to increase the size of an existing partition. It is used in conjunction with IOCTL_DISK_UPDATE_DRIVE_SIZE to first extend a disk, so that it will contain a new free space area, and then to extend an existing partition on the disk into the newly attached free space. It takes a DISK_GROW_PARTITION structure as the only parameter. The space after the specified partition must be free in order for this operation to work. A partition cannot be extended over another existing partition.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the buffer made available to the driver, which must be >= sizeof(DISK_GROW_PARTITION). Otherwise, the driver returns with an error status of STATUS_BUFFER_TOO_SMALL.

The buffer at Irp->AssociatedIrp.SystemBuffer contains the DISK_GROW_PARTITION values which will be used to increase the size of the partition. The structure is defined as follows:

typedef struct _DISK_GROW_PARTITION {
  ULONG  PartitionNumber;
  LARGE_INTEGER  BytesToGrow;
} DISK_GROW_PARTITION, *PDISK_GROW_PARTITION;

Members

PartionNumber
Indicates an id number identifying the partition that is to be enlarged.
BytesToGrow
Indicates the number of bytes that the partition should be extended by. Note that this value is not the new size of the partition.

Output

None

Status Block

The Status field is set to STATUS_SUCCESS or possibly to STATUS_BUFFER_TOO_SMALL, STATUS_INVALID_PARAMETER, STATUS_UNSUCCESSFUL, or STATUS_DRIVER_INTERNAL_ERROR.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.


IOCTL_DISK_INTERNAL_SET_VERIFY

Operation

Allows a driver to set the verify bit on a disk device object if the mode of the caller is kernel mode.

Input

None

Output

None

Status Block

The Status field is set to STATUS_SUCCESS. If the mode of the requester is not kernel mode, the requested operation is not performed, but STATUS_SUCCESS is still returned.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.


IOCTL_DISK_INTERNAL_CLEAR_VERIFY

Operation

Allows a driver to clear the verify bit on a disk device object, if the mode of the caller is kernel mode.

Input

None

Output

None

Status Block

The Status field is set to STATUS_SUCCESS. If the mode of the requester is not kernel mode, the requested operation is not performed, but STATUS_SUCCESS is still returned.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.


IOCTL_DISK_IS_WRITABLE

Operation

Determines whether a disk is writable.

Input

None

Output

None

I/O Status Block

The Information field is set to zero. The Status field can be set to STATUS_SUCCESS, or possibly to STATUS_INSUFFICIENT_RESOURCES, STATUS_IO_DEVICE_ERROR, or STATUS_MEDIA_WRITE_PROTECTED.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.


IOCTL_DISK_PERFORMANCE

Operation

Increments a reference counter that enables the collection of disk performance statistics, such as the numbers of bytes read and written since the driver last processed this request, for a corresponding disk monitoring application. In Windows 2000 this IOCTL is handled by the filter driver diskperf. In Windows XP and later operating systems, the partition manager handles this request for disks and ftdisk.sys and dmio.sys handle this request for volumes. Caller must be running at IRQL = PASSIVE.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the buffer, which must be at least sizeof(DISK_PERFORMANCE).

Output

The driver returns the DISK_PERFORMANCE data in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to sizeof(DISK_PERFORMANCE) when the Status field is set to STATUS_SUCCESS. Otherwise, the Status field can be set to STATUS_INVALID_PARAMETER or STATUS_BUFFER_TOO_SMALL.

Headers

Defined in ntdddisk.h. Include ntdddisk.h

See Also

IOCTL_DISK_PERFORMANCE_OFF


IOCTL_DISK_PERFORMANCE_OFF

Operation

The IOCTL_DISK_PERFORMANCE_OFF request disables the counters that were enabled by previous calls to IOCTL_DISK_PERFORMANCE. This request is available in Windows® XP and later operating systems. Caller must be running at IRQL = PASSIVE_LEVEL.

Input

None

Output

None

I/O Status Block

The Information member is set to zero. The Status member is set to STATUS_SUCCESS if the operation was successful. Otherwise, the Status member is set to the appropriate error code.

Headers

Defined in ntdddisk.h. Include ntdddisk.h

See Also

IOCTL_DISK_PERFORMANCE


IOCTL_DISK_REASSIGN_BLOCKS

Operation

Maps defective blocks to new location on disk. This request instructs the the device to reassign the bad block address to a good block from its spare-block pool.

Input

The buffer at Irp->AssociatedIrp.SystemBuffer contains the REASSIGN_BLOCKS values to be set. Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the buffer, which must be >= sizeof(REASSIGN_BLOCKS). Note that this structure contains a variable-sized array of block numbers.

Output

None

I/O Status Block

The Information field is set to zero. The Status field can be set to STATUS_SUCCESS, or possibly to STATUS_INFO_LENGTH_MISMATCH, STATUS_INSUFFICIENT_RESOURCES, or STATUS_BUFFER_TOO_SMALL.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.

See Also

REASSIGN_BLOCKS


IOCTL_DISK_SET_CACHE_INFORMATION

Operation

Sets disk cache configuration data.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the buffer made available to the driver, which must be >= sizeof(DISK_CACHE_INFORMATION). Otherwise, the driver returns with an error status of STATUS_BUFFER_TOO_SMALL.

Output

The device driver returns disk cache data in the buffer at Irp->AssociatedIrp.SystemBuffer. The data is structured as follows:

The device driver returns the DISK_CACHE_INFORMATION in the buffer at Irp->AssociatedIrp.SystemBuffer. For a definition of this see the manual page entry for IOCTL_DISK_GET_CACHE_INFORMATION.

ParametersSavable
Indicates whether the device is capable of saving any parameters in non-volatile storage.
ReadCacheEnabled
Indicates whether the read cache is enabled.
WriteCacheEnabled
Indicates whether the write cache is enabled.
ReadRetentionPriority
The value given this property determines the likelihood of various types of data remaining in the cache. By means of this value, for instance, data cached from a READ or WRITE operation may be given a different priority than that given data which is cached under other circumstances, such as prefetch operations. Thus a value of EqualPriority indicates that no data is held in the cache on a preferential basis. When ReadRetentionPriority is set to EqualPriority, then all types of data have equal access to cache memory. On the other hand, a value of KeepPrefetchedData indicates that a preference is to be given to prefetched data while a value of KeepReadData indicates that a preference is to be given to data cached from a READ operation.
WriteRetentionPriority
(See discussion under ReadRetentionPriority).
DisablePrefetchTransferLength
Prefetching might be disabled whenever the number of blocks requested exceeds the value in DisablePrefetchTransferLength. When zero, prefetching is disabled no matter what the size of the block request.
PrefetchScalar
If TRUE, then ScalarPrefetch.Maximum will be used together with the transfer length to calculate the amount of data that can be prefetched. If FALSE, then BlockPrefetch.Maximum will be maximum amount of data as an absolute number of disk blocks that can be prefetched.
ScalarPrefetch.Maximum
When PrefetchScalar is TRUE, this value will be a scalar multiplier of the transfer length of the request. When multiplied by the transfer length, it will yield the maximum amount of data that can be prefetched into the cache on a disk operation.
ScalarPrefetch.Minimum
When PrefetchScalar is TRUE, this value will be a scalar multiplier of the transfer length of the request. When multiplied by the transfer length, it will yield the minimum amount of data that can be prefetched into the cache on a disk operation.
BlockPrefetch.Maximum
When PrefetchScalar is FALSE, this value will indicate the maximum amount of data, as an absolute number of disk blocks, that can be prefetched into the cache on a disk operation.
BlockPrefetch.Minimum
When PrefetchScalar is FALSE, this value will indicate the minimum amount of data, as an absolute number of disk blocks, that can be prefetched into the cache on a disk operation.

Status Block

To be done.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.


IOCTL_DISK_SET_DRIVE_LAYOUT

Operation

Repartitions a disk as specified. (Floppy drivers need not handle this request.)

Input

The buffer at Irp->AssociatedIrp.SystemBuffer contains the DRIVE_LAYOUT_INFORMATION values to be set. Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the buffer, which must be >= sizeof(DRIVE_LAYOUT_INFORMATION).

Output

Returns updated DRIVE_LAYOUT_INFORMATION, possibly with modified partition numbers, to the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the size in bytes of the returned information. The Status field can be set to STATUS_SUCCESS, or possibly to STATUS_INVALID_PARAMETER, STATUS_INFO_LENGTH_MISMATCH, STATUS_INSUFFICIENT_RESOURCES, or STATUS_BUFFER_TOO_SMALL.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.

See Also

DRIVE_LAYOUT_INFORMATION


IOCTL_DISK_SET_DRIVE_LAYOUT_EX

Operation

Repartitions a disk as specified. (Floppy drivers need not handle this request.)

Input

The buffer at Irp->AssociatedIrp.SystemBuffer contains the DRIVE_LAYOUT_INFORMATION_EX values to be set. Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the buffer, which must be >= sizeof(DRIVE_LAYOUT_INFORMATION_EX).

Output

Returns updated DRIVE_LAYOUT_INFORMATION_EX, possibly with modified partition numbers, to the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the size in bytes of the returned information. The Status field can be set to STATUS_SUCCESS, or possibly to STATUS_INVALID_PARAMETER, STATUS_INFO_LENGTH_MISMATCH, STATUS_INSUFFICIENT_RESOURCES, or STATUS_BUFFER_TOO_SMALL.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.

See Also

DRIVE_LAYOUT_INFORMATION_EX


IOCTL_DISK_SET_PARTITION_INFO

Operation

Changes the partition type of the specified disk partition. (Floppy drivers need not handle this request.)

Input

The buffer at Irp->AssociatedIrp.SystemBuffer contains the SET_PARTITION_INFORMATION to be set. Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size of the buffer, which must be >= sizeof(SET_PARTITION_INFORMATION).

Output

None

I/O Status Block

The Information field is set to zero. The Status field can be set to STATUS_SUCCESS, or possibly to STATUS_INVALID_PARAMETER, STATUS_INVALID_DEVICE_REQUEST, STATUS_UNSUCCESSFUL, STATUS_INFO_LENGTH_MISMATCH, STATUS_INSUFFICIENT_RESOURCES, or STATUS_BUFFER_TOO_SMALL.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.

See Also

SET_PARTITION_INFORMATION


IOCTL_DISK_SET_PARTITION_INFO_EX

Operation

Changes the partition type of the specified disk partition. (Floppy drivers need not handle this request.)

Input

The buffer at Irp->AssociatedIrp.SystemBuffer contains the SET_PARTITION_INFORMATION_EX to be set. Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size of the buffer, which must be >= sizeof(SET_PARTITION_INFORMATION_EX).

Output

None

I/O Status Block

The Information field is set to zero. The Status field can be set to STATUS_SUCCESS, or possibly to STATUS_INVALID_PARAMETER, STATUS_INVALID_DEVICE_REQUEST, STATUS_UNSUCCESSFUL, STATUS_INFO_LENGTH_MISMATCH, STATUS_INSUFFICIENT_RESOURCES, or STATUS_BUFFER_TOO_SMALL.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.

See Also

SET_PARTITION_INFORMATION_EX


IOCTL_DISK_UPDATE_DRIVE_SIZE

Operation

Updates device extension with drive size information for current media.

Input

None

Output

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the buffer made available to the driver, which must be >= sizeof(DISK_GEOMETRY). Otherwise, the driver returns with an error status of STATUS_BUFFER_TOO_SMALL.

The device driver returns the DISK_GEOMETRY structure in the buffer at Irp->AssociatedIrp.SystemBuffer. This structure is defined as follows:

typedef struct _DISK_GEOMETRY {
  LARGE_INTEGER  Cylinders;
  MEDIA_TYPE  MediaType;
  ULONG  TracksPerCylinder;
  ULONG  SectorsPerTrack;
  ULONG  BytesPerSector;
} DISK_GEOMETRY, *PDISK_GEOMETRY;

Members

MediaType
Indicates whether the disk is RemovableMedia or FixedMedia.
Cylinders
Indicates the number of cylinders on the disk device.
TracksPerCylinder
Indicates the number of tracks in a cylinder.
SectorsPerTrack
Indicates the number of sectors in each track.
BytesPerSector
Indicates the number of bytes in a disk sector.

Status Block

The Information field is set to the size of the block of disk geometry information being returned, sizeof(DISK_GEOMETRY). The Status field is set to STATUS_SUCCESS or possibly to STATUS_BUFFER_TOO_SMALL, STATUS_INSUFFICIENT_RESOURCES, STATUS_IO_DEVICE_ERROR, or STATUS_DEVICE_NOT_READY.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.

See Also

DISK_GEOMETRY


IOCTL_DISK_VERIFY

Operation

The IOCTL_DISK_VERIFY requests performs a logical format of a specified extent on a disk.

Input

The buffer at Irp->AssociatedIrp.SystemBuffer contains the VERIFY_INFORMATION data specifying the starting offset and length to be verified. Parameters.DeviceIoControl.InputBufferLength indicates the size in bytes of the buffer, which must be >= sizeof(VERIFY_INFORMATION).

Output

None

I/O Status Block

The Information field is set to the number of bytes verified when the Status field is set to STATUS_SUCCESS. Otherwise, the Status field can be set to STATUS_BUFFER_TOO_SMALL, STATUS_INFO_LENGTH_MISMATCH, STATUS_INVALID_PARAMETER, STATUS_INSUFFICIENT_RESOURCES, STATUS_NONEXISTENT_SECTOR, STATUS_DEVICE_DATA_ERROR, STATUS_INVALID_DEVICE_REQUEST, STATUS_IO_TIMEOUT, or STATUS_DEVICE_NOT_CONNECTED.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.

See Also

VERIFY_INFORMATION


IOCTL_SCSI_GET_DUMP_POINTERS

Operation

The system-supplied storage port drivers and atdisk driver support this request. Any replacement driver that controls a disk used for the paging file must support this request.

This request is issued during system initialization. The driver must return configuration parameters that are used if a system crash occurs to dump memory to the paging file. The DUMP_POINTERS structure describes these configuration parameters, and the driver must set all parameters appropriately to its disk. Each pointer must be a valid pointer or NULL; each size must be a valid size or zero.

Input

None

Output

The driver returns the DUMP_POINTERS parameters in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The driver sets Irp->IoStatus.Information to sizeof(DUMP_POINTERS). The driver sets the Status field to STATUS_SUCCESS or possibly to STATUS_BUFFER_TOO_SMALL, STATUS_INVALID_PARAMETER, or STATUS_NOT_SUPPORTED. An error return indicates that the crash dump functionality is disabled and no memory dump is produced if a system failure occurs.

Headers

Defined in ntddscsi.h; Include ntddscsi.h.


IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS

Operation

Returns the physical location(s) of a volume on one or more disks.

Input

None

Output

The driver returns a VOLUME_DISK_EXTENTS structure in the buffer at Irp->AssociatedIrp.SystemBuffer, which must be at least sizeof(VOLUME_DISK_EXTENTS). This structure is defined as follows:

typedef struct _VOLUME_DISK_EXTENTS {
    ULONG NumberOfDiskExtents;
    DISK_EXTENT Extents[1];
} VOLUME_DISK_EXTENTS, *PVOLUME_DISK_EXTENTS;
NumberOfDiskExtents
The number of extents that comprise the volume, which can span multiple disks. An extent is a contiguous run of sectors on one disk.
Extents
An array of DISK_EXTENT structures that indicate the physical location of a given extent. This structure is defined as follows:
typedef struct _DISK_EXTENT {
    ULONG DiskNumber;
    LARGE_INTEGER StartingOffset;
    LARGE_INTEGER ExtentLength;
} DISK_EXTENT, *PDISK_EXTENT;
DiskNumber
The number of the disk that contains this extent. This is the same disk number that is used to construct the name of the disk (for example, PhysicalDriveX or HarddiskX).
StartingOffset
The offset in bytes from the beginning of the disk.
ExtentLength
The number of bytes of this extent.

I/O Status Block

The driver sets Irp->IoStatus.Information and the Status field as follows:

  • If the buffer at Irp->AssociatedIrp.SystemBuffer is < sizeof(VOLUME_DISK_EXTENTS), the driver sets Irp->IoStatus.Information to zero and returns STATUS_INVALID_PARAMETER.
  • If the buffer at Irp->AssociatedIrp.SystemBuffer is at least sizeof(VOLUME_DISK_EXTENTS) but too small for all data to be returned, the driver sets sets Irp->IoStatus.Information to sizeof(VOLUME_DISK_EXTENTS) and sets Status to STATUS_BUFFER_OVERFLOW.
  • If the buffer at Irp->AssociatedIrp.SystemBuffer is large enough for all data to be returned, the driver sets Irp->IoStatus.Information to sizeof(VOLUME_DISK_EXTENTS) + ((NumberOfDiskExtents – 1) * sizeof(DISK_EXTENT)) and sets Status to STATUS_SUCCESS.

Headers

Defined in ntddvol.h; Include ntddvol.h.


SMART_GET_VERSION

Operation

Returns version information, a capabilities mask, and a bitmask for the device. This IOCTL must be handled by drivers that support Self-Monitoring Analysis and Reporting Technology (SMART).

Input

Parameters.DeviceIoControl.OutputBufferLength indicates the size in bytes of the buffer, which must be >= sizeof(GETVERSIONINPARAMS).

Output

The driver returns the information to the buffer at
Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The driver sets the Information field to sizeof(GETVERSIONINPARAMS) when it sets the Status field to STATUS_SUCCESS. Otherwise, the driver sets the Information field to zero and sets the Status field to possibly STATUS_INVALID_PARAMETER.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.


SMART_RCV_DRIVE_DATA

Operation

Returns the ATA-2 identify data, the SMART thresholds, or the SMART attributes for the device. This IOCTL must be handled by drivers that support SMART.

Input

The buffer at Irp->AssociatedIrp.SystemBuffer contains a SENDCMDINPARAMS structure that describes the request being sent to the device. The irDriveRegs.bCommandReg member specifies ID_CMD when identify data is requested and SMART_CMD when SMART data is requested. If SMART data is requested, the irDriveRegs.bFeaturesReg member specifies either READ_ATTRIBUTES or READ_THRESHOLDS.

Parameters.DeviceIoControl.InputBufferLength specifies the size in bytes of the input buffer, which must be >= (sizeof(SENDCMDINPARAMS) – 1).

Parameters.DeviceIoControl.OutputBufferLength specifies the size in bytes of the output buffer, which must be >= (sizeof(SENDCMDOUTPARAMS) – 1 + 512).

Output

The driver returns the SENDCMDOUTPARAMS structure and a 512-byte buffer of drive data to the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The driver sets the Information field to (sizeof(SENDCMDOUTPARAMS) – 1 + 512) when it sets the Status field to STATUS_SUCCESS. Otherwise, the driver sets the Information field to zero and the Status field to possibly STATUS_INVALID_PARAMETER or STATUS_INSUFFICIENT_RESOURCES.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.


SMART_SEND_DRIVE_COMMAND

Operation

Sends one of the following SMART commands to the device:

  • Enable or disable reporting on the device
  • Enable or disable autosaving of attributes
  • Save current attributes now
  • Execute offline diagnostics
  • Get current SMART status

This IOCTL must be handled by drivers that support SMART.

Input

The buffer at Irp->AssociatedIrp.SystemBuffer contains a SENDCMDINPARAMS structure that describes the command being sent to the device. The irDriveRegs.bCommandReg member must specify SMART_CMD. The irDriveRegs.bFeaturesReg member must specify one of ENABLE_SMART, DISABLE_SMART, ENABLE_DISABLE_AUTOSAVE, SAVE_ATTRIBUTE_VALUES, EXECUTE_OFFLINE_DIAG, or RETURN_SMART_STATUS.

Parameters.DeviceIoControl.InputBufferLength specifies the size in bytes of the input buffer, which must be >= (sizeof(SENDCMDINPARAMS) – 1).

Parameters.DeviceIoControl.OutputBufferLength specifies the size in bytes of the output buffer, which must be >= (sizeof(SENDCMDOUTPARAMS) – 1). If SMART status is being requested, the output buffer must be >= (sizeof(SENDCMDOUTPARAMS) – 1 + sizeof(IDEREGS)).

Output

The driver returns the SENDCMDOUTPARAMS structure to the buffer at
Irp->AssociatedIrp.SystemBuffer. If SMART status was requested, and successfully received from the device, the driver includes the IDEREGS structure in the output buffer.

I/O Status Block

When the driver sets the Status field to STATUS_SUCCESS, it sets the Information field is set to ((sizeof(SENDCMDOUTPARAMS) – 1) + sizeof(IDEREGS)) for returning SMART status and to (sizeof(SENDCMDOUTPARAMS) – 1) for all other commands. The driver should set the Status field to STATUS_INVALID_PARAMETER if an input parameter is incorrect or to STATUS_IO_DEVICE_ERROR if the device aborts a command it does not support. If Status is not STATUS_SUCCESS, the driver sets the Information field to zero.

Headers

Defined in ntdddisk.h; Include ntdddisk.h.


CD-ROM I/O Control Codes

All public I/O control codes for drivers of CD-ROM devices use buffered I/O. Consequently, the input or output data for these requests is at Irp->AssociatedIrp.SystemBuffer.

Class drivers for CD-ROM devices handle additional public I/O control codes, along with those described in this section. See Mass Storage Device I/O Control Codes for more information about requirements for storage class drivers.


IOCTL_CDROM_CHECK_VERIFY

Operation

This IOCTL is replaced by IOCTL_STORAGE_CHECK_VERIFY. The only difference between the two IOCTLs is the base value.


IOCTL_CDROM_CLOSE_DOOR

Operation

None. This I/O control code has been replaced by IOCTL_STORAGE_LOAD_MEDIA, described in Mass Storage Device I/O Control Codes.


IOCTL_CDROM_FIND_NEW_DEVICES

Operation

This IOCTL is replaced by IOCTL_STORAGE_FIND_NEW_DEVICES. The only difference between the two IOCTLs is the base value.


IOCTL_CDROM_GET_CONTROL

Operation

The driver determines the current audio playback mode.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location indicates the size in bytes of the buffer, which must be >= sizeof(CDROM_AUDIO_CONTROL).

Output

The driver returns the CDROM_AUDIO_CONTROL data in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the number of bytes returned. The Status field is set to STATUS_SUCCESS or possibly to STATUS_BUFFER_TOO_SMALL, STATUS_DEVICE_NOT_READY, STATUS_IO_DEVICE_ERROR, STATUS_IO_TIMEOUT, STATUS_INSUFFICIENT_RESOURCES, STATUS_VERIFY_REQUIRED, or STATUS_INVALID_DEVICE_REQUEST.

Headers

Defined in ntddcdrm.h; Include ntddcdrm.h.


IOCTL_CDROM_GET_DRIVE_GEOMETRY

Operation

IOCTL_CDROM_GET_DRIVE_GEOMETRY returns information about the CDROM's geometry (media type, number of cylinders, tracks per cylinder, sectors per track, and bytes per sector).

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the buffer, which must be >= sizeof(DISK_GEOMETRY).

Output

The driver returns the DISK_GEOMETRY-type information in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the size in bytes of the returned data. The Status field is set to STATUS_SUCCESS or possibly to STATUS_UNRECOGNIZED_MEDIA, STATUS_INVALID_PARAMETER, STATUS_INFO_LENGTH_MISMATCH, or STATUS_BUFFER_TOO_SMALL.

Headers

Defined in ntddcdrm.h; Include ntddcdrm.h.


IOCTL_CDROM_GET_LAST_SESSION

Operation

The driver determines whether a disc is multisession. It compares the first and last session and the starting track of the last session. If the first session is the same as the last, the disc is not multisession. If the disc is multisession, the driver stores session block addresses in the table of contents.

Input

None

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INVALID_DEVICE_REQUEST, STATUS_DEVICE_BUSY, STATUS_DEVICE_NOT_READY, STATUS_IO_TIME_OUT, or STATUS_VERIFY_REQUIRED.

Headers

Defined in ntddcdrm.h; Include ntddcdrm.h.


IOCTL_CDROM_GET_VOLUME

Operation

The driver determines the current volume for each of its device's audio ports.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location indicates the size in bytes of the buffer, which must be >= sizeof(CDROM_VOLUME_CONTROL).

Output

The driver returns the CDROM_VOLUME_CONTROL data in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to sizeof(CDROM_VOLUME_CONTROL) when the Status field is set to STATUS_SUCCESS. Otherwise, the Information field is set to zero, and the Status field possibly can be set to STATUS_BUFFER_TOO_SMALL, STATUS_DEVICE_NOT_READY, STATUS_IO_DEVICE_ERROR, STATUS_VERIFY_REQUIRED, or STATUS_IO_TIMEOUT.

Headers

Defined in ntddcdrm.h; Include ntddcdrm.h.


IOCTL_CDROM_PAUSE_AUDIO

Operation

Suspends audio play.

Input

None

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INVALID_DEVICE_REQUEST if audio is not currently playing, STATUS_IO_DEVICE_ERROR, STATUS_NO_MEDIA_IN_DEVICE, STATUS_DEVICE_NOT_READY, STATUS_IO_TIME_OUT, or STATUS_VERIFY_REQUIRED.

Headers

Defined in ntddcdrm.h; Include ntddcdrm.h.


IOCTL_CDROM_PLAY_AUDIO_MSF

Operation

Plays the specified range of the media.

Input

The buffer at Irp->AssociatedIrp.System buffer contains the starting and ending MSF values. Parameters.DeviceIoControl.InputBufferLength in the I/O stack location indicates the size in bytes of the buffer, which must be >= sizeof(CDROM_PLAY_AUDIO_MSF).

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INVALID_DEVICE_REQUEST, STATUS_BUFFER_TOO_SMALL, STATUS_DEVICE_NOT_READY, STATUS_IO_DEVICE_ERROR, STATUS_IO_TIME_OUT, or STATUS_VERIFY_REQUIRED.

Headers

Defined in ntddcdrm.h; Include ntddcdrm.h.


IOCTL_CDROM_RAW_READ

Operation

Reads data from the CD-ROM in raw mode.

Input

If the IOCTL is from user mode, Irp->AssociatedIrp.SystemBuffer contains a structure that specifies the starting disk offset, the sector count, and the track mode (XA or CDDA) for the read. Parameters.DeviceIoControl.InputBufferLength specifies the size in bytes of the structure, which must be >= sizeof(RAW_READ_INFO). Parameters.DeviceIoControl.OutputBufferLength specifies the size of the buffer to be read, which must be >= sizeof(SectorCount * RAW_SECTOR_SIZE).

If the IOCTL is from kernel mode, Parameters.DeviceIoControl.Type3InputBuffer contains a structure that specifies the starting disk offset, the sector count, and the track mode (XA or CDDA) for the read. Parameters.DeviceIoControl.OutputBufferLength specifies the size of the buffer to be read, which must be >= sizeof(SectorCount * RAW_SECTOR_SIZE).

Output

The driver writes the requested bytes directly (using DMA or PIO) to the buffer described by the MDL at Irp->MdlAddress.

I/O Status Block

If the read is successful, the driver sets Status to STATUS_SUCCESS and Information to the number of bytes transferred. If the read is not successful, the driver sets Information to zero and Status to possibly STATUS_INVALID_PARAMETER, STATUS_INSUFFICIENT_RESOURCES, or STATUS_INVALID_DEVICE_REQUEST.

Headers

Defined in ntddcdrm.h; Include ntddcdrm.h.


IOCTL_CDROM_READ_Q_CHANNEL

Operation

Returns the current position, media catalog, or ISRC track data.

Input

The buffer at Irp->AssociatedIrp.SystemBuffer contains a CDROM_SUB_Q_DATA_FORMAT structure with the Format member set to one of the following:

IOCTL_CDROM_CURRENT_POSITION

IOCTL_CDROM_MEDIA_CATALOG

IOCTL_CDROM_TRACK_ISRC

If Format is set to IOCTL_CDROM_TRACK_ISRC, Track must be set to the track for which ISRC data is requested.

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location indicates the size in bytes of the buffer, which must be >= sizeof(SUB_Q_CHANNEL_DATA).

Output

The driver returns the SUB_Q_CHANNEL_DATA information in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the number of bytes returned. The Status field is set to STATUS_SUCCESS or possibly to STATUS_BUFFER_TOO_SMALL, STATUS_IO_DEVICE_ERROR, STATUS_INSUFFICIENT_RESOURCES, STATUS_INVALID_DEVICE_REQUEST, STATUS_NO_MEDIA_IN_DEVICE, STATUS_DEVICE_NOT_READY, STATUS_IO_TIME_OUT, or STATUS_VERIFY_REQUIRED.

Headers

Defined in ntddcdrm.h; Include ntddcdrm.h.

See Also

SUB_Q_CHANNEL_DATA


IOCTL_CDROM_READ_TOC

Operation

Returns the table of contents of the media.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location indicates the size in bytes of the buffer, which must be >= sizeof(CDROM_TOC).

Output

The driver returns the CDROM_TOC data in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the number of bytes returned. The Status field is set to STATUS_SUCCESS or possibly to STATUS_BUFFER_TOO_SMALL, STATUS_NO_MEDIA_IN_DEVICE, STATUS_DEVICE_NOT_READY, STATUS_IO_TIMEOUT, STATUS_IO_DEVICE_ERROR, STATUS_DEVICE_BUSY, or STATUS_VERIFY_REQUIRED.

Headers

Defined in ntddcdrm.h; Include ntddcdrm.h.

See Also

CDROM_TOC


IOCTL_CDROM_READ_TOC_EX

Operation

This IOCTL requests queries the target device for the Table of Contents (TOC), the Program Memory Area (PMA), and the Absolute Time in Pre-Groove (ATIP). If the media is not a CD ROM and does not support a TOC, this IOCTL returns information similar to that of a CD ROM TOC. This is required for compatibility with some legacy Initiator environments. This request is available in Windows XP and later operating systems.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location indicates the size in bytes of the output buffer, which must be >= MINIMUM_CDROM_READ_TOC_EX_SIZE.

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location indicates the size in bytes of the input buffer, which must be >= sizeof(CDROM_READ_TOC_EX).

Irp->AssociatedIrp.SystemBuffer points to a buffer of type CDROM_READ_TOC_EX whose contents indicate what information should be retrieved from the target device.

Parameters.Read.Length in the I/O stack location indicates the size in bytes of the information to be retrieved from the target device.

Output

The driver returns the query data in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the number of bytes returned. The Status field is set to STATUS_SUCCESS or possibly to STATUS_BUFFER_TOO_SMALL or STATUS_INSUFFICIENT_RESOURCES.

Headers

Defined in Ntddcdrm.h; Include Ntddcdrm.h

See Also

CDROM_READ_TOC_EX


IOCTL_CDROM_RESUME_AUDIO

Operation

Resumes a suspended audio operation.

Input

None

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INVALID_DEVICE_REQUEST if audio is not currently suspended, STATUS_IO_DEVICE_ERROR, STATUS_NO_MEDIA_IN_DEVICE, STATUS_DEVICE_NOT_READY, STATUS_IO_TIME_OUT, or STATUS_VERIFY_REQUIRED.

Headers

Defined in ntddcdrm.h; Include ntddcdrm.h.


IOCTL_CDROM_SEEK_AUDIO_MSF

Operation

Moves the heads to the specified MSF on the media.

Input

The buffer at Irp->AssociatedIrp.SystemBuffer contains the CDROM_SEEK_AUDIO_MSF specification. Parameters.DeviceIoControl.InputBufferLength indicates the size in bytes of the buffer.

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS or possibly to STATUS_BUFFER_TOO_SMALL, STATUS_INVALID_DEVICE_REQUEST, STATUS_IO_DEVICE_ERROR, STATUS_NO_MEDIA_IN_DEVICE, STATUS_DEVICE_NOT_READY, STATUS_IO_TIME_OUT, or STATUS_VERIFY_REQUIRED.

Headers

Defined in ntddcdrm.h; Include ntddcdrm.h.

See Also

CDROM_SEEK_AUDIO_MSF


IOCTL_CDROM_SET_VOLUME

Operation

The driver resets the volume for its device's audio ports.

Input

The buffer at Irp->AssociatedIrp.SystemBuffer contains the CDROM_VOLUME_CONTROL value(s) to be set. Parameters.DeviceIoControl.InputBufferLength in the I/O stack location indicates the size in bytes of the buffer, which must be >= sizeof(CDROM_VOLUME_CONTROL).

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS or possibly to STATUS_BUFFER_TOO_SMALL, STATUS_DEVICE_NOT_READY, STATUS_IO_TIMEOUT, STATUS_IO_DEVICE_ERROR, STATUS_VERIFY_REQUIRED, or STATUS_INVALID_DEVICE_REQUEST.

Headers

Defined in ntddcdrm.h; Include ntddcdrm.h.


IOCTL_CDROM_STOP_AUDIO

Operation

Ends audio play.

Input

None

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INVALID_DEVICE_REQUEST if audio is not currently playing, STATUS_IO_DEVICE_ERROR, STATUS_NO_MEDIA_IN_DEVICE, STATUS_DEVICE_NOT_READY, STATUS_IO_TIME_OUT, or STATUS_VERIFY_REQUIRED.

Headers

Defined in ntddcdrm.h; Include ntddcdrm.h.


DVD I/O Control Codes

All public I/O control codes for drivers of DVD devices use buffered I/O. Consequently, the input or output data for these requests is at Irp->AssociatedIrp.SystemBuffer.

Class drivers for DVD devices handle all public I/O control codes for CD-ROM devices and additional public I/O control codes for storage devices, along with those described in this section. See Mass Storage Device I/O Control Codes for information about I/O control codes for CD-ROM devices. See Mass Storage Device I/O Control Codes for more information about requirements for storage class drivers.


IOCTL_DVD_END_SESSION

Operation

Ends a DVD session by invalidating its authentication grant ID (AGID).

Input

The buffer at Irp->AssociatedIrp.SystemBuffer contains the session ID.

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS.

Headers

Defined in ntddcdvd.h; Include ntddcdvd.h.


IOCTL_DVD_GET_REGION

Operation

Returns Region Playback Control (RPC) information for a DVD device, such as whether the player supports the RPC2 standard, the current region code of the player, and the remaining number of times the player's region code can be changed by the user. It also indicates the region code of the currently mounted disc.

Input

None. Parameters.DeviceIoControl.OutputBufferLength indicates the size in bytes of the buffer at Irp->AssociatedIrp.SystemBuffer, which must be >= sizeof(DVD_REGION).

Output

The driver returns the DVD_REGION data in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the number of bytes transferred. The Status field is set to STATUS_SUCCESS or possibly STATUS_INSUFFICIENT_RESOURCES.

Headers

Defined in ntddcdvd.h; Include ntddcdvd.h.


IOCTL_DVD_READ_KEY

Operation

Returns a copy-protection key of the specified type: challenge key, bus key, title key, read RPC key, set RPC key, or disk key. A challenge key or bus key is sent back to the device to complete the related step in a DVD authentication sequence. After the authentication sequence is completed, a title key is used to encrypt and decrypt user data transferred from a DVD disc, and a disk key is used to encrypt and decrypt title key data.

Input

The buffer at Irp->AssociatedIrp.SystemBuffer contains a DVD_COPY_PROTECT_KEY structure that indicates the session ID of the DVD session and the type of key to return. Parameters.DeviceIoControl.OutputBufferLength indicates the size in bytes of the buffer, which must be >= the size of one of the following: DVD_CHALLENGE_KEY_LENGTH, DVD_BUS_KEY_LENGTH, DVD_TITLE_KEY_LENGTH, DVD_RPC_KEY_LENGTH, DVD_SET_RPC_KEY_LENGTH, or DVD_DISK_KEY_LENGTH.

Output

The driver returns the DVD_COPY_PROTECT_KEY data in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the number of bytes transferred. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INSUFFICIENT_RESOURCES.

Headers

Defined in ntddcdvd.h; Include ntddcdvd.h.


IOCTL_DVD_READ_STRUCTURE

Operation

Returns information about a DVD disc, such as a layer descriptor, copyright information, or manufacturer-specific information.

Input

The buffer at Irp->AssociatedIrp.SystemBuffer contains a DVD_READ_STRUCTURE structure that indicates the session ID and type of information to return. Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location indicates the size in bytes of the buffer, which must be >= sizeof(Descriptor) where Descriptor is DVD_LAYER_DESCRIPTOR, DVD_COPYRIGHT_DESCRIPTOR, DVD_DISK_KEY_DESCRIPTOR, DVD_BCA_DESCRIPTOR, or DVD_MANUFACTURER_DESCRIPTOR.

Output

The driver returns the disc information in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the number of bytes transferred. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INSUFFICIENT_RESOURCES.

Headers

Defined in ntddcdvd.h; Include ntddcdvd.h.


IOCTL_DVD_SEND_KEY

Operation

Sends the specified key to a DVD device in order to complete the related step in an authentication sequence.

Input

The buffer at Irp->AssociatedIrp.SystemBuffer contains a DVD_COPY_PROTECT_KEY structure that indicates the session ID, key type, and key to be sent to the device.

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INSUFFICIENT_RESOURCES.

Headers

Defined in ntddcdvd.h; Include ntddcdvd.h.


IOCTL_DVD_START_SESSION

Operation

Returns an authentication grant ID (AGID) as a DVD session ID, which a caller must pass to the device in all subsequent operations in a DVD session.

Input

None

Output

The driver returns a DVD_SESSION_ID structure in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to sizeof(DVD_SESSION_ID). The Status field is set to STATUS_SUCCESS or possibly to STATUS_INSUFFICIENT_RESOURCES.

Headers

Defined in ntddcdvd.h; Include ntddcdvd.h.


IOCTL_STORAGE_SET_READ_AHEAD

Operation

Skip to the given a target address when the device reaches a certain trigger address during read-ahead cacheing.

Input

The buffer at Irp->AssociatedIrp.SystemBuffer contains a STORAGE_SET_READ_AHEAD structure that indicates the trigger and target addresses.

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS.

Headers

Defined in ntddcdvd.h; Include ntddcdvd.h.


Tape I/O Control Codes

All public I/O control codes for drivers of tape devices use buffered I/O. Consequently, the input or output data for these requests is at Irp->AssociatedIrp.SystemBuffer.

Class drivers for tape devices handle additional public I/O control codes, along with those described in this section. See Mass Storage Device I/O Control Codes for more information about requirements for storage class drivers.


IOCTL_TAPE_CHECK_VERIFY

Operation

This IOCTL is replaced by IOCTL_STORAGE_CHECK_VERIFY. The only difference between the two IOCTLs is the base value.


IOCTL_TAPE_CREATE_PARTITION

Operation

Creates the specified number of fixed, select, or initiator partition(s) of the given size on the media.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location indicates the size in bytes of the parameter buffer, which must be >= sizeof(TAPE_CREATE_PARTITION). The buffer at Irp->AssociatedIrp.SystemBuffer specifies the partition(s) to be created. For a description of TAPE_CREATE_PARTITION see TapeMiniCreatePartition.

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS or possibly to STATUS_IO_DEVICE_ERROR, STATUS_MEDIA_WRITE_PROTECTED, STATUS_DEVICE_DATA_ERROR, STATUS_NO_SUCH_DEVICE, STATUS_IO_TIMEOUT, STATUS_DEVICE_NOT_READY, STATUS_INFO_LENGTH_MISMATCH, STATUS_NO_MEDIA_IN_DEVICE, or STATUS_VERIFY_REQUIRED.

Headers

Defined in ntddtape.h; Include ntddtape.h.


IOCTL_TAPE_ERASE

Operation

Erases the current tape partition, either as a TAPE_ERASE_LONG (a.k.a. "secure") operation that overwrites data with a pattern or as a TAPE_ERASE_SHORT (a.k.a. "quick") operation that writes an end-of-recorded-data mark at the current position.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location indicates the size in bytes of the parameter buffer, which must be >= sizeof(TAPE_ERASE). If the Immediate member is TRUE, the operation should be asynchronous. For a description of the TAPE_ERASE structure see TapeMiniErase.

Output

None

I/O Status Block

The Information field is set to the number of bytes transferred. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INFO_LENGTH_MISMATCH, STATUS_DEVICE_DATA_ERROR, STATUS_NO_SUCH_DEVICE, STATUS_IO_TIMEOUT, STATUS_IO_DEVICE_ERROR, STATUS_MEDIA_WRITE_PROTECTED, STATUS_INSUFFICIENT_RESOURCES, STATUS_NOT_IMPLEMENTED, STATUS_NO_MEDIA_IN_DEVICE, or STATUS_VERIFY_REQUIRED.

Headers

Defined in ntddtape.h; Include ntddtape.h.


IOCTL_TAPE_FIND_NEW_DEVICES

Operation

This IOCTL is replaced by IOCTL_STORAGE_FIND_NEW_DEVICES. The only difference between the two IOCTLs is the base value.


IOCTL_TAPE_GET_MEDIA_PARAMS

Operation

Returns information about the media's total and remaining capacity, its block size, the number of partitions, and whether it is write-protected.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location indicates the size in bytes of the parameter buffer, which must be >= sizeof(TAPE_GET_MEDIA_PARAMETERS).

Output

The driver returns the TAPE_GET_MEDIA_PARAMETERS data in the buffer at Irp->AssociatedIrp.SystemBuffer. For a description of the TAPE_GET_MEDIA_PARAMETERS structure see TapeMiniGetMediaParameters.

I/O Status Block

The Information field is set to the number of bytes returned. The Status field is set to STATUS_SUCCESS or possibly to STATUS_IO_DEVICE_ERROR, STATUS_DEVICE_DATA_ERROR, STATUS_DATA_OVERRUN, STATUS_NO_SUCH_DEVICE, STATUS_IO_TIMEOUT, STATUS_DEVICE_NOT_READY, STATUS_INFO_LENGTH_MISMATCH, STATUS_NO_MEDIA_IN_DEVICE, or STATUS_VERIFY_REQUIRED.

Headers

Defined in ntddtape.h; Include ntddtape.h.


IOCTL_TAPE_GET_POSITION

Operation

Returns the current absolute, logical, or pseudological partition and offset position on the tape.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location indicates the size in bytes of the parameter buffer, which must be >= sizeof(TAPE_GET_POSITION).

Output

The driver returns the TAPE_GET_POSITION data in the buffer at Irp->AssociatedIrp.SystemBuffer. For a description of the TAPE_GET_POSITION structure see TapeMiniGetPosition.

I/O Status Block

The Information field is set to the number of bytes returned. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INFO_LENGTH_MISMATCH, STATUS_IO_DEVICE_ERROR, STATUS_DEVICE_DATA_ERROR, STATUS_NO_SUCH_DEVICE, STATUS_IO_TIMEOUT, STATUS_DEVICE_NOT_READY, STATUS_NO_MEDIA_IN_DEVICE, or STATUS_VERIFY_REQUIRED.

Headers

Defined in ntddtape.h; Include ntddtape.h.


IOCTL_TAPE_GET_STATUS

Operation

Returns the current status of the drive.

Input

None

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS or possibly to STATUS_DEVICE_DATA_ERROR, STATUS_NO_SUCH_DEVICE, STATUS_IO_TIMEOUT, STATUS_DEVICE_NOT_READY, STATUS_NO_MEDIA_IN_DEVICE, or STATUS_VERIFY_REQUIRED.

Headers

Defined in ntddtape.h; Include ntddtape.h.


IOCTL_TAPE_OLD_SET_MEDIA_PARAMS

Operation

Resets the block size of the media in the drive. This IOCTL performs the same function as IOCTL_TAPE_SET_MEDIA_PARAMS, except that the caller needn't have opened the device for both READ and WRITE access. It is sufficient to open the device for READ access in order to use this IOCTL.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location indicates the size in bytes of the parameter buffer, which must be >= sizeof(TAPE_SET_MEDIA_PARAMETERS). The buffer at Irp->AssociatedIrp.SystemBuffer contains the block size to be set. For a description of the TAPE_SET_MEDIA_PARAMETERS structure see TapeMiniSetMediaParameters.

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS or possibly to STATUS_IO_DEVICE_ERROR, STATUS_MEDIA_WRITE_PROTECTED, STATUS_DEVICE_DATA_ERROR, STATUS_NO_SUCH_DEVICE, STATUS_IO_TIMEOUT, STATUS_DEVICE_NOT_READY, STATUS_INFO_LENGTH_MISMATCH, STATUS_NO_MEDIA_IN_DEVICE, or STATUS_VERIFY_REQUIRED.

Headers

Defined in ntddtape.h; Include ntddtape.h.


IOCTL_TAPE_PREPARE

Operation

Loads or unloads tape, resets the tape's tension, locks or unlocks the ejection mechanism, or formats the tape.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location indicates the size in bytes of the parameter buffer, which must be >= sizeof(TAPE_PREPARE). If the Immediate member is TRUE, the operation should be asynchronous. For a description of the TAPE_PREPARE structure see TapeMiniPrepare.

Output

None

I/O Status Block

The Information field is set to the number of bytes transferred. The Status field is set to STATUS_SUCCESS or possibly to STATUS_NO_SUCH_DEVICE, STATUS_IO_TIMEOUT, STATUS_IO_DEVICE_ERROR, STATUS_INSUFFICIENT_RESOURCES, STATUS_DEVICE_NOT_CONNECTED, STATUS_MEDIA_WRITE_PROTECTED, STATUS_NO_MEDIA_IN_DEVICE, or STATUS_VERIFY_REQUIRED.

Headers

Defined in ntddtape.h; Include ntddtape.h.


IOCTL_TAPE_SET_DRIVE_PARAMS

Operation

Adjusts a tape drive's configurable parameters.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location indicates the size in bytes of the parameter buffer, which must be >= sizeof(TAPE_SET_DRIVE_PARAMETERS). The buffer at Irp->AssociatedIrp.SystemBuffer contains the values to be set. For a description of the TAPE_SET_DRIVE_PARAMETERS structure see TapeMiniSetDriveParameters.

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS or possibly to STATUS_IO_DEVICE_ERROR, STATUS_INVALID_DEVICE_REQUEST, STATUS_DEVICE_DATA_ERROR, STATUS_NO_SUCH_DEVICE, STATUS_IO_TIMEOUT, STATUS_INFO_LENGTH_MISMATCH, or STATUS_DEVICE_NOT_READY.

Headers

Defined in ntddtape.h; Include ntddtape.h.


IOCTL_TAPE_SET_MEDIA_PARAMS

Operation

Resets the block size of the media in the drive.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location indicates the size in bytes of the parameter buffer, which must be >= sizeof(TAPE_SET_MEDIA_PARAMETERS). The buffer at Irp->AssociatedIrp.SystemBuffer contains the block size to be set. For a description of the TAPE_SET_MEDIA_PARAMETERS structure see TapeMiniSetMediaParameters.

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS or possibly to STATUS_IO_DEVICE_ERROR, STATUS_MEDIA_WRITE_PROTECTED, STATUS_DEVICE_DATA_ERROR, STATUS_NO_SUCH_DEVICE, STATUS_IO_TIMEOUT, STATUS_DEVICE_NOT_READY, STATUS_INFO_LENGTH_MISMATCH, STATUS_NO_MEDIA_IN_DEVICE, or STATUS_VERIFY_REQUIRED.

Headers

Defined in ntddtape.h; Include ntddtape.h.


IOCTL_TAPE_SET_POSITION

Operation

Moves the current position on the tape to the specified partition and offset, according to the given method.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location indicates the size in bytes of the parameter buffer, which must be >= sizeof(TAPE_SET_POSITION). If the Immediate member is TRUE, the operation should be asynchronous. For a description of the TAPE_SET_POSITION structure see TapeMiniSetPosition.

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INFO_LENGTH_MISMATCH, STATUS_IO_DEVICE_ERROR, STATUS_DEVICE_DATA_ERROR, STATUS_NO_SUCH_DEVICE, STATUS_IO_TIMEOUT, STATUS_DEVICE_NOT_READY, STATUS_NO_MEDIA_IN_DEVICE, or STATUS_VERIFY_REQUIRED.

Headers

Defined in ntddtape.h; Include ntddtape.h.


IOCTL_TAPE_WRITE_MARKS

Operation

Writes one of setmarks, filemarks, short filemarks, or long filemarks to tape.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location indicates the size in bytes of the parameter buffer, which must be >= sizeof(TAPE_WRITE_MARKS). If the Immediate member is TRUE, the operation should be asynchronous. For a description of the TAPE_WRITE_MARKS structure see TapeMiniWriteMarks.

Output

None

I/O Status Block

The Information field is set to the number of bytes written. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INFO_LENGTH_MISMATCH, STATUS_IO_DEVICE_ERROR, STATUS_DEVICE_DATA_ERROR, STATUS_NO_SUCH_DEVICE, STATUS_IO_TIMEOUT, STATUS_DEVICE_NOT_READY, STATUS_MEDIA_WRITE_PROTECTED, STATUS_NO_MEDIA_IN_DEVICE, or STATUS_VERIFY_REQUIRED.

Headers

Defined in ntddtape.h; Include ntddtape.h.


Changer I/O Control Codes

All public I/O control codes for drivers of changer devices use buffered I/O. Consequently the input or output data for these requests is at Irp->AssociatedIrp.SystemBuffer.

Class drivers for changer devices handle additional public I/O control codes, along with those described in this section. See Mass Storage Device I/O Control Codes for more information about requirements for storage class drivers.


IOCTL_CHANGER_EXCHANGE_MEDIUM

Operation

Moves a piece of media from a source element to one destination, and the piece of media originally in the first destination to a second destination. The source and second destination are often the same, which essentially swaps the two pieces of media.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location indicates the size in bytes of the parameter buffer, which must be >= sizeof(CHANGER_EXCHANGE_MEDIUM). The buffer at Irp->AssociatedIrp.SystemBuffer contains the CHANGER_EXCHANGE_MEDIUM data, which indicates the source, both destinations, and whether either or both media should be flipped, assuming the device supports two-sided media. For a description of the CHANGER_EXCHANGE_MEDIUM structure see ChangerExchangeMedium.

Output

None

I/O Status Block

The Information field is set to sizeof(CHANGER_EXCHANGE_MEDIUM). The Status field is set to STATUS_SUCCESS or possibly to STATUS_DESTINATION_ELEMENT_FULL, STATUS_INFO_LENGTH_MISMATCH, STATUS_INSUFFICIENT_RESOURCES, STATUS_INVALID_DEVICE_REQUEST, STATUS_INVALID_ELEMENT_ADDRESS, STATUS_INVALID_PARAMETER, or STATUS_SOURCE_ELEMENT_EMPTY.

Headers

Defined in ntddchgr.h; Include ntddchgr.h.


IOCTL_CHANGER_GET_ELEMENT_STATUS

Operation

Returns the status of all elements or the status of a specified number of elements of a particular type.

For a description of the possible element types see CHANGER_ELEMENT.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location indicates the size in bytes of the parameter buffer for input, which must be >= sizeof(CHANGER_READ_ELEMENT_STATUS). For a description of the CHANGER_READ_ELEMENT_STATUS structure see ChangerGetElementStatus.

The buffer at Irp->AssociatedIrp.SystemBuffer contains the CHANGER_READ_ELEMENT_STATUS data that indicates the element type and the number of elements for which to return status.

If the caller sets the VolumeTagInfo member of CHANGER_READ_ELEMENT_STATUS to TRUE, the element status returned will include volume tag information.

Parameters.DeviceIoControl.OutputBufferLength indicates the size in bytes of the parameter buffer for output. For elements of type ChangerDrive this must be >= NumberOfElements * sizeof(CHANGER_ELEMENT_STATUS_EX). For elements of all other types this must be >= NumberOfElements * sizeof(CHANGER_ELEMENT_STATUS).

Output

The changer miniclass driver returns the changer element status data in the buffer at Irp->AssociatedIrp.SystemBuffer. Some elements of type ChangerDrive return product information data. If the device provides product information, the miniclass driver will report the element status data in a structure of type CHANGER_ELEMENT_STATUS_EX. The miniclass driver sets ELEMENT_STATUS_PRODUCT_DATA in the Flags member of the structure to indicate that it contains product information data. For elements of all types other than ChangerDrive, the driver reports element status data in a structure of type CHANGER_ELEMENT_STATUS.

I/O Status Block

The Information field is set to the number of bytes returned. The Status field is set to STATUS_SUCCESS or possibly to STATUS_BUFFER_TOO_SMALL, STATUS_INFO_LENGTH_MISMATCH, STATUS_INSUFFICIENT_RESOURCES, STATUS_INVALID_ELEMENT_ADDRESS, or STATUS_INVALID_PARAMETER.

Headers

Defined in ntddchgr.h; Include ntddchgr.h.

See Also

CHANGER_ELEMENT_STATUS, CHANGER_ELEMENT_STATUS_EX, CHANGER_ELEMENT, ChangerGetElementStatus


IOCTL_CHANGER_GET_PARAMETERS

Operation

Returns the parameters of the device.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location indicates the size in bytes of the parameter buffer, which must be >= sizeof(GET_CHANGER_PARAMETERS).

Output

The driver returns the GET_CHANGER_PARAMETERS data in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the number of bytes returned. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INFO_LENGTH_MISMATCH or STATUS_INSUFFICIENT_RESOURCES.

Headers

Defined in ntddchgr.h; Include ntddchgr.h.


IOCTL_CHANGER_GET_PRODUCT_DATA

Operation

Returns product data for the device.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location indicates the size in bytes of the parameter buffer, which must be >= sizeof(CHANGER_PRODUCT_DATA).

Output

The driver returns the CHANGER_PRODUCT_DATA data in the buffer at Irp->AssociatedIrp.SystemBuffer. For a description of the CHANGER_PRODUCT_DATA structure see ChangerGetProductData.

I/O Status Block

The Information field is set to the number of bytes returned. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INFO_LENGTH_MISMATCH.

Headers

Defined in ntddchgr.h; Include ntddchgr.h.


IOCTL_CHANGER_GET_STATUS

Operation

Returns the current status of the device.

Input

None

Output

None

I/O Status Block

The Information field is set to zero. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INSUFFICIENT_RESOURCES.

Headers

Defined in ntddchgr.h; Include ntddchgr.h.


IOCTL_CHANGER_INITIALIZE_ELEMENT_STATUS

Operation

Initializes the status of all elements or of specified number of elements of a particular type.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location indicates the size in bytes of the parameter buffer, which must be >= sizeof(CHANGER_INITIALIZE_ELEMENT_STATUS). The buffer at Irp->AssociatedIrp.SystemBuffer contains the element type and the number of elements to initialize. If the BarCodeScan member is TRUE and CHANGER_BAR_CODE_SCANNER_INSTALLED is also set in Features0 of CHANGER_GET_PARAMETERS, the elements should be initialized using a bar code scan. For a description of the CHANGER_INITIALIZE_ELEMENT_STATUS structure see ChangerInitializeElementStatus.

Output

None

I/O Status Block

The Information field is set to sizeof(CHANGER_INITIALIZE_ELEMENT_STATUS). The Status field is set to STATUS_SUCCESS or possibly to STATUS_INFO_LENGTH_MISMATCH, STATUS_INSUFFICIENT_RESOURCES, STATUS_INVALID_ELEMENT_ADDRESS, or STATUS_INVALID_PARAMETER.

Headers

Defined in ntddchgr.h; Include ntddchgr.h.


IOCTL_CHANGER_MOVE_MEDIUM

Operation

Moves a piece of media from a source element to a destination.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location indicates the size in bytes of the parameter buffer, which must be >= sizeof(CHANGER_MOVE_MEDIUM). The buffer at Irp->AssociatedIrp.SystemBuffer contains the CHANGER_MOVE_MEDIUM data, which indicates the transport to use for the operation, the source, the destination, and whether the medium should be flipped, assuming the device supports two-sided media. For a description of the CHANGER_MOVE_MEDIUM structure see ChangerMoveMedium.

Output

None

I/O Status Block

The Information field is set to sizeof(CHANGER_MOVE_MEDIUM). The Status field is set to STATUS_SUCCESS or possibly to STATUS_DESTINATION_ELEMENT_FULL, STATUS_INFO_LENGTH_MISMATCH, STATUS_INSUFFICIENT_RESOURCES, STATUS_INVALID_DEVICE_REQUEST, STATUS_INVALID_ELEMENT_ADDRESS, STATUS_INVALID_PARAMETER, or STATUS_SOURCE_ELEMENT_EMPTY.

Headers

Defined in ntddchgr.h; Include ntddchgr.h.


IOCTL_CHANGER_QUERY_VOLUME_TAGS

Operation

Returns volume tag information for the specified elements.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location indicates the size in bytes of the parameter buffer, which must be >= sizeof(CHANGER_SEND_VOLUME_TAG_INFORMATION). The buffer at Irp->AssociatedIrp.SystemBuffer indicates the starting element for which to return information, the action to perform, and a template to use when searching for volume IDs.

Parameters.DeviceIoControl.OutputBufferLength indicates the size in bytes of the parameter buffer for output, which must be >= sizeof(READ_ELEMENT_ADDRESS_INFO).

Output

The driver returns the READ_ELEMENT_ADDRESS_INFO data in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the correct output buffer size in bytes. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INFO_LENGTH_MISMATCH, STATUS_INSUFFICIENT_RESOURCES, STATUS_INVALID_DEVICE_REQUEST, or STATUS_INVALID_ELEMENT_ADDRESS.

Headers

Defined in ntddchgr.h; Include ntddchgr.h.


IOCTL_CHANGER_REINITIALIZE_TRANSPORT

Operation

Physically recalibrates a transport element, typically after the changer has been powered on or a calling application has initiated a recovery operation. Recalibration may involve returning the transport to its "home" position.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location indicates the size in bytes of the parameter buffer, which must be >= sizeof(CHANGER_ELEMENT). The buffer at Irp->AssociatedIrp.SystemBuffer indicates the element to initialize.

Output

None

I/O Status Block

The Information field is set to sizeof(CHANGER_ELEMENT). The Status field is set to STATUS_SUCCESS or possibly to STATUS_INFO_LENGTH_MISMATCH, STATUS_INSUFFICIENT_RESOURCES, STATUS_INVALID_ELEMENT_ADDRESS, or STATUS_INVALID_PARAMETER.

Headers

Defined in ntddchgr.h; Include ntddchgr.h.


IOCTL_CHANGER_SET_ACCESS

Operation

Sets the state of the device's import/export port (IEport), door, or keypad.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location indicates the size in bytes of the parameter buffer, which must be >= sizeof(CHANGER_SET_ACCESS). The buffer at Irp->AssociatedIrp.SystemBuffer contains the element and the operation to perform. For a description of the CHANGER_SET_ACCESS structure see ChangerSetAccess.

Output

None

I/O Status Block

The Information field is set to the number of bytes set. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INFO_LENGTH_MISMATCH, STATUS_INSUFFICIENT_RESOURCES, STATUS_INVALID_DEVICE_REQUEST, or STATUS_INVALID_PARAMETER.

Headers

Defined in ntddchgr.h; Include ntddchgr.h.


IOCTL_CHANGER_SET_POSITION

Operation

Sets the changer's robotic transport mechanism to the specified element address, typically to optimize moving or exchanging media by positioning the transport beforehand.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location indicates the size in bytes of the parameter buffer, which must be >= sizeof(CHANGER_SET_POSITION). The buffer at Irp->AssociatedIrp.SystemBuffer specifies the transport to move and the destination. If the Flip member is TRUE and the device supports two-sided media, the media currently carried by the transport should be flipped. For a description of the CHANGER_SET_POSITION structure see ChangerSetPosition.

Output

None

I/O Status Block

The Information field is set to sizeof(CHANGER_SET_POSITION). The Status field is set to STATUS_SUCCESS or possibly to STATUS_INFO_LENGTH_MISMATCH, STATUS_INSUFFICIENT_RESOURCES, STATUS_INVALID_DEVICE_REQUEST, or STATUS_INVALID_PARAMETER.

Headers

Defined in ntddchgr.h; Include ntddchgr.h.


SCSI Port I/O Control Codes

All storage class drivers are required to set the minor function code with IRP_MN_SCSI_CLASS in the port driver's I/O stack location of any IRP that a class driver allocates and sets up to send on to the system port driver. For example, a legacy class driver must set this minor function code when it makes an IOCTL_SCSI_GET_ADDRESS request to obtain the address of a target device.

For incoming IRPs originating with a user I/O request or with a higher-level driver, storage class drivers should ignore the minor function code in the port driver's I/O stack location, leaving it as is. In general, such requests can be sent directly to the system-supplied port driver only if no storage class driver for the target device exists. Otherwise, such requests must be directed to the storage class driver for the appropriate type of underlying storage device.

The following shows I/O control requests that a storage port driver supports. All public I/O control codes for the port driver use buffered I/O. Consequently, most input or output data for these requests is at Irp->AssociatedIrp.SystemBuffer.


IOCTL_SCSI_GET_INQUIRY_DATA

Operation

Returns the SCSI inquiry data for all devices on a given SCSI bus. Usually, the caller is a SCSI class driver, but the caller can be an application that makes IOCTL_SCSI_MINIPORT, IOCTL_SCSI_PASS_THROUGH, IOCTL_SCSI_PASS_THROUGH_DIRECT, or IOCTL_SCSI_RESCAN_BUS requests to the port driver.

Only legacy drivers can issue this request. The request fails if it is sent to a PDO created by the port driver.

To get SCSI inquiry data, a Plug and Play driver must issue an IOCTL_STORAGE_QUERY_PROPERTY request for STORAGE_DEVICE_DESCRIPTOR data to the PDO for each device to which the driver has been added (that is, each device for which the driver has received an AddDevice call). A legacy driver should forward this request to the port driver. This request fails if it is sent to the FDO for an adapter.

Input

Parameters.DeviceIoControl.OutputBufferLength indicates the size in bytes of the buffer which must be >= (sizeof(SCSI_ADAPTER_BUS_INFO) + (NumberOfBuses -1) * sizeof(SCSI_BUS_DATA)) + (InquiryDataSize * NumberOfLUs), where the InquiryDataSize is (sizeof(SCSI_INQUIRY_DATA) - 1 + INQUIRYDATABUFFERSIZE) rounded up to an alignment boundary.

Output

The buffer at Irp->AssociatedIrp.SystemBuffer contains the returned inquiry data.

I/O Status Block

The Information field contains the number of bytes returned in the output buffer. The Status field indicates the results of the operation.

Headers

Defined in ntddscsi.h; Include ntddscsi.h.


IOCTL_SCSI_GET_CAPABILITIES

Operation

Returns the capabilities and limitations of the underlying SCSI HBA. The most important information is returned in the MaximumTransferLength and AlignmentMask members. Class drivers and users of IOCTL_SCSI_PASS_THROUGH and IOCTL_SCSI_PASS_THROUGH_DIRECT are required to honor these limitations.

Only legacy drivers can issue this request. The request fails if it is sent to a PDO created by the port driver.

To get SCSI capabilities data, a Plug and Play driver must issue an IOCTL_STORAGE_QUERY_PROPERTY request for STORAGE_ADAPTER_DESCRIPTOR data to the PDO for each device to which the driver has been added (that is, each device for which the driver has received an AddDevice call). A legacy driver should forward this request to the port driver. This request fails if it is sent to the FDO for an adapter.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location indicates the size in bytes of the buffer, which must be >= sizeof(IO_SCSI_CAPABILITIES).

Output

Updated IO_SCSI_CAPABILITIES information is returned to the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field contains the number of bytes returned in the output buffer. The Status field indicates the results of the operation.

Headers

Defined in ntddscsi.h; Include ntddscsi.h.


IOCTL_SCSI_GET_ADDRESS

Operation

Returns the address information, such as the target id (TID) and the logical unit number (LUN) of a particular SCSI target. A legacy class driver can issue this request to the port driver to obtain the address of its device. This request is not relevant to storage class drivers that support Plug and Play, because the port driver supplies the address information on behalf of the class driver.

This request must be directed to a class driver or to a PDO created by the port driver.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location indicates the size in bytes of the buffer, which must be >= sizeof(SCSI_ADDRESS).

Output

Updated SCSI_ADDRESS information is returned to the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field contains the number of bytes returned in the output buffer. The Status field indicates the results of the operation.

Headers

Defined in ntddscsi.h; Include ntddscsi.h.


IOCTL_SCSI_MINIPORT

Operation

Sends a special control function to an HBA-specific miniport driver. Results vary, depending on the particular miniport driver to which this request is forwarded. If the caller specifies a nonzero Length, either the input or output buffer must be at least (sizeof(SRB_IO_CONTROL) + DataBufferLength)).

Input

The buffer at Irp->AssociatedIrp.SystemBuffer must contain an SRB_IO_CONTROL structure. Parameters.DeviceIoControl.InputBufferLength indicates the size in bytes of the buffer, which must be at least sizeof (SRB_IO_CONTROL), with additional storage for data if the Length field is nonzero.

Output

An updated SRB_IO_CONTROL structure is returned to the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field contains the number of bytes returned in the output buffer. The Status field indicates the results of the operation.

Headers

Defined in ntddscsi.h; Include ntddscsi.h.


IOCTL_SCSI_PASS_THROUGH

Operation

Allows an application to send almost any SCSI command to a target device, with the following restrictions:

  • Multitarget commands, such as COPY, are not allowed.
  • Bidirectional data transfer operations are not supported.
  • If a class driver for the target type of device exists, the request must be sent to that class driver. Thus, an application can send this request directly to the system port driver for a target logical unit only if there is no class driver for the type of device connected to that LU. The system port driver does not check to determine if a device has been claimed by a class driver before processing a pass-through request. Therefore, if an application bypasses a class driver that has claimed a device and sends a pass-through request for that device directly to the port driver, then a conflict for control of the device can occur between the class driver and the application.
  • This request cannot be used if the CDB might require the underlying miniport driver to access memory directly. If the caller's CDB might require direct access to memory, use IOCTL_SCSI_PASS_THROUGH_DIRECT instead.
  • Applications must not attempt to send a pass-through request asynchronously. All pass-through requests must be synchronous.
  • Applications do not require administrative privileges to send a pass-through request to a device, but they must have read-write access to the device.

The calling application creates the SCSI command descriptor block, which can include a request for request-sense data if a CHECK CONDITION occurs.

IOCTL_SCSI_PASS_THROUGH is a buffered device control request. To bypass buffering in system memory, callers should use IOCTL_SCSI_PASS_THROUGH_DIRECT. When handling an IOCTL_SCSI_PASS_THROUGH_DIRECT request, the system locks down the buffer in user memory and the device accesses this memory directly.

This request is typically used for transferring small amounts of data (<16K).

Input

Parameters.DeviceIoControl.InputBufferLength indicates the size in bytes of the buffer at Irp->AssociatedIrp.SystemBuffer, which must be at least (RequestSenseStorageSize + sizeof (SCSI_PASS_THROUGH)). The size of the SCSI_PASS_THROUGH structure varies, depending on its DataTransferLength specification.

This structure includes a SCSI CDB, which must be initialized by the caller except for the path, target ID, and LUN, which are filled in by the port driver. For a data-out command, the data to be transferred is included in the buffer at Irp->AssociatedIrp.SystemBuffer at DataBufferOffset in the SCSI_PASS_THROUGH structure. However, the caller must allocate additional storage, immediately following SCSI_PASS_THROUGH, if the caller asks for request-sense data.

Output

The port driver returns any request-sense data and any data transferred from the device to the buffer at Irp->AssociatedIrp.SystemBuffer. The SenseInfoLength and DataTransferLength in the SCSI_PASS_THROUGH structure are updated to indicate the amount of data transferred.

I/O Status Block

The Information field is set to the number of bytes returned in the output buffer at Irp->AssociatedIrp.SystemBuffer. The Status field is set to STATUS_SUCCESS or possibly to STATUS_BUFFER_TOO_SMALL or STATUS_INVALID_PARAMETER if the input Length value in SCSI_PASS_THROUGH is improperly set.

Headers

Defined in ntddscsi.h; Include ntddscsi.h.


IOCTL_SCSI_PASS_THROUGH_DIRECT

Operation

Allows an application to send almost any SCSI command to a target device, with the following restrictions:

  • Multitarget commands, such as COPY, are not allowed.
  • Bidirectional data transfer operations are not supported.
  • If a class driver for the target type of device exists, the request must be sent to that class driver. Thus, an application can send this request directly to the system port driver for a target logical unit only if there is no class driver for the type of device connected to that LU.
  • This request must be made if the input CDB might require the underlying miniport driver to access memory directly.

The calling application creates the SCSI command descriptor block, which can include a request for request-sense data if a CHECK CONDITION occurs. If the CDB requests a data transfer operation, the caller must set up a cache-aligned buffer from which or into which the miniport driver can transfer data directly. This request is typically used for transferring larger amounts of data (>16K).

Input

Parameters.DeviceIoControl.InputBufferLength indicates the size in bytes of the buffer at Irp->AssociatedIrp.SystemBuffer, which must be at least (RequestSenseStorageSize + sizeof (SCSI_PASS_THROUGH_DIRECT)). The size of the SCSI_PASS_THROUGH_DIRECT structure is fixed.

This structure includes a SCSI CDB, which must be initialized by the caller except for the path, target ID, and LUN, which are filled in by the port driver. For a data-out command, the data to be transferred must be in a cache-aligned buffer. The DataBuffer member of SCSI_PASS_THROUGH_DIRECT is a pointer to this cache-aligned buffer. The caller must allocate additional storage, following the SCSI_PASS_THROUGH_DIRECT structure, if the caller asks for request-sense data.

Output

The port driver returns any request-sense data and the SCSI_PASS_THROUGH_DIRECT structure to the buffer at Irp->AssociatedIrp.SystemBuffer. The SenseInfoLength and DataTransferLength are updated to indicate the amount of data transferred. The port driver returns any data transferred from the device to the supplied cache-aligned buffer at DataBuffer.

I/O Status Block

The Information field is set to the number of bytes returned in the output buffer at Irp->AssociatedIrp.SystemBuffer. The Status field is set to STATUS_SUCCESS or possibly to STATUS_BUFFER_TOO_SMALL or STATUS_INVALID_PARAMETER if the input Length value in SCSI_PASS_THROUGH is improperly set.

Headers

Defined in ntddscsi.h; Include ntddscsi.h.


IOCTL_SCSI_RESCAN_BUS

Operation

The port driver rescans the LUNs on the bus(es). It collects SCSI inquiry data about all devices on the bus(es), while preserving any claims on their respective devices for SCSI class drivers.

This request is obsolete and is supported for legacy code only. This request must be directed to an FDO, and is valid only for legacy (nonPnP) class drivers and SCSI bus enumeration. If the bus can detect device insertion, this request is not relevant.

Usually, this request originates in a system-supplied Win32 application such as Windisk or Setup when the user connects new device(s) for which the system has no Plug and Play drivers on a SCSI bus dynamically: that is, without shutting down the system. When this request is satisfied, such an application next makes an IOCTL_STORAGE_QUERY_PROPERTY request to the system port driver and examines the returned inquiry data. If the application finds any unclaimed devices of a given type, it then sends one or more IOCTL_STORAGE_FIND_NEW_DEVICES requests to the appropriate storage class drivers.

Input

None

Output

None

I/O Status Block

The Information field is set to zero. The Status field indicates the results of the operation.

Headers

Defined in ntddscsi.h; Include ntddscsi.h.


Mount Manager I/O Control Codes

This section contains the following topics:

I/O Control Codes Sent by the Mount Manager

I/O Control Codes Sent by Mount Manager Clients

For detailed information concerning the various types of volume and device Ids managed by the mount manager, and how these Ids relate to the IOCTL requests discussed in this section, see Supporting Mount Manager Requests in a Storage Class Driver.


I/O Control Codes Sent by the Mount Manager

The Mount Manager publishes an interface that client drivers, such as class drivers, must support in order to receive persistent symbolic link names from the Mount Manager. Mount Manager client drivers register to receive the IOCTLs listed in this section from the Mount Manager by calling IoRegisterDeviceInterface with the MOUNTDEV_MOUNTED_DEVICE_GUID GUID defined in mountmgr.h. Any driver that subscribes to this interface must support some subset of these IOCTLs. To determine whether a specific IOCTL is required, check the Operation section of the IOCTL.


IOCTL_MOUNTDEV_QUERY_DEVICE_NAME

Operation

Support for this IOCTL by Mount Manager clients is mandatory. Upon receiving this IOCTL a client driver must provide the (nonpersistent) device (or target) name for the volume. Mount Manager uses the device name returned by the client as the target of a symbolic link. An example of a device name would be "\Device\HarddiskVolume1".

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size, in bytes, of the output buffer, which must be greater than or equal to sizeof(MOUNTDEV_NAME).

Output

The Mount Manager client returns a variable-length structure of type MOUNTDEV_NAME, defined in mountmgr.h, at the beginning of the buffer at Irp->AssociatedIrp.SystemBuffer. The device name must be inserted at the address pointed to by the Name member of this structure.

I/O Status Block

The Information field is set to the length of the NULL-terminated string containing the device name.

If the operation is successful, the mount manager client must set the Information field to the length of the NULL-terminated string containing the device name and the Status field to STATUS_SUCCESS.

If the output buffer is too small to hold the device name, the mount manager client must set the Information field to sizeof(MOUNTDEV_NAME) and the Status field to STATUS_BUFFER_OVERFLOW.

Headers

Defined in mountmgr.h; Include mountmgr.h.


IOCTL_MOUNTDEV_QUERY_UNIQUE_ID

Operation

Support for this IOCTL by Mount Manager clients is mandatory. Upon receiving this IOCTL the Mount Manager client must provide a counted byte string identifier that is unique to the client (that is the device or the volume). The client cannot change this unique ID without alerting the Mount Manager (see IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY).

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size, in bytes, of the output buffer, which must be greater than or equal to sizeof(MOUNTDEV_UNIQUE_ID).

Output

The device class or volume driver returns the MOUNTDEV_UNIQUE_ID structure in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the length of the NULL-terminated string containing the identifier.

If the operation is successful, the Status field is set to STATUS_SUCCESS.

Headers

Defined in mountmgr.h; Include mountmgr.h.


IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY

Operation

Support for this IOCTL by Mount Manager clients is optional. Upon receiving this IOCTL the Mount Manager client must confirm that its unique identifier should be changed. It does this by completing the IOCTL. The Mount Manager will then replace all occurrences of the old unique identifier value with a new unique identifier supplied by the client.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size, in bytes, of the buffer at Irp->AssociatedIrp.SystemBuffer, which must be at least sizeof(MOUNTDEV_UNIQUE_ID). MOUNTDEV_UNIQUE_ID is a variable length structure that, on input, contains the old unique identifier for the device or volume.

Output

In order to change the unique identifier, the client driver completes this IOCTL after storing the required information in the buffer at Irp->AssociatedIrp.SystemBuffer. The client driver must place a header defined by the MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT structure, at the beginning of the buffer: Following this header, the client driver loads the buffer with both the old and the new unique identifiers, in that order. The identifiers must be located at the offsets from the start of the buffer indicated in the header.

I/O Status Block

If the operation is successful, the Status field is set to STATUS_SUCCESS and the Information field is set to the total number of bytes in the output buffer. The total amount of output data can be calculated by adding the length of the header sizeof(MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT) to the lengths of the old and new unique identifiers:

OldUniqueIdLength +

NewUniqueIdLength +

sizeof(MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT).

The operation will fail and the Status field be set to STATUS_INVALID_PARAMETER if any of the following conditions hold:

  • InputBufferLength < sizeof(MOUNTDEV_UNIQUE_ID)
  • OldUniqueIdLength > InputBufferLength
  • OutputBufferLength < sizeof(MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT)

If OutputBufferLength is less than the total amount of output data, then the operation will fail, Status will be set to STATUS_BUFFER_OVERFLOW and Information will be set to sizeof(MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT).

Headers

Defined in mountmgr.h; Include mountmgr.h.


IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME

Operation

Support for this IOCTL by Mount Manager clients is optional. Some Mount Manager clients are able to keep track of their drive letters and other symbolic link names across reboots of the system without the help of the Mount Manager. Such clients can send a suggested symbolic link name to the Mount Manager in response to this IOCTL. The Mount Manager uses the suggested name if the Mount Manager's database does not already contain a persistent name for the client's volume. Otherwise, it ignores the suggestion and uses the symbolic link name in its persistent name database.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size, in bytes, of the output buffer, which must be greater than or equal to sizeof(MOUNTDEV_SUGGESTED_LINK_NAME).

Output

The client driver must place a variable-length structure of type MOUNTDEV_SUGGESTED_LINK_NAME, defined in mountdev.h, at the beginning of the buffer at Irp->AssociatedIrp.SystemBuffer. Starting at the address of the structure member Name, the client driver must insert the suggested persistent name.

I/O Status Block

If the operation is successful then the Information field is set to the total number of bytes returned and the Status field is set to STATUS_SUCCESS.

If OutputBufferLength is less than sizeof(MOUNTDEV_SUGGESTED_LINK_NAME), the Status field is set to STATUS_INVALID_PARAMETER.

If OutputBufferLength is less than the total length of output data, the Status field is set to STATUS_BUFFER_OVERFLOW and the Information field is set to sizeof(MOUNTDEV_SUGGESTED_LINK_NAME).

Headers

Defined in mountmgr.h; Include mountmgr.h.


IOCTL_MOUNTDEV_LINK_CREATED

Operation

Support for this IOCTL by Mount Manager clients is optional. The Mount Manager uses this IOCTL to alert the client driver that a persistent name has been assigned to its volume. The input for this IOCTL is the persistent name assigned.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size, in bytes, of the input buffer, which must be greater than or equal to sizeof(MOUNTDEV_NAME).

The Mount Point Manager places a variable-length structure of type MOUNTDEV_NAME, defined in mountmgr.h, at the beginning of the buffer at Irp->AssociatedIrp.SystemBuffer. The Mount Manager inserts the persistent name just assigned at the address pointed to by the Name member of this structure.

Output

None

I/O Status Block

No status.

Headers

Defined in mountmgr.h; Include mountmgr.h.


IOCTL_MOUNTDEV_LINK_DELETED

Operation

Support for this IOCTL by Mount Manager clients is optional. It alerts the Mount Manager client that a persistent name associated with it has been deleted. The input for this IOCTL is the persistent name that was deleted.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size, in bytes, of the input buffer, which must be greater than or equal to sizeof(MOUNTDEV_NAME).

The Mount Point Manager places a variable-length structure of type MOUNTDEV_NAME, defined in mountmgr.h, at the beginning of the buffer at Irp->AssociatedIrp.SystemBuffer. The Mount Manager inserts the persistent name just assigned at the address pointed to by the Name member of this structure.

Output

None

I/O Status Block

No status.

Headers

Defined in mountmgr.h; Include mountmgr.h.


I/O Control Codes Sent by Mount Manager Clients

The Mount Manager publishes an interface that allows Mount Manager clients to set, query, and delete persistent names for volumes. To access this interface, clients can obtain a pointer to the Mount Manager's device object using the object name MOUNTMGR_DEVICE_NAME, defined in mountmgr.h. For instance,

    // Obtain a pointer to the Mount Manager device object &
    // use it to send any of the I/O Control codes in this
    // section to the Mount Manager.
    RtlInitUnicodeString(&name, MOUNTMGR_DEVICE_NAME);
    status = IoGetDeviceObjectPointer(&name,
                FILE_READ_ATTRIBUTES,
                &fileObject, &deviceObject);
    irp = IoBuildDeviceIoControlRequest(
            IOCTL_MOUNTMGR_CREATE_POINT,
            deviceObject, createPoint, createPointSize,
            NULL, 0, FALSE, &event, &ioStatus);
    status = IoCallDriver(deviceObject, irp);

The call sequence in this pseudocode sample has been simplified for the sake of brevity. See IOCTL_MOUNTMGR_CREATE_POINT for a more complete pseudocode example.

The following material describes the I/O control codes that Mount Manager clients can send to the Mount Manager.


IOCTL_MOUNTMGR_CREATE_POINT

Operation

Mount Manager clients can use this IOCTL to request that the Mount Manager create a persistent symbolic link name for the indicated volume. For a discussion of the various sorts of persistent symbolic links managed by the Mount Manager see Supporting Mount Manager Requests in a Storage Class Driver.

The input to this request is the persistent symbolic link name to be created and a name that is already valid for purposes of identifying the volume. The name given for purposes of identifying the volume can be of any type: a unique volume name, a symbolic link name, or a nonpersistent device name. If the new persistent name is not already in use, the call will succeed and the Mount Manager database will be modified to reflect that the new persistent name belongs to the volume. If the Mount Manager database already contains the new persistent name, but the volume that owns that name is not in the system, this call will overwrite ownership of the given persistent name.

The Mount Manager allows the creation of a new persistent symbolic link name even if it has not yet been notified of the given volume in the MOUNTDEV_MOUNTED_DEVICE_GUID device interface notification. In such a case, the Mount Manager simply creates the symbolic link and updates the Mount Manager database.

The Mount Manager enforces a policy of at most one persistent drive letter per volume. If an IOCTL_MOUNTMGR_CREATE_POINT request is sent with a drive letter, the request will fail if there is already a drive letter assigned to the volume, unless the Mount Manager has not yet been notified of the volume by means of the MOUNTDEV_MOUNTED_DEVICE_GUID device interface notification. In the latter case, the call succeeds and the Mount Manager purges the Mount Manager database of any other drive letters previously assigned to the volume.

Note that a client can discover whether the Mount Manager has received the MOUNTDEV_MOUNTED_DEVICE_GUID device interface notification for its volume by querying the Mount Manager with IOCTL_MOUNTMGR_QUERY_POINTS.

In this pseudocode sample, a Mount Manager client uses IOCTL_MOUNTMGR_CREATE_POINT to send the Mount Manager a device object name and its corresponding symbolic link:

    // The persistent symbolic link is a drive letter in
    // this case:
    swprintf(dosBuffer, L"\\DosDevices\\%c:", DriveLetter);
    RtlInitUnicodeString(&dosName, dosBuffer);
    // The non-persistent volume (device) object name is
    // formed using the volume number as a suffix
    swprintf(ntBuffer, L"\\Device\\HarddiskVolume%d",
                       Extension->VolumeNumber);
    RtlInitUnicodeString(&ntName, ntBuffer);
    createPointSize = sizeof(MOUNTMGR_CREATE_POINT_INPUT) +
                      dosName.Length + ntName.Length;
    // Allocate a header with length and offset information
    createPoint = (PMOUNTMGR_CREATE_POINT_INPUT)
                  ExAllocatePool(PagedPool,
                  createPointSize);
    createPoint->SymbolicLinkNameOffset =
                  sizeof(MOUNTMGR_CREATE_POINT_INPUT);
    createPoint->SymbolicLinkNameLength = dosName.Length;
    createPoint->DeviceNameOffset =
        createPoint -> SymbolicLinkNameOffset +
        createPoint -> SymbolicLinkNameLength;
    createPoint->DeviceNameLength = ntName.Length;
    RtlCopyMemory((PCHAR) createPoint +
                  createPoint -> SymbolicLinkNameOffset,
                  dosName.Buffer, dosName.Length);
    RtlCopyMemory((PCHAR) createPoint +
                  createPoint->DeviceNameOffset,
                  ntName.Buffer, ntName.Length);
    // Use the name of the Mount Manager device object
    // defined in mountmgr.h (MOUNTMGR_DEVICE_NAME) to
    // obtain a pointer to the Mount Manager.
    RtlInitUnicodeString(&name, MOUNTMGR_DEVICE_NAME);
    status = IoGetDeviceObjectPointer(&name,
                              FILE_READ_ATTRIBUTES,
                              &fileObject, &deviceObject);
    KeInitializeEvent(&event, NotificationEvent, FALSE);
    irp = IoBuildDeviceIoControlRequest(
            IOCTL_MOUNTMGR_CREATE_POINT,
            deviceObject, createPoint, createPointSize,
            NULL, 0, FALSE, &event, &ioStatus);
    // Send the irp to the mount manager requesting
    // that a new mount point (persistent symbolic link)
    // be created for the indicated volume.
    status = IoCallDriver(deviceObject, irp);

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size, in bytes, of the input buffer, which must be greater than or equal to sizeof(MOUNTMGR_CREATE_POINT_INPUT).

The Mount Point Manager places a header, defined the structure MOUNTMGR_CREATE_POINT_INPUT in mountmgr.h, at the beginning of the buffer at Irp->AssociatedIrp.SystemBuffer. The Mount Manager inserts the newly-assigned persistent symbolic link name at the address pointed to by the SymbolicLinkNameOffset member of this structure, and it inserts the nonpersistent device name at the address pointed to by the DeviceNameOffset member of this structure.

Output

None

I/O Status Block

If the operation is successful, the Status field is set to STATUS_SUCCESS.

If InputBufferLength is less than sizeof(MOUNTMGR_CREATE_POINT_INPUT), the Status field is set to STATUS_INVALID_PARAMETER.

Headers

Defined in mountmgr.h; Include mountmgr.h.


IOCTL_MOUNTMGR_QUERY_POINTS

Operation

This IOCTL returns triples that consist of a persistent symbolic link name for the volume (that is a mount point), a unique ID for the volume, and a nonpersistent device name (such as "\Device\HarddiskVolume1") for the volume. The input to this IOCTL is a MOUNTMGR_MOUNT_POINT structure containing a single triple where at least one of the three fields must be present. The Mount Manager returns triples for all mount points corresponding to the volume indicated in the input triple.

If a symbolic link is present in the input triple, Mount Manager queries the client for the nonpersistent device name corresponding to the symbolic link in the input, and then uses the device name to locate other symbolic links in the mounted device list that are associated with the volume.

If there is no symbolic link in the input triple, but the unique ID is present, the Mount Manager uses the unique ID to search the mounted device list. If both the symbolic link and the unique ID are omitted, the Mount Manager uses the nonpersistent device name in the input triple to search the list.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size, in bytes, of the input buffer, which must be greater than or equal to sizeof(MOUNTMGR_MOUNT_POINT).

The Mount Manager client initializes the MOUNTMGR_MOUNT_POINT structure, defined in mountmgr.h, at the beginning of the buffer at Irp->AssociatedIrp.SystemBuffer. Immediately following this structure, the MM client loads the symbolic link name, the unique ID and the device name, in that order.

Output

The Mount Manager initializes a variable-length structure of type MOUNTMGR_MOUNT_POINTS, defined in mountmgr.h, at the beginning of the buffer at Irp->AssociatedIrp.SystemBuffer. The Mount Manager inserts the mount points, associated with the indicated volume, at the address pointed to by the MountPoints[] member of this structure. Each mount point is represented by MOUNTMGR_MOUNT_POINT structure as defined in the Input section for this IOCTL.

I/O Status Block

If the operation is successful, the Status field is set to STATUS_SUCCESS.

If neither the unique ID nor the nonpersistent device name are found in the volumes mounted device list, the Status field is set to STATUS_INVALID_PARAMETER.

If InputBufferLength is less than sizeof(MOUNTMGR_MOUNT_POINT), the Status field is set to STATUS_INVALID_PARAMETER.

If InputBufferLength is less than the total length of the three input ID strings, the Status field is set to STATUS_INVALID_PARAMETER.

If OutputBufferLength is less than sizeof(MOUNTMGR_MOUNT_POINT), the Status field is set to STATUS_INVALID_PARAMETER.

If OutputBufferLength is less than sizeof(MOUNTMGR_MOUNT_POINTS) plus the sum of the sizes of the mount point triples, the Status field is set to STATUS_BUFFER_OVERFLOW.

If any of the three strings contained within any of the triples is aligned on an odd address (for example, address & 01 != 0), the Status field is set to STATUS_INVALID_PARAMETER.

Headers

Defined in mountmgr.h; Include mountmgr.h.


IOCTL_MOUNTMGR_DELETE_POINTS

Operation

This IOCTL is identical in input and output to IOCTL_MOUNTMGR_QUERY_POINTS. The difference is that IOCTL_MOUNTMGR_DELETE_POINTS has the side effect of deleting the symbolic links and Mount Manager database entries for the triples returned.

If the input to this IOCTL is ("\DosDevices\X:", NULL, NULL) where X is the current drive letter for the volume indicated in the input triple, the Mount Manager adds a special entry to its database indicating that the client does not require a drive letter. On subsequent reboots, Mount Manager will not assign a default drive letter to the volume.

Input

See IOCTL_MOUNTMGR_QUERY_POINTS.

Output

See IOCTL_MOUNTMGR_QUERY_POINTS.

I/O Status Block

See IOCTL_MOUNTMGR_QUERY_POINTS.

Headers

Defined in mountmgr.h; Include mountmgr.h.


IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY

Operation

This IOCTL is identical in input and output to IOCTL_MOUNTMGR_QUERY_POINTS. The difference is that IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY has the side effect of deleting the Mount Manager database entries for the triples returned. However, Mount Manager does not delete the symbolic links corresponding to the database entries.

If the input to this IOCTL is ("\DosDevices\X:", NULL, NULL) where X is the current drive letter for the volume indicated in the input triple, the Mount Manager adds a special entry to its database indicating that the client does not require a drive letter. On subsequent reboots, Mount Manager will not assign a default drive letter to the volume.

Input

See IOCTL_MOUNTMGR_QUERY_POINTS.

Output

See IOCTL_MOUNTMGR_QUERY_POINTS.

I/O Status Block

See IOCTL_MOUNTMGR_QUERY_POINTS.

Headers

Defined in mountmgr.h; Include mountmgr.h.


IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER

Operation

This IOCTL checks to see if the given volume has a drive letter. If it already has a drive letter, or if the volume has a special Mount Manager database entry indicating that it does not require a drive letter, this routine returns the current drive letter (if there is one) and does nothing. If the given volume does not have a drive letter and does not have a special Mount Manager database entry indicating that it does not require a drive letter, the next available drive letter is assigned to the volume. If the volume's nonpersistent device name begins with "\Device\Floppy", the Mount Manager will check for available drive letters starting with the letter "A." If the volume name begins with "\Device\CdRom" the Mount Manager will check for available drive letters starting with drive letter "D." In all other cases, the Mount Manager starts with drive letter "C." This IOCTL is designed to be used by the IoAssignDriveLetters routine.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size, in bytes, of the input buffer, which must be greater than or equal to sizeof(MOUNTMGR_DRIVE_LETTER_TARGET).

Parameters.DeviceIoControl.OuputBufferLength in the I/O stack location of the IRP indicates the size, in bytes, of the output buffer, which must be greater than or equal to sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION).

The Mount Manager client initializes the MOUNTMGR_DRIVE_LETTER_TARGET structure, defined in mountmgr.h, at the beginning of the buffer at Irp->AssociatedIrp.SystemBuffer. The client must insert the name of the target volume at the address pointed to by the DeviceName[] member of this structure. The target volume name is the name of the nonpersistent device object associated with the volume (for example, "\Device\HarddiskVolume1").

Output

The Mount Manager inserts either the current drive letter or the newly assigned drive letter (see previous discussion) in the MOUNTMGR_DRIVE_LETTER_INFORMATION structure, defined in mountmgr.h, at the beginning of the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

If the operation is successful , the Status field is set to STATUS_SUCCESS.

If InputBufferLength is less than sizeof(MOUNTMGR_DRIVE_LETTER_TARGET) or if OutputBufferLength is less than sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION), the Status field is set to STATUS_INVALID_PARAMETER.

Headers

Defined in mountmgr.h; Include mountmgr.h.


IOCTL_MOUNTMGR_AUTO_DL_ASSIGNMENTS

Operation

This IOCTL informs the Mount Manager that it should assign drive letters to volumes automatically as they are introduced in the system. This IOCTL is called by IoAssignDriveLetters when it is finished.

Input

None

Output

None

I/O Status Block

If the operation is successful, the Status field is set to STATUS_SUCCESS.

Headers

Defined in mountmgr.h; Include mountmgr.h.


IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED

Operation

This IOCTL alerts the Mount Manager that a volume mount point has been created, so that the Mount Manager can replicate the database entry for the given mount point. Its primary function is allow volume mount points to persist even when the volumes are moved from one system to another.

The Win32® routine SetVolumeMountPoint sends this IOCTL to the Mount Manager, in order to inform the Mount Manager that a newly-created directory junction is pointing to a volume name. The Mount Manager responds by storing the volume name contained in the directory junction along with its unique ID on the volume hosting the directory junction.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size, in bytes, of the input buffer, which must be greater than or equal to sizeof(MOUNTMGR_VOLUME_MOUNT_POINT).

The Mount Manager client initializes the MOUNTMGR_VOLUME_MOUNT_POINT structure, defined in mountmgr.h, at the beginning of the buffer at Irp->AssociatedIrp.SystemBuffer.

Output

None

I/O Status Block

If the operation is successful, the Status field is set to STATUS_SUCCESS.

If InputBufferLength is less than sizeof(MOUNTMGR_VOLUME_MOUNT_POINT), the Status field is set to STATUS_INVALID_PARAMETER.

Headers

Defined in mountmgr.h; Include mountmgr.h.


IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED

Operation

Mount Manager clients use this IOCTL to alert the Mount Manager that a volume mount point has been created so that the Mount Manager can replicate the database entry for the given mount point.

The Win32® routine DeleteVolumeMountPoint sends this IOCTL to the Mount Manager, in order to inform the it that a directory junction is no longer pointing to a volume name. The Mount Manager responds by deleting the volume name formerly contained in the directory junction along with its unique ID from the volume hosting the directory junction.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size, in bytes, of the input buffer, which must be greater than or equal to sizeof(MOUNTMGR_VOLUME_MOUNT_POINT).

The Mount Manager client initializes the MOUNTMGR_VOLUME_MOUNT_POINT structure, defined in mountmgr.h, at the beginning of the buffer at Irp->AssociatedIrp.SystemBuffer.

Output

None

I/O Status Block

If the operation is successful, the Status field is set to STATUS_SUCCESS.

If InputBufferLength is less than sizeof(MOUNTMGR_VOLUME_MOUNT_POINT), the Status field is set to STATUS_INVALID_PARAMETER.

Headers

Defined in mountmgr.h; Include mountmgr.h.


IOCTL_MOUNTMGR_CHANGE_NOTIFY

Operation

Clients send this IOCTL to the Mount Manager to be informed whenever there is a change in the Mount Manager's persistent symbolic link name database.

Mount Manager maintains a counter called EpicNumber that records how many changes have occurred in its persistent name database since the last startup. Clients send a number to the Mount Manager with every change notification request IRP, and the Mount Manager responds in the following manner:

  • If the number supplied by the client is not equal to EpicNumber, Mount Manager returns STATUS_SUCCESS, indicating that changes have occurred since the client last compared its number with the Mount Manager's EpicNumber.
  • If the number supplied by the client is equal to EpicNumber, Mount Manager interprets this as a request to be informed of the next change to the persistent name database, and it queues the change notification IRP and returns STATUS_PENDING. Whenever a change occurs in the database, Mount Manager completes all of the pending change notification IRPs thereby informing clients of the change.

A client that only wants to be informed of the changes to a particular volume is advised to register for Plug and Play target device notification and watch for GUID_IO_VOLUME_NAME_CHANGE.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size, in bytes, of the input buffer, which must be greater than or equal to sizeof(MOUNTMGR_CHANGE_NOTIFY_INFO).

The Mount Manager client initializes the MOUNTMGR_CHANGE_NOTIFY_INFO structure, defined in mountmgr.h, at the beginning of the buffer at Irp->AssociatedIrp.SystemBuffer.

Output

The Mount Manager returns the current EpicNumber in the MOUNTMGR_CHANGE_NOTIFY_INFO structure, defined in mountmgr.h, at the beginning of the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

If the operation is successful, the Status field is set to STATUS_SUCCESS, and the Information field is set to sizeof(MOUNTMGR_CHANGE_NOTIFY_INFO).

If InputBufferLength is less than sizeof(MOUNTMGR_CHANGE_NOTIFY_INFO) or OuputBufferLength is less than sizeof(MOUNTMGR_CHANGE_NOTIFY_INFO), the Status field is set to STATUS_INVALID_PARAMETER

Headers

Defined in mountmgr.h; Include mountmgr.h.


IOCTL_MOUNTMGR_KEEP_LINKS_WHEN_OFFLINE

Operation

This IOCTL directs the Mount Manager to keep a symbolic link active after the Plug and Play Manager has given notification that its corresponding volume has gone offline. When the volume goes back online, the Mount Manager reassigns the symbolic link to the volume. No other volume is allowed to claim the symbolic link while its original owner is offline.

Clusters use this IOCTL to ensure that a node can continue to access a volume with the same drive letter, even if the volume is not continually present in the system.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size, in bytes, of the input buffer, which must be greater than or equal to sizeof(MOUNTMGR_TARGET_NAME).

The Mount Manager client loads the following structure with the symbolic link that will persist even after its volume is removed from the system. The initialized structure MOUNTMGR_TARGET_NAME, defined in mountmgr.h, is inserted at the beginning of the buffer at Irp->AssociatedIrp.SystemBuffer.

Output

None

I/O Status Block

If the operation is successful, the Status field is set to STATUS_SUCCESS.

The input buffer size, indicated by InputBufferLength, must be large enough to hold the structure MOUNTMGR_TARGET_NAME and the symbolic link name that follows it. If it is not large enough, the Status field is set to STATUS_INVALID_PARAMETER.

Headers

Defined in mountmgr.h; Include mountmgr.h.


IOCTL_MOUNTMGR_CHECK_UNPROCESSED_VOLUMES

Operation

When a volume arrives in the system, it registers for the MOUNTDEV_MOUNTED_DEVICE_GUID interface class and the Mount Manager receives a Plug and Play notification (see Mount Manager I/O Control Codes for a discussion of this process). When the Mount Manager receives this notification, it queries the client driver that manages the volume for the volume's unique ID. In some cases, however, particularly with clusters, the client notifies the Mount Manager of the arrival of its volume, but then does not respond when queried for the volume's unique ID. The Mount Manager keeps these volumes in a dead mounted device list. Clients can use the IOCTL_MOUNTMGR_CHECK_UNPROCESSED_VOLUMES IOCTL to request that the Mount Manager rescan its dead mounted device list and make another attempt to query the clients on the list for the unique IDs of their respective volumes.

This IOCTL is used primarily for cluster support.

Input

None

Output

None

I/O Status Block

If the operation is successful, the Status field is set to STATUS_SUCCESS.

Headers

Defined in mountmgr.h; Include mountmgr.h.


IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION

Operation

This IOCTL allows a client to simulate a Plug and Play device interface arrival notification with the given volume name. If a client does not register a device interface of type MOUNTDEV_MOUNTED_DEVICE_GUID, the Mount Manager is not alerted of its arrival. However, the client can alert the Mount Manager of its volume's arrival directly by means of this IOCTL.

This IOCTL allows clients to obtain drive letters for newly created volumes during text mode setup when the Plug and Play device installer is not running.

Clients that have registered a device interface of type MOUNTDEV_MOUNTED_DEVICE_GUID in the normal way should not use this IOCTL.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size, in bytes, of the input buffer, which must be greater than or equal to sizeof(MOUNTMGR_TARGET_NAME).

The Mount Manager client loads the following structure with the nonpersistent target device name. The initialized structure MOUNTMGR_TARGET_NAME, defined in mountmgr.h, is inserted at the beginning of the buffer at Irp->AssociatedIrp.SystemBuffer.

Output

None

I/O Status Block

If the operation is successful, the Status field is set to STATUS_SUCCESS.

The input buffer size, indicated by InputBufferLength, must be large enough to hold the structure MOUNTMGR_TARGET_NAME and the symbolic link name that follows it. If it is not large enough, the Status field is set to STATUS_INVALID_PARAMETER.

Headers

Defined in mountmgr.h; Include mountmgr.h.


Volume Manager I/O Control Codes

Volume manager clients use the IOCTLs in this section to communicate with the volume manager.


IOCTL_VOLUME_LOGICAL_TO_PHYSICAL

Operation

The IOCTL_VOLUME_LOGICAL_TO_PHYSICAL request returns physical offsets and physical disk numbers for a given volume logical offset.

For example, a logical volume offset inside a mirrored volume with two plexes corresponds to two physical offsets, one in each of the two disks participating in the mirror. In response to this IOCTL, the volume manager returns two physical offsets and two physical disk numbers for the logical volume offset.

The volume manager supports this IOCTL for all types of basic and dynamic volumes.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size, in bytes, of the input buffer, which must be greater than or equal to the value of sizeof(VOLUME_LOGICAL_OFFSET).

Caller inserts the VOLUME_LOGICAL_OFFSET structure containing the logical offset at the beginning of the buffer at Irp->AssociatedIrp.SystemBuffer.

Output

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size, in bytes, of the output buffer.

The output buffer size must be large enough to hold the structure VOLUME_PHYSICAL_OFFSETS which contains a variable-length array of structures of type VOLUME_PHYSICAL_OFFSET.

The volume manager returns one or more physical offsets and disk numbers in the VOLUME_PHYSICAL_OFFSETS structure at the beginning of the buffer, at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

If the operation is successful, the Status member is set to STATUS_SUCCESS. Otherwise, the Status member is set to the appropriate error code. Possible error codes include the following:

Value | Meaning
STATUS_INVALID_PARAMETER
 | The input buffer is too small.
STATUS_BUFFER_TOO_SMALL
 | The output buffer is too small. The volume manager sets the Irp->IoStatus.Information member to the size of the output buffer the caller should have provided.

Headers

Defined in ntddvol.h. Include ntddvol.h.

See Also

IOCTL_VOLUME_PHYSICAL_TO_LOGICAL, VOLUME_LOGICAL_OFFSET, VOLUME_PHYSICAL_OFFSETS, VOLUME_PHYSICAL_OFFSET


IOCTL_VOLUME_PHYSICAL_TO_LOGICAL

Operation

The IOCTL_VOLUME_PHYSICAL_TO_LOGICAL request returns the logical offset corresponding to a physical disk number and a physical offset.

The volume manager supports this IOCTL as described for all types of basic and dynamic volumes.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size, in bytes, of the input buffer, which must be greater than or equal to the value of sizeof(VOLUME_PHYSICAL_OFFSET).

Caller inserts the VOLUME_PHYSICAL_OFFSET structure, containing the physical offset and physical disk number, at the beginning of the buffer, at Irp->AssociatedIrp.SystemBuffer.

Output

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size, in bytes, of the output buffer, which must be greater than or equal to the value of sizeof(VOLUME_LOGICAL_OFFSET).

The volume manager returns the logical offset in the VOLUME_LOGICAL_OFFSET structure at the beginning of the buffer, at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

If the operation is successful, the Status member is set to STATUS_SUCCESS.

If either input or output buffer is too small, the volume manager sets the Status member to STATUS_BUFFER_TOO_SMALL and the Irp->IoStatus.Information member to the size of the output buffer provided by the caller.

If the given physical disk number and physical offset do not belong to the volume or if they are taken from RAID parity data, this call will fail with STATUS_INVALID_PARAMETER.

Headers

Defined in ntddvol.h. Include ntddvol.h.

See Also

IOCTL_VOLUME_LOGICAL_TO_PHYSICAL, VOLUME_LOGICAL_OFFSET, VOLUME_PHYSICAL_OFFSETS, VOLUME_PHYSICAL_OFFSET


IOCTL_VOLUME_READ_PLEX

Operation

The IOCTL_VOLUME_READ_PLEX IOCTL performs a read on a specific plex of a volume. Since all plexes are identical, the volume manager can retrieve data from any of a volume's plexes during a normal read operation. The volume manager spreads reads among a volume's plexes, in order to balance the I/O load on the physical media and to maximize read performance.

If, however, an application or kernel-mode component must read data from a particular plex instead of letting the volume manager pick one, it can use this IOCTL to do so.

Input

Parameters.DeviceIoControl.InputBufferLength in the I/O stack location of the IRP indicates the size, in bytes, of the input buffer, which must be greater than or equal to the value of sizeof(VOLUME_READ_PLEX_INPUT).

Caller inserts the VOLUME_READ_PLEX_INPUT structure, containing the logical offset, at the beginning of the buffer at Irp->AssociatedIrp.SystemBuffer.

Output

Like IRP_MJ_READ, this IOCTL stores the read data in the memory buffer passed as a memory descriptor list (MDL) in the Irp->MdlAddress field.

I/O Status Block

If the operation is successful, the volume manager sets the Status field to STATUS_SUCCESS.

The VOLUME_READ_PLEX_INPUT structure at Irp->AssociatedIrp.SystemBuffer has a Length member that must be aligned on a 512-byte boundary. If Length does not have the proper alignment, the operation fails and the volume manager sets the Status field to VKE_EINVAL.

Headers

Defined in ntddvol.h. Include ntddvol.h.

See Also

VOLUME_READ_PLEX_INPUT


Storage Class Installer Directives

Some INF file directives are particular to the storage class co-installer. They are documented in this section. The storage class co-installer is registered for the following setup classes:

  • CDROM
  • DiskDrive
  • TapeDrive

Thus, material in this section does not apply to some storage devices, such as medium changers.


The UseINFDeviceDesc Directive

UseInfDeviceDesc is an INF file directive. It is recognized by the storage co-installer for any of the storage device classes for which the storage class installer is registered. However, it is primarily used with tape devices.

This directive indicates to the storage class installer that it must use the device description provided in the INF file to define the device's FriendlyName property in the registry. This permits vendors to choose the name that programs, such as the Device Manager, display for their device. Without this directive, storage class installer's default behavior is to store the device description taken from the SCSI inquiry data, reported by the device's hardware upon enumeration.

For instance, a vendor such as Compaq might use this directive in an INF file that installs a Compaq tape drive to ensure that the Device Manager displays the device's name as "Compaq Tape Drive" instead of displaying a more generic name, such as "DEC Tape Drive".


Kernel Streaming Overview

Kernel Streaming (KS) is a broad term for the services that support kernel-mode processing of streamed data. KS enables efficient real-time streaming for multimedia devices such as sound cards and TV tuner cards.

This section introduces Kernel Streaming topics that are relevant to minidriver development under the following Microsoft-supplied class driver models: Port Class, Stream Class, and AVStream. For information specific to developing minidrivers under AVStream, please see AVStream Overview.

The following diagram shows the kernel streaming model in NT-based operating systems and Microsoft® Windows® Me and later. Note that AVStream is valid only in DirectX 8.0 and Microsoft® Windows® XP.

Microsoft provides three class drivers, all of which broker interactions between the KS layer at the top of the diagram, and the minidriver below. These class drivers are clients of the upper KS layer, which provides a set of services in compliance with the Microsoft-defined WDM-CSA (Windows Driver Model Connection Streaming Architecture) kernel streaming specification.

  • AVStream supports both audio and video minidrivers, and provides additional features not found in its predecessors. Use the AVStream services if you are implementing a new driver, or if your stream or port class-based minidriver could benefit from being ported to use AVStream. See AVStream Overview.
  • Kernel Streaming 1.0 (KS1.0) refers to the Microsoft-supplied Port Class and Stream Class class drivers. These class drivers provide services to facilitate development of audio and video minidrivers. For more information on the Stream Class, please see the Stream Minidriver Design Guide. Port Class is covered in the WDM Audio Driver Design Guide, and video capture and DVD minidrivers are covered in the Video Capture Minidriver Design Guide and DVD Minidrivers, respectively.

KS provides mechanisms for drivers to report capabilities to the operating system. Clients written to run on top of the kernel streaming model can determine the multimedia capabilities of the current platform.

KS drivers can be either filter and functional drivers. The operating system can load filter drivers to transparently extend the multimedia capabilities of a platform.

The WDM Streaming architecture divides processing of data into basic "building-blocks" called filters. These filters serve as the atomic components in the system. Each filter's capability is partly described by a number of connection points called pin factories, from which pin instances can normally be created. Each pin instance can consume, produce, or both consume and produce a data stream, such as digital audio. More specialized tasks can be solved by connecting these filters together, via their pin instances, into a meta-topology (not the same as an internal filter topology discussed later). An example is connecting filters to play filtered and mixed audio.

The WDM Streaming architecture also provides mechanisms for querying filters and controlling filters (for example, getting the volume level, or starting playback). Specific implementation of these mechanisms, such as an interface to pass coefficients to a low-pass audio filter, are also provided.


Kernel Streaming Implementation

Kernel streaming is based on the DirectShow model of filters and filter pins. See the Microsoft Windows Platform SDK documentation for more information about DirectShow.

While components interacting with DirectShow operate in user-mode, Kernel Streaming components run in kernel-mode. KS filters are accessed through file handles, and share an underlying device object per physical instance of hardware.

The following diagram illustrates a filter.

Conceptual Filter

The type of filter is defined by the functional categories to which it belongs. For example, an audio mixer could have a pin that consumes audio data, of which infinite instances can be made to connect to other audio producing filters. The mixer could also have a single pin which produces audio, of which only a single instance can be made.

Communication with this kernel mode filter by its user mode component takes place through file I/O; the communication path is established by calling the Win32 function CreateFile with the name of the device. For example, "\\.\filters\audio\default renderer" could be a link to the audio device which the user configured for default output. PnP also exposes enumeration functions that can be used to locate both hardware-based and software-based filters by supported filter functional categories. For more information on functional categories, see KSPROPERTY_TOPOLOGY_CATEGORIES.

Once a handle has been obtained, communication with this filter from user mode is performed by calling the Win32 function DeviceIoControl. This interface allows parameters that have been serialized into data-blocks to be passed to and from the filter. For instance, one method of communicating with filters via this function is by using a property set exposed by the filter. Property sets provide a way of uniquely identifying a set of characteristics, and defining which parameters are required in order to modify and retrieve these characteristics. For instance, a property could facilitate getting or setting a value such as volume.

Communication from user mode to a pin instance also normally takes place through file I/O operations. However, when establishing a connection to a pin factory, a client can instead choose some other supported method of communication. .

Pin factories represent locations where a filter can consume or produce data. Each pin factory can support a number of different data formats, such as 16-bit 44K audio and 16-bit 22k audio. The pin factories that are available on a filter, and their formats, can be enumerated from the filter. Thus, the pin factories are not seen as separate objects from the filter, but rather as a convenient grouping of capabilities. For example, if pin factory 2's available formats are desired, they can be enumerated by calling DeviceIoControl on the filter requesting the property "PinFormats" for pin factory number "2".

Configuration of a PCM Sample Sent to an FX Processor and Then to an Audio Renderer

A pin factory just represents the possible connection point, and before a client or another filter can stream data to or from a filter it must first create a pin instance connection and obtain a handle to that connection. This is done by specifying the pin factory number and the handle of the filter on which the connection is going to be made. Once the connection is made, a handle is passed back that can be used to stream data to or from. Note that this is similar to how classes and instances work in C++. The pin factory is the class of which instances (connections) must be made.

The connection path may have in or out data flow, such as demonstrated in the illustration above, in which audio data moves in a particular direction. It is important to note that although IRP flow through an IRP stack is top-down, the state transition path must be performed bottom-up to provide the proper stack order and depth. As a result, each pin factory must specify a communications property of sink, source, or both that determines the connection type for each pin. For an IRP-based medium, this represents whether the pin is an IRP sink, source, or may act as either a sink or a source of IRP's. This is not to be confused with data flow, as this describes how communication occurs once a connection is established.

Dispatching a State Change Request.

This illustration displays the communication and dataflow pin properties for the FX processor example.

An upper layer component submits a connection request to the kernel-mode filters using the connection function KsCreatePin, which in turn forwards this request to the filter. The data format property defines the raw data format of the medium.

Device Objects and Connections

The above illustration displays the file handles created as the result of connection requests. The client requests a connection between the source and the sink pins. The sink connection point is always created first, and the handle is passed in when creating the source end of the connection. In this example, these filters create file handles to the connection in response to the request. As a result, the device object underlying the source will base its stack size on the stack size of the sink device object, plus one. The source device object will maintain a pointer to the sink device object, process incoming requests modifying data as necessary, and forward the requests to the lower level driver using the IoCallDriver function of the NT kernel. A file object is kept for each step of the path, which is handed to the next filter in the path. A handle to this file object is returned by the connection request, and is what is passed to the source connection point. The file object is referenced so that the handle may be closed by the client if no longer necessary. If instead the data flow was reversed, and the above rendering filter was a capturing filter, the order of connection would remain the same if the communication types on the various pins remained the same.

Creating a connection does not imply creating new device objects to represent the connection. A single underlying device object is used to support an instance of a filter, and all the instances of pins on that filter. The context information would normally be kept in the FsContext or FsContext2 member of the FILE_OBJECT structure. So context information is preserved while non-paged memory use is kept at a minimum.

As illustration below, a software digital audio mixer may provide an indeterminate number of connections to the source pin and provide a single destination pin. The pin properties define the medium; for this example the medium is DeviceIoControl. However, each pin may specify multiple mediums allowing the upper layers to determine the best possible data medium for the connection path.

Configuration of Pins to Mix Multiple Audio Sources.

A device contains a stack depth indicator which the kernel uses when creating Irp's for that device, no matter which, if any file object is associated with the IRP (It is possible for a kernel mode client of a device to not have a file object associated with an IRP, but this is a special case, such as PnP Irp's). When various connections are made to a filter, this stack depth must be maintained such that any of the resulting I/O paths will have enough stack locations for any IRP passed through the filter. This depth is recalculated each time a pin transitions out of a Stop state. It is important for a filter to keep this depth as small as possible in order to minimize system resource usage.


Kernel Streaming Headers

All Kernel Streaming and AVStream reference material covers structures and functions that are declared in ks.h. This is the header that the minidriver needs to include in order to access the Microsoft-supplied KS and AVStream class driver support.


Connection

The connection interface consists of IRP_MJ_CREATE, which is sent to the device object underlying the filter which owns the target pin on which the connection is being created. A connection request is either just a request to create a connection on a pin, or a request sent to one filter to connect a specified pin handle on another filter. In the former case, one would send a request to a filter to create a connection on its pin. In the latter case, the resultant handle from the aforementioned connection would be passed in a connection request to a filter to create a connection on its pin. That is, the second case must have a pin to connect to (sink), whereas the first case can be thought of as a connection from (source). Again, this terminology is only in reference to how the filters are connected together, and has no bearing on the direction in which data flows.

The second connection would increment the reference count on the underlying file object of the pin handed to it, and return a new file handle to the caller. A close would cause the connection to be terminated, however the handle on the first pin might still be open, so that must also be closed before the underlying file object is destroyed. This also implies that if the first pin is relying on resources provided by the second pin, it must be notified by the second pin when the connection is being terminated.

A connection is always represented by a file handle in user mode, which can be closed in order to terminate the connection. Within the filter, reference counts on the underlying FILE_OBJECT are incremented and decremented as other connections are created and destroyed. This means that after connecting a filter's pins, none of the handles need to remain open excepting that which describes the connection points in the graph of filters (the second handle created when establishing a connection between pins). This includes the handle to the filter itself, which will be reference counted by pin instances as they are created. This also means that abnormal termination is handled robustly through the O/S process cleanup of handles. So the connection interface can be thought of as an IRP_MJ_CREATE which opens a pin instance with an extended set of parameters.

The extra parameters on the connection request specify the medium, interface, and data format to use on the connection. The medium is the basic method of communication that the connection will use. The IRP-based medium is what would normally be used, but this may be something different for filter's whose functional piece resides on some DSP, and whose communication path could be contained on that DSP. The interface is the group of methods and properties to use, implemented on the specified medium. This could be a streaming music interface which would indicate a specific set of properties and methods available. The data format is the chosen format to use with that interface. This could be dynamically changed in some instances.

The KsCreatePin function generates a call to NtCreateFile, using the filter file handle as the root, and the connection structure as the file name information. When a device routes this to its pin create dispatch function, the IRP is validated using KsValidateConnectRequest, which retrieves the connection structure.

For example:

The kernel mode client locates and opens the wave device filter and software mixer filter using PnP interfaces. This results in handles WaveDeviceHandle and SWMixHandle.

The client finds the appropriate pin factory for the connection on each device, enumerating properties on each pin factory if necessary.

The client calls the connection helper function to establish the connection on each filter, passing the medium, interface, and data format in a connection structure:

Error = KsCreatePin(
  IN SWMixHandle,
  IN Connect,
  IN DesiredAccess,
  OUT &PinHandle);

The function sends an IRP_MJ_CREATE to the filter, specifying the source pin factor identifier, and in the case of an IRP-source, the handle to the IRP sink pin previously created.

There are two properties within the pin property set which can be used to assist in determining if connections can be made, and using what data format. Depending on the use of these, a client need not know the structure of a specific data format type, or data range type. These are data ranges, and data range intersection. Querying data ranges allows a client to determine the full set of available data ranges for a specified pin. Querying data range intersection allows a client to specify a list of data ranges to choose from, and retrieve the best data format to use in connecting the specified pin. Given the internal topology, a graph builder can map the path from one data format on a pin, to another data format on some other pin, and determine if this path generates the correct result.

Data range intersection is meant to be used in conjunction with topology, and data ranges in order to choose a data format to connect filters, without having to know the specifics of a data format or data range. That is, the client could treat data formats as opaque structures, and still use these properties to choose viable data formats with which to make connections. Obviously the data range intersection is just that, an intersection, which may contain multiple choices. However, only the "best" choice would be returned by the filter in the form of a data format structure. This data format could then be passed on to use in determining how to make the pin connection. In some cases the entire graph of connections could be determined before actually making a single connection. Clients which have intimate knowledge of data formats and ranges may elect to perform their own intersection and choose a more appropriate data format rather than using what the filter proposes as the "best" format.

For instances wherein the affected pins and their data ranges are not known until the connection is actually made, such as a splitter filter which consumes the Active Streaming Format, and produces individual streams for each stream in the original stream, data range intersection may fail with an error specific to this case.


Connection Clients

Connections are instantiated through requests by a client. In some instances this client may be a filter which is abstracting underlying connections, but for the most part, the client is some set of tools such as DirectShow's automated graph creation. This client may not actually know that there are kernel-mode filters involved, but instead may be communicating with some generic DirectShow user mode filter which has enumerated properties and methods on the kernel mode component in order to present them as interfaces in user mode. Other clients may live on top of DirectShow, or instantiate the kernel mode filters directly. Such clients could include DirectX, VB, or Active Animation. These would provide solution graphs to specific problems, but may not use DirectShow to build the graphs. The advantage would be mostly one of efficiency, and creating an exact solution, but would be at a cost of being able to drop other filters into that same graph in order to perform additional synchronization. So at the very least it would be appropriate to use DirectShow filter graph objects, even if automated graph building is not used.

This figure depicts using DirectShow as the connection client, with the standard Filter Graph Editor sample application showing the visual representation of the graph. From the point of view of DirectShow, these filters are just standard user mode components.

A client is responsible for:

  • Attempting to determine initial compatibility between two pins before requesting that they be connected, thereby making it more likely that a connection is possible.
  • Instantiating any intermediate filters needed in order to complete the connection in a compatible manner.
  • Assigning any quality management, and master clock.

If the user mode DirectShow filters are to be bypassed, the client is also responsible for negotiating medium, interfaces, and data formats to be used between the kernel mode filters. Normally this is something which the user mode DirectShow filters perform. The end result is that these connections become data and control paths, and are used by applications in synchronizing and transforming media streams.


Streaming Interface

The standard streaming interface consists of IOCTL_KS_READ_STREAM and IOCTL_KS_WRITE_STREAM, which are sent to pin connections to send or receive data in a non-buffered manner. These requests contain a stream header list, each optionally pointing to the actual stream data. The headers also may contain the presentation time and duration (depending on the data format negotiated, e.g., MPEG II may not always send buffers with time stamps). These presentation times are then used to synchronize to the master clock's presentation time (when a master clock is being used). Altering this presentation time changes the synchronization between filter pins. This also enables easily relocating the synchronization points without modifying the data itself, and without maintaining an entire history of transforms to apply to an underlying physical clock in order to report that presentation time. The filter graph can then easily maintain timings with sample accuracy. For example, sending data through a filter that time-shifts audio samples and requires an external stream to synchronize to this shifted data is merely a matter of translating presentation timestamps.

The presentation time on a stream need not start at zero, but always progresses. For instance, playback from some file source may begin at some point within the file, so that the initial presentation time in the first stream buffer would most likely not be zero. Any change in this presentation time must be performed by a filter which alters such times, such as through some script. So presentation time can generally be thought of as "file" position, though the source may not at all be from a file. Some data formats allow buffers to be sent without time stamps and/or duration specified. They must use the appropriate flags specified below in that case.

DeviceIoControl(
  IN DeviceHandle,
  IN IOCTL_KS_WRITE_STREAM,  /* or IOCTL_KS_READ_STREAM */
  IN NULL,
  IN 0,
  OUT &StreamHdrList,
  IN StreamHdrCount,
  OUT &BytesReturned,
  OUT &Overlapped);

If the buffers passed to the streaming interface need to be modified in-place by the filter, the requirement must have been negotiated when determining an allocator. This enables efficient in-place transforms to be done on a stream of data without having to copy data as it passes through a series of filters. Additional media-specific streaming interfaces may be defined. For example a Music streaming interface may define additional music-specific properties in addition to the standard set, not to imply that media-specific streaming interfaces are always a superset of a basic streaming interface.

The stream header may also indicate that this is the end of a media stream or sequence. This is used to stop any QM problems from being generated, or to show the end of a segment within a stream containing discontiguous segments. If these flags are used on a write, there may be no actual data buffer attached to the request.


Kernel Streaming Client Interface

The interface a kernel streaming driver presents to a client consists of a set of file objects. Each file object represents a different capability of the driver. Clients issue I/O requests to file objects to control different aspects of the driver.

The file objects of a kernel streaming driver fall in several distinct families:

  • Filters

    A KS filter encapsulates a functional unit on a device. A driver can support multiple instances of the same filter. A driver for a multifunction device can support several different types of KS filters. Do not confuse KS filters with filter drivers — every type of KS driver, either functional or filter, has one or more KS filter file objects that it creates.

  • Pins

    A pin represents an I/O channel on the device. Clients can connect to pins, and connect pins to each other. Clients can also query a pin for the types of data formats it supports.

  • Clocks

    Drivers that support on-board clocks expose the clock as a file object. Clients can query the clock time, as well as request to be notified when the clock reaches a certain time.

  • Allocators

    Drivers that support custom memory management interfaces, for example management of device on-board memory, expose the interface as a file object. Clients can use the file object to allocate and deallocate memory.

KS file objects are organized hierarchically — clients use IRP_MJ_CREATE to instantiate KS filters on the driver, and in turn use IRP_MJ_CREATE to instantiate pins on the filter, and clocks and allocators on a pin.

The kernel streaming architecture provides an extensible mechanism for drivers and clients to interact. KS objects support several different semantic concepts:

  • Properties

    KS objects support properties. Clients can query the object to determine what types of properties it supports, and it can get or set such properties. For example, audio driver pins can support properties to allow clients to get or set the device volume.

  • Events

    A KS object can define the types of asynchronous events it supports. Clients can query the object to determine what events it supports, and they can request to be notified when an event occurs. For example, a client can request a clock object to notify it when the clock reaches a certain timestamp.

  • Methods

    Like COM objects, KS objects can support methods. For example, allocator objects support methods to allocate or deallocate memory.

Microsoft defines standard sets of properties, events, and methods. Clients and drivers can support these sets to cooperate to support standard forms of multimedia. Drivers can also support custom sets of properties, events, and methods that device-specific clients can use to interact with a particular device.

Clients interact with KS objects through a set of IRP_MJ_DEVICE_CONTROL IOCTLs. Clients specify the driver and kernel streaming object in the DeviceObject and FileObject members of the IO_STACK_LOCATION for the IRP.

  • IOCTL_KS_READ_STREAM

    Clients use this to read data from a pin.

  • IOCTL_KS_WRITE_STREAM

    Clients use this to write data from a pin.

  • IOCTL_KS_PROPERTY

    Clients use this IOCTL to get or set properties, or to determine the properties supported by a KS object.

  • IOCTL_KS_ENABLE_EVENT

    Clients use this IOCTL to request notification of an event type, or to determine the events supported by a KS object.

  • IOCTL_KS_DISABLE_EVENT

    Clients use this IOCTL to rescind a previous request notification.

  • IOCTL_KS_METHOD

    Clients use this IOCTL to execute a method on a KS object.

Drivers do not need to support these I/O requests directly. Microsoft provides class drivers to handle the intricacies of supporting these requests. See Kernel Streaming Driver Implementation for details.


Kernel Streaming Driver Implementation

To ease the development of kernel streaming drivers, Microsoft provides class drivers that handle most of the work of supporting kernel streaming semantics:

  • The audio port class driver supports internal sound cards on a system bus such as ISA or PCI.
  • The stream class driver supports kernel streaming drivers which process video signals, including DVD devices, video capture devices. This class driver also supports external sound devices.
  • The AVStream class driver supports both audio and video minidrivers. Use AVStream for development of new classes of minidrivers, such as Broadcast Driver Architecture.

Each class driver provides an interface to support kernel streaming objects and their I/O requests. Drivers provide a description of the KS objects they support, and the class drivers transparently handle the creation of file objects, and receiving the IOCTL_KS_XXX requests.

The audio port class driver is documented in Audio Miniport Drivers. The stream class driver is documented in the Stream Minidriver Design Guide. For more on AVStream, please see the AVStream Overview.

For each individual multimedia technology area, Microsoft has defined standard kernel streaming semantics that drivers support. Audio, video capture and DVD devices are documented in the following chapters:

WDM Audio Driver Design Guide

Video Capture Minidriver Design Guide

DVD Minidrivers


Efficient Streaming

Kernel streaming is more efficient when the number of ring transitions is minimized. The following diagrams indicate different possible scenarios involving various numbers of ring transitions. Each ring transition is time-consuming due to parameter validation, security validation, and possibly data copying. Accordingly, your kernel streaming package will be more efficient with fewer such transitions.

The following diagram represents one possible flow of data. Code modules executing in user mode are shown above the double line; code executing in kernel mode is shown below the double line. The first transition of the data stream between user mode and kernel mode might be, for example, to achieve decompression. The second transition might be to perform rendering. In this case, KsProxy handles the transition to kernel-mode, effectively making a kernel-mode component appear as a DirectShow module to user-mode modules.

Data Streaming Involving Multiple User Mode to Kernel Mode Transitions

. In the next example, almost all the data streaming takes place in kernel mode. The filter modules executing in user mode apply controls to the kernel-mode device drivers and hardware. For example, in the case of a video data stream, a user-mode filter might apply a color correction control to the kernel-mode driver/hardware renderer.

WDM Data Streaming Involving One Mode Transition

The following diagram shows a stream entirely produced and consumed in kernel mode, with only controls exposed to the user mode client. In this case, , a source filter reads a file, passes it through a hardware based codec, and then passes it on through the remaining filters. If the filters in-between reside on the same physical hardware, they may negotiate a faster transfer mechanism or interface, which avoids memory copies, and possibly avoids use of the host CPU in their communication.

WDM Data Streaming Involving No Mode Transitions


KS Properties, Events, and Methods

Each KS object supports intrinsic operations that allow clients to get and set object state, execute object methods, and register notification callbacks for events. Drivers support each of these categories of operations — properties, methods, and events — in a standardized manner.

  • Set

    Functionally similar operations are grouped together in a set. Each property, event, or method set is identified by a GUID. Microsoft defines GUIDs for standard technology-specific operations. Drivers can define their own GUIDs for custom operations.

  • Identifier

    Each operation is specified by an ID number within the set.

  • Operation-specific identification data

    Specific operations may require additional data to be completely specified. For example, pins on an audio device support the KSPROPSETID_Audio property set. An audio pin may support several different audio channels. Clients getting or setting certain KSPROPSETID_Audio properties must specify the audio channel to which the request applies. Currently, the only Microsoft-defined KS operations that require additional data are property sets.

Standard GUIDs and identifiers for general-purpose operations are found in the header ks.h. Standard GUIDs and identifiers for particular classes of multimedia technology are found in ksmedia.h.

Clients issue I/O requests to get and set properties, execute methods, and register or unregister event notifications. For each of these I/O requests, the client passes two buffers:

  • Instance Specification. The client specified the operation instance to be the target of the I/O request. Every instance specification begins with a header that describes the operation set, operation ID, and operation flags, followed by any operation-specific identification data. The following table describes the header structures.
    Operation type | Instance specification header
    Property | KSPROPERTY
    Event | KSEVENT
    Method | KSMETHOD

    To handle operations that require extended data structures, drivers use extended data structures that contain the instance header as the first member. For example, properties in the KSPROPSETID_Pin property set use the KSP_PIN structure to specify the property instance. The appropriate extended data structure is documented with each individual property set.

  • Operation data. The client specifies a data buffer for the operation. Property requests use this buffer to either get or set the property. Method requests use this buffer for method input or output. Event notification requests use this property to determine the event notification type requested.


KS Properties

Filters and pins can support property sets that represent things like the number of pins available and the types of connections they can make. Property sets are also used to configure filters and pins. Property sets are a method for accessing a group of related data on an object, and each property request may be fulfilled either synchronously or asynchronously.

Each property set has a unique identifier, which is used to access a requested property set. The method of using unique identifiers for property sets allows custom driver extensions that will not conflict with any other custom extensions or future development.

Filters and pins support property sets using the IOCTL_KS_PROPERTY device I/O control. If a filter or pin must support multiple distinct copies of the same property set, it must use instance identifiers.

The flags of an identifier are used to distinguish between Getting a property and Setting a property.

To get or set individual properties, clients call the Win32 function DeviceIoControl with an IOCTL_KS_PROPERTY request. The class driver in use receives an IRP, in turn, and then the class driver calls KsPropertyHandler.

KsInitializeDriver initializes the driver object of an AVStream driver. Clients make this call from DriverEntry. Note that clients wishing to handle device initialization on their own do not need to call this function. KsInitializeDriver takes as one of its parameters a pointer pointing to an array of structures containing filter descriptors for the individual filter types supported by the device in question. Moving down the chain to properties, KSFILTER_DESCRIPTOR has a pointer to a KSAUTOMATION_TABLE, a new AVStream feature that consolidates properties, methods, and events. Defining Automation Tables in the BDA Design Guide contains more information on automation tables. As such, a KSAUTOMATION_TABLE contains a pointer to an array of KSPROPERTY_SET objects. KSPROPERTY_SET is a KS 1.0 structure that contains a pointer to an array of KSPROPERTY_ITEM objects. Another KS 1.0 object, KSPROPERTY_ITEM contains pointers to handlers for property events, such as Get and Set.

The Flags member of KSPROPERTY specifies the type of operation: KSPROPERTY_TYPE_GET for a get property request, and KSPROPERTY_TYPE_SET for a set property request.

When the client makes a get property request, the driver returns the property in the data buffer the client passes. When the client makes a set property request, the driver uses the data in the passed data buffer to specify the new property value.

Additional values for the Flags member allow the client to request information about a property. For example:

  • KSPROPERTY_TYPE_SETSUPPORT

    If the client specifies this flag, the driver returns no data in the data buffer, but it returns STATUS_SUCCESS if it supports the property set, and an error code if it does not.

  • KSPROPERTY_TYPE_BASICSUPPORT

    If the client specifies this flag, the driver returns STATUS_SUCCESS if it supports the property, and an error code if it does not. In the data buffer, the driver passes information about the property, such as if the property is read-only, write-only, or read-write.

All property sets must support the KSPROPERTY_TYPE_BASICSUPPORT and KSPROPERTY_TYPE_RELATIONS flags. These allow queries for the support of a specific property within a property set, optionally valid values, and related properties, if supported by that property. Do this by specifying a support handler in the SupportHandler field of KSPROPERTY_ITEM.

For basic support (KSPROPERTY_TYPE_BASICSUPPORT), the flags returned from a query determine whether one has read, write, or read/write access to the property. The queried identifier is appended to the structure as property-specific data. For multiple instance property sets, this refers to all the sets as a whole, rather than any particular instance. When querying for related properties, a list of related properties is returned.

Furthermore, the return from a KSPROPERTY_TYPE_BASICSUPPORT request depends on the size of the output buffer passed to the call. If the output buffer is the size of a ULONG, only the access flags are returned. If the output buffer is the size of the KSPROPERTY_DESCRIPTION structure described below, the structure is filled with the access flags (KSPROPERTY_TYPE_GET and KSPROPERTY_TYPE_SET that are the same flags used when Setting and Getting the property), the inclusive size of the entire values information, the property value type information, and the number of members lists that would normally follow the structure. Otherwise the size of the output buffer must be large enough to contain both the description header, and all values information (excluding the default value that can be queried separately). This allows a client to query the size of values information before attempting to acquire it. Please see KSPROPERTY_DESCRIPTION for more information.

Also see KSPROPERTY_MEMBERSHEADER for more information.

The property values within a filter are stored in a slightly different manner, with the aim towards easy static definitions, and enumeration by a helper function that converts to a serialized format for return. Its property item description (KSPROPERTY_ITEM is described later) may optionally point to a KSPROPERTY_VALUES structure, which contains a list of value lists.

Each outer list element is a wrapper for a KSPROPERTY_MEMBERSHEADER structure, and the list of associated values. The values list depends on the description in the header, containing a range, stepped range, or straight values.

  • KSPROPERTY_TYPE_DEFAULTVALUES

    If the client specifies this flag, the driver uses the data buffer to return a description of its value type, including possibly its allowed range and default value. This flag is similar in result to KSPROPERTY_TYPE_BASICSUPPORT, except that any values returned are those that have been marked with KSPROPERTY_MEMBER_FLAG_DEFAULT in KSPROPERTY_MEMBERSHEADER.Flags.

  • Relations

    For relations support (KSPROPERTY_TYPE_RELATIONS) the return also depends on the size of the output buffer passed to the call. If the output buffer size is zero, the size that would be used to return the related properties is returned in BytesReturned with a warning status of STATUS_BUFFER_OVERFLOW. Else if the buffer is the size of a KSMULTIPLE_ITEM structure, both the byte size and count of relations is returned. Else the buffer is expected to be long enough to return the KSMULTIPLE_ITEM structure and all related property identifiers, which is returned as just a list of KSIDENTIFIER structures. This is how a client determines the effects of changing this property, which may affect properties in completely different property sets. The assumption is that if a related property is returned in the list, that is all the information necessary to find that property. I.e., it belongs to a property set on the same pin, filter, or clock, and there is only one such property set, not multiple instances, or refers to the same set instance.

  • Serialization

    Support for serialization of a property set is done through KSPROPERTY_TYPE_SERIALIZESET and KSPROPERTY_TYPE_UNSERIALIZESET. These allow a built-in method of acquiring, or setting the state of multiple properties with a single call from the client. These are broken up into multiple calls by KsPropertyHandler if the KS handler is being used to process property requests. When using this handler, the property set definition controls which properties are to be serialized. The KSPROPERTY_ITEM.SerializedSize is checked for a non-zero value indicating the size in bytes of the property, where –1 is unknown and must be queried (all unknown properties begin with a KSMULTIPLE_ITEM structure that can be queried separately). A value of zero indicates that the property should not be serialized. To query for the total size a serialization would take, pass a zero length buffer. The in BytesReturned is filled with the size in bytes the buffer must be to serialize the set and a warning status of STATUS_BUFFER_OVERFLOW is returned. A buffer allocated that size can then be filled with the serialized data.

    The format of the serialization buffer is a KSPROPERTY_SERIALHDR, followed by serialized properties. Each property that follows contains a header (KSPROPERTY_SERIAL), followed by the property data, with the start of each property on FILE_LONG_ALIGNMENT. Note that the serial header structure is defined to be on FILE_LONG_ALIGNMENT.

  • Raw Serialization

    Support for raw serialization of a property set is done through KSPROPERTY_TYPE_SERIALIZERAW and KSPROPERTY_TYPE_UNSERIALIZERAW. This can only be supported if a property item handler exists, as the data format is private to the property set. The standard KsPropertyHandler function just passes this on to the handler, if one exists. Size of such serialization can also be queried by passing a zero length buffer to a serialize raw request. Since handlers are attached to property items, and not the property set, then a specific item within the property set must be specified in the Property parameter. This handler may deal with multiple properties within the set.

  • Parameter Access Macros

    The following macros are defined to allow access to Irp->Tail.Overlay.DriverContext parameters in the IRP passed to a handler function. These are initialized by KsPropertyHandler and KsPropertyHandlerWithAllocator.

  • KSPROPERTY_SET_IRP_STORAGE

    This macro accesses a pointer to the KSPROPERTY_SET in which the property was located.

  • KSPROPERTY_ITEM_IRP_STORAGE

    This macro accesses a pointer to the specific KSPROPERTY_ITEM located. Note that this value is only set when using KsPropertyHandlerWithAllocator.


KS Events

See KS Properties, Events, and Methods for an overview of KS operations.

See Event Handling in AVStream for details on how minidrivers running under AVStream should handle events.

Clients of a driver can request to be notified when a certain condition holds. For example, a client can schedule to take a specific action when the time stamp on a data stream reaches a certain point.

To request event notification, the client submits an IOCTL_KS_ENABLE_EVENT request. In the data buffer of the request, the client passes a KSEVENTDATA structure that describes how the driver should notify the client when the event occurs.

Clients can unregister an event through the IOCTL_KS_DISABLE_EVENT request. To identify the event, clients passes the address of the original data buffer. This address does not have to point to the original data buffer — the driver simply uses it to identify which event notification to disable.

An event type may require additional parameters of the event notification to be specified. For example, the KSEVENT_CLOCK_POSITION_MARK event on a clock is triggered when the clock reaches a certain time stamp. Clients that register to be notified of this event must also specify the timestamp that triggers the event. Any additional data parameters are passed in the data buffer after the KSEVENTDATA structure. Drivers that support such an event type use an extended data structure, whose first member is KSEVENTDATA, to hold the notification data. The structure types are discussed with the respective event set.

The client can specify different options for the event notification within the Flags member of KSEVENT:

  • KSEVENT_TYPE_ENABLE

    The driver notifies the client each time the event occurs, until the client explicitly unregisters the notification.

  • KSEVENT_TYPE_ONESHOT

    The driver notifies the client the first time the event occurs. The client is not notified on any subsequent occurrences of that event, and does not need to unregister the notification.

  • KSEVENT_TYPE_ENABLEBUFFERED

    Instead of notifying the client, the driver queues event notifications. The client then issues a second IOCTL_KS_ENABLE_EVENT request with the KSEVENT_TYPE_QUERYBUFFER to receive the queued event notifications.

Clients can also use the KSEVENT_TYPE_SETSUPPORT and KSEVENT_TYPE_BASICSUPPORT flags to probe a KS object for its support of an event set, or a specific event.


KS Methods

See KS Properties, Events, and Methods for an overview of KS operations.

Clients use the IOCTL_KS_METHOD request to execute a method on a KS object. The Flags member of KSMETHOD specifies the validity of the data buffer for the operation: KS_METHOD_TYPE_NONE if the data buffer cannot be read or written to, KS_METHOD_TYPE_READ or KS_METHOD_TYPE_WRITE if the data is read- or write-only, and KS_METHOD_TYPE_MODIFY if the data buffer can be both read or written.

Clients can also use IOCTL_KS_METHOD to query if a driver supports a method set by specifying KS_METHOD_TYPE_SETSUPPORT, or a specific method within a method set by specifying KS_METHOD_TYPE_BASICSUPPORT.


Method Sets

Method sets are used to perform an action, rather than merely setting or retrieving an attribute as in properties. As a general rule, if an aspect of a device is manipulated by "getting" and "setting" it, then it is most likely a property. However, if it is something that performs an action, such as allocating memory, then it is most likely a method.

Method sets provide a way to access related actions. Each method request may be fulfilled either synchronously or asynchronously. The method sets themselves have unique identifiers, which are used to retrieve the correct method set requested. The method of using unique identifiers for method sets allows custom driver extensions that will not conflict with any other custom extensions, or future development.

Filters or pins support method sets using the IOCTL_KS_METHOD device I/O control. If a filter or pin must support multiple distinct copies of the same method set, it must use instance identifiers.

Although similar to a property set, the parameters for a method differ in that a method may pass no information, or pass it in, out, or bi-directionally. The expected parameter passing type is determined by the definition within the filter, and must be known to the client. The filter uses the first group of flags to define the type of method. The client uses the second set of flags when initiating a method request. These flags indicate what action, if any, will take place on the second buffer of the device I/O control.

The request is passed using the KSMETHOD structure, which may contain instance information appended to the structure. A method-specific buffer may be passed.

All method sets must support the KSMETHOD_TYPE_BASICSUPPORT flag, and allows one to query for the support of a specific method within a method set. The buffer is returned with the flags specifying the type of support for the method (KSMETHOD_TYPE_WRITE, etc.), or an error is returned. In order to query for support of a method set in general, use the KSMETHOD_TYPE_SETSUPPORT flag. In this case the identifier is ignored.

The IOCTL_KS_METHOD is defined using the METHOD_NEITHER flag. However, the buffers are copied as needed when processed using the KsMethodHandler service. The first buffer is copied, and the second buffer is copied if needed according to the above flags. Therefore access exceptions on this data is not a problem within method handlers called by this service, except for the case of KSMETHOD_TYPE_SOURCE in combination with KSMETHOD_TYPE_NONE. Refer to the API section for details on this service.

Parameter Access Macros

The following macros are defined to allow access to Irp->Tail.Overlay.DriverContext parameters in the IRP passed to a handler function. These are initialized by KsMethodHandler and KsMethodHandlerWithAllocator.

KSMETHOD_SET_IRP_STORAGE

This macro accesses a pointer to the KSMETHOD_SET in which the method was located.

KSMETHOD_ITEM_IRP_STORAGE

This macro accesses a pointer to the specific KSMETHOD_ITEM located. Note that this value is only set when using KsMethodHandlerWithAllocator.

KSMETHOD_TYPE_IRP_STORAGE

This macro accesses the type of method as described in the KSMETHOD_ITEM. If the method will be processed asynchronously using KsDispatchSpecificMethod, this storage must be maintained intact.


KS Filters, Pins and Node Topology

This section introduces the basics of pins and their interactions.


Pin Connections

To interact with a KS driver, a client instantiates a KS filter on that driver. Clients normally instantiate a KS filter through Microsoft® DirectShow®. A driver can support multiple types of filters, and multiple instances of the same type of filter. Typically, a driver might support multiple types of filters if it supported multiple types of multimedia functionality. When the client instantiates a KS filter, the driver creates a file object. The client sends all subsequent kernel streaming I/O requests to filter, or any child file objects it creates.

Each KS filter can support several different streams of data simultaneously. To set up a data stream, the client instantiates a pin on the filter. The filter represents each pin as a file object subordinate to the file object for the filter. The client instantiates a pin by sending an IRP_MJ_CREATE request to the filter.

Pins come in different flavors that determine how they can be used:

  • IRP source versus IRP sink

    An IRP sink pin responds to IOCTL_KS_READ_STREAM and IOCTL_KS_WRITE_STREAM requests; an IRP source pin issues them. A client can send I/O requests directly to an IRP sink pin. When a client instantiates an IRP source pin, on the other hand, it specifies an IRP sink pin the IRP source connects to. Once connected, the IRP source pin transparently reads or writes data to the IRP sink, with no further intervention by the client required.

  • Data source versus data sink

    A data source pin provides data, while a data sink pin consumes data. Data source pins can only be connected to data sink pins. Note that the property of being a data source or sink is independent of being an IRP source or sink. For example, the client can connect a data source, IRP sink pin to a data sink, IRP source pin. The IRP source pin sends IOCTL_KS_READ_STREAM requests to fetch data from the IRP sink.

By forming connections between KS filters, a client can dynamically assemble a filter graph through which data can flow transparently. For example, a client could dynamically load a filter that translates between audio data formats, and attach it to serve as a bridge between two devices that speak different formats.

Note that the DDK provides the KsStudio utility in the tools\wdmaudio directory of the DDK. The KsStudio utility can be used to build, examine, and test WDM KS filter graphs on Microsoft® Windows® 98 and later and Microsoft® Windows® 2000 and later. Although the KsStudio utility is designed primarily for audio filter graphs, it can be used to build and explore graphs for any WDM KS filters.

When a client performs I/O, it usually has specific requirements for the type of data it wishes to send or receive from the device. For example, a client can choose whether it receives audio or video data from a DVD player. To this end, KS filters expose several different pin factories. In its create request, the client specifies a pin factory, and the filter creates a pin of that type for the connection. The filter can create one or many pins from the same pin factory.

To provide for run-time discovery of pin factories and their capabilities, KS filters support the KSPROPSETID_Pin property set. Clients use the KSPROPERTY_PIN_CTYPES property of this property set to determine the number of pin factories supported by the filter. (See KS Properties for a general description of properties and property sets.)

The other members of the KSPROPSETID_Pin property set allow clients to discover individual properties of each pin factory. Clients can query for the following pin factory properties:

  • Communication direction

    (KSPROPERTY_PIN_COMMUNICATION) This property specifies the direction of IRP flow on pins instantiated by the pin factory. Pins can be IRP sources, IRP sinks, both, or neither.

  • Dataflow direction

    (KSPROPERTY_PIN_DATAFLOW) This property specifies the direction of data flow on pins instantiated by the pin factory. Pins can be data sources, data sinks, or both.

  • Data formats

    (KSPROPERTY_PIN_DATARANGES, KSPROPERTY_PIN_CONSTRAINEDDATARANGES, and KSPROPERTY_PIN_DATAINTERSECTION) Pins typically can support only certain data formats. These properties specify the data formats supported by pins instantiated by the pin factory. See KS Data Formats and Data Ranges for details.

  • Medium

    (KSPROPERTY_PIN_MEDIUMS) Devices can support custom communication mediums that bypass IRP processing. For example, a DVD device might be able to write directly to the video card, bypassing the CPU. The KS filter represents such mediums by a GUID that represents the medium set, and an ID number that identifies the medium within the medium set. Clients use this property to request a list of all mediums supported by pins instantiated by the pin factory. Clients specify the actual medium to use when they connect to the pin.

  • Interface

    (KSPROPERTY_PIN_INTERFACES) Pins instantiated by the pin factory can require a certain set of properties, events, and methods. The KS filter uses the interface property to indicate the pin factory requirements. Each interface is identified by a GUID that represents the interface set, and an ID number that identifies the interface within the interface set.

  • Category

    (KSPROPERTY_PIN_CATEGORY) The KS filter uses this property to indicate the standard functional category of pins instantiated by the pin factory.

  • Name

    (KSPROPERTY_PIN_NAME) The KS filter can provide names for each of its pin factories in the Registry.


Pin Internal Topology

KS filters may also support internal connections. For example, consider a simple filter that has one data sink pin and one data source pin. The filter receives incoming data on the data sink pin, processes it internally, and writes it to the data source pin. In the following figure, the pins are shown as heavy line segments. Internally, the filter connects the data sink pin to an internal processing unit, a node, which in turn is connected to the data source pin.

Diagram of a Simple KS Filter

More complicated devices may combine or split data flows between pins. For example, consider an audio mixer that supports several pin instances that accept data streams. The mixer combines them into a single stream, and writes that stream to a data source pin. Graphically, we could represent the data flow as follows:

Diagram of a Mixer

Each input pin can be thought of as connected to output pins on the mixer node in the center. The mixer node, in turn, can be thought of as having an input pin connected to the output pin on the KS filter. The graph describes the internal relationship between the filter's pins. An even more complicated device could support several different nodes, which perform different transformations on data flowing through the filter.

KS filters can report internal connections between pins, and internal nodes through the KSPROPSETID_Topology property set.

  • The KSPROPERTY_TOPOLOGY_NODES property provides a sequence of GUIDs that represent the type of the node. Microsoft defines a standard set of node types of the form KSNODETYPE_XXX in the ksmedia.h header. In other requests of the property set, clients refer to a node by its zero-based index in this sequence.
  • The KSPROPERTY_TOPOLOGY_CONNECTIONS property provides a sequence of KSTOPOLOGY_CONNECTION structures that represent the connections between pins and nodes.
  • In the mixer example above, the sequence of KSTOPOLOGY_CONNECTION structures could be as follows:
    //    FromNode,       FromNodePin,     ToNode,        ToNodePin,
{
 {  KSFILTER_NODE,        0,            0,               0     },
 {       0,               1,       KSFILTER_NODE,        1     }
}
  • The KS filter represents internal connections as pins on the internal nodes. Actual pins are represented as connections on the KSFILTER_NODE node.


Reading and Writing on Pins

Clients perform reads and writes on pins by scatter/gather. When a client submits an IOCTL_KS_READ_STREAM or IOCTL_KS_WRITE_STREAM requests, it passes an array of KSSTREAM_HEADER structures that describe the data buffer for the operation.

Each entry in the KSSTREAM_HEADER array describes one entry in the scatter/gather list. The Data member holds the virtual address of the data buffer, while the FrameExtent member specifies the size. Typically, each entry specifies a single frame in a stream of time-dependent data. Drivers can include a current time stamp in the PresentationTime member and a duration in the Duration member.

KS drivers and clients can dynamically negotiate data formats. When the data format of a stream changes, the driver specifies the KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY flag in the OptionsFlag member of a KSSTREAM_HEADER. The driver passes the new data format itself, described in a KSDATAFORMAT structure, in the corresponding data buffer. For more details, see KS Data Format Negotiation.

Drivers or clients can also specify stream state information in the OptionsFlag member of KSSTREAM_HEADER. For example, KSSTREAM_HEADER_OPTIONS_ENDOFSTREAM specifies that the current frame is the last. See KSSTREAM_HEADER for a description of the possible flags.

Drivers may require extended stream header structures to describe each frame. Such a structure must contain KSSTREAM_HEADER as its first member. For example, video streams require the KS_FRAME_INFO structure to describe each frame of streaming video data.


Specifying a KS Data Format or Data Range

To support the many forms of multimedia data, each pin possesses a current data format. Data formats are specified by one, two, or three GUIDs, plus optionally some additional parameters particular to each data format.

Each data format has a major format GUID. Within major formats, the data format can require a subformat GUID and a specifier GUID. A particular data format can also require additional information to completely determine the data format. For example, the major format KSDATAFORMAT_TYPE_VIDEO requires the length and width of the viewing area of the source video stream to be completely specified.

Both clients and drivers use the KSDATAFORMAT structure to describe data formats. The structure specifies the three GUIDs that specify the basic format type, followed in memory by a variable-sized format-specific data block.

Pins frequently support ranges of data formats. For example, a pin can support the KSDATAFORMAT_TYPE_VIDEO major format, but for a restricted range of values for the length and width of the source viewing area. Drivers use the KSDATARANGE structure to specify a range of data formats (drivers can support several different ranges). The format-independent part of KSDATARANGE is a copy of KSDATAFORMAT – the driver can specify a specific GUID for the major format, subformat, or specifier, or the driver can specify a wildcard to match all formats, all subformats, or all specifiers.

The standard members of KSDATARANGE are also followed in memory by a variable-sized format-specific data block. The layout of this block is independent of the format-specific data block used by KSDATAFORMAT, even for the same major format, subformat, and specifier. For example, to specify a range of values for the length and width of a video viewing area requires more information than specifying a single value for the length and width, so the data range structure used by KSDATAFORMAT_TYPE_VIDEO is laid out differently than the data format structure used by the same format type.

Thus, each data format has two data structures associated with it – one to specify the data format, and one to specify a range of the data format. The documentation for each data format includes both the data format structure, and the data range structure.

Note that while KSDATAFORMAT and KSDATARANGE have the same standard headers, the variable-sized data block that follows need not be the same. For example, video capture drivers use the KS_DATAFORMAT_VIDEOINFOHEADER structure to describe video data formats, and the KS_DATARANGE_VIDEO structure to describe ranges of data formats.


KS Data Format Negotiation

Clients and KS filters can negotiate the data format to use for a data stream. Clients can use four different properties to query data format support of pins instantiated by a given pin factory on the filter:

  • KSPROPERTY_PIN_DATARANGES. The KS filter reports all data ranges supported by pins instantiated by the pin factory. This includes every data format the pin can ever support.
  • KSPROPERTY_PIN_CONSTRAINEDDATARANGES. The KS filter reports all data ranges supported by pins instantiated by the pin factory, given the current internal driver state.
  • KSPROPERTY_PIN_PROPOSEDATAFORMAT. Clients can use this property to query if pins instantiated by the pin factory support a specific data format. The KS filter returns STATUS_SUCCESS if the pins supports the data format, or an error code otherwise.
  • KSPROPERTY_PIN_DATAINTERSECTION. Clients can use this property to offer a range of data formats. The KS filter returns a single format in that range that pins instantiated by the pin factory support, if any exist.

Once a pin is instantiated, the client can determine the current data format or request a change of data format through KSPROPSETID_Connection property requests. For example, the client can use the KSPROPERTY_CONNECTION_PROPOSEDATAFORMAT request to determine if a pin supports a given data format. The client can then use the KSPROPERTY_CONNECTION_DATAFORMAT request to actually change the data format.


KS Clocks

KS drivers use clock objects to represent a time-dependent counter. Clock objects can represent actual on-board hardware clocks, or they can represent the current timestamp of a data stream.

Clocks support the KSPROPSETID_Clock property set. A clock provides two, possibly different, timestamps at any given instance. The physical time of a clock is tied to a physical clock — either the system clock, or an on-board hardware clock The physical time of a clock only moves forward. The presentation time of a clock represents the timestamps on a data stream. For example, a clock can represent the current time on an audio stream that supports rewinding. The presentation time may reverse, or be reset to arbitrary values.

Clients can use the KSPROPERTY_CLOCK_PHYSICALTIME property to determine the current physical time on the clock, and KSPROPERTY_CLOCK_TIME to determine the current presentation time. For either request, the driver returns the current time in 100 nanosecond units in a LONGLONG in its data buffer. Clocks are not required to support a 100 nanosecond resolution. Clients can determine the actual clock resolution through the KSPROPERTY_CLOCK_RESOLUTION property.

A client can request to be notified when a clock reaches a certain timestamp, or to receive periodic notification that a fixed amount of time on the clock has elapsed. To do so, clients register the KSEVENT_CLOCK_POSITION_MARK to request notification that a certain timestamp has been reached, and KSEVENT_CLOCK_INTERVAL_MARK to request periodic notification.

A data stream may synchronize input and output to a clock, known as the master clock for the stream. Drivers can synchronize their streams to clocks created by other drivers, and multiple streams can be synchronized to one clock. A client can determine the master clock on a pin through the KSPROPERTY_STREAM_MASTERCLOCK property. Clients can also use this property to set the master clock for the pin.


Master Clocks

A master clock controls the rate of presentation time within a graph, and is used by filters within that graph to synchronize presentation time stamps in streams. It provides a standard mechanism to query the current presentation time, query the physical clock time, compare presentation, physical, and local host times, and to establish event notifications based on position changes in the master clock's presentation time. A client of a master clock may also look at the parent file object of the clock, which is contained in RelatedFileObject member of the FILE_OBJECT structure. This allows a filter to determine if the clock is actually owned by that particular filter, even in the case where the device object supports multiple filters, or different clocks on multiple pins. Master clocks are assigned to pins by the filter graph, and are acquired from filter pin instances that provide clocks.

A master clock's current presentation time is normally derived from the presentation time of a particular stream within a graph, though it could also be derived from some external pulse, such as the local host clock. If it is being derived from a stream, and the stream experiences a famine state, the reference clock will also stall until data flow has resumed, unless the time discontinuity flag is set. When a graph is stopped, the clock presentation time is stopped, thus, a clock is a graph-specific entity, and sharing a clock between graphs would likely be handled by some proxy inbetween, which interprets the changes in the first graph's clock so that the graphs are independent.

In some cases the data stream may have time discontinuities. When these discontinuities are marked in the data stream, the presentation time should continue to progress at the underlying physical clock rate, until the next data frame is sent. At that point, if the presentation time has not reached the timestamp present in the new frame, then rendering of the frame is delayed until that point. If the presentation time has already proceeded past the frame's presentation time, then the physical time is set back to the frame's timestamp, and the frame is rendered. If the frame has no timestamp, it is assumed to be stamped with whatever the current presentation time is, and immediately rendered. If the time discontinuity is not marked, then the presentation clock will stall until the next frame is received. It will then be set to the timestamp on that frame. If the frame has no timestamp, it is assumed to be stamped sequencially with the current time.

This treatment of time discontinuities holds true for both data streams of regular sample frequency, such as video and audio, and those with irregular sample frequency, such as MIDI. In the case of a MIDI data stream, each packet should have a time discontinuity flag set, so that the presentation time, which is based on some underlying physical clock, can continue to progress. When the next packet is received, the presentation time will progress until the new timestamp is reached, and the samples will then be rendered. If the flag is not set, then the presentation time will not progress, and the next packet will determine what the new presentation time will be. If the next packet does not have a timestamp, the presentation time will just progress from the same point, and the packet will be immediately rendered.

The interface to a master clock is a file object and supports methods, properties and events just as filters and pins. All queries against the file object are available only at PASSIVE_LEVEL. However, the clock position query is also supported through a direct function call pointer available at DISPATCH_LEVEL, which is valid as long as the file object is valid. This direct call must be passed the clock's file object as a context parameter. It is assumed that the filter that acquired the clock file handle will ensure that there are no outstanding calls to the clock entry points when the file object is released.

The file handle is acquired through a create request on a filter pin instance, much as the pin creation is done by IRP_MJ_CREATE. The request causes a file handle to be created, just as a file handle to a pin is created, with its own context information. This is then passed back to the caller. This handle can then be used to set the master clock for kernel mode filters. The pin instance that owns the master clock can tell that it indeed owns the master clock when the filter is being assigned the graph's master clock by querying for the parent file object.

Not all filter pins have to support a master clock or synchronize to a master clock, and most likely only rendering and capturing pins need do so.

When a filter is given the file handle to this master clock, it can then be used to query properties and such. From a DirectShow point of view, if a master clock is based on a kernel mode filter, it must support an interface to query the file handle to the kernel mode portion of the master clock. If the interface is not supported, then it is assumed that the clock is user mode-based, and kernel mode filters cannot synchronize to it. The DirectShow proxy filter requesting the master clock handle would then pass it to its underlying kernel mode filter file handle. The kernel mode filter would reference the underlying file object. If the filter already had a master clock, it would dereference the file object and use the new handle, which may be NULL for no master clock, instead. This can only be done when the filter is in a Stop state.

The DirectShow proxy filter is responsible for closing the handle it retrieved from the master clock interface. Also, a kernel mode filter must release its reference on any master clock on being closed in case of abnormal termination. Any DirectShow proxy filter will support a property that indicates that the filter must have a kernel mode-based clock. This will allow any graph building process to build viable graphs more efficiently. Additionally, a kernel mode proxy for a user mode clock exists. This accepts correction times from a client, and interpolates using the PC clock.

Any user mode component, including the user mode proxy of the master clock, becomes just another client of the master clock, except that it cannot acquire the direct function call pointer used at DISPATCH_LEVEL by kernel mode filters. So the DirectShow proxy filters could retain the handle acquired from the master clock for direct access to the kernel mode clock, or duplicate the handle for cross-process access. However, the same interfaces should be available on the proxy clock itself.

The clock presentation time is used by other filters or applications to synchronize actions or stream presentation times to. There is no method to set the presentation time on a master clock directly. One would indirectly affect clock presentation time by pausing, flushing, and seeking a graph to some presentation time. This will cause new data to be retrieved with a new presentation time. Normally source filters would pay attention to a seek presentation time request, and produce data with the new presentation time. The first timestamp on the stream underlying the master clock would set the new clock time.

If a filter is composing a stream from multiple sources, each of which is composed of data within different parts of a file, the composing filter must obviously be communicating with an interface that specifies byte positions, and translate presentation timestamps to use in the streams. Such filters feeding the composition filter would be passed modified presentation time positions in seek requests, or they may ignore the seek position if the composition filter interface request specific data. In other words, either a filter is receptive to seek requests, and may additionally use the master clock to synchronize its pins presentation times with clock presentation time, or it receives specific requests from a connection.

A graph does not necessarily have a master clock. Data could be presented a nominal rates based on individual physical clocks with no specific relationship to each other. For instance, an audio stream mixer with independent pins that are merely mixed, but not necessarily with any specific relationship to each other, would not need a clock.

The physical time on the master clock object is one that is normally hardware-based, and although related to the clock presentation time by virtue of being presented by the same filter pin, is independent of it. It would normally be connected to the rate at which data is actually being presented, but may not be running when the graph is in a Pause state. That is, if some pre-roll is done when in a Pause state, it may not affect the physical clock. If a filter that presents the master clock has no physical clock at all, and merely presents data as it is received, then presumably the "physical clock" would actually just progress on a basis of the data presented, and probably stop progressing when data is not being presented, as when the device is in a famine state.

The physical time behind the master clock may be remote, in which case it is the responsibility of the local proxy to provide accurate readings. For instance, compensating for the delay across a 1394 connection, or averaging the delay across a network. Additionally, if some other kernel filter is just a proxy for a second device on the same 1394 bus, the two devices may negotiate a private method of interfacing with the master clock. They would have to use private interfaces to determine the type of clock in order to verify compatibility.


Default Clock

A default implementation of a clock source is supported, which may be used by filters that would normally use the system clock to regulate their data flow. This clock supports the normal KSPROPSETID_Clock interface, and may be accessed just as any other clock presented by a filter pin. The underlying data structure however is created by the filter pin, and shared among that pin, and any instances of the clock that are created. The clock relies on the pin to update the current state and other elements in the shared structure. The default clock handles notification requests and clock queries. The property set and functions used to create and support default clocks are described in later sections.

When a pin on the filter that provides this clock is assigned a master clock, it should treat this clock just as if the pin owned the clock (which in fact it does). The pin should reference the clock file object, just as if it was assigned some other clock implementation. The default clock does not reference the pin's file object when an instance is created, so there is no circular reference counting problems. Instead, it keeps an internal reference count based on the initial allocation of the common clock structure, and on each file object opened on the clock. Even if the clock's owner frees the clock structure, it will remain in place until all file objects are closed. The pin may of course directly access the default clock object, rather than go through the standard clock interface.


Rate Matching

Rate matching involves compensating for actual frequency variations in physical clocks. Two crystals will never resonate at the exact same frequency, and thus two time sources based on those crystals will never run at the exact same frequency. So a mechanism is needed to allow one clock to compensate for the relative drift against another clock, and thus modify the contents of the stream produced is a means of rate matching.

For example, consider a hardware-based audio source set to produce samples at a frequency of 44.1 kHz, and a separate hardware based audio sink also set to consume samples at a frequency of 44.1 kHz. The physical clocks on which the production or consumption of samples is actually based are separate, and cannot be guaranteed to be exactly the same relative to each other. The source may actually be running at 44.100005 kHz relative to the sink, which would mean that more samples are being produced than consumed, and over time, drift would occur between the two, causing eventual flood. Likewise, not enough samples may be produced, which would generate a famine condition for the consumer.

The master clock allows any filter to query an accurate representation of "wall clock" time, which is an ever-progressing 100-nanosecond resolution counter. If the audio consumer owns the master clock, presumably the physical hardware that is rendering the audio would be used to present the physical time on the master clock. The audio producer would be able to query this physical time at intervals to determine relative drift. The producer would then compensate the number of samples to match the frequency difference. In the case of audio, this rate matching is a built in function that can be used by a filter to modify the samples in a stream buffer.

In some cases the physical time may be based on the same hardware. The producer in that case would not need to compare for drift, but that is based on the type of clock, which is a stream property for which the producer can query the master clock owner. For example, if the producer and consumer are both on the same full duplex audio card, then producer and consumer could use the same hardware timing. In this instance if the producer queried the stream property for the type of master clock, it would find that the clock was based on the very same hardware instance used by the producer. It would not need to perform any rate matching in this case.

Any of these clocks are just approximations of "wall clock" time, and the same presentation rendered on a different machine will play for a slightly different amount of time. But in most cases, the important factor is the relative drift between physical clocks, rather than the drift against some perfect "wall clock" time.

Using the physical clock for rate matching allows instantaneous feedback of rate differences, rather than using something like the clock presentation time, which stalls based on data famine, and therefore only allows an infinitely long sequence of approximations to match the rate. For example, if too much data is produced, then correct feedback is given to slow the rate (except if famine occurs at any point), although a data flood would not automatically be relieved. However, if not enough data was produced, or the stream was live, so data was delayed, the rate of flow would always approach its nominal rate, and would force the production rate up (how fast would depend on how often the rate was checked, versus how many buffers produced), but would take an infinite amount of time to reach the correct rate. Using the physical clock would produce the same result with a data flood, which would have to be corrected by Quality Management complaints, but the data famine would be self-correcting. That is, the reference clock would stall while data was being produced, and thus close the gap, and adjust for the frequency discrepancy at the same time.


KS Allocators

An allocator is a KS object that handles allocating data buffers for I/O requests. A KS driver can provide an allocator for a pin optimized for I/O throughput.

Drivers can in principle support allocators for multiple buffer types, for example on-board RAM in a video card. However, most drivers use the default allocator. The default allocator allocates system memory. Drivers can specify frame size, maximum number of frames, and alignment requirements. The default allocator takes care of meeting the requirements, and can optimize by reusing discarded frames.

Drivers that support an allocator respond to the KSPROPERTY_CONNECTION_ALLOCATORFRAMING property. The data buffer for this property is a KSALLOCATOR_FRAMING structure. Drivers use this structure to specify the requirements they impose on their data buffers. Such restrictions can include: fixed frame size, a strict upper bound on allowable outstanding frames, alignment, or pool type. Drivers that support the default allocator set the KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY flag of the RequirementsFlag member.

Minidrivers running under AVStream should use the KSALLOCATOR_FRAMING_EX structure to specify allocator requirements. Please see additional information in the documentation for this structure.


Frame Allocators

Minidrivers running under AVStream may include pins that implement their own allocators. Do this by setting the KSALLOCATOR_DISPATCH member of the KSPIN_DISPATCH structure. Specify NULL for this member if you do not want to specify an allocator for this pin.

Simple Allocator Configuration

This diagram represents the configuration of a simple allocator where a single allocator is assigned for use by three filters. No allocation is required in the transform or sink filters because the system has not assigned an allocator handle to these filters.

The source filter allocates a frame, fills it with data and submits it to the next filter. The transform filter performs an in-place data transformation and submits the frame to the next filter. When the sink filter completes the I/O operation, the source filter either frees or reuses the frame. Flow control is maintained in this filter graph by the number of total outstanding frames that can be allocated from the sink allocator and by the rate of completion of the I/O operation.

Allocator Configuration with Multiple Sinks

This diagram represents an allocator configuration where a source frame is routed to multiple destination sinks. For instance, the file writer could represent wave out to a file, and the device a sound card to which audio is being sent.

This filter graph contains two allocators: the transform's allocator and the device's allocator. The source filter allocates a frame from the transform allocator, fills it with data and submits it to the transform filter and then to the file writer. On receipt of a frame, the transform filter allocates a frame from the device allocator, performs a transformation of the data into the new frame and submits this frame to the device.

Flow control is maintained in this filter graph by the number of total outstanding frames that can be allocated from the allocators and by the rate of completion of the I/O operations. Note that there must be a separate allocator for each separate list of source/sink segments created through connecting pins. If separate allocators are not present, a given segment may consume all frames available, leaving none for the next segment, which may require one or more frames to process the data created by the previous segment.


Allocator Negotiation

When an DirectShow client connects a filter graph and initiates negotiation of the IMemInputPin interface, that client, through a proxy, negotiates the respective properties of the kernel-mode allocators by querying each kernel-mode filter at the data output handle of each filter connection for its requirements using the KSPROPERTY_CONNECTION_ALLOCATORFRAMING property. This property can only be set when the pin state is KSSTATE_STOP.

When the filter graph requirements have been determined and if there are any requirements for kernel-mode allocators, the client creates the allocators using the associated pin handles of the filter connections and sets the allocator property for each source handle of each filter connection using KSPROPERTY_STREAM_ALLOCATOR. The receiving pin references a non-NULL handle to the allocator using ObRefrenceObjectByHandle. For optimization, setting a NULL handle to signify that no allocator is required is an optional operation for a client and therefore all filters must default to a NULL allocator. If no allocator is specified by the client, the filter can assume that the stream segments submitted via stream I/O controls meet the filter's requirements and it may freely modify the data in-place if necessary.


Default Allocator

The default allocator provides a system memory allocator for device drivers that are able to transfer data from system memory but requiring specific memory allocation properties. The default allocator simplifies a filter by only requiring a filter to handle the allocator requirements request.

To interface to the default allocator, the filter responds to the KSPROPERTY_CONTROL_ALLOCATORFRAMING property and returns the requirements including the KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY flag for the filter. When an IRP_MJ_CREATE is submitted and the create type is KSCREATE_REQUEST_ALLOCATOR, the filter forwards the IRP to the default allocator handler by calling the KsCreateDefaultAllocator function. All remaining processing is handled by the default allocator.


Filter Specific Allocator

Filters requiring allocators for on-board memory or other device dependent storage methods can provide an specific allocator by supporting the allocator properties and methods.

An allocator is represented by a file object of the device. A create request of the KSCREATE_REQUEST_ALLOCATOR type is submitted to the filter specifying the framing options for the allocator. The allocator creation function validates the create request using the KsValidateAllocatorCreateRequest function that returns a pointer to the KSALLOCATOR_FRAMING structure and a pointer to the parent file object.

If the allocator can not satisfy the framing requirements, it returns immediately with a failure code. Otherwise the filter attaches a pointer to a structure to the FsContext member of the file object and services the resulting allocator requests. Note that the allocator does not call ObReferenceObjectByPointer for the related (or parent) file object as such a reference would cause a circular reference and would not allow the parent pin object to be closed.

The allocator must support the standard stream allocator properties and methods detailed in the property set and method set references in later sections.

There are two interfaces available to the allocator. All allocators must provide the IRP-based KSMETHODSET_Stream_Allocator interface. Optionally, if the allocation pool type can be serviced at DISPATCH_LEVEL, a function table interface may be supported.

Allocators control the flow of data by maintaining a maximum number of allocated frames.

The IRP-based interface operates as follows:

When an allocate request is submitted to the allocator, the allocator completes the request with a pointer to a frame or if all frames have been allocated, the allocator marks the IRP pending, adds the IRP to the allocator's queue and returns STATUS_PENDING.

When a free request is submitted to the allocator, the allocator attempts to complete the first request in the queue for the IRP based interface, if any, otherwise the frame is returned to the free list. If the DISPATCH_LEVEL interface is also supported, the allocator signals the stream allocator "free frame" event. Note that it is possible for both the DISPATCH_LEVEL interface and the IRP-based interface to contend for the free frames. Synchronization to the queue is maintained by the cancel spinlock.

The DISPATCH_LEVEL interface operates as follows:

When an allocate request is submitted to the allocator, the allocator returns a pointer to a frame is one is available or it returns NULL immediately.

When a free request is submitted to the allocator, the allocator signals the stream allocator "free frame" event notifying the client that a free frame is available. Additionally, if there are allocation request IRPs waiting to be completed, the allocator must schedule a worker item (if the current IRQL is not PASSIVE_LEVEL) and complete the request with the free frame.


KS Mediums and Interfaces

A medium defines a way of communication, such as the bus over which the communication occurs. The IRP-based medium is what would typically be used, but this can be something different for a filter whose functional piece resides on a DSP and whose communication path could be contained on that DSP. Each filter and each pin on a filter must designate what mediums it supports. For example, a filter could specify that it communicates through IRPs.

An interface defines what can actually be communicated. The interface is the group of methods and properties to use, implemented on the specified medium. Each interface has a medium-specific implementation, but the same interface can be implemented over several mediums.

The IOCTLs described in this documentation refer to the standard IRP-based KSMEDIUMSETID_Standard medium set, and interfaces implemented in that medium. This standard IRP-based medium is also the medium used to communicate with the filters themselves in order to establish connections or query general filter properties. Even if the filter is a local proxy for a remote filter on another machine, it would use the same medium for filter communication. However, the pins on the filters may expose, for example, a socket-based medium, or may hide that from the connecting filter and do the processing itself.

A medium can also represent communication over some external bus, such as between components on a DSP. The GUID for the medium set would be the unique identifier for this bus, and the ID within that medium set would represent the unique instance of that type of bus. This unique instance corresponds to the PnP bus identifier that can be queried by a device from the bus that enumerated the device. (Refer to the PnP documentation for retrieving a bus identifier.) The standard medium set then just represents the system bus, though each ID within that set is used to represent a form of communication. Thus, it is slightly different than the use for other buses.

Medium Sets

The KSPIN_MEDIUM structure identifies a medium with a unique medium set and the elements of that set.

typedef    KSIDENTIFIER    KSPIN_MEDIUM, *PKSPIN_MEDIUM;

A pin can support multiple mediums, as well as interfaces on those mediums. The way in which a pin is described indicates that the list of interfaces is supported on all mediums enumerated for a pin. So, if there is a case in which this is not true, another pin can be used to describe each subset of interfaces for the specific mediums. More details can be found in KSPROPSETID_Pin and KSPropertyHandler.

Interface Sets

Interfaces also are described as a set and as an element of that set. The KSINTERFACESETID_Standard contains the set of standard interfaces supported by various types of pins.

Interface sets use the following structures:

KSPIN_INTERFACE

KSPIN_CONNECT

KSPIN_DESCRIPTOR


Interface Sets

Interfaces also are described as a set, and an element of that set. The KSINTERFACESETID_Standard contains the set of standard interfaces supported by various types of pins.

The KSPIN_INTERFACE structure identifies an interface, with a unique interface set, and element of that set.

typedef KSIDENTIFIER KSPIN_INTERFACE;
typedef enum {
  KSINTERFACE_STANDARD_STREAMING,
  KSINTERFACE_STANDARD_LOOPED_STREAMING,
  KSINTERFACE_STANDARD_CONTROL
} KSINTERFACE_STANDARD;
Standard Interfaces | Description
KSINTERFACE_STANDARD_STREAMING | Basic streaming interface.
KSINTERFACE_STANDARD_LOOPED_STREAMING | Basic streaming interface that also enables looping on buffers.
KSINTERFACE_STANDARD_CONTROL | Non-streaming control interface.

The interfaces within the standard set cover the base set of pin classes that have been implemented. Note that for MDL-based streaming, the originator of the request must create a stream header for each MDL in the list, and assign a completion routine if the MDL list must not be freed on completion of the IRP.


KS Supplemental Documentation

Built on Wednesday, July 11, 2001


Quality Management

Quality Management (QM) notifications are one method of fine-tuning flow control based on resource constraints, and of determining degradation needs in a filter graph. The other flow control being buffer allocation interfaces, which block on allocation requests, limiting the number of outstanding buffers in order to constrain data flow. QM notifications are sent to a Quality Manager, should one exist, through a kernel mode proxy. If one does not exist, QM notifications are not supported. The Quality Manager is acquired much the same way as the file handle to a master clock.

When a Quality Manager is assigned to a graph, each pin instance in the graph is notified. The Quality Manager can be changed at any point. Old QM information may be discarded on assignment of a new Quality Manager.

When a connection is established in an DirectShow proxy of a kernel mode filter, the connection may query the user mode Quality Manager for an interface to use in retrieving a handle to the kernel mode Quality Manager proxy. The DirectShow filter then passes that handle, along with an DirectShow-specific context parameter, to the pin instance via a stream property. The kernel filter's pin instance references the underlying file object, and can use that to send QM problem notifications to the kernel mode Quality Manager proxy. The DirectShow filter is responsible for closing the handle that it retrieved, but it may also be used for direct access to the kernel mode Quality Manager, should that be needed.

The kernel mode filter pin now has a file object and context parameter for the Quality Manager proxy that can be notified via the normal method and property calls. If a new Quality Manager is specified for the connection, or a NULL Quality Manager is specified, any previous Quality Manager reference should be dereferenced. If the connection is closed, then any outstanding Quality Manager file object should be dereferenced.

This Quality Manager is specific to the connection, and any QM problems reported to the manager include the context parameter specified in the original property call, which is then presumably passed to the user mode Quality Manager. In the case of DirectShow being the connection client, this context parameter may be a pointer to the DirectShow proxy filter pin interface, which it could use to determine topology.

This allows a DirectShow proxy to have both kernel mode connections and user mode connections, and allows kernel mode filters to be contained in multiple graphs. The former is of immediate use, but the later will not be of use until future versions. This also implies that the kernel mode portion is currently just a funnel for QM problems reported by kernel mode connections. In the DirectShow scenario these problems are then routed to the user mode Quality Manager, which determines what to do based on the strategy and QM information previously queried from the pins.

To do this the user mode portion of the Quality Manager keeps multiple asynchronous IRP's outstanding on the kernel mode proxy in order to receive the QM problems. The context parameters returned could be translated into DirectShow pin interfaces so that all QM problems can be treated equally within the graph. In the case of user mode QM problems, the interface to the Quality Manager could been used directly. The Quality Manager then makes calls to various pin interfaces within the graph in an attempt to solve the QM problem. For proxy DirectShow pin connections, the kernel mode connection sends the QM problem to the kernel mode QM manager with the context parameter, which the kernel mode Quality Manager forwards to the user mode Quality Manager via the pending I/O previously mentioned. Please see related documentation on the KSQUALITY structure in Kernel Streaming reference material.

QM problem complaints are generated by filter pin instances when data is not being received fast enough, or too much data is being received, or not enough resources are available to deal with the data stream (which in some cases may look exactly like data is not being received fast enough). These conditions are determined from the KSQUALITY.DeltaTime and KSQUALITY.Proportion elements in the QM complaint. For instance, a delta time of zero, but a proportion of 500 would indicate that only 50% of the frames being sent to a filter pin instance are actually being used. This would indicate that the filter does processing of frames asynchronously to when they are sent, and does not have enough resources to process those frames.

Alternatively a negative delta with a 100% proportion would indicate a flood of data, and a famine would be specified by positive delta (frames are being delivered past the time at which they could be used). An ill-formed filter that performs too much processing of the data as it is sent, rather than queuing the frames, may complain that data is being sent too late if it does not have sufficient resources to process the frames fast enough. That is, by the time it is finished with one frame, and accepts the next frame, the optimal time may have passed to use that frame. Since the filter is constructed in this manner, it really is a resource complaint.

A resource complaint on one filter pin may be followed shortly by a famine complaint on some pin down the data stream. So the Quality Manager must act on complaints serially to determine if it has solved the problem. There is also the special condition of time discontinuity. No QM complaints related to data famine should be generated after a time discontinuity has been received (which indicates the end of a stream segment).

Note that the delta is specified in native units, which are determined by the Interface used by the connection. A Quality Manager may not understand the specific units, but it can still use the information to determine if frames are being delivered too late or too early. If any connection in the stream supports Rate Capability queries, and has a Topologically related connection of the correct Interface, then the Quality Manager would be able to translate between unknown time stamp formats.

A QM complaint is considered to be outstanding until told otherwise, although complaints of the same type may be generated by the same pin instance, and override previous complaints. Also, if the QM returns to a tolerable rate, the pin may generate a QM that indicates that the problem has been solved (Proportion = 1000, DeltaTime = 0). Even when the graph is in a Stop state, QM notifications may be sent, as in the case of pre-configuring the QM of a graph on a low-end machine.

The type of items that can be degraded are represented by KSDEGRADE structures. Also see the enumeration KSDEGRADE_STANDARD.

There is a standard set of identifiers KSDEGRADESETID_Standard, which contains the very basic broad categories of items that can be degraded.

The sample degradation implies manipulation of the frequency of samples in a stream processed by a pin. For example, by producing less samples less time may be spent processing samples that may not be used. Specific data formats may imply which samples are to be removed first. In loose terms, this sets the number of "frames" that are produced by the filter or filter pin compared to the number received.

The quality degradation implies manipulation of the quality of data samples in a stream processed by a pin. For example, by reducing the size of samples less work may be done in processing them, as in the case of a Px64 algorithm, or reducing from 16-bit to 8-bit PCM wave samples; as long as the destination filter can interpret the changed data format. In loose terms, this sets the quality of "data frames" that are produced by the filter or filter pin.

The computational degradation implies manipulation of the general computational effort expended on a stream processed by a pin. For example, a 100th order algorithm could be reduced to a 50th order algorithm. In loose terms, this sets the amount of effort expended by a filter or filter pin in processing a stream.

For the first three strategies, the Flags member of the KSDEGRADE structure contains the current percentage in one-tenth percentage points of degradation in this category, where 1000 is no degradation. For the last strategy, Flags contains the amount of time in native units as specified by the Interface. Since this is a ULONG value, multiple Skip requests may be needed to remedy the QM complaint.


Object State

Resetting state essentially returns the object (e.g., a pin) to the state it was in upon being set to an Acquire state. That is, state information based on stream contents is discarded (for example RLE information). Any reset must be propagated through a data stream from pin connection to pin connection by the proxy. Any reset request received on any pin while resetting is ignored, and a reset on any pin may affect the filter as a whole, as it propagates the request through the effected pins in relation to what the filter routing for that pin instance is.

A reset is initiated on a pin by sending an IOCTL_KS_RESET_STATE IOCTL with a value of KSRESET_BEGIN contained in the input buffer. This begins the reset state, and indicates to a pin that any pending or new data received while in a reset state should be rejected withSTATUS_DEVICE_NOT_READY. The reset state is ended by either a disconnection, or by receiving an IOCTL_KS_RESET_STATE with a value of KSRESET_END contained in the input buffer (It is not canceled by changing pin state). This indicates to a pin that new data can be accepted. It also indicates that it can once again pass data to it connection, even if previously data had been rejected. Normally rejecting data indicates to a pin that it should halt sending more data.

An object's state may be flushed using IRP_MJ_FLUSH. This is used to ensure the object state and stream data has been flushed to permanent storage, or otherwise completely processed by the underlying hardware. Any object may support this through a KSDISPATCH_TABLE entry.


Recalculating Stack Depth

When the state of a pin transitions from KSSTATE_STOP, each connection that forwards IRPs must recalculate stack depth. In kernel-mode drivers this allows connections to be made and remade in any order.

What this implies is that although connections can be established in any order, changing state from Stop to any other state must be performed from bottom of stack up. Each request causes the pin to recalculate its stack requirements (StackSize member of the DEVICE_OBJECT structure) based on the lower pin in the stack (if it forwards IRPs and therefore relies on the lower stack depth). A filter that forwards IRPs must keep a list of all pin instance file objects associated with this device object so that the StackSize in the device object can be recalculated correctly. Any request out of order can be rejected because lower stack depth may not have been recalculated, however KsForwardIrp validates that there is remaining stack, and returns STATUS_INVALID_DEVICE_REQUEST otherwise. So this recalculation is only needed if IRPs are passed on through connections, rather than associated IRPs being created.

The second implication is that no IRP can be passed down a connection until an Acquire state has been reached, since the stack depth is not yet known.

If a driver attaches itself to a filter using IoAttachDevice, it must recalculate stack depth also, adding an additional stack location for itself.


Canceling I/O

Canceling outstanding I/O for a thread must be performed through NtCancelIoFile. Closing an object or setting a streaming object to a Stop state also cancels outstanding I/O. This would possibly be done when responding to real-time input that directs a different path to be taken.


Asynchronous Assumptions

All file object are opened assuming asynchronous access. That is, each filter must perform its own serialization. Any synchronous access must be emulated by waiting on the request to complete, as KsSynchronousDeviceIoControl does. There is no extra overhead in doing this, as the file system would internally wait for the file object to be signaled in any case. However it does mean that the filter itself can control how much serialization is needed for the various types of requests, in that property queries should not need to overly inhibit streaming of data, etc.

.


AVStream Overview

AVStream is Microsoft's next generation multimedia class driver. This is the only multimedia class driver that Microsoft will evolve.

Existing minidrivers under stream class and port class continue to work in Microsoft® Windows® XP. However, Microsoft now supports the older stream class driver only on an as-is basis. Vendors may still write audio drivers using port class.

Vendors developing new drivers that would have run under stream class may wish to consider instead writing to AVStream. AVStream is especially recommended for vendors who are writing software filters or drivers for new technology areas or new device types.

AVStream offers significant advantages to the vendor by:

  • Requiring less code on the part of the minidriver writer.
  • Providing a unified kernel streaming class model for both audio and video minidrivers.
  • Providing support for vendors to use COM objects to plug in new interfaces without altering existing minidriver binaries.

Under AVStream, vendors still provide a minidriver that interacts with a Microsoft-provided class driver. However, there are important differences at the API level that are covered in the AVStream reference sections.

This section contains the following topics:

AVStream Object Hierarchy

Sample AVStream Minidrivers

AVStream Headers

Initializing an AVStream Minidriver

AVStream Descriptors

AVStream Dispatch Tables

Event Handling in AVStream

Pin-Centric Processing

Filter-Centric Processing

Processing Commonality

Common AVStream Services

Special Concerns of Hardware Drivers

AVStream DMA Services

AVStream Queues

Stream Pointers

This material is relevant only to the Windows XP and Microsoft® DirectX® 8.0 releases and later.


AVStream Object Hierarchy

An AVStream minidriver can expose many different types of filters through a hierarchy that is illustrated in the following diagram:

AVStream Object Hierarchy

Built on Wednesday, July 11, 2001


Sample AVStream Minidrivers

The DDK includes two sample AVStream minidrivers: Avshws and Avssamp. Avshws is a pin-centric capture driver for a simulated piece of hardware. Avshws also shows how to implement DMA through AVStream. Avssamp is a filter-centric capture driver that does not perform DMA.

These samples demonstrate many of the concepts that are described in this documentation. These sample drivers can be tailored to a driver developer's needs. Readmes corresponding to these samples can be found in the DDK, located in the same directories as the samples. These readmes are not included in the DDK documentation.


AVStream Headers

All Kernel Streaming and AVStream reference material covers structures and functions that are declared in ks.h. This is the header that the minidriver needs to include in order to access the Microsoft-supplied KS and AVStream class driver support.


Initializing an AVStream Minidriver

This section describes the steps required to initialize an AVStream minidriver.

An AVStream minidriver that does not handle device initialization on its own calls KsInitializeDriver from the minidriver's DriverEntry routine. A driver that handles device initialization on its own will not call this function. KsInitializeDriver initializes the driver object of an AVStream driver. This function also initializes IRP dispatching, PNP add device messages, and unloading.

In calling KsInitializeDriver, the minidriver passes a pointer to the driver object to initialize a pointer to the registry path, and, optionally, a device descriptor. Note that passing the KSDEVICE_DESCRIPTOR object is not required. If the minidriver does pass a device descriptor, AVStream creates a device with the specified characteristics at AddDevice time.

The device descriptor object contains a pointer to a KSDEVICE_DISPATCH structure. The device descriptor object contains a pointer to an array of filter descriptors. Provide a KSFILTER_DESCRIPTOR for each filter type that your minidriver supports. When the minidriver calls KsInitializeDriver, AVStream creates a filter factory object for each type of filter exposed by the minidriver. Individual filters are then instantiated by the filter factory upon receipt of a create IRP for the associated create item. Each filter descriptor contains a pointer to an array of KSPIN_DESCRIPTOR_EX objects. AVStream creates a pin factory on the relevant filter for each type of pin the minidriver exposes through that filter.

When a connection is made to a given pin type on a filter, it is the AVStream pin factory that instantiates a pin object. Note that each filter must expose at least one pin. The minidriver uses the InstancesNecessary member of KSPIN_DESCRIPTOR_EX to specify a count of the number of instances of this pin type that are necessary for proper functioning of the filter. Similarly, the minidriver can impose a maximum on the number of pins that the pin factory can instantiate by using the InstancesPossible member of this structure.

When laying out the descriptors, a minidriver writer must decide what type of processing each filter type will perform. AVStream provides two distinct types of processing: Filter-Centric Processing, and Pin-Centric Processing.

Also see AVStream Queues and Stream Pointers.

To install an AVStream minidriver, follow the guidelines in Creating an INF File. Also see the INF files corresponding to AVStream sample drivers in the DDK.


AVStream Descriptors

An AVStream minidriver describes itself and the filter types it supports through the use of descriptor structures. The descriptor contains the basic characteristics of the object it describes. This allows AVStream to provide default behavior on the part of the minidriver, eliminating the need for the driver writer to provide extra code for common behavior. Each key component — the device, the filter factory, and the pin factory — has an associated descriptor.

The main descriptor for an AVStream minidriver is the device descriptor, KSDEVICE_DESCRIPTOR. This structure tells AVStream how many filter types the minidriver exposes, where to find descriptors for each of these filter types, and where to find the relevant device dispatch table. The FilterDescriptors entry in the device descriptor points to a table of pointers to filter descriptors, one for each filter type the minidriver exposes.

A KSFILTER_DESCRIPTOR tells AVStream how many pins types the filter supports, where to find descriptors for them, the KS categories the filter is to be registered under, and the topology of the filter. Inside each filter descriptor, the minidriver must provide a table of pin descriptors that describe each pin type present on the filter.

A KSPIN_DESCRIPTOR_EX tells AVStream what interfaces, mediums, and data formats a specific pin supports.

Typically, AVStream minidrivers lay out static descriptor tables in their source and call KsInitializeDriver to perform the setup work.

There are other types of descriptors as well, such as the node descriptor KSNODE_DESCRIPTOR that describes a given topology node.

The dispatch table is common to each of the three main descriptor types. See AVStream Dispatch Tables.


AVStream Dispatch Tables

The AVStream dispatch table, KSDEVICE_DISPATCH, is a set of function pointers to dispatch functions. This structure allows the minidriver to extend the behavior provided by AVStream by specifying the dispatch messages it would like to receive.

These functions receive notifications of certain events and may extend or modify the default event handling provided by AVStream. For example, a device can provide dispatch functions to get Plug and Play (PnP)-related information, such as add device, start device, poststart, query stop, cancel stop, stop, query remove, cancel remove, remove, query capabilities, surprise removal, query power, and set power. In this way, a hardware driver can determine the resources that PnP has assigned to a given device.

Both KSFILTER_DISPATCH and KSPIN_DISPATCH structures provide a dispatch called Process. Use this dispatch to differentiate a filter-centric filter from a pin-centric one. A filter that provides a process dispatch function in the filter dispatch table is filter-centric. On the other hand, a filter that provides a process dispatch in each of the pin descriptor tables is pin-centric. See Filter-Centric Processing and Pin-Centric Processing.

Filters can register to be notified about creations, deletions, the need to process data, and resets. Pins can register to be notified of events such as creation, closure, the need to process data, resets, setting of data formats, and state changes. Minidrivers register dispatch functions only for the notifications they would like to receive.

For more information about dispatch functions, see KSFILTER_DISPATCH, KSPIN_DISPATCH, and KSALLOCATOR_DISPATCH.


Event Handling in AVStream

In order to support events, an AVStream minidriver places a series of KSEVENT_ITEM structures in the automation table (see KSAUTOMATION_TABLE). When some other component wishes to be notified of that event, it sends an IOCTL_KS_ENABLE_EVENT down to the device. In the event item, the AddHandler and RemoveHandler pointers may be NULL or non-NULL. To decide which is better for your driver, please consult the comments section in KSEVENT_ITEM.


Pin-Centric Processing

Pin-centric processing means that AVStream attempts processing when new data (or a new buffer) arrives into a previously empty queue. The minidriver can change this default behavior by specifying the KSPIN_FLAG_INITIATE_PROCESSING_ON_EVERY_ARRIVAL flag in KSPIN_DESCRIPTOR_EX. If this flag is set, AVStream attempts processing every time a data frame or buffer arrives into the queue. Similarly, If the pin specifies KSPIN_FLAG_DO_NOT_INITIATE_PROCESSING, AVStream never directly calls upon the pin to process. In this case, the minidriver is responsible for calling KsPinAttemptProcessing to initiate a pin process dispatch.

A filter that uses pin-centric processing must provide a processing dispatch in each KSPIN_DISPATCH table and omit the processing dispatch in the KSFILTER_DISPATCH table. Once you have supplied the descriptor structures and registered them with AVStream by using KsInitializeDriver, your filter can be instantiated and used. As stated earlier, AVStream provides much of the default behavior necessary to make your filter work as a WDM-CSA (kernel streaming) compliant filter.

In the pin-centric dispatch, AVStream provides a pointer to the pin object that has available data. The minidriver's processing dispatch can then acquire a pointer into the data stream with KsPinGetLeadingEdgeStreamPointer. This acquires the leading edge stream pointer into the queue. All data manipulation takes place through the stream pointer and stream pointer API.

Processing attempts can fail for a variety of reasons. For instance, processing cannot occur if the minidriver is holding the processing mutex through KsPinAcquireProcessingMutex. Problems may also arise if the minidriver directly manipulates a gate by using the KsGate* calls.

In general, software filters use filter-centric processing and hardware filters use pin-centric processing. However, there are rare cases in which a hardware filter may be filter-centric and a software filter may be pin-centric.

Pin-centric filters typically perform data routing, in particular data routing to and from hardware that performs a transform or renders data.

See the Avshws sample in the DDK. This is a pin-centric capture driver for a simulated piece of hardware. Avshws also shows how to implement DMA through AVStream.


Filter-Centric Processing

A filter that implements filter-centric processing should provide a processing dispatch in the KSFILTER_DISPATCH table and leave off processing dispatches in each of the KSPIN_DISPATCH tables. Once you have supplied all of the descriptor structures and registered them with AVStream by using KsInitializeDriver, your filter can be instantiated and used. Again, AVStream provides much of the default behavior necessary to make your filter work as a WDM-CSA (kernel streaming) compliant filter.

If you choose filter-centric processing, the processing dispatch is called when there are data frames available on each instantiated pin. The rules applied to pin-centric processing still apply here, but the overall result is more complex.

The events described in pin-centric processing as triggering a processing attempt still apply to filter-centric processing. Pins will still trigger processing attempts as described in pin-centric processing; however, the processing attempts are on the filter and the following new rules apply:

  • A processing attempt will not succeed unless frames are available on every pin that does not specify KSPIN_FLAG_FRAMES_NOT_REQUIRED_FOR_PROCESSING.
  • A processing attempt will not succeed if a pin on the filter is in a state below the minimum processing level (normally this is KSSTATE_PAUSE, although it can be set to KSSTATE_RUN by specifying KSPIN_FLAG_PROCESS_IN_RUN_STATE_ONLY).
  • A processing attempt will not succeed if the required number of pins as specified by InstancesNecessary (a member of KSPIN_DESCRIPTOR_EX) is not met.
  • A processing attempt will not succeed if the minidriver has previously closed the filter's process control gate using the KsGate* functions.

In general, software filters use filter-centric processing and hardware filters use pin-centric processing. However, there are rare cases in which a hardware filter may be filter-centric and a software filter may be pin-centric.

Filter-centric filters typically operate at the software level. For instance, filter-centric processing could be used for a software transform, or data flow routing at the software level.

The DDK includes two sample AVStream minidrivers: Avshws and Avssamp. Avshws is a pin-centric capture driver for a simulated piece of hardware. Avshws also shows how to implement DMA through AVStream. Avssamp is a filter-centric capture driver that does not perform DMA.

See the Avssamp sample in the DDK. This sample illustrates how to write a filter-centric AVStream capture driver.


Processing Commonality

Both pin-centric and filter-centric processing attempts cause processing to continue until one of the specified events occurs:

  • No data is currently available on the pin (pin-centric) or on a pin that does not specify KSPIN_FLAG_FRAMES_NOT_REQUIRED_FOR_PROCESSING (filter-centric).
  • The processing routine returns STATUS_PENDING.

See the flags related to processing in KSPIN_DESCRIPTOR_EX. Once processing has stopped, the minidriver may restart by calling KsPinAttemptProcessing or KsFilterAttemptProcessing. This is necessary if the defaults are used, meaning pin flags are not set.

This situation is encountered when the processing dispatch is called with frames available on the pin (or on every pin that requires frames in the filter-centric case), and the minidriver chooses not to process by returning STATUS_PENDING. Since by default, processing is only attempted when new data arrives into a previously empty queue and none of the associated queues are empty, the minidriver will never be called on to process. Thus, if the minidriver sets STATUS_PENDING in this circumstance, it must then inform AVStream when ready to resume processing. Do this by calling KsPinAttemptProcessing or KsFilterAttemptProcessing.

A minidriver must NOT return STATUS_SUCCESS from the processing dispatch if the minidriver does not actually process data. This causes AVStream to immediately recall the minidriver, resulting in an infinite loop between AVStream and the processing dispatch.


Common AVStream Services

AVStream provides several services on behalf of the client that are useful for any driver. One of the main services provided is the object bag. Each AVStream object that is visible to the client minidriver (KSDEVICE, KSFILTERFACTORY, KSFILTER, and KSPIN) provides a container known as the object bag. An object bag is a generic container for holding dynamically allocated memory associated with a given object. Whenever a client minidriver allocates dynamic memory with ExAllocatePool and associates it with a given object, the minidriver should call KsAddItemToObjectBag to add the allocated memory to the object bag.

The main advantage of the object bag to the client is simplification of cleanup. When an item is placed into an object bag, a cleanup function is associated with the object (typically this is ExFreePool, however, the client minidriver can provide its own cleanup function). Whenever the object is destroyed (for example, the pin or filter is closed), the object bag will be terminated; AVStream removes every item from the object bag and calls the associated cleanup function.

A single item can be contained in more than one object bag. In this case, the given item is not cleaned up until it is no longer contained in any object bag. For more information, see Object Bags.


Special Concerns of Hardware Drivers

Minidrivers manipulating hardware may provide PnP dispatch functions in the KSDEVICE_DISPATCH. The routines most typically supported are the PnP start device and query capabilities messages, as well as the power messages for hardware supporting any sort of power management.

The PnP start device dispatch is commonly used to allocate context information and associate it with the AVStream device. (In stream class terms, this context information would be the device extension). This dispatch also provides the minidriver with the resources assigned to the device by the PnP subsystem. Typically, this list is parsed to find the interrupt assigned to the device as well as the physical address of any memory regions. Minidrivers are responsible for connecting the interrupt with IoConnectInterrupt.

In addition, hardware that supports DMA must obtain a DMA adapter object with IoGetDmaAdapter. Any buffers that your minidriver requires for DMA transfers can be allocated with HalAllocateCommonBuffer at this stage also.

There is another key factor associated with hardware drivers. Because of the multiple filter types and multiple instance support inherent in AVStream, client minidrivers should NOT attempt to configure hardware to support a particular filter until pins on that filter transition to KSSTATE_ACQUIRE. Many older drivers, particularly stream class drivers, tended to configure the hardware (or acquire the hardware resources) when key pins were connected on a filter. This is an incorrect design for a minidriver.

Consider an example in which a piece of hardware can support both encoding and decoding of some type of data, but can only do one of these operations at a time. As such, it exposes two different types of filters: an encode filter and a decode filter. Imagine now that an application builds a filter graph containing the encode filter and the minidriver loads microcode or configures the hardware for encoding at pin connection time. The filter graph starts and the hardware is encoding. Now, imagine that another application attempts to place a decode filter in a filter graph. When the decode pins are connected, the device configures the hardware for decoding and this causes serious problems in the encode graph that is currently running. Thus, the rule is: do not acquire hardware resources (load microcode or configure hardware for a particular filter) until the appropriate pins on that filter transition into KSSTATE_ACQUIRE.


AVStream DMA Services

The Avshws sample in the DDK illustrates how to build an AVStream minidriver that uses DMA.

First, set up an interrupt by calling IoConnectInterrupt. Then, set up a DMA adapter object using IoGetDmaAdapter. Then register the DMA adapter object with AVStream by calling KsDeviceRegisterAdapterObject. At this point, AVStream performs some basic services on behalf of the minidriver.

A KSPIN that is performing DMA to or from hardware must specify the flag KSPIN_FLAG_GENERATE_MAPPINGS. When the minidriver specifies this flag, AVStream automatically generates scatter/gather mappings for each frame in the queue when the minidriver locks a stream pointer referencing that frame. This means that instead of each KSSTREAM_POINTER_OFFSET structure pointing directly to the virtual addresses of the data, it points to a mappings table through the Mappings field.

The count and remaining fields of the stream pointer offset are mapping granular instead of byte granular. Each mapping in the mappings table contains the physical address of a contiguous chunk of the frame, the number of bytes in the chunk, and the alignment of the chunk.

The minidriver specifies the maximum size for a single scatter/gather mapping by providing a MaxMappingByteCount field in its call to KsDeviceRegisterAdapterObject. If any scatter/gather mapping exceeds this maximum size, AVStream automatically breaks it into multiple scatter/gather mappings, each of which is no larger than the size specified in MaxMappingByteCount.


AVStream Queues

AVStream provides an internal queue object for each pin or inplace transport on a filter. Queues control data frame travel, and are not exposed to the minidriver. Queues are used internally to hold frames until they are processed and released by the minidriver. The minidriver accesses data in the queue by using stream pointers.

Any data frame in the window between the leading edge stream pointer and the trailing edge stream pointer has an its own reference count. Data frames leave the queue when they are behind the leading edge and have a zero reference count. Queuing works for filters using either Pin-Centric Processing or Filter-Centric Processing.

The associated queue holds load-bearing frames for an input pin until the minidriver is done processing them:

Input Pin and Queue

For an output pin, the associated queue holds empty frames until the client has filled them:

Output Pin and Queue

When a stream is processed in place, the queue holds load-bearing frames that have arrived on the input pin until the client has processed the frames, and they are ready to pass through the output pin:

Inplace Processing on a Queue

Data movement out of the queue is controlled by the position of the leading edge stream pointer and by reference counts. Any data frame in the queue that is ahead of the leading edge has not yet been "seen" by the minidriver and will not leave the queue unless the IRP associated with the frame is canceled. Each stream pointer pointing to a data frame in the queue adds a reference to that data frame. Further, any data frame in the window between the leading edge and the trailing edge has an additional reference count. Data frames leave the queue when they are behind the leading edge and have a zero reference count.

A minidriver is not notified that an IRP has been canceled if the minidriver has no stream pointers referencing canceled frames that are ahead of the queue's leading edge.

Depending on the pipe configuration, a single queue may be associated with one or many pins. In cases in which data is not being processed in place and there is no pipe splitting, there is a queue for each pin.

Also see Stream Pointers.


Stream Pointers

Introduction to Stream Pointers

Leading and Trailing Edge Stream Pointers

Locking and Unlocking Stream Pointers

Cloning Stream Pointers

Stream Pointers and Offsets

Stream Pointers and IRP Cancellation

Additional Stream Pointer Functionality


Introduction to Stream Pointers

The minidriver manipulates the Kernel Streaming framework's internal queue implementation by using the KSSTREAM_POINTER structure and related routines. A stream pointer is a reference to a frame that is residing in an associated queue. See AVStream Queues. There may be any number of stream pointers associated with a queue.

Minidrivers that use filter-centric processing do not need to deal with stream pointers directly. Minidrivers that use pin-centric processing, the stream pointer abstraction provides many different ways to access stream data.

The following rules apply to queues, stream pointers, and frames:

  • A frame may be in only one queue at a time.
  • Any number of stream pointers may reference a frame.
  • A stream pointer is associated with a particular queue and may only reference frames in that queue.
  • A frame that is referenced by one or more stream pointers does not leave the queue in which it resides unless the frame is canceled (that is, unless the IRP that contains the frame is canceled).
  • A frame that is referenced by one or more locked stream pointers cannot be canceled. A frame that is not referenced by any locked stream pointers may be canceled.

Also see Leading and Trailing Edge Stream Pointers.


Leading and Trailing Edge Stream Pointers

Each AVStream queue object contains, by default, one stream pointer known as the leading edge stream pointer. The leading edge stream pointer is a pointer into the data stream that points to the most recent unread data in the queue. It is through this pointer that the client first encounters new frames.

When frames arrive into an empty queue, the leading edge is set to point to the first of these data frames. Behavior is the same regardless of whether the frame holds data or is empty. Pin-centric filters call KsStreamPointerAdvance to advance the leading edge. AVStream advances the leading edge pointer for filter-centric filters. The leading edge also advances when a streaming IRP is canceled.

Some queues have a trailing edge stream pointer, which often, but not always, indicates the oldest frame of interest to the client. the trailing edge trails behind the leading edge and is advanced only by the minidriver or by cancellation.

For leading and trailing edge stream pointers, some additional rules apply:

  • The initial reference count for a frame arriving at a queue is zero.
  • All stream pointers except the trailing edge stream pointer increment a frame's reference count when they are set to reference that frame.
  • All stream pointers except the leading edge stream pointer in a queue that has a trailing edge stream pointer decrement a frame's reference count when they are set to no longer reference that frame.
  • When a frame's reference count changes from one to zero, the frame leaves the queue for its next destination.

The effect of these rules is that frames between the leading and trailing edge remain in the queue unless they are canceled, even if they have no stream pointer referencing them. This is useful for clients that maintain a 'window' on a stream consisting of multiple contiguous frames. Clients that access the stream at only one point can use just the leading edge stream pointer. Clients that control the movement of each frame individually can create their own stream pointers by cloning an existing stream pointer. The use of the trailing edge and cloning may also be mixed, if desired, as illustrated in the following figure.

Examples of AVStream Stream Pointers Referencing the Queue

The leading edge stream pointer and optional trailing edge stream pointer are created and managed by the queue. The functions KsPinGetLeadingEdgeStreamPointer and KsPinGetTrailingEdgeStreamPointer provide access to these stream pointers through a pin associated with the queue.


Locking and Unlocking Stream Pointers

Each pointer into the data stream can be in one of two states: locked or unlocked. A locked stream pointer is guaranteed to point to valid data. An unlocked stream pointer, however, may not point at data. It is invalid for a client minidriver to attempt to access the data referenced by the stream pointer while it is unlocked. The minidriver must first call KsStreamPointerLock. To unlock a stream pointer, use KsStreamPointerUnlock.


Cloning Stream Pointers

Minidrivers can clone stream pointers. Cloning creates a new stream pointer that is identical to the parent: The clone references the same frame and has the same lock status.

Once created, clones are independent of their parents and may be locked, unlocked, deleted or advanced to a different frame. Minidrivers clone stream pointers by calling KsStreamPointerClone.

Also see KsPinGetFirstCloneStreamPointer, KsStreamPointerDelete, and KsStreamPointerGetNextClone.


Stream Pointers and Offsets

In addition to a reference to a frame, stream pointers contain a pair of offsets into the frame. See KSSTREAM_POINTER and KSSTREAM_POINTER_OFFSET.

For clients that use virtual addresses to access stream data, the offsets allow the stream position to be specified to byte resolution. For clients that use scatter/gather physical mappings, the offsets allow the stream position to be specified to the resolution of one mapping.

Two offsets are provided so that in-place processing may use separate input and output offsets.

The framework supplies functions that advance offsets and move to a new frame when offsets hit the end of the old frame. See KsStreamPointerAdvanceOffsets, KsStreamPointerAdvanceOffsetsAndUnlock, and KSSTREAM_POINTER_OFFSET.

Clients may alter offsets or simply access the data at frame resolution.

Also see Stream Pointers and IRP Cancellation.


Stream Pointers and IRP Cancellation

Cancellation poses a problem in many circumstances in which IRPs must be kept in a queue (KS queues contain frames, which are in turn related to IRPs).

If a minidriver is holding a locked stream pointer referencing a particular frame, the frame and the IRP associated with that frame cannot be canceled. Minidrivers should avoid holding locked stream pointers for an extended period of time. Sometimes, however, a client wants to hold a data pointer into the stream but still allow the frame to be canceled. In this case, the minidriver must hold an unlocked stream pointer on the data frame and supply a cancellation callback in the creation of the stream pointer by using KsStreamPointerClone.

The KS framework gives the client a number of options with regard to cancellation:

  • Many clients only need brief access to stream data at a single access point. This is accomplished by requesting a locked stream pointer (probably by calling KsPinGetLeadingEdgeStreamPointer with a state argument of KSSTREAM_POINTER_STATE_LOCKED) and unlocking the stream pointer immediately after processing is complete (with KsStreamPointerUnlock or KsStreamPointerAdvanceOffsetsAndUnlock). This is simple for the client and does not block cancellation for a significant amount of time assuming that the thread does not block between acquiring the pointer and unlocking it.
  • Some clients need access to stream data for an indefinite amount of time, but are able to relinquish their claim in the context of a cancellation callback. This is generally accomplished by creating a clone (by calling KsStreamPointerClone) of a locked stream pointer (usually the leading edge), unlocking it, and responding correctly to the cancellation callback supplied in the call to KsStreamPointerClone.
  • Because the callback occurs with the queue's spinlock taken, very little can be done with the stream pointer in the callback except delete it. Fortunately, this is almost always exactly what the client wants to do, after making sure the associated data will not be accessed. This approach to cancellation can be more difficult for the client, but it often provides the best balance between efficient access and quick response to cancellation.
  • Some clients need period access to a frame and can tolerate the disappearance of the frame between accesses. This is accomplished by keeping an unlocked clone and locking it whenever access is to occur. If the frame is canceled, the next attempt to lock the stream pointer will fail, and the client can delete the stream pointer. As with the first option, responsiveness to cancellation is a function of how long the stream pointer is locked.
  • Some clients need access to stream data for an indefinite period, but are unable to relinquish their claim in response to a callback. In such cases, a locked clone stream pointer may be maintained for any length of time to prevent cancellation. However, responsiveness to cancellation may be poor depending on how long the stream pointer remains locked. Stream pointer timeouts, discussed below, may be useful in such cases.

Also see Additional Stream Pointer Functionality.


Additional Stream Pointer Functionality

There are a few miscellaneous features relating to stream pointers that may be useful for some clients:

  • A timer can be set on any stream pointer. A callback to the client indicates that the timer has expired. To set a timeout, call KsStreamPointerScheduleTimeout, and call KsStreamPointerCancelTimeout to cancel a timeout.
  • When a clone is created using KsStreamPointerClone, an optional context size can be supplied. If a non-zero context size is supplied, additional memory is allocated for the context and the stream pointer's Context field is set to point to the allocated context. Because the memory is allocated along with the stream pointer structure, no additional allocation calls are generated by using this feature.
  • Clone stream pointers associated with a queue can be enumerated (by way of an associated pin) using KsPinGetFirstCloneStreamPointer and KsStreamPointerGetNextClone.


AVStream Concepts

This section contains information relevant only to the Microsoft® Windows® XP and DirectX® 8.0 releases and later.

This section covers:

Object Bags

Flow Control Gates in AVStream

Pipes, Pipe Sections, and Circuits

Frame Injection

AVStream Splitters

Format Negotiation and Data Intersections

Graph Builders

Kernel Mode Filters, DirectShow, and Proxying

Mutexes in AVStream


Object Bags

Object bags are dynamic memory containers that an AVStream minidriver uses to associate dynamic memory with a given object. This object may contain context information or other information that the minidriver allocates off the pool. Object bags can be used with any AVStream object, from a device down to a pin.

Because AVStream automatically performs cleanup tasks when objects are deleted, using object bags simplifies cleanup. Whenever an AVStream object (for example, a pin or filter) is deleted, AVStream empties the corresponding object bag. During this process, AVStream calls the Free method for each item in the bag in order to free the dynamic memory associated with the item. Note that only available memory limits the number of items that an object bag can contain.

With object bags, many AVStream objects can share a specific piece of dynamic data. To facilitate this, AVStream allows minidrivers to place a given item in multiple object bags. When a minidriver places an item into an object bag, this bag is also associated with the device to which the object belongs. The first time an item is placed into any object bag associated with a device, the item is also placed into the device bag and is given a reference count of one. When the item is placed into an additional object bag, the item's reference count in the device bag is incremented.

Items can also be removed from an object bag, either automatically by AVStream when the object is terminated, or manually by the minidriver through a call to KsRemoveItemFromObjectBag or KsDiscard. Items should be removed from an object bag only when they no longer are associated with a given object.

When an item is removed from an object bag, its reference count is decremented in the corresponding device bag entry. If the item's reference count becomes zero, the item is removed from the device bag. Depending on how the item was removed, the item's cleanup function then may be called. The default cleanup function is ExFreePool, but the minidriver can request that AVStream call a different cleanup function upon removal of an item. To do this, the minidriver specifies the cleanup function when it adds the item to an object bag by calling KsAddItemToObjectBag.

AVStream also uses the object bag to track what structures are editable within descriptors. If a descriptor or a substructure of a descriptor is dynamically allocated, it will be in the bag for the object to which the descriptor is attached. This is the how KsEdit determines whether or not a given structure can be edited. The following diagram explains the object bag concept.

Structure of an Object Bag

This figure represents a hypothetical situation where a filter and a pin both have an associated context structure. There is also a chunk of dynamic memory that is used by both the filter and the pin. Filter context and dynamic memory are in the filter object bag; pin context and dynamic memory are in the pin object bag. The arrows show the associations between items in object bags and their respective entries in the device bag.

For example, if the filter context is removed from the filter object bag, the filter's reference count becomes 0, which causes the device bag's cleanup function to be called. On the other hand, if the dynamic memory is removed from the filter object bag and not from the pin object bag, the device bag's cleanup function is not called because its reference count would still be 1.


Flow Control Gates in AVStream

Gates are an AVStream control flow mechanism. Inside AVStream, they are used as a processing control mechanism, controlling when data is processed. Each gate is represented by a KSGATE structure.

AVStream gates are similar to ordinary logic gates, including AND and OR gates. Both gate types are implemented using the KSGATE structure, but the semantics of the fields in KSGATE are different. As an example, consider a pin that has an AND gate as a processing control. There can be any number of inputs to this AND gate and each input can be in one of two states: on and off. The diagram below illustrates three different AND gates each with three inputs.

Three AND Gates

The first AND gate in this figure has one on input and two off inputs. The state of the gate is therefore off or closed since by definition all inputs to an AND gate must be on for the gate to pass the signal. You will notice a similar situation for the second gate in the diagram. The third gate, however, has all on inputs; the gate is therefore on or open.

In each of the gates, you will notice a bold number. This is the value that is stored in the Count field of the KSGATE structure. For an AND gate, the value is one minus the number of off inputs:

Count = 1 - (number of off inputs)

If this value is less than or equal to zero, the gate is considered to be closed. If this value is greater than zero, the gate is open.

OR gates are also implemented using KSGATE, but the semantics of the Count field are different. The following diagram illustrates this.

Three OR Gates

The first gate in this figure has three off inputs. The state of the gate is therefore off or closed. However, the second gate is in the on or open state because at least one of its inputs is on. The bold number in the OR gates is again the value stored in the Count field of KSGATE for the given gate. For an OR gate, this value is the number of on inputs to the gate. If this value is equal to zero, the gate is considered to be closed. If this value is greater than zero, the gate is open.

Count = (number of on inputs)

Note that AVStream performs no checks internally as to whether the state a minidriver sets the gate to is valid. AND gates have a valid Count range of one or below whereas OR gates have a valid Count range of zero or above. Minidrivers should not use the gate API to set gates to invalid values.

In each of the three gates above, note the arrow at the right of each gate. This arrow could be used as an input to another gate. In this way, gates can be attached to other gates, forwarding transitions from one gate to the next. When a gate is attached to another gate and it transitions from closed to open, it turns on an input to the gate it is attached to. Similarly, when a gate attached to another gate transitions from open to closed, it turns off an input to the second gate.

AVStream uses this gating mechanism to determine when it is appropriate to process data and for what device. When a thread enters a state in which it is ready to process, it attempts to capture the on input of the AND gate that controls processing for the processing object. The thread attempts capture by making a call to KsGateCaptureThreshold. This call checks whether the gate is open and if it is, it closes it. In either case, the state of the gate (open or closed) is returned. If the gate was originally open, processing commences. While processing is proceeding, no other thread can capture the on input of the gate; therefore no other thread can process data.

This mechanism can also be used by minidrivers to suspend processing for an indefinite period of time. In order to do this, a minidriver should add or turn off an input to the processing AND gate and no processing occurs.

For more information regarding the gate API, see the following KsGateXxx and KsXxxGateXxx functions:

KsGateAddOffInputToAnd, KsGateAddOffInputToOr, KsGateAddOnInputToAnd, KsGateAddOnInputToOr, KsGateCaptureThreshold, KsGateGetStateUnsafe, KsGateInitialize, KsGateInitializeAnd, KsGateInitializeOr, KsGateRemoveOffInputFromAnd, KsGateRemoveOffInputFromOr, KsGateRemoveOnInputFromAnd, KsGateRemoveOnInputFromOr, KsGateTerminateAnd, KsGateTerminateOr, KsGateTurnInputOff, KsGateTurnInputOn, KsGateTurnInputOn, KsGateTurnInputOn, KsGateTurnInputOn, KsGateTurnInputOn


Pipes, Pipe Sections, and Circuits

A pipe is a set of filters that share a common allocator. A pipe is not an object physically implemented by AVStream. The following illustration shows a simple pipe composed of three AVStream filters: a source filter, an inplace transform filter, and a renderer filter:

Pipe Example Using All AVStream Filters

The filter on the left in this figure is a source filter. Behavior of this filter is specified by the AVStream minidriver code attached to the filter's queue. In this particular pipe, the source filter has been chosen as the allocator, and thus has a requestor object associated with it. Data from the source filter flows into a transform filter implemented by another AVStream driver. Finally, data flows into the renderer filter implemented by a third AVStream filter.

When this graph is first built, the pins, shown in the diagram connecting the three large blocks, are interconnected. When the graph transitions to an ACQUIRE state, the pins query each other to verify that they are AVStream pins and that they have completed acquisition. If they are AVStream pins, the pins are bypassed and AVStream transport interfaces are established. These interfaces connect the first filter's queue directly to the second filter's queue and the second filter's queue directly to the third filter's queue. The third filter's queue is attached back to the requestor so that frames sent downstream are returned and recycled once they are completed by the renderer. This AVStream data path is a circuit.

AVStream implements the pipe in sections. A pipe section is that piece of a pipe that is associated with a given filter.

However, it is not always the case that every filter in a graph is an AVStream filter. The following figure illustrates the case where the transform is not an AVStream filter, but is still a kernel-mode filter.

Pipe Example Using Non-AVStream Kernel-Mode Transform Filter

In this diagram, as in the previous figure, there are three filters: one AVStream source filter, one kernel streaming transform filter (this could be a driver that uses KS directly or a minidriver under stream class), and one AVStream renderer filter. As in the previous graph, the pins are first interconnected. When the graph transitions to ACQUIRE, however, the sequence of events changes. The Kernel Streaming 1.0 filter does not support the AVStream transport interface. Thus the pins are not bypassed.

When an object leaves the source filter's queue, it ends up in the pin where it gets passed down to the transform through the call to IoCallDriver. When the renderer's input pin receives an IRP, the pin places the IRP in the queue. When the renderer driver completes frames, the frames are sent back to the pin where an IoCompleteRequest routine causes them to be sent back upstream. The source filter's output pin receives a completion notification and then moves frames back to the requestor where they are recycled into the circuit.

It is also possible, however, that the source of frames or the final destination is in user mode. As an example, consider the case of a kernel-mode non-inplace transform filter receiving frames from a user-mode DirectShow® filter and sending the new transformed frame to a kernel-mode AVStream renderer. The structure of the pipe is illustrated in the following diagram.

User-Mode Source to AVStream

There are two different pipes and three pipe sections involved in this example. Frames come down from user mode and are injected into the queue for the input pipe section by the AVStream pin object. The second pipe is a circuit for the transformed frames that are allocated in kernel mode by the non-inplace transform filter. Since the renderer is an AVStream filter, the pins can be bypassed and the frames can be sent through the AVStream transport interface directly into the renderer's queue.

There is another case in which the requestor does not receive frames from a kernel-mode allocator. Instead, the minidriver specifically injects frames into the circuit by calling KsPinSubmitFrame or KsPinSubmitFrameMdl. For more information, see Frame Injection.


Frame Injection

The default behavior for building the AVStream constructs required to stream data between filters is as follows: A requestor is created that in turn primes a queue by allocating a given number of frames. The minidriver then fills the frames either by pin-centric or filter-centric processing. The frames then move across a transport to the next object in the circuit. The frame proceeds around the circuit until it eventually returns to the requestor. At this point, the frame is reused.

Minidrivers, however, can override this default behavior by calling KsPinRegisterFrameReturnCallback while the filter is in the stop state (that is, the pin object is created and the pin creation dispatch is called). This places the requestor in an injection mode where instead of acquiring empty frames from an allocator and placing them in the queue, it waits until the minidriver specifically injects frames into the circuit through a call to KsPinSubmitFrame or KsPinSubmitFrameMdl.

When the frames make their way around the circuit and back to the requestor, the frame return callback registered by KsPinRegisterFrameReturnCallback is called so that the minidriver can deallocate the frame, complete anything pending on the return of the frame, or refill and reinject the frame. The diagram below illustrates the construction for an AVStream filter set composed of a source, an inplace transform, and a renderer with the source injecting frames.

Frame Injection

Built on Wednesday, July 11, 2001


AVStream Splitters

One very convenient feature provided by AVStream is the splitter. Any pin that specifies KSPIN_FLAG_SPLITTER behaves as an automatic splitter. The entire functionality of the splitter is contained within AVStream. All a minidriver needs to do is specify this flag; AVStream automatically handles all data copying necessary to perform the splitting. In releases post-DirectX 8.0, the KSPIN_FLAG_SPLITTER flag works for pins on both filter-centric and pin-centric filters. Older releases support this flag only for pins on filter-centric filters.

The following diagram shows the configuration of a filter that has specified that its output pin should be a splitter (when the downstream filters of the output pin are modifying data inplace).

AVStream Filter with a Splitter Output Pin

Note that this diagram does not show where frames are coming from on the output pin; there may be a requestor and allocator associated with each queue and belonging to this pipe section, or the frames may come from some other downstream filter. Frames arrive on the input pin and are placed into the input queue. The minidriver interfaces only with the input queue and the output queue for the original pin. AVStream handles the automatic copying of data from the first pin's queue to the second pin's queue. The following diagram shows how the minidriver distinguishes these two pins in the process pins list.

Process Pins Table for Two Split Pins

There are two types of pins described in this figure: the input pin and the output pin. There is one instance of the input pin and two instances of the output pin.

In this diagram DB refers to the DelegateBranch field of the process pin and CS to the CopySource field. Both the DelegateBranch and CopySource fields of the input pin and the first output pin are NULL. This is an indication that the minidriver is responsible for handling frames on these pins.

The second output pin, however, has a CopySource that points back to the first output pin. This indicates that the second output pin is in a separate pipe from the first output pin and that AVStream is automatically copying any data that is placed into the first output pin's queue into the second output pin's queue.

More complicated splitter cases can arise when two output pins are built into the same pipe. This can occur, for example, if downstream filters are not modifying the data sent out using the aforementioned output pins. Because there is no modification, they can be considered read-only and both downstream filters can receive the same buffers. It is also possible that there is mixing of downstream filters: some downstream filters that automatically attach to the splitter pin modify the data and some do not. In this case, you may see a filter layout similar to the following diagram, which depicts a filter that has had three instances of the split output pin connected.

AVStream Filter with Three Split Output Pins

Pins A and B in this figure are assigned to the same pipe because the downstream filters do not modify the data; thus the filters downstream of A and B receive the same buffer pointers. Pin C could not be assigned to the pipe containing A and B and was therefore assigned to a separate pipe. Note that the minidriver only has to interact with the input queue and a single output queue. AVStream performs automatic copying from the A/B queue and the C queue. It also creates a splitter object that sends the same data frames through pin A and pin B (note that the stream headers differ).

The process pins table should look as follows:

Process Pins Table for Three Split Output Pins

This process pins table again only has two types of pins: the input pin and the output pin. However, this time there are three instances of the output pin. Pin A has a NULL DelegateBranch and CopySource. Pin B has a DelegateBranch pointing back to A, and pin C has a CopySource pointing back to A. The only pin that the minidriver must interact with under normal circumstances is pin A.

The DelegateBranch field indicates whether or not a specific pin receives frames from another process pin in the same pipe. If this field is non-NULL, then AVStream is performing an automatic split and the pin from which the split data comes is the process pin pointed to by DelegateBranch. The CopySource field indicates whether or not this pin receives copies of frames from a process pin in another pipe. An important distinction here is that DelegateBranch indicates that the same data buffers are being received downstream and CopySource indicates that AVStream is copying the data into different buffers.

For simplification of the above diagrams, requestors and allocators were intentionally left out of the diagrams. The diagrams are intended only to demonstrate the frame splitting process.

For more information on the KSPIN_FLAG_SPLITTER flag, see KSPIN_DESCRIPTOR_EX.


Format Negotiation and Data Intersections

A data intersection is a mechanism in a KS-compliant driver that chooses a data format from two lists of data ranges. A data format is a single format that is set on the connection; it specifies exact parameters. For example, an audio data format might specify a certain format of audio at X samples per second and Y bits per sample. A data range on the other hand specifies a format with a range of valid parameters. An audio data range might specify a certain format of audio at A-B samples per second and C-D bits per sample.

When the minidriver lays out a pin descriptor, it provides a list of data ranges that it supports. The data intersection converts this list of data ranges into a specific, viable data format. When a KS compliant driver receives an intersection request, it is given two lists of data ranges and asked to intersect them. It is the responsibility of the data intersection to select a specific data format in the intersection of the two lists of data ranges. The diagram below illustrates an example of an intersection within a generic KS compliant driver.

Data Intersection

The driver has received two lists of data ranges to intersect: list 1 and list 2. Note that the diagram shows only one range of parameters per data range. It is quite likely that a data range specifies ranges for more than one value (that is, audio specifying samples per second and bits per sample ranges). The intersection of these two data ranges is shown to the right in the Data Intersection figure. It is a range of "type B" with the parameter in the highlighted region. The data intersection handler is then responsible for choosing the optimal data format within that range.

To simplify dealing with lists of data ranges, AVStream, like many other class drivers, performs the data intersection through a callback function: the pin's intersect handler. When the intersect handler is called, two data ranges are passed to it, one from each list. The two data ranges are guaranteed to match with respect to major type, subformat, and specifier. Further, the required attributes of the data ranges are guaranteed to match.

It is the responsibility of the intersection handler to find the intersection of the two data ranges and then to select and return a preferred data format from that range. If the two data ranges do not intersect, the handler returns STATUS_NO_MATCH. If they do intersect and sufficient buffer space is provided to copy a format back, the intersection routine chooses a format in the intersection and copies it back to the caller.

Once a data format has been selected for the connection, the pins are created, and AVStream calls an internal routine to set the data format on the pin. This validates that the selected data format is within the data range in the minidriver's pin descriptor list of data ranges. If the minidriver specifies a SetDataFormat dispatch, this dispatch is called to inform the minidriver that a specific format is being set on the pin. The SetDataFormat dispatch is prototyped as follows:

NTSTATUS
  SetDataFormat (
    IN PKSPIN Pin,
    IN PKSDATAFORMAT OldFormat OPTIONAL,
    IN PKSMULTIPLE_ITEM OldAttributeList OPTIONAL,
    IN const KSDATARANGE* DataRange,
    IN const KSATTRIBUTE_LIST* AttributeRange OPTIONAL
);

The selected data format is PinConnectionFormat. AVStream verifies that the format is a partial match for DataRange (in at least as much as major type, subformat, specifier, and attributes). The minidriver's dispatch function is responsible for determining whether it really is a match for DataRange; this is the last chance for the minidriver to turn down a specific data format for the connection. If it is determined that the format is to be turned down (that it is not a match), the dispatch function should return STATUS_NO_MATCH instead of STATUS_SUCCESS.


Graph Builders

How these mechanisms are used to connect two filters depends on the graph builder. Intersections, for example, may be performed in a cross-pin manner or in a single-pin manner. A graph builder, for example, upon attempting to connect two pins on two filters A and B, may take the list of data ranges on the appropriate pin on filter A and ask filter B to perform an intersection with the associated pin. This would be an example of the intersection type illustrated in the Data Intersection figure in Format Negotiation and Data Intersections. Filter B would attempt to find a data format in the intersection that is acceptable to both pins and then return this to the builder. The returned format would then be used for a connection.

Conversely, a builder, upon attempting to connect two pins, may use intersections in a single-pin manner. For example, upon attempting to connect two pins on two filters A and B, the builder may get a specific data range from the pin on filter B and ask filter B to perform an intersection between the acquired data range and the pin's list of data ranges. This intersection may seem irrelevant as it often intersects a data range with itself. However, it serves an important purpose: it turns the data range into a data format which is both inside the range and optimal for filter B. This data format could then be suggested to filter A.

To maximize versatility, the intersection routine should be prepared to deal with both eventualities.


Kernel Mode Filters, DirectShow, and Proxying

Kernel mode filters often are connected in user mode through the proxy (which makes a kernel mode filter appear to user mode as a DirectShow filter). When this mode of connection is used, DirectShow uses its normal means to attempt to connect the filters: For example, pin A's media types are enumerated and relayed to pin B until a connection is made or the available types on pin A are exhausted. If the available types are exhausted, the enumeration happens in reverse: pin B's media types are enumerated and relayed to pin A.

It is important to note that the relation is made between kernel mode data formats and DirectShow media types. When a media type is enumerated off a kernel mode pin, the Nth data range on the pin is intersected with the pin's data range. This intersection yields a data format, as described in Format Negotiation and Data Intersections. The proxy converts the resulting data format into a DirectShow media type.

When a media type is relayed to a proxied pin, the proxy either asks a data handler to determine whether the media type is acceptable, or it determines whether the media type is a partial match for a data range on the pin. A partial match indicates that, in the context of kernel mode semantics, the major type, subformat, specifier, and required attributes match, either exactly or by wildcard. If the media type is a partial match, the connection proceeds.

Before the connection completes, AVStream calls the minidriver's SetDataFormat dispatch to inform the minidriver of the data format being set. Note that this format corresponds to the user mode media type that was suggested to the proxied pin. AVStream also provides the data range that was determined to be a partial match for the format. At this point, the minidriver's SetDataFormat dispatch still can decline the format by returning STATUS_NO_MATCH. The dispatch might do this if, for example, it determines that the format is not a match for the range.


Mutexes in AVStream

In AVStream, minidrivers perform synchronization tasks by using three types of mutexes and process control gates. All three mutexes are directly accessible to the minidriver. For more information on process control gates, see Flow Control Gates in AVStream.

Synchronize hierarchy objects from device to filter with the device mutex, and synchronize objects from filter to pin using the control mutex. See related details in the sections listed below.

Several AVStream API functions require that associated mutexes be held. Notes are included in the Comments sections of relevant function reference pages stating which mutex should be held before calling that particular function.

Device Mutex in AVStream

Filter Control Mutex in AVStream

Processing Mutex in AVStream


Device Mutex in AVStream

The first mutex is the device mutex. Each AVStream device has a single associated device mutex. This mutex is used to synchronize access to the object hierarchy from the device down to the filters. Creation and destruction of both filter factories and filters are synchronized with this mutex. Certain Plug and Play and power management operations are also synchronized with this mutex. The main concern of the minidriver in dealing with the device mutex is in manually creating filter factories with KsCreateFilterFactory or in traversing the object hierarchy through the KsXxxGetFirstChildXxx and KsXxxGetNextSiblingXxx functions. The object hierarchy is guaranteed to be stable only from the device down to individual filters if the device mutex is held.

AVStream holds the device mutex on behalf of the minidriver during the following operations:

  • PnP QueryStop (IRP_MN_QUERY_STOP) dispatch
  • PnP QueryRemove (IRP_MN_QUERY_REMOVE) dispatch
  • PostStart dispatch
  • PnP StartDevice (IRP_MN_START_DEVICE) dispatch
  • Power Management QueryPower (IRP_MN_QUERY_POWER) dispatch
  • Power Management SetPower (IRP_MN_SET_POWER) dispatch
  • Sleep and Wake notifications on filters and pins

It is important to note that the device mutex is not recursively reobtainable. This means that if AVStream executes a callback to a minidriver for a Sleep notification in the context of thread A, and then the minidriver subsequently attempts to obtain the mutex in that same thread (A), thread A deadlocks with itself.

Also note that AVStream often obtains control mutexes while the device mutex is already held. Consequently, as a general rule, a thread that has taken a control mutex should not subsequently take the device mutex.

To manipulate the device mutex, use the following functions:

KsAcquireDevice, KsReleaseDevice


Filter Control Mutex in AVStream

The second mutex used in AVStream is the filter control mutex. Each AVStream filter instance has an associated filter control mutex. This mutex is used to synchronize access to the object hierarchy from the filter downward to individual pins. Creation and destruction of filters and pins are synchronized with this mutex. The filter control mutex is also used to synchronize state transitions. The main concern of the minidriver in dealing with the filter control mutex is in traversing the object hierarchy via the KsXxxGetFirstChildXxx and KsXxxGetNextSiblingXxx functions. The object hierarchy is guaranteed to be stable only from a specific filter instance downward if the filter control mutex is held.

AVStream also obtains the filter control mutex when handling properties that require the hierarchy to remain stable, such as when performing descriptor modification.

Note that there is a single control mutex used for the object hierarchy from the filter level downward. This means that a pin object uses its parent's control mutex (the filter control mutex) when a minidriver calls this function with a pin object.

AVStream holds the filter control mutex on behalf of the minidriver during the following operations:

  • Filter Create dispatch
  • Filter Close dispatch
  • Pin Create dispatch
  • Pin Close dispatch
  • Pin Connect dispatch
  • Pin Disconnect dispatch
  • Pin Reset dispatch
  • Pin SetDataFormat dispatch
  • Pin SetDeviceState dispatch

It is important to note that, like the device mutex, the filter control mutex is not recursively reobtainable. If, for instance, AVStream makes a callback to a minidriver for a Create dispatch in the context of thread A and the minidriver later attempts to obtain the mutex in that same thread (A), thread A deadlocks with itself.

As mentioned in Filter Control Mutex in AVStream, a thread that has taken a processing mutex should not subsequently take the filter control mutex. In addition, AVStream often obtains process mutexes while already holding control mutexes.

To manipulate the filter control mutex, use the following functions:

KsAcquireControl, KsFilterAcquireControl, KsPinAcquireControl, KsReleaseControl, KsFilterReleaseControl, KsPinReleaseControl


Processing Mutex in AVStream

The third mutex is the processing mutex. Individual filters and pins have their own processing mutexes. AVStream independently acquires the processing mutex before processing at the filter and pin level, in order to synchronize access to processing-related structures. AVStream also acquires the processing mutex during other operations, including binding pins to a pipe section, sleep or wake power operations, and making modifications to descriptors. Minidrivers can manually acquire the mutex to perform a synchronous operation, such as processing or descriptor modification. A minidriver should obtain the processing mutex before making any change that cannot happen concurrently with processing.

As with the other two types of mutexes, process mutexes also are not recursively reobtainable. This means that if a minidriver attempts to grab the process mutex while processing, a deadlock occurs.

Do not use the processing mutex to suspend processing for long periods of time. Instead, manipulate the processing control gate directly using the KsGateXxx functions.

As mentioned in Filter Control Mutex in AVStream, a thread that has taken a process mutex should not subsequently take the filter control mutex.

To manipulate the processing mutex, use the following functions:

KsFilterAcquireProcessingMutex, KsPinAcquireProcessingMutex, KsFilterReleaseProcessingMutex, KsPinReleaseProcessingMutex


Stream Minidriver Design Guide

This section details the outdated Stream.sys class driver. With the release of Microsoft® Windows® XP, Microsoft recommends that vendors consider developing new non-audio multimedia drivers using the next generation class model, AVStream. See details in the AVStream Overview. Microsoft now only supports Stream.sys on an as-is basis. If developing an audio miniport driver, see Audio Miniport Drivers.

Most classes of devices should be supported by supplying a streaming minidriver. In particular, video capture devices, like digital cameras and DVD players, are supported through streaming minidrivers, as well as external sound devices. See the Video Capture Minidriver Design Guide and Vendor-Supplied DVD Drivers.

Stream minidrivers support kernel streaming semantics. To use this document, driver developers should be familiar with basic kernel streaming concepts, as explained in Kernel Streaming Overview.

The stream class driver is designed to make writing hardware drivers for streaming devices simpler, by handling many of the aspects of interacting with the operating system.

  • The minidriver can allow the stream class driver to handle synchronization on its behalf. For example, the stream class driver can optionally serialize I/O requests for the minidriver. Allowing the class driver to handle synchronization makes the minidriver multiprocessor-safe but non-reentrant. This is suitable for low-end to medium-end hardware.
  • The class driver automatically synchronizes file operations. For example, the opening of a stream and a device are correctly serialized without the minidriver using mutexes, semaphores, or events.
  • The class driver abstracts the implementation of kernel streaming semantics from the minidriver.
  • The class driver handles all interaction with the PnP Manager. For example:
    • The class driver creates the functional device object on the minidriver's behalf.
    • The class driver manages resource configuration (such as translating port addresses, translating and mapping memory ranges, and connecting interrupts).
    • The class driver handles PnP IRPs, such as IRP_MN_START_DEVICE, or IRP_MN_STOP_DEVICE.
  • All low-level buffer management is handled by the class driver:
    • Allocating DMA adapter object, if necessary.
    • Mapping buffers and building scatter/gather lists for DMA.
    • Locking and flushing buffers correctly for both DMA and PIO.
  • All IOCTL parameter validation is performed by the class driver.
  • All requests are timed by the class driver with a watchdog timer.
  • The minidriver does not create a device object, but shares the class driver's device object as necessary. This saves system resources.
  • Only one device object is created per adapter. Multiple subdevices (called streams) supported by the adapter are represented by kernel streaming pins.


Class Driver and Minidriver Definitions

A Microsoft-provided class driver is an intermediate driver designed to provide a simple interface between a vendor-written minidriver and the operating system. A minidriver is a hardware-specific DLL that uses a Microsoft-provided class driver to accomplish most actions through function calls, and provides only device-specific controls.

Under WDM, the minidriver registers its associated hardware adapters with the class driver, and the class driver creates a file object to represent each adapter that registers. The minidriver uses the class driver's device object to make system calls. The class driver is accessed by user-mode clients through WDM Streaming.

The interactions between class driver and minidriver include:

  • The minidriver does not create a device object, but shares the class driver's device object as necessary. This saves system resources.
  • Only one device object is created per adapter. Multiple subdevices (called streams) supported by the adapter are represented by WDM Streaming pins.


Stream Class and Minidriver Interface

The stream class interface is primarily a set of function calls between the class driver and the minidriver. The class driver controls the request flow, calling the adapter minidriver when access to the adapter hardware is necessary. The class driver is responsible for multiprocessor and interrupt synchronization. After both the class driver and the minidriver are initialized, the minidriver is passive and is called only by the class driver. Most of the function calls from the minidriver to the class driver are low-level service requests.

The basic mechanism controlling commands and information to the minidriver is the stream request block (SRB). A set of SRBs is provided for each minidriver to access particular capabilities of a driver and are usually specific for each data stream supported by the device. This information is passed to the device through an operating-system-controlled DMA in a large circular buffer.

An SRB comprises a command and data associated with that command. A HW_STREAM_REQUEST_BLOCK structure contains all information relating to a specific SRB. This structure, often referred to simply as an SRB, contains additional parameters to supplement the command.

The following illustration shows the interaction between the stream class and the minidriver during initialization.

Initializing the Adapter

All streaming minidriver functions are optionally synchronized with the minidriver's interrupt service routine (ISR), making the minidrivers nonreentrant. In other words, when a thread is executing in the minidriver, no calls will be made to any other function within the minidriver, including the ISR. This nonreentrant condition holds true even on multiprocessor Windows NT/Windows 2000 systems, making the minidrivers easier to write. The stream class driver achieves this nonreentrant condition by masking off the IRQ of the streaming minidriver (and all lower priority IRQs) using KeSynchronizeExecution when code is executing in any of the minidriver's routines. For more information on synchronization, see Minidriver Synchronization.

The streaming minidriver can call WDM system services as necessary. However, the minidriver does not allocate a device object but utilizes the class driver's device object to make system calls. Most minidrivers will not need to make WDM system calls, as all necessary functionality is available from the class driver.

Minidrivers must be aware that all minidriver entry points are called at IRQL > DISPATCH_LEVEL when making WDM system service calls, except for the StreamClassCallAtNewPriority routine. This function allows service calls at IRQL = DISPATCH_LEVEL or PASSIVE_LEVEL, depending on the priority specified. This limitation on IRQL can be overridden by setting the TurnOffSynchronization Boolean in the HW_INITIALIZATION_DATA structure to TRUE.


Writing a Stream Minidriver

The main design goal of the stream class driver is to handle the work both of handling the operating system, which includes the intricacies of supporting multiprocessor machines, and of supporting kernel streaming semantics. It requires the minidriver to handle only the device-specific portion of any operation it must perform. The class driver allocates memory for the minidriver, performs bookkeeping for any NT kernel resources the minidriver may require, and (optionally) handles all synchronization issues.

The class driver communicates to the minidriver through a set of minidriver-provided callbacks. Most of the work of writing a streaming minidriver occurs in writing these callbacks.

In this documentation, we refer to each type of minidriver-provided routines as StrMiniXXX. The minidriver may have to provide one or more versions of each routine, depending on how many different functions the underlying hardware is capable of performing.

A streaming driver typically can support several different streams of data. For example, a DVD player produces both an audio and a video stream. Within the context of kernel streaming, each stream of data is represented by a pin. (See KS Filters, Pins and Node Topology for a description of pins.)

The stream class driver keeps track of each pin on the minidriver. In the terminology of the class driver, each pin type is a stream. Streams, like pin types, may have multiple instances. Since streams can receive I/O requests, the driver must provide callbacks for each stream.

The following are the routines the minidriver may have to provide. They are documented more fully below and in the reference guide.

Routines every minidriver provides

StrMiniCancelPacket

StrMiniReceiveDevicePacket

StrMiniRequestTimeout

StrMiniEvent

StrMiniInterrupt

Routines the minidriver provides for each individual stream

StrMiniReceiveStreamDataPacket

StrMiniReceiveStreamControlPacket

StrMiniEvent

StrMiniClock

It is possible for the minidriver to use the same callback for several different streams. The callback can determine the stream on whose behalf it was called from its parameters.

The minidriver must, like all WDM drivers, also provide a DriverEntry routine. The main task of the DriverEntry routine of a minidriver is to register the minidriver with the class driver.

The class driver receives all I/O requests on behalf of the minidriver. To obtain the information it needs to complete the request, the class driver builds a stream request block (SRB) and passes it to one of the StrMiniXXXPacket routines. The class driver dispatches I/O requests to the device as a whole to the StrMiniReceiveDevicePacket routine. It passes requests to individual streams to the StrMiniReceiveStreamDataPacket (for kernel streaming read and write requests) or StrMiniReceiveStreamControlPacket (for other requests).

Normally, the class driver queues its requests, and passes them one at a time to the minidriver. The minidriver may optionally do its own synchronization; the minidriver is then responsible for queuing requests it cannot immediately handle. See Minidriver Synchronization for details.

The minidriver must provide two additional routines for manipulating stream request blocks. The class driver calls StrMiniCancelPacket when it receives a cancel IRP, and needs to tell the minidriver to cancel a specific packet. The class driver also keeps track of how long the minidriver takes to complete its handling of a stream request block. If the minidriver takes too long, the class driver will time out the request, and call the minidriver's StrMiniRequestTimeout routine.

When a hardware interrupt occurs, the operating system signals the class driver, which then calls the minidriver's StrMiniInterrupt routine to handle the interrupt.


Handling Stream Request Blocks

The operating system dispatches all I/O requests on the device to the class driver. The class driver in turn requests hardware-specific information from the minidriver by passing SRBs to the minidriver. The class driver specifies the operation it requests in the Command member of the stream request block.

Both the minidriver as a whole, and each stream within the minidriver, may receive I/O requests. The minidriver must provide a StrMiniReceiveDevicePacket routine to handle device-wide requests. Each stream must support two routines to handle I/O requests: one for data requests, and one for control requests. The class driver will call the data request callback, StrMiniReceiveStreamDataPacket, to handle all read and write requests on a stream. All other requests for a stream are passed to StrMiniReceiveStreamControlPacket.

If the class driver is handling synchronization for the minidriver, it queues stream requests, and dispatches them to the minidriver one at a time. The class driver maintains three separate queues — one for device requests, and one each for stream data and control requests. The minidriver may signal that it is ready for a new request from one of these queues as follows:

Request Type | Routine | NotificationType Parameter of Routine
device request | StreamClassDeviceNotification | ReadyForNextDeviceRequest
stream control request | StreamClassStreamNotification | ReadyForNextStreamControlRequest
stream data request | StreamClassStreamNotification | ReadyForNextStreamDataRequest

When the class driver calls StrMiniReceiveXXXPacket, it hands off the stream request block to the minidriver. The minidriver's routine has sole access to the stream request block until it signals to the class driver it has completed the request.

When the minidriver finishes processing a request, it should signal the class driver it has completed the request as follows:

  1. The minidriver should set the status of the request in the Status field of the stream request block.
  2. The minidriver should signal it has completed the request, by calling StreamClassDeviceNotification or StreamClassStreamNotification. To complete a device request, the minidriver calls StreamClassDeviceNotification with a NotificationType parameter of DeviceRequestComplete. To complete a stream request, the minidriver calls StreamClassStreamNotification with a NotificationType parameter of StreamRequestComplete.
  3. If the class driver is handling synchronization, and if the minidriver has not yet signaled the class driver that it is ready for another request on this queue, it should do so now.

The minidriver can combine 2 and 3 by calling StreamClassCompleteRequestAndMarkQueueReady.

The minidriver processes requests asynchronously, so the class driver may need to cancel or time out a request. For these purposes, the minidriver must provide a StrMiniCancelPacket and a StrMiniRequestTimeout routine. The class driver will call the respective minidriver routine when it cancels or times out a request.

The class driver cancels a request when the underlying I/O request is cancelled by the operating system. The class driver times out requests that take too long to process — it decrements a counter of how many seconds until it times out a request in the TimeoutCounter member of the stream request block. If the minidriver needs to defer processing on a request for a long period of time, it should set the TimeoutCounter member to zero — the class driver will then not time out the request. Once the minidriver resumes processing of the request, it should reset TimeoutCounter to be equal to the TimeoutOriginal member of the stream request block. The minidriver can reset TimeoutOriginal to change the length of time before the request times out. See HW_STREAM_REQUEST_BLOCK for details.


Minidriver Initialization

When the operating system first initializes the minidriver, it calls the minidriver's DriverEntry routine. See DriverEntry for Stream Class Minidrivers. The minidriver must register itself with the class driver by calling StreamClassRegisterMinidriver.

The minidriver passes an HW_INITIALIZATION_DATA structure, which provides the class driver with preliminary information, including the device-wide callbacks, StrMiniReceiveDevicePacket, StrMiniCancelPacket, StrMiniRequestTimeout, and StrMiniInterrupt.

The class driver then uses StrMiniReceiveDevicePacket to signal the minidriver that it should initialize the device. It sends the SRB_INITIALIZE_DEVICE request, and passes a PORT_CONFIGURATION_INFORMATION structure with the needed hardware information. When completing this request, the minidriver supplies the size in bytes of the HW_STREAM_DESCRIPTOR structure it will use to describe all of its streams.

Once the minidriver completes that request, the class driver uses StrMiniReceiveDevicePacket to send the SRB_GET_STREAM_INFO request. The minidriver then supplies information on all of its streams, including each stream's callbacks.

Once the class driver finishes processing the stream data, it uses StrMiniReceiveDevicePacket to send the SRB_INITIALIZATION_COMPLETE request. At this point, the minidriver is ready to start handling requests on each stream.


Minidriver Flow of Control

The following set of steps is typically followed in initializing, using, and uninitializing streaming minidrivers. The following referenced commands and structures are described elsewhere in this documentation.

The steps followed in initializing, using, and uninitializing streaming minidrivers are

  1. The hardware adapter supported by the minidriver is detected by the Plug and Play enumerator. The enumerator checks the registry to resolve any symbolic references and passes the request to the I/O subsystem.
  2. The I/O subsystem loads the minidriver and calls the minidriver's DriverEntry routine (see DriverEntry for Stream Class Minidrivers) where a HW_INITIALIZATION_DATA structure is allocated and initialized. A file object is created from the information in the DriverEntry routine.
  3. The minidriver's DriverEntry routine then calls the stream class driver's StreamClassRegisterMinidriver function and passes the HW_INITIALIZATION_DATA structure as a parameter. The HW_INITIALIZATION_DATA structure includes the addresses of minidriver functions that handle SRBs. This allows the minidriver to respond to SRBs sent by the class driver.
  4. During initialization, the stream class driver calls the function specified in the HW_INITIALIZATION_DATA structure's HwReceivePacket member (see StrMiniReceiveDevicePacket) with and SRB with the Command member set to SRB_INITIALIZE_DEVICE. The minidriver then initializes the hardware adapter.
  5. The stream class driver calls the function specified in the HW_INITIALIZATION_DATA structure's HwReceivePacket member with SRB_GET_STREAM_INFO. The minidriver then returns information on the streams it supports.
  6. The stream class driver calls the function specified in the HW_INITIALIZATION_DATA structure's HwReceivePacket member with SRB_OPEN_STREAM, with a HW_STREAM_OBJECT structure. The minidriver performs the necessary hardware action to open the specified stream.
  7. The stream class driver sends or requests data from the stream by passing a SRB_READ_DATA or SRB_WRITE_DATA command to the function specified in the ReceiveDataPacket member of the HW_STREAM_OBJECT structure for the stream.
  8. The stream class driver gets and sets properties and other control information for the stream by passing the appropriate stream request block (HW_STREAM_REQUEST_BLOCK) to the function specified in the ReceiveControlPacket member of the HW_STREAM_OBJECT structure for the stream.
  9. When the system is through using a stream, the stream class driver calls the function specified in the HW_INITIALIZATION_DATA structure's HwReceivePacket member with SRB_CLOSE_STREAM. The minidriver then closes the specified stream.
  10. When it is time to uninitialize the adapter, the stream class driver calls the function specified in the HW_INITIALIZATION_DATA structure's HwReceivePacket member with SRB_UNINITIALIZE_DEVICE. The minidriver then uninitializes the device.


DriverEntry for Stream Class Minidrivers

DriverEntry initializes a stream class minidriver. This routine is required.

ULONG
  DriverEntry(
    IN PVOID  Argument1,
    IN PVOID  Argument2
    );

Parameters

Argument1

Supplies a context value with which the adapter minidriver should call StreamClassRegisterMinidriver. For Windows® 2000 and later, this points to a DRIVER_OBJECT.

Argument2

Supplies a second context value with which the adapter minidriver should call StreamClassRegisterMinidriver. For Windows 2000 and later, this points to a registry path.

Return Value

DriverEntry returns the value returned by its call to StreamClassRegisterMinidriver.

Comments

DriverEntry is the initial entry point for a stream class minidriver.

Since StreamClassRegisterMinidriver performs most of the required driver initialization, the primary task of a stream class minidriver's DriverEntry routine is to allocate and fill in a HW_INITIALIZATION_DATA structure with driver-specific constants and entry points. The DriverEntry should then call StreamClassRegisterMinidriver.

See Also

StreamClassRegisterMinidriver, HW_INITIALIZATION_DATA, Writing a DriverEntry Routine


Supporting Multiple Streams

The minidriver describes the streams it supports in its StrMiniReceiveDevicePacket routine, in response to a SRB_GET_STREAM_INFO request. The CommandData.StreamBuffer points to the HW_STREAM_DESCRIPTOR structure the minidriver should fill in with a description of the streams it supports.

The HW_STREAM_DESCRIPTOR structure begins with a HW_STREAM_HEADER structure, which describes the number of streams the minidriver supports. It is followed by an array of HW_STREAM_INFORMATION structures, each of which describes an individual stream. The class driver uses each HW_STREAM_INFORMATION to handle the KSPROPSETID_Pin property set – the index within the array serves as the pin type ID.

For most minidrivers, the data in the HW_STREAM_DESCRIPTOR is fixed at compile-time. In that case, the minidriver can allocate the data structure statically.

The minidriver describes the topology of connections between its streams through the Topology member of HW_STREAM_HEADER. The class drivers uses this structure to handle the KSPROPSETID_Topology property set for the minidriver.


Data Formats and Data Ranges in Streaming Minidrivers

Each stream details the data ranges it supports in the StreamFormatsArray member of its HW_STREAM_INFORMATION structure.


Supporting Property Sets

Both the minidriver as a whole and individual streams can receive property requests. The minidriver supplies the property sets it supports in the DevicePropertiesArray of HW_STREAM_HEADER. Each stream supplies the property sets it supports in the StreamPropertiesArray of the HW_STREAM_INFORMATION structure for that stream.

The minidriver defines a property set it handles through the KSPROPERTY_SET data structure, which in turn points to the array of KSPROPERTY_ITEM structures, one for each property in the property set. If the GetSupported member of KSPROPERTY_ITEM is TRUE, the minidriver supports getting the property data. If the SetSupported member of KSPROPERTY_ITEM is TRUE, the minidriver supports setting the property data.

Most property support requests are handled automatically by the class driver, using information the minidriver provides in the KSPROPERTY_ITEM structure for the property. For example, if the class driver receives a KSPROPERTY_TYPE_BASICSUPPORT request, it looks up the data type and value ranges in the Values member of KSPROPERTY_ITEM. See KSPROPERTY_ITEM for details. If the minidriver needs to perform custom processing of a support request (which is rare), it may set the SupportHandler member of KSPROPERTY_ITEM to TRUE. The class driver will then handle the support request as if it were a property get request. The minidriver can determine the actual type of the request from the Flags member of the property identifier.

The class driver gets or sets minidriver properties by passing a SRB_GET_DEVICE_PROPERTY or SRB_SET_DEVICE_PROPERTY request to the minidriver's StrMiniReceiveDevicePacket routine. The class driver gets or sets stream properties by passing a SRB_GET_STREAM_PROPERTY or SRB_SET_STREAM_PROPERTY request to the stream's StrMiniReceiveStreamControlPacket routine.

The class driver handles many properties on behalf of the minidriver, with an occasional assist from the minidriver through one of the minidriver's callbacks. The minidriver does not define these properties in its property set arrays. For an explanation of how the class driver handles the KSPROPSETID_Pin and KSPROPSETID_Topology property sets, see Supporting Multiple Streams.


Handling Events

Minidrivers may support event sets. Both the device as a whole and individual streams can receive requests to enable or disable events. The class driver handles event enable and disable requests. It queues each enabled event, with a separate queue for each stream, and for the device. If an event is disabled, the class driver deletes it from the queue. Note that the class driver queues each enabled event, whether or not the minidriver does its own synchronization.

The minidriver supplies the event sets it supports in the DeviceEventsArray member of the HW_STREAM_HEADER structure. Each stream supplies the event sets it supports in the StreamEventsArray of the HW_STREAM_INFORMATION structure for that stream.

The minidriver defines an event set it handles through the KSEVENT_SET data structure, which in turn points to the array of KSEVENT_ITEM structures, one for each event in the event set.

The minidriver provides a StrMiniEvent callback routine for each stream that can receive event requests, as well as a callback for the device itself, if it can receive event requests. If the StrMiniEvent routine returns a status code other than SUCCESS, the class driver will not queue the event.

When a client makes an event enable request, it passes a KSEVENTDATA structure, which describes how the event should be signaled once it occurs, optionally followed by event-specific parameters. When the class driver receives the request, it builds a KSEVENT_ENTRY structure to describe how the event should be triggered. It queues the KSEVENT_ENTRY structures for each event. The minidriver can use the StreamClassGetNextEvent routine to examine the event queue.

When the event actually occurs, the minidriver signals the class driver by calling either StreamClassDeviceNotification or StreamClassStreamNotification. The minidriver can signal events in several different ways: it can signal that a specific event has occurred, or it can signal that all events of a specific type has occurred. See StreamClassDeviceNotification or StreamClassStreamNotification for details.

The class driver can parse a KSEVENTDATA structure to create its KSEVENT_ENTRY structure, but it cannot do the same for any event-specific parameters that follow it in the original request. The minidriver can allocate additional space after the KSEVENT_ENTRY structure for a specific type of event, by providing a non-zero value for the ExtraEntryData member of the KSEVENT_ITEM it used to declare the event. When StrMiniEvent is called for that type of event, it should store any event-specific parameters from KSEVENTDATA in this memory.


Minidriver Synchronization

Streaming minidriver developers have the option of allowing the class driver to handle synchronization. When minidrivers register themselves with the class driver, they can opt for class-driver-provided synchronization by setting the TurnOffSynchronization member of HW_INITIALIZATION_DATA to FALSE.

When the class driver handles synchronization, it ensures that two pieces of the minidriver code are never executed simultaneously. The class driver queues all stream requests, and passes them to the minidriver one at a time.

One purpose of this synchronization is to spare the minidriver writer from having to deal with all the details of driver synchronization and request queuing in a multitasking, re-entrant, multiprocessor environment. However, some minidrivers should not use it. Two examples are provided in the Synchronization Examples topic that illustrate what a minidriver needs to do concerning synchronization.

Turning stream class synchronization off means that all requests are immediately and asynchronously called down to the minidriver in the context of the submitting thread at PASSIVE_LEVEL. Exceptions to the preceding rule are HwCancelPacket, TimeoutHandler, and Timer routines. These are are called at DISPATCH_LEVEL. A final exception is the interrupt handler, which is called at DIRQL.

When synchronization is off, the minidriver is responsible for performing synchronization in compliance with the WDM model. If a minidriver is called back at passive level, it can then be preempted by any higher IRQL events such as DPC's or interrupts. Similarly, if a minidriver is called back at DPC, it can subsequently be preempted by interrupts. Minidriver functions that manipulate shared resources must synchronize the accesses.

Multiple requests can be simultaneously issued to the same or different streams when stream class synchronization is off. The minidriver must queue its own requests and handle any hardware synchronization with other threads and the ISR. Spin locks, mutexes, and KeSynchronizeExecution are some of the synchronization objects available to stream minidrivers running without stream class synchronization.


Synchronization Examples

The following examples illustrate what a minidriver needs to do regarding synchronization and includes examples of when synchronization should not be used:

  • Example One: Minidriver With A Functioning ISR

    If stream class synchronization is turned on, all minidriver entry points are called at raised IRQL, using KeSynchronizeExecution, which means that the IRQ level of the adapter and all lower IRQ levels are masked when the minidriver is executing its code. Therefore, it is imperative that the minidriver does only a small amount of work in this mode.

    The minidriver should not run code that typically takes more than 10 to 20 microseconds at raised IRQL. If you use the debug build of stream.sys, the stream class will log the amount of time spent at raised IRQL and assert if the driver is spending too much time there. If the minidriver simply needs to program hardware DMA registers for a request, or just needs to read ports in its ISR, it is usually acceptable to do all of its processing at raised IRQL.

    If the minidriver needs to do processing that takes more than a few microseconds, such as a minidriver that transfers data through PIO, the minidriver should use StreamClassCallAtNewPriority to schedule a DISPATCH_LEVEL callback. In the callback, the minidriver can take up to around 1/2 to 1 millisecond to do its processing. One thing to remember when in this mode is that the DISPATCH_LEVEL callback is not synchronized with the ISR.

    This lack of synchronization is not a problem if the hardware remains stable when the minidriver accesses resources (for example, ports or a queue) during the callback as well as in the ISR. But if instability could be a problem, the minidriver must use StreamClassCallAtNewPriority to schedule a HIGH priority callback where the DISPATCH_LEVEL callback touches resources that are shared with the resources used by the ISR.

    Note that a HIGH priority callback is equivalent to calling KeSynchronizeExecution. KeSynchronizeExecution requires the minidriver to reference several parameters that StreamClassCallAtNewPriority does not, but in general the two result in the same behavior.

    If the minidriver only occasionally needs to run code that takes more than 1/2 to 1 millisecond, or occasionally needs to call services at PASSIVE_LEVEL (such as at initialization time), then setting StreamClassCallAtNewPriority to LOW priority can be used to acquire a PASSIVE_LEVEL worker thread. Note that a low-priority callback is not synchronized with anything and that the minidriver could receive new requests (assuming ReadyForNextRequest NotificationType parameter is pending) or an ISR call when running a low priority callback.

  • Example Two: Minidriver Without An ISR

    If stream class synchronization is turned on, the minidriver's entry points are all called at DISPATCH_LEVEL. The minidriver can do processing of up to around 1/2 to 1 millisecond duration without needing to adjust priority. If the minidriver only occasionally needs to run code that takes more than 1/2 millisecond, or occasionally needs to call services at PASSIVE_LEVEL (such as at initialization time), then StreamClassCallAtNewPriority with LOW priority can be used to acquire a PASSIVE_LEVEL worker thread. Note that a low-priority callback is not synchronized with anything and the minidriver could receive new requests (assuming ReadyForNextRequest NotificationType parameter is pending) when running a low-priority callback.

  • When Stream Class Synchronization Should Not Be Used

    The following are examples of situations where stream class synchronization should not be used. These include:

    • When drivers frequently (more than about 20 percent of the requests the minidriver receives) need to do processing that takes more than 1 millisecond, or need to frequently call PASSIVE_LEVEL services, such as Microsoft DirectDraw® services. When using the debug version of stream.sys, stream class will assert both of these cases and halt if they are detected with synchronization turned on.
    • When the minidriver is a filter with no associated hardware. Such a minidriver should be running at PASSIVE_LEVEL since there is no underlying hardware to synchronize with and the minidriver typically does a lot of processing. It is easier to do your own synchronization in this case than to waste overhead using stream class synchronization. If necessary, use mutexes to protect your queues.

      Bugs in synchronization code can often be difficult to find, and in certain environments (such as NT-based operating systems running on multiprocessor systems) bugs may show up only after many hours of stress. Based on experience with vendors, these are not the kinds of things that most vendors have the capability or desire to debug. Only driver writers familiar with writing fully asynchronous WDM device drivers should attempt to do their own synchronization.

    • When the minidriver is a bus-on-bus type driver (for example, a USB or 1394 peripheral driver) that does not really worry about synchronization of the actual hardware, but just calls requests down to the next layer at PASSIVE_LEVEL and receives callbacks typically at DISPATCH_LEVEL.


Notes on Writing Stream Class Minidrivers

  • Minidrivers must run on both Intel and non-Intel x86 processors, and therefore must be written in C (or other high-level language). Minidrivers should not contain assembly language source code.
  • Some hardware requires firmware to be loaded before it will function. Minidrivers should embed firmware in the data segment of the minidriver. Optionally, the minidriver can dynamically load its firmware by calling the appropriate WDM file I/O functions, if, for example, the minidriver uses several versions of firmware that would make embedding it impractical.
  • Turn off synchronization (by setting the TurnOffSynchronization member in the HW_INITIALIZATION_DATA structure to TRUE) if the minidriver needs to go to PASSIVE_LEVEL (low priority) for most requests. See the Minidriver Synchronization section for more information on synchronization.
  • Hardware resources (port or memory addresses) should be accessed through the macros found in wdm.h. For example, to write to a word port, the macro WRITE_PORT_USHORT should be used. To write a buffer to a port, WRITE_PORT_BUFFER_USHORT should be used.
  • Minidrivers should not have unprotected spin loops. If the minidriver needs to spin while waiting for the value of a port to change, the loop must be protected by a loop counter.
  • Minidrivers that need to synchronously wait for a small period of time should use KeStallExecutionProcessor. This routine should be used sparingly so system performance is not degraded.
  • Minidrivers that need to wait a long period of time (more than a few microseconds) for an operation to complete should either be interrupt-driven or use the StreamClassScheduleTimer function to schedule a timed callback. Minidrivers should not spin for more than a few microseconds waiting for a status change, since it degrades overall system performance.
  • Devices that use bus master DMA need only to use the scatter/gather DMA list supplied in the stream request block structure (HW_STREAM_REQUEST_BLOCK). No locking or mapping of the DMA buffers is necessary. See the HW_STREAM_REQUEST_BLOCK structure for more information. Additionally, if minidrivers need to break up DMA requests, the StreamClassGetPhysicalAddress function can be used to get the physical address of the offset within the virtual buffer pointers.


Stream Class Debugging

Use the checked (debug) version of stream.sys to print out informative messages about the status of the minidriver and ASSERT when errors in the minidriver are encountered.

The following, additional tips can be used when debugging stream class minidrivers:

  • When debugging with the wdeb386 debugger (or with Softice) on Windows Me systems, debugging information is available by breaking into the debugger, typing .NTKERN, and then selecting option D. This displays the debug log, which shows entries in chronological order. When debugging with Windows® 2000, the debug information is printed to the debug terminal in real time.
  • To adjust the output level of the debugger, load stream.sys symbols (stream.sym for Windows Me and stream.sys for Windows 2000) and modify the StreamDebug variable with "e StreamDebug xx". The default is 00, which prints only severe errors. Set it to FF to print all messages.
  • Minidrivers can print their own messages, using stream.sys facilities previously described, by calling StreamClassDebugPrint. Note that the output level as previously described must be set to be greater than or equal to the output level chosen in the call.


WDM Audio Driver Design Guide

Kernel Streaming (KS) services support kernel-mode processing of data streams for audio and for other types of continuous media (see Kernel Streaming Overview). Conceptually, a stream undergoes processing as it flows along a data path that contains some number of processing nodes. A set of related nodes is grouped together to form a KS filter, which represents a more-or-less independent block of stream-processing functionality. More complex functions can be constructed in a modular way by cascading several filters together to form a filter graph.

KS filters are connected together through their pins. A pin on an audio filter can be thought of as an audio jack. The output pin of the upstream filter is connected to the input pin of the downstream filter. The data stream from the output pin must have a data format that the input pin can accept. Data buffering is typically required to smooth out momentary mismatches in the rates at which an output pin produces data and an input pin consumes it.

A KS filter is implemented as a kernel-mode driver object that encapsulates some number of related stream-processing functions. The functionality can be implemented in software or in hardware. In this model, an audio adapter can be viewed as a collection of hardware devices, and the adapter driver exposes each of these devices to the audio system as an individual filter.

An adapter driver exposes a collection of filter factories to the audio system. Each filter factory is capable of instantiating filters of a particular type. If the adapter contains one or more devices that are similar or identical in function, the driver groups the filters for those devices together into the same filter factory. If the adapter contains several different types of devices, those devices are presented through several different filter factories.

A KS filter exposes a collection of pin factories to the audio system. Each pin factory is capable of instantiating pins of a particular type. If the filter can provide one or more pins that are similar or identical in function, the filter groups those pins together into the same pin factory. For example, a filter that performs audio mixing might have one pin factory that can instantiate a single output pin and a second pin factory that can instantiate several input pins.

SysAudio is the system graph builder (see SysAudio System Driver). SysAudio constructs audio filter graphs for applications that use Microsoft® DirectSound® and Windows® Multimedia APIs such as waveOut.

Because SysAudio instantiates an input or output pin on a filter only when it routes a data stream into or out of that filter, the number of streams that enter and exit a filter are, in most cases, the same as the number of input and output pins, respectively. In some contexts, the terms pin and stream can be used interchangeably.

KS services are built upon the Windows Driver Model. Note that the term KS filter must be carefully distinguished from the term filter driver, which is another WDM concept. A filter driver resides in a WDM driver stack and can intercept and modify the IRPs (I/O request packets) that propagate through the stack. Upper- and lower-level filter drivers reside above and below the function driver, respectively. In this chapter, the term filter refers to a KS filter rather than a filter driver unless noted otherwise. For more information about filter drivers, see Types of WDM Drivers.

A WDM audio driver provides the following functionality:

  • The driver exposes all the types of input and output streams that it can support and also the number of instances of each stream that it can support. The driver exposes this information in the form of a set of pin factories and the number of pins that each factory can instantiate. For example, a typical audio device might provide a KS filter that can input a single PCM audio stream and output a single PCM audio stream. The driver might support only a single instance of a filter with these capabilities.
  • The driver supports one or more property sets. For example, all audio drivers should support KSPROPSETID_Audio, but some audio drivers might support additional property sets as well. Clients of the driver use property requests both to discover a filter's capabilities and to change the filter's configurable settings.
  • The driver optionally supports a hardware clock. This clock should be readable and writable so that streams can synchronize with other streams on the same or different hardware. For additional information, see KSPROPSETID_Clock.
  • The driver optionally supports other media interfaces. For example, the driver might support KSINTERFACE_STANDARD_STREAMING, KSINTERFACE_MEDIA_WAVE_QUEUED, or KSINTERFACE_STANDARD_LOOPED_STREAMING (see Interface Sets).

Note that the KsStudio utility (ksstudio.exe) is included with the DDK tools. The KsStudio utility can be used to build, examine, and test WDM KS filter graphs on Windows 98/Me, and Windows 2000 and later. Although KsStudio is designed primarily for audio filter graphs, it can be used to build and explore graphs for any WDM KS filters. See the documentation for the KsStudio utility in the Windows DDK.

This chapter contains the following sections:

WDM Audio Architecture

Audio Streams: Data Formats and Data Ranges

WDM Audio Platform Differences

DirectSound Hardware Acceleration in WDM Audio

DirectSound Speaker-Configuration Settings

DirectSound Capture Effects

Supporting Non-PCM Wave Formats

KMixer Driver Sample Rate Conversion and Mixing Policy

Factors Governing Wave-Output Latency

Digital Rights Management

GFX Filters

WDM Audio Extensions to Legacy Windows Multimedia APIs

Multifunction Audio Devices

System-Wide Unique Device IDs


WDM Audio Architecture

This section includes the following topics about the WDM audio architecture:

Audio Filters, Pins, and Nodes

WDM Audio Components

Typical Audio Configurations

Vendor Audio Driver Options

DDK Audio Driver Samples

See the following for more information about the WDM audio architecture:

www.microsoft.com/hwdev/audio

Introduction to Port Class

WDM Audio Platform Differences


Audio Filters, Pins, and Nodes

A WDM adapter driver exposes its audio hardware as a collection of filter factories, each of which can create one or more filter instances. A KS (kernel streaming) filter object can encapsulate an audio hardware function that performs some type of digital processing of the audio wave data that streams through the filter. For example, the filter might do rendering or synthesis of a stream, or it might add reverb to a stream.

A filter instance exposes pin factories, each of which can create one or more pin instances. These pins can be connected to the pins of other filters to produce filter graphs. To be part of an audio filter graph, a filter must have one or more pin instances.

A pin represents an input or output connection point through which a data stream enters or exits the filter. Each pin specifies the range of data formats that it can support, and only a stream with a compatible format can flow through the pin.

A filter for a WDM audio device exposes its internal topology in the form of nodes and connections.

Topology nodes lie on the data paths that pass through the filter. A node represents a point of control within the filter. Each node logically encapsulates a modular chunk of the filter's functionality and performs digital-signal processing on the data stream that passes through the node. A node might represent a volume control, for example, that can be adjusted under software control.

The filter object also specifies the connections between its various pins and nodes. Implicit in these connections is the ordering of nodes along each data path through the filter.

This section presents the features of filters, pins, and nodes that are specific to WDM audio drivers. The following topics are discussed:

Audio Filters

Filter Factories

Pin Factories

Nodes and Connections

Audio Filter Graphs

Topology Filters

Virtual Audio Devices

Properties of Audio Filters, Pins, and Nodes

Audio Stream Data Formats

Hardware Events

For a more general discussion of kernel-streaming filters, pins, and nodes, see KS Filters, Pins and Node Topology.


Audio Filters

In the figure below, the box in the middle is a KS filter that represents an audio device. A KS filter is a kernel object and is identified by a kernel object handle. The data stream flows into the filter from the left, passes through a couple of nodes for processing, and exits the filter on the right. The filter is created by a filter factory, which is shown as a box with dashed edges at the bottom of the filter.

KS Filter with Two Nodes

In the figure, two pins are instantiated on the filter. The pin on the left is a data sink, which means that data flows into the filter through the pin. Data flows out of the filter through the pin on the right, which is a data source. By convention, usage of the terms source and sink in KS is filter-centric.

In contrast, the mixer API's terminology for SRC and DST (source and destination) mixer lines is graph-centric:

  • The stream enters a mixer device through the SRC mixer line.
  • The stream exits a mixer device through the DST mixer line.

In other words, a SRC mixer line maps to a data-sink pin on a KS filter, and a DST mixer line maps to a data-source pin. For more information, see Kernel Streaming Topology to Audio Mixer API Translation.

For the sake of simplicity, the figure omits the filter's pin factories, which create the pin instances.

In addition to being data sinks and data sources, pins and filters can also be IRP sinks and IRP sources. In other words, pins and filters can not only receive IRPs—they can send IRPs as well. The three dark arrows in the figure represent IRPs. The pin on the left side of the figure is an IRP sink. The pin on the right is an IRP source. The figure also shows an IRP being sent to the filter object itself.


Filter Factories

An audio adapter driver provides filter factories to manage the instantiation of filters. Each filter factory can instantiate one or more KS filters of a particular type. If a filter type encapsulates a particular hardware function, the number of filters of that type that the factory can instantiate is limited by the underlying hardware resources.

Because a filter factory manages a largely autonomous block of hardware functionality, each filter factory can be considered to be a device driver in its own right. In fact, the term adapter driver, as it is used above, refers to a collection of related drivers—filter factories—that are packaged together to manage the various hardware functions on an adapter card.

As with any other WDM driver, a filter factory provides a DriverEntry routine and handles power management and setup functionality. During installation, the INF file for the driver registers one or more filter device names (see Device Identification Strings). These names are entered into the registry, where each filter is associated with one or more KS filter categories, as described in Installing Device Interfaces for an Audio Adapter. All audio devices are classified under KSCATEGORY_AUDIO, but an audio device might also be classified under additional categories such as KSCATEGORY_RENDER (for an audio rendering device) or KSCATEGORY_SYNTHESIZER (for a synthesizer). The KS categories that the filters are registered under are meant to advertise the general functionality of the filter.

The operating system uses the Setup API (see Device Installation Components) to discover and enumerate all the KSCATEGORY_AUDIO filter factories in the registry. The registry entry for each factory specifies both the filter factory's friendly name and its device name, which is a long string that a client passes to the create-file call that instantiates the filter. This call might be made to ZwCreateFile from kernel mode or to CreateFile (see Platform SDK documentation) from user mode. A filter is a kernel-mode object and is identified by a kernel handle. The create-file call returns an instance handle that clients can use to refer to the filter. User-mode clients or upstream filters in the audio graph can use this handle to send or forward IOCTL requests to the filter.

A typical WDM audio adapter might reside on a PCI bus, for example, and contain several audio ports that render or capture wave data. A single device might contain audio-out ports for driving speakers, lineout jacks, and so on, and also audio-in ports to input signals from microphones, linein jacks, and so on. These audio ports are represented as wave filters.

The driver that implements a wave filter for an audio port is a combination of the following:

  • Proprietary code that is hardware-specific
  • Generic code that is common to all filters of the same type

The PortCls system driver (portcls.sys) implements the generic portion of the port driver, which it exposes to the adapter driver through system calls and COM interfaces. This makes the task of writing a driver for a proprietary device much easier.

A hardware vendor is required to write only the miniport driver, which contains all the hardware-specific code for the filter. When a filter factory instantiates a filter, it first creates the miniport driver for the filter. The miniport driver then creates and binds itself to the appropriate port driver in order to form a fully functioning filter. The port and miniport drivers communicate with each other through well-defined software interfaces (see Miniport Interfaces and Supporting a Device).

To get to the filter's pin factories, nodes, and connections, the client queries the filter for its miniport interface and calls the GetDescription method on that interface. The GetDescription call retrieves a PCFILTER_DESCRIPTOR structure that contains arrays of descriptors for the filter's pin factories, nodes, and connections. The descriptor types are:

PCPIN_DESCRIPTOR

PCNODE_DESCRIPTOR

PCCONNECTION_DESCRIPTOR

For an example of how a driver sets up its PCFILTER_DESCRIPTOR structure, see the header file table.h in the SB16 sample audio driver in the DDK.


Pin Factories

Pin factories are essentially descriptions of the pins that can be created on a filter. A filter instance for an audio wave device is implemented by a miniport driver, which contains all of the hardware-specific code and data for the filter, and a port driver, which implements the generic filter functionality and is available from the PortCls system driver.

The miniport driver stores pin information in an array of PCPIN_DESCRIPTOR structures that describe the pins that can be created on the filter. Each structure specifies a pin factory, and a pin factory is identified by its index in the array.

Each pin factory contains an array of KSPIN_DESCRIPTOR structures. Each of these structures describes a particular pin. The structure contains the following information:

  • Filter-relative direction of data flow
  • Filter-relative direction of communication flow (In all current Windows versions, KS filters use IRPs for communication.)
  • Pin category
  • Friendly name
  • Instance capabilities
  • Data-format capabilities

A pin factory specifies the data formats that it supports by providing an array of KSDATARANGE structures. Before connecting a sink pin on one filter to a source pin on another filter, a client can search the data ranges for a compatible format. The client or graph-builder can also call the filter's data-intersection handler, which essentially asks the filter itself to find a compatible format (see Data-Intersection Handlers).

A filter can have multiple pin factories, and a pin factory can support multiple pin instances. Having multiple pin factories on a filter is useful for distinguishing separate data paths for the different types of data that flow through the filter. For example, one pin factory might support PCM data streams, and another pin factory might support AC3 streams. Having multiple pin instances on a pin factory typically implies mixing, in which case the filter contains a SUM node (see KSNODETYPE_SUM).

Like filters, pins are real kernel objects and are identified by kernel handles. The handle for a pin instance is created by calling KsCreatePin. As a kernel object, a pin can be specified as the target of an IRP. A client of the driver specifies the pin handle when sending an IOCTL request to a pin.

When constructing an audio filter graph, the SysAudio system driver links one filter to another by connecting their pins. A source pin from one filter can be connected to the sink pin of another filter. Data and IRPs from the source pin flow into the sink pin through this connection. To make the connection, a client (typically SysAudio) first creates the source pin by calling KsCreatePin and then creates the sink pin by calling KsCreatePin again. In the second call, however, the client specifies that the new sink pin is to be connected to the source pin that was created in the first call.


Nodes and Connections

The filter provides a description of its topology nodes in the form of an array of node descriptors (see PCNODE_DESCRIPTOR). Each descriptor in the array describes a single node and contains a GUID that specifies the node type (for example, KSNODETYPE_REVERB). For a list of the standard node types that are defined for audio devices, see Audio Topology Nodes.

The filter identifies each of its nodes by the node's index in the descriptor array. For example, when sending a node-specific property request to a filter or to a particular pin on a filter, a client includes the node ID (the array index) in the request in order to identify the target node.

The filter provides a description of its internal connections in the form of an array of connection descriptors (see PCCONNECTION_DESCRIPTOR). Each descriptor describes one of the filter's internal connections. A descriptor can describe a connection between a pin and a node, a connection between two nodes, or a pass-through pin-to-pin connection.

The nodes and connections that the filter exposes together define the filter's internal topology. The topology is a map of the audio device's internal layout and should accurately reflect the organization of the hardware that it represents. The Windows Multimedia mixer API, for example, translates the filter's internal connections into mixer lines and its nodes into controls on the mixer lines (see Kernel Streaming Topology to Audio Mixer API Translation). Any inaccuracies in the filter's internal topology are reflected in the mixer-line representation and may cause errors or unexpected behavior in an application that uses the mixer API.


Audio Filter Graphs

An audio filter graph is a collection of audio filters that have been connected together to process one or more audio data streams. For example, the figure below is a simplified diagram of a graph that performs audio rendering and capture.

Simple Filter Graph for Rendering and Capture

The port/miniport wave filter represents a hardware function in an audio adapter.

On the left side of the figure, the audio stream from a DirectSound or waveOut application (top) plays through a speaker (bottom). On the right side, a DirectSound or waveIn application (top) records the stream that is input from a microphone (bottom). In both cases, an instance of the KMixer system mixer is interposed between the wave filter and the application.

KMixer is a versatile software filter that can readily convert between a variety of audio formats and sample rates at its source and sink pins. KMixer can typically accommodate the differences between the stream format that the hardware is configured for and the stream format that the application expects.

At the bottom of the figure, the source pin that drives the speaker and the sink pin that receives the microphone signal are both labeled as bridge pins. A bridge pin represents a hardwired connection at the start or end point of an audio stream. One distinguishing characteristic of a bridge pin is that you cannot send IRPs to it. The signal that enters or leaves a bridge pin can be either analog or digital. In this example, the bridge pin on the left transmits the output signal from a DAC (digital-to-analog converter), which drives a speaker. The bridge pin on the right receives the signal from a microphone, which enters an ADC (analog-to-digital converter).


Topology Filters

A topology filter is essentially an analog mixer. It represents the portion of an audio adapter's hardware that performs analog processing and mixing. The pins on a topology filter are analog inputs and outputs. These pins represent physical connections to either of the following:

  • Speaker, microphone, linein, and lineout jacks. These are examples of the bridge pins that are described in Audio Filter Graphs.
  • Other hardware devices on the same adapter card that process audio streams with wave and MIDI formats. The adapter driver represents these other devices as separate wave and MIDI filters.

The adapter driver creates a topology filter by binding its proprietary topology miniport with a topology port that the PortCls system driver creates. The miniport object exposes an IMiniportTopology interface, and the port object exposes a IPortTopology interface.

In spite of its name, a topology filter is only one of several types of filter that expose their internal topology or layout. For example, a typical WaveCyclic or WavePci filter exposes a topology that consists of at least two pins and either a DAC (digital-to-analog converter) or ADC (analog-to-digital converter) depending on whether the underlying device does audio rendering or capture.

Similar to other types of audio filters, a topology filter uses an array of PCCONNECTION_DESCRIPTOR structures to describe its internal topology. The miniport exposes this array in the PCFILTER_DESCRIPTOR structure that it outputs from the IMiniport::GetDescription method. The array specifies the topology as a list of connections between the topology filter's nodes and pins (see Nodes and Connections). The WDMAud system driver translates these connections and nodes into the mixer lines and controls that the mixer API exposes to applications. As discussed in Audio Filters, an input pin on a KS filter maps to a SRC mixer line, and an output pin on a filter maps to a DST mixer line.

A typical audio adapter can play wave and MIDI files through a speaker, and can capture audio signals from a microphone and a MIDI synthesizer. The code example below contains the PCCONNECTION_DESCRIPTOR array for a topology filter that exposes these capabilities:

    // topology pins
    enum
    {
        KSPIN_TOPO_WAVEOUT_SRC = 0,
        KSPIN_TOPO_SYNTHOUT_SRC,
        KSPIN_TOPO_SYNTHIN_SRC,
        KSPIN_TOPO_MIC_SRC,
        KSPIN_TOPO_LINEOUT_DST,
        KSPIN_TOPO_WAVEIN_DST
    };

    // topology nodes
    enum
    {
        KSNODE_TOPO_WAVEOUT_VOLUME = 0,
        KSNODE_TOPO_WAVEOUT_MUTE,
        KSNODE_TOPO_SYNTHOUT_VOLUME,
        KSNODE_TOPO_SYNTHOUT_MUTE,
        KSNODE_TOPO_MIC_VOLUME,
        KSNODE_TOPO_SYNTHIN_VOLUME,
        KSNODE_TOPO_LINEOUT_MIX,
        KSNODE_TOPO_LINEOUT_VOLUME,
        KSNODE_TOPO_WAVEIN_MUX
    };

    static PCCONNECTION_DESCRIPTOR MiniportConnections[] =
    {
       // FromNode---------------------FromPin------------------ToNode-----------------------ToPin

        { PCFILTER_NODE,               KSPIN_TOPO_WAVEOUT_SRC,  KSNODE_TOPO_WAVEOUT_VOLUME,  1 },
        { KSNODE_TOPO_WAVEOUT_VOLUME,  0,                       KSNODE_TOPO_WAVEOUT_MUTE,    1 },
        { KSNODE_TOPO_WAVEOUT_MUTE,    0,                       KSNODE_TOPO_LINEOUT_MIX,     1 },

        { PCFILTER_NODE,               KSPIN_TOPO_SYNTHOUT_SRC, KSNODE_TOPO_SYNTHOUT_VOLUME, 1 },
        { KSNODE_TOPO_SYNTHOUT_VOLUME, 0,                       KSNODE_TOPO_SYNTHOUT_MUTE,   1 },
        { KSNODE_TOPO_SYNTHOUT_MUTE,   0,                       KSNODE_TOPO_LINEOUT_MIX,     2 },

        { PCFILTER_NODE,               KSPIN_TOPO_SYNTHIN_SRC,  KSNODE_TOPO_SYNTHIN_VOLUME,  1 },
        { KSNODE_TOPO_SYNTHIN_VOLUME,  0,                       KSNODE_TOPO_WAVEIN_MUX,      1 },

        { PCFILTER_NODE,               KSPIN_TOPO_MIC_SRC,      KSNODE_TOPO_MIC_VOLUME,      1 },
        { KSNODE_TOPO_MIC_VOLUME,      0,                       KSNODE_TOPO_WAVEIN_MUX,      2 },

        { KSNODE_TOPO_LINEOUT_MIX,     0,                       KSNODE_TOPO_LINEOUT_VOLUME,  1 },
        { KSNODE_TOPO_LINEOUT_VOLUME,  0,                 PCFILTER_NODE,  KSPIN_TOPO_LINEOUT_DST },

        { KSNODE_TOPO_WAVEIN_MUX,      0,                 PCFILTER_NODE,  KSPIN_TOPO_WAVEIN_DST }
    };

Constant PCFILTER_NODE above is the null node ID and is defined in header file portcls.h. For a description of how this constant is used to distinguish external pins on a filter from logical pins on a node, see PCCONNECTION_DESCRIPTOR.

Each pin name above ends with either "SRC" and "DST" depending on whether the mixer API maps the pin to a SRC or DST mixer line.

The PCCONNECTION_DESCRIPTOR array in the code example above describes the topology filter in the figure below.

Example: Topology Filter Connections Described by PCCONNECTION_DESCRIPTOR Array

The topology filter in the figure has four input (sink) pins on the left and two output (source) pins on the right. The data paths that connect the top two input pins and top output pin mix the two analog signals that have been rendered from the wave and MIDI streams that are being played back. The data paths that connect the bottom two input pins and bottom output pin multiplex the captured analog signals that are being recorded.

The four input pins operate as follows:

  • The KSPIN_TOPO_WAVEOUT_SRC pin is physically connected to the output pin of a wave filter, which renders a wave stream from a source such as a .wav file to produce the analog signal at the pin.
  • The KSPIN_TOPO_SYNTHOUT_SRC pin is physically connected to the output pin of a synth filter, which might render, for example, a MIDI stream from a source such as a .mid file to produce the analog signal at the pin.
  • The KSPIN_TOPO_SYNTHIN_SRC pin is physically connected to a synthesizer that generates an analog signal. (Note that a more practical hardware design might take a MIDI input stream from an MPU-401 MIDI interface and convert it directly to wave format, bypassing the topology filter altogether.)
  • The KSPIN_TOPO_MIC_SRC pin is physically connected to an input jack that takes an analog signal from a microphone.

The two output pins operate as follows:

  • The KSPIN_TOPO_LINEOUT_DST pin is physically connected to an analog lineout jack that typically drives a set of speakers.
  • The KSPIN_TOPO_WAVEIN_DST pin is physically connected to the input pin of a wave filter, which converts the analog signal to a wave stream and writes it to a destination such as a .wav file.

The volume and mute nodes (see KSNODETYPE_VOLUME and KSNODETYPE_MUTE) are used to control the volume levels of the various streams. The SUM node (see KSNODETYPE_SUM) mixes the audio streams from the wave and MIDI inputs. The MUX node (see KSNODETYPE_MUX) selects between the two input streams.

The figure uses a dashed arrow to indicate a connection between two nodes or between a pin and a node. The arrow points in the direction of data flow. The diagram shows a total of 13 connections, each of which corresponds to one of the 13 elements in the PCCONNECTION_DESCRIPTOR array in the code example above.

In addition to the topology filter, the adapter driver creates other filters—wave, FM synth, wave table, and so on—that connect to the pins on the topology filter.

For example, the wave filter that is physically connected to the topology filter's KSPIN_TOPO_WAVEOUT_SRC pin contains a DAC (represented by a KSNODETYPE_DAC node) that converts PCM data to the analog signal that it outputs to the topology filter's pin. The FM-synth or a wave-table synth filter that is physically connected to the topology filter's KSPIN_TOPO_SYNTHOUT_SRC pin similarly converts MIDI data to an analog signal that it outputs to the topology filter's pin. The topology filter mixes the analog signals from these two pins and outputs the mixed signal to the speakers.

Because the topology filter's inputs and outputs are all analog signals, however, not all filters that are created by the adapter driver are necessarily connected to the topology filter. For example, UART filters are not hooked to the topology filter because they send or receive raw digital MIDI data, which cannot be mixed with an analog audio signal. Similarly, wave filters that input or output S/PDIF streams typically do not connect to the topology filter's pins because they send or receive raw PCM data, which (like MIDI) cannot be mixed with an analog signal.

The topology filter's physical connections to other filters that represent other hardware devices on the same adapter card need to be distinguished from other types of connections to filters. For example, pins on some filters can be connected or disconnected under software control.

During device startup, the adapter driver registers the topology filter's physical connections by calling PcRegisterPhysicalConnection once per connection. The port needs this information in order to respond to KSPROPERTY_PIN_PHYSICALCONNECTION get-property requests.

See the sample audio adapter drivers in the Windows DDK for example implementations of miniports with the following interfaces:

IMiniportTopology

IMiniportWaveCyclic

IMiniportWavePci

IMiniportMidi

IMiniportDMus


Virtual Audio Devices

SysAudio, the system audio device, is the system driver that is responsible for building audio filter graphs for typical applications. SysAudio's clients include DirectSound and the WDMAud system driver, which serves as the interface between WDM audio drivers and the audio-specific Windows Multimedia APIs waveIn, waveOut, midiIn, midiOut, mixer, and aux (described in Platform SDK documentation).

The KsStudio.exe tool in the DDK is an example of an application that bypasses SysAudio and allows users to construct filter graphs manually.

Following PnP device enumeration, SysAudio takes stock of the registered audio hardware and software components in order to determine how to construct the various audio filter graphs that its clients might require.

After determining the list of filter graphs that it can build from the available hardware and software components, SysAudio registers these graphs as virtual audio devices for playback, recording, MIDI input/output, and mixing. SysAudio reserves the registry category KSCATEGORY_AUDIO_DEVICE exclusively for its virtual audio devices. Adapter drivers should not register themselves in this category.

A SysAudio client can treat a filter factory for a virtual audio device similarly to a filter factory for a hardware or software component. When asked by a client to instantiate a particular pin on a virtual device, SysAudio constructs the graph automatically and manages the graph's internal pin connections transparently to the client. This allows the client to treat a filter graph as a single filter, thereby avoiding complexities of graph management such as inter-filter communication.


Properties of Audio Filters, Pins, and Nodes

Clients of a WDM audio driver can send get- and set-property requests (KSPROPERTY_TYPE_GET and KSPROPERTY_TYPE_SET) to the filters and pins that the driver has instantiated. For information about sending IOCTL_KS_PROPERTY requests to filters and pins, see KS Properties.

WDM audio drivers support the four types of properties that are shown in the table below.

Property type | Target of property request
Filter property | Filter instance
Pin property | Pin instance
Filter node property | Filter instance + node ID
Pin node property | Pin instance + node ID

A filter property represents a capability or control-state setting that belongs to a filter instance. A set-property request for a filter property is sent to a particular filter instance and affects the state of that filter as a whole.

A pin property represents a capability or control-state setting that belongs to an individual pin (or equivalently, a data stream) instance on a filter. In general, a set-property request to a pin affects only the state of the target pin, not the filter as a whole. However, this rule is occasionally broken. For example, when the KSPROPERTY_AUDIO_CHANNEL_CONFIG property is set on one pin instance, it affects the channel configuration for the entire filter.

When sending a filter property request, the target filter is specified by its instance handle (see Filter Factories). Similarly, when sending a pin property request, the target pin is specified by its instance handle (see Pin Factories). Either type of request contains a KSPROPERTY structure that specifies the following:

  • A GUID that identifies the property set.
  • An index that identifies a property within the specified property set.
  • A flag that indicates the type of property request.

Related properties are gathered together to form a property set. A particular property is specified by its property set and by an index that identifies its position within that set.

Nodes can also have properties. A node property request contains a KSNODEPROPERTY structure, which has both an embedded KSPROPERTY structure and a node ID.

A filter node property is filter property that is also a node property. A filter node property request specifies the target node with both a filter handle and a node ID. Similarly, a pin node property is a pin property that is also a node property. A pin node property request specifies the target node with both a pin handle a node ID.

A filter can contain two or more nodes that have the same node ID. For example, in the case of a filter that performs mixing, the mixer inputs might all be instances of a sink pin from the same pin factory, and all of the pin instances can have volume nodes (see KSNODETYPE_VOLUME) that share the same node ID. A node on a particular data path is specified by the combination of a node ID and a pin instance handle.

A pin node property belongs to a node that is associated with a particular pin instance. In the case of a filter that contains a SUM or MUX node (see KSNODETYPE_SUM and KSNODETYPE_MUX), the following rules apply:

  • If the property belongs to a node that lies downstream from a sink (input) pin and upstream from the SUM or MUX node, the property request is sent to the sink pin.
  • If the property belongs to a node that lies downstream from a SUM or MUX node and upstream from a source (output) pin, the property request is sent to the source pin. (Also, a property request for a SUM or MUX node is sent to the source pin.)

With these conventions, a particular node on a particular data path can be identified uniquely.

In contrast, a filter node property represents the default value for a node property. When instantiating a pin, the driver sets the properties for the pin's nodes to their default values. A filter node set-property request changes the default value that is used for the specified property and node ID. The request has no effect on pins that have already been instantiated. It affects only future pin instantiations.

A miniport driver provides information about the properties that it supports in the form of an array of PCPROPERTY_ITEM structures. Each structure contains the following information about a property:

  • The property-set GUID and property ID (or index).
  • A function pointer to the handler routine for the property.
  • A set of flags that specify the property operations that the handler supports.

The property-item array is contained in the automation table within the PCFILTER_DESCRIPTOR structure that the filter factory outputs through its GetDescription method (see Filter Factories).

When specifying the data for a set-property request to a filter, pin, or node, the application program or kernel-mode client that sends the request needs to know the size of the data buffer that the driver expects for that property. The data size might be difficult to determine in advance because it can vary not only with the property, but also with the target filter, pin, or node, and with the particular device that implements the filter.

The driver's handler routine for a particular property should be able to provide this information in response to a basic-support property request (KSPROPERTY_TYPE_BASICSUPPORT). Clients expect drivers to follow these conventions when handling a basic-support request:

  • If the request specifies the value size as sizeof(ULONG) then the property handler should write sizeof(KSPROPERTY_DESCRIPTION) structure into the ULONG-sized data buffer.
  • If the request specifies the value size as sizeof(KSPROPERTY_DESCRIPTION), the handler should write a KSPROPERTY_DESCRIPTION structure into the data buffer. The handler sets the DescriptionSize field of the structure equal to that structure's size plus the size of all of the additional, property-specific information that the handler has available to load into the data buffer following the structure.
  • If the request specifies a value size that is large enough to contain both the KSPROPERTY_DESCRIPTION structure and the property-specific information, the handler should write the property-specific information into the portion of the data buffer that follows the end of the KSPROPERTY_DESCRIPTION structure. When writing the KSPROPERTY_DESCRIPTION structure, the handler should set the DescriptionSize field to that structure's size plus the size of the property-specific information that follows the structure.

The property-specific information that the handler writes into the data buffer typically includes data ranges for property values. For example, the basic-support request for a KSPROPERTY_AUDIO_VOLUMELEVEL property on a volume node retrieves the minimum and maximum volume settings for that node.

For coding examples, refer to the property-handler implementations in the sample audio-adapter drivers in the Windows DDK.


Audio Stream Data Formats

Several property requests provide information on the data formats that an audio device is capable of handling at its input and output pins.

The audio-stream data formats that a pin is capable of supporting are expressed in a KSMULTIPLE_ITEM array of KSDATARANGE-derived structures. Pin data-range support is exposed through the following three KSPROPSETID_Pin properties on the filter:

KSPROPERTY_PIN_DATARANGES

This property reports data ranges that are static and represent all possible formats supported. Typically, data ranges are contained in a static array in the adapter driver.

KSPROPERTY_PIN_CONSTRAINEDDATARANGES

This property reports data ranges that are dynamic and represent the subset of formats supported at the time of the property request. The property handler should contain the logic to decide which formats the pin is capable of supporting at run time. For example, a hardware implementation could have DMA constraints that do not allow support for full-duplex in certain format combinations.

KSPROPERTY_PIN_DATAINTERSECTION

This property selects a data format from a list of data ranges. Selection is based on dynamic capabilities and the format is taken from the subset of formats that the driver can support at the time of the property request. To use this property, the caller supplies an array of data ranges. Beginning at the first element, the property handler searches the array until it finds a data range that it is currently capable of supporting. If successful, the handler outputs a data format that is taken from that data range and returns STATUS_SUCCESS. Otherwise, the handler returns STATUS_NO_MATCH.

In Microsoft® Windows® 98/Me, and Windows 2000 and later, the audio-system components use the KSPROPERTY_PIN_DATARANGES and KSPROPERTY_PIN_DATAINTERSECTION properties. Support for KSPROPERTY_PIN_CONSTRAINEDDATARANGES is optional.

More information on stream data formats is available in the following sections:

KS Data Formats and Data Ranges

Explains how to negotiate a common data format between two pins in a kernel-streaming filter graph.

Audio Streams: Data Formats and Data Ranges

Presents examples of how pin factories expose the PCM audio data formats that their pins support.

Supporting Non-PCM Wave Formats

Explains how WDM audio drivers can support non-PCM audio wave formats.

Data-Intersection Handlers

Explains how a data-intersection handler selects an audio data format that is common to two pins so that they can be connected.


Hardware Events

Some audio devices provide hardware volume-control knobs, mute switches, or other types of controls. Applications can respond to changes in hardware controls by adjusting the volume or otherwise changing the way that the audio stream is played. When the user adjusts a hardware control, the miniport driver uses the IPortEvents interface to inform the port-class driver that a hardware event has occurred. The port-class driver, in turn, notifies the application of the event so that it can read the new control setting from the device.

Your miniport driver can query the port-class driver for the IPortEvents interface at the time that it services the Init call (see IMiniportWavePci::Init, for example) from the port-class driver. On Windows 98 SE, Windows Me, and Windows 2000 and later, that query will succeed. For a code example, see the SB16 sample audio adapter in the DDK.

When the port-class driver calls your driver's IMiniport::GetDescription method, the method outputs a PCFILTER_DESCRIPTOR structure that specifies, among other things, the events that your device supports. The list of events is found in the structure's AutomationTable.Events member. Each event in the list is specified by a PCEVENT_ITEM structure. Your driver should set the PCEVENT_ITEM structure's Set and Id members to KSEVENTSETID_AudioControlChange and KSEVENT_CONTROL_CHANGE, and should load a pointer to the driver's EventHandler routine into the Handler member. Your driver should also set the PCEVENT_ITEM_FLAG_BASICSUPPORT bit in the Flags member to indicate basic support for control-change events, and set the PCEVENT_ITEM_FLAG_ONESHOT and/or PCEVENT_ITEM_FLAG_ENABLE bits to indicate that it supports one-shot and/or recurring notification.

When an application later calls mixerOpen to request notification of a particular event, the port-class driver then calls your driver's EventHandler routine with a pointer to a PCEVENT_REQUEST structure. This structure's Verb member is set to PCEVENT_VERB_ADD and its EventItem member specifies the event that is to be enabled. The structure also contains a pointer to a KSEVENT_ENTRY structure that your driver should treat as opaque system data. After enabling the event, your driver should call IPortEvents::AddEventToEventList with the same PCEVENT_ENTRY pointer. With this call, the driver acknowledges that the event is enabled.

When the hardware event occurs and your driver's interrupt service routine detects a mute or a volume change, your driver signals the event to the port-class driver by calling IPortEvents::GenerateEventList with a set of parameters that describe the event. For example, the following call describes a control change in a lineout-volume node:

    pPE->GenerateEventList(NULL, KSEVENT_CONTROL_CHANGE,
                          FALSE, ULONG(-1), TRUE, LINEOUT_VOL);

In this example, pPE is a pointer to the IPortEvents object. During this call, the port-class driver searches its event list for all events that match the call parameters. Unspecified parameters (such as the event set ID and pin ID in the example above) are treated as wildcards and always match the corresponding parameters in the list.


WDM Audio Components

This section describes the built-in WDM audio components that support ISA, PCI, and USB audio devices. The two sections below discuss user-mode and kernel-mode components, respectively:

User-Mode WDM Audio Components

Kernel-Mode WDM Audio Components


User-Mode WDM Audio Components

The user-mode WDM audio components are:

  • WinMM System Component
  • WDMAud System Driver
  • DirectSound System Component
  • DirectMusic System Component

WinMM System Component

The WinMM system components (winmm.dll and its 16-bit counterpart, mmsystem.dll) implement the Microsoft® Windows® multimedia APIs waveXxx, midiXxx, mixerXxx, and auxXxx (see Platform SDK documentation). The WinMM components use the WDMAud system driver to translate the WinMM API calls into kernel-streaming I/O requests.

WDMAud System Driver

The user-mode WDMAud system driver (wdmaud.drv) is paired with the kernel-mode WDMAud system driver (wdmaud.sys). Together, the WDMAud system drivers translate between WinMM API calls and kernel-streaming I/O requests. The kernel-mode mode WDMAud driver is a client of the SysAudio system driver.

DirectSound System Component

The DirectSound® system component (dsound.dll) supports the DirectSound API (see Platform SDK documentation). The DirectSound component is a client of the SysAudio driver. If hardware mixing is available, the SysAudio driver connects DirectSound hardware buffers directly to the rendering device. Otherwise, the SysAudio driver connects DirectSound software buffers to the KMixer system driver.

DirectMusic System Component

The DirectMusic® system component supports the DirectMusic API (see Platform SDK documentation). The DirectMusic component is a client of the SysAudio driver.


Kernel-Mode WDM Audio Components

The kernel-mode WDM audio components are:

WDMAud System Driver

SysAudio System Driver

KMixer System Driver

Redbook System Driver

SBEmul System Driver

SWMidi System Driver

DMusic System Driver

AEC System Driver

DRMK System Driver

Splitter System Driver

Port Class Adapter Driver and PortCls System Driver

USBAudio Class System Driver

WDMAud System Driver

The kernel-mode WDMAud system driver (wdmaud.sys) is paired with the user-mode WDMAud system driver (wdmaud.drv). The pair of WDMAud drivers translate between user-mode Windows multimedia system calls and kernel-streaming I/O requests. WDMAud performs I/O for the following APIs: waveIn, waveOut, midiIn, midiOut, mixer, and aux (described in the Platform SDK documentation). The kernel-mode WDMAud driver is a KS (kernel streaming) filter and a client of the SysAudio driver.

SysAudio System Driver

The SysAudio system driver (sysaudio.sys) builds the filter graphs that render and capture audio content. The SysAudio driver represents audio filter graphs as virtual audio devices and registers each virtual audio device as an instance of a KSCATEGORY_AUDIO_DEVICE device interface. (Adapter drivers should not register themselves in this category, which is reserved exclusively for SysAudio.) For example, a virtual MIDI device might represent a filter graph that is created by connecting the SWMidi driver, the KMixer driver, and a port/miniport driver. The client communicates only with the virtual audio device rather than with the individual devices that make up the virtual audio device. Transparent to the client, the SysAudio driver configures all the KS filters in the filter graph that are connected together to form the virtual audio device. The following audio stream sources use the graphs that SysAudio builds:

  • DirectSound (See Platform SDK documentation.)
  • Windows multimedia APIs waveIn, waveOut, midiIn, midiOut, mixer, and aux
  • Redbook (See Redbook System Driver.)
  • Sound Blaster emulator (See SBEmul System Driver.)
  • Kernel-mode software synthesizers (See SWMidi System Driver and DMusic System Driver.)
  • DRMK System Driver

KMixer System Driver

The KMixer system driver (kmixer.sys) is the KS filter that does the following:

  • Mixes multiple PCM audio streams
  • High-quality format conversion
  • Mixing and sample-rate conversion (See KMixer Driver Sample Rate Conversion and Mixing.)
  • Bit-depth conversion
  • Speaker configuration and channel mapping

In addition to simple 8- and 16-bit, mono and stereo data formats, the KMixer driver supports:

  • PCM and IEEE floating-point data
  • Bit depths greater than 16 bits, and multichannel formats with more than two channels
  • HRTF (head-related transfer function) 3D processing

Redbook System Driver

The Redbook system driver (redbook.sys) is the KS filter that supports rendering CD digital audio. The Redbook driver is a client of the SysAudio system driver. The system routes CD digital audio through the file system to the Redbook driver and then to the SysAudio driver. The CD digital audio is rendered on the preferred wave output device (as set in the Multimedia property pages in the Control Panel).

SBEmul System Driver

The SBEmul system driver (sbemul.sys) provides Sound Blaster emulation for MS-DOS® applications. The SBEmul driver is a client of the SysAudio system driver. To render and capture content, the SysAudio driver uses the preferred wave and MIDI devices (as set in the Multimedia property pages in the Control Panel).

Sound Blaster emulation is supported only on Windows 98/Me.

SWMidi System Driver

The SWMidi system driver is the KS filter that provides software-based General MIDI (GM) and high-quality Roland GS wavetable synthesis.

DMusic System Driver

The DMusic system driver (dmusic.sys) is the KS filter that supports high-quality downloadable sound (DLS) synthesis. The DMusic driver is a port class adapter driver (see Introduction to Port Class).

AEC System Driver

The AEC system driver (aec.sys) supports full-duplex DirectSound applications by implementing AEC (automatic echo cancellation) and noise-suppression algorithms in software. For more information, see DirectSound Capture Effects.

DRMK System Driver

The DRMK system driver (drmk.sys) is the KS filter that decrypts audio streams containing DRM-protected content. See Digital Rights Management.

Splitter System Driver

The Splitter system driver (splitter.sys) is the KS filter that creates two or more output streams from a single input capture stream. The Splitter driver transparently copies the input stream to two more output streams independently of the format of the input stream.

The Splitter driver is supported by Windows Me, and Microsoft® Windows® XP and later.

Port Class Adapter Driver and PortCls System Driver

A port-class adapter driver uses the port/miniport driver architecture (see Introduction to Port Class) to support an audio device. The PortCls driver provides built-in driver support for ISA and PCI audio devices. Although the PortCls system driver (portcls.sys) also provides the framework for vendor-supplied port-class adapter drivers, Microsoft recommends that vendors use a built-in port-class adapter driver to support ISA and PCI audio devices. The PortCls framework might also be useful for constructing drivers for audio devices on other hardware buses or for software-only devices.

USBAudio Class System Driver

The USBAudio class system driver (usbaudio.sys) is a KS minidriver (see Stream Minidriver Design Guide) that provides driver support for USB audio devices that comply with the Universal Serial Bus Device Class Definition for Audio Devices (release 1.0). This specification is available at www.usb.org. The USBAudio driver supports a subset of the features that are described in the USB audio specification.

The USBAudio driver for Windows 98 introduced support for USB devices such as speakers and microphones. Support for MIDI devices was added in Windows Me.

When an audio device identifies itself as USB-compliant during plug-and-play device enumeration, the system automatically loads the USBAudio driver to drive the device. USBAudio drives the device directly, without the aid of a proprietary adapter driver. This means that a device that complies with the USB audio specifications requires no proprietary adapter driver.

Microsoft recommends that hardware vendors use the USBAudio driver for their USB audio devices instead of writing proprietary adapter drivers.

In Windows 98, USBAudio supports the following features:

  • All Type I formats (except 8-bit signed PCM)
  • AC3 Type II format
  • All synchronization types (synchronous, asynchronous, adaptive)
  • Multichannel devices

However, USBAudio in Windows 98 does not support:

  • 8-bit signed PCM format
  • MPEG Type II format
  • Type III formats
  • USB MIDI
  • WAVEFORMATEXTENSIBLE wave format (USBAudio uses packed WAVE_FORMAT_PCM for 24-bit data instead.)

In Windows 98 Second Edition (SE), Windows Me, and Windows 2000 and later, USBAudio supports all the same features as Windows 98, with one exception: USBAudio supports WAVEFORMATEXTENSIBLE but does not support packed WAVE_FORMAT_PCM for 24-bit data.

In Windows Me, and Windows XP and later, USBAudio supports all the features that are supported in Windows 98 SE and Windows 2000. In addition, Windows Me and Windows XP support USB MIDI but do not support USB MIDI Elements.


Typical Audio Configurations

This section presents a collection of typical audio configurations for rendering and capturing audio content. The following configurations are shown:

Rendering and Capturing Wave Content

Rendering and Capturing MIDI Content

Rendering and Capturing Audio Content by Using a Port Class Audio Adapter

Rendering and Capturing Audio Content by Using the USBAudio Driver

Rendering Wave Content Using DirectSound Software and Hardware Buffers


Rendering and Capturing Wave Content

The following figure shows the configuration of WDM audio components that render and capture wave content.

Rendering and Capturing Wave Content

See the following for a description of the WDM audio components:

DirectSound System Component

WDMAud System Driver

SBEmul System Driver

SysAudio System Driver

KMixer System Driver

Redbook System Driver

Splitter System Driver

See the following for more information about the configuration of the port class adapter driver and the USBAudio driver:

Rendering and Capturing Audio Content by Using a Port Class Audio Adapter

Rendering and Capturing Audio Content by Using the USBAudio Driver


Rendering and Capturing MIDI Content

The following figure shows the relationship between the system-supplied WDM audio components that support rendering and capturing MIDI content.

Rendering and Capturing MIDI Content

See the following for a description of the WDM audio components:

DirectMusic System Component

WDMAud System Driver

SBEmul System Driver

SysAudio System Driver

KMixer System Driver

Redbook System Driver

Splitter System Driver

See the following for more information about the configuration of the port class adapter driver and the USBAudio driver:

Rendering and Capturing Audio Content by Using a Port Class Audio Adapter

Rendering and Capturing Audio Content by Using the USBAudio Driver


Rendering and Capturing Audio Content by Using a Port Class Audio Adapter

The following figure shows a configuration of a port class audio adapter driver that renders and captures audio content.

Rendering and Capturing Audio Content by Using a Port Class Audio Adapter Driver

See the following for a description of the WDM audio components:

DirectSound System Component

DirectMusic System Component

WDMAud System Driver

SBEmul System Driver

KMixer System Driver

Redbook System Driver

Splitter System Driver

See the following for more detail about the filter graphs above the port class audio adapter:

Rendering and Capturing Wave Content

Rendering and Capturing MIDI Content


Rendering and Capturing Audio Content by Using the USBAudio Driver

The following figure shows a configuration of the USBAudio driver that renders and captures audio content.

Rendering and Capturing Audio Content Using the USBAudio Driver

See the following for a description of the WDM audio components:

DirectSound System Component

WDMAud System Driver

SBEmul System Driver

KMixer System Driver

Redbook System Driver

Splitter System Driver

See the following for more detail about the filter graphs above the USBAudio driver:

Rendering and Capturing Wave Content

Rendering and Capturing MIDI Content


Rendering Wave Content Using DirectSound Software and Hardware Buffers

The following figure shows a configuration of WDM components that renders to DirectSound software and hardware buffers.

Rendering Wave Content Using DirectSound Software and Hardware Buffers

See the following for a description of the WDM audio components:

DirectSound System Component

SysAudio System Driver

KMixer System Driver

Port Class Adapter Driver and Portcls System Driver

USBAudio Class System Driver


Vendor Audio Driver Options

To take advantage of the built-in system support for audio devices, Microsoft recommends that vendors use one of the following:

  • A port-class adapter driver (see Audio Miniport Drivers) for ISA and PCI devices
  • The USB audio class minidriver (see USBAudio Class System Driver) for USB devices

However, if these options are not sufficient, a vendor can implement one of the following:

  • A proprietary KS filter (see KS Filters, Pins and Node Topology)

    Microsoft does not recommend a proprietary KS filter because they are difficult to implement, and are unnecessary for most ISA, PCI, and USB devices.

  • Stream class minidriver (see Stream Minidriver Design Guide)

    Microsoft does not recommend a proprietary stream class minidriver because it is difficult to implement, although it can be appropriate for devices that integrate audio and video.


DDK Audio Driver Samples

The Windows DDK includes a number of audio driver samples that illustrate the principles and features of the WDM audio architecture. These are working implementations with source code that can serve as a starting point for writing a proprietary driver.

The DDK contains the following audio driver samples:

  • ac97

    Intel AC97 sample. This sample shows how to write an audio adapter driver that implements a WavePci miniport for a PCI add-in card.

  • ddksynth

    Kernel-mode DLS synthesizer. This sample can be adapted for a MIDI output device as well.

  • dmusuart

    MPU-401 miniport for processing DirectMusic and MIDI input streams. This sample can be adapted for custom miniports.

  • fmsynth

    FM-synth miniport for MIDI. This sample can be adapted for custom miniports.

  • mpu401

    Stand-alone adapter sample. This audio adapter driver implements standard functionality for an MPU-401 MIDI interface device. The source code for this sample is quite small because it uses only the system-supplied miniports that are implemented in portcls.sys.

  • msvad

    Microsoft Virtual Audio Device. This is a collection of samples that all use the same "virtual audio device" in lieu of an actual hardware-based adapter driver. Each sample highlights a different facet of the WDM audio driver architecture.

  • sb16

    Sound Blaster 16 sample. This sample implements an audio adapter driver for an SB-compatible adapter card on an ISA bus.

  • stdunk

    Standard IUnknown sample. Skeleton implementation of a standard IUnknown interface that conforms to the PortCls model for using COM in the kernel.

For details, see the readme documentation that accompanies each of these samples in the DDK.

To install the portion of the Windows DDK that contains the WDM audio driver samples, follow these instructions:

  • Run the Windows DDK setup application.
  • From the list of component groups that the setup application displays, first select "WDM Samples" under "Windows DDK"; then select "Audio Samples".

When setup completes, you will find the audio driver samples in the src\wdm\audio subdirectory under the main directory of your DDK installation.


Audio Streams: Data Formats and Data Ranges

Each audio pin declares which stream formats it supports. Stream formats are described by KSDATAFORMAT and KSDATARANGE structures. The following are examples of the KSDATAFORMAT and KSDATARANGE structures that should be used to describe audio streams in the most common audio formats:

MIDI Stream Data Format

MIDI Stream Data Range

PCM Stream Data Format

PCM Stream Data Range

PCM Multichannel Stream Data Format

PCM Multichannel Stream Data Range

PCM High Bitdepth Stream Data Format

PCM High Bitdepth Stream Data Range

DirectSound Stream Data Format

DirectSound Stream Data Range


MIDI Stream Data Format

Uses a KSDATAFORMAT structure to describe the data format.

DataFormat.FormatSize = sizeof(KSDATAFORMAT);
DataFormat.Flags      = 0;
DataFormat.SampleSize = 0;
DataFormat.Reserved   = 0;
DataFormat.MajorFormat = STATICGUIDOF(KSDATAFORMAT_TYPE_MUSIC);
DataFormat.SubFormat   = STATICGUIDOF(KSDATAFORMAT_SUBTYPE_MIDI);
DataFormat.Specifier   = STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE);


MIDI Stream Data Range

Uses a KSDATARANGE_MUSIC structure to describe the data format range for MIDI.

DataRange.FormatSize = sizeof(KSDATARANGE_MUSIC);
DataRange.Flags      = 0;
DataRange.SampleSize = 0;
DataRange.Reserved   = 0;
DataRange.MajorFormat = STATICGUIDOF(KSDATAFORMAT_TYPE_MUSIC);
DataRange.SubFormat   = STATICGUIDOF(KSDATAFORMAT_SUBTYPE_MIDI);
DataRange.Specifier   = STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE);
Technology            = STATICGUIDOF(KSMUSIC_TECHNOLOGY_PORT);
Channels              = 0;
Notes                 = 0;
ChannelMask           = 0xFFFF;


PCM Stream Data Format

Uses a KSDATAFORMAT_WAVEFORMATEX structure to describe the wave data format.

DataFormat.FormatSize = sizeof(KSDATAFORMAT_WAVEFORMATEX);
DataFormat.Flags      = 0;
DataFormat.SampleSize = 0;
DataFormat.Reserved   = 0;
DataFormat.MajorFormat = STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO);
DataFormat.SubFormat   = STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM);
DataFormat.Specifier   = STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX);
Format.wFormatTag      = WAVE_FORMAT_PCM;
Format.nChannels       = 2;
Format.nSamplesPerSec  = 44100;
Format.nAvgBytesPerSec = 176400;
Format.nBlockAlign     = 4;
Format.wBitsPerSample  = 16;
Format.cbSize          = 0;


PCM Stream Data Range

Uses a KSDATARANGE_AUDIO structure to describe the range of audio formats.

DataRange.FormatSize = sizeof(KSDATARANGE_AUDIO);
DataRange.Flags      = 0;
DataRange.SampleSize = 0;
DataRange.Reserved   = 0;
DataRange.MajorFormat = STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO);
DataRange.SubFormat   = STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM);
DataRange.Specifier   = STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX);
MaximumChannels              = 2;
MinimumBitsPerSample         = 2;
MinimumSampleFrequency       = 5000;
MaximumSampleFrequency       = 48000;


PCM Multichannel Stream Data Format

Uses an extended version of a KSDATAFORMAT_WAVEFORMATEX structure.

DataFormat.FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEXTENSIBLE);
DataFormat.Flags      = 0;
DataFormat.SampleSize = 0;
DataFormat.Reserved   = 0;
DataFormat.MajorFormat = STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO);
DataFormat.SubFormat   = STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM);
DataFormat.Specifier   = STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX);
Format.wFormatTag      = WAVE_FORMAT_EXTENSIBLE;
Format.nChannels       = 4;
Format.nSamplesPerSec  = 44100;
Format.nAvgBytesPerSec = 352800;
Format.nBlockAlign     = 8;
Format.wBitsPerSample  = 16;
Format.cbSize          = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
Format.wValidBitesPerSample = 16;
Format.dwChannelMask   = KSAUDIO_SPEAKER_SURROUND;
Format.SubFormat       = KSDATAFORMAT_SUBTYPE_PCM;


PCM Multichannel Stream Data Range

Uses a KSDATARANGE_AUDIO structure to describe the range of audio formats.

DataRange.FormatSize = sizeof(KSDATARANGE_AUDIO);
DataRange.Flags      = 0;
DataRange.SampleSize = 0;
DataRange.Reserved   = 0;
DataRange.MajorFormat = STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO);
DataRange.SubFormat   = STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM);
DataRange.Specifier   = STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX);
MaximumChannels              = 4;   // max number of channels or -1 for unlimited
MinimumBitsPerSample         = 2;
MaximumBitsPerSample         = 16;
MinimumSampleFrequency       = 5000;
MaximumSampleFrequency       = 48000;


PCM High Bitdepth Stream Data Format

Uses an extended version of a KSDATAFORMAT_WAVEFORMATEX structure as PCM Multichannel, with the exception of the values for Format.wBitsPerSample and Format.wValidBitsPerSample, as noted in the following sample.

DataFormat.FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEXTENSIBLE);
DataFormat.Flags      = 0;
DataFormat.SampleSize = 0;
DataFormat.Reserved   = 0;
DataFormat.MajorFormat = STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO);
DataFormat.SubFormat   = STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM);
DataFormat.Specifier   = STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX);
Format.wFormatTag      = WAVE_FORMAT_EXTENSIBLE;
Format.nChannels       = 4;
Format.nSamplesPerSec  = 44100;
Format.nAvgBytesPerSec = 352800;
Format.nBlockAlign     = 8;
Format.wBitsPerSample  = 24;
Format.cbSize          = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
Format.wValidBitesPerSample = 20;
Format.dwChannelMask   = KSAUDIO_SPEAKER_SURROUND;
Format.SubFormat       = KSDATAFORMAT_SUBTYPE_PCM;


PCM High Bitdepth Stream Data Range

Uses a KSDATARANGE_AUDIO structure to describe the data format range as PCM Multichannel, with the exception of the value of MaximumBitsPerSample.

This value should be set to the sample container size and must be a multiple of 8. For example, if the device supports 20-bits of valid audio data in 24-bit containers, the value for MaximumBitsPerSample must be set to 24.

DataRange.FormatSize = sizeof(KSDATARANGE_AUDIO);
DataRange.Flags      = 0;
DataRange.SampleSize = 0;
DataRange.Reserved   = 0;
DataRange.MajorFormat = STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO);
DataRange.SubFormat   = STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM);
DataRange.Specifier   = STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX);
MaximumChannels              = 4;   // max number of channels or -1 for unlimited
MinimumBitsPerSample         = 2;
MaximumBitsPerSample         = 16; // 16, 24, 32, etc
MinimumSampleFrequency       = 5000;
MaximumSampleFrequency       = 48000;


DirectSound Stream Data Range

Uses a KSDATARANGE_AUDIO structure to describe the range of audio formats as PCM Multichannel, with the exception of the value of MaximumBitsPerSample.

This value should be set to the sample container size and must be a multiple of 8. For example, if the device supports 20-bits of valid audio data in 24-bit containers, the value for MaximumBitsPerSample must be set to 24.

DataRange.FormatSize = sizeof(KSDATARANGE_AUDIO);
DataRange.Flags      = 0;
DataRange.SampleSize = 0;
DataRange.Reserved   = 0;
DataRange.MajorFormat = STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO);
DataRange.SubFormat   = STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM);
DataRange.Specifier   = STATICGUIDOF(KSDATAFORMAT_SPECIFIER_DSOUND);
MaximumChannels              = 4;   // max number of channels or -1 for unlimited
MinimumBitsPerSample         = 2;
MaximumBitsPerSample         = 16; // 16, 24, 32, etc
MinimumSampleFrequency       = 5000;
MaximumSampleFrequency       = 48000;


WDM Audio Platform Differences

This section discusses the levels of support for WDM audio drivers that are provided in the various versions of Microsoft® Windows®.

The following topics describe the support for WDM audio in the different Windows releases that are available:

Windows 98 Support for WDM Audio

Windows 98 Second Edition Support for WDM Audio

Windows 2000 Support for WDM Audio

Windows Me Support for WDM Audio

Windows XP Support for WDM Audio

The following topic summarizes the support that is provided for non-PCM audio formats in the different Windows versions that are available:

Differences in Support for Non-PCM Formats

For information about how the support for WDM drivers in general differs among Windows versions, including a discussion of floating-point issues for drivers, see Differences in WDM Versions.


Windows 98 Support for WDM Audio

Microsoft does not recommend using a WDM audio driver on Windows 98 because Windows 98 does not support the following:

  • WavePci port
  • DirectSound® hardware mixing
  • KMixer sample rate conversion (SRC) for capture streams
  • DirectMusic® kernel support

However, Windows 98 does support the following WDM capabilities:

  • WDM version 1.0
  • Audio ports: Topology, WaveCyclic (without hardware acceleration), and MIDI
  • MIDI miniports: FMSynth and UART
  • USB audio: Basic support for wave capture and render


Windows 98 Second Edition Support for WDM Audio

Windows 98 SE supports the following WDM capabilities:

  • WDM version 1.0
  • Complete support for the following audio ports: Topology, WaveCyclic, DMus, and MIDI
  • Partial support for the WavePci port, which is subject to the following limitations:
    • It supports a maximum of 64 streams.
    • IMiniportWavePciStream::GetPosition does not work in all situations.
  • MIDI miniports: FMSynth, DMusUART, and UART
  • DirectSound hardware mixing and 3D acceleration
  • KMixer sample-rate conversion (SRC) for capture streams (See KMixer Driver Sample Rate Conversion and Mixing Policy.)
  • Multichannel formats (See www.microsoft.com/hwdev/audio/multichaud.htm.)
  • Other DirectMusic kernel support, including the DMusic system driver (dmusic.sys)
  • USB audio: All the features of Windows 98, plus multichannel support


Windows 2000 Support for WDM Audio

Windows 2000 supports the following WDM audio capabilities:

  • WDM version 1.10
  • All the features that Windows 98 SE supports (See Windows 98 Second Edition Support for WDM Audio.)
  • Complete support for a WavePci port
  • USB audio: All the features of Windows 98 SE


Windows Me Support for WDM Audio

Windows Me supports the following WDM audio capabilities:

  • WDM version 1.05
  • All the features that Windows 2000 supports (See Windows 2000 Support for WDM Audio.)
  • Copying, or splitting, an input capture stream to produce two identical output streams (See Splitter System Driver.)
  • Kernel-mode Digital Rights Management (DRM)
  • DirectSound support for non-PCM formats (See Differences in Support for Non-PCM Formats.)
  • USB audio: All the features of Windows 2000, plus MIDI


Windows XP Support for WDM Audio

Microsoft® Windows® XP supports the following WDM audio capabilities:

  • WDM version 1.20
  • All the features that Windows 2000 and Windows Me support (See Windows 2000 Support for WDM Audio and Windows Me Support for WDM Audio.)
  • AVStream filters, which extend the Kernel Streaming 1.0 system services (See AVStream Overview.)
  • Hardware acceleration of DirectSound capture effects (See Exposing Hardware Accelerated Capture Effects.)
  • Access to the extended capabilities of a WDM audio driver through Windows multimedia functions
  • USB audio: All the features that Windows 2000 and Windows Me support, plus GFX (global effects) filtering (See GFX Filters.)


Differences in Support for Non-PCM Formats

The discussion below summarizes the level of support for non-PCM audio formats that is provided by the WDM audio framework in the different versions of Windows that are available. For background information on this topic, see Supporting Non-PCM Wave Formats.

Windows 98 Gold

Windows 98 Gold provides no support for non-PCM wave formats through DirectSound, the waveOut API, or any other audio interface that uses the SysAudio system driver. (For information on DirectSound and waveOut, see the Platform SDK documentation.)

Windows 98 Second Edition

Like Windows 98 Gold, Windows 98 SE has no support for non-PCM wave formats, except that the USBAudio class system driver (usbaudio.sys) can handle the packed AC3 format through DirectShow. (This format is described in USB Audio Support for Non-PCM Formats.) However, USBAudio still provides no support for non-PCM formats to waveOut and DirectSound applications.

Windows 98 SE + QFE

Installing the QFE (quick-fix engineering) package for Windows 98 SE enables support for non-PCM formats for waveOut applications that use PortCls devices. (The QFE is described in Additional Requirements for Windows 98.) However, the following caveats apply:

  • The waveOutGetPosition function (see Platform SDK documentation) retrieves incorrect timing information for streams with non-PCM formats.
  • An adapter driver that wants to provide non-PCM support to waveOut applications should provide a non-PCM data range with the format specifier set to KSDATAFORMAT_SPECIFIER_WAVEFORMATEX. Although PortCls automatically clones the miniport's data ranges from KSDATAFORMAT_SPECIFIER_WAVEFORMATEX to KSDATAFORMAT_SPECIFIER_DirectSound, it does so only for PCM data ranges. (You can confirm this by running the KsStudio.exe kernel-streaming tool from the Windows DDK.) To make its non-PCM support accessible to DirectSound applications, the driver needs to explicitly specify a second copy of the same data range and set the format specifier for this data range to KSDATAFORMAT_SPECIFIER_DirectSound. (For more information, see Declaring Non-PCM Data Ranges.)
  • When a driver defines a non-PCM pin, this causes a "phantom control" to show up in the window of the SndVol32 "Volume Options" applet (sndvol32.exe) that ships with Windows. SndVol32 displays a non-PCM pin as a grayed-out SRC mixer line without a slider or other control. (You can confirm this behavior by running the sample mixer application, MixApp.exe. See the description of MixApp in the Visual C++ audio samples in the Platform SDK documentation.) Users might find this display confusing. For this reason, some hardware vendors choose not to expose their AC3 pins on Windows 98 SE.

The built-in version of DirectSound does not support non-PCM formats. However, when DirectSound 8 is installed in Windows 98 SE + QFE, DirectSound applications can use non-PCM formats with both PortCls devices and USB audio devices.

Windows Me

Windows Me provides support for non-PCM formats for waveOut applications that use PortCls devices.

The waveOutGetPosition call works correctly for non-PCM streams.

PortCls automatically clones non-PCM data ranges for DirectSound.

The problem with phantom sliders in SndVol32 (see above) is fixed.

The IPortClsVersion interface is not implemented, but other means of determining the operating system version are available. For example, you can detect the OS version by calling IoIsWdmVersionAvailable or by simply querying the port object for its IDrmPort interface, which is not supported in Windows 98 and Windows 2000.

In Windows Me, the USBAudio driver does not support the packed AC3 format through DirectShow. Also, USBAudio does not support non-PCM formats for DirectSound applications that use the built-in DirectSound implementation. However, when DirectSound 8 is added to Windows Me, DirectSound applications can use non-PCM formats on USB audio devices.

The initial QFE that has been released for Windows Me contains no non-PCM fixes.

Windows 2000

Like Windows 98, Windows 2000 provides no support for non-PCM formats, regardless of DirectSound version.

In Windows 2000, the USBAudio driver does not support packed AC3 formats through DirectShow. USBAudio also does not support any non-PCM formats for DirectSound applications.

Windows 2000 Service Pack 2

SP2 adds support for non-PCM formats to waveOut applications that use PortCls devices.

PortCls automatically clones non-PCM data ranges for DirectSound.

The IPortClsVersion interface is available in SP2.

The waveOutGetPosition call works correctly for non-PCM streams.

SP2 still has the problem with phantom sliders in SndVol32 (see above).

When DirectSound 8 is added to Windows 2000 SP2, DirectSound applications can use non-PCM formats.

Windows XP

Windows XP supports non-PCM formats for waveOut applications that use PortCls devices.

The waveOutGetPosition call works correctly for non-PCM streams.

PortCls automatically clones non-PCM data ranges for DirectSound.

The built-in version of DirectSound correctly handles non-PCM formats on PortCls devices.

The problem with phantom sliders in SndVol32 (see above) is fixed.

The USBAudio driver correctly handles packed AC3 formats through DirectShow. However, USBAudio does not support non-PCM formats for DirectSound applications.


DirectSound Hardware Acceleration in WDM Audio

This section describes WDM audio driver support for hardware acceleration of DirectSound. The following topics are discussed:

Supporting 2D DirectSound Acceleration in WDM Audio

Supporting 3D DirectSound Acceleration in WDM Audio

DirectSound Node-Ordering Requirements

Supporting a Mixture of 2D and 3D Pins

DirectSound Hardware-Acceleration and SRC Sliders

Exposing Custom Audio Property Sets


Supporting 2D DirectSound Acceleration in WDM Audio

DirectSound® exposes hardware-accelerated 2D mixing for WDM audio miniports that meet the following requirements:

  • The miniport includes a pin factory that is an IRP sink (KSPIN_COMMUNICATION_SINK), has a KSPIN_DATAFLOW direction of KSPIN_DATAFLOW_IN, and exposes a data range (KSDATARANGE_AUDIO structure) in which the specifier (DataFormat.Specifier member) is set to KSDATAFORMAT_SPECIFIER_DSOUND.
  • The pin factory's KSPROPERTY_PIN_CINSTANCES handler sets the PossibleCount member of the KSPIN_CINSTANCES structure to a value greater than one. The PossibleCount value specifies the number of pin instances that can currently be instantiated from the pin factory.
  • The pin factory must support the KSPROPERTY_AUDIO_CPU_RESOURCES property and should report KSAUDIO_CPU_RESOURCES_NOT_HOST_CPU for all nodes that are hardware accelerated.
  • The pin should meet the DirectSound node-ordering requirements (see DirectSound Node-Ordering Requirements).


Supporting 3D DirectSound Acceleration in WDM Audio

DirectSound® exposes hardware-accelerated 3D mixing for WDM audio miniports that meet the following requirements:

  • The pin must meet the requirements listed in Supporting 2D DirectSound Acceleration in WDM Audio.
  • The pin should include a 3D node (KSNODETYPE_3D_EFFECTS) in its node chain. (See DirectSound Node-Ordering Requirements.)
  • The pin must support the KSPROPSETID_DirectSound3DBuffer property set on the KSNODETYPE_3D_EFFECTS node.
  • The pin must support the KSPROPSETID_DirectSound3DListener property set on the KSNODETYPE_3D_EFFECTS node.


DirectSound Node-Ordering Requirements

A DirectSound 2D or 3D mixer pin should have a node chain that contains the following sequence of nodes:

  • Volume node (See KSNODETYPE_VOLUME.)
  • 3D node (This node is optional. See KSNODETYPE_3D_EFFECTS.)
  • Supermix node (See KSNODETYPE_SUPERMIX.)
  • Volume node
  • SRC node (See KSNODETYPE_SRC.)
  • SUM node (See KSNODETYPE_SUM.)

The nodes above are listed in the order in which they are encountered by data streaming into the pin. Other nodes can be interleaved between these nodes without causing problems, provided that the above order is preserved.

A 2D pin requires all of the nodes listed above, except for the 3D node, which is optional. A 3D pin requires all of the nodes listed above, including the 3D node.

The SRC (sample-rate conversion) node should precede the SUM node. The SRC and SUM nodes are typically adjacent, although this is not a requirement. The IDirectSoundBuffer::SetFrequency method (see Platform SDK documentation) perturbs the SRC node's resampling rate.

A mixer that contains only SRC and SUM nodes is sufficient for mixing streams that are managed by system drivers such as SWMidi and Redbook (see SWMidi System Driver and Redbook System Driver), but DirectSound additionally requires that two volume nodes and a supermix node precede the SUM node. DirectSound sends volume changes resulting from IDirectSoundBuffer::SetVolume calls to the first volume node and sends panning effects from IDirectSoundBuffer::SetPan calls to the second volume node.

DirectSound can produce 3D effects on a 2D pin by using the SetVolume, SetPan, and SetFrequency calls to control the volume and SRC nodes:

  • SetVolume calls can simulate changes in the distance of a sound source from the listener.
  • SetPan calls can simulate changes in orientation of a sound source relative to the listener.
  • SetFrequency calls can simulate Doppler effects and HRTFs (head-related transfer functions).

The supermix node is a crossbar matrix that connects M input channels to N output channels, where N should be equal to the number of channels in your device's final output stream.

The optional 3D node is required to manage hardware-accelerated 3D effects (see Supporting 3D DirectSound Acceleration in WDM Audio), but is not needed for software 3D processing. Most existing implementations place the 3D node before the SRC node and between the first volume node and the supermix node, but other configurations are possible.

The input stream to the 3D node typically contains a single channel. In DirectSound 8.0 and later, only mono PCM buffers can be created with 3D effects. Earlier versions of DirectSound, however, support 3D nodes with both mono and stereo input streams, and drivers should support both in order to ensure compatibility with older applications.


Supporting a Mixture of 2D and 3D Pins

If your WDM audio driver supports a mixture of 2D and 3D pins, a 3D pin can double for use as a 2D pin, but not vice versa. When DirectSound requires a 2D pin, it can substitute an unused 3D pin for that purpose, if one is available from the driver. If DirectSound requires a 3D pin, however, it will continue to search the driver's list of pin instances until it finds a 3D pin and ignore any 2D pins encountered during the search. DirectSound will check the driver's list of pin factories in the order in which they are listed until it finds a pin instance that satisfies its requirements.

When reporting the 2D-pin count, your driver should specify the number of 2D-pin instances plus the number of 3D-pin instances. When reporting the 3D-pin count, your driver should ignore the 2D pins and specify only the number of 3D-pin instances.

DirectSound versions that are previous to Windows Me have a known problem in dealing with a pin factory that exposes a mixture of 2D and 3D pins: DirectSound incorrectly reports the 3D-pin count to be the number of 2D pin instances plus the number of 3D pin instances. A workaround solution to this problem is to write your driver so that it segregates the 2D and 3D pins into two separate pin factories. One factory exposes only the 2D pins, and the other factory exposes only the 3D pins. With WDM drivers, DirectSound will correctly report the 2D-pin count as the sum of the counts of the 2D and 3D pins from the two factories, and it will correctly report the 3D-pin count as the number of 3D pins from the one 3D-pin factory. When exposing separate factories for 2D and 3D pins, your driver should list the 2D-pin factory before the 3D-pin factory. This is necessary because when DirectSound is looking for a 2D pin, it will use the first 2D or 3D pin that it finds, and DirectSound checks the pin factories in the order in which the driver lists them. If the driver lists the 3D factory first, it risks having DirectSound deplete the supply of 3D pins by unnecessarily using them in place of 2D pins.

In summary, if your driver exposes a mixture of 2D and 3D pins, it should follow these rules in order to run correctly on earlier versions of DirectSound:

  • Provide two separate pin factories for the 2D and 3D pins, respectively.
  • List the 2D-pin factory ahead of the 3D-pin factory.

These workarounds are unnecessary with later versions of DirectSound. The problem that is described above is fixed in Windows Me, and in Microsoft® Windows® XP and later. It is also fixed in DirectSound 8, which is redistributed for use with older Windows versions. With this fix, your driver can safely mix 2D and 3D pins together in a single pin factory and DirectSound will correctly report the 2D- and 3D-pin counts. Also, when DirectSound requires a 2D pin, it will choose to use a 3D pin in place of a 2D pin only when it has exhausted the supply of 2D pins from all pin factories.


DirectSound Hardware-Acceleration and SRC Sliders

Windows 98/Me, and Windows 2000 and later, provide global slider controls for altering DirectSound performance on a system-wide basis. The sliders control the level of hardware acceleration and quality of sample-rate conversion (SRC) that are made available to DirectSound applications.

To locate the DirectSound hardware-acceleration and SRC sliders under Windows XP, for example, follow these steps:

  • Open the Sounds and Audio Devices applet in the Control Panel.
  • Click the Audio tab.
  • Select a device from the Sound Playback list.
  • Click the Advanced button.
  • Click the Performance tab.

At this point, you should see two sliders that are labeled Hardware acceleration and Sample rate conversion quality.

The hardware-acceleration slider has four settings that range from "None" (level 0) on the left to "Full" (level three) on the right. The table below shows the meaning of these settings:

Acceleration level | Setting name | Description
0 | Emulation | Forces emulation.
1 | Basic | Disables hardware acceleration of DirectSound secondary buffers.
2 | Standard | Enables hardware acceleration of DirectSound secondary buffers but disables vendor-specific property-set extensions.
3 | Full | Enables hardware acceleration of DirectSound secondary buffers and enables vendor-specific property-set extensions.

Emulation Setting
The Emulation setting above forces DirectSound into emulation mode. In this mode, DirectSound applications run as though no DirectSound driver is present. All mixing is done by DirectSound in user mode, and the resulting audio data is played back through the waveOut API. The result is typically a large increase in latency. Note that after you select this setting, you might need to reboot if you are running a Windows version that is earlier than Windows XP and you want to change to one of the other three settings: Basic, Standard, or Full. This problem has been fixed in the version of DirectSound that ships with Windows XP and later.
Basic Setting
The Basic setting disables hardware acceleration of DirectSound secondary buffers. Under this setting, all DirectSound applications run as though no hardware acceleration is available, regardless of the capabilities of the sound card that is being used. You can use this setting during testing to emulate a sound card that has no DirectSound acceleration. With an adapter such as the OPL, which has no acceleration of DirectSound secondary buffers, this setting has the same effect as the Standard setting.
Standard Setting
The Standard setting enables hardware acceleration of DirectSound secondary buffers but disables vendor-specific extensions such as EAX (Creative Technologies' environmental audio extensions) that are exposed as property sets through the IKsPropertySet interface. On Windows 2000, the Standard setting is selected by default and can be changed only by direct end-user action. This purpose of this behavior is to improve stability and to prevent software from placing the audio system in a state from which it cannot be removed without rebooting.
Full Setting
The Full setting enables full acceleration of DirectSound secondary buffers. This setting also enables property sets for vendor-specific extensions that are exposed through the IKsPropertySet interface. IKsPropertySet extensions include vendor-specific hardware enhancements such as EAX. This is the default setting on Windows 98/Me and Windows XP. Again, for the sake of stability, the default setting can be changed only by direct end-user action.

The table below summarizes the default settings for the hardware-acceleration and SRC sliders for the various Windows releases.

Windows release | Default hardware-acceleration setting | Default SRC setting
Windows 98 | Full | Good
Windows 2000 | Full | Good
Windows Me | Standard | Good
Windows XP | Full | Best

In Windows XP, the KMixer system driver uses an SRC algorithm that provides a signal-to-noise ratio of up to 85 decibels when the SRC slider is set to Best.


Exposing Custom Audio Property Sets

By default, DirectSound® ignores custom property sets in Windows Me, and in Windows 2000 and later. In order to have a custom property set recognized by DirectSound on these versions of Windows, users must first enable custom property sets on their system. Custom audio property sets are enabled by default on Windows 98 Second Edition.

For example, to enable custom audio property sets in Windows 2000

  1. Open the Sounds and Multimedia applet in the Control Panel.
  2. Click the Audio tab.
  3. Select the appropriate preferred device in the Sound Playback list.
  4. Click the Advanced button.
  5. Click the Performance tab.
  6. Click and slide the Hardware Acceleration slider to Full.
  7. Click Apply.

DirectSound is now enabled to pass custom property sets to the driver.

Four settings are available on the Hardware Acceleration slider: None, Basic, Standard, and Full. (See DirectSound Hardware-Acceleration and SRC Sliders.)


DirectSound Speaker-Configuration Settings

This section describes the DirectSound speaker-configuration settings and how to implement WDM audio drivers that support these configurations. The following topics are discussed:

Translating Speaker-Configuration Requests

Applying Speaker-Configuration Settings

Proprietary Speaker-Configuration Utilities

DSSPEAKER_SURROUND Speaker Configuration

DSSPEAKER_DIRECTOUT Speaker Configuration


Translating Speaker-Configuration Requests

When an application calls IDirectSound::SetSpeakerConfig (see Platform SDK documentation) to change the speaker configuration, DirectSound translates the specified DSSPEAKER_Xxx speaker-configuration parameter to the equivalent KSAUDIO_Xxx channel-configuration mask. It sends a channel-config set-property request (see KSPROPERTY_AUDIO_CHANNEL_CONFIG) containing this mask to the filter that represents the DirectSound device.

In the table below, each DSPEAKER_Xxx parameter on the left is paired with the equivalent KSAUDIO_Xxx channel-configuration mask, which appears on the right.

DSSPEAKER parameter | KSAUDIO channel-configuration mask
DSSPEAKER_DIRECTOUT | KSAUDIO_SPEAKER_DIRECTOUT
DSSPEAKER_HEADPHONE | KSAUDIO_SPEAKER_STEREO
DSSPEAKER_MONO | KSAUDIO_SPEAKER_MONO
DSSPEAKER_STEREO | KSAUDIO_SPEAKER_STEREO
DSSPEAKER_QUAD | KSAUDIO_SPEAKER_QUAD
DSSPEAKER_SURROUND | KSAUDIO_SPEAKER_SURROUND
DSSPEAKER_5POINT1 | KSAUDIO_SPEAKER_5POINT1
DSSPEAKER_7POINT1 | KSAUDIO_SPEAKER_7POINT1

In the table above, DirectSound specifies both its headphone and stereo speaker configurations with the same channel mask, KSAUDIO_SPEAKER_STEREO. To distinguish between these two configurations, DirectSound sends the filter a second set-property request, which specifies a speaker geometry (see KSPROPERTY_AUDIO_STEREO_SPEAKER_GEOMETRY). To indicate headphones, DirectSound passes the value KSAUDIO_STEREO_SPEAKER_GEOMETRY_HEADPHONE with the speaker-geometry request.

In the case of stereo speakers, however, the caller to SetSpeakerConfig can specify one of several possible DSSPEAKER_Xxx stereo-speaker geometries. These appear in the left column of the table below, and the equivalent KSAUDIO_Xxx parameters appear on the right.

DSSPEAKER stereo-speaker geometry | KSAUDIO stereo-speaker geometry
DSSPEAKER_GEOMETRY_WIDE | KSAUDIO_STEREO_SPEAKER_GEOMETRY_WIDE
DSSPEAKER_GEOMETRY_NARROW | KSAUDIO_STEREO_SPEAKER_GEOMETRY_NARROW
DSSPEAKER_GEOMETRY_MIN | KSAUDIO_STEREO_SPEAKER_GEOMETRY_MIN
DSSPEAKER_GEOMETRY_MAX | KSAUDIO_STEREO_SPEAKER_GEOMETRY_MAX

If the caller does not explicitly specify one of the geometries in the left column above, DirectSound assumes DSSPEAKER_GEOMETRY_WIDE by default.


Applying Speaker-Configuration Settings

DirectSound keeps track of its current speaker-configuration setting in the registry and applies that setting to the audio hardware each time a new DirectSound device is created.

An application program can change the system-wide speaker configuration by calling the IDirectSound::SetSpeakerConfig method, which updates the speaker-configuration setting in the registry. The method also attempts to apply the new setting immediately to the hardware, although audio devices are typically unable to change speaker settings while the DirectSound object exists. See Translating Speaker-Configuration Requests for a list of the speaker configurations that DirectSound defines for this method.

A user can change the configuration through the speaker-configuration dialog in the Multimedia Properties page (mmsys.cpl) in the Control Panel. To locate the DirectSound speaker-configuration dialog under Windows XP, for example, follow these steps:

  • Open the Sounds and Audio Devices applet in the Control Panel.
  • Click the Audio tab.
  • Select a device from the Sound Playback list.
  • Click the Advanced button.
  • Click the Speakers tab.

At this point, you should see the label Speaker Setup next to a list of the speaker configurations that you can select from.

DirectSound uses a KSPROPERTY_AUDIO_CHANNEL_CONFIG set-property request to send the speaker-configuration information to a 3D node or DAC node (KSNODETYPE_3D_EFFECTS or KSNODETYPE_DAC) in an audio filter graph. For a 3D node, the target for the property request is actually the pin (3D-stream object) that feeds the node. For a DAC node, the target is the filter object that contains the DAC node. In either case, the speaker-configuration setting is global and affects the audio device as a whole. All audio applications that subsequently run are subject to the new setting until DirectSound changes the setting again.

Note that only versions of DirectSound that ship with Windows Me, and with Windows XP and later, will send speaker-configuration property requests to DAC nodes—earlier versions of DirectSound do not support this feature. However, all versions of DirectSound will send these requests to 3D nodes.

If an application program has created more than one 3D node, DirectSound sends speaker-configuration requests only to the first 3D node to be created.

DirectSound sends speaker-configuration requests to the 3D and DAC nodes each time an application creates a DirectSound object or calls the IDirectSound::SetSpeakerConfig method. Audio devices are typically unable to change their speaker configuration while they are managing active streams, and DirectSound tries to avoid this limitation where possible. For example, when creating a DirectSound object, DirectSound sends the speaker-configuration requests after instantiating the filter but before instantiating any pins on the filter—that is, before creating any streams.

This limitation is harder to avoid in the case of a call to SetSpeakerConfig. When an application calls SetSpeakerConfig, the adapter driver typically fails DirectSound's speaker-configuration request. This is because the DirectSound object already exists, which means that the device already has active streams to manage.

In this case, the adapter driver has two options for dealing with a speaker-configuration request that it has failed:

  • The driver can choose to remember the requested configuration and apply it just as soon as all its streams are destroyed.
  • The driver can choose to ignore the request entirely and rely on DirectSound to send another speaker-configuration request the next time that a DirectSound object is created.

The first approach gives a better user experience because if the user selects a new setting through the speaker-configuration control panel, the change takes effect immediately in all applications—not just DirectSound applications. (Of course, if any audio applications are running at the time that the new setting is selected, the change is deferred until all audio applications terminate.) With the second approach, however, the change does not take effect until a DirectSound application runs. For example, if an application that uses the Windows Multimedia waveOut API is the first application to run after changing the control panel setting, the user may wonder why the new setting has no apparent effect.

In response to a speaker-configuration request sent to a 3D or DAC node, a typical adapter driver updates the speaker configuration in the audio hardware only if no pins are currently instantiated by any audio application. That means that if a waveOut application, for example, has one or more pins open at the time that a second application calls DirectSoundCreate, the driver might need to defer any pending changes to the audio device's speaker configuration until a later time.

If your driver is unable to fulfill a request to change the device's speaker-configuration, it should simply fail the request. Failing a speaker-configuration request during DirectSound object creation or a SetSpeakerConfig call will not cause the DirectSound object creation or SetSpeakerConfig call to fail.

At boot time, an audio adapter driver initializes the hardware's speaker configuration to its default setting, which is typically stereo. As soon as any application creates a DirectSound object, DirectSound will apply the setting stored in the registry to the hardware. An application program must create a DirectSound device before it can call SetSpeakerConfig to change the speaker-configuration setting in the registry, but this registry setting typically takes effect in the hardware only after the DirectSound device is released and a second DirectSound device is created.

Immediately after installing an audio device or when a speaker-configuration error occurs, the DirectSound speaker configuration defaults to stereo.


Proprietary Speaker-Configuration Utilities

Hardware vendors occasionally provide proprietary speaker-configuration utilities to be used with their audio drivers in place of the speaker dialog in the Windows control panel. Such utilities have a potential problem: they sometimes change the speaker configuration in a proprietary way that fails to notify Windows of the change. This can result in a bad user experience if the settings in the proprietary utility do not match those in the control panel. If you believe that your device requires a proprietary utility, you should take the following steps to integrate your utility with Windows:

  • Implement a DAC node in your driver that supports the KSPROPERTY_AUDIO_CHANNEL_CONFIG property. Through this node, Windows informs the driver immediately of changes made by the user in the Windows control panel.
  • Your configuration utility should call the DirectSound methods GetSpeakerConfig and SetSpeakerConfig to manage the speaker configuration.

The SetSpeakerConfig call informs DirectSound (and Windows) of changes that your utility makes to the speaker configuration. Also, your utility's initialization code should call GetSpeakerConfig to see if the user has changed any settings through the Windows control panel. If so, the utility should reflect these changes in its user interface.

If your device supports multichannel formats that have no precise Windows equivalents, your configuration utility should do the following:

  • When changing to a speaker configuration that has no precise Windows equivalent, call SetSpeakerConfig with the closest Windows equivalent. This is in addition to making any proprietary calls that are needed to configure the driver.
  • When changing to a speaker configuration that does have a precise Windows equivalent, call SetSpeakerConfig to update the speaker mode.

If you make Windows better aware of your device's capabilities, DirectSound can enable some features that it could not otherwise enable (for example, multichannel 3D panning).


DSSPEAKER_SURROUND Speaker Configuration

An application program can change the DirectSound speaker configuration to surround mode by calling the IDirectSound::SetSpeakerConfig method with the speaker-configuration parameter set to DSSPEAKER_SURROUND. This specifies a four-channel PCM format in which the channels are mapped to left, right, center, and back speakers.

Once it takes effect, the DSSPEAKER_SURROUND speaker-configuration setting is global and affects the audio device as a whole. All audio applications that subsequently run are subject to the new setting until DirectSound changes the setting again.

DirectSound uses the following algorithm to configure the audio system for surround mode:

  1. DirectSound first asks the driver to go into the surround speaker mode by sending a KSPROPERTY_AUDIO_CHANNEL_CONFIG set-property request to the driver's DAC node (or 3D node if it has no DAC node). (See KSNODETYPE_DAC and KSNODETYPE_3D_EFFECTS.) The KSAUDIO_CHANNEL_CONFIG structure that accompanies this property request specifies the KSAUDIO_SPEAKER_SURROUND speaker configuration. If the request succeeds, the audio device routes the four channels to four analog outputs that are connected directly to left, right, center, and back speakers.
  2. If that fails, DirectSound asks the driver to configure the device in stereo speaker mode and to enable its KSNODETYPE_SURROUND_ENCODER node, if it has one. If this succeeds, the device converts the four-channel stream from the application to a surround-encoded stereo signal that it outputs in either digital or analog form. (The hardware should do the encoding after mixing the streams that flow into the device's various mixer pins.) The user can connect the device's stereo outputs to an external decoder that converts the encoded signal into four channels that are output to left, right, center, and back speakers.
  3. If that fails, DirectSound enables the KSNODETYPE_SURROUND_ENCODER node in KMixer. (The device is already in stereo mode from the previous step.) Again, the stereo signal that is output by the device can be fed to an external decoder.

If this algorithm succeeds, the application can create and play four-channel PCM buffers. In cases (1) and (2) above, the hardware buffers that the device reads from use four channels, but in case (3) the hardware buffers use a stereo format. The application can write directly to the hardware buffers in cases (1) and (2), but in case (3) it should write to a software buffer and allow KMixer to convert the application's four-channel stream to the surround-encoded stereo format needed for the hardware buffer.

In case (3) above, the application should avoid using hardware buffers for any of its output streams. Note that KMixer mixes all of its input streams before encoding the mix to produce the surround stereo stream. However, any stream that enters a hardware mixer pin will be mixed in hardware with the encoded stereo from KMixer, which will degrade the quality of the surround audio when it is decoded. The application can prevent this by using only software buffers.

A stereo stream that has been surround-encoded by a KSNODETYPE_SURROUND_ENCODER node can be decoded into four channels (left, right, center, and back) by a KSNODETYPE_PROLOGIC_DECODER node.


DSSPEAKER_DIRECTOUT Speaker Configuration

An application program can change the DirectSound speaker configuration to direct-out mode by calling the IDirectSound::SetSpeakerConfig method with the speaker-configuration parameter set to DSSPEAKER_DIRECTOUT (see Platform SDK documentation). This specifies a speakerless configuration in which the channels in the playback stream from the application are output directly to the audio adapter without being interpreted as speaker positions. However, the input stream can still be modified by sample-rate conversion, attenuation, filtering, and other types of processing that require no assumptions about the assignment of speakers to channels.

Once it takes effect, the DSSPEAKER_DIRECTOUT speaker-configuration setting is global and affects the audio device as a whole. All audio applications that subsequently run are subject to the new setting until DirectSound changes the setting again.

In direct-out mode, the audio device renders the first channel to the first output connector on the device, the second channel to the second output on the device, and so on. This allows an audio authoring application to output multichannel data directly to a device such as an external mixer or an audio storage device (hard disk, ADAT, and so on). For example, the channels in a 48-channel stream might be assigned as shown below.

Channel number | Content
0 | Vocal
1 | Drums
2 | Guitar
3 | Bass
...
47 | Piano

For this kind of raw audio data, speaker positions are meaningless, and assigning speaker positions to the input or output streams might cause unwanted side effects. For example, a component such as KMixer might intervene inappropriately by applying speaker-specific effects such as 3D virtualization or Dolby Surround Pro Logic encoding to the stream. Note that the number of raw-data channels is not limited by the number of bits in the channel mask.

Even a device that is not designed specifically for audio editing should typically accept a KSPROPERTY_AUDIO_CHANNEL_CONFIG set-property request to change its speaker configuration to KSAUDIO_SPEAKER_DIRECTOUT. In general, a device should avoid failing the request unless it can somehow verify that its outputs are connected to speakers and cannot be used externally for any other purpose (for example, as inputs to an external mixer).

An application that uses direct-out mode is typically written for a specific hardware device. This allows the application to know in advance which direct-out data formats the device supports, including the number of channels and how the data in those channels should be interpreted. This knowledge is necessary because when an application calls IDirectSound::GetSpeakerConfig on a device that is configured in direct-out mode, the device merely confirms that it is in this mode; it provides no additional information regarding the number of channels in the stream formats that it supports in direct-out mode. (This information might be obtained, however, by sending a KSPROPERTY_AUDIO_MIX_LEVEL_CAPS get-property request to the supermix node on the device's mixer pin; see DirectSound Node-Ordering Requirements.)

When specifying the wave format for a direct-out stream, an application should set the dwChannelMask member of the WAVEFORMATEXTENSIBLE structure to the value KSAUDIO_SPEAKER_DIRECTOUT, which is zero. A channel mask of zero indicates that no speaker positions are defined. As always, the number of channels in the stream is specified in the Format.nChannels member.

Hardware vendors have the option of supporting DirectSound hardware acceleration when their devices are configured in direct-out mode. A DirectSound application can play back a direct-out stream through one of the device's mixing pins, if one is available. Once all the available hardware pin instances have been exhausted, any new streams will pass through KMixer instead.

When mixing streams for a device that is configured in direct-out mode, KMixer will apply a one-to-one mapping between the channels of the input streams from the applications and the channels of the mix stream that it outputs to the device. This means that if the application generates several direct-out streams that have the same number of channels, for example, each channel N of the output mix is simply the sum of channels N of all the streams that enter KMixer.

When mixing several direct-out streams that differ in the number of channels they contain, KMixer's mixing algorithm is slightly more complex. In this case, each channel N of the mix is the sum of channels N of all input streams that have a channel N. For example, if KMixer mixes quad and stereo input streams to form a quad output mix, channels zero and one of the output mix are the sums of channels zero and one, respectively, of the input stereo and quad streams. The stereo input stream contributes nothing, however, to channels two and three of the mix, which are taken solely from the last two channels of the quad input stream.

An application that attempts to do either of the following is risking unpredictable behavior:

  • Play a stream that is not in direct-out format through a device that is configured in direct-out mode.
  • Play a direct-out stream through a device that is not configured in direct-out mode.

When faced with one of these cases, KMixer avoids simply failing the attempt to open the stream. Instead, it tries to handle the apparent incompatibility as best it can by using the one-to-one mapping algorithm that is described above. The user may or may not be satisfied with the result. Other audio components cannot be expected to handle these cases in the same way as KMixer. For example, the driver for a device that is configured in direct-out mode should fail an attempt to open a hardware buffer for an output stream that is not in direct-out format, and vice versa.

An audio authoring application might need to let the user listen to the data that it has mixed into the first several channels of its output stream but ignore the raw data that is still contained in the remaining channels of the stream. KMixer's behavior makes this straightforward. For example, if a 24-channel playback stream contains a stereo mix in channels zero and one and raw data in channels two through 23, the application does the following:

  • Configures the target audio device (this is not necessarily the device that the application uses to edit the stream) in stereo mode by calling SetSpeakerConfig with DSSPEAKER_STEREO.
  • Changes dwChannelMask in the playback stream's WAVEFORMATEXTENSIBLE structure to KSAUDIO_SPEAKER_STEREO but leaves Format.nChannels set to 24, which is the total number of channels in the stream.

KMixer mixes only the stereo channels of the playback stream, which are described in the channel mask, and discards the remaining 22 channels, which contain raw data. Recall that any change made the DirectSound speaker-configuration setting is unlikely to take effect until the current DirectSound object is destroyed and another is created (see Applying Speaker-Configuration Settings).


DirectSound Capture Effects

DirectSound 8 adds some new features for enabling and controlling third-party effects during audio capture. This and later versions of DirectSound support the following two capture effects:

  • Acoustic echo cancellation (AEC)
  • Noise suppression (NS)

A full-duplex DirectSound application can use the IDirectSoundCaptureFXAec and IDirectSoundCaptureFXNoiseSuppress interfaces to control these effects. The IDirectSoundCaptureBuffer::GetObjectInPath method retrieves pointers to objects with these interfaces. The DirectDrawFullDuplexCreate function creates the IDirectSoundCaptureBuffer object, and the parameters that the caller passes to this function include an array of DSCEFFECTDESC structures. The array specifies the effects that are to be enabled in the capture buffer. The guidDSCFXClass member of each structure in the array contains a GUID that specifies an effect: AEC or NS. The DirectSound name for each GUID is shown in the table below, along with the KS name for the same GUID value. For details, see the DirectX 8.0 SDK documentation.

DirectSound GUID name | KS GUID name
GUID_DSCFX_CLASS_AEC | KSNODETYPE_ACOUSTIC_ECHO_CANCEL
GUID_DSCFX_CLASS_NS | KSNODETYPE_NOISE_SUPPRESS

In Microsoft® Windows® XP and later, you can expose your audio device's hardware-accelerated capture effects to DirectSound applications. In addition, the AEC system filter (aec.sys) provides software emulation of AEC and NS effects.

These topics are discussed in the remainder of this section:

Exposing Hardware-Accelerated Capture Effects

AEC System Filter


Exposing Hardware-Accelerated Capture Effects

In Windows XP and later, the WDM audio framework supports hardware acceleration of audio-capture effects that are exposed through DirectSound. These effects include AEC (acoustic echo cancellation) and NS (noise suppression). A miniport driver can expose hardware acceleration for any subset of these effects, depending on the capabilities of the underlying device.

In order to expose the hardware's capabilities for AEC and NS effects, each pin on the AEC filter that the driver implements should meet these requirements:

  • The pin should include an individual node in its node chain to represent each hardware effect that is to be incorporated into the graph. The KS node types for AEC and NS effects are specified by the following GUIDs:

    KSNODETYPE_ACOUSTIC_ECHO_CANCEL

    KSNODETYPE_NOISE_SUPPRESS

  • The AEC and NS nodes on the pin should support the KSPROPSETID_General property set and should provide information about the manufacturer when queried for the KSPROPERTY_GENERAL_COMPONENTID property.
  • The AEC and NS nodes on the pin should support the KSPROPSETID_TopologyNode property set and its two properties:

    KSPROPERTY_TOPOLOGYNODE_ENABLE enables an effect.

    KSPROPERTY_TOPOLOGYNODE_RESET resets the effect to its default state.

    The driver should disable both AEC and NS effects by default. A disabled AEC or NS node operates in pass-through mode, which allows the data stream to pass through the node without modification.

  • The AEC and NS nodes on the pin should support the following properties of the KSPROPSETID_Audio property set:

    KSPROPERTY_AUDIO_CPU_RESOURCES

    KSPROPERTY_AUDIO_ALGORITHM_INSTANCE

  • The pin should support the following properties of the KSPROPSETID_Audio property set:

    KSPROPERTY_AUDIO_POSITION

    KSPROPERTY_AUDIO_LATENCY

  • The pin should expose its data-range capabilities (see Audio Stream Data Formats).

The specific requirements for exposing hardware-accelerated AEC and NS nodes are presented below.

Acoustic Echo Cancellation

A PCM miniport driver exposes hardware support for AEC in the form of a topology for both the capture and render streams that meets this additional requirement:

  • The pin must include an AEC node (KSNODETYPE_ACOUSTIC_ECHO_CANCEL), which must be specified in its proper position in the ordered node chain (see below).

Noise Suppression

A PCM miniport driver exposes hardware support for NS in the form of a topology for the capture stream that meets this additional requirement:

  • The pin must include an NS node (KSNODETYPE_NOISE_SUPPRESS), which must be specified in its proper position in the ordered node chain (see below).

Node-Chain Ordering

Currently, the DirectSound capture-effects architecture requires that the nodes be specified in the order in which they are requested by the application. As a result, the order in which the miniport driver specifies its nodes must match the order that is used by the AEC system filter (aec.sys), which implements the AEC and NS algorithms in software.

To enable hardware acceleration, the driver must specify the effects that are implemented by the hardware in the following order:

KSNODETYPE_ADC

KSNODETYPE_ACOUSTIC_ECHO_CANCEL

KSNODETYPE_NOISE_SUPPRESS

Note that this list can omit any unimplemented effects as long as the relative ordering is preserved.

AEC Node Pin Assignments

An adapter driver uses an array of PCCONNECTION_DESCRIPTOR structures to specify the connections within a filter. Each array element describes one connection, which can be node-to-node, node-to-pin, or pin-to-pin. For details, see Nodes and Connections.

In order to use the PCCONNECTION_DESCRIPTOR structure, the driver writer assigns "logical" pins to nodes. These are "pins" on the nodes themselves and are used solely to specify the connections inside the filter. This is in contrast to the external pins on the filter, which are used to connect to other filters.

The table below shows the pin IDs that the adapter driver should assign to the four logical pins on the AEC node.

Pin ID parameter name | Value | Meaning
KSNODEPIN_AEC_RENDER_IN | 1 | Sink pin (node input) for render stream.
KSNODEPIN_AEC_RENDER_OUT | 0 | Source pin (node output) for render stream.
KSNODEPIN_AEC_CAPTURE_IN | 2 | Sink pin (node input) for capture stream.
KSNODEPIN_AEC_CAPTURE_OUT | 3 | Source pin (node output) for capture stream.

The pin IDs above are defined in the header file ksmedia.h.

The code example below shows how an adapter driver can specify the internal topology of an AEC filter that contains both an AEC node and an NS node:

    // AEC Filter Topology

    // Pin IDs for external pins on AEC filter
    #define ID_CaptureOutPin   0   // microphone stream
    #define ID_CaptureInPin    1
    #define ID_RenderOutPin    2   // speaker stream
    #define ID_RenderInPin     3

    // Generic pin IDs for simple node with one input and one output
    #define NODE_INPUT_PIN     1
    #define NODE_OUTPUT_PIN    0

    // Node IDs
    #define NODE_ID_AEC        0   // acoustic echo cancellation
    #define NODE_ID_NS         1   // noise suppression

    // The array below defines the internal topology of an
    // AEC filter that contains an AEC node and an NS node.

    const PCCONNECTION_DESCRIPTOR AecConnections[] = {
        { PCFILTER_NODE, ID_RenderInPin,       NODE_ID_AEC,    KSNODEPIN_AEC_RENDER_IN  },
        { NODE_ID_AEC,   KSNODEPIN_AEC_RENDER_OUT,   PCFILTER_NODE,  ID_RenderOutPin    },
        { PCFILTER_NODE, ID_CaptureInPin,      NODE_ID_AEC,    KSNODEPIN_AEC_CAPTURE_IN },
        { NODE_ID_AEC,   KSNODEPIN_AEC_CAPTURE_OUT,  NODE_ID_NS,     NODE_INPUT_PIN     },
        { NODE_ID_NS,    NODE_OUTPUT_PIN,      PCFILTER_NODE,  ID_CaptureOutPin   }
    };

The AecConnections array in the code example above defines the filter topology that is shown in the figure below.

Example: Internal Topology of an AEC Filter

The figure above represents each connection inside the filter with a dashed arrow that points in the direction of data flow. A total of five connections appear in the figure. Each connection corresponds to one of the five elements in the AecConnections array in the code example.


AEC System Filter

The AEC system filter (aec.sys) implements the AEC and NS algorithms in software. An audio filter graph that incorporates a capture effect that is implemented in the AEC system filter is subject to the following restrictions:

  • The graph can handle only PCM data formats.
  • The capture and render streams must have the same sample rate.
  • The AEC and NS nodes can handle only monophonic streams. If the capture stream is multichannel (for example, stereo), all channels other than the first are ignored. Only monophonic streams can be connected on the render side.
  • The sample rate for the stream must be between 8 and 16 kHz or between 44 and 48 kHz.
  • The bit depth must be 16 bits for the capture stream and 8 or 16 bits for the render stream.
  • The clock rate must be matched between the capture and render streams. The current AEC system filter implements no mechanism for matching sample rates across devices. This precludes using AEC when the capture and render functions are performed by different devices.
  • When the AEC system filter is used, the SysAudio system driver turns off hardware acceleration for mixing, sample-rate conversion, 3D spatialization, and so on. All mixing of streams is done in software emulation by KMixer.
  • No "non-linear" signal processing can occur before the AEC or NS node on the capture side of the graph or after the AEC or NS node on the render side. This means that GFX (global effects) filtering cannot be performed on a capture stream that uses the AEC system filter. However, you can do GFX on a render stream by inserting the GFX node upstream from the AEC or NS node in the render graph.
  • AEC filtering cancels only echoes coming from the AEC-filtered channels in your computer. Audio that is output through channels that do not pass through AEC will not be echo-canceled. Echoes in a non-AEC audio channel are functionally equivalent to echoes in the audio that is playing on a radio in the office next to your computer. AEC has no way of canceling (and no effect on) echoes from either a radio or a non-AEC channel.

The above requirements apply to all kernel-streaming audio filter graphs that incorporate capture effects that are implemented in aec.sys. These restrictions reflect fundamental assumptions in the design and implementation of the AEC system filter for Windows XP. The constraints on stream formats might change in future versions of Windows.

DirectSound applications can create capture and render streams with sample rates and bit depths that fall outside the constraints described above and then rely on KMixer to do sample-rate conversion on both the capture and render streams. However, the overall audio quality will still depend on the sample rates and bit depths given above because the audio card will have to use a data format that works with the AEC system filter.

Any product design that uses the AEC system filter will need to take the above constraints into account. You should be able to evaluate a particular audio system in the light of these constraints to determine how AEC filtering will behave. Here are some example questions and answers:

Q: I've created a DirectSound buffer for stereo rendering, but both channels sound the same when I'm using AEC. Why is this?

A: AEC works only on mono streams, so KMixer is mixing the stereo stream back to mono to meet this constraint.

Q: Why does my 44-kHz, 16-bit audio sound like 16 kHz when I use AEC?

A: Because KMixer is sample-rate converting the audio stream to 16 kHz to meet the AEC frequency constraints.

Q: Why can't I get a hardware-accelerated DirectSound buffer with AEC?

A: Because SysAudio turns off hardware-accelerated mixing when AEC is enabled.


Supporting Non-PCM Wave Formats

In Windows 98 and Windows 2000, the WDM audio framework did not allow Windows clients to use the standard audio APIs (waveOut, DirectSound, and DirectShow) to play non-PCM audio data through the PortCls system driver.

This limitation has been removed in Windows Me, and Microsoft® Windows® XP and later, which can play audio data encoded in a non-PCM format such as AC3. In addition, a QFE (quick-fix engineering) package is available for Windows 98 SE that contains all fixes necessary to play non-PCM data through waveOut and DirectSound. Service Pack 2 for Windows 2000 also contains these fixes.

This section describes limitations in earlier versions of Windows that prevented clients from playing non-PCM audio, and presents a set of guidelines for adapting a WDM audio driver to support non-PCM data formats on more recent versions of Windows.


Background of Non-PCM Support

Several issues prevented earlier versions of Windows from supporting non-PCM formats through the waveOut and DirectSound APIs. These issues and how they have been resolved are discussed below.

waveOut API

The software layer that separates waveOut applications from VxD wave drivers is fairly thin. Drivers and applications that support a custom wave format can stream data in that format regardless of whether the operating system understands the format.

However, in Windows 98 and Windows 2000, the WDM audio framework forces all the audio data that is processed by the waveOut API (and DirectShow's waveOut renderer) to pass through the KMixer system driver (kmixer.sys), which is the kernel audio mixer. A waveOutOpen call succeeds only if KMixer supports the format, regardless of whether the driver supports the format.

KMixer handles WAVE_FORMAT_PCM on all WDM operating systems. Windows 98 SE, and Windows 2000 and later, extend KMixer to support not only WAVE_FORMAT_IEEE_FLOAT but also WAVEFORMATEXTENSIBLE variants of PCM and IEEE-float formats. Because KMixer supports no non-PCM formats, an attempt to pass non-PCM data through KMixer will fail.

Windows Me, and Windows XP and later, support non-PCM formats by allowing non-PCM audio data to simply bypass KMixer. Specifically, waveOut non-PCM data flows directly to PortCls (or USBAudio) instead of first passing through KMixer. Any mixing of non-PCM data must be done in hardware, but applications that use non-PCM data in a format such as AC3 typically do not require mixing and drivers typically do not support hardware mixing in that format.

DirectSound API

On legacy waveOut drivers and VxD drivers, DirectSound supports WAVEFORMATEX (but not WAVEFORMATEXTENSIBLE) PCM formats for both primary and secondary buffers, with 8 or 16 bits per sample, one or two channels, and a sampling rate between 100 Hz and 100 kHz. VxD drivers can further limit the formats allowed for primary buffers when the cooperative level is set to DSSCL_WRITEPRIMARY (see the description of the IDirectSoundBuffer::SetFormat method in the DirectX SDK). These limitations have not changed in Windows Me or Windows XP.

WDM drivers can support PCM formats in both WAVEFORMATEX and WAVEFORMATEXTENSIBLE form. For Windows 98 SE, Windows Me, and Windows 2000 and later, drivers can also support the WAVE_FORMAT_IEEE_FLOAT format for both primary and secondary DSBCAPS_LOCSOFTWARE buffers (mixed by KMixer) in both WAVEFORMATEX and WAVEFORMATEXTENSIBLE form.

Calling SetFormat to specify the data format of a primary buffer has only an indirect effect on the final mixing format chosen by the sound card. The primary buffer object is used to obtain the IDirectSound3DListener interface and to set the device's global volume and pan, but does not represent the single output stream from the sound card. Instead, KMixer mixes the primary-buffer data in order to allow several DSSCL_WRITEPRIMARY DirectSound clients to run simultaneously.

On Windows 98 and Windows 2000, DirectSound supports only PCM data. (The same is true of DirectShow, which uses DirectSound's renderer.) A call to CreateSoundBuffer with a non-PCM format always fails, even if the driver supports the format. Failure occurs for two reasons. First, whenever DirectSound creates a KS pin, it automatically specifies KSDATAFORMAT_SUBTYPE_PCM instead of deriving the subtype from the wFormatTag member of the WAVEFORMATEX structure that is used to create the IDirectSoundBuffer object. Second, DirectSound requires every data path to have volume and SRC (sample-rate conversion) nodes (see KSNODETYPE_VOLUME and KSNODETYPE_SRC), regardless of whether the client requests pan, volume, or frequency controls on the DirectSound buffer. This requirement is met if either the data passes through KMixer or the device performs hardware mixing. For non-PCM formats, however, KMixer is not present in the data path and the drivers themselves typically fail when asked to perform hardware mixing.

Windows Me, and Windows XP and later, remove the limitations that prevented DirectSound applications from using non-PCM formats. DirectSound 8 (and later versions) uses the correct format subtype and no longer automatically requires volume and SRC nodes in every data path.


Requirements for a Non-PCM Pin Factory

Under Windows Me, and Windows XP and later, drivers that play non-PCM WAVEFORMATEX formats should expose their non-PCM pins according to the following guidelines.

First, define a pin factory for your non-PCM data format that is separate from any PCM pin factories. PCM and non-PCM cannot share the same single-instance pin factory because the sole pin instance will automatically be allocated to KMixer. If the pin factory supports multiple instances, PCM and non-PCM can co-exist on the same pin factory. In this case, however, you cannot guarantee that these pin instances will be available to a non-PCM client at runtime; PCM clients might have already allocated them. The safest option is to provide a separate pin factory for your non-PCM format.

In order for the pin to be discovered and used by DirectSound 8, you must define this non-PCM pin factory on a filter that already supports PCM. In other words, do not put the non-PCM pin in a totally separate filter in your miniport. Otherwise, DirectSound will not detect the non-PCM pin. This also means that a device that does not support PCM at all cannot support a non-PCM format either.

Second, implement a data-range-intersection handler on your non-PCM pin. PortCls provides a built-in handler, but this default handler always chooses PCM, so you will need to add your own. You should not support WAVE_FORMAT_PCM in the intersection handler for your non-PCM pin. Note that this handler can be called with an OutputBufferLength of 0, in which case the caller is asking only for the size of the preferred data range, not for the data itself. In this case, the handler should respond by copying the non-PCM data range's size into the ResultantFormatLength parameter and returning STATUS_BUFFER_OVERFLOW. The msvad sample in the DDK contains the code for a DataRangeIntersection routine that you can use as an example handler. To test your DataRangeIntersection routine, use the KsStudio utility to instantiate your pin—it first calls your intersection handler in order to determine an acceptable default format. (KsStudio is included with the DDK tools.) To support a non-PCM format, your driver must properly handle it in the following locations:

  • IMiniport::DataRangeIntersection method
  • miniport methods Init and NewStream (See IMiniportWavePci, for example.)
  • miniport-stream method SetFormat (See IMiniportWavePciStream::SetFormat, for example.)


Converting Between Format Tags and Subformat GUIDs

The guidelines for handling non-PCM WAVE_FORMAT_EXTENSIBLE formats are similar to those for non-PCM formats that are specified by wave-format tags. Specifically, a WAVE_FORMAT_EXTENSIBLE format should have a pin factory separate from the factory for PCM formats, and it requires its own data-range intersection handler.

The audio format for a WAVE_FORMAT_EXTENSIBLE format is specified by the GUID in the SubFormat member of the KSDATAFORMAT structure. Every registered wave-format tag has a corresponding subformat GUID, which is generated by the DEFINE_WAVEFORMATEX_GUID macro in ksmedia.h. For example, the GUID corresponding to the WAVE_FORMAT_DOLBY_AC3_SPDIF tag is defined as DEFINE_WAVEFORMATEX_GUID(WAVE_FORMAT_DOLBY_AC3_SPDIF).

This code snippet from ksmedia.h shows how to define a new GUID as an autoinitialized static variable:

#define STATIC_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX \
    0x00000000L, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
DEFINE_GUIDSTRUCT("00000000-0000-0010-8000-00aa00389b71", KSDATAFORMAT_SUBTYPE_WAVEFORMATEX);
#define KSDATAFORMAT_SUBTYPE_WAVEFORMATEX DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_WAVEFORMATEX)

These macros from ksmedia.h convert between wave-format tags and their associated GUIDs:

#if !defined( DEFINE_WAVEFORMATEX_GUID )
#define DEFINE_WAVEFORMATEX_GUID(x) \
    (USHORT)(x), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
#endif

#define INIT_WAVEFORMATEX_GUID(Guid, x) \
{ \
    *(Guid) = KSDATAFORMAT_SUBTYPE_WAVEFORMATEX; \
    (Guid)->Data1 = (USHORT)(x); \
}

#define IS_VALID_WAVEFORMATEX_GUID(Guid) \
    (!memcmp(((PUSHORT)&KSDATAFORMAT_SUBTYPE_WAVEFORMATEX) + 1, \
    ((PUSHORT)(Guid)) + 1, sizeof(GUID) - sizeof(USHORT)))

#define EXTRACT_WAVEFORMATEX_ID(Guid)    (USHORT)((Guid)->Data1)

The sample code below combines these techniques to create a subformat GUID that is based on the wave-format tag WAVE_FORMAT_AC3_SPDIF, which has the value 0x0092:

#define STATIC_KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF \
    DEFINE_WAVEFORMATEX_GUID(WAVE_FORMAT_DOLBY_AC3_SPDIF)

DEFINE_GUIDSTRUCT("00000092-0000-0010-8000-00aa00389b71",
    KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF);

#define KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF \
    DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF)
…
INIT_WAVEFORMATEX_GUID(pMyGuid,myWaveFormatTag);
…
if (IS_VALID_WAVEFORMATEX_GUID(aWaveFormatExGuidPtr)) {
    aWaveFormatTag = EXTRACT_WAVEFORMATEX_ID(aWaveFormatExGuidPtr);
}


KS Topology Considerations

The WDMAud system driver (wdmaud.sys) translates the KS-filter topology into the legacy mixer lines that are exposed through the mixer API. A non-PCM pin corresponds to a SRC line (MIXERLINE_COMPONENTTYPE_SRC_XXX) in the mixer API. If this pin is in a data path that eventually flows into a bridge pin (the physical connection at the endpoint of a graph) that is dedicated to non-PCM data, the mixer API exposes the bridge pin as an additional DST line (MIXERLINE_COMPONENTTYPE_DST_XXX), separate from the DST line for PCM data. This can add unnecessary complexity to the controls that are visible through a mixer-API client such as a replacement for the SndVol32 utility. If you prefer not to expose a non-PCM pin in this manner, one approach is to make sure that the data path that contains the pin eventually feeds into a SUM node that is shared by the PCM data path. That is, join the non-PCM DST line to the main DST line. Unfortunately, this workaround misrepresents the true hardware topology and might lead to future problems with clients that attempt to control the non-PCM data stream through nodes downstream from the SUM node. A better approach is to modify the mixer-API client to simply ignore SRC and DST lines that have no controls.

If you use the KsStudio utility (included with the DDK tools) to view your wave filter in KSCATEGORY_AUDIO, you should expect to see a separate pin for non-PCM data. When viewing the composite system audio graph under KSCATEGORY_AUDIO_DEVICE, you should see your non-PCM data ranges on the main wave-output pin, alongside any PCM data ranges. Note that SysAudio (sysaudio.sys), the system audio device, generates KSCATEGORY_AUDIO_DEVICE automatically—a driver should not register itself manually in this category.

You are not required to connect a non-PCM data path to the topology miniport. This connection is of benefit only if the non-PCM data path interacts with the rest of the device's topology; for instance, if it feeds into a common mixer or sample-rate converter. Connecting a streaming pin to a bridge pin, where both pins are on the wave miniport, forms a valid, complete topology for a non-PCM data stream that flows directly to an S/PDIF port, for example.


Specifics for waveOut Clients

A call to waveOutOpen returns WAVERR_BADFORMAT if a driver does not support the specified wave format.

Windows does not currently support the looping of a wave header with a non-PCM format. An attempt to loop a non-PCM format will fail, but the system does not detect the failure until the header-submittal (not header-preparation) stage because of architectural constraints. Specifically, a call to waveOutPrepareHeader might accept a non-PCM wave header with WHDR_BEGINLOOP and/or WHDR_ENDLOOP set in dwFlags, but a subsequent call to waveOutWrite will fail and return MMSYSERR_INVALPARAM. If WHDR_BEGINLOOP and WHDR_ENDLOOP are not set in dwFlags, however, specifying dwLoops>1 will not cause waveOutWrite to fail.

When non-PCM data is playing, a call to waveOutBreakLoop fails with return code MMSYSERR_INVALPARAM.


Specifics for DirectSound Clients

On Windows 98 and Windows 2000, DirectSound does not support non-PCM formats, regardless of the DirectSound version. (However, DirectSound 8 does support non-PCM formats on both Windows 98 SE + QFE and Windows 2000 SP2. Also, the versions of DirectSound that ship with Windows Me, and Windows XP and later, support non-PCM formats.)

To determine whether a WDM driver supports a particular wave format, a client can attempt to create a DSBCAPS_LOCHARDWARE buffer in that format on the driver and see if the attempt succeeds. The DirectSound API provides no other way to discover which non-PCM data formats are supported.

DirectSound allows secondary DSBCAPS_LOCHARDWARE buffers to have any valid WAVEFORMATEX or WAVEFORMATEXTENSIBLE format that the selected driver supports. When searching for the format in the driver's list of supported formats, DirectSound checks only for formats that contain the KSDATAFORMAT_SPECIFIER_DSOUND specifier.

You can extend a DirectSound application to use a non-PCM format by first creating a WAVEFORMATEX or WAVEFORMATEXTENSIBLE structure that describes the format. Next, load a pointer to the structure into the lpwfxFormat member of the DSBUFFERDESC structure that is passed to the CreateSoundBuffer method. No other changes to existing DirectSound code are required in order to use a non-PCM format. Note that the controls that a driver typically supports for PCM data are unlikely to be supported for some non-PCM formats. For example, a card that supports digital output of AC3-encoded data is unlikely to support the DSBCAPS_CTRLPAN or DSBCAPS_CTRLVOLUME controls on that data, so attempting to create the DirectSound buffer with those flags can fail.

DirectSound playback through VxD drivers or legacy waveOut drivers is still limited to PCM; non-PCM formats are not supported.


AC3 Data Ranges

Wave-format tag 0x0092 is defined as AC3-over-S/PDIF. Tags 0x0240 and 0x0241 are synonymous with 0x0092 and many DVD applications treat the three tags as identical. To eliminate redundancy, however, drivers and applications should support only tag 0x0092 (and not support tags 0x0240 and 0x0241).

When AC3 data passes over an S/PDIF link in digital form without being decoded, it can be treated the same as a two-channel, 16-bit, 48-kHz PCM stream. In fact, when specifying an AC3-over-S/PDIF data range, the wave-format tag itself is the only thing that differs from a data range of PCM data being output through the S/PDIF port.

AC3 data is streamed in units called frames. Each frame can be independently decoded into 1536 samples of PCM audio (multiplied by the number of channels in the frame). This represents 32 milliseconds of audio at a 48-kHz sample rate. A 5.1-channel AC3 frame occupies fewer bytes than 1536 stereo PCM samples. (There are exceptions to this, but those types of AC3 frames are very uncommon, cannot be transmitted over S/PDIF, and can be ignored here.) In order to avoid delivering the compressed audio bitstream over the S/PDIF interface faster than real time (that is, to prevent delivery of 32 milliseconds of audio in less than 32 milliseconds), an AC3 frame must be padded with zeros until it takes up the same number of bytes as 1536 stereo PCM samples.

If you attempt to send unpadded AC3 to a PortCls adapter driver that uses WaveCyclic, be aware that when the port driver senses data starvation (because the data stream contains fewer bytes than a two-channel uncompressed stream would), it will fill the cyclic buffer with silence. The AC3 decoder is likely to have problems interpreting these periods of silence, which are in PCM rather than AC3 format.

If you are passing AC3 through an S/PDIF port to a decoder, you should indicate that the stream is in a non-PCM format by setting the /AUDIO bit on the S/PDIF transceiver. The decoder reads this bit from the S/PDIF channel-status block to determine whether the data stream is encoded in a non-PCM format.


Declaring Non-PCM Data Ranges

This code example shows how to declare the KSDATARANGE_AUDIO table entries for the AC3-over-S/PDIF format:

static KSDATARANGE_AUDIO PinDataRangesAC3Stream[] =
{
  {
    {
      sizeof(KSDATARANGE_AUDIO),
      0,
      0,
      0,
      STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
      STATICGUIDOF(KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF),
      STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
    },
    2,     // Max number of channels.
    16,    // Minimum number of bits per sample.
    16,    // Maximum number of bits per channel.
    48000, // Minimum rate.
    48000  // Maximum rate.
  },

  // If you do not include this second data range (which is identical
  // except for the SPECIFIER_DSOUND), then your non-PCM pin will
  // not be seen by DirectSound on Win98SE or Win2K, regardless
  // of the presence of QFE/service pack or the DirectX version.
  //
  {
    {
      sizeof(KSDATARANGE_AUDIO),
      0,
      0,
      0,
      STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
      STATICGUIDOF(KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF),
      STATICGUIDOF(KSDATAFORMAT_SPECIFIER_DSOUND)
    },
    2,     // Max number of channels.
    16,    // Minimum number of bits per sample.
    16,    // Maximum number of bits per channel.
    48000, // Minimum rate.
    48000  // Maximum rate.
  }
};

The second data-range entry in the table above is necessary to enable DirectSound to handle the non-PCM AC3-over-S/PDIF format on Windows 98 SE + QFE and Windows 2000 SP2.

For each data range that the miniport driver specifies with KSDATAFORMAT_SPECIFIER_WAVEFORMATEX, PortCls automatically adds a second data range that is specified with KSDATAFORMAT_SPECIFIER_DSOUND but is otherwise identical to the first. (You can verify this by using the KsStudio utility to view the list of data ranges. KsStudio is included with the DDK tools.) On Windows 98 and Windows 2000, PortCls creates KSDATAFORMAT_SPECIFIER_DSOUND versions of data ranges only for KSDATAFORMAT_SUBTYPE_PCM formats because DirectSound versions before DirectSound 8 support only PCM. This limitation is removed in Windows Me, and Windows XP and later, but is not fixed in the QFE for Windows 98 or in Windows 2000 SP2. In order for a driver to support non-PCM on DirectSound on these Windows versions, it should explicitly list two data ranges for each non-PCM data format—one with KSDATAFORMAT_SPECIFIER_WAVEFORMATEX and another with KSDATAFORMAT_SPECIFIER_DSOUND.


USB Audio Support for Non-PCM Formats

Microsoft's USB Audio driver does not currently support USB Audio Type III formats with padded AC3. (See the Universal Serial Bus Device Class Definition for Audio Data Formats for more information.)

USBAudio.sys, the USB audio system driver, can accept packed, "raw" AC3 (as opposed to the padded, AC3-over-S/PDIF format accepted by the PortCls driver). USBAudio supports the internal format of DirectShow's DVD-splitter filter, which can be connected directly to USBAudio under the control of KsProxy. Specifically, the non-padded AC3 data range exposed by USBAudio is KSDATAFORMAT_SUBTYPE_AC3_AUDIO, which is the same GUID as MEDIASUBTYPE_DOLBY_AC3.

USBAudio currently does not support DirectSound playback of non-PCM audio data.


Additional Requirements for Windows 98

In Windows 98, a bug in the system graph builder prevents a KSCATEGORY_AUDIO_DEVICE wave-data path from operating correctly unless it contains at least one node. Because PCM pins are either hardware mixing pins (with SUM, volume, and SRC nodes, for example; see KSNODETYPE_SUM, KSNODETYPE_VOLUME, and KSNODETYPE_SRC) or have KMixer (and its nodes) inserted above them, this problem affects non-PCM pins only. In order for your driver to work on Windows 98 SE + QFE, make sure that the data path through a non-PCM pin always has at least one node. When passing AC3 over S/PDIF, for example, you can add a KSNODETYPE_SPDIF_INTERFACE node that implements a property to manipulate the SCMS (serial copy management system) bits.

The earliest QFE package for Windows 98 SE that contains the fix to enable AC3-over-S/PDIF playback is the following:

QFE number | Executable file | Release date
WinSE 9724 | 269601USA8.EXE | 8/9/2000

All later QFEs for Windows 98 SE also contain this fix.

This QFE installs updated versions of the following audio system files:

  • kmixer.sys
  • portcls.sys
  • sbemul.sys
  • sysaudio.sys
  • usbaudio.sys
  • wdmaud.sys
  • wdmaud.drv

The IPortClsVersion interface is not available in this QFE, which means that this interface cannot be used to detect the presence of the QFE. The best way to determine whether the QFE is installed is to try to access the following registry key:

  • registry path: HKLM\Software\Microsoft\Windows\CurrentVersion\Setup\Updates\W98.SE\UPD\269601
  • member: UpdID
  • value: 269601


KMixer Driver Sample Rate Conversion and Mixing Policy

This section describes the following topics about the KMixer system driver, which is the kernel-mode system driver that mixes kernel-streaming (KS) audio streams:

Types of Sample Rate Conversion

Policy for Sample Rate Conversion of Audio Streams

Policy for Mixing Audio Streams and Setting the Output Sample Rate


Types of Sample Rate Conversion

The different kinds of sample-rate conversion (SRC) that the KMixer system driver can perform are shown in the following table.

Type of Sample Rate Conversion | Characteristics
Linear interpolation | Uses linear interpolation to achieve reasonable results if converting similar sampling rates, for example, converting a 12-kHz rate to a 13-kHz rate. DirectSound® applications use linear interpolation by default.
Multipoint interpolation | Uses a simplified version of high-end multipoint interpolation to achieve a signal-to-noise ratio of approximately 70 dB.
High-end multipoint interpolation | Uses oversampling to achieve a signal-to-noise ratio greater than or equal to 90 dB.
Add/Drop (also known as truncation or nearest neighbor) | Uses a simple replacement technique that minimizes system load, but achieves the lowest quality. This type of SRC is only used if system constraints prevent using one of the higher quality types of SRC.

KMixer uses software emulation to implement all the above SRC techniques.


Policy for Sample Rate Conversion of Audio Streams

This section describes the policy that the KMixer driver uses for sample-rate conversion (SRC).

The KMixer driver only does SRC on audio streams if it must do so to match the sample rate of more than one stream. Most applications that use more than one audio stream use the same sample rate for each stream. However, the KMixer driver uses the following client-based policy to match sampling rates:

  • DirectSound clients

    For rendering streams, the user-mode multimedia control panel gives a user some control over which type of SRC the KMixer driver uses with DirectSound. The slider shown in the Advanced Audio Properties dialog associates "Good" through "Best" to linear, multipoint interpolation, and high-end multipoint interpolation, respectively. Linear interpolation is the default for DirectSound 6.0 and later versions.

    For capture streams, the KMixer driver always uses high-end multipoint interpolation.

  • All other audio stream clients

    The KMixer driver always uses high-end multipoint interpolation for render and capture streams that are associated with the Windows® Multimedia System, Redbook CD, and the Sound Blaster emulator and software synthesizer.

The following table categorizes types of Windows audio applications and the system component that each type of application uses.

Audio Application | System Component
Windows 98 Sound Recorder | MMSystem
Windows 98 Media Player | DirectSound
DirectX | DirectSound
Most game titles | DirectSound
Most high-end wave editors | MMSystem


Policy for Mixing Audio Streams and Setting the Output Sample Rate

This section describes the following topics about the algorithm that the KMixer driver uses to minimize SRC (sample-rate conversion) and mixing:

Connecting the First Audio Stream

Connecting Additional Audio Streams

Special Cases

Connecting the First Audio Stream

  • When the SysAudio driver initializes the KMixer driver for an audio device, it assigns a sample rate corresponding to the higher of 44.1 kHz and the highest rate available on the audio device. The highest rate that the KMixer driver supports is 100 kHz. Note that the Miniport request handler returns the rates available on the device.
  • When a client requests to connect an audio stream to a device, the KMixer driver queries the device to determine if it supports the incoming rate. If the device supports the incoming rate, the KMixer driver passes the incoming stream to the device without SRC. Otherwise, the KMixer driver maintains the current output rate, and does the following:
    • If the device supports the current output rate, the KMixer driver uses SRC to convert the input rate to the current output rate.
    • If the device does not support the current output rate, the KMixer driver maintains the current rate and fails the client's request to connect the audio stream to the device.

Connecting Additional Audio Streams

The following summarizes the policy on rate conversion and mixing for input streams that clients attempt to connect after connecting the first input stream (in the order that the KMixer driver applies the tests):

Rate Test | Rate Conversion and Mixing Policy
New incoming rate is equal to the current output rate. | Perform mixing only.
New incoming rate is equal to the rate of another input stream. | Mix the new input stream with the other input stream at the same rate to take advantage of the existing SRC from input to output.
New incoming rate is lower than the current maximum input rate. | Do SRC to the current output rate and mix.
New incoming rate is higher that the current maximum input rate. | If the hardware supports the new input rate: Change the current maximum output rate and the hardware rate to the new incoming rate. Do SRC on all other streams to the new maximum output rate and mix them with the new stream. If the hardware does not support the new input rate, maintain the current output rate and do SRC on the new incoming stream to the current maximum input rate.

Special Cases

  • The KMixer driver does not adjust its output rate when a client makes an IDirectSoundBuffer::SetFrequency call on a DirectSound buffer. The KMixer driver only adjusts the output rate when the buffer is first played.
  • The Sound Blaster emulator (see SBEMul System Driver) performs dynamic adjustments to its sample rate. The KMixer driver maintains an output rate greater than or equal to the emulator.


Factors Governing Wave-Output Latency

This section describes the sources of latency for a wave-output stream. Some of the factors that affect latency are:

  • whether the stream flows through or bypasses KMixer
  • whether the stream is output to a WaveCyclic or WavePci device
  • whether the stream is generated by DirectSound or the waveOut API

The following topics are discussed:

KMixer Latency

WaveCyclic Latency

WavePci Latency

Avoiding Data Copying


KMixer Latency

Inserting KMixer, the system software mixer, into a wave-data stream adds KMixer's inherent latency to the total latency of that stream.

DirectSound streams that feed into hardware mixer pins bypass KMixer and avoid the latency of software mixing in KMixer. DirectSound will make use of all of an audio device's available hardware-accelerated mixer pins as long as those pins have a topology that conforms to the node ordering that DirectSound requires.

In all current versions of Windows, including Windows Me and Microsoft® Windows® XP, the waveOut API has a limitation that prevents it from taking advantage of all available hardware acceleration. An audio stream that is output by the waveOut API always passes through KMixer, even if the audio device provides hardware-accelerated mixing. If waveOut and DirectSound audio streams are played concurrently, the DirectSound audio streams can still use any available hardware-mixing pins, although the waveOut streams will all pass through KMixer and go to a single hardware buffer.

Other non-DirectSound stream sources have limitations similar to those of waveOut that prevent them from using hardware-accelerated mixing. These sources include:

  • Redbook filter (See Redbook System Driver.)
  • Sound Blaster emulator (See SBEMul System Driver.)
  • Kernel-mode software synthesizers (See SWMidi System Driver and DMusic System Driver.)
  • DRMK, the Digital Rights Management decryption module (See DRM Overview.)

Similar to waveOut streams, streams from the four sources above always pass through KMixer but can play concurrently with hardware-accelerated DirectSound streams.

If an audio device performs hardware mixing, streams that feed directly into the hardware mixing pins bypass KMixer and avoid the KMixer latency. The SysAudio system driver always reserves one hardware pin for KMixer so that after the other (unreserved) hardware pins have all been allocated, any additional streams can be mixed by KMixer and fed into the reserved hardware pin.

In the case of a single-stream device, KMixer is always instantiated on the one available rendering pin.

KMixer's buffer-management policy determines its latency. Upon being instantiated, KMixer initially allocates three buffers for wave data. After that, KMixer makes sure that a minimum of two buffers are queued at the miniport at all times. At any moment, the miniport has access to at least two buffers: the buffer that the device is currently reading and a second buffer that the miniport can switch to immediately when the first buffer is exhausted. Meanwhile, KMixer can write new data into the third buffer.

If at any time the driver has less than two buffers, KMixer interprets this as a starvation condition and begins allocating additional buffers. If starvation continues, KMixer can allocate up to eight buffers, but it allocates no further buffers once this limit is reached. Consequently, a driver might find as many as eight buffers in its queue following a period of severe starvation.

The parameters described above are specific to the current implementation of KMixer and may change in future versions of Windows.


WaveCyclic Latency

If your WaveCyclic miniport provides hardware mixing, DirectSound will submit an IRP to the WaveCyclic port-class driver that contains the entire DirectSound wave stream in a single cyclic buffer. The WaveCyclic port receives the IRP and feeds the wave data piece-by-piece into the DMA buffer that your driver exposes. WaveCyclic attempts to keep the DMA buffer's write pointer about forty milliseconds ahead of the read pointer. Even when your driver is doing hardware mixing with DirectSound, it can expect about forty milliseconds of extra data in the DMA buffer.

After a period of near starvation, a KMixer stream can contain intervals of silence. If WaveCyclic has received only enough wave data from KMixer to maintain thirty rather than forty milliseconds of extra data in the DMA buffer, WaveCyclic will begin writing silence into the DMA buffer following the end of the valid data from KMixer. This policy ensures that if starvation occurs and the device reads past the end of the valid data, the audio device will render silence instead of stale or uninitialized data.

The amount of silence written to the DMA buffer is kept fairly small, and if KMixer does succeed in supplying the WaveCyclic port with additional data before the silence has been played, that data overwrites the silence in the buffer. In the absence of starvation, the audio device will receive a continuous stream of mixed data without intervals of forced silence. When you are debugging your driver, however, you might see your miniport's IMiniportWaveCyclicStream::Silence method being called even though your audio renderer is not starving.


WavePci Latency

The WavePci port-class driver handles buffering of an audio stream differently from the WaveCyclic driver.

If your WavePci miniport provides hardware mixing, DirectSound will submit an IRP to the WavePci port-class driver that contains the entire DirectSound wave stream in a single cyclic buffer. DirectSound allocates the buffer as a contiguous block of virtual memory. To avoid copying the DirectSound buffer, the kernel-streaming layer maps the buffer into kernel-mode virtual memory and generates a MDL (memory descriptor list) that specifies both the virtual and physical addresses of the memory pages in the cyclic buffer. The WavePci port-class driver partitions the cyclic buffer into a sequence of allocator frames. The miniport specifies the allocator-frame size when its IMiniportWavePciStream::GetAllocatorFraming method is called by the port-class driver during stream initialization. The size must be less than or equal to the page size.

The WavePci port-class driver exposes the cyclic buffer to the miniport as a sequence of mappings. A mapping is either an entire allocation frame or a portion of a frame. If a particular allocation frame lies completely within a page, the port-class driver presents that frame to the miniport as a single mapping. If an allocation frame straddles a page boundary, the port-class driver splits the frame at the page boundary and presents it as two successive mappings. Each call to IPortWavePciStream::GetMapping yields the next successive mapping in the sequence.

In contrast to the WaveCyclic case, where the driver has little control over factors that govern the latency of the audio stream, the WavePci miniport can determine for itself the number of mappings that it has open at any time. The number of open mappings increases by one with each call to GetMapping and decreases by one with each call to ReleaseMapping. By controlling both the number of open mappings and the size of each mapping (the allocation-frame size, to be precise), the miniport can determine the number of milliseconds of buffering that are available to the hardware. Your WavePci miniport should request enough page mappings to reduce the chances of starvation to acceptable levels, but it should not ask for so many that the system latency grows too large.

In general, DMA hardware should be designed to directly access audio frames that are stored at arbitrary byte alignments and that straddle boundaries between noncontiguous pages of physical memory. If you have a device that requires that the mappings be an even integral number of audio frames, that device will be limited in the kinds of audio formats that it can support. Of course, a device with this limitation should still be able to handle an audio frame size that is a power of two. For example, a device with four channels and a 16-bit sample size requires an audio-frame size of eight bytes. An integral number of audio frames fits neatly within a page (or any other allocation-frame size that is a multiple of eight bytes). However, in the case of a 5.1-channel stream with 16-bit samples, the audio frame size is 12 bytes and a stream that exceeds the size of a single page necessarily contains audio frames that straddle page boundaries. Hardware that cannot handle arbitrary byte alignments and arbitrary byte-length mappings must depend on the driver to perform an intermediate copy, which degrades performance.

The ac97 sample adapter driver in the DDK implements a GetAllocatorFraming method that the miniport uses to pass its frame-allocation-size requirements to the kernel allocator. In Windows 2000 and Windows Me, this method is called only when the Splitter system driver (splitter.sys) is instantiated above the output pin. However, in Windows XP and later, the GetAllocatorFraming method determines the allocation-frame size for output as well as for input streams.


Avoiding Data Copying

You can improve driver performance by designing your audio hardware to avoid unnecessary data copying.

For example, a WaveCyclic device can make its hardware buffer directly accessible as system memory in order to avoid the overhead of copying data from an intermediate buffer in system memory.

Also, if your device requires an audio format with a channel ordering that is incompatible with the standard WDM audio formats, the driver might have to perform in-place conversion of each audio frame in an intermediate buffer before the hardware can process it. This can degrade performance. For additional information, see the white paper entitled Enhanced Audio Formats for Multi-Channel Configurations and High-Bit Resolution at www.microsoft.com/hwdev/audio/multichaud.htm.


Digital Rights Management

Digital rights management (DRM) provides content providers with the means to protect their proprietary music or other data from unauthorized copying and other illegal uses. DRM technology protects digital content by encrypting it and attaching to it usage rules that determine the conditions under which a user can play back the content. Usage rules typically prevent copying or limit the number of times the content will play. The operating system works together with drivers to enforce these rules.

DRM is designed to be transparent to users unless they attempt to violate the usage rules that they agreed to when they purchased the digital content.

Any digital-audio content that is protected by DRM can be played only by trusted audio drivers. These are drivers that have been certified by Microsoft to have no loopholes through which the DRM security measures can be circumvented.

DRM certification is optional. A driver that passes the WHQL Windows-logo test but does not pass the DRM-compliance test will still be able to play digital content that is not DRM-protected. However, only DRM-compliant drivers will be able to play DRM-protected content.


DRM Overview

DRM for digital audio is implemented on Windows 98/Me, and Windows 2000 and later. However, only Windows Me, and Microsoft® Windows® XP and later, implement DRM security within the kernel. Currently, Windows provides no DRM security for MIDI streams or for DLS sets.

DRM-protected digital content is stored in encrypted form on a disk or other storage-media type. The encryption algorithm scrambles the content to make it unintelligible until it has been decrypted. During playback, the content remains scrambled as it is read from the disk and buffered in memory. Near the end of the data path, the DRM system (the KS filter drmk.sys) unscrambles the data and feeds it directly to the audio driver to be played. By limiting the extent of the data path over which unscrambled content is transmitted, the DRM system makes the content less vulnerable to unauthorized copying.

In Windows 98 and Windows 2000, a security loophole allows users to easily load rogue drivers that route the playback of secure content to disk in unencrypted form. Windows Me, and Windows XP and later, close this loophole by allowing only trusted audio drivers to play DRM-protected content.

In Windows Me, and Windows XP and later, secure content remains scrambled while it traverses the audio-data path until it enters the protected environment of the kernel. Within the kernel, protected components unscramble the data and feed the unscrambled data to a trusted driver for playback. When configuring a filter graph to play back an unscrambled audio stream, the DRM system authenticates the adapter driver for each KS filter that it places in the graph. The system informs the driver of the usage rules for the protected content. The driver, in turn, advises the DRM system of any downstream filters to which it routes the content, and the system authenticates those filters as well. This process continues until the graph is complete. The system rejects the entire graph if the playback stream passes through any component that is not DRM-compliant.

A DRM-compliant driver must prevent unauthorized copying while digital content is being played. In addition, the driver must disable all digital outputs that can transmit the content over a standard interface (such as S/PDIF) through which the decrypted content can be captured. Note that this requirement does not apply to USB devices. Currently, the DRM system will play secure content only through a USB speaker device with no digital outputs.


Content IDs and Content Rights

A content ID (identifier) is a ULONG value that the DRM system generates at runtime to identify DRM-protected content in the audio-data stream that feeds into a particular pin.

Content rights are a digital representation of the rights granted by the content provider to the user for playing and copying DRM-protected content. Content rights are specified in the form of a DRMRIGHTS structure that the DRM system passes to the driver.

DRMRIGHTS contains two flags: DigitalOutputDisable and CopyProtect. If the DigitalOutputDisable flag is set, the driver must disable any digital outputs that leave the PC system (through an S/PDIF connector, for example). If the CopyProtect flag is set, the driver must disable features that might allow a persistent copy of the secure content to be saved to disk or to any other form of nonvolatile storage. For instance, typical audio hardware allows a playback signal to be routed through the capture channel. If this signal is in digital form, the captured signal may be a perfect digital copy of the input signal. If the playback mix contains data from any stream that has a CopyProtect flag set, the driver must mute the playback-capture path.

A DRM-compliant audio driver must support the IDrmAudioStream interface on its WaveCyclic and WavePci miniport objects, which expose sink pins for rendering audio data. In order to obtain a reference to an IDrmAudioStream object from the driver, the DRM system calls the QueryInterface method on the pin, which has an interface of type IMiniPortWaveCyclicStream or IMiniportWavePciStream. The IDrmAudioStream interface supports only one method, SetContentId (in addition to the three IUnknown methods). When the DRM system calls SetContentId, it passes in a content ID and content rights, which the driver associates with the pin's data stream.

Some audio drivers support hardware mixing and can handle several input data streams at the same time. This type of driver must keep track of both the content IDs for the individual streams and the composite content rights of all the streams. The system provides an IDrmPort interface with several methods that can help your driver keep track of composite rights. Your driver can obtain a reference to an IDrmPort object by passing the GUID IID_IDrmPort to the QueryInterface method on the associated system port driver.


DRM Requirements

This section presents the requirements that an audio miniport driver must meet in order to be certified as DRM-compliant by the Microsoft® Windows® Hardware Quality Lab (WHQL). These requirements apply specifically to PortCls miniports, which are hardware-specific counterparts to the WavePci and WaveCyclic class drivers in PortCls. DRM certification is not currently available for USB drivers.

Windows Me, and Windows XP and later, allow only trusted audio drivers to play DRM-protected content. Windows identifies a trusted driver by means of a DRM-specific digital signature that is stored in the driver's .cat (catalog) files. Microsoft issues a DRM signature only to a hardware vendor whose driver meets the requirements for a trusted driver. The DRM signature is separate from and in addition to the Windows-logo signature.

To qualify as trusted, a driver must pass Microsoft's WHQL DRM-compliance test, which is performed after the driver has successfully passed the WHQL Windows-logo test. The DRM-compliance test is optional and is performed only at the hardware vendor's request. Note that a driver that passes the Windows-logo test but not the DRM-compliance test will still be able to play content that is not protected by DRM security.

The DRM-compliance test requires a trusted audio driver to do the following:

  • The audio miniport driver must implement the IDrmAudioStream interface in its stream objects, which must return an object of type IDrmAudioStream if queried for IID_IDrmAudioStream.
  • When copy protection is requested (DRMRIGHTS.CopyProtect=TRUE), the audio driver must disable the ability to capture the stream currently being played back. This means that the driver must not save the unprotected digital content to any form of nonvolatile storage, which includes hard disk, EEPROM, memory card, and memory stick. Also, the driver must disable the capture multiplexer on an output D/A converter and otherwise prevent the loopback of digital content.
  • When an audio driver is asked to disable the digital audio output on the device (DRMRIGHTS.DigitalOutputDisable=TRUE), it must disable all digital audio outputs that are capable of transmitting content over a standard interface through a standard interconnection scheme. Digital outputs include—but are not strictly limited to—S/PDIF, IEEE 1394, parallel, serial, modem, and network ports. (This requirement does not currently apply to USB.)
  • When handling secure content, an audio driver must never attach an untrusted driver to its stack. In other words, the audio driver must rely only on other components that also contain DRM signatures. The driver must never facilitate the transfer of audio data to any component that does not have a DRM signature. In particular, if a driver passes digital content to another component, the driver must use the DRM APIs in the kernel to make the DRM system aware of this fact.

The following checklist may help driver writers avoid some common pitfalls:

  • If the driver disables waveOut capture and S/PDIF output while DRM-protected content plays, the driver must remember to enable them again after the DRM-protected content finishes playing (and the DRM buffer is destroyed).
  • If the device performs hardware mixing, the driver should keep track of any changes in composite usage rights that occur when streams are added to or removed from the mix. Any time the mix includes one or more copy-protected DRM streams, for example, capture must be muted. It must remain muted if capture is turned on while the protected mix is playing.
  • After a change to the filter graph or to the property settings that are associated with a stream, the driver might need to immediately update the stream's copy-protection and output-enable settings. The driver must synchronize its operation to prevent protected content from being copied to a capture buffer or digital output. For example, when the input stream to a capture multiplexer changes, the driver must not allow secure content to become vulnerable during the time required to turn muting on and off.

In addition to passing the DRM-compliance test, the audio device and driver must not allow a user to select a mode of operation that defeats or subverts the DRM components in the kernel. Specifically, the driver must not provide registry settings, user-control panels, or other methods of disabling the DRM functions.

While developing your driver's DRM functionality, you might need to generate test files with content that is protected by a variety of DRM security levels. The SAPTool, which is included with the Platform SDK tools, can be used for this purpose. This tool accepts as input an unprotected file in .wma or .asf format. It generates an output file with one of several DRM security levels that the user can choose from.


GFX Filters

Microsoft® Windows® XP and later provide support for GFX (global effects) filtering of an audio stream. Windows XP supports GFX only for USB devices.

A GFX filter can apply an audio-signal transform to the final audio mix that is rendered by an audio device. The effect is global because it affects all of the streams that are combined to form the final mix. Examples of these effects are EQ, bass enhancement, and speaker correction.

A GFX filter can also process the signal that is captured by an audio device. The GFX filter is inserted into the capture stream before any other processing of the audio signal.

A GFX filter is packaged as an AVStream minidriver and an associated INF file. (See Device Installation Files.)

Because a typical GFX filter is tied more to a specific hardware configuration (for example, to compensate for the characteristics of a particular set of speakers) than to an individual application, end users rather than applications typically choose which GFX filters to apply to which audio devices. For each audio device, the end user chooses which GFX filters to apply and also the order in which to apply them. The user selects the GFX filters through the Multimedia control panel. The operating system keeps track of GFX configurations on a per-user basis.

Hardware-specific GFX filters can be applied to particular capture devices as well as to render devices. For example, a GFX filter might process the input signals from a microphone array.

A GFX filter typically serves as a host-based (or non-accelerated) enhancement of hardware and is hardware-specific. For example, when a user plugs in USB speakers, a particular GFX filter might automatically load for those speakers. The operating system then restores the GFX filter configuration and settings that it saved when the speakers were used previously.

While a vendor can provide a hardware-accelerated GFX filter, a GFX filter that is not itself hardware-accelerated will still allow the audio APIs to continue to utilize other types of hardware acceleration. This requires that host-based GFX filters can be inserted after hardware mixing. Also, when GFX filters are not present, the operating system avoids needlessly bringing the final mix back into the host.

Applications that provide general control over the audio configuration can instantiate the GFX control-panel user interface for an audio device. For example, Media Player can instantiate the user interface for a master-EQ control. (See Vendor's GFX User Interface.)

In addition to providing hardware-specific global effects, GFX filters can also provide general-purpose filtering (for example, EQ) that is not tied to any particular hardware configuration.

GFX filters should not be used to implement virtual audio devices. For example, a GFX cannot be used to create a composite, four-channel audio device from two independent stereo audio devices.

Any modifications that a vendor makes to an adapter driver in order to support GFX filters should be backwards compatible with any earlier versions of Windows that the driver needs to support.


Requirements for a GFX Filter Factory

In order for the operating system to be able to treat an AVStream filter factory as a factory for GFX filters, the factory should do the following:

  • Its should register its device interface in both the KSCATEGORY_AUDIO and KSCATEGORY_DATATRANSFORM device-interface registry keys.
  • It should have either one input and one output pin, or two input/output pairs.
  • It should add a Gfx subkey to the filter's KSCATEGORY_AUDIO device-interface registry key. The filter factory's INF file typically uses AddReg directives to add the Gfx subkey to the registry path during driver installation.


Installing a Device-Specific GFX Filter

In Windows XP and later, the operating system provides a setup mechanism that allows automatic loading and connection of a vendor-supplied global effect that is designed for a specific audio device.

The user can access the global effect through the Multimedia control-panel user interface, which can do the following:

  • Enumerate audio devices.
  • Enumerate the GFX filters that are currently applied to each audio device.
  • Enumerate the GFX filters that are available for each audio device.
  • Modify the order in which GFX filters are applied to an audio device.
  • Invoke a vendor-supplied GFX-specific user interface for each GFX instance.
  • Remove GFX filters from an audio graph.

The Windows Multimedia functions include a gfx API that applications can use to perform each of the above tasks (see Platform SDK documentation).

The vendor-supplied user interface that is accessible through the Multimedia control panel (see Vendor's GFX User Interface) should be able to detect that a candidate GFX filter is intended for a specific hardware device and display the GFX candidate as a selection only for that hardware.

At driver-installation time, the vendor loads information about its proprietary GFX factory into a registry path that has the following format:

DIRegKey\Gfx\AutoLoad\GfxAutoLoadInst

In the path above, DIRegKey represents the subpath for the filter's KSCATEGORY_AUDIO device-interface registry key, Gfx and AutoLoad are both literal subkey names, and GfxAutoLoadInst represents the subkey that contains the information that the operating system needs to automatically load the GFX factory.

The vendor supplies an INF file that installs the GFX factory. This file uses an AddReg directive to add the registry subkey AutoLoad to the device's Gfx key. Under the AutoLoad key, the INF file adds one or more GfxAutoLoadInst subkeys and assigns arbitrary names to these subkeys. Typically these subkeys are named "0", "1", "2", and so on. Most GFX drivers need only one subkey and will name it "0". The GfxAutoLoadInst subkey contains the values that are shown in the following table.

Value name
[data type]
Description
NewAutoLoad
[REG_DWORD] 		Indicates whether the audio system has processed this GfxAutoLoadInst registry key.

1 = Audio system needs to process this registry key.
0 = Audio system has processed this registry key.

The AddReg directive in the GFX driver's INF file sets this value to one. The directives in the add-registry-section use the FLG_ADDREG_NOCLOBBER flag so that the audio system will not reprocess the registry entries if the GFX driver is only being updated.

After the audio system processes this registry information, it sets this value to zero.
Type
[REG_DWORD] 		Specifies if the system should load the GFX filter as a render, capture, or render/capture GFX.

1 = render
2 = capture
3 = render/capture

The GfxAutoLoadInst key should also contain a subkey that is named UserInterface\CLSID. This subkey contains the information that the operating system needs to identify the vendor's GFX user interface. The subkey's value is shown in the table below.

Value name [data type] | Description
(Default) [REG_SZ] | String representation of the CLSID of the COM object that implements the GFX-specific user interface.

The vendor's INF file might also add subkeys with the names Render and/or Capture to the GfxAutoLoadInst key. The Render subkey exists only if the value of the Type entry (see above) is 0x1 (render GFX) or 0x3 (render/capture GFX); this subkey contains a description of the rendering hardware for which the GFX was designed. The Capture subkey exists only if the value of the Type entry is 0x2 (capture GFX) or 0x3 (render/capture GFX); this subkey describes the capture hardware for which the GFX was designed. The following table shows the values that are contained in the Render and Capture subkeys.

Value name [data type] | Description
HardwareId [REG_MULTI_SZ] | The PnP device IDs of the hardware devices that expose the render or capture device interfaces through which this GFX filter is managed.
ReferenceString [REG_SZ] | The reference string that is used by the hardware device to call IoRegisterDeviceInterface when registering the render or capture device interface through which this GFX filter is managed.

Given the registry information above, the operating system can find the device interfaces that it needs to load the hardware-specific GFX filter.


GFX Topology Requirements

For a GFX filter that performs either rendering or capture but not both, the filter should have only one input pin and one output pin. This avoids any ambiguity in how to connect the pins into the final mix or input stream.

A render/capture GFX filter, which can perform both rendering and capture, should have two input and two output pin factories, each of which can create only a single pin instance. The SysAudio system driver assumes that the four pins are assigned the functions that are shown in the table below.

Pin ID | Pin function
0 | Outputs data processed for rendering.
1 | Inputs data to process for rendering.
2 | Outputs processed capture data.
3 | Inputs capture data for processing.


GFX Data Format Requirements

The data formats that a GFX filter's input and output pins support should include the PC 99 minimum set of data formats (see PC 99 System Design Guide, chapter 17). The minimum set includes 44.1-kHz, 16-bit stereo and 48-kHz, 16-bit stereo.

Either pin (input or output) of the GFX filter should be able to connect with any of the data formats in the PC 99 minimum set as long as the opposite pin is still unconnected.

Once one of the two pins is connected with a data format in the PC 99 minimum set of data formats, the opposite pin should be able to connect with one or more of the data formats in that same set.

The above requirements apply to all GFX filters regardless of whether they are intended to be used for capture or rendering.


Vendor's GFX User Interface

A vendor who provides a GFX filter should also provide a COM user-interface object that supports the ISpecifyPropertyPages interface. For information about this interface, see the Platform SDK documentation. The CLSID of this COM object is specified in the GFX driver's installation INF file. (See the description of the UserInterface/CLSID subkey in Installing a Device-Specific GFX Filter.) In addition, the vendor should provide property-page COM objects that implement the IPropertyPage interface for each property-page CLSID that is returned by the UI object's ISpecifyPropertyPages interface. For information about this interface, see the Platform SDK documentation. Vendors can choose appropriate mechanisms for implementing, installing, and registering these COM objects.

The vendor's control-panel UI passes a data object to the property pages through the IPropertyPage::SetObjects call. The vendor's property-page object can call IDataObject::GetData (see Platform SDK documentation) with the medium type specified as TYMED_HGLOBAL. This call retrieves an open handle to the vendor's GFX filter. The vendor's property page objects can use this handle to access the GFX filter's KS properties, events, and methods. The property-page object is responsible for ensuring that the handle is eventually closed by calling CloseHandle (see Platform SDK documentation).


Persistence of GFX Settings

A GFX filter does not explicitly save any of its settings persistently from one filter instance to the next. Instead, it relies on the operating system to keep track of its settings between instantiations. The operating system uses get- and set-property requests to save and restore the state of a GFX filter.

The GFX filter implements the KS property KSPROPERTY_AUDIO_FILTER_STATE in order to identify the property sets that need to be saved persistently. This property's get request retrieves an array of property-set GUIDs.

Just after instantiating the GFX filter, the operating system queries the filter for its KSPROPERTY_AUDIO_FILTER_STATE property to obtain the list of property sets to restore. Next, using KS serialization (described in KS Properties), the operating system walks through each property in each property set and restores each to its previously saved value.

Similarly, just before closing a GFX instance, the operating system queries the KSPROPERTY_AUDIO_FILTER_STATE property to obtain the list of property sets to save. As before, the operating system uses KS serialization to walk through each property in each property set, get each value, and save the value persistently.


Target Device ID

Some GFX filters, especially those that are designed to process signals for specific hardware, might need to know which device they are producing data for (in the case of a rendering GFX filter) or receiving data from (in the case of a capture GFX filter). For example, a filter may need to alter its signal processing algorithm to accommodate different members of a family of related devices.

Just after instantiating a GFX filter but before restoring the filter's persistent properties, the operating system will set a property called KSPROPERTY_AUDIOGFX_RENDERTARGETDEVICEID or KSPROPERTY_AUDIOGFX_CAPTURETARGETDEVICEID (for render or capture GFX filters, respectively) to inform the GFX of the PnP device ID of the render or capture device. The format of the property data for KSPROPERTY_AUDIOGFX_xxxTARGETDEVICEID is a NULL-terminated Unicode string.

KSPROPERTY_AUDIOGFX_RENDERTARGETDEVICEID and KSPROPERTY_AUDIOGFX_CAPTURETARGETDEVICEID are defined in ksmedia.h.


DRM Support

The operating system requires a GFX driver to meet the same requirements for handling DRM-protected content as any other driver in the WDM audio system. In order to support DRM (digital rights management), the GFX/AVStream filter implements a property handler for KSPROPERTY_DRMAUDIOSTREAM_CONTENTID. This handler calls DrmForwardContentToDeviceObject to advise the DRM system of the connected downstream pin that receives the content. The GFX/AVStream filter calls KsPinGetConnectedPinFileObject and KsPinGetConnectedPinDeviceObject to retrieve the FILE_OBJECT and DEVICE_OBJECT parameters to pass to DrmForwardContentToDeviceObject.


WDM Audio Extensions to Legacy Windows Multimedia APIs

Recent versions of Windows have extended the audio functions in the Windows multimedia APIs aux, midiIn, midiOut, mixer, waveIn, and waveOut to output information about the status and capabilities of WDM audio drivers.

The auxGetDevCaps, midiInGetDevCaps, midiOutGetDevCaps, mixerGetDevCaps, waveInGetDevCaps, and waveOutGetDevCaps functions can output driver-specific information that uniquely identifies an audio device.

The midiOutMessage, waveInMessage, and waveOutMessage functions can output the device ID of the current preferred audio device.

The following topics are discussed in this section:

Extended Capabilities from a WDM Audio Driver

Accessing the Preferred Device ID


Extended Capabilities from a WDM Audio Driver

By handling the KSPROPERTY_GENERAL_COMPONENTID property, an audio filter can provide hardware-specific information that applications can use to uniquely identify the underlying device. Microsoft® Windows® XP is the first version of Windows to support this feature; this feature is not available for earlier versions.

The filter provides the hardware-specific information in the form of a KSCOMPONENTID structure that contains the following:

  • manufacturer GUID
  • product GUID
  • component GUID
  • name GUID
  • hardware version number
  • hardware revision number

To provide access to this information, a WDM audio driver specifies a property handler for KSPROPERTY_GENERAL_COMPONENTID in the filter automation table.

An application can access the data from the driver's KSCOMPONENTID structure through the following legacy Windows multimedia APIs: aux, midiIn, midiOut, mixer, waveIn, and waveOut. A client queries the driver for this information by calling one of the multimedia functions in the following table and passing in an extended-capabilities structure as the second argument:

Multimedia function | Extended-capabilities structure
auxGetDevCaps | AUXCAPS2
midiInGetDevCaps | MIDIINCAPS2
midiOutGetDevCaps | MINIOUTCAPS2
mixerGetDevCaps | MIXERCAPS2
waveInGetDevCaps | WAVEINCAPS2
waveOutGetDevCaps | WAVEOUTCAPS2

After receiving the KSCOMPONENTID structure from the filter's property handler, the WDMAud system driver (wdmaud.sys) converts the data from this structure to the xxxCAPS2 format that the xxxGetDevCaps functions use.

After verifying that the capabilities structure passed to the function is large enough to contain the manufacturer, product, and name GUIDs, the xxxGetDevCaps function copies this information into the extended structure before returning. (The component GUID from KSCOMPONENTID is currently not used.)

WDMAud concatenates the Version and Revision members from KSCOMPONENTID to form the 16-bit revision number that the xxxGetDevCaps function copies into the vDriverVersion member of the capabilities structure:

vDriverVersion = (Version << 8) | (Revision & 0xFF)

Microsoft previously required vendors to register manufacturer IDs and product IDs for their audio devices. These IDs were then released in the header file mmreg.h.

In Microsoft® Windows® XP and later, registered IDs are no longer necessary; they are replaced by the manufacturer and product GUIDs that are provided through the KSPROPERTY_GENERAL_COMPONENTID property. The GUIDs are more convenient for vendors to use than registered IDs because GUIDs are inherently unique, easily generated, and require no registration.

However, if you have already registered product and manufacturer IDs with Microsoft (and they are in mmreg.h), you can use the macros INIT_MMREG_PID and INIT_MMREG_MID in ksmedia.h to convert your product and manufacturer IDs into GUIDs. If you use these macros to generate the GUIDs, WDMAud will be able to recover the original product and manufacturer IDs from the GUIDs and copy these IDs into the wPid and wMid members of the capabilities structure that is filled in by the xxxGetDevCaps call.

Otherwise, if you do not have registered manufacturer and product IDs, simply use the GUIDGEN utility to generate the manufacturer and product GUIDs. When a driver's GUIDs are of this type, WDMAud loads default constants MM_UNMAPPED and MM_PID_UNMAPPED into the wMid and wPid members, respectively, of the capabilities structure that is filled in by the xxxGetDevCaps call.

WDMAud uses the Name GUID in the KSCOMPONENTID structure to look up a "Name" key in the registry. This key is located under the registry pathname HKLM\System\CurrentControlSet\Control\MediaCategories. The "Name" key for a device has an associated string value that contains the device name. The xxxGetDevCaps function copies the first 31 characters of this name string into the szPname member of the capabilities structure. For device names longer than 31 characters, a client application can open the registry key and directly read the entire string. A driver can populate this registry entry in one of two ways:

  • The driver can specify the entry in the device's INF file at install time.
  • The driver can load the entry during execution of its filter-initialization routine.

The name GUID is optional. If the driver sets the Name member in the KSCOMPONENTID to the GUID_NULL value, WDMAud will provide the device's friendly name to the xxxGetDevCaps function, which will copy this name into the szPname member of the capabilities structure.

If the filter exposes no handler for the KSPROPERTY_GENERAL_COMPONENTID property, WDMAud will use default values in place of the data from the KSCOMPONENTID structure. The default values for the legacy portion of the capabilities structure are as follows:

  • wMid = MM_MICROSOFT
  • wPid = a device class from the following list:

    MM_MSFT_WDMAUDIO_WAVEOUT

    MM_MSFT_WDMAUDIO_WAVEIN

    MM_MSFT_WDMAUDIO_MIDIOUT

    MM_MSFT_WDMAUDIO_MIDIIN

    MM_MSFT_WDMAUDIO_MIXER

    MM_MSFT_WDMAUDIO_AUX

  • vDriverVersion = 0x050a (for Windows XP) or 0x0500 (pre-Windows XP)

On Windows releases before Windows XP, the legacy members of the capabilities structure are always set to the defaults above. On Windows XP and later, the default values for the extended capabilities are as follows:

  • NameGuid = GUID_NULL
  • INIT_MMREG_MID(&ManufacturerGuid, wMid)
  • INIT_MMREG_PID(&ProductGuid, wPid)

The INIT_MMREG_MID and INIT_MMREG_PID macros above are defined in ksmedia.h. These macros are used to convert the manufacturer and product IDs in the wMid and wPid members to GUIDs that are loaded into the ManufacturerGuid and ProductGuid members.


Accessing the Preferred Device ID

In Windows Me, and Windows 2000 and later, the Windows multimedia functions waveOutMessage, waveInMessage, and midiOutMessage can output the device ID of the preferred device. This information is useful to applications that, for example, allow users to select a device to open from a list of two or more devices. Such an application typically needs to indicate which among the devices in the list is the preferred device.

In order to retrieve the device ID of the current preferred audio device, an application calls the xxxMessage function with the message parameter set to the constant DRVM_MAPPER_PREFERRED_GET. The function returns MMSYSERR_NOERROR if the operation is successful. Otherwise, it returns one of the error codes defined in the header file mmsystem.h.

The caller sets the xxxMessage call parameters dwParam1 and dwParam2 to point to two DWORD locations. The two pointers are specified as follows:

OUT DWORD_PTR dwParam1
Points to a DWORD location in which the function is to store the device ID of the current preferred device. The function sets this location to (-1) if no device is available that qualifies as a preferred device.
OUT DWORD_PTR dwParam2
Points to a DWORD location in which the function is to store status flags. Only one flag bit is currently defined (for waveInMessage and waveOutMessage calls only): DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY.

When the DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY flag bit is set in the DWORD location that is pointed to by dwParam2, this means that the waveOut and waveIn APIs will use only the current preferred device and will not search for other available devices if the preferred device is unavailable. Note that the midiOutMessage function does not output this flag—the midiOut API always uses only the preferred device. The flag that is output by either the WaveOutMessage or WaveInMessage call applies to the preferred device for both the waveIn and waveOut APIs, regardless of whether the call is made to waveInMessage or waveOutMessage.

When calling the waveOutMessage, waveInMessage, or midiOutMessage function with the DRVM_MAPPER_PREFERRED_GET message, specify the device handle as MIDI_MAPPER (for midiOutMessage) or WAVE_MAPPER (for waveInMessage or waveOutMessage) and cast this value to the appropriate handle type: HMIDIOUT, HWAVEIN, or HWAVEOUT. The xxxMessage functions accept this value in place of a valid device handle in order to allow an application to determine the default device ID without first having to open a device.

The constants DRVM_MAPPER_PREFERRED_GET and DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY are defined in header file mmddk.h.


Multifunction Audio Devices

A multifunction device (see Supporting Multifunction Devices) is a single adapter card that incorporates two or more separate functions (or subdevices). A multifunction device can contain two or more audio subdevices. It may also span device classes. A device that contains audio and modem subdevices, for instance, belongs to both the media class and the modem class.

The WavePci port-class driver in PortCls places special requirements on multifunction devices. In particular, an adapter driver must provide a way to configure each subdevice so that it can be controlled independently of the other subdevices in a multifunction device. This can be accomplished by setting up the PCI configuration space for your multifunction device in one of two ways:

  1. The preferred method is to assign a separate device ID to each logically distinct subdevice on your multifunction device. If your multifunction device contains modem, audio, and joystick subdevices, for example, the system should be able to represent each subdevice as an independent devnode in the device tree. The subdevice represented by each device ID has its own set of PCI configuration registers and is orthogonal to and independent of the other subdevices. For instance, enabling or disabling one subdevice (the audio subdevice, for example) should have no effect on any other subdevice (the modem, for example). This type of multifunction device requires no special hardware-specific driver support apart from the proprietary drivers for the subdevices themselves.
  2. A second way to design a multifunction device is to assign a single device ID to the device as a whole and to provide separate BARs (PCI base-address registers) for the individual subdevices. In this scheme, the subdevices share a common set of configuration registers but each subdevice has its own BAR or BARs. The system multifunction driver (mf.sys on Windows 2000, for example) can configure the base address for each subdevice's status, command, and data registers independently of the registers for the other functions. If your device's BARs are not logically separable by subdevice, PortCls will be unable to interface to your device.

The remainder of this section describes the steps necessary to implement approach (2) above. The following topics are discussed:

System Multifunction Drivers

Multiple Audio Subdevices

Game Ports

Multifunction Device Limits


System Multifunction Drivers

If your multifunction device uses a single device ID and multiple BARs, your adapter driver need not enumerate the subdevices itself. Instead, your driver can rely on a system driver to do the enumeration.

On Windows 2000 and later, the system multifunction driver, mf.sys, does the enumeration. Your driver must specify the subdevices in its startup code and INF file, but mf.sys enumerates the individual subdevices during installation.

On Windows 98/Me, a configuration-management VxD called ConfigMg.vxd is used instead of mf.sys, although it does basically the same thing. You can find an example of the INF syntax for specifying the subdevices in your multifunction device by looking at the file mf.inf on any Windows 98 or Windows Me installation.


Multiple Audio Subdevices

A multifunction device can contain two or more audio subdevices. For example, an adapter driver might allow an eight-channel audio device to be exposed to the system as four stereo channels. When writing an adapter driver to expose multiple subdevices in this way, you should incorporate information about the subdevices into your driver's startup sequence and INF file.

First, your adapter driver should expose each stereo subdevice as a separate instance of a port/miniport pair during the startup sequence. Several of the sample adapters in the DDK implement an InstallSubdevice function that creates and registers a subdevice consisting of a system port driver, a miniport driver, and a set of resources that are to be bound to this pair. During startup, your driver should call its InstallSubdevice function once for each stereo subdevice and specify a unique name for each port/miniport pair.

In addition, the unique name you assign to this pair must match the KSNAME string that you specify in your driver's INF file. For example, your driver might assign the names "Wave1" and "Wave2" to two subdevices during startup, as shown below:

InstallSubdevice(..., "Wave1",...);
InstallSubdevice(..., "Wave2",...);

In this case, the same names should appear in the INF file:

KSNAME_Wave1="Wave1"
KSNAME_Wave2="Wave2"

Your INF file should add interfaces that contain these names:

AddInterface=%KSCATEGORY_AUDIO%
%KSNAME_Wave1%,Test.Interface.Wave1
AddInterface=%KSCATEGORY_AUDIO%
%KSNAME_Wave2%,Test.Interface.Wave2

The INF file should create AddReg sections in order to add information about these interfaces to the registry:

[Test.Interface.Wave1]
AddReg=Test.I.Wave1.AddReg
[Test.Interface.Wave2]
AddReg=Test.I.Wave2.AddReg

The AddReg sections should also specify the registry entries for each subdevice:

[Test.I.Wave1.AddReg]
HKR,,CLSID,,%Proxy.CLSID%
HKR,,FriendlyName,,%Test.Wave1.szName%
[Test.I.Wave2.AddReg]
HKR,,CLSID,,%Proxy.CLSID%
HKR,,FriendlyName,,%Test.Wave2.szName%

Finally, the INF file should define the friendly names for these subdevices:

Test.Wave1.szName="Punch"
Test.Wave2.szName="Judy"

The friendly names show up in the audio control panel to identify the subdevices.


Game Ports

If your multifunction audio device contains game ports, note that the adapter driver's handling of the game ports on Windows 2000 and later differs from that on Windows 98/Me. In contrast, all three operating systems are consistent in their use of WDM audio drivers. On Windows 98/Me, the joystick portion of the operating system is still VxD-based and you must write a hybrid VxD-WDM adapter driver. This is unnecessary on Windows 2000 and later, which support joysticks with a DirectInput HID driver.

If your game port requires Type-F DMA transfers, note that these are supported on Windows 98/Me, but not on Windows 2000 or later. The PC 2001 System Design Guide does not require support for legacy game ports on new PCs, which are likely to use USB joystick devices instead.

A limitation in Windows 98 prevents loading a child VxD from a WDM parent. This can cause problems with a multifunction device that combines a joystick, which requires a VxD on Windows 98, with an audio device that has a WDM parent. This limitation has been removed in Windows 98 SE and Windows Me.


Multifunction Device Limits

The number of audio functions per multifunction device is limited by the following factors:

  • When the adapter driver calls PcAddAdapterDevice, the function's fourth parameter, MaxObjects, specifies the maximum number of miniport objects that the driver can support. The sample adapter drivers in the DDK set this parameter to the integer constant MAX_MINIPORTS, which is typically defined to be a small value (five or less). You might need to increase this value if you plan to support multiple stereo pairs or other types of audio subdevices.
  • Windows 2000 allows a maximum of ten device interfaces on each of the following Windows multimedia APIs: waveIn, waveOut, midiIn, midiOut, mixer, and aux. See Windows 2000 Device-Interface Limits for details. These limits do not apply to Windows 98/Me, or to Microsoft® Windows® XP and later, which allow arbitrary numbers of device interfaces.


System-Wide Unique Device IDs

A driver for a typical audio adapter should easily be able to support several instances of the same audio adapter card in a system. Nearly all of the data structures that a driver maintains are stored in the device-extension buffer (see description of DEVICE_OBJECT structure's DeviceExtension field). If several instances of a driver share any global data, however, those instances should synchronize their access to this data.

One additional requirement is that each subdevice on a particular instance of an adapter card should have a device-ID string (see Device Identification Strings) that uniquely identifies the subdevice across all instances of the same adapter card in the system.

The most straightforward way to accomplish this is to expose each subdevice on the adapter card as a logically distinct device to the PnP Manager. This is option (1) in Multifunction Audio Devices.

A second approach is to use the system-supplied multifunction bus driver to manage the subdevices on the adapter card. The MF bus driver assigns to each subdevice a device ID that is guaranteed to be unique across the system, even if the system contains several instances of the same adapter card. The MF bus driver accommodates designs in which the subdevices share a common set of configuration registers but each subdevice has its own set of PCI base-address registers. The subdevices should have no hidden dependencies on each other and should be able to operate concurrently without interfering with each other or with other devices in the system. This is option (2) in Multifunction Audio Devices.

A third approach is to use a proprietary bus driver to manage the subdevices on an adapter card. This is frequently necessary if the subdevices have mutual dependencies that must be managed centrally. Such dependencies can occur in a couple of ways:

  • The subdevices might share some on-card resource. For example, if the subdevices share a DSP (digital signal processor), the bus driver might need to download the proprietary operating system that runs on the DSP before starting up the first subdevice.
  • A design flaw might cause a dependency among subdevices. For example, a design flaw might require the subdevices to be powered up or down in a particular sequence.

When either type of dependency exists, a proprietary bus driver is nearly always a better solution than presenting the subdevices directly to the PnP Manager and attempting to hide the dependencies under the covers.

If you provide your own bus driver for an adapter card, you should ensure that the device IDs that your bus driver assigns are unique across the system.

A bus driver provides a device ID for one of its children in response to an IRP_MN_QUERY_ID query from the PnP Manager. The ID can be specified in one of two ways, which the bus driver indicates in its response to an IRP_MN_QUERY_CAPABILITIES query by setting the DEVICE_CAPABILITIES structure's UniqueID field to TRUE or FALSE:

  • UniqueID=TRUE

    This means that the name of the child is guaranteed to be unique throughout the system. The device ID string contains a device ID plus an instance ID, which is a serial number that uniquely identifies the hardware instance.

  • UniqueID=FALSE

    This means that the name of the child is unique only with respect to the parent. Most devices use this means of identification. In this case, the PnP Manager will extend the device-ID string that it receives to make it unique through the system. The extended string is a function of the parent device's unique ID.

All audio bus drivers should set UniqueID=FALSE for their children. This causes the PnP Manager to extend the child's device ID string by adding information about the device's parent in order to make the ID unique on the machine.


Audio Miniport Drivers

This section describes audio miniport driver interfaces and how to develop audio adapter drivers for audio hardware whose registers are directly accessible to the system processor over a system bus. This class of hardware includes all ISA/DMA, PCMCIA, and PCI audio adapters.

This documentation does not discuss how to support audio devices that reside on an external bus. USB audio devices, in particular, should conform to USB audio device class specifications and should therefore require no software drivers. Failure to design a USB device to operate in this manner might result in future incompatibility between the KMixer system driver and the upper end of a USB driver. For more information about USB audio support, see USBAudio Class System Driver.

The following discussion assumes that the reader is familiar with KS (kernel streaming) concepts. For background information, see the Kernel Streaming Overview section.

The WDM audio driver model divides a driver implementation into port and miniport drivers that are complementary but separate. This division makes audio hardware drivers easier to write by isolating KS filter implementation issues from hardware interface issues. Hardware vendors write miniport drivers to directly control their hardware devices, but the port drivers that implement the KS filters are provided with the operating system. The port and miniport drivers communicate with each other through precisely defined interfaces.

Various aspects of miniport driver development are discussed in the topics below:

Introduction to Port Class

Implementation of Function-Specific Interfaces

Supporting a Device

Audio Miniports Overview

COM in the Kernel

Adapter Driver Construction

Miniport Interfaces

Kernel Streaming Topology to Audio Mixer API Translation

Installing a Port Class Audio Adapter

Data-Intersection Handlers

Power Management for Audio Devices

Version Numbers for Audio Drivers


Introduction to Port Class

PortCls is an audio port-class driver that Microsoft includes as part of the operating system. PortCls is implementated in portcls.sys as an export driver (a kernel-mode DLL) that provides kernel-streaming functionality for ISA/DMA and PCI audio device drivers. The portcls.sys file contains the following:

  • A set of helper functions that can be called by the adapter driver
  • A collection of audio ports

The hardware vendor for an audio device is responsible for providing an adapter driver. The adapter driver includes initialization and miniport-management code (including the DriverEntry function) and a collection of audio miniports.

When the adapter driver loads, it creates a set of miniports and a corresponding set of ports. These ports are typically a subset of those that are available in the portcls.sys file. Each miniport is bound to a matching port from portcls.sys to form a complete subdevice (see Subdevice Creation). The combination port and miniport subdevice is a KS (kernel streaming) filter (see Audio Filters). For example, a typical adapter driver might contain three miniports: PCI wave, UART, and Topology. During initialization, these miniports are bound to the WavePci, MIDI, and Topology ports that are contained in the portcls.sys file. These three subdevices form three KS filters, which together expose the complete functionality of the audio adapter.

Typically, the ports provide the majority of the functionality for each class of audio subdevice. For example, the WaveCyclic port does most of the work that is required to stream audio data to a DMA-based audio device, whereas the miniport provides device-specific details such as the DMA address and device name.

Audio adapter drivers and miniports are typically written in C++ and make extensive use of COM interfaces. The port/miniport architecture promotes modular design. Miniport driver writers should implement their miniport as a C++ class derived from the IMiniport interface that is defined in the header file portcls.h. At driver load time, the adapter driver instantiates one or more IMiniport-derived classes, along with corresponding IPort-derived classes, and binds them together. Hardware initialization also takes place at driver load time—typically in the Init method of the IMiniport-derived class (for example, see IMiniportWavePci::Init). For more information on COM implementations of audio miniports, see COM in the Kernel.

The following diagram illustrates the relationship between port and miniport drivers and their position in the audio stack.

Relationship Between Port and Miniport Drivers

Port-class and stream-class drivers are similar in that they are both WDM drivers, they support the Connection Streaming Architecture (data streaming), and they interact with DirectShow® in the same manner. However, port-class drivers differ from stream-class drivers in the areas of multiprocessor handling and reentrancy. Port-class drivers do the following:

  • Use a three-tier approach that combines the class driver, port drivers, and vendor-supplied miniports.
  • Have a restricted number of audio functions, allowing miniports to operate closer to the audio hardware.
  • Allow several port or miniport drivers to be linked for a specific device. This feature allows for better support for multifunction cards.
  • Do not support external buses (for example, USB). All port drivers support devices that reside on the system buses (ISA, PCMCIA, and PCI).

The terminology that is used to describe WDM audio ports and miniports differs in some respects from the terms that are used for other classes of Windows drivers. These differences are listed in Audio Miniports Overview.


Implementation of Function-Specific Interfaces

A typical audio adapter card contains a collection of audio hardware functions, which the adapter driver can expose to the WDM audio system through a corresponding collection of miniport interfaces. Each type of miniport interface—wave, MIDI, topology, and so on—represents a particular type of audio function on an adapter card. A driver can also expose several instances of the same miniport interface in order to represent multiple instances of the same (or similar) hardware functions.

See Miniport Interfaces for more information.


Supporting a Device

The current implementation of the PortCls system driver (portcls.sys) provides the following ports:

Topology_Port

WaveCyclic Port

WavePci Port

MIDI Port

DMus Port


Topology Port

The Topology port specifies the topology of a device, which is exposed as a set of mixer lines by the Windows Multimedia mixer API. The adapter driver provides a corresponding miniport object, which has an IMiniportTopology interface. PortCls forms a Topology filter by binding the miniport driver to the Topology port driver.


WaveCyclic Port

The WaveCyclic port provides wave audio functionality on a DMA-based device. The adapter driver provides a corresponding miniport object, which has an IMiniportWaveCyclic interface. PortCls forms a WaveCyclic filter by binding the miniport driver to the WaveCyclic port driver.


WavePci Port

The WavePci port provides wave audio functionality on a scatter/gather PCI device. The adapter driver provides a corresponding miniport object, which has an IMiniportWavePci interface. PortCls forms a WavePci filter by binding the miniport driver to the WavePci port driver.


MIDI Port

The MIDI port provides MIDI functionality. The adapter driver provides a corresponding miniport object, which has an IMiniportMidi interface. PortCls forms a MIDI filter by binding the miniport driver to the MIDI port driver.

In addition, PortCls contains built-in miniport drivers for MIDI devices that have FMSynth, DMusUART, and UART functions. PortCls forms a MIDI filter by binding an FMSynth, DMusUART, or UART miniport to a MIDI port. For information on using these built-in miniports, see PcNewMiniport.


DMus Port

The DMus port provides DirectMusic® functionality. For more information about driver support for DirectMusic, see Synthesizer Miniport Overview.

By using a layered approach, the manufacturer can write an adapter driver that operates on multiple levels, depending on the functions that the adapter supports. To determine the level of support required for a given function, the manufacturer should first determine whether the function is compatible with hardware for which a miniport driver already exists.

To implement WDM support for a device:

  1. If the function is compatible with the hardware, use the existing miniport driver to support the function.
  2. If the function is not compatible with the hardware, then determine whether the function is sufficiently similar to functions supported by existing port drivers.
  3. If the function should be supported by the port driver, write the portion of the miniport driver that implements the function. That function should comply with the miniport interface specification of the owning port driver.
  4. If there is no such port driver, write a minidriver to support the function that complies with the interface specification for the streaming-class driver.


Audio Miniports Overview

The following is a list of terms used in Microsoft® Windows® driver architecture. WDM driver architecture uses some of these terms, but its definitions differ from those of Windows for some terms. The purpose of this list is to delineate the general driver architecture that WDM draws from and to clearly state differences between classic Windows definitions of layered drivers and those of the WDM implementation of its own driver architecture.

Miniport Driver (classic)

The miniport driver (classic) is the hardware-specific driver for an adapter that resides on a system bus (for example, PCI or ISA). This driver has a single entry point, namely DriverEntry, and registers a table of functions with a port driver. This table of functions serves as an upper-edge interface of the miniport.

The miniport driver sits below the port driver in the audio stack. That is, all calls to the miniport are made from the port driver and all calls out of the minidriver are to the port driver (the lower-edge interface), making the driver platform-independent.

Port Driver (classic)

The port driver (classic) surrounds a miniport driver.

The port driver:

  • Implements WDM streaming filters.
  • Provides a common interface to the rest of the operating system.
  • Handles system requests from the system and recasts these requests as calls into the miniport's function table.
  • Provides a library of support functions (port's lower-edge interface) to the miniport.

Minidriver (classic)

The minidriver (classic) represents a hardware component on a bus. The minidriver uses the bus driver to communicate to the physical device over the bus, and binds together the bus driver and one or more class drivers.

Class drivers help the minidriver present the physical device to clients as a type of logical device. In WDM environments, a minidriver typically receives requests in IRP form from class drivers, and sends requests in IRP form to a bus driver.

A minidriver might also have to communicate with several class drivers. An example of a minidriver that binds to multiple class drivers is a minidriver for a CD-ROM drive on a 1394 bus. It might bind to a file-system class driver so that the drive can be accessed from the file system. However, it also binds to a Redbook system driver so that audio can be streamed from CDs.

Bus Driver (classic)

The bus driver (classic) provides minidrivers access to a physical bus. The Microsoft® Windows® HAL is sometimes referred to as the system bus driver because it provides access to the system bus.

Class Driver (classic)

The class driver (classic) implements behavior expected of a class of devices.

The class driver:

  • Eliminates duplication of functionality in hardware-specific drivers.
  • Is not bus-specific.
  • Is not aware of resource issues (for example, DMA and interrupts).

The following diagram illustrates relationships between the port-class and adapter drivers:

Relationship between Port Class and Adapter Drivers

Miniport Driver (WDM Audio Miniport)

The miniport driver (WDM audio miniport) implements a function-specific interface for a function on a particular adapter (for example, an audio card). A miniport driver is a component of an adapter driver. It is not recognized as a driver by the operating system.

Like classic miniport drivers, audio miniports do not implement DriverEntry, are not registered, and do not rely entirely on their respective port drivers for support. Multiple miniports that address multiple functions can be linked into a single adapter driver (and associated with a single device object).

Adapter Driver (WDM Audio Miniport)

The adapter driver (WDM audio miniport) serves as a container for all miniport drivers associated with a given adapter. This adapter driver is recognized as a driver by the operating system and is contained in its own .sys file.

The adapter driver consists of a set of miniport drivers and additional code that addresses initialization issues.

Port Driver (WDM Audio Miniport)

The port driver (WDM audio miniport) implements a WDM streaming filter on behalf of a miniport and operates in the context of a port-class driver. The port driver exposes the miniport's function-specific code as a WDM streaming filter to the system and is responsible for adapter-independent code.

Unlike the port driver (classic), the port driver (WDM audio miniport) shares the device object and is, therefore, instantiated differently. A port driver (WDM audio miniport) is also more like a class driver in that it implements behavior that is expected of a class of devices (it is not bus-independent).

Port Class Driver (WDM Audio Miniport)

The port-class driver (WDM audio miniport) primarily functions as a container for multiple subdevices that are associated with a single device object. Bus drivers create a single physical device object (PDO) for each plug-and-play (PnP) node they enumerate.

In the case of audio adapters, a single PnP node often corresponds to multiple audio functions. To expose the various functions associated with a node as distinct devices, it would generally be necessary to write a bus driver for the adapter that would enumerate the functions and create corresponding PDOs. In this scenario, one or more drivers would then need to bind to the PDOs, and would have to negotiate with the bus driver for access to shared resources on the adapter.

The port-class driver uses the kernel streaming driver's ability to expose various aspects of a single device object, so that the operating system recognizes it as a set of distinct devices or subdevices.

A reference string is appended to the device name to specify the desired subdevice. The kernel streaming driver dispatches creation IRPs based on this reference string. After a file object is created, the kernel streaming driver provides dispatching IRPs that are targeted at the file object In addition, the port-class driver implements a COM-based model for packaging subdevices.

An adapter driver instantiates a port driver and a miniport driver and binds them together by passing a pointer to the miniport to the initialization function of the port driver. The resulting port/miniport stack constitutes a subdevice, as specified by port class.

The port-class driver's PcRegisterSubdevice function registers the subdevice, which is perceived as a device by the rest of the system. The port receives creation IRPs targeted at the device object, but for only those IRPs specified by the reference string under which the subdevice is registered. The port also receives the IRPs targeted at the file objects associated with the subdevice. The port is responsible for the subdevice's behavior as a kernel streaming driver filter and for communicating appropriately with the miniport.


COM in the Kernel

For background information on COM interfaces, see the COM section of the Platform SDK documentation.

Miniport upper-edge interfaces consist of function tables. In traditional miniports, the function table is supplied to the port driver during registration, at which time the miniport informs the port driver of the size of the context structure that the miniport will require. The port driver copies the function table to some private location, allocates the context structure, and calls an initialization function in the function table, passing a pointer to the context structure.

Similarly, audio miniports use a function table, but it is statically allocated and does not need to be copied by the port driver. The port driver is also relieved of its context ("object") memory from a specified pool and installs a pointer to the function table into the context. Because the function table pointer is always the first field in the context, the port driver needs only a context pointer and can access the function table through the context.

This approach was taken because COM supplies a solid, efficient, widely-understood model for creating abstracted objects. The audio miniport model leverages industry experience with COM and the body of COM literature. Objects can be implemented and used in C or C++. Assembly language can also be used, but should only be used where portability is not required.

In user mode, COM objects are created using a function such as CoCreateInstance, where the client is unaware of how the memory required for the object is allocated. However, in kernel mode, where the allocation of memory tends to be tightly controlled, a different method of object creation is used.

The audio driver model uses the concept of the COM interface, as defined by the IUnknown interface. However, using mechanisms such as in-process servers, or accessing the registry, are not required. Miniports are not required to support aggregation.

By convention, the function used to create a particular class of objects always takes the same form.

NTSTATUS CreateMyObject(
  OUT PUNKNOWN *Unknown,
  IN REFGUID ClassId,
  IN PUNKNOWN OuterUnknown    // OPTIONAL,
  IN POOL_TYPE PoolType
);

Parameters

Unknown
Pointer to an IUnknown interface. The object is passed back through Unknown.
ClassId
Class GUID is passed as ClassId. Used only if the function creates objects of multiple classes. Otherwise, it is set to NULL.
OuterUnknown
IUnknown interface for aggregating the new object. Can be set to NULL to indicate that no aggregation is required.
PoolType
Specifies the type of memory pool from which the object is to be allocated (see POOL_TYPE).

The first three parameters are identical to the parameters of the COM CoCreateInstance function.

Another convention is to supply a New function for a class. This function creates and initializes an object, and then passes a pointer back to the interface. Because the initialization parameters are class-specific, so is the prototype of the New function. The New function provides an easy way to access the constructor for the object.

NTSTATUS NewMyObject(
  OUT PMYINTERFACE *FavoredInterfacePointer,
  IN PUNKNOWN OuterUnknown    // OPTIONAL,
  IN POOL_TYPE PoolType,      // more parameters
);

Such functions provide an easy way to instantiate (create and initialize) an object.

The conventions for counting references on audio objects with COM interfaces are described in Reference-Counting Conventions for COM Objects.


Adapter Driver Construction

Driver support for a particular audio adapter card takes the form of an adapter driver. An adapter driver consists of some function-generic code (primarily for initialization) and a set of miniports that represent the specific audio functions on the adapter. The hardware vendor supplies the function-generic code and any miniports that are not supplied by the system.

See Miniport Interfaces for more information.


Startup Sequence

Because the adapter driver is installed as a kernel-mode driver service, the operating system loads the adapter driver at system startup time and calls the driver's DriverEntry routine. The DriverEntry routine receives two parameters: a driver object and a registry pathname. DriverEntry should call the PortCls routine PcInitializeAdapterDriver with the driver-object and registry-pathname parameters plus a third parameter, which is a pointer to the adapter driver's AddDevice function.

In the following example, the driver's DriverEntry function passes the function pointer MyAddDevice, which points to the driver's AddDevice function, as the third parameter to the PcInitializeAdapterDriver routine.

NTSTATUS
  DriverEntry(
    PDRIVER_OBJECT  DriverObject,
    PUNICODE_STRING  RegistryPath
    )
  {
      return PcInitializeAdapterDriver(DriverObject, RegistryPath, MyAddDevice);
  }

The PcInitializeAdapterDriver routine installs the supplied AddDevice routine in the driver object's driver extension and installs the port-class driver's IRP handlers in the driver object itself.

The following code is an example implementation of the driver's MyAddDevice function.

#define MAX_MINIPORTS 6    // maximum number of miniports
NTSTATUS
  MyAddDevice(
    PDRIVER_OBJECT  DriverObject,
    PDEVICE_OBJECT  PhysicalDeviceObject
    )
  {
      return PcAddAdapterDevice(DriverObject, PhysicalDeviceObject, MyStartDevice,
                                MAX_MINIPORTS, 0);
  }

This function calls the PortCls routine PcAddAdapterDevice, which creates the specified adapter device, associates a driver with the device, and stores a pointer to the adapter driver's MyStartDevice function, which is called when the operating system starts the device. The PcAddAdapterDevice routine creates a functional device object and associates it with the physical device object that is supplied by the system. The new functional device object is created with an extension that the port-class driver uses to store context information about the device. This context includes the MyStartDevice function pointer that is supplied by MyAddDevice.

After the operating system determines what resources (interrupts, DMA channels, I/O port addresses, and so on) to assign to the device, it sends the device a request to start. In response to this request, the request handler in the port-class driver calls the adapter driver's MyStartDevice function, which is shown in the example code below.

NTSTATUS
  MyStartDevice(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp,
    PRESOURCELIST ResourceList
    )
{
    ...
}

The request handler supplies MyStartDevice with pointers to the device object, IRP_MN_START_DEVICE request, and resource list (see IResourceList). The MyStartDevice function partitions the resource list into the resources that are required for each miniport that needs to be started. The function then starts each miniport and returns control to the port-class driver, which completes the IRP and returns control to the operating system.

For more examples of driver startup code, see the sample audio adapter drivers in the Windows DDK.


Subdevice Creation

The term subdevice is used to describe the binding of the following four components:

  • Miniport — an object that exposes the miniport interface
  • Port — an object that exposes the port interface
  • List of resources — adapter driver resources attributed to the subdevice
  • Reference string — a name added to the device path name to specify a subdevice during filter creation

The port-class driver does not distinguish between the port driver and the miniport driver; it simply wants an object, such as the port driver object, that has an interface to handle system-generated requests. Likewise, the port-class driver is not concerned about resources, and only needs to bind the request handler (the port driver) to a reference string. The adapter driver should bind the port, miniport, and resources together, whereas the port-class driver is only called to bind the port driver to the reference string.

The following code example illustrates this procedure:

  //
  // Instantiate the port using a function supplied by the port class
  //
  PPORT       port;
  NTSTATUS    ntStatus = PcNewPort(&port,PortClassId);

  if (NT_SUCCESS(ntStatus))
  {
    PUNKNOWN miniport;
   //
   // Create the miniport object
   //
    if (MiniportCreate)   // a function to create a custom miniport
    {
      ntStatus = MiniportCreate( &miniport,
        MiniportClassId,
        NULL,
        NonPagedPool);
    }
    else
    {
      ntStatus = PcNewMiniport((PMINIPORT*)&miniport,MiniportClassId);
    }

    if (NT_SUCCESS(ntStatus))
    {
      //
      // Bind the port, miniport and resources.
      //
      ntStatus = port->Init( DeviceObject,
        Irp, miniport, UnknownAdapter, ResourceList );
      if (NT_SUCCESS(ntStatus))
      {
        //
        // Hand the port driver and the reference
        // string to the port class
        //
          ntStatus = PcRegisterSubdevice( DeviceObject,
            Name, port );
      }

       //
       // We don't need to reference the miniport driver now.
       // Either the port driver references it,
       // or we've failed so it should be deleted.
       //
       miniport->Release();
    }

    //
    // Release the reference that existed when PcNewPort() gave us the
    // pointer in the first place. This is the right thing to do
    // regardless of the outcome.
    //
    port->Release();
  }


Reference-Counting Conventions for COM Objects

The methods in the audio interfaces follow a general set of rules for counting references on the COM objects that they take as input parameters or return as output parameters. These rules are summarized below. Note the exceptions to these rules that are also described below. For more information on COM interfaces, see the COM section of the Platform SDK documentation.

Reference Counting on Input Parameters

When calling a method that takes a reference to an object X as an input parameter, the caller is obliged to hold its own reference on the object for the duration of the call. This behavior is necessary to ensure that the method's pointer to object X remains valid until it returns. If the object Y that implements this method needs to hold a reference to object X beyond the return from this method, the method should call AddRef on object X before returning. When object Y later finishes using object X, it should call Release on object X.

For example, the IServiceGroup::AddMember method calls AddRef on the IServiceSink object that it adds to its service group. To complement this behavior, the IServiceGroup::RemoveMember method calls Release on the IServiceSink object that it removes from the service group.

Reference Counting on Output Parameters

A method that passes an object reference to the caller through an output parameter should call AddRef on the object before it returns (or before it releases its own reference to the object). This behavior is necessary to ensure that the caller holds a valid reference upon return from the call. The caller is responsible for calling Release on the object when it has finished using it.

For example, the IMiniportWaveCyclic::NewStream method calls AddRef on the stream, service-group, and DMA-channel objects that it outputs to the caller (the WaveCyclic port). The caller is responsible for releasing these references when it no longer needs them. See the SB16 sample adapter in the Windows DDK for an example implementation of the IMiniportWaveCyclic::NewStream method that shows this behavior.

Exceptions to the Rules

See IMiniportWavePci::NewStream for a description of the unconventional reference counting that this method performs on its DmaChannel output parameter.


Writing 64-Bit Audio Drivers

If you are writing a 64-bit driver or writing a driver that can be compiled to run on both 32- and 64-bit systems, follow the porting guidelines in Driver Programming Techniques. Some of the pitfalls that you might encounter in writing a 64-bit audio driver are described below.

First and foremost, a potential problem to look for in existing 32-bit driver code is conversion between pointer types and integer types such as DWORD or ULONG. Programmers with experience writing code for 32-bit machines might be used to assuming that a pointer value will fit into a DWORD or ULONG. For 64-bit code, this assumption is dangerous. Casting a pointer to type DWORD or ULONG can cause a 64-bit pointer to be truncated. A better approach is to cast the pointer to type DWORD_PTR or ULONG_PTR. An unsigned integer of type DWORD_PTR or ULONG_PTR is always large enough to store the entire pointer, regardless of whether the code is compiled for a 32- or 64-bit machine.

For example, the IRP pointer field IoStatus.Information is of type ULONG_PTR. The following code shows what not to do when copying a 64-bit pointer value to this field:

    PDEVICE_RELATIONS pDeviceRelations;
    Irp->IoStatus.Information = (ULONG)pDeviceRelations;  // wrong

The above code erroneously casts the pDeviceRelations pointer to type ULONG, which can truncate the pointer value if sizeof(pDeviceRelations) > sizeof(ULONG). The correct approach is to cast the pointer to ULONG_PTR, as shown below:

    PDEVICE_RELATIONS pDeviceRelations;
    Irp->IoStatus.Information = (ULONG_PTR)pDeviceRelations;  // correct

This preserves all 64 bits of the pointer value.

A resource list stores the physical address of a resource in a structure of type PHYSICAL_ADDRESS (see IResourceList). To avoid truncating a 64-bit address, you should access the structure's QuadPart member rather than its LowPart member when copying an address into the structure or reading an address from the structure. For example, the FindTranslatedPort macro returns a pointer to a CM_PARTIAL_RESOURCE_DESCRIPTOR structure that contains the base address of an I/O port. The u.Port.Start member of this structure is a PHYSICAL_ADDRESS pointer to the base address. The following code shows what not to do:

    PUSHORT pBase = (PUSHORT)FindTranslatedPort(0)->u.Port.Start.LowPart;  // wrong

Again, this can truncate the pointer. Instead, you should access the QuadPart of this member, as shown below:

    PUSHORT pBase = (PUSHORT)FindTranslatedPort(0)->u.Port.Start.QuadPart;  // correct

This will copy the entire 64-bit pointer.

Inline Win64 functions such as PtrToUlong and UlongToPtr safely convert between pointer and integer types without relying on assumptions about the relative sizes of these types. If one type is shorter than the other, it must be extended when converting to the longer type. Whether the shorter type is extended by filling with the sign bit or with zeros is well defined for each Win64 function. This means that any code snippets such as

    ULONG ulSlotPhysAddr[NUM_PHYS_ADDRS];
    ulSlotPhysAddr[0] = ULONG(pulPhysDmaBuffer) + DMA_BUFFER_SIZE;  // wrong

should be replaced by

    ULONG_PTR ulSlotPhysAddr[NUM_PHYS_ADDRS];
    ulSlotPhysAddr[0] = PtrToUlong(pulPhysDmaBuffer) + DMA_BUFFER_SIZE;  // correct

This is preferred even though ulSlotPhyAddr might represent the value of a hardware register that is only 32 rather than 64 bits long. See The New Data Types for a list of all the new Win64 helper functions for converting between pointer and integer types.


Miniport Interfaces

The following is a list of classes of miniport driver interfaces:

WaveCyclic Miniport

Supports access to DMA-based wave I/O functions of ISA and other audio cards. The interface specifically addresses cyclic (autoinit) DMA buffers; it ignores streaming issues.

PCI Scatter/Gather Miniport

Supports access to wave audio functions such as the wave I/O functions of a PCI audio card. In this model, lists of wave audio buffers are logically appended to create a stream of wave audio.

Topology Miniport

Supports access to the various controls (volume, equalization, and reverb) that audio adapters typically include. This interface is focused on enumerating components (known as nodes) in the topology, discovering their interconnections, and reading and writing control parameters.

MIDI Miniports

Supports access to simple MIDI-hardware devices such as FM synthesizers. This class of driver is served by the MIDI port driver, but timing is handled by the port driver. The miniport driver is only responsible for the delivery of MIDI bytes. MIDI devices that handle their own timing are supported by a different class of miniport that is served by the Microsoft® DirectMusic® (DMUS) port driver.

Advanced MIDI DLS Miniports

Supports more advanced hardware and software and MIDI devices such as wavetable synthesizers. This class of miniport drivers is served by the DirectMusic (DMUS) port driver, which provides high performance for devices such as MPU-401. Timing can be handled by either the miniport driver or the port driver. In addition to MIDI playback and recording, the miniport driver supports Downloadable Sounds (DLS). This miniport class also support software synthesis.


WaveCyclic Miniport

This class of miniport drivers supports access to cyclic DMA-based wave audio functions. The interface addresses cyclic buffers specifically, and ignores streaming issues. Multiple channels are supported, each one unidirectional.

The miniport should support two interfaces: the first supports miniport initialization, channel enumeration, and stream creation; the second is the stream interface, which exposes most of the miniport's functionality.

The overall miniport interface supports three functions:

  • Initialize the miniport.
  • Enumerate the channels.
  • Create the stream object.

The stream object interface (which is not derived from IMiniport) exposes the bulk of the miniport functionality.

See IMiniportWaveCyclic and IMiniportWaveCyclicStream for more information.


PCI Scatter/Gather Miniport

The PCI Scatter/Gather Wave Input and Output class of miniport drivers supports access to scatter/gather DMA-based wave audio functions. The interface addresses physical mappings specifically, and ignores streaming issues. Multiple channels are supported; each channel is unidirectional.

The miniport should support two interfaces:

  • The first is the miniport interface, which is for miniport initialization, channel enumeration, and stream creation.
  • The second is the stream interface, which exposes most of the miniport's functionality.

The following two interfaces are supported:

IMiniportWavePci

IMiniportWavePciStream


Topology Miniport

The Topology class of miniport drivers supports access to the various controls (volume, equalization, and hardware reverb) that are typically offered by audio adapters by exposing a topology that consists of a set of nodes and their interconnections. A node can have any number of properties, one of which is typically the control value that is specific to the node type.

Controls are organized in a hierarchy to allow arbitrary subdivision of the control graph. A top-level control, designated by the identifier zero, contains, directly or indirectly, all other controls in the graph.

Nodes that have control values can be specified to have any type of value that can be supported by the property mechanism. Typically, a node will have a maximum of one control value. For example, a volume node would have a value indicating its current volume setting. Volume and pan would be exposed as separate nodes.

Nodes are connected to one another by entities called connections. Connections are directed, referring to a from node and a to node. A connection also specifies a pin number for both of its associated nodes. Although pins are not explicitly supported as entities in the topology, the inputs and outputs with distinct functions can be differentiated by the pin numbering in the connection entities. For example, a state variable filter might have three output pins, one each for high, middle, and low frequencies. Pin numbering allows clients of the miniport to determine which connections are associated with which pins.

A distinguished node identification is used to represent the topology's external connections. In the WDM streaming environment, the pins on this filter node are the pins on the filter implemented by the topology port driver. These pins represent physical connections of the adapter hardware; they do not allow connection or support of data flow. Some of the filter pins represent connections internal to the system, such as the point at which analog data from a DAC enter the topology. Other filter pins represent external physical connections, such as the Line Out jack on an audio adapter.

Node pin numbering alone does not allow the client to determine the functions of the pins. Although the miniport identifies the type of a node (by means of a GUID), it does not provide a description of the node type or a description of the pins supported by the node type.

Note The set of node types and associated properties is described in the section on Audio Topology Nodes.

The miniport interface also supports the delivery of unsolicited control value changes from the miniport to the port driver. This feature allows for devices that can be physically manipulated by the user. External changes to node control values are indicated by a notification call to the lower edge of the port driver.

The PCCONNECTION_DESCRIPTOR structure provides a descriptor to the topology miniport interface for describing connections between two pins in a topology. A pin can be a part of multiple connections.

The following interface is supported:

IMiniportTopology

A miniport with an IMiniportTopology interface binds to the corresponding port driver, which has an IPortTopology interface, to form a topology filter.


MIDI Miniports

The MIDI miniport model is intended for simple devices that process MIDI data on a byte-by-byte basis. Multiple MIDI streams are supported; each stream is unidirectional. The MIDI port driver handles all timing issues in both directions and relies on the miniport driver to promptly move data on and off the adapter in response to the calls listed in the following section. This functionality is supported in miniport drivers via the IMiniportMidi and IMiniportMidiStream interfaces.

IMiniportMidi handles miniport initialization and creation of MIDI streams, and IMiniportMidiStream passes MIDI bytes and the state of the stream. The miniport driver calls the IPortMidi interface on the port driver.

The following two interfaces are supported for MIDI:

IMiniportMidi

IMiniportMidiStream


Advanced MIDI DLS Miniports

The DirectMusic (DMus) miniport model is intended for wavetable and other more advanced MIDI devices, including those that support DLS (downloadable sounds). Multiple MIDI streams are supported; each channel is unidirectional. The main MIDI functionality is implemented in miniport drivers via the IMiniportDMus and IMXF interfaces. Additional DLS functionality for software synthesizers is supported through the ISynthSinkDMus interface.

IMiniportDMus handles miniport initialization and creation of MIDI streams; IMXF handles the passing of MIDI messages and the state of the stream. ISynthSinkDMus handles the PCM interface out of the miniport driver.

The miniport driver calls the following additional interfaces on the port driver:

IPortDMus

IAllocatorMXF

IMasterClock


Kernel Streaming Topology to Audio Mixer API Translation

The mixer API is a set of Windows multimedia functions that are used to retrieve information about audio-mixer devices. The mixer API classifies audio-mixer lines as source and destination lines. Source lines are inputs into the audio card (for example, CD, microphone, line-in, and wave). Destination lines are outputs from the card (for example, speakers, headphones, phone line, and wave in). For a source line to be valid, it should have a unique path from the source to a destination. A single source line might map to more than one destination, but no more than a single path can connect a source line to a destination line. For more information on the mixer API, see the Platform SDK documentation.

The WDM driver for an audio adapter exposes a KS-filter topology that represents the data paths through the hardware and the functions that are available on those paths. The WDMAud system driver (in the wdmaud.sys and wdmaud.drv files) should interpret the KS-filter topology and generate the corresponding source and destination mixer lines that are exposed through the mixer API. WDMAud also handles the mixer API calls and translates them into the equivalent property calls on the filter pins and nodes that are managed by the adapter driver.

The KMixer system driver (kmixer.sys) and SWMidi system driver (swmidi.sys) are integral components of the kernel audio stack. KMixer provides system-wide audio mixing, bit-depth conversion, sample-rate conversion, and channel-to-speaker configuration (supermix) translation for PCM audio streams. SWMidi provides high-quality software synthesis of MIDI streams. The system audio driver, SysAudio (see SysAudio System Driver), combines the capabilities of KMixer and SWMidi with the installed audio adapter drivers to form functionally enhanced virtual audio devices.

WDMAud manages the interface between the KS portion and the legacy (see WinMM System Component) portion of the audio stack. WDMAud translates the pins on the SysAudio-virtualized filters into the legacy mixer lines that are presented in applications such as SndVol32. The translation from KS topology to mixer lines is performed as follows:

  1. Source pins (KSPIN_DATAFLOW_OUT) in the KS topology are exposed as DST mixer lines.
  2. Sink pins (KSPIN_DATAFLOW_IN) in the KS topology are exposed as SRC mixer lines.
  3. WDMAud walks the filter graph beginning at the source pin that lies at the endpoint of the filter graph and traverses the graph in the direction opposite to data flow until a sink pin is reached.
  4. The properties that are supported on each node that is encountered during the traversal are exposed as controls on the SRC line.

For more information on the topology parsing algorithm used by WDMAud, refer to WDMAud Topology Parsing.


Topology Pins

Topology pins are translated into source and destination audio-mixer lines that are exposed by the mixer API. When a pin is queried for its KSPROPERTY_PIN_DATAFLOW property, a sink pin returns the value KSPIN_DATAFLOW_IN and a source pin returns KSPIN_DATAFLOW_OUT. Sink pins become source mixer lines, and source pins become destination mixer lines. Each pin found in the topology will become either a source or destination line, but might not be shown in SNDVOL32 because of restrictions that are described in SYSTRAY and SNDVOL32.


Topology Nodes

Audio applications can access mixer controls through the Windows multimedia function mixerGetLineControls. This function retrieves an array of one or more MIXERCONTROL structures, each of which describes the state and metrics of a single control node on an audio line. The dwControlType member of the MIXERCONTROL structure is set to an enumeration value that specifies the type of the control. A number of mixer-control types have been specified for audio VxDs, but only a subset of these controls is available for WDM audio drivers.

WDMAud translates some but not all topology nodes into corresponding mixer-line controls. The topology-node types that are listed in the following table have counterparts that are mixer-line controls.

Node type | Topology-node type name | Mixer-control type name
AGC | KSNODETYPE_AGC | MIXERCONTROL_CONTROLTYPE_ONOFF
Loudness | KSNODETYPE_LOUDNESS | MIXERCONTROL_CONTROLTYPE_LOUDNESS
Mute | KSNODETYPE_MUTE | MIXERCONTROL_CONTROLTYPE_MUTE
Tone (multiple) | KSNODETYPE_TONE | MIXERCONTROL_CONTROLTYPE_ONOFF (if KSPROPERTY_AUDIO_BASS_BOOST is supported) MIXERCONTROL_CONTROLTYPE_BASS (if KSPROPERTY_AUDIO_BASS is supported) MIXERCONTROL_CONTROLTYPE_TREBLE (if KSPROPERTY_AUDIO_TREBLE is supported)
Volume | KSNODETYPE_VOLUME | MIXERCONTROL_CONTROLTYPE_VOLUME
Peakmeter | KSNODETYPE_PEAKMETER | MIXERCONTROL_CONTROLTYPE_PEAKMETER (Windows Me, and Windows XP and later)
MUX | KSNODETYPE_MUX | MIXERCONTROL_CONTROLTYPE_MUX
Stereo wide | KSNODETYPE_STEREO_WIDE | MIXERCONTROL_CONTROLTYPE_FADER
Chorus | KSNODETYPE_CHORUS | MIXERCONTROL_CONTROLTYPE_FADER
Reverb | KSNODETYPE_REVERB | MIXERCONTROL_CONTROLTYPE_FADER
Supermix (multiple) | KSNODETYPE_SUPERMIX | MIXERCONTROL_CONTROLTYPE_MUTE (if KSPROPERTY_AUDIO_MUTE is supported in the supermix node) MIXERCONTROL_CONTROLTYPE_VOLUME (see comments in text)

Topology-node types that are missing from the table above are not translated into mixer-line controls, and mixer-line controls that are missing from the table are not supported by WDM audio drivers.

Note that MIXERCONTROL_CONTROLTYPE_CUSTOM is missing from the table. This means that WDM audio drivers do not support custom mixer controls.

A tone node supports four properties: bass, treble, mid frequency, and bass boost. The mid-frequency property has no mixer-line counterpart, but the other three properties do. For each tone node discovered in the topology, a query is made for each of the supported properties:

KSPROPERTY_AUDIO_BASS

KSPROPERTY_AUDIO_TREBLE

KSPROPERTY_AUDIO_BASS_BOOST

Each property query that succeeds generates a mixer-line control. Due to naming issues, a single tone node should support only a single property. If a device supports both bass and treble, for instance, it should have two tone nodes so that the nodes can have different names.

A supermix node is queried to support up to two controls: mute and volume. A supermix node can be used as a mute control when it satisfies at least one of these two conditions for every entry in the supermix node's capabilities table:

  • The entry supports the mute property, as specified by the Capabilities.Mute flag.
  • The entry is fully attenuated (-Inf dB attenuation) and cannot be turned up, which is specified by both Capabilities.Minimum and Capabilities.Maximum having the value LONG_MIN (0x80000000).

A supermix node can be used as a volume control when every entry in the supermix capabilities table has a nonzero range. All other controls are translated one-to-one. When a recognized node is encountered, the mixer-line driver queries the respective property for that node.

To check for stereo or mono support, the left channel is queried, followed by the right channel, and finally, if both of these fail, the master channel (-1) is tried. If none of these queries succeeds, no control is generated for that node. Note that the MUX node is not queried for each channel. Instead, a single query to retrieve the current MUX selection is performed.

The name of the control is returned as a string when the node is queried for its KSPROPERTY_TOPOLOGY_NAME property. If a node generates more than one control, all controls will share the same name.

Windows Me, and Microsoft® Windows® XP and later, support peakmeter nodes (see KSNODETYPE_PEAKMETER) This node type is not supported by earlier versions of Windows.


WDMAud Topology Parsing

Destination mixer lines are parsed first. Destination lines are parsed in the reverse order from which they are discovered by SysAudio. For example, the higher numbered pins are parsed first. Parsing starts at the immediate parent of the pin. Each node is translated according to these rules until a terminating condition is found:

  • Current node being parsed is a SUM node.
  • Current node being parsed is a MUX node.
  • Current node has multiple parents.

SUM and MUX nodes are the classic terminators of the destination line. A SUM node does not generate any controls. A MUX node generates a MUX control in the destination line that contains references to each of the source lines controlled by the MUX.

If multiple parents are discovered, parsing is immediately terminated. The mixer-line driver treats this condition as a "virtual sum" where multiple inputs are combined.

The name of the destination line comes from the name returned from the KSPROPERTY_PIN_NAME property on that pin.

After all destination line controls have been translated, the mixer line translates the source lines. Again, they end up being parsed in the reverse order as queried from SysAudio. Source lines are parsed in the opposite direction as destination lines, when parsing starts from the pins and proceeds downward until a terminating condition is found:

  • Parser has found a destination.
  • Current node being translated belongs to a destination line.
  • Current node is a SUM node.
  • Current node is a MUX node.

When a MUX is encountered during parsing of a source line that belongs to a destination line, it is translated into a control. However, it is used only as a placeholder to update the line numbers in the MUX stored in the destination line later. The final line numbers are not yet available at this point so a placeholder is required.

Both a MUX and a SUM node terminate a source line, therefore any nodes between a SUM or MUX and another SUM or MUX are not translated.

Note The line names in the MUX are derived from the pin name for the line, except when the line feeding into a MUX is from a SUM or MUX node. In that case, the name of the line is the name of the MUX or SUM node. When the mixer driver discovers this, it builds a virtual mixer line with the name of the SUM or MUX node, and then translates all the controls between the SUM or MUX and the MUX.

Note A split in the topology is a case where a node has more than a single child. This is useful when a single pin routes to two separate destinations but shares some common controls, such as volume or a mute. Any time a split is encountered, the WDMAud driver creates a new line and duplicates all the controls parsed up to the split. This happens unconditionally whenever a split is encountered, even after encountering a SUM node that terminates a source line.


SYSTRAY and SNDVOL32

The SYSTRAY applet (systray.exe) is responsible for displaying the speaker icon in the system-tray notification area of the taskbar. By default, this is at the bottom-right corner of the Windows screen. The speaker icon represents the SndVol32 volume-control applet (sndvol32.exe).

If the speaker icon is hidden, you can display the speaker icon on the taskbar as follows:

  • Open the Sounds and Multimedia applet in the control panel.
  • On the Sounds tab, under Sound Volume, select the "Show volume control on the taskbar" option.

If your sound card's volume level can be changed under software control, a speaker icon appears on the taskbar. You can change the volume by clicking that icon and adjusting the sliders.

At login time, SYSTRAY queries the audio driver for a mixer line with a MIXERLINE_COMPONENTTYPE_DST_SPEAKERS (speaker destination) or MIXERLINE_COMPONENTTYPE_DST_HEADPHONES (headphone destination) component type to determine whether the speaker icon should be displayed. If neither of these component types is found, SYSTRAY will not display the speaker icon. If it does find the line, it queries the line to see if it contains a mute control. SYSTRAY completes its login-time mixer-line processing by internally storing the line ID and mute control ID for future reference.

The SndVol32 applet provides a user interface for controlling all volume controls in the system. When a user clicks the speaker icon in the system tray, a master volume control, which is provided by SndVol32, appears. SndVol32 uses a different algorithm to determine what it displays. For the master volume slider, it looks for the first volume control on the "master" destination (for example, the destination that is numbered zero). Typically, this will end up being the speaker destination.

When SndVol32 runs, it queries the mixer-line driver looking for a set of controls that it knows about. To display a slider panel, it should have at least one of the following controls on the SOURCE line:

  • Volume control
  • Mute control
  • Advanced control (AGC, bass, or treble)

If none of these controls are found, SndVol32 will not display the panel. A source line simply being part of a MUX with no controls is not sufficient for display. This can easily be circumvented by putting in a fake MUTE control in the topology to get the panels to display. When the line simply feeds into a MUX, the Select box displayed for MUXes will hide the MUTE control.

WDM Audio topology nodes that do not map well into a mixer line control are not displayed by SndVol32. Refer to Topology Nodes for details on which nodes get translated into mixer-line controls. The WDM mixer-line driver translates some nodes into controls, but SndVol32 only displays the set of controls that it knows about.


Exposing Miniport Topology

A miniport driver describes the internal topology of a KS filter in terms of pins, nodes, and connections. This topology specifies the data-flow paths through the filter, and also defines the logical targets—pins and nodes—for property requests. The intra-filter topology is a logical representation of the internal structure of the hardware device that underlies the filter. The miniport describes this topology with static arrays of pin, node, and connection descriptors.

  • Pins are specified in a static array of PCPIN_DESCRIPTOR structures. Each pin has an ID that is its ordinal in the array.
  • Nodes are specified in a static array of PCNODE_DESCRIPTOR structures. Each node has an ID that is its ordinal in the array.
  • Connections (pin-to-pin, pin-to-node, or node-to-node) are specified in a static array of PCCONNECTION_DESCRIPTOR structures.

The miniport exposes these three arrays in the PCFILTER_DESCRIPTOR structure that it outputs from its IMiniport::GetDescription method.

Example

The code example below specifies the internal topology of a simple KS filter that has one input pin and one output pin. The filter contains a single node, which is a volume-level control.

#define WAVEOUT_SRC_PIN  0
#define LINEOUT_DST_PIN  1

PCPIN_DESCRIPTOR
MiniportPins[] =
{
    {   // Pin 0 -- WAVEOUT_SRC_PIN
        0,0,0,  // InstanceCount
        NULL,   // AutomationTable
        {       // KsPinDescriptor
            0,                                          // InterfacesCount
            NULL,                                       // Interfaces
            0,                                          // MediumsCount
            NULL,                                       // Mediums
            SIZEOF_ARRAY(PinDataRangePointersBridge),   // DataRangesCount
            PinDataRangePointersBridge,                 // DataRanges
            KSPIN_DATAFLOW_IN,                          // DataFlow
            KSPIN_COMMUNICATION_NONE,                   // Communication
            &KSNODETYPE_LEGACY_AUDIO_CONNECTOR,         // Category
            NULL,                                       // Name
            0                                           // Reserved
        }
    },
    {   // Pin 1 -- LINEOUT_DST_PIN
        0,0,0,  // InstanceCount
        NULL,   // AutomationTable
        {       // KsPinDescriptor
            0,                                          // InterfacesCount
            NULL,                                       // Interfaces
            0,                                          // MediumsCount
            NULL,                                       // Mediums
            SIZEOF_ARRAY(PinDataRangePointersBridge),   // DataRangesCount
            PinDataRangePointersBridge,                 // DataRanges
            KSPIN_DATAFLOW_OUT,                         // DataFlow
            KSPIN_COMMUNICATION_NONE,                   // Communication
            &KSNODETYPE_SPEAKER,                        // Category
            &KSAUDFNAME_VOLUME_CONTROL,                 // Name (this name shows up as
                                                        // the playback panel name in SoundVol)
            0                                           // Reserved
        }
    }
};

#define WAVEOUT_VOL_NODE  0

PCNODE_DESCRIPTOR TopologyNodes[] =
{
    {   // WAVEOUT_VOL_NODE
        0,                      // Flags
        &AutomationVolume,      // AutomationTable
        &KSNODETYPE_VOLUME,     // Type
        &KSAUDFNAME_WAVE_VOLUME // Name
    }
};

PCCONNECTION_DESCRIPTOR MiniportConnections[] =
{ //FromNode-----------FromPin-----------ToNode-------------ToPin
  { PCFILTER_NODE,     WAVEOUT_SRC_PIN,  WAVEOUT_VOL_NODE,  1 },
  { WAVEOUT_VOL_NODE,  0,                PCFILTER_NODE,     LINEOUT_DST_PIN }
};

The figure below shows the topology of the filter that is described by the sample code above.

A Simple Filter Topology

This filter is a simple example of a topology filter, which an adapter driver forms by binding its IMiniportTopology object to an IPortTopology object that the PortCls system driver creates. The filter's input (sink) and output (source) pins are named WAVEOUT_SRC_PIN and LINEOUT_DST_PIN. The mixer API exposes the connections to these pins as SRC and DST mixer lines, respectively.

Both pins handle analog signals. Pin WAVEOUT_SRC_PIN takes the analog signal that is output by a wave filter, which might be a filter of type WaveCyclic or WavePci. The wave filter represents the portion of the audio adapter's hardware that converts a wave stream into an analog signal. Pin LINEOUT_DST_PIN outputs an analog signal that drives a set of speakers.

The filter contains a single node, WAVEOUT_VOL_NODE, which represents the volume control. It is a node of type KSNODETYPE_VOLUME. All nodes of this type support the KSPROPERTY_AUDIO_VOLUMELEVEL property, which a client of the filter uses to control the volume level.

The node has two "logical" pins, which are numbered 0 and 1. The two connections that are specified by the MiniportConnections array are represented in the figure by dashed arrows that point in the direction of data flow. Each connection is described by one of the two elements in the array.


Installing a Port Class Audio Adapter

This section includes the following topics about the device-class-specific information that a vendor should include in an INF file to install a port-class audio adapter (see Introduction to Port Class):

Specifying Version Information for an Audio Adapter

Installing Device Interfaces for an Audio Adapter

Installing Core System Components for an Audio Adapter

Installing Windows Multimedia System Support for an Audio Adapter

Installing an Audio Adapter Service

Miscellaneous Installation Issues for an Audio Adapter

The information in this section applies to Microsoft® Windows® 98/Me, and Windows 2000 and later. See Device Installation Overview for a description of the general INF file requirements and options for all device classes.

The description of the required INF file entries in this section is based on a hypothetical XYZ Audio Device. Example Manufacturer and Models sections for this device are shown below:

[VendorName]  ; Manufacturer section
%XYZ-Audio-Device-Description%=XYZ-Audio-Device, <Plug and Play hardware ID>
[XYZ-Audio-Device]  ; Models section
AddReg=XYZ-Audio-Device.AddReg

The adapter driver for the XYZ Audio Device is xyzaud.sys. This file name will be used in the example AddReg and AddService sections that are presented below.

For additional examples, see the sample INF files ac97\driver\ac97sampl.inf and sb16\mssb16.inf in the WDM\Audio directory in the directory tree that contains the DDK samples.


Specifying Version Information for an Audio Adapter

This section describes the version information that an INF file specifies for a port-class audio adapter.

A vendor should specify the following entries in the Version section of an INF file for a port-class audio adapter:

Signature="$CHICAGO$"
Class=MEDIA
ClassGUID={4d36e96c-e325-11ce-bfc1-08002be10318}

See INF Version Section for a description of additional version requirements and options for all device classes.


Installing Device Interfaces for an Audio Adapter

This section describes how to specify device interfaces in a port-class audio adapter's INF file.

A client accesses an audio device through a set of device interfaces that a vendor should specify in the adapter's INF file. The device interfaces specified in the device's INF file have a one-to-one correspondence with the subdevices that the adapter driver creates when it initializes the device (see Subdevice Creation). The INF file specifies a FriendlyName entry value, which is accessible in user mode, for each device interface under the interface's registry key.

In the kernel-streaming architecture, topology categories represent device interface classes. See the KSCATEGORY_Xxx categories defined in ks.h and ksmedia.h.

The topology categories most relevant to audio adapters are:

  • KSCATEGORY_ACOUSTIC_ECHO_CANCEL
  • KSCATEGORY_AUDIO
  • KSCATEGORY_CAPTURE
  • KSCATEGORY_MIXER
  • KSCATEGORY_RENDER
  • KSCATEGORY_SYNTHESIZER
  • KSCATEGORY_TOPOLOGY
  • KSCATEGORY_DRM_DESCRAMBLE

All audio devices are classified under KSCATEGORY_AUDIO, but an audio device might also be classified under additional categories such as KSCATEGORY_RENDER (for an audio rendering device) or KSCATEGORY_SYNTHESIZER (for a synthesizer). For each category that the INF file specifies for a device, the Windows installer builds a set of registry entries for that device under the category name (see Filter Factories).

The following example installs four common system-defined device interfaces that an adapter typically supports for an audio device.

Example of Installing Audio Device Interfaces

The following device install section for the XYZ Audio Device uses the AddInterface directive to install four audio adapter interfaces. The directive assigns a unique reference string to each interface, which the adapter driver can use to distinguish between instances of each interface class.

[XYZ-Audio-Device.Interfaces]
AddInterface=%KSCATEGORY_AUDIO%,%KSName_Wave%,XYZ-Audio-Device.Wave
AddInterface=%KSCATEGORY_RENDER%,%KSName_Wave%, XYZ-Audio-Device.Wave
AddInterface=%KSCATEGORY_CAPTURE%,%KSName_Wave%, XYZ-Audio-Device.Wave
AddInterface=%KSCATEGORY_TOPOLOGY%,%KSName_Topology%, XYZ-Audio-Device.Topology

The AddReg section specified by each AddInterface directive adds the following registry entries to a device interface subkey, which is accessible in user mode under the \DeviceClasses\<InterfaceGUID> registry key:

  • A FriendlyName registry entry specifies a friendly name for each device interface.
  • DirectShow® requires a CLSID registry entry, set to a proxy GUID value, which indicates that the adapter can be accessed and controlled by the KSProxy system driver.

The following INF file entries add the FriendlyName and CLSID registry entries for each interface:

[XYZ-Audio-Device.Wave]
AddReg=XYZ-Audio-Device.Wave.AddReg
[XYZ-Audio-Device.Wave.AddReg]
HKR,,FriendlyName,,%WaveDeviceName%
HKR,,CLSID,,%Proxy.CLSID%

[XYZ-Audio-Device.Topology]
AddReg=XYZ-Audio-Device.Topology.AddReg
[XYZ-Audio-Device.Topology.AddReg]
HKR,,FriendlyName,,%WaveDeviceMixer%
HKR,,CLSID,,%Proxy.CLSID%

The following is the Strings section for this example.

[Strings]
KSCATEGORY_AUDIO = "{6994AD04-93EF-11D0-A3CC-00A0C9223196}"
KSCATEGORY_RENDER="{65E8773E-8F56-11D0-A3B9-00A0C9223196}"
KSCATEGORY_CAPTURE="{65E8773D-8F56-11D0-A3B9-00A0C9223196}"
KSCATEGORY_TOPOLOGY="{DDA54A40-1E4C-11D1-A050-405705C10000}"
Proxy.CLSID ="{17CCA71B-ECD7-11D0-B908-00A0C9223196}"
WaveDeviceName = "XYZ Audio Device"
WaveDeviceMixerName = "XYZ Audio Device Super Mixer"

The string name that an INF AddInterface directive specifies for a KSCATEGORY_Xxx device interface cannot be localized because the adapter driver uses the same name internally as a string constant. The sample adapter drivers in the DDK use the following string names for their audio device interfaces:

  KSNAME_Wave="Wave"
  KSNAME_UART="UART"
  KSNAME_FMSynth="FMSynth"
  KSNAME_Topology="Topology"
  KSNAME_Wavetable="Wavetable"
  KSNAME_DMusic="DMusic"

For the sake of uniformity, your proprietary driver should assign these same names to its corresponding device interfaces. If your driver supports additional device interfaces that are proprietary, you can invent your own proprietary names for these interfaces. Make sure that the names that the driver uses match those in your INF file. If the strings do not match, system setup will not load the driver.


Installing Core System Components for an Audio Adapter

This section includes the following topics about installing the core system components for a port-class audio adapter:

Installing in Windows 2000 and Later

Installing in Windows 98/Me

The INF DDInstall Section for each hardware ID specified in the manufacture's MODEL section should specify the inclusion of the KS.Registration section in ks.inf and the WDMAUDIO.Registration section in wdmaudio.inf. The ks.inf file installs the core kernel streaming components. The wdmaudio.inf file installs the core WDM audio components. Vendors should not modify or replace these system INF files.


Installing in Windows 2000 and Later

The following entries in a device-install section add the system-driver information that installs the core system components for an audio adapter in Windows 2000 and later:

[XYZ-Audio-Device.Registration.NTX86]
Include=ks.inf, wdmaudio.inf
Needs=KS.Registration, WDMAUDIO.Registration

See INF DDInstall Section for a discussion of the Include and Needs directives.


Installing in Windows 98/Me

The following entries in a device-install section add the system-driver information that installs the core system components for an audio adapter in Windows 98/Me:

[XYZ-Audio-Device.Registration]
AlsoInstall=KS.Registration(ks.inf),WDMAUDIO.Registration(wdmaudio.inf)

The AlsoInstall directive should only be used if the INF file is provided by a vendor and the device is installed in Windows 98/Me. For Windows 2000 and later, use the Include and Needs directives instead.


Installing Windows Multimedia System Support for an Audio Adapter

This section describes the information that the system audio drivers require to establish support by the Windows multimedia system for a port-class audio adapter.

The following AddReg section sets the registry entries that the system uses to establish support for the audio adapter by the Windows Multimedia System:

[XYZ-Audio-Device.AddReg]
HKR,,AssociatedFilters,,"wdmaud,swmidi,redbook"
HKR,,Driver,,xyzaud.sys
HKR,Drivers,SubClasses,,"wave,midi,mixer,aux"

HKR,Drivers\wave\wdmaud.drv, Driver,,wdmaud.drv
HKR,Drivers\midi\wdmaud.drv, Driver,,wdmaud.drv
HKR,Drivers\mixer\wdmaud.drv,Driver,,wdmaud.drv
HKR,Drivers\aux\wdmaud.drv,Driver,,wdmaud.drv

HKR,Drivers\wave\wdmaud.drv,Description,,%XYZ-Audio-Device-Description%
HKR,Drivers\midi\wdmaud.drv,Description,,%XYZ-Audio-Device-Description%
HKR,Drivers\mixer\wdmaud.drv,Description,,%XYZ-Audio-Device-Description%
HKR,Drivers\aux\wdmaud.drv,Description,,%XYZ-Audio-Device-Description%


Installing an Audio Adapter Service

This section includes the following topics about installing a port-class adapter service:

Installing an Audio Adapter Service in Windows 2000 and Later

Installing an Audio Adapter Service in Windows 98/Me


Installing an Audio Adapter Service in Windows 2000 and Later

The following AddService directive installs the adapter driver xyzaud.sys for the XYZ Audio Device:

[XYZ-Audio-Device.Services.NTX86]
AddService = XYZ-Audio-Device, 0x00000002, XYZ-Audio-Device.Service.Install

[XYZ-Audio-Device.Service.Install]
DisplayName   = %XYZ-Audio-Device.ServiceDescription%
ServiceType   = 1                  ; SERVICE_KERNEL_DRIVER
StartType     = 3                  ; SERVICE_DEMAND_START
ErrorControl  = 1                  ; SERVICE_ERROR_NORMAL
ServiceBinary = %12%\system32\drivers\xyzaud.sys


Installing an Audio Adapter Service in Windows 98/Me

The INF file sets an NTMPDriver entry value in the adapter driver's registry key as follows:

[XYZ-Audio-Device.AddReg]
HKR,,NTMPDriver,,"xyzaud.sys,sbemul.sys"


Miscellaneous Installation Issues for an Audio Adapter

Listed are the most common installation issues for an audio adapter:

  • Only Windows 98/Me support the UseFDMA flag. In these operating systems, the [WDMAUDIO.FDMA] section in the wdmaudio.inf file sets the UseFDMA flag in the registry, causing the DMA controller to be configured to perform Type-F DMA transfers. If a proprietary INF file needs to set this flag, it does so by including wdmaudio.inf and invoking the [WDMAUDIO.FDMA] section of that file.

    Windows 2000 and later (including the 64-bit versions of Windows) ignore the UseFDMA flag, and the [WDMAUDIO.FDMA] section in their wdmaudio.inf files does not load this flag into the registry

  • Windows 98 does not support the following:
    • WavePci (see PCI Scatter/Gather Miniport) and DMus (see Advanced MIDI DLS Miniports) miniports
    • Hardware mixing on a WaveCyclic miniport

    The INF file for a port-class audio adapter (see Introduction to Port Class) that uses the above functionality should not install the driver in Windows 98. See Installation Issues for an Audio Driver in Windows 98.

  • Windows 98 Second Edition does not support the full functionality of a WavePci miniport. In Windows 98 SE, installation of a port-class adapter driver with a WavePci miniport is driver-specific.
  • During initial installation of an audio device or when undergoing an operating system upgrade that destroys existing audio settings, the driver should ensure that the settings are initialized to reasonable default values. For more information, see Default Audio Volume Settings.
  • During an operating system upgrade, an audio device's installed driver and registry settings can frequently be preserved. See Operating System Upgrades for guidelines on how to make this process transparent to users.
  • Windows 2000 limits the number of device interfaces that can be exposed through the following Windows multimedia APIs: waveIn, waveOut, midiIn, midiOut, mixer, and aux. See Windows 2000 Device-Interface Limits.


Installation Issues for an Audio Driver in Windows 98

Support for WDM audio drivers is limited in Windows 98, as explained in Windows 98 Support for WDM Audio. For this reason, vendors might want to prevent their audio drivers from installing in Windows 98. Also, a vendor who does choose to allow a driver to install under Windows 98 might want to design the driver to perform a runtime check to see if it is running in Windows 98 before it attempts to use any audio capabilities that Windows 98 does not support.

These topics are discussed below:

Stopping Installation from a Driver's INF File

Performing a Runtime Check for Windows 98

Stopping Installation from a Driver's INF File

The following excerpt from the DDK sample INF file ac97sampl.inf shows how to use a KnownRegEntries directive to stop installation in Windows 98:

[AC97SMPL]
KnownRegEntries=AC97.KnownRegEntries

[AC97.KnownRegEntries]
IsWin98Gold=keep

[IsWin98Gold]
1=HKLM,Software\Microsoft\Windows\CurrentVersion,VersionNumber,0,4.10.1998

The registry subkey under HKLM that is specified in the IsWin98Gold section does not have to specify Software\Microsoft\Windows\CurrentVersion. A vendor can use a vendor-specific registry entry and value to control a driver's installation.

The "keep" entry excludes the driver specified in the INF file from the list of driver candidates for the device's specified in the INF file.

Performing a Runtime Check for Windows 98

An adapter driver's StartDevice routine can perform a simple test to determine whether or not it is running in Windows 98. The example function below queries the WaveCyclic port for the IPortEvents interface. Only versions of Windows later than Windows 98 support this interface. If the driver is running in Windows 98, the IsWin98Gold function below returns TRUE. Otherwise, it returns FALSE to indicate that it is running on one of the following: Windows 98 SE, Windows Me, or Windows 2000 and later.

BOOL IsWin98Gold()
{
    BOOL    fWin98Gold=TRUE;

    // create a wave cyclic port
    PPORT pPort = 0;
    ntStatus = PcNewPort(&pPort, CLSID_PortWaveCyclic);

    if (!NT_SUCCESS(ntStatus))
    {
        DOUT(DBG_ERROR, ("Error creating a Port"));
        return (FALSE);
    }

    // query an event interface (not supported in Windows 98)
    PPORTEVENTS pPortEvents = 0;
    ntStatus = pPort->QueryInterface(IID_IPortEvents, (PVOID *)&pPortEvents);
    if (NT_SUCCESS(ntStatus))
    {
        fWin98Gold = FALSE;
        pPortEvents->Release();
    }
    pPort->Release();
    return (fWin98Gold);
}


Default Audio Volume Settings

The SndVol32 applet displays a set of volume sliders. A master volume slider controls the volume of the mixed output signal. The other sliders indicate the volume-level settings for the various audio sources (wave, CD audio, MIDI, and so on). If the driver does not explicitly initialize these volume settings at the time that it is installed, the operating system chooses its own default values for these settings. The defaults that the operating system chooses are not the same across all Windows releases and vendors might need to take these differences into account in order to ensure that the volume settings immediately following driver installation are neither too high nor too low.

By default, Windows 98/Me and Windows 2000 set all the SndVol32 volume levels to the middle of the slider, a position that represents six decibels of attenuation. The operating system applies this default setting to the master volume as well as to all the other volume sliders (wave, CD audio, MIDI, and so on).

The wave, CD audio, and MIDI sliders typically control volume nodes on KMixer. These nodes scale the audio stream before it reaches the audio hardware. By scaling the data, KMixer is discarding digital resolution that the hardware could use to render a higher-quality audio signal.

Windows XP, in order to avoid this loss of audio quality, uses different default volume settings. It sets the volume levels on the wave, CD audio, MIDI, and other audio sources to zero decibels of attenuation (pass-through mode). This translates to a full-volume slider setting for each of these sources in SndVol32. These settings improve the default sound quality by ensuring that KMixer does not degrade the original resolution of the source signal.

Windows XP does not change the default master-volume setting, which remains at six decibels of attenuation. The master volume control represents the hardware volume node on the adapter pin that KMixer's output pin is connected to.

Of course, the INF file that installs an audio adapter driver can override the operating system's default volume settings with its own default settings. To achieve the best sound quality at installation, a driver should leave the default volume settings on the various audio sources (wave, CD audio, MIDI, and so on) at full volume and set the default master volume to six decibels or more of attenuation. A default setting of zero decibels (full volume) for the master volume control might subject users to an unpleasantly loud sound the first time they boot their systems following device installation. A default master volume setting in the range 9 to 18 decibels of attenuation is typically loud enough to be clearly audible.

As a general rule, if the audio adapter drives a set of analog speakers that have their own volume control, the INF file should not set the default volume level too low. Otherwise, a user might try to compensate by cranking up the volume on the speakers instead of increasing the master volume on the sound card. The result of amplifying a low signal level will be a loss in audio quality.

Ideally, if a set of active speakers ships in the same box with the audio adapter card, the factory should adjust the volume knob on the speakers to the position that works best with the adapter's default volume setting.


Operating System Upgrades

An audio device's driver and registry settings can frequently be preserved across operating system upgrades. The discussion below presents some guidelines for accomplishing this.

Preserving Audio Settings

A typical audio adapter driver keeps track of device settings—chiefly volume levels and mute settings—in the system registry. When the user alters these settings through a control panel or other audio application, the driver updates the appropriate registry entries. Each time the system boots, the driver restores the device settings from the registry.

When upgrading from Windows 98/Me to an NT-based operating system (Windows 2000 or later), the Windows installation program is unable to preserve these settings.

However, when upgrading from Windows 98 to Windows Me, or from one NT-based operating system to another (for example, from Windows 2000 to Windows XP), the installation program leaves the driver's existing registry settings intact. Users largely prefer this behavior because it preserves the adjustments they have made to the system over time instead of forcing them to try to restore their settings manually each time they upgrade the operating system.

Some proprietary drivers, however, blindly overwrite these registry settings with defaults each time they are installed. A better approach for a driver is to determine at installation time whether certain driver-specific registry entries already exist. If they do exist, the driver should preserve the settings that are contained in these entries instead of overwriting them.

Migration DLL

During an upgrade from Windows 98/Me to an NT-based operating system (Windows 2000 and later), the Windows installation program treats a device driver that was installed under Windows 98/Me as incompatible and discards both the driver and its registry settings. Worse yet, if the NT-based Windows release has no built-in driver support for the device, the installation program will ask the user to provide the driver software.

Frequently, a better approach is to use a migration DLL to copy the registry settings and re-install the existing drivers, which can be done transparently to the user. For this purpose, Microsoft provides the Devupgrd migration DLL and its associated documentation. These are included in the Setup Plug-and-Play samples in the Windows DDK. The migration DLL should be used only with WDM drivers that are initially installed under Windows 98/Me but are also capable of running on Windows 2000 and later.

During device installation, the migration DLL does the following:

  • Reads device driver information from its location in the Windows 98/Me registry.
  • Adds the necessary information to the Setup INF file to ensure that the device is properly installed.

Devupgrd must be added to the Windows 98/Me registry so that the upgrade code for the NT-based Windows release will load and process it during system migration.


Windows 2000 Device-Interface Limits

In Windows 2000, the Windows multimedia functions allow a maximum of ten device interfaces on each of the following APIs: waveIn, waveOut, midiIn, midiOut, mixer, and aux. For example, an application can create up to ten device interfaces for waveIn devices, and another ten for waveOut devices.

In Microsoft® Windows® XP, the limit on the number of device interfaces per API is increased from ten to 32.

These limits do not apply to Windows 98/Me, which allow applications to create arbitrary numbers of device interfaces.

A device interface uniquely identifies each subsystem driver. For example, a device that ships with two subsystem drivers—one for Sound Blaster and one for USB—requires two device interfaces.

The limitation on the number of device interfaces does not limit the number of devices. A subsystem driver that manages several devices (four MIDI devices, for instance) still requires only a single device interface.

Example

For example, an adapter driver might expose the following device interfaces:

Device interface 1: wave

Device interface 2: UART

Device interface 3: wavetable

Assume that these three device interfaces expose the following devices:

  • Device interface 1 (wave)

    1 waveOut device

    1 waveIn device

    1 midiOut device (software synthesizer)

    1 mixer device

    1 aux device

  • Device interface 2 (UART)

    1 midiOut device (MPU401)

    1 midiIn device (MPU401)

    (0 for all other device types)

  • Device interface 3 (wavetable)

    1 midiOut device (wavetable synthesizer)

    (0 for all other device types)

The following table summarizes the number of device interfaces per device type:

Device type | Number of device interfaces
waveOut | 1
waveIn | 1
midiOut | 3
midiIn | 1
mixer | 1
aux | 1

If a system contains four of these adapters, the total number of midiOut device interfaces is 4x3 = 12. Windows will install only ten of the 12 midiOut device interfaces for use by its multimedia functions. If an application calls midiOutGetNumDevs, the call will return ten rather than 12.


Data-Intersection Handlers

The SysAudio system driver constructs an audio filter graph by connecting together pairs of audio-filter pins. Before a source pin can be connected to a sink pin, SysAudio must negotiate a common format that the two pins can use to exchange data. The details of this negotiation are largely delegated to the data-intersection handlers that are implemented in the individual filters.

When connecting a KMixer source pin to the sink pin of an audio port, for example, SysAudio calls the port driver's data-intersection handler to determine a common format for the two pins. The port driver consists of a port-class driver (WavePci, for example) that is paired with an adapter driver. The adapter driver's proprietary data-intersection handler is always given the first opportunity to determine a common format. If the proprietary handler declines this opportunity, however, the port-class driver's default data-intersection handler determines the format instead.

The port-class driver's default data-intersection handler is designed to deal with the most common hardware features. For simple audio devices, the default handler provides a convenient alternative to implementing a proprietary handler in the adapter driver. However, adapters with more advanced features might need proprietary handlers in order to expose the full capabilities of the hardware.

The remainder of this section describes some of the limitations of the port-class driver's default data-intersection handler and presents the techniques that are needed to design a proprietary data-intersection handler for an adapter driver. The following topics are discussed:

Data Intersection

Default Data-Intersection Handlers

Proprietary Data-Intersection Handlers

Hardware Constraints on Sample Frequency

Output Buffer Size

Data Ranges with Discrete Values

Wild Cards

Data-Range Properties

KMixer Behavior


Data Intersection

The SysAudio system driver constructs an audio filter graph by connecting pairs of filter pins that support compatible audio data formats. SysAudio uses a technique called data intersection (short for data-range intersection) to negotiate a common format between two pins.

The set of formats that each pin supports is specified as an array of data ranges, where each data range is a structure of type KSDATARANGE_AUDIO. A data range specifies a general format type, which can be KSDATAFORMAT_WAVEFORMATEX or KSDATAFORMAT_DSOUND. In addition, the data range specifies a range of values for each of the following parameters:

  • bits per sample
  • sample frequency
  • number of channels

The KSDATARANGE_AUDIO structure specifies both minimum and maximum values for the bits-per-sample and sample-frequency ranges but only a maximum for the number-of-channels range. The minimum number of channels is implicitly one.

The job of negotiating a common data format for two pins consists of finding two data ranges—one from each pin—that intersect each other. A pair of data ranges intersect if:

  • They support the same general wave format (WAVEFORMATEX or DSound).
  • Their bits-per-sample ranges overlap.
  • Their sample-frequency ranges overlap.

As mentioned previously, the KSDATAFORMAT_AUDIO structure implies a hardware model in which the minimum number of channels supported by a pin is always one. According to this model, the number-of-channels ranges for any two pins should always overlap because both pins support at least one channel. Obviously, a hardware adapter with a minimum number of channels greater than one does not conform to this model, but the adapter driver can include a proprietary data-intersection handler to deal with issues like this. See the example in Proprietary Data-Intersection Handlers.

Once the handler finds a pair of intersecting data ranges for the two pins, a common data format can be selected from the region of intersection:

  • The number of bits per sample is selected from the region in which the two bits-per-sample ranges overlap.
  • The sample frequency is selected from the region in which the two sample-frequency ranges overlap.
  • The number of channels is selected from the region in which the two number-of-channels ranges overlap.

When negotiating a common format for an audio port's sink pin and the source pin of another filter (KMixer, for example), SysAudio first obtains the source pin's data-range array. SysAudio then sends a KSPROPERTY_DATA_INTERSECTION request to the sink pin and includes the source pin's data-range array with this request. The kernel-streaming layer intercepts the request and iteratively calls the port-class driver's data-intersection handler once for each successive element in the source pin's data-range array, beginning with the first element, until the handler succeeds in finding a data intersection.

With each call to the port-class driver's data-intersection handler, the handler first obtains the sink pin's data-range array from the adapter driver. It then iterates through the array, beginning with the first element, until it succeeds in finding an intersection between a sink-pin data range and the current source-pin data range. The handler selects a common format that lies within the intersection and outputs this format to the caller.

At each step in the iteration, the port-class driver calls the adapter driver's proprietary data-intersection handler with the two data ranges—one for each of the two pins. If at any step the proprietary handler declines to handle a data-intersection check between the two data ranges, the port-class driver's data-intersection handler performs the check instead.

To summarize, the search for an intersection between a source-pin data range and a sink-pin data range is an iterative process:

  • In the outer loop, the kernel-streaming layer iterates through successive elements in the source pin's data-range array, beginning with the first array element.
  • In the inner loop, the port-class driver iterates through successive elements in the sink pin's data-range array, beginning with the first array element.

The search stops upon finding the first data intersection. This process tends to favor the elements toward the beginning of each pin's data-range array. When specifying an array of data ranges for a pin, an adapter driver should order the array elements by placing data ranges for preferred formats toward the beginning of the array.


Default Data-Intersection Handlers

An adapter's proprietary data-intersection handler (the miniport object's DataRangeIntersection method) can decline to perform the data-intersection check by returning the STATUS_NOT_IMPLEMENTED status code. In this case, the port-class driver's default data-intersection handler performs the check on behalf of the adapter.

You can implement a minimal data-intersection handler for your adapter driver as a DataRangeIntersection method that declines all data-intersection requests by returning STATUS_NOT_IMPLEMENTED.

The current implementation of the port-class driver's default handler is limited in the types of data ranges that it can handle:

  • only PCM data formats
  • only mono and stereo audio streams

An adapter driver that supports non-PCM or multichannel formats should implement a proprietary data-intersection handler instead of relying on the port-class driver to handle data intersections for these formats.

In addition, the default handler supports only audio formats that can be specified by a KSDATAFORMAT_DSOUND or KSDATAFORMAT_WAVEFORMATEX structure. It does not support any format that contains a WAVEFORMATEXTENSIBLE structure, which is needed, for example, to specify the channel mask for a format with more than two channels.

When choosing a common format from the intersection between two data ranges, the port-class driver's default handler always selects the highest value in each parameter's region of intersection:

  • If the intersection spans more than one valid sample frequency (11, 22, and 44 kHz, for example), the default handler picks the highest frequency.
  • If the intersection spans more than one valid bits-per-sample value (8, 16, and 32 bits, for example), the default handler picks the largest value.
  • If the intersection spans both mono and stereo formats, the default handler picks stereo.

If the default handler selects a format that is unsatisfactory, the adapter driver has the option of rejecting the format by failing the NewStream call (for example, see IMiniportWavePci::NewStream) when SysAudio attempts to create a sink pin with the format. If the call fails, SysAudio will not continue looking for data intersections. Instead, it will attempt to create a connection by iterating through a list of the PCM formats that are supported by system filters such as KMixer until it finds one that that the adapter's sink pin can support as well. The list is ordered with higher quality formats first. As before, the adapter rejects unsatisfactory formats in the list by failing the NewStream calls for those formats.


Proprietary Data-Intersection Handlers

You can overcome the limitations of the default data-intersection handler by writing a proprietary handler for your adapter. A proprietary handler is implemented as the DataRangeIntersection method on a miniport object. See the sample adapter drivers in the DDK for examples of DataRangeIntersection methods.

A proprietary data-intersection handler can compensate for nonstandard hardware features that cannot be adequately specified in the KSDATARANGE_AUDIO structure. For example, the ICHAud sample adapter driver in the DDK manages hardware that can support two or more audio channels during playback, but cannot support mono. The sample's DataRangeIntersection method determines whether the data range for the other filter's source pin is limited to mono (that is, MaximumChannels < 2). If so, it fails the call by returning STATUS_NO_MATCH.

A proprietary data-intersection handler has the option of handling data intersections on some of its pins and allowing the port-class driver's default data-intersection handler to handle data intersections on the other pins.

The remainder of this section presents guidelines for implementing proprietary data-intersection handlers.


Hardware Constraints on Sample Frequency

Some audio devices require that the sample frequency at the adapter filter's sink pin match the frequency of a digital output port or the input stream from a microphone. For example, Sound Blaster 16-compatible hardware typically has a single crystal, which constrains its input and output streams to run at the same clock rate. An adapter that can support more than one clock rate for its various on-board audio streams might still need to restrict the number of different clock rates to some small number.

For these reasons, an adapter driver might need to constrain the sample frequency on one on-board stream to match that of another on-board stream. For example, a Sound Blaster 16-compatible adapter might require that the sample frequency at the adapter's sink pin match the rate at which the latches are clocked at the output DACs.

When KMixer's source pin is connected to an adapter's sink pin, KMixer might need to call the adapter's SetFormat method (for example, see IMiniportWavePciStream::SetFormat) to adjust the sample frequency at the connection to match the highest sample frequency of the audio streams at its inputs. If the adapter is unable to change the frequency—perhaps because it is constrained by the clock rates of other on-board streams—it can fail the SetFormat call. In this case, KMixer will respond by making more SetFormat calls with successively lower sample frequencies until the call succeeds. Once KMixer has settled on a reduced sample frequency, it will sample-down its higher frequency input streams accordingly.


Output Buffer Size

The miniport's DataRangeIntersection method copies the structure that specifies the negotiated data format into a buffer that is allocated by the caller. The method's OutputBufferLength parameter specifies the buffer's size in bytes. Note that the size of the format structure varies with the selected format. In order to avoid writing past the end of the buffer, the DataRangeIntersection method should first verify that the allocated buffer is big enough to contain the format.

For a mono or stereo format, the minimum size for the output buffer is either sizeof(KSDATAFORMAT_WAVEFORMATEX) or sizeof(KSDATAFORMAT_DSOUND), depending on whether a WAVEFORMATEX or DSound format has been selected.

If the wave format supports more than two channels, the WAVEFORMATEX structure that is embedded at the end of the KSDATAFORMAT_WAVEFORMATEX structure expands to occupy an additional number of bytes that is equal to the difference sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX).


Data Ranges with Discrete Values

If your audio device supports sample frequencies of 11, 22, and 44 kHz, for example, you can specify all three frequencies as a range of 11 to 44 kHz in a single KSDATARANGE_AUDIO structure. This technique has the benefit of being concise. A potential disadvantage is that a buggy data-intersection handler might choose an invalid parameter value (for example, 27 kHz) that falls within the range. In this case, the adapter driver has no option but to fail the NewStream call (for example, see IMiniportWavePci::NewStream) that attempts to create a pin with the invalid format.

Another approach is to provide a list of data ranges in which each data range specifies a discrete value rather than a range of values for each parameter. For example, instead of providing a single data range to specify a range of sample frequencies from 11 to 44 kHz, the data-range array can contain three separate elements for 11, 22, and 44 kHz. In each of these elements, the maximum and minimum sample frequencies are set to the same value (11, 22, or 44 kHz). The benefit of this approach is that it eliminates any ambiguity about the precise values that are supported. Also, if one discrete value is preferred over another, the data range that contains this value can be moved to a position in the array that is ahead of the data range that contains the other value. A minor disadvantage of discrete values is that they can increase the size of the data-range array.


Wild Cards

The header file ks.h defines the following wild-card parameters for KS data ranges:

  • KSDATAFORMAT_TYPE_WILDCARD
  • KSDATAFORMAT_SUBTYPE_WILDCARD
  • KSDATAFORMAT_SPECIFIER_WILDCARD

The MajorFormat, Subformat, and Specifier members of the DataRange member of the KSDATARANGE_AUDIO structure can be set to these values. A wild card matches any corresponding value to which it is being compared, including any data formats that might be defined in the future. System filters that can move data without understanding the data format are the primary users of wild cards. Adapter drivers should avoid specifying wild cards in the data ranges for their filter pins, but should be prepared to accept wild cards in the data ranges for the client filter's pins.


Data-Range Properties

Data ranges are used not only for data intersection, but can be accessed as device properties as well (see Audio Stream Data Formats). For this reason, an adapter driver whose data-intersection handler takes care of all format negotiations on its pins should still include a complete set of data ranges. The data ranges should reflect as closely as possible the data-format preferences that are embodied in the adapter's data-intersection handler.

A pin's data ranges can be accessed through the following properties:

KSPROPERTY_PIN_DATARANGES

KSPROPERTY_PIN_CONSTRAINEDDATARANGES

These two properties designate the pin's static data ranges and constrained data ranges, respectively.

Constrained data ranges provide more accurate information on the current capabilities of a device because they are dynamically updated to account for any on-board resources that have already been allocated for other purposes. By comparison, static data ranges might inaccurately report hardware capabilities that depend on resources that are no longer available.

In the current PortCls implementation, the default data-intersection handlers in the port-class drivers use only an adapter's static data ranges.


KMixer Behavior

An audio adapter's sink pin is typically connected to the source pin from the KMixer system filter during playback of a PCM stream. As wave streams are added to or removed from the audio mix, KMixer might need to call the miniport stream's SetFormat method (for example, see IMiniportWavePciStream::SetFormat) to adjust the sink pin's sample frequency.

In order to preserve the quality of the wave-data streams that enter its sink pins, KMixer attempts to adjust the sample frequency at its source pin to match the highest sample frequency of the streams entering its sink pins. Accordingly, as new streams are added or removed from the mix entering its sink pins, KMixer might need to increase or decrease the sample frequency at its source pin in order to accommodate the new mix. KMixer attempts to change the sample frequency at the connection between its source pin and an adapter's sink pin by calling the adapter's SetFormat method to request the change. If KMixer's call to SetFormat requests a sample rate that is higher than the adapter can support, the adapter fails the call. In this case, KMixer responds by calling SetFormat with successively lower sample frequencies until the SetFormat call succeeds. KMixer then down-samples the higher-frequency streams at its sink pins as necessary to accommodate the lower sample frequency at its source pin.

When SysAudio first creates the connection between KMixer's source pin and an adapter's sink pin, the initial sample frequency at the connection might not match the highest sample frequency at KMixer's sink pins. In this case, KMixer attempts to adjust the connection's sample frequency by calling SetFormat, as described previously.

In the current KMixer implementation, KMixer's handling of the bits-per-sample and number-of-channels settings at its source pin differs from its handling of the sample frequency. Once SysAudio creates a connection between the KMixer source pin and an adapter sink pin, KMixer never modifies the connection's initial bits-per-sample or number-of-channels settings. Ideally, these settings should match the maximum settings in the data streams entering KMixer's sink pins in order to preserve the quality of the audio data. Therefore, the adapter's proprietary data-intersection handler should choose the format with the highest bits-per-sample and number-of-channels values that lies within the intersection of the data ranges for the two pins. Note that a proprietary handler that is written to work this way will not need to be rewritten if in the future KMixer's behavior changes to dynamically adjust the connection's bits-per-sample and number-of-channels settings to accommodate dynamic changes in the KMixer inputs.


Power Management for Audio Devices

The PortCls system driver handles all power-management IRPs on behalf of audio adapter drivers. PortCls manages the power state of an audio device by making calls through the adapter driver's IAdapterPowerManagement and IPowerNotify interfaces. Both interfaces are optional. The adapter driver for a device that can change its power state in response to requests from PortCls should expose an IAdapterPowerManagement interface. In addition, a miniport object that requires advance warning of an impending power-down should expose an IPowerNotify interface.

The remainder of this section presents information on these topics:

Implementing the IAdapterPowerManagement Interface

Implementing the IPowerNotify Interface


Implementing the IAdapterPowerManagement Interface

When implementing the IAdapterPowerManagement interface for your driver, refer to the implementation of the CAdapterCommon class in the sample audio drivers in the DDK. This class handles device interrupts and performs other functions that are common to all audio adapter drivers. Your adapter's CAdapterCommon class should inherit from the IAdapterPowerManagement interface and support this interface in its NonDelegatingQueryInterface method. (See the description of the INonDelegatingUnknown interface in the MSDN library for details on non-delegating interfaces.)

You can use the IMP_IAdapterPowerManagement definition from the portcls.h header file to add the function declarations for the IAdapterPowerManagement methods PowerChangeState, QueryPowerChangeState, and QueryDeviceCapabilities to your driver's CAdapterCommon class definition.

During the PortCls system driver's call to an adapter's StartDevice function, the adapter should register its IAdapterPowerManagement interface with PortCls by calling PcRegisterAdapterPowerManagement. For a code example, see the StartDevice function in the SB16 sample adapter driver in the DDK. The first parameter that is passed to the PcRegisterAdapterPowerManagement call is an IUnknown pointer to the adapter driver's CAdapterCommon object. PortCls queries this object for its IAdapterPowerManagement interface.

When PortCls calls the adapter driver's IAdapterPowerManagement::PowerChangeState method to change the device's power state, the adapter driver should cache the device's new power state in the adapter's CAdapterCommon object. During the CAdapterCommon::Init call (see the implementation in the DDK's sample adapter drivers), the driver should set the initial power state to PowerDeviceD0 before returning from a successful initialization. The driver should write to the hardware only if it is known to be in an appropriate power state. In the SB16 sample driver in the DDK, for example, the driver writes to the hardware only in the PowerDeviceD0 state.

Before powering down in response to a PowerChangeState call, the adapter driver should place the audio outputs in a state that will prevent speaker noise when the power switches off. The shutdown process might include ramping the DAC outputs to zero, turning off the DACs, and muting the MIDI lines, for example.


Implementing the IPowerNotify Interface

If your driver's miniport or miniport-stream objects need to know about power-state changes, they can support the IPowerNotify interface in their QueryInterface methods and receive notification from the PortCls system driver as power changes occur.

When the power state changes, the PortCls system driver calls the IPowerNotify::PowerChangeNotify method to individually notify each miniport and miniport-stream object that supports the IPowerNotify interface. During the PowerChangeNotify call, a miniport object should cache the new device power state. During the CAdapterCommon::Init call (see the implementation in the MSVAD sample adapter in the DDK, for example), the miniport should set its cached power state to the initial value, PowerDeviceD0.

Before calling PowerChangeState to power down, PortCls calls IPowerNotify::PowerChangeNotify to give the miniport an opportunity to save any necessary device context. This context might include the hardware-register values that embody the current filter topology and mixer-line settings, for example. After calling PowerChangeState to power up, PortCls calls PowerChangeNotify so that the miniport can restore the saved context.

When powering down, PortCls pauses any active audio data streams before calling PowerChangeNotify. When powering up, PortCls calls PowerChangeNotify before restarting any paused audio data streams.

Your miniport and miniport-stream object classes can inherit from the IPowerNotify interface and support this interface in their NonDelegatingQueryInterface method. You can use the IMP_IPowerNotify definition from the portcls.h header file to add the function declaration for the PowerChangeNotify method to the class definition for your driver's miniport and stream objects.


Version Numbers for Audio Drivers

Windows operating systems support three types of audio driver models: the VxD, WDM, and NT4 (Windows NT 4.0) driver models. The version number that you assign to your audio adapter driver depends on the driver model that you use, the Windows release that you target, and perhaps the DirectX® release as well. The four tables below list driver version numbers by driver model type.

Driver model: VxD drivers for Windows 95.

DirectX release | Driver version numbers
Windows 95 without DirectX support | 4.00.00.0096 to 4.02.00.0094
DX1 | 4.02.00.0096 to 4.02.00.9999
DX2 | 4.03.00.1097 to 4.03.00.9999
DX3 | 4.04.00.1097 to 4.04.00.9999
DX5 | 4.05.00.1000 to 4.05.00.9999
DX6 | 4.06.00.1000 to 4.06.00.9999

Driver model: VxD drivers for Windows 98.

DirectX release | Driver version numbers
DX5 | 4.05.01.2500 to 4.05.99.9999
DX6 | 4.06.00.1000 to 4.06.00.9999

Driver model: WDM drivers for Windows 98/Me, and Windows 2000 and later.

Windows release | Driver version numbers
Windows 98 | 4.10.00.2500 to 4.10.00.9999
Windows 2000 | 5.00.00.3500 to 5.00.00.9999
Windows Me | 4.90.00.3500 to 4.90.00.9999
Windows XP | 5.10.00.3500 to 5.10.00.9999

Driver model: NT4 drivers (Windows NT 4.0 only).

Windows release | Driver version numbers
Windows NT 4.0 | 4.00.00.1400 to 4.00.00.9999

For device drivers that do not support DirectX, the version number should be greater than or equal to 4.00.00.0096 and less than or equal to 4.02.00.0094. Device drivers that support DirectX version 1.0 should have a version number in the range 4.02.00.0096 to 4.02.00.9999. Device drivers that support later versions of DirectX should have a version numbers in the range appropriate for the distributed version of DirectX, as shown in the tables above.

All WDM drivers should have version numbers that are greater than or equal to 4.10.00.2500, which is the low end of the Windows 98 version-number range.

Note that WDM drivers that are written for earlier versions of Windows will run correctly on later versions as well. For example, a WDM driver that is written to run in Windows 2000 will also run in Microsoft® Windows® XP and later.

DirectX Version 1.0 drivers will work in systems with DirectX 2.0 installed. However, DirectX 2.0 drivers will not work correctly unless DirectX 2.0 is installed. The same is true for DirectX 3.0 and later releases.

A cross-platform driver should set its version number to the highest version number for the platforms on which the driver runs. For example, a vendor should use a driver-version number of 5.00.00.XXXX for a driver that supports Windows 2000, Windows 98, Windows 98 SE, and Windows Me.


Internal and External Version Numbers

The driver's resource file specifies the driver-file version in two ways:

  • As an internal or binary version number that is specified in the double-DWORD value FILEVERSION. The operating system currently does not use this value.
  • As an external or display version number that is specified in the FileVersion character string. The operating system displays this string when the user views the properties of individual driver files.

Under the Windows XP user interface, for example, you can view a driver file's FileVersion string in several ways:

  • Under the Windows Explorer, select the Properties of the driver file, click on the Version tab, and view the File version number.
  • Under the Device Manager, select the Properties of a particular audio device, click on the Driver tab, click on Driver Details, select the driver file from the list of files in the driver package, and view the File version number of the selected driver file.
  • Under Sounds and Audio Devices in the Control Panel, click on the Hardware tab, select the Properties of the device, click on the Driver tab, select Driver Details, select the driver file from the list of files in the driver package, and view the File version number of the selected driver file.

In order to make your driver version numbers compatible with both Windows and DirectX, follow these rules when you specify the internal and external version numbers:

  • The internal version number has the format x.xx.00.xxxx. The two extra zeros before the last dot are required.
  • The external version string should use the format x.xx.xxxx (without the two extra zeros in the internal version number).

These internal and external version numbers should match (except for the two extra zeros, as noted above).


INF Driver-Version Entry

The INF file in a driver package specifies the driver-version information for the drivers that are installed by the INF. The version information in the INF identifies the driver package as a whole, in contrast to the internal and external version numbers for the individual driver files within the package.

The INF specifies each driver's date and version number in a DriverVer directive with the following format:

DriverVer=mm/dd/yyyy[,x.y.v.z]

The date parameter mm/dd/yyyy consists of a two-digit month code mm, two-digit day code dd, and four-digit year code yyyy. This parameter specifies the date of the driver package and applies to all the driver files, including the INF file. A hyphen (-) can be used as the date-field separator in place of the slash (/). The operating system uses the DriverVer date to perform driver-version comparisons when selecting between two versions of a driver. This date also appears in the Driver Date value that the Device Manager displays.

The optional version number x.y.v.z , which is shown in brackets above, is used for display purposes only (for example, in the Driver Version number that the Device Manager displays). The operating system does not use this value for driver selection. When compiling driver files, make sure that the internal version number that is specified in the FILEVERSION parameter in the driver's resource file matches the DriverVer version number in the INF.

When the operating searches for drivers, it chooses a driver with a more recent DriverVer date over a driver with an earlier date. If an INF file has no DriverVer entry or is unsigned, the operating system applies the default date of 00/00/0000.

Windows 2000, Windows XP and later, require that the INF file for a driver package provide a DriverVer directive.


DirectX File Version Numbers

VxDs that support DirectX should meet the DirectX setup requirements for driver version numbers and driver capabilities. See the DirectX 8.0 Programmer's Reference. These requirements do not apply to WDM or Windows NT 4.0 drivers.

Use the following procedure to double-check the driver version numbers:

  • Use the Setup application provided with any DX-supported game to install the device driver. Record the version numbers for all installed files, including all .drv, .dll, .vxd, and .exe files in the driver-installation package.

Confirm that all internal version numbers correspond to external (string) version numbers and that the numbers follow the version-numbering rules (see Version Numbers for Audio Drivers).

  • Use the Windows Explorer to view the directory containing the files. Right-click each file and choose Properties to verify that the copyright information is correct. In particular, verify that your driver does not specify "Microsoft" as the vendor name.

To enable DirectSound drivers to report that they have been certified by Microsoft, copy the self-executable archive file dscert.exe from c:\akit or c:\akitnt to a temporary folder and execute it to extract the archived files. Then follow the instructions in text file dscert.txt, which is one of the extracted files.

DirectX driver certification is DirectX-specific and is entirely separate from the certification for the "Designed for Windows" logo. If you have any questions about DirectX version numbers, send e-mail to DXDriver@microsoft.com.


Control Panel Branding by Vendors

In Windows XP and later, the Sounds and Audio Devices control panel supports third-party branding of audio-device controls. Vendors can display the following items next to the controls for their audio devices:

  • company logo
  • proprietary device name
  • URL for a vendor web page

The INF file that installs the device driver also loads the control-panel customization data into the registry. Bitmapped images of company logos are contained in the installed driver files themselves.

Branding information is visible to Windows users in the following locations:

  • The Volume page of the Sounds and Audio Devices control panel (mmsys.cpl)
  • The SndVol32 "Volume Options" applet (sndvol32.exe)

The branding information is stored in the registry in a "Branding" subkey under the audio device's root key, which is located under the media-class key. The "Branding" subkey can contain one or more of the REG_SZ values that are shown in the table below.

Value name | Meaning
icon | Name of the file that contains the icon that is used by the SndVol32 control menu.
bitmap | Name of the file that contains the 32-by-32 bitmap that is displayed in the Volume page of the Sound and Audio Devices control panel.
url | The URL address of the vendor's web site. The visual representation is the audio device name in the Volume page of the control panel next to the logo. The audio device name is hotlinked to the vendor's web site.

These values are added to the registry by directives within the add-registry-section (see INF AddReg Directive) of the INF file that installs the device driver. The control panel will use defaults for any values that are missing from the "Branding" subkey.

The "bitmap" logo appears to the left of the proprietary device name at the top of the Volume page; if the "url" value exists, the device name is hotlinked to the vendor web site. The "icon" logo appears in the top-left corner of the SndVol32 control menu.

The proprietary device name that appears in the Volume page and SndVol32 control menu is the device's "friendly" name, which is specified by a directive in the add-registry-section of the INF file that installs the device. This directive contains the keyword "FriendlyName", as shown in the example in INF AddReg Directive. In Windows 98/Me, Windows 2000, and Windows XP, Volume and SndVol32 display only the first 31 characters of the name string. Longer strings are truncated.

Example

The example below shows three directives from the add-registry-section of a vendor's INF file:

[XYZ-Audio-Device.AddReg]
HKR,Branding,icon,,"foo.sys,102"
HKR,Branding,bitmap,,"c:\mydir\myimage.bmp"
HKR,Branding,url,,"http://www.foo.com/"

These three directives add control-panel branding information to the registry. HKR is the audio device's root key in the registry. The string value for the "icon" and "bitmap" keys can be specified in one of two formats: "file,resourceid" or "imagefile". The first directive in the example above uses the "file,resourceid" format. The directive assigns to the "icon" key a string value that contains a filename, foo.sys, and a resource ID of 102. The filename and resource ID are separated by a comma (with no spaces). The file foo.sys contains the icon resource. The second directive above assigns an "imagefile" formatted string to the "bitmap" key; the string contains the full pathname of a .bmp file that contains the bitmap.

The example directive for the "icon" value above can be changed to use the "imagefile" format, but in this case the string value should contain the pathname of a file with an .ico filename extension.

In the case of the "file,resourceid" format, the control-panel software searches the same list of the search paths as the LoadLibrary function (see the Platform SDK documentation). If this path list does not contain the file, the software also searches the "drivers" directory (see INF DestinationDirs Section). This format allows the images to be easily stored in the driver file itself without requiring that absolute pathnames be specified in the INF file.


DirectMusic Synths and Synth Sinks

This document is a design guide for implementing Microsoft® DirectMusic® synthesizers (synths) and synth sinks. Software synths and synth sinks can be implemented in user mode. Software or hardware components that provide the same functionality can be implemented in kernel mode.

For information about the DirectMusic API, see the Platform SDK documentation.

This design guide contains the following sections:

DirectMusic DDI Overview

Custom Rendering in User Mode

Kernel Mode Hardware Acceleration DDI


DirectMusic DDI Overview

User-mode concepts generally apply to kernel mode. For this reason, this guide begins with a discussion of user-mode implementations that gradually progresses to specific kernel-mode topics.

Typically, the best design strategy is to first write a user-mode implementation of the DirectMusic® DDI (device driver interface), even if the final product will be a kernel-mode implementation. Even if the final implementation uses hardware components, it can be beneficial to begin with a software version in user mode. After the user-mode version is completed, the software can be converted to kernel mode and connections established with the hardware, one feature at a time. For more information, see User Mode Versus Kernel Mode.

The user-mode interface for DirectMusic software synths is IDirectMusicSynth. For DirectMusic sinks, the user-mode interface is IDirectMusicSynthSink. The IKsControl interface is used for kernel streaming.

Kernel-mode terminology differs slightly from user-mode because of the port/miniport driver concept (described in Introduction to Port Class). The synth responsibilities are shared between the port and miniport drivers, with the device-specific areas falling in the miniport driver. The kernel-mode synth sink is part of the kernel port driver. As such, unlike the user-mode synth sink, the kernel-mode synth sink is not replaceable. Most, if not all, of the work that is required to build a custom kernel-mode driver is in the writing of the miniport driver. In most cases, the miniport driver is the only thing that the driver writer needs to write in order to support a piece of hardware or to implement a custom software synth for DirectMusic.

The following kernel-mode interfaces are used for custom DirectMusic miniport drivers:

IAllocatorMXF

IMiniportDMus

ISynthSinkDMus

IMXF

IMasterClock

IPortDMus


User Mode Versus Kernel Mode

A custom synth can be written in either user mode or kernel mode. In general, software synths are easier to implement in user mode, but they can frequently achieve lower latency in kernel mode. Hardware components can be supported only in kernel mode. There are good reasons, however, to consider beginning in user mode regardless of where the final implementation will be. These considerations are the subject of this section.

User-mode software implementations have many advantages. Building software synthesizers (and synth sinks) is much simpler in user mode. The user-mode interfaces are very easy to use, and debugging is greatly simplified. Another benefit is that the resulting component is simply a Windows executable. Because this executable is a COM object, installing it is simply a matter of self-registering from the command line with regsvr32.exe. (The RegSvr32 system application calls your DLL's DllRegisterServer function. For more information, see the Platform SDK documentation.)

If you decide that a user-mode implementation is all you need, there is the added benefit of being able to deliver your product with an application without a complicated driver installation and without requiring a reboot after installation. Your component can then optionally be enumerated as one of the available ports, depending on whether you want other applications to be able to use it. (See Registering Your Synthesizer for more information on this topic.)

The advantage of a kernel-mode software implementation is lower latency. However, this advantage is not as great as it used to be before the advent of time-stamped messages. Legacy MIDI APIs had no time-stamping, so when you played a note, that was exactly when it was cued to play. Time-stamping makes it possible to cue notes to play at specified times in the future. Using time-stamping means that the note will play at the correct time unless the advance warning is less than the latency inherent in the system.

Latency is only an issue when sounds are cued to play with little or no advance warning. When this is an issue, it may be worth the extra effort to implement software components in kernel mode. Thus, kernel-mode implementations are recommended only when there is an undesirable limitation to a user-mode software implementation or when supporting hardware acceleration.

If you decide to do a kernel-mode implementation, the best approach is still to begin development in user mode. The source code for Microsoft's user-mode synth is provided in the Windows DDK, so you don't have to write a new synth from scratch. You can use the existing code to better understand how the DLS (downloadable sounds; see Platform SDK documentation) downloads are parsed. Then you can add any new functionality (such as parsing additional chunks) and debug this logic in user mode first, stubbing out the hardware accesses.

Once you have your implementation working in user mode, you can move the whole thing down to kernel mode and make it work there. After you have the software version working in kernel mode, your next step is to begin moving the functionality to your hardware (if you have hardware, that is). The user- and kernel-mode software synths serve as useful scaffolds during the process of getting your hardware synth up and running.

To summarize: for software-only components, the recommended practice is to implement them first in user mode (to work out the design kinks with easy interfaces, debugging, installation, and removal) and then convert to kernel mode if there seems to be a need due to latency or other considerations.

For hardware components, we recommend implementing a software version in user mode (to work out the design kinks with easy interfaces, debugging, installation, and removal). Once this works satisfactorily, convert it to a kernel-mode software version. Finally, connect the kernel-mode component to hardware, one feature at a time, until everything works as desired.


Custom Rendering in User Mode

The Microsoft® Software Synthesizer is a user-mode component of the DirectMusic® installation and should be adequate for most synthesizer purposes. Future versions of DirectMusic will have a kernel-mode software synth as the default implementation. DirectMusic also allows you to implement your own user-mode software synthesizer or redirect rendered output to a device other than Microsoft® DirectSound® with a custom synth sink. (Custom synth sinks are seldom necessary.)

The source code to Microsoft's implementation of a user-mode software synthesizer is shipped in the DirectMusic DDK. You can use this code as an example for implementing your own custom user-mode synth. The most important header files for DirectMusic synths and synth sinks are dmusics.h (user mode only), dmusicks.h (kernel mode only), dmusbuff.h, and dmusprop.h.

The following topics cover aspects of customizing the rendering process. These concepts apply to both user and kernel mode except where noted otherwise, although the examples assume a user-mode implementation.

Synthesizers and Wave Sinks

MIDI to Wave

Synthesizer Timing

Custom DLS

Registering Your Synthesizer


Synthesizers and Wave Sinks

The rendering engine has two parts:

  • The synthesizer, which takes MIDI messages and converts them to wave audio samples.
  • The wave sink, which provides a destination for the wave samples and helps synchronize the output.

By default, a DirectMusic application uses the Microsoft Software Synthesizer (dmsynth.dll) as the synthesizer and DirectSound as the wave-output device. Either or both of these defaults can be overridden. For example, an application might use the Microsoft Software Synthesizer but direct the output to a .wav file, or it might implement a custom synthesizer that works with the default DirectSound sink. This latter is the more likely scenario because the default synth sink should work very well for most synthesizers.

The following diagram shows the architecture surrounding DirectMusic user-mode synthesizers and wave sinks.

DirectMusic Architecture for User-Mode Synthesizers and Wave Sinks

The application sends data to the user-mode IDirectMusicPort object (see Platform SDK documentation), which passes the data (MIDI or DLS) down to the software synth (dmsynth.dll by default) so that it can render the notes into wave data. The synth sink manages the timing and hands the synth a buffer to fill when it is ready to receive a burst of data. The synth fills up the buffer (an IDirectSoundBuffer object by default) with data so that it can be passed to DirectSound, which plays it through the KMixer system driver and takes advantage of any DirectSound hardware acceleration on the system.

This same basic architecture also applies to kernel-mode implementations, with the exception that the sink hands the data buffer directly to the hardware or to KMixer. See Kernel Mode Hardware Acceleration DDI for more on the architecture in kernel mode.

In user mode, a software synthesizer is created by implementing the IDirectMusicSynth interface, and a synth sink is created by implementing IDirectMusicSynthSink.

Before the synthesizer can be activated, the wave sink should be created and connected to the synth by a call to IDirectMusicSynth::SetSynthSink. This should be the very first call after creating the synth, because many of the timing-related calls are actually passed through to equivalent calls on IDirectMusicSynthSink.

Once these steps are completed, the user-mode DirectMusicPort should be open and activated for use. As soon as this much of the driver code is working, you can begin implementing features—use the user-mode Microsoft Software Synthesizer source code as a template and add your new functionality as you go.

See IDirectMusicSynth for a discussion of how to create an instance of the DirectMusic default user-mode synthesizer, connect it to an instance of the default user-mode wave sink, open the user-mode DirectMusicPort, and activate it for use.

The sample source code that ships as part of the DDK can serve as the template for your implementation. The default software synth for DirectMusic in DirectX® 6.1 is the user-mode synth. In later versions of DirectX, the default is the kernel-mode synth.


MIDI to Wave

The main work of the synthesizer is done in two steps:

  • Getting MIDI messages
  • Mixing the rendered notes into the wave audio stream

This section details generally how this is done in user mode, although the concepts are the same in kernel mode. See Kernel Mode Hardware Acceleration DDI for specifics on how to do the same thing with a kernel-mode miniport driver.

In user mode, the IDirectMusicSynth::PlayBuffer method is called by the application when it has MIDI messages ready to play. It is the application's responsibility to call PlayBuffer in a timely fashion and to timestamp the buffer correctly, taking latency into account. (See Synthesizer Timing.) Your implementation of this method retrieves the waiting messages and stores them in an internal format, which is stamped with a time that is based on the reference time that is passed in with the buffer.

The synth sink calls IDirectMusicSynth::Render whenever it is ready to receive data. For example, if the destination for the rendered data is a DirectSound secondary buffer, your implementation of IDirectMusicSynthSink::Activate might set up a thread that waits for a DirectSound PlayBuffer notification. When the DirectSoundBuffer requires data, DirectSound notifies the thread, which in turn calls Render, passing in a pointer to the IDirectSoundBuffer object (described in Platform SDK documentation) and the number and position of the samples that are to be rendered.

Because the DirectSound buffer is circular, a virtually contiguous region in the buffer can be split into two pieces, which requires that the possibility of wraparound be taken into account. Typically, this is handled by calling Render twice, once for each part of the locked portion of the DirectSound buffer. IDirectSoundBuffer::Lock is called on a DirectSound buffer to ask for write permission to a region of it. For example, if Lock is called on 2K bytes of data starting 1K bytes from the end of the buffer, what will be locked is the last 1K bytes up to the end of the buffer and another 1K bytes starting at the beginning of the buffer. In this case, Lock actually returns two pointers and corresponding lengths, which are guaranteed to point to contiguous regions of memory, and which together describe the region of the buffer that is locked. In order to hide this abstraction, the synth sink calls the synth's Render method twice in this case, so that the Render method only has to deal with contiguous blocks of memory.

Your implementation of the Render method is responsible for determining what needs to be done in response to the MIDI messages that are retrieved in PlayBuffer. From the dwLength parameter values of successive calls to Render, the method can keep track of the sample time and act on messages that are valid for the current rendering period. When a note-on message is processed, the note can be stored internally and rendered again on each pass through the method until a corresponding note-off message is received.


Synthesizer Timing

The synthesizer works with two different systems of time:

  • Reference time
  • Sample time

The reference time is the absolute time (in master-clock units) at which a sequence of messages is to be played. In user-mode implementations, it is passed to the IDirectMusicSynth::PlayBuffer method when MIDI messages are fed to the synthesizer. The synthesizer, synth sink, and the rest of DirectMusic should all work under the same master clock, which is attached to the synthesizer by your implementation of the IDirectMusicSynth::SetMasterClock method and to the synth sink by IDirectMusicSynthSink::SetMasterClock.

Sample time is used to measure offsets into the synthesizer's output buffer. This buffer is filled with wave samples, so sample time is relative to the sampling rate. For example, at a sampling rate of 22.1 kHz, each second of time is equivalent to 22,100 samples or 44,200 bytes (in the case of a 16-bit mono format).

In order to place its output into the correct position in the buffer, the synthesizer needs some way to convert between reference time and sample time. In user-mode implementations, this mechanism is provided by the IDirectMusicSynthSink::RefTimeToSample method. The reverse conversion is implemented in the IDirectMusicSynthSink::SampleToRefTime method.

Because the playback of the wave sample buffer is likely to be controlled by a different timing crystal than the master clock, reference time and sample time will tend to drift apart. It is the synth sink's responsibility to keep them in step by implementing a phase-locked loop. This clock synchronization is described in Clock Synchronization.


Latency

Another consideration in synthesizer timing is latency. A MIDI message cannot simply be submitted to the synthesizer and rendered into the output buffer at the current sample time. Allowance should be made for data that has already been placed in the buffer but has not yet been streamed to the wave output device. The difference between the current time and the first time that a note can play is called the latency.

The synth sink therefore should implement a latency clock, which is an IReferenceClock object (described in Platform SDK documentation). The latency clock's IReferenceClock::GetTime method retrieves the sample time up to which data has already been written to the buffer, and converts this to reference time relative to the master clock. The synth sink does conversions between reference and sample time with IDirectMusicSynthSink::SampleToRefTime and IDirectMusicSynthSink::RefTimeToSample, so in this case, the synth calls IDirectMusicSynthSink::RefTimeToSample to accomplish the conversion.

Latency time is all managed by the synth sink. Your implementation of the IDirectMusicSynthSink::GetLatencyClock method should output a pointer to the latency clock, and this pointer must in turn be retrieved by IDirectMusicSynth::GetLatencyClock. The application uses the latency clock to determine the earliest point in time at which a MIDI message can be cued to play when it is passed to the synthesizer by calling the IDirectMusicSynth::PlayBuffer method.

An example of the latency of a MIDI message is shown in the figure below.

Latency of a MIDI Message (Example)

In the figure above, the latency clock points to the first place in the PCM buffer loop where a note may be played. Note that the master clock is at 22 time units, which is the point where sound is playing from now, but the space between 22 and 30 time units has already been filled with wave data and can no longer be written to. Therefore, the first place where a time-stamped MIDI event could be played is at time 30. Thus, the latency clock reads 30 time units.

Messages can be scheduled to play anytime at or after this latency time. So messages that are to be rendered "immediately" are stamped with the latency time (not the current time), before being placed in the synthesizer's input buffer.


Time-stamped events

The big picture of the synthesizer timing is that instead of sending a note exactly when it needs to play, each note is time-stamped and placed in a buffer. This buffer is then processed and played within two milliseconds of the time that is specified by the time-stamp. (The timing resolution is in hundreds of nanoseconds, but we will talk in terms of milliseconds because these are more meaningful time units for this discussion.)

Since the latency is known to the system through the latency clock, time-stamped events can be waiting in a buffer to play at their proper time, rather than just dropping events into a cue and hoping the latency is low.

A master clock implements a COM IReferenceClock interface (defined by DirectShow). All of the devices on the system use this reference time.

Microsoft's synth sink implementation builds a thread that wakes up every 20 milliseconds. The thread's job is to create another buffer and hand it to DirectSound. To create that buffer, it calls into the synthesizer and asks it to render a specified amount of music data. The amount it asks for is determined by the actual time the thread wakes up, which is not exact.

What is actually passed into the synthesizer is not a buffer or wave object but a pointer to memory, which identifies the location in memory at which to start writing data into the PCM buffer, and a length parameter that specifies how much data to write. The synth can then write PCM data into this buffer and fill it in up to the specified amount. That is, it renders from the start address until it reaches the specified length. That block of memory can be a DirectSoundBuffer (which is the default case), but it could just as easily be a DirectShow graph or some other target defined by the synth sink.

The PCM buffer is conceptually cyclical; that is, it is constantly looping. The synthesizer renders the 16-bit numbers that describe the sound into successive slices of the buffer. The slice size will be slightly different every time the thread awakens because the sink can't wake up exactly every 20 milliseconds. So every time the thread does wake up, it plays catch up, in effect saying "where am I supposed to be now?"

From the application's perspective, the synth port driver itself has a IDirectMusicSynth::GetLatencyClock function that gets the clock from the synth sink. So there are two clocks: the master clock that everyone listens to, including the synth sink, and the latency clock that is implemented by the synth sink and is seen by the application as a port providing the latency clock. In other words, the application asks for the latency clock, but doesn't really know it is coming from the synth sink.

The time returned by this latency clock is the earliest time that the buffer can be rendered to because we have rendered up to that point in the buffer already. If the synth had rendered a smaller buffer on its last write, we would have a smaller latency.

So the synth sink calls IDirectMusicSynth::Render on the synth, presenting the buffer and requesting that it be filled with rendered data.

Queueing of Time-Stamped Messages

As shown in the figure above, the synth takes all the time-stamped events that come in as a result of PlayBuffer function calls. Each input buffer contains time-stamped messages. Each of these messages is put in a queue to be rendered into a buffer at the time specified by its time stamp.

One of the important things about this model is there is no particular order other than the timestamp. These events are streamed in, so they can be added into the queue at any time before rendering. Everything is event-based with regard to time. For example, if the reference time is currently at 400 time units, then everything stamped to happen at time 400 is happening now. Events stamped to happen ten units from now will happen at time 410.


Clock Synchronization

A critical thing for the synth sink to do is to resolve time drift between the reference- and sample-clock crystals. It does this with a phase-locked loop.

The synth sink keeps track of what sample number it is on; that is, what sample buffer can be written to next. So even though it knows that it is on, for example, sample 20, the synth sink still needs to check the master clock to get a reference time. It has a thread that wakes up approximately every 20 milliseconds and asks the master clock for the current time. The master clock might report back that the current time (in milliseconds) is 420, for example.

The synth sink also maintains a latency clock, which shows the offset between the current time according to the master clock and the sample time. It uses this information to calculate what it thinks the master clock should read and checks to see if there has been a drift.

The synth sink uses a phase-locked loop to adjust the sample time. It doesn't adjust the whole amount when it checks for drift; that is because the readings contain some jitter. Instead, it moves the sample clock by some fraction of the distance toward the master clock. In this way, the synth sink smooths out jitter errors while staying roughly in sync. It also takes this time and converts it to a latency clock time that is relative to the master clock. This is important because the application may want to know where the synthesizer is rendering at any point.

For example, if the master clock is currently at time 420 and the application has a note that it wants to play as soon as possible, the latency clock will tell it the earliest time that the note can be played. The application should not ask to play the note at time 420, for example, because the latency would make this request impossible to honor. If the software synthesizer has a latency of 100 milliseconds, the next time it can play a note is at time 520.

Suppose an event is marked to play at time 520 in reference time. The synthesizer does its work by rendering notes down into samples and performing all its calculations in sample time. Therefore, it needs to know what a reference time of 520 converts to in sample time. In user mode, the synth sink provides two functions that the synth uses: IDirectMusicSynthSink::SampleToRefTime and IDirectMusicSynthSink::RefTimeToSample. To do the conversion in this case, the synth calls IDirectMusicSynthSink::RefTimeToSample on the synth sink.

The synth sink then gives back a sample time—say 600, for example. The note in question gets rendered at sample time 600. Then, when the synth gets called by the synth sink to Render—say from sample time 600 to 800—the note is rendered into the buffer at sample time 600.

Note The sample time is kept as a 64-bit number to avoid rollover. (A DWORD value will roll over in 27 hours.)

To summarize, the synth does all its internal math in sample time and the synth sink does the conversion to sample time from reference time and vice versa. The synth sink also does all the work of managing synchronization with the master clock and all the work of providing latency information. This technique makes writing the synth much easier.


Custom DLS

If you are writing your own synthesizer, you also have to provide support for DLS so that the application can convert MIDI note messages to particular instrument sounds. Specifically, you should implement your IDirectMusicSynth::Download method so that it can download instrument wave and articulation data to the synthesizer. This method should accept raw data (typically from a collection file) and store it in a form that can be used by your rendering engine.


DLS Level 1 Download Support

When DirectMusic downloads DLS data to the driver, the format of the data buffer is defined in terms of several DirectMusic structures. The downloaded data begins with two structures—a header and an offset table:

  • DMUS_DOWNLOADINFO – A fixed-size header that describes the information that is being downloaded.
  • DMUS_OFFSETTABLE – Follows the header and describes the offsets of the various chunks of information within the downloaded data.

Following the offset table is the actual data, which can begin with either of the following structures:

  • DMUS_INSTRUMENT – Describes a DLS instrument.
  • DMUS_WAVEDATA – Contains the actual PCM data of a sample.

For more information on these data structures and the data formats that are used to download instrument and wave data, see the discussion of DirectMusic low-level DLS in the SDK Platform documentation.

The DLS data format is identical in kernel and user modes.

Later sections provide additional information about DLS downloads to the driver.


Registering Your Synthesizer

When you create a software synthesizer, you must provide a way to register it in the system, making it available as a port driver that can be enumerated.

To do so, you provide additional functionality in your implementation of the DllRegisterServer COM function. This function is typically called by the installation program to tell the DLL to register itself as a COM object. However, a synthesizer must take an extra step and add an entry in the list of available software synthesizers. To do so, it creates a key in the following path:

  HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DirectMusic\SoftwareSynths

This path is defined in dmusicc.h as REGSTR_PATH_SOFTWARESYNTHS.

The key is named with the class identifier of the synthesizer COM object. Within the key is a string field called "Description" with the name of the synthesizer.

The following example code shows a function, RegisterSynth, that can be called from DllRegisterServer:

const char cszSynthRegRoot[] = REGSTR_PATH_SOFTWARESYNTHS "\\";
const char cszDescriptionKey[] = "Description";
const int CLSID_STRING_SIZE = 39;
HRESULT CLSIDToStr(const CLSID &clsid, char *szStr, int cbStr);

HRESULT RegisterSynth(REFGUID guid,
                      const char szDescription[])
{
    HKEY hk;
    char szCLSID[CLSID_STRING_SIZE];
    char szRegKey[256];

    HRESULT hr = CLSIDToStr(guid, szCLSID, sizeof(szCLSID));
    if (!SUCCEEDED(hr))
    {
        return hr;
    }

    strcpy(szRegKey, cszSynthRegRoot);
    strcat(szRegKey, szCLSID);

    if (RegCreateKey(HKEY_LOCAL_MACHINE,
                     szRegKey,
                     &hk))
    {
        return E_FAIL;
    }

    hr = S_OK;
    if (RegSetValueEx(hk,
                  cszDescriptionKey,
                  0L,
                  REG_SZ,
                  (const unsigned char *)szDescription,
                  strlen(szDescription) + 1))
    {
        hr = E_FAIL;
    }

    RegCloseKey(hk);
    return hr;
}


Kernel Mode Hardware Acceleration DDI

This portion of the design guide contains information necessary to write kernel-mode drivers for DirectMusic®-enabled hardware or software synthesizers (synths). The features described here are optional and can be implemented in addition to the base-level WDM MIDI miniport driver, which supports the native MIDI APIs under Microsoft® Windows® 95/98/Me, Windows NT 4.0, Windows 2000, and later.

Implementing kernel-mode components entails making additions to the miniport DDI (device driver interface) that allow WDM MIDI drivers to support DirectMusic hardware acceleration. A good design strategy is to begin by implementing a user-mode version of your driver and then convert it to kernel mode once it is working properly (see User Mode Versus Kernel Mode).

If you have not written a user-mode version prior to doing your kernel-mode implementation, at least read the user-mode sections of this document to become familiar with the concepts, which apply to kernel mode as well. Kernel-mode discussions build on common concepts that are introduced in the user-mode examples.

The next two sections give a brief background of WDM kernel streaming and an overview of synthesizer miniport-driver implementations, respectively:

DirectMusic WDM Kernel Streaming Background

Synthesizer Miniport Overview


DirectMusic WDM Kernel Streaming Background

This section may be useful for driver writers who are new to DirectMusic® and WDM kernel streaming, or to anyone who wants a brief overview of kernel-mode architecture. Experienced WDM audio driver writers might want to skip ahead to the DirectMusic kernel-mode overview section. For a more general introduction to kernel streaming, see Kernel Streaming Overview.

Historically, there were two types of drivers for Windows: the Windows 95-style VxDs and the drivers for the NT-based operating systems. Windows 98/Me contains ntkern.vxd, which has all the NT kernel services and allows most NT drivers to run on Windows 98/Me. WDM drivers use the NT driver environment for cross-platform compatibility. They also implement power management and Plug and Play.

WDM kernel streaming architecture had its roots in ActiveMovie (which became DirectShow®), where the concept of filter chains was used for streaming media. Each filter in the chain could be a user-mode filter, a piece of user-mode code that proxied a kernel-mode filter, or even a piece of user-mode code that was marshaling a piece of hardware (see Kernel Mode Filters, DirectShow, and Proxying). This architecture was brought into the Windows® 2000 kernel to give birth to kernel streaming.

The "pin" terminology comes originally from DirectAnimation® and DirectShow. A pin is now a kernel-streaming term for a target that can be used to connect one filter with another. For example, when there are two filters—the first with an "out" pin and the second with an "in" pin—the pins can be connected so that the first filter can pass information to the second filter. (See the example in Audio Filter Graphs.)

Kernel streaming is now part of WDM and is used by WDM Audio. DirectMusic® uses WDM Audio as a kernel-mode component, passing its information down into kernel-mode in the form of IRPs (I/O request packets). All the DirectMusic interfaces are strictly WDM.

WDM kernel streaming audio filter chains are usually system-provided, but can also be provided by ISVs and IHVs. The SysAudio system driver is a component that manages the filter chains. It locates the filters and hooks them together to construct a filter graph. (SysAudio is not itself a member of the graph.)

Fortunately, it is not necessary to be a kernel-streaming expert to implement your miniport driver. It is also not necessary to write your own port driver to do a custom audio filter because you can just use the built-in port driver. Custom implementations simply need to implement a miniport driver to convert samples to wave and render the specified amount of wave output to the destination that is requested by the synth sink.

Microsoft wrote a large set of common code that vendors can leverage to make writing filters for DirectMusic much easier. Now vendors can just build a mini-filter and reference all of the common code, which makes custom filters much easier to build. This is similar to the class driver/minidriver model that other Windows driver architectures use (for a comparison, see Audio Miniports Overview).

WDM Audio has a component called PortCls (see Port Class Adapter Driver and PortCls System Driver), which is the class driver for several types of audio filters. These audio filters handle PCI wave devices, cyclical DMA wave devices, and MIDI devices. Instead of referring to the driver components as filters and mini-filters or as drivers and minidrivers, we refer to them as port and miniport drivers. PortCls contains a MIDI port, for example.

For each port driver, there can be different kinds of miniport drivers that do device-specific operations. For example, in Windows 98, there is one MIDI port driver and different miniport drivers are connected to it, such as the MPU-401 device and FM synthesis device. The port driver just sequences data, regardless of whether it is going to FM or MPU. The miniport driver handles the specifics of actually playing the MIDI data.

Because the sequencer is in the port driver itself, it holds the time-stamped data until it is due, then plays it through the appropriate miniport driver. For example, the MPU-401 miniport driver sends wave out to the device via the external synth module. The miniport driver's output is managed by the port driver's synth sink.

The miniport driver stores up MIDI notes and when the synth sink (which is part of the port driver) asks for the next block of audio data, the miniport driver renders the requested amount of wave data into the specified memory location. More information on this process is provided in the Synthesizer Miniport Driver Definition section.

Microsoft provides standard miniport driver functionality for all MPUs. Because the MPU specification defines exactly what the hardware should do and how it responds, Microsoft provides a miniport driver to handle MPUs as part of PortCls. All sound cards that have MPUs can use this same miniport driver.

The built-in miniport drivers in PortCls only attach to the MIDI port, so DirectMusic introduced PortDMus. PortDMus is the DirectMusic kernel-mode port driver that handles sequencing and other functions for DirectMusic and represents MIDI, wave, and DLS (downloadable sounds). The example MPU driver (adapter.cpp) now references PortDMus and the DirectMusic miniport driver.

If all you need is MPU functionality, you can use the built-in MSMPU401.sys miniport driver, which ships with the DDK. Just connect it to the port, set an IRQ, and you have a custom MPU for a very small amount of new code. Previously, this driver referenced the built-in interfaces that were identified by the IID_IPortMidi and IID_IMiniportDriverUart (which represents the MPU-401 miniport driver that is built into PortCls) class GUIDs (see PcNewPort and PcNewMiniport). Now MSMPU401.sys references the CLSID_IPortDMus and CLSID_MiniportDriverDMusUART GUIDs so that it can support DirectMusic.

When PortDMus receives MIDI data, it routes the data to the sequencer where each note is sorted on the basis of its timestamp. When the note is due, it is passed down to the miniport driver. The miniport driver implementation can specify how far in advance it wants to pre-fetch these notes.

When DLS data is passed into PortDMus, it is routed directly to the miniport driver. Since these are just sounds that can be played, there is no need to involve the sequencer or synth sink when they are downloaded.


Synthesizer Miniport Overview

Both a synth and a sink are necessary for DirectMusic support. Default implementations of each are provided with DirectMusic. The user-mode Microsoft Software Synthesizer is provided as the default synth and DirectSound® is the default synth sink. These provide full hardware emulation, but further performance enhancements can typically be achieved with kernel-mode software or hardware implementations.

If you are implementing support for hardware, the only choice is to write a kernel-mode driver. In kernel mode, the synth sink is provided by the PortDMus port in PortCls and should not need to be replaced for custom implementations (as is sometimes done in user mode).

For kernel-mode DirectMusic drivers, the most important header file is dmusicks.h. It contains the main kernel-mode interfaces you need to implement your miniport driver. These interfaces are:

IMiniportDMus

ISynthSinkDMus

IMXF

IAllocatorMXF

IMasterClock

IPortDMus

The last three of these interfaces are implemented in PortCls.sys.

Two other header files that will be of interest are DMusProp.h, which contains DirectMusic property items, and DMusBuff.h, which contains the main IRP structure, DMUS_EVENTHEADER.

The following diagram shows the relationship between the IHV adapter driver and the rest of the DirectMusic system.

Relationship of Adapter Driver to DirectMusic System

At the topmost level, the driver is exposed via a DirectMusic port driver (an IDirectMusicPort interface instance). This is how an application talks to DirectMusic. This port driver communicates downward to a pin instance via standard kernel streaming calls through the DeviceIoControl function (described in Platform SDK documentation).

Each miniport driver object is connected to a matching port driver object. The port driver object provides basic services to the miniport driver. Each pin instance (which maps to one open instance of the device) has services for format conversion, sequencing, and so on. Pins can be targets or sources, and can support multiple data formats and ranges. Each pin instance specifies target or source, and exactly which data format and range is supported.

The miniport driver object is created by the IHV's adapter driver. While there is one pin instance, sequencer, and so on, per open instance of the driver, there is only one port-miniport driver pair per piece of hardware (or loaded kernel software synthesizer). Communication with the miniport driver is through a stream of events that is passed down to the miniport driver and by property items that are supported by the miniport driver.

The next section explains the details of a DirectMusic miniport driver implementation.


Synthesizer Miniport Driver Definition

DirectMusic synthesizer miniport drivers are based on the WDM MIDI miniport driver with extensions to support DLS downloads greater than 16 channels per instance, and have the potential to sequence note events in hardware. The synthesizer-miniport driver interface differs from the MIDI-miniport driver interface in the following ways:

A synthesizer-miniport driver implements the interface IMiniportDMus as opposed to IMiniportMidi. This interface is similar to IMiniportMidi, but the NewStream method creates an IMXF and connects to IAllocatorMXF in PortDMus, as opposed to implementing an IMiniportMidiStream. IAllocatorMXF and IMXF wrap the standard GetMessage and PutMessage calls (see IAllocatorMXF::GetMessage and IMXF::PutMessage). These calls deal with packaged events rather than with raw MIDI bytes.

A DirectMusic synthesizer miniport driver can implement some or all of the DirectMusic properties. These properties allow the system to manage DLS downloads and channel allocations for the device. The DMusProp.h header file defines DirectMusic-specific property items. See Audio Drivers Property Sets for more information about these properties.

DirectMusic synthesizer miniport drivers are expected to allow the creation of multiple pin instances. Each pin instance acts as one virtual synthesizer and contains a set of channels and DLS downloads independent of the other pin instances.

Some of the properties described in the Audio Drivers Property Sets reference section act on a pin instance, and others are global. To process the global properties, the synthesizer must have a synthesizer node in its topology. The description of each property item indicates whether that item will be sent to the synthesizer node or to a pin instance.

Port and Miniport Drivers for a DirectMusic Synthesizer

For each piece of hardware supporting synthesis, there exists a port driver object and a miniport driver object, as shown above. The port driver object exposes one instance of an IPortSynthesizer interface, which is held by the miniport driver object. The miniport driver exports one instance of an IMiniportDMus interface, which is held by the port driver. For every instantiated pin, the port driver will request a matching IMXF interface. Communication between the system and this instance is the combination of property requests addressed to the pin and events flowing to or from the IMXF stream interface.

Two objects must be passed to the miniport driver when it is created: the clock and the allocator object. The clock is very important for render and capture operations. The miniport driver needs to render notes at their specified times; when the miniport driver reads in MIDI data, it needs to know the time so it can timestamp the kernel event. See Latency Clocks for more information on this topic.

The allocator object is used as a memory pool to recycle memory. All MIDI messages in the system are allocated from this common pool. The allocator object should be used to create or destroy the individual messages.


MIDI Transport

PortDMus is involved on the front and back sides of the miniport driver's synthesizer work. MIDI data comes into PortDMus and is routed to the sequencer. The MIDI messages are sequenced according to their timestamps and are passed to the miniport driver when their timestamps are due. (DLS data passes right through PortDMus to the miniport driver with no pre-processing.)

When miniport driver input gets converted to wave data, its output is managed by the synth sink (also called a "render sink" or "wave sink") in PortDMus.

PortDMus is a kernel-streaming filter. An input pin accepts DirectMusic data from dmusic.dll. PortDMus also has a wave-output pin, which is utilized by the synth sink. The miniport driver is unaware of this pin because it only needs to write data where the synth sink tells it to. This insulates the driver writer from having to know much about the details of kernel streaming. You can just write your miniport driver so that it renders wave data to the requested destination and PortDMus takes care of sending it out to the system. SysAudio's graph filter connects the filters to make everything flow correctly.

Flow of MIDI and DLS Data Through PortDMus Driver

As shown in the diagram above, MIDI data comes into the port driver (PortDMus) and, after sequencing, is passed to the miniport driver. The miniport driver converts the MIDI data to wave format, which is rendered into a buffer that is designated by another part of the PortDMus, the synth sink. Then, instead of going out to DirectSound as it does in user mode, the wave output goes to the audio hardware through the KMixer system driver. DirectSound is really just an API that exposes KMixer, and DirectSound acceleration consists of the mixer functions being accelerated in hardware instead of emulated in software by KMixer.

The SysAudio system driver, which builds the audio filter graph, connects PortDMus to a piece of hardware. The synth sink portion of the PortDMus hands the data out through its wave-out pin, which SysAudio can connect to the hardware device. It pulls wave data from the miniport driver (without regard to whether it is a hardware or software synth), and handles all timing issues. Comparing to user mode, the miniport driver is analogous to the synth, whereas the synth sink is just part of PortDMus.

If a miniport driver can provide its output back to the host, it exposes a wave pin with KSPIN_DATAFLOW_OUT (see KSPIN), and SysAudio does the right thing by connecting it to KMixer.


IMXF interfaces

All MIDI transport in the DirectMusic port and miniport driver is carried out using the same interface: IMXF.

IMXF is the COM interface for a DirectMusic MIDI transform filter. Both the miniport driver and the sequencer and other entities in the port driver that handle MIDI data use IMXF as their common COM interface. Once the miniport driver implements this interface, it can participate in MIDI transport. IPortDMus, which resides in PortCls, manages IMXF. The interface from the capture to capture sink is also an IMXF interface.

MIDI data is transported between user mode and kernel mode in buffers of packed time-stamped data. The kernel port driver breaks these buffers into individual events (see DMUS_KERNEL_EVENT in the structure reference section). The high-resolution MIDI sequencer passes these events to the miniport driver when the trigger time occurs.

On the input side, the kernel port driver extracts individual input messages from the miniport driver and builds packed buffers to pass up to user mode. Accordingly, the data transport model for DirectMusic miniport drivers consists of IMXF::PutMessage and IAllocatorMXF::GetMessage. More detail on both these interfaces is presented in the next section as we discuss the allocator.


Allocator

The interfaces to and from the allocator are IMXF and IAllocatorMXF. These interfaces allow you to re-use DMUS_KERNEL_EVENT structures without allocating and deallocating memory. IMXF::PutMessage gives a structure to the allocator and IAllocatorMXF::GetMessage retrieves a freshly zeroed DMUS_KERNEL_EVENT structure from the allocator for reuse. (The allocator gets created with empty DMUS_KERNEL_EVENT structures in the pool so it will never be empty.)

Flow of IRPs Through Port and Miniport Drivers

As shown in the figure above, IRPs (in the form of DMUS_EVENTHEADER structures) come in from dmusic.dll to the Unpacker. The Unpacker calls IAllocatorMXF::GetMessage to retrieve an empty DMUS_KERNEL_EVENT structure. The Unpacker breaks apart the IRP, fills in the DMUS_KERNEL_EVENT structures (one per MIDI event), and passes them down to the Sequencer (using its MXF interface). The Sequencer reorders them based on their timestamps and, when they are due, passes them to the miniport driver by calling IMXF::PutMessage. The miniport driver pulls the MIDI data out of the DMUS_KERNEL_EVENT structures so that it can render it into wave data. It passes the used DMUS_KERNEL_EVENT structures back to the Allocator with another IMXF::PutMessage call.

The reverse situation happens for capture. MIDI data comes in from the hardware to the miniport driver and the miniport driver calls IAllocatorMXF::GetMessage to get an empty DMUS_KERNEL_EVENT structure. DMUS_KERNEL_EVENT structures are filled with timestamps and data and passed to the Capture Sink via IMXF::PutMessage. The miniport driver can pass more than one message per structure if it sets the DMUS_KEF_EVENT_INCOMPLETE flag in the DMUS_KERNEL_EVENT structure. The Capture Sink in PortDMus will correctly parse this raw data stream and emit DMUS_KERNEL_EVENT structures that contain "cooked" MIDI messages (one per structure).

It is also possible for the miniport driver itself to emit "cooked" messages to the Capture Sink. In this case, the DMUS_KEF_EVENT_INCOMPLETE bit is not set in DMUS_KERNEL_EVENT. The Capture Sink can just pass the cooked structures straight on to the Packer, which will package the messages up into IRPs and send them on to dmusic.dll. DirectMusic capture is only for recording MIDI. For wave, you would use DirectSound capture.

Once the Packer pulls the data out of a DMUS_KERNEL_EVENT structure, it discards the used DMUS_KERNEL_EVENT structure into the Allocator with IMXF::PutMessage. When the IRP buffer is full, it is passed up to dmusic.dll. The Packer receives empty IRPs from dmusic.dll, fills them up, and completes them. More IRPs keep trickling down so that it always has one to fill.


Latency Clocks

The synthesizer miniport driver model is designed to allow synchronization of audio output between multiple devices. As such, it contains a more complex timing model than that provided by a pure UART device.

Events are delivered to (and captured from) the miniport driver with an associated timestamp. This timestamp is relative to a master clock. The master clock is the same clock used by all sequencing in the entire system. Master-clock time is measured in units of 100-nanosecond ticks.

The master clock is provided to the miniport driver by PortCls as a kernel-mode IMasterClock interface. A pointer to the IMasterClock interface is given at pin creation time when IMiniportDMus::NewStream is called in the miniport driver. Currently the master clock wraps the system real-time clock. The master clock will never be changed when there are pins that require it in the run state. It is a constant-rate clock that never pauses.

All rendering devices have some amount of latency between the time they accept an event and the time the event can actually be heard. This latency can be constant or variable (as in the case of a software synthesizer, where the latency depends on the current playback position of the audio buffer). This latency is compensated for in two ways:

  1. Allow the miniport driver to receive events far enough in advance so that they can be played on time, despite the latency of the device. Events are sequenced for the miniport driver by a sequencer engine in the synthesizer port (PortDMus).

    At pin-creation time, PortDMus will query the miniport driver for a delta time in 100-nanosecond units. This delta time is how far ahead of each event's presentation time the miniport driver wants to receive the event. The port driver will make its best effort to deliver events this far ahead. Specifying a very large value for this delta (specified by SchedulePreFetch parameter of IMiniportDMus::NewStream) will make the port driver pass the events to the miniport driver as soon as they are delivered to the port driver from user mode.

  2. Inform applications how far ahead to schedule events. Using the maximum latency is not desirable in this case. Since events cannot be cancelled once they are submitted, the closer events can be submitted to their presentation time, the more responsively the application and synth can interact. To handle this requirement, DirectMusic has introduced the concept of a latency clock.

    The latency clock provides the nearest time in the future that an event can be scheduled to play and still play on time. In other words, if the application schedules an event to be played before the current time according to the latency clock, then the event will be played late. Synthesizer miniport drivers provide a latency clock by responding to the KSPROPERTY_SYNTH_LATENCYCLOCK property item.

    The miniport driver will be queried for KSPROPSETID_Synth and KSPROPERTY_SYNTH_LATENCYCLOCK. The miniport driver's property handler should return a latency clock that specifies, in terms of the master clock, the next time that data can be rendered on time. For example, if the master clock currently reads 50, and there are currently 25 units of latency, then the latency clock will read 75. The reason the clock is implemented in this way is that the latency does not need to be constant, and the returned value is of more use to applications than just the delta.


Miniport Driver Property Item Requests

This section is a brief introduction to DirectMusic property item requests. A complete overview of this and other kernel-streaming concepts can be found in the Kernel Streaming Overview.

DirectMusic miniport drivers need to handle the audio drivers property sets. A property request comes in two pieces. The first is the property set that is defined by the KSPROPERTY structure. The second piece is a data buffer that contains instance data that is specific to the property item.

The KSPROPERTY structure contains the following:

  • A pre-defined GUID specifying the set (such as KSPROPSETID_Synth_Dls)
  • An item ID specifying the property item within the set (such as KSPROPERTY_SYNTH_DLS_DOWNLOAD)
  • Flags specifying the requested operation

The Flags member of KSPROPERTY may contain exactly one of the following flags to specify the operation requested of the miniport driver:

KSPROPERTY_TYPE_GET
To retrieve the given property item's value.
KSPROPERTY_TYPE_SET
To set the given property item's value.
KSPROPERTY_TYPE_BASICSUPPORT
To determine the type of support available for the property set. The data returned in *pvPropertyData will be a DWORD containing one or both of KSPROPERTY_TYPE_GET and KSPROPERTY_TYPE_SET, indicating which operations are possible.

The second part of the property item request is the instance data, which is a buffer that can be used to pass data to or from the miniport driver. How this buffer is used is dependent on whether the request is a SET or a GET:

  • If the request is a KSPROPERTY_TYPE_SET, the instance data is sent to the miniport driver but is not returned to the requestor.
  • If the request is a KSPROPERTY_TYPE_GET, the instance data is filled out in the miniport driver and returned to the requestor.

A property item request can be directed to a particular node in the miniport driver topology. The miniport driver topology describes the layout of the driver and the underlying hardware. Within the topology can be nodes where property items can be sent, whether or not there are pin instances available at the time of the request.

A pin instance must be created for DirectMusic playback. DirectMusic data is sent to the node of its type, KSNODETYPE_DMSYNTH. The following is an example of a miniport driver connection:

Connect stream in to synth: PCFILTER_NODE pin 0 (out) -> node 0 pin 1 (in)

Connect synth to audio out: node 0 pin 0 (out) -> PCFILTER_NODE pin 1 (in)

The supported data formats are a data range that specifies what format a pin can receive data in.

The DirectMusic format (STATIC_KSDATAFORMAT_SUBTYPE_DIRECTMUSIC) must be defined in the miniport driver's topology so that DirectMusic can send its data to the miniport driver. This format is defined by the DMUS_EVENTHEADER structure (see Platform SDK documentation) in dmusbuff.h. When the miniport driver specifies that it supports this particular data range, DirectMusic can expose that data range to the user (through a pin on the port itself).


Making PortDMus the Default DirectMusic Port Driver

To make PortDMus the default for all DirectMusic applications, generate a GUID (using uuidgen.exe or guidgen.exe) to uniquely identify your synth and fill it into the Guid member in your KSPROPERTY_SYNTH_CAPS property handler. Then set the following entry in your INF:

Key:    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DirectMusic\Defaults
String Value:    DefaultOutputPort


Exposing Your Device as a Legacy Device

You may want to write a single device driver that exposes your hardware as both a DirectMusic device and a legacy MIDI device. There are three cases where this might be useful:

  1. If the device doesn't support DLS. Examples include the MPU-401 driver (see the MSMPU-401 sample in the DDK), a device that has only a ROM set, and a fixed-function software synth (FM, for example).

    In this case, the device can expose a legacy interface as well as a DirectMusic interface. It should expose only one legacy pin. It is important to list the pin with the legacy interface first so that WDM Audio will enumerate it as an MME device.

  2. If the device does support DLS, but powers up in a loaded state (i.e. DLS RAM + GM/GS/XG in ROM).

    In this case, the device can also expose both interfaces. If the two interfaces are mutually exclusive (that is, if once you download something, the ROM isn't visible), then it should be a single pin with two interfaces to choose from (as opposed to two pins).

  3. When the device does support DLS, but powers up "empty" (in other words, the DirectMusic software synth) and thus needs DLS "babysitting".

    This "babysitting" is unnecessary if the device does not require DLS downloads (if it has a default sample set in ROM, for example), or if a DirectMusic pin is opened (the DirectMusic APIs will ensure that DLS downloads occur).

    If you wish to expose your DLS device via the legacy APIs, there is a small bit of extra work to be done. When a legacy pin is opened on a device that requires DLS instruments, the driver should locate and open a file containing the DLS collection to be used. The driver should then intercept patch and bank changes, retrieve the appropriate data from the DLS file, and call the driver with the proper DLS downloads from the file.

    This case is problematic because WDM Audio and other clients will not be aware that they need to download a collection. They will just start sending MIDI patch changes and notes.


Voice Allocation

Most adapter drivers that contain a synthesizer miniport driver will also contain DirectSound hardware acceleration. This brings up the question of voice allocation between synthesizer voices and hardware-accelerated DirectSound buffers.

DirectMusic synths—both hardware and software—should support multiple instances in order to maximize the number of concurrent clients. A synth writer might be tempted to statically allocate voices to synths, but it is strongly preferable to consider all available synths instances as drawing from a common, dynamic voice pool. Each instance then reports the available number of voices as the total number available in the pool.

When implemented this way, even a hardware synth with a limited number of physical voices can support numerous synth instances. In real time, the STATS call will inform the client how many voices each instance is currently using. If the dynamic pool is depleted and a synth instance requires a new voice, then that synth instance must implement a voice-stealing scheme to free a voice from within that instance.

The following allocation scheme is based on the idea that voices used by a synthesizer are more easily shared than DirectSound buffers because the driver has control over what data goes in what voice and can make decisions about voice stealing (outlined in the DLS level-1 specification).

All of the voices available to the miniport driver (hardware, software, or some combination of hardware and software) are divided into two pools. The first pool, the free pool, consists of voices that are not committed anywhere. The second pool, the dynamic pool, consists of voices that are committed to use by synthesizer instances. These voices may or may not currently be in use by a synthesizer instance. The dynamic pool is sized as the maximum number of voices requested by any synthesizer instance, subject to the current contents of the free pool. DirectSound buffers are removed from the free pool upon allocation and returned on deallocation. Here is a sample set of allocations that illustrate the scheme in practice:

Time | Request | Free Pool | Dynamic Pool | Miniport driver Action
0 | Power Up | 64 | 0 | Initialize.
1 | DSound(4) | 60 | 0 | Statically allocate four voices to DirectSound buffers.
2 | Synth(32) | 28 | 32 | Increase dynamic pool to 32 voices.
3 | Synth(24) | 28 | 32 | No action. There are already more than 24 voices in the dynamic pool.
4 | DSound(24) | 4 | 32 | Statically allocate 24 voices to DirectSound buffers.
5 | Synth(48) | 0 | 36 | Increase dynamic pool to 36 voices. (The method that creates the port will return S_FALSE and DMUS_PORTPARAMS.dwVoices = 36)
6 | DSound(10) | 0 | 36 | Fail. No voices in free pool.
7 | DSound(-5) | 5 | 36 | Note that these do not go back into the dynamic pool, even though the last request was for more than were granted.

Note that DirectSound buffers are actually allocated one by one, and are grouped together in the table for the purpose of readability.

Immediately after a synthesizer pin instance is created, no voices should be allocated based on it. Shortly after creation, a KSPROPERTY_SYNTH_PORTPARAMETERS property item will be received. This property item indicates, among other things, the number of voices that are to be associated with this instance. This item also gives the miniport driver the chance to report back the actual new size of the dynamic pool in case all requested voices could not be allocated.


Default Sound Sample Sets

Some synthesizers ship with a default sound set that conforms to General MIDI or some extension thereof. This sound set is provided for applications that do not support sample downloading or desire a default sound set to use in conjunction with downloaded samples. There are two possible delivery mechanisms for such a sound set: as a prepackaged DLS set, or as a ROM set.

In the case of the prepackaged DLS set, management of the set is delegated to DirectMusic. Microsoft provides a default DLS set based on the Roland GS samples. Manufacturers wishing to use a different default set with their hardware should contact the DirectMusic group at Microsoft. Sample sets provided in this manner should not set the capabilities bits indicating hardware support for a sample set; only ROM sets should set these bits.

ROM sets are also managed by the system. In order to preserve maximum sample memory for use by downloadable samples, the miniport driver should not load the entire ROM set into sample RAM. (This is not an issue for hardware which can play samples directly out of ROM). The system will provide instrument download requests for needed patches before the patch change itself is delivered. If an instrument download refers to a patch in the ROM sample set, then the dwDLId member of the DMUS_DOWNLOADINFO structure (see description in Platform SDK documentation) will contain the tag DOWNLOAD_ID_ROMSET (defined as 0xFFFFFFFF).


DirectMusic Support Items

A DirectMusic-synthesis miniport driver specifies its hardware capabilities in the form of an array of property items. Each property item is a PCPROPERTY_ITEM structure that contains the following:

  • A property-set GUID that defines a particular hardware feature that is defined by DirectMusic
  • A pointer to a property-handler method that is implemented within the driver
  • A set of flags that specify whether the handler can get the property, set the property, and indicate basic support for the property

Property Set GUIDs

The following property-set GUIDs are defined by DirectMusic:

GUID_DMUS_PROP_DLS1

GUID_DMUS_PROP_DLS2

GUID_DMUS_PROP_Effects

GUID_DMUS_PROP_GM_Hardware

GUID_DMUS_PROP_GS_Capable

GUID_DMUS_PROP_GS_Hardware

GUID_DMUS_PROP_INSTRUMENT2

GUID_DMUS_PROP_LegacyCaps

GUID_DMUS_PROP_MemorySize

GUID_DMUS_PROP_SampleMemorySize

GUID_DMUS_PROP_SamplePlaybackRate

GUID_DMUS_PROP_SetSynthSink

GUID_DMUS_PROP_SynthSink_DSOUND

GUID_DMUS_PROP_SynthSink_WAVE

GUID_DMUS_PROP_Volume

GUID_DMUS_PROP_WavesReverb

GUID_DMUS_PROP_WriteLatency

GUID_DMUS_PROP_WritePeriod

GUID_DMUS_PROP_XG_Capable

GUID_DMUS_PROP_XG_Hardware

For definitions of the property-set GUIDs above, see the description of the KSPROPERTY structure in the DirectX 8.0 Programmer's Reference in the Platform SDK. The property set for each of the above GUIDs consists of a single element that is identified by an index of zero.

IKsControl Interface

The IKsControl interface is used to get, set, or query for basic support of properties, events, and methods. This interface is part of the WDM KS (kernel streaming) architecture, but is also used by DirectMusic to expose properties of DirectMusic ports. To retrieve this interface, call the IDirectMusicPort::QueryInterface method (described in Platform SDK documentation) with the riid parameter set to IID_IKsControl.

The IKsControl interface has three methods: KsProperty, KsEvent, and KsMethod. At present, only KsProperty is supported by DirectMusic.

The IKsControl::KsProperty method gets or sets the value of a property. The manner in which a property-item request is routed to a particular port depends on how the port is implemented:

  • No properties are supported by ports that represent DirectMusic emulation on top of the Win32 handle-based multimedia calls (the midiOut and midiIn APIs). Use the GUID_DMUS_PROP_LegacyCaps property-set GUID to query a port for whether it is implemented with Win32 multimedia calls.
  • Property-item requests to a port that represents a pluggable software synthesizer are answered totally in user mode. The topology of this type of port is a synthesizer (represented by an IDirectMusicSynth interface) that is connected to a sink node (an IDirectMusicSynthSink interface). The property request will be given first to the synthesizer node, and then to the sink node if it is not recognized by the synthesizer.


Video Capture Minidriver Design Guide

This section describes how to create video capture minidrivers, which are clients of the stream class driver (Kernel Streaming 1.0, not the newer AVStream class, or Kernel Streaming 2.0) for the Microsoft® Windows® 98 and later and the Microsoft® Windows® 2000 and later operating systems using the Windows Driver Model (WDM) architecture.

This section assumes familiarity with concepts discussed in Kernel Streaming Overview and information contained in Stream Minidriver Design Guide.

This section includes:

  • Introduction to Video Capture
  • Streaming Data from a Video Capture Minidriver
  • Medium GUIDs
  • Using Video Capture Property Sets
  • Flow of Control for Video Capture
  • Time Stamps
  • Video Stream Formats
  • Video Stream Extended Headers
  • Video Stream Categories and Mediums
  • Video Stream Categories

For more information on WDM video capture driver development see www.microsoft.com/hwdev/vidcap.


Introduction to Video Capture

Video capture minidrivers work in combination with the stream class driver to control hardware devices that produce streams of video images and related data. Video capture minidrivers provide the following functionality:

  • Capture of compressed and uncompressed video streams from digital and analog video sources such as S-Video and RCA video-in jacks
  • Control of devices associated with video streams such as TV tuners, video routing devices, TV audio control, and video compressors
  • Control of camera properties such as zoom, pan, and focus
  • Control of video qualities such as hue, saturation, brightness and sharpness
  • Control of video ports and capture from video port streams
  • Capture of vertical blanking interval (VBI) data
  • Capture of timecode
  • Capture of ancillary data streams
  • WDM streaming (for kernel-mode) and DirectShow™ (for user-mode) compatibility


Relationship to Video for Windows Capture Drivers

The design of Video for Windows (VfW) video capture was optimized for capturing movies to disk. Features important to video conferencing, TV viewing, capture of video fields, and ancillary data streams are missing from the VfW architecture. To circumvent these limitations, vendors have augmented VfW by implementing proprietary extensions. However, without standardized interfaces, applications that use these features must include hardware-dependent code.

With the integration of DVD, MPEG decoders, video decoders and tuners, video port extensions (VPE), and audio codecs on single adapters, a unified driver model that supports all these devices and handles resource contention simplifies development efforts.

The stream class provides a framework for resolving these issues. It supports a uniform streaming model for standard and custom data types. Similarly, property sets for most standard devices are defined and can easily be extended if needed. Because the stream class follows WDM streaming conventions, it supports data transfer between kernel drivers without requiring a transition to user mode. Thus there is no decrease in system performance associated with thread context switches between user-mode and kernel-mode.

Due to the large installed base of VfW applications, it is anticipated that VfW drivers will continue to flourish for devices that are primarily used for capturing movies. Capture devices that are used primarily for TV viewing and video conferencing are expected to migrate more quickly from the VfW model to the WDM streaming model.

To bridge the VfW and WDM worlds, a mapper is provided as part of the operating system. This component, called the VfW-to-WDM mapper, makes WDM drivers appear as VfW drivers for legacy applications.


DirectShow Filters Used with the Stream Class Video Capture Drivers

DirectShow (formerly called Microsoft® ActiveMovie®) is the common client for WDM video capture drivers. DirectShow filters are responsible for exposing the technology contained in the video capture minidriver to user mode applications.

There are four system-provided DirectShow filters that work with stream class drivers to expose the underlying video capture driver functionality. Information about each of these filters is described in the following table.

DLL | Functionality | Purpose | DirectShow Interfaces exposed
KSProxy.ax | Video Capture | Provides output streams of digital video data and ancillary data streams. | IAMAnalogVideoDecoder IAMCameraControl IAMVideoProcAmp IAMDroppedFrames IAMStreamConfig IAMVideoControl IAMVideoCompression IAMBufferNegotiation
KSTVTune.ax | TVTuning | Provides tuning control of analog TV, digital TV, FM and AM tuners. | IAMTVTuner
KSXBar.ax | Crossbar | Provides routing of video and audio streams. | IAMCrossbar
KSXBar.ax | TVAudio | Provides control of TV audio such as SAP selection. | IAMTVAudio

Each of these functions (Video Capture, TVTuning, Crossbar, and TVAudio) appears in a DirectShow filter graph as a separate filter exposing unique interfaces.

For more information about the DirectShow interfaces listed above, refer to the DirectShow SDK. The DirectShow SDK documentation also includes a sample application (AMCAP) that demonstrates how to construct the full range of both WDM and VFW capture graphs.


DirectShow Filter to Minidriver Communication

DirectShow filters interact with video capture drivers using DeviceIoCtl function calls that are translated by the stream class into stream request blocks (SRB) and are then forwarded to the video capture minidrivers for processing. There are two categories of SRBs: those that are used to control the device generally, and those that affect an individual stream. The major SRBs for each category are shown in the following table.

Function | Device | Stream
Property Write | SRB_SET_DEVICE_PROPERTY | SRB_SET_STREAM_PROPERTY
Property Read | SRB_GET_DEVICE_PROPERTY | SRB_GET_STREAM_PROPERTY
Stream Write | None | SRB_WRITE_DATA
Stream Read | None | SRB_READ_DATA
Open Stream | SRB_OPEN_STREAM | None
Close Stream | SRB_CLOSE_STREAM | None
Create Format | SRB_GET_DATA_INTERSECTION | None
Change Stream State | None | SRB_SET_STREAM_STATE

Of the filters that comprise the "front end" of a capture graph, only the capture filter truly participates in Kernel Streaming. All other filters (TVTuner, TVAudio, Crossbar) are used to control device-level property sets in the video capture minidriver itself. Thus, drivers that support TVTuning, TVAudio, and Crossbars do not expose kernel pins for each of their streams. These streams only exist as user-mode constructs for the purpose of creating the graph topology.


DirectShow Filter Graph Configurations

The flexibility of DirectShow makes possible numerous filter graph configurations that mirror the capabilities of the underlying hardware. The following sections illustrate a number of possible configurations:

USB or 1394 Conferencing Camera

USB Camera with a Still Pin

PCI TVTuner Capture Device with Multiple Streams

Video Port Capture Device


USB or 1394 Conferencing Camera

The simplest graph consists of a capture filter that exposes a single video stream with no TVTuning capabilities. This type of graph is used by USB and 1394 conferencing cameras.

Microsoft provides a minidriver library for USB cameras (USBCAMD). For information about USBCAMD, see USB Camera Minidriver Library Design Guide and USB Camera Minidriver Library.

USB/1394 Video Conferencing Filter Graph

Note that the single capture stream from the camera is replicated by a user-mode DirectShow filter (Smart Tee Filter) to provide separate capture and preview streams. This replication is performed without requiring a data copy.


USB Camera with a Still Pin

A slightly more complex graph is created for a conferencing camera that exposes a "still" pin. This still pin may provide a higher resolution image when the user pushes a button on the camera.

Microsoft provides a minidriver library for USB cameras (USBCAMD). For information about USBCAMD, see USB Camera Minidriver Library Design Guide and USB Camera Minidriver Library.

USB Video Camera Filter Graph

Here, the still pin streams only a single image when the user pushes the button on the camera. Alternatively, the still pin can be triggered by programmatic control.

The Windows Image Acquisition (WIA) technology built upon the Still Image Architecture (STI) complements the functionality provided by USBCAMD. See Windows Image Acquisition Drivers and Still Image Drivers for more information.

The WIA Video Snapshot filter is an addition to WIA that shipped with Windows XP and later operating systems. It is a filter driver that enables still frames to be captured from the video stream.

There are two methods of capturing a still from the device. The first is to insert the WIA Video Snapshot filter downstream from the capture filter and trigger a capture programmatically. The second is to enable still pin support using the USBCAMD model. The WIA Video Snapshot filter may then be triggered by pushing a button on the device.

The advantage of capturing an image from the still pin as opposed to the video stream is that the still pin may provide a higher resolution image (in addition to permitting the user to capture an image by pressing a button on the device).

driver writers can add still pin support to their drivers if they want to enable user to trigger captures via a hardware button on device and/or the device can capture higher resolution still. If support isn't explicitly added, the WIA Video Snapshot filter can be software triggered, but the resolution will be the same resolution as the stream.

Some still pin implementations can only be rendered after the capture pin because they are based on the capture pin data formats.

For more information on WIA driver development see www.microsoft.com/hwdev/wia.


PCI TVTuner Capture Device with Multiple Streams

PCI capture devices with TVTuners, Crossbar, and TVAudio require the creation of a more complex graph. These devices are often capable of bus mastering separate preview and capture streams, each with a potentially different color space and frame dimensions. Such devices may also provide separate streams for vertical blanking interval (VBI) or timecode.

TV Tuner/Capture Card Filter Graph

The PROPSETID_ALLOCATOR_CONTROL property set is unique to this type of graph.

An optional variation for this type of graph is to connect the Preview pin to an Overlay Mixer filter instead of the standard video renderer using the KS_VIDEOINFOHEADER2 structure format. When used in this mode with a display device that supports the VPE Kernel Mode Video Transport, buffers are passed to the capture device along with the Microsoft® DirectDraw® surface handles in the KS_FRAME_INFO structure. The capture driver then can retain ownership of the buffers indefinitely--locking, filling, unlocking, and flipping the surfaces as they are captured. The capture driver must register for notifications indicating loss of surfaces while running full screen MS-DOS applications or exclusive-mode games. In these cases, complete the buffers back to the capture filter.


Video Port Capture Device

Video port-based capture hardware requires the most complex type of capture graph. These devices must provide a video port pin that is connected to the Overlay Mixer. This video port stream allows hardware-based transport to display the preview image without CPU or PCI bus overhead. A separate pin provides capture capability. During capture, the capture buffers are provided to the display driver, which fills the buffer by bus mastering. The interaction between the capture driver and the display driver is defined in Kernel-Mode Video Transport.

If a device supports VBI capture it typically will expose two additional pins: VPVBI and VBI. The VPVBI pin is used by the VBISurf filter to allocate video port surfaces for VBI capture. The VBI pin itself provides the raw VBI samples.

Analog TV video and VBI capture filter graph

Property sets that are unique to this type of graph are: KSPROPSETID_VPConfig
KSPROPSETID_VPVBIConfig
PROPSETID_ALLOCATOR_CONTROL.


Streaming Data from a Video Capture Minidriver

Video capture minidrivers (which are clients of the stream class) can support multiple, simultaneous streams of compressed and uncompressed video, timecode, closed caption, raw and decoded VBI data, and custom data formats. For each data type that can be produced simultaneously with other data types, the driver should create a new stream. Each stream is exposed as a separate kernel streaming pin by the stream class. These pins are mirrored by the DirectShow capture filter. For more information on pins and streaming, see Kernel Streaming Overview.

Video streams are composed of time-stamped, digitized video and related information such as VBI and timecode. Streams can be paused, started, and stopped independently. Stream samples are time stamped with a 100-nanosecond resolution clock.

Each video stream pin can support a variety of different formats. For example, a single pin could support RGB16, RGB24, YUV9, and JPEG digital video. Most devices will support only a few of these pins. More information about stream formats and format ranges is provided in Video Stream Formats.

Streaming conventions are also applied to input pins on the capture filter that represent analog video flowing into the capture device, and to video port output connections for both images and VBI.


VBI Capture

When capturing VBI streams, the capture device should provide "raw", undecoded VBI samples so that downstream codecs can extract CC, NABTS, Teletext, and other proprietary data from the raw samples.


Tuning Data Flow

VBI decoders must be immediately informed of tuning changes. For example, as the tuner switches from channel 3 to channel 4, the VBI decoder must be notified at the beginning of the tuning operation so it can temporarily stop decoding during the period of signal instability. When the tuning operation completes, the VBI decoder must be notified of the new channel and any video standard or country/region code changes that may have occurred.

The tuning packet is propagated from the tuner, through the crossbar, then into the analog video input pin on the capture filter. This packet is only available in user mode until it reaches the capture filter. The capture minidriver receives this tuning packet as a KS_TVTUNER_CHANGE_INFO structure on the analog video input pin.

The tuning packet must be propagated to any VBI output pins using the extended header (see Video Stream Extended Headers). VBI decoders that operate as a chain must similarly propagate the extended header information from their input pins to their output pins.


Medium GUIDs

Breaking apart the Tuner, Crossbar, Capture, and TVAudio components into separate filters results in the need to provide a means to correctly describe the topological connectivity between components. Medium GUIDs (Mediums) are used to describe a hardware connection, and this value is used by graph builders to construct graphs.

Mediums are exposed by the KSPIN_MEDIUM structure, which consists of a GUID-type member (Set) followed by two ULONG members (Id and Flags). The Set member should be assigned a unique GUID representing a hardware connection. The Id member should be set to an instance value, and the Flags member should be set to zero. This allows installation of multiple instances of the same hardware.

Since TVTuner, Crossbar, and TVAudio minidrivers do not actually create Kernel Streaming pins for their inputs and outputs, these drivers need to call a special function to register themselves with DirectShow to allow for automatic graph building. The function used for this purpose is StreamClassRegisterFilterWithNoKSPins.

When deriving a new minidriver from sample code in the Microsoft® Windows® 2000 DDK, it is important to remember to generate new GUID values for the Mediums that reflect the unique topology presented by the minidriver. Failure to do so can result in the Mediums for one device colliding with the Mediums defined for another device.


Using Video Capture Property Sets

Property sets are used to control behavior of devices and streams. Whenever possible, minidrivers should implement the standard property sets defined in ksmedia.h and described in this documentation, such as KSPROPSETID_Pin and PROPSETID_ALLOCATOR_CONTROL. Minidrivers should avoid defining new property sets if one of the standard property sets provides the same functionality.

User-mode applications typically call COM interfaces to control property settings. The COM interface then sends and receives stream and adapter property sets to the driver via DeviceIoControl.

It is important to note that stream property sets as opposed to adapter property sets are not available unless a pin is connected.


Adapter and Stream Property Sets

Property sets are classified as belonging to either the adapter or to a particular stream. Adapter property sets are global with respect to the device and affect all streams. For example, PROPSETID_VIDCAP_CAMERACONTROL, which is used for camera positioning, affects all output streams and is therefore classified as an adapter property set. Note that some properties sets such as PROPSETID_VIDCAP_VIDEOCOMPRESSION (which controls the compression behavior of a single output stream) are implemented as an adapter property that includes a stream index. This is required because stream property sets are unavailable when the pin is not connected. Adapter property sets are always available.

The following table lists the primary property sets used by WDM Video Capture minidrivers. It also indicates whether the property is at the adapter or stream level and whether the property set is required.

Property Set | Adapter Property Set | Capture Stream Property Set | Required
PROPSETID_ALLOCATOR_CONTROL |  | Y | Y
PROPSETID_TUNER | Y |  |
PROPSETID_VIDCAP_CAMERACONTROL | Y |  |
PROPSETID_VIDCAP_CROSSBAR | Y |  |
PROPSETID_VIDCAP_DROPPEDFRAMES |  | Y | Y
PROPSETID_VIDCAP_TVAUDIO | Y |  |
PROPSETID_VIDCAP_VIDEOCOMPRESSION | Y |  |
PROPSETID_VIDCAP_VIDEOCONTROL | Y |  |
PROPSETID_VIDCAP_VIDEODECODER | Y |  |
PROPSETID_VIDCAP_VIDEOPROCAMP | Y |  |

At a minimum, a driver must support properties to control buffer allocation and to report the number of frames dropped during capture as noted in the table above. Support for all other property sets is optional, depending on the capabilities of the device. It is strongly recommended that cameras, which offer only a limited set of capture frame rates, implement the PROPSETID_VIDCAP_VIDEOCONTROL to allow video conferencing applications to make optimal use of system bandwidth.


Property Set Range and Default Values

Several properties can support range and default values. This information can be used by UI elements such as sliders and scrollbars.

The range and default value information is provided in a KSPROPERTY_VALUES structure that is part of a property definition. This structure includes a pointer to a static table consisting of one or more KSPROPERTY_MEMBERSLIST items. Within the KSPROPERTY_MEMBERSLIST structure, the driver can specify either a value or a range of values member. Ranges include the minimum, maximum, and stepping value. Set the MembersFlags member of the KSPROPERTY_MEMBERSHEADER structure to the value KSPROPERTY_MEMBER_RANGES to indicate that the KSPROPERTY_MEMBERSLIST item is a range of values. A KSPROPERTY_MEMBERSLIST item is also used to specify a default value for the property. This is done by setting the MembersFlags member of the KSPROPERTY_MEMBERSHEADER to the value KSPROPERTY_MEMBER_VALUE.

Video capture properties that support range and default values are listed in Video Capture Property Sets.


Custom Property Sets and Interfaces

Some devices and streams may implement custom property sets to control device-specific or stream-specific parameters. Typically, these kernel property sets are exposed as COM interfaces by a KSProxy plug-in. Similarly, custom property pages may be implemented to provide user interfaces to control these property sets, also by creating a KSProxy plug-in.

To create a custom property set:

  1. Create a unique GUID for your property set using Guidgen.exe.
  2. Add the property set implementation to your driver.

To create a custom COM interface or property page for your property set:

  1. Create a KsProxy plug-in DLL implementing your COM interface or property page. The InterfaceID GUID for the interface should match the property set GUID defined above. Link to ksproxy.lib to get the implementation of ::SynchronousDeviceControl.
  2. Add the standard DirectShow mechanism of exposing CFactoryTemplateg_Templates from your DLL to allow self registration of your interface.
  3. Add lines to the device INF file to expose the COM interface and property page as shown in the sample MyINF.inf below.

    The following code samples are extracted from the implementation of IAMCameraControl.

Camera.h

/*
Implements IAMCameraControl via KSPROPERTY_VIDCAP_CAMERACONTROL
*/

class CCameraControlInterfaceHandler :
    public CUnknown,
    public IAMCameraControl {

public:
    DECLARE_IUNKNOWN;

    static CUnknown* CALLBACK CreateInstance(
        LPUNKNOWN UnkOuter,
        HRESULT* hr);

    CCameraControlInterfaceHandler(
        LPUNKNOWN UnkOuter,
        TCHAR* Name,
        HRESULT* hr);

    STDMETHODIMP NonDelegatingQueryInterface(
        REFIID riid,
        PVOID* ppv);

    STDMETHODIMP Set(
            IN long Property,
            IN long lValue,
            IN long Flags);

private:
    HANDLE m_ObjectHandle;
};

Camera.cpp

/*
Implements IAMCameraControl via KSPROPERTY_VIDCAP_CAMERACONTROL
*/

#include "pch.h"
#include "camera.h"

CUnknown*
CALLBACK
CCameraControlInterfaceHandler::CreateInstance(
    LPUNKNOWN   UnkOuter,
    HRESULT*    hr
    )
{
    CUnknown *Unknown;

    Unknown = new CCameraControlInterfaceHandler(UnkOuter, NAME("IAMCameraControl"), hr);
    if (!Unknown) {
        *hr = E_OUTOFMEMORY;
    }
    return Unknown;
}

CCameraControlInterfaceHandler::CCameraControlInterfaceHandler(
    LPUNKNOWN   UnkOuter,
    TCHAR*      Name,
    HRESULT*    hr
    ) :
    CUnknown(Name, UnkOuter, hr)
{
    if (SUCCEEDED(*hr)) {
        if (UnkOuter) {
            IKsObject*  Object;
            *hr =  UnkOuter->QueryInterface(uuidof(IKsObject), reinterpret_cast<PVOID*>(&Object));
            if (SUCCEEDED(*hr)) {
                m_ObjectHandle = Object->KsGetObjectHandle();
                // m_Object handle is file handle of the driver
                if (!m_ObjectHandle) {
                    *hr = E_UNEXPECTED;
                }
                Object->Release();
            }
        } else {
            *hr = VFW_E_NEED_OWNER;
        }
    }
}

STDMETHODIMP
CCameraControlInterfaceHandler::Set(
     IN long Property,
     IN long lValue,
     IN long lFlags
     )
{
    KSPROPERTY_CAMERACONTROL_S  CameraControl;
    ULONG       BytesReturned;

    CameraControl.Property.Set = PROPSETID_VIDCAP_CAMERACONTROL;
    CameraControl.Property.Id = Property;
    CameraControl.Property.Flags = KSPROPERTY_TYPE_SET;
    CameraControl.Value = lValue;
    CameraControl.Flags = lFlags;
    CameraControl.Capabilities = 0;

    return ::SynchronousDeviceControl(
                m_ObjectHandle,
                IOCTL_KS_PROPERTY,
                &CameraControl,
                sizeof(CameraControl),
                &CameraControl,
                sizeof(CameraControl),
                &BytesReturned);
}

STDMETHODIMP
CCameraControlInterfaceHandler::NonDelegatingQueryInterface(
    REFIID  riid,
    PVOID*  ppv
    )
{
    if (riid == uuidof(IAMCameraControl)) {
        return GetInterface(static_cast<IAMCameraControl*>(this), ppv);
    }
    return CUnknown::NonDelegatingQueryInterface(riid, ppv);
}

MyINF.inf

;IAMCameraControl
HKCR,CLSID\{C6E13370-30AC-11d0-A18C-00A0C9118956},,,%PlugIn_IAMCameraControl%
HKCR,CLSID\{C6E13370-30AC-11d0-A18C-00A0C9118956}\InprocServer32,,,kswdmcap.ax
HKCR,CLSID\{C6E13370-30AC-11d0-A18C-00A0C9118956}\InprocServer32,ThreadingModel,,Both
; This IID is aggregated for the filter given the CLSID of the property set
HKLM,System\CurrentControlSet\Control\MediaInterfaces\{C6E13370-30AC-11d0-A18C-00A0C9118956},,,%PlugIn_IAMCameraControl%
HKLM,System\CurrentControlSet\Control\MediaInterfaces\{C6E13370-30AC-11d0-A18C-00A0C9118956},IID,1,70,33,E1,C6,AC,30,d0,11,A1,8C,00,A0,C9,11,89,56

; CameraControl Property Page
HKCR,CLSID\{71F96465-78F3-11d0-A18C-00A0C9118956},,,%PropPage_CameraControl%
HKCR,CLSID\{71F96465-78F3-11d0-A18C-00A0C9118956}\InprocServer32,,,kswdmcap.ax
HKCR,CLSID\{71F96465-78F3-11d0-A18C-00A0C9118956}\InprocServer32,ThreadingModel,,Both
; Associate the property set with the above property page
HKLM,System\CurrentControlSet\Control\MediaSets\{C6E13370-30AC-11d0-A18C-00A0C9118956}\PropertyPages\{71F96465-78F3-11d0-A18C-00A0C9118956},,,%PropPage_CameraControl%


Flow of Control for Video Capture

The flow of control for video capture involves:

Initializing of the driver

Creating a Format

Opening and Closing a Stream

Determining or updating the Streaming States

Capturing Video from the stream

A video capture stream is used in this example. Non-video streams, such as VBI, behave similarly although they use different KS_DATARANGE_Xxx and KS_DATAFORMAT_Xxx structures.


Initializing

When initializing and using streaming minidrivers the following steps are typically employed. These steps are not unique to streaming video. The commands and structures referenced in the following text are described in Stream Class Driver Routines, Stream Class Structures and Stream Minidriver Routines.

To Initialize a Streaming Class Minidriver:

  1. The hardware adapter supported by the minidriver is detected by the Plug and Play Manager.
  2. The Plug and Play Manager loads the minidriver and calls the minidriver's DriverEntry routine. A file object is created from the information in the DriverEntry routine.
  3. The minidriver calls the stream class driver's StreamClassRegisterMinidriver function and passes the HW_INITIALIZATION_DATA structure as a parameter. The HW_INITIALIZATION_DATA structure includes the addresses of minidriver functions that handle stream request block (SRB) command codes. This allows the minidriver to respond to SRB codes sent by the class driver. A complete list of SRB command codes supported by the stream class is documented in the Stream Class SRB Reference.


Creating a Format

Video capture devices can capture video in a number of different formats. The KSDATARANGE structure is used to convey information about the width, height, granularity, cropping, and frame rates for a particular color space. The structures KS_DATARANGE_VIDEO and KS_DATARANGE_VIDEO2 are extensions of the KSDATARANGE structure and should be used for describing video capture formats.

The process of selecting one format is termed performing a data intersection. The SRB used in this process is SRB_GET_DATA_INTERSECTION. The driver is responsible for verifying the correctness of the data range requested and then creating a particular format from the data range, typically using KS_DATAFORMAT_VIDEOINFOHEADER or KS_DATAFORMAT_VIDEOINFOHEADER2.

Finally, the driver must calculate certain fields within the resulting format as shown below:

.
.
.
// Calculate biSizeImage for this request, and put the result in both
// the biSizeImage field of the bmiHeader AND in the SampleSize field
// of the DataFormat.
//
// Note that for compressed sizes, this calculation will probably not
// be just width * height * bitdepth

DataFormatVideoInfoHeaderOut->VideoInfoHeader.bmiHeader.biSizeImage =
DataFormatVideoInfoHeaderOut->DataFormat.SampleSize =
KS_DIBSIZE(DataFormatVideoInfoHeaderOut->VideoInfoHeader.bmiHeader);
.
.
.


Opening and Closing a Stream

Streams are opened using the SRB_OPEN_STREAM request. Information passed in this SRB includes the index of the stream to open and a pointer to a pointer to a KS_VIDEOINFOHEADER structure. The stream index corresponds to the index of the stream in the array of KS_DATARANGE_VIDEO structures returned by the driver in response to SRB_GET_STREAM_INFO. For more information about handling SRB_GET_STREAM_INFO see Video Stream Categories.

The following pseudocode obtains the stream index, KS data format and KS video info header:

int StreamNumber = pSrb->StreamObject->StreamNumber;
PKS_DATAFORMAT_VIDEOINFOHEADER  pKSDataFormat =
    (PKS_DATAFORMAT_VIDEOINFOHEADER) pSrb->CommandData.OpenFormat;
PKS_VIDEOINFOHEADER pVideoInfoHdrRequested =
    &pKSDataFormat->VideoInfoHeader;

Drivers should verify that they can support the requested stream format. In particular, the contents of the KS_BITMAPINFOHEADER structure should be verified, along with cropping and scaling information specified by the rcSource and rcTarget rectangles.

If the device hardware cannot support the capture frame rate requested in the AvgTimePerFrame field of KS_VIDEOINFOHEADER, it should always select the next lower frame rate available. For example, if a camera can support 7 fps and 15 fps and a client application attempts to open the stream at 10 fps, the camera should create a 7 fps physical stream. For a ten second capture in which all available 70 physical frames are captured, the driver should report 100 frames captured, 30 frames of which were dropped by the KSPROPERTY_DROPPEDFRAMES_CURRENT property.

Special rules apply when the output buffer is a DirectDraw surface. In this case, the biWidth member of the BITMAPINFOHEADER structure actually represents the "stride" of the destination DirectDraw surface, which will typically be larger than the video image width.

To determine the requested image width, use the following pseudocode:

if (IsRectEmpty(&pVideoInfoHdrRequested->rcTarget) {
    Width =  pVideoInfoHdrRequested->bmiHeader.biWidth;
    Height = pVideoInfoHdrRequested->bmiHeader.biHeight;
}
else {
    Width = pVideoInfoHdrRequested->rcTarget.right –
            pVideoInfoHdrRequested->rcTarget.left;
    Height = pVideoInfoHdrRequested->rcTarget.bottom –
             pVideoInfoHdrRequested->rcTarget.top;
}

The stream is closed by SRB_CLOSE_STREAM. All outstanding stream SRBs should be returned to stream class.


Streaming States

Each stream provided by the driver exists in one of four states: stopped, acquiring, paused, or running. Upon initialization, the stream is, by definition, in the stopped state. Transitions to the other states are made through SRB_SET_STREAM_STATE. The following table identifies and describes the four stream states.

State | Description
KSSTATE_STOP | Using absolute minimum of resources. No outstanding data SRBs at the driver.
KSSTATE_ACQUIRE | Acquiring resources. Allocating all needed resources such as bandwidth on USB and 1394.
KSSTATE_PAUSE | Preparing to instantly make transition to the Run state.
KSSTATE_RUN | Streaming. Fill buffers and complete SRBs through CompleteStreamSRB.


State Transitions

To ensure orderly resource allocation, only a subset of the possible state transitions is allowed. The following table lists the allowed transitions along with tasks that the driver typically will perform.

Transition | Description
Stop to Pause | Allocate resources. The read SRBs typically are queued after the transition to the Pause state has completed.
Pause to Run | Begin streaming.
Run to Pause | Stop streaming. The outstanding read SRBs remain in the driver-maintained queue.
Pause to Stop | Deallocate resources and complete all outstanding read SRBs. SRBs that have not been filled with an image are completed with zero length in the DataUsed member of the KSSTREAM_HEADER structure.

Note that the transitions may cycle multiple times between the Pause and Run state before returning to the Stop state. Drivers should expect transitions such as:

stop -> acquire -> pause -> run -> pause -> run -> pause -> stop

When a stream is in the Stopped state, it must immediately complete all outstanding data-read SRBs.

Since a user-mode application can terminate unexpectedly while streaming, all capture drivers must accept an SRB_CLOSE_STREAM at any time. Under these conditions, all outstanding buffers are canceled by the stream class through the cancel routine immediately before the SRB_CLOSE_STREAM is received. Note that the stream state may not be set to the stopped state before the termination.


Capturing Video

Once the stream is in the running state, the capture process begins. Based on the frame interval specified by the AvgTimePerFrame member of the KS_VIDEOINFOHEADER structure passed when the stream is opened, the stream transfers images into buffers passed through SRB_READ_DATA. Additional information about the image captured is returned in the KS_FRAME_INFO structure that is appended to the end of the KSSTREAM_HEADER structure.

The following pseudocode obtains the appended KS_FRAME_INFO structure:

PKSSTREAM_HEADER pDataPacket = pSrb->CommandData.DataBufferArray;
PKS_FRAME_INFO pFrameInfo = (PKS_CAPTURE_FRAME_INFO) (pDataPacket + 1);

The driver should set additional information fields about the data captured, such as frames captured, frames dropped, and field polarity.

*pFrameInfo = pStrmEx->FrameInfo;

Next, the driver should set the discontinuity flag if frames have been previously dropped, and then reset its internal flag.

if (pStrmEx->fDiscontinuity) {
    pDataPacket->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY;
    pStrmEx->fDiscontinuity = FALSE;
}

Finally, the driver should relinquish control of the SRB, completing the frame capture.

CompleteStreamSRB (pSrb);


Time Stamps

DirectShow and kernel streaming both utilize time stamps to synchronize multiple data streams. Time is measured in 100 nanosecond (ns) units. Kernel-mode clocks begin counting time when they first transition out of the stopped state. Thereafter, time increases monotonically until the stream again transitions to the stopped state.

Each data packet transferred corresponds to a single frame or field of video or ancillary data. Capture drivers concerned with frame-accurate video capture can choose to provide a clock that all other filters can use as a Reference Clock. DV Minidrivers are an example of minidrivers that should provide graph clocks. Alternatively, capture drivers that run asynchronously to other multimedia streams, such as USB and 1394 conferencing cameras, should time stamp their packets using a clock provided by another component, such as an audio digitizer.

Capture drivers indicate that they are able to provide a master clock by setting the following values in the HW_STREAM_OBJECT:

PHW_STREAM_OBJECT *pStreamObject;

PStreamObject->HWClockFunction = (PHW_CLOCK_FUNCTION)StreamClockRtn;

PStreamObject->ClockSupportFlags =
    CLOCK_SUPPORT_CAN_READ_ONBOARD_CLOCK |
    CLOCK_SUPPORT_CAN_RETURN_STREAM_TIME;


Video Stream Formats

The range of potential formats for a stream is exposed from the minidriver through an array of KSDATARANGE structures. This structure describes image characteristics such as color format, bit depth, and cropping and scaling possibilities.

A specific format is described by a KSDATAFORMAT structure. A single KSDATARANGE can indicate thousands of potential KSDATAFORMAT structures. For example, a KSDATARANGE structure could specify RGB24 with a minimum size of 160x120 and a maximum size of 720x480, with size granularity step size in x and y of 1. From this, an application could request any of more than 200,000 possible output image dimensions through a unique KSDATAFORMAT structure.

Generally, DirectShow and WDM streaming share media format definitions and streaming conventions. This uniformity is somewhat obscured by the differences in naming conventions used by kernel and user-mode components. For example, many format and GUID definitions used in the kernel have the prefix "KS_" but are otherwise identical to their user-mode counterparts. BITMAPINFOHEADER is a user-mode structure, and KS_BITMAPINFOHEADER is the kernel version of the same structure.

Stream formats in the kernel are defined using the KSDATAFORMAT structure. This structure can be extended to include additional type-specific format information such as ranges or format structures.

Comments

DirectShow uses a similar structure to define stream formats.

typedef struct  _AMMediaType    {
    GUID majortype;            // Same as KSDATAFORMAT.MajorFormat
    GUID subtype;              // Same as KSDATAFORMAT.SubFormat
    BOOL bFixedSizeSamples;
    BOOL bTemporalCompression;
    ULONG lSampleSize;         // Same as KSDATAFORMAT.SampleSize
    GUID formattype;           // Same as KSDATAFORMAT.Specifier
    IUnknown __RPC_FAR *pUnk;
    ULONG cbFormat;
    BYTE *pbFormat;
 } AM_MEDIA_TYPE;

Despite the differences in naming conventions, the GUID values used are identical in both of the structures above. Throughout the rest of this document, the WDM streaming naming conventions are used, followed when applicable by the corresponding DirectShow names.

For most video capture streams, the type of the MajorFormat member is KSDATAFORMAT_TYPE_VIDEO (MEDIATYPE_Video), and the type of the Specifier member is FORMAT_VideoInfo. The subtype member and the format block are used to convey details of the particular video data type, such as indicating the color space used.

Note that the low-order four bytes of the subtype member should match the FOURCC values used in the biCompression member of the KS_BITMAPINFOHEADER structure. For example, the following GUID identifies the FOURCC (YVU9) video format. These bytes hold hexadecimal ASCII codes for this format, in reverse order.

39555659-0000-0010-8000-00AA00389B71
      59 = 'Y'
    56 = 'V'
  55 = 'U'
39 = '9'


Video Stream Extended Headers

Some of the output streams from a video capture driver use an extended header to provide auxiliary information about the stream and current frame contents. For example, image stream headers provide information about the current frame number, number of dropped frames, and field polarity flags. As each frame is completed, the driver must fill in the extended header with the auxiliary information about the frame captured.

Drivers must indicate to the stream class their ability to provide this additional information by setting the StreamHeaderMediaSpecific member of the HW_STREAM_OBJECT structure to zero or to one of the two following options.

Extended Header Size | Purpose
KS_FRAME_INFO | Frame count, drop frame count, field polarity flags, and DirectDraw surface handles.
KS_VBI_FRAME_INFO | VBI format, channel change information, video standard.

Video Stream Categories includes a table for each stream category. That table includes the extended header size value that the driver should use per stream category.


Video Stream Categories and Mediums

Traditionally, DirectShow streams have been identified solely by their MediaTypes. While this is sufficient for rendering simple filter graphs, more complex graphs and graphs that reflect a hardware topology require additional information for correct graph building.

Kernel streaming introduces two additional ways to identify and connect pins in a filter graph: Categories and Mediums. The first way is to assign a pin to a Category, which is a GUID that identifies the primary purpose of the pin. For example, a capture filter could have two output pins with identical MediaTypes on each pin. In the case where the filter gives priority to one of the pins, the higher-priority pin could be assigned to the Capture category (PINNAME_VIDEO_CAPTURE), and the lower-priority pin to the Preview category (PINNAME_VIDEO_PREVIEW).

The second way of identifying and connecting a pin is through the use of a Medium. A Medium is a unique identifier containing a GUID that is exposed on an output pin on one filter and on an input pin on another filter. The Medium is used to ensure connectivity between these two pins. One way to think of a Medium is that it identifies a copper trace or wire between the output pin and the input pin.

The DirectShow graph builder interfaces, IFilterMapper2 and ICaptureGraphBuilder, can be used to construct graphs based on both Mediums and Categories.


Video Stream Categories

The KSProxy capture filter provides several different types of streams/pins. The tables in the following sections describe both the different types of streams/pins and the data format types associated with each stream.

Stream category and stream content information is provided by the driver in response to a SRB_GET_STREAM_INFORMATION request. The minidriver returns information about each stream category it supports in a HW_STREAM_INFORMATION structure.

Within the HW_STREAM_INFORMATION structure is a StreamFormatsArray member, which has an entry for each unique data format that the minidriver provides for the specified stream category. Each StreamFormatsArray entry contains stream format information, including image characteristics such as color format, bit depth, cropping and scaling information. Also included in the StreamFormatsArray member is the range of formats available for the specified stream category.

For each video stream category there are corresponding KSDATAFORMAT and KSDATARANGE structures to be used when describing the stream in the HW_STREAM_INFORMATION structure. The structures that correspond to the video capture pin categories are listed in the tables in the following sections.

The Category GUID and PinName GUID for a given video capture stream type are normally identical. These GUIDs are specified in the Category and Name members of the HW_STREAM_INFORMATION structure. The only case where the GUIDs are not the same is when a given stream Category has more than one instance on a filter. In this case, the Category GUIDs should match, but each pin should be assigned a unique PinName GUID.

The following sections contain information pertaining to each of the different video capture stream categories. The PinName and Category GUIDs are listed as well as the video capture structures that should be used when using each of the categories. Required property set support is also listed for each category. Finally, the corresponding user-mode DirectShow type information is listed here for convenience.


Capture, Preview, and Still Categories

The capture, preview, and still stream categories are almost identical in terms of data formats and stream characteristics.

Category/PinName | Description
PINNAME_VIDEO_CAPTURE | Capture category output pins provide a stream of compressed or uncompressed digital video. Typically, this stream is used for writing movies to disk, video conferencing, and for image analysis.
PINNAME_VIDEO_PREVIEW | Preview category output pins provide a stream of usually uncompressed digital video. Typically, the stream is used to view the video stream on the local monitor, in either RGB or YUV formats that can be directly displayed by DirectDraw. In resource-limited situations, capture drivers should prioritize the preview stream lower than the capture stream.
PINNAME_VIDEO_STILL | Still category output pins are used with dual-mode cameras that are capable of producing both a capture stream and a still image stream that is often of higher quality than the capture stream. The still image stream includes the ability to externally or internally trigger acquisition of an image.

Note Since many cameras produce only a single output stream, the DirectShow SDK documentation includes a Smart Tee filter that splits a single stream into a Capture and a Preview stream. Therefore, cameras that produce only a single stream should not internally duplicate their data streams to produce a preview stream.

The following table lists the common characteristics of Capture, Preview, and Still streams.

DataRange Structure | KS_DATARANGE_VIDEO (frames only) KS_DATARANGE_VIDEO2 (fields or frames) KS_DATARANGE_MPEG1_VIDEO KS_DATARANGE_MPEG2_VIDEO
DataFormat Structure | KS_DATAFORMAT_VIDEO (frames only) KS_DATAFORMAT_VIDEO2 (fields or frames) KS_MPEG1VIDEOINFO (for MPEG1) KS_MPEGVIDEOINFO2 (for MPEG2)
Major Format GUID | KSDATAFORMAT_TYPE_VIDEO
Sub-Format GUID | RGB16, RGB24, UYVY, JPEG, …
Specifier GUID | KSDATAFORMAT_SPECIFIER_VIDEOINFO (frames only) KSDATAFORMAT_SPECIFIER_VIDEOINFO2 (fields or frames)
Extended Header Size | KS_FRAME_INFO if not an MPEG format. Zero if an MPEG format.
Required Property Sets | KSPROPSETID_Connection PROPSETID_VIDCAP_DROPPEDFRAMES
Required Event Sets | None
DirectShow majortype | MEDIATYPE_Video
DirectShow formattype | FORMAT_VideoInfo (frames only) FORMAT_VideoInfo2 (fields or frames)


VBI Category

Category/PinName | Description
PINNAME_VIDEO_VBI | VBI category pins provide a stream of raw, unparsed vertical blanking interval (VBI) data. Typically, this stream is passed to codecs that extract closed captioning, NABTS, WST, timecode, and other digital data streams.

When creating the category PinName PINNAME_VIDEO_VBI, the following structures must be used.

DataRange Structure | KS_DATARANGE_VIDEO_VBI
DataFormat Structure | KS_DATAFORMAT_VIDEO_VBI
MajorFormat GUID | KS_DATAFORMAT_TYPE_VBI
SubFormat GUID | KSDATAFORMAT_SUBTYPE_RAW8
Specifier GUID | KSDATAFORMAT_SPECIFIER_VBI
Extended Header Size | KS_VBI_FRAME_INFO
Required Property Sets | None
Required Event Sets | None
DirectShow majortype | MEDIATYPE_VBI
DirectShow formattype | FORMAT_VBI


Raw NABTS Category

Category/PinName | Description
PINNAME_VIDEO_NABTS | North American Broadcast Teletext Standard (NABTS) category output pins provide a raw stream of decoded NABTS data.

When creating the category PinName PINNAME_VIDEO_NABTS, the following structures must be used. Note that the subformat is different for corrected NABTS and raw NABTS.

DataRange Structure | KS_DATARANGE
DataFormat Structure | KS_DATAFORMAT
Major Format GUID | KS_DATAFORMAT_TYPE_NABTS
SubFormat GUID | KSDATAFORMAT_SUBTYPE_NABTS
Specifier GUID | KSDATAFORMAT_SPECIFIER_NONE
Extended Header Size | 0
Required Property Sets | None
Required Event Sets | None
DirectShow majortype | MEDIATYPE_VBI
DirectShow formattype | FORMAT_VBI


Corrected NABTS Category

Category/PinName | Description
PINNAME_VIDEO_NABTS | NABTS category output pins provide a stream of decoded Forward Error Correction (FEC) NABTS data.

When creating the category PinName PINNAME_VIDEO_NABTS, the following structures must be used. Note that the subformat is different for corrected NABTS and raw NABTS.

DataRange Structure | KS_DATARANGE
DataFormat Structure | KS_DATAFORMAT
Major Format GUID | KS_DATAFORMAT_TYPE_NABTS
SubFormat GUID | KSDATAFORMAT_SUBTYPE_NABTS_FEC
Specifier GUID | KSDATAFORMAT_SPECIFIER_NONE
Extended Header Size | 0
Required Property Sets | None
Required Event Sets | None
DirectShow majortype | MEDIATYPE_VBI
DirectShow formattype | FORMAT_VBI


TELETEXT Category

Category/PinName | Description
PINNAME_VIDEO_TELETEXT | TELETEXT category output pins provide a stream of decoded World Standard Teletext (WST) data.

When creating the category PinName PINNAME_VIDEO_TELETEXT, the following structures must be used.

DataRange Structure | KS_DATARANGE_VIDEO_VBI
DataFormat Structure | KS_DATAFORMAT_VIDEO_VBI
Major Format GUID | KS_DATAFORMAT_TYPE_VBI
SubFormat GUID | KSDATAFORMAT_SUBTYPE_TELETEXT
Specifier GUID | KSDATAFORMAT_SPECIFIER_NONE
Extended Header Size | 0
Required Property Sets | None
Required Event Sets | None
DirectShow majortype | MEDIATYPE_VBI
DirectShow formattype | FORMAT_VBI


CC Category

Category/PinName | Description
PINNAME_VIDEO_CC | CC category output pins provide a stream of decoded, closed-caption byte pairs from field 1, line 21.

When creating the category PinName, PINNAME_VIDEO_CC, the following structures must be used.

DataRange Structure | KS_DATARANGE
DataFormat Structure | KS_DATAFORMAT
Major Format GUID | KSDATAFORMAT_TYPE_AUXLine21Data
Sub-Format GUID | KSDATAFORMAT_SUBTYPE_Line21_BytePair
Specifier GUID | KSDATAFORMAT_SPECIFIER_NONE
Extended Header Size | 0
Required Property Sets | None
Required Event Sets | None
DirectShow majortype | None
DirectShow formattype | None


Timecode Category

Category/PinName | Description
PINNAME_VIDEO_TIMECODE | Timecode category output pins provide a stream of timecode.

When creating the category PinName PINNAME_VIDEO_TIMECODE, the following structures must be used.

DataRange Structure | KSDATARANGE
DataFormat Structure | KSDATAFORMAT
Major Format GUID | None defined. Define GUID using Direct Show's MEDIATYPE_Timecode.
Sub-Format GUID | KSDATAFORMAT_SUBTYPE_NONE
Specifier GUID | KSDATAFORMAT_SPECIFIER_NONE
Extended Header Size | 0
Required Property Sets | None
Required Event Sets | None
DirectShow majortype | MEDIATYPE_Timecode
DirectShow formattype | MEDIASUBTYPE_None


Videoport Category

Category/PinName | Description
PINNAME_VIDEO_VIDEOPORT | Videoport category streams are used to transfer image streams from an analog video decoder directly to DirectDraw surfaces through a hardware connection.

When creating the category PinName, PINNAME_VIDEO_VIDEOPORT, the following structures must be used.

DataRange Structure | KSDATARANGE
DataFormat Structure | KSDATAFORMAT
Major Format GUID | KSDATAFORMAT_TYPE_VIDEO
Sub-Format GUID | KSDATAFORMAT_SUBTYPE_VPVideo
Specifier GUID | KSDATAFORMAT_SPECIFIER_NONE
Extended Header Size | 0
Required Property Sets | KSPROPSETID_VPConfig
Required Event Sets | KSEVENTSETID_VPNotify
DirectShow majortype | Mediatype_Video
DirectShow formattype | None


Videoport VBI Category

Category/PinName | Description
PINNAME_VIDEO_VIDEOPORT_VBI | Video port VBI category streams are used to transfer VBI streams from an analog decoder directly to DirectDraw surfaces through a hardware connection.

When creating the category PinName PINNAME_VIDEO_VIDEOPORT_VBI, the following structures must be used.

DataRange Structure | KSDATARANGE
DataFormat Structure | KSDATAFORMAT
MajorFormat GUID | KSDATAFORMAT_TYPE_VIDEO
Sub-Format GUID | KSDATAFORMAT_SUBTYPE_VPVBIVideo
Specifier GUID | KSDATAFORMAT_SPECIFIER_NONE
Extended Header Size | 0
Required Property Sets | KSPROPSETID_VPVBIConfig
Required Event Sets | KSEVENTSETID_VPVBINotify
DirectShow majortype | MEDIATYPE_Video
DirectShow formattype | None


Analog Video Category

Category/PinName | Description
PINNAME_VIDEO_ANALOGVIDEOIN | The Analog Video category represents the stream of analog video input to a video decoder.

When creating the category PinName PINNAME_VIDEO_ANALOGVIDEOIN, the following structures must be used.

DataRange Structure | KS_DATARANGE_ANALOGVIDEO
DataFormat Structure | KS_DATARANGE_ANALOGVIDEO
MajorFormat GUID | KSDATAFORMAT_TYPE_ANALOGVIDEO
Sub-Format GUID | KSDATAFORMAT_SUBTYPE_NONE
Specifier GUID | KSDATAFORMAT_SPECIFIER_ANALOGVIDEO
Extended Header Size | 0
Required Property Sets | None
Required Event Sets | None
DirectShow majortype | MEDIATYPE_AnalogVideo
DirectShow formattype | FORMAT_AnalogVideo

Although the analog video stream essentially models the input to the analog video decoder, it simultaneously acts as a data transport for tuning information. Tuning packets, originating at the TVTuner filter, are passed through any intervening crossbar filters at the start and end of every tuning operation. The data packet is a KS_TVTUNER_CHANGE_INFO, and contains the country/region code, channel, frequency, and analog video standard in use.

Capture filters must propagate this tuning packet in the extended header of VBI output streams to downstream VBI codecs.


USB Camera Minidriver Library Design Guide

The USB camera minidriver library (USBCAMD) is a kernel-mode minidriver library that can be used by developers of video camera minidrivers for the USB bus. USBCAMD simplifies the development of USB bus camera drivers by managing all the USB interfaces for the camera minidriver.

USBCAMD is intended for streaming video cameras (web cameras). Note that web cameras with snapshot capability (still frames) are also supported by USBCAMD. See New in USBCAMD Version 2.0 for more information. Hybrid cameras, those that primarily take stills but that can also capture video are supported by writing a USBCAMD driver and a Microsoft Windows Image Acquisition (WIA) still camera driver (for still image storage and management). See Windows Image Acquisition Drivers for more information about WIA.

See Introduction to USB Drivers for more information about supporting USB devices.

This section includes:

USBCAMD Overview

USBCAMD Operation

New in USBCAMD Version 2.0

Designing a USBCAMD Minidriver

For more information on WDM video capture driver development see www.microsoft.com/hwdev/vidcap.


USBCAMD Overview

USBCAMD offers significant advantages to development of USB bus camera minidrivers. The primary function of USBCAMD is to manage an isochronous stream from the device and allow the camera minidriver to extract video frames from the stream and perform processing on them before they are returned to the calling application. USBCAMD handles all the synchronization, start, stop, and error recovery issues associated with maintaining the ISO stream on the USB bus. The camera minidriver determines if the data is valid, part of the current video frame, or part of the next frame, and indicates this to USBCAMD. The device-specific functions (such as properties) are handled by the camera minidriver as well as support for additional non-ISO streams (for example, still image). USBCAMD also provides support for the use of bulk/interrupt transfer pipes for still image transfer.

USB cameras that support a single isochronous data stream where synchronization information (start of video frames) is embedded in the data stream are ideal for USBCAMD.

Typically, a camera minidriver that connects through the USB bus will be a client of the stream class driver on the upper end and the USB port driver on the lower end as shown in the following diagram.

USB Video Capture Development

In the "A" grouping configuration, the camera minidriver communicates to the stream class driver, the camera, and the USB bus. A minidriver, written to use USBCAMD (grouping "B"), needs to contain only the code that is device-specific (for example, video format, property sets, compression or decompression, and color space conversion). The USBCAMD library will control the actual connection to the stream class driver and the USB bus driver, thereby simplifying the code in the camera minidriver.

USBCAMD provides generic services that manage isochronous data streams on the USB bus. This allows the minidriver writer to focus on support for camera properties and image processing instead of the details of maintaining an ISO stream on the USB bus.

Additional developer information, including the USB specifications, may be obtained through the USB consortium web site at www.usb.org/developers/.

General or consumer information may be obtained at www.usb.org.


USBCAMD Operation

The camera minidriver passes the stream request blocks (SRB) associated with the video stream to USBCAMD. USBCAMD will then start and stop the ISO stream when necessary. USBCAMD will call the camera minidriver when it is necessary to allocate bandwidth and free bandwidth (usually the camera minidriver will select an appropriate alternate setting). This ensures that the camera will only be using USB bandwidth when it is running. The camera minidriver "sees" each packet on the ISO stream and is responsible for indicating the start of a new video frame. Some SRBs are handled by the camera minidriver. For example, SRBs that report video format or handle property requests are handled entirely by the minidriver.

The camera minidriver binds to the USBCAMD library by calling USBCAMD_DriverEntry in its DriverEntry routine. USBCAMD will register the minidriver with the stream class driver. The camera minidriver will receive SRBs sent from the stream class driver. The camera minidriver can call routines in USBCAMD to help process the SRBs. The USBCAMD library will call into the camera minidriver via a set of callback routines that are passed to USBCAMD. The camera minidriver passes its callback routines to USBCAMD in a USBCAMD_DEVICE_DATA2 structure. This structure is passed to USBCAMD through a call to USBCAMD_InitializeNewInterface. A complete description of the control flow between the stream class driver, USBCAMD, and the camera minidriver is described in Device Initialization and Pin Opening.


New in USBCAMD Version 2.0

USBCAMD 1.0 first shipped with the Windows® 98 DDK. Version 2.0 of USBCAMD ships with the Windows® 2000 DDK. USBCAMD version 2.0 presents several new features and changes that are described as follows:

  • Dual-mode Support

    USBCAMD version 2.0 is capable of exposing a still pin to a stream class as well as a capture pin. The still pin can be exposed for imaging devices that have either dedicated pipes for still pins or that use the same pipe for both still and video pins.

  • More Versatile USB Pipe-Configuration Support

    USBCAMD now supports cameras that use bulk or ISO pipes for video and still transfer. USBCAMD no longer assumes preset configuration information about the number or type of pipes used. Rather, the library queries the minidriver and builds this information dynamically during initialization.

  • Support for Hardware-Triggered Events through an Interrupt Pipe

    A minidriver can register an external trigger event through an interrupt pipe. The interrupt can be handled by USBCAMD. An example of this is using an interrupt pipe to notify the device driver when a snapshot button is pressed.

  • Further Integration with the Still Image Class Stack

    The Still Image architecture (STI) event monitor can be notified of device events. For example, by pressing the snapshot button, the STI monitor will be notified and a preregistered STI application, associated with the still pin on the camera, can be launched using the STI push model.

  • Completion of SRBs

    USBCAMD version 1.0 and USBCAMD version 2.0 have different assumptions about who is responsible for completing SRBs. This can result in non-completion of I/O events or multiple completion of I/O events.

    USBCAMD version 2.0 completes SRBs whereas in USBCAMD version 1.0 completion of SRBs was the camera minidriver's responsibility.

  • Additional Enhancements

    USBCAMD version 2.0 is designed to reduce buffer copying as well as support power management and Plug and Play in Windows® 2000 and later versions.

  • Hibernation Support Added

    Hibernation support has been added to USBCAMD and is present in Windows Millennium Edition (Windows Me) and later. Before Windows Me, no hibernation support was present in USBCAMD (this includes Windows 2000, Windows 98 SE and Windows 98 Gold).

  • Limitations of USBCAMD Version 2.0

    Note that USBCAMD Version 2.0 handles cameras that have a single interface with multiple alternate settings controlling the video signals. All alternate settings should have the same type and number of pipes.

  • USBCAMD Timeline

    USBCAMD version 1.0 is supported on Windows 98 Gold and Windows 98 SE as usbcamd.sys, but is not supported on Windows 2000.

    USBCAMD version 2.0 is supported on Windows Me and later as both usbcamd.sys and usbcamd2.sys.

    USBCAMD version 2.0 adds support for still pins, power management (e.g. hibernation) and extended versions of the APIs.

    For Windows Me and later versions, camera vendors should write to USBCAMD version 2.0 instead of the older, obsolete version 1.0 specification.

  • USBCAMD Sources Removed

    Usbcamd.sys and usbcamd2.sys are kernel DLLs that are intended to be used by multiple camera vendors.

    The USBCAMD libraries must not be altered or replaced by individual IHVs. The source code is no longer being provided.

    The Windows XP DDK provides comprehensive documentation for all the new version 2.0 APIs so that vendors may make full use of this supplied library. Please see the USBCAMD Overview topic for more information about creating USBCAMD minidrivers.


Designing a USBCAMD Minidriver

The following topics describe the implementation and operation of a camera minidriver that is a client of USBCAMD.

Device Initialization and Pin Opening

Data Flow Using ISO Pipes

Using Bulk Pipes to Retrieve Still Frames from the Camera

Minidriver Entry Points

Ideally, USB imaging devices designed for use with USBCAMD will have one of the following configurations:

  1. USB cameras that support a single ISO data stream where synchronization information (start and end of video or still frames) is embedded in the data stream. These cameras can time-multiplex both video and still frames through the same ISO pipe or reuse individual video frames as still frames.
  2. Same as the first configuration where USB cameras support a single ISO data stream with the addition of an Interrupt Pipe for external trigger event notifications.
  3. Same as the first configuration where USB cameras support a single ISO data stream with the addition of two I/O bulk pipes to control and retrieve still frames from camera.
  4. USB cameras that support dual ISO streams where one is used for streaming data and the other for synchronization information (start and end of video or still frames). These cameras can also time-multiplex both video and still frames through the same ISO pipe or reuse individual video frames as still frames.
  5. USB cameras that use two bulk pipes for streaming data and control parameters to and from the camera and a third optional interrupt pipe for trigger event notifications.


Device Initialization and Pin Opening

The following procedures illustrate the flow between the camera minidriver and the USBCAMD library in the processing of SRBs sent from the stream class driver to the USBCAMD library.

Processing of the following SRBs is described:

SRB_INITIALIZE_DEVICE

  1. Camera minidriver: Initialize the USBCAMD library by calling USBCAMD_InitializeNewInterface, indicating video or still raw processing requirements in kernel, such as enable device events.
  2. Camera minidriver: Call USBCAMD_AdapterReceivePacket.
  3. USBCAMD: Acquire USB device and configuration descriptors.
  4. USBCAMD: Call minidriver's CamConfigureEx routine.
  5. Camera minidriver: Complete the configuration. Choose an alternate setting and maximum transfer size. Fill in the array of USBCAMD_Pipe_Config_Descriptor structures.
  6. USBCAMD: Parse the array of USBCAMD_Pipe_Config_Descriptor structures.
  7. USBCAMD: Call minidriver's CamInitialize routine.
  8. Camera minidriver: Complete the initialization. Set the device power and activate the default setting on the camera.
  9. USBCAMD: Provide the number of streams and stream descriptor size to stream class.

SRB_GET_STREAM_INFO

  1. Camera minidriver: Provide the HW_STREAM_INFORMATION stream information structure to stream class.
  2. Camera minidriver: Fill in pointer to the array of device property sets in stream class's HW_STREAM_HEADER structure.
  3. Camera minidriver: Call USBCAMD_AdapterReceivePacket.
  4. USBCAMD: Fill in the number of pins in the stream header.
  5. USBCAMD: Expose the device event table, if any.
  6. USBCAMD: Fix entry values in the stream information table. Set category name (capture/still).
  7. USBCAMD: Fill in pointer to the stream property array.

SRB_INITIALIZATION_COMPLETE

  1. Camera minidriver: Acquire GUID_USBCAMD_INTERFACE for USBCAMD2 using IRP_MJ_PNP and IRP_MN_QUERY_INTERFACE.

SRB_GET_DEVICE_PROPERTY

  1. Camera minidriver: Get the properties the camera driver handles such as PROPSETID_VIDCAP_VIDPROCAMP, PROPSETID_VIDCAP_CAMERACONTROL and PROPSETID_VIDCAP_VIDEOCONTROL and any other custom property sets.

SRB_SET_DEVICE_PROPERTY

  1. Camera minidriver: Set the properties the camera driver handles by acquiring the parameters of PROPSETID_VIDCAP_VIDPROCAMP, PROPSETID_VIDCAP_CAMERACONTROL and PROPSETID_VIDCAP_VIDEOCONTROL and any other custom property sets.

SRB_GET_DATA_INTERSECTION

  1. Camera minidriver: Return a KSDATAFORMAT structure from a KSDATARANGE structure.
  2. Camera minidriver: Check that the framerate requested (VideoInfoHeader.AvgTimePerFrame) is within the upper and lower limits for the video format requested. If it exceeds the limits, the minidriver should correct the following values in pSrb->CommandData.IntersectInfo->Datarange: VideoInfoHeader.AvgTimePerFrame, VideoInfoHeader.dwBitRate

SRB_OPEN_STREAM

  1. Camera minidriver: Verify the video format.
  2. Camera minidriver: Call USBCAMD_AdapterReceivePacket.
  3. USBCAMD: Save the video format accepted by the camera minidriver.
  4. USBCAMD: Call the minidriver's CamAllocateBandwidthEx routine to allocate bandwidth based on video-format data and get the maximum buffer size for this format.
  5. Camera minidriver: Calculate the isochronous channel's maximum packet size that satisfies the requested frame rate and output windows size.
  6. Camera minidriver: Choose the closest alternate setting by calling USBCAMD_SelectAlternateInterface. The minidriver should provide USBCAMD with the maximum possible frame size that can be produced by the camera.
  7. Camera minidriver: Set the hardware scaling on the camera. Set the camera controls to the stored values in the registry, or to the default setting if the first time.
  8. Camera minidriver: Ensure that the framerate (VideoInfoHeader.AvgTimePerFrame) falls within the limits for the video format, and correct it if it does not
  9. USBCAMD: Call the minidriver's CamStartCaptureEx routine.
  10. Camera minidriver: Set the hardware to capture mode.
  11. USBCAMD: Initialize ISO or bulk transfer.

SRB_CLOSE_STREAM

  1. USBCAMD: Cancel pending IRPs submitted to USBCAMD. Return any pending data SRBs to stream class.
  2. USBCAMD: Call the minidriver's CamStopCaptureEx routine.
  3. Camera minidriver: Send a stop capture command to the camera.
  4. USBCAMD: Call the minidriver's CamFreeBandwidthEx to free ISO bus BW, if applicable.
  5. Camera minidriver: Select an idle alternate setting.
  6. USBCAMD: Free resources associated with USB pipes.

SRB_UNINITIALIZE_DEVICE

  1. USBCAMD: If any streams are still open, close them by calling CamStopCaptureEx/CamFreeBandwidthEx for each stream
  2. USBCAMD: Call CamUninitialize.
  3. Camera minidriver: Clean up and free resources.

SRB_SURPRISE_REMOVAL

  1. USBCAMD: Cancel pending data SRBs and return the SRBs with STATUS_CANCELLED.
  2. USBCAMD: Call CamStopCaptureEx/CamFreeBandwidthEx on all opened streams
  3. USBCAMD: Return STATUS_CANCELLED on any read/write SRBs that come down after SRB_SURPRISE_REMOVAL.

SRB_SET_DATAFORMAT

  1. Camera minidriver: Verify the new video format.
  2. Camera minidriver: Call USBCAMD_SetVideoFormat.
  3. USBCAMD: Save the new format with the associated stream extension.

SRB_CHANGE_POWER_STATE from Power ON to Power OFF

  1. USBCAMD: Stop streaming on isochronous pipe if applicable, or cancel pending bulk or interrupt transfers.
  2. USBCAMD: Call minidriver's CamStopCaptureEx routine.
  3. Camera minidriver: Send stop capture command to hardware.

SRB_CHANGE_POWER_STATE from Power OFF to Power ON

  1. USBCAMD: Restart streaming on isochronous pipe if applicable, or resubmit bulk or interrupt transfer to USB class.
  2. Camera minidriver: Restore camera settings and camera power consumption to normal levels.
  3. USBCAMD: Call minidriver's CamStopCaptureEx routine.
  4. USBCAMD: Call minidriver's CamStartCaptureEx routine.


Data Flow Using ISO Pipes

Data buffers are allocated and submitted to the driver before a stream state change from Pause to Run. The number of buffers allocated is determined by the driver when a SRB_GET_STREAM_PROPERTY is sent with a property ID of KSPROPERTY_CONNECTION_ALLOCATORFRAMING. USBCAMD requests three frames for video pins and one frame for still pins.

These buffers are queued in the read queue for the stream extension every time USBCAMD receives a SRB_READ_DATA request. Stream class uses SRB_SET_STREAM_STATE to request changing the stream state from Pause to Run. USBCAMD begins streaming on the isochronous channel by requesting two ISO transfers of 32 packets. Each packet has a maximum size corresponding to the maximum size in the selected alternate setting.

Streaming on the isochronous channel is independent of Microsoft® DirectShow® streaming. Double-buffer ISO transfer requests are continuously submitted to USBCAMD and will not stop until one of the following two conditions occur: a stop DirectShow stream state is issued (KSSTATE_STOP), or a camera driver requests USBCAMD to stop ISO streaming using the USBCAMD_SetIsoPipeState routine. A dispatch level timer with 250 microseconds resolution is always active and ready to respond to an error condition while ISO streaming is on.

USBCAMD_TIMEOUT_STREAM_WAIT will be set when a hardware error causes a time-out on a data SRB. USBCAMD_STOP_STREAM will be set whenever there is a need to stop ISO streaming.

The interaction between USBCAMD and the camera minidriver takes place at two levels while streaming is in progress:

  1. The first level is DISPATCH_LEVEL. At this level, USBCAMD calls the camera driver's CamProcessUSBPacketEx routine for every packet that USBCAMD receives back from USBD. The camera minidriver should set the appropriate error flags in the case of error conditions. The driver should also set a new frame flag if the beginning of a new frame is detected using the FrameComplete flag.
  2. The second level occurs when a frame is completed. At this level USBCAMD calls the camera driver's CamProcessRawVideoFrameEx routine, from the context of a worker thread, to process a frame if there is a need to perform a color space conversion or decompression. USBCAMD will return a completed raw frame to stream class and is processed by the camera minidriver at passive level. If there is insufficient frame data or an error occurred during decompression due to bad data,etc. BytesReturned should be set to 0.


Using Bulk Pipes to Retrieve Still Frames from the Camera

An STI USB minidriver can retrieve still frames from the camera using USBCAMD bulk services.

The following steps outline how to retrieve still frames from cameras that use bulk pipes for still image transfer.

  1. Open the WDM video capture source filter associated with the camera.
  2. Open the still pin on the filter handle obtained in Step 1.
  3. Send a ReadFile on that pin with maximum-sized buffer.
  4. Set the stream state from Pause to Run.
  5. Get the interface pointer to PROPSETID_VIDCAP_VIDEOCONTROL property set.
  6. Set the KS_VideoControlFlag_Trigger flag associated with property ID KSPROPERTY_VIDEOCONTROL_MODE.
  7. Once the video control handler of the camera minidriver receives the trigger request, it should call USBCAMD_BulkReadWrite with a NULL buffer pointer.
  8. USBCAMD will dequeue a data SRB from the still pin and call the minidriver's CamNewVideoFrameEx entry point before it starts the bulk transfer. The camera minidriver can reduce the requested size of the bulk transfer if it determines that the actual still frame is smaller than the maximum size allocated by DirectShow.
  9. Upon completion of the bulk transfer, USBCAMD will call the CamProcessRawVideoFrameEx entry point for further processing. Afterward, USBCAMD will finish the stream class read request on the still pin.

A user application can cancel a requested bulk read or write by sending a CancelIO to the still pin. If there is a need to load tables to the camera through a bulk out pipe, the USBD driver can send a WriteFile to the still pin.

Still data flow is intended for use in a pull model. A pull occurs when an application requests a still. Still data flow will also work in a push model where it functions as a pull. A push occurs when the user pushes the button on the camera, triggering the device event. USBCAMD will send a KSEVENTSETID_VIDCAPTOSTI event that can be propagated all the way to the imaging application.


Minidriver Entry Points

The camera minidrivers defines all its entry points in a USBCAMD_DEVICE_DATA2 structure. The USBCAMD_DEVICE_DATA structure is supported in USBCAMD version 2.0 only for purposes of backward compatibility. For more information on the camera minidriver callback routines, refer to section on USB Camera Minidriver Library Callback Functions.


DVD Minidrivers

Digital video disc (DVD) is a trademarked name owned by the DVD Consortium. DVD provides digital data storage that encompasses audio, video, and other digital data. This documentation discusses the design of DVD decoder minidrivers that are used for movie playback (video and audio) from DVD. The DVD Consortium has utilized several major compression technologies in the storage of video and audio on a DVD disc, including MPEG-2 (both video and audio), AC-3, and DTS.

For more information on WDM DVD decoder minidriver development see www.microsoft.com/hwdev/dvd.


DVD Architecture Overview

The following diagram illustrates a hardware decoder-based DVD solution and how it fits into the layered Windows Driver Model (WDM) architecture. It shows the complete support for hardware decoders with existing DVD technologies under Microsoft® Windows® XP. The white boxes represent software supplied by Microsoft, and the shaded box represents the component provided by hardware vendors. The ovals represent hardware supplied by IHVs and OEMs. PCs with Microsoft DVD support both DVD storage and, if the proper decoding hardware or software is present, full DVD video playback.

Hardware DVD Decoding

The following diagram illustrates a software-only DVD decoder solution. This solution does not require a hardware driver and is shown for comparative purposes. The white boxes represent software supplied by Microsoft. There are no shaded boxes because this is a software-only solution. The ovals represent hardware supplied by IHVs and OEMs.

Software DVD Decoding


DVD Support in Windows

The Microsoft® family of Windows® operating systems, from Windows 98 Gold to Windows XP provide support for DVD playback.

The Windows XP DDK uses the Windows Driver Model (WDM) environment for DVD decoder minidriver development.

Use the DDK to create WDM DVD decoder minidrivers for:

Windows 98 Gold

Windows 98 SE

Windows Millennium Edition

Windows 2000

Windows XP and later operating systems.

The DVD header files and libraries are included in the Windows XP DDK.

Header files and path:

$(DDK_INC_PATH)\ksmedia.h

$(DDK_INC_PATH)\ntddcdvd.h

Library files and path:

$(DDK_LIB_PATH)\stream.lib

$(DDK_LIB_PATH)\ks.lib

$(DDK_LIB_PATH)\ksguid.lib

$(DDK_LIB_PATH)\dxapi.lib

Under Windows XP, the following components support DVD:

  • WDM Stream Class Driver

    The WDM stream class driver supports streaming data types and MPEG-2 and AC-3 hardware decoders. Hardware vendors have to write only a small amount of interface code in a WDM streaming minidriver to ensure that the specific features in their hardware are supported natively under Windows. For more information, see Stream Class Driver Routines, Stream Class Structures, or Stream Minidriver Routines. Also, see the sample minidrivers under the DVD section of the Windows XP DDK release.

  • DVD-ROM Class Driver

    DVD-ROM has its own industry-defined command set, which was referred to during development as the Mt. Fuji command set and is currently under review by the Small Form Factor Committee (to be published as SFF 8090). Support for this command set is provided in Windows XP by an updated CD-ROM class driver. This class driver supports the full Mt. Fuji command set, including commands for copyright protection and regionalization. In Windows XP, support will be provided in a new WDM DVD-ROM device driver. The new driver provides the ability to read data sectors from a DVD-ROM drive.

  • UDF File System

    NT-based operating systems provide a UDF-installable file system, similar to FAT and NTFS. This installable file system supports UDF-formatted DVD discs.

  • Microsoft® DirectShow®

    DirectShow filters and related support include a DVD Navigator/Splitter, proxy filters for interfacing with the hardware decoder minidrivers for video, SP and audio streams, line21 decoder (closed caption), a video mixer, video renderer, and an audio renderer.

  • Microsoft DirectDraw® HAL with VPE

    Decoded video streams are very large, possibly too large even for the PCI bus on a personal computer. One way manufacturers have solved this problem by creating dedicated buses to transfer decoded video streams from an MPEG-2 decoder to the display card. Microsoft provides software support for these interfaces using the DirectDraw hardware abstraction layer (HAL) with Video Port Extensions (VPE). This is a technique to pass video that was decoded in hardware to the VGA. For software decoders, the AGP bus can be used to transfer the decoded video to the VGA.

  • Copyright Protection

    Copyright protection for DVD is provided by encrypting sectors on a disc and then decrypting those sectors prior to decoding them. Microsoft helps support both software and hardware decryptors by way of the DVD Navigator/splitter, which oversees the authentication sequence between the decoders and the DVD-ROM drives in a PC. The key exchange sequence is implemented through properties sent to the DVD decoder's input pins in the minidriver.


DirectShow and DVD Support

DirectShow provides support for many DVD playback capabilities, including:

  • Standard DirectShow interface, which lets any application fully control DVD playback, including nonlinear video playback and user interactivity.
  • Interlaced video media types.
  • New video, audio, and DVD subpicture decoder filter interfaces for applications that require low-level control.

The following DirectShow filters are provided by Microsoft:

  • DirectShow DVD Navigator/Splitter Filter

    The DVD Navigator/Splitter filter provides the intelligence for playing DVD movies. It is able to interpret the programming language embedded in DVD movies, parental control, and multiple languages, and it processes most DVD-specific data structures. This filter reads the DVD stream directly from a DVD disc and produces individual media type outputs, such as audio, video, and subpicture. The filter reacts to commands in the stream and handles all user input.

  • DirectShow Proxy Filter

    This filter converts DirectShow interfaces to WDM connection and streaming architecture properties. It creates (that is, instantiates) a device object for each data type to be decoded in hardware, such as audio and video data types. This filter supports plug-ins that allow expansion for new interfaces.

  • DirectShow Closed-Caption Decoding Filter

    This filter converts the closed-caption data that might be included in a DVD video stream into text images.

  • DirectShow Video Port Manager and Rendering Filters

    These filters enable playback of video using hardware video ports, and provide support for blending low-bandwidth video streams, such as the closed caption decoder output stream.

Note Microsoft does not provide MPEG-2 or AC-3 software/hardware decoder filters with Windows XP. Vendors must supply either a DirectShow-compatible software decoder for each required stream, or provide a WDM streaming-compatible DVD minidriver to support their DVD hardware decoders.


Vendor-Supplied DVD Drivers

Hardware vendors need to write only a small amount of interface code in a DVD minidriver to ensure that specific features in their hardware are supported natively under Windows.

DVD decoder drivers are stream class minidrivers. This means that developers, creating drivers for multifunction devices, can build on the stream class using a single driver model that works for all data types. Previously, a developer would have to create drivers using various models for MPEG-2, audio, MIDI, and subpicture. WDM DVD drivers are easy to write, are portable, and have no multiprocessor issues if they utilize stream class synchronization. Refer to the Stream Minidriver Design Guide for more information.

The following topics are included:

DVD Streams

Close Captioning

Data and Time Discontinuities

Copy Protection

Copy Protection Implementation Notes

A/V Synchronization


DVD Streams

DVD minidrivers support both input and output data streams. Streams are uniquely defined by three GUIDs (major type, minor type, and specifier) and a format block. Stream formats are also referred to as media types. See DirectShow in the Platform SDK documentation, Graphics and Multimedia Services, DirectX Media SDK directories, and the Kernel-Mode Streaming Reference for more information on media types and format blocks.

Two streams are discussed for DVD implementation:

Input Streams

Output Streams


Input Streams

The DVD input streams are provided to the minidriver as arrays of encrypted DVD PACKs. PACKs are as defined in the DVD specification. Note that the SCR field of the PACK is set to zero since Microsoft's DVD architecture uses the "master clock" paradigm for audio and video synchronization. Typically, the audio stream of the DVD minidriver provides the master clock. See DirectShow in the Platform SDK, Graphics and Multimedia Services, DirectX Media SDK directories, and the Stream Class Driver Reference.

DVD data streams are sent to the minidriver through the SRB_WRITE_DATA function. See Handling Stream Request Blocks for more information on SRB functions. Hardware should support scatter/gather DMA, since several DVD PACKs may be present in a single request packet.

The following media types define the input streams utilized by DVD.

MPEG 2 Video Stream

Major Format GUID | KSDATAFORMAT_TYPE_DVD_ENCRYPTED_PACK
Minor Format GUID | KSDATAFORMAT_SUBTYPE_MPEG2_VIDEO
Format Block Specifier GUID | KSDATAFORMAT_SPECIFIER_MPEG2_VIDEO
Format Block Structure | MPEG2VIDEOINFO (Superset of VIDEOINFO2 structure. Also indicates MPEG Profile and Level.)

AC-3 Audio Stream

Major Format GUID | KSDATAFORMAT_TYPE_DVD_ENCRYPTED_PACK
Minor Format GUID | KSDATAFORMAT_SUBTYPE_AC3_AUDIO
Format Block Specifier GUID | KSDATAFORMAT_SPECIFIER_WAVEFORMATEX (Note that this is expected to change.)
Format Block Structure | KSDATAFORMAT_WAVEFORMATEX Superset of WaveFormatEx (More than two channels. Down-mix descriptor.)

LPCM Audio Stream

Major Format GUID | KSDATAFORMAT_TYPE_DVD_ENCRYPTED_PACK
Minor Format GUID | KSDATAFORMAT_SUBTYPE_LPCM_AUDIO
Format Block Specifier GUID | KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
Format Block Structure | KSDATAFORMAT_WAVEFORMATEX

DTS Audio Stream

Major Format GUID | KSDATAFORMAT_TYPE_DVD_ENCRYPTED_PACK
Minor Format GUID | KSDATAFORMAT_SUBTYPE_DTS_AUDIO
Format Block Specifier GUID | KSDATAFORMAT_SPECIFIER_WAVEFORMATEX (Note that this is expected to change.)
Format Block Structure | KSDATAFORMAT_WAVEFORMATEX Superset of WaveFormatEx (More than two channels. Down-mix descriptor.)

SDDS Audio Stream

Major Format GUID | KSDATAFORMAT_TYPE_DVD_ENCRYPTED_PACK
Minor Format GUID | KSDATAFORMAT_SUBTYPE_SDDS_AUDIO
Format Block Specifier GUID | KSDATAFORMAT_SPECIFIER_WAVEFORMATEX (Note that this is expected to change.)
Format Block Structure | KSDATAFORMAT_WAVEFORMATEX Superset of WaveFormatEx (More than two channels. Down-mix descriptor.)

Audio stream format can change between AC3 and LPCM during playback. When this happens, the minidriver receives an audio data packet with the KSSTREAM_HEADER_OPTIONSF_TYPECHANGED bit set in the OptionsFlags member of the KSSTREAM_HEADER structure.

The minidriver may never see the TYPECHANGED flag if it does not correctly expose the data formats supported by its audio stream. Correctly exposing the data formats supported by a stream involves two steps. First, the SRB_GET_STREAM_INFO handler for the stream must set the StreamFormatsArray pointer to point to an array of NumberOfFormatArrayEntries pointers, each of which points to a valid format block. Second, the SRB_GET_DATA_INTERSECTION handler must copy the format block corresponding to the proposed format into the supplied buffer. See the sample minidrivers under the DVD section of the Windows XP DDK release.

Subpicture Stream

Major Format GUID | KSDATAFORMAT_TYPE_DVD_ENCRYPTED_PACK
Minor Format GUID | KSDATAFORMAT_SUBTYPE_SUBPICTURE
Format Block Specifier GUID | KSDATAFORMAT_SPECIFIER_NONE
Format Block Structure | None

For subpicture highlighting, palette information and highlight information are passed as properties. The subpicture data stream consists of packets of data, as provided by the DVD specification. While the PACK header is stripped off, it is still provided.


Output Streams

The following output stream media types are defined for DVD.

Video Port Stream

Major Format GUID | KSDATAFORMAT_TYPE_VIDEO
Minor Format GUID | KSDATAFORMAT_SUBTYPE_VPVideo
Format Block Specifier GUID | KSDATAFORMAT_SPECIFIER_NULL No format block.

Kernel-mode interface provides control of Video Port Extensions (VPE) settings. For more information, see the Video Port Extensions specifications.

CC Out Stream

Major Format GUID | KSDATAFORMAT_TYPE_AUXLine21Data
Minor Format GUID | KSDATAFORMAT_SUBTYPE_Line21_ GOPPacket
Format Block Specifier GUID | KSDATAFORMAT_SPECIFIER_NONE No format block.

A frame size of 200 (decimal) in the SampleSize member of the KSDATAFORMAT structure must be specified. See Close Captioning for more information.


Close Captioning

Support for close captioning is required. The decoder must provide close captioning information for the Microsoft line 21 decoder. Applications may not simply decode the close captioning information inside the MPEG2 decoder and add it to the video stream. The decoder presents the close captioning pin as an output pin. After the stream is opened, the decoder receives SRB_READ_DATA requests on the stream. The decoder queues these requests until close captioning data is available.

When a group of pictures (GOP) start code is processed in the video stream, the decoder looks for user data (close captioning information) and returns that information using one of the stream request blocks (SRB) present on the close captioning stream queue. All data discontinuity and format block changes should be propagated from the Video Pin to the Close Captioning pin.


Copy Protection Implementation Notes

The following topics address issues of implementing copy protection methods.

Multiple Streams on the Same Hardware

Synchronizing Key Exchange With Data Flow

Regionalization

Macrovision


Multiple Streams on the Same Hardware

Many decoders have several streams using the same piece of decoder hardware. For these devices, it is not necessary to perform key negotiation separately on each stream. To indicate this to the DVD decoder model, use the KSPROPERTY_DVD_SET_COPY_STATE property. When a get operation is issued on this property, a decoder may respond with either of the following:

KS_DVDCOPYSTATE_AUTHENTICATION_NOT_REQUIRED

KS_DVDCOPYSTATE_AUTHENTICATION_REQUIRED

KS_DVDCOPYSTATE_AUTHENTICATION_NOT_REQUIRED indicates that the given stream does not require key negotiation because another stream on the same hardware has already performed it. To allow for other applications besides DVD-MOVIE playback, in the case where a decoder needs to perform copy protection on only one stream, the Decoder performs negotiation on the first stream to receive a Get property call for KSPROPERTY_DVD_SET_COPY_STATE after stream opening. Do not hardcode the copy protection properties to work with only one stream.

For example, if the decoder receives the Get property on the audio stream first, it responds with KS_DVDCOPYSTATE_AUTHENTICATION_REQUIRED on the audio stream and KS_DVDCOPYSTATE_AUTHENTICATION_NOT_REQUIRED on all other streams. After replying with AUTHENTICATION_NOT_REQUIRED, that stream will not receive any more key exchange properties until the next title key is negotiated. At that point, the decoder may again choose to reply with AUTHENTICATION_NOT_REQUIRED.


Synchronizing Key Exchange With Data Flow

The key exchange process may begin prior to all data from the previous key being processed. An example of this would be in the transition from the Trailer Title Set into the Main Program Title set on some movies. There is a flag in the TypeSpecificFlags field of the KSSTREAM_HEADER structure for each data packet. This flag is the KS_AM_UseNewCSSKey. It indicates that the data sample immediately following that header is the first data sample to which the new title key applies. If the decrypter can process a new key exchange while still using the old key, the decoder should process the key exchange as it receives the properties. If the decrypter must wait until all movie data requiring the previous key has been processed, then the decrypter holds the SRB for the Set property. The decrypter uses a KSPROPERTY_DVDCOPY_SET_COPY_STATE with parameter KS_DVDCOPYSTATE_INITIALIZE or KS_DVDCOPYSTATE_INITIALIZE_TITLE until it has received the KS_AM_UseNewCSSKey flag on all streams that are connected to it. After that, the decoder processes all packets received until that point. This will prevent using the incorrect key on the incorrect data.


Regionalization

The Decoder should not be involved in any part of the regionalization process. Other parts of the streaming architecture will enforce regionalization. Under most circumstances, the decoder minidriver does not implement the KSPROPERTY_DVDCOPY_REGION property.

If the decoder is forced to be limited to a certain region (by hardware or other considerations) then it may respond to the KSPROPERTY_DVDCOPY_REGION property to override all other system regions. The decoder should set exactly one bit corresponding to the region that the decoder is designated for. Note that the logic is inverted from the region coding on the media. For example, a decoder designed to work only in Region 1 (USA) returns 0x01 to the KSPROPERTY_DVDCOPY_REGION property.

If the decoder provides a region, the system region change application will still function. It is used to change the system region, in case there are other decoders in the system. However, the Windows DVD playback will only function if the system region and the decoder region match.


Macrovision

Macrovision is supported by the last device handling the video data prior to leaving the computer. In the case of a video port connection to a video card, the video card and the navigator will handle all macrovision processing. The decoder is not involved. If the decoder has an NTSC output, macrovision encoding and macrovision compliance is the responsibility of the decoder card. The KSPROPERTY_COPY_MACROVISION property indicates the level of macrovision encoding on the media (levels zero to three). The decoder may use this information to enable or disable macrovision encoding on the NTSC output.


A/V Synchronization

Synchronization among several streams is defined in the WDM (kernel-mode) Streaming Reference. Since DVD inputs can be composed of two or more streams, those guidelines apply though synchronization is usually transparent in WDM drivers. However, programmers need to be aware of several factors effecting DVD streams:

  • Audio provides the master clock. The audio stream synthesizes the clock when there is no data. When audio data stops, the audio stream uses the system clock based on rate matching and clock frequency as returned by KeQueryPerformanceCounter. All other streams slave to audio.
  • SW Audio decoder must be supported in user mode. The clock forwarder DirectShow filter forwards the DirectShow clock to the mindriver. This is transparent to the minidriver.
  • The decoder should not use the time stamps in the primary elementary stream (PES) header.
  • SCRs are not used in synchronization.
  • The minidriver does not see time stamp discontinuities. The DVD navigator makes all time stamps contiguous.

If a decoder provides decode capabilities for both audio and video, the decoder may use hardware synchronization only when the audio stream is opened as the system master clock. If the audio stream is not the master clock, the video stream must synchronize video decode to the stream class master clock.


Broadcast Receiver Topology

A Broadcast Driver Architecture (BDA) receiver topology is an abstract representation of a filter graph. It is composed of a network of logical nodes, each of which performs an operation on a signal. Each node can be associated with an individual filter or combined with other nodes in a filter. The following sections discuss BDA receiver topology:

Functional Topology

Control Nodes, Filters and Hardware

Common Control Nodes and Filters


Functional Topology

To enable the building of broadcast receiver filter graphs in a way that works for all varieties of network types, and hardware and software implementations of, for example, tuners and decoders, Broadcast Architecture takes the familiar concept of a filter graph from DirectShow and abstracts it in the concept of a functional topology. A functional topology, like a filter graph, describes the series of transformations that occur on the incoming signal. However, unlike a filter graph, a functional topology does not describe any actual filters or software modules; or how an operation is implemented in software or hardware. Instead, it describes a configuration of abstract control nodes, each of which represents some common discrete operation.

Depending on the type of hardware and software components that are installed in a computer, the same functional topology can result in different filter graph configurations or actual topologies. For example, if a hardware vendor chooses to implement a tuner and a demodulator on the same circuit card, then KSProxy represents this hardware device in the filter graph as a single filter with two internal control nodes. A BDA device filter distinguishes itself from a more traditional DirectShow filter because a single BDA device filter can encapsulate as many hardware functions (control node implementations) as are built into a single functional module (for example, a circuit card or chip).

The function that a control node provides is uniquely identified by a GUID. For definitions of node description GUIDS, see the header file, bdamedia.h, in the DDK. During the graph-building process, the network provider filter uses these GUIDs to determine which nodes are useful in supporting a particular network type or tuning space. Filters in a broadcast receiver filter graph indicate, through a COM interface, the node types and the pin types they support. The Ring 0 drivers for filters indicate this same information through KS property sets. A filter contains data structures that describe its node types, pin types, and the ways in which pins and nodes can be connected. This information is called the filter's template topology. The following figure illustrates a template topology.

Template topology

The template topology in the preceding figure contains five different node types and four different pin types. The numbers of the pin and node types are arbitrary identifiers assigned by the filter. Each node type, however, is associated with a node description GUID that the network provider can examine. Each node type can occur only once in the topology, but since the filter arbitrarily assigns identifiers to node types, the same control node GUID could be associated with more than one node type. For example, node types that are identified with numbers 1 and 3 could represent the same control node GUID with two different output paths. A template topology must represent this scenario with two separate node types. The lines that connect these pin and node types in the template topology show the paths that the filter supports.

The network provider must examine this topology and determine the transformations that the filter performs on a signal in any particular graph. For more information on the data structures that describe the template topology, see Broadcast Driver Architecture Minidrivers.


Control Nodes, Filters and Hardware

BDA control nodes in BDA receiver topology can be separated into individual filters or combined in filters. In addition, BDA control nodes can be associated with hardware or be software-only components. The following sections describe:

Control Nodes

Combining Nodes in a Filter

Separating Nodes in Individual Filters

Control Nodes for Processing IP Data


Control Nodes

The following figure shows an example of one possible functional topology that receives digital broadcast content. It illustrates the operations necessary to:

  • tune and demodulate the signal.
  • capture and demultiplex the signal.
  • obtain electronic program guide (EPG) information.
  • obtain audio and video content.
  • obtain IP data.

Receiver topology

Note that some functions in receiver topology that acquire content, such as the tuner, are always associated with hardware. Other functions, such as content stream demultiplexing, can be performed with hardware or software components. Still others, such as the transport information filter (TIF) and network provider filter, are always software components.

The blocks in the preceding figure correspond to BDA control nodes. Each control node combines network and program-specific parameter data with the input signal, or signal component, using a standard algorithm. The result produces a new signal component that is useful to the control nodes connected immediately downstream.


Combining Nodes in a Filter

The following figure of a sample DirectShow filter graph shows one possible way in which the control nodes can be represented as filters in a filter graph. The network provider is always its own filter and precedes all other filters. In this sample, because the tuner and demodulator nodes are combined on the same circuit card, they appear as one filter. The capture filter follows the tuner/demodulator filter. For all of these filters so far, the actual internal and external connections in the filter match the control nodes. The next filter downstream is the MPEG-2 transport stream demultiplexer, which is represented by a single filter that exposes the packet identifier (PID) filters as shown in the figure in the Control Nodes section. The actual MPEG-2 transport stream demultiplexer filter reproduces the topology as many times as necessary to handle all the elementary streams.

Sample DirectShow Filter Graph with Tuner and Demodulator Combined in One Filter


Separating Nodes in Individual Filters

The following figure of a sample DirectShow filter graph shows another way in which the control nodes can be represented as filters in a filter graph. In this sample, the tuner and demodulator control nodes are separated into individual filters. All other control nodes are as described in the Combining Nodes in a Filter section.

Sample DirectShow Filter Graph with Separate Tuner and Demodulator Filters


Control Nodes for Processing IP Data

The following sequence and figure describe the data flow for IP data that is part of the received digital signal.

  1. The receiver device receives IP data and passes the IP data over the PC bus as part of the transport stream.
  2. The demultiplexer receives the transport stream and passes the private sections containing the IP data.
  3. The private sections are received by the multiprotocol encapsulation (MPE) parser, which removes the multiprotocol encapsulation and outputs the IP data. The MPE parser passes the IP data to the IPSink filter.
  4. The IPSink filter passes the IP data through a private interface to the broadcast NDISIP miniport driver.
  5. The NDISIP miniport driver is installed as a virtual NDIS miniport. The NDISIP miniport driver sends the IP data to NDIS.
  6. NDIS propagates the IP data through TCP/IP and Windows Sockets (WinSock) as it would for any other NDIS adapter.

IP data flow


Common Control Nodes and Filters

The types of control nodes and filters that are shown in the figures in the Control Nodes, Filters and Hardware section are common to the reception of digital satellite, terrestrial, and cable broadcasts. However, you can create other node types and filters for a wide variety of broadcast media and devices as well. It is important to remember that each control node need not correspond to a single BDA device filter. In some cases, a single BDA device filter can encapsulate more than one control node.

The following list describes control nodes and filters that are commonly found in Broadcast Architecture:

Network Provider
A network provider filter (or network provider) routes a digital television signal to and through BDA devices. A variety of broadcast providers currently transmit digital television signals over three basic network types—satellite, cable and antenna. These digital signals are transmitted in formats defined by multiple standards, including ATSC, DVB-S, DVB-C, and DVB-T. BDA devices receive and manage these digital signals.

A network provider:

  • is the source filter in a filter graph, although no data actually passes through it.
  • exists for each network type or can be created for a new network type.
  • participates in the graph building process.
  • communicates with other filters in the graph through property and method sets of BDA minidrivers that initialized such filters.

Each network provider can build a different graph configuration for its associated network type. Applications pass tune requests to a network provider, which in turn passes the information to a BDA minidriver. See the Broadcast Architecture section of the Platform SDK documentation for more information.

Tuner
This control node filters the particular frequency that carries the transport stream. It can appear inside a filter by itself or together with other control nodes.
Demodulator
A control node that translates the analog signal into a digital bit stream. It can appear inside a filter by itself or together with other control nodes.
Capture
A filter that moves the data into host memory.
PID Filter
A control node that selects one or more elementary data streams from the transport stream. This is the primary function of a demultiplexer. It can appear inside a filter by itself or together with other control nodes.
MPE Parser
A filter that parses IP data from a stream containing MPEG-2 private sections.
IPSink
A filter that accepts IP packets as data samples and forwards the data to the NDIS TCP/IP stack.
NDISIP
An NDIS miniport driver that acts as a receiver for a network adapter for the data that the IPSink filter passes.


Broadcast Driver Architecture Minidrivers

Broadcast Driver Architecture (BDA) minidrivers control hardware that performs the following operations:

  • tuning a digital broadcast signal
  • demodulating the digital signal
  • capturing frames of the digital signal
  • demultiplexing the signal into video, audio, and data streams

BDA minidrivers are AVStream minidrivers that run under the AVStream module in the kernel-streaming driver ks.sys. AVStream is a class driver that provides a unified kernel streaming class model for both audio and video minidrivers, and that supports use of COM objects without altering existing minidriver binaries. The AVStream class driver provides much of the default behavior required to make a minidriver's filter work as a WDM-CSA (kernel streaming) compliant filter. To simplify the task of writing BDA minidrivers, you can use the BDA support library (Bdasup.lib) of functions that is included in the DDK. This library provides extensive default handling for the BDA minidriver's property and method sets.

Typically, driver writers only have to code the appropriate static template structures, register them with the BDA support library, and then let the library provide default handling for all the properties and methods. In some instances, a BDA minidriver must intercept a property or method request and perform appropriate operations.

The following figure shows an architectural overview for BDA minidrivers:

BDA minidriver architecture

The following sections describe implementation details for a BDA minidriver, discuss details of some property and method sets, and contain sample code that shows how to intercept certain properties and methods:

Initializing a BDA Minidriver

Starting a BDA Minidriver

Creating Dispatch Tables

Defining Automation Tables

Initializing a BDA Filter

Determining BDA Device Topology

Mapping Connection Topology

Determining the Controlling Pin of a Node

Configuring a BDA Filter

Changing BDA Filter Properties

Accessing Frequency Properties of a BDA Node

Caching Pin Information for DirectShow


Initializing a BDA Minidriver

A BDA minidriver is initialized similarly to other AVStream minidrivers. The BDA minidriver's DriverEntry function calls the AVStream KsInitializeDriver function to initialize the BDA minidriver's driver object. In this call, the BDA minidriver passes a pointer to a KSDEVICE_DESCRIPTOR structure that specifies characteristics of the device, which can include:

  • A pointer to a KSDEVICE_DISPATCH structure that contains the dispatch table for the BDA device. At a minimum, the BDA minidriver should supply routines that create and start the device and specify these routines in the Add and Start members respectively of the KSDEVICE_DISPATCH structure. The BDA minidriver's create routine should allocate memory for the device class and reference the pointer to the KSDEVICE structure for the BDA device to this device class. The BDA minidriver's start routine should get information about the device from the registry, set information on the device, and then register a group of static template structures with the BDA support library. See Starting a BDA Minidriver for more information.
  • An array of KSFILTER_DESCRIPTOR structures for the individual filter types supported by this device. This structure type describes the characteristics of a filter created by a given filter factory. You should specify members of structures of this type in this array if you create your BDA minidriver so that it does not use the BDA support library (Bdasup.lib) to handle your BDA minidriver's property and method sets. If you create your BDA minidriver so that it uses the BDA support library, then your BDA minidriver should instead call the BdaCreateFilterFactory support function to add filter factory descriptors (KSFILTER_DESCRIPTOR structures) for your device. See Starting a BDA Minidriver for more information.

The following code snippet shows examples of an array of filter descriptors, a dispatch table for the BDA device, and the descriptor for the BDA device:

//
//  Array containing descriptors for all filter factories
//  available on the device.
//
//  Note!  Only used when dynamic topology is not used (that is,
//         only when filters and pins are fixed). Typically, this
//         is when the network provider is not present.
//
DEFINE_KSFILTER_DESCRIPTOR_TABLE(FilterDescriptors)
{
    &TemplateTunerFilterDescriptor
};
//
//  Device Dispatch Table
//
//  Lists the dispatch routines for the major events related to
//  the underlying device.
//
extern
const
KSDEVICE_DISPATCH
DeviceDispatch =
{
    CDevice::Create,    // Add
    CDevice::Start,     // Start
    NULL,               // PostStart
    NULL,               // QueryStop
    NULL,               // CancelStop
    NULL,               // Stop
    NULL,               // QueryRemove
    NULL,               // CancelRemove
    NULL,               // Remove
    NULL,               // QueryCapabilities
    NULL,               // SurpriseRemoval
    NULL,               // QueryPower
    NULL                // SetPower
};
//
//  Device Descriptor
//
//  Brings together the data structures that define the device and
//  the initial filter factories that can be created on it.
//  Note that because template topology structures are specific
//  to BDA, the device descriptor does not include them.
//  Note also that if BDA dynamic topology is used, the device
//  descriptor does not specify a list of filter factory descriptors.
//  If BDA dynamic topology is used, the BDA minidriver calls
//  BdaCreateFilterFactory to add filter factory descriptors.
extern
const
KSDEVICE_DESCRIPTOR
DeviceDescriptor =
{
    &DeviceDispatch,    // Dispatch
#ifdef DYNAMIC_TOPOLOGY // network provider is present
    0,    // FilterDescriptorsCount
    NULL, // FilterDescriptors
#else     // network provider is not present
    SIZEOF_ARRAY( FilterDescriptors), // FilterDescriptorsCount
    FilterDescriptors                 // FilterDescriptors
#endif // DYNAMIC_TOPOLOGY


Starting a BDA Minidriver

When a BDA device starts operating, the Plug and Play (PnP) Manager dispatches IRP_MN_START_DEVICE. The AVStream class in turn calls the start routine of the BDA minidriver associated with the BDA device. This start routine retrieves information about the device from the registry, sets information on the device, and then calls the BdaCreateFilterFactory support function to:

  • Create the filter factory for the device from the initial filter descriptor (KSFILTER_DESCRIPTOR) for the device. The initial filter descriptor references dispatch and automation tables for the filter and input pins. See Creating Dispatch Tables and Defining Automation Tables for more information.
  • Associate the filter factory with a BDA_FILTER_TEMPLATE structure. This structure references the template filter descriptor for the device and the list of possible pairs of input and output pins. This descriptor and list in turn reference:
    • Static template structures that a network provider can use to determine the topology of a BDA filter.
    • Nodes and pins for a BDA filter along with possible ways to connect the filter.
    • Routines that a network provider can use to create and close a filter instance.
    • Static template structures that a network provider can use to manipulate a BDA filter.
  • Register the static template structures that are specified by BDA_FILTER_TEMPLATE with the BDA support library so that the library can provide default handling for a BDA minidriver's properties and methods.

The following code snippet shows an example of an initial filter descriptor for the device that BdaCreateFilterFactory sets as the filter factory:

const KSFILTER_DESCRIPTOR    InitialTunerFilterDescriptor;
//
//  Filter Factory Descriptor for the tuner filter
//
//  This structure brings together all of the structures that define
//  the tuner filter instance as it appears when it is first created.
//  Note that not all template pin and node types are exposed as
//  pin and node factories when the filter instance is created.
//
DEFINE_KSFILTER_DESCRIPTOR(InitialTunerFilterDescriptor)
{
    &FilterDispatch,             // Table of dispatch routines
    &FilterAutomation,           // Table of properties and methods
    KSFILTER_DESCRIPTOR_VERSION, // Version
    0,                           // Flags
    &KSNAME_Filter,              // Reference Guid
    DEFINE_KSFILTER_PIN_DESCRIPTORS(InitialPinDescriptors),
                                   // PinDescriptorsCount
                                   // PinDescriptorSize
                                   // PinDescriptors
    DEFINE_KSFILTER_CATEGORY(KSCATEGORY_BDA_RECEIVER_COMPONENT),
                            // CategoriesCount
                            // Categories
    DEFINE_KSFILTER_NODE_DESCRIPTORS_NULL(NodeDescriptors),
                                    // NodeDescriptorsCount
                                    // NodeDescriptorSize
                                    // NodeDescriptors
    DEFINE_KSFILTER_DEFAULT_CONNECTIONS, // ConnectionsCount
                                         // Connections
    NULL                // ComponentId
};

The following code snippet shows an example of an array of initial pin descriptors that are exposed by an initialized filter. The network provider initializes a filter using such an array before the network provider configures that filter. However, when configuring an initialized filter, the network provider selects pins that are referenced in the pointer to the filter descriptor member of the BDA_FILTER_TEMPLATE structure. See Configuring a BDA Filter for more information.

//
//  Initial Pin Descriptors
//
//  This data structure defines the pins that will appear on the
//  filter when it is first created.
//
const
KSPIN_DESCRIPTOR_EX
InitialPinDescriptors[] =
{
    //  Antenna Pin
    //
    {
        &AntennaPinDispatch,
        &AntennaAutomation,   // AntennaPinAutomation
        {
            0,  // Interfaces
            NULL,
            0,  // Mediums
            NULL,
            SIZEOF_ARRAY(AntennaPinRanges),
            AntennaPinRanges,
            KSPIN_DATAFLOW_IN,
            KSPIN_COMMUNICATION_BOTH,
            NULL,   // Name
            NULL,   // Category
            0
        },
        KSPIN_FLAG_DO_NOT_USE_STANDARD_TRANSPORT |
        KSPIN_FLAG_FRAMES_NOT_REQUIRED_FOR_PROCESSING |
        KSPIN_FLAG_FIXED_FORMAT,
        1,      // InstancesPossible
        0,      // InstancesNecessary
        NULL,   // Allocator Framing
        NULL    // PinIntersectHandler
    }
};

Note that an initialized filter must have one or more input pins exposed so that the Microsoft® DirectShow® IFilterMapper2 or IFilterMapper interface can locate that filter. See the Microsoft Windows Platform SDK documentation for information about these DirectShow interfaces.

The following code snippet shows examples of a BDA_FILTER_TEMPLATE structure and related structures and arrays:

const KSFILTER_DESCRIPTOR  TemplateTunerFilterDescriptor;
const BDA_PIN_PAIRING  *TemplateTunerPinPairings;
//
//  BDA Template Topology Descriptor for the filter factory.
//
//  This structure defines the pin and node types that the network
//  provider can create on the filter and how they are arranged.
//
const
BDA_FILTER_TEMPLATE
TunerBdaFilterTemplate =
{
    &TemplateTunerFilterDescriptor,
    SIZEOF_ARRAY(TemplateTunerPinPairings),
    TemplateTunerPinPairings
};
//
//  Filter Factory Descriptor for the tuner filter template topology
//
//  This structure brings together all of the structures that define
//  the topologies that the tuner filter can assume as a result of
//  pin factory and topology creation methods.
//
DEFINE_KSFILTER_DESCRIPTOR(TemplateTunerFilterDescriptor)
{
    &FilterDispatch,             // Table of dispatch routines
    &FilterAutomation,           // Table of properties and methods
    KSFILTER_DESCRIPTOR_VERSION, // Version
    0,                           // Flags
    &KSNAME_Filter,              // Reference Guid
    DEFINE_KSFILTER_PIN_DESCRIPTORS(TemplatePinDescriptors),
                                   // PinDescriptorsCount
                                   // PinDescriptorSize
                                   // PinDescriptors
    DEFINE_KSFILTER_CATEGORY(KSCATEGORY_BDA_RECEIVER_COMPONENT),
                            // CategoriesCount
                            // Categories
    DEFINE_KSFILTER_NODE_DESCRIPTORS(NodeDescriptors),
                                    // NodeDescriptorsCount
                                    // NodeDescriptorSize
                                    // NodeDescriptors
    DEFINE_KSFILTER_CONNECTIONS(TemplateTunerConnections),
                               // ConnectionsCount
                               // Connections
    NULL                // ComponentId
};
//
//  Lists how pairs of input and output pins are configured.
//
//  Values given to the BDA_PIN_PAIRING structures in the list inform
//  the network provider which nodes get duplicated when more than one
//  output pin type is connected to a single input pin type or when
//  more that one input pin type is connected to a single output pin
//  type. Also, informs of the joints array.
//
const
BDA_PIN_PAIRING TemplateTunerPinPairings[] =
{
    //  Antenna to Transport Topology Joints
    //
    {
        0,  // ulInputPin
        1,  // ulOutputPin
        1,  // ulcMaxInputsPerOutput
        1,  // ulcMinInputsPerOutput
        1,  // ulcMaxOutputsPerInput
        1,  // ulcMinOutputsPerInput
        SIZEOF_ARRAY(AntennaTransportJoints),   // ulcTopologyJoints
        AntennaTransportJoints                  // pTopologyJoints
    }
};


Creating Dispatch Tables

You must create a filter dispatch table for a filter descriptor (KSFILTER_DESCRIPTOR) of a BDA minidriver so that the network provider filter can open and initialize an instance of the filter and later release the filter instance. You must also create a pin dispatch table for each pin descriptor (KSPIN_DESCRIPTOR_EX) in the array of pin types that are available in the filter's template topology. The network provider filter uses a pin dispatch table to open and initialize a pin and later release the pin. The following code snippet shows examples of filter and pin dispatch tables:

//
//  Filter Dispatch Table
//
//  Lists the dispatch routines for major events at the filter
//  level.
//
const
KSFILTER_DISPATCH
FilterDispatch =
{
    CFilter::Create,        // Create
    CFilter::FilterClose,   // Close
    NULL,                   // Process
    NULL                    // Reset
};

//
//  Input Pin Dispatch Table
//  Lists the dispatch routines for major events at the pin level.
//
const
KSPIN_DISPATCH
AntennaPinDispatch =
{
    CAntennaPin::PinCreate,         // Create
    CAntennaPin::PinClose,          // Close
    NULL,                           // Process signal data
    NULL,                           // Reset
    NULL,                           // SetDataFormat
    CAntennaPin::PinSetDeviceState, // SetDeviceState
    NULL,                           // Connect
    NULL,                           // Disconnect
    NULL,                           // Clock
    NULL                            // Allocator
};


Defining Automation Tables

An automation table for a filter, pin, or node is what describes the properties and methods supported by the filter, pin, or node. If a BDA minidriver supplies a property or method handler that is already implemented by AVStream, the BDA minidriver's implementation supersedes AVStream's.

A BDA minidriver should define arrays of property and method sets and then define automation tables for those set arrays so that the minidriver can automatically process requests. See the Determining BDA Device Topology section for an example of how the minidriver also defines a property set to which this section refers.

The following code snippet shows examples of filter automation tables and arrays of property and method sets:

//
//  Filter Level Property Set supported
//
//  This array defines a property set supported by the
//  filter that is exposed by the minidriver.
//
DEFINE_KSPROPERTY_SET_TABLE(FilterPropertySets)
{
    DEFINE_KSPROPERTY_SET
    (
        &KSPROPSETID_BdaTopology,                   // Set
        SIZEOF_ARRAY(FilterTopologyProperties),     // PropertiesCount
        FilterTopologyProperties,                   // PropertyItems
        0,                                          // FastIoCount
        NULL                                        // FastIoTable
    )
};
//
//  Filter Level Method Sets supported
//
//  This array defines method sets supported by the
//  filter that is exposed by the minidriver.
//
DEFINE_KSMETHOD_SET_TABLE(FilterMethodSets)
{
    DEFINE_KSMETHOD_SET
    (
        &KSMETHODSETID_BdaChangeSync,               // Set
        SIZEOF_ARRAY(BdaChangeSyncMethods),         // PropertiesCount
        BdaChangeSyncMethods,                       // PropertyItems
        0,                                          // FastIoCount
        NULL                                        // FastIoTable
    ),
    DEFINE_KSMETHOD_SET
    (
        &KSMETHODSETID_BdaDeviceConfiguration,      // Set
        SIZEOF_ARRAY(BdaDeviceConfigurationMethods),// PropertiesCount
        BdaDeviceConfigurationMethods,              // PropertyItems
        0,                                          // FastIoCount
        NULL                                        // FastIoTable
    )
};
//
//  Filter Automation Table
//
//  Lists all arrays of property and method sets for the filter that
//  is exposed by the minidriver.
//
DEFINE_KSAUTOMATION_TABLE(FilterAutomation) {
    DEFINE_KSAUTOMATION_PROPERTIES(FilterPropertySets),
    DEFINE_KSAUTOMATION_METHODS(FilterMethodSets),
    DEFINE_KSAUTOMATION_EVENTS_NULL
};

The following code snippet shows an example of a node automation table and an array of property sets:

//
//  RF tuner node property set supported
//
//  This array defines a property set supported by the
//  RF Tuner Node associated with the antenna input pin.
//
DEFINE_KSPROPERTY_SET_TABLE(RFNodePropertySets)
{
    DEFINE_KSPROPERTY_SET
    (
        &KSPROPSETID_BdaFrequencyFilter,            // Set
        SIZEOF_ARRAY(RFNodeFrequencyProperties),    // PropertiesCount
        RFNodeFrequencyProperties,                  // PropertyItems
        0,                                          // FastIoCount
        NULL                                        // FastIoTable
    )
};
//
//  Radio frequency tuner node automation table
//
//
DEFINE_KSAUTOMATION_TABLE(RFTunerNodeAutomation) {
    DEFINE_KSAUTOMATION_PROPERTIES( RFNodePropertySets),
    DEFINE_KSAUTOMATION_METHODS_NULL,
    DEFINE_KSAUTOMATION_EVENTS_NULL
};


Initializing a BDA Filter

A network provider filter uses the create dispatch routine of the BDA device's initial filter descriptor to create an initial filter instance of the BDA device when the network provider creates a filter graph. This initial filter descriptor was set as a filter factory and associated with the BDA filter template for the BDA device when the BDA device started. The initial filter instance that is created should expose at least one input. Typically, the initial filter instance exposes an input pin for each possible input pin in the initial filter descriptor but exposes no output pins. See Starting a BDA Minidriver and Creating Dispatch Tables for more information.

The BDA filter's create routine should allocate memory for its filter object, should set member variables for the filter object, and then should call the BdaInitFilter support function to initialize the filter instance. In this call, the BDA filter's create routine passes a pointer to the KSFILTER structure for the initial filter to create and a pointer to the BDA_FILTER_TEMPLATE structure that describes possibilities for the filter's template topology for the initial filter instance.


Determining BDA Device Topology

A BDA device topology is composed of a connected network of nodes, each of which represent some transformation on a signal. Nodes can be grouped arbitrarily among different filters. This arbitrary grouping provides hardware vendors with a certain freedom in how they implement their hardware and drivers so that such hardware and drivers work in a generic way with the network providers for the different types of networks they wish to support.

For this arbitrary grouping architecture to work, the network provider must be able to query filters as to what kind of transformations those filters perform on a signal (that is, what types of node networks the filter can support). The underlying Ring 0 minidriver for a filter conveys a picture of its supported node networks to the network provider through the KSPROPSETID_BdaTopology property set.

When determining the template topology for a filter, the network provider iterates lists of node types and pin types and queries each node and pin for its capabilities. The network provider uses the following properties of KSPROPSETID_BdaTopology to determine the template topology for the filter:

  • KSPROPERTY_BDA_NODE_TYPES

    Node types represent possible functional nodes within the filter. The KSPROPERTY_BDA_NODE_TYPES property returns a list of all node types that are provided by a filter instance of the BDA minidriver. The minidriver assigns arbitrary values to identify node types. Typically, the minidriver uses the index of each element in the list of the minidriver's node types as the value for each node type. The BDA minidriver assigns each node type a node description GUID. Description GUIDs for node types that the network provider currently supports are defined in bdamedia.h. This node description indicates to the network provider what the node does. In a template topology, a node type can occur only once. However, more than one node of a specific type may have the same node description GUID. This allows a specific signal transformation to occur in more than one place in the filter's topology while allowing the network provider to identify a single topology node unambiguously.

  • KSPROPERTY_BDA_PIN_TYPES

    Pin types represent possible connections to other filters in the graph. The KSPROPERTY_BDA_PIN_TYPES property returns a list of all pin types that can be created on the filter. In a template topology, a pin type can occur only once.

  • KSPROPERTY_BDA_TEMPLATE_CONNECTIONS

    The KSPROPERTY_BDA_TEMPLATE_CONNECTIONS property returns an array that represents all the possible connections between node types and pin types that can be configured on the filter. See Mapping Connection Topology for more information.

When a filter instance is first created and added to the graph, it typically has input pins but no output pins. To create output pins, the network provider first uses the KSPROPSETID_BdaTopology properties to determine what operations the filter can perform. From these properties, the network provider determines which operations it requires the filter to perform for a particular filter graph. The network provider then uses the KSMETHODSETID_BdaDeviceConfiguration method set to create output pins matching a particular pin type and create the internal topology, which is the actual hardware path, between those pins and the input pins. See Configuring a BDA Filter for more information.

The following code snippet shows how to define functions that are exported by the BDA support library as dispatch routines for the KSPROPSETID_BdaTopology property set:

//
//  KSPROPSETID_BdaTopology property set
//
//  Defines the dispatch routines for the filter level
//  topology properties
//
DEFINE_KSPROPERTY_TABLE(FilterTopologyProperties)
{
    DEFINE_KSPROPERTY_ITEM_BDA_NODE_TYPES(
        BdaPropertyNodeTypes,
        NULL
        ),
    DEFINE_KSPROPERTY_ITEM_BDA_PIN_TYPES(
        BdaPropertyPinTypes,
        NULL
        ),
    DEFINE_KSPROPERTY_ITEM_BDA_TEMPLATE_CONNECTIONS(
        BdaPropertyTemplateConnections,
        NULL
        ),
    DEFINE_KSPROPERTY_ITEM_BDA_CONTROLLING_PIN_ID(
        BdaPropertyGetControllingPinId,
        NULL
        )
};


Mapping Connection Topology

In order for the BDA support library to provide properties and methods to applications in Ring 3 on behalf of a BDA minidriver, the BDA minidriver must provide a mapping of its connection topology to the BDA support library. The BDA minidriver previously provided this mapping when it passed an array of BDA_TEMPLATE_CONNECTION structures to the support library in an array of KSTOPOLOGY_CONNECTION structures in its BdaCreateFilterFactory function call. See Starting a BDA Minidriver for more information. This array provides a representation of all the possible connections between node and pin types that can be made within a filter or between a filter and adjoining filters.

The network provider filter can subsequently make a KSPROPERTY_BDA_TEMPLATE_CONNECTIONS property request of the KSPROPSETID_BdaTopology property set on a filter instance of the BDA minidriver to retrieve the minidriver's connection topology. The BDA minidriver in turn calls the BdaPropertyTemplateConnections support function, which returns the list of the filter's template connections (BDA_TEMPLATE_CONNECTION structures) in an array of KSTOPOLOGY_CONNECTION structures. The members of a BDA_TEMPLATE_CONNECTION structure identify the following pairs of node and pin types of a connection:

  • node and pin types where the connection begins
  • node and pin types where the connection ends

Setting the node type to a value of –1 indicates that the connection begins or ends at a pin of either an upstream or downstream filter respectively. Otherwise, the value of the node type corresponds to the index of the element in the zero-based array of internal node types. This array is an array of KSNODE_DESCRIPTOR structures. The value of the pin type corresponds to the index of the element in the zero-based array of pin types that are available in the template filter descriptor for the BDA minidriver. This array is an array of KSPIN_DESCRIPTOR_EX structures.

The following code snippet shows example arrays of node types and pin types that are available in the template filter descriptor for the BDA minidriver:

//
//  Template Node Descriptors
//
//  This array describes all Node Types available in the template
//  topology of the filter.
//
const
KSNODE_DESCRIPTOR
NodeDescriptors[] =
{
    {   // 0 node type
        &RFTunerNodeAutomation,// PKSAUTOMATION_TABLE AutomationTable;
        &KSNODE_BDA_RF_TUNER,  // Type
        NULL                   // Name
    },
    {   // 1 node type
        &VSB8DemodulatorNodeAutomation, // PKSAUTOMATION_TABLE
                                        // AutomationTable;
        &KSNODE_BDA_8VSB_DEMODULATOR,   // Type
        NULL                            // Name
    }
};
//
//  Template Pin Descriptors
//
//  This data structure defines the pin types available in the filters
//  template topology. These structures will be used to create a
//  pin factory ID for a pin type when BdaMethodCreatePin is called.
//
const
KSPIN_DESCRIPTOR_EX
TemplatePinDescriptors[] =
{
    //  Antenna Pin
    //  0 pin type
    {
        &AntennaPinDispatch,
        &AntennaAutomation,   // AntennaPinAutomation
        {
            0,  // Interfaces
            NULL,
            0,  // Mediums
            NULL,
            SIZEOF_ARRAY(AntennaPinRanges),
            AntennaPinRanges,
            KSPIN_DATAFLOW_IN,
            KSPIN_COMMUNICATION_BOTH,
            NULL,   // Name
            NULL,   // Category
            0
        },
        KSPIN_FLAG_DO_NOT_USE_STANDARD_TRANSPORT |
        KSPIN_FLAG_FRAMES_NOT_REQUIRED_FOR_PROCESSING |
        KSPIN_FLAG_FIXED_FORMAT,
        1,      // InstancesPossible
        0,      // InstancesNecessary
        NULL,   // Allocator Framing
        NULL    // PinIntersectHandler
    },

    //  Tranport Pin
    //  1 pin type
    {
        &TransportPinDispatch,
        &TransportAutomation,   // TransportPinAutomation
        {
            0,  // Interfaces
            NULL,
            1,  // Mediums
            &TransportPinMedium,
            SIZEOF_ARRAY(TransportPinRanges),
            TransportPinRanges,
            KSPIN_DATAFLOW_OUT,
            KSPIN_COMMUNICATION_BOTH,
            (GUID *) &PINNAME_BDA_TRANSPORT,   // Name
            (GUID *) &PINNAME_BDA_TRANSPORT,   // Category
            0
        },
        KSPIN_FLAG_DO_NOT_USE_STANDARD_TRANSPORT |
        KSPIN_FLAG_FRAMES_NOT_REQUIRED_FOR_PROCESSING |
        KSPIN_FLAG_FIXED_FORMAT,
        1,
        1,      // InstancesNecessary
        NULL,   // Allocator Framing
        NULL    // PinIntersectHandler
    }
};

The following code snippet shows examples of arrays of template connections and joints:

//
//  BDA Template Topology Connections
//
//  Lists the possible connections between pin types and
//  node types. This structure along with the BDA_FILTER_TEMPLATE,
//  KSFILTER_DESCRIPTOR, and BDA_PIN_PAIRING structures
//  describe how topologies are created in the filter.
//
const
KSTOPOLOGY_CONNECTION TemplateTunerConnections[] =
{
    { -1,  0,  0,  0}, // from upstream filter to 0 pin of 0 node
    {  0,  1,  1,  0}, // from 1 pin of 0 node to 0 pin of 1 node
    {  1,  1,  -1, 1}, // from 1 pin of 1 node to downstream filter
};
//
//  Lists the template joints between antenna (input) and transport
//  (output) pin types. Values given to joints correspond to indexes
//  of elements in the preceding KSTOPOLOGY_CONNECTION array.
//
//  For this template topology, the RF node (0) belongs to the antenna
//  pin and the 8VSB demodulator node (1) belongs to the transport pin
//
const
ULONG   AntennaTransportJoints[] =
{
    1  // Second element in the preceding KSTOPOLOGY_CONNECTION array.
};


Determining the Controlling Pin of a Node

Unlike filters and pins, nodes do not have an associated file handle by which applications in Ring 3 can access them. Because nodes are internal components within a filter, they exist somewhere between the filter's input and output pins. The network provider must determine which filter pin to use, then use the pin to access a node. This filter pin is called the controlling pin for that node. To determine the controlling pin for each node in the BDA template connection list of a filter, the network provider queries the KSPROPERTY_BDA_CONTROLLING_PIN_ID property of the KSPROPSETID_BdaTopology property set. The BDA minidriver in turn calls the BdaPropertyGetControllingPinId support function for each node. In this call, the minidriver passes a pointer to a KSP_BDA_NODE_PIN structure. This structure identifies the property request to retrieve the controlling pin for a specific node type and a pair of the filter's input and output pins. The BDA support library returns the identifier of the controlling pin for the node type.

A BDA minidriver does not typically intercept the KSPROPERTY_BDA_CONTROLLING_PIN_ID property. The minidriver automatically dispatches the BdaPropertyGetControllingPinId support function from the KSPROPSETID_BdaTopology property set. See Determining BDA Device Topology for more information.

The support library is able to do all the work of determining the identifier of the controlling pin because the BDA minidriver provided the support library with a pointer to the BDA_FILTER_TEMPLATE structure when the BDA minidriver started operating. See Starting a BDA Minidriver for more information. A BDA minidriver informs the BDA support library how to determine controlling pins through information contained in BDA_FILTER_TEMPLATE. This information includes:

  • An array of connections. This array is a KSTOPOLOGY_CONNECTION array that provides a representation of all the possible connections between node and pin types that can be made within a filter or between a filter and adjoining filters. See Mapping Connection Topology for more information on the KSTOPOLOGY_CONNECTION array.
  • An array of joint values. A joint is a point in the topology where one input splits into one or more paths to different outputs, or one or more inputs join into a single output path. The value given to a joint corresponds to the index of an element in the KSTOPOLOGY_CONNECTION array. Most topologies will have only one joint.
  • An array of BDA_PIN_PAIRING structures. These structures identify input and output pin types, the maximum number of input-type instances that can be created on the filter, and the maximum number of output-type instances that can be created on the filter. These structures also contain a pointer to the array of joint values between the input and output pins. See Starting a BDA Minidriver for more information on the BDA_PIN_PAIRING array.

The following figure shows how the support library determines the filter pin that controls a specific node:

Determination of controlling pin


Configuring a BDA Filter

A BDA minidriver processes method requests of the KSMETHODSETID_BdaDeviceConfiguration method set to configure a filter instance for the minidriver in the current filter graph.

In the following code snippet, two of the methods of the KSMETHODSETID_BdaDeviceConfiguration method set are dispatched directly to the BDA support library and the remaining method is first intercepted by the BDA minidriver before dispatching to the BDA support library.

//
//  BDA Device Configuration Method Set
//
//  Defines the dispatch routines for the filter level
//  topology configuration methods
//
DEFINE_KSMETHOD_TABLE(BdaDeviceConfigurationMethods)
{
    DEFINE_KSMETHOD_ITEM_BDA_CREATE_PIN_FACTORY(
        BdaMethodCreatePin,
        NULL
        ),
    DEFINE_KSMETHOD_ITEM_BDA_DELETE_PIN_FACTORY(
        BdaMethodDeletePin,
        NULL
        ),
    DEFINE_KSMETHOD_ITEM_BDA_CREATE_TOPOLOGY(
        CFilter::CreateTopology,
        NULL
        )
};
/*
** CreateTopology()
**
** Keeps track of topology association between input and output pins
**
*/
NTSTATUS
CFilter::
CreateTopology(
    IN PIRP         pIrp,
    IN PKSMETHOD    pKSMethod,
    PVOID           pvIgnored
    )
{
    NTSTATUS            Status = STATUS_SUCCESS;
    CFilter *           pFilter;
    ULONG               ulPinType;
    PKSFILTER           pKSFilter;

    ASSERT( pIrp);
    ASSERT( pKSMethod);

    //  Obtain a "this" pointer for the method.
    //
    //  Because this function is called directly from the property
    //  dispatch table, get pointer to the underlying object.
    //
    pFilter = FilterFromIRP( pIrp);
    ASSERT( pFilter);
    if (!pFilter)
    {
        Status = STATUS_INVALID_PARAMETER;
        goto errExit;
    }

    //  Let the BDA support library create the standard topology.
    //  It will also validate the method, instance count, etc.
    //
    Status = BdaMethodCreateTopology( pIrp, pKSMethod, pvIgnored);
    if (Status != STATUS_SUCCESS)
    {
        goto errExit;
    }

    //  This is where the filter can keep track of associated pins.
    //
errExit:
    return Status;
}

The KSMETHOD_BDA_CREATE_TOPOLOGY method request calls the minidriver's CFilter::CreateTopology method. This method calls the BDA support library function BdaMethodCreateTopology to create a topology between filter pins. This function actually creates a topology structure in Ring 3, which reflects, for other property sets, the known connections of the filter. A BDA minidriver should intercept the KSMETHOD_BDA_CREATE_TOPOLOGY method request as shown in the preceding code snippet if that minidriver must send special instructions to the hardware when connecting particular pin types--for example, if the BDA device performs hardware demultiplexing and creates an arbitrary number of output pins fanned off from a single input pin.


Changing BDA Filter Properties

Because multiple instances of an application that views media broadcasts can run simultaneously on a system, you should write a BDA minidriver to accommodate multiple instances of a filter. Each filter instance can contain different information. For example, one instance of a tuner filter can contain a request to tune to channel 5, while another instance can contain a request to tune to channel 8. As control transitions from one instance to another, the BDA minidriver must instruct the underlying tuning device to change the way resources are configured. A BDA minidriver processes method requests of the KSMETHODSETID_BdaChangeSync method set to coordinate a list of property requests on one the minidriver's filter instances.

The primary purpose of the KSMETHODSETID_BdaChangeSync method set is to provide trigger points at which the underlying minidriver for a filter can acquire and release resources from the minidriver's device object. The minidriver must coordinate these trigger points with the filter's transition to and from a stopped state. For example, if the filter is in a stopped state, the minidriver should assign new resources to the filter but not acquire those resources whenever the network provider specifies to commit BDA topology changes. When the filter subsequently transitions out of its stopped state, the minidriver should then attempt to acquire those resources from the underlying device.

On the other hand, if the filter is already active, the minidriver should attempt to acquire new resources from the underlying device whenever the network provider specifies to commit BDA topology changes. Only one instance of the filter can be active—in the running state and holding the same resources—at any given time. When a filter transitions to the stopped state, it should therefore release all its resources, including those resources that were allocated for any of its pins, so that the resources are available to another filter graph that transitions to the running state.

Typically, a BDA minidriver's filter object intercepts and supplies methods for the methods of the KSMETHODSETID_BdaChangeSync method set. For example, the minidriver supplies methods for starting, checking, and committing filter changes and for getting the change state of a filter. In addition, the following minidriver-supplied methods should call the corresponding BDA support library functions to synchronize changes on the structures that the minidriver previously registered with the BDA support library:

  • Start-changes method calls the BdaStartChanges function.
  • Check-changes method calls the BdaCheckChanges function.
  • Commit-changes method calls the BdaCommitChanges function.
  • Get-changed-state method calls the BdaGetChangeState function.

The following code snippet shows how to intercept method requests of the KSMETHODSETID_BdaChangeSync method set using an internal method:

//
//  BDA Change Sync Method Set
//
//  Defines the dispatch routines for the filter level
//  Change Sync methods
//
DEFINE_KSMETHOD_TABLE(BdaChangeSyncMethods)
{
    DEFINE_KSMETHOD_ITEM_BDA_START_CHANGES(
        CFilter::StartChanges,
        NULL
        ),
    DEFINE_KSMETHOD_ITEM_BDA_CHECK_CHANGES(
        CFilter::CheckChanges,
        NULL
        ),
    DEFINE_KSMETHOD_ITEM_BDA_COMMIT_CHANGES(
        CFilter::CommitChanges,
        NULL
        ),
    DEFINE_KSMETHOD_ITEM_BDA_GET_CHANGE_STATE(
        CFilter::GetChangeState,
        NULL
        )
};

The following code snippet shows how the internal start-changes method in a BDA minidriver resets pending resource changes after the minidriver calls the BdaStartChanges support function to initiate the setting of new BDA topology changes:

//
// StartChanges ()
//
//    Puts the filter into change state.  All changes to BDA topology
//    and properties changed after this will be in effect only after
//    CommitChanges.
//
NTSTATUS
CFilter::
StartChanges(
    IN PIRP         pIrp,
    IN PKSMETHOD    pKSMethod,
    OPTIONAL PVOID  pvIgnored
    )
{
    NTSTATUS        Status = STATUS_SUCCESS;
    CFilter *       pFilter;

    ASSERT( pIrp);
    ASSERT( pKSMethod);

    // Obtain a "this" pointer for the method.
    //
    // Because this function is called directly from the property
    // dispatch table, must get pointer to the underlying object.
    //
    pFilter = FilterFromIRP( pIrp);
    ASSERT( pFilter);
    if (!pFilter)
    {
        Status = STATUS_INVALID_PARAMETER;
        goto errExit;
    }

    //  Reset any pending BDA topology changes.
    //
    Status = BdaStartChanges( pIrp);
    if (!NT_SUCCESS( Status))
    {
        goto errExit;
    }

    //  Reset any pending resource changes.
    //
    pFilter->m_NewTunerResource = pFilter->m_CurTunerResource;
    pFilter->m_BdaChangeState = BDA_CHANGES_COMPLETE;

errExit:
    return Status;
}


Accessing Frequency Properties of a BDA Node

A network provider uses the KSPROPSETID_BdaFrequencyFilter property set to control an RF tuner node in a BDA filter topology. For example, the network provider uses this property set to inform the tuner node how to tune the RF signal.

In the following code snippet, the controlling pin of the tuner node in the BDA minidriver intercepts and supplies methods for one property of the KSPROPSETID_BdaFrequencyFilter property set:

//
//  BDA RF Tune Frequency Filter
//
//  Defines the dispatch routines for the Frequency Filter Properties
//  on the RF Tuner Node
//
DEFINE_KSPROPERTY_TABLE(RFNodeFrequencyProperties)
{
    DEFINE_KSPROPERTY_ITEM_BDA_RF_TUNER_FREQUENCY(
        CAntennaPin::GetCenterFrequency,
        CAntennaPin::PutCenterFrequency
        ),
    DEFINE_KSPROPERTY_ITEM_BDA_RF_TUNER_POLARITY(
        NULL, NULL
        ),
    DEFINE_KSPROPERTY_ITEM_BDA_RF_TUNER_RANGE(
        NULL, NULL
        ),
    DEFINE_KSPROPERTY_ITEM_BDA_RF_TUNER_TRANSPONDER(
        NULL, NULL
        ),
};


Caching Pin Information for DirectShow

An application can use the DirectShow IFilterMapper2 interface to automatically search for filters that meet certain criteria. This application can use the list of proposed filters that IFilterMapper2 returns to automatically build filter graphs with filters that receive and render television signals. To quickly find filters that meet the criteria specified, IFilterMapper2 uses information about a filter and its pins that was previously entered into a cache. The discussion in the following paragraphs refers to this cache as the pin data cache.

The information contained in the pin data cache includes a list of mediums and media types for each pin that the filter can expose. IFilterMapper2 uses this cache information to determine whether a possible filter can connect to a pin on a filter that is already in the graph. Making this determination eliminates the overhead of creating an instance of a filter only to determine that connecting to the filter is prevented because a medium or media type does not match. If the pin data cache for a filter is not up-to-date, a filter could be wrongly eliminated as a candidate for connection in a filter graph.

Whenever a BDA minidriver determines that its pin data cache that DirectShow uses is not up-to-date, that minidriver must update the pin data cache so that pin information for BDA filter instances of the minidriver's BDA component is accurately exposed in a filter graph. A BDA minidriver updates DirectShow's pin data cache as described in the following scenarios:

  • A BDA minidriver may or may not be required to update DirectShow's pin data cache when the minidriver initially creates BDA filter instances depending on how that minidriver presents BDA filters as DirectShow filters in user mode. A BDA minidriver's information (INF) file specifies the mechanism that the minidriver uses to present its BDA filters as DirectShow filters.

    BDA minidrivers typically use the kernel-streaming (KS) proxy module (Ksproxy.ax) to present their BDA filters as DirectShow filters. KS proxy automatically updates DirectShow's pin data cache to expose pin information for BDA filters whenever instances of those filters are initially created. Therefore, BDA minidrivers that use KS proxy are not required to perform any action to update DirectShow's pin data cache when they initially create instances of filters. If a BDA filter is exposed to user mode through KS proxy, the cached information automatically includes the mediums and media types for the pin factories that exist on the filter instance immediately after the filter's create dispatch routine returns.

    Some BDA minidrivers do not use KS proxy to present their BDA filters as DirectShow filters. For example, BDA receiver minidrivers that implement BDA filters to receive or process analog television signals use either the KSTVTune.ax or KSXBar.ax modules to present these BDA filters as DirectShow filters. Because these modules do not use standard KS proxy interface methods to update DirectShow's pin data cache, BDA minidrivers for these types of BDA filters must update DirectShow's pin data cache when those minidrivers initially create instances of filters. To ensure that DirectShow's pin data cache is updated when instances of these filters are created, a BDA minidriver calls the BdaFilterFactoryUpdateCacheData function immediately after calling the BdaInitFilter function inside the implementation of the filter's create dispatch routine. In this call, the minidriver passes pin information to update all initial pins on the filter.

  • Pins can be created on a BDA filter dynamically after the filter's create dispatch routine completes. If the initially created instance of a BDA filter does not expose instances of all the pins that are listed in the BDA filter's template topology (BDA_FILTER_TEMPLATE), then the BDA minidriver must call BdaFilterFactoryUpdateCacheData to force information about all pins listed in the filter's template topology.

Note Updating DirectShow's pin data cache has significant overhead because it touches and modifies the registry. In addition, updating DirectShow's pin data cache impacts the amount of time required for DirectShow to automatically build filter graphs. Therefore, a BDA minidriver should call BdaFilterFactoryUpdateCacheData for all possible pins only when it determines that its pin data cache that DirectShow uses is not up-to-date.

If possible, a BDA minidriver should call BdaFilterFactoryUpdateCacheData whenever a driver, firmware, or hardware update has occurred.


Building and Testing BDA Drivers

The following sections describe how to build and test a Broadcast Driver Architecture (BDA) driver:

Building BDA Drivers

Testing BDA Drivers Using BDA Filters


Building BDA Drivers

You can use the DDK to build your Broadcast Driver Architecture (BDA) driver. To build a BDA driver, open a DDK command window, change to the appropriate BDA driver's source code subdirectory of the DDK's main source directory, and use the DDK's build command. The build command gets instructions on how to build the BDA driver from the Sources file that resides in the BDA driver's source code subdirectory.

For more information on the Build utility, the DDK's build environments, the macros and environment variables which control the Build utility, and the files that are required to build your BDA driver, see Using the Build Utility and Build Utility Reference.

The following list contains the macro names to use in a BDA Sources file and discusses how to use them to build your BDA driver:

TARGETNAME
Set to the BDA driver's name so that when the DDK builds the driver it is built with this name. The following code provides an example:
TARGETNAME=BDAsampl  # DDK builds the driver as BDAsampl.sys
TARGETPATH
Set the destination directory for the built driver. Note that depending on whether your build environment is "free" or "checked", you can use the BUILD_ALT_DIR variable to append "fre" or "chk" to the \obj subdirectory that the build command creates under the directory containing the Sources file. The following code provides an example:
TARGETPATH=obj$(BUILD_ALT_DIR) # built driver in \objfre or \objchk
TARGETTYPE
Set the type of file to build as a driver (as opposed to, for example, a program or DLL) as shown in the following code:
TARGETTYPE=DRIVER  # DDK builds the driver as *.sys
TARGETLIBS
Point to the library files to which the BDA driver's sample source must link. A BDA driver must at least link to the libraries shown in the following code example:
TARGETLIBS=..\..\..\..\lib\ks.lib \
           ..\..\..\..\lib\ksguid.lib \
           ..\..\..\..\lib\BdaSup.lib
INCLUDES
Point to a list of paths to search for the header files that the BDA driver's sample source requires in order to compile. The following code provides an example:
INCLUDES=..\..\..\..\inc; \
    $(DDK_INC_PATH)\wdm;
SOURCES
Point to a list of source files that must be compiled to build the driver. The files must reside in the directory in which the Sources file resides. The following code provides an example:
SOURCES= \
    ObjDesc.cpp     \
    inpin.cpp     \
    outpin.cpp    \
    Filter.cpp      \
    Device.cpp      \
    bdaguid.c       \
    BDAsampl.rc
DRIVERTYPE
Set type of driver to WDM as shown in the following code:
DRIVERTYPE=WDM
USE_MAPSYM
Generate .sym symbol files, in addition to the .pdb symbol files. These files map names to addresses. Setting this macro is required to debug on Windows 98/Me platforms. Set this macro as shown in the following example:
USE_MAPSYM=1


Testing BDA Drivers Using BDA Filters

You can use the DirectShow Filter Graph Editor (Graphedt.exe) to insert a DirectShow filter instance of your BDA component in a filter graph so that you can test your component. You can obtain the Graph Editor from the DDK.

You can use the Graph Editor to perform rudimentary tests of a BDA component, such as, connecting pins that are exposed by a filter instance of the component to other pins of filter types in the graph.

To use the Graph Editor to thoroughly test functionality of your BDA component, you must build a filter graph that starts with a BDA network provider filter, contains a filter instance of your BDA component, and is rendered, at least, through a demultiplexer filter (packet identifier (PID) filter) to a transport information filter (TIF). The biggest problem with using the Graph Editor is that there is no dedicated application to submit requests via the ITuner interface that the network provider filter implements. However, the network provider filter has associated property pages that provide some limited ability to exercise the ITuner interface.


Introduction to AV/C Drivers

Microsoft supports the Audio Video Control (AV/C) protocol, which is built upon the IEC-61883 standard.

The AV/C protocol driver Microsoft supplies is called avc.sys. It is a functional driver that supports the AV/C subunit protocol. The AV/C subunit protocol is a method for issuing commands and sending responses from subunits on devicew such as MiniDV camcorders and digital-VHS tape deck. For example, a MiniDV camcorder has two subunits, a camera subunit (the imaging device) and a tape subunit (storage of the media-signal). A digital-VHS tape deck has a tape subunit and a tuner subunit. These subunits can be controlled externally from a computer if the camcorder is connected to a PC through the IEEE 1394 serial bus and appropriate "subunit drivers" are written for the hardware. These drivers are WDM drivers that connect to the AV/C system-supplied driver (avc.sys) to provide that control.

An AV/C unit, such as a Digital Video camcorder (DV) or Digital VHS (DVHS) tape deck, can stream isochronous data over the IEEE 1394 bus using the IEC 61883 specifications. When an AV/C device is connected to a computer with the Microsoft® Windows® XP operating system, it is enumerated as an AV/C device by two lower protocol drivers: avc.sys and 61883.sys. Drivers of these devices are called AV/C subunit drivers. These drivers are written as Windows Driver Model (WDM) architecture and Kernel Streaming (KS) mini drivers.

An AV/C subunit driver in general supports:

  • Device control based on a device type defined by http://www.1394ta.org/Technology/Specifications/index.htm, (www.1394ta.org), and
  • Connection management and streaming media signal over the 1394 bus based on http://www.iec.ch/.

An AV/C subunit driver can use services provided by the AV/C protocol driver (avc.sys) to perform device control, and use the 61883 protocol (61883.sys) driver to provide connection management and data streaming.

See IEC-61883 Client Drivers for more information about the 61883 protocol.

Microsoft also supplies an optional streaming filter driver that aids in the processing of two specific data formats: standard definition digital video (SDDV, or the 61883-2 specification) and MPEG2TS (or the 61883-4 specification).

The optional AV/C Streaming filter driver is called avcstrm.sys. It resides between individual subunit drivers and functional driver, avc.sys.

The following sections include the design guides for the AV/C Protocol driver and AV/C Streaming lower filter driver:

AV/C Protocol and Subunit Driver Support

AV/C Streaming

The following sections include the enumerations and structures used by AV/C and AV/C Streaming:

AV/C Enumerations

AV/C Structures

AV/C Streaming Enumerations

AV/C Streaming Structures


AV/C Protocol and Subunit Driver Support

This section describes the Microsoft implementation of the Audio/Video Control (AV/C) protocol and provides guidelines for developing subunit minidrivers. Examples of AV/C subunit types include TV tuners, tape, disk and cameras.

The AV/C protocol is built upon the IEEE 1394 bus and 61883 protocol. For more information about these topics, see The IEEE 1394 Driver Stack and IEC-61883 Client Drivers. Subunit drivers are WDM drivers that are either stream class-based (Kernel Streaming 1.0) or AVStream class-based (Kernel Streaming 2.0). See AVStream Overview for further information on AVStream Minidrivers. The AVStream class is the preferred interface to use.

See Kernel Streaming Overview and Stream Minidriver Design Guide for more information about the stream class and streaming drivers.

This section includes:

Introduction to AV/C

Peer Device Stack

Virtual Device Stack

AV/C Requests

AV/C Appendices


Introduction to AV/C

Microsoft supports the AV/C protocol (as defined by the 1394 Trade Association) and subunit enumeration through the avc.sys Windows Driver Model (WDM) device driver.

Avc.sys may be loaded in one of two manners. If a physical AV/C device is connected to the PC, an instance of avc.sys is loaded and the GUID_AVC_CLASS device interface is registered. This is the "peer" mode of avc.sys.

Alternatively, AV/C subunit drivers may expose PC hardware as valid AV/C targets. The instance of avc.sys loaded to support this mode registers the GUID_VIRTUAL_AVC_CLASS device interface. This is the "virtual" mode of avc.sys.

An instance of the avc.sys driver is inserted on the driver stack above the 61883.sys and 1394bus.sys drivers for every AV/C unit enumerated on the 1394 bus. Enumeration occurs, for example, after a 1394 bus reset, or after a MiniDV camcorder has been plugged into the bus and its power turned on.

Peer subunit drivers are WDM drivers for subunits in AV/C devices such as MiniDV camcorders and Digital-VHS tape decks, attached to the PC through an IEEE 1394 serial bus connection.

Virtual subunit drivers are WDM drivers that expose PC hardware, such as hard drives and web cameras as valid AV/C subunits which may be targeted for AV/C commands and responses.

Using standard AV/C unit and subunit commands, the avc.sys driver discovers the active subunits in the AV/C unit for which it was loaded, and using standard PnP facilities, causes subunit drivers to load for each physical subunit. These subunit drivers may be generic for the type of subunit (for example, a class driver), or may be a vendor-specific implementation. The subunit driver selection is based on the device ID generated from the unit information of the device, in combination with the type and ID of the subunit. The template for an AV/C device ID is:

AVC\<Vendor>&<Model>&<SubunitType>&<SubunitID>

For more information about subunit enumeration and the format of the device IDs associated with an AV/C device, see Peer Subunit Enumeration.

The subunit drivers access and control the physical 1394 AV/C subunits through an I/O control (IOCTL) interface with avc.sys. Avc.sys takes care of the AV/C command and response protocol, including all interaction with the 61883 Function Control Protocol (FCP). This does not prevent the subunit driver from communicating and directly accessing certain 61883.sys functionality when necessary. This may become necessary, when, for example, the subunit driver represents a subunit that uses a stream format not supported by Microsoft.

Any peer subunit driver can cause the computer to become a peer device (command target), simply by issuing an IOCTL to avc.sys requesting incoming requests. This means that a peer subunit device driver on the PC can actually receive requests from the device for which it has been loaded. This does not mean that a tape subunit will be sending tape subunit commands to the PC, but instead permits support for such things as CCM (Connection and Compatibility Management, http://www.1394ta.org) and DTCP (Digital Transmission Content Protection, http://www.dtcp.com).

Microsoft provides an optional filter driver to handle format-aware streaming services. For more information, see AV/C Streaming.

The 1394 driver stack may also be configured to expose computer functionality to other devices on the 1394 bus through the 1394, 61883 and AV/C protocol drivers. This is known as virtual 1394 device support. For more information, see Virtual Device Stack.

From information stored in the registry, or through direct program control, the avc.sys driver enumerates the active virtual subunits in the computer's AV/C unit, and using standard PnP facilities, causes virtual subunit drivers to load. For example, a webcam attached to the computer might have a virtual subunit driver loaded to enable it to be used as a camera subunit. A hard drive may have a virtual subunit driver loaded to enable it to be used as a storage device (like a tape subunit in a DV camcorder). The virtual subunit drivers respond to external AV/C control, status, and notification commands through the IOCTL_AVC_CLASS interface with avc.sys.

The registry is the persistent way to save virtual device configuration, but virtual device configuration is always carried out programmatically. That is, although the registry holds the persistent information, that information should not be placed in the registry directly. Instead, it can be done through a combination of I/O control codes (IOCTLs) under software control and INF AddReg directives under setup control.

Virtual 1394 device support permits the following:

  • Implementing devices through software that do not yet exist in hardware (excellent for prototyping new hardware, or getting a jump on implementing new subunit drivers).
  • Exposing computer resources as AV/C subunits.
  • Implementing extensions to target functionality such as Authentication and Key Exchange (AKE) and Connection and Compatibility Management (CCM) by third parties on the computer.
  • Developing automated test suites for non-virtual (peer) subunit drivers, without requiring the presence of actual hardware. This permits testing of boundary conditions not otherwise possible with the range of hardware devices available.

Features of the avc.sys driver include:

  • AV/C Peer Subunit Enumeration
  • AV/C command arbitration
  • Interim response handling (see AV/C Requests)
  • Plug control and enumeration within the WDM Kernel Streaming framework (see Connection Management)
  • AV/C Virtual Subunit Enumeration
  • Peer device functionality

For the full details of the 1394 AV/C protocols, see the specifications at http://www.1394ta.org/

Note For the sake of readability, the code samples provided in Allocating and Initializing an IRB and Setting Up the IRP for AV/C Processing do not include error handling.


Peer Device Stack

The peer device stack (as opposed to the Virtual Device Stack) consists of the set of WDM drivers loaded to represent devices visible on the 1394 bus, and controlled from the computer. All external device control is initiated through this stack. The peer device stack also can contain WDM filter drivers that provide vendor or device specific target AV/C functionality. For more information on AV/C target functionality, see Peer Stack as Command Target.


Peer Driver Enumeration

As AV/C devices are added and removed from the 1394 bus, drivers are loaded and unloaded by the Plug and Play Manager. The following diagram shows the driver stack.

Peer AV/C Device Stack

At the bottom of the stack are 1394ohci.sys and 1394bus.sys. These drivers provide the basic 1394 infrastructure support. There are instances of these drivers for each 1394 adapter in the system.

Next in the stack is 61883.sys. This protocol driver provides the IEEE 61883-1 connection management protocol (CMP), common isochronous packet (CIP), and function control protocol (FCP) support, as well as PnP enumeration of devices for each command transaction set (CTS). There is an instance of this driver for each 61883-enabled node on the 1394 bus.

Next in the stack is avc.sys. This driver provides AV/C protocol support, PnP enumeration of devices for each AV/C subunit, and plug connection management and control.

Next in the stack are the subunit drivers. This is the level where all of the unique AV/C subunit functionality is implemented. There is generally an instance of a particular subunit driver for each subunit type and ID within that type.

For more information about the mechanism for subunit enumeration and the format of the device IDs associated with an AV/C device, see Peer Subunit Enumeration.


Peer Subunit Enumeration

This section describes the mechanism for subunit enumeration and the format of the device IDs associated with an AV/C device.

Avc.sys creates one device object for each AV/C subunit present on a device. When the 1394 bus is reset, for example, when a device on the bus is added or removed, avc.sys re-enumerates all the subunits on the device. This allows the device to reconfigure itself (that is, add or remove subunits) without having to reload avc.sys. Subunit drivers are added and removed only as the corresponding physical subunits are added and removed. Avc.sys cannot distinguish between multiple subunits of the same type, so addition and removal of these subunits loads and unloads the drivers with the highest subunit IDs.

Each device object has one or two hardware IDs and multiple compatible IDs. One or more of these IDs are specified in the INF file associated with a subunit driver and are used to find suitable drivers to load for each subunit. For more information about implementing subunit INF files, see INF File Sections and Directives.

A typical AV/C subunit hardware ID is formatted as follows:

AVC\<Vendor ID>&<Model ID>&<Subunit Type>&<Subunit ID>

All numeric fields in device and compatible IDs are tagged as follows (with exceptions as noted):

  • Vendor - "VEN_" (unless vendor text is available)
  • Model - "MOD_" (unless model text is available)
  • SubunitType - "TYP_"
  • SubunitID - "ID_"

The individual elements of the device ID are as follows:

Element | Description
Vendor ID | If vendor name text is available in the Configuration ROM, it is used. Otherwise, the unique module vendor ID is used. This numeric value is obtained from the Module_Vendor_ID entry in the Configuration ROM root_directory. The Command and Status Register (CSR) Architecture Key for this immediate entry is 0316 (hexadecimal), and the remaining 24 bits are the numeric module vendor ID.
Model ID | The best available model information, giving precedence to the unit directory entries. First in order of preference is the model text from the Configuration ROM unit directory. Second in preference is the numeric ID from the unit directory. Third is the model text from the root directory. Last is the model ID from the root directory.
Subunit Type | If available, the subunit type is extracted from the subunit address and converted to a string of hexadecimal values for each byte (there are multiple bytes only if the subunit type has been extended). In any case, the initial byte is extracted from the five most significant bits of the address byte, as described in section 5.3.3 of the AV/C Digital Interface Command Set General Specification, Rev 3.0. For a list of the supported subunit types, see the AvcSubunitType enumeration.
Subunit ID | If the subunit type is available, the subunit ID also is available. When querying the AV/C Unit for its subunit information, it is given a count of the subunits for each type. This zero-based count is used to create a device ID for each subunit. The subunit address specification also allows for the subunit ID to be extended, but this aspect is hidden from the subunit driver (and from you, the author of the INF file). The zero-based instance number is used in all cases. For example, if the Subunit ID is extended to support 270 subunits, the 270th subunit has a subunit ID of '10D' (269 decimal).

The hardware and compatible IDs generated by avc.sys for standard devices (that is, devices that report one or more subunits) are as follows:

  • Hardware IDs
AVC\<Vendor>&<Model>&<SubunitType>&<SubunitID>
Most complete, but this is seldom used in an inf file because the subunit ID (the last ampersand-delimited portion of the device ID) is not usually of interest.
AVC\<Vendor>&<Model>&<SubunitType>
Preferred for use in inf files, especially when there can be multiple subunits of the same type on the device (and those subunits share the same driver). Can be used by hardware vendors or Microsoft, depending upon who provides the device driver.
  • Compatible IDs
AVC\<Vendor>&<SubunitType>
Used for vendor-specific subunit drivers. Generally used only in Microsoft-provided inf files to load Microsoft-provided subunit drivers for a well defined class of subunits.
AVC\<SubunitType>
Used for AV/C subunit-specific drivers. Generally used only in Microsoft-provided inf files to load Microsoft-provided subunit drivers for a well defined class of subunits.
  • The following compatible IDs are not provided:
AVC\<SubunitType>&<SubunitID>
Nothing ID-specific can be done without a Vendor_ID.
AVC\<Vendor>
A vendor-specific "universal" subunit driver should include supported AVC\<Vendor>&<SubunitType> entries in its INF file.
AVC\GENERIC
A "universal" subunit driver should include supported AVC/<SubunitType> entries in its INF file.

The device and compatible IDs generated by avc.sys for camcorder devices (devices with one camera subunit, one tape recorder/player subunit, and any number of other subunits) are as follows:

  • Hardware ID
AVC\<Vendor>&<Model>&CAMCORDER
Used in vendor-specific INF files if msdv.sys is not to be loaded.
  • Compatible IDs
AVC\<Vendor>&CAMCORDER
Used in msdv.inf to load msdv.sys.
AVC\CAMCORDER
Used in msdv.inf to load msdv.sys.
  • The following Compatible IDs are not provided:
AVC\<Vendor>
A vendor-specific "universal" subunit driver should include supported AVC\<Vendor>&CAMCORDER entries in its INF file.
AVC\GENERIC
A "universal" subunit driver should include supported AVC\CAMCORDER entries in its INF file.

Note: Post-Windows XP Beta 2, a DV-specific discovery mechanism was included in avc.sys, so any DV tape device (including camcorders) will have "&DV" appended to the Hardware ID and Compatible IDs. This may be disabled by unsetting bit 3 the AvcFlags registry value (AvcFlags & 0x8). This detection is enabled by default for all Tape devices.

The device and compatible IDs generated by avc.sys for non-standard and non-compliant devices are only exposed if the AvcFlags registry value has bit 1 set (AvcFlags & 0x2). The correct way to set this flag is through the INF file for the device. The IDs are as follows:

  • Hardware ID
AVC\<Vendor>&<Model>
Used in vendor-specific INF files to load drivers for non-standard and non-compliant devices.
  • Compatible IDs
AVC\<Vendor>
A vendor-specific "universal" unit driver includes this entry in its INF file.
AVC\GENERIC
A "universal" unit driver includes this entry in its INF file.

The following are samples of device and compatible IDs:

The company Fabrikam, Inc. has a vendor ID of 0x50F2

A Fabrikam, Inc. DV Camcorder (camcorder is special case):

- Camcorder device ID:

AVC\VEN_12345&MOD_0&CAMCORDER&DV (may be used by Fabrikam, Inc. to override msdv.sys)

- Camcorder compatible IDs:

AVC\VEN_12345&CAMCORDER&DV (the style of ID that would be used in msdv.inf to load msdv.sys)
AVC\CAMCORDER&DV

A Fabrikam, Inc. DVHS VCR with one tuner subunit and one tape recorder/player subunit:

- Tape recorder/player subunit device ID:

AVC\VEN_50F2&MOD_0&TYP_4&ID_0

- Tape recorder/player subunit compatible IDs (a tape recorder/player—audio or video—subunit type = 4):

AVC\VEN_50F2&MOD_0&TYP_4
AVC\VEN_50F2&TYP_4 (used in msdv.inf to load msdv.sys)
AVC\TYP_4

- Tuner subunit device ID:

AVC\VEN_50F2&MOD_0&TYP_5&ID_0

- Tuner subunit compatible IDs (a tuner subunit type = 5):

AVC\VEN_50F2&MOD_0&TYP_5
AVC\VEN_50F2&TYP_5
AVC\TYP_5


Driver Frameworks

All subunit drivers are written as WDM architecture drivers. However, being a WDM driver does not provide the standard mechanism necessary for applications to interact with and control your driver. The recommended approach for control of these types of devices at the application level is by DirectShow filters and filter graphs. The KS Proxy mechanism of DirectShow provides a generic filter (ksproxy.ax), a standard way to represent properties of the device (KS property sets), and a standard way to represent events that the device might trigger (KS event sets).

The KS proxy filter can be extended with "proxy plug-ins," either provided by Microsoft or by each vendor, that allow COM interfaces to hide the low-level details of the KS property and event sets. However, a general way to directly access the property and event sets remains available. The IAMExtTransport interface (for tape subunits) is an example of an interface implemented in a proxy plug-in. The plug-in can also include property pages, providing a UI for control of the device. These property pages are generally used for testing purposes (through GraphEdit or AMCap), rather than for end-user device interaction. The plug-in is associated with your subunit driver by the INF file.

The KS Proxy mechanism is supported at the driver level by one of two driver frameworks. The first framework is called the Stream Class architecture. A subunit driver within this framework is referred to as a Streaming Minidriver. The next generation framework, which is recommended for all new driver development, is AV Streaming. Drivers using either framework can coexist, even within the same AV/C unit. For more information, see AVStream Overview.


Peer Stack as Command Target

The peer stack can include support for AV/C target functionality. In the context of the peer stack, target functionality is limited to the support of AV/C unit commands. Subunit drivers can perform this function, but for devices with multiple subunits, a WDM filter driver is the preferred method. The computer is only exposed as an AV/C target if an upper driver (subunit or filter driver) registers to receive incoming requests (through AVC_FUNCTION_GET_REQUEST). For more information about AV/C unit commands, see AVC_FUNCTION.

When enabled as an AV/C target, avc.sys provides implementations of UNIT_INFO and SUBUNIT_INFO commands. For more information, see The Unit Command Extension Driver.

Driver loading is based on device IDs, therefore unit functionality may be loaded selectively on a device or vendor-specific basis. The virtual stack supports this mechanism generically (not in a device-specific way). For more information, see Peer Subunit Enumeration and Virtual Device Stack.

Through this peer stack extension mechanism, third party vendors can independently implement value-add features such as 5C, as well as extensions to the AV/C implementation provided by Microsoft.


Virtual Device Stack

The virtual device stack (as opposed to the Peer Device Stack) consists of the set of WDM drivers loaded to represent capabilities and resources of the computer as targets on the 1394 bus. A virtual AV/C device stack is instantiated if any of the computer's resources are to be exposed as AV/C units or subunits. Even if the peer device stack is used to implement device-specific unit extensions, any unhandled unit commands, as well as all incoming subunit commands, are delivered to the virtual device stack.

The virtual stack cannot send commands directly to external devices. The peer stack provides this functionality. However, any client of the virtual stack can use IOCTL_AVC_CLASS functions to discover and reference peer instances of avc.sys. For more information, see AVC_FUNCTION_FIND_PEER_DO and AVC_FUNCTION_PEER_DO_LIST.


Virtual Driver Enumeration

As virtual AV/C devices are added and removed from the system, drivers are loaded and unloaded by the Plug and Play Manager. The following diagram illustrates the driver stack.

Virtual AV/C Device Stack

At the bottom of the stack are 1394ohci.sys and 1394bus.sys. These drivers provide the basic 1394 infrastructure support. There are instances of these drivers for each 1394 adapter in the system.

Next in the stack is 61883.sys. This protocol driver provides the IEEE 61883-1 connection management protocol (CMP), common isochronous packet (CIP), and function control protocol (FCP) support, as well as PnP enumeration of devices for each command transaction set (CTS). Instances of this driver are loaded as a result of I/O control codes delivered to 1394 bus, or from registry entries managed by 1394 bus.

Next in the stack is avc.sys. This driver provides AV/C protocol support and PnP enumeration of devices for each virtual AV/C subunit. Instances of this device are loaded from registry entries managed by 61883.sys (using the default virtual device ID in 61883.inf or by providing a custom INFfile).

Next in the stack are the virtual subunit drivers. This is the level where all of the unique AV/C subunit functionality is implemented. There is an instance of a particular subunit driver for each virtual subunit.

For more information about the mechanism for subunit enumeration and the format of the device IDs associated with an AV/C device, see Virtual Subunit Enumeration.


Virtual Subunit Enumeration

This section describes the mechanism for subunit enumeration and the format of the device IDs associated with a virtual AV/C device.

Avc.sys creates one device object for each virtual AV/C subunit. Examples of virtual AV/C subunits would include a hard disk or a web camera. As each virtual subunit is added and removed, avc.sys triggers a 1394 bus reset. This allows other devices on the 1394 bus to detect the new functionality being exposed by the computer. Subunit drivers are added based on the avc.sys instance's registry settings, and can be added and removed at run time by I/O control (IOCTL) requests. Avc.sys cannot distinguish between multiple subunits of the same type, so addition and removal of these subunits loads and unloads the drivers with the highest subunit IDs.

Each virtual device object has a Hardware ID and multiple Compatible IDs. These are PnP device IDs, and are used to find suitable drivers to load for each subunit. For more information about implementing subunit INF files, see INF File Sections and Directives.

The device and compatible IDs for virtual subunit drivers are as follows:

  • Device ID
VAVC\VEN_*\MOD_*\TYP_*\ID_*
  • Compatible IDs
VAVC\TYP_*\ID_*
VAVC\TYP_*
VAVC\GENERIC.

Note that * is the appropriate value in hex.

The VEN_ and MOD_ values are the same as specified in the INF file that caused the virtual instance of 61883.sys to load. The TYP_ and ID_ values are as specified when avc.sys is told to enumerate the device.

The enumeration of the device is accomplished through use of the IOCTL_AVC_UPDATE_VIRTUAL_SUBUNIT_INFO, IOCTL_AVC_REMOVE_VIRTUAL_SUBUNIT_INFO and IOCTL_AVC_BUS_RESET I/O control codes.

It is necessary to send the proper 1394 IOCTLs to begin the enumeration process. See IEEE1394_API_ADD_VIRTUAL_DEVICE and IEEE1394_API_REMOVE_VIRTUAL_DEVICE (subcommands of the IOCTL_IEEE1394_API_REQUEST IOCTL) for more information. The 61883.inf file already contains a device ID for this purpose: "V1394\A02D&10001", although a different ID may be provided in a custom inf file.

For a description of the mechanism and format of the device and compatible IDs, see Peer Subunit Enumeration.


Writing a Virtual Subunit Driver

A virtual subunit driver can be "thick" or "thin." The only requirement is that it be written as a WDM driver. A "thick" driver implements most, if not all, functionality of the virtual device. A "thin" driver provides a proxy interface to the virtual device functionality, which may be another driver or a user-mode component. The interface between user mode and the virtual subunit driver is implementation specific and may be accomplished through I/O control codes (IOCTLs), private interfaces (see IoRegisterDeviceInterface) or through Windows Management Instrumentation (WMI).

The IOCTL_AVC_CLASS function codes AVC_FUNCTION_GET_REQUEST and AVC_FUNCTION_SEND_RESPONSE are the key mechanisms by which the virtual subunit driver interacts with the rest of the virtual driver stack. A virtual subunit driver submits an AVC_FUNCTION_GET_REQUEST IRP in its IRP_MN_START_DEVICE handler (after completion by lower drivers). The completion routine for the AVC_FUNCTION_GET_REQUEST IRP is called each time a request for your subunit is received. The completion routine must send a response (by AVC_FUNCTION_SEND_RESPONSE with an asynchronous IRP) within 100ms (according to the AV/C protocol rules); it may use the AVC_COMMAND_IRB structure contained in the request to send the response. Then it must resubmit an AVC_FUNCTION_GET_REQUEST IRP before finally returning from the response's completion routine.


The Unit Command Extension Driver

If AV/C target functionality is enabled, avc.sys supports only SUBUNIT_INFO (0x31) and UNIT_INFO (0x30) opcodes directly. These opcodes are described in the AV/C Digital Interface Command Set General Specification, Rev 3.0.

In order to support additional unit commands, such as those for CCM or DTCP, avc.sys provides a "plug-in" extension mechanism. Any number of subunit or WDM filter drivers can register the unit opcodes they support through the AlternateOpcodes member of the AVC_COMMAND_IRB submitted through the AVC_FUNCTION_GET_REQUEST function. AlternateOpcodes is a counted byte array, with element 0 being the number of alternate opcodes in the remaining bytes. AlternateOpcodes is ignored when sending a response, so there is no need to hide the alternate opcodes when processing a unit request.

To use the built-in extension mechanism, specify the unit address (0xff) in the SubunitAddress member of the AVC_COMMAND_IRB structure. The SubunitAddress member is left alone in the case of unit commands (which means that the unit address you provide will still be there). The virtual subunit driver always is able to key off of the SubunitAddress member.


AV/C Requests

Subunit drivers communicate with avc.sys through the standard IRP-based request mechanism employed by all drivers based on the WDM architecture.

IOCTL_AVC_CLASS IRPs are sent by the internal I/O device control dispatch (IRP_MJ_INTERNAL_DEVICE_CONTROL). The IOCTL_AVC_CLASS control code is always accompanied by an I/O Request Block (IRB), which further describes the AV/C operation to perform. The IRB header includes a function number, which determines the structure of the rest of the IRB. The IRB structure and size varies according to the function.

All other I/O control codes supported by avc.sys, IOCTL_AVC_UPDATE_VIRTUAL_SUBUNIT_INFO, IOCTL_AVC_REMOVE_VIRTUAL_SUBUNIT_INFO, and IOCTL_AVC_BUS_RESET are sent by the standard I/O device control dispatch (IRP_MJ_DEVICE_CONTROL).

The primary AV/C function used by peer devices is AVC_FUNCTION_COMMAND, which corresponds with the AVC_COMMAND_IRB structure, and defines the mechanism for sending AV/C requests and receiving the associated AV/C responses. Many of the details of building AV/C commands are handled by avc.sys, but the subunit driver must provide the opcode and operands of each command.

The process for building and sending an AV/C command can vary depending upon the style of IRP handling or particular subunit constraints, but, in general, it is as follows:

To Build and Send an AV/C Command:

  1. Allocate and initialize an IRP appropriate for the number of drivers below your subunit driver (as specified in the parent driver's device object). See Allocating an IRP.
  2. Allocate an IRB (I/O Request Block) appropriate for the type of AV/C function desired, and fill in the block with the desired AV/C request parameters. See Allocating and Initializing an IRB.
  3. Set up the IRP with the appropriate function parameters. See Setting Up the IRP for AV/C Processing.
  4. Set an IO completion routine for the IRP, which at a minimum parses the response, but that may also free the IRP and IRB resources. See Creating the I/O Completion Routine.
  5. Submit the IRP to avc.sys (by calling IoCallDriver). See Submitting the IRP.
  6. Repeat Steps 1 through 5 as necessary.

Basic IRP processing allows for a lower driver to either complete the IRP synchronously (immediately), or defer its completion until later. When the operation is deferred, the IRP is marked "pending," and the lower driver returns STATUS_PENDING from its IOCTL dispatch routine, which comes back to the calling driver as the return code from IoCallDriver. Avc.sys translates the AV/C request/response protocol to this model.

Any status or inquiry request that results in an immediate response is fully complete during the span of the IoCallDriver invocation. An immediate response indicates that a response occurs within the 100ms AV/C response timeout constraint detailed in the AV/C specification. A notify request responds immediately only if there is an error condition. Some control and all notify requests acknowledge, but may not necessarily complete, the request in the 100ms timeframe. The acknowledgment is through an "interim" response, which is referred to in this documentation as Interim Processing. An Interim response results in IoCallDriver returning STATUS_PENDING. If this occurs, your driver's I/O completion routine is the point of notification when the request is satisfied.


Allocating an IRP

The style of IRP management you use influences how to obtain an IRP for use with avc.sys. Usually IoAllocateIrp is sufficient. Never call IoInitializeIrp on an IRP you allocated by IoAllocateIrp. If you are trying to reinitialize to reuse an IRP, call IoFreeIrp on the old IRP, and then IoAllocateIrp to get a new IRP.

Note that using ExAllocatePooland ExFreePool alone eventually fragments the non-paged pool, which decreases system throughput.

If you plan to allocate many IRPs simultaneously, the global resource used by IoAllocateIrp could be depleted, resulting in decreased system throughput. In this situation, you should either use a zone buffer, or a lookaside list to manage IRP storage.


Allocating and Initializing an IRB

The IRB is a block of data describing the operation to perform. Each function supported by avc.sys is associated with a specific IRB structure. The memory for the IRB must be allocated from non-paged pool. Just as with IRP allocation, there is a potential for pool fragmentation. This fragmentation problem can be avoided by using a zone buffer or, preferably, a lookaside list for IRB storage management. Once the memory has been allocated, fill in the parameters for the function according to its associated structure definition.

Following is a code sample showing how the AVC_COMMAND_IRB might be allocated and initialized for an AV/C control command consisting of a single operand byte:

    #include <avc.h>
    …
    PAVC_COMMAND_IRB  AvcIrb;
    …
    AvcIrb = ExAllocatePool(NonPagedPool, sizeof(AVC_COMMAND_IRB));
    …
    RtlZeroMemory(AvcIrb, sizeof(AVC_COMMAND_IRB));

#ifdef __cplusplus
    AvcIrb->Common.Function = AVC_FUNCTION_COMMAND;
#else
    AvcIrb->Function = AVC_FUNCTION_COMMAND;
#endif
    /*++ Do this to override the default timeout and retry values
    AvcIrb->TimeoutFlag = 1;
    AvcIrb->RetryFlag = 1;
    AvcIrb->Timeout.Quadpart = DEFAULT_AVC_TIMEOUT * 5;
    AvcIrb->Retries = 1;
    --*/
    AvcIrb->CommandType = AVC_CTYPE_CONTROL;
    AvcIrb->Opcode = Opcode;
    AvcIrb->OperandLength = 1;
    AvcIrb->Operand[0] = Operand;

For the list of available functions and their associated structure definitions, see AV/C Protocol Driver Function Codes, AV/C Structures and AV/C Enumerations.


Setting Up the IRP for AV/C Processing

Avc.sys receives the IRB and processes the request through the IRP allocated in Allocating and Initializing an IRB.

Following is a code sample showing how to set up the IRP:

    #include <avc.h>
    …
    PAVC_COMMAND_IRB  AvcIrb;
    PIRP Irp;
    PIO_STACK_LOCATION NextIrpStack;
    …
    AvcIrb = ExAllocatePool(NonPagedPool, sizeof(AVC_COMMAND_IRB));
    …
    Irp = IoAllocateIrp(DeviceExtension->ParentDeviceObject->StackSize, FALSE);
    …
    NextIrpStack = IoGetNextIrpStackLocation(Irp);
    NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
    NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_AVC_CLASS;
    NextIrpStack->Parameters.Others.Argument1 = AvcIrb;


Creating the I/O Completion Routine

Subunit drivers must allocate IRPs to communicate with avc.sys, therefore an I/O completion routine is required. The completion routine prevents the I/O Manager from continuing to process the IRP after the subunit's call to the lower driver completes. The I/O completion routine must always return STATUS_MORE_PROCESSING_REQUIRED. Beyond that requirement, the way your driver deals with its control flow and resource management is flexible.

When you set the IO completion routine, you can include a PVOID context parameter. This can be a pointer to anything you want, as long as the completion routine is written specifically to deal with it. If you are sure that the AV/C requests you make never involve interim processing (see AV/C Requests), then your completion routine can be very simple: use it to trigger a KSEVENT (passed as the PVOID context). The main code path that called IoCallDriver provides the storage for the event, and uses KeWaitForSingleObject to synchronize with the completion routine. The IRP and IRB are freed by the main code path.

If, however, you intend to make requests that could involve interim processing, the completion routine is responsible for handling the response and freeing the IRP and IRB resources. The main code path relinquishes all IRP processing responsibility to the completion routine.


Submitting the IRP

The IRP is submitted to the lower driver though the IoCallDriver routine. The avc.sys driver attempts to guarantee that an AV/C request is made, and at least an interim response received within the span of this call. The following table of return codes describe how the request was handled.

Return code | Description
STATUS_SUCCESS | The request was made, and a final response received within the bounds of the timeout and retry parameters. The AV/C response code must still be examined to determine the true result of the operation (STATUS_SUCCESS simply means that a round-trip request/response cycle was completed).
STATUS_TIMEOUT | The request was made, but no response was received before all timeout and retry processing was complete. The target device ignores requests if a previous request is still being processed. Some AV/C devices are non-compliant, and refuse to respond within the 100ms timeout, even after several successive attempts. The AVC_COMMAND_IRB structure permits the adjustment of the default Timeout and Retries members (100ms and 9, respectively), but these default settings have been sufficient for all known implementations.
STATUS_PENDING | The request was made, and an interim response was received. It is the responsibility of the completion routine to handle the final response and free the IRP and IRB resources.
STATUS_REQUEST_ABORTED | When submitting AV/C requests, immediately abort when the IRP completion status is STATUS_REQUEST_ABORTED.
STATUS_* | Any other return code indicates that an error occurred that was beyond the scope of the AV/C protocol.


Connection Management

The AV/C peer instance provides functions for 1394 (and AV/C subunit) plug connection and format management. Kernel Streaming (KS) pin format negotiation and pin connection mechanisms are translated to plug connections through avc.sys.

Currently, avc.sys does not support Connection and Compatibility Management (CCM) or asynchronous connections, although this functionality can be added to your subunit driver, or provided through a WDM filter driver.

Some key aspects of the architecture are:

  • 1394 and AV/C subunit plug connections are represented as KS pin connections on the computer.
  • 1394 serial bus plugs (input and output plugs) are directly represented as KS pins only when there is no internal subunit plug connection capability. In this case, there is one pin per 1394 serial bus plug.
  • There is a medium GUID representing 1394 serial bus connections.
  • Medium GUIDs for permanent internal AV/C unit and subunit connections are synthesized from the device unique ID and plug addresses.
  • There are new KSDATARANGE and KSDATAFORMAT extensions for AV/C connections.

The mediums and formats together help to determine whether a KS pin connection represents data to and from the computer, over the 1394 serial bus, or internal to a device.

To Initialize a Subunit Driver and Establish Pin Connections

  1. Submit an AVC_FUNCTION_GET_PIN_COUNT request. Use the resulting pin count in the remaining functions to indicate the pin (offsets from 0 to PinCount-1).
  2. For each pin, submit an AVC_FUNCTION_GET_PIN_DESCRIPTOR request. Use the returned KSPIN_DESCRIPTOR to complete the filter definition. Avc.sys fills in the MediumsCount, Mediums, DataFlow, and Communication members of KSPIN_DESCRIPTOR. The subunit driver is permitted to copy the KSPIN_DESCRIPTOR and override any of the members, although it is recommended that it leave the medium list intact (the list may contain GUIDs synthesized for permanent subunit plug connections).

    The pointers in the KSPIN_DESCRIPTOR structure are to paged pool that remains until the subunit driver's PDO is removed. Care must be exercised to not destroy the contents.

    The subunit driver is permitted to replace the pointer if it has something better to point to. However, it must not free these memory ranges. If using the AVStream KS framework (KS 2.0), the KsEdit routine deals with replacing memory references like this.

    Note that avc.sys does not fill in the KSPIN_DESCRIPTOR's Interfaces, DataRanges, Category, Name, or ConstrainedDataRanges members. A fully functional avcstrm.sys driver (or other lower filter driver associated with your subunit driver) might fill in the DataRanges (along with an IntersectHandler and optional Context). However, if the DataRanges are not specified when this function completes, it is the subunit's responsibility to provide them.

    Regardless of the origin of the DataRanges, each standard range must be paired with a duplicate range that has an AVCPRECONNECTINFO structure appended (using the appropriate specifier GUIDs) to support both device-to-pc and device-to-device connections. Avc.sys can be called upon to provide an AVCPRECONNECTINFO structure for each pin, through the AVC_FUNCTION_GET_CONNECTINFO request.

  3. The IntersectHandler routine (either the one supplied in the result of AVC_FUNCTION_GET_PIN_DESCRIPTOR, or one provided by your subunit driver) creates a DataFormat structure for a matching pair of DataRanges structures. For more information about data intersection, see Format Negotiation and Data Intersections. The DataFormat structure for matching AVCPRECONNECTINFO ranges has an AVCCONNECTINFO structure appended to it. This is a copy of the local pin's AVCPRECONNECTINFO structure with the Flags member replaced by the hPlug member. The hPlug member must remain NULL if the KSPIN_FLAG_AVC_PERMANENT bit is set. If the KSPIN_FLAG_AVC_PCRONLY or KSPIN_FLAG_AVC_FIXEDPCR bits were set in Flags, the UnitPlugNumber and DataFlow members would be used to obtain an hPlug handle from 61883. Any other combination of bits (or no bits) means that the hPlug can be obtained for any available plug number (using the DataFlow member to determine plug direction).

    The IntersectHandler routine must pass the resulting AVCCONNECTINFO structure down to avc.sys. This ensures that avc.sys can later make any necessary plug connections within the unit itself (for example, connections between unit input or output plugs with subunit destination or source plugs).

  4. Finally, when the data format is set on a pin (after format negotiation), the pin must examine the format for an AVCCONNECTINFO structure. If one is found, then the pin does not move data to or from the 1394 bus from or to the computer. Instead, it uses AVC_FUNCTION_SET_CONNECTINFO to send the AVCCONNECTINFO contents to a lower driver. Potentially, both the lower filter driver (for example, avcstrm.sys) and the avc.sys driver perform connection operations, but, at this point, the AVCCONNECTINFO contents only should be cached (no connection operations performed). The lower driver does not cache an AVCCONNECTINFO that it provided. In this way, only one pin makes hPlug connections between units. If there is no lower filter driver (avcstrm.sys), the subunit driver should decide whether or not to deliver the AVCCONNECTINFO to the lower driver. Avc.sys does not need to see AVCCONNECTINFO structures for plug control register (PCR) only connections.

    If the subunit is not using a lower filter driver for stream format management, the subunit driver is responsible for setting up 1394 serial bus plug connections. For more information, see AV/C Streaming.

    The subunit driver should cache the hPlug from the format to set up a peer-to-peer connection if:

    • The hPlug does not match the one you created.
    • The DeviceID does not match the one you received in AVCPRECONNECTINFO.
    • The DataFlow does not match the data flow of your pin.
  5. When pin connection resources are to be acquired, submit an AVC_FUNCTION_ACQUIRE request. The lower driver (or the subunit driver itself) uses any cached AVCCONNECTINFO to make the hPlug connections. The internal connections between subunit and unit plugs are made by avc.sys upon receiving the AVC_FUNCTION_ACQUIRE request, using the cached AVCCONNECTINFO. Avc.sys does not cache information, nor attempt internal plug connections, if it has no internal plug control or the connection is marked as permanent.
  6. When pin connection resources are to be released, submit an AVC_FUNCTION_RELEASE request. The lower driver and avc.sys keep any cached AVCCONNECTINFO, so that alternating acquire and release operations may be performed.
  7. Submit an AVC_FUNCTION_CLR_CONNECTINFO to remove the cached AVCCONNECTINFO data.

Note that the AVC_FUNCTION_SET_CONNECTINFO must be called once with the AVCCONNECTINFO created during data intersection (the local AVCCONNECTINFO), and once with the AVCCONNECTINFO passed when setting the format (the foreign AVCCONNECTINFO). For connections between subunits of different devices, a filter driver (for example, avcstrm.sys) caches the foreign information (the foreign hPlug), and avc.sys caches the local information. For connections between subunits within the same device, the filter driver does not cache any information, and avc.sys caches only the information for the foreign subunit. The filter driver must pass all AVC_FUNCTION_SET_CONNECTINFO requests down to avc.sys, so it can be shielded from the subunit plug connection decision-making.

The AV/C connection lock bit is set when making the connection. Output pins (source plugs) expose multiple pin instances allowing overlay connections (from the same output to an additional input). However, if this occurs, there is nothing that prevents a disconnect command from deleting all the existing connections. This is inherent in the AV/C specification. When overlaying connections, the subunit sends multiple AVC_FUNCTION_SET_CONNECTINFO and AVC_FUNCTION_ACQUIRE request pairs (without intervening AVC_FUNCTION_RELEASE requests). Furthermore, this same behavior may result when a second computer is introduced to the 1394 bus, or a second incompatible application is run on the same computer.

AV/C external plug connections are not directly supported by avc.sys, but avc.sys can still be used to establish internal connections between subunit plugs and external plugs by providing synthesized AVCCONNECTINFO structures. The subunit driver can create an AVCCONNECTINFO structure by using the AVC_FUNCTION_GET_UNIQUE_ID function code to fill in the DeviceID member, supplying the unit address (0xff) and the external plug number (plug number logical-ORed with 0x80) for the SubunitAddress and SubunitPlugNumber members, and supplying the correct data flow direction in DataFlow. The hPlug and UnitPlugNumber members should be set to NULL. The number of input and output external plugs can be detected through the AVC_FUNCTION_GET_EXT_PLUG_COUNTS function.

An approach that allows avc.sys to make the proper internal plug connections and exposes possible external plug connections to applications is to have filter factories for each possible external plug. The resulting filter instances would expose an appropriate input or output pin, which in turn would provide AVCCONNECTINFO structures.


AV/C Appendices

The AV/C appendices are broken down into the following parts:

AV/C Debug Output


AV/C Debug Output

The debug version of avc.sys permits the output of trace messages to a debug window. The "AvcDebugLevel" ULONG is a bitmap of possible trace levels. Each nibble represents a category of trace output. The default value is 0x00CCCCCC, which sets all message categories to ERROR and WARNING output levels. The best setting for monitoring AV/C command activity would be 0x000ECCCC (adds the TRACE class of messages to the AV/C category of output). To turn off all debug output, set all bits to zero. The bitmaps for each category are described below.

Generic Message Category

The GENERIC category covers all generic output. The most interesting class of output is FLOW, which when enabled will log a message at each function's entry and exit points. On Win9x systems, all TL_FLOW, and most TL_TRACE messages will go to the .ntkern circular buffer pool. To see these log entries, break into the debugger, type .ntkern, and select the 'D' option. Pressing the spacebar after pressing 'D' will continue dumping the buffer, one page at a time. Any other key will cancel the dump. To turn off the .ntkern logging and have the messages go to the standard debug output, you may set the ulind variable to 1 (default is 0), with the 'e ulind' debugger command.

Meaning | Value
TL_MASK | 0x0000000F
TL_FLOW | 0x00000001
TL_TRACE | 0x00000002
TL_WARNING | 0x00000004
TL_ERROR | 0x00000008

Plug and Play Message Category

The PNP category deals with all Plug and Play related output.

Meaning | Value
TL_PNP_MASK | 0x000000F0
TL_PNP_TRACE | 0x00000020
TL_PNP_WARNING | 0x00000040
TL_PNP_ERROR | 0x00000080

Power Management Message Category

The POWER category deals with all power management related output, including hibernation.

Meaning | Value
TL_POWER_MASK | 0x00000F00
TL_POWER_TRACE | 0x00000200
TL_POWER_WARNING | 0x00000400
TL_POWER_ERROR | 0x00000800

I/O Message Category

The IO category deals with all inter-driver communication related output, including IRP processinging.

Meaning | Value
TL_IO_MASK | 0x0000F000
TL_IO_NOISE | 0x00001000
TL_IO_TRACE | 0x00002000
TL_IO_WARNING | 0x00004000
TL_IO_ERROR | 0x00008000

AV/C Message Category

The AVC category deals with all AV/C command related output, plus some potentially interesting internal driver messages related to object lists and spin locks (NOISE class). Included in the TRACE class of messages are command execution times.

Meaning | Value
TL_AVC_MASK | 0x000F0000
TL_AVC_NOISE | 0x00010000
TL_AVC_TRACE | 0x00020000
TL_AVC_WARNING | 0x00040000
TL_AVC_ERROR | 0x00080000

Connection Message Category

The Connection category deals with all plug connection related output.

Meaning | Value
TL_CXN_MASK | 0x00F00000
TL_CXN_NOISE | 0x00100000
TL_CXN_TRACE | 0x00200000
TL_CXN_WARNING | 0x00400000
TL_CXN_ERROR | 0x00800000


AV/C Streaming

This section describes the AV/C Streaming filter driver. Avcstrm.sys is a lower level subunit filter driver that is located immediately above avc.sys and 61883.sys in the driver stack and below any subunit drivers. The AV/C Stream filter driver provides additional support for the AV/C protocol driver. This support is strictly optional.

This section includes:

Introduction to AV/C Streaming

AV/C Streaming Device Stack

AV/C Streaming Resources

Installing Subunit Devices

Using Avcstrm.sys

For more information about the AV/C protocol upon which the AV/C Streaming filter driver is built, see AV/C Protocol and Subunit Driver Support.

For more information about the 61883 protocol, see IEC-61883 Client Drivers.


Introduction to AV/C Streaming

The AV/C Streaming filter driver (avcstrm.sys) provides easy-to-integrate services to stream various media signals to its client AV/C subunit driver. Since this filter driver services only AV/C subunits and provides format aware streaming services, it is called the AV/C Streaming (avcstrm.sys) filter driver.

The services the optional AV/C Streaming filter driver provides help stream the media signal (data) from an AV/C subunit if that signal is in either SDDV or MPEG2TS formats. These formats are the two most common methods of storing the digital data in the media signal.

The tape subunit specifications by the 1394 Trade Association support different transport state controls such as play, pause, record and stop, regardless of its media signal. However, the media signal for the same subunit type may be different or it may be the same. Both DV and DVHS contain tape subunits. However, DV uses the SDDV media signal based on the IEC 61883-2 specifications, and DVHS uses the MPEG2TS media signal based on the 61883-4 specifications.

Therefore a tape subunit filter driver must then support both SDDV and MPEG2TS media signals but use the same device control for the tape subunit. This implies that every subunit driver would have to duplicate the same program functionality to provide such format aware streaming capability. Consequently, Microsoft provides this filter driver for the subunit driver stack to provide such service to various subunit drivers of the same or different subunit type.

Programming an AV/C subunit driver on Microsoft's 61883 and AV/C subunit driver stacks requires driver functions to receive or transmit data streams using device driver interfaces (DDIs) provided by the 61883 protocol driver. These driver functions perform the following operations:

  • Allocate isochronous resources and make an isochronous connection
  • Queue data buffers
  • Attach and complete receiving or transmitting data buffers
  • Synchronize stream state across threads


AV/C Streaming Device Stack

The AV/C Streaming filter driver (avcstrm.sys) is installed as a lower level filter driver to subunit drivers to provide streaming services. The interface to this service is based on the I/O request packet (IRP) model used by the WDM architecture with a list of supported I/O control (IOCTL) functions. It can service a subunit driver that is based on either the stream class driver model (Kernel Streaming 1.0) or the new AVStream class driver model (Kernel Streaming 2.0). The following diagram illustrates AV/C subunit drivers that use the AV/C stream filter driver. The AVStream driver model is the preferred interface to use.

Peer AV/C Device Stack with lower filter driver avcstrm.sys

Avcstrm.sys is format aware. It must know the format of the streaming data, such as SDDV or MPEG2TS, in order to make the proper isochronous connection between the source and the target devices. With the given format information, it can then interface with the AV/C subunit's driver through the 61883 protocol driver to receive or transmit data. Because avcstrm.sys is format aware, it will have to be updated to add a different format (for example a service pack or new OS release). Currently, SDDV and MPEG2TS formats are the only formats implemented.

In the future, avcstrm.sys may be extended to:

  • Query data format
  • Perform data intersection (negotiate data format between two pins)
  • Be a clock provider
  • Get and set streaming properties

Currently, each subunit driver must implement the preceding operations.

The AV/C Streaming filter driver does not timestamp data at this time. A clock provider needs to timestamp the data as well as provide the current stream time. If a subunit driver is a clock provider, it needs to implement this functionality. The subunit driver must timestamp the data if it is to be a clock provider.


AV/C Streaming Resources

The AV/C Stream filter driver relies on the 61883.sys protocol driver. It uses DDIs provided by 61883.sys to do isochronous connection and isochronous data streaming, and uses avc.sys to issue AV/C commands for external device control. The following items list related documentation and other related references:

AV/C Protocol and Subunit Driver Support

IEC-61883 Protocol Driver

http://www.microsoft.com/hwdev/wdm

http://www.microsoft.com/hwdev/1394

http://www.microsoft.com/hwdev/vidcap

http://www.1394ta.org/Technology/Specifications/index.htm

http://www.iec.ch/


Installing Subunit Devices

The INF file of a functional driver (during the subunit device driver installation) installs avcstrm.sys as a lower filter driver on the driver stack. The INF includes a ".HW" section to perform installation of a device. The following is an example of adding avcstrm.sys as a lower filter driver on either Win9x and later or Windows 2000 and later platforms with "Subunit" as the install section name:

[Subunit.HW]
AddReg=Subunit_AddFilter_W9x

[Subunit.NT.HW]
AddReg=Subunit_AddFilter_NT

[SubUnit_AddFilter_W9x]
HKR,,"LowerFilters",0x00010000,"avcstrm.sys"    ; Win9X use "avcstrm.sys" as driver name

[Subunit_AddFilter_NT]
HKR,,"LowerFilters",0x00010000,"AVCSTRM"    ; NT use this "AVCSTRM" as Service name

For Windows 2000 and later, a functional driver also must make the necessary driver dependency in the service install section to preserve the proper driver loading order. In the following example, the AVCSTRM service section is loaded before the subunit driver:

ServiceBinary = %12%\subunit.sys
Dependencies  = AVCSTRM             ; loaded before subunit.sys

For more details, see INF File Sections and Directives.


Using Avcstrm.sys

The AV/C Streaming filter driver (avcstrm.sys) can start providing services after its client subunit driver creates a data stream. A data stream can be categorized to perform three functions: data streaming, clock provider, and getting and setting of stream properties or events. These three functions are inter-related, and the data stream's behavior will be controlled with stream state: stop, pause, or run.

A subunit driver first requests that the AV/C Streaming filter driver open a stream with a given data format. This data format contains definitions of the signal format used in IEC 61883-x protocol specifications. This signal can be SDDV or MPEG2TS. This protocol defines how data is transmitted on the 1394 bus. The AV/C Streaming filter driver validates and caches the data format, queries the available isochronous resources from the target device, such as plug information, and allocates the necessary resources for queuing data streaming requests. Upon successful creation of a stream, a stream context is returned. This context is a pointer to an opaque structure that contains information about the current stream, such as data format and stream state.

After a stream is created, a subunit driver can start to send down the stream data request. This request will be queued and a separate IRP will be allocated and submitted to 61883.sys for receiving data or data transmission. Upon completion of the data request, the completion routine will be called. This request is asynchronous because data transfer is controlled by the stream state and availability of the data.

The stream may be in either paused or run states when stream data requests arrive. The isochronous connection is made in the paused state. The AV/C Streaming filter driver will request the 61883-protocol driver (61883.sys) to allocate bandwidth and isochronous channel, if needed, transitioning into the run state.

A data stream will be stopped when transitioning into the stop state. The AV/C Streaming filter driver will reclaim ownership of the data buffer by requesting 61883 to detach the data buffers. These data buffers will be completed with STATUS_CANCELLED.

A stream may need to be aborted during events such as surprise device removal or data IRP cancellation, for example, if the thread that dispatched the IOCTL was terminated. When transitioning to a stop state, the AV/C Streaming filter driver will stop isochronous data transfer but it does not change the stream state.

As a filter driver, avcstrm.sys filters and processes only the I/O request packet (IRP) with MajorFunction of IRP_MJ_INTERNAL_DEVICE_CONTROL and the I/O control (IOCTL) code of IOCTL_AVCSTRM_CLASS, and passes through other IRPs to the lower stack. Depending on the request, the AV/C Streaming filter driver processes an IRP from its client and then creates one or more locally allocated IRPs to request service from its lower stack, either the 61883 or AV/C protocol drivers. Even though the IRP from a subunit driver can be used to send down a request to the lower stack, it is safer to create a different IRP in case a class driver claims ownership of an IRP.

The AV/C Streaming filter driver is designed to work with the kernel streaming (KS) mini driver on the 61883 and AV/C stack. A subunit driver can use either the stream class driver (KS 1.0) or the AVStream class driver (KS 2.0) to handle and provide the semantics of kernel streaming, but it has no built in dependency on structures used by only the class driver. A subunit driver that uses a class driver must extract the KS structure from the class driver structures to construct requests to be issued to the AV/C Streaming filter driver. Therefore, the subunit driver has a dependency only on ks.h and avcstrm.h.

In the following section, each AV/C Streaming command function is discussed (some with sample code). The sample code used in this section is from a streaming class (KS 1.0) based subunit driver.


Creating a stream

A data stream context must be created before the AV/C Streaming filter driver can provide services. The context points to an opaque structure that contains the requested data format, data stream state, and properties. It is like a stream extension. A data format structure and the direction of the data flow are its input parameters. If the stream can be created successfully, it will return a stream context. This context is cached by the subunit driver and is used for subsequent AV/C Streaming requests.

This is a synchronous operation. The operation first creates a stream request structure to open a stream and then calls the user-defined IRP synchronous routine to call to lower driver to create a data stream based on the given data flow direction and data format defined in AVCSTRM_FORMAT_INFO. The following sample code shows how to open a data stream context.

#include <avcstrm.h>

INIT_AVCSTRM_HEADER(pAVCStrmReq, AVCSTRM_OPEN);
pAVCStrmReq->CommandData.OpenStruct.AVCFormatInfo =            &AVCStrmFormatInfoTable[pDevExt->VideoFormatIndex];
pAVCStrmReq->CommandData.OpenStruct.AVCStreamContext = NULL;
pAVCStrmReq->CommandData.OpenStruct.DataFlow         = DataFlow;

Status =
    AVCStrmReqSubmitIrpSynch(
        pDevExt->pBusDeviceObject,
        pStrmExt->pIrpReq,
        pAVCStrmReq
        );

if(STATUS_SUCCESS == Status) {
    // Save the context, which is used for
    // Subsequent call to AVCStrm filter driver
    pStrmExt->AVCStreamContext =
        pAVCStrmReq->CommandData.OpenStruct.AVCStreamContext;
}


Submitting a data buffer

With an open stream, a subunit driver can start to attach stream samples to AV/C Streaming. These samples can be either read or write operations and they can be submitted in the same manner to the AV/C Streaming filter driver. This service is always asynchronous because of its dependency on current stream state and stream data availability.

INIT_AVCSTRM_HEADER(pAVCStrmReq, (pSrb->Command == SRB_READ_DATA) ?      AVCSTRM_READ : AVCSTRM_WRITE);
pAVCStrmReq->AVCStreamContext = pStrmExt->AVCStreamContext;  // from cached context saved in OPEN_STREAM request

// The AV/C Streaming filter driver does not act as a clock provider. The subunit driver must provide this functionality if it wants to be the clock provider.

pAVCStrmReq->CommandData.BufferStruct.StreamHeader = pSrb->CommandData.DataBufferArray;

pAVCStrmReq->CommandData.BufferStruct.FrameBuffer =
MmGetSystemAddressForMdlSafe(pSrb->Irp->MdlAddress,          NormalPagePriority);

// This is an Async operation
NextIrpStack = IoGetNextIrpStackLocation(pIrpReq);
NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_AVCSTRM_CLASS;
NextIrpStack->Parameters.Others.Argument1 = pAVCStrmReq;

// Not cancelable! But can be aborted with AVCSTRM_ABORT_STREAMING
IoSetCancelRoutine(
    pIrpReq,
    NULL
    );

IoSetCompletionRoutine(
    pIrpReq,
    AVCTapeReqReadDataCR,
    pDriverReq,
    TRUE,  // Success
    TRUE,  // Error
    TRUE   // or Cancel
    );

pSrb->Status = STATUS_PENDING;

Status =
    IoCallDriver(
        pDevExt->pBusDeviceObject,
        pIrpReq
        );

Because the operation is asynchronous, the status should be STATUS_PENDING. When the data is completed, the completion routine will be called. In the completion routine, a subunit driver can do post processing, including updating statistics of data processed and possibly add presentation time if the subunit is the clock provider.

// Keep track of number of frames processed
pStrmExt->FramesProcessed++;

// Retrieve current stream time
if(pStrmExt->hMasterClock)
    pStrmExt->CurrentStreamTime = pSrb->CommandData.DataBufferArray->PresentationTime.Time;

// Update final status
pSrb->Status = pIrpReq->IoStatus.Status;

// Complete this data SRB
StreamClassStreamNotification(
    StreamRequestComplete,
    pSrb->StreamObject,
    pSrb
    );


Getting and Setting the Stream State

A subunit receives IOCTLs from a client application to get the current stream state or to set to a new stream state. When a data stream is created, it is initialized to KSSTATE_STOP state. The isochronous resource is allocated in the KSSTATE_ACQUIRE state, and if it fails, it will return STATUS_INSUFFICIENT_RESOURCE (declared in ntstatus.h) in the KSSTATE_PAUSE state. Data streaming will commence in the KSSTATE_RUN state.

This sample code will set the stream to a new state:

INIT_AVCSTRM_HEADER(pAVCStrmReq, AVCSTRM_SET_STATE);
pAVCStrmReq->AVCStreamContext = pStrmExt->AVCStreamContext; // from cached context saved in OPEN_STREAM request
pAVCStrmReq->CommandData.StreamState = StreamState; // New stream state

Status =
    AVCStrmReqSubmitIrpSynch(
        pDevExt->pBusDeviceObject,
        pStrmExt->pIrpReq,
        pAVCStrmReq
        );

This sample code will query for the current stream state:

INIT_AVCSTRM_HEADER(pAVCStrmReq, AVCSTRM_GET_STATE);
pAVCStrmReq->AVCStreamContext = pStrmExt->AVCStreamContext;  // from cached context saved in OPEN_STREAM request

Status =
    AVCStrmReqSubmitIrpSynch(
        DeviceObject,
        pStrmExt->pIrpReq,
        pAVCStrmReq
        );

// If return STATUS_SUCCESS, the current stream state is in
// pAVCStrmReq->CommandData.StreamState


Closing a stream

After a stream operation is completed, the data stream must be closed to free the resources allocated by the open stream request.

If the stream state is not stopped or there is pending I/O, the close stream request will complete the data request and set the status of the IRP to STATUS_CANCELLED.

INIT_AVCSTRM_HEADER(pAVCStrmReq, AVCSTRM_CLOSE);
pAVCStrmReq->AVCStreamContext = pStrmExt->AVCStreamContext;  // from cached context saved in OPEN_STREAM request
Status =
    AVCStrmReqSubmitIrpSynch(
        pDevExt->pBusDeviceObject,
        pStrmExt->pIrpReq,
        pAVCStrmReq
        );


Aborting a stream

When a subunit encounters special conditions, such as device removal or stream data IOCTL cancellation, then the streaming operation should be aborted. The abort operation request is synchronous but the abort completion is not. Only the first abort stream request is accepted and processed; duplicate requests will be ignored but returned with STATUS_SUCCESS. The AV/C Streaming filter driver then schedules a work item to abort streaming. When a stream is aborted, it starts to complete the AVCSTRM_READ/AVCSTRM_WRITE request with STATUS_CANCELLED. The stream state is not changed with the abort request, and the data stream still must be closed to clean up and release resources.

In the abort work item routine, AV/C Streaming will first stop the isochronous data transfer, but it does not affect the stream state. AV/C Streaming then goes through the attached streams data queue to detach stream buffers and return them with STATUS_CANCELLED.

To issue this request, an AV/C Streaming request is initialized with the AVCSTRM_ABORT_STREAMING request and the data stream context.

INIT_AVCSTRM_HEADER(pAVCStrmReq, AVCSTRM_ABORT_STREAMING);
pAVCStrmReq->AVCStreamContext = pStrmExt->AVCStreamContext;  // from cached context saved in OPEN_STREAM request

Status =
    AVCStrmReqSubmitIrpSynch(
        pStrmExt->pDevExt->pBusDeviceObject,
        pStrmExt->pIrpAbort,
        pAVCStrmReq
        );

When a data stream is aborted, it can be resumed (if the device has not been removed) after its stream state has been reset to KSSTATE_STOP by its client application.


Kernel Streaming Enumeration and Structures

This section contains reference pages for the Microsoft®-supplied Kernel Streaming structures.


BUS_INTERFACE_REFERENCE

A software device enumerator (swenum) exports this interface to allow drivers to reference count PDOs such that the device will remain active while in use and be unloaded when not in use.

typedef struct {
    //
    // Standard interface header
    //

    INTERFACE                   Interface;

    //
    // Standard bus interfaces
    //

    PFNREFERENCEDEVICEOBJECT    ReferenceDeviceObject;
    PFNDEREFERENCEDEVICEOBJECT  DereferenceDeviceObject;
    PFNQUERYREFERENCESTRING     QueryReferenceString;

} BUS_INTERFACE_REFERENCE, *PBUS_INTERFACE_REFERENCE;

Members

Interface
Specifies the exported INTERFACE.
ReferenceDeviceObject
Increments the reference count for the given PDO. This assures that the device object will remain active and enumerated until the reference count returns to 0.
DereferenceDeviceObject
Decrements the reference count of the PDO. When the PDO's reference count is 0, it becomes eligible for removal. Note that this condition does not guarantee removal.
QueryReferenceString
Creates a buffer from the paged pool and copies the reference string associated with the PDO into this buffer. The caller is expected to free the buffer using ExFreePool.

Headers

Declared in ks.h. Include ks.h.


KS_FRAMING_ITEM

The KS_FRAMING_ITEM structure is one of the new objects used to declare allocator requirements on a kernel mode pin. Each KSALLOCATOR_FRAMING_EX contains one or more framing items.

typedef struct {
    GUID MemoryType;
    GUID BusType;
    ULONG MemoryFlags;
    ULONG BusFlags;
    ULONG Flags;
    ULONG Frames;
    ULONG FileAlignment;
    ULONG MemoryTypeWeight;
    KS_FRAMING_RANGE PhysicalRange;
    KS_FRAMING_RANGE_WEIGHTED FramingRange;
} KS_FRAMING_ITEM, *PKS_FRAMING_ITEM;

Members

MemoryType
The type of memory used for buffers/data frames. There is a partial correspondence between this field and the field PoolType in KSALLOCATOR_FRAMING. The two fields differ in that PoolType allowed only paged/non-paged. MemoryType can be any of the following:
KSMEMORY_TYPE_WILDCARD / KSMEMORY_TYPE_DONT_CARE / KSTYPE_DONT_CARE -
Can handle any type of memory
KSMEMORY_TYPE_SYSTEM -
KSMEMORY_TYPE_USER -
KSMEMORY_TYPE_KERNEL_PAGED -
Buffers must be kernel paged memory. This corresponds to KSALLOCATOR_FRAMING.PoolType ==PagedPool and KSALLOCATOR_FRAMING.RequirementsFlags having SYSTEM_MEMORY set.
KSMEMORY_TYPE_KERNEL_NONPAGED -
Buffers must be kernel nonpaged memory. This would correspond to KSALLOCATOR_FRAMING.PoolType == NonPagedPool and KSALLOCATOR_FRAMING.RequirementsFlags having SYSTEM_MEMORY set.
KSMEMORY_TYPE_DEVICE_UNKNOWN
BusType

Specifies the physical bus accessing the physical memory specified by MemoryType. Use this field to determine a compatible memory type based on the bus used for the connection medium. This distinction is crucial when a pin exposes different memory types based on the connection medium.

MemoryFlags
Currently specifies only KSALLOCATOR_REQUIREMENTF_MUST_ALLOCATE, to indicate that the connection point requires that it allocate any frames sent.
BusFlags
Not currently used.
Flags
Similar to the options flags and requirements flags found in KSALLOCATOR_FRAMING..
Frames
Total number of allowable outstanding frames. Corresponds to KSALLOCATOR_FRAMING.Frames.
FileAlignment
Requirement for frame alignment. Corresponds to KSALLOCATOR_FRAMING.FileAlignment.
MemoryTypeWeight
This memory type weight pin-wide.
PhysicalRange
Specifies the physical limit of frame sizes.
FramingRange
Specifies the optimal range of frame sizes.

Headers

Declared in ks.h. Include ks.h.

Comments

Each KSALLOCATOR_FRAMING_EX instance contains one or more framing items.

See Also

KSALLOCATOR_FRAMING_EX , KS_FRAMING_RANGE , KS_FRAMING_RANGE_WEIGHTED , KS_COMPRESSION


KS_FRAMING_RANGE

The KS_FRAMING_RANGE structure specifies a range for frame sizes for a given framing item.

typedef struct {
    ULONG MinFrameSize;
    ULONG MaxFrameSize;
    ULONG Stepping;
} KS_FRAMING_RANGE, *PKS_FRAMING_RANGE;

Members

MinFrameSize
Minimum frame size.
MaxFrameSize
Maximum frame size.
Stepping

Headers

Declared in ks.h. Include ks.h.

Comments

Frames can be size k where

k = MinFrameSize + Stepping * Z,. where MinFrameSize <= k <= MaxFrameSize


KS_FRAMING_RANGE_WEIGHTED

The KS_FRAMING_RANGE_WEIGHTED structure specifies a weighted framing range.

typedef struct {
    KS_FRAMING_RANGE Range;
    ULONG InPlaceWeight;
    ULONG NotInPlaceWeight;
} KS_FRAMING_RANGE_WEIGHTED, *PKS_FRAMING_RANGE_WEIGHTED;

Members

Range
The framing range.
InPlaceWeight
Maximum frame size.
NotInPlaceWeight

Headers

Declared in ks.h. Include ks.h.


KSALLOCATOR_FRAMING

The KSALLOCATOR_FRAMING structure is used to query framing requirements and submit requests of a filter. Use it to submit an allocator creation request to a handle of a sink via IRP_MJ_CREATE.

typedef struct {
    union {
        ULONG    OptionsFlags;
        ULONG    RequirementsFlags;
    };
    POOL_TYPE   PoolType;
    ULONG        Frames;
    ULONG        FrameSize;
    ULONG        FileAlignment;
    ULONG        Reserved;
} KSALLOCATOR_FRAMING, *PKSALLOCATOR_FRAMING;

Members

OptionsFlags
Specifies the allocator option flags specified during allocator creation for the connection point. For a description of the flags, see the Comments section.
RequirementsFlags
Specifies the allocator requirements specified during the query of the connection point. For a description of the flags, see the Comments section.
PoolType
Allocation pool type for kernel mode only. See POOL_TYPE for pool type identifier details.
Frames
Specifies the total number of allowable outstanding frames. Zero indicates that the filter has no requirement for this member.
FrameSize
Specifies the total size of the frame including prefix and postfix. Zero indicates that the filter has no requirement for this member.
FileAlignment
Specifies the alignment allocation specification. The minimum allocation alignment is FILE_QUAD_ALIGNMENT. Allocators must always align on at least quad boundaries.
Reserved
Reserved for system use. Set to zero.

Headers

Declared in ks.h. Include ks.h.

Comments

The RequirementsFlags member can contain the following values.

Flag Value | Description
KSALLOCATOR_REQUIREMENTF_INPLACE_MODIFIER | Indicates that the connection point can perform an in-place modification.
KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY | Indicates that the connection point requires system memory for allocations. If this option is not set, it is assumed that the sink provides a system address space mapping to on-board RAM or other forms of storage on the device.
KSALLOCATOR_REQUIREMENTF_FRAME_INTEGRITY | Indicates that the connection point requires that downstream filters maintain the data integrity of specified frames.
KSALLOCATOR_REQUIREMENTF_MUST_ALLOCATE | Indicates that the connection point requires that it allocate any frames sent.
KSALLOCATOR_REQUIREMENTF_PREFERENCES_ONLY | Indicates that the Requirements flags are preferences only and the connection point is able to allocate frames that do not meet those specifications.

The OptionsFlags member can contain the following values.

OptionsFlags | Description
KSALLOCATOR_OPTIONF_COMPATIBLE | Indicates that the framing options of the allocator being created are compatible with the downstream allocator. This option is typically specified when an in-place modifier is assigned an allocator for copy buffers. If the filter is not required to modify a given frame, it may submit the frame to the downstream filter without allocating an additional frame from the downstream allocator, when this option is specified.
KSALLOCATOR_OPTIONF_SYSTEM_MEMORY | Indicates the use of system memory for allocations. When specified, the allocator must allocate memory from the pool as specified in the PoolType member. Otherwise, it is assumed that the sink provides a system address mapping to on-board RAM or other forms of storage on the device.

See Also

KsCreateAllocator


KSALLOCATOR_FRAMING_EX

The KSALLOCATOR_FRAMING_EX structure is used to query framing requirements and submit requests of a filter.

typedef struct {
    ULONG CountItems;
    ULONG PinFlags;
    KS_COMPRESSION OutputCompression;
    ULONG PinWeight;
    KS_FRAMING_ITEM     FramingItem[1];
} KSALLOCATOR_FRAMING_EX, *PKSALLOCATOR_FRAMING_EX;

Members

CountItems
The number of framing items that are present in the extended allocator framing structure. Count of items in KSALLOCATOR_FRAMING_EX.FramingItem.
PinFlags
Reserved, set to zero.
OutputCompression
Defines the frame ratio for transforms that change the size of a frame. For instance, a decompressor might specify 3 to 1 and a compressor might specify 1 to 3. May be used to allow in-place compression and expansion of frames through pins with different framing requirements.
PinWeight
This pin's framing weight graph-wide. Reserved, set to zero.
FramingItem
The actual framing item(s).

Headers

Declared in ks.h. Include ks.h.

Comments

KSALLOCATOR_FRAMING_EX is a replacement for KSALLOCATOR_FRAMING. AVStream provides support for this extended allocator framing structure, but does not support KSALLOCATOR_FRAMING. When using AVStream, use KSALLOCATOR_FRAMING_EX to define allocator requirements on a pin in a kernel level filter.

A minidriver can also use DECLARE_SIMPLE_FRAMING_EX to declare an extended framing structure in line with the original structure. This macro is defined in ks.h:

#define DECLARE_SIMPLE_FRAMING_EX(FramingExName, MemoryType, Flags, Frames, Alignment, MinFrameSize, MaxFrameSize) const KSALLOCATOR_FRAMING_EX FramingExName

DECLARE_SIMPLE_FRAMING_EX declares a KSALLOCATOR_FRAMING_EX structure called FramingExName with the specified memory type (often either STATIC_KS_TYPE_DONT_CARE or one of the kernel paged or non paged GUIDs). The Frames and Alignment fields correspond to the KSALLOCATOR_FRAMING. MinFrameSize and MaxFrameSize ensure that frames are within a specific size range. Flags corresponds to the old OptionsFlags and RequirementsFlags in KSALLOCATOR_FRAMING.

See Also

KS_FRAMING_ITEM , KSALLOCATOR_FRAMING , KS_COMPRESSION , KS_FRAMING_RANGE , KS_FRAMING_RANGE_WEIGHTED


KSATTRIBUTE

The KSATTRIBUTE structure defines an additional attribute of a data range or data format that is not covered by the KSDATARANGE/KSDATAFORMAT structures or the extended information based on the range/format specifier.

typedef struct {
    ULONG Size;
    ULONG Flags;
    GUID Attribute;
} KSATTRIBUTE, *PKSATTRIBUTE;

Members

Size
The size of the attribute. This will be at least the size of the KSATTRIBUTE structure and may be more if there exists extended information based on the identifying GUID in the Attribute field.
Flags
The flags of the attribute. The only used flag is KSATTRIBUTE_REQUIRED; this flag specifies that an attribute is required. If this flag is not set, the attribute is optional. Note that the topmost bit is reserved for internal use in KS.
Attribute
A unique identifier identifying the attribute.

Headers

Declared in ks.h. Include ks.h.

Comments

Please note that KSATTRIBUTE is used in conjunction with data ranges and data formats; attributes on data ranges and formats are taken into consideration when determining if a data range intersects with another data range or whether a data format is acceptable to a given pin.

See Also

KSDATARANGE,

KSDATAFORMAT


KSBUFFER_ITEM

The KSBUFFER_ITEM structure is used to store a list of data buffers copied from the event source, which can be retrieved by the event sink through KSEVENT_TYPE_QUERYBUFFER. It extends the normal DPC structure, which may be needed for event generation, but does not use the structure itself.

typedef struct {
    KSDPC_ITEM          DpcItem;
    LIST_ENTRY          BufferList;
} KSBUFFER_ITEM, *PKSBUFFER_ITEM;

Members

DpcItem
Contains the DPC item structure, which may be used by internal DPC's, but is not used for data buffering.
BufferList
The head of a list of pool allocated buffers that are created by calls to KsGenerateDataEvent for events that have buffering enabled.

Headers

Declared in ks.h. Include ks.h.


KSCLOCK_CREATE

The KSCLOCK_CREATE structure is used in clock create parameters for KsCreateClock function.

typedef struct {
    ULONG       CreateFlags;
} KSCLOCK_CREATE, *PKSCLOCK_CREATE;

Members

CreateFlags
Currently consists of a flags item, which must be set to zero.

Headers

Declared in ks.h. Include ks.h.


KSCLOCK_FUNCTIONTABLE

The KSPROPERTY_CLOCK_FUNCTIONTABLE property fills in a KSCLOCK_FUNCTIONTABLE structure with function pointers that are valid until the file object for the clock is released.

typedef struct {
    PFNKSCLOCK_GETTIME GetTime;
    PFNKSCLOCK_GETTIME GetPhysicalTime;
    PFNKSCLOCK_CORRELATEDTIME GetCorrelatedTime;
    PFNKSCLOCK_CORRELATEDTIME GetCorrelatedPhysicalTime;
} KSCLOCK_FUNCTIONTABLE, *PKSCLOCK_FUNCTIONTABLE;

Members

GetTime
This entry point is used to retrieve the current clock time.
GetPhysicalTime
This entry point is used to retrieve the current underlying physical time.
GetCorrelatedTime
This entry point is used to retrieve the current clock time and a correlated system time as an atomic operation.
GetCorrelatedPhysicalTime
This entry point is used to retrieve the current physical time and a correlated system time as an atomic operation.

Headers

Declared in ks.h. Include ks.h.


KSCOMPONENT_ID

A client may query the KSPROPERTY_GENERAL_COMPONENTID property to retrieve the component information within the provided KSCOMPONENT_ID structure.

typedef struct {
    GUID Manufacturer;
    GUID Product;
    GUID Component;
    GUID Name;
    ULONG Version;
    ULONG Revision;
} KSCOMPONENTID, *PKSCOMPONENTID;

Members

Manufacturer
Contains the unique identifier for the manufacturer of the component. This is generated by the manufacturer, and may be resolved to a localized string representation through a registry entry.
Product
Contains the unique identifier for the product to which the component belongs. This is generated by the manufacturer, and may be resolved to a localized string representation through a registry entry.
Component
Contains the unique identifier for the component. This is generated by the manufacturer, and may be resolved to a localized string representation through a registry entry.
Name

Optionally contains the unique identifier for the name, which may be different than the Component entry, or this may be GUID_NULL. This is generated by the manufacturer, and may be resolved to a localized string representation through a registry entry.

Version
Contains the version number for the component or product.
Revision
Contains the revision number for the component or product.

Headers

Declared in ks.h. Include ks.h.


KSCORRELATED_TIME

The KSPROPERTY_CLOCK_CORRELATEDTIME property is passed a KSCORRELATED_TIME structure, which is filled in with the current time and system time.

typedef struct {
    LONGLONG    Time;
    LONGLONG    SystemTime;
} KSCORRELATED_TIME, *PKSCORRELATED_TIME;

Members

Time
Contains the current clock time in 100-nanosecond units.
SystemTime
Contains the correlated system time in 100-nanosecond units.

Headers

Declared in ks.h. Include ks.h.

Comments

The system time is acquired from KeQueryPerformanceCounter. Note that the performance counter is not suspended when the machine is suspended, so that correlations will change when the machine goes through a suspend.


KSDATAFORMAT

The KSDATAFORMAT structure is a variable-length structure that describes a data format.

typedef struct {
    ULONG FormatSize;
    ULONG Flags;
    ULONG SampleSize;
    ULONG Reserved;
    GUID MajorFormat;
    GUID SubFormat
    GUID Specifier;
} KSDATAFORMAT;

Members

FormatSize
Size in bytes of this structure. This must be at least sizeof(KSDATAFORMAT), but may be larger for specific settings of MajorFormat, SubFormat, and Specifier.
Flags
Normally set to zero.
SampleSize
The sample size of the data, for fixed sample sizes, or zero if the format has a variable sample size.
Reserved
Reserved for system use. Drivers must set this to zero.
MajorFormat
Specifies general format type. The currently supported data formats may be found in as the KSDATAFORMAT_TYPE_XXX symbolic constants in the ksmedia.h header that comes with the DDK documentation. A data stream that has no particular format should use KSDATAFORMAT_TYPE_STREAM (defined in ks.h) as its MajorFormat.
SubFormat
Specifies the subformat of a general format type. The currently supported data formats may be found in the KSDATAFORMAT_SUBTYPE_XXX symbolic constants in the ksmedia.h header that comes with the DDK documentation. Major formats that do not support subformats should use KSDATAFORMAT_SUBTYPE_NONE for this member.
Specifier
Specifies additional data format type information for a specific setting of MajorFormat and Subformat. The significance of this field is determined by the major format (and subformat, if the major format supports subformats). For example, Specifier may represent a particular encoding of a subformat, or it may be used to specify what type of data structure follows KSDATAFORMAT in memory.

The following specifiers (defined in ks.h) are of general use:

KSDATAFORMAT_SPECIFIER_NONE
Stands for no specifier. Used for formats that do not support specifiers.
KSDATAFORMAT_SPECIFIER_FILENAME
Indicates that a zero-terminated Unicode string immediately follows the KSDATAFORMAT structure in memory.
KSDATAFORMAT_SPECIFIER_FILEHANDLE
Indicates that a file handle immediately follows KSDATAFORMAT in memory.

Headers

Declared in ks.h. Include ks.h.

Comments

At the minimum, a data format is specified by the MajorFormat, SubFormat, and Specifier members. A family of similar data formats may share the same values for MajorFormat, SubFormat, and Specifier. In that case, the specific data format is distinguished by additional data that follows the Specifier member in memory.

Technology-specific data formats are detailed within that technology area's documentation.


KSDATARANGE

The KSDATARANGE structure is a variable-length structure that describes a range of data formats.

typedef struct {
    ULONG FormatSize;
    ULONG Flags;
    ULONG SampleSize;
    ULONG Reserved;
    GUID MajorFormat;
    GUID SubFormat
    GUID Specifier;
} KSDATARANGE;

Members

FormatSize
Size in bytes of this structure. This must be at least sizeof(KSDATARANGE), but may be larger for specific settings of MajorFormat, SubFormat, and Specifier.
Flags
This field is ignored.
SampleSize
This field is ignored.
Reserved
Reserved. Drivers must set this to zero.
MajorFormat
Either the specific major format of a data format that this data range matches, or KSDATAFORMAT_TYPE_WILDCARD if this data range matches all major formats. When MajorFormat has this value, both SubFormat and Specifier must also take on their wild card values.
SubFormat
Either the specific subformat of a data format that this data range matches, or KSDATAFORMAT_SUBTYPE_WILDCARD if this data range matches all subformats. (In this instance, the specifier is not required to be its wild card value, unless MajorFormat is KSDATAFORMAT_TYPE_WILDCARD.)
Specifier
Either the specifier of the data format that this data range matches, or KSDATAFORMAT_SPECIFIER_WILDCARD if this data range matches all specifier values.

Headers

Declared in ks.h. Include ks.h.

Comments

Drivers use data ranges to describe the ranges of data formats they support.


KSDEGRADE

The KSDEGRADE identifier is defined in the ks.h header file:

typedef KSIDENTIFIER KSDEGRADE, *PKSDEGRADE;

Headers

Declared in ks.h. Include ks.h.

See Also

KSDEGRADE_STANDARD , Quality Management


KSDEGRADE_STANDARD

The KSDEGRADE_STANDARD enumeration type lists different types of degradation.

typedef enum {
    KSDEGRADE_STANDARD_SAMPLE,
    KSDEGRADE_STANDARD_QUALITY,
    KSDEGRADE_STANDARD_COMPUTATION,
    KSDEGRADE_STANDARD_SKIP
} KSDEGRADE_STANDARD;

Elements

KSDEGRADE_STANDARD_SAMPLE
Sample degradation.
KSDEGRADE_STANDARD_QUALITY
Quality degradation.
KSDEGRADE_STANDARD_COMPUTATION
Computation degradation.
KSDEGRADE_STANDARD_SKIP
Skip ahead a specified delta in the data stream.

Headers

Declared in ks.h. Include ks.h.

See Also

KSDEGRADE , Quality Management


KSDISPATCH_TABLE

The KSDISPATCH_TABLE structure is used for dispatching IRP's to various types of objects contained under a single DRIVER_OBJECT. A pointer to a dispatch table is contained in the opaque object header that is the first element of data pointed to by an FsContext within a file object.

typedef struct {
    PDRIVER_DISPATCH        DeviceIoControl;
    PDRIVER_DISPATCH        Read;
    PDRIVER_DISPATCH        Write;
    PDRIVER_DISPATCH        Flush;
    PDRIVER_DISPATCH        Close;
    PDRIVER_DISPATCH        QuerySecurity;
    PDRIVER_DISPATCH        SetSecurity;
    PFAST_IO_DEVICE_CONTROL FastDeviceIoControl;
    PFAST_IO_READ           FastRead;
    PFAST_IO_WRITE          FastWrite;
} KSDISPATCH_TABLE, *PKSDISPATCH_TABLE;

Members

DeviceIoControl
The Device I/O Control handler.
Read
The Read handler.
Write
The Write handler.
Flush
The Flush handler.
Close
The Close handler.
QuerySecurity
The Query Security handler.
SetSecurity
The Set Security handler.
FastDeviceIoControl
The fast Device I/O Control handler.
FastRead
The fast Read handler.
FastWrite
The fast Write handler.

Headers

Declared in ks.h. Include ks.h.


KSDPC_ITEM

The KSDPC_ITEM structure is used to store information related to any internal DPC's that might be used to generate event notification from a raised IRQL level. It uses a reference counting scheme to determine when to free the structure.

typedef struct {
    KDPC            Dpc;
    ULONG           ReferenceCount;
    KSPIN_LOCK      AccessLock;
} KSDPC_ITEM, *PKSDPC_ITEM;

Members

Dpc
Contains the DPC structure that is queued to perform notifications that cannot occur at raised IRQL.
ReferenceCount
Specifies whether or not pending DPC's will be referencing this structure. This is initially set to 1 when the event structure is created, and decremented when destroyed. If the reference count is non-zero at that time, then the last DPC to run will free the structure rather than the event disable call.
AccessLock
This lock is used to synchronize deletion of an event item with any DPC that might be running.

Headers

Declared in ks.h. Include ks.h.


KSE_NODE

Just as KSP_NODE is used for properties on a node, the KSE_NODE structure is used for events on a node.

typedef struct {
    KSEVENT Event;
    ULONG NodeId;
    ULONG Reserved;
} KSE_NODE;

Members

Event
Specifies the event.
NodeId
Specifies the node ID.
Reserved
Reserved for system use. Should be set to zero.

Headers

Declared in ks.h. Include ks.h.


KSERROR

The KSError structure is used to report Streaming errors in both kernel and user mode to their respective Quality Managers.

typedef struct {
    PVOID       Context;
    ULONG       Status;
} KSERROR, *PKSERROR;

Members

Context
Contains a context parameter that was originally passed to the connection.
Status
Contains the NTSTATUS error.

Headers

Declared in ks.h. Include ks.h.

Comments

Streaming error notifications can be generated against the Quality Management sink, if assigned. The same method of proxying Quality Management complaints is used for forwarding Error reports for DirectShow graphs.


KSEVENT

The KSEVENT structure describes the event and request type of a event request.

typedef struct {
    GUID Set;
    ULONG Id;
    ULONG Flags;
} KSEVENT;

typedef KSIDENTIFIER KSEVENT;

Members

Set
A GUID identifying this event set.
Id
Specifies the member of the event set.
Flags
Specifies the request type. Should be one of:
Value | Type of event request
KSEVENT_TYPE_ENABLE | Enable event notification for this event type. The driver continues event notification until the client explicitly disables it.
KSEVENT_TYPE_ONESHOT | Enable event notification for the next occurrence of this event, only. The client does not need to (and should not) disable the event once it has occurred.
KSEVENT_TYPE_SETSUPPORT | Queries for the list of event sets, or support of a particular event set.
KSEVENT_TYPE_BASICSUPPORT | Queries for support of a particular event type.
KSEVENT_TYPE_ENABLEBUFFERED | Enable buffered event notifications. The driver buffers each notification without signaling the client. The client then uses KSEVENT_TYPE_QUERYBUFFER to retrieve buffered events.
KSEVENT_TYPE_TOPOLOGY | Event passed is of type KSE_NODE, where NodeId indicates the numeric id of the topology node. Do not set this flag on its own; instead, OR it with other flags from this list.
KSEVENT_TYPE_QUERYBUFFER | Retrieve the next buffered event notification.

Headers

Declared in ks.h. Include ks.h.

Comments

The KSEVENT, KSMETHOD, and KSPROPERTY structures are aliases for the KSIDENTIFIER structure. As such, their definitions are identical.


KSEVENTDATA

The KSEVENTDATA structure specifies the method by which a driver notifies a client when an event occurs.

Headers

Declared in ks.h. Include ks.h.

Comments

Drivers should treat this as an opaque data structure.


KSEVENT_ENTRY

The kernel streaming subsystem uses the KSEVENT_ENTRY structure to describe how an event should be triggered.

Headers

Declared in ks.h. Include ks.h.

Comments

Drivers should treat this as an opaque data structure.


KSEVENT_ITEM

Drivers can use the KSEVENT_ITEM structure to describe how they support an event within an event set.

typedef struct {
    ULONG               EventId;
    ULONG               DataInput;
    ULONG               ExtraEntryData;
    PFNKSADDEVENT       AddHandler;
    PFNKSREMOVEEVENT    RemoveHandler;
    PFNKSHANDLER        SupportHandler;
} KSEVENT_ITEM, *PKSEVENT_ITEM;

Members

EventId
The unique ID of the event within the event set.
DataInput
Specifies the size of event data. The event data begins with a KSEVENTDATA structure that describes how the client should be notified when the event occurs, optionally followed by any additional parameters that specify when the event occurs. Must be at least sizeof(KSEVENTDATA).
ExtraEntryData
Specifies the size of any additional memory that the system should allocate for each enable request for this event. The driver uses this memory to store any data it needs to keep track of the event request. The memory is allocated directly after the event enable request's KSEVENT_ENTRY structure.
AddHandler
Not used by the stream class driver. AVStream minidrivers may place a pointer to a handler here. Related details in Comments below.
RemoveHandler
Not used by the stream class driver. AVStream minidrivers may place a pointer to a handler here. Related details in Comments below.
SupportHandler
Not used by the stream class driver.

Headers

Declared in ks.h. Include ks.h.

Comments

The following comments are for AVStream minidrivers only.

If an AVStream minidriver specifies AddHandler as non-NULL, note that the default behavior of adding the item to the object's event list is not performed by AVStream. Should the minidriver choose not to perform the default action, and instead specifies an AddHandler and does not add the event to the object's event list via KsDefaultAddEventHandler() or via a Ks*AddEvent() call, the minidriver is directly responsible for cleaning up the event.

A minidriver that specifies AddHandlers and RemoveHandlers and does not properly clean the events up can cause a resource (memory/handle) leak.

Alternatively, a minidriver can add to the default behavior by calling KsDefaultAddEventHandler or Ks*AddEvent in the AddHandler routine and then adding implementation-specific steps following this call. If this is the case, AVStream will still automatically perform cleanup duties upon receiving IOCTL_KS_DISABLE_EVENT or filter/pin closure as long as RemoveHandler is NULL. If RemoveHandler is non-NULL, the minidriver must clean up the event. If the event is on the object's event list (via a NULL AddHandler or via the AddHandler calling KsDefaultAddEventHandler()), then the RemoveHandler must do a RemoveEntryList:

&EventEntry -> ListEntry


KSEVENT_SET

The KSEVENT_SET structure describes the events that make up an event set.

typedef struct {
    const GUID *Set;
    ULONG EventsCount;
    const KSEVENT_ITEM *EventItem;
} KSEVENT_SET, *PKSEVENT_SET;

Members

Set
Pointer to the GUID that identifies the event set.
EventsCount
The number of events in the event set.
EventItem
Pointer to the beginning of the array of KSEVENT_ITEM structures that describe each event in the event set. The size of the array is in the EventsCount member.

Headers

Declared in ks.h. Include ks.h.


KSEVENT_TIME_INTERVAL

The KSEVENT_TIME_INTERVAL structure is used in various events within the KSEVENTSETID_Clock event set.

typedef struct {
  KSEVENTDATA  EventData;
  LONGLONG  TimeBase
  LONGLONG  Interval;
} KSEVENT_TIME_INTERVAL, *PKSEVENT_TIME_INTERVAL;

Members

EventData
Specifies the standard event structure.
TimeBase
Specifies the initial clock time when the event should be signaled.
Interval
Specifies the subsequent interval when the event should continue to be signaled.

Headers

Declared in ks.h. Include ks.h.

See Also

KSEVENT_TIME_MARK


KSEVENT_TIME_MARK

The KSEVENT_TIME_MARK structure is used in various events within the KSEVENTSETID_Clock event set.

typedef struct {
  KSEVENTDATA  EventData;
  LONGLONG  MarkTime;
} KSEVENT_TIME_MARK, *PKSEVENT_TIME_MARK;

Members

EventData
Specifies the standard event structure.
MarkTime
Specifies the clock time when the event should be signaled.

Headers

Declared in ks.h. Include ks.h.

Comments

The flags indicate the type of units for the interval. The interval can be specified in KSEVENT_DATA_MARKF_FILETIME units for these events, which are 100-nanosecond units.

See Also

KSEVENT_TIME_INTERVAL


KSEVENTS_LOCKTYPE

The enumerated types of KSEVENTS_LOCKTYPE specify the exclusion lock. The types are used with EventFlags in several event-set helper functions.

typedef enum {
    KSEVENTS_NONE,
    KSEVENTS_SPINLOCK,
    KSEVENTS_MUTEX,
    KSEVENTS_FMUTEX,
    KSEVENTS_FMUTEXUNSAFE,
    KSEVENTS_INTERRUPT,
    KSEVENTS_ERESOURCE
} KSEVENTS_LOCKTYPE;

EventsFlags | Description
KSEVENTS_NONE | No lock.
KSEVENTS_SPINLOCK | Lock is assumed to be a KSPIN_LOCK.
KSEVENTS_MUTEX | Lock is assumed to be a KMUTEX.
KSEVENTS_FMUTEX | Lock is assumed to be a FAST_MUTEX and is acquired by raising IRQL to APC_LEVEL.
KSEVENTS_FMUTEXUNSAFE | Lock is assumed to be a FAST_MUTEX and is acquired without raising IRQL to APC_LEVEL.
KSEVENTS_INTERRUPT | Lock is assumed to be an interrupt synchronization spin lock.
KSEVENTS_ERESOURCE | Lock is assumed to be an ERESOURCE.

Headers

Declared in ks.h. Include ks.h.


KSFASTMETHOD_ITEM

Each method in a method set is described by a KSMETHOD_ITEM in an array of such items. This specifies the method, type of method, handler, and required size of parameters. The array elements may be placed in any arbitrary order. Arbitrary items may also have an associated KSFASTMETHOD_ITEM, which enables Fast I/O dispatching.

typedef struct {
    ULONG                   MethodId;
    union {
        PFNKSFASTHANDLER        MethodHandler;
        BOOLEAN                 MethodSupported;
    };
} KSFASTMETHOD_ITEM, *PKSFASTMETHOD_ITEM;

Members

MethodId
Contains the identifier of the method and the flags describing the type of method.
MethodHandler
Points to the fast handler for this method.
MethodSupported
Set to TRUE if the method is supported, otherwise set to FALSE.

Headers

Declared in ks.h. Include ks.h.

See Also

KSMETHOD_ITEM


KSFASTPROPERTY_ITEM

The KSFASTPROPERTY_ITEM structure is used with items for fast I/O dispatching.

typedef struct {
  ULONG  PropertyId;
  PFNKSFASTHANDLER  GetPropertyHandler;
  PFNKSFASTHANDLER  SetPropertyHandler;
  ULONG  Reserved;
} KSFASTPROPERTY_ITEM, *PKSFASTPROPERTY_ITEM;

Members

PropertyId
Specifies the identifier of the specific property within the set.
GetPropertyHandler
Specifies the fast handler for retrieving the property. If this is NULL, the property cannot be read with a fast handler.
SetPropertyHandler
Specifies the fast handler for setting the property. If this is NULL, the property cannot be set with a fast handler.
Reserved
Reserved and set to zero.

Headers

Declared in ks.h. Include ks.h.


KSFRAMETIME

This property is supported by rendering pins, and is used to return the duration of the next "frame" of data, and flags associated with that frame.

typedef struct {
    LONGLONG    Duration;
    ULONG       FrameFlags;
    ULONG       Reserved;
} KSFRAMETIME, *PKSFRAMETIME;

Members

Duration
The duration in presentation time units.
FrameFlags
Flags specific to the next frame, or to all frames. These are described in the following table.
Reserved
Set to zero.

Headers

Declared in ks.h. Include ks.h.

Comments

Note that this is an optional property, which need only be implemented if the pin instance understands the specifics of the media type it is transporting.

DeviceIoControl(
    DeviceHandle,
    IOCTL_KS_PROPERTY,
    &Property,
    sizeof(KSPROPERTY),
    &Extent,
    sizeof(KSFRAMETIME),
    &BytesReturned,
    &Overlapped);

define KSFRAMETIME_VARIABLESIZE    0x00000001


KSIDENTIFIER

The KSIDENTIFIER structure uses a GUID to uniquely identify a set, and a set-specific ID to refer to a member within that set.

typedef struct {
    GUID Set;
    ULONG Id;
    ULONG Flags;
} KSIDENTIFIER;

typedef KSIDENTIFIER KSEVENT;

Members

Set
Contains the globally unique set identifier.
Id
Contains the set-specific identifier for an item within the set.
Flags
Used for various set types, such as Properties and Methods. Zero when not used.

Headers

Declared in ks.h. Include ks.h.

Comments

The KSEVENT, KSMETHOD, and KSPROPERTY structures are aliases for the KSIDENTIFIER structure. As such, their definitions are identical.

The use of an ID within the set allows one to perform a single large compare for a set identifier, then smaller quick compares (for example, by using a switch statement for identifiers within a set). For instance, a property set is referred to by a unique GUID identifier, and properties within that set are referred to by the short ID.

Method, event, interface, and medium sets can be thought of as "classes" of sets.


KSINTERVAL

The KSINTERVAL structure specifies a base time and time interval for recurring events.

typedef struct {
    LONGLONG TimeBase;
    LONGLONG Interval;

Members

} KSINTERVAL, *PKSINTERVAL;
TimeBase
64-bit time base.
Interval
Recurrence interval, also 64-bit.

Headers

Declared in ks.h. Include ks.h.

See Also

KSEVENT_CLOCK_INTERVAL_MARK , KSEVENT_CLOCK_POSITION_MARK.


KSM_NODE

Just as KSP_NODE is used for properties on a node, the KSM_NODE structure is used for methods on a node.

typedef struct {
    KSMETHOD Method;
    ULONG NodeId;
    ULONG Reserved;
} KSM_NODE;

Members

Method
Specifies the method.
NodeId
Specifies the node ID.
Reserved
Reserved for system use. Should be set to zero.

Headers

Declared in ks.h. Include ks.h.


KSMETHOD

The KSMETHOD structure describes the method and request type of a method request.

typedef struct {
    GUID Set;
    ULONG Id;
    ULONG Flags;
} KSIDENTIFIER;

typedef KSIDENTIFIER KSMETHOD;

Members

Set
A GUID identifying this method set.
Id
Specifies the member of the method set.
Flags
Specifies the request type. A request can contain a combination of the following values: Also see KSMETHOD_TYPE_Xxx flags for KSMETHOD_ITEM.
Value | Type of method request
KSMETHOD_TYPE_BASICSUPPORT | Indicates to query the minidriver to determine if it supports the specified method of the method set.
KSMETHOD_TYPE_SEND | Indicates that the minidriver should execute the specified method. The effect of the method on the given parameters must be known to the client. That is, whether the parameters are read from, written to, both, or neither. The minidriver uses the KSMETHOD_ITEM structure to specify the method's effect on the parameters.
KSMETHOD_TYPE_SETSUPPORT | Indicates to query the minidriver to determine if it supports the specified method set.
KSMETHOD_TYPE_TOPOLOGY | Indicates that the specified method is of type KSM_NODE, where the NodeId member indicates the identifier of the topology node. Do not set this flag on its own; instead, OR it with other flags from this list.

Headers

Declared in ks.h. Include ks.h.

Comments

The KSEVENT, KSMETHOD, and KSPROPERTY structures are aliases for the KSIDENTIFIER structure. As such, their definitions are identical.

A client can use the IOCTL_KS_METHOD request along with the KSMETHOD structure to execute methods on a KS object that the minidriver handles. For more information, see KS Methods and Method Sets.

See Also

KSEVENT, KSMETHOD_ITEM, KSM_NODE, KSPROPERTY


KSMETHOD_ITEM

The KSMETHOD_ITEM structure describes a single method within a method set.

typedef struct {
    ULONG MethodId;
    PFNKSHANDER MethodHandler;
    ULONG MinMethod;
    ULONG MinData;
    PFNKSHANDLER SupportHandler;
    ULONG Flags;
} KSMETHOD_ITEM;

Members

MethodId
Identifier of this method within its method set.
MethodHandler
Pointer to the method implementation provided by a minidriver.
MinMethod
Minimum size of buffer required to specify the method completely. This size is at least sizeof(KSMETHOD) bytes.
MinData
Minimum size of buffer required to specify the method data buffer. This buffer is used to read and/or write information related to the method.
SupportHandler
Pointer to the support handler provided by a minidriver.
Flags
Specifies the request type of this method request. Set this member to a combination of the following values:
Value | Type of method request
KSMETHOD_TYPE_NONE | Indicates that the second buffer—the data buffer—is not expected to be used. For buffered methods although space is allocated, no data is copied to or from the system buffer. When in source mode (KSMETHOD_TYPE_SOURCE), no MDL is created.
KSMETHOD_TYPE_READ | Indicates that parameters are expected to be read from the second buffer. When buffered, data is copied to the system buffer. When in source mode, the data is probed and locked for IoReadAccess.
KSMETHOD_TYPE_WRITE | Indicates that parameters are expected to be written to the second buffer. When buffered, data is copied from the system buffer. When in source mode, the data is probed and locked for IoWriteAccess.
KSMETHOD_TYPE_MODIFY | Indicates that parameters are expected to be read and written to the second buffer. The data passed in is overwritten by the data returned. This might imply that a structure passed in could be merely updated. When buffered, the data is copied to the system buffer, and copied back when the IRP is completed. When in source mode, the data is probed and locked for IoModifyAccess.
KSMETHOD_TYPE_SOURCE | Indicates the method is to be processed in source mode. An MDL is allocated and the data is probed and locked. To indicate a buffered method, OR this flag with other flags from this list.

Headers

Declared in ks.h. Include ks.h.

Comments

A minidriver uses the KSMETHOD_ITEM structure to define methods in a method set. The minidriver implements methods and uses the MethodHandler member to point to these methods. A client can then use the IOCTL_KS_METHOD request along with the KSMETHOD structure to execute methods on a KS object that the minidriver handles. For more information, see KS Methods and Method Sets.

See Also

KSFASTMETHOD_ITEM, KSMETHOD


KSMETHOD_SET

The KSMETHOD_SET structure is used by drivers to describe a method set.

typedef struct {
    const GUID* Set;
    ULONG MethodsCount;
    PKSMETHOD_ITEM MethodItem;
    ULONG FastIoCount;
    PKSFASTMETHOD_ITEM FastIoTable;
} KSMETHOD_SET;

Members

Set
Specifies the GUID
MethodsCount
Specifies the number of methods in this method set.
MethodItem
Pointer to an array of KSMETHOD_ITEM structures. Each structure describes one method of the method set.
FastIoCount
Reserved for system use. Do not use.
FastIoTable
Reserved for system use. Do not use.

Headers

Declared in ks.h. Include ks.h.


KSMULTIPLE_ITEM

The KSMULTIPLE_ITEM structure is a generic header for property data that can contain multiple entries.

typedef struct {
    ULONG Size;
    ULONG Count;
} KSMULTIPLE_ITEM;

Members

Size
The size in bytes of this header and the items following.
Count
The number of items following.

Headers

Declared in ks.h. Include ks.h.


KSNODE_CREATE

The KSNODE_CREATE structure describes the set of information used to create the node handle.

typedef struct {
    ULONG CreateFlags;
    ULONG Node;
} KSNODE_CREATE, *PKSNODE_CREATE;

Members

CreateFlags
Set to zero.
Node
Indicates what node a handle should be created for. This refers to the node identifiers returned when querying topology information. A node identifier of –1 may be used to refer to the collection of nodes as a whole, if the filter supports it.

Headers

Declared in ks.h. Include ks.h.


KSOBJECT_CREATE_ITEM

The KSOBJECT_CREATE_ITEM structure is used to look up the string passed to a create request. A pointer to the create item structure containing the matching string is placed in KSCREATE_ITEM_IRP_STORAGE(Irp) before calling the associated create function.

typedef struct {
    PDRIVER_DISPATCH        Create;
    PVOID                   Context;
    UNICODE_STRING          ObjectClass;
    PSECURITY_DESCRIPTOR    SecurityDescriptor;
    ULONG                   Flags;
} KSOBJECT_CREATE_ITEM, *PKSOBJECT_CREATE_ITEM;

Members

Create
Contains the create dispatch function for this particular base object class.
Context
This value can be used to store object type-specific context information. Since a pointer to the create item structure is contained in KSCREATE_ITEM_IRP_STORAGE(Irp) before calling the specific create routine, this can be retrieved during creation of a new object.
ObjectClass
Points to a Unicode string that identifies the object class. This is the string that was used to register with PnP for a particular class of object supported by this device.
SecurityDescriptor
Optionally contains a security descriptor for this type of object, else it is NULL. If security is used, this must be freed when the object type is no longer used. This must use pool memory, and cannot be shared, as it may be replaced. If this is modified, the Flags element is updated.
Flags

Specifies the request type. Flags as described below

Value | Type of method request
KSCREATE_ITEM_SECURITYCHANGED | Indicates that the security descriptor on this object type has been changed and should be persisted.
KSCREATE_ITEM_WILDCARD | Indicates that this create item represents a wildcard that will be used for any create requests that do not match any other create items. The ordering of the wildcard entry in the list of create items is irrelevant. Only a single wildcard entry is valid on any list of create items.
KSCREATE_ITEM_NOPARAMETERS | Indicates that this create item does not allow any parameters to be passed, and will fail if any are found. Normally, create parameters are passed on to the create handler. This cannot be used with a wildcard flag.

Headers

Declared in ks.h. Include ks.h.


KSOBJECT_CREATE

The KSOBJECT_CREATE structure contains an array of create handlers for base object classes supported by this device object.

typedef struct {
    ULONG                    CreateItemsCount;
    PKSOBJECT_CREATE_ITEM    CreateItemsList;
} KSOBJECT_CREATE, *PKSOBJECT_CREATE;

Members

CreateItemsCount
Contains the number of items in the following table.
CreateItemsList
Points to an array of create handlers for base object classes supported by this device object.

Headers

Declared in ks.h. Include ks.h.


KSOBJECTTYPE

The KSOBJECTTYPE enumeration type lists different types of kernel streaming objects.

typedef enum {
    KsObjectTypeDevice,
    KsObjectTypeFilterFactory,
    KsObjectTypeFilter,
    KsObjectTypePin
    } KSOBJECTTYPE;

Elements

KsObjectTypeDevice
Object is a device.
KsObjectTypeFilterFactory
Object is a filter factory.
KsObjectTypeFilter
Object is a filter.
KsObjectTypePin
Object is a pin.

Headers

Declared in ks.h. Include ks.h.

See Also

KsGetObjectTypeFromFileObject , KsGetObjectFromFileObject, KsGetFilterFromFileObject, KsGetPinFromFileObject, KsPinGetConnectedPinFileObject


KSP_NODE

Kernel streaming clients use the KSP_NODE structure to specify the property and node type within a KSPROPERTY_TOPOLOGY_NAME property request.

typedef struct {
    KSPROPERTY Property;
    ULONG NodeId;
    ULONG Reserved;
} KSP_NODE;

Members

Property
Specifies the property.
NodeId
Specifies the node ID.
Reserved
Reserved for system use. Should be set to zero.

Headers

Declared in ks.h. Include ks.h.


KSP_PIN

Kernel streaming clients use the KSP_PIN structure to specify the property and pin type within a KSPROPSETID_Pin property request.

typedef struct {
    KSPROPERTY Property;
    ULONG PinId;
    ULONG Reserved;
} KSP_PIN;

Members

Property
Specifies the property.
PinId
Specifies the pin type ID.
Reserved
Reserved. Should be set to zero.

Headers

Declared in ks.h. Include ks.h.


KSP_TIMEFORMAT

The KSP_TIMEFORMAT structure corresponds to KSPROPERTY_MEDIASEEKING_CONVERTTIMEFORMAT. The fields of the structure correspond one to one with DirectShow's IMediaSeeking::ConvertTimeFormat.

typedef struct {
    KSPROPERTY Property;
    GUID SourceFormat;
    GUID TargetFormat;
    LONGLONG Time;
} KSP_TIMEFORMAT, *PKSP_TIMEFORMAT;

Members

Property
Specifies the property.
SourceFormat
TargetFormat
Time

Headers

Declared in ks.h. Include ks.h.


KSPIN_CONNECT

Clients use the KSPIN_CONNECT structure to describe the connection they request from a driver in a KsCreatePin call.

typedef struct {
    KSPIN_INTERFACE Interface;
    KSPIN_MEDIUM Medium;
    ULONG PinId;
    HANDLE PinToHandle;
    KSPRIORITY Priority;
} KSPIN_CONNECT;

Members

Interface
Specifies the interface to use for this connection.
Medium
Specifies the medium to use for this connection.
PinId
Specifies the pin type ID number. If the PinToHandle field is not NULL, this field contains the identifier of the source pin to which the request is being sent. Otherwise this field refers to the sink pin that is being connected to. If a pin can support being both a source and sink in communications, then this is the implicit method of telling it how it should act in the connection.
PinToHandle
NULL when a client requests a connection to itself. Otherwise, the target of the connection request. This field is used to indicate both what type of destination pin the create is intended for, and in the case of a source destination, what pin to connect to. In the case of a source destination, this contains the handle of the pin instance to establish a connection to. In the case of a sink destination, this field contains NULL, and is not otherwise used.
Priority
Specifies the priority for the connection. Usually KSPRIORITY_NORMAL. See the KSPROPERTY_CONNECTION_PRIORITY property for details.

Headers

Declared in ks.h. Include ks.h.

Comments

If the KSPIN_CONNECT.PinToHandle element is not NULL, IRP_MJ_CREATE instructs the device to connect the source KSPIN_CONNECT.PinId pin to the KSPIN_CONNECT.PinToHandle pin instance. Otherwise, this is a request from a client for connection to the KSPIN_CONNECT.PinId pin using the KSPIN_CONNECT.Medium method and a specific data format specified after the connection structure. In either case, the device driver may fail this request if this connection cannot be accepted.


KSPIN_DESCRIPTOR

The KSPIN_DESCRIPTOR structure describes the basic KSPROPSETID_Pin properties of a pin type.

typedef struct {
    ULONG InterfacesCount;
    const KSPIN_INTERFACE* Interfaces;
    ULONG MediumsCount;
    const KSPIN_MEDIUM *Mediums;
    ULONG DataRangesCount;
    const PKSDATARANGE* DataRanges;
    KSPIN_DATAFLOW DataFlow;
    KSPIN_COMMUNICATION Communication;
    const GUID* Category;
    const GUID* Name;
    ULONG ConstrainedDataRangesCount;
    PKSDATARANGE* ConstrainedDataRanges;
} KSPIN_DESCRIPTOR;

Members

InterfacesCount
The size of the array pointed to by Interfaces.
Interfaces
The interfaces supported by this pin type.
MediumsCount
The number of elements in the array pointed to by Mediums.
Mediums
The mediums supported by this pin type.
DataRangesCount
The size of the array pointed to by DataRanges.
DataRanges
The data ranges supported by this pin type.
DataFlow
One of KSPIN_DATAFLOW_IN or KSPIN_DATAFLOW_OUT. See KSPROPERTY_PIN_DATAFLOW for the meaning of each value.
Communication
One of KSPIN_COMMUNICATION_NONE, KSPIN_COMMUNICATION_SINK, KSPIN_COMMUNICATION_SOURCE, KSPIN_COMMUNICATION_BOTH or KSPIN_COMMUNICATION_BRIDGE. See KSPROPERTY_PIN_COMMUNICATION for the meaning of each value.
Category
The category GUID.
Name
The GUID of the localized Unicode string name for the pin type, stored in the Registry.
ConstrainedDataRangesCount
The number of entries in the array pointed to by ConstrainedDataRanges.
ConstrainedDataRanges
The set of data ranges the pin type currently supports, based on the driver's internal state.

Headers

Declared in ks.h. Include ks.h.

Comments

Drivers typically define one KSPIN_DESCRIPTOR structure for each pin type they support.

See Also

KSPIN_MEDIUM


KSPIN_INTERFACE

The KSPIN_INTERFACE structure describes a specific interface within an interface set.

typedef struct {
    GUID Set;
    ULONG Id;
    ULONG Flags;
} KSIDENTIFIER;

typedef KSIDENTIFIER KSPIN_INTERFACE;

Members

Set
The GUID that specifies this interface set.
Id
The ID number of this particular interface within the interface set.
Flags
Reserved for system use.

Headers

Declared in ks.h. Include ks.h.


KSPIN_MEDIUM

The KSPIN_MEDIUM structure identifies a specific connection on a communication bus.

typedef struct {
    GUID Set;
    ULONG Id;
    ULONG Flags;
} KSIDENTIFIER;

typedef KSIDENTIFIER KSPIN_MEDIUM;

Members

Set
A GUID that specifies this communication bus.
Id
Identifies a unique connection on the bus.
Flags
Reserved for system use.

Headers

Declared in ks.h. Include ks.h.

Comments

The KSPIN_MEDIUM structure identifies a medium, with a unique medium GUID and instance identifier, which is generated in a bus-specific manner. There is a reserved identifier value KSMEDIUM_TYPE_ANYINSTANCE that is used when bus instances are not of concern. For instance, the KSMEDIUMSETID_Standard refers to the system bus, of which there should only be one. So this instance identifier is always used just as a convenience.

A pin may support multiple mediums and interfaces on those mediums. The way in which a pin is described implies that the list of interfaces is supported on all mediums enumerated for a pin. So if there is a case in which this is not true, another pin may be used to describe each subset of interfaces for the specific mediums. Also see KSPROPERTY_PIN_MEDIUMS.

The medium is also cached by KS to speed up the search for a possible connection.

An example of use of this structure can be found in a tuner sample, in which KSPIN_MEDIUM represents unique connections between tuners, crossbars, and other tuner components.


KSPIN_PHYSICALCONNECTION

Data type returned by KSPROPERTY_PIN_PHYSICALCONNECTION.

typedef struct {
    ULONG Size;
    ULONG Pin;
    WCHAR SymbolicLinkName[1];
} KSPIN_PHYSICALCONNECTION, *PKSPIN_PHYSICALCONNECTION;

Members

Size
Pin
SymbolicLinkName

Headers

Declared in ks.h. Include ks.h.


KSPRIORITY

The KSPRIORITY structure is used to specify priority and is used with the KSPROPERTY_CONNECTION_PRIORITY property.

typedef struct {
  ULONG  PriorityClass;
  ULONG  PrioritySubClass;
} KSPRIORITY, *PKSPRIORITY;

Members

PriorityClass
Specifies a number ranging from 1 to 0xFFFFFFFF, where 1 is least priority and 0xFFFFFFFF is the highest priority. Zero is reserved for future use. When setting a class value, 0xFFFFFFFF is used to indicate exclusive access to the resources consumed by the pin. See the Comments section for a list of possible values.
PrioritySubClass
Specifies a number ranging from 1 to 0xFFFFFFFF, where 1 is the least priority within the class and 0xFFFFFFFF is the most priority. Zero is reserved for future use.

Headers

Declared in ks.h. Include ks.h.

Comments

Values for KSPRIORITY.PriorityClass include:

PriorityClass | Description
KSPRIORITY_LOW | Specifies the lowest priority.
KSPRIORITY_NORMAL | Specifies normal priority.
KSPRIORITY_HIGH | Specifies an elevated priority.
KSPRIORITY_EXCLUSIVE | Specifies the highest priority, which implies exclusive access to resources.

The KSPRIORITY.PrioritySubClass member allows a client to set exclusive use of resources consumed by a pin and also to prioritize the use of those resources by the client's pins within that exclusive class. The initial priority of a pin is set by the connection request typically performed through KsCreatePin, and is usually KSPRIORITY_NORMAL, with a subclass priority of 1. A pin uses these priorities as parameters when allocating shared resources from any component managing resources. Resource allocation occurs when formats are set on pins.

If the removal of resources by a higher priority client causes the filter pin to fail, the client must be notified through the KSEVENT_CONNECTION_PRIORITY event (assuming that the client had registered for event notification of this type).


KSPROPERTY

The KSPROPERTY structure describes the property and request type of a property request.

typedef struct {
    GUID Set;
    ULONG Id;
    ULONG Flags;
} KSIDENTIFIER;

typedef KSIDENTIFIER KSPROPERTY;

Members

Set
A GUID identifying this property set.
Id
Specifies the member of the property set.
Flags
Specifies the request type. Should be one of the following values:
Value | Type of property request
KSPROPERTY_TYPE_GET | Get the current property data setting.
KSPROPERTY_TYPE_SET | Set the current property data setting.
KSPROPERTY_TYPE_SETSUPPORT | Does the driver support this property set?
KSPROPERTY_TYPE_BASICSUPPORT | What request types does the driver handle for this property? What is the valid data type, and what are the valid ranges for the property data?
KSPROPERTY_TYPE_DEFAULTVALUES | What are the driver's default values for the property data for this property? If default values exist, they are returned in the Basic Support information, rather than the normal range values. Default values are tagged as such by the filter when defining property range values.
KSPROPERTY_TYPE_RELATIONS | Specify all properties whose property data depends on the current setting of this property. Specifies that the property relations list is to be returned, or the amount of buffer room required by such a list if the return buffer is the size of a ULONG. Each element is on FILE_QUAD_ALIGNMENT, preceded by a KSMULTIPLE_ITEM structure. This is not valid when querying support of the property set in general.
KSPROPERTY_TYPE_SERIALIZESET | Serialize the property set, using the standard KSPROPERTY_SERIALHDR and KSPROPERTY_SERIAL structures.
KSPROPERTY_TYPE_UNSERIALIZESET | Unserialize the property set, using the standard KSPROPERTY_SERIALHDR and KSPROPERTY_SERIAL structures.
KSPROPERTY_TYPE_SERIALIZESIZE | What is the size of the property data for this property, when serialized as part of a KSPROPERTY_TYPE_SERIALIZESET request? The size is returned in the output buffer as a ULONG. A size of zero indicates that a property does not need to be serialized.
KSPROPERTY_TYPE_SERIALIZERAW | Specifies that the properties in this set should be serialized by the property set support handler, if one exists. If not, the call will fail. The serialization format is private. This operation must be the inverse of KSPROPERTY_TYPE_UNSERIALIZERAW.
KSPROPERTY_TYPE_TOPOLOGY | Property passed is of type KSP_NODE, where NodeId indicates the numeric id of the topology node. Do not set this flag on its own; instead, OR it with the above.
KSPROPERTY_TYPE_UNSERIALIZERAW | Specifies that the buffer provided contains a group of properties belonging to this set that should be unserialized by the property set support handler, if one exists. If not, the call will fail. The serialization format is private. This operation must be the inverse of KSPROPERTY_TYPE_SERIALIZERAW.

Headers

Declared in ks.h. Include ks.h.

Comments

The KSEVENT, KSMETHOD, and KSPROPERTY structures are aliases for the KSIDENTIFIER structure. As such, their definitions are identical.


KSPROPERTY_BOUNDS_LONG

The KSPROPERTY_BOUNDS_LONG structure defines the bounds for a 32-bit property.

typedef union {
    struct {
        LONG SignedMinimum;
        LONG SignedMaximum;
    };
    struct {
        ULONG UnsignedMinimum;
        ULONG UnsignedMaximum;
    };
} KSPROPERTY_BOUNDS_LONG, *PKSPROPERTY_BOUNDS_LONG;

Members

Signed Minimum
Minimum specified as a signed 32-bit value.
Signed Maximum
Maximum specified as a signed 32-bit value.
Unsigned Minimum
Minimum specified as an unsigned 32-bit value.
Unsigned Maximum
Maximum specified as an unsigned 32-bit value.

Headers

Declared in ks.h. Include ks.h.

Comments

See the Testcap sample in the DDK for examples of usage.

See Also

KSPROPERTY_VALUES, KSPROPERTY_MEMBERSLIST


KSPROPERTY_BOUNDS_LONGLONG

The KSPROPERTY_BOUNDS_LONGLONG structure defines the bounds for a 64-bit property.

typedef union {
    struct {
        LONGLONG SignedMinimum;
        LONGLONG SignedMaximum;
    };
    struct {
        ULONGLONG UnsignedMinimum;
        ULONGLONG UnsignedMaximum;
    };
} KSPROPERTY_BOUNDS_LONGLONG, *PKSPROPERTY_BOUNDS_LONGLONG;

Members

Signed Minimum
Minimum specified as a signed 64-bit value.
Signed Maximum
Maximum specified as a signed 64-bit value.
Unsigned Minimum
Minimum specified as an unsigned 64-bit value.
Unsigned Maximum
Maximum specified as an unsigned 64-bit value.

Headers

Declared in ks.h. Include ks.h.

Comments

See the Testcap sample in the DDK for examples of usage.

See Also

KSPROPERTY_VALUES, KSPROPERTY_MEMBERSLIST


KSPROPERTY_DESCRIPTION

The KSPROPERTY_DESCRIPTION structure specifies the size and type of values contained in a specific property.

typedef struct {
  ULONG AccessFlags;
  ULONG DescriptionSize;
  KSIDENTIFIER PropTypeSet;
  ULONG MembersListCount;
  ULONG Reserved;
} KSPROPERTY_DESCRIPTION;

Members

AccessFlags
Contains the access allowed to this property.
DescriptionSize
Contains the inclusive size of the entire values information. This is the size of KSPROPERTY_DESCRIPTION if no values information is supported.
PropTypeSet
If supported by the specific property, specifies the type of values contained in this property. This group is uniquely specified by a GUID, such that new types of values may be created without overlapping with extensions to this set. The value types indicate the type of the value (like VT_BOOL, VT_UI4 in the standard set). This is GUID_NULL, with an identifier of zero, if values information is not supported by this property.
MembersListCount
Contains the number of members list headers that would normally follow this header.
Reserved
Reserved for future use. Set to zero.

Headers

Declared in ks.h. Include ks.h.

Comments

The property values type set is specified by a KSIDENTIFIER structure. The basic set supported is KSPROPTYPESETID_General. The identifiers within that set are the standard VARENUM types used for OLE.

The values information that may follow the KSPROPERTY_DESCRIPTION structure is described by a list of variable length structures, each with a common header describing the type of variable length data, and the members in that list element. If supported, these contain the valid values that the specific property may contain.


KSPROPERTY_ITEM

Drivers can use the KSPROPERTY_ITEM structure to describe how they support a property in a property set.

typedef struct {
    ULONG PropertyId;
    union {
        PFNKSHANDLER GetPropertyHandler;
        BOOLEAN GetSupported;
    };
    ULONG MinProperty;
    ULONG MinData;
    union {
        PFNKSHANDLER SetPropertyHandler;
        BOOLEAN SetSupported;
    };
    PKSPROPERTY_VALUES Values;
    ULONG RelationsCount;
    PKSPROPERTY Relations;
    PKFNKSHANDLER SupportHandler;
    ULONG SerializedSize;
} KSPROPERTY_ITEM;

Members

PropertyId
Specifies the ID of the property being described.
GetPropertyHandler
Used only by drivers running under AVStream or KS 1.0. Contains the handler for retrieving the property. If this is NULL, the property cannot be read.
GetSupported
Used only by minidrivers running under stream class. TRUE if this property supports get requests, FALSE if it does not. (The class driver fulfills the request through the SRB_GET_DEVICE_PROPERTY or SRB_GET_STREAM_PROPERTY requests.)
MinProperty
The minimum buffer length to hold the property identifier. Must be at least sizeof(KSPROPERTY).
MinData
The minimum buffer length to hold the data read from or written to this property.
SetPropertyHandler
Used only by drivers running under AVStream or KS 1.0. Contains the handler for setting the property. If this is NULL, the property cannot be set.
SetSupported
TRUE if this property supports set requests, FALSE if it does not. (The class driver fulfills the request through the SRB_SET_DEVICE_PROPERTY or SRB_SET_STREAM_PROPERTY requests.)
Values
If not NULL, this specifies the acceptable and/or default values for a property. These are the same as the values reported by a driver in response to an IOCTL_KS_PROPERTY request with the KSPROPERTY_TYPE_BASICSUPPORT and KSPROPERTY_TYPE_DEFAULTVALUES flags set.
RelationsCount
The number of entries in the array pointed to by Relations.
Relations
Points to an array of related properties. Two properties are considered related if changing one property may affect the value of the other property. The Flags member of each entry is unused.
SupportHandler
Provide only if implementing your own format for raw serialization or raw unserialization. Basic support queries, range queries, and relations queries are automatically handled by AVStream, which will return the relevant values from other members of this KSPROPERTY_ITEM structure.
SerializedSize
The size of the property when serialized in a KSPROPERTY_TYPE_SERIALIZESET request. Should be zero if the property cannot be serialized.

Headers

Declared in ks.h. Include ks.h.

Comments

Stream class minidrivers use KSPROPERTY_ITEM to describe to the client how to fulfill property requests on each property within a set. Handling for the property set as a whole is specified in the KSPROPERTY_SET structure, which contains pointers to arrays of KSPROPERTY_ITEM structures.

The stream class driver handles property requests on behalf of the minidriver. When the stream class driver requires more information from the minidriver, it passes an SRB_XXX request to one of the minidriver's StrMiniReceiveXXXRequest routines. The stream class driver handles the different request types as follows:

Property request flags value | Response
KSPROPERTY_TYPE_GET | If GetSupported is TRUE, the stream class driver submits an SRB_GET_DEVICE_PROPERTY or SRB_GET_STREAM_PROPERTYrequest to the appropriate minidriver StrMiniReceiveXXXRequest routine.
KSPROPERTY_TYPE_SET | If SetSupported is TRUE, the stream class driver submits an SRB_SET_DEVICE_PROPERTY or SRB_SET_STREAM_PROPERTY request to the appropriate minidriver StrMiniReceiveXXXRequest routine.
KSPROPERTY_TYPE_BASICSUPPORT | The stream class driver uses KSPROPERTY_ITEM to obtain the information necessary to fulfill this request. For example, to specify the data type and permitted ranges of the property data, they each use the Values member of this structure.
KSPROPERTY_TYPE_SETSUPPORT | The stream class driver completes the property request IRP as STATUS_SUCCESS if and only if the driver supplies an entry for the property set within its KSPROPERTY_SET structure.
KSPROPERTY_TYPE_DEFAULTVALUES | The stream class driver uses the Values member of this structure to determine the default values for the property data.
KSPROPERTY_TYPE_RELATIONS | The stream class driver uses the Relations member to determine what properties are related to this property.


KSPROPERTY_MEDIAAVAILABLE

Corresponds with DirectShow's IMediaSeeking::GetAvailable.

typedef struct {
    LONGLONG Earliest;
    LONGLONG Latest;
} KSPROPERTY_MEDIAAVAILABLE, *PKSPROPERTY_MEDIAAVAILABLE;

Members

Earliest
Latest

Headers

Declared in ks.h. Include ks.h.


KSPROPERTY_MEMBERSHEADER

The KSPROPERTY_MEMBERSHEADER structure is one member of the KSPROPERTY_MEMBERSLIST structure. Its purpose is to describe the size and type of each element in the members list pointed to by the Members member of the KSPROPERTY_MEMBERSLIST structure.

typedef struct {
    ULONG   MembersFlags;
    ULONG   MembersSize;
    ULONG   MembersCount;
    ULONG   Flags;
} KSPROPERTY_MEMBERSHEADER, *PKSPROPERTY_MEMBERSHEADER;

Members

MembersFlags
Specifies the type of entries in the members list. Should be one of the following values:
Value | Description
KSPROPERTY_MEMBER_RANGES | Indicates that the following value members are described as ranges, with a minimum and maximum range. The size of the range pair is determined by the type of values as specified in KSPROPERTY_DESCRIPTION.PropTypeSet. The number of range pairs is determined by KSPROPERTY_MEMBERSHEADER.MembersCount.
KSPROPERTY_MEMBER
_STEPPEDRANGES 		Indicates that the following members are described as ranges with a specified stepping between values within that range. The stepping is followed by the minimum and maximum range pair. The size of the stepping value is also determined by KSPROPERTY_DESCRIPTION.PropTypeSet. The number of range pairs is determined by KSPROPERTY_MEMBERSHEADER.MembersCount.
KSPROPERTY_MEMBER_VALUES | Each entry in the members array is a single value. The size of each valid value is determined by KSPROPERTY_DESCRIPTION.PropTypeSet. The number of values is determined by KSPROPERTY_MEMBERSHEADER.MembersCount.

MembersSize
The size, in bytes, of the members array.
MembersCount
The number of entries in the members array.
Flags
Either zero, if the entries in the members array specify acceptable values for a property, or KSPROPERTY_MEMBER_FLAG_DEFAULT. This flag indicates that the members in this list represent the default values for this property. These values are returned when the client uses the KSPROPERTY_TYPE_DEFAULTVALUES flag on a query.

Headers

Declared in ks.h. Include ks.h.

Comments

KSPROPERTY_MEMBERSHEADER is an auxiliary structure used by KSPROPERTY_MEMBERSLIST.


KSPROPERTY_MEMBERSLIST

The KSPROPERTY_MEMBERSLIST structure specifies a list of acceptable values and/or default values for a property.

typedef struct {
    KSPROPERTY_MEMBERSHEADER    MembersHeader;
    const VOID*                 Members;
} KSPROPERTY_MEMBERSLIST, *PKSPROPERTY_MEMBERSLIST;

Members

MembersHeader
Specifies how each entry in the array pointed to by Members should be interpreted.
Members
Points to an array of entries. Each entry describes a value or a set of a values. The type of each entry is specified in MembersHeader.MembersFlags. The number of entries is specified in MembersHeader.MembersCount.

Headers

Declared in ks.h. Include ks.h.

Comments

KSPROPERTY_MEMBERSLIST is an auxiliary structure used by KSPROPERTY_VALUES to specify a list of acceptable values for a property.

An entry in the Members array can represent either a value, or a range of values. Optionally the range may include a step value.

If MembersHeader.MembersFlags == KSPROPERTY_MEMBER_VALUES, then each entry is a single value. The type of the value is specified in the PropTypeSet member of KSPROPERTY_VALUES.

If MembersHeader.MembersFlags == KSPROPERTY_MEMBER_RANGES, then each entry is a range of values, specified by a minimum and a maximum value. The type of each value is specified in the PropTypeSet member of KSPROPERTY_VALUES.

If MembersHeader.MembersFlags == KSPROPERTY_MEMBER_STEPPEDRANGES, then each entry is a step size, followed by a range. The type of each value is specified in the PropTypeSet member of KSPROPERTY_VALUES.

If MembersHeader.Flags == KSPROPERTY_MEMBER_FLAG_DEFAULT, the value or set of values supplied represent default values for the property.

Otherwise, the entries represent a list of acceptable values for the property


KSPROPERTY_POSITIONS

The KSPROPERTY_POSITIONS structure is used with the KSPROPERTY_MEDIASEEKING_POSITIONS property. Corresponds to DirectShow's IMediaSeeking::GetPositions and IMediaSeeking::SetPositions.

typedef struct {
    LONGLONG Current;
    LONGLONG Stop;
    KS_SEEKING_FLAGS CurrentFlags;
    KS_SEEKING_FLAGS StopFlags;
} KSPROPERTY_POSITIONS, *PKSPROPERTY_POSITIONS;

Members

Current
Current position as a 64-bit value.
Stop
Stop position as a 64-bit value.
CurrentFlags
StopFlags

Headers

Declared in ks.h. Include ks.h.


KSPROPERTY_SERIAL

Each property that follows the KSPROPERTY_SERIALHDR contains a header (KSPROPERTY_SERIAL), followed by the property data, with the start of each property on FILE_LONG_ALIGNMENT. Note that the serial header structure is defined to be on FILE_LONG_ALIGNMENT.

typedef struct {
    KSIDENTIFIER    PropTypeSet;
    ULONG           Id;
    ULONG           PropertyLength;
} KSPROPERTY_SERIAL, *PKSPROPERTY_SERIAL;

Members

PropTypeSet
Specifies the type of property data. This is the same information obtained from querying Basic Support.
Id
Contains the identifier for this property.
PropertyLength
The length in bytes of the following property data. This does not include any alignment buffering that may be appended to the property data before the next property in the serialization.

Headers

Declared in ks.h. Include ks.h.

See Also

KSPROPERTY_SERIALHDR


KSPROPERTY_SERIALHDR

The format of the serialization buffer is a KSPROPERTY_SERIALHDR, followed by serialized properties.

typedef struct {
    GUID            PropertySet;
    ULONG           Count;
} KSPROPERTY_SERIALHDR, *PKSPROPERTY_SERIALHDR;

Members

PropertySet
Contains the GUID of the property set contained in the serialized buffer.
Count
Contains the count of serialized properties to follow.

Headers

Declared in ks.h. Include ks.h.

See Also

KSPROPERTY_SERIAL


KSPROPERTY_SET

A kernel streaming driver or pin may use the KSPROPERTY_SET structure to describe how it supports a property set.

typedef struct {
    const GUID* Set;
    ULONG PropertiesCount;
    PKSPROPERTY_ITEM PropertyItem;
    ULONG FastIoCount
    PKSFAST_PROPERTY_ITEM FastIoTable;
} KSPROPERTY_SET;

Members

Set
The GUID that identifies the property set.
PropertiesCount
Size of the array pointed to by the PropertyItem member.
PropertyItem
Points to the beginning of an array of KSPROPERTY_ITEM structures that describe how the driver or pin supports each property in the set.
FastIoCount
Reserved for system use.
FastIoTable
Reserved for system use.

Headers

Declared in ks.h. Include ks.h.


KSPROPERTY_STEPPING_LONG

The KSPROPERTY_STEPPING_LONG structure defines the valid range of values for a 32-bit property.

typedef struct {is
    ULONG SteppingDelta;
    ULONG Reserved;
    KSPROPERTY_BOUNDS_LONG Bounds;
} KSPROPERTY_STEPPING_LONG, *PKSPROPERTY_STEPPING_LONG;

Members

SteppingDelta
See comments below.
Reserved
Reserved for system use.
Bounds
See comments below.

Headers

Declared in ks.h. Include ks.h.

Comments

Any value k that satisfies the following criteria is valid:

Bounds.*Minimum + Z * SteppingDelta, Bounds.*Minimum <= k <= Bounds.*Maximum

Also see the Testcap sample in the DDK for examples of usage.

See Also

KSPROPERTY_VALUES, KSPROPERTY_MEMBERSLIST


KSPROPERTY_STEPPING_LONGLONG

The KSPROPERTY_STEPPING_LONGLONG structure defines the valid range of values for a 64-bit property.

typedef struct {
    ULONGLONG SteppingDelta;
    KSPROPERTY_BOUNDS_LONGLONG Bounds;
} KSPROPERTY_STEPPING_LONGLONG, *PKSPROPERTY_STEPPING_LONGLONG;

Members

SteppingDelta
See below.
Bounds
See below.

Headers

Declared in ks.h. Include ks.h.

Comments

Any value k that satisfies the following criteria is valid:

Bounds.*Minimum + Z * SteppingDelta, Bounds.*Minimum <= k <= Bounds.*Maximum

Also see the Testcap sample in the DDK for examples of usage.

See Also

KSPROPERTY_VALUES, KSPROPERTY_MEMBERSLIST


KSPROPERTY_VALUES

The KSPROPERTY_VALUES structure describes the type and acceptable and/or default values of a property.

typedef struct {
    KSIDENTIFIER                    PropTypeSet;
    ULONG                           MembersListCount;
    const KSPROPERTY_MEMBERSLIST*   MembersList;
} KSPROPERTY_VALUES, *PKSPROPERTY_VALUES;

Members

PropTypeSet
A KSIDENTIFIER structure (see KSEVENT) that identifies the data type of the property. The Set member of a KSIDENTIFIER structure indicates the set of value types supported, and the Id member of the same structure identifies the type within the set.
MembersListCount
Number of entries in the array pointed to by MembersList.
MembersList
Pointer to an array of KSPROPERTY_MEMBERSLIST structures. Each entry specifies a list of possible values or sets of values that the property may assume.

Headers

Declared in ks.h. Include ks.h.

Comments

PropTypeSet.Set almost always equals KSPROPTYPESETID_General. The individual value types in KSPROPTYPESETID_General correspond to the VARENUM types documented in the Platform SDK.

Possible values for PropTypeSet.Id include:

Value | Data type
VT_I4 | Signed 4-byte quantity
VT_UI4 | Unsigned 4-byte quantity


KSQUALITY

The KSQuality structure is used to report QM problems in both kernel and user mode to their respective Quality Managers.

typedef struct {
    PVOID       Context;
    ULONG       Proportion;
    LONGLONG    DeltaTime;
} KSQUALITY, *PKSQUALITY;

Members

Context
Contains a context parameter that was originally passed to the connection.
Proportion
Indicates the percentage of frames currently being received that are actually being used. This is expressed in units of one-tenth of a percent, where 1000 is optimal.
DeltaTime
Indicates the delta in native units (as indicated by the Interface) from optimal time at which the frames are being delivered, where a positive number means too late, and a negative number means too early. Zero indicates a correct delta.

Headers

Declared in ks.h. Include ks.h.


KSQUERYBUFFER

The KSQUERYBUFFER structure is used when querying for outstanding buffers available on an event with KSEVENT_TYPE_QUERYBUFFER.

typedef struct {
    KSEVENT         Event;
    PKSEVENTDATA    EventData;
    PVOID           Reserved;
} KSQUERYBUFFER, *PKSQUERYBUFFER;

Members

Event
Contains the description of the original event, with the KSEVENT_TYPE_QUERYBUFFER flag set instead of the KSEVENT_TYPE_ENABLEBUFFERED flag.
EventData
Contains the original pointer to the event data passed when the event was enabled. This pointer is used as the unique identifier in locating the event, just as it is used when disabling the event.
Reserved
Not used, and set to zero.

Headers

Declared in ks.h. Include ks.h.

Comments

If KSEVENT_TYPE_ENABLEBUFFERED was used to enable an event that also buffers data, then the data produced by the event can be queried using this method. The description of the event being queried is provided as the first parameter, and any buffer is provided as the second parameter to the query.

The query returns STATUS_NOT_FOUND if the event was not found; STATUS_INVALID_PARAMETER if it was not being buffered; STATUS_NO_MORE_ENTRIES if no buffers were available; STATUS_BUFFER_TOO_SMALL if the buffer size was insufficient; else STATUS_SUCCESS. The length of buffer needed can be queried by providing a zero length output buffer. The size of buffer is returned in the BytesReturned parameter, with a warning status of STATUS_BUFFER_OVERFLOW.

See Also

KSEVENT


KSQUALITY_MANAGER

The KSQUALITY_MANAGER structure is used with the KSPROPERTY_STREAM_QUALITY property and contains the handle of the Quality Manager sink and a context to pass in the quality complaints.

typedef struct {
  HANDLE  QualityManager;
  PVOID  Context;
} KSQUALITY_MANAGER, *PKSQUALITY_MANAGER;

Members

QualityManager
Specifies the handle to the quality manager receiving the KSQUALITY complaint structures using KSMETHOD_QUALITY_REPORT. This handle must be referenced in order to later use it.
Context
Specifies the context parameter to use when reporting quality problems. The context is used by the Quality Manager to distinguish between various clients that can send complaints to the same file object.

Headers

Declared in ks.h. Include ks.h.


KSRATE

The query is passed a KSRATE structure appended to the Property containing the rate request (known as a KSRATE_CAPABILITY structure), and is returned a KSRATE structure filled in with the capability given the rate request.

typedef struct {
    LONGLONG        PresentationStart;
    LONGLONG        Duration;
    KSPIN_INTERFACE Interface;
    LONG            Rate;
    ULONG           Flags;
} KSRATE, *PKSRATE;

Members

PresentationStart
Contains the start point for the rate in presentation time units.
Duration
Contains the duration of the rate in presentation time units.
Interface
Contains either the interface used in the connection this rate request is being sent to, or the interface of a related connection. This allows the time units to be interpreted by the pin.
Rate
Contains the rate in terms of 1/10th percentage points, where 1000 is the nominal 1.0 rate, 500 is 0.5 rate, and so on. Negative numbers indicate reverse rates.
Flags
See the table below.
Flag | Description
KSRATE_NOPRESENTATIONSTART | Specifies that there is no valid start time in this rate change request or query.
KSRATE_NOPRESENTATIONDURATION | Specifies that there is no valid duration in this rate change request or query.

Headers

Declared in ks.h. Include ks.h.


KSRATE_CAPABILITY

The KSRATE_CAPABILITY structure is just a Property identifier followed by the Rate structure.

typedef struct {
    KSPROPERTY      Property;
    KSRATE          Rate;
} KSRATE_CAPABILITY, *PKSRATE_CAPABILITY;

Members

Property
Property identifier.
Rate
Rate structure.

Headers

Declared in ks.h. Include ks.h.


KSRELATIVEEVENT

The KSPROPERTY_CONNECTION_STARTAT property is passed a KSRELATIVEEVENT structure:

typedef struct {
    ULONG Size;
    ULONG Flags;
    union {
        HANDLE ObjectHandle;
        PVOID ObjectPointer;
    };
    PVOID Reserved;
    KSEVENT Event;
    KSEVENTDATA EventData;
} KSRELATIVEEVENT;

Members

Size

The inclusive size of the structure, including any event specific data appended to the EventData element.

Flags

Flags indicating what type of object is being specified in the ObjectHandle and ObjectPointer union.

ObjectHandle

If the Flags element contains the KSRELATIVEEVENT_FLAG_HANDLE flag, this element contains the handle of the object supporting the event to be used.

ObjectPointer

If the Flags element contains the KSRELATIVEEVENT_FLAG_POINTER flag, this element contains a pointer to the object supporting the event to be used. This is valid only for kernel-mode clients.

Reserved
Reserved and set to zero.
Event
Contains the event to be used.
EventData
Contains the header for the event-specific data. The header itself is not actually used, except as a starting point to access the event-specific data, and must be initialized to zero.

Headers

Declared in ks.h. Include ks.h.


KSRESOLUTION

The KSPROPERTY_CLOCK_RESOLUTION property is passed a KSRESOLUTION structure, which is returned with the granularity and error of the clock.

typedef struct {
    LONGLONG    Granularity;
    LONGLONG    Error;
} KSRESOLUTION, *PKSRESOLUTION;

Members

Granularity
Contains the increment granularity of the clock in 100-nanosecond units, where 1 is the best.
Error
Contains the ± notification error of the clock in 100-nanosecond units, where 0 is the best, meaning the event notification granularity is as good as the increment granularity.

Headers

Declared in ks.h. Include ks.h.


KSSTATE

The KSSTATE enumeration type lists possible states of a Kernel Streaming object.

typedef enum {
    KSSTATE_STOP;
    KSSTATE_ACQUIRE;
    KSSTATE_PAUSE;
    KSSTATE_RUN;
} KSSTATE;

Elements

KSSTATE_STOP
Using absolute minimum of resources.
KSSTATE_ACQUIRE
Acquiring resources.
KSSTATE_PAUSE
Preparing to make instant transition to Run state.
KSSTATE_RUN
Streaming.

Headers

Declared in ks.h. Include ks.h.


KSSTREAMALLOCATOR_FUNCTIONTABLE

This property retrieves the function table of the given allocator.

typedef struct {
    PFNALLOCATOR_ALLOCATEFRAME  AllocateFrame;
    PFNALLOCATOR_FREEFRAME      FreeFrame;
} KSSTREAMALLOCATOR_FUNCTIONTABLE, *PKSSTREAMALLOCATOR_FUNCTIONTABLE;

Members

AllocateFrame
FreeFrame

Headers

Declared in ks.h. Include ks.h.

Comments

This property is only supported by allocators supporting the DISPATCH_LEVEL function interface. Allocators supporting this property must be able to allocate and free frames at IRQL <= DISPATCH_LEVEL.

Because the DISPATCH_LEVEL interface is closely associated with the IRP-based interface, acquiring the function table is likely to result in the creation of an internal notification event to allow pending I/O to be completed when frames are returned to the free list. When the handle to the allocator is closed, the function table pointers are invalid and the associated events are automatically disabled.

This property is only accessible from kernel-mode.

DeviceIoControl(
    AllocatorHandle,
    IOCTL_KS_PROPERTY,
    &Allocator,
    sizeof(KSPROPERTY),
    &AllocatorFunctions,
    sizeof(KSSTREAMALLOCATOR_FUNCTIONTABLE),
    &BytesReturned,
    &Overlapped);


KSSTREAMALLOCATOR_STATUS

This property retrieves the current status of the given allocator.

typedef struct {
    KSALLOCATOR_FRAMING Framing;
    ULONG               AllocatedFrames;
    ULONG               Reserved;
} KSSTREAMALLOCATOR_STATUS, *PKSSTREAMALLOCATOR_STATUS;

Members

Framing
Contains the framing specified when the allocator was created.
AllocatedFrames
Contains the current number of allocated frames. Highly dynamic.
Reserved
Reserved and set to zero.

Headers

Declared in ks.h. Include ks.h.

Comments

This status indicates the framing specifications and the currently allocated frames.

DeviceIoControl(
    AllocatorHandle,
    IOCTL_KS_PROPERTY,
    &Allocator,
    sizeof(KSPROPERTY),
    &AllocatorStatus,
    sizeof(KSSTREAMALLOCATOR_STATUS),
    &BytesReturned,
    &Overlapped);


KSSTREAMALLOCATOR_STATUS_EX

The status for allocators supporting the extended allocator framing.

typedef struct {
    KSALLOCATOR_FRAMING_EX Framing;
    ULONG                  AllocatedFrames;
    ULONG                  Reserved;
} KSSTREAMALLOCATOR_STATUS_EX, *PKSSTREAMALLOCATOR_STATUS_EX;

Members

Framing
Contains the framing specified when the allocator was created.
AllocatedFrames
Contains the current number of allocated frames.
Reserved
Reserved and set to zero.

Headers

Declared in ks.h. Include ks.h.

Comments

Corresponds closely with KSSTREAMALLOCATOR_STATUS except that instead of passing back a KSALLOCATOR_FRAMING, it passes back the extended structure.


KSSTREAM_HEADER

The KSSTREAM_HEADER structure is a variable-length structure that describes a packet of data to be read from or written to a streaming driver pin.

typedef struct {
    ULONG       Size;
    ULONG       TypeSpecificFlags;
    KSTIME      PresentationTime;
    LONGLONG    Duration;
    ULONG       FrameExtent;
    ULONG       DataUsed;
    PVOID       Data;
    ULONG       OptionsFlags;
} KSSTREAM_HEADER, *PKSSTREAM_HEADER;

Members

Size
The size in bytes of the structure. Should be at least sizeof(KSSTREAM_HEADER).
TypeSpecificFlags
Flags specific to a data format.
PresentationTime
The presentation time for the related stream buffer, nominally in 100-nanoseconds units. This represents the presentation time of the initial sample in the stream data, and cannot be separately modified without knowledge of the data format. If the no-timestamp flag is set, this is ignored.
Duration
Optionally contains the duration of this stream segment in the same units as the presentation time. Set to zero when not used. This can be used to shorten the data presented from the amount of data actually passed. For instance, a set of MPEG frames may be passed all in a single block because of encryption constraints and the duration indicates the actual amount of data to be rendered.
FrameExtent
Specifies the size of the entire frame. The region within the frame extent is available to the filter and the resulting valid data size for the stream operation is reflected in the DataUsed member.
DataUsed
For a write operations, this field contains the number of bytes within the frame that are valid when submitting a frame to a lower-level driver. The headers are not modified on a write operation, however, IO_STATUS_BLOCK.Information contains the total number of bytes actually written. This is not the same as the return for a read operation. For a read operation, this field is not used when submitting a frame to a lower-level driver and must be set to 0. On return, this member contains the number of bytes actually filled in this frame and the IO_STATUS_BLOCK.Information field contains the size of the list of headers actually used.
Data
The virtual address of the data buffer.
OptionsFlags
Describes a variety of attributes of the data stream. The OptionsFlags member can have the following values:
#define    KSSTREAM_HEADER_OPTIONSF_SPLICEPOINT        0x00000001
#define    KSSTREAM_HEADER_OPTIONSF_PREROLL            0x00000002
#define    KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY    0x00000004
#define    KSSTREAM_HEADER_OPTIONSF_TYPECHANGED        0x00000008
#define    KSSTREAM_HEADER_OPTIONSF_TIMEVALID        0x00000010
#define    KSSTREAM_HEADER_OPTIONSF_TIMEDISCONTINUITY    0x00000040
#define    KSSTREAM_HEADER_OPTIONSF_FLUSHONPAUSE        0x00000080
#define    KSSTREAM_HEADER_OPTIONSF_DURATIONVALID        0x00000100
#define    KSSTREAM_HEADER_OPTIONSF_ENDOFSTREAM        0x00000200
#define    KSSTREAM_HEADER_OPTIONSF_LOOPEDDATA        0x80000000

Value | Description
KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY | Specifies that there has been a discontinuity in the data stream before the data contained in this packet. This implies that the filter may need to reset its internal state before processing the data. No actual data buffer need be attached.
KSSTREAM_HEADER_OPTIONSF_DURATIONVALID | The Duration member of this structure is valid.
KSSTREAM_HEADER_OPTIONSF_ENDOFSTREAM | Indicates that this frame represents the end of the data stream. This can then be used to generate an end-of-stream event.
KSSTREAM_HEADER_OPTIONSF_FLUSHONPAUSE | If the stream is paused, this buffer should be flushed. This parameter is used, for example, by live data sources, where a pause renders the current data stale.
KSSTREAM_HEADER_OPTIONSF_LOOPEDDATA | This data buffer is the start of looped data. The driver should loop on this data until explicitly stopped.
KSSTREAM_HEADER_OPTIONSF_PREROLL | The data in this buffer is used to prime the device state. This is a stream-specific option.
KSSTREAM_HEADER_OPTIONSF_SPLICEPOINT | The data stream is at a natural point for splicing. A client would use this, for example, when sending data that uses inter-frame compression, such as MPEG video, to indicate that it would be safe to splice at this point.
KSSTREAM_HEADER_OPTIONSF_TIMEDISCONTINUITY | There is a discontinuity in the data stream after this packet. This flag may be used for positional oriented interfaces to indicate an end of stream data. No actual data buffer need be attached.
KSSTREAM_HEADER_OPTIONSF_TIMEVALID | The PresentationTime member of this structure is valid. Indicates that this buffer has a valid timestamp associated with it.
KSSTREAM_HEADER_OPTIONSF_TYPECHANGED | The data format for this stream has changed. The data buffer actually contains the KSDATAFORMAT structure that defined the new format. Valid only for streams that have previously negotiated dynamic type changing. On a Stream Write, the new data format must be contained in place of a media sample, and if the media-specific extension size is different, must be the last header in a list of headers for that stream request. The data allocator is not used to contain the new media format. On a Stream Read, any further I/O remains pending until the new format is retrieved through KSPROPERTY_CONNECTION_DATAFORMAT. On a Stream Write, the header must not be extended, and must be the only header in the Write.

Headers

Declared in ks.h. Include ks.h.

Comments

This structure may be followed in memory by additional information specific to the type of data in the data packet.

The presentation time is normally in 100-nanosecond units, however the standard format of this time is based on the data format. For instance, this number might represent the current sample. This number can be normalized using the KSSTREAM_HEADER.PresentationTime.Numerator and KSSTREAM_HEADER.PresentationTime.Denominator as a scaling fractional. This allows time to be represented in a native format to reduce unnecessary conversions, but implies that the native value can be linearly scaled. A value of 1/1 indicates that no scaling is necessary. A conversion should use the Numerator first, then the Denominator, in order to reduce rounding errors. For example, an audio stream may present the current time as a byte offset in the data stream:

#define BITS_PER_BYTE    8
#define NANOSECONDS    10000000

StreamHdr->PresentationTime.Numerator = BITS_PER_BYTE * NANOSECONDS;
StreamHdr->PresentationTime.Denominator = BitsPerSample * Channels * Frequency;
StreamHdr->PresentationTime.Time = ByteOffset;
StreamHdr->Duration = ByteLength;

On an IOCTL_KS_READ_STREAM portions of the stream header are filled in by the call. Each KSSTREAM_HEADER.DataUsed element will contain the actual number of bytes read, which is less than or equal to each KSSTREAM_HEADER.FrameExtent. The pIrp->IoStatus.Information element will contain the total size of the header data to return, which is at least one sizeof(KSSTREAM_HEADER). The headers could be longer if this was defined by the data format.

On an IOCTL_KS_WRITE_STREAM, the member elements must be initialized, and each KSSTREAM_HEADER.DataUsed element contains the number of bytes to write. The actual number of total bytes written is returned in pIrp->IoStatus.Information. This is less than or equal to the total of all KSSTREAM_HEADER.DataUsed elements in the headers.


KSTIME

The KSTIME structure contains a time stamp.

typedef struct {
    LONGLONG    Time;
    ULONG       Numerator;
    ULONG       Denominator;
} KSTIME, *PKSTIME;

Members

Time
The time value, usually in 100-nanosecond units.
Numerator
If the time value is scaled, this is the numerator of the scaling factor. For a non-scaled value, this should be one. Numerator must not be zero.
Denominator
If the time value is scaled, this is the denominator of the scaling factor. For a non-scaled value, this should be one. Denominator must not be zero.

Headers

Declared in ks.h. Include ks.h.

Comments

Unscaled time stamps are in 100-nanosecond units. A data stream may use different units by specifying the numerator and denominator of a scale factor.


KSTOPOLOGY

A driver may use the KSTOPOLOGY structure to describe the topology of its pins and nodes.

typedef struct {
    ULONG CategoriesCount;
    const GUID* Categories;
    ULONG TopologyNodesCount;
    const GUID* TopologyNodes;
    ULONG TopologyConnectionsCount;
    const KSTOPOLOGY_CONNECTION* TopologyConnections;
    const GUID* TopologyNodesNames;
    ULONG Reserved;
} KSTOPOLOGY;

Members

CategoriesCount
The number of functional categories the driver supports.
Categories
Pointer to the beginning of the array of functional categories the driver supports.
TopologyNodesCount
The number of nodes the driver supports.
TopologyNodes
Pointer to the beginning of the array of GUIDs that describe the type of each node. This should be one of the KSNODE_XXX GUIDs defined in the header ksmedia.h.
TopologyConnectionsCount
The number of entries in the array pointed to by TopologyConnections. The node numbers of each entry must correspond to the array offset of the node within TopologyNodes. When this structure is a part of a streaming minidriver's HW_STREAM_HEADER, the pin numbers must correspond to the offsets within the array of HW_STREAM_INFORMATION structures within the minidriver's HW_STREAM_DESCRIPTOR structure.
TopologyConnections
Pointer to the beginning of the array of topology connections for this structure.
TopologyNodesNames
The GUID of the localized Unicode string name for the node, stored in the Registry.
Reserved
Reserved for system use. Drivers should set this to zero.

Headers

Declared in ks.h. Include ks.h.

Comments

A stream class minidriver creates and passes this structure as part of its HW_STREAM_HEADER structure. The class driver uses this structure to process topology property requests. The property data the class driver returns is determined from the KSTOPOLOGY structure as follows:

KSPROPERTY_TOPOLOGY_CATEGORIES
Returns the array that begins at the Categories member of KSTOPOLOGY.
KSPROPERTY_TOPOLOGY_CONNECTIONS
Returns the array that begins at the TopologyConnections member of KSTOPOLOGY.
KSPROPERTY_TOPOLOGY_NAME
KSPROPERTY_TOPOLOGY_NODES
Returns the array that begins at the Nodes member of KSTOPOLOGY.


KSTOPOLOGY_CONNECTION

The KSTOPOLOGY_CONNECTION structure describes a single data-path connection inside a KS filter. A streaming driver returns an array of KSTOPOLOGY_CONNECTION structures in response to a KSPROPERTY_TOPOLOGY_CONNECTIONS get-property request.

typedef struct {
    ULONG FromNode;
    ULONG FromNodePin;
    ULONG ToNode;
    ULONG ToNodePin;
} KSTOPOLOGY_CONNECTION;

Members

FromNode
Node ID of the node on the upstream end of the connection. If this end of the connection is an external pin on the filter--not a logical pin on a node--set this member to the null node-ID value, KSFILTER_NODE.
FromNodePin
Pin ID for the upstream end of the connection. If FromNode is KSFILTER_NODE, the pin on this end of the connection is an external pin on the filter. If not, the pin on this end is a logical pin on an internal node.
ToNode
Node ID of the node on the downstream end of the connection. If this end of the connection is an external pin on the filter--not a logical pin on a node--set this member to the null node-ID value, KSFILTER_NODE.
ToNodePin
Pin ID for the downstream end of the connection. If ToNode is KSFILTER_NODE, the pin on this end of the connection is an external pin on the filter. If not, the pin on this end is a logical pin on an internal node.

Headers

Declared in ks.h. Include ks.h.

Comments

KSTOPOLOGY_CONNECTION represents a single connection inside a filter, between either external pins, internal nodes, or an external pin and an internal node.

When representing a connection between two external pins, both FromNode and ToNode should be set to KSFILTER_NODE, and the FromNodePin and ToNodePin should be the pin type ID of the respective pins. (See KSPROPSETID_Pin for a description of pin type IDs.)

Otherwise, FromNodePin or ToNodePin represent a logical incoming or outgoing pin for the connection. The logical pin numbers are used solely to describe a connection between nodes: they have no existence outside of the KSPROPERTY_TOPOLOGY_CONNECTIONS property.

The PCCONNECTION_DESCRIPTOR structure name is an alias for KSTOPOLOGY_CONNECTION.

See Also

BdaPropertyTemplateConnections, PCCONNECTION_DESCRIPTOR, KSPROPERTY_TOPOLOGY_CONNECTIONS, KSPROPSETID_Topology


Kernel Streaming Functions

This section describes the functions and macros available to kernel-mode drivers through the KS libraries. Some of these, such as pin-related items, are described in more detail elsewhere and references are made to the detailed explanations.

  • Allocator Functions

    Functions that assist with the management of allocators.

  • Clock Functions

    Functions that assist with the management of clocks.

  • Method Set Functions

    Functions that assist with the management of method sets. These functions enable a filter or pin to present a method set to a client as well as perform some of the basic parameter validation and routing.

  • Property Set Functions

    Functions that assist with the management of property sets. These functions can enable a filter or pin to present a property set to a client as well as perform some of the basic parameter validation and routing.

  • Event Set Functions

    Functions that assist with the management of event sets.

  • Connection Functions

    Functions that assist in creating and destroying connections.

  • IRP Management Functions

    Functions that assist in general processing of IRPs.

  • Topology Management Functions

    Functions that assist in the management of a topology.

  • General Utility Functions

    Functions that are general helper functions.


Allocator Functions

This section specifies the helper functions for allocators. These functions allow a device object to create allocators, interface to the system default allocator, and validate creation requests. The following functions are provided:

KsCreateAllocator

KsCreateDefaultAllocator

KsValidateAllocatorCreateRequest

KsCreateDefaultAllocatorEx


KsCreateAllocator

The KsCreateAllocator function creates a handle to an allocator for the given sink connection handle. This function does not complete the IRP or set the status in the IRP.

KSDDKAPI NTSTATUS NTAPI
  KsCreateAllocator(
    IN HANDLE  ConnectionHandle,
    IN PKSALLOCATOR_FRAMING  AllocatorFraming,
    OUT PHANDLE  AllocatorHandle
    );

Parameters

ConnectionHandle
Specifies the handle to the sink connection on which to create the allocator.
AllocatorFraming
Specified framing for the allocator.
AllocatorHandle
Specifies the pointer to a handle to store the allocator handle.

Return Value

The KsCreateAllocator function returns STATUS_SUCCESS if successful, or it returns an error if unsuccessful.

Headers

Declared in ks.h. Include ks.h.

Comments

There are two versions of thhe KsCreateAllocator function: one for user-mode clients and one for kernel-mode clients. This function can only be called at PASSIVE_LEVEL for kernel-mode clients.

See Also

KSALLOCATOR_FRAMING


KsCreateDefaultAllocator

Given a validated IRP_MJ_CREATE request, the KsCreateDefaultAllocator function creates a default allocator that uses the specified memory pool and associates the IoGetCurrentIrpStackLocation(Irp)->FileObject with the allocator using an internal dispatch table (KSDISPATCH_TABLE).

KSDDKAPI NTSTATUS NTAPI
  KsCreateDefaultAllocator(
    IN PIRP  Irp
    );

Parameters

Irp
Specifies the IRP with the IRP_MJ_CREATE request being handled.

Return Value

The KsCreateDefaultAllocator function returns STATUS_SUCCESS if successful, or it returns an error if unsuccessful.

Headers

Declared in ks.h. Include ks.h.


KsCreateDefaultAllocatorEx

Creates a default allocator that uses the specified memory pool and associates the IoGetCurrentIrpStackLocation(pIrp)->FileObject with this allocator using an internal dispatch table (KSDISPATCH_TABLE).

KSDDKAPI NTSTATUS NTAPI
  KsCreateDefaultAllocatorEx(
    IN PIRP Irp,
    IN PVOID InitializeContext OPTIONAL,
    IN PFNKSDEFAULTALLOCATE DefaultAllocate OPTIONAL,
    IN PFNKSDEFAULTFREE DefaultFree OPTIONAL,
    IN PFNKSINITIALIZEALLOCATOR InitializeAllocator OPTIONAL,
    IN PFNKSDELETEALLOCATOR DeleteAllocator OPTIONAL    );

Parameters

Irp
Contains the IRP with the allocator create request being handled.
InitializeContext
Optionally contains a context to use with an external allocator. This is only used as the initialization context to the optional InitializeAllocator callback when creating an allocator context. The parameter is not otherwised used. If an external allocator is not provided, this parameter must be set to NULL.
DefaultAllocate
Optionally contains an external allocate function that is used in place of the default pool allocation. If this is NULL, default allocation is used.
DefaultFree
Optionally contains an external free function that is used in place of the default pool allocation. If an external allocator is not provided, this parameter must be set to NULL.
InitializeAllocator
Optionally contains an external allocator initialization function to which the InitializeContext parameter is passed. This function is expected to return an allocator context based on the allocator framing. If an external allocator is not provided, this parameter must be set to NULL.
DeleteAllocator
Optionally contains an external allocator delete function that is used for external allocators. If an external allocator is not provided, this parameter must be set to NULL.

Return Value

Returns STATUS_SUCCESS, else an error on default allocator creation failure. Does not complete the IRP or set the status in the IRP.

Headers

Declared in ks.h. Include ks.h.

Comments

Assumes that the KSCREATE_ITEM_IRP_STORAGE (IRP) points to the create item for this allocator, and assigns a pointer to it in the FsContext. This is used for any security descriptor queries or changes.


KsValidateAllocatorCreateRequest

The KsValidateAllocatorCreateRequest function validates an IRP_MJ_CREATE request as an allocator request and returns the create structure associated with the request on success.

KSDDKAPI NTSTATUS NTAPI
  KsValidateAllocatorCreateRequest(
    IN PIRP  Irp,
    OUT PKSALLOCATOR_FRAMING*  AllocatorFraming
    );

Parameters

Irp
Specifies the IRP with the IRP_MJ_CREATE request being validated.
AllocatorFraming
Caller-defined pointer that on successful completion contains an address to the framing structure supplied with the request.

Return Value

The KsValidateAllocatorCreateRequest function returns STATUS_SUCCESS if successful, or an error if the allocator request is not valid.

Headers

Declared in ks.h. Include ks.h.


Clock Functions

This section specifies the helper functions for clocks. These functions allow a device object to create clocks, interface to the system default clock, and validate creation requests. Internally the default clock implementation uses the shared structure KSIDEFAULTCLOCK. This allows a single structure to control many file object clients. There are specific functions for creating and manipulating one of these clock instances. This internal structure may change at any time and cannot be relied on externally. Externally, it is cast as a PVOID.

In order to allow convenient conversion from the performance counter time to 100-nanosecond units, a macro has been provided. KSCONVERT_PERFORMANCE_TIME performs an accurate 64-bit muldiv given the performance counter frequency and performance counter time, resulting in 100-nanosecond time units.

The following functions are provided:

KsCreateClock

KsCreateDefaultClock

KsAllocateDefaultClock

KsAllocateDefaultClockEx

KsFreeDefaultClock

KsValidateClockCreateRequest

KsGetDefaultClockState

KsSetDefaultClockState

KsGetDefaultClockTime

KsSetDefaultClockTime

Headers

Declared in ks.h. Include ks.h.


KsAllocateDefaultClock

The KsAllocateDefaultClock function allocates and initializes the default clock structure.

The function can only be called at PASSIVE_LEVEL.

KSDDKAPI NTSTATUS NTAPI
  KsAllocateDefaultClock(
    OUT PKSDEFAULTCLOCK*  DefaultClock
    );

Parameters

DefaultClock
Specifies the caller-allocated shared default clock structure. The current time is set to zero and the state is set to KSSTATE_STOP. Upon successful completion of this routine, the structure indicated by this pointer will contain a reference to the default clock. The data returned should be treated as opaque and reserved for system use.

Return Value

The KsAllocateDefaultClock function returns STATUS_SUCCESS if successful, or a memory error if unsuccessful.

Headers

Declared in ks.h. Include ks.h.

Comments

The internal DefaultClock.ReferenceCount element is initialized to one by the KsAllocateDefaultClock function. The element is incremented and decremented as each notification DPC is queued and completed. When the structure is to be freed, the element is used to determine if the owner of the clock should free the structure or if a pending DPC should free it asynchronously.

When the clock is no longer needed, the driver must call KsFreeDefaultClock to release any resources allocated for use with the clock.

See Also

KsFreeDefaultClock , KsAllocateDefaultClockEx


KsCreateClock

The KsCreateClock function creates a handle to a clock instance. The function can only be called at PASSIVE_LEVEL.

KSDDKAPI NTSTATUS NTAPI
  KsCreateClock(
    IN HANDLE  ConnectionHandle,
    IN PKSCLOCK_CREATE  ClockCreate,
    OUT PHANDLE  ClockHandle
    );

Parameters

ConnectionHandle
Specifies the handle to the connection on which to create the clock.
ClockCreate
Specifies clock create parameters. This currently consists of a flag that must be set to zero.
ClockHandle
Specifies the new clock handle.

Return Value

The KsCreateClock function returns STATUS_SUCCESS if successful, or it returns an error on clock creation failure.

Headers

Declared in ks.h. Include ks.h.


KsCreateDefaultClock

Given an IRP_MJ_CREATE request, the KsCreateDefaultClock function creates a default clock that uses the system clock as a time base and associates the IoGetCurrentIrpStackLocation(Irp)->FileObject with the clock using an internal dispatch table (KSDISPATCH_TABLE). Does not complete the IRP or set the status in the IRP.

The KsCreateDefaultClock function can only be called at PASSIVE_LEVEL.

KSDDKAPI NTSTATUS NTAPI
  KsCreateDefaultClock(
    IN PIRP  Irp,
    IN PKSDEFAULTCLOCK  DefaultClock
    );

Parameters

Irp
Specifies the IRP with the clock-create request being handled.
DefaultClock
Specifies an initialize default clock structure that is shared among any instance of the default clock for the parent.

Return Value

The KsCreateDefaultClock function returns STATUS_SUCCESS if successful, or an error if unsuccessful.

Headers

Declared in ks.h. Include ks.h.

Comments

The clock can be created after using KsAllocateDefaultClock to create and initialize the internal structures for a default clock instance. After initialization, many file objects can be created against the same underlying default clock instance.

See Also

KsAllocateDefaultClock


KsFreeDefaultClock

The KsFreeDefaultClock function frees a default clock structure previously allocated with KsAllocateDefaultClock, taking into account any currently running timer DPCs. This assumes that all instances of the clock have been closed. This may actually just decrement the internal reference counter and allow a pending DPC to free the structure asynchronously.

This may only be called at PASSIVE_LEVEL.

KSDDKAPI VOID NTAPI
  KsFreeDefaultClock(
    IN PKSDEFAULTCLOCK  DefaultClock
    );

Parameters

DefaultClock
Specifies the previously allocated structure to free.

Return Value

None

Headers

Declared in ks.h. Include ks.h.


KsGetDefaultClockState

The KsGetDefaultClockState function gets the current state of the clock.

The function can be called at DISPATCH_LEVEL.

KSDDKAPI KSSTATE NTAPI
  KsGetDefaultClockState(
    IN PKSDEFAULTCLOCK  DefaultClock
    );

Parameters

DefaultClock
Specifies an initialized, default clock structure that is shared among any instance of the default clock for the parent.

Return Value

The KsGetDefaultClockState function returns the current clock state.

Headers

Declared in ks.h. Include ks.h.

See Also

KsSetDefaultClockState


KsGetDefaultClockTime

The KsGetDefaultClockTime function gets the current time of the clock.

The function can be called at DISPATCH_LEVEL.

KSDDKAPI LONGLONG NTAPI
  KsGetDefaultClockTime(
    IN PKSDEFAULTCLOCK  DefaultClock
    );

Parameters

DefaultClock
Specifies an initialize default clock structure that is shared among any instance of the default clock for the parent.

Return Value

The KsGetDefaultClockTime function returns the current clock time.

Headers

Declared in ks.h. Include ks.h.

See Also

KsSetDefaultClockTime


KsSetDefaultClockState

The KsSetDefaultClockState function sets the current state of the clock that is used to reflect the current state of the underlying filter pin. The owner of the default clock is expected to serialize access to this function and to call KsSetDefaultClockTime.

The function can be called at DISPATCH_LEVEL.

KSDDKAPI VOID NTAPI
  KsSetDefaultClockState(
    IN PKSDEFAULTCLOCK  DefaultClock,
    IN KSSTATE  State
    );

Parameters

DefaultClock
Specifies an initialize default clock structure that is shared among any instance of the default clock for the parent.
State
Specifies the new state to set the clock.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

See Also

KsGetDefaultClockState


KsSetDefaultClockTime

The KsSetDefaultClockTime function sets the current time of the clock. It modifies the current time returned by the clock. The owner of the default clock is expected to serialize access to this function and to the KsSetDefaultClockState function.

The function can be called at DISPATCH_LEVEL.

KSDDKAPI VOID NTAPI
  KsSetDefaultClockTime(
    IN PKSDEFAULTCLOCK  DefaultClock,
    IN LONGLONG  Time
    );

Parameters

DefaultClock
Specifies an initialize default clock structure that is shared among instances of the default clock for the parent.
Time
Specifies the new time to set the clock.

Headers

Declared in ks.h. Include ks.h.

Return Value

None

See Also

KsGetDefaultClockTime


KsValidateClockCreateRequest

The KsValidateClockCreateRequest function validates the clock creation request and returns the create structure associated with the request.

This can only be called at PASSIVE_LEVEL.

KSDDKAPI NTSTATUS NTAPI
  KsValidateClockCreateRequest(
    IN PIRP  Irp,
    OUT PKSCLOCK_CREATE*  ClockCreate
    );

Parameters

lrp
Specifies the IRP with the clock create request being handled.
ClockCreate
Specifies the clock create structure pointer passed to the create request.

Return Value

The KsValidateClockCreateRequest function returns STATUS_SUCCESS if successful, or an error if unsuccessful.

Headers

Declared in ks.h. Include ks.h.


Method Set Functions

This section specifies method set handlers and the helper functions for method sets. When a device object presents a method set to a client, these helper functions can perform some of the basic parameter validation and routing based on a method set table.

The following helper functions are provided:

KsMethodHandler

KsMethodHandlerWithAllocator

KsFastMethodHandler

Typically, a class driver, such as AVStream, calls a helper function, such as the KsMethodHandler function, to handle a method requested through IOCTL_KS_METHOD. The helper function then determines the appropriate method handler function (MethodHandler) to call from the KSMETHOD structure that accompanies the IOCTL_KS_METHOD request. This MethodHandler call receives a prepared IRP, with parameters extracted. A pointer to the KSMETHOD_SET to which the method belongs is placed in the KSMETHOD_SET_IRP_STORAGE (Irp) field and the type of method request is placed in KSMETHOD_TYPE_IRP_STORAGE (Irp). This information is used when doing asynchronous processing on the method with KsDispatchSpecificMethod.

A method set item can additionally have a support handler (SupportHandler) that can be used to determine support for the particular method item. A pointer to the KSMETHOD_SET to which the method belongs is placed in the KSMETHOD_SET_IRP_STORAGE(Irp) field before calling the support handler.

When defining methods in a method set, a minidriver uses the MethodHandler and SupportHandler members of the KSMETHOD_ITEM structure to point to its implementations of MethodHandler and SupportHandler respectively.

The MethodHandler and SupportHandler functions have the following syntax:

typedef NTSTATUS
  (*PFNKSHANDLER)(
    IN     PIRP  Irp,
    IN     PKSIDENTIFIER  Request,
    IN/OUT PVOID  Data
    );

Parameters

Irp
Specifies the IRP that contains the method request.
Request
Specifies an aligned copy of the method parameter. This is typically a pointer to a KSMETHOD structure.
Data
Specifies an aligned copy of the method data parameter or the system address of the original data parameter, depending on the flag that was specified in the KSMETHOD_ITEM structure for the method.

Return Value

The MethodHandler function returns STATUS_SUCCESS if the method is handled and the data buffer has been filled per the flag that was specified in KSMETHOD_ITEM. Alternatively, MethodHandler returns the STATUS_SOME_NOT_MAPPED informational error if the method is handled but the particular request was not completed by MethodHandler and must be completed by the calling helper function. If it returns another error message, either the method is not supported or a parameter error occurred.

Headers

Declared in ks.h. Include ks.h.

Comments

The handler declaration used for MethodHandler and SupportHandler is also used for handlers of property and event sets, with the same parameters and return values.

When a helper function, such as KsMethodHandler, calls a method handler whose data buffer is defined as a write or modify buffer, the method handler must set the Information member of the IO_STATUS_BLOCK structure for the IoStatus member within the IRP (Irp parameter) to the size of that data buffer. A minidriver sets the Flags member of the KSMETHOD_ITEM structure for the method to KSMETHOD_TYPE_WRITE or KSMETHOD_TYPE_MODIFY to define the method handler's data buffer as write or modify respectively.

The following code snippet shows an example of an implementation of a method handler that sets the size of the returning data buffer in the IRP:

NTSTATUS
  MethodHandler(PIRP pIrp, PKSIDENTIFIER Request, PVOID Data) {
    NTSTATUS Status = STATUS_UNSUCCESSFUL;
    // Pointer to hold the position on the Irp stack
    PIO_STACK_LOCATION  pIrpStack  = NULL;
    ASSERT(pIrp);
    if(Data) {
        // Modify data here
    }
    // Find the current Irp stack.
    pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
    if(pIrpStack) {
        // Set the size of the returning Irp data.
        pIrp->IoStatus.Information =
          pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
        Status = STATUS_SUCCESS;
    }
    return(Status);
}

See Also

KSMETHOD, KsMethodHandler, KSMETHOD_ITEM, KSMETHOD_SET


KsFastMethodHandler

The KsFastMethodHandler function handles fast methods requested through IOCTL_KS_METHOD. It responds to all method identifiers defined by the sets that are also contained in the fast I/O list. This function can only be called at PASSIVE_LEVEL.

KSDDKAPI BOOLEAN NTAPI
  KsFastMethodHandler(
    IN PFILE_OBJECT  FileObject,
    IN PKSMETHOD UNALIGNED  Method,
    IN ULONG  MethodLength,
    IN OUT PVOID UNALIGNED  Data,
    IN ULONG  DataLength,
    OUT PIO_STATUS_BLOCK  IoStatus,
    IN ULONG  MethodSetsCount,
    IN  const KSMETHOD_SET  *MethodSet
    );

Parameters

FileObject
Specifies the file object on which the request was made.
Method
Specifies the original method parameter. This will always be on FILE_LONG_ALIGNMENT, but may not be on FILE_QUAD_ALIGNMENT.
MethodLength
Specifies the length indicated by the caller of the method parameter.
Data
Specifies the original unaligned data parameter.
DataLength
Specifies the length indicated by the caller of the data parameter.
IoStatus
Specifies an aligned structure that is used to return error status and information.
MethodSetsCount
Indicates the number of method set structures being passed.
MethodSet
Specifies the pointer to the list of method set information.

Return Value

The KsFastMethodHandler function returns TRUE if the request is handled, or FALSE if the request is not handled. If the request is not handled, an IRP is generated. If the request was handled, the function sets the IoStatus->Information element to zero because of an internal error or the element is set by a method handler. The method handler also sets the IoStatus->Status field when the method is handled.

Headers

Declared in ks.h. Include ks.h.

Comments

The owner of a method set can perform prefiltering or postfiltering of the method handling using the KsFastMethodHandler and KsMethodHandler functions. The KsFastMethodHandler function is used to process requests made through the fast I/O dispatch interface for Device Control. It is only used to process requests that can be fulfilled quickly. The Wait parameter of the fast I/O function is not passed and assumed to be TRUE.

See Also

Method Set Functions, KsMethodHandler


KsMethodHandler

The KsMethodHandler function handles methods requested through IOCTL_KS_METHOD. It works with all method identifiers defined by the sets. The function can only be called at PASSIVE_LEVEL.

KSDDKAPI NTSTATUS NTAPI
  KsMethodHandler(
    IN PIRP  Irp,
    IN ULONG  MethodSetsCount,
    IN KSMETHOD_SET  MethodSet
    );

Parameters

Irp
Specifies the IRP with the method request being handled.
MethodSetsCount
Indicates the number of method set structures being passed.
MethodSet
Specifies the pointer to the list of method set information.

Return Value

The KsMethodHandler function returns STATUS_SUCCESS if successful, or an error specific to the method being handled if unsuccessful. The function always sets the IO_STATUS_BLOCK.Information field of the PIRP.IoStatus element within the IRP to zero because of an internal error, unless the element is set by a method handler. For information on a method handler setting this element, see the Comments section of Method Set Functions. The function does not set the IO_STATUS_BLOCK.Status field nor complete the IRP.

Headers

Declared in ks.h. Include ks.h.

Comments

The owner of a method set can perform pre-filtering or post-filtering of the method handling using the KsMethodHandler and KsFastMethodHandler functions.

See Also

Method Set Functions, KsFastMethodHandler


KsMethodHandlerWithAllocator

The KsMethodHandlerWithAllocator functions performs the same handling as KsMethodHandler, with the same restrictions, but allows an optional allocator callback to be used to provide a buffer for the parameters. If used, the filter may need to free the buffer in some nonconventional manner. Note that the IRP_BUFFERED_IO and IRP_DEALLOCATE_BUFFER flags are not set when using a custom allocator.

KSDDKAPI NTSTATUS NTAPI
  KsMethodHandlerWithAllocator(
    IN PIRP  Irp,
    IN ULONG  MethodSetsCount,
    IN PKSMETHOD_SET  MethodSet,
    IN PFNKSALLOCATOR  Allocator  OPTIONAL,
    IN ULONG  MethodItemSize  OPTIONAL,
    );

Parameters

Irp
Specifies the IRP with the method request being handled.
MethodSetsCount
Indicates the number of method set structures being passed.
MethodSet
Specifies the pointer to the list of method set information.
Allocator
Optionally points to an allocation function that will be used to allocate memory to store the method parameters.
MethodItemSize
Optionally contains the size of each KSMETHOD_ITEM structure in each list of methods. The method item may be extended in order to store private information. If this parameter is zero, the structure size is assumed to be normal. If it is greater than or equal to a method item structure, the KSMETHOD_ITEM_IRP_STORAGE macro can be used to return a pointer to the method item so the custom data can be retrieved.

Return Value

The KsMethodHandler function returns STATUS_SUCCESS if successful, or an error specific to the method being handled if unsuccessful. The function always sets the IO_STATUS_BLOCK.Information field of the PIRP.IoStatus element within the IRP to zero because of an internal error, or the element is set by a method handler. The function does not set the IO_STATUS_BLOCK.Status field nor complete the IRP.

Headers

Declared in ks.h. Include ks.h.


Property Set Functions

This section specifies the helper functions for property sets and property set handlers. When a device object presents a property set to a client, these functions can perform some of the basic parameter validation and routing based on a property set table.

The following functions are provided:

KsFastPropertyHandler

KsPropertyHandler

KsPropertyHandlerWithAllocator

KsUnserializeObjectPropertiesFromRegistry

The property set handlers include PFNKSHANDLER and PFNKSFASTHANDLER, and are described in the following text.

PFNKSHANDLER

PFNKSHANDLER defines the entry point for a specific handler of a property within a property set and is the type of function that is called by a general property set handler for a specific property. A pointer to the KSPROPERTY_SET to which the property belongs is then placed in the KSPROPERTY_SET_IRP_STORAGE(Irp) field.

typedef NTSTATUS (*PFNKSHANDLER)(
  IN PIRP  Irp,
  IN PKSIDENTIFIER  Request,
  IN OUT PVOID  Data
  );

Parameters

Irp
Specifies the original IRP passed to the property handler function.
Request
Specifies an aligned copy of the property parameter.
Data
Specifies an aligned copy of the property data parameter or a place in which to return data.

Return Value

The callback PFNKSHANDLER returns STATUS_SUCCESS if successful, or an error specific to the property being handled if unsuccessful. If data is being returned, it sets the Irp->IoStatus.Information field, but does not set the Irp->IoStatus.Status field nor does it complete the IRP. It can mark the IRP pending if it is to be completed asynchronously.

PFNKSFASTHANDLER

PFNKSFASTHANDLER circumvents the creation of an IRP in order to process a request if a property set contains fast I/O implementations. If implemented, it is in addition to and not a replacement for, typical IRP handlers. These handlers must deal with unaligned data and possible access violations; they are only used when the property can be quickly processed.

typedef BOOLEAN (*PFNKSFASTHANDLER)(
  IN PFILE_OBJECT  FileObject,
  IN PKSIDENTIFIER UNALIGNED  Request,
  IN ULONG  RequestLength,
  IN OUT PVOID UNALIGNED  Data,
  IN ULONG  DataLength,
  OUT PIO_STATUS_BLOCK  IoStatus
  );

Parameters

FileObject
Specifies the file object on which the request was made.
Request
Specifies the original property parameter. This will always be on FILE_LONG_ALIGNMENT, but can not be on FILE_QUAD_ALIGNMENT.
RequestLength
Specifies the length indicated by the caller of the property parameter.
Data
Specifies the original unaligned data parameter.
DataLength
Specifies the length indicated by the caller of the data parameter.
IoStatus
Specifies an aligned structure that is used to return error status and information. This information is then copied to the original I/O status structure on completion.

Return Value

PFNKSFASTHANDLER returns TRUE if the call was handled. If the call was not handled, it returns FALSE and an IRP is generated to handle the request.

Headers

Declared in ks.h. Include ks.h.


KsFastPropertyHandler

The KsFastPropertyHandler function handles fast property requests through IOCTL_KS_PROPERTY. It responds to all property identifiers defined by the sets that are also contained in the fast I/O list. This function can only be called at PASSIVE_LEVEL.

KSDDKAPI BOOLEAN NTAPI
  KsFastPropertyHandler(
    IN PFILE_OBJECT  FileObject,
    IN PKSPROPERTY UNALIGNED  Property,
    IN ULONG  PropertyLength,
    IN OUT PVOID UNALIGNED  Data,
    IN ULONG  DataLength,
    OUT PIO_STATUS_BLOCK  IoStatus,
    IN ULONG  PropertySetsCount,
    IN const KSPROPERTY_SET  *PropertySet
    );

Parameters

FileObject
Specifies the file object on which the request was made.
Property
Specifies the original method parameter. This is always on FILE_LONG_ALIGNMENT, but may not be on FILE_QUAD_ALIGNMENT.
PropertyLength
Specifies the length indicated by the caller of the property parameter.
Data
Specifies the original unaligned data parameter.
DataLength
Specifies the length indicated by the caller of the data parameter.
IoStatus
Specifies an aligned structure used to return error status and information.
PropertySetsCount
Indicates the number of property set structures being passed.
PropertySet
Specifies the pointer to the list of property set information.

Return Value

The KsFastPropertyHandler function returns TRUE if the request was handled, or FALSE if the request was not handled. If FALSE is returned, an IRP is generated. If the request was handled, the function sets the IoStatus->Information element, either through setting it to zero because of an internal error, or through a property handler setting it. The property handler also sets the IoStatus->Status field when the property is actually handled.

Headers

Declared in ks.h. Include ks.h.

Comments

The owner of a property set can perform prefiltering or postfiltering of the property handling, as well as processing requests made through the fast I/O dispatch interface for device control. The KsFastPropertyHandler function is only used to process requests that can be fulfilled quickly. The Wait parameter of the fast I/O function is not passed and is assumed to be TRUE.

See Also

Property Set Functions, KsPropertyHandler


KsPropertyHandler

Drivers call KsPropertyHandler function for IRP handling.

KSDDKAPI NTSTATUS NTAPI
  KsPropertyHandler(
    IN PIRP  Irp,
    IN ULONG  PropertySetsCount,
    IN  const KSPROPERTY_SET  *PropertySet
    );

Parameters

Irp
Specifies the IRP with the property request being handled.
PropertySetsCount
Specifies the number of property sets being passed.
PropertySet
Points to an array of KSPROPERTY_SET structures. The driver should provide one structure for each property set it wants KsPropertyHandler to handle.

Return Value

The KsPropertyHandler function returns STATUS_SUCCESS if successful, or an error specific to the property being handled if unsuccessful. The function sets the IRP->IO_STATUS_BLOCK.Information member, either through setting it to zero because of an internal error, or through a property handler setting it. The function does not set the lrp->IoStatus.Status member nor does it complete the IRP.

Headers

Declared in ks.h. Include ks.h.

Comments

KsPropertyHandler responds to all property identifiers defined by the sets, and can only be called at PASSIVE_LEVEL.

Each KSPROPERTY_SET entry contains a pointer to an array of KSPROPERTY_ITEM structures in its PropertyItem member. For driver-specific processing, KsPropertyHandler hands off each request to one of the driver-supplied callbacks within PropertyItem. KsPropertyHandler takes care of any IRP processing required.

KsPropertyHandler does not use the FastIoTable member of its KSPROPERTY_SET structure. If the driver needs to support Fast I/O handling of requests, the same KSPROPERTY_SET structure should be passed to the KsFastPropertyHandler routine.

The owner of the property sets can perform prefiltering or postfiltering of property handling. Basic property structure access exceptions are handled by the KsPropertyHandler function, though cleanup for specific exceptions must be covered by the property handler.

See Also

Property Set Functions, KsFastPropertyHandler


KsPropertyHandlerWithAllocator

The KsPropertyHandlerWithAllocator performs the same handling as KsPropertyHandler, with the same restrictions, but allows an optional allocator callback to be used to provide a buffer for the parameters. If used, the filter may need to free the buffer in some nonconventional manner. IRP_BUFFERED_IO and IRP_DEALLOCATE_BUFFER flags are not set when using a custom allocator.

KSDDKAPI NTSTATUS NTAPI
  KsPropertyHandlerWithAllocator(
    IN PIRP  Irp,
    IN ULONG  PropertySetsCount,
    IN PKSPROPERTY_SET  PropertySet,
    IN PFNKSALLOCATOR  Allocator  OPTIONAL,
    IN ULONG  PropertyItemSize  OPTIONAL,
    );

Parameters

Irp
Specifies the IRP with the property request being handled.
PropertySetsCount
Specifies the number of property sets being passed.
PropertySet
Specifies the pointer to an array of property set information.
Allocator
Optionally points to an allocation function used to allocate memory to store the property parameters. See Event Set Functions.
PropertyItemSize
Optionally contains the size of each KSPROPERTY_ITEM structure in the properties. The property item may be extended in order to store private information. If this parameter is zero, the structure size is assumed to be normal. If it is greater than or equal to a property item structure, the KSPROPERTY_ITEM_IRP_STORAGE macro can be used to return a pointer to the property item so the custom data can be retrieved.

Return Value

The KsPropertyHandler function returns STATUS_SUCCESS if successful, or an error specific to the property being handled if unsuccessful. The function sets the Irp->IoStatus.Information member, either through setting it to zero because of an internal error, or through a property handler setting it. The function does not set the lrp->IoStatus.Status member nor does it complete the IRP.

Headers

Declared in ks.h. Include ks.h.


KsUnserializeObjectPropertiesFromRegistry

The KsUnserializeObjectPropertiesFromRegistry function, when given a destination object and a registry path, enumerates the named values and applies them as serialized data to the specified property sets listed in the serialized data. An IRP is generated when sending the serialized data, so no assumption is made on use of KS property structures to internally define the property sets. The function does not use the names of the values.

KSDDKAPI NTSTATUS NTAPI
  KsUnserializeObjectPropertiesFromRegistry(
    IN PFILE_OBJECT  FileObject,
    IN HANDLE  ParentKey  OPTIONAL,
    IN PUNICODE_STRING  RegistryPath  OPTIONAL
    );

Parameters

FileObject
Specifies the file object whose properties are being set.
ParentKey
Optionally contains a handle to the parent of the path, or NULL. The Parent Key and/or the RegistryPath must be passed.
RegistryPath
Optionally contains the path to the key whose subkeys will be enumerated as property sets, or otherwise NULL. The ParentKey and/or the Registry Path must be passed.

Return Value

The KsUnserializeObjectPropertiesFromRegistry function returns STATUS_SUCCESS if the property sets were unserialized. The function returns an error if the registry path was invalid, one of the subkeys was invalid, setting a property was unsuccessful, the serialized format was invalid, or a property set was not supported on the object.

Headers

Declared in ks.h. Include ks.h.

See Also

Property Set Functions


Event Set Functions

This section contains the helper functions for event sets and event generating code. These functions allow a device object to present an event set to a client and to perform some of the basic parameter validations and routing based on an event set table.

The following functions are provided:

KsGenerateEvent

KsEnableEventWithAllocator

KsGenerateDataEvent

KsGenerateEventList

KsEnableEvent

KsDiscardEvent

KsDisableEvent

KsFreeEventList

The PFNKSADDEVENT function prototype defines the entry point for an event set list add handler:

typedef NTSTATUS (*PFNKSADDEVENT)(
  IN PIRP  Irp,
  IN PKSEVENTDATA  EventData,
  IN struct _KSEVENT_ENTRY*  EventEntry
  );

Parameters

Irp
Specifies the original enable IRP passed to the event handler function.
EventData
Specifies an aligned copy of the original data attached to the event request.
EventEntry
Specifies the initialized entry that was created for the event request.

Return Value

The callback should return STATUS_SUCCESS or an error specific to the event being enabled. The function does not set the Irp->IoStatus.Information and Irp->IoStatus.Status fields, nor does it complete the IRP. It may mark the IRP pending if it is to be completed asynchronously. However, if enabling the event subsequently fails, KsDiscardEvent must be used to free the event entry data allocated by KsEnableEvent.

The PFNKSREMOVEEVENT function prototype defines the entry point for an event set list-remove handler:

typedef VOID (*PFNKSREMOVEEVENT)(
  IN PFILE_OBJECT  FileObject,
  IN struct _KSEVENT_ENTRY*  EventEntry
  );

Parameters

FileObject
Contains the file object on which the request was made.
EventEntry
Specifies the entry that was originally created for the event request.

Return Value

The callback must succeed.

Comments

The function allows a filter pin or master clock to keep separate lists for different types of events. Event set list handlers are specified for each event set.

The PFNKSALLOCATOR callback function is optionally used as a parameter to KsEnableEventWithAllocator, KsPropertyHandlerWithAllocator, and KsMethodHandlerWithAllocator. It specifies a filter-provided function that is used to allocate memory for data buffers. Normally pool memory is used for buffer allocations. This enables filters that pass event, property, and method queries directly to hardware to avoid extra data copies by allowing them to provide the buffer into which such data is placed by the standard handling functions. Thus, a filter may have memory blocks that already have been mapped to an adapter from which buffer allocations can occur.

Since this memory presumably is not normal pool allocated memory, the filter must perform buffer cleanup on completion of the IRP. This means that for input operations from user mode that are not synchronous, the allocator must allocate an MDL for the destination buffer, probe and lock it, and retrieve a system address. This must be done in order to enable copying of the return data to the original buffer.

Typedef NTSTATUS (*PFNKSALLOCATOR)(
  IN PIRP  Irp,
    IN ULONG  BufferSize,
    IN BOOL  InputOperation
    );

Parameters

Irp
Specifies the IRP for which the buffer allocation request is being made.
BufferSize
Specifies the size of buffer needed. This size covers all parameters in the request.
InputOperation
Set to TRUE if this is an input operation, meaning that on successful return, the Irp->IoStatus.Information field will contain the number of bytes to copy back to the original input buffer.

Comments

Typically, pool memory is used for buffer allocations. This enables filters that pass event, property, and method queries directly to hardware to avoid extra data copies by allowing them to provide the buffer into which such data is placed by the standard handling functions. So, a filter may have memory blocks that have already been mapped to an adapter from which buffer allocations can occur.

Since this memory presumably is not typical pool-allocated memory, the filter must perform buffer cleanup on completion of the Irp. This means that for input operations from usermode that are not synchronous, the allocator must allocate an MDL for the destination buffer, probe and lock it, and retrieve a system address. This must be done in order to enable copying of the return data to the original buffer.


KsDisableEvent

The KsDisableEvent function disables events requested through IOCTL_KS_DISABLE_EVENT. It responds to all events previously enabled through KsEnableEvent. If the input buffer length is zero, it is assumed that all events on the list are to be disabled. This function can only be called at PASSIVE_LEVEL.

KSDDKAPI NTSTATUS NTAPI
  KsDisableEvent(
    IN PIRP  Irp,
    IN OUT PLIST_ENTRY  EventsList,
    IN KSEVENTS_LOCKTYPE  EventsFlags,
    IN PVOID  EventsLock
    );

Parameters

Irp
Specifies the IRP passed to the removal function, which uses the IRP to obtain context information. The file object associated with the IRP is used to compare against the file object originally specified when enabling the event. This allows a single event list to be used for multiple clients differentiated by file objects.
EventsList
Points to the head of the list of KSEVENT_ENTRY items on which the event may be found. If a client uses multiple event lists and does not know what list this event is on, the client can call this function multiple times. An event not found will return STATUS_UNSUCCESSFUL.
EventsFlags
Specifies a KSEVENTS_LOCKTYPE flag specifying the type of exclusion lock to be used in accessing the event list. If no flag is set, then no lock is taken.
EventsLock
Used to synchronize access to an element on the list. After the element has been accessed, it is marked as being deleted so that subsequent removal requests fail. The lock is then released after calling the removal function, if any. The removal function must synchronize with event generation before actually removing the element from the list.

Return Value

The KsDisableEvent function returns STATUS_SUCCESS if successful, or an error specific to the event being enabled. The function always sets the IO_STATUS_BLOCK.Information field of the PIRP.IoStatus element within the IRP to zero. It does not set the IO_STATUS_BLOCK.Status field, nor does it complete the IRP.

Headers

Declared in ks.h. Include ks.h.

Comments

It is important that the remove handler synchronize with event generation to ensure that when the event is removed from the list, it is not currently being serviced. Access to this list is assumed to be controlled with the lock passed.

See Also

Event Set Functions, KsEnableEvent


KsDiscardEvent

The KsDiscardEvent function discards the memory used by an event entry after the objects have been dereferenced. The function can be called when manually disabling events that have not been disabled by the event owner (by calling the KsFreeEventList function to disable events). For example, the function can be called when asynchronously enabling an event fails and the event entry needs to be discarded.

KSDDKAPI VOID NTAPI
  KsDiscardEvent(
    IN PKSEVENT_ENTRY  EventEntry
    );

Parameters

EventEntry
Specifies the pointer to the entry to discard. This pointer is no longer valid after a successful call to this function.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

Typically, the KsDiscardEvent function is automatically called by the KsDisableEvent function when a request to disable an event occurs, or by the KsFreeEventList function when a request to free a list of events occurs. This function can only be called at PASSIVE_LEVEL.

See Also

Event Set Functions


KsEnableEvent

The KsEnableEvent function enables events requested through IOCTL_KS_ENABLE_EVENT. It responds to all event identifiers defined by the sets. This function can only be called at PASSIVE_LEVEL.

KSDDKAPI NTSTATUS NTAPI
  KsEnableEvent(
    IN PIRP  Irp,
    IN ULONG  EventSetsCount,
    IN KSEVENT_SET*  EventSet,
    IN OUT PLIST_ENTRY  EventsList  OPTIONAL,
    IN KSEVENTS_LOCKTYPE  EventsFlags  OPTIONAL,
    IN PVOID  EventsLock  OPTIONAL
    );

Parameters

Irp
Specifies the IRP with the enable request being handled. The file object associated with the IRP is stored with the event for later comparison when disabling the event.
EventSetsCount
Indicates the number of event set structures being passed.
EventSet
Specifies a pointer to the list of event set information.
EventsList
If the enabling event's KSEVENT_SET.AddHandler for the event set is NULL, it must point to the head of the list of KSEVENT_ENTRY items on which the event is to be added. This function assumes a single list for at least a subset of events.
EventsFlags
Specifies KSEVENTS_LOCKTYPE flags specifying the type of exclusion lock to be used in accessing the event list, if any. If no flag is set, then no lock is taken. If a handler is specified already, this parameter is ignored.
EventsLock
If the KSEVENT_SET.AddHandler for the event set containing the event being enabled is NULL, then this is used to synchronize access to the list. This value can be NULL if no flag is set in EventsFlags.

Return Value

The KsEnableEvent function returns STATUS_SUCCESS if successful, or an error specific to the event being enabled if unsuccessful. The function always sets the IO_STATUS_BLOCK.Information field of the PIRP.IoStatus element within the IRP to zero. It does not set the IO_STATUS_BLOCK.Status field, nor does it complete the IRP.

Headers

Declared in ks.h. Include ks.h.

See Also

Event Set Functions


KsEnableEventWithAllocator

The KsEnableEventWithAllocator function enables events requested through IOCTL_KS_ENABLE_EVENT but also allows an optional allocator callback to be used to provide a buffer for the parameters. It responds to all event identifiers defined by the sets. This function can only be called at PASSIVE_LEVEL.

If used, the filter may need to free the buffer in some nonconventional manner. Note that the IRP_BUFFERED_IO and IRP_DEALLOCATE_BUFFER flags are not set when using a custom allocator.

KSDDKAPI NTSTATUS NTAPI
  KsEnableEventWithAllocator(
    IN PIRP  Irp,
    IN ULONG  EventSetsCount,
    IN PKSEVENT_SET  EventSet,
    IN OUT PLIST_ENTRY  EventsList  OPTIONAL,
    IN KSEVENTS_LOCKTYPE  EventsFlags  OPTIONAL,
    IN PVOID  EventsLock  OPTIONAL,
    IN PFNKSALLOCATOR  Allocator  OPTIONAL,
    IN ULONG  EventItemSize  OPTIONAL
    );

Parameters

Irp
Specifies the IRP with the enable request being handled. The file object associated with the IRP is stored with the event for later comparison when disabling the event.
EventSetsCount
Indicates the number of event set structures being passed.
EventSet
Specifies a pointer to the list of event set information.
EventsList
If the enabling event's KSEVENT_SET.AddHandler for the event set is NULL, it must point to the head of the list of KSEVENT_ENTRY items on which the event is to be added. This function assumes a single list for at least a subset of events.
EventsFlags
Specifies KSEVENTS_LOCKTYPE flags specifying the type of exclusion lock to be used in accessing the event list, if any. If no flag is set, then no lock is taken. If a handler is specified already, this parameter is ignored.
EventsLock
If the KSEVENT_SET.AddHandler for the event set containing the event being enabled is NULL, then this is used to synchronize access to the list. This value can be NULL if no flag is set in EventsFlags.
Allocator
Optionally points to an allocation function that will be used to allocate memory to store the event parameters.
EventItemSize
Optionally contains the size of each KSEVENT_ITEM structure in each list of events. The event item may be extended in order to store private information. If this parameter is zero, the structure size is assumed to be normal. If it is greater than or equal to an event item structure, the KSEVENT_ITEM_IRP_STORAGE macro can be used to return a pointer to the event item so the custom data can be retrieved.

Return Value

Same as KsEnableEvent, which returns STATUS_SUCCESS if successful, or an error specific to the event being enabled if unsuccessful. The function always sets the IO_STATUS_BLOCK.Information field of the PIRP.IoStatus element within the IRP to zero. It does not set the IO_STATUS_BLOCK.Status field, nor does it complete the IRP.

Headers

Declared in ks.h. Include ks.h.

Comments

If the optional allocator callback is used, the filter may need to free the buffer in some nonconventional manner. Note that the IRP_BUFFERED_IO and IRP_DEALLOCATE_BUFFER flags are not set when using a custom allocator.


KsFreeEventList

The KsFreeEventList function handles freeing all events from a specified list, with the assumption that these events are composed of KSEVENT_ENTRY structures. This function can only be called at PASSIVE_LEVEL.

KSDDKAPI VOID NTAPI
  KsFreeEventList (
    IN PFILE_OBJECT  FileObject,
    IN OUT PLIST_ENTRY  EventsList,
    IN KSEVENTS_LOCKTYPE  EventsFlags,
    IN PVOID  EventsLock
    );

Parameters

FileObject
Specifies the file object passed to the removal function for context information. The file object associated is used to compare against the file object originally specified when enabling the event. This allows a single event list to be used for multiple clients differentiated by file objects.
EventsList
Points to the head of the list of KSEVENT_ENTRY items to be freed. If any events on the list are currently being disabled, they are passed over. If any new elements are added to the list while it is being processed, they may not be freed.
EventsFlags
Specifies a KSEVENTS_LOCKTYPE flag specifying the type of exclusion lock to be used in accessing the event list. If no flag is set, then no lock is taken.
EventsLock
Used to synchronize access to an element on the list. After the element has been accessed, it is marked as being deleted so subsequent removal requests fail. The lock is then released after calling the removal function, if any. The removal function must synchronize with event generation before actually removing the element from the list.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

The KsFreeEventList function calls the remove handler, then it calls KsDiscardEvent for each event. It does not assume that the caller is the event owner.

See Also

Event Set Functions, KsDiscardEvent


KsGenerateDataEvent

The KsGenerateDataEvent function generates one of the standard event notifications when given an event entry structure and callback data. This allows a device to determine when event notifications should be generated, yet still use this helper function to perform the actual notification. This function may be called at IRQL level.

KSDDKAPI NTSTATUS NTAPI
  KsGenerateDataEvent(
    IN PKSEVENT_ENTRY  EventEntry,
    IN ULONG  DataSize,
    IN PVOID  Data
    );

Parameters

EventEntry
Specifies the event entry structure that references the event data. The information is used to determine what type of notification to perform. If the notification type is not one of the predefined standards, an error is returned. In the case of a single, nonrecurring event, this entry will be invalid when returned from the function. Therefore, any code that enumerates a list of events must pre-increment to acquire the next event in the list before passing this event to the function.
DataSize
Specifies the size in bytes of the Data parameter passed.
Data
Points to data to be passed to the client callback. This data is copied to one of the preallocated buffer slots set up when the event was enabled. The size of the data must be less than whatever was originally allocated or the event will fail.

Return Value

The KsGenerateDataEvent function returns STATUS_SUCCESS if successful, or if unsuccessful it returns an exception or memory error.

Headers

Declared in ks.h. Include ks.h.

Comments

It is assumed that the event list lock has been acquired before this function is called. This function can result in a call to the RemoveHandler for the event entry. Therefore, the function must not be called at higher than the IRQ level of the lock, or the Remove function must be able to handle being called at such an IRQ level.

This function is specifically for events that pass data back through a callback to a client.

See Also

Event Set Functions


KsGenerateEvent

The KsGenerateEvent function generates a standard event notification given an event entry structure. A device determines when event notifications are generated using the KSEVENT_ENTRY structure, then uses this function to perform the actual notification. This function can be called at IRQL level.

KSDDKAPI NTSTATUS NTAPI
  KsGenerateEvent(
    IN PKSEVENT_ENTRY  EventEntry
    );

Parameters

EventEntry
Specifies the event entry structure that references the event data. The information is used to determine what type of notification to perform. If the notification type is not one of the predefined standards, an error is returned. In the case of a single, nonrecurring event, this entry will be invalid on returning from the function. Therefore, any code that enumerates a list of events must pre-increment to acquire the next event in the list before passing this event to the function.

Return Value

The KsGenerateEvent function returns STATUS_SUCCESS if successful, or if unsuccessful it returns an exception or memory error.

Headers

Declared in ks.h. Include ks.h.

See Also

Event Set Functions


KsGenerateEventList

The KsGenerateEventList function enumerates the event list and searches for the specified event to generate. It can be called at IRQL level if the locking mechanism permits it.

KSDDKAPI VOID NTAPI
  KsGenerateEventList(
    IN GUID*  Set OPTIONAL,
    IN ULONG  EventId,
    IN PLIST_ENTRY  EventsList,
    IN KSEVENTS_LOCKTYPE  EventsFlags,
    IN PVOID  EventsLock
    );

Parameters

Set
Specifies an optional set that the event to be generated belongs to. If present, this value is compared against the set identifier for each event in the list. If not present, the set identifiers are ignored and just the specific event identifier is used in the comparison for matching events on the list. This comparison saves time when all events are known to be contained in a single set.
EventId
Specifies the specific event identifier to look for on the list.
EventsList
Points to the head of the list of KSEVENT_ENTRY items on which the event can be found.
EventsFlags
Specifies the KSEVENTS_LOCKTYPE flag specifying the exclusion lock type to be used in accessing the event list. If no flag is set, then no lock is taken.
EventsLock
Used to synchronize access to an element on the list. The lock is taken before enumerating the list and released after enumeration.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

See Also

Event Set Functions


Connection Functions

Several WDM Streaming functions assist with creating and destroying connections. The following functions are provided:

KsCreatePin

KsValidateConnectRequest

KsPinPropertyHandler

KsPinDataIntersection

KsHandleSizedListQuery

For more information on functions that handle IRPs, see the IRP Management Functions.


KsCreatePin

The KsCreatePin function passes a connection request to a device, creating a pin instance. This function can only be called at PASSIVE_LEVEL for kernel-mode clients.

KSDDKAPI NTSTATUS NTAPI
  KsCreatePin(
    IN HANDLE  FilterHandle,
    IN PKSPIN_CONNECT  Connect,
    IN ACCESS_MASK  DesiredAccess,
    OUT PHANDLE  PinHandle
    );

Parameters

FilterHandle
Specifies the handle of the filter initiating the create request and where the connection will occur.
Connect
Specifies a system address that is the connection information. This should be followed in memory by a KSDATAFORMAT data structure, describing the data format requested for the connection.
DesiredAccess
Specifies the access desired to the pin. This is typically FILE_READ_ACCESS or FILE_WRITE_ACCESS. For data flowing into the pin this value should be set to FILE_WRITE_ACCESS, and for data flowing out of the pin this should be set to FILE_READ_ACCESS regardless of the communication method.
ConnectionHandle
Specifies the connection handle passed. The routine fills this in with a handle to the file object of the created connection. This value can then be used to disconnect with CloseHandle.

Return Value

The KsCreatePin function returns STATUS_SUCCESS if the connection was successful, or it returns an error if the connection failed.

Headers

Declared in ks.h. Include ks.h.

Comments

The routine sends a IRP_MJ_CREATE request to the driver. The driver accepts the request only if the interface, medium, and data format are compatible

If Connect->PinToHandle is NULL, KsCreatePin creates a pin the caller can use to send requests to the streaming driver specified in Connect->FilterHandle.. Connect->PinId determines the pin type of the pin to be created.


KsHandleSizedListQuery

The KsHandleSizedListQuery function, depending on the length of the system buffer, returns either the size of the buffer needed, number of entries in the specified data list, or copies the entries themselves. This assumes the structure of KSMULTIPLE_ITEM to be a Size followed by a Count.

KSDDKAPI NTSTATUS NTAPI
  KsHandleSizedListQuery(
    IN PIRP  Irp,
    IN ULONG  DataItemsCount,
    IN ULONG  DataItemSize,
    IN const VOID*  DataItems
    );

Parameters

Irp
Specifies the IRP with the identifier list request.
DataItemsCount
Specifies the number of items in the identifier list.
DataItemSize
Specifies the size of a data item.
DataItems
Specifies the list of data items.

Return Value

The KsHandleSizedListQuery function returns STATUS_SUCCESS if the number of entries and the data can be copied. If the buffer is larger than the size to store just the size and the count of entries but too small to contain all the entries, the function returns status STATUS_BUFFER_TOO_SMALL.

Headers

Declared in ks.h. Include ks.h.

Comments

Use the KsHandleSizedListQuery function when implementing properties that are to return information in the multiple item format.


KsPinDataIntersection

The KsPinDataIntersection function handles the KSPROPERTY_PIN_DATAINTERSECTION property, through a callback, and performs much of the initial validation of the parameters passed. The function also calls the intersection handler function with each potential data range after matching it to the list of data ranges assigned to that pin factory.

KSDDKAPI NTSTATUS NTAPI
  KsPinDataIntersection(
    IN PIRP  Irp,
    IN PKSP_PIN  Pin,
    OUT PVOID  Data,
    IN ULONG  DescriptorsCount,
    IN const KSPIN_DESCRIPTOR*  Descriptor,
    IN PFNKSINTERSECTHANDLER  IntersectHandler
    );

Parameters

Irp
Specifies the IRP handling the property request.
Pin
Specifies the specific property being queried.
Data
Specifies the pin property specific data.
DescriptorsCount
Indicates the number of descriptor structures.
Descriptor
Specifies the pointer to the list of pin information structures.
IntersectHandler
Specifies the handler for comparison of a data range. For more information, see the Comments section.

Return Value

The KsPinDataIntersection function returns STATUS_SUCCESS if a matching range is found, STATUS_NO_MATCH if no matching range was found, or an error specific to the property being handled. The intersection handler provided to KsPinDataIntersection is called with each data range supplied by the caller until either a match is found, or an error occurs.

Note that the intersection handler function has its own set of return values, as described in the following text.

Headers

Declared in ks.h. Include ks.h.

Comments

A match can occur under three conditions: if the major format of the range passed is a wildcard or matches a pin factory range, if the sub-format is a wildcard or matches, and if the specifier is a wildcard or matches. Since the data range size may be variable, it is not validated beyond checking that it is at least the size of a data range structure.

The intersection handler function is as follows:

typedef NTSTATUS (*PFNKSINTERSECTHANDLER)(
  IN PIRP Irp,
  IN PKSP_PIN Pin,
  IN PKSDATARANGE DataRange,
  OUT PVOID Data
  );

Parameters

Irp
Specifies the IRP handling the property request.
Pin
Specifies the specific property being queried and the pin factory identifier that has been validated.
DataRange
Specifies the current data range to compare. The data range has been validated as either matching a particular range on the pin or as a wildcard match.
Data
Specifies the data format returned, or the size of the data format.


KsPinPropertyHandler

The KsPinPropertyHandler function performs standard handling of the static members of the KSPROPSETID_Pin property set. This handling does not include KSPROPERTY_PIN_CINSTANCES or KSPROPERTY_PIN_DATAINTERSECTION.

KSDDKAPI NTSTATUS NTAPI
  KsPinPropertyHandler(
    IN PIRP  Irp,
    IN PKSPROPERTY  Property,
    IN OUT PVOID  Data,
    IN ULONG  DescriptorsCount,
    IN const KSPIN_DESCRIPTOR*  Descriptor
    );

Parameters

Irp
Specifies the IRP handling the connection request.
Property
Specifies the specific property information.
Data
Specifies the data parameter mapped to a system address. This is the same parameter passed to a property handler through a KsPropertyHandler callback.
DescriptorsCount
Specifies the number of pin descriptors being passed.
Descriptor
Specifies the pointer to the list of pin descriptors.

Return Value

The KsPinPropertyHandler function returns STATUS_SUCCESS or an error specific to the property being handled. The function fills in the IO_STATUS_BLOCK.Information field of the PIRP.IoStatus element within the IRP. It does not set the IO_STATUS_BLOCK.Status field nor complete the IRP.

Headers

Declared in ks.h. Include ks.h.

Comments

Do not use the KsPinPropertyHandler function to define a pin property set; a pin property set can be more easily defined using the DEFINE_KSPROPERY_PINSET macro.


KsValidateConnectRequest

The KsValidateConnectRequest function validates the structures passed to IRP_MJ_CREATE and returns a pointer to the connection structure and the root file object.

This function can only be called at PASSIVE_LEVEL.

KSDDKAPI NTSTATUS NTAPI
  KsValidateConnectRequest(
    IN PIRP  Irp,
    IN ULONG  DescriptorsCount,
    IN KSPIN_DESCRIPTOR*  Descriptor,
    OUT PKSPIN_CONNECT*  Connect
    );

Parameters

Irp
Specifies the IRP handling the create request.
DescriptorsCount
Specifies the number of pin descriptors passed.
Descriptor
Specifies a pointer to the list of pin descriptors.
Connect
Specifies the returned connection structure.

Return Value

The KsValidateConnectRequest function returns STATUS_SUCCESS if successful, or it returns an error.

Headers

Declared in ks.h. Include ks.h.

Comments

The KsValidateConnectRequest function handles basic connection structure access exceptions and validates the communication requirements, medium, protocol, and basic data format. The validation performed on the data format passed is based on the data range list for the specified pin against which a pin instance is to be created. Validation is successful in three instances: if a range major format is a wildcard, the range major format matches and the range sub-format is a wildcard, or the range major format, range sub-format, and the range specifier all match.

The buffer is passed a copy of the original input buffer, if the originator was not in kernel mode, and is therefore safe to access.


Topology Management Functions

Various functions can be used to assist with topology management, including:

KsCreateTopologyNode

KsValidateTopologyNodeCreateRequest

KsTopologyPropertyHandler


KsCreateTopologyNode

The KsCreateTopologyNode function creates a handle to a topology node instance. The function can only be called at PASSIVE_LEVEL.

KSDDKAPI NTSTATUS NTAPI
  KsCreateTopologyNode(
    IN HANDLE  ParentHandle,
    IN PKSNODE_CREATE  NodeCreate,
    IN ACCESS_MASK  DesiredAccess,
    OUT PHANDLE  NodeHandle
    );

Parameters

ParentHandle
Specifies the handle to the parent on which the node is created.
NodeCreate
Specifies topology node create parameters.
DesiredAccess
Specifies the desired access to the object. This is typically GENERIC_READ and/or GENERIC_WRITE.
NodeHandle
Location for the topology node handle.

Return Value

Returns STATUS_SUCCESS, or an error if unable to create a node.

Headers

Declared in ks.h. Include ks.h.

Comments

The KSNODE_CREATE structure describes the set of information used to create the node handle.

typedef struct {
  ULONG  CreateFlags;
  ULONG  Node;
} KSNODE_CREATE;

Parameters

CreateFlags
Always set to zero.
Node
Specifies that node a handle should be created for. This refers to the node identifiers returned when querying topology information.


KsTopologyPropertyHandler

The KsTopologyPropertyHandler function performs standard handling of the static members of the KSPROPSETID_Topology Property Set. The function uses the KSTOPOLOGY structure, which describes the set of information that is returned by this property set.

KSDDKAPI NTSTATUS NTAPI
  KsTopologyPropertyHandler(
    IN PIRP  Irp,
    IN PKSPROPERTY  Property,
    IN OUT PVOID  Data,
    IN const KSTOPOLOGY*  Topology
    );

Parameters

Irp
Specifies the IRP handling the property request.
Property
Specifies the specific property being queried.
Data
Specifies the topology property-specific data.
Topology
Points to a KSTOPOLOGY structure containing the topology information.

Return Value

The KsTopologyPropertyHandler function returns STATUS_SUCCESS if successful, or it returns an error specific to the property being handled. The function always fills in the IO_STATUS_BLOCK.Information field of the PIRP.IoStatus element within the IRP. It does not set the IO_STATUS_BLOCK.Status field, nor does it complete the IRP.

Headers

Declared in ks.h. Include ks.h.


KsValidateTopologyNodeCreateRequest

The KsValidateTopologyNodeCreateRequest function validates a topology node creation request and returns the create structure associated with the request. The function can only be called at PASSIVE_LEVEL.

KSDDKAPI NTSTATUS NTAPI
  KsValidateTopologyNodeCreateRequest(
    IN PIRP  Irp,
    IN PKSTOPOLOGY  Topology,
    OUT PKSNODE_CREATE*  NodeCreate
    );

Parameters

Irp
Specifies the IRP with the node create request being handled.
Topology
Specifies the topology structure associated with the parent object. This is used to validate the create request.
NodeCreate
Location for the node create structure pointer passed to the create request.

Return Value

The KsValidateTopologyNodeCreateRequest function returns a STATUS_SUCCESS if successful, or else an error if unsuccessful.

Headers

Declared in ks.h. Include ks.h.


IRP Management Functions

IRP management functions assist in the general handling of IRPs. They include, alphabetically:

KsAcquireResetValue

KsAddIrpToCancelableQueue

KsAddObjectCreateItemToDeviceHeader

KsAddObjectCreateItemToObjectHeader

KsAllocateDeviceHeader

KsAllocateExtraData

KsAllocateObjectCreateItem

KsAllocateObjectHeader

KsCancelIo

KsCancelRoutine

KsDefaultDeviceIoCompletion

KsDefaultForwardIrp

KsDispatchFastIoDeviceControlFailure

KsDispatchFastReadFailure

KsDispatchFastWriteFailure

KsDispatchInvalidDeviceRequest

KsDispatchIrp

KsDispatchSpecificMethod

KsDispatchSpecificProperty

KsForwardAndCatchIrp

KsForwardIrp

KsFreeDeviceHeader

KsFreeObjectHeader

KsGetChildCreateParameter

KsMoveIrpsOnCancelableQueue

KsProbeStreamIrp

KsQueryInformationFile

KsQueryObjectAccessMask

KsQueryObjectCreateItem

KsReadFile

KsReleaseIrpOnCancelableQueue

KsRemoveIrpFromCancelableQueue

KsRemoveSpecificIrpFromCancelableQueue

KsSetInformationFile

KsSetMajorFunctionHandler

KsStreamIo

KsWriteFile


KsAcquireResetValue

The KsAcquireResetValue function retrieves the current reset state from a IOCTL_KS_RESET IRP.

KSDDKAPI NTSTATUS NTAPI
  KsAcquireResetValue(
    IN PIRP  Irp,
    OUT KSRESET*  ResetValue
    );

Parameters

Irp
Points to the IRP from which to retrieve the reset state.
ResetValue
Points to a caller-allocated buffer, that on successful completion contains the reset value (KSRESET_BEGIN, KSRESET_END) associated with the Irp

Return Value

The KsAcquireResetValue function returns STATUS_SUCCESS if the reset value was obtained.

Headers

Declared in ks.h. Include ks.h.


KsAddIrpToCancelableQueue

The KsAddIrpToCancelableQueue function adds an IRP to a queue of cancellable IRPs, thus allowing the IRP to be canceled. If the IRP had been previously set to a canceled state, the KsAddIrpToCancelableQueue function completes the canceling of that IRP.

KSDDKAPI VOID NTAPI
  KsAddIrpToCancelableQueue(
    IN OUT PLIST_ENTRY  QueueHead,
    IN PKSPIN_LOCK  SpinLock,
    IN PIRP  Irp,
    IN KSLIST_ENTRY_LOCATION  ListLocation,
    IN PDRIVER_CANCEL  DriverCancel  OPTIONAL
    );

Parameters

QueueHead
Specifies the driver-allocated storage for the head of the queue on which to add the IRP.
SpinLock
Points to driver's spin lock for queue access to the queue specified at QueueHead. A copy of this pointer is kept in the IRP's KSQUEUE_SPINLOCK_IRP_STORAGE(Irp) for use by the cancel routine, if necessary.
Irp
Specifies the IRP to add to the queue specified at QueueHead.
ListLocation
Indicates whether this IRP should be placed at the beginning or end of the queue. This value must be KsListEntryTail or KsListEntryHead.
DriverCancel
Optional parameter that specifies a driver-supplied cancel routine to use. If this is NULL, the standard KsCancelRoutine is used.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

If the IRP has been put into a cancel state when this routine is called, KsAddIrpToCancelableQueue will immediately call the cancel routine specified at DriverCancel, or if no routine was specified at DriverCancel the default streaming cancel routine is called.

The KsAddIrpToCancelableQueue function allows IRPs to be canceled even before being placed on a cancel list, or when being moved from one list to another. This function can be called at IRQ level DISPATCH_LEVEL or lower unless the driver-allocated queue and all entries in the queue are system-resident or allocated from resident storage.

The function does not use the cancel spinlock to add items to the list. Access to the list is synchronized using the provided spinlock and relies on atomic operations on Irp->CancelRoutine.


KsAddObjectCreateItemToDeviceHeader

The KsAddObjectCreateItemToDeviceHeader function adds the specified create-item to an empty item in the previously allocated create item list for this device header. An empty item is signified by a NULL create dispatch function in the entry. This function assumes that the caller is serializing multiple changes to the create items list.

KSDDKAPI NTSTATUS NTAPI
  KsAddObjectCreateItemToDeviceHeader(
    IN KSDEVICE_HEADER  Header,
    IN PDRIVER_DISPATCH  Create,
    IN PVOID  Context,
    IN PWCHAR  ObjectClass,
    IN PSECURITY_DESCRIPTOR  SecurityDescriptor
    );

Parameters

Header
Points to the device header that contains the previously allocated child create table.
Create
Specifies the create dispatch function.
Context
Specifies the context parameter.
ObjectClass
Specifies a pointer to a NULL-terminated character string that will be used for comparison on create requests. This pointer must remain valid while the device object is active.
SecurityDescriptor
Specifies the security descriptor. This must remain valid while the device object is active.

Return Value

The KsAddObjectCreateItemToDeviceHeader function returns STATUS_SUCCESS if an empty create item slot was found and the item was added.If unsuccessful, it returns STATUS_ALLOTTED_SPACE_EXCEEDED.

Headers

Declared in ks.h. Include ks.h.


KsAddObjectCreateItemToObjectHeader

The KsAddObjectCreateItemToObjectHeader function adds the specified create-item to an empty item in the previously allocated create item list for this object header. An empty item is signified by a NULL create dispatch function in the entry. This function assumes that the caller is serializing multiple changes to the create items list.

KSDDKAPI NTSTATUS NTAPI
  KsAddObjectCreateItemToObjectHeader(
    IN KSOBJECT_HEADER  Header,
    IN PDRIVER_DISPATCH  Create,
    IN PVOID  Context,
    IN PWCHAR  ObjectClass,
    IN PSECURITY_DESCRIPTOR  SecurityDescriptor
    );

Parameters

Header
Points to the object header that contains the previously allocated child- create table.
Create
Specifies the create dispatch function to use.
Context
Specifies the context parameter.
ObjectClass
Specifies a pointer to a NULL-terminated character string that is used for comparison on create requests. This pointer must remain valid while the object is active.
SecurityDescriptor
Specifies the security descriptor. This must remain valid while the object is active.

Return Value

The KsAddObjectCreateItemToObjectHeader function returns STATUS_SUCCESS if an empty create item slot was found and the item was added. If unsuccessful, it returns STATUS_ALLOTTED_SPACE_EXCEEDED.

Headers

Declared in ks.h. Include ks.h.


KsAllocateDeviceHeader

The KsAllocateDeviceHeader function allocates and initializes the required device extension header.

KSDDKAPI NTSTATUS NTAPI
  KsAllocateDeviceHeader(
    OUT PVOID  Header,
    IN ULONG  ItemsCount,
    IN PKSOBJECT_CREATE_ITEM  ItemsList  OPTIONAL
    );

Parameters

Header
Points to the location in which to return a pointer to the initialized header.
ItemsCount
Specifies the number of sub-items in the ItemsList. This should be zero if an ItemsList is not passed.
ItemsList
Optional. Points to a KSOBJECT_CREATE_ITEM structure for each sub-item. If there are no sub-items, this value should be NULL and ItemsCount should be zero.

Return Value

The KsAllocateDeviceHeader function returns STATUS_SUCCESS if successful or STATUS_INSUFFICIENT_RESOURCES if unable to allocate the necessary resources.

Headers

Declared in ks.h. Include ks.h.

Comments

The KsAllocateDeviceHeader function allocates memory for the KSDEVICE_HEADER structure for a device. When the header is no longer needed, the driver should call the KsFreeDeviceHeader function to free the memory allocated.

If sub-objects exist for a given device, the driver must, before calling KsAllocateDeviceHeader, allocate a buffer of either paged or nonpaged memory of sufficient size to hold a KSOBJECT_CREATE_ITEM structure for each sub-object. For example:

/* Allocate a buffer for 4 sub-objects for a given streaming device */
PKSOBJECT_CREATE_ITEM createBuffer ;
ULONG bufferSize  = (sizeof (KSOBJECT_CREATE_ITEM)) * 4 ;

createBuffer = (PKSOBJECT_CREATE_ITEM)
               ExAllocatePool (PagedPool, bufferSize) ;

Drivers must not free the memory allocated for the sub-object KSOBJECT_CREATE_ITEM list until after calling KsFreeDeviceHeader. Failure to do so can result in a bug check condition.

Callers of the routine must be running at IRQL < DISPATCH_LEVEL.

See Also

KsFreeDeviceHeader, KSOBJECT_CREATE_ITEM


KsAllocateExtraData

The KsAllocateExtraData function is used with streaming IRPs to allocate a buffer to contain additional header data. A pointer to the allocated buffer is returned, and the buffer must eventually be freed by the caller. The function must be called at IRQL < DISPATCH_LEVEL.

KSDDKAPI NTSTATUS NTAPI
  KsAllocateExtraData(
    IN PIRP  Irp,
    IN ULONG  ExtraSize,
    OUT PVOID*  ExtraBuffer
    );

Parameters

Irp
Specifies the IRP containing the stream headers. The IRP must have been previously passed to KsProbeStreamIrp to buffer the headers.
ExtraSize
Specifies the size, in bytes, of additional memory to allocate between each stream header. This value must be alignable on an eight-byte boundary. A copy of the headers is placed in the returned buffer, with the extra data size inserted between each header. This must be freed by the caller.
ExtraBuffer
Points to a caller-allocated pointer that, on successful completion, points to a system-allocated buffer containing the stream headers and the requested padding between them. This must be freed by the caller.

Return Value

The KsAllocateExtraData function returns STATUS_SUCCESS if successful, or it returns a resource or access error.

Headers

Declared in ks.h. Include ks.h.

Comments

When KsAllocateExtraData completes successfully, a pointer to a block of memory is returned that contains both the stream data headers from the IRP, specified at Irp, and padding between each header of size specified in ExtraSize. An example of such a resultant buffer is shown below:

When the extra buffer is no longer needed, the memory should be freed using ExFreePool.


KsAllocateObjectCreateItem

The KsAllocateObjectCreateItem function allocates a slot for the specified create item, optionally allocating space for and copying the create item data as well. This function assumes that the caller is serializing multiple changes to the create entry list.

KSDDKAPI NTSTATUS NTAPI
  KsAllocateObjectCreateItem(
    IN KSDEVICE_HEADER  Header,
    IN PKSOBJECT_CREATE_ITEM  CreateItem,
    IN BOOL AllocateEntry,
    IN PFNKSITEMFREECALLBACK  ItemFreeCallback  OPTIONAL
    );

Parameters

Header
Points to the device header on which to attach the create item.
CreateItem
Contains the create item to attach.
AllocateEntry
Indicates whether the create item pointer passed should be attached directly to the header, or if a copy of it should be made instead.
ItemFreeCallback
Optionally contains a pointer to a callback function that is called when the create entry is being destroyed upon freeing the device header. This is only valid when AllocateEntry is TRUE.

Return Value

Returns STATUS_SUCCESS if a new item was allocated and attached. Otherwise, it returns STATUS_INSUFFICIENT_RESOURCES.

Headers

Declared in ks.h. Include ks.h.

Comments

The PFNKSITEMFREECALLBACK is a method that should be called when freeing an allocated create item. It allows the client to perform any cleanup, including flushing security descriptor changes, which would be indicated by the flags set in the create item structure.

typedef NTSTATUS (*PFNKSITEMFREECALLBACK)(
  IN PKSOBJECT_CREATE_ITEM  CreateItem
    );

Parameters

CreateItem
Contains the create item that was previously allocated during the KsAllocateObjectCreteItem call. The Context parameter of this item must contain sufficient information to perform cleanup for this create item.

Return Value

The PFNKSITEMFREECALLBACK function returns STATUS_SUCCESS if the item was successfully freed. Otherwise, an appropriate error code is returned.


KsAllocateObjectHeader

The KsAllocateObjectHeader function initializes the required file context header.

KSDDKAPI NTSTATUS NTAPI
  KsAllocateObjectHeader(
    OUT PVOID  Header,
    IN ULONG  ItemsCount,
    IN PKSOBJECT_CREATE_ITEM  ItemsList  OPTIONAL,
    IN PIRP Irp,
    IN KSDISPATCH_TABLE*  Table
    );

Parameters

Header
Points to the caller-allocated location in which to return a pointer to the initialized KSOBJECT_HEADER if successful.
ItemsCount
Specifies the number of object create items in the ItemsList to be added to the object header once the header is allocated. This value should be zero if ItemsList is NULL.
ItemsList
Optionally specifies a pointer to a caller-allocated buffer containing a series of KSOBJECT_CREATE_ITEM structures to be dded to the object header. Must be set to NULL if there are no object create items.
Irp
Points to the IRP, of major function IRP_MJ_CREATE, that contains the necessary information to complete the creation of the object header.
Table
Points to an initialized dispatch table for this file object.

Return Value

The KsAllocateObjectHeader function returns STATUS_SUCCESS if successful or STATUS_INSUFFICIENT_RESOURCES if not enough resources are available to fulfill the request.

Headers

Declared in ks.h. Include ks.h.

Comments

Before calling this routine the driver must allocate system-resident storage for a KSDISPATCH_TABLE and initialize the dispatch table. The memory for this dispatch table cannot be released until KsFreeObjectHeader is called.

KsAllocateObjectHeader allocates the memory for the KSOBJECT_HEADER structure and returns a pointer to the header at Header. Drivers must not attempt to free the memory themselves, but rather call KsFreeObjectHeader when all operations requiring this object header have been completed.

If sub-objects exist for a given device, the driver must, before calling KsAllocateObjectHeader, allocate a buffer of either paged or nonpaged memory of sufficient size to hold a KSOBJECT_CREATE_ITEM structure for each sub-object. For example:

/* Allocate a buffer for 4 sub-objects for a given streaming device */
PKSOBJECT_CREATE_ITEM createBuffer ;
ULONG bufferSize  = (sizeof (KSOBJECT_CREATE_ITEM)) * 4 ;

createBuffer = (PKSOBJECT_CREATE_ITEM)
               ExAllocatePool (PagedPool, bufferSize) ;

Drivers must not free the memory allocated for the sub-object KSOBJECT_CREATE_ITEM list until after calling KsFreeDeviceHeader. Failure to do so can result in a bug check condition.

Callers of this routine must be running at IRQL < DISPATCH_LEVEL.

See Also

KsFreeObjectHeader, KSOBJECT_CREATE_ITEM, KsFreeDeviceHeader


KsCancelIo

The KsCancelIo function cancels all IRPs on the specified cancel list. If an IRP on the list does not have a cancel routine, only the cancel bit is set in the IRP. The function can be called at IRQ level DISPATCH_LEVEL or lower.

KSDDKAPI VOID NTAPI
  KsCancelIo(
    IN OUT PLIST_ENTRY  QueueHead,
    IN PKSPIN_LOCK  SpinLock
    );

Parameters

QueueHead
Specifies the head of a driver-maintained queue containing the IRP's to be cancelled.
SpinLock
Points to a caller-allocated spin lock for queue access. A copy of this pointer is kept in the IRP's KSQUEUE_SPINLOCK_IRP_STORAGE(Irp) for use by the cancel routine, if necessary.

Headers

Declared in ks.h. Include ks.h.

Comments

KsCancelIo cancels all IRPs in a given driver-maintained queue. If the IRP has a cancel routine, the cancel routine is called. Otherwise, the cancel flag in the IRP is set to TRUE. The IRPs are not removed from the queue by this routine. It is the sole responsibility of the driver to ensure that the IRPs are removed either by the cancel routine specified in the IRP or by some other driver-supplied functionality.

If the IRP being cancelled has a driver-supplied cancel routine, the cancel spin lock can be obtained from the IRP by calling KSQUEUE_SPINLOCK_IRP_STORAGE.

See Also

KsAddIrpToCancelableQueue, KSQUEUE_SPINLOCK_IRP_STORAGE

Return Value

None


KsCancelRoutine

The KsCancelRoutine function performs standard IRP cancel functionality: it removes the entry and then cancels and completes the request. The function is defined as a PDRIVER_CANCEL routine. It is the default function used for KsAddIrpToCancelableQueue if none is provided.

KSDDKAPI VOID NTAPI
  KsCancelRoutine(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Specifies the device object that owns the IRP.
Irp
Specifies the IRP being canceled.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

This function would typically be called by the I/O subsystem on canceling an IRP but can be called directly in response to an KSMETHOD_STREAM_PRESENTATION Set request. As with any typical cancel routine, this function expects the I/O cancel spin lock to have been acquired upon entering the function.

Note that this routine expects the KSQUEUE_SPINLOCK_IRP_STORAGE(Irp) to point to the list access spinlock as provided in KsAddIrpToCancelableQueue.

KsCancelRoutine can be used to do the preliminary list removal processing, without actually completing the IRP. If the Irp->IoStatus.Status is set to STATUS_CANCELLED on entering this function, then the IRP will not be completed. Otherwise, the status will be set to STATUS_CANCELLED and the IRP will be completed. This KsCancelRoutine can be used within a cancel routine to do the initial list and spinlock manipulation and return to the driver's completion routine to do specific processing and final IRP completion.

See Also

KsAddIrpToCancelableQueue


KsDefaultDeviceIoCompletion

The KsDefaultDeviceIoCompletion function is used to return a default response and to complete any device I/O control. It can be used in the KSDISPATCH_TABLE and as the default response to unknown Ioctl's. It is important to use this function so that queries such as property requests return the correct value rather than just STATUS_INVALID_DEVICE_REQUEST when properties are not support for instance.

KSDDKAPI NTSTATUS NTAPI
  KsDefaultDeviceIoCompletion(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Specifies the device object dispatched to.
Irp
Specifies the IRP to return a default response to.

Return Value

The KsDefaultDeviceIoCompletion function returns the default response to the possible IOCTLs.

Headers

Declared in ks.h. Include ks.h.

Comments

Note that this routine will complete the IRP.


KsDefaultForwardIrp

This default handler allows dispatch routines to forward I/O requests to corresponding Physical Device Objects.

KSDDKAPI ULONG NTAPI
KsDecrementCountedWorker(
    IN PKSWORKER Worker
    );

Parameters

Worker
Contains the previously allocated worker.

Return Value

Returns the status of the underlying Physical Device Object IRP processing.

Headers

Declared in ks.h. Include ks.h.

Comments

This default handler provides a way for dispatch routines to fulfill the requirement that a driver have an IRP_MJ_* function handler for specific major functions.


KsDispatchFastIoDeviceControlFailure

The KsDispatchFastIoDeviceControlFailure function is used in a KSDISPATCH_TABLE.FastDeviceIoControl entry that are not handled. The function should always return FALSE.

KSDDKAPI BOOLEAN NTAPI
  KsDispatchFastIoDeviceControlFailure(
    IN PFILE_OBJECT  FileObject,
    IN BOOLEAN  Wait,
    IN PVOID  InputBuffer  OPTIONAL,
    IN ULONG  InputBufferLength,
    OUT PVOID  OutputBuffer  OPTIONAL,
    IN ULONG  OutputBufferLength,
    IN ULONG  IoControlCode,
    OUT PIO_STATUS_BLOCK  IoStatus,
    IN PDEVICE_OBJECT  DeviceObject
    );

Parameters

FileObject
Not used.
Wait
Not used.
InputBuffer
Not used.
InputBufferLength
Not used.
OutputBuffer
Not used.
OutputBufferLength
Not used.
IoControlCode
Not used.
IoStatus
Not used.
DeviceObject
Not used.

Return Value

The KsDispatchFastIoDeviceControlFailure function returns FALSE.

Headers

Declared in ks.h. Include ks.h.

Comment

The KsDispatchFastIoDeviceControlFailure function is needed since the dispatch table for a particular opened instance of a device may not handle a specific major function that another opened instance needs to handle. Therefore, the function pointer in the driver object must always point to a function, such as the KsDispatchFastIoDeviceControlFailure function, that calls a dispatch table entry.


KsDispatchFastReadFailure

The KsDispatchFastReadFailure function is used in a KSDISPATCH_TABLE.FastRead entry when fast I/O read is not handled. The function should always return FALSE.

KSDDKAPI BOOLEAN NTAPI
  KsDispatchFastReadFailure(
    IN PFILE_OBJECT  FileObject,
    IN PLARGE_INTEGER  FileOffset,
    IN ULONG  Length,
    IN BOOLEAN  Wait,
    IN ULONG  LockKey,
    OUT PVOID  Buffer,
    OUT PIO_STATUS_BLOCK  IoStatus,
    IN PDEVICE_OBJECT  DeviceObject
    );

Parameters

FileObject
Not used.
FileOffset
Not used.
Length
Not used.
Wait
Not used.
LockKey
Not used.
Buffer
Not used.
IoStatus
Not used.
DeviceObject
Not used.

Return Value

The KsDispatchFastReadFailure function returns FALSE.

Headers

Declared in ks.h. Include ks.h.

Comment

The KsDispatchFastReadFailure function is needed since the dispatch table for a particular opened instance of a device may not handle a specific major function that another opened instance needs to handle. Therefore, the function pointer in the driver object must always point to a function, such as the KsDispatchFastReadFailure function, that calls a dispatch table entry.


KsDispatchFastWriteFailure

The KsDispatchFastWriteFailure function is used in a KSDISPATCH_TABLE.FastWrite entry when fast I/O is not handled for a write operation. The function should always return FALSE.

KSDDKAPI BOOLEAN NTAPI
  KsDispatchFastReadFailure(
    IN PFILE_OBJECT  FileObject,
    IN PLARGE_INTEGER  FileOffset,
    IN ULONG  Length,
    IN BOOLEAN  Wait,
    IN ULONG  LockKey,
    IN PVOID  Buffer,
    OUT PIO_STATUS_BLOCK  IoStatus,
    IN PDEVICE_OBJECT  DeviceObject
    );

Parameters

FileObject
Not used.
FileOffset
Not used.
Length
Not used.
Wait
Not used.
LockKey
Not used.
Buffer
Not used.
IoStatus
Not used.
DeviceObject
Not used.

Return Value

The KsDispatchFastWriteFailure function returns FALSE.

Headers

Declared in ks.h. Include ks.h.

Comment

The KsDispatchFastWriteFailure function is needed since the dispatch table for a particular opened instance of a device may not handle a specific major function that another opened instance needs to handle. Therefore, the function pointer in the driver object must always point to a function, such as the KsDispatchFastWriteFailure function, that calls a dispatch table entry.


KsDispatchInvalidDeviceRequest

The KsDispatchInvalidDeviceRequest function is used in KSDISPATCH_TABLE entries that are not handled and that need to return STATUS_INVALID_DEVICE_REQUEST.

KSDDKAPI NTSTATUS NTAPI
  KsDispatchInvalidDeviceRequest(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Specifies the device object associated with the IRP.
Irp
Specifies the IRP that is not being handled.

Return Value

The KsDispatchInvalidDeviceRequest function returns STATUS_INVALID_DEVICE_REQUEST and completes the IRP.

Headers

Declared in ks.h. Include ks.h.

Comments

The KsDispatchInvalidDeviceRequest function is needed because the dispatch table for an opened instance of a device may not handle a specific major function that another opened instance needs to handle. Therefore, the function pointer in the driver object must always point to a function that calls a dispatch table entry.

See Also

KsDispatchFastIoDeviceControlFailure, KsDispatchFastWriteFailure, KsDispatchFastReadFailure


KsDispatchIrp

This function is used to multiplex an Irp to a specific file context.

KSDDKAPI
NTSTATUS
NTAPI
KsDispatchIrp(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    );

Parameters

DeviceObject
Irp

Return Value

Headers

Declared in ks.h. Include ks.h.

Comments

KsDispatchIrp will either make a call into the file object's KSDISPATCH_TABLE to handle the IRP, or if the file object refers to an AVStream device, it will directly dispatch the IRP to the appropriate AVStream device. Very few AVStream minidrivers will use this function. Class drivers written under AVStream may use it.


KsDispatchSpecificMethod

The KsDispatchSpecificMethod function dispatches a method to a specific handler. The function assumes that the caller has previously dispatched the IRP to a handler through the KsMethodHandler function.

The function can only be called at PASSIVE_LEVEL.

KSDDKAPI NTSTATUS NTAPI
  KsDispatchSpecificMethod(
    IN PIRP  Irp,
    IN PFNKSHANDLER  Handler
    );

Parameters

Irp
Specifies the IRP with the method request being dispatched.
Handler
Specifies the pointer to the specific method handler.

Return Value

The KsDispatchSpecificMethod function returns STATUS_SUCCESS if successful, or if unsuccessful it returns an error.

Headers

Declared in ks.h. Include ks.h.

Comments

The KsDispatchSpecificMethod function is intended for additional processing of the method such as completing a pending operation.

See Also

KsMethodHandler


KsDispatchSpecificProperty

The KsDispatchSpecificProperty function dispatches the property to a specific handler. The function assumes that the caller has previously dispatched this IRP to a handler through the KsPropertyHandler function.

This function can only be called at PASSIVE_LEVEL.

KSDDKAPI NTSTATUS NTAPI
  KsDispatchSpecificProperty(
    IN PIRP  Irp,
    IN PFNKSHANDLER  Handler
    );

Parameters

Irp
Specifies the IRP with the property request being dispatched.
Handler
Specifies the pointer to the specific property handler.

Return Value

The KsDispatchSpecificProperty function returns STATUS_SUCCESS if successful, or if unsuccessful it returns an error.

Headers

Declared in ks.h. Include ks.h.

Comments

The KsDispatchSpecificProperty function is intended for additional processing of a property such as completing a pending operation.

See Also

KsPropertyHandler


KsForwardAndCatchIrp

The KsForwardAndCatchIrp function forwards an IRP to the specified driver after initializing the next stack location, and regains control of the IRP on completion from that driver. The function is used with devices that can be stacked and do not use file objects to communicate.

If a file object is being used, the caller must initialize the current stack location with that file object before calling the KsForwardAndCatchIrp function. The function verifies that there is a new stack location to copy into before attempting to do so. If there is not a new stack location, the function returns STATUS_INVALID_DEVICE_REQUEST. Regardless of whether a new stack location is present, the IRP is not completed.

KSDDKAPI NTSTATUS NTAPI
  KsForwardAndCatchIrp(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp,
    IN PFILE_OBJECT  FileObject,
    IN KSSTACK_USE  StackUse
    );

Parameters

DeviceObject
Specifies the device to forward the IRP to.
Irp
Specifies the IRP that is being forwarded to the specified driver.
FileObject
Specifies a file object value to copy to the next stack location. This can be NULL in order to set no file object, but the value is always copied to the next stack location. If the current file object is to be preserved, it must be passed in this parameter.
StackUse
Specifies a value ennumerated by KSSTACK_USE. If the value is KsStackCopyToNewLocation, the parameters are copied to the next stack location. If the value is KsStackReuseCurrentLocation, the current stack location is reused when the IRP is forwarded and the stack location is returned to the current location. If the value is KsStackUseNewLocation, the new stack location is used as is.

Return Value

The KsForwardAndCatchIrp function returns the result of the IoCallDriver, or it returns an invalid status if no more stack depth is available.

Headers

Declared in ks.h. Include ks.h.

Comments

The type KSSTACK_USE enumeration specifies how the IRP stack is used when forwarding the IRP to the next driver.

Enumeration | Description
KsStackCopyToNewLocation | Indicates that the parameters are to be copied to the next stack location.
KsStackReuseCurrentLocation | Indicates that the current stack location is to be reused.
KsStackUseNewLocation | Indicates that the next stack location is to be used without modification.


KsForwardIrp

The KsForwardIrp function forwards an IRP to the specified driver after initializing the next stack location and setting the file object.

KSDDKAPI NTSTATUS NTAPI
  KsForwardIrp(
    IN PIRP  Irp,
    IN PFILE_OBJECT  FileObject,
    IN BOOLEAN  ReuseStackLocation
    );

Parameters

Irp
Specifies the IRP that is being forwarded to the specified driver.
FileObject
Specifies the file object to initialize the next stack with.
ReuseStackLocation
Specifies the new stack location.

Return Value

The KsForwardIrp function returns the result of the IoCallDriver, or it returns an invalid status if no more stack depth is available.

Headers

Declared in ks.h. Include ks.h.

Comments

Use the KsForwardIrp function when only the FileObject parameter of the forwarded IRP changes when the current stack parameters are copied to the next stack location. The function verifies that there is a new stack location to copy into before attempting to copy. If there is no new stack location, the IRP is completed with STATUS_INVALID_DEVICE_REQUEST.


KsFreeDeviceHeader

The KsFreeDeviceHeader function cleans up and frees a previously allocated device header.

KSDDKAPI VOID NTAPI
  KsFreeDeviceHeader(
    IN PVOID  Header
    );

Parameters

Header
Indicates the device header to free that had been previously allocated by KsAllocateDeviceHeader.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

See Also

KsAllocateDeviceHeader


KsFreeObjectHeader

The KsFreeObjectHeader function cleans up and frees a previously allocated object header.

KSDDKAPI VOID NTAPI
  KsFreeObjectHeader(
    IN PVOID  Header
    );

Parameters

Header
Points to the object header to free.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

See Also

KsAllocateObjectHeader


KsGetChildCreateParameter

The KsGetChildCreateParameter function returns the standard parameter passed to a create request. It is used when passing a create parameter in the standard method used for creating pins, clocks, and allocators.

KSDDKAPI NTSTATUS NTAPI
  KsGetChildCreateParameter(
    IN PIRP Irp,
    OUT PVOID*  CreateParameter
    );

Parameters

Irp
Specifies the Create IRP whose parameter is being retrieved.
CreateParameter
Location in which to return the create information.

Return Value

The KsGetChildCreateParameter function returns STATUS_SUCCESS if successful or STATUS_INVALID_PARAMETER if the size was incorrect.

Headers

Declared in ks.h. Include ks.h.

Comments

The KsGetChildCreateParameter function assumes that the create request has been processed by the standard create dispatching list, which places the create item in KSCREATE_ITEM_IRP_STORAGE(Irp).


KsMoveIrpsOnCancelableQueue

The KsMoveIrpsOnCancelableQueue function moves the specified IRPs from the SourceList to the DestinationList. An IRP is moved if the ListCallback function indicates that it should be moved, whether or not it is currently acquired. It then continues through the list until the callback indicates that the search should be terminated, or the end of the list is reached. This function minimizes the use of the Cancel Spinlock by using the provided spinlocks to synchronize access when possible. The function does not allow the cancel routine to be modified while moving IRPs. The function can be called at DISPATCH_LEVEL or lower.

KSDDKAPI NTSTATUS NTAPI
  KsMoveIrpsOnCancelableQueue(
    IN OUT PLIST_ENTRY  SourceList,
    IN PKSPIN_LOCK  SourceLock,
    IN OUT PLIST_ENTRY  DestinationList,
    IN PKSPIN_LOCK  DestinationLock  OPTIONAL,
    IN KSLIST_ENTRY_LOCATION  ListLocation,
    IN PFNKSIRPLISTCALLBACK  ListCallback,
    IN PVOID  Context
    );

Parameters

SourceList
Specifies the head of the queue from which to remove the IRPs.
SourceLock
Pointer to driver's spin lock for source queue access.
DestinationList
Specifies the head of the queue on which to add the IRPs.
DestinationLock
Optionally contains a pointer to driver's spin lock for destination queue access. If this is not provided, the SourceLock is assumed to control both queues. If provided, this lock is always acquired after the SourceLock. If the destination list has a separate spinlock, the Cancel Spinlock is first acquired in order to move IRPs and allow the KSQUEUE_SPINLOCK_IRP_STORAGE() spinlock to be updated.
ListLocation
Indicates whether the IRPs should be enumerated from the head or the tail of the source queue. Any IRPs that are moved are placed on the destination queue's opposite end so that ordering is maintained.
ListCallback
Callback used to indicate whether or not a specific IRP should be moved from SourceList to DestinationList, or if enumeration should be terminated. If the function returns STATUS_SUCCESS, the IRP is moved. If the function returns STATUS_NO_MATCH, the IRP is not moved. Any other return warning or error value will terminate enumeration and be returned by the function. The STATUS_NO_MATCH value will not be returned as an error by the function. This function is called at DISPATCH_LEVEL. It is always called at least once at the end with a NULL IRP value in order to complete list processing.
Context
Context passed to ListCallback.

Return Value

Returns STATUS_SUCCESS if the list was completely enumerated, else returns any warning or error returned by ListCallback that interrupted enumeration.

Headers

Declared in ks.h. Include ks.h.


KsProbeStreamIrp

The KsProbeStreamIrp function makes the specified modifications to the input and output buffers of the given IRP based on the flags passed, and it then validates the stream header. This is useful when localizing exception handling or performing asynchronous work on an IRP. The resulting IRP is in essentially the METHOD_OUT_DIRECT or METHOD_IN_DIRECT format, with the exception that the access to the data buffer may be IoModifyAccess, depending on the flags passed to this function or the flags in the stream header.

KSDDKAPI NTSTATUS NTAPI
  KsProbeStreamIrp(
    IN PIRP  Irp,
    IN ULONG  ProbeFlags,
    IN ULONG  HeaderSize
    );

Parameters

Irp
Specifies the IRP whose input and output buffers are to be mapped. The requestor mode of the IRP is used when probing the buffers.
ProbeFlags
Specifies flags specifying how to probe the streaming IRP; the flags are listed in the following table.
HeaderSize
Specifies the size to validate each header header against passed to this client, or zero if no validation is to be done. If used, it is assumed that the entire buffer passed is a multiple of this header size, unless the buffer instead contains a single format change header.

Return Value

The KsProbeStreamIrp function returns STATUS_SUCCESS if successful, or it returns a memory or access error.

Headers

Declared in ks.h. Include ks.h.

Comments

If the function is used only to allocate MDL's and not to probe and lock the addresses, the caller must have a completion routine to clean up the MDL's. For instance, a just-in-time locking mechanism can allocate the MDL list but only lock memory as needed. The client must provide cleanup code to remove the partially locked MDL list before the IRP is completed, presumably in a completion routine.

If the headers appear to have already been copied to a system buffer, it is not validated again. In general, calling the KsProbeStreamIrp function multiple times with an IRP is not harmful. After calling the function, the stream headers are available in PIRP.AssociatedIrp.SystemBuffer. If the stream buffer MDLs have been allocated, they are available through the PIRP.MdlAddress.

The following defines are used for the ProbeFlags variable:

ProbeFlags Value | Description
KSPROBE_READ | Indicates that the operation is a stream read on the device. This is the default.
KSPROBE_WRITE | Indicates that the operation is a stream write on the device.
KSPROBE_ALLOCATEMDL | Indicates that MDLs should be allocated for the stream buffers if they have not already been allocated. If no stream buffers are present, the flag is ignored. If KSPROBE_PROBEANDLOCK is not specified at the same time as this flag, the caller must have a completion routine in order to clean up any MDL's if not all the MDLs were successfully probed and locked.
KSPROBE_PROBEANDLOCK | If the KSPROBE_ALLOCATEMDL is set, indicates that the memory referenced by the MDLs for the stream buffers should be probed and locked. If the MDL allocation flag is not set, this flag is ignored even if the MDL allocation has previously taken place. The method of probing is determined by what type of IRP is being passed. For a write operation, IoReadAccess is used. For a read operation, IoWriteAccess is used. If the client that sent the data is using the nonpaged pooll, appropriate MDLs are initialized rather than probing and locking.
KSPROBE_SYSTEMADDRESS | Retrieves a system address for each MDL in the chain so the caller does not need to do this in a separate step. This is ignored if the probe and lock flag is not set, even if the MDLs have previously been probed.
KSPROBE_ALLOWFORMATCHANGE | For a Stream Write, allows the KSSTREAM_HEADER_OPTIONSF_TYPECHANGED flag to be set in the stream header. This implies that the stream header is not of extended length, even if an extended header size was indicated. Also, there may only be one stream header contained in the IRP in this case. The buffer associated with this header contains the new data format. For system memory data streams, the buffer should not have been acquired from the negotiated allocator, as it is not part of the data stream.


KsQueryInformationFile

The KsQueryInformationFile function performs an information query against the specified file object. The function attempts to use FastIoDispatch if possible, or it generates an information request against the device object.

KSDDKAPI NTSTATUS NTAPI
  KsQueryInformationFile(
    IN PFILE_OBJECT  FileObject,
    OUT PVOID  FileInformation,
    IN ULONG  Length,
    IN FILE_INFORMATION_CLASS  FileInformationClass
    );

Parameters

FileObject
Specifies the file object from which to query the standard information.
FileInformation
Indicates the place in which to put the file information. This is assumed to be a valid or probed address.
Length
Specifies the correct length of the FileInformation buffer.
FileInformationClass
Specifies the class of information being requested.

Return Value

The KsQueryInformationFile function returns STATUS_SUCCESS if successful, or if unsuccessful it returns a query error.

Headers

Declared in ks.h. Include ks.h.

Comments

The KsQueryInformationFile function should only be used in cases where the query would result in an actual request to the underlying driver. For example, FilePositionInformation would not generate such a request and should not be used. It assumes the caller is serializing access to the file for operations against a FO_SYNCHRONOUS_IO file object.


KsQueryObjectAccessMask

The KsQueryObjectAccessMask function returns the access originally granted to the first client that created a handle on the associated object. Access can not be changed by duplicating handles.

KSDDKAPI ACCESS_MASK NTAPI
  KsQueryObjectAccessMask(
    IN KSOBJECT_HEADER  Header
    );

Parameters

Header
Points to a header previously allocated by KsAllocateObjectHeader whose access-granted mask pointer is to be returned.

Return Value

The KsQueryObjectAccessMask function returns an access mask.

Headers

Declared in ks.h. Include ks.h.

See Also

KsAllocateObjectHeader


KsQueryObjectCreateItem

The KsQueryObjectCreateItem function returns the create item assigned to the object when created.

KSDDKAPI PKSOBJECT_CREATE_ITEM NTAPI
  KsQueryObjectCreateItem(
    IN KSOBJECT_HEADER  Header
    );

Parameters

Header
Indicates the header previously allocated.

Return Value

The KsQueryObjectCreateItem function returns a pointer to a create item.

Headers

Declared in ks.h. Include ks.h.


KsReadFile

The KsReadFile function performs a read against the specified file object. It is assumed the caller is serializing access to the file for operations against a FO_SYNCHRONOUS_IO file object. The function attempts to use FastIoDispatch if possible, or generates a read request against the device object. All relevant statistics are updated.

KSDDKAPI NTSTATUS NTAPI
  KsReadFile(
    IN PFILE_OBJECT  FileObject,
    IN PKEVENT  Event  OPTIONAL,
    IN PVOID  PortContext  OPTIONAL,
    OUT PIO_STATUS_BLOCK  IoStatusBlock,
    OUT PVOID  Buffer,
    IN ULONG  Length,
    IN ULONG  Key  OPTIONAL,
    IN KPROCESSOR_MODE  RequestorMode
    );

Parameters

FileObject
Specifies the file object to perform the read against.
Event
Optionally contains the event to use in the read. If no event is passed, the call is assumed to be on a synchronous file object. If not, the caller is waiting on the file object's event, or it may be asynchronously completed. If the file has been opened for synchronous I/O, this must be NULL. If the variable is used, it must be an event allocated by the object manager.
PortContext
Optionally contains context information for a completion port.
IoStatusBlock
Specifies the address where the status information is to be returned. This is always assumed to be a valid address, regardless of the requestor mode.
Buffer
Specifies the buffer in which to place the data read. If the buffer needs to be probed and locked, an exception handler is used, along with RequestorMode.
Length
Specifies the size of the buffer passed.
Key
Optionally contains a key, or zero if none
RequestorMode
Indicates the processor mode to place in the read IRP if one needs to be generated. Additionally, it is used if the buffer needs to be probed and locked. This variable also determines if a fast I/O call can be performed. If the requestor mode is not KernelMode, but the previous mode was, then fast I/O cannot be used.

Return Value

The KsReadFile function returns STATUS_SUCCESS if successful, STATUS_PENDING if action is pending, or it returns a read error if unsuccessful.

Headers

Declared in ks.h. Include ks.h.


KsReleaseIrpOnCancelableQueue

The KsReleaseIrpOnCancelableQueue function releases an acquired IRP that is already on a queue that can be canceled. The function sets the cancel function and completes the canceling of the IRP, if necessary. The function can be called at IRQ level DISPATCH_LEVEL or lower.

KSDDKAPI VOID NTAPI
  KsReleaseIrpOnCancelableQueue(
    IN PIRP  Irp,
    IN PDRIVER_CANCEL  DriverCancel  OPTIONAL
    );

Parameters

Irp
Specifies the IRP to release.
DriverCancel
Optional parameter that specifies the cancel routine to use. If this is NULL, the standard KsCancelRoutine is used.

Return Value

None

Headers

Declared in ks.h. Include ks.h.


KsRemoveIrpFromCancelableQueue

The KsRemoveIrpFromCancelableQueue function pops the next noncanceled IRP from the specified queue that can be canceled and removes its cancel status. The function searches the list until an IRP is found that has a cancel routine or until the end of the list is reached. The function minimizes the use of the cancel spinlock by using the provided spinlock to synchronize access in most cases. The function may be called at IRQ level DISPATCH_LEVEL or lower.

KSDDKAPI PIRP NTAPI
  KsRemoveIrpFromCancelableQueue(
    IN OUT PLIST_ENTRY  QueueHead,
    IN PKSPIN_LOCK  SpinLock,
    IN KSLIST_ENTRY_LOCATION  ListLocation,
    IN KSIRP_REMOVAL_OPERATION  RemovalOperation
    );

Parameters

QueueHead
Points to the head of the queue from which to remove the IRP.
SpinLock
Points to driver's spin lock for queue access.
ListLocation
Indicates whether this IRP should come from the beginning or end of the queue.
RemovalOperation
Specifies whether or not the IRP is removed from the list or just acquired by setting the cancel function to NULL. If it is only acquired, the IRP must be later released with KsReleaseIrpOnCancelableQueue or completely removed with KsRemoveSpecificIrpFromCancelableQueue.

Return Value

The KsRemoveIrpFromCancelableQueue function returns the next noncanceled IRP on the list, or it returns NULL if none is found or if an IRP that has not already been acquired cannot be found.

Headers

Declared in ks.h. Include ks.h.

Comments

These enumerations are used in the previous parameters to control where the IRP is removed from and how.

typedef enum {
    KsListEntryTail,
    KsListEntryHead
} KSLIST_ENTRY_LOCATION;

typedef enum {
    KsAcquireOnly,
    KsAcquireAndRemove
} KSIRP_REMOVAL_OPERATION;

See Also

KsReleaseIrpOnCancelableQueue, KsRemoveSpecificIrpFromCancelableQueue


KsRemoveSpecificIrpFromCancelableQueue

The KsRemoveSpecificIrpFromCancelableQueue function removes the specified IRP from the specified queue. This is performed on an IRP that was previously acquired using KsRemoveIrpFromCancelableQueue, but that was not actually removed from the queue.

KSDDKAPI VOID NTAPI
  KsRemoveSpecificIrpFromCancelableQueue(
    IN PIRP  Irp
    );

Parameters

Irp
Points to I/O request packet.

Return Value

None

Headers

Declared in ks.h. Include ks.h.


KsSetInformationFile

The KsSetInformationFile function performs an information set against the specified file object. The function attempts to use FastIoDispatch if possible, or it generates an information set against the device object.

KSDDKAPI NTSTATUS NTAPI
  KsSetInformationFile(
    IN PFILE_OBJECT  FileObject,
    IN PVOID  FileInformation,
    IN ULONG  Length,
    IN FILE_INFORMATION_CLASS  FileInformationClass
    );

Parameters

FileObject
Specifies the file object to set the standard information on.
FileInformation
Indicates the place in which to put the file information. The file information is assumed to be a valid or probed address.
Length
Specifies the correct length of the FileInformation buffer.
FileInformationClass
Specifies the class of information being set.

Return Value

The KsSetInformationFile function returns STATUS_SUCCESS if successful, or if unsuccessful it returns a set error.

Headers

Declared in ks.h. Include ks.h.

Comments

The KsSetInformationFile function should be used only when the set would result in an actual request to the underlying driver, not including complex operations that require additional parameters to be sent to the driver such as rename, deletion, and completion. For example, FilePositionInformation would not generate such a request and should not be used. It assumes the caller is serializing access to the file for operations against a FO_SYNCHRONOUS_IO file object.


KsSetMajorFunctionHandler

The KsSetMajorFunctionHandler function sets the handler for a specified major function to use the internal dispatching. It routes through a KSDISPATCH_TABLE contained in the opaque object header to be the first element within a structure pointed to by an FsContext within a file object. The dispatching assumes the table and FsContext structure are initialized by the device using KsAllocateObjectHeader.

KSDDKAPI NTSTATUS NTAPI
  KsSetMajorFunctionHandler(
    IN PDRIVER_OBJECT  DriverObject,
    IN ULONG  MajorFunction
    );

Parameters

DriverObject
Specifies the driver object whose major function is to be handled.
MajorFunction
Specifies the major function identifier to be handled. This sets the major function pointer in the driver object to an internal function that then dispatches to the KSDISPATCH_TABLE function. The pointer to this table is assumed to be the first element in a structure pointed to by FsContext in the file object of the specific IRP being dispatched. The valid major function identifiers are as listed.
Identifier | Description
IRP_MJ_CREATE | Create IRP. In this instance, a create request could be used for either creating a new instance of a filter, or for creating some object such as a pin under a filter or a clock under a pin. This assumes that the first element in the driver object's extent contains a KSDEVICE_HEADER structure that is used to find the type of object to create, based on the name passed. If a parent file object is specified, then that object's KSDISPATCH_TABLE.ChildCreateHandlerTable in the FsContext is looked at to determine what handler to use for the create, or use the device object's table.
IRP_MJ_CLOSE | Close IRP.
IRP_MJ_DEVICE_CONTROL | Device control IRP.
IRP_MJ_READ | Read IRP.
IRP_MJ_WRITE | Write IRP.
IRP_MJ_FLUSH_BUFFERS | Flush IRP.
IRP_MJ_QUERY_SECURITY | Query security information.
IRP_MJ_SET_SECURITY | Set security information.
KSDISPATCH_FASTIO | This flag may be added to the MajorFunction identifier in order to specify that the entry refers to the fast I/O dispatch table, rather than the typical major function entry. This is valid only with IRP_MJ_READ, IRP_MJ_WRITE or IRP_MJ_DEVICE_CONTROL. The driver is responsible for creating the DriverObject->FastIoDispatch table. As with normal dispatching, if a handler is set for the driver object, all file objects must handle that fast I/O, even if the entry just points to DispatchFastIoDeviceControlFailure or a similar function.

Return Value

Returns STATUS_SUCCESS if the MajorFunction identifier is valid.

Headers

Declared in ks.h. Include ks.h.

Comments

If a major function handler is set for a driver object, all file objects must handle that major function, even if the entry just points to KsDispatchInvalidDeviceRequest.

KSDISPATCH_FASTIO

This flag may be used to specify that the fast I/O entry should be set rather than the IRP-based entry.


KsStreamIo

The KsStreamIo function performs a stream read or write against the specified file object. The function attempts to use FastIoDispatch if possible, or it generates a read or write request against the device object.

KSDDKAPI NTSTATUS NTAPI
  KsStreamIo(
    IN PFILE_OBJECT FileObject,
    IN PKEVENT Event OPTIONAL,
    IN PVOID PortContext OPTIONAL,
    IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL,
    IN PVOID CompletionContext OPTIONAL,
    IN KSCOMPLETION_INVOCATION CompletionInvocationFlags OPTIONAL,
    OUT PIO_STATUS_BLOCK IoStatusBlock,
    IN OUT PVOID StreamHeaders,
    IN ULONG Length,
    IN ULONG Flags,
    IN KPROCESSOR_MODE RequestorMode
    );

Parameters

FileObject
Specifies the file object to perform the I/O against.
Event
Optionally contains the event to use in the I/O. If none is passed, the call is assumed to be on a synchronous file object or the caller is waiting on the file object's event, or else it can be asynchronously completed. If used, and the KSSTREAM_SYNCHRONOUS flag is not set, this must be an event allocated by the object manager. If the caller is performing asynchronous I/O, it must either wait on the file object's event or pass an event in this parameter and wait on it. If this is not done, then there is no way for the caller to know when the IoStatusBlock has been updated by the call.
PortContext
Optionally contains context information for a completion port.
CompletionRoutine
Optionally points to a completion routine for this IRP.
CompletionContext
If CompletionRoutine is specified, this provides a context pointer in the completion routine callback.
CompletionInvocationFlags
Specifies invocation flags specifying when the completion routine is invoked. See following table for the values used.
IoStatusBlock
Location to return the status information. This is always assumed to be a valid address, regardless of the requestor mode. The value must remain valid until the call has updated the status. The caller must either perform synchronous I/O or must wait on the file object's event or an event passed in the Event parameter before allowing this address to become invalid.
StreamHeaders
Specifies the list of stream headers. This address, as well as the addresses of the data buffers, are assumed to have been probed for appropriate access. Kernel-mode clients submitting streaming headers must allocate the headers from NonPagedPool memory.
Length
Specifies the size of the StreamHeaders passed.
Flags
Specifies various flags for the I/O. See the following table for the values used.
RequestorMode
Indicates the processor mode to place in the IRP if one is needs to be generated. This variable also determines if a fast I/O call can be performed. If the requestor mode is not kernel mode, but the previous mode is, then fast I/O cannot be used.

Return Value

The KsStreamIo function returns STATUS_SUCCESS if successful, STATUS_PENDING if action is pending, or if unsuccessful it returns an I/O error.

Headers

Declared in ks.h. Include ks.h.

Comments

The following enumerated values are used for the CompletionInvocationFlags variable and are of type KSCOMPLETION_INVOCATION:

CompletionInvocationFlags Value | Description
KsInvokeOnSuccess | Invokes the completion routine on success.
KsInvokeOnError | Invokes the completion routine on error.
KsInvokeOnCancel | Invokes the completion routine on cancellation.

The following defined values are used for the Flags variable:

Flags Values | Description
KSSTREAM_READ | Specifies that an IOCTL_KS_STREAMREAD IRP is to be built. This is the default.
KSSTREAM_WRITE | Specifies that an IOCTL_KS_STREAMWRITE IRP is to be built.
KSSTREAM_PAGED_DATA | Specifies that the data is pageable. This is the default and can be used at all times.
KSSTREAM_NONPAGED_DATA | Specifies that the data is nonpaged and can be used as a performance enhancement.
KSSTREAM_SYNCHRONOUS | Specifies that the IRP is synchronous. This means that if the Event parameter is passed, it is not treated as an Object Manager event and is not referenced or dereferenced.


KsWriteFile

The KsWriteFile function performs a write against the specified file object. It is assumed that the caller is serializing access to the file for operations against a FO_SYNCHRONOUS_IO file object. The function attempts to use FastIoDispatch if possible, or it generates a write request against the device object. All relevant statistics are updated.

KSDDKAPI NTSTATUS NTAPI
  KsWriteFile(
    IN PFILE_OBJECT  FileObject,
    IN PKEVENT  Event  OPTIONAL,
    IN PVOID  PortContext  OPTIONAL,
    OUT PIO_STATUS_BLOCK  IoStatusBlock,
    IN PVOID  Buffer,
    IN ULONG  Length,
    IN ULONG  Key  OPTIONAL,
    IN KPROCESSOR_MODE  RequestorMode
    );

Parameters

FileObject
Specifies the file object to perform the read against.
Event
Optionally contains the event to use in the write. If no event is passed, the call is assumed to be on a synchronous file object or the caller is waiting on the file object's event. If the call is not on a synchronous file object, it can be asynchronously completed. If the file has been opened for synchronous I/O, this variable must be NULL. If this variable is used, it must be an event allocated by the object manager.
PortContext
Optionally contains context information for a completion port.
IoStatusBlock
Indicates the location in which to return the status information. This is always assumed to be a valid address, regardless of the requestor mode.
Buffer
Specifies the buffer from which to write the data. If the buffer needs to be probed and locked, an exception handler is used, along with RequestorMode.
Length
Specifies the size of the buffer passed.
Key
Optionally contains a key, or zero if none.
RequestorMode
Indicates the processor mode to place in the read IRP if one needs to be generated. Additionally, it is used if a buffer needs to be probed and locked. This variable also determines if a fast I/O call can be performed. If the requestor mode is not KernelMode, but the previous mode was, then fast I/O cannot be used.

Return Value

The KsWriteFile function returns STATUS_SUCCESS if successful, STATUS_PENDING if action is pending, or it returns a read error if unsuccessful.

Headers

Declared in ks.h. Include ks.h.


Security Functions

This following section describes the general helper functions. These include:

KsAcquireDeviceSecurityLock

KsCreateDefaultSecurity

KsDispatchQuerySecurity

KsDispatchSetSecurity

KsReleaseDeviceSecurityLock


KsAcquireDeviceSecurityLock

The KsAcquireDeviceSecurityLock function acquires the security lock associated with a device object. An exclusive lock is acquired when changing a security descriptor. When manipulating the security of any object under a particular device object, this lock must be acquired.

KSDDKAPI VOID NTAPI
  KsAcquireDeviceSecurityLock(
    IN PVOID  Header,
    IN BOOLEAN  Exclusive
    );

Parameters

Header
Points to a driver-allocated device header, previously allocated by KsAllocateDeviceHeader, for the device object described by the KSDEVICE_HEADER structure.
Exclusive
Indicates, if set to TRUE, that the lock is to be acquired exclusively.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

A shared lock is acquired when validating access during a create. An exclusive lock is acquired when changing a security descriptor. Callers of this routine must be running at IRQL < DISPATCH_LEVEL.

See Also

KsAllocateDeviceHeader


KsCreateDefaultSecurity

The KsCreateDefaultSecurity function creates a security descriptor with default security, optionally inheriting parameters from a parent security descriptor.

KSDDKAPI NTSTATUS NTAPI
  KsCreateDefaultSecurity(
    IN PSECURITY_DESCRIPTOR ParentSecurity OPTIONAL,
    OUT PSECURITY_DESCRIPTOR* DefaultSecurity
    );

Parameters

ParentSecurity
Points to the parent object's security descriptor, describing inherited security parameters. This argument is optional.
DefaultSecurity
Points to the place in which to put the returned default security descriptor.

Return Value

KsCreateDefaultSecurity returns STATUS_SUCCESS if the operation is successful, else a resource or assignment error.

Headers

Declared in ks.h. Include ks.h.

Comments

KsCreateDefaultSecurity is used to initialize sub-objects that do not have any stored security.


KsDispatchQuerySecurity

The KsDispatchQuerySecurity function is used in the KSDISPATCH_TABLE.QuerySecurity entry to handle querying about the current security descriptor. The assumption is that the KSOBJECT_HEADER structure is being used in the FsContext data structure and that the CreateItem points to a valid item that optionally contains a security descriptor.

KSDDKAPI NTSTATUS NTAPI
  KsDispatchQuerySecurity(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Specifies the device object associated with the IRP.
Irp
Specifies the IRP that is being handled.

Return Value

The KsDispatchQuerySecurity function returns the security query status and completes the IRP if a security descriptor is present. If no security descriptor is present, it returns STATUS_NO_SECURITY_ON_OBJECT.

Headers

Declared in ks.h. Include ks.h.


KsDispatchSetSecurity

The KsDispatchSetSecurity function is used in the KSDISPATCH_TABLE.SetSecurity entry to handle setting the current security descriptor. The assumption is that the KSOBJECT_HEADER structure is being used in the FsContext data structure and that the CreateItem points to a valid item that optionally contains a security descriptor.

KSDDKAPI NTSTATUS NTAPI
  KsDispatchSetSecurity(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Specifies the device object associated with the IRP.
Irp
Specifies the IRP that is being handled.

Return Value

The KsDispatchSetSecurity function returns the security set status and completes the IRP.

Headers

Declared in ks.h. Include ks.h.

Comments

This security descriptor must be allocated in its own piece of pool memory, since KsDispatchSetSecurity will replace the existing descriptor with a new allocation. Therefore, it cannot be shared with CreateItem.


KsReleaseDeviceSecurityLock

The KsReleaseDeviceSecurityLock function releases a previously acquired security lock on the device object header.

KSDDKAPI VOID NTAPI
  KsReleaseDeviceSecurityLock(
    IN KSDEVICE_HEADER  Header
    );

Parameters

Header
Points to a header previously allocated by KsAllocateDeviceHeader whose security lock is to be released.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

See Also

KsAllocateDeviceHeader


General Utility Functions

This following section describes the general helper functions. These include:

KsCacheMedium

KsDecrementCountedWorker

KsDefaultDispatchPnp

KsDefaultDispatchPower

KsDereferenceBusObject

KsForwardAndCatchIrp

KsForwardIrp

KsFreeObjectCreateItem

KsFreeObjectCreateItemsByContext

KsIncrementCountedWorker

KsLoadResource

KsNullDriverUnload

KsPinDataIntersectionEx

KsQueryDevicePnpObject

KsQueueWorkItem

KsRecalculateStackDepth

KsReferenceBusObject

KsRegisterCountedWorker

KsRegisterWorker

KsSetDevicePnpAndBaseObject

KsSetPowerDispatch

KsSetTargetDeviceObject

KsSetTargetState

KsSynchronousIoControlDevice

KsUnregisterWorker

KsValidateAllocatorFramingEx


KsCacheMedium

The KsCacheMedium function improves graph building performance of pins that use Mediums to define connectivity.

KSDDKAPI NTSTATUS NTAPI
  KsCacheMedium(
    IN PUNICODE_STRING SymbolicLink,
    IN PKSPIN_MEDIUM Medium,
    IN DWORD PinDirection
    );

Parameters

Symbolic Link
The symbolic link used to open the device interface.
Medium
Points to the medium to cache.
PinDirection
Contains the direction of the Pin. 1 is output, 0 is input.

Return Value

KsCacheMedium returns STATUS_SUCCESS if the caching operation is successful, failure if it is not.

Headers

Declared in ks.h. Include ks.h.

Comments

KsCacheMedium improves graph building performance by creating a registry key at:

\System\CurrentControlSet\Control\MediumCache\GUID\DWORD\DWORD

This enables fast lookup of connected filters in TvTuner and other complex graphs. Note that the GUID identifies the Medium of the connection, and that the DWORDs denote the device instance. The value name is the SymbolicLink for the driver, and ActualValue is the pin direction.turning.


KsDecrementCountedWorker

Decrements the current worker count of a worker previous created by KsRegisterCountedWorker. This should be called after each task within a worker has been completed.

KSDDKAPI ULONG NTAPI
KsDecrementCountedWorker(
    IN PKSWORKER Worker
    );

Parameters

Worker
Contains the previously allocated worker.

Return Value

Returns the current counter. A count of zero implies that the task list has been completed.

Headers

Declared in ks.h. Include ks.h.

Comments

This should be called after each task within a worker has been completed. A corresponding KsIncrementCountedWorker would have been previously called in order to increment the count. This may be called at DISPATCH_LEVEL.


KsDefaultDispatchPnp

The KsDefaultDispatchPnp function is the default, main PnP dispatch handler; notifications regarding the functional device object can be directed to this handler. This function passes all notifications to the PnP device object previously set with KsSetDevicePnpAndBaseObject and assumes the use of a device header. When the function is passed an IRP_MN_REMOVE_DEVICE, the device object is deleted.

KSDDKAPI NTSTATUS NTAPI
  KsDefaultDispatchPnp(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Specifies the functional device object.
Irp
Specifies the PnP IRP.

Return Value

The KsDefaultDispatchPnp function returns the status of the underlying physical device object IRP processing.

Headers

Declared in ks.h. Include ks.h.

Comments

The KsDefaultDispatchPnp function is useful when there is no extra cleanup needed when removing a device beyond freeing the device header and deleting the actual device object.


KsDefaultDispatchPower

The KsDefaultDispatchPower function is a default main Power dispatch handler. Notifications regarding the Functional Device Object can be directed here. This function passes all notifications to the PnP Device Object previously set with KsSetDevicePnpAndBaseObject, and assumes the use of a device header.

KSDDKAPI NTSTATUS NTAPI
KsDefaultDispatchPower(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Specifies the Functional Device Object.
Irp
Specifies the Power IRP.

Return Value

Returns the status of the underlying Physical Device Object IRP processing.

Headers

Declared in ks.h. Include ks.h.

Comments

The KsDefaultDispatchPower function is useful when there is no extra cleanup needed on power IRPs, or just as a way of completing any power IRP. It also allows specific file objects, such as the default clock imlementation, to attach themselves to the power IRPs using KsSetPowerDispatch, and act on them before they are completed by this routine. This function calls each power dispatch routine before completing the IRP.


KsDereferenceBusObject

Dereferences the bus Physical Device Object.

KSDDKAPI VOID NTAPI
  KsDereferenceBusObject(
    IN KSDEVICE_HEADER Header
    );

Parameters

Header
Points to a header previously allocated by KsAllocateDeviceHeader that also contains the PnP device stack object.

Return Value

None.

Headers

Declared in ks.h. Include ks.h.

Comments

This is used by filters that use the device header to keep track of the corresponding PnP object stack. This is normally called when closing a filter, if required by the bus for the given device. As an example, a software device would require such a call. This call matches a previous call to KsReferenceBusObject when opening the filter instance. The caller must have previously also called KsSetDevicePnpAndBaseObject in order to set the PnP device stack object. This would have been done in the PnP AddDevice function. The function calls the DereferenceDeviceObject method on the previously retrieved interface. The interface itself is released and freed when the device header is freed.


KsFreeObjectCreateItem

Frees the slot for the specified create item.

KSDDKAPI NTSTATUS NTAPI
  KsFreeObjectCreateItem(
    IN KSDEVICE_HEADER Header,
    IN PUNICODE_STRING CreateItem
    );

Parameters

Header
Points to the device header on which the create item is attached.
CreateItem
Contains the name of the create item to free.

Return Value

Returns STATUS_SUCCESS if the item was freed, else STATUS_OBJECT_NAME_NOT_FOUND.

Headers

Declared in ks.h. Include ks.h.

Comments

This function does not assume that the caller is serializing multiple changes to the create entry list.

See Also

KsFreeObjectCreateItemsByContext


KsFreeObjectCreateItemsByContext

Frees all create items with a specific context.

KSDDKAPI NTSTATUS NTAPI
  KsFreeObjectCreateItemsByContext(
    IN KSDEVICE_HEADER Header,
    IN PVOID Context
    );

Parameters

Header
Points to the device header on which the create items are attached.
CreateItem
Contains the context of the create items to free. All create items with this context value will be freed.

Return Value

Returns STATUS_SUCCESS if the item was freed, else STATUS_OBJECT_NAME_NOT_FOUND.

Headers

Declared in ks.h. Include ks.h.

Comments

Instead of freeing create items by name as KsFreeObjectCreateItems does, this function will free all create items with a specific context. For example, all create items associated with a filter factory will have the factory as context and can be freed simultaneously with this call instead of one at a time. Note that this function does not assume that the caller is serializing multiple changes to the create entry list.

See Also

KsFreeObjectCreateItem


KsIncrementCountedWorker

Increments the current worker count, and optionally queues the counted work item with the worker previously created by KsRegisterCountedWorker.

KSDDKAPI ULONG NTAPI
  KsDecrementCountedWorker(
    IN PKSWORKER Worker
    );

Parameters

Worker
Contains the previously allocated worker.

Return Value

Returns the current counter. A count of one implies that a worker was actually scheduled.

Headers

Declared in ks.h. Include ks.h.

Comments

This should be called after an addition has been made to the worker's list of tasks to perform. A corresponding KsDecrementCountedWorker should be called within the work item after each task has been completed. This may be called at DISPATCH_LEVEL.


KsLoadResource

Copies (loads) a resource from the given image.

KSDDKAPI NTSTATUS NTAPI
  KsLoadResource(
    IN PVOID ImageBase,
    IN POOL_TYPE PoolType,
    IN ULONG_PTR ResourceName,
    IN ULONG ResourceType,
    OUT PVOID *Resource,
    OUT PULONG ResourceSize
    );

Parameters

ImageBase
Pointer to the image base
PoolType
Pool type to use when copying resource
ResourceName
Resource name.
ResourceType
Resource type
Resource
Pointer to resultant resource memory.
ResourceSize
Pointer to ULONG value to receive the size of the resource.

Return Value

STATUS_SUCCESS if successful, STATUS_INSUFFICIENT_RESOURCES if memory cannot be allocated, otherwise an appropriate error code.

Headers

Declared in ks.h. Include ks.h.


KsNullDriverUnload

The KsNullDriverUnload function is a default function a driver can use when it has no other tasks to do in its unload function, but must still allow the device to be unloaded by its presence.

VOID
  KsNullDriverUnload(
    IN PDRIVER_OBJECT  DriverObject
    );

Parameters

DriverObject
Specifies the driver object for this device.

Return Value

None

Headers

Declared in ks.h. Include ks.h.


KsPinDataIntersectionEx

Performs handling of the KSPROPERTY_PIN_DATAINTERSECTION through a callback.

KSDDKAPI NTSTATUS NTAPI
  KsPinDataIntersectionEx(
    IN PIRP Irp,
    IN PKSP_PIN Pin,
    OUT PVOID Data,
    IN ULONG DescriptorsCount,
    IN const KSPIN_DESCRIPTOR* Descriptor,
    IN ULONG DescriptorSize,
    IN PFNKSINTERSECTHANDLEREX IntersectHandler OPTIONAL,
    IN PVOID HandlerContext OPTIONAL
    );

Parameters

Irp
Contains the IRP with the property request being handled
Pin
Contains the specific property being queried.
Data
Contains the pin property specific data.
DescriptorsCount
Indicates the number of descriptor structures.
Descriptor
Contains the pointer to the list of pin information structures.
DescriptorSize
Size of the descriptor structures in bytes.
IntersectHandler
Contains the optional handler for comparison of a Data Range.
HandlerContext
Optional context supplied to the handler.

Return Value

Returns STATUS_SUCCESS, else an error specific to the property being handled.

Headers

Declared in ks.h. Include ks.h.

Comments

This is very similar to KsPinDataIntersection, except for some slight differences that are noted here. In this version, the size of the descriptor is passed, a feature that allows extended descriptors. Also, note that the callback is prototyped differently [NTSTATUS Callback (Context, Irp, Pin, DataRange, MatchingDataRange, DataBufferSize, Data, DataSize) versus the old version's NTSTATUS Callback (Irp, Pin, DataRange, Data)]. In the new version, the output buffer (Data) length is passed as a parameter to the callback (DataBufferSize) instead of needing to be extracted from the current I/O stack location. Also, the callback function is passed a context parameter (the same Context passed to KsPinDataIntersectionEx). Furthermore, the size of the resultant format is passed back in DataSize instead of Irp->IoStatus.Information. These differences excepted, the routines work quite similarly.


KsQueryDevicePnpObject

The KsQueryDevicePnpObject function returns the PnP device object that can be stored in the device header. This is the next device object on the PnP stack and is the device object that PnP requests are forwarded to if KsDefaultDispatchPnp is used.

KSDDKAPI PDEVICE_OBJECT NTAPI
  KsQueryDevicePnpObject(
    IN KSDEVICE_HEADER  Header
    );

Parameters

Header
Points to a header previously allocated by KsAllocateDeviceHeader whose PnP device object is to be returned.

Return Value

The KsQueryDevicePnpObject function returns the previously set PnP device object. If none was set, it returns NULL.

Headers

Declared in ks.h. Include ks.h.

See Also

KsDefaultDispatchPnp


KsQueueWorkItem

The KsQueueWorkItem function queues the specified work item with a worker previous created by the KsRegisterWorker function. The worker can only be on a queue in one place, so subsequent queuing of the worker must wait until the work item has begun executing. The function can only be called at DISPATCH_LEVEL.

KSDDKAPI NTSTATUS NTAPI
  KsQueueWorkItem(
    IN PKSWORKER  Worker,
    IN PWORK_QUEUE_ITEM  WorkItem
    );

Parameters

Worker
Specifies the previously allocated worker.
WorkItem
Specifies the initialized work item to queue. This work item is only associated with the worker as long as the worker is on a queue. The work item must have been initialized by ExInitializeWorkItem.

Return Value

The KsQueueWorkItem function returns STATUS_SUCCESS if the work item was queued, or if unsuccessful the function returns an error when attempting to create a new worker if no threads are currently available.

Headers

Declared in ks.h. Include ks.h.


KsRecalculateStackDepth

The KsRecalculateStackDepth function recalculates the maximum stack depth required by the underlying device object based on all of the objects that have set a target device (they have added themselves to the object list on the underlying device object using the KsSetTargetDeviceObject function). If the PnP device object has been set on the underlying device header using KsSetDevicePnpAndBaseObject, that device is also taken into account when calculating the maximum stack depth.

KSDDKAPI VOID NTAPI
  KsRecalculateStackDepth(
    IN KSDEVICE_HEADER  Header,
    IN BOOLEAN  ReuseStackLocation
    );

Parameters

Header
Points to a header previously allocated by KsAllocateDeviceHeader.
ReuseStackLocation
If this is set to TRUE, the current stack location is reused when any IRP is forwarded. This means that this object does not require its own stack location when forwarding IRPs and an extra location is not added to the maximum stack size. If set to FALSE, the calculated stack size is incremented by one. If the Pnp object stack is set, the reuse parameter also applies to that stack. Note that KsDefaultDispatchPnp always reuses the current stack location. The minimum stack depth is 1.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

The KsRecalculateStackDepth function assumes that KsSetDevicePnpAndBaseObject has been called on this device header and has assigned a base object whose stack depth is to be recalculated.

This function allows IRPs to be forwarded through an object by ensuring that any IRP allocated on this device will have sufficient stack locations to allow it to be forwarded. Stack depth must be recalculated on a streaming device when the device transitions out of a Stop state. It can also be recalculated when an object is freed in order to conserve resources.

See Also

KsSetTargetDeviceObject, KsAllocateDeviceHeader, KsSetDevicePnpAndBaseObject, KsDefaultDispatchPnp


KsReferenceBusObject

References the bus Physical device object.

KSDDKAPI NTSTATUS NTAPI
  KsReferenceBusObject(
    IN KSDEVICE_HEADER Header
    );

Parameters

Header
Points to a header previously allocated by KsAllocateDeviceHeader that also contains the PnP device stack object.

Return Value

Returns STATUS_SUCCESS if the reference was successful, else an error such as STATUS_INSUFFICIENT_RESOURCES.

Headers

Declared in ks.h. Include ks.h.

Comments

This function is used by filters that use the device header to keep track of their PnP object stack. This is normally called on a successful Open of the filter when the bus for this device requires such a reference (such as software devices), and is matched by a call to KsDereferenceBusObject on a close of that filter instance. The caller must have previously also called KsSetDevicePnpAndBaseObject in order to set the PnP device stack object. This would have been done in the PnP AddDevice function. If the object has not been previously referenced, interface space is allocated and the function uses the PnP device object to acquire the bus referencing interface. It then calls the ReferenceDeviceObject method on that interface. The interface itself is released and freed when the device header is freed.


KsRegisterCountedWorker

Handles clients registering for use of a thread.

KSDDKAPI NTSTATUS NTAPI
  KsRegisterCountedWorker(
    IN WORK_QUEUE_TYPE WorkQueueType,
    IN PWORK_QUEUE_ITEM CountedWorkItem,
    OUT PKSWORKER* Worker
    );

Parameters

WorkQueueType
Contains the priority of the work thread. This is normally one of the following: CriticalWorkQueue, DelayedWorkQueue, or HyperCriticalWorkQueue.
CountedWorkItem
Contains a pointer to the work queue item that will be queued as needed based on the current count value.
Worker
Contains the opaque context that must be used when scheduling a work item. Also contains the queue type, and is used to synchronize completion of work items.

Return Value

Returns STATUS_SUCCESS if a worker was initialized.

Headers

Declared in ks.h. Include ks.h.

Comments

This must be matched by a corresponding KsUnregisterWorker when thread use is completed. This function resembles KsRegisterWorker, with the addition of passing the work item that will always be queued. This is to be used with KsIncrementCountedWorker and KsDecrementCountedWorker in order to minimize the number of work items queued, and reduce mutual exclusion code necessary in a work item needed to serialize access against multiple work item threads. The worker queue can still be used to queue other work items. This may only be called at PASSIVE_LEVEL.


KsRegisterWorker

The KsRegisterWorker function handles clients registering for use of a thread. The function can create a new thread of the specified priority if there are currently no free threads available. This must be matched by a corresponding KsUnregisterWorker when thread use is completed. The function can only be called at PASSIVE_LEVEL.

typedef PVOID PKSWORKER;

The worker routines function on opaque PKSWORKER objects that are created for each work item queued at one time.

KSDDKAPI NTSTATUS NTAPI
  KsRegisterWorker(
    IN WORK_QUEUE_TYPE  WorkQueueType,
    OUT PKSWORKER*  Worker
    );

Parameters

WorkQueueType
Specifies the priority of the thread to create. This is usually either CriticalWorkQueue, DelayedWorkQueue, or HyperCriticalWorkQueue.
Worker
Location to put the opaque context that must be used when scheduling a work item. This contains the queue type and is used to synchronize completion of work items.

Return Value

The KsRegisterWorker function returns STATUS_SUCCESS if a worker was initialized, or if unsuccessful the function returns a thread or parameter error.

Headers

Declared in ks.h. Include ks.h.


KsSetDevicePnpAndBaseObject

The KsSetDevicePnpAndBaseObject function sets the PnP device object in the device header, which is the next device object on the PnP stack and is the device object that PnP requests are forwarded to if KsDefaultDispatchPnp is used.

KSDDKAPI VOID NTAPI
  KsSetDevicePnpAndBaseObject(
    IN KSDEVICE_HEADER  Header,
    IN PDEVICE_OBJECT  PnpDeviceObject,
    IN PDEVICE_OBJECT  BaseDevice
    );

Parameters

Header
Points to a header previously allocated by KsAllocateDeviceHeader in which to put the PnP device object.
PnpDeviceObject
Specifies the PnP device object to place in the device header, overwriting any previously set device object.
BaseDevice
Specifies the base device object to which this device header is attached. This must be set if KsRecalculateStackDepth is used.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

See Also

KsAllocateDeviceHeader, KsRecalculateStackDepth


KsSetPowerDispatch

Sets the power dispatch function to be called when the driver object receives an IRP_MJ_POWER IRP. This is only effective if KsDefaultDispatchPower is called to dispatch or complete power IRPs.

This has the effect of adding this object header to a list of object headers that have power dispatch routines to execute. The head of this list is kept by the device header. Assumes that the caller has previously allocated a device header on the underlying Device Object with KsAllocateDeviceHeader.

KSDDKAPI VOID NTAPI
KsSetPowerDispatch(
    IN KSOBJECT_HEADER  Header,
    IN PFNKSCONTEXT_DISPATCH  PowerDispatch  OPTIONAL,
    IN PVOID  PowerContext  OPTIONAL
    );

Parameters

Header
Points to a header previously allocated by KsAllocateObjectHeader.
PowerDispatch
Optionally contains the power dispatch function that will be called, or NULL if the function is to be removed from the list of functions being called. This function must not complete the power IRP sent. The return value of this function must be STATUS_SUCCESS. KsSetPowerDispatch can be called while executing this power dispatch routine if the purpose is to manipulate this list entry only. Manipulating other list entries may confuse the current enumeration.
PowerContext
Optionally contains the context parameter to pass to the power dispatch function.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

The PFNKSCONTEXT_DISPATCH function prototype describes the type of function expected to be called with IRP_MJ_POWER IRPs. The below Context parameter is the value passed in the above PowerContext parameter.

typedef NTSTATUS (*PFNKSCONTEXT_DISPATCH)(
  IN PVOID Context,
  IN PIRP Irp
  );


KsSetTargetDeviceObject

The KsSetTargetDeviceObject function sets the target device object of an object. The function adds the object header to a list of object headers that have target devices.

KSDDKAPI VOID NTAPI
  KsSetTargetDeviceObject(
    IN KSOBJECT_HEADER  Header,
    IN PDEVICE_OBJECT  TargetDevice  OPTIONAL
    );

Parameters

Header
Points to a header previously allocated by KsAllocateObjectHeader.
TargetDevice
Optionally contains the target device object that will be used when recalculating the stack depth for the underlying device object. If the value is NULL, any current setting is removed. If the value is any setting other than NULL, the current setting is replaced.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

The KsSetTargetDeviceObject function assumes that the caller has previously allocated a device header on the underlying device object with the KsAllocateDeviceHeader function. The presence of the device header allows future calls to the function KsRecalculateStackDepth, and the device header is used when the object will be forwarding IRPs through a connection to another device and needs to keep track of the stack depth.

If KsSetDevicePnpAndBaseObject is also used to assign the PnP object stack, that device object will also be taken into account when recalculating stack depth.

See Also

KsSetDevicePnpAndBaseObject, KsRecalculateStackDepth, KsAllocateDeviceHeader, KsAllocateObjectHeader


KsSetTargetState

Sets the enabled state of a target device associated with the specified object header.

KSDDKAPI VOID NTAPI
  KsSetTargetState(
    IN KSOBJECT_HEADER Header,
    IN KSTARGET_STATE TargetState
    );

Parameters

Header
Points to a header previously allocated by KsAllocateDeviceHeader.
TargetState
Contains the new state of the target associated with this object header. This may be either KSTARGET_STATE_DISABLED or KSTARGET_STATE_ENABLED.

Return Value

None.

Headers

Declared in ks.h. Include ks.h.

Comments

Assumes that such a target has been set with KsSetTargetDeviceObject. The target is initially disabled, and is ignored when recalculating stack depth. For WDM Streaming devices, this is called on a transition back to a Stop state, after having enabled the target and used KsRecalculateStackDepth on a transition to Acquire state. This allows the stack depth to be minimized.


KsUnregisterWorker

The KsUnregisterWorker function allows clients to unregister a worker. The function can destroy threads, depending on the number of threads in use. This must only be used after successful execution of KsRegisterWorker. The function can only be called at PASSIVE_LEVEL.

KSDDKAPI VOID NTAPI
  KsUnregisterWorker(
    IN PKSWORKER  Worker
    );

Parameters

Worker
Specifies the previously allocated worker to be unregistered. The function will wait until any outstanding work item is completed.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

The client must ensure that outstanding I/O initiated on any worker thread has been completed before unregistering the worker has been completed. This means canceling or completing outstanding I/O either before unregistering the worker, or before the worker item returns from its callback for the last time and is unregistered. Unregistering of a worker will wait for any currently queued work items to complete before returning.


KsValidateAllocatorFramingEx

Validates allocator framing submitted in a 'set' of the property KSPROPERTY_CONNECTION_ALLOCATORFRAMING_EX.

KSDDKAPI NTSTATUS NTAPI
  KsValidateAllocatorFramingEx(
    IN PKSALLOCATOR_FRAMING_EX Framing,
    IN ULONG BufferSize,
    IN const KSALLOCATOR_FRAMING_EX *PinFraming
    );

Parameters

Framing
Contains the framing structure to validate.
BufferSize
Contains the size of the buffer containing the framing structure.
PinFraming
Contains the framing structure exposed by the pin. This is the structure that is returned when a 'get' is performed on the same property.

Return Value

Returns STATUS_SUCCESS, else an error.

Headers

Declared in ks.h. Include ks.h.


Kernel Streaming Property Sets

This section documents general kernel streaming property sets that may optionally apply across the broad spectrum of technology types. Property sets that are device-type specific are covered in the documentation on how to write that type of driver.


KSPROPSETID_Clock

Kernel streaming clock objects support the KSPROPSETID_Clock property set. Clients can use these properties to examine the clock state.


KSPROPERTY_CLOCK_CORRELATEDPHYSICALTIME

Read-only. Clients use KSPROPERTY_CLOCK_CORRELATEDPHYSICALTIME to compare the current physical time on a clock to the current system time.

Specifying This Property

KSPROPERTY

Property Data

KSCORRELATED_TIME, a data structure of the form:

typedef struct {
    LONGLONG Time;
    LONGLONG SystemTime;
} KSCORRELATED_TIME;

The Time member contains the current physical time (see KSPROPERTY_CLOCK_PHYSICALTIME), while SystemTime contains the current system time as reported by KeQueryPerformanceCounter.


KSPROPERTY_CLOCK_CORRELATEDTIME

Read-only. Clients use KSPROPERTY_CLOCK_CORRELATEDTIME to compare the current presentation time on a clock to the current system time.

Specifying This Property

KSPROPERTY

Property Data

KSCORRELATED_TIME, a data structure of the form:

typedef struct {
    LONGLONG Time;
    LONGLONG SystemTime;
} KSCORRELATED_TIME;

The Time member contains the current presentation time (see KSPROPERTY_CLOCK_TIME), while SystemTime contains the current system time as reported by KeQueryPerformanceCounter.


KSPROPERTY_CLOCK_FUNCTIONTABLE

The KSPROPERTY_CLOCK_FUNCTIONABLE property is used to retrieve the entry points for querying time at DISPATCH_LEVEL, which allows filters to perform precise rate matching. This property fills in a KSCLOCK_FUNCTIONTABLE structure with function pointers that are valid until the file object for the clock is released.

A client can access this property using the following sample code:

DeviceIoControl(
    DeviceHandle,
    IOCTL_KS_PROPERTY,
    &Property,
    sizeof(KSPROPERTY),
    &FunctionTable,
    sizeof(FunctionTable),
    &BytesReturned,
    &Overlapped);

The KSCLOCK_FUNCTIONTABLE structure is as follows:

typedef struct {
  PFNKSCLOCK_GETTIME  GetTime;
  PFNKSCLOCK_GETTIME  GetPhysicalTime;
  PFNKSCLOCK_CORRELATEDTIME  GetCorrelatededTime;
  PFNKSCLOCK_CORRELATEDTIME  GetCorrelatededPhysicalTime;
} KSCLOCK_FUNCTIONTABLE;

Members

GetTime
Indicates the entry point used to retrieve the current clock time.
GetPhysicalTime
Indicates the entry point used to retrieve the current underlying physical time.
GetCorrelatededTime
Indicates the entry point used to retrieve the current clock time and a correlated system time as an atomic operation.
GetCorrelatedPhysicalTime
Indicates the entry point used to retrieve the current physical time and a correlated system time as an atomic operation.

Comments

Two typedef functions are used to retrieve the current clock time and the clock's physical time. The following typedef function is used in the function table for retrieving both the current clock time and the clock's physical time. For retrieving a clock time synchronized with the system clock, the second typedef function is used.

PFNKSCLOCK_GETTIME

typedef LONGLONG (FASTCALL *PFNKSCLOCK_GETTIME)(
    IN PFILE_OBJECT    FileObject);

Parameters

FileObject
Specifies the file object underlying the file handle that was returned when the clock instance was created.

Return Values

Returns a time value.

PFNKSCLOCK_CORRELATEDTIME

typedef LONGLONG (FASTCALL *PFNKSCLOCK_CORRELATEDTIME)(
  IN PFILE_OBJECT  FileObject,
  OUT PULONGLONG   SystemTime);

Parameters

FileObject
Specifies the file object underlying the file handle that was returned on creating the clock instance.
SystemTime
Points to the location to store the correlated system time. The system time is acquired using the function KeQueryInterrruptTime.

Return Values

Returns a clock time value that is correlated to the returned system time.


KSPROPERTY_CLOCK_PHYSICALTIME

Read-only. Clients use KSPROPERTY_CLOCK_PHYSICAL_TIME to determine the current physical time of a clock.

Specifying This Property

KSPROPERTY

Property Data

LONGLONG, representing the current physical time in 100-nanosecond units.

Comments

The physical time of a clock is an ever-progressing counter. Unlike the presentation time, it cannot reverse.

Clocks are not required to support a 100-nanosecond resolution. To determine the clock resolution, clients can use the KSPROPERTY_CLOCK_RESOLUTION request.


KSPROPERTY_CLOCK_RESOLUTION

Clients use KSPROPERTY_CLOCK_RESOLUTION to determine the precision of a clock.

Specifying This Property

KSPROPERTY

Property Data

KSRESOLUTION, a data structure of the form:

typedef struct {
    LONGLONG Granularity;
    LONGLONG Error;
} KSRESOLUTION;

The Granularity member specifies the accuracy of the clock, in 100-nanosecond units. The Error member specifies any additional delay the clock has in issuing a clock event notification, in 100-nanosecond units.

Comments

The delay introduced in the Error member is in addition to that in the Granularity member. For example, a clock with a Granularity of one and Error of two would be able to issue clock event notifications every 300 nanoseconds.


KSPROPERTY_CLOCK_TIME

Clients use KSPROPERTY_CLOCK_TIME to determine the current presentation time on a clock.

Specifying This Property

KSPROPERTY.

Property Data

LONGLONG, specifying the current presentation time in 100-nanosecond units.

Comments

The presentation time of a clock can be reversed, unlike the physical time. The presentation time of a clock typically represents a timestamp on an underlying data stream. For example, a clock for a DVD player can report the timestamp of the current position in the DVD as its presentation time.

Clocks are not required to support a 100-nanosecond resolution. To determine the clock resolution, clients can use the KSPROPERTY_CLOCK_RESOLUTION request.


KSPROPSETID_Connection

Clients use the properties in the KSPROPSETID_Connection property set to examine or set the state of a connection on a pin. Pin instances handle these properties.

Stream minidrivers do not have to handle the KSPROPERTY_CONNECTION_STATE, KSPROPERTY_CONNECTION_PROPOSEDATAFORMAT, and KSPROPERTY_CONNECTION_DATAFORMAT properties directly. The stream class driver handles them, using Stream Request Blocks (SRB) to query for more information where necessary.


KSPROPERTY_CONNECTION_ALLOCATORFRAMING

Read-only. Clients use this property to determine framing requirements for a pin.

Specifying This Property

KSPROPERTY

Property Data

KSALLOCATOR_FRAMING, which describes the framing requirements for the pin. For example, the FrameSize member specifies the frame size of data on the pin.


KSPROPERTY_CONNECTION_ACQUIREORDERING

The KSPROPERTY_CONNECTION_ACQUIREORDERING property is an optional property that is should be implemented on a pin when state change order is significant. For example, the property should be implemented on communication sink pins if the sink requires pins connected to its communication source pins to be set to an Acquire state before the sink pins are set.

This read-only property is used to determine whether the Stop-to-Acquire state change is significant for this communication sink pin. If the property is not implemented, the assumption is that ordering is not significant. For IRP-based data flow, this would be implemented by a pin when it forwards streaming IRPs rather than creating new IRPs for requests, and thus needs to indicate correct stack depth to the connected source pin. If the pin did not forward IRPs, then recalculation of stack depth would not be important, as the stack depth for the filter would be static. For more information on stack-depth recalculation, see Recalculating Stack Depth.

A client can access this property using the following sample code:

DeviceIoControl(
    DeviceHandle,
    IOCTL_KS_PROPERTY,
    Property,
    sizeof(KSPROPERTY),
    &AcquireOrdering,
    sizeof(BOOL),
    &BytesReturned,
    &Overlapped);

Parameters

Property
Specifies the property identifier.

Return Values

Returns TRUE if state change ordering is significant. Otherwise, it returns FALSE. If FALSE is to be returned, the property need not be implemented.


KSPROPERTY_CONNECTION_DATAFORMAT

Read/write. Clients use this to get or set the current data format.

Specifying This Property

KSPROPERTY

Property Data

KSDATAFORMAT, specifying the current data format.

Comments

KS filters only need to support this property if they allow clients to reset the current property, or if connections can be made with the data format incompletely specified.


KSPROPERTY_CONNECTION_PRIORITY

Read/write. Clients use KSPROPERTY_CONNECTION_PRIORITY to get or set the priority of a connection.

Specifying This Property

KSPROPERTY

Property Data

KSPRIORITY, a structure of the form:

typedef struct {
    ULONG PriorityClass;
    ULONG PrioritySubClass;
} KSPRIORITY;

One priority is greater than another if the PriorityClass member is greater, or if the PriorityClass members are identical and the PrioritySubClass member is greater.

The following predefined values of PriorityClass are available: KSPRIORITY_LOW, KSPRIORITY_NORMAL, KSPRIORITY_HIGH, and KSPRIORITY_EXCLUSIVE. Priority defaults to KSPRIORITY_NORMAL. KSPRIORITY_EXCLUSIVE indicates the connection has exclusive access to resources used by a pin.

Comments

The priority values have global significance: a client can use the reported values to set priorities between two different pins on two unrelated kernel streaming (KS) filters.

KSPROPERTY_CONNECTION_PRIORITY is an optional property. Clients treat pins that do not support it as having priority KSPRIORITY_NORMAL.


KSPROPERTY_CONNECTION_PROPOSEDATAFORMAT

Write-only. Clients can use this to propose a new data format for the connection. The KS filter returns STATUS_SUCCESS if the pin can be reset to the proposed data format, or an error code otherwise.

Specifying This Property

KSPROPERTY

Property Data

KSDATAFORMAT, specifying the proposed data format.

Comments

Note that this property request does not change the data format. Clients use the KSPROPERTY_CONNECTION_DATAFORMAT to change the format.


KSPROPERTY_CONNECTION_STATE

KSPROPERTY_CONNECTION_STATE specifies the current run state of the pin. The pin only reads or writes data in the KSSTATE_RUN state.

Specifying this Property

KSPROPERTY

Property Data

One of the following values:

Value | Description
KSSTATE_STOP | The initial state of a pin. No data is actually being read or written. In this state, the pin uses the least amount of resources possible.
KSSTATE_ACQUIRE | The pin is acquiring the resources necessary to read or write data.
KSSTATE_PAUSE | The pin is ready to read or write data, but data transfer is temporarily paused.
KSSTATE_RUN | The state from which the pin can actually read or write data.

Comments

Both individual pins and the KS filter as a whole may support this property.


KSPROPSETID_General

The KSPROPSETID_General Property Set specifies the general filter characteristics that can be queried. Some or all of this property set can be supported by a filter pin. The properties are enumerated in KSPROPERTY_GENERAL.


KSPROPERTY_GENERAL_COMPONENTID

The KSPROPERTY_GENERAL_COMPONENTID property is an optional property that allows a client to access general component information stored in the KSCOMPONENT_ID structure. A client can access information in this property using the following sample code:

DeviceIoControl(
    DeviceHandle,
    IOCTL_KS_PROPERTY,
    &Property,
    sizeof(KSPROPERTY),
    &Component,
    sizeof(KSCOMPONENTID),
    &BytesReturned,
    &Overlapped);


KSPROPSETID_MediaSeeking

The KSPROPSETID_MediaSeeking property set specifies the media seeking characteristics that can be queried and manipulated. All of this property set can be supported by a filter instance that uses media seeking.

The KSPROPSETID_MediaSeeking property set includes:

KSPROPERTY_MEDIASEEKING_CAPABILITIES

KSPROPERTY_MEDIASEEKING_FORMATS

KSPROPERTY_MEDIASEEKING_TIMEFORMAT

KSPROPERTY_MEDIASEEKING_POSITION

KSPROPERTY_MEDIASEEKING_STOPPOSITION

KSPROPERTY_MEDIASEEKING_POSITIONS

KSPROPERTY_MEDIASEEKING_DURATION

KSPROPERTY_MEDIASEEKING_AVAILABLE

KSPROPERTY_MEDIASEEKING_PREROLL

KSPROPERTY_MEDIASEEKING_CONVERTTIMEFORMAT


KSPROPERTY_MEDIASEEKING_CAPABILITIES

The KSPROPERTY_MEDIASEEKING_CAPABILITIES read-only property retrieves the media-seeking capabilities of a filter. These capabilities include the ability to seek to an absolute position, to seek forwards or backwards in the media, to get the current position while in play or stop mode, to get the duration, or to play backwards. Note that these are capabilities of the filter as a whole; this property is designed to map to DirectShow seeking capabilities, where such capabilities are queried only on a filter, not a pin, basis.

If this property is not supported, it is assumed that the filter does not require positional information and that the filter can be treated as a pass through.

A client can access this property using the following sample code:

DeviceIoControl(
    FilterHandle,
    IOCTL_KS_PROPERTY,
    &Property,
    sizeof(KSPROPERTY),
    &SeekingCapabilities,
    sizeof(KS_SEEKING_CAPABILITIES),
    &BytesReturned,
    &Overlapped);


KSPROPERTY_MEDIASEEKING_FORMATS

The KSPROPERTY_MEDIASEEKING_FORMATS read-only property retrieves the media time formats supported by a filter. This information is returned as a multiple item property.

A client can access this property using the following sample code:

DeviceIoControl(
    FilterHandle,
    IOCTL_KS_PROPERTY,
    &Property,
    sizeof(KSPROPERTY),
    &SeekingFormats,
    SeekingFormatLength,
    &BytesReturned,
    &Overlapped);


KSPROPERTY_MEDIASEEKING_TIMEFORMAT

The KSPROPERTY_MEDIASEEKING_TIMEFORMAT read-only property retrieves the current media time format for a filter. The property sets the current media time format that is returned as a time format GUID.

A client can access this property using the following sample code:

DeviceIoControl(
    FilterHandle,
    IOCTL_KS_PROPERTY,
    &Property,
    sizeof(KSPROPERTY),
    &SeekingTimeFormat,
    sizeof(GUID),
    &BytesReturned,
    &Overlapped);


KSPROPERTY_MEDIASEEKING_POSITION

The KSPROPERTY_MEDIASEEKING_POSITION read-only property retrieves the media time of a filter.

A client can access this property using the following sample code:

DeviceIoControl(
    FilterHandle,
    IOCTL_KS_PROPERTY,
    &Property,
    sizeof(KSPROPERTY),
    &Position,
    sizeof(LONGLONG),
    &BytesReturned,
    &Overlapped);


KSPROPERTY_MEDIASEEKING_STOPPOSITION

The KSPROPERTY_MEDIASEEKING_STOPPOSITION read-only property retrieves the stop media time on a filter. The stop media time is the time that can be set if a stop time is supported by the filter.

A client can access this property using the following sample code:

DeviceIoControl(
    FilterHandle,
    IOCTL_KS_PROPERTY,
    &Property,
    sizeof(KSPROPERTY),
    &StopPosition,
    sizeof(LONGLONG),
    &BytesReturned,
    &Overlapped);


KSPROPERTY_MEDIASEEKING_POSITIONS

The KSPROPERTY_MEDIASEEKING_POSITIONS write-only property sets the media time and/or the stop time on a filter.

A client can access this property using the following sample code:

DeviceIoControl(
    FilterHandle,
    IOCTL_KS_PROPERTY,
    &Property,
    sizeof(KSPROPERTY),
    &Positions,
    sizeof(KSPROPERTY_POSITIONS),
    &BytesReturned,
    &Overlapped);


KSPROPERTY_MEDIASEEKING_DURATION

The KSPROPERTY_MEDIASEEKING_DURATION read-only property retrieves the media duration on a filter.

A client can access this property using the following sample code:

DeviceIoControl(
    FilterHandle,
    IOCTL_KS_PROPERTY,
    &Property,
    sizeof(KSPROPERTY),
    &Duration,
    sizeof(LONGLONG),
    &BytesReturned,
    &Overlapped);


KSPROPERTY_MEDIASEEKING_AVAILABLE

The KSPROPERTY_MEDIASEEKING_AVAILABLE read-only property retrieves the media time span (the time span that a client can seek within) that is currently available on a filter.

A client can access this property using the following sample code:

DeviceIoControl(
    FilterHandle,
    IOCTL_KS_PROPERTY,
    &Property,
    sizeof(KSPROPERTY),
    &Available,
    sizeof(KSPROPERTY_MEDIAAVAILABLE),
    &BytesReturned,
    &Overlapped);


KSPROPERTY_MEDIASEEKING_PREROLL

The KSPROPERTY_MEDIASEEKING_PREROLL read-only property retrieves the amount of preroll in 100-nanosecond units required on a filter.

A client can access this property using the following sample code:

DeviceIoControl(
    FilterHandle,
    IOCTL_KS_PROPERTY,
    &Property,
    sizeof(KSPROPERTY),
    &Preroll,
    sizeof(LONGLONG),
    &BytesReturned,
    &Overlapped);


KSPROPERTY_MEDIASEEKING_CONVERTTIMEFORMAT

The KSPROPERTY_MEDIASEEKING_CONVERTTIMEFORMAT read-only property converts the specified media time from one supported format to another.

A client can access this property using the following sample code:

DeviceIoControl(
    FilterHandle,
    IOCTL_KS_PROPERTY,
    &PropertyTimeFormat,
    sizeof(KSP_TIMEFORMAT),
    &Time,
    sizeof(LONGLONG),
    &BytesReturned,
    &Overlapped);


KSPROPSETID_Pin

Clients use the properties in the KSPROPSETID_Pin property set to query a KS filter for information on each pin factory it supports.

The KSPROPERTY_PIN_CTYPES property specifies how many pin factories the KS filter supports. All other properties in this property set specify information about an individual pin factory. The KS filter identifies each pin factory by an ID, which ranges from zero to the number of pin factories minus one. The client includes the pin factory ID within the KSP_PIN structure it uses when it issues the property request.

Stream minidrivers do not have to handle most of these properties directly. The stream class driver handles them, using Stream Request Blocks (SRBs) to query for more information where necessary. The exceptions are: KSPROPERTY_PIN_GLOBALCINSTANCES, KSPROPERTY_PIN_NECESSARYINSTANCES, and KSPROPERTY_PIN_PHYSICALCONNECTION.


KSPROPERTY_PIN_CATEGORY

Read-only. The category of the pin factory.

Specifying This Property

KSP_PIN. The PinId member specifies the pin factory.

Property Data

GUID that represents the category.


KSPROPERTY_PIN_CINSTANCES

Read-only. The current number of pins this pin factory has instantiated, as well as the maximum number of pins this pin factory can instantiate, per filter.

Specifying This Property

KSP_PIN. The PinId member specifies the pin factory.

Property Data

KSPIN_CINSTANCES, a data structure of the form:

typedef struct {
    ULONG PossibleCount;
    ULONG CurrentCount;
} KSPIN_CINSTANCES;

The following is a description of each member of the KSPIN_CINSTANCES structure.

PossibleCount
Specifies the maximum number of pins the pin factory can instantiate on the filter, or KSINTANCE_INDETERMINATE if there is no maximum.
CurrentCount
Specifies the current number of pins the pin factory has instantiated on the filter.

Comments

This property specifies the per-filter maximum for a given pin factory. Use the KSPROPERTY_PIN_GLOBALCINSTANCES property to specify the overall maximum for a given pin factory.


KSPROPERTY_PIN_COMMUNICATION

Read-only. The communication direction of pins instantiated on a pin factory.

Specifying this Property

KSP_PIN. The PinId member specifies the pin factory.

Property Data

The KS filter returns one of the following values, which specifies the communication direction of a pin instantiated by this pin factory:

KSPIN_COMMUNICATION_NONE
The pin factory does not instantiate any pins.
KSPIN_COMMUNICATION_SINK
The pin factory instantiates IRP sink pins. Such pins can only be connected to IRP source pins.
KSPIN_COMMUNICATION_SOURCE
The pin factory instantiates IRP source pins. Such pins can only be connected to IRP sink pins.
KSPIN_COMMUNICATION_BOTH
The pin factory instantiates pins that are both IRP sinks and IRP sources.
KSPIN_COMMUNICATION_BRIDGE
This pin cannot connect to other pins, but instances may be created on it to receive non-KS I/O requests.

Comments

Source pins send IRPs to sink pins. Do not confuse the communication direction with data flow direction. (See KSPROPERTY_PIN_DATAFLOW.) A source pin may read or write data, and a sink pin may have data read to it or written from it.


KSPROPERTY_PIN_CONSTRAINEDDATARANGES

Read-only. This property specifies the list of data ranges currently supported by pins instantiated on the pin factory.

Specifying This Property

KSP_PIN. The PinId member specifies the pin factory.

Property Data

A KSMULTIPLE_ITEM structure, followed by a sequence of 64-bit aligned KSDATARANGE structures.

Comments

A KS filter uses this property to report the data ranges currently supported by pins instantiated on this pin factory, based on any constraints imposed by the current internal state of the KS filter. Use the KSPROPERTY_PIN_DATARANGES property to report the complete list of all data ranges supported by the KS filter, regardless of dynamic constraints.


KSPROPERTY_PIN_CTYPES

Read-only. Clients use this request to determine how many pin types a KS filter supports.

Specifying This Property

KSPROPERTY

Property Data

ULONG. The number of pin factories the KS filter supports.


KSPROPERTY_PIN_DATAFLOW

Read-only. Clients use this property to determine if data flows in or out of a pin type.

Specifying This Property

KSP_PIN. The PinId member specifies the pin factory.

Property Data

The KS filter returns one or more of the following flags:

KSPIN_DATAFLOW_IN
The pin factory instantiates data sink pins. Such pins can only be connected to data source pins.
KSPIN_DATAFLOW_OUT
The pin factory instantiates data source pins. Such pins can only be connected to data sink pins.


KSPROPERTY_PIN_DATAINTERSECTION

Read-only. The client supplies a list of data formats. The KS filter returns the first data format on that list supported by pins instantiated by the pin factory.

Specifying This Property

A KSP_PIN structure, followed by a KSMULTIPLE_ITEM structure and a sequence of 64-bit aligned KSDATARANGE structures. The PinId member of KSP_PIN specifies the pin factory.

Property Data

KSDATAFORMAT, the first matching data format.


KSPROPERTY_PIN_DATARANGES

Read-only. Clients use this property to determine the data ranges supported by pins instantiated by the pin factory.

Specifying This Property

KSP_PIN. The PinId member specifies the pin factory.

Property Data

A KSMULTIPLE_ITEM structure, followed by a sequence of 64-bit aligned KSDATARANGE structures.

Comments

KS filters return all data ranges supported by pins instantiated by the pin factory. A KS filter may not support a reported data range in its current internal state. To determine the data ranges supported by the current internal state, use KSPROPERTY_PIN_CONSTRAINEDDATARANGES.


KSPROPERTY_PIN_GLOBALCINSTANCES

Read-only. The current number of pins this pin factory has instantiated, as well as the maximum number of pins this pin factory can instantiate. This property is optional.

Specifying This Property

KSP_PIN. The PinId member specifies the pin factory.

Property Data

KSPIN_CINSTANCES, a data structure of the form:

typedef struct {
    ULONG PossibleCount;
    ULONG CurrentCount;
} KSPIN_CINSTANCES;

The following is a description of each member of the KSPIN_CINSTANCES structure.

PossibleCount
Specifies the maximum number of pin the pin factory can instantiate on the driver, or KSINTANCE_INDETERMINATE if there is no maximum.
CurrentCount
Specifies the current number of pins the pin factory has instantiated on the driver.

Comments

KSPROPERTY_PIN_GLOBALCINSTANCES specifies the absolute current and maximum number of instances, over all instances of the filter. To determine per-filter values, use KSPROPERTY_PIN_CINSTANCES.


KSPROPERTY_PIN_INTERFACES

Read-only. The list of interfaces supported by pins instantiated by the pin factory.

Specifying This Property

KSP_PIN. The PinId member specifies the pin factory.

Property Data

A KSMULTIPLE_ITEM structure, followed by a sequence of KSPIN_INTERFACE structures. The interfaces are ordered by preference.


KSPROPERTY_PIN_MEDIUMS

Read-only. The list of mediums supported by pins instantiated by the pin factory.

Specifying This Property

KSP_PIN. The PinId member specifies the pin factory.

Property Data

A KSMULTIPLE_ITEM structure, followed by a sequence of KSPIN_MEDIUM structures. The mediums are ordered by preference.

Comments

For more information on mediums, please see related information in the Pin Connections section. Also see the KSPIN_MEDIUM structure.


KSPROPERTY_PIN_NAME

Read-only. The localized Unicode string name for the pin factory.

Specifying This Property

KSP_PIN. The PinId member specifies the pin factory.

Property Data

A buffer containing the localized Unicode string.


KSPROPERTY_PIN_NECESSARYINSTANCES

Read-only. The minimum number of pins that the pin factory must instantiate before the filter can perform I/O operations.

Specifying This Property

KSP_PIN. The PinId member specifies the pin factory.

Property Data

ULONG, specifying the minimum number of pins that the pin factory must instantiate.


KSPROPERTY_PIN_PHYSICALCONNECTION

Specifying This Property

KSP_PIN. The PinId member specifies the pin factory.

Property Data

Built on Wednesday, July 11, 2001


KSPROPERTY_PIN_PROPOSEDATAFORMAT

Write-only. Clients use this to determine pins instantiated by the pin factory support a specific data format. The KS filter returns STATUS_SUCCESS if pins can be reset to the proposed data format, or an error code otherwise.

Specifying This Property

KSP_PIN. The PinId member specifies the pin factory.

Property Data

A KSDATAFORMAT structure, specifying the proposed data format.

Comments

This property does not actually change the data format. Clients use KSPROPERTY_CONNECTION_DATAFORMAT to change the data format.


KSPROPSETID_Stream Property Set

Clients use properties in the KSPROPSETID_Stream property set to query a pin for its stream state properties.

The KSPROPSETID_Stream property set is enumerated by KSPROPERTY_STREAM and includes:

KSPROPERTY_STREAM_ALLOCATOR

KSPROPERTY_STREAM_QUALITY

KSPROPERTY_STREAM_DEGRADATION

KSPROPERTY_STREAM_MASTERCLOCK

KSPROPERTY_STREAM_TIMEFORMAT

KSPROPERTY_STREAM_PRESENTATIONTIME

KSPROPERTY_STREAM_PRESENTATIONEXTENT

KSPROPERTY_STREAM_FRAMETIME

KSPROPERTY_STREAM_RATECAPABILITY

KSPROPERTY_STREAM_RATE


KSPROPERTY_STREAM_ALLOCATOR

The KSPROPERTY_STREAM_ALLOCATOR property is an optional property that should be implemented if the pin allocates stream buffers or can provide an allocator. It may be read-only, write-only, or read/write, depending on the following situations.

The property sets the handle of the allocator assigned to the stream connection point. A connection point for KSPIN_COMMUNICATION_SOURCE checks the property to determine the handle of the allocator that should be used for data allocations. This property is typically set by a graph manager such as DirectShow.

An allocator handle is obtained and can be used to set the allocator for another filter pin. A filter using the allocator must reference the object to obtain a pointer to a file object and dereference the file object when a new allocator is assigned or when the connection is closed. The property can also be queried to determine if this connection point supports providing an allocator.

A client can access this property using the following sample code:

DeviceIoControl(
    DeviceHandle,
    IOCTL_KS_PROPERTY,
    &Allocator,
    sizeof(KSPROPERTY),
    &AllocatorHandle,
    sizeof(HANDLE),
    &BytesReturned,
    &Overlapped);

Return Values

The returned value is always a NULL handle. However, support is determined by whether or not the call returns successfully.


KSPROPERTY_STREAM_QUALITY

The KSPROPERTY_STREAM_QUALITY property is an optional write-only property that should be implemented if the pin generates Quality Management complaints. If a pin does not report quality problems, it does not need to support this property.

A client can set this property to the handle and context parameter of a Quality Management complaint sink. The pin connection uses this information to notify the Quality Manager of problems using KSQUALITY structures with the given context parameter.

The property takes a KSQUALITY_MANAGER structure, which contains the handle of the Quality Manager sink, and a context to pass in the quality complaints.

typedef struct {
  HANDLE  QualityManager;
  PVOID   Context;
} KSQUALITY_MANAGER;
QualityManager
Contains the handle to the quality manager that will be sent KSQUALITY complaint structures using KSMETHOD_QUALITY_REPORT. This handle must be referenced in order to later use it.
Context
Contains the context parameter to use when reporting quality problems. This is used by the quality manager to distinguish between various clients that may be using the same file object to send complaints to.

A client can access this property using the following sample code:

DeviceIoControl(
    DeviceHandle,
    IOCTL_KS_PROPERTY,
    &Property,
    sizeof(KSPROPERTY),
    &Manager,
    sizeof(KSQUALITY_MANAGER),
    &BytesReturned,
    &Overlapped);


KSPROPERTY_STREAM_DEGRADATION

The KSPROPERTY_STREAM_DEGRADATION property is an optional property that should be implemented if the pin allows degradation strategies.

A client can query this property to retrieve the current degradation settings or it can set this property to change the current degradation settings. The degradation settings are used to modify the usage of resources by a filter pin in response to a QM complaint, or to adjust quality back to some higher level. This is typically used by a Quality Manager to adjust degradation settings, and query the type of setting that can be adjusted and their current values. It may pass multiple KSDEGRADE structures when setting values. For more information on Quality Managers, see Quality Management.

On a query, this property returns the size and count of the structures to be returned in KSMULTIPLE_ITEM format, followed by KSDEGRADE structures. The multiple item format must be used on both querying and setting degradation strategies. A client can access this property using the following sample code:

DeviceIoControl(
    DeviceHandle,
    IOCTL_KS_PROPERTY,
    &Property,
    sizeof(KSPROPERTY),
    &Degradation,
    DegradationSize,
    &BytesReturned,
    &Overlapped);

Return Values

When queried, the property returns the size and count of the structures to be returned in KSMULTIPLE_ITEM format, followed by KSDEGRADE structures.


KSPROPERTY_STREAM_MASTERCLOCK

The KSPROPERTY_STREAM_MASTERCLOCK property is an optional property that should be implemented if the pin uses or produces a master clock that can be used for synchronization.

The property can be used to query whether a master clock is supported by a pin or to set the current master clock for a pin. This is typically done through a graph manager, such as in DirectShow. A master clock handle is retrieved and can be used to set the master clock on another pin, or can be used as the user mode proxy of a master clock, such as in a DirectShow graph.

When the clock is set on a pin, the pin references the underlying file object and can later perform queries against that file object. The file handle itself must be closed by the client that queried for the handle.

A filter does not need to support the property when it neither produces a master clock nor needs to reference one, such as a converter filter placed in the middle of a graph with no need to synchronize with other streams. The property can also be used as read-only when a filter produces a master clock but does not synchronize to an external master clock.

A client can access this property using the following sample code:

DeviceIoControl(
    DeviceHandle,
    IOCTL_KS_PROPERTY,
    &Property,
    sizeof(KSPROPERTY),
    &ClockHandle,
    sizeof(HANDLE),
    &BytesReturned,
    &Overlapped);

Return Values

The property returns a NULL handle when queried. Support is determined by whether or not the call returns successfully.


KSPROPERTY_STREAM_TIMEFORMAT

The KSPROPERTY_STREAM_TIMEFORMAT property is an optional property that should be implemented if the pin supports the Rate, Presentation Time/Extent, or Skip Degradation properties (for more information on these properties, see Quality Management). This allows a client to easily determine the time format used for connection and the format of the time stamp information used in Rate, Presentation Time/Extent, and Skip Degradation operations. The property is used to retrieve the time format used on a particular pin connection.

A client can access this property using the following sample code:

DeviceIoControl(
    DeviceHandle,
    IOCTL_KS_PROPERTY,
    &Property,
    sizeof(KSPROPERTY),
    &Guid,
    sizeof(GUID),
    &BytesReturned,
    &Overlapped);

Return Values

The property returns a GUID specifying the time format used in the connection and indicating the format of the presentation time and extent. The defined time formats correspond to those defined by DirectShow.


KSPROPERTY_STREAM_PRESENTATIONTIME

The KSPROPERTY_STREAM_PRESENTATIONTIME property is an optional property that should be implemented if a pin retains positional information or uses different interfaces with different time stamp formats on topologically related pins. Therefore, it would need to have the time stamps translated as a seek presentation time occurs.

This property is used to retrieve and set the current presentation time of a filter pin. The time is specified as a KSTIME value whose interpretation depends on the interface used. For the standard streaming interface, time is specified in 100-nanosecond increments (unless the numerator and denominator specify otherwise) representing the presentation position of the stream the filter is currently processing or is seeking to process. If this is a rendering filter, this position represents the data that is currently being rendered. This positioning information is synchronized with the master clock's presentation time. Presentation time typically begins at zero and may represent a time offset into file data.

If this was the standard position interface, the value is nominally a byte position in the stream unless the numerator and denominator specify otherwise. The numerator and denominator can be used to specify block alignment that the interface enforces. Presumably, the denominator is always one, and the numerator indicates the multiplication factor and, thus, the enforced alignment.

This property is also used when translating positional values during propagation of a seek request. The seek positional value on one pin is translated within the filter to presentation time on topologically related pins. A client sets this property with a new stream position in order to seek. This would typically be called by the proxy when a seek is required after canceling outstanding I/O and resetting device state. If a reset has not been performed, the filter may have to automatically cancel and reset appropriately. The property is passed a KSTIME containing the new stream position in units consistent with the interface used on the connection.

After a client (for example, a DirectShow proxy) writes a seek request to one connection, it then queries the other topologically related connections for a presentation time. Any other connections that conduct a successful read request make the proxy pass the result position to the other end of that connection. In this manner, seek positions are propagated (for example, throughout the DirectShow graph) without having to know the unit format other than the initial unit format passed by a client. Translations occurs within the filter as the positional information propagates through the topology within a filter. This roundabout method is used because communication methods may be limited between various filters in a graph depending on the Interfaces they use. When setting a new seek position, the numerator/denominator pair must be acceptable by the pin.

A client can access this property using the following sample code:

DeviceIoControl(
    DeviceHandle,
    IOCTL_KS_PROPERTY,
    &Property,
    sizeof(KSPROPERTY),
    &Position,
    sizeof(KSTIME),
    &BytesReturned,
    &Overlapped);


KSPROPERTY_STREAM_PRESENTATIONEXTENT

The KSPROPERTY_STREAM_PRESENTATIONEXTENT property is an optional property that should be implemented if the pin has knowledge of the stream extent. The property can also be supported when the extent of a stream is known by a source pin.

A client can access this property using the following sample code:

DeviceIoControl(
    DeviceHandle,
    IOCTL_KS_PROPERTY,
    &Property,
    sizeof(KSPROPERTY),
    &Extent,
    sizeof(LONGLONG),
    &BytesReturned,
    &Overlapped);

Return Values

The property returns the extent as a LONGLONG, with the same resolution format as the presentation time.


KSPROPERTY_STREAM_FRAMETIME

The KSPROPERTY_STREAM_FRAMETIME property is an optional property that should be implemented if a pin recognizes the specifics of the media type it is transporting. It allows a client to determine the duration of the next frame based on the particular media stream, and use that information to step-frame a sequence.

The property is supported by rendering pins and is used to return the duration of the next frame of data and any flags associated with that frame. A frame is generally the smallest usable unit into which the data can be split. For a video stream, this would be a video frame or, possibly, a field. For audio, this would be a sample for each channel in the stream. For MIDI, this would be the next MIDI event.

The duration is measured in terms of the presentation time units provided by the pin. This is dependent on the interface and the numerator/denominator pair used in the presentation time. This does not apply to streams that are not oriented towards any specific media type, such as generic file readers.

A client can access this property using the following sample code:

DeviceIoControl(
    DeviceHandle,
    IOCTL_KS_PROPERTY,
    &Property,
    sizeof(KSPROPERTY),
    &Extent,
    sizeof(KSFRAMETIME),
    &BytesReturned,
    &Overlapped);

Return Values

The property returns a KSFRAMETIME structure.

typedef struct {
  ULONGLONG  Duration;
  ULONG  FrameFlags;
  ULONG  Reserved;
} KSFRAMETIME;

Members

Duration
Indicates the duration in presentation time units.
FrameFlags
Specifies flags specific to the next frame, or to all frames. Currently, only one is defined.
FrameFlags Flags | Description
KSFRAMETIME_VARIABLESIZE | Specifies that each frame may differ in duration.

Reserved
Reserved and set to zero.


KSPROPERTY_STREAM_RATECAPABILITY

The KSPROPERTY_STREAM_RATECAPABILITY property is an optional read-only property that should be implemented if a pin allows rate changes, or the interface between topologically-related pins is different and results in the use of a different time stamp format. The property can also be used to translate time stamp formats in general, such as Skip Degradation requests. The property is to be replaced in a subsequent version.

The property is supported by pins that modify the rate of data through resampling or time stamp changes. All rate changes involve requesting a rate and determining how much a specific pin can correct that rate to obtain the nominal 1.0 rate. For example, a pin requesting a video playback rate of 2.0 would imply a request to render at twice the nominal rate of the video clip; a rate request of 0.5 would imply a half-speed rendering.

This property allows a graph manager to query all connection points involved in the flow of a particular stream (obtained through KSPROPERTY_PIN_DATAROUTING) for their capability in adjusting a requested rate to the nominal rate.

The rate request contains both the presentation start time and the duration for that rate request. This allows for constraints that might apply to specific portions of a data stream to be taken into account. The presentation time, numerator/denominator pair, and duration units are expressed in terms of the Interface specified in the structure. If a standard interface is not used, the initial rate change queries can not be sent to a pin since the presentation time units would not be known unless the KSRATE.flags are used to indicate the presentation time units.

This implies that as a client passes around this query, it must start at a connection for which it knows the interface units. A pin must be able to accept interface identifiers used by any pin with which similar topology. It must also translate the interface identifier and time units to its own. In this manner, a client can traverse a graph from one known interface point and have units translated by connection points at each step of the way.

It is important to support this property if Interface changes are made even if rate changes cannot be made, so the Interface and time units can be adjusted when queries are made. The result would not change the rate returned but would change the Interface, PresentationStart, and Duration.

Rate capability requests can only be performed in Pause or Run state and become invalid after changing to any other state. Queries where the rate is initially 1.0 should always succeed as they are typically just requests to translate time stamp formats.

A client can access this property using the following sample code:

DeviceIoControl(
    DeviceHandle,
    IOCTL_KS_PROPERTY,
    &RateCapability,
    sizeof(KSRATE_CAPABILITY),
    &Rate,
    sizeof(KSRATE),
    &BytesReturned,
    &Overlapped);

The query is passed a KSRATE structure appended to the property containing a KSRATE_CAPABILITY structure (the rate request).

The KSRATE_CAPABILITY structure is a property identifier followed by the KSRATE structure.

typedef struct {
  KSPROPERTY  Property;
  KSRATE  Rate;
} KSRATE_CAPABILITY;

Members

Property
Specifies the KSPROPERTY_STREAM_RATECAPABILITY property.
Rate
Specifies the requested rate.

Return Values

This returns a KSFRAMETIME structure.


KSPROPERTY_STREAM_RATE

The KSPROPERTY_STREAM_RATE property is an optional read/write property that should be implemented if a pin allows rate changes, or the interface between topologically-related pins is different and results in a different time stamp format being used. The property is going to be removed or changed in a subsequent version.

The property is supported by pins that can modify the rate of data through resampling or time stamp changes so that a requested rate can be closer to the nominal rate of 1.0. This property works in conjunction with KSPROPERTY_STREAM_RATECAPABILITY and is used to set the rate of a segment after querying the capability of the pin.

Reading the property returns the current rate and segment. Setting the rate for a new segment replaces any current rate setting. In this manner, stopping a fast-forward request can be done by requesting a rate setting of 1.0, which should always be accepted. If the specified rate is not obtainable, the pin can reject the request instead of attempting a best-fit setting.

The rate setting and query both use the KSRATE structure that Specifies the presentation start, duration, and rate. Rate changes can only be performed in Pause or Run state and are stopped after changing to any other state. The rate change is specified by the percentage over or under the nominal 1.0 rate that the pin is to adjust for and the current setting is returned in the same format.

This property should also be used to translate the interface and time units specified in the previous property and should be implemented on filters that change interfaces between pins, even if rate changes are not supported. For example, a filter that supports KSINTERFACE_STANDARD_POSITION on one pin and translates to KSINTERFACE_STANDARD_STREAMING on another pin related by topology may not support rate changes. The filter should be able to take the change request on either pin and either interface and change to its own interface and units, though the rate would be unchanged.

If the pin also produces a clock, a rate change must not change the slope of the physical time, since any client using the clock for rate matching is expecting the slope to be as if the underlying hardware were running at a nominal 1.0 rate. This means that a pin that cannot ensure that the physical clock slope remains consistent without significant drift cannot accept rate adjustment requests.

A client can access this property using the following sample code:

DeviceIoControl(
    DeviceHandle,
    IOCTL_KS_PROPERTY,
    &Property,
    sizeof(KSPROPERTY),
    &Rate,
    sizeof(KSRATE),
    &BytesReturned,
    &Overlapped);


KSPROPSETID_StreamAllocator

The KSPROPSETID_StreamAllocator property set specifies the streaming allocator characteristics that can be queried and manipulated. All properties can be supported by an allocator instance. For more information on stream allocators, see Frame Allocators.

The KSPROPSETID_StreamAllocator property set includes:

KSPROPERTY_STREAMALLOCATOR_FUNCTIONTABLE

KSPROPERTY_STREAMALLOCATOR_STATUS


KSPROPERTY_STREAMALLOCATOR_FUNCTIONTABLE

The KSPROPERTY_STREAMALLOCATOR_FUNCTIONTABLE property retrieves the function table of the given allocator. The property is only used by allocators supporting the DISPATCH_LEVEL function interface. Allocators supporting this property must be able to allocate and free frames of IRQL levels at and below DISPATCH_LEVEL. This property is accessible only from kernel mode.

Because the DISPATCH_LEVEL interface is closely associated with the IRP-based interface, acquiring the function table is likely to result in the creation of an internal notification event to allow pending I/O to be completed when frames are returned to the free list. When the handle to the allocator is closed, the function table pointers are invalid and the associated events are automatically disabled.

A client can access this property using the following sample code:

DeviceIoControl(
    AllocatorHandle,
    IOCTL_KS_PROPERTY,
    &Allocator,
    sizeof(KSPROPERTY),
    &AllocatorFunctions,
    sizeof(KSSTREAMALLOCATOR_FUNCTIONTABLE),
    &BytesReturned,
    &Overlapped);


KSPROPERTY_STREAMALLOCATOR_STATUS

The KSPROPERTY_STREAMALLOCATOR_STATUS property retrieves the current status of the given allocator in the KSSTREAMALLOCATOR_STATUS structure. The status indicates the framing specifications and the currently allocated frames.

A client can access this property using the following sample code:

DeviceIoControl(
    AllocatorHandle,
    IOCTL_KS_PROPERTY,
    &Allocator,
    sizeof(KSPROPERTY),
    &AllocatorStatus,
    sizeof(KSSTREAMALLOCATOR_STATUS),
    &BytesReturned,
    &Overlapped);

The STREAMALLOCATOR_STATUS structure description is as follows:

typedef struct {
  KSALLOCATOR_FRAMING  Framing;
  ULONG  AllocatedFrames;
  ULONG  Reserved;
} KSSTREAMALLOCATOR_STATUS;

Members

Framing
Specifies the framing specified when the allocator was created.
AllocatedFrames
Specifies the current number of allocated frames. Obviously, this number is dynamic in nature.
Reserved
Reserved and set to zero.


KSPROPSETID_Topology

Clients use requests in the KSPROPSETID_Topology property set to examine a KS filter's internal topology.

Each node in the topology has a zero-based node ID: KS filters with n nodes number them from 0 to n-1. The whole KS filter itself may be treated as a node, and has the special node ID number KSFILTER_NODE.

Stream minidrivers do not need to handle the properties in this property set. The stream class driver handles them on behalf of the minidriver.


KSPROPERTY_TOPOLOGY_CATEGORIES

Read-only.

Specifying This Property

KSPROPERTY.

Property Data

A KSMULTIPLE_ITEM structure, followed by a sequence of GUIDs representing the possible functional categories the KS filter supports. Microsoft provides standard categories in ks.h and ksmedia.h. The following is a list of the functional categories that are not technology-specific:

Functional Category | Description
KSCATEGORY_BRIDGE | Bridge to outside the kernel streaming subsystem.
KSCATEGORY_CAPTURE | Captures.
KSCATEGORY_ COMMUNICATIONSTRANSFORM | Transforms the type of communications being used.
KSCATEGORY_DATACOMPRESSOR | Compresses a data stream.
KSCATEGORY_DATADECOMPRESSOR | Decompresses a data stream.
KSCATEGORY_DATATRANSFORM | Transforms a data stream.
KSCATEGORY_FILESYSTEM | Moves a data stream into or out of the file system.
KSCATEGORY_INTERFACETRANSFORM | Transforms the interface type being used.
KSCATEGORY_MEDIUMTRANSFORM | Transforms the medium type being used.
KSCATEGORY_MIXER | Mixes multiple data streams.
KSCATEGORY_RENDER | Renderer.
KSCATEGORY_SPLITTER | Splits a data stream.


KSPROPERTY_TOPOLOGY_CONNECTIONS

Read-only. KSPROPERTY_TOPOLOGY_CONNECTION describes the connections between each node of a KS filter.

Specifying This Property

KSPROPERTY

Property Data

A KSMULTIPLE_ITEM structure, followed by a sequence of KSTOPOLOGY_CONNECTION structures.

Comments

KSPROPERTY_TOPOLOGY_CONNECTIONS represents connections between pins and nodes on a KS filter. The KS filter represents each connection as formed between an incoming and an outgoing logical pin. The KS filter itself is a node, with ID number KSFILTER_NODE. Logical pins on KSFILTER_NODE represent external pins created by the pin factory with matching ID, while logical pins on all other nodes simply represent the incoming or outgoing portion of an internal connection.

Logical pins on any nodes other than KSFILTER_NODE are not external pins that clients can connect, but are simply a notion used to describing the internal connections between nodes. They cannot be instantiated, and they cannot receive I/O requests. They have no existence outside of the KSPROPERTY_TOPOLOGY_CONNECTIONS property.


KSPROPERTY_TOPOLOGY_NAME

Read-only. The localized Unicode string name of the node.

Specifying This Property

KSP_NODE. The NodeId member specifies the node ID of the node.

Property Data

A buffer to hold the string name.


KSPROPERTY_TOPOLOGY_NODES

Read-only. KSPROPERTY_TOPOLOGY_NODES provides a list of the topology nodes and node types the KS filter supports.

Specifying This Property

KSPROPERTY

Property Data

A KSMULTIPLE_ITEM structure, followed by a sequence of GUIDs representing the node types. The index within the sequence must match the node ID number.


Kernel Streaming Event Sets

Built on Wednesday, July 11, 2001


Event Sets

Event sets are groups of related events, like property sets, that can generate a notification to listeners. For example, changes in device state, or reaching a specific sample position, might cause a filter pin instance to generate an event notification to any clients that have registered to receive a notification.

Device objects support event sets by using the IOCTL_KS_ENABLE_EVENT and IOCTL_KS_DISABLE_EVENT device I/O controls. If a filter or pin must support multiple distinct copies of the same event set, it must use instance identifiers. A particular event can be defined as a single shot, meaning that the event only fires once and is then automatically disabled. An example of this is a positional mark, where an event is triggered when the device reaches a specified position. Other events can be defined to trigger multiple times until disabled.

Assign unique IDs to event sets so that custom driver extensions will not conflict with other custom extensions.


Enable Event

The IOCTL_KS_ENABLE_EVENT request enables the specified event. The format of the event request varies for each specific event. An event is defined by:

  • An event set identifier.
  • An event identifier.
  • Event-specific data.

The KSEVENT structure contains the event identification information, and is essentially a KSIDENTIFIER. The flags element contains the type of query to perform,.which can be one of the following:

#define KSEVENT_TYPE_ENABLE         0x00000001
#define KSEVENT_TYPE_ONESHOT        0x00000002
#define KSEVENT_TYPE_ENABLEBUFFERED 0x00000004
#define KSEVENT_TYPE_SETSUPPORT     0x00000100
#define KSEVENT_TYPE_BASICSUPPORT   0x00000200
#define KSEVENT_TYPE_QUERYBUFFER    0x00000400
Flags | Description
KSEVENT_TYPE_ENABLE | Normal enabling of an event for continuous notification. The event is not discarded until the client requests that it be discarded, or the file object on which the event was created is closed.
KSEVENT_TYPE_ONESHOT | Enables the event for a single notification. The event is discarded after a single notification.
KSEVENT_TYPE_ENABLEBUFFERED | Enables the event with event data buffering activated. If event generation also produces data, it will be buffered until either the event is disabled, or the data is retrieved by the client.
KSEVENT_TYPE_SETSUPPORT | Queries for the list of event sets, or support of a particular event set.
KSEVENT_TYPE_BASICSUPPORT | Queries for support of a particular event type.
KSEVENT_TYPE_QUERYBUFFER | Queries for previously buffered data for an enabled event. This is used when event data buffering is also enabled.

For some event sets, where multiple instances of a single event set exist, a request might also specify event instance information. Instance information is event-specific, meaning that it is appended to the end of the structure.

typedef struct {
  ULONG NotificationType;
  union {
    struct {
      HANDLE Event;
      ULONG Reserved[2];
    } EventHandle;
    struct {
      HANDLE Semaphore;
      ULONG Reserved;
      LONG Adjustment;
    } SemaphoreHandle;
    struct {
      PVOID Event;
      KPRIORITY Increment;
      ULONG Reserved;
    } EventObject;
    struct {
      PVOID Event;
      KPRIORITY Increment;
      LONG Adjustment;
    } EventObject;
    struct {
      PKDPC Dpc;
      ULONG ReferenceCount;
      ULONG Reserved;
    } Dpc;
    struct {
      PWORK_QUEUE_ITEM WorkQueueItem;
      WORK_QUEUE_ITEM WorkQueueItem;
      ULONG Reserved;
    } WorkItem;
    struct {
      PWORK_QUEUE_ITEM WorkQueueItem;
      PKSWORKER KsWorkerObject;
      ULONG Reserved;
    } KsWorkItem;
  };
} KSEVENTDATA
KSEVENTDATA Member | Description
NotificationType | Contains flags indicating what type of notification should be performed.
EventHandle.Event | When the KSEVENT_EVENT_HANDLE flag is set, this contains a handle to a synchronization event.
EventHandle.Reserved[2] | Reserved and set to zero.
SemaphoreHandle.Semaphore | When the KSEVENT_SEMAPHORE_HANDLE flag is set, this contains a handle to a semaphore.
SemaphoreHandle.Reserved | Reserved and set to zero.
SemaphoreHandle.Adjustment | Contains the adjustment to the semaphore when it is released.
EventObject.Event | When the KSEVENT_EVENT_OBJECT flag is set, and the IRP requestor mode was kernel-mode, this contains a pointer to a synchronization event.
EventObject.Increment | Specifies the priority increment to pass on to the event signal.
EventObject.Reserved | Reserved and set to zero.
SemaphoreObject.Semaphore | When the KSEVENT_SEMAPHORE_OBJECT flag is set, and the IRP requestor mode was kernel-mode, this contains a handle to a semaphore.
SemaphoreObject.Increment | Specifies the priority increment to pass on to the semaphore release.
SemaphoreObject.Adjustment | Contains the adjustment to the semaphore when it is released.
Dpc.Dpc | When the KSEVENT_DPC flag is set, and the IRP requester mode was kernel-mode, this contains a pointer to an initialized KDPC structure. The first system parameter points to the original KSEVENT structure. The second system parameter is undefined.
Dpc.ReferenceCount | Indicates that the DPC has been queued. This should be initialized to zero, and interlocked decremented when the DPC has been processed. This is incremented when the DPC is actually queued. It allows a client to determine if the DPC has been taken off the queue to run, but has not completed execution yet and to determine when data pertaining to the DPC can safely be freed. The queued count should be decremented within the DPC to maintain accuracy.
Dpc.Reserved | Reserved and set to zero.
WorkItem.WorkQueueItem | Points to an initialized work queue item which is used to queue a work item when the event is to be signaled. The work item is scheduled if the List.Blink element of the work queue item is NULL. If this element is NULL, and the event is to be signaled, the work item is queued. If this element is not NULL, then the event is not signaled. Normally the work item function would set this element to NULL when it could successfully be re-entered.
WorkItem.WorkQueueType | Contains the queue on which the work item is to be placed.
WorkItem.Reserved | Reserved and set to zero.
KsWorkItem.WorkQueueItem | Optionally points to an initialized work queue item which is used to queue a work item when the event is to be signaled. The work item is scheduled if the List.Blink element of the work queue item is NULL. If this element is NULL, and the event is to be signaled, the work item is queued. If this element is not NULL, then the event is not signaled. Normally the work item function would set this element to NULL when it could successfully be re-entered. If the WorkQueueItem is NULL, it is assumed that the work item is a counted work item, and KsIncrementedCountedWorker will be used for notification.
KsWorkItem.KsWorkerObject | Contains the worker on which the work item is to be queued.
KsWorkItem.Reserved | Reserved and set to zero.

#define  KSEVENTF_EVENT_HANDLE    0x00000001
#define  KSEVENTF_SEMAPHORE_HANDLE  0x00000002
#define  KSEVENTF_EVENT_OBJECT    0x00000004
#define  KSEVENTF_SEMAPHORE_OBJECT  0x00000008
#define  KSEVENTF_DPC      0x00000010
#define  KSEVENTF_WORKITEM    0x00000020
#define  KSEVENTF_KSWORKITEM    0x00000080
NotificationType Flags | Description
KSEVENTF_EVENT_HANDLE | Indicates that a Win32 synchronization or notification object handle is being passed. The KSEVENTDATA.EventHandle.Event element contains the handle.
KSEVENTF_SEMAPHORE_HANDLE | Indicates that a Win32 semaphore handle is being passed. The KSEVENTDATA.SemaphoreHandle.Semaphore element contains the handle.
KSEVENTF_EVENT_OBJECT | Indicates that a pointer to a kernel synchronization or notification object is being passed. The KSEVENTDATA.EventObject.Event element contains a pointer to this object. This is available only to kernel mode clients.
KSEVENTF_SEMAPHORE_OBJECT | Indicates that a pointer to a kernel semaphore object is being passed. The KSEVENTDATA.SemaphoreObject.Semaphore element contains a pointer to this object. This is available only to kernel mode clients.
KSEVENTF_DPC | Indicates that a pointer to a kernel DPC structure is being passed. The KSEVENTDATA.Dpc.Dpc element contains a pointer to the DPC. This is available only to kernel mode clients.
KSEVENTF_WORKITEM | Indicates that a pointer to a kernel work item structure is being passed. The KSEVENTDATA.WorkItem.WorkQueueItem contains a pointer to the work item. This is available only to kernel mode clients.
KSEVENTF_KSWORKITEM | Indicates that a pointer to a kernel work item structure is being passed. The KSEVENTDATA.KsWorkItem.WorkQueueItem contains a pointer to the work item, and is queued to a previously registered KS Worker. This is available only to kernel mode clients.

All event sets must support the KSEVENT_TYPE_BASICSUPPORT flag, which allows you to query for the support of a specific event within an event set. For multiple instance event sets, this refers to all the event sets as a whole, rather than any particular event set instance.

A synchronization or notification object event, DPC, or work item is normally used to signal the occurrence of the event, unless otherwise specified by the specific event type. Event object, DPC notification and work item queuing can only be accessed by kernel-mode components. The original address of the KSEVENTDATA structure can later be used to disable the event, although the actual address does not have to be valid throughout the lifetime of the event. In order to query for support of an event set in general, use the KSEVENT_TYPE_SETSUPPORT flag.

DeviceIoControl(
  DeviceHandle,
  IOCTL_KS_ENABLE_EVENT,
  &Event,
  sizeof(KSEVENT),
  &EventData,
  sizeof(KSEVENTDATA),
  &BytesReturned,
  &Overlapped);


Disable Event

The IOCTL_KS_DISABLE_EVENT request disables a specified event. The same pointer that was used to enable the event must be used to disable it. The pointer uniquely identifies the event. Optionally, a NULL pointer and length of zero can be specified as the first buffer to disable all active events for the client. The format is defined as above. Note that all pending DPCs and work items should be disposed of before freeing any critical structures that they rely on.

DeviceIoControl(
  DeviceHandle,
  IOCTL_KS_DISABLE_EVENT,
  &EventData,
  sizeof(KSEVENTDATA),
  NULL,
  0,
  &BytesReturned,
  &Overlapped);

Parameter Access Macros

The following macros are defined to allow access to Irp->Tail.Overlay.DriverContext parameters in the Irp passed to a handler function. These are initialized by KsEnableEvent and KsEnableEventWithAllocator.

KSEVENT_SET_IRP_STORAGE

This macro accesses a pointer to the KSEVENT_SET where the event was located. This is only initialized for a basic support callback, and not for an enable callback.

KSEVENT_ITEM_IRP_STORAGE

This macro accesses a pointer to the specific KSEVENT_ITEM located. Note that this value is only set when using KsEnableEventWithAllocator.

KSEVENT_ENTRY_IRP_STORAGE

This macro accesses a pointer to the KSEVENT_ENTRY being allocated. This is not initialized for a basic support callback, only for an enable callback. If the event enable is to be handled asynchronously, this storage location must be maintained intact.


KSEVENTSETID_Clock

Clients can request to be notified of clock state events on a clock by registering these events with the clock's file object:

KSEVENT_CLOCK_INTERVAL_MARK

KSEVENT_CLOCK_POSITION_MARK

When a client submits the IOCTL_KS_ENABLE_EVENT request to register for event notification, it submits as a data buffer the structure documented in the EventData section of each event reference page.


KSEVENT_CLOCK_INTERVAL_MARK

Clients enable the KSEVENT_CLOCK_INTERVAL_MARK event to be notified when an initial time value is reached, and then at fixed time increments after that.

Event Data

KSEVENT_TIME_INTERVAL, a structure of the form:

typedef struct {
    KSEVENTDATA EventData;
    LONGLONG TimeBase;
    LONGLONG Interval;
} KSEVENT_TIME_INTERVAL;

TimeBase specifies the initial time that triggers this event; an Interval specifies the interval between subsequent occurrences of the event.


KSEVENT_CLOCK_POSITION_MARK

A KSEVENT_CLOCK_POSITION_MARK event occurs when a certain time on a clock is reached.

Event Data

KSEVENT_TIME_MARK, a structure of the form:

typedef struct {
    KSEVENTDATA EventData;
    LONGLONG MarkTime;
} KSEVENT_TIME_MARK;

The MarkTime member specifies the time stamp that triggers the event.


KSEVENTSETID_StreamAllocator Event Set

The KSEVENTSETID_StreamAllocator event set specifies two events: one event used internally in the default allocator implementation to service outstanding allocation requests made through the IRP interface, and one public event used to notify clients of free frame availability.

The KSEVENTSETID_StreamAllocator event set includes:

KSEVENT_STREAMALLOCATOR_INTERNAL_FREEFRAME

KSEVENT_STREAMALLOCATOR_FREEFRAME


KSEVENT_STREAMALLOCATOR_INTERNAL_FREEFRAME

The KSEVENT_STREAMALLOCATOR_INTERNAL_FREEFRAME event is used only internally in the default allocator implementation and other implementations to service waiters that have pending allocation IRPs. It should not be enabled by clients.


KSEVENT_STREAMALLOCATOR_FREEFRAME

The KSEVENT_STREAMALLOCATOR_FREEFRAME event can be used to receive notification when a free frame is available for allocation. This event can be used by clients using a direct call interface instead of an IRP interface, which typically queues pending requests that cannot be fulfilled.


KSEVENTSETID_Connection Event Set

The KSEVENTSETID_Connection event set specifies the general events that can be enabled on a filter and a pin. The set consists of:

KSEVENT_CONNECTION_POSITIONUPDATE

KSEVENT_CONNECTION_DATADISCONTINUITY

KSEVENT_CONNECTION_TIMEDISCONTINUITY

KSEVENT_CONNECTION_PRIORITY

KSEVENT_CONNECTION_ENDOFSTREAM


KSEVENT_CONNECTION_POSITIONUPDATE

The KSEVENT_CONNECTION_POSITIONUPDATE event allows a client to receive notification of changes in the current position. The margin of change is stream and filter dependent.


KSEVENT_CONNECTION_DATADISCONTINUITY

The KSEVENT_CONNECTION_DATADISCONTINUITY event allows a client to receive notification of a data discontinuity. This event occurs when a data discontinuity flag is sent through the stream interface on a pin. There are no parameters to this event.


KSEVENT_CONNECTION_TIMEDISCONTINUITY

The KSEVENT_CONNECTION_TIMEDISCONTINUITY event allows a client to receive notification of a time discontinuity. This event occurs when a time discontinuity flag is sent through the stream interface on a pin. There are no parameters to this event.


KSEVENT_CONNECTION_PRIORITY

The KSEVENT_CONNECTION_PRIORITY event allows a client to receive notification of priority failures. This event occurs when resources are lost due to priority levels. There are no parameters to this event.


KSEVENT_CONNECTION_ENDOFSTREAM

The KSEVENT_CONNECTION_ENDOFSTREAM event allows a client to receive notification of an end of stream event. This event occurs, when a standard streaming header is used, when a buffer whose header has the KSTREAM_HEADER_OPTIONSF_ENDOFSTREAM variable completes processing. "Rendering" points must support this event so the end of stream event can be detected by the client.


AVStream Functions

This section contains reference pages for the Microsoft-supplied AVStream class driver routines. This material is relevant only for Microsoft® Windows® XP and DirectX® 8.0 releases and later.


AddDevice Routine for AVStream Minidrivers

The vast majority of AVStream minidrivers do not supply their own AddDevice routines. Instead, they use KsAddDevice, the default AddDevice handler installed by KsInitializeDriver. Minidrivers that nonetheless wish to provide their own AddDevice handler should follow the guidelines on this reference page.

NTSTATUS
  AddDevice(
    IN PDRIVER_OBJECT  DriverObject,
    IN PDEVICE_OBJECT  PhysicalDeviceObject
    );

Parameters

DriverObject
Caller-supplied pointer to a DRIVER_OBJECT structure. This is the driver's driver object.
PhysicalDeviceObject
Caller-supplied pointer to a DEVICE_OBJECT structure representing a physical device object (PDO) created by a lower-level driver.

Headers

Declared in ks.h. Include ks.h.

Comments

If the driver calls KsInitializeDriver during DriverEntry and later replaces the AddDevice handler, the minidriver can call KsAddDevice from within this routine, to perform the default add handling.

The minidriver may call KsCreateDevice from this routine, passing in a nominally optional KSDEVICE_DESCRIPTOR. If KsInitializeDriver is not called, this is the highest level call that will create an AVStream device described by a descriptor.

If the minidriver creates its own FDO and manually attaches itself to the device stack, it should call KsInitializeDevice to create the AVStream device.

If the driver does not provide a KSDEVICE_DESCRIPTOR and yet still creates a device, AVStream creates a default AVStream device. This device contains no filter factories and never dispatches to the minidriver. The minidriver can still instantiate KSFILTERFACTORY structures on the device by calling KsCreateFilterFactory.

To install your own AddDevice handler:

DriverObject -> DriverExtension -> AddDevice = MyAddDevice();

It is highly recommended that AVStream minidrivers use the functionality provided by KsInitializeDriver, rather than override the default AddDevice routine supplied by the class driver.

See Also

KsCreateDevice, KsInitializeDevice, KsInitializeDriver, KSDEVICE, KsDispatchIrp, KsAddDevice


DriverEntry of AVStream

The DriverEntry function is the initial entry point into an AVStream minidriver.

NTSTATUS
  DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPathName
    )

Parameters

DriverObject
This is the driver object to initialize for this instance.
RegistryPathName
Contains the registry path that was used to load this instance.

Return Value

Returns the value returned by KsInitializeDriver.

Headers

Declared in ks.h. Include ks.h.

Comments

Each AVStream minidriver must have a function explicitly named DriverEntry in order to be loaded. DriverEntry is called directly by the I/O system. Usually, DriverEntry calls KsInitializeDriver and then returns the value returned by KsInitializeDriver.

See Also

KsInitializeDriver, DriverEntry, DRIVER_OBJECT, DEVICE_OBJECT


KsAcquireControl

The KsAcquireControl function acquires the filter control mutex for Object.

VOID
  KsAcquireControl(
    IN PVOID  Object
    );

Parameters

Object
The object for which to acquire the filter control mutex. This should be either a KSFILTER or a KSPIN, cast to PVOID.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

Minidrivers typically do not call this function directly, but instead call either KsFilterAcquireControl or KsPinAcquireControl. These functions provide the necessary type casting to PVOID automatically.

For more information, see Mutexes in AVStream.

KsAcquireControl must be called at IRQL = PASSIVE_LEVEL.

See Also

KsReleaseControl, KsFilterAcquireControl, KsPinAcquireControl, Mutexes in AVStream, KSFILTER, KSPIN


KsAcquireDevice

The KsAcquireDevice function gains synchronous access for Device by acquiring the device mutex.

VOID
  KsAcquireDevice(
    IN PKSDEVICE  Device
    );

Parameters

Device
AVStream device for which synchronous control should be acquired.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

KsAcquireDevice must be called at IRQL = PASSIVE_LEVEL.

See Also

KsReleaseDevice, KSDEVICE, Mutexes in AVStream


KsAddDevice

The KsAddDevice function is the default AddDevice handler installed by KsInitializeDriver .

NTSTATUS
  KsAddDevice(
    IN PDRIVER_OBJECT  DriverObject,
    IN PDEVICE_OBJECT  PhysicalDeviceObject
    );

Parameters

DriverObject
Pointer to the WDM driver object for the minidriver.
PhysicalDeviceObject
Pointer to the WDM physical device object.

Headers

Declared in ks.h. Include ks.h.

Comments

Normally, an AVStream minidriver does not call this function directly.

For more information, see AddDevice Routine for AVStream Minidrivers.

KsAddDevice extracts the device descriptor stored in the device extension allocated from a call to KsInitializeDriver and creates the device described by it. If KsInitializeDriver is not used to initialize the driver, this function creates a device with the default characteristics and no filter factories. The minidriver always has the option of calling KsCreateDevice directly, in which case the driver extension is not used by AVStream.

KsAddDevice must be called at IRQL = PASSIVE_LEVEL.

Do not call both KsCreateDevice and KsAddDevice.

See Also

KsCreateDevice, KsInitializeDevice, KsInitializeDriver, KSDEVICE, KsDispatchIrp, DRIVER_OBJECT, DEVICE_OBJECT, AddDevice Routine for AVStream Minidrivers


KsAddEvent

The KsAddEvent function adds an event to Object's event list.

VOID
  KsAddEvent(
    IN PVOID  Object,
    IN PKSEVENT_ENTRY  EventEntry
    );

Parameters

Object
The object to which to add the event.
EventEntry
Pointer to an event entry structure describing the event to add to Object.

Headers

Declared in ks.h. Include ks.h.

Comments

Minidrivers typically do not call this routine directly; instead, they use KsFilterAddEvent or KsPinAddEvent.

Once events have been added to the event list, these events can then be generated as data events by a Ks Xxx GenerateEvents call. Typecasting of the object (a filter or pin) to PVOID must be provided by the caller.

KsAddEvent must be called at IRQL = PASSIVE_LEVEL.

See Also

KsFilterAddEvent, KsPinAddEvent, KsDefaultAddEventHandler, KsGenerateEvents, KSEVENT_ENTRY


KsAddItemToObjectBag

The KsAddItemToObjectBag function adds an object or chunk of memory to the given object bag.

NTSTATUS
  KsAddItemToObjectBag(
    IN KSOBJECT_BAG  ObjectBag,
    IN PVOID  Item,
    IN PFNKSFREE  Free  OPTIONAL
    );

Parameters

ObjectBag
The KSOBJECT_BAG (equivalent to type PVOID) to which to add the requested item. Every AVStream object (for example, KSFILTER and KSPIN) has a field called Bag. Pass that field in this parameter.
Item
A pointer to the item to add to the object bag.
Free
A function that is called when the item is removed from the object bag or when the object bag is deleted. This function is typically used to free any dynamic memory associated with Item. The function should be prototyped as follows:
void Free (IN PVOID Data);

If NULL is passed in this parameter, Item is freed with ExFreePool when removed from the object bag or when the object bag is deleted.

Return Value

Either returns STATUS_SUCCESS indicating that the addition went normally or STATUS_INSUFFICIENT_RESOURCES indicating that there are insufficient system resources for the operation to proceed.

Headers

Declared in ks.h. Include ks.h.

Comments

For more information, see Object Bags.

Note that the mutex associated with the bag must be held. For related information, see KsMergeAutomationTables and Mutexes in AVStream.

KsAddItemToObjectBag must be called at IRQL = PASSIVE_LEVEL.

See Also

KsRemoveItemFromObjectBag, KsDiscard, KsAllocateObjectBag, KsFreeObjectBag, KsCopyObjectBagItems , _KsEdit, Object Bags, ExFreePool


KsAllocateObjectBag

The KsAllocateObjectBag function creates an object bag and associates it with Device.

NTSTATUS
  KsAllocateObjectBag(
    IN PKSDEVICE  Device,
    OUT KSOBJECT_BAG  *ObjectBag
    );

Parameters

Device
The AVStream device structure representing the device object associated with the newly created object bag.
ObjectBag
A pointer to a KSOBJECT_BAG (equivalent to type PVOID) where the newly allocated object bag is deposited.

Return Value

Returns STATUS_SUCCESS if a new object bag is created. If a new object bag is not allocated, it returns STATUS_INSUFFICIENT_RESOURCES.

Headers

Declared in ks.h. Include ks.h.

Comments

An allocated object bag is not automatically deleted. The minidriver calling KsAllocateObjectBag is responsible for deletion of the object bag. The easiest way to do this is by calling KsFreeObjectBag. Alternatively, if the minidriver has the addresses of the items in the bag, the minidriver can delete them individually by calling KsRemoveItemFromObjectBag.

KsAllocateObjectBag must be called at IRQL = PASSIVE_LEVEL.

For more information, see Object Bags.

See Also

KsFreeObjectBag, KsAddItemToObjectBag, KsRemoveItemFromObjectBag, KsDiscard, KsCopyObjectBagItems


KsCompletePendingRequest

The KsCompletePendingRequest function is used to complete a dispatch function that has previously returned STATUS_PENDING.

VOID
  KsCompletePendingRequest(
    IN PIRP  Irp
    );

Parameters

Irp
The IRP that must be completed; this is passed in the dispatch function that returned a pending code.

Headers

Declared in ks.h. Include ks.h.

Comments

If the dispatch function in question does not pass an IRP, it cannot be put into a pending status. Minidrivers should set the status field of the IRP before calling this function.

KsCompletePendingRequest can be used for PnP dispatch functions in the device dispatch table or filter creation and closure requests. Dispatch functions that allow STATUS_PENDING to be returned and that then do pend must call this function when they complete the request.

KsCompletePendingRequest can be called at IRQL <= DISPATCH_LEVEL.

Return Value

None

See Also

KSDEVICE_DISPATCH, KSFILTER_DISPATCH, IRP


KsCopyObjectBagItems

The KsCopyObjectBagItems function copies all items from one object bag into another.

NTSTATUS
  KsCopyObjectBagItems(
    IN KSOBJECT_BAG  ObjectBagDestination,
    IN KSOBJECT_BAG  ObjectBagSource
    );

Parameters

ObjectBagDestination
The KSOBJECT_BAG (equivalent to type PVOID) into which to copy items.
ObjectBagSource
The KSOBJECT_BAG from which items are copied to ObjectBagDestination.

Return Value

Returns STATUS_SUCCESS if the copy is successful. Otherwise, it returns an error code. Most often, this is STATUS_INSUFFICIENT_RESOURCES indicating insufficient system resources to complete the copy operation. If STATUS_INSUFFICIENT_RESOURCES is returned, it is quite possible that some, but not all, of the items have been copied from ObjectBagSource to ObjectBagDestination.

Headers

Declared in ks.h. Include ks.h.

Comments

For more information, see Object Bags.

Note that mutexes for both bags should be held. If the object bag in question is associated with a filter or a pin, acquire the filter control mutex. If the object bag belongs to a filter factory or the device, acquire the device mutex. See Mutexes in AVStream for more information.

KsCopyObjectBagItems must be called at IRQL = PASSIVE_LEVEL.

See Also

KsAllocateObjectBag, KsFreeObjectBag, KsAddItemToObjectBag, KsRemoveItemFromObjectBag, KsDiscard, _KsEdit, KsEdit, KsPinGetConnectedPinInterface, KsPinGetConnectedFilterInterface, KsPinGetReferenceClockInterface, KsPinSetPinClockTime, Object Bags, Mutexes in AVStream


KsCreateDevice

The KsCreateDevice function creates an AVStream device.

NTSTATUS
  KsCreateDevice(
    IN PDRIVER_OBJECT  DriverObject,
    IN PDEVICE_OBJECT  PhysicalDeviceObject,
    IN const KSDEVICE_DESCRIPTOR*  Descriptor, /* optional */
    IN ULONG  ExtensionSize, /* optional */
    OUT PKSDEVICE*  Device /* optional */
    );

Parameters

DriverObject
Pointer to the WDM driver object of the minidriver.
PhysicalDeviceObject
Pointer to the WDM physical device object for the device you want to create under AVStream.
Descriptor
Pointer to a device descriptor that describes the characteristics of the device being created. If this pointer is NULL, a device is created with default characteristics and no associated filter factories.
ExtensionSize
Contains the size of the device extension. If this is zero, the default extension size is used. If not, it must be at least sizeof (KSDEVICE_HEADER).
Device
Pointer to a PKSDEVICE where the created AVStream device structure is stored. This is an optional parameter.

Return Value

Returns STATUS_SUCCESS if the device is created successfully. Otherwise, it returns an appropriate error code.

Headers

Declared in ks.h. Include ks.h.

Comments

Normally, the minidriver does not call this function directly. Instead, KsCreateDevice is called by the default AddDevice handler, KsAddDevice.

A minidriver that calls KsCreateDevice directly should not use KsInitializeDriver. If the minidriver is not calling KsInitializeDriver, it should instead provide its own AddDevice callback. The minidriver can then call KsCreateDevice from that AddDevice callback.

If no KSDEVICE_DESCRIPTOR is provided, AVStream creates a device with the default characteristics and no associated filter factories. If a KSDEVICE_DESCRIPTOR is supplied and contains a KSDEVICE_DISPATCH table with a create dispatch, the create dispatch is called.

KsCreateDevice must be called at IRQL = PASSIVE_LEVEL.

Do not call both KsCreateDevice and KsAddDevice.

See Also

KsAddDevice, KsInitializeDevice, KSDEVICE, KsInitializeDriver, KSDEVICE_DESCRIPTOR, KSDEVICE_DISPATCH, DRIVER_OBJECT, DEVICE_OBJECT


KsCreateFilterFactory

The KsCreateFilterFactory function adds a filter factory to a given device.

NTSTATUS
  KsCreateFilterFactory(
    IN PDEVICE_OBJECT  DeviceObject,
    IN const KSFILTER_DESCRIPTOR  *Descriptor,
    IN PWCHAR  RefString, /* optional */
    IN PSECURITY_DESCRIPTOR  SecurityDescriptor, /* optional */
    IN ULONG  CreateItemFlags,
    IN PFNKSFILTERFACTORYPOWER  SleepCallback, /* optional */
    IN PFNKSFILTERFACTORYPOWER  WakeCallback, /* optional */
    OUT PKSFILTERFACTORY  FilterFactory /* optional */
    );

Parameters

DeviceObject
The device object on which to add a filter factory.
Descriptor
Pointer to a filter descriptor that describes the characteristics of individual filters that this factory can create.
RefString
If this argument is provided, this string is used as the reference string for filters created by this factory. Otherwise, the reference GUID provided in the descriptor is used.
SecurityDescriptor
The security descriptor to use in creation of filters by this filter factory.
CreateItemFlags
The following table lists the flags that the minidriver writer uses to specify the characteristics of filters that the new filter factory can create. Set this member to the bitwise OR of the flags below.
Flag | Meaning
KSCREATE_ITEM_SECURITY_CHANGED | Indicates that the security descriptor on this object type has been changed and should be persisted.
KSCREATE_ITEM_WILDCARD | Indicates that this create item represents a wildcard that is used for any create requests that do not match any other create items. The ordering of the wildcard entry in the list of create items is irrelevant. Only a single wildcard entry is valid on any list of create items.
KSCREATE_ITEM_NOPARAMETERS | Indicates that this create item does not allow any parameters to be passed, and fails if any are found. (Normally, create parameters are passed on to the create handler.) This flag cannot be used with a wildcard flag.
KSCREATE_ITEM_FREEONSTOP | Indicates that the create item should be freed at PnP stop. Note that AVStream automatically frees such create items when the device receives PnP stop (after the client has received the PnP stop notification).

SleepCallback
Pointer to a function designed to handle notifications that the device associated with this filter is going to sleep. This function should be prototyped as follows:
void SleepCallback (IN PKSFILTERFACTORY FilterFactory,
    IN DEVICE_POWER_STATE State);

If this parameter is NULL, there is no notification to this filter factory that the device is going to sleep.

WakeCallback
Pointer to a function designed to handle notifications that the device associated with this filter is waking up. This function should be prototyped as follows:
  void WakeCallback (IN PKSFILTERFACTORY FilterFactory,
    IN DEVICE_POWER_STATE State);

If this parameter is NULL, there is no notification to this filter factory that the device is waking up.

FilterFactory
Pointer to a KSFILTERFACTORY object into which is deposited a pointer to the newly created filter factory object. This is an optional parameter; the caller need not be informed of the resulting filter factory object.

Return Value

Returns STATUS_SUCCESS if the filter factory can be created. Otherwise, it returns an appropriate error code.

Comments

Note that KsCreateFilterFactory requires that the device mutex be held. For more information, see Mutexes in AVStream.

This function should be used by minidrivers that either initialize themselves without a call to KsInitializeDriver or that must dynamically add and remove new filter types.

KsCreateFilterFactory must be called at IRQL = PASSIVE_LEVEL.

Headers

Declared in ks.h. Include ks.h.

See Also

KsDeleteFilterFactory, KSFILTER_DESCRIPTOR, KSPIN_DESCRIPTOR_EX, KSNODE_DESCRIPTOR, Mutexes in AVStream


KsDefaultAddEventHandler

The KsDefaultAddEventHandler function is a default routine to handle event 'add' requests.

NTSTATUS
  KsDefaultAddEventHandler(
    IN PIRP  Irp,
    IN PKSEVENTDATA  EventData,
    IN OUT PKSEVENT_ENTRY  EventEntry
    );

Parameters

Irp
The event IRP. This contains the object into which the event is inserted.
EventData
Data associated with the event.
EventEntry
The event entry that is to be inserted into the object's event list. The object is determined by Irp.

Return Value

Returns the success or failure of adding the event into the object's event list.

Headers

Declared in ks.h. Include ks.h.

Comments

KsDefaultAddEventHandler determines the relevant object from Irp and adds the specified event to the object's event list.

This is functionally equivalent to KsAddEvent (or Ks*AddEvent, see below) for the object that is associated with Irp. Use KsDefaultAddEventHandler from a minidriver-specified AddEvent handler to insert the event into the object's event list.

KsDefaultAddEventHandler must be called at IRQL = PASSIVE_LEVEL.

See Also

KsAddEvent, , KsFilterAddEvent, KsPinAddEvent, KsGenerateEvents, KSEVENT_ENTRY


KsDeleteFilterFactory

The KsDeleteFilterFactory macro deletes a given filter factory.

NTSTATUS
  KsDeleteFilterFactory(
    IN PKSFILTERFACTORY  FilterFactory
    );

Parameters

FilterFactory
The filter factory that is to be deleted.

Return Value

STATUS_SUCCESS is returned if the filter factory was able to be deleted. Otherwise, an appropriate error code is returned.

Headers

Declared in ks.h. Include ks.h.

Comments

KsDeleteFilterFactory must be called at IRQL = PASSIVE_LEVEL.

See Also

KsCreateFilterFactory, KsFilterFactoryAddCreateItem, KsFilterFactorySetDeviceClassesState


KsDeviceGetBusData

The KsDeviceGetBusData function reads data from the bus where the given AVStream device resides.

ULONG
  KsDeviceGetBusData(
    IN PKSDEVICE  Device,
    IN ULONG  DataType,
    IN PVOID  Buffer,
    IN ULONG  Offset,
    IN ULONG  Length
    );

Parameters

Device
Pointer to the structure representing the given AVStream device for which data from the bus should be read.
DataType
The space from which data will be read. 0 corresponds to configuration space.
Buffer
Pointer to a buffer that receives the data read from the bus. Must be at least as large as Length.
Offset
Contains the offset in the space specified by DataType from which data will be read.
Length
Specifies the amount of data that will be read into Buffer.

Return Value

KsDeviceGetBusData returns the number of bytes actually read from the bus. If an errors occurs, this value usually is zero.

Headers

Declared in ks.h. Include ks.h.

Comments

Depending on the driver for the bus where the specified device resides, there are two possible behaviors and restriction sets on this function. If the given bus driver supports the bus interface standard (usually PCI), call this function at either IRQL = PASSIVE_LEVEL or DISPATCH_LEVEL. After such a call, KsDeviceGetBusData returns the actual number of bytes read from the requested space. If, however, the given bus driver does not support the bus interface standard, then AVStream communicates with the bus driver through IoCallDriver. Note that this restricts use of KsDeviceGetBusData to IRQL = PASSIVE_LEVEL and also means that the return value is either 0, in the case of failure, or equal to Length if data acquisition was successful.

To ensure compatibility, minidriver writers may want to restrict use of KsDeviceGetBusData to IRQL = PASSIVE_LEVEL.

See Also

KsDeviceSetBusData, IoCallDriver


KsDeviceGetFirstChildFilterFactory

The KsDeviceGetFirstChildFilterFactory function returns the first child filter factory belonging to a given AVStream device.

PKSFILTERFACTORY
  KsDeviceGetFirstChildFilterFactory(
    IN PKSDEVICE  Device
    );

Parameters

Device
The AVStream device for which to find the first child filter factory.

Return Value

The first child filter factory of Device is returned. If there are no filter factories registered on Device, NULL is returned.

Headers

Declared in ks.h. Include ks.h.

Comments

This call is an inline function call to KsGetFirstChild. Note that the object hierarchy is only guaranteed stable while the appropriate mutex is held, in this case the device mutex.

For a graphical representation of AVStream parent/child relationships, see the diagram in AVStream Overview.

KsDeviceGetFirstChildFilterFactory must be called at IRQL = PASSIVE_LEVEL.

See Also

KSDEVICE, KSFILTERFACTORY, KsGetFirstChild, KsFilterFactoryGetNextSiblingFilterFactory, Mutexes in AVStream, AVStream Overview


KsDeviceGetOuterUnknown

The KsDeviceGetOuterUnknown function returns the outer unknown interface of the AVStream device specified by Device.

PUNKNOWN
  KsDeviceGetOuterUnknown(
    IN PKSDEVICE  Device
    );

Parameters

Device
The AVStream device for which to get the outer unknown interface.

Return Value

The outer unknown interface of Device is returned. This returned interface can then be used to query for other interfaces.

Headers

Declared in ks.h. Include ks.h.

Comments

This call is an inline function call to KsGetOuterUnknown.

KsDeviceGetOuterUnknown must be called at IRQL = PASSIVE_LEVEL.

See Also

KsGetOuterUnknown, KsFilterFactoryGetOuterUnknown, KsFilterGetOuterUnknown, KsPinGetOuterUnknown, KsRegisterAggregatedClientUnknown, AVStream Overview, IksControl


KsDeviceRegisterAdapterObject

The KsDeviceRegisterAdapterObject function registers a DMA adapter object with AVStream for performing scatter/gather DMA on the specified device.

VOID
  KsDeviceRegisterAdapterObject(
    IN PKSDEVICE  Device,
    IN PADAPTER_OBJECT  AdapterObject,
    IN ULONG  MaxMappingByteCount,
    IN ULONG  MappingTableStride
    );

Parameters

Device
Pointer to the stucture representing the AVStream device for which to register an adapter object.
AdapterObject
Pointer to the adapter object for the device. Must be acquired through IoGetDmaAdapter before calling KsDeviceRegisterAdapterObject.
MaxMappingByteCount
Specifies the maximum size that the device can handle for a single mapping. Allows AVStream to automatically break up large chunks of contiguous physical memory into multiple scatter/gather elements for devices that impose a size limit on individual mappings in DMA transfers.
MappingTableStride
Specifies how many bytes each entry in the mapping table requires. This must be at least sizeof (KSMAPPING) and can be as large as necessary.

Additional space can be used by the minidriver as context information.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

A minidriver that calls KsDeviceRegisterAdapterObject is responsible for previously acquiring the adapter object through IoGetDmaAdapter.

Also note that if the minidriver specifies the KSPIN_FLAG_GENERATE_MAPPINGS flag for any pin on any filter on the device, the minidriver must call KsDeviceRegisterAdapterObject before processing any data. More information on this flag can be found in the reference page for KSPIN_DESCRIPTOR_EX.

KsDeviceRegisterAdapterObject must be called at IRQL = PASSIVE_LEVEL.

See Also

KSFILTER_DESCRIPTOR, KSPIN_DESCRIPTOR_EX, KSMAPPING, IoGetDmaAdapter


KsDeviceRegisterAggregatedClientUnknown

This inline function is a wrapper for KsRegisterAggregatedClientUnknown.

KSDDKAPI PUNKNOWN NTAPI
  KsDeviceRegisterAggregatedClientUnknown(
    IN PKSDEVICE  Device,
    IN PUNKNOWN  ClientUnknown
    );

Parameters

Device
The specified AVStream device.
ClientUnknown
The client unknown object.

Return Values

Returns the newly created aggregate object.

Headers

Declared in ks.h. Include ks.h.

Comments

This inline function only performs a typecast and then calls KsRegisterAggregatedClientUnknown.

See Also

KsRegisterAggregatedClientUnknown


KsDeviceSetBusData

The KsDeviceSetBusData function writes data to the bus on which the specified AVStream device resides.

ULONG
  KsDeviceSetBusData(
    IN PKSDEVICE  Device,
    IN ULONG  DataType,
    IN PVOID  Buffer,
    IN ULONG  Offset,
    IN ULONG  Length
    );

Parameters

Device
Pointer to the structure representing the AVStream device for which you want data to be written to the bus.
DataType
The space to which data is written. Zero corresponds to configuration space.
Buffer
A pointer to a buffer that contains the data you want to write out to the bus. This buffer must be at least as long as specified by Length.
Offset
Contains the offset into the space specified by DataType where data is written.
Length
Specifies the amount of data to write out to the bus from Buffer.

Return Value

KsDeviceSetBusData returns the number of bytes actually written to the bus. In the case of an error, zero is the usual return result.

Headers

Declared in ks.h. Include ks.h.

Comments

Depending on the driver for the bus where the specified device resides, there are two possible behaviors and restriction sets on this function. If the given bus driver supports the bus interface standard (usually PCI), call this function at either IRQL = PASSIVE_LEVEL or DISPATCH_LEVEL. After such a call, KsDeviceSetBusData returns the actual number of bytes written to the requested space. If, however, the given bus driver does not support the bus interface standard, then AVStream communicates with the bus driver using IoCallDriver. Note that this restricts use of KsDeviceSetBusData to IRQL = PASSIVE_LEVEL and also means that the return value is either 0, in the case of failure, or equal to Length if the data was written successfully.

Drivers running on Windows 2000 and later can make this call at IRQL = DISPATCH_LEVEL. However, to ensure compatibility, minidriver writers may want to restrict use of KsDeviceSetBusData to IRQL = PASSIVE_LEVEL.

See Also

KsDeviceGetBusData, IoCallDriver


KsDiscard

The KsDiscard macro removes a given item from an object bag.

ULONG
  KsDiscard(
    IN KSxxx  Object,
    IN PVOID  Pointer
    );

Parameters

Object
The object out of whose bag the item pointed to by Pointer is to be removed.
Pointer
Pointer to the item to be removed from the requested object's bag.

Return Value

Same as KsRemoveItemFromObjectBag (Object -> Bag, Pointer, TRUE).

Headers

Declared in ks.h. Include ks.h.

Comments

This macro is implemented as a C-style preprocessing macro in the ks.h header.

KsDiscard calls KsRemoveItemFromObjectBag, passing the object bag associated with Object (Object -> Bag), the item specified by Pointer, and TRUE for the Free parameter.

KsDiscard must be called at IRQL = PASSIVE_LEVEL.

See Also

KsRemoveItemFromObjectBag


_KsEdit

The _KsEdit function guarantees that a given item is dynamically allocated and associated with an AVStream object through the object bag.

KSDDKAPI NTSTATUS NTAPI
  _KsEdit(
    IN KSOBJECT_BAG  ObjectBag,
    IN OUT PVOID*  PointerToPointerToItem,
    IN ULONG  NewSize,
    IN ULONG  OldSize,
    IN ULONG  Tag
    );

Parameters

ObjectBag
The KSOBJECT_BAG (equivalent to type PVOID) to use in the check. If the item is not contained within the object bag, _KsEdit dynamically allocates sufficient memory for the item, copies the old contents, and places the newly allocated memory in this object bag.
PointerToPointerToItem
A pointer to a pointer to the item being edited.
NewSize
The amount of memory to allocate for the item.
OldSize
The amount of memory the item currently takes up.
Tag
Contains the pool tag to use for the allocations.

Return Value

Success or failure of the edit is returned. If this fails, the minidriver should not assume that it safe to go ahead with whatever operation caused the edit.

Headers

Declared in ks.h. Include ks.h.

Comments

For more information, see Object Bags.

Note that KsEdit and KsEditSized are macros created to make _KsEdit easier to use. While _KsEdit allows you to resize an item, KsEdit does not. The macro KsEdit calls _KsEdit, specifying sizeof(**PointerToPointerToItem) as both sizes.

For instance, consider a pin that needs to modify its allocator framing on creation. Since the descriptor is statically layed out in code and new pins may use it, the solution is to modify the pin descriptor as follows:

        KsEdit(Pin, &Pin->Descriptor, Tag);
        Pin->Descriptor->AllocatorFraming = NewAllocatorFraming;

The call to KsEdit guarantees that Pin->Descriptor is dynamic memory that is associated with Pin. Note that arbitrary modification of descriptors and other AVStream structures can cause undesirable results. Minidrivers should exercise caution when using KsEdit on AVStream structures.

KsEditSized calls _KsEdit almost identically to the parameters passed into KsEditSized, except that Object is replaced by Object->Bag and the pointer is typecast to PVOID.

Note that when calling _KsEdit, a caller must hold the mutex associated with the bag. Please see related information in the section Mutexes in AVStream.

_KsEdit must be called at IRQL = PASSIVE_LEVEL.

See Also

Mutexes in AVStream


KsFilterAcquireControl

The KsFilterAcquireControl function acquires the filter control mutex for the AVStream filter specified by Filter.

VOID
  KsFilterAcquireControl(
    IN PKSFILTER  Filter
    );

Parameters

Filter
The KSFILTER for which to acquire the control mutex.

Return Value

None

Headers

Declared inline in ks.h. Include ks.h.

Comments

This function is an inline call to KsAcquireControl with the appropriate typecasting. Minidrivers that manipulate the filter control mutex should call this function instead of calling KsAcquireControl directly.

KsFilterAcquireControl must be called at IRQL = PASSIVE_LEVEL.

See Also

KsFilterReleaseControl, KsAcquireControl, Mutexes in AVStream, KSFILTER


KsFilterAcquireProcessingMutex

The KsFilterAcquireProcessingMutex function acquires the processing mutex for the specified AVStream filter.

VOID
  KsFilterAcquireProcessingMutex(
    IN PKSFILTER  Filter
    );

Parameters

Filter
Pointer to the AVStream filter for which to acquire the processing mutex.

Return Value

None; however, the processing control mutex is acquired upon return.

Headers

Declared in ks.h. Include ks.h.

Comments

A minidriver that needs to suspend processing for a long period of time should not use this mechanism. Instead, manipulate the processing control gate directly using the KsGate* functions.

KsFilterAcquireProcessingMutex must be called at IRQL = PASSIVE_LEVEL.

See Also

KsFilterReleaseProcessingMutex, KsFilterReleaseProcessingMutex, KsFilterAttemptProcessing, KsPinGetAndGate, KsPinAcquireProcessingMutex, KsPinReleaseProcessingMutex, Mutexes in AVStream


KsFilterAddEvent

The KsFilterAddEvent function adds an event to Filter's event list.

VOID
  KsFilterAddEvent(
    PKSFILTER  Filter,
    PKSEVENT_ENTRY  EventEntry
    );

Parameters

Filter
The filter to which to add a specified event.
EventEntry
Pointer to an event entry structure describing the event to add to Filter.

Headers

Declared inline in ks.h. Include ks.h.

Comments

This function is an inline function call to KsAddEvent.

KsFilterAddEvent must be called at IRQL = PASSIVE_LEVEL.

See Also

KsAddEvent, KsGenerateEvents, KSEVENT_ENTRY


KsFilterAddTopologyConnections

The KsFilterAddTopologyConnections function adds new topology connections to a filter.

KSDDKAPI NTSTATUS NTAPI
  KsFilterAddTopologyConnections (
    IN PKSFILTER Filter,
    IN ULONG NewConnectionsCount,
    IN const KSTOPOLOGY_CONNECTION *const NewTopologyConnections
    );

Parameters

Filter
The filter to which to add the new connections.
NewConnectionsCount
The number of connections in NewTopologyConnections.
NewTopologyConnections
An array containing the new topology connections.

Return Value

Success or failure of the attempt to add topology connections. Failure can occur due to invalid connections having been specified in the list, low memory, or other reasons. If failure occurs, none of the topology connections are added.

Headers

Declared in ks.h. Include ks.h.

Comments

Note that the filter control mutex must be held before calling this function.

KsFilterAddTopologyConnections must be called at IRQL = PASSIVE_LEVEL.

See Also

Mutexes in AVStream


KsFilterAttemptProcessing

The KsFilterAttemptProcessing function attempts to initiate processing on Filter.

VOID
  KsFilterAttemptProcessing(
    IN PKSFILTER  Filter,
    IN BOOLEAN  Asychronous
    );

Parameters

Filter
Pointer to the AVStream filter object on which to attempt processing.
Asynchronous
Contains an indication as to whether the processing dispatch should occur asynchronously or not (should it occur). An asynchronous dispatch is guaranteed if this is TRUE; however, synchronous processing dispatches are governed by conditions described below.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

If the minidriver calls KsFilterAttemptProcessing when all of the conditions required to process data are met, a processing dispatch occurs. For more information on the process callback, see KSFILTER_DISPATCH. In order for the attempt to result in an actual dispatch, the filter's process control gate must be in an open state. Unlike pin-centric processing, for which relatively few conditions affect the process control gate, filter-centric processing has many conditions that affect the process control gate. For more information on these requirements, see Filter-Centric Processing.

If the process control gate is open, a processing dispatch occurs, either synchronously or asynchronously. If the caller specifies TRUE in the Asynchronous parameter, the processing dispatch always occurs asynchronously in a work item. However, if the caller requests a synchronous processing dispatch, the dispatch only occurs synchronously if the system is currently at an IRQL at which the minidriver can handle processing. If at PASSIVE_LEVEL, the dispatch is guaranteed to happen synchronously. Conversely, if at DISPATCH_LEVEL, the dispatch only happens synchronously if KSFILTER_FLAG_DISPATCH_LEVEL_PROCESSING is specified on the filter. Otherwise, a work item is queued to perform processing.

Note that this is only an attempt at processing; calling this function does not guarantee that processing will commence. Processing only occurs if the process control gate is "open."

KsFilterAttemptProcessing must be called at IRQL <= DISPATCH_LEVEL.

See Also

KSGATE, Filter-Centric Processing, Pin-Centric Processing, Processing Commonality, Flow Control Gates in AVStream, KSFILTER_DISPATCH, KsGateCaptureThreshold and other KsGate* functions, KsPinAttemptProcessing


KsFilterCreateNode

The KsFilterCreateNode function creates a new topology node on the specified filter.

KSDDKAPI NTSTATUS NTAPI
  KsFilterCreateNode (
    IN PKSFILTER Filter,
    IN const KSNODE_DESCRIPTOR *const NodeDescriptor,
    OUT PULONG NodeID
    );

Parameters

Filter
The filter on which to create a new topology node.
NodeDescriptor
The descriptor of the new node.
NodeID
The ID of the new node is returned here.

Return Value

Success or failure of creating the node. The call may fail due to invalid parameters, low memory, or other reasons. Failure means that the node is not added.

Headers

Declared in ks.h. Include ks.h.

Comments

Note that the filter control mutex must be held before calling this function.

KsFilterCreateNode must be called at IRQL = PASSIVE_LEVEL.

See Also

KsFilterCreatePinFactory, Mutexes in AVStream


KsFilterCreatePinFactory

The KsFilterCreatePinFactory function creates a new pin factory on the specified filter.

KSDDKAPI NTSTATUS NTAPI
  KsFilterCreatePinFactory (
    IN PKSFILTER Filter,
    IN const KSPIN_DESCRIPTOR_EX *const PinDescriptor,
    OUT PULONG PinID
    );

Parameters

Filter
The filter on which to create a new pin factory.
PinDescriptor
The descriptor of the pin.
PinID
The ID of the factory is returned here.

Headers

Declared in ks.h. Include ks.h.

Return Value

Success or failure of the attempt to create the pin factory. Failure may occur due to invalid parameters or low memory. If a failure is returned, a pin factory was not created.

Comments

Note that the filter control mutex must be held before calling this function.

KsFilterCreatePinFactory must be called at IRQL = PASSIVE_LEVEL.

See Also

KsFilterCreateNode, Mutexes in AVStream


KsFilterFactoryGetDevice

The KsFilterFactoryGetDevice function returns the AVStream device to which FilterFactory belongs.

PKSDEVICE __inline
  KsFilterFactoryGetDevice(
    IN PKSFILTERFACTORY  FilterFactory
    );

Parameters

FilterFactory
The filter factory for which to find the corresponding AVStream device.

Return Value

Returns a pointer to the AVStream device to which FilterFactory belongs.

Headers

Declared in ks.h. Include ks.h.

Comments

This call is an inline function call to KsGetDevice.

See the section AVStream Overview for more information on the AVStream object hierarchy.

KsFilterFactoryGetDevice must be called at IRQL = PASSIVE_LEVEL.

See Also

KSFILTERFACTORY, KSDEVICE, KsGetDevice, AVStream Overview


KsFilterGenerateEvents

The KsFilterGenerateEvents function generates events of an indicated type that are present in Filter's event list.

VOID _inline
  KsFilterGenerateEvents(
    IN PKSFILTER  Filter,
    IN const GUID*  EventSet, /* optional */
    IN ULONG  EventId,
    IN ULONG  DataSize,
    IN PVOID  Data, /* optional */
    IN PFNKSGENERATEEVENTCALLBACK  CallBack, /* optional */
    IN PVOID  CallBackContext /* optional */
    );

Parameters

Filter
The filter on which to generate events.
EventSet
The event set GUID to match for determination of which events to generate. If this parameter is NULL, set GUID is not taken into account for determining matching events.
EventId
The event ID to match for determining which events to generate.
DataSize
The size of Data.
Data
The data with which to generate the data event. For more information, see the Comments section below.
CallBack
Pointer to a caller-specified function that is called to determine whether a given event should be generated. If this is NULL, no callback verification is performed to determine whether or not an event should be generated (only EventSet and EventId are used). For more information, see the Comments section below.
CallBackContext
Pointer to a caller-specified context that is passed to the callback function CallBack. For more information, see the Comments section below.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

When calling this function, a minidriver must place Data and CallBackContext in a locked, non-pageable data segment. In addition, note that the Callback is made at DISPATCH_LEVEL. The callback function must be in a locked segment and must be prepared to run at IRQL = DISPATCH_LEVEL. Note that there is an additional issue in DX8 only: EventSet must be in a locked data segment.

This is an inline function call to KsGenerateEvents that performs the necessary typecasting. Minidrivers should usually call this version instead of directly calling KsGenerateEvents.

An event is generated if:

  • The event is present in Filter's event list and EventId matches the event's ID
  • EventSet either matches the event's set GUID or is NULL, and
  • CallBack is either NULL or authorizes the match.

CallBack is a caller-specified callback used for additional match determination. It is prototyped as follows:

BOOLEAN CallBack (IN PVOID Context, IN PKSEVENT_ENTRY EventEntry);

Place the context for the callback function in CallBackContext. The callback function should return TRUE if EventEntry should be generated. Otherwise, the callback function should return FALSE.

KsFilterGenerateEvents must be called at IRQL <= DISPATCH_LEVEL.

See Also

KsAddEvent, KsGenerateEvents, KsPinGenerateEvents, KSEVENT_ENTRY, Event Handling in AVStream, KS Events


KsFilterFactoryAddCreateItem

The KsFilterFactoryAddCreateItem function adds a new create item for the specified filter factory.

KSDDKAPI NTSTATUS NTAPI
  KsFilterFactoryAddCreateItem(
    IN PKSFILTERFACTORY  FilterFactory,
    IN PWCHAR  RefString,
    IN PSECURITY_DESCRIPTOR  SecurityDescriptor OPTIONAL,
    IN ULONG  CreateItemFlags
    );

Parameters

FilterFactory
The filter factory to which to add a new create item.
RefString
A text string that identifies the create item.
SecurityDescriptor
Optionally contains a security descriptor for this type of object. For related information, see KSOBJECT_CREATE_ITEM.
CreateItemFlags
See the table for the Flags member of KSOBJECT_CREATE_ITEM.

Return Values

Returns success or failure of the attempt to add a new create item.

Headers

Declared in ks.h. Include ks.h.

Comments

Normally, only a single create item using the reference GUID supplied in the filter descriptor is added for the filter factory. This function allows the caller to add create items associated with the given filter factory.

See Also

KSOBJECT_CREATE_ITEM, KsAllocateObjectCreateItem, KsAddObjectCreateItemToDeviceHeader, KsAddObjectCreateItemToObjectHeader, KsFreeObjectCreateItem, KsQueryObjectCreateItem, Initializing an AVStream Minidriver


KsFilterFactoryGetFirstChildFilter

The KsFilterFactoryGetFirstChildFilter function returns the first instantiated filter created by FilterFactory.

PKSFILTER __inline
  KsFilterFactoryGetFirstChildFilter(
    IN PKSFILTERFACTORY  FilterFactory
    );

Parameters

FilterFactory
The filter factory for which to find the first instantiated child filter.

Return Value

A pointer to the first instantiated filter created by FilterFactory is returned. If there are no instantiated filters created by FilterFactory, NULL is returned.

Headers

Declared in ks.h. Include ks.h.

Comments

This call is an inline function call to KsGetFirstChild. Note that the object hierarchy is only guaranteed to be stable while the appropriate mutex is held, in this case the device mutex.

KsFilterFactoryGetFirstChildFilter must be called at IRQL = PASSIVE_LEVEL.

See Also

KSFILTER, KSFILTERFACTORY, KsGetFirstChild, KsFilterGetNextSiblingFilter, Mutexes in AVStream


KsFilterFactoryGetNextSiblingFilterFactory

The KsFilterFactoryGetNextSiblingFilterFactory function returns the next filter factory belonging to the parent device of FilterFactory.

PKSFILTERFACTORY __inline
  KsFilterFactoryGetNextSiblingFilterFactory(
    IN PKSFILTERFACTORY  FilterFactory
    );

Parameters

FilterFactory
The filter factory for which to return the next filter factory of its parent device.

Return Value

The next sibling filter factory of FilterFactory is returned. If no such filter factory exists, NULL is returned.

Headers

Declared in ks.h. Include ks.h.

Comments

This call is an inline function call to KsGetNextSibling. Note that the object hierarchy is only guaranteed to be stable while the appropriate mutex is held, in this case the device mutex.

KsFilterFactoryGetNextSiblingFilterFactory must be called at IRQL = PASSIVE_LEVEL.

See Also

KSFILTERFACTORY, KsDeviceGetFirstChildFilterFactory, KsGetNextSibling, Mutexes in AVStream


KsFilterFactoryGetOuterUnknown

The KsFilterFactoryGetOuterUnknown function returns the outer unknown interface of the specified filter factory.

PUNKNOWN __inline
  KsFilterFactoryGetOuterUnknown(
    IN PKSFILTERFACTORY  FilterFactory
    );

Parameters

FilterFactory
The filter factory for which to return the outer unknown interface.

Return Value

The outer unknown interface of FilterFactory is returned. The minidriver can then use it to query for other interfaces.

Headers

Declared in ks.h. Include ks.h.

Comments

This call is an inline function call to KsGetOuterUnknown.

KsFilterFactoryGetOuterUnknown must be called at IRQL = PASSIVE_LEVEL.

See Also

KsGetOuterUnknown, KsRegisterAggregatedClientUnknown, AVStream Overview, KsFilterRegisterAggregatedClientUnknown, KsFilterGetOuterUnknown, KsPinGetOuterUnknown, IksControl


KsFilterFactoryGetParentDevice

The KsFilterFactoryGetParentDevice function returns the parent device of the given filter factory.

PKSDEVICE __inline
  KsFilterFactoryGetParentDevice(
    IN PKSFILTERFACTORY  FilterFactory
    );

Parameters

FilterFactory
The filter factory for which to return the parent device.

Return Value

The parent device of the filter factory is returned. This is the AVStream device to which the filter factory belongs.

Headers

Declared in ks.h. Include ks.h.

Comments

This call is an inline function call to KsGetParent. Note that the object hierarchy is guaranteed to be stable only while the appropriate mutex is held, in this case the device mutex.

KsFilterFactoryGetParentDevice must be called at IRQL = PASSIVE_LEVEL.

See Also

KSDEVICE, KSFILTERFACTORY, KsGetParent, Mutexes in AVStream


KsFilterFactoryGetSymbolicLink

The KsFilterFactoryGetSymbolicLink function returns the symbolic link associated with a given filter factory.

PUNICODE_STRING
  KsFilterFactoryGetSymbolicLink(
    IN PKSFILTERFACTORY  FilterFactory
    );

Parameters

FilterFactory
The filter factory for which to acquire the symbolic link.

Return Value

A pointer to a Unicode string containing the symbolic link for the filter factory is returned if the call is successful, and NULL if unsuccessful. NULL indicates that no device interfaces have been registered for FilterFactory.

Headers

Declared in ks.h. Include ks.h.

Comments

If FilterFactory has no registered device interfaces, KsFilterFactoryGetSymbolicLink returns NULL.

KsFilterFactoryGetSymbolicLink must be called at IRQL = PASSIVE_LEVEL.


KsFilterFactoryRegisterAggregatedClientUnknown

This inline function is a wrapper for KsRegisterAggregatedClientUnknown.

KSDDKAPI PUNKNOWN NTAPI
  KsFilterFactoryRegisterAggregatedClientUnknown(
    IN PKSFILTERFACTORY  FilterFactory,
    IN PUNKNOWN  ClientUnknown
    );

Parameters

FilterFactory
The specified AVStream filter factory.
ClientUnknown
The client unknown object.

Return Values

Returns the newly created aggregate object.

Headers

Declared in ks.h. Include ks.h.

Comments

Note that this inline function only performs a typecast and then calls KsRegisterAggregatedClientUnknown.

See Also

KsRegisterAggregatedClientUnknown


KsFilterFactorySetDeviceClassesState

The KsFilterFactorySetDeviceClassesState function enables or disables the device classes that have been registered by a given filter factory.

KSDDKAPI
NTSTATUS
NTAPI
KsFilterFactorySetDeviceClassesState(
    IN PKSFILTERFACTORY  FilterFactory,
    IN BOOLEAN  NewState
    );

Parameters

FilterFactory
A pointer to the filter factory for which to change device class status.
NewState
If set to TRUE, the device classes are enabled; if FALSE, they are disabled.

Return Values

Returns STATUS_SUCCESS or an error code.

Headers

Declared in ks.h. Include ks.h.

Comments

KsFilterFactorySetDeviceClassesState must be called at IRQL = PASSIVE_LEVEL.


KsFilterFactoryUpdateCacheData

The KsFilterFactoryUpdateCacheData function updates the FilterData registry key and the Medium cache (a set of registry keys) for a given filter factory.

NTSTATUS
  KsFilterFactoryUpdateCacheData (
    IN PKSFILTERFACTORY  FilterFactory,
    IN const KSFILTER_DESCRIPTOR*  FilterDescriptor OPTIONAL
    );

Parameters

FilterFactory
The KSFILTERFACTORY for which to update FilterData and Medium cache in the registry.
FilterDescriptor
An optional KSFILTER_DESCRIPTOR for which the FilterData key and Medium cache will be updated. If NULL, FilterFactory's descriptor is used instead. Provide if the filter factory uses dynamic pins and needs to update information for pins that have not yet been instantiated.

Return Value

Returns STATUS_SUCCESS or a failure code, indicating whether the relevant registry information was successfully updated. Returns STATUS_INVALID_PARAMETER if no device interface is found that corresponds to the categories passed in the filter descriptor.

Headers

Declared in ks.h. Include ks.h.

Comments

This routine updates the FilterData key and Medium cache for all categories specified in FilterDescriptor. If FilterDescriptor is NULL, the FilterData and Medium cache will be updated for all categories specified in FilterFactory's KSFILTER_DESCRIPTOR member.

KsRegisterFilterWithNoKSPins provides similar functionality, but should not be used if two instances of KSFILTER_DESCRIPTOR under the same KSDEVICE are registered in the same category, and differ only in reference GUID. In this case, KsRegisterFilterWithNoKSPins updates data only for the first, even though the second may have been specified.

Do not use this routine in place of KsRegisterFilterWithNoKSPins for filters with no KS pins, such as analog style crossbars. Use this routine only for a specific filter for which the minidriver is passing the corresponding filter factory.

In addition, KsRegisterFilterWithNoKSPins only allows one medium per registered pin. This may not be sufficient for a BDA minidriver.

See Also

KsRegisterFilterWithNoKSPins, KSFILTER_DESCRIPTOR, KSFILTERFACTORY, AVStream Object Hierarchy


KsFilterGetAndGate

The KsFilterGetAndGate function returns Filter's AND gate.

PKSGATE
  KsFilterGetAndGate(
    IN PKSFILTER  Filter
    );

Parameters

Filter
Pointer to the AVStream filter for which to acquire the corresponding AND gate.

Return Value

Filter's AND gate is returned.

Headers

Declared in ks.h. Include ks.h.

Comments

A minidriver can use AND gates on a filter as a processing control mechanism for that filter.

See Also

KSGATE, KsGateCaptureThreshold, KsGateTurnInputOn, KsGateTurnInputOff, KsPinAttachAndGate, KsPinGetAndGate


KsFilterGetChildPinCount

The KsFilterGetChildPinCount function returns the number of pins of a given type that are currently instantiated on a given filter.

ULONG
  KsFilterGetChildPinCount(
    IN PKSFILTER  Filter,
    IN ULONG  PinId
    );

Parameters

Filter
The filter for which to find the number of instantiated pins of type PinId.
PinId
The pin type for which to find the number of instantiated pins. PinId is an index into the array of pin descriptors for the filter to which the pin belongs.

Return Value

Returns the number of pins of type PinId that are currently instantiated on Filter. If no such pins exist or if PinId is out of range, zero is returned.

Headers

Declared in ks.h. Include ks.h.

Comments

The count returned by this call is only guaranteed to be correct if the function is called while the filter control mutex is held. The count remains correct after the call as long as this mutex continues to be held. As soon as the mutex is released, other pins can be added or removed, thereby altering the actual pin count.

KsFilterGetChildPinCount must be called at IRQL = PASSIVE_LEVEL.

See Also

KSPIN, KSFILTER, KsFilterGetFirstChildPin, KsPinGetNextSiblingPin, Mutexes in AVStream


KsFilterGetDevice

The KsFilterGetDevice function returns the AVStream device to which Filter belongs.

PKSDEVICE __inline
  KsFilterGetDevice(
    IN PKSFILTER  Filter
    );

Parameters

Filter
The filter for which to find the owning AVStream device.

Return Value

The AVStream device to which Filter belongs is returned.

Headers

Declared in ks.h. Include ks.h.

Comments

This call is an inline function call to KsGetDevice.

KsFilterGetDevice must be called at IRQL = PASSIVE_LEVEL.

See Also

KSFILTER, KSDEVICE, KsGetDevice


KsFilterGetFirstChildPin

The KsFilterGetFirstChildPin function returns the first instantiated pin of type PinId on the filter specified by Filter.

PKSPIN
  KsFilterGetFirstChildPin(
    IN PKSFILTER  Filter,
    IN ULONG  PinId
    );

Parameters

Filter
The filter to query for instantiated pins.
PinId
The numeric ID of the pin type for which to find the first instantiated member.

Return Value

Returns the first instantiated pin of type PinId on the specified filter.

Headers

Declared in ks.h. Include ks.h.

Comments

Note that the object hierarchy is only guaranteed stable while the appropriate mutex is held, in this case the filter control mutex.

KsFilterGetFirstChildPin must be called at IRQL = PASSIVE_LEVEL.

See Also

KSPIN, KsFilterGetChildPinCount, KsPinGetNextSiblingPin, Mutexes in AVStream


KsFilterGetNextSiblingFilter

The KsFilterGetNextSiblingFilter function returns the next instantiated filter belonging to the parent filter factory of Filter.

PKSFILTER __inline
  KsFilterGetNextSiblingFilter(
    IN PKSFILTER  Filter
    );

Parameters

Filter
The filter for which to find the next sibling filter.

Return Value

Returns the next sibling filter of Filter. If no such instantiated filter exists, returns NULL.

Headers

Declared in ks.h. Include ks.h.

Comments

This call is an inline function call to KsGetNextSibling. Note that the object hierarchy is only guaranteed stable while the appropriate mutex is held, in this case the device mutex.

KsFilterGetNextSiblingFilter must be called at IRQL = PASSIVE_LEVEL.

See Also

KSFILTER, KsFilterFactoryGetFirstChildFilter, KsGetNextSibling, Mutexes in AVStream


KsFilterGetOuterUnknown

The KsFilterGetOuterUnknown function returns the outer unknown interface of the filter specified by Filter.

PUNKNOWN __inline
  KsFilterGetOuterUnknown(
    IN PKSFILTER  Filter
    );

Parameters

Filter
The filter for which to return the outer unknown interface.

Return Value

Returns the outer unknown interface of Filter. The interface can then be used to query for other interfaces, or it can be used in conjunction with a Ks*RegisterAggregatedClientUnknown call to cause Filter to aggregate a minidriver supplied COM object.

Headers

Declared in ks.h. Include ks.h.

Comments

This call is an inline function call to KsGetOuterUnknown.

KsFilterGetOuterUnknown must be called at IRQL = PASSIVE_LEVEL.

See Also

KsGetOuterUnknown, KsRegisterAggregatedClientUnknown, KsPinRegisterAggregatedClientUnknown, KsRegisterAggregatedClientUnknown, AVStream Overview, KsFilterRegisterAggregatedClientUnknown, KsPinGetOuterUnknown, IksControl


KsFilterGetParentFilterFactory

The KsFilterGetParentFilterFactory function returns the parent filter factory of the given filter.

PKSFILTERFACTORY __inline
  KsFilterGetParentFilterFactory(
    IN PKSFILTER  Filter
    );

Parameters

Filter
The filter for which to return the parent filter factory.

Return Value

Returns the parent filter factory of Filter. This is AVStream filter factory from which Filter was created.

Headers

Declared in ks.h. Include ks.h.

Comments

This call is an inline function call to KsGetParent . Note that the object hierarchy is only guaranteed stable while the appropriate mutex is held, in this case the device mutex. For more information on mutexes, see Mutexes in AVStream.

KsFilterGetParentFilterFactory must be called at IRQL = PASSIVE_LEVEL.

See Also

KSFILTER, KSFILTERFACTORY, KsGetParent, Mutexes in AVStream


KsFilterRegisterAggregatedClientUnknown

This inline function is a wrapper for KsRegisterAggregatedClientUnknown.

KSDDKAPI PUNKNOWN NTAPI
  KsFilterRegisterAggregatedClientUnknown(
    IN PKSFILTER  Filter,
    IN PUNKNOWN  ClientUnknown
    );

Parameters

Filter
The specified AVStream filter.
ClientUnknown
The client unknown object.

Return Values

Returns the newly created aggregate object.

Headers

Declared in ks.h. Include ks.h.

Comments

Note that this inline function only performs a typecast and then calls KsRegisterAggregatedClientUnknown.

See Also

KsRegisterAggregatedClientUnknown


KsFilterRegisterPowerCallbacks

The KsFilterRegisterPowerCallbacks function registers power management callbacks for Filter.

VOID
  KsFilterRegisterPowerCallbacks(
    IN PKSFILTER  Filter,
    IN PFNKSFILTERPOWER  Sleep, /* optional */
    IN PFNKSFILTERPOWER  Wake /* optional */
    );

Parameters

Filter
The filter for which to register power callbacks. In order to receive power notification messages, the filter must be capable of processing, so Filter must be filter-centric.
Sleep
Pointer to a function that handles sleep requests for the device. For more information, see the Comments section below.
Wake
Pointer to a function that handles wake requests for the device. For more information, see the Comments section below.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

The two callbacks should be prototyped as follows:

void Sleep/Wake (IN PKSFILTER Filter, IN DEVICE_POWER_STATE State);

The Sleep callback is made if Filter is a filter-centric filter and the device is going to sleep. The Wake callback is made if Filter is a filter-centric filter and the device is waking up.

KsFilterRegisterPowerCallbacks must be called at IRQL = PASSIVE_LEVEL.

Do not attempt to obtain the filter control mutex from within either the Sleep or Wake callback, or deadlock may occur. For more on mutexes, see Mutexes in AVStream.

See Also

KsPinRegisterPowerCallbacks, Initializing an AVStream Minidriver, Filter-Centric Processing


KsFilterReleaseControl

The KsFilterReleaseControl function releases the control mutex for the AVStream filter specified by Filter.

VOID __inline
  KsFilterReleaseControl(
    IN PKSFILTER  Filter
    );

Parameters

Filter
The AVStream filter for which to release the control mutex.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

This function is an inline call to KsReleaseControl with the appropriate typecasting. When manipulating a filter, minidrivers should call this function instead of calling KsReleaseControl directly.

See Mutexes in AVStream for a description of the filter control mutex.

KsFilterReleaseControl must be called at IRQL = PASSIVE_LEVEL.

See Also

KsFilterAcquireControl, KsReleaseControl, Mutexes in AVStream


KsFilterReleaseProcessingMutex

The KsFilterReleaseProcessingMutex function releases the processing mutex for the AVStream filter specified by Filter.

VOID
  KsFilterReleaseProcessingMutex(
    IN PKSFILTER  Filter
    );

Parameters

Filter
Pointer to the AVStream filter for which to release the processing mutex.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

For more AVStream-specific information on mutexes, please see Mutexes in AVStream.

KsFilterReleaseProcessingMutex must be called at IRQL = PASSIVE_LEVEL.

See Also

KsFilterAcquireProcessingMutex, Mutexes in AVStream, Processing Mutex in AVStream


KsFreeObjectBag

The KsFreeObjectBag function empties and frees an object bag.

VOID
  KsFreeObjectBag(
    IN KSOBJECT_BAG  ObjectBag
    );

Parameters

ObjectBag
The KSOBJECT_BAG (equivalent to type PVOID) to be emptied and then freed.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

For more information, see Object Bags.

KsFreeObjectBag removes any items present in ObjectBag. In addition, if the reference count for a given object is zero (that is, the object is not present in any other object bag associated with the same device as ObjectBag), then that item is freed.

KsFreeObjectBag must be called at IRQL = PASSIVE_LEVEL.

See Also

KsAllocateObjectBag, KsAddItemToObjectBag, KsRemoveItemFromObjectBag, KsDiscard, KsCopyObjectBagItems, Object Bags


KsGateAddOffInputToAnd

The KsGateAddOffInputToAnd function adds a new input in the OFF state to a given AND gate.

VOID __inline
  KsGateAddOffInputToAnd(
    IN PKSGATE  AndGate
    );

Parameters

AndGate
The AND gate to which to add a new OFF input.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

Adding an OFF input to an open AND gate closes the gate and propagates the close down to any attached gates.

This function should only be used on gates that were specifically created as AND gates; AVStream does not verify that the given gate is an AND gate.

KsGateAddOffInputToAnd is an inline function call to KsGateTurnInputOff. If conceptually adding a new input to a gate, the minidriver should call KsGateAddOffInputToAnd rather than KsGateTurnInputOff.

KsGateAddOffInputToAnd may be called at any IRQL.

See Also

KsGateRemoveOffInputFromAnd, KsGateAddOnInputToAnd, KsGateRemoveOnInputFromAnd, KsGateTurnInputOn, KsGateTurnInputOff


KsGateAddOffInputToOr

The KsGateAddOffInputToOr function adds a new input in the OFF state to a given OR gate.

VOID __inline
  KsGateAddOffInputToOr(
    IN PKSGATE  OrGate
    );

Parameters

OrGate
The OR gate to which to add a new OFF input.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

This function should only be used on gates that were specifically created as OR gates; AVStream does not verify that the given gate is an OR gate.

This call is an empty function. It should be used for code readability and clarity.

KsGateAddOffInputToOr may be called at any IRQL.

See Also

KsGateRemoveOffInputFromOr, KsGateAddOnInputToOr, KsGateRemoveOnInputFromOr, KsGateTurnInputOn, KsGateTurnInputOff


KsGateAddOnInputToAnd

The KsGateAddOnInputToAnd function adds a new input in the ON state to a given AND gate.

VOID __inline
  KsGateAddOnInputToAnd(
    IN PKSGATE  AndGate
    );

Parameters

AndGate
The AND gate to which to add a new ON input.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

This function should only be used on gates that were specifically created as AND gates; AVStream does not verify that the given gate is an AND gate.

This call is an empty function. It should be used for code readability and clarity.

KsGateAddOnInputToAnd may be called at any IRQL.

See Also

KsGateRemoveOnInputFromAnd, KsGateAddOffInputToAnd, KsGateRemoveOffInputFromAnd, KsGateTurnInputOn, KsGateTurnInputOff


KsGateAddOnInputToOr

The KsGateAddOnInputToOr function adds a new input in the ON state to a given OR gate.

VOID __inline
  KsGateAddOnInputToOr(
    IN PKSGATE  OrGate
    );

Parameters

OrGate
The OR gate to which to add a new ON input.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

Adding an ON input to an OR gate in the OFF or closed state results in the gate opening and the transition being propagated to any gates attached to OrGate. Use this function only with gates that were specifically created as OR gates. AVStream does not verify that the given gate is an OR gate.

This call is an inline function call to KsGateTurnInputOn. Minidrivers should call KsGateAddOnInputToOr rather than KsGateTurnInputOn if conceptually adding a new input to the gate.

KsGateAddOnInputToOr may be called at any IRQL.

See Also

KsGateRemoveOnInputFromOr, KsGateAddOffInputToOr, KsGateRemoveOffInputFromOr, KsGateTurnInputOn, KsGateTurnInputOff


KsGateCaptureThreshold

The KsGateCaptureThreshold function is used to capture an ON input of an AND gate specified by Gate.

BOOLEAN __inline
  KsGateCaptureThreshold(
    IN PKSGATE  Gate
    );

Parameters

Gate
The AND gate for which to capture an ON input synchronously.

Return Value

Returns TRUE if the AND gate was originally open. Note that returning TRUE implies that the gate was closed so that no other thread could simultaneously capture the gate and commence processing.

A return value of FALSE indicates that the gate was originally closed and that this thread was unable to capture an ON input of the gate. Thus, the current thread cannot process.

Headers

Declared in ks.h. Include ks.h.

Comments

KsGateCaptureThreshold checks the state of the given AND gate and if it is open turns off an input to the gate, thereby transitioning the gate to a closed state. If the gate is closed, the function does nothing. Unlike KsGateGetStateUnsafe, this call is done synchronously with respect to other gate state changes. It is the primary synchronization mechanism for processing based on gate control.

Despite its name, this function is only a valid call for AND gates, not gates in general. AVStream, however, does not verify whether Gate is an AND gate or an OR gate. It is the caller's responsibility to ensure that the call is only made on AND gates.

The call is made using interlocked functions and is thus synchronous with respect to any of the other gate state change functions; it is also a very efficient method of process control.

KsGateCaptureThreshold may be called at any IRQL.

See Also

KsGateInitializeAnd, KsGateInitializeOr, KsGateGetStateUnsafe, KsGateAddOnInputToAnd, KsGateAddOnInputToOr, KsGateAddOffInputToAnd, KsGateAddOffInputToOr, KsGateRemoveOnInputFromAnd, KsGateRemoveOnInputFromOr, KsGateRemoveOffInputFromAnd, KsGateRemoveOffInputFromOr, KsGateTurnInputOn, KsGateTurnInputOff


KsGateGetStateUnsafe

The KsGateGetStateUnsafe function returns the state of the given gate (open or closed) in an unsafe manner, that is without regard to synchronization.

BOOLEAN __inline
  KsGateGetStateUnsafe(
    IN PKSGATE  Gate
    );

Parameters

Gate
The gate for which to return the state.

Return Value

This call returns TRUE if the gate is open and FALSE if the gate is closed.

Headers

Declared in ks.h. Include ks.h.

Comments

Because KsGateGetStateUnsafe does not handle synchronization, it is possible to get a result that is not consistent with the state of the gate if the gate is in mid-transition from one state to another at the time of the call. Consider two connected gates, A->B. A transitions to closed, causing B to transition from open to closed. If, at the same time, this call is made in another thread between A being closed and B being closed, this call would still return that B was open.

KsGateGetStateUnsafe returns whether Gate->Count is greater than zero. The function does not use any interlocked functions to do this. Thus, the call is performed without regard to synchronization.

KsGateGetStateUnsafe may be called at any IRQL.


KsGateInitialize

The KsGateInitialize function initializes a gate for use.

VOID __inline
  KsGateInitialize(
    IN PKSGATE  Gate,
    IN LONG  InitialCount,
    IN PKSGATE  NextGate, /* optional */
    IN BOOLEAN  StateToPropagate
    );

Parameters

Gate
Pointer to the KSGATE structure to initialize.
InitialCount
Specifies the initial count to place on the gate. Fills in Gate -> Count. For a new AND gate, this should be 1 (1 – 0 off inputs), and for a new OR gate, this should be 0 (0 on inputs). See Flow Control Gates in AVStream.
NextGate
Pointer to a gate to which Gate should attach its output for state transitions. This parameter is optional; a gate need not be attached to another gate.
StateToPropagate
Specifies whether to propagate ON transitions or OFF transitions. For an OR gate, set to TRUE, and for an AND gate, set to FALSE.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

Minidrivers should not call KsGateInitialize directly, but should instead use KsGateInitializeAnd or KsGateInitializeOr.

AND and OR gates are conceptualizations of the gating mechanism. AVStream does not distinguish between them in the implementation of the common gate functions. The gate functions specific to AND and OR gates are inline calls to the common gate functions.

KsGateInitialize may be called at any IRQL.

See Also

KsGateInitializeAnd, KsGateInitializeOr, KsGateTerminateAnd, KsGateTerminateOr, Flow Control Gates in AVStream, KSGATE


KsGateInitializeAnd

The KsGateInitializeAnd function initializes a KSGATE structure as an AND gate and attaches it to the OR gate specified by NextOrGate.

VOID __inline
  KsGateInitializeAnd(
    IN PKSGATE  AndGate,
    IN PKSGTE  NextOrGate /* optional */
    );

Parameters

AndGate
Pointer to the KSGATE structure to initialize as a new AND gate.
NextOrGate
Pointer to an existing KSGATE structure to which AndGate attaches. This parameter should be an OR gate and is optional.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

The next gate (following AndGate) must be an OR gate, whether it is specified in this call or later.

KsGateInitializeAnd is an inline call to KsGateInitialize.

KsGateInitializeAnd may be called at any IRQL.

See Also

KsGateInitialize, KsGateInitializeOr, KsGateTerminateAnd, KsGateTerminateOr, Flow Control Gates in AVStream, KSGATE


KsGateInitializeOr

The KsGateInitializeOr function initializes a KSGATE structure as an OR gate and attaches it to the AND gate specified by NextAndGate.

VOID __inline
  KsGateInitializeOr(
    IN PKSGATE  OrGate,
    IN PKSGATE  NextAndGate OPTIONAL
    );

Parameters

OrGate
Pointer to the KSGATE structure to initialize as a new OR gate.
NextAndGate
Pointer to an existing KSGATE structure to which OrGate attaches. Optional.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

The next gate (following OrGate) must be an AND gate, whether it is specified in this call or later. If you need to connect an OR gate to another OR gate, use KsGateInitialize.

This function is an inline call to KsGateInitialize.

KsGateInitializeOr may be called at any IRQL.

See Also

KsGateInitialize, KsGateInitializeAnd, KsGateTerminateAnd, KsGateTerminateOr, KSGATE, Flow Control Gates in AVStream


KsGateRemoveOffInputFromAnd

The KsGateRemoveOffInputFromAnd function removes an existing input that is in the OFF state from an AND gate.

VOID
  KsGateRemoveOffInputFromAnd(
    IN PKSGATE  AndGate
    );

Parameters

AndGate
The AND gate from which to remove an OFF input

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

Removing the last OFF input from the gate results in the gate opening and the transition being propagated to any gates connected to AndGate.

KsGateRemoveOffInputFromAnd should only be used on gates that were specifically created as AND gates; AVStream does not verify that the given gate is an AND gate.

KsGateRemoveOffInputFromAnd is an inline function call to KsGateTurnInputOn. If conceptually removing an existing input to the gate rather than turning it off, a minidriver should call KsGateRemoveOffInputFromAnd instead of KsGateTurnInputOn.

KsGateRemoveOffInputFromAnd may be called at any IRQL.

See Also

KsGateAddOffInputToAnd, KsGateAddOnInputToAnd, KsGateRemoveOnInputFromAnd, KsGateTurnInputOn, KsGateTurnInputOff, KSGATE, Flow Control Gates in AVStream


KsGateRemoveOffInputFromOr

The KsGateRemoveOffInputFromOr function removes an existing input that is in the OFF state from an OR gate.

VOID __inline
  KsGateRemoveOffInputFromOr(
    IN PKSGATE  OrGate
    );

Parameters

OrGate
The OR gate from which to remove an OFF input.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

KsGateRemoveOffInputFromOr should only be used on gates that were specifically created as AND gates; AVStream does not verify that the given gate is truly an AND gate.

This call is an empty function. It should be used for code readability and clarity.

KsGateRemoveOffInputFromOr may be called at any IRQL.

See Also

KsGateAddOffInputToOr, KsGateAddOnInputToOr, KsGateRemoveOnInputFromOr, KsGateTurnInputOn, KsGateTurnInputOff, Flow Control Gates in AVStream


KsGateRemoveOnInputFromAnd

The KsGateRemoveOnInputFromAnd function removes an existing input that is in the ON state from an AND gate.

VOID
  KsGateRemoveOnInputFromAnd(
    IN PKSGATE  AndGate
    );

Parameters

AndGate
The AND gate from which to remove an ON input.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

KsGateRemoveOnInputFromAnd should only be used on gates that were specifically created as AND gates; AVStream does not verify that the given gate is truly an AND gate.

This call is an empty function. It should be used for code readability and clarity.

KsGateRemoveOnInputFromAnd may be called at any IRQL.

See Also

KsGateAddOnInputToAnd, KsGateAddOffInputToAnd, KsGateRemoveOffInputFromAnd, KsGateTurnInputOn, KsGateTurnInputOff, Flow Control Gates in AVStream


KsGateRemoveOnInputFromOr

The KsGateRemoveOnInputFromOr function removes an existing input that is in the ON state from an OR gate.

VOID
  KsGateRemoveOnInputFromOr(
    IN PKSGATE  OrGate
    );

Parameters

OrGate
The OR gate from which to remove an ON input.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

Removing the last ON input from a given OR gate results in the gate closing and the transition being propagated to any gates connected to OrGate.

KsGateRemoveOnInputFromOr should only be used on gates that were specifically created as AND gates; AVStream does not verify that the given gate is an AND gate.

This call is an inline function call to KsGateTurnInputOff. If conceptually removing an existing input to a gate, a minidriver should call KsGateRemoveOnInputFromOr rather than KsGateTurnInputOff.

KsGateRemoveOnInputFromOr may be called at any IRQL.

See Also

KsGateAddOnInputToOr, KsGateAddOffInputToOr, KsGateRemoveOffInputFromOr, KsGateTurnInputOn, KsGateTurnInputOff, Flow Control Gates in AVStream


KsGateTerminateAnd

The KsGateTerminateAnd function deletes an existing AND gate and removes an input from any attached OR gate.

VOID __inline
  KsGateTerminateAnd(
    IN PKSGATE  AndGate
    );

Parameters

AndGate
The AND gate to delete. Note that this should be at the beginning of a gate chain.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

Logical gates should be deleted in a front to back manner. KsGateTerminateAnd does not patch the gate chain for gates that are deleted at the end or in the middle.

KsGateTerminateAnd may be called at any IRQL.

See Also

KsGateInitializeAnd, KsGateInitializeOr, KsGateTerminateOr, Flow Control Gates in AVStream


KsGateTerminateOr

The KsGateTerminateOr function deletes an existing OR gate and removes an input from any attached AND gate.

VOID
  KsGateTerminateOr(
    IN PKSGATE  OrGate
    );

Parameters

OrGate
The OR gate to delete. Note that this should be at the beginning of a gate chain.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

Logical gates should be deleted in a front to back manner. KsGateTerminateOr does not patch the gate chain for gates that are deleted at the end or in the middle.

KsGateTerminateOr may be called at any IRQL.

See Also

KsGateInitializeAnd, KsGateInitializeOr, KsGateTerminateAnd, Flow Control Gates in AVStream


KsGateTurnInputOff

The KsGateTurnInputOff function turns off an existing input to Gate.

VOID __inline
  KsGateTurnInputOff(
    IN PKSGATE  Gate /* optional */
    );

Parameters

Gate
The gate that currently has an input in the ON state to transition to the OFF state. May be an AND gate or an OR gate.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

It is the minidriver's responsibility to verify that the gate that the minidriver passes to KsGateTurnInputOff has at least one ON input. If you call this function with an OR gate that has no inputs currently in the ON state, the call sets the OR gate into an invalid state. If you call this function with an AND gate that has no inputs currently in the ON state, the result is equivalent to adding another input in the OFF state to Gate.

Furthermore, if turning an input off would cause Gate to transition from the open state to the closed state, this call instead turns off an input to whatever gate is attached to Gate.

KsGateTurnInputOff may be called at any IRQL.

See Also

KsGateTurnInputOn, KsGateAddOnInputToAnd, KsGateAddOnInputToOr, KsGateAddOffInputToAnd, KsGateAddOffInputToOr, KsGateRemoveOnInputFromAnd, KsGateRemoveOnInputFromOr, KsGateRemoveOffInputFromAnd, KsGateRemoveOffInputFromOr, Flow Control Gates in AVStream, KSGATE


KsGateTurnInputOn

The KsGateTurnInputOn function turns on an existing input to Gate.

VOID __inline
  KsGateTurnInputOn(
    IN PKSGATE  Gate /* optional */
    );

Parameters

Gate
The gate that currently has an input in the OFF state to transition to the ON state. May be an AND gate or an OR gate.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

It is the minidriver's responsibility to verify that the gate that the minidriver passes to KsGateTurnInputOn has at least one OFF input. If you call this function with an AND gate that has no inputs currently in the OFF state, the call sets the AND gate into an invalid state. If you call this function with an OR gate that has no inputs currently in the OFF state, the result is equivalent to adding another input in the ON state to Gate.

Furthermore, if turning an input on would cause Gate to transition from the closed state to the open state, this call instead turns on an input to whatever gate is attached to Gate.

KsGateTurnInputOn may be called at any IRQL.

See Also

KsGateTurnInputOff, KsGateAddOnInputToAnd, KsGateAddOnInputToOr, KsGateAddOffInputToAnd, KsGateAddOffInputToOr, KsGateRemoveOnInputFromAnd, KsGateRemoveOnInputFromOr, KsGateRemoveOffInputFromAnd, KsGateRemoveOffInputFromOr, Flow Control Gates in AVStream, KSGATE


KsGenerateEvents

The KsGenerateEvents function generates events of an indicated type that are present in Object's event list.

VOID
  KsGenerateEvents(
    IN PVOID  Object,
    IN const  GUID* EventSet, /* optional */
    IN ULONG  EventId,
    IN ULONG  DataSize,
    IN PVOID  Data, /* optional */
    IN PFNKSGENERATEEVENTCALLBACK  CallBack, /* optional */
    IN PVOID  CallBackContext /* optional */
    );

Parameters

Object
The object on which to generate events. This can be an AVStream filter or pin object.
EventSet
The event set GUID to match to determine which events to generate. If this parameter is NULL, set GUID isnot taken into account for determining matching events.
EventId
The event ID to match to determine which events to generate.
DataSize
The size of the data with which to generate the data event.
Data
The data with which to generate the data event. See additional information below.
CallBack
Pointer to a caller-specified function that is called to determine whether a given event should be generated. If this is NULL, no callback verification is performed to determine whether or not an event should be generated (only EventSet and EventId are used).
CallBackContext
Pointer to a caller-specified context that is passed to the callback function CallBack.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

When calling this function, a minidriver must place Data and CallBackContext in a locked, non-pageable data segment. In addition, note that the Callback is made at DISPATCH_LEVEL. The callback function must be in a locked segment and must be prepared to run at IRQL = DISPATCH_LEVEL. Note that there is an additional issue in DX8 only: EventSet must be in a locked data segment.

Minidrivers typically do not call this function directly and instead use one of the versions that performs appropriate casting: KsFilterGenerateEvents or KsPinGenerateEvents.

An event is generated if it is present in Object's event list and EventId matches the event's ID, EventSet either matches the event's set GUID or is NULL, and CallBack is either NULL or authorizes the match.

CallBack is a caller-specified callback used for additional match determination. It is prototyped as follows:

BOOLEAN CallBack (IN PVOID Context, IN PKSEVENT_ENTRY EventEntry);

Place context for the callback function in CallBackContext. The callback function should return TRUE if EventEntry should be generated. Otherwise, FALSE should be returned.

KsGenerateEvents must be called at IRQL <= DISPATCH_LEVEL.

See Also

KsAddEvent, KsFilterGenerateEvents, KsPinGenerateEvents, KSEVENT_ENTRY, Event Handling in AVStream, KS Events


KsGetDevice

The KsGetDevice function returns the AVStream device structure to which Object belongs.

PKSDEVICE
  KsGetDevice(
    IN PVOID  Object
    );

Parameters

Object
The object to query for the device to which it belongs.

Return Value

Returns the AVStream device to which Object belongs.

Headers

Declared in ks.h. Include ks.h.

Comments

Object should be one of: PKSPIN, PKSFILTER, or PKSFILTERFACTORY. Callers must perform appropriate typecasting to PVOID.

Minidrivers typically do not call this function directly. There are a number of functions that perform inline calls to KsGetDevice and that perform typecasting automatically: KsFilterFactoryGetDevice, KsFilterGetDevice, and KsPinGetDevice.

KsGetDevice must be called at IRQL = PASSIVE_LEVEL.

See Also

KSPIN, KSFILTER, KSFILTERFACTORY, KSDEVICE, KsFilterFactoryGetDevice, KsFilterGetDevice, KsPinGetDevice


KsGetDeviceForDeviceObject

The KsGetDeviceForDeviceObject function returns the AVStream device structure for a given functional device object.

PKSDEVICE
  KsGetDeviceForDeviceObject(
    IN PDEVICE_OBJECT  FunctionalDeviceObject
    );

Parameters

FunctionalDeviceObject
A pointer to the functional device object for which to return the corresponding KSDEVICE structure.

Return Value

KsGetDeviceForDeviceObject returns a pointer to the KSDEVICE structure corresponding to FunctionalDeviceObject. Returns NULL if FunctionalDeviceObject is a child PDO.

Headers

Declared in ks.h. Include ks.h.

Comments

KsGetDeviceForDeviceObject may be called at any IRQL.

See Also

KSDEVICE, DRIVER_OBJECT, DEVICE_OBJECT


KsGetFilterFromFileObject

The KsGetFilterFromFileObject function returns the AVStream filter object associated with FileObject.

PKSFILTER __inline
  KsGetFilterFromFileObject(
    IN PFILE_OBJECT  FileObject
    );

Parameters

FileObject
The file object for which to return the associated AVStream filter object.

Headers

Declared in ks.h. Include ks.h.

Comments

It is the responsibility of the minidriver to verify that FileObject is a file object associated with an AVStream filter. Do this by calling KsGetObjectTypeFromFileObject before calling KsGetFilterFromFileObject.

KsGetFilterFromFileObject is an inline call to KsGetObjectFromFileObject. The difference is that KsGetFilterFromFileObject typecasts the return to a PKSFILTER.

KsGetFilterFromFileObject may be called at any IRQL.

See Also

KsGetObjectFromFileObject, KsGetObjectTypeFromFileObject


KsGetFilterFromIrp

The KsGetFilterFromIrp function returns the AVStream filter object associated with a given IRP.

PKSFILTER
  KsGetFilterFromIrp(
    PIRP  Irp
    );

Parameters

Irp
The IRP for which to return the associated filter.

Return Value

Returns either the filter associated with the given IRP or NULL. NULL indicates that either the IRP was not associated with an AVStream object or that it was associated with a topology node. Currently, IRPs associated with topology nodes cannot be queried for their associated filter.

Headers

Declared in ks.h. Include ks.h.

Comments

If the IRP is I/O for a pin, KsGetFilterFromIrp returns the filter to which the pin belongs. If the IRP is I/O for a topology node, KsGetFilterFromIrp returns NULL.

Currently, IRPs associated with topology nodes cannot be queried for associated filters. This may change in a future revision of AVStream.

See Also

KsGetPinFromIrp, IRP


KsGetFirstChild

The KsGetFirstChild function returns the first AVStream child object of Object.

PVOID
  KsGetFirstChild(
    IN PVOID  Object
    );

Parameters

Object
The object for which to find the first AVStream child object.

Return Value

Returns the first AVStream child object of Object. If no such child object exists, returns NULL.

Headers

Declared in ks.h. Include ks.h.

Comments

See AVStream Overview for a hierarchy description of AVStream objects.

Minidrivers rarely call this function directly. Those that do must manually perform typecasts to and from PVOID. There are a number of functions that are inline calls to KsGetFirstChild and perform typecasts for you: KsDeviceGetFirstChildFilterFactory and KsFilterFactoryGetFirstChildFilter. Note that the object hierarchy is only guaranteed stable while the appropriate mutex is held, in this case the device mutex. See Mutexes in AVStream for more information.

KsGetFirstChild must be called at IRQL = PASSIVE_LEVEL.

See Also

KsGetParent, KsDeviceGetFirstChildFilterFactory, KsFilterFactoryGetFirstChildFilter, KsFilterGetFirstChildPin, Mutexes in AVStream


KsGetNextSibling

The KsGetNextSibling function returns the next sibling of a given object.

PVOID
  KsGetNextSibling(
    IN PVOID  Object
    );

Parameters

Object
The object for which to find the next sibling.

Return Value

Returns the next sibling object of Object. If no such sibling object exists, returns NULL.

Headers

Declared in ks.h. Include ks.h.

Comments

If Object is a filter factory, KsGetNextSibling returns the next filter factory belonging to the parent device, and so on. Callers must perform appropriate typecasting to and from PVOID.

The object hierarchy is only guaranteed stable while the appropriate mutex is held, in this case the device mutex. See more details in Mutexes in AVStream.

Minidrivers rarely call KsGetNextSibling directly. There are a number of functions that are inline calls to KsGetNextSibling and that perform the typecasting for you: KsFilterFactoryGetNextSiblingFilterFactory, KsFilterGetNextSiblingFilter, and KsPinGetNextSiblingPin.

KsGetNextSibling must be called at IRQL = PASSIVE_LEVEL.

See Also

KSFILTERFACTORY, KSFILTER, KSPIN, KsFilterFactoryGetNextSiblingFilterFactory, KsFilterGetNextSiblingFilter, KsPinGetNextSiblingPin, Mutexes in AVStream, AVStream Overview


KsGetNodeIdFromIrp

The KsGetNodeIdFromIrp function returns the node ID of the node to which Irp was submitted.

ULONG
  KsGetNodeIdFromIrp(
    IN PIRP  Irp
    );

Parameters

Irp
The IRP for which to determine the associated node ID. This IRP must have been sent to a file object corresponding to a filter, pin, or node.

Return Value

KsGetNodeIdFromIrp returns the ID of the node to which Irp was submitted. If Irp was instead submitted to directly to the filter, returns KSNODE_FILTER.

Headers

Declared in ks.h. Include ks.h.

Comments

KsGetNodeIdFromIrp may be called at any IRQL.

See Also

Pin Connections, IRP, KsAddIrpToCancelableQueue, KsForwardIrp, KsDispatchIrp


KsGetObjectFromFileObject

The KsGetObjectFromFileObject function returns the AVStream object cast to PVOID from FileObject.

PVOID
  KsGetObjectFromFileObject(
    IN PFILE_OBJECT  FileObject
    );

Parameters

FileObject
The file object for which to determine the associated AVStream object.

Return Value

Returns the AVStream object associated with FileObject (cast to PVOID). This may be a PKSFILTER or a PKSPIN, for example.

Headers

Declared in ks.h. Include ks.h.

Comments

KsGetObjectFromFileObject may be called at any IRQL.

See Also

KsGetObjectTypeFromFileObject, KsGetFilterFromFileObject, KsGetPinFromFileObject, KsPinGetConnectedPinFileObject


KsGetObjectTypeFromFileObject

The KsGetObjectTypeFromFileObject function returns the AVStream object type that is associated with a given file object.

KSOBJECTTYPE
  KsGetObjectTypeFromFileObject(
    IN PFILE_OBJECT  FileObject
    );

Parameters

FileObject
The file object for which to determine the associated AVStream object type.

Return Value

Returns the object type of the AVStream object associated with FileObject as a KSOBJECTTYPE enumeration. This can be one of the following: KsObjectTypeDevice, KsObjectTypeFilterFactory, KsObjectTypeFilter, or KsObjectTypePin.

Headers

Declared in ks.h. Include ks.h.

Comments

KsGetObjectTypeFromFileObject may be called at any IRQL.

See Also

KsGetObjectFromFileObject, KsGetFilterFromFileObject, KsGetPinFromFileObject, KsPinGetConnectedPinFileObject


KsGetObjectTypeFromIrp

The KsGetObjectTypeFromIrp function returns the AVStream object type that is associated with a given IRP.

KSOBJECTTYPE
  KsGetObjectTypeFromIrp(
    IN PIRP  Irp
    );

Parameters

Irp
The IRP for which to find the associated AVStream object type.

Headers

Declared in ks.h. Include ks.h.

Return Value

Returns the type of AVStream object associated with the given IRP as a KSOBJECTTYPE enumeration. This is one of the following: KsObjectTypeDevice, KsObjectTypeFilterFactory, KsObjectTypeFilter, KsObjectTypePin.

Comments

KsGetObjectTypeFromIrp may be called at any IRQL.

See Also

Pin Connections, IRP, KsAddIrpToCancelableQueue, KsForwardIrp, KsDispatchIrp


KsGetOuterUnknown

The KsGetOuterUnknown function returns the outer unknown interface of a given AVStream object.

PUNKNOWN
  KsGetOuterUnknown(
    IN PVOID  Object
    );

Parameters

Object
The AVStream object for which to return the outer unknown interface.

Return Value

Returns the outer unknown interface of Object. This can then be used to query for interfaces.

Headers

Declared in ks.h. Include ks.h.

Comments

KsGetOuterUnknown can be used to manipulate an AVStream object in a COM-like manner. Typically, minidrivers should not call this function directly; instead, use one of the inline versions that perform automatic typecasting: KsDeviceGetOuterUnknown, KsFilterFactoryGetOuterUnknown, KsFilterGetOuterUnknown, KsPinGetOuterUnknown.

Minidrivers using this function must include kcom.h and also must use a C++ compiler, because the kernel COM system for AVStream uses C++.

KsGetOuterUnknown must be called at IRQL = PASSIVE_LEVEL.

See Also

KsDeviceGetOuterUnknown, KsFilterFactoryGetOuterUnknown, KsFilterGetOuterUnknown, KsPinGetOuterUnknown, KsRegisterAggregatedClientUnknown, AVStream Overview, IksControl


KsGetParent

The KsGetParent function acquires the parent of the given object.

PVOID
  KsGetParent(
    IN PVOID  Object
    );

Parameters

Object
The AVStream object for which to find the parent. This can be a KSDEVICE, KSFILTERFACTORY, KSFILTER, or KSPIN. Callers must manually typecast the object to a PVOID.

Return Value

Returns the parent of Object as a PVOID. Callers must manually cast this return value to whatever the type of the parent of Object is.

Headers

Declared in ks.h. Include ks.h.

Comments

See the diagram in AVStream Overview for a graphical representation of AVStream parent/child relationships.

The object hierarchy is only guaranteed stable while the appropriate mutex is held, in this case the device mutex. See Mutexes in AVStream for more information.

Minidrivers rarely use this function directly. Callers of KsGetParent must manually perform typecasts to and from PVOID. There are a number of inline versions that do the casting for you: KsFilterFactoryGetParentDevice, KsFilterGetParentFilterFactory, and KsPinGetParentFilter.

KsGetParent must be called at IRQL = PASSIVE_LEVEL.

See Also

KSDEVICE, KSFILTERFACTORY, KSFILTER, KSPIN, KsFilterFactoryGetParentDevice, KsFilterGetParentFilterFactory, KsPinGetParentFilter, Mutexes in AVStream, AVStream Overview


KsGetPinFromFileObject

The KsGetPinFromFileObject function returns the AVStream pin object associated with FileObject.

PKSPIN __inline
    KsGetPinFromFileObject(
    IN PFILE_OBJECT  FileObject
    );

Parameters

FileObject
The file object for which to return the associated AVStream pin object. See note below.

Headers

Declared in ks.h. Include ks.h.

Comments

The minidriver must verify that FileObject is a file object associated with an AVStream pin. Do this by calling KsGetObjectTypeFromFileObject.

This call is an inline call to KsGetObjectFromFileObject. KsGetPinFromFileObject typecasts the return as a PKSPIN.

KsGetPinFromFileObject may be called at any IRQL.

See Also

KsGetObjectFromFileObject, KsGetObjectTypeFromFileObject


KsGetPinFromIrp

The KsGetPinFromIrp function returns the AVStream pin object associated with the given IRP.

PKSPIN
  KsGetPinFromIrp(
    IN PIRP  Irp
    );

Parameters

Irp
The IRP for which to return the associated pin.

Return Value

Returns the pin associated with the given IRP or NULL. NULL indicates that either the IRP is not associated with an AVStream object or that it is associated with a filter or a topology node.

Headers

Declared in ks.h. Include ks.h.

Comments

Currently, IRPs associated with topology nodes cannot be queried for associated pins. This may change in a future revision of AVStream.

KsGetPinFromIrp may be called at any IRQL.

See Also

KsGetFilterFromIrp, KsGetNodeIdFromIrp, KsAcquireControl, KsReleaseControl, KsFilterAcquireControl, KsFilterReleaseControl,


KsInitializeDevice

The KsInitializeDevice function is called by AVStream to initialize the AVStream device class from within KsCreateDevice.

NTSTATUS
  KsInitializeDevice (
    IN PDEVICE_OBJECT  FunctionalDeviceObject,
    IN PDEVICE_OBJECT  PhysicalDeviceObject,
    IN PDEVICE_OBJECT  NextDeviceObject,
    IN const KSDEVICE_DESCRIPTOR*  Descriptor /* optional */
    );

Parameters

FunctionalDeviceObject
Pointer to the WDM functional device object for the device being initialized.

Normally, this is returned from an IoCreateDevice call. Minidrivers calling this function directly are responsible for calling IoCreateDevice and attaching themselves to the device stack.

PhysicalDeviceObject
Pointer to the WDM physical device object for the device being initialized.
NextDeviceObject
Pointer to the next device object in the device stack as determined by a call to IoAttachDeviceToDeviceStack.
Descriptor
Pointer to a device descriptor that describes the characteristics of the device being initialized. If this parameter is NULL, the device is initialized with the default characteristics and has no associated filter factories.

Return Value

Returns STATUS_SUCCESS indicating that the device was successfully initialized. Otherwise, returns an appropriate error code.

Headers

Declared in ks.h. Include ks.h.

Comments

Most minidrivers do not call this routine directly. Only call KsInitializeDevice if your minidriver does not use KsInitializeDriver for initialization, handles AddDevice independently, and does not use KsAddDevice or KsCreateDevice in its AddDevice handler.

KsInitializeDevice must be called at IRQL = PASSIVE_LEVEL.

See Also

KsInitializeDriver, KsAddDevice, KsCreateDevice, KsTerminateDevice, KSDEVICE, IoCreateDevice, IoAttachDeviceToDeviceStack, DRIVER_OBJECT, DEVICE_OBJECT


KsInitializeDriver

The KsInitializeDriver function initializes the driver object of an AVStream minidriver.

NTSTATUS
  KsInitializeDriver(
    IN PDRIVER_OBJECT  DriverObject,
    IN PUNICODE_STRING  RegistryPath,
    IN const KSDEVICE_DESCRIPTOR  *Descriptor/* optional */
    );

Parameters

DriverObject
Pointer to the driver object for the AVStream driver being initialized. Minidrivers that call KsInitializeDriver should use the driver object passed to DriverEntry by the operating system.
RegistryPath
Pointer to the registry path string passed into the minidriver's DriverEntry function by the operating system.
Descriptor
Pointer to a KSDEVICE_DESCRIPTOR structure that specifies the characteristics of the device being initialized.

Return Value

Returns STATUS_SUCCESS or an appropriate error code as returned by IoCreateDevice or internal AVStream device initialization routines.

Headers

Declared in ks.h. Include ks.h.

Comments

This function is typically called from DriverEntry. If the minidriver passes in a device descriptor, AVStream creates a device with the specified characteristics at AddDevice time. Minidrivers that perform device initialization themselves do not necessarily need to call KsInitializeDriver.

KsInitializeDriver must be called at IRQL = PASSIVE_LEVEL.

See Also

KSDEVICE_DISPATCH, KSFILTER_DESCRIPTOR, KsInitializeDevice, KSDEVICE_DESCRIPTOR, IoCreateDevice, DriverEntry of AVStream, Initializing an AVStream Minidriver, DRIVER_OBJECT, DEVICE_OBJECT


KsMergeAutomationTables

The KsMergeAutomationTables function merges two automation tables.

NTSTATUS
  KsMergeAutomationTables(
    OUT PKSAUTOMATION_TABLE  *AutomationTableAB,
    IN PKSAUTOMATION_TABLE  AutomationTableA, /* optional */
    IN PKSAUTOMATION_TABLE  AutomationTableB, /* optional */
    IN KSOBJECT_BAG  Bag /* optional */
    );

Parameters

AutomationTableAB
Pointer to a KSAUTOMATION_TABLE where the address of the resulting merged automation table is placed.
AutomationTableA
The first of the two automation tables to merge. This table is the dominant table with respect to duplicate entries.
AutomationTableB
The second of the two automation tables to merge.
Bag
The newly created automation table is placed in this KSOBJECT_BAG (equivalent to type PVOID) for later clean up. This parameter is optional.

Return Value

Returns STATUS_SUCCESS if the merge successfully completes. If unsuccessful, returns an error code. The most frequent error code is STATUS_INSUFFICIENT_RESOURCES, which indicates that there are insufficient system resources to complete the merge.

Headers

Declared in ks.h. Include ks.h.

Comments

For more information, see Object Bags.

AutomationTableA is the dominant table in the merge. If there is an entry that appears in both AutomationTableA and AutomationTableB, the entry in AutomationTableA is the one that is placed into the merged table. The newly created automation table is placed in the requested object bag if one is provided. The old automation tables are not modified by this call. If the caller wants to delete them or remove them from a bag, the caller must do this independently. See Object Bags for more information on the AVStream construct.

If Bag parameter is not NULL, the minidriver should take the mutex associated with the object bag. If the bag is associated with a pin or a filter, then the control mutex must be held. If the bag is associated with a filter factory or a device, then the device mutex should be held. See Mutexes in AVStream.

KsMergeAutomationTables must be called at IRQL = PASSIVE_LEVEL.

See Also

Mutexes in AVStream, Object Bags, , Defining Automation Tables, KsRemoveItemFromObjectBag, KsAddItemToObjectBag, KsCopyObjectBagItems


KsPinAcquireControl

The KsPinAcquireControl function acquires the control mutex for the AVStream pin specified by Pin.

VOID __inline
  KsPinAcquireControl(
    IN PKSPIN  Pin
    );

Parameters

Pin
Pointer to the KSPIN for which to acquire the control mutex.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

The pin control mutex is the same mutex that is used by Pin's parent. This means that the mutex for Pin is also a filter control mutex. See Mutexes in AVStream for more mutex-related information.

KsPinAcquireControl is an inline call to KsAcquireControl with the appropriate typecasting. Minidrivers manipulating pins should call KsPinAcquireControl instead of calling KsAcquireControl directly.

KsPinAcquireControl must be called at IRQL = PASSIVE_LEVEL.

See Also

KsAcquireControl, KsPinReleaseControl, KsReleaseControl, KSPIN, Mutexes in AVStream


KsPinAcquireProcessingMutex

The KsPinAcquireProcessingMutex function acquires the processing mutex for the AVStream pin specified by Pin.

VOID
  KsPinAcquireProcessingMutex(
    IN PKSPIN  Pin
    );

Parameters

Pin
Pointer to the AVStream pin object for which to acquire the processing mutex.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

See more information on mutexes in Mutexes in AVStream.

KsPinAcquireProcessingMutex must be called at IRQL = PASSIVE_LEVEL.

See Also

KsPinReleaseProcessingMutex, Mutexes in AVStream, KsReleaseControl, KsPinAcquireControl, KsPinReleaseControl


KsPinAddEvent

The KsPinAddEvent function adds a specified event to Pin's event list.

VOID __inline
  KsPinAddEvent(
    IN PKSPIN  Pin,
    IN PKSEVENT_ENTRY  EventEntry
    );

Parameters

Pin
The pin to which to add a specified event.
EventEntry
Pointer to an event entry structure describing the event to add to Pin.

Headers

Declared in ks.h. Include ks.h.

Comments

This function is an inline function call to KsAddEvent.

KsPinAddEvent must be called at IRQL = PASSIVE_LEVEL.

See Also

KsAddEvent, KsGenerateEvents, KSEVENT_ENTRY, KsDefaultAddEventHandler, KsGenerateEvents,KsFilterGenerateEvents, KsPinGenerateEvents


KsPinAttachAndGate

The KsPinAttachAndGate function connects Pin as an input to a previously initialized AND gate, and connects AndGate as an input to the relevant filter's AND gate.

VOID
  KsPinAttachAndGate(
    IN PKSPIN Pin,
    IN PKSGATE AndGate OPTIONAL
    );

Parameters

Pin
The pin to use an input to the AND gate.
AndGate
The previously initialized AND gate to connect to the relevant filter's AND gate.

Headers

Declared in ks.h. Include ks.h.

Comments

To insert the gate, first call KsGateInitializeAnd. Then call KsPinAttachAndGate. For more information, see Flow Control Gates in AVStream.

KsPinAttachAndGate must be called at IRQL = PASSIVE_LEVEL before the pin in question leaves KSSTATE STOP.

See Also

KsPinAttachOrGate, KsGateInitializeAnd, Flow Control Gates in AVStream, KSGATE


KsPinAttachOrGate

The KsPinAttachOrGate function connects Pin as an input to a previously initialized OR gate, and connects OrGate as an input to the relevant filter's AND gate.

VOID
  KsPinAttachOrGate(
    IN PKSPIN Pin,
    IN PKSGATE OrGate OPTIONAL
    );

Parameters

Pin
The pin to use an input to the OR gate.
OrGate
The previously initialized OR gate to connect to the relevant filter's AND gate.

Headers

Declared in ks.h. Include ks.h.

Comments

To insert the gate, first call KsGateInitializeOr. Then call KsPinAttachOrGate.

Do not leave an unattached OR gate at filter creation time. Instead, create the OR gate later, for example when the minidriver instantiates the pin.

KsPinAttachOrGate must be called at IRQL = PASSIVE_LEVEL before the pin in question leaves KSSTATE STOP.

See Also

KsPinAttachAndGate, KsGateInitializeOr, Flow Control Gates in AVStream, KSGATE


KsPinAttemptProcessing

The KsPinAttemptProcessing function is used to resume processing on a specific pin on a pin-centric filter. It attempts to initiate processing on Pin by sending a processing dispatch call to Pin's processing object.

VOID
  KsPinAttemptProcessing(
    IN PKSPIN  Pin,
    IN BOOLEAN  Asynchronous
    );

Parameters

Pin
Pointer to the AVStream pin object on which to attempt processing.
Asynchronous
Indicates the minidriver's preference whether the processing should occur synchronously or asynchronously. If TRUE, processing is always asynchronous. However, synchronous processing only happens under certain circumstances. For more information, see the Comments section below.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

A minidriver may need to call KsPinAttemptProcessing to resume processing in various situations. For example, if the client has shut off the processing control gate with KsGateTurnInputOff, call this function when ready to attempt processing. Note that this only causes a processing dispatch if the process control gate is in the open state. Another situation involves the minidriver having previously returning STATUS_PENDING to a processing dispatch. For more details, see Processing Commonality.

The processing dispatch occurs either synchronously or asynchronously, and only if the processing control gate is open. The Asynchronous flag specifies the minidriver's preference. If the minidriver requests an asynchronous process dispatch, the dispatch is always asynchronous. However, a synchronous dispatch only occurs if the system is currently at IRQL less than the maximum processing IRQL. In other words, if the minidriver does not specify dispatch level processing and the call is made at IRQL = DISPATCH_LEVEL, then the call occurs in an asynchronous work item at PASSIVE_LEVEL.

KsPinAttemptProcessing must be called at IRQL <= DISPATCH_LEVEL.

See Also

KSGATE, KsFilterAttemptProcessing, Flow Control Gates in AVStream, KSGATE, Filter-Centric Processing, Pin-Centric Processing, Processing Commonality, KSFILTER_DISPATCH, KsGateCaptureThreshold and other KsGate* functions


KsPinGenerateEvents

The KsPinGenerateEvents function generates events of an indicated type that are present in Pin's event list.

VOID __inline
  KsPinGenerateEvents(
    IN PKSPIN  Pin,
    IN const GUID*  EventSet, /* optional */
    IN ULONG  EventId,
    IN ULONG  DataSize,
    IN PVOID  Data, /* optional */
    IN PFNKSGENERATEEVENTCALLBACK  CallBack, /* optional */
    IN PVOID  CallBackContext /* optional */
    );

Parameters

Pin
The pin on which to generate events.
EventSet
The event set GUID to match to determine which events to generate. If this parameter is NULL, set GUID is not taken into account for determining matching events.
EventId
The event ID to match to determine which events to generate.
DataSize
The size of the data with which to generate the data event.
Data
The data with which to generate the data event.
CallBack
Pointer to a caller-specified function that is called to determine whether a given event should be generated. If this is NULL, no callback verification is performed to determine whether or not an event should be generated (only EventSet and EventId are used).
CallBackContext
Pointer to a caller-specified context that is passed to the callback function CallBack.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

When calling this function, a minidriver must place Data and CallBackContext in a locked, non-pageable data segment. The Callback is made at DISPATCH_LEVEL. The callback function must be in a locked segment and must be prepared to run at IRQL = DISPATCH_LEVEL. Note that there is an additional issue in DX8 only: EventSet must be in a locked data segment.

This is an inline function call to KsGenerateEvents, which performs the necessary typecasting. Minidrivers should usually call this version instead of directly calling KsGenerateEvents.

An event is generated if:

  • The event is present in Pin's event list and EventId matches the event's ID
  • EventSet either matches the event's set GUID or is NULL, and
  • CallBack is either NULL or authorizes the match.

CallBack is a caller-specified callback used for additional match determination. It is prototyped as follows:

BOOLEAN CallBack (IN PVOID Context, IN PKSEVENT_ENTRY EventEntry);

Place context for the callback function in CallBackContext. The callback function returns TRUE if EventEntry should be generated. Otherwise, it returns FALSE.

KsPinGenerateEvents must be called at IRQL <= DISPATCH_LEVEL.

See Also

KsAddEvent, KsGenerateEvents, KsFilterGenerateEvents, KSEVENT_ENTRY, Event Handling in AVStream, KS Events


KsPinGetAndGate

The KsPinGetAndGate function returns the processing control gate for Pin.

PKSGATE
  KsPinGetAndGate(
    IN PKSPIN  Pin
    );

Parameters

Pin
The pin for which to return the processing control gate.

Headers

Declared in ks.h. Include ks.h.

Return Value

Returns the processing control gate for Pin.

Comments

See more information in Flow Control Gates in AVStream.

KsPinGetAndGate may be called at any IRQL.

See Also

Flow Control Gates in AVStream, KsFilterGetAndGate, KSGATE


KsPinGetConnectedFilterInterface

The KsPinGetConnectedFilterInterface function queries the filter to which Pin is connected in order to obtain a pointer to a COM-style interface.

NTSTATUS
  KsPinGetConnectedFilterInterface(
    IN PKSPIN  Pin,
    IN const GUID*  InterfaceId,
    OUT PVOID*  Interface
    );

Parameters

Pin
The filter to which the connected pin of Pin is attached is queried for the requested interface.
InterfaceId
Pointer to a GUID representing the interface ID for the interface to obtain. A QueryInterface call is automatically performed for this interface.
Interface
As is done in COM, the resulting interface pointer is deposited into *Interface. This interface has a corresponding reference count and must be released by the caller as in COM.

Return Value

Returns STATUS_SUCCESS if the interface exists on the connected filter or in the AVStream thunk. If STATUS_SUCCESS is returned, the interface pointer is deposited into *Interface. Otherwise, returns STATUS_NOINTERFACE. Note that this corresponds to the COM HRESULT E_NOINTERFACE.

Headers

Declared in ks.h. Include ks.h.

Comments

By default, objects support the IUnknown interface and the IKsControl interface. If the respective filter and connected pin are AVStream objects, the query and the returned interface pointer are direct calls to the other driver. If, on the other hand, the connected pin and filter do not belong to an AVStream driver, a thunk is created that provides IKsControl support through synchronous calls to the driver containing the filter, through IoCallDriver.

The most common usage of KsPinGetConnectedFilterInterface is to acquire the control interface for the filter to which Pin attaches. This control interface can then be used for property, method, or event calls down to the connected pin, or can query for interfaces that have been aggregated onto the connected filter. If the connected filter is an AVStream filter; AVStream only provides thunking for IKsControl and IUnknown for non AVStream filters).

KsPinGetConnectedFilterInterface must be called at IRQL = PASSIVE_LEVEL.

The "thunk" is only created if Pin is a source pin; thus, the calls only work if one or more of the following is true:

  • The connection is intra-AVStream (Pin's connected pin is an AVStream pin).
  • Pin is a source pin.

Otherwise, STATUS_UNSUCCESSFUL is returned.

See Also

KsPinGetConnectedPinInterface, KsPinGetReferenceClockInterface, KsGetOuterUnknown, IKsControl, IKsReferenceClock, KsFilterGetOuterUnknown, KsRegisterAggregatedClientUnknown


KsPinGetConnectedPinDeviceObject

The KsPinGetConnectedPinDeviceObject function returns the device object at the top of the device stack corresponding to the sink pin attached to the source pin Pin.

PDEVICE_OBJECT
  KsPinGetConnectedPinDeviceObject(
    IN PKSPIN Pin,
    )

Parameters

Pin
The source pin for which to obtain the connected sink pin's device object.

Return Value

If Pin is a source pin, returns the device object at the top of the device stack on which the sink pin resides. Otherwise, returns NULL.

Headers

Declared in ks.h. Include ks.h.

Comments

The returned device object is not necessarily the functional device object (FDO) for the device on which the sink resides, since there might exist an upper level filter driver. It is, however, the device object to which IOCTLs destined for the sink pin are sent.

KsPinGetConnectedPinDeviceObject only returns the connected pin's device object if Pin is a source pin. Otherwise, the function returns NULL.

See Also

KsGetDeviceForDeviceObject


KsPinGetConnectedPinFileObject

The KsPinGetConnectedPinFileObject function returns the file object for the pin to which Pin is connected. Works only for source pins.

PFILE_OBJECT
  KsPinGetConnectedPinFileObject(
    IN PKSPIN  Pin
    );

Parameters

Pin
Pointer to the AVStream pin object for which to acquire the file object for the connected pin.

Return Value

Returns the file object for the pin to which Pin is connected.

Headers

Declared in ks.h. Include ks.h.

Comments

This call only works if Pin is a source pin. If Pin is not a source pin, KsPinGetConnectedPinFileObject returns NULL.

KsPinGetConnectedPinFileObject must be called at IRQL = PASSIVE_LEVEL.

See Also

KsPinGetConnectedPinInterface, KsPinGetConnectedFilterInterface


KsPinGetConnectedPinInterface

The KsPinGetConnectedPinInterface function queries the pin to which Pin is connected for a COM style interface.

NTSTATUS
  KsPinGetConnectedPinInterface(
    IN PKSPIN  Pin,
    IN const GUID*  InterfaceId,
    OUT PVOID*  Interface
  );

Parameters

Pin
The pin connected to Pin is queried for the requested interface.
InterfaceId
Pointer to the GUID of interface ID for the interface to be obtained. A QueryInterface call is automatically performed for this interface.
Interface
As is done in COM, the resulting interface pointer is deposited into *Interface. This interface has a corresponding reference count and must be released by the caller as in COM.

Return Value

Returns STATUS_SUCCESS if the interface exists on the connected pin or in the AVStream thunk. If STATUS_SUCCESS is returned, the interface pointer is deposited into *Interface. Otherwise, returns STATUS_NOINTERFACE. This corresponds to the COM HRESULT E_NOINTERFACE.

Headers

Declared in ks.h. Include ks.h.

Comments

By default, objects support the IUnknown interface and the IKsControl interface. If the connected pin is an AVStream pin, the query and the returned interface pointer are direct calls to the other driver. If, on the other hand, the connected pin does not belong to an AVStream driver, a thunk is created that provides IKsControl support through synchronous calls to the driver containing the connected pin, using IoCallDriver.

The most common usage of KsPinGetConnectedPinInterface is to acquire the control interface for the connected pin. This control interface can be used for property, method, or event calls down to the connected pin or can query for interfaces that have been aggregated onto the connected pin. If the connected pin is an AVStream pin; AVStream only provides thunking for IKsControl and IUnknown for non AVStream pins.

KsPinGetConnectedPinInterface must be called at IRQL = PASSIVE_LEVEL.

The "thunk" is only created if Pin is a source pin; thus, the calls only work if one or more of the following is true:

  • The connection is intra-AVStream (Pin's connected pin is an AVStream pin).
  • Pin is a source pin.

Otherwise, STATUS_UNSUCCESSFUL is returned.

See Also

KsPinGetConnectedFilterInterface, KsPinGetReferenceClockInterface, KsGetOuterUnknown, IKsControl, IKsReferenceClock, KsFilterGetOuterUnknown, KsRegisterAggregatedClientUnknown


KsPinGetCopyRelationships

The KsPinGetCopyRelationships function allows a pin-centric splitter to obtain copy relationship information about a specific pin.

VOID
  KsPinGetCopyRelationships(
    IN PKSPIN Pin,
    OUT PKSPIN* CopySource
    OUT PKSPIN* DelegateBranch
    )

Parameters

Pin
Pointer to the pin about which to acquire copy information.
CopySource
AVStream places a pointer here to the pin that is the copy source for Pin. If Pin is the copy source, AVStream sets to NULL.
DelegateBranch
AVStream places a pointer here to the pin from which Pin receives delegated frames. If Pin is the delegator, AVStream sets to NULL.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

KsPinGetCopyRelationships returns copy source pin and delegate branch pin information. The information returned corresponds to the CopySource and DelegateBranch fields of a KSPROCESSPIN passed into the processing dispatch of a filter-centric filter, with the sole difference that it returns PKSPIN and not PKSPROCESSPIN. See AVStream Splitters for more on these fields.

All pins operate independently in the context of a pin-centric filter. As a result, a minidriver that calls KsPinGetCopyRelationships is responsible for ensuring that the appropriate synchronization is performed before call-time. To guarantee safety when calling KsPinGetCopyRelationships, either obtain the control mutex (do not use this mechanism in a processing dispatch) or make sure that the pin does not transition below KSSTATE_PAUSE while calling or using the information obtained. For more information on mutexes, see Mutexes in AVStream.

For more information, see Pin-Centric Processing and Filter-Centric Processing.

See Also

KSPIN_DESCRIPTOR_EX, KSPROCESSPIN


KsPinGetDevice

The KsPinGetDevice function returns the AVStream device to which Pin belongs.

PKSDEVICE
  KsPinGetDevice(
    IN PKSPIN  Pin
    );

Parameters

Pin
The pin for which to return the owning AVStream device.

Return Value

Returns the AVStream device to which Pin belongs.

Headers

Declared in ks.h. Include ks.h.

Comments

This call is an inline function call to KsGetDevice.

KsPinGetDevice must be called at IRQL = PASSIVE_LEVEL.

See Also

KSPIN, KSDEVICE, KsGetDevice, KSDEVICE_DESCRIPTOR


KsPinGetFirstCloneStreamPointer

The KsPinGetFirstCloneStreamPointer function returns the first cloned stream pointer on Pin.

PKSSTREAM_POINTER
  KsPinGetFirstCloneStreamPointer(
    IN PKSPIN  Pin
    );

Parameters

Pin
The pin on which to return the first clone stream pointer.

Return Value

Returns either the first cloned stream pointer on Pin or NULL, indicating that no clone stream pointers exist for Pin.

Headers

Declared in ks.h. Include ks.h.

Comments

KsPinGetFirstCloneStreamPointer, along with KsStreamPointerGetNextClone can be used to enumerate all clone stream pointers on a given pin in the order in which they were cloned. For more information, see the sections AVStream Queues and Stream Pointers.

KsPinGetFirstCloneStreamPointer must be called at IRQL <= DISPATCH_LEVEL.

See Also

KsStreamPointerGetNextClone, KsStreamPointerClone, KSSTREAM_POINTER,


KsPinGetLeadingEdgeStreamPointer

The KsPinGetLeadingEdgeStreamPointer function acquires the leading edge stream pointer for the queue associated with the given pin.

PKSSTREAM_POINTER
  KsPinGetLeadingEdgeStreamPointer(
    IN PKSPIN  Pin,
    IN KSSTREAM_POINTER_STATE  State
    );

Parameters

Pin
Pointer to the pin for the queue of which to acquire the leading edge stream pointer.
State
Specifies how to acquire the leading edge stream pointer. Can be one of the following:
KSSTREAM_POINTER_STATE_UNLOCKED
Acquire the leading edge stream pointer regardless of whether it references a data frame or not.

No attempts can be made to access any data associated with the pointer until the pointer is locked. Also note that frames associated with an unlocked stream pointer can be cancelled.

KSSTREAM_POINTER_STATE_LOCKED
Acquire and lock the leading edge stream pointer. If no data frame is associated with the stream pointer, return NULL. If a non-null pointer is returned, it is a locked stream pointer and has a data frame associated with it. Frames associated with a locked stream pointer cannot be cancelled.

Return Value

Returns the leading edge stream pointer or NULL. A return value of NULL may occur because there is no queue associated with the pin, indicating that the pin does not use the standard transport mechanism. Alternatively, a return value of NULL may occur because an attempt to lock the leading edge failed, indicating that there is no data frame associated with the leading edge.

Headers

Declared in ks.h. Include ks.h.

Comments

Filters that implement pin-centric processing often calls KsPinGetLeadingEdgeStreamPointer.

KsPinGetLeadingEdgeStreamPointer must be called at IRQL <= DISPATCH_LEVEL.

See Also

KsStreamPointerLock, KsStreamPointerUnlock, KsStreamPointerAdvance, KsStreamPointerAdvanceOffsetsAndUnlock, KsStreamPointerClone, KsStreamPointerDelete, KsPinGetTrailingEdgeStreamPointer


KsPinGetNextSiblingPin

The KsPinGetNextSiblingPin function returns the next instantiated pin of the same type and on the same filter as Pin.

PKSPIN
  KsPinGetNextSiblingPin(
    IN PKSPIN  Pin
    );

Parameters

Pin
The pin for which to find the next instantiated sibling pin.

Return Value

Returns the next instantiated sibling pin of Pin. If no such pin exists, returns NULL.

Headers

Declared in ks.h. Include ks.h.

Comments

KsPinGetNextSiblingPin is an inline function call to KsGetNextSibling. Note that the object hierarchy is only stable while the appropriate mutex is held, in this case the filter control mutex. See Mutexes in AVStream for more information.

KsPinGetNextSiblingPin must be called at IRQL = PASSIVE_LEVEL.

See Also

KSPIN, KsFilterGetFirstChildPin, KsGetNextSibling, Mutexes in AVStream


KsPinGetOuterUnknown

The KsPinGetOuterUnknown function returns the outer unknown interface of the pin specified by Pin.

PUNKNOWN __inline
  KsPinGetOuterUnknown(
    IN PKSPIN  Pin
    );

Parameters

Pin
The pin for which to return the outer unknown interface.

Return Value

Returns the outer unknown interface of Pin. This can subsequently be used to query for other interfaces.

Headers

Declared in ks.h. Include ks.h.

Comments

KsPinGetOuterUnknown is an inline function call to KsGetOuterUnknown.

KsPinGetOuterUnknown must be called at IRQL = PASSIVE_LEVEL.

See Also

KsGetOuterUnknown, KsRegisterAggregatedClientUnknown, AVStream Overview, KsFilterGetOuterUnknown, IksControl, KsFilterFactoryGetOuterUnknown, KsDeviceGetOuterUnknown


KsPinGetParentFilter

The KsPinGetParentFilter function returns the parent filter of Pin.

KSFILTER
  KsPinGetParentFilter(
    IN PKSPIN  Pin
    );

Parameters

Pin
The pin for which to return the parent filter.

Return Value

Returns the parent filter of Pin.

Headers

Declared in ks.h. Include ks.h.

Comments

KsPinGetParentFilter returns the filter to which Pin belongs. The call is an inline function call to KsGetParent. Note that the object hierarchy is only stable while the appropriate mutex is held, in this case the filter control mutex. See AVStream Overview for more information on the object hierarchy in AVStream and Mutexes in AVStream for more information on mutexes in the AVStream environment.

KsPinGetParentFilter must be called at IRQL = PASSIVE_LEVEL.

See Also

KSFILTER, KSPIN, KsGetParent, Mutexes in AVStream, AVStream Overview


KsPinGetReferenceClockInterface

The KsPinGetReferenceClockInterface function returns a COM style interface to the reference clock associated with Pin. This interface pointer will be an IKsReferenceClock.

NTSTATUS
  KsPinGetReferenceClockInterface(
    IN PKSPIN  Pin,
    OUT PIKSREFERENCECLOCK*  Interface
    );

Parameters

Pin
The AVStream pin object for which to return the reference clock interface.
Interface
The IKsReferenceClock pointer is deposited into *Interface. Note that this is a COM style interface with an associated reference count. Minidrivers must release the interface when finished with it.

Return Value

Returns STATUS_SUCCESS and deposits the IKsReferenceClock interface into Interface if the pin implements the clock or has received notification of the master clock through the KSPROPERTY_STREAM_MASTERCLOCK property. Returns STATUS_DEVICE_NOT_READY if the pin has not yet received notification of the master clock.

Headers

Declared in ks.h. Include ks.h.

Comments

The most common time to call KsPinGetReferenceClockInterface is in a state transition to KSSTATE_ACQUIRE.

KsPinGetReferenceClockInterface must be called at IRQL = PASSIVE_LEVEL.

See Also

KsPinGetConnectedPinInterface, KsPinGetConnectedFilterInterface, KsPinSetPinClockTime, KsGetOuterUnknown, IKsControl, IKsReferenceClock, KsFilterGetOuterUnknown, KsRegisterAggregatedClientUnknown


KsPinGetTrailingEdgeStreamPointer

The KsPinGetTrailingEdgeStreamPointer function acquires the trailing edge stream pointer for the queue associated with the specified pin.

PKSSTREAM_POINTER
  KsPinGetTrailingEdgeStreamPointer(
    IN PKSPIN  Pin,
    IN KSSTREAM_POINTER_STATE  State
    );

Parameters

Pin
Pointer to the pin for whose queue to return the trailing edge stream pointer.
State
Specifies the state in which to acquire the trailing edge stream pointer.

See State in KsPinGetLeadingEdgeStreamPointer.

Return Value

Returns the trailing edge stream pointer or NULL. A return value of NULL can indicate that there is no trailing edge for the queue associated with the pin. In this case, the pin descriptor probably does not specify that the pin should have a distinct trailing edge. Alternatively, NULL can indicate that there is no queue associated with the pin. In this case, the pin in question does not use the standard transport mechanism. A return value of NULL can also indicate that an attempt to lock the trailing edge failed. In other words, there is no data frame currently associated with the leading edge.

Headers

Declared in ks.h. Include ks.h.

Comments

The trailing edge stream pointer is a special pointer into the data stream that exists if and only if the pin descriptor for the pin specifies a distinct trailing edge. If this pointer exists, it points to the oldest data in the queue unless specifically advanced by a KsStreamPointerAdvance* or a KsStreamPointerUnlock call. Older data can exist in the queue also if cloned stream pointers exist for frames older than the one pointed to by the trailing edge.

Data frames that reside in the window between the leading edge stream pointer and the trailing edge stream pointer have at least one reference count and thus will not leave the queue and be completed until they exit the window as a result of the advancement of the trailing edge. Note that frames between the leading edge and trailing edge are not locked by default and therefore can be cancelled.

KsPinGetTrailingEdgeStreamPointer is mostly of use in pin-centric filters. See Pin-Centric Processing for more information on this processing paradigm.

KsPinGetTrailingEdgeStreamPointer will not work unless the pin descriptor for the pin specifies that the queue is to have a distinct trailing edge by setting the KSPIN_FLAG_DISTINCT_TRAILING_EDGE flag.

KsPinGetTrailingEdgeStreamPointer must be called at IRQL <= DISPATCH_LEVEL.

See Also

KsPinGetLeadingEdgeStreamPointer, KsStreamPointerLock, KsStreamPointerUnlock, KsStreamPointerAdvance, KsStreamPointerAdvanceOffsetsAndUnlock, KsStreamPointerClone, KsStreamPointerDelete, Pin-Centric Processing, Filter-Centric Processing


KsPinHandshake

The KsPinHandshake function attempts a protocol handshake with a connected pin.

NTSTATUS
  KsPinHandshake(
    IN PKSPIN  Pin,
    IN PKSHANDSHAKE  In,
    OUT PKSHANDSHAKE  Out
    );

Parameters

Pin
Pointer to the pin object that is initiating the handshake. The handshake request is passed on to the pin connected to this object.
In
Pointer to the structure containing the handshake information to be passed to the connected pin. See KSHANDSHAKE.
Out
Pointer to a structure that is filled in with handshake information by the connected pin.

Return Value

Returns STATUS_SUCCESS if the connected pin is accepting the negotiated connection. Otherwise returns an appropriate error code.

Headers

Declared in ks.h. Include ks.h.

Comments

Protocol handshakes can be used to negotiate private interfaces between two pins that are both AVStream pins.

Connections between AVStream pins are performed using this type of handshake.

KsPinGetHandshake must be called at IRQL = PASSIVE_LEVEL.

See Also

KsPinGetConnectedPinInterface, KSHANDSHAKE


KsPinRegisterAggregatedClientUnknown

This inline function is a wrapper for KsRegisterAggregatedClientUnknown.

KSDDKAPI PUNKNOWN NTAPI
  KsPinRegisterAggregatedClientUnknown(
    IN PKSPIN  Pin,
    IN PUNKNOWN  ClientUnknown
    );

Parameters

Pin
The specified AVStream pin.
ClientUnknown
The client unknown object.

Return Values

Returns the newly created aggregate object.

Headers

Declared in ks.h. Include ks.h.

Comments

This inline function only performs a typecast and then calls KsRegisterAggregatedClientUnknown.

See Also

KsRegisterAggregatedClientUnknown


KsPinRegisterFrameReturnCallback

The KsPinRegisterFrameReturnCallback function registers a frame return callback with AVStream for a given pin.

VOID
  KsPinRegisterFrameReturnCallback(
    IN PKSPIN  Pin,
    IN PFNKSPINFRAMERETURN  FrameReturn
    );

Parameters

Pin
Pointer to the AVStream pin object that you want to place into injection mode by registering a frame return callback.
FrameReturn
Pointer to a function that is called when an injected frame has completed its trip around the circuit and is ready to be recycled or freed. For more information, see the Comments section below.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

The frame return callback should be prototyped as follows:

void
  FrameReturn(
    IN PKSPIN  Pin,
    IN PVOID  Data,  /* optional */
    IN ULONG  Size,  /* optional */
    IN PMDL  Mdl,  /* optional */
    IN PVOID  Context,  /* optional */
    IN NTSTATUS  Status  /* optional */
    );

The Pin pointer points to the pin on which this frame was injected. Data and Size are the data pointer and buffer size as originally specified in KsPinSubmitFrame. Mdl points to a memory descriptor list describing the injected frame as originally done by KsPinSubmitFrameMdl . The Context pointer is the minidriver-supplied context attached to the frame when the frame was injected into the circuit. Status contains a copy of Irp->IoStatus.Status for the IRP to which the requested frame was attached. If a pin has registered a frame return callback before transitioning from KSSTATE_STOP to KSSTATE_ACQUIRE, the pin is placed into injection mode. This indicates that the pin will not receive buffers and fill them, but rather manually inject data frames into the circuit using KsPinSubmitFrame or KsPinSubmitFrameMdl. When the data frame completes its travel around the circuit and returns to the pin on which it was submitted, AVStream recycles it by calling FrameReturn.

Minidrivers that call this function are directly responsible for injecting frames into the circuit; they do not receive buffers to fill and do not directly interact with the queue as do most minidrivers. Also note that the frame return callback should be registered before the kernel pipe section is created. The kernel pipe section is created when the pin transitions to KSSTATE_ACQUIRE.

KsPinRegisterFrameReturnCallback must be called at IRQL = PASSIVE_LEVEL.

See Also

KsPinSubmitFrame, KsPinSubmitFrameMdl, Frame Injection


KsPinRegisterHandshakeCallback

The KsPinRegisterHandshakeCallback function allows a pin to request a callback when AVStream receives a handshake request for the pin specifying a protocol that AVStream does not handle by default.

VOID
  KsPinRegisterHandshakeCallback(
    IN PKSPIN  Pin,
    IN PFNKSPINHANDSHAKE  Handshake

Parameters

Pin
The pin for which to register a handshake callback.
Handshake
Pointer to the function to be called when AVStream receives a protocol handshake request on Pin that it does not handle. See additional information below.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

Prototype the function as follows:

NTSTATUS Handshake (IN PIRP Irp,
    IN PKSIDENTIFIER Request,
    IN OUT PVOID Data);

The function should check the GUID in Request to determine if the pin supports the requested protocol. If so, fill in Data as a PKSHANDSHAKE structure, and return STATUS_SUCCESS. Otherwise, return STATUS_INVALID_DEVICE_REQUEST.

Pins that support private protocol connections with other AVStream pins should register a handshake callback.

Minidrivers that support private protocols between a given pin and another AVStream pin should call this routine as soon as possible to register a callback. Then if another pin requests a handshake, the minidriver can return the request.

KsPinRegisterHandshakeCallback must be called at IRQL = PASSIVE_LEVEL.

See Also

KsPinHandshake, KSHANDSHAKE, KsFilterRegisterPowerCallbacks, KsPinRegisterPowerCallbacks, KsRegisterAggregatedClientUnknown


KsPinRegisterPowerCallbacks

The KsPinRegisterPowerCallbacks function registers power management callbacks for Pin.

VOID
  KsPinRegisterPowerCallbacks(
    IN PKSPIN  Pin,
    IN PFNKSPINPOWER  Sleep, /* optional */
    IN PFNKSPINPOWER  Wake, /* optional */
    );

Parameters

Pin
The pin for which to register power callbacks. Note that the pin must actually process (be pin-centric) in order to receive power notification messages.
Sleep
Pointer to a function that handles sleep requests for the device. For more information, see the deadlock warning below in the Comments section.
Wake
Pointer to a function that handles wake requests for the device. For more information. see the deadlock warning below in the Comments section.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

Prototype the callbacks as follows:

void Sleep/Wake (IN PKSPIN Pin, IN DEVICE_POWER_STATE State);

The Sleep callback is made if Pin is a pin-centric pin and the device is going to sleep. The Wake callback is made if Pin is a pin-centric pin and the device is waking up.

Note that at least one of the callbacks must be specified when calling KsPinRegisterPowerCallbacks.

Do not attempt to obtain the filter control mutex from within either the Sleep or Wake callback. Doing so induces a risk of deadlock. For more information on mutexes, see Mutexes in AVStream.

See Also

KsFilterRegisterPowerCallbacks


KsPinReleaseControl

The KsPinReleaseControl function releases the control mutex for the AVStream pin specified by Pin.

VOID __inline
  KsPinReleaseControl(
    IN PKSPIN  Pin
    );

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

The pin control mutex is the same mutex that is used by Pin's parent. In other words, the pin control mutex is the filter control mutex of Pin's parent. See Mutexes in AVStream for more information on mutexes.

Note that this function is an inline call to KsReleaseControl. Minidrivers manipulating a pin should call this function instead of calling KsReleaseControl directly.

KsPinReleaseControl must be called at IRQL = PASSIVE_LEVEL.

See Also

KsReleaseControl, KsPinAcquireControl, KsAcquireControl, Mutexes in AVStream


KsPinReleaseProcessingMutex

The KsPinReleaseProcessingMutex function releases the processing mutex for the AVStream pin specified by Pin.

VOID
  KsPinReleaseProcessingMutex(
    IN PKSPIN  Pin
    );

Parameters

Pin
Pointer to the AVStream pin object for which to acquire the processing mutex.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

Minidrivers that must suspend processing for a long time should not use this mutex to do so. Instead, directly manipulate the processing control gate using the KsGate* functions. See links to these functions in Flow Control Gates in AVStream.

KsPinReleaseProcessingMutex must be called at IRQL = PASSIVE_LEVEL.

See Also

KsPinAcquireProcessingMutex, KSGATE, Flow Control Gates in AVStream


KsPinSetPinClockTime

The KsPinSetPinClockTime function sets the current time on the clock exposed by Pin.

VOID
  KsPinSetPinClockTime(
    IN PKSPIN  Pin,
    IN LONGLONG  Time
    );

Parameters

Pin
Pointer to the AVStream pin object for which the exposed clock is set to the time specified by Time.
Time
Specifies the time that is set on the clock exposed by Pin.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

KsPinSetPinClockTime modifies the current time returned by the clock. If an external clock is used, this function can still be used to force a resetting of the current timer when the external timer is not being used. In this case, the time provided is ignored and must be set to zero.

KsPinSetPinClockTime must be called at IRQL <= DISPATCH_LEVEL.

See Also

KsPinGetReferenceClockInterface, KsPinGetConnectedPinInterface, KsPinGetConnectedFilterInterface, KsGetOuterUnknown, IKsControl, IKsReferenceClock, KsFilterGetOuterUnknown, KsRegisterAggregatedClientUnknown


KsPinSubmitFrame

If a pin has been placed into injection mode by a call to KsPinRegisterFrameReturnCallback, the KsPinSubmitFrame function submits a frame directly into the transport circuit.

NTSTATUS
  KsPinSubmitFrame(
    IN PKSPIN  Pin,
    IN PVOID  Data, /* optional */
    IN ULONG  Size, /* optional */
    IN PKSSTREAM_HEADER  StreamHeader, /* optional */
    IN PVOID  Context, /* optional */
    );

Parameters

Pin
The pin on which to submit a frame.
Data
An optional pointer to the frame buffer. This should be NULL if and only if Size is equal to 0.
Size
The size of the frame buffer to which the Data field points. If the Data field is NULL, then this field must be set to zero.
StreamHeader
Contains an optional pointer to a stream header. The stream header is copied if this parameter is supplied.
Context
Contains an optional pointer that is passed to the frame return callback registered through a call to KsPinRegisterFrameReturnCallback.

Return Value

Returns STATUS_SUCCESS if frame submission is successful. Otherwise returns an appropriate error code.

Headers

Declared in ks.h. Include ks.h.

Comments

KsPinSubmitFrame must be called at IRQL <= DISPATCH_LEVEL.

See Also

KsPinSubmitFrameMdl, KsPinRegisterFrameReturnCallback


KsPinSubmitFrameMdl

If a pin has been placed into injection mode by a call to KsPinRegisterFrameReturnCallback, the KsPinSubmitFrameMdl functionsubmits a frame directly into the transport circuit.

KSDDKAPI NTSTATUS NTAPI
  KsPinSubmitFrameMdl(
    IN PKSPIN  Pin,
    IN PMDL  Mdl OPTIONAL,
    IN PKSSTREAM_HEADER  StreamHeader OPTIONAL,
    IN PVOID  Context OPTIONAL
    );

Parameters

Pin
The pin on which to submit a frame.
Mdl
A memory descriptor list describing the frame buffer.
StreamHeader
Contains an optional pointer to a stream header. The stream header is copied if this parameter is supplied.
Context
Contains an optional pointer that is passed to the frame return callback registered through KsPinRegisterFrameReturnCallback.

Return Value

Returns STATUS_SUCCESS if frame submission is successful. Otherwise returns an appropriate error code.

Headers

Declared in ks.h. Include ks.h.

Comments

The difference between this function and KsPinSubmitFrame is that this function will submit a frame using an Mdl rather than using a data and size argument.

KsPinSubmitFrameMdl must be called at IRQL <= DISPATCH_LEVEL.

See Also

KsPinSubmitFrame, KsPinRegisterFrameReturnCallback


KsRegisterAggregatedClientUnknown

In a manner very similar to COM, the KsRegisterAggregatedClientUnknown function aggregates two objects: the specified AVStream object and a client unknown object.

KSDDKAPI PUNKNOWN NTAPI
  KsRegisterAggregatedClientUnknown(
    IN PVOID  Object,
    IN PUNKNOWN  ClientUnknown
    );

Parameters

Object
The specified AVStream object.
ClientUnknown
The client unknown object.

Return Values

Returns the newly created aggregate object.

Headers

Declared in ks.h. Include ks.h.

Comments

The client unknown becomes the inner part of the aggregate object, and the AVStream object becomes the outer unknown. When an interface is queried that AVStream does not handle, AVStream passes the query is to the inner aggregate. If a client unknown is already aggregated on the AVStream object, AVStream releases the previously registered aggregate and uses the unknown passed to KsRegisterAggregatedClientUnknown as the new inner unknown. There are four wrappers to KsRegisterAggregatedClientUnknown that perform typecasts.

KsRegisterAggregatedClientUnknown must be called at IRQL = PASSIVE_LEVEL.

Minidrivers do not need to be running in a C++ environment to use this function.

See Also

KsDeviceRegisterAggregatedClientUnknown, KsFilterFactoryRegisterAggregatedClientUnknown, KsFilterRegisterAggregatedClientUnknown, and KsPinRegisterAggregatedClientUnknown, KsGetOuterUnknown


KsReleaseDevice

The KsReleaseDevice function releases the device mutex and exits the critical region.

VOID
  KsReleaseDevice(
    IN PKSDEVICE  Device
    );

Parameters

Device
The AVStream device of which to release synchronous control.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

KsReleaseDevice is used by a client that has finished accessing the device in a synchronous manner following a previous call to KsAcquireDevice.

For more information, see Mutexes in AVStream.

KsReleaseDevice must be called at IRQL = PASSIVE_LEVEL.

See Also

KsAcquireDevice, KSDEVICE


KsRegisterFilterWithNoKSPins

The KsRegisterFilterWithNoKSPins function registers with DirectShow filters that have no kernel streaming pins and, therefore, do not stream in kernel mode.

NTSTATUS
  KsRegisterFilterWithNoKSPins(
    IN PDEVICE_OBJECT  DeviceObject,
    IN const GUID*  InterfaceClassGUID,
    IN ULONG  PinCount,
    IN BOOL*  PinDirection,
    IN KSPIN_MEDIUM*  MediumList,
    IN GUID*  CategoryList /* optional */
    );

Parameters

DeviceObject
The device object for the device to which to register the filter.
InterfaceClassGUID
The GUID representing the class to register. For instance, this would point to KSCATEGORY_TVTUNER for a TvTuner filter.
PinCount
The count of the number of pins on the filter.
PinDirection
An array of Boolean values indicating pin direction for each pin on the filter. Output pins are TRUE; input pins are FALSE. This array must be PinCount in length.
MediumList
An array of KSPIN_MEDIUM structures defining the mediums for each pin on the filter. This array must be PinCount in length.
CategoryList
Contains an array of GUIDs defining the categories for each pin on the filter. If this parameter is present, it must be PinCount in length.

Return Value

Returns success or failure of creating the FilterData key in the registry.

Headers

Declared in ks.h. Include ks.h.

Comments

Use KsRegisterFilterWithNoKSPins to register TvTuners, Crossbars, and similar components. KsRegisterFilterWithNoKSPins creates a new registry key, FilterData, that contains the mediums, and optionally the categories, for each pin on the filter.

This function is only used to register filters that have no corresponding kernel pins. If successful, KsRegisterFilterWithNoKSPins creates a key in the registry that can be then used by DirectShow.

If writing a BDA minidriver, consider using KsFilterFactoryUpdateCacheData instead of this routine. See details on the reference page for KsFilterFactoryUpdateCacheData.

For more information, see AVStream Descriptors and Initializing an AVStream Minidriver.

KsRegisterFilterWithNoKSPins must be called at IRQL = PASSIVE_LEVEL.

See Also

KsFilterRegisterPowerCallbacks, KsFilterFactoryUpdateCacheData, DRIVER_OBJECT, DEVICE_OBJECT


KsReleaseControl

The KsReleaseControl function releases the control mutex for Object.

VOID
  KsFilterReleaseControl(
    IN PVOID  Object
    );

Parameters

Object
The object for which to release the control mutex.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

Object should be either a filter or a pin cast to PVOID.

Minidrivers typically do not call KsReleaseControl directly, but instead call KsFilterReleaseControl or KsPinReleaseControl. These versions automatically provide the necessary typecasting to PVOID.

For more information, see Mutexes in AVStream.

KsReleaseControl must be called at IRQL = PASSIVE_LEVEL.

See Also

KsAcquireControl, KsFilterAcquireControl, KsPinAcquireControl, KsFilterReleaseControl, KsPinReleaseControl


KsRemoveItemFromObjectBag

The KsRemoveItemFromObjectBag function removes an item from an object bag.

ULONG
  KsRemoveItemFromObjectBag(
    IN KSOBJECT_BAG  ObjectBag,
    IN PVOID  Item,
    IN BOOLEAN  Free
   );

Parameters

ObjectBag
The KSOBJECT_BAG (equivalent to type PVOID) from which to remove Item.
Item
The item to remove from the requested object bag. Note that Item is removed from the requested object bag only. It is not removed from any other object bags that it may be in.
Free
Indicates whether or not Item should be freed once it has been removed from the specified object bag. Only set Free if Item is not contained in any other object bag.

Return Value

Returns the number of references on Item. A return value of zero indicates that Item was not in ObjectBag at call-time.

A return value of one indicates that Item was successfully removed from ObjectBag and that it was not in any other object bag. If a free was requested in this case, AVStream frees Item using either ExFreePool or the Free method specified at KsAddItemToObjectBag call-time.

A return value above one indicates that the item is present in another object bag and that there are still references on it. In this case, AVStream removed Item from ObjectBag, but did not free it regardless of the value of Free.

Headers

Declared in ks.h. Include ks.h.

Comments

For more information, see Object Bags.

KsRemoveItemFromObjectBag frees Item only if the number of references on this item is zero and a free was requested.

For more information on object bags as an AVStream construct, see Object Bags.

Note that the mutex associated with the bag must be held. For more information, see Mutexes in AVStream.

KsRemoveItemFromObjectBag must be called at IRQL = PASSIVE_LEVEL.

See Also

KsAddItemToObjectBag, KsDiscard, KsAllocateObjectBag, KsFreeObjectBag, KsCopyObjectBagItems, KsMergeAutomationTables


KsStreamPointerAdvance

The KsStreamPointerAdvance function advances a stream pointer to the next data frame.

NTSTATUS
  KsStreamPointerAdvance(
    IN PKSSTREAM_POINTER  StreamPointer
    );

Parameters

StreamPointer
The stream pointer to advance to reference the next available data frame.

Return Value

Returns STATUS_SUCCESS to indicate a successful advancement. Returns an error code otherwise. STATUS_DEVICE_NOT_READY is the most often returned error code and often indicates that locking the stream pointer after advancement failed. In other words, StreamPointer references the last frame in the queue.

Headers

Declared in ks.h. Include ks.h.

Comments

If StreamPointer is locked at call-time, AVStream unlocks it before advancing it. Once advanced, the stream pointer is placed back into its original state (locked or unlocked) on the new frame.

An attempt to advance a stream pointer that is unlocked always succeeds and returns STATUS_SUCCESS. Since the stream pointer is not locked, there is no way to determine if the stream pointer references actual data. The minidriver must attempt a lock to determine if the newly advanced stream pointer references a data frame or not.

For more information, see the sections AVStream Queues and Stream Pointers.

KsStreamPointerAdvance must be called at IRQL <= DISPATCH_LEVEL.

See Also

KsStreamPointerLock, KsStreamPointerUnlock, KsStreamPointerAdvanceOffsets, KsStreamPointerAdvanceOffsetsAndUnlock, KSSTREAM_POINTER


KsStreamPointerAdvanceOffsets

The KsStreamPointerAdvanceOffsets function advances the offsets of StreamPointer.

NTSTATUS
  KsStreamPointerAdvanceOffsets(
    IN PKSSTREAM_POINTER  StreamPointer,
    IN ULONG  InUsed,
    IN ULONG  OutUsed,
    IN BOOLEAN  Eject
    );

Parameters

StreamPointer
The stream pointer of which to advance the offsets. StreamPointer should be in the locked state when this function is called.
InUsed
The number of bytes to advance the input pointer of this stream pointer.

(StreamPointer -> OffsetIn)

OutUsed
The number of bytes to advance the output pointer of this stream pointer

(StreamPointer -> OffsetOut)

Eject
Indicates whether the stream pointer should be advanced to the next data frame regardless of whether advancing the offsets causes the stream pointer to point to the end of a frame.

Return Value

Returns STATUS_SUCCESS on success. Returns STATUS_DEVICE_NOT_READY if either StreamPointer was not locked at call-time or thatthe stream pointer could not be locked after advancement.

Headers

Declared in ks.h. Include ks.h.

Comments

AVStream updates the in and out data pointers and other related fields by the requested values. If advancing the offsets results in zero bytes remaining in the current frame, AVStream advances the stream pointer to the next data frame and relocks it.

It is the responsibility of the minidriver to verify that StreamPointer is locked before calling KsStreamPointerAdvanceOffsets. Also, a single advancement cannot advance a stream pointer further than the beginning of the next frame in the queue. Thus, minidrivers should not attempt to advance offsets by a value greater than StreamPointer -> Offset*.Remaining.

For more information, see the sections AVStream Queues and Stream Pointers.

KsStreamPointerAdvanceOffsets must be called at IRQL <= DISPATCH_LEVEL.

See Also

KsStreamPointerLock, KsStreamPointerUnlock, KsStreamPointerAdvance, KsStreamPointerAdvanceOffsetsAndUnlock


KsStreamPointerAdvanceOffsetsAndUnlock

The KsStreamPointerAdvanceOffsetsAndUnlock function advances StreamPointer the specified number of bytes into the stream (adjusting the OffsetIn and OffsetOut fields of StreamPointer as requested) and unlocks it.

VOID
  KsStreamPointerAdvanceOffsetsAndUnlock(
    IN PKSSTREAM_POINTER  StreamPointer,
    IN ULONG  InUsed,
    IN ULONG  OutUsed,
    IN BOOLEAN  Eject
    );

Parameters

StreamPointer
The stream pointer to advance and unlock.
InUsed
Contains the number of input bytes used. AVStream advances the input offset by this number of bytes. This must be less than the total number of remaining unused bytes in the frame referenced by StreamPointer. If InUsed is equal to the remaining number of bytes in the frame referenced by StreamPointer, AVStream advances StreamPointer to the next available data frame.
OutUsed
Contains the number of output bytes used. AVStream advances the output offset by this number of bytes. This must be less than the total number of remaining unused bytes in the frame referenced by StreamPointer. If OutUsed is equal to the remaining number of bytes in the frame referenced by StreamPointer, AVStream advances StreamPointer to the next available data frame.
Eject
Indicates whether or not StreamPointer should be advanced to the next available data frame regardless of the values in InUsed and OutUsed.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

If using the specified number of bytes in the stream pointer results in zero remaining bytes to process in the current frame, AVStream advances the stream pointer to the next available frame. Minidrivers can force advancement to the next frame regardless of the number of bytes used by setting Eject.

KsStreamPointerAdvanceOffsetsAndUnlock must be called at IRQL <= DISPATCH_LEVEL.

See Also

KsStreamPointerAdvance, KsStreamPointerUnlock, KsStreamPointerLock, KsStreamPointerClone, KsStreamPointerDelete


KsStreamPointerCancelTimeout

The KsStreamPointerCancelTimeout function cancels a previously scheduled timeout callback on the specified stream pointer.

VOID
  KsStreamPointerCancelTimeout(
    IN PKSSTREAM_POINTER  StreamPointer
    );

Parameters

StreamPointer
The stream pointer for which to cancel a registered timeout callback.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

Minidrivers should use KsStreamPointerScheduleTimeout to schedule a timeout callback on a specified stream pointer.

KsStreamPointerCancelTimeout does not affect stream pointers that have no currently scheduled timeout callback.

See related information in Stream Pointers.

KsStreamPointerCancelTimeout must be called at IRQL <= DISPATCH_LEVEL.

See Also

KsStreamPointerScheduleTimeout, KsPinGetFirstCloneStreamPointer


KsStreamPointerClone

The KsStreamPointerClone function creates a clone of a given stream pointer.

NTSTATUS
  KsStreamPointerClone(
    IN PKSSTREAM_POINTER  StreamPointer,
    IN PFNKSSTREAMPOINTER  CancelCallback /* optional */,
    IN ULONG  ContextSize,
    OUT PKSSTREAM_POINTER  *CloneStreamPointer
    );

Parameters

StreamPointer
The stream pointer that is to be cloned.
CancelCallback
Specifies a function to call if the IRP to which the data frame pointed to by StreamPointer belongs is cancelled. Prototype the callback as follows:
void CancelCallback (IN PKSSTREAM_POINTER StreamPointer);

Note that the callback is called while the filter control mutex is held; thus, the callback function cannot perform any queue manipulation or call any functions that acquire the filter control mutex. Normally, this callback function is used to remove context information or send information to hardware concerning the cancellation of data.

ContextSize
Indicates how many bytes of minidriver context information the resulting clone stream pointer should have. If nonzero, the requested number of bytes are allocated immediately after the returned stream pointer, and the Context field of CloneStreamPointer points to the allocated memory.
CloneStreamPointer
Pointer to a PKSSTREAM_POINTER into which AVStream deposits the cloned stream pointer upon completion of the cloning operation.

Return Value

Returns either STATUS_SUCCESS, indicating that the cloning operation completed normally, or an appropriate error code.

Headers

Declared in ks.h. Include ks.h.

Comments

The resulting clone initially refers to the same data frame as the original stream pointer and is in the same state (locked or unlocked). Adding a clone stream pointer referencing a data frame increments the reference count on that particular frame. Note that the frame in question, and therefore the IRP to which the frame belongs, is not completed until the reference count drops to zero.

For more information, see the sections AVStream Queues and Stream Pointers.

KsStreamPointerClone must be called at IRQL <= DISPATCH_LEVEL.

See Also

KsStreamPointerDelete, KsStreamPointerLock, KsStreamPointerUnlock, KsStreamPointerAdvance, KsStreamPointerAdvanceOffsets, KsStreamPointerAdvanceOffsetsAndUnlock


KsStreamPointerDelete

The KsStreamPointerDelete function deletes a clone stream pointer, releasing a reference on the frame to which this stream pointer referred.

VOID
  KsStreamPointerDelete(
    IN PKSSTREAM_POINTER  StreamPointer
    );

Parameters

StreamPointer
The clone stream pointer to delete. Must be a clone stream pointer; cannot be the leading or trailing edge stream pointer.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

If the frame to which StreamPointer points has no other references on it after deletion, it is completed. When the last frame in a given IRP is completed, the IRP is completed.

The leading edge and trailing edge stream pointers for a given queue and pin are special stream pointers that cannot be deleted.

For more information, see the sections AVStream Queues and Stream Pointers.

KsStreamPointerDelete must be called at IRQL <= DISPATCH_LEVEL.

See Also

KsStreamPointerClone, KsPinGetLeadingEdgeStreamPointer, KsPinGetTrailingEdgeStreamPointer


KsStreamPointerGetIrp

The KsStreamPointerGetIrp function returns the IRP associated with the frame that is referenced by the given stream pointer.

PIRP
  KsStreamPointerGetIrp(
    IN PKSSTREAM_POINTER  StreamPointer,
    OUT PBOOLEAN  FirstFrameInIrp, /* optional */
    OUT PBOOLEAN  LastFrameInIrp /* optional */
    );

Parameters

StreamPointer
References the frame for which the associated IRP is returned.
FirstFrameInIrp
AVStream sets to TRUE if the frame referenced by StreamPointer is the first frame in the returned IRP and sets FALSE if not.
LastFrameInIrp
AVStream sets to TRUE if the frame referenced by the stream pointer is the last frame in the returned IRP and sets FALSE if not.

Return Value

Returns the IRP associated with the frame referenced by the given stream pointer or returns NULL. A return value of NULL indicates that the stream pointer is not locked.

Headers

Declared in ks.h. Include ks.h.

Comments

KsStreamPointerGetIrp can also be used to determine if StreamPointer references the first and/or last frame contained in the returned IRP.

StreamPointer must be locked in order for KsStreamPointerGetIrp to execute successfully. Any attempt to call this function with an unlocked stream pointer results in a NULL return value.

FirstFrameInIrp and/or LastFrameInIrp must be non-NULL at call-time in order for AVStream to fill in these values.

For more information, see the sections AVStream Queues and Stream Pointers.

KsStreamPointerGetIrp must be called at IRQL <= DISPATCH_LEVEL.

See Also

KsStreamPointerLock, KsStreamPointerGetMdl


KsStreamPointerGetMdl

The KsStreamPointerGetMdl function returns the MDL associated with the frame referenced by StreamPointer.

PMDL
  KsStreamPointerGetMdl(
    IN PKSSTREAM_POINTER  StreamPointer
    );

Parameters

StreamPointer
References the frame for which to return the associated MDL.

Return Value

Returns either a pointer to the MDL describing the frame referenced by StreamPointer or returns NULL. A NULL return value usually indicates that the given stream pointer was not locked at call-time.

Headers

Declared in ks.h. Include ks.h.

Comments

The stream pointer must be locked in order for KsStreamPointerGetMdl to execute successfully.

For more information, see the sections AVStream Queues and Stream Pointers.

KsStreamPointerGetMdl must be called at IRQL <= DISPATCH_LEVEL.

See Also

KsStreamPointerGetIrp, KsStreamPointerLock


KsStreamPointerGetNextClone

The KsStreamPointerGetNextClone function returns the clone stream pointer that was cloned immediately after the specified clone.

PKSSTREAM_POINTER
  KsStreamPointerGetNextClone(
    IN PKSSTREAM_POINTER  StreamPointer
    );

Parameters

StreamPointer
The clone stream pointer for which the clone stream pointer cloned immediately after it on the same pin is returned.

Return Value

Returns the clone stream pointer cloned immediately after StreamPointer on the same pin. Alternatively, returns NULL indicating that either StreamPointer is the last clone on the pin or that StreamPointer is not a clone. If not a clone, StreamPointer is either the leading or trailing edge stream pointer.

Headers

Declared in ks.h. Include ks.h.

Comments

The returned pointer always refers to the same pin as StreamPointer. KsStreamPointerGetNextClone, in conjunction with KsPinGetFirstCloneStreamPointer, can be used to enumerate all clone stream pointers on a given pin in the order in which they were cloned.

For more information, see the sections AVStream Queues and Stream Pointers.

KsStreamPointerGetNextClone must be called at IRQL <= DISPATCH_LEVEL.

See Also

KsPinGetFirstCloneStreamPointer, KsStreamPointerClone, KsStreamPointerDelete


KsStreamPointerLock

The KsStreamPointerLock function attempts to lock the specified stream pointer.

NTSTATUS
  KsStreamPointerLock(
    IN PKSSTREAM_POINTER  StreamPointer
    );

Parameters

StreamPointer
The stream pointer to attempt to lock.

Return Value

Returns either STATUS_SUCCESS, indicating that the stream pointer has been locked, or an appropriate error code. STATUS_DEVICE_NOT_READY is the usual error code indicating that the frame could not be locked. This error code frequently means that the frame to which StreamPointer was pointing was cancelled.

Headers

Declared in ks.h. Include ks.h.

Comments

A locked stream pointer guarantees that there is a data frame associated with the stream pointer and that this frame is not cancelled as long as the lock is maintained. The minidriver should lock a stream pointer before attempting to access the data to which the stream pointer points.

If the pin that the stream pointer references specifies that DMA scatter/gather mappings should be generated using KSPIN_FLAG_GENERATE_MAPPINGS, AVStream generates the mappings when the stream pointer is locked.

For more information, see the sections AVStream Queues and Stream Pointers.

KsStreamPointerLock must be called at IRQL <= DISPATCH_LEVEL.

See Also

KsStreamPointerUnlock


KsStreamPointerScheduleTimeout

The KsStreamPointerScheduleTimeout function registers a timeout callback with AVStream for the given stream pointer.

VOID
  KsStreamPointerScheduleTimeout(
    IN PKSSTREAM_POINTER  StreamPointer,
    IN PFNKSSTREAMPOINTER  Callback,
    IN ULONGLONG  Interval
    );

Parameters

StreamPointer
The stream pointer for which to register a timeout.
Callback
Pointer to a function that is called after the amount of time specified by Interval if StreamPointer has not already been deleted by this point. See additional information below.
Interval
Contains the interval from the current time to the time that the timeout occurs, counted in 100-nanosecond units.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

Prototype the callback function as follows:

void Callback (IN PKSSTREAM_POINTER StreamPointer);

If the stream pointer has not been deleted or the timeout cancelled before the requested time interval expires, the specified callback function is called.

It is safe to call KsStreamPointerScheduleTimeout on a stream pointer that already has a timeout scheduled. In this case, AVStream cancels the previous timeout and replaces it with the new timeout.

For more information, see the sections AVStream Queues and Stream Pointers.

KsStreamPointerScheduleTimeout must be called at IRQL <= DISPATCH_LEVEL.

See Also

KsStreamPointerCancelTimeout, KsStreamPointerDelete


KsStreamPointerSetStatusCode

The KsStreamPointerSetStatusCode function allows specification of a successful or unsuccessful error code with which to complete the given IRP.

KSDDKAPI NTSTATUS NTAPI
  KsStreamPointerSetStatusCode(
    IN PKSSTREAM_POINTER StreamPointer,
    IN NTSTATUS Status
    );

Parameters

StreamPointer
The IRP contains the frame to which this pointer points.
Status
The error code with which to complete the IRP.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

Note that the IRP contains the frame to which StreamPointer points.

For more information, see the sections AVStream Queues and Stream Pointers.

KsStreamPointerSetStatusCode must be called at IRQL <= DISPATCH_LEVEL.

See Also

KSPIN_DISPATCH


KsStreamPointerUnlock

The KsStreamPointerUnlock function unlocks a stream pointer that has previously been locked by an acquisition function (KsGet*EdgeStreamPointer) or by KsStreamPointerLock.

VOID
  KsStreamPointerUnlock(
    IN PKSSTREAM_POINTER  StreamPointer,
    IN BOOLEAN  Eject
    );

Parameters

StreamPointer
The stream pointer to unlock.
Eject
Specifies whether or not to advance StreamPointer to the next data frame.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

KsStreamPointerUnlock can also advance the stream pointer to the next data frame. See the description of Eject above.

For more information, see the sections AVStream Queues and Stream Pointers.

KsStreamPointerUnlock must be called at IRQL <= DISPATCH_LEVEL.

See Also

KsStreamPointerLock, KsStreamPointerAdvance, KsStreamPointerAdvanceOffsets, KsStreamPointerAdvanceOffsetsAndUnlock, KsPinGetLeadingEdgeStreamPointer, KsPinGetLeadingEdgeStreamPointer, KSSTREAM_POINTER, KSPIN_DESCRIPTOR_EX, KSPIN_DISPATCH


KsTerminateDevice

The KsTerminateDevice function removes an AVStream device.

VOID
  KsTerminateDevice(
    IN PDEVICE_OBJECT  DeviceObject
    );

Parameters

DeviceObject
Pointer to a device object for the device of which to remove AVStream support.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

Normally, AVStream calls KsTerminateDevice upon receipt of a PnP remove device IRP (IRP_MN_REMOVE_DEVICE). Most minidrivers do not call this function directly; however, it can be used to remove AVStream support for the device given in DeviceObject.

KsTerminateDevice must be called at IRQL = PASSIVE_LEVEL.

See Also

KsInitializeDriver, KsInitializeDevice, KsAddDevice, KsCreateDevice, KSDEVICE, DRIVER_OBJECT, DEVICE_OBJECT


AVStream Structures

This section contains reference pages for the Microsoft-supplied AVStream structures. This material is relevant only for Microsoft® Windows® XP and later operating systems used in combination with DirectX® 8.0 and later releases.


KSALLOCATOR_DISPATCH

KSALLOCATOR_DISPATCH contains the callbacks required for a pin to implement its own kernel-level allocator.

typedef struct {
  PFNKSPININITIALIZEALLOCATOR  InitializeAllocator;
  PFNKSDELETEALLOCATOR  DeleteAllocator;
  PFNKSDEFAULTALLOCATE  Allocate;
  PFNKSDEFAULTFREE  Free;
} KSALLOCATOR_DISPATCH, *PKSALLOCATOR_DISPATCH;

Members

InitializeAllocator
Pointer to a minidriver-supplied AVStrMiniInitializeAllocator callback routine.
DeleteAllocator
Pointer to a minidriver-supplied AVStrMiniDeleteAllocator callback routine.
Allocate
Pointer to a minidriver-supplied AVStrMiniAllocate callback routine.
Free
Pointer to a minidriver-supplied AVStrMiniAllocatorFreeFrame callback routine.

Headers

Declared in ks.h. Include ks.h.

Comments

This structure is available in Windows XP and later operating systems and it DirectX 8.0 and later versions.

By providing a pointer to a KSALLOCATOR_DISPATCH structure in the relevant KSPIN_DISPATCH structure, a minidriver declares that the corresponding pin is capable of performing kernel-level allocation. The allocator might or might not be used by the graph manager. Remember that memory allocated at kernel level cannot be passed to a user-mode filter.

See Also

KSPIN_DISPATCH


KSAUTOMATION_TABLE

KSAUTOMATION_TABLE defines a structure that combines tables for properties, methods, and events.

typedef struct KSAUTOMATION_TABLE_
KSAUTOMATION_TABLE, *PKSAUTOMATION_TABLE;
struct KSAUTOMATION_TABLE_ {
  ULONG  PropertySetsCount;
  ULONG  PropertyItemSize;
  const  KSPROPERTY_SET* PropertySets;
  ULONG  MethodSetsCount;
  ULONG  MethodItemSize;
  const  KSMETHOD_SET* MethodSets;
  ULONG  EventSetsCount;
  ULONG  EventItemSize;
  const KSEVENT_SET*  EventSets;
#if !defined(_WIN64)
  PVOID  Alignment;
#endif // !defined(_WIN64)
};

Members

PropertySetsCount
The number of property sets in this automation table.
PropertyItemSize
The size of the property items in this table.
PropertySets
Pointer to an array of KSPROPERTY_SET objects (PropertySetsCount in length) defining the property sets in this automation table. Each set contains a specific number of items of size PropertyItemSize.
MethodSetsCount
The number of method sets in this automation table
MethodItemSize
The size of method items in this table.
MethodSets
An array of KSMETHOD_SET objects (MethodSetsCount in length) defining the method sets in this automation table. Each set has a specific number of items in it of size MethodItemSize.
EventSetsCount
The number of event sets in this automation table.
EventItemSize
The size of event items in this table.
EventSets
An array of KSEVENT_SET objects (EventSetsCount in length) defining the event sets in this automation table. Each set has a specific number of items in it of size EventItemSize.
Alignment
Reserved for internal use by AVStream. Minidrivers should not manipulate this member.

Headers

Declared in ks.h. Include ks.h.

Comments

This structure is available in Windows XP and later operating systems and DirectX 8.0 and later versions.

Note that each object (pin, filter, topology node) should define an automation table. Most minidrivers will use the following macros:

        DEFINE_KSAUTOMATION_* (table)
        DEFINE_KSAUTOMATION_*_NULL

[with * replaced by PROPERTIES, EVENTS, or METHODS] that automatically fill in the count,

size, and sets member. For example:

        DEFINE_KSAUTOMATION_TABLE (MyAutomationTable) {
            DEFINE_KSAUTOMATION_PROPERTIES (MyPropertyTable),
            DEFINE_KSAUTOMATION_METHODS (MyMethodTable),
            DEFINE_KSAUTOMATION_EVENTS (MyEventTable)
        };


KSCLOCK_DISPATCH

KSCLOCK_DISPATCH allows a pin to expose a clock that can be chosen by the graph manager as the master clock.

typedef struct {
  PFNKSPINSETTIMER  SetTimer;
  PFNKSPINCANCELTIMER  CancelTimer;
  PFNKSPINCORRELATEDTIME  CorrelatedTime;
  PFNKSPINRESOLUTION  Resolution;
} KSCLOCK_DISPATCH, *PKSCLOCK_DISPATCH;

Members

SetTimer
Optionally contains a pointer to an alternate function to use in generating DPC timer callbacks based on a Presentation Time. If this is set, this function will be used to set timers based on deltas to the current Presentation Time in order to generate event notifications. If an alternate function is specified to set timers, a corresponding CancelTimer function must also be provided. This is set to NULL if the default KeSetTimerEx function is to be used to approximate the next notification time. This would normally be set only if a KeSetTimerEx function was being used. The function must have the same characteristics as the default function.

The function should be prototyped as follows:

  BOOLEAN SetTimer (IN PKSPIN Pin,
    IN PKTIMER Timer,
    IN LARGE_INTEGER DueTime,
    IN PKDPC Dpc);

See the documentation for KeSetTimerEx for details on implementation of this function. Any client implementation must behave in a similar manner.

CancelTimer
Optionally contains an alternate function to use in canceling outstanding timer callbacks. If an alternate function is provided to cancel timers, a corresponding SetTimer function must also be provided. This is set to NULL if the default KeCancelTimer function is to be used. The function must have the same characteristics as the default function.

The function should be prototyped as follows:

  BOOLEAN CancelTimer (IN PKSPIN Pin,
    IN PKTIMER Timer);

See the documentation for KeCancelTimer for details on the implementation of this function. Any client implementation must behave in a similar manner.

CorrelatedTime
Pointer to a function to retrieve the current clock time and a correlated system time as an atomic operation. The function should be prototyped as follows:
  LONGLONG CorrelatedTime (IN PKSPIN Pin,
    OUT PLONGLONG SystemTime);

The current clock time should be returned and the current system time should be placed in SystemTime.

Resolution
Pointer to a function to specify the resolution of the clock. This corresponds to the KS property KSPROPERTY_CLOCK_RESOLUTION. This function should report the granularity in terms of 100-nanosecond units. For more information, see the KS documentation on KSPROPERTY_CLOCK_RESOLUTION.

The function should be prototyped as follows:

    void Resolution (IN PKSPIN Pin,
        OUT PKSRESOLUTION Resolution);

Headers

Declared in ks.h. Include ks.h.

Comments

This structure is available in Windows XP and later operating systems and in DirectX 8.0 and later versions.

See Also

KSPIN_DISPATCH


KSDEVICE_DESCRIPTOR

The KSDEVICE_DESCRIPTOR structure describes the characteristics of a particular device.

typedef struct {
  const KSDEVICE_DISPATCH*  Dispatch;
  ULONG  FilterDescriptorsCount;
  const  KSFILTER_DESCRIPTOR*const* FilterDescriptors;
} KSDEVICE_DESCRIPTOR, *PKSDEVICE_DESCRIPTOR;

Members

Dispatch
Pointer to the client dispatch table for this device. This dispatch table contains client dispatch functions for PNP messages such as Add, Start, Stop, Remove. Clients are not required to supply a dispatch table unless they wish to receive callbacks for the PNP messages described in the dispatch table. Any member of the dispatch table can be NULL to indicate that the client does not wish to receive notification for that particular message. See KSDEVICE_DISPATCH for more information.
FilterDescriptorsCount
Contains the number of filter descriptors for this device that will be provided in the FilterDescriptors member. Zero is a legal value for this member; clients can create filter factories dynamically with the KsCreateFilterFactory function instead of statically describing them in the device descriptor.
FilterDescriptors
Pointer to an array of filter descriptors that describe filters creatable by this device. This member may be NULL if FilterDescriptorsCount is zero. See KSFILTER_DESCRIPTOR for more information.

Headers

Declared in ks.h. Include ks.h.

Comments

This structure is available in Windows XP and later operating systems and in DirectX 8.0 and later versions.

Most often, this structure will be used in conjunction with KsInitializeDriver in the client's DriverEntry function to initialize the device. This structure is also used to manually initialize or create devices with the KsInitializeDevice and KsCreateDevice functions.

See Also

KSDEVICE_DISPATCH, KSFILTER_DESCRIPTOR, KsInitializeDriver, KsInitializeDevice, KsCreateDevice


KSDEVICE_DISPATCH

The KSDEVICE_DISPATCH routine describes the callbacks that a client will receive regarding device creation, PnP messages, etc.

typedef struct {
  PFNKSDEVICECREATE  Add;
  PFNKSDEVICEPNPSTART  Start;
  PFNKSDEVICE  PostStart;
  PFNKSDEVICEIRP  QueryStop;
  PFNKSDEVICEIRPVOID  CancelStop;
  PFNKSDEVICEIRPVOID  Stop;
  PFNKSDEVICEIRP  QueryRemove;
  PFNKSDEVICEIRPVOID  CancelRemove;
  PFNKSDEVICEIRPVOID  Remove;
  PFNKSDEVICEQUERYCAPABILITIES  QueryCapabilities;
  PFNKSDEVICEIRPVOID  SurpriseRemoval;
  PFNKSDEVICEQUERYPOWER  QueryPower;
  PFNKSDEVICESETPOWER  SetPower;
} KSDEVICE_DISPATCH, *PKSDEVICE_DISPATCH;

Members

Add
Optional. Can be NULL. Pointer to a minidriver-supplied AVStrMiniDeviceAdd callback routine.
Start
Optional. Can be NULL. Pointer to a minidriver-supplied AVStrMiniDeviceStart callback routine.
PostStart
Optional. Can be NULL. Pointer to a minidriver-supplied AVStrMiniDevicePostStart callback routine.
QueryStop
Optional. Can be NULL. Pointer to a minidriver-supplied AVStrMiniDeviceQueryStop callback routine.
CancelStop
Optional. Can be NULL. Pointer to a minidriver-supplied AVStrMiniDeviceCancelStop callback routine.
Stop
Optional. Can be NULL. Pointer to a minidriver-supplied AVStrMiniDeviceStop callback routine.
QueryRemove
Optional. Can be NULL. Pointer to a minidriver-supplied AVStrMiniDeviceQueryRemove callback routine.
CancelRemove
Optional. Can be NULL. Pointer to a minidriver-supplied AVStrMiniDeviceCancelRemove callback routine.
Remove
Optional. Can be NULL. Pointer to a minidriver-supplied AVStrMiniDeviceRemove callback routine.
QueryCapabilities
Optional. Can be NULL. Pointer to a minidriver-supplied AVStrMiniDeviceQueryCapabilities callback routine.
SurpriseRemoval
Optional. Can be NULL. Pointer to a minidriver-supplied AVStrMiniDeviceSurpriseRemoval callback routine.
QueryPower
Optional. can be NULL. Pointer to a minidriver-supplied AVStrMiniDeviceQueryPower callback routine.
SetPower
Optional. Can be NULL. Pointer to a minidriver-supplied AVStrMiniDeviceSetPower callback routine.

Headers

Declared in ks.h. Include ks.h.

Comments

This structure is available in Windows XP and later operating systems and in DirectX 8.0 and later versions.

In describing a device with the KSDEVICE_DESCRIPTOR structure, clients will include a pointer to a dispatch table defined by this structure. Any member of this structure may be NULL indicating that the minidriver will receive no notification for that particular message.

See Also

KSDEVICE_DESCRIPTOR


KSDEVICE

The KSDEVICE structure describes a WDM functional device that is managed by AVStream.

typedef struct {
  const KSDEVICE_DESCRIPTOR*  Descriptor;
  KSOBJECT_BAG  Bag;
  PVOID  Context;
  PDEVICE_OBJECT  FunctionalDeviceObject;
  PDEVICE_OBJECT  PhysicalDeviceObject;
  PDEVICE_OBJECT  NextDeviceObject;
  BOOLEAN  Started;
  SYSTEM_POWER_STATE  SystemPowerState;
  DEVICE_POWER_STATE  DevicePowerState;
} KSDEVICE, *PKSDEVICE;

Members

Descriptor
The descriptor structure describing the characteristics of the device and the static filters supported by it. See KSDEVICE_DESCRIPTOR.
Bag
The KSOBJECT_BAG (equivalent to type PVOID) associated with the device. See Object Bags.
Context
Use this member to associate context information with the device. AVStream stores a pointer to a device extension in this member for minidrivers that allocate a device extension in AVStrMiniDeviceStar t. Memory allocated for context should be placed in the object bag using KsAddItemToObjectBag. Context is initialized to NULL at create time.
FunctionalDeviceObject
Pointer to the WDM functional device object for the device being described.
PhysicalDeviceObject
Pointer to the WDM physical device object for the device being described.
NextDeviceObject
Pointer to the next device in the driver stack as determined by IoAttachDeviceToDeviceStack.
Started
Indicates whether this particular device has been started or not. This flag is set during the processing of the IRP_MN_START_DEVICE and is reset during the processing of the IRP_MN_STOP_DEVICE. A device that is not started returns STATUS_DEVICE_NOT_READY in response to all requests to create a filter.
SystemPowerState
The current power state of the system.
DevicePowerState
The current power state of the device.

Headers

Declared in ks.h. Include ks.h.

Comments

This structure is available in Windows XP and later operating systems and in DirectX 8.0 and later versions.

Clients typically use this structure if they must implement specific PnP or Power Management behavior that is not provided by AVStream. A pointer to a KSDEVICE structure is the first parameter to all dispatch routines specified in KSDEVICE_DISPATCH, and the client is free to use the context information to attach its own context for these routines. In addition, clients may obtain a pointer to the KSDEVICE structure from a WDM device object pointer by calling KsGetDeviceForDeviceObject.

As mentioned above, Context is initialized to NULL at create time. However, descendants of this KSDEVICE structure will have their corresponding Context members set to the value of the parent object's Context member. This happens when the new object is created. See AVStream Object Hierarchy. Also see the reference pages for the possible AVStream descendant objects: KSFILTERFACTORY, KSFILTER and KSPIN.

See Also

KSDEVICE_DESCRIPTOR, Object Bags, KsAddItemToObjectBag, KsGetDeviceForDeviceObject


KSFILTERFACTORY

The KSFILTERFACTORY structure represents a filter factory.

typedef struct {
  Const KSFILTER_DESCRIPTOR*  Descriptor;
  KSOBJECT_BAG  Bag;
  PVOID  Context;
} KSFILTERFACTORY, *PKSFILTERFACTORY;

Members

Descriptor
Pointer to the descriptor structure that describes the characteristics of filters created by this factory.
Bag
The KSOBJECT_BAG (equivalent to type PVOID) associated with this filter factory. Object bags are structures used to associate dynamic memory with a specific AVStream object. Anything in the filter factory object bag will automatically be cleaned up when the filter factory is deleted. See the conceptual section on object bags for more information.
Context
A pointer that the client may use to associate context information with the filter factory. AVStream does not use this member in any way. Note that any dynamic memory associated with the filter factory should be placed in the object bag with KsAddItemToObjectBag. Context is initialized to the value of the Context member of the parent KSDEVICE at the time the factory is created. See AVStream Object Hierarchy.

Headers

Declared in ks.h. Include ks.h.

Comments

This structure is available in Windows XP and later operating systems and in DirectX 8.0 and later versions.

A filter factory explicitly represents a device's ability to instantiate a given type of filter as described by a filter descriptor.

Drivers for hardware typically use this structure to manage a particular function of the hardware that is exposed as a type of filter. Software filters generally do not need to manage the device at this level.

Filter factory objects are created in two ways. They can be created during the AddDevice processing as indicated by the device descriptor's list of filter descriptors. They can also be created explicitly by the client in a call to KsCreateFilterFactory. The client may create filter factories at any time, but this is typically done during the processing of the PnP start IRP when an evaluation of assigned resources indicates what types of filters must be exposed by the device.

For the purposes of synchronization, the lifetime of filter factories created implicitly is defined as the interval starting when the client's device create dispatch function is (or would be) called and ending after the client's device PnP remove dispatch function is (or would be) called. The lifetime of filter factories created explicitly by calling KsCreateFilterFactory starts immediately after that call returns.

See Also

KSFILTER_DESCRIPTOR, KsCreateFilterFactory, Object Bags, KsAddItemToObjectBag


KSFILTER_DESCRIPTOR

The KSFILTER_DESCRIPTOR structure describes the characteristics of a filter created by a given filter factory.

typedef struct {
  const KSFILTER_DISPATCH*  Dispatch;
  const KSAUTOMATION_TABLE*  AutomationTable;
  ULONG  Version;
  ULONG  Flags;
  const GUID*  ReferenceGuid;
  ULONG  PinDescriptorsCount;
  ULONG  PinDescriptorSize;
  const KSPIN_DESCRIPTOR_EX*  PinDescriptors;
  ULONG  CategoriesCount;
  const GUID*  Categories;
  ULONG  NodeDescriptorsCount;
  ULONG  NodeDescriptorSize;
  const KSNODE_DESCRIPTOR  NodeDescriptors;
  ULONG  ConnectionsCount;
  const KSTOPOLOGY_CONNECTION*  Connections;
  const KSCOMPONENTID*  ComponentId;
} KSFILTER_DESCRIPTOR, *PKSFILTER_DESCRIPTOR;

Members

Dispatch
Pointer to the dispatch table for this type of filter. This member is optional and need only be provided by clients that wish to receive notifications about filter creations, deletions, and so on. Drivers that are interested in the processing of data (transforms) will typically provide this dispatch table and provide a processing function. Providing a filter-processing function instead of individual pin-processing functions is what makes a driver filter-centric instead of pin-centric.
AutomationTable
Pointer to the automation table for this type of filter. The automation table is what describes the properties, methods, and events supported by this filter. This automation table will be merged with the automation table supplied by AVStream for all filters. Should the client supply a property, method, or event handler already implemented by AVStream, the client's implementation supercedes AVStream's.
Version
The version of the filter descriptor. This member should be set to KSFILTER_DESCRIPTOR_VERSION.
Flags
Flags describing the behavior of the filter. Flags can be any of the below:
Flag | Description
KSFILTER_FLAG_DISPATCH_LEVEL_PROCESSING | Indicates that the filter will to process at IRQL DISPATCH_LEVEL as opposed to PASSIVE_LEVEL. This applies to the filter process callback as described in KSFILTER_DISPATCH.
KSFILTER_FLAG_CRITICAL_PROCESSING | If asynchronous processing has been specified or if passive level processing is demanded and a process call comes in at dispatch level, processing will be done in a queued work item. This flag indicates that the work item should be placed on the critical work queue as opposed to the delayed work queue.
KSFILTER_FLAG_RECEIVE_ZERO_LENGTH_SAMPLES | Set this flag if a filter-centric filter needs to receive zero-length samples (stream headers with flags but no data). If this flag is not set, zero length samples will be passed on to downstream pins, with automatic propagation of necessary flags. Note that this is identical to default behavior in DX8 and prior. If this happens, the minidriver never recognizes these samples. Set the Terminate flag in KSPROCESSPIN to "turn off" this flag. Also see Filter-Centric Processing.
KSFILTER_FLAG_HYPERCRITICAL_PROCESSING | If asynchronous processing has been specified or if passive level processing is demanded and a process call comes in at dispatch level, processing will be done in a queued work item. This flag indicates that the work item should be placed on the hypercritical work queue as opposed to the delayed work queue or critical work queue.

ReferenceGuid
Pointer to a GUID that is the binary representation of the Unicode reference string identifying this filter type. Other methods of supplying a reference string require that the filter descriptor be registered using KsCreateFilterFactory.
PinDescriptorsCount
The number of pin descriptors that will be provided for this filter type in PinDescriptors. Because all filters must expose at least one pin, zero is an illegal value for this member.
PinDescriptorSize
The size of each individual descriptor in the descriptor table. This value must be a multiple of eight and must be at least sizeof (KSPIN_DESCRIPTOR_EX). Larger values allow client-specific descriptor information to be appended to pin descriptors.
PinDescriptors
Pointer to a table of pin descriptors that describe the pins supported by this filter type. Because all filters must expose at least one pin, zero is an illegal value for this member.
CategoriesCount
The number of category GUIDs that will be provided in Categories for this filter type. Zero is a legal value for this member.
Categories
The list of category GUIDs for this filter type. If required, a device interface is registered for each category. This member may be null if and only if CategoriesCount is zero.
NodeDescriptorsCount
The number of topology node descriptors provided in NodeDescriptors. Zero is a legal value for this member.
NodeDescriptorSize
The size of each individual descriptor in the descriptor table. This value must be a multiple of eight and at least sizeof (KSNODE_DESCRIPTOR). Larger values allow client-specific descriptor information to be appended to node descriptors.
NodeDescriptors
Pointer to a table of topology node descriptors describing the topology nodes for this filter type. This member may be null if and only if NodeDescriptorsCount is zero.
ConnectionsCount
The number of topology connections present in Connections. This member may be zero indicating that the default connection set will be used. Using default connections means that the topology of the filter will be described with a single topology node where each pin on the filter is connected to the corresponding ID on the topology node. The direction of each connection is determined by pin data flow.
Connections
Pointer to a table of topology connections present in this filter type. This member is optional; it may be NULL if and only if ConnectionsCount is zero (in which case, the default topology will be used).
ComponentId
The component ID for this filter type. This is used for the component ID property that provides identification information. This member is optional.

Headers

Declared in ks.h. Include ks.h.

Comments

This structure is available in Windows XP and later operating systems and in DirectX 8.0 and later versions.

In laying out the filter descriptor, there are a number of macros that the caller may find useful. Instead of specifying count, size, and then table for the pin descriptor table, categories table, and node descriptors table, there are a number of useful macros:

Macro | Description
DEFINE_KSFILTER_PIN_DESCRIPTORS(table) | Automatically inserts the number of items in table, the size of each item in the table, and the table of pin descriptors itself into the filter descriptor.
DEFINE_KSFILTER_CATEGORIES(table) | Automatically inserts the number of categories in the table and the table itself into the filter descriptor.
DEFINE_KSFILTER_CATEGORIES_NULL | Automatically fills in the category members for a filter that defines no categories.
DEFINE_KSFILTER_NODE_DESCRIPTORS(table) | Automatically inserts the number of items in the table, the size of each item in the table, and the table of node descriptors itself into the filter descriptor.
DEFINE_KSFILTER_NODE_DESCRIPTORS_NULL | Automatically fills in the node descriptor members for a filter that defines no topology nodes.
DEFINE_KSFILTER_CONNECTIONS(table) | Automatically inserts the number of connections in the table and the table itself into the filter descriptor.
DEFINE_KSFILTER_DEFAULT_CONNECTIONS | Automatically fills in the connections table for a filter that defines no explicit connections.

See Also

KSFILTER_DISPATCH, KSPIN_DESCRIPTOR_EX, KSNODE_DESCRIPTOR, KSTOPOLOGY_CONNECTION, KSCOMPONENT_ID, KsCreateFilterFactory


KSFILTER_DISPATCH

The KSFILTER_DISPATCH structure describes the client callbacks that will be made to notify the client of certain events on a given filter type.

typedef struct {
  PFNKSFILTERIRP  Create;
  PFNKSFILTERIRP  Close;
  PFNKSFILTERPROCESS  Process;
  PFNKSFILTERVOID  Reset;
} KSFILTER_DISPATCH, *PKSFILTER_DISPATCH;

Members

Create
Optional. Can be NULL. Pointer to a minidriver-supplied AVStrMiniFilterCreate callback routine.
Close
Optional. Can be NULL. Pointer to a minidriver-supplied AVStrMiniFilterClose callback routine.
Process
Optional. Can be NULL. Pointer to a minidriver-supplied AVStrMiniFilterProcess callback routine.
Reset
Optional. Can be NULL. Pointer to a minidriver-supplied AVStrMiniFilterReset callback routine.

Headers

Declared in ks.h. Include ks.h.

Comments

This structure is available in Windows XP and later operating systems and in DirectX 8.0 and later versions.

Any of the callback pointers may be NULL, indicating that the driver does not wish to receive notification of a given event.

See Also

KsCompletePendingRequest, Filter-Centric Processing, KSPROCESSPIN, KSPROCESSPIN_INDEXENTRY, Processing Commonality


KSFILTER

KSFILTER describes an instantiated filter.

typedef struct {
  const KSFILTER_DESCRIPTOR*  Descriptor;
  KSOBJECT_BAG  Bag;
  PVOID  Context;
} KSFILTER, *PKSFILTER;

Members

Descriptor
Pointer to the descriptor that describes the characteristics of this particular filter.
Bag
The KSOBJECT_BAG (equivalent to type PVOID) associated with this filter instance. Object bags are structures used to associate dynamic memory with a specific AVStream object. Anything in the filter object bag will automatically be cleaned up when the filter is deleted.
Context
A pointer that is used by the client to associate context information with the specific filter instance. Typically, such context information will be associated in the filter's Create dispatch as defined in the KSFILTER_DISPATCH table for this filter instance. Any dynamically allocated context information should be placed in the object bag with KsAddItemToObjectBag. Context is initialized to the value of the Context member of the parent KSFILTERFACTORY at the time the filter is created. See AVStream Object Hierarchy.

Headers

Declared in ks.h. Include ks.h.

Comments

This structure is available in Windows XP and later operating systems and in DirectX 8.0 and later versions.

Drivers implementing software filters typically associate filter state with this structure. Processing for software filters is usually done in the filter's Process dispatch function. Hardware filters typically do not use this structure because the focus of the hardware driver is the platform transition: the movement of data between the host and the external hardware. This transition is typically handled with code associated with an AVStream queue object.

For the purposes of synchronization, the lifetime of this object is the interval starting when the client's PreCreate dispatch function is called (or would be called) and ending when the client's Close dispatch function returns, assuming the function does not return STATUS_PENDING. If it does return STATUS_PENDING, the object's lifetime ends when the client indicates completion of the close request by calling KsCompletePendingRequest.

See Also

KSFILTER_DESCRIPTOR, KSFILTER_DISPATCH, KsCompletePendingRequest, Object Bags, KsAddItemToObjectBag


KSHANDSHAKE

The KSHANDSHAKE structure is used to pass information back and forth while pins are handshaking in an attempt to negotiate a private interface.

typedef struct {
  GUID  ProtocolId;
  PVOID  Argument1;
  PVOID  Argument2;
} KSHANDSHAKE, *PKSHANDSHAKE;

Members

ProtocolId
A GUID representing the interface or protocol that is being negotiated between two AVStream pins.
Argument1
An interface-dependent argument. Most often, this is used to pass back and forth COM-style interface pointers once a specific private interface or protocol has been agreed upon.
Argument2
An interface-dependent argument.

Headers

Declared in ks.h. Include ks.h.

Comments

This structure is available in Windows XP and later operating systems and in DirectX 8.0 and later versions.

See KsPinHandshake for more information about negotiating private interfaces between AVStream pins.

Pin handshaking is a concept that is usable only between two pins that support IOCTL_KS_HANDSHAKE. Currently, only AVStream pins support this interface; thus this is only useful for negotiating private interfaces between two AVStream pins. Currently, connections between AVStream pins are negotiated via this mechanism.

See Also

KsPinHandshake


KSMAPPING

The KSMAPPING structure is used to describe a single contiguous chunk of physical memory for use in scatter/gather DMA operations.

typedef struct {
  PHYSICAL_ADRESS  PhysicalAddress;
  ULONG  ByteCount;
  ULONG  Alignment;
} KSMAPPING, *PKSMAPPING;

Members

PhysicalAddress
Contains the physical address of this piece of the data frame.
ByteCount
Contains the number of bytes of contiguous physical memory in this individual mapping.
Alignment
Specifies the memory alignment of the beginning of the buffer.

Headers

Declared in ks.h. Include ks.h.

Comments

This structure is available in Windows XP and later operating systems and in DirectX 8.0 and later versions.

In order for clients to make use of this structure within the stream pointer offsets, the pin on which this is referring must specify scatter/gather DMA mapping generation through KSPIN_FLAG_GENERATE_MAPPINGS and the client must register its DMA adapter object with AVStream via KsDeviceRegisterAdapterObject. The KSPIN_FLAG_GENERATE_MAPPINGS flag is defined on the KSPIN_DESCRIPTOR_EX reference page.

See Also

KSSTREAM_POINTER_OFFSET, KsDeviceRegisterAdapterObject


KSGATE

The KSGATE structure describes an AVStream gate object.

typedef struct {
  LONG  Count;
  PKSGATE  NextGate;
} KSGATE, *PKSGATE;

Members

Count
Indicates the count on the gate. When this member is above zero, the gate is considered to be in the "open" state and allows processing. When the member is zero or below, the gate is considered to be in the "closed" state and does not allow processing. Although the KSGATE structure is the universal gate implementation in AVStream, conceptually, there are both AND and OR gates. For AND gates, Count will be one minus the number of off inputs to the gate. For OR gates, Count will be the number of on inputs for the gate. Thus, in general, this member can contain any value; however, for AND gates, it can only contain values of one or less, and for OR gates, it can only contain values of zero or greater. Clients should be careful not to specifically set the Count member to an invalid value for the given conceptual gate this structure represents.
NextGate
Pointer to the next gate in the gate chain. The output of one gate may be fed into another gate as an input and the outputting gate will pass state transitions down the gate chain. There are restrictions on this propogation using the KsGate*And and KsGate*Or functions. NextGate for an AND gate must point to an OR gate, and for an OR gate must point to an AND gate. Clients can specify state transitions manually via KsGateInitialize instead of KsGateInitializeAnd or KsGateInitializeOr.

Headers

Declared in ks.h. Include ks.h.

Comments

This structure is available in Windows XP and later operating systems and in DirectX 8.0 and later versions.

Conceptually, flow control gates are logical AND and OR gates; in AVStream, they are used as a processing-control mechanism. For more information, see Flow Control Gates in AVStream.

All of the manipulations of Count are done using interlocked functions to provide synchronous state changes. There is no distinction as to whether a given KSGATE represents an AND gate or an OR gate. Thus, clients should be careful not to transition a gate into an invalid state by using KsGate*And functions on an OR gate or KsGate*Or functions on an AND gate or by using KsGateTurnInput* functions invalidly.

See Also

KsGateInitialize , KsGateInitializeAnd, KsGateInitializeOr, KSGATE


KSNODE_DESCRIPTOR

The KSNODE_DESCRIPTOR structure describes a topology node within a filter.

typedef struct {
  const KSAUTOMATION_TABLE*  AutomationTable;
  const GUID*  Type;
  const GUID*  Name;
} KSNODE_DESCRIPTOR, *PKSNODE_DESCRIPTOR;

Members

AutomationTable
Pointer to an automation table for this topology node. The automation table contains the properties, methods, and events supported by this topology node.
Type
Pointer to a GUID defining the topology node.
Name
Pointer to a GUID that represents the name of this topology node. This is used to return information on a KSPROPERTY_TOPOLOGY_NAME query. For more information on topology nodes, see Pin Internal Topology.

Headers

Declared in ks.h. Include ks.h.

Comments

This structure is available in Windows XP and later operating systems and in DirectX 8.0 and later versions.

See Also

KSFILTER_DESCRIPTOR


KSPIN_DESCRIPTOR_EX

The KSPIN_DESCRIPTOR_EX structure describes the characteristics of a pin type on a given filter type.

typedef struct {
  Const KSPIN_DISPATCH*  Dispatch;
  Const KSAUTOMATION_TABLE*  AutomationTable;
  KSPIN_DESCRIPTOR  PinDescriptor;
  ULONG  Flags;
  ULONG  InstancesPossible;
  ULONG  InstancesNecessary;
  Const KSALLOCATOR_FRAMING_EX*  AllocatorFraming;
  PFNKSINTERSECTIONHANDLEREX  IntersectHandler;
} KSPIN_DESCRIPTOR_EX, *PKSPIN_DESCRIPTOR_EX;

Members

Dispatch
Pointer to the client dispatch table for this pin. This pointer is optional and only need be provided by clients that wish to receive notifications regarding pin creation, deletion, state changes, and so on.Clients that need to perform pin-centric processing (filters concerned with the routing of data, in other words hardware drivers) must provide this dispatch table and a process dispatch. See KSPIN_DISPATCH for more information.
AutomationTable
Pointer to the automation table for this pin. The automation table contains the properties, methods, and events supported by the pin. This automation table will be merged with the automation table provided by AVStream for all pins. If the client supplies any property, event, or method handlers that are already provided by AVStream, the clients' implementation will supercede that of AVStream.
PinDescriptor
The basic pin descriptor described in the kernel streaming documentation. See KSPIN_DESCRIPTOR for more information.
Flags
Flags specifying the behavior of the pin. This can be any combination of the following.
Flag | Description
KSPIN_FLAG_DISPATCH_LEVEL_PROCESSING | Indicates that the client wishes the process dispatch to happen at IRQL DISPATCH_LEVEL instead of PASSIVE_LEVEL
KSPIN_FLAG_CRITICAL_PROCESSING | If asynchronous processing has been specified or if passive level processing is demanded and a process call comes in at dispatch level, processing will be done in a queued work item. This flag indicates that the work item should be placed on the critical work queue as opposed to the delayed work queue.
KSPIN_FLAG_HYPERCRITICAL_PROCESSING | If asynchronous processing has been specified or if passive level processing is demanded and a process call comes in at dispatch level, processing will be done in a queued work item. This flag indicates that the work item should be placed on the hypercritical work queue as opposed to the delayed work queue or critical work queue.
KSPIN_FLAG_ASYNCHRONOUS_PROCESSING | Indicates that the pin should process data asynchronously. We will not wait for one process dispatch to be called before proceeding with additional frames.
KSPIN_FLAG_DO_NOT_INITIATE_PROCESSING | Indicates that the processing should never be initiated; the process dispatch provided in the dispatch table will never be called. This is useful for clients that intend to directly poll the queue at, for example, DPC time to transport data to hardware.
KSPIN_FLAG_INITIATE_PROCESSING_ON_EVERY_ARRIVAL | Indicates that processing should occur every time a data frame arrives into the queue. Without specifying this flag of KSPIN_FLAG_DO_NOT_INITIATE_PROCESSING, the process dispatch will only be called when data arrives into a previously empty queue.
KSPIN_FLAG_FRAMES_NOT_REQUIRED_FOR_PROCESSING | Indicates that frames are not required on this pin for processing to commence. This flag is useful only for filter-centric filters. Pins that do not specify this flag will delay processing on the filter if they do not have available frames. Pins that do specify this flag will not delay processing in this manner. If a pin specifies this flag, it becomes the responsibility of the process dispatch to check for available frames.
KSPIN_FLAG_ENFORCE_FIFO | Specifying this flag causes the queue to force IRPs to be handled in a first-in-first-out manner. If one IRP is completed by the minidriver prior to an IRP that was sent earlier, the later IRP will not be completed by AVStream until the earlier IRP has been completed by the minidriver.
KSPIN_FLAG_GENERATE_MAPPINGS | Indicates that scatter/gather mappings should be generated for devices that will use scatter/gather DMA to transport data from the pin to hardware. Clients that intend to use this feature need to register their DMA adapter object with AVStream via the KsDeviceRegisterAdapterObject function.
KSPIN_FLAG_DISTINCT_TRAILING_EDGE | Indicates that the queue associated with the pin should have a trailing edge stream pointer. The trailing edge pointer is a special stream pointer that points (usually) to the oldest data in the queue (unless clone pointers exist on older data). Any data frame sitting in the window between the leading and trailing edge stream pointers are considered to have at least one reference count on them and will not be completed until they move out of the window by advancing the trailing edge with KsPinGetTrailingEdgeStreamPointer and one of the KsStreamPointerAdvance* or KsStreamPointerUnlock functions. Pins that do not specify this flag do not have a trailing edge stream pointer.
KSPIN_FLAG_PROCESS_IN_RUN_STATE_ONLY | Indicates that this pin will only process data while in KSSTATE_RUN. Pins that specify this flag will never be called upon to process while not in KSSTATE_RUN. Further, any pin that specifies this flag and is part of a filter-centric filter will cause the filter not to process if the given pin is not in KSSTATE_RUN.
KSPIN_FLAG_SPLITTER | Indicates that this pin (an output pin) is a splitter. Pins that specify this flag should indicate a number of possible instances greater than one. When a second instance of this pin is created, AVStream will automatically set up a splitter so that frames sent to the original pin are copied to the new pin. Note that this copying is done automatically by AVStream. Clients typically can ignore process pins that have nonNULL DelegateBranch and CopySource pointers. These members indicate that the pin is part of a splitter branch and is handled automatically by AVStream. In releases post-DirectX 8.0, this flag works for pins on both filter-centric and pin-centric filters. Older releases support this flag only for pins on filter-centric filters.
KSPIN_FLAG_USE_STANDARD_TRANSPORT | This flag forces the pin to use the standard transport mechanism. It overrides all other checks (communication type, medium type, interface type, etc.) on the pin. Specifying both this flag and KSPIN_FLAG_DO_NOT_USE_STANDARD_TRANSPORT will result in the standard transport being used. This flag overrides all other checks.
KSPIN_FLAG_DO_NOT_USE_STANDARD_TRANSPORT | Indicates that the pin does not use the standard transport mechanism. Pins that do not use the standard transport mechanism will not belong to a pipe section and will not have associated queues.
KSPIN_FLAG_FIXED_FORMAT | Indicates that this pin uses a fixed data format. Any attempt to set the data format will return STATUS_INVALID_DEVICE_REQUEST.
KSPIN_FLAG_GENERATE_EOS_EVENTS
KSPIN_FLAG_RENDERER
KSPIN_FLAG_SOME_FRAMES_REQUIRED_FOR_PROCESSING When specified on a filter-centric filter pin, indicates that one or more instances of the pin type in question must have frames available in order to process data. Mutually exclusive with KSPIN_FLAG_FRAMES_NOT_REQUIRED_FOR_PROCESSING.

Note that this behavior can be obtained through KsPinAttachOrGate by manually setting up an OR gate as the frame gate for every instance of the pin and attaching this OR gate to the filter's AND gate.

When using this flag, minidrivers cannot call KsPinAttachAndGate or KsPinAttachOrGate on the associated pin instances. (The flag effectively does this for you for the simple OR case.) Also see Filter-Centric Processing.
KSPIN_FLAG_PROCESS_IF_ANY_IN_RUN_STATE | When specified on a filter-centric pin, indicates that processing may occur when one or more of the pin instances so flagged are in the run state. Note that all non-stopped pins still must be in at least pause to process data. The default behavior is to process in pause; KSPIN_FLAG_PROCESS_IN_RUN_STATE_ONLY allows this behavior to be changed to processing in run when all of the pin instances are in run. Also see Filter-Centric Processing.
KSPIN_FLAG_IMPLEMENT_CLOCK | Indicates that this pin exposes a clock that can be selected by the graph manager as a master clock.

InstancesPossible
Contains a count of the maximum number of possible instances of this pin. Any attempt to instantiate more than this number of pins of the given type will fail. Set to KSINSTANCE_INDETERMINATE to have no limit on number of pins instantiated.
InstancesNecessary
Contains a count of the number of instances of this pin type that are necessary for proper functioning of this filter. Any attempt to change the state of a filter that does not have this number of instances of this type of pin will fail.
AllocatorFraming
Specifies the allocator framing requirements for this pin type. Allocator framing specifies items such as memory alignment requirements, maximum frame size, minimum frame size, etc… This member can be NULL, which will indicate that this pin does not support the allocator framing property. See KSALLOCATOR_FRAMING_EX for more information.
IntersectHandler
Pointer to the data-intersection handler function. If this member is NULL, the pin will handle data intersection queries for data ranges with the specifier KSDATAFORMAT_SPECIFIER_NONE. The intersection handler function receives a single data range from the query and a single data range from the pins list of data ranges. The type, subtype, and specifier GUIDs of these ranges are guaranteed to match, though some may be wildcards. The function either indicates the data ranges do not match, or it produces the best data format in the intersection of the two data ranges. See Data Intersections and AVStream for more information.

Headers

Declared in ks.h. Include ks.h.

Comments

This structure is available in Windows XP and later operating systems and in DirectX 8.0 and later versions.

The remaining undocumented flags will be documented in time.

Note that under certain circumstances the allocator framing requirements of your pin may be ignored despite the fact that your allocator framing specifies that alignment or size is absolutely required to be a certain value. If your kernel-mode driver is connected to an upstream user-mode filter that allocates for it and the particular upstream filter's allocator does not understand framing requirements, this can happen (current particular examples include the MPEG-2 splitter).

Further, note that if you specify KSPIN_FLAG_DO_NOT_INITIATE_PROCESSING and the pin does use the standard transport mechanism, you must have a processing object. This means there must be some process dispatch provided (either at the filter level or at the pin level); even if this function will never be called, it must be provided in this circumstance.

See Also

KSPIN_DISPATCH, KSPIN_DESCRIPTOR, KSALLOCATOR_FRAMING_EX, Data Intersections and AVStream, KsDeviceRegisterAdapterObject, Avstream Splitters


KSPIN_DISPATCH

The KSPIN_DISPATCH structure describes the callbacks that will be made to inform the client of certain events on a pin.

typedef struct {
  PFNKSPINIRP  Create;
  PFNKSPINIRP  Close;
  PFNKSPIN  Process;
  PFNKSPINVOID  Reset;
  PFNKSPINSETDATAFORMAT  SetDataFormat;
  PFNKSPINSETDEVICESTATE  SetDeviceState;
  PFNKSPIN  Connect;
  PFNKSPINVOID  Disconnect;
  const KSCLOCK_DISPATCH*  Clock;
  const KSALLOCATOR_DISPATCH*  Allocator;
} KSPIN_DISPATCH, *PKSPIN_DISPATCH;

Members

Create
Optional. Can be NULL. Pointer to a minidriver-supplied AVStrMiniPinCreate callback routine.
Close
Optional. Can be NULL. Pointer to a minidriver-supplied AVStrMiniPinClose callback routine.
Process
Optional. Can be NULL. Pointer to a minidriver-supplied AVStrMiniPinProcess callback routine.
Reset
Optional. Can be NULL. Pointer to a minidriver-supplied AVStrMiniPinReset callback routine.
SetDataFormat
Optional. Can be NULL. Pointer to a minidriver-supplied AVStrMiniPinSetDataFormat callback routine.
SetDeviceState
Optional. Can be NULL. Pointer to a minidriver-supplied AVStrMiniPinSetDeviceState callback routine.
Connect
Optional. Can be NULL. Pointer to a minidriver-supplied AVStrMiniPinConnect callback routine.
Disconnect
Optional. Can be NULL. Pointer to a minidriver-supplied AVStrMiniPinDisconnect callback routine.
Clock
Specify this member for a pin that exposes a clock. See KSCLOCK_DISPATCH.
Allocator
Optional. Can be NULL. Specify this member for a pin that is capable of performing kernel-level allocation. See KSALLOCATOR_DISPATCH.

Headers

Declared in ks.h. Include ks.h.

Comments

This structure is available in Windows XP and later operating systems and in DirectX 8.0 and later versions.

The undocumented dispatch functions will be documented at a future time.

Any of the callback pointers can be NULL, indicating that the minidriver does not require to receive notification for this particular dispatch.

If the minidriver needs to determine whether or not it has been signaled to go to a specific state (for example KSSTATE_RUN), comparing the value of the DeviceState member of KSPIN to KSSTATE_RUN is not a reliable method of doing this. DeviceState refers to the state to which the pin has been signaled to go, not the pipe. To perform the above reliably, instead create a variable in the SetDeviceState callback of this structure and then check this variable to make the determination.

See Also

KSCLOCK_DISPATCH, KSALLOCATOR_DISPATCH, KsCompletePendingRequest, KSPIN


KSPIN

The KSPIN structure describes an instantiated pin.

typedef struct {
  const KSPIN_DESCRIPTOR_EX*  Descriptor;
  KSOBJECT_BAG  Bag;
  PVOID  Context;
  ULONG  Id;
  KSPIN_COMMUNICATION  Communication;
  BOOLEAN  ConnectionIsExternal;
  KSPIN_INTERFACE  ConnectionInterface;
  KSPIN_MEDIUM  ConnectionMedium;
  KSPRIORITY  ConnectionPriority;
  PKSDATAFORMAT  ConnectionFormat;
  PKSMULTIPLE_ITEM  AttributeList;
  ULONG  StreamHeaderSize;
  KSPIN_DATAFLOW  DataFlow;
  KSSTATE  DeviceState;
  KSRESET  ResetState;
  KSSTATE  ClientState;
} KSPIN, *PKSPIN;

Members

Descriptor
Pointer to the pin descriptor for this particular pin. See KSPIN_DESCRIPTOR_EX for more information.
Bag
The KSOBJECT_BAG (equivalent to type PVOID) for this particular pin instance. Object bags are structures used to associate dynamic memory with a specific AVStream object. Anything in the pin object bag will automatically be cleaned up when the pin is closed.
Context
This is a pointer clients can use to associate context information with a specific pin instance. Typically, this will be used for pin/stream extensions and will be allocated in the create dispatch provided in the pin dispatch table. Note that any dynamic memory allocated for context information should be placed in the pin instance's object bag via KsAddItemToObjectBag. Context is initialized to the value of the Context member of the parent KSFILTER at the time the pin is created. See AVStream Object Hierarchy.
Id
This is the pin type identifier; it is the index into the array of pin descriptors provided for the given filter type.
Communication
Indicates the type of communication used for this pin. See KSPIN_DESCRIPTOR for more information regarding this member.
ConnectionIsExternal
If this is TRUE, it indicates that the connected pin does not support the AVStream connection handshake. This is an indication of whether or not the connection between this pin and the pin it is connected to is a connection between two AVStream pins.
ConnectionInterface
The identifier for the interface being used for the connection. This information is supplied by the graph builder when the pin is created.
ConnectionMedium
The identifier for the connection medium. This information is supplied by the graph builder when the pin is created.
ConnectionPriority
The priority of the connection. This information is supplied by the graph builder when the pin is created.
ConnectionFormat
The data format of the connection. This information is initially supplied by the graph builder when the pin is created and may be changed through property access or by format change messages inserted into the stream. Access to this member is synchronized by the filter control mutex. This member should not be changed by the client.
AttributeList
The list of attributes, supplied during pin creation, that describes the connection. Specifies the direction of data flow for this pin (KSPIN_DATAFLOW_IN or KSPIN_DATAFLOW_OUT). This information is a static attribute of the pin and appears in the pin descriptor. It is cached here for access at IRQL above PASSIVE_LEVEL.
DeviceState
The KSSTATE to which the pin has been told to transition. Not necessarily the same as the state of the pipe, which is reported through AVStrMiniPinSetDeviceState. Initially KSSTATE_STOP, this member is changed when AVStream receives a connection state property set IOCTL. Access is synchronized using the Filter Control Mutex in AVStream. Minidrivers should not change this member. See note in Comments section below. Also see the ClientState member.
ResetState
The current reset state of the pin. This member is initially KSRESET_END and is changed through property access. Access to this member is synchronized by the filter control mutex. The client should not change this member.
StreamHeaderSize
Indicates the size of each KSSTREAM_HEADER for the pin. Typically used for output pins, a client can set this to any value greater than sizeof (KSSTREAM_HEADER) and have extended stream headers allocated (each stream header will be StreamHeaderSize bytes long). If a client does not set this member, this indicates that no extended information will follow stream headers. In such a situation, each stream header will be precisely sizeof (KSSTREAM_HEADER)). Clients can set this in the pin creation dispatch.
DataFlow
Specifies the direction of data flow for the pin. Possible settings include KSPIN_DATAFLOW_IN and KSPIN_DATAFLOW_OUT. This information is a static attribute of the pin and appears in the pin descriptor. It is cached here for access at IRQL above PASSIVE_LEVEL.
ClientState
The KSSTATE at which the pin is currently set. Updated immediately before AVStrMiniPinSetDeviceState is called. If this callback routine fails, AVStream rolls back ClientState to its previous value. Minidrivers that fail state transitions and that check this member during processing should be aware of this sequence of events.

Headers

Declared in ks.h. Include ks.h.

Comments

This structure is available in Windows XP and later operating systems and in DirectX 8.0 and later versions.

In many ways, pins are the focus of filter behavior. This is reflected in the fact that the pin structure has a large number of members. Many minidrivers need to refine pin behavior and maintain additional pin-associated context. For filters with fairly conventional pin behavior, no additional refinement or context will be required. In many cases, default pin behavior is sufficient; the pins are accessed via filter-centric processing.

For synchronization purposes, the lifetime of this object is the interval starting when the minidriver's PreCreate dispatch function is called (or would be called) and ending when the minidriver's Close dispatch function returns, assuming the function does not return STATUS_PENDING. If it does return STATUS_PENDING, the object's lifetime ends when the client indicates completion of the close request by calling KsCompletePendingRequest.

If the minidriver needs to determine whether or not it has been told to go to a specific KSSTATE, comparing the value of the DeviceState member of KSPIN to that state is not a reliable method. Instead, either look at the ClientState member, or create a variable in the SetDeviceState callback and then check this variable. SetDeviceState is a member of KSPIN_DISPATCH.

See Also

KSPIN_DESCRIPTOR_EX, KsAddItemToObjectBag , KsCompletePendingRequest, KSPIN_DISPATCH, Object Bags


KSPROCESSPIN

The KSPROCESSPIN structure is used in filter-centric processing as a means to easily access data available on a specific input pin or to write out data that has been processed to an output pin. The structure describes the process state of a specific pin.

typedef struct {
  PKSPIN  Pin;
  PKSSTREAM_POINTER  StreamPointer;
  PKSPROCESSPIN  InPlaceCounterpart;
  PKSPROCESSPIN  DelegateBranch;
  PKSPROCESSPIN  CopySource;
  PVOID  Data;
  ULONG  BytesAvailable;
  ULONG  BytesUsed;
  ULONG  Flags;
  BOOLEAN  Terminate;
} KSPROCESSPIN, *PKSPROCESSPIN;

Members

Pin
Pointer to the AVStream pin object that this process structure is describing. Everything in the structure will refer to this pin.
StreamPointer
A KSSTREAM_POINTER pointing into the input stream at the current input location or into the output stream at the current output location. This can be used, for example, by output pins to stamp information onto the associated KSSTREAM_HEADER (ProcessPin->StreamPointer->StreamHeader->Flags=...).
InPlaceCounterpart
If the pipe section that this process pin belongs to corresponds to an in-place transform,InPlaceCounterPart will point to the counterpart pin of this process pin (that is- if this is the input to the in-place transform, InPlaceCounterPart will point to the output process pin for the transform and vice versa).
DelegateBranch
If frames coming out of this process pin are being split and sent to multiple sink pins, and the split does not cause a data copy (that is the split is sending the frames in a read-only manner and all of the split pin instances are in the same pipe), DelegateBranch will point to the first instance of the process pin (the one that clients must be concerned with the splitter will automatically handle any processs pin that has a nonNULL DelegateBranch).
CopySource
If frames coming out of this process pin are being split and sent to multiple sink pins in a manner that does cause a data copy (that is one of the downstream filters is modifying the data frame via an in-place transform), CopySource will point to the process pin from which the frame was copied. The splitter will automatically handle any process pin that has a nonNULL CopySource.
Data
If the pin being described by this process entry is an input pin, this will point to the next available byte of data to be input. On the other hand, if it is an output pin, it will point to an output buffer where processed data will be put.
BytesAvailable
Indicates how many bytes of data are available in Data.
BytesUsed
How many bytes of this data frame have been used by the process function. Clients should set this member to update how much they have read or written.
Flags
Should this particular process pin correspond to an input pin, this will contain a copy of the flags out of the stream header for the current flag.
Terminate
Contains an indication of whether the current data frame should be sent downstream after the process dispatch finishes despite the fact that not all data has been consumed.

Headers

Declared in ks.h. Include ks.h.

Comments

This structure is available in Windows XP and later operating systems and in DirectX 8.0 and later versions.

Only clients using filter-centric processing need concern themselves with process pins. Further, process pins that have a nonNULL DelegateBranch or a nonNULL CopySource are typically not of concern to the client. The splitter will automatically handle process pins with these pointers.

Typically, most clients will be concerned with the members Pin, Data, BytesAvailable, BytesUsed, Flags, and Terminate. Data can be read from the stream or written into the stream through the Data member; BytesAvailable tells the client how many bytes of data are available in the current data frame (buffer) that Data points to. As the client minidriver reads from or writes to the stream, BytesUsed should be updated to reflect how many bytes of data have been consumed. The Terminate flag can be set if the minidriver is done with the current frame despite the fact that BytesUsed is not equal to BytesAvailable. Once the minidriver exits the processing dispatch, pointers will be advanced, frames will be completed as appropriate, etc.

See Also

KSPROCESSPIN_INDEXENTRY


KSPROCESSPIN_INDEXENTRY

The KSPROCESSPIN_INDEXENTRY structure is used in filter-centric processing to bring together all of the input and output pins in one context.

typedef struct {
  PKSPROCESSPIN  *Pins;
  ULONG  Count;
} KSPROCESSPIN_INDEXENTRY, *PKSPROCESSPIN_INDEXENTRY;

Members

Pins
Pointer to an array of KSPROCESSPIN structures. Pins will be ordered in pin ID order. The array will contain a listing of the instances of the given pin.
Count
The number of process pins in Pins that are currently instantiated.

Headers

Declared in ks.h. Include ks.h.

Comments

This structure is available in Windows XP and later operating systems and in DirectX 8.0 and later versions.

This pointer table is indexed in order of the pins described in the pin descriptor table for the corresponding filter. The first pin described in the descriptor table will have the first entry in the index table passed to the processing dispatch. See the processing dispatch in KSPIN_DISPATCH.

See Also

KSPROCESSPIN, Filter-Centric Processing


KSSTREAM_POINTER

The KSSTREAM_POINTER structure is the basic AVStream pointer into a stream.

typedef struct {
  PVOID  Context;
  PKSPIN  Pin;
  PKSSTREAM_HEADER  StreamHeader;
  PKSSTREAM_POINTER_OFFSET  Offset;
  KSSTREAM_POINTER_OFFSET  OffsetIn;
  KSSTREAM_POINTER_OFFSET  OffsetOut;
} KSSTREAM_POINTER, *PKSSTREAM_POINTER;

Members

Context
A pointer to client-requested context information. The leading edge and trailing edge stream pointers will have this member set to NULL. Cloned stream pointers can specify that they wish to have context information via the mechanism described in KsStreamPointerClone.
Pin
Pointer to the AVStream pin object to which this stream pointer belongs.
StreamHeader
Pointer to the stream header object for the data frame that this stream pointer currently points to. See KSSTREAM_HEADER for more information.
Offset
Points either to OffsetIn or OffsetOut depending on whether the pin to which this stream pointer belongs is an input pin or output pin.
OffsetIn
A structure describing the data that the stream pointer currently points at. See KSSTREAM_POINTER_OFFSET for more information.
OffsetOut
A structure used to output data on an output pin. See KSSTREAM_POINTER_OFFSET for more information.

Headers

Declared in ks.h. Include ks.h.

Comments

This structure is available in Windows XP and later operating systems and in DirectX 8.0 and later versions.

A queue object for a stream has at least one hard defined stream pointer: the leading-edge stream pointer. This pointer normally points to the newest unprocessed data frame in the queue. Queues for pins that specify KSPIN_FLAG_DISTINCT_TRAILING_EDGE in the relevant KSPIN_DESCRIPTOR_EX also have a trailing-edge stream pointer. See Leading and Trailing Edge Stream Pointers.

The queue can have any number of stream pointers associated with it; these can be created with the KsStreamPointerClone function. Stream pointers place references on the frames they point to. Also, any data frame in the window between the leading edge stream pointer and the trailing edge stream pointer has a reference on it as a result of being in that window. As long as a data frame has more than one reference on it, it is guaranteed to leave the queue and be completed.

Stream pointers can be in one of two states: unlocked and locked. An unlocked stream pointer is not guaranteed to actually reference an existing data frame within the queue. In order to access the data that you believe the pointer points at, it must be locked. Further, data frames pointed to by an unlocked stream pointer can be cancelled; the client can receive notification of cancellation through the mechanism described in KsStreamPointerClone. Locked stream pointers are guaranteed to reference data in the queue. Data frames pointed to by locked stream pointers cannot be cancelled. See Locking and Unlocking Stream Pointers.

When a minidriver is finished with a particular stream pointer, it should call KsStreamPointerDelete to delete the pointer and release a reference on the pointed-to frame. The leading-edge and trailing-edge stream pointers cannot be deleted. Unlock these stream pointers when they are not in use.

For more general conceptual information on stream pointers, see the Stream Pointers section.

See Also

KSSTREAM_HEADER, KSSTREAM_POINTER_OFFSET, KsStreamPointerClone , KsStreamPointerDelete, KsStreamPointerLock, KsStreamPointerUnlock, KsStreamPointerAdvance, KsStreamPointerAdvanceOffsets, KsStreamPointerAdvanceOffsetsAndUnlock


KSSTREAM_POINTER_OFFSET

The KSSTREAM_POINTER_OFFSET structure describes the offset of the stream pointer into the data stream. It also describes the amount of data available for input/output or the mappings for scatter/gather DMA.

typedef struct {
    union {
        PUCHAR  Data;
        PKSMAPPING  Mappings;
    };
    ULONG  Count;
    ULONG  Remaining;
} KSSTREAM_POINTER_OFFSET, *PKSSTREAM_POINTER_OFFSET;

Members

Data
If the client has not specified that this pin is to perform automatic scatter/gather DMA mapping generation via KSPIN_FLAG_GENERATE_MAPPINGS, then this will point to a buffer containing input data or a buffer to which data is to be output.
Mappings
If the client has specified that this pin is to perform automatic scatter/gather DMA mapping generation via KSPIN_FLAG_GENERATE_MAPPINGS, then this will point to a table of KSMAPPINGs describing each individual contiguous chunk of physical memory that the client can use to set up a scatter/gather DMA operation with hardware.
Count
Contains either the number of bytes of data available in the Data buffer or it contains the number of mappings in the Mappings table depending on whether this pin has specified mapping generation or not.
Remaining
Used by the client to describe how many bytes of data have been read/written or how many scatter/gather mappings have been read from/written to depending on whether this pin has specified mapping generation or not.

Headers

Declared in ks.h. Include ks.h.

Comments

This structure is available in Windows XP and later operating systems and in DirectX 8.0 and later versions.

See Also

KSSTREAM_POINTER , KSMAPPING


AVStream Minidriver Routines

This section contains reference pages for the minidriver-supplied AVStream minidriver routines. This material is relevant only for Windows® XP and DirectX® 8.0 releases and later. This section documents routines exported by the minidriver that are specified in the following AVStream structures: KSALLOCATOR_DISPATCH, KSDEVICE_DISPATCH, KSFILTER_DISPATCH, KSPIN_DISPATCH.

Note that the names of these routines are vendor-defined because each is specified by a function pointer within the previously listed structures.


AVStrMiniInitializeAllocator

An AVStream minidriver's AVStrMiniInitializeAllocator routine initializes an allocator that will be associated with a pin.

NTSTATUS
  AVStrMiniInitializeAllocator(
    IN PKSPIN  Pin,
    IN PKSALLOCATOR_FRAMING  AllocatorFraming,
    OUT PVOID  *Context
    );

Parameters

Pin
Pointer to a KSPIN structure describing the pin with which the allocator is to be associated.
AllocatorFraming
Pointer to a KSALLOCATOR_FRAMING structure describing the framing requirements that the allocator should use.
Context
Pointer to a context for the allocator that will be passed as a parameter to the other routines for this structure. For example, the driver could store pin or allocator framing structures for later reference by the other callback routines. Note that other routines for KSALLOCATOR_DISPATCH must have at least an indirect way of referencing Pin. (For instance, AVStrMiniAllocate will need to be able to access the AllocatorFraming information for Pin, and Context is the only parameter that AVStream will pass it.)

Return Value

AVStrMiniInitializeAllocator should return STATUS_SUCCESS or the error code that it received attempting to create the allocator.

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

The minidriver specifies this routine's address in the InitializeAllocator member of its KSALLOCATOR_DISPATCH structure. The minidriver passes this structure to the class driver in KSPIN_DISPATCH.

Note that kernel mode allocators cannot allocate frames that could eventually reach user mode.

AVStream calls AVStrMiniInitializeAllocator to initialize the given allocator. The handler for this routine should prepare to handle memory allocation and free requests.

For more information, see KS Allocators.

See Also

AVStrMiniDeleteAllocator, KSALLOCATOR_DISPATCH, KSALLOCATOR_FRAMING, KSPIN, KSPIN_DISPATCH


AVStrMiniDeleteAllocator

An AVStream minidriver's AVStrMiniDeleteAllocator routine deletes the allocator that is associated with a pin.

VOID
  AVStrMiniDeleteAllocator(
    IN PVOID  Context
    );

Parameters

Context
Pointer to the allocator's context structure created by AVStrMiniInitializeAllocator.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

The minidriver specifies this routine's address in the DeleteAllocator member of its KSALLOCATOR_DISPATCH structure. The minidriver passes this structure to the class driver in KSPIN_DISPATCH.

Once this function is called, AVStream will no longer use the allocator to allocate and free memory. This handler should release all system resources reserved by the allocator.

For more information, see KS Allocators.

See Also

AVStrMiniInitializeAllocator, KSALLOCATOR_DISPATCH, KSPIN_DISPATCH


AVStrMiniAllocate

An AVStream minidriver's AVStrMiniAllocate routine allocates a frame using the allocator specified in the Context parameter.

PVOID
  AVStrMiniAllocate(
    IN PVOID  Context
    );

Parameters

Context
Pointer to the allocator's context structure created in AVStrMiniInitializeAllocator.

Return Value

Allocate returns a pointer to the newly allocated memory. Return NULL if the attempt to allocate memory failed.

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

The minidriver specifies this routine's address in the Allocate member of its KSALLOCATOR_DISPATCH structure. The minidriver passes this structure to the class driver in KSPIN_DISPATCH.

AVStream calls this routine to allocate a frame. The handler should allocate a frame as described by the allocator framing context passed into the initialization dispatch.

For more information, see KS Allocators.

See Also

AVStrMiniInitializeAllocator, KSALLOCATOR_DISPATCH, KSPIN_DISPATCH


AVStrMiniAllocatorFreeFrame

An AVStream minidriver's AVStrMiniAllocatorFreeFrame routine frees the specified frame.

VOID
  AVStrMiniAllocatorFreeFrame(
    IN PVOID  Context,
    IN PVOID  Buffer
    );

Parameters

Context
Pointer to the allocator's context structure created in AVStrMiniInitializeAllocator.
Buffer
Pointer to the frame to be freed.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and later operating systems and in DirectX 8.0 and later versions.

The minidriver specifies this routine's address in the Free member of its KSALLOCATOR_DISPATCH structure. The minidriver passes this structure to the class driver in KSPIN_DISPATCH.

AVStream calls AVStrMiniFree to free a frame, passing as parameters the context structure set in the initialization dispatch and a pointer to the frame to free.

For more information, see KS Allocators.

See Also

AVStrMiniInitializeAllocator, KSALLOCATOR_DISPATCH


AVStrMiniDeviceAdd

An AVStream minidriver's AVStrMiniDeviceAdd routine notifies the minidriver that AVStream's PnP AddDevice routine has completed.

NTSTATUS
  AVStrMiniDeviceAdd(
    IN PKSDEVICE  Device
    );

Parameters

Device
Pointer to a KSDEVICE structure describing the functional device object (FDO) that has just been created.

Return Value

Should return STATUS_SUCCESS or the error code that was returned from the attempt to perform the operation. If the minidriver returns failure status, the related AddDevice call will also fail. See the Comments section below for more details.

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

The minidriver specifies this routine's address in the Add member of its KSDEVICE_DISPATCH structure.

AVStream calls AVStrMiniDeviceAdd from its default AddDevice routine, at KSDEVICE initialization time. At the point at which this routine is called, the WDM device object (DEVICE_OBJECT) has been created, the KSDEVICE structure has been instantiated and initialized, and the KS device header has been allocated.

Minidrivers can use this routine to associate context information with the AVStream device object, or to initialize a device extension.

If this routine returns an unsuccessful status code, AVStream's AddDevice routine will fail. STATUS_PENDING is not a legal return code because no IRP is involved. The routine is called at IRQL = PASSIVE_LEVEL only.

This routine is optional.

See Also

KSDEVICE_DISPATCH


AVStrMiniDeviceStart

An AVStream minidriver's AVStrMiniDeviceStart routine is called when an IRP_MN_START_DEVICE request is sent for a specified device.

NTSTATUS
  AVStrMiniDeviceStart(
    IN PKSDEVICE  Device,
    IN PIRP  Irp,
    IN PCM_RESOURCE_LIST  TranslatedResourceList OPTIONAL,
    IN PCM_RESOURCE_LIST  UntranslatedResourceList OPTIONAL
    );

Parameters

Device
Pointer to a KSDEVICE structure describing the device to be started.
Irp
Pointer to the IRP_MN_START_DEVICE that was received.
TranslatedResourceList
Pointer to a CM_RESOURCE_LIST structure that contains the translated resource list extracted from Irp. Equals NULL if Device has no assigned resources. Optional.
UntranslatedResourceList
Pointer to a CM_RESOURCE_LIST structure that contains the untranslated resource list extracted from Irp. Equals NULL if the KSDEVICE member of this parameter list has no assigned resources. Optional.

Return Value

Should return STATUS_SUCCESS or the error code that was returned from the attempt to perform the operation. The start is guaranteed to succeed if the routine returns a successful status code. Do NOT return STATUS_PENDING.

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

The minidriver specifies this routine's address in the Start member of its KSDEVICE_DISPATCH structure.

Typically, this routine is used by minidrivers that must evaluate assigned resources. Resource lists are extracted from Irp for the convenience of the minidriver.

Note that TranslatedResourceList and UntranslatedResourceList are optional parameters that will be NULL if the device has no assigned resources.

STATUS_PENDING is not a legal return code from this function. To perform actions in the context of a worker thread before AVStream has completed start actions such as enabling device interfaces, use a post start dispatch. See AVStrMiniDevicePostStart.

This routine is optional.

See Also

KSDEVICE_DISPATCH, CM_RESOURCE_LIST


AVStrMiniDevicePostStart

An AVStream minidriver's AVStrMiniDevicePostStart routine is called when AVStream performs post-PnP-start processing. Use it to load drivers at start time, for example. Such events then will occur in the context of a worker thread after PnP start.

NTSTATUS
  AVStrMiniDevicePostStart(
    IN PKSDEVICE  Device,
    );

Parameters

Device
Pointer to a KSDEVICE structure describing the device for which the IRP_MN_START_DEVICE request was sent.

Return Value

Should return STATUS_SUCCESS or the error code that was returned from the attempt to perform the operation. If this routine returns failure, any pending IRP_MJ_CREATE requests between the IRP_MN_START_DEVICE request and the IRP_MN_STOP_DEVICE request will be failed. Do not return STATUS_PENDING.

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

The minidriver specifies this routine's address in the PostStart member of its KSDEVICE_DISPATCH structure.

This routine is optional.

See Also

KSDEVICE_DISPATCH


AVStrMiniDeviceQueryStop

An AVStream minidriver's AVStrMiniDeviceQueryStop routine is called when it receives an IRP_MN_QUERY_STOP_DEVICE request.

NTSTATUS
  AVStrMiniDeviceQueryStop(
    IN PKSDEVICE  Device,
    IN PIRP  Irp
    );

Parameters

Device
Pointer to the KSDEVICE that dispatched the PnP query stop IRP.
Irp
The IRP_MN_QUERY_STOP_DEVICE issued by Device.

Return Value

Should return STATUS_SUCCESS or the error code that was returned from the attempt to perform the operation. Success indicates that the device can commit to a stop and an error code indicates that it cannot. Do not return STATUS_PENDING.

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

The minidriver specifies a pointer to this routine in the QueryStop member of its KSDEVICE_DISPATCH structure.

Use AVStrMiniQueryStop to prevent the stopping of the device or to disallow activity that would prevent the minidriver from committing to a stop operation. If this routine is not specified, AVStream assumes that the minidriver can commit to a stop operation.

This routine is optional.

See Also

KSDEVICE_DISPATCH, KSDEVICE


AVStrMiniDeviceCancelStop

An AVStream minidriver's AVStrMiniDeviceCancelStop routine is called when an IRP_MN_CANCEL_STOP_DEVICE is dispatched by the device.

VOID
  AVStrMiniDeviceCancelStop(
    IN PKSDEVICE  Device,
    IN PIRP  Irp
    );

Parameters

Device
Pointer to the KSDEVICE that dispatched the IRP_MN_CANCEL_STOP_DEVICE.
Irp
The IRP_MN_CANCEL_STOP_DEVICE issued by Device.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

The minidriver specifies this routine's address in the CancelStop member of its KSDEVICE_DISPATCH structure.

This routine is optional.

See Also

KSDEVICE_DISPATCH, KSDEVICE


AVStrMiniDeviceStop

An AVStream minidriver's AVStrMiniDeviceStop routine is called when an IRP_MN_STOP_DEVICE is dispatched by the device.

VOID
  AVStrMiniDeviceStop(
    IN PKSDEVICE  Device,
    IN PIRP  Irp
    );

Parameters

Device
Pointer to the KSDEVICE that dispatched the IRP_MN_STOP_DEVICE.
Irp
The IRP_MN_STOP_DEVICE issued by Device.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

The minidriver specifies this routine's address in the Stop member of its KSDEVICE_DISPATCH structure.

This is usually provided by minidrivers that need to detach from previously assigned resources before completing a stop operation.

This routine is optional.

See Also

KSDEVICE_DISPATCH, KSDEVICE


AVStrMiniDeviceQueryRemove

An AVStream minidriver's AVStrMiniDeviceQueryRemove is called when an IRP_MN_QUERY_REMOVE_DEVICE is dispatched by the device.

NTSTATUS
  AVStrMiniQueryRemove(
    IN PKSDEVICE  Device,
    IN PIRP  Irp
    );

Parameters

Device
Pointer to the KSDEVICE that dispatched the IRP_MN_QUERY_REMOVE_DEVICE.
Irp
The IRP_MN_QUERY_REMOVE_DEVICE issued by Device.

Return Value

Should return STATUS_SUCCESS or the error code that was returned from the attempt to perform the operation. Return success if the device can be removed (or drivers can be updated) without disrupting the machine. If this is not the case, return an appropriate error code.

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

The minidriver specifies this routine's address in the QueryRemove member of its KSDEVICE_DISPATCH structure.

This routine is called when an IRP_MN_QUERY_REMOVE_DEVICE is dispatched by the device. It will usually be provided by minidrivers that want to prevent removal of the device or by minidrivers that must disallow activity that would otherwise prevent them from committing to a device removal operation. If this routine is not provided, AVStream will assume that the device can commit to a removal.

The routine is called at IRQL = PASSIVE_LEVEL and may not return STATUS_PENDING; a success code indicates that the device can commit to a removal and an error code indicates that it cannot.

This routine is optional.

See Also

KSDEVICE_DISPATCH, KSDEVICE


AVStrMiniDeviceCancelRemove

An AVStream minidriver's AVStrMiniDeviceCancelRemove routine is called when an IRP_MN_CANCEL_REMOVE_DEVICE is dispatched by the device.

VOID
  AVStrMiniDeviceCancelRemove(
    IN PKSDEVICE  Device,
    IN PIRP  Irp
    );

Parameters

Device
Pointer to the KSDEVICE that dispatched the IRP_MN_CANCEL_REMOVE_DEVICE.
Irp
The IRP_MN_CANCEL_REMOVE_DEVICE issued by Device.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

The minidriver specifies this routine's address in the CancelRemove member of its KSDEVICE_DISPATCH structure.

This routine is called when an IRP_MN_CANCEL_REMOVE_DEVICE is dispatched by the device.

This routine is optional.

See Also

KSDEVICE_DISPATCH, KSDEVICE


AVStrMiniDeviceRemove

An AVStream minidriver's AVStrMiniDeviceRemove routine is called when an IRP_MN_REMOVE_DEVICE is dispatched by the device.

VOID
  AVStrMiniDeviceRemove(
    IN PKSDEVICE  Device,
    IN PIRP  Irp
    );

Parameters

Device
Pointer to the KSDEVICE that dispatched the IRP_MN_REMOVE_DEVICE.
Irp
The IRP_MN_REMOVE_DEVICE issued by Device.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

The minidriver specifies this routine's address in the MiniRemove member of its KSDEVICE_DISPATCH structure.

AVStream calls this routine when an IRP_MN_REMOVE_DEVICE is dispatched by the device. Typically, it will be provided by minidrivers that must free device-associated resources upon device removal. This routine is called at IRQL = PASSIVE_LEVEL.

This routine is optional.

See Also

KSDEVICE_DISPATCH, KSDEVICE


AVStrMiniDeviceQueryCapabilities

An AVStream minidriver's AVStrMiniDeviceQueryCapabilities routine is called when an IRP_MN_QUERY_CAPABILITIES is dispatched by the device.

NTSTATUS
  AVStrMiniDeviceQueryCapabilities(
    IN PKSDEVICE  Device,
    IN PIRP  Irp,
    IN OUT PDEVICE_CAPABILITIES  Capabilities
    );

Parameters

Device
Pointer to the KSDEVICE that dispatched the IRP_MN_QUERY_CAPABILITIES.
Irp
The IRP_MN_QUERY_CAPABILITIES issued by Device.
Capabilities
Pointer to the DEVICE_CAPABILITIES structure that describes PnP and Power capabilities of Device.

Return Value

Should return STATUS_SUCCESS or the error code that was returned from the attempt to perform the operation. Return success if providing query capabilities. If not, return an appropriate error code. Do not return STATUS_PENDING.

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

The minidriver specifies this routine's address in the QueryCapabilities member of its KSDEVICE_DISPATCH structure.

This routine is called when an IRP_MN_QUERY_CAPABILITIES is dispatched by the device. It will usually be provided by minidrivers that need to supply information regarding power management capabilities. This routine is called at IRQL = PASSIVE_LEVEL.

This routine is optional.

See Also

KSDEVICE_DISPATCH, KSDEVICE


AVStrMiniDeviceSurpriseRemoval

An AVStream minidriver's AVStrMiniDeviceSurpriseRemoval routine is called when an IRP_MN_SURPRISE_REMOVAL is dispatched by the device.

VOID
  AVStrMiniDeviceSurpriseRemoval(
    IN PKSDEVICE  Device,
    IN PIRP  Irp
    );

Parameters

Device
Pointer to the KSDEVICE that dispatched the IRP_MN_SURPRISE_REMOVAL.
Irp
The IRP_MN_SURPRISE_REMOVAL issued by Device.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

The minidriver specifies this routine's address in the SurpriseRemoval member of its KSDEVICE_DISPATCH structure.

This routine is optional.

See Also

KSDEVICE_DISPATCH, KSDEVICE


AVStrMiniDeviceQueryPower

AVStream calls a minidriver's AVStrMiniDeviceQueryPower routine when it receives an IRP_MN_QUERY_POWER request.

NTSTATUS
  AVStrMiniDeviceQueryPower(
    IN PKSDEVICE  Device,
    IN PIRP  Irp,
    IN DEVICE_POWER_STATE  DeviceTo,
    IN DEVICE_POWER_STATE  DeviceFrom,
    IN DEVICE_POWER_STATE  SystemTo,
    IN DEVICE_POWER_STATE  SystemFrom,
    IN POWER_ACTION  Action
    );

Parameters

Device
Pointer to the KSDEVICE structure that dispatched the IRP_MN_QUERY_POWER.
Irp
Pointer to the IRP_MN_QUERY_POWER issued by Device.
DeviceTo
The power state requested by the issuer of Irp.
DeviceFrom
The current device power state.
SystemTo
System state to transition to, specified when a system power state transition is being queried. This value is unspecified if the call is due to a device power state change query.
SystemFrom
Current system state, specified when a system power state transition is being queried. This value is unspecified if the call is due to a device power state change query.
Action
Specifies additional information about the requested transition. Possible values are enumerators of the POWER_ACTION type.

Return Value

Should return STATUS_SUCCESS or the error code that was returned from the attempt to perform the operation. By returning STATUS_SUCCESS, the driver guarantees that it will not start any operation that would change its ability to set the requested power state. The driver should queue any IRP that would require such an operation until it completes a IRP_MN_SET_POWER that returns the device to an acceptable power state.

Note This value should not return STATUS_PENDING.

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

The Power Manager or a device power policy owner sends an IRP_MN_QUERY_POWER request to determine whether it can change the system or device power state (for example, to go to sleep).

If a driver fails an IRP_MN_QUERY_POWER request for a system power state, the Power Manager typically responds by issuing an IRP_MN_SET_POWER. Usually, this IRP will reaffirm the current system state. However, it is possible that drivers might receive an IRP_MN_SET_POWER to the queried state or to some other intermediate state. Drivers should be prepared to handle these situations.

The minidriver specifies this routine's address in the QueryPower member of its KSDEVICE_DISPATCH structure.

This routine is optional.

See Also

KSDEVICE_DISPATCH, IRP_MN_QUERY_POWER


AVStrMiniDeviceSetPower

AVStream calls a minidriver's AVStrMiniDeviceSetPower routine when it receives a IRP_MN_SET_POWER.

VOID
  AVStrMiniDeviceSetPower(
    IN PKSDEVICE  Device,
    IN PIRP  Irp,
    IN DEVICE_POWER_STATE  To,
    IN DEVICE_POWER_STATE  From
    );

Parameters

Device
Pointer to the KSDEVICE structure that received the IRP_MN_SET_POWER.
Irp
The IRP_MN_SET_POWER issued by Device.
To
The target device power state.
From
The current device power state.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

If a driver has registered its device for idle detection, the Power Manager sends an IRP_MN_SET_POWER to change the power state of an idle device.

The minidriver specifies this routine's address in the SetPower member of its KSDEVICE_DISPATCH structure.

This routine is optional.

See Also

KSDEVICE_DISPATCH, IRP_MN_SET_POWER


AVStrMiniFilterCreate

An AVStream minidriver's AVStrMiniFilterCreate routine is called when a filter is created. Typically, this routine is used by minidrivers that want to initialize the context and resources associated with the filter.

NTSTATUS
  AVStrMiniFilterCreate (
    IN PKSFILTER  Filter,
    IN PIRP  Irp
    );

Parameters

Filter
Pointer to the KSFILTER that was just created.
Irp
Pointer to the IRP_MJ_CREATE for Filter.

Return Value

If the routine succeeds, the create operation is guaranteed to succeed. Return STATUS_SUCCESS or the error code that was returned from the attempt to create the filter. STATUS_PENDING is also a legal return code. If a minidriver returns STATUS_PENDING, AVStream will not complete the IRP_MJ_CREATE immediately. Before returning STATUS_PENDING, the minidriver must call IoMarkIrpPending. When the processing of the create is complete, the minidriver must set the IRP's status code and then call KsCompletePendingRequest.

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

The minidriver specifies this routine's address in the Create member of its KSFILTER_DISPATCH structure.

At the point at which the routine is called, the file object has an associated context, and the KS object header has been allocated.

This routine is called at IRQL = PASSIVE_LEVEL with the device mutex held.

This routine is optional.

See Also

KSFILTER_DISPATCH, IoMarkIrpPending, KsCompletePendingRequest


AVStrMiniFilterClose

An AVStream minidriver's AVStrMiniFilterClose routine is called when a filter is closed. It usually is provided by minidrivers that want to free the context and resources associated with the filter.

NTSTATUS
  AVStrMiniFilterClose (
    IN PKSFILTER  Filter,
    IN PIRP  Irp
    );

Parameters

Filter
Pointer to the KSFILTER structure that was just closed.
Irp
Pointer to the IRP_MJ_CLOSE for the filter.

Return Value

Return STATUS_SUCCESS or STATUS_PENDING. If a minidriver returns STATUS_PENDING, AVStream will not complete the IRP_MJ_CLOSE immediately. Before returning STATUS_PENDING, however, the minidriver must call IoMarkIrpPending. Once the processing of the close is complete, the minidriver must set the IRP's status code and then call KsCompletePendingRequest.

The minidriver may also return the error code that it received attempting to close the filter, but this is not recommended.

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

The minidriver specifies this routine's address in the Close member of its KSFILTER_DISPATCH structure.

At the point at which the routine is called, any registered events on the filter have been freed, but the object is otherwise intact.

This routine is called at IRQL = PASSIVE_LEVEL with the device mutex held. For more information on mutexes, see Mutexes in AVStream.

This routine is optional.

See Also

KSFILTER_DISPATCH, IoMarkIrpPending, KsCompletePendingRequest


AVStrMiniFilterProcess

An AVStream minidriver's AVStrMiniFilterProcess routine is called when the filter is meant to process frames. It is used to perform filter-centric processing.

NTSTATUS
  AVStrMiniFilterProcess (
    IN PKSFILTER  Filter,
    IN PKSPROCESSPIN_INDEXENTRY  ProcessPinsIndex
    );

Parameters

Filter
Pointer to the KSFILTER structure that must process frames.
ProcessPinsIndex
Pointer to the KSPROCESSPIN_INDEXENTRY structure that AVStream indexes in order of the pins described in the pin descriptor table for Filter.

Return Value

Return STATUS_SUCCESS to continue processing. Return STATUS_PENDING to stop processing until the next triggering event. The minidriver may return an error code, but this will be treated as described for STATUS_PENDING.

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

The minidriver specifies this routine's address in the Process member of its KSFILTER_DISPATCH structure.

The routine is called at either IRQL = DISPATCH_LEVEL or PASSIVE_LEVEL depending on the preference expressed in the filter descriptor. Filter descriptors that specify KSFILTER_FLAG_DISPATCH_LEVEL_PROCESSING may have their process callback at DISPATCH_LEVEL; filter descriptors that do not specify this flag will have their process callback at PASSIVE_LEVEL.

For more information, see Filter-Centric Processing and Processing Commonality.

This routine is optional.

See Also

KSFILTER_DISPATCH, KSPROCESSPIN_INDEXENTRY


AVStrMiniFilterReset

An AVStream minidriver's AVStrMiniFilterReset routine is called when AVStream receives an IOCTL_KS_RESET_STATE to return the filter to the state it was in at Acquire-time. This routine is also called when a queue associated with a pin on the filter is flushed. This routine will only be called for a filter-centric filter.

NTSTATUS
  AVStrMiniFilterReset(
    IN PKSFILTER  Filter,
    );

Parameters

Filter
Pointer to the KSFILTER to return to its previous state.

Return Value

AVStream does not currently use the return value.

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

For more information, see filter-centric processing.

Note that it is not the filter in question, but rather a pin on this filter that actually receives the reset IOCTL.

The minidriver specifies this routine's address in the Reset member of its KSFILTER_DISPATCH structure.

The filter control mutex may be held during this function. See Filter-Control Mutex in AVStream.

This routine is optional.

See Also

KSFILTER_DISPATCH


AVStrMiniPinCreate

An AVStream minidriver's AVStrMiniPinCreate routine is called when a pin is created. Typically, this routine is used by minidrivers that want to initialize the context and resources associated with the pin.

NTSTATUS
  AVStrMiniPinCreate(
    IN PKSPIN  Pin,
    IN PIRP  Irp
    );

Parameters

Pin
Pointer to the KSPIN that was just created.
Irp
Pointer to the IRP_MJ_CREATE for Pin.

Return Value

If the routine succeeds, the create operation is guaranteed to succeed. Return STATUS_SUCCESS or STATUS_PENDING. If a minidriver returns STATUS_PENDING, AVStream will not complete the IRP_MJ_CREATE immediately. Before returning STATUS_PENDING, however, the minidriver must call IoMarkIrpPending. Once the processing of the create is complete, the minidriver must set the IRP's status code and then call KsCompletePendingRequest.

Alternatively, the minidriver may return the error code that it received attempting to create the pin.

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

The minidriver specifies this routine's address in the Create member of its KSPIN_DISPATCH structure.

This routine is called when a pin is created. At the point at which this routine is called, the file object has an associated context, and the KS object header has been allocated. Typically, this function will be provided by minidrivers that want to initialize the context and resources associated with the pin.

The filter control mutex is held while in this function. The function will be called at IRQL = PASSIVE_LEVEL.

This routine is optional.

See Also

KSPIN_DISPATCH, IoMarkIrpPending, KsCompletePendingRequest


AVStrMiniPinClose

An AVStream minidriver's AVStrMiniPinClose routine is called when a pin is closed. It usually is provided by minidrivers that want to free the context and resources associated with the pin.

NTSTATUS
  AVStrMiniPinClose (
    IN PKSPIN  Pin,
    IN PIRP  Irp
    );

Parameters

Pin
Pointer to the KSPIN that was just closed.
Irp
Pointer to the IRP_MJ_CLOSE for Pin.

Return Value

Return STATUS_SUCCESS or STATUS_PENDING. If a minidriver returns STATUS_PENDING, AVStream will not complete the IRP_MJ_CLOSE immediately. Before returning STATUS_PENDING, however, the minidriver must call IoMarkIrpPending. Once the processing of the close is complete, the minidriver must set the IRP's status code and then call KsCompletePendingRequest.

The routine may return the error code that it received attempting to close the filter, but this is not recommended.

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

The minidriver specifies this routine's address in the Close member of its KSPIN_DISPATCH structure.

At the point at which the routine is called, any registered events on the pin have been freed, but the object is otherwise intact.

The filter control mutex is held while in this function. For more information on mutexes, please see Mutexes in AVStream.

This routine is optional.

See Also

KSPIN_DISPATCH, IoMarkIrpPending, KsCompletePendingRequest


AVStrMiniPinProcess

An AVStream minidriver's AVStrMiniPinProcess routine is called when there is data available for a KSPIN structure to process. Use this routine to perform pin-centric processing.

NTSTATUS
  AVStrMiniPinProcess(
    IN PKSPIN  Pin
    );

Parameters

Pin
Pointer to the KSPIN that has frame data available to process.

Return Value

Return STATUS_SUCCESS to continue processing. Return STATUS_PENDING to stop processing until the next triggering event. The minidriver may return an error code, but this will be treated as described for STATUS_PENDING.

For more information, see Processing Commonality. See below for information on frame completion.

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

The minidriver specifies this routine's address in the Process member of its KSPIN_DISPATCH structure.

Indicate that a filter uses pin-centric processing by providing this dispatch function. AVStream calls the process dispatch in three unique situations, depending on the pin flags set in the relevant KSPIN_DESCRIPTOR_EX structure. By default, this routine is called when new data arrives into a previously empty queue. Alternatively, it can be called every time a data frame arrives, regardless of whether the queue was previously empty or not. To do this, set KSPIN_FLAG_INITIATE_PROCESSING_ON_EVERY_ARRIVAL. Or, to indicate that this routine should never be called except in the event of a minidriver call to KsPinAttemptProcessing, set KSPIN_FLAG_DO_NOT_INITIATE_PROCESSING.

If the minidriver does not wish to complete the frame immediately, force the leading edge to remain stationary , . Or, specify a distinct trailing edge by setting KSPIN_FLAG_DISTINCT_TRAILING_EDGE on KSPIN_DESCRIPTOR_EX. As a final alternative, clone the leading edge stream pointer by calling KsStreamPointerClone.

The process dispatch is either made at the default IRQL = PASSIVE_LEVEL, or possibly at DISPATCH_LEVEL if the minidriver has specified KSPIN_FLAG_DISPATCH_LEVEL_PROCESSING in the relevant KSPIN_DESCRIPTOR_EX.

This routine is optional.

See Also

KSPIN_DISPATCH, KSPIN_DESCRIPTOR_EX, KsStreamPointerClone, Pin-Centric Processing, Filter-Centric Processing


AVStrMiniPinReset

An AVStream minidriver's AVStrMiniPinReset routine is called when a KSPIN structure's reset state is changed due to the arrival of an IOCTL_KS_RESET_STATE device control. This routine is also called when the queue associated with the given pin is flushed. This routine is only called on pin-centric pins.

VOID
  AVStrMiniPinReset(
    IN PKSPIN  Pin,
    );

Parameters

Pin
Pointer to the KSPIN structure to return to its previous state.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

For more information, see Pin-Centric Processing.

The minidriver specifies this routine's address in the Reset member of its KSPIN_DISPATCH structure.

Typically, this routine is provided by minidrivers that must flush hardware buffers. The filter control mutex may be held during this function. See Filter-Control Mutex in AVStream.

This routine is optional.

See Also

KSPIN_DISPATCH, KSPIN


AVStrMiniPinSetDataFormat

An AVStream minidriver's AVStrMiniPinSetDataFormat routine is called at pin creation time to verify that the previously agreed upon data format is acceptable for this KSPIN structure and a match for this KSDATARANGE structure. This routine is also called due to certain types of dynamic format changes, for example the acceptance of a KSPROPERTY_CONNECTION_PROPOSEDATAFORMAT property request.

NTSTATUS
  AVStrMiniPinSetDataFormat(
    IN PKSPIN  Pin,
    IN PKSDATAFORMAT  OldFormat  OPTIONAL,
    IN PKSMULTIPLE_ITEM  OldAttributeList  OPTIONAL,
    IN const KSDATARANGE  *DataRange,
    IN const KSATTRIBUTE_LIST  *AttributeRange  OPTIONAL
    );

Parameters

Pin
Pointer to the KSPIN structure for which the data format is changing.
OldFormat
Optional. Pointer to a KSDATAFORMAT structure. Minidrivers can use this field to determine the data format that the pin was using before this call. If NULL, indicates that no data format has been set for the pin and that Pin's create dispatch has not yet been made. A NULL value here indicates that this routine was called at initialization time for format verification.
OldAttributeList
Optional. Pointer to a KSMULTIPLE_ITEM structure that stores attributes for the previous format.
DataRange
Pointer to a KSDATARANGE structure. The data range for the new format.
AttributeRange
Optional. The attribute range for the new format.

Return Value

Return STATUS_SUCCESS if Pin's ConnectionFormat member matches the range that was passed to this routine. Return STATUS_NO_MATCH if ConnectionFormat does not match the passed range and the minidriver would like to continue to attempt to find a match with another range. Return an error code of choice if ConnectionFormat does not match the passed range and the minidriver does not want to continue to try to find a match with another range. Do not return STATUS_PENDING.

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

In a ring 3 graph, the Kernel Streaming Proxy module (KsProxy) sets the data format based on the agreed upon connection format or a dynamic format change. KsProxy issues a KSPROPERTY_CONNECTION_DATAFORMAT request which, after some initial validation, is translated into this dispatch call to the minidriver. See Kernel Streaming Proxy Reference. For more information, see KS Data Formats and Data Ranges and Format Negotiation and Data Intersections.

The minidriver specifies the address for AVStrMiniPinSetDataFormat in the SetDataFormat member of its KSPIN_DISPATCH structure.

This routine can be called before the pin receives an IRP_MJ_CREATE, and minidrivers should be prepared to deal with this situation.

OldFormat, OldAttributeList, and AttributeRange are all optional parameters and can be NULL.

This routine is optional.

See Also

KSPIN_DISPATCH, IRP_MJ_CREATE, KSDATARANGE, KSMULTIPLE_ITEM, KSDATAFORMAT, KSPIN


AVStrMiniPinSetDeviceState

An AVStream minidriver's AVStrMiniPinSetDeviceState routine is called when the state of a KSPIN structure is changed due to the arrival of a connection state property 'set' IOCTL. Typically, this will be provided by minidrivers that need to change the state of hardware.

NTSTATUS
  AVStrMiniPinSetDeviceState(
    IN PKSPIN  Pin,
    IN KSSTATE  ToState,
    IN KSSTATE  FromState);
    );

Parameters

Pin
Pointer to the KSPIN structure for which state is changing.
ToState
The target KSSTATE after receipt of the IOCTL.
FromState
The previous KSSTATE.

Return Value

Return STATUS_SUCCESS or the error code that was returned from the attempt to set the state. Do not return STATUS_PENDING. The filter control mutex is held during this function. See Filter Control Mutex in AVStream.

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

The minidriver specifies this routine's address in the SetDeviceState member of its KSPIN_DISPATCH structure.

Minidrivers will not receive a stop upon initial connection of the pin.

Pins that use the standard transport mechanism (standard interface/standard medium or an explicit use of KSPIN_FLAG_USE_STANDARD_TRANSPORT in KSPIN_DESCRIPTOR_EX) receive filtered state changes through the owning pipe through this routine. This means that no transition will be more than a single step. In other words, KSSTATE_STOP transitions to KSSTATE_ACQUIRE, KSSTATE_ACQUIRE transitions to KSSTATE_PAUSE, and so on. In addition, state changes received in this routine represent the state of the pipe as a whole, not the individual state of the pin as reported in the DeviceState member of the KSPIN structure.

Pins that do not use the standard transport mechanism (non-standard interface, non-standard medium, or an explicit use of KSPIN_FLAG_DO_NOT_USE_STANDARD_TRANSPORT in KSPIN_DESCRIPTOR_EX) receive non-filtered state changes through this routine. As such, non-standard transport pins must be prepared to deal with state changes that jump more than a single step. As an example, consider a jump from KSSTATE_RUN to KSSTATE_STOP without an intervening KSSTATE_PAUSE. In addition, the state reported to this routine will be identical to the state reported in the DeviceState member of the relevant KSPIN structure.

This routine is optional.

See Also

KSPIN_DISPATCH


AVStrMiniPinConnect

An AVStream minidriver's AVStrMiniPinConnect routine is called when the relevant KSPIN is serving as a sink pin and is connected to an AVStream source pin.

NTSTATUS
  AVStrMiniPinConnect(
    IN PKSPIN  Pin,
    );

Parameters

Pin
Pointer to the relevant KSPIN serving as sink pin.

Return Value

Return STATUS_SUCCESS or the error returned from the attempt to establish an intra-connection. Do not return STATUS_PENDING. AVStream treats a pending return value as invalid and causes the connection to fail.

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

The minidriver specifies this routine's address in the Connect member of its KSPIN_DISPATCH structure.

This routine is optional.

To learn more about sink pins and source pins, see Pin Connections.

See Also

KSPIN_DISPATCH


AVStrMiniPinDisconnect

An AVStream minidriver's AVStrMiniPinDisconnect routine is called when the relevant KSPIN is serving as a sink pin and it is disconnected from an AVStream source pin.

VOID
  AVStrMiniPinDisconnect(
    IN PKSPIN  Pin,
    );

Parameters

Pin
Pointer to the relevant KSPIN, serving as a sink pin.

Return Value

None

Headers

Declared in ks.h. Include ks.h.

Comments

This routine is available in Windows XP and DirectX 8.0 and later.

The minidriver specifies this routine's address in the Disconnect member of its KSPIN_DISPATCH structure.

This routine is optional.

To learn more about sink pins and source pins, see Pin Connections.

See Also

KSPIN_DISPATCH


AVStream Interfaces

Built on Wednesday, July 11, 2001


IKsControl

The IKsControl interface is a COM-style interface implemented on AVStream filters and pins. It allows clients in kernel mode to access AVStream automation objects (properties, methods, and events). See the IKsControl kernel-streaming proxy COM interface for information on the user-mode equivalent of this interface.

DECLARE_INTERFACE_(IKsControl, IUnknown) {
  DEFINE_ABSTRACT_UNKNOWN()

    STDMETHOD_(NTSTATUS, KsProperty)(THIS_
      IN PKSPROPERTY Property,
    IN ULONG PropertyLength,
      IN OUT PVOID PropertyData,
      IN ULONG DataLength,
    OUT ULONG* BytesReturned
    ) PURE;
  STDMETHOD_(NTSTATUS, KsMethod)(THIS_
      IN PKSMETHOD Method,
      IN ULONG MethodLength,
    IN OUT PVOID MethodData,
      IN ULONG DataLength,
      OUT ULONG* BytesReturned
  ) PURE;
    STDMETHOD_(NTSTATUS, KsEvent)(THIS_
      IN PKSEVENT Event,        /* optional */
      IN ULONG EventLength,
      IN OUT PVOID EventData,
      IN ULONG DataLength,
      OUT ULONG* BytesReturned
  ) PURE;
};

Methods

KsProperty
Get or set a property as specified by Property on the object to which this IKsControl interface refers.
KsMethod
Call a method as specified by Method on the object to which this IKsControl interface refers.
KsEvent
Query support for, enable, or disable an event as specified by Event on the object to which this IKsControl interface refers.

Comments

The IKsControl interface will typically be acquired through a call to KsPinGetConnected*Interface. Remember that this is a COM-style interface, and that the function call to get this interface will have called the QueryInterface method and thus called the AddRef method to increment the interface pointer. Once done with the IKsControl interface, the client must release it with a call to the Release method.

Clients written in C will see the IKsControl interface as a structure containing a pointer to a table of functions instead of a C++ abstract base class. A client written in C++ might do the following:

    IKsControl *Control;

    if (NT_SUCCESS (
      KsPinGetConnectedPinInterface (
        Pin,
        IID_IKsControl,
        (PVOID *)&Control)
{
        Control -> KsProperty (…);
        Control -> Release ();
    }

a client written in C would instead do the following:

    IKsControl *Control;

    If (NT_SUCCESS (
      KsPinGetConnectedPinInterface (
        Pin,
        IID_IKsControl,
        (PVOID *)&Control)
    ) {
      Control -> lpVtbl -> KsProperty (…);
      Control -> lpVtbl -> Release ();
    }

See Also

KsPinGetConnectedPinInterface , KsPinGetConnectedFilterInterface, AVStream, KCOM


IKsReferenceClock

The IKsReferenceClock interface is a COM-style interface provided by AVStream on all pins. The pin will pass the request onto the master clock.

DECLARE_INTERFACE_(IKsReferenceClock, IUnknown) {
    DEFINE_ABSTRACT_UNKNOWN()

  STDMETHOD_(LONGLONG, GetTime)(THIS
    ) PURE;
  STDMETHOD_(LONGLONG, GetPhysicalTime)(THIS
  ) PURE;
  STDMETHOD_(LONGLONG, GetCorrelatedTime)(THIS_
      OUT PLONGLONG SystemTime
  ) PURE;
  STDMETHOD_(LONGLONG, GetCorrelatedPhysicalTime)(THIS_
      OUT PLONGLONG SystemTime
  ) PURE;
  STDMETHOD_(NTSTATUS, GetResolution)(THIS_
      OUT PKSRESOLUTION Resolution
  ) PURE;
  STDMETHOD_(NTSTATUS, GetState)(THIS_
      OUT PKSSTATE State
  ) PURE;
};

Methods

GetTime
Queries the associated reference clock for the current time.
GetPhysicalTime
Queries the associated reference clock for the current physical time.
GetCorrelatedTime
Queries the associated reference clock for the current correlated time and system time.
GetCorrelatedPhysicalTime
Queries the associated reference clock for the current correlated physical time and system time.
GetResolution
Queries the associated reference clock for its resolution.
GetState
Queries the associated reference clock for its current state.

Comments

The IKsReferenceClock interface will typically be acquired through a call to KsPinGetReferenceClockInterface. Remember that this is a COM-style interface, and that the function call to get this interface will have called QueryInterface and thus invoked AddRef to increment the interface pointer. Once done with the IKsReferenceClock interface, the client must release it with a call to Release.

Clients written in C will see the IKsReferenceClock interface as a structure containing a pointer to a table of functions instead of a C++ abstract base class. A client written in C++ might do the following:

    PIKSREFERENECLOCK RefClock;

    if (NT_SUCCESS (
      KsPinGetReferenceClockInterface (
        Pin,
        &RefClock)
) {
        … RefClock -> GetCorrelatedTime (…);
        RefClock -> Release ();
    }

a client written in C would instead do the following:

    PIKSREFERENCECLOCK RefClock;

    If (NT_SUCCESS (
      KsPinGetReferenceClockInterface (
        Pin,
        &RefClock)
    ) {
      … RefClock -> lpVtbl -> GetCorrelatedTime (…);
      RefClock -> lpVtbl -> Release ();
    }

See Also

KsPinGetConnectedPinInterface , KsPinGetConnectedFilterInterface, AVStream Overview


Stream Class Driver Routines

This section contains reference pages for the Microsoft®-supplied Stream Class driver routines.


StreamClassAbortOutstandingRequests

StreamClassAbortOutstandingRequests aborts all outstanding requests, either to a particular stream, or to the entire driver.

VOID
  StreamClassAbortOutstandingRequests(
    IN PVOID  HwDeviceExtension,
    IN PHW_STREAM_OBJECT  HwStreamObject,
    IN NTSTATUS  Status
    );

Parameters

HwDeviceExtension
Points to the minidriver's device extension.
HwStreamObject
Specifies what stream to abort requests on, or NULL to abort all requests to the minidriver.
Status
Status to be returned when the request is aborted.

Return Value

None

Headers

Declared in strmini.h. Include strmini.h.

Comments

This call also signals the class driver that the minidriver is ready to receive new requests of the type cancelled.

If the HwStreamObject parameter is NULL, all device and stream requests are cancelled.


StreamClassCallAtNewPriority

StreamClassCallAtNewPriority schedules a routine to be called at a different priority.

VOID
  StreamClassCallAtNewPriority(
    IN PHW_STREAM_OBJECT  StreamObject OPTIONAL,
    IN PVOID  HwDeviceExtension,
    IN STREAM_PRIORITY  Priority,
    IN PHW_PRIORITY_ROUTINE  PriorityRoutine,
    IN PVOID  Context
    );

Parameters

StreamObject
Specifies the stream is associated with the routine, or NULL if the routine is associated with the device as a whole. There can be at most one routine per stream, and one routine for the device.
HwDeviceExtension
Pointer to the minidriver's device extension.
Priority
Specifies one of the following values:
Priority | Usage
High | The stream class driver calls the routine at the same priority as the minidriver's StrMini Xxx callbacks. Do not use this setting, unless the routine must be synchronized with the minidriver's interrupt service routine.
Dispatch | The stream class driver calls the routine at DISPATCH_LEVEL. Use this priority if routine takes less than 1 millisecond to complete.
Low | The stream class driver calls the routine at PASSIVE_LEVEL. Use this priority if routine takes less than 1 millisecond to complete.
LowToHigh

PriorityRoutine
Routine to be called at the new priority level.
Context
Specifies the parameter to be passed to the routine.

Return Value

None

Headers

Declared in strmini.h. Include strmini.h.


StreamClassCompleteRequestAndMarkQueueReady

StreamClassCompleteRequestAndMarkQueueReady completes a request, and signals the class driver that the minidriver is ready to receive a new request of the same type.

VOID
  StreamClassCompleteRequestAndMarkQueueReady(
    IN PHW_STREAM_REQUEST_BLOCK  Srb
    );

Parameters

Srb
Pointer to the HW_STREAM_REQUEST_BLOCK that the minidriver has completed processing.

Return Value

None

Headers

Declared in strmini.h. Include strmini.h.

Comments

This call is equivalent to calling StreamClass Xxx Notification twice, once to signal that the request is completed, and once to signal that the minidriver is ready for the next request of that type.

See Also

StreamClassDeviceNotification, StreamClassStreamNotification


StreamClassDeviceNotification

Minidrivers use StreamClassDeviceNotification to notify the class driver that it has completed a stream request, or that an event has occurred.

VOID
  StreamClassDeviceNotification(
    IN STREAM_MINIDRIVER_DEVICE_NOTIFICATION_TYPE  NotificationType,
    IN PVOID  HwDeviceExtension,
    ...  /* Additional parameters, as required by NotificationType */
    /* For DeviceRequestComplete, add */
    PHW_STREAM_REQUEST_BLOCK  pSrb,
    /* For SignalDeviceEvent and DeleteDeviceEvent, add */
    PKSEVENT_ENTRY  EventEntry,
    /* For SignalMultipleDeviceEvents, add */
    GUID  *EventSet,
    ULONG  EventId
    );

Parameters

NotificationType
DeviceRequestComplete
Notify the class driver that the minidriver has completed its handling of the device stream request block the optional third argument of this routine, pSrb, points to. Once the minidriver calls this on an SRB, the SRB should be considered to be owned by the class driver, and may be de-allocated at any time.
ReadyForNextDeviceRequest
Notify the class driver that the minidriver is ready to receive another device request.
SignalDeviceEvent
Signal that the event specified by the EventEntry parameter has occurred.
SignalMultipleDeviceEvents
Signal all events that match the criteria specified in the EventSet and EventId parameters
DeleteDeviceEvent
Delete the event specified by the EventEntry parameter.
HwDeviceExtension
Pointer to the minidriver's device extension.
pSrb
If NotificationType equals DeviceRequestComplete, this parameter indicates to the class driver what stream request block the minidriver has completed processing. Once this routine completes, this address should be considered to be no longer valid.
EventEntry
If NotificationType equals either SignalDeviceEvent or DeleteDeviceEvent, this specifies the event to be signaled or deleted.
EventSet
If NotificationType equals SignalMultipleDeviceEvents, this parameter specifies the event set to match against in the device event queue.
EventId
If NotificationType equals SignalMultipleDeviceEvents, this parameter specifies the event ID to match against in the device event queue.

Return Value

None

Headers

Declared in strmini.h. Include strmini.h.

Comments

The minidriver uses this routine for requests or events that apply to the minidriver as a whole. Stream-specific requests or events use StreamClassStreamNotification.


StreamClassGetDmaBuffer

StreamClassGetDmaBuffer returns a pointer to the DMA buffer the class driver allocates for the minidriver.

PVOID
   StreamClassGetDmaBuffer(
    IN PVOID  HwDeviceExtension
    );

Parameters

HwDeviceExtension
Points to the minidriver's device extension.

Return Value

StreamClassGetDmaBuffer returns a pointer to the DMA buffer.

Headers

Declared in strmini.h. Include strmini.h.

See Also

The minidriver specifies the size of the DMA buffer in the DmaBufferSize member of its HW_INITIALIZATION_DATA structure.


StreamClassGetNextEvent

Minidrivers can use StreamClassGetNextEvent to walk the event queue for the device, or for a particular stream. The caller may specify additional search criteria to match events on the event queue.

PKSEVENT_ENTRY
  StreamClassGetNextEvent(
    IN PVOID  HwDeviceExtension,
    IN PHW_STREAM_OBJECT  HwStreamObject,
    IN OPTIONAL GUID  * EventGuid,
    IN OPTIONAL ULONG  EventItem,
    IN OPTIONAL PKSEVENT_ENTRY  CurrentEvent
    );

Parameters

HwDeviceExtension
Pointer to the minidriver's device extension.
HwStreamObject
To walk the event queue of a particular stream, the stream's stream object should be passed in this parameter. The caller should pass NULL to walk the event queue of the device itself.
EventGuid
Specifies the event set to match when walking the queue, or NULL to match any event set.
EventItem
Specifies the event id to match when walking the queue, or -1 to match any event.
CurrentEvent
Pointer to an event in the event queue, or NULL.

Return Value

If CurrentEvent is not NULL, StreamClassGetNextEvent returns the next matching event after CurrentEvent in the queue (or NULL if there is no such next event). If CurrentEvent is NULL, StreamClassGetNextEvent returns the first matching event in the queue.

Headers

Declared in strmini.h. Include strmini.h.

Comments

The minidriver can call StreamClassGetNextEvent successively to loop through the event queue, examining one event at a time.


StreamClassGetPhysicalAddress

StreamClassGetPhysicalAddress translates a virtual memory address to a physical memory address and locks the corresponding physical memory for a DMA operation.

STREAM_PHYSICAL_ADDRESS
  StreamClassGetPhysicalAddress(
    IN PVOID  HwDeviceExtension,
    IN PHW_STREAM_REQUEST_BLOCK  HwSRB OPTIONAL,
    IN PVOID  VirtualAddress,
    IN STREAM_BUFFER_TYPE  Type,
    OUT ULONG  *Length
    );

Parameters

HwDeviceExtension
Points to the minidriver's device extension.
HwSRB
Specifies a stream request block. Only used if the Type parameter has the value SRBDataBuffer, otherwise HwSRB should be NULL.
VirtualAddress
Specifies the virtual address to be translated.
Type
Specifies the type of buffer pointed to by VirtualAddress. May be one of PerRequestExtension, DmaBuffer, or SRBDataBuffer.
Length
StreamClassGetPhysicalAddress fills in this parameter with the length, in bytes, of the buffer.

Return Value

StreamClassGetPhysicalAddress returns the translated virtual address as a physical memory address.

Headers

Declared in strmini.h. Include strmini.h.

Comments

The type of buffer to be used is specified in the Type parameter. The meanings of these values are shown in the following table:

Buffer Type | Description
PerRequestExtension | Indicates the physical address of the SRB extension.
DmaBuffer | Indicates the physical address of the DMA buffer.
SRBDataBuffer | Indicates the physical address of the data buffer.


StreamClassQueryMasterClock

When the minidriver calls StreamClassQueryMasterClock, the class driver queries the appropriate time value of the master clock asynchronously, and passes the result to the routine passed in the ClockCallbackRoutine parameter.

VOID
  StreamClassQueryMasterClock(
    IN PHW_STREAM_OBJECT  HwStreamObject,
    IN HANDLE  MasterClockHandle,
    IN TIME_FUNCTION  TimeFunction,
    IN PHW_QUERY_CLOCK_ROUTINE  ClockCallbackRoutine
    );

Parameters

HwStreamObject
Pointer to the stream that is querying its master clock. The stream may only have one query pending at a time. The class driver passes this value to the callback in the HwStreamObject member of the callback's TimeContext parameter.
MasterClockHandle
Specifies the handle for the master clock we are querying. The class driver passes this in the SRB_INDICATE_MASTER_CLOCK request to the minidriver's StrMiniReceiveStreamControlPacket routine
TimeFunction
Specifies what time function to query the master clock for. See HW_TIME_CONTEXT for the possible values. The class driver passes this value to the callback in the Function member of the TimeContext parameter.
ClockCallbackRoutine
Specifies the routine the class driver will pass the results to. The function prototype must be:
    ClockCallbackRoutine(PHW_TIME_CONTEXT TimeContext);

Return Value

None

Headers

Declared in strmini.h. Include strmini.h.

Comments

The class driver queries the master clock and passes the results in the TimeContext parameter (of type HW_TIME_CONTEXT) of the callback. In particular, it sets the Time member of this structure to the time value requested in the TimeFunction parameter, the current system time in the SystemTime member of the same structure, and the minidriver's device extension in the HwDeviceExtension member of that structure.

The class driver deallocates the HW_TIME_CONTEXT structure once the clock callback routine completes, so the callback must store any information the minidriver wishes to maintain. For that purpose, the callback routine may use previously-allocated space in the either minidriver's device extension (TimeContext->HwDeviceExtension), or the stream extension of the stream that queried its master clock (TimeContext->HwStreamObject->HwStreamExtension).

See Also

HW_TIME_CONTEXT, StreamClassQueryMasterClockSync


StreamClassQueryMasterClockSync

The minidriver may call StreamClassQueryMasterClockSync to synchronously query a stream's master clock.

VOID STREAMAPI
  StreamClassQueryMasterClockSync(
    IN HANDLE  MasterClockHandle,
    IN OUT PHW_TIME_CONTEXT  TimeContext
    );

Parameters

MasterClockHandle
Specifies the handle for the master clock we are querying. The class driver passes this in the SRB_INDICATE_MASTER_CLOCK request to the minidriver's StrMiniReceiveStreamControlPacket routine
TimeContext
Specifies the HW_TIME_CONTEXT structure the class driver will pass to the master clock's StrMiniClock routine. Before calling this routine, the minidriver must fill in the HwDeviceExtension, HwStreamObject, and Function members of TimeContext. StreamClassQueryMasterClockSync completes the Time and SystemTime members.

Return Value

None

Headers

Declared in strmini.h. Include strmini.h.

Comments

The routine must be called at or below DISPATCH_LEVEL. If the caller is running at a raised IRQL, it should use the asynchronous version, StreamClassQueryMasterClock, instead.

The class driver calls the master clock's StrMiniClock routine to query the clock.

See Also

HW_TIME_CONTEXT, StreamClassQueryMasterClock


StreamClassReadWriteConfig

StreamClassReadWriteConfig reads or writes configuration data for the minidriver's parent bus driver.

BOOLEAN STREAMAPI
  StreamClassReadWriteConfig(
    IN PVOID  HwDeviceExtension,
    IN BOOLEAN  Read,
    IN PVOID  Buffer,
    IN ULONG  Offset,
    IN ULONG  Length
    );

Parameters

HwDeviceExtension
Pointer to the minidriver's device extension.
Read
The caller sets Read to TRUE to read the configuration information, and FALSE to write the configuration information.
Buffer
Points to the buffer to use to read/write the configuration information.
Offset
Specifies the offset within the configuration information to begin the read/write operation.
Length
Specifies the length of the data to read or write.

Return Value

Returns TRUE on success, FALSE on failure.

Headers

Declared in strmini.h. Include strmini.h.

Comments

This routine reads or writes configuration information for the minidriver's parent bus driver. For example, for a PCI device, StreamClassReadWriteConfig reads or writes PCI configuration information.

This routine can only be called at PASSIVE_LEVEL.


StreamClassReenumerateStreams

The minidriver may call StreamClassReenumerateStreams to cause the class driver to update its description of the streams the minidriver supports. The class driver will reissue a SRB_GET_STREAM_INFO request to the minidriver's StrMiniReceiveDevicePacket routine.

VOID
  StreamClassReenumerateStreams(
    IN PVOID  HwDeviceExtension,
    IN ULONG  StreamDescriptorSize
    );

Parameters

HwDeviceExtension
Pointer to the minidriver's device extension.
StreamDescriptorSize
Indicates the size of the buffer needed by the minidriver to hold the new HW_STREAM_DESCRIPTOR data.

Return Value

None

Headers

Declared in strmini.h. Include strmini.h.


StreamClassRegisterAdapter

This routine is obsolete. Use StreamClassRegisterMinidriver instead.


StreamClassRegisterMinidriver

StreamClassRegisterMinidriver registers a stream minidriver with the stream class driver. A stream minidriver must call StreamClassRegisterMinidriver within its DriverEntry routine.

NTSTATUS
  StreamClassRegisterMinidriver(
    IN PVOID  Argument1,
    IN PVOID  Argument2,
    IN PHW_INITIALIZATION_DATA  HwInitializationData
    );

Parameters

Argument1
Points to the first argument to the minidriver's DriverEntry routine.
Argument2
Points to the second argument to the minidriver's DriverEntry routine.
HwInitializationData
Points to an HW_INITIALIZATION_DATA structure that provides the information the class driver needs to begin initializing the minidriver.

Return Value

Returns STATUS_SUCCESS on success, or the appropriate error code on failure.

Headers

Declared in strmini.h. Include strmini.h.

Comments

Most of the information passed in the HW_INITIALIZATION_DATA structure informs the class driver of the minidriver-wide callbacks, and what size buffers to allocate for the minidriver's data structures. The class driver queries the minidriver for additional start-up information through SRB_INITIALIZE_DEVICE and SRB_GET_STREAM_INFO requests to the minidriver's StrMiniReceiveDevicePacket routine (passed as the HwReceivePacket member of HW_INITIALIZATION_DATA).

See Also

HW_INITIALIZATION_DATA


StreamClassRegisterFilterWithNoKSPins

The StreamClassRegisterFilterWithNoKSPins routine is used to register filter drivers with Microsoft® DirectShow® that have no kernel streaming pins and, therefore, do not stream in kernel mode.

NTSTATUS
  StreamClassRegisterFilterWithNoKSPins(
    IN PDEVICE_OBJECT  DeviceObject,
    IN const GUID  * InterfaceClassGUID,
    IN ULONG  PinCount,
    IN BOOL  * PinDirection,
    IN KSPIN_MEDIUM  * MediumList,
    IN OPTIONAL GUID  * CategoryList
    );

Parameters

DeviceObject
Points to the driver's device object.
InterfaceClassGUID
Specifies the interface class GUID to register.
PinCount
Specifies the number of pins on the filter.
PinDirection
Specifies an array of Boolean values, one for each pin on the filter.
MediumList
Specifies an array of KSPIN_MEDIUM structures, one for each pin on the filter.
CategoryList
If non-NULL, specifies an array of pin category GUIDs, one for each pin on the filter.

Return Value

Returns STATUS_SUCCESS on success, or the appropriate error code on failure.

Headers

Declared in strmini.h. Include strmini.h.


StreamClassScheduleTimer

The minidriver calls StreamClassScheduleTimer to schedule a timer, and a routine to be called when the timer expires.

VOID STREAMAPI
  StreamClassScheduleTimer(
    IN PHW_STREAM_OBJECT  StreamObject OPTIONAL,
    IN PVOID  HwDeviceExtension,
    IN ULONG  NumberOfMicroseconds,
    IN PHW_TIMER_ROUTINE  TimerRoutine,
    IN PVOID  Context
    );

Parameters

StreamObject
Specifies the stream that sets the timer, or NULL if the timer is set for the whole driver. The minidriver may only schedule one timer per stream, and one for the driver as a whole.
HwDeviceExtension
Pointer to the minidriver's device extension.
NumberOfMicroseconds
Specifies the amount of time, in microseconds, before the timer expires.
TimerRoutine
Specifies the routine called when the timer expires. The routine's prototype must be of the form:
    TimerRoutine(PVOID Context);
Context
The parameter the class driver passes to the routine once the timer expires.

Return Value

None

Headers

Declared in strmini.h. Include strmini.h.


StreamClassStreamNotification

Streams use StreamClassStreamNotification to notify the class driver that it has completed a stream request, or that an event has occurred.

VOID
  StreamClassStreamNotification(
    IN STREAM_MINIDRIVER_STREAM_NOTIFICATION_TYPE  NotificationType,
    IN PHW_STREAM_OBJECT  StreamObject,
    ...  /* Additional parameters, as required by NotificationType */
    /* For StreamRequestComplete, add */
    PHW_STREAM_REQUEST_BLOCK  pSrb,
    /* For SignalStreamEvent and DeleteStreamEvent add */
    PKSEVENT_ENTRY  EventEntry,
    /* For SignalMultipleStreamEvents, add */
    GUID  *EventSet,
    ULONG  EventId
    );

Parameters

NotificationType
StreamRequestComplete
Notify the class driver that the minidriver has completed its handling of the stream-oriented stream request block pointed to by the optional third argument of this routine.
ReadyForNextStreamDataRequest
Notify the class driver that this stream is ready to receive another data request.
ReadyForNextStreamControlRequest
Notify the class driver that this stream is ready to receive another control request.
SignalStreamEvent
Signal that the event specified by the EventEntry parameter has occurred.
SignalMultipleStreamEvents
Signal that all events that match the criteria specified in the EventSet and EventId parameters have occurred.
DeleteStreamEvent
Delete the event specified by the EventEntry parameter.
StreamObject
Points to the stream object of the stream we are notifying the class driver about.
pSrb
If NotificationType equals StreamRequestComplete, this parameter indicates to the class driver which stream request block the minidriver has completed processing. Once this routine completes, this address should be considered to be no longer valid.
EventEntry
If NotificationType equals either SignalStreamEvent or DeleteStreamEvent, then this specifies the event to be signaled or deleted.
EventSet
If NotificationType equals SignalMultipleStreamEvents, this parameter specifies the event set to match against in the event queue for this stream.
EventId
If NotificationType equals SignalMultipleStreamEvents, this parameter specifies the event ID to match against in the event queue for this stream.

Return Value

None

Headers

Declared in strmini.h. Include strmini.h.

Comments

The minidriver uses this routine for requests or events that apply to the minidriver as a whole. Stream-specific requests or events use StreamClassDeviceNotification.


Stream Class Structures

This section contains reference pages for the Microsoft®-supplied Stream Class structures.


HW_CLOCK_OBJECT

The HW_CLOCK_OBJECT structure describes the clock associated with a stream.

typedef struct _HW_CLOCK_OBJECT {
    PHW_CLOCK_FUNCTION  HwClockFunction;
    ULONG  ClockSupportFlags;
    ULONG  Reserved[2];
} HW_CLOCK_OBJECT, *PHW_CLOCK_OBJECT;

Members

HwClockFunction
Pointer to the stream's StrMiniClock routine.
ClockSupportFlags
Specifies which options the StrMiniClock routine supports.
CLOCK_SUPPORT_CAN_READ_ONBOARD_CLOCK
The StrMiniClock routine can return the current clock value for the stream's clock. The StrMiniClock routine must be able to handle a Function setting of TIME_READ_ONBOARD_CLOCK in the HW_TIME_CONTEXT structure passed as a parameter.
CLOCK_SUPPORT_CAN_RETURN_STREAM_TIME
The StrMiniClock routine can return the current presentation time stamp for the stream. The StrMiniClock routine must be able to handle a Function setting of TIME_GET_STREAM_TIME in the HW_TIME_CONTEXT structure passed as a parameter.
Reserved[2]
Reserved for system use. Do not use.

Headers

Declared in strmini.h. Include strmini.h.

See Also

HW_STREAM_OBJECT, StrMiniClock, HW_TIME_CONTEXT


HW_EVENT_DESCRIPTOR

When the class driver calls one of the minidriver's StrMiniEvent routines, it passes a pointer to an HW_EVENT_DESCRIPTOR structure to describe the event as enabled or disabled.

typedef struct _HW_EVENT_DESCRIPTOR {
    BOOLEAN                      Enable;
    PKSEVENT_ENTRY               EventEntry;
    PKSEVENTDATA                 EventData;
    union {
        struct _HW_STREAM_OBJECT    *StreamObject;
        struct _HW_DEVICE_EXTENSION *DeviceExtension;
    };
    ULONG                        EnableEventSetIndex;
    ULONG                        Reserved[2];
} HW_EVENT_DESCRIPTOR, *PHW_EVENT_DESCRIPTOR;

Members

Enable
This is set to TRUE for an enabled event, and FALSE for a disabled event.
EventEntry
Points to the KSEVENT_ENTRY structure that describes this event.
EventData
Points to the KSEVENTDATA structure that describes this instance of the event.
StreamObject
Points to the stream object for the stream that owns the event that the class driver is enabling/disabling, or NULL if the event belongs to the driver as a whole.
DeviceExtension
Points to the minidriver's device extension.
EnableEventSetIndex
For stream events, this specifies the index of the event set within the StreamEventsArray member of the stream's HW_STREAM_INFORMATION structure.

For device events, this specifies the index of the event set within the DeviceEventsArray member of the minidriver's HW_STREAM_HEADER structure.

Reserved[2]
Reserved for system use. Do not use.

Headers

Declared in strmini.h. Include strmini.h.


HW_INITIALIZATION_DATA

The HW_INITIALIZATION_DATA structure specifies the basic information the class driver needs to begin initializing the minidriver. The minidriver passes an HW_INITIALIZATION_DATA structure to the class driver when it registers itself by calling StreamClassRegisterMinidriver.

typedef struct HW_INITIALIZATION_DATA {
    ULONG  HwInitializationDataSize;
    PHW_INTERRUPT  HwInterrupt;
    PHW_RECEIVE_DEVICE_SRB  HwReceivePacket;
    PHW_CANCEL_SRB  HwCancelPacket;
    PHW_REQUEST_TIMEOUT_HANDLER  HwRequestTimeoutHandler;
    ULONG  DeviceExtensionSize;
    ULONG  PerRequestExtensionSize;
    ULONG  PerStreamExtensionSize;
    ULONG  FilterInstanceExtensionSize;
    BOOLEAN  BusMasterDMA;
    BOOLEAN  Dma24BitAddresses;
    ULONG  BufferAlignment;
    BOOLEAN  TurnOffSynchronization;
    ULONG  DmaBufferSize;
    ULONG  Reserved[2];
} HW_INITIALIZATION_DATA, *PHW_INITIALIZATION_DATA;

Members

HwInitializationDataSize
Specifies the size of this data structure, in bytes.
HwInterrupt
Points to the minidriver's StrMiniInterrupt routine.
HwReceivePacket
Points to the minidriver's StrMiniReceiveDevicePacket routine.
HwCancelPacket
Points to the minidriver's StrMiniCancelPacket routine.
HwRequestTimeoutHandler
Points to the minidriver's StrMiniRequestTimeout routine.
DeviceExtensionSize
Specifies the size of the buffer the class driver should allocate for the minidriver's device extension. The minidriver may use this buffer to record private information global to the minidriver. The class driver passes pointers to this buffer in the HwDeviceExtension member of HW_STREAM_OBJECT, HW_STREAM_REQUEST_BLOCK, HW_TIME_CONTEXT, and PORT_CONFIGURATION_INFORMATION structures it passes to the minidriver.
PerRequestExtensionSize
Specifies the size of the buffer the class driver should allocate for the buffer pointed to by SRBExtension member of HW_STREAM_REQUEST_BLOCK structures it passes to the minidriver. The class driver will allocate one buffer for each HW_STREAM_REQUEST_BLOCK.
PerStreamExtensionSize
Specifies the size of the buffer the class driver should allocate for the buffer pointed to by the HwStreamExtension member of a stream's HW_STREAM_OBJECT. The class driver will allocate one buffer for each stream.
FilterInstanceExtensionSize
Specifies the size of the buffer the class extension should allocate for the buffer pointed to by the HwInstanceExtension member of HW_STREAM_REQUEST_BLOCK structures it passes to the minidriver. The class driver allocates one buffer for each instance of the minidriver.
BusMasterDMA
If TRUE, the device can perform direct bus master DMA to the minidriver's DMA buffer.
Dma24BitAddresses
Minidrivers should set this to TRUE if the DMA hardware the devices uses can access only the lower 24 bits of the address space.
BufferAlignment
Specifies the alignment requirement for DMA buffers. For example, a value of 4 indicates the DMA buffers should be aligned on 4-byte boundaries.
TurnOffSynchronization
If TRUE, the minidriver will handle its own synchronization; otherwise the class driver handles synchronization. Most minidrivers should set this value to FALSE. See Minidriver Synchronization in the Streaming Minidriver Design Guide for more information.
DmaBufferSize
Specifies the size of the DMA buffer the class driver should allocate for the minidriver. The minidriver gets a pointer to this buffer by calling StreamClassGetDmaBuffer. The class driver allocates contiguous non-pageable memory that will not be available to the operating system, or to other drivers, so this value should be as small as possible.
Reserved[2]
Reserved for system use. Minidrivers should ignore this member.

Headers

Declared in strmini.h. Include strmini.h.


HW_STREAM_DESCRIPTOR

The minidriver uses the HW_STREAM_DESCRIPTOR structure to return stream information to the stream class driver.

typedef struct _HW_STREAM_DESCRIPTOR {
    HW_STREAM_HEADER  StreamHeader;
    HW_STREAM_INFORMATION  StreamInfo;
}  HW_STREAM_DESCRIPTOR, *PHW_STREAM_DESCRIPTOR;

Members

StreamHeader
Contains the header for the stream descriptor.
StreamInfo
Contains the stream information block for the zero stream.

Headers

Declared in strmini.h. Include strmini.h.

Comments

The minidriver builds this structure and returns it to the class driver in response to a SRB_GET_STREAM_INFO request. The class driver makes this request by calling the minidriver's StrMiniDeviceRequestPacket routine.

The class driver expects HW_STREAM_DESCRIPTOR to be laid out in memory as an HW_STREAM_HEADER followed by an array of HW_STREAM_INFORMATION structures. The array begins at the address of the StreamInfo member. The HW_STREAM_HEADER's NumberOfStreams member indicates the number of entries in the array. The minidriver uses HW_STREAM_HEADER to describe those kernel streaming properties of the driver as a whole, while each HW_STREAM_INFORMATION structure describes each individual stream the device supports.

See Also

HW_STREAM_HEADER, HW_STREAM_INFORMATION


HW_STREAM_HEADER

The HW_STREAM_HEADER structure describes the kernel streaming semantics supported by the minidriver as a whole, as part of a HW_STREAM_DESCRIPTOR structure.

typedef struct _HW_STREAM_HEADER {
    ULONG  NumberOfStreams;
    ULONG  SizeOfHwStreamInformation;
    ULONG  NumDevPropArrayEntries;
    PKSPROPERTY_SET  DevicePropertiesArray;
    ULONG  NumDevEventArrayEntries;
    PKSEVENT_SET  DeviceEventsArray;
    PKSTOPOLOGY  Topology;
    PHW_EVENT_ROUTINE  DeviceEventRoutine
    ULONG  Reserved[2];
} HW_STREAM_HEADER, *PHW_STREAM_HEADER;

Members

NumberOfStreams
The number of HW_STREAM_INFORMATION structures that follow this header.
SizeOfHwStreamInformation
The size, in bytes, of the HW_STREAM_INFORMATION structure.
NumDevPropArrayEntries
The number of entries in the array pointed to by DevicePropertiesArray.
DevicePropertiesArray
Pointer to the beginning of the array of property sets that the minidriver as a whole supports. (Property sets supported by individual streams can be found in the StreamPropertiesArray member of the stream's HW_STREAM_INFORMATION structure.)
NumDevEventArrayEntries
The number of entries in the array pointed to by DeviceEventsArray.
DeviceEventsArray
Pointer to the beginning of the array of event sets supported by the minidriver.
Topology
Pointer to the KSTOPOLOGY structure that describes the minidriver's internal topology of nodes and pins. The class driver uses this to handle the KSPROPSETID_Topology property set for the minidriver.
DeviceEventRoutine
Points to the minidriver's StrMiniEvent routine.
Reserved
Reserved for system use. Do not use.

Headers

Declared in strmini.h. Include strmini.h.

See Also

HW_STREAM_INFORMATION, HW_STREAM_DESCRIPTOR


HW_STREAM_INFORMATION

The HW_STREAM_INFORMATION structure describes the kernel streaming semantics supported by individual streams, as part of an HW_STREAM_DESCRIPTOR structure.

typedef struct _HW_STREAM_INFORMATION {
    ULONG  NumberOfPossibleInstances;
    KSPIN_DATAFLOW  DataFlow;
    BOOLEAN  DataAccessible;
    ULONG  NumberOfFormatArrayEntries;
    PKSDATARANGE*  StreamFormatsArray;
    PVOID  ClassReserved[4];
    ULONG  NumStreamPropArrayEntries;
    PKSPROPERTY_SET  StreamPropertiesArray;
    ULONG  NumStreamEventArrayEntries;
    PKSEVENT_SET  StreamEventsArray;
    GUID*  Category;
    GUID*  Name;
    ULONG  MediumsCount;
    const KSPIN_MEDIUM*  Mediums;
    BOOLEAN  BridgeStream;
    ULONG  Reserved[2];
} HW_STREAM_INFORMATION, *PHW_STREAM_INFORMATION;

Members

NumberOfPossibleInstances
Specifies the number of possible instances of this stream that can be opened.
DataFlow
The direction that data can travel on this stream. For unidirectional data flow, DataFlow has the value KSPIN_DATAFLOW_IN or KSPIN_DATAFLOW_OUT. For bidirectional data flow, DataFlow has the value KSPIN_DATAFLOW_FULLDUPLEX.
DataAccessible
Specifies whether the stream data is accessible to the class driver.
NumberOfFormatArrayEntries
The number of entries in the array that begins at the address in the StreamFormatsArray member.
StreamFormatsArray
Pointer to the beginning of the array of data ranges that this stream supports. (The name of this member is deceptive. This member points to an array of KSDATARANGE structures, not KSDATAFORMAT structures.)
ClassReserved[4]
Reserved for use by the class driver. Do not use.
NumStreamPropArrayEntries
The number of entries in the array that begins at the address in the StreamPropertiesArray member.
StreamPropertiesArray
Pointer to the beginning of the array of property sets supported by this stream.
NumStreamEventArrayEntries
The number of entries in the array that begins at the address in the StreamEventsArray field.
StreamEventsArray
Pointer to the beginning of the array of event sets supported by this stream.
Category
Specifies the GUID of the pin category.
Name
Specifies the GUID of the localized Unicode string name for the pin type, stored in the Registry.
MediumsCount
The number of entries in the array that begins at the address in the Mediums field.
Mediums
Pointer to the beginning of the array of media supported by this stream. If the minidriver does not specify a medium, the class driver uses the KSMEDIUMSETID_STANDARD, KSMEDIUM_TYPE_ANYINSTANCE medium as the default.
BridgeStream
If TRUE, the communications type of this stream's underlying pin type is KSPIN_COMMUNICATION_BRIDGE. Otherwise, the default communications type of a stream is KSPIN_COMMUNICATION_SINK.

Most minidrivers will set this member to FALSE. See KSPROPERTY_PIN_COMMUNICATIONS for a description of communication types.

Reserved[2]
Reserved for system use. Do not use.

Headers

Declared in strmini.h. Include strmini.h.

Comments

The class driver uses the elements of HW_STREAM_INFORMATION to handle the KSPROPSETID_Pin property requests. The index within the HW_STREAM_DESCRIPTOR structure serves as the pin type ID number.

Note that the class driver does not use this data to handle the KSPROPERTY_PIN_DATAINTERSECTION property. See STREAM_DATA_INTERSECT_INFO for a description of how the class driver handles this property.

See Also

HW_STREAM_DESCRIPTOR, HW_STREAM_HEADER


HW_STREAM_OBJECT

HW_STREAM_OBJECT describes an instance of a minidriver stream.

typedef struct _HW_STREAM_OBJECT {
    ULONG  SizeOfThisPacket;
    ULONG  StreamNumber;
    PVOID  HwStreamExtension;
    PHW_RECEIVE_STREAM_DATA_SRB  ReceiveDataPacket;
    PHW_RECEIVE_STREAM_CONTROL_SRB  ReceiveControlPacket;
    HW_CLOCK_OBJECT  HwClockObject;
    BOOLEAN  Dma;
    BOOLEAN  Pio;
    PVOID  HwDeviceExtension;
    ULONG  StreamHeaderMediaSpecific;
    ULONG  StreamHeaderWorkspace;
    BOOLEAN  Allocator;
    PHW_EVENT_ROUTINE  HwEventRoutine;
    ULONG  Reserved[2];
} HW_STREAM_OBJECT, *PHW_STREAM_OBJECT;

Members

SizeOfThisPacket
Specifies the size, in bytes, of this structure.
StreamNumber
Specifies the offset of the stream within the minidriver's HW_STREAM_DESCRIPTOR structure.
HwStreamExtension
Points to the stream extension, a buffer allocated by the class driver for the minidriver to use to hold private information about this stream. The minidriver sets the size of the buffer in the HW_INITIALIZATION_DATA structure it passes when it registers itself with the stream class driver.
ReceiveDataPacket
Pointer to the stream's StrMiniReceiveStreamDataPacket routine.
ReceiveControlPacket
Pointer to the stream's StrMiniReceiveStreamControlPacket routine.
HwClockObject
Contains the stream's clock object. See HW_CLOCK_OBJECT for details.
Dma
If TRUE, the device uses DMA to transfer data for this stream.
Pio
If TRUE, the device uses programmed I/O to transfer data for this stream. Note that both the Pio and Dma members may be TRUE.
HwDeviceExtension
Pointer to the minidriver's device extension. The minidriver may use this buffer to record private information global to the minidriver. The minidriver sets the size of this buffer in the HW_INITIALIZATION_DATA structure it passes when it registers itself via StreamClassRegisterMinidriver. The class driver also passes pointers to this buffer in the HwDeviceExtension member of the HW_STREAM_REQUEST_BLOCK, HW_TIME_CONTEXT, and PORT_CONFIGURATION_INFORMATION structures it passes to the minidriver.
StreamHeaderMediaSpecific
Specifies the size of the media-specific, per-stream header extension.

StreamHeaderWorkspace
Specifies the size of the per-stream-header workspace.
Allocator
Specifies whether the driver uses allocators. Most minidrivers set this value to FALSE.
HwEventRoutine
Pointer to the stream's StrMiniEvent routine
Reserved[2]
Reserved for system use. Do not use.

Headers

Declared in strmini.h. Include strmini.h.

Comments

This structure is created by the class driver to hold information about a particular stream in the minidriver. For each stream-specific request, the class driver passes the HW_STREAM_OBJECT for the stream in the StreamObject member of the stream request block (See HW_STREAM_REQUEST_BLOCK).

When the class driver opens the stream and issues the SRB_OPEN_STREAM request to the minidriver's StrMiniReceiveDevicePacket routine, the minidriver initializes the stream object.

See Also

HW_CLOCK_OBJECT


HW_STREAM_REQUEST_BLOCK

The stream class driver uses the HW_STREAM_REQUEST_BLOCK structure to pass information to and from the minidriver, using minidriver provided callbacks.

typedef struct _HW_STREAM_REQUEST_BLOCK {
    ULONG              SizeOfThisPacket;
    SRB_COMMAND        Command;
    NTSTATUS           Status;
    PHW_STREAM_OBJECT  StreamObject;
    PVOID              HwDeviceExtension;
    PVOID              SRBExtension;

    union _CommandData {
        PKSSTREAM_HEADER              DataBufferArray;
        PHW_STREAM_DESCRIPTOR         StreamBuffer;
        KSSTATE                       StreamState;
        PSTREAM_PROPERTY_DESCRIPTOR   PropertyInfo;
        PKSDATAFORMAT                 OpenFormat;
        struct _PORT_CONFIGURATION_INFORMATION  *ConfigInfo;
        HANDLE                        MasterClockHandle;
        DEVICE_POWER_STATE            DeviceState;
        PSTREAM_DATA_INTERSECT_INFO   IntersectInfo;
    } CommandData;

    ULONG            NumberOfBuffers;
    ULONG            TimeoutCounter;
    ULONG            TimeoutOriginal;
    struct _HW_STREAM_REQUEST_BLOCK   *NextSRB;
    PIRP             Irp;
    ULONG            Flags;
    PVOID            HwInstanceExtension;

    union {
        ULONG   NumberOfBytesToTransfer;
        ULONG   ActualBytesTransferred;
    };

    PKSSCATTER_GATHER   ScatterGatherBuffer
    ULONG               NumberOfPhysicalPages;
    ULONG               Reserved[2];
} HW_STREAM_REQUEST_BLOCK, *PHW_STREAM_REQUEST_BLOCK;

Members

SizeOfThisPacket
Specifies the size, in bytes, of this structure.
Command
Specifies the operation to be performed by the minidriver's callback. The class driver passes certain of the SRB_XXX command codes to each type of minidriver callback.
Status
When the minidriver completes this stream request, it fills this member with the status code of the request. See the documentation for the appropriate StrMini Xxx Request routine for the status codes minidrivers are expected to use.
StreamObject
For stream oriented requests, the class driver sets this to point to the HW_STREAM_OBJECT structure that specifies the stream the class driver is making a request on.
HwDeviceExtension
Pointer to the minidriver's device extension. The minidriver may use this buffer to record private information global to the minidriver. The minidriver sets the size of this buffer in the HW_INITIALIZATION_DATA structure it passes when it registers itself via StreamClassRegisterMinidriver. The class driver also passes pointers to this buffer in the HwDeviceExtension member of the HW_STREAM_OBJECT, HW_TIME_CONTEXT, and PORT_CONFIGURATION_INFORMATION structures it passes to the minidriver.
SRBExtension
Points to an uninitialized buffer the class driver allocates for the minidriver to use while processing this stream request block. This buffer is deallocated once the minidriver completes its handling of the block (see StreamClassDeviceNotification or StreamClassStreamNotification for details).
CommandData
CommandData is a union of members provided for command-code-specific data. The following demonstrates the correspondence between members and command codes.
Member | Command code | Description
DataBufferArray SRB_READ_DATA

SRB_WRITE_DATA

 Pointer to an array of KSSTREAM_HEADER structures. The number of entries in this array is specified in NumberOfBuffers. Each KSSTREAM_HEADER describes one block of data.
StreamBuffer SRB_GET_STREAM_INFO Points to the HW_STREAM_DESCRIPTOR structure the minidriver fills in with a description of the kernel streaming semantics it supports.

The minidriver specifies the size of this buffer in the StreamDescriptorSize member of its PORT_CONFIGURATION_INFORMATION structure.
StreamState SRB_GET_STREAM_STATE

SRB_SET_STREAM_STATE

 The stream state. See KSPROPERTY_CONNECTION_STATE for details.
PropertyInfo SRB_GET_DEVICE_PROPERTY

SRB_SET_DEVICE_PROPERTY

SRB_GET_STREAM_PROPERTY

SRB_SET_STREAM_PROPERTY

 Points to the STREAM_PROPERTY_DESCRIPTOR structure that specifies the parameters for the property get or set operation.
OpenFormat SRB_OPEN_STREAM

SRB_PROPOSE_DATA_FORMAT

 Pointer to the KSDATAFORMAT structure that specifies the format.
ConfigInfo | SRB_INITIALIZE_DEVICE | Pointer to the PORT_CONFIGURATION_INFORMATION structure used to initialize the device
MasterClockHandle SRB_OPEN_MASTER_CLOCK

SRB_INDICATE_MASTER_CLOCK

 Handle for the clock object that now serves as the master clock.
DeviceState | SRB_CHANGE_POWER_STATE | Specifies the new power state.
IntersectInfo | SRB_GET_DATA_INTERSECTION | Pointer to a STREAM_DATA_INTERSECT_INFO structure that describes the parameters of this operation.

NumberOfBuffers
If Command is either SRB_READ_DATA or SRB_WRITE_DATA, then this specifies the number of entries in the array of KSSTREAM_HEADER structures that begins at the address pointed to by CommandData.DataBufferArray. Otherwise this parameter is unused.
TimeoutCounter
The number of seconds before this request times out. The class driver decrements this once per second. If the class driver decrements TimeoutCounter to zero before the minidriver completes this request, it will call the minidriver's StrMiniRequestTimeout routine. If the minidriver sets this to zero, the request does not time out.
TimeoutOriginal
The class driver sets this to the original value of TimeoutCounter upon the creation of the SRB.
NextSRB
Points to another stream request block. The minidriver can use this member to queue stream request blocks.
Irp
Pointer to the IRP for the request. Most minidrivers do not need to use this member.
Flags
Specifies the type of request. The class driver and the minidriver can use this member to determine which callback the class driver passed this stream request block to.
Value | Callback used
None | StrMiniReceiveDevicePacket
SRB_HW_FLAGS_STREAM_REQUEST | StrMiniReceiveStreamControlPacket
SRB_HW_FLAGS_DATA_TRANSFER | SRB_HW_FLAGS_STREAM_REQUEST | StrMiniReceiveStreamDataPacket

SRB_HW_FLAGS_STREAM_REQUEST bit is set for stream-specific requests (which are passed to the minidriver's StrMiniReceiveStream Xxx Packet routines). The SRB_HW_FLAGS_DATA_TRANSFER bit is set for data transfer requests (which are passed to the minidriver's

HwInstanceExtension
Pointer to the minidriver's instance extension. The minidriver may use this buffer to record private information global to this instance of the minidriver. The minidriver sets the size of this buffer in the HW_INITIALIZATION_DATA structure it passes when it registers itself via StreamClassRegisterMinidriver.
NumberOfBytesToTransfer
For a SRB_READ_DATA or SRB_WRITE_DATA request, the number of bytes to be transferred.
ActualBytesTransferred
For control requests, the number of bytes actually transferred.
ScatterGatherBuffer
Points to an array of KSSCATTER_GATHER structures, of the form:
typedef struct {
    PHYSICAL_ADDRESS PhysicalAddress;
    ULONG Length;
} KSSCATTER_GATHER, *PKSSCATTER_GATHER;

The array describes a scatter/gather list that can be used by the minidriver to do DMA. The memory does not need to be probed, locked, mapped, or flushed — the stream class driver performs these for the minidriver.

NumberOfPhysicalPages
Specifies the size of the array passed in the ScatterGatherBuffer member.
Reserved[2]
Reserved for system use. Do not use.

Headers

Declared in strmini.h. Include strmini.h.

Comments

The stream class driver passes pointers to HW_STREAM_REQUEST_BLOCK structures to the minidriver's StrMiniReceiveStreamDataPacket, StrMiniReceiveStreamControlPacket, and StrMiniReceiveDevicePacket routines.

The minidriver owns this stream request block until the request times out or it completes the request. The minidriver signals to the class driver that it has completed the request by calling StreamClassDeviceNotification(DeviceRequestComplete, pSrb->HwDeviceExtension, pSRB) for device-specific requests, or calling StreamClassStreamNotification(StreamRequestComplete, pSrb->StreamObject, pSrb) for stream-specific requests. (The minidriver can also complete a request by calling StreamClassCompleteRequestAndMarkQueueReady(pSrb). See that routine for details.)

If the class driver times out the request, it will call the minidriver's StrMiniRequestTimeout routine, which has the responsibility of terminating processing of the request. If the minidriver queues a request for later processing, it should set the TimeoutCounter member to zero, which will prevent the class driver from timing out the request. Once the minidriver is ready to resume processing the request, it should reset the TimeoutCounter member to the value of TimeoutOriginal.


HW_TIME_CONTEXT

The class driver passes an HW_TIME_CONTEXT structure as a parameter to be filled in by a stream's StrMiniClock routine, or returns a completed HW_TIME_CONTEXT structure when it responds to a StreamClassQueryMasterClock or StreamClassQueryMasterClockSync request.

typedef struct _HW_TIME_CONTEXT {
    struct _HW_DEVICE_EXTENSION  *HwDeviceExtension;
    struct _HW_STREAM_OBJECT  *HwStreamObject;
    TIME_FUNCTION  Function;
    ULONGLONG  Time;
    ULONGLONG  SystemTime;
} HW_TIME_CONTEXT, *PHW_TIME_CONTEXT;

Members

HwDeviceExtension
Points to the minidriver's device extension buffer. The class driver fills in this member when it passes the structure to a stream's StrMiniClock, or to the callback passed to StreamClassQueryMasterClock. When passed as a parameter to StreamClassQueryMasterClockSync, the caller must fill in this member itself.

The minidriver may use its device extension to record private information global to the minidriver. The minidriver sets the size of this buffer in the HW_INITIALIZATION_DATA structure it passes when it registers itself via StreamClassRegisterMinidriver. The class driver also passes pointers to this buffer in the HwDeviceExtension member of the HW_STREAM_OBJECT, HW_STREAM_REQUEST_BLOCK, and PORT_CONFIGURATION_INFORMATION structures it passes to the minidriver.

HwStreamObject
When the class driver passes HW_TIME_CONTEXT to a stream's StrMiniClock routine, this member points to the stream's HW_STREAM_OBJECT structure.

When the class driver passes a completed HW_TIME_CONTEXT structure to the callback provided by StreamClassQueryMasterClock, it fills in this member with a pointer to the stream object of the stream that makes the query request.

Function
Specifies the type of time value that is stored in the Time member. The possible values are:
TIME_GET_STREAM_TIME
The Time member holds the current presentation time stamp.
TIME_READ_ONBOARD_CLOCK
The Time member holds the current clock time.
Time
The time value, in 100-nanosecond units, specified by the Function member.
SystemTime
The current system time, in 100-nanosecond units.

Headers

Declared in strmini.h. Include strmini.h.

See Also

HW_CLOCK_OBJECT, StreamClassQueryMasterClock, StreamClassQueryMasterClockSync, StrMiniClock


PORT_CONFIGURATION_INFORMATION

PORT_CONFIGURATION_INFORMATION describes the hardware settings of a streaming minidriver's device. The class driver fills in most members with information provided by the operating system.

typedef struct _PORT_CONFIGURATION_INFORMATION {
    ULONG  SizeOfThisPacket;
    PVOID  HwDeviceExtension;
    PDEVICE_OBJECT  ClassDeviceObject;
    PDEVICE_OBJECT  PhysicalDeviceObject;
    ULONG  SystemIoBusNumber;
    INTERFACE_TYPE  AdapterInterfaceType;
    ULONG  BusInterruptLevel;
    ULONG  BusInterruptVector;
    KINTERRUPT_MODE  InterruptMode;
    ULONG  DmaChannel;
    ULONG  NumberOfAccessRanges;
    PACCESS_RANGE  AccessRanges;
    ULONG  StreamDescriptorSize;
    PIRP  Irp;
    PKINTERRUPT  InterruptObject;
    PADAPTER_OBJECT  DmaAdapterObject;
    PDEVICE_OBJECT  RealPhysicalDeviceObject;
    ULONG  Reserved[1];
} PORT_CONFIGURATION_INFORMATION, PPORT_CONFIGURATION_INFORMATION;

Members

SizeOfThisPacket
The size of this structure, in bytes. The class driver fills in this member.
HwDeviceExtension
Pointer to the minidriver's device extension. The minidriver may use this buffer to record private information global to the minidriver. The minidriver sets the size of this buffer in the HW_INITIALIZATION_DATA structure it passes when it registers itself via StreamClassRegisterMinidriver. The class driver also passes pointers to this buffer in the HwDeviceExtension member of the HW_STREAM_OBJECT, HW_STREAM_REQUEST_BLOCK, and HW_TIME_CONTEXT structures it passes to the minidriver.
ClassDeviceObject
Points to the class-driver-provided functional device object (FDO) for the driver's device.
PhysicalDeviceObject
Points to the device object for the driver at the top of the driver stack when the class driver attaches to the driver stack. Drivers use this member when calling IoCallDriver to communicate with the driver stack. The RealPhysicalDeviceObject member points to the actual PDO for the driver's device.
SystemIoBusNumber
The class driver fills in this member with the system bus ID number of the device. Bus 0 is the primary system bus.
AdapterInterfaceType
Specifies the type of system bus the device is connected to. Possible values include Isa, Eisa, MicroChannel, PCIBus, and PCMCIABus.
BusInterruptLevel
The class driver fills in this member with the IRQL for interrupts on this bus.
BusInterruptVector
The class driver fills in this member with the interrupt vector used by the device.
InterruptMode
The class driver fills in this member with the interrupt mode, either Latched or LevelSensitive.
DmaChannel
If the device connects to the ISA bus, the class driver fills in this member with the DMA channel of the device.
NumberOfAccessRanges
The number of entries in the AccessRanges array.
AccessRanges
An array of ACCESS_RANGE structures. Each structure describes a range of hardware resources, such as I/O port or memory ranges.
StreamDescriptorSize
The minidriver fills in this member with the size of its HW_STREAM_DESCRIPTOR structure.
Irp
Pointer to the PnP device start IRP that triggered this SRB_INITIALIZE_DEVICE request.
InterruptObject
If the device uses interrupts, the class driver fills in this member with a pointer to the associated Interrupt object.
DmaAdapterObject
If the device uses DMA, the class driver fills in this member with a pointer to the associated DmaAdapter object.
RealPhysicalDeviceObject
Pointer to the PDO for the driver's device.
Reserved
Reserved for system use. Do not use.

Headers

Declared in strmini.h. Include strmini.h.

Comments

Most of the members of PORT_CONFIGURATION_INFORMATION provide information to the minidriver about its use of hardware resources, such as its interrupt vector and the IRQL for its interrupts.


STREAM_DATA_INTERSECT_INFO

STREAM_DATA_INTERSECT_INFO describes the parameters of a data intersection operation.

typedef struct _STREAM_DATA_INTERSECT_INFO {
    ULONG  StreamNumber;
    PKSDATARANGE  DataRange;
    PVOID  DataFormatBuffer;
    ULONG  SizeOfDataFormatBuffer;
}  STREAM_DATA_INTERSECT_INFO, *PSTREAM_DATA_INTERSECT_INFO;

Members

StreamNumber
Specifies the stream number. This corresponds to the offset of the stream within the minidriver's array of HW_STREAM_INFORMATION structures. The possible data formats depend on the stream type.
DataRange
Pointer to the data ranges to be examined for a match.
DataFormatBuffer
Pointer to the buffer the minidriver fills in with the matching data format.
SizeOfDataFormatBuffer
Specifies the size in bytes of the DataFormatBuffer.

Headers

Declared in strmini.h. Include strmini.h.

Comments

The class driver passes this data structure when it submits a SRB_GET_DATA_INTERSECTION request to the minidriver's StrMiniReceiveDevicePacket.


STREAM_PROPERTY_DESCRIPTOR

STREAM_PROPERTY_DESCRIPTOR specifies the parameters of property get/set requests that the class driver passes to the minidriver.

typedef struct _STREAM_PROPERTY_DESCRIPTOR {
    PKSPROPERTY  Property;
    ULONG  PropertySetID;
    PVOID  PropertyInfo;
    ULONG  PropertyInputSize;
    ULONG  PropertyOutputSize;
}  STREAM_PROPERTY_DESCRIPTOR, *PSTREAM_PROPERTY_DESCRIPTOR;

Members

Property
Specifies the property to be read/written.
PropertySetID
Specifies the index of the property set within either the HW_STREAM_HEADER's DevicePropertiesArray (for minidriver properties) or the HW_STREAM_INFORMATION's StreamPropertiesArray (for stream properties).
PropertyInfo
Points to a buffer that the property data will be read from or written to.
PropertyInputSize
Size of the Property buffer.
PropertyOutputSize
Size of the PropertyInfo buffer.

Headers

Declared in strmini.h. Include strmini.h.


Stream Minidriver Routines

The following are all routines that a stream minidriver must provide. The stream class driver calls these routines to handle minidriver-specific actions.


StrMiniCancelPacket

The class driver calls the minidriver's StrMiniCancelPacket routine to signal that a stream request has been cancelled.

VOID STREAMAPI
  StrMiniCancelPacket(
    IN PHW_STREAM_REQUEST_BLOCK  pSrb
    );

Parameters

pSrb
Pointer to the stream request that had been cancelled.

Return Value

None

Headers

Declared in strmini.h. Include strmini.h.

Comments

The minidriver specifies this routine in the HwCancelPacket member of its HW_INITIALIZATION_DATA structure. The minidriver passes this structure to the class driver when it registers itself by calling StreamClassRegisterMinidriver.

Minidrivers that rely on the class driver to handle synchronization should, once they have successfully cancelled a request, signal to the class driver that they are ready for another request by using StreamClassStreamNotification or StreamClassDeviceNotification with the appropriate ReadyForNext Xxx Request.


StrMiniClock

Each stream may have a clock associated to it. The class driver queries the clock by calling the stream-supplied StrMiniClock function, provided in each stream's HW_STREAM_OBJECT.

VOID STREAMAPI
  StrMiniClock(
    IN PHW_TIME_CONTEXT  HwTimeContext
    );

Parameters

HwTimeContext
Pointer to the HW_TIME_CONTEXT structure that StrMiniClock must fill out with the requested information.

Return Value

None

Headers

Declared in strmini.h. Include strmini.h.

Comments

A stream specifies its StrMiniClock function within the HwClockFunction member of the HW_CLOCK_OBJECT substructure of its HW_STREAM_OBJECT. The minidriver fills out the HW_STREAM_OBJECT for a stream within its StrMiniReceiveDevicePacket routine in response to a SRB_OPEN_STREAM request.

When the class driver calls StrMiniClock, it fills in the HwDeviceExtension, HwStreamObject, and Function members of the HwTimeContext parameter. It expects StrMiniClock to fill in the Time member with the time value, in 100-nanosecond units, specified in the Function parameter. StrMiniClock must also fill in the SystemTime member with the current system time, by calling KeQueryPerformanceCounter, and converting the result to 100-nanosecond units.

The StrMiniClock routine must handle the functions specified in the ClockSupportFlags of the clock's HW_CLOCK_OBJECT. See HW_CLOCK_OBJECT for details.

See Also

HW_CLOCK_OBJECT, HW_TIME_CONTEXT


StrMiniEvent

The class driver calls StrMiniEvent to signal to a minidriver an event should be enabled or disabled.

NTSTATUS STREAMAPI
  StrMiniEvent(
    IN PHW_EVENT_DESCRIPTOR  EventDescriptor
    );

Parameters

EventDescriptor
Describes the event, and whether it should be enabled or disabled.

Return Value

For event enable events, StrMiniEvent returns STATUS_SUCCESS if the event is successfully enabled, or an error code on failure. The class driver ignores the return value on disable requests.

Headers

Declared in strmini.h. Include strmini.h.

Comments

The class driver queues the KSEVENT_ENTRY structure it passes in EventDescriptor->EventEntry. Every other member of EventDescriptor is deallocated once StrMiniEvent exits, so any event-specific data contained in the EventData member of EventDescriptor that the minidriver needs to keep should be stored by the minidriver.

For that purpose, the minidriver can allocate space directly after the KSEVENT_ENTRY structure by providing a non-zero value in the ExtraEntryData member of the KSEVENT_ITEM structure it used to declare the event.


StrMiniInterrupt

StrMiniInterrupt is the minidriver's interrupt service routine.

BOOLEAN STREAMAPI
  StrMiniInterrupt(
    PVOID  DeviceExtension
    );

Parameters

DeviceExtension
Pointer to the minidriver's device extension.

Return Value

StrMiniInterrupt returns TRUE if the device generated the interrupt, and FALSE otherwise.

Headers

Declared in strmini.h. Include strmini.h.

Comments

The class driver calls StrMiniInterrupt each time it receives an interrupt on behalf of the minidriver.

An interrupt may be shared among several different devices. The minidriver's StrMiniInterrupt routine must determine if its underlying hardware actually generated the interrupt. If the device did not generate the interrupt, StrMiniInterrupt should return FALSE as soon as possible — for shared interrupts, the operating system calls the interrupt service routines registered for that interrupt until one of the routines returns TRUE, so the ISR may keep the actual device that generated the interrupt waiting if it takes too long to complete.


StrMiniReceiveDevicePacket

VOID STREAMAPI
  StrMiniReceiveDevicePacket(
    IN OUT PHW_STREAM_REQUEST_BLOCK  pSRB
    );

Parameters

pSRB
Pointer to the stream request block.

Return Value

None

Headers

Declared in strmini.h. Include strmini.h.

Comments

The minidriver specifies this routine in the HwRequestTimeout member of its HW_INITIALIZATION_DATA structure. The minidriver passes this structure to the class driver when it registers itself by calling StreamClassRegisterMinidriver.

StrMiniReceiveDevicePacket must handle class driver requests that apply to the driver as a whole, such as initializing the device, or opening a stream within the device. The class driver passes its information in the form of a pointer to a stream request block. The class driver fills in some of the entries in the stream request block. The minidriver, upon completion of the routine, must fill in additional information that the class driver will use to continue processing.

Upon completion of its handling of the request, the minidriver passes the structure back to the class driver by calling StreamClassDeviceNotification (DeviceRequestComplete, pSRB->HwDeviceExtension, pSRB).

See information on relevant SRB codes in Stream Class SRB Reference.

When the minidriver finishes its processing of the request, it enters the return status of the operation in pSRB->Status. The minidriver should enter STATUS_SUCCESS for normal successful processing. If the minidriver does not support that Command value, it should set pSRB->Status to STATUS_NOT_IMPLEMENTED. If there is a device hardware error that prevents the minidriver from completing the request, it should set pSRB->Status to STATUS_IO_DEVICE_ERROR. Other error codes the routine uses in specific circumstances are listed above with the specific Command code.


StrMiniReceiveStreamControlPacket

VOID STREAMAPI
  StrMiniReceiveStreamControlPacket(
    IN OUT PHW_STREAM_REQUEST_BLOCK  pSRB
    );

Parameters

pSRB
Pointer to the stream request block.

Return Value

None

Headers

Declared in strmini.h. Include strmini.h.

Comments

The stream class driver calls the minidriver's StrMiniReceiveStreamControlPacket routine to handle I/O requests for a specific stream (except read and write requests, which the class driver passes to the StrMiniReceiveStreamDataPacket routine).

The minidriver registers its StrMiniReceiveStreamControlPacket routine as follows: When the class driver opens the stream, it passes an SRB_OPEN_STREAM request block to the minidriver's StrMiniReceiveDevicePacket routine. The StreamObject member of the request packet points to an HW_STREAM_OBJECT. The minidriver sets the ReceiveControlPacket member of the structure pointed to by StreamObject to the minidriver's StrMiniReceiveControlPacket routine.

Upon completion of its handling of the request, the minidriver passes the structure back to the class driver by calling StreamClassStreamNotification (StreamRequestComplete, pSRB->StreamObject, pSRB).

See information on relevant SRB codes in Stream Class SRB Reference.

When the minidriver finishes its processing of the request, it enters the return status of the operation in pSRB->Status. The minidriver should enter STATUS_SUCCESS for normal successful processing. If the minidriver does not support that Command value, it should set pSRB->Status to STATUS_NOT_IMPLEMENTED. If there is a device hardware error that prevents the minidriver from completing the request, it should set pSRB->Status to STATUS_IO_DEVICE_ERROR. Other error codes the routine uses in specific circumstances are listed above with the specific Command code.


StrMiniReceiveStreamDataPacket

VOID STREAMAPI
  StrMiniReceiveStreamDataPacket(
    IN OUT PHW_STREAM_REQUEST_BLOCK  pSRB
    );

Parameters

pSRB
Pointer to the stream request block.

Return Value

None

Headers

Declared in strmini.h. Include strmini.h.

Comments

The stream class driver calls the minidriver's StrMiniReceiveStreamDataPacket routine to handle read and write requests for a specific stream.

The minidriver registers its StrMiniReceiveStreamDataPacket routine as follows: When the class driver opens the stream, it passes a SRB_OPEN_STREAM request block to the minidriver's StrMiniReceiveDevicePacket routine. The StreamObject of the request packet points to a HW_STREAM_OBJECT. The minidriver sets the ReceiveDataPacket member of the structure pointed to by pSRB->StreamObject to the minidriver's StrMiniReceiveDataPacket routine.

Upon completion of its handling of the request, the minidriver passes the structure back to the class driver by calling StreamClassStreamNotification (StreamRequestComplete, pSRB->StreamObject, pSRB).

See information on relevant SRB codes in Stream Class SRB Reference.

When the minidriver finishes its processing of the request, it enters the return status of the operation in pSRB->Status. The minidriver should enter STATUS_SUCCESS for normal successful processing. If the minidriver does not support that Command value, it should set pSRB->Status to STATUS_NOT_IMPLEMENTED. If there is a device hardware error that prevents the minidriver from completing the request, it should set pSRB->Status to STATUS_IO_DEVICE_ERROR. Other error codes the routine uses in specific circumstances are listed above with the specific Command code.


StrMiniRequestTimeout

The stream class driver calls the minidriver's StrMiniRequestTimeout routine to signal to the minidriver that a request has timed out.

VOID STREAMAPI
  StrMiniRequestTimeout(
    IN PHW_REQUEST_BLOCK  pSrb
    );

Parameters

pSrb
Pointer to the stream request that has timed out.

Return Value

None

Headers

Declared in strmini.h. Include strmini.h.

Comments

The minidriver specifies this routine in the HwRequestTimeoutHandler member of its HW_INITIALIZATION_DATA structure. The minidriver passes this structure to the class driver when it registers itself by calling StreamClassRegisterMinidriver.

When the class driver first issues a request, it sets a timeout value (in seconds) with the TimeoutCounter member of the HW_STREAM_REQUEST_BLOCK pointed to by pSrb. The class driver decrements the TimeoutCounter member of that structure once a second. A request times out when the class driver decrements TimeoutCounter to zero, at which time the class driver calls StrMiniRequestTimeout to handle any clean-up necessary to cease processing the request.

Minidrivers that rely on the class driver to handle synchronization should, once they have successfully handled the request timeout, signal to the class driver that they are ready for another request by using StreamClassStreamNotification or StreamClassDeviceNotification with the appropriate ReadyForNext Xxx Request.


Stream Class SRB Reference

The class driver uses the HW_STREAM_REQUEST_BLOCK structure to pass SRB requests to the minidriver. In this reference section, pSRB refers to a pointer to a HW_STREAM_REQUEST_BLOCK object. The stream class driver passes this pointer when it calls minidriver-provided callbacks.

SRB requests are either device/instance-specific or stream-specific. Depending on the SRB command, additional parameters may be passed in the HW_STREAM_REQUEST_BLOCK.

See Device-Specific Command Codes and Stream-Specific Command Codes.


Device-Specific Command Codes

The following SRB commands are device-specific:

SRB_CHANGE_POWER_STATE

SRB_CLOSE_DEVICE_INSTANCE

SRB_CLOSE_STREAM

SRB_GET_DATA_INTERSECTION

SRB_GET_DEVICE_PROPERTY

SRB_GET_STREAM_INFO

SRB_INITIALIZATION_COMPLETE

SRB_INITIALIZE_DEVICE

SRB_OPEN_DEVICE_INSTANCE

SRB_OPEN_STREAM

SRB_PAGING_OUT_DRIVER

SRB_SET_DEVICE_PROPERTY

SRB_SURPRISE_REMOVAL

SRB_UNINITIALIZE_DEVICE

SRB_UNKNOWN_DEVICE_COMMAND


SRB_CHANGE_POWER_STATE

The class driver sends this request to signal to the minidriver that it should reset its power state. pSRB->DeviceState specifies the new power state. See HW_STREAM_REQUEST_BLOCK.

Return Value

The minidriver should set one of the following as the status in the SRB:

STATUS_SUCCESS
Indicates successful completion of the command.
STATUS_NOT_IMPLEMENTED
Indicates that the function is not supported by the minidriver.
STATUS_IO_DEVICE_ERROR
Indicates that a hardware failure occurred and low power cannot be invoked.

Comments

For more information on power states, see Managing Power for Individual Devices.


SRB_CLOSE_DEVICE_INSTANCE

The class driver sends this request to close a previously opened instance of the adapter.

Return Value

The minidriver should set one of the following as the status in the SRB:

STATUS_SUCCESS
Indicates successful completion of the command.
STATUS_NOT_IMPLEMENTED
Indicates that the function is not supported by the minidriver.
STATUS_IO_DEVICE_ERROR
Indicates that a hardware failure occurred.

Comments

Most adapters do not support multiple instances, so in those cases the FilterInstanceExtensionSize field in the HW_INITIALIZATION_DATA structure should be set to zero and should never receive this command.


SRB_CLOSE_STREAM

The class driver sends this request to close a stream.

Return Value

The minidriver should set one of the following as the status in the SRB:

STATUS_SUCCESS
Indicates successful completion of the command.
STATUS_NOT_IMPLEMENTED
Indicates that the function is not supported by the minidriver.
STATUS_IO_DEVICE_ERROR
Indicates that a hardware failure occurred.

Comments

The class driver provides a HW_STREAM_OBJECT buffer in pSRB->StreamObject, with pSRB->StreamObject->StreamNumber set to the number of the stream to be closed. The pSRB pointer points to a HW_STREAM_REQUEST_BLOCK structure. StreamNumber corresponds to the offset of the stream within the HW_STREAM_DESCRIPTOR structure that the minidriver provides in response to a SRB_GET_STREAM_INFO request.

If the minidriver successfully closes the stream, the minidriver returns STATUS_SUCCESS. Otherwise, it returns an appropriate error status.

When the SRB_CLOSE_STREAM command is received by the minidriver, the responding minidriver routine should:

  1. Free any resources allocated by the minidriver when the stream was opened.
  2. Stop referencing the clock if a clock was used for the stream.
  3. Reset the stream state to Stop.

Note that a stream could be closed arbitrarily while streaming if an associated user-mode application crashes. Therefore, you must release all outstanding resources for the stream, complete all pending SRBs for the stream, and put the stream back into a quiescent state.


SRB_GET_DATA_INTERSECTION

The class driver sends this request to query the minidriver for the best-matching data format in a data range.

Return Value

The minidriver should set one of the following as the status in the SRB:

STATUS_SUCCESS
Indicates that a match was found.

Comments

pSRB->CommandData.IntersectInfo specifies both the data range to search for a match and the buffer to return the format. The pSRB pointer points to a HW_STREAM_REQUEST_BLOCK structure. (The IntersectInfo member is of type pointer to a STREAM_DATA_INTERSECT_INFO structure.)

The class driver uses this request to satisfy KSPROPERTY_PIN_DATAINTERSECTION property requests. The class drivers feeds one KSDATARANGE at a time to the minidriver until the minidriver returns the request with a pSRB->Status value of STATUS_SUCCESS. The minidriver checks for a match in DataRange.Specifier values.

Generally, the resulting data format is immediately used to open a stream in that format. For more information on data formats and data ranges, see Format Negotiation and Data Intersections.


SRB_GET_DEVICE_PROPERTY

The class driver sends this request to query the minidriver for the data necessary to complete a property get request on a minidriver-defined property.

Return Value

The minidriver should set one of the following as the status in the SRB:

STATUS_SUCCESS
Indicates successful completion of the command.
STATUS_NOT_IMPLEMENTED
Indicates that the function is not supported by the minidriver.
STATUS_IO_DEVICE_ERROR
Indicates that a hardware failure occurred.

Comments

The class driver passes the parameters of the operation in the pSRB->CommandData.PropertyInfo buffer, a structure of the form STREAM_PROPERTY_DESCRIPTOR. The pSRB pointer points to a HW_STREAM_REQUEST_BLOCK structure. The Property member of STREAM_PROPERTY_DESCRIPTOR describes the property in question, while the PropertyInfo member specifies a buffer to copy the property data into. If the buffer is too small, the minidriver should set the Status member of pSRB to STATUS_BUFFER_OVERFLOW.

For more information on property sets, see KS Properties.

See Also

STREAM_PROPERTY_DESCRIPTOR


SRB_GET_STREAM_INFO

The class driver sends this request to obtain a description of the device and the streams it supports.

Return Value

The minidriver should set one of the following as the status in the SRB:

STATUS_SUCCESS
Indicates successful completion of the command.
STATUS_IO_DEVICE_ERROR
Indicates that a hardware failure occurred.

Comments

The class driver passes a buffer in pSRB->CommandData.StreamBuffer of the size specified by the minidriver in response to the class driver's SRB_INITIALIZE_DEVICE request. The pSRB pointer points to a HW_STREAM_REQUEST_BLOCK structure. Also see PORT_CONFIGURATION_INFORMATION.

The minidriver fills CommandData.StreamBuffer with an HW_STREAM_DESCRIPTOR that describes the device and the streams it supports. The size of this buffer is indicated by the minidriver in the StreamDescriptorSize field in the PORT_CONFIGURATION_INFORMATION structure.

The class driver normally issues this request only once. The minidriver may force the class driver to reissue this request, to update its description of the supported streams, by calling StreamClassReenumerateStreams.

When the SRB_GET_STREAM_INFO command is received by the minidriver, the minidriver should:

  1. Retrieve the pointers for the stream header and the stream information data structures. For example:
     PHW_STREAM_HEADER pstrhdr =
  (PHW_STREAM_HEADER)&(pSrb->CommandData.StreamBuffer->StreamHeader);
 PHW_STREAM_INFORMATION pstrinfo =
  (PHW_STREAM_INFORMATION)&(pSrb->CommandData.StreamBuffer->StreamInfo);
  2. Verify that the buffer is large enough to hold the returned data.
  3. Write the information to the buffer.


SRB_INITIALIZATION_COMPLETE

The class driver sends this request to signal the minidriver that it has completed its initialization.

Comments

Once the minidriver completes this request, the class driver can begin to send SRB_OPEN_STREAM requests.

When this SRB is received by the minidriver, the minidriver should create any necessary Registry entries. For example, a DirectShow filter might register a TV tuner or Crossbar for use with the FilterGraph using the StreamClassRegisterFilterWithNoKSPins routine.


SRB_INITIALIZE_DEVICE

The class driver sends this request when it begins initializing the minidriver's hardware.

Return Value

The minidriver should set one of the following as the status in the SRB:

STATUS_SUCCESS
Indicates that a host adapter was found and the configuration information was successfully determined.
STATUS_IO_DEVICE_ERROR
Indicates that a host adapter was found, but there was an error in obtaining the configuration information. If possible, the error should be logged.
STATUS_NO_SUCH_DEVICE
Indicates that the supplied configuration information was invalid.

Comments

The class driver passes a pointer to a PORT_CONFIGURATION_INFORMATION structure in pSRB->CommandData.ConfigInfo. The pSRB pointer points to a HW_STREAM_REQUEST_BLOCK structure. The class driver fills out most fields in pSRB->CommandData.ConfigInfo with information that it gets about the device from the operating system. Under most circumstances, the minidriver only needs to fill in the StreamDescriptorSize member of ConfigInfo with the size of its HW_STREAM_DESCRIPTOR structure.


SRB_OPEN_DEVICE_INSTANCE

The class driver sends this request to open an instance of the adapter.

Return Value

The minidriver should set one of the following as the status in the SRB:

STATUS_SUCCESS
Indicates successful completion of the command.
STATUS_NOT_IMPLEMENTED
Indicates that the function is not supported by the minidriver.
STATUS_TOO_MANY_NODES
Indicates that there are not enough resources to open this stream.
STATUS_IO_DEVICE_ERROR
Indicates that a hardware failure occurred.

Comments

If the minidriver supports multiple instances of a device, this command is sent by the class driver each time a new instance of the adapter is opened. As an example, consider a DSP decoder that can allocate n number of instances of the streams specified. The HwInstanceExtension field in the SRB should then be set to the minidriver's per-instance workspace by the class driver.

Most adapters do not support multiple instances, so in those cases the FilterInstanceExtensionSize field in the HW_INITIALIZATION_DATA structure should be set to zero and should never receive this command.

See Also

SRB_CLOSE_DEVICE_INSTANCE


SRB_OPEN_STREAM

The class driver sends this request to open a stream.

Return Value

The minidriver should set one of the following as the status in the SRB:

STATUS_SUCCESS
Indicates successful completion of the command.
STATUS_NOT_IMPLEMENTED
Indicates that the function is not supported by the minidriver.
STATUS_TOO_MANY_NODES
Indicates that there are not enough resources to open this stream.
STATUS_IO_DEVICE_ERROR
Indicates that a hardware failure occurred.

Comments

The class driver provides a HW_STREAM_OBJECT buffer in pSRB->StreamObject, with pSRB->StreamObject->StreamNumber set to the number of the stream to be opened. The pSRB pointer points to a HW_STREAM_REQUEST_BLOCK structure. StreamNumber corresponds to the offset of the stream within the HW_STREAM_DESCRIPTOR structure the minidriver provides in response to a SRB_GET_STREAM_INFO request. The class driver specifies the data format that the opened stream should provide in pSRB->CommandData->OpenFormat.

When the minidriver receives this request, it should determine if the specified stream can be opened at this time. The minidriver should also verify the KSDATAFORMAT format passed in. the SRB's OpenFormat field. If the stream can be opened, the minidriver updates the HW_STREAM_OBJECT structure, and returns STATUS_SUCCESS. If the maximum number of stream instances are already open, or the hardware resources necessary to open this stream are unavailable, the minidriver returns an appropriate error status.

When the SRB_OPEN_STREAM command is received by the minidriver, the minidriver should:

  1. Check that the maximum number of stream instances has not been exceeded and that the stream index value is valid.
  2. Check that the data format requested is valid for this stream.
  3. Set the format for the stream.
  4. Maintain an array of all the stream extension structures in the device extension so that IRPs can be cancelled from any stream.
  5. Specify pointers, in the stream object, to the stream data handlers and control handlers.
  6. Set the DMA flag in the stream object if the device will perform DMA directly to the data buffer addresses passed into the ReceiveDataPacket routines. If the driver accesses data buffers passed in using logical addressing, also set the PIO flag in the stream object.
  7. If clock support is available on the stream, indicate this through the HwClockObject member in the stream object.


SRB_PAGING_OUT_DRIVER

The class driver sends this request to signal that it is about to page out the minidriver.

Return Value

The minidriver should set one of the following as the status in the SRB:

STATUS_SUCCESS
Indicates successful completion of the command.

Comments

The class driver only attempts to page out the minidriver if it has no open streams or devices. Though it is unlikely that a minidriver would have pending callbacks in this state, the minidriver should cancel any outstanding callbacks upon receipt of this SRB. The minidriver should disable adapter interrupts and then return STATUS_SUCCESS.

The class driver pages out the minidriver only if the minidriver turns on this feature. The minidriver enables this feature by setting the registry variable PageOutWhenUnopened to 1 in the device's INF file. See the sample streaming minidriver's INFs for more information.


SRB_SET_DEVICE_PROPERTY

The class driver sends this request to query the minidriver for the data necessary to complete a property set request on a minidriver-defined property.

Return Value

The minidriver should set one of the following as the status in the SRB:

STATUS_SUCCESS
Indicates successful completion of the command.
STATUS_NOT_IMPLEMENTED
Indicates that the function is not supported by the minidriver.
STATUS_IO_DEVICE_ERROR
Indicates that a hardware failure occurred.

Comments

The class driver passes the parameters of the operation in the pSRB->CommandData.PropertyInfo buffer, a structure of the form STREAM_PROPERTY_DESCRIPTOR. The pSRB pointer points to a HW_STREAM_REQUEST_BLOCK structure. The Property member of STREAM_PROPERTY_DESCRIPTOR describes the property in question, while the PropertyInfo member specifies a buffer from which to copy the property data. If the buffer is too small, the minidriver should set the Status member pointed to by pSRB to STATUS_BUFFER_OVERFLOW.

For more information on property sets, see KS Properties.

See Also

STREAM_PROPERTY_DESCRIPTOR


SRB_SURPRISE_REMOVAL

The class driver sends this request when a device has been unexpectedly removed (surprise removal) from the computer. For more information, see Removing a Device.


SRB_UNINITIALIZE_DEVICE

The class driver sends this request to signal the minidriver to disable itself.

Return Value

The minidriver should set one of the following as the status in the SRB:

STATUS_SUCCESS
Indicates successful completion of the command.
STATUS_NOT_IMPLEMENTED
Indicates that the function is not supported by the minidriver.
STATUS_ADAPTER_HARDWARE_ERROR
Indicates that the minidriver cannot uninitialize at this time.

Comments

The minidriver should deallocate any resources it allocated, and disable the device's interrupts. (The class driver automatically deallocates any resources it allocated on behalf of the minidriver.)


SRB_UNKNOWN_DEVICE_COMMAND

The class driver sends this request to pass IRPs that it does not know how to handle to the minidriver. pSRB->Irp points to the unhandled IRP. See HW_STREAM_REQUEST_BLOCK.

This request can be used as an IRP pass-through mechanism for IRPs that the stream class does not understand, but that the minidriver might. For example, there are several PNP IRPs that the stream class does not process, but that a 1394 camera driver does.


Stream-Specific Command Codes

Stream-specific command codes are defined for a previously opened stream. The StreamObject field in the SRB specifies the stream on which to carry out the specified command.

The stream-specific SRB command codes, with underlying structures shown in the topic, are:

SRB_CLOSE_MASTER_CLOCK

SRB_GET_DATA_FORMAT

SRB_GET_STREAM_PROPERTY

SRB_GET_STREAM_STATE

SRB_INDICATE_MASTER_CLOCK

SRB_OPEN_MASTER_CLOCK

SRB_PROPOSE_DATA_FORMAT

SRB_PROPOSE_STREAM_RATE

SRB_READ_DATA

SRB_SET_DATA_FORMAT

SRB_SET_STREAM_PROPERTY

SRB_SET_STREAM_RATE

SRB_SET_STREAM_STATE

SRB_WRITE_DATA

SRB_UNKNOWN_STREAM_COMMAND


SRB_CLOSE_MASTER_CLOCK

The class driver issues this request to indicate to a stream that it is no longer the master clock for the minidriver.

Return codes

The minidriver should set one of the following as the status in the SRB:

STATUS_SUCCESS
Indicates successful completion of the command.
STATUS_NOT_IMPLEMENTED
Indicates that the function is not supported by the minidriver.
STATUS_IO_DEVICE_ERROR
Indicates that a hardware failure occurred.


SRB_GET_DATA_FORMAT

The class driver issues this request to query the data format for the stream. The minidriver should set pSRB->CommandData to the current data format for the stream.

For more information on data formats, see the Stream Minidriver Design Guide.


SRB_GET_STREAM_PROPERTY

The class driver sends this request to query the minidriver for the data necessary to complete a property get request on a minidriver-defined property for this stream.

Return Value

The minidriver should set one of the following as the status in the SRB:

STATUS_SUCCESS
Indicates successful completion of the command.
STATUS_NOT_IMPLEMENTED
Indicates that the function is not supported by the minidriver.
STATUS_IO_DEVICE_ERROR
Indicates that a hardware failure occurred.

Comments

The class driver passes the parameters of the operation in the pSRB->CommandData.PropertyInfo buffer, a structure of the form STREAM_PROPERTY_DESCRIPTOR. The pSRB pointer points to a HW_STREAM_REQUEST_BLOCK structure.

The Property member of the STREAM_PROPERTY_DESCRIPTOR structure describes the property in question, while the PropertyInfo member specifies a buffer to copy the property data into. If the buffer is too small, the minidriver should set the Status member pointed to by pSRB to STATUS_BUFFER_OVERFLOW.

See Also

SRB_SET_STREAM_PROPERTY, STREAM_PROPERTY_DESCRIPTOR


SRB_GET_STREAM_STATE

The class driver sends this request to get the stream state for this stream. The minidriver enters the stream state in pSRB->CommandData.StreamState. See KSPROPERTY_CONNECTION_STATE for a description of stream states.


SRB_INDICATE_MASTER_CLOCK

The class driver issues this request to indicate to a stream the handle for the clock object that now serves as its master clock, or a zero handle to indicate the stream is free running.

Return Value

The minidriver should set one of the following as the status in the SRB:

STATUS_SUCCESS
Indicates successful completion of the command.
STATUS_NOT_IMPLEMENTED
Indicates that the function is not supported by the minidriver.
STATUS_IO_DEVICE_ERROR
Indicates that a hardware failure occurred.

Comments

The class driver sets the CommandData.MasterClockHandle member pointed to by pSRB to the handle for the clock object that represents the master clock. The pSRB pointer points to a HW_STREAM_REQUEST_BLOCK structure.

A stream may query the time value of the master clock by passing the master clock handle to StreamClassQueryMasterClock or StreamClassQueryMasterClockSync.

Until the minidriver receives a SRB_INDICATE_MASTER_CLOCK for a particular stream, it can assume that the stream is free running. If the handle passed in this SRB for a slave pin is the same as the handle passed to the minidriver in SRB_OPEN_MASTER_CLOCK, the minidriver can read the time directly from the master clock because it controls the master and the slave.

The minidriver should retain the CommandData.MasterClockHandle field in the SRB that points to the handle for the master clock. If this handle is zero, it indicates to the minidriver that this stream is now free running and cannot be a slave to a master clock.


SRB_OPEN_MASTER_CLOCK

The class driver issues this request to indicate to a stream that it now serves as the master clock for the minidriver.

Return Value

The minidriver should set one of the following as the status in the SRB:

STATUS_SUCCESS
Indicates successful completion of the command.
STATUS_NOT_IMPLEMENTED
Indicates that the function is not supported by the minidriver.
STATUS_IO_DEVICE_ERROR
Indicates that a hardware failure occurred.

Comments

The class driver sets the CommandData.MasterClockHandle member pointed to by pSRB to the handle for the clock object it creates to represent the master clock. The pSRB pointer points to a HW_STREAM_REQUEST_BLOCK structure.

The minidriver should retain the CommandData.MasterClockHandle field value in the SRB that points to the handle of the master clock.


SRB_PROPOSE_DATA_FORMAT

The class driver issues this request to determine if the stream supports a given data format.

Return codes

The minidriver should set one of the following as the status in the SRB:

STATUS_SUCCESS
Indicates successful completion of the command.
STATUS_NOT_IMPLEMENTED
Indicates that the function is not supported by the minidriver.
STATUS_NOT_SUPPORTED
Indicates that the proposed format is not supported by the minidriver.
STATUS_IO_DEVICE_ERROR
Indicates that a hardware failure occurred.

Comments

When the class driver receives a KSPROPERTY_CONNECTION_PROPOSEDATAFORMAT request, it uses this SRB code to determine whether the proposed format is supported. The class driver passes the proposed data format in the CommandData.OpenFormat member pointed to by pSRB. The pSRB pointer points to a HW_STREAM_REQUEST_BLOCK structure.

If the minidriver does not support the data format, it sets pSRB->Status to STATUS_NOT_SUPPORTED. If the minidriver is able to switch the stream to the specified format, it sets this field to STATUS_SUCCESS.

If the minidriver is able to accept the new format, the class driver at some later time may send the minidriver a format change, which is indicated by the OptionsFlags member in a KSSTREAM_HEADER structure.

See Also

SRB_SET_DATA_FORMAT, SRB_GET_DATA_FORMAT


SRB_PROPOSE_STREAM_RATE

The SRB_PROPOSE_STREAM_RATE command proposes a new rate but does not change it.


SRB_READ_DATA

The class driver has received a read request for the minidriver.

Return Value

The minidriver can set one of the following as the status in the SRB, or it can pass additional error codes to indicate error situations such as memory errors and bad parameters. The class driver checks only for STATUS_SUCCESS.

STATUS_SUCCESS
Indicates successful completion of the command.
STATUS_NOT_IMPLEMENTED
Indicates that the function is not supported by the minidriver.
STATUS_IO_DEVICE_ERROR
Indicates that a hardware failure occurred.

Comments

The value of pSRB->CommandData.DataBufferArray points to an array of KSSTREAM_HEADER structures, which together describe the data buffer. The pSRB pointer points to a HW_STREAM_REQUEST_BLOCK structure. pSRB->CommandData.NumberOfBuffers specifies the size of the array.

When the SRB_READ_DATA command is received by the minidriver, the responding minidriver routine should:

  1. Check to determine the current stream state. The minidriver should only accept read requests when in either the Pause or Run state. If the stream is stopped, it should immediately complete and return the SRB.
  2. Place the SRB in the queue.


SRB_SET_DATA_FORMAT

The class driver issues this request to set the data format for the stream.

Return Value

STATUS_SUCCESS
Indicates successful completion of the command.
STATUS_NOT_SUPPORTED
Indicates that the minidriver does not support the requested data format.

Comments

The class driver passes the new data format in the CommandData.OpenFormat member of the pSRB pointer. (This pointer points to a HW_STREAM_REQUEST_BLOCK structure.)

For more information on data formats, see the Stream Minidriver Design Guide.


SRB_SET_STREAM_PROPERTY

The class driver sends this request to query the minidriver for the data necessary to complete a property set request on a minidriver-defined property for this stream.

Return Value

The minidriver should set one of the following as the status in the SRB:

STATUS_SUCCESS
Indicates successful completion of the command.
STATUS_NOT_IMPLEMENTED
Indicates that the function is not supported by the minidriver.
STATUS_IO_DEVICE_ERROR
Indicates that a hardware failure occurred.

Comments

The class driver passes the parameters of the operation in the pSRB->CommandData.PropertyInfo buffer, a structure of the form STREAM_PROPERTY_DESCRIPTOR. The pSRB pointer points to a HW_STREAM_REQUEST_BLOCK structure.

The Property member of STREAM_PROPERTY_DESCRIPTOR describes the property in question, while the PropertyInfo member specifies a buffer from which to copy the property data. If the buffer is too small, the minidriver should set the Status member pointed to by pSRB to STATUS_BUFFER_OVERFLOW.

See Also

SRB_GET_STREAM_PROPERTY, STREAM_PROPERTY_DESCRIPTOR


SRB_SET_STREAM_RATE

The SRB_SET_STREAM_RATE command sets the rate at which a stream should run.


SRB_SET_STREAM_STATE

The class driver sends this request to set the stream state for this stream.

Return Value

The minidriver should set one of the following as the status in the SRB:

STATUS_SUCCESS
Indicates successful completion of the command.
STATUS_NOT_IMPLEMENTED
Indicates that the function is not supported by the minidriver.
STATUS_IO_DEVICE_ERROR
Indicates that a hardware failure occurred.

Comments

The class driver specifies the new stream state in pSRB->CommandData.StreamState. The pSRB pointer points to a HW_STREAM_REQUEST_BLOCK structure. See KSPROPERTY_CONNECTION_STATE for a description of stream states.

The minidriver should set the stream to the specified state and return STATUS_SUCCESS if successful. An appropriate error code should be returned if the operation fails.

See Also

SRB_GET_STREAM_STATE


SRB_UNKNOWN_STREAM_COMMAND

When the class driver receives an IRP for a stream of a type it does not handle, it hands it off to the minidriver with the SRB_UNKNOWN_STREAM_COMMAND code.


SRB_WRITE_DATA

The class driver has received a write request for the minidriver. The value of pSRB->CommandData.DataBufferArray points to an array of KSSTREAM_HEADER structures, which together describe the data buffer. The value of pSRB->CommandData.NumberOfBuffers specifies the size of the array. The pSRB pointer points to a HW_STREAM_REQUEST_BLOCK structure.

Return Value

The minidriver can set one of the following as status in the SRB, or it can pass additional error codes to indicate error situations such as memory errors and bad parameters. The class driver is concerned only with STATUS_SUCCESS.

STATUS_SUCCESS
Indicates successful completion of the command.
STATUS_NOT_IMPLEMENTED
Indicates that the function is not supported by the minidriver.
STATUS_IO_DEVICE_ERROR
Indicates that a hardware failure occurred.

See Also

SRB_SET_STREAM_STATE


Audio Drivers Property Sets

This section describes the audio-specific property sets that are available for audio drivers that use WDM kernel-streaming services in Microsoft® Windows® 98/Me, and Windows 2000 and later.

The reference page for each property contains a table with the column headings that are shown below.

Get Set Target Property descriptor type Property value type

These headings have the following meanings:

  • Get

    Does the target KS object support the KSPROPERTY_TYPE_GET property request? (Yes or no.)

  • Set

    Does the target KS object support the KSPROPERTY_TYPE_SET property request? (Yes or no.)

  • Target

    This is the KS object to which property request is sent. The target for an audio property is either a filter or a pin. (The property request specifies the target object by its kernel handle.)

  • Property descriptor type

    The property descriptor specifies the property and the operation to perform on that property. The descriptor always begins with a KSPROPERTY structure, but some types of descriptor contain additional information. For example, the KSNODEPROPERTY structure is a property descriptor that begins with a KSPROPERTY structure but also includes a node ID.

  • Property value type

    A property has a value and the type of this value depends on the property. For example, a property that can be in one of only two states—on or off—typically has a BOOL value. A property that can assume integer values from 0 to 0xFFFFFFFF might have a ULONG value. More complex properties might have values that are arrays or structures.

The property descriptor and property value above are the property-specific versions of the instance-specification and operation-data buffers that are discussed in KS Properties, Events, and Methods.

A property request uses one of the following flags to specify the operation that is to be performed on the property:

  • KSPROPERTY_TYPE_BASICSUPPORT
  • KSPROPERTY_TYPE_GET
  • KSPROPERTY_TYPE_SET

All filter and pin objects support the basic-support operation on their properties. Whether they support the get and set operations depends on the property. A property that represents an inherent capability of the filter or pin object is likely to require only a get operation. A property that represents a configurable setting might require only a set operation, although a get operation might also be useful for reading the current setting. For more information about using the get, set, and basic-support operations with audio properties, see Properties of Audio Filters, Pins, and Nodes.

The following property sets are defined for audio drivers:

KSPROPSETID_Acoustic_Echo_Cancel

KSPROPSETID_Audio

KSPROPSETID_AudioGfx

KSPROPSETID_DirectSound3DBuffer

KSPROPSETID_DirectSound3DListener

KSPROPSETID_Synth

KSPROPSETID_Synth_Dls

KSPROPSETID_TopologyNode


KSPROPSETID_Acoustic_Echo_Cancel

The KSPROPSETID_Acoustic_Echo_Cancel property set is used to control and monitor an AEC node (see KSNODETYPE_ACOUSTIC_ECHO_CANCEL). This property set is supported in Microsoft® Windows® XP and later. The properties in this set are optional properties of an AEC node.

The KSPROPSETID_Acoustic_Echo_Cancel property set includes the following properties:

KSPROPERTY_AEC_MODE

KSPROPERTY_AEC_NOISE_FILL_ENABLE

KSPROPERTY_AEC_STATUS


KSPROPERTY_AEC_NOISE_FILL_ENABLE

The KSPROPERTY_AEC_NOISE_FILL_ENABLE property is used to enable and disable background noise filling. This is an optional property of an AEC node.

Get | Set | Target | Property descriptor type | Property value type
Yes | No | Pin | KSNODEPROPERTY | BOOL

Comments

The property value is of type BOOL. Setting this value to TRUE enables background noise filling. When enabled, the node inserts background comfort noise into the capture stream in order to avoid the unnatural silence that occurs when the captured data stream is set to zero after perfect echo cancellation. Setting this value to FALSE disables background noise filling.

When the filter containing the AEC node is created or the node is reset, background noise filling is disabled by default.

See Also

KSNODETYPE_ACOUSTIC_ECHO_CANCEL


KSPROPERTY_AEC_STATUS

The KSPROPERTY_AEC_STATUS property is used to monitor the status of an AEC node (see KSNODETYPE_ACOUSTIC_ECHO_CANCEL). This is an optional property of an AEC node.

Get | Set | Target | Property descriptor type | Property value type
Yes | No | Pin | KSNODEPROPERTY | ULONG

Comments

The property value is of type ULONG. This is a status value that can be set to the bitwise OR of one or more of the flag bits in the left column of the table below, which are defined in header file ksmedia.h.

Status flag | Value | DSCFX_AEC_STATUS flag
AEC_STATUS_FD_HISTORY_UNINITIALIZED | 0x0 | DSCFX_AEC_STATUS_HISTORY_UNINITIALIZED
AEC_STATUS_FD_HISTORY_CONTINUOUSLY_CONVERGED | 0x1 | DSCFX_AEC_STATUS_HISTORY_CONTINUOUSLY_CONVERGED
AEC_STATUS_FD_HISTORY_PREVIOUSLY_DIVERGED | 0x2 | DSCFX_AEC_STATUS_HISTORY_PREVIOUSLY_DIVERGED
AEC_STATUS_FD_CURRENTLY_CONVERGED | 0x8 | DSCFX_AEC_STATUS_CURRENTLY_CONVERGED

The corresponding DSCFX_AEC_STATUS flags are shown in the right column above. See the Platform SDK documentation for information on these flags.

The three least significant bits in the status value represent the convergence history (CH) of the AEC algorithm. The CH status bits can be used by a DirectSound application to determine whether the algorithm has converged and also whether it has remained in the converged state since the time that it started processing data. Depending on the audio hardware, the AEC algorithm might fail to converge, in which case the resulting capture buffer is likely to include the echo from the speakers.

When the filter containing the AEC node is created or the node is reset, the AEC algorithm initially sets the three CH status bits to zero. This is the uninitialized state, AEC_STATUS_FD_HISTORY_UNINITIALIZED.

Once the AEC algorithm converges, the CH status switches to the converged state, AEC_STATUS_FD_HISTORY_CONTINUOUSLY_CONVERGED.

If the AEC algorithm ever loses convergence, the CH status switches to the diverged state, AEC_STATUS_FD_HISTORY_PREVIOUSLY_DIVERGED. Although the status is most likely to switch to the diverged state from the converged state, it might also switch directly from the uninitialized state to the diverged state. Once the CH status has switched to the diverged state, it will remain in that state until the algorithm is reset or starvation is detected.

When the AEC system filter detects starvation at any of its four pins—capture in, capture out, render in, or render out—it resets its internal state, including the convergence history.

Note that bit two of the three CH status bits is not currently used.

As an alternative to using the CH status bits, the application can monitor the real-time convergence status by checking the AEC_STATUS_FD_CURRENTLY_CONVERGED flag bit. If this bit is set, the algorithm is currently converged. The algorithm can lose convergence temporarily when changes occur in the acoustic path. The real-time convergence flag is filtered in order to prevent such momentary losses from inappropriately switching the CH status bits to the DSCFX_AEC_STATUS_FD_HISTORY_PREVIOUSLY_DIVERGED state.

See Also

KSNODETYPE_ACOUSTIC_ECHO_CANCEL


KSPROPSETID_Audio

The KSPROPSETID_Audio property set indicates the range of data and control supported by an audio stream. The miniport driver should support the KSPROPERTY_AUDIO_LATENCY property. All other properties in this property set are optional.

In cases where the hardware does not support a capability, the miniport driver should return an error for the get- and set-property calls so that the upper-layer driver can handle the call. For example, a miniport driver for hardware that does not support volume control should return an error for the KSPROPERTY_AUDIO_VOLUMELEVEL calls, thus enabling a driver higher in the stack (such as a kernel mixer) to set the volume of a stream.

The following properties are part of the KSPROPSETID_Audio property set:

KSPROPERTY_AUDIO_3D_INTERFACE

KSPROPERTY_AUDIO_AGC

KSPROPERTY_AUDIO_ALGORITHM_INSTANCE

KSPROPERTY_AUDIO_BASS

KSPROPERTY_AUDIO_BASS_BOOST

KSPROPERTY_AUDIO_CHANNEL_CONFIG

KSPROPERTY_AUDIO_CHORUS_LEVEL

KSPROPERTY_AUDIO_COPY_PROTECTION

KSPROPERTY_AUDIO_CPU_RESOURCES

KSPROPERTY_AUDIO_DELAY

KSPROPERTY_AUDIO_DEMUX_DEST

KSPROPERTY_AUDIO_DEV_SPECIFIC

KSPROPERTY_AUDIO_DYNAMIC_RANGE

KSPROPERTY_AUDIO_DYNAMIC_SAMPLING_RATE

KSPROPERTY_AUDIO_EQ_BANDS

KSPROPERTY_AUDIO_EQ_LEVEL

KSPROPERTY_AUDIO_FILTER_STATE

KSPROPERTY_AUDIO_LATENCY

KSPROPERTY_AUDIO_LOUDNESS

KSPROPERTY_AUDIO_MANUFACTURE_GUID

KSPROPERTY_AUDIO_MID

KSPROPERTY_AUDIO_MIX_LEVEL_CAPS

KSPROPERTY_AUDIO_MIX_LEVEL_TABLE

KSPROPERTY_AUDIO_MUTE

KSPROPERTY_AUDIO_MUX_SOURCE

KSPROPERTY_AUDIO_NUM_EQ_BANDS

KSPROPERTY_AUDIO_PEAKMETER

KSPROPERTY_AUDIO_POSITION

KSPROPERTY_AUDIO_PREFERRED_STATUS

KSPROPERTY_AUDIO_PRODUCT_GUID

KSPROPERTY_AUDIO_QUALITY

KSPROPERTY_AUDIO_REVERB_LEVEL

KSPROPERTY_AUDIO_SAMPLING_RATE

KSPROPERTY_AUDIO_STEREO_ENHANCE

KSPROPERTY_AUDIO_STEREO_SPEAKER_GEOMETRY

KSPROPERTY_AUDIO_SURROUND_ENCODE

KSPROPERTY_AUDIO_TREBLE

KSPROPERTY_AUDIO_VOLUMELEVEL

KSPROPERTY_AUDIO_WIDE_MODE

KSPROPERTY_AUDIO_WIDENESS


KSPROPERTY_AUDIO_3D_INTERFACE

The KSPROPERTY_AUDIO_3D_INTERFACE property specifies the 3D algorithm that is to be used for the sound buffer.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Filter | KSNODEPROPERTY | GUID

Comments

See the list of GUID values that are defined for the guid3dAlgorithm member of the DSBUFFERDESC structure in the Platform SDK documentation. Also see the description of the IDirectSound::CreateSoundBuffer method.

See Also

KSNODEPROPERTY


KSPROPERTY_AUDIO_AGC

The KSPROPERTY_AUDIO_AGC property indicates the current state of the automatic gain control for the specified channel.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Filter | KSNODEPROPERTY_AUDIO_CHANNEL | BOOL

Comments

A value of TRUE indicates that the automatic gain control is ON.

See Also

KSNODEPROPERTY_AUDIO_CHANNEL, KSNODETYPE_AGC


KSPROPERTY_AUDIO_ALGORITHM_INSTANCE

The KSPROPERTY_AUDIO_ALGORITHM_INSTANCE property indicates the DSP (digital-signal processing) algorithm that is used to achieve the third-party effect that is applied to audio data that streams through the target pin. The effects that are defined for this property include acoustic echo cancellation and noise suppression.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSNODEPROPERTY | GUID

Comments

The property value is a GUID that identifies the effect that is applied to the data stream that passes through the pin. The following GUIDs and the effects that they represent are specified for the KSPROPERTY_AUDIO_ALGORITHM_INSTANCE property.

GUID value | Meaning
KSALGORITHMINSTANCE_SYSTEM_ACOUSTIC_ECHO_CANCEL | System default acoustic echo cancellation
KSALGORITHMINSTANCE_SYSTEM_NOISE_SUPPRESS | System default noise suppression

The algorithm-instance GUID matches the value in the guidDSCFXInstance member of a DSCEFFECTDESC structure that is passed to the IDirectSoundCapture::CreateCaptureBuffer method or DirectSoundFullDuplexCreate function (for more information, see the Platform SDK documentation).

See Also

KSNODEPROPERTY


KSPROPERTY_AUDIO_BASS

The KSPROPERTY_AUDIO_BASS property indicates the base-level for the specified channel.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Filter | KSNODEPROPERTY_AUDIO_CHANNEL | ULONG

Comments

The base level is indicated as a ULONG value. Level values use the following scale:

A dB range from –2147483648 to +2147483647

where

–2147483648 is –Infinity dB attenuation

–2147483647 is –32767.99998474 dB (attenuation)

and

+2147483647 is +32767.99998474 dB (gain)

The scale has a resolution of 1/65536 dB. The filter will succeed a set-property request that specifies a value that is beyond the range of the filter but will clamp the value to the supported range; in a subsequent request to get this property, however, it will return the actual value used.

See the description of the IAMAudioInputMixer::get_Bass and IAMAudioInputMixer::put_Bass methods in the Platform SDK documentation.

See Also

KSNODEPROPERTY_AUDIO_CHANNEL, KSNODETYPE_TONE


KSPROPERTY_AUDIO_BASS_BOOST

The KSPROPERTY_AUDIO_BASS_BOOST property indicates the base boost for the specified channel.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Filter | KSNODEPROPERTY_AUDIO_CHANNEL | BOOL

Comments

A value of TRUE indicates that the bass boost in ON for the specified channel. A value of FALSE indicates that the bass boost is OFF.

See Also

KSNODEPROPERTY_AUDIO_CHANNEL, KSNODETYPE_TONE


KSPROPERTY_AUDIO_CHANNEL_CONFIG

The KSPROPERTY_AUDIO_CHANNEL_CONFIG property specifies the actual spatial placement of channels in the stream.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSNODEPROPERTY | KSAUDIO_CHANNEL_CONFIG

See Also

KSNODEPROPERTY, KSAUDIO_CHANNEL_CONFIG, KSNODETYPE_PROLOGIC_DECODER


KSPROPERTY_AUDIO_CHORUS_LEVEL

The KSPROPERTY_AUDIO_CHORUS_LEVEL property indicates the current chorus level.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Filter | KSPROPERTY | LONG

Comments

This property is used to get and set the volume level of the chorus echo. Chorus is a voice-doubling effect that is created by echoing the original sound with a slight delay and slightly modulating the delay of the echo. For more information, see the description of the IDirectSoundFXChorus interface in the SDK Platform documentation.

Chorus-level values follow a linear range from 0 to 65535 percent (0xffffffff). The value 0x00010000 represents 100 percent.

See Also

KSPROPERTY, KSNODETYPE_CHORUS


KSPROPERTY_AUDIO_COPY_PROTECTION

This parameter name is reserved for future use.


KSPROPERTY_AUDIO_CPU_RESOURCES

The KSPROPERTY_AUDIO_CPU_RESOURCES property indicates whether the specified node's functionality makes use of the host CPU.

Get | Set | Target | Property descriptor type | Property value type
Yes | No | Filter | KSNODEPROPERTY | ULONG

Comments

The miniport driver should set the KSPROPERTY_AUDIO_CPU_RESOURCE property value to one of the following two values:

Value | Meaning
KSAUDIO_CPU_RESOURCES_HOST_CPU | This node implements its functionality in software that runs on the host CPU.
KSAUDIO_CPU_RESOURCES_NOT_HOST_CPU | This node implements its functionality in hardware.

See Also

KSNODEPROPERTY, KSNODETYPE_PEAKMETER


KSPROPERTY_AUDIO_DELAY

The KSPROPERTY_AUDIO_DELAY property is used to indicate the time lag introduced by a KSNODETYPE_DELAY node.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Filter | KSNODEPROPERTY_AUDIO_CHANNEL | KSTIME

See Also:

KSNODEPROPERTY_AUDIO_CHANNEL, KSTIME, KSNODETYPE_DELAY


KSPROPERTY_AUDIO_DEMUX_DEST

The KSPROPERTY_AUDIO_DEMUX_DEST property is used to indicate the destination to which the demultiplexed input stream is directed.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Filter | KSNODEPROPERTY | ULONG

Comments

The value for KSPROPERTY_AUDIO_DEMUX_DEST is a ULONG that contains the pin ID on the demultiplexer that is connected to the desired destination.

See Also

KSNODEPROPERTY, KSNODETYPE_DEMUX


KSPROPERTY_AUDIO_DEV_SPECIFIC

The KSPROPERTY_AUDIO_DEV_SPECIFIC property is used to access a device-specific property whose value is expressed in a device-specific format. Whether the property supports get and/or set requests is also device-specific.

See Also

KSNODETYPE_DEV_SPECIFIC


KSPROPERTY_AUDIO_DYNAMIC_RANGE

The KSPROPERTY_AUDIO_DYNAMIC_RANGE property is used to indicate the dynamic range of the audio stream.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Filter | KSPROPERTY | KSAUDIO_DYNAMIC_RANGE

Comments

By default, the values for the QuietCompression and LoudCompression members of the KSAUDIO_DYNAMIC_RANGE structure are set to 0 percent. This produces the full dynamic range of the audio stream.

Some devices might not support changes to QuietCompression and LoudCompression. If the client attempts to change a value that the device does not support, the miniport driver should return an error.

See Also

KSAUDIO_DYNAMIC_RANGE, KSNODETYPE_LOUDNESS


KSPROPERTY_AUDIO_DYNAMIC_SAMPLING_RATE

The KSPROPERTY_AUDIO_DYNAMIC_SAMPLING_RATE is used to enable and disable dynamic tracking of the sampling rate.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Filter | KSNODEPROPERTY | BOOL

Comments

The property value for KSPROPERTY_AUDIO_DYNAMIC_SAMPLING_RATE is TRUE when dynamic tracking of the sampling rate is enabled. In this mode, the input stream's sampling rate can be varied explicitly by setting the rate through KSPROPERTY_AUDIO_SAMPLING_RATE or implicitly by setting the rate through the time stamps on the input stream.

See Also

KSNODEPROPERTY, KSPROPERTY_AUDIO_SAMPLING_RATE, KSNODETYPE_ADC, KSNODETYPE_DAC, KSNODETYPE_SRC


KSPROPERTY_AUDIO_EQ_BANDS

The KSPROPERTY_AUDIO_EQ_BANDS property represents an equalization table with N frequency bands. This is a get-only property.

Get | Set | Target | Property descriptor type | Property value type
Yes | No | Filter | KSNODEPROPERTY_AUDIO_CHANNEL | Array of ULONG values

Comments

This property specifies the center frequencies of the N frequency bands as an array of ULONG values:

   ULONG   CenterFreqVal[N];

Each array element represents an integer frequency value that is specified in Hertz, as is shown in the table below.

Array element | Description
CenterFreqVal[0] | The center frequency (in Hz) for equalization band 0.
CenterFreqVal[1] | The center frequency (in Hz) for equalization band 1.
CenterFreqVal[N–1] | The center frequency (in Hz) for equalization band N–1.

The number of equalization bands, N, can be determined by first submitting a KSPROPERTY_AUDIO_NUM_EQ_BANDS request.

See Also

KSNODEPROPERTY_AUDIO_CHANNEL, KSNODETYPE_EQUALIZER, KSPROPERTY_AUDIO_NUM_EQ_BANDS


KSPROPERTY_AUDIO_EQ_LEVEL

The KSPROPERTY_AUDIO_EQ_LEVEL property is used to indicate the equalization levels for N frequency levels.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Filter | KSNODEPROPERTY_AUDIO_CHANNEL | Array of ULONGs

Comments

This property is specified in an array of frequency levels, one for each band. It is specified as follows:

   LONG    Level[N];
Order | Description
Level [0] | Level for band 0. Level values use the following scale: a dB range from –2147483648 to +2147483648 is –Infinity dB attenuation, –2147483647 is –32767.99998474 dB (attenuation), and +2147483647 is +32767.99998474 dB (gain). The scale has a resolution of 1/65536 dB. The filter will succeed a set-property request that specifies a value that is beyond the range of the filter but will clamp the value to the supported range; in a subsequent request to get this property, however, it will return the actual value used.
Level [1] | Level for band 1.
Level [N–1] | Level for band N–1.

The number of equalization bands, N, can be determined by first submitting a KSPROPERTY_AUDIO_NUM_EQ_BANDS request.

See Also

KSNODEPROPERTY_AUDIO_CHANNEL, KSNODETYPE_EQUALIZER, KSPROPERTY_AUDIO_NUM_EQ_BANDS


KSPROPERTY_AUDIO_FILTER_STATE

The KSPROPERTY_AUDIO_FILTER_STATE property is used to query a GFX filter for a list of the property sets that it supports. The list is retrieved in the form of an array of property-set GUIDs.

Get | Set | Target | Property descriptor type | Property value type
Yes | No | Filter | KSPROPERTY | array of GUIDs

Comments

The size of the array of GUIDs for the KSPROPERTY_AUDIO_FILTER_STATE property is implied by the number of bytes returned by the property. Before retrieving the array, the operating system first queries the size (in bytes) of the property's GUID array by sending the driver a KSPROPERTY_AUDIO_FILTER_STATE request with a zero-length output buffer. The driver responds by returning the required output-buffer size along with the status code STATUS_BUFFER_OVERFLOW.

With these GUIDs, the operating system can serially interrogate the properties within each property set. This information enables the operating system to restore the state of a GFX filter object at the time that it is instantiated, and also to save the state of a GFX filter object at the time that it is destroyed. The purpose for saving and restoring the GFX filter's state is to preserve any changes the user has made to the filter's settings and to make them persistent across successive instantiations of the filter.

When saving or restoring the state of the GFX filter, the operating system serializes its requests for the properties in each property set. See the discussion of serialization in KS Properties.

See Also

KSPROPERTY


KSPROPERTY_AUDIO_LATENCY

The KSPROPERTY_AUDIO_LATENCY property is used to report the delay (or amount of audio buffering) that is associated with the stream.

Get | Set | Target | Property descriptor type | Property value type
Yes | No | Pin | KSPROPERTY | KSTIME

See Also

KSPROPERTY, KSTIME


KSPROPERTY_AUDIO_LOUDNESS

The KSPROPERTY_AUDIO_LOUDNESS property is used to indicate the loudness (overall dynamic range and bass boost) for the specified channel.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Filter | KSNODEPROPERTY_AUDIO_CHANNEL | BOOL

Comments

KSPROPERTY_AUDIO_LOUDNESS is TRUE when loudness is on for an individual channel; otherwise, KSPROPERTY_AUDIO_LOUDNESS is FALSE.

See Also

KSNODEPROPERTY_AUDIO_CHANNEL, KSNODETYPE_LOUDNESS


KSPROPERTY_AUDIO_MANUFACTURE_GUID

This parameter name is reserved for future use.


KSPROPERTY_AUDIO_MID

The KSPROPERTY_AUDIO_MID property is used to indicate the current mid frequency of the stream for the specified channel.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Filter | KSNODEPROPERTY_AUDIO_CHANNEL | LONG

Comments

Mid-level values use the following scale: a dB range from –2147483648 to +2147483647, where –2147483648 is –Infinity dB attenuation, a –2147483647 is –32767.99998474 dB (attenuation), and +2147483647 is +32767.99998474 dB (gain). The scale has a resolution of 1/65536 dB. The filter will succeed a set-property request that specifies a value that is beyond the range of the filter but will clamp the value to the supported range; in a subsequent request to get this property, however, it will return the actual value used.

See Also

KSNODEPROPERTY_AUDIO_CHANNEL, KSNODETYPE_TONE


KSPROPERTY_AUDIO_MIX_LEVEL_CAPS

KSPROPERTY_AUDIO_MIX_LEVEL_CAPS is used to indicate the mix-level capabilities for a supermix node (see KSNODETYPE_SUPERMIX). It provides information for all input and output channels.

Get | Set | Target | Property descriptor type | Property value type
Yes | No | Filter | KSNODEPROPERTY | KSAUDIO_MIXCAP_TABLE

See Also

KSNODEPROPERTY, KSAUDIO_MIXCAP_TABLE, KSNODETYPE_SUPERMIX


KSPROPERTY_AUDIO_MIX_LEVEL_TABLE

KSPROPERTY_AUDIO_MIX_LEVEL_TABLE is used to indicate the mix levels for a supermix node (see KSNODETYPE_SUPERMIX). It provides information for all input and output channels.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Filter | KSNODEPROPERTY | Array of KSAUDIO_MIXLEVEL structures

Comments

The value for KSPROPERTY_AUDIO_MIX_LEVEL_TABLE for a device with M input channels and N output channels is an array of M*N KSAUDIO_MIXLEVEL structures. This array is used to map M input channels to N output channels. If no mapping exists from the M[ij] to the N[ij] element, the Mute member of the [ij] entry should be set to TRUE. The size of the table is calculated from the KSAUDIO_MIXCAP_TABLE structure that is retrieved from KSPROPERTY_AUDIO_MIX_LEVEL_CAPS. The size of the KSAUDIO_MIXLEVEL array is InputChannels * OutputChannels * sizeof(KSAUDIO_MIXLEVEL).

See Also

KSNODEPROPERTY, KSAUDIO_MIXCAP_TABLE, KSPROPERTY_AUDIO_MIX_LEVEL_CAPS, KSAUDIO_MIXLEVEL, KSNODETYPE_SUPERMIX


KSPROPERTY_AUDIO_MUTE

The KSPROPERTY_AUDIO_MUTE property is used to indicate the current muting state of the stream for the specified channel.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSNODEPROPERTY_AUDIO_CHANNEL | BOOL

Comments

A value of TRUE indicates that the channel is muted.

See Also

KSNODEPROPERTY_AUDIO_CHANNEL, KSNODETYPE_MUTE


KSPROPERTY_AUDIO_MUX_SOURCE

The KSPROPERTY_AUDIO_MUX_SOURCE property is used to indicate the source for the MUX output stream.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Filter | KSNODEPROPERTY | ULONG

Comments

The value for KSPROPERTY_AUDIO_MUX_SOURCE is a ULONG that specifies the pin ID on the MUX node of the input pin that is connected to the selected source.

See Also

KSNODEPROPERTY, KSNODETYPE_MUX


KSPROPERTY_AUDIO_NUM_EQ_BANDS

The KSPROPERTY_AUDIO_NUM_EQ_BANDS property is used to retrieve the number of frequency bands in the equalization table.

Get | Set | Target | Property descriptor type | Property value type
Yes | No | Filter | KSNODEPROPERTY_AUDIO_CHANNEL | ULONG

Comments

The property value for KSPROPERTY_AUDIO_NUM_EQ_BANDS is a ULONG that indicates the number of frequency bands available.

See Also

KSNODEPROPERTY_AUDIO_CHANNEL, KSNODETYPE_EQUALIZER, KSPROPERTY_AUDIO_EQ_BANDS, KSPROPERTY_AUDIO_EQ_LEVEL


KSPROPERTY_AUDIO_PEAKMETER

The KSPROPERTY_AUDIO_PEAKMETER property indicates the maximum audio signal level that occurred at a peakmeter node (see KSNODETYPE_PEAKMETER) since the last time the peakmeter node was reset.

Get | Set | Target | Property descriptor type | Property value type
Yes | No | Pin | KSPROPERTY_AUDIO_PEAKMETER | LONG

Return Value

Status Value | Meaning
STATUS_SUCCESS | The KS audio filter returned the current value of the peakmeter.
STATUS_NOT_IMPLEMENTED | The KS filter cannot return the current value of the peakmeter.

Comments

A KS audio filter handles this property request synchronously. If the request succeeds, the peakmeter is reset. If the request does not succeed, the peakmeter is not changed.

The system sends an IOCTL_KS_PROPERTY request for the KSPROPERTY_AUDIO_PEAKMETER property at IRQL PASSIVE_LEVEL.

See Also

KSNODETYPE_PEAKMETER


KSPROPERTY_AUDIO_POSITION

The KSPROPERTY_AUDIO_POSITION property indicates the current positions of the read and write cursors in the sound buffer for the pin's audio stream.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSPROPERTY | KSAUDIO_POSITION

See Also

KSPROPERTY, KSAUDIO_POSITION


KSPROPERTY_AUDIO_PREFERRED_STATUS

The KSPROPERTY_AUDIO_PREFERRED_STATUS property indicates whether the client has selected the target filter to act as the system's preferred audio device.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Filter | KSPROPERTY | BOOL

Comments

The property value is of type BOOL. A value of TRUE enables the device to operate as the preferred device. A value of FALSE means that the device is not to act as the preferred device.

For more information on the preferred audio device, see Accessing the Preferred Device ID.

See Also

KSPROPERTY, SetupPreferredAudioDevices


KSPROPERTY_AUDIO_PRODUCT_GUID

This parameter name is reserved for future use.


KSPROPERTY_AUDIO_QUALITY

The KSPROPERTY_AUDIO_QUALITY property indicates the stream's quality level.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSPROPERTY | ULONG

Comments

The value for KSPROPERTY_AUDIO_QUALITY is a ULONG and should be set to one of the following values.

Value | Description
KSAUDIO_QUALITY_PC | Standard PC quality (no constraints)
KSAUDIO_QUALITY_BASIC | Basic (low-end) consumer audio quality (default value)
KSAUDIO_QUALITY_ADVANCED | Advanced (high-end) consumer audio quality

See Also

KSPROPERTY, KSNODETYPE_SRC


KSPROPERTY_AUDIO_REVERB_LEVEL

KSPROPERTY_AUDIO_REVERB_LEVEL is used to indicate the current reverberation level.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSPROPERTY | ULONG

Comments

Reverb values follow a linear range from 0 to 65535 percent (0xffffffff). The value 0x00010000 represents 100 percent.

See Also

KSPROPERTY, KSNODETYPE_REVERB


KSPROPERTY_AUDIO_SAMPLING_RATE

The KSPROPERTY_AUDIO_SAMPLING_RATE property indicates the sampling rate of the stream.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSNODEPROPERTY | ULONG

Comments

The KSPROPERTY_AUDIO_SAMPLING_RATE property value is a ULONG indicating the number of samples per second (in Hz). The miniport driver should return an error on set-property requests if the specified sampling rate is not available.

See Also

KSNODEPROPERTY, KSNODETYPE_ADC, KSNODETYPE_DAC, KSNODETYPE_SRC


KSPROPERTY_AUDIO_STEREO_ENHANCE

This parameter name is reserved for future use.


KSPROPERTY_AUDIO_STEREO_SPEAKER_GEOMETRY

The KSPROPERTY_AUDIO_STEREO_SPEAKER_GEOMETRY property is used in combination with KSPROPERTY_AUDIO_CHANNEL_CONFIG to implement the DirectSound® speaker-configuration property for hardware-accelerated 3D audio.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSNODEPROPERTY | LONG

Comments

The property value can be set to one of the following parameters, which are defined in header file ksmedia.h:

  • KSAUDIO_STEREO_SPEAKER_GEOMETRY_HEADPHONES
  • KSAUDIO_STEREO_SPEAKER_GEOMETRY_MIN
  • KSAUDIO_STEREO_SPEAKER_GEOMETRY_NARROW
  • KSAUDIO_STEREO_SPEAKER_GEOMETRY_WIDE
  • KSAUDIO_STEREO_SPEAKER_GEOMETRY_MAX

The parameters above are equivalent in meaning to (but not equal in value to) the following values, which are used by the IDirectSound::GetSpeakerConfig method (see Platform SDK documentation) and are defined in header file dsound.h:

  • DSSPEAKER_HEADPHONES
  • DSSPEAKER_STEREO | DSSPEAKER_GEOMETRY_MIN
  • DSSPEAKER_STEREO | DSSPEAKER_GEOMETRY_NARROW
  • DSSPEAKER_STEREO | DSSPEAKER_GEOMETRY_WIDE
  • DSSPEAKER_STEREO | DSSPEAKER_GEOMETRY_MAX

See Also

KSNODEPROPERTY


KSPROPERTY_AUDIO_SURROUND_ENCODE

The KSPROPERTY_AUDIO_SURROUND_ENCODE property indicates whether the filter's surround encoder is enabled or disabled. A surround encoder is a node of type KSNODETYPE_SURROUND_ENCODER that performs Dolby Surround Pro Logic encoding.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Filter | KSNODEPROPERTY | BOOL

Comments

A property value of TRUE indicates that the surround-encoder node is enabled.

In Microsoft® Windows® XP and later, the KMixer system driver supports the KSPROPERTY_AUDIO_SURROUND_ENCODE property.

If enabled, the surround-encoder node encodes the four-channel input stream (with channels for left, right, center, and back speakers) to a surround-encoded stereo output stream. The output stream can be decoded by a KSNODETYPE_PROLOGIC_DECODER node, for example. It can also be played through the audio device's analog stereo outputs, which can be connected to an external surround decoder that directly drives left, right, center, and back speakers.

See Also

KSNODEPROPERTY, KSNODETYPE_SURROUND_ENCODER, KSNODETYPE_PROLOGIC_DECODER


KSPROPERTY_AUDIO_TREBLE

The KSPROPERTY_AUDIO_TREBLE property indicates the current treble control value for the stream on the specified channel.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Filter | KSNODEPROPERTY_AUDIO_CHANNEL | ULONG

Comments

Treble-level values use the following scale: a dB range from –2147483647 to +2147483647, where –2147483648 is –Infinity dB attenuation, –2147483647 is –32767.99998474 dB (attenuation), and +2147483647 is +32767.99998474 dB (gain). The scale has a resolution of 1/65536 dB. The filter will succeed a set-property request that specifies a value that is beyond the range of the filter but will clamp the value to the supported range; in a subsequent request to get this property, however, it will return the actual value used.

See the description of the IAMAudioInputMixer::get_Treble and IAMAudioInputMixer::put_Treble methods in the Platform SDK documentation.

See Also

KSNODEPROPERTY_AUDIO_CHANNEL, KSNODETYPE_TONE


KSPROPERTY_AUDIO_VOLUMELEVEL

The KSPROPERTY_AUDIO_VOLUMELEVEL is used to indicate the current volume level.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Filter/Pin | KSNODEPROPERTY_AUDIO_CHANNEL | ULONG

Comments

Volume-level values use the following scale: a dB range from –2147483648 to +2147483647, where –2147483648 is –Infinity dB attenuation, –2147483647 is –32767.99998474 dB attenuation, and +2147483647 is +32767.99998474 dB gain.

The scale has a resolution of 1/65536 dB. If a value is specified beyond the range of the filter, the filter will still succeed the request to set this property, but it will return the actual value used in subsequent calls to get this property.

See Also

KSNODEPROPERTY_AUDIO_CHANNEL, KSNODETYPE_VOLUME


KSPROPERTY_AUDIO_WIDE_MODE

This parameter name is reserved for future use.


KSPROPERTY_AUDIO_WIDENESS

This parameter name is reserved for future use.


KSPROPSETID_AudioGfx

The KSPROPSETID_AudioGfx property set is used to inform GFX filters of the device IDs of the audio devices that are used for rendering and/or capture. A device ID is specified in the form of a NULL-terminated Unicode string (see Device Identification Strings).

The following properties are part of the KSPROPSETID_AudioGfx property set:

KSPROPERTY_AUDIOGFX_CAPTURETARGETDEVICEID

KSPROPERTY_AUDIOGFX_RENDERTARGETDEVICEID


KSPROPERTY_AUDIOGFX_CAPTURETARGETDEVICEID

The KSPROPERTY_AUDIOGFX_CAPTURETARGETDEVICEID property is used to inform a GFX filter of the PnP device ID of the audio device that is the source of the capture stream. The target GFX filter for this set-property request is configured to be used either as a capture- or render/capture-GFX filter.

Get | Set | Target | Property descriptor type | Property value type
No | Yes | Filter | KSPROPERTY | NULL-terminated Unicode string

Comments

For additional information on GFX filters and device IDs, see GFX Filters and Device Identification Strings.

See Also

KSPROPERTY


KSPROPERTY_AUDIOGFX_RENDERTARGETDEVICEID

The KSPROPERTY_AUDIOGFX_RENDERTARGETDEVICEID property is used to inform a GFX filter of the PnP device ID of the audio device that renders the final audio mix. The target GFX filter for this set-property request is configured to be used either as a render- or render/capture-GFX filter.

Get | Set | Target | Property descriptor type | Property value type
No | Yes | Filter | KSPROPERTY | NULL-terminated Unicode string

Comments

For additional information on GFX filters and device IDs, see GFX Filters and Device Identification Strings.

See Also

KSPROPERTY


KSPROPSETID_DirectSound3DBuffer

The KSPROPSETID_DirectSound3DBuffer property set contains all the device-specific properties that are needed to implement the IDirectSound3DBuffer interface (see Platform SDK documentation). Using this property set, the 3D-buffer properties that are specified by the API are passed directly between DirectSound and the WDM audio driver. This property set is handled by the KSNODETYPE_3D_EFFECTS node, which handles both the 3D-buffer and 3D-listener properties.

The KSPROPSETID_DirectSound3DBuffer property set contains the following properties:

KSPROPERTY_DIRECTSOUND3DBUFFER_ALL

KSPROPERTY_DIRECTSOUND3DBUFFER_CONEANGLES

KSPROPERTY_DIRECTSOUND3DBUFFER_CONEORIENTATION

KSPROPERTY_DIRECTSOUND3DBUFFER_CONEOUTSIDEVOLUME

KSPROPERTY_DIRECTSOUND3DBUFFER_MAXDISTANCE

KSPROPERTY_DIRECTSOUND3DBUFFER_MINDISTANCE

KSPROPERTY_DIRECTSOUND3DBUFFER_MODE

KSPROPERTY_DIRECTSOUND3DBUFFER_POSITION

KSPROPERTY_DIRECTSOUND3DBUFFER_VELOCITY


KSPROPERTY_DIRECTSOUND3DBUFFER_ALL

The KSPROPERTY_DIRECTSOUND3DBUFFER_ALL property is used to set or get all the DirectSound 3D-buffer properties for the specified buffer.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSNODEPROPERTY | KSDS3D_BUFFER_ALL

Comments

The KSDS3D_BUFFER_ALL structure is similar to the DS3DBUFFER structure, which is described in the Platform SDK documentation.

Also see the description of the IDirectSound3DBuffer::GetAllParameters and IDirectSound3DBuffer::SetAllParameters methods in the Platform SDK documentation.

See Also

KSNODEPROPERTY, KSDS3D_BUFFER_ALL


KSPROPERTY_DIRECTSOUND3DBUFFER_CONEANGLES

The KSPROPERTY_DIRECTSOUND3DBUFFER_CONEANGLES property is used to indicate the inside and outside cone angles of the sound projection cone for the specified 3D sound buffer.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSNODEPROPERTY | KSDS3D_BUFFER_CONE_ANGLES

Comments

For more information on the inside and outside cone angles of the sound projection cone for a DirectSound 3D buffer, see the following topics in the Platform SDK documentation:

  • The dwInsideConeAngle and dwOutsideConeAngle members of the DS3DBUFFER structure.
  • The IDirectSound3DBuffer::GetConeAngles and IDirectSound3DBuffer::SetConeAngles methods.

See Also

KSNODEPROPERTY, KSDS3D_BUFFER_CONE_ANGLES


KSPROPERTY_DIRECTSOUND3DBUFFER_CONEORIENTATION

The KSPROPERTY_DIRECTSOUND3DBUFFER_CONEORIENTATION property is used to indicate the orientation of the sound projection cone for the specified 3D sound buffer.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSNODEPROPERTY | DS3DVECTOR

Comments

For more information on the sound projection cone for a DirectSound 3D buffer, see the following topics in the Platform SDK documentation:

  • The vConeOrientation member of the DS3DBUFFER structure.
  • The IDirectSound3DBuffer::GetConeOrientation and IDirectSound3DBuffer::SetConeOrientation methods.

See Also

KSNODEPROPERTY, DS3DVECTOR


KSPROPERTY_DIRECTSOUND3DBUFFER_CONEOUTSIDEVOLUME

The KSPROPERTY_DIRECTSOUND3DBUFFER_CONEOUTSIDEVOLUME property is used to indicate the current cone-outside sound volume for the specified 3D sound buffer.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSNODEPROPERTY | LONG

Comments

The value for this property is specified in hundredths of decibels.

For more information on the cone-outside sound volume for a DirectSound 3D buffer, see the following topics in the Platform SDK documentation:

  • The lConeOutsideVolume member of the DS3DBUFFER structure.
  • The IDirectSound3DBuffer::GetOutsideVolume and IDirectSound3DBuffer::SetOutsideVolume methods.

See Also

KSNODEPROPERTY


KSPROPERTY_DIRECTSOUND3DBUFFER_MAXDISTANCE

The KSPROPERTY_DIRECTSOUND3DBUFFER_MAXDISTANCE property is used to indicate the current maximum distance for the specified 3D sound buffer.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSNODEPROPERTY | FLOAT

Comments

For more information on the maximum distance for a DirectSound 3D buffer, see the following topics in the Platform SDK documentation:

  • The flMaxDistance member of the DS3DBUFFER structure.
  • The IDirectSound3DBuffer::GetMaxDistance and IDirectSound3DBuffer::SetMaxDistance methods.

See Also

KSNODEPROPERTY


KSPROPERTY_DIRECTSOUND3DBUFFER_MINDISTANCE

The KSPROPERTY_DIRECTSOUND3DBUFFER_MINDISTANCE property is used to indicate the current minimum distance for the specified 3D sound buffer.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSNODEPROPERTY | FLOAT

Comments

For more information on the minimum distance for a DirectSound 3D buffer, see the following topics in the Platform SDK documentation:

  • The flMinDistance member of the DS3DBUFFER structure.
  • The IDirectSound3DBuffer::GetMinDistance and IDirectSound3DBuffer::SetMinDistance methods.

See Also

KSNODEPROPERTY


KSPROPERTY_DIRECTSOUND3DBUFFER_MODE

The KSPROPERTY_DIRECTSOUND3DBUFFER_MODE property is used to indicate the current mode of the specified 3D sound buffer.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSNODEPROPERTY | ULONG

Comments

The property value is a ULONG with one of the following values, which are defined in header file dsound.h:

  • DS3DMODE_NORMAL
  • DS3DMODE_HEADRELATIVE
  • DS3DMODE_DISABLE

For the meaning of these parameters and for more information on the mode for a DirectSound 3D buffer, see the following topics in the Platform SDK documentation:

  • The dwMode member of the DS3DBUFFER structure.
  • The IDirectSound3DBuffer::GetMode and IDirectSound3DBuffer::SetMode methods.

See Also

KSNODEPROPERTY


KSPROPERTY_DIRECTSOUND3DBUFFER_POSITION

The KSPROPERTY_DIRECTSOUND3DBUFFER_POSITION property is used to indicate the position of the specified 3D sound buffer.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSNODEPROPERTY | DS3DVECTOR

Comments

For more information on the position of a DirectSound 3D buffer, see the following topics in the Platform SDK documentation:

  • The vPosition member of the DS3DBUFFER structure.
  • The IDirectSound3DBuffer::GetPosition and IDirectSound3DBuffer::SetPosition methods.

See Also

KSNODEPROPERTY, DS3DVECTOR


KSPROPERTY_DIRECTSOUND3DBUFFER_VELOCITY

The KSPROPERTY_DIRECTSOUND3DBUFFER_VELOCITY property is used to indicate the value for the current velocity of the specified 3D sound buffer.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSNODEPROPERTY | DS3DVECTOR

Comments

For more information on the velocity of a DirectSound 3D buffer, see the following topics in the Platform SDK documentation:

  • The vVelocity member of the DS3DBUFFER structure.
  • The IDirectSound3DBuffer::GetVelocity and IDirectSound3DBuffer::GetVelocity methods.

See Also

KSNODEPROPERTY, DS3DVECTOR


KSPROPSETID_DirectSound3DListener

The KSPROPSETID_DirectSound3DListener property set contains all the device-specific properties that are needed to implement the IDirectSound3DListener interface (see Platform SDK documentation). Using this property set, the 3D-buffer properties that are specified by the API are passed directly between DirectSound and the WDM audio driver. This property set is handled by the KSNODETYPE_3D_EFFECTS node. This node handles both the 3D-buffer and 3D-listener properties, so the WDM audio driver should apply any updated listener properties to other buffers that share the same listener.

The KSPROPSETID_DirectSound3DListener property set contains the following properties:

KSPROPERTY_DIRECTSOUND3DLISTENER_ALL

KSPROPERTY_DIRECTSOUND3DLISTENER_ALLOCATION

KSPROPERTY_DIRECTSOUND3DLISTENER_BATCH

KSPROPERTY_DIRECTSOUND3DLISTENER_DISTANCEFACTOR

KSPROPERTY_DIRECTSOUND3DLISTENER_DOPPLERFACTOR

KSPROPERTY_DIRECTSOUND3DLISTENER_ORIENTATION

KSPROPERTY_DIRECTSOUND3DLISTENER_POSITION

KSPROPERTY_DIRECTSOUND3DLISTENER_ROLLOFFFACTOR

KSPROPERTY_DIRECTSOUND3DLISTENER_VELOCITY


KSPROPERTY_DIRECTSOUND3DLISTENER_ALL

The KSPROPERTY_DIRECTSOUND3DLISTENER_ALL property is used to set or get all the DirectSound 3D-listener properties for the specified listener ID.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSNODEPROPERTY | KSDS3D_LISTENER_ALL

Comments

The KSDS3D_LISTENER_ALL structure is similar to the DS3DBUFFER structure, which is described in the Platform SDK documentation. Also see the description of the IDirectSound3DBuffer::GetAllParameters and IDirectSound3DBuffer::SetAllParameters methods.

See Also

KSNODEPROPERTY, KSDS3D_LISTENER_ALL


KSPROPERTY_DIRECTSOUND3DLISTENER_ALLOCATION

The KSPROPERTY_DIRECTSOUND3DLISTENER_ALLOCATION property is used to tell the driver when to allocate and free the storage for its listener data. Storage is allocated when the listener is created and freed when the listener is deleted. This property can also be used to query the driver whether listener data is currently allocated.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSNODEPROPERTY | BOOL

Comments

When setting the KSPROPERTY_DIRECTSOUND3DLISTENER_ALLOCATION property value, a property value of TRUE directs the driver to allocate storage for its listener data; a value of FALSE tells the driver to free the listener data. When getting the property, a value of TRUE or FALSE indicates whether or not the driver currently holds a storage allocation for listener data.

See Also

KSNODEPROPERTY


KSPROPERTY_DIRECTSOUND3DLISTENER_BATCH

The KSPROPERTY_DIRECTSOUND3DLISTENER_BATCH property is used to indicate the batch-mode setting for the 3D listener.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSNODEPROPERTY | BOOL

Comments

The value of this property is a BOOL. When the value of this property is TRUE, the miniport driver should cache all changes to the listener properties and all associated buffer properties. When the value is FALSE, changes to the listener properties and buffer properties take effect immediately.

When this property transitions from TRUE to FALSE the miniport driver should put all cached properties into effect immediately. If possible, any cached properties should be put into effect simultaneously.

For more information on batch-mode settings for 3D listeners, see the description of the IDirectSound3DListener::CommitDeferredSettings method in the Platform SDK documentation.

See Also

KSNODEPROPERTY


KSPROPERTY_DIRECTSOUND3DLISTENER_DISTANCEFACTOR

The KSPROPERTY_DIRECTSOUND3DLISTENER_DISTANCEFACTOR property is used to indicate the distance factor that should be applied to any distance values.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSNODEPROPERTY | FLOAT

Comments

The default distance unit is meters. Users can control the distance unit by modifying the distance factor applied to the default distance unit.

See the description of the IDirectSound3DListener::GetDistanceFactor and IDirectSound3DListener::SetDistanceFactor methods in the Platform SDK documentation.

See Also

KSNODEPROPERTY


KSPROPERTY_DIRECTSOUND3DLISTENER_DOPPLERFACTOR

The KSPROPERTY_DIRECTSOUND3DLISTENER_DOPPLERFACTOR property is used to indicate the doppler factor for the specified 3D listener.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSNODEPROPERTY | FLOAT

Comments

See the description of the IDirectSound3DListener::GetDopplerFactor and IDirectSound3DListener::SetDopplerFactor methods in the Platform SDK documentation.

See Also

KSNODEPROPERTY


KSPROPERTY_DIRECTSOUND3DLISTENER_ORIENTATION

The KSPROPERTY_DIRECTSOUND3DLISTENER_ORIENTATION property is used to indicate the listener's orientation for the specified 3D listener.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSNODEPROPERTY | KSDS3D_LISTENER_ORIENTATION

Comments

See the description of the IDirectSound3DListener::GetOrientation and IDirectSound3DListener::SetOrientation methods in the Platform SDK documentation.

See Also

KSNODEPROPERTY, KSDS3D_LISTENER_ORIENTATION


KSPROPERTY_DIRECTSOUND3DLISTENER_POSITION

The KSPROPERTY_DIRECTSOUND3DLISTENER_POSITION property is used to indicate the position for the specified 3D listener.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSNODEPROPEORTY | DS3DVECTOR

Comments

The 3D listener's position is measured in distance units. The default distance unit is a meter. The distance unit can be changed by setting the KSPROPERTY_DIRECTSOUND3DLISTENER_DISTANCEFACTOR property.

See the description of the IDirectSound3DListener::GetPosition and IDirectSound3DListener::SetPosition methods in the Platform SDK documentation.

See Also

KSNODEPROPERTY, DS3DVECTOR


KSPROPERTY_DIRECTSOUND3DLISTENER_ROLLOFFFACTOR

The KSPROPERTY_DIRECTSOUND3DLISTENER_ROLLOFFFACTOR property is used to indicate the roll-off factor for the specified 3D listener.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSNODEPROPERTY | FLOAT

Comments

See the description of the IDirectSound3DListener::GetRolloffFactor and IDirectSound3DListener::SetRolloffFactor methods in the Platform SDK documentation.

See Also

KSNODEPROPERTY


KSPROPERTY_DIRECTSOUND3DLISTENER_VELOCITY

The KSPROPERTY_DIRECTSOUND3DLISTENER_VELOCITY property is used to indicate the velocity vector for the specified 3D listener.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSNODEPROPERTY | DS3DVECTOR

Comments

The 3D listener's velocity is measured in distance units per second. The default distance unit is a meter. The distance unit can be changed by setting the KSPROPERTY_DIRECTSOUND3DLISTENER_DISTANCEFACTOR property.

See the description of the IDirectSound3DListener::GetVelocity and IDirectSound3DListener::SetVelocity methods in the Platform SDK documentation.

See Also

KSNODEPROPERTY, DS3DVECTOR


KSPROPSETID_Synth

The KSPROPSETID_Synth property set includes the following properties:

KSPROPERTY_SYNTH_CAPS (get only)

KSPROPERTY_SYNTH_CHANNELGROUPS (get/set)

KSPROPERTY_SYNTH_LATENCYCLOCK (get only)

KSPROPERTY_SYNTH_PORTPARAMETERS (get only)

KSPROPERTY_SYNTH_RUNNINGSTATS (get only)

KSPROPERTY_SYNTH_VOICEPRIORITY (get/set)

KSPROPERTY_SYNTH_VOLUME (get/set)

KSPROPERTY_SYNTH_VOLUMEBOOST (get/set)

This property set contains items that are global to the configuration of the miniport. These properties will only be applied to the synthesizer topology node at a time when no pin instances exist. The properties in this set are specified as KSPROPERTY_SYNTH enumeration values.

  typedef enum
  {
      KSPROPERTY_SYNTH_VOLUME = 0,  /* should be first */
      KSPROPERTY_SYNTH_VOLUMEBOOST,
      KSPROPERTY_SYNTH_CAPS,
      KSPROPERTY_SYNTH_PORTPARAMETERS,
      KSPROPERTY_SYNTH_CHANNELGROUPS,
      KSPROPERTY_SYNTH_VOICEPRIORITY,
      KSPROPERTY_SYNTH_LATENCYCLOCK
  } KSPROPERTY_SYNTH;


KSPROPERTY_SYNTH_CAPS

[GET]

This property item is used by the system to determine the capabilities of the synthesizer.

Returns

typedef struct _SYNTHCAPS
{
    GUID    Guid;
    DWORD   Flags;
    DWORD   MemorySize;
    DWORD   MaxChannelGroups;
    DWORD   MaxVoices;
    DWORD   MaxAudioChannels;
    DWORD   EffectFlags;
    WCHAR   Description[128];
} SYNTHCAPS, *PSYNTHCAPS;

Members

GUID
Specifies a globally unique identifier for this property-set structure.
Flags
Specifies the bitwise OR of zero, one, or more of the following flags, which represent the capabilities of the driver:
SYNTH_PC_DLS
The driver supports downloadable sample collections (DLS level 1).
SYNTH_PC_EXTERNAL
The synth represents a connection to external hardware.
SYNTH_PC_SOFTWARESYNTH
The driver implements a software synthesizer.
SYNTH_PC_MEMORYSIZEFIXED
The memory size given in the MemorySize member is valid and represents the maximum amount of sample memory in bytes. This flag is normally set when the sample memory is not system memory.
SYNTH_PC_GMINHARDWARE
The synth supports the General MIDI sound set in hardware.
SYNTH_PC_GSINHARDWARE
The synth supports the Roland GS sound set in hardware.
SYNTH_PC_REVERB
The synth supports reverb.
SYNTH_PC_DLS2
The driver supports downloadable sample collections (DLS level 2).
SYNTH_PC_SYSTEMMEMORY
The synth can use system memory.
MemorySize
Specifies the amount of sample memory on the device, in bytes. This field should contain the value SYNTH_PC_SYSTEMMEMORY if the device uses system memory for sample memory with no limitation on the amount of memory allocated.
MaxChannelGroups
Specifies the maximum number of channel groups this driver supports. Each channel group represents a set of 16 MIDI channels, and has associated with it all of the state that a MIDI hardware device would keep; such as DLS, GM, GS, XG, or other mode. DLS downloads, however, are per driver and can be used by any of the channel groups. This prevents wasting memory by downloading several copies of the same DLS sample, one per channel group.
MaxVoices
Specifies the maximum number of voices of the rendering device.
MaxAudioChannels
Specifies the maximum number of audio channels supported by the rendering device.
EffectFlags
Specifies flags for different supported effects.
Description[128]
Specifies a text description of the device, such as "Microsoft MPU-401".

Return Value

The following error codes are not necessarily comprehensive.

STATUS_SUCCESS
The operation completed successfully.
STATUS_UNSUCCESSFUL
The operation was not completed successfully.

Comments

See the description of the IDirectMusicPort::GetCaps method and the DMUS_PORTCAPS structure in the Platform SDK documentation.


KSPROPERTY_SYNTH_CHANNELGROUPS

[GET/SET]

The KSPROPERTY_SYNTH_CHANNELGROUPS property is used by the system to set or retrieve the number of active channel groups on the pin instance. Channel groups are numbered, beginning with zero, on each pin instance.

Takes/Returns

ULONG uNumChannelGroups
Indicates how many channel groups should be supported by this pin. The range of channel groups on the pin is thus zero through [uNumChannelGroups – 1].

Return Values

The following error codes are not necessarily comprehensive.

STATUS_SUCCESS
The operation completed successfully.
STATUS_BUFFER_TOO_SMALL
The buffer was too small to complete the operation.
STATUS_UNSUCCESSFUL
The operation was not completed successfully.

Comments

See the descriptions of the IDirectMusicPort::GetNumChannelGroups and IDirectMusicPort::SetNumChannelGroups methods in the Platform SDK documentation.

See Also

IDirectMusicSynth::SetNumChannelGroups


KSPROPERTY_SYNTH_LATENCYCLOCK

[GET]

This property is used to query the miniport for the stream's current latency-clock time, which is always greater than the master-clock time. KSPROPERTY_SYNTH_LATENCYCLOCK:GET should return a latency-clock time that equals the current master-clock time plus the minimum guaranteed latency of the audio filter that the stream passes through. An application program that schedules audio data to be played before the current latency-clock time risks having the data played late.

Returns

ULONGLONG uLatencyTime
The current latency time, which is specified relative to the master clock and expressed in 100-nanosecond units.

Return Value

The following error codes are not necessarily comprehensive.

STATUS_SUCCESS
The operation completed successfully.
STATUS_BUFFER_TOO_SMALL
The buffer was too small to complete the operation.
STATUS_UNSUCCESSFUL
The operation was not completed successfully.
STATUS_INVALID_DEVICE_REQUEST
The operation is invalid for this device.

Comments

Latency clocks are typically used to synchronize audio output streams among multiple devices. See the discussion of the KSPROPERTY_SYNTH_LATENCYCLOCK property in Latency Clocks.

Also see the descriptions of the IDirectMusicPort::GetLatencyClock and IReferenceClock::GetTime methods in the Platform SDK documentation.

See Also

IDirectMusicSynth::GetLatencyClock


KSPROPERTY_SYNTH_PORTPARAMETERS

[GET]

This is the most complicated of the DirectMusic® property items to handle. Although it is a GET, it also sets the port parameters. The port sends the property item request with a DMUS_PORTPARAMS structure (described in the Platform SDK documentation) as its instance data. There is also a data buffer, but because this is a GET, the data buffer is only used to retrieve information from the miniport.

The miniport needs to copy the DMUS_PORTPARAMS structure to the data buffer and examine the parameters to see if it can support them all. If it cannot support what was requested, the miniport fills in what it can support into the DMUS_PORTPARAMS structure (in the data buffer).

If no changes are made to DMUS_PORTPARAMS, then the caller should get back in the data buffer an identical copy of the what was sent down in the instance data.

By convention, the driver also fills in values that don't have corresponding bits set in the dwValidParams member so that the caller can see what defaults were used. The miniport returns the actual parameters it was able to satisfy and uses these parameters to build a wave interface. Among other things, the miniport should correctly handle sample-rate changes in the KSPROPERTY_SYNTH_PORTPARAMETERS handler.

Takes/Returns

typedef struct _SYNTH_PORTPARAMS
{
    DWORD   ValidParams;
    DWORD   Voices;
    DWORD   ChannelGroups;
    DWORD   AudioChannels;
    DWORD   SampleRate;
    DWORD   EffectsFlags;
    DWORD   Share;
} SYNTH_PORTPARAMS, *PSYNTH_PORTPARAMS;

Members

ValidParams
This DWORD is a bit field indicating which of the SYNTH_PORTPARAMS structure members contain valid data. The value is a bitwise OR of zero or more of the following flag bits:
SYNTH_PORTPARAMS_VOICES
The Voices field is valid.
SYNTH_PORTPARAMS_CHANNELGROUPS
The ChannelGroups field is valid.
SYNTH_PORTPARAMS_AUDIOCHANNELS
The AudioChannels field is valid.
SYNTH_PORTPARAMS_SAMPLERATE
The SampleRate field is valid.
SYNTH_PORTPARAMS_EFFECT
The EffectsFlags flag is valid.
SYNTH_PORTPARAMS_SHARE
The Share field is valid.
Voices
Specifies the maximum number of simultaneous voices that the application wishes to play on this port.
ChannelGroups
Specifies the number of channel groups requested for this port. Each channel groups contains 16 channels.
AudioChannels
Specifies the number of audio channels.
SampleRate
Specifies the number of samples per second for the audio data produced by the port.
EffectsFlags
These flags specify the type of effects produced for audio output from this port. The effects are enabled with default settings. Reverb is controlled by the SYNTH_REVERB_PARAMS property set.
SYNTH_EFFECT_NONE
No effects are selected
SYNTH_EFFECT_REVERB
Reverb is enabled
SYNTH_EFFECT_CHORUS
Chorus effect enabled.
SYNTH_EFFECT_DELAY
Delay effect enabled.
Share
When this member is TRUE, all ports use the channel groups assigned to this port. When this member is FALSE, the port is opened in exclusive mode and the use of the same channel groups by other ports is not allowed.

Return Value

The following error codes are not necessarily comprehensive.

STATUS_SUCCESS
The operation completed successfully.
STATUS_UNSUCCESSFUL
The operation was not completed successfully.


KSPROPERTY_SYNTH_RUNNINGSTATS

[GET]

This property item is used to query the miniport for statistics about the synthesizer. The miniport should return a data structure containing these statistics as shown below.

Returns

typedef struct _SYNTH_STATS
{
    DWORD   ValidStats;       /* Flags indicating which fields below are valid. */
    DWORD   Voices;           /* Average number of voices playing. */
    DWORD   TotalCPU;         /* Total CPU usage as percent * 100. */
    DWORD   CPUPerVoice;      /* CPU per voice as percent * 100. */
    DWORD   LostNotes;        /* Number of notes lost in 1 second. */
    DWORD   FreeMemory;       /* Free memory in bytes */
    LONG    PeakVolume;       /* Decibel level * 100. */
} SYNTH_STATS, *PSYNTH_STATS;

Members

ValidStats
Specifies flags indicating which fields in the SYNTH_STATS structure are valid.
SYNTH_STATS_VOICES
The Voices field contains valid data.
SYNTH_STATS_TOTAL_CPU
The TotalCPU field contains valid data.
SYNTH_STATS_CPU_PER_VOICE
The CPUPerVoice field contains valid data.
SYNTH_STATS_LOST_NOTES
The LostNotes field contains valid data.
SYNTH_STATS_PEAK_VOLUME
The PeakVolume field contains valid data.
SYNTH_STATS_FREE_MEMORY
The FreeMemory field contains valid data.
Voices
Returns the average number of voices playing.
TotalCPU
Returns the CPU usage as percent * 100.
CPUPerVoice
Returns the CPU usage per voice as percent * 100.
LostNotes
Returns the number of notes lost in 1 second.
FreeMemory
Returns the free memory in bytes
PeakVolume
Returns the decibel level * 100.

Comments

See the description of the IDirectMusicPort::GetRunningStats method and the DMUS_SYNTHSTATS structure in the Platform SDK documentation.

See Also

IDirectMusicSynth::GetRunningStats


KSPROPERTY_SYNTH_VOICEPRIORITY

[GET/SET]

The KSPROPERTY_SYNTH_VOICEPRIORITY property is used to specify which voice gets priority when voices need to be bumped from the cache. There are two types of data set using this property: the property data, and optional instance data. The instance data selects the instance to which the item refers. In the case of this property item, the instance data represents the channel group and channel, and the data is a DWORD that specifies the priority. The data is only a DWORD, therefore there is no structure defined for it. If this property item request is a SET, then the priorities are passed in; if this is a GET, the priorities are returned.

Takes/Returns

The instance data is a SYNTHVOICEPRIORITY_INSTANCE structure.

typedef struct _SYNTHVOICEPRIORITY_INSTANCE
{
    DWORD   ChannelGroup;
    DWORD   Channel;
} SYNTHVOICEPRIORITY_INSTANCE, *PSYNTHVOICEPRIORITY_INSTANCE;

Members

ChannelGroup
Specifies the channel group that the voice belongs to.
Channel
Specifies the channel the voice is on.

Voice priorities

The following voice priorities are defined. They are shown in order of highest to lowest priority. These are or'ed with the channel voice priority offsets to arrive at the voice priority for each channel and passed in the property data.

  DAUD_CRITICAL_VOICE_PRIORITY
  DAUD_HIGH_VOICE_PRIORITY
  DAUD_STANDARD_VOICE_PRIORITY
  DAUD_LOW_VOICE_PRIORITY
  DAUD_PERSIST_VOICE_PRIORITY

Default priorities

The following list contains the default priorities that are assigned, if not overridden. By default, priorities are equal across channel groups (for example, channel 5 on channel group 1 has the same priority as channel 5 on channel group 2).

In accordance with DLS level-1 specifications, channel 10 has the highest priority, followed by 1 through 16, except for 10.

  DAUD_CHAN1_VOICE_PRIORITY_OFFSET
  DAUD_CHAN2_VOICE_PRIORITY_OFFSET
  DAUD_CHAN3_VOICE_PRIORITY_OFFSET
  DAUD_CHAN4_VOICE_PRIORITY_OFFSET
  DAUD_CHAN5_VOICE_PRIORITY_OFFSET
  DAUD_CHAN6_VOICE_PRIORITY_OFFSET
  DAUD_CHAN7_VOICE_PRIORITY_OFFSET
  DAUD_CHAN8_VOICE_PRIORITY_OFFSET
  DAUD_CHAN9_VOICE_PRIORITY_OFFSET
  DAUD_CHAN10_VOICE_PRIORITY_OFFSET
  DAUD_CHAN11_VOICE_PRIORITY_OFFSET
  DAUD_CHAN12_VOICE_PRIORITY_OFFSET
  DAUD_CHAN13_VOICE_PRIORITY_OFFSET
  DAUD_CHAN14_VOICE_PRIORITY_OFFSET
  DAUD_CHAN15_VOICE_PRIORITY_OFFSET
  DAUD_CHAN16_VOICE_PRIORITY_OFFSET

Each of these is bitwise ORed with DAUD_STANDARD_VOICE_PRIORITY to give the default for each channel group. For example:

  #define DAUD_CHAN1_DEF_VOICE_PRIORITY  (DAUD_STANDARD_VOICE_PRIORITY | DAUD_CHAN1_VOICE_PRIORITY_OFFSET)

Return Value

The following error codes are not necessarily comprehensive.

STATUS_SUCCESS
The operation completed successfully.
STATUS_BUFFER_TOO_SMALL
The buffer was too small to complete the operation.
STATUS_UNSUCCESSFUL
The operation was not completed successfully.

Comments

See the descriptions of the IDirectMusicPort::GetChannelPriority and IDirectMusicPort::SetChannelPriority methods in the Platform SDK documentation.

See Also

IDirectMusicSynth::GetChannelPriority, IDirectMusicSynth::SetChannelPriority


KSPROPERTY_SYNTH_VOLUME

[GET/SET]

Specifies an offset in 1/100ths of a decibel, for changing the volume of any particular device. The miniport should change its volume or report its volume, depending on whether the request is to get or set the property.

Takes/Returns

LONG lDecibels
If this is a SET, this specifies the volume setting in units of 1/100ths of a decibel. If this is a GET, this returns the current volume setting.

Return Value

STATUS_SUCCESS
The operation completed successfully.
STATUS_BUFFER_TOO_SMALL
The buffer was too small to complete the operation.
STATUS_UNSUCCESSFUL
The operation was not completed successfully.


KSPROPERTY_SYNTH_VOLUMEBOOST

[GET/SET]

This property item allows the system to boost the final output of the synthesizer after all voice articulation and mixing have been completed. This item is used to equalize the volume of the synthesizer with other audio output in the system and should be consistent across all devices.

Takes/Returns

LONG lBoostDecibels
Specifies the amount to add to the audio signal after the mix stage, in 1/100ths of a decibel. This value can be positive or negative. No other boost should be added to the output; the synthesizer should follow strict DLS level-1 conventions for articulation.

Return Value

The following error codes are not necessarily comprehensive.

STATUS_SUCCESS
The operation completed successfully.
STATUS_BUFFER_TOO_SMALL
The buffer was too small to complete the operation.
STATUS_UNSUCCESSFUL
The operation was not completed successfully.


KSPROPSETID_Synth_Dls

The KSPROPSETID_Synth_Dls property set contains items that pertain to downloading and unloading DLS samples and instruments. This section documents the behavior of the properties with regard to the "chunks" of memory being downloaded and unloaded. The actual format of the downloaded instrument and wave data chunks is specified in the low-level DLS discussion in the Platform SDK documentation.

DLS downloads and unloads can occur at any time during the pin's existence. Unlike DirectMusic events, they are not time stamped and should be processed as soon as possible.

Throughout this description, the term DLS resource, or just resource, refers to either a DLS instrument chunk or a DLS wave chunk. The system properly maintains reference counts on all DLS resources, so if the last instrument referencing a wave is unloaded, then the system will explicitly generate a call to unload the wave as well. Conversely, the call to unload a wave will not be made until the last instrument referencing the wave has been unloaded.

The KSPROPERTYSETID_Synth_Dls property set contains the following properties:

KSPROPERTY_SYNTH_DLS_APPEND (get)

KSPROPERTY_SYNTH_DLS_COMPACT (set)

KSPROPERTY_SYNTH_DLS_DOWNLOAD (get)

KSPROPERTY_SYNTH_DLS_UNLOAD (set)

The properties in this set are specified as KSPROPERTY_SYNTH_DLS enumeration values.

typedef enum
{
    KSPROPERTY_SYNTH_DLS_DOWNLOAD = 0,
    KSPROPERTY_SYNTH_DLS_UNLOAD,
    KSPROPERTY_SYNTH_DLS_COMPACT,
    KSPROPERTY_SYNTH_DLS_APPEND
} KSPROPERTY_SYNTH_DLS;


KSPROPERTY_SYNTH_DLS_DOWNLOAD

[GET]

The KSPROPERTY_SYNTH_DLS_DOWNLOAD property item is used for DLS downloads to the synth. The miniport should return a handle to the instance data and indicate whether that buffer can be freed if you have made your own copy of the data buffer. See the discussion of low-level DLS in the Platform SDK documentation for more information on DLS downloads.

Takes

The actual data to be downloaded.

SYNTH_BUFFER

typedef struct _SYNTH_BUFFER
{
    ULONG   BufferSize;
    PVOID   BufferAddress;
} SYNTH_BUFFER, *PSYNTH_BUFFER;

For KSPROPERTY_SYNTH_DLS_DOWNLOAD, PCPROPERTY_REQUEST.Instance is a PSYNTH_BUFFER. The synth buffer is used to send DLS data and articulations to the driver. The reason that this property supports a get request is that data is sent down as instance data and returned as a handle that a user-mode component can later use to reference that data when it wants to unload it.

Members

BufferSize
The size in bytes of the buffer that BufferAddress points to.
BufferAddress
Pointer to a user-mode address that needs to be converted for kernel use.

Example

Download data is passed with a user memory address that needs to be probed and locked before using.

NTSTATUS Status = STATUS_UNSUCCESSFUL;
PSYNTH_BUFFER pDlsBuffer = (PSYNTH_BUFFER)pRequest->Instance;
PMDL pMdl = IoAllocateMdl(pDlsBuffer->BufferAddress, pDlsBuffer->BufferSize, FALSE, FALSE, NULL);
if (pMdl)
{
    __try
    {
        MmProbeAndLockPages(pMdl, KernelMode, IoReadAccess);
        PVOID pvUserData = MmGetSystemAddressForMdl(pMdl);

       // do something with the data
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        Status = GetExceptionCode();
    }

    MmUnlockPages(pMdl);
    IoFreeMdl(pMdl);
}
else
{
    Status = STATUS_NO_MEMORY;
}

Returns

HANDLE DownloadHandle
The driver returns a unique handle to the downloaded chunk in this field. The system will use this handle whenever referring to this chunk, which is described in the SYNTHDOWNLOAD structure below.

SYNTHDOWNLOAD

typedef struct _SYNTHDOWNLOAD
{
    HANDLE  DownloadHandle;
    BOOL    Free;               /* the client buffer can be freed */
} SYNTHDOWNLOAD, *PSYNTHDOWNLOAD;

Members

DownloadHandle
This is a handle to the downloaded data buffer.
Free
This member should be set to TRUE if you've made your own copy of the data. This allows the client buffer to be freed.

Return Values

The following error codes are not necessarily comprehensive.

STATUS_SUCCESS
The operation completed successfully.
STATUS_BUFFER_TOO_SMALL
The buffer was too small to complete the operation.
STATUS_UNSUCCESSFUL
The operation was not completed successfully.
STATUS_NO_MEMORY
There is no memory to complete this request.

See Also

IDirectMusicSynth::Download


KSPROPERTY_SYNTH_DLS_UNLOAD

[SET]

Takes

HANDLE hDownloadHandle
The handle to the downloaded object to free. This handle will be a handle the driver has returned in a previous get of KSPROPERTY_SYNTH_DLS_DOWNLOAD. The driver should unload the resource as soon as no notes are playing using the resource. If a note on event comes in on a patch using the resource, it should be ignored unless a new DLS resource has been downloaded in the interim.

If the synthesizer is not able to free the memory associated with the DLS instance at the time of the property request, then it can use asynchronous property completion to finish the request at a later time.

Return Values

The following error codes are not necessarily comprehensive.

STATUS_SUCCESS
The operation completed successfully.
STATUS_BUFFER_TOO_SMALL
The buffer was too small to complete the operation.
STATUS_UNSUCCESSFUL
The operation was not completed successfully.
STATUS_PENDING
The operation will complete at a later time.

See Also

IDirectMusicSynth::Unload


KSPROPERTY_SYNTH_DLS_COMPACT

[SET]

This property item is a request for the synthesizer to make available the largest possible chunk of free sample memory. The implementation should not interrupt playback.

Return Values

The following error codes are not necessarily comprehensive.

STATUS_SUCCESS
The operation completed successfully.
STATUS_UNSUCCESSFUL
The operation was not completed successfully.


KSPROPERTY_SYNTH_DLS_APPEND

[GET]

Returns

ULONG uAppendBytes
The number of bytes the miniport would like to reserve for its own use at the end of a DLS download. Any download buffer will contain the requested number of bytes after the end of the downloaded data. This area is intended for drivers that need extra padding for alignment requirements or to replicate the start of a sample to simplify sample interpolation.

Return Values

The following error codes are not necessarily comprehensive.

STATUS_SUCCESS
The operation completed successfully.
STATUS_UNSUCCESSFUL
The operation was not completed successfully.


KSPROPSETID_TopologyNode

The KSPROPSETID_TopologyNode property set provides generic control over the various topology nodes. For a list of topology node types, see Audio Topology Nodes. The properties in this set can be used to enable, disable, and reset topology nodes. This property set is supported in Windows XP and later.

The KSPROPSETID_TopologyNode property set contains the following properties:

KSPROPERTY_TOPOLOGYNODE_ENABLE

KSPROPERTY_TOPOLOGYNODE_RESET


KSPROPERTY_TOPOLOGYNODE_ENABLE

The KSPROPERTY_TOPOLOGYNODE_ENABLE property is used to turn on or off the topology nodes in an already-built topology.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Filter | KSNODEPROPERTY | BOOL

Comments

A value of TRUE indicates that the node is turned ON. A value of FALSE indicates that the node is turned OFF.

Enabling an already enabled node or disabling an already disabled node has no effect but should not be treated as an error.

See Also

KSNODEPROPERTY


KSPROPERTY_TOPOLOGYNODE_RESET

The KSPROPERTY_TOPOLOGYNODE_RESET resets the node completely and places it in its initial known state.

Get | Set | Target | Property descriptor type | Property value type
No | Yes | Filter | KSNODEPROPERTY | BOOL

Comments

A value of TRUE resets the node to its default initial state at the time of creation. A value of FALSE has no effect but should not be treated as an error.

See Also

KSNODEPROPERTY


Audio Events

The following event set is defined for WDM audio drivers:

KSEVENTSETID_AudioControlChange


KSEVENTSETID_AudioControlChange

The events within the KSEVENTSETID_AudioControlChange set are used to notify clients when a miniport driver detects a hardware event, which is a change in a hardware volume-control knob, mute switch, or other type of hardware control.

The only event in this set is KSEVENT_CONTROL_CHANGE.


KSEVENT_CONTROL_CHANGE

The KSEVENT_CONTROL_CHANGE event indicates that a change in control value has occurred at a node that represents a hardware volume-control knob, mute switch, or other type of hardware control.


Audio Topology Nodes

A standard set of nodes is defined for audio devices. The driver describes the device's audio topology by describing nodes and connections between these nodes. The SysAudio system driver uses this information to construct the audio filter graphs.

Each node supports a set of node properties. Node properties differ from pin properties by the inclusion of a node ID that identifies the internal node to which the property is directed. Thus, a get- or set-property request is delivered to a specific pin instance and node ID that uniquely identifies the desired node in the audio topology. Below is a list of audio topology node types:

KSNODETYPE_ACOUSTIC_ECHO_CANCEL

KSNODETYPE_ADC

KSNODETYPE_AGC

KSNODETYPE_CHORUS

KSNODETYPE_DAC

KSNODETYPE_DELAY

KSNODETYPE_DEMUX

KSNODETYPE_3D_EFFECTS

KSNODETYPE_DEV_SPECIFIC

KSNODETYPE_EQUALIZER

KSNODETYPE_LOUDNESS

KSNODETYPE_MUTE

KSNODETYPE_MUX

KSNODETYPE_PEAKMETER

KSNODETYPE_PROLOGIC_DECODER

KSNODETYPE_REVERB

KSNODETYPE_SRC

KSNODETYPE_STEREO_ENHANCE

KSNODETYPE_STEREO_WIDE

KSNODETYPE_SURROUND_ENCODER

KSNODETYPE_SUM

KSNODETYPE_SUPERMIX

KSNODETYPE_TONE

KSNODETYPE_VOLUME


KSNODETYPE_ACOUSTIC_ECHO_CANCEL

The KSNODETYPE_ACOUSTIC_ECHO_CANCEL node represents an AEC (acoustic echo cancellation) control. In a full-duplex audio application such as telephone conferencing, echoes of the render stream being output through the speakers are picked up in the microphone that generates the capture stream. After characterizing the sound reflections in the room or other physical environment, the full-duplex system relies on an AEC node to monitor the render stream in order cancel out the echoes that it adds to the capture stream.

An AEC node has connections for two input streams and two output streams. One input/output pair is used for the capture stream, and the other input/output pair is used for the render stream. The capture-output and render-input streams have the same format. The capture-input and render-output streams can have a different number of channels and different sample rates; in a typical implementation, however, the two streams either have the same sample rate or a combination such as 16 and 48 kHz or 11 and 44 kHz in which one sample rate is an integer multiple of the other.

An AEC node should number its logical pins with the pin IDs from header file ksmedia.h, which are shown in the table below.

Pin ID parameter | Meaning
KSNODEPIN_AEC_RENDER_IN | Sink pin (node input) for render stream.
KSNODEPIN_AEC_RENDER_OUT | Source pin (node output) for render stream.
KSNODEPIN_AEC_CAPTURE_IN | Sink pin (node input) for capture stream.
KSNODEPIN_AEC_CAPTURE_OUT | Source pin (node output) for capture stream.

Note that the "pins" in the table above are logical pins on the node, which are used solely to specify connections internal to the filter, rather than external pins on the filter, which are used to connect to other filters. For details, see PCCONNECTION_DESCRIPTOR.

For information on how a filter containing an AEC node can provide support for full-duplex DirectSound applications, see DirectSound Capture Effects.

When a filter containing an AEC node is created or the node is reset, the node is initially configured to operate in pass-through mode.

A KSNODETYPE_ACOUSTIC_ECHO_CANCEL node should support the following properties in order to enable hardware acceleration:

KSPROPERTY_AUDIO_CPU_RESOURCES

KSPROPERTY_AUDIO_ALGORITHM_INSTANCE

KSPROPERTY_TOPOLOGYNODE_ENABLE

KSPROPERTY_TOPOLOGYNODE_RESET

A KSNODETYPE_ACOUSTIC_ECHO_CANCEL node can also support the following optional properties in order to provide additional control and monitoring capabilities:

KSPROPERTY_AEC_MODE

KSPROPERTY_AEC_NOISE_FILL_ENABLE

KSPROPERTY_AEC_STATUS


KSNODETYPE_ADC

The KSNODETYPE_ADC node represents an analog-to-digital converter (ADC). The ADC has one input stream and one output stream.

A KSNODETYPE_ADC node can support the following optional properties:

KSPROPERTY_AUDIO_SAMPLING_RATE

KSPROPERTY_AUDIO_DYNAMIC_SAMPLING_RATE


KSNODETYPE_AGC

The KSNODETYPE_AGC node represents an automatic gain control (AGC). An AGC node has one input stream and one output stream; each of the two streams has the same data format. It automatically adjusts the amount of attenuation or gain applied to the input stream to achieve maximum dynamic range without clipping.

A KSNODETYPE_AGC node should support the following property:

KSPROPERTY_AUDIO_AGC


KSNODETYPE_CHORUS

The KSNODETYPE_CHORUS node represents a chorus effects processor, which adds a chorus effect to the output stream. The chorus node has one input stream and one output stream; these two streams share the same data format.

A KSNODETYPE_CHORUS node should support the following required property:

KSPROPERTY_AUDIO_CHORUS_LEVEL


KSNODETYPE_DAC

The KSNODETYPE_DAC node represents a digital-to-analog converter (DAC). The DAC has one input stream and one output stream.

A KSNODETYPE_DAC node can support the following optional properties:

KSPROPERTY_AUDIO_SAMPLING_RATE

KSPROPERTY_AUDIO_DYNAMIC_SAMPLING_RATE


KSNODETYPE_DELAY

The KSNODETYPE_DELAY node represents a delay control. The delay control has one input stream and one output stream; these two streams share the same data format. The delay control causes the output stream to lag behind the input stream by some specified amount of time.

A KSNODETYPE_DELAY node should support the following required property:

KSPROPERTY_AUDIO_DELAY


KSNODETYPE_DEMUX

The KSNODETYPE_DEMUX node represents a demultiplexer. This control has a single input stream and multiple output streams.

A KSNODETYPE_DEMUX node should support the following property:

KSPROPERTY_AUDIO_DEMUX_DEST


KSNODETYPE_DEV_SPECIFIC

The KSNODETYPE_DEV_SPECIFIC node represents a device-specific control. The device-specific control can have multiple input streams and multiple output streams. It performs a set of functions that are specific to the particular audio device.

A KSNODETYPE_DEV_SPECIFIC node should support the following required property:

KSPROPERTY_AUDIO_DEV_SPECIFIC


KSNODETYPE_3D_EFFECTS

The KSNODETYPE_3D_EFFECTS node represents a 3D-effects processor for the device-specific 3D HAL that underlies the IDirectSound3DBuffer and IDirectSound3DListener APIs (see the Platform SDK documentation). The 3D-effects node has one input stream with M channels and one output stream with N channels. It positions the individual channels of the input stream within the 3D-sound field of the output stream.

The 3D-effects node is used to monitor and control the following DirectSound 3D-listener and 3D-buffer properties:

KSPROPERTY_DIRECTSOUND3DBUFFER_ALL

KSPROPERTY_DIRECTSOUND3DBUFFER_POSITION

KSPROPERTY_DIRECTSOUND3DBUFFER_VELOCITY

KSPROPERTY_DIRECTSOUND3DBUFFER_CONEANGLES

KSPROPERTY_DIRECTSOUND3DBUFFER_CONEORIENTATION

KSPROPERTY_DIRECTSOUND3DBUFFER_CONEOUTSIDEVOLUME

KSPROPERTY_DIRECTSOUND3DBUFFER_MINDISTANCE

KSPROPERTY_DIRECTSOUND3DBUFFER_MAXDISTANCE

KSPROPERTY_DIRECTSOUND3DBUFFER_MODE

KSPROPERTY_DIRECTSOUND3DLISTENER_ALL

KSPROPERTY_DIRECTSOUND3DLISTENER_POSITION

KSPROPERTY_DIRECTSOUND3DLISTENER_VELOCITY

KSPROPERTY_DIRECTSOUND3DLISTENER_ORIENTATION

KSPROPERTY_DIRECTSOUND3DLISTENER_DISTANCEFACTOR

KSPROPERTY_DIRECTSOUND3DLISTENER_ROLLOFFFACTOR

KSPROPERTY_DIRECTSOUND3DLISTENER_DOPPLERFACTOR

KSPROPERTY_DIRECTSOUND3DLISTENER_BATCH


KSNODETYPE_EQUALIZER

The KSNODETYPE_EQUALIZER node represents an equalizer with multiple frequency bands. The equalizer has one input stream and one output stream; each of the two streams has the same data format. It can adjust the amount of each frequency band in the output stream.

A KSNODETYPE_EQUALIZER node should support the following required properties:

KSPROPERTY_AUDIO_EQ_LEVEL

KSPROPERTY_AUDIO_NUM_EQ_BANDS

KSPROPERTY_AUDIO_EQ_BANDS


KSNODETYPE_LOUDNESS

The KSNODETYPE_LOUDNESS node represents a loudness control that adjusts the dynamic range of the output stream. The loudness control has one input stream and one output stream; each of the two streams has the same data format.

A KSNODETYPE_LOUDNESS node should support at least one of the following properties:

KSPROPERTY_AUDIO_LOUDNESS

KSPROPERTY_AUDIO_DYNAMIC_RANGE


KSNODETYPE_MUTE

The KSNODETYPE_MUTE node represents a mute control. This node has one input stream and one output stream; each of the two streams has the same data format. It switches the input on or off.

A KSNODETYPE_MUTE node should support the following required property:

KSPROPERTY_AUDIO_MUTE


KSNODETYPE_MUX

The KSNODETYPE_MUX node represents a multiplexer (MUX). The MUX has multiple input streams and one output stream, all with the same data format. Only one input stream at a time is routed to the output stream.

A KSNODETYPE_MUX node should support the following required property:

KSPROPERTY_AUDIO_MUX_SOURCE


KSNODETYPE_NOISE_SUPPRESS

The KSNODETYPE_NOISE_SUPPRESS node represents a noise-suppression (NS) control. An NS node has connections for one input stream and one output stream. Both streams have the same format.

When a filter containing an NS node is created or the node is reset, the node is initially configured to operate in pass-through mode.

An NS node can be incorporated into an AEC (acoustic echo cancellation) filter to support full-duplex DirectSound applications. For more information, see DirectSound Capture Effects.

A KSNODETYPE_NOISE_SUPPRESS node in an AEC filter should support the following properties in order to enable hardware acceleration:

KSPROPERTY_AUDIO_CPU_RESOURCES

KSPROPERTY_AUDIO_ALGORITHM_INSTANCE

KSPROPERTY_TOPOLOGYNODE_ENABLE

KSPROPERTY_TOPOLOGYNODE_RESET


KSNODETYPE_PEAKMETER

A KSNODETYPE_PEAKMETER node represents a hardware peakmeter. A KS peakmeter node has one input pin and one output pin; the two pins share the same data format.

A KS peakmeter internally logs the maximum value of the audio signal since the last time the peakmeter was reset to zero. The peakmeter automatically resets itself to zero after an IOCTL_KS_PROPERTY request to get a KSPROPERTY_AUDIO_PEAKMETER property.

A peakmeter requires hardware support. A software peakmeter is not feasible because the adapter driver does not have access to signals that are present on line-in, microphone, or other inputs that are mixed with the playback channel.

Microsoft recommends making a peakmeter node the final node through which a stream passes within a filter. On a render stream, an audio adapter usually connects a peakmeter node after a master output KSNODETYPE_MUTE node or a KSNODETYPE_VOLUME node. The same approach applies to a capture stream or any other streams for which the filter incorporates a peakmeter node.

An audio adapter should name a peakmeter node KSAUDFNAME_PEAKMETER.

A peakmeter node should provide a property handler for the property flags (see KSPROPERTY) that appear in the table below.

Flag name | Meaning
KSPROPERTY_TYPE_GET | Returns the current value of the hardware peakmeter.
KSPROPERTY_TYPE_BASICSUPPORT | Returns a data range of -32768 to 32767, which is the data range of 16-bit digital audio.

The property handler should verify input parameters and left and right channel information.

A peakmeter node should also support the properties in the following table.

Property name | Description
KSPROPERTY_AUDIO_PEAKMETER | Represents the peakmeter control.
KSPROPERTY_AUDIO_CPU_RESOURCES | Indicates whether the specified node's functionality makes use of the host CPU.


KSNODETYPE_PROLOGIC_DECODER

The KSNODETYPE_PROLOGIC_DECODER node represents a Dolby Surround Pro Logic decoder. The decoder control has one stereo input stream and one output stream with one to four channels. In the four-channel output format, the channels are mapped to left, right, center, and back speaker. In the three-channel output format, the channels are mapped to left, right, and back speakers.

A KSNODETYPE_PROLOGIC_DECODER node should support the KSPROPERTY_AUDIO_CHANNEL_CONFIG property, which is used to select the output format.


KSNODETYPE_REVERB

The KSNODETYPE_REVERB node represents a reverberation (or reverb) control. The reverb control has one input stream and one output stream; each of the two streams has the same data format. It adds reverberation to the output stream.

A KSNODETYPE_REVERB node should support the following required property:

KSPROPERTY_AUDIO_REVERB_LEVEL


KSNODETYPE_SRC

The KSNODETYPE_SRC node represents a sample-rate converter, which produces an output stream that is a digitally re-sampled version of the input stream. The SRC node has one input stream and one output stream, each with the same number of channels.

A KSNODETYPE_SRC node can support the following optional properties:

KSPROPERTY_AUDIO_SAMPLING_RATE

KSPROPERTY_AUDIO_DYNAMIC_SAMPLING_RATE

KSPROPERTY_AUDIO_QUALITY


KSNODETYPE_STEREO_ENHANCE

This parameter name is reserved for future use.


KSNODETYPE_STEREO_WIDE

This parameter name is reserved for future use.


KSNODETYPE_SURROUND_ENCODER

The KSNODETYPE_SURROUND_ENCODER node represents a Dolby Surround Pro Logic encoder. The node accepts a four-channel input stream with channels for left, right, center, and back speakers. The node encodes the input stream as a surround-encoded stereo output stream.

The functionality of the KSNODETYPE_SURROUND_ENCODER node is complementary to the KSNODETYPE_PROLOGIC_DECODER node, which takes a surround-encoded stereo input stream and decodes it into a four-channel stream with channels for left, right, center, and back speakers.

In Microsoft® Windows® XP and later, KMixer has a KSNODETYPE_SURROUND_ENCODER node.

A KSNODETYPE_SURROUND_ENCODER node should support the KSPROPERTY_AUDIO_SURROUND_ENCODE property, which is used to enable and disable the node.


KSNODETYPE_SUM

The KSNODETYPE_SUM node represents a simple summer (SUM). The SUM has multiple input streams and one output stream, all with the same data format. The input streams are mixed equally to produce the output stream.

A KSNODETYPE_SUM node does not currently support any properties.


KSNODETYPE_SUPERMIX

The KSNODETYPE_SUPERMIX node represents a super mixer. A super mixer has one input stream with M channels and one output stream with N channels. For each output channel, the super mixer specifies a mix level for each of the input channels that adds to the mix in the output channel. The M-channel input stream is up-mixed or down-mixed to N channels.

A KSNODETYPE_SUPERMIX node should support the following required properties:

KSPROPERTY_AUDIO_MIX_LEVEL_TABLE

KSPROPERTY_AUDIO_MIX_LEVEL_CAPS


KSNODETYPE_TONE

The KSNODETYPE_TONE node represents a tone control. The tone control has one input stream and one output stream; the two streams have the same data format. It can attenuate the amount of bass, treble, or mid-frequencies of the output stream. In addition, it may optionally support a bass boost or gain.

A KSNODETYPE_TONE node should support at least one of the following properties:

KSPROPERTY_AUDIO_BASS

KSPROPERTY_AUDIO_MID

KSPROPERTY_AUDIO_TREBLE

KSPROPERTY_AUDIO_BASS_BOOST


KSNODETYPE_VOLUME

The KSNODETYPE_VOLUME node represents a volume (gain or attenuation) control. The volume control has one input stream and one output stream; each of the two streams has the same data format. It can apply attenuation (reduction in volume) or gain (increase in volume) to the stream. In addition, it may optionally support inverting the signal.

A KSNODETYPE_VOLUME node should support the following required property:

KSPROPERTY_AUDIO_VOLUMELEVEL


Audio Drivers Structures

This section describes, in alphabetic order, the structures that are used by WDM audio miniport drivers.


DS3DVECTOR

The DS3DVECTOR structure contains position coordinates, position vector components, or velocity vector components.

typedef struct _DS3DVECTOR {
union
{
    FLOAT x;
    FLOAT dvx;
};
union
{
    FLOAT y;
    FLOAT dvy;
union
{
    FLOAT z;
    FLOAT dvz;
} ;
} DS3DVECTOR, *PDS3DVECTOR;

Members

x
X coordinate of the position.
y
Y coordinate of the position.
z
Z coordinate of the position.
dvx
X component of the vector.
dvy
Y component of the vector.
dvz
Z component of the vector.

Headers

Declared in ksmedia.h. Include ksmedia.h.

See Also

KSDS3D_BUFFER_ALL, KSDS3D_LISTENER_ALL, KSDS3D_LISTENER_ORIENTATION


KSAUDIO_CHANNEL_CONFIG

A KSAUDIO_CHANNEL_CONFIG structure specifies the configuration of channels within the data format of an audio stream. This structure is used to set or get the data value for the KSPROPERTY_AUDIO_CHANNEL_CONFIG property.

typedef struct {
  LONG  ActiveSpeakerPositions;
} KSAUDIO_CHANNEL_CONFIG;

Members

ActiveSpeakerPositions
Specifies both the number of channels and the assignment of those channels to speaker positions.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The following table shows the flag bits that are defined for the ActiveSpeakerPositions member.

Speaker position | Flag bit
SPEAKER_FRONT_LEFT | 0x1
SPEAKER_FRONT_RIGHT | 0x2
SPEAKER_FRONT_CENTER | 0x4
SPEAKER_LOW_FREQUENCY | 0x8
SPEAKER_BACK_LEFT | 0x10
SPEAKER_BACK_RIGHT | 0x20
SPEAKER_FRONT_LEFT_OF_CENTER | 0x40
SPEAKER_FRONT_RIGHT_OF_CENTER | 0x80
SPEAKER_BACK_CENTER | 0x100
SPEAKER_SIDE_LEFT | 0x200
SPEAKER_SIDE_RIGHT | 0x400
SPEAKER_TOP_CENTER | 0x800
SPEAKER_TOP_FRONT_LEFT | 0x1000
SPEAKER_TOP_FRONT_CENTER | 0x2000
SPEAKER_TOP_FRONT_RIGHT | 0x4000
SPEAKER_TOP_BACK_LEFT | 0x8000
SPEAKER_TOP_BACK_CENTER | 0x10000
SPEAKER_TOP_BACK_RIGHT | 0x20000

Each audio data format contains channels for one or more of the above speaker positions. The number of channels simply equals the number of nonzero flag bits in the ActiveSpeakerPositions member.

The relative positions of the channels within each block of audio data always follow the same relative ordering as the flag bits in the table above. For example, if ActiveSpeakerPositions contains the value 0x00000033, the format defines four audio channels that are assigned for playback to the front-left, front-right, back-left, and back-right speakers, respectively. The channel data should be interleaved in that order within each block. (This is the KSAUDIO_SPEAKER_QUAD configuration that appears in the second table below.)

The following table shows the speaker configurations that are defined for DVD.

Configuration | Speaker positions
KSAUDIO_SPEAKER_GROUND_FRONT_LEFT | SPEAKER_FRONT_LEFT
KSAUDIO_SPEAKER_GROUND_FRONT_CENTER | SPEAKER_FRONT_CENTER
KSAUDIO_SPEAKER_GROUND_FRONT_RIGHT | SPEAKER_FRONT_RIGHT
KSAUDIO_SPEAKER_GROUND_REAR_LEFT | SPEAKER_BACK_LEFT
KSAUDIO_SPEAKER_GROUND_REAR_RIGHT | SPEAKER_BACK_RIGHT
KSAUDIO_SPEAKER_TOP_MIDDLE | SPEAKER_TOP_CENTER
KSAUDIO_SPEAKER_SUPER_WOOFER | SPEAKER_LOW_FREQUENCY

The following table shows the speaker configurations that are defined for DirectSound.

Configuration | Speaker positions
KSAUDIO_SPEAKER_DIRECTOUT | 0 (no speakers)
KSAUDIO_SPEAKER_MONO | (SPEAKER_FRONT_CENTER)
KSAUDIO_SPEAKER_STEREO | (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT)
KSAUDIO_SPEAKER_QUAD | (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT)
KSAUDIO_SPEAKER_SURROUND | (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_CENTER)
KSAUDIO_SPEAKER_5POINT1 | (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT)
KSAUDIO_SPEAKER_7POINT1 | (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_FRONT_LEFT_OF_CENTER | SPEAKER_FRONT_RIGHT_OF_CENTER)

In the table above, the constant KSAUDIO_SPEAKER_DIRECTOUT has the value zero, which means that no speaker positions are assigned to the channels in the multi-channel stream. For example, channel zero might represent percussion, channel one might represent trumpet, channel two might represent voice, and so on. In this configuration, the channels in the input stream are output directly to the hardware without modification and without being interpreted as speaker positions.

Example

The speaker configuration for a 5.1-channel format is defined by the constant KSAUDIO_SPEAKER_5POINT1 in the table above. The geometric layout of the speakers is shown in the figure below, which shows the positions of the front-left, front-right, front-center, back-left, and back-right speakers; the figure omits the low-frequency speaker because it is nondirectional.

5.1-Channel Speaker Configuration (Low-Frequency Speaker Not Shown)

For this example, the ordering of the six channels within each block of audio data is as follows:

  1. SPEAKER_FRONT_LEFT
  2. SPEAKER_FRONT_RIGHT
  3. SPEAKER_FRONT_CENTER
  4. SPEAKER_LOW_FREQUENCY
  5. SPEAKER_BACK_LEFT
  6. SPEAKER_BACK_RIGHT

Assuming a 16-bit sample size, each block of audio data occupies 12 bytes, which are ordered as shown in the figure below.

Ordering of Bytes for the 5.1-Channel Example

See Also

KSPROPERTY_AUDIO_CHANNEL_CONFIG, WAVEFORMATEXTENSIBLE


KSAUDIO_DYNAMIC_RANGE

The KSAUDIO_DYNAMIC_RANGE structure specifies the dynamic range of an audio stream. This structure is used to get or set the data value for the KSPROPERTY_AUDIO_DYNAMIC_RANGE property.

typedef struct {
  ULONG  QuietCompression;
  ULONG  LoudCompression;
} KSAUDIO_DYNAMIC_RANGE, *PKSAUDIO_DYNAMIC_RANGE;

Members

QuietCompression
Value ranging from 0 to 100 percent (0xffffffff) of the linear range compression for soft sounds. The higher this value, the higher the volume of soft sounds.
LoudCompression
Value ranging from 0 to 100 percent (0xffffffff) of the linear range compression for loud sounds. The higher this value, the lower the volume of loud sounds.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comment

By default, both of these values are set to 0 percent, which reproduces the full dynamic range of the audio stream.

See Also

KSPROPERTY_AUDIO_DYNAMIC_RANGE


KSAUDIO_MIX_CAPS

The KSAUDIO_MIX_CAPS structure specifies the mixing capabilities of a particular data path from one input channel of a supermixer node (see KSNODETYPE_SUPERMIX) to an output channel of the same node. An array of these structures is used by a KSAUDIO_MIXCAP_TABLE structure to specify the mixing capabilities for all such paths through a supermixer node.

typedef struct {
  BOOL  Mute;
  LONG  Minimum;
  LONG  Maximum;
  LONG  Resolution;
} KSAUDIO_MIX_CAPS, *PKSAUDIO_MIX_CAPS;

Members

Mute
Indicates whether the data path from the input channel to the output channel is muted (not mixed).
Minimum
Indicates the minimum mix level for the data path from the input channel to the output channel. Level values use the following scale: a dB range from –2147483648 to +2147483647, where –2147483648 is –Infinity dB attenuation, –2147483647 is –32767.99998474 dB (attenuation), and +2147483647 is +32767.99998474 dB (gain). The scale has a resolution on 1/65536 dB.
Maximum
Indicates the maximum mix level for the data path from the input channel to the output channel. Level values use the following scale: a dB range from –2147483648 to +2147483647, where –2147483648 is –Infinity dB attenuation, –2147483647 is –32767.99998474 dB (attenuation), and +2147483647 is +32767.99998474 dB (gain). The scale has a resolution of 1/65536 dB.
Resolution
Indicates the resolution of the mix level for the data path from the input channel to the output channel. Resolution values use the following scale: a range from 0 to +2147483647, where 0 is no control, and any other number is the number of steps between "real" changes.

Headers

Declared in ksmedia.h. Include ksmedia.h.

See Also

KSPROPERTY_AUDIO_MIX_LEVEL_CAPS, KSPROPERTY_AUDIO_MIX_LEVEL_TABLE, KSAUDIO_MIXCAP_TABLE, KSNODETYPE_SUPERMIX


KSAUDIO_MIXCAP_TABLE

A KSAUDIO_MIXCAP_TABLE structure specifies the mixing capabilities of a supermixer node (see KSNODETYPE_SUPERMIX). This structure is used to get or set the data value for the KSPROPERTY_AUDIO_MIX_LEVEL_CAPS property.

typedef struct {
  ULONG  InputChannels;
  ULONG  OutputChannels;
  KSAUDIO_MIX_CAPS  Capabilities[];
} KSAUDIO_MIXCAP_TABLE, *PKSAUDIO_MIXCAP_TABLE;

Members

InputChannels
Number of input channels.
OutputChannels
Number of output channels.
Capabilities
The first entry in a two-dimensional array of KSAUDIO_MIX_CAPS structures. Given a supermixer node with M input channels and N output channels, the array contains M*N elements. Each element describes the mix-level capabilities of the path from a particular input channel to a particular output channel.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The Capabilities table is an M-by-N matrix that maps M input channels into N output channels. If no mapping exists from the input i to output j, the Mute member of the (i,j) entry should be set to TRUE. The size of the table is calculated from the KSAUDIO_MIXCAP_TABLE structure that is retrieved by a KSPROPERTY_AUDIO_MIX_LEVEL_CAPS get-property request. If the InputChannels and OutputChannels members have the values M and N, respectively, the total storage required for the KSAUDIO_MIXCAP_TABLE structure plus the KSAUDIO_MIX_CAPS array is calculated as

sizeof(KSAUDIO_MIXCAP_TABLE) + (M*N - 1)*sizeof(KSAUDIO_MIX_CAPS)

The KSAUDIO_MIXCAP_TABLE structure can be sent first with a property size of two ULONGs that should fill in only the first two members of the KSAUDIO_MIXCAP_TABLE structure. A second property request can then be made with enough storage allocated to contain the capabilities of all the channels.

The Capabilities table is stored as a two-dimensional array. The individual KSAUDIO_MIX_CAPS entries in the table are addressed as shown in the following table.

Order | Description
Entry 0 | Mix caps of input channel 0 mixed into output channel 0.
Entry 1 | Mix caps of input channel 0 mixed into output channel 1.
Entry N–1 | Mix caps of input channel 0 mixed into output channel N–1.
Entry N | Mix caps of input channel 0 mixed into output channel 0.
Entry N+1 | Mix caps of input channel 0 mixed into output channel 1.
Entry 2N–1 | Mix caps of input channel 0 mixed into output channel N–1.
Entry (N-1) * (M-1) | Mix caps of input channel M–1 mixed into output channel N–1.

See Also

KSPROPERTY_AUDIO_MIX_LEVEL_CAPS, KSPROPERTY_AUDIO_MIX_LEVEL_TABLE, KSAUDIO_MIX_CAPS, KSNODETYPE_SUPERMIX


KSAUDIO_MIXLEVEL

The KSAUDIO_MIXLEVEL structure specifies the mixing level of a particular data path from one input channel of a supermixer node (see KSNODETYPE_SUPERMIX) to an output channel of the same node. To specify the mixing levels of all paths through a supermixer node with M input channels and N output channels requires a mix-level table consisting of an M-by-N array of KSAUDIO_MIXLEVEL structures. This table is used to set or get the data value for the KSPROPERTY_AUDIO_MIX_LEVEL_TABLE property.

typedef struct  {
  BOOL  Mute;
  LONG  Level;
} KSAUDIO_MIXLEVEL, *PKSAUDIO_MIXLEVEL;

Members

Mute
Boolean value that indicates whether the input channel is muted (not mixed) into the output channel.
Level
Level values use the following scale: a dB range from –2147483648 to +2147483647, where –2147483648 is –Infinity dB attenuation, –2147483647 is –32767.99998474 dB (attenuation), and +2147483647 is +32767.99998474 dB (gain). The scale has a resolution of 1/65536 dB. The filter will succeed a set-property request that specifies a value that is beyond the range of the filter but will clamp the value to the supported range; in a subsequent request to get this property, however, it will return the actual value used.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

Given a supermixer node with M input channels and N output channels, the KSPROPERTY_AUDIO_MIX_LEVEL_TABLE get-property request retrieves an M-by-N array of KSAUDIO_MIXLEVEL structures. The number of input and output channels can be determined first by making a KSPROPERTY_AUDIO_MIX_LEVEL_CAPS get-property request.

The table of KSAUDIO_MIXLEVEL entries is organized as a two-dimensional array. The individual table entries within the array are addressed as shown in the following table.

Order | Description
Entry 0 | Mix level of input channel 0 mixed into output channel 0.
Entry 1 | Mix level of input channel 0 mixed into output channel 1.
Entry N–1 | Mix level of input channel 0 mixed into output channel N–1.
Entry N | Mix level of input channel 0 mixed into output channel 0.
Entry N+1 | Mix level of input channel 0 mixed into output channel 1.
Entry 2N–1 | Mix level of input channel 0 mixed into output channel N–1.
Entry (N-1) * (M-1) | Mix level of input channel M-1 mixed into output channel N-1.

See Also

KSPROPERTY_AUDIO_MIX_LEVEL_TABLE, KSPROPERTY_AUDIO_MIX_LEVEL_CAPS, KSNODETYPE_SUPERMIX


KSAUDIO_POSITION

A KSAUDIO_POSITION structure specifies the current positions of the read and write cursors in the sound buffer for an audio stream. This structure is used to get and set the data value for the KSPROPERTY_AUDIO_POSITION property.

typdef struct
{
  ULONGLONG  PlayOffset;
  ULONGLONG  WriteOffset;
} KSAUDIO_POSITION, *PKSAUDIO_POSITION;

Members

PlayOffset
Specifies the current play position as a byte offset from the beginning of the stream.
WriteOffset
Specifies the current write position as a byte offset from the beginning of the stream.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

During playback, the play and write offsets are interpreted as follows:

  • PlayOffset is the offset of the last byte in the buffer that has played. PlayOffset + 1 is the offset of the next byte that will play.
  • WriteOffset is the offset of the last byte in the playback buffer.

When an application submits another buffer to the device for playback, WriteOffset will increment upon receipt of that buffer to indicate the new WriteOffset value, but PlayOffset does not change until after that buffer has actually been played by the device.

During recording, the play and write offsets are interpreted as follows:

  • PlayOffset is the offset of the last byte in the buffer that has been captured. PlayOffset + 1 is the offset of the next byte that will be captured.
  • WriteOffset is the offset of the last byte in the capture buffer.

When an application submits another buffer to the device for capturing, the WriteOffset value will increment upon receipt of that buffer. The PlayOffset value will not change until data has actually been captured into the buffer.

The space between PlayOffset and WriteOffset is considered off-limits to the application because this represents buffers that have already been sent to the driver.

Note that PlayOffset and WriteOffset are not offsets into any one physical buffer that either your driver has allocated or an application has allocated. Instead, these offsets are stream-relative and can be thought of as offsets into an idealized buffer that contains the entire stream and is contiguous from beginning to end. Any internal offsets that point into the actual physical buffers that contain the data need to be maintained separately.

See the description of the IDirectSoundBuffer::GetCurrentPosition and IDirectSoundBuffer::SetCurrentPosition methods in the Platform SDK documentation.

See Also

KSPROPERTY_AUDIO_POSITION


KSDATAFORMAT_DSOUND

The KSDATAFORMAT_DSOUND structure provides detailed information about a DirectSound audio stream.

typdef struct
{
  KSDATAFORMAT      DataFormat;
  KSDSOUND_BUFFERDESC  BufferDesc;
} KSDATAFORMAT_DSOUND, *PKSDATAFORMAT_DSOUND;

Members

DataFormat
A KSDATAFORMAT structure that specifies the stream's data format.
BufferDesc
A KSDSOUND_BUFFERDESC structure that describes the DirectSound buffer.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

In response to an input DataRange parameter that specifies a DirectSound format (see example in DirectSound Stream Data Range), the IMiniport::DataRangeIntersection method checks to see if the specified pin supports a compatible DirectSound format. If so, the method outputs a KSDATAFORMAT_DSOUND structure (see example in DirectSound Stream Data Format) to the buffer that the ResultantFormat parameter points to.

See Also

KSDATAFORMAT, KSDSOUND_BUFFERDESC, IMiniport::DataRangeIntersection


KSDATAFORMAT_WAVEFORMATEX

A KSDATAFORMAT_WAVEFORMATEX structure is used to provide detailed information about an audio stream consisting of wave data.

typdef struct
{
  KSDATAFORMAT  DataFormat;
  WAVEFORMATEX  WaveFormatEx
} KSDATAFORMAT_WAVEFORMATEX, *PKSDATAFORMAT_WAVEFORMATEX;

Members

DataFormat
A KSDATAFORMAT structure that specifies the stream's data format.
WaveFormatEx
An initialized WAVEFORMATEX structure that describes the contents of the wave audio stream.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

In response to an input DataRange parameter that specifies a WAVEFORMATEX format (see example in PCM Stream Data Range), the IMiniport::DataRangeIntersection method checks to see if the specified pin supports a compatible WAVEFORMATEX format. If so, the method outputs a KSDATAFORMAT_WAVEFORMATEX structure (see example in PCM Stream Data Format) to the buffer that the ResultantFormat parameter points to.

Note that the WaveFormatEx member of the KSDATAFORMAT_WAVEFORMATEX structure can be extended to include additional format information (for example, a channel configuration mask). For details, see WAVEFORMATEXTENSIBLE.

See Also

KSDATAFORMAT, WAVEFORMATEX, WAVEFORMATEXTENSIBLE, IMiniport::DataRangeIntersection


KSDATARANGE_AUDIO

A KSDATARANGE_AUDIO structure is used to describe a range of audio formats.

typdef struct
{
  KSDATARANGE  DataRange;
  ULONG  MaximumChannels;
  ULONG  MinimumBitsPerSample;
  ULONG  MaximumBitsPerSample;
  ULONG  MinimumSampleFrequency;
  ULONG  MaximumSampleFrequency;
} KSDATARANGE_AUDIO, *PKSDATARANGE_AUDIO;

Members

DataRange
An initialized KSDATARANGE structure that indicates the MajorFormat and SubFormat GUIDs as well as the Specifier GUID for the audio data.
MaximumChannels
Maximum number of channels supported.
MinimumBitsPerSample
Minimum bits per sample supported.
MaximumBitsPerSample
Maximum bits per sample supported.
MinimumSampleFrequency
Minimum frequency allowed.
MaximumSampleFrequency
Maximum frequency allowed.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

For information on data ranges and intersection handling, see Data-Intersection Handlers.

See Also

KSDATARANGE


KSDATARANGE_MUSIC

A KSDATARANGE_MUSIC structure is used to describe a range of DirectMusic MIDI formats.

typdef struct
{
   KSDATARANGE              DataRange;
   GUID                     Technology;
   ULONG                    Channels;
   ULONG                    Notes;
   ULONG                    ChannelMask;
} KSDATARANGE_MUSIC, *PKSDATARANGE_MUSIC;

Members

DataRange
An initialized KSDATARANGE structure that indicates the MajorFormat and SubFormat GUIDs as well as the Specifier GUID for the DirectMusic data.
Technology
GUID describing the type of the MIDI output device. It can be one of the following:
KSMUSIC_TECHNOLOGY_PORT
The device is a MIDI hardware port.
KSMUSIC_TECHNOLOGY_SYNTH
The device is a synthesizer.
KSMUSIC_TECHNOLOGY_SQSYNTH
The device is a square-wave synthesizer.
KSMUSIC_TECHNOLOGY_FMSYNTH
The device is an FM synthesizer.
KSMUSIC_TECHNOLOGY_MAPPER
The device is the Microsoft MIDI mapper.
KSMUSIC_TECHNOLOGY_WAVETABLE
The device is a hardware wavetable synthesizer.
KSMUSIC_TECHNOLOGY_SWSYNTH
The device is a software synthesizer.
Channels
Maximum number of simultaneous channels that can be played by an internal synthesizer device. If the device is a port, this member is not meaningful and is set to 0.
Notes
Maximum number of simultaneous notes that can be played by an internal synthesizer device. If the device is a port, this member is not meaningful and is set to 0.
ChannelMask
Channels that an internal synthesizer device responds to, where the least significant bit refers to channel 0 and the most significant bit to channel 15. Port devices that transmit on all channels set this member to 0xFFFF.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

For information on data ranges and intersection handling, see Data-Intersection Handlers.

See Also

KSDATARANGE


KSDSOUND_BUFFERDESC

A KSDSOUND_BUFFERDESC structure is used to describe a DirectSound buffer.

typedef struct
{
  ULONG  Flags;
  ULONG  Control;
  WAVEFORMATEX  WaveFormatEx
} KSDSOUND_BUFFERDESC, *PKSDSOUND_BUFFERDESC;

Members

Flags
Buffer-configuration flags. This member can be set to the bitwise OR of one or more of the following flag bits:
KSDSOUND_BUFFER_PRIMARY
Indicates that the buffer is a primary sound buffer (the buffer the user hears when a game is playing).
KSDSOUND_BUFFER_STATIC
Indicates that the buffer will be used for static sound data.
KSDSOUND_BUFFER_LOCHARDWARE
Forces the buffer to use hardware mixing.
KSDSOUND_BUFFER_LOCSOFTWARE
Forces the buffer to be stored in system memory and use software mixing.
Control
Control flags that indicate capabilities of the buffer. This member can be set to the bitwise OR of one or more of the following flag bits:
KSDSOUND_BUFFER_CTRL_3D
Indicates that the buffer is either a primary buffer or a secondary buffer that uses 3D control.
KSDSOUND_BUFFER_CTRL_FREQUENCY
Indicates that the buffer has frequency-control capability.
KSDSOUND_BUFFER_CTRL_PAN
Indicates that the buffer has pan-control capability.
KSDSOUND_BUFFER_CTRL_VOLUME
Indicates that the buffer has volume-control capability.
KSDSOUND_BUFFER_CTRL_POSITIONNOTIFY
Indicates that the buffer has position-notification capability.
WaveFormatEx
A WAVEFORMATEX structure that describes the waveform format for the buffer.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The KSDATAFORMAT_DSOUND structure contains a BufferDesc member that is a KSDSOUND_BUFFERDESC structure.

Note that the WaveFormatEx member of the KSDSOUND_BUFFERDESC structure can be extended to include additional format information (for example, a channel configuration mask). For details, see WAVEFORMATEXTENSIBLE.

See Also

KSDATAFORMAT_DSOUND, WAVEFORMATEX, WAVEFORMATEXTENSIBLE


KSDS3D_BUFFER_ALL

A KSDS3D_BUFFER_ALL structure is used to specify all 3D characteristics of a sound buffer at any given point in time. This structure is used to set or get the data value for the KSPROPERTY_DIRECTSOUND3DBUFFER_ALL property.

typedef struct
{
  DS3DVECTOR  Position;
  DS3DVECTOR  Velocity;
  ULONG  InsideConeAngle;
  ULONG  OutsideConeAngle;
  DS3DVECTOR  ConeOrientation;
  LONG  ConeOutsideVolume;
  FLOAT  MinDistance;
  FLOAT  MaxDistance;
  ULONG  Mode;
} KSDS3D_BUFFER_ALL, *PKSDS3D_BUFFER_ALL;

Members

Position
A DS3DVECTOR structure containing the X,Y, and Z position coordinates of the 3D sound buffer.
Velocity
A DS3DVECTOR structure containing the X,Y, and Z velocity components of the 3D sound buffer
InsideConeAngle
The angle in degrees of the inside sound projection cone.
OutsideConeAngle
The angle in degrees of the outside sound projection cone.
ConeOrientation
A DS3DVECTOR structure containing the X,Y, and Z components of the orientation of the 3D buffer's sound projection cone.
ConeOutsideVolume
Indicates the cone outside volume.
MinDistance
Specifies the minimum distance between the speaker and listener. (See the discussion of minimum and maximum distances for DirectSound 3-D buffers in the Platform SDK documentation.)
MaxDistance
Specifies the maximum distance between the speaker and listener.
Mode
The 3D sound-processing mode. This can be one of the following values from the header file dsound.h:
  • DS3DMODE_DISABLE
  • DS3DMODE_HEADRELATIVE
  • DS3DMODE_NORMAL

For the meaning of these parameters, see the description of the dwMode member of the DS3DBUFFER structure in the Platform SDK documentation.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The members of this structure are similar to those defined for the DS3DBUFFER structure in the Platform SDK documentation. Also see the description of the IDirectSound3DBuffer::GetAllParameters and IDirectSound3DBuffer::SetAllParameters methods in the Platform SDK documentation.

See Also

DS3DVECTOR, KSPROPERTY_DIRECTSOUND3DBUFFER_ALL


KSDS3D_BUFFER_CONE_ANGLES

A KSDS3D_BUFFER_CONE_ANGLES structure specifies the inside and outside cone angles. This structure is used to set or get the data value for the KSPROPERTY_DIRECTSOUND3DBUFFER_CONEANGLES property.

typedef struct
{
  ULONG      InsideConeAngle;
  ULONG  OutsideConeAngle;
} KSDS3D_BUFFER_CONE_ANGLES, *PKSDS3D_BUFFER_CONE_ANGLES;

Members

InsideConeAngle
The angle in degrees of the inside sound projection cone.
OutsideConeAngle
The angle in degrees of the outside sound projection cone.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

See the description of the IDirectSound3DBuffer::GetConeAngles and IDirectSound3DBuffer::SetConeAngles methods in the Platform SDK documentation.

See Also

KSPROPERTY_DIRECTSOUND3DBUFFER_CONEANGLES


KSDS3D_LISTENER_ALL

A KSDS3D_LISTENER_ALL structure specifies all the properties of the DirectSound 3D listener. This structure is used to get or set the data value for the KSPROPERTY_DIRECTSOUND3DLISTENER_ALL property.

typedef struct
{
  DS3DVECTOR  Position;
  DS3DVECTOR  Velocity;
  DS3DVECTOR  OrientFront;
  DS3DVECTOR  OrientTop;
  FLOAT  DistanceFactor;
  FLOAT  RolloffFactor;
  FLOAT  DopplerFactor;
} KSDS3D_LISTENER_ALL, *PKSDS3D_LISTENER_ALL;

Members

Position
A DS3DVECTOR structure containing the position vector of the 3D listener.
Velocity
A D3DVECTOR structure containing the velocity vector of the 3D listener.
OrientFront
A D3DVECTOR structure containing the front orientation vector of the 3D listener.
OrientTop
A D3DVECTOR structure containing the top orientation vector of the 3D listener.
DistanceFactor
Float containing the distance factor for the 3D listener.
RolloffFactor
Float containing the roll-off factor for the 3D listener.
DopplerFactor
Float containing the doppler factor for the 3D listener.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

This structure is similar to the DS3DBUFFER structure that is described in the Platform SDK documentation. The Platform SDK documentation also discusses:

  • Distance, roll-off, and doppler factors for DirectSound 3-D listeners
  • IDirectSound3DListener::GetAllParameters and IDirectSound3DListener::SetAllParameters methods

See Also

DS3DVECTOR, KSPROPERTY_DIRECTSOUND3DLISTENER_ALL


KSDS3D_LISTENER_ORIENTATION

A KSD3D_LISTENER_ORIENTATION structure specifies the position vector of the 3D listener. This structure is used to get or set the data value for the KSPROPERTY_DIRECTSOUND3DLISTENER_ORIENTATION property.

typedef struct
{
  DS3DVECTOR  Front;
  DS3DVECTOR  Top;
} KSDS3D_LISTENER_ORIENTATION, *PKSDS3D_LISTENER_ORIENTATION;

Members

Front
DS3DVECTOR structure containing the front orientation vector of the 3D listener.
Top
DS3DVECTOR structure containing the top orientation vector of the 3D listener.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

See the description of the IDirectSound3DListener::GetOrientation and IDirectSound3DListener::SetOrientation methods in the Platform SDK documentation.

See Also

KSPROPERTY_DIRECTSOUND3DLISTENER_ORIENTATION, DS3DVECTOR


KSMUSICFORMAT

The KSMUSICFORMAT structure is used to send and receive information about MIDI input from and output to WDM audio devices. In particular, this structure is used to send and receive IRPs. The IRP itself contains in its SystemBuffer field a pointer to a KSSTREAM_HEADER structure, which serves as a header for a packet of data that is to be read from or written to a streaming driver pin. The KS stream header contains in its Data field a pointer to the buffer that contains the data. The data in that buffer consists of a sequence of messages, each of which is a KSMUSICFORMAT structure that is immediately followed by some number of bytes of data.

typedef struct {
  ULONG  TimeDeltaMs;
  ULONG  ByteCount;
} KSMUSICFORMAT, *PKSMUSICFORMAT;

Members

TimeDeltaMs
Indicates when this series of MIDI data bytes are to be played. If this is the first KSMUSICFORMAT structure in the buffer, this field represents the delta (time change, in milliseconds) from the PresentationTime in the KSSTREAM_HEADER structure. Otherwise, the field represents the delta offset (in milliseconds) from the previous message (KMUSICFORMAT structure). If this time is in the past, then the message is played immediately.
ByteCount
Number of bytes of data that follow this structure. Because the subsequent structure or properties should be DWORD aligned and might allow for extra blanks or used bytes, ByteCount should be the actual number of bytes present and not include any padding separating the data structures.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

Timestamps in these IRPs always increase across successively issued IRPs. However, because each IRP in a sequence is fully serviced before servicing of the next IRP begins, time must also always increase across IRPs. This can lead to an anomalous situation, as described in the following example.

Action | Description
IRP #1 PresentationTime = 123 ms |
Message. #1 TimeDeltaMs: 0 | Will be played at 123 ms.
Message. #2 TimeDeltaMs: 1 | Will be played at 124 ms.
Message. #3 TimeDeltaMs: 7 | Will be played at 131 ms.
IRP #2 PresentationTime = 120 ms |
Message. #1 TimeDeltaMs: 5 | Should be played at 125 ms, but will be played at 131 ms. This IRP will not be processed until the previous IRP at 131 ms is finished.
Message. #2 TimeDeltaMs: 15 | Will be played at 140 ms.

See Also

KSSTREAM_HEADER


KSNODEPROPERTY

The KSNODEPROPERTY structure is used to specify a node and a property of that node.

typedef struct {
  KSPROPERTY  Property;
  ULONG  NodeId
  ULONG  Reserved;
} KSNODEPROPERTY; *PKSNODEPROPERTY;

Members

Property
KSPROPERTY structure indicating the property to get or set
NodeId
Specifies the node ID
Reserved
Reserved for internal use

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

See discussion of KSNODEPROPERTY structure in Properties of Audio Filters, Pins, and Nodes.

See Also

KSPROPERTY


KSNODEPROPERTY_AUDIO_CHANNEL

The KSNODEPROPERTY_AUDIO_CHANNEL structure is used to specify several audio properties.

typedef struct {
  KSNODEPROPERTY  NodeProperty;
  LONG  Channel;
  ULONG  Reserved;
} KSNODEPROPERTY_AUDIO_CHANNEL, *PKSNODEPROPERTY_AUDIO_CHANNEL;

Members

NodeProperty
KSNODEPROPERTY structure indicating the property to get or set
Channel
Channel number to control. This ranges from 0 to (TotalChannels – 1). When –1 (0xffffffff) is specified, the level applies to the entire stream.
Reserved
Reserved. Do not use.

Headers

Declared in ksmedia.h. Include ksmedia.h.

See Also

KSNODEPROPERTY


WAVEFORMATEX

A WAVEFORMATEX structure is used to define the format of wave audio data. This structure is used to specify a wide range of wave formats. See the list of WAVE_FORMAT_XXX formats that are defined in the header file mmreg.h.

typedef struct
{
  WORD  wFormatTag;
  WORD  nChannels;
  DWORD  nSamplesPerSec;
  DWORD  nAvgBytesPerSec;
  WORD  nBlockAlign;
  WORD  wBitsPerSample;
  WORD  cbSize;
} WAVEFORMATEX; *PWAVEFORMATEX;

Members

wFormatTag
Specifies the waveform audio format type. See comments below.
nChannels
Specifies the number of channels of audio data. For monophonic audio, set this member to one. For stereo, set this member to two.
nSamplesPerSec
Specifies the sample frequency at which each channel should be played or recorded. If wFormatTag is WAVE_FORMAT_PCM, then common values for nSamplesPerSec are 8.0 kHz, 11.025kHz, 22.05 kHz, and 44.1kHz. For non-PCM formats, this member should be computed according to the manufacturer's specification of the format tag.
nAvgBytesPerSec
Required average data transfer rate; specified in bytes per second. This value is used for buffer-size estimation.
nBlockAlign
Block alignment specified in bytes. The block alignment is the minimum atomic unit of data for the wFormatTag format type. If wFormatTag is WAVE_FORMAT_PCM, this value should be equal to (nChannels * wBitsPerSample)/8. For non-PCM formats, this member should be computed according to the manufacturer's specification of the format tag.

Playback and record software should process a multiple of nBlockAlign bytes of data at a time. Data written and read from a device should always start at the beginning of a block.

wBitsPerSample
Specifies the number of bits per sample for the specified wFormatTag type. If wFormatTag is WAVE_FORMAT_PCM, then wBitsPerSample should be equal to 8 or 16. For non-PCM formats, this member should be set according to the manufacturer's specification of the format tag. Some compression schemes cannot define a value for wBitsPerSample. In those cases, wBitsPerSample can be set to 0.
cbSize
The number of extra bytes of data that are appended to the end of the WAVEFORMATEX structure.

Headers

Declared in mmreg.h and mmsystem.h. Include mmreg.h or mmsystem.h.

Comments

The wFormatTag member is set to one of the wave formats that are defined in mmreg.h. Some of the more common nonproprietary formats are listed in the table below.

wFormatTag value | Meaning
WAVE_FORMAT_PCM | PCM (pulse-code modulated) data in integer format
WAVE_FORMAT_IEEE_FLOAT | PCM data in IEEE floating-point format
WAVE_FORMAT_DRM | DRM-encoded format (for digital-audio content protected by Microsoft Digital Rights Management)
WAVE_FORMAT_ALAW | A-law-encoded format
WAVE_FORMAT_MULAW | Mu-law-encoded format
WAVE_FORMAT_ADPCM | ADPCM (adaptive differential pulse-code modulated) data
WAVE_FORMAT_MPEG | MPEG-1 data format (stream conforms to ISO 11172-3 Audio specification)
WAVE_FORMAT_DOLBY_AC3_SPDIF | AC3 (aka Dolby Digital) over S/PDIF

See Also

WAVEFORMATEXTENSIBLE


WAVEFORMATEXTENSIBLE

The WAVEFORMATEXTENSIBLE structure is used to specify the wave format of an audio data stream. This is an extended form of the WAVEFORMATEX structure that can adequately support more than two channels.

typedef struct {
  WAVEFORMATEX  Format;
  union {
    WORD  wValidBitsPerSample;
    WORD  wSamplesPerBlock;
    WORD  wReserved;
  } Samples;
  DWORD  dwChannelMask;
  GUID  SubFormat;
} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;

Members

Format
WAVEFORMATEX structure. The wFormat member of WAVEFORMATEX should be set to WAVE_FORMAT_EXTENSIBLE. The wBitsPerSample member of WAVEFORMATEX is defined unambiguously as the size of the container for each sample. Individual samples should be byte-aligned. Therefore, this value should be an integer multiple of eight.
wValidBitsPerSample
Specifies the precision of the sample in bits. Typically this value will be equal to the wBitsPerSample member of Format. However, it is possible that these values would be different. For example, if the wave data originated from a 20-bit A/D converter, then wValidBitsPerSample could be set to 20 and wBitsPerSample might be 24 or 32. If wValidBitsPerSample is less than wBitsPerSample, the actual PCM data is "left-aligned" within the container. The sample itself is justified most significant; all extra bits are at the least-significant portion of the container. All non-valid data bits should be set to zero.

The value of wValidBitsPerSample should never exceed that of wBitsPerSample. If this is encountered, the data format can be rejected.

wSamplesPerBlock
The number of samples contained in one compressed block. This value is used in buffer estimation. This value is used with compressed formats that have a fixed number of samples within each block. This value can be set to zero if a variable number of samples is contained in each block of compressed audio data. In this case, buffer estimation and position information needs to be obtained in other ways.
wReserved
Reserved for internal use. Set to zero.
dwChannelMask
Bit mask indicating the assignment of channels in the multi-channel stream to speaker positions. See comments below.
SubFormat
GUID for the subformat.

Headers

Declared in mmreg.h, mmsystem.h, and ksmedia.h. Include ksmedia.h.

Comments

The member dwChannelMask contains a mask that indicates which channels are present in the multi-channel stream. The least-significant bit represents the front-left speaker, the next bit corresponds to the front-right speaker, and so on. The following flag bits are defined in the header file ksmedia.h:

Speaker position | Flag bit
SPEAKER_FRONT_LEFT | 0x1
SPEAKER_FRONT_RIGHT | 0x2
SPEAKER_FRONT_CENTER | 0x4
SPEAKER_LOW_FREQUENCY | 0x8
SPEAKER_BACK_LEFT | 0x10
SPEAKER_BACK_RIGHT | 0x20
SPEAKER_FRONT_LEFT_OF_CENTER | 0x40
SPEAKER_FRONT_RIGHT_OF_CENTER | 0x80
SPEAKER_BACK_CENTER | 0x100
SPEAKER_SIDE_LEFT | 0x200
SPEAKER_SIDE_RIGHT | 0x400
SPEAKER_TOP_CENTER | 0x800
SPEAKER_TOP_FRONT_LEFT | 0x1000
SPEAKER_TOP_FRONT_CENTER | 0x2000
SPEAKER_TOP_FRONT_RIGHT | 0x4000
SPEAKER_TOP_BACK_LEFT | 0x8000
SPEAKER_TOP_BACK_CENTER | 0x10000
SPEAKER_TOP_BACK_RIGHT | 0x20000

The channels that are specified in dwChannelMask should be present in the order shown above, beginning at the top.

For example, if only front-left and front-center are specified, then front-left and front-center should be in channels 0 and 1, respectively, of the interleaved stream.

As a second example, if nChannels (in the Format member; see WAVEFORMATEX) is set to four and dwChannelMask is set to 0x00000033, the audio channels are intended for playback to the front-left, front-right, back-left and back-right speakers. The channel data should be interleaved in that order within each block.

Channel locations beyond the predefined ones are considered reserved.

Alternately, the channel mask can be specified as one of the following constants, which are defined in ksmedia.h and are bitwise-ORed combinations of the above flags that represent standard speaker configurations:

KSAUDIO_SPEAKER_MONO

KSAUDIO_SPEAKER_STEREO

KSAUDIO_SPEAKER_QUAD

KSAUDIO_SPEAKER_SURROUND

KSAUDIO_SPEAKER_5POINT1

KSAUDIO_SPEAKER_7POINT1

KSAUDIO_SPEAKER_DIRECTOUT

A hardware device can be set to one of these speaker configurations by a KSPROPERTY_AUDIO_CHANNEL_CONFIG set-property request. For more information on setting speaker configurations, see KSAUDIO_CHANNEL_CONFIG.

Typically, the count in nChannels equals the number of bits set in dwChannelMask, but this is not necessarily so. If nChannels is less than the number of bits set in dwChannelMask, the extra (most significant) bits in dwChannelMask are ignored. If nChannels exceeds the number of bits set in dwChannelMask, the channels that have no corresponding mask bits are not assigned to any particular speaker location. In any speaker configuration other than KSAUDIO_SPEAKER_DIRECTOUT, an audio sink such as KMixer (see KMixer System Driver) simply ignores these excess channels and mixes only the channels that have corresponding mask bits.

KSAUDIO_SPEAKER_DIRECTOUT represents a configuration with no speakers and is defined in ksmedia.h to be zero. In this configuration, the audio device renders the first channel to the first port on the device, the second channel to the second port on the device, and so on. This allows an audio authoring application to output multi-channel data directly and without modification to a device such as a digital mixer or a digital audio storage device (hard disk, ADAT, and so on). For example, channels 0 to 30 might respectively contain drums, guitar, bass, voice, and so on. For this kind of raw audio data, speaker positions are meaningless, and assigning speaker positions to the input or output streams might cause a component such as KMixer to intervene inappropriately by performing an unwanted format conversion. If a device is unable to process the raw audio streams, it should reject a request to change its speaker configuration to KSAUDIO_SPEAKER_DIRECTOUT.

For more information on multi-channel configurations, refer to www.microsoft.com/hwdev/audio/multichaud.htm.

For information on converting between a WAVEFORMATEX wFormatTag value and a WAVEFORMATEXTENSIBLE SubFormat GUID, see Converting Between Format Tags and Subformat GUIDs.

See Also

WAVEFORMATEX, KSAUDIO_CHANNEL_CONFIG


Digital Rights Management Reference

This section describes support for Digital Rights Management (DRM) of kernel-streaming (KS) audio content in Windows Me, and Microsoft® Windows® XP and later. The following topics are discussed:

DRM Routines

DRM Property Sets

DRM Structures

See the port-class audio driver reference for information on the following DRM-related interfaces:

IDrmAudioStream.

IDrmPort


DRM Routines

This section describes the following DRM routines:

DEFINE_DRMRIGHTS_DEFAULT

DrmCreateContentMixed

DrmDestroyContent

DrmForwardContentToFileObject

DrmForwardContentToInterface

DrmGetContentRights


DEFINE_DRMRIGHTS_DEFAULT

The DEFINE_DRMRIGHTS_DEFAULT macro defines a constant DRMRIGHTS structure that specifies default DRM content rights.

DEFINE_DRMRIGHTS_DEFAULT(
    DRMRIGHTS  DrmRights
    );

Parameters

DrmRights
Specifies a name for a constant DRMRIGHTS structure. The macro sets the members of DrmRights to the following default values:
CopyProtect
Set to FALSE (zero). This means that the digital content is subject to no restrictions on copying.
DigitalOutputDisable
Set to FALSE (zero). This means that the adapter's digital outputs (for example, S/PDIF connectors) are not disabled.

Headers

Declared in drmk.h. Include drmk.h.

See Also

DRMRIGHTS


DrmCreateContentMixed

The DrmCreateContentMixed routine computes the DRM content rights for a composition of KS audio streams, and creates a DRM content ID that represents the composite audio stream.

NTSTATUS
  DrmCreateContentMixed(
    IN PULONG  paContentId,
    IN ULONG  cContentId,
    OUT PULONG  pMixedContentId
    );

Parameters

paContentId
Pointer to an array of DRM content IDs. Each content ID represents a KS audio stream. If cContentID is zero, paContentID can be NULL. A content ID of zero is a special value that represents an audio stream with default content rights (see DEFINE_DRMRIGHTS_DEFAULT).
cContentId
Specifies the count of DRM content IDs in the paContentId array. The array can hold zero or more content IDs.
pMixedContentId
Pointer to a variable that receives the new DRM content ID assigned to a composite KS audio stream. If cContentID is zero, the new content ID is assigned default DRM content rights.

Return Value

DrmCreateContentMixed returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in drmk.h. Include drmk.h.

Comments

A KS audio filter uses the DrmCreateContentMixed routine to obtain a DRM content ID for a composition of zero or more KS audio streams. If a caller does not specify any DRM content IDs, the routine returns a content ID that is assigned default DRM content rights.

After any change to the content rights of the components of a composite audio stream, a KS audio filter must use DrmCreateContentMixed to obtain a new content ID for the composite audio stream. DrmCreateContentMixed assigns the most restrictive of the content rights assigned to all the content IDs specified in the paContentId array.

After a KS audio filter finishes using a content ID that it created using DrmCreateContentMixed, the filter must call DrmDestroyContent to delete the content ID. However, before deleting an old content ID, a KS audio filter must first successfully forward a new content ID to all the streams to which it previously forwarded the old content ID. Note that a KS audio filter forwards a content ID by using a DrmForwardContentToXxx routine.

DrmCreateContentMixed runs in the context of the caller at IRQL PASSIVE_LEVEL.

See Also

DrmDestroyContent, DrmForwardContentToFileObject, DrmForwardContentToInterface, DrmGetContentRights


DrmDestroyContent

The DrmDestroyContent routine deletes a specified DRM content ID that was created by DrmCreateContentMixed.

NTSTATUS
  DrmDestroyContent(
    IN ULONG  ContentId
    );

Parameters

ContentId
Specifies a nonzero DRM content ID assigned to a KS audio stream by DrmCreateContentMixed. Note that a content ID of zero represents an audio stream with default DRM content rights, and cannot be used with this routine.

Return Value

DrmCreateContentMixed returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in drmk.h. Include drmk.h.

Comments

A KS audio filter can only use DrmDestroyContent to delete a DRM content ID that it obtained by using DrmCreateContentMixed. Note that a KS audio filter must not use DrmDestroyContent to delete a DRM content ID set by IDrmAudioStream::SetContentId or by an IOCTL_KS_PROPERTY request that sets the KSPROPERTY_DRMAUDIOSTREAM_CONTENTID property. Only the KS audio filter that created the content ID should delete it.

DrmDestroyContent runs in the context of the caller at IRQL PASSIVE_LEVEL.

See Also

KSPROPERTY_DRMAUDIOSTREAM_CONTENTID, DrmCreateContentMixed, DrmForwardContentToFileObject, DrmForwardContentToInterface, DrmGetContentRights, IDrmAudioStream::SetContentId


DrmForwardContentToFileObject

The DrmForwardContentToFileObject routine forwards the specified DRM content ID to a file object that represents a KS audio pin.

NTSTATUS
  DrmForwardContentToFileObject(
    IN ULONG  ContentId,
    IN PFILE_OBJECT  FileObject
    );

Parameters

ContentId
Specifies a DRM content ID assigned to a KS audio stream.
FileObject
Pointer to a file object that represents the KS audio pin to which the KS audio stream is sent.

Return Value

DrmForwardContentToFileObject returns STATUS_SUCCESS if the call was successful. Possible error return values include:

Error Status | Description
STATUS_NOT_IMPLEMENTED | Possibly indicates that the KS audio pin that is associated with FileObject does not support the DRM content rights that are assigned to ContentId.

Headers

Declared in drmk.h. Include drmk.h.

Comments

The DrmForwardContentToFileObject routine authenticates the KS audio filter that implements the KS audio pin represented by FileObject. If DrmForwardContentToFileObject successfully authenticates the KS audio filter, it sets the KS property KSPROPERTY_DRMAUDIOSTREAM_CONTENTID on the audio pin that is represented by FileObject. The property data includes a DRM content ID and a DRMRIGHTS structure. DrmForwardContentToFileObject does not use FileObject after returning.

DrmForwardContentToFileObject runs in the context of the caller at IRQL PASSIVE_LEVEL.

See Also

KSPROPERTY_DRMAUDIOSTREAM_CONTENTID, DRMRIGHTS, DrmCreateContentMixed, DrmDestroyContent, DrmForwardContentToInterface, DrmGetContentRights


DrmForwardContentToInterface

The DrmForwardContentToInterface routine forwards a specified DRM content ID to a KS audio filter that receives a KS audio stream through a COM interface.

NTSTATUS
  DrmForwardContentToInterface(
    ULONG  ContentId,
    PUNKNOWN  pUnknown,
    ULONG  NumMethods
    );

Parameters

ContentId
Specifies a DRM content ID assigned to a KS audio stream.
pUnknown
Pointer to a COM interface that directly receives KS audio stream data for a KS audio filter.
NumMethods
Specifies the total number of functions in the pUnknown COM interface, including all the functions in its base interfaces.

Return Value

DrmForwardContentToInterface returns STATUS_SUCCESS if the call was successful. Possible error return values include:

Error Status | Description
STATUS_NOT_IMPLEMENTED | Possibly indicates that the KS audio stream that is associated with pUnknown does not support the DRM content rights that are assigned to ContentId.

Headers

Declared in drmk.h. Include drmk.h.

Comments

DrmForwardContentToInterface authenticates the KS audio filter driver or library that implements the pUnknown interface. If DrmForwardContentToInterface successfully authenticates the KS audio filter driver, it does the following:

  • Queries a KS audio stream's pUnknown interface for its IDrmAudioStream interface.
  • If the KS audio stream supports an IDrmAudioStream interface, the routine calls IDrmAudioStream::SetContentId to set the DRM content ID and DRM content rights on the audio stream. Before returning, DrmForwardContentToInterface releases the IDrmAudioStream interface.

DrmForwardContentToInterface runs in the context of the caller at IRQL PASSIVE_LEVEL.

See Also

DrmCreateContentMixed, DrmDestroyContent, DrmForwardContentToFileObject, DrmGetContentRights, IDrmAudioStream::SetContentId


DrmGetContentRights

The DrmGetContentRights routine returns the DRM content rights assigned to a specified DRM content ID.

NTSTATUS
  DrmGetContentRights(
    IN ULONG  ContentId,
    OUT PDRMRIGHTS  DrmRights
    );

Parameters

ContentId
Specifies a DRM content ID.
DrmRights
Pointer to a DRMRIGHTS structure that specifies the DRM content rights that are assigned to the protected stream that is identified by ContentId.

Headers

Declared in drmk.h. Include drmk.h.

Return Value

DrmGetContentRights returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Comments

KS audio filters use DrmGetContentRights to obtain the DRM content rights assigned to a DRM content ID that the KS audio filter created by using DrmCreateContentMixed.

Note that IDrmAudioStream::SetContentId and an IOCTL_KS_PROPERTY request to set the KSPROPERTY_DRMAUDIOSTREAM_CONTENTID property forward the DRM content rights to the target KS audio stream or pin.

DrmGetContentRights runs in the context of the caller at IRQL PASSIVE_LEVEL.

See Also

DRMRIGHTS, KSPROPERTY_DRMAUDIOSTREAM_CONTENTID, DrmCreateContentMixed, DrmDestroyContent, DrmForwardContentToFileObject, DrmForwardContentToInterface, IDrmAudioStream::SetContentId


DRM Property Sets

This section describes the KSPROPSETID_DrmAudioStream property set.


KSPROPSETID_DrmAudioStream

The KSPROPSETID_DrmAudioStream property set specifies a DRM content ID and DRM content rights on a KS audio stream.

The following properties are part of the KSPROPSETID_DrmAudioStream property set:

KSPROPERTY_DRMAUDIOSTREAM_CONTENTID


KSPROPERTY_DRMAUDIOSTREAM_CONTENTID

A client uses the KSPROPERTY_DRMAUDIOSTREAM_CONTENTID property to set a DRM content ID and DRM content rights on a KS audio pin.

Get | Set | Target | Property descriptor type | Property value type
No | Yes | KS audio pin | KSP_DRMAUDIOSTREAM_CONTENTID | A ULONG followed by a DRMRIGHTS structure

Return Value

Status value | Meaning
STATUS_SUCCESS | The KS audio filter enforces the specified DRM content rights.
STATUS_NOT_IMPLEMENTED | The KS filter cannot enforce the specified DRM content rights.

Headers

Declared in drmk.h. Include drmk.h.

Comments

A KS audio filter handles this property request synchronously. If the request returns STATUS_SUCCESS, all the downstream KS audio nodes (see Audio Topology Nodes) of the target KS audio pin were also successfully configured with the specified DRM content ID and DRM content rights. (Note that a downstream node is a direct or indirect sink for the audio content flowing through an audio pin.)

The DRM system can set this property any time during the lifetime of the file object that represents a KS audio pin.

If the request does not succeed, the previously set DRM content ID and DRM content rights remain set on the KS audio stream.

The DRM system sends an IOCTL_KS_PROPERTY request for the KSPROPERTY_DRMAUDIOSTREAM_CONTENTID property at IRQL PASSIVE_LEVEL.

The handler for the KSPROPERTY_DRMAUDIOSTREAM_CONTENTID property should verify that the property-request IRP originates in kernel mode (that is, confirm that the IRP's RequestorMode field equals KernelMode). If the IRP originates in user mode, the handler should fail the IRP and return status code INVALID_DEVICE_REQUEST.

See Also

DRMRIGHTS


DRM Structures

This section describes the DRMRIGHTS structure.


DRMRIGHTS

The DRMRIGHTS structure specifies the DRM content rights assigned to a KS audio pin or a port-class driver (see Introduction to Port Class) stream object.

typedef struct tagDRMRIGHTS {
  BOOL  CopyProtect;
  ULONG  Reserved;
  BOOL  DigitalOutputDisable;
} DRMRIGHTS , *PDRMRIGHTS;

Members

CopyProtect
Specifes one of the following copy-protection values:
TRUE (nonzero)
Enable copy protection. A software component (1) should not store the content in any form in any nonvolatile storage, and (2) should not pass the content by reference or value to any other component within the host system that is not authenticated by the DRM system.
FALSE (zero)
Disable copy protection. There are no restrictions on copying the content.
DigitalOutputDisable
Specifies one of the following digital output protection values:
TRUE (nonzero)
Disable digital outputs. A software component must not transfer the content out of the host system through any type of digital interface. Note that digital output protection does not affect USB devices because the host system includes USB devices.
FALSE (zero)
Enable digital outputs. There are no restrictions on transferring the content from the host system to an external component.

This flag applies primarily to S/PDIF outputs.

See Also

DrmCreateContentMixed, DrmDestroyContent, DrmForwardContentToFileObject, DrmForwardContentToInterface, DrmGetContentRights


Media-Class INF Extensions

The following INF file keywords are defined specifically for installing media-class device drivers:

AlsoInstall

KnownFiles

KnownRegEntries

SetupPreferredAudioDevices


AlsoInstall

The AlsoInstall directive specifies the core system components that need to be installed for use by an audio adapter driver. This directive is supported only by Windows 98/Me and is specific to the installation of media-class device drivers. It is not supported in Windows 2000 and later.

The AlsoInstall directive is specified in the DDInstall section and has the following format:

AlsoInstall = inf-section-name1(inf-filename1)[, inf-section-name2(inf-filename2)[,...]]

Each item in the list to the right of the equal sign (=) consists of an INF section name that is followed by the name (in parentheses) of the INF file that contains the section.

Driver writers should use the system-supplied INF files to install core components instead of attempting to install these components directly from within their proprietary INF files. The system-supplied INF files are updated as necessary with each Windows release in order to accommodate OS changes and ensure that existing drivers continue to work properly.

For Windows 2000 and later, use the Include and Needs directives instead of AlsoInstall.

Examples

For example, the following directive installs the core WDM components in Windows 98/Me:

AlsoInstall = WDMAUDIO.Registration(wdmaudio.inf)

Compare the above with the equivalent directives for Windows 2000 and later:

Include = wdmaudio.inf
Needs = WDMAUDIO.Registration

As a second example, the following directive installs the core kernel-streaming components in Windows 98/Me:

AlsoInstall = KS.Registration(ks.inf)

Note that both sets of system components can be installed in a single directive:

AlsoInstall = KS.Registration(ks.inf), WDMAUDIO.Registration(wdmaudio.inf)

See Also

Installing in Windows 98/Me


KnownFiles

The KnownFiles directive provides explicit control over whether to improve or degrade the ranking of a driver. The change in driver ranking is conditional and takes effect only if the existing driver installation contains one or more known driver files. This directive is supported only by Windows 98/Me and is specific to the installation of media-class device drivers. It is not supported in Windows 2000 and later.

A KnownFiles directive appears in a DDInstall section and has the following format:

KnownFiles = known-files-section

The directive specifies the name of a known-files-section, which contains a list of known driver files and specifies whether the driver's ranking should be raised or lowered if any of those files are already installed. The general format for a known-files-section is shown below:

[known-files-section]
known-filename = force | keep | safe
known-filename2 = force | keep | safe
...

Each of the directives in the section specifies the name of a known file and one of the following keywords: force, keep, or safe. The keyword takes effect only if the media-class installer finds the named file among the system's existing (previously installed) drivers. The three keywords and their meanings are shown in the table below.

Keyword | Meaning
force | Improve the driver's ranking. This is likely to force installation of the driver, in which case it replaces the previously installed driver.
keep | Degrade the driver's ranking. This increases the likelihood that the system will keep the previously installed driver.
safe | The driver is safe to install. This keyword does not directly modify the driver's ranking, but it does lessen the negative impact of any warnings on the driver's ranking.

The effect of the force and keep keywords is to modify the driver's ranking. The Setup API assigns an initial ranking number to each driver and sorts the drivers into several ranges of ranking numbers (see How Setup Selects Drivers):

  • range 0 to 0xFFF (hardware ID matches)
  • range 0x1000 to 0x1FFF (compatible ID matches)
  • range 0x2000 to 0x2FFF (and so on)

The media-class installer can then modify the initial rankings based on factors such as directives in a known-files-section. The change in ranking number due to the force or keep keyword is a small fraction of a range and the initial driver ranking is biased toward the center of the range.

A driver with a smaller ranking number is preferable to a driver with a larger ranking number. The Setup API chooses a driver in the top range (0 to 0xFFF) over one in the second range (0x1000 to 0x1FFF), for example. Note that the force, keep, and safe keywords have no effect over this choice when the two drivers fall into different ranges.

Example

The following example is a fragment of an INF file that checks the system for known driver files aaa.sys and bbb.sys during installation:

KnownFiles = XYZ.KnownFiles
...
[XYZ.KnownFiles]
aaa.sys = keep
bbb.sys = force

If the system already contains a file named aaa.sys from a previous installation, the installer will keep the existing version of that file instead of replacing it with a new version of the file. However, if the system already contains a file named bbb.sys from a previous installation, the installer will do one of the following:

  • Replace the existing version of bbb.sys with a new version of bbb.sys if one is available.
  • Simply delete the existing version of bbb.sys if the INF file does not provide a new version of the file.

Also See

How Setup Selects Drivers


KnownRegEntries

The KnownRegEntries directive provides explicit control over whether to improve or degrade the ranking of a driver. The change in driver ranking is conditional and takes effect only if the registry contains one or more known entries. This directive is supported only by Windows 98/Me and is specific to the installation of media-class device drivers. It is not supported in Windows 2000 and later.

This directive conditionally modifies the ranking of a driver relative to the driver that is currently installed. (See How Setup Selects Drivers for a discussion of driver ranking.) The directive is conditional and takes effect only if the registry contains entries that match a set of known registry entries that are listed in the INF file. All the entries in the list must match; a single mismatch prevents the directive from taking effect. A known registry entry is specified by its registry path, entry name, and value. If the registry contains matches for all the entries in the list, the media-class installer either boosts or reduces the driver's ranking, depending on which option is selected.

A KnownRegEntries directive appears in a DDInstall section and has the following format:

KnownRegEntries = known-regentries-section

The directive specifies the name of a known-regentries-section, which contains one or more directives that specify how the driver's ranking is to be modified in the event that the registry contains matches for a particular list of entries. The format for a known-regentries-section is as follows:

[known-regentries-section]
known-regvalues-section = force | keep | safe
known-regvalues-section2 = force | keep | safe
...

The known-regvalues-section that is named in each of the directives above contains a list of registry entries. The keyword force, keep, or safe specifies how the media-class installer should modify the driver's ranking in the event that the registry contains all of the entries that are listed in the known-regvalues-section. See the KnownFiles reference page for a detailed discussion of the effect of the force, keep, and safe keywords on driver ranking.

The general format for a known-regvalues-section is shown below:

[known-regvalues-section]
1 = reg-root, subkey, value-entry-name, flags, value
1 = reg-root2, subkey2, value-entry-name2, flags2, value2
...

Each directive above specifies the path, entry name, data type, and data value of a registry entry. The literal character "1" to the left of the equal sign (=) is required by the syntax but has no other significance. The reg-root, subkey, value-entry-name, flags, and value parameters above are the same as the parameters in an entry in the add-registry-section that is named in an AddReg directive. In this case, however, the flags parameter is restricted to one of two values: 0 (FLG_ADDREG_TYPE_SZ) or 1 (FLG_ADDREG_BINVALUETYPE).

The change in driver ranking (force, keep, or safe) occurs only if the installer succeeds in finding a matching registry entry for each of the directives in the known-regvalues-section. For each entry, a match is successful only if the registry contains an entry with the same path, entry name, data type, and data value.

Example

The following example is a fragment of an INF file that conditionally forces an existing driver to be updated and replaced by the new driver:

KnownRegEntries = XYZ.KnownRegEntries
...
[XYZ.KnownRegEntries]
IsABCProcessor = force
...
[IsABCProcessor]
1 = HKLM,Hardware\Description\System\CentralProcessor\0,Identifier,0,"ABC Processor 123"

The KnownRegEntries directive in the first line of the example above specifies that the name of the known-regentries-section is XYZ.KnownRegEntries. The directive in the XYZ.KnownRegEntries section declares the name of a known-regvalues-section, IsABCProcessor. The force keyword in this directive indicates that if the all the values in the known-regvalues-section match those in the registry, the installer program should "force" the driver to be installed. In the known-regvalues-section, IsABCProcessor, the directive specifies a registry key that is named Identifier and whose value is a string. If the registry contains an entry with string value "ABC Processor 123" at the specified path, the force keyword is enabled, which improves the driver's ranking and increases the likelihood that it will be installed.

Also See

Driver Information in the Registry, How Setup Selects Drivers


SetupPreferredAudioDevices

The SetupPreferredAudioDevices keyword is used to specify the preferred audio device, which is the device that the audio system enables by default when the system contains one or more audio devices. This keyword is media-class specific and is supported by Windows 98/Me, and by Windows 2000 and later.

When creating an audio device, an application program can elect to use the default (or preferred) device instead of explicitly specifying a device. (For example, see the descriptions of the waveOutOpen and DirectSoundCreate functions in the Platform SDK documentation.)

The audio system keeps track of the current preferred audio device in the system registry. When a user upgrades a system by installing a new audio device, the proprietary INF file that installs the device typically updates the registry to designate the new device as the preferred audio device.

The SetupPreferredAudioDevices keyword can appear within a registry-update directive in the add-registry-section (see INF AddReg Directive) of an INF file for an audio device. This directive has the following format:

reg-rootkey, [reg-subkey], SetupPreferredAudioDevices, [flags], [dword-value]

The directive instructs the audio system to use the device's audio functions as the defaults for sound playback, sound recording, and MIDI music playback. Following installation, these three defaults appear in the Sounds and Multimedia control panel under the Audio tab. The user can use the control panel to change the default devices.

The directive's dword-value parameter specifies a DWORD value that should be nonzero in order to enable the directive; if this value is zero, the directive has no effect. Because Windows 98/Me do not support the REG_DWORD registry data type, however, dword-value is typically expressed as a four-byte REG_BINARY type instead of as a DWORD (for example, as "01,00,00,00" instead of "0x00000001"). The dword-value parameter can be specified in "raw" binary format by setting the directive's flags parameter to "1" (FLG_ADDREG_BINVALUETYPE).

The directive takes effect at the time that the driver for the device is installed. If another device occupies the role of preferred device at the time that the new device is installed, the directive causes the new device to assume the role of preferred device, displacing the other device from this role.

When upgrading or reinstalling the driver for a device that has already been installed, you might want to avoid altering the user's current preferred-device selections for sound playback, sound recording, and MIDI music playback. If so, set the FLG_ADDREG_NOCLOBBER bit in the flags parameter, in which case the directive takes effect only if this is the device's initial installation.

Example

The following example is a fragment of an INF file that shows how to use the SetupPreferredAudioDevices keyword:

AddReg = XYZ-Audio-Device.AddReg
...
[XYZ-Audio-Device.AddReg]
HKR,,SetupPreferredAudioDevices,3,01,00,00,00

The directive at the end of the example specifies that the device named "XYZ-Audio-Device" is to be the preferred audio device. HKR is the audio device's root key in the registry. The flags parameter is set to three, which is the bitwise OR of FLG_ADDREG_BINVALUETYPE and FLG_ADDREG_NOCLOBBER; the latter prevents the device's existing preferred-device registry entries from getting overwritten in the event that the device is already installed and its driver is merely being upgraded. The four bytes at the end of the directive specify a nonzero value, which is necessary to enable the directive.


Port Class Audio Driver Reference

This section includes the following topics:

Audio Port Class Routines

Audio Helper Object Interfaces

Audio Port Object Interfaces

Audio Miniport Object Interfaces

Audio Stream Object Interfaces

DirectMusic Interfaces

Audio Power Management

Audio Port Class Structures


Audio Port Class Routines

This section describes, in alphabetic order, general routines provided by PortCls. These routines do not belong to any interface. They are used by audio miniport drivers to perform general utility functions such as registering with the PortCls and installing sub-devices.

PcAddAdapterDevice

PcCompleteIrp

PcCompletePendingPropertyRequest

PcCreateContentMixed

PcDestroyContent

PcDispatchIrp

PcForwardContentToFileObject

PcForwardContentToInterface

PcForwardIrpSynchronous

PcGetContentRights

PcGetDeviceProperty

PcGetTimeInterval

PcInitializeAdapterDriver

PcNewDmaChannel

PcNewInterruptSync

PcNewMiniport

PcNewPort

PcNewRegistryKey

PcNewResourceList

PcNewResourceSublist

PcNewServiceGroup

PcRegisterAdapterPowerManagement

PcRegisterIoTimeout

PcRegisterPhysicalConnection

PcRegisterPhysicalConnectionFromExternal

PcRegisterPhysicalConnectionToExternal

PcRegisterSubdevice

PcRequestNewPowerState

PcUnregisterIoTimeout


PcAddAdapterDevice

The PcAddAdapterDevice routine adds an adapter device.

PORTCLASSAPI NTSTATUS NTAPI
  PcAddAdapterDevice(
    IN PDRIVER_OBJECT  DriverObject,
    IN PDEVICE_OBJECT  PhysicalDeviceObject,
    IN PCPFNSTARTDEVICE  StartDevice,
    IN ULONG  MaxObjects,
    IN ULONG  DeviceExtensionSize
    );

Parameters

DriverObject
Pointer to the driver object. This pointer is passed as a parameter to the adapter's add-device handler.
PhysicalDeviceObject
Pointer to the physical device object for the device. This pointer is passed as a parameter to the adapter's add-device handler.
StartDevice
Pointer to a function that is called when the operating system starts the device.
MaxObjects
Maximum number of subdevices to be registered by calls to PcRegisterSubdevice.
DeviceExtensionSize
Device extension size. Use zero for default size. See comments below for user-supplied extension sizes.

Return Value

PcAddAdapterDevice returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

An adapter driver calls PcAddAdapterDevice when it receives a call to its add-device handler (see AddDevice). The add-device handler is typically installed in the device object by a call to PcInitializeAdapterDriver, but it can also be installed by the adapter driver by other means. PcAddAdapterDevice creates the functional device object for the physical device object that was passed to the add-device handler.

DeviceExtensionSize is typically zero. Some adapters may want to reserve additional space in the device extension, in which case they may specify a DeviceExtensionSize greater than PORT_CLASS_DEVICE_EXTENSION_SIZE, which is the default size. Any value greater than zero and less than PORT_CLASS_DEVICE_EXTENSION_SIZE is illegal. Adapters are free to use any part of the device extension after offset PORT_CLASS_DEVICE_EXTENSION_SIZE. They are also free to use bytes in the offset range of 16 to 31 inclusive. If the extension is regarded as an array of ULONGs, ULONGs four through seven are available for use by the adapter.

The StartDevice parameter points to a function of type PCPFNSTARTDEVICE, which is defined in portcls.h to be

  NTSTATUS
    (*PCPFNSTARTDEVICE)(
        IN      PDEVICE_OBJECT  DeviceObject,
        IN      PIRP            Irp,
        IN      PRESOURCELIST   ResourceList
        );

For more information on PcAddAdapterDevice and the adapter driver's StartDevice and AddDevice routines, see Startup Sequence.

Example

The following example code shows how an adapter driver can use the DeviceExtensionSize parameter to append 64 bytes of device-specific extension data to the end of the storage block that PortCls allocates for the device context:

  #define MY_EXTENSION_SIZE 64
  NTSTATUS ntstatus = PcAddAdapterDevice(DriverObject,   PhysicalDeviceObject,
                                         MyStartDevice, MAX_MINIPORTS,
                                         MY_EXTENSION_SIZE + PORT_CLASS_DEVICE_EXTENSION_SIZE);

The PcAddAdapterDevice call above is similar to the example in the startup sequence description, except that the last parameter that is passed to PcAddAdapterDevice is nonzero.

The adapter driver can then access the device-specific extension data as shown below, where variable pMyExtensionData is the driver's temporary pointer to this data:

  PDEVICE_CONTEXT pDeviceContext = (PDEVICE_CONTEXT)(PhysicalDeviceObject->DeviceExtension);
  PVOID pMyExtensionData = (PVOID)((PCHAR)pDeviceContext + PORT_CLASS_DEVICE_EXTENSION_SIZE);

See Also

AddDevice, DRIVER_OBJECT, DEVICE_OBJECT


PcCompleteIrp

The PcCompleteIrp routine is used when an IRP handler returns STATUS_PENDING and the IRP must later be completed. The IRP handler should not call this routine; it should call PcDispatchIrp instead.

PORTCLASSAPI NTSTATUS NTAPI
  PcCompleteIrp(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp,
    IN NTSTATUS  Status
    );

Parameters

DeviceObject
Pointer to the device object for the device.
Irp
Request to be completed.
Status
Status of the completed IRP.

Return Value

PcCompleteIrp returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

See Also

PcDispatchIrp, DEVICE_OBJECT


PcCompletePendingPropertyRequest

The PcCompletePendingPropertyRequest routine is called to complete a pending property request.

PORTCLASSAPI NTSTATUS NTAPI
  PcCompletePendingPropertyRequest(
    IN PPCPROPERTY_REQUEST  PropertyRequest,
    IN NTSTATUS  NtStatus
    );

Parameters

PropertyRequest
Pointer to the property request that was passed to the property handler.
NtStatus
Completion status of the request.

Return Value

PcCompletePendingPropertyRequest returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

If a miniport returns STATUS_PENDING from a property handler, it is obliged to keep a pointer to the property-request structure and to complete the request at some later time by calling this routine.

See Also

PCPROPERTY_REQUEST


PcCreateContentMixed

The PcCreateContentMixed routine computes the DRM content rights for a composition of KS audio streams, and creates a DRM content ID that represents the composite audio stream.

PORTCLASSAPI NTSTATUS NTAPI
  PcCreateContentMixed(
    IN PULONG  paContentId,
    IN ULONG  cContentId,
    OUT PULONG  pMixedContentId
    );

Parameters

paContentId
Pointer to an array of DRM content IDs. Each content ID represents a KS audio stream. If cContentId is zero, paContentId can be NULL. A content ID of zero is a special value that represents an audio stream with default content rights.
cContentId
Specifies the count of DRM content IDs in the paContentId array. The array can hold zero or more content IDs.
pMixedContentId
Pointer to a variable that receives the new DRM content ID that is assigned to the composite KS audio stream. If cContentId is zero, the new content ID is assigned default DRM content rights.

Return Value

PcCreateContentMixed returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

PcCreateContentMixed performs the same function as DrmCreateContentMixed.

See Digital Rights Management for more information.

See Also

DrmCreateContentMixed, PcDestroyContent


PcDestroyContent

The PcDestroyContent routine deletes a specified DRM content ID that was created by PcCreateContentMixed.

PORTCLASSAPI NTSTATUS NTAPI
  PcDestroyContent(
    IN ULONG  ContentId
    );

Parameters

ContentId
Specifies a nonzero DRM content ID assigned to a KS-audio stream by PcCreateContentMixed. Note that a ContentId of zero represents an audio stream with default DRM content rights and cannot be used with this routine.

Return Value

PcDestroyContent returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

PcDestroyContent performs the same function as DrmDestroyContent.

See Digital Rights Management for more information.

See Also

DrmDestroyContent, PcCreateContentMixed


PcDispatchIrp

The PcDispatchIrp routine dispatches an IRP.

PORTCLASSAPI NTSTATUS NTAPI
  PcDispatchIrp(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Pointer to the device object.
Irp
Pointer to the IRP that is to be dispatched.

Return Value

PcDispatchIrp returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

The PcInitializeAdapterDriver routine loads pointers to handlers for several IRPs into the driver object. An adapter driver can choose to overwrite one or more of the pointers written by PcInitializeAdapterDriver with a pointer to its own IRP handler. If the driver's local IRP handler determines that the IRP should be handled by PortCls instead, the local handler calls PcDispatchIrp to forward the IRP to PortCls.

For a code example, see the SB16 sample audio adapter in the Windows DDK.

See Also

PcInitializeAdapterDriver, DEVICE_OBJECT


PcForwardContentToFileObject

The PcForwardContentToFileObject routine forwards a specified DRM content ID to a KS audio pin that is represented by a file object.

PORTCLASSAPI NTSTATUS NTAPI
  PcForwardContentToFileObject(
    IN ULONG  ContentId,
    IN PFILE_OBJECT  FileObject
    );

Parameters

ContentId
Specifies a DRM content ID that is assigned to a KS audio stream.
FileObject
Pointer to a file object that represents the KS audio pin to which the KS audio stream is sent.

Return Value

PcForwardContentToFileObject returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code. The table below shows some of the possible error codes.

Error Status | Description
STATUS_NOT_IMPLEMENTED | Possibly indicates that the KS audio pin that is associated with FileObject does not support the DRM content rights that are assigned to ContentId.

Headers

Declared in portcls.h. Include portcls.h.

Comments

PcForwardContentToFileObject performs the same function as DrmForwardContentToFileObject.

See Digital Rights Management for more information.

See Also

DrmForwardContentToFileObject, DrmForwardContentToInterface, PcForwardContentToInterface, FILE_OBJECT


PcForwardContentToInterface

The PcForwardContentToInterface routine forwards a specified DRM content ID to a KS audio filter that receives a KS audio stream through a COM interface.

PORTCLASSAPI NTSTATUS NTAPI
  PcForwardContentToInterface(
    ULONG  ContentId,
    PUNKNOWN  pUnknown,
    ULONG  NumMethods
    );

Parameters

ContentId
Specifies a DRM content ID assigned to a KS audio stream.
pUnknown
Pointer to a COM interface that directly receives KS audio stream data for a KS audio filter.
NumMethods
Specifies the total number of methods in the COM interface, including all the methods in its base interfaces.

Return Value

PcForwardContentToInterface returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code. The table below shows some of the possible error codes.

Error Status | Description
STATUS_NOT_IMPLEMENTED | Possibly indicates that the KS audio pin that is associated with FileObject does not support the DRM content rights that are assigned to ContentId.

Headers

Declared in portcls.h. Include portcls.h.

Comments

PcForwardContentToInterface performs the same function as DrmForwardContentToInterface.

See Digital Rights Management for more information.

See Also

DrmForwardContentToFileObject, DrmForwardContentToInterface, PcForwardContentToFileObject


PcForwardIrpSynchronous

The PcForwardIrpSynchronous routine is used by IRP handlers to forward a PnP IRP to the PDO.

PORTCLASSAPI NTSTATUS NTAPI
  PcForwardIrpSynchronous(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

Parameters

DeviceObject
Pointer to the audio device's device object.
Irp
Pointer to the IRP that is to be forwarded.

Return Value

PcForwardIrpSynchronous returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

PcForwardIrpSynchronous causes the next physical device object (PDO) to receive the IRP and block until the IRP has been completed by the physical device driver. At that point, PcForwardIrpSynchronous unblocks and returns to the caller. The caller (an IRP handler) should eventually return, possibly with a pending status. In general, any IRP handler that calls this routine should specify the action IRP_ACTION_FINISH upon returning. Any other action would result in the IRP being forwarded to the physical device a second time.

See Also

DEVICE_OBJECT


PcGetContentRights

The PcGetContentRights routine outputs the DRM content rights that are assigned to a specified DRM content ID.

PORTCLASSAPI NTSTATUS NTAPI
  PcGetContentRights(
    IN ULONG  ContentId,
    OUT PDRMRIGHTS  DrmRights
    );

Parameters

ContentId
Specifies a DRM content ID.
DrmRights
Pointer to a DRMRIGHTS structure that receives the DRM content rights that are assigned to the audio stream or streams that are identified by ContentId.

Return Value

PcGetContentRights returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

PcGetContentRights performs the same routine as DrmGetContentRights.

See Digital Rights Management for more information.

See Also

PcCreateContentMixed, DRMRIGHTS


PcGetDeviceProperty

The PcGetDeviceProperty routine returns the requested device property from the registry.

PORTCLASSAPI NTSTATUS NTAPI
  PcGetDeviceProperty(
    IN PVOID  DeviceObject,
    IN DEVICE_REGISTRY_PROPERTY  DeviceProperty,
    IN ULONG  BufferLength,
    OUT PVOID  PropertyBuffer,
    OUT PULONG  ResultLength
    );

Parameters

DeviceObject
Pointer to the device object for the device.
DeviceProperty
Specifies the PnP device property that is requested.
BufferLength
Length in bytes of the buffer that is to receive the requested property data.
PropertyBuffer
Pointer to a caller-allocated buffer that is to receive the requested property data.
ResultLength
Pointer to a variable that receives the number of bytes actually returned or, if the input length is too small, the number of bytes required for the available property data.

Return Value

PcGetDeviceProperty returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

Valid values for the DeviceProperty parameter are the same as those that are defined for IoGetDeviceProperty.

The DeviceProperty parameter is set to one of the following DEVICE_REGISTRY_PROPERTY enumeration values:

DevicePropertyAddress

DevicePropertyBootConfiguration

DevicePropertyBootConfigurationTranslated

DevicePropertyBusNumber

DevicePropertyBusTypeGuid

DevicePropertyClassGuid

DevicePropertyClassName

DevicePropertyCompatibleIDs

DevicePropertyDetachability

DevicePropertyDeviceDescription

DevicePropertyDriverKeyName

DevicePropertyEnumeratorName

DevicePropertyFriendlyName

DevicePropertyHardwareID

DevicePropertyInstallState

DevicePropertyLegacyBusType

DevicePropertyLocationInformation

DevicePropertyManufacturer

DevicePropertyPhysicalDeviceObjectName

DevicePropertyUINumber

See Also

IoGetDeviceProperty, DEVICE_OBJECT


PcGetTimeInterval

The PcGetTimeInterval routine returns the time elapsed since a specified time. Time is measured in 100-nanosecond units.

PORTCLASSAPI ULONGLONG NTAPI
  PcGetTimeInterval(
    IN ULONGLONG  Since
    );

Parameters

Since
Time from which to measure the interval. Typically, this routine is called once with a "since" of zero to get the current time, and is called subsequently with a "since" of the recorded current time to get time intervals from that time.

Return Value

PcGetTimeInterval returns the current time minus Since.

Headers

Declared in portcls.h. Include portcls.h.

Comments

The value that is specified in parameter Since is measured in 100-nanosecond units. If Since is zero, the time returned is the number of 100-nanosecond ticks since January 1, 1601. The time units are the same as those used to specify the system time in the KeQuerySystemTime routine.

The following macros from portcls.h are useful for converting seconds, milliseconds, and microseconds to 100-millisecond units:

GTI_SECONDS

GTI_MILLISECONDS

GTI_MICROSECONDS

Example

This routine can be used for timing purposes by first saving the current time,

    ULONGLONG ullTime = PcGetTimeInterval(0);

and then checking to see whether the required interval has passed

    if (PcGetTimeInterval(ullTime) >= GTI_MILLISECONDS(5))

See Also

KeQuerySystemTime


PcInitializeAdapterDriver

The PcInitializeAdapterDriver routine binds an adapter driver to the port-class driver. IRP handlers and handlers for device addition and removal are installed in the driver object. Adapter drivers that must bind to more than one class driver should not call this routine.

PORTCLASSAPI NTSTATUS NTAPI
  PcInitializeAdapterDriver(
    IN PDRIVER_OBJECT  DriverObject,
    IN PUNICODE_STRING  RegistryPathName,
    IN PDRIVER_ADD_DEVICE  AddDevice
    );

Parameters

DriverObject
Pointer to the driver object. This pointer is passed as a parameter to the adapter's DriverEntry function.
RegistryPathName
Registry path name passed as a parameter to the adapter's DriverEntry function.
AddDevice
Pointer to the adapter's AddDevice function.

Return Value

PcInitializeAdapterDriver returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

The AddDevice handler supplied in the call to this routine should call PcAddAdapterDevice. For more information, see Startup Sequence.

The AddDevice parameter is a pointer of type PDRIVER_ADD_DEVICE, which is defined in ntddk.h to be:

NTSTATUS
  (*PDRIVER_ADD_DEVICE) (
      IN struct _DRIVER_OBJECT *DriverObject,
      IN struct _DEVICE_OBJECT *PhysicalDeviceObject
      );

The PcInitializeAdapterDriver routine loads pointers to handlers for the following IRPs into the driver object:

  • IRP_MJ_CLOSE
  • IRP_MJ_CREATE
  • IRP_MJ_DEVICE_CONTROL
  • IRP_MJ_FLUSH_BUFFERS
  • IRP_MJ_PNP
  • IRP_MJ_POWER
  • IRP_MJ_QUERY_SECURITY
  • IRP_MJ_READ
  • IRP_MJ_SET_SECURITY
  • IRP_MJ_SYSTEM_CONTROL
  • IRP_MJ_WRITE

PortCls uses its own internal handlers for the CREATE, PNP, POWER, and SYSTEM_CONTROL IRPs above. It uses the default KS handlers for the other seven IRPs.

An adapter driver that overwrites one or more of the pointers above with a pointer to its own IRP handler can call PcDispatchIrp from within its handler routine in order to forward the IRP to PortCls.

See Also

DriverEntry, AddDevice, PcAddAdapterDevice, PcDispatchIrp, DRIVER_OBJECT


PcNewDmaChannel

The PcNewDmaChannel routine creates a new DMA channel.

PORTCLASSAPI NTSTATUS NTAPI
  PcNewDmaChannel(
    OUT PDMACHANNEL  *OutDmaChannel,
    IN PUNKNOWN  OuterUnknown    OPTIONAL,
    IN POOL_TYPE  PoolType,
    IN PDEVICE_DESCRIPTION DeviceDescription,
    IN PDEVICE_OBJECT DeviceObject
    );

Parameters

OutDmaChannel
DMA channel created by this routine. This parameter is a pointer to a location that is to receive a reference to an object with an IDmaChannel interface.
OuterUnknown
Pointer to the IUnknown interface of an object that needs to aggregate the object. Unless aggregation is required, this parameter should be NULL.
PoolType
Specifies the type of storage pool from which the object is to be allocated.
DeviceDescription
Pointer to a DEVICE_DESCRIPTION structure that describes the attributes of the physical device for which the caller is requesting a DMA object.
DeviceObject
Pointer to the device object for the physical adapter device.

Return Value

PcNewDmaChannel returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

See Also

IDmaChannel, POOL_TYPE, DEVICE_DESCRIPTION, DEVICE_OBJECT


PcNewInterruptSync

The PcNewInterruptSync routine creates and initializes an interrupt-level synchronization object.

PORTCLASSAPI NTSTATUS NTAPI
  PcNewInterruptSync(
    OUT PINTERRUPTSYNC  *OutInterruptSync,
    IN PUNKNOWN  OuterUnknown    OPTIONAL,
    IN PRESOURCELIST  ResourceList,
    IN ULONG  ResourceIndex,
    IN INTERRUPTSYNCMODE  Mode,
    );

Parameters

OutInterruptSync
Pointer to a variable that receives the reference to the IInterruptSync object that is created by this routine.
OuterUnknown
Pointer to the IUnknown interface of an object that needs to aggregate the object. Unless aggregation is required, this parameter should be NULL.
ResourceList
Pointer to an IResourceList object that is to be supplied to the miniport during initialization. The port driver will examine this resource list but will not modify it.
ResourceIndex
Index of the interrupt resource in the resource list.
Mode
Manner in which multiple ISRs are handled. See comments below.

Return Value

PcNewInterruptSync returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

The Mode parameter is set to one of the INTERRUPTSYNCMODE enumeration values in the table below.

Value | Meaning
InterruptSyncModeNormal | Call each ISR in the list until one of them returns STATUS_SUCCESS.
InterruptSyncModeAll | Call each ISR in the list exactly once, regardless of the return code of the various ISRs.
InterruptSyncModeRepeat | Traverse the entire ISR list until a trip through the list occurs in which no ISR in the list returns STATUS_SUCCESS.

See Also

IInterruptSync, IResourceList


PcNewMiniport

The PcNewMiniport routine creates a new system-supplied miniport based on its class ID.

PORTCLASSAPI NTSTATUS NTAPI
  PcNewMiniport(
    OUT PMINIPORT  *OutMiniport,
    IN REFCLSID  ClassId
    );

Parameters

OutMiniport
Pointer to a variable that receives the reference to an IMiniport object that is created by this routine. This object has the miniport interface that is specified in the ClassId parameter.
ClassId
The class GUID that specifies the miniport interface that is being requested. Used only if the routine creates objects of multiple classes. Otherwise, it is set to NULL.

Return Value

PcNewMiniport returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

The standard miniports for MPU-401 UARTs and OPL3 synthesizers can be created with PcNewMiniport. These are built-in miniports that are provided with the PortCls system driver. Miniports that are part of the adapter driver are not created in this way.

The ClassId parameter can be set to one of the GUIDs in the following table.

GUID | System-supplied driver
CLSID_MiniportDriverDMusUART | Synth miniport driver for use with DMusUART port driver.
CLSID_MiniportDriverDMusUARTCapture | Capture miniport driver for use with DMusUART port driver.
CLSID_MiniportDriverFmSynth | Miniport driver for use with FMSynth port driver.
CLSID_MiniportDriverFmSynthWithVol | Same as above except that driver also supports volume node.
CLSID_MiniportDriverUart | Miniport driver for use with UART port driver.

The first two GUIDs in the table above are defined in header file dmusicks.h; the last three are defined in portcls.h.

The DMusUART port uses a DirectMusic driver that outputs MIDI data to a device with a pure MPU-401 MIDI interface. To produce sound, this device needs an external MIDI sound module attached to it.

The DMusUART capture port uses a DirectMusic driver that captures MIDI data from a device with a pure MPU-401 interface.

The UART port driver is obsolescent. New adapter driver code should use the DMusUART port driver, which supercedes UART and implements a superset of its functionality.

See Subdevice Creation for more information on creating ports and miniports for subdevices.

See Also

IMiniport


PcNewPort

The PcNewPort routine creates a new system-supplied port object whose interface is specified by a class ID.

PORTCLASSAPI NTSTATUS NTAPI
  PcNewPort(
    OUT PPORT  *OutPort,
    IN REFCLSID  ClassId
    );

Parameters

OutPort
Pointer to a variable that receives the reference to the IPort object that is generated by the call. This object has the port interface that is specified in the ClassId parameter.
ClassId
Class GUID that specifies the type of port interface that is being requested. Used only if the routine creates objects of multiple classes. Otherwise, it is set to NULL.

Return Value

PcNewPort returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

The ClassId parameter can be set to one of the GUIDs in the table below.

Class GUID | Port interface name
CLSID_PortDMus | IPortDMus
CLSID_PortMidi | IPortMidi
CLSID_PortTopology | IPortTopology
CLSID_PortWaveCyclic | IPortWaveCyclic
CLSID_PortWavePci | IPortWavePci

CLSID_PortDMus is defined in header file dmusicks.h. The other four GUIDs in the table above are defined in portcls.h.

In Microsoft® Windows® XP and later, the MIDI and DirectMusic ports use the same internal software implementation. This means that the CLSID_PortMidi GUID is equivalent to CLSID_PortDMus.

See Subdevice Creation for more information on creating ports and miniports for subdevices.

See Also

IPort


PcNewRegistryKey

The PcNewRegistryKey routine creates and initializes a registry key object.

PORTCLASSAPI NTSTATUS NTAPI
  PcNewRegistryKey(
    OUT PREGISTRYKEY  *OutRegistryKey,
    IN PUNKNOWN  OuterUnknown  OPTIONAL,
    IN ULONG  RegistryKeyType,
    IN ACCESS_MASK  DesiredAccess,
    IN PVOID  DeviceObject  OPTIONAL,
    IN PVOID  SubDevice  OPTIONAL,
    IN POBJECT_ATTRIBUTES  ObjectAttributes  OPTIONAL,
    IN ULONG  CreateOptions  OPTIONAL,
    OUT PULONG  Disposition  OPTIONAL
    );

Parameters

OutRegistryKey
Points to the variable that receives the reference to the IRegistryKey object that is created by the call.
OuterUnknown
Pointer to the IUnknown interface of an object that needs to aggregate the object. Unless aggregation is required, this parameter should be NULL.
RegistryKeyType
Indicates to the routine the type of registry access desired.
DesiredAccess
Specifies the type of access that the caller requires to the subkey being opened or created.
DeviceObject
Pointer to the adapter driver's device object. This is a DEVICE_OBJECT structure that is cast to type PVOID.
SubDevice
Aspect of the device to be offered to clients. Adapter drivers should assign the value NULL to this parameter.
ObjectAttributes
Points to the initialized object attributes of the key being opened.
CreateOptions
Flags indicating the create options. Can be zero if none are desired.
Disposition
Points to a variable that receives a value indicating whether or not a key was created or an existing key was opened.

Return Value

PcNewRegistryKey returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

The RegistryKeyType parameter should be set to one of the enumeration values in the table below.

Value | Required parameters
GeneralRegistryKey | ObjectAttributes and CreateOptions are both required.
DeviceRegistryKey | DeviceObject is required.
DriverRegistryKey | DeviceObject is required.
HwProfileRegistryKey | DeviceObject is required.

The DesiredAccess, ObjectAttributes, CreateOptions, and Disposition parameters take on the values that are defined for the parameters with the same names in the ZwCreateKey call.

See Also

IRegistryKey, ZwCreateKey, DEVICE_OBJECT


PcNewResourceList

The PcNewResourceList routine creates and initializes a resource list.

PORTCLASSAPI NTSTATUS NTAPI
  PcNewResourceList(
    OUT PRESOURCELIST  *OutResourceList,
    IN PUNKNOWN  OuterUnknown  OPTIONAL,
    IN POOL_TYPE  PoolType,
    IN PCM_RESOURCE_LIST  TranslatedResources,
    IN PCM_RESOURCE_LIST  UntranslatedResources
    );

Parameters

OutResourceList
Pointer to a variable that will receive the reference to the IResourceList object that is generated by the call.
OuterUnknown
Pointer to the IUnknown interface of an object that needs to aggregate the resource-list object. Unless aggregation is required, this parameter should be NULL.
PoolType
Specifies the type of pool from which the object is to be allocated.
TranslatedResources
WDM-supplied resource list for translated resources.
UntranslatedResources
WDM-supplied resource list for untranslated resources.

Return Value

PcNewResourceList returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

For a discussion of translated and untranslated (or raw) resource lists, see Mapping Bus-Relative Addresses to Virtual Addresses.

See Also

IResourceList, POOL_TYPE


PcNewResourceSublist

The PcNewResourceSublist routine creates and initializes an empty resource list that is derived from another resource list.

PORTCLASSAPI NTSTATUS NTAPI
  PcNewResourceSublist(
    OUT PRESOURCELIST  *OutResourceList,
    IN PUNKNOWN  OuterUnknown  OPTIONAL,
    IN POOL_TYPE  PoolType,
    IN PRESOURCELIST  ParentList,
    IN ULONG  MaximumEntries
    );

Parameters

OutResourceList
Pointer to the variable that will receive the reference to the IResourceList object that is created by the call.
OuterUnknown
Pointer to the IUnknown interface of an object that needs to aggregate the object. Unless aggregation is required, this parameter should be NULL.
PoolType
Specifies the type of pool from which the object is to be allocated.
ParentList
Resource list from which the child list will be created.
MaximumEntries
Maximum number of entries that will be added to the resource list.

Return Value

PcNewResourceSublist returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

See Also

IResourceList, POOL_TYPE


PcNewServiceGroup

The PcNewServiceGroup routine creates and initializes a service group object.

PORTCLASSAPI NTSTATUS NTAPI
  PcNewServiceGroup(
    OUT PSERVICEGROUP  *OutServiceGroup,
    IN PUNKNOWN  OuterUnknown  OPTIONAL
    );

Parameters

OutServiceGroup
Pointer to a variable that is to receive the reference to the IServiceGroup object that is created by the call.
OuterUnknown
Pointer to the IUnknown interface of an object that needs to aggregate the object. Unless aggregation is required, this parameter should be NULL.

Return Value

PcNewServiceGroup returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

See Also

IServiceGroup


PcRegisterAdapterPowerManagement

The PcRegisterAdapterPowerManagement routine registers the adapter's power management with PortCls.

PORTCLASSAPI NTSTATUS NTAPI
  PcRegisterAdapterPowerManagement(
    IN PUNKNOWN  pUnknown,
    IN PVOID  pvContext1
    );

Parameters

pUnknown
Pointer to an adapter driver object's IUnknown interface. The PortCls system driver queries this object for its IAdapterPowerManagement interface.
pvContext1
A PVOID pointer to the Functional Device Object (FDO).

Return Value

PcRegisterAdapterPowerManagement returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

See Also

IAdapterPowerManagement


PcRegisterIoTimeout

The PcRegisterIoTimeout routine registers a driver-supplied I/O-timer callback routine for a specified device object. Once registered, the port-class driver calls the timer callback approximately once per second for as long as the device remains active.

PcRegisterIoTimeout should be called at IRQL=PASSIVE_LEVEL.

PORTCLASSAPI NTSTATUS NTAPI
  PcRegisterIoTimeout(
    IN PDEVICE_OBJECT  pDeviceObject,
    IN PIO_TIMER_ROUTINE  pTimerRoutine,
    IN PVOID  pContext
    );

Parameters

pDeviceObject
Points to a device object representing a device on which I/O operations can time out.
pTimerRoutine
Points to the driver-supplied I/O-timer callback routine.
pContext
Points to the driver-specific context with which the I/O-timer callback routine will be called.

Return Value

PcRegisterIoTimeout returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code. The table below shows some of the possible error codes.

Error Status | Description
STATUS_INSUFFICIENT_RESOURCES | Possibly indicates that a memory allocation failed inside the port-class driver.
STATUS_UNSUCCESSFUL | Possibly indicates that a timer callback with the same combination of device object, I/O-timer callback routine, and context is already registered.

Headers

Declared in portcls.h. Include portcls.h.

Comments

An adapter driver calls the PcRegisterIoTimeout routine to enable a low-resolution watchdog timer. Drivers use this routine primarily to monitor devices that have no means to generate an event themselves if they fail to complete a previously initiated I/O operation within some maximum time interval.

After the driver calls PcRegisterIoTimeout, the port-class driver calls the driver's I/O-timer callback routine approximately once per second for as long as the device remains active. (The device is activated by an IRP_MN_START_DEVICE request and deactivated by an IRP_MN_STOP_DEVICE request.)

The driver can disable the timer by calling PcUnregisterIoTimeout.

Only one timer callback with a particular combination of device object, I/O-timer callback routine, and context can be registered at a time.

The meaning of the pContext parameter is determined by the adapter driver, but the driver typically sets this parameter to point to an object such as the miniport, miniport-stream, or adapter object.

The pTimerRoutine parameter is of type PIO_TIMER_ROUTINE, which is defined in ntddk.h to be

VOID
  (*PIO_TIMER_ROUTINE) (
      IN PDEVICE_OBJECT DeviceObject,
      IN PVOID Context
      );

When the port-class driver calls the timer routine, it passes the same device-object and context parameters that the adapter driver earlier passed to PcRegisterIoTimeout.

The I/O-timer callback routine is called at IRQL=DISPATCH_LEVEL and should reside in nonpaged memory.

See Also

PcUnregisterIoTimeout, DEVICE_OBJECT


PcRegisterPhysicalConnection

The PcRegisterPhysicalConnection routine registers a physical connection between two audio adapter filters that are instantiated by the same adapter driver.

PORTCLASSAPI NTSTATUS NTAPI
  PcRegisterPhysicalConnection(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PUNKNOWN  FromUnknown,
    IN ULONG  FromPin,
    IN PUNKNOWN  ToUnknown,
    IN ULONG  ToPin
    );

Parameters

DeviceObject
Pointer to the device object for the adapter device.
FromUnknown
Specifies an IUnknown COM interface of a port object (see Introduction to Port Class). The port object that is associated with FromUnknown is bound to the subdevice (see Subdevice Creation) that supplies the connection's source pin.
FromPin
Specifies the number of the source pin on the filter that is associated with the FromUnknown interface.
ToUnknown
Specifies an IUnknown COM interface of a port object. The port object that is associated with ToUnknown is bound to the subdevice that supplies the connection's sink pin.
ToPin
Specifies the number of the sink pin on the filter that is associated with the ToUnknown interface.

Return Value

PcRegisterPhysicalConnection returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

An adapter driver calls PcRegisterPhysicalConnection to register a physical connection with the PortCls system driver. PortCls stores this information so that the port driver can subsequently use the information to respond to a KSPROPERTY_PIN_PHYSICALCONNECTION property request.

The parameters that the caller provides to the PcRegisterPhysicalConnection routine describe a physical connection between two subdevices (represented as individual filters) on the same adapter card.

Unlike a logical connection between two pins, which can be configured under software control, a physical connection is hardwired. For example, a typical adapter card might have a physical connection that carries the analog signal from the output pin of its wave-output filter to the input pin of its topology filter.

For an example of a StartDevice routine that uses the PcRegisterPhysicalConnection call to register an adapter's physical connections, see the source code for the SB16 sample adapter in the Windows DDK.

See Also

PcRegisterPhysicalConnectionFromExternal, PcRegisterPhysicalConnectionToExternal, DEVICE_OBJECT


PcRegisterPhysicalConnectionFromExternal

The PcRegisterPhysicalConnectionFromExternal routine registers a physical connection to an audio adapter filter from an external audio adapter filter.

PORTCLASSAPI NTSTATUS NTAPI
  PcRegisterPhysicalConnectionFromExternal(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PUNICODE_STRING  FromString,
    IN ULONG  FromPin,
    IN PUNKNOWN  ToUnknown,
    IN ULONG  ToPin
    );

Parameters

DeviceObject
Pointer to the device object for the device.
FromString
Pointer to the name of the external filter that supplies the connection's source pin.
FromPin
Specifies the number of the source pin on the external filter named by FromString.
ToUnknown
Specifies an IUnknown COM interface of a port object (see Introduction to Port Class). The port object that is associated with ToUnknown is bound to the subdevice (see Subdevice Creation) that supplies the connection's sink pin.
ToPin
Specifies the number of the sink pin on the filter that is associated with the ToUnknown interface.

Return Value

PcRegisterPhysicalConnectionFromExternal returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

An adapter filter is external to an adapter driver if it is instantiated by a different adapter driver.

An adapter driver calls PcRegisterPhysicalConnectionFromExternal to register a physical connection to one of its subdevices from an external device. The port driver subsequently uses the information about the connection to respond to a KSPROPERTY_PIN_PHYSICALCONNECTION property request.

The information that is required to register an external physical connection should be supplied to the two drivers. This can be done during an initial coordinated install of the two devices, or it can be done dynamically by a user-mode configuration program that coordinates changes to the configurations of both devices.

See Also

PcRegisterPhysicalConnection, PcRegisterPhysicalConnectionToExternal, DEVICE_OBJECT


PcRegisterPhysicalConnectionToExternal

The PcRegisterPhysicalConnectionToExternal routine registers a physical connection from an audio adapter filter to an external audio adapter filter.

PORTCLASSAPI NTSTATUS NTAPI
  PcRegisterPhysicalConnectionToExternal(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PUNKNOWN  FromUnknown,
    IN ULONG  FromPin,
    IN PUNICODE_STRING  ToString,
    IN ULONG  ToPin
    );

Parameters

DeviceObject
Pointer to the device object for the device.
FromUnknown
Specifies an IUnknown COM interface of a port object (see Introduction to Port Class). The port object that is associated with FromUnknown is bound to the subdevice (see Subdevice Creation) that supplies the connection's source pin.
FromPin
Specifies the number of the source pin on the filter that is associated with the FromUnknown interface.
ToString
Pointer to the name of the external filter that supplies the sink pin for the connection.
ToPin
Specifies the number of the sink pin on the external filter named by ToString.

Return Value

PcRegisterPhysicalConnectionToExternal returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

An adapter filter is external to an adapter driver if it is instantiated by a different adapter driver.

An adapter driver calls PcRegisterPhysicalConnectionToExternal to register a physical connection from one of its subdevices to an external device. The port driver subsequently uses the information about the connection to respond to a KSPROPERTY_PIN_PHYSICALCONNECTION property request.

The information required to register an external physical connection should be supplied to the two drivers. This can be done either during an initial coordinated install of the two devices, or dynamically by a user-mode configuration program that coordinates changes to the configuration of both devices.

See Also

PcRegisterPhysicalConnection, PcRegisterPhysicalConnectionFromExternal, DEVICE_OBJECT


PcRegisterSubdevice

The PcRegisterSubdevice routine registers a subdevice to make it available for use by clients.

PORTCLASSAPI NTSTATUS NTAPI
  PcRegisterSubdevice(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PWCHAR  Name,
    IN PUNKNOWN  Unknown
    );

Parameters

DeviceObject
Pointer to the adapter driver's device object.
Name
Short name used to distinguish different subdevices registered on the same device. Each subdevice of a given device should have a unique name.
Unknown
Pointer to the subdevice's DDI top edge. This is generally the IPort interface of the port.

Return Value

PcRegisterSubdevice returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

See Also

DEVICE_OBJECT, IPort


PcRequestNewPowerState

The PcRequestNewPowerState routine is used to request a new power state for the device. This routine is typically not needed by adapter drivers but can occasionally be useful in working around some kinds of hardware problems.

PORTCLASSAPI NTSTATUS NTAPI
  PcRequestNewPowerState(
    IN PDEVICE_OBJECT  pDeviceObject,
    IN DEVICE_POWER_STATE  RequestedNewState
    );

Parameters

pDeviceObject
Pointer to the functional device object (FDO).
RequestedNewState
Device power state being requested. Supported values include PowerDeviceD0, PowerDeviceD1, PowerDeviceD2, and PowerDeviceD3.

Return Value

PcRequestNewPowerState returns STATUS_SUCCESS if the call was successful. Otherwise, returns an appropriate error message.

Headers

Declared in portcls.h. Include portcls.h.

Comment

An adapter driver can call PcRequestNewPowerState to compensate for hardware design flaws. For example, if the functions in an audio adapter are not mutually independent and need to be shut down in a particular order, the adapter can call PcRequestNewPowerState to ensure that a particular subdevice is shut down first.

The RequestedNewState parameter can be set to one of the DEVICE_POWER_STATE enumeration values in the table below.

Power State | Meaning
PowerDeviceD0 | Full power state
PowerDeviceD1 | The sleep state with the lowest power-up latency
PowerDeviceD2 | A medium-latency sleep state
PowerDeviceD3 | A full hibernation state and the sleep state with the longest power-up latency

The hardware can be accessed only in power state PowerDeviceD0. In any other state, the driver should cache any attempted hardware accesses and defer those accesses until the PowerDeviceD0 state is restored.

See Also

DEVICE_OBJECT, Power Management for Audio Devices


PcUnregisterIoTimeout

The PcUnregisterIoTimeout routine unregisters a driver-supplied I/O-timer callback routine for a specified device object.

This routine should be called at IRQL=PASSIVE_LEVEL.

PORTCLASSAPI NTSTATUS NTAPI
  PcUnregisterIoTimeout(
    IN PDEVICE_OBJECT  pDeviceObject,
    IN PIO_TIMER_ROUTINE  pTimerRoutine,
    IN PVOID  pContext
    );

Parameters

pDeviceObject
Points to the same device object that the driver supplied when it previously called PcRegisterIoTimeout.
pTimerRoutine
Points to the same I/O-timer callback routine that the driver supplied when it previously called PcRegisterIoTimeout.
pContext
Points to the same driver-determined context that the driver supplied when it previously called PcRegisterIoTimeout.

Return Value

PcUnregisterIoTimeout returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code. The table below shows some of the possible error codes.

Error Status | Description
STATUS_NOT_FOUND | Indicates that no timer callback with the same device object, callback routine, and context is currently registered.

Headers

Declared in portcls.h. Include portcls.h.

Comments

This call succeeds only if a time-out callback with the same device object, timer routine, and context was previously registered with a call to the PcRegisterIoTimeout routine.

See Also

PcRegisterIoTimeout, DEVICE_OBJECT


IDmaChannel

The IDmaChannel interface provides an abstraction of a DMA channel and its associated parameters.

An IDmaChannel object encapsulates the following:

  • A master or slave DMA channel
  • The data buffer that is associated with the channel
  • Information that describes how the channel is to be used

Ports and miniports use DMA-channel objects to communicate information regarding DMA-channel usage. Typically, a miniport allocates a set of DMA channels during initialization or during the creation of a stream. At the time that a new stream is created, the miniport tells the port driver which DMA-channel object will be used for the stream. The miniport passes the IDmaChannel object as a parameter to the NewStream call (for example, see IMiniportWavePci::NewStream).

DMA-channel objects can be created for slave or master DMA channels:

  • In the case of a slave DMA channel, the DMA channel object controls the slave DMA hardware.
  • In the case of a master DMA channel, the DMA channel object controls the slave DMA hardware.

A master DMA-channel object is little more than a backboard for sharing information about the DMA channel between the port and miniport. In either case, the DMA-channel object exposes the following:

  • An adapter object
  • A single common buffer that the driver and DMA hardware can share
  • A buffer-size value that can be queried and changed

The adapter object is a DMA-adapter structure for a physical device object. The adapter object is automatically created when the DMA-channel object is created by one of the following methods:

IPortWavePci::NewMasterDmaChannel

IPortWaveCyclic::NewMasterDmaChannel

IPortWaveCyclic::NewSlaveDmaChannel

The method IDmaChannel::GetAdapterObject can be used to obtain a pointer to the adapter object.

In the case of a slave DMA channel, the IDmaChannel::TransferCount method returns the maximum transfer size (the MapSize parameter) that was specified in the call to IDmaChannelSlave::Start. Also, the adapter object provides some methods for manipulating and querying the DMA device. None of these methods are meaningful for master DMA channels.

IDmaChannel::AllocateBuffer and IDmaChannel::FreeBuffer are used to manage the single common buffer that is associated with the DMA-channel object. The buffer that is allocated by the object is guaranteed to be accessible by both the driver (with kernel virtual-memory addresses) and DMA device (with physical-memory addresses). In addition, the buffer will be physically contiguous. Typically, the best strategy is to allocate the DMA buffer during miniport initialization when physically contiguous memory is most plentiful. IDmaChannel::AllocatedBufferSize returns the size of the buffer as it was specified in the call to IDmaChannel::AllocateBuffer.

IDmaChannel::MaximumBufferSize indicates the actual maximum buffer size that can be used. This might exceed the allocated size if the allocated size is not an even multiple of the page size. It might be less than the allocated size if the DMA device cannot support transfers of the allocated size. IDmaChannel::BufferSize and IDmaChannel::SetBufferSize are used to query and set the size of the buffer to be used for DMA transfers. When the buffer is allocated, the buffer size is set to the maximum buffer size. After initialization, both the port and miniport have the opportunity to change the buffer size and discover its current value. The miniport uses the result of IDmaChannel::BufferSize to determine the transfer size for DMA operations when the DMA channel is started. IDmaChannel::SystemAddress, and IDmaChannel::PhysicalAddress are used to obtain the virtual and physical addresses of the buffer, respectively.

IDmaChannel::CopyTo and IDmaChannel::CopyFrom copy sample data to and from the DMA buffer.

The DMA buffer is not necessarily used to transfer the streamed data. In the case of the WavePci port driver, the streamed data is delivered to (or from) the miniport using scatter/gather mappings. The miniport can still have use for the buffer as a shared memory space for communication between the miniport and adapter.

Port drivers provide miniports with functions that they can use to create DMA channels. Unless otherwise noted in the description of the port driver, it is not absolutely necessary to use DMA objects allocated from the port driver. The port driver simply requires a pointer to an IDmaChannel interface that supports the methods it needs. Check the documentation for each port driver for a list of the DMA-channel methods that the port driver requires.

Typically, the easiest path is to use the DMA-channel allocation functions that are offered by the port driver. In some rare cases, the miniport developer will want to implement the DMA-channel object in some special way that meets the needs of a particular adapter. This sometimes requires the implementation of a new object. At other times, it is sufficient to have the miniport's stream object expose IDmaChannel and implement the DMA-channel methods itself.

The IDmaChannel interface supports the following methods:

IDmaChannel::AllocateBuffer

IDmaChannel::AllocatedBufferSize

IDmaChannel::BufferSize

IDmaChannel::CopyFrom

IDmaChannel::CopyTo

IDmaChannel::FreeBuffer

IDmaChannel::GetAdapterObject

IDmaChannel::MaximumBufferSize

IDmaChannel::PhysicalAddress

IDmaChannel::SetBufferSize

IDmaChannel::SystemAddress

IDmaChannel::TransferCount


IDmaChannel::AllocateBuffer

The AllocateBuffer method allocates a common buffer that can be accessed by the port driver and DMA hardware. Callers of AllocateBuffer should run at a passive IRQL.

NTSTATUS
  AllocateBuffer(
    IN ULONG  BufferSize,
    IN PPHYSICAL_ADDRESS  PhysicalAddressConstraint  OPTIONAL
    );

Parameters

BufferSize
Size in bytes of the buffer to be allocated.
PhysicalAddressConstraint
Optional constraint to place on the physical address of the buffer. If this parameter is nonNULL, only the bits that are set in the constraint address will vary from the beginning to the end of the buffer. For example, to request a buffer that does not cross a 64-kilobyte boundary, specify the physical address constraint 0x000000000000ffff.

Return Value

AllocateBuffer returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

This method should be called only once following the creation of the DMA-channel object unless the previously allocated buffer is first freed by calling FreeBuffer.

See Also

IDmaChannel::FreeBuffer


IDmaChannel::AllocatedBufferSize

The AllocatedBufferSize method returns the size of the allocated buffer. Callers of AllocatedBufferSize can run at any IRQL.

ULONG
  AllocatedBufferSize(
    VOID
    );

Parameters

None

Return Value

AllocatedBufferSize returns the size in bytes of the allocated buffer.

Headers

Declared in portcls.h. Include portcls.h.


IDmaChannel::BufferSize

The BufferSize method returns the size in bytes of the DMA channel's data buffer. Callers of BufferSize can run at any IRQL.

ULONG
  BufferSize(
    VOID
    );

Parameters

None

Return Value

BufferSize returns the size in bytes of the buffer.

Headers

Declared in portcls.h. Include portcls.h.

Comments

The BufferSize method returns the buffer size that was set by the previous call to IDmaChannel::SetBufferSize. If SetBufferSize has not been called since the IDmaChannel::AllocateBuffer call, BufferSize returns the allocated buffer size. The DMA-channel object does not actually use this value internally. This value is maintained by the object to allow its various clients to communicate the intended size of the buffer. This call is often used to obtain the map-size parameter to the IDmaChannelSlave::Start method.

See Also

IDmaChannel::SetBufferSize, IDmaChannel::AllocateBuffer, IDmaChannelSlave::Start


IDmaChannel::CopyFrom

The CopyFrom method copies sample data from the DMA channel's common buffer. Callers of CopyFrom can run at any IRQL.

NTSTATUS
  CopyFrom(
    IN PVOID  Destination,
    IN PVOID  Source,
    IN ULONG  ByteCount
    );

Parameters

Destination
Points to the destination buffer.
Source
Points to the source buffer.
ByteCount
Number of bytes to be copied.

Return Value

CopyFrom returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comment

The Source and Destination pointers are both kernel-mode virtual addresses. The IDmaChannel::SystemAddress call returns the virtual address of a DMA channel's common buffer.

See Also

IDmaChannel::SystemAddress


IDmaChannel::CopyTo

The CopyTo method copies sample data to the DMA channel's common buffer. Callers of CopyTo can run at any IRQL.

NTSTATUS
  CopyTo(
    IN PVOID  Destination,
    IN PVOID  Source,
    IN ULONG  ByteCount
    );

Parameters

Destination
Points to the destination buffer.
Source
Points to the source buffer.
ByteCount
Number of bytes to be copied.

Return Value

CopyTo returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comment

The Source and Destination pointers are both kernel-mode virtual addresses. The IDmaChannel::SystemAddress call returns the virtual address of a DMA channel's common buffer.

See Also

IDmaChannel::SystemAddress


IDmaChannel::FreeBuffer

The FreeBuffer method frees the buffer that was previously allocated by AllocateBuffer. Callers of FreeBuffer should run at IRQL PASSIVE_LEVEL.

VOID
  FreeBuffer(
    VOID
    );

Parameters

None

Return Value

None

Headers

Declared in portcls.h. Include portcls.h.

Comments

Because the buffer is automatically freed when the DMA-channel object is deleted, the FreeBuffer method is not typically used.

See Also

IDmaChannel::AllocateBuffer


IDmaChannel::GetAdapterObject

The GetAdapterObject method returns the DMA-channel's hardware adapter object. Callers of GetAdapterObject can run at any IRQL.

PADAPTER_OBJECT
  GetAdapterObject(
    VOID
    );

Parameters

None

Return Value

GetAdapterObject returns a pointer to the DMA-channel object's internal adapter object, which is a DMA_ADAPTER structure.

Headers

Declared in portcls.h. Include portcls.h.

Comments

The method returns a pointer to a DMA adapter object that has a system-defined interface to the DMA operations that the hardware supports. The adapter driver can pass this pointer as a parameter to the AllocateCommonBuffer and FreeCommonBuffer functions if the miniport needs to allocate its own physically contiguous memory for common buffer blocks. These blocks can be accessed both by DMA hardware and by software running on the processor.

See Also

DMA_ADAPTER, AllocateCommonBuffer, FreeCommonBuffer


IDmaChannel::MaximumBufferSize

The MaximumBufferSize method returns the size in bytes of the largest buffer that this DMA-channel object is configured to support. Callers of MaximumBufferSize can run at any IRQL.

ULONG
  MaximumBufferSize(
    VOID
    );

Parameters

None

Return Value

MaximumBufferSize returns the size in bytes of the largest buffer that this DMA channel supports.

Headers

Declared in portcls.h. Include portcls.h.


IDmaChannel::PhysicalAddress

The PhysicalAddress method returns the physical address of the allocated buffer. Callers of PhysicalAddress can run at any IRQL.

PHYSICAL_ADDRESS
  PhysicalAdress(
    VOID
    );

Parameters

None

Return Value

PhysicalAddress returns the physical address of the allocated buffer.

Headers

Declared in portcls.h. Include portcls.h.


IDmaChannel::SetBufferSize

The SetBufferSize method sets the current buffer size, which is the value that IDmaChannel::BufferSize returns. By default, this value is set to the allocated buffer size after IDmaChannel::AllocateBuffer is called and before SetBufferSize is called. The DMA-channel object does not actually use this value internally. The current buffer size is maintained by the object to allow its various clients to communicate the intended size of the buffer. Callers of SetBufferSize can run at any IRQL.

void
  SetBufferSize(
    ULONG  BufferSize
    );

Parameters

BufferSize
Current size in bytes.

Return Value

None

Headers

Declared in portcls.h. Include portcls.h.

Also See

IDmaChannel::AllocateBuffer, IDmaChannel::BufferSize


IDmaChannel::SystemAddress

The SystemAddress method returns the system address of the allocated buffer. Callers of SystemAddress can run at any IRQL.

PVOID
  SystemAddress(
    VOID
    );

Parameters

None

Return Value

SystemAddress returns the address in kernel-mode virtual-address space of the allocated buffer.

Headers

Declared in portcls.h. Include portcls.h.


IDmaChannel::TransferCount

The TransferCount method returns the size in bytes of the buffer that is currently being transferred by a slave DMA object. Callers of TransferCount can run at any IRQL.

ULONG
  TransferCount(
    VOID
    );

Parameters

None

Return Value

TransferCount returns the size in bytes of the buffer that is currently being transferred.

Headers

Declared in portcls.h. Include portcls.h.


IDmaChannelSlave

The IDmaChannelSlave interface provides a set of methods for monitoring and controlling a slave DMA channel. IDmaChannelSlave inherits from the IDmaChannel interface.

In addition to the methods in the IDmaChannel base interface, the IDmaChannelSlave interface supports the following methods:

IDmaChannelSlave::ReadCounter

IDmaChannelSlave::Start

IDmaChannelSlave::Stop

IDmaChannelSlave::WaitForTC


IDmaChannelSlave::ReadCounter

The ReadCounter method reads the counter of a slave DMA object. Callers of ReadCounter should run at IRQL <= DISPATCH_LEVEL.

ULONG
  ReadCounter(
    VOID
    );

Parameters

None

Return Value

ReadCounter returns the DMA object's counter value. When the object is started, this value is set to the map size (the IDmaChannelSlave::Start method's MapSize parameter). The value decrements until it reaches zero, at which time it is reset to the map size. This process repeats until the DMA object is stopped (by calling the IDmaChannelSlave::Stop method).

Headers

Declared in portcls.h. Include portcls.h.

See Also

IDmaChannelSlave::Start,

IDmaChannelSlave::Stop


IDmaChannelSlave::Start

The Start method starts a slave DMA object. Callers of Start should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  Start(
    ULONG  MapSize,
    BOOL  WriteToDevice
    );

Parameters

MapSize
Number of bytes of the allocated buffer that are to be mapped.
WriteToDevice
TRUE if data is to be moved from the buffer to the device; FALSE if it is to be moved from the device to the buffer.

Return Value

Start returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.


IDmaChannelSlave::Stop

The Stop method stops a slave DMA object. Callers of Stop should run at IRQL <= DISPATCH_LEVEL

NTSTATUS
  Stop(
    VOID
    );

Parameters

None

Return Value

Stop returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

This call flushes any data remaining in the DMA controller's internal cache at the time that the DMA transfer operation is stopped.

See Also

IDmaChannelSlave::Start


IDmaChannelSlave::WaitForTC

The WaitForTC method waits for the DMA-transfer terminal count to complete, or it times out if the specified time-out interval expires first. Callers of WaitForTC can run at any IRQL.

NTSTATUS
  WaitForTC(
    ULONG  Timeout,
    );

Parameters

Timeout
Integer value that specifies the time-out interval in microseconds. This is how long the method waits for the transfer to complete. The specified time is rounded down to the nearest ten-microsecond increment.

Return Value

WaitForTC returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.


IInterruptSync

The IInterruptSync interface represents an interrupt-sync object that synchronizes the execution of a list of routines. The list can contain both ISRs (interrupt-service routines) and routines that are not ISRs. IInterruptSync inherits from the IUnknown interface.

The PortCls function PcNewInterruptSync creates a new IInterruptSync object that connects to an interrupt resource. More than one ISR can be associated with a single sync object.

The IInterruptSync::RegisterServiceRoutine method associates ISRs with a sync object.

PINTERRUPTSYNCROUTINE is a function pointer type for routines that are synchronized by an interrupt-sync object:

  typedef NTSTATUS (*PINTERRUPTSYNCROUTINE)
  (
      IN      struct IInterruptSync * InterruptSync,
      IN      PVOID                   DynamicContext
  );

Both ISRs and routines that are synchronized with ISRs use this type. Any routine that that is defined to be of type PINTERRUPTSYNCROUTINE can be synchronized with all ISRs that are registered with the sync object. Associated with each interrupt-sync object are one or more ISRs of this type. The sync object synchronizes the ISR with other routines.

The IInterruptSync interface is flexible in the way that it deals with multiple ISRs. The ISRs are kept in a linked list that is walked at interrupt time. When an ISR registers itself with a sync object, it specifies whether it should be added to the beginning or end of this list. The manner in which this list of ISRs is handled is specified in the call to PcNewInterruptSync when the object is created. The call supports the three options that are specified by the INTERRUPTSYNCMODE enumeration constants in the table below.

Constant | Meaning
InterruptSyncModeNormal | Call each ISR in the list until one of them returns STATUS_SUCCESS.
InterruptSyncModeAll | Call each ISR in the list exactly once, regardless of the return codes of the preceding ISRs.
InterruptSyncModeRepeat | Traverse the entire ISR list until a trip through the list occurs in which no ISR in the list returns STATUS_SUCCESS.

In the InterruptSyncModeNormal mode, the sync object calls each ISR in the list until one of them returns STATUS_SUCCESS. Any ISRs in the list that follow this ISR are not called. This mode emulates the way that the operating system normally handles ISRs. If none of the ISRs return STATUS_SUCCESS, the behavior is the same as InterruptSyncModeAll.

In the InterruptSyncModeAll mode, each ISR in the list is called exactly once, regardless of the return codes of the preceding ISRs. This is intended for more primitive hardware where the source of the interrupt is not deterministic, although it might be useful in other situations as well. For example, two interrupt sources could be tightly synchronized on every interrupt, regardless of which source the interrupt came from.

In the InterruptSyncModeRepeat mode, the entire associated ISR list is repeatedly traversed until a trip through the list occurs in which no ISR in the list returns STATUS_SUCCESS. This is intended to handle situations in which interrupts from multiple sources might fire on the same interrupt line at the same time, or a second interrupt might fire during ISR processing. Every interrupt source should be able to determine if it needs processing. The system will stop responding if an ISR that always returns STATUS_SUCCESS is registered with an interrupt-sync object in this mode.

In any of these modes, the interrupt-sync object will acknowledge the interrupt to the operating system if any of the registered ISRs return STATUS_SUCCESS. In all three modes, if all interrupt sources indicate that they did not successfully handle the interrupt, the interrupt-sync object will return an unsuccessful result to the operating system.

Another facet of IInterruptSync is its ability to synchronize execution of ISRs with other routines that are not ISRs. Execution of any registered ISR is guaranteed to be held off until the routine that is passed to IInterruptSync::CallSynchronizedRoutine has finished running.

The following methods manage the sync object's list of ISRs and other synchronized routines:

IInterruptSync::CallSynchronizedRoutine

IInterruptSync::Connect

IInterruptSync::Disconnect

IInterruptSync::GetKInterrupt

IInterruptSync::RegisterServiceRoutine


IInterruptSync::CallSynchronizedRoutine

The CallSynchronizedRoutine method calls a routine that is not an ISR (interrupt-service routine) but whose execution needs to be synchronized with ISRs.

NTSTATUS
  CallSynchronizedRoutine(
    IN PINTERRUPTSYNCROUTINE  Routine,
    IN PVOID  DynamicContext
    )

Parameters

Routine
The routine to be called. This routine will run exclusive of the object's ISR and all other routines that are synchronized through the object. Even on multiple-processor machines, routines that are synchronized by a given object will not run concurrently.
DynamicContext
A context value to be passed to the routine.

Return Value

CallSynchronizedRoutine returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

Execution of any registered ISR is guaranteed to be held off until the call to the routine that is passed to CallSynchronizedRoutine has completed.


IInterruptSync::Connect

The Connect method initializes the synchronization object.

NTSTATUS
  Connect(
    void
    )

Parameters

None

Return Value

Connect returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comment

The Connect method connects the synchronization object to the interrupt. This interrupt is specified in the ResourceList and ResourceIndex parameters that are passed to the PcNewInterruptSync call that creates the synchronization object.

See Also

PcNewInterruptSync


IInterruptSync::Disconnect

The Disconnect method disconnects the synchronization object from the interrupt.

void
  Disconnect(
    void
    )

Parameters

None

Return Value

None

Headers

Declared in portcls.h. Include portcls.h.


IInterruptSync::GetKInterrupt

The GetKInterrupt method gets a WDM interrupt object from a port-class synchronization object.

PKINTERRUPT
  GetKInterrupt(
    void
    )

Parameters

None

Return Value

GetKInterrupt returns a pointer to a the WDM interrupt object.

Headers

Declared in portcls.h. Include portcls.h.

Comments

A PKINTERRUPT pointer is one of the two parameters that are passed to every interrupt service routine. Every IInterruptSync object has an associated PKINTERRUPT pointer. It points to the associated kernel interrupt object, which is opaque.

A driver typically calls GetKInterrupt only if it needs to obtain this pointer so that it can call KeSynchronizeExecution directly.

See Also

KeSynchronizeExecution


IInterruptSync::RegisterServiceRoutine

The RegisterServiceRoutine method registers the routine to be called when an interrupt occurs.

NTSTATUS
  RegisterServiceRoutine(
    IN PINTERRUPTSYNCROUTINE  Routine,
    IN PVOID  DynamicContext,
    IN BOOLEAN  First
    );

Parameters

Routine
Pointer to routine to be called.
DynamicContext
Context value that is supplied to the routine when it is called.
First
If TRUE, the routine is added at the head of the list. If FALSE, the routine is added to the tail of the list. When an interrupt occurs, the routine at the head of the list is called first, and the routine at the tail is called last.

Return Value

RegisterServiceRoutine returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.


IRegistryKey

The IRegistryKey interface provides an abstraction of a registry key that a miniport driver can use to access the key and the subkeys under the key. IRegistryKey inherits from the IUnknown interface.

The miniport obtains a reference to an IRegistryKey object by calling PcNewRegistryKey or IPort::NewRegistryKey.

When querying an IRegistryKey object for information about a registry entry under the specified key, the query can output the information in one of three formats, each of which uses a different key-query structure. The table below shows the KEY_INFORMATION_CLASS enumeration values that indicate which of the three key-query structures is output by the query.

KEY_INFORMATION_CLASS value | Key-query structure
KeyBasicInformation | KEY_BASIC_INFORMATION
KeyFullInformation | KEY_FULL_INFORMATION
KeyNodeInformation | KEY_NODE_INFORMATION

The following methods are available through the IRegistryKey interface:

IRegistryKey::DeleteKey

IRegistryKey::EnumerateKey

IRegistryKey::EnumerateValueKey

IRegistryKey::NewSubKey

IRegistryKey::QueryKey

IRegistryKey::QueryRegistryValues

IRegistryKey::QueryValueKey

IRegistryKey::SetValueKey


IRegistryKey::DeleteKey

The DeleteKey method deletes the registry key. Callers of DeleteKey should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  DeleteKey(
    void
    );

Parameters

None

Return Value

DeleteKey returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

See Also

ZwDeleteKey


IRegistryKey::EnumerateKey

The EnumerateKey method returns information about the subkeys of the open key. Callers of EnumerateKey should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  EnumerateKey(
    IN ULONG  Index,
    IN KEY_INFORMATION_CLASS  KeyInformationClass,
    OUT PVOID  KeyInformation,
    IN ULONG  Length,
    OUT PULONG  ResultLength
    );

Parameters

Index
Specifies the zero-based index of the subkey for which the information is requested.
KeyInformationClass
Specifies the type of information to be returned in the buffer as one of the following: KeyBasicInformation, KeyFullInformation, KeyNodeInformation.
KeyInformation
Points to a caller-allocated buffer to receive the requested data. The buffer contains a structure of type KEY_BASIC_INFORMATION, KEY_FULL_INFORMATION, or KEY_NODE_INFORMATION, depending on the value of KeyInformationClass.
Length
Size in bytes of the KeyInformation buffer, which the caller should set according to the given KeyInformationClass.
ResultLength
Points to the number of bytes actually returned to KeyInformation or, if the input length is too small, points to the number of bytes required for the available information.

Return Value

EnumerateKey returns STATUS_SUCCESS if the call was successful in retrieving the requested information in the KeyInformation buffer. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error Status | Description
STATUS_BUFFER_OVERFLOW | Indicates that the specified buffer length is too small.
STATUS_NO_MORE_ENTRIES | Indicates that no more subkeys are available (subkey index is larger than or equal to the number of subkeys).

Headers

Declared in portcls.h. Include portcls.h.

See Also

KEY_BASIC_INFORMATION, KEY_FULL_INFORMATION, KEY_NODE_INFORMATION, ZwEnumerateKey


IRegistryKey::EnumerateValueKey

The EnumerateValueKey method returns information about a registry entry that contains a value key. Callers of EnumerateKeyValue should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  EnumerateKeyValue(
    IN ULONG  Index,
    IN KEY_VALUE_INFORMATION_CLASS  KeyValueInformationClass,
    OUT PVOID  KeyValueInformation,
    IN ULONG  Length,
    OUT PULONG  ResultLength
    );

Parameters

Index
Specifies the zero-based index of the value key for which the information is requested.
KeyValueInformationClass
Specifies the type of information to be returned in the buffer as one of the following: KeyBasicInformation, KeyFullInformation, KeyNodeInformation.
KeyValueInformation
Points to a caller-allocated buffer to receive the requested data. The buffer holds a structure of type KEY_BASIC_INFORMATION, KEY_FULL_INFORMATION, or KEY_NODE_INFORMATION, depending on the value of KeyInformationClass.
Length
Size in bytes of the KeyValueInformationBuffer, which the caller should set according to the given KeyValueInformationClass.
ResultLength
Points to the number of bytes actually returned to KeyValueInformation or, if the input length is too small, points to the number of bytes required for the available information.

Return Value

EnumerateValueKey returns STATUS_SUCCESS if the call was successful in copying the requested information into the KeyValueInformation buffer. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error Status | Description
STATUS_BUFFER_OVERFLOW | Indicates that the specified buffer length is too small.
STATUS_INVALID_PARAMETER | Indicates that one of the parameters passed to the method is not valid.
STATUS_NO_MORE_ENTRIES | Indicates that no more value keys are available (the Index parameter is greater than or equal to the number of value keys).

Headers

Declared in portcls.h. Include portcls.h.

See Also

KEY_BASIC_INFORMATION, KEY_FULL_INFORMATION, KEY_NODE_INFORMATION, ZwEnumerateValueKey


IRegistryKey::NewSubKey

The NewSubKey method opens a subkey under the open key and creates an IRegistryKey object to represent the subkey if this object does not already exist. Callers of NewSubKey should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  NewSubKey(
    OUT PREGISTRYKEY  *RegistrySubKey,
    IN PUNKNOWN  OuterUnknown,
    IN ACCESS_MASK  DesiredAccess,
    IN PUNICODE_STRING  SubKeyName,
    IN ULONG  CreateOptions,
    OUT PULONG  Disposition  OPTIONAL
    );

Parameters

RegistrySubKey
Pointer to a location to which the method outputs the pointer to the IRegistryKey interface for the specified subkey.
OuterUnknown
Pointer to the IUnknown interface of an object that needs to aggregate the registry key object. If aggregation is not required, specify this parameter as NULL.
DesiredAccess
Specifies the type of access that the caller requires to the subkey that is being opened or created. These values that can be specified for this parameter are the same as those for the PcNewRegistryKey call's DesiredAccess parameter.
SubKeyName
Points to the name of the desired subkey.
CreateOptions
Specifies options to be applied when creating a new key, as a compatible combination of the following: REG_OPTION_VOLATILE, REG_OPTION_NON_VOLATILE, REG_OPTION_CREATE_LINK, and REG_OPTION_BACKUP_RESTORE. These are the same values that can be specified for the PcNewRegistryKey call's CreateOptions parameter.
Disposition
Points to the variable to which the method is to output the value that indicates whether a new subkey was created or an existing subkey was opened: REG_CREATED_NEW_KEY and REG_OPENED_EXISTING_KEY. These are the same values that can be specified for the PcNewRegistryKey call's Disposition parameter.

Return Value

NewSubKey returns STATUS_SUCCESS if the call was successful in outputting a valid PREGISTRYKEY value to the RegistrySubKey parameter. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Also See

PcNewRegistryKey


IRegistryKey::QueryKey

The QueryKey method provides data about the class of a key, and the number and sizes of its subkeys. The callers of QueryKey should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  QueryKey(
    IN KEY_INFORMATION_CLASS  KeyInformationClass,
    OUT PVOID  KeyInformation,
    IN ULONG  Length,
    OUT PULONG  ResultLength
    );

Parameters

KeyInformationClass
Specifies the type of information to be returned in the buffer as one of the following: KeyBasicInformation, KeyFullInformation, KeyNodeInformation.
KeyInformation
Points to a caller-allocated buffer to receive the requested data. The buffer holds a structure of type KEY_BASIC_INFORMATION, KEY_FULL_INFORMATION, or KEY_NODE_INFORMATION, depending on the value of KeyInformationClass.
Length
Size in bytes of the KeyInformation buffer, which the caller should set according to the given KeyInformationClass.
ResultLength
Points to the number of bytes actually returned to KeyInformation or, if the input length is too small, points to the number of bytes required for the available information.

Return Value

QueryKey returns STATUS_SUCCESS if the call was successful in copying the requested information to the KeyInformation buffer. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error Status | Description
STATUS_BUFFER_OVERFLOW | Indicates that the specified buffer length is too small.
STATUS_INVALID_PARAMETER | Indicates that one of the parameters passed to the method is not valid.

Headers

Declared in portcls.h. Include portcls.h.

See Also

KEY_BASIC_INFORMATION, KEY_FULL_INFORMATION, KEY_NODE_INFORMATION, ZwQueryKey


IRegistryKey::QueryRegistryValues

The QueryRegistryValues method allows the caller to query several values from the registry with a single call. The caller of QueryRegistryValues should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  QueryRegistryValues(
    IN PRTL_QUERY_REGISTRY_TABLE  QueryTable,
    IN PVOID  Context  OPTIONAL
    );

Parameters

QueryTable
Points to an array of one or more RTL_QUERY_REGISTRY_TABLE structures (see definition in comments below). Each structure specifies the value name and subkey name for a registry entry that the caller is querying. Each structure also contains a function pointer to a caller-supplied QueryRoutine callback that the QueryRegistryValues method will call with information about the corresponding registry entry. The array should be terminated by a structure with a NULL Name member.
Context
This is an arbitrary PVOID pointer value that the QueryRegistryValues method passes as a call parameter to each of the QueryRoutine callbacks. This is typically a pointer to a caller-defined structure that contains context data that the caller's QueryRoutine accesses. The meaning of this value is known only to the caller. The QueryRegistryValues method performs no validation of the pointer.

Return Value

QueryRegistryValues returns STATUS_SUCCESS if the call was successful in processing the entire QueryTable. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error Status | Description
STATUS_INVALID_PARAMETER | Indicates that the QueryTable parameter that was passed to the method is not valid.
STATUS_OBJECT_NAME_NOT_FOUND | Indicates that the method was unable to find the object that was specified in one of the QueryTable entries.

If the user-supplied QueryRoutine function returns an error code, the QueryRegistryValues method will immediately return with that same error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

This method uses caller-supplied callback routines to successively enumerate the values of a list of registry entries. If successful, the method returns after calling all the callback routines in the list.

The structure that is pointed to by the QueryTable parameter is defined as follows:

typedef struct _RTL_QUERY_REGISTRY_TABLE
{
    PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine;
    ULONG   Flags;
    PWSTR   Name;
    PVOID   EntryContext;
    ULONG   DefaultType;
    PVOID   DefaultData;
    ULONG   DefaultLength;
} RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE;

The QueryRoutine member above is a function pointer to a caller-supplied callback routine. For additional information about the RTL_QUERY_REGISTRY_TABLE structure, see the description of the RtlQueryRegistryValues routine.

Also See

RtlQueryRegistryValues


IRegistryKey::QueryValueKey

The QueryValueKey method returns value key entries. Callers of QueryValueKey should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  QueryValueKey(
    IN PUNICODE_STRING  ValueName,
    IN KEY_VALUEINFORMATION_CLASS  KeyValueInformationClass,
    OUT PVOID  KeyValueInformation,
    IN ULONG  Length,
    OUT PULONG  ResultLength
    );

Parameters

ValueName
Value entry provided by the manufacturer.
KeyValueInformationClass
Specifies the type of information to be returned in the buffer as one of the following: KeyValueBasicInformation, KeyValueFullInformation, KeyValueNodeInformation.
KeyValueInformation
Points to a caller-allocated buffer to receive the requested data.
Length
Size in bytes of the KeyValueInformation buffer, which the caller should set according to the given KeyValueInformationClass.
ResultLength
Points to the number of bytes actually returned to KeyValueInformation or, if the input length is too small, points to the number of bytes required for the available information.

Return Value

QueryValueKey will return STATUS_SUCCESS if the call succeeds in copying the requested information is returned to the KeyValueInformation buffer. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error Status | Description
STATUS_BUFFER_OVERFLOW | Indicates that the specified buffer length is too small.
STATUS_INVALID_PARAMETER | Indicates that one of the parameters passed to the method is not valid.
STATUS_OBJ_NAME_NOT_FOUND | Indicates that the value entry with the specified name was not found.

Headers

Declared in portcls.h. Include portcls.h.

See Also

ZwQueryValueKey


IRegistryKey::SetValueKey

The SetValueKey method replaces or creates a value entry under the open key. Caller of SetValueKey should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  SetValueKey(
    IN PUNICODE_STRING  ValueName  OPTIONAL,
    IN ULONG  Type,
    IN PVOID  Data,
    IN ULONG  DataSize
    );

Parameters

ValueName
Points to the name of the value entry for which the data is to be written. This parameter can be a NULL pointer if the value entry has no name. If a name string is specified and the given name is not unique relative to its containing key, the data for an existing value entry is replaced.
Type
Specifies the type of the data to be written for ValueName. System-defined types include:

REG_BINARY

REG_DWORD

REG_DWORD_LITTLE_ENDIAN

REG_DWORD_BIG_ENDIAN

REG_EXPAND_SZ

REG_LINK

REG_MULTI_SZ

REG_NONE

REG_SZ

REG_RESOURCE_LIST

REG_RESOURCE_REQUIREMENTS_LIST

REG_FULL_RESOURCE_DESCRIPTOR

These parameter types are explained in ZwSetValueKey.

Data
User-supplied structure or value appropriate to the function.
DataSize
Size in bytes of Data.

Return Value

SetValueKey returns STATUS_SUCCESS if the call was successful in setting the specified value key. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error Status | Description
STATUS_INVALID_PARAMETER | Indicates that one of the parameters passed to the method is not valid.
STATUS_OBJECT_NAME_NOT_FOUND | Indicates that method was unable to find the named value key.

Headers

Declared in portcls.h. Include portcls.h.

See Also

ZwSetValueKey


IResourceList

The IResourceList interface provides an abstraction of a configuration resource list, which is a list of the system hardware resources that the PnP Manager assigns to a device at startup time (see Starting a Device in a Function Driver). These resources can include:

  • Interrupt vectors
  • DMA channels
  • I/O port addresses
  • Blocks of bus-relative memory addresses

The IResourceList object encapsulates both the translated and untranslated (or raw) resource lists, which are described in Mapping Bus-Relative Addresses to Virtual Addresses. When the port driver calls an adapter driver's StartDevice function (see Startup Sequence) or a miniport's Init method (see IMiniportWavePci::Init, for example), it passes in an IResourceList object as one of the call parameters.

IResourceList inherits from the IUnknown interface.

The IResourceList interface supports the following methods:

IResourceList::AddEntry

IResourceList::AddEntryFromParent

IResourceList::FindTranslatedEntry

IResourceList::FindUntranslatedEntry

IResourceList::NumberOfEntries

IResourceList::NumberOfEntriesOfType

IResourceList::TranslatedList

IResourceList::UntranslatedList

The header file portcls.h defines set of macros to simplify the handling of resource-list objects. For each type of resource, the following four macros are defined:

ULONG
  NumberOfpluralresourcename(
    void
    );

PCM_PARTIAL_RESOURCE_DESCRIPTOR
  FindTranslatedsingularresourcename(
    ULONG  Index
    );

PCM_PARTIAL_RESOURCE_DESCRIPTOR
  FindUntranslatedsingularresourcename(
    ULONG  Index
    );

NTSTATUS
  AddsingularresourcenameFromParent(
    PRESOURCELIST  Parent,
    ULONG  Index
    );

The following table shows the resource types for which these macros are defined.

Resource Type Name | Singular Form | Plural Form
CmResourceTypePort | Port | Ports
CmResourceTypeInterrupt | Interrupt | Interrupts
CmResourceTypeMemory | Memory | Memories
CmResourceTypeDma | Dma | Dmas
CmResourceTypeDeviceSpecific | DeviceSpecific | DeviceSpecifics
CmResourceTypeBusNumber | BusNumber | BusNumbers
CmResourceTypePrivate | Private | Privates
CmResourceTypeAssignedResource | AssignedResource | AssignedResources
CmResourceTypeSubAllocateFrom | SubAllocateFrom | SubAllocateFroms

For the meanings of the resource-type names in the left column above, see CM_PARTIAL_RESOURCE_DESCRIPTOR.

The following table explicitly lists the four macros that portcls.h defines for each of the nine resource types. To the right of each macro is the equivalent call to a IResourceList method.

Macro | Equivalent IResourceList Call
NumberOfPorts() | NumberOfEntriesOfType(CmResourceTypePort)
FindTranslatedPort(n) | FindTranslatedEntry(CmResourceTypePort,(n))
FindUntranslatedPort(n) | FindUntranslatedEntry(CmResourceTypePort,(n))
AddPortFromParent(p,n) | AddEntryFromParent((p),CmResourceTypePort,(n))
NumberOfInterrupts() | NumberOfEntriesOfType(CmResourceTypeInterrupt)
FindTranslatedInterrupt(n) | FindTranslatedEntry(CmResourceTypeInterrupt,(n))
FindUntranslatedInterrupt(n) | FindUntranslatedEntry(CmResourceTypeInterrupt,(n))
AddInterruptFromParent(p,n) | AddEntryFromParent((p),CmResourceTypeInterrupt,(n))
NumberOfMemories() | NumberOfEntriesOfType(CmResourceTypeMemory)
FindTranslatedMemory(n) | FindTranslatedEntry(CmResourceTypeMemory,(n))
FindUntranslatedMemory(n) | FindUntranslatedEntry(CmResourceTypeMemory,(n))
AddMemoryFromParent(p,n) | AddEntryFromParent((p),CmResourceTypeMemory,(n))
NumberOfDmas() | NumberOfEntriesOfType(CmResourceTypeDma)
FindTranslatedDma(n) | FindTranslatedEntry(CmResourceTypeDma,(n))
FindUntranslatedDma(n) | FindUntranslatedEntry(CmResourceTypeDma,(n))
AddDmaFromParent(p,n) | AddEntryFromParent((p),CmResourceTypeDma,(n))
NumberOfDeviceSpecifics() | NumberOfEntriesOfType(CmResourceTypeDeviceSpecific)
FindTranslatedDeviceSpecific(n) | FindTranslatedEntry(CmResourceTypeDeviceSpecific,(n))
FindUntranslatedDeviceSpecific(n) | FindUntranslatedEntry(CmResourceTypeDeviceSpecific,(n))
AddDeviceSpecificFromParent(p,n) | AddEntryFromParent((p),CmResourceTypeDeviceSpecific,(n))
NumberOfBusNumbers() | NumberOfEntriesOfType(CmResourceTypeBusNumber)
FindTranslatedBusNumber(n) | FindTranslatedEntry(CmResourceTypeBusNumber,(n))
FindUntranslatedBusNumber(n) | FindUntranslatedEntry(CmResourceTypeBusNumber,(n))
AddBusNumberFromParent(p,n) | AddEntryFromParent((p),CmResourceTypeBusNumber,(n))
NumberOfDevicePrivates() | NumberOfEntriesOfType(CmResourceTypeDevicePrivate)
FindTranslatedDevicePrivate(n) | FindTranslatedEntry(CmResourceTypeDevicePrivate,(n))
FindUntranslatedDevicePrivate(n) | FindUntranslatedEntry(CmResourceTypeDevicePrivate,(n))
AddDevicePrivateFromParent(p,n) | AddEntryFromParent((p),CmResourceTypeDevicePrivate,(n))
NumberOfAssignedResources() | NumberOfEntriesOfType(CmResourceTypeAssignedResource)
FindTranslatedAssignedResource(n) | FindTranslatedEntry(CmResourceTypeAssignedResource,(n))
FindUntranslatedAssignedResource(n) | FindUntranslatedEntry(CmResourceTypeAssignedResource,(n))
AddAssignedResourceFromParent(p,n) | AddEntryFromParent((p),CmResourceTypeAssignedResource,(n))
NumberOfSubAllocateFroms() | NumberOfEntriesOfType(CmResourceTypeSubAllocateFrom)
FindTranslatedSubAllocateFrom(n) | FindTranslatedEntry(CmResourceTypeSubAllocateFrom,(n))
FindUntranslatedSubAllocateFrom(n) | FindUntranslatedEntry(CmResourceTypeSubAllocateFrom,(n))
AddSubAllocateFromFromParent(p,n) | AddEntryFromParent((p),CmResourceTypeSubAllocateFrom,(n))


IResourceList::AddEntry

The AddEntry method adds an entry to a resource list. Callers of AddEntry should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  AddEntry(
    PCM_PARTIAL_RESOURCE_DESCRIPTOR  Translated,
    PCM_PARTIAL_RESOURCE_DESCRIPTOR  Untranslated
    );

Parameters

Translated
Translated version of the entry to be added.
Untranslated
Untranslated version of the entry to be added.

Return Value

AddEntry returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error Status | Description
STATUS_INSUFFICIENT_RESOURCES | Indicates there are no free entries in the list.

Headers

Declared in portcls.h. Include portcls.h.

See Also

CM_PARTIAL_RESOURCE_DESCRIPTOR


IResourceList::AddEntryFromParent

The AddEntryFromParent method adds to a resource list an entry found in the resource list's parent list. For each resource type, a macro is defined to call this method, as previously described. Callers of AddEntryFromParent should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  AddEntryFromParent(
    IN PRESOURCELIST  Parent,
    IN CM_RESOURCE_TYPE  Type,
    IN ULONG  Index
    );

Parameters

Parent
Pointer to parent IResourceList object from which the entry is to be taken.
Type
Identifies the resource type of the entry that is to be added. For a list of valid values, see the Type member of the CM_PARTIAL_RESOURCE_DESCRIPTOR structure.
Index
Index in the parent list of the entry to add. A value of zero for this parameter will cause the method to add the first occurrence of an entry of the specified type.

Return Value

AddEntryFromParent returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error Status | Description
STATUS_INSUFFICIENT_RESOURCES | Indicates there are no free entries in the list.
STATUS_INVALID_PARAMETER | Indicates the entry was not found in the parent list.

Headers

Declared in portcls.h. Include portcls.h.

See Also

CM_PARTIAL_RESOURCE_DESCRIPTOR


IResourceList::FindTranslatedEntry

The FindTranslatedEntry method returns a pointer to a translated entry of the specified type, or NULL if no such entry is found. The Index parameter indicates which occurrence of that type of entry to find. The first occurrence has an index of zero. Callers of FindTranslatedEntry should run in IRQL PASSIVE_LEVEL.

PCM_PARTIAL_RESOURCE_DESCRIPTOR
  FindTranslatedEntry(
    IN CM_RESOURCE_TYPE  Type,
    IN ULONG  Index
    );

Parameters

Type
Identifies the resource type of the entry to find. For a list of valid values, see the Type member of the CM_PARTIAL_RESOURCE_DESCRIPTOR structure.
Index
Index of the entry to find. A value of zero for this parameter will cause the method to return a pointer to the first occurrence of an entry of the specified type.

Return Value

FindTranslatedEntry returns a pointer to the specified entry or is NULL if the entry does not exist. This pointer remains valid until the resource-list object is deleted.

Headers

Declared in portcls.h. Include portcls.h.

Also See

CM_PARTIAL_RESOURCE_DESCRIPTOR


IResourceList::FindUntranslatedEntry

The FindUntranslatedEntry method returns a pointer to an untranslated entry of the specified type, or NULL if no such pointer is found. The Index parameter indicates which occurrences of that type entry to find. The first occurrence has an index of zero. For each resource type, a macro is defined to call this method as previously described. Callers of FindUntranslatedEntry should run at IRQL PASSIVE_LEVEL.

PCM_PARTIAL_RESOURCE_DESCRIPTOR
  FindUntranslatedEntry(
    IN CM_RESOURCE_TYPE  Type,
    IN ULONG  Index
    );

Parameters

Type
Identifies the resource type of the entries that are to be counted. For a list of valid values, see the Type member of the CM_PARTIAL_RESOURCE_DESCRIPTOR structure.
Index
Index of the entry to find. A value of zero for this parameter will cause the method to return a pointer to the first occurrence of an entry of the specified type.

Return Value

FindUntranslatedEntry returns a pointer to the specified entry or is NULL if the entry does not exist. This pointer remains valid until the resource object is deleted.

Headers

Declared in portcls.h. Include portcls.h.

Also See

CM_PARTIAL_RESOURCE_DESCRIPTOR


IResourceList::NumberOfEntries

The NumberOfEntries method returns the number of resource items in the resource list. Callers of NumberOfEntries should run at IRQL PASSIVE_LEVEL.

ULONG
  NumberOfEntries(
    void
    );

Parameters

None

Return Value

NumberOfEntries returns the number of items in the resource list.

Headers

Declared in portcls.h. Include portcls.h.


IResourceList::NumberOfEntriesOfType

The NumberOfEntriesOfType method returns the number of resource items of a given type in the resource list. For each resource type, a macro is defined to call this method as previously described. Callers of NumberOfEntriesOfType should run at IRQL PASSIVE_LEVEL.

ULONG
  NumberOfEntriesOfType(
    IN CM_RESOURCE_TYPE  Type
    );

Parameters

Type
Identifies the resource type of the entries that are to be counted. For a list of valid values, see the Type member of the CM_PARTIAL_RESOURCE_DESCRIPTOR structure.

Return Value

NumberOfEntriesOfType returns the number of items of the indicated type in the resource list.

Headers

Declared in portcls.h. Include portcls.h.

Also See

CM_PARTIAL_RESOURCE_DESCRIPTOR


IResourceList::TranslatedList

The TranslatedList method returns the list of translated resources. Callers of TranslatedList should run at IRQL PASSIVE_LEVEL.

PCM_RESOURCE_LIST
  TranslatedList(
    void
    );

Parameters

None

Return Value

TranslatedList returns a pointer to a CM_RESOURCE_LIST structure that specifies all of the system hardware resources that are assigned to the device. This pointer remains valid until the resource-list object is deleted.

Headers

Declared in portcls.h. Include portcls.h.

See Also

CM_RESOURCE_LIST


IResourceList::UntranslatedList

The UntranslatedList method returns the list of untranslated resources. Callers of UntranslatedList should run at IRQL PASSIVE_LEVEL.

PCM_RESOURCE_LIST
  UntranslatedList(
    void
    );

Parameters

None

Return Value

UntranslatedList returns a pointer to a CM_RESOURCE_LIST structure that specifies all of the system hardware resources that are assigned to the device. The resources in the list are in untranslated form. This pointer remains valid until the resource-list object is deleted.

Headers

Declared in portcls.h. Include portcls.h.

See Also

CM_RESOURCE_LIST


IServiceGroup

The IServiceGroup interface encapsulates a group of objects that all require notification of the same service request. When the service-group object receives notification of the request, it forwards the notification to each of the objects in the group. IServiceGroup inherits from the IServiceSink interface.

A miniport creates an IServiceGroup object by calling PcNewServiceGroup.

Service-group objects exposing an IServiceGroup interface are typically used to demultiplex requests for interrupt service, although the functionality of a service group is general enough to make it potentially useful for other purposes as well. The miniport's ISR (interrupt-service routine) calls a notification method in the lower-edge interface of the port; the notification method takes a pointer to the service group as a call parameter. During this call, the port calls RequestService (see IServiceSink::RequestService) on the service group and queues a DPC (deferred procedure call). When the DPC executes, it forwards the service request to all member objects in the service group.

The miniport code typically does not need to call any IServiceGroup interface methods. Instead, the port calls these methods to add its own IServiceSink objects to the service groups that it obtains from the miniport. Miniports create service-group objects as required and associate those service groups with objects that will require service. For example, a WaveCyclic miniport associates a stream object with the service group that it specifies as an output parameter to the IMiniportWaveCyclic::NewStream method.

In the context of WaveCyclic miniports, associating all streams with one service group causes the port to service all streams based on a single notification. Associating each stream with its own service group allows the interrupt-service routine to select the stream that will be serviced by the port during the execution of the DPC.

A miniport's ISR calls one of the following port methods to notify a service group of a service request:

IPortDMus::Notify

IPortMidi::Notify

IPortWaveCyclic::Notify

IPortWavePci::Notify

A miniport outputs a reference to its service group when the port calls one of the following initialization methods:

IMiniportDMus::Init

IMiniportMidi::Init

IMiniportWavePci::Init

The port adds its own IServiceSink object to the service group that it obtains from the Init call. When the miniport's ISR later calls Notify to send notification to that service group, the service group queues a DPC that forwards notification to the port's IServiceSink object, which in turn forwards notification to the miniport by calling one of the following service methods:

IMiniportDMus::Service (not used)

IMiniportMidi::Service

IMiniportWavePci::Service

A miniport also outputs a reference to its service group when the port calls one of the following stream-creation methods:

IMiniportDMus::NewStream

IMiniportMidi::NewStream

IMiniportWaveCyclic::NewStream

IMiniportWavePci::NewStream

As discussed above, the miniport has the option of creating a different service group for each stream or sharing a single service group across all streams.

In the case of a WavePci port, the port object adds its own IServiceSink object to the service group that it obtains from the IMiniportWavePci::NewStream call. When the miniport's ISR later calls Notify to send notification to that service group, the service group queues a DPC that forwards the notification to the port's IServiceSink object, which in turn does the following:

  • Forwards notification to the miniport stream by calling the service method IMiniportWavePciStream::Service.
  • Triggers any position and/or clock events on the pin that are ready to fire.

In addition to the RequestService method in the IServiceSink base interface from which it is derived, the IServiceGroup interface supports the following five methods:

IServiceGroup::AddMember

IServiceGroup::CancelDelayedService

IServiceGroup::RequestDelayedService

IServiceGroup::RemoveMember

IServiceGroup::SupportDelayedService


IServiceGroup::AddMember

The AddMember method adds a member to the service group.

NTSTATUS
  AddMember(
    IN PSERVICESINK  pServiceSink
    );

Parameters

pServiceSink
Pointer to the IServiceSink interface of the new member of the service group.

Return Value

AddMember returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Also See

IServiceSink


IServiceGroup::CancelDelayedService

The CancelDelayedService method cancels the previously requested delayed service.

VOID
  CancelDelayedService(
    void
    );

Parameters

None

Return Value

None

Headers

Declared in portcls.h. Include portcls.h.


IServiceGroup::RequestDelayedService

The RequestDelayedService method requests service after the specified delay.

VOID
  RequestDelayedService(
    IN ULONGLONG  ulDelay;
    );

Parameters

ulDelay
Specifies the absolute or relative time at which the timer is to expire. If the value of ulDelay is negative, the expiration time is relative to the current system time. Otherwise, the expiration time is absolute. The expiration time is expressed in system time units (100-nanosecond intervals). Absolute expiration times track any changes in the system time; relative expiration times are not affected by system time changes.

Return Value

None

Headers

Declared in portcls.h. Include portcls.h.

Comments

Before calling RequestDelayedService to request a timer delay, initialize the timer by calling IServiceGroup::SupportDelayedService.

See Also

IServiceGroup::SupportDelayedService


IServiceGroup::RemoveMember

The RemoveMember method removes the specified member from the service group.

VOID
  RemoveMember(
    IN PSERVICESINK  pServiceSink
    );

Parameters

pServiceSink
Pointer to the IServiceSink interface of the member that is to be removed.

Return Value

None

Headers

Declared in portcls.h. Include portcls.h.

See Also

IServiceSink


IServiceGroup::SupportDelayedService

The SupportDelayedService method indicates that the service group should prepare to support delayed service.

VOID
  SupportDelayedService(
    void
    );

Parameters

None

Return Value

None

Headers

Declared in portcls.h. Include portcls.h.

Comments

The SupportDelayedService method initializes the notification timer that is used for delayed service. Call this method once before making any calls to IServiceGroup::RequestDelayedService.

See Also

IServiceGroup::RequestDelayedService


IServiceSink

The IServiceSink interface encapsulates handling of a service request. The source of the service request is typically the miniport's interrupt-service routine. An IServiceSink object is typically a member of a service group that is managed by an IServiceGroup object. IServiceSink inherits from the IUnknown interface.

IServiceSink is the base interface for IServiceGroup. This allows an IServiceGroup object to add itself (as an object with an IServiceSink interface) to another IServiceGroup object's service group.

The cost of adding an IServiceSink interface to other types of objects is small because the interface supports only a single method.

The IServiceSink interface supports the following method:

IServiceSink::RequestService


IServiceSink::RequestService

The RequestService method is called to forward a service request to an IServiceSink object. Callers of RequestService run at IRQL DISPATCH_LEVEL.

VOID
  RequestService(
    void
    );

Parameters

None

Return Value

None

Headers

Declared in portcls.h. Include portcls.h.


Audio Port Object Interfaces

This section includes the following topics:

IDrmPort

IPort

IPortClsVersion

IPortEvents

IPortMidi

IPortTopology

IPortWaveCyclic

IPortWavePci

IPortWavePciStream


IDrmPort

The IDrmPort interface provides several methods that can help your driver keep track of composite rights. This interface is supported by the WaveCyclic and WavePci port drivers. IDrmPort inherits from IUnknown.

To obtain a reference to a port driver's IDrmPort object, a miniport calls QueryInterface on its associated IPortWaveCyclic or IPortWavePci object and specifies REFIID IID_IDrmPort.

The interface supports the following methods:

IDrmPort::CreateContentMixed

IDrmPort::DestroyContent

IDrmPort::ForwardContentToFileObject

IDrmPort::ForwardContentToInterface

IDrmPort::GetContentRights


IDrmPort::CreateContentMixed

The CreateContentMixed method computes the DRM content rights for a composition of KS audio streams, and creates a DRM content ID that represents the composite audio stream.

NTSTATUS
  CreateContentMixed(
    IN PULONG  paContentId,
    IN ULONG  cContentId,
    OUT PULONG  pMixedContentId
    );

Parameters

paContentId
Pointer to an array of DRM content IDs. Each content ID represents a KS audio stream. If cContentID is zero, paContentID can be NULL. A content ID of zero is a special value that represents an audio stream with default content rights (see DEFINE_DRMRIGHTS_DEFAULT).
cContentId
Specifies the number of DRM content IDs in the paContentId array. The array can hold zero or more content IDs.
pMixedContentId
Pointer to a variable that receives the new DRM content ID that is assigned to the composite KS audio stream. If cContentID is zero, the new content ID is assigned default DRM content rights.

Return Value

CreateContentMixed returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

CreateContentMixed is similar in function to DrmCreateContentMixed and PcCreateContentMixed.

See discussion of composite content rights in Content IDs and Content Rights.

See Also

DEFINE_DRMRIGHTS_DEFAULT, DrmCreateContentMixed, PcCreateContentMixed


IDrmPort::DestroyContent

The DestroyContent method deletes a specified DRM content ID that was created by IDrmPort::CreateContentMixed.

NTSTATUS
  DestroyContent(
    IN ULONG  ContentId
    );

Parameters

ContentId
Specifies a nonzero DRM content ID that is assigned to a KS audio stream by CreateContentMixed. Note that a content ID of zero represents an audio stream with default DRM content rights and cannot be used with this routine.

Return Value

DestroyContent returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

DestroyContent is similar in function to DrmDestroyContent and PcDestroyContent.

See Also

IDrmPort::CreateContentMixed, DrmDestroyContent, PcDestroyContent.


IDrmPort::ForwardContentToFileObject

The ForwardContentToFileObject method forwards a specified DRM content ID to a KS audio pin represented by a file object.

NTSTATUS
  ForwardContentToFileObject(
    IN ULONG  ContentId,
    IN PFILE_OBJECT  FileObject
    );

Parameters

ContentId
Specifies a DRM content ID assigned to a KS audio stream.
FileObject
Pointer to a file object that represents the KS audio pin to which the KS audio stream is sent.

Return Value

ForwardContentToFileObject returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

ForwardContentToFileObject is similar in function to DrmForwardContentToFileObject and PcForwardContentToFileObject.

See Also

DrmForwardContentToFileObject, PcForwardContentToFileObject


IDrmPort::ForwardContentToInterface

The ForwardContentToInterface method forwards a specified DRM content ID to a KS audio filter that receives a KS audio stream through a COM interface.

NTSTATUS
  ForwardContentToInterface(
    ULONG  ContentId,
    PUNKNOWN  pUnknown,
    ULONG  NumMethods);

Parameters

ContentId
Specifies a DRM content ID assigned to a KS audio stream.
pUnknown
Pointer to an IUnknown interface that directly receives KS audio stream data for a KS audio filter.
NumMethods
Specifies the total number of methods in the COM interface that is pointed to by pUnknown, including all the methods in its base interfaces.

Return Value

ForwardContentToInterface returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

ForwardContentToInterface does the same function as DrmForwardContentToInterface and PcForwardContentToInterface.

See Also

DrmForwardContentToInterface, PcForwardContentToInterface


IDrmPort::GetContentRights

The GetContentRights method returns the DRM content rights assigned to a specified DRM content ID.

NTSTATUS
  PcGetContentRights(
    IN ULONG  ContentId,
    OUT PDRMRIGHTS  DrmRights
    );

Parameters

ContentId
Specifies a DRM content ID.
DrmRights
Pointer to a DRMRIGHTS structure that specifies the DRM content rights assigned to ContentId.

Return Value

GetContentRights returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

GetContentRights is similar in function to DrmGetContentRights and PcGetContentRights.

See Also

DRMRIGHTS, DrmGetContentRights, PcGetContentRights


IPort

The IPort interface is the generic interface for audio port drivers. All audio port drivers expose IPort as part of their lower edge. The adapter driver calls the initialization method on this interface. IPort inherits from the IUnknown interface.

The IPort interface provides a uniform means for initializing audio port drivers of all types. IPort is the base interface for the IPortDMus, IPortMidi, IPortTopology, IPortWaveCyclic, and IPortWavePci interfaces. Call PcNewPort to create a port object with one of these interfaces.

The IPort interface supports the following methods:

IPort::GetDeviceProperty

IPort::Init

IPort::NewRegistryKey


IPort::GetDeviceProperty

The GetDeviceProperty method provides simplified access to device properties that are contained in the registry for PnP devices. Callers of GetDeviceProperty should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  GetDeviceProperty(
    IN DEVICE_REGISTRY_PROPERTY  DeviceRegistryProperty,
    IN ULONG  BufferLength,
    OUT PVOID  PropertyBuffer,
    OUT PULONG  ReturnLength
    );

Parameters

DeviceRegistryProperty
Identifies the particular device property that the caller is requesting. The valid values for this parameter are the same as those that are defined for the IoGetDeviceProperty call's DeviceProperty parameter.
BufferLength
Length in bytes of the buffer that is to receive the requested information.
PropertyBuffer
Pointer to a caller-allocated buffer that is to receive the requested property information.
ReturnLength
Points to the number of bytes that are actually returned to PropertyBuffer or, if the input length is too small, points to the number of bytes that are required for the available information.

Return Value

GetDeviceProperty returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code. If the property buffer provided by the caller is too small, the method will return STATUS_BUFFER_TOO_SMALL and output the needed size in ReturnLength.

Headers

Declared in portcls.h. Include portcls.h.

See Also

IoGetDeviceProperty


IPort::Init

The Init method initializes the port driver. The miniport supplied by the third parameter should be the miniport interface that is supported by the port driver or the call will fail. The miniport is initialized by the port driver during this call. Callers of Init should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  Init(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp,
    IN PUNKNOWN  UnknownMiniport,
    IN PUNKNOWN  UnknownAdapter  OPTIONAL,
    IN PRESOURCELIST  ResourceList
    );

Parameters

DeviceObject
Pointer to the driver's device object, which was passed as an argument to the StartDevice call (described in Startup Sequence).
Irp
Pointer to the IRP that was passed as an argument to the StartDevice call.
UnknownMiniport
Pointer to the IUnknown interface of the uninitialized miniport. This interface is queried for the specific miniport interface supported by the port driver, and the initialization function on that interface is called.
UnknownAdapter
Pointer to the IUnknown interface of the adapter object. This pointer is optional and can be specified as NULL.
ResourceList
Pointer to the IResourceList object that was passed as an argument to the StartDevice call. After passing this reference to the miniport, the port driver is free to examine the contents of the resource list but will not modify the contents of the resource list.

Return Value

Init returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

See Also

IResourceList


IPort::NewRegistryKey

The NewRegistryKey method creates an IRegistryKey object and outputs a reference to this object to the caller. The IRegistryKey interface provides an adapter driver with access to a registry key. The NewRegistryKey method either opens an existing key or creates a new registry key. Callers of this method should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  NewRegistryKey(
    OUT PREGISTRYKEY  *OutRegistryKey,
    IN PUNKNOWN  OuterUnknown  OPTIONAL,
    IN ULONG  RegistryKeyType,
    IN ACCESS_MASK  DesiredAccess,
    IN POBJECT_ATTRIBUTES  ObjectAttributes  OPTIONAL,
    IN ULONG  CreateOptions  OPTIONAL,
    OUT PULONG  Disposition  OPTIONAL
    );

Parameters

OutRegistryKey
Pointer to a location to which the method outputs the pointer to the new IRegistryKey object.
OuterUnknown
Pointer to the IUnknown interface of an object that needs to aggregate the registry key object. If aggregation is not required, specify this parameter as NULL.
RegistryKeyType
Indicates to the method the type of registry access desired. In particular, this parameter should indicate one of the following.
Type of Registry | Description
GeneralRegistryKey | Provide generic access to any key type.
DeviceRegistryKey | Open a key for storing device-specific information.
DriverRegistryKey | Open a key for storing driver-specific information.
HwProfileRegistryKey | Open a key relative to the current hardware profile for device or driver information.
DeviceInterfaceRegistryKey | Open a registry key for storing information about a particular device interface.

DesiredAccess
Specifies the type of access that the caller requires to the key. The supported values for this parameter are the same as those that are specified for the ZwCreateKey call parameter with the same name.
ObjectAttributes
Points to the initialized object attributes of the key being opened. This parameter is required for GeneralRegistryKey accesses and not used for the others. The supported values for this parameter are the same as those that are specified for the ZwCreateKey call parameter with the same name.
CreateOptions
Flags indicating the create options. Can be zero if none are desired. The supported values for this parameter are the same as those that are specified for the ZwCreateKey call parameter with the same name.
Disposition
Points to a variable that receives a value indicating whether or not a key was created or an existing key was opened. The supported values for this parameter are the same as those that are specified for the ZwCreateKey call parameter with the same name.

Return Value

NewRegistryKey returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

The NewRegistryKey method is similar to the PcNewRegistryKey routine except that the device object and port must be explicitly specified in a PcNewRegistryKey call but are simply implied in a NewRegistryKey call.

See Also

IRegistryKey, PcNewRegistryKey, ZwCreateKey


IPortClsVersion

The IPortClsVersion interface is used by a miniport driver to identify the version of the Windows operating system that the driver is running on. IPortClsVersion inherits from the IUnknown interface.

The following Windows versions support the IPortClsVersion interface:

  • Windows 2000 SP2
  • Windows XP and later

To obtain a reference to the port's IPortClsVersion interface, the miniport calls QueryInterface on the port object and specifies REFIID IID_IPortClsVersion. The following port types support IPortClsVersion:

IPortWaveCyclic

IPortWavePci

IPortDMus

IPortMidi

IPortTopology

The IPortClsVersion interface supports the following method:

IPortClsVersion::GetVersion


IPortClsVersion::GetVersion

The GetVersion method returns the version of the Windows operating system that the driver is running on. The version information includes the Windows release as well as the installed QFE (quick-fix engineering) package for Windows 98/Me or service pack for Windows 2000 and later releases. Callers of this method should run at IRQL PASSIVE_LEVEL.

DWORD
  GetVersion(
    void
    );

Parameters

None

Return Value

The GetVersion method returns a DWORD value that specifies the Windows version number. See comments below.

Comments

The header file portcls.h defines the Windows version numbers that appear in the table below.

Version number | Windows version | Supports IPortClsVersion?
kVersionWin98 | Windows 98 | no
kVersionWin98SE | Windows 98 Second Edition | no
kVersionWin2K | Windows 2000 | no
kVersionWin98SE_QFE2 | Windows 98 SE + QFE Package 269601 (See Additional Requirements for Windows 98.) | no
kVersionWin2K_SP2 | Windows 2000 + Service Pack 2 | YES
kVersionWinME | Windows Me | no
kVersionWin98SE_QFE3 | Reserved for future use | YES
kVersionWinME_QFE1 | Reserved for future use | YES
kVersionWinXP | Windows XP | YES

Note that portcls.h defines version numbers for Windows versions that both do and do not support the IPortClsVersion interface. Both types of version number can be useful. A miniport driver typically contains a proprietary routine that determines the Windows version and can return any of the version numbers above. When executed on a platform that does not support IPortClsVersion, this routine needs to use other software tests to determine the Windows version. For a code example of such a routine, see the SB16 sample adapter driver in the Windows DDK.

The version numbers in the table above are listed in roughly chronological order. Each successive Windows version in the table does not necessarily represent a feature superset of the preceding version. For example, the version that is represented by kVersionWin2K has more audio features than the version that is represented by kVersionWin98SE_QFE2.

See Also

IoIsWdmVersionAvailable


IPortEvents

The IPortEvents interface is used by miniport drivers to notify clients of hardware events. Drivers typically use this interface to notify the system of hardware-generated volume or mute changes, although IPortEvents can be used for any type of event notification. IPortEvents interface is an optional lower-edge port driver interface. It can be used, for example, to notify mixer applications of control and/or line changes. (For information about the mixer API, see the Platform SDK documentation.) IPortEvents inherits from the IUnknown interface.

A miniport exposes an event in the same way that it exposes properties: through an automation table (see PCAUTOMATION_TABLE). The following objects, all of which are exposed by the miniport driver, can specify an automation table that contains properties and/or events:

  • The miniport itself
  • Each pin that the miniport exposes
  • Each node that the miniport exposes

Each event entry in an automation table is a structure of type PCEVENT_ITEM that specifies the following:

  • An event set
  • An event within the set
  • Flags indicating support options
  • A function pointer to the handler for the event

Once the driver is started and its port/miniport pairs have been registered with the system, the WDMAud system driver, which translates mixer API calls into KS commands to WDM audio drivers, will open each port/miniport pair and interrogate its capabilities. During this process, WDMAud will traverse the miniport's filter topology in search of a control node that supports a hardware event. The event is represented by the combination of event-set GUID KSEVENTSETID_AudioControlChange and event ID KSEVENT_CONTROL_CHANGE. When WdmAud finds these, it will enable the event, effectively registering itself as a client of the event. Subsequently, each time the miniport signals the event, WDMAud will be notified and will generate the appropriate windows messages for its clients.

In addition to exposing the event in the automation table, a miniport driver that needs to expose events should query the port driver for its IPortEvents interface. The following ports support the IPortEvents interface:

IPortDMus

IPortMidi

IPortTopology

IPortWaveCyclic

IPortWavePci

Call QueryInterface on the port object and specify REFIID IID_IPortEvents.

The IPortEvents interface supports the following two methods:

IPortEvents::AddEventToEventList

IPortEvents::GenerateEventList


IPortEvents::AddEventToEventList

The AddEventToEventList method adds an event to the port's event list.

VOID
  AddEventToEventList(
    IN PKSEVENT_ENTRY  EventEntry
    );

Parameters

EventEntry
Pointer to the event entry that describes the event.

Return Value

None

Headers

Declared in portcls.h. Include portcls.h.

Comments

This method is used by miniport drivers to add events to the event list that is maintained by the miniport's port driver. This is typically called by the miniport's event handler in response to a PCEVENT_VERB_ADD request after the handler has validated support for the event being requested.

Callers of AddEventToEventList should be running at IRQL_PASSIVE_LEVEL.

See Also

KSEVENT_ENTRY, IPortEvents::GenerateEventList, EventHandler


IPortEvents::GenerateEventList

The GenerateEventList method signals selected events in the port's event list.

VOID
  GenerateEventList(
    IN GUID  *Set  OPTIONAL,
    IN ULONG  EventId,
    IN BOOL  PinEvent,
    IN ULONG  PinId,
    IN BOOL  NodeEvent,
    IN ULONG  NodeId
    );

Parameters

Set
This optional parameter indicates the event set to be signaled.
EventId
Identifies the event ID of the event to be signaled.
PinEvent
Indicates whether or not PinId should be used in qualifying which events to signal.
PinId
Indicates the pin ID of the event to be signaled. If PinEvent is TRUE, then only events associated with pin PinId will be signaled.
NodeEvent
Indicates whether or not NodeId should be used in qualifying which events to signal.
NodeId
Indicates the node ID of the event to be signaled. If NodeEvent is TRUE, only events associated with node NodeId will be signaled.

Return Value

None

Headers

Declared in portcls.h. Include portcls.h.

Comments

This method is used by miniport drivers to signal events in the port's event list. In response to the miniport calling this method, the port driver walks its event list and signals ALL registered events that meet the criteria expressed by the call parameters.

While callers of GenerateEventList can be running at any IRQL, there are limitations associated with calling at IRQL > DISPATCH_LEVEL. Specifically, in the currently implementation of GenerateEventList is called at IRQL > DISPATCH_LEVEL a DPC is queued to do the event list processing. That DPC contains the parameter context for a single call. As a result, it is possible to miss signaling events if multiple calls are made at IRQL > DISPATCH_LEVEL.

See Also

IPortEvents::AddEventToEventList, EventHandler


EventHandler

An EventHandler routine processes event requests.

typedef
NTSTATUS
  (*PCPFNEVENT_HANDLER)
   IN PPCEVENT_REQUEST  EventRequest,
    );

Parameters

EventRequest
Points to an initialized PCEVENT_REQUEST structure.

Return Value

The event handler returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

Each event exposed by a miniport is associated with an event handler. The purpose of the event handler is to process event requests from the port driver and its clients. The EventRequest structure passed as an input parameter to the handler contains information indicating the miniport, pin, and node information necessary to determine the target of the event request. This is the same information that is provided with property requests.

The miniport exposes its event handlers through its IMiniport::GetDescription method. This method outputs a descriptor structure (see PCFILTER_DESCRIPTOR) that defines the filter that the miniport and its associated port implement together. This structure contains a pointer to the miniport's automation table (see PCAUTOMATION_TABLE), which in turn contains a pointer to an array of the miniport's events. Each array element is a PCEVENT_ITEM structure and contains a PCPFNEVENT_HANDLER function pointer to the handler for the event.

See Also

IPortEvents::AddEventToEventList, IPortEvents::GenerateEventList, PCEVENT_REQUEST, IMiniport::GetDescription, PCFILTER_DESCRIPTOR, PCAUTOMATION_TABLE, PCEVENT_ITEM


IPortMidi

The IPortMidi interface is the MIDI interface that is exposed by the MIDI port driver to the adapter driver that implements the MIDI miniport object. It is, effectively, the port driver's lower-edge interface and provides a method for the miniport's interrupt-service routine to notify the port driver that data is available for reading. IPortMidi inherits from the IPort interface.

A miniport creates an IPortMidi object by calling PcNewPort and specifying REFIID IID_IPortMidi.

In addition to the methods that are supported by the IPort interface, the IPortMidi interface supports the following methods:

IPortMidi::Notify

IPortMidi::RegisterServiceGroup


IPortMidi::Notify

The Notify method notifies the port driver that an interrupt indicating the progress of the DMA pointer has occurred. It should be called from the miniport's interrupt-service routine. Callers of Notify can run at any IRQL.

VOID
  Notify(
    IN PSERVICEGROUP  ServiceGroup  OPTIONAL
    );

Parameters

ServiceGroup.
Pointer to the miniport's IServiceGroup object.

Return Value

None

Headers

Declared in portcls.h. Include portcls.h.

See Also

IServiceGroup


IPortMidi::RegisterServiceGroup

The RegisterServiceGroup method registers the service group to be used for the IPortMidi::Notify method. Callers of RegisterServiceGroup should be run at IRQL PASSIVE_LEVEL.

NTSTATUS
  RegisterServiceGroup(
    IN PSERVICEGROUP  ServiceGroup
    );

Parameters

ServiceGroup
Pointer to the miniport's IServiceGroup object that is being registered.

Return Value

RegisterServiceGroup returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

See Also

IPortMidi::Notify, IServiceGroup


IPortTopology

The IPortTopology interface is exposed by the topology port driver to the adapter driver that implements the topology miniport object. This interface is part of the port driver's lower-edge interface and provides a function to notify the port driver that control changes are available for reading. IPortTopology inherits from the IPort interface.

A miniport creates an IPortTopology object by calling PcNewPort and specifying REFIID IID_IPortTopology.

The IPortTopology interface supports only the methods that are defined for the IPort interface.


IPortWaveCyclic

The IPortWaveCyclic interface is exposed by the WaveCyclic port to the adapter driver that implements the WaveCyclic miniport object. This interface provides a notification method that the miniport's interrupt-service routine calls. Slave and bus master DMA channels can also be instantiated on this interface. IPortWaveCyclic inherits from the IPort interface.

A miniport creates an IPortWaveCyclic object by calling PcNewPort and specifying REFIID IID_IPortWaveCyclic.

In addition to the methods that are supported by the IPort interface, the IPortWaveCyclic supports the following methods:

IPortWaveCyclic::NewMasterDmaChannel

IPortWaveCyclic::NewSlaveDmaChannel

IPortWaveCyclic::Notify


IPortWaveCyclic::NewMasterDmaChannel

The NewMasterDmaChannel method creates a new instance of a bus master DMA channel. Callers of NewMasterDmaChannel should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  NewMasterDmaChannel(
    OUT PDMACHANNEL  *DmaChannel,
    IN PUNKNOWN  OuterUnknown,
    IN PRESOURCELIST  ResourceList  OPTIONAL,
    IN ULONG  MaximumLength,
    IN BOOL  Dma32BitAddresses,
    IN BOOL  Dma64BitAddresses,
    IN DMA_WIDTH  DmaWidth,
    IN DMA_SPEED  DmaSpeed
    );

Parameters

DmaChannel
Pointer to a location to which the method outputs a pointer to the new DMA-channel object's IDmaChannel interface.
OuterUnknown
Pointer to the IUnknown interface of an object that needs to aggregate the DMA-channel object. If aggregation is not required, specify this parameter as NULL.
ResourceList
Pointer to an IResourceList object. This resource list contains the resource that describes the DMA channel. This parameter is optional and can be specified as NULL.
MaximumLength
Maximum length in bytes of the cyclic DMA buffer that will be associated with this channel.
Dma32BitAddresses
Specifies the use of 32-bit addresses.
Dma64BitAddresses
Specifies the use of 64-bit addresses.
DmaWidth
Indicates the width of the DMA channel.
DmaSpeed
The DMA speed can be specified as one of the following DMA_SPEED enumeration values: Compatible, TypeA, TypeB, TypeC, or TypeF.

Return Value

NewMasterDmaChannel returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

The definitions of the parameters for the NewMasterDmaChannel call are similar to those for the members of the DEVICE_DESCRIPTION structure with the same names.

See Also

IDmaChannel, IResourceList, DEVICE_DESCRIPTION


IPortWaveCyclic::NewSlaveDmaChannel

The NewSlaveDmaChannel method creates a new instance of a slave DMA channel. Callers of NewSlaveDmaChannel should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  NewSlaveDmaChannel(
    OUT PDMACHANNEL  *DmaChannel,
    IN PUNKNOWN  OuterUnknown,
    IN PRESOURCELIST  ResourceList  OPTIONAL,
    IN ULONG  DmaIndex,
    IN ULONG  MaximumLength,
    IN BOOL  DemandMode,
    IN DMA_SPEED  DmaSpeed
    );

Parameters

DmaChannel
Pointer to a location to which the method outputs a pointer to the new DMA-channel object's IDmaChannel interface.
OuterUnknown
Pointer to the IUnknown interface of an object that needs to aggregate the DMA-channel object. If aggregation is not required, specify this parameter as NULL.
ResourceList
Pointer to an IResourceList object. This resource list contains the resource that describes the DMA channel.
DmaIndex
Index in the resource list of the DMA channel descriptor. This is used as a parameter to a FindxxxEntry call performed on the IResourceList object.
MaximumLength
Maximum length in bytes of the cyclic DMA buffer that will be associated with this channel.
DemandMode
Indicates whether the device associated with the DMA channel supports demand mode.
DmaSpeed
The DMA speed can be specified as one of the following DMA_SPEED enumeration values: Compatible, TypeA, TypeB, TypeC, or TypeF.

Return Value

NewSlaveDmaChannel returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

The definitions of the parameters for the NewSlaveDmaChannel call are similar to those for the members of the DEVICE_DESCRIPTION structure with the same names.

See Also

IDmaChannel, IResourceList, DEVICE_DESCRIPTION


IPortWaveCyclic::Notify

The Notify method notifies the port driver that an interrupt indicating the progress of the DMA pointer has occurred. It should be called from the miniport's interrupt-service routine. Callers of Notify can run at any IRQL.

VOID
  Notify(
   IN PSERVICEGROUP  ServiceGroup
   );

Parameters

ServiceGroup
Pointer to the miniport's IServiceGroup object.

Return Value

Notify returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

This method is vital for accurate timing. Most miniports will call this method in response to a notification interrupt after having cleared the interrupt source. Although the miniport is free to use other methods for determining when to call this method, precise timing is important and should be maintained.

When an ISR is installed, a context parameter (ServiceContext) is submitted along with the address of the ISR (for details, see Providing ISR Context Information). When the interrupt occurs, the operating system calls the ISR, passing ServiceContext as one of the parameters of the ISR. It is up to the driver developer to determine what value ServiceContext will contain. Though not required, it is recommended that ServiceContext be a pointer to the miniport object. The context will then allow access to any information required by the ISR.

See Also

IServiceGroup


IPortWavePci

The IPortWavePci interface is exposed by the WavePci port to the adapter driver that implements the WavePci miniport object. This interface provides notification and DMA services to the miniport object. IPortWavePci inherits from the IPort interface.

A miniport creates an IPortWavePci object by calling PcNewPort and specifying REFIID IID_IPortWavePci.

In addition to the methods that are supported by the IPort interface, the IPortWavePci interface supports the following two methods:

IPortWavePci::NewMasterDmaChannel

IPortWavePci::Notify


IPortWavePci::NewMasterDmaChannel

The NewMasterDmaChannel method creates a new instance of a bus-master DMA channel.

NTSTATUS
  NewMasterDmaChannel(
    OUT PDMACHANNEL  *DmaChannel,
    IN PUNKNOWN  OuterUnknown OPTIONAL,
    IN POOL_TYPE  PoolType,
    IN PRESOURCELIST  ResourceList OPTIONAL,
    IN BOOLEAN  ScatterGather,
    IN BOOLEAN  Dma32BitAddresses
    IN BOOLEAN  Dma64BitAddresses
    IN BOOLEAN  IgnoreCount,
    IN DMA_WIDTH  DmaWidth,
    IN DMA_SPEED  DmaSpeed
    IN ULONG  MaximumLength,
    IN ULONG  DmaPort
    );

Parameters

DmaChannel
Pointer to a location to which the method outputs a pointer to the new DMA-channel object's IDmaChannel interface.
OuterUnknown
Pointer to the IUnknown interface of an object that needs to aggregate the DMA-channel object. If aggregation is not required, OuterUnknown can be set to NULL.
PoolType
Specifies the type of memory pool from which the storage for the DMA-channel object should be allocated. See POOL_TYPE.
ResourceList
Pointer to an IResourceList object describing the DMA channel.
ScatterGather
Requests that the DMA channel support scatter/gather DMA. Always set this parameter to TRUE.
Dma32BitAddresses
Specifies the use of 32-bit addresses for DMA operations.
Dma64BitAddresses
Specifies the use of 64-bit addresses for DMA operations.
IgnoreCount
Indicates whether to ignore the DMA controller's transfer counter. Set to TRUE if the DMA controller in this platform does not maintain an accurate transfer counter, and therefore requires a workaround.
DmaWidth
Not used. Set to (DMA_WIDTH)-1.
DmaSpeed
Not used. Set to (DMA_SPEED)-1.
MaximumLength
Maximum number of bytes in the cyclic buffer that will be associated with this DMA channel.
DmaPort
Not used. Set to 0.

Return Value

NewMasterDmaChannel returns STATUS_SUCCESS if the call was successful. Otherwise, it returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

The definitions of the parameters for the NewMasterDmaChannel call are similar to those for the members of the DEVICE_DESCRIPTION structure with the same names.

See Also

IDmaChannel, IResourceList, DEVICE_DESCRIPTION, POOL_TYPE


IPortWavePci::Notify

The Notify method notifies the port driver that an interrupt indicating the progress of the DMA pointer has occurred. It should be called from the miniport's interrupt-service routine. Callers of Notify can run at any IRQL.

VOID
  Notify(
    IN PSERVICEGROUP  ServiceGroup
    );

Parameters

ServiceGroup
Pointer to the miniport's IServiceGroup object.

Return Value

Notify returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

This method is vital for accurate timing. Most miniports will call this method in response to a notification interrupt after having cleared the interrupt source. Although the miniport is free to use other methods for determining when to call this method, precise timing is important and should be maintained.

When an ISR is installed, a context parameter (ServiceContext) is submitted along with the address of the ISR (for details, see Providing ISR Context Information). When the interrupt occurs, the operating system calls the ISR, passing ServiceContext as one of the parameters of the ISR. It is up to the driver developer to determine what value ServiceContext will contain. Though not required, it is recommended that ServiceContext be a pointer to the miniport object. The context will then allow access to any information required by the ISR.

See Also

IServiceGroup


IPortWavePciStream

The IPortWavePciStream interface is exposed by the WavePci port to the adapter driver that implements the WavePci miniport object. IPortWavePciStream is the stream-associated callback interface that the the port driver implements to provide services to miniport stream objects. The stream is associated with a pin on the WavePci filter. The miniport forms this filter by binding with the port. The IMiniportWavePci::NewStream method creates the stream object. IPortWavePciStream inherits from the IUnknown interface.

The IPortWavePciStream interface supports the following methods:

IPortWavePciStream::GetMapping

IPortWavePciStream::ReleaseMapping

IPortWavePciStream::TerminatePacket


IPortWavePciStream::GetMapping

The GetMapping method obtains a mapping from the port driver and associates a tag with the mapping. Mappings obtained through this method should be released using IPortWavePciStream::ReleaseMapping unless they are revoked by the port driver. Mappings are revoked by a call to the stream's IMiniportWavePciStream::RevokeMappings method. Callers of GetMapping should run at IRQL <= DISPATCH_LEVEL.

NTSTATUS
  GetMapping(
    IN PVOID  Tag,
    OUT PPHYSICAL_ADDRESS  PhysicalAddress,
    OUT PVOID  *VirtualAddress,
    OUT PULONG  ByteCount,
    OUT PULONG  Flags
    );

Parameters

Tag
Tag to be associated with the mapping. This tag can be used in subsequent RevokeMappings calls to identify the mapping for revocation.
PhysicalAddress
Physical address of the mapping.
VirtualAddress
Virtual address of the mapping.
ByteCount
Number of bytes in the mapping.
Flags
Nonzero flag value indicates that the mapping acquired in this call is the last mapping in a packet. This flag recommends that the hardware interrupt the miniport when it is done with this mapping. In response to the interrupt, the miniport can obtain new mappings to deliver to the hardware. The miniport is not obligated to follow this recommendation.

Return Value

GetMapping returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

The port driver presents the cyclic wave buffer to the miniport as a sequence of mappings. The initial call to GetMapping outputs the mapping at the beginning of the buffer. Each successive call to GetMapping presents the next sequential mapping in the buffer. After reaching the end of the buffer (as indicated by the Flags parameter), the next GetMapping call outputs the mapping at the beginning of the buffer and the mapping sequence repeats.

The size of the mapping depends on the allocation-frame size that the IMiniportWavePciStream::GetAllocatorFraming method specifies to the kernel allocator. The frame size must be less than or equal to the page size. The port driver partitions the wave buffer into allocation frames of the specified size. If an allocation frame lies completely within a page, the port driver presents the frame to the miniport as a single mapping. If an allocation frame straddles the boundary between two pages, the port driver splits the frame at the page boundary and presents the frame as two successive mappings.

The kernel-mode virtual-memory address of the mapping is output through the VirtualAddress parameter. The miniport driver uses this address to access the mapping under direct program control. The page that contains the mapping is locked and no page fault can occur when the driver accesses the mapping. The audio device's bus-master DMA controller uses the address that is output through the PhysicalAddress parameter to access the mapping.

A miniport driver is most likely to call GetMapping during a call to the miniport stream's SetState, Service, or MappingAvailable method (see IMiniportWavePciStream).

To avoid potential deadlocks, the adapter driver should avoid holding a spinlock during its call to GetMapping. See the AC97 sample in the DDK for a code example that uses a spinlock to serialize accesses to shared data structures and peripherals in a multiprocessor system. The sample code calls KeReleaseSpinlock before calling GetMapping and calls KeAcquireSpinlock after calling GetMapping. Between the calls to release and acquire the spinlock, the driver thread should not assume that it has exclusive access to the data or peripherals that are guarded by the spinlock. The Driver Verifier tool (see www.microsoft.com/hwdev/driver/driververify.htm) checks for active spinlocks during calls to GetMapping; if it detects one, it generates a 0xC4 (deadlock detection) bugcheck.

See Also

IMiniportWavePciStream::RevokeMappings, IMiniportWavePciStream::GetAllocatorFraming, IPortWavePciStream::ReleaseMapping, KeReleaseSpinlock, KeAcquireSpinlock


IPortWavePciStream::ReleaseMapping

The ReleaseMapping method releases a mapping that was previously obtained by calling IPortWavePciStream::GetMapping. Callers of ReleaseMapping should run at IRQL <= DISPATCH_LEVEL.

NTSTATUS
  ReleaseMapping(
    IN PVOID  Tag
    );

Parameters

Tag
Tag of the mapping that is to be released.

Return Value

ReleaseMapping returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

To avoid potential deadlocks, the adapter driver should avoid holding a spinlock during its call to ReleaseMapping. See the AC97 sample in the DDK for a code example that uses a spinlock to serialize accesses to shared data structures and peripherals in a multiprocessor system. The sample code calls KeReleaseSpinlock before calling ReleaseMapping and calls KeAcquireSpinlock after calling ReleaseMapping. Between the calls to release and acquire the spinlock, the driver thread should not assume that it has exclusive access to the data or peripherals that are guarded by the spinlock. The Driver Verifier tool (see www.microsoft.com/hwdev/driver/driververify.htm) checks for active spinlocks during calls to ReleaseMapping; if it detects one, it generates a 0xC4 (deadlock detection) bugcheck.

See Also

IPortWavePciStream::GetMapping, KeReleaseSpinlock, KeAcquireSpinlock


IPortWavePciStream::TerminatePacket

The TerminatePacket method terminates the packet currently being mapped. Callers of TerminatePacket should run at IRQL <= DISPATCH_LEVEL.

NTSTATUS
  TerminatePacket(
    void
    );

Parameters

None

Return Value

TerminatePacket returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

The TerminatePacket method is used primarily for capture situations in which packets need to end at specific points in the stream (for example, for video frames).


Audio Miniport Object Interfaces

This section discusses the following audio miniport interfaces:

IMiniport

IMiniportMidi

IMiniportTopology

IMiniportWaveCyclic

IMiniportWavePci

IPinCount


IMiniport

The IMiniport interface is the generic miniport interface that all miniport objects support. IMiniport inherits from the IUnknown interface.

IMiniport is the base interface for the following miniport interfaces:

IMiniportDMus

IMiniportMidi

IMiniportTopology

IMiniportWaveCyclic

IMiniportWavePci

The IMiniport interface supports the following methods:

IMiniport::DataRangeIntersection

IMiniport::GetDescription


IMiniport::DataRangeIntersection

The DataRangeIntersection method determines the highest quality intersection of two data ranges.

NTSTATUS
  DataRangeIntersection(
    IN ULONG  PinId,
    IN PKSDATARANGE  DataRange,
    IN PKSDATARANGE  MatchingDataRange,
    IN ULONG  OutputBufferLength,
    OUT PVOID  ResultantFormat  OPTIONAL,
    OUT PULONG  ResultantFormatLength
    );

Parameters

PinId
Pin for which the data intersection is being determined.
DataRange
Pointer to KSDATARANGE structure that contains the data range submitted by client in the data-range intersection property request.
MatchingDataRange
Pin's data range to be compared with client's data range.
OutputBufferLength
Size of the buffer pointed to by the resultant format parameter.
ResultantFormat
Pointer to a location to which the method outputs the resultant format.
ResultantFormatLength
Pointer to a location to which the method outputs the length of the resultant format. This is the actual length of the resultant format that is placed at ResultantFormat. This should be less than or equal to OutputBufferLength.

Return Value

DataRangeIntersection returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error code | Meaning
STATUS_NOMATCH | There is no intersection.
STATUS_NOT_IMPLEMENTED | Defers data-intersection handling to the port driver's default handler.

Headers

Declared in portcls.h. Include portcls.h.

Comments

See the discussion of data-intersection handlers in Data-Intersection Handlers.

See Also

KSDATARANGE


IMiniport::GetDescription

The GetDescription method outputs a pointer to a filter descriptor.

NTSTATUS
  GetDescription(
    OUT PPCFILTER_DESCRIPTOR  *Description
    );

Parameters

Description
Pointer to a location to which the method outputs a pointer to the filter descriptor. The filter descriptor is a structure of type PCFILTER_DESCRIPTOR.

Return Value

GetDescription returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

This method outputs a pointer to the miniport's filter-description structure. This is a PCFILTER_DESCRIPTOR structure that describes the KS filter that the miniport implements. The structure contains descriptions of the filter's pins, nodes, connections, and properties.

See Also

PCFILTER_DESCRIPTOR


IMiniportMidi

The IMiniportMidi interface is exposed to the port driver by the adapter driver that implements the MIDI miniport object. This interface provides methods for initializing the miniport and for reading and writing MIDI data. IMiniportMidi inherits from the IMiniport interface.

The IMiniportMidi interface supports the following methods:

IMiniportMidi::Init

IMiniportMidi::NewStream

IMiniportMidi::Service


IMiniportMidi::Init

The Init method initializes the miniport. Callers of Init should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  Init(
    IN PUNKNOWN  UnknownAdapter,
    IN PRESOURCELIST  ResourceList,
    IN PPORTMIDI  Port
    OUT PSERVICEGROUP  *ServiceGroup
    );

Parameters

UnknownAdapter
A pointer to the IUnknown interface of the adapter object.
ResourceList
Pointer to IResourceList interface of the resource-list object that is to be supplied to the miniport during initialization. After passing this reference to the miniport, the port driver is free to examine the contents of the resource list but will not modify the contents of the resource list.
Port
Pointer to the IPortMidi object that is bound to this miniport.
ServiceGroup
Pointer to a location to which the method outputs a pointer to the IServiceGroup interface of the miniport's service-group object. This is the service group that is being registered for interrupt notification.

Return Value

Init returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

See Also

IResourceList, IPortMidi, IServiceGroup


IMiniportMidi::NewStream

The NewStream method creates a new instance of a logical stream associated with a specified physical channel. Callers of NewStream should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  NewStream(
    OUT PMINIPORTMIDISTREAM  Stream,
    IN PUNKNOWN  OuterUnknown  OPTIONAL,
    IN POOL_TYPE  PoolType,
    IN ULONG  Pin,
    IN BOOLEAN  Capture,
    IN PKSDATAFORMAT  DataFormat
    OUT PSERVICEGROUP  ServiceGroup
    );

Parameters

Stream
Pointer to a location to which the method outputs a pointer to the stream object's IMiniportMidiStream interface.
OuterUnknown
Pointer to the IUnknown interface of an object that needs to aggregate the stream object. Unless aggregation is desired, this parameter will be NULL.
PoolType
Specifies the type of memory pool from which the storage for the DMA-channel object should be allocated. See POOL_TYPE.
Pin
Number of the pin that is to be opened. Input and output pins are numbered independently starting at zero. The first input pin is numbered zero, and the first output pin is numbered zero.
Capture
TRUE for an input (capture) channel, and FALSE for an output (playback) channel.
DataFormat
Pointer to a KSDATAFORMAT structure that specifies the data format to use for this instance.
ServiceGroup
Pointer to a location to which the method outputs a pointer to the IServiceGroup interface of the stream's service-group object. This is the service group that is being registered for interrupt notification.

Return Value

NewStream returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

See Also

IMiniportMidiStream, POOL_TYPE, KSDATAFORMAT, IServiceGroup


IMiniportMidi::Service

The Service method notifies the miniport of a request for service. Callers of Service run at IRQL DISPATCH_LEVEL.

void
  Service(
    void
    );

Parameters

None

Return Value

None

Headers

Declared in portcls.h. Include portcls.h.

Comments

When the port calls the miniport's IMiniportMidi::Init method, that method outputs a reference to the miniport's IServiceGroup object. The port adds its own IServiceSink object to this service group and awaits notification of a service request. The source of the notification is typically the miniport's interrupt-service routine.

When the miniport's interrupt-service routine calls the port's IPortMidi::Notify routine, the port queues a DPC (deferred procedure call). When the DPC executes, it calls the RequestService method on each of the IServiceSink objects in the service group. When the DPC calls this method on the port's IServiceSink object, the port in turn calls the miniport's Service method.

See Also

IMiniportMidi::Init, IServiceGroup, IServiceSink, IPortMidi::Notify


IMiniportTopology

The IMiniportTopology interface is exposed to the topology port driver by the adapter driver that implements the topology miniport object. The topology miniport binds with the topology port to form a topology filter. Through a sequence of property requests, the topology filter enumerates the pins, nodes, and connections that comprise the internal topology of the audio adapter. The filter also supports the acquisition of control-change information. A topology filter does not process streams and an IMiniportTopology object cannot instantiate pins. IMiniportTopology inherits from the IMiniport interface.

In addition to the methods that the IMiniport interface supports, the IMiniportTopology supports the following method:

IMiniportTopology::Init


IMiniportTopology::Init

The Init method initializes the miniport. Callers of this method should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  Init(
    IN PUNKNOWN  UnknownAdapter,
    IN PRESOURCELIST  ResourceList,
    IN PPORTTOPOLOGY  Port
    );

Parameters

UnknownAdapter
A pointer to the adapter object's IUnknown interface.
ResourceList
Pointer to the IResourceList interface of the resource-list object that is to be supplied to the miniport during initialization. After passing this reference to the miniport, the port driver is free to examine the contents of the resource list but will not modify the contents of the resource list.
Port
Pointer to the IPortTopology object that is bound to this miniport.

Return Value

Init returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

See Also

IResourceList, IPortTopology


IMiniportWaveCyclic

The IMiniportWaveCyclic interface is exposed to the WaveCyclic port driver by the adapter driver that implements the WaveCyclic miniport object. This interface provides a method for initializing the miniport and a method for creating a miniport stream object. The stream object is associated with a pin on the WaveCyclic filter that the miniport forms by binding with the port. IMiniportWaveCyclic inherits from IMiniport.

In addition to the methods that the IMiniport interface supports, the IMiniportWaveCyclic interface supports the following two methods:

IMiniportWaveCyclic::Init

IMiniportWaveCyclic::NewStream


IMiniportWaveCyclic::Init

The Init method initializes the miniport. Initialization includes verification of the hardware using the resources specified in the resource list. Callers of Init should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  Init(
    IN PUNKNOWN  UnknownAdapter,
    IN PRESOURCELIST  ResourceList,
    IN PPORTWAVECYCLIC  Port
    );

Parameters

UnknownAdapter
A pointer to the IUnknown interface of the adapter object.
ResourceList
Pointer to IResourceList interface of the resource-list object that is to be supplied to the miniport during initialization. After passing this reference to the miniport, the port driver is free to examine the contents of the resource list but will not modify the contents of the resource list.
Port
Pointer to the IPortWaveCyclic object that is bound to this miniport.

Return Value

Init returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

See Also

IResourceList, IPortWaveCyclic


IMiniportWaveCyclic::NewStream

The NewStream method creates a new instance of a logical stream that is associated with a specified physical channel. Callers of NewStream should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  NewStream(
    OUT PMINIPORTWAVECYCLICSTREAM  *Stream,
    IN PUNKNOWN  OuterUnknown  OPTIONAL,
    IN POOL_TYPE  PoolType,
    IN ULONG  Pin,
    IN BOOL  Capture,
    IN PKSDATAFORMAT  DataFormat,
    OUT PDMACHANNEL  *DmaChannel,
    OUT PSERVICEGROUP  *ServiceGroup,
    );

Parameters

Stream
Pointer to a location to which the method outputs a pointer to the stream object's IMiniportWaveCyclicStream interface.
OuterUnknown
Pointer to the IUnknown interface of an object that needs to aggregate the stream object. This value is NULL if aggregation is not needed.
PoolType
Specifies the type of memory pool from which the storage for the DMA-channel object should be allocated. See POOL_TYPE.
Pin
Number of the pin that is to be opened. Input and output pins are numbered independently starting at zero. The first input pin is numbered zero, and the first output pin is numbered zero.
Capture
TRUE for an input (capture) channel, and FALSE for an output (playback) channel.
DataFormat
Pointer to a KSDATAFORMAT structure indicating the format to use for this instance.
DmaChannel
Pointer to IDmaChannel interface of the miniport's DMA-channel object. The port driver calls only the following methods on this object:

AllocatedBufferSize

BufferSize

CopyFrom

CopyTo

SetBufferSize

SystemAddress

ServiceGroup
Pointer a location to which the method outputs a pointer to the IServiceGroup interface of the stream's service-group object. This is the service group that is being registered for interrupt notification.

Return Value

NewStream returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

See Also

IMiniportWaveCyclicStream, POOL_TYPE, KSDATAFORMAT, IDmaChannel, IServiceGroup


IMiniportWavePci

The IMiniportWavePci interface is exposed to the WavePci port driver by the adapter driver that implements the WavePci miniport object. This interface provides a method for initializing the miniport, a method for creating a miniport stream object, and a method for notifying the miniport of a service request. The stream object is associated with a pin on the WavePci filter that the miniport forms by binding with the port. IMiniportWavePci inherits from the IMiniport interface.

In addition to the methods in the IMiniport interface, the IMiniportWavePci interface supports the following methods:

IMiniportWavePci::Init

IMiniportWavePci::NewStream

IMiniportWavePci::Service


IMiniportWavePci::Init

The Init method initializes the miniport. Initialization includes verification of the hardware using the resources specified in the resource list. Callers of Init should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  Init(
    IN PUNKNOWN  UnknownAdapter,
    IN PRESOURCELIST  ResourceList,
    IN PPORTWAVEPCI  Port,
    OUT PSERVICEGROUP  *ServiceGroup
    );

Parameters

UnknownAdapter
A pointer to the IUnknown interface of the adapter object.
ResourceList
Pointer to IResourceList interface of resource-list object that is to be supplied to the miniport during initialization. After passing this reference to the miniport, the port driver is free to examine the contents of the resource list but will not modify the contents of the resource list.
Port
Pointer to the port driver's IPortWavePci interface object.
ServiceGroup
Pointer to a location to which the method outputs a pointer to the IServiceGroup interface of the miniport's service-group object. This is the service group that is being registered for interrupt notification.

Return Value

Init returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Also See

IResourceList, IPortWavePci, IServiceGroup


IMiniportWavePci::NewStream

The NewStream method creates a new instance of a logical stream associated with a specified physical channel. Callers of NewStream should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  NewStream(
    OUT PMINIPORTWAVEPCISTREAM  Stream,
    IN PUNKNOWN  OuterUnknown  OPTIONAL,
    IN POOL_TYPE  PoolType,
    IN PPORTWAVEPCISTREAM  PortStream,
    IN ULONG  Pin,
    IN BOOL  Capture,
    IN PKSDATAFORMAT  DataFormat,
    OUT PDMACHANNEL  *DmaChannel,
    OUT PSERVICEGROUP  *ServiceGroup
    );

Parameters

Stream
Pointer to a location to which the method outputs a pointer to the stream object's IMiniportWavePciStream interface.
OuterUnknown
Pointer to the IUnknown interface of an object that needs to aggregate the stream object. This value can be NULL if the aggregation is not required.
PoolType
Specifies the type of memory pool from which the storage for the DMA-channel object should be allocated. See POOL_TYPE.
PortStream
Pointer to the IPortWavePciStream interface of the port driver's stream object.
Pin
Number of the pin that is to be opened. Input and output pins are numbered independently starting at zero. The first input pin is numbered zero, and the first output pin is numbered zero.
Capture
TRUE for an input (capture) channel, FALSE for an output (playback) channel.
DataFormat
Pointer to KSDATAFORMAT structure that indicates the format to use for this stream.
DmaChannel
Pointer to the miniport's IDmaChannel object.
ServiceGroup
Pointer to a location to which the method outputs a pointer to the IServiceGroup interface of the stream's service-group object. This is the service group that is being registered for interrupt notification.

Return Value

NewStream returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

The NewStream method does not follow the usual reference-counting conventions in its handling of the reference that it outputs through the DmaChannel OUT parameter. When the port finishes using the references that it receives through the NewStream method's other OUT parameters, Stream and ServiceGroup, it releases them, as expected. In contrast, the port never uses the DmaChannel reference after the return from NewStream and it never releases this reference.

The AC97 sample adapter in the Windows DDK reflects this behavior. This sample's implementation of the IMiniportWavePci::NewStream method calls AddRef on the Stream and ServiceGroup references that it outputs but not the DmaChannel reference. This behavior is preserved for the sake of backward compatibility.

Note that the NewStream methods for the other port types (WaveCyclic, in particular) follow the usual reference-counting conventions for all their OUT parameters.

For more information, see Reference-Counting Conventions for COM Objects.

See Also

IMiniportWavePciStream, POOL_TYPE, IPortWavePciStream, KSDATAFORMAT, IDmaChannel, IServiceGroup


IMiniportWavePci::Service

The Service method notifies the miniport of a request for service. Callers of Service run at IRQL DISPATCH_LEVEL.

void
  Service(
    void
    );

Parameters

None

Return Value

None

Headers

Declared in portcls.h. Include portcls.h.

Comments

When the port calls the miniport's IMiniportWavePci::Init method, that method outputs a reference to the miniport's IServiceGroup object. The port adds its own IServiceSink object to this service group and awaits notification of a service request. The source of the notification is typically the miniport's interrupt-service routine.

When the miniport's interrupt-service routine calls the port's IPortWavePci::Notify routine, the port queues a DPC (deferred procedure call). When the DPC executes, it calls the RequestService method on each of the IServiceSink objects in the service group. When the DPC calls this method on the port's IServiceSink object, the port in turn calls the miniport's Service method.

See Also

IMiniportWavePci::Init, IServiceGroup, IServiceSink, IPortWavePci::Notify


IPinCount

The IPinCount interface provides a means for the miniport to monitor and manipulate its pin counts dynamically as pins are instantiated and closed. This is an optional interface that a miniport can expose if it needs either or both of the following:

  • To be explicitly notified of changes in Kernel Streaming pin counts.
  • To dynamically change its pin counts.

In the case of a wave audio device, for example, streams with different attributes (3D, stereo/mono, and so on) might also have different "weights" in terms of the amount of hardware resources they consume.

When opening a "heavyweight" stream, the miniport might need to decrement the available pin count by two instead of by one in order to more accurately indicate the number of pins that can be created with the remaining resources.

The process is reversed when a "heavyweight" stream is closed. The available pin count might increase by more than one in order to reflect the fact that two or more "lightweight" streams can be created from the newly freed resources.

The interface provides a single method. The port driver that is bound to the miniport calls this method in response to a pin-count query.

The IPinCount interface supports the following method:

IPinCount::PinCount


IPinCount::PinCount

The PinCount method queries the miniport for its pin count.

VOID
  PinCount(
    IN ULONG  PinId,
    IN OUT PULONG  FilterNecessary,
    IN OUT PULONG  FilterCurrent,
    IN OUT PULONG  FilterPossible,
    IN OUT PULONG  GlobalCurrent,
    IN OUT PULONG  GlobalPossible
    );

Parameters

PinId
Identifies the pin factory.
FilterNecessary
The minimum number of pins that the pin factory must instantiate before the filter can perform I/O operations.
FilterCurrent
The current number of pin instances. This number counts the pins that the pin factory has already instantiated on the filter.
FilterPossible
The maximum number of pins that the pin factory can instantiate on the filter. Set to KSINSTANCE_INDETERMINATE if there is no maximum.
GlobalCurrent
The current number of pins that the pin factory has instantiated on the driver.
GlobalPossible
The maximum number of pins that the pin factory can instantiate on the driver. Set to KSINSTANCE_INDETERMINATE if there is no maximum.

Return Value

None

Headers

Declared in portcls.h. Include portcls.h.

Comments

The PortCls system driver calls the PinCount method when it receives one of the following KS property requests:

KSPROPERTY_PIN_CINSTANCES

KSPROPERTY_PIN_GLOBALCINSTANCES

KSPROPERTY_PIN_NECESSARYINSTANCES

The PinCount call notifies the miniport that its pin count is being queried. The call has two purposes:

  • To give the miniport an opportunity to alter the current pin counts.
  • To let the miniport know the current pin counts.

FilterNecessary, FilterCurrent, FilterPossible, GlobalCurrent, and GlobalPossible are all IN-OUT parameters that point to values in the miniport's filter description. During the PinCount call, the miniport can examine these values and has the option of editing the values in order to more accurately indicate how many additional pins can be created from the remaining resources.

FilterCurrent and FilterPossible specify the per-filter values for a given pin factory.

GlobalCurrent and GlobalPossible specify the total values for a given pin factory over all instances of the filter.

Miniports typically do not need to change the FilterNecessary parameter, but it is included for the sake of completeness.

Miniports should not explicitly cause streams to be created or destroyed from within the PinCount method. There are no other real restrictions on what miniports can do during this call.

PortCls calls the PinCount method at the time that a stream is created.

The code for this method should reside in paged memory.

See Also

KSPROPERTY_PIN_CINSTANCES, KSPROPERTY_PIN_GLOBALCINSTANCES, KSPROPERTY_PIN_NECESSARYINSTANCES


Audio Stream Object Interfaces

This section discusses the following audio-stream interfaces:

IDrmAudioStream

IMiniportWaveCyclicStream

IMiniportWavePciStream


IDrmAudioStream

The IDrmAudioStream interface implements DRM protection of the digital content in an audio stream. For information on DRM, see Digital Rights Management. IDrmAudioStream inherits from the IUnknown interface.

The following audio-stream objects support the IDrmAudioStream interface:

  • An audio-stream object created by IMiniportWaveCyclic::NewStream
  • An audio-stream object created by IMiniportWavePci::NewStream

To obtain a reference to an IDrmAudioStream object, call the QueryInterface method on either of the audio-stream objects above and specify REFIID IID_IDrmAudioStream.

The IDrmAudioStream interface supports the following method:

IDrmAudioStream::SetContentId


IDrmAudioStream::SetContentId

The SetContentId method sets the DRM content ID and its assigned DRM content rights on a KS audio stream. This method runs in the context of the caller at IRQL PASSIVE_LEVEL.

NTSTATUS
  SetContentId(
    IN ULONG  ContentId,
    IN PDRMRIGHTS  DrmRights
    );

Parameters

ContentId
A runtime identifier that the DRM system generates at runtime to identify DRM-protected content in this stream.
DrmRights
Pointer to a DRMRIGHTS structure that specifies the rights granted by the content provider to the user for playing and copying DRM-protected content in this stream.

Return Value

SetContentId returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in drmk.h. Include drmk.h.

Comments

The DRM system can call the SetContentId method at any time during the lifetime of a KS audio stream.

A KS audio filter completes the execution of a call to the SetContentId method synchronously. If the function returns STATUS_SUCCESS, this indicates that all the downstream KS audio nodes (see Audio Topology Nodes) of a KS audio stream have also been successfully configured with the specified DRM content ID and DRM content rights. (Note that a downstream node is a direct or indirect sink for an audio stream.)

If the KS audio filter cannot enforce the specified DRM content rights, the SetContentId method returns the error code STATUS_NOT_IMPLEMENTED. In this case, the KS audio stream's previously set DRM content ID and DRM content rights remain set on the stream.

For more information on the use of this method, see Digital Rights Management.

See Also

DRMRIGHTS, DrmCreateContentMixed, DrmDestroyContent, DrmForwardContentToFileObject, DrmForwardContentToInterface, DrmGetContentRights


IMiniportMidiStream

The IMiniportMidiStream interface is exposed to the MIDI port driver by the adapter driver that implements the MIDI miniport object. IMiniportMidiStream inherits from the IUnknown interface.

IMiniportMidiStream represents the stream that is associated with a pin on the MIDI filter that the miniport forms by binding with the port. This interface provides methods for reading and writing a MIDI stream and for setting the format and state of a MIDI stream. The IMiniportMidi::NewStream method creates the stream.

The IMiniportMidiStream interface supports the following methods:

IMiniportMidiStream::Read

IMiniportMidiStream::SetFormat

IMiniportMidiStream::SetState

IMiniportMidiStream::Write


IMiniportMidiStream::Read

The Read method accepts an incoming MIDI data stream.

NTSTATUS
  Read(
    IN PVOID  BufferAddress,
    IN ULONG  BufferLength,
    OUT PULONG  BytesRead
    );

Parameters

BufferAddress
Buffer address of the incoming MIDI stream.
BufferLength
Length in bytes of the buffer pointed to by BufferAddress.
BytesRead
Actual number of bytes successfully accepted from the stream.

Return Value

Read returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.


IMiniportMidiStream::SetFormat

The SetFormat method sets the wave format of the stream.

NTSTATUS
  SetFormat(
    IN PKSDATAFORMAT  DataFormat
    );

Parameters

DataFormat
Pointer to a KSDATAFORMAT structure that contains the new format that the stream is to be set to.

Return Value

SetFormat returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

See Also

KSDATAFORMAT


IMiniportMidiStream::SetState

The SetState method sets the stream's transport state to a new state value.

NTSTATUS
  SetState(
    IN KSSTATE  NewState
    );

Parameters

NewState
KSSTATE enumeration value that indicates the new state that the stream is to be set to.

Return Value

SetState returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

The new state can be one of the following:

  • KSSTATE_RUN

    Data transport in the current audio filter graph is running and functioning as normal.

  • KSSTATE_ACQUIRE

    This is a transitional state that helps to manage the transition between KSSTATE_RUN and KSSTATE_STOP.

  • KSSTATE_PAUSE

    This is a transitional state that helps to manage the transition between KSSTATE_RUN and KSSTATE_STOP.

  • KSSTATE_STOP

    Data transport is stopped in the current audio filter graph.

For most miniports, KSSTATE_ACQUIRE and KSSTATE_PAUSE are indistinguishable.

Transitions always occur in one of the following two sequences:

  • STOP -> ACQUIRE -> PAUSE -> RUN
  • RUN -> PAUSE -> ACQUIRE -> STOP

See Also

KSPROPERTY_CONNECTION_STATE


IMiniportMidiStream::Write

The Write method produces an outgoing MIDI data stream.

NTSTATUS
  Write(
    IN PVOID  BufferAddress,
    IN ULONG  BytesToWrite,
    OUT PULONG  BytesWritten
    );

Parameters

BufferAddress
Pointer to the buffer that contains the MIDI data for the stream.
BytesToWrite
Length in bytes of the MIDI data stream buffer at BufferAddress.
BytesWritten
Actual number of bytes successfully written to the stream. This value must be either the same value as BytesToWrite or the next greater multiple of four.

Return Value

Write returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.


IMiniportWaveCyclicStream

The IMiniportWaveCyclicStream interface is exposed to the WaveCyclic port driver by the adapter driver that implements the WaveCyclic miniport object. IMiniportWaveCyclicStream inherits from the IUnknown interface.

This interface represents the data stream at a pin on the WaveCyclic filter that the miniport forms by binding with the port. This interface provides methods to manage a single stream of incoming or outgoing audio data. The IMiniportWaveCyclic::NewStream method creates the stream object.

The IMiniportWaveCyclicStream interface supports the following methods:

IMiniportWaveCyclicStream::GetPosition

IMiniportWaveCyclicStream::NormalizePhysicalPosition

IMiniportWaveCyclicStream::SetFormat

IMiniportWaveCyclicStream::SetNotificationFreq

IMiniportWaveCyclicStream::SetState

IMiniportWaveCyclicStream::Silence


IMiniportWaveCyclicStream::GetPosition

The GetPosition method gets the current position of the DMA read or write pointer for the stream. Callers of GetPosition should run at IRQL <= DISPATCH_LEVEL.

NTSTATUS
  GetPosition(
    OUT PULONG  Position
    );

Parameters

Position
Position of the DMA pointer expressed as a byte offset from the beginning of the stream.

Return Value

GetPosition returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.


IMiniportWaveCyclicStream::NormalizePhysicalPosition

The NormalizePhysicalPosition method converts a physical buffer position to a time-based value. Callers of NormalizePhysicalPosition can run at any IRQL.

NTSTATUS
  NormalizePhysicalPosition(
    IN OUT PULONG  PhysicalPosition
    );

Parameters

PhysicalPosition
Pointer to a location that contains either the physical position or the time-based value. On entry, this location contains the physical-position value to convert. On return, it contains the converted value, which is time-based.

Return Value

NormalizePhysicalPosition returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

PhysicalPosition is both an input and an output parameter. Given a physical position based on the actual number of bytes transferred, NormalizePhysicalPosition converts the position to a time-based value of 100-nanosecond units.


IMiniportWaveCyclicStream::SetFormat

The SetFormat method changes the format associated with a stream. Callers of SetFormat should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  SetFormat(
    IN PKSDATAFORMAT  DataFormat
    );

Parameters

DataFormat
Pointer to a KSDATAFORMAT structure that indicates the new format of the stream.

Return Value

SetFormat returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

See Also

KSDATAFORMAT


IMiniportWaveCyclicStream::SetNotificationFreq

The SetNotificationFreq method controls the frequency at which notification interrupts are generated by setting the interval between successive interrupts. Callers of SetNotificationFreq should run at IRQL PASSIVE_LEVEL.

ULONG
  SetNotificationFreq(
    IN ULONG  Interval,
    OUT PULONG  FrameSize,
    );

Parameters

Interval
Value expressed in milliseconds that indicates the interval between notification interrupts.
FrameSize
Pointer to a ULONG variable where the method writes the maximum number of bytes that can be transferred in Interval milliseconds. This byte count determines the size of the buffer that needs to be allocated for the input or output stream.

Return Value

SetNotificationFreq returns the new notification interval expressed in milliseconds. In all current Windows releases, the port driver ignores this value.

Headers

Declared in portcls.h. Include portcls.h.

Comments

During each notification interrupt, the miniport's interrupt service routine calls the IPortWaveCyclic::Notify method with the stream's IServiceGroup object as the call parameter. This is the IServiceGroup object that the miniport previously output to the port during the IMiniportWaveCyclic::NewStream call.

See Also

IPortWaveCyclic::Notify, IServiceGroup, IMiniportWaveCyclic::NewStream


IMiniportWaveCyclicStream::SetState

The SetState method sets the new state of playback or recording for the stream. Callers of SetState should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  SetState(
   IN KSSTATE  State
    );

Parameters

State
KSSTATE enumeration value that indicates the new state for the stream.

Return Value

SetState returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

The new state can be one of the following:

  • KSSTATE_RUN

    Data transport in the current audio filter graph is running and functioning as normal.

  • KSSTATE_ACQUIRE

    This is a transitional state that helps to manage the transition between KSSTATE_RUN and KSSTATE_STOP.

  • KSSTATE_PAUSE

    This is a transitional state that helps to manage the transition between KSSTATE_RUN and KSSTATE_STOP.

  • KSSTATE_STOP

    Data transport is stopped in the current audio filter graph.

For most miniports, KSSTATE_ACQUIRE and KSSTATE_PAUSE are indistinguishable.

Transitions always occur in one of the following two sequences:

  • STOP -> ACQUIRE -> PAUSE -> RUN
  • RUN -> PAUSE -> ACQUIRE -> STOP

See Also

KSPROPERTY_CONNECTION_STATE


IMiniportWavePciStream

The IMiniportWavePciStream interface is exposed to the WavePci port driver by the adapter driver that implements the WavePci miniport object. IMiniportWavePciStream inherits from the IUnknown interface.

This interface represents the data stream at a pin on the WavePci filter that the miniport forms by binding with the port. Most of the miniport's functionality is exposed through the IMiniportWavePciStream interface. The IMiniportWavePci::NewStream method creates the stream object.

The IMiniportWavePciStream interface supports the following methods:

IMiniportWavePciStream::GetAllocatorFraming

IMiniportWavePciStream::GetPosition

IMiniportWavePciStream::MappingAvailable

IMiniportWavePciStream::NormalizePhysicalPosition

IMiniportWavePciStream::RevokeMappings

IMiniportWavePciStream::Service

IMiniportWavePciStream::SetFormat

IMiniportWavePciStream::SetState


IMiniportWavePciStream::GetAllocatorFraming

The GetAllocatorFraming method gets the allocator-framing requirements for the stream. Callers of GetAllocatorFraming should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  GetAllocatorFraming(
    OUT PKSALLOCATOR_FRAMING  AllocatorFraming
    );

Parameters

AllocatorFraming
Pointer to KSALLOCATOR_FRAMING structure into which the method is to write the miniport's allocator-framing requirements for this stream.

Return Value

GetAllocatorFraming returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

See the discussion of allocator framing in WavePci Latency.

See Also

KSALLOCATOR_FRAMING


IMiniportWavePciStream::GetPosition

The GetPosition method gets the current position of the stream. Callers of GetPosition should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  GetPosition(
    OUT PULONGLONG  Position
    );

Parameters

Position
Pointer to a location to which the method outputs the current byte position of the stream.

Return Value

GetPosition returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

The miniport is required to maintain stream position based on the mappings it acquires, regardless of whether mappings are released or revoked. The position indicated by the GetPosition method is the miniport's best estimate of the byte position of the data currently in the DAC or ADC. The position is initially zero and is set to rest by a transition into the stopped state.


IMiniportWavePciStream::MappingAvailable

The MappingAvailable method indicates that a new mapping is available. Callers of MappingAvailable should run at IRQL PASSIVE_LEVEL.

VOID
  MappingAvailable(
    void
    );

Parameters

None

Return Value

None

Headers

Declared in portcls.h. Include portcls.h.

Comments

The port driver calls the MappingAvailable method to notify the miniport that a new mapping has become available only after the miniport's previous request for mapping through IPortWavePciStream::GetMapping has been refused.

See the discussion of allocator framing in WavePci Latency.

Also See

IPortWavePciStream::GetMapping


IMiniportWavePciStream::NormalizePhysicalPosition

The NormalizePhysicalPosition method converts a physical buffer position to a time-based value. Callers of NormalizePhysicalPosition can run at any IRQL.

NTSTATUS
  NormalizePhysicalPosition(
    IN OUT PULONG  PhysicalPosition
    );

Parameters

PhysicalPosition
Pointer to a location that contains either the physical position or time-based value. On entry, this location contains the physical-position value that is to be converted. On return, it contains the converted value, which is time-based.

Return Value

NormalizePhysicalPosition returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

Given a physical position based on the actual number of bytes transferred, the NormalizePhysicalPosition method converts the position to a time-based value that is expressed in 100-nanosecond units.


IMiniportWavePciStream::RevokeMappings

The RevokeMappings method revokes mappings that were previously obtained through IPortWavePciStream::GetMapping. Mappings are revoked when a request (IRP) is canceled and the memory previously mapped might not be available. Callers of RevokeMappings should run at IRQL DISPATCH_LEVEL.

NTSTATUS
  RevokeMappings(
    IN PVOID  FirstTag,
    IN PVOID  LastTag,
    OUT PULONG  MappingsRevoked
    );

Parameters

FirstTag
Pointer to the tag associated with the first mapping that is being revoked.
LastTag
Pointer to the tag associated with the last mapping that is being revoked.
MappingsRevoked
Number of mappings in the indicated interval that were actually mapped (not yet released). Due to synchronization issues, some of the revoked mappings might already have been released by the miniport.

Return Value

RevokeMappings returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

See the discussion of allocator framing in WavePci Latency.

See Also

IPortWavePciStream::GetMapping


IMiniportWavePciStream::Service

The Service method notifies the miniport of a request for service. Callers of Service run at IRQL DISPATCH_LEVEL.

void
  Service(
   void
    );

Parameters

None

Return Value

None

Headers

Declared in portcls.h. Include portcls.h.

Comments

When the port calls the miniport's IMiniportWavePci::NewStream method, that method outputs a reference to the new stream's IServiceGroup object. The port stream adds its own IServiceSink object to the service group and awaits notification of a service request. The source of the notification is typically the miniport's interrupt-service routine.

When the miniport's interrupt-service routine calls the port's IPortWavePci::Notify routine, the port queues a DPC (deferred procedure call). When the DPC executes, it calls the RequestService method on each of the IServiceSink objects in the service group. When the DPC calls this method on the port stream's IServiceSink object, the port in turn calls the miniport stream's Service method.

See Also

IMiniportWavePci::NewStream, IServiceGroup, IServiceSink, IPortWavePci::Notify


IMiniportWavePciStream::SetFormat

The SetFormat method sets the format of the stream. Callers of SetFormat should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  SetFormat(
    IN PKSDATAFORMAT  DataFormat
    );

Parameters

DataFormat
Pointer to KSDATAFORMAT structure that describes the format of the stream.

Return Value

SetFormat returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

See Also

KSDATAFORMAT


IMiniportWavePciStream::SetState

The SetState method changes the state of the stream transport. Callers of SetState should run at IRQL PASSIVE_LEVEL.

NTSTATUS
  SetState(
    IN KSSTATE  State
    );

Parameters

State
KSSTATE enumeration value that indicates the new state of the stream.

Return Value

SetState returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

The new state can be one of the following:

  • KSSTATE_RUN

    Data transport in the current audio filter graph is running and functioning as normal.

  • KSSTATE_ACQUIRE

    This is a transitional state that helps to manage the transition between KSSTATE_RUN and KSSTATE_STOP.

  • KSSTATE_PAUSE

    This is a transitional state that helps to manage the transition between KSSTATE_RUN and KSSTATE_STOP.

  • KSSTATE_STOP

    Data transport is stopped in the current audio filter graph.

For most miniports, KSSTATE_ACQUIRE and KSSTATE_PAUSE are indistinguishable.

Transitions always occur in one of the following two sequences:

  • STOP -> ACQUIRE -> PAUSE -> RUN
  • RUN -> PAUSE -> ACQUIRE -> STOP

See Also

KSPROPERTY_CONNECTION_STATE


DirectMusic Interfaces

This section describes the Microsoft® DirectMusic® interfaces that are associated with kernel streaming audio. The following topics are discussed:

DirectMusic User Mode Synth and Synth Sink Interfaces

DirectMusic Kernel Mode Interfaces


DirectMusic User Mode Synth and Synth Sink Interfaces

This section contains reference information for the following DirectMusic® user mode interfaces:

IDirectMusicSynth (for user-mode synths)

IDirectMusicSynthSink (for user-mode synth sinks)


IDirectMusicSynth

The IDirectMusicSynth interface is used by DirectMusic to communicate with user-mode synthesizers. If you create a software synthesizer, it should have an IDirectMusicSynth interface to plug into DirectMusic. IDirectMusicSynth inherits from the IUnknown interface.

The synthesizer is not complete without a connection to a wave sink, which is represented as an object with an IDirectMusicSynthSink interface. The wave sink connects the synthesizer to the audio stream out — for example, DirectSound®, DirectShow®, or waveform audio.

Most applications do not need to call the methods of the IDirectMusicSynth interface directly; typically the port manages the synthesizer. You can, however, talk to the synthesizer directly during development and testing.

Before the synthesizer can be activated, a wave sink should be created first and connected to the synth via a call to SetSynthSink. This should be the very first call after creating the synth because many of the timing-related calls, including GetLatencyClock and SetMasterClock, are actually passed through to equivalent calls on IDirectMusicSynthSink.

The default IDirectMusicSynthSink implementation, DirectMusicSynthSink, uses DirectSound.

The methods of the IDirectMusicSynth interface can be organized in the following groups:

Activation | Activate
Channels | GetChannelPriority
 | SetChannelPriority
Instruments | Download
 | Unload
Information | GetAppend
 | GetFormat
 | GetLatencyClock
 | GetPortCaps
 | GetRunningStats
Playback | PlayBuffer
 | Render
Ports | Open
 | Close
 | SetNumChannelGroups
Miscellaneous parameters | SetMasterClock
 | SetSynthSink

All COM interfaces inherit the IUnknown interface methods. This interface supports the following three methods:

AddRef
QueryInterface
Release

Because these methods are common to all COM interfaces, they are not covered in this document.

Also see the descriptions of the IDirectMusic and IDirectMusicPort interfaces in the Platform SDK documentation.

See Also

IDirectMusicSynthSink


IDirectMusicSynth::Activate

The Activate method enables or disables the audio device under program control.

HRESULT
  Activate(
    BOOL  fEnable
    );

Parameters

fEnable
TRUE enables audio and FALSE disables audio.

Return Values

Activate returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error status | Description
S_FALSE | Indicates audio device is already inactive.
E_FAIL | Indicates that the request failed.
E_OUTOFMEMORY | Indicates that not enough memory is available to load the device.
DMUS_E_SYNTHNOTCONFIGURED | Indicates that the synth is not opened or not properly configured.
DMUS_E_NOSYNTHSINK | Indicates that the IDirectMusicSynthSink object was not connected.
DMUS_E_SYNTHACTIVE | Indicates that the synth is already active.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

By enabling or disabling the audio device under program control, Activate gives the application the ability to manage its use of resources. When it is not playing music, it can deactivate the wave-out resource, which frees it for other applications to use.

The wave-out resource is actually managed by a separate COM object, which has a IDirectMusicSynthSink interface. This should first be connected with a call to SetSynthSink. Otherwise, the synthesizer will fail the Activate call with DMUS_E_NOSYNTHSINK.

Activation is mostly managed by the wave sink object. When IDirectMusicSynth::Activate is called, the synth sets its internal activation state and calls IDirectMusicSynthSink::Activate to enable or disable the wave output.

See Also

IDirectMusicSynthSink::Activate, IDirectMusicSynth::Open


IDirectMusicSynth::Close

The Close method closes the port.

HRESULT
  Close(
    );

Parameters

None

Return Values

Close returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error status | Description
DMUS_E_ALREADYCLOSED | Indicates that the port was not open.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

When the port closes, all instruments and waves downloaded to the port are released. However, it is good practice for applications to free these objects before closing the port.

See Also

IDirectMusicSynth::Open


IDirectMusicSynth::Download

The Download method downloads a wave or instrument definition to the synthesizer.

HRESULT
  Download(
    LPHANDLE  phDownload,
    LPVOID  pvData,
    LPBOOL  pbFree
    );

Parameters

phDownload
Address of a variable to receive the download handle, which is used later to unload the data.
pvData
Pointer to continuous memory segment with download data. For an overview of the data format, see Low-Level DLS description in the DirectMusic SDK documentation.
pbFree
Address of a variable to receive a Boolean value indicating whether the synthesizer wishes to keep the memory in pvData allocated (FALSE) or whether the application can free it (TRUE).

Return Values

Download returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error status | Description
E_POINTER | Indicates that one of the pointers is invalid.
E_FAIL | Indicates that the method is unable to download the data.
DMUS_E_SYNTHNOTCONFIGURED | Indicates that the synth is not open or not properly configured.
DMUS_E_NOTMONO | Indicates that the wave chunk has more than one interleaved channel.
DMUS_E_BADARTICULATION | Indicates a bad articulation chunk or link.
DMUS_E_BADINSTRUMENT | Indicates a bad instrument chunk or link.
DMUS_E_BADWAVELINK | Indicates a bad link to the wave download data.
DMUS_E_NOARTICULATION | Indicates that the region in instrument has neither global nor local articulation.
DMUS_E_NOTPCM | Indicates that the wave data is not PCM.
DMUS_E_BADWAVE | Indicates that the wave header is corrupt.
DMUS_E_BADOFFSETTABLE | Indicates that the offset table contains errors.
DMUS_E_UNKNOWNDOWNLOAD | Indicates that the download data is neither instrument nor wave.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

The data is stored in a continuous chunk of memory, pointed to by pvData. However, at the head of the chunk are two data structures, which define the nature of the data to follow. These are the DMUS_DOWNLOADINFO and DMUS_OFFSETTABLE structures (described in Platform SDK documentation). DMUS_DOWNLOADINFO is a header that describes how to parse the data, including its size and intention (wave or instrument.) DMUS_OFFSETTABLE provides a set of byte offsets into the data segment that follows. All parsing through the data is managed through this table.

Whenever a structure in the data references another structure, it describes it by an index into the offset table. The offset table then converts it into a byte offset into the data. This allows the synthesizer to do bounds checking on all references, making the implementation more robust. In kernel mode implementations, the driver can make its own private copy of the offset table, and so ensure that an application in user mode can not alter its referencing and cause a crash.

The dwDLType member of DMUS_DOWNLOADINFO specifies the type of data being downloaded. It is set to DMUS_DOWNLOADINFO_INSTRUMENT for an instrument, DMUS_DOWNLOADINFO_WAVE for a wave. As new data types emerge, identifiers will be allocated for them. dwDLId holds a unique 32-bit identifier for the object. This identifier is used to connect objects together. In the case of DLS level-1, it is used to connect waves to instruments. The dwNumOffsetTableEntries member of DMUS_DOWNLOADINFO describes the number of entries in the DMUS_OFFSETTABLE structure, which follows. Finally, the cbSize member specifies the total size of the memory chunk that consists of DMUS_DOWNLOADINFO + DMUS_OFFSETTABLE + data chunk.

Note that the download memory is always padded with an extra 32 bytes. This allows synthesizer implementations that require additional padding at the end of loops for multi point interpolation to fill the space after the end of a wave chunk with additional data, up to 32 bytes. This additional padding is reflected by cbSize.

Depending on the synthesizer implementation, the synthesizer might decide to use the memory in the download chunk. After all, if enough memory has been allocated to store a wave, that same memory can be used by the synthesizer to store it for playback. So the synthesizer has the option of retaining the memory, and it returns its decision in the pbFree parameter. If it does keep the memory, then the caller should not free it. Later, the IDirectMusicSynth::Unload method has a callback mechanism to handle asynchronous freeing of the memory once the unload request has been made.

See Also

IDirectMusic, IDirectMusicSynth, IDirectMusicSynth::Unload


IDirectMusicSynth::GetAppend

The GetAppend method retrieves the amount of memory the port needs to have appended to the end of a download buffer.

HRESULT
  GetAppend(
    DWORD*  pdwAppend
    );

Parameters

pdwAppend
Address of a variable to receive the number of appended samples for which memory is required. The actual amount of memory can be calculated from the wave format.

Return Values

GetAppend returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error status | Description
E_POINTER | Indicates that the pointer buffer is invalid.
E_NOTIMPL | Indicates that the method is not implemented.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

Depending on the synth implementation, when it is about to download a wave, it needs to know if it needs to add a little more data attached to the end of the wave. This extra memory can be used by the port's synthesis engine to interpolate across a loop boundary.

For example, if a wave loops for 20 samples at the end, the interpolation math that calculates what to do as it loops back might need to have some extra data at the end so it can interpolate properly.

This allows the synth to use the exact same wave data that DirectMusic pulls out of the DLS file instead of copying this wave chunk to a new structure to append the extra data.

Also see the description of the IDirectMusicPort::Download method in the Platform SDK documentation.


IDirectMusicSynth::GetChannelPriority

The GetChannelPriority method is provided so that an application can retrieve the priority of a MIDI channel.

HRESULT
  GetChannelPriority(
    DWORD  dwChannelGroup,
    DWORD  dwChannel,
    LPDWORD  pdwPriority
    );

Parameters

dwChannelGroup
Group the channel is in.
dwChannel
Index of the channel on the group.
pdwPriority
Address of a variable that is to receive the priority ranking value. For a list of the ranking values that are defined for this parameter, see the IDirectMusicPort::GetChannelPriority reference page in the Platform SDK documentation.

Return Values

GetChannelPriority returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

Also see the descriptions of the IDirectMusicPort::GetChannelPriority and IDirectMusicPort::SetChannelPriority methods in the Platform SDK documentation.

See Also

IDirectMusicSynth::SetChannelPriority


IDirectMusicSynth::GetFormat

The GetFormat method retrieves information about the wave format.

HRESULT
  GetFormat(
    LPWAVEFORMATEX  pWaveFormatEx,
    LPDWORD  pdwWaveFormatExSize
    );

Parameters

pWaveFormatEx
Pointer to WAVEFORMATEX structure that is to receive information about the format. This value can be NULL. See comments below.
pdwWaveFormatExSize
Size in bytes of the structure pointed to by pWaveFormatEx.

Return Values

GetFormat returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error status | Description
E_POINTER | Indicates that one of the pointers is not valid.
DMUS_E_SYNTHNOTCONFIGURED | Indicates that the synth is not open or is not properly configured.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

The WAVEFORMATEX structure can have a variable length that depends on the details of the format. Therefore, before retrieving the format description, an application will first query the IDirectMusicSynth object for the size of the format by calling this method and specifying NULL for the pWaveFormatEx parameter. In this case, the synth should return the size of the structure in the pdwWaveFormatExSize parameter. The application can then allocate sufficient memory and call IDirectMusicSynth::GetFormat again to retrieve the format description.

If the pWaveFormatEx parameter is not NULL, DirectMusic writes, at most, pdwWaveFormatExSize bytes to pWaveFormatEx.

Also see the description of the IDirectMusicPort interface and IDirectMusicPort::GetFormat method in the Platform SDK documentation.

See Also

WAVEFORMATEX


IDirectMusicSynth::GetLatencyClock

The GetLatencyClock method retrieves the IReferenceClock that tracks the current mix time.

HRESULT
  GetLatencyClock(
    IReferenceClock**  ppClock
    );

Parameters

ppClock
Pointer to a variable that is to receive a pointer to an IReferenceClock object (described in Platform SDK documentation). This object is able to return the current mix time.

Return Values

GetLatencyClock returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error status | Description
E_FAIL | Indicates that the method was unable to access the latency clock.
E_POINTER | Indicates that the ppClock pointer is not valid.
DMUS_E_NOSYNTHSINK | Indicates that the IDirectMusicSynthSink object was not connected.
DMUS_E_SYNTHNOTCONFIGURED | Indicates that the synth is not open or is not properly configured.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

This method returns the latency clock created by the wave sink (IDirectMusicSynthSink) object, which handles the output audio stream. The latency IReferenceClock returns the current render time whenever its IReferenceClock::GetTime method is called. This time is always relative to the time established by the master clock (installed in the synthesizer and wave sink through a call to IDirectMusicSynth::SetMasterClock and IDirectMusicSynthSink::SetMasterClock). The latency time is used by the performance to identify the next available time to start playing a note. The latency should not exceed 450 milliseconds.

Also see the description of the IDirectMusic and IReferenceClock interfaces in the Platform SDK documentation.

See Also

IDirectMusicSynthSink, IDirectMusicSynth::SetMasterClock, IDirectMusicSynthSink::SetMasterClock


IDirectMusicSynth::GetPortCaps

The GetPortCaps method retrieves the capabilities of a port.

HRESULT
  GetPortCaps(
    LPDMUS_PORTCAPS  pCaps
    );

Parameters

pCaps
Pointer to a DMUS_PORTCAPS structure (described in Platform SDK documentation) that the method writes the port's capabilities into.

Return Values

GetPortCaps returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error status | Description
E_POINTER | Indicates a bad pCaps pointer.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

When an application enumerates the available DirectMusic ports with a call to IDirectMusic::EnumPort, DirectMusic calls each registered device's GetPortCaps method.

This means that the additional overhead of creating and initializing the synthesizer occurs with this call. It is a good idea to keep the overhead of simply creating a synthesizer to a minimum, because there is a chance that it is being created only so that its capabilities can be obtained, and then it will be released.

Also see the description of the IDirectMusic interface in the Platform SDK documentation.


IDirectMusicSynth::GetRunningStats

The GetRunningStats method retrieves current information about the state of the synthesizer so an application can tell how the synth is performing.

HRESULT
  GetRunningStats(
    LPDMUS_SYNTHSTATS  pStats
    );

Parameters

pStats
Pointer to a DMUS_SYNTHSTATS structure (described in Platform SDK documentation) that the method writes the statistics into.

Return Values

GetRunningStats returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error status | Description
E_FAIL | Indicates that the method is unable to get the stats.
E_POINTER | Indicates a bad pStats pointer.
E_NOTIMPL | Indicates that the synthesizer has not implemented this method (so expect the worst!).
DMUS_E_SYNTHNOTCONFIGURED | Indicates that the synth is not open or not properly configured.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

This method returns current information about the state of the synthesizer, including CPU loading, peak volume, and how many notes were stolen (i.e. from changing priority levels). An application can periodically call GetRunningStats to get the status of the synthesizer as it runs. The method outputs the data into a DMUS_SYNTHSTATS structure.

All of the running status parameters, with the exception of dwFreeMemory, are refreshed every second.

Normally, GetRunningStats is accessed by the application via a call to IDirectMusicPort::GetRunningStats, which is described in the Platform SDK documentation.


IDirectMusicSynth::Open

The Open method opens a synthesizer port.

HRESULT
  Open(
    LPDMUS_PORTPARAMS  pPortParams
    );

Parameters

pPortParams
Pointer to a DMUS_PORTPARAMS structure (described in Platform SDK documentation) with options for opening the port. If this parameter is set to NULL, default settings are used.

Return Values

Open returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error status | Description
E_POINTER | Indicates a bad pointer was passed in pPortParams.
DMUS_E_ALREADYOPEN | Indicates that the port was already opened.
DMUS_E_NOSYNTHSINK | Indicates that no sink is available for output.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

The port can be opened only once. A second attempt to open the port will fail.

Note that DirectMusic does support multiple instances of a synthesizer port. It does this by CoCreating multiple IDirectMusicSynth objects.

The port is valid until it is closed by the IDirectMusicSynth::Close method.

When opening the port, the DMUS_PORTPARAMS structure pointed to by pPortParams carries setup parameters for the port, including sample rate, stereo mode, number of voices, and more.

When opening the port, some of the parameters asked for in DMUS_PORTPARAMS might not be supported or the port might "upgrade" a parameter request (that is, return the maximum number of voices supported instead of just what was asked for). In either of these cases, the Microsoft Software Synthesizer will return S_FALSE and modify DMUS_PORTPARAMS accordingly, to show what is actually supported. Custom synths should emulate this behavior to ensure compatibility with existing code. See umsynth.cpp, which is provided with the DDK, for Open implementation.

Opening a port is not enough to enable the synthesizer. The synthesizer is enabled by opening the port AND enabling audio output through IDirectMusicSynth::Activate.

See Also

IDirectMusicSynthSink, IDirectMusicSynth::Close, IDirectMusicSynth::Download, IDirectMusicSynth::Unload, IDirectMusicSynth::PlayBuffer, IDirectMusicSynth::Activate


IDirectMusicSynth::PlayBuffer

The PlayBuffer method downloads a stream of MIDI messages to the synthesizer.

HRESULT
  PlayBuffer(
    REFERENCE_TIME  rt,
    LPBYTE  pbBuffer,
    DWORD  cbBuffer
    );

Parameters

rt
Start time of the buffer. This should be in REFERENCE_TIME units, relative to the master clock, previously set with a call to IDirectMusicSynth::SetMasterClock. And, this should be after the time returned by the clock in IDirectMusicSynth::GetLatencyClock.
pbBuffer
Memory chunk with all the MIDI messages, generated by IDirectMusicBuffer.
cbBuffer
Size of buffer.

Return Values

PlayBuffer returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error status | Description
E_POINTER | Indicates a bad buffer pointer.
DMUS_E_SYNTHNOTCONFIGURED | Indicates that the synth is not open or not properly configured.
DMUS_E_NOSYNTHSINK | Indicates that the IDirectMusicSynthSink object was not connected.
DMUS_E_SYNTHINACTIVE | Indicates that the method was called when the synth is inactive, which is not valid.
E_FAIL | Indicates that the method is unable to queue the messages.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

This is the software synthesizer's implementation of IDirectMusicPort::PlayBuffer. For more details on the buffer format, please see IDirectMusicPort::PlayBuffer.

In order to properly associate the time stamp of each MIDI message in the buffer, the synth needs to convert from the REFERENCE_TIME format to its internal sample based time. Because the wave-out stream is actually managed by IDirectMusicSynthSink, the synth calls IDirectMusicSynthSink::RefTimeToSample for each MIDI message to convert its time stamp into sample time.

So, typically, the synthesizer pulls each MIDI message from the buffer, stamps it in sample time, then places it in its own internal queue. The queue is emptied later by the rendering process, which is managed by IDirectMusicPort::Render and called by IDirectMusicSynthSink.

Also see the descriptions of the IDirectMusic, IDirectMusicPort, and IDirectMusicBuffer interfaces and the IDirectMusicPort::PlayBuffer method in the Platform SDK documentation.

See Also

IDirectMusicSynth::SetMasterClock, IDirectMusicSynth::GetLatencyClock, IDirectMusicSynth::Render, IDirectMusicSynthSink::RefTimeToSample, IDirectMusicSynthSink


IDirectMusicSynth::Render

The Render method is called by the synthesizer sink to render to the audio stream, pointed to by pBuffer.

HRESULT
  Render(
    short  * pBuffer,
    DWORD  dwLength,
    DWORD  dwPosition
    );

Parameters

pBuffer
Pointer to buffer to write into.
dwLength
Length of buffer, in samples. This is not the memory size of the buffer. The memory size can vary, dependent on the buffer format, which the synth sets when in response to an IDirectMusicSynth::Activate command.
dwPosition
Position in the audio stream, in samples. This value should always increment by dwLength after each call.

Return Value

Render returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error status | Description
E_FAIL | Indicates that the method failed.
E_POINTER | Indicates a bad buffer.
DMUS_E_SYNTHNOTCONFIGURED | Indicates that the synth is not open or not properly configured.
DMUS_E_SYNTHINACTIVE | Indicates that the method is not valid when synth is inactive.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

Typically, a synthesizer manages converting messages into rendered wave data in two processes. First, it time stamps the MIDI messages it receives from the application via calls to IDirectMusicSynth::PlayBuffer and places them in its own internal queue. Then, in response to Render, it generates audio by pulling MIDI messages from the queue and synthesizing the appropriate tones within the time span of the requested render buffer.

As the synthesizer renders the MIDI messages into the buffer, it calls IDirectMusicSynthSink::RefTimeToSample to translate the MIDI time stamps into sample positions. This guarantees extremely accurate timing (as long as the IDirectMusicSynthSink implementation is well written.)

Also see the description of the IDirectMusic interface in the Platform SDK documentation.

See Also

IDirectMusicSynth::Activate, IDirectMusicSynth::PlayBuffer, IDirectMusicSynthSink::RefTimeToSample


IDirectMusicSynth::SetChannelPriority

The SetChannelPriority method is used to set the priority of a MIDI channel.

HRESULT
  SetChannelPriority(
    DWORD  dwChannelGroup,
    DWORD  dwChannel,
    DWORD  dwPriority
    );

Parameters

dwChannelGroup
Group the channel is in. This value should be one or greater.
dwChannel
Index of the channel on the group.
dwPriority
The priority ranking of the channel. For a list of the ranking values that are defined for this parameter, see the IDirectMusicPort::GetChannelPriority reference page in the Platform SDK documentation.

Return Values

SetChannelPriority returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

This is implemented to support the MIDI synthesis engine and allows the allocated voices to run at different priorities depending on which channel they are on. Sometimes voices are freed when there are too many to deal with at one time and they are kicked out based on priority of the channel they are on. If a voice comes in on a higher priority channel, and there are no more free voices, the MIDI synthesis engine will steal from the lowest priority voice and re-assign the channels.

Also see the description of the IDirectMusicPort::GetChannelPriority and IDirectMusicPort::SetChannelPriority methods in the Platform SDK documentation.

See Also

IDirectMusicSynth::GetChannelPriority


IDirectMusicSynth::SetMasterClock

The SetMasterClock method provides the synthesizer with a master time source, required for synchronization with the rest of DirectMusic.

HRESULT
  SetMasterClock(
    IReferenceClock*  pClock
    );

Parameters

pClock
Pointer to master IReferenceClock (defined in Platform SDK documentation) object, which is used by all devices in the current instance of DirectMusic.

Return Value

SetMasterClock returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error status | Description
E_POINTER | Indicates a bad interface pointer.
DMUS_E_SYNTHNOTCONFIGURED | Indicates that the synth is not open or not properly configured.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

The synthesizer wave out device, which is managed by IDirectMusicSynthSink, can not function until it has received a master clock to synchronize to. It phase locks its own internal clock to the master clock, and is thus able to provide timing information to the synthesizer so it can make sense of the time stamps it receives in the calls to IDirectMusicSynth::PlayBuffer.

In most implementations, SetMasterClock does little more than pass the master clock to the IDirectMusicSynthSink with a call to IDirectMusicSynthSink::SetMasterClock.

The master clock is very different from the latency clock, which is retrieved from the synth with a call to IDirectMusicSynth::GetLatencyClock. While the master clock provides the time base, the latency clock simply tracks the progress of the synthesizer's render engine. This enables the application to know the earliest time that it can submit an event for playback by calling the PlayBuffer method. The latency clock is tightly synchronized to the master clock, so its units are relative.

You can measure the latency of the synthesizer by comparing the time of the latency clock with the master clock. Note that the latency clock will have jitter, reflecting the bursts of synthesizer mixing, while the master clock should increment smoothly. Latency should not exceed 450 milliseconds.

Also see the description of the IDirectMusic interface in the Platform SDK documentation.

See Also

IDirectMusicSynthSink, IDirectMusicSynth::PlayBuffer, IDirectMusicSynthSink::SetMasterClock, IDirectMusicSynth::GetLatencyClock


IDirectMusicSynth::SetNumChannelGroups

The SetNumChannelGroups method instructs the synthesizer to reset its number of channel groups.

HRESULT
  SetNumChannelGroups(
    DWORD  dwGroups
    );

Parameters

dwGroups
Number of channel groups requested.

Return Value

SetNumChannelGroups returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error status | Description
DMUS_E_SYNTHNOTCONFIGURED | Indicates that the synth is not open or not properly configured.
E_FAIL | Indicates that the method is unable to allocate the channel groups.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

Even though IDirectMusicSynth::Open tells the port how many channel groups to create, the application might later need to dynamically increase or reduce the number with a call to SetNumChannelGroups.

Each channel group supports a set of 16 MIDI channels. For example, if dwChannelGroups is set to three, the synthesizer creates 48 channels.

Also see the description of the IDirectMusic interface in the Platform SDK documentation.

See Also

IDirectMusicSynth::Open


IDirectMusicSynth::SetSynthSink

The SetSynthSink method establishes the connection of the synth to the wave sink.

HRESULT
  SetSynthSink(
    IDirectMusicSynthSink  * pSynthSink
    );

Parameters

pSynthSink
The IDirectMusicSynthSink sink object to connect to synth, or NULL to disconnect.

Return Value

SetSynthSink returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error status | Description
E_POINTER | Indicates that a bad pointer was passed in pSynthSink.
E_FAIL | Indicates that the method failed because it was unable to connect to the IDirectMusicSynthSink object.
E_OUTOFMEMORY | Indicates that not enough memory is available to establish the connection.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

Before the synthesizer can expose much of its functionality, it should be connected to a wave sink object, which is represented by the IDirectMusicSynthSink interface. The IDirectMusicSynth::SetSynthSink method establishes this connection.

The IDirectMusicSynthSink object does the work of actually connecting up to the ultimate audio destination, which might be DirectSound, Win32® wave audio, or some other audio stream. The default implementation sends data to DirectSound.

This approach allows a synthesizer to connect to many different styles of audio out without special code within the synthesizer itself. This makes it very easy to connect one synthesizer implementation to any available wave-out device.

Also see the description of the IDirectMusic interface in the Platform SDK documentation.

See Also

IDirectMusicSynthSink


IDirectMusicSynth::Unload

The Unload method unloads a wave or instrument definition that was previously downloaded by a call to IDirectMusicSynth::Download.

HRESULT
  Unload(
    HANDLE  hDownload,
    HRESULT (CALLBACK  *lpFreeHandle),
    HANDLE  hUserData
    );

Parameters

hDownload
Handle to data, obtained by a call to the IDirectMusicSynth::Download method.
HRESULT ( CALLBACK *lpFreeHandle)
lpFreeHandle is a pointer to a callback function that will be called when the memory is no longer in use. If the original call to IDirectMusicSynth::Download returned FALSE in pbFree, the synthesizer hung onto the memory in the download chunk. If so, the caller should be notified once the memory can be freed, but that could occur later than Unload because a wave might be currently in use.
hUserData
Pointer to user data, passed as a parameter to the lpFreeHandle function, typically used so the callback routine can retrieve its state.

Return Value

Unload returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error status | Description
E_FAIL | Indicates that the method is unable to unload data (hDownload probably invalid).
DMUS_E_SYNTHNOTCONFIGURED | Indicates that the synth is not open or not properly configured.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

If the downloaded memory was used by the synthesizer (and indicated by returning FALSE in pbFree after the call to IDirectMusicSynth::Download),) the callback routine lpFreeHandle should be provided to release the memory. The memory can not be released immediately if it is currently being used to render a note. Once the note finishes, lpFreeHandle is called by the synthesizer, indicating the memory can finally be freed.

Also see the descriptions of the IDirectMusic and IDirectMusicPort interfaces and the IDirectMusicPort::UnloadInstrument method in the Platform SDK documentation.

See Also

IDirectMusicSynth::Download


IDirectMusicSynthSink

The IDirectMusicSynthSink interface represents a streaming wave device that pulls audio from the software synthesizer. By separating IDirectMusicSynth from IDirectMusicSynthSink, the application can take the output of any synthesizer and feed it to an audio device of its choosing. IDirectMusicSynthSink inherits from the IUnknown interface.

The default implementation of IDirectMusicSynthSink feeds the wave data into DirectSound. However, you are free to create your own IDirectMusicSynthSink and use it to manage the audio-output stream in any way you like; for example, to Win32 waveform audio or to DirectShow. If you create a wave stream object, it should have an IDirectMusicSynthSink interface to plug into the IDirectMusicSynth.

In addition to managing the wave stream, the sink owns the timing for the synthesizer. It receives the master clock by a call to IDirectMusicSynth::SetMasterClock, which passes the master time source on with an identical call to IDirectMusicSynthSink::SetMasterClock. Because the master clock cannot be from the same crystal as the streaming wave, the sink must keep them synchronized.

Additionally, so that the synthesizer can keep track of time appropriately, it provides two calls to convert from master clock time to sample time and back: IDirectMusicSynthSink::RefTimeToSample and IDirectMusicSynthSink::SampleToRefTime.

The sink generates the latency clock because it actually manages the times at which samples get written by calls to IDirectMusicSynth::Render. When DirectMusic calls IDirectMusicSynth::GetLatencyClock on the port, it simply turns around and calls IDirectMusicSynthSink::GetLatencyClock.

When a software synthesizer is first opened, it is given a sample rate and number of channels (stereo or mono) in the DMUS_PORTPARAMS structure. It then converts these into a standard WAVEFORMATEX structure that it passes to the sink when the sink calls the IDirectMusicSynth::GetFormat method.

The methods of the IDirectMusicSynthSink interface can be organized in the following groups:

Initialization | Activate
 | GetDesiredBufferSize
 | Init
 | SetDirectSound
Timing | GetLatencyClock
 | RefTimeToSample
 | SampleToRefTime
 | SetMasterClock

All COM interfaces inherit the IUnknown interface methods. This interface supports the following three methods:

AddRef
QueryInterface
Release


IDirectMusicSynthSink::Activate

The Activate method activates or deactivates the synthesizer sink.

HRESULT
  Activate(
    BOOL  fEnable
    );

Parameters

fEnable
TRUE to activate and FALSE to deactivate audio.

Return Values

Activate returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error status | Description
E_FAIL | Indicates that the method is unable to activate or deactivate the synth sink.
DMUS_E_SYNTHNOTCONFIGURED | Indicates that the synth is not set or not properly configured.
DMUS_E_SYNTHACTIVE | Indicates that the sink is already active.
DMUS_E_DSOUND_NOT_SET | Indicates that SetDirectSound hasn't been called successfully.
DMUS_E_NO_MASTER_CLOCK | Indicates that SetMasterClock hasn't been called successfully.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

The synthesizer itself can be told to enable or disable the audio device. In turn, it calls the synth sink, which manages the audio device. This gives the application the ability to manage its use of resources. When it is not playing music, it can deactivate, and so free the wave-out device for other applications.

Also see the description of the IDirectMusic interface in the Platform SDK documentation.

See Also

IDirectMusicSynth, IDirectMusicSynth::Activate


IDirectMusicSynthSink::GetDesiredBufferSize

The GetDesiredBufferSize method retrieves the buffer size, in samples, desired by the synthesizer.

HRESULT
  GetDesiredBufferSize(
    LPDWORD  pdwBufferSizeInSamples
    )

Parameters

pdwBufferSizeInSamples
Address of a variable to receive the desired buffer size.

Return Values

GetDesiredBufferSize returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error status | Description
DMUS_E_SYNTHNOTCONFIGURED | Indicates that the synth is not set.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

The GetDesiredBufferSize method returns the desired buffer size based on the current format of the synth. DirectSound buffers passed to IDirectMusicSynthSink::SetDirectSound might be invalid unless they are at least this size.

Also see the description of the IDirectMusicPort interface in the Platform SDK documentation.

See Also

IDirectMusicSynthSink::SetDirectSound


IDirectMusicSynthSink::GetLatencyClock

The GetLatencyClock method retrieves the latency clock, which measures the progress of the output audio stream.

HRESULT
  GetLatencyClock(
    IReferenceClock  ** ppClock
    );

Parameters

ppClock
Returned IReferenceClock interface for latency clock.

Return Values

GetLatencyClock returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error status | Description
E_FAIL | Indicates that the method is unable to access latency clock.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

The latency IReferenceClock returns the current render time whenever its IReferenceClock::GetTime method is called. This time is always relative to the time established by the master clock, installed in the synth sink by using IDirectMusicSynthSink::SetMasterClock. The latency time is used by the performance layer of DirectMusic to identify the next available time to start playing a note.

Also see the descriptions of the IReferenceClock and IDirectMusic interfaces in the Platform SDK documentation.

See Also

IDirectMusicSynth, IDirectMusicSynth::SetMasterClock


IDirectMusicSynthSink::Init

The Init method initializes the sink.

HRESULT
  Init(
    IDirectMusicSynth  * pSynth
    );

Parameters

pSynth
Pointer to the IDirectMusicSynth to which to connect.

Return Values

Init returns S_OK if the call is successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

When a synthesizer is connected to a sink by a call to IDirectMusicSynth::SetSynthSink, the synthesizer calls Init.

In order to avoid cyclical references, the IDirectMusicSynthSink does not increment the reference count of its IDirectMusicSynth. Instead, it abides by the rule that IDirectMusicSynth is always the parent and will always release the IDirectMusicSynthSink when it is done with it.

Once connected, the synth sink needs to be activated with a call to IDirectMusicSynthSink::Activate. At this point it starts generating wave buffers, which it passes to the synthesizer by calling IDirectMusicSynth::Render.

Also see the description of the IDirectMusic interface in the Platform SDK documentation.

See Also

IDirectMusicSynth, IDirectMusicSynth::SetSynthSink, IDirectMusicSynth::Render, IDirectMusicSynth::Activate, IDirectMusicSynthSink::Activate


IDirectMusicSynthSink::RefTimeToSample

The RefTimeToSample method converts a reference time to a sample time.

HRESULT
  RefTimeToSample(
    REFERENCE_TIME  rfTime,
    DWORD  * pdwSampleTime
    );

Parameters

rfTime
Reference time. Measured in 100-nanosecond units.
pdwSampleTime
Pointer to a location to which the method outputs the sample time.

Return Values

RefTimeToSample returns S_OK if the call is successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

The RefTimeToSample method converts reference time to sample time. Sample time is relative to the sampling frequency. For example, if the output buffer is in a 44.2 kHz format, a sample time of 44,200 is equivalent to one second.

The synth sink manages the timing relationship between the master clock (set with a call to IDirectMusicSynthSink::SetMasterClock) and the audio stream.

See Also

IDirectMusicSynthSink::SetMasterClock, IDirectMusicSynthSink::SampleToRefTime


IDirectMusicSynthSink::SampleToRefTime

The SampleToRefTime method converts a sample time to a reference time.

HRESULT
  SampleToRefTime(
    DWORD  dwSampleTime,
    REFERENCE_TIME  * prfTime
    );

Parameters

dwSampleTime
Sample time.
prfTime
Pointer to a location to which the method outputs the reference time.

Return Values

SampleToRefTime returns S_OK if the call is successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

The SampleToRefTime method converts sample time to reference time. Sample time is expressed as the number of samples rendered, and reference time is measured in 100-nanosecond units.

The synth sink manages the timing relationship between the master clock (set with a call to IDirectMusicSynthSink::SetMasterClock) and the audio stream.

See Also

IDirectMusicSynthSink::SetMasterClock, IDirectMusicSynthSink::RefTimeToSample


IDirectMusicSynthSink::SetDirectSound

The SetDirectSound method connects the synthesizer sink with an existing DirectSound object and a DirectSound buffer.

HRESULT
  SetDirectSound(
    LPDIRECTSOUND  pDirectSound,
    LPDIRECTSOUNDBUFFER  pDirectSoundBuffer
    );

Parameters

pDirectSound
This is a pointer to an IDirectSound interface with which to associate the sink.
pDirectSoundBuffer
This is a pointer to an IDirectSoundBuffer interface with which to associate the sink. This value can be NULL.

Return Values

SetDirectSound returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error status | Description
DMUS_E_SYNTHNOTCONFIGURED | Indicates that the synth not set.
DMUS_E_SYNTHACTIVE | Indicates that the sink is active.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

The IDirectSound instance is received from IDirectMusicPort::SetDirectSound and might not be NULL.

If pDirectSoundBuffer is NULL, the primary buffer for IDirectSound will be upgraded, if necessary, to support the sample rate and channel information for the sink (obtained from IDirectMusicSynth::GetFormat).

The IDirectSoundBuffer should be a secondary streaming buffer with a format that matches that obtained from the synthesizer. If pDirectSoundBuffer is NULL, then an appropriate IDirectSoundBuffer instance will be created internally.

Neither the IDirectSound nor the IDirectSoundBuffer instance can be changed once the sink has been activated.

Also see the descriptions of the IDirectMusic and IDirectMusicPort interfaces in the Platform SDK documentation.

See Also

IDirectMusicSynth::GetFormat


IDirectMusicSynthSink::SetMasterClock

The SetMasterClock method provides the synth sink with a master time source, which is required for synchronization with the rest of DirectMusic.

HRESULT
  SetMasterClock(
    IReferenceClock  * pClock
    );

Parameters

pClock
Master clock to which to synchronize.

Return Values

SetMasterClock returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code. The table below shows some of the possible error codes.

Error status | Description
E_FAIL | Indicates that the method is unable to accept clock.

Headers

Declared in dmusics.h. Include dmusics.h.

Comments

The synth sink cannot function until it has received a master clock to synchronize the streaming wave with the rest of DirectMusic.

Because the master time and sample time might be driven by different crystals, they can drift apart. The synth sink can lock its understanding of the current sample time to the master time with a phase-locked loop.

The master clock is different from the latency clock, which is retrieved from the synth sink with a call to IDirectMusicSynth::GetLatencyClock. While the master clock provides the time base, the latency clock simply tracks the progress of the rendering of notes into the wave stream. This enables the application to know the earliest time it can submit a message for playback by using the IDirectMusicSynth::PlayBuffer method. The latency clock should be tightly synchronized to the master clock, so its units are relative.

You can measure the latency of the synthesizer by comparing the time of the latency clock with the master clock. Note that the latency clock will have jitter, reflecting the bursty nature of synthesizer mixing (each call to IDirectMusicSynth::Render jumps forward by the buffer length). In contrast, the master clock increments smoothly.

See Also

IDirectMusicSynth::GetLatencyClock, IDirectMusicSynth::PlayBuffer, IDirectMusicSynth::Render


DirectMusic Kernel Mode Interfaces

This section contains references for the following DirectMusic interfaces:

IAllocatorMXF (provided by PortDMus)

IMasterClock (provided by PortDMus)

IMiniportDMus (provided by adapter driver)

IMusicTechnology (provided by PortDMus)

IMXF (provided by both adapter driver and PortDMus)

IPortDMus (provided by PortDMus)

ISynthSinkDMus (provided by adapter driver)


IAllocatorMXF

The IAllocatorMXF interface is used for DirectMusic miniport streams. It is the entry point to the allocator that allocates and manages the reuse of DMUS_KERNEL_EVENT structures.

The allocator also abstracts the allocation of memory for large events. The uData member of DMUS_KERNEL_EVENT is a union that is the size of a pointer (four bytes on a 32-bit system and eight bytes on a 64-bit system). If the data is small enough to fit in that space, then uData will contain the actual MIDI data. But if the data for that event is larger than the four (or eight) bytes, then the cbEvent member will indicate this and therefore uData will contain a pointer to a buffer rather than actual MIDI data. This buffer is managed by the allocator and will be a constant size for any port implementation.

The port driver calls IMiniportDMus::NewStream to obtain a reference to the IAllocatorMXF interface of the memory allocator. IAllocatorMXF inherits from the IMXF interface.

DECLARE_INTERFACE_(IAllocatorMXF,IMXF)
{
    STDMETHOD(GetMessage)
    (   THIS_
        OUT     PDMUS_KERNEL_EVENT * ppDMKEvt
    )   PURE;

    STDMETHOD_(USHORT,GetBufferSize)
    (   THIS
    )   PURE;

    STDMETHOD(GetBuffer)
    (   THIS_
        OUT     PBYTE * ppbBuffer
    )   PURE;

    STDMETHOD(PutBuffer)
    (   THIS_
        IN      PBYTE   pbBuffer
    )   PURE;
};


IAllocatorMXF::GetMessage

The GetMessage method serves as the retrieval point for any DirectMusic kernel-mode component that utilizes the port's allocator to reuse DMUS_KERNEL_EVENT structures.

HRESULT
  GetMessage(
    OUT PDMUS_KERNEL_EVENT  * ppDMKEvt
    );

Parameters

ppDMKEvt
Pointer to a pointer to the event structure being retrieved. Contains the event to be captured.

Return Value

GetMessage returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in dmusicks.h. Include dmusicks.h.

Comments

The miniport will use this method to retrieve event structures for MIDI capture. This retrieves a DMUS_KERNEL_EVENT structure from the same pool that IMXF::PutMessage puts to when it discards them to the allocator. The port will retrieve events when prompted by the usual Service DPC.

See Also

DMUS_KERNEL_EVENT, IMXF::PutMessage


IAllocatorMXF::GetBufferSize

The GetBufferSize method gets the buffer size from the allocator.

USHORT
  GetBufferSize(
  VOID
    );

Parameters

None

Return Value

GetBufferSize returns the size in bytes of the buffer.

Headers

Declared in dmusicks.h. Include dmusicks.h.

Comments

GetBufferSize simply returns the size of the buffer that the allocator provides. (For more information, see IAllocatorMXF introduction.) Because this is constant for any version of the port, GetBufferSize will normally only need to be called once, usually when the miniport stream is created.


IAllocatorMXF::GetBuffer

The GetBuffer method returns a pointer to a buffer. The miniport calls this method only when it needs to send large chunks of data to the capture sink.

HRESULT
  GetBuffer(
    OUT PBYTE  *ppbBuffer
    );

Parameter

ppbBuffer
Returns a pointer to the buffer being requested.

Return Value

GetBuffer returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in dmusicks.h. Include dmusicks.h.

Comments

This method is used whenever a component needs to package more data than can be stored in the uData member of DMUS_KERNEL_EVENT. The allocator returns a pointer to a buffer when GetBuffer is called. The size of this buffer is determined by calling IAllocatorMXF::GetBufferSize. This will only need to be done once because the buffer size is constant for any allocator implementation.

See Also

DMUS_KERNEL_EVENT, IAllocatorMXF::GetBufferSize.


IAllocatorMXF::PutBuffer

This method is not currently used by the miniport. The PutBuffer method passes a buffer to the allocator, but this occurs automatically when IMXF::PutMessage is called anyway.

HRESULT
  PutBuffer(
    IN PBYTE  pbBuffer
    );

Parameter

pbBuffer
Pointer to a buffer being handed to the allocator.

Return Value

PutBuffer returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in dmusicks.h. Include dmusicks.h.

Comments

This method does not need to be used by the miniport because when it does a IMXF::PutMessage to the allocator, the allocator will look at the cbEvent member of the DMUS_KERNEL_EVENT structure to determine if uData is a pointer or just data. If cbEvent specifies that the event data is greater than the storage capacity of uData (4 bytes on a 32 bit system and 8 bytes on a 64 bit system), then it will know that uData points to a buffer that can be reused.

See Also

IMXF::PutMessage, DMUS_KERNEL_EVENT


IMasterClock

The IMasterClock interface is implemented in the port to support timing in the IMFX interfaces that make up the MIDI transport part of the filter graph. IMasterClock inherits from the IUnknown interface.

DECLARE_INTERFACE_(IMasterClock,IUnknown)
{
    STDMETHOD(GetTime)
    (   THIS_
        OUT     REFERENCE_TIME  * prtTime
    )   PURE;
};


IMasterClock::GetTime

The GetTime method returns the current reference time read from the master clock.

HRESULT
  GetTime(
    OUT REFERENCE_TIME  *prtTime
    );

Parameter

prtTime
Pointer to the reference time. Reference time is measured in 100-nanosecond units.

Return Value

GetTime returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in dmusicks.h. Include dmusicks.h.

Comments

A pointer to the master clock is handed to the miniport when a miniport stream is created with IMiniportDMus::NewStream. This is used to determine the reference time by calling GetTime.

See Also

IMiniportDMus::NewStream


IMiniportDMus

The IMiniportDMus interface inherits from IMiniport and is the main interface that is implemented by a synthesizer miniport. It is defined as follows:

DECLARE_INTERFACE_(IMiniportDMus,IMiniport)
{
    STDMETHOD(Init)
    (   THIS_
        IN      PUNKNOWN        pUnknownAdapter,
        IN      PRESOURCELIST   pResourceList,
        IN      PPORTDMUS       pPort,
        OUT     PSERVICEGROUP * ppServiceGroup
    )   PURE;

    STDMETHOD_(void,Service)
    (   THIS
    )   PURE;

    STDMETHOD(NewStream)
    (   THIS_
        OUT     PMXF                  * ppMXF,
        IN      PUNKNOWN                pOuterUnknown    OPTIONAL,
        IN      POOL_TYPE               PoolType,
        IN      ULONG                   uPin,
        IN      DMUS_STREAM_TYPE        StreamType,
        IN      PKSDATAFORMAT           pDataFormat,
        OUT     PSERVICEGROUP         * ppServiceGroup,
        IN      PAllocatorMXF           pAllocatorMXF,
        IN      PMASTERCLOCK            pMasterClock,
        OUT     PULONGLONG              puuSchedulePreFetch
    )   PURE;
};


IMiniportDMus::Init

The Init method initializes the miniport. Callers of Init should run at IRQL PASSIVE_LEVEL.

HRESULT
  Init(
    IN PUNKNOWN  pUnknownAdapter,
    IN PRESOURCELIST  pResourceList,
    IN PPORTDMUS  pPort
    OUT PSERVICEGROUP  * ppServiceGroup,
    );

Parameters

pUnknownAdapter
Pointer to the IUnknown of the adapter object on whose behalf this miniport is being created.
pResourceList
Pointer to an IResourceList object that contains the resource list that is to be supplied to the miniport during initialization. After passing this reference to the miniport, the port driver is free to examine the contents of the resource list but will not modify the contents of the resource list.
pPort
Pointer to an IPortDMus object that provides the port driver's callback interface.
ppServiceGroup
Pointer to a location to which the method outputs a pointer to the IServiceGroup interface of the miniport's service-group object. This is the service group that this miniport wants to have used for calls to IPortDMus::Notify.

Return Value

Init returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in dmusicks.h. Include dmusicks.h.

See Also

IResourceList, IPortDMus, IServiceGroup, IPortDMus::Notify


IMiniportDMus::Service

This method does not currently need to be implemented in the miniport. The Service method is currently unused.

VOID
  Service(
  VOID
    );

Parameters

None

Return Value

None

Headers

Declared in dmusicks.h. Include dmusicks.h.

Comments

Service was intended to be called during a DPC and was to be executed as the result of a call of the IPortDMus::Notify method. Instead PortDMus calls IMXF::PutMessage on the miniport's input stream with a NULL parameter to accomplish this, so Service is currently unused.

Also See

IPortDMus::Notify, IMXF::PutMessage


IMiniportDMus::NewStream

The NewStream method creates a new instance of a logical stream associated with a specified physical channel. Callers of NewStream should run at IRQL PASSIVE_LEVEL.

HRESULT
  NewStream(
    OUT PMXF  * ppMXF,
    IN PUNKNOWN  pOuterUnknown  OPTIONAL,
    IN POOL_TYPE  PoolType,
    IN ULONG  uPinId,
    IN DMUS_STREAM_TYPE  StreamType,
    IN PKSDATAFORMAT  pDataFormat,
    OUT PSERVICEGROUP  * ppServiceGroup,
    IN PAllocatorMXF  pAllocatorMXF,
    IN PMASTERCLOCK  pMasterClock,
    OUT PULONGLONG  puuSchedulePreFetch
    );

Parameters

ppMXF
Pointer to a location to which the method outputs a pointer to the stream object's IMXF interface.
pOuterUnknown (optional)
Pointer to the IUnknown interface of an object that needs to aggregate the stream object. Unless aggregation is desired, this parameter will be NULL.
PoolType
Specifies the type of memory pool from which the storage for the DMA-channel object should be allocated. See POOL_TYPE.
uPinId
Identifies the pin. (Not currently used.)
StreamType
Specifies the type of data stream with one of the following enumeration values:
DMUS_STREAM_MIDI_INVALID
Specifies that a stream is invalid for MIDI.
DMUS_STREAM_MIDI_RENDER
Specifies an output (playback) stream.
DMUS_STREAM_MIDI_CAPTURE
Specifies an input stream.
DMUS_STREAM_WAVE_SINK
Specifies a wave out stream.
pDataFormat
Pointer to the kernel streaming KSDATAFORMAT structure specifying the format to use for this instance.
ppServiceGroup
Pointer a location to which the method is to output a pointer to the IServiceGroup interface of the stream's service-group object. This is the service group that is being registered for interrupt notification.
pAllocatorMXF
Pointer to an IAllocatorMXF objext. This is the port's memory allocator, which is needed to recycle DMUS_KERNEL_EVENT structures.
pMasterClock
Pointer to an IMasterClock object. This master clock passes a wrapper for the KS clock to the miniport. The master-clock pointer is required to sync to reference time.
puuSchedulePreFetch
This is how far ahead to query for events. The time is specified in 100-nanosecond units. The port has the responsibility of sequencing events that exceed the amount of time that the miniport specifies here.

Return Value

NewStream returns S_OK if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in dmusicks.h. Include dmusicks.h.

Also See

IMXF, POOL_TYPE, KSDATAFORMAT, IServiceGroup, IAllocatorMXF, DMUS_KERNEL_EVENT, IMasterClock


IMusicTechnology

In Microsoft Windows XP and later, the IMusicTechnology interface is supported by the FMSynth, DMusUART, and UART miniports. These are system-supplied miniport drivers that are contained in portcls.sys. The IMusicTechnology interface is obtained by calling the miniport's QueryInterface method.

This interface is used to change the DirectMusic technology that is specified in the Technology member in the KSDATARANGE_MUSIC structures that specify the data ranges for the miniport's pins.

During a call to the Windows Multimedia midiOutGetDevCaps function, the WDMAud system driver converts the GUID in the Technology member to the corresponding integer constant that is loaded into the wTechnology member of the MIDIOUTCAPS structure that is output by the function.


IMusicTechnology::SetTechnology

The SetTechnology method changes the Technology member of each KSDATARANGE_MUSIC structure in the data ranges for the miniport's pins. This method should be called before the miniport's Init method. If SetTechnology is not called, the miniport's Technology members are all set to KSMUSIC_TECHNOLOGY_PORT by default.

Callers of SetTechnology should run at IRQL_PASSIVE_LEVEL.

HRESULT SetTechnology(
    IN const GUID* Technology
    );

Parameters

Technology
This parameter should be set to one of the GUIDs that are defined for the Technology member of the KSDATARANGE_MUSIC structure.

Return Value

SetTechnology returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

The following table lists the GUIDs that are defined for the Technology parameter and the corresponding integer value to which the wTechnology member of the MIDIOUTCAPS structure is set during a call to midiOutGetDevCaps.

Technology GUID | MIDIOUTCAPS.wTechnology
KSMUSIC_TECHNOLOGY_PORT | MOD_MIDIPORT
KSMUSIC_TECHNOLOGY_SQSYNTH | MOD_SQSYNTH
KSMUSIC_TECHNOLOGY_FMSYNTH | MOD_FMSYNTH
KSMUSIC_TECHNOLOGY_WAVETABLE | MOD_WAVETABLE
KSMUSIC_TECHNOLOGY_SWSYNTH | MOD_SWSYNTH

Example

The following example demonstrates how to use the IMusicTechnology interface to change the DirectMusic technology specified for the built-in PortCls DMusUART miniports.

The sample code below changes the DirectMusic technology GUID to KSMUSIC_TECHNOLOGY_WAVETABLE.

// Create the miniport.
PUNKNOWN miniport;

ntStatus = PcNewMiniport((PMINIPORT*)&miniport, CLSID_MiniportDriverDMusUART);

// Query the miniport for the IMusicTechnology interface.
IMusicTechnology* pMusicTechnology;

if (NT_SUCCESS(ntStatus))
{
    ntStatus = miniport->QueryInterface(IID_IMusicTechnology, (PVOID*)&pMusicTechnology);
}

// Set the Technology members in the DirectMusic data-range entries
// for all the pins that are exposed by this miniport.
// SetTechnology should be called before initializing the miniport.
if (NT_SUCCESS(ntStatus))
{
    ntStatus = pMusicTechnology->SetTechnology(&KSMUSIC_TECHNOLOGY_WAVETABLE);
}

See Also

KSDATARANGE_MUSIC


IMXF

The IMXF interface represents the stream on a DirectMusic MIDI transport filter. MIDI transport occurs through IMXF, which is the miniport's primary interface for managing DirectMusic streams. IMXF inherits from the IUnknown interface.

See MIDI Transport for more information.

DECLARE_INTERFACE_(IMXF,IUnknown)
{
    STDMETHOD(SetState)
    (   THIS_
        IN      KSSTATE kState
    )   PURE;

    STDMETHOD(PutMessage)
    (   THIS_
        IN      PDMUS_KERNEL_EVENT  pDMKEvt
    )   PURE;

    STDMETHOD(ConnectOutput)
    (   THIS_
        IN      PMXF    pSinkMXF
    )   PURE;

    STDMETHOD(DisconnectOutput)
    (   THIS_
        IN      PMXF    pSinkMXF
    )   PURE;
};


IMXF::SetState

The SetState method is used to set state information for MIDI transform interfaces.

NTSTATUS
  SetState(
  IN KSSTATE  kState
    );

Parameter

kState
The state that the filter graph is to be set to.

Return Value

SetState returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in dmusicks.h. Include dmusicks.h.

Comments

The following KSSTATE enumeration values are defined for the kState parameter:

  • KSSTATE_RUN

    Everything is running and functioning as normal. In this state, the IMXF interface will be active and pass messages as usual.

  • KSSTATE_ACQUIRE

    This is a transitional state that helps manage the transition between KSSTATE_RUN and KSSTATE_STOP. In this state, messages cannot be passed downstream in the filter graph.

  • KSSTATE_PAUSE

    This is a transitional state that helps manage the transition between KSSTATE_RUN and KSSTATE_STOP.

  • KSSTATE_STOP

    Everything is stopped in the current filter graph.

The behavior of the miniport depends on the state of the filter graph. This behavior differs for render (output) and capture (input).

On the output side, if the current state is anything other than KSSTATE_RUN, the IMXF interface should hold onto the data and not pass it to the hardware. If the current state is KSTATE_STOP then the miniport should discard any data it is given by passing that data to the allocator.

On the input side, if the input stream is in either KSSTATE_RUN or KSSTATE_PAUSE, it is legal for the miniport to get messages from the allocator and send them upstream to the capture sink. If the state is KSSTATE_STOP or KSSTATE_ACQUIRE and the hardware is trying to produce data, that data should be thrown away.

See Also

KSPROPERTY_CONNECTION_STATE


IMXF::PutMessage

The PutMessage method passes a DMUS_KERNEL_EVENT structure to its next destination. The miniport uses this method to discard used event structures so that they can be recycled by the allocator.

NTSTATUS
  PutMessage(
    IN PDMUS_KERNEL_EVENT  pDMKEvt
    );

Parameter

pDMKEvt
Pointer to the DMUS_KERNEL_EVENT structure being passed to its destination.

Return Value

PutMessage returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in dmusicks.h. Include dmusicks.h.

Comments

This method is used by the miniport during rendering to discard used DMUS_KERNEL_EVENT structures to the allocator for reuse. The miniport will use this method once it has extracted MIDI data from the structures for rendering.

PutMessage will also be used during MIDI capture to package and pass MIDI messages to the capture sink in PortDMus. These messages can be single, multiple, or fragmentary MIDI events and are packaged in DMUS_KERNEL_EVENT structures (which are retrieved by IAllocatorMXF::GetMessage calls).

The allocator is always the last destination in any chain, so every DMUS_KERNEL_EVENT structure will eventually be recycled. If IMXF::ConnectOutput has not been called, PutMessage will default to passing the structure to the allocator.

See Also

DMUS_KERNEL_EVENT, IAllocatorMXF::GetMessage, IMXF::ConnectOutput


IMXF::ConnectOutput

The ConnectOutput method connects this IMXF interface with the sink specified by the pSinkMXF parameter.

NTSTATUS
  ConnectOutput(
    IN PMXF  pSinkMXF
    );

Parameter

pSinkMXF
Pointer to the destination (sink) IMXF interface we are connecting to in the port.

Return Value

ConnectOutput returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in dmusicks.h. Include dmusicks.h.


IMXF::DisconnectOutput

The DisconnectOutput method disconnects this IMXF interface from the synth sink or capture sink.

NTSTATUS
  DisconnectOutput(
    IN PMXF  pSinkMXF
    );

Parameter

pSinkMFX
Pointer to the destination (sink) IMFX interface we are disconnecting from.

Return Value

DisconnectOutput returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in dmusicks.h. Include dmusicks.h.

Comments

This zeros the location that was previously filled in with IMXF::ConnectOutput. Output will go to the allocator from this point on until IMXF::ConnectOutput is called again.

See Also

IMXF::ConnectOutput


IPortDMus

The IPortDMus interface inherits from IPortMidi and adds two methods for event management. These two methods form the interface to the allocator for this port instance.

DECLARE_INTERFACE_(IPortDMus,IPort)
{
    STDMETHOD_(void,Notify)
    (   THIS_
        IN      PSERVICEGROUP   pServiceGroup    OPTIONAL
    )   PURE;

    STDMETHOD_(void,RegisterServiceGroup)
    (   THIS_
        IN      PSERVICEGROUP   pServiceGroup
    )   PURE;
};

A miniport creates an IPortDMus object by calling PcNewPort and specifying REFIID IID_IPortDMus.


IPortDMus::Notify

The Notify method should be called from the miniport's interrupt-service routine when a hardware interrupt has occurred. This call requests that the port driver call the miniport back with a DPC while the miniport handles the interrupt. Callers of Notify can run at any IRQL.

void
  Notify(
    IN PSERVICEGROUP  pServiceGroup  OPTIONAL
    );

Parameters

pServiceGroup (optional)
Pointer to an IServiceGroup object. This is the service group that is specified by either IPortDMus::RegisterServiceGroup or IMiniportDMus::Init. The service group is used to group together a set of entities in the port that should work together in a deferred procedure. This should not be needed by DirectMusic miniports.

Return Value

None

Headers

Declared in dmusicks.h. Include dmusicks.h.

Comments

When a hardware interrupt signals, for example, that some register needs to be read, the miniport can not use the MXF graph at the elevated IRQL. Instead, the miniport can store the input data (a byte of MIDI data, for example) and wait for the port to get back to it with a DPC. This happens once the IRQL drops to the DPC level (DISPATCH_LEVEL) again.

The port receives the notification at the elevated hardware interrupt IRQL and puts a DPC on the queue. When IRQL drops to the DPC level, the DPC fires and the miniport is serviced by the port.

For its DPC, the port calls IMXF::PutMessage on the miniport input stream with a parameter of NULL to signify that the miniport can now PutMessage up into the MXF graph because the IRQL has dropped back to DISPATCH_LEVEL.

Also See

IServiceGroup, IPortDMus::RegisterServiceGroup, IMiniportDMus::Init


IPortDMus::RegisterServiceGroup

This method should not need to be called from the miniport. The RegisterServiceGroup method registers a service group with the PortDMus port driver.

void
  RegisterServiceGroup(
    IN PSERVICEGROUP  pServiceGroup
    );

Parameter

pServiceGroup
Pointer to an IServiceGroup object. This is the service group that is to be registered.

Return Value

None

Headers

Declared in dmusicks.h. Include dmusicks.h.

Comments

The RegisterServiceGroup method registers a service group to be used for the IPortDMus::Notify method. Callers of RegisterServiceGroup should be run at IRQL PASSIVE_LEVEL. This method was intended to group together a set of entities in the port that should work together in a DPC so that they can all be handled at once. The miniport should not need this functionality.

See Also

IServiceGroup, IPortDMus::Notify


ISynthSinkDMus

The ISynthSinkDMus interface handles wave output for the synth. This interface is provided by the miniport for the synth sink to call into to render wave output. ISynthSinkDMus inherits from the IMXF interface.

The ISynthSinkDMus interface contains methods to render, convert sample to reference time, convert reference to sample time, and sync to the master clock.

DECLARE_INTERFACE_(ISynthSinkDMus,IMXF)
{
    STDMETHOD_(void,Render)
    (   THIS_
        IN      PBYTE       pbBuffer,
        IN      DWORD       dwLength,
        IN      LONGLONG    llPosition
    )   PURE;

    STDMETHOD(SyncToMaster)
    (   THIS_
        IN      REFERENCE_TIME  rtTime,
        IN      BOOL            fStart
    )   PURE;

    STDMETHOD(SampleToRefTime)
    (   THIS_
        IN      LONGLONG         llSampleTime,
        OUT     REFERENCE_TIME * prtTime
    )   PURE;

    STDMETHOD(RefTimeToSample)
    (   THIS_
        IN      REFERENCE_TIME  rtTime,
        OUT     LONGLONG *      pllSampleTime
    )   PURE;
};

Also see DirectMusic Synths and Synth Sinks for more information about rendering, clocks, and clock synchronization.


ISynthSinkDMus::Render

The Render method renders wave data into a destination sink.

void
  Render(
    IN PBYTE  pbBuffer,
    IN DWORD  dwLength,
    IN LONGLONG  llPosition
    );

Parameters

pbBuffer
Pointer to the buffer the synth sink wants data written to.
dwLength
Specifies the length (in bytes) of the requested data to be rendered.
llPosition
Specifies the position (in bytes) in the PCM buffer at which to begin rendering. Rendering continues from this point for the specified dwLength.

Return Value

None

Headers

Declared in dmusicks.h. Include dmusicks.h.

Comments

The port's synth sink calls this method when the miniport needs to render wave data into the destination buffer.


ISynthSinkDMus::SyncToMaster

The SyncToMaster method allows synchronization to the master clock in order to avoid drift.

HRESULT
  SyncToMaster(
    IN REFERENCE_TIME  rtTime,
    IN BOOL  fStart
    );

Parameters

rtTime
Pointer to the reference time from the master clock. The reference time is measured in 100-nanosecond units.
fStart
Specifies whether the sample clock is to be reset to zero with this reference time. TRUE indicates that the sample clock should reset to zero at time rtTime.

Return Value

SyncToMaster returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in dmusicks.h. Include dmusicks.h.


ISynthSinkDMus::SampleToRefTime

The SampleToRefTime method converts sample time into reference time. A sample time is passed in and the corresponding reference time is returned.

HRESULT
  SampleToRefTime(
    IN LONGLONG  llSampleTime,
    OUT REFERENCE_TIME  * prtTime
    );

Parameters

llSampleTime
Specifies the sample time being passed in.
prtTime
This is a pointer to the reference time that is used to return the reference time. The reference time is measured in 100-nanosecond units.

Return Value

SampleToRefTime returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in dmusicks.h. Include dmusicks.h.


ISynthSinkDMus::RefTimeToSample

The RefTimeToSample method converts reference time into sample time. A reference time is passed in and the corresponding sample time is returned.

HRESULT
  RefTimeToSample(
    IN REFERENCE_TIME  rtTime,
    OUT LONGLONG  * pllSampleTime
    );

Parameters

rtTime
Pointer to the reference being passed in. The reference time is measured in 100-nanosecond units.
pllSampleTime
Pointer to the sample time that is returned.

Return Value

RefTimeToSample returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in dmusicks.h. Include dmusicks.h.


Audio Power Management

This section describes the power management facilities that are exposed to WDM audio drivers by the Port Class Library. The following topic is discussed:

Audio Power Management Interfaces


Audio Power Management Interfaces

This section includes the following topics about the power management interfaces provided to WDM audio drivers by the Port Class Library:

IAdapterPowerManagement

IPowerNotify


IAdapterPowerManagement

The IAdapterPowerManagement interface is used to manage the power state of an audio adapter. IAdapterPowerManagement inherits from the IUnknown interface.

Power management of the WDM audio adapter is accomplished primarily through the IAdapterPowerManagement interface that the adapter driver registers with PortCls during the StartDevice phase of device initialization. Registration is accomplished through the PcRegisterAdapterPowerManagement routine exported for this purpose by PortCls.

The IAdapterPowerManagement interface consists of the following three methods, which Port Class Library uses to facilitate device power management:

IAdapterPowerManagement::PowerChangeState

IAdapterPowerManagement::QueryDeviceCapabilities

IAdapterPowerManagement::QueryPowerChangeState


IAdapterPowerManagement::PowerChangeState

The PowerChangeState method requests that the device change to a new power state. PowerChangeState is called by PortCls in response to an IRP_MN_SET_POWER power IRP. It is a call that should not fail. It is used by PortCls and the system to place the device in the desired power state. When the system attempts to suspend or resume an active audio stream, the driver should be capable of saving or restoring its device context appropriately.

To assist the driver, PortCls will pause any active audio streams prior to calling this method to place the device in a sleep state. After calling this method, PortCls will unpause active audio streams, to wake the device up. Miniports can opt for additional notification by utilizing the IPowerNotify interface.

void
  PowerChangeState)(
    IN POWER_STATE  NewState
    );

Parameters

NewState
The requested, new power state for the device. The new power state (NewStateQuery.DeviceState) can be one of four values:
Power State | Meaning
PowerDeviceD0 | Full power state (D0). This code may be a function of the current power state. Save the new state. This local value is used to determine when to cache property accesses and when to permit the driver from accessing the hardware.
PowerDeviceD1 | The sleep state having the lowest latency with respect to the latency time required to return to D0
PowerDeviceD2 | A medium latency sleep state. In this state, the device driver cannot assume that it can touch the hardware, so any accesses need to be cached and the hardware restored upon entering D0.
PowerDeviceD3 | A full hibernation state and is the longest latency sleep state. The driver cannot access the hardware in this state and should cache any hardware accesses and restore the hardware upon returning to D0 or D1

Return Value

None

Headers

Declared in portcls.h. Include portcls.h.

Comments

The miniport should perform the requested change to the device's power state before it returns from the PowerChangeState call. If the miniport needs to save or restore any device state before a power-state change, the miniport should support the IPowerNotify interface, which allows it to receive advance warning of any such change. Before returning from a successful PowerChangeState call, the miniport object should cache the new power state.

While the miniport is in one of the sleep states (any state other than PowerDeviceD0), it should avoid writing to the hardware. The miniport should cache any hardware accesses that must be deferred until the device powers up again. If the power state is changing from one of the sleep states to PowerDeviceD0, the miniport should perform any deferred hardware accesses after it has powered up the device. If the power state is changing from PowerDeviceD0 to a sleep state, the miniport can perform any necessary hardware accesses during the PowerChangeState call before it powers down the device.

While powered down, a miniport is never asked to create a miniport or stream object. PortCls always places the device in the PowerDeviceD0 state before calling the miniport's NewStream method.

The code for this method should reside in paged memory.

See Also

IPowerNotify


IAdapterPowerManagement::QueryDeviceCapabilities

The QueryDeviceCapabilities method is called by PortCls in response to a PnP IRP_MN_QUERY_CAPABILITIES IRP. This method passes to the WDM driver a capabilities structure that defines the mappings between system power states and device power states.

NTSTATUS
  QueryDeviceCapabilities)(
    IN PDEVICE_CAPABILITIES  PowerDeviceCaps
    );

Parameters

PowerDeviceCaps
A pointer to a DEVICE_CAPABILITIES structure that specifies the device's capabilities.

Return Value

QueryDeviceCapabilities returns STATUS_SUCCESS if call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

Values for each mapping are filled in when the structure is passed with the method call. Typically, the adapter driver should not change these settings. If the adapter driver must override the defaults, it can change the mappings to a deeper (less-powered) device power state but not to a weaker (more-powered) device power state. For example, the mappings for S1 (PowerSystemSleeping1) can be changed from D1 to D3, but not to D0.

In order to fill in the PowerDeviceCaps for a device, the miniport should register the interface portclass in or before the AddDevice function. The operating system queries devices before StartDevice is called. (For more information on AddDevice and StartDevice, see Startup Sequence.) In order to change the mappings between system power states and device power states, the adapter driver changes the PowerDeviceCaps.DeviceState array. These mappings should be changed only if required. The following sample shows how to map D1 mappings to D3:

for  (i=ULONG(PowerSystemWorking); i<=ULONG(PowerSystemShutdown); i++ )
    {
        if (PowerDeviceCaps->DeviceState[i] == PowerDeviceD1)
        {
            PowerDeviceCaps->DeviceState[i] = PowerDeviceD3;
        }
    }

The code for this method should reside in paged memory.

See Also

DEVICE_CAPABILITIES


IAdapterPowerManagement::QueryPowerChangeState

The QueryPowerChangeState method is called by PortCls in response to the receipt of an IRP_MN_QUERY_POWER power IRP. This call is used by PortCls and the system to query for acceptability of a potential device power state change. The driver can deny the power state change by returning a value other than STATUS_SUCCESS. A call to QueryPowerStateChange is not guaranteed to occur prior to all PowerChangeState calls.

NTSTATUS
  QueryPowerChangeState)(
   IN POWER_STATE  NewStateQuery
    )

Parameters

NewStateQuery
A POWER_STATE enumeration value that specifies the new power state that is being requested for the device.

Return Value

QueryPowerChangeState returns STATUS_SUCCESS if call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comment

See IAdapterPowerManagement::PowerChangeState for a list of the power states that are defined in the POWER_STATE enumeration type.

The code for this method should reside in paged memory.

See Also

IAdapterPowerManagement::PowerChangeState


IPowerNotify

The IPowerNotify interface is an optional interface that miniports can expose if they desire explicit notification of power-state changes. The interface provides a single method (or callback) that is called by the miniport's corresponding port driver in response to a power-state change. IPowerNotify inherits from the IUnknown interface.

Using wave audio as an example, when the device is requested to go to a sleep state the port driver pauses any active streams and then calls the power notify callback to inform the miniport of the impending power down. The miniport then has an opportunity to save any necessary context before the adapter's PowerChangeState method is called.

The process is reversed when the device is powering up. PortCls first calls the adapter's PowerChangeState method to power up the adapter. The port driver then calls the miniport's callback to allow the miniport to restore its context. Finally, the port driver unpauses any previously paused active audio streams.

For additional information, see Implementing the IPowerNotify Interface.

The IPowerNotify interface supports the following method:

IPowerNotify::PowerChangeNotify


IPowerNotify::PowerChangeNotify

The PowerChangeNotify method notifies the miniport of changes in the power state.

NTSTATUS
  PowerChangeNotify(
    IN POWER_STATE  PowerState
    );

Parameters

PowerState
Current power state. (See enumerated power states in IAdapterPowerManagement::PowerChangeState.)

Return Value

PowerChangeNotify returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.

Comments

The PortCls system driver calls the miniport's PowerChangeNotify method to notify it of changes in the power state. The purpose of this call is to give the miniport an opportunity to save any hardware-specific context just before powering down or to restore a previously saved context just after powering up.

The miniport can write to the hardware registers or on-board memory during the PowerChangeNotify call. If the system is powering down (making a state transition away from PowerDeviceD0), the PortCls system driver calls PowerChangeNotify before it calls IAdapterPowerManagement::PowerChangeState and after it has paused any active audio data streams. This gives the miniport an opportunity to save any hardware-specific device context before the device powers down. For example, a WavePci miniport might need to save its DMA registers if the power down occurs during a sequence of scatter/gather data transfers. If the system is powering up (making a state transition toward PowerDeviceD0), PortCls calls PowerChangeNotify after it calls PowerChangeState and before it restarts any paused audio data streams. This gives the miniport an opportunity to restore a previously saved context after the device has powered up.

The code for this method should reside in paged memory.

See Also

IAdapterPowerManagement::PowerChangeState


Audio Port Class Structures

This section describes the structures that are defined by the header file portcls.h for use with PortCls port and miniport drivers.


PCAUTOMATION_TABLE

The PCAUTOMATION_TABLE structure contains a miniport's master table of properties, methods, and events.

typedef struct
{
    ULONG                     PropertyItemSize;
    ULONG                     PropertyCount;
    const PCPROPERTY_ITEM    *Properties;
    ULONG                     MethodItemSize;
    ULONG                     MethodCount;
    const PCMETHOD_ITEM      *Methods;
    ULONG                     EventItemSize;
    ULONG                     EventCount;
    const PCEVENT_ITEM       *Events;
    ULONG                     Reserved;
} PCAUTOMATION_TABLE, *PPCAUTOMATION_TABLE;

Members

PropertyItemSize
Size in bytes of the property structure used.
PropertyCount
The number of property items in the Properties array.
Properties
Pointer to the filter's array of properties.
MethodItemSize
Size in bytes of the methods structure used.
MethodCount
The number of method items in the Methods array.
Methods
Pointer to the filter's array of methods.
EventItemSize
Size in bytes of the event structure used.
EventCount
The number of event items in the Events array.
Events
Pointer to the filter's array of events.
Reserved
Reserved. Set to zero.

Comments

Any of the item pointers can be NULL, in which case the corresponding counts should be zero. For item tables that are not zero length, the item size should not be smaller than the size of the corresponding item structure that is defined in the header file portcls.h. The minimum size for a property, event, or method item is sizeof(PCPROPERTY_ITEM), sizeof(PCEVENT_ITEM), or sizeof(PCMETHOD_ITEM), respectively. The item size can be larger than this, in which case the item structure is assumed to be followed by private data. Item sizes should be a multiple of eight.

See Also

PCPROPERTY_ITEM, PCEVENT_ITEM, PCMETHOD_ITEM


PCCONNECTION_DESCRIPTOR

The PCCONNECTION_DESCRIPTOR structure describes a single data-path connection inside a KS filter. A filter's internal topology can be specified by an array of PCCONNECTION_DESCRIPTOR structures. A WDM audio adapter driver returns an array of these structures in response to a IMiniport::GetDescription call or a KSPROPERTY_TOPOLOGY_CONNECTIONS get-property request. PCCONNECTION_DESCRIPTOR is an alias for KSTOPOLOGY_CONNECTION.

typedef struct {
    ULONG FromNode;
    ULONG FromNodePin;
    ULONG ToNode;
    ULONG ToNodePin;
} PCCONNECTION_DESCRIPTOR;

Members

FromNode
Node ID of the node on the upstream end of the connection. If this end of the connection is an input (sink) pin on the filter—not a logical pin on a node—set this member to the null node-ID value, PCFILTER_NODE.
FromNodePin
Pin ID for the upstream end of the connection. If the FromNode member is set to PCFILTER_NODE, the pin on this end of the connection is an input (sink) pin on the filter. Otherwise, it is a logical pin on an internal node.
ToNode
Node ID of the node on the downstream end of the connection. If this end of the connection is an output (source) pin on the filter—not a logical pin on a node—set this member to the null node-ID value, PCFILTER_NODE.
ToNodePin
Pin ID for the downstream end of the connection. If the ToNode member is set to PCFILTER_NODE, the pin on this end of the connection is an output (source) pin on the filter. Otherwise, it is a logical pin on an internal node.

Headers

Declared in portcls.h. Include portcls.h.

Comments

The PCCONNECTION_DESCRIPTOR structure specifies a single connection inside a filter. The connection can be one of the following:

  • A connection between two internal nodes.
  • A connection between an internal node and a pin on the filter.
  • A connection between two pins on the filter.

The last type of connection occurs when an input pin on a filter streams data directly to an output pin on the same filter.

An adapter driver uses an array of PCCONNECTION_DESCRIPTOR structures to specify the internal topology of a filter.

The data stream flows from the FromNode end to the ToNode end of the connection.

To use the PCCONNECTION_DESCRIPTOR structure, the driver writer assigns "logical" pins to the nodes inside the filter. These "pins" are connection points on the nodes and are analogous to the external pins that the filter uses to connect to other filters. However, logical pins on nodes are used solely to specify the connections inside the filter.

A simple node with a single input and a single output typically numbers its input and output pins one and zero, respectively. By convention, this numbering is based on the direction of IRP flow rather than data flow.

More complex nodes might require standardized pin IDs in order to allow clients to more easily determine the assignment of functions to specific pins. For example, the KSNODETYPE_ACOUSTIC_ECHO_CANCEL node uses standardized IDs for its four pins.

When the pin on one end of a connection is an input or output pin on the filter rather than a logical pin on a node, set the FromNode or ToNode member (depending on which end of the connection you are specifying) to the null node-ID value, PCFILTER_NODE.

Avoid confusing logical pins, which are used solely to describe connection points on nodes within a filter, with the external pins that filters use to connect to other filters. Logical pins are rarely used outside of the PCCONNECTION_DESCRIPTOR structure. In this document, the term pin refers to a pin on a KS filter rather than a logical pin on a node unless noted otherwise.

The IMiniport::GetDescription method outputs a PCFILTER_DESCRIPTOR structure that contains a pointer to a PCCONNECTION_DESCRIPTOR array.

For a simple code example that shows how the PCCONNECTION_DESCRIPTOR structure is used, see Exposing Miniport Topology.

See Also

IMiniport::GetDescription, KSPROPERTY_TOPOLOGY_CONNECTIONS, KSTOPOLOGY_CONNECTION, PCFILTER_NODE, PCFILTER_DESCRIPTOR


PCEVENT_ITEM

The PCEVENT_ITEM structure is used to describe an event that is supported by a particular filter, pin, or node.

typedef struct
{
    const GUID             *Set;
    ULONG                   Id;
    ULONG                   Flags;
    PCPFNEVENT_HANDLER      Handler;
} PCEVENT_ITEM, *PPCEVENT_ITEM;

Members

Set
The GUID of the event set.
Id
The ID of an event within the event set.
Flags
Flags indicating the type of event. This value should be set to one of the following:
PCEVENT_ITEM_FLAG_ENABLE
Indicates the event notification should be enabled for this event type. The driver should continue event notification until the client explicitly disables it.
PCEVENT_ITEM_FLAG_ONESHOT
Indicates that the event notification should be enabled for the next occurrence of this event only. The client does not (and should not) disable the event once it has occurred.
PCEVENT_ITEM_FLAG_BASICSUPPORT
If the client specifies this flag, the driver returns STATUS_SUCCESS if it supports the event, and an error code if it does not.
Handler
Function pointer to the miniport's event handler. This pointer is of type PCPFNEVENT_HANDLER, which is defined as follows:
typedef NTSTATUS (*PCPFNEVENT_HANDLER)
(
    IN PPCEVENT_REQUEST EventRequest
);

The handler takes a single input parameter, which is a pointer to a PCEVENT_REQUEST structure.

See Also

PCEVENT_REQUEST


PCEVENT_REQUEST

The PCEVENT_REQUEST structure is used to specify an event request. This structure is used as a parameter to an EventHandler routine.

typedef struct _PCEVENT_REQUEST
{
    PUNKNOWN                MajorTarget;
    PUNKNOWN                MinorTarget;
    ULONG                   Node;
    const PCEVENT_ITEM     *EventItem;
    PKSEVENT_ENTRY          EventEntry;
    ULONG                   Verb;
    PIRP                    Irp;
} PCEVENT_REQUEST, *PPCEVENT_REQUEST;

Members

MajorTarget
Pointer to the object. Kernel streaming targets are generic, so the type of the object is specified as IUnknown to allow general usage.
MinorTarget
The stream or voice. If the major target is a node, the MinorTarget can specify the stream or voice with which the targeted node instance is associated. This value can be set to NULL if not used.
Node
Node parameter for the requested targeted. If not used, set this member to constant PCFILTER_NODE, which has the value ULONG(-1).
EventItem
Pointer to the PCEVENT_ITEM structure for this request.
EventEntry
Pointer to the KSEVENT_ENTRY structure for this request.
Verb
Identifier flags for the process. This member should be set to one of the following flags:
Flag | Meaningt
PCEVENT_VERB_ADD | Indicates that a client wishes to enable the event identified. After validating the event and target information, the EventHandler routine would add the event using the IPortEvents::AddEventToEventList method.
PCEVENT_VERB_REMOVE | This notifies the EventHandler that an event is being disabled and removed from the list.
PCEVENT_VERB_SUPPORT | This request is a query for support. If the miniport supports the event for the targed identified in the request it should succeed this query. Else, it should fail.
PCEVENT_VERB_NONE | No action is needed

Irp
Pointer to the irp.

See Also

PCFILTER_NODE, PCEVENT_ITEM, KSEVENT_ENTRY, EventHandler, IPortEvents::AddEventToEventList


PCFILTER_NODE

The PCFILTER_NODE constant is the null node ID for the FromNode or ToNode field in a PCCONNECTION_DESCRIPTOR structure. If the structure's FromNode or ToNode member is set to PCFILTER_NODE, the pin on this end of the connection is an input or output pin on the filter. Otherwise, it is a logical pin on a node inside the filter.

PCFILTER_NODE is defined as follows:

#define PCFILTER_NODE KSFILTER_NODE

The value KSFILTER_NODE is ((ULONG)-1).


PCFILTER_DESCRIPTOR

The PCFILTER_DESCRIPTOR structure describes a miniport's implementation of a filter. The structure specifies the filter's pins, nodes, connections, and properties.

typedef struct
{
    ULONG                           Version;
    const PCAUTOMATION_TABLE       *AutomationTable;
    ULONG                           PinSize;
    ULONG                           PinCount;
    const PCPIN_DESCRIPTOR         *Pins;
    ULONG                           NodeSize;
    ULONG                           NodeCount;
    const PCNODE_DESCRIPTOR        *Nodes;
    ULONG                           ConnectionCount;
    const PCCONNECTION_DESCRIPTOR  *Connections;
    ULONG                           CategoryCount;
    const GUID *                    Categories;
} PCFILTER_DESCRIPTOR, *PPCFILTER_DESCRIPTOR;

Members

Version
Reserved. This value should be set to zero.
AutomationTable
Pointer to the automation table. This is a structure of type PCAUTOMATION_TABLE.
PinSize
Size in bytes of the Pins array.
PinCount
The number of pins in the Pins array.
Pins
Pointer to the array of pin descriptors. Each array element is a PCPIN_DESCRIPTOR structure.
NodeSize
Size in bytes of the Nodes array.
NodeCount
Number of nodes in the Nodes array.
Nodes
Pointer to the array of node descriptors. Each array element is a PCNODE_DESCRIPTOR structure.
ConnectionCount
The number of connections in the Connections array.
Connections
Pointer to the array of connections descriptors. Each array element is a PCCONNECTION_DESCRIPTOR structure.
CategoryCount
The number of GUIDs in the Categories array.
Categories
Pointer to the array of GUIDs that specifies the categories that the object belongs to. See the discussion of topology categories in Installing Device Interfaces for an Audio Adapter.

Comments

The IMiniport::GetDescription method returns a pointer to a PCFILTER_DESCRIPTOR structure that describes the miniport's pins, nodes, connections, and properties.

See Also

PCAUTOMATION_TABLE, PCPIN_DESCRIPTOR, PCNODE_DESCRIPTOR, PCCONNECTION_DESCRIPTOR, IMiniport::GetDescription


PCMETHOD_ITEM

A PCMETHOD_ITEM structure describes a method supported by a filter, pin, or node.

typedef struct
{
    const GUID             *Set;
    ULONG                   Id;
    ULONG                   Flags;
    PCPFNMETHOD_HANDLER     Handler;
} PCMETHOD_ITEM, *PPCMETHOD_ITEM;

Members

Set
The GUID of the method set.
Id
The ID of the method.
Flags
Flags that specify the type of parameter passing and memory access that a method uses. This member can be set to a bitwise OR of one or more of the following:
Flag | Meaning
PCMETHOD_ITEM_FLAG_MODIFY | The method reads from and writes to the parameter buffer.
PCMETHOD_ITEM_FLAG_NONE | The parameter buffer is not used.
PCMETHOD_ITEM_FLAG_READ | The method reads from the parameter buffer.
PCMETHOD_ITEM_FLAG_SOURCE | The method probes and locks memory pages before attempting memory access.
PCMETHOD_ITEM_FLAG_WRITE | The method writes to the parameter buffer.

Handler
Function pointer to the method handler. This pointer is of type PCPFNMETHOD_HANDLER, which is defined as follows:
  typedef NTSTATUS (*PCPFNMETHOD_HANDLER)
  (
      IN PPCMETHOD_REQUEST MethodRequest
  );

The handler takes a single input parameter, which is a pointer to a structure of type PCMETHOD_REQUEST.

See Also

PCMETHOD_REQUEST


PCMETHOD_REQUEST

The PCMETHOD_REQUEST structure specifies a method request.

typedef struct _PCMETHOD_REQUEST
{
    PUNKNOWN                MajorTarget;
    PUNKNOWN                MinorTarget;
    ULONG                   Node;
    const PCMETHOD_ITEM    *MethodItem;
    ULONG                   Verb;
} PCMETHOD_REQUEST, *PPCMETHOD_REQUEST;

Members

MajorTarget
Pointer to the IUnknown interface of a miniport object that supports the method set and method specified by MethodItem.
MinorTarget
Pointer to an IUnknown interface of a stream object associated with MajorTarget. This parameter should be set to NULL if there is no minor target.
Node
Node ID of the major target. If there is no node, set this member to constant PCFILTER_NODE, which has the value ULONG(-1).
MethodItem
Pointer to a PCMETHOD_ITEM structure that describes a method supported by a filter, pin, or node.
Verb
Flags that specify which method-related operations to perform. This member can be set to a bitwise OR of one or more of the flag bits in the table below.
Flag bit | Meaning
PCMETHOD_ITEM_FLAG_BASICSUPPORT | Returns basic support information about the method specified by MethodItem->Id.
PCMETHOD_ITEM_FLAG_SEND | Executes the method specified by MethodItem->Id. The client should conform to the basic-support information for the method.
PCMETHOD_ITEM_FLAG_SETSUPPORT | Returns information about support for the method set specified by MethodItem->Set.

See Also

PCFILTER_NODE, PCMETHOD_ITEM


PCNODE_DESCRIPTOR

The PCNODE_DESCRIPTOR structure describes a node in the filter that a miniport implements.

typedef struct
{
    ULONG                       Flags;
    const PCAUTOMATION_TABLE   *AutomationTable;
    const GUID                 *Type;
    const GUID                 *Name;
} PCNODE_DESCRIPTOR, *PPCNODE_DESCRIPTOR

Members

Flags
Set to zero. No flag bits are currently defined.
AutomationTable
Pointer to the automation table, which is a structure of type PCAUTOMATION_TABLE. This value can be set to NULL to indicate no automation support.
Type
Pointer to a GUID that identifies the node type.
Name
Points to a GUID that represents the name of this topology node. This GUID is specified in a KSPROPERTY_TOPOLOGY_NAME get-property request to obtain the corresponding name string for the node. This pointer can be set to NULL to indicate that the GUID in the Type member should be used to determine the node name.

Comments

The IMiniport::GetDescription method outputs a pointer to a PCFILTER_DESCRIPTOR structure that contains a pointer to an array of PCNODE_DESCRIPTOR structures.

For a simple code example that shows how the PCNODE_DESCRIPTOR structure is used, see Exposing Miniport Topology.

See Also

KSPROPERTY_TOPOLOGY_NAME, PCAUTOMATION_TABLE, IMiniport::GetDescription


PCPIN_DESCRIPTOR

The PCPIN_DESCRIPTOR structure describes a pin in the filter that the miniport implements.

typedef struct
{
    ULONG                       MaxGlobalInstanceCount;
    ULONG                       MaxFilterInstanceCount;
    ULONG                       MinFilterInstanceCount;
    const PCAUTOMATION_TABLE   *AutomationTable;
    KSPIN_DESCRIPTOR            KsPinDescriptor;
} PCPIN_DESCRIPTOR, *PPCPIN_DESCRIPTOR

Members

MaxGlobalInstanceCount
The maximum number of global instances supported. This value can be set to zero to indicate that the pin cannot be instantiated. A value of ULONG(-1) indicates the pin can be allocated any number of times. Any other value indicates a specific number of times the pin can be allocated.
MaxFilterInstanceCount
The maximum number of filter instances supported. This value can be set to zero to indicate that the pin can not be instantiated. A value of ULONG(-1) indicates the pin can be allocated any number of times Any other value indicates a specific number of times the pin can be allocated.
MinFilterInstanceCount
The minimum number of filter instances supported
AutomationTable
Pointer to the automation table used. The pointer can be NULL to indicate that no automation is supported.
KsPinDescriptor
The KS pin descriptor. It can have zero interfaces and zero mediums. The list of interfaces is ignored in all cases. The medium list will default to a list containing only the standard medium (device I/O).

Comments

The IMiniport::GetDescription method outputs a pointer to a PCFILTER_DESCRIPTOR structure that contains a pointer to an array of PCPIN_DESCRIPTOR structures.

For a simple code example that shows how the PCPIN_DESCRIPTOR structure is used, see Exposing Miniport Topology.

See Also

PCAUTOMATION_TABLE, KSPIN_DESCRIPTOR


PCPROPERTY_ITEM

The PCPROPERTY_ITEM structure describes a property that is supported by a particular filter, pin, or node.

typedef struct
{
    const GUID             *Set;
    ULONG                   Id;
    ULONG                   Flags;
    PCPFNPROPERTY_HANDLER   Handler;
} PCPROPERTY_ITEM, *PPCPROPERTY_ITEM;

Members

Set
Pointer to a property set.
Id
The specific property being addressed.
Flags
Flags indicating the type of property support available. This value can be set to a bitwise-ORed combination of the flag bits that are described in the table below.
Flag bits | Type of property request
PCPROPERTY_ITEM_FLAG_GET | Get the current property data setting.
PCPROPERTY_ITEM_FLAG_SET | Set the current property data setting.
PCPROPERTY_ITEM_FLAG_DEFAULTVALUES | Requests the driver's default values for the property data.
PCPROPERTY_ITEM_FLAG_BASICSUPPORT | Which request types does the driver handle for this property? What is the valid data type, and what are the valid ranges for the property data?
PCPROPERTY_ITEM_FLAG_SERIALIZESIZE | What is the size of the property data for this property when it is serialized as part of a KSPROPERTY_TYPE_SERIALIZESET request?
PCPROPERTY_ITEM_FLAG_SERIALIZERAW | Serialize this property in a driver-dependent manner. This operation is the inverse of PCPROPERTY_ITEM_FLAG_UNSERIALIZERAW.
PCPROPERTY_ITEM_FLAG_UNSERIALIZERAW | Unserialize this property in a driver-dependent manner. This operation is the inverse of PCPROPERTY_ITEM_FLAG_SERIALIZERAW.
PCPROPERTY_ITEM_FLAG_SERIALIZE | PCPROPERTY_ITEM_FLAG_SERIALIZERAW | PCPROPERTY_ITEM_FLAG_UNSERIALIZERAW | PCPROPERTY_ITEM_FLAG_SERIALIZESIZE
Handler
Function pointer to property handler. The pointer is of type PCPFNPROPERTY_HANDLER, which is defined as follows:
typedef NTSTATUS (*PCPFNPROPERTY_HANDLER)
(
    IN PPCPROPERTY_REQUEST PropertyRequest
);

The handler takes a single input parameter, which is a pointer to a PCPROPERTY_REQUEST structure. The handler can return STATUS_PENDING, in which case it should eventually call PcCompletePendingPropertyRequest to complete the request.

See Also

PCPROPERTY_REQUEST, PcCompletePendingPropertyRequest


PCPROPERTY_REQUEST

The PCPROPERTY_REQUEST structure contains a property request that is submitted to a property handler.

typedef struct _PCPROPERTY_REQUEST
{
    PUNKNOWN                 MajorTarget;
    PUNKNOWN                 MinorTarget;
    ULONG                    Node;
    const PCPROPERTY_ITEM   *PropertyItem;
    ULONG                    Verb;
    ULONG                    InstanceSize;
    PVOID                    Instance;
    ULONG                    ValueSize;
    PVOID                    Value;
    PIRP                     Irp;
} PCPROPERTY_REQUEST, *PPCPROPERTY_REQUEST;

Members

MajorTarget
IUnknown pointer to the filter or pin object.
MinorTarget
IUnknown pointer to the associated stream or voice object. If the target is a node, the MinorTarget can be used to indicate the stream or voice with which the targeted node instance is associated. Can be NULL if no minor target is needed.
Node
Node ID parameter for the requested target. If not used, set this to ULONG(-1).
PropertyItem
Pointer to the property item, which is a structure of type PCPROPERTY_ITEM.
Verb
Identifier flags for the process.
InstanceSize
The size in bytes of the property-instance buffer.
Instance
Pointer to the property-instance buffer.
ValueSize
The size in bytes of the property-value buffer.
Value
Pointer to the property-value buffer.
Irp
Pointer to the IRP.

Comments

For background information on audio properties, see Properties of Audio Filters, Pins, and Nodes. For a list of the available audio-specific properties, see Audio Drivers Property Sets.

See Also

PCPROPERTY_ITEM


DirectMusic KS Structures

This section describes the structures that are defined by the header file dmusicks.h for use with WDM audio drivers that provide kernel streaming support for DirectMusic.


DMUS_KERNEL_EVENT

The DMUS_KERNEL_EVENT structure is used to package time-stamped music events. In the case of MIDI capture, it can be packaged with single, multiple, or fragmentary MIDI messages. The usFlags member should be set to DMUS_KEF_EVENT_INCOMPLETE unless it is a single complete MIDI message. This structure also contains a time stamp relative to the master clock and extended channel information. Mapping to the correct DLS instrument is implicit in the triplet of <pin, channel group, channel>.

typedef struct _DMUS_KERNEL_EVENT
    {                                           //  this    offset
        BYTE            bReserved;              //  1       0
        BYTE            cbStruct;               //  1       1
        USHORT          cbEvent;                //  2       2
        USHORT          usChannelGroup;         //  2       4
        USHORT          usFlags;                //  2       6
        REFERENCE_TIME  ullPresTime100Ns;       //  8       8
        _DMUS_KERNEL_EVENT *pNextEvt;           //  4 (8)  16
        union
        {
            BYTE        abData[sizeof(PBYTE)];  //  4 (8)  20 (24)
            PBYTE       pbData;
            _DMUS_KERNEL_EVENT *pPackageEvt;
        } uData;
    } DMUS_KERNEL_EVENT, *PDMUS_KERNEL_EVENT;   //         24 (32)

Members

bReserved
Reserved for future use. Do not use.
cbStruct
Drivers should not modify this member. It is the size of the DMUS_KERNEL_EVENT structure itself and might change in the future.
cbEvent
Specifies the unrounded number of event bytes referred to by uData.
usChannelGroup
Specifies which channel group (set of 16 MIDI channels) receives or originated this event. This is unique only within the target MIDI device (miniport).
usFlags
Specifies flags used to indicate whether an event is a package, whether this event concludes the message, and so on. A package encapsulates a list of events that should be dealt with atomically.
DMUS_KEF_EVENT_COMPLETE
Specifies messages in which the entire message is contained either in uData.abData or in the buffer pointed to by uData.pbData. The former would include all short messages, and potentially very brief SysEx messages. Keep in mind that sizeof(PBYTE) could be 8 instead of 4 on future versions of Windows.
DMUS_KEF_EVENT_INCOMPLETE
Specifies that this event is an incomplete package or sysex. This flag specifies that the message continues beyond this event. During MIDI capture, the miniport can sent "uncooked" MIDI events to the capture sink by specifying this flag.
DMUS_KEF_PACKAGE_EVENT
Specifies that this event is a package. The uData.pPackageEvt field contains a pointer to a chain of events which should be dealt with atomically.
ullPresTime100Ns
Specifies the presentation time for this event. This 64-bit value is expressed in 100-nanosecond units. The master clock should be used to evaluate this presentation time.
pNextEvt
Pointer to the next event in the list, or NULL if no event follows. This facilitates passing chains of identically time-stamped messages to the miniport. Additionally, hardware that does its own mixing can receive or transmit groups of messages at one time.
uData
If cbEvent is less than or equal to sizeof(PBYTE), then uData.abData is a byte array of length cbEvent, containing the event data bytes. Otherwise, depending on the value of usFlags, uData.pPackageEvt refers to a list of events to be handled together, or uData.pbData refers to a buffer containing cbEvent bytes of event data. The event data are typically MIDI status and data bytes.
abData
see above
pbData
see above
pPackageEvt
Pointer to a chain of events.


Macro Definitions for Obsolete Functions

The header file portcls.h defines a number of macros that aid in compiling legacy driver code without requiring edits to source files. These macros conveniently replace calls to obsolete PortCls and kernel-mode driver functions with calls to the new PortCls and kernel-mode driver functions. If you have old source code that contains references to the obsolete functions, you can use the macros in portcls.h to recompile the source files to create executable code that calls the new functions.

The following topics are discussed:

Obsolete Port Class Functions

Obsolete Kernel-Mode Driver-Support Functions


Obsolete Port Class Functions

The header file portcls.h defines macros that contain the names of obsolete PortCls functions that have been replaced by new PortCls functions. These macros allow old source code that contains references to obsolete PortCls function names to be recompiled to use the new PortCls functions without requiring any edits to the source files.

When compiling source code that uses the obsolete names, define the parameter name PC_OLD_NAMES. This parameter can be defined by the compiler command-line argument "-DPC_OLD_NAMES" if that is more convenient than introducing the statement "#define PC_OLD_NAMES" into the source files themselves.

The following table lists the obsolete PortCls function names in the left column. For each obsolete name, the center column contains the name of the new PortCls function that replaces it.

Obsolete function name | New function name | Did arguments change?
AddAdapterDevice | PcAddAdapterDevice | YES
CompletePendingPropertyRequest | PcCompletePendingPropertyRequest | no
GetTimeInterval | PcGetTimeInterval | no
InitializeAdapterDriver | PcInitializeAdapterDriver | YES
NewDmaChannel | PcNewDmaChannel | no
NewMiniport | PcNewMiniport | no
NewPort | PcNewPort | no
NewResourceList | PcNewResourceList | no
NewResourceSublist | PcNewResourceSublist | no
NewServiceGroup | PcNewServiceGroup | no
RegisterPhysicalConnection | PcRegisterPhysicalConnection | YES
RegisterPhysicalConnectionFromExternal | PcRegisterPhysicalConnectionFromExternal | YES
RegisterPhysicalConnectionToExternal | PcRegisterPhysicalConnectionToExternal | YES
RegisterSubdevice | PcRegisterSubdevice | YES

In some cases, the change amounts to no more than a simple name change: The qualifier "Pc" is inserted at the beginning of the name to indicate that the function is implemented in PortCls. In other cases, however, the argument list has changed in addition to the name of the function. The right column in the table above indicates whether the arguments have changed.

In cases in which the arguments changed, the macros in portcls.h convert the argument lists for the obsolete PortCls functions to the equivalent arguments for the new PortCls functions. The following macros contain argument conversions:

#define InitializeAdapterDriver(c1,c2,a) \
    PcInitializeAdapterDriver(PDRIVER_OBJECT(c1),PUNICODE_STRING(c2),PDRIVER_ADD_DEVICE(a))
#define AddAdapterDevice(c1,c2,s,m) \
    PcAddAdapterDevice(PDRIVER_OBJECT(c1),PDEVICE_OBJECT(c2),s,m,0)
#define RegisterSubdevice(c1,c2,n,u) \
    PcRegisterSubdevice(PDEVICE_OBJECT(c1),n,u)
#define RegisterPhysicalConnection(c1,c2,fs,fp,ts,tp) \
    PcRegisterPhysicalConnection(PDEVICE_OBJECT(c1),fs,fp,ts,tp)
#define RegisterPhysicalConnectionToExternal(c1,c2,fs,fp,ts,tp) \
    PcRegisterPhysicalConnectionToExternal(PDEVICE_OBJECT(c1),fs,fp,ts,tp)
#define RegisterPhysicalConnectionFromExternal(c1,c2,fs,fp,ts,tp) \
    PcRegisterPhysicalConnectionFromExternal(PDEVICE_OBJECT(c1),fs,fp,ts,tp)


Obsolete Kernel-Mode Driver-Support Functions

The header file portcls.h defines four macros that contain the names of obsolete kernel-mode driver-support functions. These macros allow old source code that contains references to the obsolete function names to be recompiled to use the new kernel functions without requiring any edits to the source files.

When compiling source code that uses the obsolete names, define the parameter name PC_OLD_NAMES. This parameter can be defined by the compiler command-line argument "-DPC_OLD_NAMES" if that is more convenient than introducing the statement "#define PC_OLD_NAMES" into the source files themselves.

The following table lists the obsolete kernel-mode driver-support function names in the left column. For each obsolete name, the right column contains the name of the new kernel function that replaces it. In each case, the macro definition amounts to a simple name change. The argument lists for the obsolete function and the new function are identical.

Obsolete function name | New function name
WIN95COMPAT_ReadPortUChar | READ_PORT_UCHAR
WIN95COMPAT_WritePortUChar | WRITE_PORT_UCHAR
WIN95COMPAT_ReadPortUShort | READ_PORT_USHORT
WIN95COMPAT_WritePortUShort | WRITE_PORT_USHORT


Video Capture Property Sets

This section describes each of the following predefined video capture property sets and each of the properties within the set.

PROPSETID_ALLOCATOR_CONTROL

PROPSETID_TUNER

PROPSETID_VIDCAP_CAMERACONTROL

PROPSETID_VIDCAP_CROSSBAR

PROPSETID_VIDCAP_DROPPEDFRAMES

PROPSETID_VIDCAP_TVAUDIO

PROPSETID_VIDCAP_VIDEOCOMPRESSION

PROPSETID_VIDCAP_VIDEOCONTROL

PROPSETID_VIDCAP_VIDEODECODER

PROPSETID_VIDCAP_VIDEOPROCAMP

A table in the description of each property indicates whether or not video capture drivers are required to support reading or writing the property. Drivers should return E_UNSUPPORTED in response to get or set requests for properties that are not supported by the driver.


PROPSETID_ALLOCATOR_CONTROL

The following properties are members of the PROPSETID_ALLOCATOR_CONTROL property set:

KSPROPERTY_ALLOCATOR_CONTROL_HONOR_COUNT

KSPROPERTY_ALLOCATOR_CONTROL_SURFACE_SIZE

DirectShow Interface

Properties in the PROPSETID_ALLOCATOR_CONTROL property set are used by the Overlay Mixer to control Microsoft® DirectDraw® surface allocation and dimensions. This pin property set should be implemented by devices that want to control the number of DirectDraw surfaces allocated and indicate to the Overlay Mixer that video scaling is not possible at the video decoder.


KSPROPERTY_ALLOCATOR_CONTROL_HONOR_COUNT

KSPROPERTY_ALLOCATOR_CONTROL_HONOR_COUNT informs the Overlay Mixer how to determine the number of DirectDraw surfaces to allocate.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | No | N/A

Property Data

Information pertaining to this property is expressed in a DWORD. Drivers that support this property should return 1 to force the Overlay Mixer to use the number of surfaces specified in the KSPROPERTY_CONNECTION_ALLOCATORFRAMING property. A return value of zero causes the Overlay Mixer to calculate how many surfaces to allocate.

Ranges and Default Values

None


KSPROPERTY_ALLOCATOR_CONTROL_SURFACE_SIZE

KSPROPERTY_ALLOCATOR_CONTROL_SURFACE_SIZE is used to inform client filters that provide DirectDraw surface allocators (such as Overlay Mixer), that a capture is in progress and that DirectDraw surfaces must be allocated at a fixed size regardless of the present size of the overlay.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | No | N/A

Property Data

Drivers that support this property return two DWORDs that describe the width and height of the required overlay surface. The Overlay Mixer will allocate overlay surfaces of this size. If this size is not the size specified in the MediaType during pin connection then the video will be scaled at the video port to this size. No other scaling at the video port will occur regardless of the scaling abilities of the VGA chip.

The Overlay Mixer will always query this new property if it is connected to its upstream filter through a video port on its primary input pin. If that filter does not implement this property, the Overlay Mixer will assume that it is not capturing and will scale the video at the video port as necessary to keep the video displayed correctly.

Ranges and Default Values

None


PROPSETID_TUNER

User-mode clients use the elements of the PROPSETID_TUNER property set to query or control devices that support TV or radio tuning. The property set supports multi-standard video tuners as well as tuners with multiple inputs. The following properties are members of the PROPSETID_TUNER property set:

KSPROPERTY_TUNER_CAPS

KSPROPERTY_TUNER_FREQUENCY

KSPROPERTY_TUNER_IF_MEDIUM

KSPROPERTY_TUNER_INPUT

KSPROPERTY_TUNER_MODE

KSPROPERTY_TUNER_MODE_CAPS

KSPROPERTY_TUNER_STANDARD

KSPROPERTY_TUNER_STATUS

A single tuning device may support tuning digital and analog TV and AM/FM radio, as well as digital satellite systems (DSS). The driver indicates which tuning modes it supports through the KSPROPERTY_TUNER_CAPS property. Properties of the individual tuning modes are indicated through the KSPROPERTY_TUNER_MODES_CAPS property.

World-wide, analog TV signals can be broadcast in accordance with several different analog TV standards such as NTSC, PAL, or SECAM. Clients use the KSPROPERTY_TUNER_MODES_CAPS property to query the supported standards, and use KSPROPERTY_TUNER_STANDARD to get or set the current standard for a TV tuner. Analog signal standards are represented by symbolic constants in the form KS_AnalogVideo_Xxx. A complete list may be found in ksmedia.h.

DirectShow Interface

Properties in the PROPSETID_TUNER property set are accessible in user mode through the DirectShow IAMTVTuner interface.


KSPROPERTY_TUNER_CAPS

KSPROPERTY_TUNER_CAPS is used to describe the basic capabilities of a tuner.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | Yes
Set (Write) | No | N/A

Property Data

Information pertaining to this property is expressed in the KSPROPERTY_TUNER_CAPS_S structure.

Ranges and Default Values

None

See Also

KSPROPERTY_TUNER_CAPS_S


KSPROPERTY_TUNER_FREQUENCY

The KSPROPERTY_TUNER_FREQUENCY property is used to set or get the current frequency or channel of the tuner.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | Yes
Set (Write) | Yes | Yes

Property Data

Information pertaining to this property is expressed in the KSPROPERTY_TUNER_FREQUENCY_S structure.

Ranges and Default Values

None

See Also

KSPROPERTY_TUNER_FREQUENCY_S


KSPROPERTY_TUNER_IF_MEDIUM

KSPROPERTY_TUNER_IF_MEDIUM is used to describe the medium for the intermediate frequency pin for devices that support Digital TV tuning. If this property is supported, kstvtune.ax will create an additional pin that represents the hardware-based MPEG-2 transport stream originating at the tuner. This pin is used solely to define graph topology. Data samples flowing through the user-mode stream from this pin on kstvtune.ax consist of KS_TVTUNER_CHANGE_INFO structures.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | No | N/A

Property Data

The IFMedium member of the KSPROPERTY_TUNER_IF_MEDIUM_S structure is used to specify the medium of the intermediate frequency pin.

Ranges and Default Values

None

See Also

KSPROPERTY_TUNER_IF_MEDIUM_S


KSPROPERTY_TUNER_INPUT

The KSPROPERTY_TUNER_INPUT property describes the input of the tuner in the current tuning mode. This property is normally used to select between cable and antenna inputs to a tuner.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | Yes
Set (Write) | Yes | Yes

Property Data

Information pertaining to this property is expressed in the KSPROPERTY_TUNER_INPUT_S structure.

Ranges and Default Values

None

See Also

KSPROPERTY_TUNER_INPUT_S


KSPROPERTY_TUNER_MODE

User-mode clients use the KSPROPERTY_TUNER_MODE property to get or set the tuning mode of a device. A mode is typically analog TV, digital TV, FM, AM, or DSS.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | Yes
Set (Write) | Yes | Yes

Property Data

Information pertaining to this property is expressed in the KSPROPERTY_TUNER_MODE_S structure.

Ranges and Default Values

None

See Also

KSPROPERTY_TUNER_MODE_S


KSPROPERTY_TUNER_MODE_CAPS

KSPROPERTY_TUNER_MODE_CAPS describes the capabilities of a tuning mode for a device that supports TV or radio tuning. For each separate mode (analog TV, digital TV, FM, AM, or DSS), the driver reports capabilities such as minimum and maximum frequency, tuning granularity, settling time, and number of inputs.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | Yes
Set (Write) | No | N/A

Property Data

Information pertaining to this property is expressed in the KSPROPERTY_TUNER_MODE_CAPS_S_S structure.

Ranges and Default Values

None

See Also

KSPROPERTY_TUNER_MODE_CAPS_S


KSPROPERTY_TUNER_STANDARD

The KSPROPERTY_TUNER_STANDARD property is used to get and set the current analog video standard. This property is used only when the current mode is KSPROPERTY_TUNER_MODE_TV.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | Yes
Set (Write) | Yes | Yes

Property Data

Information pertaining to this property is expressed in the KSPROPERTY_TUNER_STANDARD_S structure.

Ranges and Default Values

None

See Also

KSPROPERTY_TUNER_STANDARD_S


KSPROPERTY_TUNER_STATUS

The KSPROPERTY_TUNER_STATUS property is used to retrieve information about the tuning process including the current frequency, phase locked loop (PLL) offset, and signal strength.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | Yes
Set (Write) | No | N/A

Property Data

Information pertaining to this property is expressed in the KSPROPERTY_TUNER_STATUS_S structure.

Ranges and Default Values

None

See Also

KSPROPERTY_TUNER_STATUS_S


PROPSETID_VIDCAP_CAMERACONTROL

User-mode clients use the elements of the PROPSETID_VIDCAP_CAMERACONTROL property set to query or control devices that can function as digital cameras. The controls provided are a subset of the ITU T.RDC (www.itu.int) standard. Support for this property set is optional and should be implemented only by devices that offer camera control settings.

The members of the PROPSETID_VIDCAP_CAMERACONTROL property set that control lens and exposure settings for digital camera are:

KSPROPERTY_CAMERACONTROL_EXPOSURE

KSPROPERTY_CAMERACONTROL_FOCUS

KSPROPERTY_CAMERACONTROL_IRIS

KSPROPERTY_CAMERACONTROL_ZOOM

The members of the PROPSETID_VIDCAP_CAMERACONTROL property set that control camera positioning are:

KSPROPERTY_CAMERACONTROL_PAN

KSPROPERTY_CAMERACONTROL_ROLL

KSPROPERTY_CAMERACONTROL_TILT

DirectShow Interface

Properties in the PROPSETID_VIDCAP_CAMERACONTROL property set are accessible in user mode through the DirectShow IAMCameraControl interface.


KSPROPERTY_CAMERACONTROL_EXPOSURE

User-mode clients use KSPROPERTY_CAMERACONTROL_EXPOSURE to get or set the camera's length of exposure setting.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | Yes | No

Property Data

The Value member of the KSPROPERTY_CAMERACONTROL_S structure is used to specify the length of exposure. This value is expressed in log base 2 seconds, thus for values less than zero, the exposure time is 1/2n seconds. For positive values and zero, the exposure time is 2n seconds. For example:

Value | -7 | -6 | -5 | -4 | -3 | -2 | -1 | 0 | 1
Seconds | 1/128 | 1/64 | 1/32 | 1/16 | 1/8 | 1/4 | 1/2 | 1 | 2

Ranges and Default Values

Every video capture driver that supports this property must define its own range and default value for this property. The value type must be VT_I4.

See Also

KSPROPERTY_CAMERACONTROL_S


KSPROPERTY_CAMERACONTROL_FOCUS

User-mode clients use KSPROPERTY_CAMERACONTROL_FOCUS to get or set the camera's focus setting.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | Yes | No

Property Data

The Value member of the KSPROPERTY_CAMERACONTROL_S structure is used to specify the focus setting. This value is expressed in millimeters.

Ranges and Default Values

Every video capture driver that supports this property must define its own range and default value for this property. The value type must be VT_I4.

See Also

KSPROPERTY_CAMERACONTROL_S


KSPROPERTY_CAMERACONTROL_IRIS

User-mode clients use this property to get or set a camera's aperture setting.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | Yes | No

Property Data

The Value member of the KSPROPERTY_CAMERACONTROL_S structure is used to specify the camera's aperture setting. This value is expressed in units of fstop * 10.

Ranges and Default Values

Every video capture driver that supports this property must define its own range and default value for this property. The value type must be VT_I4.

See Also

KSPROPERTY_CAMERACONTROL_S


KSPROPERTY_CAMERACONTROL_PAN

User-mode clients use KSPROPERTY_CAMERACONTROL_PAN to get or set the camera's pan setting.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | Yes | No

Property Data

The Value member of the KSPROPERTY_CAMERACONTROL_S structure is used to specify the pan setting. This value is expressed in degrees. Positive values indicate that the camera is rotated clockwise. Negative values indicate that the camera is rotated counterclockwise.

Camera's Pan Setting

Ranges and Default Values

Every video capture driver that supports this property must define a range and default value for this property. The range for the device must be a subset of -180 to 180 inclusive and the default value must be zero. The value type must be VT_I4.

See Also

KSPROPERTY_CAMERACONTROL_S


KSPROPERTY_CAMERACONTROL_ROLL

User-mode clients use KSPROPERTY_CAMERACONTROL_ROLL to get or set the camera's roll setting.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | Yes | No

Property Data

The Value member of the KSPROPERTY_CAMERACONTROL_S structure is used to specify the roll setting. This value is expressed in degrees. Positive values cause a clockwise rotation of the camera along the image-viewing axis. Negative values cause a counterclockwise rotation of the camera.

Camera's Roll Setting

Ranges and Default Values

Every video capture driver that supports this property must define a range and default value for this property. The range for the device must be a subset of -180 to 180 and the default value must be zero. The value type must be VT_I4.

See Also

KSPROPERTY_CAMERACONTROL_S


KSPROPERTY_CAMERACONTROL_TILT

User-mode clients use KSPROPERTY_CAMERACONTROL_TILT to get or set the camera's tilt setting.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | Yes | No

Property Data

The Value member of the KSPROPERTY_CAMERACONTROL_S structure is used to specify the tilt setting. This value is expressed in degrees. Positive values point the imaging plane up. Negative values point the imaging plane down.

Camera's Tilt Setting

Ranges and Default Values

Every video capture driver that supports this property must define a range and default value for this property. The range for the device must be a subset of -180 to 180 and the default value must be zero. The value type must be VT_I4.

See Also

KSPROPERTY_CAMERACONTROL_S


KSPROPERTY_CAMERACONTROL_ZOOM

User-mode clients use KSPROPERTY_CAMERACONTROL_ZOOM to get or set the camera's zoom setting.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | Yes | No

Property Data

The Value member of the KSPROPERTY_CAMERACONTROL_S structure is used to specify the zoom. This value is expressed in millimeters.

Ranges and Default Values

Every video capture driver that supports this property must define a range and default value for this property. The range for the device must be a subset of 10 to 600. The value type must be VT_I4.

See Also

KSPROPERTY_CAMERACONTROL_S


PROPSETID_VIDCAP_CROSSBAR

The PROPSETID_VIDCAP_CROSSBAR property set is used to get or set information pertaining to routing video and audio signals. The crossbar is modeled after a general switching matrix with N inputs and M outputs. Any of the input signals can be routed to one or more of the outputs. Actual hardware implementations probably will allow only a subset of this general routing capability.

The crossbar can be used to route either digital or analog signals. A single crossbar can route both video and audio signals. Video pins optionally can indicate an audio pin that is related to the video pin.

The following properties are members of the PROPSETID_VIDCAP_CROSSBAR property set:

KSPROPERTY_CROSSBAR_CANROUTE

KSPROPERTY_CROSSBAR_CAPS

KSPROPERTY_CROSSBAR_PININFO

KSPROPERTY_CROSSBAR_ROUTE

DirectShow Interface

Properties in the PROPSETID_VIDCAP_CROSSBAR property set are accessed through the DirectShow IAMCrossbar interface.


KSPROPERTY_CROSSBAR_CANROUTE

The KSPROPERTY_CROSSBAR_CANROUTE property is used to determine whether the device is capable of supporting a specified routing.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | Yes
Set (Write) | No | N/A

Property Data

Information pertaining to this property is expressed in the KSPROPERTY_CROSSBAR_ROUTE_S structure.

Ranges and Default Values

None

See Also

KSPROPERTY_CROSSBAR_ROUTE_S


KSPROPERTY_CROSSBAR_CAPS

The KSPROPERTY_CROSSBAR_CAPS property is used to get the crossbar capabilities of the device (the number of input and output pins on the crossbar).

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | Yes
Set (Write) | No | N/A

Property Data

Information pertaining to this property is expressed in the KSPROPERTY_CROSSBAR_CAPS_S structure.

Ranges and Default Values

None

See Also

KSPROPERTY_CROSSBAR_CAPS_S


KSPROPERTY_CROSSBAR_PININFO

The KSPROPERTY_CROSSBAR_PININFO property is used to get the type of physical connection represented by the pin (Data Direction Flow /Medium GUIDs/Pin Type). For video pins, this property will also indicate whether or not there is an audio pin associated with a particular video pin.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | Yes
Set (Write) | No | N/A

Property Data

Information pertaining to this property is expressed in the KSPROPERTY_CROSSBAR_PININFO_S structure.

Ranges and Default Values

None

See Also

KSPROPERTY_CROSSBAR_PININFO_S


KSPROPERTY_CROSSBAR_ROUTE

The KSPROPERTY_CROSSBAR_ROUTE property is used to route a video or audio stream by specifying an output pin index and an input pin index.

As a special case, an audio output pin should mute the output audio stream when routed to an input pin index of -1. This is typically used to mute the audio during a channel change.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | No | N/A
Set (Write) | Yes | Yes

Property Data

Information pertaining to this property is expressed in the KSPROPERTY_CROSSBAR_ROUTE_S structure.

Ranges and Default Values

None

See Also

KSPROPERTY_CROSSBAR_ROUTE_S


PROPSETID_VIDCAP_DROPPEDFRAMES

The following properties are members of the PROPSETID_DROPPED_FRAMES property set:

KSPROPERTY_DROPPEDFRAMES_CURRENT

Microsoft® DirectShow® Interface

None


KSPROPERTY_DROPPEDFRAMES_CURRENT

KSPROPERTY_DROPPED_FRAMES_CURRENT is used to dynamically query the capture driver for the number of frames captured, the number of frames dropped, and the average frame size. The counts of frames captured and frames dropped should reset when the stream transitions from stop to pause.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | Yes
Set (Write) | No | N/A

Property Data

Information pertaining to this property is expressed in the KSPROPERTY_DROPPEDFRAMES_CURRENT_S structure.

Ranges and Default Values

None


PROPSETID_VIDCAP_VIDEOCOMPRESSION

The PROPSETID_VIDCAP_VIDEOCOMPRESSION properties are used to get and set video compression settings for the device. Support for this property set is optional and should be implemented only by devices that have a video compression codec.

The following properties are members of the PROPSETID_VIDCAP_VIDEOCOMPRESSION property set:

KSPROPERTY_VIDEOCOMPRESSION_GETINFO

KSPROPERTY_VIDEOCOMPRESSION_KEYFRAME_RATE

KSPROPERTY_VIDEOCOMPRESSION_OVERRIDE_FRAME_SIZE

KSPROPERTY_VIDEOCOMPRESSION_OVERRIDE_KEYFRAME

KSPROPERTY_VIDEOCOMPRESSION_PFRAMES_PER_KEYFRAME

KSPROPERTY_VIDEOCOMPRESSION_QUALITY

KSPROPERTY_VIDEOCOMPRESSION_WINDOWSIZE

DirectShow Interface

Properties in the PROPSETID_VIDCAP_VIDEOCOMPRESSION property set are accessible in user mode through the DirectShow IAMVideoCompression interface.


KSPROPERTY_VIDEOCOMPRESSION_GETINFO

The KSPROPERTY_VIDEOCOMPRESSION_GETINFO property is used to get the video compression capabilities of the device.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | Yes
Set (Write) | No | N/A

Property Data

Information pertaining to this property is expressed in the KSPROPERTY_VIDEOCOMPRESSION_GETINFO_S structure.

Ranges and Default Values

None

See Also

KSPROPERTY_VIDEOCOMPRESSION_GETINFO_S


KSPROPERTY_VIDEOCOMPRESSION_KEYFRAME_RATE

The KSPROPERTY_VIDEOCOMPRESSION_KEYFRAME_RATE property is used to get or set the key frame rate.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | Yes | No

Property Data

The Value member of the KSPROPERTY_VIDEOCOMPRESSION_S structure is used to get or set this property.

Ranges and Default Values

None

See Also

KSPROPERTY_VIDEOCOMPRESSION_S


KSPROPERTY_VIDEOCOMPRESSION_OVERRIDE_FRAME_SIZE

The KSPROPERTY_VIDEOCOMPRESSION_OVERRIDE_FRAME_SIZE property is used to temporarily override the frame size. This property is not supported by capture drivers.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | Yes | No

Property Data

The Value member of the KSPROPERTY_VIDEOCOMPRESSION_S structure is used to specify the overriding data rate for the frame.

Ranges and Default Values

None

Comments

Drivers that support this property should set the KS_CompressionCaps_CanCrunch flag in the Capabilities member of the KSPROPERTY_VIDEOCOMPRESSION_GETINFO_S structure that is used to get the device's video compression capabilities.

See Also

KSPROPERTY_VIDEOCOMPRESSION_S, KSPROPERTY_VIDEOCOMPRESSION_GETINFO_S


KSPROPERTY_VIDEOCOMPRESSION_OVERRIDE_KEYFRAME

The KSPROPERTY_VIDEOCOMPRESSION_OVERRIDE_KEYFRAME property is used to temporarily override the key frame rate. This property is not supported by capture drivers.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | No | N/A
Set (Write) | Yes | No

Property Data

The Value member of the KSPROPERTY_VIDEOCOMPRESSION_S structure is used to specify the number of the frame that is to be made a key frame.

Ranges and Default Values

None

See Also

KSPROPERTY_VIDEOCOMPRESSION_S


KSPROPERTY_VIDEOCOMPRESSION_PFRAMES_PER_KEYFRAME

The KSPROPERTY_VIDEOCOMPRESSION_PFRAMES_PER_KEYFRAME property is used to get or set the predicted (P) frame interval.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | Yes | No

Property Data

The Value member of the KSPROPERTY_VIDEOCOMPRESSION_S structure is used to specify the number of P frames per key frame. If a set request and the value is negative, the driver should set the P frame rate to the default value.

Ranges and Default Values

None

Comments

Drivers that support this property should set the KS_VideoCompressionCaps_CanBFrame flag in the Capabilities member of the KSPROPERTY_VIDEOCOMPRESSION_GETINFO_S structure that is used to get the driver's video compression capabilities.

See Also

KSPROPERTY_VIDEOCOMPRESSION_S, KSPROPERTY_VIDEOCOMPRESSION_GETINFO_S


KSPROPERTY_VIDEOCOMPRESSION_QUALITY

The KSPROPERTY_VIDECOMPRESSION_QUALITY property is used to get or set the quality of video compression.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | Yes | No

Property Data

The Value member of the KSPROPERTY_VIDEOCOMPRESSION_S structure is used to specify the quality range.

Ranges and Default Values

Values for this property range from 0 to 10000. Zero indicates the lowest quality, 10000 the highest. The driver determines its own default value.

Comments

Drivers that support this property should set the KS_CompressionCaps_CanQuality flag in the Capabilities member of the KSPROPERTY_VIDEOCOMPRESSION_GETINFO_S structure that is used to get the driver's video compression capabilities. If a driver sets the KS_CompressionCaps_CanQuality, it should provide both get and set support for the property.

See Also

KSPROPERTY_VIDEOCOMPRESSION_S, KSPROPERTY_VIDEOCOMPRESSION_GETINFO_S


KSPROPERTY_VIDEOCOMPRESSION_WINDOWSIZE

The KSPROPERTY_VIDECOMPRESSION_WINDOWSIZE property is used to get or set the window size. The video compression window size is the number of frames over which the average size cannot exceed the specified data rate.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | Yes | No

Property Data

The Value member of the KSPROPERTY_VIDEOCOMPRESSION_S structure is used to specify the window size.

Ranges and Default Values

None

Comments

Drivers that support this property should set the KS_CompressionCaps_CanWindow flag in the Capabilities member of the KSPROPERTY_VIDEOCOMPRESSION_GETINFO_S structure that is used to get the driver's video compression capabilities. If a driver sets the KS_CompressionCaps_CanWindow flag, it should provide both get and set support for the property.

For a window of size n, the average frame size of any consecutive n frames will not exceed the stream's specified data rate. Individual frames can be larger or smaller. For example, if the data rate has been set to 100 kilobytes per second (KBps) on a 10 frame per second (fps) movie, each frame must be less than or equal to 10 kilobytes. The individual frames can be any size as long as the average size is less than or equal to 10 kilobytes.

See Also

KSPROPERTY_VIDEOCOMPRESSION_S, KSPROPERTY_VIDEOCOMPRESSION_GETINFO_S


PROPSETID_VIDCAP_TVAUDIO

The PROPSETID_VIDCAP_TVAUDIO property set is used to control settings unique to audio from television sources. This includes secondary audio program (SAP), and stereo or mono selection. These controls are generally found on devices external to the system audio mixer.

The following properties are members of the PROPSETID_VIDCAP_TVAUDIO property set:

KSPROPERTY_TVAUDIO_CAPS

KSPROPERTY_TVAUDIO_CURRENTLY_AVAILABLE_MODES

KSPROPERTY_TVAUDIO_MODE

DirectShow Interface

Properties in the PROPSETID_VIDCAP_TVAUDIO property set are accessible in user mode through the DirectShow IAMTVAudio interface.


KSPROPERTY_TVAUDIO_CAPS

The KSPROPERTY_TVAUDIO_CAPS property is used to retrieve the capabilities of the TV audio device.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | Yes
Set (Write) | No | N/A

Property Data

Information pertaining to this property is specified in a KSPROPERTY_TVAUDIO_CAPS_S structure.

Ranges and Default Values

None

See Also

KSPROPERTY_TVAUDIO_CAPS_S


KSPROPERTY_TVAUDIO_MODE

The KSPROPERTY_TVAUDIO_MODE property is used to set the audio mode for the device.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | Yes
Set (Write) | Yes | Yes

Property Data

The Mode member of the KSPROPERTY_TVAUDIO_MODE_S structure is used to specify the audio mode.

Ranges and Default Values

None

See Also

KSPROPERTY_TVAUDIO_MODE_S


PROPSETID_VIDCAP_VIDEOCONTROL

The PROPOSETID_VIDCAP_VIDEOCONTROL property set is used to control additional aspects of the capture process such as enumerating available frame rates and image orientation.

Support of this property set is mandatory for devices that cannot capture at arbitrary frame rates. Generally, analog digitizers can support any frame rate request that USB and 1394 conferencing cameras support, but with a limited set of frame rates.

The following properties are members of the PROPSETID_VIDCAP_VIDEOCONTROL property set:

KSPROPERTY_VIDEOCONTROL_CAPS

KSPROPERTY_VIDEOCONTROL_ACTUAL_FRAME_RATE

KSPROPERTY_VIDEOCONTROL_FRAME_RATES

KSPROPERTY_VIDEOCONTROL_MODE

DirectShow Interface

This property set currently is not available through a DirectShow interface.


KSPROPERTY_VIDEOCONTROL_ACTUAL_FRAME_RATE

The KSPROPERTY_VIDEOCONTROL_ACTUAL_FRAME_RATE property is used to get the frame rate at which the device is streaming for the specified pin.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | No | N/A

Property Data

Information pertaining to this property is specified in a KSPROPERTY_VIDEOCONTROL_ACTUAL_FRAME_RATE_S structure.

Ranges and Default Values

None

See Also

KSPROPERTY_VIDEOCONTROL_ACTUAL_FRAME_RATE_S


KSPROPERTY_VIDEOCONTROL_CAPS

The KSPROPERTY_VIDEOCONTROL_CAPS property is used to identify the video control capabilities of the device.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | Yes
Set (Write) | No | N/A

Property Data

The VideoControlCaps member of the KSPROPERTY_VIDEOCONTROL_CAPS_S structure is used to specify the video control capabilities of the device.

Ranges and Default Values

None

See Also

KSPROPERTY_VIDEOCONTROL_CAPS_S


KSPROPERTY_VIDEOCONTROL_FRAME_RATES

The KSPROPERTY_VIDEOCONTROL_FRAME_RATES property is used to enumerate the available frame rates.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | No | N/A

Property Data

The available frame rates are returned in a KSMULTIPLE_ITEM array. The application sends the driver a KSPROPERTY_VIDEOCONTROL_FRAMES_RATES request specifying the stream index and image dimensions in a KSPROPERTY_VIDEOCONTROL_FRAME_RATES_S structure. The driver returns frame rates information in the caller's KSMULTIPLE_ITEM array buffer.

If the size of the buffer passed to the driver is zero, the driver should set the NumberOfBytesToTransfer member of the HW_STREAM_REQUEST_BLOCK structures passed to the driver to the size of the buffer required and return STATUS_BUFFER_OVERFLOW. If the buffer passed to the driver is greater than zero, but is not large enough to contain the frame rates information, the driver should return STATUS_BUFFER_TOO_SMALL to the caller. If the caller passes in a large enough buffer, the driver should enter the frame rate information into the buffer and return STATUS_SUCCESS.

Ranges and Default Values

Individual values are given in units of 100 Nanoseconds.

See Also

KSPROPERTY_VIDEOCONTROL_FRAME_RATES_S


KSPROPERTY_VIDEOCONTROL_MODE

The KSPROPERTY_VIDEOCONTROL_MODE property is used to control the mode of image production. This includes settings for horizontal and vertical image flipping, and enabling frame capture by an external trigger.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | Yes | No

Property Data

The Mode member of the KSPROPERTY_VIDEOCONTROL_MODE_S structure is used to specify the video control mode.

Ranges and Default Values

None

See Also

KSPROPERTY_VIDEOCONTROL_MODE_S


PROPSETID_VIDCAP_VIDEODECODER

The PROPSETID_VIDCAP_VIDEODECODER property set is used to control an analog video decoder. An analog video decoder converts baseband analog video signals into a digital format such as RGB or YUV. Support for this property set is mandatory for analog video capture devices.

The following properties are members of the PROPSETID_VIDCAP_VIDEODECODER property set:

KSPROPERTY_VIDEODECODER_CAPS

KSPROPERTY_VIDEODECODER_OUTPUT_ENABLE

KSPROPERTY_VIDEODECODER_STANDARD

KSPROPERTY_VIDEODECODER_STATUS

KSPROPERTY_VIDEODECODER_VCR_TIMING

DirectShow Interface

Properties in the PROPSETID_VIDCAP_VIDEODECODER property set are accessible in user mode through the DirectShow IAMAnalogVideoDecoder interface.


KSPROPERTY_VIDEODECODER_CAPS

The KSPROPERTY_VIDEODECODER_CAPS property describes the basic capabilities of a video decoder.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | Yes
Set (Write) | No | N/A

Property Data

Information pertaining to this property is specified in a KSPROPERTY_VIDEODECODER_CAPS_S structure.

Ranges and Default Values

None

See Also

KSPROPERTY_VIDEODECODER_CAPS

Built on Wednesday, July 11, 2001


KSPROPERTY_VIDEODECODER_OUTPUT_ENABLE

The KSPROPERTY_VIDEODECODER_OUTPUT_ENABLE property is used to tri-state the output of video decoders that reside on a shared video port bus.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | Yes | No

Property Data

The Value member of the KSPROPERTY_VIDEODECODER_S structure is used to specify the output enable setting. A value of zero indicates tri-state output. A nonzero value indicates that the device is actively driving the video port bus.

Ranges and Default Values

None

See Also

KSPROPERTY_VIDEODECODER_S


KSPROPERTY_VIDEODECODER_STANDARD

The KSPROPERTY_VIDEODECODER_STANDARD property is used to set and retrieve the current analog video standard.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | Yes
Set (Write) | Yes | Yes

Property Data

The Value member of the KSPROPERTY_VIDEODECODER_S structure is used to specify the current analog video standard. For get requests, the driver should set this member to one of the following KS_AnalogVideoStandard values that are defined in ksmedia.h. For set requests, the caller should request one of these values:

KS_AnalogVideo_None
KS_AnalogVideo_NTSC_M
KS_AnalogVideo_NTSC_M_J
KS_AnalogVideo_NTSC_433

KS_AnalogVideo_PAL_B
KS_AnalogVideo_PAL_D
KS_AnalogVideo_PAL_G
KS_AnalogVideo_PAL_H
KS_AnalogVideo_PAL_I
KS_AnalogVideo_PAL_M
KS_AnalogVideo_PAL_N

KS_AnalogVideo_PAL_60

KS_AnalogVideo_SECAM_B
KS_AnalogVideo_SECAM_D
KS_AnalogVideo_SECAM_G
KS_AnalogVideo_SECAM_H
KS_AnalogVideo_SECAM_K
KS_AnalogVideo_SECAM_K1
KS_AnalogVideo_SECAM_L
KS_AnalogVideo_SECAM_L1

Ranges and Default Values

None

See Also

KSPROPERTY_VIDEODECODER_S


KSPROPERTY_VIDEODECODER_STATUS

The KSPROPERTY_VIDEDECODER_STATUS property is used to retrieve status information from the video decoder.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | Yes
Set (Write) | No | N/A

Property Data

Information pertaining to this property is specified in a KSPROPERTY_VIDEODECODER_STATUS_S structure.

Ranges and Default Values

None

See Also

KSPROPERTY_VIDEODECODER_STATUS_S


KSPROPERTY_VIDEODECODER_VCR_TIMING

The KSPROPERTY_VIDEODECODER_VCR_TIMING property is used to control whether the VCR is expecting video from a tape source or a broadcast source. The timing accuracy of synchronization pulses on tape sources typically is not as accurate as from broadcast sources.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | Yes | No

Property Data

The Value member of the KSPROPERTY_VIDEODECODER_S structure indicates whether to use VCR timing. A value of zero indicates a broadcast source. A nonzero value indicates a tape source.

Ranges and Default Values

None

See Also

KSPROPERTY_VIDEODECODER_S


PROPSETID_VIDCAP_VIDEOPROCAMP

The PROPSETID_VIDCAP_VIDEOPROCAMP property set is used to adjust image color attributes in either analog or digital domains. This property set should be implemented for devices that allow adjustment of brightness, contrast, hue, and other image quality settings.

The following properties are members of the PROPSETID_VIDCAP_VIDEOPROCAMP property set:

KSPROPERTY_VIDEOPROCAMP_BACKLIGHT_COMPENSATION

KSPROPERTY_VIDEOPROCAMP_BRIGHTNESS

KSPROPERTY_VIDEOPROCAMP_COLORENABLE

KSPROPERTY_VIDEOPROCAMP_CONTRAST

KSPROPERTY_VIDEOPROCAMP_GAMMA

KSPROPERTY_VIDEOPROCAMP_SATURATION

KSPROPERTY_VIDEOPROCAMP_SHARPNESS

KSPROPERTY_VIDEOPROCAMP_WHITEBALANCE

Each property in the PROPSETID_VIDEOPROCAMP property set includes a range and default value. The range for the property set is defined in real world units to allow programmatic control of parameters. Since actual hardware is often limited in how closely it can approximate this ideal, each device also can define a subset of this theoretical range and the step size. This allows controls, such as sliders and scroll bars, to be programmed to give a visible effect for each step.

For example, the overall theoretical range for brightness is defined as -100 to 100 IRE units. IRE is an NTSC-centric measure of video levels where zero corresponds to the blanking, or full-black level, and 100 represents pure white. If a VideoProcAmp was able to shift a pure black input signal (perhaps generated by completely covering the camera lens) and cause it to appear as pure white, then its range would be zero to 100 IRE.

Most VideoProcAmps actually provide a limited range of brightness control. One way to measure the range is to cover the camera lens and determine the output signal over the range of adjustment and then normalize this to IRE units. After the range has been calculated, the stepping value can be derived by taking the maximum and minimum values and dividing by the number of adjustment steps (max + min)/N adjustment steps.

Note The actual values used in the property sets are multiplied by 100 to give improved granularity.

DirectShow Interface

Properties in the PROPSETID_VIDCAP_VIDEOPROCAMP property set are accessible in user mode through the DirectShow IAMVideoProcAmp interface.


KSPROPERTY_VIDEOPROCAMP_BACKLIGHT_COMPENSATION

The KSPROPERTY_VIDEOPROCAMP_BACKLIGHT_COMPENSATION property is used to set and get the backlight compensation setting on the camera.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | Yes | No

Property Data

The Value member of the KSPROPERTY_VIDEOPROCAMP_S structure is used to specify the backlight compensation. A value of zero indicates that the backlight compensation is disabled. A value of 1 indicates that the backlight compensation is enabled.

Ranges and Default Values

This value may be either 0 or 1. The default value for this property is 1. The value type must be VT_I4.

Comments

The values used in the property sets are multiplied by 100 to give improved granularity.

See Also

KSPROPERTY_VIDEOPROCAMP_S


KSPROPERTY_VIDEOPROCAMP_COLORENABLE

The KSPROPERTY_VIDEOPROCAMP_COLORENABLE property is used to set and retrieve the color enable setting.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | Yes | No

Property Data

The Value member of the KSPROPERTY_VIDEOPROCAMP_S structure is used to specify the color enable setting. A value of zero indicates that color is disabled. A value of 1 indicates that color is enabled.

Ranges and Default Values

This value may be either 0 or 1. The default value for this property is 1. The value type must be VT_I4.

See Also

KSPROPERTY_VIDEOPROCAMP_S


KSPROPERTY_VIDEOPROCAMP_CONTRAST

The KSPROPERTY_VIDEOPROCAMP_CONTRAST property is used to set or get the camera's contrast or luma gain setting.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | Yes | No

Property Data

The Value member of the KSPROPERTY_VIDEOPROCAMP_S structure is used to specify the contrast value. The contrast value is expressed as a gain factor multiplied by 100.

Ranges and Default Values

Every video capture driver must define a range and default value for the Value member of this property. The required range must be a subset of 0 to 10000, and the default value must be 100 (1x). The value type must be VT_I4.

See Also

KSPROPERTY_VIDEOPROCAMP_S


KSPROPERTY_VIDEOPROCAMP_GAMMA

The KSPROPERTY_VIDEOPROCAMP_GAMMA property is used to get and set the camera's gamma setting.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | Yes | No

Property Data

The Value member of the KSPROPERTY_VIDEOPROCAMP_S structure is used to specify the gamma setting. The value of the gamma setting is expressed in gamma multiplied by 100.

Ranges and Default Values

Every video capture driver must define a range and default value for this property. The required range must be a subset of 1 to 500, and the default values are typically 100 (gamma = 1) or 220 (gamma = 2.2). The value type must be VT_I4.

See Also

KSPROPERTY_VIDEOPROCAMP_S


KSPROPERTY_VIDEOPROCAMP_HUE

The KSPROPERTY_VIDEOPROCAMP_HUE property is used to set and get the hue setting of the camera.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | Yes | No

Property Data

The Value member of the KSPROPERTY_VIDEOPROCAMP_S structure is used to specify the hue setting. The value of the hue setting is expressed in degrees multiplied by 100.

Ranges and Default Values

Every video capture driver must define a range and default value for the Value member of this property. The required range must be a subset of -18000 to 18000 (-180 to +180 degrees). The default value must be zero. The value type must be VT_I4.

See Also

KSPROPERTY_VIDEOPROCAMP_S


KSPROPERTY_VIDEOPROCAMP_SATURATION

The KSPROPERTY_VIDEOPROCAMP_SATURATION property is used to set and get the saturation or chroma gain setting of the camera.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | Yes | No

Property Data

The Value member of the KSPROPERTY_VIDEOPROCAMP_S structure is used to specify the saturation setting. The value of the saturation setting is expressed as gain multiplied by 100.

Ranges and Default Values

Every video capture driver must define a range and default value for this property. The required range must be a subset of 0 to 10000, and the default value must be 100 (1x). The value type must be VT_I4.

See Also

KSPROPERTY_VIDEOPROCAMP_S


KSPROPERTY_VIDEOPROCAMP_SHARPNESS

The KSPROPERTY_VIDEOPROCAMP_SHARPNESS property is used to set and get the camera's sharpness setting.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | Yes | No

Property Data

The Value member of the KSPROPERTY_VIDEOPROCAMP_S structure is used to specify the sharpness setting. Sharpness is expressed in arbitrary units.

Ranges and Default Values

Every video capture driver must define a range and default value for the value of this property. The required range must be a subset of 0 to 100, and the default value must be 50. The value type must be VT_I4.

See Also

KSPROPERTY_VIDEOPROCAMP_S


KSPROPERTY_VIDEOPROCAMP_WHITEBALANCE

The KSPROPERTY_VIDEOPROCAMP_WHITEBALANCE property is used to set or get the camera's white balance setting.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | Yes | No

Property Data

The Value member of the KSPROPERTY_VIDEOPROCAMP_S structure is used to specify the white balance setting. The white balance value is expressed as a color temperature in degrees Kelvin.

Ranges and Default Values

The range and default value for white balance is device-dependent. Every video capture driver must define a range and default value for this property. The value type must be VT_I4.

See Also

KSPROPERTY_VIDEOPROCAMP_S


Video Capture Structures

This section describes structures used by video capture minidrivers to pass property values, data format, data range, and general video capture information between the minidriver and the stream class driver and user-mode applications.


KS_ANALOGVIDEOINFO

The KS_ANALOGVIDEOINFO structure is used with the format FORMAT_AnalogVideo.

typedef struct tagKS_AnalogVideoInfo {
    RECT            rcSource;
    RECT            rcTarget;
    DWORD           dwActiveWidth;
    DWORD           dwActiveHeight;
    REFERENCE_TIME  AvgTimePerFrame;
} KS_ANALOGVIDEOINFO, *PKS_ANALOGVIDEOINFO;

Members

rcSource
Specifies the portion of the active video signal to use. Typically this would be set to {0,0,720,480}.
rcTarget
Specifies the destination rectangle. This value and rcSource are relative to dwActiveWidth and dwActiveHeight and typically will be set to {0,0,720,480}.
dwActiveWidth
Specifies the active width of the rectangle. Typically this value should be set to 720 (ITUR-601 active samples per line).
dwActiveHeight
Specifies the active height of the rectangle. This value is usually set to 480.
AvgTimePerFrame
Specifies the average time per frame in 100 nanosecond units.

Headers

Declared in ksmedia.h. Include ksmedia.h.


KS_BITMAPINFOHEADER

The KS_BITMAPINFOHEADER structure contains all the details about the video stream, including the actual image dimensions and the pixel depth.

typedef struct tagKS_BITMAPINFOHEADER{
    DWORD    biSize;
    LONG     biWidth;
    LONG     biHeight;
    WORD     biPlanes;
    WORD     biBitCount;
    DWORD    biCompression;
    DWORD    biSizeImage;
    LONG     biXPelsPerMeter;
    LONG     biYPelsPerMeter;
    DWORD    biClrUsed;
    DWORD    biClrImportant;
} KS_BITMAPINFOHEADER, *PKS_BITMAPINFOHEADER;

Members

biSize
Specifies the size of the structure in bytes.
biWidth
Specifies the width of the bitmap in pixels.
biHeight
Specifies the height of the bitmap in pixels.
biPlanes
Specifies the number of planes. This is always set to 1.
biBitCount
Specifies the color bits per pixel (1, 4, 8, or 24).
biCompression
Specifies the compression scheme.
biSizeImage
Specifies the size of bitmap bits in bytes. (Only required if using compression.)
biXPelsPerMeter
Specifies the horizontal resolution in pixels per meter.
biYPelsPerMeter
Specifies the vertical resolution in pixels per meter.
biClrUsed
Specifies the number of colors used in the image.
biClrImportant
Specifies the number of important colors in the image.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

This is the same structure as the user-mode, GDI bitmap header (BITMAPINFOHEADER) structure. A source filter can request that the sink filter take only a section of the video by providing a clipping rectangle in the rcSource member. However, if the sink filter does not check for the clipping rectangle on connection, the sink filter will simply render all of the video, without consequence.

Ideally, a sink filter will check the rcSource and if it does not support image extraction and the rectangle is not empty, then it will reject the connection. A filter should use SetRectEmpty to reset a rectangle to all zeroes (and IsRectEmpty to later check the rectangle). The rcTarget specifies the destination rectangle for the video. Most source filters will set this member to all zeroes. A downstream filter can request that the video be placed in a particular area of the buffers it supplies. In this case, it will call QueryAccept with a nonempty target.


KS_DATAFORMAT_VBIINFOHEADER

The KS_DATAFORMAT_VBIINFOHEADER structure provides detailed information on the VBI stream.

typedef struct tagKS_DATAFORMAT_VBIINFOHEADER {
    KSDATAFORMAT            DataFormat;
    KS_VBIINFOHEADER        VBIInfoHeader;
} KS_DATAFORMAT_VBIINFOHEADER, *PKS_DATAFORMAT_VBIINFOHEADER;

Members

DataFormat
Specifies the data format.
VBIInfoHeader
Contains the structure that specifies the details of the VBI stream.

Headers

Declared in ksmedia.h. Include ksmedia.h.

See Also

KS_VBIINFOHEADER


KS_DATAFORMAT_VIDEOINFO_PALETTE

The KS_DATAFORMAT_VIDEOINFO_PALETTE structure is used to provide detailed information on the video stream, including color information.

typedef struct tagKS_DATAFORMAT_VIDEOINFO_PALETTE {
    KSDATAFORMAT            DataFormat;
    KS_VIDEOINFO            VideoInfo;
} KS_DATAFORMAT_VIDEOINFO_PALETTE, *PKS_DATAFORMAT_VIDEOINFO_PALETTE;

Members

DataFormat
Specifies the data format.
VideoInfo
Contains the structure that specifies the details of the video stream.

Headers

Declared in ksmedia.h. Include ksmedia.h.

See Also

KSDATAFORMAT, KS_VIDEOINFO


KS_DATAFORMAT_VIDEOINFOHEADER

The KS_DATAFORMAT_VIDEOINFOHEADER structure provides detailed information on the video stream.

typedef struct tagKS_DATAFORMAT_VIDEOINFOHEADER {
    KSDATAFORMAT            DataFormat;
    KS_VIDEOINFOHEADER      VideoInfoHeader;
} KS_DATAFORMAT_VIDEOINFOHEADER, *PKS_DATAFORMAT_VIDEOINFOHEADER;

Members

DataFormat
Specifies the data format.
VideoInfoHeader
Contains the structure that specifies the details of the video stream.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

This format is used for most capture output streams.

See Also

KSDATAFORMAT, KS_VIDEOINFOHEADER


KS_DATAFORMAT_VIDEOINFOHEADER2

The KS_DATAFORMAT_VIDEOINFOHEADER2 structure provides detailed information on the video stream.

typedef struct tagKS_DATAFORMAT_VIDEOINFOHEADER2 {
    KSDATAFORMAT            DataFormat;
    KS_VIDEOINFOHEADER2     VideoInfoHeader2;
} KS_DATAFORMAT_VIDEOINFOHEADER2, *PKS_DATAFORMAT_VIDEOINFOHEADER2;

Members

DataFormat
Specifies the data format.
VideoInfoHeader2
Contains the structure that specifies the details of the video stream.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

This structure should be used instead of a KS_DATAFORMAT_VIDEOINFOHEADER structure when the driver requires a KS_VIDEOINFOHEADER2 structure. The KS_VIDEOINFOHEADER2 structure should be used instead of KS_VIDEOINFOHEADER when the driver must describe interlaced content or specify bob or weave.

See Also

KSDATAFORMAT, KS_DATAFORMAT_VIDEOINFOHEADER


KS_DATARANGE_ANALOGVIDEO

The KS_DATARANGE_ANALOGVIDEO structure is used to describe the analog video stream.

typedef struct tagKS_DATARANGE_ANALOGVIDEO {
    KSDATARANGE                  DataRange;
    KS_ANALOGVIDEOINFO           AnalogVideoInfo;
} KS_DATARANGE_ANALOGVIDEO, *PKS_DATARANGE_ANALOGVIDEO;

Members

DataRange
Specifies the major identifier for the format.
AnalogVideoInfo
Contains the structure that specifies the details of the analog video stream.

Headers

Declared in ksmedia.h. Include ksmedia.h.

See Also

KSDATARANGE, KS_ANALOGVIDEOINFO


KS_DATARANGE_MPEG1_VIDEO

The KS_DATARANGE_MPEG1_VIDEO structure is used to declare the range of MPEG-1 video formats available for a stream.

typedef struct tagKS_DATARANGE_MPEG1_VIDEO {
    KSDATARANGE                  DataRange;
    BOOL                         bFixedSizeSamples;
    BOOL                         bTemporalCompression;
    DWORD                        StreamDescriptionFlags;
    DWORD                        MemoryAllocationFlags;
    KS_VIDEO_STREAM_CONFIG_CAPS  ConfigCaps;
    KS_MPEG1VIDEOINFO            VideoInfoHeader;
} KS_DATARANGE_MPEG1_VIDEO;

Members

DataRange
Specifies the major identifier for the format.
bFixedSizeSamples
Specifies that all the samples are the same size if set to TRUE.
bTemporalCompression
Specifies whether each sample can stand independently on its own, without relying on previous or future samples.
StreamDescriptionFlags
This member is unused and should be set to zero.
MemoryAllocationFlags
This member is unused and should be set to zero.
ConfigCaps
Contains the structure that specifies the configuration of the stream, including scaling, cropping, and frame and data rates.
VideoInfoHeader
Contains the structure that specifies the details of the video stream.

Headers

Declared in ksmedia.h. Include ksmedia.h.


KS_DATARANGE_MPEG2_VIDEO

The KS_DATARANGE_MPEG2_VIDEO structure is used to declare the range of MPEG-2 video formats available for a stream.

typedef struct tagKS_DATARANGE_MPEG2_VIDEO {
    KSDATARANGE                  DataRange;
    BOOL                         bFixedSizeSamples;
    BOOL                         bTemporalCompression;
    DWORD                        StreamDescriptionFlags;
    DWORD                        MemoryAllocationFlags;
    KS_VIDEO_STREAM_CONFIG_CAPS  ConfigCaps;
    KS_MPEG1VIDEOINFO2           VideoInfoHeader;
} KS_DATARANGE_MPEG2_VIDEO;

Members

DataRange
Specifies the major identifier for the format.
bFixedSizeSamples
Specifies that all the samples are the same size if set to TRUE.
bTemporalCompression
Specifies if each sample can stand independently on its own, without relying on previous or future samples.
StreamDescriptionFlags
This member is unused and should be set to zero.
MemoryAllocationFlags
This member is unused and should be set to zero.
ConfigCaps
Contains the structure that specifies the configuration of the stream, including scaling, cropping, and frame and data rates.
VideoInfoHeader
Contains the structure that specifies the details of the video stream.

Headers

Declared in ksmedia.h. Include ksmedia.h.


KS_DATARANGE_VIDEO_PALETTE

The KS_DATARANGE_VIDEO_PALETTE structure is used to describe the stream and its color capabilities.

typedef struct tagKS_DATARANGE_VIDEO_PALETTE {
    KSDATARANGE                  DataRange;
    BOOL                         bFixedSizeSamples;
    BOOL                         bTemporalCompression;
    DWORD                        StreamDescriptionFlags;
    DWORD                        MemoryAllocationFlags;
    KS_VIDEO_STREAM_CONFIG_CAPS  ConfigCaps;
    KS_VIDEOINFO                 VideoInfo;
} KS_DATARANGE_VIDEO_PALETTE, *PKS_DATARANGE_VIDEO_PALETTE;

Members

DataRange
Specifies the major identifier for the format.
bFixedSizeSamples
Specifies that all the samples are the same size if set to TRUE.
bTemporalCompression
Specifies whether each sample can stand independently on its own, without relying on previous or future samples.
StreamDescriptionFlags
This member is unused and should be set to zero.
MemoryAllocationFlags
This member is unused and should be set to zero.
ConfigCaps
Contains the structure that specifies the configuration of the stream, including scaling, cropping, and frame and data rates.
VideoInfo
Contains the structure that specifies the details of the video stream.

Headers

Declared in ksmedia.h. Include ksmedia.h.

See Also

KSDATARANGE, KS_VIDEO_STREAM_CONFIG_CAPS, KS_VIDEOINFO


KS_DATARANGE_VIDEO_VBI

The KS_DATARANGE_VIDEO_VBI structure is used to describe a stream containing VBI data.

typedef struct tagKS_DATARANGE_VIDEO_VBI {
    KSDATARANGE                  DataRange;
    BOOL                         bFixedSizeSamples;
    BOOL                         bTemporalCompression;
    DWORD                        StreamDescriptionFlags;
    DWORD                        MemoryAllocationFlags;
    KS_VIDEO_STREAM_CONFIG_CAPS  ConfigCaps;
    KS_VBIINFOHEADER             VBIInfoHeader;
} KS_DATARANGE_VIDEO_VBI, *PKS_DATARANGE_VIDEO_VBI;

Members

DataRange
Specifies the major identifier for the format.
bFixedSizeSamples
Specifies that all the samples are the same size if set to TRUE.
bTemporalCompression
Specifies whether each sample can stand independently on its own, without relying on previous or future samples.
StreamDescriptionFlags
This member is unused and should be set to zero.
MemoryAllocationFlags
This member is unused and should be set to zero.
ConfigCaps
Contains the structure that specifies the configuration of the stream, including scaling, cropping, and frame and data rates.
VBIInfoHeader
Contains the structure that specifies the details of the video stream.

Headers

Declared in ksmedia.h. Include ksmedia.h.

See Also

KSDATARANGE, KS_VIDEO_STREAM_CONFIG_CAPS, KS_VBIINFOHEADER


KS_DATARANGE_VIDEO

The KS_DATARANGE_VIDEO structure is used to describe a range of video streams.

typedef struct tagKS_DATARANGE_VIDEO {
    KSDATARANGE                  DataRange;
    BOOL                         bFixedSizeSamples;
    BOOL                         bTemporalCompression;
    DWORD                        StreamDescriptionFlags;
    DWORD                        MemoryAllocationFlags;
    KS_VIDEO_STREAM_CONFIG_CAPS  ConfigCaps;
    KS_VIDEOINFOHEADER           VideoInfoHeader;
} KS_DATARANGE_VIDEO, *PKS_DATARANGE_VIDEO;

Members

DataRange
Specifies the major identifier for the format.
bFixedSizeSamples
Specifies that all the samples are the same size if set to TRUE.
bTemporalCompression
Specifies whether each sample can stand independently on its own, without relying on previous or future samples.
StreamDescriptionFlags
This member is unused and should be set to zero.
MemoryAllocationFlags
This member is unused and should be set to zero.
ConfigCaps
Contains the structure that specifies the configuration of the stream, including scaling, cropping, and frame and data rates.
VideoInfoHeader
Contains the structure that specifies the details of the video stream.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The KS_DATARANGE_VIDEO structure is used for two related purposes:

  • At driver initialization time, an array of KS_DATARANGE_VIDEO structures is returned from the driver, exposing all the supported formats for a given pin, including the possible cropping and scaling options.
  • When a particular format is selected in user mode, this structure is used to determine whether a proposed format is supported by the driver. User-mode clients modify the contents of the VideoInfoHeader member but leave all other elements of KS_DATARANGE_VIDEO unchanged. The minidriver then verifies the requested parameters and returns a KS_DATAFORMAT_VIDEO structure. At this time, members that are unique to the particular format requested are calculated by the minidriver.

For example, a stream that supports RGB16, RGB24, YVU9, and JPEG capture formats defines an array of four of these structures.

See Also

KSDATARANGE, KS_VIDEO_STREAM_CONFIG_CAPS, KS_VIDEOINFOHEADER


KS_DATARANGE_VIDEO2

The KS_DATARANGE_VIDEO2 structure is used to describe the video stream.

typedef struct tagKS_DATARANGE_VIDEO2 {
    KSDATARANGE                  DataRange;
    BOOL                         bFixedSizeSamples;
    BOOL                         bTemporalCompression;
    DWORD                        StreamDescriptionFlags;
    DWORD                        MemoryAllocationFlags;
    KS_VIDEO_STREAM_CONFIG_CAPS  ConfigCaps;
    KS_VIDEOINFOHEADER2          VideoInfoHeader2;
} KS_DATARANGE_VIDEO2, *PKS_DATARANGE_VIDEO2;

Members

DataRange
Specifies the major identifier for the format.
bFixedSizeSamples
Specifies that all the samples are the same size if set to TRUE.
bTemporalCompression
Specifies whether each sample can stand independently on its own, without relying on previous or future samples.
StreamDescriptionFlags
This member is unused and should be set to zero.
MemoryAllocationFlags
This member is unused and should be set to zero.
ConfigCaps
Contains the structure that specifies the configuration of the stream, including scaling, cropping, and frame and data rates.
VideoInfoHeader2
Contains the structure that specifies the details of the video stream.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

This structure should be used instead of a KS_DATARANGE_VIDEO structure when the driver requires a KS_VIDEOINFOHEADER2 structure. The KS_VIDEOINFOHEADER2 structure should be used instead of KS_VIDEOINFOHEADER when the driver must describe interlaced content or specify bob or weave.

See Also

KSDATARANGE, KS_VIDEO_STREAM_CONFIG_CAPS, KS_VIDEOINFOHEADER2


KS_FRAME_INFO

The KS_FRAME_INFO structure is used to extend the KSSTREAM_HEADER structure for video streams.

typedef struct tagKS_FRAME_INFO {
    ULONG     ExtendedHeaderSize;
    DWORD     dwFrameFlags;
    LONGLONG  PictureNumber;
    LONGLONG  DropCount;
    HANDLE    hDirectDraw;
    HANDLE    hSurfaceHandle;
    RECT      DirectDrawRect;
    DWORD     Reserved1;
    DWORD     Reserved2;
    DWORD     Reserved3;
    DWORD     Reserved4;
} KS_FRAME_INFO, *PKS_FRAME_INFO;

Members

ExtendedHeaderSize
Specifies the size of this structure.
dwFrameFlags
Specifies flags indicating additional information about the frame captured. During capture, the driver sets this member using the flags discussed in the following Comments section.
PictureNumber
Specifies a count representing the current picture number. The counter is reset to zero when the stream is placed in the run state.
DropCount
Specifies the number of pictures that were not captured. During capture, the driver sets this member. This counter should be incremented whenever a frame should have been captured but was not; this condition usually arises when no buffers were available during capture.
hDirectDraw
Specifies the user-mode handle to DirectDraw. This handle is only provided to the driver when capturing to a DirectDraw surface for preview or overlay purposes.
hSurfaceHandle
Specifies the user-mode handle to the DirectDraw surface. This handle is only provided to the driver when capturing to a DirectDraw surface for preview or overlay purposes.
DirectDrawRect
Specifies the portion of the DirectDraw surface that has been locked. This is normally the entire surface.
Reserved1
This member is reserved and should not be used by a driver.
Reserved2
This member is reserved and should not be used by a driver.
Reserved3
This member is reserved and should not be used by a driver.
Reserved4
This member is reserved and should not be used by a driver.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The KS_FRAME_INFO structure provides a way to return information about the frame captured, as well as a way to pass Microsoft® DirectDraw® handles used when capturing to a DirectDraw surface.

The PictureNumber member count represents the idealized count of the current picture, which is calculated in one of two ways:

  • Measure the time since the stream was started and divide by the frame duration. This method is appropriate for devices that do not provide their own clock. For example: PictureNumber = ElapsedTime / FrameDuration
  • Add together the count of frames captured and the count of frame dropped. This method is appropriate for devices that provide their own clock. For example: PictureNumber = FramesCaptured + FramesDropped

When calculating PictureNumber and DropCount, it is important to use the frame duration specified when the stream was opened, which may not necessarily match the rate at which the device is actually producing images. For example, a USB camera may only produce images at 7.5 fps, but a client could open the stream at 8 fps. In this case, all calculations should use the 8 fps number.

The dwFrameFlags member is set by the driver using the following flags:

Flag | Description
KS_VIDEO_FLAG_FRAME | Indicates a complete frame.
KS_VIDEO_FLAG_FIELD1 | Indicates Field 1 of a two-field sequence.
KS_VIDEO_FLAG_FIELD2 | Indicates Field 2 of a two-field sequence.
KS_VIDEO_FLAG_I_FRAME | Indicates that this frame can be completely decoded without reference to any other frames.
KS_VIDEO_FLAG_P_FRAME | Indicates that this is a predicted frame.
KS_VIDEO_FLAG_B_FRAME | Indicates that this is a bidirectional frame.


KS_RGBQUAD

The KS_RGBQUAD structure is used to describe a color consisting of relative intensities of red, green, and blue.

typedef struct tagKS_RGBQUAD {
    BYTE    rgbBlue;
    BYTE    rgbGreen;
    BYTE    rgbRed;
    BYTE    rgbReserved;
} KS_RGBQUAD;

Members

rgbBlue
Specifies the intensity of blue in the color.
rgbGreen
Specifies the intensity of green in the color.
rgbRed
Specifies the intensity of red in the color.
rgbReserved
Reserved; must be zero.

Headers

Declared in ksmedia.h. Include ksmedia.h.


KS_TRUECOLORINFO

The KS_TRUECOLOR structure contains color palette and bit mask information for a video image.

typedef struct tagKS_TRUECOLORINFO {
    BYTE         dwBitMasks[KS_iMASK_COLORS];
    KS_RGBQUAD   bmiColors[KS_iPALLETE_COLORS];
} KS_TRUECOLORINFO;

Members

dwBitMasks
An array of color masks (one per each color element).
bmiColors
An array of palette colors.

Headers

Declared in ksmedia.h. Include ksmedia.h.


KS_TVTUNER_CHANGE_INFO

The KS_TVTUNER_CHANGE_INFO structure is used to provide VBI codecs with information about the currently tuned channel.

typedef struct tagKS_TVTUNER_CHANGE_INFO {
    DWORD    dwFlags;
    DWORD    dwCountryCode;
    DWORD    dwAnalogVideoStandard;
    DWORD    dwChannel;
} KS_TVTUNER_CHANGE_INFO, *PKS_TVTUNER_CHANGE_INFO;

Members

dwFlags
Specifies flags indicating the status of the tuning operation. The flag can be one of the following.
Flag | Description
KS_TVTUNER_CHANGE_BEGIN_TUNE | Indicates that a tuning operation has begun. VBI codecs should stop decoding at this time, because the video signal may become corrupted.
KS_TVTUNER_CHANGE_END_TUNE | Indicates completion of a tuning operation. VBI codecs should resume decoding.

dwCountryCode
Specifies the country/region code in use. This corresponds to the International Telecommunications Unit (ITU) long distance dialing code.
dwAnalogVideoStandard
Specifies the current analog video standard. This value should be set to one of the following KS_AnalogVideo_Xxx values:
KS_AnalogVideo_None
KS_AnalogVideo_NTSC_M
KS_AnalogVideo_NTSC_M_J
KS_AnalogVideo_NTSC_433

KS_AnalogVideo_PAL_B
KS_AnalogVideo_PAL_D
KS_AnalogVideo_PAL_G
KS_AnalogVideo_PAL_H
KS_AnalogVideo_PAL_I
KS_AnalogVideo_PAL_M
KS_AnalogVideo_PAL_N

KS_AnalogVideo_PAL_60

KS_AnalogVideo_SECAM_B
KS_AnalogVideo_SECAM_D
KS_AnalogVideo_SECAM_G
KS_AnalogVideo_SECAM_H
KS_AnalogVideo_SECAM_K
KS_AnalogVideo_SECAM_K1
KS_AnalogVideo_SECAM_L
KS_AnalogVideo_SECAM_L1
dwChannel
Specifies the current channel number.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

A packet containing a KS_TVTUNER_CHANGE_INFO structure normally originates at a TV Tuner filter, and is propagated through any crossbars to an analog video decoder capture filter. The capture filter in turn must propagate this packet to downstream VBI codecs as part of a VBI media sample.


KS_VBI_FRAME_INFO

The KS_VBI_FRAME_INFO structure is used to extend the KSSTREAM_HEADER structure for VBI streams.

typedef struct tagKS_VBI_FRAME_INFO {
    ULONG                   ExtendedHeaderSize;
    DWORD                   dwFrameFlags;
    LONGLONG                PictureNumber;
    LONGLONG                DropCount;
    DWORD                   dwSamplingFrequency;
    KS_TVTUNER_CHANGE_INFO  TvTunerChangeInfo;
    KS_VBIINFOHEADER        VBIInfoHeader;
} KS_VBI_FRAME_INFO, *PKS_VBI_FRAME_INFO;

Members

ExtendedHeaderSize
Specifies the size of this structure.
dwFrameFlags
Specifies flags indicating additional information about the frame captured. When capturing, the driver sets this member using flags described in the following Comments section.
PictureNumber
Specifies a count representing the current picture number. The counter is reset to zero when the stream is placed in the Run state.
DropCount
Specifies the number of pictures that were not captured. When capturing, the driver sets this member. This counter should be incremented whenever a frame should have been captured but was not; this condition usually arises when no buffers were available during capture.
dwSamplingFrequency
Sampling frequency in hertz (Hz).
TvTunerChangeInfo
Specifies information about the current VBI data source, including country/region code, analog video standard, and channel. This member is only valid if dwFrameFlags specifies the KS_VBI_FLAG_TVTUNER_CHANGE flag.
VBIInfoHeader
Specifies information about the current VBI data source, including start line, end line, sampling frequency, and video standard. This member is only valid if dwFrameFlags specifies the KS_VBI_FLAG_VBIINFOHEADER_CHANGE flag.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The KS_VBI_FRAME_INFO structure provides a way to return information about the frame captured, as well as providing tuning information to VBI decoders.

The PictureNumber member count represents the idealized count of the current picture based on the format used to open the stream, which is calculated in one of two ways:

  • Measure the time since the stream was started and divide by the frame duration. This method is appropriate for devices that do not provide their own clock. For example: PictureNumber = (CurrentStreamTime - StartStreamTime) / FrameDuration
  • Add together the count of frames captured and the count of frames dropped. This method is appropriate for devices that provide their own clock. For example: PictureNumber = FramesCaptured + FramesDropped

When calculating the PictureNumber and DropCount, it is important to use the frame duration specified when the stream was opened, which may not necessarily match the rate at which the device is actually producing images. For example, a USB camera may only produce images at 7.5 fps, but a client could open the stream at 8 fps. In this case, all calculations should use the 8 fps number.

The dwFrameFlags member is set by the driver using the following flags.

Flag | Description
KS_VBI_FLAG_FRAME | Indicates a complete frame.
KS_VBI_FLAG_FIELD1 | Indicates Field 1 of a two-field sequence.
KS_VBI_FLAG_FIELD2 | Indicates Field 2 of a two-field sequence.
KS_VBI_FLAG_TVTUNER_CHANGE | Indicates that the TvTunerChangeInfo member structure contains valid data.
KS_VBI_FLAG_VBIINFOHEADER_CHANGE | Indicates that the VBIInfoHeader member structure contains valid data.


KS_VBIINFOHEADER

The KS_VBIINFOHEADER structure is used for raw vertical blanking interval (VBI) streams.

typedef struct tagKS_VBIINFOHEADER {
    ULONG    StartLine;
    ULONG    EndLine;
    ULONG    SamplingFrequency;
    ULONG    MinLineStartTime;
    ULONG    MaxLineStartTime;
    ULONG    ActualLineStartTime;
    ULONG    ActualLineEndTime;
    ULONG    VideoStandard;
    ULONG    SamplesPerLine;
    ULONG    StrideInBytes;
    ULONG    BufferSize;
} KS_VBIINFOHEADER, *PKS_VBIINFOHEADER;

Members

StartLine
Specifies line number of the first digitized VBI line.
EndLine
Specifies the line number of the last digitized VBI line.
SamplingFrequency
Specifies the sampling frequency expressed in hertz (Hz).
MinLineStartTime
Specifies the shortest possible interval from the leading edge of H-sync in 10-nanosecond units (that is, in hundredths of microseconds).
MaxLineStartTime
Specifies the longest possible interval from the leading edge of H-sync in 10-nanosecond units (that is, in hundredths of microseconds).
ActualLineStartTime
Specifies the actual starting point of VBI digitization from the leading edge of H-sync in 10-nanosecond units (that is, in hundredths of microseconds).
ActualLineEndTime
Specifies the actual ending point for VBI digitization from the leading edge of H-sync in 10-nanosecond units (that is, in hundredths of microseconds).
VideoStandard
Specifies the KS_AnalogVideoStandard_Xxx value.
SamplesPerLine
Specifies the number of samples digitized per video line.
StrideInBytes
Specifies the stride in bytes between the first sample on a given line and the first sample on the next line. This value can be larger than SamplesPerLine.
BufferSize
Specifies the size in bytes of the buffer to store the entire digitized VBI signal.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

VBI streams are usually converted to NABTS, CC, and Intercast streams.


KS_VIDEOINFO

The KS_VIDEOINFO structure is used to describe the video stream.

typedef struct tagKS_VIDEOINFO {
    RECT                   rcSource;
    RECT                   rcTarget;
    DWORD                  dwBitRate;
    DWORD                  dwBitErrorRate;
    REFERENCE_TIME         AvgTimePerFrame;
    KS_BITMAPINFOHEADER    bmiHeader;
    union {
        KS_RGBQUAD         bmiColors[KS_iPALETTE_COLORS];
        DWORD              dwBitMasks[KS_iMASK_COLORS];
        KS_TRUECOLORINFO   TrueColorInfo;
          };
} KS_VIDEOINFO;

Members

rcSource
Specifies the portion of the active video signal to use.
rcTarget
Specifies the destination rectangle.
dwBitRate
Specifies the approximate data bit rate.
dwBitErrorRate
Specifies the bit error rate for the stream.
AvgTimePerFrame
Specifies the average time per frame, in 100-nanosecond units.
bmiHeader
Specifies the bitmap header information.
bmiColors[KS_iPALETTE_COLORS]
Specifies the color palette.
dwBitMasks[KS_iMASK_COLORS]
Array of color masks (one per color).
TrueColorInfo
A KS_TRUECOLORINFO structure that specifies color palette information.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

This structure should not be used unless the biSize member of the KS_BITMAPINFOHEADER member is set to sizeof(KS_BITMAPINFOHEADER).

See Also

KS_BITMAPINFOHEADER, KS_RGBQUAD, KS_TRUECOLORINFO


KS_VIDEOINFOHEADER

The KS_VIDEOINFOHEADER structure is used to specify details of the video stream.

typedef struct tagKS_VIDEOINFOHEADER {
    RECT                 rcSource;
    RECT                 rcTarget;
    DWORD                dwBitRate;
    DWORD                dwBitErrorRate;
    REFERENCE_TIME       AvgTimePerFrame;
    KS_BITMAPINFOHEADER  bmiHeader;
} KS_VIDEOINFOHEADER, *PKS_VIDEOINFOHEADER;

Members

rcSource
Specifies a RECT structure that defines the source video window. This RECT structure can be a clipping rectangle to select a portion of the source video stream.
rcTarget
Specifies a RECT structure that defines the destination video window.
dwBitRate
A DWORD value that indicates the video stream's approximate data rate, in bits per second.
dwBitErrorRate
A DWORD value that indicates the video stream's data error rate, in bit errors per second.
AvgTimePerFrame
A REFERENCE TIME value that indicates the video frame's average display time, in 100-nanosecond units.
bmiHeader
Specifies a KS_BITMAPINFOHEADER structure that contains color and dimension information for the video image bitmap.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The KS_VIDEOINFOHEADER structure is identical to the DirectShow VIDEOINFOHEADER structure.

See Also

KS_BITMAPINFOHEADER


KS_VIDEOINFOHEADER2

The KS_VIDEOINFOHEADER2 structure is used to specify details of the video stream.

typedef struct tagVIDEOINFOHEADER2 {
    RECT                rcSource;
    RECT                rcTarget;
    DWORD               dwBitRate;
    DWORD               dwBitErrorRate;
    REFERENCE_TIME      AvgTimePerFrame;
    DWORD               dwInterlaceFlags;
    DWORD               dwCopyProtectFlags;
    DWORD               dwPictAspectRatioX;
    DWORD               dwPictAspectRatioY;
    DWORD               dwReserved1;
    DWORD               dwReserved2;
    KS_BITMAPINFOHEADER bmiHeader;
} KS_VIDEOINFOHEADER2;

Members

rcSource
Specifies a RECT structure that indicates what part of the source stream should be used to fill the destination buffer. The renderers can use this member to request that the decoders stretch or clip the stream.
rcTarget
Specifies a RECT structure that indicates what part of the destination buffer should be used.
dwBitRate
A DWORD value that indicates the video stream's appropriate data rate.
dwBitErrorRate
A DWORD value that indicates the video stream's data error rate.
AvgTimePerFrame
A REFERENCE TIME value that indicates the video frame's average display time, in 100-nanosecond units.
dwInterlaceFlags
Specifies interlace information. This member can be set to one or more of the KS_INTERLACE_Xxx flags described in the following Comments section.
dwCopyProtectFlags
Specifies a KSCOPYPROTECT RestrictDuplication value to indicate if duplication of a stream should be restricted. If undefined, specify zero or the connection will be rejected.
dwPictAspectRatioX
Specifies the x dimension of the picture-aspect ratio (for example, 16 for a 16x9 display). The value is expressed in inches by inches, not pixels by pixels.
dwPictAspectRatioY
Specifies the y dimension of the picture aspect ratio (for example, 9 for 16x9 display). The value is expressed in inches by inches, not pixels by pixels.
dwReserved1
Reserved for system use. Must be set to zero or the connection is rejected.
dwReserved2
Reserved for system use. Must be set to zero or the connection is rejected.
bmiHeader
A KS_BITMAPINFOHEADER structure that contains color and dimension information for the video image bitmap.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The KS_VIDEOINFOHEADER2 structure is identical to the DirectShow VIDEOINFOHEADER2 structure, which is documented in the Platform SDK.

Capture drivers that produce video fields (instead of frames) must use the KS_DATARANGE_VIDEO2 structure, which contains a KS_VIDEOINFOHEADER2 structure.

Values for the dwInterlaceFlags member are listed in the following table. (Set undefined flags to zero or the connection is rejected.)

Value | Description
KS_INTERLACE_IsInterlaced | Indicates an interlace stream. If zero, other interlace bits are irrelevant.
KS_INTERLACE_1FieldPerSample | Indicates one field per media sample. If zero, indicates two fields per media sample.
KS_INTERLACE_Field1First | Indicates that Field 1 is first. If zero, indicates that Field 2 is first. Top field in PAL is field 1, top field in NTSC is field 2.
KS_INTERLACE_UNUSED | Unused.
KS_INTERLACE_FieldPatternMask | Bits used to indicate field pattern.
KS_INTERLACE_FieldPatField1Only | Stream never contains a Field 2.
KS_INTERLACE_FieldPatField2Only | Stream never contains a Field 1.
KS_INTERLACE_FieldPatBothRegular | There will be a Field 2 for every Field 1.
KS_INTERLACE_FieldPatBothIrregular | Random pattern of Field 1s and Field 2s.
KS_INTERLACE_DisplayModeMask | Bits used to indicate display mode.
KS_INTERLACE_DisplayModeBobOnly | Indicates Bob display mode only.
KS_INTERLACE_DisplayModeWeaveOnly | Indicates Weave display mode only.
KS_INTERLACE_DisplayModeBobOrWeave | Indicates either Bob or Weave display mode


KS_VIDEO_STREAM_CONFIG_CAPS

The KS_VIDEO_STREAM_CONFIG_CAPS structure is identical to the DirectShow VIDEO_STREAM_CONFIG_CAPS structure, and includes the following information: analog video standard, scaling capabilities, cropping capabilities, minimum and maximum frame rates, and minimum and maximum data rates.

typedef struct  _KS_VIDEO_STREAM_CONFIG_CAPS  {
    GUID        guid;
    ULONG       VideoStandard;
    SIZE        InputSize;
    SIZE        MinCroppingSize;
    SIZE        MaxCroppingSize;
    int         CropGranularityX;
    int         CropGranularityY;
    int         CropAlignX;
    int         CropAlignY;
    SIZE        MinOutputSize;
    SIZE        MaxOutputSize;
    int         OutputGranularityX;
    int         OutputGranularityY;
    int         StretchTapsX;
    int         StretchTapsY;
    int         ShrinkTapsX;
    int         ShrinkTapsY;
    LONGLONG    MinFrameInterval;
    LONGLONG    MaxFrameInterval;
    LONG        MinBitsPerSecond;
    LONG        MaxBitsPerSecond;
} KS_VIDEO_STREAM_CONFIG_CAPS;

Members

guid
Specifies the KSDATAFORMAT_SPECIFIER_VIDEOINFO value. This GUID is identical to the DirectShow MEDIATYPE_Video value.
VideoStandard
Specifies the analog video standards supported by the stream. It should be set to one or more of the following KS_AnalogVideo_Xxx values ORed together:
KS_AnalogVideo_None
KS_AnalogVideo_NTSC_M
KS_AnalogVideo_NTSC_M_J
KS_AnalogVideo_NTSC_433

KS_AnalogVideo_PAL_B
KS_AnalogVideo_PAL_D
KS_AnalogVideo_PAL_G
KS_AnalogVideo_PAL_H
KS_AnalogVideo_PAL_I
KS_AnalogVideo_PAL_M
KS_AnalogVideo_PAL_N

KS_AnalogVideo_PAL_60

KS_AnalogVideo_SECAM_B
KS_AnalogVideo_SECAM_D
KS_AnalogVideo_SECAM_G
KS_AnalogVideo_SECAM_H
KS_AnalogVideo_SECAM_K
KS_AnalogVideo_SECAM_K1
KS_AnalogVideo_SECAM_L
KS_AnalogVideo_SECAM_L1

Digital cameras should set this member to KS_AnalogVideo_None.

InputSize
Specifies the size of the incoming signal. InputSize indicates the image rectangle's width and height in pixels. This is the largest signal the filter can digitize with each pixel remaining unique.
MinCroppingSize
Specifies the smallest cropping rectangle allowed, as specified in the rcSource member of the KS_VIDEOINFOHEADER structure associated with the DataRange.
MaxCroppingSize
Specifies the largest cropping rectangle allowed, as specified in the rcSource member of the KS_VIDEOINFOHEADER structure associated with the DataRange.
CropGranularityX
Specifies the horizontal granularity of the cropping size. For example, valid widths could be specified as even multiples of four.
CropGranularityY
Specifies the vertical granularity of cropping size. For example, valid heights could be specified as even multiples of four.
CropAlignX
Specifies the horizontal alignment of the cropping rectangle inside InputSize. For example, the driver could specify that valid rectangles must start on a boundary that is a multiple of four.
CropAlignY
Specifies the vertical alignment of the cropping rectangle inside InputSize. For example, the driver could specify that valid rectangles must start on a boundary that is a multiple of four.
MinOutputSize
Specifies the smallest bitmap this pin can produce.
MaxOutputSize
Specifies the largest bitmap this pin can produce.
OutputGranularityX
Specifies the granularity of the output bitmap width.
OutputGranularityY
Specifies the granularity of the output bitmap height.
StretchTapsX
Specifies a value indicating how well the filter can stretch the image's width. A value of zero means the filter cannot stretch. A value of 1 indicates the filter uses pixel doubling, a value 2 indicates the filter uses interpolation (2 taps), and a value of 3 or higher indicates the filter implements a higher-order (smoother) form of interpolation.
StretchTapsY
Specifies a value indicating how well the filter can stretch the image's height. A value of zero means the filter cannot stretch. A value of 1 indicates the filter uses pixel doubling, a value of 2 indicates the filter uses interpolation (2 taps), and a value of 3 or higher indicates the filter implements a better form of interpolation.
ShrinkTapsX
Specifies a value indicating how well the filter can shrink the image's width. A value of zero indicates that the filter cannot shrink. A value of 1 indicates the filter eliminates some rows of pixels to achieve shrinking, a value of 2 indicates the filter uses interpolation (2 taps), and a value of 3 or higher indicates the filter implements a better form of interpolation.
ShrinkTapsY
Specifies a value indicating how well the filter can shrink the image's height. A value of zero indicates the filter cannot shrink. A value of 1 indicates that the filter eliminates some rows of pixels to achieve shrinking, a value of 2 indicates that the filter uses interpolation (2 taps), and a value of 3 or higher indicates that the filter implements a better form of interpolation.
MinFrameInterval
Specifies the minimum frame rate allowed. This value applies to capture filters only.
MaxFrameInterval
Specifies the maximum frame rate allowed. This value applies to capture filters only.
MinBitsPerSecond
Specifies the minimum data rate this pin can produce.
MaxBitsPerSecond
Specifies the maximum data rate this pin can produce.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

It is important to understand the relationships between the members of this structure. For example, assume the following values for some of the structure members:

MinCroppingSize = (160, 120)

MaxCroppingSize = (320, 240)

CropGranularityX = 4

CropGranularityY = 8

These values indicate that valid cropping sizes begin at MinCroppingSize and increase in steps in the x-direction by CropGranularityX and in the y-direction by CropGranularityY. In this case the x-value can be anywhere from 160 to 320 pixels in steps of 4 and the y-value can be anywhere from 120 to 240 pixels in steps of 8.

In this scenario a few of the valid sizes are:

  • 160 x 120, 164 x 120, 168 x 120, 172 x 120, and so on.
  • 160 x 128, 164 x 128, 168 x 128, 172 x 128, and so on.
  • 160 x 136, 164 x 136, 168 x 136, 172 x 136, and so on.

CropAlignX and CropAlignY indicate where the cropping rectangle can be inside the input size rectangle. Given a 160 x 120 cropping rectangle and the following:

CropAlignX = 2

CropAlignY = 4

some of the valid values for the rcSource member of the KS_VIDEOINFOHEADER structure would be:

  • (0, 0, 160, 120)
  • (2, 0, 162, 120)
  • (2, 4, 162, 124)
  • (2, 8, 162, 128)

For a 320 x 240 cropping rectangle and the same cropping alignment values, (2, 4, 322, 244) is one example of the many valid rectangles.

The structure members discussed in this section work together to specify which values of rcSource are valid for the KS_VIDEOINFOHEADER structure that describes the output pin's media type. Of the remaining structure members, MinOutputSize, MaxOutputSize, OutputGranularityX, and OutputGranularityY describe the biWidth and biHeight members of the KS_BITMAPINFOHEADER structure contained in the pin's media type KS_VIDEOINFOHEADER structure.


KS_MPEG1VIDEOINFO

The KS_MPEG1VIDEOINFO structure describes an MPEG-1 video stream.

typedef struct tagKS_MPEG1VIDEOINFO {
    KS_VIDEOINFOHEADER  hdr;
    DWORD              dwStartTime;
    DWORD              cbSequenceHeader;
    BYTE               bSequenceHeader[1];
} KS_MPEG1VIDEOINFO;

Members

hdr
A KS_VIDEOINFOHEADER structure that is used to specify details of the video stream.
dwStartTime
A 25-bit "group-of-pictures" time code at the start of data.
cbSequenceHeader
Length in bytes of bSequenceHeader.bSequenceHeader

Sequence header including quantization matrices, if any.

Headers

Declared in ksmedia.h. Include ksmedia.h.


KS_MPEGVIDEOINFO2

The KS_MPEGVIDEOINFO2 structure describes an MPEG-2 video stream.

typedef struct  tagKS_MPEGVIDEOINFO2 {
    KS_VIDEOINFOHEADER2  hdr;
    DWORD                dwStartTimeCode;
    DWORD                cbSequenceHeader;
    DWORD                dwProfile;
    DWORD                dwLevel;
    DWORD                dwFlags;
    DWORD                bSequenceHeader[1];
} KS_MPEGVIDEOINFO2;

Members

hdr
A KS_VIDEOINFOHEADER2 structure that specifies details of the video stream.
dwStartTimeCode
A 25-bit "group-of-pictures" time code at the start of data (not used for DVD).
cbSequenceHeader
Length in bytes of bSequenceHeader (zero for DVD).
dwProfile
KS_MPEG2Profile enumerated type member.
dwLevel
KS_MPEG2Level enumerated type member.
dwFlags
Flags indicating preferences.
bSequenceHeader
Sequence header including quantization matrices, if any.

Headers

Declared in ksmedia.h. Include ksmedia.h.


KSPROPERTY_CAMERACONTROL_S

The KSPROPERTY_CAMERACONTROL_S structure is used to set or get properties in the PROPSETID_VIDCAP_CAMERACONTROL property set.

typedef struct {
    KSPROPERTY Property;
    LONG       Value;
    ULONG      Flags;
    ULONG      Capabilities;
} KSPROPERTY_CAMERACONTROL_S, *PKSPROPERTY_CAMERACONTROL_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
Value
Specifies the value of the property. This member is read/write.
Flags
For Get requests, Flags indicates the current KSPROPERTY_CAMERACONTROL_FLAGS_Xxx setting for the specified property. For Set requests, Flags indicates the desired KSPROPERTY_CAMERACONTROL_FLAGS_Xxx setting for the specified property.

Flags can be set to one of the following:
Value | Meaning
KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL | Indicates that the setting is controlled manually.
KSPROPERTY_CAMERACONTROL_FLAGS_AUTO | Indicates that the setting is controlled automatically.
KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE | Indicates that the setting is in absolute values.
KSPROPERTY_CAMERACONTROL_FLAGS_RELATIVE | Indicates that the setting is in relative values.

Capabilities
Indicates the driver's camera control capabilities for the specified property. This member is read-only. It will be one of the KSPROPERTY_CAMERACONTROL_FLAGS_Xxx values described in the description of the Flags member.

Headers

Declared in ksmedia.h. Include ksmedia.h.

See Also

KSPROPERTY, PROPSETID_VIDCAP_CAMERACONTROL


KSPROPERTY_CROSSBAR_CAPS_S

The KSPROPERTY_CROSSBAR_CAPS_S structure is used to get the crossbar capabilities for the device.

typedef struct {
    KSPROPERTY Property;
    ULONG      NumberOfInputs;
    ULONG      NumberOfOutputs;
} KSPROPERTY_CROSSBAR_CAPS_S, *PKSPROPERTY_CROSSBAR_CAPS_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
NumberOfInputs
Indicates the number of audio and video input pins on the crossbar.
NumberOfOutputs
Indicates the number of audio and video output pins on the crossbar.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The KSPROPERTY_CROSSBAR_CAPS property is read-only.

See Also

KSPROPERTY, PROPSETID_VIDCAP_CROSSBAR, KSPROPERTY_CROSSBAR_CAPS


KSPROPERTY_CROSSBAR_PININFO_S

The KSPROPERTY_CROSSBAR_PININFO_S structure is used to get the crossbar pin info for the device.

typedef struct {
    KSPROPERTY     Property;
    KSPIN_DATAFLOW Direction;
    ULONG          Index;
    ULONG          PinType;
    ULONG          RelatedPinIndex;
    KSPIN_MEDIUM  Medium;
} KSPROPERTY_CROSSBAR_PININFO_S, *PKSPROPERTY_CROSSBAR_PININFO_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
Direction
The driver-provided direction of data flow for the pin specified at Index. This value can be either KSPIN_DATAFLOW_IN or KSPIN_DATAFLOW_OUT.
Index
Zero-based index of the pin for which crossbar information is being queried. Input pins are queried separately from output pins.
PinType
The driver-provided type of physical connector. PinType should be set to one of the following KS_PhysicalConnectorType enum values found in ksmedia.h:
KS_PhysConn_Video_Tuner
KS_PhysConn_Video_Composite
KS_PhysConn_Video_Svideo
KS_PhysConn_Video_RGB
KS_PhysConn_Video_YRYBY
KS_PhysConn_Video_SerialDigital
KS_PhysConn_Video_ParallelDigital
KS_PhysConn_Video_SCSI
KS_PhysConn_Video_AUX
KS_PhysConn_Video_Video_1394
KS_PhysConn_Video_USB
KS_PhysConn_Video_VideoDecoder
KS_PhysConn_Video_VideoEncoder
KS_PhysConn_Video_SCART

KS_PhysConn_Audio_Tuner
KS_PhysConn_Audio_Line
KS_PhysConn_Audio_Misc
KS_PhysConn_Audio_AESDigital
KS_PhysConn_Audio_SPDIFDigital
KS_PhysConn_Audio_SCSI
KS_PhysConn_Audio_AUX
KS_PhysConn_Audio_1394
KS_PhysConn_Audio_USB
KS_PhysConn_Audio_AudioDecoder
RelatedPinIndex
Optionally, the driver can return the pin index of a pin that is related to the pin specified in Index. For example, the driver can set the RelatedPinIndex to the pin index of the audio stream that goes with a video stream at Index. RelatedPinIndex applies only to pins of the same direction (input or output) as the pin being queried. If no other pins are related to the current pin, the driver should return (-1).
Medium
The KSPIN_MEDIUM structure that represents the hardware connection for the pin. This information is returned by the driver.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The KSPROPERTY_CROSSBAR_PININFO property is read only.

All index values are zero-based, and input pins are counted separately from output pins.

See Also

KSPROPERTY, PROPSETID_VIDCAP_CROSSBAR, KSPROPERTY_CROSSBAR_PININFO


KSPROPERTY_CROSSBAR_ROUTE_S

The KSPROPERTY_CROSSBAR_ROUTE_S structure is used to query whether a particular routing is possible, and to set the current routing for a pin.

typedef struct {
    KSPROPERTY Property;
    ULONG      IndexInputPin;
    ULONG      IndexOutputPin;
    ULONG      CanRoute;
} KSPROPERTY_CROSSBAR_ROUTE_S, *PKSPROPERTY_CROSSBAR_ROUTE_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
IndexInputPin
The zero-based index of the input pin for which the query is being made.
IndexOutputPin
The zero-based index of the output pin for which the query is being made.
CanRoute
Returns whether or not the driver supports routing between the pins specified by IndexInputPin and IndexOutputPin. A nonzero value indicates that routing is supported. If the driver does not support routing between the two pins, this value will be zero.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The KSPROPERTY_CROSSBAR_ROUTE property is read and write. If the value of IndexInputPin is (-1) on an audio output pin, then the audio stream should be muted.

See Also

KSPROPERTY, PROPSETID_VIDCAP_CROSSBAR, KSPROPERTY_CROSSBAR_ROUTE


KSPROPERTY_DROPPEDFRAMES_CURRENT_S

The KSPROPERTY_DROPPEDFRAMES_CURRENT_S structure is used to get dropped frame information from the driver.

typedef struct {
    KSPROPERTY Property;
    LONGLONG   PictureNumber;
    LONGLONG   DropCount;
    ULONG      AverageFrameSize;
} KSPROPERTY_DROPPEDFRAMES_CURRENT_S, *PKSPROPERTY_DROPPEDFRAMES_CURRENT_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
PictureNumber
The current picture number provided by the driver. This value is the sum of the number of frames captured plus the number of frames dropped. This counter should reset to zero when the stream state transitions from Stop to Run.
DropCount
The count of frames dropped provided by the driver. This counter increments whenever the driver was scheduled to capture a frame, but could not, perhaps due to buffer starvation. This counter should reset to zero when the stream state transitions from Stop to Run.
AverageFrameSize
The average size of frames captured. This value is provided by the driver.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The KSPROPERTY_DROPPEDFRAMES_CURRENT property is read only.

See Also

KSPROPERTY, PROPSETID_VIDCAP_DROPPEDFRAMES, KSPROPERTY_DROPPEDFRAMES_CURRENT


KSPROPERTY_TUNER_CAPS_S

Drivers for devices that support TV and radio tuning use the KSPROPERTY_TUNER_CAPS_S structure, which identifies the hardware capabilities of the tuner, in handling KSPROPERTY_TUNER_CAPS property requests.

typedef struct {
    KSPROPERTY   Property;
    ULONG        ModesSupported;
    KSPIN_MEDIUM VideoMedium
    KSPIN_MEDIUM TVAudioMedium;
    KSPIN_MEDIUM RadioAudioMedium;
} KSPROPERTY_TUNER_CAPS_S, *PKSPROPERTY_TUNER_CAPS_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
ModesSupported
A bitwise OR of the supported tuner modes. A driver can set ModesSupported to one or more of the following:
Value | Meaning
KSPROPERTY_TUNER_MODE_TV | Indicates that the tuner is capable of tuning analog broadcast or cable television channels.
KSPROPERTY_TUNER_MODE_FM_RADIO | Indicates that the tuner is capable of tuning FM radio channels.
KSPROPERTY_TUNER_MODE_AM_RADIO | Indicates that the tuner is capable of tuning AM radio channels.
KSPROPERTY_TUNER_MODE_DSS | Indicates that the tuner is capable of tuning DSS channels.
KSPROPERTY_TUNER_MODE_ATSC | Indicates that the tuner is capable of tuning digital television channels. This setting can be used for ATSC, DVB-C, or DVB-T television reception.

VideoMedium
Specifies a unique GUID representing the hardware connection of the analog video signal. This value is used to enforce connections between filters. Possible values are NULL, indicating no pin is created; GUID_NULL, indicating Medium is not used to enforce connections; or a GUID. If a GUID value is used, only crossbar pins with a matching Medium GUID are allowed to connect.
TVAudioMedium
Specifies a unique GUID representing the hardware connection of the TV audio signal. This value is used to enforce connections between filters. Possible values are NULL, indicating no pin is created; GUID_NULL, indicating Medium is not used to enforce connections; or a GUID. If a GUID value is used, only crossbar pins with a matching Medium GUID are allowed to connect.
RadioAudioMedium
Specifies a unique GUID representing the hardware connection of the analog radio audio signal. This value is used to enforce connections between filters. Possible values are NULL, indicating no pin is created; GUID_NULL, indicating Medium is not used to enforce connections; or a GUID. If a GUID value is used, only crossbar pins with a matching Medium GUID are allowed to connect.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The KSPROPERTY_TUNER_CAPS property is read-only.

See Also

KSPROPERTY, PROPSETID_TUNER, KSPROPERTY_TUNER_CAPS, KSPROPERTY_TUNER_IF_MEDIUM


KSPROPERTY_TUNER_IF_MEDIUM_S

The KSPROPERTY_TUNER_IF_MEDIUM_S structure is used to return the Medium GUID for the pin that is capable of supporting tuning to an intermediate frequency.

typedef struct {
    KSPROPERTY     Property;
    KSPIN_MEDIUM   IFMedium;
} KSPROPERTY_TUNER_IF_MEDIUM_S, *PKSPROPERTY_TUNER_IF_MEDIUM_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
IFMedium
The GUID for the pin that is capable of supporting an intermediate frequency. If no pin supports an intermediate frequency, the driver should return GUID_NULL.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The KSPROPERTY_TUNER_IF_MEDIUM property is read-only. Support for the KSPROPERTY_TUNER_IF_MEDIUM property causes Kstvtune.ax to create an additional pin representing an MPEG-2 transport stream. A data packet sent on this pin in user mode consists only of a KS_TVTUNER_CHANGE_INFO structure.

See Also

KSPROPERTY, PROPSETID_TUNER, KSPROPERTY_TUNER_IF_MEDIUM


KSPROPERTY_TUNER_MODE_CAPS_S

Drivers for devices that support video and audio tuning use the KSPROPERTY_TUNER_MODE_CAPS_S structure in handling KSPROPERTY_TUNER_MODE_CAPS property requests.

typedef struct {
    KSPROPERTY Property;
    ULONG      Mode
    ULONG      StandardsSupported;
    ULONG      MinFrequency;
    ULONG      MaxFrequency;
    ULONG      TuningGranularity
    ULONG      NumberOfInputs;
    ULONG      SettlingTime
    ULONG      Strategy;
} KSPROPERTY_TUNER_MODE_CAPS_S, *PKSPROPERTY_TUNER_MODE_CAPS_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
Mode
The tuner mode that the caller is requesting capability information about. It can be one of the following tuner modes:
Value | Meaning
KSPROPERTY_TUNER_MODE_TV | Indicates that the tuner is capable of tuning broadcast or cable television channels.
KSPROPERTY_TUNER_MODE_FM_RADIO | Indicates that the tuner is capable of tuning FM radio channels.
KSPROPERTY_TUNER_MODE_AM_RADIO | Indicates that the tuner is capable of tuning AM radio channels.
KSPROPERTY_TUNER_MODE_DSS | Indicates that the tuner is capable of tuning DSS channels.
KSPROPERTY_TUNER_MODE_ATSC | Indicates that the tuner is capable of tuning Advanced Television Systems Committee broadcasts (Digital TV for the United States) or other digital television standard.

StandardsSupported
Describes the analog video standards supported. The driver should return one or more of the following KS_AnalogVideo_Xxx values found in ksmedia.h if Mode is set to KSPROPERTY_TUNER_MODE_TV.
KS_AnalogVideo_None
KS_AnalogVideo_NTSC_M
KS_AnalogVideo_NTSC_M_J
KS_AnalogVideo_NTSC_433

KS_AnalogVideo_PAL_B
KS_AnalogVideo_PAL_D
KS_AnalogVideo_PAL_G
KS_AnalogVideo_PAL_H
KS_AnalogVideo_PAL_I
KS_AnalogVideo_PAL_M
KS_AnalogVideo_PAL_N

KS_AnalogVideo_PAL_60

KS_AnalogVideo_SECAM_B
KS_AnalogVideo_SECAM_D
KS_AnalogVideo_SECAM_G
KS_AnalogVideo_SECAM_H
KS_AnalogVideo_SECAM_K
KS_AnalogVideo_SECAM_K1
KS_AnalogVideo_SECAM_L
KS_AnalogVideo_SECAM_L1
MinFrequency
The lowest frequency supported by the tuner. This value is in hertz (Hz).
MaxFrequency
The highest frequency supported by the tuner. This value is in hertz (Hz).
TuningGranularity
The smallest possible step size between two settings of the tuning frequency. This value is in hertz (Hz).
NumberOfInputs
The number of inputs on the tuner.
SettlingTime
The time, in milliseconds, for a new frequency setting to become stable.
Strategy
Specifies the tuning method. Strategy can be set to one of the following KS_TUNER_STRATEGY_Xxx values:
Value | Meaning
KS_TUNER_STRATEGY_PLL | Indicates that the tuning accuracy for the device is measured by a phase locked loop (PLL) offset.
KS_TUNER_STRATEGY_SIGNAL_STRENGTH | Indicates that the tuning accuracy for the device is measured by a signal strength.
KS_TUNER_STRATEGY_DRIVER_TUNES | Indicates that the driver wants total control over the fine tuning process. No fine tuning will be done by Kstvtune.ax.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The driver fills in the mode capabilities for the requested tuner mode.

The KSPROPERTY_TUNER_MODE_CAPS property is ready-only.

See Also

KSPROPERTY, PROPSETID_TUNER, KSPROPERTY_TUNER_MODE_CAPS


KSPROPERTY_TUNER_MODE_S

Drivers for devices that support video and audio tuning use the KSPROPERTY_TUNER_MODE_S structure in handling KSPROPERTY_TUNER_MODE property requests.

typedef struct {
    KSPROPERTY Property;
    ULONG      Mode;
} KSPROPERTY_TUNER_MODE_S, *PKSPROPERTY_TUNER_MODE_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
Mode
If the request is a Get request, the driver should return the current tuner mode. If the request is a Set request, the driver should switch the current tuner mode to the specified value. Mode can be one of the following tuner modes:
Value | Meaning
KSPROPERTY_TUNER_MODE_TV | Indicates that the tuner is currently tuning (get) or should switch to tuning broadcast or cable television channels (set).
KSPROPERTY_TUNER_MODE_FM_RADIO | Indicates that the tuner is currently tuning (get) or should switch to tuning (set) FM radio channels.
KSPROPERTY_TUNER_MODE_AM_RADIO | Indicates that the tuner is currently tuning (get) or should switch to tuning (set) AM radio channels.
KSPROPERTY_TUNER_MODE_DSS | Indicates that the tuner is currently tuning (get) or should switch to tuning (set) tuning DSS channels.
KSPROPERTY_TUNER_MODE_ATSC | Indicates that the tuner is capable of tuning (get) or should switch to tuning (set) Advanced Television Systems Committee broadcasts (Digital TV for the United States). This setting can also be used by DVB-T and DVB-C systems.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The KSPROPERTY_TUNER_MODE is a read/write property.

See Also

KSPROPERTY, PROPSETID_TUNER, KSPROPERTY_TUNER_MODE


KSPROPERTY_TUNER_FREQUENCY_S

Drivers for devices that support video and radio tuning use the KSPROPERTY_TUNER_FREQUENCY_S structure, which conveys frequency tuning information, in handling KSPROPERTY_TUNER_FREQUENCY property requests.

typedef struct {
    KSPROPERTY Property;
    ULONG      Frequency;
    ULONG      LastFrequency;
    ULONG      TuningFlags;
    ULONG      VideoSubChannel;
    ULONG      AudioSubChannel;
    ULONG      Channel;
    ULONG      Country;
} KSPROPERTY_TUNER_FREQUENCY_S, *PKSPROPERTY_TUNER_FREQUENCY_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
Frequency
If the request is a Get request, the driver returns the current frequency of the tuner. If the request is a Set request, the driver should set the frequency of the tuner to the specified value. This value is specified in hertz (Hz).
LastFrequency
This value is set to the last frequency tuned.
TuningFlags
If the request is a Get request, the driver returns the current tuning flags. If the request is a Set request, the driver should use the specified tuning method. TuningFlags can be set to one of the following values:
Value | Meaning
KS_TUNER_TUNING_EXACT | Specifies that the tuner should tune directly to the specified Frequency, bypassing any fine tuning logic.
KS_TUNER_TUNING_FINE | Specifies that the tuning operation should perform a comprehensive search for the best tuning. This flag is only used if the strategy is KS_TUNER_STRATEGY_DRIVER_TUNES.
KS_TUNER_TUNING_COARSE | Specifies that the tuning operation should perform a fast search, attempting only to determine if a valid signal is present. This flag is only used if the strategy is KS_TUNER_STRATEGY_DRIVER_TUNES.

VideoSubChannel
If the request is a Get request, the driver should return the video subchannel for the digital television source. If the request is a Set request, the driver should set the video subchannel for the digital television source. VideoSubChannel is only used by devices that support the DSS tuner mode (KSPROPERTY_TUNER_MODE_DSS).
AudioSubChannel
If the request is a Get request, the driver should return the audio subchannel for the digital television source. If the request is a Set request, the driver should set the audio subchannel for the digital television source. AudioSubChannel is only used by devices that support the DSS tuner mode (KSPROPERTY_TUNER_MODE_DSS).
Channel
If the request is a Get request, the driver should return the television channel for the video source. If the request is a Set request, the driver should set the video source to the specified television channel.
Country
Specifies the current country/region code for the tuning operation. Country/region codes follow the Telephony API (TAPI) country/region code values that correspond to the international long distance dialing codes.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The KSPROPERTY_TUNER_FREQUENCY is a read/write property.

See Also

KSPROPERTY, PROPSETID_TUNER, KSPROPERTY_TUNER_FREQUENCY


KSPROPERTY_TUNER_STANDARD_S

Drivers for devices that support video tuning use the KSPROPERTY_TUNER_STANDARD_S structure, which conveys tuning standard information, in handling KSPROPERTY_TUNER_STANDARD property requests.

typedef struct {
    KSPROPERTY Property;
    ULONG      Standard;
} KSPROPERTY_TUNER_STANDARD_S, *PKSPROPERTY_TUNER_STANDARD_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
Standard
Describes an analog video standard. Standard should be set to one of the following KS_AnalogVideo_Xxx values found in ksmedia.h:
KS_AnalogVideo_None
KS_AnalogVideo_NTSC_M
KS_AnalogVideo_NTSC_M_J
KS_AnalogVideo_NTSC_433

KS_AnalogVideo_PAL_B
KS_AnalogVideo_PAL_D
KS_AnalogVideo_PAL_G
KS_AnalogVideo_PAL_H
KS_AnalogVideo_PAL_I
KS_AnalogVideo_PAL_M
KS_AnalogVideo_PAL_N

KS_AnalogVideo_PAL_60

KS_AnalogVideo_SECAM_B
KS_AnalogVideo_SECAM_D
KS_AnalogVideo_SECAM_G
KS_AnalogVideo_SECAM_H
KS_AnalogVideo_SECAM_K
KS_AnalogVideo_SECAM_K1
KS_AnalogVideo_SECAM_L
KS_AnalogVideo_SECAM_L1

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

KSPROPERTY_TUNER_STANDARD is a read-only property.

See Also

KSPROPERTY, PROPSETID_TUNER, KSPROPERTY_TUNER_STANDARD


KSPROPERTY_TUNER_INPUT_S

Drivers for devices that support multiple inputs for TV and radio tuning use the KSPROPERTY_TUNER_INPUT_S structure, which conveys the connection index to be used for the tuner input, in handling KSPROPERTY_TUNER_INPUT property requests.

typedef struct {
    KSPROPERTY Property;
    ULONG      InputIndex;
} KSPROPERTY_TUNER_INPUT_S, *PKSPROPERTY_TUNER_INPUT_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
InputIndex
Specifies the connection index to be used as the tuner input. This value should be in the range of 0 through (number of inputs-1).

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

KSPROPERTY_TUNER_INPUT is a read-only property.

See Also

KSPROPERTY, PROPSETID_TUNER, KSPROPERTY_TUNER_INPUT


KSPROPERTY_TUNER_STATUS_S

Drivers for devices that support TV and radio tuning use the KSPROPERTY_TUNER_STATUS_S structure, which retrieves information about the tuning process, including the tuning frequency, in handling KSPROPERTY_TUNER_STATUS property requests.

typedef struct {
    KSPROPERTY Property;
    ULONG      CurrentFrequency;
    ULONG      PLLOffset;
    ULONG      SignalStrength;
    ULONG      Busy;
} KSPROPERTY_TUNER_STATUS_S, *PKSPROPERTY_TUNER_STATUS_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
CurrentFrequency
The driver should set the value of CurrentFrequency to the current tuner frequency. This value is in hertz (Hz).
PLLOffset
The driver should set the value of PLLOffset to the PLL offset in multiples of the tuning granularity. This is used if the tuner strategy is KS_TUNER_STRATEGY_PLL. If the tuner strategy is not KS_TUNER_STRATEGY_PLL, this value has no meaning. The following table demonstrates the value to be returned by the driver for various tuning conditions, assuming the tuning granularity is 62.5kHz:
Frequency Offset | PLLOffset
+125,000 | +2
+62,500 | +1
Perfectly tuned | 0
-62,500 | -1
-125,000 | -2

SignalStrength
The driver should set the value of SignalStrength to the amplitude of the signal. This is used if the tuner strategy is KS_TUNER_STRATEGY_SIGNAL_STRENGTH. If the tuner strategy is not KS_TUNER_STRATEGY_SIGNAL_STRENGTH, this value has no meaning.
Busy
If the driver is in the process of tuning, the value of Busy should be set to TRUE. Otherwise, the value of Busy should be set to FALSE.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

KSPROPERTY_TUNER_STATUS is a read-only property.

See Also

KSPROPERTY, PROPSETID_TUNER, KSPROPERTY_TUNER_STATUS


KSPROPERTY_TVAUDIO_CAPS_S

Drivers for devices that support audio from television sources use the KSPROPERTY_TVAUDIO_CAPS_S structure, which retrieves the capabilities of the TV audio device, in handling KSPROPERTY_TVAUDIO_CAPS property requests.

typedef struct {
    KSPROPERTY   Property;
    ULONG        Capabilities;
    KSPIN_MEDIUM InputMedium;
    KSPIN_MEDIUM OutputMedium;
} KSPROPERTY_TVAUDIO_CAPS_S, *PKSPROPERTY_TVAUDIO_CAPS_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
Capabilities
The driver should return the capabilities of the TV audio device by setting one or more of the following KS_TVAUDIO_MODE_Xxx flags:
Value | Meaning
KS_TVAUDIO_MODE_MONO | Device supports mono audio.
KS_TVAUDIO_MODE_STEREO | Device supports stereo audio.
KS_TVAUDIO_MODE_LANG_A | Device supports a primary (default) language.
KS_TVAUDIO_MODE_LANG_B | Device supports a second language.
KS_TVAUDIO_MODE_LAND_C | Device supports a third language.

InputMedium
Reserved for system use.
OutputMedium
Reserved for system use.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

KSPROPERTY_TVAUDIO_CAPS is a read-only property.

See Also

KSPROPERTY, PROPSETID_VIDCAP_TVAUDIO, KSPROPERTY_TVAUDIO_CAPS


KSPROPERTY_TVAUDIO_MODE_S

Drivers for devices that support audio from television sources use the KSPROPERTY_TVAUDIO_S structure, which sets and retrieves the current TV audio mode, in handling KSPROPERTY_TVAUDIO_MODE property requests.

typedef struct {
    KSPROPERTY Property;
    ULONG      Mode;
} KSPROPERTY_TVAUDIO_S, *PKSPROPERTY_TVAUDIO_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
Mode
For Get requests, the driver returns the current mode of the TV audio device. For Set requests, the driver sets the current mode of the TV audio device to the specified value. Mode can be one of the following KS_TVAUDIO_MODE_Xxx values:
Value | Meaning
KS_TV_AUDIO_MODE_MONO | Indicates that the audio is in mono.
KS_TVAUDIO_MODE_STEREO | Indicates that the audio is in stereo.
KS_TVAUDIO_MODE_LANG_A | Indicates that the audio is in the primary language.
KS_TVAUDIO_MODE_LANG_B | Indicates that the audio is in the second language supported by the device.
KS_TVAUDIO_MODE_LANG_C | Indicates that the audio is in the third language supported by the device.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The KSPROPERTY_TVAUDIO_MODE is a read/write property.

See Also

KSPROPERTY, PROPSETID_VIDCAP_TVAUDIO, KSPROPERTY_TVAUDIO_MODE


KSPROPERTY_VIDEOCOMPRESSION_GETINFO_S

The KSPROPERTY_VIDEOCOMPRESSIONS_GETINFO_S structure is used to get information about the video compression supported by the device.

typedef struct {
    KSPROPERTY Property;
    ULONG      StreamIndex;
    LONG       DefaultKeyFrameRate;
    LONG       DefaultPFrameRate;
    LONG       DefaultQuality;
    LONG       NumberOfQualitySettings;
    LONG       Capabilities;
} KSPROPERTY_VIDEOCOMPRESSION_GETINFO_S, *PKSPROPERTY_VIDEOCOMPRESSION_GETINFO_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
StreamIndex
The zero-based index of the stream being queried.
DefaultKeyFrameRate
Indicates the estimated number of frames per key frame.
DefaultPFrameRate
Indicates the predicted number of frames per key frame.
DefaultQuality
The default quality value. This value should be in the range from 0 through 10000.
NumberOfQualitySettings
Indicates the number of discrete compression quality settings the device supports.
Capabilities
Specifies the compression capabilities of the device. It can be one or more of the following values ORed together:
Value | Meaning
KS_CompressionCaps_CanQuality | Indicates that the video compressor supports quality settings.
KS_CompressionCaps_CanCrunch | Indicates that the video compressor can compress the video to a specified data rate. If a driver supports this capability, the dwBitRate member of the KS_VIDEOINFOHEADER structure will contain the default data rate.
KS_CompressionCaps_CanKeyFrame | Indicates that the video compressor supports a user-specified key-frame rate.
KS_CompressionCaps_CanBFrame | Indicates that the video compressor supports a user-specified P frame interval. The frames that occur between the key frames and P frames are bidirectional (B) frames.
KS_CompressionCaps_CanWindow | Indicates that the video compressor supports a user-specified window size (number of frames whose average size cannot exceed the specified data rate).

Headers

Declared in ksmedia.h. Include ksmedia.h.

See Also

KSPROPERTY, PROPSETID_VIDCAP_VIDEOCOMPRESSION


KSPROPERTY_VIDEOCOMPRESSION_S

The KSPROPERTY_VIDEOCOMPRESSION_S structure is used to get or set one of the KSPROPERTY_VIDEOCOMPRESSION_Xxx properties of a specified stream.

typedef struct {
    KSPROPERTY Property;
    ULONG      StreamIndex;
    LONG       Value;
} KSPROPERTY_VIDEOCOMPRESSION_S, *PKSPROPERTY_VIDEOCOMPRESSION_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
StreamIndex
Contains the zero-based index of the stream.
Value
For Set requests, the driver should set the property specified in Property to this value. For Get requests, the driver should return the value of the property specified in Property.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

All KSPROPERTY_VIDEOCOMPRESSION properties that use this structure are read/write.

See Also

KSPROPERTY, PROPSETID_VIDCAP_VIDEOCOMPRESSION, KSPROPERTY_VIDEOCOMPRESSION_KEYFRAME_RATE, KSPROPERTY_VIDEOCOMPRESSION_PFRAMES_PER_KEYFRAME, KSPROPERTY_VIDEOCOMPRESSION_QUALITY, KSPROPERTY_VIDEOCOMPRESSION_OVERRIDE_KEYFRAME, KSPROPERTY_VIDEOCOMPRESSION_OVERRIDE_FRAME_SIZE, KSPROPERTY_VIDEOCOMPRESSION_WINDOWSIZE


KSPROPERTY_VIDEOCONTROL_ACTUAL_FRAME_RATE_S

The KSPROPERTY_VIDEOCONTROL_ACTUAL_FRAME_RATES_S structure is used to return frame rate information in response to KSPROPERTY_VIDEOCONTROL_ACTUAL_FRAME_RATE requests.

typedef struct {
    KSPROPERTY Property;
    ULONG      StreamIndex;
    ULONG      RangeIndex;
    SIZE       Dimensions;
    LONGLONG   CurrentActualFrameRate;
    LONGLONG   CurrentMaxAvailableFrameRate;
} KSPROPERTY_VIDEOCONTROL_ACTUAL_FRAME_RATE_S, *PKSPROPERTY_VIDEOCONTROL_ACTUAL_FRAME_RATE_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
StreamIndex
Contains the zero-based index of the stream.
RangeIndex
Contains the zero-based index into the range list. The value contained at this location specifies the range in which frame rate information is being requested.
Dimensions
The size of the image.
CurrentActualFrameRate
The actual frame rate for the specified stream and range. Frame rate values are expressed in 100-nanosecond units.
CurrentMaxAvailableFrameRate
The maximum frame rate for the specified stream and range. Frame rate values are expressed in 100-nanosecond units.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The driver should return STATUS_NOT_SUPPORTED if the pin is not open.

KSPROPERTY_VIDEOCONTROL_ACTUAL_FRAME_RATE is a read-only property.

See Also

KSPROPERTY, PROPSETID_VIDCAP_VIDEOCONTROL, KSPROPERTY_VIDEOCONTROL_ACTUAL_FRAME_RATE


KSPROPERTY_VIDEOCONTROL_CAPS_S

The KSPROPERTY_VIDEOCONTROL_CAPS_S structure is used to provide information about the control capabilities of the driver through KSPROPERTY_VIDEOCONTROL_CAPS property Get requests.

typedef struct {
    KSPROPERTY Property;
    ULONG      StreamIndex;
    ULONG      VideoControlCaps
} KSPROPERTY_VIDEOCONTROL_CAPS_S, *PKSPROPERTY_VIDEOCONTROL_CAPS_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
StreamIndex
Contains the zero-based index of the stream.
VideoControlCaps
Indicates the video control capabilities for the specified stream. The driver sets this value to one or more of the following:
Value | Meaning
KS_VideoControlFlag_FlipHorizontal | Indicates that the driver is capable of flipping the image horizontally.
KS_VideoControlFlag_FlipVertical | Indicates that the driver is capable of flipping the image vertically.
KS_VideoControlFlag_ExternalTriggerEnable | Indicates that the driver is capable of enabling acquisition of a single video frame based on an external trigger. An external trigger typically is hardware-specific.
KS_VideoControlFlag_Trigger | Indicates that the driver is capable of enabling acquisition of a single video frame based on a programmatic trigger.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The KSPROPERTY_VIDEOCONTROL_CAPS is a read-only property.

See Also

KSPROPERTY, PROPSETID_VIDCAP_VIDEOCONTROL, KSPROPERTY_VIDEOCONTROL_CAPS


KSPROPERTY_VIDEOCONTROL_FRAME_RATES_S

The KSPROPERTY_VIDEOCONTROL_FRAME_RATES structure is used to contain a list of available frame rates in 100-nanosecond units.

typedef struct {
    KSPROPERTY Property;
    ULONG      StreamIndex;
    ULONG      RangeIndex;
    SIZE       Dimensions;
} KSPROPERTY_VIDEOCONTROL_FRAME_RATES_S, *PKSPROPERTY_VIDEOCONTROL_FRAME_RATES_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
StreamIndex
Contains the zero-based index of the stream.
RangeIndex
Contains the zero-based index into the range list. The value at this location specifies the range in which frame rate information is being requested.
Dimensions
The size of the image.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The driver should return a KSMULTIPLE_ITEM structure containing a list of the frame rates supported. These values should be expressed using type I4.

See Also

KSPROPERTY, PROPSETID_VIDCAP_VIDEOCONTROL


KSPROPERTY_VIDEOCONTROL_MODE_S

The KSPROPERTY_VIDEOCONTROL_MODE_S structure is used to get and set the video control modes for a stream through KSPROPERTY_VIDEOCONTROL_MODE property request.

typedef struct {
    KSPROPERTY Property;
    ULONG      StreamIndex;
    LONG       Mode;
} KSPROPERTY_VIDEOCONTROL_MODE_S, *PKSPROPERTY_VIDEOCONTROL_MODE_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
StreamIndex
Contains the zero-based index of the stream.
Mode
For a Set request, Mode contains the requested video control mode. For a Get request the driver should return the current video control mode of the device. It can be one of the following values:
Value | Meaning
KS_VideoControlFlag_FlipHorizontal | Indicates that the driver is flipping (Get request), or should flip (Set request) the image horizontally.
KS_VideoControlFlag_FlipVertical | Indicates that the driver is flipping (Get request), or should flip (Set request) the image vertically.
KS_VideoControlFlag_ExternalTriggerEnable | Indicates that the driver has enabled (Get request), or should enable (Set request) the acquisition of a single video frame based on an external trigger. An external trigger is typically hardware-specific.
KS_VideoControlFlag_Trigger | Indicates that the driver has enabled (Get request), or should enable (Set request) the acquisition of a single video frame based on a programmatic trigger.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The KSPROPERTY_VIDEOCONTROL_MODE is a read/write property.

See Also

KSPROPERTY, PROPSETID_VIDCAP_VIDEOCONTROL, KSPROPERTY_VIDEOCONTROL_MODE


KSPROPERTY_VIDEODECODER_CAPS_S

Drivers for devices that support video decoding use the KSPROPERTY_VIDEODECODER_CAPS_S structure, which identifies the hardware capabilities of the video decoder, in handling KSPROPERTY_VIDEODECODER_CAPS property requests.

typedef struct {
    KSPROPERTY Property;
    ULONG      StandardsSupported;
    ULONG      Capabilities;
    ULONG      SettlingTime;
    ULONG      HSyncPerVSync;
} KSPROPERTY_VIDEODECODER_CAPS_S, *PKSPROPERTY_VIDEODECODER_CAPS_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
StandardsSupported
Specifies the video standards supported by the device. This value can be one or more of the following KS_Analog_Xxx bits ORed together:
KS_AnalogVideo_None
KS_AnalogVideo_NTSC_M
KS_AnalogVideo_NTSC_M_J
KS_AnalogVideo_NTSC_433

KS_AnalogVideo_PAL_B
KS_AnalogVideo_PAL_D
KS_AnalogVideo_PAL_G
KS_AnalogVideo_PAL_H
KS_AnalogVideo_PAL_I
KS_AnalogVideo_PAL_M
KS_AnalogVideo_PAL_N

KS_AnalogVideo_PAL_60

KS_AnalogVideo_SECAM_B
KS_AnalogVideo_SECAM_D
KS_AnalogVideo_SECAM_G
KS_AnalogVideo_SECAM_H
KS_AnalogVideo_SECAM_K
KS_AnalogVideo_SECAM_K1
KS_AnalogVideo_SECAM_L
KS_AnalogVideo_SECAM_L1
Capabilities
Specifies the video decoder capabilities. It should be set to zero or one of the following:
Value | Meaning
KS_VIDEODECODER_FLAGS_CAN_DISABLE_OUTPUT | Indicates that the decoder can translate its output lines. This flag is used by video decoders that use a video port.
KS_VIDEODECODER_FLAGS_CAN_USE_VCR_LOCKING | Indicates that the video decoder can alter its PLL timings to lock onto noisy signals. This typically is used when the video source is a VCR that introduces variability in the vertical and horizontal sync timing.
KS_VIDEODECODER_FLAGS_CAN_INDICATE_LOCKED | Indicates that the video decoder can distinguish whether it has locked to an incoming analog video signal.

SettlingTime
Specifies the settling time when changing input video sources. This value is expressed in milliseconds.
HSyncPerVSync
Specifies the number of horizontal sync pulses the video decoder produces during the vertical sync period. Decoders that follow the ITU_656 should set this value to six.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

KSPROPERTY_VIDEODECODER_CAPS is read-only.

See Also

KSPROPERTY, PROPSETID_VIDCAP_VIDEODECODER, KSPROPERTY_VIDEODECODER_CAPS


KSPROPERTY_VIDEODECODER_S

The KSPROPERTY_VIDEODECODER_S structure is used to set or get properties in the PROPSETID_VIDCAP_VIDEODECODER property set.

typedef struct {
    KSPROPERTY Property;
    ULONG      Value;
} KSPROPERTY_VIDEODECODER_S, *PKSPROPERTY_VIDEODECODER_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
Value
For Set requests, the driver should set the property specified in Property to this value. For Get requests, the driver should return the value of the property specified in Property.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The KSPROPERTY_VIDEODECODER_S structure is shared among the KSPROPERTY_VIDEODECODER_STANDARD, KSPROPERTY_VIDEODECODER_OUTPUT_ENABLE, and KSPROPERTY_VIDEODECODER_VCR_TIMING properties within the property set.See Also

KSPROPERTY, KSPROPERTY_VIDEODECODER_STANDARD, KSPROPERTY_VIDEODECODER_OUTPUT_ENABLE, KSPROPERTY_VIDEODECODER_VCR_TIMING


KSPROPERTY_VIDEODECODER_STATUS_S

Drivers for devices that support video decoding use the KSPROPERTY_VIDEODECODER_STATUS_S structure in handling KSPROPERTY_VIDEODECODER_STATUS property requests.

typedef struct {
    KSPROPERTY Property;
    ULONG      NumberOfLines;
    ULONG      SignalLocked;
} KSPROPERTY_VIDEODECODER_STATUS_S, *PKSPROPERTY_VIDEODECODER_STATUS_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
NumberOfLines
Indicates the number of lines detected in the incoming analog video signal.
SignalLocked
Indicates whether the signal is locked. Zero indicates that the signal is not locked. A nonzero value indicates the signal is locked.

Headers

Declared in ksmedia.h. Include ksmedia.h.

Comments

The KSPROPERTY_VIDEODECODER_STATUS_S structure is used to retrieve information about the video decoding process, including the number of lines in the incoming analog video signal.

KSPROPERTY_VIDEODECODER_STATUS is a read-only property.

See Also

KSPROPERTY, KSPROPERTY_VIDEODECODER_STATUS


KSPROPERTY_VIDEOPROCAMP_S

Video capture drivers use the KSPROPERTY_VIDEOPROCAMP_S structure to get or set the value of all the properties in the PROPSETID_VIDCAP_VIDEOPROCAMP property set.

typedef struct {
    KSPROPERTY Property;
    LONG   Value;
    ULONG  Flags;
    ULONG  Capabilities;
} KSPROPERTY_VIDEOPROCAMP_S, *PKSPROPERTY_VIDEOPROCAMP_S;

Members

Property
An initialized KSPROPERTY structure that describes the property set, property ID, and request type.
Value
For Set requests, the driver should set the property specified in Property to this value. For Get requests, the driver should return the value of the property specified in Property.
Flags
For Set requests, this value indicates the desired setting. For Get requests, this value contains the current setting. Valid settings for Flags are one of the following:
Value | Meaning
KSPROPERTY_VIDEOPROCAMP_FLAGS_MANUAL | Indicates that the property is to be adjusted manually.
KSPROPERTY_VIDEOPROCAMP_FLAGS_AUTO | Indicates that the property is to be adjusted automatically.

Capabilities
This member has meaning only for Get requests. The driver should return the capabilities of the videoprocamp with respect to the property specified in Property. This member should be set to one of the following:
Value | Meaning
KSPROPERTY_VIDEOPROCAMP_FLAGS_MANUAL | The device supports manual setting of the specified property.
KSPROPERTY_VIDEOPROCAMP_FLAGS_AUTO
 The device supports automatic setting of the specified property.

Headers

Declared in ksmedia.h. Include ksmedia.h.

See Also

KSPROPERTY, PROPSETID_VIDCAP_VIDEOPROCAMP, KSPROPERTY_VIDEOPROCAMP_BACKLIGHT_COMPENSATION, KSPROPERTY_VIDEOPROCAMP_BRIGHTNESS, KSPROPERTY_VIDEOPROCAMP_COLORENABLE, KSPROPERTY_VIDEOPROCAMP_CONTRAST, KSPROPERTY_VIDEOPROCAMP_GAMMA, KSPROPERTY_VIDEOPROCAMP_HUE, KSPROPERTY_VIDEOPROCAMP_SATURATION, KSPROPERTY_VIDEOPROCAMP_SHARPNESS, KSPROPERTY_VIDEOPROCAMP_WHITEBALANCE


USB Camera Minidriver Library

The USB Camera Minidriver Library section covers the following topics:

USB Camera Minidriver Library Structures

USB Camera Minidriver Library Callback Functions

USB Camera Minidriver Library Services


USB Camera Minidriver Library Structures

The section on USB Camera Minidriver Library Structures describes the structures used by video camera minidriver writers that use the USBCAMD minidriver library. Of the structures documented below, only USBCAMD_DEVICE_DATA is supported in USBCAMD version 1.0 of the USBCAMD library. The other three structures (USBCAMD_DEVICE_DATA2, USBCAMD_INTERFACE, and USBCAMD_Pipe_Config_Descriptor) were introduced in USBCAMD version 2.0.


USBCAMD_DEVICE_DATA

This structure is obsolete. A camera minidriver should use USBCAMD_DEVICE_DATA2 instead. This structure should be used only if maintaining backward compatibility with USBCAMD version 1.0.

The USBCAMD_DEVICE_DATA structure is used to define entry points for the camera minidriver's callback routines. Required and optional entry points are noted below.

typedef struct _USBCAMD_DEVICE_DATA
{
    ULONG  Sig;
    PCAM_INITIALIZE_ROUTINE  CamInitialize;
    PCAM_INITIALIZE_ROUTINE  CamUnInitialize
    PCAM_PROCESS_PACKET_ROUTINE  CamProcessUSBPacket;
    PCAM_NEW_FRAME_ROUTINE  CamNewVideoFrame;
    PCAM_PROCESS_RAW_FRAME_ROUTINE  CamProcessRawVideoFrame;
    PCAM_START_CAPTURE_ROUTINE  CamStartCapture;
    PCAM_STOP_CAPTURE_ROUTINE  CamStopCapture;
    PCAM_CONFIGURE_ROUTINE  CamConfigure;
    PCAM_STATE_ROUTINE  CamSaveState;
    PCAM_STATE_ROUTINE  CamRestoreState;
    PCAM_ALLOCATE_BW_ROUTINE  CamAllocateBandwidth;
    PCAM_FREE_BW_ROUTINE  CamFreeBandwidth;
} USBCAMD_DEVICE_DATA, *PUSBCAMD_DEVICE_DATA;

Members

Sig
Reserved for future use.
CamInitialize
Points to the driver's CamInitialize routine. This is a required entry point for camera minidrivers that use USBCAMD.
CamUnInitialize
Points to the driver's CamUnInitialize routine. This is a required entry point for camera minidrivers that use USBCAMD.
CamProcessUSBPacket
Points to the driver's CamProcessUSBPacket routine. This is an optional entry point. If the driver does not implement this routine, it must point to an empty routine.
CamNewVideoFrame
Points to the driver's CamNewVideoFrame routine. This is an optional entry point. If the driver does not implement this routine, it must point to an empty routine.
CamProcessRawVideoFrame
Points to the driver's CamProcessRawVideoFrame routine. This is an optional entry point. If the driver does not implement this routine, it must point to an empty routine.
CamStartCapture
Points to the driver's CamStartCapture routine. This is a required entry point for camera minidrivers that use USBCAMD.
CamStopCapture
Points to the driver's CamStopCapture routine. This is a required entry point for camera minidrivers that use USBCAMD.
CamConfigure
Points to the driver's CamConfigure routine. This is a required entry point for camera minidrivers that use USBCAMD.
CamSaveState
Points to the driver's CamSaveState routine. This is an optional entry point. If the driver does not implement this routine, it must point to an empty routine.
CamRestoreState
Points to the driver's CamRestoreState routine. This is an optional entry point. If the driver does not implement this routine, it must point to an empty routine.
CamAllocateBandwidth
Points to the driver's CamAllocateBandwidth routine. This is a required entry point for camera minidrivers that use USBCAMD.
CamFreeBandwidth
Points to the driver's CamFreeBandwidth routine. This is a required entry point for camera minidrivers that use USBCAMD.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

A camera minidriver will pass a USBCAMD_DEVICE_DATA structure to USBCAMD as a parameter to the USBCAMD library routine USBCAMD_AdapterReceivePacket in USBCAMD version 1.0.

See Also

USBCAMD_DEVICE_DATA2


USBCAMD_DEVICE_DATA2

The USBCAMD_DEVICE_DATA2 structure is for use with version 2.0 of USBCAMD. Minidrivers that must be backward compatible with version 1.0 of the USBCAMD library should use the USBCAMD_DEVICE_DATA structure.

The USBCAMD_DEVICE_DATA2 structure is used to define entry points for the camera minidriver's callback routines. Required and optional entry points are noted below.

typedef struct _USBCAMD_DEVICE_DATA2
{
    ULONG  Sig;
    PCAM_INITIALIZE_ROUTINE  CamInitialize;
    PCAM_INITIALIZE_ROUTINE  CamUnInitialize
    PCAM_PROCESS_PACKET_ROUTINE_EX  CamProcessUSBPacketEx;
    PCAM_NEW_FRAME_ROUTINE_EX  CamNewVideoFrameEx;
    PCAM_PROCESS_RAW_FRAME_ROUTINE_EX  CamProcessRawVideoFrameEx;
    PCAM_START_CAPTURE_ROUTINE_EX  CamStartCaptureEx;
    PCAM_STOP_CAPTURE_ROUTINE_EX  CamStopCaptureEx;
    PCAM_CONFIGURE_ROUTINE_EX  CamConfigureEx;
    PCAM_STATE_ROUTINE  CamSaveState;
    PCAM_STATE_ROUTINE  CamRestoreState;
    PCAM_ALLOCATE_BW_ROUTINE_EX  CamAllocateBandwidthEx;
    PCAM_FREE_BW_ROUTINE_EX  CamFreeBandwidthEx;
} USBCAMD_DEVICE_DATA2, *PUSBCAMD_DEVICE_DATA2;

Members

Sig
Reserved for future use.
CamInitialize
Points to the driver's CamInitialize routine. This is a required entry point for camera minidrivers that use USBCAMD.
CamUnInitialize
Points to the driver's CamUnInitialize routine. This is a required entry point for camera minidrivers that use USBCAMD.
CamProcessUSBPacketEx
Points to the driver's CamProcessUSBPacketEx routine. This is an optional entry point. If the driver does not implement this routine, it must point to an empty routine.
CamNewVideoFrameEx
Points to the driver's CamNewVideoFrameEx routine. This is an optional entry point. If the driver does not implement this routine, it must point to an empty routine.
CamProcessRawVideoFrameEx
Points to the driver's CamProcessRawVideoFrameEx routine. This is an optional entry point. If the driver does not implement this routine, it must point to an empty routine.
CamStartCaptureEx
Points to the driver's CamStartCaptureEx routine. This is a required entry point for camera minidrivers that use USBCAMD.
CamStopCaptureEx
Points to the driver's CamStopCaptureEx routine. This is a required entry point for camera minidrivers that use USBCAMD.
CamConfigureEx
Points to the driver's CamConfigureEx routine. This is a required entry point for camera minidrivers that use USBCAMD.
CamSaveState
Points to the driver's CamSaveState routine. This is an optional entry point. If the driver does not implement this routine, it must point to an empty routine.
CamRestoreState
Points to the driver's CamRestoreState routine. This is an optional entry point. If the driver does not implement this routine, it must point to an empty routine.
CamAllocateBandwidthEx
Points to the driver's CamAllocateBandwidthEx routine. This is a required entry point for camera minidrivers that use USBCAMD.
CamFreeBandwidthEx
Points to the driver's CamFreeBandwidthEx routine. This is a required entry point for camera minidrivers that use USBCAMD.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

A camera minidriver will pass a USBCAMD_DEVICE_DATA structure to USBCAMD as a parameter to the USBCAMD library routine USBCAMD_InitializeNewInterface.

See Also

USBCAMD_InitializeNewInterface,CamInitialize, CamUnInitialize, CamProcessUSBPacketEx, CamProcessUSBPacketEx, CamNewVideoFrameEx, CamNewVideoFrameEx, CamProcessRawVideoFrameEx, CamStartCaptureEx, CamStopCaptureEx, CamConfigureEx, CamSaveState, CamRestoreState, CamAllocateBandwidthEx, CamFreeBandwidthEx


USBCAMD_INTERFACE

The USBCAMD_INTERFACE structure defines a set of callback routines related to the USB bus interfaces.

typedef struct {
  INTERFACE  Interface;
  PFNUSBCAMD_WaitOnDeviceEvent  USBCAMD_WaitOnDeviceEvent;
  PFNUSBCAMD_BulkReadWrite  USBCAMD_BulkReadWrite;
  PFNUSBCAMD_SetVideoFormat  USBCAMD_SetVideoFormat;
  PFNUSBCAMD_SetIsoPipeState  USBCAMD_SetIsoPipeState;
  PFNUSBCAMD_CancelBulkReadWrite  USBCAMD_CancelBulkReadWrite;
} USBCAMD_INTERFACE, *PUSBCAMD_INTERFACE;

Members

Interface
Specifies the INTERFACE that is exported by USBCAMD for use by other drivers.
USBCAMD_WaitOnDeviceEvent
Pointer to USBCAMD_WaitOnDeviceEvent routine.
USBCAMD_BulkReadWrite
Pointer to USBCAMD_BulkReadWrite routine.
USBCAMD_SetVideoFormat
Pointer to USBCAMD_SetVideoFormat routine.
USBCAMD_SetIsoPipeState
Pointer to USBCAMD_SetIsoPipeState routine.
USBCAMD_CancelBulkReadWrite
Pointer to USBCAMD_CancelBulkReadWrite routine.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

USBCAMD_INTERFACE is not supported in USBCAMD version 1.0.

The camera minidriver acquires the USBCAMD_INTERFACE entry points at any point. The IRP for acquiring a USBCAMD_INTERFACE is IRP_MN_QUERY_INTERFACE and it should be sent at IRQL = PASSIVE_LEVEL. Typically a camera minidriver would acquire the address of the USBCAMD_INTERFACE entry points once towards the end of the initialization of the camera minidriver. The routines contained in the USBCAMD_INTERFACE structure are described in the USB Camera Minidriver Library Services.

See Also

INTERFACE, USBCAMD_WaitOnDeviceEvent, USBCAMD_BulkReadWrite, USBCAMD_SetVideoFormat, USBCAMD_SetIsoPipeState, USBCAMD_CancelBulkReadWrite, USB Camera Minidriver Library Services


USBCAMD_Pipe_Config_Descriptor

The USBCAMD_Pipe_Config_Descriptor structure is used for USBCAMD operations. It assists with establishing a connection between pipes discovered and streams to be declared (video or still). An array of USBCAMD_Pipe_Config_Descriptor structures is passed into CamConfigureEx, along with the array size, which is equal to the number of pipes found.

typedef struct _pipe_config_descriptor {
  CHAR  StreamAssociation;
  UCHAR  PipeConfigFlags;
} USBCAMD_Pipe_Config_Descriptor, *PUSBCAMD_Pipe_Config_Descriptor;

Members

StreamAssociation
Specifies the type of stream. This value should be set to one of the following values:
Value | Meaning
USBCAMD_VIDEO_STREAM | Stream consists of video data.
USBCAMD_STILL_STREAM | Stream consists of still data.
USBCAMD_VIDEO_STILL_STREAM | Stream consist of both video and still data.

PipeConfigFlags
Specifies the pipe characteristics. This value should be set to one of the following values:
Value | Meaning
USBCAMD_DATA_PIPE | Video or still data pipe.
USBCAMD_MULTIPLEX_PIPE | Pipe used for both still and video data.
USBCAMD_SYNC_PIPE | Out-of-band signaling pipe.
USBCAMD_DONT_CARE_PIPE | Pipe is not to be used for video or still streaming.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

USBCAMD_Pipe_Config_Descriptor is not supported in USBCAMD version 1.0.

The camera minidriver indicates pipe stream associations by identifying all streams associated with a particular pipe. If there is more than one stream association, USBCAMD creates a virtual still pin and assumes that the first stream is video followed by a still stream. The camera minidriver must set the PipeConfigFlags member to the value USBCAMD_DONT_CARE_PIPE if a particular pipe should not be used by USBCAMD. For example, when using an audio and video ISO pipe, and a camera device that supports stills and video, the PipeConfigFlags member in the first structure should be set to USBCAMD_DONT_CARE_PIPE. The second USBCAMD_Pipe_Config_Descriptor structure should have its StreamAssociation member value set to USBCAMD_VIDEO_STILL_STREAM and its PipeConfigFlags member value set to USBCAMD_MULTIPLEX_PIPE.

USBCAMD makes the assumption that the camera has one configuration description and all alternate settings have the same number and types of pipes.


USB Camera Minidriver Library Callback Functions

This section describes required and optional routines that a camera minidriver implements in order to use the USBCAMD library. A minidriver sets entry points to its CamXxx routines in its USBCAMD_DEVICE_DATA2 structure that the minidriver passes to USBCAMD. Camera minidrivers that must maintain backwards compatibility with USBCAMD version 1.0 should use a USBCAMD_DEVICE_DATA structure and associated callback routines.

A camera minidriver's CamXxx routines can have any names chosen by the minidriver writer.


CamAllocateBandwidth

This routine is obsolete. A camera minidriver should provide a CamAllocateBandwidthEx routine instead. This routine should be used only if maintaining backward compatibility with USBCAMD version 1.0 and using the USBCAMD_DEVICE_DATA structure.

A camera minidriver's CamAllocateBandwidth routine selects the appropriate alternate setting within the USB video streaming interface and prepares the device to stream. This routine is required.

NTSTATUS
  CamAllocateBandwidth(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext,
    PULONG  RawFrameLength,
    PVOID  Format
    );

Parameters

BusDeviceObject
Pointer to camera minidriver's device object created by the USB hub.
DeviceContext
Pointer to camera minidriver's device context.
RawFrameLength
Size, in bytes, of the raw frame data from the packet stream.
Format
Pointer to a KS_DATAFORMAT_VIDEOINFOHEADER structure that is associated with this stream.

Return Value

CamAllocateBandwidth returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

USBCAMD calls the camera minidriver's CamAllocateBandwidth routine immediately before the isochronous video capture stream is started. It is called in connection with a Run command.

See Also

CamAllocateBandwidthEx


CamAllocateBandwidthEx

CamAllocateBandwidthEx is not called by USBCAMD version 1.0.

A driver's CamAllocateBandwidthEx function selects the appropriate alternate setting within the USB video streaming interface and prepares the device to stream. This routine is required.

NTSTATUS
  CamAllocateBandwidthEx(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext,
    PULONG  RawFrameLength,
    PVOID  Format,
    ULONG  StreamNumber
    );

Parameters

BusDeviceObject
Pointer to camera minidriver's device object created by the USB hub.
DeviceContext
Pointer to camera minidriver's device context.
RawFrameLength
Size, in bytes, of the raw frame data from the packet stream.
Format
Pointer to a KS_DATAFORMAT_VIDEOINFOHEADER structure associated with this stream.
StreamNumber
Indicates the stream number.

Return Value

CamAllocateBandwidthEx returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

USBCAMD calls the camera minidriver's CamAllocateBandwidthEx routine immediately before the isochronous video capture stream is started. It is called in connection with a Run command.

See Also

USBCAMD_DEVICE_DATA2


CamConfigure

This routine is obsolete. A camera minidriver should provide a CamConFigureEx routine instead. This routine should be used only if maintaining backward compatibility with USBCAMD version 1.0 and using the USBCAMD_DEVICE_DATA structure.

A camera minidriver's CamConfigure routine configures the ISO streaming interface. This routine is required.

NTSTATUS
  CamConfigure(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext,
    PUSBD_INTERFACE_INFORMATION  Interface,
    PUSB_CONFIGURATION_DESCRIPTOR  ConfigurationDescriptor,
    PLONG  DataPipeIndex,
    PLONG  SyncPipeIndex
    );

Parameters

BusDeviceObject
Pointer to camera minidriver's device object created by the USB hub.
DeviceContext
Pointer to camera minidriver's device context.
Interface
A pointer to a USB_INTERFACE_INFORMATION structure initialized with the proper values for a SELECT_CONFIGURATION URB request. This interface structure corresponds to a single ISO interface on the device. The minidriver is able to select a particular alternate setting and pipe.
ConfigurationDescriptor
A pointer to an initialized USB_CONFIGURATION_DESCRIPTOR for this device.
DataPipeIndex
A pointer to a LONG value that indicates the index of the data pipe. The camera minidriver should fill in this value before returning.
SyncPipeIndex
A pointer to a LONG value that indicates the index of the sync pipe , if one is needed. The camera minidriver should fill in this value before returning.

Return Value

CamConfigure returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

See Also

CamConfigureEx, USBD_INTERFACE_INFORMATION, USB_CONFIGURATION_DESCRIPTOR


CamConfigureEx

CamConfigureEx is not called by USBCAMD version 1.0.

A camera minidriver's CamConfigureEx routine configures the ISO streaming interface. This routine is required.

The CamConfigureEx routine is called by the USBCAMD library to configure the ISO streaming interface. USBCAMD library calls the driver's CamConfigureEx routine just before the device is configured. At this point, USBCAMD can be notified of which interface and which alternate setting to use for the idle state. USBCAMD expects that the device has a single interface with multiple alternate settings and each alternate setting has the same number of pipes.

Camera minidrivers use CamConfigureEx to inform USBCAMD about the relationship between the discovered pipes and streams.

NTSTATUS
  CamConfigureEx(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext,
    PUSBD_INTERFACE_INFORMATION  Interface,
    PUSBD_CONFIGURATION_DESCRIPTOR  ConfigurationDescriptor,
    ULONG  PipeConfigListSize,
    PUSBCAMD_Pipe_Config_Descriptor  PipeConfig,
    PUSB_DEVICE_DESCRIPTOR  DeviceDescriptor
    );

Parameters

BusDeviceObject
Pointer to camera minidriver's device object created by the USB hub.
DeviceContext
Pointer to camera minidriver's device context.
Interface
A pointer to a USBD_INTERFACE_INFORMATION structure initialized with the proper values for a SELECT_CONFIGURATION URB request. This interface structure corresponds to a single ISO interface on the device. The camera minidriver is able to select a particular alternate setting and pipe.
ConfigurationDescriptor
A pointer to a USBD_CONFIGURATION_DESCRIPTOR for this device.
PipeConfigListSize
The number of elements in the PipeConfig array.
PipeConfig
A pointer to the USBCAMD_Pipe_Config_Descriptor array.
DeviceDescriptor
Pointer to USB device descriptor.

Return Value

CamConfigureEx returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

See Also

USBCAMD_DEVICE_DATA2, USBD_INTERFACE_INFORMATION, USBD_CONFIGURATION_DESCRIPTOR


CamFreeBandwidth

This routine is obsolete. A camera minidriver should provide a CamFreeBandwidthEx routine instead. This routine should be used only if maintaining backward compatibility with USBCAMD version 1.0 and using the USBCAMD_DEVICE_DATA structure.

A camera minidriver's CamFreeBandwidth routine should select an alternate USB interface that uses no bandwidth. This routine is required.

NTSTATUS
  CamFreeBandwidth(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext
    );

Parameters

BusDeviceObject
Pointer to camera minidriver's device object created by the USB hub.
DeviceContext
Pointer to camera minidriver's device context.

Return Value

CamFreeBandwidth returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

USBCAMD calls the camera minidriver's CamFreeBandwidth routine after the ISO video stream has stopped.

See Also

CamFreeBandwidthEx


CamFreeBandwidthEx

CamFreeBandwidthEx is not called by USBCAMD version 1.0.

A camera minidriver's CamFreeBandwidthEx should select an alternate USB interface that uses no bandwidth. This routine is required.

NTSTATUS
  CamFreeBandwidthEx(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext,
    ULONG  StreamNumber
    );

Parameters

BusDeviceObject
Pointer to camera minidriver's device object created by the USB hub.
DeviceContext
Pointer to camera minidriver's device context.
StreamNumber
Indicates stream number.

Return Value

CamFreeBandwidthEx returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

USBCAMD calls the camera minidriver's CamFreeBandwidthEx routine after the ISO video stream has stopped.

See Also

USBCAMD_DEVICE_DATA2


CamInitialize

CamInitialize is called by version 1.0 and version 2.0 of USBCAMD.

A camera minidriver's CamInitialize routine initializes the device.

NTSTATUS
  CamInitialize(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext
    );

Parameters

BusDeviceObject
Pointer to camera minidriver's device object created by the USB hub.
DeviceContext
Pointer to camera minidriver's device context.

Return Value

CamInitialize returns STATUS_SUCCESS or an appropriate error code. This routine is required.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

USBCAMD calls the camera minidriver's CamInitialize routine the first time the device is used.


CamNewVideoFrame

A camera minidriver's CamNewVideoFrame routine initializes a new video frame context. This routine is optional.

VOID
  CamNewVideoFrame(
    PVOID  DeviceContext,
    PVOID  FrameContext
    );

Parameters

DeviceContext
Pointer to camera minidriver's device context.
FrameContext
Pointer to camera minidriver's frame context.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

USBCAMD calls the camera minidriver's CamNewVideoFrame routine at IRQL = DISPATCH_LEVEL.

This routine is obsolete. A camera minidriver should provide a CamNewVideoFrameEx routine instead. This routine should be used only if maintaining backward compatibility with USBCAMD version 1.0 and using the USBCAMD_DEVICE_DATA structure.

See Also

CamNewVideoFrameEx


CamNewVideoFrameEx

CamNewVideoFrameEx is not called by USBCAMD version 1.0.

A camera minidriver's CamNewVideoFrame routine initializes a new video frame context structure. This routine is optional.

VOID
  CamNewVideoFrame(
    PVOID  DeviceContext,
    PVOID  FrameContext,
    ULONG  StreamNumber,
    PULONG  FrameLength
    );

Parameters

DeviceContext
Minidriver device context.
FrameContext
Frame context to be initialized.
StreamNumber
Indicates the stream associated with this new frame.
FrameLength
A pointer to the raw frame buffer length. The camera minidriver may decrease this value if it does not require a buffer transfer on the USB bus of the specified size. The camera minidriver should not increase this value.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

USBCAMD calls the camera minidriver's CamNewVideoFrameEx routine at IRQL = DISPATCH_LEVEL.

Return Value

None


CamProcessRawVideoFrame

This routine is obsolete. A camera minidriver should provide a CamProcessRawVideoFrameEx routine instead. This routine should be used only if maintaining backward compatibility with USBCAMD version 1.0 and using the USBCAMD_DEVICE_DATA structure.

A camera minidriver's CamProcessRawVideoFrame routine decodes the raw video frame. This routine is optional.

NTSTATUS
  CamProcessRawVideoFrame(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext,
    PVOID  FrameContext,
    PVOID  FrameBuffer,
    ULONG  FrameLength,
    PVOID  RawFrameBuffer,
    ULONG  RawFrameLength,
    ULONG  NumberOfPackets,
    PULONG  BytesReturned
    );

Parameters

BusDeviceObject
Pointer to camera minidriver's device object created by the USB hub.
DeviceContext
Pointer to camera minidriver's device context.
FrameContext
Pointer to camera minidriver's frame context.
FrameBuffer
Pointer to the buffer that will receive the final processed video frame.
FrameLength
Length of the frame buffer (from the original read request) in bytes.
RawFrameBuffer
Pointer to the buffer containing the received USB packets.
RawFrameLength
Length of RawFrameBuffer in bytes.
NumberOfPackets
Number of USB packets received into RawFrameBuffer.
BytesReturned
Pointer to the number of bytes read. The minidriver should set this to zero if it encounters any errors during processing.

Return Value

CamProcessRawVideoFrame returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

USBCAMD calls the camera minidriver's CamProcessRawVideoFrame routine at IRQL = PASSIVE_LEVEL.

See Also

CamProcessRawVideoFrameEx


CamProcessRawVideoFrameEx

CamProcessRawVideoFrameEx is not called by USBCAMD version 1.0.

USBCAMD calls the minidriver's CamProcessRawVideoFrameEx routine to perform decoding of the raw video frame. This routine is optional.

NTSTATUS
  CamProcessRawVideoFrame(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext,
    PVOID  FrameContext,
    PVOID  FrameBuffer,
    ULONG  FrameLength,
    PVOID  RawFrameBuffer,
    ULONG  RawFrameLength,
    ULONG  NumberOfPackets,
    PULONG  BytesReturned,
    ULONG  ActualRawFrameLength,
    ULONG  StreamNumber
    );

Parameters

BusDeviceObject
Pointer to camera minidriver's device object created by the USB hub.
DeviceContext
Pointer to camera minidriver's device context.
FrameContext
Pointer to minidriver's frame context.
FrameBuffer
Pointer to the buffer that should receive the final processed video frame.
FrameLength
Length of the frame buffer (from the original read request) specified in bytes.
RawFrameBuffer
Pointer to the buffer containing the received USB packets.
RawFrameLength
Length of RawFrameBuffer in bytes.
NumberOfPackets
Number of USB packets received into RawFrameBuffer.
BytesReturned
Pointer to the number of bytes read. The minidriver should set this to zero if it encounters any errors during processing.
ActualRawFrameLength
Contains the length of the actual buffer received from the camera. This value is specified in bytes.
StreamNumber
Indicates the stream number this frame is associated with.

Return Value

CamProcessRawVideoFrameEx returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

USBCAMD will clear the stream header options flag before passing the raw frame to the driver. The default flag is key frames only. The camera driver should set the stream header option flags appropriately if it needs to indicate anything other than key frames. USBCAMD calls this routine at IRQL = PASSIVE_LEVEL.

This routine will not be called if either one of the following bits are set in CamControlFlag:

  • USBCAMD_CamControlFlag_NoVideoRawProcessing
  • USBCAMD_CamControlFlag_NoStillRawProcessing


CamProcessUSBPacket

This routine is obsolete. A camera minidriver should provide a CamProcessUSBPacketEx instead. This routine should be used only if maintaining backward compatibility with USBCAMD version 1.0 and using the USBCAMD_DEVICE_DATA structure.

A camera minidriver's CamProcessUSBPacket routine processes a USB packet. This routine is optional.

ULONG
  CamProcessUSBPacket(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext,
    PVOID  CurrentFrameContext,
    PUSBD_ISO_PACKET_DESCRIPTOR  SyncPacket,
    PVOID  SyncBuffer,
    PUSBD_ISO_PACKET_DESCRIPTOR  DataPacket,
    PVOID  DataBuffer,
    PBOOLEAN  FrameComplete,
    PBOOLEAN  NextFrameIsStill
    );

Parameters

BusDeviceObject
Pointer to camera minidriver's device object created by the USB hub.
DeviceContext
Pointer to camera minidriver's device context.
CurrentFrameContext
Pointer to minidriver's frame context.
SyncPacket
Pointer to a USBD_ISO_PACKET_DESCRIPTOR from the sync pipe. This value will be NULL if the interface has only one pipe.
SyncBuffer
Pointer to data for the SyncPacket.
DataPacket
Pointer to a USBD_ISO_PACKET_DESCRIPTOR from the data pipe.
DataBuffer
Pointer to the DataPacket.
FrameComplete
Pointer to a BOOLEAN value that the camera minidriver sets to indicate whether this is the first data packet for a new video frame.
NextFrameIsStill
Pointer to a BOOLEAN value that the camera minidriver sets to indicate whether the next frame is a still frame or not. This value should be set to FALSE if the video stream is providing a live image or TRUE if the next frame is a still image or an image capture stream.

Return Value

This routine returns a ULONG that indicates the number of bytes that should be copied into the buffer (RawFrameBuffer or FrameBuffer).

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

USBCAMD calls the minidriver's CamProcessUSBPacket routine at IRQL = DISPATCH_LEVEL. The minidriver should complete this routine as quickly as possible. Image processing should be deferred to the CamProcessRawVideoFrame routine.

See Also

CamProcessUSBPacketEx, USBD_ISO_PACKET_DESCRIPTOR, CamProcessRawVideoFrame


CamProcessUSBPacketEx

CamProcessUSBPacketEx is not called by USBCAMD version 1.0.

USBCAMD calls the driver's CamProcessUSBPacketEx routine to allow the minidriver to process the USB packet.

ULONG
  CamProcessUSBPacketEx(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext,
    PVOID  CurrentFrameContext,
    PUSBD_ISO_PACKET_DESCRIPTOR  SyncPacket,
    PVOID  SyncBuffer,
    PUSBD_ISO_PACKET_DESCRIPTOR  DataPacket,
    PVOID  DataBuffer,
    PBOOLEAN  FrameComplete,
    PULONG  PacketFlag,
    PULONG  ValidDataOffset
    );

Parameters

BusDeviceObject
Pointer to camera minidriver's device object created by the USB hub.
DeviceContext
Pointer to camera minidriver's device context.
CurrentFrameContext
Pointer to camera minidriver's frame context.
SyncPacket
Pointer to a USBD_ISO_PACKET_DESCRIPTOR from the sync pipe. This value will be NULL if the interface has only one pipe.
SyncBuffer
Pointer to data for the SyncPacket.
DataPacket
ISO packet descriptor from data pipe.
DataBuffer
Pointer to DataPacket.
FrameComplete
Pointer to a BOOLEAN value that the camera minidriver sets to indicate whether this is the first data packet for a new video frame.
PacketFlag
Pointer to a value that the minidriver should set to indicate the contents of the current frame. It should be set to one of the following values:
Item | Description
USBCAMD_PROCESSPACKETEX_DropFrame | The current frame is unsalvageable. The read IRP should be recycled.
USBCAMD_PROCESSPACKETEX_NextFrameIsStill | The frame is a still image.
USBCAMD_PROCESSPACKETEX_CurrentFrameIsStill | The current frame is for the still pin.

ValidDataOffset
A pointer to a ULONG which contains a value that indicates the offset from the beginning of the packet that USBCAMD should start the copy from. This is to eliminate the extra buffer copy in the case of in-band signal. If the camera is not using in-band signaling, this value should be set to zero.

Return Value

This routine returns a ULONG that indicates the number of bytes that should be copied.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

USBCAMD calls the minidriver's CamProcessUSBPacketEx routine at IRQL = DISPATCH_LEVEL. The minidriver should complete their CamProcessUSBPacketEx routine as quickly as possible. Image processing should be deferred to the CamProcessRawVideoFrameEx routine.

This routine is used with ISO pipes only (video or still streaming).

See Also

USBD_ISO_PACKET_DESCRIPTOR


CamRestoreState

CamRestoreState is called by version 1.0 and version 2.0 of USBCAMD.

A camera minidriver's CamRestoreState routine restores a previously saved state. This routine is optional.

NTSTATUS
  CamRestoreState(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext
    );

Parameters

BusDeviceObject
Pointer to camera minidriver's device object created by the USB hub.
DeviceContext
Pointer to camera minidriver's device context.

Return Value

CamRestoreState should return the value STATUS_SUCCESS.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

USBCAMD calls the minidriver's CamRestoreState in the context of a SRB_CHANGE_POWER_STATE request where the power state is going from OFF to ON (D3 to D0).

USBCAMD ignores the return value from the minidriver's CamRestoreState.

This routine is obsolete and is no longer called in the WinXP version of USBCAMD. If the driver needs to save or restore device-specific data it should do so when processing SRB_CHANGE_POWER_STATE.


CamSaveState

CamSaveState is called by version 1.0 and version 2.0 of USBCAMD.

The CamSaveState routine in version 1.0 stores the current device context state.

NTSTATUS
  CamSaveState(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext
    );

Parameters

BusDeviceObject
Pointer to camera minidriver's device object created by the USB hub. This value may be NULL.
DeviceContext
Pointer to camera minidriver's device context.

Return Value

This routine should return the value STATUS_SUCCESS.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

USBCAMD calls the minidriver's CamRestoreState in the context of a SRB_CHANGE_POWER_STATE request where the power state is going from ON to OFF (D0 to D3).

USBCAMD ignores the return value from the minidriver's CamSaveState routine.

This routine is obsolete and is no longer called in the WinXP version of USBCAMD. If the driver needs to save or restore device-specific data it should do so when processing SRB_CHANGE_POWER_STATE.


CamStartCapture

This routine is obsolete. A camera minidriver should provide a CamStartCaptureEx routine instead. The CamStartCapture routine should be used only if maintaining backward compatibility with USBCAMD version 1.0 and using the USBCAMD_DEVICE_DATA structure.

A camera minidriver's CamStartCapture routine selects the appropriate alternate USB interface and prepares the device to stream. This routine is required.

NTSTATUS
  CamStartCapture(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext
    );

Parameters

BusDeviceObject
Pointer to camera minidriver's device object created by the USB hub.
DeviceContext
Pointer to camera minidriver's device context.

Return Value

CamStartCapture returns STATUS_SUCCESS or an appropriate error code. This return value is the completion code for the read IRP.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

USBCAMD calls the camera minidriver's CamStartCapture routine immediately prior to the start of the ISO video capture stream. CamStartCapture is called in the context of a Run command.

See Also

CamStartCaptureEx,


CamStartCaptureEx

CamStartCaptureEx is not called by USBCAMD version 1.0.

A camera minidriver's CamStartCaptureEx routine selects the appropriate alternate USB interface and prepares the device to stream. This routine is required.

NTSTATUS
  CamStartCaptureEx(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext,
    ULONG  StreamNumber
    );

Parameters

BusDeviceObject
Pointer to camera minidriver's device object created by the USB hub.
DeviceContext
Pointer to camera minidriver's device context.
StreamNumber
Indicates stream number.

Return Value

CamStartCaptureEx returns STATUS_SUCCESS or an appropriate error code. This return value is the completion code for the read IRP.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.


CamStopCapture

This routine is obsolete. CamStopCaptureEx should be used instead. This routine should be used only if maintaining backward compatibility with USBCAMD version 1.0.

A camera minidriver's CamStopCapture routine does processing after the stream is stopped. Typically, a camera minidriver will select an alternate USB interface that uses no additional bandwidth. This routine is required.

NTSTATUS
  CamStopCapture(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext
    );

Parameters

BusDeviceObject
Pointer to camera minidriver's device object created by the USB hub.
DeviceContext
Pointer to camera minidriver's device context.

Return Value

CamStopCapture returns STATUS_SUCCESS or an appropriate error code. This return value is the completion code for the read IRP.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

USBCAMD calls the minidriver's CamStopCapture routine immediately after the ISO video stream is stopped.

See Also

CamStopCaptureEx


CamStopCaptureEx

CamStopCaptureEx is not called by USBCAMD version 1.0.

A camera minidriver's CamStopCaptureEx routine does processing after the stream is stopped. Typically, a camera minidriver will select an alternate USB interface that uses no additional bandwidth. This routine is required.

NTSTATUS
  CamStopCaptureEx(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext,
    ULONG  StreamNumber
    );

Parameters

BusDeviceObject
Pointer to camera minidriver's device object created by the USB hub.
DeviceContext
Pointer to camera minidriver's device context.
StreamNumber
Indicates stream number.

Return Value

CamStopCaptureEx returns STATUS_SUCCESS or an appropriate error code. This return value is the completion code for the read IRP.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

USBCAMD calls the minidriver's CamStopCaptureEx routine immediately after the ISO video stream is stopped.


CamUnInitialize

CamUnInitialize is called by version 1.0 and Version 2.0 of USBCAMD.

A camera minidriver's CamUnInitialize routine performs any minidriver-specific clean-up. Typically this would include the deallocation of any resources the camera minidriver maintained. This is a required routine.

NTSTATUS
  CamUnInitialize(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext
    );

Parameters

BusDeviceObject
Pointer to camera minidriver's device object created by the USB hub.
DeviceContext
Pointer to camera minidriver's device context.

Return Value

CamUnInitialize returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

USBCAMD will call the camera minidriver's CamUnInitialize routine while processing an SRB_UNINITIALIZE_DEVICE request. The CamUnInitialize routine in version 1.0 is invoked after the user no longer requires the peripheral for that session. While the stream class driver automatically resets values associated with the minidriver, this call allows the minidriver to deallocate specific resources used during its operation.


USBCAMD_InitializeNewInterface

USBCAMD_InitializeNewInterface is called by the camera minidriver upon receiving an SRB_INITIALIZE_DEVICE request. It provides USBCAMD with all the necessary information to configure the camera minidriver correctly with the stream class driver and the USB driver. This is only used for USBCAMD version 2.0.

ULONG
  USBCAMD_InitializeNewInterface(
    IN PVOID  DeviceContext,
    IN PVOID  DeviceData,
    IN ULONG  Version,
    IN ULONG  CamControlFlag
    );

Parameters

DeviceContext
Pointer to device-specific context.
DeviceData
Pointer to USBCAMD_DEVICE_DATA2 structure.
Version
Version information. This value should be set to the value USBCAMD_VERSION_200 for use with USBCAMD version 2.0.
CamControlFlag
Flags to control interaction with the camera minidriver. The camera minidriver should set this value to one or more of the following:
Value | Meaning
USBCAMD_CamControlFlag_NoVideoRawProcessing | If the camera minidriver does not need to operate on video, it should set the USBCAMD_CamControlFlag_NoVideoRawProcessing for the video frame.
USBCAMD_CamControlFlag_NoStillRawProcessing | If the camera minidriver does not need to operate on the still image raw frame, it should set the USBCAMD_CamControlFlag_NoStillRawProcessing bit in order to eliminate one buffer copy.
USBCAMD_CamControlFlag_AssociatedFormat | The USBCAMD_CamControlFlag_AssociatedFormat bit should be set if the camera driver uses the same format for video as it does on the virtual still pin. After this flag is set, USBCAMD will not allow the virtual still pin to be opened in a format different from the video pin. The USBCAMD_CamControlFlag_AssociatedFormat bit should be set only when the virtual still pin produces frames of the same format as the video frames.
USBCAMD_CamControlFlag_EnableDeviceEvents | Setting the USBCAMD_CamControlFlag_EnableDeviceEvents will expose a device event to stream class and DSHOW. This will enable an STI Monitor to launch a still image application if the still button is pressed on the camera. USBCAMD will send a KSEVENT_VIDCAPTOSTI_EXT_TRIGGER event if this bit is set and the camera's still button is pressed.

Return Value

This routine returns the value USBCAMD_VERSION_200.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

See USBCAMD New Services Code Example for usage.


PCOMMAND_COMPLETE_FUNCTION

The camera minidriver can provide to USBCAMD the address of a completion routine that USBCAMD should call at the completion of one of its services.

typedef VOID
(*PCOMMAND_COMPLETE_FUNCTION)(
    PVOID  DeviceContext,
    PVOID  CommandContext,
    NTSTATUS  NtStatus
    );

Parameters

DeviceContext
User-supplied value or structure relevant to the stream.
CommandContext
Context passed to the CommandComplete routine.
NtStatus
The NTSTATUS of the called routine.

Return Value

None

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

The following USBCAMD services provide completion notification:

USBCAMD_BulkReadWrite

USBCAMD_ControlVendorCommand

USBCAMD_WaitOnDeviceEvent

See Also

USBCAMD_BulkReadWrite, USBCAMD_ControlVendorCommand, USBCAMD_WaitOnDeviceEvent


PADAPTER_RECEIVE_PACKET_ROUTINE

The camera minidriver should provide USBCAMD with the address of its routine that processes SRBs in its call to USBCAMD_DriverEntry.

typedef VOID
  (*PADAPTER_RECEIVE_PACKET_ROUTINE)(
    IN PHW_STREAM_REQUEST_BLOCK  Srb
    );

Parameters

Srb
SRB passed to the camera minidriver's SRB handling routine.

Return Value

None

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

See Also

USBCAMD_DriverEntry


USB Camera Minidriver Library Services

The following lists USBCAMD services available to camera minidrivers. Version 1.0 services are supported by USBCAMD version 2.0 to ensure backward compatibility with camera minidrivers using USBCAMD version 1.0.

The USBCAMD services are:

  • Version 2.0 Services
  • Version 1.0 Services


Version 2.0 Services

In addition to USBCAMD version 1.0 services, USBCAMD version 2.0 supports the new services described in the following topics:

USBCAMD_BulkReadWrite

USBCAMD_CancelBulkReadWrite

USBCAMD_SetIsoPipeState

USBCAMD_SetVideoFormat

USBCAMD_WaitOnDeviceEvent

USBCAMD_InitializeNewInterface


USBCAMD_BulkReadWrite

USBCAMD_BulkReadWrite is not available in USBCAMD version 1.0.

The USBCAMD_BulkReadWrite routine performs a read or write operation on the specified bulk pipe. USBCAMD can accept one read and one write request at a time.

NTSTATUS
  USBCAMD_BulkReadWrite(
    IN PVOID  DeviceContext,
    IN USHORT  PipeIndex,
    IN PVOID  Buffer,
    IN ULONG  BufferLength,
    IN PCOMMAND_COMPLETE_FUNCTION  CommandComplete,
    IN PVOID  CommandContext
    );

Parameters

DeviceContext
Pointer to device specific context.
PipeIndex
Index of the bulk pipe.
Buffer
Pointer to the read or write buffer. If this parameter is set to NULL for a read request, USBCAMD will pull a data SRB from the SRB read queue of the stream associated with this pipe. Write requests with a NULL buffer pointer are only allowed on the still pin if a SRB_WRITE_DATA request has been submitted to the still pin.
BufferLength
Length of read/write buffer.
CommandComplete
Pointer to the camera minidriver's PCOMMAND_COMPLETE_FUNCTION, which will be called when the bulk read or write is completed. This value can be NULL.
CommandContext
Pointer to a block of memory that is passed to the caller's CommandComplete routine.

Return Value

USBCAMD_BulkReadWrite returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

See Also

USBCAMD_INTERFACE


USBCAMD_CancelBulkReadWrite

USBCAMD_CancelBulkReadWrite is not available in USBCAMD version 1.0.

The USBCAMD_CancelBulkReadWrite routine cancels a pending read or write request.

NTSTATUS
  USBBCAMD_CancelBulkReadWrite(
    IN PVOID  DeviceContext,
    IN ULONG  PipeIndex
    );

Parameters

DeviceContext
Pointer to device-specific context.
PipeIndex
Index of the bulk pipe.

Return Value

USBCAMD_CancelBulkReadWrite returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

See Also

USBCAMD_INTERFACE


USBCAMD_SetIsoPipeState

USBCAMD_SetIsoPipeState is not available in USBCAMD version 1.0.

The USBCAMD_SetIsoPipeState routine allows the camera minidriver to control the streaming state on the ISO pipe. Note that the streaming state on the ISO bus works differently from the streaming state in stream class and in Microsoft® DirectShow®. It is possible to stop the ISO pipe from streaming for a short period while the overall video capture graph is still in a Run state. This routine is used to enable dual-mode cameras. In a dual-mode camera, if there is a request to get still data while streaming is in progress, the stream must be stopped on the ISO pipe. The still call will then be serviced and the ISO stream will be restarted.

NTSTATUS
  USBCAMD_SetIsoPipeState(
    IN PVOID  DeviceContext,
    IN ULONG  PipeStateFlags
    );

Parameters

DeviceContext
Pointer to device-specific context.
PipeStateFlags
State flags. This member should be set to either USBCAMD_STOP_STREAM or USBCAMD_START_STREAM.

Return Value

USBCAMD_SetIsoPipeState returns STATUS_SUCCESS or an appropriate error code.

Comments

Note that using this routine to stop the ISO pipe does not allow you to change the alternate setting or channel bandwidth. The ISO stream needs to be closed before the alternate setting is changed.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

See Also

USBCAMD_INTERFACE


USBCAMD_SetVideoFormat

USBCAMD_SetVideoFormat is not available in USBCAMD version 1.0.

The USBCAMD_SetVideoFormat routine is used to notify USBCAMD that the video format has changed.

NTSTATUS
  USBCAMD_SetVideoFormat(
    IN PVOID  DeviceContext,
    IN PHW_STREAM_REQUEST_BLOCK  pSrb
    );

Parameters

DeviceContext
Pointer to device-specific context.
pSrb
Pointer to SRB.

Return Value

USBCAMD_SetVideoFormat returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

Camera minidrivers handle all SRBs related to video format. Camera minidrivers should use USBCAMD_SetVideoFormat to inform USBCAMD of a video format change. Typically, the camera minidriver calls USBCAMD_SetVideoFormat from within its SRB_SET_DATAFORMAT handler.

See Also

USBCAMD_INTERFACE


USBCAMD_WaitOnDeviceEvent

USBCAMD_WaitOnDeviceExit is not available in USBCAMD version 1.0.

The USBCAMD_WaitOnDeviceEvent routine is used to perform a read from the interrupt pipe if the camera has an interrupt pipe for external event notifications.

The typical usage scenario for this routine is a camera with a snapshot button and an interrupt pipe associated with it. When a user presses the snapshot button, the read request on the interrupt pipe will be satisfied and the camera minidriver will be called back. If the camera driver had set USBCAMD_CamControlFlag_EnableDeviceEvents in CamControlFlag during a USBCAMD_InitializeNewInterface call, the STI monitor would also be notified of the snapshot event.

NTSTATUS
  USBCAMD_WaitOnDeviceEvent(
    IN PVOID  DeviceContext,
    IN ULONG  PipeIndex,
    IN PVOID  Buffer,
    IN ULONG  BufferLength,
    IN PCOMMAND_COMPLETE_FUNCTION  EventComplete,
    IN PVOID  EventContext,
    IN BOOLEAN  LoopBack
    );

Parameters

DeviceContext
A pointer to device-specific context.
PipeIndex
Index of the interrupt pipe.
Buffer
A pointer to the read buffer.
BufferLength
Length of buffer in bytes.
EventComplete
A pointer to the camera minidriver's PCOMMAND_COMPLETE_FUNCTION routine, which will be called when the interrupt read is completed. This value can be NULL.
EventContext
A pointer to memory block that will be passed to the EventComplete routine.
LoopBack
BOOLEAN value. If set to TRUE, USBCAMD will resubmit another read request to the interrupt pipe every time it completes an interrupt read.

Return Value

USBCAMD_WaitOnDeviceExit returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

See Also

USBCAMD_INTERFACE


Version 1.0 Services

USBCAMD version 1.0 supports the following services:

USBCAMD_AdapterReceivePacket

USBCAMD_ControlVendorCommand

USBCAMD_DriverEntry

USBCAMD_GetRegistryKeyValue

USBCAMD_SelectAlternateInterface

These services are supported in USBCAMD version 2.0 for purposes of backward compatibility.


USBCAMD_AdapterReceivePacket

The camera minidriver calls the USBCAMD library USBCAMD_AdapterReceivePacket routine to allow USBCAMD to process an SRB. Typically this routine will be called by the camera minidriver from its AdapterReceivePacket routine.

PVOID
  USBCAMD_AdapterReceivePacket(
    IN PHW_STREAM_REQUEST_BLOCK  Srb,
    IN PUSBCAMD_DEVICE_DATA  DeviceData,
    IN PDEVICE_OBJECT  *DeviceObject,
    IN BOOLEAN  NeedsCompletion
    );

Parameters

Srb
SRB passed to the camera minidriver's USBCAMD_AdapterReceivePacket routine.
DeviceData
USBCAMD_DEVICE_DATA structure with entry points to the camera minidriver's callback routines.
DeviceObject
Pointer to the device's PDO.
NeedsCompletion
BOOLEAN value indicating whether the SRB should be completed. If this value is set to TRUE, USBCAMD processes and completes the SRB request. Otherwise, USBCAMD ignores the SRB request. If this value is set to FALSE, USBCAMD will just return the device context pointer.

Return Value

USBCAMD_AdapterReceivePacket returns a pointer to the device-specific context for this instance of the camera DeviceContext.

Comments

This routine can also be used by the minidriver to retrieve the device context by setting the NeedsCompletion parameter to FALSE. In this case, the DeviceData and DeviceObject parameters are ignored.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.


USBCAMD_ControlVendorCommand

USBCAMD_ControlVendorCommand service sends vendor-specific commands to the control pipe. This routine may be called at IRQL >= PASSIVE_LEVEL. If the routine is called at IRQL > PASSIVE_LEVEL, the command will be deferred. After completion, the CommandComplete routine is called with a pointer to CommandContext.

NTSTATUS
  USBCAMD_ControlVendorCommand(
    IN PVOID  DeviceContext,
    IN UCHAR  Request,
    IN USHORT  Value,
    IN USHORT  Index,
    IN PVOID  Buffer,
    IN OUT PULONG  BufferLength,
    IN BOOLEAN  GetData,
    IN PCOMMAND_COMPLETE_FUNCTION  CommandComplete,
    IN PVOID  CommandContext
    );

Parameters

DeviceContext
Pointer to device-specific context.
Request
Value of the Request field for the vendor command.
Value
Value of the Value field for the vendor command.
Index
Value of the Index field for the vendor command.
Buffer
Pointer to a data buffer if the command has data. If the command does not have any data, this value will be NULL.
BufferLength
Pointer to buffer length value. Buffer length is expressed in bytes. If the value of Buffer is NULL, BufferLength may also be NULL.
GetData
Flag indicating data direction. GetData indicates data was sent from the device to the host.
CommandComplete
Pointer to camera minidriver's routine that will be called when the command is completed. This value can be NULL.
CommandContext
Pointer to block of memory that will be passed to the specified CommandComplete routine.

Return Value

USBCAMD_ControlVendorCommand returns NTSTATUS code from command or STATUS_PENDING if the command is deferred.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.


USBCAMD_DriverEntry

USBCAMD_DriverEntry is called from the camera minidriver's DriverEntry routine to register the minidriver with USBCAMD. This effectively binds the two drivers together.

ULONG
  USBCAMD_DriverEntry(
    PVOID  Context1,
    PVOID  Context2,
    ULONG  DeviceContextSize,
    ULONG  FrameContextSize,
    PADAPTER_RECEIVE_PACKET_ROUTINE  ReceivePacket
    );

Parameters

Context1
The context arguments are private plug and play structures used by the stream class driver to find the resources for this adapter
Context2
The context arguments are private plug and play structures used by the stream class driver to find the resources for this adapter
DeviceContextSize
Size, in bytes, required for the minidriver's device-specific context.
FrameContextSize
Size, in bytes, required for the minidriver's frame-specific context structure. Use NULL if not needed.
ReceivePacket
Entry point for receiving adapter-based SRB requests.

Return Value

Returns an NTSTATUS value indicating the result of the registration attempt. If a value other than STATUS_SUCCESS is returned, the minidriver will be unloaded.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.

Comments

FrameContextSize is optional. A nonNULL value should be provided only with calls to CamNewVideoFrame or CamProcessRawVideoFrame.


USBCAMD_GetRegistryKeyValue

USBCAMD_GetRegistryKeyValue retrieves a device-instance-specific registry key value.

NTSTATUS
  USBCAMD_GetRegistryKeyValue (
    IN HANDLE  Handle,
    IN PWCHAR  KeyNameString,
    IN ULONG  KeyNameStringLength,
    IN PVOID  Data,
    IN ULONG  DataLength
    );

Parameters

Handle
Handle to a valid and open device registry key.
KeyNameString
String buffer describing the key type.
KeyNameStringLength
Length of KeyNameString.
Data
Pointer to a caller-specified value or structure.
DataLength
Length, in bytes, of Data.

Return Value

Returns NO_ERROR, if successful. Otherwise, an appropriate error message is supplied.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.


USBCAMD_SelectAlternateInterface

USBCAMD_SelectAlternateInterface is called by the camera minidriver to select an alternate setting within the USB video streaming interface. On successful completion, the RequestInterface structure is filled in with the information from the SELECT_INTERFACE request. This routine is typically called by the camera minidriver in response to a request to allocate or free bandwidth. This should not be called when any video streams in the minidriver are open.

NTSTATUS
  USBCAMD_SelectAlternateInterface(
    IN PVOID  DeviceContext,
    IN OUT PUSBD_INTERFACE_INFORMATION  RequestInterface
    );

Parameters

DeviceContext
Device-specific context.
RequestInterface
Appropriate interface to select.

Return Value

Returns the status from the SELECT_INTERFACE request.

Headers

Declared in usbcamdi.h. Include usbcamdi.h.


DVD Reference Guide

The following sections contain information on the following topics:

DVD Property Sets

Data and Time Discontinuities

Copy Protection

Master Clock

DVD Structures


DVD Property Sets

Properties query or change stream aspects. Several property sets are used for DVD. All DVD input streams support the DVD copy protection property set in addition to the property sets outlined in this topic. For more information on property sets in general, see the WDM Stream Class Driver topics in the WDM DDK documentation. There are three property sets discussed for DVD implementation:

Audio Output Property Set

Subpicture Property Set

Video Port Property Set

KSPROPERTY_DVDSUBPIC_COMPOSIT_ON


Audio Output Property Set

The audio stream should support the KSPROPERTY_AUDDECOUT property set. This set indicates the forms of output available from the decoder. Two properties are available:

KSPROPERTY_AUDDECOUT_MODES

KSPROPERTY_AUDDECOUT_CUR_MODE


KSPROPERTY_AUDDECOUT_MODES

The KSPROPERTY_AUDDECOUT_MODES property is read-only. The return value enumerates all the available output modes for the audio decoder and is a DWORD. It can be any combination of the following bits.

Item | Description
KSAUDDECOUTMODE_STEREO_ANALOG | Indicates that the output is in analog stereo.
KSAUDDECOUTMODE_PCM_51 | Indicates that the output is in PCM 5.1 channel digital.
KSAUDDECOUTMODE_SPDIFF | Indicates that the output is SPDIFF format AC3 digital.


KSPROPERTY_AUDDECOUT_CUR_MODE

The KSPROPERTY_AUDDECOUT_CUR_MODE property is read/write and contains the current output mode. The data passed with this property is a DWORD. Acceptable values are defined in KSPROPERTY_AUDDECOUT_MODES .

The miniPortAudioGetProperty function returns the current mode of the decoder, while the miniPortAudioSetProperty function requests that the decoder switch the output format to the requested mode.

It is recommended that a default value for this property be initially set in the minidriver's serialized property set in the registry.


Subpicture Property Set

The GUID of this set is KSPROPERTY_DVDSUBPIC. Subpicture properties control the color, contrast, and output of the subpicture display. Three properties are available:

KSPROPERTY_DVDSUBPIC_PALETTE

KSPROPERTY_DVDSUBPIC_HLI

KSPROPERTY_DVDSUBPIC_COMPOSIT_ON


KSPROPERTY_DVDSUBPIC_PALETTE

The KSPROPERTY_DVDSUBPIC_PALETTE property sets the palette for a subpicture. The structure name is KSPROPERTY_SPPAL. The format is in the DVD specification. It contains an array of 16 YUV elements. These elements correspond to the 4-bit color numbers requested within the subpicture command stream.

typedef struct _KSPROPERTY_SPPAL
{
    KS_DVD_YUV   sppal[16];
} KSPROPERTY_SPPAL, *PKSPROPERTY_SPPAL;

Members

sppal
Current subpicture palette.


KSPROPERTY_DVDSUBPIC_HLI

The KSPROPERTY_DVDSUBPIC_HLI property is set-only. It specifies a rectangle of subpicture or screen whose color or contrast is to be changed. This differs from the DVD specification in that the Microsoft DVD navigator parses all button and keyboard information and only passes one highlight rectangle down to the subpicture decoder at any given time. As a result, highlight information is sent to the decoder more often than it is present in the DVD stream.

The highlight information arrives asynchronously to the data stream. The decoder uses the highlight Start and End time stamps to correlate the highlight information to the relevant subpicture information, if any. If the decoder has not received any subpicture stream information for the requested time stamps, the decoder assumes that the highlight information is stand-alone and does not apply to a subpicture. In this case, the color and contrast information can be assumed to be all the same color.

The data is not entirely in DVD disc format. Microsoft provides an additional structure of type KSPROPERTY_SPHLI that is passed as the parameter to this property. This structure describes the currently selected button from the DVD highlight information.

The DVD navigator processes all keystroke information and sends new highlight information each time a button state changes. The information describes only one mode of one button at a time. It includes a display rectangle in pixel coordinates of the screen, or a display of the subpicture, if present. The structure also contains color and contrast information but only for the present state of the currently selected button. The format is defined in the DVD specification.

Highlight information contains Start and End Timestamps. These are in the same units as other time stamps, with two exceptions: A Start Timestamp of 0xFFFFFFFF means the highlight property is effective upon receipt, and an End Timestamp of 0xFFFFFFFF means the highlight property is valid until the next highlight is received.

The HLISS field is as defined in the DVD specification. A value of zero indicates that all highlights are invalid and the decoder should disable all highlights.

typedef struct _KSPROPERTY_SPHLI
{
  USHORT  HLISS;
  USHORT  Reserved;
  ULONG   StartPTM;
  ULONG   EndPTM;
  USHORT  StartX;
  USHORT  StartY;
  USHORT  StopX;
  USHORT  StopY;
  KS_COLCON  ColCon;
} KSPROPERTY_SPHLI, *PKSPROPERTY_SPHLI;

Members

HLISS
Highlight status of current selection.
Reserved
Reserved for internal use. Do not use or set.
StartPTM
Start of presentation time.
EndPTM
End of presentation time.
StartX
Start x-coordinate pixel of the current highlight button.
StartY
Start y-coordinate pixel of the current highlight button.
StopY
Ending x-coordinate pixel of the current highlight button.
StopY
Ending y-coordinate pixel of the current highlight button.
ColCon
Color contrast description.


KSPROPERTY_DVDSUBPIC_COMPOSIT_ON

The KSPROPERTY_DVDSUBPIC_COMPOSIT_ON property is write-only. It enables or disables subpicture display usually by either calling SPSetSPEnable or SPSetSPDisable. If subpicture display is disabled, the decoder should still decode the subpicture data but not display it. This facilitates instant display when an enable command is received. There is a forced display subpicture command in the subpicture data command stream that overrides the KSPROPERTY_DVDSUBPIC_COMPOSIT_ON property.


Video Port Property Set

The Video Port property set has been separated into two sets: one retrieves (reads) information and the other sets (writes) information. This was designed to minimize memory limitations from variable-length lists returned by some functions.

Two video port property sets are discussed for DVD implementation:

Video Port Read Property Set

Video Port Write Property Set

Video Port Events

Additional information about events


Video Port Read Property Set

The GUID of Video Port property set is KSPROPSETID_VPConfig. The following seven get-only properties are supported.

Property | Description
KSPROPERTY_VPCONFIG_ NUMCONNECTINFO | A DWORD of the maximum number of electrical connection configurations.
KSPROPERTY_VPCONFIG_ GETCONNECTINFO | Retrieves all possible video port configurations. The structure is DDVIDEOPORTCONNECT.
KSPROPERTY_VPCONFIG_ NUMVIDEOFORMAT | A DWORD of the maximum number of supported pixel formats.
KSPROPERTY_VPCONFIG_ VPDATAINFO | Determines the initial state of the video port configuration. The structure is KS_AMVPDATAINFO.
KSPROPERTY_VPCONFIG_ GETVIDEOFORMAT | Retrieves all possible pixel formats. The structure name is DDPIXELFORMAT.
KSPROPERTY_VPCONFIG_ DECIMATIONCAPABILITY | A BOOLEAN indicating the size of the video image that can be reduced. FALSE indicates the image area may still be resized, but would also be clipped to the rectangle instead of scaled.
KSPROPERTY_VPCONFIG_ MAXPIXELRATE | Retrieves the maximum pixel rate based on pixel format. Specifies width of connection. The structure is KSVPMAXPIXELRATE.


Video Port Write Property Set

The GUID of the Video Port property set is KSPROPSETID_VPConfig. The following seven set-only properties are supported.

Property | Description
KSPROPERTY_VPCONFIG_ SETCONNECTINFO | Sets the hardware to user-defined connection information for the video port. It is a pointer to an array of DDVIDEOPORTCONNECT structures as returned by KSPROPERTY_VPCONFIG_GETCONNECTINFO.
KSPROPERTY_VPCONFIG_ DDRAWHANDLE | For use with Microsoft® DirectDraw®. Returns the DirectDraw handle property information.
KSPROPERTY_VPCONFIG_ VIDEOPORTID | For use with DirectDraw. Returns the video port ID property information.
KSPROPERTY_VPCONFIG_ DDRAWSURFACEHANDLE | For use with DirectDraw. Returns the surface handle property information.
KSPROPERTY_VPCONFIG_ SETVIDEOFORMAT | Sets the video format to user-defined specifications. It is a pointer to an array of DDPIXELFORMAT structures as returned by KSPROPERTY_VPCONFIG_GETVIDEOFORMAT.
KSPROPERTY_VPCONFIG_ INVERTPOLARITY | Toggles the global polarity flag, forcing the VPE port to be inverted. Since this feature is hardware dependent, models not using this feature must return STATUS_NOT_IMPLEMENTED.
KSPROPERTY_VPCONFIG_ SCALEFACTOR | Sets the video dimensions to user-defined specifications. The structure is KS_AMVPSIZE.


Video Port Events

The KS_EVENTSETID_VPNotify property set has only one event, KSEVENT_VPNOTIFY_FORMATCHANGE. This event is used to propagate an event such as a video-format change from the minidriver in kernel mode to DirectShow in user-mode.

The minidriver can detect a change in the video-format, for example 640x480 to 720x480. User-mode components must then be notified of the change so that the necessary actions can take place between DirectShow filters and KsProxy.

To accomplish this, KsProxy's VPE plug-in uses the IOCTL_KS_ENABLE_EVENT I/O control code to pass a user-mode event handle (created using the Win32 API CreateEvent) with the event's flags set to KSEVENT_TYPE_ENABLE via this property set to the minidriver, which saves the event handle.

The minidriver later sets this event handle to notify the VPE plug-in of KsProxy, which re-negotiates the connection based on the new format.

The VPE plug-in disables the event notification by sending the IOCTL_KS_DISABLE_EVENT I/O control code with the same event handle. The event handle is then closed by the VPE plug-in. The minidriver must not close the handle.

When some parameter of the video format changes, such as pixel aspect ratio, the decoder will receive a format block. (For more information, see KSSTREAM_HEADER_OPTIONSF_TYPECHANGED.) The decoder should signal the video port to renegotiate the video port connection. The decoder calls StreamClassStreamNotification with the parameter SignalMultipleStreamEvents.

The decoder must indicate that support is provided for this event in the HW_STREAM_INFORMATION entry for the VideoPort stream. The event set ID for the video port event is KSEVENTSETID_VPNotify and the event ID is KSEVENT_VPNOTIFY_FORMATCHANGE.


Data and Time Discontinuities

The KSSTREAM_HEADER block, which is appended to each sample, contains the OptionsFlags field.

The following three values are important to DVD playback:

KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY

KSSTREAM_HEADER_OPTIONSF_TYPECHANGED

KSSTREAM_HEADER_OPTIONSF_TIMEDISCONTINUITY

The data sample associated with a header that contains one of these fields may contain a null data packet or valid data.


KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY

The KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY bit indicates that the sample immediately following it belongs to a different source (or location/position) of data than the previous sample. This indicates that whatever processing was in progress using the previous sample must be completed. This bit often will come in the middle of a previous frame, thus indicating that the decoder should discard the previous frame and begin processing with the new data.


KSSTREAM_HEADER_OPTIONSF_TIMEDISCONTINUITY

The KSSTREAM_HEADER_OPTIONSF_TIMEDISCONTINUITY bit indicates that there will be a time gap in data immediately following this sample. For example, if the DVD stream contains a still frame encoded as a single I frame, the decoder receives all of the data for the I frame, with the last sample containing the TIMEDISCONTINUITY flag. This indicates that the decoder should immediately decode the I frame and not wait for B frame data.


KSSTREAM_HEADER_OPTIONSF_TYPECHANGED

The KSSTREAM_HEADER_OPTIONSF_TYPECHANGED bit indicates that the sample connected with the header will be a new KSDATAFORMAT block for the stream. This allows for changing of data types dynamically. An example would be the changing of video from 4x3 to 16x9, or the changing of audio from AC3 to PCM. The decoder should make all necessary changes for the new format block only when all data prior to the packet with the new format block has been processed.

A video format change must also signal KSSTREAM_EVENTs to the video port connection to indicate that the video format has changed.


Copy Protection

Microsoft worked with the Copyright Protection Technical Working Group (CPTWG), which announced in November 1996 that its DVD technology subcommittee proposed solutions for preventing unauthorized copying of filmed entertainment from prerecorded DVD-Video. The subcommittee has proposed controls using a scrambling scheme first proposed by the DVD Consortium for encrypting disc content and licensing the decryption technology.

Microsoft will provide software that facilitates the authentication process required by this scheme, thus allowing a DVD-ROM drive to authenticate and transfer keys with a DVD decrypter. Microsoft has no current plans to ship a DVD decrypter and, instead, is providing operating system code that will act as the agent to allow either hardware or software decrypters to be authenticated.

The key exchange process is initiated and controlled by the DVD navigator. The DVD minidriver only needs to implement the properties listed in the following section. The rest is handled by other components

Each DVD input stream will receive copy protection properties. This is true even if all DVD streams are controlled by the same hardware. For additional information on decoders that require key negotiation to be performed only once for all streams, see the Copy Protection Implementation Notes section.

Two topics are included:

Copy Protection Properties

DVD Key Sequence


Copy Protection Properties

The GUID of the video port property set is KSPROPERTY_COPYPROT. The following eight properties are available.

Property | Description
KSPROPERTY_DVDCOPY_ CHLG_KEY | Both get and set are supported on this property. A get property requests the decoder to provide its bus challenge key. A set property provides the decoder with the bus challenge key from the DVD drive. The data passed in this property will be a structure of type DVDCOPY_CHLGKEY.
KSPROPERTY_DVDCOPY_ DVD_KEY1 | This is a set-only property. This property provides the DVD drive bus key 1 to the decoder. The data passed will be a structure of type DVDCOPY_BUSKEY.
KSPROPERTY_DVDCOPY_ DEC_KEY2 | This is a get-only property. This property requests that the decoder's bus key 2 be transferred to the DVD drive. The data passed will be a structure of type DVDCOPY_BUSKEY.
KSPROPERTY_DVDCOPY_ TITLE_KEY | This is a set-only property. This provides Title Key from Current Content. The key is a structure of type DVDCOPY_TITLEKEY.
KSPROPERTY_DVDCOPY_ DISC_KEY | Set-only property. This provides Disc Key. The key is a structure of type DVDCOPY_DISCKEY.
KSPROPERTY_COPY_ MACROVISION | Set only. The key is a structure of type KS_COPY_MACROVISION. This is the analog NTSC video stream and will soon handle NTSC macrovision properties.
KSPROPERTY_DVDCOPY_ REGION | Get only. The DVD minidriver's fit into exactly one region bit. The key is a structure of type KS_DVDCOPY_REGION.
KSPROPERTY_DVDCOPY_ SET_COPY_STATE | Get and set only. The key is a structure of type KS_DVDCOPY_SET_COPY_STATE. This property uses KS_DVDCOPYSTATE_AUTHENTICATION_NOT_REQUIRED, KS_DVDCOPYSTATE_AUTHENTICATION_REQUIRED, KS_DVDCOPYSTATE_INITIALIZE, and KS_DVDCOPYSTATE_INITIALIZE_TITLE.


DVD Key Sequence

The following sequence will be repeated on every open DVD input pin on the decoder. The decoder receives the keys in the following sequence:

Get KSPROPERTY_DVDCOPY_CHLG_KEY

Set KSPROPERTY_DVDCOPY_DVD_KEY1

Set KSPROPERTY_DVDCOPY_CHLG_KEY

Get KSPROPERTY_DVDCOPY_DEC_KEY2

Set KSPROPERTY_DVDCOPY_DISC_KEY

Then, the following keys are received:

Get KSPROPERTY_DVDCOPY_CHLG_KEY

Set KSPROPERTY_DVDCOPY_DVD_KEY1

Set KSPROPERTY_DVDCOPY_CHLG_KEY

Get KSPROPERTY_DVDCOPY_DEC_KEY2

Set KSPROPERTY_DVDCOPY_TITLE_KEY

This sequence will also be repeated for every open DVD input pin on the decoder. It may occur at any time after a DVD disc key is successfully established. It may also occur more than once per disc key. Anytime a sector containing a Title Key is read, the authentication process must be successfully completed. If authentication fails, the read will be blocked and a corresponding error message returned.


Master Clock

The following three topics discuss the Master Clock:

Master Clock and SRB_OPEN_STREAM

DVD Clock Events

DVD Clock Functions


Master Clock and SRB_OPEN_STREAM

The decoder may indicate that a given stream is capable of providing master clock information. This indicates that the stream will be the one to which all others synchronize. Only two members of the SRB structure are needed.

Members

HwClockFunction
Pointer to the decoder minidriver routine to process calls for clock information. The decoder is set when the SRB_OPEN_STREAM call for the master clock stream is received. This indicates that a stream is capable of being a master clock for the system.
ClockSupportFlags
The following values are used.
Property Description
CLOCK_SUPPORT_CAN_
SET_ONBOARD_CLOCK 		Indicates the device can change the onboard clock time to any arbitrary value.
CLOCK_SUPPORT_CAN_
READ_ONBOARD_CLOCK 		Indicates the current clock time can be read for this stream from the hardware. This clock does not have to correlate to the current stream time, it just indicates the ability of the driver to return the value in 100ns units of the onboard clock.
CLOCK_SUPPORT_CAN_
RETURN_STREAM_TIME 		Indicates this stream can return the current stream time being processed in the hardware.


DVD Clock Events

Any decoder stream that supports a master clock for DVD playback must also support the following two clock events. These events provide reference information to any component in the system when they need to synchronize any time during DVD playback. The GUID for the event set is KSEVENTSETID_Clock.

The decoder should check for outstanding clock events at every reasonable opportunity. Typical implementations might examine all clock events on interrupts generated for each video start code, or on interrupts generated for VSYNC. The following two events are provided.

Event | Description
KSEVENT_CLOCK_ POSITION_MARK | This event provides notification that a specified stream time has been exceeded. This event is signaled using the SignalStreamEvent parameter to the StreamClassStreamNotification function. After this call has been made, the KSEVENT_ENTRY structure may not be used for any further function calls, including calls to the StreamClassGetNextEvent function.
KSEVENT_CLOCK_ INTERVAL_MARK | This event provides periodic notification at a specified interval after a specified start team has been reached.


DVD Clock Functions

All clock handles should be store with the appropriate and individual streams and not globally or in a static variable.

Function | Description
SRB_OPEN_MASTER_ CLOCK | Indicates to the decoder that the specified stream is being opened as a master clock, and provides a master clock handle to be used on all calls into the decoder master clock routine for access to that clock.
SRB_CLOSE_MASTER_ CLOCK | Indicates the given master clock handle is no longer active.
SRB_INDICATE_MASTER_ CLOCK | Provided to all streams indicating the handle to be used when calling for time stamps.


DVD Structures

The following are a list of structures used by DVD minidrivers.


KSVPMAXPIXELRATE

The KSVPMAXPIXELRATE structure is used to retrieve current video port's maximum pixel rate between stream services.

typedef struct
{
  KS_AMVPSIZE  Size;
  DWORD  MaxPixelsPerSecond;
  DWORD  Reserved;
} KSVPMAXPIXELRATE, *PKSVPMAXPIXELRATE;

Members

Size
Size of the KSVPMAXPIXELRATE structure.
MaxPixelsPerSecond
Maximum pixel throughput for the selected image size.
Reserved
Reserved.


KS_AMVPSIZE

The KS_AMVPSIZE structure is used to retrieve and pass video port size information between stream services.

typedef struct tagKS_AMVPSIZE
{
  DWORD  dwWidth;
  DWORD  dwHeight;
} KS_AMVPSIZE, *PKS_AMVPSIZE ;

Members

dwWidth
Width in pixels.
dwHeight
Height in pixels.


DVDCOPY_CHLGKEY

The DVDCOPY_CHLGKEY structure is used to retrieve and pass the challenge key information for the DVD Copy Protection authentication process.

typedef struct _DVDCOPY_CHLGKEY
{
  BYTE  ChlgKey[10];
  BYTE  Reserved[2];
} DVDCOPY_CHLGKEY, *PDVDCOPY_CHLGKEY;

Members

ChlgKey
DVD driver's challenge key.
Reserved
Reserved.


DVDCOPY_BUSKEY

The DVDCOPY_BUSKEY structure is used to retrieve the bus key information for the DVD Copy Protection authentication process.

typedef struct _DVDCOPY_BUSKEY
{
  BYTE  BusKey[5];
  BYTE  Reserved[1];
} DVDCOPY_BUSKEY, *PDVDCOPY_BUSKEY;

Members

BusKey
DVD driver's bus key.
Reserved
Reserved.


DVDCOPY_DISCKEY

The DVDCOPY_DISCKEY structure is used to retrieve the disc key information for the DVD Copy Protection authentication process.

typedef struct _DVDCOPY_DISCKEY
{
  BYTE  DiscKey[2048];
} DVDCOPY_DISCKEY, *PDVDCOPY_DISCKEY;

Members

DiscKey
Disc key.


DVDCOPY_TITLEKEY

The DVDCOPY_TITLEKEY structure is used to retrieve the title key information for the DVD Copy Protection authentication process.

typedef struct _KS_DVDCOPY_TITLEKEY {
  ULONG  KeyFlags;
  ULONG  ReservedNT[2];
  UCHAR  TitleKey[6];
  UCHAR  Reserved[2];
} KS_DVDCOPY_TITLEKEY, *PKS_DVDCOPY_TITLEKEY;

Members

KeyFlags
Title key flags settings, which provide CPM, CGMS, and CP_SEC information from the DVD drive.
ReservedNT
Reserved.
TitleKey
Title key from current content.
Reserved
Reserved.


KS_DVDCOPY_REGION

KS_DVDCOPY_REGION sets the copy region according to language restrictions.

typedef struct _KS_DVDCOPY_REGION
{
  UCHAR  Reserved;
  UCHAR  RegionData;
  UCHAR  Reserved2[2];
} KS_DVDCOPY_REGION, *PKS_DVDCOPY_REGION;

Members

Reserved
Reserved. Do not use.
RegionData
The region code for the nationality or language.
Reserved2
Reserved. Do not use.


KS_COPY_MACROVISION

KS_COPY_MACROVISION indicates the macrovision level of the data stream. This is a set property.

typedef struct _KS_COPY_MACROVISION
{
  ULONG MACROVISIONLevel;
} KS_COPY_MACROVISION, *PKS_COPY_MACROVISION;

Members

MACROVISIONLevel
Zero indicates that macrovision copy protection should not be in effect. Any other value indicates that macrovision copy protection should be in place.


KS_DVDCOPY_SET_COPY_STATE

KS_DVDCOPY_SET_COPY_STATE sets the copy state of the DVD stream. This is an optional property.

typedef struct _KS_DVDCOPY_SET_COPY_STATE
{
  ULONG DVDCopyState;
} KS_DVDCOPY_SET_COPY_STATE, *PKS_DVDCOPY_SET_COPY_STATE;

Members

DVDCopyState
In the set form, this member is used to provide the decoder notice of certain states of the key negotiation process. This is informational to the decoder only. See Multiple Streams on the Same Hardware for more uses of this property

Comments

When this property is issued as a Get call, the filter may respond with one of two responses:

KS_DVDCOPYSTATE_AUTHENTICATION_NOT_REQUIRED

KS_DVDCOPYSTATE_AUTHENTICATION_REQUIRED

This indicates whether this pin does or does not require CSS authentication to be performed. If the property is not implemented, the default is assumed to be KS_DVDCOPYSTATE_AUTHENTICATION_REQUIRED.

The main use for this would be a decoder that supports multiple pins with the same decryptor. For example, if one filter provides both SubPicture and Video decoding, the keys only need to be exchanged for one of the two pins. If a filter is going to return NOT_REQUIRED on one of the pins, it must always return REQUIRED on the first pin that the property is issued on.

When this property is issued as a Set call, this is an informational call used by hardware decoders to indicate what phase of the copy protection negotiation is being entered. The decoder may hold off the SET_STATE with one of the following until the correct bits indicating that a new CSS key is required have been received:

KS_DVDCOPYSTATE_INITIALIZE
Indicates the start of a disc key negotiation sequence.
KS_DVDCOPYSTATE_INITIALIZE_TITLE
Indicates the start of a title key negotiation sequence.
KS_DVDCOPYSTATE_DONE
Indicates the completion of a key negotiation sequence.


Broadcast Driver Architecture Reference

A minidriver for Broadcast Driver Architecture (BDA) uses the functions, property and method sets, constants, enumerations, and structures in this reference to configure itself and control its operation.

The BDA Reference includes:

Broadcast Driver Architecture Support Functions

Broadcast Driver Architecture Property, Event, and Method Sets

Broadcast Driver Architecture Enumerations and Structures

Broadcast Driver Architecture Constants


Broadcast Driver Architecture Support Functions

This section documents the support functions that a BDA minidriver uses. The system-supplied BDA support library (Bdasup.lib) provides these functions. In order for your BDA minidriver to use these functions, you must include the Bdasup.h header file in your code and link to Bdasup.lib when you build your driver.

The following sections provide more information about the BDA support functions:

BdaCheckChanges

BdaCommitChanges

BdaCreateFilterFactory

BdaCreateFilterFactoryEx

BdaCreatePin

BdaCreateTopology

BdaDeletePin

BdaFilterFactoryUpdateCacheData

BdaGetChangeState

BdaInitFilter

BdaMethodCreatePin

BdaMethodCreateTopology

BdaMethodDeletePin

BdaPropertyGetControllingPinId

BdaPropertyGetPinControl

BdaPropertyNodeDescriptors

BdaPropertyNodeEvents

BdaPropertyNodeMethods

BdaPropertyNodeProperties

BdaPropertyNodeTypes

BdaPropertyPinTypes

BdaPropertyTemplateConnections

BdaStartChanges

BdaUninitFilter

BdaValidateNodeProperty


BdaCheckChanges

The BdaCheckChanges function verifies a new set of BDA topology changes before they are committed.

STDMETHODIMP_(NTSTATUS)
  BdaCheckChanges(
    IN PIRP  Irp
    );

Parameters

Irp
Points to the IRP for the request to verify changes.

Return Value

Returns STATUS_SUCCESS or an appropriate error code.

Returns the result that the BdaCommitChanges function would have returned.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

A BDA minidriver calls the BdaCheckChanges function to verify a group of BDA topology changes after the minidriver receives a KSMETHOD_BDA_CHECK_CHANGES request of the KSMETHODSETID_BdaChangeSync method set from the network provider. BDA minidrivers define dispatch and filter-automation tables so that those minidrivers either dispatch the BdaCheckChanges function directly or intercept this request using an internal method, which then calls the BdaCheckChanges function. For example, BDA minidrivers that intercept this request can obtain a pointer to the BDA filter from the passed IRP so that they can validate the new list of resources for the filter. See Defining Automation Tables and Changing BDA Filter Properties for more information.

A BDA minidriver calls BdaCheckChanges at IRQL = PASSIVE_LEVEL.

BdaCheckChanges is available on Windows® XP and later. BdaCheckChanges is available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.

See Also

BdaCommitChanges, KSMETHODSETID_BdaChangeSync


BdaCommitChanges

The BdaCommitChanges function commits the changes to BDA topology that have occurred since the last call to the BdaStartChanges function.

STDMETHODIMP_(NTSTATUS)
  BdaCommitChanges(
    IN PIRP  Irp
    );

Parameters

Irp
Points to the IRP for the request to commit changes.

Return Value

Returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

A BDA minidriver calls the BdaCommitChanges function to commit a set of BDA topology changes after the minidriver receives a KSMETHOD_BDA_COMMIT_CHANGES request of the KSMETHODSETID_BdaChangeSync method set from the network provider. BDA minidrivers define dispatch and filter-automation tables so that those minidrivers either dispatch the BdaCommitChanges function directly or intercept this request using an internal method, which then calls the BdaCommitChanges function. For example, BDA minidrivers that intercept this request can obtain a pointer to the BDA filter from the passed IRP so that they can:

  1. Set the new list of resources for the filter to the pending list of resources.
  2. Set the change state of the filter to BDA_CHANGES_COMPLETE.
  3. Commit the resources on the underlying device.

See Defining Automation Tables and Changing BDA Filter Properties for more information.

A BDA minidriver calls BdaCommitChanges at IRQL = PASSIVE_LEVEL.

BdaCommitChanges is available on Windows® XP and later. BdaCommitChanges is available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.

See Also

BDA_CHANGE_STATE, BdaCheckChanges, BdaStartChanges, KSMETHODSETID_BdaChangeSync


BdaCreateFilterFactory

The BdaCreateFilterFactory function adds the specified filter descriptor as a filter factory to the specified device and associates the filter factory with the specified BDA template topology.

STDMETHODIMP_(NTSTATUS)
  BdaCreateFilterFactory(
    IN PKSDEVICE  pKSDevice,
    IN const KSFILTER_DESCRIPTOR  *pFilterDescriptor,
    IN const BDA_FILTER_TEMPLATE  *pBdaFilterTemplate
    );

Parameters

pKSDevice
Points to the BDA device to which to add the filter factory with associated BDA template topology.
pFilterDescriptor
Points to a KSFILTER_DESCRIPTOR structure that describes a filter for the BDA device. Note that not all of the template pin and node types may be exposed as pin and node factories when the filter is first initialized.
pBdaFilterTemplate
Points to a BDA_FILTER_TEMPLATE structure that describes a BDA template topology.

Return Value

Returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

A BDA minidriver calls the BdaCreateFilterFactory function to add a filter factory with an associated BDA template topology to a device and to register all of the topology's static template structures with the BDA support library (BdaSup.sys). The BDA support library can then handle the following method and property calls:

KSMETHODSETID_BdaChangeSync

KSMETHODSETID_BdaDeviceConfiguration

KSPROPSETID_BdaTopology

If a BDA minidriver requires a pointer to the newly created filter factory (KSFILTERFACTORY), the minidriver should call the BdaCreateFilterFactoryEx function instead.

A BDA minidriver calls BdaCreateFilterFactory at IRQL = PASSIVE_LEVEL.

BdaCreateFilterFactory is available on Windows® XP and later. BdaCreateFilterFactory is available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.

See Also

BdaCreateFilterFactoryEx, BDA_FILTER_TEMPLATE, KSDEVICE, KSFILTER_DESCRIPTOR, KSFILTERFACTORY, KSMETHODSETID_BdaChangeSync, KSMETHODSETID_BdaDeviceConfiguration, KSPROPSETID_BdaTopology


BdaCreateFilterFactoryEx

The BdaCreateFilterFactoryEx function adds the specified filter descriptor as a filter factory to the specified device and associates the filter factory with the specified BDA template topology.

STDMETHODIMP_(NTSTATUS)
  BdaCreateFilterFactoryEx(
    IN  PKSDEVICE  pKSDevice,
    IN  const KSFILTER_DESCRIPTOR  *pFilterDescriptor,
    IN  const BDA_FILTER_TEMPLATE  *pBdaFilterTemplate,
    OUT PKSFILTERFACTORY  *ppKSFilterFactory
    );

Parameters

pKSDevice
Points to the BDA device to which to add the filter factory with associated BDA template topology.
pFilterDescriptor
Points to a KSFILTER_DESCRIPTOR structure that describes a filter for the BDA device. Note that not all of the template pin and node types may be exposed as pin and node factories when the filter is first initialized.
pBdaFilterTemplate
Points to a BDA_FILTER_TEMPLATE structure that describes a BDA template topology.
ppKSFilterFactory
Points to a buffer that receives a pointer to a KSFILTERFACTORY structure for the newly created filter factory.

Return Value

Returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

A BDA minidriver calls the BdaCreateFilterFactoryEx function to add a filter factory with an associated BDA template topology to a device and to register all of the topology's static template structures with the BDA support library (BdaSup.sys). The BDA support library can then handle the following method and property calls:

KSMETHODSETID_BdaChangeSync

KSMETHODSETID_BdaDeviceConfiguration

KSPROPSETID_BdaTopology

A BDA minidriver calls BdaCreateFilterFactoryEx rather than the BdaCreateFilterFactory function whenever it requires a pointer to the newly created KSFILTERFACTORY. The BdaCreateFilterFactory function also creates a filter factory but doesn't return it to the caller. The BDA minidriver requires a pointer to the newly created KSFILTERFACTORY if the minidriver must call the _KsEdit function to edit KSFILTERFACTORY.

A BDA minidriver calls BdaCreateFilterFactoryEx at IRQL = PASSIVE_LEVEL.

BdaCreateFilterFactoryEx is available on Windows® XP and later. BdaCreateFilterFactoryEx is available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.

See Also

BdaCreateFilterFactory, BDA_FILTER_TEMPLATE, KSDEVICE, KSFILTER_DESCRIPTOR, _KsEdit, KSFILTERFACTORY, KSMETHODSETID_BdaChangeSync, KSMETHODSETID_BdaDeviceConfiguration, KSPROPSETID_BdaTopology


BdaCreatePin

The BdaCreatePin function creates a new pin in the specified filter.

STDMETHODIMP_(NTSTATUS)
  BdaCreatePin(
    IN PKSFILTER  pKSFilter,
    IN ULONG  ulPinType,
    OUT ULONG  *pulPinId
    );

Parameters

pKSFilter
Points to the filter in which to create a pin.
ulPinType
Type of pin to create.
pulPinId
Points to a variable that receives the identifier for the created pin.

Return Value

Returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

A BDA minidriver calls the BdaMethodCreatePin function when the network provider dynamically creates a pin using the KSMETHOD_BDA_CREATE_PIN_FACTORY request of the KSMETHODSETID_BdaDeviceConfiguration method set. If a BDA minidriver must create a pin without relying on the network provider, the BDA minidriver should call the BdaCreatePin function directly.

A BDA minidriver calls BdaCreatePin at IRQL = PASSIVE_LEVEL.

BdaCreatePin is available on Windows® XP and later. BdaCreatePin is available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.

See Also

BdaDeletePin, BdaMethodCreatePin, KSFILTER, KSMETHODSETID_BdaDeviceConfiguration


BdaCreateTopology

The BdaCreateTopology function creates the topology between two pins.

STDMETHODIMP_(NTSTATUS)
  BdaCreateTopology(
    IN PKSFILTER  pKSFilter,
    IN ULONG  InputPinId,
    IN ULONG  OutputPinId
    );

Parameters

pKSFilter
Points to the BDA filter on which to create topology.
InputPinId
Identifier of the filter's input pin.
OutputPinId
Identifier of the filter's output pin.

Return Value

Returns STATUS_SUCCESS or an appropriate error code.

Returns NULL if no valid pin pairing exists with the specified input and output pins.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

A BDA minidriver calls the BdaMethodCreateTopology function when the network provider dynamically creates a topology between filter pins using the KSMETHOD_BDA_CREATE_TOPOLOGY request of the KSMETHODSETID_BdaDeviceConfiguration method set. If a BDA minidriver must create a topology between filter pins without relying on the network provider, the BDA minidriver should call the BdaCreateTopology function directly.

A BDA minidriver calls BdaCreateTopology at IRQL = PASSIVE_LEVEL.

BdaCreateTopology is available on Windows® XP and later. BdaCreateTopology is available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.

See Also

BdaMethodCreateTopology, KSFILTER, KSMETHODSETID_BdaDeviceConfiguration


BdaDeletePin

The BdaDeletePin function deletes a pin from the specified filter.

STDMETHODIMP_(NTSTATUS)
  BdaDeletePin(
    IN PKSFILTER  pKSFilter,
    IN ULONG  *pulPinId
    );

Parameters

pKSFilter
Points to the filter in which to delete a pin.
pulPinId
Points to a variable that contains the identifier for the pin to delete.

Return Value

Returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

A BDA minidriver calls the BdaMethodDeletePin function when the network provider dynamically deletes a pin using the KSMETHOD_BDA_DELETE_PIN_FACTORY request of the KSMETHODSETID_BdaDeviceConfiguration method set. If a BDA minidriver must delete a pin without relying on the network provider, the BDA minidriver should call the BdaDeletePin function directly.

A BDA minidriver calls BdaDeletePin at IRQL = PASSIVE_LEVEL.

BdaDeletePin is available on Windows® XP and later. BdaDeletePin is available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.

See Also

BdaCreatePin, BdaMethodDeletePin, KSFILTER, KSMETHODSETID_BdaDeviceConfiguration


BdaFilterFactoryUpdateCacheData

The BdaFilterFactoryUpdateCacheData function updates the pin data cache for an instance of a filter.

NTSTATUS
  BdaFilterFactoryUpdateCacheData (
    IN PKSFILTERFACTORY  pFilterFactory,
    IN const KSFILTER_DESCRIPTOR  *pFilterDescriptor OPTIONAL
    );

Parameters

pFilterFactory
Pointer to the KSFILTERFACTORY for which to update the pin data cache.
pFilterDescriptor
Pointer to an optional KSFILTER_DESCRIPTOR for which the pin data cache will be updated. If NULL, pFilterFactory's descriptor is used instead. Provide for dynamic pin creation, that is, pin creation that occurs after a filter's create dispatch routine completes.

Return Value

Returns STATUS_SUCCESS or an appropriate error code. Returns STATUS_INVALID_PARAMETER if no device interface is found that corresponds to the categories passed in the filter descriptor.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

A BDA minidriver calls the BdaFilterFactoryUpdateCacheData function to update the pin data cache for all pins specified at pFilterDescriptor. In this call, the BDA minidriver typically passes the pFilterDescriptor member of a BDA_FILTER_TEMPLATE structure that describes the template topology for the BDA filter to pFilterDescriptor. If pFilterDescriptor is NULL, the cached information will be updated for all pin factories specified at pFilterFactory's KSFILTER_DESCRIPTOR member. For information about the pin data cache, see Caching Pin Information for DirectShow.

The KsRegisterFilterWithNoKSPins function provides similar functionality but only allows one medium per registered pin. This may not be sufficient for a BDA minidriver.

See Also

BDA_FILTER_TEMPLATE, KSFILTER_DESCRIPTOR, KSFILTERFACTORY, KsRegisterFilterWithNoKSPins


BdaGetChangeState

The BdaGetChangeState function returns the current change state of BDA topology.

STDMETHODIMP_(NTSTATUS)
  BdaGetChangeState(
    IN PIRP  Irp,
    OUT BDA_CHANGE_STATE  *pChangeState
    );

Parameters

Irp
Points to the IRP for the request to get the current change state.
pChangeState
Points to a variable that receives the current change state of BDA topology. The BDA change state can be one of the following values from the BDA_CHANGE_STATE enumeration:
Value | Description
BDA_CHANGES_COMPLETE | BDA topology changes are complete.
BDA_CHANGES_PENDING | BDA topology changes are pending.

Return Value

Returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

A BDA minidriver calls the BdaGetChangeState function to retrieve the current change state of BDA topology after the minidriver receives a KSMETHOD_BDA_GET_CHANGE_STATE request of the KSMETHODSETID_BdaChangeSync method set from the network provider. BDA minidrivers define dispatch and filter-automation tables so that those minidrivers either dispatch the BdaGetChangeState function directly or intercept this request using an internal method, which then calls the BdaGetChangeState function. For example, BDA minidrivers that intercept this request can obtain a pointer to the BDA filter from the passed IRP so that they can:

  1. Not only check for pending topology changes but also for pending changes on the filter.
  2. Return the current change state for both BDA topology and the BDA filter.

See Defining Automation Tables and Changing BDA Filter Properties for more information.

A BDA minidriver calls BdaGetChangeState at IRQL = PASSIVE_LEVEL.

BdaGetChangeState is available on Windows® XP and later. BdaGetChangeState is available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.

See Also

BDA_CHANGE_STATE, KSMETHODSETID_BdaChangeSync


BdaInitFilter

The BdaInitFilter function initializes the BDA filter context associated with a filter instance.

STDMETHODIMP_(NTSTATUS)
  BdaInitFilter(
    IN PKSFILTER  pKSFilter,
    IN const BDA_FILTER_TEMPLATE  *pBdaFilterTemplate
    );

Parameters

pKSFilter
Points to the filter in which to initialize the BDA filter context.
pBdaFilterTemplate
Points to a BDA_FILTER_TEMPLATE structure that describes the filter template for the BDA device. To determine topology for and configure the initialized filter, the network provider uses information referenced in this BDA_FILTER_TEMPLATE structure.

Return Value

Returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

A BDA minidriver calls the BdaInitFilter function to initialize an instance of a filter using a specific BDA filter template and a filter factory that was previously created through a call to the BdaCreateFilterFactory function. The BDA minidriver can subsequently use this filter instance in calls to other BDA support functions, such as, BdaCreatePin.

When a BDA minidriver calls BdaInitFilter, the BDA support driver (Bdasup.sys) creates its own BDA filter context. This BDA filter context is hidden from the BDA minidriver. However, when required, the BDA support driver can access this BDA filter context. The BDA support driver adds a pointer to this BDA filter context to the object bag for the associated KSFILTER object. When the associated KSFILTER object is destroyed, AVStream requests that the BDA support driver delete this BDA filter context from the object bag. In this way, the BDA support driver can destroy this BDA filter context without requiring intervention by the BDA minidriver.

A BDA minidriver calls BdaInitFilter at IRQL = PASSIVE_LEVEL.

BdaInitFilter is available on Windows® XP and later. BdaInitFilter is available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.

See Also

BdaCreateFilterFactory, BdaCreatePin, BDA_FILTER_TEMPLATE, KSFILTER


BdaMethodCreatePin

The BdaMethodCreatePin function creates a pin factory.

STDMETHODIMP_(NTSTATUS)
  BdaMethodCreatePin(
    IN PIRP  Irp,
    IN KSMETHOD  *pKSMethod,
    OUT ULONG  *pulPinFactoryID
    );

Parameters

Irp
Points to the IRP for the request to create a pin factory.
pKSMethod
Points to a KSMETHOD structure that describes the method and request type of a method request.
pulPinFactoryID
Points to a variable that receives the identifier of the pin factory.

Return Value

Returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

A BDA minidriver calls the BdaMethodCreatePin function to create a pin factory after the minidriver receives a KSMETHOD_BDA_CREATE_PIN_FACTORY request of the KSMETHODSETID_BdaDeviceConfiguration method set from the network provider. Most BDA minidrivers can define dispatch and filter-automation tables so that those minidrivers dispatch the BdaMethodCreatePin function directly. See Defining Automation Tables and Configuring a BDA Filter for more information.

If a BDA minidriver must create a pin without relying on the network provider, the BDA minidriver should call the BdaCreatePin function.

A BDA minidriver calls BdaMethodCreatePin at IRQL = PASSIVE_LEVEL.

BdaMethodCreatePin is available on Windows® XP and later. BdaMethodCreatePin is available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.

See Also

BdaCreatePin, BdaMethodDeletePin, KSMETHOD, KSMETHODSETID_BdaDeviceConfiguration


BdaMethodCreateTopology

The BdaMethodCreateTopology function creates a template topology between two pins of a filter.

STDMETHODIMP_(NTSTATUS)
  BdaMethodCreateTopology(
    IN PIRP  Irp,
    IN KSMETHOD  *pKSMethod,
    OPTIONAL PVOID  pvIgnored
    );

Parameters

Irp
Points to the IRP for the request to create topology.
pKSMethod
Points to a KSMETHOD structure that describes the method and request type of a method request.
pvIgnored
Points to a buffer that is ignored.

Return Value

Returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

A BDA minidriver calls the BdaMethodCreateTopology function to create the template topology between two filter pins after the minidriver receives a KSMETHOD_BDA_CREATE_TOPOLOGY request of the KSMETHODSETID_BdaDeviceConfiguration method set from the network provider. Most BDA minidrivers can define dispatch and filter-automation tables so that those minidrivers dispatch the BdaMethodCreateTopology function directly. Some BDA minidrivers must intercept this request rather than dispatch it directly. These mindrivers must obtain a pointer to the BDA filter from the passed IRP before calling BdaMethodCreateTopology so that they can use the filter to keep track of associated pins. These mindrivers can then send instructions to the hardware when connecting particular pin types. See Defining Automation Tables and Configuring a BDA Filter for more information.

If a BDA minidriver must create the template topology between two filter pins without relying on the network provider, the BDA minidriver should call the BdaCreateTopology function.

A BDA minidriver calls BdaMethodCreateTopology at IRQL = PASSIVE_LEVEL.

BdaMethodCreateTopology is available on Windows® XP and later. BdaMethodCreateTopology is available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.

See Also

BdaCreateTopology, KSMETHOD, KSMETHODSETID_BdaDeviceConfiguration


BdaMethodDeletePin

The BdaMethodDeletePin function deletes a pin factory.

STDMETHODIMP_(NTSTATUS)
  BdaMethodDeletePin(
    IN PIRP  Irp,
    IN KSMETHOD  *pKSMethod,
    OPTIONAL PVOID  pvIgnored
    );

Parameters

Irp
Points to the IRP for the request to delete a pin factory.
pKSMethod
Points to a KSMETHOD structure that describes the method and request type of a method request.
pvIgnored
Points to a buffer that is ignored.

Return Value

Returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

A BDA minidriver calls the BdaMethodDeletePin function to delete a pin factory after the minidriver receives a KSMETHOD_BDA_DELETE_PIN_FACTORY request of the KSMETHODSETID_BdaDeviceConfiguration method set from the network provider. Most BDA minidrivers can define dispatch and filter-automation tables so that those minidrivers dispatch the BdaMethodDeletePin function directly. See Defining Automation Tables and Configuring a BDA Filter for more information.

If a BDA minidriver must delete a pin without relying on the network provider, the BDA minidriver should call the BdaDeletePin function.

A BDA minidriver calls BdaMethodDeletePin at IRQL = PASSIVE_LEVEL.

BdaMethodDeletePin is available on Windows® XP and later. BdaMethodDeletePin is available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.

See Also

BdaDeletePin, BdaMethodCreatePin, KSMETHOD, KSMETHODSETID_BdaDeviceConfiguration


BdaPropertyGetControllingPinId

The BdaPropertyGetControllingPinId function retrieves the identifier of a pin on which to control the properties, methods, and events of a specific node.

STDMETHODIMP_(NTSTATUS)
  BdaPropertyGetControllingPinId(
    IN PIRP  Irp,
    IN KSP_BDA_NODE_PIN  *pProperty,
    OUT ULONG  *pulControllingPinId
    );

Parameters

Irp
Points to the IRP for the request to retrieve the controlling pin for a node.
pProperty
Points to a KSP_BDA_NODE_PIN structure that describes the property and request type of the property request to retrieve the controlling pin for a node.
pulControllingPinId
Points to a variable that receives the identifier of the controlling pin for a node.

Return Value

Returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

A BDA minidriver calls the BdaPropertyGetControllingPinId function to retrieve the identifier of the controlling pin for a node after the minidriver receives a KSPROPERTY_BDA_CONTROLLING_PIN_ID request of the KSPROPSETID_BdaTopology property set from the network provider. Most BDA minidrivers can define dispatch and filter-automation tables so that those minidrivers dispatch the BdaPropertyGetControllingPinId function directly. See Defining Automation Tables and Determining BDA Device Topology for more information.

A BDA minidriver calls BdaPropertyGetControllingPinId at IRQL = PASSIVE_LEVEL.

BdaPropertyGetControllingPinId is available on Windows® XP and later. BdaPropertyGetControllingPinId is available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.

See Also

KSP_BDA_NODE_PIN, KSPROPSETID_BdaTopology


BdaPropertyGetPinControl

The BdaPropertyGetPinControl function retrieves either the identifier or type of a pin.

STDMETHODIMP_(NTSTATUS)
  BdaPropertyGetPinControl(
    IN PIRP  Irp,
    IN KSPROPERTY  *pKSProperty,
    OUT ULONG  *pulProperty
    );

Parameters

Irp
Points to the IRP for the request to retrieve pin information.
pKSProperty
Points to a KSPROPERTY structure that describes the property and request type of the property request.
pulProperty
Points to a variable that receives either the identifier or type of a pin.

Return Value

Returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

A BDA minidriver calls the BdaPropertyGetPinControl function to retrieve either the identifier or type of a pin after the minidriver receives either a KSPROPERTY_BDA_PIN_ID or KSPROPERTY_BDA_PIN_TYPE request of the KSPROPSETID_BdaPinControl property set. Most BDA minidrivers can define pin-automation tables so that those minidrivers dispatch the BdaPropertyGetPinControl function directly.

A BDA minidriver calls BdaPropertyGetPinControl at IRQL = PASSIVE_LEVEL.

BdaPropertyGetPinControl is available on Windows® XP and later. BdaPropertyGetPinControl is available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.

See Also

KSPROPERTY, KSPROPSETID_BdaPinControl


BdaPropertyNodeDescriptors

The BdaPropertyNodeDescriptors function retrieves a list of nodes in a template topology.

STDMETHODIMP_(NTSTATUS)
  BdaPropertyNodeDescriptors(
    IN PIRP  Irp,
    IN KSPROPERTY  *pKSProperty,
    OUT GUID  *pguidProperty
    );

Parameters

Irp
Points to the IRP for the request to retrieve the list of nodes.
pKSProperty
Points to a KSPROPERTY structure that describes the property and request type of the property request.
pguidProperty
Points to an array that receives the list of GUIDs for the nodes in a template topology.

Return Value

Returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

A BDA minidriver calls the BdaPropertyNodeDescriptors function to retrieve the list of nodes after the minidriver receives a KSPROPERTY_BDA_NODE_DESCRIPTORS request of the KSPROPSETID_BdaTopology property set from the network provider. Most BDA minidrivers can define dispatch and filter-automation tables so that those minidrivers dispatch the BdaPropertyNodeDescriptors function directly. See Defining Automation Tables and Determining BDA Device Topology for more information.

For a list of BDA nodes that are available to create in a template topology, see BDA Node Category GUIDs.

A BDA minidriver calls BdaPropertyNodeDescriptors at IRQL = PASSIVE_LEVEL.

BdaPropertyNodeDescriptors is available on Windows® XP and later. BdaPropertyNodeDescriptors is available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.

See Also

KSPROPERTY, KSPROPSETID_BdaTopology


BdaPropertyNodeEvents

The BdaPropertyNodeEvents function retrieves a list of events that a node supports.

STDMETHODIMP_(NTSTATUS)
  BdaPropertyNodeEvents(
    IN PIRP  Irp,
    IN KSPROPERTY  *pKSProperty,
    OUT GUID  *pguidProperty
    );

Parameters

Irp
Points to the IRP for the request to retrieve the list of events for a node.
pKSProperty
Points to a KSPROPERTY structure that describes the property and request type of the property request.
pguidProperty
Points to an array that receives the list of GUIDs for the events supported by a node.

Return Value

Returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

A BDA minidriver calls the BdaPropertyNodeEvents function to retrieve the list of events for a node after the minidriver receives a KSPROPERTY_BDA_NODE_EVENTS request of the KSPROPSETID_BdaTopology property set from the network provider. Most BDA minidrivers can define dispatch and filter-automation tables so that those minidrivers dispatch the BdaPropertyNodeEvents function directly. See Defining Automation Tables and Determining BDA Device Topology for more information.

A BDA minidriver calls BdaPropertyNodeEvents at IRQL = PASSIVE_LEVEL.

BdaPropertyNodeEvents is available on Windows® XP and later. BdaPropertyNodeEvents is available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.

See Also

KSPROPERTY, KSPROPSETID_BdaTopology


BdaPropertyNodeMethods

The BdaPropertyNodeMethods function retrieves a list of methods that a node supports.

STDMETHODIMP_(NTSTATUS)
  BdaPropertyNodeMethods(
    IN PIRP  Irp,
    IN KSPROPERTY  *pKSProperty,
    OUT GUID  *pguidProperty
    );

Parameters

Irp
Points to the IRP for the request to retrieve the list of methods for a node.
pKSProperty
Points to a KSPROPERTY structure that describes the property and request type of the property request.
pguidProperty
Points to an array that receives the list of GUIDs for the methods supported by a node.

Return Value

Returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

A BDA minidriver calls the BdaPropertyNodeMethods function to retrieve the list of methods for a node after the minidriver receives a KSPROPERTY_BDA_NODE_METHODS request of the KSPROPSETID_BdaTopology property set from the network provider. Most BDA minidrivers can define dispatch and filter-automation tables so that those minidrivers dispatch the BdaPropertyNodeMethods function directly. See Defining Automation Tables and Determining BDA Device Topology for more information.

A BDA minidriver calls BdaPropertyNodeMethods at IRQL = PASSIVE_LEVEL.

BdaPropertyNodeMethods is available on Windows® XP and later. BdaPropertyNodeMethods is available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.

See Also

KSPROPERTY, KSPROPSETID_BdaTopology


BdaPropertyNodeProperties

The BdaPropertyNodeProperties function retrieves a list of properties that a node supports.

STDMETHODIMP_(NTSTATUS)
  BdaPropertyNodeProperties(
    IN PIRP  Irp,
    IN KSPROPERTY  *pKSProperty,
    OUT GUID  *pguidProperty
    );

Parameters

Irp
Points to the IRP for the request to retrieve the list of properties for a node.
pKSProperty
Points to a KSPROPERTY structure that describes the property and request type of the property request.
pguidProperty
Points to an array that receives the list of GUIDs for the properties supported by a node.

Return Value

Returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

A BDA minidriver calls the BdaPropertyNodeProperties function to retrieve the list of properties for a node after the minidriver receives a KSPROPERTY_BDA_NODE_PROPERTIES request of the KSPROPSETID_BdaTopology property set from the network provider. Most BDA minidrivers can define dispatch and filter-automation tables so that those minidrivers dispatch the BdaPropertyNodeProperties function directly. See Defining Automation Tables and Determining BDA Device Topology for more information.

A BDA minidriver calls BdaPropertyNodeProperties at IRQL = PASSIVE_LEVEL.

BdaPropertyNodeProperties is available on Windows® XP and later. BdaPropertyNodeProperties is available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.

See Also

KSPROPERTY, KSPROPSETID_BdaTopology


BdaPropertyNodeTypes

The BdaPropertyNodeTypes function retrieves a list of node types in a template topology.

STDMETHODIMP_(NTSTATUS)
  BdaPropertyNodeTypes(
    IN PIRP  Irp,
    IN KSPROPERTY  *pKSProperty,
    OUT ULONG  *pulProperty
    );

Parameters

Irp
Points to the IRP for the request to retrieve the list of node types.
pKSProperty
Points to a KSPROPERTY structure that describes the property and request type of the property request.
pulProperty
Points to an array that receives the list of node types.

Return Value

Returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

A BDA minidriver calls the BdaPropertyNodeTypes function to retrieve the list of node types after the minidriver receives a KSPROPERTY_BDA_NODE_TYPES request of the KSPROPSETID_BdaTopology property set from the network provider. Most BDA minidrivers can define dispatch and filter-automation tables so that those minidrivers dispatch the BdaPropertyNodeTypes function directly. See Defining Automation Tables and Determining BDA Device Topology for more information.

A BDA minidriver calls BdaPropertyNodeTypes at IRQL = PASSIVE_LEVEL.

BdaPropertyNodeTypes is available on Windows® XP and later. BdaPropertyNodeTypes is available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.

See Also

KSPROPERTY, KSPROPSETID_BdaTopology


BdaPropertyPinTypes

The BdaPropertyPinTypes function retrieves a list of pin types in a template topology.

STDMETHODIMP_(NTSTATUS)
  BdaPropertyPinTypes(
    IN PIRP  Irp,
    IN KSPROPERTY  *pKSProperty,
    OUT ULONG  *pulProperty
    );

Parameters

Irp
Points to the IRP for the request to retrieve list of pin types.
pKSProperty
Points to a KSPROPERTY structure that describes the property and request type of the property request.
pulProperty
Points to an array that receives the list of pin types.

Return Value

Returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

A BDA minidriver calls the BdaPropertyPinTypes function to retrieve the list of pin types after the minidriver receives a KSPROPERTY_BDA_PIN_TYPES request of the KSPROPSETID_BdaTopology property set from the network provider. Most BDA minidrivers can define dispatch and filter-automation tables so that those minidrivers dispatch the BdaPropertyPinTypes function directly. See Defining Automation Tables and Determining BDA Device Topology for more information.

A BDA minidriver calls BdaPropertyPinTypes at IRQL = PASSIVE_LEVEL.

BdaPropertyPinTypes is available on Windows® XP and later. BdaPropertyPinTypes is available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.

See Also

KSPROPERTY, KSPROPSETID_BdaTopology


BdaPropertyTemplateConnections

The BdaPropertyTemplateConnections function retrieves a list of connections that describe how pin types and node types are connected in a template topology.

STDMETHODIMP_(NTSTATUS)
  BdaPropertyTemplateConnections(
    IN PIRP  Irp,
    IN KSPROPERTY  *pKSProperty,
    OUT KSTOPOLOGY_CONNECTION  *pConnectionProperty
    );

Parameters

Irp
Points to the IRP for the request to retrieve list of connections.
pKSProperty
Points to a KSPROPERTY structure that describes the property and request type of the property request.
pConnectionProperty
Points to an array that receives the list of KSTOPOLOGY_CONNECTION structures that describe the connections in a template topology.

Return Value

Returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

A BDA minidriver calls the BdaPropertyTemplateConnections function to retrieve the list of template connections after the minidriver receives a KSPROPERTY_BDA_TEMPLATE_CONNECTIONS request of the KSPROPSETID_BdaTopology property set from the network provider. Most BDA minidrivers can define dispatch and filter-automation tables so that those minidrivers dispatch the BdaPropertyTemplateConnections function directly. See Defining Automation Tables and Determining BDA Device Topology for more information.

The BDA minidriver provided a list of connections to the BDA support library in an array of KSTOPOLOGY_CONNECTION structures when the BDA minidriver passed the BDA filter template (BDA_FILTER_TEMPLATE) in BdaCreateFilterFactory and BdaInitFilter function calls. This array is a representation of all the possible connections between node and pin types that can be made within the filter or between the filter and adjoining filters. The BdaPropertyTemplateConnections function returns this array.

A BDA minidriver calls BdaPropertyTemplateConnections at IRQL = PASSIVE_LEVEL.

BdaPropertyTemplateConnections is available on Windows® XP and later. BdaPropertyTemplateConnections is available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.

See Also

BdaCreateFilterFactory, BDA_FILTER_TEMPLATE, BdaInitFilter, KSPROPERTY, KSPROPSETID_BdaTopology, KSTOPOLOGY_CONNECTION


BdaStartChanges

The BdaStartChanges function initiates the setting of new BDA topology changes.

STDMETHODIMP_(NTSTATUS)
  BdaStartChanges(
    IN PIRP  Irp
    );

Parameters

Irp
Points to the IRP for the request to initiate changes.

Return Value

Returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

A BDA minidriver calls the BdaStartChanges function to initiate the setting of new BDA topology changes after the minidriver receives a KSMETHOD_BDA_START_CHANGES request of the KSMETHODSETID_BdaChangeSync method set from the network provider. BDA minidrivers define dispatch and filter-automation tables so that those minidrivers either dispatch the BdaStartChanges function directly or intercept this request using an internal method, which then calls the BdaStartChanges function. For example, BDA minidrivers that intercept this request can obtain a pointer to the BDA filter from the passed IRP so that they can subsequently reset pending filter resources to the new requirements and set the change state of the filter to BDA_CHANGES_COMPLETE. See Defining Automation Tables and Changing BDA Filter Properties for more information.

Calling the BdaStartChanges function causes any previously requested topology changes that have not yet been committed to be ignored.

A BDA minidriver calls BdaStartChanges at IRQL = PASSIVE_LEVEL.

BdaStartChanges is available on Windows® XP and later. BdaStartChanges is available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.

See Also

BDA_CHANGE_STATE, BdaCommitChanges, KSMETHODSETID_BdaChangeSync


BdaUninitFilter

The BdaUninitFilter function removes the BDA filter context from the associated filter instance.

STDMETHODIMP_(NTSTATUS)
  BdaUninitFilter(
    IN PKSFILTER  pKSFilter
    );

Parameters

pKSFilter
Points to the filter from which to remove the BDA filter context.

Return Value

Returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

The BdaUninitFilter function exists only to support legacy drivers and is, therefore, obsolete. That is, new BDA minidriver implementations should not call BdaUninitFilter.

In Windows® XP and later, the BDA support driver (Bdasup.sys) automatically handles removing the BDA filter context associated with a filter instance. When a BDA minidriver calls BdaInitFilter, the BDA support driver (Bdasup.sys) creates its own BDA filter context. This BDA filter context is hidden from the BDA minidriver. However, when required, the BDA support driver can access this BDA filter context. The BDA support driver adds a pointer to this BDA filter context to the object bag for the associated KSFILTER object. When the associated KSFILTER object is destroyed, AVStream requests that the BDA support driver delete this BDA filter context from the object bag. In this way, the BDA support driver can destroy this BDA filter context without requiring intervention by the BDA minidriver.

A BDA minidriver calls BdaUninitFilter at IRQL = PASSIVE_LEVEL.

BdaUninitFilter is available on Windows® XP and later. BdaUninitFilter is available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.

See Also

BdaInitFilter, KSFILTER


BdaValidateNodeProperty

The BdaValidateNodeProperty function validates that a node property request is associated with a specific pin.

STDMETHODIMP_(NTSTATUS)
  BdaValidateNodeProperty(
    IN PIRP  Irp,
    IN KSPROPERTY  *pKSProperty
    );

Parameters

Irp
Points to the IRP for the request to validate that the current pin controls the node property at pKSProperty.
pKSProperty
Points to a KSPROPERTY structure that describes the property and request type of the property request.

Return Value

Returns STATUS_SUCCESS or an appropriate error code.

Headers

Declared in Bdasup.h. Include Bdasup.h.

Comments

A pin method in a BDA minidriver calls the BdaValidateNodeProperty function to validate that the pin controls a specific node property after the minidriver receives the node property request from the network provider. This node property request can be, for example, a KSPROPERTY_BDA_RF_TUNER_FREQUENCY request of the KSPROPSETID_BdaFrequencyFilter property set or a KSPROPERTY_BDA_AUTODEMODULATE_START request of the KSPROPSETID_BdaAutodemodulate property set. These property sets manipulate tuner and demodulator nodes. After calling BdaValidateNodeProperty, the minidriver must obtain a pointer to the BDA filter from the passed IRP so that the minidriver can perform an operation on the particular node.

A BDA minidriver calls BdaValidateNodeProperty at IRQL = PASSIVE_LEVEL.

BdaValidateNodeProperty is available on Windows® XP and later. BdaValidateNodeProperty is available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.

See Also

KSPROPERTY, KSPROPSETID_BdaAutodemodulate, KSPROPSETID_BdaFrequencyFilter


Broadcast Driver Architecture Property, Event, and Method Sets

This section documents the property, event, and method sets that a BDA minidriver implements. These sets are defined in bdamedia.h. The BDA minidriver can dispatch some of the properties and methods in these sets to default implementations in the BDA support library. For more information, see Broadcast Driver Architecture Minidrivers on how the minidriver can use the BDA support library of functions to provide default handling of these sets.

The following sections provide more information about the BDA property, event, and method sets:

KSPROPSETID_BdaAutodemodulate
The BDA autodemodulate property set controls signal demodulator nodes that can automatically determine the characteristics of the modulated signal and demodulate.
KSPROPSETID_BdaCA
The BDA conditional access property set queries Entitlement Control Message (ECM) map nodes for either status or user interface (UI) to display.
KSEVENTSETID_BdaCAEvent
The BDA conditional access event set notifies conditional access (CA) plugins either of changes in status or about the existence of UI to retrieve and display.
KSMETHODSETID_BdaChangeSync
The BDA change sync method set commits multiple changes on a filter or its pins and nodes all at once.
KSMETHODSETID_BdaDeviceConfiguration
The BDA device configuration method set configures the actual topologies of connected filters.
KSPROPSETID_BdaDigitalDemodulator
The BDA digital demodulator property set controls signal demodulator nodes that cannot automatically determine the characteristics of the modulated signal.
KSPROPSETID_BdaFrequencyFilter
The BDA frequency filter property set controls the RF tuner node in a receiver topology.
KSPROPSETID_BdaLNBInfo
The BDA low-noise block (LNB) property set provides an RF tuner with information about a satellite dish's LNB device.
KSPROPSETID_BdaNullTransform
The BDA null transform property set informs a node to pass a signal through unchanged.
KSPROPSETID_BdaPIDFilter
The BDA packet identifier (PID) filter property set controls PID filter nodes. A PID filter node filters out unwanted streams from the received broadcast stream.
KSPROPSETID_BdaPinControl
The BDA pin control property set retrieves the properties of a pin from that pin.
KSPROPSETID_BdaPinEvent
The BDA pin event set notifies other filters or plugins of events related to a pin.
KSPROPSETID_BdaSignalStats
The BDA signal statistics property set retrieves signal statistics from a control node or a pin. To get signal statistics from a pin, set the NodeId member of the KSP_NODE structure to –1.
KSPROPSETID_BdaTableSection
The BDA table section property set provides a table section to a node to use when delivering data on the node's output.
KSPROPSETID_BdaTopology
The BDA topology property set retrieves the node capabilities and connections within a filter.
KSPROPSETID_BdaVoidTransform
The BDA void transform property set controls when a node starts and stops operating.

Comments

The BDA property, event, and method sets are available on Windows® XP and later. These sets are available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.


KSPROPSETID_BdaAutodemodulate

KSPROPSETID_BdaAutodemodulate is the BDA autodemodulate property set. It is used to control signal demodulator nodes that can automatically determine the characteristics of the modulated signal and demodulate.

The following properties are available:

KSPROPERTY_BDA_AUTODEMODULATE_START
Informs the demodulator node that, when it is in pause or run state, it should attempt to automatically determine the modulation parameters and demodulate the signal.
KSPROPERTY_BDA_AUTODEMODULATE_STOP
Informs the demodulator node that it should stop trying to automatically demodulate the signal.

Comments

KSPROPSETID_BdaAutodemodulate is also used for demodulator nodes, such as the 8VSB demodulator node which only support one configuration of modulation parameters. For these types of nodes, the demodulator is not informed to set specific values such as Inner and Outer forward error correction (FEC) method.


KSPROPERTY_BDA_AUTODEMODULATE_START

Clients use KSPROPERTY_BDA_AUTODEMODULATE_START to automatically determine the modulation parameters of a demodulator node and demodulate the signal.

Specifying This Property

KSP_NODE

Property Data

None

See Also

KSP_NODE


KSPROPERTY_BDA_AUTODEMODULATE_STOP

Clients use KSPROPERTY_BDA_AUTODEMODULATE_STOP to stop demodulating the signal streaming into a demodulator node.

Specifying This Property

KSP_NODE

Property Data

None

See Also

KSP_NODE


KSPROPSETID_BdaCA

KSPROPSETID_BdaCA is the BDA conditional access (CA) property set. It is used to query Entitlement Control Message (ECM) map nodes for status of those nodes and for status of associated CA modules and smart card readers. This property set can also query for user interface (UI) that CA plugins can display and control access to programs processed through an ECM map node.

The following properties are available:

KSPROPERTY_BDA_ECM_MAP_STATUS
Returns status on an ECM map node.
KSPROPERTY_BDA_CA_MODULE_STATUS
Returns status on the CA module associated with an ECM map node.
KSPROPERTY_BDA_CA_SMART_CARD_STATUS
Returns status on the smart card reader associated with an ECM map node.
KSPROPERTY_BDA_CA_MODULE_UI
Returns UI that a CA plugin can display.
KSPROPERTY_BDA_CA_SET_PROGRAM_PIDS
Sets the list of packet identifiers in a particular program.
KSPROPERTY_BDA_CA_REMOVE_PROGRAM
Prevents access to a specific program.

Comments

Properties in this property set correspond to events in the KSEVENTSETID_BdaCAEvent event set. BDA minidrivers signal events in this event set to notify CA plugins. Those CA plugins then query corresponding properties in KSPROPSETID_BdaCA. BDA minidrivers signal these events either whenever a significant status change occurs or to interact with a user. BDA minidrivers interact with a user, for example, to present a message to the user or to negotiate a transaction with a user. A significant status change is, for example, when a user removes a smart card from the smart card reader.

See Also

KSEVENTSETID_BdaCAEvent


KSPROPERTY_BDA_CA_MODULE_STATUS

Clients use KSPROPERTY_BDA_CA_MODULE_STATUS to determine status on the CA module associated with an ECM map node.

Specifying This Property

KSP_NODE

Property Data

ULONG, representing the CA module status.

See Also

KSEVENT_BDA_CA_MODULE_STATUS_CHANGED, KSP_NODE


KSPROPERTY_BDA_CA_MODULE_UI

Clients use KSPROPERTY_BDA_CA_MODULE_UI to retrieve interface data that a CA plugin can display to users.

Specifying This Property

KSP_NODE

Property Data

A BDA_CA_MODULE_UI structure that contains the user interface (UI) data.

See Also

BDA_CA_MODULE_UI, KSEVENT_BDA_CA_MODULE_UI_REQUESTED, KSP_NODE


KSPROPERTY_BDA_CA_REMOVE_PROGRAM

Clients use KSPROPERTY_BDA_CA_REMOVE_PROGRAM to prevent access to a specific program.

Specifying This Property

KSP_NODE

Property Data

ULONG, representing the program to make inaccessible.

See Also

KSEVENT_BDA_PROGRAM_FLOW_STATUS_CHANGED, KSP_NODE


KSPROPERTY_BDA_CA_SET_PROGRAM_PIDS

Clients use KSPROPERTY_BDA_CA_SET_PROGRAM_PIDS to set the list of packet identifiers in a particular program.

Specifying This Property

KSP_NODE

Property Data

A BDA_PROGRAM_PID_LIST structure that contains the list of packet identifiers for a specified program.

See Also

BDA_PROGRAM_PID_LIST, KSEVENT_BDA_PROGRAM_FLOW_STATUS_CHANGED, KSP_NODE


KSPROPERTY_BDA_CA_SMART_CARD_STATUS

Clients use KSPROPERTY_BDA_CA_SMART_CARD_STATUS to determine status on the smart card reader associated with an ECM map node.

Specifying This Property

KSP_NODE

Property Data

ULONG, representing the smart card reader status.

See Also

KSEVENT_BDA_CA_SMART_CARD_STATUS_CHANGED, KSP_NODE


KSPROPERTY_BDA_ECM_MAP_STATUS

Clients use KSPROPERTY_BDA_ECM_MAP_STATUS to determine status on an ECM map node.

Specifying This Property

KSP_NODE

Property Data

ULONG, representing the ECM map node status.

See Also

KSEVENT_BDA_PROGRAM_FLOW_STATUS_CHANGED, KSP_NODE


KSEVENTSETID_BdaCAEvent

KSEVENTSETID_BdaCAEvent is the BDA conditional access (CA) event set. It is used to notify CA plugins of changes in status of CA modules and smart card readers associated with Entitlement Control Message (ECM) map nodes. This event set can also notify CA plugins about the existence of user interface (UI) that those plugins should retrieve and display and about changes in program information.

The following events are available:

KSEVENT_BDA_PROGRAM_FLOW_STATUS_CHANGED
Notifies of a status change in program information.
KSEVENT_BDA_CA_MODULE_STATUS_CHANGED
Notifies of a status change on the CA module associated with an ECM map node.
KSEVENT_BDA_CA_SMART_CARD_STATUS_CHANGED
Notifies of a status change on the smart card reader associated with an ECM map node.
KSEVENT_BDA_CA_MODULE_UI_REQUESTED
Notifies of the existence of UI that a CA plugin can retrieve and display.

Comments

Each event in this event set corresponds to a property in the KSPROPSETID_BdaCA property set. CA plugins request to be notified when events in a BDA component occur. BDA minidrivers signal events in this event set to notify CA plugins. Those CA plugins then query corresponding properties in KSPROPSETID_BdaCA. BDA minidrivers signal these events either whenever a significant status change occurs or to interact with a user. BDA minidrivers interact with a user, for example, to present a message to the user or to negotiate a transaction with a user. A significant status change is, for example, when a user removes a smart card from the smart card reader.

See Also

KSPROPSETID_BdaCA


KSEVENT_BDA_CA_MODULE_STATUS_CHANGED

Clients use KSEVENT_BDA_CA_MODULE_STATUS_CHANGED to request notification when status on the CA module associated with an ECM map node changes.

Specifying This Event

KSEVENT

Event Data

A KSEVENTDATA structure that describes how to notify about the event.

Comments

For information about a KSEVENTDATA structure, see Enable Event.

See Also

KSEVENT, KSPROPERTY_BDA_CA_MODULE_STATUS


KSEVENT_BDA_CA_MODULE_UI_REQUESTED

Clients use KSEVENT_BDA_CA_MODULE_UI_REQUESTED to request notification when interface data is available to retrieve and display to users.

Specifying This Event

KSEVENT

Event Data

A KSEVENTDATA structure that describes how to notify about the event.

Comments

For information about a KSEVENTDATA structure, see Enable Event.

See Also

KSEVENT, KSPROPERTY_BDA_CA_MODULE_UI


KSEVENT_BDA_CA_SMART_CARD_STATUS_CHANGED

Clients use KSEVENT_BDA_CA_SMART_CARD_STATUS_CHANGED to request notification when status on the smart card reader associated with an ECM map node changes.

Specifying This Event

KSEVENT

Event Data

A KSEVENTDATA structure that describes how to notify about the event.

Comments

For information about a KSEVENTDATA structure, see Enable Event.

See Also

KSEVENT, KSPROPERTY_BDA_CA_SMART_CARD_STATUS


KSEVENT_BDA_PROGRAM_FLOW_STATUS_CHANGED

Clients use KSEVENT_BDA_PROGRAM_FLOW_STATUS_CHANGED to request notification when status on program information changes.

Specifying This Event

KSEVENT

Event Data

A KSEVENTDATA structure that describes how to notify about the event.

Comments

For information about a KSEVENTDATA structure, see Enable Event.

See Also

KSEVENT, KSPROPERTY_BDA_CA_REMOVE_PROGRAM, KSPROPERTY_BDA_CA_SET_PROGRAM_PIDS, KSPROPERTY_BDA_ECM_MAP_STATUS


KSMETHODSETID_BdaChangeSync

KSMETHODSETID_BdaChangeSync is the BDA change sync method set. It is used to coordinate a list of property requests on a filter and its pins and nodes.

The following methods are available:

KSMETHOD_BDA_START_CHANGES
Resets a change list and starts keeping track of a new set of changes.
KSMETHOD_BDA_CHECK_CHANGES
Determines whether a list of requested changes will work.
KSMETHOD_BDA_COMMIT_CHANGES
Commits a list of requested changes.
KSMETHOD_BDA_GET_CHANGE_STATE
Determines the current change state for a filter.

Comments

This method set is implemented on filters. The network provider filter can use this method set to begin a list of changes, make the changes, then commit them all at once.


KSMETHOD_BDA_CHECK_CHANGES

Clients use KSMETHOD_BDA_CHECK_CHANGES to determine whether a list of requested changes will work.

Specifying This Method

KSMETHOD with Flags member set to KSMETHOD_TYPE_NONE.

Method Data

None

Comments

Before committing a list of changes, the network provider makes a KSMETHOD_BDA_CHECK_CHANGES request to determine whether the requested changes will work. The minidriver may reserve resources when this request is made, to guarantee that the resources are available.

See Also

BdaCheckChanges, KSMETHOD


KSMETHOD_BDA_COMMIT_CHANGES

Clients use KSMETHOD_BDA_COMMIT_CHANGES to commit a list of requested changes.

Specifying This Method

KSMETHOD with Flags member set to KSMETHOD_TYPE_NONE.

Method Data

None

Comments

When the network provider makes a KSMETHOD_BDA_COMMIT_CHANGES request, the list of changes are committed on the underlying filter, at which point the filter resets its state and a new cycle can begin.

See Also

BdaCommitChanges, KSMETHOD


KSMETHOD_BDA_GET_CHANGE_STATE

Clients use KSMETHOD_BDA_GET_CHANGE_STATE to determine the current change state for a filter.

Specifying This Method

KSMETHOD with Flags member set to KSMETHOD_TYPE_READ.

Method Data

Value from the BDA_CHANGE_STATE enumeration that identifies the current change state for the filter.

See Also

BDA_CHANGE_STATE, BdaGetChangeState, KSMETHOD


KSMETHOD_BDA_START_CHANGES

Clients use KSMETHOD_BDA_START_CHANGES to reset a change list.

Specifying This Method

KSMETHOD with Flags member set to KSMETHOD_TYPE_NONE.

Method Data

None

Comments

Before the network provider begins to make changes, it makes a KSMETHOD_BDA_START_CHANGES request, which causes any existing change list that has not been committed to be discarded and informs the filter's pins and nodes to start keeping track of a new set of changes. The network provider then calls the necessary interface methods on the filter or its pins, but the methods are not actually called yet. If at any point the network provider determines that the changes will not work, it can call this method to clear out the list.

See Also

BdaStartChanges, KSMETHOD


KSMETHODSETID_BdaDeviceConfiguration

KSMETHODSETID_BdaDeviceConfiguration is the BDA device configuration method set. It is used to configure a filter for a filter graph.

The following methods are available:

KSMETHOD_BDA_CREATE_PIN_FACTORY
Triggers a call that creates a pin factory for the filter.
KSMETHOD_BDA_DELETE_PIN_FACTORY
Triggers a call that deletes a pin factory for the filter.
KSMETHOD_BDA_CREATE_TOPOLOGY
Creates a topology structure in Ring 3 that reflects the known connections in the filter.

Comments

This method set is implemented on filters.

If a BDA minidriver does not define it's own handlers for the methods in this method set, then the BDA support library will add default handlers when the BDA minidriver calls the BdaInitFilter function.

See Also

BdaInitFilter


KSMETHOD_BDA_CREATE_PIN_FACTORY

Clients use KSMETHOD_BDA_CREATE_PIN_FACTORY to create a pin factory for a filter.

Specifying This Method

KSM_PIN with the Flags member of the Method member set to KSMETHOD_TYPE_READ.

Method Data

ULONG, representing the identifier of the pin factory.

See Also

BdaMethodCreatePin, KSM_PIN


KSMETHOD_BDA_CREATE_TOPOLOGY

Clients use KSMETHOD_BDA_CREATE_TOPOLOGY to create a topology structure in Ring 3 that reflects the known connections in a filter.

Specifying This Method

KSMETHOD with the Flags member set to KSMETHOD_TYPE_WRITE.

Method Data

A KSMULTIPLE_ITEM structure, which is the header for a list of topology information.

See Also

BdaMethodCreateTopology, KSMETHOD, KSMULTIPLE_ITEM


KSMETHOD_BDA_DELETE_PIN_FACTORY

Clients use KSMETHOD_BDA_DELETE_PIN_FACTORY to delete a pin factory for a filter.

Specifying This Method

KSM_PIN with the Flags member of the Method member set to KSMETHOD_TYPE_NONE.

Method Data

None

Comments

Specifies the pin factory to delete in the PinId member of the KSM_PIN structure.

See Also

BdaMethodDeletePin, KSM_PIN


KSPROPSETID_BdaDigitalDemodulator

KSPROPSETID_BdaDigitalDemodulator is the BDA digital demodulator property set. It is used to control signal demodulator nodes that require specific values to be set.

The following properties are available:

KSPROPERTY_BDA_MODULATION_TYPE
Sets or retrieves the demodulator type such as QPSK or 8VSB.
KSPROPERTY_BDA_INNER_FEC_TYPE
Sets or retrieves the inner forward error correction (FEC) type.
KSPROPERTY_BDA_INNER_FEC_RATE
Sets or retrieves the binary convolution scheme used for the inner FEC.
KSPROPERTY_BDA_OUTER_FEC_TYPE
Sets or retrieves the outer FEC type.
KSPROPERTY_BDA_OUTER_FEC_RATE
Sets or retrieves the binary convolution coding scheme used for the outer FEC.
KSPROPERTY_BDA_SYMBOL_RATE
Sets or retrieves the symbol rate.
KSPROPERTY_BDA_SPECTRAL_INVERSION
Sets or retrieves the setting for spectral inversion.
KSPROPERTY_BDA_GUARD_INTERVAL
Sets or retrieves the setting for guard interval.
KSPROPERTY_BDA_TRANSMISSION_MODE
Sets or retrieves the setting for how broadcast signals are transmitted.

Comments

The KSPROPSETID_BdaDigitalDemodulator property set describes the properties of a DVB demodulator node. Use this property set instead of KSPROPSETID_BdaAutodemodulate if the demodulator requires specific values to be set.

See Also

KSPROPSETID_BdaAutodemodulate


KSPROPERTY_BDA_GUARD_INTERVAL

Clients use KSPROPERTY_BDA_GUARD_INTERVAL to control the setting for guard interval of a demodulator node.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the demodulator node.

Property Data

Value from the GuardInterval enumeration that identifies a setting for guard interval.

See Also

GuardInterval, KSP_NODE


KSPROPERTY_BDA_INNER_FEC_RATE

Clients use KSPROPERTY_BDA_INNER_FEC_RATE to control the binary convolution scheme used for the inner forward error correction (FEC) type of a demodulator node.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the demodulator node.

Property Data

Value from the BinaryConvolutionCodeRate enumeration that identifies a binary convolution scheme.

See Also

BinaryConvolutionCodeRate, KSP_NODE


KSPROPERTY_BDA_INNER_FEC_TYPE

Clients use KSPROPERTY_BDA_INNER_FEC_TYPE to control the inner forward error correction (FEC) type of a demodulator node.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the demodulator node.

Property Data

Value from the FECMethod enumeration that identifies an FEC type.

See Also

FECMethod, KSP_NODE


KSPROPERTY_BDA_MODULATION_TYPE

Clients use KSPROPERTY_BDA_MODULATION_TYPE to control the demodulator type such as QPSK or 8VSB.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the demodulator node.

Property Data

Value from the ModulationType enumeration that identifies a demodulator type.

See Also

KSP_NODE, ModulationType


KSPROPERTY_BDA_OUTER_FEC_RATE

Clients use KSPROPERTY_BDA_OUTER_FEC_RATE to control the binary convolution scheme used for the outer forward error correction (FEC) type of a demodulator node.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the demodulator node.

Property Data

Value from the BinaryConvolutionCodeRate enumeration that identifies a binary convolution scheme.

See Also

BinaryConvolutionCodeRate, KSP_NODE


KSPROPERTY_BDA_OUTER_FEC_TYPE

Clients use KSPROPERTY_BDA_OUTER_FEC_TYPE to control the outer forward error correction (FEC) type of a demodulator node.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the demodulator node.

Property Data

Value from the FECMethod enumeration that identifies an FEC type.

See Also

FECMethod, KSP_NODE


KSPROPERTY_BDA_SYMBOL_RATE

Clients use KSPROPERTY_BDA_SYMBOL_RATE to control the symbol rate of a demodulator node.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the demodulator node.

Property Data

ULONG, representing the symbol rate.

See Also

KSP_NODE


KSPROPERTY_BDA_SPECTRAL_INVERSION

Clients use KSPROPERTY_BDA_SPECTRAL_INVERSION to control the setting for spectral inversion of a demodulator node.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the demodulator node.

Property Data

Value from the SpectralInversion enumeration that identifies a setting for spectral inversion.

See Also

KSP_NODE, SpectralInversion


KSPROPERTY_BDA_TRANSMISSION_MODE

Clients use KSPROPERTY_BDA_TRANSMISSION_MODE to control the setting on a demodulator node for how broadcast signals are transmitted.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the demodulator node.

Property Data

Value from the TransmissionMode enumeration that identifies a setting for how broadcast signals are transmitted.

See Also

KSP_NODE, TransmissionMode


KSPROPSETID_BdaFrequencyFilter

KSPROPSETID_BdaFrequencyFilter is the BDA frequency filter property set. It is used to control the RF tuner node in a receiver topology.

The following properties are available:

KSPROPERTY_BDA_RF_TUNER_FREQUENCY
Informs the tuner node about the base frequency of the signal carrier. Multiply the base frequency by the value of the KSPROPERTY_BDA_RF_TUNER_FREQUENCY_MULTIPLIER property to obtain the actual frequency.
KSPROPERTY_BDA_RF_TUNER_POLARITY
Informs the tuner node about the polarization that is used on the transmitted signal.
KSPROPERTY_BDA_RF_TUNER_RANGE
Sets the tuner range.
KSPROPERTY_BDA_RF_TUNER_TRANSPONDER
Informs the tuner node of the appropriate transponder number.
KSPROPERTY_BDA_RF_TUNER_BANDWIDTH
Informs the tuner node of the bandwidth of the transmitted signal.
KSPROPERTY_BDA_RF_TUNER_FREQUENCY_MULTIPLIER
Informs the tuner node about the value with which to multiply the value of the KSPROPERTY_BDA_RF_TUNER_FREQUENCY property to obtain the actual frequency.

Comments

The KSPROPSETID_BdaFrequencyFilter property set is generic across almost all tuners. It is used to inform the tuner node how to tune the RF signal.


KSPROPERTY_BDA_RF_TUNER_BANDWIDTH

Clients use KSPROPERTY_BDA_RF_TUNER_BANDWIDTH to control the bandwidth setting of the tuner node.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the tuner node.

Property Data

ULONG, representing the bandwidth.

Comments

Bandwidth is the range of frequencies used to transmit a signal or group of interrelated signals. In other words, the amount of information that can be transmitted at one time.

Specifying the KSPROPERTY_BDA_RF_TUNER_BANDWIDTH property with:

  • BDA_CHAN_BANDWITH_NOT_SET (–1) indicates that the bandwidth is not set.
  • BDA_CHAN_BANDWITH_NOT_DEFINED (0) indicates that the bandwidth is not defined.

See Also

KSP_NODE


KSPROPERTY_BDA_RF_TUNER_FREQUENCY

Clients use KSPROPERTY_BDA_RF_TUNER_FREQUENCY along with KSPROPERTY_BDA_RF_TUNER_FREQUENCY_MULTIPLIER to control the frequency setting of the tuner node.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the tuner node.

Property Data

ULONG, representing the base frequency.

Comments

Specifying the KSPROPERTY_BDA_RF_TUNER_FREQUENCY property with:

  • BDA_FREQUENCY_NOT_SET (–1) indicates that the frequency is not set.
  • BDA_FREQUENCY_NOT_DEFINED (0) indicates that the frequency is not defined.

If the KSPROPERTY_BDA_RF_TUNER_FREQUENCY_MULTIPLIER property specified a multiplier of BDA_FREQUENCY_MULTIPLIER_NOT_SET (–1), BDA_FREQUENCY_MULTIPLIER_NOT_DEFINED (0), or 1, then the KSPROPERTY_BDA_RF_TUNER_FREQUENCY property specifies the frequency in Hertz. If KSPROPERTY_BDA_RF_TUNER_FREQUENCY_MULTIPLIER specified a multiplier of greater than 1, then the frequency in Hertz is obtained by multiplying the value of the KSPROPERTY_BDA_RF_TUNER_FREQUENCY property by the value of the KSPROPERTY_BDA_RF_TUNER_FREQUENCY_MULTIPLIER property.

See Also

KSP_NODE, KSPROPERTY_BDA_RF_TUNER_FREQUENCY_MULTIPLIER


KSPROPERTY_BDA_RF_TUNER_FREQUENCY_MULTIPLIER

Clients use KSPROPERTY_BDA_RF_TUNER_FREQUENCY_MULTIPLIER along with KSPROPERTY_BDA_RF_TUNER_FREQUENCY to control the frequency setting of the tuner node.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the tuner node.

Property Data

ULONG, representing the frequency multiplier.

Comments

If the KSPROPERTY_BDA_RF_TUNER_FREQUENCY_MULTIPLIER property specified a multiplier of BDA_FREQUENCY_MULTIPLIER_NOT_SET (–1), BDA_FREQUENCY_MULTIPLIER_NOT_DEFINED (0), or 1, then the KSPROPERTY_BDA_RF_TUNER_FREQUENCY property specifies the frequency in Hertz. If KSPROPERTY_BDA_RF_TUNER_FREQUENCY_MULTIPLIER specified a multiplier of greater than 1, then the frequency in Hertz is obtained by multiplying the value of the KSPROPERTY_BDA_RF_TUNER_FREQUENCY property by the value of the KSPROPERTY_BDA_RF_TUNER_FREQUENCY_MULTIPLIER property.

See Also

KSP_NODE, KSPROPERTY_BDA_RF_TUNER_FREQUENCY


KSPROPERTY_BDA_RF_TUNER_POLARITY

Clients use KSPROPERTY_BDA_RF_TUNER_POLARITY to control the polarity setting of the tuner node.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the tuner node.

Property Data

ULONG, representing the polarity of the transmitted signal.

Comments

For some transmissions, particularly satellite transmissions, the signal may be polarized. This property informs the tuner node about the polarization of the transmitted signal. The Polarization enumeration contains values that specify the polarity of the signal.

See Also

KSP_NODE, Polarization


KSPROPERTY_BDA_RF_TUNER_RANGE

Clients use KSPROPERTY_BDA_RF_TUNER_RANGE to control the tuner range, that is, the domain on which to find a particular carrier frequency.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the tuner node.

Property Data

ULONG, representing the tuner range.

Comments

Specifying the KSPROPERTY_BDA_RF_TUNER_RANGE property with:

  • BDA_RANGE_NOT_SET (–1) indicates that the tuner range is not set.
  • BDA_RANGE_NOT_DEFINED (0) indicates that the tuner range is not defined.

Some tuners control an external device, such as a multiswitch, that defines the domain on which to find a particular carrier frequency. This property sets the tuner range either to –1, meaning that tuner range is not used for the particular tuning space, or to a value that is specific to the tuning space.

See Also

KSP_NODE


KSPROPERTY_BDA_RF_TUNER_TRANSPONDER

Clients use KSPROPERTY_BDA_RF_TUNER_TRANSPONDER to inform the tuner node of the appropriate transponder number.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the tuner node.

Property Data

ULONG, representing the transponder number.

Comments

Some tuning spaces have all of the information about how to acquire a frequency imbedded in hardware. These tuning spaces specify a transponder number. This property informs the tuner node of this transponder number. The tuner hardware can then automatically determine the tuning characteristics needed to acquire the intermediate frequency. In this case, the other properties in the KSPROPSETID_BdaFrequencyFilter property set are set to –1.

See Also

KSP_NODE


KSPROPSETID_BdaLNBInfo

KSPROPSETID_BdaLNBInfo is the BDA low-noise block (LNB) information property set. It is used to provide an RF tuner with information about a satellite dish's LNB device.

The following properties are available:

KSPROPERTY_BDA_LNB_LOF_LOW_BAND
Informs the RF tuner node about the local oscillator frequency (LOF) that is used by the LNB for shifting the frequency of incoming low-band RF signals.
KSPROPERTY_BDA_LNB_LOF_HIGH_BAND
Informs the RF tuner node about the LOF that is used by the LNB for shifting the frequency of incoming high-band RF signals.
KSPROPERTY_BDA_LNB_SWITCH_FREQUENCY
Informs the RF tuner node about the frequency of incoming RF signals at which the tuner should inform the LNB device to switch from using low-band LOF to using high-band LOF or vice versa.

Comments

The LNB is the device at the focal point of a satellite dish. The LNB gathers the signal reflected by the dish and sends it to the RF tuner's LNB amplifier.

The KSPROPSETID_BdaLNBInfo property set communicates information about a satellite dish's LNB device to an RF tuner. When a client sends a KSPROPERTY_BDA_RF_TUNER_FREQUENCY request to tune an RF tuner to a specific frequency, the tuner can send, if required, control signals to the LNB device to adjust internal parameters according to the properties of the LNB.

See Also

KSPROPERTY_BDA_RF_TUNER_FREQUENCY


KSPROPERTY_BDA_LNB_LOF_HIGH_BAND

Clients use KSPROPERTY_BDA_LNB_LOF_HIGH_BAND to inform the RF tuner node about the local oscillator frequency (LOF) that is used by the low-noise block (LNB) device for shifting the frequency of incoming high-band RF signals.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the RF tuner node.

Property Data

ULONG, representing the LOF that is used by the LNB for high-band signals.

Comments

The LNB gathers the RF signal reflected by the satellite dish, shifts the frequency of the RF signal down by the high-band LOF amount, and sends the resulting signal to the RF tuner.

See Also

KSP_NODE


KSPROPERTY_BDA_LNB_LOF_LOW_BAND

Clients use KSPROPERTY_BDA_LNB_LOF_LOW_BAND to inform the RF tuner node about the local oscillator frequency (LOF) that is used by the low-noise block (LNB) device for shifting the frequency of incoming low-band RF signals.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the RF tuner node.

Property Data

ULONG, representing the LOF that is used by the LNB for low-band signals.

Comments

The LNB gathers the RF signal reflected by the satellite dish, shifts the frequency of the RF signal down by the low-band LOF amount, and sends the resulting signal to the RF tuner.

See Also

KSP_NODE


KSPROPERTY_BDA_LNB_SWITCH_FREQUENCY

Clients use KSPROPERTY_BDA_LNB_SWITCH_FREQUENCY to inform the RF tuner node about the frequency of incoming RF signals at which the tuner should inform the low-noise block (LNB) device to switch from using low-band local oscillator frequency (LOF) to using high-band LOF or vice versa when the LNB shifts the frequency of RF signals.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the RF tuner node.

Property Data

ULONG, representing the frequency of incoming RF signals at which the LNB should switch from using low-band LOF to using high-band LOF.

Comments

If a client sends a KSPROPERTY_BDA_RF_TUNER_FREQUENCY request to tune an RF tuner to a specific frequency and this frequency is greater than or equal to the switch frequency specified using KSPROPERTY_BDA_LNB_SWITCH_FREQUENCY, then the RF tuner should send a command to the LNB to switch to the high-band LOF. The RF tuner should then expect that the LNB device shifts the frequency of the incoming RF signal by the high-band LOF amount, which was specified using KSPROPERTY_BDA_LNB_LOF_HIGH_BAND.

Likewise, if a client sends a KSPROPERTY_BDA_RF_TUNER_FREQUENCY request to tune an RF tuner to a specific frequency and this frequency is less than the switch frequency, then the RF tuner should send a command to the LNB to switch to the low-band LOF. The RF tuner should then expect that the LNB device shifts the frequency of the incoming RF signal by the low-band LOF amount, which was specified using KSPROPERTY_BDA_LNB_LOF_LOW_BAND.

See Also

KSP_NODE, KSPROPERTY_BDA_LNB_LOF_HIGH_BAND, KSPROPERTY_BDA_LNB_LOF_LOW_BAND, KSPROPERTY_BDA_RF_TUNER_FREQUENCY


KSPROPSETID_BdaNullTransform

KSPROPSETID_BdaNullTransform is the BDA null transform property set. It is used to instruct a node to pass a signal through without change. Starting a NULL transform on a node effectively changes the node into direct connection from its input to its output with no other function.

The following properties are available:

KSPROPERTY_BDA_NULL_TRANSFORM_START
Disables any transform that the node previously applied to a signal and allows the signal to pass through the node unchanged.
KSPROPERTY_BDA_NULL_TRANSFORM_STOP
Restarts the transform that the node performed on the signal before that transform was disabled with the KSPROPERTY_BDA_NULL_TRANSFORM_START property.

Comments

The network provider filter can use this property set if a node supports it and the network provider needs the signal to pass through that particular node unchanged.


KSPROPERTY_BDA_NULL_TRANSFORM_START

Clients use KSPROPERTY_BDA_NULL_TRANSFORM_START to disable any transform that the node previously applied to a signal and to allow the signal to pass through the node unchanged.

Specifying This Property

KSPROPERTY

Property Data

None

See Also

KSPROPERTY


KSPROPERTY_BDA_NULL_TRANSFORM_STOP

Clients use KSPROPERTY_BDA_NULL_TRANSFORM_STOP to restart the transform that the node performed on the signal before that transform was disabled with the KSPROPERTY_BDA_NULL_TRANSFORM_START property.

Specifying This Property

KSPROPERTY

Property Data

None

See Also

KSPROPERTY, KSPROPERTY_BDA_NULL_TRANSFORM_START


KSPROPSETID_BdaPIDFilter

KSPROPSETID_BdaPIDFilter is the BDA packet identifier (PID) filter property set. It is used to filter out unwanted sub-streams from the received broadcast MPEG2 transport stream. This property set controls the properties of a PID filter node.

The following properties are available:

KSPROPERTY_BDA_PIDFILTER_MAP_PIDS
Informs the PID filter node about the list of MPEG2 PIDs of transport stream packets that should be passed to the downstream filter or node.
KSPROPERTY_BDA_PIDFILTER_UNMAP_PIDS
Informs the PID filter node about packets identified with specific PIDs to filter from the input stream.
KSPROPERTY_BDA_PIDFILTER_LIST_PIDS
Returns an array of PIDs that identify groups of packets that the PID filter node delivers from the input stream to the output stream.


KSPROPERTY_BDA_PIDFILTER_LIST_PIDS

Clients use KSPROPERTY_BDA_PIDFILTER_LIST_PIDS to retrieve from a PID filter node the list its PIDs that identify groups of packets that the node delivers from the input stream to the output stream.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the PID filter node.

Property Data

None

See Also

KSP_NODE


KSPROPERTY_BDA_PIDFILTER_MAP_PIDS

Clients use KSPROPERTY_BDA_PIDFILTER_MAP_PIDS to inform the PID filter node about the list of MPEG2 PIDs of transport stream packets that should be passed to the downstream filter or node. This property also informs the PID filter node what output type (for example table sections or transport stream) to use when delivering data on the node's output.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the PID filter node.

Property Data

A BDA_PID_MAP structure that describes a map of the data to filter out of the input stream.

Comments

The PID filter node merges the list that is provided with this property with the list of PIDs that the node currently passes downstream. If a PID in the provided list is already in the PID filter node's list, then the output type of the provided list takes precedence. This property is also used to retrieve the type of data that the node outputs. The BDA_PID_MAP structure describes a map of this output data.

See Also

BDA_PID_MAP, KSP_NODE


KSPROPERTY_BDA_PIDFILTER_UNMAP_PIDS

Clients use KSPROPERTY_BDA_PIDFILTER_UNMAP_PIDS to inform the PID filter node about packets identified with specific PIDs to filter from the input stream (that is, stop passing from input to output).

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the PID filter node.

Property Data

A BDA_PID_UNMAP structure that describes a map of packets identified with specific PIDs to filter from the input stream.

Comments

Any PID in this list that is not passed by the node is ignored.

See Also

BDA_PID_UNMAP, KSP_NODE


KSPROPSETID_BdaPinControl

KSPROPSETID_BdaPinControl is the BDA pin control property set. It is used to retrieve some BDA-specific information about a particular pin.

The following properties are available:

KSPROPERTY_BDA_PIN_ID
Returns the BDA identifier (ID) for a pin.
KSPROPERTY_BDA_PIN_TYPE
Returns the value that specifies the type of a pin.

Comments

After the network provider creates a pin for a filter using a KSMETHOD_BDA_CREATE_PIN_FACTORY request of the KSMETHODSETID_BdaDeviceConfiguration method set, the network provider uses the properties of KSPROPSETID_BdaPinControl to update its internal representation of the actual receiver topology.

Each pin factory of a BDA filter should support this property set. If a BDA minidriver does not define this property set, then the BDA support library adds support when the pin factory is created by either the BdaCreatePin or BdaInitFilter function.

The properties in this property set return information about a pin. Typically, pins of a filter are not required to intercept any of these properties. The BDA support library provides the BdaPropertyGetPinControl default function to handle this property set.

See Also

BdaCreatePin, BdaInitFilter, BdaPropertyGetPinControl, KSMETHODSETID_BdaDeviceConfiguration


KSPROPERTY_BDA_PIN_ID

Clients use KSPROPERTY_BDA_PIN_ID to retrieve the BDA identifier (ID) for a pin.

Specifying This Property

KSPROPERTY

Property Data

ULONG, representing the pin ID.

Comments

When the network provider creates a pin for a filter using KSMETHOD_BDA_CREATE_PIN_FACTORY, the BDA minidriver for the filter gives that pin an ID. KSPROPERTY_BDA_PIN_ID returns this ID.

See Also

KSMETHOD_BDA_CREATE_PIN_FACTORY, KSPROPERTY


KSPROPERTY_BDA_PIN_TYPE

Clients use KSPROPERTY_BDA_PIN_TYPE to retrieve the value that specifies the type of a pin.

Specifying This Property

KSPROPERTY

Property Data

ULONG, representing the pin type.

Comments

When the network provider creates a pin for a filter using KSMETHOD_BDA_CREATE_PIN_FACTORY, it specifies a pin type from the list of pin types included in the filter's BDA template topology. KSPROPERTY_BDA_PIN_TYPE returns this pin type. In the filter's BDA template topology each pin type can only occur once, but it can occur multiple times in an actual topology. The value for the pin type corresponds to the index of the element in the zero-based array of pin types. This array of pin types is an array of KSPIN_DESCRIPTOR_EX structures.

See Also

KSMETHOD_BDA_CREATE_PIN_FACTORY, KSPIN_DESCRIPTOR_EX, KSPROPERTY


KSPROPSETID_BdaPinEvent

KSPROPSETID_BdaPinEvent is the BDA pin event set. It is used for notifying filters or applications that requested notification of events related to a specific pin.

The following events are available:

KSEVENT_BDA_PIN_CONNECTED
Notifies when a pin becomes connected.
KSEVENT_BDA_PIN_DISCONNECTED
Notifies when a pin becomes disconnected.

Comments

The network provider filter uses this event set to register for notification of events related to pins as those events occur.

If a BDA minidriver does not define this event set, then the BDA support library adds support when a pin is created by either the BdaCreatePin or BdaInitFilter function.

If a BDA minidriver defines its own handlers for this event set, then the minidriver is responsible for signaling the events in this event set to notify filters or plugins that previously requested notification.


KSEVENT_BDA_PIN_CONNECTED

Clients use KSEVENT_BDA_PIN_CONNECTED to request notification when a pin becomes connected.

Specifying This Event

KSEVENT

Event Data

A KSEVENTDATA structure that describes how to notify about the event.

Comments

For information about using a KSEVENTDATA structure to notify about an event, see Enable Event.

See Also

KSEVENT, KSEVENTDATA


KSEVENT_BDA_PIN_DISCONNECTED

Clients use KSEVENT_BDA_PIN_DISCONNECTED to request notification when a pin becomes disconnected.

Specifying This Event

KSEVENT

Event Data

A KSEVENTDATA structure that describes how to notify about the event.

Comments

For information about using a KSEVENTDATA structure to notify about an event, see Enable Event.

See Also

KSEVENT, KSEVENTDATA


KSPROPSETID_BdaSignalStats

KSPROPSETID_BdaSignalStats is the BDA signal statistics property set. It is used to retrieve signal statistics from a control node or a pin.

The following properties are available:

KSPROPERTY_BDA_SIGNAL_STRENGTH
Optional.
Indicates the carrier strength of the signal in mDb (1/1000 of a decibel (DB)).
KSPROPERTY_BDA_SIGNAL_QUALITY
Optional.
Indicates the amount of data successfully extracted from the signal as a percent.
KSPROPERTY_BDA_SIGNAL_PRESENT
Required.
Indicates whether a signal carrier is present.
KSPROPERTY_BDA_SIGNAL_LOCKED
Required.
Indicates whether a signal can be locked.
KSPROPERTY_BDA_SAMPLE_TIME
Optional.
Indicates the sample time over which signal level and quality are averaged.

Comments

When specifying the particular property of the KSPROPSETID_BdaSignalStats property set to get a signal statistic from a pin, set the NodeId member of the KSP_NODE structure to –1.


KSPROPERTY_BDA_SIGNAL_LOCKED

Clients use KSPROPERTY_BDA_SIGNAL_LOCKED to determine whether a signal can be locked.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the control node or is set to –1 to specify a pin.

Property Data

BOOL, representing whether a signal can be locked. Returns TRUE if a signal can be locked and FALSE otherwise.

Comments

If an RF tuner node returns TRUE, a phase-lock-loop (PLL) lock is typically indicated.

If a demodulator node returns TRUE, a signal quality of at least 20% is indicated.

See Also

KSP_NODE, KSPROPERTY_BDA_SIGNAL_QUALITY


KSPROPERTY_BDA_SIGNAL_PRESENT

Clients use KSPROPERTY_BDA_SIGNAL_PRESENT to determine whether a signal carrier is present.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the control node or is set to –1 to specify a pin.

Property Data

BOOL, representing whether a signal carrier is present. Returns TRUE if a signal carrier is present and FALSE otherwise.

Comments

The RF tuner node should provide this indication.

See Also

KSP_NODE


KSPROPERTY_BDA_SIGNAL_QUALITY

Clients use KSPROPERTY_BDA_SIGNAL_QUALITY to determine the amount of data successfully extracted from the signal as a percent.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the control node or is set to –1 to specify a pin.

Property Data

LONG, representing the data that is extracted from the signal as a percent.

Comments

The demodulation node typically reports signal quality, which is a representation of how much of the original data could be extracted from the signal.

In the case of analog signals, this percentage can be computed by examining the timing of horizontal sync (HSync) and vertical sync (VSync) as well as by looking at information contained in horizontal-blanking (HBlanking) and vertical-blanking (VBlanking) intervals.

In the case of digital signals, this percentage can be computed by examining packet cyclic redundancy checks (CRC) and forward error correction (FEC) confidence values as follows:

  • 100 percent is ideal.
  • 95 percent shows very little (almost unnoticeable) artifacts when rendered.
  • 90 percent contains few enough artifacts as to be easily viewable.
  • 80 percent is the minimum level to be viewable.
  • 60 percent is the minimum level to expect data services, including receiving an electronic program guide (EPG), to work.
  • 20 percent indicates that the demodulator is aware that a properly modulated signal exists but cannot produce enough data to be useful.

See Also

KSP_NODE


KSPROPERTY_BDA_SIGNAL_STRENGTH

Clients use KSPROPERTY_BDA_SIGNAL_STRENGTH to determine the carrier strength of the signal in mDb (1/1000 of a decibel (DB)).

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the control node or is set to –1 to specify a pin.

Property Data

LONG, representing the carrier strength of the signal in mDb.

Comments

A strength of 0 is nominal strength as expected for the given type of broadcast network. Sub-nominal strengths are reported as positive mDb. Super-nominal strengths are reported as negative mDb.

See Also

KSP_NODE


KSPROPERTY_BDA_SAMPLE_TIME

Clients use KSPROPERTY_BDA_SAMPLE_TIME to determine the sample time over which signal level and quality are averaged.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the control node or is set to –1 to specify a pin.

Property Data

LONG, representing the sample time in milliseconds.

Comments

Each time a client requests a signal statistics property, the node should report the average value for the last n milliseconds where n is the value indicated by KSPROPERTY_BDA_SAMPLE_TIME. If no time value is set or if the driver does not support KSPROPERTY_BDA_SAMPLE_TIME, the driver should default to a sample time of 100 milliseconds.

The driver can report time values for the most recently completed sample period.

See Also

KSP_NODE, KSPROPERTY_BDA_SIGNAL_QUALITY, KSPROPERTY_BDA_SIGNAL_STRENGTH


KSPROPSETID_BdaTableSection

KSPROPSETID_BdaTableSection is the BDA table section property set. It is used to provide a table section to a node to use when delivering data on the node's output.

The following property is available:

KSPROPERTY_BDA_TABLE_SECTION
Informs a node about the table section to use when delivering data on the node's output.


KSPROPERTY_BDA_TABLE_SECTION

Clients use KSPROPERTY_BDA_TABLE_SECTION to inform nodes about the table section to use when delivering data on the node's output.

Specifying This Property

KSP_NODE. The NodeId member specifies the identifier of the LNB amplifier node.

Property Data

A BDA_TABLE_SECTION structure that describes the table section.

See Also

BDA_TABLE_SECTION, KSP_NODE


KSPROPSETID_BdaTopology

KSPROPSETID_BdaTopology is the BDA topology property set. It is used for querying filters about their capabilities.

The following properties are available:

KSPROPERTY_BDA_NODE_TYPES
Returns a list of the node types.
KSPROPERTY_BDA_PIN_TYPES
Returns a list of the pin types.
KSPROPERTY_BDA_TEMPLATE_CONNECTIONS
Returns a list of connections between pins and nodes in a template topology.
KSPROPERTY_BDA_NODE_METHODS
Returns a list of methods supported on a node.
KSPROPERTY_BDA_NODE_PROPERTIES
Returns a list of properties supported on a node.
KSPROPERTY_BDA_NODE_EVENTS
Returns a list of events supported on a node.
KSPROPERTY_BDA_CONTROLLING_PIN_ID
Returns the controlling pin for a node in the BDA template connection list.
KSPROPERTY_BDA_NODE_DESCRIPTORS
Returns a list of nodes.

Comments

The BDA support library provides default methods to handle this property set. The network provider filter uses this property set to determine the template topology of the filter, and the methods, properties and events supported on each node and pin. The network provider filter uses this node and pin information to determine what kinds of operations the filter can perform on the signal and whether to add the filter to the graph. The actual topology of a filter refers to the pin and node connections that are actually made on the filter by the network provider.

The properties in this property set define what the filter can do. Typically, filters are not required to intercept any of these properties. For more information, see Broadcast Driver Architecture Minidrivers on how the BDA minidriver for a filter can use the BDA support library of functions to provide default handling of these properties. A driver writer should create static structures that enable handling of this property set. Once these structures are created and registered with the BDA support library, the driver writer is not required to do anything further to support this property set.


KSPROPERTY_BDA_CONTROLLING_PIN_ID

Clients use KSPROPERTY_BDA_CONTROLLING_PIN_ID to retrieve the controlling pin for a node in the BDA template connection list.

Specifying This Property

KSP_BDA_NODE_PIN

Property Data

ULONG, representing the controlling pin ID.

Comments

Nodes are associated with one pin in the filter, either an input pin or an output pin. Nodes can only be accessed through the controlling pin because nodes do not have their own file handle. The network provider can use this property and the KSP_BDA_NODE_PIN structure to query for the controlling pin for each node in the BDA template connection list (KSTOPOLOGY_CONNECTION or BDA_TEMPLATE_CONNECTION array).

See Also

BdaPropertyGetControllingPinId, BDA_TEMPLATE_CONNECTION, KSP_BDA_NODE_PIN, KSTOPOLOGY_CONNECTION


KSPROPERTY_BDA_NODE_DESCRIPTORS

Clients use KSPROPERTY_BDA_NODE_DESCRIPTORS to retrieve a list of nodes.

Specifying This Property

KSPROPERTY

Property Data

None

Comments

The list of nodes is an array of GUIDs for available nodes.

For a list of BDA nodes that are available to create in a template topology, see BDA Node Category GUIDs.

See Also

BdaPropertyNodeDescriptors, KSPROPERTY


KSPROPERTY_BDA_NODE_EVENTS

Clients use KSPROPERTY_BDA_NODE_EVENTS to retrieve a list of events supported on a node.

Specifying This Property

KSPROPERTY

Property Data

None

Comments

The list of events supported by a node is a list of GUIDs.

The network provider will use this property to query the capabilities of each node in the BDA template connection list.

See Also

BdaPropertyNodeEvents, KSPROPERTY


KSPROPERTY_BDA_NODE_METHODS

Clients use KSPROPERTY_BDA_NODE_METHODS to retrieve a list of methods supported on a node.

Specifying This Property

KSPROPERTY

Property Data

None

Comments

The list of methods supported by a node is a list of GUIDs.

The network provider will use this property to query the capabilities of each node in the BDA template connection list.

See Also

BdaPropertyNodeMethods, KSPROPERTY


KSPROPERTY_BDA_NODE_PROPERTIES

Clients use KSPROPERTY_BDA_NODE_PROPERTIES to retrieve a list of properties supported on a node.

Specifying This Property

KSPROPERTY

Property Data

None

Comments

The list of properties supported by a node is a list of GUIDs.

The network provider will use this property to query the capabilities of each node in the BDA template connection list.

See Also

BdaPropertyNodeProperties, KSPROPERTY


KSPROPERTY_BDA_NODE_TYPES

Clients use KSPROPERTY_BDA_NODE_TYPES to retrieve a list of node types.

Specifying This Property

KSPROPERTY

Property Data

None

Comments

In a template topology each node type can only occur once, but it can occur multiple times in an actual topology. This list of node types is an array of KSNODE_DESCRIPTOR structures. Typically, the index of each element in this array is used to identify each particular node type.

See Also

BdaPropertyNodeTypes, KSNODE_DESCRIPTOR, KSPROPERTY


KSPROPERTY_BDA_PIN_TYPES

Clients use KSPROPERTY_BDA_PIN_TYPES to retrieve a list of pin types.

Specifying This Property

KSPROPERTY

Property Data

None

Comments

In a template topology each pin type can only occur once, but it can occur multiple times in an actual topology. This list of pin types is an array of KSPIN_DESCRIPTOR_EX structures.

See Also

BdaPropertyPinTypes, KSPIN_DESCRIPTOR_EX, KSPROPERTY


KSPROPERTY_BDA_TEMPLATE_CONNECTIONS

Clients use KSPROPERTY_BDA_TEMPLATE_CONNECTIONS to retrieve a list of connections between pins and nodes in a template topology.

Specifying This Property

KSPROPERTY

Property Data

A BDA_TEMPLATE_CONNECTION structure that describes a connection in a template topology.

Comments

The list of connections between pins and nodes in a template topology is an array of BDA_TEMPLATE_CONNECTION structures.

See Also

BdaPropertyTemplateConnections, BDA_TEMPLATE_CONNECTION, KSPIN_DESCRIPTOR_EX, KSPROPERTY


KSPROPSETID_BdaVoidTransform

KSPROPSETID_BdaVoidTransform is the BDA void transform property set. It is used for controlling when nodes start and stop. The network provider filter uses this property set to control the operation of nodes.

The following properties are available:

KSPROPERTY_BDA_VOID_TRANSFORM_START
Starts operation of a node.
KSPROPERTY_BDA_VOID_TRANSFORM_STOP
Stops operation of a node.


KSPROPERTY_BDA_VOID_TRANSFORM_START

Clients use KSPROPERTY_BDA_VOID_TRANSFORM_START to start operation of a node.

Specifying This Property

KSPROPERTY

Property Data

None

See Also

KSPROPERTY


KSPROPERTY_BDA_VOID_TRANSFORM_STOP

Clients use KSPROPERTY_BDA_VOID_TRANSFORM_STOP to stop operation of a node.

Specifying This Property

KSPROPERTY

Property Data

None

See Also

KSPROPERTY


Broadcast Driver Architecture Enumerations and Structures

A BDA minidriver uses the following enumerations and structures.

ATSCComponentTypeFlags

BDA_CA_MODULE_UI

BDA_CHANGE_STATE

BinaryConvolutionCodeRate

BDA_FILTER_TEMPLATE

BDANODE_DESCRIPTOR

BDA_PID_MAP

BDA_PID_UNMAP

BDA_PIN_PAIRING

BDA_PROGRAM_PID_LIST

BDA_TABLE_SECTION

BDA_TEMPLATE_CONNECTION

BDA_TEMPLATE_PIN_JOINT

BDA_TRANSPORT_INFO

ComponentCategory

ComponentStatus

DVBSystemType

FECMethod

GuardInterval

HierarchyAlpha

KS_BDA_FRAME_INFO

KS_DATARANGE_BDA_ANTENNA

KS_DATARANGE_BDA_TRANSPORT

KSM_BDA_PIN

KSM_BDA_PIN_PAIR

KSM_PIN

KSM_PIN_PAIR

KSP_BDA_NODE_PIN

KSP_NODE_ESPID

MEDIA_SAMPLE_CONTENT

ModulationType

MPEG2StreamType

MPEG2_TRANSPORT_STRIDE

PID_MAP

Polarization

SpectralInversion

TransmissionMode

Comments

The BDA enumerations and structures are available on Windows® XP and later. These enumerations and structures are available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.


ATSCComponentTypeFlags

The ATSCComponentTypeFlags enumeration contains a value that specifies a bitmask of the various properties of an ATSC stream.

typedef enum ATSCComponentTypeFlags {
    ATSCCT_AC3 = 0x00000001,
} ATSCComponentTypeFlags;

Element

ATSCCT_AC3
Bitmask that specifies an ATSC AC3 audio stream type.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.


BDA_CA_MODULE_UI

The BDA_CA_MODULE_UI structure describes the user interface (UI) that conditional access (CA) plugins can display.

typedef struct _BDA_CA_MODULE_UI {
    ULONG  ulFormat;
    ULONG  ulbcDesc;
    ULONG  ulDesc[MIN_DIMENSION];
} BDA_CA_MODULE_UI, *PBDA_CA_MODULE_UI;

Members

ulFormat
Value that specifies the format of the UI.
ulbcDesc
Number of descriptors in the ulDesc array.
ulDesc
Array of descriptors for the UI.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.

See Also

KSPROPERTY_BDA_CA_MODULE_UI, KSPROPSETID_BdaCA


BDA_CHANGE_STATE

The BDA_CHANGE_STATE enumeration contains values that specify the state of topology changes in a filter.

typedef enum {
    BDA_CHANGES_COMPLETE = 0,
    BDA_CHANGES_PENDING
} BDA_CHANGE_STATE, * PBDA_CHANGE_STATE;

Elements

BDA_CHANGES_COMPLETE
BDA topology changes are complete.
BDA_CHANGES_PENDING
BDA topology changes are pending.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.

See Also

BdaGetChangeState


BinaryConvolutionCodeRate

The BinaryConvolutionCodeRate enumeration contains values that specify the binary convolution scheme used for either the inner or outer forward error correction (FEC) of a signal demodulator node.

typedef V1_ENUM enum BinaryConvolutionCodeRate {
    BDA_BCC_RATE_NOT_SET = -1,
    BDA_BCC_RATE_NOT_DEFINED = 0,
    BDA_BCC_RATE_1_2 = 1,   // 1/2
    BDA_BCC_RATE_2_3,   // 2/3
    BDA_BCC_RATE_3_4,   // 3/4
    BDA_BCC_RATE_3_5,
    BDA_BCC_RATE_4_5,
    BDA_BCC_RATE_5_6,   // 5/6
    BDA_BCC_RATE_5_11,
    BDA_BCC_RATE_7_8,   // 7/8
    BDA_BCC_RATE_MAX,
} BinaryConvolutionCodeRate;

Elements

BDA_BCC_RATE_NOT_SET
Rate not set.
BDA_BCC_RATE_NOT_DEFINED
Rate not defined.
BDA_BCC_RATE_1_2
Rate set to 1/2.
BDA_BCC_RATE_2_3
Rate set to 2/3.
BDA_BCC_RATE_3_4
Rate set to 3/4.
BDA_BCC_RATE_3_5
Rate set to 3/5.
BDA_BCC_RATE_4_5
Rate set to 4/5.
BDA_BCC_RATE_5_6
Rate set to 5/6.
BDA_BCC_RATE_5_11
Rate set to 5/11.
BDA_BCC_RATE_7_8
Rate set to 7/8.
BDA_BCC_RATE_MAX
Maximum value in the enumeration exceeded.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.

See Also

KSPROPSETID_BdaDigitalDemodulator


BDA_FILTER_TEMPLATE

The BDA_FILTER_TEMPLATE structure describes the template topology for a BDA filter.

typedef struct _BDA_FILTER_TEMPLATE {
    const KSFILTER_DESCRIPTOR *  pFilterDescriptor;
    ULONG                        ulcPinPairs;
    const BDA_PIN_PAIRING *      pPinPairs;
} BDA_FILTER_TEMPLATE,  *PBDA_FILTER_TEMPLATE;

Members

pFilterDescriptor
Points to a KSFILTER_DESCRIPTOR structure that describes a template for a filter for the BDA device.
ulcPinPairs
Number of pairs of pins in the pPinPairs array.
pPinPairs
Array of BDA_PIN_PAIRING structures that describe the topology between a pair of the filter's input and output pins.

Headers

Defined in Bdasup.h. Include Bdasup.h.

See Also

BdaCreateFilterFactory, BdaInitFilter, BDA_PIN_PAIRING, KSFILTER_DESCRIPTOR


BDANODE_DESCRIPTOR

The BDANODE_DESCRIPTOR structure describes a BDA node.

typedef struct _BDANODE_DESCRIPTOR {
    ULONG  ulBdaNodeType;
    GUID   guidFunction;
    GUID   guidName;
} BDANODE_DESCRIPTOR, *PBDANODE_DESCRIPTOR;

Members

ulBdaNodeType
The node type as the BDA template topology identifies it. The BDA node-type identifier typically corresponds to the index of the element in the zero-based array of node types. This array of node types is an array of KSNODE_DESCRIPTOR structures.
guidFunction
GUID that describes the node's function. See BDA Node Category GUIDs for a list of these GUIDs.
guidName
GUID that can be used to store a string containing the name of the node. Applications can search the registry for this GUID to obtain the node's name and then can display the name.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.

See Also

BDA Node Category GUIDs, KSNODE_DESCRIPTOR


BDA_PID_MAP

The BDA_PID_MAP structure describes a type of data to filter out of the input stream of a packet identifier (PID) filter and then pass to a downstream filter. This output consists of packets that are identified with PIDs and contain particular media content.

typedef struct _BDA_PID_MAP {
    MEDIA_SAMPLE_CONTENT  MediaSampleContent;
    ULONG                 ulcPIDs;
    ULONG                 aulPIDs[MIN_DIMENSION];
} BDA_PID_MAP, *PBDA_PID_MAP;

Members

MediaSampleContent
MEDIA_SAMPLE_CONTENT enumeration value that specifies the type of media content that packets contain.
ulcPIDs
Number of PIDs in the aulPIDs array.
aulPIDs
Array of PIDs that identify packets to map to the output of a PID filter.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.

See Also

BDA_PID_UNMAP, KSPROPSETID_BdaPIDFilter, MEDIA_SAMPLE_CONTENT, PID_MAP


BDA_PID_UNMAP

The BDA_PID_UNMAP structure describes packet types to stop filtering from the input stream of a packet identifier (PID) filter. These packet types are identified with PIDs.

typedef struct _BDA_PID_UNMAP {
    ULONG  ulcPIDs;
    ULONG  aulPIDs[MIN_DIMENSION];
} BDA_PID_UNMAP, *PBDA_PID_UNMAP;

Members

ulcPIDs
Number of PIDs in the aulPIDs array.
aulPIDs
Array of PIDs that identify packets to unmap from the output of a PID filter.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.

See Also

BDA_PID_MAP, KSPROPSETID_BdaPIDFilter, MEDIA_SAMPLE_CONTENT, PID_MAP


BDA_PIN_PAIRING

The BDA_PIN_PAIRING structure describes the topology between a pair of input and output pins.

typedef struct _BDA_PIN_PAIRING {
    ULONG          ulInputPin;
    ULONG          ulOutputPin;
    ULONG          ulcMaxInputsPerOutput;
    ULONG          ulcMinInputsPerOutput;
    ULONG          ulcMaxOutputsPerInput;
    ULONG          ulcMinOutputsPerInput;
    ULONG          ulcTopologyJoints;
    const ULONG *  pTopologyJoints;
} BDA_PIN_PAIRING, * PBDA_PIN_PAIRING;

Members

ulInputPin
Index of the element in the zero-based array of pin types (KSPIN_DESCRIPTOR_EX array) that indicates the input pin of the pair.
ulOutputPin
Index of the element in the zero-based array of pin types (KSPIN_DESCRIPTOR_EX array) that indicates the output pin of the pair.
ulcMaxInputsPerOutput
Maximum number of input pins per output pin. The network provider creates duplicates of nodes that are controlled by the input pin depending on the value specified in ulcMaxInputsPerOutput.
ulcMinInputsPerOutput
Minimum number of input pins per output pin. The network provider creates duplicates of nodes that are controlled by the input pin depending on the value specified in ulcMinInputsPerOutput.
ulcMaxOutputsPerInput
Maximum number of output pins per input pin. The network provider creates duplicates of nodes that are controlled by the output pin depending on the value specified in ulcMaxOutputsPerInput.
ulcMinOutputsPerInput
Minimum number of output pins per input pin. The network provider creates duplicates of nodes that are controlled by the output pin depending on the value specified in ulcMinOutputsPerInput.
ulcTopologyJoints
Number of joints in the pTopologyJoints array.
pTopologyJoints
Array of joint values. The value given to a joint corresponds to the index of an element in a array of template connections (KSTOPOLOGY_CONNECTION or BDA_TEMPLATE_CONNECTION array). A topology joint marks the point in the template topology where control of nodes switches from the input pin to the output pin. Those nodes that occur upstream of the topology joint are controlled through the input pin. Those nodes that occur downstream of the topology joint are controlled through the output pin.

Headers

Defined in Bdasup.h. Include Bdasup.h.

See Also

BDA_FILTER_TEMPLATE, BDA_TEMPLATE_CONNECTION, KSPIN_DESCRIPTOR_EX, KSTOPOLOGY_CONNECTION


BDA_PROGRAM_PID_LIST

The BDA_PROGRAM_PID_LIST structure describes data of a specific program to view. This data consists of packets that are identified with packet identifiers (PID).

typedef struct _BDA_PROGRAM_PID_LIST {
    ULONG   ulProgramNumber;
    ULONG   ulcPIDs;
    ULONG   ulPID[MIN_DIMENSION];
} BDA_PROGRAM_PID_LIST, *PBDA_PROGRAM_PID_LIST;

Members

ulProgramNumber
Number of the program to be viewed.
ulcPIDs
Number of PIDs in the ulPID array.
ulPID
Array of PIDs that identify packets of program data.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.

See Also

KSPROPERTY_BDA_CA_SET_PROGRAM_PIDS, KSPROPSETID_BdaCA


BDA_TABLE_SECTION

The BDA_TABLE_SECTION structure describes a table section.

typedef struct _BDA_TABLE_SECTION {
    ULONG   ulPrimarySectionId;
    ULONG   ulSecondarySectionId;
    ULONG   ulcbSectionLength;
    ULONG   argbSectionData[MIN_DIMENSION];
} BDA_TABLE_SECTION, *PBDA_TABLE_SECTION;

Members

ulPrimarySectionId
Identifier of the primary table section.
ulSecondarySectionId
Identifier of the secondary table section.
ulcbSectionLength
Size, in bytes, of the argbSectionData array.
argbSectionData
Array of table section data.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.

See Also

KSPROPSETID_BdaTableSection


BDA_TEMPLATE_CONNECTION

The BDA_TEMPLATE_CONNECTION structure describes the template for a BDA connection in terms of where it begins and ends.

typedef struct _BDA_TEMPLATE_CONNECTION {
    ULONG   FromNodeType;
    ULONG   FromNodePinType;
    ULONG   ToNodeType;
    ULONG   ToNodePinType;
}BDA_TEMPLATE_CONNECTION, *PBDA_TEMPLATE_CONNECTION;

Members

FromNodeType
Index of the element in the zero-based array of internal node types (KSNODE_DESCRIPTOR array) that indicates the node type where the connection begins or –1 to indicate that the connection begins at an upstream filter.
FromNodePinType
Index of the element in the zero-based array of pin types (KSPIN_DESCRIPTOR_EX array) that indicates the pin type where the connection begins. The array of pin types is the list of pin types that are available in the filter's template topology.
ToNodeType
Index of the element in the zero-based array of internal node types (KSNODE_DESCRIPTOR array) that indicates the node type where the connection ends or –1 to indicate that the connection ends at a downstream filter.
ToNodePinType
Index of the element in the zero-based array of pin types (KSPIN_DESCRIPTOR_EX array) that indicates the pin type where the connection ends. The array of pin types is the list of pin types that are available in the filter's template topology.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.

See Also

BDA_PIN_PAIRING, BdaPropertyTemplateConnections, KSNODE_DESCRIPTOR, KSPIN_DESCRIPTOR_EX, KSPROPSETID_BdaTopology, KSTOPOLOGY_CONNECTION


BDA_TEMPLATE_PIN_JOINT

The BDA_TEMPLATE_PIN_JOINT structure describes a joint in a template topology.

typedef struct _BDA_TEMPLATE_PIN_JOINT {
    ULONG   uliTemplateConnection;
    ULONG   ulcInstancesMax;
}BDA_TEMPLATE_PIN_JOINT, *PBDA_TEMPLATE_PIN_JOINT;

Members

uliTemplateConnection
Index of an element in a array of template connections (KSTOPOLOGY_CONNECTION or BDA_TEMPLATE_CONNECTION array) that represents the joint.
ulcInstancesMax
Maximum number of possible instances of the joint in the template topology.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.

See Also

BDA_TEMPLATE_CONNECTION, KSTOPOLOGY_CONNECTION


BDA_TRANSPORT_INFO

The BDA_TRANSPORT_INFO structure describes formatting for a stream connection.

typedef struct tagBDA_TRANSPORT_INFO {
    ULONG           ulcbPhyiscalPacket;
    ULONG           ulcbPhyiscalFrame;
    ULONG           ulcbPhyiscalFrameAlignment;
    REFERENCE_TIME  AvgTimePerFrame;
} BDA_TRANSPORT_INFO, *PBDA_TRANSPORT_INFO;

Members

ulcbPhyiscalPacket
Size, in bytes, of a physical packet (for example, the size of a satellite link payload).
ulcbPhyiscalFrame
Size, in bytes, of each physical frame (0 indicates no hardware requirement).
ulcbPhyiscalFrameAlignment
Capture buffer alignment in bytes (0 and 1 indicate no alignment requirements).
AvgTimePerFrame
REFERENCE TIME value that indicates the video frame's average display time, in 100-nanosecond units.

Headers

Defined in Bdamedia.h. Include Bdamedia.h.

Comments

A BDA_TRANSPORT_INFO structure in conjunction with a KSDATARANGE structure makes up a KS_DATARANGE_BDA_TRANSPORT data range. A data range describes a range of data formats.

Pins of filters specify the data ranges they support to enable stream connections to pins of other filters that also support those data ranges.

See Also

KSDATARANGE, KS_DATARANGE_BDA_TRANSPORT, KSPIN_DESCRIPTOR


ComponentCategory

The ComponentCategory enumeration contains values that specify a substream of the received broadcast stream.

typedef V1_ENUM enum ComponentCategory {
    CategoryNotSet = -1,
    CategoryOther = 0,
    CategoryVideo,
    CategoryAudio,
    CategoryText,
    CategoryData,
} ComponentCategory;

Elements

CategoryNotSet
Specifies that the category of the substream is not set.
CategoryOther
Specifies a category other than video, audio, text, or data.
CategoryVideo
Specifies that the category of the substream is video.
CategoryAudio
Specifies that the category of the substream is audio.
CategoryText
Specifies that the category of the substream is text.
CategoryData
Specifies that the category of the substream is data.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.


ComponentStatus

The ComponentStatus enumeration contains values that specify the status of a substream of the received broadcast stream.

typedef enum ComponentStatus {
    StatusActive,
    StatusInactive,
    StatusUnavailable,
} ComponentStatus;

Elements

StatusActive
Specifies the substream is active.
StatusInactive
Specifies the substream is inactive.
StatusUnavailable
Specifies the substream is not available.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.


DVBSystemType

The DVBSystemType enumeration contains values that specify the broadcast system for a particular digital video broadcast (DVB) tuning space instance.

typedef enum DVBSystemType {
    DVB_Cable,
    DVB_Terrestrial,
    DVB_Satellite,
} DVBSystemType;

Elements

DVB_Cable
Cable broadcast system.
DVB_Terrestrial
Terrestrial broadcast system.
DVB_Satellite
Satellite broadcast system.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.


FECMethod

The FECMethod enumeration contains values that specify the forward error correction (FEC) type used by a signal demodulator node.

typedef V1_ENUM enum FECMethod {
    BDA_FEC_METHOD_NOT_SET = -1,
    BDA_FEC_METHOD_NOT_DEFINED = 0,
    BDA_FEC_VITERBI = 1,
    BDA_FEC_RS_204_188,
    BDA_FEC_MAX,
} FECMethod;

Elements

BDA_FEC_METHOD_NOT_SET
FEC method not set.
BDA_FEC_METHOD_NOT_DEFINED
FEC method not defined.
BDA_FEC_VITERBI
FEC is Viterbi binary convolution.
BDA_FEC_RS_204_188
FEC is Reed-Solomon 204/188 (outer FEC).
BDA_FEC_MAX
Maximum value in the enumeration exceeded.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.

See Also

KSPROPSETID_BdaDigitalDemodulator


GuardInterval

The GuardInterval enumeration contains values that specify the type of guard interval used by a signal demodulator node.

typedef V1_ENUM enum GuardInterval {
    BDA_GUARD_NOT_SET = -1,
    BDA_GUARD_NOT_DEFINED = 0,
    BDA_GUARD_1_32 = 1, // Guard interval is 1/32
    BDA_GUARD_1_16, // Guard interval is 1/16
    BDA_GUARD_1_8, // Guard interval is 1/8
    BDA_GUARD_1_4, // Guard interval is 1/4
    BDA_GUARD_MAX,
} GuardInterval;

Elements

BDA_GUARD_NOT_SET
Guard interval not set.
BDA_GUARD_NOT_DEFINED
Guard interval not defined.
BDA_GUARD_1_32
Guard interval set to 1/32.
BDA_GUARD_1_16
Guard interval set to 1/16.
BDA_GUARD_1_8
Guard interval set to 1/8.
BDA_GUARD_1_4
Guard interval set to 1/4.
BDA_GUARD_MAX
Maximum value in the enumeration exceeded.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.


HierarchyAlpha

The HierarchyAlpha enumeration contains values that specify the hierarchy alpha used by a signal demodulator node.

typedef V1_ENUM enum HierarchyAlpha {
    BDA_HALPHA_NOT_SET = -1,
    BDA_HALPHA_NOT_DEFINED = 0,
    BDA_HALPHA_1 = 1,
    BDA_HALPHA_2,
    BDA_HALPHA_4,
    BDA_HALPHA_MAX,
} HierarchyAlpha;

Elements

BDA_HALPHA_NOT_SET
Hierarchy alpha not set.
BDA_HALPHA_NOT_DEFINED
Hierarchy alpha not defined.
BDA_HALPHA_1
Hierarchy alpha set to 1.
BDA_HALPHA_2
Hierarchy alpha set to 2.
BDA_HALPHA_4
Hierarchy alpha set to 4.
BDA_HALPHA_MAX
Maximum value in the enumeration exceeded.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.


KS_BDA_FRAME_INFO

The KS_BDA_FRAME_INFO structure describes BDA extensions to the KSSTREAM_HEADER structure, which describes a packet of data to be read from or written to a streaming driver pin.

typedef struct tagKS_BDA_FRAME_INFO {
    ULONG  ExtendedHeaderSize;
    DWORD  dwFrameFlags;
    ULONG  ulEvent;
    ULONG  ulChannelNumber;
    ULONG  ulSubchannelNumber;
    ULONG  ulReason;
} KS_BDA_FRAME_INFO, *PKS_BDA_FRAME_INFO;

Members

ExtendedHeaderSize
Size, in bytes, of the BDA extensions described in this extended header structure.
dwFrameFlags
Flags specific to BDA extensions.
ulEvent
Identifier of an event.
ulChannelNumber
Channel number of a television program.
ulSubchannelNumber
Subchannel number of a television program.
ulReason
Identifies the reason the packet was transferred.

Headers

Defined in Bdamedia.h. Include Bdamedia.h.

See Also

KSSTREAM_HEADER


KS_DATARANGE_BDA_ANTENNA

The KS_DATARANGE_BDA_ANTENNA structure describes a range of data formats for a BDA antenna stream.

typedef struct tagKS_DATARANGE_BDA_ANTENNA {
    KSDATARANGE  DataRange;
} KS_DATARANGE_BDA_ANTENNA, *PKS_DATARANGE_BDA_ANTENNA;

Members

DataRange
KSDATARANGE structure that describes a range of data formats with the MajorFormat member specified as STATIC_KSDATAFORMAT_TYPE_BDA_ANTENNA.

Comments

A data range describes a range of data formats.

Pins of filters specify the data ranges they support to enable stream connections to pins of other filters that also support those data ranges.

Headers

Defined in Bdamedia.h. Include Bdamedia.h.

See Also

BDA Stream Format GUIDs, KSDATARANGE, KSPIN_DESCRIPTOR


KS_DATARANGE_BDA_TRANSPORT

The KS_DATARANGE_BDA_TRANSPORT structure describes a range of data formats for a BDA transport stream.

typedef struct tagKS_DATARANGE_BDA_TRANSPORT {
    KSDATARANGE         DataRange;
    BDA_TRANSPORT_INFO  BdaTransportInfo;
} KS_DATARANGE_BDA_TRANSPORT, *PKS_DATARANGE_BDA_TRANSPORT;

Members

DataRange
KSDATARANGE structure that describes a range of data formats.
BdaTransportInfo
BDA_TRANSPORT_INFO structure that describes formatting for a BDA transport stream connection.

Headers

Defined in Bdamedia.h. Include Bdamedia.h.

Comments

A BDA_TRANSPORT_INFO structure in conjunction with a KSDATARANGE structure makes up a KS_DATARANGE_BDA_TRANSPORT data range. A data range describes a range of data formats.

Pins of filters specify the data ranges they support to enable stream connections to pins of other filters that also support those data ranges.

See Also

BDA Stream Format GUIDs, BDA_TRANSPORT_INFO, KSDATARANGE, KSPIN_DESCRIPTOR


KSM_BDA_PIN

The KSM_BDA_PIN structure describes a method request to create or delete a pin factory for a filter.

typedef struct _KSM_BDA_PIN {
    KSMETHOD    Method;
    union {
        ULONG       PinId;
        ULONG       PinType;
    };
    ULONG       Reserved;
} KSM_BDA_PIN, * PKSM_BDA_PIN;

Members

Method
KSMETHOD structure that describes a method and request type of a method request.
PinId
Member of the union in KSM_BDA_PIN that contains the identifier (ID) of a pin factory of a filter.
PinType
Member of the union in KSM_BDA_PIN that contains the value that specifies the pin type.
Reserved
Reserved.

Headers

Defined in Bdamedia.h. Include Bdamedia.h.

See Also

KSMETHOD


KSM_BDA_PIN_PAIR

The KSM_BDA_PIN_PAIR structure describes a method request to retrieve the pin pairing structure (BDA_PIN_PAIRING) between a pair of input and output pins.

typedef struct _KSM_BDA_PIN_PAIR {
    KSMETHOD    Method;
    union {
        ULONG       InputPinId;
        ULONG       InputPinType;
    };
    union {
        ULONG       OutputPinId;
        ULONG       OutputPinType;
    };
} KSM_BDA_PIN_PAIR, * PKSM_BDA_PIN_PAIR;

Members

Method
KSMETHOD structure that describes a method and request type of a method request.
InputPinId
Member of the union in KSM_BDA_PIN_PAIR that contains the identifier (ID) of an input pin of the filter.
InputPinType
Member of the union in KSM_BDA_PIN_PAIR that contains the value that specifies the input pin type.
OutputPinId
Member of the union in KSM_BDA_PIN_PAIR that contains the identifier (ID) of an output pin of the filter.
OutputPinType
Member of the union in KSM_BDA_PIN_PAIR that contains the value that specifies the output pin type.

Headers

Defined in Bdamedia.h. Include Bdamedia.h.

See Also

BDA_PIN_PAIRING, KSMETHOD


KSM_PIN

The KSM_PIN structure describes a method request to create or delete a pin factory for a filter.

typedef struct _KSM_PIN {
    KSMETHOD    Method;
    union {
        ULONG       PinId;
        ULONG       PinType;
    };
    ULONG       Reserved;
} KSM_PIN, * PKSM_PIN;

Members

Method
KSMETHOD structure that describes a method and request type of a method request.
PinId
Member of the union in KSM_PIN that contains the identifier (ID) of a pin factory of a filter.
PinType
Member of the union in KSM_PIN that contains the value that specifies the pin type.
Reserved
Reserved.

Headers

Defined in Bdasup.h. Include Bdasup.h.

Comments

When the network provider creates or deletes a pin for a filter using either KSMETHOD_BDA_CREATE_PIN_FACTORY or KSMETHOD_BDA_DELETE_PIN_FACTORY of the KSMETHODSETID_BdaDeviceConfiguration method set, the BDA minidriver for the filter gives that pin an ID. The ID for the pin is returned in KSM_PIN.

See Also

KSMETHODSETID_BdaDeviceConfiguration


KSM_PIN_PAIR

The KSM_PIN_PAIR structure describes a method request to retrieve the pin pairing structure (BDA_PIN_PAIRING) between a pair of input and output pins.

typedef struct _KSM_PIN_PAIR {
    KSMETHOD    Method;
    ULONG       InputPinId;
    ULONG       OutputPinId;
    ULONG       Reserved;
} KSM_PIN_PAIR, * PKSM_PIN_PAIR;

Members

Method
KSMETHOD structure that describes a method and request type of a method request.
InputPinId
Identifier of an input pin of the filter.
OutputPinId
Identifier of an output pin of the filter.
Reserved
Reserved.

Headers

Defined in Bdasup.h. Include Bdasup.h.

See Also

BDA_PIN_PAIRING, KSMETHOD


KSP_BDA_NODE_PIN

The KSP_BDA_NODE_PIN structure describes a property request to retrieve the controlling pin for a node.

typedef struct _KSP_BDA_NODE_PIN {
    KSPROPERTY      Property;
    ULONG           ulNodeType;
    ULONG           ulInputPinId;
    ULONG           ulOutputPinId;
} KSP_BDA_NODE_PIN, *PKSP_BDA_NODE_PIN;

Members

Property
KSPROPERTY structure that describes the property and request type of the property request.
ulNodeType
Index of the element in the zero-based array of internal node types (KSNODE_DESCRIPTOR array) that specifies the node type for which to retrieve the controlling pin.
ulInputPinId
Identifier of an input pin of the filter.
ulOutputPinId
Identifier of an output pin of the filter.

Headers

Defined in Bdamedia.h. Include Bdamedia.h.

See Also

BdaPropertyGetControllingPinId, KSNODE_DESCRIPTOR, KSPROPERTY, KSPROPSETID_BdaTopology


KSP_NODE_ESPID

The KSP_NODE_ESPID structure describes property and node type for an Entitlement Control Message (ECM) map node along with the packet identifier (PID) for an elementary stream that the ECM map node processes.

typedef struct {
    KSP_NODE    Property;
    ULONG       EsPid;
} KSP_NODE_ESPID, *PKSP_NODE_ESPID;

Members

Property
KSP_NODE structure that describes a property and node type.
EsPid
Packet identifier (PID) that identifies packets in the elementary stream.

Headers

Defined in Bdamedia.h. Include Bdamedia.h.

See Also

KSP_NODE


MEDIA_SAMPLE_CONTENT

The MEDIA_SAMPLE_CONTENT enumeration contains values that specify the type of data in a group of packets that a packet identifier (PID) filter outputs.

typedef enum {
    MEDIA_TRANSPORT_PACKET,
    MEDIA_ELEMENTARY_STREAM,
    MEDIA_MPEG2_PSI,
    MEDIA_TRANSPORT_PAYLOAD
} MEDIA_SAMPLE_CONTENT ;

Elements

MEDIA_TRANSPORT_PACKET
Packets in the output stream are complete transport stream (TS) packets. That is, the PID filter does not demultiplex packets from the input stream but just passes them through to the output.
MEDIA_ELEMENTARY_STREAM
Packets in the output stream consist of packet elementary stream (PES) payloads. That is, the PID filter demultiplexes packets from the input stream that contain either audio or video data.
MEDIA_MPEG2_PSI
Packets in the output stream consist of MPEG2 sections. That is, the PID filter demultiplexes packets from the input stream that contain IP data or data from a Program Allocation Table (PAT), Program Map Table (PMT), or Conditional Access Table (CAT). Each data sample output will consist of exactly one MPEG2 section.
MEDIA_TRANSPORT_PAYLOAD
Packets in the output stream consist of gathered TS packet payloads. That is, the PID filter demultiplexes packets from the input stream that contain, for example, PES or electronic program guide (EPG) packets.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.

See Also

BDA_PID_MAP, KSPROPSETID_BdaPIDFilter, PID_MAP


ModulationType

The ModulationType enumeration contains values that specify the type of a signal demodulator node.

typedef V1_ENUM enum ModulationType {
    BDA_MOD_NOT_SET = -1,
    BDA_MOD_NOT_DEFINED = 0,
    BDA_MOD_16QAM = 1,
    BDA_MOD_32QAM,
    BDA_MOD_64QAM,
    BDA_MOD_80QAM,
    BDA_MOD_96QAM,
    BDA_MOD_112QAM,
    BDA_MOD_128QAM,
    BDA_MOD_160QAM,
    BDA_MOD_192QAM,
    BDA_MOD_224QAM,
    BDA_MOD_256QAM,
    BDA_MOD_320QAM,
    BDA_MOD_384QAM,
    BDA_MOD_448QAM,
    BDA_MOD_512QAM,
    BDA_MOD_640QAM,
    BDA_MOD_768QAM,
    BDA_MOD_896QAM,
    BDA_MOD_1024QAM,
    BDA_MOD_QPSK,
    BDA_MOD_BPSK,
    BDA_MOD_OQPSK,
    BDA_MOD_8VSB,
    BDA_MOD_16VSB,
    BDA_MOD_ANALOG_AMPLITUDE,  // std am
    BDA_MOD_ANALOG_FREQUENCY,  // std fm
    BDA_MOD_MAX,
} ModulationType;

Elements

BDA_MOD_NOT_SET
Specifies the demodulator type is not set.
BDA_MOD_NOT_DEFINED
Specifies the demodulator type is not defined.
BDA_MOD_16QAM
Specifies 16QAM demodulator type.
BDA_MOD_32QAM
Specifies 32QAM demodulator type.
BDA_MOD_64QAM
Specifies 64QAM demodulator type.
BDA_MOD_80QAM
Specifies 80QAM demodulator type.
BDA_MOD_96QAM
Specifies 96QAM demodulator type.
BDA_MOD_112QAM
Specifies 112QAM demodulator type.
BDA_MOD_128QAM
Specifies 128QAM demodulator type.
BDA_MOD_160QAM
Specifies 160QAM demodulator type.
BDA_MOD_192QAM
Specifies 192QAM demodulator type.
BDA_MOD_224QAM
Specifies 224QAM demodulator type.
BDA_MOD_256QAM
Specifies 256QAM demodulator type.
BDA_MOD_320QAM
Specifies 320QAM demodulator type.
BDA_MOD_384QAM
Specifies 384QAM demodulator type.
BDA_MOD_448QAM
Specifies 448QAM demodulator type.
BDA_MOD_512QAM
Specifies 512QAM demodulator type.
BDA_MOD_640QAM
Specifies 640QAM demodulator type.
BDA_MOD_768QAM
Specifies 768QAM demodulator type.
BDA_MOD_896QAM
Specifies 896QAM demodulator type.
BDA_MOD_1024QAM
Specifies 1024QAM demodulator type.
BDA_MOD_QPSK
Specifies QPSK demodulator type.
BDA_MOD_BPSK
Specifies BPSK demodulator type.
BDA_MOD_OQPSK
Specifies OQPSK demodulator type.
BDA_MOD_8VSB
Specifies 8VSB demodulator type.
BDA_MOD_16VSB
Specifies 16VSB demodulator type.
BDA_MOD_ANALOG_AMPLITUDE
Specifies amplitude-modulated demodulator type.
BDA_MOD_ANALOG_FREQUENCY
Specifies frequency-modulated demodulator type.
BDA_MOD_MAX
Maximum value in the enumeration exceeded.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.

See Also

KSPROPSETID_BdaDigitalDemodulator


MPEG2StreamType

The MPEG2StreamType enumeration contains values that specify an MPEG2 substream of the received broadcast stream.

typedef V1_ENUM enum MPEG2StreamType {
    BDA_UNITIALIZED_MPEG2STREAMTYPE = -1,
    Reserved1 = 0x0,
    ISO_IEC_11172_2_VIDEO     = Reserved1 + 1,
    ISO_IEC_13818_2_VIDEO     = ISO_IEC_11172_2_VIDEO + 1,
    ISO_IEC_11172_3_AUDIO     = ISO_IEC_13818_2_VIDEO + 1,
    ISO_IEC_13818_3_AUDIO     = ISO_IEC_11172_3_AUDIO + 1,
    ISO_IEC_13818_1_PRIVATE_SECTION =
                              ISO_IEC_13818_3_AUDIO + 1,
    ISO_IEC_13818_1_PES       =
                     ISO_IEC_13818_1_PRIVATE_SECTION + 1,
    ISO_IEC_13522_MHEG        = ISO_IEC_13818_1_PES + 1,
    ANNEX_A_DSM_CC            = ISO_IEC_13522_MHEG + 1,
    ITU_T_REC_H_222_1         = ANNEX_A_DSM_CC + 1,
    ISO_IEC_13818_6_TYPE_A    = ITU_T_REC_H_222_1 + 1,
    ISO_IEC_13818_6_TYPE_B    = ISO_IEC_13818_6_TYPE_A + 1,
    ISO_IEC_13818_6_TYPE_C    = ISO_IEC_13818_6_TYPE_B + 1,
    ISO_IEC_13818_6_TYPE_D    = ISO_IEC_13818_6_TYPE_C + 1,
    ISO_IEC_13818_1_AUXILIARY = ISO_IEC_13818_6_TYPE_D + 1,
    ISO_IEC_13818_1_RESERVED =
                            ISO_IEC_13818_1_AUXILIARY + 1,
    USER_PRIVATE            = ISO_IEC_13818_1_RESERVED + 1
} MPEG2StreamType;

Elements

BDA_UNITIALIZED_MPEG2STREAMTYPE
Specifies an MPEG2 stream type that is not initialized.
Reserved1
Reserved
ISO_IEC_11172_2_VIDEO
Specifies an 11172-2 video MPEG2 stream type.
ISO_IEC_13818_2_VIDEO
Specifies an 13818-2 video MPEG2 stream type.
ISO_IEC_11172_3_AUDIO
Specifies an 11172-3 audio MPEG2 stream type.
ISO_IEC_13818_3_AUDIO
Specifies an 13818-3 audio MPEG2 stream type.
ISO_IEC_13818_1_PRIVATE_SECTION
Specifies an 13818-1 private section MPEG2 stream type.
ISO_IEC_13818_1_PES
Specifies an 13818-1 PES MPEG2 stream type.
ISO_IEC_13522_MHEG
Specifies an 13522 MHEG MPEG2 stream type.
ANNEX_A_DSM_CC
Specifies an ANNEX_A_DSM_CC MPEG2 stream type.
ITU_T_REC_H_222_1
Specifies an ITU_T_REC_H_222_1 MPEG2 stream type.
ISO_IEC_13818_6_TYPE_A
Specifies an 13818-6-TYPE-A MPEG2 stream type.
ISO_IEC_13818_6_TYPE_B
Specifies an 13818-6-TYPE-B MPEG2 stream type.
ISO_IEC_13818_6_TYPE_C
Specifies an 13818-6-TYPE-C MPEG2 stream type.
ISO_IEC_13818_6_TYPE_D
Specifies an 13818-6-TYPE-D MPEG2 stream type.
ISO_IEC_13818_1_AUXILIARY
Specifies an 13818-1 auxiliary MPEG2 stream type.
ISO_IEC_13818_1_RESERVED
Specifies an 13818-1-reserved MPEG2 stream type.
USER_PRIVATE
Specifies a user-private MPEG2 stream type.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.


MPEG2_TRANSPORT_STRIDE

The MPEG2_TRANSPORT_STRIDE structure describes the format block of the MPEG2 transport stride.

typedef struct _MPEG2_TRANSPORT_STRIDE {
    DWORD   dwOffset ;
    DWORD   dwPacketLength ;
    DWORD   dwStride ;
} MPEG2_TRANSPORT_STRIDE, *PMPEG2_TRANSPORT_STRIDE ;

Members

dwOffset
Offset in bytes into a packet.
dwPacketLength
Size in bytes of a packet.
dwStride
Stride of data in a packet.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.

Comments

The MPEG2 transport stride format block is associated with the MEDIATYPE_Stream/MEDIASUBTYPE_MPEG2_TRANSPORT_STRIDE media type. Format blocks that are associated with this media type must start with the MPEG2_TRANSPORT_STRIDE structure.


PID_MAP

The PID_MAP structure describes a group of packets in the output stream of a packet identifier (PID) filter. This group consists of packets that are identified with an identical PID and contain particular media content.

typedef struct {
    ULONG                 ulPID ;
    MEDIA_SAMPLE_CONTENT  MediaSampleContent ;
} PID_MAP ;

Members

ulPID
Identifier of particular packets.
MediaSampleContent
MEDIA_SAMPLE_CONTENT enumeration value that specifies the type of media content that packets contain.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.

See Also

BDA_PID_MAP, KSPROPSETID_BdaPIDFilter, MEDIA_SAMPLE_CONTENT


Polarization

The Polarization enumeration contains values that specify the polarity of the broadcast signal.

typedef V1_ENUM enum Polarisation {
    BDA_POLARISATION_NOT_SET = -1,
    BDA_POLARISATION_NOT_DEFINED = 0,
    BDA_POLARISATION_LINEAR_H = 1,
    BDA_POLARISATION_LINEAR_V,
    BDA_POLARISATION_CIRCULAR_L,
    BDA_POLARISATION_CIRCULAR_R,
    BDA_POLARISATION_MAX,
} Polarisation;

Elements

BDA_POLARISATION_NOT_SET
Polarization on the signal is not set.
BDA_POLARISATION_NOT_DEFINED
Polarization on the signal is not defined.
BDA_POLARISATION_LINEAR_H
Polarization on the signal is linear horizontal.
BDA_POLARISATION_LINEAR_V
Polarization on the signal is linear vertical.
BDA_POLARISATION_CIRCULAR_L
Polarization on the signal is circular left.
BDA_POLARISATION_CIRCULAR_R
Polarization on the signal is circular right.
BDA_POLARISATION_MAX
Maximum value in the enumeration exceeded.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.

See Also

KSPROPSETID_BdaFrequencyFilter


SpectralInversion

The SpectralInversion enumeration contains values that specify how spectral inversion is set on a signal demodulator node.

typedef V1_ENUM enum SpectralInversion {
    BDA_SPECTRAL_INVERSION_NOT_SET = -1,
    BDA_SPECTRAL_INVERSION_NOT_DEFINED = 0,
    BDA_SPECTRAL_INVERSION_AUTOMATIC = 1,
    BDA_SPECTRAL_INVERSION_NORMAL,
    BDA_SPECTRAL_INVERSION_INVERTED,
    BDA_SPECTRAL_INVERSION_MAX
} SpectralInversion;

Elements

BDA_SPECTRAL_INVERSION_NOT_SET
Spectral inversion not set.
BDA_SPECTRAL_INVERSION_NOT_DEFINED
Spectral inversion not defined.
BDA_SPECTRAL_INVERSION_AUTOMATIC
Spectral inversion is automatic.
BDA_SPECTRAL_INVERSION_NORMAL
Spectral inversion is normal.
BDA_SPECTRAL_INVERSION_INVERTED
Spectral inversion is inverted.
BDA_SPECTRAL_INVERSION_MAX
Maximum value in the enumeration exceeded.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.

See Also

KSPROPSETID_BdaDigitalDemodulator


TransmissionMode

The TransmissionMode enumeration contains values that specify the carrier frequency of the broadcast transmission.

typedef V1_ENUM enum TransmissionMode {
    BDA_XMIT_MODE_NOT_SET = -1,
    BDA_XMIT_MODE_NOT_DEFINED = 0,
    BDA_XMIT_MODE_2K = 1,
    BDA_XMIT_MODE_8K,
    BDA_XMIT_MODE_MAX,
} TransmissionMode;

Elements

BDA_XMIT_MODE_NOT_SET
Transmission mode not set.
BDA_XMIT_MODE_NOT_DEFINED
Transmission mode not defined.
BDA_XMIT_MODE_2K
Transmission uses 1705 carriers, that is a 2K FFT.
BDA_XMIT_MODE_8K
Transmission uses 6817 carriers, that is an 8K FFT.
BDA_XMIT_MODE_MAX
Maximum value in the enumeration exceeded.

Headers

Defined in Bdatypes.h. Include Bdatypes.h.


Broadcast Driver Architecture Constants

A BDA minidriver uses the following constants:

BDA Filter Category GUIDs
BDA minidrivers use these GUIDs to specify the types of BDA filters to create.
BDA Node Category GUIDs
BDA minidrivers use these GUIDs to specify the types of BDA nodes to create.
BDA Pin Name GUIDs
BDA minidrivers use these GUIDs to specify the names of pins they support.
BDA Stream Format GUIDs
BDA minidrivers use these GUIDs to specify the data formats they support.

Comments

The BDA constants are available on Windows® XP and later. These constants are available on Windows 2000 and Windows 98/Me platforms only if DirectX 8.0 or later is installed on those platforms.


BDA Filter Category GUIDs

A BDA minidriver uses the BDA filter category GUIDs to specify the types of BDA filters to create. A BDA minidriver assigns these GUIDs in the array to which the Categories member of a KSFILTER_DESCRIPTOR structure points. The Bdamedia.h header file defines these GUIDs.

The following filter category GUIDs are available in BDA:

KSCATEGORY_BDA_RECEIVER_COMPONENT
A BDA minidriver assigns this GUID to specify to create a BDA receiver filter.
KSCATEGORY_BDA_NETWORK_TUNER
A BDA minidriver assigns this GUID to specify to create a BDA network tuner filter.
KSCATEGORY_BDA_NETWORK_EPG
A BDA minidriver assigns this GUID to specify to create a BDA electronic program guide (EPG) filter.
KSCATEGORY_BDA_IP_SINK
A BDA minidriver assigns this GUID to specify to create a BDA IP sink filter.
KSCATEGORY_BDA_NETWORK_PROVIDER
A BDA minidriver assigns this GUID to specify to create a BDA network provider filter.
KSCATEGORY_BDA_TRANSPORT_INFORMATION
A BDA minidriver assigns this GUID to specify to create a BDA transport information filter (TIF).


BDA Node Category GUIDs

A BDA minidriver uses the BDA node category GUIDs to specify the types of BDA nodes that are available to create. A BDA minidriver assigns one of these GUIDs in the variable to which the Type member of a KSNODE_DESCRIPTOR structure points. The Bdamedia.h header file defines these GUIDs.

The network provider uses the KSPROPERTY_BDA_NODE_TYPES property of the KSPROPSETID_BdaTopology property set to retrieve a list of nodes types available from the BDA minidriver. This list of node types is an array of KSNODE_DESCRIPTOR structures.

The following node category GUIDs are available in BDA:

KSNODE_BDA_RF_TUNER
A BDA minidriver assigns this GUID to specify that a BDA radio frequency tuner node is available.
KSNODE_BDA_QAM_DEMODULATOR
A BDA minidriver assigns this GUID to specify that a BDA QAM-type demodulator node is available.
KSNODE_BDA_QPSK_DEMODULATOR
A BDA minidriver assigns this GUID to specify that a BDA QPSK-type demodulator node is available.
KSNODE_BDA_8VSB_DEMODULATOR
A BDA minidriver assigns this GUID to specify that a BDA 8VSB-type demodulator node is available.
KSNODE_BDA_OPENCABLE_POD
A BDA minidriver assigns this GUID to specify that a BDA open-cable POD node is available.
KSNODE_BDA_PID_FILTER
A BDA minidriver assigns this GUID to specify that a BDA packet identifier (PID) filter node is available.
KSNODE_BDA_IP_SINK
A BDA minidriver assigns this GUID to specify that a BDA IP sink node is available.


BDA Pin Name GUIDs

A BDA minidriver uses BDA pin name GUIDs to specify the names and categories of pins it supports. A BDA minidriver assigns these GUIDs to the Name and Category members of a KSPIN_DESCRIPTOR structure. The Bdamedia.h header file defines these GUIDs. Pins of filters specify their names and categories to connect to pins of other filters that also specify those names and categories.

The following pin name GUIDs are available in BDA:

PINNAME_BDA_TRANSPORT
Pin name for a BDA transport pin.
PINNAME_BDA_ANALOG_VIDEO
Pin name for a BDA analog video pin.
PINNAME_BDA_ANALOG_AUDIO
Pin name for a BDA analog audio pin.
PINNAME_BDA_FM_RADIO
Pin name for a BDA FM radio pin.
PINNAME_BDA_IF_PIN
Pin name for a BDA intermediate frequency pin.
PINNAME_BDA_OPENCABLE_PSIP_PIN
Pin name for a BDA Open Cable PSIP pin.
PINNAME_IPSINK_INPUT
Pin name for an input pin to a BDA IP sink node (KSNODE_BDA_IP_SINK).
PINNAME_MPE
Pin name for a multiprotocol encapsulation (MPE) pin.


BDA Stream Format GUIDs

A BDA minidriver uses BDA stream format GUIDs to specify the data formats it supports. A BDA minidriver assigns these GUIDs to members of a KSDATARANGE structure. The Bdamedia.h header file defines these GUIDs. Pins of filters specify the ranges of data formats they support to connect to pins of other filters that also support those ranges.

The following stream GUIDs are available in BDA:

KSDATAFORMAT_TYPE_BDA_ANTENNA
A BDA minidriver assigns this GUID to the MajorFormat member of the DataRange member of a KS_DATARANGE_BDA_ANTENNA structure to enable connecting to a specific upstream filter, such as a network provider filter.
KSDATAFORMAT_SUBTYPE_BDA_MPEG2_TRANSPORT
A BDA minidriver assigns this GUID to the SubFormat member of a KSDATARANGE structure to enable connecting to a pin of a filter that also assigns this sub format.
KSDATAFORMAT_SPECIFIER_BDA_TRANSPORT
A BDA minidriver assigns this GUID to the Specifier member of either a KSDATARANGE structure or the DataRange member of a KS_DATARANGE_BDA_TRANSPORT structure to enable connecting to a pin of a filter that also assigns this specifier.
KSDATAFORMAT_TYPE_BDA_IF_SIGNAL
A BDA minidriver assigns this GUID to the MajorFormat member of a KSDATARANGE structure to enable connecting to a pin of a filter that also assigns this major format.
KSDATAFORMAT_TYPE_MPEG2_SECTIONS
A BDA minidriver assigns this GUID to the MajorFormat member of a KSDATARANGE structure to enable connecting to a pin of a filter that also assigns this major format.
KSDATAFORMAT_SUBTYPE_ATSC_SI
A BDA minidriver assigns this GUID to the SubFormat member of a KSDATARANGE structure to enable connecting to a pin of a filter that also assigns this sub format.
KSDATAFORMAT_SUBTYPE_DVB_SI
A BDA minidriver assigns this GUID to the SubFormat member of a KSDATARANGE structure to enable connecting to a pin of a filter that also assigns this sub format.
KSDATAFORMAT_SUBTYPE_BDA_OPENCABLE_PSIP
A BDA minidriver assigns this GUID to the SubFormat member of a KSDATARANGE structure to enable connecting to a pin of a filter that also assigns this sub format.
KSDATAFORMAT_SUBTYPE_BDA_OPENCABLE_OOB_PSIP
A BDA minidriver assigns this GUID to the SubFormat member of a KSDATARANGE structure to enable connecting to a pin of a filter that also assigns this sub format.
KSDATAFORMAT_TYPE_BDA_IP
A BDA minidriver assigns this GUID to the MajorFormat member of a KSDATARANGE structure to enable connecting to a pin of a filter that also assigns this major format.
KSDATAFORMAT_SUBTYPE_BDA_IP
A BDA minidriver assigns this GUID to the SubFormat member of a KSDATARANGE structure to enable connecting to a pin of a filter that also assigns this sub format.
KSDATAFORMAT_SPECIFIER_BDA_IP
A BDA minidriver assigns this GUID to the Specifier member of either a KSDATARANGE structure to enable connecting to a pin of a filter that also assigns this specifier.
KSDATAFORMAT_TYPE_BDA_IP_CONTROL
A BDA minidriver assigns this GUID to the MajorFormat member of a KSDATARANGE structure to enable connecting to a pin of a filter that also assigns this major format.
KSDATAFORMAT_SUBTYPE_BDA_IP_CONTROL
A BDA minidriver assigns this GUID to the SubFormat member of a KSDATARANGE structure to enable connecting to a pin of a filter that also assigns this sub format.
KSDATAFORMAT_TYPE_MPE
A BDA minidriver assigns this GUID to the MajorFormat member of a KSDATARANGE structure to enable connecting to a pin of a filter that also assigns this major format.


AV/C Protocol Driver Function Codes

An AV/C subunit driver communicates with its device by submitting IRPs down the device stack to the AV/C protocol driver, avc.sys.

To make I/O requests, include the header file avc.h, which is shipped with the Microsoft® Windows® DDK.


IOCTL_AVC_CLASS

The IOCTL_AVC_CLASS I/O control code is supported only from kernel mode, using the IRP_MJ_INTERNAL_DEVICE_CONTROL dispatch.

Avc.sys supports two device interfaces, depending upon the type of instance (peer or virtual). These interfaces define the functionality that the driver exposes for subunit drivers, other drivers, and applications. During initialization, avc.sys calls IoRegisterDeviceInterface with either GUID_AVC_CLASS (a peer, or non-virtual instance) or GUID_VIRTUAL_AVC_CLASS (a virtual instance), then uses IoSetDeviceInterfaceState as appropriate for the started or stopped state of the driver.

Peer instances of avc.sys register the device interface identified by GUID_AVC_CLASS. This interface supports one I/O control code, IOCTL_AVC_CLASS, which in turn supports multiple function codes. Child drivers of peer avc.sys instances are guaranteed to have access to this interface through their parent device object.

Virtual instances of avc.sys register the device interface identified by GUID_VIRTUAL_AVC_CLASS. This interface supports four I/O control codes:

  • IOCTL_AVC_CLASS
  • IOCTL_AVC_UPDATE_VIRTUAL_SUBUNIT_INFO
  • IOCTL_AVC_REMOVE_VIRTUAL_SUBUNIT_INFO
  • IOCTL_AVC_BUS_RESET

The GUID_AVC_CLASS interface supports all IOCTL_AVC_CLASS function codes, although some have limitation on their use. However, the GUID_VIRTUAL_AVC_CLASS interface does not support all IOCTL_AVC_CLASS function codes. The reference page for each individual function code specifies whether it is supported for GUID_VIRTUAL_AVC_CLASS instances of avc.sys.

The IOCTL_AVC_CLASS function codes (and any restrictions) are described in each function code.

For more information about IRPs and IOCTLs, see Handling IRPs.

Input

Parameters->Others.Argument1 points to either an AVC_COMMAND_IRB structure or AVC_MULTIFUNC_IRB structure. Both structures contain an AVC_IRB structure as a header, as illustrated in the following example:

typedef struct _AVC_COMMAND_IRB {
  AVC_IRB  Common;
  .
  .
  .
} AVC_COMMAND_IRB, *PAVC_COMMAND_IRB;
typedef struct _AVC_MULTIFUNC_IRB {
  AVC_IRB  Common;
  .
  .
  .
} AVC_MULTIFUNC_IRB, *PAVC_MULTIFUNC_IRB;

The AVC_IRB structure contains a single Function member. This member must be set to the desired function code from the AVC_FUNCTION enumeration.

The AVC_MULTIFUNC_IRB structure contains a union member that specifies the function I/O request block type-specific parameters for the function code. The parameters and their meanings are documented with each function code.

Output

Parameters->Others.Argument1 points to the same AVC_COMMAND_IRB or AVC_MULTIFUNC_IRB structure that was passed as input. As part of completing the function, the subunit driver fills in certain submembers of the union within the structure with information for the driver. The returned information is documented with each request.

I/O Status Block

The information the AV/C protocol driver returns in the I/O Status Block (Irp->IoStatus.Status) is documented with each request.

See Also

AVC_COMMAND_IRB, AVC_MULTIFUNC_IRB, AVC_IRB, IOCTL_AVC_UPDATE_VIRTUAL_SUBUNIT_INFO, IOCTL_AVC_REMOVE_VIRTUAL_SUBUNIT_INFO, IOCTL_AVC_BUS_RESET, AVC_FUNCTION


AVC_FUNCTION_COMMAND

The AVC_FUNCTION_COMMAND function code is used to send an AV/C request and receive a response as one operation.

I/O Status Block

If successful, the AV/C protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

Possible error return values include:

Error Status | Description
STATUS_TIMEOUT | The request was made, but no response was received before all timeout and retry processing was complete. The target device ignores requests if a previous request is still being processed. Some AV/C devices are non-compliant, and refuse to respond within the 100ms timeout, even after several successive attempts. The AVC_COMMAND_IRB structure permits the adjustment of the default Timeout and Retries members (100ms and 9, respectively), but these default settings have been sufficient for all known implementations.
STATUS_PENDING | The request was made, and an interim response was received. It is the responsibility of the completion routine to handle the final response and free the IRP and IRB resources.
STATUS_REQUEST_ABORTED | When submitting AV/C requests, immediately abort when the IRP completion status is STATUS_REQUEST_ABORTED.
STATUS_* | Any other return code indicates that an error occurred that was beyond the scope of the AV/C protocol.

Headers

Declared in avc.h. Include avc.h.

Comments

This function uses the AVC_COMMAND_IRB structure as shown below.

typedef struct _AVC_COMMAND_IRB {
  AVC_IRB  Common;
  UCHAR  SubunitAddrFlag : 1;
  UCHAR  AlternateOpcodesFlag : 1;
  UCHAR  TimeoutFlag : 1;
  UCHAR  RetryFlag : 1;
  union {
    UCHAR  CommandType;
    UCHAR  ResponseCode;
  };
  PUCHAR  SubunitAddr;
  PUCHAR  AlternateOpcodes;
  LARGE_INTEGER  Timeout;
  UCHAR  Retries;
  UCHAR  Opcode;
  ULONG  OperandLength;
  UCHAR  Operands[MAX_AVC_OPERAND_BYTES];
  NODE_ADDRESS  NodeAddress;
  ULONG  Generation;
} AVC_COMMAND_IRB, *PAVC_COMMAND_IRB;

AVC_COMMAND_IRB Input

Common
The Function submember of this member must be set to AVC_FUNCTION_COMMAND from the AVC_FUNCTION enumeration.
SubunitAddrFlag
Set this to one to override the subunit address that avc.sys associates with the subunit driver. Reasons to override include: the subunit driver represents multiple subunits in a single instance; a unit command must be sent; or the driver was loaded because avc.sys could not determine the subunit type or ID. If this is set, the SubunitAddr member must point to nonpaged memory containing the desired subunit address.

This must be set to one (and the appropriate SubunitAddr supplied) if the caller is submitting requests directly to an avc.sys FDO.

Note: If this flag is not set on request, on response from a successful request, this flag is set, and the SubunitAddr member points to the actual address of the subunit. Do not attempt to alter the contents or free the memory: it is part of the parent driver's device extension. This may, of course, be set back to zero, and the SubunitAddr pointer cleared to reuse the structure for a different subunit.

AlternateOpcodesFlag
Set this to one if the command type and opcode of this request results in a response with a different opcode. Without this, only responses with matching opcodes are accepted. If this is set, the AlternateOpcodes member must pointer to nonpaged memory containing the list of alternate opcodes.
TimeoutFlag
Set this to one if the default timeout is not appropriate for the subunit. If this is set, the Timeout member must be set to the desired timeout (in 100ns units).
RetryFlag
Set this to one if the default retry count is not appropriate for the subunit. If this is set, the Retries member must be set to the desired retry count.
CommandType
On request, this member must be set to one of the enumerators from the AvcCommandType enumeration. This is a required parameter.
ResponseCode
On response, this member is set to a value from the AvcResponseCode enumeration.
SubunitAddr
Set this to the address of nonpaged memory containing the desired subunit address encoded according to Section 5.3.3 of the AV/C Digital Interface Command Set General Specification, Rev 3.0. This specification can be found at www.1394ta.org. No length is necessary because the subunit address encoding implies this. This parameter is ignored if SubunitAddrFlag is zero.
AlternateOpcodes
Set this to the address of nonpaged memory containing the desired alternate opcode list. The first byte of the opcode list is the count of opcodes to follow (equivalent to the number of bytes). The total length of the memory containing the alternate opcode list is AlternateOpcodes[0]+1. This parameter is ignored if AlternateOpcodesFlag is zero.
Timeout
Set this to the desired timeout in 100ns units. For example, the default timeout value is: Timeout.QuadPart = 1000000 (100ms in 100ns units). This parameter is ignored if TimeoutFlag is zero.
Retries
Set this to the desired number of times avc.sys should attempt to retry requests after each timeout without a response. Note that a retry count of zero means that the request is tried once. The total amount of time spent trying to process a command without getting a response is calculated by the following formula:

Timeout * (Retries + 1)

This parameter is ignored if RetryFlag is zero.

Opcode
Set this to the desired AV/C opcode (appropriate for the subunit type). This is a required parameter. On response, if AlternateOpcodesFlag was set, and one of the alternate opcodes was used to match the response, this is set to that alternate opcode.
OperandLength
Set this to the number of bytes used to store the operands in the Operands member. This is a required parameter. On response, this parameter is set to the number of bytes in the operand list used by the response.
Operands
Set this to the operand list appropriate for the subunit type and opcode. This is a required parameter. On response, this parameter contains the operand list of the response.
NodeAddress
Reserved. This must be zero.
Generation
Reserved. This must be zero.

The AVC_FUNCTION_COMMAND function code is not supported by virtual instances of avc.sys. If the caller wishes to control an external device, that device's non-virtual instance can be located through a private mechanism, or through some combination of the AVC_FUNCTION_FIND_PEER_DO, AVC_FUNCTION_PEER_DO_LIST and AVC_FUNCTION_GET_SUBUNIT_INFO function codes of the IOCTL_AVC_CLASS I/O control code.

This structure defines the common components of an AV/C command request. It holds the opcode and operands of a request, and the opcode and operands of a response (upon completion). The size of the operand list is fixed at the maximum allowable number of operands given a one-byte subunit address. If the subunit address is extended in any way, the maximum permissible number of operand bytes is reduced accordingly.

The recommended use of this structure is to first zero the structure (use RtlZeroMemory) before filling in the parameters.

This must be called at IRQL = PASSIVE_LEVEL.

See Also

AVC_FUNCTION, AvcCommandType, AvcResponseCode, AVC_FUNCTION_FIND_PEER_DO, AVC_FUNCTION_PEER_DO_LIST, AVC_FUNCTION_GET_SUBUNIT_INFO


AVC_FUNCTION_GET_PIN_COUNT

The AVC_FUNCTION_GET_PIN_COUNT function code obtains the number of pins supported by the underlying subunit device.

I/O Status Block

If successful, the AV/C protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

Possible error return values include:

Error Status | Description
STATUS_TIMEOUT | The request was made, but no response was received before all timeout and retry processing was complete.
STATUS_REQUEST_ABORTED | Immediately abort when the IRP completion status is STATUS_REQUEST_ABORTED. This indicates that the device has been removed or is no longer available on the 1394 bus.
STATUS_* | Any other return code indicates that an error occurred that was beyond the scope of the AV/C protocol.

Headers

Declared in avc.h. Include avc.h.

Comments

This function uses the PinCount member of the AVC_MULTIFUNC_IRB structure as shown below.

typedef struct _AVC_MULTIFUNC_IRB {
  AVC_IRB  Common;
  union {
    AVC_PIN_COUNT PinCount;
    .
    .
    .
  };
} AVC_MULTIFUNC_IRB, *PAVC_MULTIFUNC_IRB;

AVC_MULTIFUNC_IRB Input

Common
The Function submember of this member must be set to AVC_FUNCTION_GET_PIN_COUNT from the AVC_FUNCTION enumeration.
PinCount
Specifies the number of pins on an AV/C device upon returning from the function.

This function code is not supported by virtual instances of avc.sys.

This must be called at IRQL = PASSIVE_LEVEL.

See Also

AVC_MULTIFUNC_IRB, AVC_PIN_COUNT, AVC_FUNCTION


AVC_FUNCTION_GET_PIN_DESCRIPTOR

The AVC_FUNCTION_GET_PIN_DESCRIPTOR function code obtains the pin descriptor for each pin ID (offset from zero).

I/O Status Block

If successful, the AV/C protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

Possible error return values include:

Error Status | Description
STATUS_TIMEOUT | The request was made, but no response was received before all timeout and retry processing was complete.
STATUS_REQUEST_ABORTED | Immediately abort when the IRP completion status is STATUS_REQUEST_ABORTED. This indicates that the device has been removed or is no longer available on the 1394 bus.
STATUS_* | Any other return code indicates that an error occurred that was beyond the scope of the AV/C protocol.

Headers

Declared in avc.h. Include avc.h.

Comments

This function uses the PinDescriptor member of the AVC_MULTIFUNC_IRB structure as shown below.

typedef struct _AVC_MULTIFUNC_IRB {
  AVC_IRB  Common;
  union {
    .
    .
    .
    AVC_PIN_DESCRIPTOR PinDescriptor;
    .
    .
    .
  };
} AVC_MULTIFUNC_IRB, *PAVC_MULTIFUNC_IRB;

AVC_MULTIFUNC_IRB Input

Common
The Function submember of this member must be set to AVC_FUNCTION_GET_PIN_DESCRIPTOR from the AVC_FUNCTION enumeration.
PinDescriptor
Specifies the description of a pin on an AV/C subunit device.

This function code is not supported by virtual instances of avc.sys.

In addition to the pin descriptor, this function may also return the address of an intersect handler and an opaque context value associated with the intersect handler. If the intersect handler member is NULL, the subunit driver must provide an intersect handler. If the intersect handler member is not NULL, an intersect handler is provided and the driver may use it.

Avc.sys never provides a data intersection, but a filter driver (for example, avcstrm.sys) fills it in as the request is being completed back up through the stack.

This must be called at IRQL = PASSIVE_LEVEL.

See Also

AVC_MULTIFUNC_IRB, AVC_PIN_DESCRIPTOR, AVC_FUNCTION, KSPIN_DESCRIPTOR, AV/C Intersect Handler


AVC_FUNCTION_GET_CONNECTINFO

The AVC_FUNCTION_GET_CONNECT_INFO function code obtains the AVCPRECONNECTINFO structure for each pin ID (offset from zero).

I/O Status Block

If successful, the AV/C protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

Possible error return values include:

Error Status | Description
STATUS_TIMEOUT | The request was made, but no response was received before all timeout and retry processing was complete.
STATUS_REQUEST_ABORTED | Immediately abort when the IRP completion status is STATUS_REQUEST_ABORTED. This indicates that the device has been removed or is no longer available on the 1394 bus.
STATUS_* | Any other return code indicates that an error occurred that was beyond the scope of the AV/C protocol.

Headers

Declared in avc.h. Include avc.h.

Comments

This function uses the PreConnectInfo member of the AVC_MULTIFUNC_IRB structure as shown below.

typedef struct _AVC_MULTIFUNC_IRB {
  AVC_IRB  Common;
  union {
    .
    .
    .
    AVC_PRECONNECT_INFO PreConnectInfo;
    .
    .
    .
  };
} AVC_MULTIFUNC_IRB, *PAVC_MULTIFUNC_IRB;

The members of the AVC_PRECONNECT_INFO structure are shown below:

typedef struct _AVC_PRECONNECT_INFO {
    IN ULONG PinId
    OUT AVCPRECONNECTINFO ConnectInfo;
} AVC_PRECONNECT_INFO, *PAVC_PRECONNECT_INFO;

AVC_MULTIFUNC_IRB Input

Common
The Function submember of this member must be set to AVC_FUNCTION_GET_CONNECTINFO from the AVC_FUNCTION enumeration.
ConnectInfo
Specifies the connection information for the AV/C device.

This function code is not supported by virtual instances of avc.sys.

A subunit driver must use this function if it is responsible for creating the data ranges included in the KSPIN_DESCRIPTOR structure. The AVCPRECONNECTINFO structure is appended to the DataRanges member for connections external to the PC.

This must be called at IRQL = PASSIVE_LEVEL.

See Also

AVC_MULTIFUNC_IRB, AVC_PRECONNECT_INFO, AVCPRECONNECTINFO, AVC_FUNCTION


AVC_FUNCTION_SET_CONNECTINFO

The AVC_FUNCTION_SET_CONNECT_INFO function code sets the AVCCONNECTINFO structure for each pin ID (offset from zero).

I/O Status Block

If successful, the AV/C protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

Possible error return values include:

Error Status | Description
STATUS_TIMEOUT | The request was made, but no response was received before all timeout and retry processing was complete.
STATUS_REQUEST_ABORTED | Immediately abort when the IRP completion status is STATUS_REQUEST_ABORTED. This indicates that the device has been removed or is no longer available on the 1394 bus.
STATUS_* | Any other return code indicates that an error occurred that was beyond the scope of the AV/C protocol.

Headers

Declared in avc.h. Include avc.h.

Comments

This function uses the SetConnectInfo member of the AVC_MULTIFUNC_IRB structure as shown below.

typedef struct _AVC_MULTIFUNC_IRB {
  AVC_IRB  Common;
  union {
    .
    .
    .
    AVC_SETCONNECT_INFO SetConnectInfo;
    .
    .
    .
  };
} AVC_MULTIFUNC_IRB, *PAVC_MULTIFUNC_IRB;

AVC_MULTIFUNC_IRB Input

Common
The Function submember of this member must be set to AVC_FUNCTION_SET_CONNECTINFO from the AVC_FUNCTION enumeration.
SetConnectInfo
Specifies the connection information for the AV/C device.

This function code is not supported by virtual instances of avc.sys.

A subunit driver must use this function if it provides an intersect handler. The AVCCONNECTINFO structure (contained inside the AVC_SET_CONNECTINFO structure) is derived from the AVCPRECONNECTINFO structures that are appended to the data ranges passed to the intersect handler.

After determining that the data ranges are compatible, the intersect handler generates an AVCCONNECTINFO structure. This structure is appended to the resulting data format, and also sent to avc.sys. It does not matter if the proposed data format is passed up for a better one later, because avc.sys only caches one AVCCONNECTINFO structure.

This must be called at IRQL = PASSIVE_LEVEL.

See Also

AVC_MULTIFUNC_IRB, AVC_SETCONNECT_INFO, AVCCONNECTINFO, AVC_FUNCTION, AV/C Intersect Handler


AVC_FUNCTION_ACQUIRE

The AVC_FUNCTION_ACQUIRE function code causes avc.sys to establish any connections suggested by cached AVCCONNECTINFO values.

I/O Status Block

If successful, the AV/C protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

Possible error return values include:

Error Status | Description
STATUS_TIMEOUT | The request was made, but no response was received before all timeout and retry processing was complete.
STATUS_REQUEST_ABORTED | Immediately abort when the IRP completion status is STATUS_REQUEST_ABORTED. This indicates that the device has been removed or is no longer available on the 1394 bus.
STATUS_* | Any other return code indicates that an error occurred that was beyond the scope of the AV/C protocol.

Headers

Declared in avc.h. Include avc.h.

Comments

This function uses the PinId member of the AVC_MULTIFUNC_IRB structure as shown below.

typedef struct _AVC_MULTIFUNC_IRB {
  AVC_IRB  Common;
  union {
    .
    .
    .
    AVC_PIN_ID PinId;
    .
    .
    .
  };
} AVC_MULTIFUNC_IRB, *PAVC_MULTIFUNC_IRB;

AVC_MULTIFUNC_IRB Input

Common
The Function submember of this member must be set to AVC_FUNCTION_ACQUIRE from the AVC_FUNCTION enumeration.
PinId
Specifies the offset (or ID) of the pin for which a connection is to be acquired.

This function code is not supported by virtual instances of avc.sys.

A subunit driver must use this function when the pin becomes active.

This must be called at IRQL = PASSIVE_LEVEL.

See Also

AVC_MULTIFUNC_IRB, AVC_PIN_ID, AVC_FUNCTION


AVC_FUNCTION_RELEASE

The AVC_FUNCTION_RELEASE function code causes avc.sys to release any connections suggested by cached AVCCONNECTINFO values.

I/O Status Block

If successful, the AV/C protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

Possible error return values include:

Error Status | Description
STATUS_TIMEOUT | The request was made, but no response was received before all timeout and retry processing was complete.
STATUS_REQUEST_ABORTED | Immediately abort when the IRP completion status is STATUS_REQUEST_ABORTED. This indicates that the device has been removed or is no longer available on the 1394 bus.
STATUS_* | Any other return code indicates that an error occurred that was beyond the scope of the AV/C protocol.

Headers

Declared in avc.h. Include avc.h.

Comments

This function uses the PinId member of the AVC_MULTIFUNC_IRB structure as shown below.

typedef struct _AVC_MULTIFUNC_IRB {
  AVC_IRB  Common;
  union {
    .
    .
    .
    AVC_PIN_ID PinId;
    .
    .
    .
  };
} AVC_MULTIFUNC_IRB, *PAVC_MULTIFUNC_IRB;

AVC_MULTIFUNC_IRB Input

Common
The Function submember of this member must be set to AVC_FUNCTION_RELEASE from the AVC_FUNCTION enumeration.
PinId
Specifies the offset (or ID) of the pin for which a connection is to be released.

This function code is not supported by virtual instances of avc.sys.

A subunit driver must use this function when the pin becomes inactive.

This must be called at IRQL = PASSIVE_LEVEL.

See Also

AVC_MULTIFUNC_IRB, AVC_PIN_ID, AVC_FUNCTION


AVC_FUNCTION_CLR_CONNECTINFO

The AVC_FUNCTION_CLR_CONNECT_INFO function code causes avc.sys to remove any cached AVCCONNECTINFO values.

I/O Status Block

If successful, the AV/C protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

Possible error return values include:

Error Status | Description
STATUS_TIMEOUT | The request was made, but no response was received before all timeout and retry processing was complete.
STATUS_REQUEST_ABORTED | Immediately abort when the IRP completion status is STATUS_REQUEST_ABORTED. This indicates that the device has been removed or is no longer available on the 1394 bus.
STATUS_* | Any other return code indicates that an error occurred that was beyond the scope of the AV/C protocol.

Headers

Declared in avc.h. Include avc.h.

Comments

This function uses the PinId member of the AVC_MULTIFUNC_IRB structure as shown below.

typedef struct _AVC_MULTIFUNC_IRB {
  AVC_IRB  Common;
  union {
    .
    .
    .
    AVC_PIN_ID PinId;
    .
    .
    .
  };
} AVC_MULTIFUNC_IRB, *PAVC_MULTIFUNC_IRB;

AVC_MULTIFUNC_IRB Input

Common
The Function submember of this member must be set to AVC_FUNCTION_CLR_CONNECTINFO from the AVC_FUNCTION enumeration.
PinId
Specifies the offset (or ID) of the pin for which a connection is to be released.

This function code is not supported by virtual instances of avc.sys.

A subunit driver must use this function when the plug connections should no longer be made, even if the pin becomes "active" again.

This must be called at IRQL = PASSIVE_LEVEL.

See Also

AVC_MULTIFUNC_IRB, AVC_PIN_ID, AVC_FUNCTION


AVC_FUNCTION_GET_EXT_PLUG_COUNTS

The AVC_FUNCTION_GET_EXT_PLUG_COUNTS function code obtains the external input and output plug counts.

I/O Status Block

If successful, the AV/C protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

Possible error return values include:

Error Status | Description
STATUS_TIMEOUT | The request was made, but no response was received before all timeout and retry processing was complete.
STATUS_REQUEST_ABORTED | Immediately abort when the IRP completion status is STATUS_REQUEST_ABORTED. This indicates that the device has been removed or is no longer available on the 1394 bus.
STATUS_* | Any other return code indicates that an error occurred that was beyond the scope of the AV/C protocol.

Headers

Declared in avc.h. Include avc.h.

Comments

This function uses the ExtPlugCounts member of the AVC_MULTIFUNC_IRB structure as shown below.

typedef struct _AVC_MULTIFUNC_IRB {
  AVC_IRB  Common;
  union {
    .
    .
    .
    AVC_EXT_PLUG_COUNTS ExtPlugCounts;
    .
    .
    .
  };
} AVC_MULTIFUNC_IRB, *PAVC_MULTIFUNC_IRB;

AVC_MULTIFUNC_IRB Input

Common
The Function submember of this member must be set to AVC_FUNCTION_GET_EXT_PLUG_COUNTS from the AVC_FUNCTION enumeration.
ExtPlugCounts
Specifies the count of external input and output plugs.

This function code is not supported by virtual instances of avc.sys.

Subunit drivers are responsible for determining the function, format, and use of external plugs. Avc.sys does, however, report any permanent connections between external plugs and subunit plugs as dedicated pins on the subunit (for more information, see AVC_FUNCTION_GET_CONNECTINFO).

This must be called at IRQL = PASSIVE_LEVEL.

See Also

AVC_MULTIFUNC_IRB, AVC_EXT_PLUG_COUNTS, AVC_FUNCTION


AVC_FUNCTION_GET_UNIQUE_ID

The AVC_FUNCTION_GET_UNIQUE_ID function code obtains the unique ID of the AV/C unit.

I/O Status Block

If successful, the AV/C protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

Possible error return values include:

Error Status | Description
STATUS_TIMEOUT | The request was made, but no response was received before all timeout and retry processing was complete.
STATUS_REQUEST_ABORTED | Immediately abort when the IRP completion status is STATUS_REQUEST_ABORTED. This indicates that the device has been removed or is no longer available on the 1394 bus.
STATUS_* | Any other return code indicates that an error occurred that was beyond the scope of the AV/C protocol.

Headers

Declared in avc.h. Include avc.h.

Comments

This function uses the UniqueId member of the AVC_MULTIFUNC_IRB structure as shown below.

typedef struct _AVC_MULTIFUNC_IRB {
  AVC_IRB  Common;
  union {
    .
    .
    .
    AVC_UNIQUE_ID UniqueID;
    .
    .
    .
  };
} AVC_MULTIFUNC_IRB, *PAVC_MULTIFUNC_IRB;

The members of the AVC_UNIQUE_ID structure are shown below:

typedef struct _AVC_UNIQUE_ID {
    OUT GUID DeviceID;
} AVC_UNIQUE_ID, *PAVC_UNIQUE_ID;

AVC_MULTIFUNC_IRB Input

Common
The Function submember of this member must be set to AVC_FUNCTION_GET_UNIQUE_ID from the AVC_FUNCTION enumeration.
UniqueID
Specifies a GUID representing the unit as a whole. All subunits within the same unit share the same GUID. No two units share the same GUID.

This function code is not supported by virtual instances of avc.sys.

The subunit driver uses this function if it must report the device GUID to a controlling application (an application that must know which of the many subunit driver instances belong in the same unit), or if it is building its own AVCPRECONNECTINFO structures for external plugs.

This must be called at IRQL = PASSIVE_LEVEL.

See Also

AVC_MULTIFUNC_IRB, AVC_UNIQUE_ID, AVCPRECONNECTINFO, AVC_FUNCTION


AVC_FUNCTION_GET_REQUEST

The AVC_FUNCTION_GET_REQUEST function code is used to register to receive AV/C unit and subunit requests.

I/O Status Block

This function always sets Irp->IoStatus.Status to STATUS_PENDING.

Headers

Declared in avc.h. Include avc.h.

Comments

This function uses the AVC_COMMAND_IRB structure as shown below.

typedef struct _AVC_COMMAND_IRB {
  AVC_IRB  Common;
  UCHAR  SubunitAddrFlag : 1;
  UCHAR  AlternateOpcodesFlag : 1;
  UCHAR  TimeoutFlag : 1;
  UCHAR  RetryFlag : 1;
  union {
    UCHAR  CommandType;
    UCHAR  ResponseCode;
  };
  PUCHAR  SubunitAddr;
  PUCHAR  AlternateOpcodes;
  LARGE_INTEGER  Timeout;
  UCHAR  Retries;
  UCHAR  Opcode;
  ULONG  OperandLength;
  UCHAR  Operands[MAX_AVC_OPERAND_BYTES];
  NODE_ADDRESS  NodeAddress;
  ULONG  Generation;
} AVC_COMMAND_IRB, *PAVC_COMMAND_IRB;

AVC_COMMAND_IRB Input

Common
The Function submember of this member must be set to AVC_FUNCTION_GET_REQUEST from the AVC_FUNCTION enumeration.
SubunitAddrFlag
Used only when registering to receive unit commands. Set this to 1 and provide a Unit Address in the SubunitAddr parameter. Note that for subunit requests, on completion this is set to 1, and the SubunitAddr parameter points to memory containing the subunit address for this virtual subunit instance. The caller may access this non-paged memory, but must not attempt to free it.
AlternateOpcodesFlag
Used only when registering to receive unit commands. Set this to 1 and provide a list of opcodes supported by the caller in the AlternateOpcodes parameter.
TimeoutFlag
Ignored.
RetryFlag
Ignored.
CommandType
Ignored in input. On output, the CommandType member is set to one of the values from the AvcCommandType enumeration.
ResponseCode
Ignored for requests.
SubunitAddr
Used only when registering to receive unit commands. Set this to the address of non-paged memory containing the Unit Address encoded according to Section 5.3.3 of the AV/C Digital Interface Command Set General Specification, Rev 3.0 (0xff). This specification can be found at www.1394ta.org . Note that for subunit requests, on completion this points to memory containing the subunit address for this virtual subunit instance. The caller may access this non-paged memory, but must not attempt to free it.
AlternateOpcodes
Used only when registering to receive unit commands. Set this to the address of non-paged memory containing the list of unit opcodes supported by the caller. The first byte of the opcode list is the count of opcodes to follow (equivalent to the number of bytes). The total length of the memory containing the alternate opcode list is AlternateOpcodes[0]+1.
Timeout
Ignored.
Retries
Ignored.
Opcode
Ignored on input. On output, this contains an AV/C unit opcode. This is one of the opcodes specified through AlternateOpcodes.
OperandLength
Ignored on input. On output, this is set to the number of bytes in the operand list used by the request.
Operands
Ignored on input. On output, this parameter contains the operand list of the request.
NodeAddress
Ignored on input. On output, this is set to the node address of the source of the request. This parameter is used when sending the response (for more information, see AVC_FUNCTION_SEND_RESPONSE).
Generation
Ignored on input. On output, this is set to the generation count in force when the node address was considered valid. This parameter is used when sending the response (for more information, see AVC_FUNCTION_SEND_RESPONSE).

In the context of the GUID_AVC_CLASS Device Interface, the AVC_FUNCTION_GET_REQUEST function code is used to register to receive AV/C unit requests only (not subunit requests). This function generally is used by an upper filter driver (of the avc.sys FDO) to support peer device functionality (that is, to handle unit requests from the target device from the non-virtual stack). Although nothing prevents subunit drivers from registering to handle unit requests, subunit driver instances registering to support the same unit opcodes must cooperate with each other to share state information. Avc.sys does not directly support multiple registrations for the same unit opcodes.

This function uses the AVC_COMMAND_IRB structure. This structure defines the common components of an AV/C command request. The only valid input parameters are SubunitAddrFlag, AlternateOpcodesFlag, AlternateOpcodes and SubunitAddr, and all are required. AlternateOpcodes must point to a buffer containing the list of unit opcodes supported by the caller. SubunitAddr must point to a buffer containing a unit address (0xff).

In the case of virtual instances of avc.sys (that is, instances that register the GUID_VIRTUAL_AVC_CLASS device interface) AVC_FUNCTION_GET_REQUEST is used to register to receive AV/C unit and subunit requests. Upper filter drivers (of the virtual avc.sys FDO) generally register to handle unit requests, while subunit drivers register to handle requests for their particular type of subunit. Although nothing prevents subunit drivers from registering to handle unit requests, subunit driver instances registering to support the same unit opcodes must cooperate with each other to share state information. Avc.sys does not directly support multiple registrations for the same unit opcodes.

Subunit drivers do not set any input parameters when registering to receive subunit-specific requests.

This function always returns STATUS_PENDING, so any processing must be carried out in a completion routine. On completion, the AVC_COMMAND_IRB structure holds the opcode and operands of a request. The AV/C protocol requires that a response be sent within 100ms. This may be done from the completion routine by using the AVC_FUNCTION_SEND_RESPONSE function code, which also always returns STATUS_PENDING.

If the first response uses the AVC_RESPONSE_INTERIM response code (from the AvcResponseType enumeration), then follow-up processing is expected. The NodeAddress and Generation members, obtained by the completion of the AVC_FUNCTION_GET_REQUEST original function, must be used in subsequent responses. In any case, the next AVC_FUNCTION_GET_REQUEST function should be submitted before returning from the initial AVC_FUNCTION_SEND_RESPONSE completion routine, so that the next unit request may be received.

The recommended use of this structure is to first zero the structure (use RtlZeroMemory) before filling in the parameters.

This must be called at IRQL <= DISPATCH_LEVEL.

See Also

AVC_FUNCTION_SEND_RESPONSE, AvcResponseCode, AVC_FUNCTION, RtlZeroMemory


AVC_FUNCTION_SEND_RESPONSE

The AVC_FUNCTION_SEND_RESPONSE function code is used to respond to AV/C unit and subunit requests.

I/O Status Block

This function always sets Irp->IoStatus.Status to STATUS_PENDING.

Headers

Declared in avc.h. Include avc.h.

Comments

This function uses the AVC_COMMAND_IRB structure as shown below.

typedef struct _AVC_COMMAND_IRB {
  AVC_IRB  Common;
  UCHAR  SubunitAddrFlag : 1;
  UCHAR  AlternateOpcodesFlag : 1;
  UCHAR  TimeoutFlag : 1;
  UCHAR  RetryFlag : 1;
  union {
    UCHAR  CommandType;
    UCHAR  ResponseCode;
  };
  PUCHAR  SubunitAddr;
  PUCHAR  AlternateOpcodes;
  LARGE_INTEGER  Timeout;
  UCHAR  Retries;
  UCHAR  Opcode;
  ULONG  OperandLength;
  UCHAR  Operands[MAX_AVC_OPERAND_BYTES];
  NODE_ADDRESS  NodeAddress;
  ULONG  Generation;
} AVC_COMMAND_IRB, *PAVC_COMMAND_IRB;

AVC_COMMAND_IRB Input

Common
The Function submember of this member must be set to AVC_FUNCTION_SEND_RESPONSE from the AVC_FUNCTION enumeration.
SubunitAddrFlag
Set to the value obtained from the AVC_FUNCTION_GET_REQUEST completion.
AlternateOpcodesFlag
Ignored.
TimeoutFlag
Ignored.
RetryFlag
Ignored.
CommandType
Ignored for responses.
ResponseCode
This member must be set to one of the values from the AvcResponseCode enumeration.
SubunitAddr
Set to the value obtained from the AVC_FUNCTION_GET_REQUEST completion.
AlternateOpcodes
Ignored.
Timeout
Ignored.
Retries
Ignored.
Opcode
This must contain the AV/C unit opcode appropriate for the response (may be different than the opcode provided in the original request).
OperandLength
Set to the number of bytes in the operand list of the response.
Operands
The operand list of the response.
NodeAddress
The node address of the source of the original request.
Generation
The generation ID obtained from the original request.

In the context of the GUID_AVC_CLASS device interface, the AVC_FUNCTION_SEND_RESPONSE function code is used to respond only to AV/C unit requests.

In the case of virtual instances of avc.sys (that is, instances that register the GUID_VIRTUAL_AVC_CLASS device interface), the AVC_FUNCTION_SEND_RESPONSE function code is used to respond to AV/C unit and subunit requests.

This function always returns STATUS_PENDING, so any processing must be carried out in a completion routine. On completion, the AVC_COMMAND_IRB structure holds the opcode and operands of a request. The AV/C protocol requires that a response be sent within 100ms. This may be done from the completion routine by using the AVC_FUNCTION_SEND_RESPONSE function code, which also always returns STATUS_PENDING.

If the first response uses the AVC_RESPONSE_INTERIM response code (from the AvcResponseType enumeration), then follow-up processing is expected. The NodeAddress and Generation members, obtained by the completion of the AVC_FUNCTION_GET_REQUEST original function, must be used in subsequent responses. In any case, the next AVC_FUNCTION_GET_REQUEST function should be submitted before returning from the initial AVC_FUNCTION_SEND_RESPONSE completion routine, so that the next unit request may be received.

The recommended use of this structure is to use the contents of the original request, and update the Opcode, OperandLength, and Operands members as appropriate for the response.

This must be called at IRQL <= DISPATCH_LEVEL.

See Also

AVC_FUNCTION_GET_REQUEST, AvcResponseCode, AVC_FUNCTION


AVC_FUNCTION_FIND_PEER_DO

The AVC_FUNCTION_FIND_PEER_DO function code locates a non-virtual avc.sys instance.

I/O Status Block

If successful, the AV/C protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

Possible error return values include:

Error Status | Description
STATUS_UNSUCCESSFUL | A non-virtual instance of avc.sys was not found
STATUS_INVALID_GENERATION | A bus reset occurred before the Device Object reference could be found. Obtain a new NodeAddress and try again.

Headers

Declared in avc.h. Include avc.h.

Comments

This function uses the PeerLocator member of the AVC_MULTIFUNC_IRB structure as shown below.

typedef struct _AVC_MULTIFUNC_IRB {
  AVC_IRB  Common;
  union {
    .
    .
    .
    AVC_PEER_DO_LOCATOR PeerLocator;
    .
    .
    .
  };
} AVC_MULTIFUNC_IRB, *PAVC_MULTIFUNC_IRB;

AVC_MULTIFUNC_IRB Input

Common
The Function submember of this member must be set to AVC_FUNCTION_FIND_PEER_DO from the AVC_FUNCTION enumeration.
PeerLocator
Specifies the non-virtual (peer) instances of avc.sys.

This function locates a non-virtual avc.sys instance according to the node address of the device it represents. If an instance is not found, the IRP completes with a status of STATUS_UNSUCCESSFUL. Once an instance is located, the caller may submit any GUID_AVC_CLASS Device Interface requests through the object. The caller must release the reference to this object (through ObDereferenceObject) when finished with it.

This must be called at IRQL <= DISPATCH_LEVEL.

See Also

AVC_MULTIFUNC_IRB, AVC_PEER_DO_LOCATOR, AVC_FUNCTION, ObDereferenceObject


AVC_FUNCTION_PEER_DO_LIST

The AVC_FUNCTION_PEER_DO_LIST function code locates all non-virtual avc.sys instances.

I/O Status Block

If successful, the AV/C protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

Possible error return values include:

Error Status | Description
STATUS_INSUFFICIENT_RESOURCES | Could not obtain space for the list of device object references.

Headers

Declared in avc.h. Include avc.h.

Comments

This function uses the PeerList member of the AVC_MULTIFUNC_IRB structure as shown below.

typedef struct _AVC_MULTIFUNC_IRB {
  AVC_IRB  Common;
  union {
    .
    .
    .
    AVC_PEER_DO_LIST PeerList;
    .
    .
    .
  };
} AVC_MULTIFUNC_IRB, *PAVC_MULTIFUNC_IRB;

AVC_MULTIFUNC_IRB Input

Common
The Function submember of this member must be set to AVC_FUNCTION_PEER_DO_LIST from the AVC_FUNCTION enumeration.
PeerList
Specifies a list of all non-virtual (peer) instances of avc.sys.

The caller may submit GUID_AVC_CLASS Device Interface requests through any of the objects returned in the object list. The caller must release the references to these objects (through ObDereferenceObject), and free the memory containing the list (through ExFreePool) when finished.

This must be called at IRQL <= DISPATCH_LEVEL.

See Also

AVC_MULTIFUNC_IRB, AVC_PEER_DO_LIST, AVC_FUNCTION, DEVICE_OBJECT, ObDereferenceObject, ExFreePool


AVC_FUNCTION_GET_SUBUNIT_INFO

The AVC_FUNCTION_GET_SUBUNIT_INFO function code obtains the subunit information of the target device.

I/O Status Block

This function always sets Irp->IoStatus.Status to STATUS_SUCCESS.

Headers

Declared in avc.h. Include avc.h.

Comments

This function uses the Subunits member of the AVC_MULTIFUNC_IRB structure as shown below.

typedef struct _AVC_MULTIFUNC_IRB {
  AVC_IRB  Common;
  union {
    .
    .
    .
    AVC_SUBUNIT_INFO_BLOCK Subunits;
  };
} AVC_MULTIFUNC_IRB, *PAVC_MULTIFUNC_IRB;

AVC_MULTIFUNC_IRB Input

Common
The Function submember of this member must be set to AVC_FUNCTION_GET_SUBUNIT_INFO from the AVC_FUNCTION enumeration.
Subunits
Specifies a description of an AV/C subunit's information.

This function is satisfied locally, so no commands are sent to the target.

This must be called at IRQL <= DISPATCH_LEVEL.

See Also

AVC_MULTIFUNC_IRB, AVC_SUBUNIT_INFO_BLOCK, AVC_FUNCTION


IOCTL_AVC_UPDATE_VIRTUAL_SUBUNIT_INFO

The IOCTL_AVC_UPDATE_VIRTUAL_SUBUNIT_INFO I/O control code controls the enumeration of virtual subunits. It is available to user mode as well as kernel mode components through the IRP_MJ_DEVICE_CONTROL dispatch. For driver-to-driver communication, it is a METHOD_BUFFERED IOCTL, so set the IRP fields accordingly (IrpStack->Parameters.DeviceIoControl.InputBufferLength and Irp->AssociatedIrp.SystemBuffer).

IOCTL_AVC_UPDATE_VIRTUAL_SUBUNIT_INFO is used to add or remove subunit IDs of a single type. Successive calls with a different ID part of the subunit address cause the number of enumerated IDs to change. Note that avc.sys adds or removes the highest IDs only. This is a limitation of the AV/C specification, not the driver implementation.

This IOCTL uses the AVC_SUBUNIT_ADDR_SPEC structure.

I/O Status Block

If successful, the AV/C protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

Possible error return values include:

Error Status | Description
STATUS_INSUFFICIENT_RESOURCES | No buffer was passed, or insufficient resources available to perform a registry query.
STATUS_INVALID_BUFFER_SIZE | The buffer passed in Irp->AssociatedIrp.SystemBuffer must be at least as large as sizeof(AVC_SUBUNIT_ADDR_SPEC) which includes a single-byte subunit address, but limited to a 32 byte subunit address.
STATUS_INVALID_PARAMETER | The subunit address was specified incorrectly.
STATUS_ACCESS_DENIED | The current user has insufficient registry access privileges to make the update persistent.

Headers

Declared in avc.h. Include avc.h.

Comments

Must be called at IRQL = PASSIVE_LEVEL.

See Also

AVC_SUBUNIT_ADDR_SPEC, IOCTL_AVC_CLASS, IOCTL_AVC_REMOVE_VIRTUAL_SUBUNIT_INFO, IOCTL_AVC_BUS_RESET


IOCTL_AVC_REMOVE_VIRTUAL_SUBUNIT_INFO

The IOCTL_AVC_REMOVE_VIRTUAL_SUBUNIT_INFO I/O control code controls the enumeration of virtual subunits. It is available to user mode as well as kernel mode components through the IRP_MJ_DEVICE_CONTROL dispatch. For driver-to-driver communication, it is a METHOD_BUFFERED IOCTL, so set the IRP fields accordingly (IrpStack->Parameters.DeviceIoControl.InputBufferLength and Irp->AssociatedIrp.SystemBuffer).

IOCTL_AVC_REMOVE_VIRTUAL_SUBUNIT_INFO is used to remove all subunit IDs of a single type. The ID part of the subunit address is ignored.

This IOCTL uses the AVC_SUBUNIT_ADDR_SPEC structure.

I/O Status Block

If successful, the AV/C protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

Possible error return values include:

Error Status | Description
STATUS_INSUFFICIENT_RESOURCES | No buffer was passed, or insufficient resources available to perform a registry query.
STATUS_INVALID_BUFFER_SIZE | The buffer passed in Irp->AssociatedIrp.SystemBuffer must be at least as large as sizeof(AVC_SUBUNIT_ADDR_SPEC) which includes a single-byte subunit address, but limited to a 32 byte subunit address.
STATUS_INVALID_PARAMETER | The subunit address was specified incorrectly.
STATUS_ACCESS_DENIED | The current user has insufficient registry access privileges to make the update persistent.

Headers

Declared in avc.h. Include avc.h.

Comments

Must be called at IRQL = PASSIVE_LEVEL.

See Also

AVC_SUBUNIT_ADDR_SPEC, IOCTL_AVC_CLASS, IOCTL_AVC_UPDATE_VIRTUAL_SUBUNIT_INFO, IOCTL_AVC_BUS_RESET


IOCTL_AVC_BUS_RESET

The IOCTL_AVC_BUS_RESET I/O control code allows the caller to complete any previous IOCTL_AVC_UPDATE_VIRTUAL_SUBUNIT_INFO and IOCTL_AVC_REMOVE_VIRTUAL_SUBUNIT_INFO control requests that did not use the AVC_SUBUNIT_ADDR_TRIGGERBUSRESET flag. It is available to user mode as well as kernel mode components through the IRP_MJ_DEVICE_CONTROL dispatch.

For driver-to-driver communication, it is a METHOD_BUFFERED IOCTL, so set the IRP fields accordingly (IrpStack->Parameters.DeviceIoControl.InputBufferLength and Irp->AssociatedIrp.SystemBuffer). This request does not require any additional parameters, so the input and output buffers should be set to NULL.

This request causes avc.sys to invalidate its device relations, which results in the PnP manager asking for an updated list of child device objects (virtual subunits). If there are no new or removed child device objects, no action will be taken. If there are new or removed child device objects, their drivers will be loaded or unloaded, and a 1394 bus reset will be triggered for each PDO as each is started or removed.

See Also

AVC_SUBUNIT_ADDR_SPEC, IOCTL_AVC_CLASS, IOCTL_AVC_UPDATE_VIRTUAL_SUBUNIT_INFO, IOCTL_AVC_REMOVE_VIRTUAL_SUBUNIT_INFO


AV/C Intersect Handler

The AV/C intersect handler determines if the data ranges are compatible. This is a user-defined function based on the following prototype:

typedef
NTSTATUS
(*PFNAVCINTERSECTHANDLER)(
    IN PVOID Context,
    IN ULONG PinId,
    IN PKSDATARANGE CallerDataRange,
    IN PKSDATARANGE DescriptorDataRange,
    IN ULONG DataBufferSize,
    OUT PVOID Data OPTIONAL,
    OUT PULONG ReportedDataSize
    );

Parameters

Context
An optional value expected by the intersect handler. This value is either provided by the subunit driver (if the subunit driver provides the intersect handler), or by the lower driver providing the intersect handler.
PinId
Specifies the offset (or ID) of the pin for which the intersection is being done.
CallerDataRange
The first of two data ranges being compared.
DescriptorDataRange
The second of two data ranges being compared.
DataBufferSize
The size of the buffer passed by the Data member. If this is non-zero, then the intersect handler should attempt to return the data format resulting from a matching pair of data ranges. If this is zero, then the intersect handler should provide the required buffer size in ReportedDataSize, and return STATUS_BUFFER_OVERFLOW.
Data
An optional buffer to receive the data format resulting from a matching pair of data ranges. This member is ignored if DataBufferSize is zero.
ReportedDataSize
The actual size of the resulting data format. If DataBufferSize was zero, then this contains the required size of the buffer, but no format is returned.

Return Value

The intersect handler should return STATUS_SUCCESS if the data ranges are compatible, and there was enough buffer space to return the resulting format.

Possible error return values include:

Error Status | Description
STATUS_NO_MATCH | The data ranges are not compatible.
STATUS_INTERNAL_ERROR | There was an unexpected format size mismatch.
STATUS_BUFFER_OVERFLOW | The intersect handler is returning the required buffer size through the ReportedDataSize member.
STATUS_BUFFER_TOO_SMALL | The intersect handler was not provided with a buffer large enough to hold the resulting format. The intersect handler must be called again with the DataBufferSize set to zero to determine the required buffer size.
STATUS_INSUFFICIENT_RESOURCES | An internal buffer allocation failed.

Headers

Declared in avc.h. Include avc.h.

Comments

The AV/C intersect handler is user-defined, based on the function prototype above.

The handler is used in conjunction with the AVC_FUNCTION_GET_PIN_DESCRIPTOR function code. The purpose of the handler is to match identical pin data formats and return them to the caller.

See Also

AVC_PIN_DESCRIPTOR, AVC_FUNCTION_GET_PIN_DESCRIPTOR


AV/C Enumerations

This section describes the enumerations used by AV/C protocol subunit drivers.

To use these structures, include the avc.h header file that is shipped with the Microsoft® Windows® DDK.


AVC_FUNCTION

The AVC_FUNCTION enumeration type is used to specify AV/C subunit functions.

typedef enum _tagAVC_FUNCTION {
    AVC_FUNCTION_COMMAND = 0,
    AVC_FUNCTION_GET_PIN_COUNT = 1,
    AVC_FUNCTION_GET_PIN_DESCRIPTOR = 2,
    AVC_FUNCTION_GET_CONNECTINFO = 3,
    AVC_FUNCTION_SET_CONNECTINFO = 4,
    AVC_FUNCTION_ACQUIRE = 5,
    AVC_FUNCTION_RELEASE = 6,
    AVC_FUNCTION_CLR_CONNECTINFO = 7,
    AVC_FUNCTION_GET_EXT_PLUG_COUNTS = 8,
    AVC_FUNCTION_GET_UNIQUE_ID = 9,
    AVC_FUNCTION_GET_REQUEST = 10,
    AVC_FUNCTION_SEND_RESPONSE = 11,
    AVC_FUNCTION_FIND_PEER_DO = 12,
    AVC_FUNCTION_PEER_DO_LIST = 13,
    AVC_FUNCTION_GET_SUBUNIT_INFO = 14,
} AVC_FUNCTION;

Enumerators

AVC_FUNCTION_COMMAND
This value is a function code used to send an AV/C request and receive a response as one operation. This function code uses the AVC_COMMAND_IRB structure.

This function code is available to both peer and virtual instances of avc.sys.

AVC_FUNCTION_GET_PIN_COUNT
This value is a function code used to obtain the number of pins supported by the underlying subunit device. This function code uses the AVC_PIN_COUNT structure.

This function code is available only to peer instances of avc.sys.

AVC_FUNCTION_GET_PIN_DESCRIPTOR
This value is a function code used to obtain the pin descriptor for each pin ID. This function code uses the AVC_PIN_DESCRIPTOR structure.

This function code is available only to peer instances of avc.sys.

AVC_FUNCTION_GET_CONNECTINFO
This value is a function code used to obtain the AVCPRECONNECTINFO structure for each pin ID. This function code uses the AVC_PRE_CONNECTINFO structure.

This function code is available only to peer instances of avc.sys.

AVC_FUNCTION_SET_CONNECTINFO
This value is a function code used to set the AVCCONNECTINFO structure for each pin ID. This function code uses the AVC_SET_CONNECTINFO structure.

This function code is available only to peer instances of avc.sys.

AVC_FUNCTION_ACQUIRE
This value is a function code used to cause avc.sys to establish any connections suggested by cached AVCCONNECTINFO values. This function code uses the AVC_PIN_ID structure.

This function code is available only to peer instances of avc.sys.

AVC_FUNCTION_RELEASE
This value is a function code used to cause avc.sys to release any connections suggested by cached AVCCONNECTINFO values. This function code uses the AVC_PIN_ID structure.
AVC_FUNCTION_CLR_CONNECTINFO
This value is a function code used to cause avc.sys to remove any cached AVCCONNECTINFO values. This function code uses the This function code is available only to peer instances of avc.sys.

AVC_PIN_ID structure.

AVC_FUNCTION_GET_EXT_PLUG_COUNTS
This value is a function code used to cause avc.sys to obtain the external input and output plug counts. This function code uses the AVC_EXT_PLUG_COUNTS structure.

This function code is available only to peer instances of avc.sys.

AVC_FUNCTION_GET_UNIQUE_ID
This value is a function code used to obtain the unique ID of the AV/C unit. This function code uses the AVC_UNIQUE_ID structure.

This function code is available only to peer instances of avc.sys.

AVC_FUNCTION_GET_REQUEST
This value is a function code used to register to receive AV/C unit and subunit requests. This function code uses the AVC_COMMAND_IRB structure.

This function code is available to both peer and virtual instances of avc.sys.

AVC_FUNCTION_SEND_RESPONSE
This value is a function code used to cause avc.sys to respond to AV/C unit and subunit requests. This function code uses the AVC_COMMAND_IRB structure.

This function code is available to both peer and virtual instances of avc.sys.

AVC_FUNCTION_FIND_PEER_DO
This value is a function code used to locate a non-virtual avc.sys instance. This function code uses the AVC_PEER_DO_LOCATOR structure.

This function code is available to both peer and virtual instances of avc.sys.

AVC_FUNCTION_PEER_DO_LIST
This value is a function code used to locate all non-virtual avc.sys instances. This function code uses the AVC_PEER_DO_LIST structure.

This function code is available to both peer and virtual instances of avc.sys.

AVC_FUNCTION_GET_SUBUNIT_INFO
This value is a function code used to obtain the subunit information of the target device. This function code uses the AVC_SUBUNIT_INFO_BLOCK structure.

This function code is available to both peer and virtual instances of avc.sys.

Headers

Declared in avc.h. Include avc.h.

See Also

AVC_IRB, AVC_COMMAND_IRB, AVC_PIN_COUNT, AVC_PIN_DESCRIPTOR, AVC_PRECONNECT_INFO, AVC_SETCONNECT_INFO, AVC_PIN_ID, AVC_EXT_PLUG_COUNTS, AVC_UNIQUE_ID, AVC_PEER_DO_LOCATOR, AVC_PEER_DO_LIST and AVC_SUBUNIT_INFO_BLOCK


AvcCommandType

The AvcCommandType enumeration type is used to indicate the type of command issued by a subunit driver to its AV/C subunit through AVC_FUNCTION_COMMAND or AVC_FUNCTION_GET_REQUEST function codes.

typedef enum _tagAvcCommandType {
  AVC_CTYPE_CONTROL  = 0x00,
  AVC_CTYPE_STATUS  = 0x01,
  AVC_CTYPE_SPEC_INQ  = 0x02,
  AVC_CTYPE_NOTIFY  = 0x03,
  AVC_CTYPE_GEN_INQ  = 0x04
} AvcCommandType;

Enumerators

AVC_CTYPE_CONTROL
Specifies a control type of command.
AVC_CTYPE_STATUS
Specifies a status type of command.
AVC_CTYPE_SPEC_INQ
Specifies a specific-inquiry type of command. This permits a controller to inform targets that a specific set of operands must by furnished along with the opcode when issuing a command.
AVC_CTYPE_NOTIFY
Specifies a notify type of command.
AVC_CTYPE_GEN_INQ
Specifies a general inquiry command type. This permits a controller to query a target to find out if it supports a specific opcode without needing to pass any specific operands.

Headers

Declared in avc.h. Include avc.h.

See Also

AVC_FUNCTION_COMMAND, AVC_FUNCTION_GET_REQUEST, AVC_FUNCTION


AvcSubunitType

The AvcSubunitType enumeration type is used to indicate the type of AV/C subunit.

typedef enum _tagAvcSubunitType {
    AVC_SUBUNITTYPE_VIDEO_MONITOR = 0x00,
    AVC_SUBUNITTYPE_AUDIO         = 0x01,
    AVC_SUBUNITTYPE_PRINTER       = 0x02,
    AVC_SUBUNITTYPE_DISC_PLAYER   = 0x03,
    AVC_SUBUNITTYPE_TAPE_PLAYER   = 0x04,
    AVC_SUBUNITTYPE_TUNER         = 0x05,
    AVC_SUBUNITTYPE_CA            = 0x06,
    AVC_SUBUNITTYPE_VIDEO_CAMERA  = 0x07,
    AVC_SUBUNITTYPE_PANEL         = 0x09,
    AVC_SUBUNITTYPE_BULLETINBOARD = 0x0A,
    AVC_SUBUNITTYPE_CAMERASTORAGE = 0x0B,
    AVC_SUBUNITTYPE_VENDOR_UNIQUE = 0x1c,
    AVC_SUBUNITTYPE_EXTENDED      = 0x1e,
    AVC_SUBUNITTYPE_EXTENDED_FULL = 0xff,
    AVC_SUBUNITTYPE_UNIT          = 0x1f
} AvcSubunitType;

Enumerators

AVC_SUBUNITTYPE_VIDEO_MONITOR
Specifies a video monitor subunit type.
AVC_SUBUNITTYPE_AUDIO
Specifies an audio subunit type.
AVC_SUBUNITTYPE_PRINTER
Specifies a printer subunit type.
AVC_SUBUNITTYPE_DISC_PLAYER
Specifies a disc player subunit type.
AVC_SUBUNITTYPE_TAPE_PLAYER
Specifies a tape player subunit type.
AVC_SUBUNITTYPE_TUNER
Specifies a tuner subunit type.
AVC_SUBUNITTYPE_CA
Specifies a conditional access (CA) subunit type.
AVC_SUBUNITTYPE_VIDEO_CAMERA
Specifies a video camera subunit type.
AVC_SUBUNITTYPE_PANEL
Specifies a panel subunit type.
AVC_SUBUNITTYPE_BULLETINBOARD
Specifies a bulletin board subunit type.
AVC_SUBUNITTYPE_CAMERASTORAGE
Specifies a camera storage subunit type.
AVC_SUBUNITTYPE_VENDOR_UNIQUE
Specifies a vendor unique subunit type.
AVC_SUBUNITTYPE_EXTENDED
Specifies an extended subunit type.
AVC_SUBUNITTYPE_EXTENDED_FULL
This is used only in extension bytes
AVC_SUBUNITTYPE_UNIT
Specifies a generic subunit type.

Headers

Declared in avc.h. Include avc.h.


KSPIN_FLAG_AVC

The KSPIN_FLAG_AVC enumeration type is used for connection management and in the AVC_FUNCTION_GET_CONNECTINFO function code.

typedef enum _KSPIN_FLAG_AVC {
    KSPIN_FLAG_AVCMASK       = 0x03,
    KSPIN_FLAG_AVC_PERMANENT = 0x01,
    KSPIN_FLAG_AVC_CONNECTED = 0x02,
    KSPIN_FLAG_AVC_PCRONLY   = 0x04,
    KSPIN_FLAG_AVC_FIXEDPCR  = 0x08,
} KSPIN_FLAG_AVC;

Enumerators

KSPIN_FLAG_AVCMASK
The mask to isolate the AV/C defined bit flags
KSPIN_FLAG_AVC_PERMANENT
Part of the AV/C Connect Status bit mask. Represents a permanent connection between two subunits within the same unit.
KSPIN_FLAG_AVC_CONNECTED
Part of the AV/C Connect Status bit mask. Represents a connection that is currently active, but not necessarily permanent.
KSPIN_FLAG_AVC_PCRONLY
No subunit plug control. Only unit input and output plugs are available, and this AVCPRECONNECTINFO structure represents one of them.
KSPIN_FLAG_AVC_FIXEDPCR
Represents a permanent connection between a subunit plug and a unit (serial bus) plug. Specifying this flag implies KSPIN_FLAG_AVC_PERMANENT, although that bit is not set if this one is set.

Headers

Declared in avc.h. Include avc.h.

Comments

These bit flags are used by the intersect handler to determine plug compatibility, as well as to indicate whether or not the intersect handler is responsible for obtaining a plug handle from 61883.sys.

See Also

AVC_FUNCTION_GET_CONNECTINFO, AV/C Intersect Handler


AV/C Structures

This section describes the structures used by AV/C protocol subunit drivers.

To use these structures, include the avc.h header file that is shipped with the Microsoft® Windows® DDK.


AVC_IRB

The AVC_IRB structure is an I/O Request Block (IRB) header structure where a function number is stored.

typedef struct _AVC_IRB {
    AVC_FUNCTION Function;
} AVC_IRB, *PAVC_IRB;

Members

Function
Value from the AVC_FUNCTION enumeration specifying a function number.

Headers

Declared in avc.h. Include avc.h.

Comments

This structure is included at the head of the AVC_COMMAND_IRB and AVC_MULTIFUNC_IRB structures. These structures represent the I/O request block (IRB) associated with specific types of AV/C functions. Each specific type of AV/C function is documented in IOCTL_AVC_CLASS.

See Also

AVC_COMMAND_IRB, AVC_MULTIFUNC_IRB, AVC_FUNCTION, IOCTL_AVC_CLASS


AVC_COMMAND_IRB

The AVC_COMMAND_IRB structure defines a structure that contains an AV/C command and response pair.

typedef struct _AVC_COMMAND_IRB {
  AVC_IRB Common;
  UCHAR SubunitAddrFlag : 1;
  UCHAR AlternateOpcodesFlag : 1;
  UCHAR TimeoutFlag : 1;
  UCHAR RetryFlag : 1;
  union {
    UCHAR CommandType;
    UCHAR ResponseCode;
  };
  PUCHAR SubunitAddr;
  PUCHAR AlternateOpcodes;
  LARGE_INTEGER Timeout;
  UCHAR Retries;
  UCHAR Opcode;
  ULONG OperandLength;
  UCHAR Operands[MAX_AVC_OPERAND_BYTES];
  NODE_ADDRESS NodeAddress;
  ULONG Generation;
} AVC_COMMAND_IRB, *PAVC_COMMAND_IRB;

Members

Common
This must be set to the AVC_FUNCTION_COMMAND enumerator from the AVC_FUNCTION enumeration.
SubunitAddrFlag
This is a flag indicating if the SubunitAddr member specifies an address. Set to one if it does, otherwise set to zero.
AlternateOpcodesFlag
This is a flag indicating if the AlternateOpcodes member is valid. Set to one if it is, otherwise set to zero.
TimeoutFlag
Set this to one if the default timeout is not appropriate for the subunit. If this is set, the Timeout member must be set to the desired timeout (in 100ns units).
RetryFlag
Set this to one if the default retry count is not appropriate for the subunit. If this is set, the Retries member must be set to the desired retry count.
CommandType
This specifies a value from the AvcCommandType enumeration. This member is used only during AVC_FUNCTION_GET_REQUEST. It is ignored otherwise.
ResponseCode
This specifies a value from the AvcResponseCode enumeration. This member is used only during AVC_FUNCTION_SEND_RESPONSE. It is ignored otherwise.
SubunitAddr
Set this to the address of nonpaged memory containing the desired subunit address encoded according to Section 5.3.3 of the AV/C Digital Interface Command Set General Specification, Rev 3.0. This specification can be found at www.1394ta.org . No length is necessary because the subunit address encoding implies this. This parameter is ignored if SubunitAddrFlag is zero.
AlternateOpcodes
Set this to the address of nonpaged memory containing the desired alternate opcode list. The first byte of the opcode list is the count of opcodes to follow (equivalent to the number of bytes). The total length of the memory containing the alternate opcode list is AlternateOpcodes[0]+1. This parameter is ignored if AlternateOpcodesFlag is zero.
Timeout
Set this to the desired timeout in 100ns units. For example, the default timeout value is: Timeout.QuadPart = 1000000 (100ms in 100ns units). This parameter is ignored if TimeoutFlag is zero.
Retries
Set this to the desired number of times avc.sys should attempt to retry requests after each timeout without a response. Note that a retry count of zero means that the request is tried once. The total amount of time spent trying to process a command without getting a response is Timeout * (Retries + 1). This parameter is ignored if RetryFlag is zero.
Opcode
Set this to the desired AV/C opcode (appropriate for the subunit type). This is a required parameter. On response, if AlternateOpcodesFlag was set, and one of the alternate opcodes was used to match the response, this is set to that alternate opcode.
OperandLength
Set this to the number of bytes used to store the operands in the Operands member. This is a required parameter. On response, this parameter is set to the number of bytes in the operand list used by the response.
Operands
Set this to the operand list appropriate for the subunit type and opcode. This is a required parameter. On response, this parameter contains the operand list of the response.
NodeAddress
Reserved. This member must be zero.
Generation
Reserved. This member must be zero.

Headers

Declared in avc.h. Include avc.h.

Comments

This structure is used with the AVC_FUNCTION_COMMAND, AVC_FUNCTION_GET_REQUEST and AVC_FUNCTION_SEND_RESPONSE function codes.

See Also

AVC_FUNCTION_COMMAND, AVC_FUNCTION_GET_REQUEST, AVC_FUNCTION_SEND_RESPONSE, AVC_FUNCTION


AVC_PIN_COUNT

The AVC_PIN_COUNT structure specifies the number of pins on an AV/C subunit device.

typedef struct _AVC_PIN_COUNT {
    OUT ULONG PinCount;
} AVC_PIN_COUNT, *PAVC_PIN_COUNT;

Members

PinCount
This value is filled in by avc.sys on return from the AVC_FUNCTION_GET_PIN_COUNT function.

Headers

Declared in avc.h. Include avc.h.

Comments

This structure is used with the AVC_FUNCTION_GET_PIN_COUNT function code.

This structure is used only as a member inside the AVC_MULTIFUNC_IRB structure. It is not used by itself.

See AV/C Requests for information on building and sending an AV/C command.

See Also

AVC_MULTIFUNC_IRB, AVC_FUNCTION, AVC_FUNCTION_GET_PIN_COUNT


AVC_PIN_DESCRIPTOR

The AVC_PIN_DESCRIPTOR structure describes a pin on an AV/C subunit device.

typedef struct _AVC_PIN_DESCRIPTOR {
    IN ULONG PinId;
    OUT KSPIN_DESCRIPTOR PinDescriptor;
    OUT PFNAVCINTERSECTHANDLER IntersectHandler;
    OUT PVOID Context;
} AVC_PIN_DESCRIPTOR, *PAVC_PIN_DESCRIPTOR;

Members

PinId
Specifies the offset (or ID) of the pin for which information is to be retrieved.
PinDescriptor
Specifies a KSPIN_DESCRIPTOR structure. This structure is allocated in the nonpaged pool. The subunit driver must not free this pointer.
IntersectHandler
An optional output parameter specifying a data range intersect handler associated with the DataRanges member of the PinDescriptor member.
Context
An optional output parameter specifying a value to be passed to the IntersectHandler when it is called during format negotiation. For more information about what an intersect handler is, see Format Negotiation and Data Intersections.

Headers

Declared in avc.h. Include avc.h.

Comments

This structure is used with the AVC_FUNCTION_GET_PIN_DESCRIPTOR function code.

This structure is used only as a member inside the AVC_MULTIFUNC_IRB structure. It is not used by itself.

See AV/C Requests for information on building and sending an AV/C command.

A description of the members of the KSPIN_DESCRIPTOR structure used in AVC_PIN_DESCRIPTOR follows:

typedef struct {
    ULONG                   InterfacesCount;
    const KSPIN_INTERFACE*  Interfaces;
    ULONG                   MediumsCount;
    const KSPIN_MEDIUM*     Mediums;
    ULONG                   DataRangesCount;
    const PKSDATARANGE*     DataRanges;
    KSPIN_DATAFLOW          DataFlow;
    KSPIN_COMMUNICATION     Communication;
    const GUID*             Category;
    const GUID*             Name;
    union {
        LONGLONG            Reserved;
        struct {
            ULONG           ConstrainedDataRangesCount;
            PKSDATARANGE*   ConstrainedDataRanges;
        };
    };
} KSPIN_DESCRIPTOR, *PKSPIN_DESCRIPTOR;

Members

InterfacesCount
The subunit driver must supply this member. See KSPIN_DESCRIPTOR for details.
Interfaces
The subunit driver must supply this member. See KSPIN_DESCRIPTOR for details.
MediumsCount
Provided by avc.sys. Do not modify.
Mediums
Provided by avc.sys. Do not modify.
DataRangesCount
Specifies the number of data ranges. This is not provided by avc.sys, although a filter driver such as avcstrm.sys provides the list of formats (data ranges) that it supports. If this is zero, then the subunit driver provides the list of data ranges.
DataRanges
Not provided by avc.sys, although a filter driver such as avcstrm.sys provides the list of formats (data ranges) that it supports.
DataFlow
Provided by avc.sys. Do not modify.
Communication
Provided by avc.sys. This may be modified by the subunit driver if the pin communication implemented by the driver is different. For descriptors with DataFlow equal to KSPIN_DATAFLOW_OUT, this member is set to KSPIN_COMMUNICATION_BOTH. Otherwise, it is set to KSPIN_COMMUNICATION_SINK.
Category
The subunit driver must supply this member. See KSPIN_DESCRIPTOR for details.
Name
The subunit driver must supply this member. See KSPIN_DESCRIPTOR for details.
Reserved
Do not use.
ConstrainedDataRangesCount
Specifies the number of constrained data ranges.
ConstrainedDataRanges
The subunit driver should supply ConstrainedDataRanges if its current state supports only a subset of the data ranges specified in the DataRanges member.

See Also

AV/C Intersect Handler, KSPIN_DESCRIPTOR, AVC_MULTIFUNC_IRB


AVCPRECONNECTINFO

The AVCPRECONNECTINFO structure is used to initialize a subunit driver and establish pin connections.

typedef struct _AVCPRECONNECTINFO {
    GUID DeviceID;
    UCHAR SubunitAddress[AVCCONNECTINFO_MAX_SUBUNITADDR_LEN];
    ULONG SubunitPlugNumber;
    KSPIN_DATAFLOW DataFlow;
    ULONG Flags;
    ULONG UnitPlugNumber;
} AVCPRECONNECTINFO, *PAVCPRECONNECTINFO;

Members

DeviceID
A GUID representing the unit as a whole. All subunits within the same unit share the same GUID. No two units share the same GUID.
SubunitAddress
The encoded subunit type and subunit ID of the subunit.
SubunitPlugNumber
The plug number (within the subunit) described by the AVCPRECONNECTINFO structure.
DataFlow
The direction of data flow on this subunit plug. Destination plugs have KSPIN_DATAFLOW_IN; source plugs have KSPIN_DATAFLOW_OUT.
Flags
A bitmap with one or more bits set from the KSPIN_FLAG_AVC enumeration.
UnitPlugNumber
If a bitwise AND of Flags and KSPIN_FLAG_AVC_FIXEDPCR returns true, then this is the unit plug number required for this permanent connection (used to obtain a specific plug handle from 61883.sys). This is undefined if a bitwise AND of Flags KSPIN_FLAG_AVC_FIXEDPCR returns false.

Headers

Declared in avc.h. Include avc.h.

Comments

This structure is used with the AVC_FUNCTION_GET_CONNECTINFO function code.

This structure is used only as member of the AVC_PRECONNECT_INFO structure. It is not used by itself.

See Also

AVC_PRECONNECT_INFO, KSPIN_FLAG_AVC


AVC_PRECONNECT_INFO

The AVC_PRECONNECT_INFO structure specifies the pre-connection information for the specified pin id (zero-based offset) on an AV/C subunit device.

typedef struct _AVC_PRECONNECT_INFO {
    IN ULONG PinId
    OUT AVCPRECONNECTINFO ConnectInfo;
} AVC_PRECONNECT_INFO, *PAVC_PRECONNECT_INFO;

Members

PinId
Specifies the offset (or ID) of the pin for which information is to be retrieved.
ConnectInfo
The AVCPRECONNECTINFO values for the specified pin.

Headers

Declared in avc.h. Include avc.h.

Comments

This structure is used with the AVC_FUNCTION_GET_CONNECTINFO function code.

This structure is used only as a member inside the AVC_MULTIFUNC_IRB structure. It is not used by itself.

See AV/C Requests for information on building and sending an AV/C command.

See Also

AVC_MULTIFUNC_IRB, AVC_FUNCTION, AVC_FUNCTION_GET_CONNECTINFO


AVCCONNECTINFO

The AVCCONNECTINFO structure is used to initialize a subunit driver and establish pin connections.

typedef struct _AVCCONNECTINFO {
    GUID DeviceID;
    UCHAR SubunitAddress[AVCCONNECTINFO_MAX_SUBUNITADDR_LEN];
    ULONG SubunitPlugNumber;
    KSPIN_DATAFLOW DataFlow;
    HANDLE hPlug;
    ULONG UnitPlugNumber;
} AVCCONNECTINFO, *PAVCCONNECTINFO;

Members

DeviceID
A GUID representing the unit as a whole. All subunits within the same unit share the same GUID. No two units share the same GUID.
SubunitAddress
The encoded subunit type and subunit ID of the subunit.
SubunitPlugNumber
The plug number (within the subunit) described by the AVCPRECONNECTINFO structure.
DataFlow
The direction of data flow on this subunit plug. Destination plugs have KSPIN_DATAFLOW_IN; source plugs have KSPIN_DATAFLOW_OUT.
hPlug
A plug handle obtained from 61883.sys by the intersect handler according to the bit flags set in the associated AVCPRECONNECTINFO structure for this pin. If the proposed connection is between two subunits within the same unit, this value is NULL.
UnitPlugNumber
If hPlug != NULL, then this is the unit plug number required for this proposed connection (used in an AV/C Connect control command).

Headers

Declared in avc.h. Include avc.h.

Comments

This structure is used only as member inside the AVC_SETCONNECT_INFO structure. It is not used by itself.

See Also

AVC_FUNCTION_SET_CONNECTINFO


AVC_SETCONNECT_INFO

The AVC_SETCONNECT_INFO structure is used to initialize a subunit driver and establish pin connections.

typedef struct _AVC_SETCONNECT_INFO {
    IN ULONG PinId;
    IN AVCCONNECTINFO ConnectInfo;
} AVC_SETCONNECT_INFO, *PAVC_SETCONNECT_INFO;

Members

PinId
Specifies the offset (or ID) of the pin for which information is to be set.
ConnectInfo
The AVCCONNECTINFO values for the specified pin.

Headers

Declared in avc.h. Include avc.h.

Comments

This structure is used with the AVC_FUNCTION_SET_CONNECTINFO function code.

This structure is used only as a member inside the AVC_MULTIFUNC_IRB structure. It is not used by itself.

See AV/C Requests for information on building and sending an AV/C command.

See Also

AVC_MULTIFUNC_IRB, AVC_FUNCTION, AVC_FUNCTION_SET_CONNECTINFO


AVC_PIN_ID

The AVC_PIN_ID structure describes a pin on a subunit.

typedef struct _AVC_PIN_ID {
    IN ULONG PinId;
} AVC_PIN_ID, *PAVC_PIN_ID;

Members

PinId
Specifies the offset (or ID) of the pin.

Headers

Declared in avc.h. Include avc.h.

Comments

This structure is used with the AVC_FUNCTION_ACQUIRE, AVC_FUNCTION_RELEASE and AVC_FUNCTION_CLR_CONNECTINFO function codes.

This structure is used only as a member inside the AVC_MULTIFUNC_IRB structure. It is not used by itself.

See AV/C Requests for information on building and sending an AV/C command.

See Also

AVC_MULTIFUNC_IRB, AVC_FUNCTION, AVC_FUNCTION_ACQUIRE, AVC_FUNCTION_RELEASE, AVC_FUNCTION_CLR_CONNECTINFO


AVC_EXT_PLUG_COUNTS

The AVC_EXT_PLUG_COUNTS structure describes the number of external plugs on the subunit.

typedef struct _AVC_EXT_PLUG_COUNTS {
    OUT ULONG ExtInputs;
    OUT ULONG ExtOutputs;
} AVC_EXT_PLUG_COUNTS, *PAVC_EXT_PLUG_COUNTS;

Members

ExtInputs
Ignored on input. On output, this contains the count of external input plugs.
ExtOutputs
Ignored on input. On output, this contains the count of external output plugs.

Headers

Declared in avc.h. Include avc.h.

Comments

This structure is used with the AVC_FUNCTION_GET_EXT_PLUG_COUNTS function code.

This structure is used only as a member inside the AVC_MULTIFUNC_IRB structure. It is not used by itself.

See AV/C Requests for information on building and sending an AV/C command.

See Also

AVC_MULTIFUNC_IRB, AVC_FUNCTION, AVC_FUNCTION_GET_EXT_PLUG_COUNTS


AVC_UNIQUE_ID

The AVC_UNIQUE_ID describe the unique ID of the AV/C unit.

typedef struct _AVC_UNIQUE_ID {
    OUT GUID DeviceID;
} AVC_UNIQUE_ID, *PAVC_UNIQUE_ID;

Members

DeviceID
A GUID representing the unit as a whole. All subunits within the same unit share the same GUID. No two units share the same GUID.

Headers

Declared in avc.h. Include avc.h.

Comments

This structure is used with the AVC_FUNCTION_GET_UNIQUE_ID function code.

This structure is used only as a member inside the AVC_MULTIFUNC_IRB structure. It is not used by itself.

See AV/C Requests for information on building and sending an AV/C command.

See Also

AVC_MULTIFUNC_IRB, AVC_FUNCTION, AVC_FUNCTION_GET_UNIQUE_ID


AVC_PEER_DO_LOCATOR

The AVC_PEER_DO_LOCATOR describes non-virtual (peer) instances of avc.sys.

typedef struct _AVC_PEER_DO_LOCATOR {
    IN NODE_ADDRESS NodeAddress;
    IN ULONG Generation;
    OUT PDEVICE_OBJECT DeviceObject;
} AVC_PEER_DO_LOCATOR, *PAVC_PEER_DO_LOCATOR;

Members

NodeAddress
Set to the NodeAddress of the device whose driver instance is to be located.
Generation
Set to the Generation obtained with the NodeAddress.
DeviceObject
On success, points to the FDO of the avc.sys instance. The caller must release the reference to this object (by using ObDereferenceObject) when finished with it.

Headers

Declared in avc.h. Include avc.h.

Comments

This structure is used with the AVC_FUNCTION_FIND_PEER_DO function code.

This structure is used only as a member inside the AVC_MULTIFUNC_IRB structure. It is not used by itself.

See AV/C Requests for information on building and sending an AV/C command.

See Also

AVC_MULTIFUNC_IRB, AVC_FUNCTION, AVC_FUNCTION_FIND_PEER_DO


AVC_PEER_DO_LIST

The AVC_PEER_DO_LIST describes all non-virtual (peer) instances of avc.sys.

typedef struct _AVC_PEER_DO_LIST {
    OUT ULONG Count;
    OUT PDEVICE_OBJECT *Objects;
} AVC_PEER_DO_LIST, *PAVC_PEER_DO_LIST;

Members

Count
Ignored on input. On output, set to the number of objects in the list. If zero, the caller must not attempt to dereference the Objects member (it is set to NULL).
Objects
Ignored on input. On output (and if the Count member is not zero) Objects contains a pointer to a contiguous array of DEVICE_OBJECT pointers. The caller must release the reference held on each object (by using ObDereferenceObject), and free the memory containing the list (by using ExFreePool) when finished with it.

Headers

Declared in avc.h. Include avc.h.

Comments

This structure is used with the AVC_FUNCTION_PEER_DO_LIST function code.

This structure is used only as a member inside the AVC_MULTIFUNC_IRB structure. It is not used by itself.

See AV/C Requests for information on building and sending an AV/C command.

See Also

AVC_MULTIFUNC_IRB, AVC_FUNCTION, AVC_FUNCTION_PEER_DO_LIST


AVC_SUBUNIT_INFO_BLOCK

The AVC_SUBUNIT_INFO_BLOCK structure describes subunit information.

typedef struct _AVC_SUBUNIT_INFO_BLOCK {
    OUT UCHAR Info[AVC_SUBUNITINFO_BYTES];
} AVC_SUBUNIT_INFO_BLOCK, *PAVC_SUBUNIT_INFO_BLOCK;

Members

Info
Ignored on input. On output, this contains up to eight contiguous pages of subunit information in the format of the AV/C SUBUNIT_INFO unit command. The subunit information pages are terminated with 0xff. See Section 9.11 of the AV/C Digital Interface Command Set General Specification, Rev 3.0. This specification can be found at www.1394ta.org .

Headers

Declared in avc.h. Include avc.h.

Comments

This structure is used with the AVC_FUNCTION_GET_SUBUNIT_INFO function code.

This structure is used only as a member inside the AVC_MULTIFUNC_IRB structure. It is not used by itself.

See AV/C Requests for information on building and sending an AV/C command.

See Also

AVC_MULTIFUNC_IRB, AVC_FUNCTION, AVC_FUNCTION_GET_SUBUNIT_INFO


AVC_MULTIFUNC_IRB

The AVC_MULTIFUNC_IRB structure contains other AV/C related structures in a union.

typedef struct _AVC_MULTIFUNC_IRB {
  AVC_IRB Common;
  union {
    AVC_PIN_COUNT PinCount;
    AVC_PIN_DESCRIPTOR PinDescriptor;
    AVC_PRECONNECT_INFO PreConnectInfo;
    AVC_SETCONNECT_INFO SetConnectInfo;
    AVC_PIN_ID PinId;
    AVC_EXT_PLUG_COUNTS ExtPlugCounts;
    AVC_UNIQUE_ID UniqueID;
    AVC_PEER_DO_LOCATOR PeerLocator;
    AVC_PEER_DO_LIST PeerList;
    AVC_SUBUNIT_INFO_BLOCK Subunits;
  };
} AVC_MULTIFUNC_IRB, *PAVC_MULTIFUNC_IRB;

Members

PinCount
Used with AVC_FUNCTION_GET_PIN_COUNT.
PinDescriptor
Used with AVC_FUNCTION_GET_PIN_DESCRIPTOR.
PreConnectInfo
Used with AVC_FUNCTION_GET_CONNECT_INFO.
SetConnectInfo
Used with AVC_FUNCTION_SET_CONNECT_INFO.
PinId
Used with AVC_FUNCTION_ACQUIRE, AVC_FUNCTION_RELEASE and AVC_FUNCTION_CLR_CONNECTINFO.
ExtPlugCounts
Used with AVC_FUNCTION_GET_EXT_PLUG_COUNTS.
UniqueID
Used with AVC_FUNCTION_GET_UNIQUE_ID.
PeerLocator
Used with AVC_FUNCTION_PEER_DO_LOCATOR.
PeerList
Used with AVC_FUNCTION_PEER_DO_LIST.
Subunits
Used with AVC_FUNCTION_GET_SUBUNIT_INFO.

Headers

Declared in avc.h. Include avc.h.

Comments

The AVC_MULTIFUNC_IRB structure used with a variety of AV/C functionality. Depending on the functionality described in the AVC_IRB header, the matching, respective structure in the union is used.

See Also

AVC_PIN_COUNT, AVC_PIN_DESCRIPTOR, AVC_PRECONNECT_INFO, AVC_SETCONNECT_INFO, AVC_PIN_ID, AVC_EXT_PLUG_COUNTS, AVC_UNIQUE_ID, AVC_PEER_DO_LOCATOR, AVC_PEER_DO_LIST, AVC_SUBUNIT_INFO_BLOCK, AVC_FUNCTION_GET_PIN_COUNT, AVC_FUNCTION_GET_PIN_DESCRIPTOR, AVC_FUNCTION_GET_CONNECTINFO, AVC_FUNCTION_SET_CONNECTINFO, AVC_FUNCTION_ACQUIRE, AVC_FUNCTION_RELEASE, AVC_FUNCTION_CLR_CONNECTINFO, AVC_FUNCTION_GET_EXT_PLUG_COUNTS, AVC_FUNCTION_GET_UNIQUE_ID, AVC_FUNCTION_FIND_PEER_DO, AVC_FUNCTION_PEER_DO_LIST, AVC_FUNCTION_GET_SUBUNIT_INFO


AVC_SUBUNIT_ADDR_SPEC

The AVC_SUBUNIT_ADDR_SPEC structure is used with virtual instances of avc.sys to describe virtual subunit addresses.

typedef struct _AVC_SUBUNIT_ADDR_SPEC {
    ULONG Flags;
    UCHAR SubunitAddress[1];
} AVC_SUBUNIT_ADDR_SPEC, *PAVC_SUBUNIT_ADDR_SPEC;

Members

Flags
The flags extend the operation in the following ways:
AVC_SUBUNIT_ADDR_PERSISTENT
Makes the change persistent (in the registry) so on reboot the virtual device instances are automatically enumerated.
AVC_SUBUNIT_ADDR_TRIGGERBUSRESET
Lets the device manager know that the PDO list has changed. This causes a 1394 bus reset, which notifies devices on the 1394 bus that the topology has changed. This flag is normally set, unless there are several different subunit types to enable at the same time. The IOCTL_AVC_BUS_RESET control code performs the equivalent bus reset operation.
SubunitAddress
A Subunit Address encoded according to Section 5.3.3 of the AV/C Digital Interface Command Set General Specification, Rev 3.0. This specification can be found at www.1394ta.org. The ID part (SubunitAddress[0] & 0x7) represents the max ID (not the count of subunits), so to enumerate a single tuner subunit, you would specify 0x28 (0x5 << 3). This struct supports extended subunit addresses (just allocate a bigger struct and pass the actual length with the IOCTL).

See Also

IOCTL_AVC_BUS_RESET


AV/C Streaming Protocol Driver Function Codes

The AV/C Streaming filter driver intercepts IRPs on their way down the device stack.

To communicate with avcstrm.sys, subunit drivers must set their IRP's IoControlCode member to IOCTL_AVCSTRM_CLASS.

To make I/O requests, include the header file avcstrm.h, which is shipped with the Microsoft® Windows® DDK.


INIT_AVCSTRM_HEADER

The INIT_AVCSTRM_HEADER macro initializes the SizeOfThisBlock, Version and Function members of the AVC_STREAM_REQUEST_BLOCK structure.

VOID
  INIT_AVCSTRM_HEADER(
    IN PAVC_STREAM_REQUEST_BLOCK  AVCStrm,
    IN AVCSTRM_FUNCTION  Request
    );

Parameters

AVCStrm
Points to a caller-allocated AVC_STREAM_REQUEST_BLOCK structure.
Request
Indicates the type of the request (function code) from the AVCSTRM_FUNCTION enumeration. Each function code is documented under the IOCTL_AVCSTRM_CLASS topic.

Headers

Defined in avcstrm.h. Include avcstrm.h.

See Also

AVC_STREAM_REQUEST_BLOCK, IOCTL_AVCSTRM_CLASS, AVCSTRM_READ, AVCSTRM_WRITE, AVCSTRM_ABORT_STREAMING, AVCSTRM_OPEN, AVCSTRM_CLOSE, AVCSTRM_GET_STATE, AVCSTRM_SET_STATE, AVCSTRM_GET_PROPERTY, AVCSTRM_SET_PROPERTY


IOCTL_AVCSTRM_CLASS

Operation

An AV/C subunit driver uses the IRP_MJ_INTERNAL_DEVICE_CONTROL IRP, with the IoControlCode member set to IOCTL_AVCSTRM_CLASS, to communicate with avcstrm.sys. The driver has access to all operations provided by the AV/C Streaming filter driver (avcstrm.sys) through this request.

For more information about IRPs and IOCTLs, see Handling IRPs.

Input

On input, Irp->Parameters->Others.Arguments1 points to an AVC_STREAM_REQUEST_BLOCK structure. The Function member of the AVC_STREAM_REQUEST_BLOCK specifies the type of request. Do not set this member directly. Use the INIT_AVCSTRM_HEADER macro to initialize this member (as well as additional members of the AVC_STREAM_REQUEST_BLOCK structure). The CommandData member of the AVC_STREAM_REQUEST_BLOCK is a union that specifies the request-type-specific parameters of the request. The parameters and their meaning are documented with each request (function code). The AVCSTRM_FUNCTION enumeration provides a list of function codes supported by avcstrm.sys.

Output

On output, Irp->Parameters->Others.Arguments1 points to the AVC_STREAM_REQUEST_BLOCK structure passed as input. As part of completing the request, the bus driver fills in certain members of the CommandData union of the AVC_STREAM_REQUEST_BLOCK structure with information for the driver.

I/O Status Block

The information the AV/C Streaming driver returns in the I/O Status Block is documented with each request.

Headers

Defined in avcstrm.h. Include avcstrm.h.

Comments

Must be called at IRQL = PASSIVE_LEVEL.

See Also

AVCSTRM_READ, AVCSTRM_WRITE, AVCSTRM_ABORT_STREAMING, AVCSTRM_OPEN, AVCSTRM_CLOSE, AVCSTRM_GET_STATE, AVCSTRM_SET_STATE, AVCSTRM_GET_PROPERTY, AVCSTRM_SET_PROPERTY


AVCSTRM_READ

The AVCSTRM_READ function code is used to submit a data buffer avcstrm.sys that is filled with data from the specified stream.

I/O Status Block

If successful, avcstrm.sys sets Irp->IoStatus.Status to STATUS_SUCCESS.

Possible error return values include:

Error Status | Description
STATUS_DEVICE_REMOVED | The device corresponding to the AVCSTRM_READ operation no longer exists.
STATUS_CANCELLED | The request was unable to be completed.
STATUS_INVALID_PARAMETER | A parameter specified in the IRP is incorrect,
STATUS_INSUFFICIENT_RESOURCES | There were not sufficient system resources to complete the request.
STATUS_PENDING | The request has been received but requires further processing. The I/O completion routine will handle the final response.

Headers

Declared in avcstrm.h. Include avcstrm.h.

Comments

This function uses the BufferStruct member of the CommandData union in the AVC_STREAM_REQUEST_BLOCK structure as shown below.

typedef struct _AVC_STREAM_REQUEST_BLOCK {
  ULONG  SizeOfThisBlock;
  ULONG  Version;
  AVCSTRM_FUNCTION  Function;
  .
  .
  PVOID AVCStreamContext;
  .
  .
  union _tagCommandData {
    .
    .
    AVCSTRM_BUFFER_STRUCT  BufferStruct;
    .
    .
  } CommandData;
} AVC_STREAM_REQUEST_BLOCK, *PAVC_STREAM_REQUEST_BLOCK;

AVC_STREAM_REQUEST_BLOCK Input

SizeOfThisBlock, Version and Function
Use the INIT_AVCSTRM_HEADER macro to initialize these members. Pass AVCSTRM_READ in the Request argument of the macro.
AVCStreamContext
Specifies the stream context (handle) returned by an earlier AVCSTRM_OPEN call that is the source of data for the read operation.
BufferStruct
Specifies the buffer the read operation should place data in.

A subunit driver must first allocate an IRP and an AVC_STREAM_REQUEST_BLOCK structure. Next, it should use the INIT_AVCSTRM_HEADER macro to initialize the AVC_STREAM_REQUEST_BLOCK structure, passing AVCSTRM_READ as the Request argument to the macro. Next, the subunit driver sets the AVCStreamContext member to the stream context (handle) of the stream that provides the data to be read. Finally, the subunit driver sets the BufferStruct member of the CommandData union that describes the buffer the read operation places data into.

To send this request, a subunit submits an IRP_MJ_INTERNAL_DEVICE_CONTROL IRP with the IoControlCode member of the IRP set to IOCTL_AVCSTRM_CLASS and the Argument1 member of the IRP set to the AVC_STREAM_REQUEST_BLOCK structure that describes the read operation to take place.

This command completes asynchronously. When it is completed, the I/O completion routine set in the IRP is called.

This function code must be called at IRQL = PASSIVE_LEVEL.

See Also

AVC_STREAM_REQUEST_BLOCK, INIT_AVCSTRM_HEADER, IRP_MJ_INTERNAL_DEVICE_CONTROL, IOCTL_AVCSTRM_CLASS, AVCSTRM_BUFFER_STRUCT, AVCSTRM_FUNCTION


AVCSTRM_WRITE

The AVCSTRM_WRITE function code is used to submit a data buffer to be transmitted to the specified stream.

I/O Status Block

If successful, avcstrm.sys sets Irp->IoStatus.Status to STATUS_SUCCESS.

Possible error return values include:

Error Status | Description
STATUS_DEVICE_REMOVED | The device corresponding to the AVCSTRM_READ operation no longer exists.
STATUS_CANCELLED | The request was unable to be completed.
STATUS_INVALID_PARAMETER | A parameter specified in the IRP is incorrect,
STATUS_INSUFFICIENT_RESOURCES | There were not sufficient system resources to complete the request.
STATUS_PENDING | The request has been received but requires further processing. The I/O completion routine will handle the final response.

Headers

Declared in avcstrm.h. Include avcstrm.h.

Comments

This function uses the BufferStruct member of the CommandData union in the AVC_STREAM_REQUEST_BLOCK structure as shown below.

typedef struct _AVC_STREAM_REQUEST_BLOCK {
  ULONG  SizeOfThisBlock;
  ULONG  Version;
  AVCSTRM_FUNCTION  Function;
  .
  .
  PVOID AVCStreamContext;
  .
  .
  union _tagCommandData {
    .
    .
    AVCSTRM_BUFFER_STRUCT  BufferStruct;
    .
    .
  } CommandData;
} AVC_STREAM_REQUEST_BLOCK, *PAVC_STREAM_REQUEST_BLOCK;

AVC_STREAM_REQUEST_BLOCK Input

SizeOfThisBlock, Version and Function
Use the INIT_AVCSTRM_HEADER macro to initialize these members. Pass AVCSTRM_WRITE in the Request argument of the macro.
AVCStreamContext
Specifies the stream context (handle) returned by an earlier AVCSTRM_OPEN call that is the target for the data write operation.
BufferStruct
Specifies the buffer the write operation should obtain data from.

A subunit driver must first allocate an IRP and an AVC_STREAM_REQUEST_BLOCK structure. Next, it should use the INIT_AVCSTRM_HEADER macro to initialize the AVC_STREAM_REQUEST_BLOCK structure, passing AVCSTRM_READ as the Request argument to the macro. Next, the subunit driver sets the AVCStreamContext member to the stream context (handle) of the stream that is the target of the write data operation. Finally, the subunit driver sets the BufferStruct member of the CommandData union that describes the buffer the write operation obtains data from.

To send this request, a subunit submits an IRP_MJ_INTERNAL_DEVICE_CONTROL IRP with the IoControlCode member of the IRP set to IOCTL_AVCSTRM_CLASS and the Argument1 member of the IRP set to the AVC_STREAM_REQUEST_BLOCK structure that describes the write operation to take place.

This command completes asynchronously. When it is completed, the I/O completion routine set in the IRP is be called.

This function code must be called at IRQL = PASSIVE_LEVEL.

See Also

AVC_STREAM_REQUEST_BLOCK, INIT_AVCSTRM_HEADER, IRP_MJ_INTERNAL_DEVICE_CONTROL, IOCTL_AVCSTRM_CLASS, AVCSTRM_BUFFER_STRUCT, AVCSTRM_FUNCTION


AVCSTRM_ABORT_STREAMING

The AVCSTRM_ABORT_STREAMING function code cancels all the pending data requests and frees the resources used.

I/O Status Block

If successful, avcstrm.sys sets Irp->IoStatus.Status to STATUS_SUCCESS.

Possible error return values include:

Error Status | Description
STATUS_DEVICE_REMOVED | The device corresponding to the AVCSTRM_READ operation no longer exists.
STATUS_CANCELLED | The request was unable to be completed.
STATUS_INVALID_PARAMETER | A parameter specified in the IRP is incorrect,
STATUS_INSUFFICIENT_RESOURCES | There were not sufficient system resources to complete the request.
STATUS_PENDING | The request has been received but requires further processing. The I/O completion routine will handle the final response.

Headers

Declared in avcstrm.h. Include avcstrm.h.

Comments

Note, this functionality cancels all streaming IRPs. To cancel an individual IRP, use IoCancelIrp.

A subunit should call this when its target device is removed or the original data IRP is cancelled to stop stream operation.

This function does not use any member of the CommandData union in the AVC_STREAM_REQUEST_BLOCK structure.

typedef struct _AVC_STREAM_REQUEST_BLOCK {
  ULONG  SizeOfThisBlock;
  ULONG  Version;
  AVCSTRM_FUNCTION  Function;
  .
  .
  PVOID AVCStreamContext;
  .
  .
} AVC_STREAM_REQUEST_BLOCK, *PAVC_STREAM_REQUEST_BLOCK;

AVC_STREAM_REQUEST_BLOCK Input

SizeOfThisBlock, Version and Function
Use the INIT_AVCSTRM_HEADER macro to initialize these members. Pass AVCSTRM_ABORT_STREAMING in the Request argument of the macro.
AVCStreamContext
Specifies the stream context (handle) returned by an earlier AVCSTRM_OPEN call that is the target for the data write operation.

A subunit driver must first allocate an IRP and an AVC_STREAM_REQUEST_BLOCK structure. Next, it should use the INIT_AVCSTRM_HEADER macro to initialize the AVC_STREAM_REQUEST_BLOCK structure, passing AVCSTRM_READ as the Request argument to the macro. Next, the subunit driver sets the AVCStreamContext member to the stream context (handle) of the stream to abort streaming.

To send this request, a subunit submits an IRP_MJ_INTERNAL_DEVICE_CONTROL IRP with the IoControlCode member of the IRP set to IOCTL_AVCSTRM_CLASS and the Argument1 member of the IRP set to the AVC_STREAM_REQUEST_BLOCK structure that describes the abort streaming operation to take place.

This function code must be called at IRQL = PASSIVE_LEVEL. When a data IRP is being cancelled, it can be executed at the DISPATCH level. In this case, a subunit should start a work item and call this function in its work item routine, which is executing at the PASSIVE level.

See Also

INIT_AVCSTRM_HEADER, IRP_MJ_INTERNAL_DEVICE_CONTROL, IOCTL_AVCSTRM_CLASS, AVCSTRM_FUNCTION


AVCSTRM_OPEN

The AVCSTRM_OPEN function code opens a stream with a specific stream format.

I/O Status Block

If successful, avcstrm.sys sets Irp->IoStatus.Status to STATUS_SUCCESS.

If successful, a STATUS_SUCCESS is returned along with the stream context in AVCStreamContext member of the AVC_STREAM_REQUEST_BLOCK structure. This context is subsequently used for other avcstrm.sys requests.

Possible error return values include:

Error Status | Description
STATUS_DEVICE_REMOVED | The device corresponding to the AVCSTRM_READ operation no longer exists.
STATUS_CANCELLED | The request was unable to be completed.
STATUS_INVALID_PARAMETER | A parameter specified in the IRP is incorrect,
STATUS_INSUFFICIENT_RESOURCES | There were not sufficient system resources to complete the request.
STATUS_PENDING | The request has been received but requires further processing. The I/O completion routine will handle the final response.

Headers

Declared in avcstrm.h. Include avcstrm.h.

Comments

This function uses the OpenStruct member of the CommandData union in the AVC_STREAM_REQUEST_BLOCK structure as shown below.

typedef struct _AVC_STREAM_REQUEST_BLOCK {
  ULONG  SizeOfThisBlock;
  ULONG  Version;
  AVCSTRM_FUNCTION  Function;
  .
  .
  PVOID AVCStreamContext;
  .
  .
  union _tagCommandData {
    .
    .
    AVCSTRM_OPEN_STRUCT  OpenStruct;
    .
    .
  } CommandData;
} AVC_STREAM_REQUEST_BLOCK, *PAVC_STREAM_REQUEST_BLOCK;

AVC_STREAM_REQUEST_BLOCK Input

SizeOfThisBlock, Version and Function
Use the INIT_AVCSTRM_HEADER macro to initialize these members. Pass AVCSTRM_OPEN in the Request argument of the macro.
AVCStreamContext
Specifies the stream context (handle). This should be NULL on input, and if AVCSTRM_OPEN returns successfully, this member contains a valid stream context for subsequent avcstrm.sys operations.
OpenStruct
Specifies the description of the AV/C stream to be created.

The AVCSTRM_FORMAT enumeration provides the list of supported AV/C streaming formats (from the IEC 61883 specifications) that avcstrm.sys supports, such as SDDV (61883-2) and MPEG2TS (61883-4).

In order to make an isochronous connection, the CIP headers and subunit dependent parameters are required and are defined in the AVCSTRM_FORMAT_INFO structure.

The following is an example of the MPEG2TS format information for receiving data:

//
// MPEG2TS
//
    {
        sizeof(AVCSTRM_FORMAT_INFO),
        AVCSTRM_FORMAT_MPEG2TS,
        {
            0,0,
            CIP_DBS_MPEG,
            CIP_FN_MPEG,
            CIP_QPC_MPEG,
            CIP_SPH_MPEG,0,
            0
        },  // CIP header[0]
        {
            0x2,
            CIP_FMT_MPEG,
            CIP_TSF_OFF,
            0, 0,
            0
        },  // CIP header[1]
        SRC_PACKETS_PER_MPEG2TS_FRAME,   // varies depending on number of source packets
        BUFFER_SIZE_MPEG2TS_NO_SPH,       // Remove source packet header
        NUM_OF_XMT_BUFFERS_MPEG2TS,       // Subunit defined
        0,
        FALSE, // not striping SPH is the default
        0,
        BLOCK_PERIOD_MPEG2TS, // 192, / number of 1394 cycle offset to send one block
        0,0,0,0,
    },

A subunit driver must first allocate an IRP and an AVC_STREAM_REQUEST_BLOCK structure. Next, it should use the INIT_AVCSTRM_HEADER macro to initialize the AVC_STREAM_REQUEST_BLOCK structure, passing AVCSTRM_OPEN as the Request argument to the macro. Next, the subunit driver sets the AVCStreamContext member to NULL. On successful operation, this member should contain a valid stream context (a handle) that is used in subsequent avcstrm.sys operations. This member should not be modified thereafter until the stream is closed through AVCSTRM_CLOSE.. Finally, the subunit driver sets the OpenStruct member of the CommandData union that describes the stream to be opened.

To send this request, a subunit submits an IRP_MJ_INTERNAL_DEVICE_CONTROL IRP with the IoControlCode member of the IRP set to IOCTL_AVCSTRM_CLASS and the Argument1 member of the IRP set to the AVC_STREAM_REQUEST_BLOCK structure that describes the open operation to take place.

A subunit driver can expect this command to complete synchronously. The result returns immediately without pending operation in avcstrm.sys.

This function code must be called at IRQL = PASSIVE_LEVEL.

See Also

AVC_STREAM_REQUEST_BLOCK, INIT_AVCSTRM_HEADER, IRP_MJ_INTERNAL_DEVICE_CONTROL, IOCTL_AVCSTRM_CLASS, AVCSTRM_OPEN_STRUCT, AVCSTRM_FUNCTION, AVCSTRM_FORMAT, AVCSTRM_FORMAT_INFO


AVCSTRM_CLOSE

The AVCSTRM_CLOSE function code closes the specified stream and frees any resources allocated in AVCSTRM_OPEN.

I/O Status Block

If successful, avcstrm.sys sets Irp->IoStatus.Status to STATUS_SUCCESS.

Possible error return values include:

Error Status | Description
STATUS_DEVICE_REMOVED | The device corresponding to the AVCSTRM_READ operation no longer exists.
STATUS_CANCELLED | The request was unable to be completed.
STATUS_INVALID_PARAMETER | A parameter specified in the IRP is incorrect,
STATUS_INSUFFICIENT_RESOURCES | There were not sufficient system resources to complete the request.
STATUS_PENDING | The request has been received but requires further processing. The I/O completion routine will handle the final response.

Headers

Declared in avcstrm.h. Include avcstrm.h.

Comments

This function uses the AVCStreamContext member of the CommandData union in the AVC_STREAM_REQUEST_BLOCK structure as shown below.

typedef struct _AVC_STREAM_REQUEST_BLOCK {
  ULONG  SizeOfThisBlock;
  ULONG  Version;
  AVCSTRM_FUNCTION  Function;
  .
  .
  PVOID AVCStreamContext;
  .
  .
} AVC_STREAM_REQUEST_BLOCK, *PAVC_STREAM_REQUEST_BLOCK;

AVC_STREAM_REQUEST_BLOCK Input

SizeOfThisBlock, Version and Function
Use the INIT_AVCSTRM_HEADER macro to initialize these members. Pass AVCSTRM_CLOSE in the Request argument of the macro.
AVCStreamContext
Specifies the stream context (handle) of the stream to close. If AVCSTRM_CLOSE returns successfully, this value is no longer valid.

The following is an example of how to specify the stream to close:

    pAVCStrmReq = &pStrmExt->AVCStrmReq;
    RtlZeroMemory(pAVCStrmReq, sizeof(AVC_STREAM_REQUEST_BLOCK));
    INIT_AVCSTRM_HEADER(pAVCStrmReq, AVCSTRM_CLOSE);

    pAVCStrmReq->AVCStreamContext = pStrmExt->AVCStreamContext;

    Status =
        AVCStrmReqSubmitIrpSynch(
            pDevExt->pBusDeviceObject,
            pStrmExt->pIrpReq,
            pAVCStrmReq
            );

A subunit driver must first allocate an IRP and an AVC_STREAM_REQUEST_BLOCK structure. Next, it should use the INIT_AVCSTRM_HEADER macro to initialize the AVC_STREAM_REQUEST_BLOCK structure, passing AVCSTRM_CLOSE as the Request argument to the macro. Next, the subunit driver sets the AVCStreamContext member to the stream to close.

To send this request, a subunit submits an IRP_MJ_INTERNAL_DEVICE_CONTROL IRP with the IoControlCode member of the IRP set to IOCTL_AVCSTRM_CLASS and the Argument1 member of the IRP set to the AVC_STREAM_REQUEST_BLOCK structure that describes the close operation to take place.

A subunit driver can expect this command to complete synchronously. The result returns immediately without pending operation in avcstrm.sys.

This function code must be called at IRQL = PASSIVE_LEVEL.

See Also

AVC_STREAM_REQUEST_BLOCK, INIT_AVCSTRM_HEADER, IRP_MJ_INTERNAL_DEVICE_CONTROL, IOCTL_AVCSTRM_CLASS, AVCSTRM_FUNCTION


AVCSTRM_GET_STATE

The AVCSTRM_GET_STATE function code obtains the current stream state of the specified stream.

I/O Status Block

If successful, avcstrm.sys sets Irp->IoStatus.Status to STATUS_SUCCESS.

If successful, a STATUS_SUCCESS is returned. The StreamState member of the CommandData union has the current stream state. It can be KSSTATE_STOP, KSTATE_PAUSE, or KSSTATE_RUN.

Possible error return values include:

Error Status | Description
STATUS_DEVICE_REMOVED | The device corresponding to the AVCSTRM_READ operation no longer exists.
STATUS_CANCELLED | The request was unable to be completed.
STATUS_INVALID_PARAMETER | A parameter specified in the IRP is incorrect,
STATUS_INSUFFICIENT_RESOURCES | There were not sufficient system resources to complete the request.
STATUS_PENDING | The request has been received but requires further processing. The I/O completion routine will handle the final response.

Headers

Declared in avcstrm.h. Include avcstrm.h.

Comments

This function uses the StreamState member of the CommandData union in the AVC_STREAM_REQUEST_BLOCK structure as shown below.

typedef struct _AVC_STREAM_REQUEST_BLOCK {
  ULONG  SizeOfThisBlock;
  ULONG  Version;
  AVCSTRM_FUNCTION  Function;
  .
  .
  PVOID AVCStreamContext;
  .
  .
  union _tagCommandData {
    .
    .
    KSSTATE  StreamState;
    .
    .
  } CommandData;
} AVC_STREAM_REQUEST_BLOCK, *PAVC_STREAM_REQUEST_BLOCK;

AVC_STREAM_REQUEST_BLOCK Input

SizeOfThisBlock, Version and Function
Use the INIT_AVCSTRM_HEADER macro to initialize these members. Pass AVCSTRM_GET_STATE in the Request argument of the macro.
AVCStreamContext
Specifies the stream context (handle) returned by an earlier AVCSTRM_OPEN call to obtain the stream state from.
StreamState
If AVCSTRM_GET_STATE returns successfully, this member contains the current stream state.

A subunit driver must first allocate an IRP and an AVC_STREAM_REQUEST_BLOCK structure. Next, it should use the INIT_AVCSTRM_HEADER macro to initialize the AVC_STREAM_REQUEST_BLOCK structure, passing AVCSTRM_GET_STATE as the Request argument to the macro. Next, the subunit driver sets the AVCStreamContext member to the stream context (handle) of the stream to obtain the stream state from.

To send this request, a subunit submits an IRP_MJ_INTERNAL_DEVICE_CONTROL IRP with the IoControlCode member of the IRP set to IOCTL_AVCSTRM_CLASS and the Argument1 member of the IRP set to the AVC_STREAM_REQUEST_BLOCK structure that describes the stream to obtain the stream state from.

A subunit driver can expect this command to be completed synchronously. The result returns immediately without pending operation in avcstrm.sys.

This function code must be called at IRQL = PASSIVE_LEVEL.

See Also

AVC_STREAM_REQUEST_BLOCK, INIT_AVCSTRM_HEADER, IRP_MJ_INTERNAL_DEVICE_CONTROL, IOCTL_AVCSTRM_CLASS, KSSTATE, AVCSTRM_FUNCTION


AVCSTRM_SET_STATE

The AVCSTRM_SET_STATE function code places the specified stream into a new stream state.

I/O Status Block

If successful, avcstrm.sys sets Irp->IoStatus.Status to STATUS_SUCCESS.

Possible error return values include:

Error Status | Description
STATUS_DEVICE_REMOVED | The device corresponding to the AVCSTRM_READ operation no longer exists.
STATUS_CANCELLED | The request was unable to be completed.
STATUS_INVALID_PARAMETER | A parameter specified in the IRP is incorrect,
STATUS_INSUFFICIENT_RESOURCES | There were not sufficient system resources to complete the request.
STATUS_PENDING | The request has been received but requires further processing. The I/O completion routine will handle the final response.

Headers

Declared in avcstrm.h. Include avcstrm.h.

Comments

This function uses the StreamState member of the CommandData union in the AVC_STREAM_REQUEST_BLOCK structure as shown below.

typedef struct _AVC_STREAM_REQUEST_BLOCK {
  ULONG  SizeOfThisBlock;
  ULONG  Version;
  AVCSTRM_FUNCTION  Function;
  .
  .
  PVOID AVCStreamContext;
  .
  .
  union _tagCommandData {
    .
    .
    KSSTATE  StreamState;
    .
    .
  } CommandData;
} AVC_STREAM_REQUEST_BLOCK, *PAVC_STREAM_REQUEST_BLOCK;

AVC_STREAM_REQUEST_BLOCK Input

SizeOfThisBlock, Version and Function
Use the INIT_AVCSTRM_HEADER macro to initialize these members. Pass AVCSTRM_SET_STATE in the Request argument of the macro.
AVCStreamContext
Specifies the stream context (handle) returned by an earlier AVCSTRM_OPEN call to place into a new stream state.
StreamState
Specifies the new stream state to place the stream into.

A subunit driver must first allocate an IRP and an AVC_STREAM_REQUEST_BLOCK structure. Next, it should use the INIT_AVCSTRM_HEADER macro to initialize the AVC_STREAM_REQUEST_BLOCK structure, passing AVCSTRM_GET_STATE as the Request argument to the macro. Next, the subunit driver sets the AVCStreamContext member to the stream context (handle) of the stream to obtain the stream state from.

To send this request, a subunit submits an IRP_MJ_INTERNAL_DEVICE_CONTROL IRP with the IoControlCode member of the IRP set to IOCTL_AVCSTRM_CLASS and the Argument1 member of the IRP set to the AVC_STREAM_REQUEST_BLOCK structure that describes the stream to place into a new stream state.

A subunit driver can expect this command to be completed synchronously. The result returns immediately without pending operation in avcstrm.sys.

This function code must be called at IRQL = PASSIVE_LEVEL.

See Also

AVC_STREAM_REQUEST_BLOCK, INIT_AVCSTRM_HEADER, IRP_MJ_INTERNAL_DEVICE_CONTROL, IOCTL_AVCSTRM_CLASS, KSSTATE, AVCSTRM_FUNCTION


AVCSTRM_GET_PROPERTY

The AVCSTRM_GET_PROPERTY function code is not currently implemented.


AVCSTRM_SET_PROPERTY

The AVCSTRM_SET_PROPERTY function code is not currently implemented.


AV/C Streaming Enumerations

This section describes the enumerations use by avcstrm.sys. To use these enumerations, include the avcstrm.h header file that is shipped with the Windows DDK.


AVCSTRM_FORMAT

The AVCSTRM_FUNCTION enumeration defines the AV/C subunit stream formats supported by avcstrm.sys.

typedef enum _AVCSTRM_FORMAT {
  AVCSTRM_FORMAT_SDDV_NTSC = 0,
  AVCSTRM_FORMAT_SDDV_PAL,
  AVCSTRM_FORMAT_MPEG2TS,
  AVCSTRM_FORMAT_HDDV_NTSC,
  AVCSTRM_FORMAT_HDDV_PAL,
  AVCSTRM_FORMAT_SDLDV_NTSC,
  AVCSTRM_FORMAT_SDLDV_PAL,
} AVCSTRM_FORMAT;

Enumerators

AVCSTRM_FORMAT_SDDV_NTSC
Specifies the 61883-2 specification for SD-DVCR data transmission, Standard Definition NTSC.
AVCSTRM_FORMAT_SDDV_PAL
Specifies the 61883-2 specification for SD-DVCR data transmission, Standard Definition PAL.
AVCSTRM_FORMAT_MPEG2TS
Specifies the 61883-4 specification for MPEG2-TS data transmission.
AVCSTRM_FORMAT_HDDV_NTSC
Specifies the 61883-3 specification for HD-DVCR data transmission, High Definition NTSC. This format is not supported.
AVCSTRM_FORMAT_HDDV_PAL
Specifies the 61883-3 specification for HD-DVCR data transmission, High Definition PAL. This format is not supported.
AVCSTRM_FORMAT_SDLDV_NTSC
Specifies the 61883-5 specification for SDL-DVCR data transmission. NTSC. This format is not supported.
AVCSTRM_FORMAT_SDLDV_PAL
Specifies the 61883-5 specification for SDL-DVCR data transmission. PAL. This format is not supported.

Headers

Defined in avcstrm.h. Include avcstrm.h.

See Also

AVCSTRM_FORMAT_INFO


AVCSTRM_FUNCTION

The AVCSTRM_FUNCTION enumeration defines the functionality exposed by the avcstrm.sys driver.

typedef enum _AVCSTRM_FUNCTION {
  AVCSTRM_READ = 0,
  AVCSTRM_WRITE,
  AVCSTRM_ABORT_STREAMING,
  AVCSTRM_OPEN = 0x100,
  AVCSTRM_CLOSE,
  AVCSTRM_GET_STATE,
  AVCSTRM_SET_STATE,
  AVCSTRM_GET_PROPERTY,
  AVCSTRM_SET_PROPERTY,
} AVCSTRM_FUNCTION;

Enumerators

AVCSTRM_READ
Read data from a stream.
AVCSTRM_WRITE
Write data to a stream.
AVCSTRM_ABORT_STREAMING
Abort streaming. This cancels all streaming IRPs. To cancel an individual IRP, use IoCancelIrp.
AVCSTRM_OPEN
Open a stream in a specific format.
AVCSTRM_CLOSE
Close a stream and free any resources allocated for the stream.
AVCSTRM_GET_STATE
Obtain the stream state.
AVCSTRM_SET_STATE
Place the stream into a new state.
AVCSTRM_GET_PROPERTY
Get stream property. This function is not implemented.
AVCSTRM_SET_PROPERTY
Set stream property. This function is not implemented.

Headers

Defined in avcstrm.h. Include avcstrm.h.

See Also

AVCSTRM_READ, AVCSTRM_WRITE, AVCSTRM_ABORT_STREAMING, AVCSTRM_OPEN, AVCSTRM_CLOSE, AVCSTRM_GET_STATE, AVCSTRM_SET_STATE, AVCSTRM_GET_PROPERTY, AVCSTRM_SET_PROPERTY


AV/C Streaming Structures

This section describes the structures use by avcstrm.sys. To use these structures, include the avcstrm.h header file that is shipped with the Windows DDK.


AVC_STREAM_REQUEST_BLOCK

The AVC_STREAM_REQUEST_BLOCK structure describes an AV/C streaming request to be processed by avcstrm.sys.

typedef struct _AVC_STREAM_REQUEST_BLOCK {
  ULONG  SizeOfThisBlock;
  ULONG  Version;
  AVCSTRM_FUNCTION  Function;
  ULONG  Flags;
  NTSTATUS  Status;
  PVOID  AVCStreamContext;
  PVOID  Context1;
  PVOID  Context2;
  PVOID  Context3;
  PVOID  Context4;
  ULONG  Reserved[4];
  union _tagCommandData {
    KSSTATE  StreamState;
    AVCSTRM_OPEN_STRUCT  OpenStruct;
    AVCSTRM_BUFFER_STRUCT  BufferStruct;
  } CommandData;
} AVC_STREAM_REQUEST_BLOCK, *PAVC_STREAM_REQUEST_BLOCK;

Members

SizeOfThisBlock
Specifies the size of the request block in bytes. Do not set this value directly. Instead, use the INIT_AVCSTRM_HEADER macro.
Version
Specifies the version of avcstrm.sys device driver interface (DDI) to service a request. Do not set this value directly. Instead, use the INIT_AVCSTRM_HEADER macro.
Function
Indicates the request (function code) avcstrm.sys services. This must be a value from the AVCSTRM_FUNCTION enumeration. Do not set this value directly. Instead, use the INIT_AVCSTRM_HEADER macro.
Flags
Special flags to indicate special service or deviation from standard service. This is currently not used.
Status
Final status of this request.
AVCStreamContext
This is context (handle) of a stream. Set this to NULL for the AVCSTRM_OPEN function code. For other function codes, this must be set to a valid value retrieved from an earlier call to AVCSTRM_OPEN.
Context1
The context pointers of the client.
Context2
The context pointers of the client.
Context3
The context pointers of the client.
Context4
The context pointers of the client.
Reserved
Reserved. Do not use.
CommandData
This is a union of command data to be passed to avcstrm.sys for service.
StreamState
Specifies the current state of the specified stream. This is used with the AVCSTRM_GET_STATE and AVCSTRM_SET_STATE function codes.
OpenStruct
Specifies a description of a stream to open. This is used with the AVCSTRM_OPEN function code.
BufferStruct
Specifies a description of a buffer used to read or write data from/to a specified stream. This is used with the AVCSTRM_READ and AVCSTRM_WRITE function codes.

Headers

Defined in avcstrm.h. Include avcstrm.h.

Comments

The AVC_STREAM_REQUEST_BLOCK is the primary structure used by a subunit driver to interface with avcstrm.sys.

Every AV/C stream request is described by this structure. This structure is passed as part of the IRP to avcstrm.sys for service..

To use this structure, set the IRP's Irp->Parameters->Others.Argument1 member to an allocated and initialized AVC_STREAM_REQUEST_BLOCK that describes the request (functionality) that the subunit driver wants avcstrm.sys to service.

See Also

AVCSTRM_FUNCTION, KSSTATE, AVCSTRM_OPEN_STRUCT, AVCSTRM_BUFFER_STRUCT, AVCSTRM_READ, AVCSTRM_WRITE, AVCSTRM_OPEN, AVCSTRM_CLOSE, AVCSTRM_ABORT_STREAMING, AVCSTRM_GET_STATE, AVCSTRM_SET_STATE, AVCSTRM_GET_PROPERTY, AVCSTRM_SET_PROPERTY


AVCSTRM_BUFFER_STRUCT

The AVCSTRM_BUFFER_STRUCT structure describes a buffer to be submitted to avcstrm.sys for read or write operations.

typedef struct _AVCSTRM_BUFFER_STRUCT {
  BOOL  ClockProvider;
  HANDLE  ClockHandle;
  PKSSTREAM_HEADER  StreamHeader;
  PVOID  FrameBuffer;
  PVOID  Context;
} AVCSTRM_BUFFER_STRUCT, * PAVCSTRM_BUFFER_STRUCT;

Members

ClockProvider
Indicates whether the subunit driver itself serves as a clock provider. This is TRUE if this stream also serves as a clock provider, Otherwise, this is FALSE.
ClockHandle
Specifies a handle to a clock provider other than the subunit driver itself.
StreamHeader
Pointer to a kernel streaming header that describes a packet of data to be read from or written to a streaming driver pin.
FrameBuffer
Pointer to a non-paged system-space virtual address for the buffer described by the MDL.
Context
Pointer to a client context value.

Headers

Defined in avcstrm.h. Include avcstrm.h.

See Also

KSSTREAM_HEADER


AVCSTRM_FORMAT_INFO

The AVCSTRM_FORMAT_INFO structure is used to describe a data stream.

typedef struct _AVCSTRM_FORMAT_INFO {
  ULONG  SizeOfThisBlock;
  AVCSTRM_FORMAT  AVCStrmFormat;
  CIP_HDR1  cipHdr1;
  CIP_HDR2_SYT  cipHdr2;
  ULONG  SrcPacketsPerFrame;
  ULONG FrameSize;
  ULONG  NumOfRcvBuffers;
  ULONG  NumOfXmtBuffers;
  DWORD  OptionFlags;
  ULONG  AvgTimePerFrame;
  ULONG  BlockPeriod;
  ULONG Reserved[4];
} AVCSTRM_FORMAT_INFO, * PAVCSTRM_FORMAT_INFO;

Members

SizeOfThisBlock
Specifies the size of this data structure, in bytes.
AVCStrmFormat
Specifies one of the AV/C streaming subunit formats defined in AVCSTRM_FORMAT.
cipHdr1
Specifies the definition of the first quadlet of the two quadlet CIP header.
cipHdr2
Specifies the definition of the second quadlet of the two quadlet CIP header.
SrcPacketsPerFrame
Specifies the number of source packets to fill a data frame.
FrameSize
Specifies the data buffer size.
NumOfRcvBuffers
Specifies the number of receiving buffers.
NumOfXmtBuffers
Specifies the number of transmitting buffers.
OptionFlags
Specifies any option flags. Currently, only one flag is defined:
AVCSTRM_FORMAT_OPTION_STRIP_SPH
Strip the SPH (source packet header) from the 192-byte data packet for MPEG2TS.
AvgTimePerFrame
Specifies the average time per frame in 100 nanosecond units.
BlockPeriod
Specifies the block period. This is used for transmit only. It is calculated from 1/ BlockPerSecond * 1,000,000,000 picoseconds. For SDDV, it transmits one block per 1394 cycle. 1/(29.97 * 250) * 1,000,000,000,000 = 133,466,800 picoseconds.
Reserved
Reserved. Do not use. Must be set to 0.

Headers

Defined in avcstrm.h. Include avcstrm.h.

See Also

AVCSTRM_FORMAT, CIP_HDR1, CIP_HDR2_FDF, CIP_HDR2_MPEGTS, CIP_HDR2_SYT


AVCSTRM_OPEN_STRUCT

The AVCSTRM_OPEN_STRUCT structure describes a data stream to be opened.

typedef struct _AVCSTRM_OPEN_STRUCT {
  KSPIN_DATAFLOW  DataFlow;
  PAVCSTRM_FORMAT_INFO  AVCFormatInfo;
  PVOID  AVCStreamContext;
  HANDLE hPlugLocal
} AVCSTRM_OPEN_STRUCT, * PAVCSTRM_OPEN_STRUCT;

Members

DataFlow
Specifies the direction of the data-flow.
AVCFormatInfo
Pointer to a description of the subunit stream format.
AVCStreamContext
Pointer to a stream context (handle) that is passed to subsequent avcstrm.sys operations. Its content should not be used or altered.
hPlugLocal
Specifies a local plug created by an AV/C subunit, which is used to connect to the target device.

Headers

Defined in avcstrm.h. Include avcstrm.h.

Comments

The AVCSTRM_OPEN function code uses this structure to describe the open operation. If the operation is successful, a stream context (handle) is returned to the caller in the AVCStrmContext member of this structure, not the AVCStrmContext member in the AVC_STREAM_REQUEST_BLOCK structure.

This value can then be used in subsequent avcstrm.sys operations by placing it in the AVCStrmContext member of the AVC_STREAM_REQUEST_BLOCK structure.

See Also

AVCSTRM_FORMAT_INFO, AVCSTRM_OPEN


CIP_HDR1

The CIP_HDR1 structure describes the generic data structure of the two quadlet CIP headers (first quadlet of the pair).

typedef struct _CIP_HDR1 {
    ULONG DBC:           8;
    ULONG Rsv00:         2;
    ULONG SPH:           1;
    ULONG QPC:           3;
    ULONG FN:            2;
    ULONG DBS:           8;
    ULONG SID:           6;
    ULONG Bit00:         2;
} CIP_HDR1, *PCIP_HDR1;

Members

DBC
Data block counter. This is not used by subunit driver. It must be set to 0.
Rsv00
Reserved bits. Do not use this. It must be 0:0.
SPH
Specifies a source packet header. A value of 1 indicates the presence of a source packet header. A value of 0 indicates no source packet header.
QPC
Quadlet padding count (0..7 quadlets).
FN
Specifies the fractional number.
DBS
Specifies the data block size in quadlets.
SID
Specifies the source node ID (ID of transmitter). Not used by the subunit driver. Must be set to 0.
Bit00
Must be set to 0:0.

Headers

Defined in avcstrm.h. Include avcstrm.h.

See Also

CIP_HDR2_FDF, CIP_HDR2_MPEGTS, CIP_HDR2_SYT


CIP_HDR2_FDF

The CIP_HDR2_FDF structure describes the second quadlet of a CIP header pair.

typedef struct _CIP_HDR2_FDF {
  ULONG  FDF:         24;
  ULONG  FMT:          6;
  ULONG  Bit10:        2;
} CIP_HDR2_FDF, *PCIP_HDR2_FDF;

Members

FDF
Format dependent field. This is not used for opening a stream. These must be set to 0.
FMT
CIP format. For example, 000000 = DV and 100000 = MPEG2TS.
Bit10
Must be set to 1:0

Headers

Defined in avcstrm.h. Include avcstrm.h.

See Also

CIP_HDR1


CIP_HDR2_MPEGTS

The CIP_HDR2_MPEGTS structure describes the second quadlet of a CIP header pair for an MPEGTS format stream.

typedef struct _CIP_HDR2_MPEGTS {
  ULONG  TSF:          1;
  ULONG  RSV23bit:    23;
  ULONG  FMT:          6;
  ULONG  Bit10:        2;
} CIP_HDR2_MPEGTS, *PCIP_HDR2_MPEGTS;

Members

TSF
Time-shift flag. This is not used for opening a stream.
RSV23bit
Reserved bits. This must be 0. Do not use this.
FMT
CIP format. For example, 000000 = DV and 100000 = MPEGTS.
Bit10
Must be set to 1:0

Headers

Defined in avcstrm.h. Include avcstrm.h.

See Also

CIP_HDR1


CIP_HDR2_SYT

The CIP_HDR2_SYT structure describes the second quadlet of a CIP header pair for a DV format stream.

typedef struct _CIP_HDR2_SYT {
  ULONG SYT:          16;
  ULONG RSV:           2;
  ULONG STYPE:         5;
  ULONG F5060_OR_TSF:  1;
  ULONG FMT:           6;
  ULONG Bit10:         2;
} CIP_HDR2_SYT, *PCIP_HDR2_SYT;

Members

SYT
Lower 16 bits of CYCLE_TIME. This is not used for opening a stream.
RSV
Must be set to 0:0.
STYPE
Specifies the video signal type, which is used for transmitting real time data.
F5060_OR_TSF
Specifies field encoding or time-shift flag depending on the value of FMT. This flag may be either 0 for NTSC or 1 for PAL, or 1 for TimeShiftFlag. This flag has multiple meanings (like a union) depending on the FMT member. If the FMT member indicates DV format, then this is either 50/60 flag (NTSC or PAL); if it is it MPEG-TS, then this is a time-shifting flag.
FMT
CIP format ID. For example, 000000 = DV and 100000 = MPEG2TS. If this is 111111 (no data), then DBS, FN, SPH and DBC (in the first quadlet of the CIP header, CIP_HDR1) are ignored.
Bit10
Must be set to 1:0.

Headers

Defined in avcstrm.h. Include avcstrm.h.

See Also

CIP_HDR1


DVINFO

The DVINFO structure describes a DV stream format including its default streaming source information and stream control information.

typedef struct _DVINFO {
  DWORD    dwDVAAuxSrc;
  DWORD    dwDVAAuxCtl;
  DWORD    dwDVAAuxSrc1;
  DWORD    dwDVAAuxCtl1;
  DWORD    dwDVVAuxSrc;
  DWORD    dwDVVAuxCtl;
  DWORD    dwDVReserved[2];
} DVINFO, *PDVINFO;

Members

dwDVAAuxSrc
Specifies the Audio Auxiliary Data Source Pack for the first audio block (first 5 DV DIF sequences for 525-60 systems or 6 DV DIF sequences for 625-50 systems) of a frame. A DIF sequence is a data block that contains 150 DIF blocks. A DIF block consists of 80 bytes. The Audio Auxiliary Data Source Pack is defined in section D.7.1 of Part 2, Annex D, "The Pack Header Table and Contents of Packs" of the Specification of Consumer-use Digital VCRs.
dwDVAAuxCtl
Specifies the Audio Auxiliary Data Source Control Pack for the first audio block of a frame. The Audio Auxiliary Data Control Pack is defined in section D.7.2 of Part 2, Annex D, "The Pack Header Table and Contents of Packs" of the Specification of Consumer-use Digital VCRs.
dwDVAAuxSrc1
Specifies the Audio Auxiliary Data Source Pack for the second audio block (second 5 DV DIF sequences for 525-60 systems or 6 DV DIF sequences for 625-50 systems) of a frame.
dwDVAAuxCtl1
Specifies the Audio Auxiliary Data Source Control Pack for the second audio block of a frame.
dwDVVAuxSrc
Specifies the Video Auxiliary Data Source Pack as defined in section D.8.1 of Part 2, Annex D, "The Pack Header Table and Contents of Packs" of the Specification of Consumer-use Digital VCRs.
dwDVVAuxCtl
Specifies the Video Auxiliary Data Source Control Pack as defined in section D.8.2 of Part 2, Annex D, "The Pack Header Table and Contents of Packs" of the Specification of Consumer-use Digital VCRs.
dwDVReserved
Reserved. This must be set to 0. Do not use this.

Headers

Defined in avcstrm.h. Include avcstrm.h.


KS_DATAFORMAT_DV_AVC

The KS_DATAFORMAT_DV_AVC structure stores the data format for an AV/C digital video connection.

typedef struct tagKS_DATAFORMAT_DV_AVC {
  KSDATAFORMAT DataFormat;
  DVINFO       DVVideoInfo;
  AVCCONNECTINFO ConnectInfo;
} KS_DATAFORMAT_DV_AVC, *PKS_DATAFORMAT_DV_AVC;

Members

DataFormat
Specifies the data format of the digital video connection.
DVVideoInfo
Specifies the digital video information, for example, sound tracks and video information.
ConnectInfo
Specifies the AV/C connection information.

Headers

Defined in avcstrm.h. Include avcstrm.h.

See Also

KSDATAFORMAT, DVINFO, AVCCONNECTINFO


KS_DATAFORMAT_MPEG2TS_AVC

The KS_DATAFORMAT_MPEG2TS_AVC structure stores the data format for an AV/C MPEG2 connection.

typedef struct tagKS_DATAFORMAT_MPEG2TS_AVC {
  KSDATAFORMAT DataFormat;
  AVCCONNECTINFO ConnectInfo;
} KS_DATAFORMAT_MPEG2TS_AVC, *PKS_DATAFORMAT_MPEG2TS_AVC;

Members

DataFormat
Specifies the data format of the MPEG2 connection.
ConnectInfo
Specifies the AV/C connection information.

Headers

Defined in avcstrm.h. Include avcstrm.h.

See Also

KSDATAFORMAT, AVCCONNECTINFO


KS_DATARANGE_DV_AVC

The KS_DATARANGE_DV_AVC structure stores a range of AV/C digital video formats.

typedef struct tagKS_DATARANGE_DV_AVC {
  KSDATARANGE  DataRange;
  DVINFO       DVVideoInfo;
  AVCPRECONNECTINFO ConnectInfo;
} KS_DATARANGE_DV_AVC, *PKS_DATARANGE_DV_AVC;

Members

DataRange
Specifies the range of supported AV/C digital video formats.
DVVideoInfo
Specifies the digital video information, for example, sound tracks and video information.
ConnectInfo
Specifies the AV/C preconnection info.

Headers

Defined in avcstrm.h. Include avcstrm.h.

See Also

KSDATARANGE, DVINFO, AVCPRECONNECTINFO


KS_DATARANGE_DVVIDEO

The KS_DATARANGE_DV_AVC structure stores a range of digital video formats.

typedef struct tagKS_DATARANGE_DVVIDEO {
  KSDATARANGE  DataRange;
  DVINFO       DVVideoInfo;
} KS_DATARANGE_DVVIDEO, *PKS_DATARANGE_DVVIDEO;

Members

DataRange
Specifies the range of supported digital video formats.
DVVideoInfo
Specifies the digital video information, for example, sound tracks and video information.

Headers

Defined in avcstrm.h. Include avcstrm.h.

See Also

KSDATARANGE, DVINFO


KS_DATARANGE_MPEG2TS_AVC

The KS_DATARANGE_MPEG2TS_AVC structure stores a range of AV/C MPEG2 formats.

typedef struct tagKS_DATARANGE_MPEG2TS_AVC {
  KSDATARANGE  DataRange;
  AVCPRECONNECTINFO ConnectInfo;
} KS_DATARANGE_MPEG2TS_AVC, *PKS_DATARANGE_MPEG2TS_AVC;

Members

DataRange
Specifies the range of supported AV/C MPEG2 formats.
ConnectInfo
Specifies the AV/C preconnection info.

Headers

Defined in avcstrm.h. Include avcstrm.h.

See Also

KSDATARANGE, AVCPRECONNECTINFO


Kernel Streaming Proxy Reference

The kernel-streaming (KS) proxy module represents KS filters of KS minidrivers as Microsoft® DirectShow® filters by assuming the characteristics of those KS filters. The proxy then sends control down to kernel mode while reflecting events in user mode. The KS proxy module also lets applications control and retrieve information from KS objects that a KS minidriver implements. KS objects include, for example, KS filters, KS pins, and KS clocks. The following sections document the KS proxy COM interfaces, exported helper functions, and structures used by applications and plug-ins.

Kernel Streaming Proxy Interfaces

Kernel Streaming Proxy Exported Functions

Kernel Streaming Proxy Structures


Kernel Streaming Proxy Interfaces

An application or a plugin can use the kernel-streaming (KS) proxy COM interfaces to control and retrieve information from KS objects that a KS minidriver handles. KS objects include, for example, KS filters, KS pins, and KS clocks. The system-supplied KS proxy library (ksproxy.lib) provides these COM interfaces. In order for an application to use these COM interfaces, you must include the ksproxy.h header file in the application's code and link to ksproxy.lib when you build your application.

Note IUnknown methods are common to all COM interfaces. COM interfaces support the AddRef, QueryInterface, and Release methods. See the Platform SDK documentation for more information on IUnknown interface methods.

The following sections provide more information about the KS proxy interfaces:

IKsAggregateControl

IKsAllocator

IKsAllocatorEx

IKsClockPropertySet

IKsControl

IKsDataTypeCompletion

IKsDataTypeHandler

IKsInterfaceHandler

IKsObject

IKsPin

IKsPinEx

IKsPinFactory

IKsPinPipe

IKsPropertySet

IKsQualityForwarder

IKsTopology


IKsAggregateControl

The IKsAggregateControl interface provides methods that add and remove COM servers as aggregate providers on kernel-streaming (KS) objects that support the interface. KS objects include, for example, KS filters, KS pins, and KS clocks.

The interface identifier (IID) for this interface is IID_IKsAggregateControl.

When to Implement

It is not necessary to implement the methods of this interface. They are implemented in ksproxy.lib for KS filters and pins.

When to Use

Use this interface to add and remove inner aggregate objects on a KS filter or pin.

Methods

The following methods are listed in Vtable order

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments reference count.
Release | Decrements reference count.

IKsAggregateControl method | Description
KsAddAggregate | Adds a COM server as an aggregate provider to a KS filter or pin.
KsRemoveAggregate | Removes a previously added COM server aggregate provider from a KS filter or pin.

Comments

All property, method, and events sets that a KS filter or pin supports can be represented on the DirectShow proxy representation of the filter or pin object by zero or more aggregated interfaces, dialogs, and so on. These client aggregated interfaces are set extensions that can then be used to communicate to the underlying KS object in order to represent the functionality of the set. A set extension is a registered COM server, which is loaded through CoCreateInstance by the KS filter or pin at handle creation time.

The primary purpose of set extensions is to allow aggregation of interfaces so as to support some set through one or more COM interfaces. However, an implementation may also include support of dialogs, asynchronous processing in threads, and so on. Registration of a set handler allows one to indicate either a specific interface that is to be aggregated or that an unnamed list of interfaces will be exposed. In the first case, only appropriate queries are sent to the object, and in the latter all queries that do not match an interface already supported are sent to this extension object.

An extension may also receive notifications of state changes by supporting the IDistributorNotify interface. If the extension object supports this interface, it will be notified of all start, stop, and pause state changes before the filter itself processes those changes. In addition, the IDistibutorNotify::NotifyGraphChange method is used on pin object extensions to indicate that the KS pin instance has just closed. This method is only used for pin interface extensions and is called on an extension object each time the pin is disconnected or reconnected, while the extension object is still loaded and aggregated by the pin object.

Notification on pin-connection changes is required because the extensions are not unloaded when a pin is disconnected. Instead, extensions are loaded the first time the pin is connected and left loaded through disconnects and reconnects, unless a reconnect indicates that the particular extension set is not supported on the pin any longer. This fact allows an extension object to retain state between reconnections, but it also means that an extension might require information about whether the KS pin is currently connected. The extension can determine this information by calling the IKsObject::KsGetObjectHandle method to query for the KS pin's object handle when the extension receives a NotifyGraphChange call. When the extension is first loaded, it can assume the pin is connected and any subsequent notification may imply a disconnection, or reconnection. Thus, the notification occurs after the actual change occurs, as opposed to state changes, which notify before.

A set extension is basically a COM server that optionally exposes the IDistributorNotify interface and zero or more other aggregated interfaces that can be used by a client of the filter to manipulate sets that the extension object represents. On an extension object creation request through CoCreateInstance, the server is always presented an outer IUnknown with which to create the COM object. This IUnknown is an interface on the filter or pin object that is loading set extensions. The IUnknown interface pointer may be used to query information or interfaces from the filter or pin, such as IKsControl. However, no reference should be left on the outer object, as it will result in a circular reference count. Using the interfaces without a reference count is acceptable, because the extension is aggregated by the outer object and, by definition, is destroyed when the outer object's reference count reaches zero.

In order to load set extensions, the proxy looks up the GUID of each set collected from the filter or pin, determining if each is present in the registry. The GUID for each set that is to have an extension loaded is:

HKLM\System\CurrentControlSet\Control\MediaInterfaces\{set guid}

If this subkey is present, the GUID of the set corresponds directly to the GUID used in the COM server parameter of the CoCreateInstance call. Each subkey may also have a named binary value iid that contains the binary representation of the GUID for the interface to be aggregated for this set extension. This is the interface GUID that will cause a QueryInterface on the filter or pin to be sent to the COM server for this extension. If this named value is not present under the subkey, all unknown QueryInterface calls will be routed through this extension object, thus allowing it to support many interfaces for a particular set exposed on the underlying object. The GUID of the set could be used as the interface identifier by either setting iid to be the GUID of the set, or by not setting an iid value. In the latter case, additional queries not supported may be sent to the extension object.

Although the MediaInterfaces registry key may be used to explicitly indicate which interface (if any) the provider aggregates, the entire entry need not be present. The implication being that any COM server can be loaded through IKsAggregateControl so that this COM server provides aggregated interfaces, whether or not the COM server is listed under the MediaInterfaces registry key.

For sets that are supported and already have defined extension object handlers that are automatically registered at installation time or when a specific type of device is added to the system, the driver installation need not perform any additional work in exposing these COM interfaces for their filter. However, to expose COM interfaces for private sets, both the MediaInterfaces entry and the COM server entry need to be added when the filter is installed.

The proxy also allows a filter to override the COM server for a set registered under MediaInterfaces. To override, create a SetAliases key under the Plug and Play interface registry key. CLSID and FriendlyName are located in the path HKLM\…\SetAliases.

Also, enter the named value {set guid}, which is the string format of the set GUID, as the binary value of the GUID for the replacement MediaInterfaces subkey. Thus, for this filter or any object under this filter, all sets with this GUID will use this alternate GUID to look for a MediaInterfaces entry rather than the GUID of the set itself. The new MediaInterfaces entry would be registered as usual.

For more information on IDistributorNotify, IUnknown, and CoCreateInstance, see the Platform SDK documentation.

See Also

IKsControl, IKsObject::KsGetObjectHandle


IKsAggregateControl::KsAddAggregate

The KsAddAggregate method adds a COM server as an aggregate provider to the list of interface providers for the KS object that exposes the IKsAggregateControl interface.

HRESULT
  KsAddAggregate(
    IN REFGUID  AggregateClass
    );

Parameters

AggregateClass
Identifies the COM server to add.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

See Also

IKsAggregateControl::KsRemoveAggregate, IKsAggregateControl


IKsAggregateControl::KsRemoveAggregate

The KsRemoveAggregate method removes a previously added COM server aggregate provider from the list of interface providers for the KS object that exposes the IKsAggregateControl interface.

HRESULT
  KsRemoveAggregate(
    IN REFGUID  AggregateClass
    );

Parameters

AggregateClass
Identifies the COM server to remove.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

See Also

IKsAggregateControl::KsAddAggregate, IKsAggregateControl


IKsAllocator

The IKsAllocator interface is for proxy use and not recommended for application use. IKsAllocator provides methods that control and query an allocator.

The interface identifier (IID) for this interface is IID_IKsAllocator.

When to Implement

It is not necessary to implement the methods of this interface. They are implemented in Ksproxy.lib.

When to Use

Not recommended for application use.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments reference count.
Release | Decrements reference count.

IKsAllocator method | Description
KsGetAllocatorHandle | Retrieves a file handle to an allocator.
KsGetAllocatorMode | Returns the mode in which an allocator allocates memory.
KsGetAllocatorStatus | Retrieves the status of an allocator.
KsSetAllocatorMode | Sets the mode in which an allocator allocates memory.


IKsAllocatorEx

The IKsAllocatorEx interface is for proxy use and not recommended for application use. IKsAllocatorEx inherits all the methods of the IKsAllocator interface and extends IKsAllocator to provide methods that further control and query an allocator.

The interface identifier (IID) for this interface is IID_IKsAllocatorEx.

When to Implement

It is not necessary to implement the methods of this interface. They are implemented in Ksproxy.lib.

When to Use

Not recommended for application use.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments reference count.
Release | Decrements reference count.

IKsAllocator method | Description
KsGetAllocatorHandle | Retrieves a file handle to an allocator.
KsGetAllocatorMode | Returns the mode in which an allocator allocates memory.
KsGetAllocatorStatus | Retrieves the status of an allocator.
KsSetAllocatorMode | Sets the mode in which an allocator allocates memory.

IKsAllocatorEx method | Description
KsGetProperties | Returns the properties for an allocator.
KsSetProperties | Sets the properties for an allocator.
KsSetAllocatorHandle | Sets the handle for an allocator.
KsCreateAllocatorAndGetHandle | Creates an allocator for a pin and retrieves a file handle to the allocator.


IKsClockPropertySet

The IKsClockPropertySet interface provides methods that let the proxy accurately reflect time.

The interface identifier (IID) for this interface is IID_IKsClockPropertySet.

When to Implement

It is not necessary to implement the methods of this interface. They are implemented in Ksproxy.lib.

When to Use

Use this interface to access the underlying kernel streaming filter clocks and to use them in the user-mode proxy module.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments reference count.
Release | Decrements reference count.

IKsClockPropertySet method | Description
KsGetCorrelatedPhysicalTime | Retrieves the physical time and the correlated system time from the underlying clock.
KsGetCorrelatedTime | Retrieves the presentation time and the correlated system time from the underlying clock.
KsGetPhysicalTime | Retrieves the current physical time from the underlying clock.
KsGetResolution | Retrieves the clock resolution from the underlying clock.
KsGetState | Retrieves the streaming state of a pin from the underlying clock.
KsGetTime | Retrieves the current presentation time from the underlying clock.
KsSetCorrelatedPhysicalTime | Sets the physical time with the correlated system time on the underlying clock.
KsSetCorrelatedTime | Sets the correlated system time with the presentation time on the underlying clock.
KsSetPhysicalTime | Sets the current physical time on the underlying clock.
KsSetTime | Sets the current presentation time on the underlying clock.


IKsClockPropertySet::KsGetCorrelatedPhysicalTime

The KsGetCorrelatedPhysicalTime method retrieves the physical time and the correlated system time from the underlying clock.

HRESULT
  KsGetCorrelatedPhysicalTime(
    OUT KSCORRELATED_TIME  *CorrelatedTime
    );

Parameters

CorrelatedTime
Pointer to a variable that receives a KSCORRELATED_TIME structure that contains the physical clock time along with the correlated system time.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The proxy uses the KSPROPERTY_CLOCK_CORRELATEDPHYSICALTIME property to retrieve the correlated time.

See Also

IKsClockPropertySet::KsSetCorrelatedPhysicalTime, KSCORRELATED_TIME, KSPROPERTY_CLOCK_CORRELATEDPHYSICALTIME


IKsClockPropertySet::KsGetCorrelatedTime

The KsGetCorrelatedTime method retrieves the current time and the correlated system time from the underlying clock.

HRESULT
  KsGetCorrelatedTime(
    OUT KSCORRELATED_TIME  *CorrelatedTime
    );

Parameters

CorrelatedTime
Pointer to a variable that receives a KSCORRELATED_TIME structure that contains the current clock time along with the correlated system time.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The KsGetCorrelatedTime method retrieves the current time and the correlated system in an atomic operation.

The proxy uses the KSPROPERTY_CLOCK_CORRELATEDTIME property to retrieve the correlated time.

See Also

IKsClockPropertySet::KsSetCorrelatedTime, KSCORRELATED_TIME, KSPROPERTY_CLOCK_CORRELATEDTIME


IKsClockPropertySet::KsGetPhysicalTime

The KsGetPhysicalTime method retrieves the physical time from the underlying clock.

HRESULT
  KsGetPhysicalTime(
    OUT LONGLONG  *Time
    );

Parameters

Time
Pointer to a variable that receives the current physical time.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The physical time is based on some underlying physical clock that always progresses, even if the physical type of clock must be changed in real time. Other physical clocks use an underlying clock's physical time for rate matching.

The proxy uses the KSPROPERTY_CLOCK_PHYSICALTIME property to retrieve the physical time.

See Also

IKsClockPropertySet::KsSetPhysicalTime, KSPROPERTY_CLOCK_PHYSICALTIME


IKsClockPropertySet::KsGetResolution

The KsGetResolution method retrieves the clock resolution from the underlying clock.

HRESULT
  KsGetResolution(
   OUT KSRESOLUTION  *Resolution
    );

Parameters

Resolution
Pointer to a variable that receives a KSRESOLUTION structure that contains the granularity and error of the underlying clock.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The KsGetResolution method retrieves the underlying clock's resolution property, which specifies the underlying clock's increment granularity and notification error in terms of 100-nanosecond units. The best granularity would be one 100-nanosecond unit; less granular increments would contain larger numbers. The least amount of notification error above and beyond the clock granularity would be reported as zero 100-nanosecond units, and less accurate clocks would use larger numbers to indicate ± error. The proxy can use this resolution property to determine maximum error and resolution in event notification and synchronization.

The proxy uses the KSPROPERTY_CLOCK_RESOLUTION property to retrieve the clock resolution.

See Also

KSPROPERTY_CLOCK_RESOLUTION, KSRESOLUTION


IKsClockPropertySet::KsGetState

The KsGetState method retrieves the streaming state of a pin from the underlying clock.

HRESULT
  KsGetState(
    OUT KSSTATE  *State
    );

Parameters

State
Pointer to a variable that receives a value that specifies the streaming state of a pin. This value can be one of the following values from the KSSTATE enumeration:
Value | Description
KSSTATE_STOP | The streaming of data to or from the pin is stopped. Represents the initial state of the pin with the least resource usage and the most latency to obtain a KSSTATE_RUN state.
KSSTATE_ACQUIRE | Represents the state at which allocators are negotiated and resources acquired, though no data may be buffered in this state.
KSSTATE_PAUSE | The clock is waiting and is prepared to instantly change to the KSSTATE_RUN state. Represents the mode of most resource usage and least latency to a Run state, without actually being in a KSSTATE_RUN state. Data can be buffered in this state. If the state of the pin is queried and that state is currently paused, the pin can return an error of STATUS_NO_DATA_DETECTED to indicate that this pin does not perform queuing of data when in a paused state.
KSSTATE_RUN | The pin is streaming data. That is, the pin consumes or produces stream data.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The state of the pin gives gross motor control for pins. Fine motor control is done on a class-by-class basis with custom properties. For instance, in order to make an external laser disc player spin up, you could set a custom Mode property specific to that class. Setting this property may also change the state of the device, though not necessarily, depending on the effect of the mode.

A filter itself can support this state property so that applications can set the entire filter's state. Otherwise, each pin must have its state set. When the state of a pin transitions from KSSTATE_STOP, each connection that forwards IRPs must recalculate stack depth.

The proxy uses the KSPROPERTY_CLOCK_STATE property to retrieve the streaming state of a pin.

See Also

KSPROPERTY_CLOCK_STATE


IKsClockPropertySet::KsGetTime

The KsGetTime method retrieves the time of the underlying clock.

HRESULT
  KsGetTime(
    OUT LONGLONG  *Time
    );

Parameters

Time
Pointer to a variable that receives the current clock time.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The proxy uses the KSPROPERTY_CLOCK_TIME property to retrieve the current clock time.

See Also

IKsClockPropertySet::KsSetTime, KSPROPERTY_CLOCK_TIME


IKsClockPropertySet::KsSetCorrelatedPhysicalTime

The KsSetCorrelatedPhysicalTime method sets the physical time with the correlated system time on the underlying clock.

HRESULT KsSetCorrelatedPhysicalTime(
    IN KSCORRELATED_TIME  *CorrelatedTime
    );

Parameters

CorrelatedTime
Pointer to a KSCORRELATED_TIME structure that contains the physical clock time along with the correlated system time to which to set the underlying clock.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The proxy uses the KSPROPERTY_CLOCK_CORRELATEDPHYSICALTIME property to set the correlated time.

See Also

IKsClockPropertySet::KsGetCorrelatedPhysicalTime, KSCORRELATED_TIME, KSPROPERTY_CLOCK_CORRELATEDPHYSICALTIME


IKsClockPropertySet::KsSetCorrelatedTime

The KsSetCorrelatedTime method sets the current time with the correlated system time on the underlying clock.

HRESULT
  KsSetCorrelatedTime(
    IN KSCORRELATED_TIME  *CorrelatedTime
    );

Parameters

CorrelatedTime
Pointer to a KSCORRELATED_TIME structure that contains the current clock time along with the correlated system time to which to set the underlying clock.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The proxy uses the KSPROPERTY_CLOCK_CORRELATEDTIME property to set the correlated time.

See Also

IKsClockPropertySet::KsGetCorrelatedTime, KSCORRELATED_TIME, KSPROPERTY_CLOCK_CORRELATEDTIME


IKsClockPropertySet::KsSetPhysicalTime

The KsSetPhysicalTime method sets the physical time on the underlying clock.

HRESULT
  KsSetPhysicalTime(
    IN LONGLONG  Time
    );

Parameters

Time
Physical time to which to set the underlying clock.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The physical time is based on some underlying physical clock that always progresses, even if the physical type of clock must be changed on the fly. Other physical clocks use an underlying clock's physical time for rate matching.

The proxy uses the KSPROPERTY_CLOCK_PHYSICALTIME property to set the physical time.

See Also

IKsClockPropertySet::KsGetPhysicalTime, KSPROPERTY_CLOCK_PHYSICALTIME


IKsClockPropertySet::KsSetTime

The KsSetTime method sets the current time on the underlying clock.

HRESULT
  KsSetTime(
    IN LONGLONG  Time
    );

Parameters

Time
Time to which to set the underlying clock.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The proxy uses the KSPROPERTY_CLOCK_TIME property to set the current clock time.

See Also

IKsClockPropertySet::KsGetTime, KSPROPERTY_CLOCK_TIME


IKsControl

The IKsControl interface provides user-mode methods that control a KS filter or KS pin. See the IKsControl AVStream COM interface for information on the kernel-mode equivalent of this interface.

The interface identifier (IID) for this interface is IID_IKsControl.

When to Implement

It is not necessary to implement the methods of this interface. They are implemented in ksproxy.lib.

When to Use

Use this interface to control a KS filter or KS pin.

Methods

The following methods are listed in Vtable order

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments reference count.
Release | Decrements reference count.

IKsControl method | Description
KsProperty | Sets a property or retrieves property information.
KsMethod | Sends a method to a KS object.
KsEvent | Enables or disables an event.


IKsControl::KsEvent

The KsEvent method enables or disables an event, along with any other defined support operations available on an event set.

HRESULT
  KsEvent(
    IN     PKSEVENT  Event OPTIONAL,
    IN     ULONG  EventLength,
    IN/OUT LPVOID  EventData,
    IN     ULONG  DataLength,
    OUT    ULONG  *BytesReturned
    );

Parameters

Event
Pointer to a KSEVENT structure that describes an event to enable the event and NULL to disable the event.
EventLength
Size, in bytes, of the buffer at Event when the event is enabled and zero when the event is disabled.
EventData
Pointer to a KSEVENTDATA structure that contains data for the event and buffer space that receives data for the event.
DataLength
Size, in bytes, of the buffer at EventData.
BytesReturned
Pointer to a variable that receives the size, in bytes, of the data that KsEvent stores in the buffer at EventData.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

To disable an event, set Event to NULL, EventLength to zero, and EventData to the pointer to the KSEVENTDATA structure that was previously used to enable the event.

See Also

KSEVENT, KSEVENTDATA


IKsControl::KsMethod

The KsMethod method sends a method to a KS object, along with any other defined support operations available on a method set.

HRESULT
  KsMethod(
    IN     PKSMETHOD  Method,
    IN     ULONG  MethodLength,
    IN/OUT LPVOID  MethodData,
    IN     ULONG  DataLength,
    OUT    ULONG  *BytesReturned
    );

Parameters

Method
Pointer to a KSMETHOD structure that describes a method and the request type of the method request.
MethodLength
Size, in bytes, of the buffer at Method.
MethodData
Pointer to a buffer that contains data and buffer space for a KSMETHOD_TYPE_SEND operation, or buffer space that receives data for all other operations.
DataLength
Size, in bytes, of the buffer at MethodData.
BytesReturned
Pointer to a variable that receives the size, in bytes, of the data that KsMethod stores in the buffer at MethodData.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

See Also

KSMETHOD


IKsControl::KsProperty

The KsProperty method sets a property or retrieves property information, along with any other defined support operations available on a property set.

HRESULT
  KsProperty(
    IN     PKSPROPERTY  Property,
    IN     ULONG  PropertyLength,
    IN/OUT LPVOID  PropertyData,
    IN     ULONG  DataLength,
    OUT    ULONG*  BytesReturned
    );

Parameters

Property
Pointer to a KSPROPERTY structure that describes a property and the request type of the property request.
PropertyLength
Size, in bytes, of the buffer at Property.
PropertyData
Pointer to a buffer that contains data for a KSPROPERTY_TYPE_SET, KSPROPERTY_TYPE_UNSERIALIZESET, or KSPROPERTY_TYPE_UNSERIALIZERAW operation, or buffer space that receives data for all other operations.
DataLength
Size, in bytes, of the buffer at PropertyData.
BytesReturned
Pointer to a variable that receives the size, in bytes, of the data that KsProperty stores in the buffer at PropertyData. If no data is stored, the size is zero.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

See Also

KSPROPERTY


IKsDataTypeCompletion

The IKsDataTypeCompletion interface provides a method to complete partially specified media types that are passed to the IAMStreamConfig::SetFormat method.

The interface identifier (IID) for this interface is IID_IKsDataTypeCompletion.

When to Implement

Implement the method of this interface so that the proxy can complete partially specified media types. This interface is optional for data type handlers.

When to Use

The proxy calls the method of this interface to complete partially specified media types that are first passed to the IAMStreamConfig::SetFormat method.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments reference count.
Release | Decrements reference count.

IKsDataTypeCompletion method | Description
KsCompleteMediaType | Completes a partially specified media type.

Comments

In order to keep the proxy data type neutral, optional data type handlers can be loaded to massage the data stream as it passes to or from kernel-mode filters. You should implement a data type handler as a COM server that, at least, supports the IKsDataTypeHandler interface. The IKsDataTypeCompletion interface is optional for data type handlers. A data type handler only supports IKsDataTypeCompletion if the media format has a partially specified form.

A data type handler is typically loaded during the pin connection process, and unloaded when the connection is broken. However, a data type handler is sometimes loaded briefly for other purposes. For instance, if an application uses DirectShow's IAMStreamConfig::SetFormat method, the application possibly uses a data type handler to complete a partial media type parameter returned from IAMStreamConfig::SetFormat. For more information on IAMStreamConfig::SetFormat, see the Platform SDK documentation.

See Also

IKsDataTypeHandler


IKsDataTypeCompletion::KsCompleteMediaType

The KsCompleteMediaType method completes a presumably partially-specified media type that was first presented to the IAMStreamConfig::SetFormat method.

HRESULT
  KsCompleteMediaType(
    IN     HANDLE  FilterHandle,
    IN     ULONG  PinFactoryId,
    IN/OUT AM_MEDIA_TYPE  *AmMediaType
    );

Parameters

FilterHandle
Handle to the underlying KS filter.
PinFactoryId
Identifier of the pin factory against which the media type is being completed.
AmMediaType
Pointer to a AM_MEDIA_TYPE structure that describes the format of the media samples. KsCompleteMediaType receives partially specified media samples, completes the specification, and returns.

Return Value

Returns NOERROR if successful and the media type was completed; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The KsCompleteMediaType method is primarily used for video media types, in which the biSizeImage member of the KS_BITMAPINFOHEADER structure is known only to the driver, because of the private compression formats supported. If required, the data type handler can query the underlying KS filter in order to complete the given media type.

When the proxy creates an instance of the data type handler for purposes of completing a media type, the proxy passes the media type to the IKsDataTypeHandler::KsSetMediaType method to first initialize this data type handler to the particular media type.

For more information on IAMStreamConfig::SetFormat and AM_MEDIA_TYPE, see the Platform SDK documentation.

See Also

IKsDataTypeHandler::KsSetMediaType, KS_BITMAPINFOHEADER


IKsDataTypeHandler

The IKsDataTypeHandler interface provides methods that perform optional preprocessing and postprocessing of media samples. This interface also can return the size of extra stream header information that is required for processing and can determine if a particular media type is within a given set of kernel streaming data ranges.

The interface identifier (IID) for this interface is IID_IKsDataTypeHandler.

When to Implement

The methods of this interface must be implemented so that the proxy can preprocess and postprocess media samples that transition between user and kernel mode. This interface is required for data type handlers.

When to Use

The proxy calls the methods of this interface to preprocess and postprocess media samples.

Methods

The following methods are listed in Vtable order

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments reference count.
Release | Decrements reference count.

IKsDataTypeHandler method | Description
KsCompleteIoOperation | Cleans up the extended header and completes the I/O operation.
KsIsMediaTypeInRanges | Validates that a media type is within specific data ranges.
KsPrepareIoOperation | Initializes the extended header and prepares the media sample for an I/O operation.
KsQueryExtendedSize | Retrieves extended header information required for I/O operations.
KsSetMediaType | Sets the media type for a data handler.

Comments

In order to keep the proxy data type neutral, optional data type handlers can be loaded to massage the data stream as it passes to or from kernel mode filters. You should implement a data type handler as a COM server that, at least, supports the IKsDataTypeHandler interface. Your data type handler can optionally support the IKsDataTypeCompletion interface.

A data type handler is typically loaded during the pin connection process, and unloaded when the connection is broken. However, a data type handler is sometimes loaded briefly for other purposes. For instance, if an application uses DirectShow's IAMStreamConfig::SetFormat method, the application possibly uses a data type handler to complete a partial media type parameter sent to the method.

The proxy uses the GUIDs from the media type as COM server classes to determine what if any data type handler to load. As long as the data type handler is registered as a COM server under an expected GUID class that the proxy looks for, the data type handler is loaded. The major format type is first used to attempt to open a data type handler COM server, followed by the subtype and format specifier if opening the data type handler fails using the major format type. If any of the attempts succeed, the proxy queries for the IKsDataTypeHandler interface and calls the interface's KsSetMediaType method to establish the current media type being used with the handler, in case the handler supports many types. If no handler is found, then the proxy assumes none is necessary when marshaling the stream to or from kernel mode, or to perform any other tasks necessary.

On a data type handler create request through CoCreateInstance, the server is always presented an outer IUnknown with which to create the COM object. This IUnknown is an interface on the pin object that is loading this handler. The IUnknown interface pointer may be used to query information or interfaces from the pin, such as the IKsPin or IKsControl interfaces, although the kernel-mode pin may not have been created at the time the handler is loaded. No reference should be left on the outer object through acquiring any interfaces, as it will result in a circular reference count. Using the interfaces without a reference count is acceptable, because the outer object owns the handler and, by definition, is destroyed when the outer object's reference count reaches zero.

For more information on IAMStreamConfig::SetFormat and CoCreateInstance, see the Platform SDK documentation.

See Also

IKsDataTypeCompletion


IKsDataTypeHandler::KsCompleteIoOperation

The KsCompleteIoOperation method cleans up the extended header and completes the input and output (I/O) operation.

HRESULT
  KsCompleteIoOperation(
    IN IMediaSample  *Sample,
    IN PVOID  StreamHeader,
    IN KSIOOPERATION  IoOperation,
    IN BOOL  Cancelled
    );

Parameters

Sample
Pointer to the IMediaSample interface for the associated media sample.
StreamHeader
Pointer to the stream header with extension.
IoOperation
Value that specifies the type of I/O operation. This value can be one of the following values from the KSIOOPERATION enumeration:
Value | Description
KsIoOperation_Write | Write data to stream.
KsIoOperation_Read | Read data from stream.

Cancelled
Boolean value that is TRUE if the I/O operation was canceled and FALSE otherwise.

Return Value

Returns NOERROR if successful; otherwise, returns an error code. If the stream's major type is KSDATAFORMAT_TYPE_AUDIO, a KsCompleteIoOperation call is inapplicable, so KsCompleteIoOperation automatically returns NOERROR.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The client only calls KsCompleteIoOperation if the data type handler indicated to the client the existence of extended header information in a call to the IKsDataTypeHandler::KsQueryExtendedSize method.

For more information on IMediaSample, see the Platform SDK documentation.

See Also

IKsDataTypeHandler::KsQueryExtendedSize


IKsDataTypeHandler::KsIsMediaTypeInRanges

The KsIsMediaTypeInRanges method validates that a media type is within the provided data ranges.

HRESULT
  KsIsMediaTypeInRanges(
    IN PVOID  DataRanges
    );

Parameters

DataRanges
Pointer to a buffer that contains a KSMULTIPLE_ITEM structure, followed by a sequence of extensible KSDATARANGE structures, aligned on 64-bit boundaries. The KSMULTIPLE_ITEM structure is a header that describes the size of the buffer and the number of entries in the list that follows the header.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

A client first calls the IKsDataTypeHandler::KsSetMediaType method to assign a media type that the client references in subsequent operations on the data type handler. The client then calls KsIsMediaTypeInRanges to validate that the media type is within particular data ranges.

See Also

IKsDataTypeHandler::KsSetMediaType, KSDATARANGE, KSMULTIPLE_ITEM


IKsDataTypeHandler::KsPrepareIoOperation

The KsPrepareIoOperation method initializes the extended header and prepares the media sample for an I/O operation.

HRESULT
  KSPrepareIoOperation(
    IN IMediaSample  *Sample,
    IN PVOID  StreamHeader,
    IN KSIOOPERATION  IoOperation
    );

Parameters

Sample
Pointer to the IMediaSample interface for the associated media sample.
StreamHeader
Pointer to the stream header with extension.
IoOperation
Value that specifies the type of I/O operation. This value can be one of the following values from the KSIOOPERATION enumeration:
Value | Description
KsIoOperation_Write | Write data to stream.
KsIoOperation_Read | Read data from stream.

Return Value

Returns NOERROR if successful; otherwise, returns an error code. If the stream's major type is KSDATAFORMAT_TYPE_AUDIO, a KsPrepareIoOperation call is inapplicable, so KsPrepareIoOperation automatically returns NOERROR.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The client only calls KsPrepareIoOperation if the data type handler indicated to the client the existence of extended header information in a call to the IKsDataTypeHandler::KsQueryExtendedSize method.

For more information on IMediaSample, see the Platform SDK documentation.

See Also

IKsDataTypeHandler::KsQueryExtendedSize


IKsDataTypeHandler::KsQueryExtendedSize

The KsQueryExtendedSize method retrieves extended header information required for input and output (I/O) operations.

HRESULT
  KsQueryExtendedSize(
    OUT ULONG  *ExtendedSize
    );

Parameters

ExtendedSize
Pointer to a variable that receives the extended header size in bytes.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

If KsQueryExtendedSize returns zero at ExtendedSize, clients should not call the KsPrepareIoOperation and KsCompleteIoOperation methods of the IKsDataTypeHandler interface because I/O preparation and completion operations are not required. For all other values that KsQueryExtendedSize returns at ExtendedSize, clients should allocate memory space for the extended stream header per the returned value and call KsPrepareIoOperation and KsCompleteIoOperation to prepare and complete the I/O operation associated with the header.

See Also

IKsDataTypeHandler::KsCompleteIoOperation, IKsDataTypeHandler::KsPrepareIoOperation


IKsDataTypeHandler::KsSetMediaType

The KsSetMediaType method sets the media type for a data type handler.

HRESULT
  KsSetMediaType(
    IN const CMediaType  *MediaType
    );

Parameters

MediaType
Pointer to a CMediaType object associated with the media type.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

Clients can call KsSetMediaType of a single data type handler to initialize this data type handler to a particular media type from a group of many disparate media types.

For more information on CMediaType class, see the Platform SDK documentation.

See Also

IKsDataTypeHandler


IKsInterfaceHandler

The IKsInterfaceHandler interface provides methods that marshal samples into the kernel based on the KSPIN_INTERFACE structure specified for the established connection.

The interface identifier (IID) for this interface is IID_IKsInterfaceHandler.

When to Implement

The methods of this interface must be implemented so that the proxy can create an instance of the interface handler and can let clients use the handler to marshal samples into the kernel based on the KSPIN_INTERFACE specified for the established connection. This interface is required for interface handlers.

When to Use

Clients call the methods of this interface to marshal samples into the kernel based on the KSPIN_INTERFACE specified for the established connection.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments reference count.
Release | Decrements reference count.

IKsInterfaceHandler method | Description
KsSetPin | Informs an interface handler about the pin with which to communicate when passing data.
KsProcessMediaSamples | Queries for the extended header size if a data handler is specified.
KsCompleteIo | Cleans up extended headers and releases media samples.

Comments

In order to keep the proxy neutral with regard to the interface used to stream data, interface handlers are loaded to translate DirectShow media samples to and from a kernel-level driver. An interface handler implements the methods of the IKsInterfaceHandler interface to perform preprocessing and postprocessing on all media samples and to signal the completion of input and output (I/O).

Each interface handler can marshal media samples using its own method. The standard interface handler that KS proxy implements uses IOCTL_KS_WRITE_STREAM for the receive operation and IOCTL_KS_READ_STREAM for the send operation, but a custom interface handler can use some other method.

When a pin is connected, the proxy uses the GUID in the Set member of the KSPIN_INTERFACE structure to determine what interface handler to load. The interface handler is registered as a COM server under that GUID class. The interface handler must handle all variations of the interface within the interface set. Bridge pins are not expected to stream data, and interface handlers are not loaded for them.

On an interface handler create request through CoCreateInstance, the server is always presented an outer IUnknown with which to create the COM object. This IUnknown is an interface on the pin object that is loading this interface handler. The IUnknown interface pointer can be used to query information or interfaces, such as the IKsControl interface, from the pin, although the kernel-mode pin may not have been created at the time the interface handler is loaded. No reference should be left on the outer object through acquiring any interfaces, as it will result in a circular reference count. Using the interfaces without a reference count is acceptable, because the outer object owns the handler and, by definition, is destroyed when the outer object's reference count reaches zero.

For more information on CoCreateInstance, see the Platform SDK documentation.

See Also

IKsControl, KSPIN_INTERFACE


IKsInterfaceHandler::KsCompleteIo

The KsCompleteIo method cleans up extended headers and releases media samples after input and output (I/O) complete.

HRESULT
  KsCompleteIo(
    IN KSSTREAM_SEGMENT  *StreamSegment
    );

Parameters

StreamSegment
Pointer to a KSSTREAM_SEGMENT structure that contains header information for a stream segment to complete.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The KsCompleteIo method discards allocated memory, updates media samples, and decrements the count of wait items for the proxy.

The KsCompleteIo method must determine the type of I/O operation that the IKsInterfaceHandler::KsProcessMediaSamples method completed from the IoOperation member of the KSSTREAM_SEGMENT structure. If the I/O operation was reading data from a stream (KsIoOperation_Read of the KSIOOPERATION enumeration), KsCompleteIo performs the following actions to deliver the sample from an output pin to the connected input pin:

  1. Reflects the stream header information in the IMediaSample interface.
  2. Calls the IKsPin::KsDeliver method of the output pin to deliver the sample. KsDeliver releases the sample so that when queuing buffers to the device, the sample can be retrieved if it is the last sample. The input pin then completes the I/O and it is safe to release the sample.

For more information on IMediaSample, see the Platform SDK documentation.

See Also

IKsInterfaceHandler::KsProcessMediaSamples, IKsPin::KsDeliver, KSSTREAM_SEGMENT


IKsInterfaceHandler::KsProcessMediaSamples

The KsProcessMediaSamples method moves samples from or to a previously assigned filter pin. A stream header is initialized to represent each media sample in the stream segment. The input and output (I/O) are then performed, the count of wait items is incremented, and the proxy I/O thread waits for completion.

HRESULT
  KsProcessMediaSamples(
    IN     IKsDataTypeHandler  *KsDataTypeHandler,
    IN     IMediaSample  **SampleList,
    IN/OUT PLONG  SampleCount,
    IN     KSIOOPERATION  IoOperation,
    OUT    PKSSTREAM_SEGMENT  *StreamSegment
    );

Parameters

KsDataTypeHandler
Pointer to the IKsDataTypeHandler interface for the data type handler that handles the type of media listed at SampleList. This data type handler has specific information about the media type being streamed.
SampleList
Pointer to a buffer that contains an array of pointers to the IMediaSample interfaces for the list of media samples to process.
SampleCount
Pointer to a variable that initially contains the number of samples in the list at SampleList and, on return, receives the actual number of samples processed.
IoOperation
Value that specifies the type of I/O operation. This value can be one of the following values from the KSIOOPERATION enumeration:
Value | Description
KsIoOperation_Write | Write data to stream.
KsIoOperation_Read | Read data from stream.

StreamSegment
Pointer to a buffer that receives a pointer to a KSSTREAM_SEGMENT structure that contains header information for a stream segment that is sent to the kernel-mode pin.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The KsProcessMediaSamples method calls the KsQueryExtendedSize method of the received IKsDataTypeHandler interface to retrieve the size of the extended header. If an extended header size is not specified, KsProcessMediaSamples discards the pointer to the IKsDataTypeHandler interface. If an extended header size is specified, KsProcessMediaSamples holds the pointer to the IKsDataTypeHandler interface until processing of the media samples is complete. The KsProcessMediaSamples method then allocates the stream headers with the appropriate header sizes. For each media sample, KsProcessMediaSamples initializes the header, copies data pointers, sets time stamps, and so on. Each sample is then added to the sample list. If it is a write operation, the sample is held by incrementing the reference count.

For more information on IMediaSample, see the Platform SDK documentation.

See Also

IKsDataTypeHandler, IKsDataTypeHandler::KsQueryExtendedSize, KSSTREAM_SEGMENT


IKsInterfaceHandler::KsSetPin

The KsSetPin method informs the streaming interface handler about the pin with which to communicate when passing data.

HRESULT
  KsSetPin(
    IN IKsPin  *KsPin
    );

Parameters

KsPin
Pointer to the IKsPin interface for the pin to which this streaming interface handler is to be attached. This pin must support the IKsObject interface from which the underlying kernel handle can be obtained.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The KsSetPin method is called after an instance of the interface handler is created but before any streaming is required of the instance.

See Also

IKsObject, IKsPin


IKsObject

The IKsObject interface provides a method to retrieve the file handle of a KS object.

The interface identifier (IID) for this interface is IID_IKsObject

When to Implement

It is not necessary to implement the method of this interface. It is implemented in ksproxy.lib.

When to Use

Use this interface to retrieve the file handle of a KS object. This handle can be used to transmit input and output requests directly to the KS object.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments reference count.
Release | Decrements reference count.

IKsObject method | Description
KsGetObjectHandle | Retrieves the file handle of a KS object.

Comments

KS objects include, for example, KS filters, KS pins, and KS clocks.


IKsObject::KsGetObjectHandle

The KsGetObjectHandle method retrieves a file handle to a KS object.

HANDLE
  KsGetObjectHandle(
    void
    );

Parameters

None

Return Value

Returns a file handle to a KS object if successful; otherwise, returns null.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

Applications can use the handle that KsGetObjectHandle returns to send control-code requests to the driver that handles the KS object. KS objects include, for example, KS filters, KS pins, and KS clocks.

See Also

KsSynchronousDeviceControl


IKsPin

The IKsPin interface provides methods that control and retrieve information about a pin.

The interface identifier (IID) for this interface is IID_IKsPin.

When to Implement

It is not necessary to implement the methods of this interface. They are implemented in ksproxy.lib.

When to Use

Use this interface to control and retrieve information about a pin.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments reference count.
Release | Decrements reference count.

IKsPin method | Description
KsQueryMediums | Retrieves mediums that a pin supports.
KsQueryInterfaces | Retrieves interfaces that a pin supports.
KsCreateSinkPinHandle | For proxy use and not recommended for application use. Creates a pin handle and stores it in the KS pin object.
KsGetCurrentCommunication | Retrieves the current communication direction, interface, and medium of a pin.
KsPropagateAcquire | For proxy use and not recommended for application use.
KsDeliver | Delivers a media sample from an output pin to an input pin.
KsMediaSamplesCompleted | Informs a pin that a stream segment completed. Used by interface handlers.
KsPeekAllocator | For proxy use and not recommended for application use. Returns a pointer to a IMemAllocator interface for a pin's assigned allocator.
KsReceiveAllocator | For proxy use and not recommended for application use. Provides an allocator for an output pin.
KsRenegotiateAllocator | Obsolete. Do not use.
KsIncrementPendingIoCount | Increments the number of I/O operations that are in progress on a pin.
KsDecrementPendingIoCount | Decrements the number of I/O operations that are in progress on a pin.
KsQualityNotify | For proxy use and not recommended for application use. Receives quality-management reports from the kernel mode equivalent of a DirectShow pin.

Comments

An interface handler (IKsInterfaceHandler) uses many of the IKsPin methods to route media samples of a particular media type.

See Also

IKsInterfaceHandler


IKsPin::KsDecrementPendingIoCount

The KsDecrementPendingIoCount method decrements the number of input/output (I/O) operations that are in progress on a pin.

LONG
  KsDecrementPendingIoCount(
    void
    );

Parameters

None

Return Value

Returns an integer from 0 to n, the value that represents the new number of I/O operations that are in progress.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The KsDecrementPendingIoCount method is typically called from within an interface handler as described in the following sequence:

  1. The proxy creates an instance of an interface handler (IKsInterfaceHandler) to handle a particular media type.
  2. A client calls the IKsInterfaceHandler::KsSetPin method to inform that interface handler about the pin with which to communicate when passing data.
  3. The client calls the IKsInterfaceHandler::KsProcessMediaSamples method to move samples from or to the assigned pin. KsProcessMediaSamples performs I/O operations and for each I/O operation, calls IKsPin::KsIncrementPendingIoCount to increment the I/O count.
  4. The client calls the IKsInterfaceHandler::KsCompleteIo method to complete an I/O operation. KsCompleteIo calls KsDecrementPendingIoCount to decrement the I/O count.

See Also

IKsInterfaceHandler, IKsInterfaceHandler::KsCompleteIo, IKsInterfaceHandler::KsProcessMediaSamples, IKsInterfaceHandler::KsSetPin, IKsPin::KsIncrementPendingIoCount


IKsPin::KsDeliver

The KsDeliver method delivers a media sample from an output pin to an input pin, continues an I/O operation by retrieving the next buffer from an allocator, and submits the buffer to the associated device.

HRESULT
  KsDeliver(
    IN IMediaSample *Sample,
    IN ULONG Flags
    );

Parameters

Sample
Pointer to the IMediaSample interface for the associated media sample.
Flags
A bitmask enumerating information about the media sample. The pin connection checks for the end of stream (EOS) flag.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Comments

An interface handler (IKsInterfaceHandler) calls KsDeliver on the output pin of a filter to deliver a media sample to the input pin of another filter. These input and output pins are connected.

For an input pin, KsDeliver is an invalid entry point and returns EFAIL.

For more information on IMediaSample, see the Platform SDK documentation.

See Also

IKsInterfaceHandler, IKsInterfaceHandler::KsCompleteIo


IKsPin::KsGetCurrentCommunication

The KsGetCurrentCommunication method retrieves the current communication direction, interface, and medium of a pin.

HRESULT
  KsGetCurrentCommunication(
    OUT KSPIN_COMMUNICATION *Communication,
    OUT KSPIN_INTERFACE *Interface,
    OUT KSPIN_MEDIUM *Medium
    );

Parameters

Communication
Pointer to a variable that receives one of the following values from the KSPIN_COMMUNICATION enumeration describing the current communication direction for a pin:
Value | Description
KSPIN_COMMUNICATION_NONE | The pin factory does not create any pin instances.
KSPIN_COMMUNICATION_SINK | The pin factory creates instances of IRP sink pins. Such pins can only be connected to IRP source pins.
KSPIN_COMMUNICATION_SOURCE | The pin factory creates instances of IRP source pins. Such pins can only be connected to IRP sink pins.
KSPIN_COMMUNICATION_BOTH | The pin factory creates instances of pins that are both IRP sinks and IRP sources.
KSPIN_COMMUNICATION_BRIDGE | The pin cannot connect to other pins, but instances may be created on it to receive non-KS I/O requests.

Interface
Pointer to a variable that receives a KSPIN_INTERFACE structure that describes the current interface for a pin.
Medium
Pointer to a variable that receives a KSPIN_MEDIUM structure that describes the current medium for a pin.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

Source pins send IRPs to sink pins. Do not confuse the communication direction with data flow direction. (See KSPROPERTY_PIN_DATAFLOW.) A source pin may read or write data, and a sink pin may have data read to it or written from it.

The current communication direction, interface, and medium of a pin are a subset of those available to the pin, and are selected when the pin handle is created.

See Also

KSPIN_INTERFACE, KSPIN_MEDIUM, KSPROPERTY_PIN_DATAFLOW


IKsPin::KsIncrementPendingIoCount

The KsIncrementPendingIoCount method increments the number of input/output (I/O) operations that are in progress on a pin.

LONG
  KsIncrementPendingIoCount(
    void
    );

Parameters

None

Return Value

Returns an integer from 1 to n, the value that represents the new number of I/O operations that are in progress.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The KsIncrementPendingIoCount method is typically called from within an interface handler as described in the following sequence:

  1. The proxy creates an instance of an interface handler (IKsInterfaceHandler) to handle a particular media type.
  2. A client calls the IKsInterfaceHandler::KsSetPin method to inform that interface handler about the pin with which to communicate when passing data.
  3. The client calls the IKsInterfaceHandler::KsProcessMediaSamples method to move samples from or to the assigned pin. KsProcessMediaSamples performs I/O operations and for each I/O operation, calls KsIncrementPendingIoCount to increment the I/O count.
  4. The client calls the IKsInterfaceHandler::KsCompleteIo method to complete an I/O operation. KsCompleteIo calls IKsPin::KsDecrementPendingIoCount to decrement the I/O count.

See Also

IKsInterfaceHandler, IKsInterfaceHandler::KsCompleteIo, IKsInterfaceHandler::KsProcessMediaSamples, IKsInterfaceHandler::KsSetPin, IKsPin::KsDecrementPendingIoCount


IKsPin::KsMediaSamplesCompleted

The KsMediaSamplesCompleted method informs a pin that a stream segment completed.

HRESULT
  KsMediaSamplesCompleted(
    IN KSSTREAM_SEGMENT  *StreamSegment
    );

Parameters

StreamSegment
Pointer to a KSSTREAM_SEGMENT structure that contains header information for a completed stream segment.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

Input pins do nothing with the supplied header information and just return NOERROR. Output pins remove the head of the input and output (I/O) queue and add the next in the list to the I/O slots.

When a client calls the IKsInterfaceHandler::KsCompleteIo method of an interface handler to complete an I/O operation, KsCompleteIo calls KsMediaSamplesCompleted for pins.

See Also

IKsInterfaceHandler, IKsInterfaceHandler::KsCompleteIo, KSSTREAM_SEGMENT


IKsPin::KsQueryInterfaces

The KsQueryInterfaces method retrieves interfaces that a pin supports.

HRESULT
  KsQueryInterfaces(
    OUT PKSMULTIPLE_ITEM  *InterfaceList
    );

Parameters

InterfaceList
Pointer to a buffer that receives a pointer to a KSMULTIPLE_ITEM structure, followed by a sequence of KSPIN_INTERFACE structures that describe interface types. The KSMULTIPLE_ITEM structure is a header that describes the size of the buffer and the number of entries in the list that follows the header.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The returned interfaces are ordered by preference.

See Also

KSMULTIPLE_ITEM, KSPIN_INTERFACE


IKsPin::KsQueryMediums

The KsQueryMediums method retrieves mediums that a pin supports.

HRESULT
  KsQueryMediums(
    OUT PKSMULTIPLE_ITEM *MediumList
    );

Parameters

MediumList
Pointer to a buffer that receives a pointer to a KSMULTIPLE_ITEM structure, followed by a sequence of KSPIN_MEDIUM structures that describe medium types. The KSMULTIPLE_ITEM structure is a header that describes the size of the buffer and the number of entries in the list that follows the header.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The returned mediums are ordered by preference.

Applications call KsQueryMediums to retrieve mediums that pins support in order to build a filter graph.

See Also

KSMULTIPLE_ITEM, KSPIN_MEDIUM


IKsPinEx

The IKsPinEx interface inherits all the methods of the IKsPin interface and extends IKsPin to provide a method that notifies the filter graph of an error to give the filter graph an opportunity to halt.

The interface identifier (IID) for this interface is IID_IKsPinEx.

When to Implement

It is not necessary to implement the methods of this interface. They are implemented in ksproxy.lib.

When to Use

Use this interface to notify the filter graph of an error value.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments reference count.
Release | Decrements reference count.

IKsPin method | Description
KsQueryMediums | Retrieves mediums that a pin supports.
KsQueryInterfaces | Retrieves interfaces that a pin supports.
KsCreateSinkPinHandle | For proxy use and not recommended for application use. Creates a pin handle and stores it in the KS pin object.
KsGetCurrentCommunication | Retrieves the current communication direction, interface, and medium of a pin.
KsPropagateAcquire | For proxy use and not recommended for application use.
KsDeliver | Delivers a media sample from an output pin to an input pin.
KsMediaSamplesCompleted | Informs a pin that a stream segment completed. Used by interface handlers.
KsPeekAllocator | For proxy use and not recommended for application use. Returns a pointer to a IMemAllocator interface for a pin's assigned allocator.
KsReceiveAllocator | For proxy use and not recommended for application use. Provides an allocator for an output pin.
KsRenegotiateAllocator | Obsolete. Do not use.
KsIncrementPendingIoCount | Increments the number of I/O operations that are in progress on a pin.
KsDecrementPendingIoCount | Decrements the number of I/O operations that are in progress on a pin.
KsQualityNotify | For proxy use and not recommended for application use. Receives quality-management reports from the kernel mode equivalent of a DirectShow pin.

IKsPinEx method | Description
KsNotifyError | Notifies the filter graph of an error to give the filter graph an opportunity to halt.

Comments

An interface handler (IKsInterfaceHandler) uses many of the IKsPinEx methods to route media samples of a particular media type.

See Also

IKsInterfaceHandler, IKsPin


IKsPinEx::KsNotifyError

The KsNotifyError method notifies the filter graph of an error to give the filter graph an opportunity to halt.

VOID
  KsNotifyError(
    IN IMediaSample *Sample,
    IN HRESULT hr
    );

Parameters

Sample
Pointer to the IMediaSample interface for the associated media sample.
hr
Error value for notification. If ERROR_OPERATION_ABORTED (that is, the I/O was purposefully canceled), the filter graph is not notified.

Return Value

None

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The KsNotifyError method notifies the filter graph of the specific error using the EC_ERRORABORT event, which specifies that the error forced the termination of an I/O operation.

For more information on IMediaSample, see the Platform SDK documentation.

See Also

IKsPinEx


IKsPinFactory

The IKsPinFactory interface provides a method that retrieves the identifier of a pin factory.

The interface identifier (IID) for this interface is IID_IKsPinFactory.

When to Implement

It is not necessary to implement the method of this interface. It is implemented in ksproxy.lib.

When to Use

Use this interface to retrieve the identifier of a pin factory.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments reference count.
Release | Decrements reference count.

IKsPinFactory method | Description
KsPinFactory | Retrieves the identifier of a pin factory.


IKsPinFactory::KsPinFactory

The KsPinFactory method retrieves the identifier of a pin factory.

HRESULT
  KsPinFactory(
    OUT ULONG  *PinFactory
    );

Parameters

PinFactory
Pointer to a variable that receives the identifier of the pin factory.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

See Also

IKsPinFactory


IKsPinPipe

The IKsPinPipe interface is for proxy use and not recommended for application use. IKsPinPipe provides methods that control a pin pipe.

The interface identifier (IID) for this interface is IID_IKsPinPipe.

When to Implement

It is not necessary to implement the methods of this interface. They are implemented in ksproxy.lib.

When to Use

Not recommended for application use.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments reference count.
Release | Decrements reference count.

IKsPinPipe method | Description
KsGetPinFramingCache | Not recommended for application use.
KsSetPinFramingCache | Not recommended for application use.
KsGetConnectedPin | Not recommended for application use.
KsGetPipe | Not recommended for application use.
KsSetPipe | Not recommended for application use.
KsGetPipeAllocatorFlag | Not recommended for application use.
KsSetPipeAllocatorFlag | Not recommended for application use.
KsGetPinBusCache | Not recommended for application use.
KsSetPinBusCache | Not recommended for application use.
KsGetPinName | Returns the name of a pin.
KsGetFilterName | Returns the name of a filter.


IKsPropertySet

The IKsPropertySet interface provides methods that access properties of KS objects that are implemented in a KS minidriver.

The interface identifier (IID) for this interface is IID_IKsPropertySet.

When to Implement

It is not necessary to implement the methods of this interface. They are implemented in ksproxy.lib.

When to Use

Use this interface to access properties of KS objects.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments reference count.
Release | Decrements reference count.

IKsPropertySet method | Description
Set | Sets a property.
Get | Retrieves a property.
QuerySupported | Determines the support of a property.

Comments

The IKsPropertySet interface methods translate user-mode property requests into kernel-mode property sets that are used by KS minidrivers.

KS objects include, for example, KS filters, KS pins, and KS clocks.


IKsPropertySet::Get

The Get method retrieves a property identified by a property-set GUID and a property identifier.

HRESULT
  Get(
    IN  REFGUID  PropSet,
    IN  ULONG  Id,
    IN  LPVOID  InstanceData,
    IN  ULONG  InstanceLength,
    OUT LPVOID  PropertyData,
    IN  ULONG  DataLength,
    OUT ULONG  *BytesReturned
    );

Parameters

PropSet
GUID that identifies the property set.
Id
Identifier of the property within the property set.
InstanceData
Pointer to instance data for the property.
InstanceLength
Size, in bytes, of the buffer at InstanceData.
PropertyData
Pointer to a buffer that receives the value of the property.
DataLength
Size, in bytes, of the buffer at PropertyData.
BytesReturned
Pointer to a variable that receives the size, in bytes, of the data that Get stores in the buffer at PropertyData.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

To retrieve a property, allocate a buffer, which Get fills with the property. To determine the necessary buffer size, specify NULL for PropertyData and zero for DataLength. The Get method returns the required buffer size in BytesReturned.

See Also

IKsPropertySet::Set


IKsPropertySet::QuerySupported

The QuerySupported method determines whether a KS object supports a property set and the level of that support.

HRESULT
  QuerySupported(
    IN  REFGUID  PropSet,
    IN  ULONG  Id,
    OUT ULONG  *TypeSupport
    );

Parameters

PropSet
GUID that identifies the property set.
Id
Identifier of the property within the property set.
TypeSupport
Pointer to a variable that receives a bitmask enumerating the flags that indicate the support that the underlying driver provides. A driver can support a combination of the following flags:
Value | Description
KSPROPERTY_SUPPORT_GET | Supports retrieving a property. Use the IKsPropertySet::Get method to retrieve the property.
KSPROPERTY_SUPPORT_SET | Supports setting a property. Use the IKsPropertySet::Set method to set the property.

Return Value

Returns NOERROR if successful; otherwise, returns one of the following error codes:

E_NOTIMPL
Property set is not supported.
E_PROP_ID_UNSUPPORTED
Property identifier (Id) is not supported for the specified property set.
E_PROP_SET_UNSUPPORTED
Property set is not supported.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

KS objects include, for example, KS filters, KS pins, and KS clocks.

See Also

IKsPropertySet::Get, IKsPropertySet::Set


IKsPropertySet::Set

The Set method sets a property identified by a property-set GUID and a property identifier.

HRESULT
  Set(
    IN REFGUID  PropSet,
    IN ULONG  Id,
    IN LPVOID  InstanceData,
    IN ULONG  InstanceLength,
    IN LPVOID  PropertyData,
    IN ULONG  DataLength,
    );

Parameters

PropSet
GUID that identifies the property set.
Id
Identifier of the property within the property set.
InstanceData
Pointer to instance data for the property.
InstanceLength
Size, in bytes, of the buffer at InstanceData.
PropertyData
Pointer to a buffer that contains the value of the property to set.
DataLength
Size, in bytes, of the buffer at PropertyData.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

See Also

IKsPropertySet::Get


IKsQualityForwarder

The IKsQualityForwarder interface inherits the method of the IKsObject interface and extends IKsObject to provide a method that flushes information from a pin.

The interface identifier (IID) for this interface is IID_IKsQualityForwarder.

When to Implement

It is not necessary to implement the method of this interface. It is implemented in ksproxy.lib.

When to Use

Use this interface to flush information from a pin.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments reference count.
Release | Decrements reference count.

IKsObject method | Description
KsGetObjectHandle | Retrieves the file handle of a KS object.

IKsQualityForwarder method | Description
KsFlushClient | Flushes information from a pin.


IKsQualityForwarder::KsFlushClient

The KsFlushClient method flushes information from a pin.

VOID
  KsFlushClient(
    IN IKsPin  *Pin
    );

Parameters

Pin
Pointer to the IKsPin interface for the pin from which to flush information.

Return Value

None

Headers

Declared in ksproxy.h. Include ksproxy.h.

See Also

IKsPin


IKsTopology

The IKsTopology interface provides a method that opens topology node objects contained within a filter.

The interface identifier (IID) for this interface is IID_IKsTopology.

When to Implement

It is not necessary to implement the method of this interface. They are implemented in ksproxy.lib.

When to Use

Use this interface to open topology node objects contained within a filter.

Methods

The following methods are listed in Vtable order:

IUnknown method | Description
QueryInterface | Returns pointers to supported interfaces.
AddRef | Increments reference count.
Release | Decrements reference count.

IKsTopology method | Description
CreateNodeInstance | Requests a KS filter object to open a topology node object.

Comments

The IKsTopology interface is supported by filters.


IKsTopology::CreateNodeInstance

The CreateNodeInstance method requests a KS filter object to open a topology node object.

HRESULT
  CreateNodeInstance(
    IN  ULONG  NodeId,
    IN  ULONG  Flags,
    IN  ACCESS_MASK  DesiredAccess,
    IN  IUnknown  *UnkOuter  OPTIONAL,
    IN  REFGUID  InterfaceId,
    OUT LPVOID  *Interface
    );

Parameters

NodeId
Identifier for the topology node object to open.
Flags
A bitmask enumerating the type of topology node object.
DesiredAccess
An ACCESS_MASK bitmask specifying how to request access to the topology node object.
UnkOuter
Pointer to an IUnknown interface that supports the topology node interface.
InterfaceId
Identifier of the topology node interface being requested.
Interface
Pointer to a variable that receives the interface pointer requested in InterfaceId. Upon successful return, *Interface contains the requested interface pointer to the object. If the object does not support the interface specified in InterfaceId, *Interface is set to NULL.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

For more information on the ACCESS_MASK bitmask, see the Platform SDK documentation.

See Also

IKsTopology


Kernel Streaming Proxy Exported Functions

An application or a plug-in can use the kernel-streaming (KS) proxy support functions to control and retrieve information from KS objects that a KS minidriver handles. KS objects include, for example, KS filters, KS pins, and KS clocks. The system-supplied KS proxy library (ksproxy.lib) provides these functions. In order for an application to use these functions, you must include the ksproxy.h header file in the application's code and link to ksproxy.lib when you build your application.

The following sections provide more information about the KS proxy functions:

KsGetMediaType

KsGetMediaTypeCount

KsGetMultiplePinFactoryItems

KsOpenDefaultDevice

KsResolveRequiredAttributes

KsSynchronousDeviceControl


KsGetMediaType

The KsGetMediaType function retrieves information about a media type on a pin factory identifier.

HRESULT
  KsGetMediaType(
    IN     int  Position,
    IN/OUT AM_MEDIA_TYPE  *AmMediaType,
    IN     HANDLE      FilterHandle,
    IN     ULONG       PinFactoryId
    );

Parameters

Position
Offset into the data range item that KsGetMediaType fills. Note that the data type of Position is int to conform to underlying calls.
AmMediaType
Pointer to a variable that receives information in a AM_MEDIA_TYPE structure.
FilterHandle
Handle to the filter that contains the pin factory to query.
PinFactoryId
Identifier of the pin factory against which the information for a media type is being returned.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The KsGetMediaType function queries the list of data ranges and performs a data intersection on the specified data range, thus producing a data format. It then converts that data format to a media type.

For more information on AM_MEDIA_TYPE, see the Platform SDK documentation.

See Also

IKsPinFactory


KsGetMediaTypeCount

The KsGetMediaTypeCount function returns the number of available media types on a pin factory identifier.

HRESULT
  KsGetMediaTypeCount(
    IN  HANDLE  FilterHandle,
    IN  ULONG  PinFactoryId,
    OUT ULONG  *MediaTypeCount
    );

Parameters

FilterHandle
Handle to the filter that contains the pin factory to query.
PinFactoryId
Identifier of the pin factory against which the number of media types is being returned.
MediaTypeCount
Pointer to a variable to receive the number of media types.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The number of available media types that KsGetMediaTypeCount returns is equal to the number of available data ranges.

See Also

IKsPinFactory, KSDATARANGE


KsGetMultiplePinFactoryItems

The KsGetMultiplePinFactoryItems function retrieves pin property items in a variable length data buffer.

HRESULT
  KsGetMultiplePinFactoryItems(
    IN  HANDLE  FilterHandle,
    IN  ULONG  PinFactoryId,
    IN  ULONG  PropertyId,
    OUT PVOID  *Items
    );

Parameters

FilterHandle
Handle to the filter that contains the pin factory to query.
PinFactoryId
Identifier of the pin factory against which the property items are being returned.
PropertyId
Identifier of the property in the pin property set (KSPROPSETID_Pin) to query.
Items
Pointer to a buffer to receive the property items. If successfully retrieved, this pointer must be subsequently deleted with the CoTaskMemFree function.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The KsGetMultiplePinFactoryItems function queries for the data size of the requested property, allocates a buffer, and retrieves the data.

For more information on CoTaskMemFree, see the Platform SDK documentation.

See Also

IKsPinFactory, KSP_PIN, KSPROPERTY, KSPROPSETID_Pin


KsOpenDefaultDevice

The KsOpenDefaultDevice function opens a handle to the first device that is listed in the specified Plug and Play (PnP) category.

HRESULT
  KsOpenDefaultDevice(
    IN  REFGUID  Category,
    IN  ACCESS_MASK  Access,
    OUT PHANDLE  DeviceHandle
    );

Parameters:

Category
Identifier of the PnP category to enumerate.
Access
An ACCESS_MASK bitmask specifying how to access the default device.
DeviceHandle
Pointer to a variable that receives the handle to the default device that is opened.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

The KsOpenDefaultDevice function passes a pointer to Category in a call to the SetupDiGetClassDevs function to obtain a handle to the list of PnP devices. For more information on the ACCESS_MASK bitmask and SetupDiGetClassDevs, see the Platform SDK documentation.


KsResolveRequiredAttributes

The KsResolveRequiredAttributes function searches the attributes list that is attached to a data range for specified attributes and ensures that all specified attributes were found.

HRESULT
  KsResolveRequiredAttributes(
    IN PKSDATARANGE  DataRange,
    IN KSMULTIPLE_ITEM  *Attributes OPTIONAL
    );

Parameters:

DataRange
Pointer to a KSDATARANGE structure that possibly has an attached attribute list. KsResolveRequiredAttributes searches the data range's attribute list for the attributes at Attributes. An attribute list attached to a data range follows that data range.
Attributes
Pointer to a buffer that contains a KSMULTIPLE_ITEM structure, followed by a sequence of KSATTRIBUTE structures that describe attributes. The KSMULTIPLE_ITEM structure is a header that describes the size of the buffer and the number of entries in the list that follows the header. If this pointer is NULL, then KsResolveRequiredAttributes only succeeds if DataRange does not have an attached attribute list.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

See Also

KSATTRIBUTE, KSDATARANGE, KSMULTIPLE_ITEM


KsSynchronousDeviceControl

The KsSynchronousDeviceControl function issues a synchronous device I/O control operation to the KS object that is specified by a file handle. KS objects include, for example, KS filters, KS pins, and KS clocks.

HRESULT
  KsSynchronousDeviceControl(
    IN HANDLE  Handle,
    IN ULONG  IoControl,
    IN PVOID  InBuffer,
    IN ULONG  InLength,
    IN/OUT PVOID  OutBuffer,
    IN ULONG  OutLength,
    OUT PULONG  BytesReturned
    );

Parameters

Handle
Handle to the KS object on which to perform the operation.
IoControl
Control code that identifies a specific type of operation to perform on a KS object.
InBuffer
Pointer to a buffer that contains data that specifies the operation to perform.
InLength
Size, in bytes, of the buffer at InBuffer.
OutBuffer
Pointer to a buffer that contains either data for the operation or buffer space that receives data for the operation.
OutLength
Size, in bytes, of the buffer at OutBuffer.
BytesReturned
Pointer to a variable that receives the size, in bytes, of the data that KsSynchronousDeviceControl stores in the buffer at OutBuffer.

Return Value

Returns NOERROR if successful; otherwise, returns an error code.

Headers

Declared in ksproxy.h. Include ksproxy.h.

Comments

To retrieve the handle to the KS object, an application should call the IKsObject::KsGetObjectHandle method.

An application can set the control code in IoControl and the buffers at InBuffer and OutBuffer as follows to specify the operation to perform:

  • Set IoControl to IOCTL_KS_PROPERTY to access a property. Set InBuffer to point to a KSPROPERTY structure that specifies the property of the property set to access and whether to retrieve information about the property or set information in the property. To set information in the property, set OutBuffer to point to that information. To retrieve information from the property, set OutBuffer to receive that information.
  • Set IoControl to IOCTL_KS_METHOD to execute a method. Set InBuffer to point to a KSMETHOD structure that specifies the method of the method set to execute and whether to read and/or write data related to the method. To read data, set OutBuffer to point to that data. To write data, set OutBuffer to receive that data.
  • Set IoControl to IOCTL_KS_ENABLE_EVENT to request that the KS object specified by Handle notify the application whenever a specific event action occurs. Set InBuffer to point to a KSEVENT structure that specifies the event of the event set about which to notify. Set OutBuffer to point to a KSEVENTDATA structure that describes how the KS object should notify the application when the event occurs. For information about a KSEVENTDATA structure, see Enable Event.
  • Set IoControl to IOCTL_KS_DISABLE_EVENT to inform the KS object specified by Handle to stop notifying the application whenever a specific event action occurs. Set InBuffer to point to a KSEVENT structure that specifies the event of the event set about which to stop notifying.

See Also

IKsObject::KsGetObjectHandle, KSEVENT, KSMETHOD, KSPROPERTY


Kernel Streaming Proxy Structures

An application or a plug-in can use the following structures to control and retrieve information from kernel-streaming (KS) objects that a KS minidriver handles:

ALLOCATOR_PROPERTIES_EX

KSSTREAM_SEGMENT

PIPE_DIMENSIONS

PIPE_TERMINATION

KS objects include, for example, KS filters, KS pins, and KS clocks.


ALLOCATOR_PROPERTIES_EX

The ALLOCATOR_PROPERTIES_EX structure is for proxy use and not recommended for application use. ALLOCATOR_PROPERTIES_EX contains information that describes properties of an allocator.

typedef struct _ALLOCATOR_PROPERTIES_EX {
    long                  cBuffers;
    long                  cbBuffer;
    long                  cbAlign;
    long                  cbPrefix;
    GUID                  MemoryType;
    GUID                  BusType;
    PIPE_STATE            State;
    PIPE_TERMINATION      Input;
    PIPE_TERMINATION      Output;
    ULONG                 Strategy;
    ULONG                 Flags;
    ULONG                 Weight;
    KS_LogicalMemoryType  LogicalMemoryType;
    PIPE_ALLOCATOR_PLACE  AllocatorPlace;
    PIPE_DIMENSIONS       Dimensions;
    KS_FRAMING_RANGE      PhysicalRange;
    IKsAllocatorEx*       PrevSegment;
    ULONG                 CountNextSegments;
    IKsAllocatorEx**      NextSegments;
    ULONG                 InsideFactors;
    ULONG                 NumberPins;
} ALLOCATOR_PROPERTIES_EX, *PALLOCATOR_PROPERTIES_EX;


KSSTREAM_SEGMENT

The KSSTREAM_SEGMENT structure contains information that describes an I/O operation occurring on a stream.

typedef struct _KSSTREAM_SEGMENT {
    IKsInterfaceHandler  *KsInterfaceHandler;
    IKsDataTypeHandler   *KsDataTypeHandler;
    KSIOOPERATION         IoOperation;
    HANDLE                CompletionEvent;
} KSSTREAM_SEGMENT, *PKSSTREAM_SEGMENT;

Members

KsInterfaceHandler
Pointer to a IKsInterfaceHandler interface for the I/O operation.
KsDataTypeHandler
Pointer to a IKsDataTypeHandler interface for the I/O operation.
IoOperation
Value that specifies the type of I/O operation. This value can be one of the following values from the KSIOOPERATION enumeration:
Value | Description
KsIoOperation_Write | Write data to stream.
KsIoOperation_Read | Read data from stream.

CompletionEvent
Handle to an event that is used to signal that the I/O operation completed.

Headers

Defined in ksproxy.h. Include ksproxy.h.

See Also

IKsDataTypeHandler, IKsInterfaceHandler, IKsInterfaceHandler::KsCompleteIo, IKsInterfaceHandler::KsProcessMediaSamples, IKsPin::KsMediaSamplesCompleted


PIPE_DIMENSIONS

The PIPE_DIMENSIONS structure is for proxy use and not recommended for application use. PIPE_DIMENSIONS contains information that describes the compression/expansion ratio of frames on various pins related to a pipe.

typedef struct _PIPE_DIMENSIONS {
    KS_COMPRESSION    AllocatorPin;
    KS_COMPRESSION    MaxExpansionPin;
    KS_COMPRESSION    EndPin;
} PIPE_DIMENSIONS, *PPIPE_DIMENSIONS;


PIPE_TERMINATION

The PIPE_TERMINATION structure is for proxy use and not recommended for application use. PIPE_TERMINATION contains information that describes the pin terminator of a pipe.

typedef struct _PIPE_TERMINATION {
    ULONG                       Flags;
    ULONG                       OutsideFactors;
    ULONG                       Weigth;
    KS_FRAMING_RANGE            PhysicalRange;
    KS_FRAMING_RANGE_WEIGHTED   OptimalRange;
    KS_COMPRESSION              Compression;
} PIPE_TERMINATION;


Virtual Device Drivers for MS-DOS Applications or Special Hardware

Note A VDD need only be written to support special-purpose hardware devices that operate under an MS-DOS® application. The provided VDM has built-in support for commonly used hardware such as serial communication ports, video, mouse, and keyboard. Consequently, you should not need a VDD to virtualize access to these common devices.

The NT-based 32-bit operating system provides a virtual DOS machine (VDM) within the Microsoft® Win32® subsystem to support real-mode and protected-mode MS-DOS applications. The VDM creates an environment where unmodified 16-bit MS-DOS binaries can execute without threatening the security and integrity of the 32-bit system. The VDM environment serves programs such as:

  • MS-DOS applications
  • 16-bit drivers
  • 16-bit Windows applications in the Windows on Windows (WOW) subsystem
  • Terminate and stay resident (TSR) programs

The NT-based operating system launches a VDM as necessary to support 16-bit applications launched by the user. There can be several VDMs running at any one time, each in its own process. Every VDM sets up a self-contained virtual DOS machine environment. Each individual VDM is dynamically configured to run either a Windows 3.x application or an MS-DOS application. When any Windows 3.x application is launched, the VDM in which it runs loads the WOW subsystem, which is a simulation of the Windows® 95 16-bit environment. Any Windows 3.x application can run either in a separate VDM or in the default shared-WOW VDM. In addition, a console session launches a VDM whenever the user starts an MS-DOS application from the command prompt.

When the VDM is launched, it:

  • Allocates memory in which to create a virtual DOS machine.
  • Reads the files \system32\config.nt and \system32\autoexec.nt.
  • Loads drivers and executes batch files as specified.
  • Loads the application and executes it.

The application runs as it would in a native MS-DOS environment because the VDM provides virtual equivalents of all the functionality MS-DOS would supply to the application. All drivers and batch files execute within the virtual DOS environment set up by the VDM.

Given the functionality of the VDM, most MS-DOS applications can run without any modification or additions in the Windows NT/Windows 2000 environment. However, there are some MS-DOS applications that depend on custom hardware, such as a fax board or a 3270 communications board. Generally, these applications have a plug-in hardware board they manipulate directly through 80386/80486 I/O port IN and OUT instructions and by writing directly to memory on the board. These applications might also use DMA to transfer data to and from the board. In an MS-DOS environment, these operations allow the application or its 16-bit driver to get direct access to the hardware device, as shown in the following figure .

Normal MS-DOS hardware device access

In an MS-DOS system, an application can perform these operations directly. In some cases, the application uses a 16-bit device driver or a TSR to communicate with the hardware. The application makes calls to the driver or calls the TSR through a software interrupt. For the purposes of this document, the 16-bit driver or TSR is considered to be an extension of the application that requests services. Thus, when this document talks about an MS-DOS application, it refers to either an MS-DOS application that manipulates a hardware device directly, or to a combination of an MS-DOS application and a 16-bit driver or TSR that manipulates the hardware.

On the NT-based operating system, MS-DOS application programs (and 16-bit drivers or TSRs) do not have sufficient processor privilege to use 80386/80486 I/O ports, and the virtual addressing mode of the system does not permit the real-mode addressing techniques of DMA to the board.

To support an MS-DOS application using special hardware in an NT-based 32-bit environment, the application developer must write a 32-bit kernel-mode device driver to access the board hardware. The developer must also write a VDD to translate operations performed by the MS-DOS application into the corresponding kernel-mode device driver calls for the particular board. The paired kernel-mode device driver and VDD for the device enable the original MS-DOS application to run in the VDM layer.

In addition to I/O port and memory access arbitration, a VDD can also support DMA, register manipulation, translation of real-mode addresses to 32-bit full pointers, and hardware interrupt simulation. The following sections describe how to write a VDD.


How to Provide Virtual Device Support

On NT-based 32-bit systems, a 16-bit MS-DOS application runs in the context of the VDM. Likewise, any TSRs or 16-bit drivers also run in the VDM layer, just as they would on a normal MS-DOS machine. Attempts to perform privileged hardware access from the VDM layer must be intercepted and routed to the kernel-mode device driver where those operations can occur without compromising system integrity.

There are two strategies for intercepting an application's attempts to access its hardware:

  1. Modify your application (or its 16-bit device driver) to call the VDD you have written, instead of directly accessing the hardware.
  2. Instead of modifying your MS-DOS application, rely on the VDM to intercept disallowed hardware accesses and route them to your VDD.

These two strategies, and the support routines provided to support them, are discussed in the following sections.


Application-Based Intercepts

This strategy involves modifying the MS-DOS application or its 16-bit driver to intercept the device access at a very high level and route it directly to the VDD, which routes the request to the appropriate kernel-mode driver. In addition to modifying the original application or driver, you must also write a VDD and kernel-mode device driver. Control calls in the original driver that access the hardware directly (I/O port or memory mapped accesses) are replaced by control calls to the VDD. In turn, the VDD calls the kernel-mode device driver.

The following figure shows how application-based intercepts flow through the various levels of the system from the application to the hardware. .

Application-based intercepts of device access


VDM-Based Intercepts

The second strategy allows the VDM to intercept device accesses at a much lower level. The original MS-DOS application and its driver are not modified. The VDM intercepts low-level port I/O or board-memory accesses and attempts to route the operation through the appropriate VDD. The VDD then calls Win32 functions, such as DeviceIoControl, to access the kernel-mode driver. This method involves writing a VDD and kernel-mode device driver, but not a replacement 16-bit driver.

Although this low-level interception is convenient, it is inefficient because the VDM has to trap and dispatch the disallowed operations. If your application needs higher performance in its communication with a hardware device, modify the application (or its 16-bit driver or TSR) so it dispatches directly to the VDD rather than relying on the VDM to intercept disallowed device-access operations.

For example, consider an MS-DOS 3270 terminal program using a 16-bit device driver to communicate with a plug-in 3270 communications board. The driver provides a control call to send a block of text out over the 3270 cable. The application prepares the block of data and then passes the data to the 16-bit driver. The driver then initiates a series of I/O port operations to directly communicate with the 3270 board. In an NT-based 32-bit system, the 16-bit device driver does not have sufficient privilege to access the I/O ports. A modified 16-bit driver makes a call to the 3270 VDD instead of trying to access the board's I/O ports. The VDD then calls the 32-bit kernel-mode device driver to control the board. You can think of the modified 16-bit driver as a stub driver, where most of the functionality has been delegated to the VDD and its corresponding kernel-mode driver.

The following figure shows how VDM-based intercepts flow through the various levels of the system from the application to the hardware. Shaded boxes show elements that must be written by the developer.

VDM-based intercepts of device access

Note You can actually use a combination of application-based and VDM-based intercepts when moving your MS-DOS program to an NT-based platform. The application-based intercepts provide the best performance, but using the VDM-based intercepts can save you the effort of rewriting parts of your application or 16-bit driver where performance is not crucial.

The VDM needs a mechanism to determine the specific device an application is trying to access. To accomplish this, each VDD tells the VDM which I/O ports it supports and the range of board memory it accesses. Each VDD/device pair claims a unique range of port addresses and memory ranges it supports. The VDD installs callback functions for ranges of I/O ports and memory areas. The VDM directs application I/O port operations and memory accesses to the appropriate VDD-installed callback functions.

For example, assume a fax board is supporting an MS-DOS application. The fax board supports I/O ports in the range 0x230-0x250 and has 32K of memory, starting at address 0xE8000. When the fax board's VDD is initialized, the VDD tells the VDM which ports it supports and where the board memory is located. When the MS-DOS fax application tries to access these I/O ports or board memory, the VDM intercepts the operations and passes them on to the fax VDD callback functions. In turn, the VDD callback functions call Win32 functions, such as DeviceIoControl, to request services from the kernel-mode device driver for the fax board.


Modifying an MS-DOS Application or 16-bit Driver

NT-based platforms provide the functions RegisterModule, UnregisterModule, and DispatchCall for a 16-bit driver or MS-DOS application to call a 32-bit VDD. These functions can be included in a 16-bit application program or driver to bridge the gap between the 16- and 32-bit environments.

During its initialization, the 16-bit driver or MS-DOS application calls RegisterModule, specifying the name of the VDD, the name of the VDD initialization routine, and the name of the VDD dispatch routine to be called each time the 16-bit application or driver calls DispatchCall. The RegisterModule function returns a handle to the VDD. If the VDD has not yet been loaded, RegisterModule loads and initializes it before returning. The application or driver can then use the VDD handle when using DispatchCall, which calls the VDD dispatch function specified in RegisterModule. When the application or driver is finished with the VDD, it can call UnregisterModule to unload the VDD and release its resources.

It is not necessary to modify an MS-DOS application or 16-bit device driver unless you want to directly call your VDD. An unmodified MS-DOS application's attempts to directly access the hardware are intercepted by the VDM and routed to the appropriate VDD. Modify your application only if you need the additional performance provided by direct high-level interceptions of device access requests.

If the VDD needs to use VDDSimulate16, the 16-bit device driver or its stub will need to change as well. For VDDSimulate16 to complete, the 16-bit driver needs to call VDDUnsimulate16.

The following functions (macros) are provided for 16-bit drivers or MS-DOS applications:

Function | Description
DispatchCall | Passes a request to a DLL.
RegisterModule | Registers a third-party DLL with the VDM.
UnRegisterModule | Unregisters a third-party DLL with the VDM.


Writing a VDD

The following sections describe how to write a virtual device driver. The VDD is a 32-bit DLL that runs in user mode on NT-based operating systems. Its purpose is to translate requests from MS-DOS programs into calls to a 32-bit kernel-mode device driver. The VDD serves as a bridge between the 16-bit MS-DOS application and the 32-bit kernel-mode driver. The VDD can be called directly from a modified MS-DOS application, as explained in Application-Based Intercepts or it can rely on the VDM to intercept device access requests from the application and route them to callback functions the VDD has installed.


Registering the Driver (Not Required for Application-Based Intercepts)

If you are writing application-based intercepts, RegisterModule loads and installs the 32-bit VDD. In this case, you do not need to follow the installation procedures described in this section.

The registry contains information for loading and configuring your driver. Each VDD for VDM-based intercepts must be identified under the key HKEY_LOCAL_MACHINE\SYSTEM \CurrentControlSet \Control \VirtualDeviceDrivers. The value entry of the key is an array of zero-terminated strings terminated by two null characters (REG_MULTI_SZ format). Each substring specifies a full path name to a VDD the system loads when the VDM process is initialized. The format of the registry entry is shown as follows:

[VirtualDeviceDrivers]

VDD = <full-path of the VDD1.DLL>\0<full-path of the VDD2.DLL>\0\0

Your application installation program can use the registry API functions, such as RegSetValue, to modify the required registry entry to enable your VDD, or you can require the user or system administrator to modify the entry with regedit.exe.

The RegSetValue function and REG_MULTI_SZ format are described in the Win32 SDK.


VDD Initialization

A VDD is implemented as a 32-bit DLL. Accordingly, it follows all the rules described for Win32 DLLs in the Win32 SDK. The system calls the DLL's main entry point function when initializing the DLL and also when terminating it.

At initialization, a VDD allocates and initializes any memory it needs. The VDD should also get a handle to the 32-bit kernel-mode driver for its device. The kernel-mode driver for the device registers a Win32 name for itself when the driver is initialized. The VDD can use this virtual name to get a handle for the driver by calling CreateFile. For example, the kernel-mode driver for a fax board might register itself under the name "fax1." The VDD can obtain a handle to the fax board driver by supplying the name "\\ .\fax1" to the CreateFile function. When the VDD has a handle to the driver, it can make ReadFile, WriteFile, or DeviceIoControl calls to communicate with the driver. If the VDD can't open the kernel-mode driver for its device, it should return FALSE to indicate an error.

If the VDD is relying on the VDM to intercept device access by the MS-DOS application, the VDD initialization must install its callback functions for handling I/O port and board-memory accesses, as explained in I/O Ports After these callback functions (also called hooks) are installed, they do the real work of the VDD. The VDM calls your callback functions to handle I/O port operations as well as accesses to board memory from the application.

If the VDD is relying on a modified MS-DOS application to directly call the VDD, there is no need to install I/O or memory access hooks.

A skeleton for the VDD initialization function is shown as follows:

BOOL VDDInitialize(IN PVOID DllHandle, IN ULONG Reason,
IN PCONTEXT Context OPTIONAL)

/*++

Routine Description:

Arguments:
    DllHandle - Not Used
    Reason - Attach or Detach
    Context - Not Used

Return Value:
    SUCCESS - TRUE
    FAILURE - FALSE

--*/

{

    switch (Reason) {

    case DLL_PROCESS_ATTACH:
    // Allocate VDD's local heap if needed. Check that NT FAX driver
    // is available by opening that device.
        break;
    case DLL_PROCESS_DETACH:
    // Deallocate VDD's local heap if needed.
    // Communicate to appropriate Device driver about your departure.
        break;
    default:
        break;
    }

    return TRUE;
}


I/O Ports

In the MS-DOS environment, a peripheral board typically has a range of I/O ports to which it can respond. These ports are often configured by jumpers on the board or through software setup. Special-purpose application programs control and communicate with the board by performing 80386/80486 assembly IN and OUT instructions to the ports supported by the board.

On NT-based platforms, application programs have insufficient processor privilege to access I/O ports. Therefore, the VDM intercepts IN and OUT instructions from MS-DOS application programs and attempts to find an I/O handler registered by a VDD for the specified port. Each VDD installs I/O handlers (also known as I/O hooks) for one or more ranges of port addresses. For example, a VDD could install I/O handlers for the port range 0x220-0x227 and 0x2F0-0x2F7. The VDM keeps track of all I/O port handlers installed by VDDs in that VDM. When the VDM intercepts an IN or OUT instruction from an MS-DOS application, it looks at all the installed I/O handlers to see if the current port being accessed falls within one of the installed port ranges.

A VDD must install I/O port handlers for the ports used by its application. The handlers are called each time there is an IN or OUT instruction on one of the designated ports. A VDD OUT handler typically gathers several OUT calls into a single complete command and then translates that command into a Win32 DeviceIoControl call to the kernel-mode device driver for the board. Likewise, a single driver call might require a VDD IN handler to be called several times to completely transfer the information back to the application.

A VDD installs its I/O port handlers within the VDD initialization routine, explained in Registering the Driver. Initialize a VDD_IO_HANDLERS structure with pointers to the VDD's I/O port handlers, specifying one or more ranges of I/O ports the VDD responds to, and call the VDDInstallIOHook function. The VDD_IO_HANDLERS structure contains slots for IN and OUT handlers for byte, word, and string operations. The VDD must supply at least byte-in and byte-out handlers. If you supply a NULL function pointer for the word and string operations, the VDM automatically emulates them by calling the byte operation functions the VDD provides, although it is often more efficient to implement word and string operations yourself.

A particular VDD can only have one set of I/O handler functions for all the I/O ports it uses. That is, a VDD cannot install one set of functions for one I/O port range and another set of functions for another port range. Of course, other VDDs can install their own functions for other ranges, although two VDDs in the same VDM cannot use overlapping port ranges.

A VDD's main entry point function is also called when the VDD is about to be terminated. At that time, the VDD can deinstall its I/O hooks by calling VDDDeinstallIOHook.

Note A VDD should never directly hook the I/O ports for DMA or Video. Video is handled by the VDM. See DMA for a discussion of how to facilitate DMA transfers in the VDM environment.

The following functions are used with I/O hooks:

Function | Description
VDDInstallIOHook | Hooks the I/O ports the VDD is responsible for.
VDDDeinstallIOHook | Unhoooks the I/O ports previously hooked by a VDD.


Memory-Mapped I/O

In the MS-DOS environment, applications often find it advantageous to write directly to the memory on a particular board. On NT-based platforms, applications cannot write directly to physical addresses. Thus, while an application may use the virtual address 0xE8000, the actual physical address of the memory will not necessarily be the same. In fact, the memory space in the range allowed for boards is initially marked as invalid by the memory manager. Any attempt to access memory in this range by unmodified MS-DOS applications results in a page fault. A VDD can control access to the memory range used by its device by using the functions described in the following sections.


Memory Hooks

A VDD can install a memory hook function called by the system when an MS-DOS application tries to access a specified range of memory on the device. The VDD installs a memory hook function by calling VDDInstallMemoryHook in the VDD initialization routine, specifying a pointer to the callback function and a range of memory it supports. The VDD should install a memory hook for all ranges of board memory the application will attempt to access.

The VDM sizes the memory ranges you specify for your memory hooks to page boundaries. Two VDDs in the same VDM cannot hook overlapping ranges of memory.

Note During VDM initialization, valid areas of ROM on plug-in boards are automatically mapped into the VDM address space. Thus, a VDD does not have to install a memory hook for the ROM on its board.

A VDD memory hook is called if the application accesses an invalid memory range on which a VDD has placed a memory hook. The chain of events looks like this:

  1. The application tries to access memory in the board's address range.
  2. Because the memory manager has marked that range as not present, the page fault handler is called and finds that the memory has not been swapped out, but it is invalid.
  3. The page fault handler then asks the VDM to verify if the memory is hooked by one of its registered VDD memory handlers.
  4. The VDM calls the memory hook the VDD installed for that range of memory. The memory hook can either:
    • Validate the range of memory by calling VDDAllocMem. When the memory hook returns, the system retries the instruction that caused the original page fault.
    • Modify the CS:IP so the offending access instruction is not retried.

Note You must solve the page-fault problem before your memory hook returns. The VDD callback function must either allocate some memory to validate the invalid range or modify the CS:IP so that the offending instruction is not retried. Failure to do either can cause an infinite loop in the page fault handler.

After the VDD has allocated a buffer for the range covered by its memory hook, the hook is not called again unless you deallocate some or all of that range, causing another page fault in that range. Use VDDFreeMem to deallocate memory allocated with VDDAllocMem. These two functions ensure the memory operations are performed in a platform-independent manner.

In a typical scenario, the VDD memory hook is called the first time the application tries to access the VDD's memory-mapped range. The memory hook calls VDDAllocMem to map that range onto the virtual address space. Subsequent accesses to that range proceed normally. The VDD eventually transfers the data in its buffer to the actual device hardware by calling the device driver. How often that transfer takes place depends on the operating characteristics of the application and the hardware. The need to transfer data is often signaled by a command sequence coming in through the I/O ports, as described in I/O Ports. Alternatively, a VDD can create its own worker thread responsible for flushing the data to the driver. This worker thread can then use Sleep or WaitForSingleObject with a timeout to get timer functionality.

Likewise, the VDD can periodically request services from the kernel-mode device driver to offload data from the board memory to the VDD buffer so it can be consumed by the application. If the memory hook encounters an unrecoverable error, such as a failure to allocate memory, it should put up a message to the user by calling MessageBox and then call VDDTerminateVDM.

The memory hook function is called by using the address on which the page fault occurred and an argument that tells whether it was a read or a write operation that caused the fault. There is no information given to identify the operand value. If the VDD needs to know this information, it can use GetCS and GetIP to get the segmented address of the offending instruction, use GetVDMPointer to convert it to a 32-bit address, and then use that address to decode the instruction causing the page fault.

The installation process for memory hooks is very similar to that described for I/O hooks I/O Ports. Specify a pointer to the VDD memory hook callback function and a range of memory the device supports, and then call VDDInstallMemoryHook in the initialization routine of the VDD.

The VDD must call VDDDeinstallMemoryHook to remove the memory hook when the VDD is terminated. Before removing its memory hook, a VDD should call VDDFreeMem to free any memory it allocated with VDDAllocMem. When the VDD deinstalls a memory hook, the range of memory supported by that hook is marked as invalid by the memory manager. The following code shows a template of a memory hook and its installation.

/** Global variables **/

HANDLE  hVDD;           /* VDD module handle */
HANDLE  hVddHeap;       /* VDD local heap */
PBYTE   IOBuffer;       /* buffer to simulate I/O Read and Write */
ULONG   MIOAddress;     /* memory mapped I/O linear address */
PVOID   BaseAddress;    /* memory mapped I/O virtual address */

BOOL VDDInitialize(HANDLE hVdd, DWORD dwReason, LPVOID lpReserved)

/*++

Routine Description:

    The DllEntryPoint for the VDD that handles initialization and termination.

Arguments:
    hVdd   - The handle to the VDD
    Reason - flag word that indicates why the Dll Entry Point was called
    lpReserved - Unused

Return Value:
    BOOL bRet - if (dwReason == DLL_PROCESS_ATTACH)
                   TRUE    - Dll Initialization successful
                   FALSE   - Dll Initialization failed
                else
                   always returns TRUE
--*/

{
    int     i;
    static BOOLEAN IOHook;             /* True, if we installed an I/O
                                        hooked. */
    static BOOLEAN MIOHook;            /* True, if we installed a
                                        memory hook. */
    static VDD_IO_PORTRANGE PortRange;
    VDD_IO_HANDLERS  IOHandlers;

/**
    Keep a copy of VDD handle in a global variable so the other
    functions can see it.
**/
    hVDD = hVdd;

    switch (dwReason) {

    case DLL_PROCESS_ATTACH:

        // Allocate the VDD's local heap.
        hVddHeap = HeapCreate(0, 0x1000, 0x10000);

    if (!hVddHeap) {
        OutputDebugString("VDD: Can't create local heap");
            return FALSE;
    }

        IOBuffer = (PBYTE)HeapAlloc(hVddHeap,0,IO_PORT_RANGE);

    if (!IOBuffer)    {
        OutputDebugString("VDD: Can't allocate IO buffer from heap");
            HeapDestroy(hVddHeap);
            return FALSE;
    }

        // Communicate your departure to the appropriate driver.

    // Set emulated I/O to floating.
        for (i = 0 ; i < IO_PORT_RANGE; i++)
        IOBuffer[i] = FLOATING_IO;

    IOHandlers.inb_handler = MyInB;
    IOHandlers.inw_handler = NULL;
    IOHandlers.insb_handler = NULL;
    IOHandlers.insw_handler = NULL;
    IOHandlers.outb_handler = MyOutB;
    IOHandlers.outw_handler = NULL;
    IOHandlers.outsb_handler = NULL;
    IOHandlers.outsw_handler = NULL;
    PortRange.First = IO_PORT_FIRST;
    PortRange.Last = IO_PORT_LAST;

    // Hook I/O mapped I/O.
    IOHook = VDDInstallIOHook(hVDD, (WORD) 1, &PortRange, &IOHandlers);
    // Get 32 bits linear address of memory-mapped I/O.
    MIOAddress = (ULONG) GetVDMPointer(MIO_ADDRESS, MIO_PORT_RANGE, 0);
    // Hook memory-mapped I/O.
    MIOHook = VDDInstallMemoryHook(hVDD, (PVOID) MIOAddress,
                MIO_PORT_RANGE,
                (PVDD_MEMORY_HANDLER)MyMIOHandler);
    break;

    case DLL_PROCESS_DETACH:

        // Communicate your departure to the appropriate driver.
    if (IOHook)
        VDDDeInstallIOHook(hVDD, 1, &PortRange);
    if (MIOHook) {
        VDDDeInstallMemoryHook(hVDD, (PVOID) MIOAddress, MIO_PORT_RANGE);
        if (BaseAddress) {
                VDDFreeMem(BaseAddress, PAGE_SIZE, MEM_DECOMMIT);
        }
    }

        // Deallocate VDD's local heap, if needed.
        HeapDestroy(hVddHeap);
        break;

    default:
        break;
    }

    return TRUE;
}

VOID MyInB(WORD    Port, PBYTE Buffer)
{
// Provide the data from our buffer.
    *Buffer = IOBuffer[Port - IO_PORT_FIRST];
}

VOID MyOutB(WORD Port, BYTE Data)
{
    // Update our local buffer.
    // In a real application, the VDD might want to call its associated
    // device driver to update the change.

    IOBuffer[Port - IO_PORT_FIRST] = (BYTE)Data;
    // If the I/O port is the one to trigger DMA operation, do it.
    // To demonstrate the two options in handling a DMA operation, we
    // use two ports here to trigger different DMA operation schemes.

    if (Port == IO_PORT_FIRE_DMA_FAST) {
    FastDMA( );
    }
    else {
    if(Port == IO_PORT_FIRE_DMA_SLOW) {
        SlowDMA( );
        }
    }
}

VOID MyMIOHandler(
ULONG    Address,        // faulting linear address
ULONG    RWFlags         // 1 if write operation, 0 if read
)
{

    // Map the memory for the memory-mapped I/O so we won't
    // get a page fault on our memory-mapped I/O after this.
    // We may reserve the memory during  DLL_PROCESS_ATTACH by using
    // MEM_RESERVE rather than MEM_COMMIT, as we did here.
    // The solution applied here is not the best, although it
    // is the simplest. A better way to handle memory-mapped
    // I/O is to hook the page fault as we did here and decode the
    // faulting instruction, simulate its operation, and advance 16 bits
    // application program counter(getIP and setIP).

    BaseAddress = VDDAllocMem ((LPVOID) MIOAddress, PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE);
    if (!BaseAddress) {
    OutputDebugString("VDD: Can't allocate virtual memory");
    }
}


Including Upper Memory Blocks

Many devices have a ROM that occupies a particular range in the device's memory space. If a VDD knows it will not be accessing the ROM, it can call VDDIncludeMem to allow the VDM to use the address range of the ROM as an MS-DOS UMB. A VDD most likely calls VDDIncludeMem if it has chosen to implement application-based intercepts, as described in Application-Based Intercepts, where the VDD replaces most of the functionality originally in the device ROM. Since the ROM is no longer needed, its memory space can be reused by the VDM.


Memory Access

MS-DOS applications are written to use the x86 segmented memory architecture. They use pointers composed of a 16-bit segment or selector and a 16-bit offset into the segment. Windows NT/Windows 2000, on the other hand, uses a flat memory model, in which pointers are simply 32-bit linear addresses. Because a VDD can receive a segmented address pointer from an MS-DOS application, NT-based systems provide the function GetVDMPointer to translate MS-DOS segment:offset or selector:offset style pointers to 32-bit linear address pointers. The VDD can use the 32-bit pointer to access memory by using Win32 functions, such as VDDAllocMem.

Do not manually convert segmented addresses (by shifting the segment by four and adding the offset). On a non-x86 machine, the VDM might not be based at physical address zero. The GetVDMPointer function converts a segmented address to a 32-bit address in a platform-independent manner.

If the VDD is running on a RISC-based machine, the x86 emulator precompiles instructions in memory to increase performance. When a VDD uses a pointer returned by GetVDMPointer to modify memory in a particular range, it is important to tell the emulator that a change has occurred so the emulator can recompile the instructions in that range. Calling FlushVDMPointer or FreeVDMPointer tells the emulator the memory is no longer subject to modification and the instructions in that range can be precompiled again. These functions simply return to the caller on an x86 machine.


DMA

In the MS-DOS environment, applications can use DMA to directly transfer data between application memory and the memory on a device. In the NT-based environment, applications cannot use DMA to directly access physical memory. If they could, they would subvert the memory protection afforded by the memory manager. Therefore, the VDM controls all the DMA ports used by MS-DOS applications. Requests for DMA service from MS-DOS applications do not actually result in the DMA controller being programmed. Instead, the VDM traps the parameters to the request and does not actually transfer the data. It is up to the VDD to pick up the DMA transfer request and complete the operation. Because the VDM keeps track of DMA requests on a per-channel basis, more than one VDD in the same VDM can use DMA as long as they use different channels.

Unlike the callback mechanisms for I/O port access and memory-mapped accesses, the VDD is not notified directly that a DMA transfer has been requested. Instead, the VDD determines the application has requested a DMA operation when the VDD receives a command from the application through the normal I/O port channels on its board. The application and the device must use some sort of synchronization technique to coordinate DMA transfers. Because all possible synchronization messages between an MS-DOS application and its device must pass through the VDD, the VDD is notified whenever a DMA transfer is requested. At that point, the VDD must do something to actually transfer the data.

There are two strategies for handling DMA from a VDD. The first strategy involves the least programming work, but it requires two buffer-copy operations and is inherently inefficient. The second strategy is harder to implement but more efficient because it only requires a single buffer-copy operation. These two strategies are described in the following sections.


Double-Buffer DMA Transfer

In the double-buffer strategy, the VDD calls VDDRequestDMA to move the data as described by the last DMA request. The VDDRequestDMA function looks at the last DMA command trapped by the VDM and executes a data transfer that matches those DMA parameters, although the transfer does not actually use DMA. When the DMA transfer request specifies that data be moved from an application buffer to the device, the data actually goes from the application buffer to a block of memory the VDD has mapped to the virtual address space occupied by the board. When the data has been transferred to the VDD's buffer, the VDD can then transfer it to the device by passing the data to the kernel-mode device driver. Likewise, when the DMA transfer is requesting data be moved from the device to an application buffer, the VDD first calls the kernel-mode driver to copy the data from the device to the VDD's buffer. The VDD can then transfer the data from its buffer to the application's buffer by calling VDDRequestDMA, as shown in the following figure.

Two-stage virtual DMA transfer


Single Buffer DMA Transfer

In the single-buffer strategy, the VDD again determines a DMA request is pending by receiving a command from the application. To avoid copying the data to its own memory space, the VDD calls VDDQueryDMA to determine the source, destination, and other DMA parameters. It then sends the DMA information to the kernel-mode device driver and allows that driver to transfer the data directly from the application's buffer to the device, as shown in the following figure. The kernel-mode device driver can program the DMA controller through the platform-specific HAL to carry out the transfer or it can use some other means to transfer the data. In the other direction, the VDD can request that the driver transfer data directly from the device to the application's buffer. In either direction, VDDs using this second strategy must call VDDSetDMA to update the DMA state after the transfer is complete.

Direct virtual DMA transfer

Because DMA registers contain physical addresses, a VDD that uses VDDQueryDMA must correctly convert these addresses to Win32 linear addresses in the VDM process address space.

The following figure shows how the virtual DOS machine can be laid out in memory relative to the VDM process. On an x86 machine, linear zero of the VDM process is the same as 0:0 for DOS. On a nonx86 machine these addresses might be different. The addresses returned by VDDQueryDMA are relative to the DOS 0:0.

Memory Layout for DMA addresses

On an x86 machine, there is no difference between a DMA address, as programmed by the MS-DOS application to the DMA chip, and a Win32 address. On a nonx86 machine, you must add the offset from VDM 0 to DOS 0:0 to convert a DMA address to a Win32 address. To get the offset from VDM to DOS, call GetVDMPointer(0,0,0). On an x86 machine, this call returns zero. On a RISC machine, it returns the difference between VDM 0 and DOS 0:0. Thus, adding GetVDMPointer(0,0,0) to a DMA address always gives the correct Win32 linear pointer, regardless of machine type.


Example DMA Transfers

To illustrate these two strategies, consider the example of a fax board in an MS-DOS environment. The controlling application creates an image of the fax in application memory. It then programs the DMA controller to move the fax image to the memory on the fax board. The application then sends a command to the fax board (through an I/O port operation or other means) telling it to receive the DMA transfer and start sending the fax. In an NT-based environment, the unmodified MS-DOS application running under VDM requests the DMA and then signals the fax board to receive the DMA and begin sending the fax. However, there are two differences:

  1. The DMA controller has not really been programmed because the VDM intercepted the DMA request, although the application has no way of knowing this.
  2. The command to the fax board has been intercepted by the VDD. So now, the VDD must move the data specified by the DMA request to the board.

Using the double-buffer strategy described in Double-Buffer DMA Transfer, the VDD calls VDDRequestDMA to move the data from the application's buffer to the VDD buffer. This call does not actually use the DMA controller, but performs the equivalent data transfer by other means. The VDD then calls the kernel-mode driver to move the data to the device. Finally, the VDD relays the send fax command to the kernel-mode driver.

Using the single-buffer strategy described in Single Buffer DMA Transfer, the VDD calls VDDQueryDMA to determine the parameters for the DMA request. The VDD then sends these parameters to the kernel-mode driver and enables the driver to control the data transfer directly from the application's buffer to the device. When the driver has transferred the data, the VDD calls VDDSetDMA to update the DMA state. Finally, the VDD relays the send fax command to the kernel-mode driver.

The following functions are used for memory accesses:

Function | Description
FlushVDMPointer | Flushes data associated with a memory range.
FreeVDMPointer | Releases a pointer returned by GetVDMPointer.
GetVDMPointer | Returns a linear address for an x86 address.
VDDAllocMem | Allocates memory at a given virtual address.
VDDFreeMem | Releases previously allocated memory.
VDDDeInstallMemoryHook | Releases a range of memory-mapped I/O addresses.
VDDIncludeMem | Includes a particular memory range for use as a UMB.
VDDInstallMemoryHook | Releases memory-mapped addresses.
VDDQueryDMA | Gathers all DMA data.
VDDRequestDMA | Requests a DMA transfer from a VDD.
VDDSetDMA | Resets the state of the virtual DMA controller.


Register Manipulation

The VDM provides a complete set of API functions to manipulate the registers of an x86 processor. The VDD can use these functions to get and set registers as needed to facilitate its communication with its device. These functions can be used to get CS and IP during a memory hook, as described in Memory Hooks.The register functions are useful in a VDD if your modified application calls the VDD directly, because the direct interface between an MS-DOS application and a VDD requires certain arguments be passed in registers.

On a RISC-based machine, these register manipulation functions use the virtual register set maintained by the x86 emulator.

GET Register Functions | SET Register Functions
getEAX( ) | setEAX(value)
getAX( ) | setAX(value)
getAH( ) | setAH(value)
getAL( ) | setAL(value)
getEBX( ) | setEBX(value)
getBX( ) | setBX(value)
getBH( ) | setBH(value)
getBL( ) | setBL(value)
getECX( ) | setECX(value)
getCX( ) | setCX(value)
getCH( ) | setCH(value)
getCL( ) | setCL(value)
getEDX( ) | setEDX(value)
getDX( ) | setDX(value)
getDH( ) | setDH(value)
getDL( ) | setDL(value)
getESP( ) | setESP(value)
getSP( ) | setSP(value)
getEBP( ) | setEBP(value)
getBP( ) | setBP(value)
getESI( ) | setESI(value)
getSI( ) | setSI(value)
getEDI( ) | setEDI(value)
getDI( ) | setDI(value)
getEIP( ) | setEIP(value)
getIP( ) | setIP(value)
getCS( ) | setCS(value)
getSS( ) | setSS(value)
getDS( ) | setDS(value)
getES( ) | setES(value)
getCF( ) | setCF(value)
getPF( ) | setPF(value)
getAF( ) | setAF(value)
getZF( ) | setZF(value)
getSF( ) | setSF(value)
getIF( ) | setIF(value)
getDF( ) | setDF(value)
getOF( ) | setOF(value)
getMSW( ) | setMSW(value)


Interrupt Simulation

The VDDSimulateInterrupt function allows a VDD to simulate a hardware interrupt to the VDM. Call this function if the application depends on an interrupt to tell it that some particular operation has been completed. For example, the application using a fax board might expect to get a particular interrupt when the board is done sending a fax. Because the VDD is notified when the fax board is done, the VDD can simulate the interrupt to the application.

When the VDD calls VDDSimulateInterrupt, the address pointed to by the interrupt vector starts running in 16-bit mode. For an asynchronous interrupt, the VDD should create another thread and call VDDSimulateInterrupt from that thread.

The VDDSimulate16 function is similar to VDDSimulateInterrupt, except it does not require a hardware interrupt to be supported by the 16-bit stub driver. VDDSimulate16 allows the VDD to execute a routine in its 16-bit driver and return when it has finished. Before calling VDDSimulate16, a VDD should preserve all the 16-bit registers its routine might destroy; minimally, it should preserve CS and IP. Then, set the CS and IP for the 16-bit routine. A VDD can also use registers such as AX or BX to pass parameters to its 16-bit routines. At the end of the 16-bit routine, VDDUnSimulate16 sends control back to the VDD. Because this simulation is synchronous, the VDD is blocked in VDDSimulate16 and returns only when the stub driver calls VDDUnSimulate16. The following code shows an example of how these calls are used:

vdd (Win32 Code):
    SaveCS = getCS( );
    SaveIP = getIP( );
    SaveAX = getAX( );
    setCS (16BitRoutineCS);
    setIP (16BitRoutineIP);
    setAX (DO_X_OPERATION);
    VDDSimulate16( );
    setCS (SaveCS);
    setIP (SaveIP);
    setAX (SaveAX);
    . .
    . .
Stub Driver (Initialization):
    RegisterModule        ;Loads VDD
    push cs
    pop ax
    mov bx,offset Simulate16
    DispatchCall          ;passes the address of worker
                          ;routine to VDD in ax:bx
Stub Driver (Run Time)

Simulate16:
    . .
    . .                   ;do the operation index passed in ax
VDDUnSimulate16


Hooking Callback Events

A VDD can hook a callback event if it polls DOS events for which there is no explicit close operation, such as printing using int17h.The VDDInstallUserHook and VDDDeInstallUserHook functions allow a VDD to control events such as:

  • PDB (DOS process) creation and termination
  • VDM block
  • VDM resume

A VDM in which a DOS application runs is attached to the console window in which the DOS application is running. When the first DOS binary runs in that console, the VDM is created, and the DOS binary is terminated. The VDM remains with the console window and waits for the next DOS binary to be launched. While the VDM waits, it should block all its components, including VDDs. A VDD can hook VDM Block and Resume events for this purpose. On block events, a VDD should block all worker threads and clean up any other operation it may have started. On Resume events, the VDD can restart a worker thread. VDDDeInstallUserHook de-installs all events hooked earlier.


Summary

VDDs provide a translation layer between 16-bit MS-DOS applications and special-purpose hardware devices in the NT-based system. A VDD turns an application's attempt to write directly to a device into a Win32 API call that makes a request to a kernel-mode device driver. The key characteristic of every VDD is the original MS-DOS application does not need to be modified to work on 32-bit NT-based machines. By adding a VDD and a kernel-mode device driver, an application developer can move an existing MS-DOS application and its dedicated hardware device to 32-bit NT-based systems.

For improved performance, the MS-DOS application can be modified to directly call its companion VDD. Otherwise, the unmodified application can rely on the VDM to intercept disallowed device accesses and route them to the VDD.

The three main areas in which the VDM intercepts an application's attempts to interact directly with device hardware are:

  1. I/O ports
  2. Memory mapped I/O
  3. DMA

The VDD can install callback functions to handle I/O port access and memory-mapped I/O. The VDD can also make calls to functions provided by the NT-based environment to support DMA transfers between an application and a hardware device. In addition, NT-based systems supply functions that allow a VDD to query and set processor registers and simulate interrupts. These services allow the VDD to fully support the functionality of the original MS-DOS application and its accompanying hardware device.


VDD Functions

The topics that follow describe the functions associated with Virtual Device Drivers.


DispatchCall

DispatchCall is a BIOS operation call made from the 16-bit module to pass a request to its DLL.

DispatchCall(
    );

Parameters

register AX
VDD handle returned by RegisterModule. Other registers may contain the parameters for VDD from 16-bit device driver.

Return Value

If AX is invalid, VDM is terminated with a debug message. VDD can set any register to actually return the value for a 16-bit device driver.

Comments

This service is for application-based intercepts only, to pass a request to a 32-bit DLL.

This function is a 16-bit assembly interface.

See Also

RegisterModule


FlushVDMPointer

FlushVDMPointer is obsolete. Use VdmFlushCache instead.

BOOL
  FlushVDMPointer(
    IN ULONG  Addr,
    IN USHORT  Size,
    PBYTE  Buffer,
    IN BOOL  ProtectedMode
    );


FreeVDMPointer

FreeVDMPointer is obsolete. Use VdmUnmapFlat instead.

BOOL
  FreeVDMPointer(
    IN ULONG  Address,
    IN USHORT  Size,
    PBYTE  Buffer,
    IN BOOL  ProtectedMode
    );


GetVDMPointer

GetVDMPointer is obsolete. Use VdmMapFlat instead.

PBYTE
  GetVDMPointer(
    IN ULONG  Address,
    IN ULONG  Size,
    IN BOOL  ProtectedMode
    );


Register Manipulation Services

Register manipulation services are provided by the following functions. VDD can use these functions to get and set registers as needed to communicate with the 16-bit modules.

The register functions are very useful in a VDD if your modified 16-bit module calls the VDD directly (through DispatchCall), since the direct interface between an MS-DOS application and a VDD require certain arguments be passed in registers.

ULONG getEAX( ); | VOID setEAX(ULONG);
USHORT getAX( ); | VOID setAX(USHORT);
UCHAR getAL( ); | VOID setAH(CHAR);
UCHAR getAH( ); | VOID setAL(UCHAR);
ULONG getEBX( ); | VOID setEBX(ULONG);
USHORT getBX( ); | VOID setBX(USHORT);
UCHAR getBL( ); | VOID setBH(UCHAR);
UCHAR getBH( ); | VOID setBL(UCHAR);
ULONG getECX( ); | VOID setECX(ULONG);
USHORT getCX( ); | VOID setCX(USHORT);
UCHAR getCL( ); | VOID setCH(UCHAR);
UCHAR getCH( ); | VOID setCL(UCHAR);
ULONG getEDX( ); | VOID setEDX(ULONG);
UCHAR getDH( ); | VOID setDX(USHORT);
ULONG getESP( ); | VOID setDH(UCHAR);
USHORT getSP( ); | VOID setDL(UCHAR);
ULONG getEBP( ); | VOID setESP(ULONG);
USHORT getBP( ); | VOID setSP(USHORT);
ULONG getESI( ); | VOID setEBP(ULONG);
USHORT getSI( ); | VOID setBP(USHORT);
ULONG getEDI( ); | VOID setESI(ULONG);
USHORT getDI( ); | VOID setSI(USHORT);
ULONG getEIP( ); | VOID setEDI(ULONG);
USHORT getIP( ); | VOID setDI(USHORT);
USHORT getCS( ); | VOID setEIP(ULONG);
USHORT getSS( ); | VOID setIP(USHORT);
USHORT getDS( ); | VOID setCS(USHORT);
USHORT getES( ); | VOID setSS(USHORT);
USHORT getFS( ); | VOID setDS(USHORT);
USHORT getGS( ); | VOID setES(USHORT);
ULONG getCF( ); | VOID setFS(USHORT);
ULONG getPF( ); | VOID setGS(USHORT);
ULONG getAF( ); | VOID setCF(ULONG);
ULONG getZF( ); | VOID setPF(ULONG);
ULONG getSF( ); | VOID setPF(ULONG);
ULONG getIF( ); | VOID setAF(ULONG);
ULONG getDF( ); | VOID setZF(ULONG);
ULONG getOF( ); | VOID setSF(ULONG);
USHORT getMSW( ); | VOID setIF(ULONG);
VOID setDF(ULONG); | VOID setOF(ULONG);
VOID setMSW(USHORT); |


RegisterModule

This BIOS operation call is made from the 16-bit module to register a third party DLL with the BIOS operation manager. This call returns a handle to the 16-bit caller which is used later to dispatch a call to the DLL.

RegisterModule(
    );

Parameters

Client DS:SI
ASCIIZ string of DLL name
Client ES:DI
ASCIIZ string of Initialization Routine in the DLL. (Optional if eS = 0 and DI = 0).
Client DS:BX
ASCIIZ string to Dispatch routine in the DLL.

Return Value

If successful the client's carry is cleared and the client's handle in AX will equal (non Zero). Otherwise, the client carry will be set, and an error code will be returned in AX.

Client AX | Error Code
AX = 1 | DLL not found.
AX = 2 | Dispatch routine not found.
AX = 3 | Initialization routine not found.
AX = 4 | Insufficient memory available.

Comments

RegisterModule will load the DLL specified in DS:SI. The DLL initialization routine is called and the DLL dispatch routine is stored. All calls made from the DispatchCall are sent to this routine.

See Also

UnRegisterModule, DispatchCall


UnRegisterModule

UnRegisterModule is a BIOS operation call from the 16-bit module to unregister a third party DLL with the BIOS manager.

UnRegisterModule(
    );

Parameters

Client AX
VDD handle returned by RegisterModule.

Return Value

None.

Comments

VDM is terminated with a debug message if the handle is invalid.

Use UnRegisterModule if initialization of a 16-bit application fails after registering the BIOS operation.

See Also

RegisterModule


VDDAllocMem

VDDAllocMem allocates memory at a given virtual address.

BOOL
  VDDAllocMem(
    IN HANDLE  hVdd,
    IN PVOID  Address,
    IN DWORD  Size
    );

Parameters

hVdd
Identifies the VDD.
Address
Specifies the address between 640K and 1MB where memory will be allocated.
Size
Specifies the number of bytes of memory to allocate.

Return Value

VDDAllocMem returns TRUE if successful. If the function fails then FALSE is returned and an error is logged.

The extended error codes are:

Value | Meaning
ERROR_OUTOFMEMORY | Indicates insufficient memory error.
ERROR_INVALID_ADDRESS | Identifies invalid address error.

Comments

VDDs must use this function instead of VirtualAlloc (see the Win32 SDK) to allocate memory.

Address is page-aligned downwards, and Size is stretched upward to be page-aligned.

Address is relative to DOS 0:0. GetVDMPointer should not be called on this address before calling VDDAllocMem.

This address is the same as that provided by the hook handler for memory-mapped I/O.

See Also

GetVDMPointer


VDDFreeMem

VDDFreeMem releases previously allocated memory at a given virtual address.

BOOL
  VDDFreeMem(
    IN HANDLE  hVdd,
    IN PVOID  Address,
    IN DWORD  Size
    );

Parameters

hVdd
Identifies the VDD.
Address
Specifies the address where memory will be freed.
Size
Specifies the number of bytes of memory to free.

Return Value

VDDFreeMem returns TRUE if successful. If the function fails then FALSE is returned and an error is logged. The extended error code available is ERROR_INVALID_ADDRESS, indicating an invalid address error.

Comments

The freed Address is page-aligned downwards, and Size is stretched upwards to be page-aligned.

Address is relative to DOS 0:0. That means GetVDMPointer should not be called on this address before calling VDDAllocMem.

This address is the same as that provided by the hook handler for memory-mapped I/O.

See Also

VDDAllocMem, VDDInstallMemoryHook


VDDDeInstallMemoryHook

VDDDeInstallMemoryHook releases a range of memory-mapped I/O addresses previously allocated by a VDD.

BOOL
  VDDDeInstallMemoryHook(
    IN HANDLE  hVdd,
    IN PVOID  pStart,
    IN DWORD  count
    );

Parameters

hVdd
Identifies the VDD.
pStart
Points to the starting linear address of the range.
count
Identifies the number of bytes of mapped memory that are being used.

Return Value

VDDDeInstallMemoryHook returns TRUE if successful. Otherwise, it returns FALSE and logs an error.

Comments

The memory range becomes invalid once a hook is removed. The only extended error code is ERROR_INVALID_PARAMETER.

Address is relative to DOS 0:0. That means GetVDMPointer should not be called on this address before calling VDDAllocMem.

See Also

VDDInstallMemoryHook


VDDDeInstalllOHook

VDDDeinstalllOHook unhooks the I/O ports previously hooked by a VDD.

VOID
  VDDDeInstalllOHook(
    IN HANDLE  hVdd,
    IN WORD  cPortRange,
    IN PVDD_IO_PORTRANGE  pPortRange
    );

Parameters

hVdd
Identifies the VDD.
cPortRange
Specifies the number of VDD_IO_PORTRANGE structures.
pPortRange
Points to the VDD_IO_PORTRANGE array.

Comments

When VDDDeinstalllOHook cancels a hook, the default hook on those ports subsequently returns 0xFF when reading the port and ignores write operations.

See Also

VDDInstallIOHook


VDDDeInstallUserHook

VDDDeInstallUserHook unhooks callback events previously hooked by this function.

BOOL
  VDDDeInstallUserHook(
    IN HANDLE  hVDD
    );

Parameters

hVDD
Identifies the VDD.

Return Value

TRUE if successful, FALSE otherwise. GetLastError has extended error information.

See Also

VDDInstallUserHook


VDDIncludeMem

VDDIncludeMem includes a specified memory range so that it can be used as UMB.

BOOL
  VDDIncludeMem(
    IN HANDLE  hVDD,
    IN PVOID  Address,
    DWORD  Size
    );

Parameters

hVDD
Identifies the VDD handle.
Address
Points to the address where memory is to be included.
Size
Specifies the number of bytes to be included.

Return Value

VDDIncludeMem returns TRUE if successful. Otherwise, FALSE is logged and an error is returned. The available extended error code is ERROR_INVALID_ADDRESS, indicating an invalid address error.

Comments

If there is a ROM block in the attached adapter and the corresponding VDD knows that it will never use that ROM, the VDD may put the ROM memory space back to the UMB list so the memory is available to the DOS arena.

The address and the size must exactly match the ROM of the attached adapter. It is not allowed to include a portion of the ROM to be used as a UMB.


VDDInstallMemoryHook

VDDInstallMemoryHook releases the memory-mapped I/O addresses a VDD controls.

BOOL
  VDDInstallMemoryHook(
    IN HANDLE  hVdd,
    IN PVOID  pStart,
    IN DWORD  count
    IN PVDD_MEMORY_HANDLER  MemoryHandler
    );

Parameters

hVdd
Identifies the VDD.
pStart
Points to the starting linear address.
count
Identifies the number of bytes of mapped memory.
MemoryHandler
Points to the VDD handler for the memory address range.

Return Value

VDDInstallMemoryHook returns TRUE if successful. Otherwise, it returns FALSE and logs one of the following errors:

Value | Meaning
ERROR_ACCESS_DENIED | One of the requested ports is already hooked.
ERROR_OUTOFMEMORY | There are insufficient resources.

Comments

The first VDD to hook an address will get control of the memory. There is no chaining of hooks. A VDD should grab the memory during its initialization routine. After all VDDs are loaded, the EMM component will use all remaining memory ranges for UMB support.

Installing a hook on a memory range results in the consumption of memory based on page boundaries. The pStart is rounded down. count is rounded up to the next page boundary. The VDD's memory hook handler is called for all addresses within the page(s) used. The page(s) are set aside as mapped reserved sections, and will no longer be available for use by the Win32 VDM component or other VDDs. The VDD is permitted to manipulate the memory (commit, free, etc.). Only one VDD is allowed to have memory hooks in a particular page.

The VDD's memory handler will be called with the address of any page fault and with a flag identifying whether the fault was caused by a read or write operation.

On return from the VDD hook handler, the system will assume that the page fault was handled and returns control to the VDM component.

After calling the VDD's MemoryHandler, VDM returns to the faulting cs:ip in the 16-bit application. If the VDD doesn't need this, it can adjust the cs:ip using the setCS and setIP functions.

See Also

VDDDeinstallMemoryHook


VDDInstallIOHook

VDDInstallIOHook hooks the I/O Ports for the responsible VDD.

BOOL
  VDDInstallIOHook(
    IN HANDLE  hVdd,
    IN WORD  cPortRange,
    IN PVDD_IO_PORTRANGE  pPortRange,
    IN PVDD_IO_HANDLERS  10handler
    );

Parameters

hVdd
Identifies the VDD.
cPortRange
Specifies the number of VDD_IO_PORTRANGE structures.
pPortRange
Points to the VDD_IO_PORTRANGE array.
10handler
Points to the handler array pointer.

Return Value

VDDInstallIOHook returns TRUE if successful. Otherwise, this function returns FALSE and logs one of the following errors:

Value | Meaning
ERROR_ACCESS_EXISTS | The VDD already has active I/O port handlers.
ERROR_OUTOFMEMORY | There are insufficient resources for additional VDD port handler sets.
ERROR_INVALID_ADDRESS | One of the I/O port handlers has an invalid address.

Comments

The last VDD to hook a port will always get control of the port. There is no concept of chaining hooks.

plOFn must provide the byte read and write handlers. Others can be NULL.

If word or string handlers are not provided, their effect will be emulated using byte handlers.

VDDs must not hook DMA ports. The Win32 VDM component manages this for all the clients and services provided to perform DMA operations. This includes any attempt to access and modify DMA data.

VDDs should not hook video ports. A video port can be successfully hooked but there is no guarantee that the I/O handler will get called.

Each VDD is allowed to install only one set of I/O hooks at a time.

See Also

VDDDeInstalllOHook


VDDInstallUserHook

VDDInstallUserHook hooks callback events. These callback events include PDB (DOS process) creation, PDB termination, VDM block and VDM resume.

BOOL
  VDDInstallUserHook(
    IN HANDLE  hVDD,
    IN PFNVDD_UCREATE  Ucr_Handler,
    IN PFNVDD_UTERMINATE  Uterm_handler,
    IN PFNVDD_UBLOCK  Ublock_handler,
    IN PFNVDD_URESUME  Uresume_handler
    );

Parameters

hVDD
Identifies the VDD.
Ucr_Handler
Function which will be called on PDB creation (optional). Entry: 16-bit DOS PDB; exit: none.
Uterm_handler
Function which will be called on PDB termination (optional). Entry: 16-bit DOS PDB; exit:none.
Ublock_handler
Function which will be called when NTVDM is blocked (optional).
Uresume_handler
Function which will be called with NTVDM resumes (optional).

Return Value

VDDInstallUserHook returns TRUE if successful. GetLastError (see the Win32 SDK) has extended error information.

Comments

The VDD can provide whatever event hook it may choose. Not providing a handler has no effect.

See Also

VDDDeInstallUserHook


VDDQueryDMA

VDDQueryDMA provides DMA data.

BOOL
  VDDQueryDMA(
    IN HANDLE  hVdd,
    IN WORD  iChannel,
    IN PVDD_DMA_INFO  pDmaInfo
    );

Parameters

hVdd
Identifies the VDD.
iChannel
Specifies the DMA channel to query.
pDmaInfo
Specifies the buffer location where information will be returned.

Return Value

The VDDQueryDMA function returns TRUE if successful. If the function fails then FALSE is returned and an error is logged. The extended error code is ERROR_INVALID_ADDRESS which identifies an invalid channel.

Comments

This function will assist VDDs which are doing performance critical work. Such a VDD does its own DMA transfers and avoids an extra buffer copy, which is the overhead of using VDDRequestDMA.

VDDs must call VDDSetDMA to update the state of the virtual DMA controller after completing an operation.

See Also

VDDRequestDMA, VDDSetDMA


VDDRequestDMA

VDDRequestDMA requests a DMA transfer from a VDD.

DWORD
  VDDRequestDMA(
    IN HANDLE  hVDD,
    WORD  iChannel,
    PVOID  Buffer,
    DWORD  length
    );

Parameters

hVDD
Identifies the VDD.
iChannel
Specifies the DMA channel for the transfer operation.
Buffer
Points to the buffer to or from which the data is transferred.
length
Specifies the size in bytes of the transfer count. If length is 0, the current transfer count is returned.

Return Value

VDDRequestDMA returns the number of bytes transferred. If zero is returned and GetLastError (see the Win32 SDK) is set, then the operation failed. If zero is returned and GetLastError is clear, then the DMA transfer count was zero.

The extended error code is ERROR_INVALID_ADDRESS which identifies an invalid channel.

Comments

VDDs that need to carry out DMA operations but that do not need to deal with all DMA registers should call this function.

Using this function is slower than using VDDQueryDMA and VDDSetDMA.

See Also

VDDQueryDMA, VDDSetDMA


VDDSetDMA

VDDSetDMA resets the state of the virtual DMA controller after a DMA operation using VDDQueryDMA.

BOOL
  VDDSetDMA(
    IN HANDLE  hVdd,
    IN WORD  iChannel,
    IN WORD  fDMA,
    IN PVDD_DMA_INFO  Buffer
    );

Parameters

hVdd
Identifies the VDD.
iChannel
Specifies the DMA Channel to set.
fDMA
Provides bitmask indicating what must be set:

VDD_DMA_ADDR
VDD_DMA_COUNT
VDD_DMA_PAGE
VDD_DMA_STATUS
VDD_DMA_ALL (All of the above)

Buffer
Specifies the buffer location of the DMA data.

Return Value

VDDSetDMA returns TRUE if successful. If the function fails then FALSE is returned. The error logged is ERROR_INVALID_ADDRESS to identify an invalid channel.

See Also

VDDRequestDMA, VDDQueryDMA


VDDSimulate16

VDDSimulate16 is similar to VDDSimulateInterrupt except that it does not require a hardware interrupt to be supported by the 16-bit stub device driver. VDDSimulate16 allows a VDD to execute a routine in its 16-bit driver and return when it has finished. Before calling VDDSimulate16, a VDD should preserve at least CS and IP, as well as any other 16-bit registers which its 16-bit routine might destroy. This simulation is synchronous.

VOID
  VDDSimulate16(
    );

See Also

VDDUnSimulate16


VDDSimulateInterrupt

VDDSimulateInterrupt simulates an interrupt to the VDM to support applications that expect an interrupt to signal the end of an operation.

VOID
  VDDSimulateInterrupt(
    IN INT  ms,
    IN BYTE  line,
    IN INT  count
    );

Parameters

ms
Is either ICA_MASTER or ICA_SLAVE, as appropriate.
line
Specifies the interrupt line.
count
Allows a set of interrupts to be delivered. Normally there is only one interrupt.


VDDTerminateVDM

VDDTerminateVDM terminates the VDM in which the DOS application is running.

VOID
  VDDTerminateVDM(
    ;)

Comments

The VDD must call this function if it encounters an error that results in an inconsistent VDD state.

The VDD can call MessageBox (see the Win32 SDK) to produce a popup window before terminating the application.


VDDUnSimulate16

VDDUnSimulate16 causes the simulation in Intel instructions to stop, and control to return to the VDD. This routine is a macro intended for 16-bit stub drivers. A driver should use it at the end of its worker routine.

VOID
  VDDUnSimulate16(
    );

See Also

VDDSimulate16


VdmFlushCache

VdmFlushCache flushes any data associated with a given VDM memory range that a CPU emulator might have cached.

BOOL
  VdmFlushCache(
    IN USHORT  Segment,
    IN ULONG  Offset,
    IN ULONG  Size,
    IN VDM_MODE  Mode
    );

Parameters

Segment
The segment or selector, depending on the value of Mode, of the x86 address.
Offset
The offset of the x86 address.
Size
The number of bytes in the range to be flushed, starting at Offset.
Mode
Either VDM_PM or VDM_V86.

Return Value

VdmFlushCache returns TRUE if the given range was successfully flushed.

Comments

VDDs should use this function to ensure that a RISC-based CPU emulator gets a chance to flush any data associated with a memory range. In particular, such a RISC-based CPU emulator will typically cache portions of 16-bit code in a "native instruction cache" to improve performance. If a VDD modifies a piece of code without calling VdmFlushCache, it is possible that the emulator will execute the cached original instructions instead of such a VDM-modified instruction stream. Thus, failure to call VdmFlushCache can cause unpredictable operation of the VDM in which such a VDD is running on RISC-based platforms and inconsistent operation of the VDD between CISC-based and RISC-based platforms.

On x86-based platforms, a call to VdmFlushCache is a NOOP because a VDD's 16-bit code executes in the CPU. Nonetheless, all VDDs that modify an instruction stream should call VdmFlushCache at appropriate locations in their code to ensure their portability across RISC-based and CISC-based platforms.

See Also

VdmMapFlat, VdmUnmapFlat


VdmMapFlat

VdmMapFlat returns a linear address for a given x86 address.

PVOID
  VdmMapFlat(
    IN WORD  Segment,
    IN ULONG  Offset,
    IN VDM_MODE  Mode
    );

Parameters

Segment
The segment or selector, depending on the value of Mode, of the x86 address.
Offset
The 32-bit or 16-bit offset of the x86 address.
Mode
Either VDM_PM or VDM_V86.

Return Value

VdmMapFlat returns the linear address.

Comments

VDDs call this function to form a pointer to an x86 "client" memory range for the VDM. Note that such a memory range must not be based at zero in the process, so use of VdmMapFlat makes the VDD platform independent.

If the VDD modifies code within such a range, it should call VdmFlushCache first to ensure cross-platform independence and consistency of operation.

See Also

VdmFlushCache, VdmUnmapFlat


VdmUnmapFlat

VdmUnmapFlat releases a mapping returned by VdmMapFlat.

BOOL
  VdmUnmapFlat(
    IN USHORT  Segment,
    IN ULONG  Offset,
    IN PVOID  Buffer,
    IN VDM_MODE  Mode
    );

Parameters

Segment
The segment or selector, depending on the value of Mode, of the x86 address.
Offset
The offset of the x86 address.
Buffer
The linear address returned by VdmMapFlat.
Mode
Either VDM_PM or VDM_V86.

Return Value

VdmUnmapFlat returns TRUE if the given mapping was released.

Comments

VdmUnmapFlat releases a linear address mapping obtained in a previous call to VdmMapFlat.

After calling VdmMapFlat, a VDD should call VdmUnmapFlat when such a returned linear pointer is no longer needed.

See Also

VdmFlushCache, VdmMapFlat


WOW32DriverCallback

WOW32DriverCallback allows a 32-bit thunk extension DLL to simulate a Multimedia hardware interrupt callback into 16-bit code. The built-in thunks for wave, midi, and time callbacks make use of this function to callback into 16-bit application code.

BOOL
  WOW32DriverCallback(
    DWORD  dwCallback,
    DWORD  dwFlags,
    WORD  wDeviceHandle,
    WORD  wMsg,
    DWORD  dwUser,
    DWORD  dwParam1,
    DWORD  dwParam2
    );

Parameters

dwCallback
Specifies either the address of a callback function, a window handle, or a task handle, depending on the flags specified in dwFlags.
dwFlags
Specifies how the 16-bit client application is notified, according to one of the following flags:
Flag | Meaning
DCB_FUNCTION | Indicates that a message should be sent to a callback function. dwCallback must be a 16-bit address of the 16-bit application callback routine.
DCB_WINDOW | Indicates that a message should be sent to the 16-bit window handle specified in dwCallback.
DCB_TASK | Indicates that a message should be sent ot the 16-bit task handle specified in dwCallback.

wDeviceHandle
Specifies a 16-bit handle of the device associated with the notification.
wMsg
Specifies a message to be sent to the application.
dwUser
Specifies the DWORD of user-instance data supplied by the application when the device was opened.
dwParam1
Specifies a message-dependent parameter. If this is a pointer, it must be mapped to a valid 16-bit address. All fields in the structure pointed to must be mapped correctly.
dwParam2
Specifies a message-dependent parameter. If this is a pointer, it must be mapped to a valid 16-bit address. All fields in the structure pointed to must be mapped correctly.

Return Value

WOW32DriverCallback returns TRUE if the operation was successful.

Comments

The 16-bit client specifies how it is notified when the device is opened. If notification is accomplished with a callback function, wDeviceHandle, wMsg, dwUser, dwParam1, and dwParam2 are passed to the callback. If notification is accomplished by means of a window, only wMsg, wDeviceHandle, and dwParam1 are passed.

Users will have to dynamically link to this function.

See Also

WOW32ResolveHandle


WOW32ResolveHandle

WOW32ResolveHandle allows a 32-bit thunk extension DLL to map 16-bit handles to valid 32-bit handles and vice-versa.

BOOL
  WOW32ResolveHandle(
    UINT  uHandleType,
    UINT  uMappingDirection,
    WORD  wHandle16_In,
    LPWORD  lpwHandle16_Out,
    DWORD  dwHandle32_In,
    LPDWORD  lpdwHandle32_Out
    );

Parameters

uHandleType
Specifies a generic user handle (WOW32_USER_HANDLE), generic GDI handle (WOW32_GDI_HANDLE), or multimedia handles (WAVEIN_HANDLE, WAVEOUT_HANDLE, MIDIOUT_HANDLE, or MIDIIN_HANDLE).
uMappingDirection
Specifies the handle mapping direction. Can be either WOW32_DIR_16IN_32OUT or WOW32_DIR_32IN_16OUT.
wHandle16_In
Specifies a 16-bit input handle which is ignored if uMappingDirection is WOW32_DIR_32IN_16OUT.
lpwHandle16_Out
Specifies a 16-bit output handle which is ignored if uMappingDirection is WOW32_DIR_16IN_32OUT.
dwHandle32_In
Specifies a 32-bit input handle which is ignored if uMappingDirection is WOW32_DIR_16IN_32OUT.
lpdwHandle32_Out
Specifies a 32-bit output handle which is ignored if uMappingDirection is WOW32_DIR_32IN_16OUT.

Return Value

WOW32ResolveHandle returns FALSE if a known error occurred in the mapping. A return value of TRUE indicates that the mapping was successful but does not mean that the mapped handle is valid. For example, it may be possible to map an invalid 16-bit handle to an invalid 32-bit handle.

Comments

Users will have to dynamically link this function.

See Also

WOW32DriverCallback


VDD Structures

The topics that follow describe the structures associated with Virtual Device Drivers.


VDD_DMA_INFO

VDD_DMA_INFO contains DMA information.

typedef struct _VDD_DMA_INFO {
  WORD  addr;
  WORD  count;
  WORD  page;
  BYTE  status;
  BYTE  mode;
  BYTE  mask;
} VDD_DMA_INFO, *PVDD_DMA_INFO;

Members

addr
The DMA physical address.
count
The DMA count.
page
The page identifier.
status
A numeric representation of the status.
mode
A numeric representation of the mode.
mask
The binary value used to screen out certain bits in the data value.


VDD_IO_HANDLERS

VDD_IO_HANDLERS defines an array of handlers for the VDD I/O hooks.

typedef struct _VDD_IO_HANDLERS {
  PFNVDD_INB  inb_handler;
  PFNVDD_INW  inw_handler;
  PFNVDD_INSB  insb_handler;
  PFNVDD_INSW  insw_handler;
  PFNVDD_OUTB  outb_handler;
  PFNVDD_OUTW  outw_handler;
  PFNVDD_OUTSB  outsb_handler;
  PFNVDD_OUTSW  outsw_handler;
} VDD_IO_HANDLERS, *PVDD_IO_HANDLERS

Members

inb_handler
A pointer to the VDD-provided function to simulate INB instruction. This handler is mandatory.
inw_handler
A pointer to the VDD-provided function to simulate INW instruction. This handler is optional; the system will simulate this function by using the provided INB handler.
insb_handler
A pointer to the VDD-provided function to simulate INSB instruction. This handler is optional; the system will simulate this function by using the provided INB handler.
insw_handler
A pointer to the VDD-provided function to simulate INSW instruction. This handler is optional; the system will simulate this function by using the provided INB handler.
outb_handler
A pointer to the VDD-provided function to simulate OUTB instruction. This handler is mandatory.
outw_handler
A pointer to the VDD-provided function to simulate OUTW instruction. This handler is optional; the system will simulate this function by using the provided OUTB handler.
outsb_handler
A pointer to the VDD-provided function to simulate OUTSB instruction. This handler is optional; the system will simulate this function by using the provided OUTB handler.
outsw_handler
A pointer to the VDD-provided function to simulate OUTSW instruction. This handler is optional; the system will simulate this function by using the provided OUTB handler.

Refer also to the following typedef statements.

/** Basic typedefs of VDD IO hooks **/

typedef VOID (*PFNVDD_INB)   (WORD iport,BYTE * data);
typedef VOID (*PFNVDD_INW)   (WORD iport,WORD * data);
typedef VOID (*PFNVDD_INSB)  (WORD iport,BYTE * data,WORD count);
typedef VOID (*PFNVDD_INSW)  (WORD iport,WORD * data,WORD count);
typedef VOID (*PFNVDD_OUTB)  (WORD iport,BYTE data);
typedef VOID (*PFNVDD_OUTW)  (WORD iport,WORD data);
typedef VOID (*PFNVDD_OUTSB) (WORD iport,BYTE * data,WORD count);
typedef VOID (*PFNVDD_OUTSW) (WORD iport,WORD * data,WORD count);


VDD_IO_PORTRANGE

VDD_IO_PORTRANGE defines the beginning and ending point of the dedicated port memory.

typedef struct _VDD_IO_PORTRANGE {
  WORD  First;
  WORD  Last;
} VDD_IO_PORTRANGE, *PVDD_IO_PORTRANGE;

Members

First
The beginning address of the dedicated port memory range.
Last
The ending address of the dedicate port memory range.


System-Supplied IDE Drivers

This section describes the architecture of the integrated drive electronics (IDE) driver and device object stacks, and the system-supplied drivers that they contain.

This section includes:

IDE Driver Stack

IDE Device Object Stack

For a discussion of vendor-supplied IDE drivers, see Vendor-Supplied IDE Drivers


IDE Driver Stack

Microsoft provides a complete integrated drive electronics (IDE) driver stack that is capable of driving most IDE controllers. There are three system-supplied IDE drivers in the IDE driver stack: atapi.sys (port driver), pciidex.sys (controller driver), and pciide.sys (generic controller minidriver). All three drivers are described in the figure that follows.

Note that the driver model for IDE devices changed in Microsoft® Windows® 2000. In Microsoft Windows NT® 4.0, the port driver, atapi.sys, was a SCSI miniport driver that linked to scsiport.sys. In Windows 2000 and later operating systems, the IDE port driver atapi.sys became an independent driver that no longer links to scsiport.sys, nor to any other wrapper driver. In the IDE driver model for Windows 2000 and later operating systems, the controller driver that is below the port driver in the driver stack is split into a controller driver and a controller minidriver. See the description of these drivers that accompanies the following figure.

The following figure illustrates the IDE driver stack.

IDE Driver Stack

Starting from the bottom of the figure, the following describes each driver in the IDE stack:

  1. The IDE stack in Windows 2000 and later is layered over the PCI bus driver.
  2. Microsoft provides a native IDE controller driver/minidriver pair that is capable of driving most IDE controllers. The IDE controller driver, pciidex.sys, handles the hardware-independent aspects of the driver pair, and the minidriver, pciide.sys, handles the hardware-dependent aspects.
  3. Vendors can elect to provide their own IDE controller minidriver instead of using the native minidriver, pciide.sys. Vendor-supplied minidrivers handle the hardware-specific aspects of the vendor's minidriver. The vendor's minidriver must work together with the Microsoft-supplied controller driver to form a controller-minidriver pair. See Requirements for Vendor-Supplied IDE Controller Minidrivers for an explanation of the requirements a vendor's minidriver must fulfill to work properly with the native Microsoft controller driver.
  4. Microsoft provides an IDE port driver, atapi.sys (also known as the channel driver, since it creates and manages a functional device object (FDO) for each IDE channel). The port driver is layered above the IDE controller / minidriver pair. It translates the SCSI request blocks (SRB) that it receives from the storage class driver into the format required by the underlying IDE controller. In particular, the command descriptor blocks (CDB) contained within an SRB are defined differently for ATAPI and SCSI-2 devices. The port driver repackages CDBs to make them compatible with the ATAPI transport protocol, thereby insulating upper level drivers from peculiarities of the IDE bus.


IDE Device Object Stack

To see a diagram of the device object stack corresponding to the driver stack in the IDE Driver Stack section, see Device Object Example for a PCI IDE Controller.


Vendor-Supplied IDE Drivers

The following sections discuss the guidelines for the development and installation of vendor-supplied IDE controller minidrivers:

Requirements for Vendor-Supplied IDE Controller Minidrivers

Initializing and Calling IDE Minidriver Callback Routines

Installing IDE Controller Minidrivers

Sample IDE Controller Minidrivers


Requirements for Vendor-Supplied IDE Controller Minidrivers

This section describes Microsoft® Windows® requirements for vendor-supplied IDE controller minidrivers.

The Microsoft-supplied IDE port driver, atapi.sys, and controller driver, pciidex.sys, are hardware-independent and can be used with almost all IDE controllers. Thus, vendor-supplied port drivers and controller drivers are not required.

Microsoft also supplies a native controller minidriver, pciide.sys, which handles the hardware-dependent aspects of the controller driver-minidriver pair and which can be used with most IDE controller hardware. Vendors can elect to supply their own controller minidriver instead of using pciide.sys.

A vendor-supplied controller minidriver does not need to support Plug and Play (PnP) or power management. PnP and power management operations are handled by the Microsoft-supplied controller driver, pciidex.sys.

A vendor-supplied controller minidriver does not need to register any particular interface in order to comply with system requirements.

A vendor-supplied controller minidriver should not attempt to access the registry, nor should it call kernel-mode routines other than those provided by the PciIdeX library. See Initializing and Calling IDE Minidriver Callback Routines for a discussion of the PciIdeX library.

A vendor-supplied controller minidriver must provide a set of standard callback routines that permit the system-supplied controller driver to do hardware-dependent operations transparently.

The Initializing and Calling IDE Minidriver Callback Routines section describes the callback routine interface between the system-supplied controller driver and a vendor-supplied controller minidriver.


Initializing and Calling IDE Minidriver Callback Routines

All IDE controller drivers must include a series of callback routines that implement hardware-specific functionality for IDE controller minidrivers. The diagram that follows illustrates how an IDE controller minidriver makes its callback routines available to the controller driver. Note that the PciIdeX library, though conceptually separate from the IDE controller driver as illustrated in the figure that follows, is contained within the controller driver's executable file, pciidex.sys. When a minidriver calls a PciIdeX library routine, it is in fact calling a routine within the controller driver.

Program Flow for Callback Routine Initialization

  1. The PnP Manager loads the IDE controller driver-minidriver, then calls its DriverEntry routine passing it a pointer to the driver object for the controller driver.
  2. The minidriver's DriverEntry calls the PciIdeXInitialize library routine, passing it a pointer to the minidriver's GetControllerProperties routine.
  3. PciIdeXInitialize stores the pointer to GetControllerProperties in the driver object.
  4. PnP Manager dispatches an IRP_MN_START_DEVICE request to the IDE controller driver to start the controller. The IDE controller driver receives the request and calls its StartDevice routine.
  5. StartDevice retrieves pointers to GetControllerProperties and to the controller's functional device object (FDO) extension, both of which are stored in the driver object.
  6. StartDevice calls GetControllerProperties, passing it a pointer to the controller's FDO extension.
  7. GetControllerProperties loads pointers for all of minidriver's callback routines into the controller driver's FDO extension.

Once the FDO extension is populated with function pointers that point to the minidriver's callback routines, the controller driver will be able to call any one of these callback routines by retrieving the appropriate function pointer from the FDO extension.


Installing IDE Controller Minidrivers

This section provides installation information, specific to IDE controller drivers and controller minidrivers in Microsoft® Windows® 2000 and later operating systems.

Vendors supplying their own controller minidriver should make that driver a member of the Hard Disk Controllers (HDC) setup class in the INF Version section of the driver's INF file. For example:

[version]
Signature="$WINDOWS NT$"
Class=hdc
ClassGuid={4D36E96A-E325-11CE-BFC1-08002BE10318}

There are no other special requirements associated with installing IDE controller minidrivers.

For more installation information, including a list of controller hardware supported in Windows 2000 and later operating systems, see the system-supplied INF file for hard disk controllers, mshdc.inf.

For general information on device installation in Windows 2000 and later operating systems, see:

Requirements for Vendor-Supplied IDE Controller Minidrivers

Device Installation Overview


Sample IDE Controller Minidrivers

This section identifies the sample IDE controller minidriver included with the Microsoft® Windows® DDK.

The Windows DDK includes the source code for the pciide.sys generic controller minidriver. See the sample code in the \src\storage directory of the Windows DDK.

This sample is 64-bit compliant. It builds with Microsoft Visual C® 6.0 and does not implement Plug and Play or Power Management.

The pciide.sys sample is binary compatible between Windows 95/98/Me and NT-based versions of the operating system, provided no Windows 95/98/Me VxDCalls nor any NT-based system calls are embedded in the minidriver.


IDE Controller Library and Minidriver Routines

All integrated drive electronics (IDE) controller drivers must implement a series of callback routines that implement hardware-specific functionality for IDE controller minidrivers. Microsoft supplies the PciIdeX library (pciidex.lib) to facilitate the development of these callbacks in a platform-independent manner. The following two sections describe the PciIdeX library API and list the callbacks that the controller minidriver requires:

PciIdeX Library Routines

IDE Controller Minidriver Routines


PciIdeX Library Routines

Microsoft supplies platform-specific PciIde Xxx library routines to support platform-independent IDE controller minidrivers.

The PciIde Xxx routines constitute a kernel-mode dynamic-link library. References for the PciIde Xxx routines are in alphabetical order.


PciIdeXInitialize

The PciIdeXInitialize routine initializes a controller minidriver.

NTSTATUS
  PciIdeXInitialize(
    IN PDRIVER_OBJECT  DriverObject,
    IN PUNICODE_STRING  RegistryPath,
    IN PCONTROLLER_PROPERTIES  HwGetControllerProperties,
    IN ULONG  ExtensionSize
    );

Parameters

DriverObject
Pointer to the controller minidriver's driver object.
RegistryPath
Unicode string that indicates the location in the registry where the minidriver's configuration information is stored.
HwGetControllerProperties
Pointer to a controller minidriver callback routine that queries for the PCI IDE controller properties.
ExtensionSize
Specifies the size in bytes of the driver extension.

Return Value

PciIdeXInitialize returns STATUS_SUCCESS if the allocation of the driver extension succeeds, and the appropriate error code otherwise.

Comments

An IDE controller minidriver must call PciIdeXInitialize from the DriverEntry routine, in order to initialize the driver's dispatch tables and DriverObject extension. PciIdeXInitialize initializes the controller minidriver's dispatch tables and allocates an extension for the DriverObject. This routine then stores the ExtensionSize and a pointer to the HwGetControllerProperties routine in the DriverObject extension.

An IDE controller minidriver must also implement a callback routine that reports the properties of the IDE controller. A pointer to this routine is passed to PciIdeXInitialize in its HwGetControllerProperties parameter.

See Also

IDE_CONTROLLER_PROPERTIES, HwIdeXGetControllerProperties


PciIdeXGetBusData

The PciIdeXGetBusData routine retrieves data from the location specified by ConfigDataOffset within the PCI configuration space. PcildeXGetBusData stores the retrieved data in Buffer.

NTSTATUS
  PciIdeXGetBusData(
    IN PVOID  DeviceExtension,
    IN PVOID  Buffer,
    IN ULONG  ConfigDataOffset,
    IN ULONG  BufferLength
    );

Parameters

DeviceExtension
Pointer to the device extension of the IDE controller.
Buffer
Pointer to the buffer in which data from the PCI bus configuration data space is returned.
ConfigDataOffset
Specifies an offset into the PCI configuration data space where the data to be returned can be found.
BufferLength
Specifies the length in bytes of the buffer.

Return Value

PciIdeXGetBusData returns STATUS_SUCCESS if the data was successfully retrieved from the PCI configuration space or STATUS_UNSUCCESSFUL if the data could not be retrieved.

See Also

PciIdeXInitialize, PciIdeXSetBusData


PciIdeXSetBusData

The PciIdeXSetBusData routine stores data in Buffer at an offset specified in ConfigDataOffset within the PCI configuration space.

NTSTATUS
  PciIdeXSetBusData(
    IN PVOID  DeviceExtension,
    IN PVOID  Buffer,
    IN PVOID  DataMask,
    IN ULONG  ConfigDataOffset,
    IN ULONG  BufferLength
    );

Parameters

DeviceExtension
Pointer to the device extension of the IDE controller.
Buffer
Pointer to the buffer in which data from the PCI bus configuration data space is written.
DataMask
Contains a data mask buffer that controls which bits of PCI bus configuration data are to be updated by PciIdeXSetBusData.

The length of Datamask must be the same as the length of Buffer.

ConfigDataOffset
Specifies an offset into the PCI configuration data space where the data to be updated can be found.
BufferLength
Specifies the length in bytes of the buffer.

Return Value

PciIdeXSetBusData returns STATUS_SUCCESS if the data in the PCI configuration space was successfully updated and STATUS_UNSUCCESSFUL data in the PCI configuration space could not be updated.

Comments

PciIdeXSetBusData replaces each byte of current PCI data, beginning with the byte indicated by ConfigDataOffest, with the new data contained in Buffer. For each byte, those bits not indicated by the DataMask are left untouched. The ith byte of data that follows ConfigDataOffset, therefore, is updated as follows:

ConfigDataOffest[i] =
(ConfigDataOffest[i] & ~DataMask[i]) | (DataMask[i] & Buffer[i])

PciIdeXSetBusData completes a bitwise OR, one byte at a time, of the current PCI configuration space data with the new data in Buffer. For each byte, only the bits indicated by DataMask are updated. PciIdeXSetBusData then stores the result of the logical OR in the PCI configuration space.

See Also

PciIdeXInitialize, PciIdeXGetBusData


IDE Controller Minidriver Routines

This section describes the callback routines that must be supplied by an IDE controller minidriver.

A IDE controller minidriver's HwIdeXxx routines can have any name chosen by the driver writer. DriverEntry is a required name.


DriverEntry of IDE Controller Minidriver

DriverEntry initializes the minidriver.

NTSTATUS
  DriverEntry(
    IN PDRIVER_OBJECT  DriverObject,
    IN PUNICODE_STRING  RegistryPath
    );

Parameters

DriverObject
Pointer to the IDE controller minidriver's driver object.
RegistryPath
Specifies a string indicating the registry path to the driver's configuration information in the registry.

Return Value

DriverEntry returns STATUS_SUCCESS if successful; otherwise it returns the error code received from the PciIdeXInitialize library routine.

Comments

Each controller minidriver must have a routine named DriverEntry in order to load.

An IDE controller minidriver's DriverEntry routine must call the PciIdeXInitialize library routine. PcildeXInitialize initializes the controller minidriver's dispatch tables, allocates an extension for the DriverObject, and stores various values in the driver object's extension. Values that must be stored in the driver object's extension include the size of the driver extension and a pointer to a controller minidriver HwIdeXGetControllerProperties callback routine that retrieves information about the IDE controller.

See Also

HwIdeXGetControllerProperties, IDE_CONTROLLER_PROPERTIES, PciIdeXInitialize


HwIdeXChannelEnabled

The HwIdeXChannelEnabled routine is called to determine whether Channel is enabled.

IDE_CHANNEL_STATE
  HwIdeXChannelEnabled(
    IN PVOID  DeviceExtension,
    IN ULONG  Channel
    );

Parameters

DeviceExtension
Pointer to the controller minidriver's device extension.
Channel
Specifies which channel is being queried. This parameter must be assigned a value of 0 or 1.

Return Value

HwIdeXChannelEnabled must return one of three enumeration values of type IDE_CHANNEL_STATE:

ChannelDisabled
ChannelEnabled
ChannelStateUnknown

Comments

An IDE controller minidriver must implement an HwIdeXChannelEnabled callback to report whether the specified channel is enabled or not. HwIdeXChannelEnabled retrieves the needed information from the PCI configuration space by calling the minidriver library routine PciIdeXGetBusData.

See Also

PciIdeXGetBusData


HwIdeXGetControllerProperties

The HwIdeXGetControllerProperties routine reports properties of the IDE controller hardware in the IDE_CONTROLLER_PROPERTIES structure.

NTSTATUS
  HwIdeXGetControllerProperties(
    IN PVOID  DeviceExtension,
    IN PIDE_CONTROLLER_PROPERTIES  ControllerProperties
    );

Parameters

DeviceExtension
Pointer to the controller minidriver's device extension.
ControllerProperties
Specifies various properties of the IDE controller (see IDE_CONTROLLER_PROPERTIES).

Return Value

If HwIdeXGetControllerProperties returns STATUS_SUCCESS if the controller information was successfully retrieved or STATUS_REVISION_MISMATCH if the Size member of the ControllerProperties structure does not have the expected value of sizeof(IDE_CONTROLLER_PROPERTIES). This probably indicates that the structure passed to HwIdeXGetControllerProperties in the ControllerProperties parameter is not suitable for the current version of the OS/PCI IDE controller driver

Comments

HwIdeXGetControllerProperties examines the controller's configuration data to determine what transfer modes it supports. HwldeXGetControllerProperties then returns the transfer mode information, along with pointers to the controller minidriver's callback routines and the values of various flags, in the IDE_CONTROLLER_PROPERTIES structure.

See Also

IDE_CONTROLLER_PROPERTIES, PciIdeXGetBusData, PciIdeXInitialize


HwIdeXSyncAccessRequired

The HwIdeXSyncAccessRequired routine indicates whether both channels of its controller can be accessed at once.

BOOLEAN
  HwIdeXSyncAccessRequired(
    IN PVOID  DeviceExtension
    );

Parameters

DeviceExtension
Pointer to the IDE controller minidriver's device extension.

Return Value

HwIdeXSyncAccessRequired returns TRUE if the controller only allows one channel to be accessed at a time; otherwise it returns FALSE.

Comments

HwIdeXSyncAccessRequired determines whether both channels of its controller can be accessed at once by comparing the controller's Vendor ID and Device ID with a list of the Vendor ID and Device ID of IDE controllers that are known to be Single FIFO controllers. The Vendor ID and Device ID of the IDE controller is obtained by consulting the PCI configuration data stored in DeviceExtension.

See Also

PciIdeXGetBusData


HwIdeXTransferModeSelect

The HwIdeTransferModeSelect routine returns the best PIO mode and the best DMA mode for each device indicated in XferMode.

NTSTATUS
  HwIdeXTransferModeSelect(
    IN PVOID  DeviceExtension,
    IN PPCIIDE_TRANSFER_MODE_SELECT  XferMode
    );

Parameters

DeviceExtension
Pointer to the IDE controller minidriver's device extension.
XferMode
Pointer to a PCIIDE_TRANSFER_MODE_SELECT structure supplied by the caller that is used to furnish the IDE controller minidriver with device information and to report which transfer modes the minidriver selects for each device.

Return Value

HwIdeXChannelTransferMode returns STATUS_SUCCESS if the transfer mode data is successfully retrieved; otherwise, returns STATUS_UNSUCCESSFUL.

Comments

HwIdeTransferModeSelect queries the IDE controller minidriver to determine what the best available PIO and DMA modes are for each device in a list of devices furnished in the XferMode structure. It determines this by considering both the characteristics of each device as specified in XferMode and the hardware characteristics of the IDE controller itself. The calling routine must provide the relevant device characteristics, such as the device's best PIO, best single-word DMA, best multiword DMA, and best ultra DMA cycle times, in XferMode

For a detailed summary of the information required by HwIdeTransferModeSelect, see PCIIDE_TRANSFER_MODE_SELECT.

See Also

PCIIDE_TRANSFER_MODE_SELECT


HwIdeXUdmaModesSupported

The HwIdeXUdmaModeSupported routine indicates which ultra direct memory access (UDMA) transfer mode is current and which is best for the device indicated by IdentifyData.

BOOLEAN
  HwIdeXUdmaModesSupported(
    IN  IDENTIFY_DATA  IdentifyData,
    OUT PULONG  BestXferMode,
    OUT PULONG      CurrentXferMode
    );

Parameters

IdentifyData
Specifies a structure containing the identify device information defined in the ATA/ATAPI-5 specification. Minidrivers retrieve this data in the PCIIDE_TRANSFER_MODE_SELECT structure with a call to HwIdeXTransferModeSelect. For further information on the contents of this structure, see the ATA/ATAPI-5 specification.
BestXferMode
The highest UDMA mode supported by this device.
CurrentXferMode
The currently active UDMA mode on this device.

Return Value

HwIdeXUdmaModesSupported returns STATUS_SUCCESS if the operation was a success; otherwise, it returns STATUS_UNSUCCESSFUL.

Comments

HwIdeXUdmaModesSupported interprets the identify data for a device and determines both the currently active UDMA mode and the best possible UDMA mode supported by the device. For example, if UDMA mode four is the best transfer mode that the device supports and UDMA mode two is the currently active UDMA mode, the routine should return BestXferMode = 4 and CurrentXferMode = 2.

This routine makes IDE controller drivers more extensible. If a new UDMA mode is added to the ATA/ATAPI specification, you need only to change this routine to interpret the new information in the identify data.

See Also

PCIIDE_TRANSFER_MODE_SELECT, HwIdeXTransferModeSelect


HwIdeXUseDma

The IDE controller driver calls the minidriver callback routine HwIdeXUseDma prior to an I/O operation, in order to determine whether I/O can be done by means of DMA.

NTSTATUS
  HwIdeXUseDma(
    IN PVOID  DeviceExtension,
    IN PUCHAR  CdbCommand,
    IN PUCHAR  Slave
    );

Parameters

DeviceExtension
Pointer to the IDE controller minidriver's device extension.
CdbCommand
Pointer to a control data block (CDB) structure containing the I/O operation to be requested.
Slave
Specifies whether the IDE device is a secondary (slave) or a primary (master) device. This parameter must be set to one (1) if the device is a slave and to zero (0) if the device is a master.

Return Value

HwIdeXUseDma returns one (1) if DMA is allowed and zero (0) if DMA is not allowed.

Comments

HwIdeXUseDma determines whether DMA is appropriate, based on the sort of command indicated in CdbCommand and the type of IDE controller chipset that the minidriver manages.

If HwIdeXUseDma returns zero, the controller driver must complete the data transfer in PIO mode instead of DMA mode.


The IEEE 1394 Driver Stack

A driver for a device that connects to the IEEE 1394 bus sits on top of the IEEE 1394 driver stack. The driver communicates to the device by sending IRPs to the IEEE 1394 bus driver, which the operating system provides as 1394bus.sys. The bus driver provides a hardware-independent interface to the IEEE 1394 bus. The bus driver handles some IRPs, and some it forwards to the port driver for the motherboard's host controller. Microsoft provides a standard port driver for host controllers that satisfy the Open Host Controller Interface specification, ohci1394.sys.

IEEE 1394 Device Stack.

To issue commands to devices connected to the bus, drivers issue the IRP_MJ_DEVICE_CONTROL IRP, with control code IOCTL_1394_CLASS. The driver packages the parameters in an IEEE 1394 Request Block (IRB), and passes a pointer to it in the Parameters.Others.Argument1 member of the IRP. The FunctionNumber member of the IRB determines the type of operation, and the u member describes the operation. The bus driver uses the IOCTL_1394_CLASS IRP to present an interface to both the bus and the host controller.

The IRB structure contains both parameters that apply to each bus request, and request-specific parameters. The u member of the IRB contains the request-specific parameters, in a union of data structures, one per request type.

In normal operation, drivers receive ordinary I/O requests, such as IRP_MJ_READ, converts them to the appropriate IEEE 1394 operation, and dispatches that operation to the device through IOCTL_1394_CLASS.


Asynchronous I/O for IEEE 1394 Devices

Devices on the IEEE 1394 bus communicate, in asynchronous mode, by sending and receiving packets. Devices send read, write, and lock requests to specific addresses in another device's address space. To provide quality of service, when the receiving device completes the request, it sends a response packet back to the sending device, which then sends a response acknowledgment.

A driver can communicate to its device by sending asynchronous I/O requests to the device. The driver can also allocate ranges of addresses in the IEEE 1394 address space of the host computer, and receive requests to these addresses. Both are documented below.

Sending Asynchronous I/O Request Packets on the IEEE 1394 Bus

Receiving Asynchronous I/O Request Packets on the IEEE 1394 Bus


Sending Asynchronous I/O Request Packets on the IEEE 1394 Bus

Drivers use REQUEST_ASYNC_READ, REQUEST_ASYNC_WRITE, and REQUEST_ASYNC_LOCK to send asynchronous read, write, and lock operations to a device on the IEEE 1394 bus.

Sending read or write requests

For REQUEST_ASYNC_READ and REQUEST_ASYNC_WRITE, the operation-specific parameters of the IRB are stored in either u.AsyncRead or u.AsyncWrite members of the IRB. Within that, the driver provides an MDL in Mdl. The bus driver uses this buffer to copy the data it reads from the device, or as the source of the data it writes to the device. The driver also specifies the destination IEEE 1394 address in DestinationAddress.

Within both requests, drivers specify both the size of the data buffer, in the nNumberOfBytesToRead or nNumberOfBytesToWrite members of u.AsyncXXX, and the block size, in the nBlockSize member. When the transaction actually takes place, the bus driver breaks up the data into packets of the size specified in nBlockSize. By default, the bus driver reads or writes the data contiguously: each block is read from or written to successive locations in the device's address space.

Contiguous Data Blocks

Optionally, the driver can specify the ASYNC_FLAGS_NONINCREMENTING flag for the request; then the bus driver will use the same set of addresses for each block.

Asynchronous Non-incrementing Data Blocks

Warning: The bus driver enforces the maximum asynchronous packet size for the current connection speed between the device and the computer, and the maximum speed the device reports in the MAX_REC field of its configuration ROM. If nBlockSize is greater than either of these values, the bus driver uses the enforced value for the block size. If the driver sets the ASYNC_FLAGS_NONINCREMENTING flag, this is unlikely to give the desired behavior. If drivers set this flag, they should check that the block size is smaller than the enforced limitations before submitting the request.

Sending lock requests

The IEEE 1394 bus protocol provides asynchronous lock requests, which allow atomic, test-and-set-type operations. In addition to specifying the destination address (in u.AsyncLock.DestinationAddress), the driver specifies the transaction type (in u.AsyncLock.fulTransactionType). The data value and argument value of the operation (see the IEEE 1394 specification for details) are passed in u.AsyncLock.DataValues and u.AsyncLock.Arguments

Bus reset generation

A device driver that uses asynchronous I/O keeps track of the bus reset generation. In each asynchronous request, the device driver reports that value in the u.AsyncXxx.ulGeneration member of the IRB for the request. The bus driver compares that value to the actual generation count, and if they fail to match, it fails the request with a status value of STATUS_INVALID_GENERATION. If a request fails in this manner, the driver should query for the correct generation by using the REQUEST_GET_GENERATION_COUNT bus request. However, the driver should not reissue any request that failed with this status until it retrieves new generation in its Bus Reset Notification callback. This ensures that the device is still present on the bus. Note that client drivers should not depend on IRP_MN_BUS_RESET to be notified of a bus reset. IRP_MN_BUS_RESET is obsolete in Windows XP and later operating systems.


Receiving Asynchronous I/O Request Packets on the IEEE 1394 Bus

The computer itself is a node on the IEEE 1394 bus, and therefore can receive asynchronous I/O requests. Drivers can allocate ranges of addresses in the computer's IEEE 1394 address space, and receive requests from external nodes, by submitting the REQUEST_ALLOCATE_ADDRESS_RANGE request to the bus driver.

When the driver allocates the address range, it can specify which types of transactions a device may send to the allocated addresses, by specifying one or more of ACCESS_FLAGS_TYPE_READ, ACCESS_FLAGS_TYPE_WRITE, or ACCESS_FLAGS_TYPE_LOCK in the u.AllocateAddressRange.fulAccessType member of the request's IRB. Requests not of one of the specified types automatically fail.

Two different drivers may allocate the same address range. By default, the bus driver automatically de-multiplexes the requests, and the driver only sees the requests on the allocated addresses that come from the driver's device. Drivers can request that they receive all packets sent to the addresses by all nodes on the bus, by specifying the ACCESS_FLAGS_TYPE_BROADCAST flag in u.AllocateAddressRange.fulAccessType.

Which Addresses Are Allocated?

The bus driver supports two different strategies for allocating address ranges. If the driver requires a specific range of addresses, beginning at a hard-coded address, it can specify the hard-coded address in the u.AllocateAddressRange.Required1394Offset member of the request's IRB, and the length of the address range in u.AllocateAddressRange.nLength. The bus driver will allow two different drivers to allocate the same address twice. If the same driver tries to allocate an address range beginning at the same address twice, the bus driver returns the request with a status code of STATUS_SUCCESS, but the request itself is ignored.

Otherwise, the driver can allow the bus driver to choose the allocated addresses. The bus driver keeps track of all address ranges allocated by drivers, and will only return previously unallocated addresses.

The bus driver does not allocate the address contiguously. The addresses are segmented according to the MDL provided as backing store. Each segment in the MDL corresponds to one segment in the address range. A driver that needs the allocated addresses to be contiguous can allocate contiguous memory from non-paged pool.

If the driver needs to guarantee that every segment is smaller than a specific size, they can specify that size in u.AllocateAddressRange.MaxSegmentSize. Drivers that do not need to specify a maximum segment size set u.AllocateAddressRange.MaxSegmentSize to zero.

The bus driver returns the address ranges in the memory location pointed to by the u.AllocateAddressRange.p1394AddressRange member of the IRB. The device driver must allocate a large-enough array to hold each ADDRESS_RANGE structure, even in the worst case segmentation scenario. If the driver does not specify a segment size, or its maximum segment size is bigger than PAGE_SIZE, then the driver can determine the worst case by using the ADDRESS_AND_SIZE_TO_SPAN_PAGES macro on the buffer used for backing store. If the maximum segment size is smaller than PAGE_SIZE, the driver must allocate an array of size u.AllocateAddressRange.nLength / u.AllocateAddressRange.MaxSegmentSize + 2.

When the bus driver returns the allocated addresses, it records the actual number of address ranges allocated in u.AllocateAddressRange.hAddressRange.

Allocation And Backing Store

The bus driver receives all asynchronous packet requests on behalf of the driver. At the driver's behest, it can transparently handle the request, or it can dispatch the request to the driver. By setting options when it allocates the addresses, the driver can choose how the bus driver handles each request.

  1. The driver provides backing store for the address range, and the bus driver transparently handles all read, write, and lock requests by using the backing store.

    When the driver allocates addresses, it can supply an MDL in u.AllocateAddressRange.Mdl to serve as backing store. The bus driver maps the MDL onto the range of addresses it allocate for the driver, and handles all requests by reading or writing from the MDL. If the host controller supports it, the transaction is handled entirely by the host controller's DMA hardware. (When possible, the device driver should allow the bus driver to choose the range of addresses allocated: the bus driver will choose 1394 addresses that support automatic DMA for each transaction.)

    The driver must specify NOTIFY_FLAGS_NEVER for u.AllocateAddressRange.fulNotificationFlags.

    Here's an example:

    pIRB->u.AllocateAddressRange.Mdl = an MDL previously allocated by the driver.
pIRB->u.AllocateAddressRange.fulNotificationFlags = NOTIFY_FLAGS_NEVER

    For this option alone, the driver can also allocate address ranges while at a raised IRQL level. The driver can submit the request directly to the port driver, bypassing the usual IRP method of communication, by calling the port driver's physical mapping routine. The device driver passes the IRB to the port driver's physical mapping routine. The port driver will then allocate the address range asynchronously; when the port driver finishes, it calls the device driver's notification routine, passed in u.AllocateAddressRange.Callback, and passes u.AllocateAddressRange.Context as the parameter. The notification routine is called at DISPATCH_LEVEL.

    The device driver can get a pointer to the port driver's physical mapping routine by submitting the GET_LOCAL_HOST_INFO request to the bus driver, with nLevel = GET_PHYS_ADDR_ROUTINE. The bus driver returns a GET_LOCAL_HOST_INFO4 structure, which contains the physical mapping routine, and a context parameter that the device driver passes along with the IRB to the physical mapping routine.

    Here is an example of how the driver can set up the request for the physical mapping routine. The physical mapping routine does not change, so the driver would normally only submit this request once.

    GET_LOCAL_HOST_INFO5 PhysMapInfo;
pGetInfoIRB->FunctionNumber = GET_LOCAL_HOST_INFO;
pGetInfoIRB->GET_PHYS_ADDR_ROUTINE;

/* Driver submits the request. */

    Continuing the example, here is how the driver can use the physical mapping routine to submit the request at an elevated IRQL.

    VOID AllocationCompletionRoutine(PVOID Context);
/* Driver fills out the members of the IRB, including these: */
pIRB->u.AllocateAddressRange.Mdl = an MDL previously allocated by the driver.
pIRB->u.AllocateAddressRange.fulNotificationFlags = NOTIFY_FLAGS_NEVER
pIRB->Callback = AllocationCompletionRoutine;
pIRB->Context = information specific to this allocation the driver wants passed to its callback.

/* Driver submits the request to the physical mapping routine. */
PhysMapInfo.PhysAddrMappingRoutine(PhysMapInfo.Context, pIRB);

/*
The bus driver does the allocation asynchronously. When its done, it will signal the driver by executing AllocationCompletionRoutine(pIRB->u.AllocateAddressRange.Context);
*/
  2. The driver provides backing store for the address range. The bus driver notifies the driver after it completes each I/O transaction.

    The driver can provide either a single MDL, or a linked list of MDLs, as backing store. If the driver provides a single MDL, the bus driver pumps data into or out of the MDL in response to the asynchronous request. Once it completes the transaction, it signals the device driver by calling the driver-supplied notification callback.

    The device driver supplies the notification routine in the u.AllocateAddressRange.Callback member of the IRB. The driver must set at least one of the NOTIFY_FLAGS_AFTER_XXX flags. When the bus driver calls the routine, it passes a NOTIFICATION_INFO structure, which specifies the MDL backing store (in Mdl), the byte offset within the MDL where the transaction began (in ulOffset), and the length in bytes of the range of addresses affected (in nLength). The notification routine is called at DISPATCH_LEVEL. Any context information for this request that the driver passes in u.AllocateAddressRange.Context is passed by the bus driver in the Context member of NOTIFICATION_INFO.

    Using only one MDL, there is some risk of synchronization problems: the device may write to the address range faster than the driver can read from it. To avoid such a clash, for addresses to which the device only has write access the driver can provide a linked list of MDLs, in u.AllocateAddressRange.FifoSListHead, and a spin lock in u.AllocateAddressRange.FifoSpinLock. When the bus driver receives each asynchronous request packet, it holds the spin lock and pops off the first element on the list to fulfill the request. It then calls the driver's notification routine.

    In the NOTIFICATION_INFO structure, the bus driver provides the MDL it used to handle the transaction (in Mdl), the byte offset of the first address affected (in ulOffset), and the length of the ranges of addresses affected (in nLength). It also provides the ADDRESS_FIFO of the MDL (in Fifo). Before the driver returns from its notification routine, it should either use Fifo to push the element back on the list, or provide another MDL of the same size; otherwise, the bus driver will run out of MDLs to use in handling write requests from the device.

    Here is an extended example of using this type of notification. Globally, the driver creates an interlocked, singly-linked list, and a spin lock. The driver needs to access the them at raised IRQL's, so they must be in non-paged memory. Typically, drivers keep them in their device extensions.

    PSLIST_HEADER FifoSListHead;
KSPIN_LOCK FifoSpinLock;

ExInitializeSListHead(FifoSListHead);
KeInitializeSpinLock(FifoSpinLock);

    When the driver submits the request, it can set up the relevant IRB members as follows:

    VOID DriverNotificationRoutine(PNOTIFICATION_INFO NotificationInfo);

pIRB->u.AllocateAddressRange.Mdl = NULL;
pIRB->u.AllocateAddressRange.fulAccessType = ACCESS_FLAGS_READ;
pIRB->u.AllocateAddressRange.fulNotificationFlags = NOTIFY_FLAGS_AFTER_WRITE;
pIRB->u.AllocateAddressRange.FifoSListHead = FifoSListHead;
pIRB->u.AllocateAddressRange.FifoSpinLock = FifoSpinLock;
pIRB->u.AllocateAddressRange.Callback = NotificationRoutine;
pIRB->u.AllocateAddressRange.Context = context information specific to this request -- the bus driver will pass this as the Context member of the NOTIFICATION_INFO it passes to NotificationRoutine.

    In the callback, the driver either needs to allocate a new MDL and push it onto the list, or push the original MDL back on the list. For the latter, the bus driver passes the original ADDRESS_FIFO for the current MDL. Here is an example of the driver pushing the current MDL back on the list:

    ExInterlockedPushEntrySList(FifoSListHead, NotificationInfo->Fifo->FifoList, FifoSpinLock);

    If the driver specifies a single MDL as backing store in the original allocation request, the driver may return one or more address ranges.

  3. The bus driver signals the driver each time a request arrives, and hands off the packet to the driver.

    The driver provides a callback in the u.AllocateAddressRange.Callback member of the IRB. The NOTIFY_FLAGS_AFTER_XXX flags are ignored, and all packets are handed to the driver to handle.

    The driver must set the Mdl, FifoSListHead, and FifoSpinLock members of u.AllocateAddressRange to NULL. Here is an example of the settings for a driver that wishes to be notified when it receives asynchronous request packets of all three types.

    VOID DriverSuppliedCallback( IN PNOTIFICATION_INFO NotificationInfo );

pIRB->u.AllocateAddressRange.Callback = DriverNotificationRoutine;
pIRB->u.AllocateAddressRange.Context = information specific to this address range.
pIRB->u.AllocateAddressRange.Mdl = NULL;
pIRB->u.AllocateAddressRange.FifoSListHead = NULL;
pIRB->u.AllocateAddressRange.FifoSpinLock = NULL;

    The bus driver allocates a single contiguous range of addresses.

    The bus driver passes a NOTIFICATION_INFO structure to the driver's callback routine. The device driver must create its own response packet (see the IEEE 1394 specification for details), and it must allocate its own buffer to contain the response packet it creates. The response packet must be from non-paged pool or from a buffer that has been probed and locked.

    Within NOTIFICATION_INFO, the bus driver provides an uninitialized MDL in the ResponseMdl member. It also provides pointers to memory locations where it expects the device driver to enter a pointer to the response packet (in ResponsePacket), and the response packet length (in ResponseLength). The driver can also provide a kernel event object. The bus driver signals the kernel event object once it completes the transaction.

    Here is an example of how the device driver can fill in the necessary information in its notification routine.

    /* Suppose the driver creates its response packet in PVOID ResponsePacket, of length ResponseLength. It has created a kernel event ResponseEvent. */
MmInitializeMdl(NotificationInfo->ResponseMdl, ResponsePacket, ResponseLength);
MmBuildMdlFForNonPagedPool(Notification->ResponseMdl);
*(NotificationInfo->ResponsePacket) = ResponsePacket.
*(NotificationInfo->ResponseLength) = ResponseLength;
*(NotificationInfo)->ResponseEvent = Event;


Isochronous I/O for IEEE 1394 Devices

Real-time multimedia devices such as digital cameras need large amounts of bandwidth to send data in a steady stream, but do not require guaranteed delivery. (For example, a dropped frame from a digital camera would degrade the quality of the signal, but it would not destroy its meaning.) For such devices, IEEE 1394 provides isochronous transfer, which provides guaranteed bandwidth, but does not guarantee delivery.


Setting up Isochronous Transfer for IEEE 1394 Devices

Before drivers can start their device, they must follow these steps:

Step 1. Choose transfer speed.

The IEEE 1394 bus can support several different speeds, limited by what the hardware allows. Even if a specific device supports a certain speed, it may be plugged into another device that only supports lower speeds. Drivers must determine at run-time the transfer speed between the device and the computer. They query the bus driver with the REQUEST_GET_SPEED_BETWEEN_DEVICES request to determine the maximum possible speed between two devices on the bus, or the device and the host computer.

Step 2. Allocate bandwidth.

Before any isochronous data transfer can take place, the driver must reserve bandwidth on the bus. The bus tracks the amount of bandwidth allocated until it reaches a fixed amount (according to the IEEEE 1394-1995 specification, the maximum bandwidth that which can be sent is 80% of one bus cycle, which is 125 nanoseconds); it then does not allow any other device to acquire bandwidth until some of the currently allocated bandwidth is freed. The driver submits the REQUEST_ISOCH_ALLOCATE_BANDWIDTH request to the bus driver to reserve bandwidth.

If the request fails, the driver must not attempt any data transfer. Drivers should not assume that because bandwidth is not currently available, it will never be available. Bandwidth may become free at any time, so drivers should leave themselves in a state where they can attempt to allocate bandwidth later when appropriate.

If the request succeeds, the bus driver returns a bandwidth handle. The driver uses this handle in future bandwidth-related requests to the bus driver. For example, the driver can use REQUEST_ISOCH_SET_CHANNEL_BANDWIDTH on the handle to adjust the amount of bandwidth allocated. When the driver has finished with the allocated bandwidth, it must use REQUEST_ISOCH_FREE_BANDWIDTH to free the bandwidth, so that it can be used by other devices on the bus.

Step 3. Allocate a channel.

After a bandwidth allocation request succeeds, the driver requests an isochronous channel on which to write data. Multiple devices can read packets on one isochronous channel, but only one device can write to a channel. Devices that receive isochronous packets do not send acknowledgment packets in return.

Drivers request a channel by sending the REQUEST_ISOCH_ALLOCATE_CHANNEL request to the bus driver. The driver may request a specific channel, or ISOCH_ANY_CHANNEL to allocate any free channel. On success, the bus driver returns the allocated channel. If the bus driver returns an error code, drivers must not attempt any data transfer, and they must deallocate the bandwidth they allocated in Step 2.

Drivers should not assume that because a channel is not currently available, it will never be available. Channels may become free at any time, so drivers should leave themselves in a state where they can attempt to allocate a channel later when appropriate.

Step 4. Allocate a resource handle.

Once the driver allocates a channel, it allocates a resource handle for that channel. In all subsequent steps, the driver uses the resource handle to specify the channel.

Drivers allocate a resource handle for the channel by submitting the REQUEST_ISOCH_ALLOCATE_RESOURCES request to the bus driver.

When the driver allocates a resource handle, it also specifies flags indicating how the buffers attached to the handle will be used:

  • If the driver will use the channel to read data from a device (a REQUEST_ISOCH_LISTEN operation), it sets the RESOURCE_USED_IN_LISTENING flag. If the driver will use the channel to write data to the device (a REQUEST_ISOCH_TALK operation), it sets the RESOURCE_USED_IN_TALKING flag.
  • The driver uses the handle to provide data buffers for the transaction. (See Step 5 for details.) By default, the bus driver uses the buffers in order until it runs out, and then pauses the operation until the device driver attaches more buffers. The driver can specify the RESOURCE_BUFFERS_CIRCULAR flag with the REQUEST_ISOCH_ALLOCATE_RESOURCES request to tell the bus driver to reuse the attached buffers rather than pausing. See Isochronous DMA Options for IEEE 1394 Devices for details.
  • The driver may specify that the operation be synchronized to a certain value of the isochronous cycle clock. See Isochronous Synchronization Options for IEEE 1394 Devices for details.
  • The driver can set options for isochronous listens. The driver can indicate whether the isochronous packet headers are stripped from the data packets. The driver can also indicate whether arriving data should be copied into the waiting data buffers one packet per buffer, or if each buffer should be filled with data. See Isochronous Listen Options for IEEE 1394 Devices for details.

If this request fails, drivers should deallocate all isochronous resources they allocated in the previous steps.

Step 5. Attach buffers to the resource handle.

Once the driver allocates a resource handle, it attaches buffers to the handle. The host DMA controller will read data from or write data to the attached buffers.

With each buffer, the driver passes an ISOCH_DESCRIPTOR structure -describing how the buffer will be used. In the buffer's ISOCH_DESCRIPTOR structure, the driver can specify the following information:

  • The maximum number of bytes per frame. When transmitting data, the host controller splits the data buffer into packets of this size.
  • An optional callback routine. The bus driver calls this routine when it has finished processing
  • Synchronization options. See Isochronous Synchronization Options for IEEE 1394 Devices for a description of the synchronization options.
  • On isochronous talk operations, the driver can designate this buffer as a list of headers to be prepended to the next few data packets. See Isochronous Talk Options for IEEE 1394 Devices for details.

Once the operation has begun, the driver can detach buffers that it no longer needs, and can attach additional buffers. The driver can use the callback routine identified in ISOCH_DESCRIPTOR to signal itself when the bus driver has completed processing the last buffer attached. If, in Step 4, the driver set the RESOURCE_BUFFERS_CIRCULAR flag, the bus driver reuses the buffers already attached, and the driver does not attach or detach buffers once the operation has begun. See Isochronous DMA Options for IEEE 1394 Devices for a description of the two strategies for handling buffers.

Step 6. Begin the data transfer

To read from the device, the driver issues the REQUEST_ISOCH_LISTEN request. To write to the device, the driver issues the REQUEST_ISOCH_TALK request. The driver can then activate the device for reading or writing, in the appropriate device-specific fashion.


Isochronous DMA Options for IEEE 1394 Devices

Once begun, isochronous transfer is continuous until halted. The host controller must have a ready supply of buffers to handle the transaction's demands. The bus driver supports two different strategies for supplying buffers for the host controller's DMA cycle.

By default, the bus driver will use the linear buffer strategy: the bus driver uses the buffers attached to the resource handle until they are used up, and then halt the DMA. Before this happens, the driver attaches additional buffers to continue the transaction. The ISOCH_DESCRIPTOR for a buffer optionally provides a callback for when the bus driver has finished with a buffer — the driver can use this to attach additional buffers. For optimal performance, the driver should attach several buffers at a time, and provide a callback only with the last buffer to signal that the supply of buffers has run out.

Isochronous Transfer with Linear Buffers (Default)

If the driver uses the same buffers repeatedly, it can choose the circular buffers strategy, by setting the RESOURCE_BUFFERS_CIRCULAR flag for the resource handle (See REQUEST_ISOCH_ALLOCATE_RESOURCES). When the bus driver uses up the supply of buffers, it automatically continues the transfer beginning at the first buffer. The driver can use the ISOCH_DESCRIPTOR callback of the last buffer to signal itself that the bus driver has begun reusing buffers.

Isochronous Transfer with RESOURCE_BUFFERS_CIRCULAR Set


Isochronous Listen Options for IEEE 1394 Devices

This chapter describes the various isochronous listen options.

Receiving or stripping packet headers

Host controllers may or may not automatically strip the headers off an isochronous packet. The bus driver sets the HOST_INFO_SUPPORTS_RETURNING_ISO_HDR flag of HostCapabilities member of the GET_LOCAL_HOST_INFO2 structure, if the host controller does not automatically strip the headers off isochronous packets.

Also, host controllers may support configurable stripping of headers. The bus driver sets the HOST_INFO_SUPPORTS_ISOCH_STRIPPING flag of HostCapabilities if the host controller can be configured to strip headers. To actually configure the host controller to strip headers, the driver submits the REQUEST_ISOCH_ALLOCATE_RESOURCES request with the RESOURCE_STRIP_ADDITIONAL_QUADLETS flag set. The nQuadletsToStrip member specifies the number of quadlets to strip off the beginning of each packet. For example, nQuadletsToStrip = 1 would strip off the isochronous packet header.

Stream versus packet-based DMA

The stream-based and packet-based DMA strategies require support from the underlying host controller. Host controllers support at least one, and OHCI-compliant controllers supports both.

In stream-based DMA, the host controller fills up each buffer, ignoring packet boundaries. In packet-based DMA, the host controller writes one isochronous packet per buffer.

If the host controller supports both types of DMA, the bus driver sets the host controller to default to stream-based DMA. To reset the host controller to packet-based DMA, the driver should set the RESOURCE_USE_PACKET_BASED flag when it allocates the resource handle.

Drivers use the REQUEST_GET_LOCAL_HOST_INFO bus request (with the u.GetLocalHostInformation

.nLevel member of the IRB = GET_HOST_CAPABILITIES) to determine the characteristics of the host controller. The bus driver returns a GET_LOCAL_HOST_INFO2 structure, and sets flags within the HostCapabilities member to indicate what the host controller supports:

DMA type | HostCapabilities flag
stream-based | HOST_INFO_STREAM_BASED
packet-based | HOST_INFO_PACKET_BASED


Isochronous Talk Options for IEEE 1394 Devices

There are three ways of organizing output data in isochronous talk operations: packets with no headers, fixed-sized data packets with headers, and variable-size data packets with headers.

Packets with no Headers

By default, the host controller sends out the data in the attached buffers, indicated by the Mdl member of the ISOCH_DESCRIPTOR structure, in the order the buffers were attached. In the default case, the host controller automatically splits the buffer into packets of size no greater than that specified in the nMaxBytesPerFrame member of the buffer's ISOCH_DESCRIPTOR structure.

For example, the driver for a device that expects to receive its data in 512 byte packets would include the following in its declaration of the buffer's ISOCH_DESCRIPTOR:

/* elsewhere, the buffer has declared: */
/*        ISOCH_DESCRIPTOR isoch_descriptor; */
isoch_descriptor->nMaxBytesPerFrame = 512;

Fixed-size Data Packets with Headers

Some devices require that some header information be prepended to each packet the device receives. (This header information would be inserted before the data, but after the IEEE 1394 standard isochronous packet header.) In this instance, drivers can assemble a buffer of headers, and a buffer of data, and have the host controller automatically prepend a header to the data packets it sends to the device. The driver indicates that a buffer contains a list of headers by specifying the DESCRIPTOR_HEADER_SCATTER_GATHER flag in that buffer's ISOCH_DESCRIPTOR structure. There are two types of headers that can prepended to a data packet: fixed-sized and variable-sized.

With fixed-size headers, the driver specifies the header size in the nMaxBytesPerFrame member of the ISOCH_DESCRIPTOR structure. The host controller treats this buffer and the next buffer as a pair: a header buffer and data buffer. When it assembles the data packets, it takes one frame from the header buffer and one frame from the data buffer, and splices them together to form the next packet it sends to the device.

For example, suppose the device expects each 512 byte data buffer to be preceded by an 8 byte header. The driver could declare a pair of ISOCH_DESCRIPTOR structures as follows:

/* elsewhere, the buffer has declared: */
/*        ISOCH_DESCRIPTOR isoch_descriptor_1, isoch_descriptor_2; */
/*        #define NUM_HEADERS to be the number of headers included in /*        the first buffer */

isoch_descriptor_1->fulFlags = DESCRIPTOR_HEADER_SCATTER_GATHER;
isoch_descriptor_1->ulLength = 8 * NUM_HEADERS;
isoch_descriptor_1->nMaxBytesPerFrame = 8;
       .
       .
       .
isoch_descriptor_2->ulLength = 512 * NUM_HEADERS;
isoch_descriptor_2->nMaxBytesPerFrame = 512;

Not all host controllers support the DESCRIPTOR_HEADER_SCATTER_GATHER flag. To determine if the host controller supports it, query the bus driver with the REQUEST_GET_LOCAL_HOST_INFO request, with nLevel = GET_HOST_CAPABILITIES. The bus driver will set the HOST_INFO_SUPPORTS_ISO_HDR_INSERTION flag of the HostCapabilities member of the GET_LOCAL_HOST_INFO2 structure it returns.

Variable-size Data Packets with Headers

This case is similar to the fixed-size packet case. In addition to the DESCRIPTOR_HEADER_SCATTER_GATHER flag, the driver sets the RESOURCE_VARIABLE_ISOCH_PAYLOAD flag in the header buffer's ISOCH_DESCRIPTOR structure as follows:

isoch_descriptor_1->fulFlags = DESCRIPTOR_HEADER_SCATTER_GATHER | RESOURCE_VARIABLE_ISOCH_PAYLOAD;

In the case of variable-size data packets, the driver must assemble a buffer of headers as in the fixed-size case. However, with variable-size packets, unlike fixed-size packets, the driver must record the size of each packet in a scatter-gather header element that it prepends to each header.

Header elements are defined by the following structure found in 1394.h:

typedef struct _IEEE1394_SCATTER_GATHER_HEADER {
  USHORT  HeaderLength;
  USHORT  DataLength;
  UCHAR  HeaderData;
} IEEE1394_SCATTER_GATHER_HEADER, *PIEEE1394_SCATTER_GATHER_HEADER;

The header element indicates both the length of the header and the length of the data. Thus with variable-size data packets, the nMaxSizeBytesPerFrame member of the data descriptor no longer indicates the size of an individual data packet. Each data packet can have a different size that is indicated in its corresponding header element. The nMaxSizeBytesPerFrame member of the header descriptor is defined as follows.

IsochDescriptor->nMaxBytesPerFrame = MAX_HEADER_DATA_SIZE+FIELD_OFFSET(HeaderElement,HeaderData)

where MAX_HEADER_DATA_SIZE indicates the size of the header to be prepended to each data packet, FIELD_OFFSET(HeaderElement,HeaderData) indicates the length of the header element inserted immediately before each header, and NUMBER_OF_PACKETS is the number of packets to be transmitted (including header-only packets).

Drivers can now transmit header-only data packets by simply setting the DataLength member of a header element to zero:

HeaderElement->DataLength = 0

The total length of the header descriptor buffer is indicated in the usual way by means of the ulLength member of the descriptor. It must be an integer multiple of the number of header scatter-gather elements:

IsochDescriptor->ulLength = IsochDescriptor->nMaxBytesPerFrame * NUMBER_OF_PACKETS;

The third member of the header element structure, HeaderData, is merely a place holder that indicates where the header data begins. If, for instance, the driver were assembling a buffer of 8-byte CIP headers, the assembled buffer would look like this:

Buffer of 8-byte CIP Headers

All headers in a given descriptor must be of the same length. This allows the OHCI port driver (OHCI1394.SYS) to parse the header descriptor like an array of fixed-size elements. Data packets can vary in size, but must be contiguous with no "holes."

Data in both header and data descriptors must be page-aligned. There is no restriction on the size of data packets, but neither header nor data packets are allowed to straddle page boundaries. Drivers must align descriptor buffers properly before setting up the MDL for the buffer.

If, for example, the driver assembles a header descriptor with 12-byte headers and 4-byte header elements, each data packet will have 16 bytes of prepended data. Since 16-bytes will fit into a 4,096-byte page exactly 256 times, none of the prepended data will ever straddle a page boundary.

If, on the other hand, the driver assembles a header descriptor with 8-byte headers and 4-byte header elements, then each data packet will have 12 bytes of prepended data. Since a 4,096 byte page is not an integer multiple of 12, the header descriptor must be under 4,096 bytes in size to prevent a header from straddling a page boundary. However, the size of the header descriptor buffer can be extended up to two pages by adjusting the base address of the buffer as illustrated in the pseudocode that follows.

// First find the number of headers (together with header elements)
// that will fit in a page. Use a floor function that rounds down to
// the nearest integer
PrependData = sizeof(header) + 8; // First two fields of header element take up 8 bytes
NumHeaders =floor(PAGE_SIZE/PrependData);
// By forcing the buffer address defined in the MDL to begin at the appropriate offset,
// the driver can guarantee that the last header in the buffer will be aligned on a page
// boundary. That way, DMA can continue across at least one page boundary.
r = PAGE_SIZE - (NumHeaders*12).
// BufferAddress = the page-aligned address returned by a memory allocation routine
// Adjust buffer starting address
BufferAddress += r;
isochDescriptor->mdl = IoAllocateMdl(BufferAddress, … and so on.)


Isochronous Synchronization Options for IEEE 1394 Devices

The IEEE 1394 driver stack supports certain automatic synchronizations of the beginning of REQUEST_ISOCH_LISTEN or REQUEST_ISOCH_TALK operations.

For an isochronous listen operation, if a driver sets the DESCRIPTOR_SYNCH_ON_SY or DESCRIPTOR_SYNCH_ON_TAG flag within a buffer's ISOCH_DESCRIPTOR structure, the driver will only receive data from packets that match the Sy or Tag value supplied within ISOCH_DESCRIPTOR. The driver can also set the DESCRIPTOR_USE_SY_TAG_IN_FIRST flag only if the first packet in a sequence needs to match Sy or Tag.

If the host controller supports it, both isochronous listen and isochronous talk can be programmed to start on certain isochronous cycle time values. The isochronous cycle time, stored in CYCLE_TIME structures, keeps track of a count of seconds (which wraps every 128 seconds), the number of isochronous cycles in the current second, and the number of IEEE 1394 bus clock ticks within the current cycle. Isochronous talk and listen operations can use the first two values to synchronize.

Drivers can synchronize both for the entire operation, and for each individual data buffer. Drivers that want to synchronize the entire operation set the RESOURCE_SYNCH_ON_TIME flag for the resource handle to be used in the request. Drivers that want operation on a specific buffer to be synchronized set the DESCRIPTOR_SYNCH_ON_TIME flag in the ISOCH_DESCRIPTOR flag for that data buffer.

If in a REQUEST_GET_LOCAL_HOST_INFO request, with nLevel set to 2, if the bus driver returns the HOST_INFO_SUPPORTS_START_ON_CYCLE flag, the host controller supports synchronizing start on isochronous cycle time values.


Completing an Isochronous Data Transfer

Once a device no longer needs to transfer data, the driver must inform the bus that the operation is complete, and then must deallocate the isochronous resources it allocated when setting up.

Drivers must follow these steps to clean up:

  1. If the driver has begun an isochronous operation through the REQUEST_ISOCH_LISTEN or REQUEST_ISOCH_TALK bus requests, it must issue the REQUEST_ISOCH_STOP request to signal the bus driver to stop the isochronous operation.
  2. Any buffers that remain attached to a resource handle must be detached by using the REQUEST_ISOCH_DETACH_BUFFERS request.
  3. If the driver has allocated a resource handle, it must deallocate it through the REQUEST_ISOCH_FREE_RESOURCES request.
  4. If the driver has a channel allocated, it must deallocate it through the REQUEST_ISOCH_FREE_CHANNEL request.
  5. The driver must deallocate any bandwidth it has allocated by using the REQUEST_ISOCH_FREE_BANDWIDTH request.


Modifying the 1394 Configuration ROM

A Microsoft® Windows® system connected to the 1394 bus exposes a Configuration ROM that describes the functional units supported by the node. For further information on 1394 Configuration ROMs, see the IEEE 1394-1995 and IEEE-1212-2000 specifications. In Windows XP and later operating system, the contents of the Configuration ROM can be dynamically defined in two ways:

  1. Drivers can dynamically modify the Configuration ROM to expose hardware designed for non-1394 buses on the 1394 bus.

    For example, consider a general purpose system has an internal DVD drive connected to the system's IDE bus. A driver that maps 1394 requests into the protocol used by the DVD drive could expose the DVD drive on the 1394 bus to other 1394 nodes. To do this it would have to add a new unit directory to the 1394 Configuration ROM of the system. Other systems connected on the 1394 bus will then be able to enumerate the general purpose system as though it were a 1394 DVD device.

  2. Drivers can use virtual physical device objects (virtual PDO) to emulate hardware in ways that facilitate the testing of device drivers.

    Device emulation allows developers to test drivers for devices that they have not yet received. Hardware emulation drivers can expose a virtual 1394 device on the 1394 bus. Developers can then debug a driver for the new hardware on another system.


IEEE 1394 Hardware Emulation Drivers

An emulation driver can change the system into a multifunction device by adding a unit directory to the system's Configuration ROM. The emulation driver intercepts requests coming from external nodes. It also does all the work necessary to emulate the 1394 registers, exposed by the hardware devices it emulates.

The following sections describe the implementation and operation of emulation drivers:

Virtual 1394 Devices

Initialization of IEEE 1394 Hardware Emulation Drivers

Changes in the DDI for IEEE 1394 Hardware Emulation Drivers


Virtual 1394 Devices

Emulation drivers are not loaded as a result of a hardware enumeration. Instead, they are loaded on top of a virtual physical device object (virtual PDO). The bus driver loads all 1394 emulation drivers when it reads the list of virtual 1394 devices defined in the registry, or when a higher level software component requests the bus driver to create a virtual 1394 device. After creating a virtual PDO for the emulated device, the 1394 bus driver loads the emulation driver in the usual way, by calling IoInvalidateDeviceRelations. This call informs the Plug and Play (PnP) Manager that a new device has arrived.

The validity of a virtual PDO is independent of bus events, so physical device removal and insertion does not affect the emulation code. With just a few exceptions, the emulation driver loaded on top of a virtual PDO can use the complete 1394 DDI in the same way as a function driver loaded on a PDO for a real device. For an explanation of differences in the way real and virtual devices use the 1394 DDI, see Changes in the DDI for IEEE 1394 Hardware Emulation Drivers.


Creating IEEE 1394 Virtual Devices

Upper-level drivers and user-mode services can add or remove virtual 1394 devices by means of a device control request with an IOCTL_IEEE1394_API_REQUEST control code. The request contains an IEEE1394_API_REQUEST structure whose RequestNumber member indicates the action to be taken by the bus driver. Since a virtual device has no device ID or instance ID, the driver, or user program that requests that a virtual device be created, must supply the device ID and instance ID in an IEEE1394_VDEV_PNP_REQUEST structure. If set, the IEEE1394_REQUEST_FLAG_PERSISTENT flag guarantees that the virtual device will be persistent across boots.

When the IEEE1394_REQUEST_FLAG_PERSISTENT is specified with IOCTL_IEEE1394_API_REQUEST, the 1394 bus driver stores nonvolatile context information about the virtual device in the registry. This allows the bus driver to automatically recreate the virtual PDO on the next boot without intervention from an upper-level driver.

The bus driver will use this registry entry to "enumerate" a virtual device for each 1394 device stack in the system. Thus, if more than one 1394 host controller is present on the system, a virtual device defined in the registry will be enumerated more than once. To ensure that each virtual device has a unique instance ID, the upper-level driver or user service that is creating the virtual device should not specify a specific "hard-coded" instance ID for virtual devices on systems that have more than one 1394 host controller. Instead, the upper-level software should set the IEEE1394_REQUEST_FLAG_USE_LOCAL_HOST_EUI flag in the IEEE1394_API_REQUEST. If this flag is set, the bus driver will use the instance ID of the host controller as the instance ID of the virtual device the next time it enumerates the device. Since each 1394 device stack will have a host controller with a unique instance ID, a virtual device, whose instance ID is the same as the instance ID of its host controller, will also have a unique instance ID.


Removing IEEE 1394 Virtual Devices

Once a virtual PDO has been created, existing Plug and Play methods can be used to remove that PDO. An IRP_MN_REMOVE_DEVICE request can be sent to the virtual PDO. An upper-level driver or user-mode service can inquire, through the usual PnP mechanism, which virtual devices are present. This mechanism uses the class GUID, provided in the virtual driver's INF file.


Initialization of IEEE 1394 Hardware Emulation Drivers

After the bus driver enumerates the virtual device on the virtual physical device object (virtual PDO) and starts the virtual device's emulation driver, the emulation driver needs to perform the following steps:

  1. Send a REQUEST_SET_LOCAL_HOST_PROPERTIES request to the bus driver with u.SetLocalHostProperties.nLevel member of the IRB set to SET_LOCAL_HOST_PROPERTIES_MODIFY_CROM in order to add a unit directory to the system's IEEE 1394 configuration ROM. This request will also add any other configuration data to the configuration ROM that is necessary in order to expose the emulated device functionality. The request needs to be sent using the virtual PDO the emulated driver is loaded on.
  2. Issue a bus reset to inform the 1394 nodes present on the bus that the system configuration ROM has changed.


Changes in the DDI for IEEE 1394 Hardware Emulation Drivers

Virtual PDOs and the drivers that load above them will have the same access to the 1394 bus DDI as a functional driver loaded on a PDO for an actual hardware device. However, since there is no target device in the case of a virtual driver, the 1394 bus driver will have to treat certain requests as special cases. The following is a list of requests that will exhibit different behavior if addressed to a virtual PDO:

  • REQUEST_ASYNC_READ/WRITE/LOCK

    Normally, the 1394 bus driver fills in the target node ID using information that was stored during the enumeration procedure. In the case of a virtual device, however, there is no target device node, so the virtual driver must provide the node ID. The bus driver will then make sure not to overwrite this information. In the case of virtual devices, the bus driver uses packet size and transfer rate information that was stored in the device object for the port.

  • REQUEST_ALLOCATE_ADDRESS_RANGE

    All address allocation requests from an emulator device driver will implicitly have ACCESS_FLAG_TYPE_BROADCAST enabled if post notification on the address range is required. This is done to allow any external node to access the address range used by the emulator driver to simulate the hardware device. Physical address allocations are treated the same as with functional drivers.

  • REQUEST_GET_ADDR_FROM_DEVICE_OBJECT

    This request is not supported for virtual devices, because there is no corresponding hardware node from which to get the node ID.

  • REQUEST_SET_DEVICE_XMIT_PROPERTIES

    This request is not supported for virtual devices, because there is no corresponding hardware node from which to get the node ID.

For all other requests, the behavior between virtual and physical devices is identical.


IEC-61883 Client Drivers

IEC-61883 is a standard communications and control interface used by IEEE 1394 audio and video devices. In Windows SE, Windows 2000 and earlier operating systems, 61883 functionality was implemented as part of the Microsoft Digital Video (MSDV) camcorder driver, msdv.sys. In Windows ME, Windows XP and later operating systems, 61883 functionality has been moved to a separate driver dedicated to 61883 support. Vendor-supplied IEC-61883 client drivers send requests to the system-supplied IEC-61883 protocol driver (61883.sys), to communicate with their devices.

IEC-61883 specifications define the protocol by which numerous consumer electronic audio and video devices can interconnect. These specifications include definitions for general data format, data flow, and connection schemes for audiovisual information. The IEC-61883 protocol driver supports devices that conform to the following ratified IEC-61883 specifications:

  • IEC 61883-1: General
  • IEC 61883-2: SD-VCR Data Transmission
  • IEC-61883-3: HD-VCR Data Transmission
  • IEC-61883-5: MPEG2-TS Data Transmission
  • IEC-61883-5: SDL-DVCR Data Transmission
  • IEC-61883-6: Audio and Music Data Transmission Protocol

This section includes:

IEC-61883 Protocol Driver

IEC-61883 Protocol Driver in a Client Driver Stack


IEC-61883 Protocol Driver

The IEC-61883 protocol driver, 61883.sys, supports function control protocol (FCP), common isochronous packet (CIP) format, and connection management procedures (CMP), as defined in the IEC 61883-1 specification. The protocol driver strips stream packet headers from requests, supports scatter/gather, and limits buffer copies to move large amounts of data efficiently.

To issue IEC-61883 commands to devices connected to the IEEE 1394 bus, IEC-61883 client drivers include 61883.h and issue the IRP_MJ_INTERNAL_DEVICE_CONTROL IRP with the I/O control code IOCTL_61883_CLASS. The client driver packages the parameters in an AV_61883_REQUEST structure and passes a pointer to it in the Parameters.Others.Argument1 member of the IRP. The Function member of the AV_61883_REQUEST structure determines the type of operation. The AV_61883_REQUEST structure contains request-specific parameters in a union of data structures, one per request type.


IEC-61883 Protocol Driver in a Client Driver Stack

IEC-61883 client drivers rely on 61883.sys to communicate with their devices using the IEC-61883 protocol.

The following diagram shows an example of the 61883.sys in an AV/C driver stack. The vendor-supplied AV/C subunit driver is the IEC-61883 client in this example.

Example of an IEC-61883 Client Driver Stack

Starting from the top of the diagram:

  • The stream class driver, stream.sys, supports kernel streaming drivers for devices such as DVD, video capture, and external sound devices. The stream class driver is documented in the Stream Minidriver Design Guide.
  • In this example, the IEC-61883 client is a vendor-supplied AV/C subunit driver. This is a kernel streaming minidriver that uses facilities provided by lower drivers in the AV/C stack to control its device. (For more information about AV/C subunit drivers, see Introduction to AV/C Drivers.)

    AV/C subunit drivers set up plug connections and streams, and expose subunit control, status, and notification. They use the kernel streaming framework to expose a generic pin property set and device-specific property and event sets.

  • The AV/C stream filter driver, avcstrm.sys, is an optional WDM filter driver that isolates stream-specific format handling for subunit drivers. The AV/C stream filter driver is specified as a lower driver by third-party INF files. It supports DV and MPEG stream format for subunit drivers and supplies CMP helper functions in conjunction with avc.sys. It also provides kernel-streaming data structures and data intersection handler.
  • The AV/C protocol driver, avc.sys, maps AV/C commands to WDM IRPs, retries requests (for example, if a subunit is busy), handles interim responses as pending IRPs, and routs responses to the correct subunit driver based on type, ID, and operation code. For Microsoft® Windows® XP and later, avc.sys also provides plug connection management. (For more information about support that Microsoft provides for the AV/C protocol, see Introduction to AV/C Drivers.)
  • The IEC-61883 protocol driver, 61883.sys, handles function control protocol (FCP), common isochronous packet (CIP) format, and connection management procedures (CMP) requests sent down the AV/C driver stack.
  • The 1394 bus driver, 1394bus.sys, enumerates devices on the IEEE 1394 bus and responds to Plug and Play and power management IRPs on their behalf.
  • The port driver for the host controller provides a hardware-independent interface to the IEEE 1394 bus. The port driver handles some IRPs and forwards others to the port driver for the motherboard's host controller. Microsoft supplies a standard port driver, ohci1394.sys, for host controllers that satisfy the 1394 Open Host Controller Interface Specification, which is available for download from http://www.microsoft.com/hwdev/1394.

AV/C subunit drivers are just one of the possible types of IEC-61883 client drivers. Another example would be a driver that utilizes the HAVi protocol layered above IEC-61883. Although 61883.sys and the IEC-61883 protocol do not have any AV/C or HAVi dependencies, clients of 61883.sys can operate under different constraints. For example, AV/C subunit drivers are usually clients of avc.sys, which provides FCP-related functions and blocks upper-level drivers from sending FCP-related requests down the stack to be handled by 61883.sys.


IEEE 1394 Bus I/O Requests

An IEEE 1394 device driver must communicate with its device by submitting IRPs down the device stack to the 1394 bus driver.

To use these I/O requests, include the header file 1394.h, which is shipped with the Windows® 2000 DDK.


IOCTL_1394_CLASS

Operation

An IEEE 1394 driver uses the IRP_MJ_DEVICE_CONTROL IRP, with IoControlCode IOCTL_1394_CLASS, to communicate with the bus driver. The driver has access to all operations provided by the IEEE 1394 bus and its host controller through this request.

Input

Parameters->Others.Arguments1 points to an IRB structure. The FunctionNumber member of the IRB specifies the type of request. The u member of the IRB is a union that specifies the request-type-specific parameters of the request. The parameters and their meaning are documented with each request.

Legal requests are as follows:

REQUEST_ALLOCATE_ADDRESS_RANGE

REQUEST_ASYNC_LOCK

REQUEST_ASYNC_READ

REQUEST_ASYNC_STREAM

REQUEST_ASYNC_WRITE

REQUEST_BUS_RESET

REQUEST_BUS_RESET_NOTIFICATION

REQUEST_CONTROL

REQUEST_FREE_ADDRESS_RANGE

REQUEST_GET_ADDR_FROM_DEVICE_OBJECT

REQUEST_GET_CONFIGURATION_INFO

REQUEST_GET_GENERATION_COUNT

REQUEST_GET_LOCAL_HOST_INFO

REQUEST_GET_SPEED_BETWEEN_DEVICES

REQUEST_GET_SPEED_TOPOLOGY_MAPS

REQUEST_ISOCH_ALLOCATE_BANDWIDTH

REQUEST_ISOCH_ALLOCATE_CHANNEL

REQUEST_ISOCH_ALLOCATE_RESOURCES

REQUEST_ISOCH_ATTACH_BUFFERS

REQUEST_ISOCH_DETACH_BUFFERS

REQUEST_ISOCH_FREE_BANDWIDTH

REQUEST_ISOCH_FREE_CHANNEL

REQUEST_ISOCH_FREE_RESOURCES

REQUEST_ISOCH_LISTEN

REQUEST_ISOCH_MODIFY_STREAM_PROPERTIES

REQUEST_ISOCH_QUERY_CYCLE_TIME

REQUEST_ISOCH_QUERY_RESOURCES

REQUEST_ISOCH_SET_CHANNEL_BANDWIDTH

REQUEST_ISOCH_STOP

REQUEST_ISOCH_TALK

REQUEST_SEND_PHY_CONFIG_PACKET

REQUEST_SET_DEVICE_XMIT_PROPERTIES

REQUEST_SET_LOCAL_HOST_PROPERTIES

Output

Parameters->Others.Arguments1 points to the IRB structure passed as input. As part of completing the request, the bus driver fills in certain members of the u member with information for the driver. The returned information is documented below with each request.

I/O Status Block

The information the bus driver returns in the I/O Status Block is documented below with each request.


REQUEST_ALLOCATE_ADDRESS_RANGE

The REQUEST_ALLOCATE_ADDRESS_RANGE request allocates addresses in the computer's IEEE 1394 address space.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      PMDL            Mdl;
      ULONG           fulFlags;
      ULONG           nLength;
      ULONG           MaxSegmentSize;
      ULONG           fulAccessType;
      ULONG           fulNotificationOptions;
      PVOID           Callback;
      PVOID           Context;
      ADDRESS_OFFSET  Required1394Offset;
      PSLIST_HEADER   FifoSListHead;
      PKSPIN_LOCK     FifoSpinLock;
      ULONG           AddressesReturned;
      PADDRESS_RANGE  p1394AddressRange;
      HANDLE          hAddressRange;
      PVOID           DeviceExtension;
    } AllocateAddressRange;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_ALLOCATE_ADDRESS_RANGE
u.AllocateAddressRange.Mdl
If non-NULL, pointer to the MDL that describes the application's buffer where asynchronous operations are to be read, written, or locked. If the driver specifies u.AllocateAddressRange.Mdl, then u.AllocateAddressRange.FifoSListHead and u.AllocateAddressRange.FifoSpinLock must be NULL.
u.AllocateAddressRange.fulFlags
Specifies whether the array entries in p1394AddressRange use big-endian byte order. If the caller specifies BIG_ENDIAN_ADDRESS_RANGE, the array entries will be in big-endian byte order (the native byte order of the IEEE 1394 protocol), even if the local host is a little-endian machine. In order to specify a little-endian address range, the caller must explicitly guarantee that the BIG_ENDIAN_ADDRESS_RANGE flag is not set using a statement similar to the following:
fulFlags = fulFlags & ~(0x0ffffffff & BIG_ENDIAN_ADDRESS_RANGE)
u.AllocateAddressRange.nLength
Specifies the number of the IEEE 1394 addresses to allocate.
u.AllocateAddressRange.MaxSegmentSize
Specifies the maximum size for each range of addresses the bus driver allocates. Use zero to indicate that the driver does not have a required maximum segment size. This member is ignored if u.AllocateAddressRange.Required1394Offset is non-NULL.
u.AllocateAddressRange.fulAccessType
Specifies access type using one or more of the following flags.
Access | Description
ACCESS_FLAGS_TYPE_READ | Allocated addresses can be read.
ACCESS_FLAGS_TYPE_WRITE | Allocated addresses can be written to.
ACCESS_FLAGS_TYPE_LOCK | Allocated addresses can be the target of a lock operation.
ACCESS_FLAGS_TYPE
_BROADCAST 		Allocated addresses can receive asynchronous I/O requests from any node on the bus. (By default, only the device driver's device can send requests to the allocated addresses).

u.AllocateAddressRange.fulNotificationOptions
If the device driver requests that the bus driver handle each request, and notifies the device driver upon completion, this specifies which asynchronous I/O request types will trigger the bus driver to the notify the device driver upon completion. See the Comments section for more details. The driver may specify one or more of the NOTIFY_FLAGS_AFTER_XXX flags.
Flag | Description
NOTIFY_FLAGS_NEVER | No notification.
NOTIFY_FLAGS_AFTER_READ | Notify the device driver after carrying out an asynchronous read operation.
NOTIFY_FLAGS_AFTER_WRITE | Notify the device driver after carrying out an asynchronous write operation.
NOTIFY_FLAGS_AFTER_LOCK | Notify the device driver after carrying out an asynchronous lock operation.

u.AllocateAddressRange.Callback
Pointer to a device driver callback routine. If the device driver specifies that the bus driver notify the device driver for each asynchronous I/O request, u.AllocateAddressRange.Callback points to the device driver's notification routine, which must have the following prototype.
VOID DriverNotificationRoutine(IN PNOTIFICATION_INFO );

If the device driver specifies that it receives no notification, and submits this request at raised IRQL through the port driver's physical mapping routine, then u.AllocateAddressRange.Callback points to the device driver's allocation completion routine, which must have the following prototype.

VOID AllocationCompletionRoutine( IN PVOID );

Drivers that do not request notification, and submit this request in the normal way at PASSIVE_LEVEL, must set this member to NULL.

u.AllocateAddressRange.Context
Pointer to any context data that that the device driver wants to pass for this set of addresses. If the provided callback (see previous) is a notification routine, the bus driver passes u.AllocateAddressRange.Context within the NOTIFICATION_INFO the parameter. If the callback is an allocation completion routine, the bus driver passes u.AllocateAddressRange.Context as the sole parameter to the routine.
u.AllocateAddressRange.Required1394Offset
Specifies a hard-coded address in the computer's IEEE 1394 address space. The bus driver allocates the addresses beginning at u.AllocateAddressRange.Required1394Offset. If no specific address is required, the driver should fill in each member of the ADDRESS_OFFSET with zero. The bus driver then chooses the addresses to allocate.
u.AllocateAddressRange.FifoSListHead
If non-NULL, specifies a properly initialized (for example, by ExInitializeSListHead) interlocked, singly-linked list of ADDRESS_FIFO elements. Each ADDRESS_FIFO contains an MDL. As the bus driver handles each incoming write request to the allocated addresses, it pops off the first element on the list and writes incoming data to the MDL. It then calls the driver's notification routine.

Each MDL provided must only span one page in memory. The driver can add or remove elements from the ADDRESS_FIFO list by using ExInterlockedPushEntrySList and ExInterlockedPopEntrySList.

If this member is non-NULL, the Mdl member of u.AllocateAddress range must be NULL, the fulNotificationFlags member must be NOTIFY_FLAGS_AFTER_WRITE (no other flags must be specified), and the driver must provide a spin lock in FifoSpinLock.

u.AllocateAddressRange.FifoSpinLock
If non-NULL, specifies a properly initialized spin lock (for example, by KeInitializeSpinLock). The spin lock will be used to serialize access to the SList provided in u.AllocateAddressRange.FifoSListHead.

The u.AllocateAddressRange.FifoSpinLock member is non-NULL if and only if u.AllocateAddressRange.FifoSListHead is non-NULL as well.

u.AllocateAddressRange.p1394AddressRange
Pointer to an array of ADDRESS_RANGE structures. The array must be large enough to hold the maximum number of structures the bus driver can return.

If the driver specifies a required address offset, or if the driver does not provide any backing store, the bus driver only returns one address range. If the driver provides backing store in u.AllocateAddressRange.Mdl the bus driver segments the allocated addresses along physical memory boundaries. If the MaxSegmentSize of u.AllocateAddressRange is 0, or if MaxSegmentSize is bigger than the page size, the driver can use the ALLOCATE_AND_SIZE_TO_SPAN_PAGES macro to determine the worst case. Otherwise, the maximum number of addresses ranges returned by the bus driver is u.AllocateAddressRange.nLength / u.MaxSegmentSize.

u.AllocateAddressRange.DeviceExtension
Reserved.

IRB Output

u.AllocateAddressRange.AddressesReturned
Specifies the number of ADDRESS_RANGE structures returned in the p1394Address member.
u.AllocateAddressRange.p1394AddressRange
If the request is successful, this points to an array of ADDRESS_RANGE structures that describe the set of address ranges allocated to fulfill this request.
u.AllocateAddressRange.hAddressRange
If the request is successful, this specifies the handle to use when freeing the allocated address ranges with the REQUEST_FREE_ADDRESS_RANGE request.

I/O Status Block

The bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS on success, or the appropriate error code on failure.

Operation

If the driver provides an address in u.AllocateAddressRange.Required1394Offset, the bus driver allocates one contiguous range of addresses, beginning at that address. Otherwise, the bus driver allocates several ranges of addresses to fulfill the request.

Asynchronous I/O packets sent to the allocated address range are received by the bus driver. What the bus driver does with the packet depends on settings in the IRB when it is submitted.

Settings for u.AllocateAddressRange Bus driver action upon receiving a request packet
Mdl non-NULL, and fulNotificationFlags is NOTIFY_FLAGS_NEVER The bus driver transparently handles the request packet by reading or writing data using the MDL. The device driver receives no notification.

For this setting, the bus driver allocates the address range asynchronously. Upon completion, it calls the allocation completion routine that the driver passed in u.AllocateAddressRange.Callback. As a parameter, it passes u.AllocateAddressRange.Context.

This form of REQUEST_ALLOCATE_ADDRESS_RANGE can only be submitted in the normal way at IRQL PASSIVE_LEVEL. At raised IRQL, the driver can submit the IRB directly to the port driver through a special interface. See below for details.
Mdl non-NULL, and one or more of NOTIFY_FLAGS_AFTER_XXX are specified. (FifoSListHead and FifoSpinLock must be NULL.) The bus driver handles the request packet by reading or writing data using the MDL. After each request type specified by NOTIFY_FLAGS_AFTER_XXX, the bus driver calls the driver's notification routine (passed in u.AllocateAddressRange.Callback), and passes a description of the operation in NOTIFICATION_INFO. See NOTIFICATION_INFO for details.

Drivers can submit this form of REQUEST_ALLOCATE_ADDRESS_RANGE at any IRQL.

FifoSListHead and FifoSpinLock non-NULL, and the only notification flag is NOTIFY_FLAGS_AFTER_WRITE. (Mdl must be NULL.) The bus driver acquires the spin lock, pops the first element off the list, and uses the MDL to handle the request packet. It then calls the driver's notification routine (passed in u.AllocateAddressRange.Callback), and passes a description of the operation in NOTIFICATION_INFO. See NOTIFICATION_INFO for details.

Drivers can submit this form of REQUEST_ALLOCATE_ADDRESS_RANGE at any IRQL.
Mdl, FifoSListHead, and FifoSpinLock NULL. The bus driver passes the request packet in the NOTIFICATION_INFO parameter of the driver's notification routine (passed in u.AllocateAddressRange.Callback). The device driver must provide the response packet. See NOTIFICATION_INFO.

The NOTIFY_FLAGS_XXX flags are ignored. The bus driver ignores the setting of u.AllocateAddressRange.MaxSegmentSize, and always returns a contiguous range of addresses.

Drivers can submit this setting of REQUEST_ALLOCATE_ADDRESS_RANGE at any IRQL.

REQUEST_ALLOCATE_ADDRESS_RANGE can be submitted through IoCallDriver at any IRQL, with one exception. If the driver receives no notification (u.AllocateAddressRange.Mdl is non-NULL and u.AllocateAddressRange.fulNotificationFlags is NOTIFY_FLAGS_NEVER), then the request can only be submitted through IoCallDriver at PASSIVE_LEVEL.

In this specific circumstance, the driver can submit the request through an alternative method, the port driver's physical mapping routine. The device driver can hand off the IRB directly to the physical mapping routine. Drivers can get a pointer to the physical mapping routine by submitting the REQUEST_GET_LOCAL_HOST_INFO bus request with nLevel = GET_PHYS_ADDR_ROUTINE. See GET_LOCAL_HOST_INFO4 for details.

The following table explains how to submit the request at different IRQLs.

Notification? | DISPATCH_LEVEL | Below DISPATCH_LEVEL
yes | IoCallDriver | IoCallDriver
no | Port driver's physical mapping routine | IoCallDriver


REQUEST_ASYNC_LOCK

The REQUEST_ASYNC_LOCK request performs an asynchronous lock operation to the device specified.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      IO_ADDRESS    DestinationAddress;
      ULONG         nNumberOfArgBytes;
      ULONG         nNumberOfDataBytes;
      ULONG         fulTransactionType;
      ULONG         fulFlags;
      ULONG         Arguments[2];
      ULONG         DataValues[2];
      PVOID         pBuffer;
      ULONG         ulGeneration;
      UCHAR         chPriority;
      UCHAR         nSpeed;
      UCHAR         tCode;
      ULONG         Reserved;
    } AsyncLock;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_ASYNC_LOCK
u.AsyncLock.DestinationAddress
Specifies the 1394 64-bit destination address for this read operation. The driver only needs to fill in the IA_Destination_Offset member of u.AsyncLock.DestinationAddress; the bus driver will fill in the IA_Destination_ID member. See IO_ADDRESS for the structure description.
u.AsyncLock.nNumberOfArgBytes
Specifies the number of argument bytes used in performing this lock operation. May be zero, 4 or 8. See the u.AsyncLock.fulTransactionType member for details.
u.AsyncLock.nNumberOfDataBytes
Specifies the number of data bytes used in performing this lock operation. May be 4 or 8. See the u.AsyncLock.fulTransactionType member for details.
u.AsyncLock.fulTransactionType
Specifies which atomic transaction to execute on the 1394 node. The following function types are supported:
fulTransactionType | Description
LOCK_TRANSACTION_MASK_SWAP | For each bit in the original value and the matching argument, reset the bit to be the same as the corresponding bit in the data value. The nNumberOfArgBytes and nNumberOfDataBytes members of u.AsyncLock must be the same.
LOCK_TRANSACTION_COMPARE_SWAP | If the original value and argument match, replace the original value with the data value. The nNumberOfArgBytes and nNumberOfDataBytes members of u.AsyncLock must be the same.
LOCK_TRANSACTION_FETCH_ADD | Add the data value to the original value. Big-endian addition is performed. The argument value is not used and the nNumberOfArgBytes member of u.AsyncLock must be zero.
LOCK_TRANSACTION_LITTLE_ADD | Add the data value to the original value. Little-endian addition is performed. The argument value is not used and the nNumberOfArgBytes member of u.AsyncLock must be zero.
LOCK_TRANSACTION_BOUNDED_ADD | If the original value and the argument differ, add the data value to the original value. The nNumberOfArgBytes and nNumberOfDataBytes members of u.AsyncLock must be the same.
LOCK_TRANSACTION_WRAP_ADD | If the original value and the argument differ, add the data value to original value. Otherwise, replace the original value with the data value. The nNumberOfArgBytes and nNumberOfDataBytes members of u.AsyncLock must be the same.

u.AsyncLock.fulFlags
Not currently used. Drivers should set this to zero.
u.AsyncLock.Arguments
Specifies the arguments used in this lock operation.
u.AsyncLock.DataValues
Specifies the data values used in this lock operation.
u.AsyncLock.pBuffer
Pointer to a buffer that receives lock data values which are returned from the node. The size of the buffer must be at least equal to the u.AsyncLock.nNumberOfDataBytes member.
u.AsyncLock.ulGeneration
Specifies the bus reset generation as known by the device driver who submitted this asynchronous request. If the generation count specified does not match the actual generation of the bus, then this request is returned with an error.
u.AsyncLock.chPriority
Reserved.
u.AsyncLock.nSpeed
Reserved.
u.AsyncLock.tCode
Reserved.
u.AsyncLock.Reserved
Reserved.

IRB Output

u.AsyncLock.pBuffer
Pointer to a buffer that the bus driver has filled in with the lock data values returned from the node.

I/O Status Block

If successful, the bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS. If u.AsyncLock.ulGeneration does not match the current bus reset generation count, the bus driver sets Irp->IoStatus.Status as STATUS_INVALID_GENERATION.

Operation

An asynchronous lock request performs an atomic operation in the node's address space. The value of the u.AsyncLock.fulTransactionType member determines the operation performed. The original value at the location given by the u.AsyncLock.DestinationAddress and the argument (in u.AsyncLock.Arguments) are compared, and depending on the outcome and the transaction type, the data value in u.AsyncLock.DataValues is used to update the original value. If the lock succeeds, the old value stored at the destination address is returned in the buffer pointed to by u.AsyncLock.pBuffer. If the lock fails, the new value is returned.


REQUEST_ASYNC_READ

The REQUEST_ASYNC_READ request performs an asynchronous read operation to the device specified.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      IO_ADDRESS    DestinationAddress;
      ULONG         nNumberOfBytesToRead;
      ULONG         nBlockSize;
      ULONG         fulFlags;
      PMDL          Mdl;
      ULONG         ulGeneration;
      UCHAR         chPriority;
      UCHAR         nSpeed;
      UCHAR         tCode;
      ULONG         Reserved;
      ULONG         ElapsedTime;
    } AsyncRead;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_ASYNC_READ
u.AsyncRead.DestinationAddress
Specifies the 1394 64-bit destination address for this read operation. The driver only needs to fill in the IA_Destination_Offset member of DestinationAddress; the bus driver will fill in the IA_Destination_ID member. See IO_ADDRESS for the structure description.
u.AsyncRead.nNumberOfBytesToRead
Specifies the number of bytes to be read from the 1394 node.
u.AsyncRead.nBlockSize
Specifies the size of each individual block within the data stream that is read as a whole from the 1394 node. If this parameter is zero, the maximum packet size for the device and speed selected is used to issue these read requests.
u.AsyncRead.fulFlags
Specifies any non-default settings for this operation. The following flags are provided:
Flag | Description
ASYNC_FLAGS_NONINCREMENTING | When the bus driver splits the request into blocks, begin the operation for each block at the same address, rather than treating each block as consecutive sections of the device's address space. Used only in asynchronous requests larger than u.AsyncRead.nBlockSize or the maximum packet size for the current speed
ASYNC_FLAGS_PING | The bus driver returns the elapsed time of the operation in u.AsyncRead.ElapsedTime.

u.AsyncRead.Mdl
Pointer to an MDL that describes the device driver's buffer, which receives data from the 1394 node.
u.AsyncRead.ulGeneration
Specifies the bus reset generation as known by the device driver that submits this asynchronous request. If the generation count specified does not match the actual generation of the bus, this request is returned with an error of STATUS_INVALID_GENERATION.
u.AsyncRead.chPriority
Reserved. Drivers must set this to zero.
u.AsyncRead.nSpeed
Reserved. Drivers must set this to zero.
u.AsyncRead.tCode
Reserved. Drivers must set this to zero.
u.AsyncRead.Reserved
Reserved. Drivers must set this to zero.

IRB Output

u.AsyncRead.ElapsedTime
If the driver specifies the ASYNC_FLAGS_PING flag, the bus driver returns the time required, in nanoseconds, to complete the read request.

I/O Status Block

If successful, the bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS. If u.AsyncLock.ulGeneration does not match the current bus reset generation count, the bus driver sets Irp->IoStatus.Status as STATUS_INVALID_GENERATION.

Operation

A REQUEST_ASYNC_READ request will read from the device's address space, beginning at the AddressOffset member of u.AsyncRead.DestinationAddress. The buffer will be broken up into blocks, and one block will be read per transaction. If the ASYNC_FLAGS_NONINCREMENTING flag is set, the driver reads each block beginning at u.AsyncRead.DestinationAddress; otherwise it will read each block from successive regions in the device's memory address space.

The IEEE 1394-1995 Specification constrains the size of reads to be ASYNC_PAYLOAD_xxx_RATE, where xxx is the approximate connection speed in megabits per second. (The speeds allowed are 100, 200, and 400 Mb/s.)

Payload Rate | Description
ASYNC_PAYLOAD_100_RATE | 100 Mb/s
ASYNC_PAYLOAD_200_RATE | 200 Mb/s
ASYNC_PAYLOAD_400_RATE | 400 Mb/s

If the block size exceeds the maximum payload size, the payload size will be used as the block size.

The size of packets may also be constrained by the device itself. The device reports the maximum packet size in the MAX_REC field of its configuration ROM. If this value is smaller than requested block size and the maximum payload size, the bus driver uses this as the block size.


REQUEST_ASYNC_STREAM

The REQUEST_ASYNC_STREAM request writes packets to an isochronous channel, during the asynchronous phase of the IEEE 1394 bus.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      ULONG           nNumberOfBytesToStream;
      ULONG           fulFlags;
      PMDL            Mdl;
      ULONG           ulTag;
      ULONG           nChannel;
      ULONG           ulSynch;
      ULONG           Reserved;
      UCHAR           nSpeed;
    } AsyncStream;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_ASYNC_STREAM.
u.AsyncStream.nNumberOfBytesToStream
Specifies the number of bytes to write.
u.AsyncStream.fulFlags
Reserved. Drivers must set this to zero.
u.AsyncStream.Mdl
Specifies the source buffer.
u.AsyncStream.ulTag
Specifies the Tag field for any packets generated from this request.
u.AsyncStream.nChannel
Specifies the channel to which the data will be written.
u.AsyncStream.ulSynch
Specifies the Sy field for any packets generated from this request.
u.AsyncStream.Reserved
Reserved. Drivers must set this to zero.
u.AsyncStream.nSpeed
Specifies the transfer rate. The possible speed values are SPEED_FLAGS_xxx, where xxx is the (approximate) transfer rate in megabits per second. Existing hardware currently supports transfer rates of 100, 200, and 400 Mb/sec.
Transfer Rate | Description
SPEED_FLAGS_100 | 100 Mb/s
SPEED_FLAGS_200 | 200 Mb/s
SPEED_FLAGS_400 | 400 Mb/s

I/O Status Block

The bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS on success. The bus driver forwards the IRP to the port driver by means of IoCallDriver, and in case of failure sets Irp->IoStatus.Status to the error status returned by IoCallDriver. See IoCallDriver for a description of the error codes it returns.

Operation

Since the packet is sent during the asynchronous phase of the bus cycle, it does not have a guaranteed bandwidth and, therefore, it lacks a guaranteed delivery time.


REQUEST_ASYNC_WRITE

The REQUEST_ASYNC_WRITE request performs an asynchronous write operation to the device specified.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      IO_ADDRESS    DestinationAddress;
      ULONG         nNumberOfBytesToWrite;
      ULONG         nBlockSize;
      ULONG         fulFlags;
      PMDL          Mdl;
      ULONG         ulGeneration;
      UCHAR         chPriority;
      UCHAR         nSpeed;
      UCHAR         tCode;
      ULONG         Reserved;
    } AsyncWrite;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_ASYNC_WRITE
u.AsyncWrite.DestinationAddress
Specifies the 1394 64-bit destination address for this read operation. The driver only must fill in the IA_Destination_Offset member of u.AsyncWrite.DestinationAddress; the bus driver will fill in the IA_Destination_ID member. See IO_ADDRESS for the structure description.
u.AsyncWrite.nNumberOfBytesToWrite
Specifies the number of bytes to write to the 1394 node.
u.AsyncWrite.nBlockSize
Specifies the size of each individual block within the data stream that is written as a whole to the node. If this parameter is zero, then the maximum packet size for the speed selected is used in breaking up these write requests.
u.AsyncWrite.fulFlags
Specifies any non-default settings for this operation. The following flags are provided:
Flag | Description
ASYNC_FLAGS_NONINCREMENTING | Do not increment 1394 address during asynchronous operation. This flag is set only in large asynchronous requests (that is, those greater than asynchronous packet size).
ASYNC_FLAGS_NO_STATUS | Always return success from the write operation, whether the write succeeds or fails.

Use the bit-wise operator OR to combine the settings.

u.AsyncWrite.Mdl
Pointer to an MDL that describes the device driver's buffer, which receives data from the 1394 node.
u.AsyncWrite.ulGeneration

Specifies the bus reset generation as known by the device driver that submitted this asynchronous request. If the generation count specified does not match the actual generation of the bus, this request is returned with a status of STATUS_INVALID_GENERATION.

u.AsyncWrite.chPriority
Reserved.
u.AsyncWrite.nSpeed
Reserved.
u.AsyncWrite.tCode
Reserved.
u.AsyncWrite.Reserved
Reserved.

I/O Status Block

If successful, the bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS. If u.AsyncLock.ulGeneration does not match the current bus reset generation count, the bus driver sets Irp->IoStatus.Status to STATUS_INVALID_GENERATION.

Operation

The REQUEST_ASYNC_WRITE request writes the data buffer into the device's address space, beginning at the u.AsyncWrite.AddressOffset member of u.AsyncWrite.DestinationAddress. The buffer is broken up into blocks, and one block is written for each transaction. If the ASYNC_FLAGS_NONINCREMENTING flag is set, the bus driver will write each block beginning at u.AsyncWrite.DestinationAddress, otherwise it will write the buffer to consecutive addresses in the memory space of the device.

The IEEE 1394-1995 Specification constrains the size of write operations to be ASYNC_PAYLOAD_xxx_RATE, where xxx is the approximate connection speed in megabits per second. (The speeds allowed are 100, 200, and 400 Mb/s.)

Payload Rate | Description
ASYNC_PAYLOAD_100_RATE | 100 Mb/s
ASYNC_PAYLOAD_200_RATE | 200 Mb/s
ASYNC_PAYLOAD_400_RATE | 400 Mb/s

If the block size exceeds the maximum payload size, the payload size will be used as the block size.

The size of packets may also be constrained by the device itself. The device reports the maximum packet size in the MAX_REC field of its configuration ROM. If this value is smaller than requested block size and the maximum payload size, the bus driver uses this as the block size.

The ASYNC_FLAGS_NO_STATUS flag should only be set if the driver has a higher-level error recovery protocol, and should only be used for quadlet-sized writes.


REQUEST_BUS_RESET

The REQUEST_BUS_RESET request initiates an IEEE 1394 bus reset.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      ULONG    fulFlags;
    } BusReset;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_BUS_RESET
u.BusReset.fulFlags
Set this flag to BUS_RESET_FLAGS_FORCE_ROOT to make the local node the root node. All other values indicate that the node is not root.


REQUEST_BUS_RESET_NOTIFICATION

The REQUEST_BUS_RESET_NOTIFICATION request registers (or de-registers) a notification routine to be executed for IEEE 1394 bus resets.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      ULONG                       fulFlags;
      PBUS_BUS_RESET_NOTIFICATION ResetRoutine;
      PVOID                       ResetContext;
    } BusResetNotification;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_BUS_RESET_NOTIFICATION
u.BusResetNotification.fulFlags
Specifies whether a callback should be registered or deactivated. Use REGISTER_NOTIFICATION_ROUTINE to register ResetRoutine as the callback. Use DEREGISTER_NOTIFICATION_ROUTINE to deactivate any previously registered callback.
u.BusResetNotification.ResetRoutine
Pointer to the notification routine for bus resets. The notification routine parameters follow this prototype:
void BusResetNotificationRoutine(IN PVOID Context);
u.BusResetNotification.ResetContext
Specifies the argument to be passed to the notification routine.

I/O Status Block

The bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS on success. If the device object provided in the IRP is the port object then the IRP will fail and the bus driver will set Irp->IoStatus.Status to STATUS_INVALID_PARAMETER.

Operation

The notification routine is called at DISPATCH_LEVEL.


REQUEST_CONTROL

The REQUEST_CONTROL request submits a vendor-specific control request to the port driver.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      ULONG    ulIoControlCode;
      PMDL     pInBuffer;
      ULONG    ulInBufferLength;
      PMDL     pOutBuffer;
      ULONG    ulOutBufferLength;
      ULONG    BytesReturned;
    } Control;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_CONTROL
u.Control.ulIoControlCode
Specifies the control code used in this request. Vendors should make these control codes unique, so that they do not overlap.
u.Control.pInBuffer
Pointer to an MDL that describes the input buffer. The input buffer contains user-defined information.
u.Control.ulInBufferLength
Specifies the length of the input buffer.
u.Control.pOutBuffer
Pointer to an MDL that describes the output buffer. The output buffer contains user-defined information.
u.Control.ulOutBufferLength
Specifies the length of the output buffer.

IRB Output

u.Control.pOutBuffer
The bus driver puts the output of the control request in the buffer described by this MDL.
u.Control.BytesReturned
The length of any data that is returned in pOutBuffer.

I/O Status Block

The bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS on success, or the appropriate error code on failure.

Operation

Vendors interested in defining their own control codes for their host controller should contact Microsoft for a unique IoControlCode. This ensures that the IoControlCode will not overlap with the control codes used by other hardware and software vendors.

Drivers that submit this request must be running at an IRQL of PASSIVE_LEVEL.


REQUEST_FREE_ADDRESS_RANGE

The REQUEST_FREE_ADDRESS_RANGE request releases a 1394 address allocated by REQUEST_ALLOCATE_ADDRESS_RANGE.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      ULONG             nAddressesToFree;
      PADDRESS_RANGE    p1394AddressRange;
      PHANDLE           pAddressRange;
      PVOID             Reserved;
    } FreeAddressRange;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_FREE_ADDRESS_RANGE
u.FreeAddressRange.nAddressesToFree
Specifies the number of entries in pAddressRange.
u.FreeAddressRange.p1394AddressRange
Specifies a pointer to an array of ADDRESS_RANGE data structures to be released. These address ranges were returned in a prior successful call to AllocateAddressRange.
u.FreeAddressRange.pAddressRange
Pointer to the array of handles to free. These handles were returned in a prior successful call to AllocateAddressRange.

I/O Status Block

The bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS on success, or the appropriate error code on failure.


REQUEST_GET_ADDR_FROM_DEVICE_OBJECT

The REQUEST_GET_ADDR_FROM_DEVICE_OBJECT request returns a 1394 node address.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      ULONG           fulFlags;
      NODE_ADDRESS    NodeAddress;
    } Get1394AddressFromDeviceObject;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_GET_ADDR_FROM_DEVICE_OBJECT
u.Get1394AddressFromDeviceObject.fulFlags
Specifies which device's node address we are querying. Zero indicates the calling device. USE_LOCAL_NODE indicates the local host controller.

IRB Output

u.Get1394AddressFromDeviceObject.NodeAddress
Contains the NODE_ADDRESS structure describing the device's node address.

I/O Status Block

The bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS on success, or the appropriate error code on failure.


REQUEST_GET_CONFIGURATION_INFO

The REQUEST_GET_CONFIGURATION_INFO request retrieves configuration information for a device. This information is gathered from the device's IEEE 1394 standard configuration ROM.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      PCONFIG_ROM      ConfigRom;
      ULONG            UnitDirectoryBufferSize;
      PVOID            UnitDirectory;
      IO_ADDRESS       UnitDirectoryLocation;
      ULONG            UnitDependentDirectoryBufferSize;
      PVOID            UnitDependentDirectory;
      IO_ADDRESS       UnitDependentDirectoryLocation;
      ULONG            VendorLeafBufferSize;
      PTEXTUAL_LEAF    VendorLeaf;
      ULONG            ModelLeafBufferSize;
      PTEXTUAL_LEAF    ModelLeaf;
    } GetConfigurationInformation;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_GET_CONFIGURATION_INFO
u.GetConfigurationInformation.ConfigRom
Pointer to the buffer that the bus driver will use to store a copy of the device's configuration ROM. The configuration ROM is defined by the IEEE 1394-1995 Specification.
u.GetConfigurationInformation.UnitDirectoryBufferSize
Specifies the size of the buffer pointed to by the UnitDirectory member of u.GetConfigurationInformation. If the UnitDirectoryBufferSize, UnitDependentDirectoryBufferSize, VendorLeafBufferSize, and ModelLeafBufferSize members of u.GetConfigurationInformation are all zero, on completion the bus driver fills in this member with the minimum buffer size needed to hold all the information.
u.GetConfigurationInformation.UnitDirectory
Pointer to where the bus driver will return the unit directory. See the IEEE 1394-1995 Specification for a description of the internals of the unit directory.
u.GetConfigurationInformation.UnitDependentDirectoryBufferSize
Specifies the size of the buffer pointed to by UnitDependentDirectory member of u.GetConfigurationInformation. If the UnitDirectoryBufferSize, UnitDependentDirectoryBufferSize, VendorLeafBufferSize, and ModelLeafBufferSize members of u.GetConfigurationInformation are all zero, on completion the bus driver fills in this member with the minimum buffer size needed to hold all the information.
u.GetConfigurationInformation.UnitDependentDirectory
Pointer to a buffer that will receives the unit dependent directory, as defined by the IEEE 1394-1995 Specification. See the IEEE 1394-1995 Specification for a description of the internals of the unit directory.
u.GetConfigurationInformation.VendorLeafBufferSize
Specifies the size of the buffer pointed to by VendorLeaf member of u.GetConfigurationInformation. If the UnitDirectoryBufferSize, UnitDependentDirectoryBufferSize, VendorLeafBufferSize, and ModelLeafBufferSize members of u.GetConfigurationInformation are all zero, on completion the bus driver fills in this member with the minimum buffer size needed to hold all the information.
u.GetConfigurationInformation.VendorLeaf
Pointer to a buffer to receive the vendor leaf TEXTUAL_LEAF structure, which describes the device vendor.
u.GetConfigurationInformation.ModelLeafBufferSize
Specifies the size of the buffer pointed to by ModelLeaf member of u.GetConfigurationInformation. If the UnitDirectoryBufferSize, UnitDependentDirectoryBufferSize, VendorLeafBufferSize, and ModelLeafBufferSize members of u.GetConfigurationInformation are all zero, on completion the bus driver fills in this member with the minimum buffer size needed to hold all the information.
u.GetConfigurationInformation.ModelLeaf
Pointer to a buffer to receive the model leaf TEXTUAL_LEAF structure, which describes the device model type.

IRB Output

u.GetConfigurationInformation.ConfigRom
If successful, the bus driver returns the configuration ROM in this buffer. If the UnitDirectoryBufferSize, UnitDependentDirectoryBufferSize, VendorLeafBufferSize, and ModelLeafBufferSize members of u.GetConfigurationInformation are all zero, the bus driver does not use this member.
u.GetConfigurationInformation.UnitDirectoryBufferSize
If the device driver passed zero for the UnitDirectoryBufferSize, UnitDependentDirectoryBufferSize, VendorLeafBufferSize, and ModelLeafBufferSize members of u.GetConfigurationInformation, the bus driver returns the size of the unit directory in this member.
u.GetConfigurationInformation.UnitDirectory
The bus driver returns the unit directory in this buffer, up the number of bytes specified by the device driver in u.GetConfigurationInformation.UnitDirectoryBufferSize.
u.GetConfigurationInformation.UnitDirectoryLocation
Specifies the address in the device's memory space where the unit directory begins. This parameter is useful when pointers are embedded within the unit directory, as these pointers are expressed in quadlet offsets from the current position. Only the IA_Destination_Offset member of the IO_ADDRESS data structure is valid.
u.GetConfigurationInformation.UnitDependentDirectoryBufferSize
If the device driver passed zero for the UnitDirectoryBufferSize, UnitDependentDirectoryBufferSize, VendorLeafBufferSize, and ModelLeafBufferSize members of u.GetConfigurationInformation, the bus driver returns the size of the unit dependent directory in this member.
u.GetConfigurationInformation.UnitDependentDirectory
The bus driver returns the unit dependent directory in this buffer, up the number of bytes specified by the device driver in u.GetConfigurationInformation.UnitDependentDirectoryBufferSize.
u.GetConfigurationInformation.UnitDependentDirectoryLocation
Specifies the 48-bit address where the unit-dependent directory begins. This parameter is useful when pointers are embedded in the unit-dependent directory, since these pointers are expressed in quadlet offsets from the current position. See IO_ADDRESS for the structure description.
u.GetConfigurationInformation.VendorLeafBufferSize
If the device driver passed zero for the UnitDirectoryBufferSize, UnitDependentDirectoryBufferSize, VendorLeafBufferSize, and ModelLeafBufferSize members of u.GetConfigurationInformation, the bus driver returns the size of the vendor leaf in this member.
u.GetConfigurationInformation.VendorLeaf
The bus driver returns the unit directory in this buffer, up the number of bytes specified by the device driver in u.GetConfigurationInformation.VendorLeafBufferSize.
u.GetConfigurationInformation.ModelLeafBufferSize
If the device driver passed zero for the UnitDirectoryBufferSize, UnitDependentDirectoryBufferSize, VendorLeafBufferSize, and ModelLeafBufferSize members of u.GetConfigurationInformation, the bus driver returns the size of the model leaf in this member.
u.GetConfigurationInformation.ModelLeaf
The bus driver returns the unit directory in this buffer, up the number of bytes specified by the device driver in u.GetConfigurationInformation.ModelLeafBufferSize.

I/O Status Block

The bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS on success, or the appropriate error code on failure.


REQUEST_GET_GENERATION_COUNT

The REQUEST_GET_GENERATION_COUNT request retrieves the current bus reset generation. This count is incremented every time the bus is reset. This generation count must be passed in each asynchronous read, write, and lock request that a device driver submits to the 1394 bus driver.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      ULONG    GenerationCount;
    } GetGenerationCount;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_GET_GENERATION_COUNT

IRB Output

u.GetGenerationCount.GenerationCount
Specifies the current generation count.

I/O Status Block

The bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS on success, or the appropriate error code on failure.


REQUEST_GET_LOCAL_HOST_INFO

The REQUEST_GET_LOCAL_HOST_INFO request returns information about the local node's host controller.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      ULONG    nLevel;
      PVOID    Information;
    } GetLocalHostInformation;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_GET_LOCAL_HOST_INFO
u.GetLocalHostInformation.nLevel
Specifies what level of information is desired from this call. The following flags are provided.
Flag | Description
GET_HOST_UNIQUE_ID | Requests the port driver to return the 64-bit unique identifier.
GET_HOST_CAPABILITIES | Requests the port driver to return the host controller's capability flags.
GET_POWER_SUPPLIED | Requests the port driver to return the bus' power characteristics.
GET_PHYS_ADDR_ROUTINE | Requests the port driver to return the host controller's physical address mapping function.
GET_HOST_CONFIG_ROM | Requests the port driver to return the host controller's configuration ROM.
GET_HOST_CSR_CONTENTS | Requests the port driver to return the speed or topology maps from the host controller's CSR. See the IEEE 1394 Specification for a description of CSRs.
GET_HOST_DMA_CAPABILITIES | Requests the port driver to return the host controller's capability flags and the size of the DMA buffer (PAGESIZE multiplied by the number of mapping registers).

u.GetLocalHostInformation.Information
Pointer to an information block to be filled in, depending on what level of information is desired. Each block has its own particular structure:
Flag | Structure
GET_HOST_UNIQUE_ID | GET_LOCAL_HOST_INFO1
GET_HOST_CAPABILITIES | GET_LOCAL_HOST_INFO2
GET_POWER_SUPPLIED | GET_LOCAL_HOST_INFO3
GET_PHYS_ADDR_ROUTINE | GET_LOCAL_HOST_INFO4
GET_HOST_CONFIG_ROM | GET_LOCAL_HOST_INFO5
GET_HOST_CSR_CONTENTS | GET_LOCAL_HOST_INFO6

IRB Output

u.GetLocalHostInformation.Information
Pointer to the information block, with the requested information filled in.

I/O Status Block

The bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS on success, or the appropriate error code on failure.


REQUEST_GET_SPEED_BETWEEN_DEVICES

The REQUEST_GET_SPEED_BETWEEN_DEVICES request returns the maximum (simultaneous) transfer speed that can be used from one source device to a set of destination devices.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      ULONG             fulFlags;
      ULONG             ulNumberOfDestinations;
      PDEVICE_OBJECT    hDestinationDeviceObjects[64];
      ULONG             fulSpeed;
    } GetMaxSpeedBetweenDevices;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_GET_SPEED_BETWEEN_DEVICES
u.GetMaxSpeedBetweenDevices.fulFlags
Specifies the source device. Zero indicates the calling device. USE_LOCAL_NODE indicates the computer itself.
u.GetMaxSpeedBetweenDevices.ulNumberOfDestinations
Specifies the number of destination devices.
u.GetMaxSpeedBetweenDevices.hDestinationDeviceObjects
Pointer to an array of the device objects of the destination devices.

IRB Output

u.GetMaxSpeedBetweenDevices.fulSpeed
Specifies the maximum possible transaction speed between the source device and the set of destination devices. The value returned is the maximum speed supported by all the devices simultaneously. The possible speed values are SPEED_FLAGS_xxx, where xxx is the (approximate) transfer rate in megabits per second. Existing hardware supports transfer rates of 100, 200, and 400 Mb/sec.
Transfer Rate | Description
SPEED_FLAGS_100 | 100 Mb/s
SPEED_FLAGS_200 | 200 Mb/s
SPEED_FLAGS_400 | 400 Mb/s

I/O Status Block

If successful, the bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS.


REQUEST_GET_SPEED_TOPOLOGY_MAPS

The REQUEST_GET_SPEED_TOPOLOGY_MAPS request returns the IEEE 1394 bus speed and topology maps. On Windows 2000 and later platforms, this request is obsolete.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      PSPEED_MAP       SpeedMap;
      PTOPOLOGY_MAP    TopologyMap;
    } GetSpeedTopologyMaps;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_GET_SPEED_TOPOLOGY_MAPS

IRB Output

u.GetSpeedTopologyMaps.SpeedMap
Pointer to the bus' SPEED_MAP structure. This member is filled on completion.
u.GetSpeedTopologyMaps.TopologyMap
Pointer to the bus' TOPOLOGY_MAP structure. The topology map will be in big-endian, irrespective of the byte order of the local node. This member is filled on completion.

I/O Status Block

The bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS on success, or the appropriate error code on failure.

Operation

On Windows 2000 and later platforms use GET_LOCAL_HOST_INFO with u.GetLocalHostInformation.nLevel = GET_HOST_CSR_CONTENTS.


REQUEST_ISOCH_ALLOCATE_BANDWIDTH

The REQUEST_ISOCH_ALLOCATE_BANDWIDTH request allocates isochronous bandwidth to be used in subsequent operations.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      ULONG     nMaxBytesPerFrameRequested;
      ULONG     fulSpeed;
      HANDLE    hBandwidth;
      ULONG     BytesPerFrameAvailable;
      ULONG     SpeedSelected;
    } IsochAllocateBandwidth;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_ISOCH_ALLOCATE_BANDWIDTH
u.IsochAllocateBandwidth.nMaxBytesPerFrameRequested
Specifies the bandwidth requested, in bytes per isochronous frame. If the host controller is configured to strip away the packet headers, the device driver does not need to include the packet header size in the number of bytes requested. The driver also does not need to round the value up to the nearest quadlet.
u.IsochAllocateBandwidth.fulSpeed
Specifies the connection speed to use in allocating bandwidth. The possible speed values are SPEED_FLAGS_xxx, where xxx is the (approximate) transfer rate in megabits per second. Existing hardware supports transfer rates of 100, 200, and 400 Mb/sec.
Transfer Rate | Description
SPEED_FLAGS_100 | 100 Mb/s
SPEED_FLAGS_200 | 200 Mb/s
SPEED_FLAGS_400 | 400 Mb/s

IRB Output

u.IsochAllocateBandwidth.hBandwidth
Specifies the handle to use to refer to the bandwidth resource.
u.IsochAllocateBandwidth.BytesPerFrameAvailable
Specifies the bytes per frame that are available after the allocation attempt. Drivers should not rely on this bandwidth being available, since another device may allocate or deallocate bandwidth at any time. The bus driver fills in this member, even if the request fails.
u.IsochAllocateBandwidth.SpeedSelected
Specifies the actual speed selected in allocating bandwidth. The value is one of SPEED_FLAGS_xxx (see the fulSpeed member description above).

I/O Status Block

If the bus driver successfully allocates the bandwidth, it sets Irp->IoStatus.Status to STATUS_SUCCESS. If it defers the request, it returns STATUS_PENDING. Otherwise it sets the appropriate error status.

Operation

Once the device driver no longer needs allocated bandwidth, it must deallocate it with the REQUEST_ISOCH_FREE_BANDWIDTH request.

On Windows 2000 and later, this request may be submitted at all IRQL levels.


REQUEST_ISOCH_ALLOCATE_CHANNEL

The REQUEST_ISOCH_ALLOCATE_CHANNEL request allocates an isochronous channel to be used in subsequent operations.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      ULONG            nRequestedChannel;
      ULONG            Channel;
      LARGE_INTEGER    ChannelsAvailable;
    } IsochAllocateChannel;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_ISOCH_ALLOCATE_CHANNEL
u.IsochAllocateChannel.nRequestedChannel
Specifies the particular channel to allocate, or ISOCH_ANY_CHANNEL for an arbitrary channel.

IRB Output

u.IsochAllocateChannel.Channel
Specifies the channel allocated, if the request succeeds.
u.IsochAllocateChannel.ChannelsAvailable
Specifies a bitmap of the available isochronous channels after the channel allocation attempt. Drivers should not rely on this information, since another device may allocate or deallocate channels at any time. The bus driver fills in this member, even if the request fails.

I/O Status Block

The bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS if it successfully allocates the channel, or otherwise to the appropriate error status.

Operation

Once a channel is no longer needed, it should be deallocated using the REQUEST_ISOCH_FREE_CHANNEL request.

Drivers that submit this request must be running at an IRQL of PASSIVE_LEVEL.


REQUEST_ISOCH_ALLOCATE_RESOURCES

The REQUEST_ISOCH_ALLOCATE_RESOURCES request allocates a resource handle for transactions over a given isochronous channel. The device driver will use the resource handle to attach and detach data buffers for isochronous transactions on that channel.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      ULONG    fulSpeed;
      ULONG    fulFlags;
      ULONG    nChannel;
      ULONG    nMaxBytesPerFrame;
      ULONG    nNumberOfBuffers;
      ULONG    nMaxBufferSize;
      ULONG    nQuadletsToStrip;
      HANDLE    hResource;
      ULARGE_INTEGER    ChannelMask
    } IsochAllocateResources;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_ISOCH_ALLOCATE_RESOURCES
u.IsochAllocateResources.fulSpeed
Specifies the connection speed to use for communication on the channel. The possible speed values are SPEED_FLAGS_xxx, where xxx is the (approximate) transfer rate in megabits per second. Existing hardware supports transfer rates of 100, 200, and 400 Mb/sec.
Transfer Rate | Description
SPEED_FLAGS_100 | 100 Mb/s
SPEED_FLAGS_200 | 200 Mb/s
SPEED_FLAGS_400 | 400 Mb/s
u.IsochAllocateResources.fulFlags
Specifies how the bus driver should use any buffers attached to the resource handle. Many of the flags specify how the bus driver should configure the IEEE host controller for DMA from or to attached buffers.

Flag | Description
RESOURCE_USED_IN_LISTENING | Attached buffers will be used to read data from an isochronous channel. Set this if the resource handle will be used in a REQUEST_ISOCH_LISTEN request.
RESOURCE_USED_IN_TALKING | Attached buffers will be used to write data to an isochronous channel. Set this if the resource handle will be used in a REQUEST_ISOCH_TALK request.
RESOURCE_BUFFERS_CIRCULAR | When the host controller uses up the current supply of attached buffers, it will continue the operation beginning again with the first buffer attached. When the isochronous transaction is in progress, the device driver must not attach or detach buffers on the resource handle.
RESOURCE_STRIP_ADDITIONAL_
QUADLETS 		The bus driver will configure the host controller to strip additional quadlets from incoming isochronous packets. The number of quadlets to be stripped is specified in nQuadletsToStrip.
RESOURCE_SYNCH_ON_TIME | The bus driver will configure the host controller to synchronize the beginning of the isochronous transaction to the CYCLE_TIME specified in the StartTime member of the request's IRB. See REQUEST_ISOCH_LISTEN or REQUEST_ISOCH_TALK.
RESOURCE_USE_PACKET_BASED | Used to switch to packet-based transfer, rather than the default. The default is stream-based transfer, unless the host controller only supports packet-based DMA.
RESOURCE_USE_MULTICHANNEL | The driver owning this resource will listen on multiple channels.

u.IsochAllocateResources.nChannel
Specifies the isochronous channel for all transactions involving the resource handle allocated by this request.
u.IsochAllocateResources.nMaxBytesPerFrame
Specifies the expected maximum isochronous frame size while transmitting and receiving on the channel..
u.IsochAllocateResources.nNumberOfBuffers
Specifies one more than the maximum expected number of buffers that are attached to the resource handle at any given time. If the RESOURCE_BUFFERS_CIRCULAR flag is specified, then nNumberOfBuffers specifies the total number of buffers attached to the resource handle, instead of the average number at any given time.
u.IsochAllocateResources.nMaxBufferSize
Specifies the maximum size of the buffers that are attached to the resource handle.
u.IsochAllocateResources.nQuadletsToStrip
Specifies the number of quadlets to strip from the beginning of every packet in an incoming isochronous stream. This parameter is ignored unless the device driver sets the RESOURCE_STRIP_ADDITIONAL_QUADLETS flag in u.IsochAllocateResources.fulFlags.
u.IsochAllocateResources.ChannelMask
Specifies a set of isochronous channels, if RESOURCE_USE_MULTICHANNEL is set, that are used for all transactions involving the resource handle allocated by this request.

IRB Output

u.IsochAllocateResources.hResource
Specifies the resource handle the device driver uses to attach or detach data buffers for isochronous transactions on the channel specified in nChannel.

I/O Status Block

The bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS, if it processes the request successfully, or to the appropriate error code.

Operation

Not all RESOURCE_XXX flags are supported. Some require hardware support from the IEEE 1394 host controller. The device driver can use the REQUEST_GET_LOCAL_HOST_INFO request, with nLevel = GET_HOST_CAPABILITIES, to determine which RESOURCE_XXX flags are supported. The bus driver returns a pointer to a GET_LOCAL_HOST_INFO2 structure, whose HostCapabilities member contains flags that determine which flags the host controller supports. The following table lists which RESOURCE_XXX flags require hardware support, and the corresponding HostCapabilities flag the driver should check:

RESOURCE_XXX flags | HostCapabilities flag
RESOURCE_STRIP _ADDITIONAL_QUADLETS | HOST_INFO_SUPPORTS _ISOCH_STRIPPING
RESOURCE_SYNCH_ON_TIME | HOST_INFO_SUPPORTS _START_ON_CYCLE
RESOURCE_USE_PACKET _BASED | HOST_INFO_PACKET_BASED

The default method of transmission for isochronous reads is stream-based: data is read until it fills the buffer, and then the bus driver begins filling the next buffer. If the RESOURCE_USE_PACKET_BASED flag is set, the bus driver uses a packet-based method of storing data: each packet is put in its own buffer and no attempt is made to fill each buffer. A particular host controller may only support packet-based or stream-based reads. Drivers should use the REQUEST_GET_LOCAL_HOST_INFO request to determine what the host controller supports.

Not all host controllers automatically strip off the packet header. Use the REQUEST_GET_LOCAL_HOST_INFO request to determine if the host controller automatically strips the packet header. This request will also determine if the host controller can be configured to strip quadlets from the beginning of each packet. Many host controllers can be configured to automatically strip off the packet header. Try setting the RESOURCE_STRIP_ADDITIONAL_QUADLETS flag and setting nQuadletsToStrip to 1.

Set the RESOURCE_SYNCH_ON_TIME to synchronize the beginning of I/O to the StartTime member of the REQUEST_ISOCH_LISTEN or REQUEST_ISOCH_TALK request. Use the REQUEST_GET_LOCAL_HOST_INFO request to determine if the host controller supports synchronization on an isochronous cycle time. Additional synchronization options can be set with each buffer attached; see the ISOCH_DESCRIPTOR member of the REQUEST_ISOCH_ATTACH_BUFFERS for details.

A multichannel resource must be stream-based and drivers can only use multichannel resources to read, not to write data. Therefore, if the RESOURCE_USE_MULTICHANNEL flag is set, the RESOURCE_USE_PACKET_BASED and RESOURCE_USED_IN_LISTENING flags must also be set. If the RESOURCE_USE_MULTICHANNEL flag is set, the bus driver ignores the u.IsochAllocateResources.nChannel member and assigns the channels defined in u.IsochAllocateResources.ChannelMask to the resource.

Drivers that submit this request must be running at an IRQL of PASSIVE_LEVEL.


REQUEST_ISOCH_ATTACH_BUFFERS

The REQUEST_ISOCH_ATTACH_BUFFERS request attaches an array of buffers to an isochronous resource handle.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      HANDLE               hResource;
      ULONG                nNumberOfDescriptors;
      PISOCH_DESCRIPTOR    pIsochDescriptor;
    } IsochAttachBuffers;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_ISOCH_ATTACH_BUFFERS
u.IsochAttachBuffers.hResource
Specifies the resource handle to attach buffers to.
u.IsochAllocateResources.nNumberOfDescriptors
Specifies the number of elements in the pIsochDescriptor array.
u.IsochAllocateResources.pIsochDescriptor
Pointer to an array of ISOCH_DESCRIPTOR structures that describe the buffers to be attached, and the parameters that specify how each buffer is to be used.

I/O Status Block

The bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS, if it processes the request successfully, or to the appropriate error code.

Operation

Once a buffer is no longer in use, the device driver must detach it from the resource handle by using the REQUEST_ISOCH_DETACH_BUFFERS request.


REQUEST_ISOCH_DETACH_BUFFERS

The REQUEST_ISOCH_DETACH_BUFFERS request detaches an array of buffers from an isochronous resource handle.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      HANDLE               hResource;
      ULONG                nNumberOfDescriptors;
      PISOCH_DESCRIPTOR    pIsochDescriptor;
    } IsochDetachBuffers;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_ISOCH_DETACH_BUFFERS
u.IsochAttachBuffers.hResource
Specifies the resource handle to detach buffers from.
u.IsochAllocateResources.nNumberOfDescriptors
Specifies the number of elements in the pIsochDescriptor array.
u.IsochAllocateResources.pIsochDescriptor
Pointer to an array of ISOCH_DESCRIPTOR structures that describe the buffers to be detached. The device driver should use the same ISOCH_DESCRIPTOR structure for a buffer that it used to attach the buffer.

I/O Status Block

The bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS, if it processes the request successfully, or to the appropriate error code.


REQUEST_ISOCH_FREE_BANDWIDTH

The REQUEST_ISOCH_FREE_BANDWIDTH request releases isochronous bandwidth that was allocated through a REQUEST_ISOCH_ALLOCATE_BANDWIDTH request.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      HANDLE    hBandwidth;
    } IsochFreeBandwidth;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_ISOCH_FREE_BANDWIDTH
u.IsochFreeBandwidth.hBandwidth
Specifies the bandwidth handle to release.

I/O Status Block

If successful, the bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS, and the isochronous bandwidth is returned to the pool of available bandwidth.

Operation

Drivers that submit this request must be running at an IRQL of PASSIVE_LEVEL.


REQUEST_ISOCH_FREE_CHANNEL

The REQUEST_ISOCH_FREE_CHANNEL request releases an isochronous channel that was allocated through a REQUEST_ISOCH_ALLOCATE_CHANNEL request.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      ULONG    nChannel;
    } IsochFreeChannel;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_ISOCH_FREE_CHANNEL
u.IsochFreeChannel.nChannel
Specifies which allocated channel to release.

I/O Status Block

If successful, the bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS, and the isochronous channel is returned to the pool of available channels.

Operation

Drivers that submit this request must be running at an IRQL of PASSIVE_LEVEL.


REQUEST_ISOCH_FREE_RESOURCES

The REQUEST_ISOCH_FREE_RESOURCES request releases the resource handle that was allocated through the REQUEST_ISOCH_ALLOCATE_RESOURCES request.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      HANDLE    hResource;
    } IsochFreeResources;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_ISOCH_FREE_RESOURCES
u.IsochFreeResources.hResource
Specifies the resource handle to release.

I/O Status Block

The bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS on success. All isochronous buffers that were attached to this resource must be detached prior to issuing this call. If a device driver attempts to free a resource handle with isochronous buffers still attached to it, the handle is not freed and the bus driver returns STATUS_INVALID_PARAMETER instead.

Operation

Drivers that submit this request must be running at an IRQL of PASSIVE_LEVEL.


REQUEST_ISOCH_LISTEN

The device driver issues a REQUEST_ISOCH_LISTEN request to read from an isochronous channel.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      HANDLE        hResource;
      ULONG         fulFlags;
      CYCLE_TIME    StartTime
    } IsochListen;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_ISOCH_LISTEN
u.IsochListen.hResource
Specifies the resource handle to use in reading data.
u.IsochListen.fulFlags
Reserved. Device drivers must set this to zero.
u.IsochListen.StartTime
Specifies the cycle time to begin reading data. This member is used only if the driver specified the RESOURCE_SYNCH_ON_TIME flag when it allocated the resource handle passed in u.IsochListen.hResource. (The timing resolution is per isochronous cycle, so the CycleOffset member of StartTime is not used.)

I/O Status Block

The bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS when it has successfully processed the request, or to the appropriate error code.

Operation

The bus driver completes this request once it has successfully scheduled the isochronous listen operation. It does not wait for the data transfer to finish, or even begin, before it completes the request.

Listening on a channel may begin immediately, or it may be synchronized to an event. If the driver set the RESOURCE_SYNCH_ON_TIME flag on the REQUEST_ISOCH_ALLOCATE_RESOURCES request that returned the resource handle, then the listen will begin on the cycle count specified in StartTime. Additional synchronization options may be set for each buffer within that buffer's ISOCH_DESCRIPTOR structure.


REQUEST_ISOCH_MODIFY_STREAM_PROPERTIES

The ISOCH_MODIFY_STREAM_PROPERTIES is used to dynamically change the properties of an allocated resource, without the need to free and re-allocate the resource.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      HANDLE            hResource;
      ULARGE_INTEGER    ChannelMask;
      ULONG             fulSpeed;
        } IsochModifyStreamProperties;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_ISOCH_MODIFY_STREAM_PROPERTIES
u.IsochModifyStreamProperties.hResource
Handle of the resource whose properties are to be changed..
u.IsochModifyStreamProperties.ChannelMask
New channels to transmit and receive on.
u.IsochModifyStreamProperties.fulSpeed
New speed of the data transfer.

IRB Output

On success the u.IsochModifyStreamProperties.ChannelMask member points to a bitmap of channels for the stream.

I/O Status Block

If successful, the bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS. If the resource passed in the IRP is invalid, then the bus driver sets Irp->IoStatus.Status to STATUS_INVALID_PARAMETER.

Operation

The resource must not be streaming when this request is issued. Before sending this request, caller should send REQUEST_ISOCH_STOP to stop the stream, then after this request is completed, caller can resume the stream with REQUEST_ISOCH_TALK. The sequence should be as follows:

REQUEST_ISOCH_STOP

REQUEST_ISOCH_MODIFY_STREAM_PROPERTIES

REQUEST_ISOCH_TALK

Also, once REQUEST_ISOCH_STOP completes caller should ensure no buffer is pending before sending REQUEST_ISOCH_MODIFY_STREAM_PROPERTIES.


REQUEST_ISOCH_QUERY_CYCLE_TIME

The ISOCH_QUERY_CURRENT_CYCLE_TIME request returns the current isochronous cycle time.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      CYCLE_TIME    CycleTime;
    } IsochQueryCurrentCycleTime;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_ISOCH_QUERY_CYCLE_TIME

IRB Output

u.IsochQueryCurrentCycleTime.CycleTime
On success, specifies the current isochronous cycle time. See the CYCLE_TIME entry for details.

I/O Status Block

If successful, the bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS.


REQUEST_ISOCH_QUERY_RESOURCES

The ISOCH_QUERY_RESOURCES request returns the bandwidth and channels currently available on the IEEE 1394 bus.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      ULONG            fulSpeed;
      ULONG            BytesPerFrameAvailable;
      LARGE_INTEGER    ChannelsAvailable;
    } IsochQueryResources;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_ISOCH_QUERY_RESOURCES
u.IsochQueryResources.fulSpeed
Specifies the speed flag to use in allocating bandwidth. The possible speed values are SPEED_FLAGS_xxx, where xxx is the approximate transfer rate in megabits per second. Existing hardware supports transfer rates of 100, 200, and 400 MBps.

Transfer Rate | Description
SPEED_FLAGS_100 | 100 Mb/s
SPEED_FLAGS_200 | 200 Mb/s
SPEED_FLAGS_400 | 400 Mb/s

IRB Output

u.IsochQueryResources.BytesPerFrameAvailable
On success, specifies the returned available bandwidth as expressed in bytes per isochronous frame.
u.IsochQueryResources.ChannelsAvailable
On success, points to a bitmap of available channels.

I/O Status Block

On success, the bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

Operation

The information returned by this request should not be relied upon; a node on the bus may request or release channels or bandwidth at any time.

Drivers that submit this request must be running at an IRQL of PASSIVE_LEVEL.


REQUEST_ISOCH_SET_CHANNEL_BANDWIDTH

The REQUEST_ISOCH_SET_CHANNEL_BANDWIDTH request resets the bandwidth on an already-allocated bandwidth handle.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      HANDLE    hBandwidth;
      ULONG     nMaxBytesPerFrame;
    } IsochSetChannelBandwidth;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_ISOCH_SET_CHANNEL_BANDWIDTH
u.IsochSetChannelBandwidth.hBandwidth
Bandwidth handle to reset.
u.IsochSetChannelBandwidth.nMaxBytesPerFrame
Specifies the new bandwidth for hBandwidth.

I/O Status Block

If the bus driver successfully resets the bandwidth on hBandwidth, the bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

Operation

This request does not require the caller to know the bandwidth that was allocated when a handle was generated. REQUEST_ISOCH_SET_CHANNEL_BANDWIDTH can be used to readjust the bandwidth on a bandwidth handle whose bytes per frame setting is unknown. Despite its name, this request does not involve isochronous channels in any way.

Drivers that submit this request must be running at an IRQL of PASSIVE_LEVEL.


REQUEST_ISOCH_STOP

The IsochStop request stops all isochronous operations on an isochronous channel.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      HANDLE    hResource;
      ULONG     fulFlags;
    } IsochStop;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_ISOCH_STOP
u.IsochStop.hResource
Specifies the resource handle for the channel on which to stop isochronous operations.
u.IsochStop.fulFlags
Reserved. Device drivers should set this member to zero.

I/O Status Block

On success, the bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS.


REQUEST_ISOCH_TALK

The REQUEST_ISOCH_TALK request begins data transfer on a isochronous channel.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      HANDLE        hResource;
      ULONG         fulFlags;
      CYCLE_TIME    StartTime;
    } IsochTalk;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_ISOCH_TALK
u.IsochTalk.hResource
Specifies the resource handle to use for this operation. Resources are acquired through the REQUEST_ISOCH_ALLOCATE_RESOURCES request.
u.IsochTalk.fulFlags
Reserved. Drivers should set this to zero.
u.IsochTalk.StartTime
Specifies the cycle time to begin operation. This member is used only if the driver specified the RESOURCE_SYNCH_ON_TIME flag when it allocated the resource handle passed in u.IsochTalk.hResource. (The timing resolution is per isochronous cycle, so the CycleOffset member of StartTime is not used.)

I/O Status Block

The bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS when the listening operation has begun, or to the appropriate error status.

Operation

Talking on a channel may begin immediately, or it may be synchronized to an event. If the driver set the RESOURCE_SYNCH_ON_TIME flag on the REQUEST_ISOCH_ALLOCATE_RESOURCES request that returned the resource handle, then the write operation will begin on the specified cycle count. Additional synchronization options can be set for each buffer in the ISOCH_DESCRIPTOR structure.

If successful, the request returns a STATUS_SUCCESS value. The call returns immediately, and does not wait for any synchronization events. The bus driver calls the callback the driver provides in ISOCH_DESCRIPTOR to signal that it has finished processing an attached buffer.


REQUEST_SEND_PHY_CONFIG_PACKET

The REQUEST_SEND_PHY_CONFIG_PACKET request sends a Phy configuration packet to the bus. A raw packet is sent out, with no checks performed.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      PHY_CONFIGURATION_PACKET    PhyConfigurationPacket;
    } SendPhyConfigurationPacket;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_SEND_PHY_CONFIG_PACKET
u.SendPhyConfigurationPacket.PhyConfigurationPacket
Pointer to the PHY_CONFIGURATION_PACKET structure.

I/O Status Block

The bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS on success, or the appropriate error code on failure.

Operation

The packet is sent to all nodes on the bus. See the IEEE 1394 Specification for a description of Phy packets.


REQUEST_SET_DEVICE_XMIT_PROPERTIES

The REQUEST_SET_DEVICE_XMIT_PROPERTIES request sets the maximum speed that is used to transmit requests to a particular device.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG FunctionNumber;
    .
    .
    .
  union {
    struct {
      ULONG    fulSpeed;
      ULONG    fulPriority;
    } SetDeviceXmitProperties;
    .
    .
    .
  } u;
} IRB;

IRB Input

FunctionNumber
REQUEST_SET_DEVICE_XMIT_PROPERTIES
u.SetDeviceXmitProperties.fulSpeed
Specifies the maximum speed for transactions to the device. The possible speed values are SPEED_FLAGS_xxx, where xxx is the (approximate) transfer rate in megabits per second. Existing hardware supports transfer rates of 100, 200, and 400 Mb/sec.
Transfer Rate | Description
SPEED_FLAGS_100 | 100 Mb/s
SPEED_FLAGS_200 | 200 Mb/s
SPEED_FLAGS_400 | 400 Mb/s
u.SetDeviceXmitProperties.fulPriority
Reserved.

I/O Status Block

The bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS on success, or the appropriate error code on failure.

Operation

By default, the maximum permitted transmission speed is the physical maximum. A driver should use this request to lower the maximum permitted speed.


REQUEST_SET_LOCAL_HOST_PROPERTIES

The REQUEST_SET_LOCAL_HOST_PROPERTIES request sets properties of the local host.

The relevant members of the IRB for this request are:

typedef struct _IRB {
  ULONG  FunctionNumber;
    .
    .
    .
  union {
    struct {
      ULONG  nLevel;
      PVOID  Information;
    } SetLocalHostProperties;
    .
    .
    .
  } u;
} IRB;

Input Parameters

FunctionNumber
REQUEST_SET_LOCAL_HOST_PROPERTIES
u.SetLocalHostProperties.nLevel
Specifies what level of information is desired from this call. The following flags are provided.
Flag | Description
SET_LOCAL_HOST_PROPERTIES_GAP_COUNT | Sets a lower bound on the value the bus will use for its gap count. See the IEEE 1394-1995 Specification for a description of the gap count.
SET_LOCAL_HOST_PROPERTIES_MODIFY_CROM | Used to add or remove unit directories. This request can not be used to modify instance directories or root keys in the configuration ROM.

u.SetLocalHostProperties.Information
Pointer to an information block to be filled in. The information returned depends on the value in u.SetLocalHostProperties.nLevel. Each block has its own particular structure:
Flag | Structure
SET_LOCAL_HOST_PROPERTIES_GAP_COUNT | SET_LOCAL_HOST_PROPS2
SET_LOCAL_HOST_PROPERTIES_MODIFY_CROM | SET_LOCAL_HOST_PROPS3

I/O Status Block

The bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS on success, or the appropriate error code on failure.

See Also

SET_LOCAL_HOST_PROPS2,

SET_LOCAL_HOST_PROPS3


IOCTL_IEEE1394_API_REQUEST

Operation

An IEEE 1394 driver uses the IRP_MJ_DEVICE_CONTROL IRP, with IoControlCode IOCTL_IEEE1394_API_REQUEST, to dynamically add or remove a virtual 1394 device.

Input

AssocicatedIrp.SystemBuffer->SystemBuffer points to an IEEE1394_API_REQUEST structure. The RequestNumber member of the IEEE1394_API_REQUEST structure specifies the type of request. The u member of the IEEE1394_API_REQUEST structure is a union that specifies the request-type-specific parameters of the request. The parameters and their meaning are documented with each request.

Parameters.DeviceIoControl.InputBufferLength provides the length of the input buffer.

Legal requests are as follows:

IEEE1394_API_ADD_VIRTUAL_DEVICE

IEEE1394_API_REMOVE_VIRTUAL_DEVICE

Output

AssocicatedIrp.SystemBuffer->SystemBuffer points to the IEEE1394_API_REQUEST structure passed as input. As part of completing the request, the bus driver fills in certain members of the u member with information for the driver. The returned information is documented with each request.

I/O Status Block

The information the bus driver returns in the I/O Status Block is documented with each request.

See Also

IEEE1394_API_REQUEST

IEEE1394_VDEV_PNP_REQUEST

IEEE1394_API_ADD_VIRTUAL_DEVICE

IEEE1394_API_REMOVE_VIRTUAL_DEVICE


IEEE1394_API_ADD_VIRTUAL_DEVICE

Operation

This request creates a virtual device and adds it to the 1394 device stack.

The relevant members of the IEEE1394_API_REQUEST structure for this request are:

typedef struct _IEEE1394_API_REQUEST {
  ULONG  RequestNumber;
  ULONG  Flags;
  union {
    IEEE1394_VDEV_PNP_REQUEST  AddVirtualDevice;
    .
    .
    .
  } u;
} IEEE1394_API_REQUEST, *PIEEE1394_API_REQUEST;

Input

RequestNumber
IEEE1394_API_REMOVE_VIRTUAL_DEVICE
Flags
See IEEE1394_API_REQUEST for a list of values that can be assigned to Flags.
u.AddVirtualDevice
See IEEE1394_VDEV_PNP_REQUEST for a list of values that can be assigned to AddVirtualDevice.

Output

None.

I/O Status Block

The bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS on success, or the appropriate error code on failure.

See Also

IOCTL_IEEE1394_API_REQUEST

IEEE1394_API_REQUEST

IEEE1394_VDEV_PNP_REQUEST

IEEE1394_API_REMOVE_VIRTUAL_DEVICE


IEEE1394_API_REMOVE_VIRTUAL_DEVICE

Operation

The IEEE1394_API_REMOVE_VIRTUAL_DEVICE request removes a virtual device from the 1394 device stack.

The relevant members of the IEEE1394_API_REQUEST structure for this request are:

typedef struct _IEEE1394_API_REQUEST {
  ULONG  RequestNumber;
  ULONG  Flags;
  union {
    IEEE1394_VDEV_PNP_REQUEST  RemoveVirtualDevice;
    .
    .
    .
  } u;
} IEEE1394_API_REQUEST, *PIEEE1394_API_REQUEST;

Input

RequestNumber
IEEE1394_API_REMOVE_VIRTUAL_DEVICE
Flags
See IEEE1394_API_REQUEST for a list of values that can be assigned to Flags.
u.RemoveVirtualDevice
See IEEE1394_VDEV_PNP_REQUEST for a list of values that can be assigned to AddVirtualDevice.

Output

None

I/O Status Block

The bus driver sets Irp->IoStatus.Status to STATUS_SUCCESS on success, or the appropriate error code on failure.

See Also

IOCTL_IEEE1394_API_REQUEST

IEEE1394_API_REQUEST

IEEE1394_VDEV_PNP_REQUEST

IEEE1394_API_ADD_VIRTUAL_DEVICE


IEEE 1394 Structures

This chapter describes structures used by IEEE 1394 device drivers.

To use these structures, include the 1394.h header file that is shipped with the Windows® 2000 DDK.


ADDRESS_FIFO

The ADDRESS_FIFO structure is an entry in a singly-linked list of MDLs used by the REQUEST_ALLOCATE_ADDRESS_RANGE IEEE 1394 bus request.

typedef struct _ADDRESS_FIFO {
  SINGLE_LIST_ENTRY  FifoList;  // Singly linked list
  PMDL  FifoMdl;     // Mdl for this FIFO element
} ADDRESS_FIFO, *PADDRESS_FIFO;

Members

FifoList
Specifies the rest of the list.
FifoMdl
Specifies the MDL for this entry of the list.


ADDRESS_OFFSET

The ADDRESS_OFFSET structure specifies the 48-bit address within a device's IEEE 1394 address space.

typedef struct _ADDRESS_OFFSET {
  USHORT  Off_High;
  ULONG  Off_Low;
} ADDRESS_OFFSET, *PADDRESS_OFFSET;

Members

Off_High
Specifies the high order offset for a IEEE 1394 address.
Off_Low
Specifies the low order offset for a IEEE 1394 address.


ADDRESS_RANGE

The ADDRESS_RANGE structure describes a range in a IEEE 1394 device's address space.

typedef struct _ADDRESS_RANGE {
  USHORT  AR_Off_High;
  USHORT  AR_Length;
  ULONG   AR_Off_Low;
} ADDRESS_RANGE, *PADDRESS_RANGE;

Members

AR_Off_High
Specifies the high order bits of the 1394 address within the buffer.
AR_Length
Specifies the length, in bytes, of a 1394 address buffer.
AR_Off_Low
Specifies the low order bits of the 1394 address within the buffer.


CONFIG_ROM

The CONFIG_ROM structure is used to contain the first 24 bytes of a IEEE 1394 device's configuration ROM.

typedef struct _CONFIG_ROM
{
  ULONG  CR_Info;
  ULONG  CR_Signiture;
  ULONG  CR_BusInfoBlockCaps;
  ULONG  CR_Node_UniqueID[2];
  ULONG  CR_Root_Info;

  // Other information may be provided by vendor
} CONFIG_ROM, *PCONFIG_ROM;

Members

CR_Info
Specifies the first 4 bytes of the configuration ROM.
CR_Signiture
Specifies a signature that will be the same for all 1394 devices.
CR_BusInfoBlockCaps
Specifies the bus capabilities of the device.
CR_Node_UniqueID
Specifies the node's 64-bit vendor-assigned unique ID.
CR_Root_Info
Specifies the first 4 bytes of the root directory information.

Context

See the IEEE 1394-1995 Specification for more details about the layout of the standard configuration ROM.


CYCLE_TIME

The CYCLE_TIME structure contains the IEEE 1394 isochronous cycle time.

typedef struct _CYCLE_TIME {
  ULONG  CL_CycleOffset:12;
  ULONG  CL_CycleCount:13;
  ULONG  CL_SecondCount:7;
} CYCLE_TIME, *PCYCLE_TIME;

Members

CL_CycleOffset
Specifies the number of clock ticks (based on a 24.576 MHz clock) since the current isochronous cycle began.
CL_CycleCount
Specifies the number of isochronous cycles in the current second.
CL_SecondCount
Specifies the number of seconds. This count wraps to zero every 128 seconds.

Comments

The layout of this structure matches that of the CYCLE_TIME register in the IEEE 1394-1995 specification.


GET_LOCAL_HOST_INFO1

The GET_LOCAL_HOST_INFO1 structure contains the data returned by a REQUEST_GET_LOCAL_HOST_INFO request using u.GetLocalHostInformation.nLevel GET_HOST_UNIQUE_ID.

typedef struct _GET_LOCAL_HOST_INFO1 {
  LARGE_INTEGER  UniqueId;
} GET_LOCAL_HOST_INFO1, *PGET_LOCAL_HOST_INFO1;

Members

UniqueId
The bus driver fills in this member with the IEEE 1394 globally unique device ID for the host controller.


GET_LOCAL_HOST_INFO2

The GET_LOCAL_HOST_INFO2 structure contains the data returned by a REQUEST_GET_LOCAL_HOST_INFO request using u.GetLocalHostInformation.nLevel GET_HOST_CAPABILITIES.

typedef struct _GET_LOCAL_HOST_INFO2 {
  ULONG  HostCapabilities;
  ULONG  MaxAsyncReadRequest;
  ULONG  MaxAsyncWriteRequest;
} GET_LOCAL_HOST_INFO2, *PGET_LOCAL_HOST_INFO2;

Members

HostCapabilities
Flag | Description
HOST_INFO_PACKET_BASED | The host controller supports packet-based isochronous transactions.
HOST_INFO_STREAM_BASED | The host controller supports stream-based isochronous transactions.
HOST_INFO_SUPPORTS_ISOCH_STRIPPING | The host controller supports configurable stripping of header information.
HOST_INFO_SUPPORTS_START_ON_CYCLE | The host controller supports synchronizing start on specific isochronous cycle times.
HOST_INFO_SUPPORTS_RETURNING_ISO_HDR | The host controller does not automatically strip off the isochronous packet header.
HOST_INFO_SUPPORTS_ISO_HDR_INSERTION | The host controller supports the DESCRIPTOR_HEADER_SCATTER_GATHER flag in ISOCH_DESCRIPTOR.

MaxAsyncReadRequest
The bus driver fills in this member with the maximum size asynchronous read request that the host controller supports.
MaxAsyncWriteRequest
The bus driver fills in this member with the maximum size asynchronous write request that the host controller supports.

Comments

Port drivers that return the HOST_INFO_PACKET_BASED flag support the IsochAllocateResources request's RESOURCE_USE_PACKET_BASED flag. Port drivers that return the HOST_STREAM_PACKET_BASED flag support stream-based I/O. If the host controller does not support stream-based I/O, the driver must use packet-based I/O, and set the RESOURCE_USE_PACKET_BASED flag when issuing the REQUEST_ISOCH_ALLOCATE_RESOURCES.

Some host controllers automatically strip the packet header off an isochronous packet. If a host controller does not automatically strip the header, the port driver will return the HOST_INFO_SUPPORTS_ISO_HDR flag. Some host controllers allow a driver to configure the host controller to strip off a given number of quadlets; for such controllers the port driver will return the HOST_INFO_SUPPORTS_ISOCH_STRIPPING flag. The driver should check this flag before calling REQUEST_ISOCH_ALLOCATE_RESOURCES with the RESOURCE_STRIP_ADDITIONAL_QUADLETS flag.

If a host controller supports synchronizing REQUEST_ISOCH_LISTEN and REQUEST_ISOCH_TALK requests to the isochronous cycle time, the port driver will return the HOST_INFO_SUPPORTS_START_ON_CYCLE. Drivers should check this flag before attempting to issue an REQUEST_ISOCH_ALLOCATE_RESOURCES request using the RESOURCE_SYNCH_ON_TIME flag, or before attaching a buffer whose ISOCH_DESCRIPTOR has the DESCRIPTOR_SYNCH_ON_TIME flag set.


GET_LOCAL_HOST_INFO3

The GET_LOCAL_HOST_INFO3 structure contains the data returned by a REQUEST_GET_LOCAL_HOST_INFO request using u.GetLocalHostInformation.nLevel = GET_POWER_SUPPLIED.

typedef struct _GET_LOCAL_HOST_INFO3 {
  ULONG    deciWattsSupplied;
  ULONG    Voltage;            // x10 -> +3.3 == 33
                               // +5.0 == 50,+12.0 == 120
                               // etc.
} GET_LOCAL_HOST_INFO3, *PGET_LOCAL_HOST_INFO3;

Members

deciWattsSupplied
Specifies the wattage supplied, in tenths of a watt.
Voltage
Specifies the voltage, in tenths of a volt.


GET_LOCAL_HOST_INFO4

The GET_LOCAL_HOST_INFO4 structure contains the data returned by a REQUEST_GET_LOCAL_HOST_INFO request using u.GetLocalHostInformation.nLevel = GET_PHYS_ADDR_ROUTINE.

typedef struct _GET_LOCAL_HOST_INFO4 {
  PPORT_PHYS_ADDR_ROUTINE  PhysAddrMappingRoutine;
  PVOID  Context;
} GET_LOCAL_HOST_INFO4, *PGET_LOCAL_HOST_INFO4;

Members

PhysAddrMappingRoutine
Pointer to the physical address mapping routine, which is of type:
NTSTATUS
PhysAddrMappingRoutine (
    IN PVOID Context,
    IN OUT PIRB Irb
);

The physical mapping routine is invoked on an REQUEST_ALLOCATE_ADDRESS_RANGE IRB. It fills in the u.AllocateAddressRange.pAddressRange member with the physical addresses that the u.AllocateAddressRange.Mdl member of the IRB are mapped to. The proper value for the Context parameter is the Context member below.

Context
Specifies the argument that should be passed as the Context argument of the physical address mapping routine.


GET_LOCAL_HOST_INFO5

The GET_LOCAL_HOST_INFO5 structure contains the data returned by a REQUEST_GET_LOCAL_HOST_INFO request using u.GetLocalHostInformation.nLevel = GET_HOST_CONFIG_ROM.

typedef struct _GET_LOCAL_HOST_INFO5 {
  PVOID  ConfigRom;
  ULONG  ConfigRomLength;
} GET_LOCAL_HOST_INFO5, *PGET_LOCAL_HOST_INFO5;

Members

ConfigRom
Pointer to the beginning of the buffer to be filled with the local host's configuration ROM.
ConfigRomLength
Specifies the length of the buffer pointed to by ConfigRom.

Comments

When submitted in a REQUEST_GET_LOCAL_HOST_INFO request, if the ConfigRomLength is smaller than the size of the Configuration ROM, a status code of STATUS_INVALID_BUFFER_SIZE is returned. In this case, the correct buffer size will be filled in the ConfigRomLength member.


GET_LOCAL_HOST_INFO6

The GET_LOCAL_HOST_INFO6 structure contains the data returned by a REQUEST_GET_LOCAL_HOST_INFO request using u.GetLocalHostInformation.nLevel = GET_HOST_CSR_CONTENTS.

typedef struct _GET_LOCAL_HOST_INFO6 {
  ADDRESS_OFFSET  CsrBaseAddress;
  ULONG  CsrDataLength;
  PVOID  CsrDataBuffer;
} GET_LOCAL_HOST_INFO6, *PGET_LOCAL_HOST_INFO6;

Members

CsrBaseAddress
Specifies the base address to examine in the CSR. CsrBaseAddress.Off_High must be INITIAL_REGISTER_SPACE_HI. The possible values of CsrBaseAddress.Off_Low are:
CsrBaseAddress.Off_Low | Type of Data
SPEED_MAP_LOCATION | The current speed map. The bus driver converts this from big-endian to machine-native format before it returns the data.
TOPOLOGY_MAP_LOCATION | The current topology map. The bus driver converts this from big-endian to machine-native format before it returns the data.

CsrDataLength
Specifies the length in bytes of the buffer that CsrDataBuffer points to.
CsrDataBuffer
Pointer to the buffer where the bus driver returns the requested CSR data.

Comments

When submitted in a REQUEST_GET_LOCAL_HOST_INFO request, if the CsrDataLength is smaller than the size of the requested data, STATUS_INVALID_BUFFER_SIZE is returned. In this case, the correct buffer size will be filled in the CsrDataLength member.


GET_LOCAL_HOST_INFO7

The GET_LOCAL_HOST_INFO7 structure contains the data returned by a REQUEST_GET_LOCAL_HOST_INFO request with u.GetLocalHostInformation.nLevel set to GET_HOST_DMA_CAPABILITIES.

typedef struct _GET_LOCAL_HOST_INFO7 {
  ULONG  HostDmaCapabilities;
  ULARGE_INTEGER  MaxDmaBufferSize;
} GET_LOCAL_HOST_INFO7, *PGET_LOCAL_HOST_INFO7;

Members

HostDmaCapabilities
See GET_LOCAL_HOST_INFO2 for the list of host controller capability flags that can be assigned to this member.
MaxDmaBufferSize
Maximum DMA buffer size. This value is determined by multiplying the number of map registers assigned to this device by the page size.


SET_LOCAL_HOST_PROPS2

SET_LOCAL_HOST_PROPS2 sets a lower bound on the value the bus will use for its gap count.

typedef struct _SET_LOCAL_HOST_PROPS2 {
  ULONG  GapCountLowerBound;
} SET_LOCAL_HOST_PROPS2, *PSET_LOCAL_HOST_PROPS2;

Members

GapCountLowerBound
Specifies lower bound of the gap count.

Headers

Include 1394.h.

Comments

See the IEEE 1394-1995 Specification for a description of the gap count.

See Also

REQUEST_SET_LOCAL_HOST_PROPERTIES


SET_LOCAL_HOST_PROPS3

SET_LOCAL_HOST_PROPS3 contains the data necessary for defining or identifying one or more unit directories in the Configuration ROM of a 1394 Host Controller.

typedef struct _SET_LOCAL_HOST_PROPS3 {
  IN ULONG  fulFlags;
  IN OUT HANDLE  hCromData;
  IN ULONG  nLength;
  IN PMDL  Mdl;
} SET_LOCAL_HOST_PROPS3, *PSET_LOCAL_HOST_PROPS3;

Members

fulFlags
Specifies the action to be taken with the unit directory data contained in the SET_LOCAL_HOST_PROPS3 structure.
Flag | Description
SLHP_FLAG_ADD_CROM_DATA | Indicates that the data contained in the SET_LOCAL_HOST_PROPS3 structure is to be used to create a new unit directory in the Host Controller's Configuration ROM.
SLHP_FLAG_REMOVE_CROM_DATA | Indicates that the data contained in the SET_LOCAL_HOST_PROPS3 structure is to be used to identify and remove an existing unit directory in the Host Controller's Configuration ROM.
hCromData
Contains a handle that is returned after one or more unit directories have been created. Drivers must store this value and pass it to the bus driver when removing these unit directories. If the SLHP_FLAG_ADD_CROM_DATA flag is set, then this is an output parameter. If the SLHP_FLAG_REMOVE_CROM_DATA flag is set, then this is an input parameter.
nLength
Contains length of the data buffer pointed to by Mdl.
Mdl
Pointer to the data buffer containing the unit directory information.

Headers

Include 1394.h.

Comments

The SET_LOCAL_HOST_PROPS3 structure is sent to the bus driver in the u.SetLocalHostProperties.Information member of an IRB during a REQUEST_SET_LOCAL_HOST_PROPERTIES request, with u.SetLocalHostProperties.nLevel = SET_LOCAL_HOST_PROPERTIES_MODIFY_CROM.

The first element of the buffer pointed to by Mdl must be a unit directory. This is followed by offsets to any other leafs or directories defined in the request. The offsets must be relative to the beginning of the buffer. If the request results in the creation of a new unit directory, the bus driver will add a pointer to the newly created directory in the root directory. The buffer pointed to by Mdl must be in big-endian data format. If a driver fails to remove its dynamically added Configuration ROM data when the driver is removed, the bus driver will do so automatically, restoring the default contents of the Configuration ROM.

See Also

IEEE1394_API_REQUEST,

REQUEST_SET_LOCAL_HOST_PROPERTIES


IEEE1394_API_REQUEST

Drivers and user-level software manage virtual IEEE1394 devices by means of a special kind of request defined in the IEEE1394_API_REQUEST structure. The bus driver receives these requests and takes the action indicated in the RequestNumber member.

typedef struct _IEEE1394_API_REQUEST {
  ULONG  RequestNumber;
  ULONG  Flags;
  union  {
    IEEE1394_VDEV_PNP_REQUEST  AddVirtualDevice;
    IEEE1394_VDEV_PNP_REQUEST  RemoveVirtualDevice;
  } u;
} IEEE1394_API_REQUEST, *PIEEE1394_API_REQUEST;

Members

RequestNumber
Determines the type of request. Each request type is documented under the value of RequestNumber in IEEE 1394 Bus I/O requests.
Flags
Flag | Description
IEEE1394_REQUEST_FLAG_UNICODE | The text string supplied in this structure is in Unicode.
IEEE1394_REQUEST_FLAG_PERSISTENT | Automatically re-create the virtual device on every boot.
IEEE1394_REQUEST_FLAG_USE_LOCAL_HOST_EUI | Use the instance ID of the host controller to define the instance ID of the virtual device to be created.
u
Specifies a union of structures, one for each value of RequestNumber. The applicable submembers of u for each request are described with each request type in IEEE 1394 Bus I/O requests.
RequestNumber | Associated member
IEEE1394_API_ADD_VIRTUAL_DEVICE | u.AddVirtualDevice
IEEE1394_API_REMOVE_VIRTUAL_DEVICE | u.RemoveVirtualDevice

Headers

Include the 1394.h header file.

Comments

The AssociatedIrp.SystemBuffer->SystemBuffer member of an IOCTL_IEEE1394_API_REQUEST IRP points to an IEEE1394_API_REQUEST structure. The bus driver uses the IRB to determine the type of request made by the device driver, and also to return the results of the operation. See IEEE 1394 Bus I/O Requests for a description of the behavior of each request.

See Also

IRB

IEEE1394_VDEV_PNP_REQUEST

IOCTL_IEEE1394_API_REQUEST


IEEE1394_VDEV_PNP_REQUEST

The IEEE1394_VDEV_PNP_REQUEST structure contains data specific to an add or remove virtual device request.

typedef struct _IEEE1394_VDEV_PNP_REQUEST{
  ULONG  fulFlags;
  ULONG  Reserved;
  ULARGE_INTEGER  InstanceId;
  UCHAR  DeviceId;
} IEEE1394_VDEV_PNP_REQUEST,*PIEEE1394_VDEV_PNP_REQUEST;

Members

fulFlags
Flag | Description
IEEE1394_REQUEST_FLAG_UNICODE | The text string supplied in DeviceId is in Unicode.
Reserved
Reserved. Driver writers must set this member to zero.
InstanceId
A 64-bit number used to identify this instance of the virtual device.
DeviceId
Supplies a buffer containing a null-terminated string to be used for generating the device ID for this device.

Headers

Include the 1394.h header file.

Comments

This structure contains the information needed to define or remove a virtual device.

See Also

IEEE1394_API_REMOVE_VIRTUAL_DEVICE

IEEE1394_API_ADD_VIRTUAL_DEVICE

IEEE1394_API_REQUEST

IOCTL_IEEE1394_API_REQUEST


IO_ADDRESS

The IO_ADDRESS structure specifies the 1394 64-bit destination address for read, write and lock operations.

typedef struct _IO_ADDRESS {
  NODE_ADDRESS  IA_Destination_ID;
  ADDRESS_OFFSET  IA_Destination_Offset;
} IO_ADDRESS, *PIO_ADDRESS;

Members

IA_Destination_ID
Pointer to the destination node address.
IA_Destination_Offset
Specifies the index of the 1394 address within the address array.


IRB

Drivers use this structure to pass most requests to IEEE 1394 bus driver.

typedef struct _IRB {
  ULONG  FunctionNumber;
  ULONG  Flags;
  ULONG  BusReserved[IRB_BUS_RESERVED_SZ];
  ULONG  PortReserved[IRB_PORT_RESERVED_SZ];
  union {
    .
    .
    .
  } u;
}

Members

FunctionNumber
Determines the type of request. Each request type is documented under the value of FunctionNumber in IEEE 1394 Bus I/O requests.
Flags
Reserved. Drivers must set this member to zero.
BusReserved
Reserved.
PortReserved
Reserved.
u
Specifies a union of structures, one for each value of FunctionNumber. The applicable submembers of u for each request are described with each request type in IEEE 1394 Bus I/O requests.
FunctionNumber | Associated member
REQUEST_ALLOCATE_ADDRESS_RANGE | AllocateAddressRange
REQUEST_ASYNC_LOCK | AsyncLock
REQUEST_ASYNC_READ | AsyncRead
REQUEST_ASYNC_STREAM | AsyncStream
REQUEST_ASYNC_WRITE | AsyncWrite
REQUEST_BUS_RESET | BusReset
REQUEST_BUS_RESET_NOTIFICATION | BusResetNotification
REQUEST_CONTROL | Control
REQUEST_ISOCH_ALLOCATE_BANDWIDTH | IsochAllocateBandwidth
REQUEST_ISOCH_ALLOCATE_CHANNEL | IsochAllocateChannel
REQUEST_ISOCH_ALLOCATE_RESOURCES | IsochAllocateResources
REQUEST_ISOCH_ATTACH_BUFFERS | IsochAttachBuffers
REQUEST_ISOCH_DETACH_BUFFERS | IsochDetachBuffers
REQUEST_ISOCH_FREE_BANDWIDTH | IsochFreeBandwidth
REQUEST_ISOCH_FREE_CHANNEL | IsochFreeChannel
REQUEST_ISOCH_FREE_RESOURCES | IsochFreeResources
REQUEST_ISOCH_LISTEN | IsochListen
REQUEST_ISOCH_QUERY_CYCLE_TIME | IsochQueryCurrentCycleTime
REQUEST_ISOCH_QUERY_RESOURCES | IsochQueryResources
REQUEST_ISOCH_SET_CHANNEL_BANDWIDTH | IsochSetChannelBandwidth
REQUEST_ISOCH_STOP | IsochStop
REQUEST_ISOCH_TALK | IsochTalk
REQUEST_FREE_ADDRESS_RANGE | FreeAddressRange
REQUEST_GET_ADDR_FROM_DEVICE_OBJECT | Get1394AddressFromDeviceObject
REQUEST_GET_CONFIGURATION_INFO | GetConfigurationInformation
REQUEST_GET_GENERATION_COUNT | GetGenerationCount
REQUEST_GET_LOCAL_HOST_INFO | GetLocalHostInformation
REQUEST_GET_SPEED_BETWEEN_DEVICES | GetMaxSpeedBetweenDevices
REQUEST_GET_SPEED_TOPOLOGY_MAPS | GetSpeedTopologyMaps
REQUEST_SEND_PHY_CONFIG_PACKET | SendPhyConfigurationPacket
REQUEST_SET_LOCAL_HOST_PROPERTIES | SetLocalHostProperties
REQUEST_SET_DEVICE_XMIT_PROPERTIES | SetDeviceXmitProperties

Comments

The Parameters->Others.Arguments1 member of an IOCTL_1394_CLASS IRP points to an IRB structure. The bus driver uses the IRB to determine the type of request made by the device driver, and also to return the results of the operation. See IEEE 1394 Bus I/O requests for a description of the behavior of each request.


ISOCH_DESCRIPTOR

The ISOCH_DESCRIPTOR structure describes a buffer to be attached or detailed from a resource handle, using the REQUEST_ISOCH_ATTACH_BUFFERS and REQUEST_ISOCH_DETACH_BUFFERS requests.

typedef struct _ISOCH_DESCRIPTOR {
  ULONG  fulFlags;
  PMDL  Mdl;
  ULONG  ulLength;
  ULONG  nMaxBytesPerFrame;
  ULONG  ulSynch;
  ULONG  ulTag;
  CYCLE_TIME  CycleTime;
  PBUS_ISOCH_DESCRIPTOR_ROUTINE  Callback;
  PVOID  Context1;
  PVOID  Context2;
  NTSTATUS  status;
  ULONG  DeviceReserved[8];
  ULONG  BusReserved[8];
  ULONG  PortReserved[16];
} ISOCH_DESCRIPTOR, *PISOCH_DESCRIPTOR;

Members

fulFlags
Specifies various flags for this isochronous descriptor:
Flag Isochronous
Transaction 		Description
DESCRIPTOR_SYNCH_ON_SY | Listen | The host controller waits for a particular Sy value that is embedded in the isochronous packet header before continuing to read data. The Sy value is specified in ulSynch.
DESCRIPTOR_SYNCH_ON_TAG | Listen | The host controller waits for a particular Tag value that is embedded in the isochronous packet header before continuing to read data. The tag value is specified in ulTag.
DESCRIPTOR_SYNCH_ON_TIME | Listen, Talk | The host controller waits for a particular isochronous cycle time before continuing the operation. The cycle time is specified in the CycleTime member.
DESCRIPTOR_USE_SY_TAG_IN_FIRST | Listen | Synchronization on the Sy or Tag members occurs only for the first packet received.
DESCRIPTOR_TIME_STAMP_ON_COMPLETION | Listen, Talk | Once the host controller completes its DMA to or from this buffer, store the cycle time in the CycleTime member of the ISOCH_DESCRIPTOR.
DESCRIPTOR_PRIORITY_TIME_DELIVERY | Talk | If the local host controller is not ready for a write, do not retry the write later. (The default behavior is to retry until the host controller is ready.)
DESCRIPTOR_HEADER_SCATTER_GATHER | Talk | The host controller treats the data in this buffer as a sequence of headers. The host controller will prepend a header from this buffer to each packet it assembles from the data in the next buffer attached.

Mdl
Specifies the MDL representing a buffer in which the data is, or will be, contained.
ulLength
Specifies the length of the Mdl.
nMaxBytesPerFrame
Specifies the maximum bytes contained in each isochronous frame. On writes, the data in the buffer will be split into isochronous packets of this size.
ulSynch
For IsochTalk requests, this member specifies the Sy field of the outgoing packet. For REQUEST_ISOCH_LISTEN requests, if the DESCIPTOR_SYNCH_ON_SY flag is set, this member specifies the value the host controller will match against the Sy field in isochronous packet headers.
ulTag
For IsochTalk requests, this member specifies the Tag field of the outgoing packet. For REQUEST_ISOCH_LISTEN requests, if the DESCIPTOR_SYNCH_ON_SY flag is set, this member specifies the value the host controller will match against the Tag field in isochronous packet headers.
CycleTime
If the DESCRIPTOR_SYNCH_ON_TIME flag is set, this member specifies the isochronous cycle time to synchronize on. (The timing resolution is per isochronous cycle. The CycleOffset member of the cycle time is not used.) If the DESCRIPTOR_TIME_STAMP_ON_COMPLETION flag is set, the bus driver will fill this member with the isochronous cycle time on completion of the operation that used this buffer.
Callback
Pointer to a callback routine. If non-NULL, the bus driver calls this routine when DMA to the buffer has completed. The callback executes at IRQL DISPATCH_LEVEL. The callback is of the following type:
void Callback(IN PVOID Context1, IN PVOID Context2);
Context1
Specifies the first parameter when the bus driver calls the routine passed in Callback.
Context2
Specifies the second parameter when the bus driver calls the routine passed in Callback.
status
Specifies the final status of the operation on this buffer. The bus driver fills in status when DMA to or from this buffer is finished.
DeviceReserved
Reserved.
BusReserved
Reserved.
PortReserved
Reserved.

Comments

Not all DESCRIPTOR_XXX flags are supported on all hardware. The device driver can use the REQUEST_GET_LOCAL_HOST_INFO request, with nLevel = GET_HOST_CAPABILITIES, to determine which DESCRIPTOR_XXX flags are supported. The bus driver returns a pointer to a GET_LOCAL_HOST_INFO2 structure, whose HostCapabilities member contains flags that determine which flags the host controller supports. The following table lists which DESCRIPTOR_XXX flags require hardware support, and the corresponding HostCapabilities flag the driver should check:

DESCRIPTOR_XXX flags | HostCapabilities
DESCRIPTOR_SYNCH_ON_TIME | HOST_INFO_SUPPORTS_START_ON_CYCLE
DESCRIPTOR_HEADER_SCATTER_GATHER | HOST_INFO_SUPPORTS_ISO_HDR_INSERTION

If the driver sets the DESCRIPTOR_HEADER_SCATTER_GATHER flag, the host controller will combine the data of the buffer specified in Mdl with the data of the next buffer attached. (Subsequent buffers are unaffected.) Each frame of the buffer will be prepended to a frame of the next buffer (in the order the data in the buffer is split into frames), and sent as the data of the next isochronous packet. The number of frames of each buffer must match, or the bus driver returns STATUS_INVALID_PARAMETER for the next REQUEST_ISOCH_ATTACH_BUFFER request.

The DESCRIPTOR_HEADER_SCATTER_GATHER flag is not supported on Windows 98/Me. It is supported on Windows 2000 and later operating systems.


NODE_ADDRESS

The NODE_ADDRESS structure specifies the 10-bit bus number and 6-bit node number that serve as the node address for a 1394 node.

typedef struct _NODE_ADDRESS {
  USHORT  NA_Node_Number:6;  // Bits 10-15
  USHORT  NA_Bus_Number:10;  // Bits 0-9
} NODE_ADDRESS, *PNODE_ADDRESS;

Members

NA_Node_Number
Specifies the 6-bit node number.
NA_Bus_Number
Specifies the 10-bit bus number.


PHY_CONFIGURATION_PACKET

The PHY_CONFIGURATION_PACKET structure contains a raw PHY configuration packet. See the IEEE 1394 specification for details.

typedef struct _PHY_CONFIGURATION_PACKET {
  ULONG  PCP_Phys_ID:6;  // Byte 0 - Bits 0-5
  ULONG  PCP_Packet_ID:2;  // Byte 0 - Bits 6-7
  ULONG  PCP_Gap_Count:6;  // Byte 1 - Bits 0-5
  ULONG  PCP_Set_Gap_Count:1;  // Byte 1 - Bit 6
  ULONG  PCP_Force_Root:1;  // Byte 1 - Bit 7
  ULONG  PCP_Reserved1:8;  // Byte 2 - Bits 0-7
  ULONG  PCP_Reserved2:8;  // Byte 3 - Bits 0-7
  ULONG  PCP_Inverse;  // Inverse quadlet
} PHY_CONFIGURATION_PACKET, *PPHY_CONFIGURATION_PACKET;

Members

PCP_Phys_ID
Specifies the node address of the root.
PCP_Packet_ID
This member must be PHY_PACKET_ID_CONFIGURATION to indicate it is a PHY configuration packet.
PCP_Gap_Count
If the PCP_Set_Gap_Count bit is set, the PHY register gap_count field is set to this value.
PCP_Set_Gap_Count
If this bit is set, the PHY register gap_count field is set to PCP_Gap_Count.
PCP_Force_Root
If set, the caller will become the root node.
PCP_Reserved1
Reserved.
PCP_Reserved2
Reserved.
PCP_Inverse
Specifies the logical inverse of the first quadlet of the packet.


SELF_ID

The SELF_ID structure contains a raw packet zero self-ID packet. See the IEEE 1394 specification for details.

typedef struct _SELF_ID {
  ULONG  SID_Phys_ID:6;  // Byte 0 - Bits 0-5
  ULONG  SID_Packet_ID:2;  // Byte 0 - Bits 6-7
  ULONG  SID_Gap_Count:6;  // Byte 1 - Bits 0-5
  ULONG  SID_Link_Active:1;  // Byte 1 - Bit 6
  ULONG  SID_Zero:1;  // Byte 1 - Bit 7
  ULONG  SID_Power_Class:3;  // Byte 2 - Bits 0-2
  ULONG  SID_Contender:1;  // Byte 2 - Bit 3
  ULONG  SID_Delay:2;  // Byte 2 - Bits 4-5
  ULONG  SID_Speed:2;  // Byte 2 - Bits 6-7
  ULONG  SID_More_Packets:1;  // Byte 3 - Bit 0
  ULONG  SID_Initiated_Rst:1;  // Byte 3 - Bit 1
  ULONG  SID_Port3:2;  // Byte 3 - Bits 2-3
  ULONG  SID_Port2:2;  // Byte 3 - Bits 4-5
  ULONG  SID_Port1:2;  // Byte 3 - Bits 6-7
} SELF_ID, *PSELF_ID;
SID_Phys_ID
Specifies the device node number.
SID_Packet_ID
Must be PHY_PACKET_ID_SELF_ID.
SID_Gap_Count
Specifies the current value of the node's PHY_CONFIGURATION register's gap_count member.
SID_Link_Active
One if the device's link and transaction layers are active, zero otherwise.
SID_Zero
Always zero.
SID_Power_Class
The possible power classes are:

POWER_CLASS_NOT_NEED_NOT_REPEAT

POWER_CLASS_SELF_POWER_PROVIDE_15W

POWER_CLASS_SELF_POWER_PROVIDE_30W

POWER_CLASS_SELF_POWER_PROVIDE_45W

POWER_CLASS_MAYBE_POWERED_UPTO_1W

POWER_CLASS_IS_POWERED_UPTO_1W_NEEDS_2W

POWER_CLASS_IS_POWERED_UPTO_1W_NEEDS_5W

POWER_CLASS_IS_POWERED_UPTO_1W_NEEDS_9W

SID_Contender
One if this node is a contender for bus or isochronous resource manager, zero otherwise.
SID_Delay
Currently always zero.
SID_More_Packets
One if this packet will be followed by SELF_ID_MORE packets, zero otherwise.
SID_Initiated_Rst
One if this node initiated the most recent bus reset, zero otherwise.
SID_Port1
SID_Port2
SID_Port3
Specifies port status. Possible values are:

SELF_ID_CONNECTED_TO_CHILD

SELF_ID_CONNECTED_TO_PARENT

SELF_ID_NOT_CONNECTED

SELF_ID_NOT_PRESENT


SELF_ID_MORE

The SELF_ID_MORE structure contains a raw packet one, two, or three self-ID packet. See the IEEE 1394 specification for details.

typedef struct _SELF_ID_MORE {
  ULONG  SID_Phys_ID:6;  // Byte 0 - Bits 0-5
  ULONG  SID_Packet_ID:2;  // Byte 0 - Bits 6-7
  ULONG  SID_PortA:2;  // Byte 1 - Bits 0-1
  ULONG  SID_Reserved2:2;  // Byte 1 - Bits 2-3
  ULONG  SID_Sequence:2;  // Byte 1 - Bits 4-5
  ULONG  SID_One:1;  // Byte 1 - Bit 6
  ULONG  SID_Reserved1:1;  // Byte 1 - Bit 7
  ULONG  SID_PortE:2;  // Byte 2 - Bits 0-1
  ULONG  SID_PortD:2;  // Byte 2 - Bits 2-3
  ULONG  SID_PortC:2;  // Byte 2 - Bits 4-5
  ULONG  SID_PortB:2;  // Byte 2 - Bits 6-7
  ULONG  SID_More_Packets:1;  // Byte 3 - Bit 0
  ULONG  SID_Reserved3:1;  // Byte 3 - Bit 1
  ULONG  SID_PortH:2;  // Byte 3 - Bits 2-3
  ULONG  SID_PortG:2;  // Byte 3 - Bits 4-5
  ULONG  SID_PortF:2;  // Byte 3 - Bits 6-7
} SELF_ID_MORE, *PSELF_ID_MORE;

Members

SID_Phys_ID
Specifies the device node number.
SID_Packet_ID
Must be PHY_PACKET_ID_SELF_ID.
SID_PortA
Specifies port status. Possible values are:

SELF_ID_CONNECTED_TO_CHILD

SELF_ID_CONNECTED_TO_PARENT

SELF_ID_NOT_CONNECTED

SELF_ID_NOT_PRESENT

SID_PortB
Specifies port status. Possible values are:

SELF_ID_CONNECTED_TO_CHILD

SELF_ID_CONNECTED_TO_PARENT

SELF_ID_NOT_CONNECTED

SELF_ID_NOT_PRESENT

SID_PortC
Specifies port status. Possible values are:

SELF_ID_CONNECTED_TO_CHILD

SELF_ID_CONNECTED_TO_PARENT

SELF_ID_NOT_CONNECTED

SELF_ID_NOT_PRESENT

SID_PortD
Specifies port status. Possible values are:

SELF_ID_CONNECTED_TO_CHILD

SELF_ID_CONNECTED_TO_PARENT

SELF_ID_NOT_CONNECTED

SELF_ID_NOT_PRESENT

SID_PortE
Specifies port status. Possible values are:

SELF_ID_CONNECTED_TO_CHILD

SELF_ID_CONNECTED_TO_PARENT

SELF_ID_NOT_CONNECTED

SELF_ID_NOT_PRESENT

SID_PortF
Specifies port status. Possible values are:

SELF_ID_CONNECTED_TO_CHILD

SELF_ID_CONNECTED_TO_PARENT

SELF_ID_NOT_CONNECTED

SELF_ID_NOT_PRESENT

SID_PortG
Specifies port status. Possible values are:

SELF_ID_CONNECTED_TO_CHILD

SELF_ID_CONNECTED_TO_PARENT

SELF_ID_NOT_CONNECTED

SELF_ID_NOT_PRESENT

SID_PortH
Specifies port status. Possible values are:

SELF_ID_CONNECTED_TO_CHILD

SELF_ID_CONNECTED_TO_PARENT

SELF_ID_NOT_CONNECTED

SELF_ID_NOT_PRESENT

SID_Reserved1
Reserved.
SID_Reserved2
Reserved.
SID_Reserved3
Reserved.
SID_Sequence
Specifies the packet number in sequence (the first SELF_ID_MORE packet is packet zero).
SID_One
Always a 1.
SID_More_Packets
One if this packet will be followed by more SELF_ID_MORE packets, zero otherwise.


SPEED_MAP

The SPEED_MAP structure is used to store a IEEE 1394 bus speed map. It describes the maximum speed obtainable by the devices on the bus.

typedef struct _SPEED_MAP {
  USHORT  SPD_Length;
  USHORT  SPD_CRC;
  ULONG   SPD_Generation;
  UCHAR  SPD_Speed_Code[4032];
} SPEED_MAP, *PSPEED_MAP;

Members

SPD_Length
Specifies the number of quadlets in the speed map.
SPD_CRC
Specifies the CRC value for the speed map.
SPD_Generation
Specifies the bus reset generation for which the speed map was created.
SPD_Speed_Code
Specifies an array of speed codes. Currently, the possible values are:

SCODE_100_RATE

SCODE_200_RATE

SCODE_400_RATE

Comments

All data will be in big-endian format.


TEXTUAL_LEAF

The TEXTUAL_LEAF structure describes the device description that can be stored in the Configuration ROM of devices that satisfy the PC 98 or PC 99 specifications.

typedef struct _TEXTUAL_LEAF
{
  USHORT  TL_CRC;
  USHORT  TL_Length;
  ULONG   TL_Spec_Id;
  ULONG  TL_Language_Id;
  UCHAR  TL_Data;
} TEXTUAL_LEAF, *PTEXTUAL_LEAF;

Members

TL_CRC
Specifies the CRC of the text string.
TL_Length
Specifies the length of the text string, in bytes.
TL_Spec_Id
Specifies which specification describes the meaning of the TL_Language_ID member.
TL_Language_Id
Specifies the language of the TL_Data member.
TL_Data
Specifies a vendor-specified textual description of the device.


TOPOLOGY_MAP

The TOPOLOGY_MAP structure is used to store an IEEE 1394 bus topology map. The relations between devices are found in the port members of the entries in TOP_Self_ID_Array.

typedef struct _TOPOLOGY_MAP {
  USHORT  TOP_Length;
  USHORT  TOP_CRC;
  ULONG   TOP_Generation;
  USHORT  TOP_Node_Count;
  USHORT  TOP_Self_ID_Count;
  SELF_ID  TOP_Self_ID_Array[];
} TOPOLOGY_MAP, *PTOPOLOGY_MAP;

Members

TOP_Length
Specifies the length in quadlets of the topology map.
TOP_CRC
Specifies the CRC value for the topology map.
TOP_Generation
Specifies the bus reset generation for which the topology map was created.
TOP_Node_Count
Specifies the number of nodes in the topology map.
TOP_Self_ID_Count
Specifies the number of entries in TOP_Self_ID_Array.
TOP_Self_ID_Array
Pointer to an array of SELF_ID and SELF_ID_MORE structures (the two structures are the same size).

Comments

All data will be in big-endian format.


IEC-61883 Protocol I/O Requests

An IEC-61883 client driver must communicate with its device by submitting IRPs down the device stack to the IEC-61883 protocol driver.

To use these I/O requests, include the header file 61883.h, which is shipped with the Microsoft® Windows® DDK.


INIT_61883_HEADER Macro

The INIT_61883_HEADER macro initializes the Function and Version members of an AV_61883_REQUEST structure.

VOID
  INIT_61883_HEADER(
    IN PAV_61883_REQUEST  Av61883,
    IN ULONG  Request
    );

Parameters

Av61883
Pointer to a caller-allocated AV_61883_REQUEST structure.
Request
The type of the request. Each request type is documented under the value of Function for a particular request.

Headers

Defined in 61883.h. Include 61883.h.

See Also

AV_61883_REQUEST, IOCTL_61883_CLASS


IOCTL_61883_CLASS

Operation

An IEC-61883 client driver uses the IRP_MJ_INTERNAL_DEVICE_CONTROL IRP with IoControlCode IOCTL_61883_CLASS to communicate with 1394 driver stack using the IEC-61883 protocol. The driver has access to all operations provided by the IEC-61883 protocol driver through this request.

Input

Parameters->Others.Argument1 points to an AV_61883_REQUEST structure. The Function member of the request structure specifies the type of request. The union member of the request structure specifies the request-type-specific parameters of the request. The parameters and their meaning are documented with each request.

Output

Parameters->Others.Argument1 points to the AV_61883_REQUEST structure passed as input. As part of completing the request, the bus driver fills in certain submembers of the union within the request structure with information for the driver. The returned information is documented with each request.

I/O Status Block

The information the IEC-61883 protocol driver returns in the I/O Status Block is documented with each request.

Headers

Defined in 61883.h. Include 61883.h.

See Also

AV_61883_REQUEST


Av61883_AttachFrame

The Av61883_AttachFrame request attaches a frame buffer to the specified plug for a subsequent Talk or Listen request.

The relevant members of the AV_61883_REQUEST structure for this request are:

typedef struct _AV_61883_REQUEST {
  ULONG Function;
  union {
    struct _CIP_ATTACH_FRAME {
      HANDLE  hConnect;
      ULONG  FrameLength;
      ULONG  SourceLength;
      PCIP_FRAME Frame;
    } CIP_ATTACH_FRAME, *PCIP_ATTACH_FRAME;
    .
    .
    .
  };
} AV_61883_REQUEST, *PAV_61883_REQUEST;

AV_61883_REQUEST Input

Function
Av61883_AttachFrame
hConnect
A handle to the connection.
FrameLength
The length of the frame in quadlets (a multiple of 4 bytes). The total frame length must be evenly divisible by a quadlet.
SourceLength
The length of the source packets, in bytes. The source length must be evenly divisible into the frame length.
Frame
Pointer to a CIP_FRAME structure that contains information about the frame and a data buffer to be sent or filled.

I/O Status Block

If successful, the IEC-61883 protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

If an incorrect parameter is passed in, the protocol driver sets Irp->IoStatus.Status to STATUS_INVALID_PARAMETER.

If the protocol driver is unable to allocate resources, it sets Irp->IoStatus.Status to STATUS_INSUFFICIENT_RESOURCES.

Operation

The IEC-61883 protocol driver subdivides the frames into source packets and blocks. By default, the timestamp returned is the time at completion of the frame transmission.

Headers

Defined in 61883.h. Include 61883.h.

See Also

AV_61883_REQUEST, CIP_FRAME


Av61883_BusReset

The Av61883_BusReset request issues a 1394 bus reset.

The relevant members of the AV_61883_REQUEST structure for this request are:

typedef struct _AV_61883_REQUEST {
  ULONG  Function;
} AV_61883_REQUEST, *PAV_61883_REQUEST;

AV_61883_REQUEST Input

Function
Av61883_BusReset

I/O Status Block

If successful, the IEC-61883 protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

Operation

This request issues a 1394 bus reset.

Headers

Defined in 61883.h. Include 61883.h.

See Also

AV_61883_REQUEST


Av61883_BusResetNotify

The Av61883_BusResetNotify request registers the caller to be notified when a reset of the 1394 bus occurs or cancels a previous registration.

The relevant members of the AV_61883_REQUEST structure for this request are:

typedef struct _AV_61883_REQUEST {
  ULONG Function;
  union {
    typedef struct _BUS_RESET_NOTIFY {
      IN ULONG  Flags;
      IN PBUS_RESET_ROUTINE  pfnNotify;
      IN PVOID  Context;
    } BUS_RESET_NOTIFY, *PBUS_RESET_NOTIFY;
    .
    .
    .
  };
} AV_61883_REQUEST, *PAV_61883_REQUEST;

AV_61883_REQUEST Input

Function
Av61883_BusResetNotify
Flags
The caller sets this member to REGISTER_BUS_RESET_NOTIFY to register to receive bus-reset notifications, or to DEREGISTER_BUS_RESET_NOTIFY to stop receiving bus-reset notifications.
pfnNotify
Pointer to a caller-supplied function to be called by the protocol driver when the 1394 bus is reset.

This function uses the following prototype:

Void
  (*PBUS_RESET_ROUTINE)(
    IN PVOID  Context;
    IN PBUS_GENERATION_NODE  BusResetInfo;
  );
Context
Pointer to the context supplied by the caller at the Context member of the input BUS_RESET_NOTIFY structure.
Context
Pointer to a caller-defined context for the function at pfnNotify. The IEC-61883 protocol driver calls this function after a reset of the 1394 bus.

I/O Status Block

If successful, the IEC-61883 protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

If an incorrect parameter is passed in, the protocol driver sets Irp->IoStatus.Status to STATUS_INVALID_PARAMETER.

Operation

When the registered callback (bus reset) routine is called, the updated generation count and node address will be specified in parameter BusResetInfo.

If a driver registers for bus-reset notification, it must cancel registration before the system unloads the driver.

Headers

Defined in 61883.h. Include 61883.h.

See Also

AV_61883_REQUEST, Av61883_SetFcpNotify


Av61883_CancelFrame

The Av61883_CancelFrame request cancels an attached frame buffer.

The relevant members of the AV_61883_REQUEST structure for this request are:

typedef struct _AV_61883_REQUEST {
  ULONG Function;
  union {
    typedef struct _CIP_CANCEL_FRAME {
      IN HANDLE  hConnect;
      IN PCIP_FRAME  Frame;
    } CIP_CANCEL_FRAME, *PCIP_CANCEL_FRAME;
    .
    .
    .
  };
} AV_61883_REQUEST, *PAV_61883_REQUEST;

AV_61883_REQUEST Input

Function
Av61883_CancelFrame
hConnect
A handle to a connection.
Frame
Pointer to a CIP_FRAME structure that contains information about the frame to cancel.

I/O Status Block

If successful, the IEC-61883 protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

If the protocol driver cannot find the specified frame, it sets Irp->IoStatus.Status to STATUS_NOT_FOUND.

Operation

This request cancels an attached frame. A frame can be cancelled while the stream is running. If the canceled frame has already been sent, the protocol driver sets a status of STATUS_NOT_FOUND.

Headers

Defined in 61883.h. Include 61883.h.

See Also

AV_61883_REQUEST, CIP_FRAME


Av61883_Connect

The Av61883_Connect request attempts to make a connection to a plug control register on the local host.

The relevant members of the AV_61883_REQUEST structure for this request are:

typedef struct _AV_61883_REQUEST {
  ULONG Function;
  union {
    typedef struct _CMP_CONNECT {
      IN HANDLE  hOutputPlug;
      IN HANDLE  hInputPlug;
      IN CMP_CONNECT_TYPE  Type;
      IN CIP_DATA_FORMAT  Format;
      OUT HANDLE  hConnect;
    } CMP_CONNECT, *PCMP_CONNECT;
    .
    .
    .
  };
} AV_61883_REQUEST, *PAV_61883_REQUEST;

AV_61883_REQUEST Input

Function
Av61883_Connect
hOutputPlug
A handle to the output plug to use for the connection. If hOutputPlug is null, the connection is for input only.
hInputPlug
A handle to the input plug to use for the connection. If hInputPlug is null, the connection is for output only.
Type
The type of connection to make. Can be one of the following:
CMP_Broadcast
A broadcast connection.
CMP_PointToPoint
A connection between a single output plug and one or more input plugs.
Format
Pointer to a CIP_DATA_FORMAT structure that specifies the format of the connection.

This structure is defined as follows:

typedef struct _CIP_DATA_FORMAT {
  UCHAR  FMT;
  UCHAR  FDF_hi;
  UCHAR  FDF_mid;
  UCHAR  FDF_lo;
  BOOLEAN  bHeader;
  UCHAR  Padding;
  UCHAR  BlockSize;
  UCHAR  Fraction;
  ULONG  BlockPeriod;
} CIP_DATA_FORMAT, *PCIP_DATA_FORMAT;
FMT
The format ID for the connection, as defined in IEC-61883-1.
FDF_hi
The high byte of the format-dependent field for the connection.
FDF_mid
The middle byte of the format-dependent field for the connection.
FDF_lo
The low byte of the format-dependent field for the connection.
bHeader
The source packet header, as defined in the IEC-61883 specification.
Padding
The number of dummy quadlets padded at the end of every source packet to enable its division into equally-sized data blocks.
BlockSize
The data block size, in quadlets.
Fraction
The number of data blocks into which a source packet is divided.
BlockPeriod
(Transmit only) For Windows XP and later, BlockPeriod is a time value in 1394 clock ticks used to calculate either when to stop processing data blocks within a CIP packet or when to insert an empty CIP packet into the stream. For example, BlockPeriod for DV NTSC is 3280. BlockPeriod for DC PAL is 3277.

AV_61883_REQUEST Output

hConnect
A handle to the connection. If the request fails, hConnect is NULL.

I/O Status Block

If successful, the IEC-61883 protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

If an incorrect parameter is passed in, the protocol driver sets Irp->IoStatus.Status to STATUS_INVALID_PARAMETER.

If the protocol driver is unable to allocate resources, it sets Irp->IoStatus.Status to STATUS_INSUFFICIENT_RESOURCES.

Operation

Drivers that submit this request must be running at IRQL = PASSIVE_LEVEL.

Headers

Defined in 61883.h. Include 61883.h.

See Also

AV_61883_REQUEST, Av61883_CreatePlug, Av61883_Disconnect


Av61883_CreatePlug

The Av61883_CreatePlug request creates an input or output plug control register (iPCR or oPCR) on the local host.

The relevant members of the AV_61883_REQUEST structure for this request are:

typedef struct _AV_61883_REQUEST {
  ULONG Function;
  union {
    typedef struct _CMP_CREATE_PLUG {
      IN CMP_PLUG_TYPE  PlugType;
      IN AV_PCR  Pcr;
      IN PCMP_NOTIFY_ROUTINE  pfnNotify;
      IN PVOID  Context;
      OUT ULONG  PlugNum;
      OUT HANDLE  hPlug;
    } CMP_CREATE_PLUG, *PCMP_CREATE_PLUG;
    .
    .
    .
  };
} AV_61883_REQUEST, *PAV_61883_REQUEST;

AV_61883_REQUEST Input

Function
Av61883_CreatePlug
PlugType
The type of plug to create. Can be one of the following:
CMP_PlugOut
An output plug, which transmits data from the device to the bus.
CMP_PlugIn
An input plug, which receives data sent by the bus to the device.
Pcr
An AV_PCR structure that contains values used by the protocol driver to initialize the plug.
pfnNotify
Pointer to a caller-supplied function to be called by the protocol driver when the plug is created.
Context
Pointer to an optional caller-supplied context for the function at pfnNotify.

AV_61883_REQUEST Output

PlugNum
The plug number of the newly created plug. If the plug could not be created, PlugNum is zero (0).
hPlug
A handle to the newly created plug. If the plug could not be created, hPlug is null.

I/O Status Block

If successful, the IEC-61883 protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

If an incorrect parameter is passed in, the protocol driver sets Irp->IoStatus.Status to STATUS_INVALID_PARAMETER.

If the protocol driver is unable to allocate resources, it sets Irp->IoStatus.Status to STATUS_INSUFFICIENT_RESOURCES.

Operation

This request is used to create a plug on the local node. A driver is responsible for deleting all of the plugs it has created before the system unloads the driver.

Headers

Defined in 61883.h. Include 61883.h.

See Also

AV_61883_REQUEST, AV_PCR, Av61883_Connect


Av61883_DeletePlug

The Av61883_DeletePlug request deletes a plug control register (iPCR or oPCR) that was created with AV61883_CreatePlug.

The relevant members of the AV_61883_REQUEST structure for this request are:

typedef struct _AV_61883_REQUEST {
  ULONG Function;
  union {
    typedef struct _CMP_DELETE_PLUG {
      IN HANDLE  hPlug;
    } CMP_DELETE_PLUG, *PCMP_DELETE_PLUG;
    .
    .
    .
  };
} AV_61883_REQUEST, *PAV_61883_REQUEST;

AV_61883_REQUEST Input

Function
Av61883_DeletePlug
hPlug
A handle to the plug to delete.

I/O Status Block

If successful, the IEC-61883 protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

Operation

A driver is responsible for deleting all of the plugs it has created before the system unloads the driver.

Headers

Defined in 61883.h. Include 61883.h.

See Also

AV_61883_REQUEST, Av61883_CreatePlug


Av61883_Disconnect

The Av61883_Disconnect request breaks the specified connection.

The relevant members of the AV_61883_REQUEST structure for this request are:

typedef struct _AV_61883_REQUEST {
  ULONG Function;
  union {
    typedef struct _CMP_DISCONNECT {
      IN HANDLE hConnect;
    } CMP_DISCONNECT, *PCMP_DISCONNECT;
    .
    .
    .
  };
} AV_61883_REQUEST, *PAV_61883_REQUEST;

AV_61883_REQUEST Input

Function
Av61883_Disconnect
hConnect
A handle to the connection to break.

I/O Status Block

If successful, the IEC-61883 protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

If an incorrect parameter is passed in, the protocol driver sets Irp->IoStatus.Status to STATUS_INVALID_PARAMETER.

Operation

Drivers that submit this request must be running at an IRQL =PASSIVE_LEVEL.

Headers

Defined in 61883.h. Include 61883.h.

See Also

AV_61883_REQUEST, Av61883_Connect


Av61883_GetFcpRequest

The Av61883_GetFcpRequest request retrieves the next FCP request from the queue of requests maintained by the IEC-61883 protocol driver.

The relevant members of the AV_61883_REQUEST structure for this request are:

typedef struct _AV_61883_REQUEST {
  ULONG Function;
  union {
    typedef struct _FCP_GET_REQUEST {
      OUT NODE_ADDRESS  NodeAddress;
      IN OUT ULONG  Length;
      IN OUT PFCP_FRAME  Frame;
    } FCP_GET_REQUEST, *PFCP_GET_REQUEST;
    .
    .
    .
  };
} AV_61883_REQUEST, *PAV_61883_REQUEST;

AV_61883_REQUEST Input

Function
Av61883_GetFcpRequest
Length
The maximum available length of the frame payload, including FCP header.
Frame
Pointer to a caller-allocated FCP_FRAME structure to receive the FCP request.

AV_61883_REQUEST Output

NodeAddress
If the protocol driver is controlling a virtual device, NodeAddress contains the node address of the device that sent the FCP request obtained with this Av61883_GetFcpRequest IRP. The caller must use this node address in the FCP response sent with Av61883_SendFcpResponse so the 1394 bus driver can route the response to the correct device.

If the protocol driver is being used to control a physical device, NodeAddress is not used.

Length
On completion, this field will contain the actual length of the request.
Frame
The FCP frame written to the caller-allocated FCP_FRAME structure by the protocol driver.

I/O Status Block

If successful, the IEC-61883 protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

If the request is queued, the protocol driver sets a status of STATUS_PENDING. If the request has been previously cancelled, the driver sets a status of STATUS_CANCELLED.

If an incorrect parameter is passed in, the protocol driver sets Irp->IoStatus.Status to STATUS_INVALID_PARAMETER.

Operation

FCP requests and responses from AV devices are routed to the IEC-61883 protocol driver, which queues the requests. Client drivers send Av61883_GetFcpRequest requests to retrieve an FCP request from the queue.

For requests sent to a virtual device, the NodeAddress member of the output FCP_GET_REQUEST structure contains the node address of the device that sent the FCP request. The client driver must supply this node address with its response so the instance of the protocol driver that controls the virtual device can route the response correctly.

For requests sent by a physical device, the 1394 bus driver determines the node address dynamically, and NodeAddress is not used.

Headers

Defined in 61883.h. Include 61883.h.

See Also

AV_61883_REQUEST, Av61883_SendFcpResponse, Av61883_SetFcpNotify, FCP_FRAME


Av61883_GetFcpResponse

The Av61883_GetFcpResponse request retrieves the next FCP response from the queue of requests maintained by the IEC-61883 protocol driver.

The relevant members of the AV_61883_REQUEST structure for this request are:

typedef struct _AV_61883_REQUEST {
  ULONG Function;
  union {
    typedef struct _FCP_GET_RESPONSE {
      OUT NODE_ADDRESS  NodeAddress;
      IN OUT ULONG  Length;
      IN OUT PFCP_FRAME  Frame;
    } FCP_GET_RESPONSE, *PFCP_GET_RESPONSE;
    .
    .
    .
  };
} AV_61883_REQUEST, *PAV_61883_REQUEST;

AV_61883_REQUEST Input

Function
Av61883_GetFcpResponse
Length
The maximum available length, in bytes, of the frame payload, including FCP header.
Frame
Pointer to a caller-allocated FCP_FRAME structure to receive the FCP response.

AV_61883_REQUEST Output

NodeAddress
If the protocol driver is being used to control a virtual device, the protocol driver supplies the node address of the device that sent the response obtained with this Av61883_GetFcpResponse IRP. If the protocol driver is being used to control a physical device, NodeAddress is not used.
Length
On completion, this field will contain the actual length of the response in bytes.
Frame
The FCP frame written to the caller-allocated FCP_FRAME structure by the protocol driver.

I/O Status Block

If successful, the IEC-61883 protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

If the request is queued, the protocol driver sets a status of STATUS_PENDING. If the request has been previously cancelled, the driver sets a status of STATUS_CANCELLED.

If an incorrect parameter is passed in, the protocol driver sets Irp->IoStatus.Status to STATUS_INVALID_PARAMETER.

Operation

FCP requests and responses from AV devices are routed to the IEC-61883 protocol driver, which queues the requests. Client drivers send Av61883_GetFcpResponse to retrieve an FCP response from the queue.

Headers

Defined in 61883.h. Include 61883.h.

See Also

AV_61883_REQUEST, Av61883_SendFcpRequest, Av61883_SetFcpNotify, FCP_FRAME


Av61883_GetPlugHandle

The Av61883_GetPlugHandle request retrieves a unique handle associated with an input or output plug. The plug handle is required for all operations on the plug.

The relevant members of the AV_61883_REQUEST structure for this request are:

typedef struct _AV_61883_REQUEST {
  ULONG Function;
  ULONG Flags;
  union {
    typedef struct _CMP_GET_PLUG_HANDLE {
      IN ULONG  PlugNum;
      IN CMP_PLUG_TYPE  Type;
      OUT HANDLE  hPlug;
    } CMP_GET_PLUG_HANDLE, *PCMP_GET_PLUG_HANDLE;
    .
    .
    .
  };
} AV_61883_REQUEST, *PAV_61883_REQUEST;

AV_61883_REQUEST Input

Function
Av61883_GetPlugHandle
Flags
Specifies either RETRIEVE_DEVICE_UNIT_INFO or RETRIEVE_LOCAL_UNIT_INFO. Depending on setting, the request will either retrieve the plug handle from the device or from the local node.
PlugNum
The number of the plug whose handle was returned by the AV61883_CreatePlug request that created the plug.
Type
The type of the plug. This can be CMP_PlugOut for an output plug, or CMP_PlugIn for an input plug.

AV_61883_REQUEST Output

hPlug
A handle to the plug specified with PlugNum and Type.

I/O Status Block

If successful, the IEC-61883 protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

If an incorrect parameter is passed in, the protocol driver sets Irp->IoStatus.Status to STATUS_INVALID_PARAMETER.

Operation

A driver uses a plug handle to get the state of a plug, modify plug settings, or delete a plug. A driver can delete only plugs it has previously created.

Headers

Defined in 61883.h. Include 61883.h.

See Also

AV_61883_REQUEST, Av61883_CreatePlug, Av61883_DeletePlug, Av61883_GetPlugState, Av61883_SetPlug


Av61883_GetPlugState

The Av61883_GetPlugState request retrieves state information for the specified plug, including its current connections and bus data format.

The relevant members of the AV_61883_REQUEST structure for this request are:

typedef struct _AV_61883_REQUEST {
  ULONG Function;
  union {
    typedef struct _CMP_GET_PLUG_STATE {
      IN HANDLE  hPlug;
      OUT ULONG  State;
      OUT ULONG  DataRate;
      OUT ULONG  Payload;
      OUT ULONG  BC_Connections;
      OUT ULONG  PP_Connections;
    } CMP_GET_PLUG_STATE, *PCMP_GET_PLUG_STATE;
    .
    .
    .
  };
} AV_61883_REQUEST, *PAV_61883_REQUEST;

AV_61883_REQUEST Input

Function
Av61883_GetPlugState
hPlug
The handle of the plug to retrieve state information.

AV_61883_REQUEST Output

State
The state of the plug. Can be one of the following:

CMP_PLUG_STATE_IDLE

CMP_PLUG_STATE_READY

CMP_PLUG_STATE_SUSPENDED

CMP_PLUG_STATE_ACTIVE

DataRate
The data rate of the plug. Can be one of the following:

CMP_SPEED_S100

CMP_SPEED_S200

CMP_SPEED_S400

Payload
The payload size for the plug.
BC_Connections
The number of broadcast connections associated with the plug.
PP_Connections
The number of point-to-point connections associated with the plug.

I/O Status Block

If successful, the IEC-61883 protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

If an incorrect parameter is passed in, the protocol driver sets Irp->IoStatus.Status to STATUS_INVALID_PARAMETER.

Operation

Plug state is volatile and can change unexpectedly.

Headers

Defined in 61883.h. Include 61883.h.

See Also

AV_61883_REQUEST, Av61883_CreatePlug, Av61883_Connect


Av61883_GetUnitInfo

The Av61883_GetUnitInfo request retrieves unit information about the device.

The relevant members of the AV_61883_REQUEST structure for this request are:

typedef struct _AV_61883_REQUEST {
  ULONG  Function;
  ULONG  Flags;
  union {
    typedef struct _GET_UNIT_INFO {
      IN ULONG  nLevel;
      IN OUT PVOID  Information;
    } GET_UNIT_INFO, *PGET_UNIT_INFO;
    .
    .
    .
  };
} AV_61883_REQUEST, *PAV_61883_REQUEST;

AV_61883_REQUEST Input

Function
Av61883_GetUnitInfo
Flags
Specifies either RETRIEVE_DEVICE_UNIT_INFO or RETRIEVE_LOCAL_UNIT_INFO. Only used when nLevel is set to GET_UNIT_INFO_CAPABILITIES.
nLevel
The level of information to retrieve. Can be one of the following:

GET_UNIT_INFO_IDS

GET_UNIT_INFO_CAPABILITIES

GET_UNIT_INFO_ISOCH_PARAMS

GET_UNIT_BUS_GENERATION_NODE

GET_UNIT_DDI_VERSION

GET_UNIT_DIAG_LEVEL

Information
If nLevel is GET_UNIT_INFO_IDS, this member points to a caller-allocated and initialized GET_UNIT_IDS structure.

The input GET_UNIT_IDS structure should be initialized to all zeros to obtain the length of the VendorText and ModelText strings. To obtain the strings themselves, the input ulVendorLength and ulModelLength members should be initialized to the values returned by the previous Av61883_GetUnitInfo call, and the input VendorText and ModelText members should point to buffers large enough to receive the strings.

If nLevel is GET_UNIT_INFO_CAPABILITIES, this member points to a caller-allocated GET_UNIT_CAPABILITIES structure.

If nLevel is GET_UNIT_INFO_ISOCH_PARAMS, this member points to a caller-allocated UNIT_ISOCH_PARAMS structure.

AV_61883_REQUEST Output

Information
Pointer to information supplied by the protocol driver about the device.

If the caller set nLevel to GET_UNIT_INFO_IDS, the protocol driver writes device ID information to the caller-allocated GET_UNIT_IDS structure at Information.

If the caller set nLevel to GET_UNIT_INFO_CAPABILITIES, the protocol driver writes a GET_UNIT_CAPABILITIES structure containing device capability information.

If the caller set nLevel to GET_UNIT_ISOCH_PARAMS, the protocol driver writes a UNIT_ISOCH_PARAMS structure containing device parameters used by the device to capture and transmit isochronous packets.

If the caller sets nLevel to GET_UNIT_BUS_GENERATION_NODE, the protocol driver writes current bus characteristics to the caller-allocated BUS_GENERATION_NODE structure at Information.

If the caller sets nLevel to GET_UNIT_DDI_VERSION, the protocol driver writes current 61883 DDI version to the caller-allocated UNIT_DDI_VERSION structure at Information.

If the caller sets nLevel to GET_UNIT_DIAG_LEVEL, the protocol driver writes current diag level to the caller-allocated UNIT_DIAG_LEVEL structure at Information.

I/O Status Block

If successful, the IEC-61883 protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

If an incorrect parameter is passed in, the protocol driver sets Irp->IoStatus.Status to STATUS_INVALID_PARAMETER.

Operation

The Plug and Play ID for a 61883 device is based on its VendorID, ModelID, and Character/Transaction Set (CTS).

Headers

Defined in 61883.h. Include 61883.h.

See Also

AV_61883_REQUEST, UNIT_ISOCH_PARAMS


Av61883_Listen

The Av61883_Listen request begins isochronous reception on the specified connection.

The relevant members of the AV_61883_REQUEST structure for this request are:

typedef struct _AV_61883_REQUEST {
  ULONG Function;
  union {
    typedef struct _CIP_LISTEN {
      IN HANDLE  hConnect;
    } CIP_LISTEN, *PCIP_LISTEN;
    .
    .
    .
  };
} AV_61883_REQUEST, *PAV_61883_REQUEST;

AV_61883_REQUEST Input

Function
Av61883_Listen
hConnect
The handle of the connection to begin isochronous reception.

I/O Status Block

If successful, the IEC-61883 protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

If an incorrect parameter is passed in, the protocol driver sets Irp->IoStatus.Status to STATUS_INVALID_PARAMETER.

If the protocol driver is unable to allocate resources, it sets Irp->IoStatus.Status to STATUS_INSUFFICIENT_RESOURCES.

Operation

This request will start capturing CIP packets, whether or not the packets have frames attached.

Headers

Defined in 61883.h. Include 61883.h.

See Also

AV_61883_REQUEST, Av61883_Talk, Av61883_Stop


Av61883_MonitorPlugs

The Av61883_MonitorPlugs request allows a driver to monitor all access to local oPCR and iPCR plugs.

The relevant members of the AV_61883_REQUEST structure for this request are:

typedef struct _AV_61883_REQUEST {
  ULONG  Function;
  union {
    typedef struct _CMP_MONITOR_PLUGS {
      IN ULONG  Flags;
      IN PCMP_MONITOR_ROUTINE  pfnNotify;
      IN PVOID  Context;
    } CMP_MONITOR_PLUGS, *PCMP_MONITOR_PLUGS;
    .
    .
    .
  };
} AV_61883_REQUEST, *PAV_61883_REQUEST;

AV_61883_REQUEST Input

Function
Av61883_MonitorPlugs
Flags
The caller sets this member to REGISTER_MONITOR_PLUG_NOTIFY to register to monitor all local plug access. This member can also be set to DEREGISTER_MONITOR_PLUG_NOTIFY to stop monitoring local plug access.
pfnNotify
Pointer to a caller-supplied function to be called by the protocol driver when a local plug is accessed.

This function uses the following prototype:

typedef void
(*PCMP_MONITOR_ROUTINE) (
  IN PCMP_MONITOR_INFO  MonitorInfo
  );
MonitorInfo
Pointer to a CMP_MONITOR_INFO structure containing the contents of the plug that was modified.
Context
Pointer to a caller-defined context for the function at pfnNotify.

I/O Status Block

If successful, the IEC-61883 protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

If an incorrect parameter is passed in, the protocol driver sets Irp->IoStatus.Status to STATUS_INVALID_PARAMETER.

Operation

This request will start monitoring access to local plugs.

Headers

Defined in 61883.h. Declared in 61883.h.

See Also

AV_61883_REQUEST, CMP_MONITOR_INFO


Av61883_SendFcpRequest

The Av61883_SendFcpRequest request sends an FCP request to the device.

The relevant members of the AV_61883_REQUEST structure for this request are:

typedef struct _AV_61883_REQUEST {
  ULONG Function;
  union {
    typedef struct _FCP_SEND_REQUEST {
      IN NODE_ADDRESS  NodeAddress;
      IN ULONG  Length;
      IN PFCP_FRAME  Frame;
    } FCP_SEND_REQUEST, *PFCP_SEND_REQUEST;
    .
    .
    .
  };
} AV_61883_REQUEST, *PAV_61883_REQUEST;

AV_61883_REQUEST Input

Function
Av61883_SendFcpRequest
NodeAddress
If the protocol driver is being used to control a virtual device, NodeAddress must contain the node address of the device to which this request is being sent so the protocol driver can route the request to the correct device. If the protocol driver is being used to control a physical device, NodeAddress is not used.
Length
The length of the Frame payload in bytes, including the FCP header.
Frame
Pointer to an FCP_FRAME structure that contains the FCP request to send to the device.

I/O Status Block

If successful, the IEC-61883 protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

If an incorrect parameter is passed in, the protocol driver sets Irp->IoStatus.Status to STATUS_INVALID_PARAMETER.

If the protocol driver is unable to allocate resources, it sets Irp->IoStatus.Status to STATUS_INSUFFICIENT_RESOURCES.

Operation

If the protocol driver is being used to represent a virtual device on the machine, the client driver must specify the NodeAddress member of FCP_SEND_REQUEST structure. This information is required in order to route the request to the proper node on the 1394 bus.

If the protocol driver is being used to control a physical device, the 1394 bus driver determines the node address dynamically, and NodeAddress is not used.

Headers

Defined in 61883.h. Include 61883.h.

See Also

AV_61883_REQUEST, Av61883_GetFcpResponse, FCP_FRAME


Av61883_SendFcpResponse

The Av61883_SendFcpResponse request sends an FCP response to the device.

The relevant members of the AV_61883_REQUEST structure for this request are:

typedef struct _AV_61883_REQUEST {
  ULONG Function;
  union {
    typedef struct _FCP_SEND_RESPONSE {
      IN NODE_ADDRESS  NodeAddress;
      IN ULONG   Length;
      IN PFCP_FRAME  Frame;
    } FCP_SEND_RESPONSE, *PFCP_SEND_RESPONSE;
    .
    .
    .
  };
} AV_61883_REQUEST, *PAV_61883_REQUEST;

AV_61883_REQUEST Input

Function
Av61883_SendFcpResponse
NodeAddress
If the protocol driver is being used to control a virtual device, NodeAddress must contain the node address of the device that sent the FCP request obtained with Av61883_GetFcpRequest so the 1394 bus driver can route the response to the correct device.

If the protocol driver is being used to control a physical device, NodeAddress is not used.

Length
The length of the frame payload in bytes, including the FCP header.
Frame
Pointer to an FCP_FRAME structure that contains the FCP response to send to the device.

I/O Status Block

If successful, the IEC-61883 protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

If an incorrect parameter is passed in, the protocol driver sets Irp->IoStatus.Status to STATUS_INVALID_PARAMETER.

If the protocol driver is unable to allocate resources, it sets Irp->IoStatus.Status to STATUS_INSUFFICIENT_RESOURCES.

Operation

The Av61883_SendFcpResponse request is used in conjunction with Av61883_GetFcpRequest. A client driver should use Av61883_SendFcpResponse to return an FCP response for a received FCP request.

If the protocol driver is being used to represent a virtual device on the machine, the NodeAddress member from Av61883_GetFcpRequest must be specified in the NodeAddress member of the FCP_SEND_RESPONSE structure. This information is required in order to route the response to the proper node on the 1394 bus.

If the protocol driver is being used to control a physical device, the 1394 bus driver determines the node address dynamically, and NodeAddress is not used.

Headers

Defined in 61883.h. Include 61883.h.

See Also

AV_61883_REQUEST, Av61883_GetFcpRequest, FCP_FRAME


Av61883_SetFcpNotify

The Av61883_SetFcpNotify request registers a client driver notification of FCP requests or responses, or cancels a prior registration.

The relevant members of the AV_61883_REQUEST structure for this request are:

typedef struct _AV_61883_REQUEST {
  ULONG Function;
  union {
    typedef struct _SET_FCP_NOTIFY {
      IN ULONG   Flags;
      IN NODE_ADDRESS  NodeAddress;
    } SET_FCP_NOTIFY, *PSET_FCP_NOTIFY;
    .
    .
    .
  };
} AV_61883_REQUEST, *PAV_61883_REQUEST;

AV_61883_REQUEST Input

Function
Av61883_SetFcpNotify
Flags
Specifies the notification requested by the driver. The driver can register by setting Flags with either or both of the following:

REGISTER_FCP_RESPONSE_NOTIFY

REGISTER_FCP_REQUEST_NOTIFY

The driver can cancel notification by setting Flags with DEREGISTER_FCP_NOTIFY, which clears REGISTER_FCP_RESPONSE_NOTIFY and REGISTER_FCP_REQUEST_NOTIFY.

NodeAddress
Reserved for use by the operating system.

I/O Status Block

If successful, the IEC-61883 protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

Operation

A driver must register for FCP notifications in order to retrieve requests or responses. The driver is responsible for canceling registration by sending an Av61883_SetFcpNotify request with DEREGISTER_FCP_NOTIFY set in Flags before the system unloads the driver.

Headers

Defined in 61883.h. Include 61883.h.

See Also

AV_61883_REQUEST, Av61883_GetFcpRequest, Av61883_GetFcpResponse, Av61883_SendFcpRequest, Av61883_SendFcpResponse


Av61883_SetPlug

The Av61883_SetPlug request changes transmission settings for a plug control register.

The relevant members of the AV_61883_REQUEST structure for this request are:

typedef struct _AV_61883_REQUEST {
  ULONG Function;
  union {
    typedef struct _CMP_SET_PLUG {
      IN HANDLE  hPlug;
      IN AV_PCR  Pcr;
    } CMP_SET_PLUG, *PCMP_SET_PLUG;
    .
    .
    .
  };
} AV_61883_REQUEST, *PAV_61883_REQUEST;

AV_61883_REQUEST Input

Function
Av61883_SetPlug
hPlug
A handle to the plug.
Pcr
An AV_PCR structure that contains settings for the plug.

I/O Status Block

If successful, the IEC-61883 protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

If an incorrect parameter is passed in, the protocol driver sets Irp->IoStatus.Status to STATUS_INVALID_PARAMETER.

If a driver attempts to set the contents of a plug register it did not create, the protocol driver sets Irp->IoStatus.Status to STATUS_ACCESS_DENIED.

Operation

This request allows a driver to set the contents of a plug register it created. Only a driver that created a plug is allowed to set the contents of that plug.

See Also

AV_61883_REQUEST, AV_PCR, Av61883_CreatePlug


Av61883_SetUnitDirectory

The Av61883_SetUnitDirectory request exposes a unit directory within the configuration ROM of the local host.

The relevant members of the AV_61883_REQUEST structure for this request are:

typedef struct _AV_61883_REQUEST {
  ULONG Function;
  union {
    typedef struct _SET_UNIT_DIRECTORY {
      IN ULONG  Flags;
      IN ULONG  UnitSpecId;
      IN ULONG  UnitSwVersion;
      IN OUT HANDLE  hCromEntry;
    } SET_UNIT_DIRECTORY, *PSET_UNIT_DIRECTORY;
    .
    .
    .
  };
} AV_61883_REQUEST, *PAV_61883_REQUEST;

AV_61883_REQUEST Input

Function
Av61883_SetUnitDirectory
Flags
Specifies whether to add or remove a unit directory. Can be ADD_UNIT_DIRECTORY_ENTRY to add a unit directory, or REMOVE_UNIT_DIRECTORY_ENTRY to remove a unit directory. If ISSUE_BUS_RESET_AFTER_MODIFY is also set, a bus reset will be issued after the add or remove.
UnitSpecId
The UnitSpecId value to use within the unit directory, as defined in the IEEE 1394-1995 Specification.
UnitSwVersion
The UnitSwVersion value to use within the unit directory, as defined in the IEEE 1394-1995 Specification.
hCromEntry
A handle to the Configuration ROM entry.

If ADD-UNIT_DIRECTORY_ENTRY is set in Flags, hCromEntry is ignored.

If REMOVE_UNIT_DIRECTORY_ENTRY is set in Flags, hCromEntry is a handle to the Configuration ROM entry to remove.

AV_61883_REQUEST Output

hCromEntry
If ADD_UNIT_DIRECTORY_ENTRY is set in Flags, a handle to the newly added unit directory is written to hCromEntry.

If REMOVE_UNIT_DIRECTORY_ENTRY is set in Flags, hCromEntry is null.

I/O Status Block

If successful, the IEC-61883 protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

Operation

This request is used to create or remove a Configuration ROM entry in the configuration ROM of a local node. A driver is responsible for removing the Configuration ROM entries it has created before the system unloads the driver.

Headers

Defined in 61883.h. Include 61883.h.

See Also

AV_61883_REQUEST


Av61883_SetUnitInfo

The Av61883_SetUnitInfo request sets the parameters that the IEC-61883 protocol driver should use when capturing and transmitting isochronous packets.

The relevant members of the AV_61883_REQUEST structure for this request are:

typedef struct _AV_61883_REQUEST {
  ULONG Function;
  union {
    typedef struct _SET_UNIT_INFO {
      IN ULONG  nLevel;
      IN OUT PVOID  Information;
    } SET_UNIT_INFO, *PSET_UNIT_INFO;
    .
    .
    .
  };
} AV_61883_REQUEST, *PAV_61883_REQUEST;

AV_61883_REQUEST Input

Function
Av61883_SetUnitInfo
nLevel
The level of information to retrieve. Can be one of the following:

SET_UNIT_INFO_DIAG_LEVEL

SET_UNIT_INFO_ISOCH_PARAMS

SET_CMP_ADDRESS_RANGE_TYPE

Information
If nLevel is SET_UNIT_INFO_DIAG_LEVEL, this member is a pointer to a caller-allocated and initialized UNIT_DIAG_LEVEL structure.

If nLevel is SET_UNIT_INFO_ISOCH_PARAMS, this member is a pointer to a caller-allocated UNIT_ISOCH_PARAMS structure.

If nLevel is SET_CMP_ADDRESS_RANGE_TYPE, this member is a pointer to a caller-allocated SET_CMP_ADDRESS_TYPE structure.

I/O Status Block

If successful, the IEC-61883 protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

If an incorrect parameter is passed in, the protocol driver sets Irp->IoStatus.Status to STATUS_INVALID_PARAMETER.

Headers

Defined in 61883.h. Include 61883.h.

See Also

AV_61883_REQUEST, UNIT_ISOCH_PARAMS


Av61883_Stop

The Av61883_Stop request stops isochronous transmission or reception on the specified connection.

The relevant members of the AV_61883_REQUEST structure for this request are:

typedef struct _AV_61883_REQUEST {
  ULONG Function;
  union {
    typedef struct _CIP_STOP {
      IN HANDLE  hConnect;
    } CIP_STOP, *PCIP_STOP;
    .
    .
    .
  };
} AV_61883_REQUEST, *PAV_61883_REQUEST;

AV_61883_REQUEST Input

Function
Av61883_Stop
hConnect
A handle to the connection on which to stop isochronous transmission or reception.

I/O Status Block

If successful, the IEC-61883 protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

If an incorrect parameter is passed in, the protocol driver sets Irp->IoStatus.Status to STATUS_INVALID_PARAMETER.

Operation

This request will stop capturing CIP packets, whether or not there are any frames attached. If frames are attached and the stream is resumed, then processing of the frame is resumed on the next source packet within the frame.

To resume the stream on the beginning of the frame, a driver must set Flags with CIP_RESET_FRAME_ON_DISCONTINUITY in the CIP_FRAME structure passed with Av61883_AttachFrame.

Headers

Defined in 61883.h. Include 61883.h.

See Also

AV_61883_REQUEST, Av61883_AttachFrame, Av61883_Listen, Av61883_Talk, CIP_FRAME


Av61883_Talk

The Av61883_Talk request begins isochronous transmission on the specified connection.

The relevant members of the AV_61883_REQUEST structure for this request are:

typedef struct _AV_61883_REQUEST {
  ULONG Function;
  ULONG Flags;
  union {
    typedef struct _CIP_TALK {
      IN HANDLE  hConnect;
    } CIP_TALK, *PCIP_TALK;
    .
    .
    .
  };
} AV_61883_REQUEST, *PAV_61883_REQUEST;

AV_61883_REQUEST Input

Function
Av61883_Talk
Flags
Possible flag settings are:
CIP_TALK_USE_SPH_TIMESTAMP
Indicates that the timestamp within the SPH should be used to calculate the timing of transmission of isochronous packets.
CIP_TALK_DOUBLE_BUFFER
Indicates that when transmitting the attached frames should be double-buffered.
hConnect
The handle of the connection to begin isochronous transmission.

I/O Status Block

If successful, the IEC-61883 protocol driver sets Irp->IoStatus.Status to STATUS_SUCCESS.

If an incorrect parameter is passed in, the protocol driver sets Irp->IoStatus.Status to STATUS_INVALID_PARAMETER.

If the protocol driver is unable to allocate resources, it sets Irp->IoStatus.Status to STATUS_INSUFFICIENT_RESOURCES.

Operation

This request will start transmitting CIP packets, whether or not there are any frames attached. If no frames are attached, empty CIP packets are transmitted for every isochronous cycle.

Headers

Defined in 61883.h. Include 61883.h.

See Also

AV_61883_REQUEST, Av61883_Listen, Av61883_Stop


IEC-61883 Structures

This section describes structures used by IEC-61883 client drivers.

To use these structures, include the 61883.h header file that is shipped with the Microsoft® Windows® DDK.


AV_61883_REQUEST

The AV_61883_REQUEST structure is used to pass requests to the IEC-61883 protocol driver.

typedef struct _AV_61883_REQUEST {
  ULONG  Function;
  ULONG  Version;
  ULONG  Flags;
  union {
    GET_UNIT_INFO  GetUnitInfo;
    SET_UNIT_INFO  SetUnitInfo;
    CMP_GET_PLUG_HANDLE  GetPlugHandle;
    CMP_GET_PLUG_STATE  GetPlugState;
    CMP_CONNECT  Connect;
    CMP_DISCONNECT  Disconnect;
    CIP_ATTACH_FRAME  AttachFrame;
    CIP_CANCEL_FRAME  CancelFrame;
    CIP_TALK  Talk;
    CIP_LISTEN  Listen;
    CIP_STOP  Stop;
    FCP_SEND_REQUEST  SendRequest;
    FCP_GET_RESPONSE  GetResponse;
    FCP_GET_REQUEST  GetRequest;
    FCP_SEND_RESPONSE  SendResponse;
    SET_FCP_NOTIFY  SetFcpNotify;
    CMP_CREATE_PLUG  CreatePlug;
    CMP_DELETE_PLUG  DeletePlug;
    CMP_SET_PLUG  SetPlug;
    BUS_RESET_NOTIFY  BusResetNotify;
    SET_UNIT_DIRECTORY  SetUnitDirectory;
....CMP_MONITOR_PLUGS  MonitorPlugs;
  } ;
} AV_61883_REQUEST, *PAV_61883_REQUEST;

Members

Function
Determines the type of request. Each request type is documented under the value of Function in IEC-61883 Protocol I/O Requests.
Version
The device driver interface (DDI) version for the request. The INIT_61883_HEADER macro initializes Version to CURRENT_61883_DDI_VERSION.
Flags
Flags specific to the request. For details, see the reference page for the request. Drivers must set this member to zero for requests that do not use flags.
GetUnitInfo
A GET_UNIT_INFO structure, used if the Function member is Av61883_GetUnitInfo.
SetUnitInfo
A SET_UNIT_INFO structure, used if the Function member is Av61883_SetUnitInfo.
GetPlugHandle
A CMP_GET_PLUG_HANDLE structure, used if the Function member is Av61883_GetPlugHandle.
GetPlugState
A CMP_GET_PLUG_STATE structure, used if the Function member is Av61883_GetPlugState.
Connect
A CMP_CONNECT structure, used if the Function member is Av61883_Connect.
Disconnect
A CMP_DISCONNECT structure, used if the Function member is Av61883_Disconnect.
AttachFrame
A CIP_ATTACH_FRAME structure, used if the Function member is Av61883_AttachFrame.
CancelFrame
A CIP_CANCEL_FRAME structure, used if the Function member is Av61883_CancelFrame.
Talk
A CIP_TALK structure, used if the Function member is Av61883_Talk.
Listen
A CIP_LISTEN structure, used if the Function member is Av61883_Listen.
Stop
A CIP_STOP structure, used if the Function member is Av61883_Stop.
SendRequest
An FCP_SEND_REQUEST structure, used if the Function member is Av61883_SendFcpRequest.
GetResponse
An FCP_GET_RESPONSE structure, used if the Function member is Av61883_GetFcpResponse.
GetRequest
An FCP_GET_REQUEST structure, used if the Function member is Av61883_GetFcpRequest.
SendResponse
An FCP_SEND_RESPONSE structure, used if the Function member is Av61883_SendFcpResponse.
SetFcpNotify
A SET_FCP_NOTIFY structure, used if the Function member is Av61883_SetFcpNotify.
CreatePlug
A CMP_CREATE_PLUG structure, used if the Function member is Av61883_CreatePlug.
DeletePlug
A CMP_DELETE_PLUG structure, used if the Function member is Av61883_DeletePlug.
SetPlug
A CMP_SET_PLUG structure, used if the Function member is Av61883_SetPlug.
BusResetNotify
A BUS_RESET_NOTIFY structure, used if the Function member is Av61883_BusResetNotify.
SetUnitDirectory
A SET_UNIT_DIRECTORY structure, used if the Function member is Av61883_SetUnitDirectory.
MonitorPlugs
A CMP_MONITOR_PLUGS structure, used if the Function member is Av61883_MonitorPlugs.

Headers

Declared in 61883.h. Include 61883.h.

Comments

The Parameters->Others.Arguments1 member of an IOCTL_61883_CLASS IRP points to an AV_61883_REQUEST structure. The IEC-61883 protocol driver uses the request structure to determine the type of request made by the client driver, and also to return the results of the operation. See IEC-61883 Protocol I/O Requests for a description of the behavior of each request.

See Also

INIT_61883_HEADER macro, IOCTL_61883_CLASS


AV_PCR

The AV_PCR structure specifies settings for an input or output plug.

typedef struct _AV_PCR {
  union {
    OPCR  oPCR;
    IPCR  iPCR;
    ULONG ulongData;
  };
} AV_PCR, *PAV_PCR;

Members

oPCR
An OPCR structure that contains initialization values for an output plug. This structure is defined as follows:
typedef struct _OPCR {
  ULONG  Payload:10;
  ULONG  OverheadID:4;
  ULONG  DataRate:2;
  ULONG  Channel:6;
  ULONG  Reserved:2;
  ULONG  PPCCounter:6;
  ULONG  BCCCounter:1;
  ULONG  OnLine:1;
} OPCR, *POPCR;
iPCR
An IPCR structure that contains initialization values for an input plug.
typedef struct _IPCR {
  ULONG  Reserved0:16;
  ULONG  Channel:6;
  ULONG  Reserved1:2;
  ULONG  PPCCounter:6;
  ULONG  BCCCounter:1;
  ULONG  OnLine:1;
} IPCR, *PIPCR;
ulongData
Reserved for internal use.

Headers

Declared in 61883.h. Include 61883.h.

See Also

Av61883_SetPlug, Av61883_CreatePlug


BUS_GENERATION_NODE

The BUS_GENERATION_NODE structure is used in conjunction with the Av61883_GetUnitInfo request to retrieve bus characteristics.

typedef struct _BUS_GENERATION_NODE {
  OUT ULONG  GenerationCount;
  OUT NODE_ADDRESS  LocalNodeAddress;
  OUT NODE_ADDRESS  DeviceNodeAddress;
} BUS_GENERATION_NODE, *PBUS_GENERATION_NODE;

Members

GenerationCount
The current bus generation count.
LocalNodeAddress
The current node address of the local node.
DeviceNodeAddress
The current node address of the device.

Headers

Declared in 61883.h. Include 61883.h.

See Also

Av61883_GetUnitInfo


CIP_FRAME

The CIP_FRAME structure describes a frame to be attached to an input or output plug.

struct _CIP_FRAME {
  IN PCIP_FRAME  pNext;
  IN ULONG  Flags;
  IN PCIP_VALIDATE_ROUTINE  pfnValidate;
  IN PVOID  ValidateContext;
  IN PCIP_NOTIFY_ROUTINE  pfnNotify;
  IN PVOID  NotifyContext;
  OUT CYCLE_TIME  Timestamp;
  OUT ULONG  Status;
  IN OUT PUCHAR  Packet;
};

Members

pNext
Reserved for internal use.
Flags
Specifies options associated with this frame.

For packets to be received, Flags can be one of the following:

CIP_VALIDATE_FIRST_SOURCE
Instructs the IEC-61883 protocol driver to call the client-driver-supplied function at pfnValidate to validate only the first source packet.
CIP_VALIDATE_ALL_SOURCE
Instructs the IEC-61883 protocol driver to call the client-driver-supplied function at pfnValidate to validate all source packets.

For packets to be received, CIP_VALIDATE_XXX can be combined with either or both of the following:

CIP_STRIP_SOURCE_HEADER
Instructs the protocol driver to strip the source header packet within a source packet.
CIP_USE_SOURCE_HEADER_TIMESTAMP
Instructs the protocol driver to timestamp the frame with the timestamp found within the source header packet.

For packets to be transmitted, Flags can be one of the following:

CIP_DV_STYLE_SYT
The value at TimeStamp is formatted for data transmission to digital video devices (SD-DVCR, HD-DVCR, or SDL-DVCR).
CIP_AUDIO_STYLE_SYT
The value at TimeStamp is formatted for audio and music data transmission to audio devices.

For packets to be transmitted or received, Flags can also be set with the following:

CIP_RESET_FRAME_ON_DISCONTINUITY
Instructs the protocol driver to resume a stopped stream at the beginning of the frame instead of the next source packet.
pfnValidate
Pointer to a caller-supplied function to validate a source packet. This function uses the following prototype:
ULONG
  (*PCIP_VALIDATE_ROUTINE) (
    IN PCIP_VALIDATE_INFO  ValidateInfo
  );
ValidateInfo
Points to a CIP_VALIDATE_INFO structure that contains information about the frame. The IEC-61883 protocol driver allocates and initializes this structure from the input CIP_FRAME structure.

The CIP_VALIDATE_INFO structure is defined as follows:

typedef struct _CIP_VALIDATE_INFO {
  HANDLE  hConnect;
  PVOID  Context;
  CYCLE_TIME TimeStamp;
  PUCHAR  Packet;
} CIP_VALIDATE_INFO, *PCIP_VALIDATE_INFO;
hConnect
A handle to the connection.
Context
Pointer to the context provided by the caller at ValidateContext in the input CIP_FRAME structure.
TimeStamp
The timestamp of the current source packet.
Packet
The packet offset for the current source packet.
ValidateContext
Pointer to an optional caller-defined context for the function at pfnValidate. If the function does not require a context, ValidateContext can be NULL.
pfnNotify
Pointer to a caller-supplied function to be called by the protocol driver when the requested frame is completed. The protocol driver calls this function at IRQL = DISPATCH_LEVEL.

This function uses the following prototype:

ULONG
  (*PCIP_NOTIFY_ROUTINE) (
    IN PCIP_NOTIFY_INFO  NotifyInfo
  );
NotifyInfo
Pointer to a CIP_NOTIFY_INFO structure that contains information about the frame. The IEC-61883 protocol driver allocates and initializes this structure from the input CIP_FRAME structure.

The CIP_NOTIFY_INFO structure is defined as follows:

typedef struct _CIP_NOTIFY_INFO {
  HANDLE  hConnect;
  PVOID  Context;
  PCIP_FRAME Frame;
} CIP_NOTIFY_INFO, *PCIP_NOTIFY_INFO;
hConnect
A handle to the connection.
Context
Pointer to the context provided by the caller at NotifyContext in the input CIP_FRAME structure.
Frame
Pointer to the completed frame.
NotifyContext
Pointer to an optional caller-defined context for the function at pfnNotify. If the function does not require a context, NotifyContext can be NULL.
Timestamp
The time associated with completion of the frame.

For packets to be received, the protocol driver sets this member to the time when transmission of the frame was completed, unless CIP_USE_SOURCE_HEADER_TIMESTAMP is set in Flags.

For packets to be transmitted, CIP-DV_STYLE_SYT or CIP_AUDIO_STYLE_SYT in Flags indicates the format of the timestamp.

Status
The status of the frame. Can be one of the following:

CIP_STATUS_SUCCESS

CIP_STATUS_CORRUPT_FRAME

CIP_STATUS_FIRST_FRAME

Packet
Pointer to the beginning of a caller-allocated data buffer to be transmitted or received with this frame. The frame length specified in the associated Av61883_AttachFrame request indicates the size of the buffer.

Headers

Declared in 61883.h. Include 61883.h.

See Also

Av61883_AttachFrame, Av61883_CancelFrame


CMP_MONITOR_INFO

The CMP_MONITOR_INFO structure is used in conjunction with the Av61883_MonitorPlugs request to allow a driver to monitor access to local oPCR and iPCR plugs.

typedef struct _CMP_MONITOR_INFO {
  ULONG  State;
  ULONG  PlugNum;
  ULONG  PlugType;
  AV_PCR  Pcr;
  PVOID  Context;
} CMP_MONITOR_INFO, *PCMP_MONITOR_INFO;

Members

State
The current state of the plug.
PlugNum
The number of the plug that was accessed.
PlugType
The type of plug, either CMP_PlugOut or CMP_PlugIn.
Pcr
The current contents of the plug.
Context
Pointer to a caller-defined context that was registered with Av61883_MonitorPlugs.

Headers

Declared in 61883.h. Include 61883.h.

See Also

Av61883_MonitorPlugs


FCP_FRAME

The FCP_FRAME structure describes a function control protocol (FCP) request.

typedef struct _FCP_FRAME {
  UCHAR  ctype:4;
  UCHAR  cts:4;
  UCHAR  payload[511];
} FCP_FRAME, *PFCP_FRAME;

Members

ctype
The command or response type as defined by the Command/Transaction Set (CTS) used for this request.
cts
The CTS used for this FCP request. The CTS specifies the command set, the structure of the command/response field, and the rules of transactions used for sending FCP commands and responses.
payload
The FCP request for this frame.

Headers

Declared in 61883.h. Include 61883.h.

See Also

Av61883_GetFcpRequest, Av61883_GetFcpResponse, Av61883_SendFcpRequest, Av61883_SendFcpResponse


GET_UNIT_CAPABILITIES

The GET_UNIT_CAPABILITIES structure is used in conjunction with the Av61883_GetUnitInfo request to retrieve unit information about a device's capabilities.

typedef struct _GET_UNIT_CAPABILITIES {
  OUT ULONG  NumOutputPlugs;
  OUT ULONG  NumInputPlugs;
  OUT ULONG  MaxDataRate;
  OUT ULONG  CTSFlags;
  OUT ULONG  HardwareFlags;
} GET_UNIT_CAPABILITIES, *PGET_UNIT_CAPABILITIES;

Members

NumOutputPlugs
The number of output plugs supported by the device.
NumInputPlugs
The number of input plugs supported by the device.
MaxDataRate
The maximum data rate of the device. Can be one of the following:

CMP_SPEED_S100
CMP_SPEED_S200
CMP_SPEED_S400

CTSFlags
A bit mask that identifies the command and transaction sets supported by the device. For example, if CTSFlags is 0001, the device supports Audio Video Control (AV/C). If CTSFlags is 4000, the device supports a vendor-unique CTS. Most devices that support multiple command and transaction sets report each CTS value in a separate Configuration ROM unit directory entry, so typically only one bit is set at a time.
HardwareFlags
If the AV_HOST_DMA_DOUBLE_BUFFERING_ENABLED flag is set, and the request level is SET_UNIT_INFO_ISOCH_PARAMS, then a size limit is imposed on members RX_NumPackets and TX_NumPackets of the UNIT_ISOCH_PARAMS structure. These members, when multiplied by the packet size, must be less than or equal to 64 KB. For example, Rx_NumPackets * PacketSize must be less than or equal to 64 KB.

Headers

Declared in 61883.h. Include 61883.h.

See Also

Av61883_GetUnitInfo


GET_UNIT_IDS

The GET_UNIT_CAPABILITIES structure is used in conjunction with the Av61883_GetUnitInfo request to retrieve device identifiers.

typedef struct _GET_UNIT_IDS {
  OUT LARGE_INTEGER  UniqueID;
  OUT ULONG  VendorID;
  OUT ULONG  ModelID;
  OUT ULONG  ulVendorLength;
  OUT PWSTR  VendorText;
  OUT ULONG  ulModelLength;
  OUT PWSTR  ModelText;
} GET_UNIT_IDS, *PGET_UNIT_IDS;

Members

UniqueID
The unique ID for the device from the bus information block within the configuration ROM of the unit.
VendorID
The vendor ID for the device.
ModelID
The model ID for the device. This value is retrieved from the root directory within the device's Configuration ROM.
ulVendorLength
The length, in bytes, of the vendor text string, including the terminating UNICODE_NULL. If ulVendorLength is not zero in the input GET_UNIT_IDS structure, VendorText must point to a buffer whose size is sizeof(ulVendorLength).
VendorText
Pointer to buffer that will receive the "friendly name" for the vendor as a UNICODE string terminated with a UNICODE_NULL. If ulVendorLength is zero in the input GET_UNIT_IDS structure, VendorText is null.
ulModelLength
The length, in bytes, of the model text string, including the terminating UNICODE_NULL. If ulModelLength is not zero in the input GET_UNIT_IDS structure, ModelText must point to a buffer whose size is sizeof(ulModelLength).
ModelText
Pointer to a buffer to receive the "friendly name" for the model as a UNICODE string terminated with a UNICODE_NULL. If ulModelLength is zero in the input GET_UNIT_IDS structure, ModelText is null. This value is retrieved from the root directory within the device's Configuration ROM.
UnitModelID
The model ID for the device. This value is retrieved from the unit directory within the device's Configuration ROM.
ulUnitModelLength
The length, in bytes, of the model text string, including the terminating UNICODE_NULL. If ulUnitModelLength is not zero in the input GET_UNIT_IDS structure, UnitModelText must point to a buffer whose size is sizeof(ulUnitModelLength).
UnitModelText
Pointer to a buffer that receives the "friendly name" for the model represented as a UNICODE string terminated with a UNICODE_NULL. If ulUnitModelLength is zero in the input GET_UNIT_IDS structure, UnitModelText will be NULL. This value is retrieved from the unit directory within the device's Configuration ROM.

Headers

Declared in 61883.h. Include 61883.h.

See Also

Av61883_GetUnitInfo


SET_CMP_ADDRESS_TYPE

The SET_CMP_ADDRESS_TYPE structure is used in conjunction with the the Av61883_SetUnitInfo request to set the parameters that the IEC-61883 protocol driver should use when capturing and transmitting isochronous packets.

typedef struct _SET_CMP_ADDRESS_TYPE {
  IN ULONG  Type;
} SET_CMP_ADDRESS_TYPE, *PSET_CMP_ADDRESS_TYPE;

Members

Type
Indicates what kind of address range plugs can be accessed in. Possible values are:
CMP_ADDRESS_TYPE_GLOBAL
This requests the default behavior. All plugs created on the local system will be created within a global address range, accessible by any node on the 1394 bus.
CMP_ADDRESS_TYPE_EXCLUSIVE
This flag must be set before any plugs are created or removed within the driver. When this flag is set, all plugs created within the driver will be in an exclusive address range, only accessible to the device for which the driver is loaded.

Headers

Declared in 61883.h. Include 61883.h.

See Also

Av61883_SetUnitInfo


UNIT_DDI_VERSION

The UNIT_DDI_VERSION structure is used in conjunction with the Av61883_GetUnitInfo request to retrieve the current 61883 DDI version.

typedef struct _UNIT_DDI_VERSION {
  OUT ULONG  Version;
} UNIT_DDI_VERSION, *PUNIT_DDI_VERSION;

Members

Version
The current 61883 DDI version.

Headers

Declared in 61883.h. Include 61883.h.

See Also

Av61883_GetUnitInfo


UNIT_DIAG_LEVEL

The UNIT_DDI_VERSION structure is used in conjunction with the Av61883_GetUnitInfo request to retrieve the current diag level

typedef struct _UNIT_DIAG_LEVEL {
  IN ULONG  DiagLevel;
} UNIT_DIAG_LEVEL, *PUNIT_DIAG_LEVEL;

Members

DiagLevel
The bitmask representing the diaglevel. Possible settings are:
DIAGLEVEL_NONE
Nothing set.
DIAGLEVEL_IGNORE_OPLUG
Ignore programming of the oPCR plug on the device when set.
DIAGLEVEL_IGNORE_IPLUG
Ignore programming of the iPCR on the device when set
DIAGLEVEL_SET_CHANNEL_63
Set the channel to 63 when disconnecting from the device.
DIAGLEVEL_IPCR_IGNORE_FREE
Do not free isochronous resources when disconnecting from the device iPCR.

Headers

Declared in 61883.h. Include 61883.h.

See Also

Av61883_GetUnitInfo


UNIT_ISOCH_PARAMS

The UNIT_ISOCH_PARAMS structure is used to get or set the parameters that the IEC-61883 protocol driver uses when capturing or transmitting isochronous packets.

typedef struct _UNIT_ISOCH_PARAMS {
  IN OUT ULONG  RX_NumPackets;
  IN OUT ULONG  RX_NumDescriptors;
  IN OUT ULONG  TX_NumPackets;
  IN OUT ULONG  TX_NumDescriptors;
} UNIT_ISOCH_PARAMS, *PUNIT_ISOCH_PARAMS;

Members

RX_NumPackets
The number of isochronous packets per descriptor to be received.
RX_NumDescriptors
The number of descriptors used for receiving isochronous data.
TX_NumPackets
The number of isochronous packets per descriptor to be transmitted.
TX_NumDescriptors
The number of descriptors used for transmitting isochronous data.

Headers

Declared in 61883.h. Include 61883.h.

Comments

The UNIT_ISOCH_PARAMS structure can be used with Av61883_SetUnitInfo to set the number of isochronous packets and descriptors used while transmitting or receiving data. Before setting isochronous parameters, a driver should send an Av61883_GetUnitInfo request to retrieve the current isochronous parameters and then make any necessary modifications with Av61883_SetUnitInfo.

See Also

Av61883_GetUnitInfo, Av61883_SetUnitInfo


Access Attribute Memory of a PCMCIA Device

This chapter describes how drivers for PCMCIA devices in Microsoft® Windows® 2000 and later operating systems can access the attribute memory of a PCMCIA device:

  • Requirements for Accessing Attribute Memory of a PCMCIA Device
  • Access PCMCIA Attribute Memory by Using a Plug and Play I/O Request

    This is a simple method that is sufficient for most purposes, but can only run at IRQL < DISPATCH_LEVEL.

  • Access PCMCIA Attribute Memory by Using a BUS_INTERFACE_STANDARD Interface

    This method eliminates the overhead of an I/O request and can run at IRQL <= DISPATCH_LEVEL

  • Access PCMCIA Attribute Memory Through a Permanent Memory Window

    A driver's ISR can use this method to directly access memory while running at IRQL DIRQL.

  • Access PCMCIA Attribute Memory by Using a PCMCIA_INTERFACE_STANDARD Interface

    Memory card drivers can use this method at IRQL <= DISPATCH_LEVEL.

These methods are supported by pcmcia.sys, the system driver for a PCMCIA bus in Windows 2000 and later operating systems.


Requirements for Accessing Attribute Memory of a PCMCIA Device

This section describes the requirements for the following types of access to attribute memory of a PCMCIA Device:

Query Device Information
A driver typically queries the following device information:
  • Identity of the device
  • Device parameters, such as capacity or speed that the driver uses to configure a device
  • Static data, such as a MAC address

Information queries are usually read-only, and are done relatively infrequently.

Configure a Device
Some drivers require write access to configuration registers in attribute memory.

A driver usually configures a device infrequently.

Note that the PCMCIA bus driver manages the standard PCMCIA configuration registers in attribute memory. Drivers must not write to these registers. If they do, unpredictable system behavior can occur. System setup and the Plug and Play Manager support INF file directives - for example, the LogConfig directive - that must be used to configure these registers.

Operate a device
Some PCMCIA devices use control registers located in attribute memory. Drivers must typically directly access these registers within an ISR. Accesses of this type can be relatively high in frequency, and require fast direct memory access.


Access PCMCIA Attribute Memory by Using a Plug and Play I/O Request

This section describes how a PCMCIA card driver can use Plug and Play I/O requests to access attribute memory.

A driver typically uses this method to initialize a device, to configure a device, or to obtain information from a device. A driver should use this method if the I/O overhead is acceptable, and the access can be done at IRQL < DISPATCH_LEVEL.

A driver can only use this method while running at IRQL < DISPATCH_LEVEL.

A driver performs the following sequence of operations:

  • Creates and initializes a new IRP_MJ_PNP request.

    The driver specifies either an IRP_MN_READ_CONFIG or an IRP_MN_WRITE_CONFIG minor function.

  • Gets the next stack location.
  • Sets the following members of the Parameters.ReadWriteConfig structure in the new stack location:
    WhichSpace
    Specifies the value PCCARD_ATTRIBUTE_MEMORY.
    Buffer
    Pointer to a paged-memory buffer that the driver allocates for the access. For a write operation, the buffer contains the data to write to the configuration space. For a read operation, the buffer is a zero-filled buffer. After the request completes, this buffer holds a copy of the attribute memory read from the device.
    Offset
    Specifies the byte offset from the base of the attribute memory where the read or write operation begins.
    Length
    Specifies the size in bytes of the buffer that the driver allocates for the request.
  • Sets a completion routine.
  • Sends the request down the device stack.


Access PCMCIA Attribute Memory by Using a BUS_INTERFACE_STANDARD Interface

This section describes how a PCMCIA card driver can use the BUS_INTERFACE_STANDARD interface to access attribute memory.

A driver should use a BUS_INTERFACE_STANDARD interface if the overhead of an I/O request is unacceptable. This method is like the I/O request method, in that it passes a buffer pointer. However, this method calls an interface routine, which eliminates the overhead of an I/O request. A driver must use this method if it accesses attribute memory while running at IRQL DISPATCH_LEVEL – for example, within a deferred procedure call (DPC).

A driver can use this method while running at IRQL <= DISPTACH_LEVEL.

A driver usually obtains a BUS_INTERFACE_STANDARD interface during its initialization. The driver uses an IRP_MN_QUERY_INTERFACE request to obtain the interface from the PCMCIA bus driver. The query interface request must be sent at IRQL PASSIVE_LEVEL.

After the driver obtains the standard bus interface, the driver can call the interface routines GetBusData or SetBusData to access attribute memory.


PCMCIA Drivers, Access PCMCIA Attribute Memory through a Permanent Memory Window

Previous Next

Access PCMCIA Attribute Memory Through a Permanent Memory Window

This section describes how a PCMCIA card driver can use a permanent-assigned memory window to access attribute memory.

A driver should use this method to support PCMCIA devices that implement device registers in attribute memory. In such cases, a driver's ISR typically needs fast direct access to the device registers while running at IRQL DIRQL.

Drivers can use this method while running at IRQL DIRQL.

Setup and the Plug and Play Manager support the INF file section DDInstall.LogConfigOverride, which can force the Plug and Play Manager to use the resources specified in a PcCardConfig entry. The LogConfigOverride section specifies a log config section that contains a PcCardConfig entry. Fields in the PcCardConfig entry specify the required memory resource, and that the memory resource is used for attribute memory.


PCMCIA Drivers, Access PCMCIA Attribute Memory by Using a PCMCIA_INTERFACE_STANDARD Interface

Previous Next

Access PCMCIA Attribute Memory by Using a PCMCIA_INTERFACE_STANDARD Interface

This section describes how a driver can use a PCMCIA_INTERFACE_STANDARD interface to access attribute memory.

The PCMCIA interface standard is provided primarily for memory card drivers and file systems.

A driver can use the PCMCIA_MODIFY_MEMORY_WINDOW interface routine supported by the PCMCIA_INTERFACE_STANDARD interface. PCMCIA_MODIFY_MEMORY_WINDOW sets the attributes of a memory window for a PCMCIA memory card. The memory window is mapped by the PCMCIA bus driver. Note that this routine does not provide a permanent window, it only modifies the current settings for an existing window. In addition, settings are not persistent over a change in the system power state.

For more information, see PCMCIA_INTERFACE_STANDARD Interface for Memory Cards.


PCMCIA_INTERFACE_STANDARD Interface for Memory Cards

This chapter describes the PCMCIA_INTERFACE_STANDARD interface that Microsoft® Windows® 2000 and later operating systems provide for PCMCIA memory cards and linear flash memory cards:

Functionality of the interface

Obtaining an interface

Calling an interface routine

Special considerations for PCMCIA memory card drivers


Functionality of the PCMCIA_INTERFACE_STANDARD Interface

This section describes the functionality of the PCMCIA_INTERFACE_STANDARD interface that PCMCIA bus driver supports in Windows 2000 and later operating systmes. The PCMCIA_INTERFACE_STANDARD interface provides a set of routines that can be called directly by a PCMCIA driver. These interface routines support the following operations:

  • Modify the attributes of the memory window that is mapped by the PCMCIA bus driver
  • Set the Vpp (secondary power source) level for the device
  • Determine if the card memory is write-protected

For more information on the routines provided by the PCMCIA_INTERFACE_STANDARD interface, see PCMCIA_INTERFACE_STANDARD Interface Memory Card Routines.


Obtaining a PCMCIA_INTERFACE_STANDARD Interface

This section describes how a driver can obtain a PCMCIA_INTERFACE_STANDARD interface for a PCMCIA memory card from the PCMCIA bus driver.

A driver obtains a PCMCIA_INTERFACE_STANDARD interface by creating and sending an IRP_MJ_PNP request that specifies a IRP_MN_QUERY_INTERFACE minor function code. The driver carries out the following operations:

  • Allocates and zero-fills a PCMCIA_INTERFACE_STANDARD structure in the paged memory pool.
  • Creates an IRP for the query interface request and gets the next stack location for the new IRP.
  • Sets the following members in the new stack location:
    • The Parameters.QueryInterface.Interface member points to the driver-allocated PCMCIA_INTERFACE_STANDARD structure that was allocated by the driver.
    • The Parameters.QueryInterface.InterfaceType member specifies a standard PCMCIA interface by the GUID value GUID_PCMCIA_INTERFACE_STANDARD.
  • Sets a completion routine and sends the request down the driver stack.

If the request is successful, the PCMCIA bus driver fills in the PCMCIA_INTERFACE_STANDARD structure pointed to by Parameters.QueryInterface.Interface.

A driver must be running at IRQL < DISPATCH_LEVEL to send this request down the driver stack.


Calling a PCMCIA_INTERFACE_STANDARD Interface Routine

This section describes how to call a PCMCIA_INTERFACE_STANDARD interface routine.

After a driver obtains an PCMCIA_INTERFACE_STANDARD structure from the PCMCIA bus driver, the driver can call the interface routines.

Each interface routine requires a context pointer. The driver must use the Context member value returned by the PCMCIA bus driver in the PCMCIA_INTERFACE_STANDARD structure. If the context pointer is not valid, the system behavior is not defined, and the system might halt.

The PCMCIA_INTERFACE_STANDARD interface routines can be called at IRQL <= DISPATCH_LEVEL. To maintain overall system performance, it is strongly recommended that a driver call these routines at IRQL < DISPATCH_LEVEL. Calling an interface routine at IRQL DISPATCH_LEVEL can cause the caller to block system operation for a significant period of time.


Special Considerations for PCMCIA Memory Card Drivers

This section describes the following special considerations pertinent to the design and operation of a PCMCIA memory card driver:

  • Restrictions of Windows 2000 and later operating systems on memory windows of PCMCIA memory cards
  • Reading and writing attribute memory on a PCMCIA memory card


Restrictions on Memory Windows

This section describes the restrictions imposed by Windows 2000 and later operating systems on memory windows of PCMCIA memory cards.

The resource requirements of a PCMCIA memory card are normally specified by the bus driver when it enumerates the device at the request of the Plug and Play Manager. Specific memory windows can also be specified in a LogConfigOverride section of a device driver's INF file. A maximum of two memory windows can be requested for a PCMCIA memory card.


Read and Write Attribute Memory

This section describes how a PCMCIA driver can read and write the attribute memory on a PCMCIA memory card.

Windows 2000 and later operating systems treat attribute memory on a PCMCIA card as configuration space. Drivers cannot access this memory directly. To access attribute memory, drivers must create an IRP using a major function code of IRP_MJ_PNP and a minor function code of IRP_MN_READ_CONFIG or IRP_MN_WRITE_CONFIG.

The PCMCIA memory card driver carries out the following operations:

  • Creates and initializes the new IRP.
  • Gets the next stack location.
  • Sets the following members of the new stack location:
    • The ReadWriteConfig.WhichSpace member specifies the value PCCARD_ATTRIBUTE_MEMORY.
    • The Buffer member points to a driver-allocated, non-paged buffer for a read or a write operation. For a write operation, the buffer contains the data to write to the configuration space. For a read operation, the buffer is a zero-filled buffer. On completion of the IRP, this buffer is set to a copy of the attribute memory read from the device.
    • The Offset member specifies the byte offset from the base of the attribute memory where the read or write operation begins.
    • The Length member specifies the size, in bytes, of the buffer that is specified at Buffer.
  • Sets a completion routine.
  • Sends the request down the drive stack.

A driver must be running at IRQL < DISPATCH_LEVEL to send this request down the driver stack.


PCMCIA_INTERFACE_STANDARD Interface Memory Card Routines

This section describes the PCMCIA_INTERFACE_STANDARD interface routines provided by the system PCMCIA bus driver in Microsoft® Windows® 2000 and later operating systems. PCMCIA memory card drivers can call these routines to perform the following operations:

  • Modify the attributes of the memory window that is mapped by the PCMCIA bus driver
  • Set the Vpp (secondary power source) level for the device
  • Determine if the card memory is write-protected

To obtain pointers to these interface routines, a driver sends the PCMCIA bus driver an IRP_MJ_PNP request that specifies a IRP_MN_QUERY_INTERFACE minor function. The bus driver returns the interface information in a PCMCIA_INTERFACE_STANDARD structure:

typedef struct _PCMCIA_INTERFACE_STANDARD {
    USHORT    Size;
    USHORT    Version;
    PINTERFACE_REFERENCE    InterfaceReference;
    PINTERFACE_DEREFERENCE    InterfaceDereference;
    PVOID    Context;
    PPCMCIA_MODIFY_MEMORY_WINDOW    ModifyMemoryWindow;
    PPCMCIA_SET_VPP    SetVpp;
    PPCMCIA_IS_WRITE_PROTECTED    IsWriteProtected;
} PCMCIA_INTERFACE_STANDARD;

For more information on how to obtain a PCMCIA_INTERFACE_STANDARD interface, see PCMCIA_INTERFACE_STANDARD Interface for Memory Cards.

The routines in this section are listed in alphabetical order.


PCMCIA_IS_WRITE_PROTECTED

The PCMCIA_IS_WRITE_PROTECTED interface routine returns the write-protect condition of a PCMCIA memory card.

BOOLEAN
  (*PPCMCIA_IS_WRITE_PROTECTED)(
    IN PVOID  Context
    );

Parameters

Context
Pointer to the context for the interface routine.

Include

ntddpcm.h

Return Value

The PCMCIA_IS_WRITE_PROTECTED interface routine returns TRUE if the memory card is write-protected, otherwise it returns FALSE.

Comments

A caller must set the Context parameter to the context that is specified by the PCMCIA bus driver. The PCMCIA bus driver returns the context for the interface routines in the Context member of the same PCMCIA_INTERFACE_STANDARD structure that contains the pointers to the interface routines. If the Context parameter is not valid, system behavior is not defined, and the system might halt.

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL. To maintain overall system performance, it is recommended that drivers call this routine at IRQL < DISPATCH_LEVEL.

See Also

PCMCIA_MODIFY_MEMORY_WINDOW, PCMCIA_SET_VPP


PCMCIA_MODIFY_MEMORY_WINDOW

The PCMCIA_MODIFY_MEMORY_WINDOW interface routine sets the attributes of a memory window for a PCMCIA memory card. The memory window is mapped by the PCMCIA bus driver.

BOOLEAN
  (*PPCMCIA_MODIFY_MEMORY_WINDOW)(
    IN PVOID  Context,
    IN PHYSICAL_MEMORY  HostBase,
    IN PHYSICAL_MEMORY  CardBase,
    IN BOOLEAN  Enable,
    IN ULONG  WindowSize,
    IN UCHAR  AccessSpeed,
    IN UCHAR  BusWidth,
    IN BOOLEAN  AttributeMemory
    );

Parameters

Context
Pointer to the context for the interface routine.
HostBase
Specifies the physical memory window to map. HostBase is the base address for the memory card in the system's physical address space.
CardBase
Specifies the byte offset in the PCMCIA card's memory where the memory mapping begins.
Enable
Specifies permission to access the memory window. If Enable is TRUE, memory access is permitted, otherwise memory access is not permitted.
WindowSize
Specifies the size, in bytes, of the memory window that is mapped. The value of WindowSize cannot exceed the memory window granted to the driver in its assigned resources. If the value of Enable is TRUE and the value of WindowSize is zero, the size of the memory window granted to the driver in its assigned resources is used. If Enable is FALSE, WindowSize is not used.
AccessSpeed
Specifies the access speed of the PCMCIA card. The value of AccessSpeed is encoded as specified by the PC Card Standard, Release 6.1. If Enable is FALSE, AccessSpeed is not used.
BusWidth
Specifies the width of bus access to the PCMCIA memory card. BusWidth must be one of the following values:
PCMCIA_MEMORY_8BIT_ACCESS
PCMCIA_MEMORY_16BIT_ACCESS

If Enable is FALSE, BusWidth is not used.

AttributeMemory
Must be FALSE.

Include

ntddpcm.h

Return Value

The PCMCIA_MODIFY_MEMORY_WINDOW interface routine returns TRUE if the memory window is successfully enabled or disabled, as specified by the Enable parameter.

Comments

A caller must set the Context parameter to the context that is specified by the PCMCIA bus driver. The PCMCIA bus driver returns the context for the interface routines in the Context member of the same PCMCIA_INTERFACE_STANDARD structure that contains the pointers to the interface routines. If the Context parameter is not valid, system behavior is not defined, and the system might halt.

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL. To maintain overall system performance, it is recommended that drivers call this routine at IRQL < DISPATCH_LEVEL.

See Also

PCMCIA_IS_WRITE_PROTECTED, PCMCIA_SET_VPP, PCMCIA_INTERFACE_STANDARD


PCMCIA_SET_VPP

The PCMCIA_SET_VPP interface routine sets the power level of the Vpp PCMCIA pin (secondary power source).

BOOLEAN
  (*PPCMCIA_SET_VPP)(
    IN PVOID  Context,
    IN UCHAR  VppLevel
    );

Parameters

Context
Pointer to the context for the interface routine.
VppLevel
Specifies the voltage level to set on the Vpp pin. VppLevel must be one of the following values:
PCMCIA_VPP_0V
Specifies that the voltage on the Vpp pin be set to zero volts and that the Vpp pin be disabled.
PCMCIA_VPP_12V
Specifies that the voltage on the Vpp pin be set to twelve volts.
PCMCIA_VPP_IS_VCC
Specifies that the voltage on the Vpp pin be set to equal the voltage on the Vcc (primary card power) pin.

Include

ntddpcm.h

Return Value

The PCMCIA_SET_VPP interface routine returns TRUE after the requested voltage level is set.

Comments

The PCMCIA_SET_VPP interface routine returns control to the caller after the requested voltage is established in a stable state for the card.

A caller must set the Context parameter to the context that is specified by the PCMCIA bus driver. The PCMCIA bus driver returns the context for the interface routines in the Context member of the same PCMCIA_INTERFACE_STANDARD structure that contains the pointers to the interface routines. If the Context parameter is not valid, system behavior is not defined, and the system might halt.

Callers of this routine can run at IRQL <= DISPATCH_LEVEL. To maintain overall system performance, it is recommended that drivers call this routine at IRQL < DISPATCH_LEVEL.

See Also

PCMCIA_IS_WRITE_PROTECTED, PCMCIA_MODIFY_MEMORY_WINDOW


SCSI Miniport Drivers

This section contains the following information:

Supporting Plug and Play in a SCSI Miniport Driver

Registry Entries for Plug and Play SCSI Miniport Drivers

SCSI Miniport Initialization Under Plug and Play

Converting a Windows NT 4.0 SCSI Miniport for Plug and Play

Required and Optional SCSI Miniport Routines

SCSI Miniport Driver's DriverEntry Routine

Calling ScsiPortInitialize

Storage Driver's Return from DriverEntry

SCSI Miniport Driver's HwScsiFindAdapter Routine

Calling ScsiPortXxx from HwScsiFindAdapter

Port-Driver-Supplied ConfigInfo for HwScsiFindAdapter

Setting up ConfigInfo in HwScsiFindAdapter

Setting Again and Returning from HwScsiFindAdapter

Returning Control from HwScsiFindAdapter

SCSI Miniport Driver's HwScsiInitialize Routine

SCSI Miniport Driver's HwScsiStartIo Routine

Modifying SRBs

Handling SRB_FUNCTION_EXECUTE_SCSI

Handling SRB_FUNCTION_ABORT_COMMAND

Handling SRB_FUNCTION_RESET_BUS

Handling SRB_FUNCTION_RESET_DEVICE

Handling SRB_FUNCTION_FLUSH and SRB_FUNCTION_SHUTDOWN

Handling SRB_FUNCTION_IO_CONTROL

Handling SRB_FUNCTION_WMI

Handling Unsupported SRB_FUNCTION_XXX

Return from HwScsiStartIo

Other SRB_FUNCTION_XXX Requests

SCSI Miniport Driver's HwScsiDmaStarted Routine

SCSI Miniport Driver's HwScsiResetBus Routine

SCSI Miniport Driver's HwScsiInterrupt Routine

Deferring Interrupt-Driven I/O from HwScsiInterrupt

SCSI Miniport Driver's HwScsiEnableInterruptsCallback Routine

SCSI Miniport Driver's HwScsiDisableInterruptsCallback Routine

SCSI Miniport Driver's HwScsiTimer Routine

SCSI Miniport Driver's HwScsiAdapterState Routine

SCSI Miniport Driver's HwScsiAdapterControl Routine

Error Handling in SCSI Miniport Drivers

SCSI miniport drivers for NT-based operating systems are HBA-specific but operating system-independent. That is, each miniport driver links itself with the system-supplied SCSI port driver, which is a dynamic-link library (DLL), and calls only the port driver's ScsiPort Xxx routines to communicate with the system and its HBA. Such SCSI miniport drivers run on other Microsoft operating systems that support Win32® applications and also export the ScsiPort Xxx routines.

Note that any SCSI miniport driver that calls routines other than the ScsiPort Xxx cannot run in both Microsoft® operating system environments. To remain portable across Microsoft Windows systems, including NT-based operating systems, SCSI miniport drivers must call only the system-supplied ScsiPort Xxx.

A SCSI miniport can be a Plug and Play driver, or it can run as a legacy driver that does not participate in Plug and Play operations such as resource redistribution or power management. The primary differences between a Plug and Play and a legacy miniport driver are the order in which initialization routines are called and enforcement of certain restrictions that were applied to miniports in Windows NT 4.0 but not enforced.


Supporting Plug and Play in a SCSI Miniport Driver

Although Windows® 2000 and later operating systems are Plug and Play operating systems, by default SCSI miniports are run as legacy drivers. The HBA for a legacy miniport driver cannot be removed from the system while it is running, nor are legacy miniports automatically detected when added to a running system. These limitations might be acceptable for certain HBAs, but SCSI miniports for PCMCIA/CardBus HBAs and HBAs in laptops should support Plug and Play.

A Plug and Play miniport must implement an HwScsiAdapterControl routine to stop and manage power to the HBA. No additional routines are required of a Plug and Play miniport driver to accommodate changes in driver initialization.

The SCSI port driver creates PDOs for target devices and the FDO for the miniport driver, and handles AddDevice, StartDevice, and UnloadDevice requests on a Plug and Play miniport driver's behalf. For general information about Plug and Play drivers, see Plug and Play.


Registry Entries for Plug and Play SCSI Miniport Drivers

To support Plug and Play, a SCSI miniport driver must:

  • Be installed as a service for the HBA.
  • Have a PnPInterface entry in the registry that indicates the interfaces for which the miniport supports Plug and Play.

Installing a miniport driver as a service for a SCSI HBA is customarily done by providing an INF file that matches the Plug and Play hardware ID for a given HBA to the correct driver to control that device. For details about setting up an INF file, see Plug and Play .

Unless a miniport driver is installed as a service for an HBA, the PnPInterface registry entry will prevent the miniport from initializing. The specified interfaces are initialized only when Plug and Play locates an appropriate HBA. If no service is properly assigned to the HBA, Plug and Play will never determine which driver to notify when it detects the device. This behavior is by design and a miniport should not attempt to circumvent it.

The PnPInterface registry entry should be made under the Services key for the miniport. For example, the following registry entry enables Plug and Play for a fictitious miniport driver called Twiddle.

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
    \Twiddle
        \Parameters
            \PnpInterface
                5 : REG_DWORD : 1
                1 : REG_DWORD : 1
                2 : REG_DWORD : 1
                8 : REG_DWORD : 1

The values preceding REG_DWORD correspond to the INTERFACE_TYPE enumerated type declared in miniport.h. The values in this example indicate that the Twiddle miniport supports Plug and Play for the following interfaces: PCIBus (5), Isa (1), Eisa (2) and PCMCIABus (8). The value following REG_DWORD is a flag that indicates Plug and Play support for the interface. (Currently, this flag can be any value but must be present. In the future, the flag may be optional.)

After the PnPInterface values are set in the registry and the system is restarted, the miniport driver can be initialized as a Plug and Play driver. During initialization, the SCSI port driver checks the registry to determine whether the miniport should be run as a Plug and Play or legacy driver. The SCSI port driver checks the registry for each interface type that the miniport supports (PCI, ISA, etc.). This is intended primarily to simplify debugging for writers of multiple-interface miniport drivers. The miniport driver writer should make sure that a miniport driver is capable of being run as a Plug and Play driver for all interfaces that driver supports.


SCSI Miniport Initialization Under Plug and Play

For Windows 2000 and later, a legacy miniport is initialized in exactly the same way as for Windows NT 4.0. When a legacy miniport calls ScsiPortInitialize, the port driver calls the miniport to locate and initialize its HBA. This is done either once for each HBA it finds (if the HBA is on an enumerable bus) or repeatedly until the miniport reports that it cannot find any more devices. Control then returns to the miniport's DriverEntry routine, where the miniport can call ScsiPortInitialize again for a different type of HBA (for example, a different interface or a different vendor and product ID). All of the initialization calls are made within the context of the miniport's DriverEntry routine and are made in the order that ScsiPortInitialize was called. Initialization of legacy drivers occurs at system startup and at no other time.

Under Plug and Play, the order of initialization cannot be preserved. When a miniport driver that is enabled for Plug and Play calls ScsiPortInitialize, the port driver stores the initialization data for future reference, then returns STATUS_SUCCESS. This is done for each interface type that is listed in the miniport's PnPInterface registry key — any interfaces not listed in that key are still initialized immediately.

Later, when the Plug and Play Manager detects an HBA for the miniport, it notifies the port driver. The port driver allocates the necessary system resources (such as memory for the miniport's device extension) and calls the miniport to find the HBA and then to initialize it. This usually happens during system startup, but it might also happen when the system detects a docking operation or when an HBA such as a PCMCIA card is hot-plugged into the system.

By the time the Plug and Play Manager reports a device, it has already allocated bus resources (such as I/O ports, memory addresses, and interrupts) for that device and that device alone. These resources are supplied to the miniport, which must either use these resources or report that no device was found. In particular, the miniport must not attempt to access ports or memory locations other than the ones specified to find a device.

A miniport driver that has been started as a Plug and Play driver might be asked to detect devices that are on non-enumerable buses. This includes buses such as ISA, which require that the miniport issue commands on the bus to find its HBA. Devices located during such detection are recorded in the registry and initialized as Plug and Play devices the next time the system is started.

For more information about Plug and Play, see Plug and Play.


Converting a Windows NT 4.0 SCSI Miniport for Plug and Play

Even if a miniport driver has enabled Plug and Play in the registry, the driver will fault during initialization unless it honors certain restrictions in the use of the HwContext pointer and resources supplied by the port driver. A miniport might also fault during initialization if it depends on a predictable initialization order of drivers.

In order to run successfully under Plug and Play, a Windows NT 4.0 miniport driver's source code might need to be modified as described in the following sections.


Use the HwContext Pointer to HwScsiFindAdapter Correctly

If a miniport's HwScsiFindAdapter receives nonzero access range values from the port driver, it must not use the HwContext pointer. Although this restriction also applied to version 4.0 miniports, nothing prevented such a miniport from using this pointer.

If the miniport can be initialized as a Plug and Play driver in Windows 2000 and later, it must not use the HwContext pointer because the SCSI port driver passes in a NULL pointer as the HwContext argument.

How an existing miniport must be modified depends on how it currently uses HwContext. For example, if the miniport uses HwContext to maintain a count of HBAs (for example, to use in DebugPrint statements) an alternative might be to use the HwDeviceExtension pointer instead. HwDeviceExtension provides a unique number that is related to the particular HBA originating the DebugPrint message. (Using a global variable to store the HBA count is a bad practice, because miniport drivers should not use global variables to maintain state information.)

As another example, if the 4.0 version of the miniport uses HwContext to communicate information about the type of device being initialized (such as information about the capabilities supported by a particular model of PCI HBA), the 5.0 version of the miniport might use ScsiPortGetBusData to get an identifier for the HBA, then use that identifier to search through a list of such parameter blocks to find the correct information.

Another possible miniport modification might be to provide this information in a registry string passed in the ArgumentString parameter. The registry string could be set by the miniport's INF file during initialization to information that pertains to the model of card detected. This provides more flexibility than hardcoding the parameters in the miniport, because such a miniport could handle new models of cards using an updated INF file instead of requiring the miniport driver to be recompiled.


Do Not Depend on Order of SCSI Miniport Initialization

Some miniport drivers support HBAs on several different system buses such as PCI, EISA, and ISA. Under Windows NT 4.0, such a miniport driver's HwScsiFindAdapter routine(s) were called in the order that the miniport called ScsiPortInitialize. In several cases, this was used to track the location of a card on one type of bus so the miniport could avoid detecting it on another.

For example, assume the Twiddle PCI SCSI HBA is also accessible on the ISA bus. Under Windows NT 4.0, the Twiddle miniport would keep track of which PCI HBAs it was called to initialize and the ISA bus locations in which they appeared. The miniport could use this information while scanning the ISA bus to determine which I/O ranges to skip.

Under Windows 2000 and later, this technique is no longer dependable. Because Plug and Play makes initialization order unpredictable, the Twiddle miniport could easily be called to scan for its ISA cards before initializing its PCI cards. The miniport would detect each PCI HBA twice, which could lead to a system crash.

In this case, if the Twiddle HBA had a command that could be used to determine the real bus interface of the card, the ISA bus scan could query each card it found. If the card were a PCI card and not an ISA card, then the Twiddle miniport driver would leave it alone until Plug and Play issued requests to pick it up.

If the order-dependent code of a miniport cannot be removed it must be run as a legacy driver on Windows 2000 and later platforms.


Use Only Supplied Resources in a Plug and Play SCSI Miniport

One of the goals for a Plug and Play system is to reduce or eliminate the number of drivers that detect their devices by accessing known memory locations. This includes drivers that determine their resources by reading the configuration space for their HBA.

Under Plug and Play, devices on enumerable buses are detected by the driver for the bus. This allows the bus driver to handle any resource conflicts, provide special-case fixes for broken bus and bridge parts, and so forth.

Consequently, a SCSI miniport must use only the resources provided by the port driver (if any) in Windows 2000 and later systems. The miniport is allowed to scan the bus for an HBA only if the port driver passes in zero-value access ranges. If the miniport attempts to use resources that are not assigned to it, the ScsiPortGetDeviceBase call will fail. Calls to read and write device registers or ports that have not been properly mapped also might fail.


Verify Resource Ranges in HwScsiFindAdapter During Detection

Although detection of devices by drivers is usually unnecessary under Plug and Play, the port driver might call a Plug and Play miniport's HwScsiFindAdapter routine to detect devices on a nonenumerable bus. Although this operation is similar to detection in Windows NT 4.0, the miniport must take care not to operate on ranges that might be in use by another device.

The miniport should call ScsiPortValidateRange before calling ScsiPortGetDeviceBase to ensure that the miniport-supplied range is safe to use. The miniport must be prepared for ScsiPortGetDeviceBase to fail and return a NULL pointer. The miniport should also avoid mapping memory starting at address zero, which makes it impossible to detect the failure of ScsiPortGetDeviceBase on some systems.


Required and Optional SCSI Miniport Routines

Every SCSI miniport driver must have at least the following system-defined routines:

  • DriverEntry to initialize the miniport driver
  • HwScsiFindAdapter to determine how (or whether) driver-supported HBA(s) are configured in the machine
  • HwScsiInitialize to initialize supported HBA(s)
  • HwScsiStartIo to start operations on its HBA(s) for incoming requests
  • HwScsiResetBus to handle bus reset requests

Depending on each HBA and the driver designer, SCSI miniport drivers also have some or all of the following system-defined routines:

  • HwScsiInterrupt to handle HBA-generated interrupts, which is optional if and only if the HBA does not generate interrupts so the miniport manages all I/O operations on its HBA by polling

    However, using polling exclusively has an adverse effect on a miniport's performance and on its HBA's I/O throughput. Such a miniport driver should also have an HwScsiTimer routine.

  • HwScsiDisableInterruptsCallback and HwScsiEnableInterruptsCallback to handle deferred I/O processing if interrupt-driven I/O operations take a long time
  • HwScsiTimer to time operations that require long delays on the HBA, or for any other purpose determined by the driver designer

    A miniport should have a HwScsiTimer routine if it has no HwScsiInterrupt routine so it can use the HwScsiTimer routine for efficient polling of its HBA.

  • HwScsiDmaStarted, which is required if the HBA uses a system DMA controller, to set up an HBA transfer after the system DMA controller has been programmed by the port driver
  • HwScsiAdapterState, which is optional if and only if the HBA has no BIOS or x86-real-mode driver and/or will never run in x86-only Microsoft Windows systems
  • HwScsiAdapterControl, which is required if the miniport driver supports Plug and Play

Each of the preceding miniport driver routines, except DriverEntry, has a name chosen to describe its functionality. Except for DriverEntry, which is a required name for every miniport's initial entry point, names for miniport driver routines can be anything the driver writer chooses.

The following sections describe the requirements for and functionality of each of these miniport driver routines. See SCSI Miniport Driver Routines for their formal definitions and descriptions of their parameters.

Error Handling in SCSI Miniport Drivers describes error-handling requirements for SCSI miniport drivers.


SCSI Miniport Driver's DriverEntry Routine

A DriverEntry routine is the initial entry point for most Windows NT kernel-mode drivers and for every SCSI miniport driver. A miniport's DriverEntry routine is called with two input arguments of type PVOID and must do the following:

  1. Initialize a HW_INITIALIZATION_DATA structure on the stack with zeros.
  2. Set the HwInitializationDataSize member to sizeof(HW_INITIALIZATION_DATA).
  3. Set driver-specific and HBA-specific values in the HW_INITIALIZATION_DATA members, including the miniport driver's entry points. The following entry points must be set:
    • HwScsiFindAdapter
    • HwScsiInitialize
    • HwScsiStartIo
    • HwScsiResetBus

    The following entry points can be set to a driver-supplied routine or must be set to NULL:

    • HwScsiInterrupt (NULL if the miniport uses polling exclusively)
    • HwScsiDmaStarted (NULL if the HBA uses PIO or is a busmaster)
    • HwScsiAdapterState (NULL if the miniport runs only on NT-based operating system platforms or if it is designed to also run on x86-only Windows platforms but the HBA has neither a BIOS nor x86-real-mode driver)
    • HwScsiAdapterControl (NULL if the miniport does not support Plug and Play)
  4. In a legacy miniport driver, set up any driver-determined context data that the miniport's HwScsiFindAdapter routine will use.
  5. Call ScsiPortInitialize with the pointers that were input to the DriverEntry routine, the address of the filled-in HW_INITIALIZATION_DATA, and the address of the context data, if any.


Calling ScsiPortInitialize

If a miniport driver's HBA can be connected on more than one type of I/O bus, the miniport must call ScsiPortInitialize for each bus type and can have a different HwScsiFindAdapter routine for each bus type. After each call to ScsiPortInitialize, such a miniport driver must modify the AdapterInterfaceType member, modify the HwScsiFindAdapter member in the HW_INITIALIZATION_DATA if the miniport has a different HwScsiFindAdapter routine for that bus type, possibly modify the miniport-supplied context data for the new bus type, and call ScsiPortInitialize for each type of bus on which a supported HBA might be connected.

If the miniport is a legacy driver that does not support Plug and Play, ScsiPortInitialize calls the miniport's HwScsiFindAdapter routine one or more times before it returns control to the miniport's DriverEntry routine. All of the HwScsiFindAdapter calls are made in the context of the miniport's DriverEntry routine, in the order DriverEntry called ScsiPortInitialize.

If the miniport supports Plug and Play, ScsiPortInitialize stores the initialization data for future use and returns STATUS_SUCCESS to the miniport's DriverEntry routine. The port driver does not call the miniport's HwScsiFindAdapter routine until the Plug and Play Manager detects an HBA for which the miniport is registered as a service.

For both Plug and Play and legacy miniport drivers, the port driver does all of the following before it calls the miniport's HwScsiFindAdapter routine:

  • Checks the validity of the HW_INITIALIZATION_DATA.
  • Collects and stores pertinent information in the device extension of a device object that it creates to represent the HBA.
  • Allocates memory for and initializes with zeros a device extension of the requested size in which the miniport driver can store driver-determined information about the HBA.
  • Allocates memory for a configuration information buffer that is sizeof(PORT_CONFIGURATION_INFORMATION).
  • In the configuration information buffer, fills in a PORT_CONFIGURATION_INFORMATION structure with as much configuration information about an HBA on a particular I/O bus as possible, from the miniport-supplied HW_INITIALIZATION_DATA and from other sources, such as the registry for a legacy miniport or from the Plug and Play Manager for a Plug and Play miniport.

For more information about the miniport driver's HwScsiFindAdapter routine, see SCSI Miniport Driver's HwScsiFindAdapter Routine.

If the miniport's DriverEntry routine sets a particular AdapterInterfaceType value in the HW_INITIALIZATION_DATA but there is no bus of that type in the machine, the port driver returns an operating system-specific status value indicating that such an HBA does not exist in the current machine. It does not call the driver-supplied HwScsiFindAdapter routine for that bus type.

A miniport driver does not remain loaded if the machine has no I/O buses of the type(s) specified by the miniport's DriverEntry routine.

For a legacy miniport, note that ScsiPortInitialize also is responsible for the following before it returns control to the legacy miniport's DriverEntry routine:

  • Setting up all necessary system objects
  • Getting configuration information from and setting configuration information in the registry
  • Allocating system resources on behalf of the miniport driver, including memory in the amounts indicated by the miniport-specified DeviceExtensionSize, SpecificLuExtensionSize, and/or SrbExtensionSize in which the miniport driver can maintain HBA-specific state, per-logical-unit state, and/or per-request state, respectively

For a Plug and Play miniport, the port driver performs these operations after the miniport driver's HwScsiFindAdapter routine returns and before the port driver calls the miniport's HwScsiInitialize routine.

Each SCSI miniport driver defines the internal structure and contents of its device extension, logical unit extensions (if any), and SRB extensions (if any). A pointer to the HBA-specific device extension is an input argument to every system-defined miniport driver routine except DriverEntry. Many ScsiPort Xxx routines require this pointer as an argument.

ScsiPortInitialize can be called only from a miniport driver's DriverEntry routine. For more information, see HW_INITIALIZATION_DATA (SCSI) and ScsiPortInitialize.


Storage Driver's Return from DriverEntry

When ScsiPortInitialize returns control, the DriverEntry routine propagates the return value of ScsiPortInitialize when DriverEntry itself returns control.

If a miniport driver calls ScsiPortInitialize more than once, its DriverEntry routine must propagate the lowest value returned by ScsiPortInitialize. A miniport driver writer cannot make any assumptions about the values returned by ScsiPortInitialize.


SCSI Miniport Driver's HwScsiFindAdapter Routine

The operating system-specific port driver fills in as much of the PORT_CONFIGURATION_INFORMATION in the configuration information buffer as it can from the miniport's HW_INITIALIZATION_DATA specification and other sources in the system before calling the given HwScsiFindAdapter routine with a pointer to the configuration information buffer.

In general, an HwScsiFindAdapter routine is responsible for using the supplied configuration information and/or for calling ScsiPort Xxx to collect sufficient configuration information to determine whether it supports an HBA on the I/O bus identified by the SystemIoBusNumber in the PORT_CONFIGURATION_INFORMATION supplied by the port driver. If so, HwScsiFindAdapter is responsible for filling in any remaining configuration information for the supported HBA in the PORT_CONFIGURATION_INFORMATION, for setting up the miniport's device extension with driver-determined state about that HBA, and for setting the Again parameter to an appropriate value before it returns control.

See PORT_CONFIGURATION_INFORMATION and HwScsiFindAdapter for more information.


Calling ScsiPortXxx from HwScsiFindAdapter

Certain ScsiPort Xxx routines can be called only from the miniport driver's HwScsiFindAdapter routine(s), in particular, the following:

  • ScsiPortValidateRange to verify that a miniport-supplied bus-relative access range has not already been claimed in the registry by another driver for its device
  • ScsiPortGetDeviceBase to map the (bus-relative) "physical" address range for an HBA to a system-assigned logical address range that the driver can use to communicate with the HBA by calling the ScsiPortRead Xxx and ScsiPortWrite Xxx routines with the mapped logical range addresses
  • ScsiPortFreeDeviceBase to release such a mapped range if HwScsiFindAdapter does not find an HBA it can support on a given I/O bus, as indicated by the PORT_CONFIGURATION_INFORMATION SystemIoBusNumber value
  • ScsiPortGetUncachedExtension to allocate a DMA buffer shared between the system and a busmaster HBA

In addition to these four routines, there is one routine that can only be called from the miniport driver's HwScsiFindAdapter routine or from HwScsiAdapterControl when the control type is ScsiSetRunningConfig:

  • ScsiPortGetBusData to get BUS_DATA_TYPE-specific configuration information, such as bus-relative device memory (access) ranges, interrupt vector or IRQL, DMA channel or port, etc.

For more information about these ScsiPort Xxx routines, see ScsiPort Routines.


Port-Driver-Supplied ConfigInfo for HwScsiFindAdapter

The system port driver always sets up the following PORT_CONFIGURATION_INFORMATION before it calls a miniport's HwScsiFindAdapter routine with a pointer to the PORT_CONFIGURATION_INFORMATION (the ConfigInfo buffer):

  • Length to sizeof(PORT_CONFIGURATION_INFORMATION)
  • AdapterInterfaceType to the miniport's HW_INITIALIZATION_DATA specification
  • InterruptMode to LevelSensitive for a PCI bus or Latched for all other bus types

    If the miniport has no HwScsiInterrupt routine and, therefore, set the HwInterrupt entry point to NULL in the HW_INITIALIZATION_DATA, this member is irrelevant.

  • AtdiskPrimaryClaimed to TRUE if a previously loaded driver is using the I/O port range 0x1F0 to 0x1FF
  • AtdiskSecondaryClaimed to TRUE if a previously loaded driver is using the I/O port range 0x170 to 0x17F
  • NumberOfAccessRanges to the miniport's HW_INITIALIZATION_DATA specification
  • Dma64BitAddresses to the miniport's HW_INITIALIZATION_DATA specification if the system has memory with physical addresses above 4GB

The port driver also attempts to fill in the following members with values from other sources in the system, such as the registry for a legacy miniport or from the Plug and Play Manager for a Plug and Play miniport:

  • SystemIoBusNumber set to the system-assigned value for the I/O bus

    The miniport's HwScsiFindAdapter routine can be called for each bus of the given AdapterInterfaceType with an updated value for SystemIoBusNumber, or this can be set to a system-determined value if the system detects an HBA on a particular bus of the given AdapterInterfaceType.

  • AccessRanges elements of type ACCESS_RANGE, set with the bus-relative RangeStart address and RangeLength, as well as whether each range is a RangeInMemory

    RangeInMemory set to FALSE indicates a range of ports in I/O space, rather than a memory-space range.

    The port driver either supplies all the information in an ACCESS_RANGE element or it sets all members of the element to (default) zero. Usually, the port driver supplies additional configuration information if it provides nonzero values for an access range.

    A miniport driver must map any bus-relative access range values supplied by the port driver with ScsiPortGetDeviceBase and use the mapped logical address values to determine whether the corresponding HBA is one that the driver supports. Never map and use a miniport-supplied range to access an HBA on the bus if the port driver supplies filled-in access range elements in the PORT_CONFIGURATION_INFORMATION it passes to the HwScsiFindAdapter routine. Using miniport-supplied addresses when the port driver has supplied range configuration information can reset an already configured HBA, making it dysfunctional, or even cause the system to fail the boot process.

    For more information about using mapped logical access ranges, see also Setting up ConfigInfo in HwScsiFindAdapter.

  • BusInterruptLevel or BusInterruptVector

    This member is irrelevant if the miniport has no HwScsiInterrupt routine.

  • DmaChannel or DmaPort if the HBA uses a system DMA controller

    If the HBA is a busmaster or uses PIO, these members are irrelevant.

  • InitiatorBusId

    If the input InitiatorBusId[0] has the value zero, the miniport can assign a default value if its HBA does not require the use of particular value(s) determined by querying the HBA. Otherwise, the miniport should use any nonzero value assigned by the port driver if possible. Every miniport must update InitiatorBusId specifications to match what its HBA uses, if necessary querying the HBA to determine the appropriate values(s).

    A miniport driver must set an entry for each SCSI bus supported by the HBA, as indicated by the value of NumberOfBuses.


Setting up ConfigInfo in HwScsiFindAdapter

An HwScsiFindAdapter routine can call ScsiPortGetBusData and examine the returned bus-type-specific configuration information, such as POS data or EISA configuration data, for a supported HBA.

If the AccessRanges elements in the input PORT_CONFIGURATION_INFORMATION (the ConfigInfo buffer) have been filled in by the port driver, the HwScsiFindAdapter routine should map the bus-relative access ranges with ScsiPortGetDeviceBase and use the returned logical access range addresses to communicate with the HBA. If access range addresses are supplied by the port driver, HwScsiFindAdapter must not scan for HBAs at other locations on that I/O bus.

In addition, if the port driver supplies access range values, HwScsiFindAdapter must not use the HwContext parameter. Such access range values are usually accompanied by additional configuration information, which indicates a Plug and Play environment. In such an environment, HwScsiFindAdapter is being called after the miniport's DriverEntry routine has returned and thus the HwContext pointer is no longer valid. Only drivers that receive zero access range values from the port driver and that do their own scanning for supported HBAs can safely use the HwContext pointer.

If the input PORT_CONFIGURATION_INFORMATION contains no configuration information other than that previously supplied by the miniport in the HW_INITIALIZATION_DATA, HwScsiFindAdapter can use values returned by ScsiPortGetBusData or, if necessary, set miniport-driver-defined default values for AccessRanges elements, BusInterruptLevel or BusInterruptVector, DmaChannel or DmaPort if the HBA uses system DMA, and InitiatorBusId.

HwScsiFindAdapter must call ScsiPortValidateRange to check whether such miniport-driver-supplied access ranges can be used safely before it accesses an HBA on the bus. If ScsiPortValidateRange returns TRUE, the miniport can call ScsiPortGetDeviceBase to map the range and use the returned logical addresses in calls to ScsiPortRead Xxx and/or ScsiPortWrite Xxx to determine whether it supports an HBA on the I/O bus. If ScsiPortValidateRange returns FALSE, the miniport driver must not attempt to map and use those bus-relative access range values.

Similarly, if the port driver calls a Plug and Play miniport to detect devices on a nonenumerable bus, the miniport driver must validate access ranges before calling ScsiPortGetDeviceBase.

If the port driver provides interrupt configuration information, the miniport must accept it and, if its HBA supports programmable interrupt configuration, should program its HBA to use the supplied interrupt value. If no interrupt configuration is supplied, as indicated either by the value zero or the value SP_UNINITIALIZED_VALUE, the miniport should either query its HBA if the HBA supports interrupt selection using jumpers or it should supply a nonzero default interrupt configuration, unless the HBA does not use interrupts. The interrupt configuration value zero indicates that the miniport controls its HBA in a polled mode.

When HwScsiFindAdapter finds an HBA it can support, this routine must fill in pertinent members, as appropriate for its HBA and the given AdapterInterfaceType, in the PORT_CONFIGURATION_INFORMATION. A miniport driver that supplies access ranges must fill in the AccessRanges information, converting each AccessRanges element's bus-relative RangeStart value with ScsiPortConvertUlongToPhysicalAddress before setting the bus-relative base address for a range in the PORT_CONFIGURATION_INFORMATION.

For a supported HBA, HwScsiFindAdapter also should save the mapped logical range addresses returned by ScsiPortGetDeviceBase in the miniport's device extension. Every miniport driver must call the ScsiPortRead Xxx and ScsiPortWrite Xxx with these mapped system addresses to communicate with its HBA(s).

For each successfully validated and mapped range in I/O space, the miniport driver calls the ScsiPortRead/WritePort Xxx routines to communicate with its HBA. For each such range in memory space, the miniport driver calls the ScsiPortRead/WriteRegister Xxx.

For an "AT-compatible" HBA, HwScsiFindAdapter should check the input Atdisk..Claimed members and attempt to claim an "AT" range by resetting the value to TRUE.


Setting Again and Returning from HwScsiFindAdapter

For a supported and successfully configured HBA, HwScsiFindAdapter returns SP_RETURN_FOUND.

Before it returns, the HwScsiFindAdapter of both legacy and Plug and Play miniports should set Again as described in this section. Although Again is irrelevant when a miniport is loaded as a Plug and Play driver, Again must be set appropriately so the system can run a Plug and Play miniport as a legacy driver if necessary.

HwScsiFindAdapter should set Again to TRUE to indicate it should be called again with exactly the same PORT_CONFIGURATION_INFORMATION but a new device extension if another of its HBAs might be connected on the same I/O bus.

If HwScsiFindAdapter cannot find an HBA it supports, it should set Again to FALSE and return SP_RETURN_NOT_FOUND. If HwScsiFindAdapter finds a supported HBA but the input PORT_CONFIGURATION_INFORMATION has inconsistent configuration data (such as an invalid DmaChannel or BusInterruptLevel on an EISA bus), it should set Again to FALSE and return SP_RETURN_BAD_CONFIG. For an HBA on a PCI bus, HwScsiFindAdapter must accept the interrupt configuration information supplied by the system.

Note that setting Again to FALSE and returning control with SP_RETURN_NOT_FOUND or SP_RETURN_BAD_CONFIG indicates that a given I/O bus, identified by the SystemIoBusNumber in the input PORT_CONFIGURATION_INFORMATION, has no HBA that the miniport driver can support. It does not prevent the system port driver from calling HwScsiFindAdapter again with updated PORT_CONFIGURATION_INFORMATION to scan another I/O bus for HBA(s) if the machine has additional I/O buses of the same AdapterInterfaceType.


Returning Control from HwScsiFindAdapter

When a legacy miniport driver's HwScsiFindAdapter routine returns control, ScsiPortInitialize returns to the DriverEntry routine if the call(s) to HwScsiFindAdapter indicated that the miniport driver could not support an HBA. Otherwise, ScsiPortInitialize claims resources in the registry and sets up necessary system resources, such as interrupt and adapter objects, on behalf of the miniport driver. Then, it calls the miniport's HwScsiInitialize routine, described in SCSI Miniport Driver's HwScsiInitialize Routine.

When a Plug and Play miniport driver's HwScsiFindAdapter routine returns control, the Plug and Play Manager is allowed to unload the miniport if the call(s) to HwScsiFindAdapter indicated that the miniport driver could not support an HBA. Otherwise, the port driver connects interrupts (other resources having been claimed and set up before the HwScsiFindAdapter call) and calls the miniport driver's HwScsiInitialize routine, which initializes the HBA.

Currently, in addition to the values it sets in the PORT_CONFIGURATION_INFORMATION, the port driver also checks the registry for user-set values that disable any or all of the following:

  • Synchronous transfers on the HBA

    The port driver ORs the default SrbFlags that it maintains for the HBA with SRB_FLAGS_DISABLE_SYNCH_TRANSFER.

  • Bus-disconnect operations on the HBA

    The port driver ORs the default SrbFlags with SRB_FLAGS_DISABLE_DISCONNECT.

  • Tagged queuing

    The port driver sets the TaggedQueuing Boolean that it maintains for the HBA to FALSE.

  • Internal queuing of requests on the HBA

    The port driver sets the MultipleRequestPerLu Boolean that it maintains about the HBA to FALSE.

Any of the immediately preceding "disable" values in the registry overrides whatever the HwScsiFindAdapter routine sets in the PORT_CONFIGURATION_INFORMATION buffer. Note that temporarily disabling synchronous transfers, bus-disconnect operations, tagged queuing, and HBA internal request queuing can simplify using a debugger to trace request handling in a miniport driver that is under development.

Note also that the NT-based operating system port driver uses values from the PORT_CONFIGURATION_INFORMATION provided by a miniport's HwScsiFindAdapter routine or from other sources (such as the registry for a legacy miniport) to fill in the IO_SCSI_CAPABILITIES data for use by storage class drivers, as described in Storage Class Drivers.


SCSI Miniport Driver's HwScsiInitialize Routine

For each supported HBA found by the miniport driver, its HwScsiInitialize routine is called to set up the HBA's registers and initial state, if any.

If the HwScsiInitialize routine enables interrupts on the HBA, the miniport's HwScsiInterrupt routine will be called to handle any interrupts the device generates during the initialization.

If initializing the HBA causes a bus reset, the HwScsiInitialize routine must call ScsiPortNotification with the NotificationType value ResetDetected.


SCSI Miniport Driver's HwScsiStartIo Routine

As its name suggests, a HwScsiStartIo routine is the entry point for incoming requests to peripheral devices on the HBA-driven bus(es). HwScsiStartIo is called with pointers to a SCSI request block (SRB) and to the miniport's device extension for per-HBA state.

If the miniport's DriverEntry routine also requested that memory be allocated for logical unit extensions (see Calling ScsiPortInitialize), the HwScsiStartIo routine calls ScsiPortGetLogicalUnit with the input device extension pointer and the PathId, TargetId, and Lun values from the input SRB.

If the DriverEntry routine requested that memory be allocated for SRB extensions, the SrbExtension member in each SRB contains a pointer to the miniport's per-request storage area. Note that a miniport driver must request that memory be allocated for SrbExtensions if it maintains per-request state information. It cannot use an SRB for this purpose.


Modifying SRBs

As mentioned in the preceding section, a SCSI miniport's DriverEntry routine must request that the port driver allocate memory for SRB extensions if the miniport maintains per-request state information.

Otherwise, a SCSI miniport driver can write values into SRBs only for the following purposes and only in the following members:

  • To return required status about each operation in the SrbStatus and ScsiStatus members
  • If an underrun occurs, to update the DataTransferLength member
  • If it supports auto request sense and transfers request-sense information, to update the SenseInfoBufferLength
  • If SRB_FLAGS_UNSPECIFIED_DIRECTION is set in the SrbFlags member and the HBA is a slave DMA device, to reset the SRB_FLAGS_DATA_IN or SRB_FLAGS_DATA_OUT, as appropriate to the current transfer request
  • If the miniport supports more than eight logical units, to set the Lun member to the logical unit number

If the HBA can handle more than eight logical units, as indicated when HwScsiFindAdapter sets up the PORT_CONFIGURATION_INFORMATION, the port driver does not interpret LUN information. The miniport is responsible for mapping the 8-bit LUN from an SRB to a SCSI-3 address if necessary.

The mapping from the 8-bit LUN to SCSI-3 address is miniport-specific. The following tables show the recommended mapping, where P is the physical addressing mode, B is the bus, and T is the target.

8-bit LUN

Bit/Byte | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
0 | P | P | B | B | T | T | T | T

SCSI-3 Address

Bit/Byte | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
0 | P | P | 0 | 0 | 0 | 0 | B | B
1 | 0 | 0 | 0 | 0 | T | T | T | T

The SCSI port driver reserves LUN 0xFF to indicate all logical units.


Handling SRB_FUNCTION_EXECUTE_SCSI

After the higher-level storage class drivers have loaded, most of the SRBs sent to the HwScsiStartIo routine have the Function member set to SRB_FUNCTION_EXECUTE_SCSI.

On receipt of an SRB_FUNCTION_EXECUTE_SCSI request, a miniport's HwScsiStartIo routine does the following:

  • Gets and/or sets up whatever context the miniport driver maintains in its device, logical unit, and/or SRB extensions

    For example, a miniport driver might set up a logical unit extension with pointers to the SRB itself and the SRB DataBuffer pointer, the SRB DataTransferLength value, and a driver-defined value (or CDB SCSIOP_XXX value) indicating the operation to be carried out on the HBA.

  • Calls an internal routine to program the HBA, as partially directed by the SrbFlags, for the requested operation

    For a device I/O operation, such an internal routine generally selects the target device and sends the CDB over the bus to the target logical unit.

If the miniport driver uses system DMA, it must call ScsiPortIoMapTransfer before programming the HBA to transfer data. ScsiPortIoMapTransfer sets up the system DMA controller and calls the miniport's HwScsiDmaStarted routine, described later in SCSI Miniport Driver's HwScsiDmaStarted Routine.

All system-defined, required device I/O control requests sent to NT-based operating system storage class drivers are mapped to SRBs with the Function member set to SRB_FUNCTION_EXECUTE_SCSI.


Handling SRB_FUNCTION_ABORT_COMMAND

An HwScsiStartIo routine is also responsible for handling incoming SRBs with the Function member set to SRB_FUNCTION_ABORT_COMMAND.

For an abort request, the miniport's HwScsiStartIo routine should verify that the given SRB has not been aborted already by calling ScsiPortGetSrb for the target logical unit and comparing the returned pointer to the current SRB's NextSrb value. If they are unequal, the current SRB has already been aborted, and the miniport's HwScsiStartIo routine should do the following:

  1. Set the input SRB's SrbStatus to SRB_STATUS_ABORT_FAILED.
  2. Call ScsiPortNotification with the NotificationType RequestComplete and with the input SRB.
  3. Call ScsiPortNotification again with the NotificationType NextRequest, or with NextLuRequest if the HBA supports tagged queuing or multiple requests per logical unit.

Otherwise, the HwScsiStartIo routine does the following:

  1. Sets up context for the request in its device, logical unit, and/or SRB extensions.
  2. Programs the HBA to abort the given NextSrb request.


Handling SRB_FUNCTION_RESET_BUS

The system port driver always sends its own reset-bus requests directly to the miniport's HwScsiResetBus routine, described in SCSI Miniport Driver's HwScsiResetBus Routine.

However, it is possible for the HwScsiStartIo routine to be called with an SRB in which the Function member is set to SRB_FUNCTION_RESET_BUS if a NT-based operating system storage class driver requests this operation. The HwScsiStartIo routine can simply call the HwScsiResetBus routine to satisfy an incoming bus-reset request.


Handling SRB_FUNCTION_RESET_DEVICE

If the HBA has the ability to reset a target device, as indicated when HwScsiFindAdapter sets up the PORT_CONFIGURATION_INFORMATION, the port driver requests a device reset when an uncompleted request times out.

The system port driver calls the miniport's HwScsiStartIo routine with an SRB in which the Function member is set to SRB_FUNCTION_RESET_DEVICE. The miniport is responsible for completing any requests that are uncompleted on the device when it receives a reset-device request.

If the device reset fails or times out, or if the timeout occurs while the port driver is waiting for a NextRequest notification, the port driver calls HwScsiResetBus.


Handling SRB_FUNCTION_FLUSH and SRB_FUNCTION_SHUTDOWN

If the HBA caches data internally, as indicated when HwScsiFindAdapter sets up the PORT_CONFIGURATION_INFORMATION, the HwScsiStartIo routine must support the SRB_FUNCTION_FLUSH and SRB_FUNCTION_SHUTDOWN requests as follows:

  • An SRB with its Function member set to SRB_FUNCTION_FLUSH tells the miniport driver to transfer data cached in the HBA, usually to a disk. The miniport must hold on to the flush request until all cached data has been transferred and, then, complete the flush request.

    Such a flush request might originate when an application closes a file or the application itself is terminated.

  • An SRB with its Function member set to SRB_FUNCTION_SHUTDOWN tells the miniport driver to complete transferring data, including flushing all cached data, out to the target device. The miniport driver must hold on to the shutdown request until no data remains in the HBA's internal cache for the target logical unit and, then, complete the shutdown request.

    Note that a miniport can be called with more than one shutdown request, possibly for the same logical unit or with several shutdown requests for different logical units, before the system itself is actually shut down.


Handling SRB_FUNCTION_IO_CONTROL

Whether a miniport driver handles SRB_FUNCTION_IO_CONTROL requests depends on whether the HBA is to provide dedicated support for a user-mode application. Supporting this request allows a set of driver-defined (a.k.a. "private") I/O control requests to be sent directly to the miniport driver. For SRBs with the Function member set to SRB_FUNCTION_IO_CONTROL, the DataBuffer member contains a pointer to a system-defined SRB_IO_CONTROL structure containing the driver-defined and application-specified ControlCode.

All system-defined, required device I/O control requests sent to NT-based operating system storage class drivers are mapped to SRBs with the Function member set to SRB_FUNCTION_EXECUTE_SCSI, not to SRB_FUNCTION_IO_CONTROL.


Handling SRB_FUNCTION_WMI

If the HBA supports Windows Management Instrumentation (WMI), the port driver will send WMI requests to the miniport driver. The HBA indicates that it supports WMI by setting the WmiDataProvider field of the PORT_CONFIGURATION_INFORMATION structure to TRUE in its DriverEntry routine.

The writer of a miniport prepares the miniport to handle WMI requests as follows:

  • If the miniport exposes custom data blocks or event blocks, it should define such blocks in a MOF file and compile it as a binary resource in the miniport's binary image. For more information, see Windows Management Instrumentation.
  • Implement required and optional HwScsiWmiXxx callback routines, as described in SCSI Miniport Driver Routines.
  • Handle SRB_FUNCTION_WMI.

If a miniport might pend WMI requests, its DriverEntry routine should request that memory be allocated for SRB extensions so the miniport can maintain request context throughout the processing of an SRB.

Before the miniport handles its first WMI request, it must allocate a SCSI_WMILIB_CONTEXT structure in its device extension and initialize the structure with the following:

  • The number of data and event blocks supported by the miniport, including standard blocks defined by the system in wmicore.mof as well as the miniport's custom blocks, if any.
  • A pointer to an array of SCSIWMIGUIDREGINFO structures, one for each block supported.
  • Entry points to the miniport's HwScsiWmiXxx callback routines. At a minimum, a miniport must provide entry points to an HwScsiWmiQueryReginfo routine and an HwScsiWmiQueryDataBlock routine.

A miniport is not required to take any action to register its data and event blocks other than setting the WmiDataProvider field of the PORT_CONFIGURATION_INFO structure to TRUE and implement the required HwScsiWmiQueryReginfo routine. The port driver is responsible for registering the miniport's blocks with the WMI kernel component.

On receipt of an SRB in which the Function member is set to SRB_FUNCTION_WMI, a miniport's HwScsiStartIo routine does the following:

  • Allocates a SCSIWMI_REQUEST_CONTEXT structure from the SRB extension if the request might pend, or from the stack if the request could never pend.
  • Checks Srb–>WMIFlags to determine whether the request is for the adapter or a logical unit.
  • Calls ScsiPortWmiDispatchFunction with pointers to the miniport's SCSI_WMILIB_CONTEXT, its device extension, and the request context, and the following parameters from the SRB:

    Srb–>WMISubFunction
    Srb–>DataPath
    Srb–>DataTransferLength
    Srb–>DataBuffer

  • Calls ScsiPortWmiPostProcess when the driver has finished processing the request. If the driver does not pend the request, then ScsiPortWmiPostProcess would most likely be called in the callback. If the driver pends the request then ScsiPortWmiPostProcess should be called when the request is completed.
  • Sets Srb–>DataTransferLength and Srb–>SrbStatus to the values returned by ScsiPortWmiGetReturnSize and ScsiPortWmiGetReturnStatus, respectively,
  • Calls ScsiPortNotification with RequestComplete and again with NextRequest or (NextLuRequest).

For more information about WMI, see Windows Management Instrumentation.


Handling Unsupported SRB_FUNCTION_XXX

Every HwScsiStartIo routine must handle the receipt of an unsupported SRB_FUNCTION_XXX as follows:

  1. Set the input SRB's SrbStatus to SRB_STATUS_INVALID_REQUEST.
  2. Call ScsiPortNotification with the NotificationType RequestComplete and with the input SRB.
  3. Call ScsiPortNotification again with the NotificationType NextRequest, or with NextLuRequest if the HBA supports tagged queuing or multiple requests per logical unit.
  4. Return control.


Return from HwScsiStartIo

Every HwScsiStartIo routine must return TRUE, indicating that the input request was processed.

If the HwScsiStartIo routine cannot carry out a requested operation when it is called, HwScsiStartIo should do the following:

  1. Set the input SRB's SrbStatus to SRB_STATUS_BUSY.
  2. Call ScsiPortNotification with the NotificationType RequestComplete and with the input SRB.
  3. Call ScsiPortNotification with the NotificationType NextRequest if the driver can accept a request to a different target logical unit than the one in the just completed SRB.
  4. Return TRUE.

The port driver resubmits any request returned with the SrbStatus value SRB_STATUS_BUSY to the miniport's HwScsiStartIo routine later.

Eventually, every miniport driver must call ScsiPortNotification twice for each SRB input to its HwScsiStartIo routine: first, to complete the request (NotificationType RequestComplete) and, second, to tell the port driver to call the HwScsiStartIo routine again with the next SRB (NotificationType NextRequest or NextLuRequest).

The HwScsiStartIo routine of a miniport driver that manages its HBA exclusively by polling calls ScsiPortNotification with the NotificationType RequestTimerCall and a pointer to its HwScsiTimer routine. For more information about the HwScsiTimer routine, see SCSI Miniport Driver's HwScsiTimer Routine.


Other SRB_FUNCTION_XXX Requests

The following SRB Function values are defined for use in future versions of the operating system:

  • SRB_FUNCTION_RECEIVE_EVENT
  • SRB_FUNCTION_RELEASE_RECOVERY
  • SRB_FUNCTION_RESET_DEVICE
  • SRB_FUNCTION_TERMINATE_IO

The NT-based operating system SCSI port driver processes requests with the following SRB Function values without calling any SCSI miniport driver:

  • SRB_FUNCTION_CLAIM_DEVICE
  • SRB_FUNCTION_RELEASE_QUEUE
  • SRB_FUNCTION_FLUSH_QUEUE
  • SRB_FUNCTION_RELEASE_DEVICE
  • SRB_FUNCTION_LOCK_QUEUE
  • SRB_FUNCTION_UNLOCK_QUEUE

For details about these functions, see Storage Class Drivers.

Miniport driver designers can assume that their miniports will never be sent an SRB with any of the immediately preceding Function values. The NT-based operating system port driver handles these requests from storage class and filter drivers to protect higher-level drivers from having to access any HBA-specific (or miniport-specific) state information in order to find their devices or to cancel queued requests. This ensures that NT-based operating system storage class and filter drivers have no dependencies on any particular model of HBA.

See SCSI_REQUEST_BLOCK structure for more information.


SCSI Miniport Driver's HwScsiDmaStarted Routine

A miniport driver of an HBA that uses the system DMA controller must have an HwScsiDmaStarted routine.

For a data transfer operation, such a miniport driver must call ScsiPortIoMapTransfer, passing in the pointers to its device extension for per-HBA data and to the SRB requesting the transfer, along with a range of logical addresses for the buffer from which or into which the data will be transferred.

Note that the logical address range passed to ScsiPortIoMapTransfer either must be the mapped values for the input SRB's DataBuffer and DataTransferLength or a proper subset of this range. For most transfer requests, a miniport driver writer can assume that all data specified in the input SRB can be transferred in a single DMA operation.

In particular, a miniport driver might have to carry out more than one slave DMA transfer operation to satisfy a given SRB only if the HBA provides application-dedicated support and the application sends large transfer requests directly to the miniport driver. Otherwise, it is the responsibility of the storage class drivers to split up large transfer requests into a set of partial transfer requests, each sized to suit the capabilities of the HBA (see Storage Class Drivers).

ScsiPortIoMapTransfer calls the miniport's HwScsiDmaStarted routine when the system DMA controller is ready to transfer data between system memory and the HBA. HwScsiDmaStarted must set up the HBA for the transfer operation.

When a transfer operation is complete, the miniport driver must call ScsiPortFlushDma before it calls ScsiPortNotification with the SRB and/or calls ScsiPortIoMapTransfer to set up the DMA controller again for a subrange in an application-supplied buffer if the HBA is dedicated to the support of a user-mode application.

ScsiPortFlushDma flushes any remaining data cached in the DMA controller. Note that ScsiPortFlushDma also can be called to cancel a system DMA transfer, even if the miniport's HwScsiDmaStarted routine has not yet been called.

See ScsiPortIoMapTransfer and ScsiPortFlushDma for more information.


SCSI Miniport Driver's HwScsiResetBus Routine

Every miniport driver must have an HwScsiResetBus routine, which is called with a pointer to the miniport's device extension for HBA state and the PathId of the bus to be reset. If an attempted bus-reset operation fails or times out, the miniport driver should call ScsiPortLogError and, then, program the HBA for a hard reset.

A bus-reset operation might require the miniport driver to clean up state it maintains in the device extension and/or logical unit extensions for devices on the bus. HwScsiResetBus must complete any outstanding requests by calling ScsiPortCompleteRequest with the SrbStatus value SRB_STATUS_BUS_RESET or, for individual SRBs, ScsiPortNotification with this status value.

After completing the bus-reset request and any outstanding requests, the miniport must call ScsiPortNotification (if it has not already done so) with the NotificationType NextRequest, or NextLuRequest if the HBA supports tagged queuing or multiple requests per logical unit.

Note that the operating system-specific port driver manages SCSI bus-reset delays on behalf of miniport drivers.


SCSI Miniport Driver's HwScsiInterrupt Routine

On entry, an HwScsiInterrupt routine should determine if its HBA actually generated an interrupt. HwScsiInterrupt must return FALSE as soon as possible if it detects a spurious interrupt so the ISR for the device that actually generated the interrupt can be called quickly.

Otherwise, a miniport's HwScsiInterrupt routine is generally responsible for completing the I/O operation that caused the interrupt. Depending on the HBA and the design of the miniport, an HwScsiInterrupt routine does some or all of the following:

  • Dismisses the interrupt on the HBA (required)
  • Notifies (by calling ScsiPortNotification or ScsiPortCompleteRequest) the port driver if the HBA indicates that certain SCSI error conditions occurred during the operation and possibly logging the error.

    For more information about logging errors, see Error Handling in SCSI Miniport Drivers.

  • Completes the requested operation that caused the interrupt, such as calling ScsiPortIoMapTransfer (see SCSI Miniport Driver's HwScsiDmaStarted Routine) if the interrupt came in from a previously selected target TID and LU indicating a readiness to transfer data

When the HwScsiInterrupt routine (or an internal miniport routine) completes an SRB, it calls ScsiPortNotification twice:

  1. First, with the NotificationType RequestComplete and the just satisfied SRB
  2. Next, with the NotificationType NextRequest, or with NextLuRequest if the HBA supports tagged queuing or multiple requests per logical unit

For better overall system performance, a miniport's HwScsiInterrupt routine should do only the minimum necessary to process I/O requests. That is, the miniport should be designed to return control from the HwScsiInterrupt routine as quickly as possible. An HwScsiInterrupt routine must not call ScsiPortStallExecution with large intervals, thereby tying up a processor and preventing other drivers from servicing their device interrupts.


Deferring Interrupt-Driven I/O from HwScsiInterrupt

If interrupt-driven I/O operations take a long time to complete, a miniport driver should have a pair of HwScsiEnableInterruptsCallback and HwScsiDisableInterruptsCallback routines.

For example, if a miniport must stall for longer than 50 microseconds doing PIO, its HwScsiInterrupt routine should not retain control of the CPU for the full polling interval in order to complete a requested operation. Instead, its HwScsiInterrupt routine should do the following:

  1. Disable interrupts from the HBA.
  2. Set up the device extension with any context necessary to complete the operation.
  3. Call ScsiPortNotification with a pointer to the device extension, the NotificationType CallEnableInterrupts, and the miniport's HwScsiEnableInterruptsCallback routine, described in SCSI Miniport Driver's HwScsiEnableInterruptsCallback Routine.
  4. Return control.

The ScsiPortNotification routine calls the HwScsiEnableInterruptsCallback routine as a DPC routine. For more information about DPCs, see DPC Objects and DPCs.

If a miniport's HwScsiInterrupt routine cannot disable interrupts on the HBA but its interrupt-driven transfers can take more than 50 microseconds in the HwScsiInterrupt routine, the driver writer should tune the miniport by limiting the size of the transfers that it accepts. Otherwise, the mouse pointer will appear "jumpy" and/or serial and parallel throughput will degrade noticeably every time the miniport is transferring data concurrently.

Such a miniport's HwScsiFindAdapter routine should reset the MaximumTransferLength value in the PORT_CONFIGURATION_INFORMATION to a value that allows the miniport to carry out interrupt-driven transfers without noticeably affecting the performance of other system drivers.

Such a miniport driver also might call ScsiPortNotification with a miniport-supplied HwScsiTimer routine. For more information about HwScsiTimer routines, which are synchronized with HwScsiInterrupt routines, see SCSI Miniport Driver's HwScsiTimer Routine.


SCSI Miniport Driver's HwScsiEnableInterruptsCallback Routine

An HwScsiEnableInterruptsCallback routine finishes processing an interrupt-driven I/O operation without inhibiting I/O operations for other devices in the machine.

When the HwScsiEnableInterruptsCallback routine gets control, all system device interrupts are enabled except from the HBA because the HwScsiInterrupt routine disabled interrupts on the HBA before it called ScsiPortNotification. Thus, the miniport's HwScsiInterrupt routine cannot be called and cannot disturb the context data it set up about the current operation while the HwScsiEnableInterruptsCallback routine is running.

A HwScsiEnableInterruptsCallback routine should do the following:

  1. Use the context that was set up for the operation in the input device extension to complete processing of the request that caused the interrupt.
  2. Call ScsiPortNotification with the NotificationType RequestComplete and the just satisfied SRB.
  3. Call ScsiPortNotification with the NotificationType NextRequest, or with NextLuRequest if the HBA supports tagged queuing or multiple requests per logical unit.
  4. Call ScsiPortNotification with a pointer to the device extension, the NotificationType CallDisableInterrupts, and the miniport's HwScsiDisableInterruptsCallback routine, described in SCSI Miniport Driver's HwScsiDisableInterruptsCallback Routine.
  5. Return control.

The NT-based operating system ScsiPortNotification routine calls the HwScsiDisableInterruptsCallback routine with a subset of the system device interrupts disabled. No device interrupt with a system-assigned hardware priority (IRQL) less than or equal to the HBA's can occur.

See IRQL for more information.


SCSI Miniport Driver's HwScsiDisableInterruptsCallback Routine

An HwScsiDisableInterruptsCallback routine should do the following:

  • Reenable interrupts from the HBA.
  • Return control.

Note that this routine must execute as quickly as possible to avoid tying up I/O operations for other devices in the machine. Consequently, an HwScsiDisableInterruptsCallback must do no more than reenable interrupts on the HBA before it returns control.


SCSI Miniport Driver's HwScsiTimer Routine

A miniport driver that does not have an HwScsiInterrupt routine because it manages all HBA I/O operations by polling should have an HwScsiTimer routine. However, miniport drivers with HwScsiInterrupt routines frequently have HwScsiTimer routines as well.

While a miniport driver can call ScsiPortStallExecution to wait for a state change on the HBA, miniport drivers should never call this routine to wait for longer than one millisecond except, possibly, for an operation performed only when a miniport is initializing. ScsiPortStallExecution ties up the processor for the given interval, preventing other code in the system from doing useful work.

Instead of calling ScsiPortStallExecution with large input intervals and wasting many CPU cycles, a miniport driver should have an HwScsiTimer routine. One or more HwScsiTimer routines are particularly useful if the HBA does not generate a completion interrupt for every operation or if any commonly requested operation, such as a bus reset, takes longer than a millisecond.

After the HBA has been programmed for such an operation, the miniport driver calls ScsiPortNotification with the NotificationType RequestTimerCall, a pointer to its HBA-specific device extension containing context about the operation, its HwScsiTimer entry point, and a driver-determined interval.

ScsiPortNotification synchronizes calls to the HwScsiTimer routine with those to the HwScsiInterrupt routine so that it cannot execute concurrently while the HwScsiTimer routine is running.

HwScsiTimer is called once for each such call to ScsiPortNotification, which can be called from the HwScsiTimer routine itself. However, any call to ScsiPortNotification with the NotificationType RequestTimerCall overrides a preceding call for which the specified interval has not expired. That is, there is only one outstanding request to call a miniport's HwScsiTimer routine at any given moment.

The interval passed in to ScsiPortNotification is in microseconds, and the minimum overhead for each call to an HwScsiTimer routine is approximately ten microseconds. An input interval of zero cancels the preceding request to call the HwScsiTimer routine, provided it has not been called or dispatched for execution on another processor in a NT-based SMP machine.


SCSI Miniport Driver's HwScsiAdapterState Routine

In NT-based operating systems, miniport drivers should set this entry point to NULL in the HW_INITIALIZATION_DATA (see Required and Optional SCSI Miniport Routines) only if either of the following conditions hold:

  • The miniport drives an HBA to be connected on an I/O bus commonly found only in high-end, RISC-based platforms. That is, an x86-based platform running an x86-only Microsoft Windows system would not have an I/O bus of a type to support the HBA.
  • The miniport drives an HBA that could be found in an x86-based platform running an x86-only Windows system, but the HBA has neither a BIOS nor an x86-only real-mode driver.

Otherwise, a miniport driver must have a HwScsiAdapterState routine in order to be portable across NT-based operating systems and x86-only Microsoft Windows systems.

A HwScsiAdapterState routine is responsible for saving and restoring the state of its HBA, as requested by the x86-only system during transitions between x86 real and protected processor mode.

See HwScsiAdapterState for more information.


SCSI Miniport Driver's HwScsiAdapterControl Routine

In NT-based operating systems, miniport drivers should set this entry point to NULL in the HW_INITIALIZATION_DATA (see Required and Optional SCSI Miniport Routines) if the miniport driver does not support Plug and Play. Otherwise, the miniport driver must have a HwScsiAdapterControl routine in order to support PnP and power management operations for its HBA.

A miniport's HwScsiAdapterControl routine is first called by the port driver with ScsiQuerySupportedControlTypes after the HBA has been initialized but before the first I/O, to determine the other operations supported by the miniport. The miniport sets the operations it supports in a SUPPORTED_CONTROL_TYPE_LIST allocated by the port driver. After HwScsiAdapterControl returns from this initial call, the port driver calls the routine again only for the operations indicated by the miniport.

A miniport's HwScsiAdapterControl routine can support any or all of the following operations:

  • ScsiStopAdapter to shut down the HBA when it has been powered off, removed from the system, or otherwise reconfigured or disabled.

    At the time the SCSI port driver calls HwScsiAdapterControl to stop the HBA, it ensures that there are no uncompleted requests. The miniport should disable interrupts on the HBA, halt all processing including background processing not subject to interrupts, and put the HBA into an uninitialized state. The miniport should not release its resources; if necessary, the port driver will release resources on behalf of the miniport. This call to HwScsiAdapterControl is preceded by an SRB_FUNCTION_FLUSH request, so it is not necessary to flush the cache unless its data has changed since the flush request was completed.

    The miniport driver is not called again for this HBA until either the PnP Manager requests that the HBA be restarted, or an HBA that was shut down for power management is powered up.

    Note that HwScsiAdapterControl, like any miniport routine, might be called to stop the HBA after the HBA has already been removed from the system.

  • ScsiSetBootConfig to restore any settings on an HBA that the BIOS might need to boot the system.

    A miniport should support ScsiSetBootConfig if it needs to call ScsiPortGetBusData or ScsiPortSetBusDataByOffset to restore such settings. The port driver calls a miniport's HwScsiAdapterControl with ScsiSetBootConfig after calling the routine to stop the HBA.

  • ScsiSetRunningConfig to restore any settings on an HBA that the miniport might need to control the HBA while the system is running.

    A miniport should support ScsiSetRunningConfig if it needs to call ScsiPortGetBusData or ScsiPortSetBusDataByOffset to restore such settings. The port driver calls a miniport's HwScsiAdapterControl with ScsiSetRunningConfig before calling the routine to restart the HBA.

  • ScsiRestartAdapter to restart an HBA that has been shut down for power management.

    At the time the port driver calls HwScsiAdapterControl to restart the HBA, all resources previously assigned to the miniport are still available and its device extension and any logical unit extensions are intact. When restarting its HBA, the miniport must not call routines that can only be called from HwScsiFindAdapter.

    If the miniport does not support ScsiRestartAdapter, the port driver calls the miniport's HwScsiFindAdapter and HwScsiInitialize routines to restart the HBA. However, such routines might do detection work that is unnecessary when restarting, so such a miniport will not power up its HBA as quickly as a miniport that supports ScsiRestartAdapter.

See HwScsiAdapterControl for more information.


Error Handling in SCSI Miniport Drivers

Every SCSI miniport driver is responsible for handling and for notifying the system port driver of the following kinds of SCSI errors, which should be set in the SrbStatus member before the driver completes the SRB it was processing when the error occurred:

  • SRB_STATUS_ERROR (if the HBA returns a nonspecific bus error)
  • SRB_STATUS_PARITY_ERROR
  • SRB_STATUS_UNEXPECTED_BUS_FREE
  • SRB_STATUS_SELECTION_TIMEOUT
  • SRB_STATUS_COMMAND_TIMEOUT
  • SRB_STATUS_MESSAGE_REJECTED
  • SRB_STATUS_NO_DEVICE
  • SRB_STATUS_NO_HBA
  • SRB_STATUS_DATA_OVERRUN (also returned for underruns)
  • SRB_STATUS_PHASE_SEQUENCE_FAILURE
  • SRB_STATUS_BUSY (TID busy)

For a data underrun, the miniport driver must update the SRB's DataTransferLength to indicate how much data actually was transferred.

In addition, the miniport driver should log some of the preceding errors by passing the SRB to ScsiPortLogError, according to the following guidelines:

  • Log an error at the discretion of the driver writer for SRB_STATUS_ERROR.
  • Always log an error for SRB_STATUS_PARITY_ERROR.
  • Always log an error for SRB_STATUS_UNEXPECTED_BUS_FREE.
  • Always log an error for SRB_STATUS_SELECTION_TIMEOUT.
  • Always log an error for SRB_STATUS_COMMAND_TIMEOUT.
  • Log an error for SRB_STATUS_DATA_OVERRUN whenever an overrun occurs, but not when an underrun occurs.
  • Always log an error for SRB_STATUS_PHASE_SEQUENCE_FAILURE.
  • Always log an error for SRB_STATUS_BUSY for hardware errors.

To log an error, a miniport driver calls ScsiPortLogError with one of the following system-defined error or warning codes:

  • SP_BUS_PARITY_ERROR maps to SRB_STATUS_PARITY_ERROR.
  • SP_UNEXPECTED_DISCONNECT (by the target logical unit)
  • SP_INVALID_RESELECTION maps to SRB_STATUS_PHASE_SEQUENCE_FAILURE or SRB_STATUS_ERROR.
  • SP_BUS_TIME_OUT maps to SRB_STATUS_SELECTION_TIMEOUT.
  • SP_REQUEST_TIMEOUT maps to SRB_STATUS_COMMAND_TIMEOUT.
  • SP_PROTOCOL_ERROR maps to SRB_STATUS_PHASE_SELECTION_FAILURE, SRB_STATUS_UNEXPECTED_BUS_FREE, or SRB_STATUS_DATA_OVERRUN for an overrun condition.
  • SP_INTERNAL_ADAPTER_ERROR maps to SRB_STATUS_ERROR.
  • SP_IRQ_NOT_RESPONDING (warning that the miniport has detected that the HBA is no longer generating interrupts)
  • SP_BAD_FW_ERROR ("FW" stands for "firmware")
  • SP_BAD_FW_WARNING

ScsiPortLogError allocates an error-log packet, sets it up, and logs the I/O error in the event log on behalf of the miniport driver. System administrators or users can monitor the condition of an HBA by examining the system event log and, if necessary, reconfigure, repair, or replace the HBA before it fails.


SCSI Miniport Driver Routines

All SCSI miniport drivers must have some of the routines described in this section. Whether any particular miniport driver has others depends on the nature of its HBA(s) or on that miniport's designer.

This chapter describes miniport routines in alphabetical order.

A miniport's HwScsiXxx routines can have any name chosen by the driver writer. DriverEntry is a required name.


DriverEntry of SCSI Miniport Driver

Each miniport driver must have a routine explicitly named DriverEntry in order to be loaded.

ULONG
  DriverEntry(
    IN PVOID  Argument1,
    IN PVOID  Argument2
    );

Parameters

Argument1
Is a pointer with which the miniport driver must call ScsiPortInitialize.
Argument2
Is a pointer with which the miniport driver must call ScsiPortInitialize.

Return Value

DriverEntry returns the value returned by ScsiPortInitialize. If it calls ScsiPortInitialize more than once, DriverEntry returns the lowest value returned by ScsiPortInitialize.

Comments

A miniport's DriverEntry routine allocates memory on the stack and initializes a HW_INITIALIZATION_DATA structure with zeros. DriverEntry must zero all members in the HW_INITIALIZATION_DATA structure before initializing it with values appropriate to the HBA(s) the miniport supports.

DriverEntry should set the HwInitializationDataSize member to sizeof(HW_INITIALIZATION_DATA) to indicate which version of this structure it is using, as well as initializing all members appropriately for its HBA(s).

Next, DriverEntry calls ScsiPortInitialize. If a miniport driver supports HBA(s) that can be connected on more than one type of I/O bus, such as both MicroChannel and Isa type buses, it should call ScsiPortInitialize once for each type of I/O bus. Such a miniport driver must return the lowest value returned by its calls to ScsiPortInitialize from the DriverEntry routine. A miniport driver writer can make no assumptions about the values returned by ScsiPortInitialize.

See Also

HwScsiFindAdapter, HW_INITIALIZATION_DATA, ScsiPortInitialize


HwScsiAdapterControl

A miniport driver's HwScsiAdapterControl routine is called to perform synchronous operations to control the state or behavior of an HBA, such as stopping or restarting the HBA for power management.

SCSI_ADAPTER_CONTROL_STATUS
  HwScsiAdapterControl(
    IN PVOID  HwDeviceExtension,
    IN SCSI_ADAPTER_CONTROL_TYPE  ControlType,
    IN PVOID  Parameters
    )

Parameters

HwDeviceExtension
Points to the miniport driver's per-HBA storage area.
ControlType
Specifies one of the following adapter-control operations.
ScsiQuerySupportedControlTypes
Reports the adapter-control operations implemented by the miniport. The port driver calls HwScsiAdapterControl with this control type after the HBA has been initialized but before the first I/O. The miniport fills in the SCSI_SUPPORTED_CONTROL_TYPE_LIST structure at Parameters with the operations it supports. After HwScsiAdapterControl returns from this call, the port driver calls the miniport's HwScsiAdapterControl only for supported operations.
ScsiStopAdapter
Shuts down the HBA. The port driver calls HwScsiAdapterControl with this control type when the HBA has been removed from the system, stopped for resource reconfiguration, shut down for power management, or otherwise reconfigured or disabled. The port driver ensures that there are no uncompleted requests and issues an SRB_FUNCTION_FLUSH request to the miniport before calling this routine.

The miniport disables interrupts on its HBA, halts all processing, (including background processing not subject to interrupts or processing of which the port driver is unaware, such as reconstructing fault-tolerant volumes), flushes any remaining cached data to persistent storage, and puts the HBA into a state from which it can be reinitialized or restarted.

The miniport should not free its resources when stopping its HBA. If the HBA was removed or stopped for PnP resource reconfiguration, the port driver releases resources on behalf of the miniport driver. If the HBA is shut down for power management, the miniport's resources are preserved so the HBA can be restarted.

After HwScsiAdapterControl returns from stopping the HBA, any data structures allocated on behalf of the miniport for the HBA should be considered invalid until the miniport is asked to restart.

Note that the port driver might call HwScsiAdapterControl to stop the adapter after the HBA has already been physically removed from the system, so the miniport's HwScsiAdapterControl routine must not perform any operations that require the HBA to be physically present while it is stopping the HBA.

The miniport driver is not called again for the HBA until either the PnP Manager requests that the HBA be started, in which case the port driver (re)initializes by calling its HwScsiFindAdapter and HwScsiInitialize routines, or an HBA that was stopped for power management is powered up, in which case the port driver calls the miniport's HwScsiAdapterControl routine with ScsiRestartAdapter or, if the miniport does not implement that control type, repeats the initialization sequence for the HBA.

ScsiRestartAdapter
Reinitializes an HBA. The port driver calls HwScsiAdapterControl with this control type to power up an HBA that was shut down for power management. All resources previously assigned to the miniport are still available, and its device extension and logical unit extensions, if any, are intact.

The miniport performs the same operations as in its HwScsiInitialize routine, such as setting up the HBA's registers and its initial state, if any.

The miniport must not call routines that can only be called from HwScsiFindAdapter or from HwScsiAdapterControl when the control type is ScsiSetRunningConfig, such as ScsiPortGetBusData and ScsiPortSetBusDataByOffset. If the miniport must call such routines to restart its HBA, it must also implement ScsiSetRunningConfig.

If the miniport does not implement ScsiRestartAdapter, the port driver calls the miniport's HwScsiFindAdapter and HwScsiInitialize routines. However, because such routines might do detection work unnecessary for restarting the HBA, such a miniport will not power up its HBA as quickly as a miniport that implements ScsiRestartAdapter.

ScsiSetBootConfig
Restores any settings on an HBA that the BIOS might need to reboot. The port driver calls HwScsiAdapterControl with this control type after calling this routine with ScsiStopAdapter.

A miniport must implement ScsiSetBootConfig if it must call ScsiPortGetBusData or ScsiPortSetBusDataByOffset before the system will be able to reboot.

ScsiSetRunningConfig
Restores any settings on an HBA that the miniport might need to control the HBA while the system is running. The port driver calls HwScsiAdapterControl with ScsiSetRunningConfig before calling this routine with ScsiRestartAdapter if the miniport implements that control type.

The HBA's interrupt is not yet connected when the port driver makes this call, so the miniport must take care not to generate an interrupt.

A miniport must implement ScsiSetRunningConfig if it must call ScsiPortGetBusData and ScsiPortSetBusDataByOffset to restore the appropriate running configuration to the HBA before it can be restarted.

Parameters
If ControlType is ScsiStopAdapter, ScsiSetBootConfig, ScsiSetRunningConfig, or ScsiRestartAdapter, Parameters is NULL.

If ControlType is ScsiQuerySupportedControlTypes, Parameters points to a caller-allocated SCSI_SUPPORTED_CONTROL_TYPE_LIST structure, which is defined as follows:

typedef struct _SCSI_SUPPORTED_CONTROL_TYPE_LIST {
    IN ULONG MaxControlType;
    OUT BOOLEAN SupportedTypeList[0];
} SCSI_SUPPORTED_CONTROL_TYPE_LIST, *PSCSI_SUPPORTED_CONTROL_TYPE_LIST;
MaxControlType
Specifies the number of entries in the SupportedTypeList array.
SupportedTypeList
Points to a caller-allocated array of BOOLEAN values that indicate the control types implemented by the miniport driver. The port driver initializes each element to FALSE.

The miniport sets the corresponding array element to TRUE for each operation it supports:

SupportedTypeList[ScsiQuerySupportedControlTypes]
SupportedTypeList[ScsiStopAdapter]
SupportedTypeList[ScsiRestartAdapter]
SupportedTypeList[ScsiSetBootConfig]
SupportedTypeList[ScsiSetRunningConfig]

The miniport must not set any element beyond SupportedTypeList[MaxControlType – 1].

Return Value

Depending on the control type, HwScsiAdapterControl might return one of the following SCSI_ADAPTER_CONTROL_STATUS values:

ScsiAdapterControlSuccess
The miniport completed the requested operation successfully. Currently, HwScsiAdapterControl must return this value for all control types.
ScsiAdapterControlUnsuccessful
Reserved for future use.

Comments

A PnP miniport must implement HwScsiAdapterControl for PnP and Power Management operations. At a minimum, a miniport's HwScsiAdapterControl routine must support ScsiQuerySupportedControlTypes and ScsiStopAdapter.

A legacy (non-PnP) miniport should set the HwScsiAdapterControl entry point to NULL in its HW_INITIALIZATION_DATA structure. PnP and power management are effectively disabled for an HBA controlled by a legacy miniport.

See Also

HW_INITIALIZATION_DATA, HwScsiFindAdapter, HwScsiInitialize, ScsiPortGetBusData, ScsiPortSetBusDataByOffset


HwScsiAdapterState

A miniport driver's HwScsiAdapterState routine saves or restores the HBA state according to the value of the SaveState parameter. If its HBA has a BIOS and, therefore, can be initialized in x86 real mode, a miniport driver must have this routine, which is called by the x86-only, OS-dependent port driver when the system transitions from x86 real to protected processor mode.

BOOLEAN
  HwScsiAdapterState(
    IN PVOID  HwDeviceExtension,
    IN PVOID  Context,
    IN BOOLEAN  SaveState
    );

Parameters

HwDeviceExtension
Points to the miniport driver's storage for per-HBA data.
Context
Is reserved for system use.
SaveState
TRUE indicates the miniport should save the current state of the HBA until the HwScsiAdapterState routine is called again with SaveState set to FALSE to restore the saved state.

Return Value

HwScsiAdapterState returns TRUE if it successfully saved or restored the HBA state.

Comments

Miniport drivers of HBAs that are initialized in x86 real mode and that are sensitive to x86-specific processor mode transitions must have a HwScsiAdapterState routine. This routine, which is usually called after the miniport's HwScsiFindAdapter routine, preserves the initialized HBA state during x86-only system transition(s) from x86 real to protected processor mode.

HwScsiAdapterState is responsible for saving the current state of the HBA in the HwDeviceExtension when it is called with SaveState set to TRUE. It must restore the HBA state when it is called subsequently with SaveState set to FALSE.

Miniport drivers of HBAs that are initialized in x86 protected mode, and miniports for which it is irrelevant whether their HBAs are being initialized on a CISC-or RISC-based platform, need not have this routine.

See Also

HwScsiFindAdapter, ScsiPortInitialize


HwScsiDisableInterruptsCallback

HwScsiDisableInterruptsCallback is called after a miniport's HwScsiEnableInterruptsCallback routine calls ScsiPortNotification with the NotificationType CallDisableInterrupts. Miniport drivers of HBAs that require interrupt processing that takes more than 50 microseconds in the ISR should have a pair of HwScsi..InterruptsCallback routines.

BOOLEAN
  HwScsiDisableInterruptsCallback(
    IN PVOID  DeviceExtension
    );

Parameters

DeviceExtension
Points to the miniport driver's per-HBA storage area.

Return Value

HwScsiDisableInterruptsCallback returns TRUE, indicating it re-enabled interrupts on the HBA.

Comments

All system interrupts with a higher hardware priority than the HBA's are enabled when the HwScsiDisableInterruptsCallback routine is called. Consequently, a HwScsiDisableInterruptsCallback routine should be optimized to run as quickly as possible.

HwScsiDisableInterruptsCallback is responsible for re-enabling interrupts on the HBA and then returning control.

See Also

HwScsiEnableInterruptsCallback, HwScsiInterrupt, ScsiPortNotification


HwScsiDmaStarted

If the HBA is a slave DMA device, the miniport driver's HwScsiDmaStarted routine is called after the OS-specific port driver has set up the system DMA controller for a DMA transfer.

PVOID
  HwScsiDmaStarted(
    IN PVOID  HwDeviceExtension
    );

Parameters

HwDeviceExtension
Points to the miniport driver's per-HBA storage area.

Comments

Only miniport drivers of slave DMA adapters must have a HwScsiDmaStarted routine.

HwScsiDmaStarted is responsible for programming the HBA for the transfer operation.

Miniport drivers of HBAs that are busmasters or use programmed I/O do not supply this routine.

See Also

ScsiPortFlushDma, ScsiPortIoMapTransfer


HwScsiEnableInterruptsCallback

HwScsiEnableInterruptsCallback is called after a miniport's HwScsiInterrupt routine disables interrupts on the HBA and calls ScsiPortNotification with the NotificationType CallEnableInterrupts. Miniport drivers of HBAs that require interrupt processing that takes more than 50 microseconds in the ISR should have a pair of HwScsi..InterruptsCallback routines.

BOOLEAN
  HwScsiEnableInterruptsCallback(
    IN PVOID  DeviceExtension
    );

Parameters

DeviceExtension
Points to the miniport driver's per-HBA storage area.

Return Value

HwScsiEnableInterruptsCallback returns TRUE.

Comments

All system interrupts are enabled when the HwScsiEnableInterruptsCallback routine gets control, except for interrupts from the HBA. Because the miniport's HwScsiInterrupt routine disables interrupts on the HBA before it calls ScsiPortNotification, the HwScsiEnableInterruptsCallback routine should be optimized to run as quickly as possible.

HwScsiEnableInterruptsCallback is responsible for completing the interrupt-driven I/O processing deferred by the HwScsiInterrupt routine, using the information it saved in the DeviceExtension. That is, HwScsiEnableInterruptsCallback completes the request that caused the interrupt to occur.

Then, HwScsiEnableInterruptsCallback calls ScsiPortNotification again with the NotificationType CallDisableInterrupts before it returns control.

See Also

HwScsiDisableInterruptsCallback, HwScsiInterrupt, ScsiPortNotification


HwScsiFindAdapter

HwScsiFindAdapter uses supplied configuration information to determine whether it supports a particular HBA and, if so, returns information about its HBA in the given ConfigInfo buffer.

ULONG
  HwScsiFindAdapter(
    IN PVOID  DeviceExtension,
    IN PVOID  HwContext,
    IN PVOID  BusInformation,
    IN PCHAR  ArgumentString,
    IN OUT PPORT_CONFIGURATION_INFORMATION  ConfigInfo,
    OUT PBOOLEAN  Again
    );

Parameters

DeviceExtension
Points to the miniport driver's per-HBA storage area. The OS-specific port driver allocates memory for and initializes this extension with zeros before it calls the miniport's HwScsiFindAdapter routine.
HwContext
Points to a context value.

Legacy (non-PnP) miniports that scan for supported adapters can define the context in their DriverEntry routine and pass its address to ScsiPortInitialize. ScsiPortInitialize passes the context pointer to HwScsiFindAdapter. Such a miniport driver can use HwContext to store state between calls to HwScsiFindAdapter.

Miniports that use configuration information provided by the port driver, rather than by scanning the I/O bus, must not use this pointer. Even if the miniport does scan the I/O bus for other configuration information, if HwScsiFindAdapter receives nonzero access range values from the port driver it must not use the HwContext pointer.

BusInformation
Points to bus-type-specific information that the OS-specific port driver has gathered. The format of this information depends on the particular bus type, which the miniport driver determines by setting the AdapterInterfaceType value in the HW_INITIALIZATION_DATA structure.
ArgumentString
Points to a zero-terminated ASCII string. This string originates from the user and, if supplied, contains device information such as a base parameter or an interrupt level from the registry.
ConfigInfo
Points to the PORT_CONFIGURATION_INFORMATION structure. The OS-specific port driver initializes this structure with any known configuration information, such as values the miniport set in the HW_INITIALIZATION_DATA and the SystemIoBusNumber. HwScsiFindAdapter must use any supplied information to determine if the HBA it describes is one that the miniport driver supports, and, if so, to initialize and configure that HBA and to fill in any missing relevant configuration information for that HBA. If possible, each miniport driver should have a set of default configuration values for each type of HBA it supports, in case the OS-dependent port driver cannot supply additional configuration information to that provided by the miniport's DriverEntry routine.
Again
Points to a BOOLEAN variable to be set by HwScsiFindAdapter before it returns control. TRUE indicates that the miniport driver wants the OS-specific port driver to call its HwScsiFindAdapter routine again with a new DeviceExtension and the same ConfigInfo. This member is set to TRUE by miniport drivers that can support more than one HBA on an I/O bus.

Return Value

HwScsiFindAdapter must return one of the following status values:

Value | Meaning
SP_RETURN_FOUND | Indicates a supported HBA was found and that the HBA-relevant configuration information was successfully determined and set in the PORT_CONFIGURATION_INFORMATION structure.
SP_RETURN_ERROR | Indicates an HBA was found but there was error obtaining the configuration information. If possible, such an error should be logged with ScsiPortLogError.
SP_RETURN_BAD_CONFIG | Indicates the supplied configuration information was invalid for the adapter.
SP_RETURN_NOT_FOUND | Indicates no supported HBA was found for the supplied configuration information.

Comments

For a legacy miniport driver, ScsiPortInitialize calls the HwScsiFindAdapter routine after allocating storage according to the DeviceExtensionSize that the miniport specified in the HW_INITIALIZATION_DATA structure. For a Plug and Play miniport driver, the port driver calls HwScsiFindAdapter when the Plug and Play Manager has detected an adapter for that miniport.

First, every HwScsiFindAdapter routine should check the value of Length in the input PORT_CONFIGURATION_INFORMATION to determine whether the port driver has allocated a structure with all the configuration information the miniport would need to find and configure its HBA(s).

Next, every HwScsiFindAdapter routine should check the AccessRanges in the PORT_CONFIGURATION_INFORMATION to determine whether the OS-specific port driver collected and set bus-relative range-configuration information for an HBA. If HwScsiFindAdapter finds nonzero access-range values, it must map the supplied values with ScsiPortGetDeviceBase and use the returned logical range addresses to access the HBA.

If the input PORT_CONFIGURATION_INFORMATION contains AccessRanges elements filled with default zeros, the HwScsiFindAdapter routine can use any appropriate search logic, such as calling ScsiPortGetBusData, or use a set of driver-supplied bus-relative default values, to fill in each such access range element and determine its validity.

HwScsiFindAdapter should call ScsiPortValidateRange before it maps any miniport-supplied access range values with ScsiPortGetDeviceBase and uses the mapped logical addresses to access an adapter. ScsiPortValidateRange verifies that the device range has not already been claimed by another driver. If ScsiPortValidateRange returns FALSE, HwScsiFindAdapter cannot map and use that range and must not attempt to do so.

HwScsiFindAdapter must check the value of NumberOfPhysicalBreaks in the input PORT_CONFIGURATION_INFORMATION. The port driver usually sets this member to a particular value. The miniport driver can set NumberOfPhysicalBreaks to a lower value if its HBA supports fewer breaks between scatter/gather lists, but the miniport must not set it to a higher value than that supplied by the port driver. If NumberOfPhysicalBreaks is set to SP_UNINITIALIZED_VALUE, the miniport must fill in the actual number of breaks between scatter/gather lists that its underlying adapter can support.

HwScsiFindAdapter should also check the input port configuration information for additional port-driver-supplied values, such as interrupt vector or level, and DMA channel or port. Usually, the OS-specific port driver supplies additional configuration information if it supplies nonzero, bus-relative values for AccessRanges elements.

A miniport driver must use any valid configuration information it finds in the input PORT_CONFIGURATION_INFORMATION to configure the HBA.

The port driver is responsible for doing bus-level configuration programming, particularly of dynamically configurable I/O buses with published standard interfaces, such as PCI and PCMCIA. For an HBA on such an I/O bus, the miniport driver can simply accept the interrupt configuration information provided as values reserved for system use. For an HBA on other types of I/O buses, a miniport should program its HBA to use any supplied interrupt value if its HBA supports programmable interrupt configuration. If no interrupt configuration is supplied, as indicated either by the value zero or the value SP_UNINITIALIZED_VALUE, the miniport should either query its HBA if the HBA supports interrupt selection using jumpers or should supply a nonzero default interrupt configuration unless the HBA does not use interrupts. The miniport should set the interrupt configuration value to zero if it controls its HBA in a polled mode.

A miniport's HwScsiFindAdapter routine should return with the Again parameter set to TRUE so the OS-specific SCSI port driver will search for additional HBAs on the I/O bus. Although Again is irrelevant when a miniport is loaded as a Plug and Play driver, Again must be set appropriately so the system can run a Plug and Play miniport as a legacy driver if necessary.

See Also

ACCESS_RANGE, DriverEntry, HW_INITIALIZATION_DATA, PORT_CONFIGURATION_INFORMATION, ScsiPortGetBusData, ScsiPortGetDeviceBase, ScsiPortInitialize, ScsiPortLogError, ScsiPortValidateRange


HwScsiInitialize

HwScsiInitialize initializes the HBA after a reboot or a power failure occurs.

BOOLEAN
  HwScsiInitialize(
    IN PVOID  DeviceExtension
    );

Parameters

DeviceExtension
Points to the miniport driver's per-HBA storage area.

Return Value

If the initialization succeeds, HwScsiInitialize returns TRUE.

Comments

HwScsiInitialize must initialize the HBA but should avoid resetting the SCSI bus or buses if possible. Interrupts can occur before this routine is called. If HwScsiInitialize resets a bus, it must call ScsiPortNotification to report that the bus was reset.

If HwScsiInitialize cannot initialize the HBA, this routine should call ScsiPortLogError before returning FALSE when it returns control.

See Also

ScsiPortLogError, ScsiPortNotification


HwScsiInterrupt

HwScsiInterrupt is called when the HBA generates an interrupt. Miniport drivers of HBAs that do not generate interrupts do not have this routine.

BOOLEAN
  HwScsiInterrupt(
    IN PVOID  DeviceExtension
    );

Parameters

DeviceExtension
Points to the miniport driver's per-HBA storage area.

Return Value

If the miniport finds that its HBA did not generate the interrupt, HwScsiInterrupt should return FALSE as soon as possible.

Comments

HwScsiInterrupt is responsible for completing interrupt-driven I/O operations. This routine must clear the interrupt on the HBA before it returns TRUE.

Miniport drivers of HBAs that require interrupt processing that takes more than 50 microseconds should have a pair of HwScsi..InterruptsCallback routines. Such a driver's HwScsiInterrupt routine should do the following, rather than calling ScsiPortStallExecution to tie up the processor while its HBA updates hardware state:

  1. Disable interrupts on the HBA.
  2. Set up the DeviceExtension with any context necessary to complete the operation.
  3. Call ScsiPortNotification with the NotificationType value CallEnableInterrupts and the entry point for the driver's HwScsiEnableInterruptsCallback routine.
  4. Return control.

Using this technique improves overall I/O throughput, including that of any other HBAs the miniport driver supports.

If a miniport's HwScsiInterrupt routine cannot disable interrupts on its HBA but its interrupt-driven transfer operations take more than 50 microseconds in the HwScsiInterrupt routine, the miniport should limit the maximum size for transfers that it accepts. Such a miniport's HwScsiFindAdapter routine can set the MaximumTransferLength member of the PORT_CONFIGURATION_INFORMATION structure to a value that restricts execution time in the HwScsiInterrupt routine for transfers. The miniport writer should adjust this value during driver development so there is no user-noticeable impact on the performance of the mouse, serial, and/or parallel drivers. Otherwise, the mouse pointer can appear to "jump" or the serial/parallel throughput to degrade noticeably whenever that miniport is transferring data.

See Also

HwScsiDisableInterruptsCallback, HwScsiEnableInterruptsCallback, ScsiPortNotification, ScsiPortStallExecution


HwScsiResetBus

HwScsiResetBus resets a given SCSI bus.

BOOLEAN
  HwScsiResetBus(
    IN PVOID  DeviceExtension,
    IN ULONG  PathId
    );

Parameters

DeviceExtension
Points to the miniport driver's per-HBA storage area.
PathId
Identifies the SCSI bus to be reset.

Return Value

If the bus is successfully reset, HwScsiResetBus returns TRUE.

Comments

HwScsiResetBus can be called even if the miniport driver is not ready for another request. The miniport driver should complete all pending requests and must reset the given bus.

HwScsiResetBus need not call ScsiPortNotification to indicate that the bus was reset.

See Also

ScsiPortCompleteRequest, ScsiPortNotification


HwScsiStartIo

All miniport drivers must have a HwScsiStartIo routine. The OS-specific port driver calls HwScsiStartIo first with each incoming I/O request for a target on a SCSI bus.

BOOLEAN
  HwScsiStartIo(
    IN PVOID  DeviceExtension,
    IN PSCSI_REQUEST_BLOCK  Srb
    );

Parameters

DeviceExtension
Points to the miniport driver's per-HBA storage area.
Srb
Points to the SCSI request block to be started.

Return Value

HwScsiStartIo returns TRUE to acknowledge receipt of the SRB.

Comments

As soon as it receives the initial request for a target peripheral, the OS-specific port driver calls the HwScsiStartIo routine with an input SRB. After this call, the HBA miniport driver owns the request and is expected to complete it.

Subsequently, the OS-specific port driver calls the HwScsiStartIo routine after the port driver receives each NextRequest, NextLuRequest, or notification as the miniport driver makes calls to ScsiPortNotification and/or ScsiPortCompleteRequest.

When the HwScsiStartIo routine is called but the driver needs to defer processing of the given SRB, HwScsiStartIo should do the following:

  1. Set the SrbStatus member to SRB_STATUS_BUSY.
  2. Call ScsiPortNotification with the request to be deferred and a notification type of RequestComplete.
  3. Return TRUE.

The port driver requeues such a request and resubmits it later.

See Also

ScsiPortCompleteRequest, ScsiPortNotification, SCSI_REQUEST_BLOCK


HwScsiTimer

HwScsiTimer is called after the interval specified when the miniport driver called ScsiPortNotification with the RequestTimerCall NotificationType value.

VOID
  HwScsiTimer(
    IN PVOID  DeviceExtension
    );

Parameters

DeviceExtension
Points to the miniport driver's per-HBA storage area.

Comments

A HwScsiTimer routine is optional.

See Also

ScsiPortNotification


HwScsiWmiExecuteMethod

A miniport driver's HwScsiWmiExecuteMethod routine is called to execute a method associated with a data block. This routine is optional.

BOOLEAN
  HwScsiWmiExecuteMethod(
    IN PVOID  DeviceContext,
    IN PSCSIWMI_REQUEST_CONTEXT  RequestContext,
    IN ULONG  GuidIndex,
    IN ULONG  InstanceIndex,
    IN ULONG  MethodId,
    IN ULONG  InBufferSize,
    IN ULONG  OutBufferSize,
    IN OUT PUCHAR  Buffer
    );

Parameters

DeviceContext
Points to the miniport-defined context value passed to ScsiPortWmiDispatchFunction.
RequestContext
Points to the SCSIWMI_REQUEST_CONTEXT structure that the miniport passed to ScsiPortWmiDispatchFunction.
GuidIndex
Specifies the data block by its index into the list of GUIDs in the SCSI_WMILIB_CONTEXT structure that the miniport passed to ScsiPortWmiDispatchFunction.
InstanceIndex
If the block specified by GuidIndex has multiple instances, InstanceIndex specifies the instance.
MethodId
Specifies the ID of the method to execute. The miniport defines the method ID as an item in a data block.
InBufferSize
Indicates the size in bytes of the input data. If there is no input data, InBufferSize is zero.
OutBufferSize
Indicates the number of bytes available in the buffer for output data.
Buffer
Points to a buffer that holds the input data and receives the output data, if any, from the method. If the buffer is too small to receive all of the output, the miniport calls ScsiPortWmiPostProcess with SRB_STATUS_DATA_OVERRUN and the size required.

Return Value

HwScsiWmiExecuteMethod returns TRUE if the request is pending, or FALSE if the request was completed.

Comments

When a miniport driver receives an SRB in which the Function member is set to SRB_FUNCTION_WMI, it calls ScsiPortWmiDispatchFunction with a pointer to an initialized SCSI_WMILIB_CONTEXT structure and MinorFunction set to Srb->WmiSubFunction. The SCSI port driver calls the miniport's HwScsiWmiExecuteMethod routine if MinorFunction indicates a request to execute a method.

If a miniport does not implement a HwScsiWmiExecuteMethod routine, it must set ExecuteWmiMethod to NULL in the SCSI_WMILIB_CONTEXT the miniport passes to ScsiPortWmiDispatchFunction. In this case, the port driver returns SRB_STATUS_ERROR to the caller.

If the method generates output, the miniport should check the size of the output buffer in OutBufferSize before performing any operation that might have side effects or that should not be performed twice. For example, if a method returns the values of a group of counters and then resets the counters, the miniport should check the buffer size before resetting the counters. This ensures that the port driver can safely re-send the request with a larger buffer. If the buffer is too small, the miniport should call ScsiPortWmiPostProcess with SRB_STATUS_DATA_OVERRUN and the size of the output buffer needed to fulfill the request.

The miniport executes the method and writes output, if any, to the buffer. Before returning from HwScsiWmiExecuteMethod, the miniport calls ScsiPortWmiPostProcess with an appropriate SrbStatus value and the number of bytes used in the output buffer.

See Also

SCSI_WMILIB_CONTEXT, SCSIWMI_REQUEST_CONTEXT, ScsiPortWmiPostProcess, ScsiPortWmiDispatchFunction


HwScsiWmiFunctionControl

A miniport driver's HwScsiWmiFunctionControl routine is called to enable or disable notification of events. It is also called to enable or disable data collection for data blocks that the miniport driver designated as expensive to collect. This routine is optional.

BOOLEAN
  HwScsiWmiFunctionControl(
    IN PVOID  DeviceContext,
    IN PSCSIWMI_REQUEST_CONTEXT  RequestContext,
    IN ULONG  GuidIndex,
    IN SCSIWMI_ENABLE_DISABLE_CONTROL  Function,
    IN BOOLEAN  Enable
    );

Parameters

DeviceContext
Points to the miniport-defined context value passed to ScsiPortWmiDispatchFunction.
RequestContext
Points to the SCSIWMI_REQUEST_CONTEXT structure that the miniport passed to ScsiPortWmiDispatchFunction.
GuidIndex
Specifies the block by its index into the list of GUIDs in the SCSI_WMILIB_CONTEXT structure that the miniport passed to ScsiPortWmiDispatchFunction.
Function
Specifies ScsiWmiEventControl to enable or disable an event, or ScsiWmiDataBlockControl to enable or disable data collection for a block that was registered as expensive to collect (that is, a block for which the miniport set WMIREG_FLAG_EXPENSIVE in Flags of the SCSIWMIGUIDREGINFO structure used to register the block).
Enable
Specifies TRUE to enable the event or data collection, or FALSE to disable it.

Return Value

HwScsiWmiFunctionControl returns TRUE if the request is pending, or FALSE if the request was completed.

Comments

When a miniport driver receives an SRB in which the Function member is set to SRB_FUNCTION_WMI, it calls ScsiPortWmiDispatchFunction with a pointer to an initialized SCSI_WMILIB_CONTEXT structure and MinorFunction set to Srb->WmiSubFunction. The SCSI port driver calls a miniport's HwScsiWmiFunctionControl routine if MinorFunction indicates a request to enable or disable an event, or to enable or disable collection for a data block that the miniport registered as expensive to collect.

If a miniport does not implement a HwScsiWmiFunctionControl routine, it must set WmiFunctionControl to NULL in the SCSI_WMILIB_CONTEXT the miniport passes to ScsiPortWmiDispatchFunction. The port driver returns SRB_STATUS_SUCCESS to the caller.

It is unnecessary for the miniport to check whether events or data collection are already enabled for a block because the port driver sends a single enable request when the first data consumer enables the block, and sends a single disable request when the last data consumer disables the block. The port driver will not call HwScsiWmiFunctionControl more than once to enable a block without an intervening call to disable it.

If the SRB is completed in the HwScsiWmiFunctionControl callback, then the miniport calls ScsiPortWmiPostProcess with an appropriate SrbStatus. If the miniport driver pends this SRB, then it should call ScsiPortWmiPostProcess when the SRB is done and before completing the SRB.

See Also

SCSIWMIGUIDREGINFO, SCSI_WMILIB_CONTEXT, ScsiPortWmiDispatchFunction, ScsiPortWmiPostProcess


HwScsiWmiQueryDataBlock

A miniport driver's HwScsiWmiQueryDataBlock routine is called to obtain either a single instance or all instances of a data block. This routine is required.

BOOLEAN
  HwScsiWmiQueryDataBlock(
    IN PVOID  Context,
    IN PSCSIWMI_REQUEST_CONTEXT  DispatchContext,
    IN ULONG  GuidIndex,
    IN ULONG  InstanceIndex,
    IN ULONG  InstanceCount,
    IN OUT PULONG  InstanceLengthArray,
    IN ULONG  BufferAvail,
    OUT PUCHAR  Buffer
    );

Parameters

Context
Points to the miniport-defined context value passed to ScsiPortWmiDispatchFunction.
DispatchContext
Points to the SCSIWMI_REQUEST_CONTEXT structure that the miniport passed to ScsiPortWmiDispatchFunction.
GuidIndex
Specifies the data block by its index into the list of GUIDs in the SCSI_WMILIB_CONTEXT structure that the miniport passed to ScsiPortWmiDispatchFunction.
InstanceIndex
If HwScsiWmiQueryDataBlock is called in response to an IRP_MN_QUERY_SINGLE_INSTANCE request, InstanceIndex specifies the instance to be queried. If HwScsiWmiQueryDataBlock is called in response to an IRP_MN_QUERY_ALL_DATA REQUEST, InstanceIndex is zero.
InstanceCount
If HwScsiWmiQueryDataBlock is called in response to an IRP_MN_QUERY_SINGLE_INSTANCE request, InstanceCount is 1. If HwScsiWmiQueryDataBlock is called in response to an IRP_MN_QUERY_ALL_DATA REQUEST, InstanceCount is the number of instances to be returned.
InstanceLengthArray
Points to an array of ULONGs that indicate the length of each instance of the data block to be returned. This array has InstanceCount elements. This value may be NULL when there is not enough space in the output buffer to fulfill the request.
BufferAvail
Specifies the maximum number of bytes available to receive data in the buffer at Buffer.
Buffer
Points to the buffer to receive instance data. If the buffer is large enough to receive all of the data, the miniport writes instance data to the buffer with each instance aligned on an 8-byte boundary. If the buffer is too small to receive all of the data, the miniport calls ScsiPortWmiPostProcess with a status of SRB_STATUS_DATA_OVERRUN and sets BufferUsed to the size of the output buffer needed to fulfill the request.

Return Value

HwScsiWmiQueryDataBlock returns TRUE if the request is pending or FALSE if the request was completed.

Comments

When a miniport driver receives an SRB in which the Function member is set to SRB_FUNCTION_WMI, it calls ScsiPortWmiDispatchFunction with a pointer to an initialized SCSI_WMILIB_CONTEXT structure and MinorFunction set to Srb->WmiSubFunction. The SCSI port driver calls the miniport's HwScsiWmiQueryDataBlock routine if MinorFunction indicates a request to obtain a single instance or all instances of a data block.

The miniport writes instance data to the buffer. For requests that do not pend, the miniport calls ScsiPortWmiPostProcess with an appropriate SrbStatus value before returning from HwScsiWmiQueryDataBlock . If the request pends, the miniport calls ScsiPortWmiPostProcess when the request is complete.

See Also

SCSI_WMILIB_CONTEXT, ScsiPortWmiPostProcess, ScsiPortWmiDispatchFunction


HwScsiWmiQueryReginfo

A miniport driver's HwScsiWmiQueryReginfo routine is called to obtain information about the data and event blocks to be registered on behalf of the miniport by the SCSI port driver. This routine is required.

UCHAR
  HwScsiWmiQueryReginfo(
    IN PVOID  DeviceContext,
    IN PSCSIWMI_REQUEST_CONTEXT  RequestContext,
    OUT PWCHAR  *MofResourceName
    );

Parameters

DeviceContext
Points to the miniport-defined context value passed to ScsiPortWmiDispatchFunction.
RequestContext
Points to the SCSIWMI_REQUEST_CONTEXT structure that the miniport passed to ScsiPortWmiDispatchFunction.
MofResourceName
Points to a null terminated Unicode string that indicates the name of the MOF resource attached to the miniport's binary image file. This string can be declared as a constant in the miniport driver. If the miniport does not have a MOF resource attached, it should set MofResourceName to NULL.

Return Value

HwScsiWmiQueryReginfo always returns TRUE.

Comments

When a miniport driver receives an SRB in which the Function member is set to SRB_FUNCTION_WMI, it calls ScsiPortWmiDispatchFunction with a pointer to an initialized SCSI_WMILIB_CONTEXT structure and MinorFunction set to Srb->WmiSubFunction. If MinorFunction indicates a request for registration information, the SCSI port driver calls the miniport's HwScsiWmiQueryReginfo routine.

The miniport provides new or updated registration information about individual blocks, or indicates blocks to remove, in the SCSI_WMILIB_CONTEXT structure it passes to ScsiPortWmiDispatchFunction. The miniport's HwScsiWmiQueryReginfo routine supplies a pointer to its MOF resource name.

The miniport must not pend or block the SRB. The miniport must not call ScsiPortWmiPostProcess or ScsiPortNotification from its HwScsiWmiQueryReginfo routine.

See Also

SCSI_WMILIB_CONTEXT, SCSIWMI_REQUEST_CONTEXT, ScsiPortWmiDispatchFunction


HwScsiWmiSetDataBlock

A miniport driver's HwScsiWmiSetDataBlock routine is called to change all data items in a single instance of a data block. This routine is optional.

BOOLEAN
  HwScsiWmiSetDataBlock(
    IN PVOID  DeviceContext,
    IN PSCSIWMI_REQUEST_CONTEXT  RequestContext,
    IN ULONG  GuidIndex,
    IN ULONG  InstanceIndex,
    IN ULONG  BufferSize,
    IN PUCHAR  Buffer
    );

Parameters

DeviceContext
Points to the miniport-defined context value passed to ScsiPortWmiDispatchFunction.
RequestContext
Points to the SCSIWMI_REQUEST_CONTEXT structure that the miniport passed to ScsiPortWmiDispatchFunction.
GuidIndex
Specifies the data block by its index into the list of GUIDs in the SCSI_WMILIB_CONTEXT structure that the miniport passed to ScsiPortWmiDispatchFunction.
InstanceIndex
If the block specified by GuidIndex has multiple instances, InstanceIndex specifies the instance.
BufferSize
Specifies the size in bytes of the buffer at Buffer.
Buffer
Points to a buffer that contains new values for the instance.

Return Value

HwScsiWmiSetDataBlock returns TRUE if the request is pending, or FALSE if the request was completed.

Comments

When a miniport driver receives an SRB in which the Function member is set to SRB_FUNCTION_WMI, it calls ScsiPortWmiDispatchFunction with a pointer to an initialized SCSI_WMILIB_CONTEXT structure and MinorFunction set to Srb->WmiSubFunction. The SCSI port driver calls the miniport's HwScsiWmiSetDataBlock routine if MinorFunction indicates a request to change an instance of a data block.

If a miniport does not implement a HwScsiWmiSetDataBlock routine, it must set SetWmiDataBlock to NULL in the SCSI_WMILIB_CONTEXT the miniport passes to ScsiPortWmiDispatchFunction. In this case, the port driver returns SRB_STATUS_ERROR to the caller.

If the miniport implements HwScsiWmiSetDataBlock it should change the instance of the data block to the new values from the buffer.

If all of the items in the data block are read-only, the miniport should return SRB_STATUS_ERROR. Otherwise, the miniport changes the items it can and returns SRB_STATUS_SUCCESS.

The miniport should call ScsiPortWmiPostProcess with an appropriate SrbStatus value when the request is completed. If the request does not pend, ScsiPortWmiPostProcess should be called in the HwScsiWmiSetDataBlock callback. Otherwise, ScsiPortWmiPostProcess should be called when the request is actually completed.

See Also

SCSI_WMILIB_CONTEXT, ScsiPortWmiDispatchFunction, ScsiPortWmiPostProcess


HwScsiWmiSetDataItem

A miniport driver's HwScsiWmiSetDataItem routine is called to change a single data item in an instance of a data block. This routine is optional.

BOOLEAN
  HwScsiWmiSetDataItem(
    IN PVOID  DeviceContext,
    IN PSCSIWMI_REQUEST_CONTEXT  RequestContext,
    IN ULONG  GuidIndex,
    IN ULONG  InstanceIndex,
    IN ULONG  DataItemId,
    IN ULONG  BufferSize,
    IN PUCHAR  Buffer
    );

Parameters

DeviceContext
Points to the miniport-defined context value passed to ScsiPortWmiDispatchFunction.
RequestContext
Points to the SCSIWMI_REQUEST_CONTEXT structure that the miniport passed to ScsiPortWmiDispatchFunction.
GuidIndex
Specifies the data block by its index into the list of GUIDs in the SCSI_WMILIB_CONTEXT structure that the miniport passed to ScsiPortWmiDispatchFunction.
InstanceIndex
If the block specified by GuidIndex has multiple instances, InstanceIndex specifies the instance.
DataItemId
Specifies the ID of the data item to set.
BufferSize
Specifies the size in bytes of the buffer at Buffer.
Buffer
Points to a buffer that contains the new value for the data item.

Return Value

HwScsiWmiSetDataItem returns TRUE if the request is pending, or FALSE if the request was completed.

Comments

When a miniport driver receives an SRB in which the Function member is set to SRB_FUNCTION_WMI, it calls ScsiPortWmiDispatchFunction with a pointer to an initialized SCSI_WMILIB_CONTEXT structure and MinorFunction set to Srb->WmiSubFunction. The SCSI port driver calls the miniport's HwScsiWmiSetDataItem routine if MinorFunction indicates a request to change an item in an instance of a data block.

If a miniport driver does not implement a HwScsiWmiSetDataItem routine, it must set SetWmiDataItem to NULL in the SCSI_WMILIB_CONTEXT the miniport passes to ScsiPortWmiDispatchFunction. In this circumstance, the port driver will return SRB_STATUS_ERROR to the caller.

If the request does not pend, the miniport driver should call ScsiPortWmiPostProcess in its HwScsiWmiSetDataItem callback. Otherwise, the miniport driver should call ScsiPortWmiPostProcess when the request is actually completed. The miniport driver should call ScsiPortWmiPostProcess with the appropriate SrbStatus value.

If the item is read-only, the miniport calls ScsiPortWmiPostProcess with SRB_STATUS_ERROR. Otherwise, the miniport changes the item and calls ScsiPortWmiPostProcess with SRB_STATUS_SUCCESS.

See Also

SCSI_WMILIB_CONTEXT, ScsiPortWmiDispatchFunction, ScsiPortWmiPostProcess


System Management Bus Driver Clients

This section describes required and optional functionality for clients of the System Management Bus (SMB) class driver in Windows 2000 and later operating systems, including the following:

Overview of SMB Drivers

Required Driver Routines for an SMB Client

SMB Client's DriverEntry Routine

SMB Client's AddDevice Routine

SMB Client's Unload Routine

SMB Client's Dispatch Routines

Sending an SMB Request

Defining an SMB Request

Requesting and Responding to SMB Alarm Notifications

Installing an SMB Client Driver


Overview of SMB Drivers

A System Management Bus (SMB) is a simple bus used primarily to communicate with devices on the motherboard, such as the battery subsystem, temperature sensor, lid switch, or other low-bandwidth devices. The SMB is generally not user configurable or accessible. Support for SMB devices is provided on Windows 2000 and later operating systems. Windows 98/Me does not support such devices.

An SMB client driver provides device-specific capabilities for an SMB device. An SMB client communicates with the SMB class driver (smbclass.sys) and the class driver for its device type, if such a driver exists. The following figure shows the drivers involved in controlling an SMB device.

SMB Drivers

As the previous figure shows, the following drivers (reading from the bottom up) are involved in controlling a device on the System Management Bus:

  • The SMB class driver, which communicates with the bus, the client driver, and the SMB host controller. The class driver, which is supplied by Microsoft, provides services common to all SMB devices.
  • The SMB host controller driver, essentially a miniclass driver that works with the SMB class driver. The SMB class driver and host controller together communicate with the device through the bus. The host controller driver is also supplied by Microsoft.
  • The SMB client driver, which sends IRPs to the SMB class driver to request operations on the device. The client driver acts as the Plug-and-Play (PnP) function driver for the SMB device. If a class driver is present for the device class, the client driver and the device class driver together handle device operations and act as the function driver.

    For example, the system-supplied smart battery driver is an SMB client as well as a battery miniclass driver; as such, it combines the functions of the SMB client and the battery miniclass driver. Together with the battery class driver, it acts as the PnP function driver for the smart battery subsystem on the SMB.

  • The device class driver for the device (optional). If a device class driver is not present, then any upper level filter drivers communicate directly with the SMB client driver.
  • Upper-level filter drivers (optional).


Required Driver Routines for an SMB Client

SMB clients must supply the following standard driver routines:

  • A DriverEntry routine to initialize the client
  • An AddDevice routine to initialize the device
  • An Unload routine to remove the client
  • One or more Dispatch routines to handle the following types of IRPs:
    • IRP_MJ_CREATE
    • IRP_MJ_CLOSE
    • IRP_MJ_DEVICE_CONTROL
    • IRP_MJ_PNP
    • IRP_MJ_POWER

An SMB client driver must include the smbus.h header file.


SMB Client's DriverEntry Routine

An SMB client must have a DriverEntry routine. The name DriverEntry is required, so that the operating system can call the routine upon loading the driver. The routine must exactly follow the system-provided prototype for DriverEntry.

The DriverEntry routine of an SMB client should set the following entry points in the input driver object:

Entry point | In
Unload | DriverObject->DriverUnload
AddDevice | DriverObject->DriverExtension->AddDevice
DispatchPower | DriverObject->MajorFunction[IRP_MJ_POWER]
DispatchPnP | DriverObject->MajorFunction[IRP_MJ_PNP]
DispatchCreate | DriverObject->MajorFunction[IRP_MJ_CREATE]
DispatchClose | DriverObject->MajorFunction[IRP_MJ_CLOSE]
DispatchDeviceControl | DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]

Because device-specific state information is not known until the PnP Manager calls the client's AddDevice routine, the DriverEntry routine does not initialize any such state. Device-specific initialization is performed in the AddDevice routine.

If the client completes initialization successfully, it returns STATUS_SUCCESS from DriverEntry. If initialization fails for any reason, the client should instead return a meaningful error status.


SMB Client's AddDevice Routine

Each SMB client driver must have an AddDevice routine (see Plug and Play), which initializes device-specific information.

The PnP Manager calls the SMB client's AddDevice routine once for each SMB device it enumerates. The client's AddDevice routine must create and initialize a functional device object (FDO) as a target of I/O for an SMB device. The client driver then attaches itself to the device stack for the SMB device by calling IoAttachDeviceToDeviceStack, so that subsequent I/O requests to the underlying SMB device are routed through the client.

The AddDevice routine also initializes any device-specific data structures. If a class driver is present for the device type, the SMB client might additionally need to call a class driver initialization routine or perform other class-specific initialization.

The SMB client returns STATUS_SUCCESS from AddDevice if all initialization completes successfully. If any part of the initialization fails, the client should free any allocated storage and return a meaningful error status from AddDevice.


SMB Client's Unload Routine

An SMB client must supply an Unload routine that frees any per-driver resources allocated by the client, and deregisters any registered notification routines. If a class driver for the device type is present, the class driver might perform some of these tasks.


SMB Client's Dispatch Routines

An SMB client must provide DispatchXxx routines for the following types of IRPs.

IRP_MJ_CREATE

An SMB client must have a DispatchCreate routine to handle IRP_MJ_CREATE requests. The actions performed by this routine depend on the type of device being controlled.

If external consumers can connect to the device, the client might need to allocate per-open resources for the device, such as memory buffers, NT objects, and doubly-linked lists for queuing IRPs. If the client is designed to support such resources, it should use the pointer to the file object in the IO_STACK_LOCATION of the IRP_MJ_CREATE request to uniquely identify the per-open area. When the client later receives an IRP_MJ_CLOSE, it must free the allocated area.

If the client has no such external requirements, it can simply complete the IRP with STATUS_SUCCESS, specifying no priority boost (IO_NO_INCREMENT).

IRP_MJ_CLOSE

An SMB client must have a DispatchClose routine to handle IRP_MJ_CLOSE requests. If the client has taken any per-open actions in its DispatchCreate routine, it must undo those actions when it handles the IRP_MJ_CLOSE. For example, a client must free any resources allocated in the DispatchCreate routine.

If the client has no such external requirements, it can simply complete the IRP with STATUS_SUCCESS, specifying no priority boost (IO_NO_INCREMENT).

IRP_MJ_PNP

An SMB client's DispatchPnP routine must be prepared to handle, at a minimum, the following PnP IRPs for the devices it controls:

IRP_MN_START_DEVICE

IRP_MN_QUERY_STOP_DEVICE

IRP_MN_STOP_DEVICE

IRP_MN_CANCEL_STOP_DEVICE

IRP_MN_QUERY_REMOVE_DEVICE

IRP_MN_REMOVE_DEVICE

IRP_MN_CANCEL_REMOVE_DEVICE

IRP_MN_SURPRISE_REMOVAL

For each IRP the client handles, it should return an appropriate status. For any IRP it is not prepared to handle, it must use IoSkipCurrentIrpStackLocation and IoCallDriver to pass the IRP down the device stack.

IRP_MJ_POWER

An SMB client's DispatchPower routine must be prepared to handle IRP_MJ_POWER requests. In most cases, the client should pass the IRP down the device stack, using IoSkipCurrentIrpStackLocation and PoCallDriver.

If the device requires power operations, but a class driver that provides power management capabilities is not present, the client driver should perform the operations if it can. Doing so might require accessing the device to change its power state, sending a device power IRP in response to a system power IRP, or completing an IRP. See Plug and Play for further information on supporting power management in drivers.

IRP_MJ_DEVICE_CONTROL

An SMB client must include a DispatchDeviceControl routine that handles IRP_MJ_DEVICE_CONTROL requests if it defines private IOCTLs for its device or if its device class defines such IOCTLs.


Sending an SMB Request

An SMB client driver communicates with its device by using internal device IOCTLs defined by the SMB class driver.

The SMB_BUS_REQUEST IOCTL provides for input and output to SMB devices. To perform I/O to an SMB device, the client driver sends an IRP that includes the following:

  • IRP_MJ_INTERNAL_DEVICE_CONTROL at Irp->MajorFunction
  • SMB_BUS_REQUEST at Irp –> Parameters.DeviceIoControl.IoControlCode
  • sizeof (SMB_REQUEST) at Irp –> Parameters.DeviceIoControl.InputBufferLength
  • An SMB_REQUEST structure at Irp –> Parameters.DeviceIoControl.Type3InputBuffer

The target of the IRP must be the FDO created by the SMB host controller. Before sending the IRP, the client driver should initialize a kernel notification event and set an IoCompletion routine. It then can call IoCallDriver and wait for the event. In its IoCompletion routine, the client sets the event and returns STATUS_MORE_PROCESSING_REQUIRED, so that it can inspect any returned data. After the event has signaled, the client should free the IRP.


Defining an SMB Request

The SMB_REQUEST structure is defined as follows:

typedef struct {
    UCHAR       Status;
    UCHAR       Protocol;
    UCHAR       Address;
    UCHAR       Command;
    UCHAR       BlockLength;
    UCHAR       Data[SMB_MAX_DATA_SIZE];
} SMB_REQUEST, *PSMB_REQUEST;

The bus driver returns one of the following in Status:

SMB_STATUS_OK
SMB_UNKNOWN_FAILURE
SMB_ADDRESS_NOT_ACKNOWLEDGED
SMB_DEVICE_ERROR
SMB_COMMAND_ACCESS_DENIED
SMB_UNKNOWN_ERROR
SMB_DEVICE_ACCESS_DENIED
SMB_TIMEOUT
SMB_UNSUPPORTED_PROTOCOL
SMB_BUS_BUSY

The client supplies the Protocol, Address, Command, BlockLength, and Data members of the structure, as appropriate to its device and the operation requested.

The class driver supports the protocols listed in the following table.

Protocol name | Description
SMB_READ_QUICK | Reads from a device but returns no data.
SMB_WRITE_QUICK | Writes to a device, returning no data.
SMB_SEND_BYTE | Sends one byte of data to a device.
SMB_RECEIVE_BYTE | Receives one byte of data from the device.
SMB_READ_BYTE | Reads a byte from an SMB device.
SMB_WRITE_BYTE | Writes a byte to an SMB device.
SMB_READ_WORD | Reads a word from an SMB device.
SMB_WRITE_WORD | Writes a word to an SMB device.
SMB_READ_BLOCK | Reads up to SMB_MAX_DATA_SIZE bytes from an SMB device.
SMB_WRITE_BLOCK | Writes up to SMB_MAX_DATA_SIZE bytes to an SMB device.
SMB_PROCESS_CALL | Combines functions of SMB_READ_WORD and SMB_WRITE_WORD. Allows a device to return a value that depends on the value input, without a synchronization mechanism to know when the data is ready.

The Command member of the SMB_REQUEST structure provides for a device-specific command code. The client driver should define these codes according to the capabilities of the device. For some devices, not all of the protocols defined by the class driver will be useful. The Address member provides for a bus address, which the client driver must supply in each call.

For a simple device that has only two states, you can use the SMB_READ_QUICK and SMB_WRITE_QUICK protocols to select one of the states. The client driver fills in only the Protocol and Address fields in the request structure.

The SMB_SEND_BYTE and SMB_RECEIVE_BYTE protocols read or write a single byte of data from a device that does not have multiple commands. The client driver must fill in the Protocol, Address, and Data[0] fields when sending a byte. When receiving a byte, the client driver must fill in the Protocol and Address fields. The bus driver returns data in Data[0].

The SMB_READ_BYTE and SMB_WRITE_BYTE protocols are used with the Command field to read or write a byte to a complex device (such as a smart battery) that supports more than one command. The client driver supplies the relevant code in Command and fills in the Protocol and Address fields. Place data to be written in Data[0], and read data from that location.

The SMB_READ_WORD and SMB_WRITE_WORD protocols are also used with a device-specific command to read or write a word. The client driver supplies the Protocol, Command, and Address, and when writing data, the data in Data[0] and Data[1] (most significant byte). On a read request, the word in returned in Data[0] and Data[1], with the most significant byte in Data[1].

The SMB_READ_BLOCK and SMB_WRITE_BLOCK protocols read or write an arbitrary number of bytes of data (up to SMB_MAX_DATA_SIZE). For a read request, the client driver supplies the Protocol, Command, and Address, and the bus driver returns the number of bytes written in BlockLength and the data in Data[0..BlockLength – 1]. For a write request, the client driver supplies the Protocol, Command, Address, BlockLength, and the data in Data[0..Blocklength – 1].

The SMB_PROCESS_CALL request is similar to a combined read-word/write-word request in a single atomic request. It allows the device to return a value that is dependent on the input value without requiring a synchronization mechanism to wait until the returned data is ready. The client driver supplies a Protocol, Address, and Command, and places the data in Data[0] and Data[1] (most significant byte), where the bus driver returns data.


Installing an SMB Client Driver

Installing an SMB client driver requires writing an INF file for the client driver and editing the battery.inf file supplied with the system. The INF file must specify the hardware ID, class name, and class GUID for the device. See Creating an INF File and Installing a Battery Driver for more information.

In battery.inf, the device controlled by the client driver must be listed in the Models section. If the device is not listed, add an entry like the following:

%ACPI\acpiNNNN.DeviceDesc% = SMBBCLIENT_Inst,ACPI\acpiNNNN

In the example, ACPI\acpiNNNN represents the ACPI hardware ID of the client device. The client device must be listed in the ACPI name space under the SMBus device, and its hardware ID must match the value of the _HID object in the ACPI name space.


SMB IOCTLS

This chapter describes the internal I/O control codes defined for System Management Bus (SMB) drivers in Windows 2000 and later operating systems. Windows 98/Me does not provide support for SMB drivers.

An SMB miniport driver or a client of such a driver can send IRP_MJ_INTERNAL_DEVICE_CONTROL requests that specify the following I/O control codes:

SMB_BUS_REQUEST

SMB_REGISTER_ALARM_NOTIFY

SMB_DEREGISTER_ALARM_NOTIFY

When the SMB class driver receives the IRP that contains the IOCTL, it either performs the requested action or calls the miniport driver to perform the action.

Drivers that send or handle IRPs that contain these IOCTLs must include the header file smbus.h.


SMB_BUS_REQUEST

Operation

The class driver performs the requested action. If the device is idle, the class driver starts I/O on the device. Otherwise, the driver puts the request in the device I/O queue, where it might be handled by the miniport driver.

Input

Irp->Parameters.DeviceIoControl.Type3InputBuffer points to an SMB_REQUEST structure that describes the I/O request.

Irp->Parameters.DeviceIoControl.InputBufferLength specifies the length of the SMB_REQUEST structure.

Output

None

I/O Status Block

IoStatus.Status is set as follows:

Set to | If
STATUS_SUCCESS | The operation succeeded.
STATUS_PENDING | The operation has been queued.
STATUS_BUFFER_TOO_SMALL or STATUS_INVALID_PARAMETER. | An error occurred.

IoStatus.Information is set to the size of the returned SMB_REQUEST structure when the IRP completes. If the IRP is pending, Information is set to zero. If the input buffer is too small, Information is set to the required length of the input buffer.

See Also

SMB_REQUEST


SMB_DEREGISTER_ALARM_NOTIFY

Operation

The SMB class driver deletes the requested alarm notification.

Input

Parameters.DeviceIoControl.Type3InputBuffer points to a handle previously returned by SMB_REGISTER_ALARM_NOTIFY.

Parameters.DeviceIoControl.InputBufferLength specifies the size of the handle.

Output

None

I/O Status Block

IoStatus.Status is set to STATUS_SUCCESS if the operation succeeded, or to an error status such as STATUS_INVALID_PARAMETER otherwise.

See Also

SMB_REGISTER_ALARM_NOTIFY


SMB_REGISTER_ALARM_NOTIFY

Operation

The SMB class driver registers an alarm notification function for alarms that occur within a specified range of bus addresses.

When the miniport driver calls SmbClassAlarm to notify the SMB class driver that a device has signaled an alarm, the class driver calls the notification function.

Input

Parameters.DeviceIoControl.Type3InputBuffer points to an SMB_REGISTER_ALARM structure.

Parameters.DeviceIoControl.InputBufferLength specifies the length of the SMB_REGISTER_ALARM structure.

Parameters.DeviceIoControl.OutputBufferLength specifies the number of bytes allocated for the returned handle (sizeof(PVOID)).

Output

Irp->UserBuffer points to a handle to be used when unregistering the alarm.

I/O Status Block

IoStatus.Status is set to STATUS_SUCCESS if the operation succeeded, or to an error status such as STATUS_INVALID_PARAMETER or STATUS_INSUFFICIENT_RESOURCES otherwise.

IoStatus.Information is set to the length of the handle returned in Irp->UserBuffer.

See Also

SMB_REGISTER_ALARM, SMB_DEREGISTER_ALARM_NOTIFY


SMB Structures

This chapter describes structures used by SMB miniport clients, SMB miniport drivers, their support routines, and related IOCTLs in Windows 2000 and later operating systems. The following structures are described in alphabetical order:

SMB_CLASS

SMB_REGISTER_ALARM

SMB_REQUEST

These structures are defined in the header file smbus.h.


SMB_CLASS

SMB_CLASS contains data shared by the SMB class driver and a miniport driver.

typedef struct _SMB_CLASS {
  USHORT  MajorVersion;
  USHORT  MinorVersion;
  PVOID  Miniport;
  PDEVICE_OBJECT  DeviceObject;
  PDEVICE_OBJECT  PDO;
  PDEVICE_OBJECT  LowerDeviceObject;
  PIRP  CurrentIrp;
  PSMB_REQUEST  CurrentSmb;
  SMB_RESET_DEVICE  ResetDevice;
  SMB_START_IO  StartIo;
  SMB_STOP_DEVICE  StopDevice;
} SMB_CLASS, *PSMB_CLASS;

Members

MajorVersion
Major version number of the class driver. Must be SMB_CLASS_MAJOR_VERSION.
MinorVersion
Minor version number of the class driver. Must be SMB_CLASS_MINOR_VERSION.
Miniport
Pointer to extension data for the miniport driver.
DeviceObject
Pointer to the functional device object (FDO) for the miniport driver.
PDO
Pointer to the physical device object (PDO) for the miniport driver.
LowerDeviceObject
Pointer to the next lower device object in the device stack.
CurrentIrp
Pointer to the current IRP request, if any; otherwise, NULL.
CurrentSmb
Pointer to the current SMB_REQUEST in the current IRP request, if any; otherwise, NULL.
ResetDevice
Pointer to the miniport driver's SmbMiniResetDevice routine.
StartIo
Pointer to the miniport driver's SmbMiniStartIo routine.
StopDevice
Pointer to the miniport driver's SmbMiniStopDevice routine.

Comments

The class driver passes this structure in calls to the miniport driver's SmbMiniInitializeMiniport routine.

The miniport driver passes this structure in calls to any of the class driver's routines.


SMB_REGISTER_ALARM

SMB_REGISTER_ALARM provides information required by the SMB class driver to register an alarm notification function.

typedef struct {
  UCHAR  MinAddress;
  UCHAR  MaxAddress;
  SMB_ALARM_NOTIFY  NotifyFunction;
  PVOID  NotifyContext;
} SMB_REGISTER_ALARM, *PSMB_REGISTER_ALARM;

Members

MinAddress
Specifies the lower limit of a range of bus addresses to which the notification function applies.
MaxAddress
Specifies the upper limit of a range of bus addresses to which the notification function applies.
NotifyFunction
Points to a notification function to be called when a miniport driver calls SmbClassAlarm to report an alarm. The function is declared as follows:
VOID
(*SMB_ALARM_NOTIFY) (
    PVOID       Context,
    UCHAR       Address,
    USHORT      Data
    );
Context
Context information passed through from the miniport driver.
Address
Bus address of the device that signaled the alarm.
Data
Alarm data passed through from the miniport driver.
NotifyContext
Points to the context data to be passed to the notification function.

Comments

An SMB miniport driver or the client of a miniport driver passes this structure when it requests alarm notification through the SMB_REGISTER_ALARM_NOTIFY IOCTL.

The values in MinAddress and MaxAddress define a range of bus addresses. If a device within the range signals an alarm, the SMB class driver calls the notification function.

See Also

SMB_REGISTER_ALARM_NOTIFY


SMB_REQUEST

SMB_REQUEST provides information required to perform a specific I/O request on an SMB device.

typedef struct {
  UCHAR  Status;
  UCHAR  Protocol;
  UCHAR  Address;
  UCHAR   Command;
  UCHAR  BlockLength;
  UCHAR  Data[SMB_MAX_DATA_SIZE];
} SMB_REQUEST, *PSMB_REQUEST;

Members

Status
Completion status of the SMB request.
Protocol
Specifies the bus protocol that applies to the current request. Possible values are:

SMB_WRITE_QUICK
SMB_READ_QUICK
SMB_SEND_BYTE
SMB_RECEIVE_BYTE
SMB_WRITE_BYTE
SMB_READ_BYTE
SMB_WRITE_WORD
SMB_READ_WORD
SMB_WRITE_BLOCK
SMB_READ_BLOCK
SMB_PROCESS_CALL

Address
Bus address of the device to which this request applies.
Command
Device-specific command to perform.
BlockLength
Number of bytes of data to which this request applies. This value is input for a write request and output for a read request.
Data
Array of data input or returned by this request.

Comments

Each client of an SMB miniport driver should define command codes that apply to its device.

See Also

SMB_BUS_REQUEST


Introduction to USB Drivers

Universal Serial Bus (USB) drivers support the Windows® Driver Model (WDM) . The following sections explain how to support a USB device on a WDM platform. This is not a general introduction to USB. Driver writers should consult the USB specification for a description of the inner workings of USB. This section includes the following:

System-Supplied USB Drivers

Vendor-Supplied USB Client Drivers

Configuring USB Devices

USB Device I/O

Selective Suspension of USB Devices


System-Supplied USB Drivers

This section describes the WDM architecture of the universal serial bus (USB) driver stack and device object stack.

This section includes:

Supported USB Classes

USB Driver Stack

USB Device Stack

USB Common Class Generic Parent Driver

For a discussion of vendor-supplied USB drivers, see Vendor-Supplied USB Client Drivers.


Supported USB Classes

For certain USB-defined classes of devices, Microsoft provides a class driver that serves as a client driver for all devices in that class. The operating system automatically supports devices in these classes, with no additional driver required.

Currently, Microsoft provides class drivers for the following classes of USB devices:

  • Hub Device Class

    Microsoft provides the hubclass.sys driver for managing USB hubs. For more information on the relationship between the hub class driver and the USB stack, see USB Driver Stack. Also for general information on the hub device class, see http://www.microsoft.com/hwdev/usb.

  • Human Interface Device (HID) Class

    Microsoft provides the hidclass.sys driver for managing HID-compliant input devices. For information on the Windows input architecture, see Windows Input Architecture for further information. For further information on Windows support for input hardware, see http://www.microsoft.com/hwdev/input.

  • Audio Class

    Microsoft provides audio class support by means of the sysaudio.sys driver. For further information on sysaudio.sys, see Kernel-Mode WDM Audio Components. For further information on Windows audio support, see http://www.microsoft.com/hwdev/audio.

  • Mass Storage Class

    Microsoft provides the usbstor.sys port driver that makes it possible to manage USB mass storage devices with Microsoft's native storage class drivers. For an example device stack that is managed by this driver, see Device Object Example for a USB Mass Storage Device. For further information on Windows storage support, see http://www.microsoft.com/hwdev/storage.

  • Printer Class

    Microsoft provides the usbprint.sys class driver that manages USB printers. For information on implementation of the printer class in Windows, see http://www.microsoft.com/hwdev/print.

  • Communications Device Class

    Microsoft implements the USB Communication Device Class Abstract Control Model by means of the Remote NDIS facility in all Windows platforms containing full-featured USB support. This facility centers the management of all 802-style network cards in a single class driver, mdismp.sys. For a detailed discussion of remote NDIS, see Overview of Remote NDIS. Mapping of remote NDIS to USB is implemented in the usb8023.sys driver. For further information on networking support in Windows, see http://www.microsoft.com/hwdev/network.

  • Content Security Class

    Microsoft does not currently supply a single class driver that implements content security. However, some content security functionality is implemented within the composite client generic parent driver. See Content Security Features in the Composite Client Generic Parent Driver for further details.

Hardware vendors should not write drivers for these device classes.


USB Driver Stack

The following sections describe the USB driver stack:

Windows 2000 USB Driver Stack

Windows XP USB Driver Stack


Windows 2000 USB Driver Stack

The following figure illustrates the WDM driver stack that is created in Microsoft® Windows® 2000 for a USB device with a single interface.

Windows 2000 USB Driver Stack

  1. At the bottom of the Windows 2000 USB driver stack is the host controller driver. It consists of a class/miniclass driver pair. The host controller class driver, usbd.sys, is paired either with the openhci.sys (Open Host Controller Interface) minidriver or with the uhcd.sys (Universal Host Controller Driver) minidriver, depending on which USB protocol the system is configured to use. The host controller class driver handles those aspects of the port driver's duties that are independent of the specific protocol.
  2. Immediately above the host controller class driver is the USB bus driver, usbhub.sys, also known as the hub driver. This is the device driver for each hub on the system.
  3. Above the hub driver sits the client device driver. This might be a vendor-supplied device driver or it might be a system-supplied driver or driver stack. For instance, most USB input devices are managed by a system-supplied HID class/miniclass driver pair (hidclass.sys and hidusb.sys) that sits on top of the USB stack. For more information on the HID driver stack, see Driver Stacks for HID Devices. In the case of composite devices, the hub driver not only drives the hub, but will also provide a generic parent facility between the hub and the various interfaces of the device. For an example of the device stack for a composite device in WIndows 2000, see Windows 2000 USB Device Stack.


Windows XP USB Driver Stack

The following figure illustrates the WDM driver stack that is created in Windows XP for two USB devices, one composite and one non-composite. The composite device has two interfaces, each of which is driven by a separate client driver.

Windows XP USB Driver Stack

There are two significant differences between the Windows 2000 and Windows XP USB driver stacks.

First, the USB device stack for Windows XP is designed to facilitate the addition of a USB 2.0 miniport driver, usbehci.sys, that Microsoft has developed for the purpose of supporting high-speed USB 2.0 technology. This miniport driver is not included with the initial release of Windows XP, but Microsoft will make it available in the future by other distribution methods. Furthermore, Microsoft plans to redesign the Windows 2000 USB stack along lines similar to the design of the Windows XP USB stack and backpropagate USB 2.0 support to Windows 2000.

The second significant change in the USB stack is that, for Windows XP, Microsoft supplies a separate generic parent driver for the support of composite USB devices. In Windows 2000, support for composite devices was built into the system-supplied USB bus (or hub) driver. Additionally, with the Windows XP generic parent driver, Microsoft provides USB Content Security Class functionality for the first time. See USB Common Class Generic Parent Driver for a discussion of this driver.

  1. At the bottom of the Windows XP USB driver stack is the host controller driver. It consists of the port driver, usbport.sys, and one or more of three miniport drivers that run concurrently. When the system detects host controller hardware, it loads one of these miniport drivers. The miniport driver, once loaded, loads the port driver, usbport.sys. The port driver handles those aspects of the host controller driver's duties that are independent of the specific protocol.

    The usbuhci.sys (universal host controller interface) miniport driver replaces the uhcd.sys miniclass driver that shipped with Windows 2000. The usbohci.sys (open host controller interface) miniport driver replaces openhci.sys. See Windows 2000 USB Driver Stack for further information about the Windows 2000 miniclass drivers. In the future, the usbehci.sys miniport driver will be provided to support hi-speed USB devices.

    Once USB 2.0 support is in place, Windows will support host controller cards with both USB 1.1 and USB 2.0 host controllers on board. On detecting this kind of hardware, Windows will create two separate device objects, one for each host controller. After that, Windows will load the usbehci.sys miniport driver for the USB 2.0-compliant host controller hardware and either usbohci.sys or openhci.sys for the USB 1.1-compliant hardware, depending on the system configuration.

  2. Above the port driver is the USB bus driver, usbhub.sys, also known as the hub driver. This is the device driver for each hub on the system.
  3. Each particular device is supported by a USB client driver. Client device drivers for non-composite devices are layered directly above the hub driver. For composite USB devices that expose multiple interfaces and which do not have their own parent class driver, the system loads an extra driver called the USB common class generic parent driver, usbccgp.sys, between the hub driver and the client device drivers. The system assigns each interface of a composite device a separate PDO, and vendors might choose to provide a separate client driver for each interface.
  4. In the case of composite devices, client device drivers are loaded above the generic parent driver. A client driver for a composite device is no different from a client driver for a non-composite devices, except for where it is loaded in the driver stack. Client drivers for composite devices sit above the generic parent driver.


USB Device Stack

The following sections describe the USB device stack:

Windows 2000 USB Device Stack

Windows XP USB Device Stack


Windows 2000 USB Device Stack

The following figure illustrates the WDM device object stack that is created in Microsoft® Windows® 2000 for a composite USB device containing both a keyboard interface and a power keys interface.

Windows 2000 USB Device Stack

Starting from the bottom of the figure, the following describes each device object or device object stack and its associated driver:

  1. The PCI bus driver enumerates the USB host controllers in the system and creates a PDO for each one. Windows 2000 supports only USB 1.1-compliant host controller hardware. The system loads the host controller class/miniclass driver pair, usbd.sys, and either uhcd.sys or openhci.sys. The host controller driver pair then creates an FDO for the host controller.
  2. The host controller class/miniclass driver pair enumerates the root USB hub. The usbhub.sys driver enumerates all other USB hubs, creating both a PDO and an FDO for each hub. The figure only shows one level of hub device objects, but USB allows daisy-chaining of hub devices, so there could potentially be many more hub device objects in the tree. In this example, the hub driver detects and enumerates the USB composite keyboard device and creates a PDO for it.
  3. In Windows 2000, a generic parent facility is provided with the USB bus (or hub) driver. The hub driver detects that the device is a composite device. After creating a PDO for the device as a whole, the hub driver creates an FDO for the entire composite device upon which it can create separate PDOs for each interface of the device. In Windows XP and Windows Me and later versions of the operating system, these actions are performed by a separate generic parent driver. See Windows XP USB Device Stack for details.
  4. In the example illustrated in the figure, the composite device consists of a HID-compliant keyboard interface and a HID-compliant power keys interface. The hub driver creates a separate PDO for each interface. Then, the HID class driver creates an FDO for each interface.


Windows XP USB Device Stack

The following figure illustrates the WDM device object stack that is created in Windows XP and later operating systems for a composite USB device containing both a keyboard interface and a power keys interface.

Windows XP USB Device Stack

Starting from the bottom of the figure, the following describes each device object or device object stack and its associated driver:

  1. The PCI bus driver enumerates the USB host controllers in the system and creates a PDO for each one. Once USB 2.0 support is available, Windows XP will be able to enumerate both USB 2.0-compliant and USB 1.1-compliant hardware. If both sorts of controller are present on the same controller card, the PCI bus driver creates two separate PDOs, one for each controller. Only one PDO is shown in the figure. After creating a PDO for the host controller, the system loads the port driver, usbport.sys, and its accompanying miniports (not shown in the figure). The port driver then creates an FDO for the host controller.
  2. The port driver enumerates the root hub. The usbhub.sys driver enumerates all other USB hubs. The figure only shows one level of hub device objects, but USB allows daisy-chaining of hub devices, so there could potentially be many more hub device objects in the tree. The hub driver detects and enumerates the USB composite keyboard device and creates a PDO for it.
  3. In Windows XP and later versions of the operating system, the generic parent facility is implemented by a separate driver called the USB composite client generic parent driver. For a detailed discussion of this driver, see USB Common Class Generic Parent Driver. When the system detects a composite device, it loads the generic parent driver, which creates an FDO for the device as a whole. Afterwards, the generic parent driver creates separate PDOs for each interface of the composite device. In Windows 2000, these actions were performed by the hub driver. See Windows 2000 USB Device Stack for more details.
  4. In the example illustrated in the figure, the composite device consists of a HID-compliant keyboard interface and a HID-compliant power keys interface. The hub driver creates a separate PDO for each interface,. After that, the HID class driver creates an FDO for each interface.


USB Common Class Generic Parent Driver

Many USB devices expose multiple USB interfaces. In USB terminology, these devices are called composite devices. Microsoft® Windows® 2000 and Windows 98 operating systems include a generic parent facility in the USB bus driver (usbhub.sys) that exposes each interface of the composite device as a separate device. In Microsoft® Windows® XP and Windows Me, this facility is streamlined and improved by transferring it to an independent driver called the USB common class generic parent driver (usbccgp.sys). Using the generic parent facility, device vendors can make selective use of Microsoft-supplied driver support for some interfaces. The following sections describe the generic parent facility in greater detail:

Software Representation of Interfaces for Composite USB Devices

Installation Issues for Composite USB Devices

Content Security Features in the Composite Client Generic Parent Driver


Software Representation of Interfaces for Composite USB Devices

As described by the USB specification, every USB device provides a set of hierarchical descriptors that define its functionality. At the top level, each device has one or more USB configuration descriptors, each of which has one or more interface descriptors. For further information on USB configuration descriptors see USB Configuration Descriptors. Configurations are mutually exclusive, so only one configuration can be selected to operate at a time. Microsoft-supplied drivers only select configuration 1. Within a configuration, interfaces may be used independently. Thus a composite USB device managed by a Microsoft-supplied driver is one that has multiple interfaces within configuration 1. Each interface is represented, at the descriptor level, by a unique value in its bInterfaceNumber member of the USB_INTERFACE_DESCRIPTOR structure.

The function of an interface is indicated by the bInterfaceClass, bInterfaceSubClass, and bInterfaceProtocol members of the same structure, along with the class-specific descriptors which might follow it. Most often, the interfaces of a composite device operate independently. For example, a composite USB keyboard with power buttons may have one interface for the keyboard and another interface for the power buttons. In this case, Windows uses the USB generic parent driver to make each interface appear as a separate device. The keyboard interface can then be managed by the Microsoft-supplied keyboard driver and the power keys interface by the Microsoft-supplied power keys driver, independently of one another.

The generic parent driver can simplify the task of vendors of composite hardware, if Microsoft-supplied drivers support for some interfaces but not others. Vendors of such devices need only supply drivers for the unsupported interfaces, because the generic parent driver facilitates the use of Microsoft-supplied drivers for the supported interfaces.


Installation Issues for Composite USB Devices

The following sections describe the Plug and Play (PnP) considerations associated with composite USB devices:

Loading Client Drivers for Interfaces of Composite Devices

Driver Loading Issues in NT-based Operating Systems


Loading Client Drivers for Interfaces of Composite Devices

When a new USB composite device is plugged into a Microsoft® Windows® machine, the USB hub driver generates a PnP event for a new device object with device ID of USB\VID_xxxx&PID_yyyy (xxxx and yyyy are taken directly from idVendor and idProduct fields of the device descriptor, respectively). The device object also has a set of compatible IDs that include USB\COMPOSITE. Windows then searches the INF files in the inf subdirectory of the Windows installation (and, possibly, a vendor-provided floppy disk) for a match. If the device ID is matched, Windows loads the single driver indicated by the installation script and the generic parent driver does not come into play. If no device ID match is found, Windows uses a compatible ID, for which it loads the USB generic parent driver .

Suppose, the composite device has three interfaces. The generic parent driver is loaded for a three-interface composite USB device whose primary device ID is USB\VID_xxxx&PID_yyyy&Rev_zzzz. The generic parent driver then generates three PnP events for three new device objects with device IDs in the USB\VID_xxxx&PID_yyyy&MI_zz format, where zz is taken from the bInterfaceNumber member of the corresponding interface descriptor. Each device object also has three compatible IDs in the form of USB\Class_ii&SubClass_jj&Prot_kk, USB\Class_ii&SubClass_jj, and USB\Class_ii, where ii, jj, and kk, are taken directly from the bInterfaceClass, bInterfaceSubClass, and bInterfaceProtocol fields of the corresponding interface descriptor structure USB_INTERFACE_DESCRIPTOR. For each new device object, Windows searches the INF files for a device ID or compatible ID match and loads the appropriate driver accordingly, just as it did for the original device object.

The generic parent driver then multiplexes the data flow from each client driver, combining these separate interactions into a single data stream for the driver of composite device. The generic parent deals with all synchronization, PnP, and power management issues.

Suppose the device has interfaces numbered 0, 1, and 2, and interfaces 0 and 1 are of a class that is supported in Windows-supplied drivers, but interface 2 requires special support by the vendor's driver. The vendor should ship a floppy disk with a driver for interface 2 and an INF file. The INF file should have an INF DDInstall section for a hardware ID that matches the device ID USB\VID_xxxx&PID_yyyy&Rev_zzzz&MI_02. The INF must not match USB\VID_xxxx&PID_yyyy, the device ID for the device itself, since this will prevent the generic parent driver from loading.


Driver Loading Issues in NT-Based Operating Systems

There is an important distinction between the way drivers are loaded in Microsoft® Windows® 98 and Windows® Me on the one hand and the way they are loaded in Windows 2000 and later operating systems on the other. Vendors who ship a third-party driver on a floppy disk should make note of this distinction. The distinction arises when the end user plugs in a device whose compatible ID is matched in Windows-supplied INF files, but whose device ID is not. (This is precisely the case for a new composite device, as the device ID is not matched, but the USB\COMPOSITE compatible ID is.)

In this case, Windows 98 opens a dialog window and allows the user to provide a floppy disk from the vendor. If the floppy disk contains an INF that matches the device ID of the device, Windows loads the vendor's driver according to the vendor's INF. In the same scenario, however, Windows 2000 and later operating systems do not give the user a chance to provide a vendor-supplied floppy disk. These operating systems just install a driver according to the compatible ID that is matched in the Microsoft-supplied INF files.

For example, suppose a vendor ships a new USB composite device, and its device ID is not matched in the native INF files. Suppose also that the vendor decides to provide a single driver for all the interfaces and not use the generic parent driver. The vendor ships the driver, along with an INF file that matches USB\VID_xxxx&PID_yyyy, the device ID of the device. When the user plugs the device into a machine with an NT-based operating system, the generic parent driver loads automatically, and the user does not have a chance to provide the vendor floppy disk. The generic parent driver then enumerates device objects for the interfaces and, since there is no match for either the device ID or compatible IDs anywhere, no drivers are loaded for these devices, and they appear as Unknown devices in the device manager.

To avoid this problem if not using the generic parent driver, vendors must provide an installation CD with an Autorun.inf file that points to a setup application. The setup application should call UpdateDriverForPlugAndPlayDevices with the device ID and a path to the relevant INF file.

This problem will not occur if the vendor writes interface drivers that work together with the generic parent facility. In that case, the generic parent facility (either usbhub.sys or usbccgp.sys) creates a separate device object for each interface, the vendor's INF matches the device IDs for only the interfaces for which the vendor provides third-party support, and the remaining interfaces are supported by Microsoft-supplied drivers.

Because of the scenario just described, vendors are encouraged to use the generic parent driver whenever the interfaces of the composite USB device are sufficiently independent of one another to allow it.


Content Security Features in the Composite Client Generic Parent Driver

Digital Rights Management (DRM) systems often make use of device serial numbers to ensure that legitimate customers have access to digitized intellectual property. If a USB device has a CSM-1 content security interface, a client driver can query for its serial number by sending an IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER request to the generic parent driver.


Vendor-Supplied USB Client Drivers

The following sections discuss the guidelines for the development and installation of vendor-supplied universal serial bus (USB) client device drivers:

Installing USB Client Drivers

Sample USB Client Drivers

Managing URBs


Installing USB Client Drivers

This section provides installation information, specific to USB client drivers in Microsoft® Windows® XP and later versions of the operating system.

Vendors supplying their own USB client driver should make that driver a member of the USB setup class in the INF Version Section of the driver's INF file. For example:

[version]
Signature="$WINDOWS NT$"
Class=USB
ClassGuid={36FC9E60-C465-11CF-8056-444553540000}

There are no other special requirements associated with installing USB client drivers.

For a list of USB hardware with native support in Windows 2000 and later, see the system-supplied INF files associated with each USB class. For example, see usbprint.inf for the USB printer class, usbstor.inf for the USB mass storage class, and input.inf for the USB HID class.

For general information on device installation in Windows 2000 and later versions of the operating system, see Device Installation Overview.


Sample USB Client Drivers

This section identifies the sample USB client drivers included with the Microsoft® Windows® DDK.

The Windows DDK includes the source code for the following drivers in the USB section of the \src\wdm directory tree of the Windows DDK:

  • Isochronous client driver sample (isousb.sys)
  • Bulk transfer client driver sample (bulkusb.sys)
  • Selective suspend client driver sample (selsusp.sys)


Managing URBs

Client drivers issue requests to their devices through a variable-length data structure known as a USB Request Block (URB). Each URB is submitted for processing to the USB bus driver by sending an IRP_MJ_INTERNAL_DEVICE_CONTROL request down the USB driver stack, with control code IOCTL_INTERNAL_USB_SUBMIT_URB.

Each URB begins with a standard header. The Length member of the header specifies the size, in bytes, of the URB. The Function member, which must be one of the URB_FUNCTION_XXX constants, determines the type of operation requested. The bus driver uses the Status member to return a USB-specific status code.

To build the IOCTL_INTERNAL_USB_SUBMIT_URB request, drivers can use the IoBuildDeviceIoControlRequest routine.


Configuring USB Devices

A Universal Serial Bus (USB) device must be explicitly configured before it can handle I/O. Since a USB device may support multiple configurations, the client driver reads the devices configuration information, parses it, and chooses the appropriate configuration.

USB devices report their configuration information through descriptors. Device descriptors contain information on the device as a whole. Configuration descriptors contain a description of each individual device configuration. String descriptors contain Unicode text strings.

Drivers follow these steps to configure their device:

  1. Read the device descriptor to determine the number of configurations the device supports. See USB Device Descriptors for details.
  2. Request each configuration descriptor from the device.
  3. Choose which configuration to enable. If the driver supports alternate settings for any interfaces of the configuration the driver also chooses which alternate interface to enable.


USB Descriptors

USB supports three top-level descriptors to describe a device. See the following sections for more information:

USB Device Descriptors

USB Configuration Descriptors

USB String Descriptors


USB Device Descriptors

The device descriptor contains information about a USB device as a whole. To obtain the device descriptor, use UsbBuildGetDescriptorRequest to build the USB request block (URB) for the request.

For example, the following call fills in the buffer at pURB with the appropriate URB.

UsbBuildGetDescriptorRequest(
    pURB, // points to the URB to be filled in
    sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST),
    USB_DEVICE_DESCRIPTOR_TYPE,
    0, // this parameter not used for device descriptors
    0, // this parameter not used for device descriptors
    pDescriptor, // points to a USB_DEVICE_DESCRIPTOR
    NULL,
    sizeof(USB_DEVICE_DESCRIPTOR),
    NULL
);

See IOCTL_INTERNAL_USB_SUBMIT_URB for a description of how to submit the URB to the bus driver. Once the bus driver completes the IRP for the request, it returns a USB_DEVICE_DESCRIPTOR in the buffer beginning at pDescriptor.

To determine the number of configurations a device supports, check the bNumConfigurations member of the returned structure.


USB Configuration Descriptors

A configuration of USB device consists of a series of interfaces. Each interface consists of one or more alternate settings, and each alternate setting is made up of a set of endpoints.

An interface, or any of its alternate settings, specifies a class code, subclass, and protocol. Each endpoint of an interface describes a single stream of input or output for the device.

A device that supports the input or output of several different kinds of data has multiple interfaces. A device that supports several streams of the same kind of data, supports multiple endpoints on a single interface.

To obtain all this information from the device, drivers request the device's configuration descriptor. With the device returns the configuration descriptor, it also returns an interface descriptor for each interface or alternate setting, and an endpoint descriptor for each endpoint.

The driver can collect this information in two steps. The driver can issue the request to get the configuration descriptor, and pass a buffer big enough to hold the configuration descriptor alone. From the configuration descriptor, the driver can determine what size buffer is needed to hold all of the configuration information. The driver then issues the same request with the bigger buffer.

The UsbBuildGetDescriptorRequest routine builds the necessary request. The bus driver returns the configuration descriptor in a USB_CONFIGURATION_DESCRIPTOR structure. This structure specifies the total length of configuration information in its wTotalLength member.

A device may support multiple configurations, numbered starting at zero. It reports the number of configurations it supports in its device descriptor. See USB Device Descriptors for details.

The following code demonstrates how to request the configuration information for the i-th configuration:

USB_CONFIGURATION_DESCRIPTOR UCD, *pFullUCD;
UsbBuildGetDescriptorRequest(
    pURB, // points to the URB to be filled in
    sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST),
    USB_CONFIGURATION_DESCRIPTOR_TYPE,
    i, // number of configuration descriptor
    0, // this parameter not used for configuration descriptors
    &UCD, // points to a USB_CONFIGURATION_DESCRIPTOR
    NULL,
    sizeof(USB_DEVICE_DESCRIPTOR),
    NULL
);
pFullUCD = ExAllocatePool(NonPagedPool, UCD.wTotalLength);
UsbBuildGetDescriptorRequest(
    pURB, // points to the URB to be filled in
    sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST),
    USB_CONFIGURATION_DESCRIPTOR_TYPE,
    i, // number of configuration descriptor
    0, // this parameter not used for configuration descriptors
    pFullUCD, // points to a USB_CONFIGURATION_DESCRIPTOR
    NULL,
    UCD.wTotalLength,
    NULL
);

Each interface descriptor is stored in a USB_INTERFACE_DESCRIPTOR structure. The driver returns one interface descriptor for each interface or alternate setting. The zero-based bInterfaceNumber member of USB_INTERFACE_DESCRIPTOR distinguishes interfaces within a configuration. For a given interface the zero-based bAlternateSetting member distinguishes between alternate settings of the interface. Each endpoint descriptor is stored in a USB_ENDPOINT_DESCRIPTOR structure.

When a device reports a configuration, each interface descriptor is followed in memory by all of the endpoint descriptors for the interface and alternate setting. The device returns interface descriptors in order of bInterfaceNumber values and then in order of bAlternateSetting values.

For example, consider a device that supports a configuration with two interfaces, and the first interface supports two alternate settings. The configuration information is laid out in memory as follows:

Example of Configuration Descriptor Layout

The operating system provides a helper function, USBD_ParseConfigurationDescriptorEx, to search for a given interface descriptor within the configuration. The driver provides a starting position within the configuration, and optionally an interface number, an alternate setting, a class, a subclass, or a protocol. The routine returns a pointer to the next matching interface descriptor.

To examine a configuration descriptor for an endpoint or string descriptor, use the USBD_ParseDescriptors routine. The caller provides a starting position within the configuration and a descriptor type, such as USB_STRING_DESCRIPTOR_TYPE or USB_ENDPOINT_DESCRIPTOR_TYPE. The routine returns a pointer to the next matching descriptor.


USB String Descriptors

Device, configuration, and interface descriptors may contain references to string descriptors. String descriptors are referenced by their one-based index number. A string descriptor contains one or more Unicode strings; each string is a translation of the others into another language.

Drivers use UsbBuildGetDescriptorRequest, with DescriptorType = USB_STRING_DESCRIPTOR_TYPE, to build the request to fetch a string descriptor. The Index parameter specifies the index number, and the LanguageID parameter specifies the language ID (the same values are used as in Microsoft® Win32® LANGID values). Drivers can request the special index number of zero to determine which language IDs the device supports. For this special value, the device returns an array of language IDs rather than a Unicode string.

Since the string descriptor consists of variable-length data, the driver must fetch it in two steps. First the driver must issue the request, passing a data buffer large enough to hold the header for a string descriptor, a USB_STRING_DESCRIPTOR structure. The bLength member of USB_STRING_DESCRIPTOR specifies the size in bytes of the entire descriptor. The driver then makes the same request with a data buffer of size bLength.

The following code demonstrates how to request the i-th string descriptor, with language ID langID:

USB_STRING_DESCRIPTOR UCD, *pFullUSD;
UsbBuildGetDescriptorRequest(
    pURB, // points to the URB to be filled in
    sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST),
    USB_STRING_DESCRIPTOR_TYPE,
    i, // index of string descriptor
    langID, // language ID of string.
    &USD, // points to a USB_STRING_DESCRIPTOR.
    NULL,
    sizeof(USB_STRING_DESCRIPTOR),
    NULL
);
pFullUSD = ExAllocatePool(NonPagedPool, UCD.wTotalLength);
UsbBuildGetDescriptorRequest(
    pURB, // points to the URB to be filled in
    sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST),
    USB_STRING_DESCRIPTOR_TYPE,
    i, // index of string descriptor
    langID, // language ID of string
    pFullUSD,
    NULL,
    USD.bLength,
    NULL
);


Selecting the USB Device Configuration

To configure a USB device, the driver chooses which configuration to enable, and within a configuration, which alternate settings of each interface to enable. The driver packages these choices in an URB_FUNCTION_SELECT_CONFIGURATION URB, which it sends to the USB bus driver. The bus driver enables each interface, and sets up a communication channel to each endpoint within the interface. In USB terminology, this connection is known as a pipe. The bus driver returns a handle for the configuration, for each interface, and for each pipe. The device driver uses the configuration handle to change configuration settings, and uses the pipe handles to perform reads and writes on a pipe.

Drivers use the USBD_CreateConfigurationRequestEx routine to build the URB_FUNCTION_SELECT_CONFIGURATION URB. A driver passes an array of USBD_INTERFACE_INFORMATION structures to the routine, which specifies the alternate setting of each interface to enable. The InterfaceDescriptor member of each structure points to the interface descriptor for the alternate setting. Each USBD_INTERFACE_INFORMATION entry contains within it, in its Pipes member, an array USBD_PIPE_INFORMATION structures — one for each endpoint of that particular interface and alternate setting.

To populate the InterfaceDescriptor members of the array, drivers can use the USBD_ParseConfigurationDescriptor support routine. For example, the following code demonstrates how a driver may use the routine to fill the array with pointers to alternate setting zero of each interface.

PUSB_CONFIGURATION_DESCRIPTOR pConfigurationDescriptor;
/* pConfigurationDescriptor points to the descriptor previously
   requested from the driver. */

PUSBD_INTERFACE_INFORMATION pInterfaceInfo;
/* pInterfaceInfo points to an array with
   pConfigurationDescriptor->bNumInterfaces entries. */

PUSB_INTERFACE_DESCRIPTOR pCurrentDescriptor;
LONG InterfaceNumber = 0;

PURB pUrb;

pCurrentDescriptor = pConfigurationDescriptor;

for (InterfaceNumber = 0;
     InterfaceNumber < pConfigurationDescriptor->bNumInterfaces;
     InterfaceNumber++
    )
{
    /* Get the next matching descriptor. Here we implicitly use
       the fact that the interface descriptors are laid out in
       order in memory.
    */
    pCurrentDescriptor = USBD_ParseConfigurationDescriptor(
                            pConfigurationDescriptor,
                            pCurrentDescriptor,
                            InterfaceNumber, // interface number
                            0, // alternate setting
                            -1,
                            -1,
                            -1,
                         );
    pInterfaceInfo[InterfaceNumber] = pCurrentDescriptor;
}
// allocate the URB
pUrb = USBD_CreateConfigurationRequestEx(
           pConfigurationDescriptor,
           pInterfaceInfo
       );

The USBD_CreateConfigurationRequestEx routine allocates the URB for the driver. Within the URB, the routine allocates an USBD_INTERFACE_INFORMATION structure for each interface descriptor the driver specifies. The routine initializes the InterfaceNumber, AlternateSetting, NumberOfPipes, Pipes[i].MaximumTransferSize, and Pipes[i].PipeFlags members.

USBD_CreateConfigurationRequestEx initializes Pipes[i].MaximumTransferSize to the default maximum transfer size for a single URB read/write request. The driver can specify a different maximum transfer size in the Pipes[i].MaximumTransferSize, if it also specifies the USBD_PF_CHANGE_MAX_PACKET flag in Pipes[i].PipeFlags.

Once the bus driver receives the URB, it fills in the rest of the members of each USBD_INTERFACE_INFORMATION structure. In particular, the Pipes array member contains information on each pipe created. For example, the Pipes[i].PipeHandle member contains a handle the driver uses to send read/write requests to the pipe. The Pipes[i].PipeType member specifies the type of transfers the pipe supports.

Within the UrbSelectConfiguration member of the URB, the bus driver returns a handle the driver can use later to select alternate interface settings. To select an alternate setting for an interface, the driver submits an URB_FUNCTION_SELECT_INTERFACE URB. The driver can use the UsbBuildSelectInterfaceRequest routine to build this URB.

To disable the device, the driver creates and submits an URB_FUNCTION_SELECT_CONFIGURATION request with a NULL configuration descriptor. The following code shows how to use the USBD_CreateConfigurationRequestEx routine to allocate the proper URB.

URB Urb;
UsbBuildSelectConfigurationRequest(
  &Urb,
  sizeof(_URB_SELECT_CONFIGURATION),
  NULL
);

The URB_FUNCTION_SELECT_CONFIGURATION and URB_FUNCTION_SELECT_INTERFACE requests can fail if there is insufficient bandwidth to support the isochronous, control, and interrupt endpoints within enabled interfaces. When that happens, the bus driver sets the Status member of the URB header to USBD_STATUS_NO_BANDWIDTH.


USB Device I/O

When the bus driver configures the device, it sets up a pipe to device endpoints. The bus driver returns a USBD_PIPE_INFORMATION structure for the pipe, which contains information about the pipe created. The PipeHandle member contains a pipe handle to use for I/O transactions on that pipe. See USB Configuration Descriptors for a description of Universal Serial Bus (USB) device configuration and obtaining the pipe handles.

USB devices can support different types of pipes. Drivers can determine the pipe type by examining the PipeType member of USBD_PIPE_INFORMATION. The different pipe types require different types of USB request blocks (URBs) to perform I/O transactions, but each structure within the URB union shares certain members: TransferFlags, TransferBuffer, TransferBufferLength, and TransferBufferMDL.

There are type-specific flags in the TransferFlags member that correspond to each URB type.

For all data transfer URBs, the USBD_TRANSFER_DIRECTION_IN flag in TransferFlags specifies the direction of the transfer. Client drivers set the USBD_TRANSFER_DIRECTION_IN flag to read data from the device. Drivers clear this flag to send data to the device.

When reading from the device, the host controller driver signals an error to the device if the device sends it a packet smaller than the maximum size (wMaxPacketSize) indicated in the device's endpoint. To override this default behavior, the client driver sets the USBD_SHORT_TRANSFER_OK flag in TransferFlags, permitting the device to send packets smaller than the maximum. If the device sends a packet larger than the maximum allowed by the endpoint, the system halts the endpoint, but pending or queued IRPs for that endpoint are not automatically retired.

When writing to the device, the host controller driver does not impose the same restrictions on packet size that it imposes when reading from the device. Some devices make frequent transmissions of small quantities of data, and it is impractical to require such devices to restrict their data transmissions to packets of uniform size. Therefore, the USB bus and host controller drivers do not assign any special significance to packets of size less than the endpoint's maximum size during data writes. This allows a client driver to break a large transfer to the device into multiple URBs of any size less than or equal to the maximum, without the USB driver stack inserting zero-length packets between the URBs.

However, for a USB device and its driver to be compliant with the Universal Serial Bus Specification 1.1, they must only transmit packets of maximum size (wMaxPacketSize) and then delimit the end of a data transmission by means of a packet of less than maximum size, or by means of a zero-length packet. For a client driver to be compliant with the USB specification, it must send a zero-length delimiting packet to a device to explicitly terminate a write transfer whenever the transfer's size is an exact multiple of the maximum. The system USB stack will not generate these packets automatically.

Data may be read from or written to either a buffer resident in memory or an MDL. In either case, the driver specifies the size of the buffer in the TransferBufferLength member. The driver provides a resident buffer in the TransferBuffer member and an MDL in the TransferBufferMDL member. Whichever one the driver provides, the other must be NULL.

If an I/O request on a control, interrupt, or bulk pipe fails, the pipe halts. Whenever the pipe halts, the driver must reset the pipe before any further I/O requests on the pipe can be handled. The driver does this by submitting a URB_FUNCTION_SYNC_RESET_PIPE request, with the UrbPipeRequest.PipeHandle member of the URB set to the pipe handle of the halted pipe. Alternatively, the driver can submit a URB_FUNCTION_RESET_PIPE request. This request clears the halt condition on the host side of the pipe, and if the device is stalled, it also clears the stall condition on the device. In order to clear a stall condition without reseting the pipe, the driver must submit a URB_FUNCTION_SYNC_CLEAR_STALL request.

The driver can abort all I/O requests on the pipe with a _URB_PIPE_REQUEST request whose _URB_HEADER parameter has its Function member set to URB_FUNCTION_ABORT_PIPE.

The following sections provide more information about the types of pipes:

USB Bulk and Interrupt Transfer

USB Isochronous Transfer

USB Control Transfer

Selective Suspension of USB Devices


USB Bulk and Interrupt Transfer

USB devices support bulk transfer pipes for data that does not require delivery in a guaranteed amount of time. The USB host controller gives a lower priority to bulk transfer than the other types of transfer.

USB devices use interrupt transfer for small packets of data that arrive asynchronously. Since all I/O is under direct control of the driver, the driver must poll the device at the frequency specified in the Interval member of the USBD_PIPE_INFORMATION structure for the pipe.

Drivers use the UsbBuildInterruptOrBulkTransferRequest routine to build the URB for I/O transactions on bulk or interrupt pipes. See USB Device I/O for a description of the information the driver provides for I/O transactions.


USB Isochronous Transfer

USB devices support isochronous transfer pipes for time-dependent data that does not require guaranteed delivery. The driver submits the URB_FUNCTION_ISOCH_TRANSFER URB to perform I/O on the pipe.

Isochronous transfer is packet-based — the device reads or writes a single packet of data each millisecond frame. Fortunately, the driver can send several consecutive packets with a single URB.

The size of the URB_FUNCTION_ISOCH_TRANSFER URB varies with the number of packets the driver sends. Drivers can use the GET_ISO_URB_SIZE macro to determine the number of bytes to allocate for the URB. The UrbIsochronousTransfer.IsoPacket array member of the URB describes the length and offset of each packet within the buffer specified in the UrbIsochronousTransfer.TransferBuffer or UrbIsochronousTransfer.TransferBufferMDL members.

Here is an example of how to create an URB for a data buffer that can hold ten packets, each sixteen bytes long:

#define NUMBER_OF_PACKETS 10
#define PACKET_SIZE 16

ULONG UrbSize;
PURB pUrb;

UrbSize = GET_ISO_URB_SIZE(NUMBER_OF_PACKETS);
pUrb = (PURB) ExAllocatePool(NonPagedPool, UrbSize);
urb->UrbIsochronousTransfer.Hdr.Length = size;
urb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
urb->PipeHandle = PipeHandle;
        .
        .
        .
urb->UrbIsochronousTransfer.NumberOfPackets = NUMBER_OF_PACKETS;

ULONG i;
for (i = 0; i<NUMBER_OF_PACKETS; i++) {
  urb->UrbIsochronousTransfer.IsoPacket[i].Offset = i*PACKET_SIZE;
  urb->UrbIsochronousTransfer.IsoPacket[i].Length = PACKET_SIZE;
}

The UrbIsochronousTransfer.StartFrame member of the URB specifies the starting USB frame number for the transaction. The driver can use the URB_FUNCTION_GET_CURRENT_FRAME_NUMBER URB to request current frame number.

For the first transaction on the pipe after being opened or reset, the driver can specify the USB_START_ISO_TRANSFER_ASAP flag in UrbIsochronousTransfer.TransferFlags. The bus driver will begin the transaction in the next available frame.


USB Control Transfer

All USB devices support endpoint zero for standard control requests. Devices can support additional endpoints for custom control requests.

For endpoints other than endpoint zero, drivers issue the URB_FUNCTION_CONTROL_TRANSFER URB request. The UrbControlTransfer.SetupPacket member of the URB specifies the initial setup packet for the control request. See the USB specification for the place of this packet in the protocol.

The USB driver stack supports the endpoint zero control requests as follows:

USB Feature Requests

USB devices support feature requests to enable or disable certain Boolean device settings. Drivers use the UsbBuildFeatureRequest support routine to build the URB feature request.

USB Status Requests

USB devices support status requests to get or set the USB-defined status bits of a device, endpoint, or interface. Drivers use the UsbBuildGetStatusRequest to build the URB status request.

Getting or Setting the USB Configuration

See Configuring USB Devices for a description of how to set the USB configuration.

Drivers use the URB_FUNCTION_GET_CONFIGURATION URB to request the current configuration. The driver passes a one-byte buffer in UrbControlGetConfiguration.TransferBuffer, which the bus driver fills in with the current configuration number.

Getting USB Descriptors

See USB Descriptors for a description of how to get USB descriptors.

Getting or Setting USB Interfaces

To select an alternate setting for an interface, the driver submits an URB_FUNCTION_SELECT_INTERFACE URB. The driver can use the UsbBuildSelectInterfaceRequest routine to format this URB. The caller supplies the handle for the current configuration, the interface members, and the new alternate settings.

Drivers use the URB_FUNCTION_GET_CONFIGURATION URB to request the current setting of an interface. The UrbControlGetInterface.Interface member of the URB specifies the interface number to query. The driver passes a one-byte buffer in UrbControlGetInterface.TransferBuffer, which the bus driver fills in with the current alternate setting.

USB Class and Vendor Requests

To submit USB class control requests and vendor endpoint zero control requests, drivers use one of the URB_FUNCTION_CLASS_XXX or URB_FUNCTION_VENDOR_XXX requests. Drivers can use the UsbBuildVendorRequest routine to format the URB.


Selective Suspension of USB Devices

In Microsoft® Windows® XP and later operating systems, the USB core stack supports a feature known as "Selective Suspend." This feature allows a driver to turn off the USB device it controls when the device becomes idle, even while the system itself remains in a fully operational power state (S0). This feature is primarily intended to conserve battery power in laptops. The USB controller, in particular, often uses a lot of battery power, even when there are no devices attached to the system. The Selective Suspend feature allows drivers to idle the host controller, empty USB hubs, including the Root Hub, and the full range of USB devices supported by the operating system.

Selective Suspend is implemented by means of the IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION IOCTL, also known as an "idle request." A function driver whose device is idle must send this IOCTL to notify the USB core stack that its device is ready to be turned off. The USB Root Hub driver, or the USB Generic Parent driver in the case of a composite device, receives the idle request and holds it pending. However, the hub driver does not actually turn off the device. The device's function driver must furnish a callback routine that does this. The callback routine is passed down the stack with the idle request, and either the USB hub driver or the USB Generic Parent driver calls the callback routine once it is safe to turn off the device. The idle request IRP continues to pend until the hub driver receives a request to turn on the device.

If the device supports remote wake up and has no IRP_MN_WAIT_WAKE request pending, the callback routine should submit an IRP_MN_WAIT_WAKE request to the USB core stack before turning off the device. Ideally, however, the function driver should submit a Wait/Wake IRP to the USB driver stack once it becomes clear that this IRP will be required, rather than waiting to do this in the callback routine.

Once suspended, a device can be awakened in one of two ways:

  1. Resumption of signaling occurs for remote wake-capable devices (that is, the Wait/Wake IRP completes successfully). Typically, the device is set to a fully operational power state (D0) by the function driver's Wait/Wake IRP completion routine.
  2. A new open request is initiated by client software.

If the device can be set to a fully operational power state (D0), the hub driver completes the idle request with a status code indicating success. This informs higher-level drivers that the device is no longer idle. If, however, the device is in a nonwake-capable power state, such as D3, or it has been removed or stopped, the hub driver completes the idle request IRP with an appropriate error code.

A function driver may cancel the idle request after it has been made, but must do so before the hub driver calls the callback routine. If the function driver cancels the idle request IRP, the hub driver will complete the IRP with an error code. When a function driver's completion routine detects that the hub driver completed the idle request IRP with an error code other than STATUS_POWER_STATE_INVALID, it should attempt to turn on the device. This should be done because the hub driver does not guarantee that the device is in a powered state whenever it completes an idle request IRP with an error.

When the system is not in the working state, the ACPI bus driver completes all Wait/Wake IRPs; whereas if the system is turned on, the USB controller driver must handle Wait/Wake IRPs for USB devices. For this reason, support for Selective Suspend in the USB core stack is disabled by default in upgrade installations of the operating system. For clean installations, the Selective Suspend feature will be enabled. Selective Suspend is disabled for upgrade installations, because some USB host controller hardware does not support selective suspension of its ports and, therefore, cannot indicate a resumption of signaling unless the entire controller is suspended.

To enable Selective Suspend support for a given Root Hub and its child devices, a user must select the checkbox under the Power Management tab for the USB Root Hub in the Device Manager.. However, function drivers should not try to determine whether selective suspend is enabled before sending idle requests. They should send the requests whenever the device is idle. If Selective Suspend support is not enabled, the hub driver will complete the idle request with an error


I/O Requests for USB Client Drivers

Windows Driver Model (WDM) clients of the Universal Serial Bus (USB) driver stack communicate to the USB driver stack, by submitting an IRP with major code IRP_MJ_INTERNAL_DEVICE_CONTROL, and one of the following minor codes:

IOCTL_INTERNAL_USB_SUBMIT_URB

IOCTL_INTERNAL_USB_GET_PORT_STATUS

IOCTL_INTERNAL_USB_RESET_PORT

IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO

IOCTL_INTERNAL_USB_ENABLE_PORT

IOCTL_INTERNAL_USB_GET_HUB_COUNT

IOCTL_INTERNAL_USB_CYCLE_PORT

IOCTL_INTERNAL_USB_GET_HUB_NAME

IOCTL_INTERNAL_USB_GET_BUS_INFO

IOCTL_INTERNAL_USB_GET_CONTROLLER_NAME

IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION


IOCTL_INTERNAL_USB_SUBMIT_URB

Drivers can use this request to submit an URB to the bus driver.

Input

Parameters.Others.Argument1 points to the URB, a variable-length structure. The UrbHeader.Function member of the URB specifies the URB type, and the UrbHeader.Length member specifies the size in bytes of the URB. The length of URB, as well as the meaning of any additional members depends on the value of UrbHeader.Function. See URB for details.

Output

Parameters.Others.Argument1 points to the URB structure. The UrbHeader.Status contains a USB status code for the requested operation. Any additional output depends on the UrbHeader.Function member of the URB submitted. See URB for details.

I/O Status Block

The lower-level drivers will set Irp->IoStatus.Status to STATUS_SUCCESS if the URB can be successfully processed. Otherwise, the bus driver will set it to the appropriate error condition, such as STATUS_INVALID_PARAMETER, or STATUS_INSUFFICIENT_RESOURCES.

See Also

URB


IOCTL_INTERNAL_USB_RESET_PORT

Drivers can use this request to reset the port associated to a PDO. This IOCTL must be sent at an IRQL of PASSIVE_LEVEL.

Input

None.

Output

None.

I/O Status Block

The bus or port driver sets Irp->IoStatus.Status to STATUS_SUCCESS or the appropriate error status.


IOCTL_INTERNAL_USB_GET_PORT_STATUS

This I/O request queries the status of the PDO. This IOCTL must be sent at IRQL = PASSIVE_LEVEL.

Input

Parameters.Others.Argument1 should be a pointer to a ULONG to be filled in with the port status flags.

Output

Parameters.Others.Argument1 points to a ULONG that has the port status flags filled in. The flags can be one or both of USBD_PORT_ENABLED, USBD_PORT_CONNECTED.

I/O Status Block

The bus or port driver sets Irp->IoStatus.Status to STATUS_SUCCESS or the appropriate error status.


IOCTL_INTERNAL_USB_ENABLE_PORT

This I/O request re-enables the port associated with a PDO. This IOCTL must be sent at IRQL = PASSIVE_LEVEL.

Input

None.

Output

None.

I/O Status Block

The bus or port driver sets Irp->IoStatus.Status to STATUS_SUCCESS or the appropriate error status.

Operation

This request may fail if the device is attached to a hub other than the root hub. In that case, a driver may use IOCTL_INTERNAL_USB_RESET_PORT to re-enable the port.


IOCTL_INTERNAL_USB_GET_HUB_COUNT

This I/O request is used internally by the hub driver. Do not use this request.


IOCTL_INTERNAL_USB_CYCLE_PORT

This I/O request simulates a device unplug and re-plug on the port associated with the PDO. This IOCTL must be sent at an IRQL of PASSIVE_LEVEL.

Input

None.

Output

None.

I/O Status Block

The bus or port driver sets Irp->IoStatus.Status to STATUS_SUCCESS or the appropriate error status.


IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO

This I/O request is used internally by the hub driver. Do not use this request.


IOCTL_INTERNAL_USB_GET_HUB_NAME

Drivers can use this request to get the device name of the USB hub. This IOCTL must be sent at an IRQL of PASSIVE_LEVEL.

Input

Parameters.DeviceIoControl.OutputBufferLength is the length of the buffer (in bytes) passed in the Irp->AssociatedIrp.SystemBuffer field.

Irp->AssociatedIrp.SystemBuffer points to a USB_ROOT_HUB_NAME structure.

Output

Irp->AssociatedIrp.SystemBuffer is filled with the root hub's symbolic name.

I/O Status Block

A lower-level driver sets Irp->IoStatus.Status to STATUS_SUCCESS or the appropriate error status. It will set Irp->IoStatus.Information to number of bytes required to hold the USB_ROOT_HUB_NAME structure. If the request fails, the driver can use this information to resubmit the request with a big enough buffer.

See Also

USB_ROOT_HUB_NAME


IOCTL_INTERNAL_USB_GET_BUS_INFO

This I/O request queries the bus driver for certain bus information. This IOCTL must be sent at IRQL PASSIVE_LEVEL.

Input

Parameters.Others.Argument1 should be a pointer to a PUSB_BUS_NOTIFICATION structure.

Output

Parameters.Others.Argument1 points to a PUSB_BUS_NOTIFICATION structure that has the TotalBandwidth, ConsumedBandwidth, and ControllerNameLength fields filled in.

I/O Status Block

The bus or port driver sets Irp->IoStatus.Status to STATUS_SUCCESS or the appropriate error status.


IOCTL_INTERNAL_USB_GET_CONTROLLER_NAME

This I/O request queries the bus driver for the device name of the USB host controller. This IOCTL must be sent at an IRQL of PASSIVE_LEVEL.

Input

Parameters.Others.Argument1 should be a pointer to a USB_HUB_NAME structure that will be filled in with the name of the host controller.

Parameters.Others.Argument2 should be a ULONG specifying the length of the buffer (in bytes) in Parameters.Others.Argument1.

Output

The bus driver will fill the buffer pointed to by Parameters.Others.Argument2 with the host controller device name. It will be filled only up to the length specified in Parameters.Others.Argument1.

I/O Status Block

The bus or port driver sets Irp->IoStatus.Status to STATUS_SUCCESS or the appropriate error status.

See Also

USB_HUB_NAME


IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION

Drivers use this request to inform the USB bus driver that a device is idle and can be suspended. When sending this IOCTL, caller must furnish a callback routine that does the actual suspension of the device. The USB bus driver will call this routine when it is safe for the device to be powered down. If the device supports remote wake up and has no Wait/Wake IRP already pending, the callback routine should submit a Wait/Wake IRP to the bus driver for the device, before powering it down.

For additional information, see Supporting Devices that Have Wake-Up Capabilities and Selective Suspension of USB Devices.

This IOCTL must be sent at an IRQL of PASSIVE_LEVEL.

Input

Parameters.DeviceIoControl.Type3InputBuffer should be a pointer to a USB_IDLE_CALLBACK_INFO structure. This structure should contain a pointer to the callback routine and a pointer to the callback routine context.

The structure holding the callback information is defined in usbioctl.h as follows:

typedef VOID (*USB_IDLE_CALLBACK)(
    PVOID Context
    );

typedef struct _USB_IDLE_CALLBACK_INFO {
  USB_IDLE_CALLBACK IdleCallback;
  PVOID IdleContext;
} USB_IDLE_CALLBACK_INFO, *PUSB_IDLE_CALLBACK_INFO;

Output

None

I/O Status Block

The bus or port driver sets Irp->IoStatus.Status to STATUS_SUCCESS or the appropriate error status.


USB Client Support Routines

Universal Serial Bus (USB) client drivers can call the following routines on Windows Driver Model (WDM) platforms. These routines assist a client driver in communicating with the USB driver stack.

Routines are described in alphabetical order.


GET_ISO_URB_SIZE

GET_ISO_URB_SIZE returns the number of bytes required to hold an isochronous transfer request.

ULONG
  GET_ISO_URB_SIZE(
    IN ULONG  NumberOfPackets
    );

Parameters

NumberOfPackets
Specifies the number of isochronous transfer packets that will be part of the transfer request.

Return Value

GET_ISO_URB_SIZE returns the number of bytes required to hold a isochronous request with the given NumberOfPackets.

Comments

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL.

See Also

URB, _URB_ISOCH_TRANSFER, USBD_ISO_PACKET_DESCRIPTOR


GET_SELECT_CONFIGURATION_REQUEST_SIZE

GET_SELECT_CONFIGURATION_REQUEST_SIZE returns the number of bytes required to create a select configuration URB.

ULONG
  GET_SELECT_CONFIGURATION_REQUEST_SIZE(
    IN ULONG  TotalInterfaces,
    IN ULONG  TotalPipes
    );

Parameters

TotalInterfaces
Specifies how many interfaces the configuration has.
TotalPipes
Specifies how many endpoints (pipes) the configuration has.

Return Value

GET_SELECT_CONFIGURATION_REQUEST_SIZE returns the number of bytes required to hold a select configuration request with the given number of pipes and interfaces.

Comments

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL.

See Also

URB, UsbBuildSelectConfigurationRequest, USBD_CreateConfigurationRequest


GET_SELECT_INTERFACE_REQUEST_SIZE

GET_SELECT_INTERFACE_REQUEST_SIZE returns the number of bytes required to create a select interface URB.

ULONG
  GET_SELECT_INTERFACE_REQUEST_SIZE(
    IN ULONG  TotalPipes
    );

Parameters

TotalPipes
Specifies the total number of endpoints (pipes) the interface has.

Return Value

GET_SELECT_INTERFACE_REQUEST_SIZE returns the number of bytes required to hold an URB to select a new setting for an interface with the given number of pipes.

Comments

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL.

See Also

URB, UsbBuildSelectInterfaceRequest


GET_USBD_INTERFACE_SIZE

GET_USBD_INTERFACE_SIZE returns the number of bytes required to hold a USBD_INTERFACE_INFORMATION interface descriptor with its associated endpoint descriptors.

ULONG
  GET_USBD_INTERFACE_SIZE(
    IN ULONG  TotalEndpoints
    );

Parameters

TotalEndpoints
Specifies the total number of endpoints (pipes) the interface has.

Return Value

GET_USBD_INTERFACE_SIZE returns the number of bytes required to hold a USBD_INTERFACE_INFORMATION structure describing the interface and a USBD_PIPE_INFORMATION structure for each endpoint in the interface.

Comments

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL.

See Also

USBD_INTERFACE_INFORMATION, USBD_PIPE_INFORMATION


UsbBuildFeatureRequest

UsbBuildFeatureRequest formats an URB with the parameters necessary to request that a feature be turned on or off on a USB device.

VOID
  UsbBuildFeatureRequest(
    IN OUT PURB  Urb,
    IN USHORT  Op,
    IN USHORT  FeatureSelector,
    IN USHORT  Index,
    IN PURB  Link  OPTIONAL
    );

Parameters

Urb
Points to an URB to be formatted as a feature request to a device.
Op
Specifies one of the following operation codes:
URB_FUNCTION_SET_FEATURE_TO_DEVICE
Sets a USB-defined feature, specified by FeatureSelector, on a device.
URB_FUNCTION_SET_FEATURE_TO_INTERFACE
Sets a USB-defined feature, specified by FeatureSelector, on an interface for a device.
URB_FUNCTION_SET_FEATURE_TO_ENDPOINT
Sets a USB-defined feature, specified by FeatureSelector, on an endpoint for an interface on a USB device.
URB_FUNCTION_SET_FEATURE_TO_OTHER
Sets a USB-defined feature, specified by FeatureSelector, on a device-defined target on a USB device.
URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE
Clears a USB-defined feature, specified by FeatureSelector, on a device.
URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE
Clears a USB-defined feature, specified by FeatureSelector, on an interface for a device.
URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT
Clears a USB-defined feature, specified by FeatureSelector, on an endpoint, for an interface, on a USB device.
URB_FUNCTION_CLEAR_FEATURE_TO_OTHER
Clears a USB-defined feature, specified by FeatureSelector, on a device defined target on a USB device.
FeatureSelector
Specifies the USB-defined feature code that should be set or cleared on the target as specified by Op.
Index
For a feature request for an endpoint or interface, specifies the index of the endpoint or interface within the configuration descriptor. For the device, this must be zero.
Link
Points to an caller-initialized URB. Link becomes the subsequent URB in a chain of requests with Urb being its predecessor.

Comments

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL.

See Also

URB, _URB_CONTROL_FEATURE_REQUEST


UsbBuildGetDescriptorRequest

UsbBuildGetDescriptorRequest formats an URB with the parameters necessary to obtain descriptor information from the host controller driver (HCD).

VOID
  UsbBuildGetDescriptorRequest(
    IN OUT PURB  Urb,
    IN USHORT  Length,
    IN UCHAR  DescriptorType,
    IN UCHAR  Index,
    IN USHORT  LanguageId,
    IN PVOID  TransferBuffer  OPTIONAL,
    IN PMDL  TransferBufferMDL  OPTIONAL,
    IN ULONG  TransferBufferLength,
    IN PURB  Link  OPTIONAL
    );

Parameters

Urb
Points to an URB to be formatted for a get descriptor request to the HCD. The caller must allocate nonpaged pool for this URB.
Length
Specifies the size, in bytes, of the URB.
DescriptorType
Specifies one of the following values:

USB_DEVICE_DESCRIPTOR_TYPE
USB_CONFIGURATION_DESCRIPTOR_TYPE
USB_STRING_DESCRIPTOR_TYPE

Index
Specifies the device-defined index of the descriptor that is to be retrieved.
LanguageId
Specifies the language ID of the descriptor to be retrieved when USB_STRING_DESCRIPTOR_TYPE is set in DescriptorType. This parameter must be 0 for any other value in DescriptorType.
TransferBuffer
Points to a resident buffer to receive the descriptor data or is NULL if an MDL is supplied in TransferBufferMDL.
TransferBufferMDL
Points to an MDL that describes a resident buffer to receive the descriptor data or is NULL if a buffer is supplied in TransferBuffer.
TransferBufferLength
Specifies the length of the buffer specified in TransferBuffer or described in TransferBufferMDL.
Link
Points to an caller-initialized URB. Link becomes the subsequent URB in a chain of requests with Urb being its predecessor.

Comments

When USB_CONFIGURATION_DESCRIPTOR_TYPE is specified for DescriptorType, all interface, endpoint, class-specific, and vendor-specific descriptors for the configuration also are retrieved. The caller must allocate a buffer large enough to hold all of this information or the data is truncated without error.

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL.

See Also

URB, USB_DEVICE_DESCRIPTOR


UsbBuildGetStatusRequest

UsbBuildGetStatusRequest formats an URB to obtain status from a device, interface, endpoint, or other device-defined target on a USB device.

VOID
  UsbBuildGetStatusRequest(
    IN OUT  Urb,
    IN USHORT  Op,
    IN USHORT  Index,
    IN PVOID  TransferBuffer  OPTIONAL,
    IN PMDL  TransferBufferMDL,
    IN PURB  Link
    );

Parameters

Urb
Points to an URB to be formatted as an status request.
Op
Specifies one of the following values:
URB_FUNCTION_GET_STATUS_FROM_DEVICE
Retrieves status from a USB device.
URB_FUNCTION_GET_STATUS_FROM_INTERFACE
Retrieves status from an interface on a USB device.
URB_FUNCTION_GET_STATUS_FROM_ENDPOINT
Retrieves status from an endpoint for an interface on a USB device.
URB_FUNCTION_GET_STATUS_FROM_OTHER
Retrieves status from a device-defined target on a USB device.
Index
Specifies the device-defined index, returned by a successful configuration request, if the request is for an endpoint or interface. Otherwise, Index must be zero.
TransferBuffer
Points to a resident buffer to receive the status data or is NULL if an MDL is supplied in TransferBufferMDL.
TransferBufferMDL
Points to an MDL that describes a resident buffer to receive the status data or is NULL if a buffer is supplied in TransferBuffer.
Link
Points to an caller-initialized URB. Link becomes the subsequent URB in a chain of requests with Urb being its predecessor.

Comments

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL.

See Also

URB, _URB_CONTROL_GET_STATUS_REQUEST


UsbBuildInterruptOrBulkTransferRequest

UsbBuildInterruptOrBulkTransferRequest formats an URB to send or receive data on a bulk pipe, or to receive data from an interrupt pipe.

VOID
  UsbBuildGetInterruptOrBulkTransferRequest(
    IN OUT PURB  Urb,
    IN USHORT  Length,
    IN USBD_PIPE_HANDLE  PipeHandle,
    IN PVOID  TransferBuffer  OPTIONAL,
    IN PMDL  TransferBufferMDL  OPTIONAL,
    IN ULONG  TransferBufferLength,
    IN ULONG  TransferFlags,
    IN PURB  Link
    );

Parameters

Urb
Points to an URB to be formatted as an interrupt or bulk transfer request.
Length
Specifies the size, in bytes, of the URB.
PipeHandle
Specifies the handle for this pipe returned by the HCD when a configuration was selected.
TransferBuffer
Points to a resident buffer for the transfer or is NULL if an MDL is supplied in TransferBufferMDL. The contents of this buffer depend on the value of TransferFlags. If USBD_TRANSFER_DIRECTION_IN is specified, this buffer will contain data read from the device on return from the HCD. Otherwise, this buffer contains driver-supplied data to be transferred to the device.
TransferBufferMDL
Points to an MDL that describes a resident buffer or is NULL if a buffer is supplied in TransferBuffer. The contents of the buffer depend on the value of TransferFlags. If USBD_TRANSFER_DIRECTION_IN is specified, the described buffer will contain data read from the device on return from the HCD. Otherwise, the buffer contains driver-supplied data to be transferred to the device. The MDL must be allocated from nonpaged pool.
TransferBufferLength
Specifies the length, in bytes, of the buffer specified in TransferBuffer or described in TransferBufferMDL.
TransferFlags
Specifies zero, one, or a combination of the following flags:
USBD_TRANSFER_DIRECTION_IN
Is set to request data from a device. To transfer data to a device, this flag must be clear. The flag must be set if the pipe is an interrupt transfer pipe.
USBD_SHORT_TRANSFER_OK
Can be used if USBD_TRANSFER_DIRECTION_IN is set. If set, directs the HCD not to return an error if a packet is received from the device that is shorter than the maximum packet size for the endpoint. Otherwise, a short request is returns an error condition.
Link
Points to an caller-initialized URB. Link becomes the subsequent URB in a chain of requests with Urb being its predecessor.

Comments

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL.

See Also

URB, USB_DEVICE_DESCRIPTOR


UsbBuildSelectConfigurationRequest

UsbBuildSelectConfigurationRequest formats an URB with the parameters necessary to select a configuration on a USB device.

VOID
  UsbBuildSelectConfigurationRequest(
    IN PURB  Urb,
    IN USHORT  Length,
    IN PUSB_CONFIGURATION_DESCRIPTOR  ConfigurationDescriptor
    );

Parameters

Urb
Points to an URB to be formatted as a select configuration request.
Length
Specifies the size, in bytes, of the URB.
ConfigurationDescriptor
Points to an initialized USB configuration descriptor that identifies the configuration to be set on the device. If NULL, the device will be set into its unconfigured state.

Comments

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL.

See Also

URB, _URB_SELECT_CONFIGURATION, USB_CONFIGURATION_DESCRIPTOR


UsbBuildSelectInterfaceRequest

UsbBuildSelectInterfaceRequest formats an URB with the parameters necessary to select an alternate setting for an interface on a USB device.

VOID
  UsbBuildSelectInterfaceRequest(
    IN PURB  Urb,
    IN USHORT  Length,
    IN USBD_CONFIGURATION_HANDLE  ConfigurationHandle,
    IN UCHAR  InterfaceNumber,
    IN UCHAR  AlternateSetting
    );

Parameters

Urb
Points to an URB that is to be formatted as a select interface request.
Length
Specifies the size, in bytes, of the URB. The URB_FUNCTION_SELECT_INTERFACE URB has a variable length. Clients can use the GET_SELECT_INTERFACE_REQUEST_SIZE macro to determine the URB length.
ConfigurationHandle
Specifies the handle for this interface returned by the HCD when a configuration was selected.
InterfaceNumber
Is the device-defined identifier for this interface specified in the descriptor for this interface.
AlternateSetting
Is the device-defined identifier of the alternate setting that this interface should now use.

Comments

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL.

See Also

URB, _URB_SELECT_INTERFACE


UsbBuildVendorRequest

UsbBuildVendorRequest formats an URB to send a vendor or class-specific command to a USB device, interface, endpoint, or other device-defined target.

VOID
  UsbBuildVendorRequest(
    IN PURB  Urb,
    IN USHORT  Function,
    IN USHORT  Length,
    IN ULONG  TransferFlags,
    IN UCHAR  ReservedBits,
    IN UCHAR  Request,
    IN USHORT  Value,
    IN USHORT  Index,
    IN PVOID  TransferBuffer  OPTIONAL,
    IN PMDL  TransferBufferMDL  OPTIONAL,
    IN ULONG  TransferBufferLength,
    IN PURB  Link  OPTIONAL,
    );

Parameters

Urb
Points to an URB that is to be formatted as a vendor or class request.
Function
Must be set to one of the following values:
URB_FUNCTION_VENDOR_DEVICE
Indicates the URB is a vendor-defined request for a USB device.
URB_FUNCTION_VENDOR_INTERFACE
Indicates the URB is a vendor-defined request for an interface on a USB device.
URB_FUNCTION_VENDOR_ENDPOINT
Indicates the URB is a vendor-defined request for an endpoint, in an interface, on a USB device.
URB_FUNCTION_VENDOR_OTHER
Indicates the URB is a vendor-defined request for a device-defined target.
URB_FUNCTION_CLASS_DEVICE
Indicates the URB is a USB-defined class request for a USB device.
URB_FUNCTION_CLASS_INTERFACE
Indicates the URB is a USB-defined class request for an interface on a USB device.
URB_FUNCTION_CLASS_ENDPOINT
Indicates the URB is a USB-defined class request for an endpoint, in an interface, on a USB device.
URB_FUNCTION_CLASS_OTHER
Indicates the URB is a USB-defined class request for a device-defined target.
Length
Specifies the length, in bytes, of the URB.
TransferFlags
Specifies zero, one, or a combination of the following flags:
USBD_TRANSFER_DIRECTION_IN
Is set to request data from a device. To transfer data to a device, this flag must be clear. The flag must be set if the pipe is an interrupt transfer pipe.
USBD_SHORT_TRANSFER_OK
Can be used if USBD_TRANSFER_DIRECTION_IN is set. If set, directs the HCD not to return an error if a packet is received from the device that is shorter than the maximum packet size for the endpoint. Otherwise, a short request is returns an error condition.
ReservedBits
Specifies a value, from 4 to 31 inclusive, that becomes part of the request type code in the USB-defined setup packet. This value is defined by USB for a class request or the vendor for a vendor request.
Request
Specifies the USB or vendor-defined request code for the device, interface, endpoint, or other device-defined target.
Value
Is a value, specific to Request, that becomes part of the USB-defined setup packet for the target. This value is defined by the creator of the code used in Request.
Index
Specifies the device-defined identifier if the request is for an endpoint, interface, or device-defined target. Otherwise, Index must be 0.
TransferBuffer
Points to a resident buffer for the transfer or is NULL if an MDL is supplied in TransferBufferMDL. The contents of this buffer depend on the value of TransferFlags. If USBD_TRANSFER_DIRECTION_IN is specified, this buffer will contain data read from the device on return from the HCD. Otherwise, this buffer contains driver-supplied data to be transferred to the device.
TransferBufferMDL
Points to an MDL that describes a resident buffer or is NULL if a buffer is supplied in TransferBuffer. The contents of the buffer depend on the value of TransferFlags. If USBD_TRANSFER_DIRECTION_IN is specified, the described buffer will contain data read from the device on return from the HCD. Otherwise, the buffer contains driver-supplied data to be transferred to the device. The MDL must be allocated from nonpaged pool.
TransferBufferLength
Specifies the length, in bytes, of the buffer specified in TransferBuffer or described in TransferBufferMDL.
Link
Points to an caller-initialized URB. Link becomes the subsequent URB in a chain of requests with Urb being its predecessor.

Comments

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL.

See Also

URB, _URB_CONTROL_VENDOR_OR_CLASS_REQUEST


USBD_CreateConfigurationRequest

This routine is exported to support existing driver binaries and is obsolete. Use USBD_CreateConfigurationRequestEx instead.

PURB
  USBD_CreateConfigurationRequest(
    IN PUSB_CONFIGURATION_DESCRIPTOR  ConfigurationDescriptor,
    IN OUT PUSHORT  Siz
    );


USBD_CreateConfigurationRequestEx

USBD_CreateConfigurationRequestEx allocates and formats an URB to select a configuration for a USB device.

PURB
  USBD_CreateConfigurationRequestEx(
    IN PUSB_CONFIGURATION_DESCRIPTOR  ConfigurationDescriptor,
    IN PUSBD_INTERFACE_LIST_ENTRY  InterfaceList
    );

Parameters

ConfigurationDescriptor
Points to a configuration descriptor, that includes all interface, endpoint, vendor, and class-specific descriptors, retrieved from a USB device.
InterfaceList
Points to the first element, in a variable-length array of the following structures, that describes interfaces to be made part of the configuration request:
typedef struct _USBD_INTERFACE_LIST_ENTRY {
    PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
    PUSBD_INTERFACE_INFORMATION Interface;
} USBD_INTERFACE_LIST_ENTRY, *PUSBD_INTERFACE_LIST_ENTRY;

The USBD_INTERFACE_LIST_ENTRY structure has the following members:

InterfaceDescriptor
Points to a interface descriptor returned from the device as part of a configuration descriptor.
Interface
Points to memory containing information about the interface and all of the endpoints associated with that interface.

Return Value

USBD_CreateConfigurationRequestEx returns an URB that can be sent to the host controller driver (HCD) to set the device in a configured state. The routine allocates memory for this URB that the caller must free when finished with the URB.

Comments

If an interface descriptor is returned in a configuration descriptor, but the caller does not include an entry in the array pointed to by InterfaceList, the HCD will ignore that interface and will not initialize the interface.

Before the caller submits the URB returned by this routine, it can override the default settings for the interface(s) or endpoint(s) contained in the interface information structure(s). InterfaceList[x]->Interface, filled in on return from USBD_CreateConfigurationRequestEx, points to a USBD_INTERFACE_INFORMATION structure. This structure contains members that can select alternate interface and endpoint settings at device-configuration time. See USBD_INTERFACE_INFORMATION for details on these members.

After all operations with this URB have been completed, the caller must free the memory allocated by this routine for the URB. Failure to do so will result in a memory leak condition.

Callers of this routine can be running at IRQL <= DISPATCH_LEVEL if the memory pointed to by ConfigurationDescriptor and InterfaceList are allocated from nonpaged pool. Otherwise, callers must be running at IRQL < DISPATCH_LEVEL.

See Also

USBD_INTERFACE_INFORMATION, _URB_SELECT_CONFIGURATION


USBD_GetInterfaceLength

USBD_GetInterfaceLength obtains the length of a given interface descriptor, including the length of all endpoint descriptors contained within the interface.

ULONG
  USBD_GetInterfaceLength(
    IN PUSB_INTERFACE_DESCRIPTOR  InterfaceDescriptor,
    IN PUCHAR  BufferEnd
    );

Parameters

InterfaceDescriptor
Points to a interface descriptor for which to obtain the length.
BufferEnd
Points to the position within a buffer at which to stop searching for the length of the interface and associated endpoints.

Return Value

USBD_GetInterfaceLength returns the length, in bytes, of the interface descriptor and all associated endpoint descriptors contained within the interface.

Comments

Callers can use this routine to obtain the length of an interface and associated endpoints that are contained within another buffer. For example, a caller could specify a location inside of a larger buffer for InterfaceDescriptor and the beginning of a location of another interface descriptor for BufferEnd. This will cause the routine to search only from the beginning of the interface descriptor specified by InterfaceDescriptor until either it finds another interface descriptor or it reaches the position specified by End.

Callers of this routine must be running at IRQL PASSIVE_LEVEL.


USBD_GetUSBDIVersion

USBD_GetUSBDIVersion returns version information about the host controller driver (HCD) that controls the clients USB device.

VOID
  USBD_GetUSBDIVersion(
    OUT PUSBD_VERSION_INFORMATION  VersionInformation
    );

Parameters

VersionInformation
Points to caller-allocated memory for the following structure, that on return from the routine, contains version information about the HCD:
typedef struct _USBD_VERSION_INFORMATION {
    ULONG USBDI_Version;
    ULONG Supported_USB_Version;
} USBD_VERSION_INFORMATION, *PUSBD_VERSION_INFORMATION;

Members

USBDI_Version
Specifies the version, as a binary-coded decimal (BCD) number, of the HCD.
Supported_USB_Version
Specifies the revision, as a BCD number, of the USB specification that this version of the HCD supports.

Comments

Callers of this routine can be running at IRQL <= DISPATCH_LEVEL if the memory for VersionInformation is allocated from nonpaged pool. Otherwise, callers must be running at IRQL < DISPATCH_LEVEL.


USBD_ParseConfigurationDescriptor

This routine is exported to support existing driver binaries and is obsolete. Use USBD_ParseConfigurationDescriptorEx instead.

PUSB_INTERFACE_DESCRIPTOR
  USBD_ParseConfigurationDescriptor(
    IN PUSB_CONFIGURATION_DESCRIPTOR  ConfigurationDescriptor,
    IN UCHAR  InterfaceNumber,
    IN UCHAR  AlternateSetting
    );


USBD_ParseConfigurationDescriptorEx

USBD_ParseConfigurationDescriptorEx searches a given configuration descriptor and returns a pointer to an interface that matches the given search criteria.

PUSB_INTERFACE_DESCRIPTOR
  USBD_ParseConfigurationDescriptorEx(
    IN PUSB_CONFIGURATION_DESCRIPTOR  ConfigurationDescriptor,
    IN PVOID  StartPosition,
    IN LONG  InterfaceNumber,
    IN LONG  AlternateSetting,
    IN LONG  InterfaceClass,
    IN LONG  InterfaceSubClass,
    IN LONG  InterfaceProtocol
    );

Parameters

ConfigurationDescriptor
Points to a USB configuration descriptor that contains the interface for which to search.
StartPosition
Points to the address within the configuration descriptor, provided at ConfigurationDescriptor, to begin searching from. To search from the beginning of the configuration descriptor, the parameters ConfigurationDescriptor and StartPosition must be the same address.
InterfaceNumber
Specifies the device-defined index of the interface to be retrieved. This should be set to -1 if it should not be a search criteria.
AlternateSetting
Specifies the device-defined alternate-setting index of the interface to be retrieved. If the caller does not wish the alternate setting value to be a search criteria, this parameter should be set to -1.
InterfaceClass
Specifies the device- or USB-defined identifier for the interface class of the interface to be retrieved. If the caller does not wish the interface class value to be a search criteria, this parameter should be set to -1.
InterfaceSubClass
Specifies the device- or USB-defined identifier for the interface subclass of the interface to be retrieved. If the caller does not wish the interface subclass value to be a search criteria, this parameter should be set to -1.
InterfaceProtocol
Specifies the device- or USB-defined identifier for the interface protocol of the interface to be retrieved. If the caller does not wish the interface protocol value to be a search criteria, this parameter should be set to -1.

Return Value

USBD_ParseConfigurationDescriptorEx returns a pointer to the first interface descriptor that matches the given search criteria. If no interface matches the search criteria, it returns NULL.

Comments

Callers can specify more than one of the search criteria (InterfaceNumber, AlternateSetting, InterfaceClass, InterfaceSubClass, and InterfaceProtocol) when using this routine to find an interface within a configuration descriptor.

When this routine parses the configuration descriptor looking for the interface descriptor that matches the search criteria, it returns the first match, terminating the search. Callers should specify as many search criteria as are necessary to find the desired interface.

Callers of this routine must be running at IRQL <= DISPATCH_LEVEL.

See Also

USB_CONFIGURATION_DESCRIPTOR


USBD_ParseDescriptors

USBD_ParseDescriptors searches a given configuration descriptor and returns a pointer to the first descriptor that matches the search criteria.

PUSB_COMMON_DESCRIPTOR
  USBD_ParseDescriptors(
    IN PVOID  DescriptorBuffer,
    IN ULONG  TotalLength,
    IN PVOID  StartPosition,
    IN LONG  DescriptorType
    );

Parameters

DescriptorBuffer
Points to a configuration descriptor that contains the descriptor for which to search.
TotalLength
Specifies the size, in bytes, of the buffer pointed to by DescriptorBuffer.
StartPosition
Points to the address within the configuration descriptor, provided at DescriptorBuffer, to begin searching from. To search from the beginning of the configuration descriptor, the parameters DescriptorBuffer and StartPosition must be the same address.
DescriptorType
Specifies the descriptor type code as assigned by USB. The following values are valid for USB-defined descriptor types:
USB_STRING_DESCRIPTOR_TYPE
Specifies that the descriptor being searched for is a string descriptor.
USB_INTERFACE_DESCRIPTOR_TYPE
Specifies that the descriptor being searched for is an interface descriptor.
USB_ENDPOINT_DESCRIPTOR_TYPE
Specifies that the descriptor being searched for is an endpoint descriptor.

Return Value

USBD_ParseDescriptors returns a pointer to the following structure that is the head of the first descriptor that matches the given search criteria, or NULL is returned if no match is found:

    typedef struct _USB_COMMON_DESCRIPTOR {
        UCHAR bLength;
        UCHAR bDescriptorType;
    } USB_COMMON_DESCRIPTOR, *PUSB_COMMON_DESCRIPTOR;

Members

bLength
Specifies the entire length of the descriptor, not this structure.
bDescriptorType
Specifies the descriptor type code, as assigned by USB, for this descriptor.

Comments

This structure is used to hold a portion of a descriptor, so that the caller of USBD_ParseDescriptors can determine the correct structure to use to access the remaining data in the descriptor. Every descriptor type has these fields at the beginning of the data and callers can use the bLength and bDescriptorType members to correctly identify the type of this descriptor.

Comments

When this routine parses the configuration descriptor looking for the descriptor that matches the search criteria, it returns the first match, terminating the search.

Callers of this routine can be running at IRQL <= DISPATCH_LEVEL.


USBD_RegisterHcFilter

USBD_RegisterHcFilter is called by USB bus filter drivers to register their device objects with the host controller driver.

VOID
  USBD_RegisterHcFilter(
    PDEVICE_OBJECT  DeviceObject,
    PDEVICE_OBJECT  FilterDeviceObject
    );

Parameters

DeviceObject
Points to the device object that is the current top of the stack as reported by IoAttachDeviceToDeviceStack.
FilterDeviceObject
Points to the filter device object created by the filter driver for its operations.

Comments

USB bus filter drivers must call this routine after attaching their device object to the device object stack for the host controller driver.

Callers of this routine must be running at IRQL PASSIVE_LEVEL.

See Also

IoAttachDeviceToDeviceStack


USB Structures

This section describes the system-defined structures used by Universal Serial Bus (USB) client drivers on Windows® Driver Model (WDM) platforms. See System Structures for information about system-defined structures that are not described here.

Drivers can use only the members of structures that are described in this section. All undocumented members of these structures are reserved for system use.

Transfer buffers that are members of structures defined in this chapter must be nonpageable memory.

The structures described in this section are listed in alphabetical order.


URB

USB client drivers set up USB request blocks (URB) to send requests to the host controller driver. The URB structure defines a format for all possible commands that can be sent to a USB device.

typedef struct _URB {
  union {
  struct _URB_HEADER  UrbHeader;
  struct _URB_SELECT_INTERFACE  UrbSelectInterface;
  struct _URB_SELECT_CONFIGURATION  UrbSelectConfiguration;
  struct _URB_PIPE_REQUEST  UrbPipeRequest;
  struct _URB_FRAME_LENGTH_CONTROL  UrbFrameLengthControl;
  struct _URB_GET_FRAME_LENGTH  UrbGetFrameLength;
  struct _URB_SET_FRAME_LENGTH  UrbSetFrameLength;
  struct _URB_GET_CURRENT_FRAME_NUMBER  UrbGetCurrentFrameNumber;
  struct _URB_CONTROL_TRANSFER  UrbControlTransfer;
  struct _URB_BULK_OR_INTERRUPT_TRANSFER  UrbBulkOrInterruptTransfer;
  struct _URB_ISOCH_TRANSFER  UrbIsochronousTransfer;
  struct _URB_CONTROL_DESCRIPTOR_REQUEST  UrbControlDescriptorRequest;
  struct _URB_CONTROL_GET_STATUS_REQUEST  UrbControlGetStatusRequest;
  struct _URB_CONTROL_FEATURE_REQUEST  UrbControlFeatureRequest;
  struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST  UrbControlVendorClassRequest;
  struct _URB_CONTROL_GET_INTERFACE_REQUEST  UrbControlGetInterfaceRequest;
  struct _URB_CONTROL_GET_CONFIGURATION_REQUEST  UrbControlGetConfigurationRequest;
  }
} URB, *PURB ;

Members

UrbHeader
Provides basic information about the request being sent to the host controller driver. For further information see _URB_HEADER.
UrbSelectInterface
Defines the format of a select interface command for a USB device. For further information see _URB_SELECT_INTERFACE.
UrbSelectConfiguration
Defines the format of a select configuration command for a USB device. For further information see _URB_SELECT_CONFIGURATION.
UrbPipeRequest
Defines the format for a command to reset a stalled pipe on a USB device. For further information see _URB_PIPE_REQUEST.
UrbFrameLengthControl
Defines the format for a command to take or release control of the frame length on a USB bus. For further information see _URB_FRAME_LENGTH_CONTROL.
UrbGetFrameLength
Defines the format for a command to get the current frame length on a USB bus. For further information see _URB_GET_FRAME_LENGTH.
UrbSetFrameLength
Defines the format for a command to alter the frame length on a USB bus. For further information see _URB_SET_FRAME_LENGTH.
UrbGetCurrentFrameNumber
Defines the format for a command to get the current frame number on a USB bus. For further information see _URB_GET_CURRENT_FRAME_NUMBER.
UrbControlTransfer
Defines the format for a command to transmit or receive data on a control pipe. For further information see _URB_CONTROL_TRANSFER.
UrbBulkOrInterruptTransfer
Defines the format for a command to transmit or receive data on a bulk pipe, or to receive data from an interrupt pipe. For further information see _URB_BULK_OR_INTERRUPT_TRANSFER.
UrbIsochronousTransfer
Defines the format of an isochronous transfer to a USB device. For further information see _URB_ISOCH_TRANSFER.
UrbControlDescriptorRequest
Defines the format for a command to retrieve or set descriptor(s) on a USB device. For further information see _URB_CONTROL_DESCRIPTOR_REQUEST.
UrbControlGetStatusRequest
Defines the format for a command to get status from a device, interface, or endpoint. For further information see _URB_CONTROL_GET_STATUS_REQUEST.
UrbControlFeatureRequest
Defines the format for a command to set or clear USB-defined features on an device, interface, or endpoint. For further information see _URB_CONTROL_FEATURE_REQUEST.
UrbControlVendorClassRequest
Defines the format for a command to send or receive a vendor or class-specific request on a device, interface, endpoint, or other device-defined target. For further information see _URB_CONTROL_VENDOR_OR_CLASS_REQUEST.
UrbControlGetInterfaceRequest
Defines the format for a command to get the current alternate interface setting for a selected interface. For further information see _URB_CONTROL_GET_INTERFACE_REQUEST.
UrbControlGetConfigurationRequest
Defines the format for a command to get the current configuration for a device. For further information see _URB_CONTROL_GET_CONFIGURATION_REQUEST.

Comments

For information on the function codes to set in each structure see _URB_HEADER.

See Also

IOCTL_INTERNAL_USB_SUBMIT_URB


_URB_BULK_OR_INTERRUPT_TRANSFER

USB client drivers set up this structure to transmit or receive data on a bulk pipe, or receive data on an interrupt pipe.

struct _URB_BULK_OR_INTERRUPT_TRANSFER {
  struct _URB_HEADER  Hdr;
  USBD_PIPE_HANDLE  PipeHandle;
  ULONG  TransferFlags;
  ULONG  TransferBufferLength;
  PVOID  TransferBuffer;
  PMDL  TransferBufferMDL;
  struct _URB *UrbLink;
  .
  .
};

Members

Hdr
Specifies the URB header information. Hdr.Function must be URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER, and Hdr.Length must be sizeof(_URB_BULK_OR_INTERRUPT_TRANSFER).
PipeHandle
Specifies the handle for this pipe returned by the host controller driver when a configuration was selected.
TransferFlags
Specifies zero, one, or a combination of the following flags:
USBD_TRANSFER_DIRECTION_IN
Is set to request data from a device. To transfer data to a device, this flag must be clear. The flag must be set if the pipe is an interrupt transfer pipe.
USBD_SHORT_TRANSFER_OK
Can be used if USBD_TRANSFER_DIRECTION_IN is set. If set, directs the host controller driver not to return an error if a packet is received from the device shorter than the maximum packet size for the endpoint. Otherwise, a short request is returns an error condition.
TransferBufferLength
Specifies the length, in bytes, of the buffer specified in TransferBuffer or described in TransferBufferMDL. The host controller driver returns the number of bytes sent to or read from the pipe in this member.
TransferBuffer
Points to a resident buffer for the transfer or is NULL if an MDL is supplied in TransferBufferMDL. The contents of this buffer depend on the value of TransferFlags. If USBD_TRANSFER_DIRECTION_IN is specified this buffer will contain data read from the device on return from the host controller driver. Otherwise, this buffer contains driver-supplied data for transfer to the device.
TransferBufferMDL
Points to an MDL that describes a resident buffer or is NULL if a buffer is supplied in TransferBuffer. The contents of the buffer depend on the value of TransferFlags. If USBD_TRANSFER_DIRECTION_IN is specified, the described buffer will contain data read from the device on return from the host controller driver. Otherwise, the buffer contains driver-supplied data for transfer to the device. This MDL must be allocated from nonpaged pool.
UrbLink
Points to an caller-initialized URB. UrbLink becomes the subsequent URB in a chain of requests with this URB being the predecessor.

Comments

Drivers can use the UsbBuildInterruptOrBulkTransferRequest service routine to format this URB.Buffers specified in TransferBuffer or described in TransferBufferMDL must be nonpageable.

Other fields that are part of this structure, but not described here, should be treated as opaque and considered reserved for system use.

See Also

URB, _URB_HEADER


_URB_CONTROL_DESCRIPTOR_REQUEST

USB client drivers set up this structure to get or set descriptors on a USB device.

struct _URB_CONTROL_DESCRIPTOR_REQUEST {
  struct _URB_HEADER Hdr;
  .
  .
  ULONG  TransferBufferLength ;
  PVOID  TransferBuffer ;
  PMDL  TransferBufferMDL ;
  struct _URB *UrbLink ;
  .
  .
  UCHAR  Index ;
  UCHAR  DescriptorType ;
  USHORT  LanguageId ;
  .
  .
} ;

Members

Hdr
Specifies the URB header information. Hdr.Function must be one of URB_FUNCTION_GET_DESCRIPTOR_FROM_XXX or URB_FUNCTION_SET_DESCRIPTOR_FROM_XXX, and Hdr.Length must be sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST).
TransferBufferLength
Specifies the length, in bytes, of the buffer specified in TransferBuffer or described in TransferBufferMDL. The host controller driver returns the number of bytes sent to or read from the pipe in this member.
TransferBuffer
Points to a resident buffer for the transfer or is NULL if an MDL is supplied in TransferBufferMDL.
TransferBufferMDL
Points to an MDL that describes a resident buffer or is NULL if a buffer is supplied in TransferBuffer.This MDL must be allocated from nonpaged pool.
UrbLink
Points to an caller-initialized URB. UrbLink becomes the subsequent URB in a chain of requests with this URB being the predecessor.
Index
Specifies the device-defined index of the descriptor that is being retrieved or set.
DescriptorType
Indicates what type of descriptor is being retrieved or set. One of the following values must be specified:

USB_DEVICE_DESCRIPTOR_TYPE
USB_CONFIGURATION_DESCRIPTOR_TYPE
USB_STRING_DESCRIPTOR_TYPE

LanguageId
Specifies the language ID of the descriptor to be retrieved when USB_STRING_DESCIPRTOR_TYPE is set in DescriptorType. This member must be set to zero for any other value in DescriptorType.

Comments

Drivers can use the UsbBuildGetDescriptorRequest service routine to format this URB.If the caller passes a buffer too small to hold all of the data, the bus driver truncates the data to fit in the buffer without error.

When the caller requests the device descriptor, the bus driver returns a USB_DEVICE_DESCRIPTOR data structure.

When the caller requests a configuration descriptor, the bus driver returns the configuration descriptor in a USB_CONFIGURATION_DESCRIPTOR structure, followed by the interface and endpoint descriptors for that configuration. The driver can access the interface and endpoint descriptors as USB_INTERFACE_DESCRIPTOR, and USB_ENDPOINT_DESCRIPTOR structures. The bus driver also returns any class-specific or device-specific descriptors. The system provides the USBD_ParseConfigurationDescriptorEx and USBD_ParseDescriptors service routines to find individual descriptors within the buffer.

When the caller requests a string descriptor, the bus driver returns a USB_STRING_DESCRIPTOR structure. The string itself is found in the variable-length bString member of the string descriptor.

Other fields that are part of this structure, but not described here, should be treated as opaque and considered reserved for system use.

See Also

URB, _URB_HEADER


_URB_CONTROL_FEATURE_REQUEST

USB client drivers set up this structure to set or clear features on a device, interface, or endpoint.

struct _URB_CONTROL_FEATURE_REQUEST {
  struct _URB_HEADER  Hdr;
  .
  .
  struct _URB  *UrbLink ;
  .
  .
  USHORT  FeatureSelector ;
  USHORT  Index ;
  .
  .
} ;

Members

Hdr
Specifies the URB header information. Hdr.Function must be one of URB_FUNCTION_SET_FEATURE_TO_XXX or URB_FUNCTION_CLEAR_FEATURE_TO_XXX, and Hdr.Length must be sizeof(_URB_CONTROL_FEATURE_REQUEST).
UrbLink
Points to an caller-initialized URB. UrbLink becomes the subsequent URB in a chain of requests with this URB being the predecessor.
FeatureSelector
Is the USB-defined feature code to be cleared or set. Using a feature code that is invalid, cannot be set, or cannot be cleared will cause the target to stall.
Index
Specifies the device-defined index, returned by a successful configuration request, if the request is for an endpoint or interface. Otherwise, Index must be zero.

Comments

Drivers can use the UsbBuildFeatureRequest service routine to format this URB.

Other fields that are part of this structure but not described here should be treated as opaque and considered reserved for system use.

See Also

URB, _URB_HEADER


_URB_CONTROL_GET_CONFIGURATION_REQUEST

USB client drivers set up this structure to retrieve the current configuration for a device.

struct _URB_CONTROL_GET_CONFIGURATION_REQUEST {
  struct _URB_HEADER  Hdr;
  .
  .
  ULONG  TransferBufferLength;
  PVOID  TransferBuffer;
  PMDL  TransferBufferMDL;
  struct _URB  *UrbLink;
  .
  .
} ;

Members

Hdr
Specifies the URB header information. Hdr.Function must be URB_FUNCTION_GET_CONFIGURATION, and Hdr.Length must be sizeof(_URB_CONTROL_GET_CONFIGURATION_REQUEST).
TransferBufferLength
Must be 1. This member specifies the length, in bytes, of the buffer specified in TransferBuffer or described in TransferBufferMDL.
TransferBuffer
Points to a resident buffer for the transfer or is NULL if an MDL is supplied in TransferBufferMDL. The bus driver returns a single byte that specifies the index of the current configuration.
TransferBufferMDL
Points to an MDL that describes a resident buffer or is NULL if a buffer is supplied in TransferBuffer. The bus driver returns a single byte that specifies the index of the current configuration. This MDL must be allocated from nonpaged pool.
UrbLink
Points to an caller-initialized URB. UrbLink becomes the subsequent URB in a chain of requests with this URB being the predecessor.

Comments

Other fields that are part of this structure but not described here should be treated as opaque and considered reserved for system use.

See Also

URB, _URB_HEADER


_URB_CONTROL_GET_INTERFACE_REQUEST

USB client drivers set up this structure to retrieve the current alternate interface setting for a interface in the current configuration.

struct _URB_CONTROL_GET_INTERFACE_REQUEST {
  struct _URB_HEADER  Hdr;
  .
  .
  ULONG  TransferBufferLength ;
  PVOID  TransferBuffer ;
  PMDL  TransferBufferMDL ;
  struct _URB  *UrbLink ;
  .
  .
  USHORT  Interface;
  .
  .
} ;

Members

Hdr
Specifies the URB header information. Hdr.Function must be URB_FUNCTION_GET_INTERFACE, and Hdr.Length must be sizeof(_URB_CONTROL_GET_INTERFACE_REQUEST).
TransferBufferLength
Must be 1. This member specifies the length, in bytes, of the buffer specified in TransferBuffer or described in TransferBufferMDL. The host controller driver returns the number of bytes sent to or read from the pipe in this member.
TransferBuffer
Points to a resident buffer for the transfer or is NULL if an MDL is supplied in TransferBufferMDL. The bus driver returns a single byte specifying the index of the current alternate setting for the interface.
TransferBufferMDL
Points to an MDL that describes a resident buffer or is NULL if a buffer is supplied in TransferBuffer. The bus driver returns a single byte specifying the index of the current alternate setting for the interface. This MDL must be allocated from nonpaged pool.
UrbLink
Points to an caller-initialized URB. UrbLink becomes the subsequent URB in a chain of requests with this URB being the predecessor.
Interface
Specifies the device-defined index of the interface descriptor being retrieved.

Comments

Other fields that are part of this structure but not described here should be treated as opaque and considered reserved for system use.

See Also

URB, _URB_HEADER


_URB_CONTROL_GET_STATUS_REQUEST

USB client drivers set up this structure to retrieve status from a device, interface, endpoint, or other device-defined target.

struct _URB_CONTROL_GET_STATUS_REQUEST {
  struct _URB_HEADER  Hdr;
  .
  .
  ULONG  TransferBufferLength ;
  PVOID  TransferBuffer ;
  PMDL  TransferBufferMDL ;
  struct _URB  *UrbLink ;
  .
  .
  USHORT  Index ;
  .
  .
} ;

Members

Hdr
Specifies the URB header information. Hdr.Function must be URB_FUNCTION_GET_STATUS, and Hdr.Length must be sizeof(_URB_CONTROL_GET_STATUS_REQUEST).
TransferBufferLength
Must be 1. This member specifies the length, in bytes, of the buffer specified in TransferBuffer or described in TransferBufferMDL. The host controller driver returns the number of bytes sent to or read from the pipe in this member.
TransferBuffer
Points to a resident buffer for the transfer or is NULL if an MDL is supplied in TransferBufferMDL. The bus driver returns a single byte specifying the index of the current alternate setting for the interface.
TransferBufferMDL
Points to an MDL that describes a resident buffer or is NULL if a buffer is supplied in TransferBuffer. The bus driver returns a single byte specifying the index of the current alternate setting for the interface. This MDL must be allocated from nonpaged pool.
UrbLink
Points to an caller-initialized URB. UrbLink becomes the subsequent URB in a chain of requests with this URB being the predecessor.
Index
Specifies the device-defined index, returned by a successful configuration request, if the request is for an endpoint or interface. Otherwise, Index must be zero.

Comments

Drivers can use the UsbBuildGetStatusRequest service routine to format this URB.

Other fields that are part of this structure but not described here should be treated as opaque and considered reserved for system use.

See Also

URB, _URB_HEADER


_URB_CONTROL_TRANSFER

USB client drivers set up this structure to transfer data to or from a control pipe.

struct _URB_CONTROL_TRANSFER {
  struct _URB_HEADER  Hdr;
  USBD_PIPE_HANDLE  PipeHandle;
  ULONG  TransferFlags;
  ULONG  TransferBufferLength;
  PVOID  TransferBuffer;
  PMD L TransferBufferMDL;
  struct _URB  *UrbLink;
  .
  .
  UCHAR  SetupPacket[8];
} ;

Members

Hdr
Specifies the URB header information. Hdr.Function must be URB_FUNCTION_CONTROL_TRANSFER, and Hdr.Length must be sizeof(_URB_CONTROL_TRANSFER).
PipeHandle
Specifies the handle for this pipe returned by the host controller driver when a configuration was selected.
TransferFlags
Specifies zero, one, or a combination of the following flags:
USBD_TRANSFER_DIRECTION_IN
Is set to request data from a device. To transfer data to a device, this flag must be clear. The flag must be set if the pipe is an interrupt transfer pipe.
USBD_SHORT_TRANSFER_OK
Can be used if USBD_TRANSFER_DIRECTION_IN is set. If set, directs the host controller driver not to return an error if a packet is received from the device shorter than the maximum packet size for the endpoint. Otherwise, a short request is returns an error condition.
TransferBufferLength
Specifies the length, in bytes, of the buffer specified in TransferBuffer or described in TransferBufferMDL. The host controller driver returns the number of bytes sent to or read from the pipe in this member.
TransferBuffer
Points to a resident buffer for the transfer or is NULL if an MDL is supplied in TransferBufferMDL. The contents of this buffer depend on the value of TransferFlags. If USBD_TRANSFER_DIRECTION_IN is specified this buffer will contain data read from the device on return from the host controller driver. Otherwise, this buffer contains driver-supplied data for transfer to the device.
TransferBufferMDL
Points to an MDL that describes a resident buffer or is NULL if a buffer is supplied in TransferBuffer. The contents of the buffer depend on the value of TransferFlags. If USBD_TRANSFER_DIRECTION_IN is specified, the described buffer will contain data read from the device on return from the host controller driver. Otherwise, the buffer contains driver-supplied data for transfer to the device. This MDL must be allocated from nonpaged pool.
UrbLink
Points to an caller-initialized URB. UrbLink becomes the subsequent URB in a chain of requests with this URB being the predecessor.
SetupPacket
Is a USB-defined request setup packet. The format of a USB request setup packet is found in the USB core specification.

Comments

Other fields that are part of this structure but not described here should be treated as opaque and considered reserved for system use.

See Also

URB, _URB_HEADER


_URB_CONTROL_VENDOR_OR_CLASS_REQUEST

USB client drivers set up this structure to issue a vendor or class-specific command to a device, interface, endpoint, or other device-defined target.

struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST {
  struct _URB_HEADER  Hdr;
  .
  .
  ULONG  TransferFlags ;
  ULONG  TransferBufferLength ;
  PVOID  TransferBuffer ;
  PMDL  TransferBufferMDL ;
  struct _URB  *UrbLink ;
  .
  .
  UCHAR  RequestTypeReservedBits;
  UCHAR  Request;
  USHORT  Value;
  USHORT  Index;
  .
  .
};

Members

Hdr
Specifies the URB header information. Hdr.Function must be one of URB_FUNCTION_CLASS_XXX or URB_FUNCTION_VENDOR_XXX GET_STATUS, and Hdr.Length must be sizeof(_URB_CONTROL_VENDOR_OR_CLASS_REQUEST).
TransferFlags
Specifies zero, one, or a combination of the following flags:
USBD_TRANSFER_DIRECTION_IN
Is set to request data from a device. To transfer data to a device, this flag must be clear. The flag must be set if the pipe is an interrupt transfer pipe.
USBD_SHORT_TRANSFER_OK
Can be used if USBD_TRANSFER_DIRECTION_IN is set. If set, directs the host controller driver not to return an error if a packet is received from the device shorter than the maximum packet size for the endpoint. Otherwise, a short request is returns an error condition.
TransferBufferLength
Specifies the length, in bytes, of the buffer specified in TransferBuffer or described in TransferBufferMDL. The host controller driver returns the number of bytes sent to or read from the pipe in this member.
TransferBuffer
Points to a resident buffer for the transfer or is NULL if an MDL is supplied in TransferBufferMDL. The contents of this buffer depend on the value of TransferFlags. If USBD_TRANSFER_DIRECTION_IN is specified this buffer will contain data read from the device on return from the host controller driver. Otherwise, this buffer contains driver-supplied data for transfer to the device.
TransferBufferMDL
Points to an MDL that describes a resident buffer or is NULL if a buffer is supplied in TransferBuffer. The contents of the buffer depend on the value of TransferFlags. If USBD_TRANSFER_DIRECTION_IN is specified, the described buffer will contain data read from the device on return from the host controller driver. Otherwise, the buffer contains driver-supplied data for transfer to the device. This MDL must be allocated from nonpaged pool.
UrbLink
Points to a caller-initialized URB. UrbLink becomes the subsequent URB in a chain of requests with this URB being the predecessor.
RequestTypeReservedBits
Specifies a value, from 4 to 31 inclusive, that becomes part of the request type code in the USB-defined setup packet. This value is defined by USB for a class request or the vendor for a vendor request.
Request
Specifies the USB or vendor-defined request code for the device, interface, endpoint, or other device-defined target.
Value
Is a value, specific to Request, that becomes part of the USB-defined setup packet for the target. This value is defined by the creator of the code used in Request.
Index
Specifies the device-defined index, returned by a successful configuration request, if the request is for an endpoint or interface. Otherwise, Index must be zero.

Comments

Drivers can use the UsbBuildVendorRequest service routine format this URB.

Other fields that are part of this structure but not described here should be treated as opaque and considered to be reserved for system use.

See Also

URB, _URB_HEADER


_URB_FRAME_LENGTH_CONTROL

USB client drivers set up this structure to take or release control of the frame length on the bus.

struct _URB_FRAME_LENGTH_CONTROL {
  struct _URB_HEADER  Hdr;
} ;

Members

Hdr
Specifies the URB header information. Hdr.Function must be either URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL or URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL, and Hdr.Length must be sizeof(_URB_FRAME_LENGTH_CONTROL).

Comments

Only one client can have control of frame length at any time. To take control of the frame length, a driver sets Hdr.Function to URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL. When a client, who has taken control of the frame length, is ready to release control, it must release control it by sending this URB with Hdr.Function set to URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL.

See Also

URB, _URB_HEADER


_URB_GET_CURRENT_FRAME_NUMBER

USB client drivers set up this structure to retrieve the current frame length on the bus.

struct _URB_GET_CURRENT_FRAME_NUMBER {
  struct _URB_HEADER  Hdr;
  ULONG  FrameNumber ;
} ;

Members

Hdr
Specifies the URB header information. Hdr.Function must be URB_FUNCTION_GET_FRAME_LENGTH, and Hdr.Length must be sizeof(_URB_GET_CURRENT_FRAME_NUMBER).
FrameNumber
Contains the current frame number, on the USB bus, on return from the host controller driver.

See Also

URB, _URB_HEADER


_URB_GET_FRAME_LENGTH

USB client drivers set up this structure to retrieve the current frame length on the bus.

struct _URB_GET_FRAME_LENGTH {
  struct _URB_HEADER  Hdr;
  ULONG  FrameLength ;
  ULONG  FrameNumber ;
} ;

Members

Hdr
Specifies the URB header information. Hdr.Function must be URB_FUNCTION_GET_FRAME_LENGTH, and Hdr.Length must be sizeof(_URB_GET_FRAME_LENGTH).
FrameLength
Contains the length of each bus frame in USB-defined bit times.
FrameNumber
Contains the earliest bus frame number that the frame length can be altered on return from the host controller driver.

Comments

Client drivers must request and be granted sole control of frame length on the bus before submitting an URB of this type. Clients can take control of frame length settings by submitting an URB using _URB_FRAME_LENGTH_CONTROL as the data structure.

See Also

URB, _URB_HEADER, _URB_FRAME_LENGTH_CONTROL


_URB_HEADER

USB client drivers set up this structure to provide basic information about the request being sent to the host controller driver.

struct _URB_HEADER {
  USHORT  Length ;
  USHORT  Function ;
  .
  .
  USBD_STATUS  Status ;
  .
  .
} ;

Members

Length
Specifies the length, in bytes, of the URB. For URB requests that use data structures other than _URB_HEADER, this member must be set to the length of the entire URB request structure, not the _URB_HEADER size.
Function
Specifies a numeric code indicating the requested operation for this URB. One of the following value must be set:
URB_FUNCTION_SELECT_CONFIGURATION
Indicates to the host controller driver that a configuration is to be selected. If set, the URB is used with _URB_SELECT_CONFIGURATION as the data structure.
URB_FUNCTION_SELECT_INTERFACE
Indicates to the host controller driver that an alternate interface setting is being selected for an interface. If set, the URB is used with _URB_SELECT_INTERFACE as the data structure.
URB_FUNCTION_ABORT_PIPE
Indicates that all outstanding requests for a pipe should be canceled. If set, the URB is used with _URB_PIPE_REQUEST as the data structure.
URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL
Indicates that the client is requesting sole control of the frame length for the USB bus. If set, the URB is used with _URB_FRAME_LENGTH_CONTROL as the data structure.
URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL
Indicates that the client is releasing control of the frame length on the USB bus. If set, the URB is used with _URB_FRAME_LENGTH_CONTROL as the data structure.
URB_FUNCTION_GET_FRAME_LENGTH
Requests the current frame length on the USB bus. If set, the URB is used with _URB_GET_FRAME_LENGTH as the data structure.
URB_FUNCTION_SET_FRAME_LENGTH
Alters the current frame length on the USB bus. If set, the URB is used with _URB_SET_FRAME_LENGTH as the data structure.
URB_FUNCTION_GET_CURRENT_FRAME_NUMBER
Requests the current frame number from the host controller driver. If set, the URB is used with _URB_GET_CURRENT_FRAME_NUMBER as the data structure.
URB_FUNCTION_CONTROL_TRANSFER
Transfers data to or from a control pipe. If set, the URB is used with _URB_CONTROL_TRANSFER as the data structure.
URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Transfers data from a bulk pipe or interrupt pipe or to an bulk pipe. If set, the URB is used with _URB_BULK_OR_INTERRUPT_TRANSFER as the data structure.
URB_FUNCTION_ISOCH_TRANSFER
Transfers data to or from an isochronous pipe. If set, the URB is used with _URB_ISOCH_TRANSFER as the data structure.
URB_FUNCTION_RESET_PIPE
Clears both the halt condition on the host side of the pipe and the stall condition on the endpoint. If set, the URB is used with _URB_PIPE_REQUEST as the data structure.
URB_FUNCTION_SYNC_RESET_PIPE
Clears the halt condition on the host side of a pipe. If set, the URB is used with _URB_PIPE_REQUEST as the data structure.
URB_FUNCTION_SYNC_CLEAR_STALL
Clears the stall condition on the endpoint. If set, the URB is used with _URB_PIPE_REQUEST as the data structure.
URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE
Retrieves the device descriptor from a specific USB device. If set, the URB is used with _URB_CONTROL_DESCRIPTOR_REQUEST as the data structure.
URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT
Retrieves the descriptor from an endpoint on an interface for a USB device. If set, the URB is used with _URB_CONTROL_DESCRIPTOR_REQUEST as the data structure.
URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE
Sets a device descriptor on a device. If set, the URB is used with _URB_CONTROL_DESCRIPTOR_REQUEST as the data structure.
URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT
Sets an endpoint descriptor on an endpoint for an interface. If set, the URB is used with _URB_CONTROL_DESCRIPTOR_REQUEST as the data structure.
URB_FUNCTION_SET_FEATURE_TO_DEVICE
Sets a USB-defined feature on a device. If set, the URB is used with _URB_CONTROL_FEATURE_REQUEST as the data structure.
URB_FUNCTION_SET_FEATURE_TO_INTERFACE
Sets a USB-defined feature on an interface for a device. If set, the URB is used with _URB_CONTROL_FEATURE_REQUEST as the data structure.
URB_FUNCTION_SET_FEATURE_TO_ENDPOINT
Sets a USB-defined feature on an endpoint for an interface on a USB device. If set, the URB is used with _URB_CONTROL_FEATURE_REQUEST as the data structure.
URB_FUNCTION_SET_FEATURE_TO_OTHER
Sets a USB-defined feature on a device-defined target on a USB device. If set, the URB is used with _URB_CONTROL_FEATURE_REQUEST as the data structure.
URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE
Clears a USB-defined feature on a device. If set, the URB is used with _URB_CONTROL_FEATURE_REQUEST as the data structure.
URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE
Clears a USB-defined feature on an interface for a device. If set, the URB is used with _URB_CONTROL_FEATURE_REQUEST as the data structure.
URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT
Clears a USB-defined feature on an endpoint, for an interface, on a USB device. If set, the URB is used with _URB_CONTROL_FEATURE_REQUEST as the data structure.
URB_FUNCTION_CLEAR_FEATURE_TO_OTHER
Clears a USB-defined feature on a device defined target on a USB device. If set, the URB is used with _URB_CONTROL_FEATURE_REQUEST as the data structure.
URB_FUNCTION_GET_STATUS_FROM_DEVICE
Retrieves status from a USB device. If set, the URB is used with _URB_CONTROL_GET_STATUS_REQUEST as the data structure.
URB_FUNCTION_GET_STATUS_FROM_INTERFACE
Retrieves status from an interface on a USB device. If set, the URB is used with _URB_CONTROL_GET_STATUS_REQUEST as the data structure.
URB_FUNCTION_GET_STATUS_FROM_ENDPOINT
Retrieves status from an endpoint for an interface on a USB device. If set, the URB is used with _URB_CONTROL_GET_STATUS_REQUEST as the data structure.
URB_FUNCTION_GET_STATUS_FROM_OTHER
Retrieves status from a device-defined target on a USB device. If set, the URB is used with _URB_CONTROL_GET_STATUS_REQUEST as the data structure.
URB_FUNCTION_VENDOR_DEVICE
Sends a vendor-specific command to a USB device. If set, the URB is used with _URB_CONTROL_VENDOR_OR_CLASS_REQUEST as the data structure.
URB_FUNCTION_VENDOR_INTERFACE
Sends a vendor-specific command for an interface on a USB device. If set, the URB is used with _URB_CONTROL_VENDOR_OR_CLASS_REQUEST as the data structure.
URB_FUNCTION_VENDOR_ENDPOINT
Sends a vendor-specific command for an endpoint on an interface on a USB device. If set, the URB is used with _URB_CONTROL_VENDOR_OR_CLASS_REQUEST as the data structure.
URB_FUNCTION_VENDOR_OTHER
Sends a vendor-specific command to a device-defined target on a USB device. If set, the URB is used with _URB_CONTROL_VENDOR_OR_CLASS_REQUEST as the data structure.
URB_FUNCTION_CLASS_DEVICE
Sends a USB-defined class-specific command to a USB device. If set, the URB is used with _URB_CONTROL_VENDOR_OR_CLASS_REQUEST as the data structure.
URB_FUNCTION_CLASS_INTERFACE
Sends a USB-defined class-specific command to an interface on a USB device. If set, the URB is used with _URB_CONTROL_VENDOR_OR_CLASS_REQUEST as the data structure.
URB_FUNCTION_CLASS_ENDPOINT
Sends a USB-defined class-specific command to an endpoint, on an interface, on a USB device. If set, the URB is used with _URB_CONTROL_VENDOR_OR_CLASS_REQUEST as the data structure.
URB_FUNCTION_CLASS_OTHER
Sends a USB-defined class-specific command to a device defined target on a USB device. If set, the URB is used with _URB_CONTROL_VENDOR_OR_CLASS_REQUEST as the data structure.
URB_FUNCTION_GET_CONFIGURATION
Retrieves the current configuration on a USB device. If set, the URB is used with _URB_CONTROL_GET_CONFIGURATION_REQUEST as the data structure.
URB_FUNCTION_GET_INTERFACE
Retrieves the current settings for an interface on a USB device. If set, the URB is used with _URB_CONTROL_GET_INTERFACE_REQUEST as the data structure.
Status
Contains a USB_STATUS_XXX code on return from the host controller driver.

Comments

The _URB_HEADER structure is a member of all USB requests that are part of the URB structure. The _URB_HEADER structure is used to provide common information about each request to the host controller driver.

Other fields that are part of this structure but not described here should be treated as opaque and considered to be reserved for system use.

See Also

URB, _URB_SELECT_INTERFACE, _URB_SELECT_CONFIGURATION, _URB_PIPE_REQUEST, _URB_FRAME_LENGTH_CONTROL, _URB_GET_FRAME_LENGTH, _URB_SET_FRAME_LENGTH, _URB_GET_CURRENT_FRAME_NUMBER, _URB_CONTROL_TRANSFER, _URB_BULK_OR_INTERRUPT_TRANSFER, _URB_ISOCH_TRANSFER, _URB_CONTROL_DESCRIPTOR_REQUEST, _URB_CONTROL_GET_STATUS_REQUEST, _URB_CONTROL_FEATURE_REQUEST, _URB_CONTROL_VENDOR_OR_CLASS_REQUEST, _URB_CONTROL_GET_INTERFACE_REQUEST, _URB_CONTROL_GET_CONFIGURATION_REQUEST


_URB_ISOCH_TRANSFER

USB client drivers set up this structure to send data to or retrieve data from an isochronous transfer pipe.

struct _URB_ISOCH_TRANSFER {
  struct _URB_HEADER  Hdr;
  USBD_PIPE_HANDLE  PipeHandle;
  ULONG  TransferFlags;
  ULONG  TransferBufferLength;
  PVOID  TransferBuffer;
  PMDL  TransferBufferMDL;
  .
  .
  ULONG  StartFrame;
  ULONG  NumberOfPackets;
  ULONG  ErrorCount;
  USBD_ISO_PACKET_DESCRIPTOR  IsoPacket[1];
};

Members

Hdr
Specifies the URB header information. Hdr.Function must be URB_FUNCTION_ISOCH_TRANSFER, and Hdr.Length must be the size of this variable-length data structure.
PipeHandle
Specifies the handle for this pipe returned by the host controller driver when a configuration was selected.
TransferFlags
Specifies zero, one, or a combination of the following flags:
USBD_TRANSFER_DIRECTION_IN
Is set to request data from a device. To transfer data to a device, this flag must be clear. The flag must be set if the pipe is an interrupt transfer pipe.
USBD_SHORT_TRANSFER_OK
Can be used if USBD_TRANSFER_DIRECTION_IN is set. If set, directs the host controller driver not to return an error if a packet is received from the device shorter than the maximum packet size for the endpoint. Otherwise, a short request is returns an error condition.
USBD_ISO_TRANSFER_ASAP
Causes the transfer to begin on the next frame, if no transfers have been submitted to the pipe since the pipe was opened or last reset. Otherwise, the transfer will begin on the first frame following all currently queued requests for the pipe. The actual frame that the transfer begins on will be adjusted for bus latency by the host controller driver.
TransferBufferLength
Specifies the length, in bytes, of the buffer specified in TransferBuffer or described in TransferBufferMDL. The host controller driver returns the number of bytes sent to or read from the pipe in this member.
TransferBuffer
Points to a resident buffer for the transfer or is NULL if an MDL is supplied in TransferBufferMDL. The contents of this buffer depend on the value of TransferFlags. If USBD_TRANSFER_DIRECTION_IN is specified this buffer will contain data read from the device on return from the host controller driver. Otherwise, this buffer contains driver-supplied data for transfer to the device.
TransferBufferMDL
Points to an MDL that describes a resident buffer or is NULL if a buffer is supplied in TransferBuffer. The contents of the buffer depend on the value of TransferFlags. If USBD_TRANSFER_DIRECTION_IN is specified, the described buffer will contain data read from the device on return from the host controller driver. Otherwise, the buffer contains driver-supplied data for transfer to the device. This MDL must be allocated from nonpaged pool.
StartFrame
Specifies the frame number the transfer should begin on. This variable must be within a system-defined range of the current frame. The range is specified by the constant USBD_ISO_START_FRAME_RANGE.

If START_ISO_TRANSFER_ASAP is set in TransferFlags, this member contains the frame number that the transfer began on, when the request is returned by the host controller driver. Otherwise, this member must contain the frame number that this transfer will begin on.

NumberOfPackets
Specifies the number of packets described by the boundless array member IsoPacket.
ErrorCount
Contains the number of packets that completed with an error condition on return from the host controller driver.
IsoPacket
Contains a variable-length array of USBD_ISO_PACKET_DESCRIPTOR structures that describe each transfer packet of the isochronous transfer.

Comments

Each entry in the IsoPacket member array specifies an offset and a length within the transfer buffer for the request. If IsoPacket has n entries, the host controller transfers use n frames to transfer data, transferring IsoPacket[i].Length bytes beginning at an offset of IsoPacket[i].Offset.

Drivers can use the GET_ISO_URB_SIZE macro to determine the size needed to hold the entire URB.

Other fields that are part of this structure but not described here should be treated as opaque and considered to be reserved for system use.

See Also

URB, _URB_HEADER, USBD_ISO_PACKET_DESCRIPTOR


_URB_PIPE_REQUEST

USB client drivers set up this structure to clear a stall condition on an endpoint.

struct _URB_PIPE_REQUEST {
  struct _URB_HEADER  Hdr;
  USBD_PIPE_HANDLE  PipeHandle ;
} ;

Members

Hdr
Specifies the URB header information. Hdr.Function must be URB_FUNCTION_RESET_PIPE or URB_FUNCTION_ABORT_PIPE, and Hdr.Length must be sizeof(_URB_PIPE_REQUEST).
PipeHandle
Specifies the handle for this pipe returned by the host controller driver when a configuration was selected.

Comments

Other fields that are part of this structure but not described here should be treated as opaque and considered to be reserved for system use.

See Also

URB, _URB_HEADER


_URB_SELECT_CONFIGURATION

USB client drivers set up this structure to select a configuration for a USB device.

struct _USB_SELECT_CONFIGURATION {
  struct _URB_HEADER  Hdr;
  PUSB_CONFIGRUATION_DESCRIPTOR  ConfigurationDescriptor ;
  USB_CONFIGURATION_HANDLE  ConfigurationHandle ;
  USBD_INTERFACE_INFORMATION  Interface ;
} ;

Members

Hdr
Specifies the URB header information. Hdr.Function must be URB_FUNCTION_SELECT_CONFIGURATION, and Hdr.Length must be the size of the entire URB.
ConfigurationDescriptor
Points to an initialized USB configuration descriptor that identifies the configuration to be used on the device. If this member is NULL, the device will be set into an unconfigured state.
ConfigurationHandle
Contains a handle that is used to access this configuration on return from the host controller driver. USB client drivers must treat this member as opaque.
Interface
Specifies a variable length array of USBD_INTERFACE_INFORMATION structures, each describing an interface supported by the configuration being selected.

Before the request is sent to the host controller driver, the driver may select an alternate setting for one or more of the interfaces contained in this array by setting members of the USBD_INTERFACE_INFORMATION structure for that interface.

On return from the host controller driver, this member contains a USBD_INTERFACE_INFORMATION structure with data about the capabilities and format of the endpoints within that interface.

Comments

An URB_FUNCTION_SELECT_CONFIGURATION URB consists of a _URB_SELECT_CONFIGURATION structure followed by a sequence of variable-length USB_INTERFACE_INFORMATION structures. Drivers can use the USBD_CreateConfigurationRequestEx service routine to allocate the URB.

Other fields that are part of this structure but not described here should be treated as opaque and considered to be reserved for system use.

See Also

URB, _URB_HEADER, USBD_INTERFACE_INFORMATION


_URB_SELECT_INTERFACE

USB client drivers set up this structure to select an alternate setting for a interface in the current configuration on a USB device.

struct _URB_SELECT_INTERFACE {
  struct _URB_HEADER  Hdr;
  USBD_CONFIGURATION_HANDLE  ConfigurationHandle ;
  USBD_INTERFACE_INFORMATION  Interface ;
} ;

Members

Hdr
Specifies the URB header information. Hdr.Function must be URB_FUNCTION_SELECT_INTERFACE, and Hdr.Length must be the size of the entire URB.
ConfigurationHandle
Specifies the handle for the configuration that this interface belongs to, returned by the host controller driver when a configuration was selected.
Interface
A variable-length structure that specifies the interface and the new alternate setting for that interface. See USBD_INTERFACE_INFORMATION for information on the members that are used to control those settings. On successful completion of processing this URB, the bus driver returns an array of handles for each pipe on this interface in the Interface.Pipes array member.

Comments

Drivers can use the GET_SELECT_INTERFACE_REQUEST_SIZE macro to determine the size of this URB, and the UsbBuildSelectInterfaceRequest routine to format the URB.

Other fields that are part of this structure but not described here should be treated as opaque and considered to be reserved for system use.

See Also

URB, _URB_HEADER, USBD_INTERFACE_INFORMATION


_URB_SET_FRAME_LENGTH

USB client drivers set up this structure to change the frame length on the bus.

struct _URB_SET_FRAME_LENGTH {
  struct _URB_HEADER  Hdr;
  LONG FrameLengthDelta;
} ;

Members

Hdr
Specifies the URB header information. Hdr.Function must be URB_FUNCTION_SET_FRAME_LENGTH, and Hdr.Length must be sizeof(_URB_SET_FRAME_LENGTH).
FrameLengthDelta
Specifies the number of USB-defined bit times to be added or subtracted from the current frame length. The maximum increase or decrease per URB is one.

Comments

Sending this request to the host controller driver before being granted control of frame length for the bus will cause an error to be returned. To take control of the frame length, an URB must first be sent with the function, URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL. See _URB_FRAME_LENGTH_CONTROL for the data structure used to obtain or release control of frame length on the bus.

See Also

URB, _URB_HEADER, _URB_FRAME_LENGTH_CONTROL


USB_BUS_INFORMATION_LEVEL_0

The QueryBusInformation function reports its output data in the USB_BUS_INFORMATION_LEVEL_0 structure if the caller sets its Level parameter to zero. This structure is available in Windows XP and later operating systems. For more information see Interface for Direct Client Access to USB Bus.

typedef struct _USB_BUS_INFORMATION_LEVEL_0 {
  ULONG  TotalBandwidth;
  ULONG  ConsumedBandwidth;
} USB_BUS_INFORMATION_LEVEL_0, *PUSB_BUS_INFORMATION_LEVEL_0;

Members

TotalBandwidth
Total bandwidth, in bits per second, available on the bus.
ConsumedBandwidth
Mean bandwidth that is already in use, in bits per second.

Headers

Declared in usbbusif.h. Include usbbusif.h.

See Also

QueryBusInformation


USB_BUS_INFORMATION_LEVEL_1

The QueryBusInformation function reports its output data in the USB_BUS_INFORMATION_LEVEL_1 structure if the caller sets its Level parameter to one. This structure is available in Windows XP and later operating systems. For more information see Interface for Direct Client Access to USB Bus.

typedef struct _USB_BUS_INFORMATION_LEVEL_1 {
  ULONG  TotalBandwidth;
  ULONG  ConsumedBandwidth;
  ULONG  ControllerNameLength;
  WCHAR  ControllerNameUnicodeString[1];
} USB_BUS_INFORMATION_LEVEL_1, *PUSB_BUS_INFORMATION_LEVEL_1;

Members

TotalBandwidth
Total bandwidth, in bits per second, available on the bus.
ConsumedBandwidth
Mean bandwidth already in use, in bits per second.
ControllerNameLength
Length of symbolic name for the host controller, in Unicode.
ControllerNameUnicodeString
Symbolic name for the host controller, in Unicode.

Headers

Declared in usbbusif.h. Include usbbusif.h.

See Also

QueryBusInformation


USB_BUS_INTERFACE_USBDI_V0

The USB hub driver makes the USB_BUS_INTERFACE_USBDI_V0 structure available to USB clients, in order to allow them to make direct calls to the hub driver without allocating IRPs.

typedef struct _USB_BUS_INTERFACE_USBDI_V0 {
  USHORT  Size;
  USHORT  Version;
  PVOID  BusContext;
  PINTERFACE_REFERENCE  InterfaceReference;
  PINTERFACE_DEREFERENCE  InterfaceDereference;
  PUSB_BUSIFFN_GETUSBDI_VERSION  GetUSBDIVersion;
  PUSB_BUSIFFN_QUERY_BUS_TIME  QueryBusTime;
  PUSB_BUSIFFN_SUBMIT_ISO_OUT_URB  SubmitIsoOutUrb;
  PUSB_BUSIFFN_QUERY_BUS_INFORMATION  QueryBusInformation;
} USB_BUS_INTERFACE_USBDI_V0, *PUSB_BUS_INTERFACE_USBDI_V0;

Members

Size
Size in bytes of the buffer that holds the interface pointers.
Version
Version of the interface.
BusContext
Device object of the parent USB bus.
InterfaceReference
Pointer to routine that increments the number of references to this interface.
InterfaceDereference
Pointer to method that decrements the number of references to this interface.
GetUSBDIVersion
Returns the USB interface version number, the version number of USB specification that defines the interface, along with host controller capabilities information that indicates whether the host controller supports real time threads. This method returns the highest USBDI interface version supported by the port driver.
QueryBusTime
Returns the current 32-bit USB frame number. This interface method replaces the USBD_QueryBusTime function provided by usbd.sys.
SubmitIsoOutUrb
The SubmitIsoOutUrb function submits a URB directly to the bus driver without requiring the allocation of an IRP. This interface method replaces the USBD_BusSubmitIsoOutUrb function provided by usbd.sys.
QueryBusInformation
Information returned depends on the value of the Level member. If Level is zero, this method returns bus bandwidth information. If Level is one, it returns bus bandwidth information and the host controller's symbolic name. This function replaces the USBD_QueryBusInformation function provided by usbd.sys.

Headers

Declared in usbbusif.h. Include usbbusif.h.

Comments

Callers of the functions in this structure can be running at any IRQL.

See Also

Interface for Direct Client Access to USB Bus, QueryBusInformation, SubmitIsoOutUrb, QueryBusTime, GetUSBDIVersion


USB_BUS_INTERFACE_USBDI_V1

The USB hub driver makes the USB_BUS_INTERFACE_USBDI_V1 structure available to USB clients, in order to allow them to make direct calls to the hub driver without allocating IRPs.

typedef struct _USB_BUS_INTERFACE_USBDI_V1 {
  USHORT  Size;
  USHORT  Version;
  PVOID  BusContext;
  PINTERFACE_REFERENCE  InterfaceReference;
  PINTERFACE_DEREFERENCE  InterfaceDereference;
  PUSB_BUSIFFN_GETUSBDI_VERSION  GetUSBDIVersion;
  PUSB_BUSIFFN_QUERY_BUS_TIME  QueryBusTime;
  PUSB_BUSIFFN_SUBMIT_ISO_OUT_URB  SubmitIsoOutUrb;
  PUSB_BUSIFFN_QUERY_BUS_INFORMATION  QueryBusInformation;
  PUSB_BUSIFFN_IS_DEVICE_HIGH_SPEED IsDeviceHighSpeed;
} USB_BUS_INTERFACE_USBDI_V1, *PUSB_BUS_INTERFACE_USBDI_V1;

Members

Size
Size in bytes of the buffer that holds the interface pointers.
Version
Version of the interface.
BusContext
Device object of the parent USB bus.
InterfaceReference
Pointer to routine that increments the number of references to this interface.
InterfaceDereference
Pointer to method that decrements the number of references to this interface.
GetUSBDIVersion
Returns the USB interface version number, the version number of USB specification that defines the interface, along with host controller capabilities information that indicates whether the host controller supports real time threads. This method returns the highest USBDI interface version supported by the port driver.
QueryBusTime
Returns the current 32-bit USB frame number. This interface method replaces the USBD_QueryBusTime function provided by usbd.sys.
SubmitIsoOutUrb
The SubmitIsoOutUrb function submits a URB directly to the bus driver without requiring the allocation of an IRP. This interface method replaces the USBD_BusSubmitIsoOutUrb function provided by usbd.sys.
QueryBusInformation
Information returned depends on the value of the Level member. If Level is zero, this method returns bus bandwidth information. If Level is one, it returns bus bandwidth information and the host controller's symbolic name. This function replaces the USBD_QueryBusInformation function provided by usbd.sys.
IsDeviceHighSpeed
Returns TRUE if the USB device is operating at high speed, USB 2.0 compliant device. Returns FALSE otherwise.

Headers

Declared in usbbusif.h. Include usbbusif.h.

Comments

This interface is only available in Windows XP and later operating systems.

The IsDeviceHighSpeed member does not indicate whether a device is capable of high speed operation, but rather whether it is in fact operating at high speed.

Functions in this interface must be callable at IRQL >= DISPATCH_LEVEL.

See Also

Interface for Direct Client Access to USB Bus, USB_BUS_INTERFACE_USBDI_V0, QueryBusInformation, SubmitIsoOutUrb, QueryBusTime, GetUSBDIVersion


USB_CONFIGURATION_DESCRIPTOR

USB client drivers use this structure to hold a USB-defined configuration descriptor.

typedef struct _USB_CONFIGURATION_DESCRIPTOR {
  UCHAR  bLength ;
  UCHAR  bDescriptorType ;
  USHORT  wTotalLength ;
  UCHAR  bNumInterfaces ;
  .
  .
  UCHAR  iConfiguration ;
  UCHAR  bmAttributes ;
  UCHAR  MaxPower ;
} USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR ;

Members

bLength
Specifies the length, in bytes, of this structure.
bDescriptorType
Must be set to USB_CONFIGURATION_DESCRIPTOR_TYPE.
wTotalLength
Specifies the total length, in bytes, of all data for the configuration. The length includes all interface, endpoint, class, or vendor-specific descriptors returned with the configuration descriptor.
bNumInterfaces
Specifies the total number of interfaces supported by this configuration.
iConfiguration
Specifies the device-defined index of the string descriptor for this configuration.
bmAttributes
Specifies a bitmap to describe behavior of this configuration. The bits are described and set in little-endian order.
Bit | Meaning
0 - 4 | Reserved.
5 | Is set if this configuration supports remote wakeup.
6 | Is set if this configuration is self-powered and does not use power from the bus.
7 | Is set if this configuration is powered by the bus.

MaxPower
Specifies the power requirements of this device in two mA units. This field is valid only if bit seven is set in bmAttributes.

Comments

If wTotalLength is greater than the buffer size provided in the URB to hold all descriptors (interface, endpoint, class, and vendor-defined) retrieved, incomplete data will be returned. In order to retrieve complete descriptors, the request will need to be re-sent with a larger buffer.

If bmAttributes bits six and seven are both set, then the device is powered both by the bus and a source external to the bus.

Other fields that are part of this structure but not described here should be treated as opaque and considered to be reserved for system use.

See Also

UsbBuildGetDescriptorRequest, USBD_CreateConfigurationRequest


USB_DEVICE_DESCRIPTOR

This structure is used by USB client drivers to hold a USB-defined device descriptor.

typedef struct _USB_DEVICE_DESCRIPTOR {
  UCHAR  bLength ;
  UCHAR  bDescriptorType ;
  USHORT  bcdUSB ;
  UCHAR  bDeviceClass ;
  UCHAR  bDeviceSubClass ;
  UCHAR  bDeviceProtocol ;
  UCHAR  bMaxPacketSize0 ;
  USHORT  idVendor ;
  USHORT  idProduct ;
  USHORT  bcdDevice ;
  UCHAR  iManufacturer ;
  UCHAR  iProduct ;
  UCHAR  iSerialNumber ;
  UCHAR  bNumConfigurations ;
} USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR ;

Members

bLength
Specifies the length, in bytes, of this descriptor.
bDescriptorType
Must be set to USB_DEVICE_DESCRIPTOR_TYPE.
bcdUSB
Identifies the version of the USB specification that this descriptor structure complies with. This value is a binary-coded decimal number.
bDeviceClass
Is the class code of the device as assigned by the USB specification group.
bDeviceSubClass
Is the subclass code of the device as assigned by the USB specification group.
bDeviceProtocol
Is the protocol code of the device as assigned by the USB specification group.
bMaxPacketSize0
Specifies the maximum packet size, in bytes, for endpoint zero of the device. The value must be set to 8, 16, 32, or 64.
idVendor
Is the vendor identifier for the device as assigned by the USB specification committee.
idProduct
Is the product identifier. This value is assigned by the manufacturer and is device-specific.
bcdDevice
Identifies the version of the device. This value is a binary-coded decimal number.
iManufacturer
Specifies a device-defined index of the string descriptor that provides a string containing the name of the manufacturer of this device.
iProduct
Specifies a device-defined index of the string descriptor that provides a string that contains a description of the device.
iSerialNumber
Specifies a device-defined index of the string descriptor that provides a string that contains a manufacturer-determined serial number for the device.
bNumConfigurations
Specifies the total number of possible configurations for the device.

Comments

This structure is used to hold a retrieved USB-defined device descriptor. This information can then be used to further configure or retrieve information about the device. Device descriptors are retrieved by submitting a get descriptor URB.

The iManufacturer, iProduct, and iSerialNumber values when returned from the host controller driver contain index values into an array of string descriptors maintained by the device. To retrieve these strings a string descriptor request can be sent to the device using these index values.

See Also

UsbBuildGetDescriptorRequest, _URB_CONTROL_DESCRIPTOR_REQUEST


USB_ENDPOINT_DESCRIPTOR

This structure is used by USB client drivers to hold a USB-defined endpoint descriptor.

typedef struct _USB_ENDPOINT_DESCRIPTOR {
  UCHAR  bLength ;
  UCHAR  bDescriptorType ;
  UCHAR  bEndpointAddress ;
  UCHAR  bmAttributes ;
  USHORT  wMaxPacketSize ;
  UCHAR  bInterval ;
} USB_ENDPOINT_DESCRIPTOR, *PUSB_ENDPOINT_DESCRIPTOR ;

Members

bLength
Specifies the length, in bytes, of this descriptor.
bDescriptorType
Must be set to USB_ENDPOINT_DESCRIPTOR_TYPE.
bEndpointAddress
Specifies the USB-defined endpoint address. The four low-order bits specify the endpoint number. The high-order bit specifies the direction of data flow on this endpoint: 1 for in, 0 for out.
bmAttributes
The two low-order bits specify the endpoint type, one of USB_ENDPOINT_TYPE_CONTROL, USB_ENDPOINT_TYPE_ISOCHRONOUS, USB_ENDPOINT_TYPE_BULK, USB_ENDPOINT_TYPE_INTERRUPT.
wMaxPacketSize
Specifies the maximum packet size that can be sent from or to this endpoint.
bInterval
For interrupt endpoints, bInterval specifies the polling interval, in frames.


USB_INTERFACE_DESCRIPTOR

This structure is used by USB client drivers to hold a USB-defined interface descriptor.

typedef struct _USB_INTERFACE_DESCRIPTOR {
  UCHAR  bLength ;
  UCHAR  bDescriptorType ;
  UCHAR  bInterfaceNumber ;
  UCHAR  bAlternateSetting ;
  UCHAR  bNumEndpoints ;
  UCHAR  bInterfaceClass ;
  UCHAR  bInterfaceSubClass ;
  UCHAR  bInterfaceProtocol ;
  UCHAR  iInterface ;
} USB_INTERFACE_DESCRIPTOR, *PUSB_INTERFACE_DESCRIPTOR ;

Members

bLength
Specifies the length, in bytes, of this descriptor.
bDescriptorType
Specifies the descriptor type. bDescriptor must be set to USB_INTERFACE_DESCRIPTOR_TYPE.
bInterfaceNumber
Specifies the index number of this interface.
bAlternateSetting
Specifies the index number of this alternate setting of the interface.
bNumEndpoints
Specifies the number of endpoints that are used by the interface, excluding the default status endpoint.
bInterfaceClass
Is the class code of the device as assigned by the USB specification group.
bInterfaceSubClass
Is the subclass code of the device as assigned by the USB specification group.
bInterfaceProtocol
Is the protocol code of the device as assigned by the USB specification group.
iInterface
Specifies the index of a string descriptor that describes the interface. iInterface must be set to 0x1.


USB_HUB_NAME

This structure stores the hub's symbolic device name.

typedef struct _USB_HUB_NAME {
  ULONG  ActualLength;
  WCHAR  HubName[1];
} USB_HUB_NAME,  *PUSB_HUB_NAME;

Members

ActualLength
Size of the entire data structure in bytes.
HubName
A pointer to this field will point to the Unicode string containing the hub's symbolic device name.

See Also

IOCTL_INTERNAL_USB_GET_CONTROLLER_NAME


USB_ROOT_HUB_NAME

This structure stores the root hub's symbolic device name.

typedef struct _USB_ROOT_HUB_NAME {
  ULONG  ActualLength;
  WCHAR  RootHubName[1];
} USB_ROOT_HUB_NAME, *PUSB_ROOT_HUB_NAME;

Members

ActualLength
Size of the entire data structure in bytes.
RootHubName
A pointer to this field will point to the Unicode string containing the root hub's symbolic device name.

See Also

IOCTL_INTERNAL_USB_GET_HUB_NAME


USB_STRING_DESCRIPTOR

This structure is used by USB client drivers to hold a USB-defined string descriptor.

typedef struct _USB_STRING_DESCRIPTOR {
  UCHAR  bLength ;
  UCHAR  bDescriptorType ;
  WCHAR  bString[1] ;
} USB_STRING_DESCRIPTOR, *PUSB_STRING_DESCRIPTOR ;

Members

bLength
Specifies the length, in bytes, of the descriptor.
bDescriptorType
Must always be USB_STRING_DESCRIPTOR_TYPE.
bString
Points to a client-allocated buffer that contains, on return from the host controller driver, a Unicode string with the requested string descriptor.

Comments

This structure is used to hold a device, configuration, interface, class, vendor, endpoint, or device string descriptor. The string descriptor provides a human-readable description of the component.

Strings returned in bString are in Unicode format and the contents of the strings are device-defined.

See Also

UsbBuildGetDescriptorRequest, _URB_CONTROL_DESCRIPTOR_REQUEST


USBD_VERSION_INFORMATION

The GetUSBDIVersion function reports its output data in the USBD_VERSION_INFORMATION structure.

typedef struct _USBD_VERSION_INFORMATION {
  ULONG  USBDI_Version;
  ULONG  Supported_USB_Version;
} USBD_VERSION_INFORMATION, *PUSBD_VERSION_INFORMATION;

Members

USBDI_Version
Binary-coded decimal USB interface version number.
Supported_USB_Version
Binary-coded decimal USB specification version number.

Headers

Declared in usbbusif.h. Include usbbusif.h.

See Also

Interface for Direct Client Access to USB Bus, GetUSBDIVersion


USBD_INTERFACE_INFORMATION

USB client drivers use this structure to hold information about an interface for a configuration on a USB device.

typedef struct _USBD_INTERFACE_INFORMATION {
  USHORT  Length ;
  UCHAR  InterfaceNumber ;
  UCHAR  AlternateSetting ;
  UCHAR  Class ;
  UCHAR  SubClass ;
  UCHAR  Protocol ;
  .
  .
  USBD_INTERFACE_HANDLE  InterfaceHandle ;
  ULONG  NumberOfPipes ;
  USBD_PIPE_INFORMATION  Pipes[1] ;
} USBD_INTERFACE_INFORMATION, *PUSBD_INTERFACE_INFORMATION;

Members

Length
Specifies the length, in bytes, of this structure.
InterfaceNumber
Is the device-defined index identifier for this interface.
AlternateSetting
Specifies a device-defined index identifier that indicates which alternate setting this interface is using, should use, or describes.
Class
Is a USB-assigned identifier to specify a USB-defined class that this interface conforms to.
SubClass
Is a USB-assigned identifier to specify a USB-defined subclass that this interface conforms to. This code is specific to the code in Class.
Protocol
Is a USB-assigned identifier to specify a USB-defined protocol that this interface conforms to. This code is specific to the codes in Class and SubClass.
InterfaceHandle
Is a host controller driver-defined handle that is used to access this interface. This field should be treated as opaque.
NumberOfPipes
Specifies the number of pipes (endpoints) in this interface.
Pipes
Is a variable length array of USBD_PIPE_INFORMATION structures to describe each pipe in the interface.

Comments

Members that are part of this structure, but not described here, should be treated as opaque and considered to be reserved for system use.

See Also

USBD_PIPE_INFORMATION


USBD_INTERFACE_LIST_ENTRY

USB client drivers use this structure to create an array of interfaces to be inserted into a configuration request.

typedef struct _USBD_INTERFACE_LIST_ENTRY {
  PUSB_INTERFACE_DESCRIPTOR  InterfaceDescriptor;
  PUSBD_INTERFACE_INFORMATION  Interface;
} USBD_INTERFACE_LIST_ENTRY, *PUSBD_INTERFACE_LIST_ENTRY;

Members

InterfaceDescriptor
Points to a USB_INTERFACE_DESCRIPTOR structure that describes the interface to be added to the configuration request.
Interface
Points to a USBD_INTERFACE_INFORMATION structure that describes the properties and settings of the interface pointed to by InterfaceDescriptor.

Comments

This structure is used by USB clients with the routine USBD_CreateConfigurationRequestEx. Clients allocate an array of these structures, one for each interface to be configured. Clients must also allocate a NULL entry in the array to be used as a terminator before calling USBD_CreateConfigurationRequestEx.

See Also

USBD_CreateConfigurationRequestEx


USBD_PIPE_INFORMATION

This structure is used by USB client drivers to hold information about a pipe from a specific interface.

typedef struct _USBD_PIPE_INFORMATION {
  USHORT  MaximumPacketSize ;
  UCHAR  EndpointAddress ;
  UCHAR  Interval ;
  USBD_PIPE_TYPE  PipeType ;
  USBD_PIPE_HANDLE  PipeHandle ;
  ULONG  MaximumTransferSize ;
  .
  .
} USBD_PIPE_INFORMATION, *PUSBD_PIPE_INFORMATION ;

Members

MaximumPacketSize
Specifies the maximum packet size, in bytes, that this pipe handles.
EndpointAddress
Specifies the bus address for this pipe.
Interval
Specifies a polling period for this pipe in milliseconds. This value is only valid if PipeType is set to UsbdPipeTypeInterrupt.
PipeType
Specifies what type of transfers this pipe uses. This value must be one of the following:
UsbdPipeTypeControl
Specifies that this pipe is a control pipe.
UsbdPipeTypeIsochronous
Specifies that this pipe uses isochronous transfers.
UsbdPipeTypeBulk
Specifies that this pipe uses bulk transfers.
UsbdPipeTypeInterrupt
Specifies that this pipe uses interrupt transfers. A value will be set in Interval to indicate how often this pipe is polled for new data.
PipeHandle
Specifies a host controller driver-defined handle that is used to access this pipe. This field should be treated as opaque.
MaximumTransferSize
Specifies the maximum size, in bytes, for a transfer request on this pipe.

Comments

Members that are part of this structure, but not described here, should be treated as opaque and considered to be reserved for system use.


USBD_ISO_PACKET_DESCRIPTOR

This structure is used by USB client drivers to describe an isochronous transfer packet.

typedef struct _USBD_ISO_PACKET_DESCRIPTOR {
  ULONG  Offset ;
  ULONG  Length ;
  USBD_STATUS  Status ;
} USBD_ISO_PACKET_DESCRIPTOR, *PUSBD_ISO_PACKET_DESCRIPTOR ;

Members

Offset
Specifies the offset, in bytes, of the buffer for this packet from the beginning of the entire isochronous transfer buffer.
Length
Contains the number of bytes read (on return from the host controller driver) or the number of bytes to write to the isochronous pipe.
Status
Contains the status, on return from the host controller driver, of this transfer packet.

Comments

This structure is used as part of an isochronous transfer request to the host controller driver using _URB_ISOCH_TRANSFER. The Offset member contains the offset from the beginning of the TransferBuffer or TransferBufferMDL members of the _URB_ISOCH_TRANSFER structure.

See Also

_URB_ISOCH_TRANSFER


Interface for Direct Client Access to USB Bus

In Windows XP and later operating systems, USB client drivers can query the hub driver for an interface rather than linking directly to usbd.sys, in order to perform certain operations.

Using this interface provides several advantages for clients:

  • Client drivers can use the services provided by the interface without allocating an IRP.
  • Clients can call the interface's functions at raised IRQL.

To use the interface, a driver must send an IRP_MN_QUERY_INTERFACE request to the hub driver. The following code snippet illustrates how to obtain this interface:

// Create an IRP, and define it to be of type
// IRP_MN_QUERY_INTERFACE in the next stack location:
irpstack = IoGetNextIrpStackLocation(irp);
irpstack->MajorFunction= IRP_MJ_PNP;
irpstack->MinorFunction= IRP_MN_QUERY_INTERFACE;

// Allocate memory for an interface of type
// USB_BUS_INTERFACE_USBDI_V0 and have the IRP point to it:
irpstack->Parameters.QueryInterface.Interface = (USB_BUS_INTERFACE_USBDI_V0) (newly allocated interface buffer);

// Assign the InterfaceSpecificData member of the IRP to be NULL
irpstack->Parameters.QueryInterface.InterfaceSpecificData = NULL;

// Set the interface type to the appropriate GUID
irpstack->Parameters.QueryInterface.InterfaceType = &USB_BUS_INTERFACE_USBDI_GUID;

// Set the size and version of interface in the IRP.
// Currently, there is only one valid version of
// this interface available to clients.
irpstack->Parameters.QueryInterface.Size = sizeof(USB_BUS_INTERFACE_USBDI_V0);
irpstack->Parameters.QueryInterface.Version = USB_BUSIF_USBDI_VERSION_0;
ntStatus = IoCallDriver(PDO that the client passes URBs to, irp);

This interface supplies the following functions:

GetUSBDIVersion

QueryBusTime

SubmitIsoOutUrb

QueryBusInformation


GetUSBDIVersion

The GetUSBDIVersion function returns the USB interface version number and the version number of the USB specification that defines the interface, along with information about host controller capabilities.

GetUSBDIVersion(
  IN PVOID  BusContext,
  IN OUT PUSBD_VERSION_INFORMATION  VersionInformation,
  IN OUT PULONG  HcdCapabilities
  )

Parameters

BusContext
Handle returned in the BusContext member of the USB_BUS_INTERFACE_USBDI_V0 structure by an IRP_MN_QUERY_INTERFACE request.
VersionInformation
Returns a pointer to a USBD_VERSION_INFORMATION structure that contains the USB interface version number and the USB specification version number. See USBD_GetUSBDIVersion for further information on USBD_VERSION_INFORMATION.
HcdCapabilities
Returns the host capability flags. Currently, the only flag reported is the USB_HCD_CAPS_SUPPORTS_RT_THREADS flag. This flag indicates whether the host controller supports real-time threads.

Return Value

None

Headers

Declared in usbbusif.h. Include usbbusif.h.

Comments

Callers of this function can be running at any IRQL.

The function returns the highest USBDI Interface Version supported by the port driver. This function replaces the USBD_GetUSBDIVersion library function provided by usbd.sys.

Released interface versions are listed in the following table:

Operating System | Interface Version
Windows 98 Gold | 0x00000102
Windows 98 SE | 0x00000200
Windows 2000 | 0x00000300
Windows Millennium Edition | 0x00000400
Windows XP | 0x00000500

See Also

USBD_VERSION_INFORMATION


QueryBusTime

The QueryBusTime function returns the current 32-bit USB frame number.

NTSTATUS
QueryBusTime(
  IN PVOID  BusContext,
  OUT PULONG  CurrentFrame
  )

Parameters

BusContext
Handle returned in the BusContext member of the USB_BUS_INTERFACE_USBDI_V0 structure by an IRP_MN_QUERY_INTERFACE request.
CurrentFrame
Receives the current USB frame number.

Return Value

Returns STATUS_SUCCESS on success, and the appropriate error code on failure.

Headers

Declared in usbbusif.h. Include usbbusif.h.

Comments

This function replaces the USBD_QueryBusTime library function provided by usbd.sys. Callers of this function can be running at any IRQL.

See Also

Interface for Direct Client Access to USB Bus


SubmitIsoOutUrb

The SubmitIsoOutUrb function submits a USB request block (URB) directly to the bus driver without requiring the allocation of an IRP.

NTSTATUS
SubmitIsoOutUrb(
  IN PVOID  BusContext,
  IN PURB  Urb
  );

Parameters

BusContext
Handle returned in the BusContext member of the USB_BUS_INTERFACE_USBDI_V0 structure by an IRP_MN_QUERY_INTERFACE request.
Urb
Points to the URB to be passed to the port driver.

Return Value

SubmitIsoOutUrb returns one of the following values:

STATUS_SUCCESS
The call completed successfully.
STATUS_NOT_SUPPORTED
Fast isochronous interfaces and real time threads are not supported by the host controller.

Headers

Declared in usbbusif.h. Include usbbusif.h.

Comments

This function replaces the USBD_BusSubmitIsoOutUrb library function provided by usbd.sys.

This function allows clients running in real-time threads at an elevated IRQL to have rapid access to the bus driver. This USB host controller must support real-time threads for this function to work.

Callers of this function can be running at any IRQL.

The calling driver forfeits any packet level error information when calling this function.

See Also

Interface for Direct Client Access to USB Bus


QueryBusInformation

The QueryBusInformation function returns bus information.

QueryBusInformation(
  IN PVOID  BusContext,
  IN ULONG  Level,
  IN OUT PVOID  BusInformationBuffer,
  IN OUT PULONG  BusInformationBufferLength,
  OUT PULONG  BusInformationActualLength
  )

Parameters

BusContext
Handle returned in the BusContext member of the USB_BUS_INTERFACE_USBDI_V0 structure by an IRP_MN_QUERY_INTERFACE request.
Level
If Level is zero, then the function returns the total bandwidth and the total consumed bandwidth in bits per second. If Level is one, the function returns the symbolic name of the controller in Unicode, in addition to the total bandwidth and the total consumed bandwidth.
BusInformationBuffer
Points to a buffer that receives the requested bus information.
BusInformationBufferLength
On input, the length of the buffer specified by BusInformationBuffer. On output, the length of the output data.
BusInformationActualLength
Length of the output data.

Return Value

QueryBusInformation returns one of the following values:

STATUS_SUCCESS
The call completed successfully.
STATUS_BUFFER_TOO_SMALL
The buffer was too small. This error code is returned in two cases:
Level = 0 this error code is returned if the size of the buffer pointed to by BusInformationBuffer < sizeof(PUSB_BUS_INFORMATION_LEVEL_0)

Level = 1 this error code is returned if the size of the buffer pointed to by BusInformationBuffer < sizeof(PUSB_BUS_INFORMATION_LEVEL_1).

Headers

Declared in usbbusif.h. Include usbbusif.h.

Comments

The exact information returned by this function depends on the value of the Level parameter. This function replaces the USBD_QueryBusInformation library function provided by usbd.sys.

Callers of this routine can be running at any IRQL.

See Also

Interface for Direct Client Access to USB Bus


Getting Started

Previous Next

Getting Started on Windows 98/Me

The Microsoft® Windows 98/Me documentation node contains some information for developing device drivers in the Windows® 95/98/Me. For some types of devices, additional Windows 98/Me and earlier information can be found under the appropriate device-type-specific nodes within the Windows DDK documentation.

Starting to Build Your Own WDM Drivers

Once you have built the sample drivers to verify the Windows DDK installation, you can start building your own WDM driver. Note that much of the information about building kernel-mode drivers in the Windows DDK also applies to building WDM drivers.

The Windows Me debugger tool provided in the Windows DDK is the Windows System Debugger (debugger.exe). It is located in the \bin\win_me\fre folder of the DDK. For detailed information on how to install and use debugger.exe, see Windows Me Debugger and Other Tools.

A remote terminal (Rterm.exe) is provided for additional debugging capabilities. RTerm, located in the \bin\win_me\fre folder of the DDK, supports source-level debugging as well as being Win32®-aware. The new application handles higher transfer rates, up to 115.2 Kbps, the Pentium instruction set, and the ability to load debug symbols dynamically from Rterm.exe. Additional information is available under the application's Help menu or by using the debugger's command-line switches and typing -? or .-?.

Rterm.exe can be used in combination with the DDK debugger, but is incompatible with older WDEB applications. The previous remote terminal utility, Rterm98, must be paired with WDEB98 to function. Likewise, the older Windows 95 version of RTerm, or an equivalent remote terminal application such as HyperTerminal (Hyperterm.exe), can be used with wdeb386.exe.

Additional Information

Information on the Windows DDK CD

For information on installing the DDK and configuring the build environment to work with Windows Me device drivers, please see install.htm and me_inst.htm both contained on the root of the Windows DDK CD, and installed by default into the same directory as the DDK.

Driver-Specific Information

For information on creating specific drivers for Windows Me, consult the Windows DDK topics listed in the following table:

Driver | Topic
Infrared (IrDA) miniport | IrDA Miniport Drivers
WDM Audio | WDM Audio Driver Design Guide
WDM DVD | DVD Minidrivers
IEEE 1394 | The IEEE 1394 Driver Stack
Modem | Overview of Modem INF Files

Note The Windows DDK contains a tool for creating modem drivers.

Information on the Microsoft Web Site

The Hardware Development Web Site at http://www.microsoft.com/hwdev provides the following information on hardware and driver development:

  • Supplemental driver development information.
  • Third-party driver development and training resources.
  • Advice from "Dr. Iver" on special driver topics, such as WDM, Plug and Play, and power management.
  • Specifications for power management, Plug and Play, and other special topics.

The MSDN® (Microsoft Developers Network) Web site at http://msdn.microsoft.com provides the following downloads and information:

  • Service packs or patches for Microsoft development tools.
  • Special developer tools for MSDN Online Members to use and evaluate. These tools are designed to complement and integrate with the Microsoft programming environments you already use.
  • Up-to-date releases of the Platform SDK.
  • Access to user groups, chats, event information, the MSDN Library Online, and a host of products and technologies for developers.

The Microsoft® DirectX® Web site at http://www.microsoft.com/directx provides information for DirectX hardware and software developers, including:

  • Microsoft DirectX SDK download.
  • Connections to technical articles, support information, and news groups.

The DDK Web site at http://www.microsoft.com/ddk provides information and resources for driver development, including:

  • Current versions of various DDKs.
  • Online help for DDKs.
  • Announcements of new DDK developments.
  • Feedback for reporting bugs, suggesting content, and rating the DDK.

The Product Support Services Web site at http://support.microsoft.com/support/ddk provides information on developing and maintaining drivers, including:

  • Additional driver samples.
  • Tools for device drivers and debugging.
  • FAQs on Windows driver development.


Using WDM Drivers with Windows Me

This documentation provides an overview for writing Windows Driver Model (WDM) device drivers under Microsoft® Windows® Millennium Edition (Windows Me). The information is useful to both new and experienced driver writers.

WDM defines a unified driver model for Windows 98, Windows Me, and Windows 2000 and later, that has standard requirements and thus reduces the amount of code that needs to be written. Programmers already familiar with Windows NT® 4.0 drivers will recognize many of the features of WDM drivers. However, the documentation and samples should be studied in order to understand WDM requirements. WDM drivers will not run on operating systems earlier than Windows 98 or Windows 2000.

By conforming to WDM, drivers can be source-compatible across Windows 98, Windows Me, and Windows 2000 and later operating systems. However, subsequent operating system releases will contain features not available in preceding versions. WDM is designed to be forward compatible but not backward compatible. That is, drivers will be compatible with the same or higher numbered WDM versions. Older WDM drivers will not be able to take advantage of new operating system services but will still load and run. However, drivers written for a newer version of WDM will most likely fail during loading on a system that supports an older version.

WDM driver writers should carefully consider which features to include. For example, does the driver need to run on different platforms? Will the hardware be widely available or is it highly specialized and thus limited in distribution? Additionally, not all hardware meets the requirements of WDM. Video drivers do not support the WDM model and must be written separately, as do certain drivers utilizing VxDs under Windows 98 and network drivers. Virtual hardware (emulation) and nonstandard buses are not supported in a WDM class.

A dual operating system driver must conform to the lowest WDM version on either operating system. For cross-operating system compatibility, thoroughly test drivers on all operating system versions you intend to support, because operating system differences can produce slightly different driver behavior. Differences are most apparent between single processor and multiprocessor platforms.


Writing Kernel-Mode Drivers

Kernel-mode drivers that conform to the Windows Driver Model (WDM) can run on Windows 98, Windows Millennium Edition, and Windows 2000 and later systems. All WDM drivers must use kernel-mode driver support routines, which are defined by the operating system. See the Kernel-Mode Driver Reference in the Windows DDK for information on these routines.

The Kernel-Mode Driver Reference documents all kernel-mode routines supported by Windows. Most of these routines are supported by WDM on Windows 98 and ME, but a few are not. The reference material for each support routine lists the header file(s) in which the routine is defined. Unless otherwise noted, routines defined in wdm.h can be used by WDM drivers on Windows 98, Windows ME, and Windows 2000 and later. Routines defined in ntddk.h, but not in wdm.h, are not supported on Windows 98 or ME.

In general, the support routines behave similarly on all three operating systems. Any individual differences are noted in the reference page for the relevant routine.


Kernel-Mode Streaming Reference

Built on Wednesday, July 11, 2001


I/O Control

This section describes the set of predefined I/O control codes (IOCTLs) that WDM Streaming supports. IRP_MJ_DEVICEIOCONTROL is received by a device through a file object in order to support these IOCTLs. The parameters depend on the subfunction passed.

The IOCTLs covered here include:

IOCTL_KS_READ_STREAM

IOCTL_KS_WRITE_STREAM

IOCTL_KS_PROPERTY

IOCTL_KS_METHOD

IOCTL_KS_ENABLE_EVENT

IOCTL_KS_DISABLE_EVENT

IOCTL_KS_RESET_STATE

The KSDISPATCH_TABLE structure is used to direct IRPs such as IRP_MJ_DEVICEIOCONTROL to various services contained in the driver object.


IOCTL_KS_READ_STREAM and IOCTL_KS_WRITE_STREAM

The standard streaming interface consists of IOCTL_KS_READ_STREAM and IOCTL_KS_WRITE_STREAM, which are sent to pin connections that send or receive data in a buffered manner. These requests contain a stream header list, each optionally pointing to the actual stream data. The headers can also contain the presentation time and duration.

Additional media-specific streaming interfaces can be defined. For example, a music streaming interface can define additional music-specific properties in addition to a standard set. This does not imply that media-specific streaming interfaces are always a superset of a basic streaming interface.

The stream header can also indicate that this is the end of a media stream or sequence. This is used to stop any QM problems from being generated, as discussed in the Default Clock section, or to show the end of a segment within a stream containing noncontiguous segments. If these flags are used on a write, there may be no actual data buffer attached to the request.


IOCTL_KS_PROPERTY

Filters and pins support property sets using the IOCTL_KS_PROPERTY device I/O control. Although this IOCTL is defined with the METHOD_NEITHER flag, the property data is passed as the output buffer to the IOCTL and probed for read access. The KsPropertyHandler function handles properties requested through IOCTL_KS_PROPERTY. For more information on helper functions for property sets, see Property Set Functions.

Property sets can represent items such as the number of pins available and the types of connections they can make. Property sets are also used to configure filters and pins. Property sets are a way to access a group of related data on an object, and each property request can be fulfilled either synchronously or asynchronously.

Each property set has a unique identifier that is used to access a requested property set. The method of using unique identifiers for property sets allows custom driver extensions that will not conflict with any other custom extensions. If a filter or pin must support multiple distinct copies of the same property set, it must use instance identifiers.

Property sets use the following structures and parameters:

KSPROPERTY_DESCRIPTION

KSPROPERTY_ITEM

KSPROPERTY_SET

KSPROPERTY_MEMBERSHEADER

KSPROPERTY_VALUES


IOCTL_KS_PROPERTY Flags

Property information is passed using a KSPROPERTY structure that is defined as follows:

typedef    KSIDENTIFIER    KSPROPERTY;

A property is defined by:

  • A property set identifier (a GUID)
  • A property identifier (a ULONG identifier within the set)
  • KSIDENTIFIER Flags

The flags set in KSIDENTIFIER.Flags are used to send additional parameters, including getting and setting properties.

Depending on the property set, a request may also have to specify property instance information in the event that multiple instances of a single property set exist. Instance information is also property specific; it is appended to the end of the structure.

A request is passed the KSPROPERTY structure, which can contain instance information appended to the structure. A property-specific buffer is passed in which to place the property value.

All property sets must support the KSPROPERTY_TYPE_BASICSUPPORT and KSPROPERTY_TYPE_RELATIONS flags. These allow queries for the support of a specific property within a property set, optional values, and related properties, if supported by that property.

For the basic query, the flags returned from a query determine whether one has write, read, or read/write access to the property. The queried identifier is appended to the structure as property-specific data. For multiple instance property sets, this refers to all the sets as a whole, rather than any particular instance. When querying for related properties, a list of related properties is returned.

Valid flags are:

KSPROPERTY_TYPE_GET

KSPROPERTY_TYPE_SET

KSPROPERTY_TYPE_SETSUPPORT

KSPROPERTY_TYPE_BASICSUPPORT

KSPROPERTY_TYPE_RELATIONS

KSPROPERTY_TYPE_SERIALIZESET

KSPROPERTY_TYPE_UNSERIALIZESET

KSPROPERTY_TYPE_SERIALIZERAW

KSPROPERTY_TYPE_UNSERIALIZERAW

KSPROPERTY_TYPE_SERIALIZESIZE

KSPROPERTY_TYPE_DEFAULTVALUES


KSPROPERTY_TYPE_GET

The IOCTL_KS_PROPERTY request with the KSPROPERTY_TYPE_GET flag set in KSIDENTIFIER.Flags returns the current value of the specified property. The format of the property depends on the specific property itself. Any instance information is appended to the property identifier. The input buffer is copied to a system buffer.


KSPROPERTY_TYPE_SET

The IOCTL_KS_PROPERTY request with the KSPROPERTY_TYPE_SET flag sets the current value of the specified property. The format of the property data is dependent on the specific property itself. Any instance information is appended to the property identifier. Although this IOCTL is defined with the METHOD_NEITHER flag, the property data is passed as the output buffer to the IOCTL and probed for read access. The input buffer is copied to a system buffer as in the case of a KSPROPERTY_TYPE_GET flag.


KSPROPERTY_TYPE_SETSUPPORT

The IOCTL_KS_PROPERTY request with the KSPROPERTY_TYPE_SETSUPPORT flag returns information on the supported property set in general. This returns an error if the property set is not supported. Otherwise, STATUS_SUCCESS is returned. The specific identifier is ignored in this instance.


KSPROPERTY_TYPE_BASICSUPPORT

The IOCTL_KS_PROPERTY request with the KSPROPERTY_TYPE_BASICSUPPORT flag specifies that the basic information on access is to be returned. For basic support, the return depends on the size of the output buffer passed to the call. If room in the buffer is supplied, the values information is returned, if supported by the property.


KSPROPERTY_TYPE_RELATIONS

The IOCTL_KS_PROPERTY request with the KSPROPERTY_TYPE_RELATIONS flag specifies that the property relations list is to be returned, or the amount of buffer room required by such a list if the return buffer is the size of a ULONG. Each element is ULONGLONG aligned, preceded by a KSMULTIPLE_ITEM structure. This is not valid when querying support of the property set in general.

For relations support (KSPROPERTY_TYPE_RELATIONS), the return also depends on the size of the output buffer passed to the call. If the output buffer size is zero, the size that would be used to return the related properties is returned in BytesReturned member with a waning status of STATUS_BUFFER_OVERFLOW. If the buffer is the size of a KSMULTIPLE_ITEM structure, both the byte size and count of relations is returned. Otherwise, the buffer is expected to be long enough to return the KSMULTIPLE_ITEM structure and all related property identifiers, which is returned as just a list of KSIDENTIFIER structures. This is how a client determines the effects of changing this property, which may affect properties in completely different property sets. The assumption is that if a related property is returned in the list, that is all the information necessary to find that property.


KSPROPERTY_TYPE_SERIALIZESET

The IOCTL_KS_PROPERTY request with the KSPROPERTY_TYPE_SERIALIZESET flag specifies that the properties in this set should be serialized to the buffer, or the size of such serialization should be returned.

Support for serialization of a property set is done through KSPROPERTY_TYPE_SERIALIZESET and KSPROPERTY_TYPE_UNSERIALIZESET. These allow a built-in method of acquiring or setting the state of multiple properties with a single call from the client. These are broken up into multiple calls by KsPropertyHandler if the KS handler is being used to process property requests. When using this handler, the properties to be serialized are controlled by the property set definition. The KSPROPERTY_ITEM.SerializedSize is checked for a nonzero value indicating the size in bytes of the property, where –1 is unknown and must be queried.

A value of zero indicates that the property should not be serialized. To query what the total size a serialization would take, pass a zero-length buffer. The BytesReturned member is filled with the size in bytes the buffer must be to serialize the set and a warning status of STATUS_BUFFER_OVERFLOW is returned. A buffer allocated at that size can then be filled with the serialized data.

The format of the serialization buffer is the GUID of the property set, followed by a ULONG count of the properties that follow. Each property that follows contains a header (KSPROPERTY_SERIAL), followed by the property data, with the start of each property on FILE_LONG_ALIGNMENT (the assumption being that the start of the client's buffer is on FILE_LONG_ALIGNMENT).

typedef struct {
  KSIDENTIFIER  PropTypeSet;
  ULONG  Id;
  ULONG  PropertyLength;
} KSPROPERTY_SERIAL;

Members

PropTypeSet
Specifies the type of property data. This is the same information obtained from querying Basic Support.
Id
Specifies the identifier for this property.
PropertyLength
Specifies the length in bytes of the following property data. Does not include any alignment buffering that may be appended to the property data before the next property in the serialization.


KSPROPERTY_TYPE_UNSERIALIZESET

The IOCTL_KS_PROPERTY request with the KSPROPERTY_TYPE_UNSERIALIZESET flag specifies that the buffer provided contains a group of properties belonging to the set that should be unserialized.


KSPROPERTY_TYPE_SERIALIZERAW

The IOCTL_KS_PROPERTY request with the KSPROPERTY_TYPE_SERIALIZERAW flag specifies that the properties in this set should be serialized by the property set support handler, if one exists. If not, the call will fail. The serialization format is private.

Support for raw serialization of a property set is done through KSPROPERTY_TYPE_SERIALIZERAW and KSPROPERTY_TYPE_UNSERIALIZERAW. This can only be supported if a property item handler exists, as the data format is private to the property set. The standard KsPropertyHandler function just passes this on to the handler, if one exists. Size of such serialization can also be queried by passing a zero length buffer to a serialize raw request. Because handlers are attached to property items and not the property set, a specific item within the property set must be specified in the Property parameter. The handler may deal with multiple properties within the set.


KSPROPERTY_TYPE_UNSERIALIZERAW

The KSPROPERTY_TYPE_UNSERIALIZERAW request specifies that the buffer provided contains a group of properties belonging to this set that should be unserialized by the property set support handler, if one exists. If not, the call will fail. The serialization format is private.


KSPROPERTY_TYPE_SERIALIZESIZE

The KSPROPERTY_TYPE_SERIALIZESIZE request specifies that the size necessary for serializing a particular property should be returned. The size is returned in the output buffer as a ULONG. A size of zero indicates that a property does not need to be serialized.


KSPROPERTY_TYPE_DEFAULTVALUES

The KSPROPERTY_TYPE_DEFAULTVALUES request indicates that the default values should be returned in the Basic Support information, if any, instead of in the normal range values. Default values are tagged as such by the filter when defining property range values.


IOCTL_KS_METHOD

Filters and pins support method sets using the IOCTL_KS_METHOD device I/O control code. IOCTL_KS_METHOD is defined with the TransferType parameter set to METHOD_NEITHER. However, needed buffers are copied when processed using the KsMethodHandler service. The first buffer is copied and the second buffer is copied, if needed, according to the KSIDENTIFIER flags.

Method sets are used to perform an action. In contrast, property sets are used to get and set attributes. If a parameter associated with a device can be manipulated by getting and setting it, then it is most likely a property. If a parameter is used to perform an action, such as allocating memory, then it is most likely a method.

Method sets provide a way to access related actions. Each method request can be fulfilled either synchronously or asynchronously. Method sets have unique identifiers that are used to retrieve the method set requested. The use of unique identifiers for method sets allows custom driver extensions to be created that do not conflict with other custom extensions.

Although similar to a property set, the parameters for a method set differ in that a method can either pass no information, or pass information in only, out only, or pass information bidirectionally.

If a filter or pin must support multiple distinct copies of the same Method set, it must use instance identifiers.

Method sets use the following structures and parameters:

KSMETHOD_ITEM

KSFASTMETHOD_ITEM

KSMETHOD_SET

IOCTL_KS_METHOD Flags

The KsMethodHandler function handles methods requested through IOCTL_KS_METHOD. For more information on helper functions for method sets, see Method Set Functions.


IOCTL_KS_METHOD Flags

Method information is passed using a KMETHOD structure that is defined as follows:

typedef    KSIDENTIFIER    KSMETHOD;

A method is defined in KSMETHOD by:

  • A method set identifier (a GUID)
  • A method identifier (a ULONG identifier within the set)
  • KSMETHOD flags

The expected parameter passing type is determined by flags in the KSMETHOD structure, just as property sets use flags to get and set a property. These flags indicate what the second buffer of the device I/O control will be used for. A method can implement a get and set mode by using different flags on calls to indicate what the second buffer should contain. For instance, a method could take some defined structure or no structure; the appropriate flag would be set for the particular case.

The IOCTL_KS_METHOD is defined with the TransferType parameter set to METHOD_NEITHER. However, needed buffers are copied when processed using the KsMethodHandler service. The first buffer is copied and the second buffer is copied, if needed, according to the KSMETHOD flags. Therefore, access exceptions on this data is not a problem within method handlers called by this service, except in the case of KSMETHOD_TYPE_SOURCE in combination with KSMETHOD_TYPE_NONE.

A request is passed the KSMETHOD_SET structure, which may contain instance information appended to the structure. A method-specific buffer can be passed.

All method sets must support the KSMETHOD_TYPE_BASICSUPPORT flag and allows queries for the support of a specific method within a method set. The buffer is returned with the flags specifying the type of support for the method (for example, KSMETHOD_TYPE_WRITE), or an error is returned. In order to query for support of a method set in general, use the KSMETHOD_TYPE_SETSUPPORT flag. In this case, the identifier is ignored.

The valid flags are:

KSMETHOD_TYPE_NONE

KSMETHOD_TYPE_READ

KSMETHOD_TYPE_WRITE

KSMETHOD_TYPE_MODIFY

KSMETHOD_TYPE_SOURCE

KSMETHOD_TYPE_SETSUPPORT

KSMETHOD_TYPE_BASICSUPPORT


KSMETHOD_TYPE_NONE

The KSMETHOD_TYPE_NONE flag is used by the filter in a method description to indicate that the second buffer is not expected to be used. For buffered methods, although space is allocated, no data is copied to or from the system buffer. When in source mode (KSMETHOD_TYPE_SOURCE), no MDL is created.


KSMETHOD_TYPE_READ

The KSMETHOD_TYPE_READ flag is used by the filter in a method description to indicate that parameters are expected to be read from the second buffer. When buffered, data is copied to the system buffer. When in source mode, the data is probed and locked for IoReadAccess.


KSMETHOD_TYPE_WRITE

The KSMETHOD_TYPE_WRITE flag is used by the filter in a method description to indicate that parameters are expected to be written to the second buffer. When buffered, data is copied from the system buffer. When in source mode, the data is probed and locked for IoWriteAccess.


KSMETHOD_TYPE_MODIFY

The KSMETHOD_TYPE_MODIFY flag is used by the filter in a method description to indicate that parameters are expected to be read and written to the second buffer. The data passed in is overwritten by the data returned. This might imply that a structure passed in could be updated. When buffered, the data is copied to the system buffer and copied back when the IRP is completed. When in source mode, the data is probed and locked for IoModifyAccess.


KSMETHOD_TYPE_SOURCE

The KSMETHOD_TYPE_SOURCE flag is used by the filter in a method description to indicate that the method is to be processed in source mode. An MDL is allocated and the data is probed and locked.


KSMETHOD_TYPE_SETSUPPORT

The KSMETHOD_TYPE_SETSUPPORT flag is used by the filter in a method description to indicate that a KSMETHOD_TYPE_WRITE method of operation query for support of the method set in general.


KSMETHOD_TYPE_BASICSUPPORT

The KSMETHOD_TYPE_BASICSUPPORT flag is used by the filter in a method description to indicate that a KSMETHOD_TYPE_WRITE method of operation query for basic support attributes of a particular method.


IOCTL_KS_ENABLE_EVENT and IOCTL_KS_DISABLE_EVENT

Device objects support event sets using the IOCTL_KS_ENABLE_EVENT and IOCTL_KS_DISABLE_EVENT device I/O control codes. Event sets are groups of related events that can generate a notification of an event occurrence. For example, a change in a device state or the reaching of a specific sample position might cause a filter pin to generate an event notification to any clients that have registered to receive such a notification.

If a filter or pin must support multiple distinct copies of the same event set, it must use instance identifiers as described in the IOCTL_KS_ENABLE_EVENT section. A particular event can be defined as a "single shot," meaning that the event only fires once and is then automatically disabled. For example, a positional mark might trigger an event when the device reaches a specified position. Other events are defined to trigger multiple times until disabled.

The IOCTL_KS_ENABLE_EVENT request enables a specified event. The format of an event request varies for each specific event itself. An event is defined by:

  • An event set identifier
  • An event identifier
  • Event-specific data

The KSEVENT structure contains the event identification information, and is a KSIDENTIFIER structure. The flags element contains the type of query to perform. This may be one of the following:

Flags | Description
KSEVENT_TYPE_ENABLE | Indicates typical enabling of an event for continuous notification. The event is not discarded until the client requests that it be discarded, or that the file object on which the event was created is closed.
KSEVENT_TYPE_ONESHOT | Enables the event for a single notification. The event is discarded after a single notification.
KSEVENT_TYPE_SETSUPPORT | Queries for the list of event sets, or support of a particular event set.
KSEVENT_TYPE_BASICSUPPORT | Queries for support of a particular event type.

For some event sets, where multiple instances of a single event set exist, a request can also specify event instance information. Instance information is also event specific; it is appended to the end of the structure.

A client enabling an event could use the following sample code:

DeviceIoControl(
    DeviceHandle,
    IOCTL_KS_ENABLE_EVENT,
    &Event,
    sizeof(KSEVENT),
    &EventData,
    sizeof(KSEVENTDATA),
    &BytesReturned,
    &Overlapped);

The IOCTL_KS_DISABLE_EVENT request disables a specified event. The same pointer that was used to enable the event must be used to disable it. The pointer is the key used to uniquely identify the event. Optionally, a NULL pointer and length of zero may be specified as the first buffer to disable all active events for the client. The format is the one previously defined. Note that all pending DPCs and work items should be disposed of before freeing any critical structures that they rely on.

A client disabling an event could use the following sample code:

DeviceIoControl(
    DeviceHandle,
    IOCTL_KS_DISABLE_EVENT,
    &EventData,
    sizeof(KSEVENTDATA),
    NULL,
    0,
    &BytesReturned,
    &Overlapped);

All event sets must support the KSEVENT_TYPE_BASICSUPPORT flag that allows queries for the support of a specific event within an event set. For multiple instance event sets, this refers to all the event sets as a whole, rather than any particular event set instance.

The synchronization or notification event, DPC, is typically used to signal the occurrence of the event, unless otherwise specified by the specific event type. Event object, DPC notification, and work item queuing can only be accessed by kernel-mode components. The original address of the KSEVENTDATA structure can later be used to disable the event, although the actual address does not have to be valid throughout the lifetime of the event. In order to query for support of an event set in general, use the KSEVENT_TYPE_SETSUPPORT flag.

Event sets use the following structures and parameters:

KSEVENT_ITEM

KSEVENT_SET

KSEVENT_ENTRY

KSDPC_ITEM

KSEVENTDATA


IOCTL_KS_RESET_STATE

Resetting the state essentially returns the object (for example, a pin) to the state it was in when it was set to an Acquire state. Any reset must be propagated through a data stream from pin connection to pin connection. During a reset, any additional reset requests that a pin receives will be ignored. Consequently, a reset on a pin can affect the filter as a whole as it propagates the request through the effected pins in relation to the filter routing for that pin.

A reset is initiated on a pin by sending IOCTL_KS_RESET_STATE with a value of KSRESET_BEGIN contained in the input buffer. This begins the Reset state and indicates to a pin that any pending or new data received while in a Reset state should be rejected with STATUS_DEVICE_NOT_READY. The reset state is ended by either a disconnection, or by receiving an IOCTL_KS_RESET_STATE with a value of KSRESET_END contained in the input buffer. It is not canceled by changing the pin state. This indicates to a pin that new data can be accepted. It also indicates that the pin can once again pass data to its previous connection, even if data had been rejected in a prior attempt. Typically, rejecting data indicates to a pin that it should halt sending more data.


Method Set Reference

This section discusses method sets, including:

KSMETHODSETID_StreamAllocator Method Set

For more information on method sets, see IOCTL_KS_METHOD Method Sets.


KSMETHODSETID_StreamAllocator Method Set

The KSMETHODSETID_StreamAllocator method set specifies the functions for the IRP-based allocator interface.

The KSMETHODSETID_StreamAllocator method set includes:

KSMETHOD_STREAMALLOCATOR_ALLOC

KSMETHOD_STREAMALLOCATOR_FREE


KSMETHOD_STREAMALLOCATOR_ALLOC

The KSMETHOD_STREAMALLOCATOR_ALLOC method is used by a client to allocate a frame from the given allocator. The method returns STATUS_PENDING if no frames are currently available. Otherwise, the method returns a pointer to a frame.

For example, a kernel-mode client could use the following sample code to allocate a frame:

Method.Identifier.Set = KSMETHODSETID_StreamAllocator;
Method.Identifier.Id = KSMETHOD_STREAMALLOCATOR_ALLOC;
Method.Flags = KSMETHOD_TYPE_WRITE;
DeviceIoControl(
    AllocatorHandle,
    IOCTL_KS_METHOD,
    &Method,
    sizeof(KSMETHOD),
    &Frame,
    sizeof(PVOID),
    &BytesReturned,
    &Overlapped);


KSMETHOD_STREAMALLOCATOR_FREE

The KSMETHOD_STREAMALLOCATOR_FREE method is used by a client to free a frame back to the given allocator. A pending KSMETHOD_STREAMALLOCATOR_ALLOC, if any, can be completed by using this method.

For example, a kernel-mode client could use the following sample code to free a frame:

Method.Identifier.Set = KSMETHODSETID_StreamAllocator;
Method.Identifier.Id = KSMETHOD_STREAMALLOCATOR_FREE;
Method.Flags = KSMETHOD_TYPE_READ;
DeviceIoControl(
    AllocatorHandle,
    IOCTL_KS_METHOD,
    &Method,
    sizeof(KSMETHOD),
    &Frame,
    sizeof( PVOID ),
    &BytesReturned,
    &Overlapped);


IRP Reference

This section describes IRPs that are used with the basic IRP medium, which is the primary implementation example in this documentation.

The IRPs include:

IRP_MJ_CLOSE

IRP_MJ_FLUSH_BUFFERS

IRP_MJ_FLUSH

IRP_MJ_CREATE

IRP_MJ_DEVICEIOCONTROL


IRP_MJ_CLOSE

IRP_MJ_CLOSE is received by a device object when a filter, filter pin, or master clock file handle is being closed.


IRP_MJ_FLUSH_BUFFERS

IRP_MJ_FLUSH_BUFFERS is received by a filter pin to flush the state of the stream. This is typically sent by a proxy when a flush request is received from another connection instance. There are no parameters to this IRP. A pin does not need to support this IRP if it does not queue data or have a stream state that is modified by the progression of data, such as a codec doing interframe compression.


IRP_MJ_FLUSH

An object's state can be flushed using IRP_MJ_FLUSH. This IRP is used to ensure that the object state and stream data have been flushed from permanent storage or completely processed by the underlying hardware. Any object can support this IRP through a KSDISPATCH_TABLE entry.


IRP_MJ_CREATE

IRP_MJ_CREATE is received by a device object when a filter, filter pin, or master clock file handle is created. The only method to establish communication is through an open file handle on one of these objects:

  • A file handle of a filter is created when an instance of the filter is required.
  • A pin file handle is created when a pin connection is established.
  • A master clock file handle is created when a filter pin is chosen as the master clock for a filter graph, assuming it supports such a clock.

Although the medium for pin communication may not use IRPs, the communication is always established through file handles (actually, reference counts on file objects). There are standard functions for creating file handles for pins so that all handles point to the same device object created by PnP either for a hardware device or for an instance of a software device.


IRP_MJ_DEVICEIOCONTROL

IRP_MJ_DEVICEIOCONTROL is received by a device through a file object in order to support the predefined kernel streaming IOCTLs. The parameters depend on the subfunction passed. For more information, see:

IOCTL_KS_PROPERTY

IOCTL_KS_DISABLE_EVENT

IOCTL_KS_ENABLE_EVENT

IOCTL_KS_METHOD

IOCTL_KS_WRITE_STREAM

IOCTL_KS_READ_STREAM

IOCTL_KS_RESET_STATE


Stream Class Video Capture Minidriver Reference

This documentation describes how to create video capture minidrivers, which are clients of the stream class driver for the Windows® 98 and the Windows NT®/Windows® 2000 operating systems under the Windows Driver Model (WDM). This document makes extensive reference to the Kernel-Mode Streaming Reference and the Stream Class Driver Reference.

This documentation contains the following sections:

Introduction

Streaming Data from a Video Capture Minidriver

Flow of Control for Video Capture

SRB Code Reference for Video Capture

Medium GUIDs

Property Sets for Video Capture

Video Capture Structures


Introduction

The Introduction section contains the following topics:

Relationship to Video for Windows Capture Drivers

Relationship to DirectShow

DirectShow Filters Used with the Stream Class

Video capture minidrivers work in combination with the stream class driver to control hardware devices that produce streams of video images and related data. The following functionality is provided by video capture minidrivers:

  • Capture of compressed and uncompressed video streams from digital and analog video sources
  • Control of devices associated with video streams such as TV tuners, video routing devices, TV audio control, and video compressors
  • Control of videoports and capture from videoport streams
  • Capture of vertical blanking interval data
  • Capture of timecode
  • Capture of ancillary data streams
  • Control of devices associated with video streams such as TV tuners, video routing devices, TV audio control, and video compressors
  • WDM streaming (kernel-mode) and DirectShow™ (user-mode) compatibility


Relationship to Video for Windows Capture Drivers

The design of Video for Windows (VFW) video capture was optimized for capturing movies to disk. Features important to video conferencing, TV viewing, capture of video fields, and ancillary data streams are missing from the VFW architecture. To circumvent these limitations, vendors have augmented VFW by implementing proprietary extensions. However, without standardized interfaces, applications that use these features must include hardware-dependent code.

With the integration of DVD, MPEG decoders, video decoders and tuners, VPE, and audio codecs on single adapters, a unified driver model that supports all these devices and handles resource contention will simplify development efforts.

The stream class provides a framework for resolving these issues. It supports a uniform streaming model for standard and custom data types. Similarly, property sets for most standard devices are defined and can be easily extended if needed. Because the stream class follows WDM streaming conventions, it supports data transfer between kernel drivers without requiring a transition to user mode.

Because of the large installed base of VFW applications, it is anticipated that VFW drivers will continue to flourish for devices that are primarily used for capturing movies. Capture devices that are used primarily for TV viewing and video conferencing are expected to migrate more quickly to WDM streaming.


Relationship to DirectShow

DirectShow™ (formerly called ActiveMovie) is the common client for driver services defined in this document. DirectShow filters interact with video capture drivers using DeviceIoctl function calls.

The flexibility of DirectShow makes possible numerous configurations of filters. The following diagrams illustrate possible configurations of user mode DirectShow filters for simultaneous preview and capture of video to disk.


DirectShow Filters Used with the Stream Class

There are four types of DirectShow™ filters that work with stream class drivers to perform video captures.

Type | Purpose | DLL
Video Capture | Provides output streams of digital video data and ancillary data streams | KSProxy.ax
TV Tuning | Provides tuning control of TV, FM, and AM tuners | KSTvTune.ax
Crossbar | Provides routing of video and audio streams | KSXBar.ax
TV Audio | Provides control of TV audio such as SAP selection | KSXBar.ax

Each of these functions appears in a DirectShow filter graph as a separate filter exposing unique control interfaces.


Streaming Data from a Video Capture Minidriver

This section contains the following topics:

Stream Categories and Mediums

Stream Categories

Stream Formats

Video Stream Extended Headers

Tuning Data Flow

Stream class video capture minidrivers can support multiple, simultaneous streams of compressed and uncompressed video, timecode, closed caption, raw and decoded VBI data, and custom data formats. For each data type that can be produced simultaneously with other data types, the driver should create a new stream. Each stream is exposed as a separate kernel streaming pin by the stream class. These pins are mirrored by the DirectShow™ capture filter. For more information on pins and streaming, see the Kernel-Mode Streaming Reference.

Video streams are composed of time-stamped, digitized video and related information such as VBI and timecode. Streams can be paused, started, and stopped independently. Stream samples are time stamped with a 100nS resolution clock.

Each pin can support a variety of different formats. For example, a single pin could support RGB16, RGB24, YUV9, and JPEG digital video. It is expected that most devices will support only a few of these pins.

Streaming conventions are also applied to input pins on the capture filter that represent analog video flowing into the capture device, and to video port output connections for both images and VBI.


Stream Categories and Mediums

Traditionally, DirectShow™ streams have been identified solely by their MediaTypes. While this is sufficient for rendering simple filter graphs, more complex graphs and graphs that reflect a hardware topology require additional information for correct graph building.

Kernel Streaming introduces two additional ways to identify and connect pins in a filter graph: Categories and Methods. The first way is to assign a pin to a Category, which is a GUID that identifies the primary purpose of the pin. For example, a capture filter could have two output pins with identical MediaTypes on each pin. If internally the filter gives priority to one of the pins, the higher priority pin could be assigned to the Capture category (PINNAME_VIDEO_CAPTURE), and the lower pin to the Preview category (PINNAME_VIDEO_PREVIEW).

The second way of identifying and connecting a pin is through the use of a Medium. A Medium is a unique identifier containing a GUID that is exposed on an output pin on one filter and an input pin on another filter. The Medium is used to ensure connectivity between these two pins. One way to think of a Medium is that it identifies a copper trace or wire between the output pin and the input pin.

The DirectShow graph builder interfaces IFilterMapper2 and ICaptureGraphBuilder can be used to construct graphs based on both Mediums and Categories.


Stream Categories

The following tables describe both the different types of pins/streams available from the KSProxy capture filter and the format types associated with each stream. The table entries prefaced by "DS" give the DirectShow equivalent in user mode.

The Category GUID and PinName GUID for a given video capture stream type are normally identical. The only case where this is not true is when a given stream Category has more than one instance on a filter. In this case, the Category GUIDs should match, but each pin should be assigned a unique PinName GUID.

The following topics are included:

Capture, Preview, and Still Categories

VBI Category

Raw NABTS Category

Corrected NABTS Category

TELETEXT Category

CC Category

EDS Category

Timecode Category

Videoport Category

Videoport VBI Category

Analog Video Category


Capture, Preview, and Still Categories

The capture, preview, and still stream Categories are almost identical in terms of data formats and stream characteristics.

Category/PinName | Description
PINNAME_VIDEO_CAPTURE | Capture Category output pins provide a stream of compressed or uncompressed digital video. This stream is typically used for writing movies to disk, video conferencing, and for image analysis.
PINNAME_VIDEO_PREVIEW | Preview Category output pins provide a stream of usually uncompressed digital video. The stream is typically used to view the video stream on the local monitor, in either RGB or YUV formats that can be directly displayed by DirectDraw. In resource-limited situations, capture drivers should prioritize the preview stream lower than the capture stream.
PINNAME_VIDEO_STILL | Still Category output pins are used with dual-mode cameras that are capable of producing both a capture stream and a still image stream that is often of higher quality than the capture stream. The still image stream includes the ability to externally or internally trigger acquisition of an image.

Note Since many cameras produce only a single output stream, the DirectShow SDK includes a Smart Tee filter that splits a single stream into a Capture and a Preview stream. Therefore, cameras that produce only a single stream should not internally duplicate their data streams to produce a preview stream.

The following table lists the common characteristics of Capture, Preview, and Still streams.

Name | Characteristic
KS Datarange | KS_DATARANGE_VIDEO (frames only) KS_DATARANGE_VIDEO2 (fields or frames)
KS Dataformat | KS_DATAFORMAT_VIDEO (frames only) KS_DATAFORMAT_VIDEO2 (fields or frames)
KS MajorFormat | KSDATAFORMAT_TYPE_VIDEO
KS SubFormat (typical) | RGB16, RGB24, UYVY, JPEG, …
KS Specifier | KSDATAFORMAT_SPECIFIER_VIDEOINFO (frames only) KSDATAFORMAT_SPECIFIER_VIDEOINFO2 (fields or frames)
Extended Header Size | KS_FRAME_INFO
Required Property Sets | KSPROPSETID_Connection PROPSETID_VIDCAP_DROPPEDFRAMES
Required Events | None
DS majortype | MEDIATYPE_Video
DS formattype | FORMAT_VideoInfo (frames only) FORMAT_VideoInfo2 (fields or frames)


VBI Category

VBI Category pins provide a stream of raw, unparsed VBI (vertical blanking interval) data. This stream is typically passed to codecs that extract closed captioning, NABTS, WST, timecode, and other digital data streams.

When creating the category PinName, PINNAME_VIDEO_VBI, the following parameters must be filled out.

Parameter | Value
KS Datarange | KS_DATARANGE_VIDEO_VBI
KS Dataformat | KS_DATAFORMAT_VIDEO_VBI
KS MajorFormat | KS_DATAFORMAT_TYPE_VBI
KS SubFormat (typical) | KSDATAFORMAT_SUBTYPE_RAW8
KS Specifier | KSDATAFORMAT_SPECIFIER_VBI
Extended Header Size | KS_VBI_FRAME_INFO
DS majortype | MEDIATYPE_VBI
DS formattype | FORMAT_VBI


Raw NABTS Category

NABTS Category output pins provide a raw stream of decoded NABTS (North American Broadcast Teletext Standard) data.

When creating the category PinName, PINNAME_VIDEO_NABTS, the following parameters must be filled out. Note that the subformat is different for corrected NABTS and raw NABTS.

Parameter | Value
KS Datarange | KS_DATARANG
KS Dataformat | KS_DATAFORMAT
KS MajorFormat | KS_DATAFORMAT_TYPE_NABTS
KS SubFormat (typical) | KSDATAFORMAT_SUBTYPE_NABTS
KS Specifier | KSDATAFORMAT_SPECIFIER_NONE
Extended Header Size | 0
DS majortype | MEDIATYPE_VBI
DS formattype | FORMAT_VBI


Corrected NABTS Category

NABTS Category output pins provide a stream of decoded FEC-corrected NABTS (North American Broadcast Teletext Standard) data.

When creating the category PinName, PINNAME_VIDEO_NABTS, the following parameters must be filled out. Note that the subformat is different for corrected NABTS and raw NABTS.

Parameter | Value
KS Datarange | KS_DATARANGE
KS Dataformat | KS_DATAFORMAT
KS MajorFormat | KS_DATAFORMAT_TYPE_NABTS
KS SubFormat (typical) | KSDATAFORMAT_SUBTYPE_NABTS_FEC
KS Specifier | KSDATAFORMAT_SPECIFIER_NONE
Extended Header Size | 0
DS majortype | MEDIATYPE_VBI
DS formattype | FORMAT_VBI


TELETEXT Category

TELETEXT Category output pins provide a stream of decoded WST (World Standard Teletext) data.

When creating the category PinName, PINNAME_VIDEO_TELETEXT, the following parameters must be filled out.

Parameter | Value
KS Datarange | KS_DATARANGE_VIDEO_VBI
KS Dataformat | KS_DATAFORMAT_VIDEO_VBI
KS MajorFormat | KS_DATAFORMAT_TYPE_VBI
KS SubFormat (typical) | KSDATAFORMAT_SUBTYPE_TELETEXT
KS Specifier | KSDATAFORMAT_SPECIFIER_NONE
Extended Header Size | 0
DS majortype | MEDIATYPE_VBI
DS formattype | FORMAT_VBI


CC Category

CC Category output pins provide a stream of decoded, closed-caption byte pairs from field 1, line 21.

When creating the category PinName, PINNAME_VIDEO_CC, the following parameters must be filled out.

Parameter | Value
KS Datarange | KS_DATARANGE
KS Dataformat | KS_DATAFORMAT
KS MajorFormat | KSDATAFORMAT_TYPE_AUXLine21Data
KS SubFormat (typical) | KSDATAFORMAT_SUBTYPE_Line21_BytePair
KS Specifier | KSDATAFORMAT_SPECIFIER_NONE
Extended Header Size | 0
DS majortype | None
DS formattype | None


EDS Category

EDS (Extended Data Services) Category output pins provide a stream of decoded byte pairs from field 2, line 21.

When creating the category PinName, PINNAME_VIDEO_EDS, the following parameters must be filled out.

Parameter | Value
KS Datarange | KS_DATARANGE_VIDEO_EDS
KS Dataformat | KS_DATAFORMAT_VIDEO_VBI
KS MajorFormat | KSDATAFORMAT_TYPE_AUXLine21Data
KS SubFormat (typical) | KSDATAFORMAT_SUBTYPE_Line21_BytePair
KS Specifier | KSDATAFORMAT_SPECIFIER_NONE
Extended Header Size | 0
DS majortype | None
DS formattype | None


Timecode Category

Timecode Category output pins provide a stream of timecode.

When creating the category PinName, PINNAME_VIDEO_TIMECODE, the following parameters must be filled out.

Parameter | Value
KS Datarange | KS_DATARANGE_VIDEO_VBI
KS Dataformat | KS_DATAFORMAT_VIDEO_VBI
KS MajorFormat | To be determined
KS SubFormat (typical) | To be determined
KS Specifier | KSDATAFORMAT_SPECIFIER_NONE
Extended Header Size | 0
DS majortype | None
DS formattype | None


Videoport Category

Videoport Category streams are used to transfer image streams from an analog video decoder directly to DirectDraw surfaces through a hardware connection.

When creating the category PinName, PINNAME_VIDEO_VIDEOPORT, the following parameters must be filled out.

Parameter | Value
KS Datarange | KSDATARANGE
KS Dataformat | KSDATAFORMAT
KS MajorFormat | KSDATAFORMAT_TYPE_VIDEO
KS SubFormat (typical) | KSDATAFORMAT_SUBTYPE_VPVideo
KS Specifier | KSDATAFORMAT_SPECIFIER_NONE
Extended Header Size | 0
Required Property Sets | KSPROPSETID_VPConfig
Required Event Sets | KSEVENTSETID_VPNotify
DS majortype | None
DS formattype | None


Videoport VBI Category

Videoport VBI Category streams are used to transfer VBI streams from an analog decoder directly to DirectDraw surfaces through a hardware connection.

When creating the category PinName, PINNAME_VIDEO_VIDEOPORT_VBI, the following parameters must be filled out.

Parameter | Value
KS Datarange | KSDATARANGE
KS Dataformat | KSDATAFORMAT
KS MajorFormat | KSDATAFORMAT_TYPE_VIDEO
KS SubFormat (typical) | KSDATAFORMAT_SUBTYPE_VPVBIVideo
KS Specifier | KSDATAFORMAT_SPECIFIER_NONE
Extended Header Size | 0
Required Property Sets | KSPROPSETID_VPVBIConfig
Required Event Sets | KSEVENTSETID_VPVBINotify
DS majortype | None
DS formattype | None


Analog Video Category

The Analog Video Category represents the stream of analog video input to a video decoder.

When creating the category PinName, PINNAME_VIDEO_ANALOGVIDEOIN, the following parameters must be filled out.

Parameter | Value
KS Datarange | KS_DATARANGE_ANALOGVIDEO
KS Dataformat | KS_DATARANGE_ANALOGVIDEO
KS MajorFormat | KSDATAFORMAT_TYPE_ANALOGVIDEO
KS SubFormat (typical) | KSDATAFORMAT_SUBTYPE_NONE
KS Specifier | KSDATAFORMAT_SPECIFIER_ANALOGVIDEO
Extended Header Size | 0
Required Property Sets | None
Required Event Sets | None
DS majortype | MEDIATYPE_AnalogVideo
DS formattype | FORMAT_AnalogVideo

Although the Analog Video stream essentially models the input to the analog video decoder, it simultaneously acts as a data transport for tuning information. Tuning packets, originating at the TVTuner filter, are passed through any intervening crossbar filters at the start and end of every tuning operation. The data packet is a KS_TVTUNER_CHANGE_INFO, and contains the country/region code, channel, frequency, and analog video standard in use.

Capture filters must propagate this tuning packet in the extended header of VBI output streams to downstream VBI codecs.


Stream Formats

The range of potential formats for a stream is exposed from the minidriver through an array of KSDATARANGE structures. This structure describes image characteristics such as color format, bit depth, and cropping and scaling possibilities.

A specific format is described by a KSDATAFORMAT structure. A single KSDATARANGE can indicate thousands of potential KSDATAFORMAT structures. For example, a KSDATARANGE could specify RGB24 with a minimum size of 160x120 and a maximum size of 720x480, with size granularity step size in x and y of 1. From this, an application could request any of the over 200,000 possible output image dimensions through a unique KSDATAFORMAT structure.

Generally, DirectShow™ and WDM streaming share media format definitions and streaming conventions. This uniformity is somewhat obscured by the differences in naming conventions used by kernel and user-mode components. For example, many format and GUID definitions used in the kernel have the prefix "KS_" but are otherwise identical to their user-mode counterparts. BITMAPINFOHEADER is a user-mode definition, and KS_BITMAPINFOHEADER is the kernel version of the same structure.

Stream formats in the kernel are defined using the KSDATAFORMAT structure. This structure can be extended to include additional type-specific format information such as ranges or format structures.

typedef union {
  struct {
  ULONG  FormatSize;
  ULONG  Flags;
  ULONG  SampleSize;
  ULONG  Reserved;
  GUID   MajorFormat;
  GUID   SubFormat;
  GUID   Specifier;
  };
    ULONGLONG  Alignment;
} KSDATAFORMAT, *PKSDATAFORMAT, KSDATARANGE, *PKSDATARANGE;

Members

FormatSize
Specifies the size of the entire KSDATARANGE or KSDATAFORMAT structure, including any extended portion.
Flags
Specifies flags that are primarily used when querying the current data format from a pin or returning a data intersection. In most cases this is set to zero. These flags are ignored on making a connection.
SampleSize
Specifies either the sample size of the data if it is a fixed sample size, or it contains zero to indicate a variable sample size. This is also ignored on making a connection, and is used when negotiating allocators.
Reserved
Reserved. Must be set to zero.
MajorFormat
Specifies the major data format for this pin. See the table in Output Stream Groupings for more information. These data format identifiers are used both for this property and to identify specific data formats queried elsewhere. This maps to a DirectShow majortype.
SubFormat
Specifies the subformat for this pin. For instance, a codec may process a video stream, and this subformat information could indicate accepted general compression categories within the video major format. This maps to a DirectShow subtype.
Specifier
Specifies the type of structure which follows the base format information. This maps to a DirectShow formattype.

Comments

DirectShow uses a similar structure to define stream formats.

typedef struct  _AMMediaType    {
    GUID majortype;            // Same as KSDATAFORMAT.MajorFormat
    GUID subtype;              // Same as KSDATAFORMAT.SubFormat
    BOOL bFixedSizeSamples;
    BOOL bTemporalCompression;
    ULONG lSampleSize;         // Same as KSDATAFORMAT.SampleSize
    GUID formattype;           // Same as KSDATAFORMAT.Specifier
    IUnknown __RPC_FAR *pUnk;
    ULONG cbFormat;
    BYTE *pbFormat;
 } AM_MEDIA_TYPE;

Despite the differences in naming conventions, the GUID values used are identical in both of the structures above. Throughout the rest of this document, the WDM streaming naming conventions are used, followed when applicable by the corresponding DirectShow names.

For most video capture streams, the MajorFormat type is KSDATAFORMAT_TYPE_VIDEO (MEDIATYPE_Video), and the Specifier is FORMAT_VideoInfo. The subformat, along with the Format block, is used to convey details of the particular video data type, such as indicating the color space used.

Note that the low-order four bytes of the subformat should match the FOURCC values used in the BitmapInfoHeader.biCompression field. For example, the following GUID identifies the FOURCC (YVU9) video format.

39555659-0000-0010-8000-00AA00389B71
59 = 'Y'
56 = 'V'
55 = 'U'
39 = '9'


Video Stream Extended Headers

Each of the output streams from a video capture driver utilizes an extended header to provide auxiliary information about the stream and current frame contents. For example, image stream headers provide information about the current frame number, number of dropped frames, and field polarity flags. As each frame is completed, the driver must fill in the extended header with the auxiliary information about the frame captured.

Drivers must indicate to the stream class their ability to provide this additional information by setting the HW_STREAM_OBJECT.StreamHeaderMediaSpecific size according to the following table.

Category/PinName | Extended Header Size | Purpose
PINNAME_VIDEO _CAPTURE | KS_FRAME_INFO | Frame count, drop frame count, field polarity flags.
PINNAME_VIDEO _PREVIEW | KS_FRAME_INFO | Frame count, drop frame count, field polarity flags.
PINNAME_VIDEO _STILL | KS_FRAME_INFO | Frame count, drop frame count, field polarity flags
PINNAME_VIDEO _VBI | KS_VBI_FRAME_INFO | VBI format, channel change information, video standard.
PINNAME_VIDEO _NABTS | KS_VBI_FRAME_INFO | VBI format, channel change information, video standard.
PINNAME_VIDEO _CC | None | None
PINNAME_VIDEO _EDS | None | None
PINNAME_VIDEO _VIDEOPORT | None | None
PINNAME_VIDEO _VIDEOPORT_VBI | None | None
PINNAME_VIDEO _ANALOGVIDEOIN | None | None
PINNAME_VIDEO _TELETEXT | KS_VBI_FRAME_ INFO | VBI format, channel change information, video standard.
PINNAME_VIDEO _TIMECODE | None | None


Tuning Data Flow

VBI decoders need to be immediately informed of tuning changes. For example, as the tuner switches from Channel 3 to Channel 4, the VBI decoder must be notified at the beginning of the tuning operation so it can temporarily stop decoding during the period of signal instability. When the tuning operation completes, the VBI decoder must be notified of the new channel and any video standard or country/region code changes that may have occurred.

The tuning packet is propagated from the tuner, through the crossbar, then into the analog video input pin on the capture filter. The capture filter receives this tuning packet as a KS_TVTUNER_CHANGE_INFO on the analog video input pin.

The tuning packet must be propagated to any VBI output pins using the extended header described above. VBI decoders that operate as a chain must similarly propagate the extended header information from their input pins to their output pins.


Flow of Control for Video Capture

The flow of control for video capture involves initializing the driver, opening a stream, determining or updating the stream state, and capturing the stream. Topics in this section include:

Initialization

Opening a Stream

Streaming States

State Transitions

Capturing Video

Time Stamps


Initialization

The following steps are typically followed when initializing and using streaming minidrivers. These steps are not unique to streaming video. Also see the Stream Minidriver Design Guide.

When initializing and using streaming minidrivers

  1. The hardware adapter supported by the minidriver is detected by the Plug and Play enumerator.
  2. Plug and Play loads the minidriver and calls the minidriver's DriverEntry routine. A file object is created from the information in the DriverEntry routine.
  3. The minidriver calls the Stream class driver's StreamClassRegisterAdapter function and passes the HW_INITIALIZATION_DATA structure as a parameter. The HW_INITIALIZATION_DATA structure includes the addresses of minidriver functions that handle stream request block (SRB) command codes. This allows the minidriver to respond to SRB codes sent by the class driver. The extensions to the SRB command codes that are unique to capturing video are detailed in the SRB reference at the end of this document; a complete list of SRB Command Codes supported by the stream class is included in the Stream Class SRB Reference.


Opening a Stream

The following section describes the life of a video image data stream. Non-video streams, such as VBI, behave similarly but use different DATARANGE and DATAFORMAT structures.

Streams are opened using the SRB_OPEN_STREAM. Information passed in this SRB includes the index of the stream to open and a pointer to a pointer to a KS_VIDEOINFOHEADER structure. The stream index corresponds to the index of the stream in the array of KS_DATARANGE_VIDEO structures returned by the driver in response to SRB_GET_STREAM_INFO.

int StreamNumber = pSrb->StreamObject->StreamNumber;
PKS_DATAFORMAT_VIDEOINFOHEADER  pKSDataFormat =
    (PKS_DATAFORMAT_VIDEOINFOHEADER) pSrb->CommandData.OpenFormat;
PKS_VIDEOINFOHEADER pVideoInfoHdrRequested = &pKSDataFormat->VideoInfoHeader;

Drivers should verify that they can support the requested stream format. In particular, the contents of the KS_BITMAPINFOHEADER should be verified for correctness, along with cropping and scaling information specified by the rcSource and rcTarget rectangles.

Special rules apply when the output buffer is a DirectDraw surface. In this case, the BITMAPINFOHEADER.biWidth parameter actually represents the "stride" of the destination DirectDraw surface, which will typically be larger than the video image width. Therefore, to determine the requested image width, the following pseudocode should be used:

if (IsRectEmpty(&pVideoInfoHdrRequested->rcTarget) {
    Width =  pVideoInfoHdrRequested->bmiHeader.biWidth;
    Height = pVideoInfoHdrRequested->bmiHeader.biHeight;
}
else {
    Width = pVideoInfoHdrRequested->rcTarget.right –
            pVideoInfoHdrRequested->rcTarget.left;
    Height = pVideoInfoHdrRequested->rcTarget.bottom –
             pVideoInfoHdrRequested->rcTarget.top;
}


Streaming States

Each stream provided by the driver exists in one of three states: stopped, paused, or running. Upon initialization, the stream is, by definition, in the Stopped state. Transitions to the other states are made through SRB_SET_STREAM_STATE.

State | Description
KSSTATE_STOP | Using absolute minimum of resources. No outstanding data SRBs at the driver.
KSSTATE_ACQUIRE | Acquiring resources. This state does not have an analog in DirectShow.
KSSTATE_PAUSE | Preparing to instantly make transition to the Run state. Allocating all needed resources such as bandwidth on USB and 1394.
KSSTATE_RUN | Streaming. Fill buffers and complete SRBs through CompleteStreamSRB.


State Transitions

To ensure orderly resource allocation, only a subset of the possible state transitions are allowed. The following table lists the allowed transitions along with tasks that the driver will typically perform.

Transition | Description
Stop to Pause | Allocate resources. The read SRBs are typically queued after the transition to the Pause state has completed.
Pause to Run | Begin streaming.
Run to Pause | Stop streaming. The outstanding read SRBs remain in the queue.
Pause to Stop | Deallocate resources and complete all outstanding read SRBs. SRBs that have not been filled with an image are completed with zero length in the KSSTREAM_HEADER.DataUsed field.

Note that the transitions may cycle multiple times between the Pause and Run state before returning to the Stop state. Drivers should expect transitions such as:

stop -> pause -> run -> pause -> run -> pause -> stop.

When a stream is in the Stopped state, it must immediately complete all outstanding data-read SRBs.

Since a user mode application can terminate unexpectedly while streaming, all capture drivers must accept an SRB_CLOSE_STREAM at any time. Under these conditions, all outstanding buffers are canceled by the stream class through the cancel routine immediately before the SRB_CLOSE_STREAM is received. Note however, that the Stream state may not be set to the stopped state prior to the termination.


Capturing Video

Once the stream is in the running state, the capture process begins. Based on the frame interval specified by AvgTimePerFrame, the stream transfers images into buffers passed through SRB_READ_DATA. Additional information about the image captured is returned in the KS_CAPTURE_FRAME_INFO structure that is appended to the end of the KSSTREAM_HEADER structure.

PKSSTREAM_HEADER            pDataPacket = pSrb->CommandData.DataBufferArray;
PKS_CAPTURE_FRAME_INFO      pFrameInfo = (PKS_CAPTURE_FRAME_INFO) (pDataPacket + 1);

The driver should set additional information fields about the data captured such as frames captured, frames dropped, and field polarity.

*pFrameInfo = pStrmEx->FrameInfo;

Next, the driver should set the discontinuity flag if frames have been previously dropped, and then reset its internal flag.

if (pStrmEx->fDiscontinuity) {
    pDataPacket->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY;
    pStrmEx->fDiscontinuity = FALSE;
}

CompleteStreamSRB (
        pSrb,
        StreamRequestComplete,
        TRUE,
        ReadyForNextStreamDataRequest);


Time Stamps

DirectShow™ and WDM streaming both utilize time stamps to synchronize multiple data streams. Time is measured in 100 nanosecond (ns) units. Kernel-mode clocks begin counting time when they first transition out of the stopped state. Thereafter, time increases monotonically until the stream again transitions to the stopped state.

Each data packet transferred corresponds to a single frame or field of video or ancillary data. Capture drivers that are concerned with frame-accurate video capture can choose to provide a clock that all other filters can use for time stamping. Alternatively, capture drivers that run asynchronously to other multimedia streams, such as USB and 1394 conferencing cameras, should time stamp their packets using a clock provided by other components, such as an audio digitizer.

Capture drivers indicate they are able to provide a master clock by setting the following values in the HW_STREAM_OBJECT:

PHW_STREAM_OBJECT *pStreamObject;

PStreamObject->HWClockFunction = (PHW_CLOCK_FUNCTION)StreamClockRtn;

PStreamObject->ClockSupportFlags =
    CLOCK_SUPPORT_CAN_READ_ONBOARD_CLOCK |
    CLOCK_SUPPORT_CAN_RETURN_STREAM_TIME;


SRB Code Reference for Video Capture

SRB command codes used by the stream class are fully defined in Stream Class Driver Reference. This section describes extensions to the SRB definitions that are unique to capturing video.


Medium GUIDs

Breaking apart the Tuner, Crossbar, Capture, and TvAudio components into separate filters results in the need to provide a means to correctly describe the topological connectivity between components. Medium GUIDs are used to describe a hardware connection, and this value is used by graph builders to construct graphs.

Mediums are exposed by the KSPIN_MEDIUM structure, which consists of a GUID (Set) followed by two ULONGs (Id and Flags). The KSPIN_MEDIUM.Set should be assigned a unique GUID representing a hardware connection. The KSPIN_MEDIUM.Id should be set to an instance value, and KSPIN_MEDIUM.Flags should be zero. This allows installation of multiple instances of the same hardware.


Property Sets for Video Capture

The following property sets are defined for video capture. Each property set definition begins with the GUID used to access the property set, along with the DirectShow™ interface used to access the properties from user mode applications.

The video capture property sets include:

PROPSETID_VIDCAP_VIDEOPROCAMP

PROPSETID_TUNER

PROPSETID_VIDCAP_TVAUDIO

PROPSETID_VIDCAP_CROSSBAR

PROPSETID_VIDCAP_VIDEODECODER

PROPSETID_VIDCAP_VIDEOENCODER

PROPSETID_VIDCAP_CAMERACONTROL

PROPSETID_VIDCAP_VIDEOCOMPRESSION

PROPSETID_VIDCAP_VIDEOCONTROL

Also included in this section is an explanation of the analog video standards supported and a discussion on how to set range and default values for properties.

KS_AnalogVideoStandard

Range and Default Values

The following table lists the correspondence between DirectShow interfaces and driver property sets. DirectShow interfaces are defined in the files control.odl and control.h. Property sets are defined in the files ksmedia.h and ks.h.

Property Set | DirectShow Interface
PROPSETID_TUNER | IAMTVTuner
PROPSETID_VIDCAP_TVAUDIO | IAMTVAudio
PROPSETID_VIDCAP_CROSSBAR | IAMCrossbar
PROPSETID_VIDCAP_VIDEOPROCAMP | IAMVideoProcAmp
PROPSETID_VIDCAP_VIDEODECODER | IAMAnalogVideoDecoder
PROPSETID_VIDCAP_VIDEOENCODER | IAMAnalogVideoEncoder
PROPSETID_VIDCAP_CAMERACONTROL | IAMCameraControl
PROPSETID_VIDCAP_VIDEOCOMPRESSION | IAMVideoCompression
PROPSETID_VIDCAP_VIDEOCONTROL | IAMVideoControl


KS_AnalogVideoStandard

The KS_AnalogVideoStandard is used to identify the various aspects of analog broadcast video. A number of the property sets for video use these values to select or describe format capabilities.

The following is a list of available values of type KS_AnalogVideoStandard:

KS_AnalogVideo_None (This is a digital sensor)

KS_AnalogVideo_NTSC_M (75 IRE Setup)

KS_AnalogVideo_NTSC_M_J (For Japan, 0 IRE Setup)

KS_AnalogVideo_NTSC_433

KS_AnalogVideo_PAL_B

KS_AnalogVideo_PAL_D

KS_AnalogVideo_PAL_G

KS_AnalogVideo_PAL_H

KS_AnalogVideo_PAL_I

KS_AnalogVideo_PAL_M

KS_AnalogVideo_PAL_N

KS_AnalogVideo_PAL_60

KS_AnalogVideo_SECAM_B

KS_AnalogVideo_SECAM_D

KS_AnalogVideo_SECAM_G

KS_AnalogVideo_SECAM_H

KS_AnalogVideo_SECAM_K

KS_AnalogVideo_SECAM_K1

KS_AnalogVideo_SECAM_L

KS_AnalogVideo_SECAM_L1


Range and Default Values

Several properties can support range and default values. These values can be added by using a static table. More information will be provided in a future draft.


PROPSETID_VIDCAP_VIDEOPROCAMP

The PROPSETID_VIDCAP_VIDEOPROCAMP property set is used to adjust image color attributes in either analog or digital domains.

Property Set GUID | PROPSETID_VIDCAP_VIDEOPROCAMP
DirectShow Interface | IAMVideoProcAmp

The property set includes the structures of type KSPROPERTY_VIDCAP_VIDEOPROCAMP:

KSPROPERTY_VIDEOPROCAMP_BRIGHTNESS

KSPROPERTY_VIDEOPROCAMP_CONTRAST

KSPROPERTY_VIDEOPROCAMP_HUE

KSPROPERTY_VIDEOPROCAMP_SATURATION

KSPROPERTY_VIDEOPROCAMP_SHARPNESS

KSPROPERTY_VIDEOPROCAMP_GAMMA

KSPROPERTY_VIDEOPROCAMP_COLORENABLE

KSPROPERTY_VIDEOPROCAMP_WHITEBALANCE

KSPROPERTY_VIDEOPROCAMP_BACKLIGHT_COMPENSATION

All properties within this property set use the same structure to set and retrieve individual properties.

typedef struct {
  KSPROPERTY  Property;
  LONG  Value;
  ULONG  Flags;
  ULONG  Capabilities;
} KSPROPERTY_VIDEOPROCAMP_S;

Members

Property
Specifies the property used.
Value
Specifies values unique to that property. See the individual property for information on the range and default value for this member.
Flags
Contains the flags described in the following table.
Capabilities
Contains the flags described in the following table.

The following table describes the values for KSPROPERTY_VIDEOPROCAMP_S.Flags and KSPROPERTY_VIDEOPROCAMP_S.Capabilities.

Flag | Description
KSPROPERTY_VIDEOPROCAMP_ FLAGS_MANUAL | Specifies that the property is to be adjusted manually.
KSPROPERTY_VIDEOPROCAMP_ FLAGS_AUTO | Specifies that the property is to be adjusted automatically.

Each property also includes a range and default value, the KSPROPERTY_VIDEOPROCAMP_S.Value. The range for the property set is defined in real world units to allow programmatic control of parameters. Since actual hardware is often limited in how closely it can approximate this ideal, each device can also define a subset of this theoretical range and the step size. This allows controls such as sliders and scroll bars to be programmed to give a visible effect for each step.

The following is an example, using the Brightness property. The overall, theoretical range for brightness is defined as –100 to 100 IRE units. IRE is an NTSC-centric measure of video levels where zero corresponds to the blanking, or full-black level, and 100 represents pure white. If a VideoProcAmp were able to shift a pure black input signal (perhaps generated by completely covering the camera lens) and cause it to appear as pure white, then its range would be zero to 100 IRE.

Note The actual values used in the property sets are multiplied by 100 to give improved granularity.

Most VideoProcAmps actually provide a limited range of brightness control. One way to measure the range is to cover the camera lens and determine the output signal over the range of adjustment, and then normalize this to IRE units.

After the range has been calculated, determine the SteppingValue by taking the maximum and minimum values and dividing by the number of adjustment steps.


KSPROPERTY_VIDEOPROCAMP_BRIGHTNESS

The KSPROPERTY_VIDEOPROCAMP_BRIGHTNESS read/write property is used to set and retrieve the brightness setting. Brightness is also known as black level. Modifying the brightness setting shifts the entire video signal equally for all luminance values.

The KSPROPERTY_VIDEOPROCAMP_S.Value member specifies the brightness value expressed in IRE units * 100 for NTSC. For non-NTSC sources, the units are arbitrary, with zero representing blanking and 10000 representing pure white. The range for Value is –10000 to 10000; the default value is 750 (7.5 IRE).


KSPROPERTY_VIDEOPROCAMP_CONTRAST

The KSPROPERTY_VIDEOPROCAMP_CONTRAST read/write property is used to set and retrieve the contrast or luma gain setting.

The KSPROPERTY_VIDEOPROCAMP_S.Value member specifies the contrast value expressed as a gain factor * 100. The Value range is from zero to 10000, and the default is 100 (1x). Note that a particular device may only implement a subset of this range.


KSPROPERTY_VIDEOPROCAMP_SATURATION

The KSPROPERTY_VIDEOPROCAMP_SATURATION read/write property is used to set and retrieve the saturation or chroma gain setting.

The KSPROPERTY_VIDEOPROCAMP_S.Value member specifies the saturation or chroma gain value expressed as gain * 100. Value ranges from zero to 10000, and the default is 100 (1x). Note that a particular device may only implement a subset of this range.


KSPROPERTY_VIDEOPROCAMP_SHARPNESS

The KSPROPERTY_VIDEOPROCAMP_SHARPNESS read/write property is used to set and retrieve the sharpness setting.

The KSPROPERTY_VIDEOPROCAMP_S.Value member specifies the sharpness value expressed in arbitrary units. Value ranges from zero to 100, and the default of 50. Note that a particular device may only implement a subset of this range.


KSPROPERTY_VIDEOPROCAMP_GAMMA

The KSPROPERTY_VIDEOPROCAMP_GAMMA read/write property is used to set and retrieve the gamma setting.

The KSPROPERTY_VIDEOPROCAMP_S.Value member specifies the gamma value expressed gamma * 100. Value ranges from 1 to 500, and the default is 100 (gamma = 1). Note that a particular device may only implement a subset of this range.


KSPROPERTY_VIDEOPROCAMP_COLORENABLE

The KSPROPERTY_VIDEOPROCAMP_COLORENABLE read/write property is used to set and retrieve the color enable setting.

The KSPROPERTY_VIDEOPROCAMP_S.Value member specifies the color enable setting which is a Boolean value. Value ranges from zero to 1, and the default is 1.


KSPROPERTY_VIDEOPROCAMP_WHITEBALANCE

The KSPROPERTY_VIDEOPROCAMP_WHITEBALANCE read/write property is used to set and retrieve the white balance setting. The KSPROPERTY_VIDEOPROCAMP_S.Value member specifies the white balance setting expressed as a color temperature in degrees Kelvin. The range and default values for this property are device dependent.


KSPROPERTY_VIDEOPROCAMP_BACKLIGHT_COMPENSATION

The KSPROPERTY_VIDEOPROCAMP_BACKLIGHT_COMPENSATION read/write property is used to set and retrieve the backlight compensation setting. The KSPROPERTY_VIDEOPROCAMP_S.Value member specifies the backlight compensation setting, which is a Boolean. Zero indicates backlight compensation is disabled, and 1 indicates backlight compensation is enabled.


PROPSETID_TUNER

The PROPSETID_TUNER property set controls broadcast or cable television tuner devices. The property set supports multistandard video tuners as well as tuners with multiple inputs.

Property Set GUID | PROPSETID_TUNER
DirectShow Interface | IAMTVTuner

The property set includes the following of type KSPROPERTY_TUNER:

KSPROPERTY_TUNER_CAPS

KSPROPERTY_TUNER_MODE_CAPS

KSPROPERTY_TUNER_MODE

KSPROPERTY_TUNER_STANDARD

KSPROPERTY_TUNER_FREQUENCY

KSPROPERTY_TUNER_INPUT

KSPROPERTY_TUNER_STATUS

Also covered in this section are several enumerated types used with tuners, including:

KS_TUNER_STRATEGY

KSPROPERTY_TUNER_MODES

Drivers are only required to handle tuning by frequency. Worldwide channel-to-frequency mapping tables are maintained in the DirectShow filter, which can also optionally handle fine tuning. Fine tuning is an iterative process utilizing a search for the best possible signal through a channel frequency band.


KS_TUNER_STRATEGY

Drivers can implement one of three methods for fine tuning, depending on their hardware capabilities.

typedef enum {
    KS_TUNER_STRATEGY_PLL             = 0X01,
    KS_TUNER_STRATEGY_SIGNAL_STRENGTH = 0X02,
    KS_TUNER_STRATEGY_DRIVER_TUNES    = 0X04,
}KS_TUNER_STRATEGY;
KS_TUNER_STRATEGY Types | Description
KS_TUNER_STRATEGY_PLL | Used by devices that can indicate tuning accuracy by measuring a PLL offset.
KS_TUNER_STRATEGY_ SIGNAL_STRENGTH | Used by drivers that indicate tuning accuracy by signal strength. The DirectShow filter performs fine tuning based on feedback returned by the driver for both of these strategies.
KS_TUNER_STRATEGY_ DRIVER_TUNES | Used by drivers that want total control over the fine tuning process.


KSPROPERTY_TUNER_MODES

Drivers can implement several different modes for tuning using the KSPROPERTY_TUNER_MODES types.

typedef enum {
    KSPROPERTY_TUNER_MODE_TV            = 0X0001,
    KSPROPERTY_TUNER_MODE_FM_RADIO      = 0X0002,
    KSPROPERTY_TUNER_MODE_AM_RADIO      = 0X0004,
    KSPROPERTY_TUNER_MODE_DSS           = 0X0008,
} KSPROPERTY_TUNER_MODES;
KSPROPERTY_TUNER_MODES Types | Description
KSPROPERTY_TUNER_ MODE_TV | Specifies the tuner is actively tuning broadcast or cable television channels.
KSPROPERTY_TUNER_ MODE_FM_RADIO | Specifies the tuner is actively tuning FM radio channels.
KSPROPERTY_TUNER_ MODE_AM_RADIO | Specifies the tuner is actively tuning AM radio channels.
KSPROPERTY_TUNER_ MODE_DSS | Specifies the tuner is actively tuning DSS channels.


KSPROPERTY_TUNER_CAPS

The KSPROPERTY_TUNER_CAPS read-only property identifies the hardware capabilities of the tuner. In response to this property request, the driver returns the following structure.

typedef struct {
  KSPROPERTY  Property;
  ULONG  ModesSupported;
  KSPIN_MEDIUM  VideoMedium;
  KSPIN_MEDIUM  TVAudioMedium;
  KSPIN_MEDIUM  RadioAudioMedium;
} KSPROPERTY_TUNER_CAPS_S, *PKSPROPERTY_TUNER_CAPS_S;

Members

Property
Specifies the KSProperty.
ModesSupported
Specifies one or more KSPROPERTY_TUNER_MODES values. This defines the tuning capabilities of the device.
VideoMediumGUID
Specifies a unique GUID representing the hardware connection of the analog video signal. This value is used to enforce connections between filters. Possible values are NULL, indicating no pin is created; GUID_NULL, indicating Medium is not used to enforce connections; or a GUID. If a GUID value is used, only crossbar pins with a matching Medium GUID are allowed to connect.
TVAudioMediumGUID
Specifies a unique GUID representing the hardware connection of the TV audio signal. This value is used to enforce connections between filters. Possible values are NULL, indicating no pin is created; GUID_NULL, indicating Medium is not used to enforce connections; or a GUID. If a GUID value is used, only crossbar pins with a matching Medium GUID are allowed to connect.
RadioAudioMediumGUID
Specifies a unique GUID representing the hardware connection of the analog radio audio signal. This value is used to enforce connections between filters. Possible values are NULL, indicating no pin is created; GUID_NULL, indicating Medium is not used to enforce connections; or a GUID. If a GUID value is used, only crossbar pins with a matching Medium GUID are allowed to connect.


KSPROPERTY_TUNER_MODE_CAPS

The KSPROPERTY_TUNER_MODE_CAPS read-only property identifies the mode capacities of the tuner. In response to this property request, the driver returns the following structure.

typedef struct {
  KSPROPERTY Property;
  ULONG  Mode;
  ULONG  StandardsSupported;
  ULONG  MinFrequency;
  ULONG  MaxFrequency;
  ULONG  TuningGranularity;
  ULONG  NumberOfInputs;
  ULONG  SettlingTime;
  ULONG  Strategy;
} KSPROPERTY_TUNER_MODE_CAPS_S, *PKSPROPERTY_TUNER_MODE_CAPS_S;

Members

Property
Specifies the property used.
Mode
Specifies a KSPROPERTY_TUNER_MODES value.
StandardsSupported
Specifies the video standards supported by the device. Support for multiple standards by bitwise OR of KS_AnalogVideo_*
MinFrequency
Specifies the lowest frequency supported by the tuner expressed in Hz.
MaxFrequency
Specifies the highest frequency supported by the tuner expressed in Hz.
TuningGranularity
Specifies the granularity of tuning expressed in Hz.
NumberOfInputs
Specifies the number of inputs on the tuner.
SettlingTime
Specifies the settling time when changing frequencies expressed in milliseconds.
Strategy
Specifies the method of tuning using KS_TUNER_STRATEGY.


KSPROPERTY_TUNER_MODE

The KSPROPERTY_TUNER_MODE read/write property set can be used to set the mode of the tuner. For example, if a tuner is capable of supporting both FM and TV tuning, this property is used to select and report the current mode of operation.

typedef struct {
  KSPROPERTY  Property;
  ULONG  Mode;
} KSPROPERTY_TUNER_MODE_S, *PKSPROPERTY_TUNER_MODE_S;

Members

Property
Specifies the property used.
Mode
Specifies the mode using values from KSPROPERTY_TUNER_MODES.


KSPROPERTY_TUNER_STANDARD

The KSPROPERTY_TUNER_STANDARD read only property is used to set and retrieve the current analog video standard. This property is only used when the current mode is KSPROPERTY_TUNER_MODE_TV. The following structure is used to communicate the standard.

typedef struct {
  KSPROPERTY  Property;
  ULONG      Standard;
} KSPROPERTY_TVTUNER_STANDARD_S, *PKSPROPERTY_TVTUNER_STANDARD_S;

Members

Property
Specifies the property used.
Standard
Specifies the video standard using KS_AnalogVideoStandard.


KSPROPERTY_TUNER_FREQUENCY

The KSPROPERTY_TUNER_FREQUENCY write-only property is used to get or set the tuning frequency.

typedef struct {
  KSPROPERTY Property;
  ULONG  Frequency;  // Hz
  ULONG  LastFrequency;  // Hz (last known good)
  ULONG  TuningFlags;  // KS_TUNER_TUNING_FLAGS
  ULONG  VideoSubChannel;  // DSS
  ULONG  AudioSubChannel;  // DSS
  ULONG  Channel;  // VBI decoders
  ULONG  Country;  // VBI decoders
} KSPROPERTY_TUNER_FREQUENCY_S, *PKSPROPERTY_TUNER_FREQUENCY_S;

Members

Property
Specifies the property used.
Frequency
Specifies the frequency in Hz.
LastFrequency
Specifies the last known fine tune frequency. This field is provided only for drivers that implement the KS_TUNER_STRATEGY of KS_TUNER_STRATEGY_DRIVER_TUNES as a starting point when beginning a new fine tune operation.
TuningFlags
Specifies how the driver should proceed with the fine tuning operation using KS_TUNER_TUNING_FLAGS. The following flags are provided.
Flag | Description
KS_TUNER_TUNING_EXACT | Specifies that the tuner should tune directly to Frequency, bypassing any fine tuning logic.
KS_TUNER_TUNING_FINE | Specifies the tuning operation should perform a comprehensive search for the best tuning. This flag is only used if the strategy is KS_TUNER_STRATEGY_DRIVER_TUNES.
KS_TUNER_TUNING_COARSE | Specifies that the tuning operation should perform a fast search, attempting only to determine if a valid signal is present. This flag is only used if the strategy is KS_TUNER_STRATEGY_DRIVER_TUNES.

VideoSubChannel
Specifies a video subchannel for digital television sources.
AudioSubChannel
Specifies an audio subchannel for digital television sources.
Channel
Specifies the TV channel when the tuning mode is equal to KSPROPERTY_TUNER_MODE_TV.
Country
Specifies the current country/region code for the tuning operation. Country/region codes follow the TAPI country/region code values which correspond to the International long distance dialing codes.


KSPROPERTY_TUNER_INPUT

The KSPROPERTY_TUNER_INPUT read/write property is used to specify the input connector.

typedef struct {
  KSPROPERTY  Property;
  ULONG  InputIndex;
} KSPROPERTY_TUNER_INPUT_S, *PKSPROPERTY_TVTUNER_INPUT_S;

Members

Property
Specifies the property used.
InputIndex
Specifies the input connection. This value must be in the range of zero to (NumberOfInputs – 1).


KSPROPERTY_TUNER_STATUS

The KSPROPERTY_TUNER_STATUS read-only property is used to retrieve information about the tuning process, including the current frequency.

typedef struct {
  KSPROPERTY  Property;
  ULONG  CurrentFrequency;
  ULONG  PLLOffset;
  ULONG  SignalStrength;
  ULONG  Busy;
} KSPROPERTY_TUNER_STATUS_S, *PKSPROPERTY_TVTUNER_STATUS_S;

Members

Property
Specifies the property used.
CurrentFrequency
Specifies the current frequency in Hertz (Hz).
PLLOffset
Specifies the PLL offset in multiples of the tuning granularity. This is used if the KS_TUNER_STRATEGY is KS_TUNER_STRATEGY_PLL.
SignalStrength
Specifies the amplitude of the signal. This is used if the KS_TUNER_STRATEGY is KS_TUNER_STRATEGY_SIGNAL_STRENGTH.


PROPSETID_VIDCAP_VIDEOENCODER

The PROPSETID_VIDCAP_VIDEOENCODER property set is used to control analog video encoders. An analog video encoder converts digital video streams in formats such as YUV or RGB into baseband analog video signals.

GUID | PROPSETID_VIDCAP_VIDEOENCODER
DirectShow Interface | IAMAnalogVideoEncoder

The property set includes the following of type KSPROPERTY_VIDCAP_VIDEOENCODER:

KSPROPERTY_VIDEOENCODER_CAPS

KSPROPERTY_VIDEOENCODER_STANDARD

KSPROPERTY_VIDEOENCODER_COPYPROTECTION

KSPROPERTY_VIDEOENCODER_CC_ENABLE

All properties within this property set use the same structure to set and retrieve individual properties.

typedef struct {
  KSPROPERTY  Property;
  LONG  Value;
  ULONG  Flags;
  ULONG  Capabilities;
} KSPROPERTY_VIDEOENCODER_S, *PKSPROPERTY_VIDEOENCODER_S;

Members

Property
Specifies the property used.
Value
Specifies values unique to that property set. See the individual property sets for information on the range and default value for this member.
Flags
To be determined.
Capabilities
To be determined.


KSPROPERTY_VIDEOENCODER_CAPS

The KSPROPERTY_VIDEOENCODER_CAPS read-only property is used to determine the capacities of the video encoder.


KSPROPERTY_VIDEOENCODER_STANDARD

The KSPROPERTY_VIDEOENCODER_STANDARD read/write property is used to set or get the supported analog video standard for the video encoder.


KSPROPERTY_VIDEOENCODER_COPYPROTECTION

The KSPROPERTY_VIDEOENCODER_COPYPROTECTION read/write property is used to set or get the supported copy protection scheme for the video encoder. This property is optional.


KSPROPERTY_VIDEOENCODER_CC_ENABLE

The KSPROPERTY_VIDEOENCODER_CC_ENABLE read/write property is used to enable or disable close captioning for the video encoder. This property is optional.


PROPSETID_VIDCAP_VIDEODECODER

The PROPSETID_VIDCAP_VIDEODECODER property set is used to control an analog video decoder. An analog video decoder converts baseband analog video signals into a digital format such as RGB or YUV.

GUID | PROPSETID_VIDCAP_VIDEODECODER
DirectShow Interface | IAMAnalogVideoDecoder

The property set includes the following of type KSPROPERTY_VIDCAP_VIDEODECODER:

KSPROPERTY_VIDEODECODER_CAPS (Read Only)

KSPROPERTY_VIDEODECODER_STANDARD (Read/Write)

KSPROPERTY_VIDEODECODER_STATUS (Read Only)

KSPROPERTY_VIDEODECODER_OUTPUT_ENABLE (Read/Write)

KSPROPERTY_VIDEODECODER_VCR_TIMING (Read/Write)


KSPROPERTY_VIDEODECODER_CAPS

The KSPROPERTY_VIDEODECODER_CAPS read-only property identifies the hardware capabilities of the analog video decoder. In response to this property request, the driver returns the following structure:

typedef struct {
  KSPROPERTY  Property;
  ULONG  StandardsSupported;
  ULONG  Capabilities;
  ULONG  SettlingTime;
  LONG   HSyncPerVSync;
 } KSPROPERTY_VIDEODECODER_CAPS_S, *PKSPROPERTY_VIDEODECODER_CAPS_S;

Members

Property
Specifies the property used.
StandardsSupported
Specifies the video standards supported by the device. Support for multiple standards by bitwise OR of KS_AnalogVideo_*r.
Capabilities
Specifies a flag based on KS_VIDEODECODER_FLAGS. The following flags are provided.
Flag Description
KS_VIDEODECODER_FLAGS_
CAN_DISABLE_OUTPUT 		Specifies that the decoder can tri-state its output lines. This flag is only important for video decoders which use a video port.
KS_VIDEODECODER_FLAGS_
CAN_USE_VCR_LOCKING 		Specifies that the video decoder can alter its PLL timings to lock onto noisy signals. This is typically used when the video source is a VCR that introduces variability in the vertical and horizontal sync timing.
KS_VIDEODECODER_FLAGS_
CAN_INDICATE_LOCKED 		Specifies that the video decoder can indicate whether it has locked to an incoming analog video signal.g.

KSPROPERTY_VIDEODECODER_CAPS_S.Capabilities uses the following flags:

typedef enum {
    KS_VIDEODECODER_FLAGS_CAN_DISABLE_OUTPUT  = 0X0001,
    KS_VIDEODECODER_FLAGS_CAN_USE_VCR_LOCKING = 0X0002,
    KS_VIDEODECODER_FLAGS_CAN_INDICATE_LOCKED = 0X0004,
}KS_VIDEODECODER_FLAGS;
SettlingTime
Specifies the settling time when changing input video sources expressed in milliseconds.
HSyncPerVSync
Specifies the number of horizontal sync pulses the video decoder produces during the vertical sync period. Decoders that follow the ITU-656 should set this value to six.


KSPROPERTY_VIDEODECODER_STANDARD

The KSPROPERTY_VIDEODECODER_STANDARD read/write property is used to set and retrieve the current analog video standard. The following structure is used to indicate the standard:

typedef struct {
  KSPROPERTY  Property;
  ULONG  Value;
} KSPROPERTY_VIDEODECODER_S, *PKSPROPERTY_VIDEODECODER_S;

Members

Property
Specifies the property used.
Value
Specifies the value to be set or retrieved.

The KSPROPERTY_VIDEODECODER_S.Value member specifies the current analog video standard using one of the values in KS_AnalogVideoStandard.


KSPROPERTY_VIDEODECODER_STATUS

The KSPROPERTY_VIDEODECODER_STATUS read-only property is used to retrieve status information from the video decoder.

typedef struct {
  KSPROPERTY  Property;
  ULONG  NumberOfLines;
  ULONG  SignalLocked;
} KSPROPERTY_VIDEODECODER_STATUS_S, *PKSPROPERTY_VIDEODECODER_STATUS_S;

Members

Property
Specifies the property used.
NumberOfLines
Specifies the number of lines detected in the incoming analog video signal.
SignalLocked
Indicates if the signal is locked. Zero indicates that the signal is not locked, 1 indicates that it is.


KSPROPERTY_VIDEODECODER_OUTPUT_ENABLE

The KSPROPERTY_VIDEODECODER_OUTPUT_ENABLE read/write property is used to tri-state the output of video decoders that reside on a shared video port bus. This property uses the KSPROPERTY_VIDEODECODER_S structure to set or retrieve information. This property is optional.

typedef struct {
  KSPROPERTY  Property;
  ULONG  Value;
} KSPROPERTY_VIDEODECODER_S, *PKSPROPERTY_VIDEODECODER_S;

Members

Property
Specifies the property used.
Value
Specifies the value to be set or retrieved.

The KSPROPERTY_VIDEODECODER_S.Value member specifies whether to tri-state the output. Zero indicates tri-state output, and 1 indicates that the device is actively driving the video port bus.


KSPROPERTY_VIDEODECODER_VCR_TIMING

The KSPROPERTY_VIDEODECODER_VCR_TIMING read/write property is used to control whether the VCR is expecting video from a tape source or a broadcast source. The timing accuracy of synchronization pulses on tape sources is typically poorer from tape sources than broadcast sources. This property uses the KSPROPERTY_VIDEODECODER_STANDARD_S structure to set or retrieve information. This property is optional.

typedef struct {
  KSPROPERTY  Property;
  ULONG  Value;
} KSPROPERTY_VIDEODECODER_S, *PKSPROPERTY_VIDEODECODER_S;

Members

Property
Specifies the property used.
Value
Specifies the value to be set or retrieved.

The KSPROPERTY_VIDEODECODER_S.Value member specifies whether to use VCR timing. Zero indicates a source other than tape, and 1 indicates a tape source.


PROPSETID_VIDCAP_CAMERACONTROL

The PROPSETID_VIDCAP_CAMERACONTROL property set is used to adjust or inquire about camera control settings. The controls available are a subset of the proposed ITU T.RDC standard. All the properties within this property set are considered optional.

Note that camera device should use the VideoProcAmp property set to adjust qualities such as brightness, contrast, hue, and saturation.

GUID | PROPSETID_VIDCAP_CAMERACONTROL
DirectShow Interface | IAMCameraControl
Property Structure | KSSTRUCT_VIDCAP_CAMERACONTROL

The properties include the following of type KSPROPERTY_VIDCAP_CAMERACONTROL:

KSPROPERTY_CAMERACONTROL_PAN

KSPROPERTY_CAMERACONTROL_TILT

KSPROPERTY_CAMERACONTROL_ROLL

KSPROPERTY_CAMERACONTROL_ZOOM

KSPROPERTY_CAMERACONTROL_EXPOSURE

KSPROPERTY_CAMERACONTROL_IRIS

KSPROPERTY_CAMERACONTROL_FOCUS

All properties within this property set use the same structure to set and retrieve individual properties.

typedef struct {
  KSPROPERTY Property;
  LONG  Value;
  ULONG  Flags;
  ULONG  Capabilities;
} KSPROPERTY_CAMERACONTROL_S, *PKSPROPERTY_CAMERACONTROL_S;

Members

Property
Specifies the property used.
Value
Specifies values unique to that property. See the individual property for information on the range and default value for this member.
Flags
Specifies the flag from KSPROPERTY_CAMERACONTROL_FLAGS_*. See the table below for a list of the flags provided.
Capabilities
Specifies the capabilities from KSPROPERTY_CAMERACONTROL_FLAGS_*. See the table below for a list of the flags provided.

The following table describes the values for KSPROPERTY_CAMERACONTROL_S.Flags and KSPROPERTY_CAMERACONTROL_S.Capabilities.

Flag | Description
KSPROPERTY_CAMERACONTROL_ FLAGS_MANUAL | Specifies that the setting is controlled manually.
KSPROPERTY_CAMERACONTROL_ FLAGS_AUTO | Specifies that the setting is controlled automatically.
KSPROPERTY_CAMERACONTROL_ FLAGS_ABSOLUTE | Specifies that the setting is in absolute values.
KSPROPERTY_CAMERACONTROL_ FLAGS_RELATIVE | Specifies that the setting is in relative values.

Each property also includes a range and default value, the KSPROPERTY_CAMERACONTROL_S.Value. The range for the property set is defined in real world units to allow programmatic control of parameters. Since actual hardware is often limited in how closely it can approximate this ideal, each device can also define a subset of this theoretical range and the size of adjustment steps.

For those properties that involve camera positioning, the point of reference is the camera imaging plane looking outward at the image being captured. Positive positioning values are generally clockwise from the origin, and negative positioning values are counterclockwise from the point of origin.


KSPROPERTY_CAMERACONTROL_PAN

The KSPROPERTY_CAMERACONTROL_PAN read/write property is used to set and retrieve the camera pan setting.

The KSPROPERTY_CAMERACONTROL_S.Value member specifies the pan setting in degrees. Values range from –180 to +180, and the default is zero. Positive values are clockwise from the origin (the camera rotates clockwise when viewed from above), and negative values are counterclockwise from the origin. Note that a particular device may only implement a subset of this range.


KSPROPERTY_CAMERACONTROL_TILT

The KSPROPERTY_CAMERACONTROL_TILT read/write property is used to set and retrieve the camera tilt setting.

The KSPROPERTY_CAMERACONTROL_S.Value member specifies the tilt setting in degrees. Values range from –180 to +180, and the default is zero. Positive values point the imaging plane up, and negative values point the imaging plane down. Note that a particular device may only implement a subset of this range.


KSPROPERTY_CAMERACONTROL_ROLL

The KSPROPERTY_CAMERACONTROL_ROLL read/write property is used to set and retrieve the camera roll setting.

The KSPROPERTY_CAMERACONTROL_S.Value member specifies the roll setting in degrees. Values range from –180 to +180, and the default is zero. Positive values cause a clockwise rotation of the camera along the image viewing axis, and negative values cause a counterclockwise rotation of the camera. Note that a particular device may only implement a subset of this range.


KSPROPERTY_CAMERACONTROL_ZOOM

The KSPROPERTY_CAMERACONTROL_ZOOM read/write property is used to set and retrieve the zoom setting.

The KSPROPERTY_CAMERACONTROL_S.Value member specifies the zoom setting in millimeter units. Values range from 10 to 600, and the default is device specific.


KSPROPERTY_CAMERACONTROL_EXPOSURE

The KSPROPERTY_CAMERACONTROL_EXPOSURE read/write property is used to set and retrieve the exposure setting.

The KSPROPERTY_CAMERACONTROL_S.Value member specifies the exposure setting in seconds using the following formula. For values less than zero, the exposure time is 1/2n seconds. For positive values and zero, the exposure time is 2n seconds. Note that a particular device may only implement a subset of this range.

For example, a device advertises a range of –7 to 1, with stepping set to 1. The corresponding exposure times are:

Value | –7 | –6 | –5 | –4 | –3 | –2 | –1 | 0 | 1
Seconds | 1/128 | 1/64 | 1/32 | 1/16 | 1/8 | ¼ | ½ | 1 | 2


KSPROPERTY_CAMERACONTROL_IRIS

The KSPROPERTY_CAMERACONTROL_IRIS read/write property is used to set and retrieve the iris setting.

The KSPROPERTY_CAMERACONTROL_S.Value member specifies the iris setting expressed as the fstop * 10. Range of values will be provided in a later release.


KSPROPERTY_CAMERACONTROL_FOCUS

The KSPROPERTY_CAMERACONTROL_FOCUS read/write property is used to set and retrieve the focus setting.

The KSPROPERTY_CAMERACONTROL_S.Value member specifies the focus setting as the distance to the optimally focused target in millimeters. The range and default values are device specific. Note that a particular device may only implement a subset of this range.


PROPSETID_VIDCAP_CROSSBAR

The PROPSETID_VIDCAP_CROSSBAR property set is used to route video and audio signals. The crossbar is modeled after a general switching matrix, with N inputs and M outputs. Any of the input signals can be routed to one or more of the outputs. Actual hardware implementations will probably allow only a subset of this general routing capability.

The crossbar can be used to route either digital or analog signals. A single crossbar can route both video and audio signals. Video pins can optionally indicate an audio pin, which is related to the video pin.

GUID | PROPSETID_VIDCAP_CROSSBAR
DirectShow Interface | IAMCrossbar

The property set includes the following of type KSPROPERTY_VIDCAP_CROSSBAR:

KSPROPERTY_CROSSBAR_CAPS (Read Only)

KSPROPERTY_CROSSBAR_PININFO (Read Only)

KSPROPERTY_CROSSBAR_CANROUTE (Read Only)

KSPROPERTY_CROSSBAR_ROUTE (Read/Write)

Also covered in this section is an additional enumerated types used with routing signals:

KS_PhysicalConnectorType


KS_PhysicalConnectorType

The enumerated types of KS_PhysicalConnectorType should match the DirectShow™ equivalents.

typedef enum {
    KS_PhysConn_Video_Tuner = 1,
    KS_PhysConn_Video_Composite,
    KS_PhysConn_Video_SVideo,
    KS_PhysConn_Video_RGB,
    KS_PhysConn_Video_YRYBY,
    KS_PhysConn_Video_SerialDigital,
    KS_PhysConn_Video_ParallelDigital,
    KS_PhysConn_Video_SCSI,
    KS_PhysConn_Video_AUX,
    KS_PhysConn_Video_1394,
    KS_PhysConn_Video_USB,
    KS_PhysConn_Video_VideoDecoder,
    KS_PhysConn_Video_VideoEncoder,
    KS_PhysConn_Video_SCART,

    KS_PhysConn_Audio_Tuner = 4096,
    KS_PhysConn_Audio_Line,
    KS_PhysConn_Audio_Mic,
    KS_PhysConn_Audio_AESDigital,
    KS_PhysConn_Audio_SPDIFDigital,
    KS_PhysConn_Audio_SCSI,
    KS_PhysConn_Audio_AUX,
    KS_PhysConn_Audio_1394,
    KS_PhysConn_Audio_USB,
    KS_PhysConn_Audio_AudioDecoder,
} KS_PhysicalConnectorType;


KSPROPERTY_CROSSBAR_CAPS

The KSPROPERTY_CROSSBAR_CAPS read-only property is used to retrieve the total number of input and output pins on the crossbar. It uses the following structure:

typedef struct {
  KSPROPERTY  Property;
  ULONG  NumberOfInputs;
  ULONG  NumberOfOutputs;
} KSPROPERTY_CROSSBAR_CAPS_S, *PKSPROPERTY_CROSSBAR_CAPS_S;

Members

Property
Specifies the property used.
NumberOfInputs
Specifies the number of audio and video input pins.
NumberOfOutputs
Specifies the number of audio and video output pins.


KSPROPERTY_CROSSBAR_PININFO

The KSPROPERTY_CROSSBAR_PININFO read-only property is used to retrieve the type of physical connection represented by the pin. In addition, video pins can optionally return the index of related audio pins. The property uses the following structure:

typedef struct {
  KSPROPERTY  Property;
  KSPIN_DATAFLOW  Direction;
  ULONG  Index;
  ULONG  PinType;
  ULONG  RelatedPinIndex;
  KSPIN_MEDIUM  Medium;
} KSPROPERTY_CROSSBAR_PININFO_S, *PKSPROPERTY_CROSSBAR_PININFO_S;

Members

Property
Specifies the property used.
Direction
Indicates either KSPIN_DATAFLOW_IN or KSPIN_DATAFLOW_OUT.
Index
Specifies the index of the pin for which information is being returned.
PinType
Specifies a value from KS_PhysicalConnectorType.
RelatedPinIndex
Specifies the index of an pin which is related to a given pin. For example, an audio pin could indicate the video pin with which it is associated. When a device supports separate composite and s-video inputs but only a single audio connector, then both video streams should set RelatedPinIndex to the index of the audio pin.
Medium
Specifies a GUID representing the hardware connection.


KSPROPERTY_CROSSBAR_ROUTE

The KSPROPERTY_CROSSBAR_ROUTE write-only property is used to route a video or audio stream. The property uses the following structure:

typedef struct {
  KSPROPERTY  Property;
  ULONG  IndexInputPin;
  ULONG  IndexOutputPin;
  ULONG  CanRoute;
} KSPROPERTY_CROSSBAR_ROUTE_S, *PKSPROPERTY_CROSSBAR_ROUTE_S;

Members

Property
Specifies the property used.
IndexInputPin
Specifies the zero-based index of the input pin.
IndexOutputPin
Specifies the zero-based index of the output pin.
CanRoute
Returns nonzero on CanRoute if routing is possible.


KSPROPERTY_CROSSBAR_CANROUTE

The KSPROPERTY_CROSSBAR_CANROUTE read-only property is used to query whether a specified routing is possible. This property uses the same structure as KSPROPERTY_CROSSBAR_ROUTE:

typedef struct {
  KSPROPERTY  Property;
  ULONG  IndexInputPin;
  ULONG  IndexOutputPin;
  ULONG  CanRoute;
} KSPROPERTY_CROSSBAR_ROUTE_S, *PKSPROPERTY_CROSSBAR_ROUTE_S;

Members

Property
Specifies the property used.
IndexInputPin
Specifies the zero-based index of the input pin.
IndexOutputPin
Specifies the zero-based index of the output pin.
CanRoute
Returns nonzero on CanRoute if routing is possible.


PROPSETID_VIDCAP_TVAUDIO

The PROPSETID_VIDCAP_TVAUDIO property set is used to control settings unique to audio from television sources. This includes secondary audio program (SAP), stereo or mono selection, and volume levels. These controls are generally found on devices external to the system audio mixer.

GUID | PROPSETID_VIDCAP_TVAUDIO
DirectShow Interface | IAMTVAudio

The property set includes the following of type KSPROPERTY_VIDCAP_TVAUDIO:

KSPROPERTY_TVAUDIO_CAPS

KSPROPERTY_TVAUDIO_MODE


KSPROPERTY_TVAUDIO_CAPS

The KSPROPERTY_TVAUDIO_CAPS read-only property is used to retrieve the capabilities of the TV audio device. It uses the following structure:

typedef struct {
  KSPROPERTY  Property;
  ULONG  Capabilities;
  KSPIN_MEDIUM  InputMedium;
  KSPIN_MEDIUM  OutputMedium;
} KSPROPERTY_TVAUDIO_CAPS_S,    *PKSPROPERTY_TVAUDIO_CAPS_S;

Members

Property
Specifies the property used.
Capabilities
Specifies the capabilities of the TV audio device, using values from KS_TVAUDIO_MODE_*
InputMediumGUID
To be determined.
OutputMediumGUID
To be determined.


KSPROPERTY_TVAUDIO_MODE

The KSPROPERTY_TVAUDIO_MODE read/write property is used to set and retrieve the current audio mode.

typedef struct {
  KSPROPERTY  roperty;
  ULONG  Mode;
} KSPROPERTY_TVAUDIO_MODE_S, *PKSPROPERTY_TVAUDIO_MODE_S;

Members

Property
Specifies the property used.
Mode
Specifies the mode of the TV audio device, using values from the following.
Value | Description
KS_TVAUDIO_MODE_MONO | Specifies the audio is in mono.
KS_TVAUDIO_MODE_STEREO | Specifies the audio is in stereo.
KS_TVAUDIO_MODE_LANG_A | Specifies the audio is an additional language.
KS_TVAUDIO_MODE_LANG_B | Specifies the audio is an additional language.
KS_TVAUDIO_MODE_LANG_C | Specifies the audio is an additional language.


PROPSETID_VIDCAP_VIDEOCOMPRESSION

The PROPSETID_VIDCAP_VIDEOCOMPRESSION properties are used to get and set video compression settings.

GUID | PROPSETID_VIDCAP_VIDEOCOMPRESSION
DirectShow Interface | IAMVideoCompression

The property set includes the following of type KSPROPERTY_VIDCAP_VIDEOCOMPRESSION:

KSPROPERTY_VIDEOCOMPRESSION_GETINFO (Read Only)

KSPROPERTY_VIDEOCOMPRESSION_KEYFRAME_RATE (Read/Write)

KSPROPERTY_VIDEOCOMPRESSION_PFRAMES_PER_KEYFRAME (Read/Write)

KSPROPERTY_VIDEOCOMPRESSION_QUALITY (Read/Write)

KSPROPERTY_VIDEOCOMPRESSION_OVERRIDE_KEYFRAME (Read/Write)

KSPROPERTY_VIDEOCOMPRESSION_OVERRIDE_FRAME_SIZE (Read/Write)

All the properties that can write settings (all properties except KSPROPERTY_VIDEOCOMPRESSION_GETINFO), use the following structure:

typedef struct {
  KSPROPERTY  roperty;
  LONG  Value;
} KSPROPERTY_VIDEOCOMPRESSION_S, *PKSPROPERTY_VIDEOCOMPRESSION_S;

Members

Property
Specifies the property used.
Value
Specifies values unique to that property. See the individual property for information on the range and default value for this member.


KSPROPERTY_VIDEOCOMPRESSION_GETINFO

The KSPROPERTY_VIDEOCOMPRESSION_GETINFO read-only property gets information on video compression supported by a device. It uses the following structure:

typedef struct {
  KSPROPERTY  Property;
  LONG  DefaultKeyFrameRate;
  LONG  DefaultPFrameRate;
  LONG  DefaultQuality;
  LONG  Cpabilities;
} KSPROPERTY_VIDEOCOMPRESSION_GETINFO_S,
*PKSPROPERTY_VIDEOCOMPRESSION_GETINFO_S;

Members

Property
Specifies the property used.
DefaultKeyFrameRate
Specifies the estimated frames per key frame.
DefaultPFrameRate
Specifies the zero-based index of the output pin.
DefaultQuality
Specifies the default quality value, ranging from zero to 10000.
Capabilities
Specifies the compression capabilities, from the KS_CompressionCaps.

The KSPROPERTY_VIDEOCOMPRESSION_GETINFO_S.Capabilities can be one of the following:

typedef enum {
    KS_CompressionCaps_CanQuality = 1,
    KS_CompressionCaps_CanCrunch = 2,
    KS_CompressionCaps_CanKeyFrame = 4,
    KS_CompressionCaps_CanBFrame = 8
} KS_CompressionCaps;


KSPROPERTY_VIDEOCOMPRESSION_KEYFRAME_RATE

The KSPROPERTY_VIDEOCOMPRESSION_KEYFRAME_RATE read/write property is used to get or set the keyframe rate.

The KSPROPERTY_VIDEOCOMPRESSION_S.Value member specifies the keyframe rate. Range of values will be provided in a later release.


KSPROPERTY_VIDEOCOMPRESSION_PFRAMES_PER_KEYFRAME

The KSPROPERTY_VIDEOCOMPRESSION_PFRAMES_PER_KEYFRAME read/write property is used to get or set the number of predicted frames per keyframe.

The KSPROPERTY_VIDEOCOMPRESSION_S.Value member specifies the number of Pframes per keyframe. Range of values will be provided in a later release.


KSPROPERTY_VIDEOCOMPRESSION_QUALITY

The KSPROPERTY_VIDEOCOMPRESSION_QUALITY read/write property is used to get or set the quality of video compression.

The KSPROPERTY_VIDEOCOMPRESSION_S.Value member specifies the quality value. Values range from zero to 10000. The default will be provided in a later release.


KSPROPERTY_VIDEOCOMPRESSION_OVERRIDE_KEYFRAME

The KSPROPERTY_VIDEOCOMPRESSION_OVERRIDE_KEYFRAME read/write property is used to temporarily override the keyframe rate.

The KSPROPERTY_VIDEOCOMPRESSION_S.Value member specifies the frame number of the frame to make a key frame. This property is not supported by capture drivers.


KSPROPERTY_VIDEOCOMPRESSION_OVERRIDE_FRAME_SIZE

The KSPROPERTY_VIDEOCOMPRESSION_OVERRIDE_FRAME_SIZE read/write property is used to temporarily override the frame rate.

The KSPROPERTY_VIDEOCOMPRESSION_S.Value member specifies the overriding frame size. This property is not supported by capture drivers.


PROPSETID_VIDCAP_VIDEOCONTROL

The PROPSETID_VIDCAP_VIDEOCONTROL property set is used to control additional aspects of the capture process such as enumerating available frame rates and image orientation.

The property set includes the following of type KSPROPERTY_VIDCAP_VIDEOCONTROL:

KSPROPERTY_VIDEOCONTROL_CAPS (Read Only)

KSPROPERTY_VIDEOCONTROL_FRAME_RATES (Read Only)

KSPROPERTY_VIDEOCONTROL_MODE (Read/Write)

The property set also uses the following enumerated control flags:

typedef enum {
    KS_VideoControlFlag_FlipHorizontal        = 0x0001,
    KS_VideoControlFlag_FlipVertical          = 0x0002,
    KS_VideoControlFlag_ExternalTriggerEnable = 0x0010,
    KS_VideoControlFlag_Trigger               = 0x0020,
} KS_VideoControlFlags;


KSPROPERTY_VIDEOCONTROL_CAPS

The KSPROPERTY_VIDEOCONTROL_CAPS read-only property is used to identify the video control capabilities of the device. This property uses the following structure:

typedef struct {
  KSPROPERTY Property;
  ULONG    VideoControlCaps;      // KS_VideoControlFlags_*
} KSPROPERTY_VIDEOCONTROL_CAPS_S, *PKSPROPERTY_VIDEOCONTROL_CAPS_S;

Members

Property
Specifies the property used.
VideoControlCaps
Specifies the video control capabilities from the KS_VideoControlFlags_* of the property set.


KSPROPERTY_VIDEOCONTROL_FRAME_RATES

The KSPROPERTY_VIDEOCONTROL_FRAME_RATES read-only property is used to enumerate the available frame rates. The available frame rates are returned in a structure of type KSMULTIPLE_ITEM with individual values given in units of 100ns. This is an optional property.


KSPROPERTY_VIDEOCONTROL_MODE

The KSPROPERTY_VIDEOCONTROL_MODE read/write property is used to control the mode of image production. This is an optional property that uses the following structure:

typedef struct {
  KSPROPERTY  Property;
  LONG   Mode;   // KS_VideoControlFlags_*
} KSPROPERTY_VIDEOCONTROL_MODE_S,
*PKSPROPERTY_VIDEOCONTROL_MODE_S;

Members

Property
Specifies the property used.
Mode
Specifies the mode, from the KS_VideoControlFlags_* of the property set.


Video Capture Structures

Video capture structures include the following data range structures:

KS_DATARANGE_VIDEO

KS_DATARANGE_VIDEO2

KS_DATARANGE_VIDEO_PALETTE

KS_DATARANGE_VIDEO_VBI

KS_DATARANGE_ANALOGVIDEO

Data format structures:

KS_DATAFORMAT_VIDEOINFOHEADER

KS_DATAFORMAT_VIDEOINFOHEADER2

KS_DATAFORMAT_VIDEOINFO_PALETTE

KS_DATAFORMAT_VBIINFOHEADER

Information structures:

KS_BITMAPINFOHEADER

KS_VIDEOINFOHEADER

KS_VIDEOINFO

KS_FRAME_INFO

KS_TVTUNER_CHANGE_INFO

KS_VBI_FRAME_INFO

KS_VBIINFOHEADER

KS_ANALOGVIDEOINFO

KS_VIDEOINFOHEADER2

KS_VIDEOSTREAM_CONFIG_CAPS


KS_ANALOGVIDEOINFO

The KS_ANALOGVIDEOINFO structure is used with the format FORMAT_AnalogVideo.

typedef struct tagKS_AnalogVideoInfo {
  RECT   rcSource;
  RECT   rcTarget;
  DWORD   dwActiveWidth;
  DWORD   dwActiveHeight;
  REFERENCE_TIME  AvgTimePerFrame;
} KS_ANALOGVIDEOINFO, *PKS_ANALOGVIDEOINFO;

Members

rcSource
Specifies the portion of the active video signal to use. The maximum width is 720, and the height can vary with the TransmissionStd value.
rcTarget
Specifies the destination rectangle. This value and rcSource are relative to the dwActiveWidth and dwActiveHeight.
dwActiveWidth
Currently set to 720 (ITUR-601 active samples per line) but may change with the introduction of HDTV.
AvgTimePerFrame
Specifies the average time per frame, in 100ns units.


KS_BITMAPINFOHEADER

The KS_BITMAPINFOHEADER structure contains all the details about the video stream, including the actual image dimensions and the pixel depth. This is the same structure as the user mode, GDI bitmap header (BITMAPINFOHEADER) structure. A source filter can request that the sink take only a section of the video by providing a clipping rectangle in rcSource. In the worst case, where the sink filter forgets to check this on connection, it will simply render all of it, without consequence.

Ideally, a sink filter will check the rcSource and if it does not support image extraction and the rectangle is not empty, then it will reject the connection. A filter should use SetRectEmpty to reset a rectangle to all zeroes (and IsRectEmpty to later check the rectangle). The rcTarget specifies the destination rectangle for the video. For most source filters, they will set this to all zeroes. A downstream filter may request that the video be placed in a particular area of the buffers it supplies. In this case, it will call QueryAccept with a nonempty target.

typedef struct tagKS_BITMAPINFOHEADER{
  DWORD  biSize;
  LONG   biWidth;
  LONG   biHeight;
  WORD   biPlanes;
  WORD   biBitCount;
  DWORD  biCompression;
  DWORD  biSizeImage;
  LONG  biXPelsPerMeter;
  LONG  biYPelsPerMeter;
  DWORD  biClrUsed;
  DWORD  biClrImportant;
} KS_BITMAPINFOHEADER, *PKS_BITMAPINFOHEADER;

Members

biSize
Specifies the size of the structure in bytes.
biWidth
Specifies the width of the bitmap in pixels.
biHeight
Specifies the height of the bitmap in pixels.
biPlanes
Specifies the number of planes. This is always set to 1.
BiBitCount
Specifies the color bits per pixel (1, 4, 8, 24).
BiCompression
Specifies the compression scheme.
BiSizeImage
Specifies the size of bitmap bits in bytes. (Only required if using compression.)
BiXPelsPerMeter
Specifies the horizontal resolution in pixels per meter.
BiYPelsPerMeter
Specifies the vertical resolution in pixels per meter.
BiClrUsed
Specifies the number of colors used in the image.
BiClrImportant
Specifies the number of important colors in the image.


KS_DATAFORMAT_VBIINFOHEADER

The KS_DATAFORMAT_VBIINFOHEADER structure provides detailed information on the VBI stream.

typedef struct tagKS_DATAFORMAT_VBIINFOHEADER {
  KSDATAFORMAT  DataFormat;
  KS_VBIINFOHEADER  VBIInfoHeader;
} KS_DATAFORMAT_VBIINFOHEADER, *PKS_DATAFORMAT_VBIINFOHEADER;

Members

DataFormat
Specifies the data format.
VBIInfoHeader
Contains the structure that specifies the details of the VBI stream.


KS_DATAFORMAT_VIDEOINFO_PALETTE

The KS_DATAFORMAT_VIDEOINFO_PALETTE structure is used to provide detailed information on the video stream, including color information.

typedef struct tagKS_DATAFORMAT_VIDEOINFO_PALETTE {
  KSDATAFORMAT  DataFormat;
  KS_VIDEOINFO  VideoInfo;
} KS_DATAFORMAT_VIDEOINFO_PALETTE, *PKS_DATAFORMAT_VIDEOINFO_PALETTE;

Members

DataFormat
Specifies the data format.
VideoInfo
Contains the structure that specifies the details of the video stream.


KS_DATAFORMAT_VIDEOINFOHEADER

The KS_DATAFORMAT_VIDEOINFOHEADER structure provides detailed information on the video stream.

typedef struct tagKS_DATAFORMAT_VIDEOINFOHEADER {
  KSDATAFORMAT  DataFormat;
  KS_VIDEOINFOHEADER  VideoInfoHeader;
} KS_DATAFORMAT_VIDEOINFOHEADER, *PKS_DATAFORMAT_VIDEOINFOHEADER;

Members

DataFormat
Specifies the data format.
VideoInfoHeader
Contains the structure that specifies the details of the video stream.


KS_DATAFORMAT_VIDEOINFOHEADER2

The KS_DATAFORMAT_VIDEOINFOHEADER2 structure provides detailed information on the video stream.

typedef struct tagKS_DATAFORMAT_VIDEOINFOHEADER2 {
  KSDATAFORMAT  DataFormat;
  KS_VIDEOINFOHEADER2  VideoInfoHeader2;
} KS_DATAFORMAT_VIDEOINFOHEADER2, *PKS_DATAFORMAT_VIDEOINFOHEADER2;

Members

DataFormat
Specifies the data format.
VideoInfoHeader2
Contains the structure that specifies the details of the video stream.


KS_DATARANGE_ANALOGVIDEO

The KS_DATARANGE_ANALOGVIDEO structure is used to describe the analog video stream.

typedef struct tagKS_DATARANGE_ANALOGVIDEO {
  KSDATARANGE  DataRange;
  KS_ANALOGVIDEOINFO  AnalogVideoInfo;
} KS_DATARANGE_ANALOGVIDEO, *PKS_DATARANGE_ANALOGVIDEO;

Members

DataRange
Specifies the major identifier for the format.
AnalogVideoInfo
Contains the structure that specifies the details of the analog video stream.


KS_DATARANGE_VIDEO_PALETTE

The KS_DATARANGE_VIDEO_PALETTE structure is used to describe the stream and its color capabilities.

typedef struct tagKS_DATARANGE_VIDEO_PALETTE {
  KSDATARANGE  DataRange;
  BOOL  bFixedSizeSamples;
  BOOL  bTemporalCompression;
  DWORD  StreamDescriptionFlags;
  DWORD  MemoryAllocationFlags;
  KS_VIDEO_STREAM_CONFIG_CAPS  ConfigCaps;
  KS_VIDEOINFO  VideoInfo;
} KS_DATARANGE_VIDEO_PALETTE, *PKS_DATARANGE_VIDEO_PALETTE;

Members

DataRange
Specifies the major identifier for the format.
bFixedSizeSamples
Specifies that all the samples are the same size if set to TRUE.
BTemporalCompression
Specifies if each sample can stand independently on its own, without relying on previous or future samples.
StreamDescriptionFlags
This field is unused and should be set to zero.
MemoryAllocationFlags
This field is unused and should be set to zero.
ConfigCaps
Contains the structure that specifies the configuration of the stream, including scaling, cropping, and frame and data rates.
VideoInfo
Contains the structure that specifies the details of the video stream.


KS_DATARANGE_VIDEO_VBI

The KS_DATARANGE_VIDEO_VBI structure is used to describe a stream containing VBI data.

typedef struct tagKS_DATARANGE_VIDEO_VBI {
  KSDATARANGE  DataRange;
  BOOL  bFixedSizeSamples;
  BOOL  bTemporalCompression;
  DWORD  StreamDescriptionFlags;
  DWORD  MemoryAllocationFlags;
  KS_VIDEO_STREAM_CONFIG_CAPS  ConfigCaps;
  KS_VBIINFOHEADER  VBIInfoHeader;
} KS_DATARANGE_VIDEO_VBI, *PKS_DATARANGE_VIDEO_VBI;

Members

DataRange
Specifies the major identifier for the format.
bFixedSizeSamples
Specifies that all the samples are the same size if set to TRUE.
bTemporalCompression
Specifies if each sample can stand independently on its own, without relying on previous or future samples.
StreamDescriptionFlags
This field is unused and should be set to zero.
MemoryAllocationFlags
This field is unused and should be set to zero.
ConfigCaps
Contains the structure that specifies the configuration of the stream, including scaling, cropping, and frame and data rates.
VBIInfoHeader
Contains the structure that specifies the details of the video stream.


KS_DATARANGE_VIDEO

The KS_DATARANGE_VIDEO structure are used for two related, but different purposes:

  • At driver initialization time, an array of KS_DATARANGE_VIDEO structures are returned from the driver, exposing all the supported formats for a given pin, including the possible cropping and scaling options.
  • When a particular format is selected in user mode, this structure is used to determine whether a proposed format is supported by the driver. User mode clients modify the contents of the VideoInfoHeader structure but leave all other elements of KS_DATARANGE_VIDEO unchanged. The minidriver then verifies the requested parameters and returns a KS_DATAFORMAT_VIDEO structure. At this time, fields which are unique to the particular format requested are calculated by the minidriver, such as KS_BITMAPINFOHEADER.biSizeImage (the maximum size for any returned image that is used by allocators to determine buffer sizes) which varies with compression settings and image dimensions.

For example, a stream that supported RGB16, RGB24, YVU9, and JPEG capture formats would define an array of four of these structures.

typedef struct tagKS_DATARANGE_VIDEO {
  KSDATARANGE  DataRange;
  BOOL  bFixedSizeSamples;
  BOOL  bTemporalCompression;
  DWORD  StreamDescriptionFlags;
  DWORD  MemoryAllocationFlags;
  KS_VIDEO_STREAM_CONFIG_CAPS  ConfigCaps;
  KS_VIDEOINFOHEADER  VideoInfoHeader;
} KS_DATARANGE_VIDEO, *PKS_DATARANGE_VIDEO;

Members

DataRange
Specifies the major identifier for the format.
bFixedSizeSamples
Specifies that all the samples are the same size if set to TRUE.
BTemporalCompression
Specifies if each sample can stand independently on its own, without relying on previous or future samples.
StreamDescriptionFlags
This field is unused and should be set to zero.
MemoryAllocationFlags
This field is unused and should be set to zero.
ConfigCaps
Contains the structure that specifies the configuration of the stream, including scaling, cropping, and frame and data rates.
VideoInfoHeader
Contains the structure that specifies the details of the video stream.


KS_DATARANGE_VIDEO2

The KS_DATARANGE_VIDEO2 structure is used to describe the video stream.

typedef struct tagKS_DATARANGE_VIDEO2 {
  KSDATARANGE  DataRange;
  BOOL  bFixedSizeSamples;
  BOOL  bTemporalCompression;
  DWORD  StreamDescriptionFlags;
  DWORD  MemoryAllocationFlags;
  KS_VIDEO_STREAM_CONFIG_CAPS  ConfigCaps;
  KS_VIDEOINFOHEADER2  VideoInfoHeader;
} KS_DATARANGE_VIDEO2, *PKS_DATARANGE_VIDEO2;

Members

DataRange
Specifies the major identifier for the format.
bFixedSizeSamples
Specifies that all the samples are the same size if set to TRUE.
BTemporalCompression
Specifies if each sample can stand independently on its own, without relying on previous or future samples.
StreamDescriptionFlags
Specifies what the stream is used for. For more information, see the table in Video Stream Extended Headers.
MemoryAllocationFlags
To be determined.
ConfigCaps
Contains the structure that specifies the configuration of the stream, including scaling, cropping, and frame and data rates.
VideoInfoHeader2
Contains the structure that specifies the details of the video stream.


KS_FRAME_INFO

The KS_FRAME_INFO structure is used to extend the KSSTREAM_HEADER structure for video streams. The structure provides a way to return information about the frame captured, as well as a way to pass DirectDraw handles used when capturing to a DirectDraw surface.

typedef struct tagKS_FRAME_INFO {
    ULONG     ExtendedHeaderSize; // Size of this extended header
    DWORD     dwFrameFlags;       // Field1, Field2, or Frame
    LONGLONG  PictureNumber;
    LONGLONG  DropCount;
    // The following are only set when using OverlayMixer
    HANDLE    hDirectDraw;        // user mode DDraw handle
    HANDLE    hSurfaceHandle;     // user mode surface handle
    RECT      DirectDrawRect;     // portion of surface locked
    // Reserved fields, never reference these
    DWORD     Reserved1;
    DWORD     Reserved2;
    DWORD     Reserved3;
    DWORD     Reserved4;
} KS_FRAME_INFO, *PKS_FRAME_INFO;

Members

ExtendedHeaderSize
Specifies the size of this structure.
dwFrameFlags
Specifies flags indicating additional information about the frame captured. When capturing, the driver sets this field using the flags discussed in the following Comments section.
PictureNumber
Specifies a count representing the current picture number. The counter is reset to zero when the stream is placed in the run state.
DropCount
Specifies the number of pictures that were not captured. When capturing, the driver sets this field. This counter should be incremented whenever a frame should have been captured but was not; this condition usually arises when no buffers were available during capture.
hDirectDraw
Specifies the user-mode handle to DirectDraw. This handle is only provided to the driver when capturing to a DirectDraw surface for preview or overlay purposes.
hSurfaceHandle
Specifies the user-mode handle to the DirectDraw surface. This handle is only provided to the driver when capturing to a DirectDraw surface for preview or overlay purposes.
DirectDrawRect
Specifies the portion of the DirectDraw surface that has been locked. This is normally the entire surface.
Reserved1
This field is reserved and should not be used by a driver.
Reserved2
This field is reserved and should not be used by a driver.
Reserved3
This field is reserved and should not be used by a driver.
Reserved4
This field is reserved and should not be used by a driver.

Comments

The PictureNumber member count represents the idealized count of the current picture, which is calculated in one of two ways:

  • Measure the time since the stream was started and divide by the frame duration. This method is appropriate for devices that do not provide their own clock.
  • Add together the count of frames captured and the count of frame dropped. This method is appropriate for device that provide their own clock.

When calculating the PictureNumber and DropCount, it is important to use the frame duration specified when the stream is opened, which may not necessarily match the rate at which the device is actually producing images. For example, a USB camera may only produce images at 7.5 fps, but a client could open the stream at 8 fps. In this case, all calculations should use the 8 fps number.

The dwFrameFlags member is set by the driver using the following flags.

Flag | Description
KS_VIDEO_FLAG_FRAME | Indicates a complete frame.
KS_VIDEO_FLAG_FIELD1 | Indicates Field 1 of a two-field sequence.
KS_VIDEO_FLAG_FIELD2 | Indicates Field 2 of a two-field sequence.
KS_VIDEO_FLAG_I_FRAME | Indicates that this frame can be completely decoded without reference to any other frames.
KS_VIDEO_FLAG_P_FRAME | Indicates that this a predicted frame.
KS_VIDEO_FLAG_B_FRAME | Indicates that this is a bidirectional frame.


KS_TVTUNER_CHANGE_INFO

The KS_TVTUNER_CHANGE_INFO structure is used to provide VBI codecs with information about the currently tuned channel.

typedef struct tagKS_TVTUNER_CHANGE_INFO {
    DWORD    dwFlags;                // KS_TVTUNER_CHANGE_*
    DWORD    dwCountryCode;          // ITU country/region code
    DWORD    dwAnalogVideoStandard;  // KS_AnalogVideoStandard
    DWORD    dwChannel;              // Channel number
} KS_TVTUNER_CHANGE_INFO, *PKS_TVTUNER_CHANGE_INFO;

Members

dwFlags
Specifies flags indicating the status of the tuning operation. The flag can be one of the following.
Flag Description
KS_TVTUNER_CHANGE_
BEGIN_TUNE 		Indicates that a tuning operation has begun. VBI codecs should stop decoding at this time, since the video signal is likely to be corrupted.
KS_TVTUNER_CHANGE_
END_TUNE 		Indicates completion of a tuning operation. VBI codecs should resume decoding.

dwCountryCode
Specifies the country/region code in use. This corresponds to the ITU long distance dialing code.
dwAnalogVideoStandard
Specifies the current analog video standard, which is enumerated by the KS_AnalogVideoStandard.
dwChannel
Specifies the current channel.

Comments

A packet containing KS_TVTUNER_CHANGE_INFO structure normally originates at a TV Tuner filter, and is propagated through any crossbars to an analog video decoder capture filter. The capture filter in turn must propagate this packet to downstream VBI codecs.


KS_VBI_FRAME_INFO

The KS_VBI_FRAME_INFO structure is used to extend the KSSTREAM_HEADER structure for VBI streams. It provides a way to return information about the frame captured, as well as providing tuning information to VBI decoders.

typedef struct tagKS_VBI_FRAME_INFO {
  ULONG  ExtendedHeaderSize;
  DWORD  dwFrameFlags;
  LONGLONG  PictureNumber;
  LONGLONG  DropCount;
  DWORD  dwSamplingFrequency;
  KS_TVTUNER_CHANGE_INFO  TvTunerChangeInfo;
  KS_VBIINFOHEADER  VBIInfoHeader;
} KS_VBI_FRAME_INFO, *PKS_VBI_FRAME_INFO;

Members

ExtendedHeaderSize
Specifies the size of this structure.
dwFrameFlags
Specifies flags indicating additional information about the frame captured. When capturing, the driver sets this field using flags described in the following Comments section.
PictureNumber
Specifies a count representing the current picture number. The counter is reset to zero when the stream is placed in the Run state.
DropCount
Specifies the number of pictures that were not captured. When capturing, the driver sets this field. This counter should be incremented whenever a frame should have been captured but was not; this condition usually arises when no buffers were available during capture.
TvTunerChangeInfo
Specifies information about the current VBI data source, including country/region code, analog video standard, and channel. This field is only valid if dwFrameFlags specifies the KS_VBI_FLAG_TVTUNER_CHANGE flag.
VBIInfoHeader
Specifies information about the current VBI data source, including start line, end line, sampling frequency, and video standard. This field is only valid if dwFrameFlags specifies the KS_VBI_FLAG_VBIINFOHEADER_CHANGE flag.

Comments

The PictureNumber member count represents the idealized count of the current picture, which is calculated in one of two ways:

  • Measure the time since the stream was started and divide by the frame duration. This method is appropriate for devices which do not provide their own clock.
  • Add together the count of frames captured and the count of frame dropped. This method is appropriate for device which provide their own clock.

When calculating the PictureNumber and DropCount, it is important to use the frame duration specified when the stream is opened, which may not necessarily match the rate at which the device is actually producing images. For example, a USB camera may only produce images at 7.5 fps, but a client could open the stream at 8 fps. In this case, all calculations should use the 8 fps number.

The dwFrameFlags member is set by the driver using the following flags.

Flag | Description
KS_VBI_FLAG_FRAME | Indicates a complete frame.
KS_VBI_FLAG_FIELD1 | Indicates Field 1 of a two-field sequence.
KS_VBI_FLAG_FIELD2 | Indicates Field 2 of a two-field sequence.
KS_VBI_FLAG_TVTUNER_ CHANGE | Indicates that the TvTunerChangeInfo structure contains valid data.
KS_VBI_FLAG_ VBIINFOHEADER_CHANGE | Indicates that the VBIInfoHeader structure contains valid data.


KS_VBIINFOHEADER

The KS_VBIINFOHEADER structure is used for raw vertical blanking interval (VBI) streams. These streams are usually converted to NABTS, CC, and Intercast streams.

typedef struct tagKS_VBIINFOHEADER {
  ULONG  StartLine;
  ULONG  EndLine;
  ULONG  SamplingFrequency;
  ULONG  MinLineStartTime;
  ULONG  MaxLineStartTime;
  ULONG  ActualLineStartTime;
  ULONG  ActualLineEndTime;
  ULONG  VideoStandard;
  ULONG  SamplesPerLine;
  ULONG  StrideInBytes;
  ULONG  BufferSize;
} KS_VBIINFOHEADER, *PKS_VBIINFOHEADER;

Members

StartLine
Specifies line number of the first digitized VBI line.
EndLine
Specifies the line number of the last digitized VBI line.
SamplingFrequency
Specifies the sampling frequency expressed in Hz.
MinLineStartTime
Specifies the shortest possible interval from the leading edge of Hsync in 10ns units (that is, MicroSeconds * 100).
MaxLineStartTime
Specifies the longest possible interval from the leading edge of Hsync in 10ns units (that is, MicroSeconds * 100).
ActualLineStartTime
Specifies the actual starting point of VBI digitization from the leading edge of HSync in 10ns units (that is, MicroSeconds * 100).
ActualLineEndTime
Specifies the actual ending point for VBI digitization from the leading edge of HSync in 10ns units (that is, MicroSeconds * 100).
VideoStandard
Specifies the KS_AnalogVideoStandard* value.
SamplesPerLine
Specifies the number of samples digitized per video line.
StrideInBytes
Specifies the stride in bytes between the first sample on a given line and the first sample on the next line. This value can be larger than SamplesPerLine.
BufferSize
Specifies the size in bytes of the buffer to store the entire digitized VBI signal.


KS_VIDEOINFO

The KS_VIDEOINFO structure is used to describe the video stream.

Note Do not use this structure unless you are sure that the BITMAPINFOHEADER has a normal biSize == sizeof(BITMAPINFOHEADER).

typedef struct tagKS_VIDEOINFO {
  RECT  rcSource;
  RECT  rcTarget;
  DWORD  dwBitRate;
  DWORD  dwBitErrorRate;
  REFERENCE_TIME  AvgTimePerFrame;
  KS_BITMAPINFOHEADER  bmiHeader;
  union {
    KS_RGBQUAD  bmiColors[KS_iPALETTE_COLORS];
    DWORD  dwBitMasks[KS_iMASK_COLORS];
    KS_TRUECOLORINFO  TrueColorInfo;
      };
} KS_VIDEOINFO;

Members

rcSource
Specifies the portion of the active video signal to use.
rcTarget
Specifies the destination rectangle.
dwBitRate
Specifies the approximate data bit rate.
DwBitErrorRate
Specifies the bit error rate for the stream.
AvgTimePerFrame
Specifies the average time per frame, in 100ns units.
bmiHeader
Specifies the bitmap header information.
bmiColors[KS_iPALETTE_COLORS]
Specifies the color palette.
dwBitMasks[KS_IMASK_COLORS]
To be determined.
TrueColorInfo
To be determined.
#define KS_SIZE_MASKS (KS_iMASK_COLORS * sizeof(DWORD))
#define KS_SIZE_PREHEADER (FIELD_OFFSET(KS_VIDEOINFOHEADER,bmiHeader))

// For normal size
// #define KS_SIZE_VIDEOHEADER (sizeof(KS_BITMAPINFOHEADER) + KS_SIZE_PREHEADER)
// !!! for abnormal biSizes
#define KS_SIZE_VIDEOHEADER(pbmi) ((pbmi)->bmiHeader.biSize + KS_SIZE_PREHEADER)


KS_VIDEOINFOHEADER

The KS_VIDEOINFOHEADER structure is used to specify details of the video stream. This structure is identical to the DirectShow VIDEOINFOHEADER structure.

typedef struct tagKS_VIDEOINFOHEADER {
  RECT  rcSource;
  RECT  rcTarget;
  DWORD  dwBitRate;
  DWORD  dwBitErrorRate;
  REFERENCE_TIME  AvgTimePerFrame;
  KS_BITMAPINFOHEADER  bmiHeader;
} KS_VIDEOINFOHEADER, *PKS_VIDEOINFOHEADER;

Members

rcSource
Specifies a RECT structure that defines the source video window. This RECT structure can be a clipping rectangle to select a portion of the source video stream.
rcTarget
Specifies a RECT structure that defines the destination video window.
dwBitRate
Specifies a DWORD value that indicates the video stream's approximate data rate, in bits per second.
dwBitErrorRate
Specifies a DWORD value that indicates the video stream's data error rate, in bit errors per second.
AvgTimePerFrame
Specifies a REFERENCE TIME value that indicates the video frame's average display time, in 100-nanosecond units.
bmiHeader
Specifies a KS_BITMAPINFOHEADER structure that contains color and dimension information for the video image bitmap.


KS_VIDEOINFOHEADER2

The KS_VIDEOINFOHEADER2 structure is used to specify details of the video stream. This structure is identical to the DirectShow VIDEOINFOHEADER2 structure.

Capture drivers that produce video fields (instead of frames) must use the KS_DATARANGE_VIDEO2 structure, which contains a KS_VIDEOINFOHEADER2 structure.

typedef struct tagKS_VIDEOINFOHEADER2 {
  RECT  rcSource;
  RECT  rcTarget;
  DWORD  dwBitRate;
  DWORD  dwBitErrorRate;
  REFERENCE_TIME  AvgTimePerFrame;
  DWORD  dwInterlaceFlags;
  DWORD  dwCopyProtectFlags;
  DWORD  dwPictAspectRatioX;
  DWORD  dwPictAspectRatioY;
  DWORD  dwReserved1;
  DWORD  dwReserved2;
  KS_BITMAPINFOHEADER bmiHeader;
} KS_VIDEOINFOHEADER2;

Members

rcSource
Specifies a RECT structure that indicates what part of the source stream should be used to fill the destination buffer. The renderers can use this field to ask the decoders to stretch or clip the stream.
rcTarget
Specifies a RECT structure that indicates what part of the destination buffer should be used.
dwBitRate
Specifies a DWORD value that indicates the video stream's appropriate data rate.
DwBitErrorRate
Specifies a DWORD value that indicates the video stream's data error rate.
AvgTimePerFrame
Specifies a REFERENCE TIME value that indicates the video frame's average display time, in 100-nanosecond units.
dwInterlaceFlags
Specifies an AMINTERLACE_* flag. See the following Comments section for flag values.
dwCopyProtectFlags
Specifies a AMCOPYPROTECT RestrictDuplication value to indicate if duplication of a stream should be restricted. If undefined, specify zero or connection should be rejected.
dwPictAspectRatioX
Specifies the X dimension of the picture aspect ratio. For example, 16 for a 16x9 display. The value is expressed in inches by inches, not pixels by pixels.
DwPictAspectRatioY
Specifies the Y dimension of the picture aspect ratio. For example, 9 for 16x9 display. The value is expressed in inches by inches, not pixels by pixels.
dwReserved1
Reserved for future use. Must be set to zero or the connection is rejected.
dwReserved2
Reserved for future use. Must be set to zero or the connection is rejected.
BmiHeader
Specifies a KS_BITMAPINFOHEADER structure that contains color and dimension information for the video image bitmap.

Comments

Values for the dwInterlaceFlags member include the following. (Set undefined flags to zero or the connection is rejected.)

Value | Description
AMINTERLACE_IsInterlaced | Indicates an interlace stream. If zero, other interlace bits are irrelevant.
AMINTERLACE_1FieldPerSample | Indicates one field per media sample. If zero, indicates two fields per media sample.
AMINTERLACE_Field1First | Indicates that Field 1 is first. If zero, indicates that Field 2 is first. Top field in PAL is field 1, top field in NTSC is field 2.
AMINTERLACE_UNUSED | Unused.
AMINTERLACE_FieldPatternMask | Bits used to indicate field pattern.
AMINTERLACE_FieldPatField1Only | Stream never contains a Field 2.
AMINTERLACE_FieldPatField2Only | Stream never contains a Field 1.
AMINTERLACE_FieldPatBothRegular | There will be a Field 2 for every Field 1.
AMINTERLACE_FieldPatBothIrregular | Random pattern of Field 1s and Field 2s.
AMINTERLACE_DisplayModeMask | Bits used to indicate display mode.
AMINTERLACE_DisplayModeBobOnly | Indicates Bob display mode only.
AMINTERLACE_DisplayModeWeaveOnly | Indicates Weave display mode only.
AMINTERLACE_DisplayModeBobOrWeave | Indicates either Bob or Weave display mode


KS_VIDEOSTREAM_CONFIG_CAPS

The KS_VIDEO_STREAM_CONFIG_CAPS structure is identical to the DirectShow VIDEO_STREAM_CONFIG_CAPS structure, and includes the following information: analog video standard, scaling capabilities, cropping capabilities, minimum and maximum frame rates, minimum and maximum data rates

typedef struct  _KS_VIDEO_STREAM_CONFIG_CAPS  {
  GUID  guid;
  ULONG  VideoStandard;
  SIZE  InputSize;
  SIZE  MinCroppingSize;
  SIZE  MaxCroppingSize;
  int  CropGranularityX;
  int  CropGranularityY;
  int  CropAlignX;
  int  CropAlignY;
  SIZE  MinOutputSize;
  SIZE  MaxOutputSize;
  int  OutputGranularityX;
  int  OutputGranularityY;
  int  StretchTapsX;
  int  StretchTapsY;
  int  ShrinkTapsX;
  int  ShrinkTapsy;
  LONGLONG  MinFrameInterval;
  LONGLONG  MaxFrameInterval;
  LONG  MinBitsPerSecond;
  LONG  MaxBitsPerSecond;
} KS_VIDEO_STREAM_CONFIG_CAPS;

Members

guid
Specifies the KSDATAFORMAT_SPECIFIER_VIDEOINFO value. This GUID is identical to the DirectShow MEDIATYPE_Video value.
VideoStandard
Specifies the logical OR of all AnalogVideoStandards supported for the stream. All possible video standards are provided by the KS_ANalogVideoStandard enumeration. Digital cameras should set this member to KS_AnalogVideo_None.
InputSize
Specifies the size of the incoming signal. This value is the SIZE structure that indicates the image rectangle's width and height in pixels. This is the largest signal the filter can digitize with each pixel remaining unique.
MinCroppingSize
Specifies the smallest cropping rectangle allowed, as specified in the KS_VIDEOINFOHEADER structure's rcSource member.
MaxCroppingSize
Specifies the largest cropping rectangle allowed, as specified in the KS_VIDEOINFOHEADER structure's rcSource member.
CropGranularityX
Specifies the horizontal granularity of the cropping size. For example, valid widths could be specified as even multiples of four.
CropGranularityY
Specifies the vertical granularity of cropping size. For example, valid heights could be specified as even multiples of four.
CropAlignX
Specifies the horizontal alignment of the cropping rectangle inside InputSize. For example, the driver could specify that valid rectangles must start on a boundary that is a multiple of four.
CropAlignY
Specifies the vertical alignment of the cropping rectangle inside InputSize. For example, the driver could specify that valid rectangles must start on a boundary that is a multiple of four.
MinOutputSize
Specifies the smallest bitmap this pin can produce.
MaxOutputSize
Specifies the largest bitmap this pin can produce.
OutputGranularityX
Specifies the granularity of the output bitmap width.
OutputGranularityY
Specifies the granularity of the output bitmap height.
StretchTapsX
Specifies a value indicating how well the filter can stretch the image's width. A value of zero means the filter can not stretch. A value of 1 indicates the filter uses pixel doubling, a value 2 indicates the filter uses interpolation (2 taps), and a value of 3 or higher indicates the filter implements a better form of interpolation.
StretchTapsY
Specifies a value indicating how well the filter can stretch the image's height. A value of zero means the filter can not stretch. A value of 1 indicates the filter uses pixel doubling, a value of 2 indicates the filter uses interpolation (2 taps), and a value of 3 or higher indicates the filter implements a better form of interpolation.
ShrinkTapsX
Specifies a value indicating how well the filter can shrink the image's width. A value of zero indicates that the filter can not shrink. A value of 1 indicates the filter eliminates some rows of pixels to achieve shrinking, a value of 2 indicates the filter uses interpolation (2 taps), and a value of 3 or higher indicates the filter implements a better form of interpolation.
ShrinkTapsY
Specifies a value indicating how well the filter can shrink the image's height. A value of zero indicates the filter can not shrink. A value of 1 indicates the filter eliminates some rows of pixels to achieve shrinking, a value of 2 indicates the filter uses interpolation (2 taps), and a value of 3 or higher indicates the filter implements a better form of interpolation.
MinFrameInterval
Specifies the minimum frame rate allowed. This value applies to capture filters only.
MaxFrameInterval
Specifies the maximum frame rate allowed. This value applies to capture filters only.
MinBitsPerSecond
Specifies the minimum data rate this pin can produce.
MaxBitsPerSecond
Specifies the maximum data rate this pin can produce.

Comments

It is important to understand the relationships between the members of this structure. For example, assume the following values for some of the structure members:

MinCroppingSize = (160, 120)

MaxCroppingSize = (320, 240)

CropGranularityX = 4

CropGranularityY = 8

These values indicate that valid cropping sizes begin at MinCroppingSize and increase in steps in the x-direction by CropGranularityX and in the y-direction by CropGranularityY. In this case the x-value can be anywhere from 160 to 320 pixels in steps of 4 and the y-value can be anywhere from 120 to 240 pixels in steps of 8.

In this scenario a few of the valid sizes are:

  • 160 x 120, 164 x 120, 168 x 120, 172 x 120, etc.
  • 160 x 128, 164 x 128, 168 x 128, 172 x 128, etc.
  • 160 x 136, 164 x 136, 168 x 136, 172 x 136, etc.

CropAlignX and CropAlignY indicate where the cropping rectangle can be inside the input size rectangle. Given a 160 x 120 sized, cropping rectangle and the following:

CropAlignX = 2

CropAlignY = 4

Some of the valid values for the KS_VIDEOINFOHEADER structure's rcSource member would be:

  • (0, 0, 160, 120)
  • (2, 0, 162, 120)
  • (2, 4, 162, 124)
  • (2, 8, 162, 128)

For a 320 x 240 cropping rectangle and the same cropping alignment values, (2, 4, 322, 244) is one example of the many legal rectangles.

The structure members discussed in this section work together to specify what values of rcSource are valid for the KS_VIDEOINFOHEADER structure that describes the output pin's media type. Of the remaining structure members, MinOutputSize, MaxOutputSize, OutputGranularityX, and OutputGranularityY describe the biWidth and biHeight members of the KS_BITMAPINFOHEADER structure contained in the pin's media type KS_VIDEOINFOHEADER structure.


USB Camera Minidriver Interface Reference

This documentation is written for developers of the Universal Serial Bus drivers for Microsoft® Windows® 98, and Windows® 2000. The USB Camera Driver is described in this documentation and is customized for Windows® 98 applications.

Hardware vendors are responsible for creating a stream class minidriver that implements the Universal Serial Bus (USB) Camera Minidriver Interface for all USB devices. The IHV-provided minidriver and the USBCAMD driver combine to create functionality equivalent to that of the test cap sample in the DDK.

The following topics are included:

USB Camera Driver

USBCAMD Function and Usage

Operation

Limitations

Minidriver Entry Points

Available USBCAMD Services


USB Camera Driver

The WDM stream class driver allows developers to create a compact minidriver that is hardware specific and lets the class driver handle the allocation of system resources and memory. The stream class driver can handle both video and audio streaming. The WDM DDK includes sample minidrivers as well as documents that explain how to implement a minidriver using the WDM stream class driver. For more information on the WDM stream class driver, see the Stream Class Driver Reference

USBCAMD is a helper driver to "stream" class minidrivers for USB digital cameras. The camera's stream class minidriver, referred to as the cam minidriver, contains the device (hardware) specific code. USBCAMD provides generic services that manage isochronous data streams on the USB. USBCAMD also manages some of the tedious USB configuration process of the camera for the cam minidriver. USBCAMD allows the minidriver writer to focus on support for camera properties and image processing instead of the details of maintaining an ISO stream on the USB.

Additional developer information, including the USB specifications, may be obtained through the USB consortium website at http://www.usb.org/developers/index.html.

General or consumer information may be obtained at http://www.usb.org


USBCAMD Function and Usage

The primary function of USBCAMD is to manage an isochronous stream from the device and allow the cam driver to extract video frames from the stream and perform any processing on them before they are returned to the calling application. USBCAMD handles all the synchronization, start, stop, and error recovery issues associated with maintaining the ISO stream on the USB. The cam minidriver determines if the data is valid and part of the current video frame, or part of the next frame, and indicates this to USBCAMD. The device-specific functions (such as properties) are handled by the cam minidriver as well as support for additional non-ISO streams (for example, still image).

USB cameras that support a single isochronous data stream where synchronization information (start of video frames) is embedded in the data stream are ideal for USBCAMD.


Operation

The cam minidriver passes the stream request blocks (SRB) associated with the video stream to USBCAMD. USBCAMD will then start and stop the ISO stream when necessary. USBCAMD will call the cam minidriver when it is necessary to allocate bandwidth and free bandwidth (usually the cam minidriver will select an appropriate alternate interface). This ensures that the camera will only be using USB bandwidth when it is running. The cam minidriver "sees" each packet on the ISO stream and is responsible for indicating the start of a new video frame. Some SRBs are handled by the cam minidriver. For example, SRBs that report video format or handle property requests are handled entirely by the minidriver.


Limitations

Currently, USBCAMD handles only a camera with a single interface (with multiple alternate settings) controlling the video portion. Since all SRBs are seen by the cam minidriver before they go to USBCAMD, it should be possible to extend functionality within the cam minidriver. For example, the cam minidriver could support two streams: one managed by USBCAMD and one controlled independently.


Minidriver Entry Points

The following is a list of entry points provided by the cam minidriver to support the ISO stream and configuration processes handled by USBCAMD. All the calls are defined as pointers to functions and appear as members in the structure USBCAMD_DEVICE_DATA. This structure must be initialized prior to use.

CamInitialize

CamUnInitialize

CamProcessUSBPacket

CamNewVideoFrame

CamProcessRawVideoFrame

CamStartCapture

CamStopCapture

CamConfigure

CamSaveState

CamRestoreState

CamAllocateBandwidth

CamFreeBandwidth


USBCAMD_DEVICE_DATA

The following structure contains pointers to all the cam minidriver's entry points and creates a basic description for a camera. It needs to be initialized prior to use and all the functions must be defined, although unused or inapplicable calls may be set to NULL. While the actual implementation is defined by the vendor, the format, in general, and the function prototype, in specific, are detailed in the following sections. Hardware vendors may create additional calls they feel necessary but they would not be supported by industry standards.

typedef struct _USBCAMD_DEVICE_DATA
{
  ULONG  Sig;
  PCAM_INITIALIZE_ROUTINE  CamInitialize;
  PCAM_INITIALIZE_ROUTINE  CamUnInitialize
  PCAM_PROCESS_PACKET_ROUTINE  CamProcessUSBPacket;
  PCAM_NEW_FRAME_ROUTINE  CamNewVideoFrame;
  PCAM_PROCESS_RAW_FRAME_ROUTINE  CamProcessRawVideoFrame;
  PCAM_START_CAPTURE_ROUTINE  CamStartCapture;
  PCAM_STOP_CAPTURE_ROUTINE  CamStopCapture;
  PCAM_CONFIGURE_ROUTINE  CamConfigure;
  PCAM_STATE_ROUTINE  CamSaveState;
  PCAM_STATE_ROUTINE  CamRestoreState;
  PCAM_ALLOCATE_BW_ROUTINE  CamAllocateBandwidth;
  PCAM_FREE_BW_ROUTINE  CamFreeBandwidth;
} USBCAMD_DEVICE_DATA, *PUSBCAMD_DEVICE_DATA;

Members

Sig
Data structure signature that a camera minidriver can fill in.
CamInitialize
Pointer to a function for initializing the minidriver.
CamUnInitialize
Pointer to a function for deallocation resources when a minidriver is no longer required.
CamProcessUSBPacket
Pointer to a function for deciding ownership of a video frame.
CamNewVideoFrame
Pointer to a function to initialize a new video frame.
CamProcessRawVideoFrame
Pointer to a function for decoding a generic video frame.
CamStartCapture
Pointer to a function to initialize a particular device stream.
CamStopCapture
Pointer to a function to deallocate bandwidth from a device stream.
CamConfigure
Pointer to a function to configure a stream prior to initializing a specific device.
CamSaveState
Pointer to a function to save the current device context.
CamRestoreState
Pointer to a function to restore the previously saved device context.
CamAllocateBandwidth
Pointer to a function to select the appropriate interface and bandwidth.
CamFreeBandwidth
Pointer to a function selecting an interface that uses no bandwidth after a stream has been stopped.


CamInitialize

CamInitialize is invoked upon using the peripheral for the first time in a session. This initializes the device and allows additional vendor commands to be provided. The device context needs to be previously configured and the initial alternate interface selected.

NTSTATUS
  CamInitialize(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext
    );

Parameters

BusDeviceObject
Device object associated with the peripheral.
DeviceContext
User-supplied value or structure relevant to the stream.

Return Values

The NTSTATUS code indicating the success or failure of the operation. Since the implementation is vendor specific, the errors messages may vary between manufacturers.


CamUnInitialize

CamUnInitialize is invoked after using the peripheral for the last time in a session. While the Stream Class driver automatically resets values associated with the minidriver, this call allows the minidriver to deallocate specific resources used during its operation. This includes any memory it explicitly allocated.

NTSTATUS
  CamUnInitialize(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext
    );

Parameters

BusDeviceObject
Device object associated with the peripheral.
DeviceContext
User-supplied relevant value or structure.

Return Values

The NTSTATUS code indicating the success or failure of the operation. Since the implementation is vendor specific, the errors messages may vary between manufacturers.


CamProcessUSBPacket

CamProcessUSBPacket, called at the DPC level, allows the minidriver to determine whether this packet is part of the current video frame or a new video frame. This function should complete as quickly as possible. Any image processing should be deferred to the CamProcessRawVideoFrame routine.

ULONG
  CamProcessUSBPacket(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext,
    PVOID  CurrentFrameContext,
    PUSBD_ISO_PACKET_DESCRIPTOR  SyncPacket,
    PVOID  SyncBuffer,
    PUSBD_ISO_PACKET_DESCRIPTOR  DataPacket,
    PVOID  DataBuffer,
    PBOOLEAN  FrameComplete,
    PBOOLEAN  NextFrameIsStill
    );

Parameters

BusDeviceObject
Device object created by the hub. URBs can be submitted to the device through this device object.
DeviceContext
Minidriver device context.
CurrentFrameContext
Context for this particular frame.
SyncPacket
ISO packet descriptor from sync pipe. Set to NULL if the interface has only one pipe.
SyncBuffer
Pointer to data for the SyncPacket
DataPacket
ISO packet descriptor from data pipe.
DataBuffer
Pointer to DataPacket.
FrameComplete
Indicates to USBCAMD that this is the first data packet for a new video frame.
NextFrameIsStill
Indicates FALSE if the video stream is providing a live image, but TRUE if the next frame is a still image or an image capture stream.

Return Values

The return value is the number of bytes that should be copied into RawFrameBuffer or FrameBuffer.


CamNewVideoFrame

CamNewVideoFrame, called at the DPC level, allows the minidriver to initialize a new video frame context structure.

VOID
  CamNewVideoFrame(
    PVOID  DeviceContext,
    PVOID  FrameContext
    );

Parameters

DeviceContext
Minidriver device context.
FrameContext
Frame context to be initialized.

Return Values

No value is returned.


CamProcessRawVideoFrame

CamProcessRawVideoFrame, called at the PASSIVE level, allows the minidriver to perform any decoding of the raw video frame.

NTSTATUS
  CamProcessRawVideoFrame(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext,
    PVOID  FrameContext,
    PVOID  FrameBuffer,
    ULONG  FrameLength,
    PVOID  RawFrameBuffer,
    ULONG  RawFrameLength,
    ULONG  NumberOfPackets,
    PULONG  BytesReturned
    );

Parameters

BusDeviceObject
Device object created by the hub.
DeviceContext
Minidriver context.
FrameContext
Minidriver context for this frame.
FrameBuffer
Pointer to the buffer that should receive the final processed video frame.
FrameLength
Length of the frame buffer (from the original read request).
RawFrameBuffer
Pointer to buffer containing the received USB packets.
RawFrameLength
Length of RawFrameBuffer.
NumberOfPackets
Number of USB packets received into RawFrameBuffer.
BytesReturned
Pointer to the number of bytes read.

Return Values

The return value is the NTSTATUS completion code for the read IRP.


CamStartCapture

CamStartCapture, called just before the ISO video capture stream is started, selects the appropriate alternate interface, and sets up the device to stream. Called in connection with the stream class RUN command.

NTSTATUS
  CamStartCapture(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext
    );

Parameters

BusDeviceObject
Device object created by the hub. URBs can be submitted to the device through this device object.
DeviceContext
Mindriver context.

Return Values

The return value is the NTSTATUS completion code for the read IRP.


CamStopCapture

CamStopCapture is called after the ISO video stream is stopped. It allows alternate interface selection that uses no bandwidth.

NTSTATUS
  StopCapture(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext
    );

Parameters

BusDeviceObject
Device object created by the hub. URBs can be submitted to the device through this device object.
DeviceContext
Minidriver device context.

Return Values

The return value is the NTSTATUS completion code for the read IRP.


CamConfigure

CamConfigure configures the ISO streaming interface, which is called just before the device is configured. At this point, USBCAMD can be instructed on which interface and alternate setting to use for the idle state. It is assumed that the device has a single interface with multiple alternate settings and each alternate setting has the same number of pipes.

NTSTATUS
  CamConfigure(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext,
    PUSBD_INTERFACE_INFORMATION  Interface,
    PUSBD_CONFIGURATION_DESCRIPTOR  ConfigurationDescriptor,
    PLONG  DataPipeIndex,
    PLONG  SyncPipeIndex
    );

Parameters

BusDeviceObject
Device object created by the hub. URBs can be submitted to the device through this device object.
DeviceContext
Minidriver device context.
Interface
USBD interface structure initialized with the proper values for select_configuration. This interface structure corresponds to a single ISO interface on the device. The minidriver is able to select a particular alternate setting and pipe.
ConfigurationDescriptor
USB configuration descriptor for this device.
DataPipeIndex
Indicates which pipe the data pipe is.
SyncPipeIndex
Indicates which pipe the sync pipe is, if one is needed.

Return Values

The return value is an NTSTATUS code.


CamSaveState

CamSaveState stores the current device context state.

NTSTATUS
  CamSaveState(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext
    );

Parameters

BusDeviceObject
Device object created by the hub. May be NULL.
DeviceContext
Peripheral's device context.

Return Values

Returns STATUS_SUCCESS.


CamRestoreState

CamRestoreState recalls a previously saved state and makes it current.

NTSTATUS
  CamRestoreState(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext
    );

Parameters

BusDeviceObject
Device object created by the hub. May be NULL.
DeviceContext
Peripheral's device context.

Return Values

Returns STATUS_SUCCESS.


CamAllocateBandwidth

CamAllocateBandwidth is called just before the isochronous video capture stream is started. The caller selects the appropriate alternate interface and sets up the device to stream. It is called in connection with the owning stream class RUN command.

NTSTATUS
  AllocateBandwidth(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext,
    PULONG  RawFrameLength,
    PVOID  Format
    );

Parameters

BusDeviceObject
Device object created by the hub.
DeviceContext
Peripheral's device context.
RawFrameLength
Size, in bytes, of the raw frame data from the packet stream.
Format
Pointer to PKS_DATAFORMAT_VIDEOINFOHEADER associated with this stream.

Return Values

Returns the NTSTATUS code indicating STATUS_SUCCESS if successful. Otherwise, it returns an appropriate error message.


CamFreeBandwidth

CamFreeBandwidth is called after the ISO video stream has been stopped and allows the caller to select an alternate interface that uses no bandwidth.

NTSTATUS
  CamFreeBandwidth(
    PDEVICE_OBJECT  BusDeviceObject,
    PVOID  DeviceContext
    );

Parameters

BusDeviceObject
Device object created by the hub.
DeviceContext
Peripheral's device context.

Return Values

Returns the NTSTATUS code indicating STATUS_SUCCESS if successful. Otherwise, it returns an appropriate error message.


Available USBCAMD Services

The following is a list of services available to the cam minidriver. They are library calls actually assigned to the USBCAMD module and as such are presented only as convenience functions. They are not a part of the minidriver DDI. Programmers may include these calls in their vendor-specific routines as needed, ignore them, or add their own. They are not intended to be comprehensive in scope.

The following topics are included:

USBCAMD_DriverEntry

USBCAMD_AdapterReceivePacket

USBCAMD_ControlVendorCommand

USBCAMD_SelectAlternateInterface

USBCAMD_GetRegistryKeyValue


USBCAMD_DriverEntry

USBCAMD_DriverEntry is called from the cam minidriver DriverEntry routine to register the minidriver with USBCAMD. This effectively binds the two drivers together.

ULONG
  USBCAMD_DriverEntry(
    PVOID Context1,
    PVOID  Context2,
    ULONG  DeviceContextSize,
    ULONG  FrameContextSize,
    PADAPTER_RECEIVE_PACKET_ROUTINE  ReceivePacket
    );

Parameters

Context1
Any value or structure appropriate to the minidriver implementation. This input parameter is not used directly in this function but is passed along to other calls within the minidriver.
Context2
Any value or structure appropriate to the minidriver implementation. This input parameter is not used directly in this function but is passed along to other calls within the minidriver.
DeviceContextSize
Size, in bytes, of the minidriver's device-specific context.
FrameContextSize
Size, in bytes, of a video frame structure. Use NULL if not needed.
ReceivePacket
Entry point for receiving adapter-based SRB requests.

Return Values

Returns an NT_STATUS value indicating the result of the registration attempt. If a value other than STATUS_SUCCESS is returned, the minidriver will be unloaded.

Comments

FrameContextSize is optional. A non-NULL value should be provided only with calls to CamNewVideoFrame or CamProcessRawVideoFrame.


USBCAMD_AdapterReceivePacket

USBCAMD_AdapterReceivePacket is called by the cam minidriver from the AdapterReceivePacket function to allow USBCAMD to process an SRB.

PVOID
  USBCAMD_AdapterReceivePacket(
    IN PHW_STREAM_REQUEST_BLOCK  Srb,
    IN PUSBCAMD_DEVICE_DATA  DeviceData,
    IN PDEVICE_OBJECT  *DeviceObject,
    IN BOOLEAN  NeedsCompletion
    );

Parameters

Srb
SRB passed to the cam minidriver's AdapterReceivePacket routine.
DeviceData
USBCAMD_DEVICE_DATA structure with entry points to the cam minidriver.
DeviceObject
Pointer to the device's PDO.
NeedsCompletion
If TRUE, processes and completes the SRB request. Otherwise, USBCAMD ignores the SRB request.

Return Values

Returns a pointer to the device-specific context for this instance of the camera Devicecontext.


USBCAMD_ControlVendorCommand

USBCAMD_ControlVendorCommand is available to send vendor-specific commands to the control pipe. This function may be called at IRQL >= PASSIVE_LEVEL. If the function is called at IRQL > PASSIVE_LEVEL, the command will be deferred. After completion, the CommandComplete parameter is called with a pointer to the CommandContext.

NTSTATUS
  USBCAMD_ControlVendorCommand(
    IN PVOID  DeviceContext,
    IN UCHAR  Request,
    IN USHORT  Value,
    IN USHORT  Index,
    IN PVOID  Buffer,
    IN OUT PULONG  BufferLength,
    IN BOOLEAN  GetData,
    IN PCOMMAND_COMPLETE_FUNCTION  CommandComplete,
    IN PVOID  CommandContext
    );

Parameters

DeviceContext
Device-specific context.
Request
Value of the bRequest field for the vendor command.
Value
Value of the wValue field for the vendor command.
Index
Value of the wIndex field for the vendor command.
Buffer
Data buffer if the command has data. May be NULL.
BufferLength
Pointer length, in bytes, of buffer. May be NULL, if Buffer is NULL.
GetData
Flag indicating data direction. GetData indicates data was sent from device to host.
CommandComplete
Function called when command is completed.
CommandContext
Context passed to CommandComplete function.

Return Values

Returns NTSTATUS code from command of STATUS_PENDING if command is deferred.


USBCAMD_SelectAlternateInterface

USBCAMD_SelectAlternateInterface is called by the cam minidriver to select an alternate interface. The RequestInterface parameter is filled in with the information from the SELECT_INTERFACE request on successful completion. This function is typically called from the cam minidriver in response to a request to allocate or free bandwidth.

NTSTATUS
  USBCAMD_SelectAlternateInterface(
    IN PVOID  DeviceContext,
    IN OUT PUSBD_INTERFACE_INFORMATION  RequestInterface
    );

Parameters

DeviceContext
Device-specific context.
RequestInterface
Appropriate interface to select.

Return Values

Returns the status from the SELECT_INTERFACE request.


USBCAMD_GetRegistryKeyValue

USBCAMD_GetRegistryKeyValue retrieves a device instance specific registry key value.

NTSTATUS
  USBCAMD_GetRegistryKeyValue (
    IN HANDLE  Handle,
    IN PWCHAR  KeyNameString,
    IN ULONG  KeyNameStringLength,
    IN PVOID  Data,
    IN ULONG  DataLength
    );

Parameters

Handle
Handle to a valid and open device registry key.
KeyNameString
String buffer describing the key type.
KeyNameStringLength
String length of KeyNameString.
Data
Pointer to a caller-specified value or structure.
DataLength
Length, in bytes, of Data.

Return Values

Returns NO_ERROR, if successful. Otherwise an appropriate error message is supplied.


WDM Audio Drivers

The Microsoft® Windows® 2000 DDK contains an updated version of the Windows Driver Model (WDM) audio development environment. Since this updated environment exists, the Windows® Me DDK does not support WDM audio driver development. Use the Windows 2000 DDK to create WDM audio drivers for Windows Me, Windows® 98 Second Edition (SE), and Windows 2000. Drivers written using the Windows 2000 DDK will run on Windows Me, Windows 98 SE, and Windows 2000.

For drivers that will be used exclusively on Windows 98 Gold (not Windows 98 SE), IHVs should write VxD drivers. Because most IHVs continue to support Windows® 95 (with VxDs), there is no extra work in supporting Windows 98.

The Windows 2000 DDK is available from http://www.microsoft.com/ddk.


USB and HID Drivers

To create USB or kernel-mode HID client drivers, refer to the Microsoft® Windows® 2000 DDK documentation. USB and HID client drivers that conform to the Windows Driver Model (WDM) are source-compatible for Windows 98, Windows Millennium Edition (Windows Me), and Windows 2000 systems, provided they use only the system support routines that are declared in wdm.h.

However, source compatibility does not guarantee that an HID or USB driver will function properly on all WDM systems. Drivers should be thoroughly tested on all systems on which they are intended to run.

There are also significant differences in the Windows 2000 and Windows Me input architectures. Readers are referred to the next section for a discussion of the Windows Me input architecture.


Windows Millennium Input Architecture

Like Microsoft® Windows® 2000, Windows Millennium Edition (Windows Me) supports devices that are compliant with the Human Interface Device (HID) firmware specification. HID is the new standard for input devices, such as keyboards, mouse and pointing devices, joysticks, gamepads, and other types of game controllers. Support is based on the specification developed by the USB Implementers' Forum and is targeted toward devices connecting through USB. For more information about the USB Implementers Forum, see http://www.usb.org/. The HID specification is available at http://www.microsoft.com/hwdev/. For a detailed discussion of the Windows 2000 input architecture, see the Windows 2000 DDK. Sections dealing with the implementation of HID in Windows 2000 are applicable to Windows Me as well.

However, there are important differences between Windows 2000 and Windows Me. In Windows Me, HID keyboards, mouse devices, joysticks, and gamepads that plug into USB are connected to the existing legacy input subsystem. This is done through a set of VxD-to-WDM mappers that map the HID data into the corresponding legacy format. This allows the operating system and existing applications to receive data transparently from these kinds of USB/HID devices.

In Windows Me, legacy VxD style minidrivers connect vmd.vxd with the serial and PS/2 ports, and vjoyd.vxd with the gameports. In Windows 2000, all virtual device drivers, both mapper drivers and minidrivers, have been replaced with WDM drivers. Since vjoyd.vxd is no longer part of the architecture in Windows 2000, there is no built-in game port emulation for MS-DOS® – based games. Legacy game port devices are supported by HID class minidrivers through HID emulation.

The following figure illustrates the Windows Me input architecture. The heart of the architecture is the HID class driver, hidclass.sys, and the HID parsers, hidparse.sys and hid.dll, all three of which are supplied by Microsoft.

The Windows Me Input Architecture

The following HID modules are shown in this figure:

HIDCLASS.SYS
Hidclass.sys is the HID class driver. It routes communication between all HID clients and the various HID minidrivers that serve as interfaces to their respective bus stacks. Hidclass.sys also manages input queues that allow several processes to have handles open on the same HID class device.

The central role played by hidclass.sys in the Windows Me input architecture derives from the Device Class Definition for Human Interface Devices published by the USB standards group which attempts to bring all USB input devices under the controlling umbrella of a single class driver. A key function of hidclass.sys is to manage the diversity of protocols employed by the input devices in the system. hidclass.sys retrieves a device's protocol information either by querying the device's firmware or, in the case of non-USB devices, by querying the minidriver associated with the port or bus to which the device is connected. In both cases, protocol information is communicated by means of report descriptors (see the definition of report descriptors in the Windows 2000 DDK).

hidclass.sys retrieves and parses a device's report descriptor as soon as the system detects the device, then makes the report descriptor data available to both user-mode and kernel-mode clients in a standard "preparsed data" format. Kernel-mode clients can retrieve preparsed data by sending an IRP of type IRP_MJ_DEVICE_CONTROL with an IOCTL code of IOCTL_HID_GET_COLLECTION_DESCRIPTOR to hidclass.sys. Upon receiving this IRP, the HID class driver provides the kernel-mode client with a collection descriptor (see the definition of collection descriptors in HID Terminology) that contains the preparsed data. User-mode clients retrieve preparsed data from hidclass.sys more indirectly, by means of a call to the HidD_GetPreparsedData routine exported by hid.dll. hid.dll sends the required device control IRP to hidclass.sys on the user-mode client's behalf. (See Initializing and Connecting an HID Client in the Windows 2000 DDK for a detailed explanation.)

In addition to centralizing the management of the data protocols used by input devices, hidclass.sys routes report information to and from the appropriate port driver, bus driver, or bus driver stack in a manner that is transparent to the HID client. Even devices that plug into older-style ports, such as traditional gameports and serial ports, can be accessed by means of the HID class driver, provided an HID minidriver exists for that port. (See When Do I Write a HID Minidriver? in the Windows 2000 DDK for a discussion of the design of HID minidrivers.)

HIDUSB.SYS
Hidusb.sys is the USB minidriver supplied by Microsoft. It sends and receives HID reports over the USB bus. (See When Do I Write an HID Minidriver? in the Windows 2000 DDK for a discussion of the design of HID minidrivers.)
HID.DLL and HIDPARSE.SYS
Hid.dll and hidparse.sys are primarily parsing services. They export routines that aid both user-mode applications and kernel-mode drivers in parsing HID reports. Hid.dll provides the user-mode parsing service. Hidparse.sys provides the kernel-mode parsing service. As parsers, they do not send IRPs down the driver stack or communicate with the HID class driver. They simply interpret the report data passed to them in a "preparsed data" form (see HID Terminology for a discussion of preparsed data) and extract the requested values.

Unlike hidparse.sys, however, not all of the routines exported by hid.dll are parsing routines. HidD_FlushQueue, for instance, flushes the class driver's ring buffers, and HidD_GetPreparsedData queries the HID class driver for a particular collection's preparsed data. Both hid.dll and hidparse.sys contain a set of routines of the form HidP_Xxx that interpret preparsed data, but only hid.dll has routines of the form HidD_Xxx, which communicate directly with the HID class driver in order to retrieve or set data. Kernel-mode HID clients that need the functionality of the HidD_Xxx routines must send IRPs to the HID class driver. For example, user-mode clients use the HidD_GetPreparsedData routine, which is exported by the hid.dll, to retrieve preparsed data from hidclass.sys. Kernel-mode clients, on the other hand, have no equivalent routine available in hidparse.sys. They must retrieve preparsed data directly from hidclass.sys by means of an IRP of type IRP_MJ_DEVICE_CONTROL with an IOCTL code of IOCTL_HID_GET_COLLECTION_DESCRIPTOR. Upon obtaining the preparsed data, user-mode clients interpret the preparsed data by calling the HidP_Xxx routines exported by the hid.dll. Kernel-mode clients call routines of the same name exported by hidparse.sys.

KBDHID.VXD
Kbdhid.vxd is a filter driver that maps keyboard HID reports into the existing legacy data format expected by vkd.vxd.
MOUHID.VXD
Mouhid.vxd is a filter driver that maps mouse HID reports into the existing legacy data format expected by vmd.vxd.
JOYHID.VXD
Joyhid.vxd calls hidparse.sys to find the various elements that might be in a joystick HID report (X, Y, rudder, throttle, hat switch, and buttons) and then maps these report values into a data format expected by vjoyd.vxd.


NDIS Miniport Drivers

To create and test an NDIS miniport driver, refer to the Windows® 2000 DDK documentation. A miniport driver created in this manner is binary compatible and will run on both the Windows 2000 and Windows® Me operating systems. However, a few features are available for miniport drivers in the Windows 2000 operating system that are not available on Windows Me.

IrDA (Infrared) Miniports

To create and test an NDIS miniport driver based on the Infrared communications port, refer to the Windows® 2000 DDK documentation in Part 2 of the Design Guide in Network Drivers.


GART Miniport Driver Design Notes and Reference

This documentation describes the graphics address remapping table (GART) miniport driver interfaces for the Microsoft® Windows® 98 operating system under the Windows Driver Model (WDM).

The following topics are included:

Technology Overview

Reference


Technology Overview

Modern 3D graphics processing on PCs requires fast processing of texture maps by both the host processor and the graphics device. After the CPU performs transformations on a texture, the data must travel across the bus to the graphics controller for display. For animation, these textures are continuously being updated by the host processor and the transmission of large data blocks across a slow bus is time consuming.

Intel's new accelerated graphics processor (AGP) architecture provides fast access by the graphics device to system memory, enabling data common to the graphic and host processors to be stored in host memory. Thus, AGP allows textures to be accessed directly from system memory during rendering rather than being pre-fetched to local graphics memory.

The AGP bus improves system performance in several ways. First, the AGP channel between system memory and the graphics device operates at 66Mhz, twice the PCI standard of 33MHz. In addition, the AGP bus operates independently of other busses in the system, providing bus-level parallelism.

Because of host paging, blocks of memory with contiguous linear addresses may not be contiguous physically. However, the graphics device must see data structures such as texture maps as a contiguous block. To solve this problem, AGP hardware is equipped with core logic to translate addresses through a memory-based graphics address remapping table, or GART. The GART performs a mapping function similar to the host's paging tables, but the two mechanisms are independent and should not be confused. This address remapping applies only to a single, programmable range of the system physical address space, as shown in the following diagram. Only addresses within the GART's aperture have the mapping applied; other addresses are passed through unchanged.

The format of the GART is unspecified and left to the hardware designer. For the latest AGP hardware specification, see http://developer.intel.com/technology/agp/index.htm


Software Architecture

Support for the new AGP architecture in the Microsoft® Windows® 98 operating system consists of several Microsoft-supplied components, and a miniport driver supplied either by Microsoft or by the hardware manufacturer. The miniport component, residing at the lowest level of the AGP architecture, is the subject of this documentation; developers of new AGP hardware have no need to modify any of the higher level components.

Application programmers typically access AGP features through Microsoft® Direct Draw® 5.0. The system satisfies certain DirectDraw 5.0 requests, like CreateSurface, by calling the PCI class driver through the virtual machine manager (VMM). In turn, the PCI class driver calls the appropriate PCI miniport driver. An application can determine whether or not there is AGP hardware installed by calling DirectDraw's GetCaps function and examining the DDCAPS2_NONLOCALVIDMEM bit returned in the ddCaps.dwCaps2 field. For example, the following is a small Windows program that will report the existence of an AGP-capable memory controller:

#include <windows.h>
#include <ddraw.h>

int WINAPI WinMain
(
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR sCmdLine,
    int nCmdShow
)
{
    LPDIRECTDRAW lpDD;
    DDCAPS ddCaps;
    DirectDrawCreate( NULL, &lpDD, NULL );
    if( lpDD != NULL )
    {
        ddCaps.dwSize = sizeof(ddCaps);
        lpDD->GetCaps( &ddCaps, NULL );
        MessageBox( NULL, (ddCaps.dwCaps2 & DDCAPS2_NONLOCALVIDMEM) ? "YES!" : "NO!", "AGP?", MB_OK );
        lpDD->Release();
    }
    else
    {
        MessageBox( NULL, "DirectDrawCreate failed.", "AGP?", MB_OK );
    }
    return 0;
}

When calling DirectDraw to allocate a surface using CreateSurface with the DDSCAPS_LOCALVIDEOMEMORY bit turned on, an application can further specify what kind of heap allocation is made by setting either the DDSCAPS_LOCALVIDMEM or DDSCAPS_NONLOCALVIDMEM flags in the ddsCaps.dwCaps field. In addition, the underlying graphics driver can request uncacheable or write-combining memory.

Unless the target hardware has special circuitry, the GART should be allocated as uncached memory.

A GART driver is a PCI miniport driver. That is, it is called only by the PCI class driver and provides a well-known interface in the form of a predefined set of entry points. The responsibilities of the miniport driver are to initialize the hardware when loaded, shutdown the hardware when unloaded, and manage the GART. A complete list of GART miniport driver entry points is shown in the following table.

Name | Purpose
DriverEntry | Called by the operating system when the driver is loaded.
PCIMP_GARTInit | Initializes hardware and internal structures.
PCIMP_GARTExit | Shuts down the miniport driver.
PCIMP_GARTReset | Re-initializes.
PCIMP_GARTReserve | Reserves GART entries.
PCIMP_GARTMap | Maps GART entries to physical addresses.
PCIMP_GARTUnMap | Unmaps GART entries.
PCIMP_GARTFree | Releases GART entries.
PCIMP_GARTFlush | Flushes specific pages.

Parameters

Each of these routines requires a distinct set of parameters, but all the PCIMP_GARTxxx routines share two parameters: pHandle and refData. The pHandle parameter is always an input; refData is an input except in PCIMP_GARTInit, in which it is an output.

The pHandle parameter is a handle to the PCI driver. The miniport uses this value as a parameter to PCIGetHandleInfo to retrieve registry values.

The refData parameter is a miniport-generated value, passed back to the PCI driver in PCIMP_Init, that the PCI driver uses in all subsequent calls to the miniport driver. Typically, it is a pointer to an internal structure describing the GART for a particular miniport driver instance, but it can in fact be any value that uniquely distinguishes the instance.

Return Values

Except for DriverEntry, which returns an NTSTATUS code, each of these functions that can report errors returns a value of type PCIMPRET, defined in PCI.H. As with NTSTATUS, the PCIMPRET data type indicates either the operation's success or describes the reason for failure. The functions that return a PCIMPRET are PCIMP_GARTInit, PCIMP_GARTReset, and PCIMP_GARTReserve; the others return VOID.

The possible PCIMP return codes are shown in the following table.

Return Code | Value
PCIMP_SUCCESS | 0x00000000
PCIMP_FAILURE | 0x00000001
PCIMP_NOT_INITIALIZED | 0x00000002
PCIMP_ALREADY_INITIALIZED | 0x00000003
PCIMP_NO_INSTANCE | 0x00000004
PCIMP_INVALID_INSTANCE | 0x00000005
PCIMP_INVALID_IRQ | 0x00000006
PCIMP_INVALID_LINK | 0x00000007
PCIMP_INVALID_PARAMETER | 0x00000008
PCIMP_NO_NEW_CAPABILITIES | 0x00000009

Although the numeric value of the error codes are shown, you should not use these values directly. They are included here as a debugging aid. If the miniport driver encounters an error, it should return the error code in the preceding table that best matches the specific error; PCIMP_FAILURE indicates a generic failure and should be returned for all other errors.


PCI Class Driver Services

The PCI class driver exports the following services that can be called from a GART miniport driver. They are described further in PCI Class Driver Service Reference.

Name | Purpose
PCIGetVersion | Gets the operating system version number.
PCIGetHandleInfo | Retrieves the bus and device-function numbers.
PCIReadConfig | Reads a configuration value.
PCIWriteConfig | Writes a configuration value.
PCIAllocatePages | Allocates memory.
PCIFreePages | Frees memory.
PCILinToDev | Converts linear address to device address.


Installing the Miniport Driver

The PCI class driver loads GART miniport drivers. In order for the class driver to recognize and load a miniport driver, the following entries must be present in the registry.

Registry Key | Description
HKLM,System\CurrentControlSet\ Services\VxD\PCI\GARTMiniports\ xxxxyyyy\Name | Name of the device or chip set (not a file name).
HKLM,System\CurrentControlSet\ Services\VxD\PCI\GARTMiniports\ xxxxyyyy\Path | Path to GART miniport driver file.
HKLM,System\CurrentControlSet\ Services\VxD\PCI\GARTMiniports\ xxxxyyyy\Instance | Instance number, usually 0x00000001.

In the preceding table, xxxxyyyy stands for a DEV-VEN ID; xxxx is a manufacturer-supplied number, and yyyy is a vendor ID obtained from PCI SIG. More information can be found at http://www.pcisig.com.


Reference

Two sets of references are available.

GART Miniport Sevices

Contains a list of required functions for the GART miniport.

PCI Class Driver Service Reference

Contains a list of functions exported by the PCI class driver


GART Miniport Sevices

The following topics contain all the functions that must be exported by the GART miniport driver, along with the function prototypes, a brief description of the parameters, and the return values.

PCIMP_GARTInit

PCIMP_GARTExit

PCIMP_GARTReset

PCIMP_GARTReserve

PCIMP_GARTFree

PCIMP_GARTMap

PCIMP_GARTUnMap

PCIMP_GARTFlush


PCIMP_GARTInit

The PCIMP_GARTInit function initializes the miniport driver.

PCIMPRET
  PCIMP_GARTInit(
    ULONG  ulInstance,
    PVOID  pHandle,
    PVOID  *ppRefData
    );

Parameters

ulInstance
In a miniport with more than one chip set, this parameter specifies the chip set, corresponding to a number in the .inf file.
pHandle
PCI handle used when calling PCI services. This handle is passed into the PCIMP service functions which will need it when calling PCI services.
ppRefData
Pointer to where the service writes a reference data DWORD.

Return Values

This service returns a PCIMPRET value.

Comments

Typically, the PCIMP_GARTInit function will sense and initialize the GART hardware and its own internal data structures. The driver can get registry parameters using the PCIReadConfig function supplied by the PCI class driver.

Although it is highly unusual for a GART miniport to support multiple chip sets, the instanceNum parameter is provided for consistency with other miniport definitions. However, the operating system might require a GART miniport to support multiple instances of a single chip set. In that case, the PCI class driver will call this function more than once—each time with a different ulInstance.


PCIMP_GARTExit

The PCIMP_GARTExit service shuts down the miniport driver.

VOID
  PCIMP_GARTExit(
    PVOID  pHandle,
    PVOID  pRefData
    );

Parameters

pHandle
PCI device handle. Should be the same value used in the preceding PCIMP_GARTInit call.
pRefData
Specifies the DWORD that was written by the PCIMP_GARTInit service.

Return Values

This service has no return value.

Comments

In response to this call, the miniport driver frees any memory and releases any resources it previously allocated, and disables the hardware.


PCIMP_GARTReset

The PCIMP_GARTReset service reconfigures the miniport driver.

PCIMPRET
  PCIMP_GARTReset(
    PVOID  pHandle,
    PVOID  pRefData,
    ULONG  ulNumPhysPages,
    ULONG  ulReservedValue,
    ULONG  ulFreeValue,
    PULONG  pulFeatures
    );

Parameters

pHandle
PCI device handle. Should be the same value used in the preceding PCIMP_GARTInit call.
pRefData
Specifies the DWORD that was written by the PCIMP_GARTInit service.
ulNumPhysPages
Specifies the number of pages of physical system memory.
ulReservedValue
Specifies an invalid physical address that can be used to mark reserved GART entries.
ulFreeValue
Specifies a different invalid physical address that can be used to mark free GART entries.
pulFeatures
Pointer to where the service writes the capabilities data. The capabilities data is a ULONG with the following flags.
Value | Meaning
MP_FLUSHES_L2_CACHE | The PCIMP_GARTFlush service flushes the L2 cache.

The PCIMP_GARTFlushfunction is used to flush specific pages in the L2 cache. If this function flushes specific pages, the PCIMP_GARTReset function should set the capability flag MP_FLUSHES_L2_CACHE.

Return Values

This service returns a PCIMPRET value.

Comments

The ulReservedValue and ulFreeValue parameters supply the miniport driver with otherwise invalid addresses to use for placeholders in the GART, for representing memory that has been reserved but not committed, and for memory that has yet to be reserved.

The driver notifies the PCI class driver of special features by depositing flags in the ULONG pointed to by the pulFeatures parameter. At this time, the only defined feature bit is MP_FLUSHES_L2_CACHE. Setting this bit tells the operating system that the miniport will be managing cache flushing. Otherwise, the operating system will flush the entire L2 cache after the following routines are called:

PCIMP_GARTReserve

PCIMP_GARTMap

PCIMP_GARTFree

PCIMP_GARTReset can be called more than once between calls to PCIMP_GARTInit and PCIMP_GARTExit. However, it is only called when the GART is empty.


PCIMP_GARTReserve

The PCIMP_GARTReserve service reserves entries in the GART table.

PCIMPRET
  PCIMP_GARTReserve(
    PVOID  pHandle,
    PVOID  pRefData,
    ULONG  ulNumPages,
    ULONG  ulAlignMask,
    PVOID  *ppMapHandle,
    PULONG  pulGARTDev,
    ULONG  ulFlags
    );

Parameters

pHandle
PCI device handle. This should be the same value used in the preceding PCIMP_GARTInit call.
pRefData
Specifies the DWORD that was written by the PCIMP_GARTInit service.
ulNumPages
Specifies the number of pages.
ulAlignMask
Specifies an alignment mask for the acceptable starting pages for the AGP device address. The parameter can be one of the following values.
Value | Meaning
0x00000000 | address is a multiple of 4K
0x00000001 | address is a multiple of 8K
0x00000003 | address is a multiple of 16K
0x00000007 | address is a multiple of 32K
0x0000000F | address is a multiple of 64K
0x0000001F | address is a multiple of 128K

ppMapHandle
Specifies a pointer to where the service writes a map handle. This is a DWORD that will be passed back in on other PCIMP service calls. The use of this parameter is at the discretion of the PCIMP designer.
pulGARTDev
Specifies a pointer to where the service writes the AGP device address.
ulFlags
Specifies the reservation flags. It must be zero or one of the following values.
Symbol | Value | Meaning
PCI_UNCACHED | 0x00000001 | Maps the pages as uncached memory.
PCI_WRITECOMBINED | 0x00000002 | Maps the pages as write-combining memory.

All other values are reserved. The default is to use uncached memory. It is erroneous to specify both PCI_UNCACHED and PCI_WRITECOMBINED.

Return Values

This service returns a PCIMPRET value.

Comments

PCIMP_GARTReserve is called to reserve GART entries for later mapping with PCIMP_GARTMap. The miniport driver must find ulNumPages contiguous entries in the GART and mark them as reserved by filling them with the value specified in the ulReservedValue parameter specified in a previous call to PCIMP_GARTReset.

If the required number of contiguous GART entries are found, PCIMP_GARTReserve return STATUS_SUCCESS and places a driver-defined handle in ppMapHandle. A convenient value to use for this handle is simply a pointer to the first of the newly reserved in the GART. The PCI class driver uses this handle to later free the GART entries through PCIMP_GARTFree.


PCIMP_GARTMap

The PCIMP_GARTMap service maps previously reserved GART entries to physical memory addresses.

VOID
 PCIMP_GARTMap(
    PVOID  pHandle,
    PVOID  pRefData,
    ULONG  ulNumPages,
    PVOID  pMapHandle,
    ULONG  ulByteOffset,
    PVOID  pSystemLin
    );

Parameters

pHandle
PCI device handle. This should be the same value used in the preceding PCIMP_GARTInit call.
pRefData
ULONG that was written by the PCIMP_GARTInit service.
ulNumPages
Specifies the number of pages to be mapped.
pMapHandle
Map handle obtained using the PCIMP_GARTReserve service.
ulByteOffset
Specifies the offset in bytes from the beginning of the memory block referred to by pMapHandle to the start of a page.
pSystemLin
Specifies the starting linear address to which the GART entries are mapped.

Return Values

This service does not have a return value.

Comments

PCIMP_GARTMap fills entries in the GART starting at ulByteOffset so as to map ulNumPages consecutive entries to contiguous linear memory beginning at the address given in pSystemLin.

The pMapValue parameter should be a value produced by a previous call to PCIMP_GARTReserve. This function does not return a value so there is no way to inform the system of an erroneous parameter value.

Note that ulByteOffset is a byte offset, so the driver will need to shift this value to the right by PAGE_SHIFT (defined in wdm.h) to obtain a page offset for use as a GART index.

Because GART remaps physical memory addresses, the driver should call the PCI class driver's PCILinToPhys function to convert pSystemLin to a physical address.


PCIMP_GARTFlush

The PCIMP_GARTFlush service flushes the specified pages from the L2 cache. This service is always called after PCIMP_GARTMap.

VOID
  PCIMP_GARTFlush(
    PVOID  pHandle,
    PVOID  pRefData,
    ULONG  ulNumPages,
    PVOID  pMapHandle,
    ULONG  ulByteOffset,
    PVOID  pSystemLin
    );

Parameters

pHandle
PCI device handle. This should be the same value used in the preceding PCIMP_GARTInit call.
pRefData
ULONG that was written by the PCIMP_GARTInit service.
ulNumPages
Specifies the number of pages. This should be the same value used in the PCIMP_GARTReserve service.
pMapHandle
Map handle obtained using the PCIMP_GARTReserve service.
ulByteOffset
Specifies the offset in bytes from the beginning of the memory block referred to by pMapHandle to the start of a page.
pSystemLin
Specifies the system linear address that was passed to a PCIMP_GARTMap service call.

Return Values

This service does not have a return value.

Comments

If the miniport's PCIMP_GARTReset returned MP_FLUSH_L2_CACHE, the operating system will not flush the L2 cache by itself. If the miniport did not return MP_FLUSH_L2_CACHE, it should do nothing when this service is called.


PCIMP_GARTUnMap

The PCIMP_GARTUnMap service unmaps the specified GART entries.

VOID
  PCIMP_GARTUnMap(
    PVOID  pHandle,
    PVOID  pRefData,
    ULONG  ulNumPages,
    PVOID  pMapHandle,
    ULONG  ulByteOffset
    );

Parameters

pHandle
PCI device handle. This should be the same value used in the preceding PCIMP_GARTInit call.
pRefData
ULONG that was written by the PCIMP_GARTInit service.
ulNumPages
Specifies the number of pages to be unmapped.
pMapHandle
Map handle obtained using the PCIMP_GARTReserve service.
ulByteOffset
Specifies the offset in bytes from the beginning of the memory block referred to by pMapHandle to the start of a page.

Return Values

This service does not have a return value.

Comments

This function undoes the action of PCIMP_GARTMap. Parameters are the same as for PCIMP_GARTMap except PCIMP_GARTUnMap requires no pSystemLin parameter.

Unmapping is typically accomplished by filling the specified GART entries with the value passed in the pReservedValue parameter of PCIMP_GARTReset. After this function completes, the entries will still be reserved and the associated map handle will still be valid.


PCIMP_GARTFree

The PCIMP_GARTFree service frees entries in the GART table.

VOID
  PCIMP_GARTFree(
    PVOID  pHandle,
    PVOID  pRefData,
    ULONG  ulNumPages,
    PVOID  pMapHandle
    );

Parameters

pHandle
PCI device handle. This should be the same value used in the preceding PCIMP_GARTInit call.
pRefData
ULONG that was written by the PCIMP_GARTInit service.
ulNumPages
Specifies the number of pages. This should be the same value used in the PCIMP_GARTReserve service.
pMapHandle
Map handle obtained using the preceding PCIMP_GARTReserve service.

Return Values

This service does not have a return value.

Comments

PCIMP_GARTFree undoes the work of PCIMP_GARTReserve by filling the previously reserved ulNumPages identified by pMapHandle with the value specified in the ulFreeValue parameter in a previous PCIMP_GARTReset call.

Note that since this function does not return a value, there is no way to notify the system of an error, such as the ulNumPages parameter not matching the number of pages originally specified in the PCIMP_GARTReserve call.

Entries that have been freed must be reserved again before they can be remapped.


PCI Class Driver Service Reference

The following topics describe the functions exported by the PCI class driver. A GART miniport driver can call these and any WDM service. The driver should not call any other system service.

PCIGetVersion

PCIGetHandleInfo

PCIReadConfig

PCIWriteConfig

PCIAllocatePages

PCIFreePages

PCILinToPhys

PCISetPhysicalCacheTypeRange


PCIGetVersion

The PCIGetVersion function returns a ULONG representing the operating system version.

ULONG
  PCIGetVersion(
    VOID
    );

Parameters

This function takes no parameters.

Return Values

Currently, there are three possible return values, as shown in the following table.

Value | Operating System
0x00000400 | Windows® 95
0x00000410 | Windows® 98
0x00000500 | Windows® 2000


PCIGetHandleInfo

Given a PCIMP device handle (passed to every PCIMP function), PCIGetHandleInfo retrieves both the PCI bus number and the device function number associated with this miniport device. These values can then be passed to PCIReadConfig and PCIWriteConfig to read and write associated configuration information.

VOID
  PCIGetHandleInfo(
    PVOID  pHandle,
    PULONG  pulBus,
    PULONG  pulDevFunc
    );

Parameters

pHandle
PCIMP device handle.
pulBus
Pointer to a ULONG where this function writes the bus number.
pulDevFunc
Pointer to a ULONG where this function writes the device/function number.

Return Values

This function has no return value.

Comments

Because they may change, the miniport should not save the bus and device/function numbers across GART miniport services. The miniport need only call PCIGetHandleInfo at the beginning of functions that call PCIReadConfig and/or PCIWriteConfig.

The device/function number, although passed as a ULONG to preserve the stack alignment, contains only one byte of information, in the least significant part of the ULONG. The lowest three bits are the function number and the upper five bits are the device number. It is not likely that a GART miniport will need to use these values separately.


PCIReadConfig

The PCIReadConfig function reads hardware-specific configuration information from a given offset in the configuration space.

ULONG
  PCIReadConfig(
    ULONG  ulBus,
    ULONG  ulDevFunc,
    ULONG  ulOffset
    );

Parameters

ulBus
Bus number.
ulDevFunc
Device/function number.
ulOffset
Offset into configuration space. Must be between zero and 252.

Return Values

Returns the ULONG read from the given offset in the configuration space.


PCIWriteConfig

The PCIWriteConfig writes a value at the specified offset in the configuration space.

VOID
  PCIWriteConfig(
    ULONG  ulBus,
    ULONG  ulDevFunc,
    ULONG  ulOffset,
    ULONG  ulValue
    );

Parameters

ulBus
Bus number.
ulDevFunc
Device/function number.
ulOffset
Offset into the configuration space.
ulValue
Value to be written.

Return Value

This function has no return value.


PCIAllocatePages

The PCIAllocatePages function allocates pages from system memory.

PVOID
  PCIAllocatePages(
    ULONG  ulNumPages,
    ULONG  ulAlignment,
    ULONG  ulFlags
    );

Parameters

ulNumPages
Number of pages to allocate.
ulAlignment
Specifies an alignment mask for the acceptable starting pages for the physical address. The following values are provided.
Value | Meaning
0x00000000 | Address is a multiple of 4K.
0x00000001 | Address is a multiple of 8K.
0x00000003 | Address is a multiple of 16K.
0x00000007 | Address is a multiple of 32K.
0x0000000F | Address is a multiple of 64K.
0x0000001F | Address is a multiple of 128K.

ulFlags
Specifies the allocation flags. Must be zero or one of the following values.
Value | Meaning
PCIPAGEZEROINIT | Fills the pages with zeros. If this value is not given, the initial content of the memory block is undefined.
PCIPAGECONTIG | Allocates contiguous physical pages to create the memory block.
PCIPAGEWRITETHROUGH | Allocates using "write-through" memory.
PCIPAGECACHEDISABLE | Allocates using "uncached" memory.

All other values are reserved. The default is to allocate memory that is not zero initialized, not contiguous, and cached. It is invalid to specify both PCIPAGEWRITETHROUGH and PCIPAGECACHEDISABLE.

Return Values

This service returns NULL or the linear address of the allocated pages.


PCIFreePages

The PCIFreePages function frees the pages allocates with PCIAllocatePages.

VOID
  PCIFreePages(
    PVOID  pLin
    );

Parameters

pLin
Linear address previously returned by PCIAllocatePages.

Return Values

This function has no return value.


PCILinToPhys

The PCILinToPhys function converts a linear address to its corresponding physical address.

ULONG
  PCILinToPhys(
    PVOID  pLin
    );

Parameters

pLin
Linear address to be translated.

Return Values

Returns the physical address.


PCISetPhysicalCacheTypeRange

The PCISetPhysicalCacheTypeRange function marks the specified range of memory with the specified attributes.

ULONG
  PCISetPhysicalCacheTypeRange(
    PVOID  pPhysAddress,
    ULONG  ulNumBytes,
    MEMORY_CACHING_TYPE  ulCacheType
    );

Parameters

pPhysAddress
Specifies the start of the memory block being typed.
ulNumBytes
Number of bytes in the block.
ulCacheType
Memory type. Can be a combination of the following values.
Value | Meaning
PCIPAGEZEROINIT | 0x00000001
PCIPAGECACHEDISABLE | 0x00000002
PCIPAGECONTIG | 0x00000004
PCIPAGEWRITETHROUGH | 0x00000008

Return Values

Returns -1 if an error occurred.


IEEE 1394 Bus Drivers

See the Windows 2000 DDK for information about creating IEEE 1394 client drivers. The IEEE 1394 documentation, samples, header files, and libraries in the Windows 2000 DDK can be used in developing 1394 client drivers for Windows Me and Windows 98 as well as for Windows 2000.

The 1394 samples included in the Windows 2000 DDK can be built and run on Windows 98 Gold, Windows 98 SE, and Windows Me as is.

For more information on IEEE 1394 driver development for Windows 98 Gold, Windows 98 SE, Windows Me, and Windows 2000, see http://www.microsoft.com/hwdev/1394/.


WDM for Windows Millennium Edition

Built on Wednesday, July 11, 2001


Cross-Platform Issues for WDM Drivers

Floating Point Registers

Worker Threads

Power IRPs

Unavailable Functions in Windows Me

WDM Audio: Peakmeters

This document describes critically important differences between Windows® 2000 and Windows Me that affect WDM drivers. These issues are especially important to developers of cross-platform WDM drivers as they will influence your design and implementation decisions.


Floating Point Registers

Windows Me does not preserve floating-point registers when switching between kernel and user mode.

Use of MMX or floating point in kernel mode corrupts the register state of applications. A driver that modifies floating-point registers will therefore negatively affect applications that operate on floating point numbers. A driver must verify that it is running on Windows 2000 before executing MMX or FP instructions.


Worker Threads

Windows Me provides a fixed number of worker threads.

The fixed number of worker threads provided by Windows Me is not necessarily enough to satisfy the demands of drivers using functions such as ExQueueWorkItem and IoQueueWorkItem, giving rise to the likelihood of deadlocks especially during power operations. To minimize the deadlock risk, you can create your own dedicated threads to handle power operations or avoid queuing work items in situations that are known to cause deadlocks.


Power IRPs

Windows Me does not allow drivers to complete power IRPs at dispatch level.

Because Windows Me's core completion routines are pageable, drivers cannot complete power IRPs at dispatch level.


Unavailable Functions in Windows Millennium Edition

Windows Me provides a subset of the functions provided by Windows 2000.

The following functions are not implemented by Windows Me:

  • IoReuseIrp
  • RtlFillMemory
  • RtlUlongByteSwap
  • RtlUlonglongByteSwap
  • RtlUshortByteSwap
  • ExInterlockedAddLargeInteger
  • KeAcquireSpinLockAtDpcLevel
  • KeReleaseSpinlockFromDpcLevel
  • KeEnterCriticalRegion
  • KeLeaveCriticalRegion


WDM Audio: Peakmeters

How to Add Peakmeters to the WDM Driver

Peakmeters are nodes and have to be added to the driver topology. It is best to add the peakmeter node after the master out mute (or volume, whatever comes last). The same has to be done for the recording line and any additional lines if you want to have peakmeters there, too. The peakmeter node is "KSNODETYPE_PEAKMETER" and the property of this node is "KSPROPERTY_AUDIO_PEAKMETER". Set the name of the node to "KSAUDFNAME_PEAKMETER".

You will also need a property handler for this node. The property handler should support "KSPROPERTY_TYPE_GET", "KSPROPERTY_TYPE_BASICSUPPORT" and the usual "KSPROPERTY_AUDIO_CPU_RESOURCES".

The basic support handler is expected to return –32768 to 32767 for the data range, since this is the data range of 16 bit audio data. In the property handler for "get" you only have to read the HW peakmeter and return it. Be sure to check all parameters for vality before and also the channel information (left/right).

Unfortunately, there is no SW peakmeter available since the driver doesn't know what signals are on "Line In", "Microphone" or other inputs that are mixed with the playback channel.


Installing and Using USB Printers with Microsoft Windows

This section includes:

Introduction

USB and Parallel Port Printing Architecture on Windows Operating Systems


Introduction

Microsoft® Windows® 2000 and Windows Millennium Edition (Windows Me) supply a general kernel-mode USB print driver, Usbprint.sys, which works with the system-supplied port monitor Usbmon.dll to provide end-to-end connectivity between USB printers and high-level printer drivers. Together these components make up the Microsoft USB printing solution.

Vendors are encouraged to write high-level printer drivers that rely on Usbprint.sys rather than writing their own kernel-mode USB print drivers. Printer vendors can now redistribute Usbprint.sys and Usbmon.dll for installation on Windows 98 and Windows 98 Second Edition, making their Windows Me printing solutions backward-compatible with Windows 98. For information, contact Microsoft at USBWinPrint@microsoft.com

Usbprint.sys greatly simplifies the task of writing a high-level printer driver:

  • Usbprint.sys handles kernel-mode operations such as power management on behalf of the high-level printer driver.
  • Usbprint.sys provides an interface very similar to that used by parallel printers, so it is possible for a single printer driver to work correctly on both USB and parallel port, without modification.
  • Usbprint.sys has been extensively tested with numerous printers, dongles, PCs, and mobile systems on the Windows 2000 operating system.

For maximum cross-platform compatibility, vendor-supplied printer drivers should not depend on proprietary device-control commands or any parallel port IOCTLs except for IOCTL_PAR_QUERY_DEVICE_ID. A printer driver that follows these guidelines can drive printers over both USB and parallel port on Microsoft Windows 2000, Windows 98, Windows 98 Second Edition, and Windows Me operating systems.

Procedures for writing a printer driver are described in the Windows 2000 DDK and Windows 98 DDK. If such a driver is correctly implemented as described in the DDK, the driver should "just work," because the printer driver installation mechanisms are the same on all three operating systems, over any bus. For a list of references, see the end of this article.

Note Usbprint.sys and Usbmon.dll work together to simplify the task of writing a vendor-supplied language monitor. If a language monitor uses only the WritePort, ReadPort, and IOCTL_PAR_QUERY_DEVICE_ID interfaces, it will be portable between USB and parallel port.


USB and Parallel Port Printing Architecture on Windows Operating Systems

The following figure shows the system-supplied and vendor-supplied components that can be involved in printing over USB and parallel ports on Windows operating systems.


Windows USB and Parallel Port Printing Architecture

The only required vendor-supplied component is the high-level printer driver, which is layered above the spooler. A vendor can optionally supply a language monitor that is layered between the spooler and Usbmon.dll (for USB) or Localmon.dll (for parallel port).

This figure shows a vendor-supplied kernel-mode USB print driver (labeled IHV-supplied USB Print Driver) that is layered above the USB driver stack, which consists of Usbhub.sys, Usbd.sys, and some layers underneath. In the past, a vendor-supplied USB print driver was needed for USB printing on Windows 98 operating systems, which did not include an in-box kernel-mode USB print driver.

Printer vendors can now redistribute the Microsoft-supplied USB print driver and port monitor, Usbprint.sys and Usbmon.dll, for installation on Windows 98 systems. Microsoft is encouraging vendors to redistribute Usbprint.sys and Usbmon.dll rather than writing their own USB print drivers and port monitors.


The USB Printer Installation Process

USB printer installation varies slightly over Windows 2000, Windows Me, and Windows 98. This section gives the differences between the three operating systems in context of the general USB printer installation process.

For information about how Windows ranks drivers and selects the preferred driver to load, see "How Does Setup Select a Driver For a Device?" in the Windows 2000 DDK. This information also applies to Windows 98/Me. Driver selection is also influenced by digital signature and the driver signing policy in effect on the system. For information, see: http://whpg/hwdev/desinit/digitsign.htm

  1. The user connects a USB printer to the PC for the first time.

    All systems. The system displays the "Found New Hardware" message.

  2. The kernel-mode USB print driver is loaded.

    Windows 2000. On the basis of the USB printer's compatible ID (USB class code Class_07), Setup locates the system-supplied Usbprint.inf and uses it to load Usbprint.sys silently.

    Windows Me. The Add Hardware Wizard appears. The user points to a vendor-supplied Usbprint.inf or requests Windows Me to perform an automatic search for this file. After Usbprint.inf is found, Setup uses it to install Usbprint.sys.

    Windows 98. The Add Hardware Wizard appears. The user points to a vendor-supplied Usbprint.inf. After Usbprint.inf is found, Setup uses it to install Usbprint.sys from the vendor-supplied product media.

  3. The high-level printer driver is installed.

    Windows 2000. Setup looks through Ntprint.inf for a matching Hardware ID. If Setup finds an exact match in Ntprint.inf, it installs the corresponding in-box driver. The user sees a message that lists the vendor name and model of the printer.

    Otherwise, the Add Hardware Wizard pops up again. The user points to the location of the vendor-supplied INF and driver files, which Setup uses to install the vendor-supplied printer driver.

    Windows Me. Setup looks for a matching in-box printer driver and, if it finds one, loads that driver without prompting the user. Otherwise, the Add Hardware Wizard pops up again. The user points to the location of the vendor-supplied INF and driver files, which Setup uses to install the vendor-supplied printer driver.

    Windows 98. The Add Hardware Wizard appears and prompts the user to complete installation. The default installation point is the original vendor file location. Setup uses the vendor-supplied printer INF file to install the printer driver.

  4. The printer is fully installed and ready to print.


INFs for Installing USB Printing on Windows Operating Systems

This section presents two sample INF files that can be modified to install USB printing on Windows 98/Me and Windows 2000.

Vendors should supply unique Plug and Play hardware IDs (VID/PID) for their devices and modify these examples as needed before including them in their driver packages.

Vendors should also prepare INFs as follows before submitting their driver packages to WHQL for testing and digital signature:

  • Use the ChkINF and INFCatReady utilities to validate the INFs for digital signature.
  • ChkINF is provided in the Windows 2000 DDK. For information, see: http://www.microsoft.com/ddk/ddkdocs/win2k/chkinf.htm.
  • INFCatReady can be downloaded from the WHQL web site. For information, see http://www.microsoft.com/hwtest.
  • Submit the INFs with your driver package to WHQL for testing and digital signature. For information, see: http://www.microsoft.com/hwdev/desinit/digitsign.htm.


Installing USB Printing on Windows Me and Windows 98

To ensure that USB printers continue to work correctly when a user upgrades from Windows 98 to Windows Me, Usbprint.sys is supplied with the system but not automatically installed on Windows Me. This avoids any possible incompatibility with a vendor-supplied kernel-mode USB print driver that might already be installed on the user's system.

To install Microsoft USB printing support on Windows 98 operating systems, printer vendors can use the same Usbprint.inf file as for Windows Me and can redistribute the files Usbprint.sys and Usbmon.dll with their driver packages. (On Windows 2000, Usbprint.inf is already on the system, so a vendor-supplied Usbprint.inf is not needed.)

The following example shows a Usbprint.inf file that can be used to install Usbprint.sys on Windows 98 or Windows Me. Notice the following [CopyFiles] section in the INF:

[USBPRINT_Inst.CopyFiles]
usbprint.sys,,,16

This entry uses the COPYFLG_NO_OVERWRITE flag (hexadecimal 10) to instruct Setup not to copy this file if it already exists on the system, which causes Setup to install Usbprint.sys on Windows 98 and Windows 98 SE but not on Windows Me. Usbprint.sys on Windows Me is a system-protected file and is already present, so this file does not need to be installed by a driver package.

[Version]
Signature="$CHICAGO$"
Class=USB
ClassGUID={36FC9E60-C465-11CF-8056-444553540000}
Provider=%MSFT%
DriverVer=12/17/1999
CatalogFile=print9x.cat

[ControlFlags]
ExcludeFromSelect = *
[DestinationDirs]
DefaultDestDir = 10,system32\drivers

[Manufacturer]
%MSFT%=Microsoft

[Microsoft]
%USBPRINT.DeviceDesc% = USBPRINT_Inst,USB\Class_07

[USBPRINT_Inst]
Copyfiles = USBPRINT_Inst.CopyFiles
AddReg    = USBPRINT.AddReg
DriverVer=12/17/1999

[USBPRINT_Inst.CopyFiles]
usbprint.sys,,,16

[USBPRINT.AddReg]
HKR,,DevLoader,,*ntkern
HKR,,NTMPDriver,,"usbprint.sys"

[SourceDisksNames]
1 = "USB disk",,,""

[SourceDisksFiles]
usbprint.sys = 1

[strings]
MSFT                  = "Microsoft"
USBPRINT.DeviceDesc   = "USB Printing Support"


Writing a Cross Platform INF to Install USB Printer Drivers

This section describes a cross-platform printer INF that will install a USB or parallel printer driver on Windows 2000, Windows Me, and Windows 98. This generic INF can also be used to install a parallel printer on Windows 95. Notice the following about this INF:

  • In the [DRIVER.DRV] section, the following entry ensures that the Microsoft-provided USB port monitor is installed under Windows 98:

    PortMonitor=usbmon.dll,usbmon.dll

  • In the [MONITOR] section, the following entry instructs Setup not to copy this file if it already exists on the system:

    usbmon.dll,,,16

This entry uses the COPYFLG_NO_OVERWRITE flag (hexadecimal 10) to instruct Setup not to copy this file if it already exists on the system. This causes Setup to install Usbmon.dll on Windows 98 and Windows 98 SE but not on Windows Me. Usbmon.dll on Windows Me is a system-protected file and is already present, so this file does not need to be installed by a driver package.

[Version]
Signature="$CHICAGO$"
Class=Printer
ClassGUID={4d36e979-e325-11ce-bfc1-08002be10318}
Provider=%MS%
CatalogFile=print9x.cat
CatalogFile.NT=print2K.cat
DriverVer=1/1/2000,4.00.2450.1

; The Manufacturer section lists all of the manufacturers that we will
display in the Dialog box

[Manufacturer]
"Man"

[HP]
"Man printer" = DRIVER.DRV,MYPNPID

[DRIVER.DRV.NT]
; Windows 2000 printer driver installation entries go here.

[DRIVER.DRV]
; Windows 95/98/Me printer driver installation entries go here.

CopyFiles=@DRIVER.DRV,UNICLR,FINSTALL,MONITOR
DataSection=UNI_DATA
PortMonitor=usbmon.dll,usbmon.dll
DriverVer=1/1/2000,4.00.2450.1

[MONITOR]
usbmon.dll,,,16

[FINSTALL]
finstall.dll
finstall.hlp

[UNICLR]
iconlib.dll
dmcolor.dll
unidrv.dll
unidrv.hlp

[UNI_DATA]
HelpFile=unidrv.hlp
DefaultDataType=EMF

[DestinationDirs.NT]
DefaultDestDir=66000

[DestinationDirs]
DefaultDestDir=11

[SourceDisksNames.NT]
2  =  %Disk2%,,,""

[SourceDisksNames]
1  =  %Disk1%,,,""

[SourceDisksFiles.NT]
;NT files to install

[SourceDisksFiles]
printer.inf  = 1
finstall.dll = 1
finstall.hlp = 1
driver.drv   = 1
iconlib.dll  = 1
dmcolor.dll  = 1
unidrv.dll   = 1
unidrv.hlp   = 1
usbmon.dll   = 1

[Strings]
MS="Microsoft"
Disk1="Win9x disk"
Disk2="Win2000 disk"


FAQ for USB Printer Installation

This section provides answers to some frequently asked questions about USB printer installation.

Q: If a user has installed my company's USB printing solution for Windows Me, what happens if a second vendor's solution tries to load?
A: The two solutions might conflict with each other and interfere with successful printing on the user's system. The operating system cannot detect or prevent such conflicts. It is recommended that vendors use the Microsoft USB printing solution.
Q: If my company supplies a top-to-bottom USB printing solution for Windows 98 and Windows Me, what is the mechanism for upgrading to the Microsoft USB printing solution?
A: Uninstall the vendor-supplied solution completely and then install the Microsoft solution. It should be possible for an update program to uninstall the vendor-supplied solution transparently, without requiring specific action on the part of the user. However, it is recommended that an update include instructions in case the user wants to perform these steps manually.
Q: If my company wants to use the Microsoft USB printing solution for Windows 98, what is the process for redistributing those files?
A: Contact Microsoft at USBWinPrint@microsoft.com for information about redistributing these files.
Q: My company has a USB printing solution for Windows Me. What is the process for driver signing? What files do I have to submit?
A: Submit your entire driver package to WHQL for testing and digital signature, as described at: http://www.microsoft.com/hwdev/desinit/digitsign.htm
Q: If my company uses the Microsoft USB printing solution for Windows 98, what happens when the user upgrades to Windows Me or Windows 2000?
A: The printer will continue to work. The user will not have to reinstall the printer after upgrading.
Q: If my company wants to redistribute Usbprint.sys and Usbmon.dll for Windows 98, do I have to resubmit the driver package to WHQL for testing?
A driver's digital signature is generated from the complete set of binaries in the driver package. Adding files or changing existing files in the package invalidates the existing digital signature. The driver package must be resubmitted to WHQL for testing and a new digital signature.


Call to Action for Windows USB Print Drivers

Built on Wednesday, July 11, 2001


Install USB printer drivers on Windows operating systems as described in this article.

  • On Windows 2000 and Windows Me, use the Microsoft-provided USB print driver, Usbprint.sys.
  • On Windows Me, provide a Usbprint.inf file in your driver package to load Usbprint.sys.
  • On Windows 98, redistribute Usbprint.sys and Usbmon.dll rather than writing a custom kernel-mode USB printer driver. For information, contact Microsoft at: USBWinPrint@microsoft.com
  • Write a cross-platform INF to install your printer driver on Windows 2000 and Windows 98/Me.
  • Use the COPYFLG_NO_OVERWRITE flag (hexadecimal 10) in INF [CopyFiles] sections to prevent Setup from copying a file that already exists on the system.


Use the following tools to prepare INFs for submission to WHQL.

  • For information about ChkINF, see http://www.microsoft.com/ddk/ddkdocs/win2k/chkinf.htm
  • For information about INFCatReady, see http://www.microsoft.com/hwtest/


Submit your driver package to WHQL for testing and digital signature.

For information, see: http://www.microsoft.com/hwdev/desinit/digitsign.htm


Attend the printer driver development forum at WinHEC 2000.

For information, see: http://www.microsoft.com/winhec/


Read about Windows printer drivers and USB printing.

Windows 2000 Driver Development Kit, available online at: http://www.microsoft.com/ddk/ddkdocs/win2K/

  • Graphics Drivers > Design Guide > Part 3: Printer Drivers and Spooler Components
  • Supplemental Documents > Print
  • "Printing Plug and Play for Windows 2000"
  • "USBPRINT Interfaces"

Windows 98 Driver Development Kit, available online at: http://www.microsoft.com/ddk/ddkdocs/win98ddk/

  • Related Driver Documentation > Supplementary Windows 98 Documentation > Printer Driver Additions
  • Related Driver Documentation > Windows 95 Documentation > Printer Driver Overview

Universal Serial Bus Device Class Definition for Printing Devices at: http://www.usb.org/developers/data/devclass/usbprn10.pdf.


I/O Supervisor Guide

This purpose of this document is severalfold:

  • To serve as a master integrating road map addressing the Input/Output Supervisor (IOS) technology
  • To update the reader with the latest information about IOS technology, tools and tips
  • To enhance (but not necessarily replace) the "Storage Technology Reference" section of the Windows 95/98 Device Driver Kit (DDK) available by MSDN® subscription or as a free download at http://www.microsoft.com/ddk

See Additional Resource Materials, for companion resources.


Introduction to I/O Supervisor

IOS is a key kernel component in Microsoft® Windows® operating systems, managing the following hardware technologies:

  • IDE fixed and removable storage devices (disk drives, CD-ROM, DVD and so on)
  • SCSI fixed and removable storage devices (disk drives, CD-ROM, DVD and so on)
  • Legacy 1.44MB floppy disk technology
  • Storage devices using other hardware interfaces such as a parallel port
  • SCSI pass through (tape drives, printers and other devices connected to SCSI bus)
  • USB storage devices

IOS does NOT address remote storage devices (devices accessed through the network using VREDIR.VXD, VSERVER.VXD, and so on).

IOS is carried forward in Windows 95 and later versions of the operating system, including:

  • Windows® 95 OSR2
  • Windows® 98
  • Windows® 98 Second Edition
  • Windows® Millennium Edition (Me)

Detailed technical material is located in the Appendices section, organized in reference material format, in order to make its use more convenient for debugging and development.


Storage Technology Version History

Windows Version | Distinguishing characteristics
Windows 95 Gold (original release) (Version A)
OSR2 (version B) • SMART hard disk technology support added (SMARTVSD.VXD).

• ESDI_506.PDR enhanced to accommodate SMARTVSD.VXD using IDE Passthrough (see Knowledge Base articles Q196550 and Q208048)

• IOS.VXD is corrected to allow preload VSDs to work correctly (see the Master Boot Record FAQ referenced in Knowledge Base article Q192606)
Windows 98 (original release) | • Power management added to ESDI_506.PDR port driver (ACPI support including timed automatic disk spin down).
Windows 98 Second Edition | • CDVSD is corrected to accommodate third-party DVD SCSI miniport interfaces (see Knowledge Base article Q208048)
Windows Me • Additional suspend/resume and hibernation support.

• Added debugger dot commands .IDUMP, .IDIDA, .IDDVT, .IDDCB to the debug version of IOS.VXD (use .I? for complete list).


IOS General Architecture

The figure below describes the overall structure of IOS device drivers that are used to interface local physical storage devices. Note that each module is labeled by number, for ease of reference in the table that follows.

Port drivers are located at the "bottom" of the IOS hierarchy, closest to the hardware. Most storage technology device driver developers use the SCSI miniport driver model to interface with their hardware (items 30 or 31 in the diagram above).

Module(s) | Comments
1, 2, 3 | These are client applications that use IOS to access all local storage devices.
4, 5, 11, 12, 18 | These modules implement the ASPI specification. ASPI is designed to provide low-level communications (at the SCSI Request Block, or SRB, level) between applications and SCSI miniport devices or (IDE) ATAPI devices. Adaptec provides this technology.
6 | The Installable File System (IFS) oversees storage data at the file system level, managing the host File System Drivers (FSDs).
7-10 | File System Drivers (FSDs) manage the format of the file systems contained on storage devices.
13 | The I/O Supervisor (a.k.a. I/O Subsystem), manages storage devices at the physical and logical partition level. It understands storage devices at the "drive number" and "sector number" level.
14 | The Volume Tracker is used to accommodate removable media devices, including PCCARD, USB, SCSI, IDE and ATAPI technologies.
15 | DISKTSD.VXD assigns logical drive letter(s) to each disk-type storage device, when given a physical DCB assigned to the given device.
16 | CDTSD.VXD assigns drive letter(s) to CD-ROM storage devices, when given a physical DCB assigned to the given device.
17 | RMM.VXD is used to direct I/O to real-mode driver(s), for when there is no functioning 32-bit protected-mode device driver for the device.
19 | ATAPCHNG.VXD is installed as needed when a CD-ROM changer is present.
20 | DISKVSD.VXD is the disk device SCSI'izer, amending its IOP into a full-blown SCSI request (complete with SCSI Request Block).
21 | CDVSD.VXD is the CD-ROM device SCSI'izer, amending its IOP into a full-blown SCSI request (complete with SCSI Request Block).
22 | SMARTVSD.VXD allows a Win32® application to obtain S.M.A.R.T. statistics from IDE disk drives. See Knowledge Base article Q208048 for sample Win32 source code.
23 | SCSI1HLP.VXD inspects CD-ROM I/O requests and compares each request against the manufacturer and model of CD-ROM. It modifies the request if needed, to accommodate special requirements, or correct unusual behavior, of certain CD-ROM devices. In some cases, SCSI1HLP will force SCSI 1 protocol behavior. SCSI1HLP also "helps" ATAPI CD-ROM devices.
24 | HSFLOP.PDR handles floppy diskette drives.
25 | ESDI_506.PDR handles IDE drives and ATAPI devices. ATAPI CD-ROM and similar ATA devices appear to IOS as if they are SCSI devices, i.e. the IOP packet includes a SCSI Request Block (SRB).
26 | SCSIPORT.PDR supplies the interface to one or more SCSI Miniport device drivers. SCSIPORT implements the Windows NT miniport standard, orchestrates the loading and initialization of miniport drivers, exports a number of services available to Miniport device drivers, and coordinates I/O between IOS and the miniport driver.
27 | IOS accommodates OEM-defined and developed components, including Vendor Supplied Drivers (VSDs) and Port Drivers.
28 | These are DOS real-mode based drivers that are used until IOS replaces these drivers with their (higher-performance) protected-mode counterparts.
29 | The SCSI Miniport is the most common technique used to develop custom port drivers. The Windows NT Device Driver Kit supplies a sample ATAPI.SYS miniport driver. This driver sample is binary compatible with Windows 95. If used, it is renamed to ATAPI.MPD and placed into the \system\iosubsys directory. This miniport driver can be used to replace much of the functionality of ESDI_506.PDR.
30 | SCSI Miniport drivers, originally developed for Windows NT, are the most common interface to SCSI adapter cards (and the attached SCSI devices) to the rest of the system. A sample functional IDE/ATAPI miniport driver (ATAPI.C) is available in the Windows NT 4 DDK.
31 | SCSI Miniport drivers can also be used to interface Parallel-port based devices such as external tape drives and external hard drives, or to interface unusual hardware, making the device appear as a SCSI device.

Each IOS-supervised driver is located in the \system\iosubsys folder.

After a driver is dynamically loaded by IOS during its Device_Init phase, IOS sends the SYS_DYNAMIC_DEVICE_INIT message to the control dispatch procedure of the newly loaded driver. The driver responds to this message by registering itself with IOS using the IOS_Register(&DRP) call.

A VxD may reside in the \system\iosubsys folder and not call IOS_Register. This is generally not good practice if the VxD does not require use of IOS services. If this is done, the DRP declaration must still be used, because IOS expects it to be there when it is dynamically loading the device, even if the device does not use IOS services.

The complete IOS_Register() process is available in IOS Registration Flowchart.

All IOS-specific data structures (IDA, DVT, DDB, DCB, VRP etc) and fields within each data structure are detailed in IOS internal data structure detail, including a block diagram showing the linkages between the structures.

If you are using the Windows Me debug version of IOS.VXD, you can use the IOS dot command .IDUMP for a complete dump of all internal IOS structures on your debugger terminal.

For more information, see Debugging Tools.

For details regarding all the IOS Services, please refer to the "Storage Technology Reference" section of the Windows 95/98 Device Driver Kit (DDK).


SCSI (NT 4) Miniport Driver Topics

This section contains assorted topics of interest to developers of SCSI miniport drivers using the Windows NT 4 Miniport model, targeting the Windows 95/98 or Windows Me platforms.

The miniport interface is the same for Windows NT and Windows 95; hence the Windows NT DDK's ATAPI miniport sample, when compiled under an NT-based operating system, works under Windows 95. There is a strict miniport protocol, designed to be portable (binary code compatible) between systems. This protocol is violated, however, if there are embedded Windows 95 VxDCall(s) or embedded Windows NT system calls within the SCSI miniport driver. Unfortunately, there are a few cases under Windows 95 where VxDCall(s) are necessary, thus breaking binary compatibility. For example, Windows 95's ScsiPortGetDeviceBase function fails to return a linear address (as described in Knowledge Base article Q169584). This means that the miniport must use a Windows 95 VMM function _MapPhysToLinear to map the physical address to a linear address.

A brief summary of the SCSI Miniport initialization sequence

  1. IOS calls the miniport's DriverEntry routine as a result of Configuration Manager devnode enumeration.
  2. The miniport calls ScsiPortInitialize (for each supported bus).
  3. SCSIPORT.PDR calls IOS_Register as a result of each call to ScsiPortInitialize.
  4. IOS_Register presents an AEP_initialize message to SCSIPORT. SCSIPORT creates a DDB, reads miniport ASCII configuration information from registry, and then calls the miniport's HwFindAdapter routine (e.g. FindController). This should occur for each bus.
  5. IOS_Register creates a temporary "inquiry" DCB and issues an AER_Device_Inquiry for each supported LUN number, and so on.
  6. Each instance of step 5 causes SCSIPORT to create an IOP, for a SCSI_PASS_THROUGH inquiry command, and sends it to the miniport's StartIo routine.
  7. For each inquiry, the miniport either succeeds or fails. If it succeeds, SCSIPORT sets up the DCB_product_id, DCB_vendor_id and DCB_rev_level into the DCB and returns AEP_success. to IOS.

Steps 2-7 occur for each bus type supported.


Windows NT IOCTL Unavailable with Windows 95

Windows NT uses a miniport IOCTL interface that is not available with Windows 95.

Windows NT allows you to send IOCTLs to SCSI miniports, using CreateFile, and a filespec such as "\\.\Scsi0" and "\\.\c:". A sample application that uses this technique is found in the Windows NT DDK: \ddk\src\storage\class\spti.

Windows 95 does not support this Windows NT IOCTL technique.

If you want to issue private commands to a (Windows 95) miniport, you can send a SCSI request to it using ASPI16 or ASPI32 (which uses the IOS "SCSI passthrough" message structure). Create a unique function code in the CDB being sent to it, that your miniport can interpret as a custom command. There is sample code in the Windows 95 DDK (\DDK\Block\SAMPLES\WNASPI32, documentation is in \DDK\Docs\DESGUIDE\STORAGE.DOC), which performs simple drive inquiry functions. ASPI is implemented using WINASPI.DLL (for 16-bit applications) or WNASPI32.DLL (32-bit applications) at Ring 3. These DLLs communicate with (ring 0) APIX.VXD, located in the IOS layered hierarchy. APIX, located at layer 11 of IOS, injects IOR_SCSI_PASS_THROUGH commands into IOS.

Another possible communications technique under Windows 95 is to write a "helper" Vendor Supplied Driver (VSD) that communicates with the user application using (Windows 95) DeviceIoControl(), behaving similarly to APIX.VXD (used by ASPI). The VSD could set up its own private IOP pointing to a private SRB that contains the appropriate SRB_FUNCTION_IO_CONTROL function. The VSD could then issue an ILB_internal_request, which sends the IOP request down to the miniport driver.

A sample passthrough VSD, available from the Windows 95 DDK Support Team, is bundled in the following file: PASSTHRU.ZIP (see IOS Sample Code). This sample demonstrates how to build the necessary SCSI Passthrough IOP packet. The sample will require changes, for example, in its IOCTL handler, which currently does nothing but will need to be modified to forward requests using ILB_internal_request.

An example of a Win32 application communicating with a generic Windows 95VXD using CreateFile() and DeviceIoControl() is in the Windows 95 DDK, \DDK\Base\SAMPLES\ASYNCW32. This sample, coupled with the Passthrough sample, can be used to create the desired "helper" VSD.


Older Windows NT Miniport Drivers

Older miniport drivers written for Windows NT do not include Plug and Play information and, therefore, will not perform well on Windows 95.


Unraveling the Scatter-Gather Descriptor Confusion

There are two different types of Scatter Gather Descriptors: linear (also known as logical) and physical.

Walt Oney's book, Systems Programming for Windows 95, includes some discussion of this issue.

Linear SGDs

The linear SGD structure is defined in \ddk\inc32\blockdev.h (as _BlockDev_Scatter_Gather):

typedef struct BlockDev_Scatter_Gather{
  ULONG BD_SG_Count;
  ULONG BD_SG_Buffer_Ptr;
}  _BlockDev_Scatter_Gather     ;

A linear SGD consists of a DWORD count followed by a DWORD linear pointer. The count is always assumed to be a block count within SCSIPORT's transfer routines (such as ScsiPortReadPortBufferUchar). Linear SGDs are terminated with a zero-length SGD element, but you should use IOR_xfer_count for total length information (this field contains the sector count if IORF_CHAR_COMMAND is not set). The IOP's IOR_buffer_ptr points to a normal linear memory buffer if (IOR_flags & IORF_SCATTER_GATHER)==FALSE. Otherwise, IOR_buffer_ptr points to a simple list of linear SGDs as defined in blockdev.h.

Physical SGDs

The physical SGD structure is defined in \ddk\inc32\sgd.h (as _SGD):

typedef struct _SGD { /* */
  ULONG  SG_buff_ptr;     /* 32-bit physical pointer to the buffer
  ULONG  SG_buff_size;    /* size of the buffer in bytes
} SGD, *PSGD;

The physical SGD structure consists of a DWORD physical pointer followed by a DWORD count (the ordering is the reverse of that used in the linear SGD structure). If the port driver demanded the physical SGD creation service, then the DCB_dmd_phys_sgd bit will be set within DCB_dmd_flags.

Inside SCSIPORT.PDR, the ILB_int_io_criteria_rtn is called before forwarding any read/write to the miniport driver. ILB_int_io_criteria_rtn will create physical SGDs if DCB_dmd_phys_sgd is set. In this case, the IOP's IOR_sgd_lin_phys field must point to a valid memory buffer, designed to accommodate the max number of physical SGDs (DCB_max_sg_elements). Each SGD is eight bytes long. It would be safe to assign (17*8) bytes of memory for IOR_sgd_lin_phys since the maximum number of SGDs is 17.


BufferAccessScsiPortControlled Flag Information

The Knowledge Base article Q116450, "BufferAccessScsiPortControlled Flag Information," describes a mechanism in Windows 95 to improve miniport performance (throughput).

Under Windows 95, if the miniport driver does not report that it supports scatter-gather, then it will only see read requests for one block at a time.

The ScatterGather flag is used to determine if the miniport can handle more than one SGD. If you do not set this flag to true, then SCSIPORT.PDR will assume that the number of SGDs is one. Typically this will result in your miniport only getting I/O requests for one block at a time.

This is obviously a problem for PIO devices, which do not typically support the concept of scatter-gather. In these cases it is possible to force SCSIPORT.PDR to emulate scatter-gather on behalf of your device. This is done by setting BufferAccessScsiPortControlled=TRUE in the PORT_CONFIGURATION_INFORMATION structure in your SCSI miniport.

Note that this field was originally only documented in the Windows NT 3.5x DDK (it was accidentally omitted from the Win95 DDK documentation). It is, however, correctly defined in the Windows 95 DDK include files. Also be aware that it is very important to not access the data buffer directly in your miniport when this flag is set; instead you should only use ScsiPort functions to access the buffer. This is due to the fact that the buffer will not be a linearly contiguous block, but instead will be a list of linear scatter-gather descriptors.

The Master field of Port_Configuration_Information is used to determine if system DMA is required. If SCSIPORT.PDR receives any indication that system DMA is required, it will allocate a 64K physically contiguous block of memory for use as a DMA buffer, and transfer lengths will be limited to 64K. Set the flag Master=TRUE if you do support bus mastering.

When using BufferAccessScsiPortControlled:

  • PIO should work fine because BufferAccessScsiPortControlled was designed for this purpose. Bus-mastering devices should not set this field to TRUE.
  • Never modify the SRB's DataTransferLength or DataBuffer. The ScsiPort{Read,Write}... functions actually scan through the chained list of SRBs in the system, matching the I/O range against DataBuffer / DataTransferLength of each pending SRB. When found, if IOR_flags.IORF_SCATTER_GATHER is set, IOR_buffer_ptr points to a list of scatter-gather descriptors, and the routine does "emulation" of scatter-gather data transfer, moving data to or from the scatter-gather memory areas. If IORF_SCATTER_GATHER is false, DataBuffer is used directly (it is assumed to be a linear address). Note that within an IOP's SRB, there is a pointer to its corresponding IOP (SrbIopPointer). This pointer can be used to inspect IOP/IOR fields such as DataBuffer, IOR_flags, and so on, when debugging.
  • Always use the ScsiPort{Read,Write}Buffer... functions when accessing your buffer.

Here is a brief description of what ScsiPortReadPortBufferUchar (and its generic counterparts) do:

  1. Scan SCSIPORT's active SRB list, examining the .DataBuffer and .DataTransferLength fields. Attempt to find a buffer that "contains" the memory address requested. If it fails, perform the desired transfer between buffer and port without using any IOP / SRB information. Then quit.
  2. Given the SRB, obtain the .SrbIopPointer. Use this to inspect for (IOR_flags and IORF_SCATTER_GATHER). If this bit is clear, perform the desired transfer between buffer and port, without using any IOP / SRB information at all. Then quit.
  3. At this point the operation is using linear SGDs. Perform the desired transfer between buffer and port, using the linear SGDs to reference the scattered chunks of memory. When the count has been exhausted, quit. Note that care must be taken to not request too many bytes, since you will run off the end of the SGD list (the code does not appear to audit for a zero-length SGD element).


How to Uniquely Identify a Specific SCSI Adapter in a DCB

A custom VSD, installed within the layered hierarchy of IOS, can uniquely identify a specific SCSI adapter by inspecting the following DCB fields: DCB_port_name, DCB_scsi_hba, and DCB_bus_number.


Dynamic Device Removal/Installation (Hot-swapping)

SCSIPORT.PDR, working in concert with IOS, supports hot swapping. In order to detect hardware changes, a custom-written IOS layer VxD can periodically check for hardware insertion or removal. When either event is detected, the custom VxD can call CONFIGMG_Reenumerate_Devnode() at AppyTime. This will cause SCSI device reenumeration. SCSI device reenumeration issues a SCSI Device Inquiry command to all devices associated with SCSI miniports, to detect the arrival or disappearance of SCSI physical devices (see IOS Registration Flowchart, chart 5 for details).

IOS detects new devices and devices which have disappeared, and issues the corresponding system messages to inform the operating system of the device change(s).

If you are developing your own ATAPI miniport driver, you can take the necessary actions within the miniport driver itself when the hardware is inserted or removed. Modify the driver to make sure it completes pending I/O that has become stuck because the hardware was unplugged (or while in the process of plugging the device in). This prevents causing the system to hang, waiting for any orphaned IOPs to complete.

In order to locate the devnode associated with the hot-swappable device, one method is to use the SETUPX API DiGetClassDevices to find all instances of the class you are interested in (for SCSI the class is "SCSIAdapter").

ScsiPortSetBusDataByOffset

This function is intended only for use when first initializing the bus. If you wish to read or write PCI Configuration Space after initialization, refer to Knowledge Base article Q140730 for more information.

This function was missing from the original Windows 95 DDK documentation but can be found in the original header file \DDK\BLOCK\INC\SRB.H.

In SCSIPORT.PDR, this routine actually is simply a wrapper to the following call: CONFIGRET CONFIGMG_Call_Enumerator_Function(DEVNODE dnDevNode, ENUMFUNC PCI_ENUM_FUNC_SET_DEVICE_INFO, ULONG Offset, PFARVOID Buffer, ULONG Length, ULONG 0).

ScsiPortSetBusDataByOffset automatically accommodates non-DWORD granular boundaries by selectively preceding and/or post pending I/O accesses with byte or word granular accesses to PCI configuration space. Thus you can write one BYTE, one WORD or one DWORD, with the correct I/O data width being issued to the PCI chip.


Obtaining Both an I/O Range And a Memory Window From Within a SCSI Miniport

If a device has both I/O and memory windows, SCSIPORT will only populate the ACCESS_RANGE array with the I/O windows.

Currently the only work-around for this problem is to read the PCI configuration space directly to get addresses of the memory windows.


Mapping Between Physical and Linear (Logical) Memory

The following SCSIPORT option flags deal with the usage of physical memory and virtual memory.

Master
If true, during SCSIPORT's CONFIG_DCB, it sets a ceiling of seventeen DCB_max_sg_elements. Also if Dma32BitAddresses=0, it sets DCB_dmd_small_memory (used if the total memory accessible by bus-master device is 16MB or less), and if applicable to the bus type, calls VDMAD_Virtualize_Channel.
MapBuffers
The purpose of this flag is to notify the SCSIPORT manager that all data buffer addresses need to be mapped to virtual addresses, in order to allow the miniport driver access to them.
NeedPhysicalAddresses
This flag causes the following DCB demand bit to be set: DCB_dmd_phys_sgd. When SCSIPORT prepares an IOP, it calls the IOS's I/0 criteria routine (ILB_int_io_criteria_rtn). If the DCB demand flag DCB_dmd_phys_sgd is set, ILB_int_io_criteria_rtn performs the service of converting the data buffer (or linear SGD list) pointed to by the (linear) IOR_buffer_pointer, into a physical SGD list pointed to by IOR_sgd_lin_phys. For more information, see Unraveling the Scatter-Gather Descriptor Confusion.


CD-ROM and DVD CD-ROM Issues

Built on Wednesday, July 11, 2001


Setting the ANSI-approved Version field in the INQUIRY response

You should typically set the ANSI-approved Version field, in the INQUIRY response, to at least 2.

Install the debug version of SCSI1HLP, CDVSD and CDTSD. Check for the following message:

SCSI-I helper VSD found SCSI-1 CD-ROM, taking over

This message indicates that SCSI1HLP believes that an old CD-ROM drive is being used because the ANSI-approved Version field is less than 2. In the SCSI II Specification for the returned INQUIRY packet, byte offset 2, the first three bits, there is a 3-bit ANSI value field. ATAPI normally returns 0 in this field, but you need to put a 2 in that field. For example, SCSI1HLP.VXD inspects this field to determine whether it needs to "help" the command. The port driver ESDI_506.PDR changes that field to 2 also.

SCSI1HLP is then installed to allow old legacy CD-ROM drives (with unusual commands) to work. This will only happen if the INQUIRY command returns a value of less than 2 in the ANSI-approved version field. Thus, new SCSI miniport drivers typically should always set the ANSI-approved version field to 2 or higher.

Note that SCSI1HLP will also load itself if it finds the DCB_DEV2_ATAPI_DEVICE bit set (see below), but you will not see it reported to the debugger.


Additional Potential Problems for DVD Miniport Drivers

Details regarding Knowledge Base hotfix article Q197004, "Fatal Exception in CDVSD Starting Windows 98"

For Windows 98, the CDVSD.VXD IOS layer driver has been updated to accommodate DVD-ROM drives. The main CDVSD is at layer 13 (DRP_VSD_5), and a new "timer extender" layer is introduced at layer 14 (DRP_VSD_6) to extend the length of time DVD commands are allowed before a timeout occurs. If a system contains a DVD-ROM drive, there must be no custom VSDs "chained in" between CDVSD (DRP_VSD_5) and SCSIPORT (DRP_NT_MPD), because the IOS callback routine in CDVSD (label VSD_Callback) depends on the current call down chain pointer to get the address of CDVSD's DRP. The current call down pointer will point to your custom VSD instead of CDVSD, ultimately resulting in a system crash. If you do not insert your custom VSD into the call down chain, but merely use the VSD to modify DCB structures for example, then this restriction does not apply. This problem has been corrected for Windows 98 Second Edition.

Another restriction is that if you use a custom VSD to set the DCB's DCB_DEV2_ATAPI_DEVICE flag (more information on this bit follows), your VSD must be located above SCSI1HLP.VXD in the IOS hierarchy (DRP_VSD_7 or lower), to prevent SCSI1HLP from being loaded and subsequently causing CDVSD's VSD_Callback code to fail. SCSI1HLP normally is used in conjunction with ESDI_506 to convert SCSI commands to ATAPI and vice versa, but is not used for DVD-ROM devices. SCSI1HLP automatically loads itself if it sees DCB_DEV2_ATAPI_DEVICE set.

SCSI1HLP can cause further problems with some devices. SCSI1HLP checks to see if MSCDEX is present; if it is present, CDVSD will not take over the CD-ROM drive because of the assumption that the MSCDEX driver will do a better job of dealing with a SCSI-1 CD-ROM drive than the p-mode IOS driver stack will. This leads to serious problems for PCI devices because they cannot share IRQs with real-mode devices.

Supporting Audio CDs

Here are the basic steps for supporting audio CDs in an ATAPI miniport driver:

  1. Return an ANSI value of 2 in the INQUIRY data.
  2. Convert MODE SENSE and MODE SELECT CDBs from 6-byte to 12-byte CDBs. This involves:
    1. converting the 6-byte command value to a 12-byte command value (1Ah to 5Ah, and so on).
    2. moving the allocation length value from byte 4 in the CDB to bytes 7-8.
    3. zeroing out other CDB bytes above byte 5 (Windows 95 does not zero these out automatically).
  3. Upon completing the command, the original CDB must be restored in the SRB. It is probably easiest to store the CDB in the miniport's SRB extension, and to restore it when the command completes.
  4. Convert the parameter page format from ATAPI to SCSI (for MODE SENSE), and vice versa (MODE SELECT). This essentially means you must convert from an ATAPI format, which looks like this:

    8-byte MODE PARAMETER HEADER

    n-byte PARAMETER PAGE

    ..to or from a SCSI-2 format, which looks like this:

    4-byte MODE PARAMETER HEADER

    8-byte MODE BLOCK DESCRIPTOR

    n-byte PARAMETER PAGE

    This means that the allocation length in the CDB will need to be increased or decreased by 4-bytes to account for the differences in the size of the parameter headers for SCSI-2 and ATAPI.

  5. Track the current block size for the CD-ROM drive, and return the correct logical block size in the block descriptor for MODE SENSE commands.

    When CDVSD issues a MODE SENSE command, it is looking for a non-zero value in the block-length field of the block descriptor. When it finds a non-zero block length (which apparently indicates support for changeable block size), it will issue the same MODE SENSE command again, for current values rather than for changeable values. In this case it will expect the current block size for the device to be listed in the block length field (2048 or 2352 bytes). The ATAPI miniport must keep track of the current block size as given in the MODE SENSE commands (2048 is the default), and return this value in the block descriptor for MODE SENSE commands.

  6. Insure that ScsiStatus is set to zero when a data underrun occurs. The NT 4 ATAPI miniport sample may not always do this correctly.

Using the DCB_DEV2_ATAPI_DEVICE Bit

The port driver ESDI_506.PDR sets the DCB bit DCB_DEV2_ATAPI_DEVICE for the IDE ATAPI CD-ROM device that it controls. SCSI1HLP detects this bit during CONFIG_DCB time and chains itself into all IOPs directed at that device. When such a SCSI command is received by SCSI1HLP, it translates the command between SCSI and ATAPI packet formats, so ESDI_506 sees only ATAPI commands. SCSI1HLP also translates ATAPI back to SCSI. When writing a SCSI miniport driver to replace the functionality of the ESDI_506 driver, this bit can be set by a custom VSD, subject to the restrictions discussed earlier in this section.

Implementing Atapi CD-Changer (Using DCB_DEV2_ATAPI_DEVICE)

The ATAPI changer driver shipped in OSR2 and Windows 98 is designed to work explicitly with ESDI_506.PDR. Specifically, it will look for the DCB_DEV2_ATAPI_DEVICE flag in the DCB created for the CD-ROM drive. This flag is never set if the IDE controller is using a SCSI miniport instead of

ESDI_506.PDR. The ATAPI changer driver will also explicitly look for a SCSI miniport name of IDEATAPI.MPD if the DCB_DEV2_ATAPI_DEVICE flag is not set. If neither of these conditions are met, the ATAPI changer driver will not be loaded.

Given this, you have a few options to support ATAPI changers:

  • You can write a small VSD that sets the DCB_DEV2_ATAPI_DEVICE for ATAPIdevices controlled by your SCSI miniport.
  • You can use the name "IDEATAPI.MPD" as your miniport name.
  • You can implement all the changer functionality in your SCSI miniport. This would involve returning INQUIRY data for each platter on the ATAPI changer (LUN0, LUN1, and so on). You would need to manage changing platters, and so on, in the miniport driver itself.


Recommended MaximumTransferLength

If an IOS request's block size is greater than the SCSI miniport driver's MaximumTransferLength, IOS will "double buffer" to accommodate your limits ("IOSSERV: request too big, so double buffering"). This is normal. However, when it double buffers, it breaks the requests down into 4K pieces, which results in some performance degradation. If you set MaximumTransferLength to 64K or larger, and a request is bigger than that, IOS will attempt to break the request into 64K chunks (instead of 4K). So for performance reasons you should consider using a 64K (or larger) maximum transfer length.

A small maximum transfer size causes IOS to massively double-buffer I/O requests. Under rare circumstances this can lead to an attempt to reenter VMM's memory manager, which causes a deadlock. The recommended corrective action is to set MaximumTransferLength to 64K or larger.

The function that determines whether to double buffer is ILB_int_io_criteria_rtn (the latest information is found in the Windows 98 DDK documentation) This routine is called in SCSIPORT just prior to SCSIPORT calling the IOS_Send_Command function. ILB_int_io_criteria_rtn returns with error if any of the various required criteria fail. It returns an error if any of the following are true:

  • The original request length is greater than the maximum transfer length supported by your miniport driver's DCB_max_xfer_len (which is ConfigInfo->MaximumTransferLength).
  • The buffer address OR buffer length fails address alignment criteria.
  • IOS is unable to generate physical SGDs (if so requested) given the setting for the maximum number of physical breaks.

SCSIPORT performs the above criteria call on behalf of your miniport driver. If SCSIPORT sees that the criteria routine fails, its sets the following flag: IORF_DOUBLE_BUFFER. SCSIPORT then calls IOS_Send_Command. This flag is looked at and eventually cleared in IOS_Send_Command. If it is set, IOS_Send_Command will double buffer the call (break the buffer into smaller pieces and ensure that they are properly aligned). This can happen even if the transfer length is short, in the case of alignment criteria failure.


Developing a Multifunction INF file

An adapter card that contains multiple bus controllers requires a Multifunction INF file. For more information, see Knowledge Base article Q242348 - "SAMPLE Ideinf.exe: Architecture of the .inf File for Windows 9x Dual IDE Controllers."


The Extended IOP Structure

The following table illustrates the structure of a typical "extended IOP" used when performing SCSI operations. Drivers that talk directly to SCSI devices (SCSI Passthrough) need to create this structure. The ordering of certain items within the extended IOP, such as the SGD list and the sense information, may vary. For example, CDVSD locates the PORT_SRB, SRB extension and sense information into the DCB expansion area—not at the end of the IOP packet as shown below.

IOP contents | Component size | Comments
DCB expansion area | DCB_expansion_length |
IOP/IOR | Size IOP | The combined IOP+IOR structure.
Physical SGD list | DCB_max_sg_elements * 8 | IOR_sgd_lin_phys points to this list. Required when target hardware requires physical addresses (such as a bus mastering device).
PORT_SRB | size PORT_SRB | Contains base SRB plus miniport SRB extension.
SRB extension | DCB_srb_ext_size | Contains Adapter port extension (APEXT) plus per-miniport-adapter memory area (miniport-requested per-request state information).
Sense information buffer | VSD_REQ_SENSE_SIZE | Set the SRB's .SenseInfoBufferLength to this size.


Additional Differences in SCSI Between Windows 95 and Windows NT 4.0

First refer to the Knowledge Base articles dealing with implementation differences between Windows 95 and Windows NT 4.0. Some of these articles are listed at the end of this section.

Plug and Play

The only major difference between the two is support for Plug and Play under Windows 95. In Windows 95 the PORT_CONFIGURATION_INFO structure will already be populated with the system resources (I/O and memory ranges, DMA channel, and so on) assigned to the controller. In this case the miniport is expected to not "sniff" for the controller.

You might consider setting flags in your code to accomplish conditional compilation (to accommodate both Windows NT and Windows 95).

Using the ATAPI Miniport Driver Sample Located in the Windows NT 4.0 DDK

A common issue deals with the Windows 95 IDE/ATAPI port driver (ESDI_506.PDR). Microsoft does not supply the source code of ESDI_506.PDR. However, Microsoft DOES supply the source code for an ATAPI miniport driver in the Windows NT DDK. This driver may be used to replace the functionality of ESDI_506. Windows NT miniport drivers are generally binary compatible with Windows 95 (there are minor differences, for example, Windows NT supports miniport I/O control commands that are not supported by Windows 95).

SCSI miniport driver devices support dynamic re-enumeration (hot-swapping), while the ESDI_506.PDR driver does not. To accommodate "hot" device removal and reinstallation, you can modify the miniport driver to detect the addition and removal of the hardware and call CM_Reenumerate_Devnode() to force the system to re-enumerate the bus (which detects both removal and arrival of devices). Part of the IOS SCSI reenumeration process is to issue device inquiries to identify new device(s) and obtain the SCSI device's hardware ID. The INF files are scanned to find a hardware ID match. If a match is found, the "new hardware" popup menu is avoided, and the process automatically completes.

Here is the general process for setting up the Windows NT ATAPI miniport sample into Windows 95:

  1. Inspect the file named scsi.inf located in the <windows directory>\inf\ path (or do a grep for "mpd" in the inf\ path). There are two different types of entries, for example:

    CopyFiles=@ncr53C9x.mpd

    HKR,,PortDriver,,ncr53C9x.mpd

    The first item causes the miniport driver (.mpd) to be copied to the \system\iosubsys\ path. The second item adds the name of the miniport driver to your entry in the registry. You need to amend scsi.inf to contain your new atapi.mpd, or create your own INF file.

  2. You can test your miniport driver by manually copying it to the \iosubsys\ path (renaming your binary file atapi.sys to atapi.mpd), and going into the registry to rename ESDI_506.PDR to the name of your miniport driver (atapi.mpd).
  3. For Windows 95, you do not need any other Windows NT files. Windows 95 uses its own port driver, SCSIPORT.PDR to interface your miniport driver.


Miscellaneous Questions and Answers

Q: While executing code in the HwInterrupt() function of my miniport, if I do something that causes another h/w interrupt, will the O/S call my HwInterrupt() function again?

A: VPICD will actually mask off the interrupt at the PIC before it calls the installed interrupt handler (SCSIPORT.PDR, in this case). This means that your HwInterrupt() procedure will not be re-entered if it causes an interrupt to occur. To be safe, make the assumption that HwInterrupt() will be called again after you return from HwInterrupt(). This would occur after SCSIPORT.PDR has physically unmasked the interrupt at the PIC because your device is still asserting an interrupt to the PIC and the PIC was EOI'd by VPICD before the original HwInterrupt() call.

It should also be noted that SCSIPORT.PDR executes an STI before calling HwInterrupt(), so other interrupts will continue to be serviced while HwInterrupt() is executing.

Q: How can I send a user-defined parameter string to the miniport?

A: This question is answered in Knowledge Base article: "Q140728 AdapterSettings Entry for SCSI Miniport under Windows 95."

As an example, the AddReg section for the NCRC810 (found in \windows\inf\scsi.inf) looks like this:

[NCRC810.reg]

HKR,,PortDriver,,ncrc810.mpd

If you wished to add an AdapterSettings string, you would simply do this:

[NCRC810.reg]

HKR,,PortDriver,,ncrc810.mpd

HKR,,AdapterSettings,,"This is the Adapter Settings string passed to HwFindAdapter"

This string would be added to the software branch of the registry for this device. To add the AdapterSettings string to the device's key in the hardware branch of the registry, specify a Hardware Section in your INF. This allows end users to modify the string via the 'Settings' property page for the device.

To add a Hardware Section, you simply add an ".HW" extension to the install section name used for your device. For example, the NCRC810's install section looks like this:

[NCRC810]

CopyFiles=@ncrc810.mpd

AddReg=IOS,NCRC810.reg

UpdateInis=DoubleBuffer

You create a separate hardware section in your INF file by adding an .HW extension to the name of your install section. You can then specify a AddReg section that adds the AdapterSettings subkey:

[NCRC810.HW]

AddReg=NCRC810.HW.reg

[NCRC810.reg]

HKR,,AdapterSettings,,"This is the Adapter Settings string passed to HwFindAdapter"

Q: My SCSI miniport supports Auto Request Sense. What SCSI status should be returned to SCSIPORT: the status of the original command that failed (check condition) or the status of the request sense that just happened (good status)? Currently, they are returning good status. Seems to work fine on Windows NT and Windows 95 for the most part. However, when using ASPI on Windows 95 we are seeing a good status returned to the application, but they think they should see a check condition.

A: Once the request sense has successfully completed, you should return an SrbStatus of SRB_STATUS_ERROR and SRB_STATUS_AUTOSENSE_VALID, and a ScsiStatus of SCSISTAT_CHECK_CONDITION.

Q: Can I assign a floppy disk drive letter to a SCSI Miniport driver?

A: Under Windows 95, a miniport driver, by itself, is not capable of assigning to drive A or B. A miniport drive can be assigned as "removable", but not as a "floppy disk".

The actual drive letter assignment is performed by the "Disk TSD" (DISKTSD.VXD) in the middle layer of the IOS hierarchy. Each time it receives the AEP_CONFIG_DCB message, it inspects the DCB. If it is a hard disk or floppy disk (which includes floptical), it inserts itself into the IOS calldown chain and assigns a drive letter using the IOS ISP_ASSOCIATE_DCB service.

This service inspects real-mode drivers; the real-mode drive letter assignment affects the assignment of drive letters in protected mode. DISKTSD also handles the situation where a single floppy disk drive appears as both drive A and drive B.

If the floppy disk device is an IDE LS120 (or any floptical type) driver used with Windows 95 version B (OSR2) or higher, note that DISKTSD checks the DCB field DCB_device_flags2 to detect this by inspecting the following bit: DCB_DEV2_IDE_FLOPTICAL_BIT. This bitmask flag is not defined in the original Windows 95 DDK; its value is 0x00000040. If it is set, it indicates the device is a floptical device. DISKTSD then issues an IOR_COMPUTE_GEOM to the device, in order to obtain the correct disk geometry information.

Miniport drivers communicate through the SCSI port port driver (SCSIPORT.PDR). Unfortunately, the miniport interface does not provide the miniport with information such as DCB_DEV2_IDE_FLOPTICAL_BIT and other such internals.

If you need to reassign drive letters and you want to keep using your miniport driver (instead of writing your own port driver), you could try writing a custom TSD (type-specific driver) that is installed into the layered hierarchy of IOS (like DISKTSD.VXD, but placed "below" DISKTSD, closer to port drivers).

The custom TSD could be used to change drive letter assignments. Perform similarly to DISKTSD (respond to AEP_CONFIG_DCB messages).

  • In general, use the ISP_GET_DCB service to locate devices. Supply the desired drive letter as input. Returns a pointer to the corresponding DCB.
  • If inspecting a floppy disk drive A, check its DCB to see if it is used as both Drive A and Drive B (check DCB_dmd_do_a_b_toggling). If it is set, clear it. This will allow you to use drive B.
  • Use the ISP_DISASSOC_DCB to "disassociate" the drive letter (for example drive B).
  • Locate the drive letter currently assigned to your drive (using ISP_GET_DCB).
  • Use the ISP_ASSOCIATE_DCB to assign your drive to drive B.
  • Use the ISP_DISASSOC_DCB to deassign the former drive letter of your drive (for example, drive D).

A sample driver is located at \DDK\Block\SAMPLES\VSD\HELPVSD\ in the Windows 95 DDK. A TSD is a VSD that has the special function in the IOS layered hierarchy of assigning drive letters (among other things). The sample's vsd_config_device() entry point is where DCB(s) need to be inspected and modified as required. The compiled TSD belongs in the \system\iosubsys\ directory (along with other IOS layer drivers).

The DDK contains documentation describing how to set up the compile environment. The easiest and quickest technique is to use the batch file DDKENV.BAT to establish your environment (DDKENV 32 BLOCK). Then change to the source code directory and run "nmake".

Q: How does Windows 95's ScsiPortGetPhysicalAddress work?

A: This SCSIPORT service is used to enable the miniport driver to obtain a physical address, given a data buffer's linear address.

Under Windows 95 (NOT Windows NT), the process is as follows

  1. If (Srb != NULL) && (VirtualAddress lies within the Srb's DataBuffer) scan the corresponding IOP's IOR_sgd_lin_phys field to obtain the desired SG element and physical offset within that element. The returned length is the number of bytes from the offset within the SG element, to the end of the SG element.

    (else)

  2. If (VirtualAddress lies within the IOP Memory Pool)
    The physical address is obtained by finding the offset within the memory pool and adding IDA_ios_mem_phys to the offset value. The returned Length is ALWAYS 4096.

    (else)

  3. _CopyPageTable(VirtualAddress/4096, 1, Pte, 0).
    PhysAddr = (Pte & 0xFFFFF000) + (VirtualAddress & 0xFFF).
    Pte is the Page Table Entry as described in the Pentium Processor Users Manual, Volume 3.
    The returned Length is ALWAYS 4096.

Based on the above information, one cannot always rely on the returned Length containing the correct length; it may be longer than the actual buffers.

In general, the returned length makes sense (within the physical SGD associated with VirtualAddress) if the SRB pointer supplied is good, and if the VirtualAddress is within range of the SRB's DataBuffer, taking into account DataTransferLength. Otherwise, the returned length field will contain a fixed 4096 byte value, which probably should not be used when performing total length calculations.

Q: How do I interpret the "problem number" that is listed in the Device Manager when a device is not working properly?

A: The problem number displayed is actually a configmg problem number, and can be found in CONFIGMG.H in the Windows 95 DDK (the CM_PROB_xxx error codes). Note that the Device Manager displays this number in decimal, while CONFIGMG.H #defines are listed in hexadecimal.


Additional SCSI Reference Material

The following reference material can be useful to SCSI Miniport developers:

  • Microsoft® Windows® 95 Device Driver Kit (supplied to MSDN® subscribers)
  • Microsoft® Windows NT® 4 Device Driver Kit (supplied to MSDN subscribers). Contains SCSI miniport information relevant to Windows 95 SCSI miniport development as well.
  • Systems Programming for Windows 95, by Walter Oney (Microsoft® Press).
    See his Web site for errata: http://www.oneysoft.com.
  • The SCSI Bus and IDE Interface, by Friedhelm Schmidt (Addison-Wesley) ISBN 0-201-42284-0.
  • Microsoft support web site:
    http://support.microsoft.com/support
  • For Windows 95 DDK samples and tools:
    http://support.microsoft.com/support/ddk

Here is a list of assorted Knowledge Base Articles for Windows 95 SCSI Miniports:

  • Q116450 "BufferAccessScsiPortControlled Flag Information"
  • Q140728 "AdapterSettings Entry for SCSI Miniport under Windows 95"
  • Q140730 "Accessing PCI Device's Configuration Space from Device Driver"
  • Q140732 "PRB: Windows 95 Doesn't Load SCSI Miniport Driver"
  • Q160667 "Miniport Driver Fails Using Certain ScsiPort APIs"
  • Q163358 "PRB: DDKDEBUG.BAT Copies Some Drivers to the Wrong Directory"
  • Q169584 "BUG: Win95: ScsiPortGetDeviceBase Does Not Return Linear Address"
  • Q242348 "SAMPLE Ideinf.exe: Architecture of the .INF File for Windows 9x Dual IDE Controllers"

Here is a list of assorted Knowledge Base Articles for Windows NT SCSI Miniports:

  • Q113706 "How to Pass Parameters to a SCSI Miniport via the Registry"
  • Q126369 "FIX: Large Transfers Via SCSI Passthrough May Crash System"
  • Q137247 "IOCTL_SCSI_MINIPORT and IOCTL_SCSI_PASS_THROUGH Limitations"
  • Q140269 "PRB: SCSI Miniport Adapter-Specific Parameter May Be Incorrect"
  • Q140610 "BUG: SCSI Miniport Parms Not Parsed on Multi PCI Bus Systems"
  • Q140268 "SCSI Miniport's Use of the SRB DataBuffer"


IOS Port Driver Topics

This section addresses common questions that arise when developing an IOS port driver.

An IOS port driver is not to be confused with a SCSI Miniport driver; the SCSIPORT.PDR IOS Port driver serves as the host to accommodate SCSI miniport drivers.


IOS Port Driver general theory of operation

A skeleton port driver code sample is located in the Windows 95 DDK at \DDK\Block\SAMPLES\PORT. Also, refer to the following book, which includes a CD-ROM containing a sample RAMDISK IOS Port Driver:

Title | Author / (Publisher) | ISBN | Comments
Systems Programming for Windows 95 | Walter Oney (Microsoft Press). | 1-55615-949-8 | See his Web site for book errata and DDK annotations: http://www.oneysoft.com

Here is the general process that should occur when an IOS port driver receives a new IOP. Note that it is assumed that the port driver is connected to a piece of hardware.

  1. The port driver checks to see if the hardware is already busy performing I/O. If it is not, go to step 2 below. If it is (busy), it enqueues the new IOP using ILB_enqueue_iop. This function is used to serialize I/O requests for your port driver. After the enqueue, the driver does a simple return (no IOS IOP_callback_ptr callback).

    Microsoft's ESDI_506.PDR source code uses the CLI instruction before the ILB_enqueue_iop:

    cli ; avoid race
    push esi ; *DCB
    push ebx ; *IOP
    call [esdi_ilb].ILB_enqueue_iop ; queue the request.
    add esp, 4+4
    STI is used afterwards. This is a precautionary measure to prevent re-entrant thread problems.

  2. At this step, the hardware is not already busy, so the driver starts I/O for the device. Normally at this step, the port driver is going to have to wait for hardware to respond. If the hardware polling method is used (instead of waking up when an interrupt arrives), the driver then calls Set_Global_Time_Out or Set_Async_Time_Out so that the driver's timeout (polling handler) routine gets called back later, for example in 10 milliseconds. Immediately after this Set_Global_Time_Out call, simply return (WITHOUT doing a JMP to the IOP_callback_ptr routine). This releases the system from your driver, so the system can run normally for a while.
  3. After a time (for example 10 milliseconds), your polling handler gets called when the global timer times out. Your handler checks your hardware's status. If the hardware has not completed, re-issue a global timeout so the hardware can be checked again (10ms) later. If the hardware has completed, finish the I/O, and CALL (not JMP to) the IOP_callback_ptr routine. This procedure has the effect of handing the IOP back to IOS in order to truly complete the request. Next, call ILB_dequeue_iop to see if there are any queued IOP's. If there are, take the new IOP, and jump to step 2 above, to start a new I/O. If there are no enqueued requests, do a simple return.

If hardware has an associated hardware interrupt, the procedure is more efficient because the driver does not have to poll the hardware.

The sample port driver in the Windows 95 DDK (\DDK\Block\SAMPLES\PORT) demonstrates enqueueing and dequeueing of IOPs.


IOP Serialization

When set, the bit DCB_DEV_SERIAL_CMD in dcb_device_flags instructs IOS to add a special entry into the calldown stack for the DCB (after the port driver gets its AEP_CONFIG_DCB call). The call is to a routine named IOS_serialize. This is used internally only, to support real-mode devices and blockdev (Win 3.1 Fastdisk (32-bit ring 0 ) drivers).

The source code for IOS_serialize (below) is enlightening, since it demonstrates the use of queueing and dequeueing. Your port driver should do its own enqueueing using ILB_enqueue_iop, and so on. Study the code below to help understand IOP queuing mechanics. Note that if you write a VSD (Vendor Supplied Device) that resides in the IOS layered hierarchy between IOS and the port driver, and if your VSD must enqueue IOPs, you cannot use ILB_enqueue_iop. ILB_enqueue_iop is reserved for use by port drivers. Instead, your VSD will need to implement a private queuing mechanism.

You may have noticed the DCB_dmd_serialize flag in the header file DCB.H. This flag is never used.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;  IOS_serialize
;       Routine serializes all I/O to a physical device
;       INPUT:  *IOP on stack
;       OUTPUT: none
;       USES:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

BeginProc       IOS_serialize, esp
ArgVar  IOPPtr, DWORD

        EnterProc
        SaveReg <edi>

        mov     eax, IOPPtr
        AssertIOP <eax>
        mov     edi, [eax].IOP_physical_dcb

        ;
        ; insert in callback stack
        ;

        mov     edx, [eax.IOP_callback_ptr]                    ; set CB
        mov     [edx.IOP_cb_address],offset32 IOS_serialize_callback
        add     [eax.IOP_callback_ptr],size IOP_callBack_entry ; move down

        AssertDCB <edi>

        ;
        ; enqueue the IOP
        ;

        push    edi
        push    eax
        call    IOS_enqueue_iop
        add     esp, 8

        call    IOS_bd_send_next_command

IOS_s_exit:
        RestoreReg <edi>

        LeaveProc
        Return

EndProc IOS_serialize

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;  IOS_serialize_callback
;       Completion routine for request serialization
;       INPUT:  *IOP on stack
;       OUTPUT: none
;       USES:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

BeginProc       IOS_serialize_callback, esp

ArgVar  CBIOPPtr, DWORD

        EnterProc

        SaveReg <esi, edi>
        mov     esi, CBIOPPtr
        AssertIOP <esi>

        mov     edi, [esi].IOP_physical_dcb
        AssertDCB <edi>

        mov     ecx, [esi].IOP_callback_ptr    ; get our callback ptr
        sub     ecx, size IOP_CallBack_Entry   ; point to next available
                                               ; callback entry
        mov     [esi].IOP_callback_ptr, ecx    ; update CallBack Pointer

        ;IOP pointer is passed on the stack

        push    esi                            ; IOP's offset
        call    [ecx].IOP_cb_address           ; make the call
        add     esp, 4                         ; restore stack

        AssertDCB <edi>

        ;
        ; dequeue the next request
        ;

        ASSERT_INTS_ENABLED
        cli
        cmp     [edi].DCB_BDD.DCB_BDP_Current_Command, 0
        je      IOS_sc_send_next

       cmp     esi, [edi].DCB_BDD.DCB_BDP_Current_Command  ; Is this the
current cmd?
        jne     ios_sc_exit

        mov     [edi].DCB_BDD.DCB_BDP_Current_Command, 0    ; No current
command!

IOS_sc_send_next:
        call    IOS_bd_send_next_command

IOS_sc_exit:
        sti
        RestoreReg <edi, esi>
        LeaveProc
        Return

EndProc IOS_serialize_callback

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;       Starts the next request for a device
;       ENTRY   edi => DCB
;               ints disabled
;       EXIT    ints enabled
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
BeginProc       IOS_bd_send_next_command

        AssertDCB<edi>
        cmp     [edi].DCB_BDD.DCB_BDP_Current_Command, 0
        jne     short ios_snc_exit

        push    edi
        call    IOS_dequeue_iop
        add     esp, 4

        or      eax, eax
        jz      IOS_snc_exit

        AssertIOP <eax>
        mov     [edi].DCB_BDD.DCB_BDP_Current_Command, eax

        sti
        SaveReg <esi, edi, ebx>

        lea     edi, [edi].DCB_BDD              ; (edi) = BDD
        mov     ecx, [eax].IOP_calldown_ptr     ; call down the request
        mov     ecx, [ecx].DCB_cd_next          ; get next entry
        mov     [eax].IOP_calldown_ptr, ecx     ; store in IOP

        push    eax                             ; place IOP pointer on stack
        call    [ecx].DCB_CD_IO_Address         ;
        add      esp, 4                         ; call next layer down

        RestoreReg <ebx, edi, esi>

IOS_snc_exit:
        sti
        ret

EndProc IOS_bd_send_next_command


What are the rules for making an R0 read/write call from an IOS port driver?

Conventional IFSMGR_Ring0_FileIO typically will not work when called from within an IOS port driver if attempting to open and use a file located on a local (FAT) drive. This is because of the blocking that can occur in VFAT. VFAT uses IFSMGR_Block to serialize the use of FAT data structures (and to prevent VFAT data structure corruption due to re-entrance). Also, there is a flag in VFAT called FullHold, which keeps track of the count of threads in VFAT and establishes a "full critical section" that is VFAT-global (not specific to a single drive letter). Attempts to perform IFSMGR_Ring0_FileIO fail (block) when called from a port driver because the original port request went through VFAT; the subsequent Ring0 file call is blocked by FullHold. However, success has been reported by developers outside of Microsoft in cases where the file is opened as a memory-mapped file under Windows 95 through Windows 98. With memory-mapped files, IFS Manager performs fewer tests for sharing violations. Therefore, you should set up a private memory-mapped file so it is not opened by any program other than yours. Also, all your I/O requests should be page (4K) aligned.

The following code, extracted from VWIN32, is used to read a memory-mapped file on behalf of Kernel32:

    mov    eax,R0_READFILE or (R0_MM_READ_WRITE shl 16) ; (eax) = read/write
    mov    al,byte ptr [function]        ; (al) = read (3f) or write(40)
    sub    al,3fh                ; (al) = read (0) or write (1)
    xor    ecx,ecx
    mov    edx,[fileloc]            ; (edx) = seek position
    mov    ecx,[cbLen]            ; (ecx) = number of bytes in i/o
    mov    esi,[memloc]            ; (esi) = transfer address
    VxDCall IFSMgr_Ring0_FileIO        ; do the i/o
    Trace_OutC    "ReadWritePage: error #EAX from file i/o"

Note that the R0_MM_READ_WRITE flag must be set for every I/O operation, not just when an attempt is made to open a file.

The following describes how PAGEFILE VXD opens the swap file (after it has been determined that the swap file can be safely accessed by 32-bit protected-mode drivers):

;    Open or Create the file

    mov    eax,R0_OPENCREATFILE            ; (eax) = open function code
    mov    bx,0110000010010010b            ; (bx) = flags: r/w, deny all,
                            ;    no inherit, no int 24,
                            ;    no caching
    xor    ecx,ecx                 ; (ecx) = attributes (nothing)
    mov    dl,00010001b                ; (dl) = open mode, open or create
    mov    dh,((R0_SWAPPER_CALL or R0_NO_CACHE or OPEN_FLAGS_NO_COMPRESS) SHR 8)
                            ; (dh) = special flags
    mov    esi, offset32 PF_Our_File_Name    ; (esi) = file name
    VxDCall IFSMgr_Ring0_FileIO            ; do the open  (eax) = handle
    jc    osf110                    ; jump if error

    mov    [PF_File_Handle],eax            ; save file handle

The original Windows 95 DDK did not mention that the flag bits need to be shifted right 8 positions. This shift is shown above. Read and write operations of the swap file are performed using normal R0_READFILE and R0_WRITEFILE functions, with no special flags set.

Here is a reportedly successful implementation of an IOS port driver that uses the above R0_MM_READ_WRITE Ring0_FileIo to access a local FAT file:

  1. Open the file with the following flags: R0_OpenFile(R0_NO_CACHE | R0_MM_READ_WRITE)
  2. CreateSemaphore()
  3. VWIN32_CreateRing0Thread()
  4. Set_Thread_Win32_Pri(16) - other values may work
  5. Set a worker thread running:

    Thread()
    while not stop
    Wait_Semaphore(BLOCK_THREAD_IDLE)
    Dequeue IOP
    Do R0 file I/O
    Do CallBack
    endwhile

  6. The IOP Handler:

    IOHandler(IOP)
    if read or write
    Enqueue IOP
    Signal_Semaphore()
    return
    endif

Also, the developer reported the need to do periodic forced volume flushes to the memory mapped file (virtual drive) when a long file is being copied to it. This is done using IFSMGR_InstallFileSystemApiHook. After write operations to the virtual volume, a data byte counter is incremented and direct calls to volume's flush function through its function table occur if the counter = 1Mb. Without this, the reading of the file from system volume slows down and would ultimately result in being locked up in Ring0_FileIo.

When R0_NO_CACHE is used, the system does not do any buffering during I/O. For example, the buffer address goes directly to the ESDI port driver.

How does Windows 95/98 itself use IFSMGR_Ring0_FileIo?

The following is an abbreviated analysis of how Windows 98's DriveSpace (DRVSPACX) accesses its host Compressed Volume Files (CVF's) located on the physical host volume.

  • DRVSPACX only uses the IFSMGR_Ring0_FileIo call when it is handling the AEP_MOUNT_NOTIFY event, in order to find and read the beginning part of all the CVF's (Compressed Volume Files) on a CVF host drive. This event is generated by IOS when IRS_MOUNT_NOTIFY is called. When performing these actions, there does not appear to be any special blocking or serialization going on.
  • Whenever DRVSPACX does use IFSMGR_Ring0_FileIO to read a CVF (see above), it uses the R0_READFILE_IN_CONTEXT flag.
  • For normal compressed volume file I/O, DRVSPACX sets up an IOP and performs direct sector I/O. DRVSPACX apparently automatically accounts for any fragmentation that the file may have on the disk, and has information about the starting sector for each CVF file.

A global search for IFSMGR_Ring0_FileIO across the Windows 98 source tree reveals the following:

  • DYNAPAGE.VXD still uses it. It appears to be used when creating, auditing, or resizing the swap file.
  • IOS uses IFSMGR_Ring0_FileIO during initialization when loading VxDs from the \system\iosubsys directory.

Q183173 BUG: IFSMGR_Ring0FileIO / Level 3 Volume Lock Conflict

There is a bug in IFS that affects VxDs that use IFSMGR_Ring0_FileIo. The corresponding Knowledge Base article (Q183173) is reproduced below. Use the online Knowledge Base to check for later potential updates to this article.

The article, "BUG: IFSMGR_Ring0FileIO / Level 3 Volume Lock Conflict" [win95ddk] can be accessed at this location:

http://support.microsoft.com/support/kb/articles/Q183/1/73.asp

[Q183173] "BUG: IFSMGR_Ring0FileIO / Level 3 Volume Lock Conflict"

[win95ddk]

The information in this article applies to the Windows 95 Device Driver Kit (DDK), version 4.0.

Symptoms

If you are using IFSMGR_Ring0FileIO services, you might encounter file access problems when you run utility programs, such as DEFRAG, while IFSMGR_Ring0FileIO files are open. For example, a file opened as ACCESS_READ_WRITE does not work after you run DEFRAG. After you run DEFRAG, the file attributes erroneously change to ACCESS_WRITEONLY.

Cause

There is a bug in IFSMGR_Ring0FileIO that becomes apparent only when a level three volume lock is released and, as a result, the volume release automatically causes the ring 0 file to be re-opened. When the file is re-opened, the file access mode is erroneously set up with the contents of the file action type. For example, a file opened as follows:

  mov     esi, OFFSET32 R0_szFileName
  mov     ebx, ACCESS_READWRITE    ; 0x0002
  xor     ecx, ecx
  mov     edx, ACTION_OPENEXISTING ; 0x0001
  mov     eax, R0_OPENCREATFILE
  VxDCall IFSMgr_Ring0_FileIO

is re-opened with the contents of EDX appearing in EBX. When appearing in EBX, the value ACTION_OPENEXISTING (0x0001) corresponds to ACCESS_WRITEONLY (0x0001).

Resolution

When the level 3 volume lock is released, it re-opens the temporarily-closed files using FS_OPEN calls down to the target FSD (typically VFAT). You can hook IFS using IFSMgr_InstallFileSystemApiHook to correct "reopen" FS_OPENs on the fly before the FSD detects it. To see if a given FS_OPEN is actually a reopen due to a level 3 volume lock release, check for (ir_options & OPEN_FLAGS_REOPEN). In the Windows 95 Device Driver Kit, see header file IFS.h for flag details. When you find one of these, you can further test for ir_pid = -1, which corresponds to a file opened using the ring 0 functions. Change ir_flags to the correct file access method. For example, if ir_flags erroneously contains ACCESS_WRITEONLY, change it to ACCESS_READWRITE. Then let the file system I/O proceed normally to complete the (corrected) file open.

Status

Microsoft has confirmed this to be a bug in the Microsoft products listed at the beginning of this article. We are researching this bug and will post new information here in the Microsoft Knowledge Base as it becomes available.

References

Windows 95 Device Driver Kit


Debugging tools

Debug binaries

The following debug binaries (and their corresponding symbol files) are particularly useful when debugging SCSI miniport drivers:

CDTSD.VXD, CDVSD.VXD, DISKTSD.VXD, DISKVSD.VXD, SCSIPORT.PDR (each placed into the \system\iosubsys folder) and

IOS.VXD, VXDLDR.VXD (placed into the \system\vmm32 folder).

The original debug binaries in the original Windows 95 DDK are intended for the use with the original (Golden) version of Windows 95. If debugging Windows 95 version b (OSR2), obtain the OSR2 debug binaries, located at the following Microsoft Web site: http://support.microsoft.com/support/ddk

Debug binaries and symbol files for Windows 98 are available at http://www.microsoft.com/ddk.


IOS dot commands

As with any technology area, install only those debug binaries that interact with your device driver, and only those debug binaries that offer dot commands (see below), so that you are not confused by frequently useless messages sent to the debug console.

The debug version of IOS.VXD (when installed into the \system\iosubsys folder) offers the following dot commands:

Command | Parameter(s) | Debug binaries that must be installed | Comments
.I? |  | IOS.VXD | Help menu for IOS commands.
.IDCB | <addr> | IOS.VXD | Dumps I/O Supervisor Device Control Block structure.
.IIOP | <addr> | IOS.VXD | Dumps I/O Supervisor I/O Packet structure.
.IMED |  | IOS.VXD | Dumps I/O Supervisor Memory Element Descriptor structures. Use this command to get addresses of active IOPs.
.IDV |  | DISKVSD.VXD and IOS.VXD | Display disk calldown/callup statistics.
.IDCBL |  | IOS.VXD | (Windows 98) Dumps the list of DCBs.
.IDVTL |  | IOS.VXD | (Windows 98) Dumps the list of DVTs.
.IDIDA |  | IOS.VXD | (Windows Me) Dumps the IDA and IOS static globals.
.IDDVT | <addr> | IOS.VXD | (Windows Me) Dumps DVT/DDB structures. Dumps everything, if no address specified.
.IDDCB | <addr> | IOS.VXD | (Windows Me) Similar to .IDCB but more comprehensive. Dumps all DCBs if no address specified.
.IDUMP |  | IOS.VXD | (Windows Me) Structured dump of IDA, DVTs, DDBs, and DCBs.

These commands work when using WDEB386, WDEB98, or SoftIce kernel-mode debuggers.

In order to extract the most information from many of these commands, install the symbol files for the various IOS components of interest, so the commands will report symbolic addresses instead of (less useful) module name/offset addresses.

For more information about dot commands, review the WDEB386 debugger documentation, contained in the DDK. For printable (Word) documentation, see utils.doc in versions of the DDK CD-ROM prior to Windows 98, also available in Knowledge Base article Q181302.


Additional debugging techniques

The following techniques may be useful when developing an IOS component:

  • If you are having problems with your miniport being loaded, or to check for import problems (for example, see Knowledge Base article Q160667, "Miniport Driver Fails Using Certain ScsiPort APIs"), you can copy the debug binary file VXDLDR.VXD into the \system\vmm32\ path, and restart the debugger. Errors will appear in the debug monitor window.
  • You can start up Windows 95 in "Logged" mode (touch the F8 key just as Windows 95 starts, then select "Logged" mode from the Startup Menu). After the system has booted up, inspect \BOOTLOG.TXT to confirm that your miniport and associated VxDs are getting loaded.
  • Using the debugger, set a breakpoint at the miniport's DriverEntry to confirm that the driver is getting the initial Inquiry command.
  • When an IOS device driver fails to load, information about that failure can frequently be found in a file named IOS.LOG. If this file exists on your system, check its contents.
  • The file IOS.INI contains two sections; the "safe" driver list ([SafeList]) and the "CD-ROM unsafe" driver list ([CDUnsafe]). The [SafeList] section contains a list of real-mode drivers that can safely be bypassed by their 32-bit protected-mode counterparts. The [CDUnsafe] section contains a list of real-mode CD-ROM drivers that cannot be safely bypassed by their 32-bit protected-mode counterparts. If the real-mode driver is not listed in [SafeList] then your protected-mode SCSI miniport driver will not run.

    See also Knowledge Base Article Q130179, "Troubleshooting MS-DOS Compatibility Mode on Hard Disks."

  • Use the Multimon utility located in Stan Mitchell's book, Inside the Windows 95 File System, as a probing and diagnostic tool to observe IFSMGR traffic, as well as INT21 and other traffic.
  • If using IFSMGR_Ring0FileIO, use GetVxDServiceOrdinal / VMMCall Hook_Device_Service to monitor the users of IFSMGR_Ring0FileIO. The DDK has documentation and samples that show how to hook a VxD's service. This can help you determine if your problems are caused by multiple users of this service.
  • Install the DEBUGCMD driver in order to use the .p? commands. These commands allow you to view threads, and so on. This is helpful when debugging blocking. Use of this VxD is further discussed in the latest version of our WDEB386 documentation, found in the Windows 98 DDK documentation, or as a Word document, available through Knowledge Base article Q181302. DEBUGCMD also works with the Soft-Ice kernel-mode debugger.
  • You can use DebugPrint statements inside Windows 95 miniport drivers. Viewing DebugPrint messages from a SCSI miniport under Windows 95 requires the installation of the debug version of VMM.VXD, IOS.VXD, and SCSIPORT.PDR. Once you have installed the debug DDK components, you should see your DebugPrint statements when you run a Windows system debugger (either WDEB386, or SoftIce/W).


Glossary

The following table lists common acronyms used in IOS. The page number column references Walter Oney's book, Systems Programming for Windows 95.

Acronym | Expanded | Page number | Description
AEP | Asynchronous Event Packet | 546 | This is the parent of a family of structures, used to pass data from the IOS to asynchronous callback procedures within VxDs.
BCB | BlockDev Command Block | 509 | Windows 3.1 Block Device Clients – structure describing the command issued to the Windows 3.1 driver (Windows 95 IOS is being called by an IOS client).
BDD | BlockDev Device Descriptor | 509 | Windows 3.1 Block Device Clients – structure describing the Windows 3.1 driver (Windows 95 IOS is being called by an IOS client). Appended to the DCB structure.
CDB | Command Descriptor Block | 530 | A field used to control SCSI (II) devices. Typically 6 or 10 bytes long.
DCB | Device Control Block | 527 | Major structure for a physical or logical block device. Major types are physical or (logical and physical), with optional INT13 and CD-ROM structure extensions.
DDB* | Device Data Block | 522-25, 533, 555 | Physical information about hardware. Describes an adapter that has one or more attached devices, each of which has a physical DCB.
DDB* | Device Description Block | 42,115, 116, 118-119 | The one and only symbol exported from the executable file that contains a VxD.
DRP | Driver Registration Packet | 528 | Used when initially loading (registering) a .VxD that is specifically used as an IOS driver.
DVT | Driver Vector Table | 516 | To manage the device drivers, the IOS creates a chain of DVT structures that contain information about the device driver, such as its file name and the address of its asynchronous event routine. The IOS adds a new DVT structure whenever a new driver or client first registers with the IOS. The IOS places the address of the DVT structure for a driver in the ILB structure, however, drivers should avoid modifying the DVT.
FSD | File System Driver | 508, 512 | Located above the IOS, below the IFS Manager. Example is VFAT.
ILB | IOS Linkage Block | 519, 522 | Contains pointers to entry points within IOS, used by port drivers and value-added drivers to gain access to IOS services. Is used when initially loading a .VxD that is specifically used as an IOS driver. DRP points to the ILB. Contains pointers your driver can use to call selected IOS exports.
IOP | IO Request Packet | 535 | Created and destroyed by IOS clients (internal and/or external); used as a parameter-passing mechanism to and from IOS.
IOR | IO Request Descriptor | 535 | Embedded in IOP. Created by an IOS client for use as an IOS parameter-passing mechanism.
IOS | Input Output Supervisor (or Subsystem) | 505 (Ch. 15) | The static VxD that contains all IOS services.
IRS | IOS Requestor Service | 516 | A group of services that the IOS provides its clients.
ISP | IOS Service Packet | 522 | Used by an IOS driver as a parameter passing mechanism to the IOS's services.
SGD | Scatter/gather Descriptor | 530 | There are two different structures associated with this acronym; physical SGDs and linear (virtual) SGDs.
SRB | SCSI Request Block | 530 | A structure used to issue commands to SCSI (II) devices. Used to communicate with SCSI miniport drivers.
TSD | Type-Specific Driver | 512-513, 529, 601 | A driver with overall responsibility for a specific class of device, such as disk drives (DISKTSD.VXD) and CD-ROM drives (CDTSD.VXD). Used to assign logical drive letters to disk partitions.
VRP | Volume Request Parameters Block | 543 | Describes the volume mounted on a particular device.
VSD | Vendor-Supplied Driver | 567 | Drivers in the calldown stack, generally used for SCSI. Sees the AEP_CONFIG_DCB event for every DCB in the system (a port driver only sees the event for devices it created).

The acronym DDB has two definitions, Device Data Block (within IOS), and Device Description Block (applicable to all VxDs).


Appendices

The following topics describe additional reference material related to IOS.


Additional resource materials

Two very useful online Word documents are contained in Knowledge Base article Q243343, "The Essential Guide to the Windows DDK." See:

  • The Essential Guide to the Windows DDK (ddkguide.doc)
  • The Essential Windows 9x DDK Resource Database (resource.doc)

The second document includes many pointers to storage technology information. Knowledge Base articles are available at http://support.microsoft.com/support, http://msdn.microsoft.com, or from within the MSDN Library CD set.

The following books are particularly useful for storage technology developers.

Title | Author | Comments
Systems Programming for Windows 95 | Walter Oney (Microsoft Press). 1-55615-949-8 | See Walter Oney's Web site for book errata and DDK annotations: http://www.oneysoft.com
Inside the Windows 95 File System | Stan Mitchell (O'Reilly & Associates) 1-56592-200-X | See http://www.sourcequest.com/win95ifs. This Web site includes a great tool for observing all sorts of internals (including IFS hook), called MultiMon. Also includes IFS sample code.
The SCSI Bus and IDE Interface | Friedhelm Schmidt (Addison-Wesley) 0-201-42284-0 | SCSI and IDE hardware.
PC Intern | Michael Tischer, Bruno Jennrich (Abacus) 1-55755-304-1 | The Encyclopedia of System Programming (heavy focus on hardware).
The Book of SCSI | Peter M. Ridge (No Starch Press) 1-886411-02-6 | SCSI hardware, software, ASPI.
The Indispensable PC Hardware Book | Hans-Peter Messmer (Addison-Wesley) 0-201-62424-9 | Detailed hardware information including hardware register I/O.

The following Knowledge Base articles reference documents located in Microsoft's Software Library.

Title | Comments
Q192603, "FILE: DskDrive.exe – Removing/Adding Disk Drives Under Win95/98" | DskDrive.exe is a file that contains Disk_Drives.doc. The Windows 95 I/O Supervisor (IOS) contains internal mechanisms for managing the removal and addition of disk drive letters and entire physical devices.
Q192604, "FILE: HotSwap.exe - Hot Swapping IDE or ATAPI CD-ROM Devices" | HotSwap.exe is a file that contains Hot_Swapping.doc. This document discusses the options available to device driver developers who wish to configure an IDE hard disk drive or ATAPI CD-ROM drive to be inserted and removed ("hot swapped") after Windows 95 has started up.
Q192606, "FILE: MBtFAQ.exe - Windows 95 or Windows 98 Master Boot Record" | MBtFAQ.exe is a file that contains Mstr_Boot_Rec_FAQ.doc. This document discusses how to develop device drivers that access Windows 95 or Windows 98 disk drives at the Master Boot Record, disk partition and head/cylinder/sector levels. For developers of disk encryption products and disk partitioning products.


IOS internal data structure detail

The following block diagram describes the relationship between the various internal IOS data structures. The rest of this section contains detail information for each field within the structures.

IOS Data Structures


IDA (IOS Data Area)

Use .IDIDA from debugger for list (using the debug version of IOS.VXD)

Offset
Element
 Comments
08 | ULONG IDA_ios_mem_phys | Physical address of IOS memory pool
10 | ULONG IDA_ios_timer | Counter - ticks every 250 milliseconds
20 | CHAR IDA_esdi_p_in_use | Non-zero = ESDI_506 has claimed the primary esdi i/o addresses (1f0 thru 1f7, 3f6 and 3f7) and irq (irq 14).
21 | CHAR IDA_esdi_s_in_use | Non-zero = ESDI_506 has claimed the secondary esdi I/O addresses(170 through 177, 376 and 377) and IRQ (IRQ 15).
22 | CHAR IDA_Num_Floppies | Number of floppies in the system as determined by the real-mode init portion of IOS.VXD.
24 USHORT IDA_platform Platform (machine type) code.

#define IS_ISA 0x0001 // platform is isa

#define IS_EISA 0x0002 // platform is eisa

#define IS_MCA 0x0004 // platform is microchannel

#define IS_FAMILY3 0x0008 // platform is Family 3
28 ULONG IDA_flags Various state flags, see below for value definitions.

IDAF_BOOT_COMPLETE 0x0001 // boot complete

IDAF_REAL_MODE_ONLY 0x0002 // no prot mode port

drivers may load

IDAF_BIG_MEMORY 0x0040 // >16MB system memory.

IDAF_PUNT_CDS 0x0800 // force CD access through

real mode (unsafe CD

driver found)

IDAF_MSCDEX_PRESENT 0x1000 // indicates MSCDEX in the

system

IDAF_DOS_PAGER 0x2000 // system is paging

through DOS

IDAF_SHUTDOWN 0x4000 // system is shutting down
6C | USHORT IDA_rm_irq | Bitmap of unrecognized real-mode drivers' IRQs. Used to identify which IRQs cannot be used by protected-mode drivers.
2C | PVOID IDA_platform_config_data | Pointer to PCD chain (containing structures PCD_fixed_disk, and PCD_floppy_disk obtained prior to switch to protected mode) as computed in the real-mode init portion of IOS.VXD. See Listing 1 for structure.
30 PVOID IDA_first_dcb
Pointer to first DCB.
34 | PVOID IDA_logical_dev_map | Pointer to an array of LDM structures (see Listing 2). Logical device map for real-mode devices.
38 PVOID IDA_physical_dev_map Pointer to struct IDM array Int13 disk map. Structure used to audit and reconcile boot record vs. drive letter when assigning drive letters during IOS conversion from real-mode to protected-mode drivers. First built during real-mode IOS init phase. Contains list of these structures:

typedef struct IDM {

UCHAR IDM_int13_number; // int 13 unit; FFh if end

of table

ULONG IDM_signature; // signature from boot

record

ULONG IDM_checksum; // checksum of boot record

USHORT IDM_flags; // bit flags; 0x1=sig is

checksum method,

0x2=has been claimed by

protected-mode driver

} IDM
3C | PVOID IDA_rmm_phys_dcb | Pointer to the RMM (Real-Mode Mapper for handling real-mode drivers) DCB if there is one.
40 | PVOID IDA_first_vrp | Pointer to first Volume Request Parameters structure (VRPs are chained together using VRP_next_vrp. See VRP.H.
44 | ULONG IDA_drive_letter_map | Logical drive bitmap for assigning logical disk numbers.
48 | ULONG IDA_cdrom_letter_map | Logical drive bitmap for CD-ROM devices.
4C | ULONG IDA_rmd_ptr | Flat pointer to start of INT 2fh startup chain (Pointer to RMD list head), obtained using INT 2fh function 16h, subfunction 90h.
50 | ULONG IDA_aspi_cam_rmds | Start of ASPI/CAM RMDs.
54 | ULONG IDA_big_mem_buf_virt | Big memory buffer pointers.
58 | ULONG IDA_big_mem_buf_phys | Physical address of big memory buffer.
5C | ULONG IDA_big_mem_buf_size | Size of big memory buffer.
60 | ULONG IDA_ios_mem_pool_size | Size of IOS local heap - size of IDA structure (memory available for IOS layer driver or port driver memory requests).

Miscellaneous internal IOS static information (also displayed using .IDIDA)

Offset
Element
 Comments
- DCB * logical_drive_table[26] This table maps the logical drive letters to their corresponding DCB.
- DCB * physical_drive_table[24] This table maps pointers to the DCBs corresponding to INT13 non-diskette physical disk storage unit numbers (starting with BIOS unit 0x80).
- DCB * physical_floppy_table[8] This table maps pointers to the DCBs corresponding to INT13 diskette physical disk storage unit numbers (starting with BIOS unit 0x00).
- void * IOSPanicHead Panic buffer list head; used when IOS is blocked from being able to allocate memory from heap.
- IOSInitFlags Assorted these flags, mostly used internally by IOS to manage the handling of real-mode ASPI and CAM drivers. Bit 0x400 indicates IOS has completed its initialization (IOS_Init_Complete).
- IOS_Int13_Device_Chain This is a linked list consisting of the DCB_bdd portion of each DCB supporting INT13. The DCB_bdds are linked using the DCB_BDD_Next field.
- Void * MemSem Wait_semaphore() semaphore handle data used by the IOS memory manager. Blocks while waiting for some other IOS client to free some memory up. See also, MemBlockers.
- BYTE MemBlockers Count of threads awaiting memory allocation using the MemSem semaphore.
- Void * SemTabSem Semaphore, initially allocated with 8 credits. Blocks if more than 8 threads attempt to go through IOS. If does not block, then one of the SemTab[] semaphores is used to accommodate the synchronous mechanism.
- Void * SemTab[8] Eight semaphores are allocated to accommodate synchronous commands. The byte in SemTabInd indicates free/busy semaphores in SemTab.
- BYTE SemTabInd Bit map indicating which SemTab[] semaphores are in use. Bit clear (0) indicates semaphore is in use.
- DCB * inquiry_dcb Pointer to the inquiry DCB used by IOS during AEP_DEVICE_INQUIRY phase of layer driver initialization. Used for testing for the existence of physical devices attached to port drivers. NOTE: This DCB is deallocated from memory after IOS completes initialization.


DVT (Driver Vector Table)

One per driver or VSD; these are chained together in descending LGN number.

Use .IDDVT from debugger for list (using the debug version of IOS.VXD)

Offset
Element
 Comments
02 | ULONG    DVT_next_dvt | Pointer to next DVT.
06 | USHORT    DVT_device_cnt | Count of devices (DCBs) added/accepted.
08 | PVOID    DVT_aer | Driver's Async Event Routine (entry point for IOS AEP_… calls).
0C | ULONG    DVT_ddb | First DDB for this DVT.
10 | ULONG    DVT_ddb_init | First DDB for this DVT when first created during initialization (used by IOS to manage DDBs for all DVTs).
14 | CHAR    DVT_ascii_name[DVT_NAME_LEN] | Name of driver including extension, e.g. esdi_506.pdr.
24 | CHAR    DVT_create_date[DVT_DATE_LEN] | (Optional) date of creation.
2C | CHAR    DVT_create_time[DVT_TIME_LEN] | (Optional) time of creation.
34 | CHAR    DVT_rev_level[DVT_REV_LEN] | (Optional) revision level of driver.
38 | ULONG    DVT_feature_code | Feature code. See Listing 3.
3C | USHORT    DVT_if_requirements | Reserved. Not currently used.
3E BYTE    DVT_bus_type I/O bus type.

DVT_BT_ESDI 0x00 // ESDI or ESDI emulator

DVT_BT_SCSI 0x01 // SCSI or SCSI emulator

DVT_BT_FLOPPY 0x02 // FLOPPY

DVT_BT_SMART 0x03 // smart device

DVT_BT_ABIOS 0x04 // ABIOS or ABIOS emulator
3F | ULONG    DVT_reference_data | Reference data passed using DRP_reference_data when this driver registers using IOS_Register.
43 | CHAR    DVT_first_drive | Reserved. Not currently used.
44 | CHAR    DVT_current_lgn | Load group number assigned to this driver.
45 | ULONG    DVT_LoadHandle | Contains the Vxd's load handle (from VXDLDR_LoadDevice) if we loaded the driver; else 0.
49 | CHAR    DVT_scsi_max_target | SCSI: max target reported by SCSI (AEP_bi_i_max_target / MaximumNumberOfTargets).
4A | CHAR    DVT_scsi_max_lun | SCSI: max LUN supported for SCSI (set to 0x7 by SCSIPORT).
4B | PVOID    DVT_entry_point | SCSI: _PELDR_GetEntryPoint's entry point into NT SCSI miniport driver.
4F | UCHAR    DVT_init_count | Number of successful AEP_INITIALIZE calls (port drivers only). If zero upon init completion, IOS will deregister this port driver.

DDB (Driver Data Block)

Offset
Element
 Comments
00 | ULONG    DDB_phys_addr | Physical address of DDB.
04 | ULONG    DDB_Next_DDB | Next DDB on dvt_DDB chain.
08 | ULONG    DDB_Next_DDB_init | Next DDB on dvt_DDB_init chain (used by IOS to manage DDBs for all DVTs).
0C | ULONG    DDB_dcb_ptr | Pointer to first DCB owned by this DDB.
10 | UCHAR    DDB_number_buses | Number of buses supported by the adapter.
11 | UCHAR    DDB_ios_flags | IOS private flags - read only for non-IOS.
12 | USHORT    DDB_sig | DWORD padding (also DDB signature for asserting).
14 | PDVT    DDB_dvt | Pointer to this DDB's DVT.
18 | DEVNODE DDB_devnode_ptr | Pointer to Plug and Play device node for device.
1C | PDDB_ACPI_BLOCK DDB_pAcpiBlock | (Win98/Me. IDE ACPI support. NULL if IDE is not behind ACPI).

_DDB_ACPI_BLOCK

(pointed to by DDB_pAcpiBlock above)

Offset
Element
 Comments
00 | TIMINGMODEEX DDB_ACPI_TimingMode | Future use (all fields in debug dump that begin with "tm_").
14 | BYTE DDB_ACPI_bPowerState | Current ACPI Power State (e. g. CM_POWERSTATE_D0).
15 | BYTE DDB_ACPI_bIdeLevel | IDE compliance level.
16 | WORD DDB_ACPI_wSig | Signature (0x5043).
(Each of the following arrays contain two elements, to accommodate both primary and secondary IDE controller)
18 | ULONG DDB_ACPI_hTaskFile[2] | Future use.
20 | ULONG DDB_ACPI_dwEidLength[2] | Length of ATA EID structure.
28 | ULONG DDB_ACPI_dwEid[2] | Future use.
30 | ULONG DDB_ACPI_dwTaskFileLength[2] | Future use.
38 | ULONG DDB_ACPI_dwTaskFile[2] | Future use.


DCB (Device Control Block)

Use .IDDCB from debugger for list (using the debug version of IOS.VXD).

DCB_common area

Offset
Element
 Comments
00 | ULONG DCB_physical_dcb | Pointer to physical device DCB (can be self)
04 | ULONG DCB_expansion_length | Total length of IOP extension filled in by IOS (excludes IOP size)
08 | PVOID DCB_ptr_cd | Pointer to calldown list (see structure _DCB_cd_entry below). This list is used to initialize new IOP packets, each of which point to calldown entries using IOP_calldown_ptr.
0C | ULONG DCB_next_dcb | Link to next DCB. Forms a global DCB chain (containing all DCBs in system).
10 | ULONG DCB_next_logical_dcb | Pointer to next logical DCB associated with this device.
14 | BYTE DCB_drive_lttr_equiv | Drive number (A: = 0, and so on) set up by ISP_ASSOCIATE_DCB and TSDs during logical device associate processing.
15 | BYTE DCB_unit_number | Either physical drive number (sequential INT13 drive number OR'd with 80h) or unit number within TSD. Set up for disk physical DCBs. Set up by DISKTSD for disk logical DCBs. Set up by CDTSD for CD-ROM physical DCBs.
16 | USHORT DCB_TSD_Flags | Flags for TSD. See DCB.H.
18 | ULONG DCB_vrp_ptr | Pointer to VRP for this DCB.
1C | ULONG DCB_dmd_flags | Demand bits of the topmost layer.
20 | ULONG DCB_device_flags | Was BDD_Flags.
24 | ULONG DCB_device_flags2 | Second set of general purpose flags.
28 | ULONG DCB_Partition_Start | Partition start sector.
2C | ULONG DCB_track_table_ptr | Pointer for the track table buffer for IOCTLs.
30 | ULONG DCB_bds_ptr | DOS BDS corresponds. to this DCB (logical DCBs only).
34 | ULONG DCB_Reserved1 | Reserved.
38 | ULONG DCB_pEID | (IDE device) Pointer to EID structure obtained from IDE device.
3C | BYTE DCB_apparent_blk_shift | Log to base 2 of apparent_blk_size.
3D | BYTE DCB_partition_type | Partition type.
3E | USHORT DCB_sig | Padding and signature.
40 | BYTE DCB_device_type | Device Type (see DCB.H).
41 | ULONG DCB_Exclusive_VM | Handle for exclusive access to this device.
45 | UCHAR DCB_disk_bpb_flags | BPB flags.
46 | UCHAR DCB_cAssoc | Count of logical drives associated with this logical DCB.
47 | UCHAR DCB_Sstor_Host | This field indicates a SuperStor host volume.
48 | USHORT DCB_user_drvlet | Contains the UserDriveLetterAssignment settings from registry, else 0xFF.
4A | USHORT DCB_Reserved3 | Reserved.
4C | BYTE DCB_fACPI | (Windows 98) Indicates location on ACPI subtree.
4D | BYTE DCB_fSpinDownIssued | (Windows 98) Indicates a spindown has been issued.
4E | BYTE DCB_bPowerState | (Windows 98) Current CM_POWERSTATE_Dn.
4F | BYTE DCB_bEidLength | (Windows 98) for ACPI _STM – always 1 to indicate 1 sector (512 bytes).

(DCB ends here if it is a logical (non-physical) DCB)

DCB physical data extension

Offset
Element
 Comments
50 | ULONG DCB_max_xfer_len | Maximum transfer length supported by the driver/hardware.
54 | ULONG DCB_actual_sector_cnt [2] | Number of sectors as seen below the TSD.
5C | ULONG DCB_actual_blk_size | Actual block size of the device as seen below the TSD.
60 | ULONG DCB_actual_head_cnt | Number of heads as seen below the TSD.
64 | ULONG DCB_actual_cyl_cnt | Number of cylinders as seen below the TSD.
68 | ULONG DCB_actual_spt | Number of sectors per track as seen below the TSD.
6C | PVOID DCB_next_ddb_dcb | Link to next physical DCB, if more than one physical DCB is associated with a DDB.
70 | PVOID DCB_dev_node | Pointer to Plug and Play device node for this device.
74 | BYTE DCB_bus_type | Type of bus (see DCB.H).
75 | BYTE DCB_bus_number | Channel (cable) within adapter.
76 | UCHAR DCB_queue_freeze | Queue freeze depth counter. If nonzero indicates frozen. Tested but not set by IOS services' Dequeue_Iop() (Unless there are BYPASS_QUEUE IOPs, Dequeue_IOP is disabled).
77 | UCHAR DCB_max_sg_elements | Maximum number of logical and/or physical s/g elements. Set initially by port, but may be MORE RESTRICTIVELY updated by other layers.
78 | UCHAR DCB_io_pend_count | Indicates number of requests pending for this DCB (VOLUME TRACKING LAYER USE ONLY).
79 | UCHAR DCB_lock_count | Depth counter for LOCK MEDIA commands (VOLUME TRACKING LAYER USE ONLY).
7A | USHORT DCB_SCSI_VSD_FLAGS | Flags for SRB builder (DISKVSD).
7C | BYTE DCB_scsi_target_id | SCSI target ID.
7D | BYTE DCB_scsi_lun | SCSI logical unit number.
7E | BYTE DCB_scsi_hba | Host Bus Adapter number relative to port driver.
7F | BYTE DCB_max_sense_data_len | Maximum Sense Data length.
80 | USHORT DCB_srb_ext_size | Miniport SRB extension length (HwInitializationData->SrbExtensionSize; per-request storage required by the miniport driver).
82 | BYTE DCB_inquiry_flags[8] | Inquiry buffer; contains results of Device Inquiry issued to the hardware. The first byte contains the DCB_type_… reported by the hardware (see DCB.H).
8A | BYTE DCB_vendor_id[8] | Vendor ID string.
92 | BYTE DCB_product_id[16] | Product ID string.
A2 | BYTE DCB_rev_level[4] | Product revision level.
A6 | BYTE DCB_port_name[8] | Name of driver, such as ESDI_506.PDR.
AE | UCHAR DCB_current_unit | Used to emulate multiple logical devices with a single physical device, e.g. the same physical floppy drive can be drive A or B.
AF | ULONG DCB_blocked_iop | Pointer to requests for an inactive volume (VOLUME TRACKING LAYER USE ONLY).
B3 | ULONG DCB_vol_unlock_timer | Unlock timer handle.
B7 | UCHAR DCB_access_timer | Used to measure time between accesses.
B8 | UCHAR DCB_Vol_Flags | Flags for Volume Tracking volume tracking use only.
B9 | BYTE DCB_q_algo | Queuing algorithm index – 0=FIFO, 1=SORTED.
BA | BYTE DCB_unit_on_ctl | Relative device number on ctlr (0-based).
BB | ULONG DCB_Port_Specific | Bytes for PORT DRIVER use.
BF | ULONG DCB_spindown_timer | Timer for drive spindown.

Extension for INT13h drives (BDD) blockdev compatibility. The following fields directly correlate with the BLOCKDEV structure BlockDev_Device_Descriptor used in Windows 3.1x BLOCKDEV (fastdisk) drivers.

Offset
Element
 Comments
C3 | ULONG DCB_BDD_Next | (Also known as BDD_Next) Chaining pointer to next BDD.
C7 | BYTE DCB_BDD_BD_Major_Version | (Also known as BDD_Major_Version.)
C8 | BYTE DCB_BDD_BD_Minor_Version | (Also known as BDD_Minor_Version.)
C9 | BYTE DCB_BDD_Device_SubType | (Also known as BDD_Device_Type.)
CA | BYTE DCB_BDD_Int_13h_Number | (Also known as BDD_Int_13h_Number.)
CB | ULONG DCB_BDD_flags | (Also known as BDD_Flags.)
CF | ULONG DCB_BDD_Name_Ptr | (Also known as BDD_Name_Ptr.)
D3 | ULONG DCB_apparent_sector_cnt[2] | (Also known as BDD_Max_Sector[2]) No. of sectors as seen by TSD and above.
DB | ULONG DCB_apparent_blk_size | (Also known as BDD_Sector_Size) block size of dev. as seen by TSD and above.
DF | ULONG DCB_apparent_head_cnt | (Also known as BDD_Num_Heads) No. of heads as seen by TSD and above.
E3 | ULONG DCB_apparent_cyl_cnt | (Also known as BDD_Num_Cylinders) No. of cyls as seen by TSD and above.
E7 | ULONG DCB_apparent_spt | (Also known as BDD_Num_Sec_Per_Track) No. of secs/trk as seen by TSD and above.
EB | ULONG DCB_BDD_Sync_Cmd_Proc | (Also known as BDD_Sync_Cmd_Proc.)
EF | ULONG DCB_BDD_Command_Proc | (Also known as BDD_Command_Proc.)
F3 | ULONG DCB_BDD_Hw_Int_Proc | (Also known as BDD_Hw_Int_Proc) Hardware interrupt procedure, <0> to indicate none used.
(End of BlockDev_Device_Descriptor)
F7 | ULONG DCB_BDP_Cmd_Queue_Ascending | Pointers to queued IOPs. Each IOP uses its IOR_next field as a chaining pointer.
FB | ULONG DCB_BDP_Cmd_Queue_Descending | Pointers to queued IOPs. Each IOP uses its IOR_next field as a chaining pointer.
FF | ULONG DCB_BDP_Current_Flags
103 | ULONG DCB_BDP_Int13_Param_Ptr
107 | ULONG DCB_BDP_Current_Command
10B | ULONG DCB_BDP_Current_Position[2] | Used to remember prior sector number (used by enqueue_iop to determine whether to queue ascending or descending).
113 | ULONG DCB_BDP_Reserved[5]
127 | ULONG DCB_fastdisk_bdd | Set for DCBs created when a fastdisk (Win3.1 block driver) registers with the blockdev BDD for it; else 0.

DCB_CDROM data extension

Offset
Element
 Comments
12B | ULONG DCB_cdrom_Partition_Start | Partition start sector.
12F | ULONG DCB_cdrom_Partition_End | Partition end sector.
133 | UCHAR DCB_cd_ls_ft | First track number in the last session.
134 | ULONG DCB_TOC[202] | CD-ROM Table of Contents buffer
45C | ULONG DCB_cd_mode_sense_buf[20/4+1] | CD-ROM mode sense buffer.
474 | UCHAR DCB_cd_first_session | Index number of first session.
475 | UCHAR DCB_cd_last_session | Index of last session on disc.
476 | ULONG DCB_play_resume_start | Restart address when paused (LBA).
47A | ULONG DCB_play_resume_stop | End of restarted play (LBA).
47E | ULONG DCB_play_status | Last command play status.
482 | ULONG DCB_cd_device_flags | Flags indicating the audio support capabilities of the device.
486 | UCHAR DCB_cd_fs_lt | Last track in the first session.
487 | UCHAR DCB_cd_bobbit_pt | Indicates the track where a CDPLUS disc is terminated to prevent data tracks from showing up in the table of contents.
488 | ULONG DCB_cd_fs_lo | Lead out address of first session.
48C | ULONG DCB_cd_last_session_start | LBA start address of data area in the last session on a multi-session disc.
490 | ULONG DCB_cd_current_block_size | Current block size selected by the mode command.
494 | UCHAR DCB_cd_vol_map[8] | Current volume / channel mapping.
4BC | ULONG DCB_cd_current_command | Current command.
4A0 | ULONG DCB_cd_queue_head | Head of current command queue.
4A4 | ULONG DCB_cd_reserved | Reserved.

_DCB_disk extension

Offset
Element
 Comments
12F | USHORT DCB_write_precomp | Write Precompensation.
131 | ULONG DCB_disk_tsd_private | Private area for TSD. used to store b: BDS ptr for single flp.

_DCB_cd_entry

(Calldown entry contained in calldown chain pointed to by DCB_ptr_cd)

Offset
Element
 Comments
00 | PVOID DCB_cd_io_address | Address of an IOS driver's AER request routine.
04 | ULONG DCB_cd_flags | Demand bits - as defined below.
08 | ULONG DCB_cd_ddb | Driver's DDB pointer.
0C | ULONG DCB_cd_next | Pointer to next calldown entry.
10 | USHORT DCB_cd_expan_off | Offset of expansion area used by the request routine.
12 | UCHAR DCB_cd_layer_flags | Flags for layer's use.
13 | UCHAR DCB_cd_lgn | Load Group number (IOS layer driver order).


IOP (Input/Output Packet)

Offset
Element
 Comments
00 | ULONG IOP_physical | Physical address of IOP.
04 | ULONG IOP_physical_dcb | Pointer to physical DCB. Filled in by IOS_SendCommand or ILB_Internal_Request.
08 | ULONG IOP_original_dcb | Pointer to DCB designated by IOR. Filled in by IOS_SendCommand (address of logical DCB).
0C | USHORT IOP_timer | Current timeout value. Filled in by IOS_SendCommand. Default value = 15 (7.5 seconds).
0E | USHORT IOP_timer_orig | rcb original timeout value. Filled in by IOS_SendCommand. Default value = 15 (7.5 seconds).
10 | ULONG IOP_calldown_ptr | Pointer to next calldown routine (structure type DCB cd_entry) Filled in by IOS_SendCommand.
14 | ULONG IOP_callback_ptr | Pointer to current callback address.
18 | ULONG IOP_voltrk_private | For use by volume tracking.
1C | ULONG IOP_Thread_Handle | Contains the handle of the thread in whose context this I/O originated. This is initialized in IOS_SendCommand. Not used if called with ILB_Internal_Request.
20 | ULONG IOP_srb | Used by SCSI'izers (or by SCSI Passthrough requests) to pass SRB pointer to next layer. Valid if (IOR_flags & IORF_SRB_VALID) is set
24 | ULONG IOP_reserved[2] | Reserved for future use - must be zero.
2C | IOP_callback_entry IOP_callback_table[IOP_CALLBACK_TABLE_DEPTH] | The mechanism to allow layer drivers to be called on the way back up, after the port driver has completed processing the IOP. The layer driver requests this event by adding itself to the callback table, when it is processing the IOP, before it gets to the port driver. See IOP_callback_entry below.
5C | BYTE IOP_format_head | Fields for low-level format.
5D | BYTE IOP_format_xfer_rate
5E | USHORT IOP_format_track
60 | ULONG IOP_format_num_sectors
IOR IOP_ior | I/O request descriptor (attached contiguously to IOP).

IOR (Input/Output Request Block)

Offset
Element
 Comments
64/00 | ULONG IOR_next | Client link for BCBs (for IORF_VERSION_002).
68/04 | USHORT IOR_func | Function to be performed - see defines below.
6A/06 | USHORT IOR_status | Request status - see IOR.H.
6C/08 | ULONG IOR_flags | Request control flags – see IOR.H.
70/0C | CMDCPLT IOR_callback | Address to call request back to if IORF_SYNC_COMMAND is not set (used in internal IOS_SendCommand routine).
74/10 | ULONG IOR_start_addr[2] | Volume relative starting address if IORF_LOGICAL_START_SECTOR is set. Physical if not set.
7C/18 | ULONG IOR_xfer_count | Number of sectors to process if IORF_CHAR_COMMAND is not set, or number of bytes if it is set. MUST be set to zero if no data transfer. Must be less than 65536 if CD-ROM.
80/1C | ULONG IOR_buffer_ptr | BlockDev client buffer pointer. Contains pointer to data buffer or to null-terminated list of linear SGDs depending on IORF_SCATTER_GATHER. Undefined if no data transfer.
84/20 | ULONG IOR_private_client | BlockDev/IOS client reserved.
88/24 | ULONG IOR_private_IOS | Reserved space for IOS.
8C/28 | ULONG IOR_private_port | Private area for port driver.
90/2C | union urequestor_usage _ureq | Requestor usage area, also used for IOCTLs. SCSIPORT uses this to point to SRB.
A4/40 | ULONG IOR_req_req_handle | Requestor-provided request handle. Often is a pointer to this IOR or its containing IOP. Pushed on the stack by IOS before IOR_callback is called.
A8/44 | ULONG IOR_req_vol_handle | Requestor provided media handle designating the media to perform the function on (VRP).
AC/48 | ULONG IOR_sgd_lin_phys | Pointer to first physical SGD, as contrasted with IOR_buffer_ptr, which points to the logical SGDs. This is either a linear or physical address, depending on the needs of the drivers, as indicated by the DCB demand bits.
B0/4C | UCHAR IOR_num_sgds | Number of physical SGDs pointed to by IOR_sgd_lin_phys.
B1/4D | UCHAR IOR_vol_designtr | Numeric representation of the drive letter designating the volume to perform the function on (c: = 2). Set this to DCB_unit_number.
B2/4E | USHORT IOR_ios_private_1 | Reserved by IOS to audit alignment. Currently used only within the ILB_io_criteria_rtn.
B4/50 | ULONG IOR_reserved_2[2] | Reserved for internal use.

IOP_callback_entry

Offset
Element
 Comments
00 | ULONG IOP_CB_address | Callback address.
04 | ULONG IOP_CB_ref_data | Pointer to callback reference data.


SRB (SCSI_REQUEST_BLOCK)

Offset
Element
 Comments
0 | USHORT Length | IN: Size SCSI_REQUEST_BLOCK.
2 | UCHAR Function | IN: Function.
3 | UCHAR SrbStatus | OUT: Status from HBA.
4 | UCHAR ScsiStatus | OUT: Status from HBA.
5 | UCHAR PathId | IN: Set to DCB_bus_number (geometry).
6 | UCHAR TargetId | IN: Set to DCB_scsi_target_id.
7 | UCHAR Lun | IN: Set to DCB_scsi_lun.
8 | UCHAR QueueTag | IN: 0. Used by SCSIPORT to enqueue the SRB on the adapter's input queue. Also see MultipleRequestPerLu in HW_INITIALIZATION_DATA structure.
9 | UCHAR QueueAction | IN: 0 (Not used in SCSIPORT).
a | UCHAR CdbLength | IN: Length of CDB e.g. 6 for Inquiry.
b | UCHAR SenseInfoBufferLength | IN: Length of SenseInfoBuffer. Postcall: miniport driver updates this field if it supports auto-sense request (transfers sense-request information).
c | ULONG SrbFlags | IN; e.g. SRB_FLAGS_DATA_IN + SRB_FLAGS_DISABLE_DISCONNECT
10 ULONG DataTransferLength IN:Size of DataBuffer, e.g. SIZE_OF_INQUIRYDATA.

OUT: miniport driver updates this field if an under-run or over-run occurs. Caution: This field, combined with DataBuffer, is used by Windows 95 ScsiPort(xxx)Buffer(xxx) (SGD emulation) routines when searching for the SRB corresponding to the memory buffer address desired. In such cases, if this SRB is being accessed by the miniport driver, never modify these fields.

14 | ULONG TimeOutValue | IN: Must set this pre-request, if SCSI PASSTHROUGH. SCSIPORT puts this into IOP_timer and IOP_timer_orig (500ms intervals)
18 | PVOID DataBuffer | IN: Point to memory created using the ILB_Service_rtn() ISP_Alloc_Mem, e.g. SIZE_OF_INQUIRYDATA, and so on. SCSIPORT sets this to the value in IOP_ior.buffer_ptr, if SRB_flags indicate data transfer in or out.
1c | PVOID SenseInfoBuffer | IN: Pointer to sense information buffer; which is typically located just past our SrbExtension. Make large enough to accommodate worst-case sense data from drive. Set to null to disable auto-sense.
20 | struct _SCSI_REQUEST_BLOCK *NextSrb | IN: Set to 0. SCSIPORT uses this field to link the enqueued SRBs in a chain (see QueueTag above)
24 | PVOID OriginalRequest | IN: 0. Not used by SCSIPORT.
28 | PVOID SrbExtension | IN: Pointer to extension area (just past this SRB, and the _PORT_SRB extension). Length of this extension area is DCB_srb_ext_size. Set up by ScsiPortInitialize() to supply miniport requested/defined per-request state information storage.
2c | ULONG QueueSortKey | Used in SCSIPORT as a temporary to hold a pointer to an APE structure if paging drive is having problems and drive retries are required.
30 | UCHAR Cdb[16] | IN: Contains desired CDB to issue to HBA. Actual command length is CdbLength. If communicating with an ATAPI device (through ESDI_506.PDR), length can be set to (a maximum of) 12, even if an actual command uses fewer bytes. If communicating with a SCSI device, the length must correspond to the expected length of the command.

_PORT_SRB

(Windows 9x Miniport SRB extension)

Offset
Element
 Comments
00 | SCSI_REQUEST_BLOCK BaseSrb | _PORT_SRB IS AN EXTENSION OF SCSI_REQUEST_BLOCK; not present under NT-based operating systems.
40 | PVOID SrbIopPointer | IN: Pointer to the IOP. This is a means for the SCSI miniport driver to gain access to the IOP (not compatible with the miniport model used in NT-based operating systems).
44 | SCSI_REQUEST_BLOCK *SrbNextSrb | This pointer chains pending SRBs together. Used by SCSIPORT.PDR to manage SRBs.
48 | SCSI_REQUEST_BLOCK *SrbNextActiveSrb | IN: Allows SCSIPORT to keep a list of all active SRBs (SRBs that have been submitted to a miniport and are still under its control).
4C | UCHAR SrbRetryCount | Internal variable to keep track of hardware retries. Used by DISKVSD / CDVSD.
4D | UCHAR Filler[3]


IOS Registration Flowchart

IOS Layer Drivers

The following chart supplies general information about the assorted IOS layer drivers, including the criteria used to determine whether or not a layer driver adds itself to the call down chain associated with a DCB it receives during AEP_CONFIG_DCB:

Device | Layer no. | Layer type | AEP_CONFIG_DCB Call down insertion qualifications (tested in the order shown)
VOLTRACK.VXD 5 DRP_

VOLTRK_

BIT

 1. Ignores if !(DCB_device_flags & DCB_DEV_REMOVABLE)

2. Hooks if DCB_device_type is DCB_type_floppy

3. Ignores if !(DCB_device_flags & DCB_DEV_LOGICAL)

4. Hooks if DCB_device_type is DCB_type_disk or DCB_type_cdrom.
CDTSD.VXD 6 DRP_

CLASS_ DRV_BIT

 1. Ignore if not (DCB_device_type == DCB_type_cdrom).

2. Ignore if any of the following DCB_dmd_flags bits are set: (DCB_dmd_srb_cdb+DCB_dmd_rsrv_1+DCB_dmd_rsrv_2).
DISKTSD.VXD 7 DRP_TSD_

BIT

 1. Ignore if a logical DCB or if handled by rmm (if DCB_device_flags & (DCB_dev_logical | DCB_dev_rmm))

2. Ignore if not a disk (DCB_device_type != DCB_type_disk)

3. Ignore if not a floppy (DCB_device_type != DCB_type_floppy)

4. Ignore if any of the following DCB_dmd_flags bits are set: (DCB_dmd_srb_cdb+DCB_dmd_rsrv_1+DCB_dmd_rsrv_2).
APIX.VXD 11 DRP_SCSI_ LAYER_BIT 1. Ignore if not a physical DCB
(!(DCB_device_flags & DCB_dev_physical))

2. Ignore if device does not use the SCSI bus
(DCB_Bus_Type != DCB_Bus_SCSI)
CDVSD.VXD 13 DRP_VSD_5_ BIT 1. Ignore if a logical DCB or if handled by rmm (if DCB_device_flags & (DCB_dev_logical | DCB_dev_rmm))

2. Ignore if device does not use the SCSI bus
(DCB_Bus_Type != DCB_Bus_SCSI)

3. Ignore if not a CD-ROM (DCB_device_type != DCB_Type_CDROM)

4. Accept if device has been forced to use protected-mode code or it is safe to use protected-mode code. Ignore if MSCDEX is installed.
NECATAPI.VXD 14 DRP_VSD_6_ BIT 1. Ignore if a logical DCB or if handled by rmm (if DCB_device_flags & (DCB_dev_logical | DCB_dev_rmm))

2. Ignore if device does not use the SCSI bus
(DCB_Bus_Type != DCB_Bus_SCSI)

3. Ignore if not a CD-ROM (DCB_device_type != DCB_Type_CDROM)

4. This VxD tweaks the CDB if the target device is an NEC ATAPI device.
DISKVSD.VXD 16 DRP_VSD_8_ BIT 1. Ignore if a logical DCB or if handled by rmm (if DCB_device_flags & (DCB_dev_logical | DCB_dev_rmm))

2. Ignore if device does not use the SCSI bus
(DCB_Bus_Type != DCB_Bus_SCSI)

3. Ignore if not a disk (DCB_device_type != DCB_Type_disk)

4. Accept if !(DCB_inquiry_flags.INQ_dev_type_mod & INQ_mod_removable).

5. Otherwise, conditionally accept depending on manufacturer ID (Insite or IOMEGA floptical).
ATAPCHNG.VXD 16 DRP_VSD_8_ BIT 1. Ignore if a logical DCB or if handled by rmm (if DCB_device_flags & (DCB_dev_logical | DCB_dev_rmm))

2. Ignore if neither DCB_port_name == IDEATAPI, or DCB_device_flags2 == DCB_DEV2_ATAPI_DEVICE

3. Ignore if not SCSI (DCB_Bus_Type != DCB_Bus_SCSI)

4. Ignore if not CD-ROM (DCB_Device_Type!=DCB_Type_CDROM)

5. Ignore if LUN=0 (if non zero, the ATAPI change created the drive)

6. Issue a sense command to the CD-ROM to identify whether it is a changer; ignore if it is not.

7. Otherwise take over the CD-ROM device.
SCSI1HLP.VXD 15 DRP_VSD_7_ BIT 1. Ignore if a logical DCB or if handled by rmm (if DCB_device_flags & (DCB_dev_logical | DCB_dev_rmm))

2. Ignore if device doesn't use the SCSI bus
(DCB_Bus_Type != DCB_Bus_SCSI)

3. Ignore if not a CD-ROM (DCB_device_type != DCB_Type_CDROM)

4. Check the dead_drive_table list. If in the list, and within the revision range specified, set DCB_cd_device_flags |= DCB_CD_FAKE_SCSI1. This will force a "bad" drive to use scsi1 behavior.

5. Check the mfg_id_table. If in the table, or if the ANSI version field indicates it is a generic SCSI1 device ((DCB_inquiry_flags[2] & 0000111) < 2), accept it (take over the device).

6. Note that when this driver intercepts requests, it will ignore IOR_SCSI_PASS_THROUGH IOPs.
SMARTVSD.VXD 17 DRP_VSD_9_ BIT 1. Ignore if a logical DCB or if handled by rmm (if DCB_device_flags & (DCB_dev_logical | DCB_dev_rmm))

2. Accept if (DCB_bus_type == DCB_BUS_ESDI) && (DCB_device_type == DCB_type_disk)), or if (DCB_device_flags2 & DCB_DEV2_ATAPI_DEVICE)

3. Note that this VxD does not "hook" into the calldown chain. It serves as a ring 3 interface (DeviceIoControl)
SCSIPORT.PDR | 21 | DRP_NT_PD_ BIT | (No qualifications needed – this is a port driver.)
ESDI_506.PDR | 22 | DRP_ESDI_PD_BIT | (No qualifications needed – this is a port driver.)
HSFLOP.PDR | 27 | DRP_NEC_ FLOPPY_BIT | (No qualifications needed – this is a port driver.)
RMM.PDR | 30 | DRP_SOC_ DRV_BIT | (No qualifications needed – this is a port driver.)


IOS Sample Code

Unless otherwise indicated, the following storage samples are available in either or both of the Windows 95 DDK and the Windows 98 DDK:

Sample type | Sample name | Comments
SCSI Miniport Driver | PC2X | This is the miniport driver for the Iomega PC2x 8-bit SCSI adapter card. Instead of using this sample, the ATAPI miniport sample described below is the recommended sample.
SCSI Miniport Driver | ATAPI | (Located in the Windows NT 4.0 DDK, not the Windows 95 or Windows 98 DDK) A SCSI miniport driver that when compiled, can be binary compatible between Windows 95/98 and NT-based versions of the operating system (but is not binary compatible if Windows system calls using VMMCall are compiled in).
IOS Port Driver | PORT | This is an IOS Port device driver sample, serving only as a template for developing a new Port driver. It is written in assembly language. Port drivers reside at the bottom of the IOS layered hierarchy, and typically communicate with storage device hardware. This sample demonstrates how to use ILB_enqueue_IOP and ILB_dequeue_IOP in order to buffer IOPs sent to the driver while the driver is already busy processing an IOP.
IOS Vendor Supplied Driver | VSD | This is an IOS Vendor Supplied Driver device driver sample, serving only as a template for developing a new VSD. This type of driver is sometimes called a helper VSD. VSD drivers reside in the middle of the IOS layered hierarchy, between port drivers and File System Drivers. They can be used to monitor and filter communications between FSDs and port drivers. They can be used to interface ring 3 applications to ring 0 IOS components. The sample is written in assembly language.
IOS Vendor Supplied Driver | PASSTHRU | (Located on our support Web site at http://support.microsoft.com/support/ddk) A sample VSD based on the HELPVSD sample, which demonstrates how to issue a command to a SCSI device using the SCSI Passthrough technique.
Win 32 Application | WNASPI | A sample ASPI for an Win32 application program linking the WNASPI32.DLL export functions. This application demonstrates how an application can issue pass-through commands to SCSI devices and ATAPI CD-ROMs. For example, tape backup utility programs use this mechanism. Note that Windows 95 also comes with WINASPI.DLL, which is used to support ASPI communications from a 16-bit Windows application.
S.M.A.R.T. Application | SMARTAPP | (Located in Knowledge Base article Q208048.) SmartApp.exe is a sample Win32 application that demonstrates how to access the SMART (Self Monitoring, Analysis and Reporting Technology) capabilities built into IDE disk drives. SMART technology is used to monitor disk drive degradation, in an effort to predict future catastrophic disk failure.

Setting up and compiling sample code

With the exception of the SMARTAPP sample, the above samples will compile successfully using NMAKE when the Windows 95 DDK is used, or BUILD when the Windows 98 DDK is used. Refer to the corresponding DDK for details. The SMARTAPP sample will build using Visual Studio.


Supplemental Listings

The following topics include information about some relevant API elements, as well as a sample.


PCD (Platform Configuration Data) Structures

/* Definitions for PCD Types */

#define PCD_TYPE_FIXED_DISK        0    /* PCD for fixed disk        */
#define PCD_TYPE_FLOPPY_DISK        1    /* PCD for floppy disk        */
#define PCD_TYPE_NEW_FIXED_DISK       2    /* fake PCD for new disk    */

typedef struct PCD_generic { /* */

    UCHAR    PCD_type;            /* see types above            */
    ULONG    PCD_delta_next;        /* delta to next PCD or zero if none  */

} PCD, *pnPCD, far *pfPCD, far *pPCD;

/*
** define the fixed disk PCD
*/

typedef struct PCD_fixed_disk { /* */

    UCHAR    PCD_filler_0;        /* "PCD_TYPE_FIXED_DISK"*/
    ULONG    PCD_filler_1;        /* PCD_delta_next*/
    UCHAR    PCD_fixed_unit_number;    /* unit number (80-ffh) */
    USHORT PCD_fixed_cyl_cnt;     /* total number of cylinders */
    USHORT PCD_fixed_head_cnt;     /* total number of heads */
    USHORT PCD_fixed_spt;      /* sectors/track */
    UCHAR    PCD_fixed_flags ;
} PCD_fixed_disk, near *pnPCD_fixed_disk, far *pfPCD_fixed_disk, far *pPCD_fixed_disk;

#define    PCD_FIXED_FL_EXTINT13    0x01

typedef struct PCD_ext_int13 { /* */
    USHORT PCD_X13_res ;
    USHORT PCD_X13_flags ;
    ULONG    PCD_X13_cyl_cnt ;
    ULONG    PCD_X13_head_cnt ;
    ULONG    PCD_X13_spt ;
    ULONG    PCD_X13_sec_cnt_lo ;
    ULONG    PCD_X13_sec_cnt_hi ;
    USHORT PCD_X13_sec_size ;
} PCD_ext_int13 ;

typedef struct PCD_X13_fixed_disk { /* */
    struct PCD_fixed_disk PCD_fixed_13 ;
    struct PCD_ext_int13 PCD_fixed_x13 ;
} PCD_X13_fixed_disk ;

/*
** define the floppy disk PCD
*/

typedef struct _DPT_floppy_disk { /* */

    UCHAR DPT_floppy_spec1;      /* step rate time, head unload time */
    UCHAR DPT_floppy_spec2;       /* head load time, DMA mode */
    UCHAR DPT_floppy_wait_time;      /* wait time until diskette motor off */
    UCHAR DPT_floppy_b_p_s;      /* bytes per sector: 0=128 1=256 2=512 3=1024 */
    UCHAR DPT_floppy_l_s_n;      /* last sector number */
    UCHAR DPT_floppy_gap_len;      /* gap length between sectors (r/w) */
    UCHAR DPT_floppy_data_len;      /* data length when no sector length */
    UCHAR DPT_floppy_gap_lenf;      /* gap length between sectors (format) */
    UCHAR DPT_floppy_f_d_v;      /* data value stored in formatted sectors */
    UCHAR DPT_floppy_h_s_t;      /* head settle time */
    UCHAR DPT_floppy_m_s_t;      /* motor start-up time */
} DPT_floppy_disk;

typedef struct PCD_floppy_disk { /* */

    UCHAR    PCD_filler_2;        /* "PCD_TYPE_FLOPPY_DISK"  */
    ULONG    PCD_filler_3;        /* PCD_delta_next                */

    UCHAR    PCD_floppy_unit_number;  /* unit number (00-7fh) */

    USHORT PCD_floppy_cyl_cnt;     /* total number of cylinders */
    USHORT PCD_floppy_head_cnt;     /* total number of heads */
    USHORT PCD_floppy_spt;      /* sectors/track */

    UCHAR  PCD_floppy_drive_type; /* CMOS drive type */
                    /* 01 = 5.25", 360k, 40 track */
                    /* 02 = 5.25", 1.2M, 80 track */
                    /* 03 = 3.5", 720K, 80 track */
                    /* 04 = 3.5", 1.44M, 80 track */
    UCHAR    PCD_floppy_flags;

   /* definition for diskette parameter table follows */

    DPT_floppy_disk    PCD_floppy_dpt;

    ULONG PCD_floppy_dpt_addr;

} PCD_floppy_disk, near *pnPCD_floppy_disk, far *pfPCD_floppy_disk, far *pPCD_floppy_disk;

// OR PCD_floppy_flags with this to specify that it supports change line
#define PCD_FLAGS_FLP_CHG_LINE_SUPPORT    0x01


LDM (Logical Device Map) Structures

typedef struct LDM { /* */
    UCHAR    LDM_drive_letter;    /* numeric drive letter equivalent (00 = a:) */
                                    /* FFh indicates end of table                */
    UCHAR    LDM_int13_unit;    /* int 13 unit number, or FFh if none */
    ULONG    LDM_serial_number;    /* serial number from the volume boot record */
    ULONG    LDM_starting_rba;    /* starting RBA of this logical volume */
    UCHAR    LDM_aspi_target;    /* aspi target id */
    UCHAR    LDM_aspi_lun;         /* aspi lun */
      UCHAR    LDM_aspi_bus;         /* aspi bus number */
    UCHAR    LDM_cam_target;    /* cam target id */
    UCHAR    LDM_cam_lun;          /* cam lun */
    UCHAR     LDM_cam_bus;          /* cam bus number */
    USHORT LDM_flags;        /* flags as defined below                    */
} LDM, *pLDM;

/*
** IDM_flags definitions follow
*/

#define    LDM_FL_CLAIMED_BIT 0x00         /* logical dev claimed in protected mode  */
#define    LDM_FL_CLAIMED  1 << LDM_FL_CLAIMED_BIT
#define    LDM_FL_INVALID_MEDIA_BIT 1
#define    LDM_FL_INVALID_MEDIA     0x02         /* the logical volume is invalid */
#define    LDM_FL_REAL_MODE_ONLY     0x04        /* device must be handled by RM driver */
#define    LDM_FL_UNSAFE_HOOK        0x08    /* device driver has been hooked */
#define    LDM_FL_HOOKED    LDM_FL_UNSAFE_HOOK
#define    LDM_FL_MONO    0x10            /* unit controlled by monolithic drvr*/


DVT_feature_code Definitions

#define DVT_FC_SCAN_DOWN   0x04    /*  on = bios scans targets from high to low*/
#define DVT_FC_IO_FOR_INQ_AEP 0x40 /*  on = PD needs to send I/O through IOP in response to an
INQUIRY AEP. Results in CONFIGURE AEP for INQUIRY DCB.*/
#define DVT_FC_HALF_SEC    0x2000  /*  on = notify driver every half second    */
#define DVT_FC_1_SEC       0x2000  /*  on = notify driver every second         */
#define DVT_FC_2_SECS       0x4000   /*  on = notify driver every two seconds    */
#define DVT_FC_4_SECS       0x8000   /*  on = notify driver every four seconds   */
#define DVT_FC_DYNALOAD     0x10000  /*  on = driver was dynaloaded    by IOS         */
#define DVT_FC_NEED_PRELOAD 0x20000  /*  on = driver needs to hook I/O even  before the
port driver. AEP_config_dcb  will be received
before PD when set */
#define DVT_FC_NEED_PRE_POST_LOAD   0x40000
#define    DVT_FC_SUPPORT_ESDI_REENUMERATION    0x80000 /* handle INQUIRY for reenumeration (along with DCB_DEV2_INQ_DCB) */
#define DVT_FC_NTMAP       0x100000

See DCB.H for more information regarding these fields.


Sample .IDUMP Report

The debug version of IOS.VXD offers assorted dot commands (use .I? for a summary).

For each of the dot commands that begin with .ID…, fields are reported in the form <symbol name>'@'<offset>, where <offset> is the numeric (hex) offset of the field within the parent structure. This information is reported only to facilitate debugging, since these offset values may vary with the version of operating system used.

Definitions for these fields are contained in IOS internal data structure detail.

For best results, install the symbol files for every IOS layer possible, in order to see symbolic addresses in these reports.

A sample debugger dump follows.

1##.i?
*** I/O Subsystem debug help ***
.IIOP <exp>  - dumps IOP/IOR/IOR callback structures for specified address
.IDCB <exp>  - dumps DCB and the calldown table lists for specified address
               or specify 0-19h for DCB from logical_drive_table
.IMED        - lists IOS Memory Pool entries
.ILDCB       - lists the DCBS
.ILDVT       - lists the devices
.IDUMP       - comprehensive structured dump of IOS components
.IDIDA       - full IOS data area dump
.IDDVT <exp> - full DVT dump
.IDDCB <exp> - full DCB dump
1##.idump
====================================================================================
c0fcf000 IDA (IOS Data Area)
 ios_mem_phys@08 00fdf000     ios_timer@10 000000d8
esdi_p_in_use@20 ee       esdi_s_in_use@21 ee          Num_Floppies@22 01
     platform@24 0001             flags@28 00000041          rm_irq@6C 0001

platform_config_data@2C c03e082a            first_dcb@30 cb5d3c10
     logical_dev_map@34 c14c83d0     physical_dev_map@38 c03e0e8a
        rmm_phys_dcb@3C 00000000            first_vrp@40 c159b550
    drive_letter_map@44 0000001f     cdrom_letter_map@48 00000000
             rmd_ptr@4C c2902067        aspi_cam_rmds@50 00000000
    big_mem_buf_virt@54 c0fdf000     big_mem_buf_phys@58 00fef000
    big_mem_buf_size@5C 00010000    ios_mem_pool_size@60 0000ff92

--- Other non-IDA internal IOS static info ---
    logical_drive_table c008228c            IOSPanicHead 00000000
   physical_drive_table c00822f4            IOSInitFlags 0000059c
  physical_floppy_table c0082354               SemTabInd ff
 IOS_Int13_Device_Chain cb5d3343                  MemSem c146d0e0
             Inquiry_DCB c15a72b0             MemBlockers 00

 scsi_max_target@49 00         entry_point@4B dbe50101

           ptr_cd@08 c14bc840         Reserved1@34 00000000      disk_bpb_flags@45 00
 next_logical_dcb@10 00000000      Exclusive_VM@41 00000000          Sstor_Host@47 00

    device_flags2@24 00000000       unit_number@15 00               bPowerState@4E 01

        rev_level@A2               queue_freeze@76 00           io_pend_count@78   00
           q_algo@B9 01      max_sense_data_len@7F 00             unit_on_ctl@BA   00

       scsi_target_id@7C 00               actual_head_cnt@60 00000002
             scsi_hba@7E 00                    actual_spt@68 00000012

 BDD_BD_Minor_Version@C8 00              apparent_cyl_cnt@E3 00000050
         BDD_Name_Ptr@CF 00000000       BDD_Sync_Cmd_Proc@EB 00000000
      BDD_Hw_Int_Proc@F3 00000000       BDP_Current_Flags@FF 00000000

 BDP_Cmd_Queue_Descending@FB 00000000

 c00823eb  00000000  00000000  0000   00       1f     DRP_IOS_REG %c00887bb

 scsi_max_target@49 00         entry_point@4B 3277ba0f

 tm_PIOSpeed1@08 00000000              dwEid@28 00000000 00000000
     tm_Flags@10 00000000         dwTaskFile@38 00000000 00000000

           ptr_cd@08 c1582f20         Reserved1@34 00000000      disk_bpb_flags@45 00
 next_logical_dcb@10 cb5d3d50      Exclusive_VM@41 00000000          Sstor_Host@47 00

    device_flags2@24 00000000       unit_number@15 80               bPowerState@4E 01

        rev_level@A2               queue_freeze@76 00           io_pend_count@78   00
       port_name@A6 ESDI_506        lock_count@79 00            srb_ext_size@80 0000
          q_algo@B9 01      max_sense_data_len@7F 00             unit_on_ctl@BA   00
       Vol_Flags@B8 00            access_timer@B7 00        next_ddb_dcb@6C 00000000

            dev_node@70 c2a5a9e0           inquiry_flags@82 00 00 00 00 00 00 00 00
         blocked_iop@AF 00000000        vol_unlock_timer@B3 00000000
       Port_Specific@BB c1582f40          spindown_timer@BF 00000000
        max_xfer_len@50 ffffffff       actual_sector_cnt@54 0000000000ebc9e0
      SCSI_VSD_FLAGS@7A 0000             actual_blk_size@5C 00000000
      scsi_target_id@7C 00               actual_head_cnt@60 0000000f
            scsi_lun@7D 00                actual_cyl_cnt@64 00003ffd
            scsi_hba@7E 00                    actual_spt@68 0000003f

--- DCB_BLOCKDEV (INT13) data extension -------------
  BDD_Device_SubType@C9 00           apparent_sector_cnt@D3 0000000000ebc9e0
  BDD_Int_13h_Number@CA 80             apparent_blk_size@DB 00000200
BDD_BD_Major_Version@C7 00             apparent_head_cnt@DF 000000f0
BDD_BD_Minor_Version@C8 00              apparent_cyl_cnt@E3 000003fe
           BDD_flags@CB 00000003            apparent_spt@E7 0000003f
        BDD_Name_Ptr@CF 00000000       BDD_Sync_Cmd_Proc@EB 00000000
            BDD_Next@C3 00000000        BDD_Command_Proc@EF 00000000
     BDD_Hw_Int_Proc@F3 00000000       BDP_Current_Flags@FF 00000000
BDP_Int13_Param_Ptr@103 00000000    BDP_Current_Command@107 00000000
       fastdisk_bdd@127 00000000   BDP_Current_Position@10B 000000000008adbc
 BDP_Cmd_Queue_Ascending@F7 00000000
BDP_Cmd_Queue_Descending@FB 00000000

--- DCB_disk data extension -------------------
write_precomp@12B 0000   disk_tsd_private@12D 00000000

----- DCB_ptr_cd Calldown Entry List (DCB_cd_...) -----
                              expan_ layer
At:       flagss@4  ddb@8     off@10 flags@12 ----- lgn@13 ----- io_address@0
c1582f20  00000000  c0fdef5c  ffb4   00       07         DRP_TSD disktsd:_LGROUP:tsd_request
c1579fd0  00000000  c1582ea0  ffb8   00       16     DRP_ESDI_PD esdi_506:_LDATA:ESDI_Request
c00823eb  00000000  00000000  0000   00       1f     DRP_IOS_REG %c00887bb

====================================================================================
cb5d3d50          Logical DCB
--- DCB_common area ---
    physical_dcb@00 cb5d3280   track_table_ptr@2C 00000000  apparent_blk_shift@3C 09
expansion_length@04 0000004c           bds_ptr@30 c28284dc      partition_type@3D 0b
          ptr_cd@08 c14bc860         Reserved1@34 00000000      disk_bpb_flags@45 00
        next_dcb@0C cb5d3da0              pEid@38 c1582f40              cAssoc@46 01
next_logical_dcb@10 cb5d3da0      Exclusive_VM@41 00000000          Sstor_Host@47 00
         vrp_ptr@18 c1576a30               sig@3E 4342             user_drvlet@48 ffff
       dmd_flags@1C 00000000         TSD_Flags@16 4008                   fACPI@4C 01
    device_flags@20 81204103  drive_lttr_equiv@14 02           fSpinDownIssued@4D 00
   device_flags2@24 00000000       unit_number@15 00               bPowerState@4E 01
 Partition_Start@28 0000003f       device_type@40 00                bEidLength@4F 01

----- DCB_ptr_cd Calldown Entry List (DCB_cd_...) -----
                              expan_ layer
At:       flagss@4  ddb@8     off@10 flags@12 ----- lgn@13 ----- io_address@0
c14bc860  00000000  c0fdef5c  ffb4   00       07         DRP_TSD disktsd:_LGROUP:tsd_request
c14f0540  00000000  c1582ea0  ffb8   00       16     DRP_ESDI_PD esdi_506:_LDATA:ESDI_Request
c157a010  00000000  00000000  0000   00       1f     DRP_IOS_REG %c00887bb

====================================================================================
cb5d3da0          Logical DCB
--- DCB_common area ---
    physical_dcb@00 cb5d3280   track_table_ptr@2C 00000000  apparent_blk_shift@3C 09
expansion_length@04 0000004c           bds_ptr@30 c2828572      partition_type@3D 0b
          ptr_cd@08 c14bc880         Reserved1@34 00000000      disk_bpb_flags@45 00
        next_dcb@0C cb5d3df0              pEid@38 c1582f40              cAssoc@46 01
next_logical_dcb@10 00000000      Exclusive_VM@41 00000000          Sstor_Host@47 00
         vrp_ptr@18 c159b550               sig@3E 4342             user_drvlet@48 ffff
       dmd_flags@1C 00000000         TSD_Flags@16 4008                   fACPI@4C 01
    device_flags@20 81204003  drive_lttr_equiv@14 03           fSpinDownIssued@4D 00
   device_flags2@24 00000000       unit_number@15 00               bPowerState@4E 01
 Partition_Start@28 003e862f       device_type@40 00                bEidLength@4F 01

----- DCB_ptr_cd Calldown Entry List (DCB_cd_...) -----
                              expan_ layer
At:       flagss@4  ddb@8     off@10 flags@12 ----- lgn@13 ----- io_address@0
c14bc880  00000000  c0fdef5c  ffb4   00       07         DRP_TSD disktsd:_LGROUP:tsd_request
c14f0560  00000000  c1582ea0  ffb8   00       16     DRP_ESDI_PD esdi_506:_LDATA:ESDI_Request
c1576aa0  00000000  00000000  0000   00       1f     DRP_IOS_REG %c00887bb

====================================================================================
c1572480 DDB Driver Data Block for DVT driver named esdi_506.pdr
dvt@14 c1582e40         Next_DDB@04 00000000    Next_DDB_init@08 00000000
dcb_ptr@0C cb5d3df0  devnode_ptr@18 c2a06020     number_buses@10 00
ios_flags@11 08              sig@12 4442            phys_addr@00 0000454c

--- c140a790 pAcpiBlock found in above DDB ---
tm_PIOSpeed0@00 00000000          hTaskFile@18 00000000 00000000
tm_DMASpeed0@04 00000000        dwEidLength@20 00000000 00000000
tm_PIOSpeed1@08 00000000              dwEid@28 00000000 00000000
tm_DMASpeed1@0C 00000000   dwTaskFileLength@30 00000000 00000000
    tm_Flags@10 00000000         dwTaskFile@38 00000000 00000000
bPowerState@14   01       bIdeLevel@15 00        wSig@16 5043

====================================================================================
cb5d3df0 Logical+Physical DCB (CRD-8322B       )    bus=    SCSI
--- DCB_common area ---
    physical_dcb@00 cb5d3df0   track_table_ptr@2C 00000000  apparent_blk_shift@3C 0b
expansion_length@04 000000d0           bds_ptr@30 00000000      partition_type@3D 00
          ptr_cd@08 c140a7f0         Reserved1@34 00000000      disk_bpb_flags@45 00
        next_dcb@0C 00000000              pEid@38 c1410b10              cAssoc@46 01
next_logical_dcb@10 00000000      Exclusive_VM@41 00000000          Sstor_Host@47 00
         vrp_ptr@18 00000000               sig@3E 4342             user_drvlet@48 ffff
       dmd_flags@1C 00070000         TSD_Flags@16 0000                   fACPI@4C 01
    device_flags@20 d039d004  drive_lttr_equiv@14 04           fSpinDownIssued@4D 00
   device_flags2@24 00000002       unit_number@15 04               bPowerState@4E 01
 Partition_Start@28 00000000       device_type@40 05                bEidLength@4F 01

--- DCB physical data extension ---------------------
      product_id@92 CRD-8322B         bus_type@74 01              bus_number@75   00
       vendor_id@8A COMPAQ        current_unit@AE 00         max_sg_elements@77   11
       rev_level@A2 1.03          queue_freeze@76 00           io_pend_count@78   00
       port_name@A6 ESDI_506        lock_count@79 00            srb_ext_size@80 0000
          q_algo@B9 00      max_sense_data_len@7F 0e             unit_on_ctl@BA   00
       Vol_Flags@B8 00            access_timer@B7 43        next_ddb_dcb@6C 00000000

            dev_node@70 c2a6a030           inquiry_flags@82 05 80 02 21 1f 00 00 00
         blocked_iop@AF 00000000        vol_unlock_timer@B3 00000000
       Port_Specific@BB c1410b10          spindown_timer@BF 00000000
        max_xfer_len@50 ffffffff       actual_sector_cnt@54 0000000000000000
      SCSI_VSD_FLAGS@7A 0000             actual_blk_size@5C 00000000
      scsi_target_id@7C 00               actual_head_cnt@60 00000001
            scsi_lun@7D 00                actual_cyl_cnt@64 00000001
            scsi_hba@7E 01                    actual_spt@68 00000001

--- DCB_BLOCKDEV (INT13) data extension -------------
  BDD_Device_SubType@C9 00           apparent_sector_cnt@D3 0000000000000000
  BDD_Int_13h_Number@CA 04             apparent_blk_size@DB 00000800
BDD_BD_Major_Version@C7 00             apparent_head_cnt@DF 00000000
BDD_BD_Minor_Version@C8 00              apparent_cyl_cnt@E3 00000000
           BDD_flags@CB 00000004            apparent_spt@E7 00000000
        BDD_Name_Ptr@CF 00000000       BDD_Sync_Cmd_Proc@EB 00000000
            BDD_Next@C3 00000000        BDD_Command_Proc@EF 00000000
     BDD_Hw_Int_Proc@F3 00000000       BDP_Current_Flags@FF 00000000
BDP_Int13_Param_Ptr@103 00000000    BDP_Current_Command@107 00000000
       fastdisk_bdd@127 00000000   BDP_Current_Position@10B 0000000000000001
 BDP_Cmd_Queue_Ascending@F7 00000000
BDP_Cmd_Queue_Descending@FB 00000000

--- DCB_CDROM data extension -------------------
cdrom_Partition_Start@12B 00000000                  TOC@134 cb5d3f24
  cdrom_Partition_End@12F 00000000     cd_first_session@474 00
    cd_mode_sense_buf@45C cb5d424c      cd_last_session@475 00
cd_last_session_start@48C 00000000             cd_fs_lt@486 00
cd_current_block_size@490 00000000         cd_bobbit_pt@487 00
   cd_current_command@4BC 00000000             cd_ls_ft@133 00
    play_resume_start@476 00000000        cd_queue_head@4A0 00000000
     play_resume_stop@47A 00000000          play_status@47E 00000000
      cd_device_flags@482 00001400             cd_fs_lo@488 00000000
           cd_vol_map@494 01 ff 02 ff 00 00 00 00

----- DCB_ptr_cd Calldown Entry List (DCB_cd_...) -----
                              expan_ layer
At:       flagss@4  ddb@8     off@10 flags@12 ----- lgn@13 ----- io_address@0
c140a7f0  00070000  00000000  ff30   00       05      DRP_VOLTRK voltrack:_LGROUP:vol_request
c1576b50  00070000  00000000  ff30   00       06   DRP_CLASS_DRV cdtsd:_LGROUP:tsd_request
c1576b30  00070008  c1401fb0  ff30   00       0d       DRP_VSD_5 cdvsd:.bss:VSD_Request
c15120c0  00000000  c1576b20  ff94   00       0f       DRP_VSD_7 scsi1hlp:_LGROUP:HLP_request
c15120e0  00000000  c1572480  ffb8   00       16     DRP_ESDI_PD esdi_506:_LDATA:ESDI_Request
c00823eb  00000000  00000000  0000   00       1f     DRP_IOS_REG %c00887bb

====================================================================================
c1579080 DVT: ascii_name@14[scsiport.pdr    ]   current_lgn@44[15]         DRP_NT_PD
rev_level@34[    ]   create_date@24[        ]   create_time@2C[        ]

ddb@0C[00000000]  next_dvt@02[c1580eb0]  ddb_init@10[00000000]

     device_cnt@06 0000      feature_code@38 00000000
     init_count@4F 00     if_requirements@3C 0000
       bus_type@3E 01      reference_data@3F 00000000
    first_drive@43 00          LoadHandle@45 c1580be0
scsi_max_target@49 01         entry_point@4B 00000000
   scsi_max_lun@4A 00                 aer@08 00000000 (%00000000)

====================================================================================
c1580eb0 DVT: ascii_name@14[aic78xx.mpd     ]   current_lgn@44[14]        DRP_NT_MPD
rev_level@34[Requ]   create_date@24[__VCOMM_]   create_time@2C[Dequeue_]

ddb@0C[cbbd4000]  next_dvt@02[c14c1af0]  ddb_init@10[00000000]

     device_cnt@06 0000      feature_code@38 00000040
     init_count@4F 01     if_requirements@3C 0000
       bus_type@3E 01      reference_data@3F c1410ab0
    first_drive@43 5f          LoadHandle@45 c1579120
scsi_max_target@49 0f         entry_point@4B c2a5bfe0
   scsi_max_lun@4A 07                 aer@08 c15807a4 (scsiport:.data:Async_Event_Handler)

====================================================================================
cbbd4000 DDB Driver Data Block for DVT driver named aic78xx.mpd
dvt@14 c1580eb0         Next_DDB@04 00000000    Next_DDB_init@08 00000000
dcb_ptr@0C 00000000  devnode_ptr@18 c29fc700     number_buses@10 01
ios_flags@11 0a              sig@12 4442            phys_addr@00 00fbd000

====================================================================================
c14c1af0 DVT: ascii_name@14[bigmem.drv      ]   current_lgn@44[12]      DRP_RESRVD18
rev_level@34[    ]   create_date@24[ (      ]   create_time@2C[ i      ]

ddb@0C[00000000]  next_dvt@02[c14b23c0]  ddb_init@10[00000000]

     device_cnt@06 0000      feature_code@38 00000000
     init_count@4F 00     if_requirements@3C 0000
       bus_type@3E 00      reference_data@3F 00000000
    first_drive@43 a2          LoadHandle@45 c14f0580
scsi_max_target@49 27         entry_point@4B 031a0102
   scsi_max_lun@4A 00                 aer@08 c14bc8ac (%c14bc8ac)

====================================================================================
c14b23c0 DVT: ascii_name@14[scsi1hlp.vxd    ]   current_lgn@44[0f]         DRP_VSD_7
rev_level@34[%Zel]   create_date@24[@0$pT ?_]   create_time@2C[  D6Vru ]

ddb@0C[00000000]  next_dvt@02[c148e3d0]  ddb_init@10[00000000]

     device_cnt@06 0000      feature_code@38 00000000
     init_count@4F 00     if_requirements@3C 0000
       bus_type@3E 00      reference_data@3F 00000000
    first_drive@43 0d          LoadHandle@45 c14c90a0
scsi_max_target@49 4e         entry_point@4B 3f6e2b8b
   scsi_max_lun@4A fe                 aer@08 c14f012c (%c14f012c)

====================================================================================
c148e3d0 DVT: ascii_name@14[cdvsd.vxd       ]   current_lgn@44[0e]         DRP_VSD_6
rev_level@34[cFpb]   create_date@24[- eo6~  ]   create_time@2C[v  WD0  ]

ddb@0C[00000000]  next_dvt@02[c14c1bb0]  ddb_init@10[00000000]

     device_cnt@06 0000      feature_code@38 00004000
     init_count@4F 00     if_requirements@3C 0000
       bus_type@3E 00      reference_data@3F 00000000
    first_drive@43 0c          LoadHandle@45 c14f4080
scsi_max_target@49 e6         entry_point@4B 26ffef26
   scsi_max_lun@4A 2d                 aer@08 c14f2a40 (cdvsd:.bss:async_request)

====================================================================================
c14c1bb0 DVT: ascii_name@14[cdvsd.vxd       ]   current_lgn@44[0d]         DRP_VSD_5
rev_level@34[    ]   create_date@24[ B      ]   create_time@2C[0       ]

ddb@0C[00000000]  next_dvt@02[c14f06b0]  ddb_init@10[00000000]

     device_cnt@06 0000      feature_code@38 00004000
     init_count@4F 00     if_requirements@3C 0000
       bus_type@3E 00      reference_data@3F 00000000
    first_drive@43 0d          LoadHandle@45 c14f4080
scsi_max_target@49 0d         entry_point@4B 00271268
   scsi_max_lun@4A 01                 aer@08 c14f2a40 (cdvsd:.bss:async_request)

====================================================================================
c14f06b0 DVT: ascii_name@14[apix.vxd        ]   current_lgn@44[0b]    DRP_SCSI_LAYER
rev_level@34['   ]   create_date@24[l       ]   create_time@2C[#       ]

ddb@0C[00000000]  next_dvt@02[c1575550]  ddb_init@10[00000000]

     device_cnt@06 0000      feature_code@38 00000000
     init_count@4F 00     if_requirements@3C 0000
       bus_type@3E 00      reference_data@3F 00000000
    first_drive@43 9c          LoadHandle@45 c14c6ce0
scsi_max_target@49 00         entry_point@4B 1b9c7803
   scsi_max_lun@4A 02                 aer@08 c14c8dd0 (%c14c8dd0)

====================================================================================
c1575550 DVT: ascii_name@14[                ]   current_lgn@44[07]           DRP_TSD
rev_level@34[    ]   create_date@24[p_WA    ]   create_time@2C[        ]

ddb@0C[00000000]  next_dvt@02[c15754f0]  ddb_init@10[00000000]

     device_cnt@06 0000      feature_code@38 00000000
     init_count@4F 00     if_requirements@3C 0000
       bus_type@3E 00      reference_data@3F 00000000
    first_drive@43 c1          LoadHandle@45 dfc15755
scsi_max_target@49 6d         entry_point@4B 01b7f44b
   scsi_max_lun@4A f3                 aer@08 c00a2348 (%c00a2348)

====================================================================================
c15754f0 DVT: ascii_name@14[                ]   current_lgn@44[07]           DRP_TSD
rev_level@34[    ]   create_date@24[p_WA    ]   create_time@2C[        ]

ddb@0C[00000000]  next_dvt@02[c14b2420]  ddb_init@10[00000000]

     device_cnt@06 0000      feature_code@38 00000000
     init_count@4F 00     if_requirements@3C 0000
       bus_type@3E 00      reference_data@3F 00000000
    first_drive@43 c1          LoadHandle@45 c3c15758
scsi_max_target@49 0b         entry_point@4B 01b7f5b3
   scsi_max_lun@4A 65                 aer@08 c009c330 (vfat:_LDATA:VFAT_async_event)

====================================================================================
c14b2420 DVT: ascii_name@14[disktsd.vxd     ]   current_lgn@44[07]           DRP_TSD
rev_level@34[ZAy2]   create_date@24[>1 u th ]   create_time@2C[j-HN1Z1I]

ddb@0C[c0fdef5c]  next_dvt@02[c146d320]  ddb_init@10[c0fdef5c]

     device_cnt@06 0000      feature_code@38 00000000
     init_count@4F 00     if_requirements@3C 0000
       bus_type@3E 00      reference_data@3F 00000000
    first_drive@43 f1          LoadHandle@45 c14f4440
scsi_max_target@49 24         entry_point@4B 2f419e6e
   scsi_max_lun@4A 79                 aer@08 c14f417c (%c14f417c)

====================================================================================
c0fdef5c DDB Driver Data Block for DVT driver named disktsd.vxd
dvt@14 c14b2420         Next_DDB@04 00000000    Next_DDB_init@08 00000000
dcb_ptr@0C 00000000  devnode_ptr@18 00000000     number_buses@10 00
ios_flags@11 00              sig@12 4442            phys_addr@00 00feef5c

====================================================================================
c146d320 DVT: ascii_name@14[                ]   current_lgn@44[07]           DRP_TSD
rev_level@34[%`^]   create_date@24[V8$P 'w}]   create_time@2C[ v jPn !]

ddb@0C[00000000]  next_dvt@02[c148e430]  ddb_init@10[00000000]

     device_cnt@06 0000      feature_code@38 00000000
     init_count@4F 00     if_requirements@3C 0000
       bus_type@3E 00      reference_data@3F 00000000
    first_drive@43 15          LoadHandle@45 63bec8b1
scsi_max_target@49 3e         entry_point@4B da47e706
   scsi_max_lun@4A ab                 aer@08 c00c7418 (%c00c7418)

====================================================================================
c148e430 DVT: ascii_name@14[cdtsd.vxd       ]   current_lgn@44[06]     DRP_CLASS_DRV
rev_level@34[  l ]   create_date@24[D@r} t  ]   create_time@2C[/ j  Z|y]

ddb@0C[00000000]  next_dvt@02[c1572200]  ddb_init@10[00000000]

     device_cnt@06 0000      feature_code@38 00000000
     init_count@4F 00     if_requirements@3C 0000
       bus_type@3E 00      reference_data@3F 00000000
    first_drive@43 37          LoadHandle@45 c14eff50
scsi_max_target@49 0e         entry_point@4B 054a16bf
   scsi_max_lun@4A 01                 aer@08 c14c7d6c (cdtsd:_LGROUP:tsd_async_event)

====================================================================================
c1572200 DVT: ascii_name@14[                ]   current_lgn@44[05]        DRP_VOLTRK
rev_level@34[    ]   create_date@24[P "Bt   ]   create_time@2C[        ]

ddb@0C[00000000]  next_dvt@02[c148e490]  ddb_init@10[00000000]

     device_cnt@06 0000      feature_code@38 00002000
     init_count@4F 00     if_requirements@3C 0000
       bus_type@3E 00      reference_data@3F 00000000
    first_drive@43 c2          LoadHandle@45 d0000000
scsi_max_target@49 d0         entry_point@4B 000000c1
   scsi_max_lun@4A 85                 aer@08 c008cd80 (%c008cd80)

====================================================================================
c148e490 DVT: ascii_name@14[cdfs.vxd        ]   current_lgn@44[05]        DRP_VOLTRK
rev_level@34[ u1H]   create_date@24[ I(KE:~ ]   create_time@2C[   Oy ^]

ddb@0C[00000000]  next_dvt@02[c14c1c20]  ddb_init@10[00000000]

     device_cnt@06 0000      feature_code@38 00002000
     init_count@4F 00     if_requirements@3C 0000
       bus_type@3E 00      reference_data@3F 00000000
    first_drive@43 36          LoadHandle@45 c14f1e70
scsi_max_target@49 53         entry_point@4B 2c906009
   scsi_max_lun@4A 01                 aer@08 c14f1810 (cdfs:_LGROUP:_CDFSAsyncEvent)

====================================================================================
c14c1c20 DVT: ascii_name@14[voltrack.vxd    ]   current_lgn@44[05]        DRP_VOLTRK
rev_level@34[    ]   create_date@24[z       ]   create_time@2C[        ]

ddb@0C[00000000]  next_dvt@02[c15759a0]  ddb_init@10[00000000]

     device_cnt@06 0000      feature_code@38 00002000
     init_count@4F 00     if_requirements@3C 0000
       bus_type@3E 00      reference_data@3F 00000000
    first_drive@43 00          LoadHandle@45 c14f0390
scsi_max_target@49 03         entry_point@4B 04002703
   scsi_max_lun@4A ca                 aer@08 c14f5440 (voltrack:_LGROUP:vol_async_event)

====================================================================================
c15759a0 DVT: ascii_name@14[                ]   current_lgn@44[02]           DRP_FSD
rev_level@34[    ]   create_date@24[        ]   create_time@2C[        ]

ddb@0C[00000000]  next_dvt@02[00000000]  ddb_init@10[00000000]

     device_cnt@06 0000      feature_code@38 00002000
     init_count@4F 00     if_requirements@3C 0000
       bus_type@3E 00      reference_data@3F 00000000
    first_drive@43 00          LoadHandle@45 f51a3a40
scsi_max_target@49 01         entry_point@4B ff000000
   scsi_max_lun@4A 02                 aer@08 c0078ffc (%c0078ffc)

1##


Supplemental Tables

The following topics include information related to SRB functions and IOS inquiries.


SRB Functions

Value | Element | Comments
x00 | SRB_FUNCTION_EXECUTE_SCSI | A SCSI device I/O request should be executed on the target logical unit.
0x01 | SRB_FUNCTION_CLAIM_DEVICE | The port driver processes this request without calling the miniport driver.
0x02 | SRB_FUNCTION_IO_CONTROL | (Supported in Windows NT IOCTL mechanism.) The request is an I/O control request. The SRB DataBuffer points to an SRB_IO_CONTROL header followed by the data area. The value in DataBuffer can be used by the driver, regardless of the value of MapBuffers field. If the HBA miniport driver supports this request, it should execute the request and notify the OS-specific port driver when it has completed it, using the normal mechanism of ScsiPortNotification with RequestComplete and NextRequest. Only the Function, SrbFlags, TimeOutValue, DataBuffer, DataTransferLength and SrbExtension are valid.
0x03 | SRB_FUNCTION_RECEIVE_EVENT | (Defined for future versions.) The HBA should be prepared to receive an Asynchronous Event Notification from the addressed target. The DataBuffer indicates where the data should be placed.
0x04 | SRB_FUNCTION_RELEASE_QUEUE | The port driver processes this request without calling the miniport driver.
0x05 | SRB_FUNCTION_ATTACH_DEVICE | The port driver processes this request without calling the miniport driver.
0x06 | SRB_FUNCTION_RELEASE_DEVICE | The port driver processes this request without calling the miniport driver.
0x07 | SRB_FUNCTION_SHUTDOWN | The system is being shut down. The request is passed to the miniport driver if CachesData was set to TRUE in the PORT_CONFIGURATION_INFORMATION data. The miniport driver can receive several of these notifications before all system activity is actually stopped; however, the last shutdown notification will occur after the last start I/O. Only the Function, PathId, TargetId and Lun fields are valid.
0x08 | SRB_FUNCTION_FLUSH | The miniport should flush any cached data for the device. The request is passed to the miniport driver if CachesData is TRUE in the PORT_CONFIGURATION_INFORMATION data. Only the Function, PathId, TargetId and Lun fields are valid.
0x10 | SRB_FUNCTION_ABORT_COMMAND | A SCSIMESS_ABORT message should be sent to cancel the request pointed to by the NextSrb field. If this is tagged queue request, then a SCSIMESS_ABORT_WITH_TAG message should be used. If the indicated request has been completed, this request should be completed normally. Only the Function, PathId, TargetId, Lun, and NextSrb fields are valid.
0x11 | SRB_FUNCTION_RELEASE_RECOVERY | (Defined for future versions.) A SCSIMESS_RELEASE_RECOVERY message should be sent to the target controller. Only the Function, PathId, TargetId and Lun fields are valid.
0x12 | SRB_FUNCTION_RESET_BUS |
0x13 | SRB_FUNCTION_RESET_DEVICE | (Defined for future versions.) The SCSI target controller should be reset using the SCSIMESS_BUS_DEVICE_RESET message. The HBA miniport driver should complete any active requests for the target controller. Only the Function, TargetId and PathId fields are valid.
0x14 | SRB_FUNCTION_TERMINATE_IO | (Defined for future versions.) A SCSIMESS_TERMINATE_IO_PROCESS message should be sent to cancel the request pointed to by the NextSrb field. If the indicated request has already completed, this request should be completed normally. Only the Function, PathId, TargetId, Lun, and NextSrb fields are valid.
0x15 | SRB_FUNCTION_FLUSH_QUEUE | The port driver processes this request without calling the miniport driver.
0x16 | SRB_FUNCTION_REMOVE_DEVICE |


IOS Inquiry Type Table.

This table (inquiry_type_table) is used by IOS to know how to process the various devices detected by SCSI or non-SCSI device inquiries.

When IOS creates a DCB , it uses the "DCB size" column to determine how much space to allocate for the DCB.

Value | SCSI Inquiry Type | DCB style | DCB size | SECTOR SIZE (BYTES) | Queue type
0 | SCSI_DASD_TYPE (hard disk) | DCB_type_disk | size DCB_disk | 512 | DCB_q_sort
1 | SCSI_SEQUENTIAL_TYPE | DCB_TYPE_TAPE | size DCB | 1 | DCB_q_fi_fo
2 | SCSI_PRINTER_TYPE | DCB_type_printer | size DCB_disk | 1 | DCB_q_fi_fo
3 | SCSI_PROCESSOR_TYPE | DCB_type_processor | size DCB | 1 | DCB_q_fi_fo
4 | SCSI_WORM_TYPE | DCB_type_worm | size DCB | 1 | DCB_q_sort
5 | SCSI_CDROM_TYPE | DCB_type_cdrom | size DCB_cdrom | 2048 | DCB_q_fi_fo
6 | SCSI_SCANNER_TYPE | DCB_type_scanner | size DCB | 1 | DCB_q_fi_fo
7 | SCSI_OPTICAL_TYPE | DCB_type_disk | size DCB | 512 | DCB_q_fi_fo
8 | SCSI_MEDIACHANGER_TYPE | DCB_type_changer | size DCB | 1 | DCB_q_fi_fo
1D | REAL_MAPPER_TYPE | DCB_type_disk | size DCB_disk | 512 | DCB_q_sort
1E | SCSI_FLOPPY_TYPE | DCB_type_floppy | size DCB_floppy | 512 | DCB_q_sort
1F | (all others / unknown) | DCB_type_disk | size DCB_disk | 1 | DCB_q_fi_fo


IOS Drive Locking

The following topics provide information about the drive-locking mechanism that IOS provides.


LOCKCD Demonstration

Summary

Demonstrates the use of the drive locking mechanism provided by IOS, which is used to provide exclusive access to a removable media storage device. Exclusive access prevents any other processes from interfering with the operations on that drive. Included are the necessary VxD source files as well as a simple C console application to exercise the code. This is a combination of C and 386 assembler code.

Building the Sample

To build the sample, you must have Visual C++ or Visual Studio installed. Run the nmake command in the root sample directory (i.e. C:\NTDDK\SRC\WIN_ME\STORAGE\LOCKCD). You must use one of the two shortcuts within the DDK Start menu (Build Environment, Checked or Free) to ensure proper environment variable settings. Once built, this sample will create one executable: lockcd.exe and its VxD, ldvxd.vxd. The VXD file must be in the same directory as the executable at run time.

Code Tour

File Manifest

File | Description
App\Ld.c | Main code base for simple demonstration.
App\Ld.h | Private header file.
INC\Ldif.h | Public interface for the VxD.
INC\Ldif.inc | ASM include file for previous.
VxD\LdIOCtl.c | Sample C interface to CD for demo VxD.
VxD\LdIOS.asm | Assembler code for IOS interface.
VxD\LdVxD.asm | Assembler code for VxD interface.
LockCD.rc | Simple resource file for .EXE.
LDVXD.rc | Simple resource file for .VxD.
LDVXD.def | Definition file for the assembler.
Makefile | Makefile.

The LdVxD directory contains all the code to interface to the IOS routines for manipulating the lock mechanisms on a CDROM drive. This is generic code and may be used as a standard CDROM interface for any application, but other device types may require modification to these files.

The main code base for the sample application (Ld.c and Ld.h) is meant to show one interpretation of how to use the locking mechanisms in a simple wrapper. The locking mechanism itself is intended mostly for removable read/write media such as a CD-R/W, but this demo application accesses the first local CDROM drive to exercise the functionality without forcing the user to have special equipment beyond a simple CDROM drive. Note that any removable media is supported by the IOS itself, even a floppy disk drive, so one must merely decide how elaborate to make the supporting VxD.

Functions

The lowest level IOS routines offer several functions to use for the purpose of selectively controlling the locks on removable media devices.

  • _IOS_LockDrive ; call IOS to lock the specified drive
  • _IOS_UnlockDrive ; call IOS to unlock the specified drive
  • _IOS_IsDriveLocked ; call IOS to query the lock status

These in turn are used in this demo in the source file ldios.asm. Within this file there are four functions of concern:

  • LD_LockDrive
  • LD_UnlockDrive
  • LD_IsDriveLocked
  • LD_RefreshLock

Because the IOS locking mechanism has a safety timeout to avoid deadlocks from dead processes or other faults, LD_RefreshLock allows you to refresh the locking mechanism to hold the lock when necessary. This function calls the IOS locking routine with an empty parameter, effectively resetting the timer without otherwise modifying the state of the lock.

Even if you only need to write C code, you will still need to use the included ASM files as well as at least part of LdIOCtl.c and Ldif.h as your coupling into the IOS library. If you choose to modify or rewrite the ASM files, be sure to follow all of the IOS routine access rules in addition to understanding the functions specific to this demo.

Because the IOS locking mechanism has a safety timeout to avoid deadlocks from dead processes or other faults, LD_RefreshLock allows you to refresh the locking mechanism to hold the lock when necessary. This function calls the IOS locking routine with an empty parameter, effectively resetting the timer without otherwise modifying the state of the lock.

Even if you only need to write C code, you will still need to use the included ASM files as well as at least part of LdIOCtl.c and Ldif.h as your coupling into the IOS library. If you choose to modify or rewrite the ASM files, be sure to follow all of the IOS routine access rules in addition to understanding the functions specific to this demonstration.


IOS Drive Locking Functions

IOS uses the following functions in drive-locking operations. These functions are briefly described in the following topics.

  • _IOS_IsDriveLocked
  • _IOS_LockDrive
  • _IOS_UnlockDrive


_IOS_IsDriveLocked

Summary

This service checks the specified drive to see if it is locked for exclusive access.

Entry/Exit

The service expects the drive number as the parameter passed in (TOS+4) and will return, in EAX, either a zero or a non-zero. Zero signifies not locked, and non-zero indicates there is a lock.

Note Drive numbering starts with zero for drive letter A: and counts up from there. If you are checking drive F: for instance, you should pass in a five.

Usage

This service function is used to check a drive whose lock state locked is unknown, and will detect if a drive has been locked using _IOS_LockDrive. The return value indicates locked or unlocked with non-zero and zero respectively.

This service uses (writes to) EAX, ECX, EDX, and Flags.

See Also

IOS_LockDrive, IOS_UnlockDrive, LockCD Demo


_IOS_UnlockDrive

Summary

This service unlocks the specified drive if it was locked for exclusive access using _IOS_LockDrive.

Entry/Exit

The service expects the entry point previously provided by the _IOS_LockDrive service as the parameter passed in (TOS+4) and will return in EAX either a zero on success or non-zero if unlocking failed.

Usage

This service function is used to unlock a drive previously (and successfully) locked with _IOS_LockDrive, and uses the passed value to search for a lock descriptor. The return value indicates success or failure. Failure occurs when the service cannot find a valid lock descriptor, which usually means there is no locked drive.

If the function succeeds it will also cancel the lock timeout timer previously set running by _IOS_LockDrive.

This service uses (writes to) EAX, ECX, EDX, and Flags.

See Also

IOS_IsDriveLocked, IOS_LockDrive, LockCD Demo


FAQ for Installing Your Driver on Windows Millennium

  1. Q: Where can I get more information about creating INFs for Windows® Millennium?

    A: See the Windows Me INF Guide. Also refer to the Windows 95 documentation included with this DDK.

  2. Q: I want to disable version checking and always copy my file. How can I do this?

    A: This is set by a flag in a CopyFile section. See Copy Files (CopyFiles).

  3. Q: I want to copy a file only if it does not exist on a user's system. How can I do this?

    A: Please see Question 2.

  4. Q: How do I avoid overwriting critical system files?

    A: Microsoft has a new feature, System File Protection (SFP) specifically designed to prevent overwriting shared system files. See Protection for System Files.

  5. Q: What files are protected under SFP?

    A: See Protection for System Files.

  6. Q: How do I disable System File Protection.

    A: System File Protection (SFP) cannot be disabled.

  7. Q: How do I write an INF file to install a WDM Driver on both Windows® 2000 and Windows Me?

    A: Please see the example in Writing a Cross Platform INF to Install USB Printer Drivers.

  8. Q: Where can I get a list of install directories or Logical Disk Identifiers (LDIDs)?

    A: Check the DestinatonDirs section in the Windows Me INF Guide.

  9. Q: How can I get my drivers signed?

    A: See Driver Signing


Windows Me INF Guide

Previous Next

Windows Me INF File Guide

This section includes basic information about INF files for Microsoft® Windows® 95/98/Me.

A basic INF file will have the following sections (more complex INF files will have additional sections). Bold section names are actual keywords. Italicized section names are arbitrary names created by the author of the INF file:

Section | Description
[Version] | Basic version information for validating the INF file.
[DefaultInstall] | Installation section that is executed by default. Has pointers to other sections specifying, for example, what files to copy and delete, registry updates, and .ini file updates.
[OtherInstall] | Uses same format as [DefaultInstall] section, but must be explicitly called. Useful for defining how a component should be uninstalled.
[DestinationDirs] | Specifies the location on the hard drive where a section's files will be copied, deleted or renamed (for example, Windows dir or Windows\System dir.)
[OptionalComponents] | Lists Install sections that are displayed when the user selects the INF file from the "Have Disk…" button during Windows Setup.
[FileCopy/Delete/RenameSection] | Lists files to be copied, deleted or renamed.
[RegistryUpdateSection] | Specifies registry additions or deletions.
[IniFileUpdateSection] | Specifies updates to .ini files. Links are created in this section.
[SourceDisksNames] | Lists disks that contain the files.
[SourceDisksFiles] | Lists the specific disk where each file is located.
[Strings] | Lists localizable strings used above.


Install Sections

[install-section-name]

Identifies the additional sections in the INF file that contain installation information for the component. The additional sections are:

Version
=version-section

CopyFiles
=file-list-section[,file-list-section]...

RenFiles
=file-list-section[,file-list-section]...

DelFiles
=file-list-section[,file-list-section]...

UpdateInis
=update-ini-section[,update-ini-section]...

UpdateIniFields
=update-inifields-section[,update-inifields-section]...

AddReg
=add-registry-section[,add-registry-section]...

DelReg
=del-registry-section[,del-registry-section]...

Ini2Reg
=ini-to-registry-section[,ini-to-registry-section]...

UpdateCFGSys
=update-config-section

UpdateAutoBat
=update-autoexec-section

Not all of these sections are required in an Install section. If an item type is used, it must specify the name of a section in the INF file. (An exception to this is the CopyFiles item, which may use the "@" character along with a file name to copy a single file without specifying a section name.) The section name must consist of printable characters.

Only one of each type of item can be used in any one Install section. More than one section name can be listed in an item, but each additional name must be preceded with a comma.

If this section is named [DefaultInstall], it will execute when you right click the INF file and select Install. This section also is executed in the Cabpack wizard when you select an INF file as the setup option.

This example shows a typical Install section. It contains CopyFiles and AddReg items that identify the sections containing information about which files to install.

[MyApplication]
CopyFiles=MyAppWinFiles, MyAppSysFiles, @SRSutil.exe
AddReg=MyAppRegEntries

The CopyFiles item provides a special notation that will allow a single file to be copied directly from the copy line. An individual file can be copied by prefixing the file name with an @ symbol. The destination for any file copied using this notation will be the DefaultDestDir as defined in the DestinationDirs section. The following example shows how to copy individual files:

CopyFiles=FileSection1, @myfile.txt,@anotherfile.txt,LastSectionName


Version

[Version]
Signature="$Chicago$"
LayoutFile=filename.inf

Defines the standard header for all Windows Me INF files. Note that if the signature is not $Chicago$ then Windows Me will not accept the INF file as an INF file for any of the classes of devices recognized by Windows Me.

Note that the signature string recognition is case-insensitive. So, for example, you can use either $Chicago$ or $CHICAGO$.

filename.inf
Names the INF file that contains the layout information (source disks and files) required to install this component. This line is optional. If not given, the SourceDisksNames and SourceDisksFiles sections must be given in this INF.

This example shows a typical Version section:

[Version]
Signature="$Chicago$"


Copy Files (CopyFiles)

[CopyFiles-section-name]
destination-file-name[, source-file-name][, temporary-file-name][,flag]

Lists the names of files to be copied from a source disk to a destination directory. The source disk and destination directory associated with each file are specified in other sections of the INF file. The file-list-section name must appear in the CopyFiles item of an Install section.

destination-file-name
Name of the destination file. If no source file name is given, this is also the name of the source file.
source-file-name
Name of the source file. If the source and destination file names for the file copy operation are the same, this is not required.
temporary-file-name
Name of a temporary file for the file copy operation. The installer copies the source file but gives it the temporary file name. The next time the operating system starts, it renames the temporary file to the destination file name. This is useful for copying files to a destination that is currently open or in use by Windows.
flag
Optional parameter used to perform special actions during the installation process. Multiple flags can be used by adding the values to create the combined flag. The following valid flags can be used:
Flag | Description
1 On CopyFiles: Warn if user tries to skip file.
1 On DelFiles | If file is in use, queue up delayed delete in wininit.ini. Otherwise an in-use file will not be deleted.
2 Setup Critical: Don't allow user to skip file.
4 Ignore version check and always copy file. | This will overwrite a newer file.
8 Force Rename (trick engine into thinking that file is in use) | Only happens if file already exists on target.
16 | If file already exists on target, do not copy.
32 | Suppress version conflict dialog and do not overwrite newer files.

This example copies three files:

[CopyTheseFilesSec]
file11 ; copies file11
file21, file22, file23 ; copies file22, temporarily naming it file23
file31, file32 ; copies file32 to file31

All the source file names used in this example must be defined in a SourceDisksFiles section and the logical disk numbers that appear in the SourceDisksFiles section must have been defined in a SourceDisksNames section. As an alternative, you can use a layout.inf file to supply this information.

Note that you can specify the copying of a single file in the CopyFiles item of the Install section itself, without building a CopyFiles section. To do this, use the special character "@" to force a single file copy. For example:

[MyApplication]
CopyFiles=MyAppWinFiles, MyAppSysFiles, @SRSutil.exe

When a single file is copied in this way, the source and destination file names must be the same and you cannot use a temporary file.


Rename Files (RenFiles)

[rename-files-section-name]
new-file-name, old-file-name

Lists the names of files to be renamed. The name of the section must appear in a Renfiles item in an Install section of the INF file.

new-file-name
New name of the file.
old-file-name
Old name of the file.

This example renames the files file42 to file41, file52 to file51, and file62 to file61:

[RenameOldFilesSec]
file41, file42
file51, file52
file61, file62

All the old file names used in this example (file42, file52, and file62) must be defined in a SourceDisksFiles section and the logical disk numbers that appear in the SourceDisksFiles section must have been defined in a SourceDisksNames section.


Delete Files (DelFiles)

[file-list-section]
file-name[,,,flag]

A DelFiles section lists the names of files to be deleted. The file-list-section name must appear in the Delfiles item of an Install section.

file-name

Identifies a file to be deleted.

flag

Optional parameter used to force Windows Me to delete the file named in the item if it is in use during the installation process. Set the flag parameter value to 1 to cause Windows 95 to queue the file deletion operation until the system has restarted. If a file marked with the flag=1 parameter setting cannot be deleted because it is in use, a system restart will occur after the device installation is complete.

If you do not use the flag parameter value equal to 1 along with a file-name parameter, and if that file is in use when the DelFiles section is executed, that file will not be deleted from the system.

This example deletes three files:

[DeleteOldFilesSec]
file1
file2
file3


Update INI File (UdpdateInis)

Previous Next

Update INI File (UpdateInis)

[update-ini-section-name]
ini-file, ini-section, [old-ini-entry], [new-ini-entry], [flags]

Replaces, deletes, or adds complete entries in the given INI file. The section name, update-ini-section-name, must appear in the UpdateInis item in an Install section of the INF file.

ini-file
Name of the INI file containing the entry to change. For more information about specifying the INI file name, see the comments below.
ini-section
Name of the section containing the entry to change.
old-ini-entry
Optional. Usually in the form Key=Value.
new-ini-entry
Optional. Usually in the form Key=Value. Either the key or value may specify replaceable strings. For example, either the key or value specified in the new-ini-entry parameter may be %String1%, where the string that replaces %String1% is defined in the Strings section of the INF file.
flags
Optional action flags. Can be one of these values:
Value | Description
0 Default. If old-ini-entry key is present in an INI file entry, that entry is replaced with new-ini-entry. Note that only the keys of the old-ini-entry parameter and the INF file entry must match, the value of each entry is ignored.

To add new-ini-entry to the INI file unconditionally, set old-ini-entry to NULL. To delete old-ini-entry from the INI file unconditionally, set new-ini-entry to NULL.
1 | If both key and value of old-ini-entry exist in an INI file entry, that entry is replaced with new-ini-entry. Note that the old-ini-entry parameter and the INF file entry must match on both key and value for the replacement to be made (this is in contrast to using an action flag value of 0, where only the keys must match for the replacement to be made).
2 If the key in the old-ini-entry parameter does not exist in the INI file, then no operation is performed on the INI file.

If the key in the old-ini-entry parameter exists in an INI file entry and the key in the new-ini-entry parameter does not exist in an INI file entry, then an entry is added to the INI file made up of the key in the new-ini-entry parameter and the old value.

Note that the match of the old-ini-entry parameter and an INI file entry is based on key alone, not key and value.
3 | Same as flag parameter value of 2 described above, except match of the old-ini-entry parameter and an entry in the INF file is based on matching both key and value, not just the key.

The wildcard character (*) can be used in specifying the key and value and they will be interpreted correctly.

The .ini file name can be a string or a strings key. A strings key has the form %strkey% where strkey is defined in the Strings section in the INF file. In either case, the name must be a valid file name.

The name should include the name of the directory containing the file, but the directory name should be given as a logical directory identifier (LDID) rather than an actual name. The installer replaces an LDID with an actual name during installation.

An LDID has the form %ldid% where ldid is one of the predefined identifiers or an identifier defined in the DestinationDirs section. Note that when the constants LDID_BOOT and LDID_BOOTHOST are replaced, the backslash is included in the path. For example LDID_BOOT may be replaced with C:\. However, in your INF file the backslash character is optional. For example, either "%30%boot.ini" and "%30%\boot.ini" can be used to reference boot.ini in the root of the boot drive.

The following examples illustrate individual items in an Update INI File section of an INF file:

%11%\sample.ini, Section1,, Value1=2 ; adds new entry
%11%\sample.ini, Section2, Value3=*, ; deletes old entry
%11%\sample.ini, Section4, Value5=1, Value5=4 ; replaces old entry

The following set of items in an Update INI File-type section of an INF file work together to operate on the Boot section of system.ini. The conditionality built into the flags parameter of the INF file items is used to add the entry "comm.drv=comm.drv" to the Boot section unless the entries "comm.drv=*vcoscomm.drv" or "comm.drv=*r0dmdcom.drv" exist in the Boot section, in which case the existing entry is preserved and the entry "comm.drv=comm.drv" is not added to the INI file. In other words, after the four INF file entries shown below are executed, there will be one "comm.drv=" entry in the Boot section of the INI file: "comm.drv=*vcoscomm.drv" or "comm.drv=*r0dmdcom.drv" or "comm.drv=comm.drv."

system.ini, boot, "comm.drv=*vcoscomm.drv","~CommDrvTemp~=*", 3
system.ini, boot, "comm.drv=*r0dmdcom.drv","~CommDrvTemp~=*", 3
system.ini, boot,,"comm.drv=comm.drv"
system.ini, boot, "~CommDrvTemp~=*","comm.drv=*", 3


Update INI Fields (UpdateIniFields)

[update-inifields-section-name]
ini-file, ini-section, profile-name, [old-field], [new-field],[flags]

Replaces, adds, and deletes fields in the value of a given INI entry. Unlike the Update INI File section type, this type of section replaces, adds, or deletes portions of a value in an INI file entry rather than the whole value. The section name, update-inifields-section-name, must appear in the UpdateIniFields item in an Install section of the INF file.

ini-file
Name of the INI file containing the entry to change. For more information about specifying the INI file name, see the topic that describes the Update INI File section type.
ini-section
Name of the INI file section containing the entry to change.
profile-name
Name of the entry to change.
old-field
Field value to delete.
new-field
Field value to add, if not already there.
flags
Specifies whether to treat the old-field and new-field parameters as if they have a wildcard character or not and/or what separator character to use when appending a new field to an INI file entry. Can be any of these values:
Value | Meaning
0 | Default. Treat "*" character literally when matching fields, and not as a wildcard character. Use blank (" ") as a separator when adding a new field to an entry.
1 | Treat "*" character as a wildcard character when matching fields. Use blank (" ") as a separator when adding a new field to an entry.
2 | Treat "*" character literally when matching fields, and not as a wildcard character. Use comma (",") as a separator when adding a new field to an entry.
3 | Treat "*" character as a wildcard character when matching fields. Use comma (",") as a separator when adding a new field to an entry.

Any comments in the INI file line are removed as they might not be applicable after changes. When looking for fields in the line in the INI file, spaces, tabs and commas are used as field delimiters. However, a space is used as the separator when the new field is appended to the line.


Add Registry (AddReg)

[add-registry-section]
reg-root-string, [subkey], [value-name], [flag], [value]

Adds subkeys or value names to the registry, optionally setting the value. The add-registry-section name must appear in an AddReg item in an Install section.

reg-root-string
Registry root name. Can be one of these values:

HKCR Same as HKEY_CLASSES_ROOT
HKCU Same as HKEY_CURRENT_USER
HKLM Same as HKEY_LOCAL_MACHINE
HKU Same as HKEY_USERS.
HKR Means relative from the Key passed into GenInstallEx.

HKR is always context sensitive to the install section the AddReg/DelReg/etc directives are processed from.

Specifically, HKR is relative to a context specific key, in context of any services installs, it's the service key.

In context of [DDInstall] it's the software key - same as SetupDiOpenDevRegKey(…DIREG_DRV…)

In context of [DDInstall.HW] it's the hardware key - same as SetupDiOpenDevRegKey(…DIREG_DEV…)

subkey
Optional. Identifies the subkey to set. Has the form key1\key2\key3.... This parameter can be expressed as a replaceable string. For example, you could use %Subkey1% where the string to replace %Subkey1% is defined in the Strings section of the INF file.
value-name
Optional. Identifies the value name for the subkey. For string type, if the value-name parameter is left empty, the value of the subkey specified in the subkey parameter is set to a NULL string. Note that the value-name parameter can be expressed as a replaceable string. For example, you could use %Valname1% where the string to replace %Valname1% is defined in the Strings section of the INF file.
flag
Optional. Determines both the value type and whether the registry key is replaced if it already exists.
Value | Meaning
0 | Default. Value is an ANSI string. Replace key if it exists.
1 | Value is a hexadecimal number. Replace key if it exists.
2 | Value is an ANSI string. Do not replace key if it exists.
3 | Value is a hexadecimal number. Do not replace key if it exists.

value
Optional. Value to set. Can be either an ANSI string or a number in hexadecimal notation and Intel format. Any item containing a binary value can be extended beyond the 128-byte line maximum by using a backslash (\) character. A string key of the form %strkey% can also be given. The strkey must be defined in the Strings section of the INF file. To use a % character in the line, use %%.

At least two fields are required, however one can be NULL, thus at least one comma is required when using this form.

The two items in the example AddReg section below add two value names to the registry. Note that %25% will be expanded to the machine's Windows directory.

[MyAppRegEntries]
HKLM,Software\MyApp,ProgramName,,"My Application"
HKLM,Software\MyApp,"Program Location",,"%25%\MyApp.exe"

Note If you use an INF file, there is no way to add DWORDs in Windows Me.


Delete Registry (DelReg)

[del-registry-section]
reg-root-string, subkey, [value-name]

Deletes a subkey or value name from the registry. The del-registry-section name must appear in an DelReg item in an Install section.

reg-root-string
Registry root name. Can be one of these values:

HKCR Same as HKEY_CLASSES_ROOT
HKCU Same as HKEY_CURRENT_USER
HKLM Same as HKEY_LOCAL_MACHINE
HKU Same as HKEY_USERS
HKR Means relative from the Key passed into GenInstallEx

HKR is always context sensitive to the install section the AddReg/DelReg/etc directives are processed from.

Specifically, HKR is relative to a context specific key, in context of any services installs, it's the service key.

In context of [DDInstall] it's the software key - same as SetupDiOpenDevRegKey(…DIREG_DRV…)

In context of [DDInstall.HW] it's the hardware key - same as SetupDiOpenDevRegKey(…DIREG_DEV…)

subkey
Identifies the subkey to delete. Has the form key1\key2\key3... This parameter can be expressed as a replaceable string. For example, you could use %Subkey1% where the string to replace %Subkey1% is defined in the Strings section of the INF file.
value-name
Optional. Identifies the value name for the subkey. Note that the value-name parameter can be expressed as a replaceable string. For example, you could use %Valname1% where the string to replace %Valname1% is defined in the Strings section of the INF file.

This type of section can contain any number of items. Each item deletes one subkey or value name from the registry.


Ini File to Registry (Ini2Reg)

[ini-to-registry-section]
ini-file, ini-section, [ini-key], reg-root-string, subkey[,flags]

Moves lines or sections from an INI file to the registry, creating or replacing a registry entry under the given key in the registry. The section name ini-to-registry-section must appear in an Ini2Reg item in an Install section of the INF file.

ini-file
Name of the INI file containing the key to copy. For more information about specifying the INI file name, see the comments in the Reference topic about the Update Ini File Section.
ini-section
Name of the section in the INI file containing the key to copy.
ini-key
Name of the key in the INI file to copy to the registry. If ini-key is empty the whole section is transferred to the specified registry key.
reg-root-string
Registry root name. Can be one of these values:

HKCR Same as HKEY_CLASSES_ROOT
HKCU Same as HKEY_CURRENT_USER
HKLM Same as HKEY_LOCAL_MACHINE
HKU Same as HKEY_USERS.
HKR Means relative from the Key passed into GenInstallEx

HKR is always context sensitive to the install section the AddReg/DelReg/etc directives are processed from.

Specifically, HKR is relative to a context specific key, in context of any services installs, it's the service key.

In context of [DDInstall] it's the software key - same as SetupDiOpenDevRegKey(…DIREG_DRV…)

In context of [DDInstall.HW] it's the hardware key - same as SetupDiOpenDevRegKey(…DIREG_DEV…)

subkey
Identifies the subkey to receive the value. Has the form key1\key2\key3...
flags
Indicates whether to delete the INI key after transfer to the registry and whether to overwrite the value in the registry if the registry key already exists. Can be one of these values:
Value | Meaning
0 | Default. Do not delete the INI entry from the INI file after moving the information in the entry to the registry. If the registry subkey already exists, do not replace its current value.
1 | Delete the INI entry from the INI file after moving the information in the entry to the registry. If the registry subkey already exists, do not replace its current value
2 | Do not delete the INI entry from the INI file after moving the information in the entry to the registry. If the registry subkey already exists, replace its current value with the value from the INI file entry.
3 | Delete the INI entry from the INI file after moving the information in the entry to the registry. If the registry subkey already exists, replace its current value with the value from the INI file entry.

For example, suppose the following entry exists in the win.ini file:

[Windows]
CursorBlinkRate=15

If a CursorBlinkRate subkey does not exist under the Control Panel\Desktop, then the following item in an Ini File to Registry section creates the subkey, sets the value of the subkey to 15, and leaves the original line in win.ini unchanged:

win.ini,Windows,CursorBlinkRate,HKCU,"Control Panel\Desktop"

If the subkey already exists, the INF file item sets the value of the subkey to 15, and leaves the original line in win.ini unchanged.


Update Config.sys (Update CfgSys)

Previous Next

Update Config.sys (UpdateCfgSys)

[update-config-section]
Buffers=legal-dos-buffer-value
DelKey=key
DevAddDev=driver-name,configkeyword[,flag][,param-string]
DevDelete=device-driver-name
DevRename=current-dev-name,new-dev-name
Files=legal-dos-files-value
PrefixPath=ldid[,ldid]
RemKey=key
Stacks=dos-stacks-values

Provides commands to add, delete, or rename commands in the config.sys file. The section name, update-config-section-name, must appear in the UpdateConfigSys item in an Install section of the INF file.

Not all item types shown in the syntax above are needed or required. An Update Config.sys section may contain as many DevRename, DevDelete, DevAddDev, DelKey, and RemKey items as needed, but the Buffers, Files, and Stacks items may only be used once in a section. When processing an Update Config.sys section, the Installer processes all DevRenames items first, all DevDelete items second, and all DevAddDev items last. The syntax and meaning of each of the types of items that can be used in an Update Config.sys section are given later in this topic.

Buffers Item

Buffers=legal-dos-buffer-value

Sets the number of file buffers. As it does with the Stacks item, the Installer compares the existing value with the proposed value and always sets the file buffers to the larger of the two values.

legal-dos-buffers-value
A legal MS-DOS buffers value.

DelKey Item

DelKey=key

Causes the config.sys command with the specified key to be commented out in the config.sys file. For example, the INF file item

DelKey=Break
Would cause a Break=on command to be commented out in the config.sys file.

The DelKey item has the same effect as the RemKey item. There can be multiple DelKey and/or RemKey items in a section of the INF file.

key
The key of the config.sys command to be commented out.

DevAddDev Item

DevAddDev=driver-name,configkeyword[,flag][,param-string]

Adds a device or install command to the config.sys file.

driver-name
Name of the driver or executable file to add. The installer validates the file name extension, ensuring that it is .sys or .exe.
configkeyword
Command name. Can be device or install.
flag
Optional placement flag. If 0, the command is placed at the bottom of the file. If 1, it is placed at the top. If flag is not given, 0 is used by default.
param-string
Optional command parameters. Must be valid for the given device driver or executable file.

DevDelete Item

DevDelete=device-driver-name

Deletes any line containing the specified file name from the config.sys file.

device-driver-name
Name of a file or device driver. The Installer searches the config.sys file for the name and deletes any line containing it. Because MS-DOS does not permit implicit file name extensions in config.sys, each device-driver-name must explicitly specify the file name extension.

In the following example, DevDelete item in an Update Config.sys section deletes lines 1 and 3 but not line 2 of the config.sys file:

DevDelete=Foo.sys
;; lines in config.sys
Device=Foo.sys ;; line #1
Install=foo.exe ;; line #2
Device=Foo.sys /d:b800 /I:3 ;; line #3

DevRename Item

DevRename=current-dev-name,new-dev-name

Renames a device driver in the config.sys file.

current-dev-name
Name of the device driver or executable file to rename. The installer looks for the name on the right side of a device or install command in the config.sys.
new-dev-name
New name for driver or executable file.

Files Item

Files=legal-dos-files-value

Sets the maximum number of open files in the config.sys file. As it does with the Stacks item, the Installer compares the existing value with the proposed value and always sets the maximum number of open files to the larger of the two values.

legal-dos-files-value
A legal MS-DOS files value.

PrefixPath Item

PrefixPath=ldid[,ldid]...

Appends the path associated with the given LDID to the path command.

ldid
Can be any of the predefined LDID values or a new value defined in the INF file. For a definition of all the predefined LDID values, see DestinationDirs.

RemKey Item

RemKey=key

Causes the config.sys command with the specified key to be commented out in the config.sys file. For example, the INF file item

RemKey=Break
Would cause a Break=on command to be commented out in the config.sys file.

The RemKey item has the same effect as the DelKey item. There can be multiple RemKey and/or DelKey items in a section of the INF file.

key
The key of the config.sys command to be commented out.

Stacks Item

Stacks=dos-stacks-values

Sets the number and size of stacks in the config.sys file. The Installer compares the existing value with the proposed value and always sets the stacks to the larger of the two values. For example, if config.sys contains stacks=9,218 and an INF file contains stacks=5,256, the installer sets the new value to stacks=9,256.

legal-dos-stacks-value
A legal MS-DOS stacks value.


Update Autoexec.bat (UpdateAutoBat)

[update-autoexec-section]
CmdAdd=command-name[,command-parameters]
CmdDelete=command-name
PrefixPath=ldid[,ldid]
RemOldPath=ldid[,ldid]
TmpDir=ldid[,subdir]
UnSet=env-var-name

Provides commands to manipulate lines in the AUTOEXEC.BAT file. The section name, update-autoexec-section-name, must appear in the UpdateAutoBat item in an Install section of the INF file.

Not all item types shown in the syntax above are needed or required in an Update Autoexec.bat section. The section can contain as many CmdAdd, CmdDelete and UnSet items as needed, but only one PrefixPath, RemOldPath and TmpDir items can be used in an INF file. The syntax and meaning of each of the item types is described later in this topic.

The installer processes all CmdDelete items before any CmdAdd items.

CmdAdd

CmdAdd=command-name[,"command-parameters"]

Adds the given command and optional command parameters to the AUTOEXEC.BAT file, at the end of the file.

command-name
Name of an executable file, with or without an extension. If the file name is also defined in the SourceDisksFiles and DestinationDirs sections of the INF file, the installer adds the appropriate path to the file name before writing it to the AUTOEXEC.BAT file.
command-parameters
A string enclosed in double quotation marks or a replaceable string like %String1% or %Myparam%, where the strings that replace %String1% and %Myparam% are defined in the Strings section of the INF file. The installer appends the string to the command-name before appending the line to the end of the AUTOEXEC.BAT file. The format of this line is dependent on the command line requirements of the given executable file.

CmdDelete

CmdDelete=command-name

Deletes any lines from AUTOEXEC.BAT that include the given command name. The installer searches for and deletes any occurrence of the given name that has a file name extension of .exe, .com, and .bat.

command-name
Name of an executable file without an extension.

PrefixPath

PrefixPath=ldid[,ldid]...

Appends the path associated with the given LDID to the path command.

ldid
Can be any of the predefined LDID values or a new value defined in the INF file. For a definition of all the predefined LDID values, see DestinationDirs.

RemOldPath

RemOldPath=ldid[,ldid]

Removes the path associated with the given LDID from the path command. For example, if the user installs the new version of Windows into c:\newwin and has an old copy of Windows in c:\windows, the following INF file item removes c:\windows from the path environmental variable:

RemOldPath=10

ldid
Can be any of the predefined LDID values or a new value defined in the INF file. For a definition of all the predefined LDID values, see DestinationDirs.

TmpDir

TmpDir=ldid[,subdir]

Creates a temporary directory within the directory given by the LDID, if it does not already exist.

ldid
Can be any of the predefined LDID values or a new value defined in the INF file. For a definition of all the predefined LDID values, see DestinationDirs.
subdir
A path name. If ldid\subdir does not already exist, it is created.

UnSet

UnSet=env-var-name

Removes any set command from the AUTOEXEC.BAT file that includes the given environment variable name.

env-var-name
Name of an environment variable.


DestinationDirs

[DestinationDirs]
file-list-section=ldid[, subdir ]
[DefaultDestDir=ldid[, subdir ]]

The DestinationDirs section defines the destination directories for the operations specified in file-list sections, which are either CopyFiles, RenFiles, or DelFiles sections. Optionally, a default destination directory can be specified for any CopyFiles, RenFiles, or DelFiles sections in the INF file that are not explicitly named in the DestinationDirs section.

file-list-section
Name of a CopyFiles, RenFiles, or DelFiles section. This name must be referred to in a Copyfiles, RenFiles, or DelFiles item in an Install section.
ldid
A logical disk identifier (LDID). Can be one of these values:

00 Null LDID. This LDID can be used to create a new LDID

01 Source Drive:\pathname

10 Machine directory (Maps to the Windows directory on a Server-Based Setup.)

11 System directory

12 IOSubsys directory

13 Command directory

17 INF Directory

18 Help directory

20 Fonts

21 Viewers

22 VMM32

23 Color directory

24 Root of drive containing the Windows directory

25 Windows directory

26 Guarenteed boot device for Windows (Winboot)

28 Host Winboot

30 Root directory of the boot drive

31 Root directory for Host drive of a virtual boot drive

subdir
Name of the directory, within the directory named by ldid, to be the destination directory.

The optional DefaultDestDir item provides a default destination for any CopyFiles items that use the direct copy (@file name) notation or any CopyFiles, RenFiles, or DelFiles sections not specified in the DestinationDirs section. If a DefaultDestDir is not used in a DestinationDirs section, then the default directory is set to LDID_WIN.

This example sets the destination directory for the MoveMiniPort section to WINDOWS\IOSUBSYS and sets the default directory for other sections to be the BIN directory on the boot drive:

[DestinationDirs]
MoveMiniPort=12 ; Destination for MoveMiniPort Section is
; windows\iosubsys
DefaultDestDirs=30,bin ; Direct copies go to Boot:\bin


SourceDisksNames

[SourceDisksNames]
disk-ordinal="disk-description",disk-label,disk-serial-number

Identifies and names the disk(s) that contain the source files for file copying and renaming operations.

disk-ordinal
A unique number that identifies a source disk. If there is more than one source disk, each must have a unique ordinal.
disk-description
A string or a strings key describing the contents or purpose of the disk. The installer displays this string to the user to identify the disk. The description is enclosed in double quotation marks.
disk-label
Volume label of the source disk that is set when the source disk is formatted.
disk-serial-number
Unused. Value must be 0.

This example identifies one source disk. The disk description is given as a strings key:

[SourceDisksNames]
55 = %ID1%, Instd1, 0
[Strings]
ID1="My Application Installation Disk 1"


SourceDisksFiles

[SourceDisksFiles]
filename=disk-number[,subdir] [,file-size]

Names the source files used during installation and identifies the source disks that contain the files.

filename
Name of the file on the source disk.
disk-number
Ordinal of the source disk that contains the file. This ordinal must be defined in the SourceDisksNames section, and must have a value greater than or equal to 1 (zero is not a valid disk-number parameter value).
subdir
Optional parameter that specifies the subdirectory on the source disk where the file resides. If this parameter is not used, the source disk root directory is the default.
file-size
Optional parameter that specifies the size of the file, in Bytes.

In the following example, the SourceDisksFiles section identifies a single source file, SRS01.386, on the disk having ordinal 1:

[SourceDisksFiles]
SRS01.386 = 1


Strings

[Strings]
strings-key=value

Defines one or more strings keys. A strings key is a name that represents a string of printable characters. Although the Strings section is generally the last section in the INF files, a string key defined in this section may be used anywhere in the INF file that the corresponding string would be used. The Installer expands the string key to the given string and uses it for further processing. Using a strings key requires that it be enclosed in percent signs (%).

strings-key
A unique name consisting of letters and digits.
value
A string consisting of letters, digits, or other printable characters. It should be enclosed in double-quotation marks if the corresponding strings key is used in a type of item that requires double quotation marks.

The Strings section makes translation of strings for international markets easier by placing all strings that can be displayed at the user interface when the INF file is used in a single section of the INF file. Strings keys should be used whenever possible.

The following example shows the strings section for a sample INF file.

[Strings]
String0="My Application"
String1="My Application Readme File"
String2="CX2590 SCSI Adapter"


Optional Components

[Optional Components]
install-section-name

Lists Install sections that are displayed when the user selects the INF file from the "Have Disk…" button in the Windows Setup tab in the Add-Remove Programs control panel. The Install sections show up as choices in the list of check-boxes.

The Optional Components section is ignored if you execute an INF file by right-clicking on the INF file and selecting Install. Instead, the [DefaultInstall] section is executed. The Optional Components section is also ignored if the INF file is being executed by using the SETUPX.DLL InstallHinfSection entry point. When executing an INF by using the SETUPX entry point, the Install section specified in the parameter to the entry point is executed.

The Install sections follow the same format as described previously, and the following additional keys can be added to the Install section to drive the UI in the "Have Disk" dialog:

OptionDesc

=option-description
Tip

=tip-description
InstallDefault

=0 | 1 ; Whether to install this component by default. 1=Yes, 0=No.
IconIndex

=icon-index
Parent=install-section-name
Needs

=install-section-name, [install-section-name]…
Include

=inf-file,

[inf-file]…

option-description
String value that is used as the component name in the list box. The option-description parameter may be %String1%, where the string that replaces %String1% is defined in the Strings section of the INF file.
tip-description
String value that is displayed in the "description" box when the component is selected in the list box. The tip-description parameter has a 255 character limit, and may be %String1%, where the string that replaces %String1% is defined in the Strings section of the INF file.
icon-index
Numeric value that determines the mini-icon that is displayed next to the component name. Valid values are:

0 Machine (base and display)
1 Integrated Circuit Chip
2 Display
3 Network wires
4 Windows Flag
5 Mouse
6 Keyboard (3 keys)
7 Phone
8 Speaker
9 Hard Disks
10 Comm Connector
11 Diamond (default value)
12 Checked box
13 Un-checked box
14 Printer
15 Net Card
16 Same as 0
17 Same as 0 w/ a sharing hand underneath
18 Unknown (question mark)
19 Atwork
20 Greyed Check box
21 Dial up networking
22 Direct cable connection
23 Briefcase
24 Exchange
25 Partial check
26 Accessories Group
27 Multimedia Group
28 Quick View
29 MSN
30 Calculator
31 Defrag
32 Generic Document
33 DriveSpace
34 Solitaire
35 HyperTerminal
36 Object Packager
37 Paint
38 Screen Saver
39 WordPad
40 Clipboard Viewer
41 Accessibility
42 Backup
43 Bitmap Document
44 Character Map
45 Mouse Pointers
46 Net Watcher
47 Phone Dialer
48 System Monitor
49 Help book
50 Globe (international settings)
51 Audio compression
52 CD Player
53 Media Player
54 Sound Scheme
55 Video Clip
56 Video Compression
57 Volume control
58 Musica Sound Scheme
59 Jungle Sound Scheme
60 Robotz Sound Scheme
61 Utopia Sound Scheme

Parent
The list box displayed in the optional components UI can have sub-levels. If the optional component is a child, the Parent= keyword defines the Install section that is the Parent.
Needs
If this component has dependencies on other components, this defines Install sections that are required by this component. If the component is selected, the user will be warned that the component requires the component(s) described in the Install section(s) listed on the Needs= line.

Note that the Install sections listed on the Needs= line must be in the same INF file. However, if dependent components from other INF are listed in the Needs= line, the INF files must be specified on the Include= line.

Include
The Include item enables you to specify INF files that Setup must also load into memory when it loads your INF file because these INF files contain sections that must be run in addition to the install sections in your INF file. The Needs item specifies the names of the sections you intend to run in the included INF file(s).

The following example defines two optional component install sections, and each install section uses the additional entries to specify UI elements and dependencies:

[Optional Components]
InstallMyToys
InstallGames
[InstallMyToys]
OptionDesc=%Toys_DESC%
Tip=%Toys_TIP%
IconIndex=35 ;Phone mini-icon for dialogs
Parent=MailApps
Needs=MSMAIL, MAPI, MicrosoftNetwork
Include=mos.inf, msmail.inf
CopyFiles=MyToysFiles
UpdateInis=MyToysLinks
AddReg=MyToysRegItems
[InstallOtherApps]
OptionDesc=%Other_DESC%
Tip=%Other_TIP%
IconIndex=4 ;windows mini icon for dialogs
CopyFiles=OtherFiles
UpdateInis=OtherLinks
AddReg=OtherRegItems
[Strings]
Toys_DESC="Mail Utilities"
Toys_TIP="Additional utilities for sending and organizing mail"
Other_DESC="Other Helpful Utilities"
Other_TIP="Calculator, disk checker and performance montitor"


About DirectSound

The Microsoft® DirectX® application programming interface (API) is a component of the Software Development Kit (SDK) that enables the creation of world class computer-based games. DirectSound® is the audio component of that SDK that provides low-latency mixing, hardware acceleration, and direct access to the sound device. DirectSound provides this functionality while maintaining compatibility with existing Microsoft Windows® 95 applications and device drivers.

Note The information contained in this document describes how to modify your audio driver to support DirectSound capabilities in Windows 95. It is included for backward compatibility. Although Windows 98 supports Windows 95-style drivers with DirectSound enhancements, new driver development should be done under the WDM audio driver model. For more information, see the WDM audio driver model supplied with the Windows 98 DDK and the Windows NT DDK.


Introduction to DirectSound

DirectX is built for speed. It allows game authors unprecedented access to the display and audio hardware, while insulating them from the specific details of that hardware. In keeping with these design goals, DirectSound is not a high-level API. Instead, DirectSound provides a device-independent interface that allows applications to take advantage of the capabilities of the audio hardware. For applications, DirectSound provides access to audio features such that hardware acceleration can be used whenever available. For sound card manufacturers, DirectSound provides a set of audio features that can be implemented in hardware such that existing DirectSound applications immediately benefit from the acceleration.

Features not supported directly in hardware are emulated in software by DirectSound without any loss of functionality. Applications can query DirectSound to determine the capabilities of the audio hardware. A high-performance application can use this information to scale its audio features. For example, applications might use several more sounds if hardware-accelerated mixing is supported by the audio hardware.

DirectSound accesses the sound hardware through the DirectSound hardware abstraction layer (HAL), an interface that is implemented by the audio device driver. This driver consists of a Windows 95 audio device driver that has been modified to support the HAL; this provides backward compatibility with existing Windows-based applications. The DirectSound HAL provides the following functionality:

  • Acquires and releases control of the audio hardware.
  • Describes the capabilities of the audio hardware.
  • When hardware is available, performs the requested operation.
  • When hardware is unavailable, fails the requested operation.

The device driver must not perform any software emulation. Its sole purpose is to report the capabilities of the hardware to DirectSound, and to pass DirectSound requests to the hardware. If the requested operation cannot be performed by the hardware, the device driver should simply fail the request. The operation is then emulated in software by DirectSound.

If a DirectSound driver is not available, DirectSound communicates with the audio hardware through the standard Windows 95 or Windows 3.1 audio device driver. In this case, all DirectSound features are still available through software emulation, but hardware acceleration is not accessible.


References and Resources

This guide includes a collection of conceptual and reference information that is not available in any other document. However, the following additional references may be of use to developers who are creating DirectSound device drivers.

  • Microsoft Win32 Software Development Kit (SDK)

    Microsoft Developer Network (MSDN) Professional membership

  • Microsoft DirectX SDK

    MSDN Professional membership

    Internet: http://www.microsoft.com/mediadev/

  • Microsoft Windows Device Driver Kit (DDK)

    MSDN Professional membership

  • Microsoft DirectX for Windows 95 DDK

    MSDN Professional membership

  • Microsoft DirectX for Windows NT DDK

    Standard part of Windows NT 4.0 DDK.

    MSDN Professional membership

  • Microsoft information for DirectX driver developers

    E-mail: directx@microsoft.com

  • White papers on DirectX and related technologies:

    http://www.microsoft.com/hwdev/devdes/ (hardware-related information)

    http://www.microsoft.com/mediadev/ (API-related information)

    http://www.microsoft.com/win32dev/ (Win32 API information)

  • Windows Hardware Quality Labs (driver testing and logo qualification)

    E-mail: whqlinfo@microsoft.com

    Internet: http://www.microsoft.com/hwtest/

For resources that are available only through a MSDN Professional membership, contact the Microsoft Developer Network.

Telephone (U.S. and Canada): (800) 759-5474 dpmt. A622WEB

Outside North America: call a local Microsoft subsidiary, or dial (510) 275-0763

Internet: http://www.microsoft.com/msdn/subscribe


Typographic Conventions

The following terms, text formats, and symbols are used in this guide.

Convention | Meaning
Bold | Indicates a function, a structure name, macro, interface, method, data type, or other keyword in Microsoft Win32®, Microsoft DirectX, C, or C++.
Italic | Indicates placeholders, most often function or method parameters; these placeholders stand for information that must be supplied by the implementation or the user.
UPPERCASE | Indicates flags, return values, and properties. In addition to standard C-language conventions, uppercase letters indicate segment names, registers, and terms used at the operating-system command level.
Monospace | Indicates source code, structure syntax, examples, user input, and program output.

The interface syntax in this guide follows the variable-naming convention known as Hungarian notation, invented by the programmer Charles Simonyi. Variables are prefixed with lowercase letters that indicate their data type. For example, lpszProfileName is a long pointer to a zero-terminated string name ProfileName. For more information about Hungarian notation, see Programming Windows 95, by Charles Petzold (Microsoft Press: 1995; ISBN 1-55615-676-6).


Architectural Overview

The following diagram shows the relationships between DirectSound and other system audio components.

To obtain the best performance, a DirectSound HAL must be implemented for the sound hardware. The HAL is a set of functions that are implemented by a driver specific to each type of sound hardware. If a DirectSound driver is not installed for the sound hardware, DirectSound uses its HAL emulation layer. This layer uses the Wave APIs to output sound. This allows DirectSound applications to run on any Windows sound device (although the performance is much better when a DirectSound driver is used).


The DirectSound HAL

The purpose of the HAL is to describe the capabilities of the hardware to DirectSound and to pass requests from DirectSound to the hardware. If the hardware cannot handle the request, the HAL fails the call and DirectSound emulates the request in software. The HAL must never emulate functions in software; emulation is best performed by the optimized code in DirectSound.

The DirectSound HAL is implemented by DirectSound drivers that exist in ring 0 without any ring 3 component (that is, they are virtual device drivers, or VxDs). Typically this is the same VxD as the ring 0 component of the Windows 95 Wave driver. These DirectSound drivers are Plug and Play compliant, which means that instances of the drivers are created by the configuration manager rather than by DirectSound. After an instance of the driver is created, it must register with DirectSound by passing a pointer to its primary interface, IDsDriver. DirectSound then uses this interface to access the HAL, as well as other interfaces it creates through IDsDriver. When the configuration manager notifies the driver that the hardware has been removed, the driver again notifies DirectSound so that DirectSound can release the driver interfaces.

Other than this instantiation and notification procedure, the driver is simply required to respond correctly to DirectSound when it calls the driver interfaces. In addition to IUnknown, the following three interfaces are currently defined: IDsDriver (supported by the main driver object), IDsDriverBuffer (supported by each sound buffer object), and IDsDriverPropertySet (optionally supported by any driver-created object).


DirectSound and Wave Drivers

As can be seen, the DirectSound API and the Wave APIs are alternative paths to the wave audio portion of the sound hardware. These two paths can (and should) coexist peacefully within a single driver. The VxD is simply required to fail an open request from one path if the device is already open through the other path. Therefore, if the device is allocated through the Wave APIs, the DirectSound allocation must fail.Similarly if the device is allocated through DirectSound, the Wave allocation must fail. It is critical that this contention management be performed correctly; if it is not, the new driver has the potential to create compatibility problems with existing applications that access the Wave APIs.


DirectSound Essentials

The following topics are discussed in this section:

  • Hardware Acceleration
  • How to Instantiate Drivers
  • DirectSound3D Windows 95 Device Driver Interface
  • DirectSound Driver Capabilities
  • Floating Point Issues in VxDs


Hardware Acceleration

The DirectSound API provides a scaleable architecture. DirectSound features are implemented in software and are available on base-level cards (the installed base). However, if the hardware resources are available, DirectSound offloads processing onto the sound card.

For application developers, scaleability means they can take advantage of hardware acceleration in a device-independent manner. Applications can simply open and configure their audio buffers, and DirectSound performs the hardware-dependent task of allocating hardware resources to the various buffers. Applications are permitted to query DirectSound about the hardware resources of the sound card and the resources allocated to each buffer. This permits high-performance applications to scale to the hardware resources available. For example, an action game might use more sounds if it knows that hardware mixing is available. This allows the game to take full advantage of high-end cards while still performing well on low-end machines.

For sound card manufacturers, scaleability means that new sound cards can add immediate value to DirectSound applications. For example, hardware mixing offloads processing to the sound card, making games run faster and smoother. Hardware 3-D support can immediately improve the sound quality by using complex algorithms that are more realistic than the simple algorithms used in the DirectSound 3-D simulation code. Finally, any applications that scale to the hardware immediately start using more sounds and 3-D positioning. This helps sell more cards by providing an immediate advantage to the consumer.

The following sections outline the hardware features that can be exploited by DirectSound, both in the current implementation and in future implementations:

  • On-card Memory for ISA Cards
  • Hardware Mixing
  • 3-D Positional Audio
  • Compressed Wave Formats
  • Wave Input


On-card Memory for ISA Cards

On-card memory for industry standard architecture (ISA) cards is not really a feature by itself; rather, it is required before the cards can provide other accelerations. With ISA cards, bus performance is a major bottleneck. Especially at high-sampling frequencies, a single stream of audio consumes a significant proportion of the bus bandwidth. Direct memory access (DMA) alleviates the CPU overhead associated with this transfer, but the bus traffic may end up stalling the CPU anyway.

Hardware acceleration of DirectSound requires that sound buffers be passed to the sound card before processing. Peripheral component interconnect (PCI) buses have the bandwidth to transmit multiple streams of audio to the card; with an ISA bus, this transfer would add overhead that would negate the benefits of hardware acceleration.

There is one case, however, in which the bus bandwidth is no longer an issue. When DirectSound applications create sound buffers, they can specify the buffers as either streaming or static. There is no difference in capabilities or structure between these two types; the only difference is the application's intended use of them. Streaming sound buffers are used for long and continually changing sounds, such as the soundtrack to a movie or a background song. Static sound buffers are used for short sounds that intend to be reused, such as a bullet sound or monster noise.

Static sound buffers are ideal for on-board memory. They are written infrequently so they don't consume significant bus bandwidth, but they can then be played consuming very few CPU cycles. Since many games use this kind of sound, on-board memory can be a major advantage. The memory should be 256K bytes or higher to be most useful to games.

Each hardware static sound buffer should support the following capabilities:

  • Play and stop.
  • Automatic looping back to start of buffer.
  • Automatic stop at end of buffer if looping not specified.
  • Should be able to stop after playing a specified number of bytes. If the number of bytes is greater than the length of the buffer, the buffer should automatically loop back to the beginning and continue until the specified number of bytes have been played.
  • Volume and pan control. Most applications use these controls; if the hardware doesn't offer them, DirectSound is unable to use the hardware for these buffers.
  • Frequency (pitch) control. This is also needed for the same reasons as volume and pan, but is not requested as often.
  • Memory re-use. Two logical sound buffers should be able to use the same memory, but have different play cursors and different effects. For example, a gunshot sound could be played twice simultaneously using different volume and pan settings. This is required to take advantage of the IDirectSound::DuplicateSoundBuffer method.

In addition, hardware buffers are not useful without the second feature, hardware mixing, described in the following section.


Hardware Mixing

Mixing is one of the main features of DirectSound. Most games attempt to mix three to eight sounds simultaneously. Latency (the delay between playing the sound and hearing it through the speakers) must be less than 20 milliseconds for the listener to perceive sounds as being synchronized with visual cues.

The advantage of hardware mixing is that it reduces the load on the system CPU, allowing the game to run faster and smoother. However, it has the disadvantage of passing more data over the system bus. For a PCI sound card this is probably not a problem; the bandwidth of the PCI bus permits multiple streaming sound buffers to be simultaneously transmitted to the card without bus congestion. For an ISA card, hardware mixing is really only useful if the card has on-board memory (as described earlier) into which static sound buffers can be loaded.

DirectSound queries the sound card for its mixing capabilities. If the card has on-board memory and mixing, DirectSound uses that memory to store static sound buffers. If the card is on a fast bus (such as PCI), the driver can request DirectSound to also assign streaming buffers to the hardware mixing channels. DirectSound always reserves one mixing channel for the DirectSound software mixer so that additional streams can be mixed in software and then transmitted to the sound card for final mixing with the hardware buffers.

Each hardware mixing channel should support the following capabilities:

  • Play and stop.
  • Automatic looping back to start of buffer.
  • Automatic stop at end of buffer if looping not specified.
  • Should be able to stop after playing a specified number of bytes. If the number of bytes is greater than the length of the buffer, the buffer should automatically loop back to the beginning and continue until the specified number of bytes have been played.
  • Volume and pan control. Most applications use these controls; if the hardware does not offer them, DirectSound is unable to use the hardware for these buffers.
  • Frequency (pitch) control. This is also needed for the same reasons as volume and pan, but is not requested as often.


3-D Positional Audio

Positional audio is a very compelling feature that adds to the realism and playability of most 3-D action games. Unfortunately, the algorithms needed to position a sound are very complex. Even using a scaled-down software implementation, real games can only position one or two sounds without hardware support.

With hardware support, games can position as many sounds as the hardware supports. The positioning is typically done using a more powerful algorithm than the DirectSound software implementation, so the positioning is more realistic and compelling. Finally, high-performance games scale to the hardware capabilities, so they may begin using more 3-D sounds if the hardware support is present, increasing the realism and sound quality.

3-D positional acceleration is useful only if the card also supports hardware mixing. 3-D support is useful on some but not all channels; at least one channel (the one used by the DirectSound software mixer) never uses 3-D positioning. The same bus performance issues apply: on fast PCI buses, sound cards can position streaming sound buffers, while on ISA buses 3-D support is most useful for static buffers located in on-board memory. However, since 3-D positioning is such a CPU-intensive task, it might be worth the bus traffic to support two streaming buffers on an ISA card: one for 3-D positioning, and the other for use by the DirectSound software mixer. Sound card manufacturers must evaluate the trade-offs involved.

The specific details of 3-D positional support can be derived from the DirectX SDK, which describes the 3-D parameters that an application can specify. A hardware implementation is not required to take advantage of all of these parameters; the hardware should position streams using whichever parameters are necessary. For example, sound direction and velocity parameters can be used to determine Doppler shifting effects, but hardware is not required to do so since this is not a critical feature.

The following 3-D positional effects (listed in order of importance) are supported:

  • Set sound position, set listener position and orientation — positions sound in 3-D space.
  • Set rolloff and distance factor of current environment — describes how the volume changes in response to distance from the source.
  • Set sound cone (orientation, angle, ambient volume) — describes sound projection characteristics.
  • Set direction and velocity of sounds and listener, set Doppler factor — used to calculate Doppler effects (not to trace the sound path or the listener path).


Compressed Wave Formats

A number of sound devices have recently included hardware support for compressed wave formats such as IMA ADPCM and G7.11. This is a useful feature only if one audio stream is playing at a time; if that stream is compressed, the hardware may be able to accelerate the decoding process. However, this feature is less useful when multiple streams are playing, since mixing must be performed on PCM streams. For this reason, DirectSound does not currently support compressed wave formats. However, support is planned for the future.

The first feature is support for compressed primary buffers. If an application obtains DSSCL_WRITEPRIMARY access and sets the primary buffer to a compressed format that is supported by the hardware, it succeeds and writes a compressed audio stream directly to the hardware. This is not useful for most applications, however, since only one stream can be played at a time.

In a future release, DirectSound will provide complete support for compressed wave formats in secondary buffers. DirectSound will use hardware decompression if available and otherwise will decompress the formats in software using the Audio Compression Manager (ACM) APIs.

It should be mentioned that, given a choice between hardware-accelerated compression/decompression and hardware-accelerated 3-D positional audio, the 3-D support is much more desirable for high-volume applications such as games.


Wave Input

DirectSound does not currently define wave capture driver interfaces other than the Mmsystem.dll ring 3 widMessage wave driver interface that exists in the original release of Windows 95. The DirectSound API supports full-duplex (that is, audio can be played while it is being recorded) on drivers and cards that are capable of this feature. Full-duplex can add significantly to the interactivity of audio, especially with multiplayer games.


How to Instantiate Drivers

This section describes how to instantiate drivers, and what drivers must do to register themselves with DirectSound. This section assumes knowledge of the Windows 95 audio device driver interface, Plug and Play, and so on. This information can be obtained from the Windows 95 Device Driver Kit (DDK). It is strongly recommended that a functional Windows 95 driver be written for the sound device before DirectSound driver support is added. The DirectSound portion of the driver is a small addition to (and relies on several components of) the Windows 95 driver.

The following topics are discussed in this section:

  • The Configuration Handler
  • DirectSound VxD Exports
  • Registering a Driver
  • Deregistering a Driver


The Configuration Handler

Windows 95 audio drivers must register a configuration handler with MMDevLdr (the component that loads the multimedia drivers - for more information, see the Windows 95 DDK). This is done by the driver when it is notified of a new devnode. The code would include something like this:

mov     ebx, OFFSET32 _ConfigHandler
VxDCall MMDEVLDR_Register_Device_Driver

The configuration manager can then send messages to the device driver. When it is okay for the driver to begin to access the device, the configuration manager sends a CONFIG_START message to the configuration handler. When handling this message, the configuration handler should register the driver with DirectSound.

The configuration manager also sends CONFIG_STOP, CONFIG_REMOVE, or CONFIG_SHUTDOWN messages to the driver. The driver should respond to all of these messages by deregistering itself so that DirectSound knows the device is no longer available.


DirectSound VxD Exports

In addition to the version service, the DirectSound virtual device driver, (Dsound.vxd), exports two services: a registration service and a deregistration service. DirectSound drivers should call these services in response to the appropriate configuration manager messages. Both services accept a pointer to an IDsDriver interface and a doubleword of flags. No flags are currently defined; the value must be zero in this implementation.

With the exception of the registration and deregistration calls, all communication is initiated by DirectSound by calling the IDsDriver interface or other interfaces that DirectSound obtains through IDsDriver.


Registering a Driver

It is best to register a DirectSound driver only after all other CONFIG_START handling has been completed. When DirectSound receives the registration call, it assumes that the driver is ready to be accessed through its IDsDriver interface. Also, before calling the registration service, the DirectSound driver must first dynaload the Dsound.vxd module. It must then register with DirectSound by passing a pointer to its IDsDriver vtable of functions. The vtable, which is constructed by the driver, consists of pointers to the functions.

The following example illustrates how a driver might register itself with DirectSound. All driver-defined functions are prefixed by "Impl_" for clarity. The Impl_DsInitialize function would be called from the CONFIG_START handler of the audio driver.

const IDSDRIVERVTBL Impl_Vtable = {
    // These are all driver-defined functions.
    Impl_QueryInterface,
    Impl_AddRef,
    Impl_Release,
    Impl_GetDesc,
    Impl_Open,
    Impl_Close,
    Impl_GetCaps,
    Impl_CreateSoundBuffer
};

typedef struct {
    // You gotta have this first...
    const IDSDRIVERVTBL *pVtable;

    // ... and whatever other context info you need goes after.
    DEVNODE DevNode;
    PDEVICEINFO pdiDsoundVxd;
    ...
} DRIVERCONTEXT, *PDRIVERCONTEXT;

...

Impl_DsInitialize( DEVNODE dn )
{
    PDRIVERCONTEXT pDriverContext;
    PVMMDDB        pDDB;
    PDEVICEINFO    pdi;
    ULONG          uReturn;

    //  Allocate memory for DRIVERCONTEXT structure.
    pDriverContext = _HeapAllocate(sizeof(*pDriverContext), HEAPZEROINIT);
    if( pDriverContext )
    {
        // Fill in Vtable and other context info.
        pDriverContext->pVtable = &Impl_Vtable;
        pDriverContext->DevNode = dn;

        // Dynaload DSOUND.VXD and save ptr to device info
        uReturn = VXDLDR_LoadDevice(&pDDB, &pdi, "dsound.vxd", TRUE);
        if( !uReturn )
        {
            pDriverContext->pdiDSoundVxd = pdi;

            // Register this driver with DSOUND.VXD
            uReturn = DSOUND_RegisterDeviceDriver((PIDSDRIVER)pDriverContext,0);
                                                  // There are no flags currently defined.
            if( uReturn == DS_OK )
            {
                // Succeeded.  Probably want to save pDriverContext somewhere,
                //   associated with DevNode so we can find it again.
                Impl_SetDriverContext( dn, pDriverContext );
                ...
            } else {
                // Failed.
            }
        }
    }
}


Deregistering a Driver

The driver must deregister with DirectSound whenever the device is removed or when the system is shutting down. The configuration manager sends either CONFIG_STOP, CONFIG_SHUTDOWN, or CONFIG_REMOVE to the configuration handler. The driver must respond by undoing all the things done by the registration function: deregistering with DirectSound, unloading the Dsound.vxd module, and freeing any memory that was allocated for the IDsDriver interface. It is best to deregister the driver from DirectSound early in the handling of these CONFIG messages since DirectSound assumes the driver can be accessed through its IDsDriver interface until it deregisters.

The following example shows how a driver would deregister itself with DirectSound. The Impl_DsShutdown function would be called from the CONFIG_STOP, CONFIG_SHUTDOWN, and CONFIG_REMOVE handlers in the audio driver.

Impl_DsShutdown( DEVNODE dn )
{
    PDRIVERCONTEXT pDriverContext;

    // Retrieve pDriverContext from dn.
    pDriverContext = Impl_GetDriverContext( dn );
    if( pDriverContext )
    {
        // Destroy record of pDriverContext (since we're killing it).
        Impl_SetDriverContext( dn, NULL );

        // Deregister with DirectSound.
        DSOUND_DeregisterDeviceDriver( (PIDSDRIVER)pDriverContext, 0 );

        // Unload DSOUND.VXD module.
        VXDLDR_UnloadDevice( pDriverContext->pdiDSoundVxd->DI_DeviceID,
                             pDriverContext->pdiDSoundVxd->DI_ModuleName );

        // Free DRIVERCONTEXT structure.
        HeapFree( pDriverContext, 0 );
        }
}


DirectSound3D Windows 95 Device Driver Interface

Windows 95 DirectSound audio drivers can support 3-D audio acceleration by supporting the interfaces described in this document. The Windows 95 implementation of DirectSound accesses these interfaces to accelerate 3-D audio virtualization. Similar interfaces will be used in the future WDM audio port/miniport driver architecture, which is currently in design. Thus, development of these interfaces can be leveraged in the new driver architecture as well.

Current DirectSound drivers for Windows 95 support two classes of logical objects within the driver. These can be referred to as the DsDriver object and DsDriverBuffer object. These are the driver objects that support the IDsDriver and IDsDriverBuffer interfaces accessed by DirectSound.

A new interface, IDsDriverPropertySet, is defined in this document. This interface is a generic mechanism allowing drivers to extend DirectSound objects with new object properties. This interface is implemented by the driver developer on the driver objects mentioned above. Since the 3-D parameters of DirectSound can be viewed as properties, this new interface also serves well for passing 3-D parameters to the driver to accelerate DirectSound3D.

A similar interface, IKsPropertySet, is implemented in the DirectSound API on DirectSoundBuffer objects. When an application accesses the IKsPropertySet interface, DirectSound forwards those calls to the driver through the IDsDriverPropertySet interface. This is the mechanism by which a hardware manufacturer can provide vendor-specific extensions to the product.


DirectSound Property Sets

A property set is a collection of related properties. The notion of property sets is pervasive throughout the new WDM audio port/miniport driver model and the new Kernel Streaming architecture. DirectSound3D uses property sets as well to communicate with the driver for 3-D virtualization.

When dealing with properties, a globally unique identifier (GUID) identifies a set of properties, and a ULONG identifies a particular property within the set.

In addition to the property set identifier (the GUID) and the property identifier (the ULONG), additional parameters can be associated with the property. These parameters are separate from the actual values of the properties. Clients typically use these parameters to further specify a particular instance of the property on the object. The property set interface specifications for IDsDriverPropertySet and IKsPropertySet intentionally leave these parameters undefined. This allows the designer of the property set to use them in a way most beneficial to the properties within the set being designed. So, the precise meaning of these parameters is defined with the definition of the properties and should be provided by the vendor whose driver implements the property set.


Using IDsDriverPropertySet to Accelerate 3-D Audio Virtualization

The following topics are discussed in this section:

  • Supporting IDsDriverPropertySet in the Driver
  • Associating a 3D Buffer with Listener Properties


Supporting IDsDriverPropertySet in the Driver

A DirectSound driver for Windows 95 accelerates 3-D audio virtualization by supporting the IDsDriverPropertySet interface on its DsDriverBuffer objects. The mechanism for supporting this interface is the same as that for standard Component Object Model (COM) interfaces. The COM semantics for interfaces, in particular the methods of IUnknown, apply. Furthermore, the driver must support the necessary property sets through the IDsDriverPropertySet interface to properly support 3-D audio virtualization.

After obtaining the IDsDriverBuffer interface from one of the driver's DsDriverBuffer objects, DirectSound calls QueryInterface to obtain the IDsDriverPropertySet interface on the DsDriverBuffer object. Once DirectSound has an IDsDriverPropertySet interface, it calls its QuerySupport method to determine whether the DsDriverBuffer supports the necessary property sets.

DirectSound uses three property sets to accelerate 3-D audio. As mentioned earlier, property sets are identified using a GUID. The GUIDs used for DirectSound3D acceleration are DSPROPSETID_DirectSoundSpeakerConfig, DSPROPSETID_DirectSound3DListener, and DSPROPSETID_DirectSound3DBuffer. The driver's primary DsDriverBuffer object should support the DSPROPSETID_DirectSoundSpeakerConfig and DSPROPSETID_DirectSound3DListener property sets. The driver's secondary DsDriverBuffer objects should support the DSPROPSETID_DirectSound3DBuffer property set.

When DirectSound calls the driver to create a secondary buffer that supports 3-D audio acceleration, it specifies the DSBCAPS_CTRL3D flag in the dwFlags parameter of IDsDriver::CreateSoundBuffer. DirectSound does not specify this flag when creating a primary buffer. However, DirectSound still queries a driver's primary buffer object for support of DSPROPSETID_DirectSound3DListener and DSPROPSETID_DirectSoundSpeakerConfig.


Associating a 3D Buffer with Listener Properties

In the DirectSound API, there may be multiple "listeners," one for each currently executing DirectSound 3-D application. Each listener has associated "3-D buffers." However, in the driver only one object supports the listener property set — the driver's primary buffer. Furthermore, the driver is not necessarily aware of any association between its secondary buffer objects and the applications that created them.

Additional information must be passed to the driver so that, when listener properties change, the driver knows which secondary buffers should be affected. Similarly, when a secondary buffer's 3-D properties are set, the driver must know which listener properties to reference when determining the 3-D effect.

To do this, DirectSound passes special data to the driver through the IDsDriverPropertySet::Get and IDsDriverPropertySet::Set methods. On any call to set a 3-D property for either listener or buffer, DirectSound passes a pointer to a 32-bit identifier that associates buffer and listener properties together. This 32-bit identifier is unique for each application using 3-D listener and buffer properties. See the reference section for information about the InstanceId member of the DSPROPERTY structure.

To help the DirectSound driver maintain its internal data structures, DirectSound notifies the driver when an application begins using 3-D audio hardware acceleration and when the application no longer uses 3-D audio hardware acceleration. DirectSound does this using the DSPROPERTY_DIRECTSOUND3DLISTENER_ALLOCATION property along with the 32-bit identifier described previously.


DirectSound Driver Capabilities

A Windows 95 DirectSound driver supporting 3-D audio acceleration should fill the members of the DSDRIVERCAPS structure to reflect such capability. The structure is repeated here.

typedef struct tDSDRIVERCAPS {
    DWORD       dwFlags;
    DWORD       dwMinSecondarySampleRate;
    DWORD       dwMaxSecondarySampleRate;
    DWORD       dwPrimaryBuffers;
    DWORD       dwMaxHwMixingAllBuffers;
    DWORD       dwMaxHwMixingStaticBuffers;
    DWORD       dwMaxHwMixingStreamingBuffers;
    DWORD       dwFreeHwMixingAllBuffers;
    DWORD       dwFreeHwMixingStaticBuffers;
    DWORD       dwFreeHwMixingStreamingBuffers;
    DWORD       dwMaxHw3DAllBuffers;
    DWORD       dwMaxHw3DStaticBuffers;
    DWORD       dwMaxHw3DStreamingBuffers;
    DWORD       dwFreeHw3DAllBuffers;
    DWORD       dwFreeHw3DStaticBuffers;
    DWORD       dwFreeHw3DStreamingBuffers;
    DWORD       dwTotalHwMemBytes;
    DWORD       dwFreeHwMemBytes;
    DWORD       dwMaxContigFreeHwMemBytes;
} DSDRIVERCAPS, *PDSDRIVERCAPS;

In particular, the dwMaxHw3DAllBuffers, dwMaxHw3DStaticBuffers, dwMaxHw3DStreamingBuffers, dwFreeHw3DAllBuffers, dwFreeHw3DStaticBuffers, and dwFreeHw3DStreamingBuffers members should be filled in properly by the driver.


Floating Point Issues in VxDs

This document implies that the DirectSound driver performs floating point operations in ring 0 of the CPU. Executing floating point operations in a VxD brings up several issues.

  • The original release of Windows 95 did not support execution of floating point operations in ring 0. When DirectX® 3 or later installs, it updates a part of Windows 95 to allow such operations. Drivers must not execute any floating point operations on Windows 95 unless DirectX 3 or later has been installed.
  • Execution of the floating point instructions must occur only within the IDsDriverPropertySet calls received by the driver from DirectSound. Drivers cannot execute floating point operations within an interrupt service routine (ISR) or virtual machine manager (VMM) event handler.
  • A floating point coprocessor must be installed in the system. The floating point emulator does not work at this level.
  • VxDs cannot link to a C run-time library. Therefore, the VxD author must use floating point sparingly in the C source code and/or must write floating point code in assembly language without relying on a C runtime library.

The DirectSound team realizes that these limitations may be serious hurdles for some driver developers. Depending on the level of interest in this specification the DirectSound team may either a) provide direct developer-to-developer support to overcome these issues, or b) provide a simple solution appropriate for all driver developers (that is, a minimal library providing some basic C run time floating point functions that a VxD can link).


DirectSound Reference

This section contains reference information for the API elements that DirectSound provides. Reference material is divided into the following categories:

• Interfaces

  • Property Sets
  • Structures
  • Return Values


Interfaces

This section contains reference information on the following DirectSound interfaces:

IDsDriver

IDsDriverBuffer

IDsDriverPropertySet


IDsDriver

The IDsDriver interface is the main control interface for the driver. It is used to create (or query for) other interfaces. The driver registers the vtable for this interface when it calls DSOUND_RegisterDeviceDriver in response to the CONFIG_START message from the Configuration Manager.

The IDsDriver interface contains the following methods:

  • AddRef
  • Close
  • CreateSoundBuffer
  • DuplicateSoundBuffer
  • GetCaps
  • GetDriverDesc
  • Open
  • QueryInterface
  • Release


IDsDriver::AddRef

The IDsDriver::AddRef method increases the object reference count by 1.

ULONG AddRef( );

Return Values

Returns the new reference count.

Remarks

When the object is initially created, its reference count should be set to one. Each time a function obtains an interface to the object or calls the AddRef method, the reference count should be increased by 1. The application uses the Release method to decrease the object's reference count by 1.

This method is part of the IUnknown interface inherited by the object.


IDsDriver::Close

The IDsDriver::Close method returns the object back to system use, that is, when DirectSound no longer requires use of the IDsDriver::CreateSoundBuffer, IDsDriver::DuplicateSoundBuffer, and IDsDriver::GetCaps methods.

HRESULT Close( );

Return Values

Returns DS_OK if successful, or DSERR_GENERIC otherwise.

Remarks

The driver should deallocate any structures it allocated on the IDsDriver::Open call, reset the hardware to a known state, and mark the device as unallocated. Once this method has been called, the Wave portion of the driver should be able to acquire the use of the hardware.

This method should not decrement the reference count on the DirectSound driver object. The reference count of an object should only be changed by the IUnknown members AddRef and Release.


IDsDriver::CreateSoundBuffer

The IDsDriver::CreateSoundBuffer method is called only when the device has been opened by DirectSound through a call to IDsDriver::Open. DirectSound calls this method to request the driver to create a hardware sound buffer with specific attributes. If the driver is able to create the sound buffer and allocate the required resources, it returns a pointer to an IDsDriverBuffer interface that DirectSound uses to control the sound buffer. Otherwise the driver fails the request by returning an error code.

HRESULT CreateSoundBuffer(
  LPWAVEFORMATEX pwfx,
  DWORD dwFlags,
  DWORD dwCardAddress,
  LPDWORD pdwcbBufferSize,
  LPBYTE *ppbBuffer,
  LPVOID *ppvObj
 );

Parameters

pwfx
Pointer to a WAVEFORMATEX structure that contains a description of the desired wave format for the sound buffer. If the device cannot create a sound buffer with that format, it should fail the call by returning DSERR_BADFORMAT.
dwFlags
The creation flags for this sound buffer. Note that these flags are a subset of those used by the IDirectSound::CreateSoundBuffer method; DirectSound intercepts and uses some of the flags so the driver does not have to worry about them.
DSBCAPS_PRIMARYBUFFER
Primary buffer requested. If this flag is not specified, the application should attempt to create a secondary buffer. DirectSound only attempts to create secondary buffers if the driver has indicated (through the DSDRIVERCAPS structure returned by IDsDriver::GetCaps) that it supports secondary hardware buffers.
DSBCAPS_CTRLFREQUENCY
DSBCAPS_CTRLPAN
DSBCAPS_CTRLVOLUME
These flags specify the controls required for the buffer. If these controls are not available, the driver should fail by returning DSERR_CONTROLUNAVAIL. Note that drivers should fail to create primary buffers if volume or pan control is requested; in the current release this doesn't work because of conflicts with the Windows 95 mixer controls.
DSBCAPS_CTRL3D
Specified only for secondary buffers. Specifies that the secondary buffer requires 3-D audio acceleration.
dwCardAddress
If the device has onboard sound memory and the driver requests that DirectSound or DirectDraw manage the heap (that is, the driver specifies DSDHEAP_CREATEHEAP or DSDHEAP_USEDIRECTDRAWHEAP), this method points to the card address of the sound memory to be used by this buffer. DirectSound guarantees that this memory is free and is large enough to contain the buffer.
pdwcbBufferSize
Pointer to a doubleword containing the requested size of the sound buffer. As an input parameter, it contains the buffer size requested by the calling application. For primary buffers, it may also be an output parameter if the hardware imposes restrictions on the size of the buffer. For example, for DMA-based cards, the driver should fill in this value with the size of the DMA buffer allocated on startup.
ppbBuffer
Pointer to a value containing the start address (that is, a pointer to a pointer) of the buffer memory. If this is a secondary buffer and the driver specified the DSDDESC_USESYSTEMMEMORY flag in the DSDRIVERDESC structure returned by the IDsDriver::GetDriverDesc call, *ppbBuffer is initialized with a pointer to the system memory allocated by DirectSound.
ppvObj
Pointer to an interface pointer that receives the IDsDriverBuffer interface to the buffer object created by the driver. If no buffer object and interface are created (that is, if the creation request fails), the driver should set the interface pointer to NULL.

Return Values

Returns DS_OK if successful, or one of the following error values otherwise:

DSERR_ALLOCATED

DSERR_INVALIDPARAM

DSERR_OUTOFMEMORY

DSERR_BADFORMAT

Remarks

The requested size of the buffer is passed in a doubleword pointed to by the lpdwRequestedSize parameter. When creating a primary buffer (that is, the DSBCAPS_PRIMARYBUFFER flag is specified), the driver may change this value to conform to hardware limitations (such as DMA buffer size). For secondary buffers, this value must not be changed.

If a secondary buffer is requested and the driver specifies the DSDDESC_USESYSTEMMEMORY flag in the DSDRIVERDESC structure returned by the IDsDriver::GetDriverDesc method, DirectSound allocates system memory for the buffer and passes a pointer to this memory in the location pointed to by ppbBuffer. The buffer will be large enough to contain the number of bytes specified in *pdwcbBufferSize. The driver must use this memory or fail the call. If the driver needs to allocate its own memory, it should do so for all buffers and not use the DSDDESC_USESYSTEMMEMORY flag.

If a primary buffer is requested or the driver does not specify the DSDDESC_USESYSTEMMEMORY flag, no memory is allocated and the ppbBuffer parameter points to a NULL pointer. The driver should allocate the required buffer memory and return a pointer to this memory in the value pointed to by ppbBuffer.

The driver should always check the DSBCAPS_CTRLxxx flags passed in the dwFlags parameter. If the driver cannot create a buffer with the requested control attributes, it should fail the creation request. If the driver succeeds the creation request, it is required to succeed the control requests (IDsDriverBuffer::SetVolumePan, and so on) when called on this buffer.

If the device has onboard sound memory and the driver requests that DirectSound or DirectDraw manage the heap (that is, the driver fills in the dwMemStartAddress and dwMemEndAddress members and specifies the DSDHEAP_CREATEHEAP or DSDHEAP_USEDIRECTDRAWHEAP flags in the DSDRIVERDESC structure), this method points to the card address of the sound memory to be used by this buffer. DirectSound guarantees that this memory is free and is large enough to contain the buffer. Otherwise this parameter is set to zero.

Due to internal contention-management code in DirectSound, drivers should always make sure that the buffer memory for primary buffers is page-locked.


IDsDriver::DuplicateSoundBuffer

The IDsDriver::DuplicatesSoundBuffer method is called only when the device has been opened by DirectSound through a call to IDsDriver::Open. This method requests that the driver duplicate an existing sound buffer. This means that the two buffers should share sound buffer memory, but all other operations and parameters should be separate. Both buffers should be playable simultaneously with different play cursors. Different volume, pan, and frequency controls should be independently modifiable, although the initial settings should be the same as the original buffer. The driver should create a duplicate buffer object and return its interface pointer in *ppv.

If the driver is unable to create a duplicate buffer which uses the same memory, it should fail the call. It should not try to allocate a new hardware memory block and copy the data, nor should it attempt to emulate the buffer in software. DirectSound takes care of these actions.

HRESULT DuplicateSoundBuffer(
  PIDSDRIVERBUFFER pIDsDriverBuffer,
  LPVOID *ppv
 );

Parameters

pIDsDriverBuffer
Pointer to the IDsDriverBuffer interface of the original sound buffer which is being duplicated.
ppv
Pointer to an interface pointer that receives the IDsDriverBuffer interface created by the driver. If no interface iscreated (that is, if the creation request fails), the driver should set the interface pointer to NULL.

Return Values

If called on a primary buffer, the driver should return DSERR_INVALIDCALL.

Returns DS_OK if successful, or one of the following error values otherwise:

DSERR_ALLOCATED

DSERR_INVALIDPARAM

DSERR_OUTOFMEMORY

DSERR_BADFORMAT


IDsDriver::GetCaps

The IDsDriver::GetCaps method is called only when the device has been opened by DirectSound through a call to IDsDriver::Open. This method requests that the driver fill in the DSDRIVERCAPS structure with the DirectSound capabilities of the hardware device. This includes information such as the number of hardware mixing channels, amount of on-board sound memory, and so on. This information is passed back to applications to allow them to optimize resource allocation. The DSDRIVERCAPS structure contains information about the maximum capabilities of the sound device, and about the currently available capabilities. The maximum capabilities must remain constant; the parameters describing the free resources must be calculated each time this method is called.

HRESULT GetCaps(
  PDSDRIVERCAPS pDsDrvCaps
 );

Parameters

pDsDrvCaps
Pointer to the DSDRIVERCAPS structure that the driver should fill in and return to DirectSound.

Return Values

Returns DS_OK if successful, or DSERR_INVALIDPARAM otherwise.


IDsDriver::GetDriverDesc

The IDsDriver::GetDriverDesc method requests that the driver fill in the DSDRIVERDESC structure with a description of the DirectSound device driver. This includes information about the driver module, and a description of the heap management services requested by the driver.

HRESULT GetDriverDesc(
  PDSDRIVERDESC pDsDriverDesc
 );

Parameters

pDsDriverDesc
Pointer to the DSDRIVERDESC structure that the driver should fill in and return to DirectSound.

Return Values

Returns DS_OK if successful, or DSERR_INVALIDPARAM otherwise.

Remarks

This is the only member of IDsDriver (except for the IUnknown methods) that DirectSound calls before calling IDsDriver::Open. The driver should always succeed this call.


IDsDriver::QueryInterface

The IDsDriver::QueryInterface method determines whether the object supports a particular COM interface. If it does, the system increases the object's reference count by 1, and the application can use that interface immediately.

HRESULT QueryInterface(
  REFIID riid,
  LPVOID FAR* ppvObj
 );

Parameters

riid
Reference identifier of the interface being requested.
ppvObj
Address of a pointer that will be filled with the returned interface pointer if the query succeeds.

Return Values

Returns DS_OK if successful, or one of the following error values otherwise:

DSERR_INVALIDPARAM

DSERR_NOINTERFACE

Remarks

When the application no longer needs to use the interface retrieved by a call to this method, it calls the Release method for that interface to free it. The QueryInterface method allows Microsoft and third parties to extend objects without interfering with existing or future functionality.

This method is part of the IUnknown interface inherited by the object.

This object must support IUnknown and IDsDriver. Both interfaces should be accessible through this method. Note, however, that IDsDriverBuffer should not be accessible through this method. Sound buffer objects are separate (although related) objects, so IDsDriverBuffer should only be accessible by calling IDsDriver::CreateSoundBuffer.


IDsDriver::Release

The IDsDriver::Release method increases the object's reference count by 1.

ULONG Release( );

Return Values

Returns the new reference count.

Remarks

When the object is created, its reference count is set to 1. Every time an application obtains an interface to the object or calls the AddRef method, the object's reference count is increased by 1. Use the Release method to decrease the object's reference count by 1.

This method is part of the IUnknown interface inherited by the object.


IDsDriverBuffer

The IDsDriverBuffer interface is used to manipulate individual sound buffers, which are separate objects from the main driver object (which supports IDsDriver). The IDsDriver::CreateSoundBuffer method creates a sound buffer object and returns an IDsDriverBuffer interface. A DirectSound driver is only required to implement sound buffer objects for hardware sound buffers (that is, the primary streaming sound buffer, and sound buffers located in onboard memory). DirectSound takes care of implementing software buffers.

The IDsDriverBuffer interface contains the following methods:

  • AddRef
  • GetPosition
  • Lock
  • Play
  • QueryInterface
  • Release
  • SetFormat
  • SetFrequency
  • SetPosition
  • SetVolumePan
  • Stop
  • Unlock


IDsDriverBuffer::AddRef

The IDsDriverBuffer method increases the object's reference count by 1.

ULONG AddRef( );

Return Values

Returns the new reference count.

Remarks

When the object is initially created, its reference count should be set to 1. Each time a function obtains an interface to the object or calls the AddRef method, the reference count should be increased by 1. The application uses the Release method to decrease the object's reference count by 1.

This method is part of the IUnknown interface inherited by the object.


IDsDriverBuffer::GetPosition

The IDsDriverBuffer::GetPosition method is called when DirectSound is querying the current position of the specified sound buffer.

HRESULT GetCurrentPosition(
  LPDWORD lpdwCurrentPlayCursor,
  LPDWORD lpdwCurrentWriteCursor
 );

Parameters

lpdwCurrentPlayCursor

Pointer to a doubleword into which the driver should write the current play cursor.

lpdwCurrentWriteCursor

Pointer to a doubleword into which the driver should write the current write cursor.

Return Values

Returns DS_OK if successful, or one of the following error values otherwise:

DSERR_INVALIDCALL

DSERR_INVALIDPARAM

Remarks

The driver returns two values: the current play cursor, and the current write cursor. The play cursor is the position which is currently being played. The write cursor is the next position at which it is acceptable to write new data into the buffer. The write cursor should be as close as possible to the play cursor — preferably within one or two samples. Note that DirectSound does not return these exact values to applications; instead it adds a buffer zone of about 10 milliseconds to the write cursor to cover multi-tasking delays, and so on.

Some hardware may not be able to notify DirectSound when a one-shot buffer has finished playing. Therefore, if the driver returns a position that is equal to the length of the buffer, DirectSound assumes that the buffer has finished playing and should stop. DirectSound then calls IDsDriverBuffer::Stop on that buffer. This should only happen for one-shot secondary buffers.


IDsDriverBuffer::Lock

The IDsDriverBuffer::Lock method is called to obtain a valid write pointer to the sound buffer's audio data.

HRESULT Lock(
  LPLPVOID ppvAudio1,
  LPDWORD pdwLen1,
  LPLPVOID ppvAudio2,
  LPDWORD pdwLen2,
  DWORD dwWritePosition,
  DWORD dwWriteLen,
  DWORD dwFlags
 );

Parameters

ppvAudio1
Pointer to a value that the driver must fill in with a pointer to the first block of sound data.
pdwLen1
Pointer to a doubleword that the driver must fill in with the number of bytes pointed to by *ppvAudio1.
ppvAudio2
Pointer to a value that the driver must fill in with a pointer to the second block of sound data. If the first block (pointed to by *ppvAudio1) points to the entire block of requested data, this value should be set to NULL.
pdwLen2
Pointer to a doubleword that the driver must fill in with the number of bytes pointed to by *ppvAudio2. If *ppvAudio2 is NULL, this value must be set to zero.
dwWritePosition
The position relative to the start of the buffer that should be locked, and therefore subject to change by the locking application.
dwWriteLen
The number of bytes relative to the write position that will be locked, and therefore subject to change by the locking application.
dwFlags
No flags are currently defined. This value will always be 0.

Return Values

Returns DS_OK if successful, or one of the following error values otherwise:

DSERR_INVALIDCALL

DSERR_INVALIDPARAM

DSERR_BUFFERLOST

Remarks

This method accepts an offset and a count of bytes, and the driver returns two write pointers and their associated sizes. Two pointers are required because sound buffers are circular. If the locked bytes do not wrap around the end of the buffer, the second pointer (*ppvAudio2) should be NULL. However, if the bytes do wrap around, the second pointer should point to the beginning of the buffer.

For some devices (such as DMA-based cards that do not support hardware secondary buffers), repeated calls to IDsDriverBuffer::Lock and IDsDriverBuffer::Unlock are unnecessary. In this case, the driver should specify the DSDCAPS_DONTNEEDLOCK flag in the DSDRIVERDESC structure returned by IDsDriver::GetDriverDesc method. If this flag is specified, then the IDsDriverBuffer::Lock method is never called by DirectSound. In that case, the IDsDriverBuffer::Lock method should simply return DSERR_UNSUPPORTED.


IDsDriverBuffer::Play

The IDsDriverBufffer::Play method causes the sound buffer to start playing from the current position.

HRESULT Play(
  DWORD dwReserved1,
  DWORD dwReserved2,
  DWORD dwFlags
 );

Parameters

dwReserved1
This parameter is reserved for future use, and must not be used or accessed for this release.
dwReserved2
This parameter is reserved for future use, and must not be used or accessed for this release.
dwFlags
Indicates how to play the buffer.
DSBPLAY_LOOPING
Play indefinitely, looping back to the beginning of the buffer when the end is reached. If this flag is not specified, the buffer stops playing when it reaches the end of the buffer memory.

Return Values

Returns DS_OK if successful, or one of the following error values otherwise:

DSERR_INVALIDCALL

DSERR_INVALIDPARAM

DSERR_BUFFERLOST

Remarks

The application is responsible for creating sound data that has the proper ramping effects before the sound buffer is started. If the sound buffer was created with the DSBCAPS_PRIMARYBUFFER flag, this method causes the primary sound buffer to start playing to the sound device. Otherwise, this method causes the sound buffer to be mixed into the primary sound buffer which is then output to the sound device.

If this method is called on a buffer that is already playing, the driver should succeed the call. If the dwFlags parameter specifies different flags than that specified in the original call, the driver should modify the behavior of this buffer to reflect the new flags.

If the DSBPLAY_LOOPING flag is not specified, the driver must ensure that the buffer stops playing when the play cursor reaches the end. When this happens, the driver should reset the current position to zero (that is, if IDsDriverBuffer::Play is called subsequently, the buffer should begin playing from the beginning of the buffer).


IDsDriverBuffer::QueryInterface

The IDsDriverBuffer::QueryInterface method determines whether the object supports a particular COM interface. If it does, the system increases the object's reference count, and the application can use that interface immediately.

HRESULT QueryInterface(
  REFIID riid,
  LPVOID FAR* ppvObj
 );

Parameters

riid
Reference identifier of the interface being requested.
ppvObj
Address of a pointer that will be filled with the returned interface pointer if the query succeeds.

Return Values

Returns DS_OK if successful, or one of the following error values otherwise:

DSERR_INVALIDPARAM

DSERR_NOINTERFACE

Remarks

When the application no longer needs to use the interface retrieved by a call to this method, it calls the Release method for that interface to free it. The QueryInterface method allows Microsoft and third parties to extend objects without interfering with each other's existing or future functionality.

This method is part of the IUnknown interface inherited by the object.

This object must support the IUnknown interface in addition to IDsDriverBuffer. Note, however, that interfaces on the main driver object (such as IDsDriver) must not be accessible through this method (that is, this method should return DSERR_NOINTERFACE if queried for them). This is because the main driver object is a separate (though related) COM object from sound buffer objects.


IDsDriverBuffer::Release

The IDsDriverBuffer::Release method increases the object's reference count by 1.

ULONG Release( );

Return Values

Returns the new reference count.

Remarks

When the object is created, its reference count is set to 1. Every time an application obtains an interface to the object or calls the AddRef method, the object's reference count is increased by 1. Use the Release method to decrease the object's reference count by 1.

This method is part of the IUnknown interface inherited by the object.


IDsDriverBuffer::SetFormat

The IDsDriverBuffer::SetFormat method sets the format of the primary sound buffer to the format described in the WAVEFORMATEX structure.

HRESULT SetFormat(
  LPWAVEFORMATEX pwfxToSet
 );

Parameters

pwfxToSet
Pointer to a WAVEFORMATEX structure that describes the new format desired for the primary sound buffer.

Return Values

Returns DS_OK if successful, or one of the following error values otherwise:

DSERR_BADFORMAT

DSERR_INVALIDCALL

DSERR_INVALIDPARAM

Remarks

This method is only valid for primary sound buffers; DirectSound never calls this method for secondary buffers. DirectSound guarantees that this method isnever called when the buffer is playing.

This call has two meanings. If the driver did not specify the DSDDESC_DOMMSYSTEMSETFORMAT flag, this call requests the driver to change the buffer's format to the specified format. However, if the driver specified the DSDDESC_DOMMSYSTEMSETFORMAT flag, this call notifies the driver that the format was just set through the Wave APIs. The driver may perform extra processing if necessary; in this case it should return DS_OK. If it does no processing, it should return DSERR_UNSUPPORTED.


IDsDriverBuffer::SetFrequency

The method sets the frequency at which the audio samples are to be played. This call does not affect the format of the buffer.

HRESULT SetFrequency(
  DWORD dwFrequency
 );

Parameters

dwFrequency
The frequency (in samples per second) at which the samples are to be played. This value must be between 100 and 100000.

Return Values

Returns DS_OK if successful, or one of the following error values otherwise:

DSERR_INVALIDCALL

DSERR_INVALIDPARAM

Remarks

DirectSound only calls this method if the sound buffer object is created with the DSBCAPS_CTRLFREQUENCY flag. If the sound device cannot support frequency control, the driver should fail IDsDriver::CreateSoundBuffer whenever the DSBCAPS_CTRLFREQUENCY flag is specified.


IDsDriverBuffer::SetPosition

The IDsDriverBuffer::SetPosition method moves the sound buffer's play cursor to the specified offset.

HRESULT SetPosition(
  DWORD dwNewPosition
 );

Parameters

dwNewPosition
Specifies the new position of the play cursor.

Return Values

Returns DS_OK if successful, or one of the following values otherwise:

DSERR_INVALIDCALL

DSERR_INVALIDPARAM

Remarks

If the buffer is currently playing, the buffer should immediately jump to the new location and continue playing. If the device cannot set the position (on DMA-based primary buffers, for example), the driver should return DSERR_UNSUPPORTED.


IDsDriverBuffer::SetVolumePan

The IDsDriverBuffer::SetVolumePan method sets the volume and pan of the sound buffer to the value specified by the lVolume member of the DSVOLUMEPAN structure.

HRESULT SetVolumePan(
  PDSVOLUMEPAN pDsVolumePan
 );

Parameters

pDsVolumePan
Pointer to a DSVOLUMEPAN structure describing the new volume and pan settings, in dB and in linear form.

Return Values

Returns DS_OK if successful, or one of the following error values otherwise:

DSERR_INVALIDCALL

DSERR_INVALIDPARAM

Remarks

DirectSound only calls this method if the sound buffer object was created with the DSBCAPS_CTRLVOLUME flag, the DSBCAPS_CTRLPAN flag, or both. If the sound device cannot support these controls, the driver should fail the IDsDriver::CreateSoundBuffer call whenever those control flags are specified.

The DirectSound API specifies volume in hundredths of decibels (dB), where 0 is the original volume of the stream (no adjustment done). Positive decibels correspond to amplification, and negative decibels correspond to attenuation. The decibel (dB) scale corresponds to the logarithmic hearing characteristics of the ear: positive decibels . An attenuation of 10 dB makes a buffer sound half as loud; an attenuation of 20 dB makes a buffer sound one quarter as loud. DirectSound volumes range from 0 (0 dB, no volume adjustment) to -10000 (-100 dB, basically silent). Amplification is not currently supported.

The DirectSound API also specifies pan in hundredths of dB, in the range of -10000 to 10000. Zero is the neutral value; a pan of 0 means that both channels are at full volume (that is, they are attenuated by 0 dB). At any other setting, one of the channels is at full volume and the other is attenuated. For example, a pan of -2173 means that the left channel is at full volume and the right channel is attenuated by 21.73 dB. Similarly, a pan of 870 means that the left channel is attenuated by 8.7 dB and the right channel is at full volume. A pan of -10000 means that the right channel is silent (the sound is "all the way to the left"), and a pan of 10000 means that the left channel is silent (the sound is "all the way to the right"). Many readers may consider this behavior to be "balance" rather than "pan".

The volume and pan values are passed to DirectSound drivers in a DSVOLUMEPAN structure. Although both are specified, if the buffer only supports one or the other, the values reflect only the supported control. The structure specifies the input volume and pan (in hundredths of dB) in the lVolume and lPan members. It also provides the linear equivalents in a fixed point 16.16 representation in the dwVolAmpFactor member (for volume) and the dwPanLeftAmpFactor and dwPanRightAmpFactor members (for pan). Finally, since volume and pan are cumulative, it specifies the total combined linear factors in the dwTotalLeftAmpFactor and dwTotalRightAmpFactor members. Drivers should use the values that are most convenient.


IDsDriverBuffer::Stop

The IDsDriverBuffer::Stop method causes the sound buffer to stop playing.

HRESULT Stop( );

Return Values

Returns DS_OK if successful, or one of the following error values otherwise:

DSERR_INVALIDCALL

DSERR_INVALIDPARAM

Remarks

For primary buffers, the driver should set the current position to zero (the beginning of the buffer) when this method is called. For secondary buffers, the driver should set the current position of the buffer to the sample after the last sample played (don't reset it to zero).


IDsDriverBuffer::Unlock

The IDsDriverBuffer::Unlock method releases a block of sound data to the driver. The driver should perform whatever actions are necessary to output the audio data to the sound device.

HRESULT Unlock(
  LPVOID pvAudio1,
  DWORD dwLen1,
  LPVOID pvAudio2,
  DWORD dwLen2
 );

Parameters

pvAudio1
Pointer to the beginning of the first audio block.
dwLen1
The number of bytes written to pvAudio1.
pvAudio2
Pointer to the beginning of the second audio block.
dwLen2
The number of bytes written to pvAudio2.

Return Values

Returns DS_OK if successful, or one of the following error values otherwise:

DSERR_INVALIDCALL

DSERR_INVALIDPARAM

Remarks

The data block is actually described by two pointers; both are required because sound buffers are circular. If the locked bytes do not wrap around the end of the buffer, the second pointer (pvAudio2) is NULL. However, if the bytes do wrap around, then the second pointer points to the beginning of the buffer.

Each call to IDsDriverBuffer::Unlock is preceded by a corresponding call to IDsDriverBuffer::Lock. The pointer parameters are always the same pointers as those returned by IDsDriverBuffer::Lock. However, the number of bytes unlocked may be less than the number of bytes locked if the application does not fill the locked region. See IDsDriverBuffer::Lock for more details.

For some devices (such as DMA-based cards that do not support hardware secondary buffers), repeated calls to IDsDriverBuffer::Lock and IDsDriverBuffer::Unlock are unnecessary. In this case, the driver should specify the DSDCAPS_DONTNEEDLOCK flag in the DSDRIVERDESC structure returned by IDsDriver::GetDriverDesc method. If this flag is specified, then the IDsDriverBuffer::Unlock method is never called by DirectSound. In that case, the IDsDriverBuffer::Unlock method should simply return DSERR_UNSUPPORTED.


IDsDriverPropertySet

The IDsDriverPropertySet methods allow clients to query for support of a particular property, retrieve the current value of a property, and set the current value of a property.

The IDsDriverPropertySet interface contains the following methods:

  • AddRef
  • Get
  • QueryInterface
  • QuerySupport
  • Release
  • Set


IDsDriverPropertySet::AddRef

The IDsDriverPropertySet::AddRef method increases the object reference count by 1.

ULONG AddRef( );

Return Values

Returns the new reference count.

Remarks

When the object is initially created, its reference count should be set to one. Each time a function obtains an interface to the object or calls the AddRef method, the reference count should be increased by 1. The application uses the Release method to decrease the object's reference count by 1.

This method is part of the IUnknown interface inherited by the object.


IDsDriverPropertySet::Get

The IDsDriverPropertySet::Get method retrieves the current value of a property. This method copies the value of the property to the buffer pointed to by pPropertyData.

Get(
  PDSPROPERTY pDsProperty,
  LPVOID pPropertyParams,
  ULONG cbPropertyParams,
  LPVOID pPropertyData,
  ULONG cbPropertyData,
  PULONG pcbReturnedData
 );

Parameters

pDsProperty
Pointer to the property being queried. See the reference for the DSPROPERTY structure.
pPropertyParams
Pointer to instance parameters for the property.
cbPropertyParams
Size of the buffer pointed to by pPropertyParams.
pPropertyData
Pointer to a buffer in which to store the value of the property.
cbPropertyData
Size of the buffer pointed to by pPropertyData.
pcbReturnedData
Pointer to a ULONG in which to store the number of bytes returned in the buffer specified by pPropertyData.


IDsDriverPropertySet::QueryInterface

The IDsDriverPropertySet::QueryInterface method determines whether the object supports a particular COM interface. If it does, the system increases the object's reference count, and the application can use that interface immediately.

HRESULT QueryInterface(
  REFIID riid,
  LPVOID FAR* ppvObj
 );

Parameters

riid
Reference identifier of the interface being requested.
ppvObj
Address of a pointer that will be filled with the returned interface pointer if the query succeeds.

Return Values

Returns DS_OK if successful, or one of the following error values otherwise:

DSERR_INVALIDPARAM

DSERR_NOINTERFACE

Remarks

When the application no longer needs to use the interface retrieved by a call to this method, it calls the Release method for that interface to free it. The QueryInterface method allows Microsoft and third parties to extend objects without interfering with each other's existing or future functionality.

This method is part of the IUnknown interface inherited by the object.

This object must support the IUnknown interface in addition to IDsDriverBuffer. Note, however, that interfaces on the main driver object (such as IDsDriver) must not be accessible through this method (that is, this method should return DSERR_NOINTERFACE if queried for them). This is because the main driver object is a separate (though related) COM object from sound buffer objects.


IDsDriverPropertySet::QuerySupport

The IDsDriverPropertySet::QuerySupport method determines whether a property set, or a property within a property set, is supported by the object.

QuerySupport(
  REFGUID PropertySetId,
  ULONG PropertyId,
  PULONG pSupport
 );

Parameters

PropertySetId
Identifies the property set.
PropertyId
Identifies the property within the property set.
pSupport
Pointer to a ULONG in which to store flags indicating the support provided by the driver.
KSPROPERTY_SUPPORT_GET
The driver sets this flag to indicate that the property can be read using the IDsDriverPropertySet::Get method.
KSPROPERTY_SUPPORT_SET
The driver sets this flag to indicate that the property can be written using the IDsDriverPropertySet::Set method.

Remarks

Whether it is valid to support some properties within the set but not others depends on the definition of the property set. Consult the hardware manufacturer's specification for the property set of interest.


IDsDriverPropertySet::Release

The IDsDriverPropertySet::Release method increases the object's reference count by 1.

ULONG Release( );

Return Values

Returns the new reference count.

Remarks

When the object is created, its reference count is set to 1. Every time an application obtains an interface to the object or calls the AddRef method, the object's reference count is increased by 1. Use the Release method to decrease the object's reference count by 1.

This method is part of the IUnknown interface inherited by the object.


IDsDriverPropertySet::Set

The IDsDriverPropertySet::Set method sets the current value of a property to the value stored in the buffer pointed to by pPropertyData.

Set(
  PDSPROPERTY pDsProperty,
  LPVOID pPropertyParams,
  ULONG cbPropertyParams,
  LPVOID pPropertyData,
  ULONG cbPropertyData
 );

Parameters

pDsProperty
Pointer to the property being queried. See the reference for the DSPROPERTY structure.
pPropertyParams
Pointer to instance parameters for the property.
cbPropertyParams
Size of the buffer pointed to by pPropertyParams.
pPropertyData
Pointer to a buffer that contains the value to which to set the property.
cbPropertyData
Size of the buffer pointed to by pPropertyData.


Property Sets

This section contains reference information for the following property sets used with DirectSound:

  • DSPROPSETID_DirectSound3Dlistener
  • DSPROPSETID_DirectSound3Dbuffer
  • DSPROPSETID_DirectSoundSpeakerConfig


DSPROPSETID_DirectSound3DListener

The following properties are available in this property set:

  • DSPROPERTY_DIRECTSOUND3DLISTENER_ALL
  • DSPROPERTY_DIRECTSOUND3DLISTENER_POSITION
  • DSPROPERTY_DIRECTSOUND3DLISTENER_VELOCITY
  • DSPROPERTY_DIRECTSOUND3DLISTENER_ORIENTATION
  • DSPROPERTY_DIRECTSOUND3DLISTENER_DISTANCEFACTOR
  • DSPROPERTY_DIRECTSOUND3DLISTENER_ROLLOFFFACTOR
  • DSPROPERTY_DIRECTSOUND3DLISTENER_DOPPLERFACTOR
  • DSPROPERTY_DIRECTSOUND3DLISTENER_BATCH
  • DSPROPERTY_DIRECTSOUND3DLISTENER_ALLOCATION


DSPROPERTY_DIRECTSOUND3DLISTENER_ALL

LPULONG           pulListenerId = pDsProperty->InstanceId;
LPDS3DLISTENER    pDs3dListener = pPropertyData;

Members

pulListenerId
Pointer to a buffer containing a 32-bit value identifying the listener to which these parameters apply.
pDs3dListener
Pointer to a DS3DLISTENER structure containing all the 3-D listener parameters. Information about the DS3DLISTENER structure can be found in the DirectX SDK documentation.


DSPROPERTY_DIRECTSOUND3DLISTENER_POSITION

LPULONG        pulListenerId = pDsProperty->InstanceId;
LPD3DVECTOR    pPosition = pPropertyData;

Members

pulListenerId
Pointer to a buffer containing a 32-bit value identifying the listener to which these parameters apply.
pPosition
Pointer to a D3DVECTOR structure containing the position vector of the 3-D listener. Information about D3DVECTOR can be found in the DirectX SDK documentation.


DSPROPERTY_DIRECTSOUND3DLISTENER_VELOCITY

LPULONG        pulListenerId = pDsProperty->InstanceId;
LPD3DVECTOR    pVelocity = pPropertyData;

Members

pulListenerId
Pointer to a buffer containing a 32-bit value identifying the listener to which these parameters apply.
pVelocity
Pointer to a D3DVECTOR structure containing the velocity vector of the 3-D listener. Information about D3DVECTOR can be found in the DirectX SDK documentation.


DSPROPERTY_DIRECTSOUND3DLISTENER_ORIENTATION

LPULONG           pulListenerId = pDsProperty->InstanceId;
struct {
     D3DVECTOR vFront;
     D3DVECTOR vTop;
} *pOrientation = pPropertyData;

Members

pulListenerId
Pointer to a buffer containing a 32-bit value identifying the listener to which these parameters apply.
pOrientation
Pointer to a structure containing the orientation vectors of the 3-D listener.


DSPROPERTY_DIRECTSOUND3DLISTENER_DISTANCEFACTOR

LPULONG       pulListenerId = pDsProperty->InstanceId;
LPD3DVALUE    pflDistanceFactor = pPropertyData;

Members

pulListenerId
Pointer to a buffer containing a 32-bit value identifying the listener to which these parameters apply.
pflDistanceFactor
Pointer to a D3DVALUE containing the distance factor for the 3-D listener. Information about D3DVALUE can be found in the DirectX SDK documentation.


DSPROPERTY_DIRECTSOUND3DLISTENER_ROLLOFFFACTOR

LPULONG       pulListenerId = pDsProperty->InstanceId;
LPD3DVALUE    pflRolloffFactor = pPropertyData;

Members

pulListenerId
Pointer to a buffer containing a 32-bit value identifying the listener to which these parameters apply.
pflRolloffFactor
Pointer to a D3DVALUE containing the rolloff factor for the 3-D listener. Information about D3DVALUE can be found in the DirectX SDK documentation.


DSPROPERTY_DIRECTSOUND3DLISTENER_DOPPLERFACTOR

LPULONG       pulListenerId = pDsProperty->InstanceId;
LPD3DVALUE    pflDopplerFactor = pPropertyData;

Members

pulListenerId
Pointer to a buffer containing a 32-bit value identifying the listener to which these parameters apply.
pflDopplerFactor
Pointer to a D3DVALUE containing the Doppler factor for the 3-D listener. Information about D3DVALUE can be found in the DirectX SDK documentation.


DSPROPERTY_DIRECTSOUND3DLISTENER_BATCH

LPULONG    pulListenerId = pDsProperty->InstanceId;
LPBOOL     pfBatch = pPropertyData;

Members

pulListenerId
Pointer to a buffer containing a 32-bit value identifying the listener to which these parameters apply.
pfBatch
Pointer to a BOOL containing the batch mode setting for the 3-D listener.

When the batch property is TRUE (indicated in pfBatch), the driver must cache all subsequent changes to the listener properties and all associated buffer properties instead of putting them into effect immediately. When this property transitions from TRUE to FALSE, the driver must put all cached properties into effect immediately (and, ideally, simultaneously).


DSPROPERTY_DIRECTSOUND3DLISTENER_ALLOCATION

LPULONG    pulListenerId = pDsProperty->InstanceId;
BOOL       fAllocate = *(BOOL*)pPropertyData;

Members

pulListenerId
Pointer to a buffer containing a 32-bit value identifying the listener to which these parameters apply.
fAllocate
When DirectSound sets this to true, then the listener identified by *pulListenerId is new. The driver should allocate any resources necessary to support the new listener. When DirectSound sets this to false, then the listener identified by *pulListenerId is no longer using 3-D audio acceleration. The driver can free any resources associated with this listener.


DSPROPSETID_DirectSound3DBuffer

The following properties are available in this property set:

  • DSPROPERTY_DIRECTSOUND3DBUFFER_ALL
  • DSPROPERTY_DIRECTSOUND3DBUFFER_POSITION
  • DSPROPERTY_DIRECTSOUND3DBUFFER_VELOCITY
  • DSPROPERTY_DIRECTSOUND3DBUFFER_CONEANGLES
  • DSPROPERTY_DIRECTSOUND3DBUFFER_CONEORIENTATION
  • DSPROPERTY_DIRECTSOUND3DBUFFER_CONEOUTSIDEVOLUME
  • DSPROPERTY_DIRECTSOUND3DBUFFER_MINDISTANCE
  • DSPROPERTY_DIRECTSOUND3DBUFFER_MAXDISTANCE
  • DSPROPERTY_DIRECTSOUND3DBUFFER_MODE


DSPROPERTY_DIRECTSOUND3DBUFFER_ALL

LPULONG         pulListenerId = pDsProperty->InstanceId;
LPDS3DBUFFER    pDs3dBuffer = pPropertyData;

Members

pulListenerId
Pointer to a buffer containing a 32-bit value identifying the listener for which these parameters apply.
pDs3dBuffer
Pointer to a DS3DBUFFER structure containing all the 3-D buffer parameters. Information about the DS3DBUFFER structure can be found in the DirectX SDK documentation.


DSPROPERTY_DIRECTSOUND3DBUFFER_POSITION

LPULONG        pulListenerId = pDsProperty->InstanceId;
LPD3DVECTOR    pPosition = pPropertyData;

Members

pulListenerId
Pointer to a buffer containing a 32-bit value identifying the listener for which these parameters apply.
pPosition
Pointer to a D3DVECTOR containing the position vector of the buffer. Information about D3DVECTOR can be found in the DirectX SDK documentation.


DSPROPERTY_DIRECTSOUND3DBUFFER_VELOCITY

LPULONG        pulListenerId = pDsProperty->InstanceId;
LPD3DVECTOR    pVelocity = pPropertyData;

Members

pulListenerId
Pointer to a buffer containing a 32-bit value identifying the listener for which these parameters apply.
pVelocity
Pointer to a D3DVECTOR containing the velocity vector of the buffer. Information about D3DVECTOR can be found in the DirectX SDK documentation.


DSPROPERTY_DIRECTSOUND3DBUFFER_CONEANGLES

LPULONG      pulListenerId = pDsProperty->InstanceId;
struct {
    DWORD    dwInsideConeAngle;
    DWORD    dwOutsideConeAngle;
} *pConeAngles = pPropertyData;

Members

pulListenerId
Pointer to a buffer containing a 32-bit value identifying the listener for which these parameters apply.
pConeAngles
Pointer to a structure containing the cone angles of the buffer.


DSPROPERTY_DIRECTSOUND3DBUFFER_CONEORIENTATION

LPULONG        pulListenerId = pDsProperty->InstanceId;
LPD3DVECTOR    pConeOrientation = pPropertyData;

Members

pulListenerId
Pointer to a buffer containing a 32-bit value identifying the listener for which these parameters apply.
pConeOrientation
Pointer to a D3DVECTOR containing the cone orientation vector of the buffer. Information about D3DVECTOR can be found in the DirectX SDK documentation.


DSPROPERTY_DIRECTSOUND3DBUFFER_CONEOUTSIDEVOLUME

LPULONG    pulListenerId = pDsProperty->InstanceId;
LPLONG     plConeOutsideVolume = pPropertyData;

Members

pulListenerId
Pointer to a buffer containing a 32-bit value identifying the listener for which these parameters apply.
plConeOutsideVolume
Pointer to a LONG containing the cone outside volume of the sound buffer.


DSPROPERTY_DIRECTSOUND3DBUFFER_MINDISTANCE

LPULONG       pulListenerId = pDsProperty->InstanceId;
LPD3DVALUE    pflMinDistance = pPropertyData;

Members

pulListenerId
Pointer to a buffer containing a 32-bit value identifying the listener for which these parameters apply.
pflMinDistance
Pointer to a D3DVALUE containing the minimum distance for the buffer. Information about D3DVALUE can be found in the DirectX SDK documentation.


DSPROPERTY_DIRECTSOUND3DBUFFER_MAXDISTANCE

LPULONG       pulListenerId = pDsProperty->InstanceId;
LPD3DVALUE    pflMaxDistance = pPropertyData;

Members

pulListenerId
Pointer to a buffer containing a 32-bit value identifying the listener for which these parameters apply.
pflMaxDistance
Pointer to a D3DVALUE containing the maximum distance for the buffer. Information about D3DVALUE can be found in the DirectX SDK documentation.


DSPROPERTY_DIRECTSOUND3DBUFFER_MODE

LPULONG    pulListenerId = pDsProperty->InstanceId;
LPDWORD    pdwMode = pPropertyData;

Members

pulListenerId
Pointer to a buffer containing a 32-bit value identifying the listener for which these parameters apply.
pdwMode
Pointer to a DWORD containing the mode for the buffer.


DSPROPSETID_DirectSoundSpeakerConfig

The following property is available in this property set:

  • DSPROPSETID_DIRECTSOUNDSPEAKERCONFIG


DSPROPERTY_DIRECTSOUNDSPEAKERCONFIG

LPDWORD    lpdwSpeakerConfig = pPropertyData;

Members

lpdwSpeakerConfig
Pointer to a buffer containing a 32-bit value describing the physical speaker configuration. See the IDirectSound::GetSpeakerConfig and IDirectSound::SetSpeakerConfig in the DirectX SDK for a description of this value.


Structures

The following structures are defined or used as part of the DirectSound DDK:

  • DSDRIVERCAPS
  • DSDRIVERDESC
  • DSPROPERTY
  • DSVOLUMEPAN


DSDRIVERCAPS

Describes the hardware capabilities (including both total and free resources) of the sound device.

typedef struct tDSDRIVERCAPS{
    DWORD    dwFlags;
    DWORD    dwMinSecondarySampleRate;
    DWORD    dwMaxSecondarySampleRate;
    DWORD    dwPrimaryBuffers;
    DWORD    dwMaxHwMixingAllBuffers;
    DWORD    dwMaxHwMixingStaticBuffers;
    DWORD    dwMaxHwMixingStreamingBuffers;
    DWORD    dwFreeHwMixingAllBuffers;
    DWORD    dwFreeHwMixingStaticBuffers;
    DWORD    dwFreeHwMixingStreamingBuffers;
    DWORD    dwMaxHw3DAllBuffers;
    DWORD    dwMaxHw3DStaticBuffers;
    DWORD    dwMaxHw3DStreamingBuffers;
    DWORD    dwFreeHw3DAllBuffers;
    DWORD    dwFreeHw3DStaticBuffers;
    DWORD    dwFreeHw3DStreamingBuffers;
    DWORD    dwTotalHwMemBytes;
    DWORD    dwFreeHwMemBytes;
    DWORD    dwMaxContigFreeHwMemBytes;
} DSDRIVERCAPS, *PDSDRIVERCAPS;

Members

dwFlags
Flags describing certain capabilities of the device. The driver should set all applicable flags.
DSCAPS_CONTINUOUSRATE
Supports all sample rates between the dwMinSecondarySampleRate and dwMaxSecondarySampleRate values. Typically this means that the actual output rate will be within +/- 10Hz of the requested frequency.
DSCAPS_PRIMARYMONO
The device supports monophonic primary buffers.
DSCAPS_PRIMARYSTEREO
The device supports stereo primary buffers.
DSCAPS_PRIMARY8BIT
The device supports primary buffers with 8-bit samples.
DSCAPS_PRIMARY16BIT
The device supports primary sound buffers with 16-bit samples.
DSCAPS_SECONDARYMONO
The device supports hardware-mixed monophonic secondary buffers.
DSCAPS_SECONDARYSTEREO
The device supports hardware-mixed stereo secondary buffers.
DSCAPS_SECONDARY8BIT
The device supports hardware-mixed secondary buffers with 8-bit samples.
DSCAPS_SECONDARY16BIT
The device supports hardware-mixed secondary sound buffers with 16-bit samples.
dwMinSecondarySampleRate
Specifies the minimum sample rate supported by this device's secondary sound buffers.
dwMaxSecondarySampleRate
Specifies the maximum sample rate supported by this device's secondary sound buffers.
dwPrimaryBuffers
Number of primary buffers supported. The driver must always set this value to 1 for this release.
dwMaxHwMixingAllBuffers
Specifies the total number of buffers that can be mixed in hardware. This member, along with the dwMaxHwMixingStaticBuffers and dwMaxHwMixingStreamingBuffers members, describe the hardware mixing capabilities of the device. This member can be less than the sum of dwMaxHwMixingStaticBuffers and dwMaxHwMixingStreamingBuffers, as there are usually some resource trade-offs.
dwMaxHwMixingStaticBuffers
Specifies the maximum number of static buffers (that is, buffers located in on-board sound memory).
dwMaxHwMixingStreamingBuffers
Specifies the maximum number of streaming buffers.
dwFreeHwMixingAllBuffers, dwFreeHwMixingStaticBuffers, and dwFreeHwMixingStreamingBuffers
Describe the free (unallocated) hardware mixing capabilities of the device. An application can use these values to determine whether hardware resources are available for allocation to a secondary sound buffer. Also, by comparing these values to dwMaxHwMixingAllBuffers, dwMaxHwMixingStaticBuffers, and dwMaxHwMixingStreamingBuffers, the resources that are already allocated can be determined.
dwMaxHw3DAllBuffers, dwMaxHw3DStaticBuffers, and dwMaxHw3DStreamingBuffers
Describe the hardware 3-D positional capabilities of the device.
dwFreeHw3DAllBuffers, dwFreeHw3DStaticBuffers, and dwFreeHw3DStreamingBuffers
Describe the free (unallocated) hardware 3-D positional capabilities of the device.
dwTotalHwMemBytes
Specifies the total amount of hardware memory (in bytes) that stores static sound buffers on the card itself.
dwFreeHwMemBytes
Specifies the total amount of free memory.
dwMaxContigFreeHwMemBytes
Specifies the maximum contiguous block of free memory (that is, the largest buffer that can currently be allocated).

If the device has no onboard sound memory, the driver should set the dwTotalHwMemBytes, dwFreeHwMemBytes, and dwMaxContigFreeHwMemBytes members to zero. If the driver is managing the heap itself, it should fill in these members correctly. Otherwise, either DirectSound or DirectDraw® is managing the heap, so DirectSound fills in these members on the driver's behalf.


DSDRIVERDESC

Describes the system details of the driver.

typedef struct tDSDRIVERDESC{
    DWORD     dwFlags;
    TCHAR     szDesc[256];
    TCHAR     szDrvname[256]
    DWORD     dnDevNode;
    WORD      wVxdId;
    WORD      wReserved;
    ULONG     ulDeviceNum;
    DWORD     dwHeapType;
    LPVOID    pvDirectDrawHeap;
    DWORD     dwMemStartAddress;
    DWORD     dwMemEndAddress;
    DWORD     dwMemAllocExtra;
    LPVOID    pvReserved1;
    LPVOID    pvReserved2;
} DSDRIVERDESC, *PDSDRIVERDESC;

Members

dwFlags
Flags describing certain characteristics of the driver:
DSDDESC_DOMMSYSTEMOPEN
Acquire the device through Mmsystem.dll (by calling the waveOutOpen function) before opening the device through IDsDriver::Open. This is recommended, since it minimizes the risk of driver bugs that might cause device contention problems between Mmsystem.dll and DirectSound.
DSDDESC_DOMMSYSTEMSETFORMAT
Set the format of the primary buffer through Mmsystem.dll (by calling waveOutOpen) rather than by calling IDsDriverBuffer::SetFormat. This allows reuse of the tested code in the Wave portion of the device driver.
DSDDESC_DONTNEEDPRIMARYLOCK
Specifies that this driver doesn't need to receive IDsDriverBuffer::Lock and IDsDriverBuffer::Unlock calls for the primary buffer. This would typically be used on a DMA-based device in which the driver needs to supply the location and size of the DMA buffer. DirectSound will get that information from IDsDriver::CreateSoundBuffer when the buffer is created. This will reduce the number of ring transitions required by the DirectSound mixer, significantly improving performance.
DSDDESC_DONTNEEDSECONDARYLOCK
Specifies that this driver doesn't need to receive IDsDriverBuffer::Lock and IDsDriverBuffer::Unlock calls for secondary buffers.
DSDDESC_USESYSTEMMEMORY
Requests that DirectSound allocate system memory buffers of the required size before calling IDsDriver::CreateSoundBuffer for secondary buffers (not for primaries). This is for convenience only; drivers can allocate their own memory equally well. If specified, the driver is required to locate the buffer in the memory that DirectSound allocates.
szDesc and szDrvname
These members consist of strings that are passed back to calling applications by the DirectSoundEnumerate function. The first is a description of the driver, for example "Windows Sound System DirectSound Driver.". The second is the filename of the driver module, for example "Mssndsys.vxd".
dnDevNode and wVxdId
The devnode of this device, and the VxD ID for this driver. These values, along with ulDeviceNum, help DirectSound determine which Wave driver, if any, is associated with this DirectSound device. DirectSound needs to make this association to use the Mmsystem.dll wave APIs when supporting the DSDDESC_DOMMSYSTEMOPEN and DSDDESC_DOMMSYSTEMSETFORMAT flags.
wReserved
Reserved for future use.
ulDeviceNum
Describes the wave device ID used by this driver (relative to this device, not the whole system). This is needed for sound hardware that exports more than one wave device (as accessed through the Wave APIs). For example, if the sound hardware has two wave devices, the driver should tell DirectSound to use either 0 or 1. For hardware that has only one wave device (that is, almost all hardware), this parameter should be set to zero.
dwHeapType
A constant describing the type of heap used for the device's onboard sound memory. This must be one of the following values:
DSDHEAP_NOHEAP
This device does not support onboard sound memory.
DSDHEAP_CREATEHEAP
Indicates that this device supports on-board sound memory, and requests DirectSound to manage the on-board memory heap (this is the easiest method for devices that support onboard memory). The driver must fill in the dwMemStartAddress and dwMemEndAddress members to describe the size of the device's memory buffer.
DSDHEAP_USEDIRECTDRAWHEAP
Indicates that this device supports on-board sound memory, and requests that DirectDraw manage the heap. See the DirectDraw memory management services in the DirectDraw DDK documentation for more details. This method should be used for shared-media devices that share on-board memory between sound and display devices. The driver must fill in the pvDirectDrawHeap member with the heap supplied by DirectDraw.
DSDHEAP_PRIVATEHEAP
Indicates that this device supports on-board sound memory, and the driver manages the on-board memory heap itself. DirectSound simply requests the driver to allocate hardware buffers, and the driver succeeds or fails depending on whether the required memory is available.
pvDirectDrawHeap
If the DSDHEAP_USEDIRECTDRAWHEAP heap type was specified, this member must be filled in with the DirectDraw heap. Otherwise, this member should be set to NULL. If specified, this heap value must be obtained from DirectDraw though the DirectDraw driver component, and transferred internally to the DirectSound driver component.
dwMemStartAddress and dwMemEndAddress
If the DSDHEAP_CREATEHEAP heap type was specified, these parameters must be filled in with the start and end addresses used by the driver to reference the onboard sound memory. Note that the end address is the last valid address, not the one after; therefore, a 64K buffer would be described by dwMemEndAddress = dwMemStartAddress+65535. When DirectSound allocates a buffer from the heap, it passes the start address of the buffer to the driver in the dwCardAddress parameter of the IDsDriver::CreateSoundBuffer call.

The dwMemStartAddress member cannot be zero. If the hardware design does in fact use a start address of zero, the driver can simply offset the start address by some arbitrary amount when returning dwMemStartAddress to DirectSound. Then, of course, the driver should remove the offset when receiving card memory addresses from DirectSound.

dwMemAllocExtra
Specifies that DirectSound should allocate the specified number of extra bytes at the end of each sound buffer it creates. This may be required by some hardware devices. If not required, this member should be set to zero. Note that these extra bytes are allocated only for on-card memory allocations, that is when DSDDESC_USESYSTEMMEMORY and DSDHEAP_PRIVATEHEAP are not set by the driver. This member is used only if the driver is not managing its own heap.
pvReserved1 and pvReserved2
These members are reserved for future use. The driver should set both of them to NULL.


DSPROPERTY

DirectSound passes property set data and an application instance identifier to a DirectSound driver using this structure.

typedef union _DSPROPERTY
{
    struct
    {
        GUID    Set;
        ULONG   Id;
        ULONG   Flags;
        ULONG   InstanceId;
    };
#if defined(_NTDDK_)
    ULONGLONG  Alignment;
#else // !_NTDDK_
    DWORDLONG  Alignment;
#endif // !_NTDDK_
} DSPROPERTY, *PDSPROPERTY;

Members

Set
Uniquely identifies a property set.
Id
Uniquely identifies a property within a property set.
Flags
Unused.
InstanceId
Passes to the driver a value identifying the application that induces the call on the property set.
Alignment
Unused.


DSVOLUMEPAN

Describes the volume and pan settings in their original (hundredths of dB) API form, in fixed-point linear form, and in combined (that is, applying both volume and pan) fixed-point linear values.

typedef struct tDSVOLUMEPAN{
    DWORD    dwTotalLeftAmpFactor;
    DWORD    dwTotalRightAmpFactor;
    LONG     lVolume;
    DWORD    dwVolAmpFactor;
    LONG     lPan;
    DWORD    dwPanLeftAmpFactor;
    DWORD    dwPanRightAmpFactor;
} DSVOLUMEPAN, *PDSVOLUMEPAN;

Members

dwTotalLeftAmpFactor and dwTotalRightAmpFactor
Specifies the total combined linear factors (since volume and pan are cumulative).
lVolume
Specifies the input volume in hundredths of dB.
dwVolAmpFactor
Provides the linear equivalents in a fixed point 16.16 representation (for volume).
lPan
Specifies the input pan in hundredths of dB.
dwPanLeftAmpFactor and dwPanRightAmpFactor
Provides the linear equivalents in a fixed point 16.16 representation (for pan).


Return Values

Errors are represented by negative values and cannot be combined.The following list describes the values that can be returned by all IDsDriver, IDsDriverBuffer, and IDsDriverPropertySet methods. For a list of the error codes each method can return, see the individual method descriptions.

DS_OK
Everything worked.
DSERR_ALLOCATED
The requested object, service, or priority level is already allocated.
DSERR_ALREADYINITIALIZED
The object has already been initialized — it cannot be reinitialized.
DSERR_BADFORMAT
DirectSound cannot create a sound buffer of the specified wave format.
DSERR_BUFFERLOST
The sound buffer memory has been lost.
DSERR_CONTROLUNAVAIL
This function is not available on this sound buffer (probably because you did not specify the flag for this control in the DSBUFFERDESC structure when creating the buffer). For information about the DSBUFFERDESC structure, see the DirectX SDK documentation.
DSERR_GENERIC
An unspecified error has occurred and the operation can not be completed.
DSERR_INVALIDPARAM
This function was called with incorrect parameters.
DSERR_INVALIDCALL
The function request cannot be performed by the sound buffer in its current state or configuration.
DSERR_NODRIVER
The requested DirectSound driver could not be created.
DSERR_NOINTERFACE
The requested interface is not available.
DSERR_OUTOFMEMORY
The DirectSound object is out of memory.
DSERR_UNSUPPORTED
Returned by API functions that are not supported in this release.


Windows Me Debugger and Other Tools

This section includes:

AMLI Debugging

Memory Check (Memcheck)

System State Monitor (SSM)

Windows System Debugger (debugger.exe, wdeb386.exe, wdeb98.exe)

Other Tools

These tools are all for use on Microsoft® Windows® 98/Me. For debugging on NT-based operating systems in user mode, you should use WinDbg, CDB, NTSD, or the Microsoft Visual Studio® debugger. For debugging on NT-based operating systems in kernel mode, you should use WinDbg or KD. See Debugging Tools for NT-Based Operating Systems for more information on these tools.


AMLI Debugging

This section includes the following topics on ACPI Machine Language (AML) Interpreter debugging:

Requirements

Installation

Usage

Commands


Requirements

There are two requirements for AMLI debugging:

  • Debug version of acpi.sys
  • Kernel debugger — debugger.exe, for example


Installation

  1. Make a backup copy of the retail version of ACPI.SYS.
  2. Replace the retail version of ACPI.SYS with the debug version.
  3. Restart the computer.
  4. When the computer restarts, it will be running the debug version of ACPI.


Usage

To enter the AMLI debugger, type "..acpi" at the kernel debugger's prompt.

In the Windows Millennium kernel debugger, type CTRL+C to generate a prompt, then type "..acpi". The AMLI debugger will respond with "AMLI(? for help)->"


Commands

This section includes the following topics:

Examples

Command Details

To list the AMLI debugger's commands, type "?" at the AMLI prompt.

AMLI(? for help)-> ?

Help - ? [<Cmd>]
Clear Breakpoints - bc <bp list> | *
Disable Breakpoints - bd <bp list> | *
Enable Breakpoints - be <bp list> | *
List Breakpoints - bl
Set Breakpoints - bp <MethodName> | <CodeAddr> ...
Clear Event Log - cl
Dump Data - d [[l=<Len>] <Addr>]
Dump Data Bytes - db [[l=<Len>] <Addr>]
Dump Data Words - dw [[l=<Len>] <Addr>]
Dump Data DWords - dd [[l=<Len>] <Addr>]
Dump Data String - da [[l=<Len>] <Addr>]
Dump Event Log - dl
Dump Object Count Table - dc
Dump Heap - dh [<Addr>]
Dump Stack - ds [/v] [<Addr>]
Dump Name Space Object - dns [[/s] [<NameStr> | <Addr>]]
Dump Data Object - do <Addr>
Edit Memory - e [<Addr> [<DataList>]]
Find NameSpace Object - find <NameSeg>
Continue Execution - g
Read Byte from Port - i <Port>
Read Word from Port - iw <Port>
Read DWord from Port - id <Port>
List All Contexts - lc
Display Nearest Method - ln [<MethodName> | <CodeAddr>]
Notify NameSpace Object - notify <Obj> <Value>
Write Byte to Port - o <Port> <Byte>
Write Word to Port - ow <Port> <Word>
Write DWord to Port - od <Port> <DWord>
Step Over AML Code - p
Quit to Kernel Debugger - q
Display Context Info. - r
Run Method - run <MethodName> | <CodeAddr> [<ArgList>]
Set Debugger Options - set [traceon | traceoff] [nesttraceon | nesttraceoff]
[lbrkon | lbrkoff] [errbrkon | errbrkoff]
[verboseon | verboseoff] [logon | logoff]
[logmuton | logmutoff] [logsize=<MaxNumEvents>]
Trace Into AML Code - t
Unassemble AML code - u [<MethodName> | <CodeAddr>]


Examples

Type "dns" to dump the ACPI namespace.
Type "find _prw" to find all declarations of _PRW. This can be used for any declared object in the namespace.
Type "dns /s \_sb.pci0.dock". This will dump the namespace of everything just under dock.
Type "dns /s \_sb.pci0.dock._dck". This will dump the namespace of everything under _dck.
Type "u \_sb.pci0.dock._dck". This will disassemble the _dck method. This will only work for methods.
Type "ln" to list the nearest method.
Type "lc" for the current context.
Type "r" to display the context information.
Type "dl" to display the event log.
Type "cl" to clear the event log.
Type "run \_sb.pci0.dock._sta" to run control method _sta on device dock. This can only be done for methods.
Type "set verboseon" to turn up the debug spew from ACPI.
Type "set traceon" to turn on ACPI trace.
Type "bp \_sb.pci0.dock._dck" to set a breakpoint on _dck.
Type "bl" to list all set breakpoints.
Type "bd br0" to disable breakpoint 0.
Type "be br0" to enable breakpoint 0.
Type "bc br0" to clear breakpoint 0.
Type "p" to step through the code/method.
Type "g" to continue code execution.


Command Details

To display the help menu for the AMLI debugger, type:

AMLI(? for help)-> ?

To find if object _BST is present in the namespace, type:

AMLI(? for help)-> find _bst
\_SB.PCI0.ISA.BAT1._BST
\_SB.PCI0.ISA.BAT2._BST

To display only the namespace for device BAT1, type:

AMLI(? for help)-> dns /s \_sb.pci0.isa.bat1

To display only the object _BST, type:

AMLI(? for help)-> dns /s \_sb.pci0.isa.bat1._bst

ACPI Name Space: \_SB.PCI0.ISA.BAT1._BST (c29c2044)
Method(_BST:Flags=0x0,CodeBuff=c29c20a5,Len=103)

To display the entire namespace, type:

AMLI(? for help)-> dns

To disassemble object _BST, type:

AMLI(? for help)-> u _sb.pci0.isa.bat1._bst

c29c20a5: Acquire(\_SB_.PCI0.ISA_.EC0_.MUT1, 0xffff)
c29c20c0: Store("CMBatt - _BST.BAT1", Debug)
c29c20d7: \_SB_.PCI0.ISA_.EC0_.CPOL()
c29c20ee: Release(\_SB_.PCI0.ISA_.EC0_.MUT1)
c29c2107: Return(PBST)

or on the address of Codebuff for _BST

AMLI(? for help)-> u c29c20a5

c29c20a5: Acquire(\_SB_.PCI0.ISA_.EC0_.MUT1, 0xffff)
c29c20c0: Store("CMBatt - _BST.BAT1", Debug)
c29c20d7: \_SB_.PCI0.ISA_.EC0_.CPOL()
c29c20ee: Release(\_SB_.PCI0.ISA_.EC0_.MUT1)
c29c2107: Return(PBST)

AMLI(? for help)->

To break into the AMLI debugger before object _BST is executed so you can step through its execution, type:

AMLI(? for help)-> bp \_sb.pci0.isa.bat1._bst

Or, you can set a breakpoint somewhere inside the method _BST and continue debugging from there.

AMLI(? for help)-> u \_sb.pci0.isa.bat1._bst

c29c20a5: Acquire(\_SB_.PCI0.ISA_.EC0_.MUT1, 0xffff)
c29c20c0: Store("CMBatt - _BST.BAT1", Debug)
c29c20d7: \_SB_.PCI0.ISA_.EC0_.CPOL()
c29c20ee: Release(\_SB_.PCI0.ISA_.EC0_.MUT1)
c29c2107: Return(PBST)

AMLI(? for help)-> bp c29c20ee

To display the list of the set breakpoints, type:

AMLI(? for help)-> bl
 0:  c29accf5 [\_WAK]
 1:  c29c20a5 [\_SB.PCI0.ISA.BAT1._BST]

To disable breakpoint one so that the AMLI debugger will not trap on it during execution, type:

AMLI(? for help)-> bd 1

AMLI(? for help)-> bl
 0:  c29accf5 [\_WAK]
 1:  c29c20a5 [\_SB.PCI0.ISA.BAT1._BST]

To remove or clear a breakpoint one, type:

AMLI(? for help)-> bc 1

In the example below , a breakpoint was set on the _WAK object. An "ln" will tell you the nearest method. An "lc" will tell you all the current context running. From this you can see that methods _Q09 and _WAK have the context and that _WAK is the active context, indicated by the asterisk (*). An "r" will display the context information. From this you can see useful thread and stack information as well as arguments passed to _WAK and the local data objects.

The Flgs are:

  • A = Async Eval
  • N = Nested Eval
  • Q = In the ready queue
  • C = Callback needed
  • R = Running
  • W = Ready
  • T = Timeout
  • D = Timer dispatch
  • F = Flushed.
Running \_WAK method
Hit Breakpoint 0.
AMLI(? for help)-> ln
c29accf5: \_WAK

AMLI(? for help)-> lc
 Ctxt=c18b6000, ThID=00000000, Flgs=A-QC-W----, pbOp=c29bf8fe, Obj=\_SB.PCI0.ISA.EC0._Q09
*Ctxt=c18b4000, ThID=c15a6618, Flgs=----R-----, pbOp=c29accf5, Obj=\_WAK

AMLI(? for help)->  r

Context=c18b4000*, Queue=00000000, ResList=00000000
ThreadID=c15a6618, Flags=00000010
StackTop=c18b5eec, UsedStackSize=276 bytes, FreeStackSize=7636 bytes
LocalHeap=c18b40c0, CurrentHeap=c18b40c0, UsedHeapSize=88 bytes
Object=\_WAK, Scope=\_WAK, ObjectOwner=c18b4108, SyncLevel=0
AsyncCallBack=ff06b5d0, CallBackData=0, CallBackContext=c99efddc

MethodObject=\_WAK
c18b40e4: Arg0=Integer(:Value=0x00000001[1])
c18b5f3c: Local0=Unknown()
c18b5f54: Local1=Unknown()
c18b5f6c: Local2=Unknown()
c18b5f84: Local3=Unknown()
c18b5f9c: Local4=Unknown()
c18b5fb4: Local5=Unknown()
c18b5fcc: Local6=Unknown()
c18b5fe4: Local7=Unknown()
c18b4040: RetObj=Unknown()

A "dl" will dump the event log with the bottom showing the latest object processed. A "cl" will clear the event log.

AMLI(? for help)-> dl
RUN!: [c15a6618]QTh=00000000,QCt=00000000,QFg=00000000: Ctx=c18b4000,rc=0
KICK: [c15a6618]QTh=00000000,QCt=00000000,QFg=00000000: rc=0
SYNC: [c15a6618]QTh=00000000,QCt=00000000,QFg=00000002,LockPhase=0,Locked=0,IRQL=00: Obj=\_WAK
ASYN: [c15a6618]QTh=00000000,QCt=00000000,QFg=00000002,LockPhase=0,Locked=0,IRQL=00: Obj=\_WAK
REST: [c15a6618]QTh=00000000,QCt=00000000,QFg=00000002: Ctx=c18b4000,Obj=\_WAK
INSQ: [c15a6618]QTh=00000000,QCt=00000000,QFg=00000002: Ctx=c18b4000,Obj=\_WAK
EVAL: [c15a6618]QTh=00000000,QCt=00000000,QFg=00000002: Ctx=c18b4000,Obj=\_WAK
RUNC: [c15a6618]QTh=c15a6618,QCt=c18b4000,QFg=00000002: Ctx=c18b4000,Obj=\_WAK

To turn up the spew from the AMLI debugger, type:

AMLI(? for help)-> set verboseon

AMLI(? for help)-> set traceon

From here you can step through the AML code, watching the code execute line by line. You can also trace into AML code.

AMLI(? for help)-> p

c29bfcb7: Store(\_SB_.PCI0.ISA_.ACAD.CHAC(SEL0=0x10e1)
c29c17b1: {
c29c17b1: | Store(LGreater(And(Arg0=0x10e1,0xf0,)=0xe0,0x80)=0xffffffff,Local0)=0xffffffff
AMLI(? for help)-> p

c29c17bb: | If(LNot(LEqual(Local0=0xffffffff,ACP_=0xffffffff)=0xffffffff)=0x0)
c29c17ce: | {
c29c17ce: | | Return(Zero)
c29c17d0: | }
c29c17d0: },Local1)=0x0
AMLI(? for help)-> t

c29bfcd4: Store(\_SB_.PCI0.ISA_.BAT1.CHBP(SEL0=0x10e1)
c29c293d: {
c29c293d: | Store("CMBatt - CHBP.BAT1",Debug)String(:Str="CMBatt - CHBP.BAT1")
="CMBatt - CHBP.BAT1"
AMLI(? for help)->

You may also run methods from within the AMLI debugger if you choose. Here we are evaluating the status of LNKA.

AMLI(? for help)-> run \_sb.lnka._sta
PCI OpRegion Access on region c29b2268 device c29b2120

\_SB.LNKA._STA completed successfully with object data:
Integer(:Value=0x0000000b[11])


Memcheck

Memcheck is an application used to keep track of nearly all memory allocations and deallocations that occur in ring zero while Microsoft® Windows® is booted, during run time. Memcheck is also useful for measuring the memory footprints used by all of the various ring zero components residing in Windows.

Though Memcheck does not automatically and singularly detect memory leaks, it provides the user with the capacity to identify and troubleshoot memory leaks to a surprisingly precise level. The user is provided two main interfaces: the Memcheck application window and the Memcheck debugger interface.

The first, and most obvious, is the Memcheck application window, which displays a list of drivers, how much swappable and fixed memory they each have allocated, and in how many handles. The display refreshes on a default interval of three seconds. This interval can be modified by the user when the program is launched using a command-line parameter (/t xxx, where xxx is an integer representing how many seconds to wait between snapshots). Such an interface is provided to the user for the purpose of identifying suspicious or questionable memory management in ring zero during run time.

Should it become evident that some ring zero component is leaking resources, a more precise and in-depth interface is provided. This second interface is accessed through the Windows System Debugger (wdeb98.exe / rterm98.exe for Windows 98 and Windows 98 SE, and debugger.exe / rterm.exe for Windows Me).

This section includes the following topics:

Memcheck Interfaces

Memcheck Log Files

Memcheck Errors


Memcheck Interfaces

First, let us review the application main window interface. This interface provides the user with an overview of the memory allocation activity within the system. The user can watch this window and determine how much memory each driver has allocated to itself, how much memory in total is allocated by ring zero components, and how much a driver's allocation pool has grown or shrunk since a system snapshot was last taken.

The following example represents the output:

Fixed Memory |  |  | Swappable Memory
VxD Name | Allocations | Bytes | Allocations | Bytes
afvxd | 2(0) | 235(0) | 0(0) | 0(0)
bios | 0(0) | 0(0) | 2(0) | 16857(0)
cbss | 14(0) | 954(0) | 0(0) | 0(0)
cdfs | 1(0) | 12(0) | 0(0) | 0(0)
cdvsd | 1(0) | 74(0) | 0(0) | 0(0)
configmg | 40(4) | 66316(80) | 1827(467) | 64573(7139)
cwbase | 1(0) | 20(0) | 0(0) | 0(0)
cwbwdm | 9(0) | 2968(0) | 0(0) | 0(0)
debug | 39(4) | 936(96) | 0(0) | 0(0)
dfs | 2(0) | 8192(0) | 0(0) | 0(0)
disktsd | 6(0) | 120(0) | 0(0) | 0(0)
dosmgr | 3(0) | 60(0) | 0(0) | 0(0)
drmk | 3(0) | 96(0) | 3(0) | 72(0)
esdi506 | 2(0) | 1102(0) | 0(0) | 0(0)
hsflop | 2(0) | 98(0) | 0(0) | 0(0)
ifsmgr | 186(32) | 16193(2016) | 60(7) | 1818(328)
ios | 32(0) | 2192(0) | 5(0) | 1968(0)
isapnp | 0(0) | 0(0) | 1(0) | 4096(0)
ks | 12(-2) | 1132(-176) | 67(-4) | 4524(-124)
mmdevldr | 4(0) | 64(0) | 0(0) | 0(0)
mstcp | 28(0) | 7368(0) | 0(0) | 0(0)
ndis | 90(0) | 202793(0) | 1(0) | 1488(0)
nmx | 2(0) | 3686400(0) | 0(0) | 0(0)
ntkern | 320(5) | 450914(-409) | 352(-5) | 13912(-104)
pccard | 20(0) | 1166(0) | 0(0) | 0(0)
pci | 0(0) | 0(0) | 24(0) | 1044(0)
pcimp | 1(0) | 12(0) | 1(0) | 60(0)
perf | 0(0) | 0(0) | 62(0) | 2373(0)
portcls | 17(0) | 6072(0) | 29(0) | 7444(0)
pppmac | 18(0) | 39018(0) | 0(0) | 0(0)
rt | 3(0) | 704(0) | 0(0) | 0(0)
scsi1hlp | 1(0) | 8(0) | 0(0) | 0(0)
serenum | 0(0) | 0(0) | 1(0) | 32(0)
serial | 3(0) | 37(0) | 0(0) | 0(0)
shell | 8(0) | 120(0) | 0(0) | 0(0)
sysaudio | 0(0) | 0(0) | 492(1) | 61834(4096)
tcpip | 116(2) | 205074(128) | 0(0) | 0(0)
tdi | 18(0) | 700(0) | 0(0) | 0(0)
uhcd | 6(0) | 2428(0) | 0(0) | 0(0)
usbd | 2(0) | 160(0) | 3(0) | 71(0)
usbhub | 4(0) | 358(0) | 2(0) | 122(0)
v86mmgr | 3(0) | 2152(0) | 2(0) | 475136(0)
vcache | 66(0) | 70486(0) | 0(0) | 0(0)
vcd | 2(0) | 679(0) | 0(0) | 0(0)
vcomm | 4(0) | 61(0) | 0(0) | 0(0)
vcond | 6(0) | 112(0) | 0(0) | 0(0)
vdd | 4(0) | 1181(80) | 0(0) | 0(0)
vdef | 1(0) | 20(0) | 0(0) | 0(0)
vdhcp | 13(0) | 4440(0) | 0(0) | 0(0)
vfat | 547(96) | 87857(22378) | 0(0) | 0(0)
vip | 1(0) | 40(0) | 0(0) | 0(0)
vmcpd | 17(3) | 8976(1584) | 0(0) | 0(0)
vmm | 611(74) | 159262(21912) | 462(15) | 4064993(91918)
vmouse | 2(0) | 31(0) | 0(0) | 0(0)
vnbt | 88(0) | 10438(0) | 0(0) | 0(0)
vnetbios | 3(2) | 4154(58) | 0(0) | 0(0)
vnetsup | 28(0) | 1528(0) | 0(0) | 0(0)
voltrack | 1(0) | 12(0) | 0(0) | 0(0)
vredir | 12(0) | 22733(0) | 0(0) | 0(0)
vtdapi | 1(0) | 16(0) | 0(0) | 0(0)
vwin32 | 95(8) | 7404(700) | 0(0) | 0(0)
vxdldr | 328(-4) | 1231914(-141556) | 9(0) | 634000(0)
vxdmon | 14(0) | 109178(0) | 0(0) | 0(0)
wdmaud | 5(0) | 120(0) | 56(0) | 14644(0)
wmidrv | 2(0) | 144(0) | 1(0) | 20(0)
wsock2 | 1(0) | 8192(0) | 0(0) | 0(0)
Total: | 2871(224) | 6435226(-93109) | 3462(480) | 5371081(99157)

Note that the interface is divided into five columns. Starting from the left, the first column is the name of the VXD/WDM driver. Second column represents how many fixed handles that driver has allocated and third column shows how many fixed bytes are allocated. The fourth and fifth columns show how many swappable handles the driver has allocated and how many swappable bytes the driver has allocated, respectively.

Also note that there is a column to the right of each of the latter four columns containing a number in parentheses. This number is the tabulated delta between how much memory was allocated to the particular driver at the time of the last snapshot and how much memory is allocated to the driver presently. For example, if we are examining how many fixed bytes are allocated to the TCP/IP driver, which at the time of the last snapshot, had 1024 bytes allocated to it, and now has 1536 bytes allocated to it, the "Fixed Bytes" column would read: 1536 (512). This denotes that the tcpip.sys driver has grown by 512 bytes since the time of the last snapshot. A negative value in parentheses indicates that the driver is now using less memory than it was at the time of the snapshot (negative values here can be safely ignored for all practical purposes). However, if one or more of the numbers in parentheses continues to grow, and never shrinks again, it is a good indication that the associated driver is leaking resources.

To take a snapshot

  1. In the File menu, click Clear delta columns.

    Memcheck will take the last recorded state of the computer and base all delta information on that snapshot from that point forward.

  2. Click Clear delta columns again to declare a new snapshot.

So now let's say we have found a hypothetical memory leak in some driver, say tcpip.sys. We have observed most keenly that every time we connect to a network resource, tcpip's memory usage grows its allocation pool by 42 bytes in one handle. This means that if I connect to a network resource every time the display refreshes, I will notice that the delta columns, as well as the total columns, will grow by one handle and 42 bytes. If we let the computer stand alone for a while without connecting to a network resource, it does not appear to free those allocations (the columns do not ever decrement by one handle and 42 bytes). We can now safely say that this driver is leaking.

The next step is to move to the second interface, through the Windows debugger for further investigation. For the purpose of this documentation, it is assumed that you have the Windows debugger loaded and a functional Rterm instance as the terminal client on the remote host already set up.

At this point you may be asking yourself: "Why are there two interfaces? Couldn't you just consolidate them into one?" If we were to attempt to display deeper and more precise information about what is happening in ring zero, we would consequently (probably) be modifying the state of the ring zero component we were looking at. And if that isn't enough for you, ring zero components change state faster than the state information can be moved to ring three and displayed to the user. Therefore, certain functionality must be left to the debugger interface, where the computer can be (basically) halted and we can poke around safely looking at memory allocation information.

To access the Memcheck driver's debugger interface, we must break in by pressing CTRL+C on the remote terminal (Rterm) client. From the x##, x--, or x%% prompt, type '..Memcheck', without the single quotation marks and press Enter. This will cause the Memcheck driver to display a menu. For the purpose of this documentation, not all of the options in this menu are relevant, and thus not all of them will be explained.

Mainly, we are concerned with the options in the "Filter On" section, the "Break On" section, and the 'd' and 's' commands. Through the "Filter On" section, we can filter out allocation information that fits specified criteria. Keep in mind that the number of allocation data that the driver could potentially be storing may very well be immense. Thus, by specifying, for example, a driver name such as tcpip (remember, it is not necessary to specify the 8.3 filename suffix, the basename will do), we can filter out those allocations that were made by tcpip only. Then, we can dump that allocation information to the Rterm by issuing the 'd' command. This will dump the entire list of all allocations made by that driver, one by one. However, in most if not all cases, the 's' command should be issued to switch the driver into "summary mode". This will tabulate all of the allocations that came from a unique caller address into one listing. For example, if the function called AllocateBuffer in tcpip made 32 separate allocations at different times, but all with the same block size, the Memcheck driver will tabulate all of these together and list this caller only once, specifying that 32 allocations were made from that address.

Let's digress from our hypothetical example to take a moment to review the Memcheck debug menu and illustrate how the allocation list is processed and output. Note the following debugger output:

1##..Memcheck
MEMCHECK DEBUG MENU 1.20 (case sensitive)
'd' dump
Filter on:
'n' driver name ()
'c' caller address 00000000h
'b' memory block size 00000000h (0)
'f' memory block flags 00000000h (zero for all)
's' turns ON summary mode
Break on:
'C' Caller address 00000000h
'B' memory block size 00000000h (0)
'F' memory block flags 00000000h
'S' stack checksum dwID 00000000h
Misc:
'l' dump dynamic loading device's footprints (Filter on vxdldr)
'v' validate a stack checksum (dwID)
't' turn OFF stack checksum generation (dwID)
'e' dump error pool
'E' dump and clear error pool
'i' turn OFF int 3's
'r' reset or clear all
'h' or '?' for help message
'm' turn OFF MEMCHECK menu
'g' or esc to exit
Enter MEMCHECK selection:n
Enter the name of the Vxd(SYS) (limit 8 chars):vcache
MEMCHECK DEBUG MENU 1.20 (case sensitive)
'd' dump
Filter on:
'n' driver name (vcache)
'c' caller address 00000000h
'b' memory block size 00000000h (0)
'f' memory block flags 00000000h (zero for all)
's' turns ON summary mode
Break on:
'C' Caller address 00000000h
'B' memory block size 00000000h (0)
'F' memory block flags 00000000h
'S' stack checksum dwID 00000000h
Misc:
'l' dump dynamic loading device's footprints (Filter on vxdldr)
'v' validate a stack checksum (dwID)
't' turn OFF stack checksum generation (dwID)
'e' dump error pool
'E' dump and clear error pool
'i' turn OFF int 3's
'r' reset or clear all
'h' or '?' for help message
'm' turn OFF MEMCHECK menu
'g' or esc to exit
Enter MEMCHECK selection:

In the previous example, we have issued the 'n' command, instructing Memcheck to filter its immense allocation list for allocations made by the component named "vcache". After entering this command, note that the Memcheck debug menu is displayed again, but this time, under the "Filter on" section, we see that we are filtering for the name "vcache". Keep in mind that all filter options are processed together, so we can continue to refine the filter by also filtering on block size, allocation flags, or caller address.

If you've ever been so bold as to not apply a filter, then issue the 'd' (dump allocation list) command, you will have probably noticed that the allocation list continues to dump for quite some time. By specifying the filter, we are able to output only the following allocations:

MEMCHECK DEBUG MENU 1.20 (case sensitive)
'd' dump
Filter on:
'n' driver name (vcache)
'c' caller address 00000000h
'b' memory block size 00000000h (0)
'f' memory block flags 00000000h (zero for all)
's' turns ON summary mode
Break on:
'C' Caller address 00000000h
'B' memory block size 00000000h (0)
'F' memory block flags 00000000h
'S' stack checksum dwID 00000000h
Misc:
'l' dump dynamic loading device's footprints (Filter on vxdldr)
'v' validate a stack checksum (dwID)
't' turn OFF stack checksum generation (dwID)
'e' dump error pool
'E' dump and clear error pool
'i' turn OFF int 3's
'r' reset or clear all
'h' or '?' for help message
'm' turn OFF MEMCHECK menu
'g' or esc to exit
Enter MEMCHECK selection:d

(dwID) | Memory | Size | Flags | Address: | Driver: | Symbol
(00000034) | c140fcb0, | 00000034, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000043) | c140ffb0, | 00000043, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000001e) | c1415a30, | 000103b0, | 00800001, | c0383e0b: | vcache | VCACHE(6)+20F
(00000042) | c14cb850, | 00000042, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000018) | c14e21e0, | 00000018, | 00800001, | c02532cc: | vcache | VCACHE(4)+24
(00000018) | c14e79b0, | 00000018, | 00800001, | c02532cc: | vcache | VCACHE(4)+24
(00000018) | c14e85d0, | 00000018, | 00800001, | c02532cc: | vcache | VCACHE(4)+24
(00000042) | c14e8a40, | 00000042, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003c) | c14e8d80, | 0000003c, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003c) | c14e8dc0, | 0000003c, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003e) | c14e8e00, | 0000003e, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003e) | c14e8e40, | 0000003e, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003c) | c14e8e80, | 0000003c, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003e) | c14e8ec0, | 0000003e, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003e) | c14e8f00, | 0000003e, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000040) | c14e8f40, | 00000040, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000040) | c14e8f80, | 00000040, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003a) | c14e8fc0, | 0000003a, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003a) | c14e9000, | 0000003a, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003e) | c14e9040, | 0000003e, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000038) | c14e9080, | 00000038, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003c) | c14e90c0, | 0000003c, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003c) | c14e9100, | 0000003c, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003e) | c14e9140, | 0000003e, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003c) | c14e9180, | 0000003c, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000044) | c14e91c0, | 00000044, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000044) | c14e9210, | 00000044, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003c) | c14e9260, | 0000003c, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000042) | c14e92a0, | 00000042, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000040) | c14e92f0, | 00000040, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000038) | c14e9330, | 00000038, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000040) | c14e9370, | 00000040, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000040) | c14e93b0, | 00000040, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000042) | c14e93f0, | 00000042, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000044) | c14e9440, | 00000044, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003e) | c14e9490, | 0000003e, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000031) | c14f26d0, | 00000031, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000040) | c14f3050, | 00000040, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000040) | c14f3090, | 00000040, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000041) | c14f30d0, | 00000041, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000041) | c14f3120, | 00000041, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000040) | c14f3170, | 00000040, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000040) | c14f31b0, | 00000040, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000040) | c14f31f0, | 00000040, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000041) | c14f3230, | 00000041, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000041) | c14f3280, | 00000041, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000042) | c14f32d0, | 00000042, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000043) | c14f3320, | 00000043, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000040) | c14f3370, | 00000040, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000043) | c14f33b0, | 00000043, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000044) | c14f3400, | 00000044, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000044) | c14f3450, | 00000044, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000042) | c14f34a0, | 00000042, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000042) | c14f34f0, | 00000042, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003f) | c14f3540, | 0000003f, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003f) | c14f3580, | 0000003f, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000041) | c14f35c0, | 00000041, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003e) | c14f3610, | 0000003e, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000043) | c14f3650, | 00000043, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000040) | c14f36a0, | 00000040, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000042) | c14f36e0, | 00000042, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000043) | c14f3730, | 00000043, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000040) | c14f3780, | 00000040, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000040) | c14f37c0, | 00000040, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000047) | c14f3800, | 00000047, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000043) | c14f3850, | 00000043, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000044) | c14f38a0, | 00000044, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000042) | c1514000, | 00000042, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000030) | c15212a0, | 00000040, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000042) | c1523000, | 00000042, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000043) | c1523180, | 00000043, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000040) | c15262c0, | 00000040, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003c) | c1530000, | 0000003c, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000040) | c15300a0, | 00000040, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000017c) | c1532200, | 00000040, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000104) | c1534430, | 00000040, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003c) | c15344d0, | 0000003c, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000042) | c15358c0, | 00000042, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000043) | c1535a70, | 00000043, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000042) | c15364a0, | 00000042, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000040) | c15377e0, | 00000040, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003f) | c1537b70, | 0000003f, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003a) | c1537bb0, | 0000003a, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000017c) | c1537db0, | 0000003e, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000038) | c1537df0, | 00000038, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000040) | c1539ec0, | 00000040, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000042) | c153a2c0, | 00000042, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003c) | c15400c0, | 0000003c, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000034) | c1540230, | 00000034, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000002c) | c1540310, | 00000040, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003c) | c15403b0, | 0000003c, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000042) | c154e350, | 00000042, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000030) | c154e590, | 00000042, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003c) | c154e980, | 0000003c, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000038) | c154f0d0, | 00000038, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000042) | c154f410, | 00000042, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000040) | c154f460, | 00000040, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(00000048) | c154f4a0, | 0000003f, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003a) | c154f540, | 0000003a, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000002c) | c154faf0, | 00000043, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000002c) | c154fdc0, | 00000042, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003f) | c15500c0, | 0000003f, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
(0000003a) | c1550160, | 0000003a, | 00800001, | c008fe4f: | vcache | VCACHE(1)+A9F
Total Bytes 00011c6dh(72813) |  |  | Count:103 |  |  |

To further shorten our output, we can give the 's' (toggle summary mode) command as follows:

MEMCHECK DEBUG MENU 1.20 (case sensitive)
'd' dump
Filter on:
'n' driver name (vcache)
'c' caller address 00000000h
'b' memory block size 00000000h (0)
'f' memory block flags 00000000h (zero for all)
's' turns ON summary mode
Break on:
'C' Caller address 00000000h
'B' memory block size 00000000h (0)
'F' memory block flags 00000000h
'S' stack checksum dwID 00000000h
Misc:
'l' dump dynamic loading device's footprints (Filter on vxdldr)
'v' validate a stack checksum (dwID)
't' turn OFF stack checksum generation (dwID)
'e' dump error pool
'E' dump and clear error pool
'i' turn OFF int 3's
'r' reset or clear all
'h' or '?' for help message
'm' turn OFF MEMCHECK menu
'g' or esc to exit
Enter MEMCHECK selection:s
MEMCHECK DEBUG MENU 1.20 (case sensitive)
'd' dump
Filter on:
'n' driver name (vcache)
'c' caller address 00000000h
'b' memory block size 00000000h (0)
'f' memory block flags 00000000h (zero for all)
's' turns OFF summary mode
Break on:
'C' Caller address 00000000h
'B' memory block size 00000000h (0)
'F' memory block flags 00000000h
'S' stack checksum dwID 00000000h
Misc:
'l' dump dynamic loading device's footprints (Filter on vxdldr)
'v' validate a stack checksum (dwID)
't' turn OFF stack checksum generation (dwID)
'e' dump error pool
'E' dump and clear error pool
'i' turn OFF int 3's
'r' reset or clear all
'h' or '?' for help message
'm' turn OFF MEMCHECK menu
'g' or esc to exit
Enter MEMCHECK selection:d
Attempting to walk tree

(dwID) | Count | nBytes |  | Address: | Driver: | Symbol
(00000000) | 99, | 00001875h, | c008fe4f: |  | vcache: | VCACHE(1)+A9F
(00000018) | 3, | 00000048h, | c02532cc: |  | vcache: | VCACHE(4)+24
(0000001e) | 1, | 000103b0h, | c0383e0b: |  | vcache: | VCACHE(6)+20F
Total Unique Callers:3, |  |  | nBytes=72813(00011c6dh)

Note that out of the 103 allocations that were dumped previously, there were only 3 unique callers. In other words, 99 allocations were made from the same address in code (in this case, 0xC008FE4F).

Going back to the original example with tcpip, let's say that we performed the action that caused the leak (in this case, connecting to a network resource) 10 times before switching into summary mode and dumping the list. We could look for any listing that reports 10 allocations. If there is only one of those listed, we can safely bet that that instance is the offender.

We would then move on to the "Break On" section, and instruct the driver to break every time an allocation was made by that particular caller address. Again, we reproduce the offending behavior, but this time, Memcheck int 3's when this operation is performed.

Now we have all the information we need to track down the leak. All that needs to be done is to grab a stack dump and, if possible, analyze it to determine what is going on. Even if it is not possible to analyze, at least we have the offending function, the repro steps, and a stack dump. This is enough for the developer of the component to figure out what exactly is the problem.

Though these are not complete directions, you are now basically familiar with the interfaces you are using and can play around with them to better understand what is going on.


Memcheck Log Files

Memcheck automatically generates one or two log files. The first and most important log file is located at c:\mcxsnap.log. This log file contains nothing but snapshots and is appended to every time the display refreshes on the application window (coinciding with the time that the driver tabulates and assembles a ring zero memory report).

This file is helpful for stress testing. If the user notices that there is no more memory available in the system, but cannot immediately isolate an offending component, this file can be parsed out and a pattern can be identified by the user. A separate tool is provided with Memcheck to parse the log file and chart out memory activity on a per-driver basis. Basically, any driver showing an unacceptable increase in memory usage should be investigated further for memory leaks.

The second file contains records of ring zero memory allocation and deallocation errors. It is located at c:\mcxerr.log. For more information on these errors see Memcheck Errors. The parser, Memparse, currently shipping with Memcheck, will intake both of these files and chronologically associate each error with its corresponding driver and snapshot number.

Memparse parses a given mcxsnap.log file into a set of text files containing graphs of each drivers' memory behavior trends. By default, Memparse operates on c:\mcxsnap.log and outputs its chart files in c:\memparse\.txt. These locations can be changed with the /f: and /d: command-line parameters. The output files are designed to be viewable on a 25x80 console.


Memcheck Errors

Periodically, as Memcheck is running, the user may encounter an int 3 in the debugger that looks something like this:

ERROR*ERROR*ERROR*ERROR*ERROR*ERROR*ERROR*ERROR*ERROR*ERROR*ERROR*ERROR
Caller Address: c186dec0
Module Name: UNKNOWN
MEMCHECK EXTERNAL ERROR: Memcheck has detected a memory deallocation failure.
This WILL result in a memory leak. _HeapFree failed!
eax=00000001 ebx=ca76e70c ecx=d21b8c40 edx=d21b8c78 esi=c2a0e960 edi=00000000
eip=c00e3a19 esp=d20d4dfc ebp=d20d4e00 iopl=0 -- -- -- nv up EI pl nz na po nc
cs=0028 ss=0030 ds=0030 es=0030 fs=0078 gs=0030 cr2=beb299f0 efl=00000202
0028:c00e3a19 cc int 3
de##ln c186dec0
0028:c186de97 DSOUND.dsvxd:_PTEXT:?Terminate@CGrace@@UAEXXZ + 29
0028:c186dec8 ?MixEndingBuffer@CGrace@@AAEXPAVCMixSource@@JJJJ@Z - 8
de##ds ss:esp
0030:d20d4dfc = 00000000, %00000000 + 0
0030:d20d4e00 = d20d4f70, %d20d4f70 + 0
0030:d20d4e04 = c00e2c64, MEMCHECK(1)+2D2C + 0
0030:d20d4e08 = c001249c, _HeapFree + 0
0030:d20d4e0c = c186dec0, ?Terminate@CGrace@@UAEXXZ + 29
0030:d20d4e10 = 00000000, %00000000 + 0
0030:d20d4e14 = 00000000, %00000000 + 0
0030:d20d4e18 = c186dec0, ?Terminate@CGrace@@UAEXXZ + 29
0030:d20d4e1c = 00000000, %00000000 + 0
0030:d20d4e20 = 00000000, %00000000 + 0
0030:d20d4e24 = 00000000, %00000000 + 0
0030:d20d4e28 = c2a0e960, %c2a0e960 + 0
0030:d20d4e2c = ca76ec6d, ?Terminate@CKeGrace@@UAEXXZ + 1d
0030:d20d4e30 = c29a9030, %c29a9030 + 0
0030:d20d4e34 = c186d3ff, ?FreeMixer@CKeGrDest@@UAEXXZ + a
0030:d20d4e38 = d20d4e64, %d20d4e64 + 0
0030:d20d4e3c = c186d812, _ioctlMixDest_FreeMixer + 13
0030:d20d4e40 = ca76e720, DSOUND_DDB + 14
0030:d20d4e44 = d20d4e64, %d20d4e64 + 0
0030:d20d4e48 = ca76e8a9, ctrlDeviceIOControl + 19
de##d
0030:d20d4e4c = d20d4e64, %d20d4e64 + 0
0030:d20d4e50 = ca76e70c, DSOUND_DDB + 0
0030:d20d4e54 = d20d4e64, %d20d4e64 + 0
0030:d20d4e58 = ca76e720, DSOUND_DDB + 14
0030:d20d4e5c = c02a3510, vWin32_DIOC_Ex_End + 14
0030:d20d4e60 = c0009310, Return_To_VM + 0
0030:d20d4e64 = d20d4f70, %d20d4f70 + 0
0030:d20d4e68 = c2920074, %c2920074 + 0
0030:d20d4e6c = ca76e70c, DSOUND_DDB + 0
0030:d20d4e70 = 00000033, %00000033 + 0
0030:d20d4e74 = 07e8f1c0, %07e8f1c0 + 0
0030:d20d4e78 = 00000004, %00000004 + 0
0030:d20d4e7c = 00000000, %00000000 + 0
0030:d20d4e80 = 00000000, %00000000 + 0
0030:d20d4e84 = 07e8f1c4, %07e8f1c4 + 0
0030:d20d4e88 = 00000000, %00000000 + 0
0030:d20d4e8c = 453a4f5c, %453a4f5c + 0
0030:d20d4e90 = 81789fa4, %81789fa4 + 0
0030:d20d4e94 = 8178d400, %8178d400 + 0
0030:d20d4e98 = 00000000, %00000000 + 0
de##d

These errors are not failures on the part of Memcheck when "Memcheck External Error" is displayed at the beginning of the description string. They are assertions raised when a component fails to allocate or deallocate memory and are put there to detect possible leaks or the potential for fatal exceptions. Generally, when one of these errors are it, the first thing that should be collected is a stack dump, going far enough down the stack to allow the owner of the component responsible for the int 3 to determine what failed. These errors are very difficult to debug due to the fact that user must, in essence, know what the offending driver is "thinking" at the time. For example, the user may encounter an error regarding some component failing to PageFree a memory block. This may or may not indicate a leak. If the driver modified the pointer it was using to refer to that memory and then passed it to PageFree, PageFree will fail and the memory will not be freed. In other words, the driver just leaked memory. On the other hand, it is possible for a driver to try to free a memory block that never existed to begin with, or try to free NULL. This also will cause PageFree to fail, but in this case, since the driver never actually allocated any memory to begin with, no leak has occurred. In fact, this case causes no undesirable effects whatsoever.

Note that whenever one of these errors occurs, the module name reported in the debugger is "UNKNOWN." This is because the driver is unable to fill in the module name at the time of the error. To find out the module name, go to the Memcheck menu and press 'e'. This will dump the error pool and fill in that value. There is a small chance that the debugger will cause a trap 14 by doing this. Should this happen, simply enter the 'gt' command into the debugger (Go Through). The trap 14 is totally recoverable. Then, try taking simply the caller address (shown directly above the module name in the error) and list the nearest symbol to it with the debugger's built-in "ln" command.

Should you be running automated stress testing and do not wish Memcheck to break into the debugger when this is running, a mechanism is provided to disable int 3s within the driver. Please note that this functionality should not be used except when running automated tests wherein simple int 3s cannot be afforded. The int 3s that the driver generates are there for a very good reason — to catch bugs.

To disable the Memcheck driver's int 3 mechanism, go to the Memcheck menu and issue the 'i' command. This will toggle the state of the int 3 mechanism between enabled and disabled.


System State Monitor

System State Monitor (SSM) is a ring 3 memory analysis tool used to aid in tracking down ring 3 or user-mode memory leaks.

System State Monitor uses:

  • KERNEL Tool helper library functions to query 32 bit process memory usage
  • Windows® 3.1 TOOLHELP.DLL library functions to monitor 16 bit tasks and their respective memory usage
  • LEAKINFO API set for querying the system objects delivered from USER.EXE and GDI.EXE

This is a complete list of objects and the associated applications (if this applies) that generated the object. For example, Window Handles and List Box item (USER), and DC objects and Bitmaps (GDI) among a few of the items we get.

SSM does not have any analysis functions built in. The next major version of this tool will incorporate the most obvious of these, and the possibility of allowing for single app or filtered app monitoring and analysis. The tool is designed as a method for monitoring events over a period of time such that we can go back through any log files and get an idea of how much memory was consumed, who consumed the memory, or, at a minimum, a projection of the application(s) that are consuming the memory.

The tool can be best thought of as an enhanced version of resource meter. It has almost all of the resource monitoring tools wrapped into a single executable so that there is a single application that may be invoked to help identify resource leaks. The main functionality was to have Heap Walk (32 bit) and Heap Walk (16 bit) in one application and to make use of the LEAKINFO API set in the same single application.

This section includes:

  • Using SSM
  • SSM Command-Line Options
  • SSM Log Files


Using SSM

The most effective use of SSM in tracking down memory leaks is to use it in a passive mode, with no UI. In this mode, depending on the method for running, we generate one or several log files that can be used to make an analysis of the system. The theory of operation is to take snapshots of the status of monitored objects over time within separate time intervals, t1 … tn, where tn is the last snapshot we took of the system. Whenever the tool takes a snapshot, we update one or more of the logs we create with the resource use for that snapshot. Once we have done so, it is fairly easy to go back through the logs to determine what exactly is being consumed, and, most of the time, the name of the application that is consuming the resource.

Once completed, you may use the UI to go back and perform very rudimentary analysis of the logs. The analysis will detail what items had deltas over time which always increased. A delta is known to have increased if the difference between two snapshots is less than zero. The only time this rule is not applied is when the deltas between heap 32 data and heap 16 data "free objects" decrease. In this special case, the deltas between snapshots will always be positive. In virtually all cases, a decrease in the heap free objects will correspond to a decrease in the heap fixed objects (32 bit only). For heap 16 objects, a block of memory, which has been freed, will be allocated to the heap and will fall under the "Free" column with a corresponding owner name of "Free" and a handle of 0x0h.


SSM Command-Line Options

SSM has a variety of command-line options, which are designed to allow flexible and robust analysis of system resources and, optionally, to increase/decrease the granularity of the snapshots. Each option can be thought of as a filter to enable some of the features of SSM.

This section describes the command-line options that are used to detail some of the objects that you can use.

/T:<Time interval between snapshots in minutes>

Specifies the time, in minutes, to take snapshots in. This can be as low as one minute or as large as MAX_INT. The time interval you specify is the most difficult to determine. The rule of thumb is as follows: If resources are consumed very quickly when running, use a time interval that is small. If resources are consumed over a large period of time, use a time interval that is very large. The following table is a rough approximation of what you would typically want to use.

Time to resource exhaustion | Time interval of snapshot
1 Hour | T:5
2 Hours | T:10
4 Hours | T:30
8 Hours | T:60
Above 8T: | T:120

The granularity you use is configurable and any number you specify for T will be honored.

Setting a small time interval for a resource depletion that will occur over several days could generate log files megabytes in size. This is not recommended. Likewise, specifying a time interval very large for resource leaks on the order of an hour or two, will not prove to be useful either. Take extreme care when specifying the interval.

/A (This is preliminary and not completely implemented)

Analyze logs and predict offenders and report lost resources. The /A parameter will take either the /EXPC parameter or the /MTTF parameter as companion arguments. When either of these are supplied, we will automatically assume that either a EZPC or MTTF log file will be present and that data in those logs is consistent with those tests. When neither of these are present, we assume the presence of a log created with /A and will analyze accordingly.


SSM Log Files

There are 6 log files created by default:

SSM-HEAP.LOG

SSM-HEAP16.LOG

SSM-GDI.LOG

SSM-USER.LOG

SSM-MOD16.LOG

SSM-ATOM.LOG

See the corresponding pages for these log files for details on what one should expect to find in these files and how to interpret their meaning.

If during any automated test, including MTTF and EZPC, we detect that any of the 16-bit resources drop to 30% available or, for 32-bit heap memory, the Memory Load (Percent used) goes to 95%, we consider this critical and go ahead and snap full detailed information.

If during any snapshot, SSM finds a 10% delta decrease in a specific item within a resource, we engage full system logging for that data item only. For example, one of the following items:

  • GDI resource usage
  • USER resource usage
  • 16-bit heaps
  • 32-bit heaps

Note that because a specific process appears to leak memory, it may not mean that that process is a leaking application. It could be that the process is legitimately using the windows API set to perform some function and the memory is being lost in that API. Care should be taken that each memory allocation in an application calls the necessary API to free that resource. Otherwise, the application will leak memory and this tool will correctly identify the problem.

After you have completed the tests, you may start SSM and choose Analyze/Analyze or Heap 32 /GDI/User/Heap 16. The output will be all objects whose delta was less than zero except in the special case of Heap 16 and Heap 32. If the Free values for either of these increases, the value is considered a decrease in that object's availability to the operating system.

If you wish to get a granular look at all snapshots, choose Analyze and Filter and select one of the object types to filter. The dialog that appears will give you a list of all elements uniquely found in all the snapshots. You can select one and only one of these to get a concurrent snapshot history of the selected element.

If you wish to see a graphical representation of the object's use, select the graph option to graph out all the objects in the list. Note that this option makes the assumption that the log files will always be less than 100.


SSM-HEAP.LOG

The output will be in the following format:

Module Name
Process ID
Thread Count
Heap Moveable
Heap Free
Heap Fixed
Virtual Committed
Virtual Free
Virtual Reserved

Definitions of items:

Module Name
Name of the module of the process being examined, for example, foo.exe
Process ID
A 32-bit number used as the Process Identifier for this process. The Kernel will use this to value as the tracking mechanism for this module.
Thread Count
Total number of threads in this process. At this time, there is no information that can be gathered about the threads.
Heap Moveable
Bytes used in the process heap that can be moved into the swap file when low memory conditions arise.
Heap Free
Number of bytes in the process heap that is currently free and unallocated.
Heap Fixed
Number of bytes in the heap which cannot be moved into the swap file.

Note Heap Moveable, Heap Free and Heap Fixed correspond to the HeapAlloc, GlobalAlloc, and LocalAlloc APIs.

Virtual Committed
Number of bytes committed with a call to VirtualAlloc with the MEM_COMMIT flag.
Virtual Free
Number of bytes of free virtual memory. Each process will always see 2 GB of virtual memory in their memory space.
Virtual Reserved
Number of bytes reserved in a call to VirtualAlloc with the MEM_RESERVED flag.

Note Virtual Committed, Virtual Free, and Virtual Reserved all correspond to memory allocated with a call to VirtualAlloc. Also note that there is 2 GB of addressable memory for every process.

This output will appear as one single tab-delimited line in the log file.


SSM-HEAP16.LOG

Output will be in the following format:

Module Name
Handle
Data type
Block Size
Unknown
DGroup
Code
Data
Task
Resource
Free
Module
Internal
Burger Master
Sentinel
Module Name
Name of the module with this handle value. This corresponds to the memory in this area.
Handle
16-bit value containing the handle to the owner of this object. We call ModuleFindHandle or TaskFindHandle with this value to get to the owner of the object.
Memory Block Size
16-bit value indicating the size, in bytes, of this memory object.
Data Type
Ignore. This value is used to determine the size of the fields.
Block Size:
Total size of the block for this module/handle. Note that module name to handle correspondence need not be unique.
Unknown
Item is GT_UNKNOWN.
Dgroup
Total size of Dgroup elements for this module.
Code
Total size of code for this element.
Data
Total data element size.
Task
Task entry for this module.
Resource
Resource for this module.
Free
Free block.
Module
A module.

Internal, Burger Master, and Reserved are internal and are measured for historical reasons.

Note If the Memory Type member is not Code or Resource, Data Type is zero.

If the Memory Type is Code, Data, or DGroup, Data Type contains the segment number for the code.

If Memory Type is GT_RESOURCE, Data Type specifies the type of resource.


SSM-USER.LOG and SSM-GDI.LOG

Output will be in the following format:

Name
Owner
Num Objects
Type
Flags
Size Near
Size Far
Name
Module name for this element. This name can be Global (object has no owner), orphaned (Object was orphaned by its owner), or will be the name of the corresponding application that allocated this object. When the name is unknown, there was no owner identified for this object. This does not mean the object has been leaked, it means that all of the methods for finding an application name for this object failed to get a name.
Owner
Owner handle. The flag's value can be used to determine if it was a 32-bit application or a 16-bit application.
Num Objects
Number of objects allocated to this module of the specified type. This is very useful in tracking application resource leaks.
Type
The type of object that was allocated to this module. One of the types described at the end of this section.
Flags
One of the flag values described at the end of this section.
Size Near
Total size of the Near heap these objects have consumed.
Size Far
Total size of the Far heap these objects have consumed.

Note Both USER details and GDI details use the same API and get the same data type back. The difference is only in their names. Hence, each of the /UD and /GD options generate identically formatted data with identical column definitions.

The following describes the types and their meaning:

USER Types:

0101    Window Class
0102    Scroll Window
0103    Listbox
0104    Leftover from Windows 3.0 (Menu)
0105    Clipboard
0106    Combo Box
0107    Palette
0108    Window Handle
0109    Records the state of a window enumeration.
010A    User heap structure
010B    A saved popup bitmap.
010C    User check point information
010D    Cached DC for a window
010E    Pending DeferWindowPos
010F    Window Property Information
0110    Listbox State Information
0111    Miscellaneous User object
0112    User Atom
0113    Private window state recorded while a "LockInput" is active.
0114    User Hook
0115    Debugging memory
0116    Global Hotkey list
0117    Popup menu
0118    A shared icon
0119    User subsystem information
011A    An unprocessed message in the message queue
011B    Internal information structure
011C    A SendMessage that has not returned
011D    USER process information.
011E    Records all active AttachThreadInput()
011F    System color state as recorded by SetSysColorsTemp
0120    Message Queue
0121    Information used by the Alt+Tab window.
0122    A hook notification message
0123    A queued keystate change

GDI Types:

 1    GDI Pen
 2    Handle to a brush
 3    Font object
 4    Palette
 5    Bitmap object
 6    Handle to a region
 7    Display Context
 8    Disable Display Context
 9    Meta DC handle
10    Metafile object

USER and GDI Flags:

0001    Stock GDI object
0002    Private GDI object
000C    Bits used to describe a DC type
0000    Other DC Type descriptors
0004    Memory Display Context
0008    Screen DC
000C    Save DC
0010    Popup Menu
0020    System Menu


SSM-ATOM.LOG

This log file represents a list of all global atoms on the system. It is overwritten on each snapshot and is used primarily for tracking global object usage. The fields are self-evident.


SSM-MOD16.LOG

Not documented. See the Windows® 3.1 SDK for LOCALINFO structure. This log is for debugging purposes only. All fields are totals for the object and the type.


Windows System Debugger

Previous Next

The Windows System Debugger

Microsoft® Windows® System Debugger (debugger.exe) is used to test and debug Windows 9x applications, dynamic-link libraries (DLL), and virtual device drivers (VxD) running with the Windows operating system. You can use System Debugger commands to inspect and manipulate memory and registers, control the execution of code, and perform other debugging operations. This document describes the debugger, explains how to start and use the debugger, and provides detailed information about the debugger commands.

Note that previous versions of the system debugger were called wdeb386.exe and wdeb98.exe, and that some versions of the documentation refer to this name instead of debugger.exe.

This section includes:

Setting up the Windows System Debugger

Using the System Debugger

Reference for Debugger Commands


Setting up the Windows System Debugger

This section is a list of frequently asked questions about setting up kernel debugging for Windows 9x. You'll find answers here about getting started with the System Debugger (debugger.exe). Additional information can be found in the MSDN® Library CD.

Q: How do I get started?
A: You need a computer with a 1394 or serial port. For 1394 many of the serial port issues discussed here do not pertain and may be skipped, including: making the cable, handshaking issues, and transmission speeds.
Q: What are 1394 debugging limitations?
A: The 1394 debugger is limited in a couple of respects. It doesn't become active until the VxD portion of the debugger gets loaded. This means that some issues that may need to be debugged before this time will be unable to be debugged. This is a result of limited space and other limitations of the 16-bit portion of the debugger. Also, when multiple 1394 controllers are present in a system, the first controller found is used for 1394. There is no way to specify which controller to use at this time.
Q: What cables do I need?
A: For 1394 debugging any 1394 cable will do. If you use a serial port, you'll need to buy or make a null-modem cable. You only need a three-line null modem cable (transmit, receive, and ground). You don't need one with handshaking lines because debugger.exe doesn't use handshaking. You should also disable handshaking on your computer. (Handshaking allows slower receivers to keep up with the amount of data being transmitted by requiring the transmitter to stop sending data until it has a chance to catch up.)
Q: How do I handle transmission speed issues without handshaking?
A: 1394 protocols will handle all speed and transmission issues. For the serial port, because handshaking is disabled, it is possible that debugger.exe could send characters to the terminal faster than the terminal can display them. If you find that characters are dropped, you should increase the delay between lines (often a terminal drops characters while scrolling). Use the y CRDELAY=delay debugger command where "value" ranges from zero (no delay) to FFFF (maximum delay). Increase the delay until your terminal stops dropping characters.

You can also lower the speed of the connection. To do this, edit wdeb.ini (located in the root of the boot drive) and change the /r:XXXXX to reflect the new baud rate. For example /r:57600 would use a baud rate of 57600. If the debugger is being loaded from system.ini, edit the debugbaud= line in the [386Enh] section for the same effect.

Q: How do I change the communications port?
A: Edit wdeb.ini (located in the root of the boot drive) and change the /c:X setting to point to the proper COM port. For legacy free machines, use /c:4. If loading the debugger from system.ini, modify the debugcom= setting in the [386Enh] section of system.ini. For 1394, the option is /c:fX, where X is the broadcast channel to use for communications. Each target machine must be on a separate broadcast channel. Channel numbers may range from 0 to 30. (Future drivers may support 0-62.)
Q: What is a null-modem serial cable?
A: Typically with serial ports, you connect a computer to something like a modem. This is how serial ports are designed: you connect a computer, or Data Terminal Equipment (DTE), to a modem, or Data Communication Equipment (DCE). When you connect a computer to another computer, or DTE to DTE, you need a null-modem cable. Debugger.exe requires only the most basic null-modem cable, the three-line null-modem cable. The following illustration shows the null-modem cable's connectors. (The pin numbering would be backwards if you were looking at the computer's ports.)

The following table shows the pin numbers and names of the cable's three lines:

Pin | Name
Pin 2 | Receive
Pin 3 | Transmit
Pin 5 | Ground

Q: Can I use a Laplink V serial cable with debugger.exe?
A: Yes. The blue Laplink cable works fine. Remember to disable handshaking.
Q: How do I disable handshaking on Windows 9x?
  1. Using your right mouse button, click My Computer, and then click Properties.
  2. In the System Properties dialog box, click the Device Manager tab.
  3. In the list of device types, double-click Ports (COM & LPT).
  4. Double-click the name of the port the cable is connected to, usually Communications Port (COM2).
  5. In the Communications Port Properties dialog box, click the Port Settings tab.
  6. In the Flow Control list, click None.
  7. Click OK.
Q: How do I set up debugger.exe?
  1. Install the Windows 9x Device Driver Kit (DDK).
  2. At the command prompt, go to the /debug subdirectory of the directory you installed the DDK in.
  3. Follow the instructions in Installing Debug Environment.
Q: How do I set up Rterm for 1394 debugging?
A: For debugging with 1394 Rterm you will need to install a driver in Windows the first time it is run. This can be accomplished by selecting Install 1394 Driver from the Communications tab on the Options screen. This will start off a driver installation wizard that will need to be directed to the 1394vdbg driver location. This location should contain two files called 1394vdbg.sys and 1394vdbg.inf. Rterm will report an error opening the channel until the driver is finished installing. This is expected. Once this driver is installed, go back to the Communications tab and select the appropriate channel for your setup.
Q: Where can I find out about debugger.exe commands?
A: See Reference for Debugger Commands.
Q: I'm a Windows 2000 and later versions developer. Can I use WinDbg for kernel debugging on Windows 9x?
A: No, you can use only debugger.exe or a third-party debugger such as SoftIce/W for kernel debugging.
Q: What should I do if I can't get debugger.exe to work?
  • Make sure you are using the debugger.exe contained in the Windows DDK. You need this version to work with the retail version of Windows 9x.
  • Run Direct Cable Connection (DCC) to make sure your null-modem cable works. DCC is optionally installed with Windows 9x. To see if it is installed, click the Start button, point to Accessories, and then look for Direct Cable Connection in the menu. If it is not there, use the Add/Remove Programs in Control Panel to install it.
  • Make sure handshaking is disabled on your computer.
  • If the debugger stops responding partway through boot, this could be because you have a debugcom or debugbaud line in your system.ini file. These entries override the values provided in wdeb.ini.
  • If the debugger is dropping characters or if you see garbage characters when doing large output, type y crdelay=8000 to slow down the delay between lines. The value of crdelay is a hexadecimal value from 0000 to FFFF. You may have to experiment with the crdelay value.
  • If you are running out of memory with the debugger, use the wdeb.ini option /L, which will have the effect of shrinking symbol files by a factor of three.
Q: Can I use debugger.exe as a VxD?
A: Yes and no. This is not supported for 1394 debugging. For serial debugging you'll save about 90 KB of conventional memory. You won't, however, be able to access symbols until after the Device_Init message is sent to your VxDs (during Windows 9x startup). So if you use the /b option in the wdeb.ini file to break in VMM32 initialization, the debugger will have no knowledge of symbols until Device_Init is sent.
Q: How do I set up debugger.exe as a VxD?
A: Use the w9xdebug.exe package to do this automatically. To configure this manually, edit system.ini with the following lines:
device=debugger.exe
LoadDebugOnlyObjs=YES
; add debugsym lines for every symbol you want to load
debugsym=C:\WINDOWS\SYSTEM\myapp.sym
debugcom=1
debugbaud=115200

The above example uses COM 1 and a baud rate of 115200.

Q: How do I change the baud rate or COM port with the VxD version of debugger.exe?
A: To change the COM port, change the value in the debugcom= line in the [386Enh] section of System.ini. The following entry sets the COM port to COM2:

debugcom=2

To change the baud rate, change the value in the debugbaud= line. The following entry sets the baud rate to 57,600:

debugbaud=57600

Note that the values in System.ini will override prior debugger.exe command-line settings for the baud rate and COM port.


Preparing to Start

You can start the System Debugger at boot, using a debug io.sys and wdeb.ini, or as a virtual device driver, by specifying it in the SYSTEM.INI file. Before you start, however, prepare for debugging by carrying out these steps:

  1. Connect a serial terminal or other computer by serial cable to a serial port on your debugging computer. Or connect the two computers with a 1394 cable.
  2. Create symbol files for the applications, DLLs, and VxDs you intend to debug (see Creating Symbol Files).
  3. Install the system debug environment if available (see Installing Debug Environment). These are debugging versions of the system DLLs and VxDs and their symbol files that can make debugging easier. These files are available in the Windows Device Driver Development Kit. 1394 debugging requires the use of Rterm.exe.


Connecting the Null-Modem Serial Cable

The debugger displays output and receives user input through a serial communication port of the computer on which it runs. To use the debugger, you must connect the null-modem cable from this serial port to either a serial terminal or the serial port of another computer. A three-wire null-modem cable is the minimum cable requirement for this connection. Typically, users connect the cable to a second computer and use their favorite serial communications software to connect to the serial port and interact with the debugger. The Windows 9x operating system comes with the serial communication program Hyperterminal.


Creating Symbol Files

Symbol files provide the information the debugger needs to display functions, structures, variables, and absolute symbols by name rather than number.

To prepare symbol files, perform the following steps

  1. Compile or assemble your source files, using the appropriate command-line option to generate object files with line-number information. For more information about compiler and assembler options, see the documentation that accompanied your compiler and assembler.
  2. Link the compiled code with the standard libraries (as needed), using the appropriate linker option to create a symbol map (.MAP) file that includes PUBLIC symbols. You may also want to use the linker option for display of line-number information. For more information about linker options, see the documentation that accompanied your linker.
  3. Run the Microsoft Symbol File Generator (MAPSYM.EXE) to create a symbol file for symbolic debugging. MAPSYM converts the contents of your application's symbol map (.MAP) file into a form suitable for loading with the debugger; then MAPSYM copies the result to a symbol (.SYM) file.

Following is the command-line syntax for MAPSYM:

mapsym [/l][/n] mapfilename

Syntax | Description
/l | Directs MAPSYM to display information on the screen about the conversion. The information includes the names of groups defined in the application, the application start address, the number of segments, and the number of symbols per segment.
/n | Directs MAPSYM to ignore line-number information in the map file. The resulting symbol file contains no line-number information.
mapfilename | Specifies the filename for a symbol map file that was created during linking. If you do not give a filename extension, .MAP is used as a default. If you do not give a full path, the current directory and drive are used as a default. MAPSYM creates a new symbol file having the same name as the map file but with the .SYM extension.

In the following example, MAPSYM uses the symbol information in FILE.MAP to create FILE.SYM in the current directory on the current drive:

mapsym /l file.map

Information about the conversion is sent to the screen. MAPSYM always places the new symbol file in the current directory on the current drive. MAPSYM can process up to 10,000 symbols for each segment in the application and up to 1024 segments. If you have many components to debug, you can combine multiple symbol files into a single file by using the Symbol File Librarian (SYMLIB.EXE). This creates a symbol library file and lets you add, remove, or replace .SYM files in it.


What are Debug Binaries

Debug binaries are Windows 9x kernel VxDs that are typically compiled with the DEBUG=1 statement contained in the corresponding makefile. Note the historic difference in nomenclature between Windows 3.x, Windows 9x and NT-based operating systems documentation:

Windows 3.x, Windows 9x | NT-based operating systems | Meaning
"Retail" | "Free build" | Normal retail code build
"Debug binary" | "Checked build" | Debug code build

You do not need to use the debug binaries in order to run and use the debugger. However, debug binaries are extremely helpful when troubleshooting VxDs:

  • Debug binaries contain additional code that issues messages to the debugger terminal. These messages can contain warnings, error information, or other valuable information.
  • Debug binaries frequently contain special debugger "dot command" handling code, not present in the retail drivers (See Dot Commands). Dot commands are intended to reveal the contents of internal data structures unique to the driver that support the Dot command.
  • Debug binaries perform additional verification of data and pointers (using ASSERT functions for example). For example, if a pointer is found to be NULL and it shouldn't be, debug binaries may contain an INT1 or INT 3 breakpoint, causing the debugger to automatically halt at that point (see Breaking Into the Debugger).
  • If symbol files are provided with the debug binary VxD, use them, to make it easier to navigate through the code.


Installing Debug Environment

Use the DbgInst utility to install the debugging environment. It will automatically create the appropriate initialization file entries, copy the appropriate files to your machine, and prompt you to reboot your debug machine. You will need to copy Rterm.exe (included in the DDK) to a separate machine for remote debugging. See the above sections in this chapter for additional information on configuring Rterm and Debugger.exe.

Replacing VMM32.VxD "bound" binaries

During setup, many standalone VxDs are bound into one large file named VMM32.VxD. The number of VxDs bound can vary from machine to machine. This is done for quicker loading. However, there is still a separate, smaller VxD called VMM32.VxD, whose job is to load static system VxDs. The "bigger" VMM32.VxD contains it. The loader VMM32.VxD will first search for and load standalone VxDs located in the path \windows\system\vmm32. These VxDs replace VxDs by the same name that were bound into VMM32.VxD at setup time. Therefore, debug binary vxds that are placed into \windows\system\vmm32 will replace their (retail build) counterparts located in the bound VMM32.VxD. Within the registry or in SYSTEM.INI, an asterisk preceding a driver name (for example, *VPICD, *VDMAD) indicates the driver is a "child" VxD located within VMM32.VxD. The driver replacement rules, just described, also apply to these child device references.

The Windows 9x path \windows\system\iosubsys contains I/O Supervisor (IOS) drivers. IOS is a layered hierarchy of drivers, implementing protected-mode 32 bit disk I/O. The drivers in this path are loaded by *IOS during its DEVICE_INIT phase.

The Windows 9x path \windows\system contains all other VxDs.

If you manually copy debug binary drivers, we recommend that you back up or rename any VxD's that go by the same name in the target path, so you can restore the normal VxDs later.

Debugging WDM Drivers

All WDM debugging under Windows 9x should be done with a standard Win9x system debugger such as debugger.exe or SoftIce. Debug output from WDM drivers such as a USB driver will not be displayed in real-time, unlike other Win95 debug components such as VxDs. Instead all WDM debug output is written to a debug log. To view this log you must use the debug interface of NTKERN.VXD. This is accomplished by breaking into the debugger and then typing "..NTKERN". You then type "D" to dump the NTKERN debug log. Note that the log is dumped in reverse order, meaning the first debug message displayed in the log is the one most recently logged. No debug binaries are required to use the debug log in NTKERN.VXD.


Starting from Boot

You can start the debugger at boot by using the debug version of io.sys and the wdeb.ini initialization file. An example wdeb.ini file looks like this:

/x /c:1 /r:57600
/s:c:\windows\explorer.sym
/s:c:\windows\system\dibeng.sym
/s:c:\windows\system\gdi32.sym
/s:c:\windows\system\gdif.sym
/s:c:\windows\system\kernel32.sym
/s:c:\windows\system\krnl386.sym
/s:c:\windows\system\ifsmgr.sym
/s:c:\windows\system\ios.sym
/s:c:\windows\system\mshtml.sym
/s:c:\windows\system\ndis.sym
/s:c:\windows\system\ntkern.sym

This wdeb.ini file loads the debugger in XMS memory (recommended) using COM 1 and a baudrate of 57,600. It also loads symbol files for several components.

Following are the command-line options and parameters:

Options | Parameters
/A | Specifies that symbol files should not be automatically loaded.
/B | Specifies that the debugger should stop just prior to VMM initialization, after all virtual devices have been loaded and the processor is running in protected mode. This option is useful if you want to install breakpoints early. Also, if you use the debugger's .VMM s command at this stop point, you can turn on verbose device tracing which displays the name of each VxD before it is called, and OK when the VxD returns.
/C:comport | Specifies a COM port for debugger output. You can specify "1", "2", "3", or "4" for comport. Machines with a Legacy Free COM port should specify COM 4.
/D:"commands" | Carries out the debugger command line specified by the string enclosed in quotation marks. Spaces, semicolons (;), and other punctuation can be included in the command string. To use a single quote (') on the command line, use double quotation marks (") before and after the single quotation mark. The commands specified in this option are carried out after symbols are loaded. This means you can set breakpoints in code even before the code has been loaded. Before a segment or module has been loaded or defined, breakpoints can be set on the logical address (a combination of map number and group number) until the segment or module is defined, at which point the breakpoint turns into a real breakpoint.
/H | Specifies that the debugger should be loaded as a VxD.
/L | Specifies that the debugger should be invisible to int 41.
/R:dddd | Sets the baud rate for the debugging terminal.
/S: symfile | Specifies a symbol file to be loaded. This option can be repeated to load more than one symbol file. If the symbol files are not in your current directory, you must supply a full path, because the debugger does not use the PATH environment variable to locate any of the files supplied on the command line. When memory is low, you can use more symbol files by running the Debugger in the Windows directory and specifying the full path of VMM32.VXD (such as \WINDOWS\SYSTEM\VMM32.VXD) instead of WIN.COM.
/T:hhhh | Sets the port number for the timing card (The default number is 250h.). See MSDN® Library CD: Q85897, "Debugger.exe-Compatible Timing Card Available."
/V | Enables verbose mode, which displays messages indicating which segments are being loaded.
/VP | Enables verbose mode, which displays messages indicating which segments are being loaded. This option displays the messages for applications only.
/X | Causes symbols to be loaded into Extended Memory Specification (XMS) memory.
/P | Specifies that debug text will be sent in packet form, with timeouts. This is slightly slower than raw serial data, but serial "line noise" is virtually eliminated.
/PX | Specifies that debug text will be sent in packet form, with infinite retries. This is slightly slower than raw serial data, but serial "line noise" is virtually eliminated.


Starting as a VxD

Running debugger.exe as a VxD requires approximately 90 KB less of conventional memory than running it from the command line. Its only disadvantage is that loaded symbols aren't available until after SYS_CRITICAL_INIT. You can start the debugger as a virtual device driver by placing the following line in your CONFIG.SYS file:

device=c:\windev\debugger.exe

You must specify the full path to the debugger.exe file. You can specify any command-line options on the device line with (for example, you can load symbol files), or you can set options by adding one or more of the following debug settings to the [386Enh] section of SYSTEM.INI:

Setting | Description
DebugCom=comport | Sets the communications port that the debugger uses for input and output. The comport can be 1, 2, 3 or 4, as described for the /C command line option.
DebugBaud=baudrate | Sets the baud rate for the communications port used by the debugger.
DebugCmd=parameters | Lists the debugger commands to execute as the debugger starts. This is typically used to set command-line parameters. For example, use DebugCmd=y /n /b to enable new options and to initially break into debugger at SYS_CRITICAL_INIT. Multiple commands must be separated by semicolons (;).
DebugSym=symbol-files | Specifies the symbol file or files to load.
DebugSymCmd=cmds | Lists the debugger commands to execute immediately after all symbols have been loaded. Multiple commands must be separated by semicolons (;).
BreakInDebugVxD=value | Sets the behavior of the CTRL+C key when pressed on the debug terminal or the CTRL+ALT+SYSREQ key combination when pressed on the computer on which the debugger is running. If value is TRUE, pressing the key stops execution at the current instruction regardless of the privilege (ring) of the code. If FALSE, pressing the keys stops execution in ring 3 code only. The default setting if this entry is not given is TRUE.

If you have the Windows 9x Device Driver Development Kit, you can use the w9xdebug.exe to set up the system debugger.

When you no longer want to run the debugger as a VxD, insert a semicolon before the device=debugger.exe (and device=DEBUGCMD.VXD if present) entry in the SYSTEM.INI file. Any debug options settings you added to the file do not need a semicolon; they will be ignored on subsequent loads of Windows 9x.


Using the System Debugger

Throughout this document, there are many references to debugger dot commands (those commands that begin with a period, such as .VMM). Many of these dot commands only work when the supporting debug binary is installed. See to Reference for Debugger Commands for more information on how to install debug binaries, in order to make debug-VxD-specific dot commands available.

There are many situations in which the debugger.exe debugger is the best or even the only debugger you should use. For example, you might use debugger.exe to diagnose problems such as the following:

  • Tracing through low-level code
  • Viewing virtual/linear/physical memory
  • Viewing advanced 386 processor data, such as the GDT, LDT, IDT, and all of the PMODE registers
  • Tracing hardware interrupt handlers
  • Tracing terminate-and-stay-resident (TSR) programs, or MS-DOS® device drivers
  • Displaying the status of virtual machines (VM)
  • Monitoring all interrupts and exceptions
  • Developing and debugging virtual devices (VxD)

This section gives information about how to use debugger.exe commands and features.


Breaking into the Debugger

To execute debugging commands, you need to break into the debugger and have it display its command prompt. You can automatically break into the debugger as Windows starts by specifying /B option on the debugger.exe command line or in a y command with the DebugCmd setting in the SYSTEM.INI file. The debugger stops execution just after loading VxDs and just prior to initialization. Breaking in at Windows start time is useful if you want to setup breakpoints or use the ".VMM S" command to turn on verbose device tracing (which displays the name of each VxD before it is called, and OK when the VxD returns)

To break into the debugger at any time interrupts are not disabled, press the CTRL+C key combination on the debugging terminal. Alternately, press the CTRL+ALT+SYSRQ key combination on the computer running the debugger. This stops execution at the next convenient location in ring 0 or ring 3 code.

To break into the debugger when interrupts are disabled, you use hardware to generate a nonmaskable interrupt (NMI). This usually means having an external "STOP" button connected to a debugging card installed in computer running the debugger. Some machines may have the capability of connecting a front panel button to the NMI line on the machine bus. In any case, using NMI has the advantage of being able to break into a machine that has hung with interrupts disabled. (You can disable the breaking on nonmaskable interrupts by using the v2 command.)

You can have your application, DLL, or VxD break into the debugger by adding an int 1 or int 3 instruction or a call to the DebugBreak function to your code. The int 1 instruction produces an "Unexpected trace interrupt" message and stops on the instruction after the int 1. This message does not indicate an error condition and can be ignored. An int 3 will break directly on the int instruction and not produce the message. The int 3 is used in system components to stop execution on an error.

Once an int instruction is hit, you can remove it by using the z (Zap) command. This command replaces the int instruction with a nop instruction. For programmers developing virtual device drivers (VxDs), the Debug_Out macro is available to send an ASCII string to the debug terminal and execute an int 1, which will break to the debugger.

Once you have broken into the debugger, you can set additional breakpoints by using the bp or br command. For example, the following command sets a breakpoint at beginning of the function _MyEntryPoint:

bp _MyEntryPoint

The system also breaks into the debugger if an application or DLL causes a general protection fault (GPF) by attempting to read or write memory with a bad selector, beyond a selector limit, or with a selector set to 0. The debugger receives control immediately if it traps interrupt vector 0Dh (the default setting). If you disable this trap (by using the vs command), Windows first displays a dialog box notifying the user of a problem. The user can click the Debug button to pass control to the debugger at the instruction that caused the fault.


Determining the State of the Processor

Once control has been given to the debugger, the prompt character used will provide the protected mode status of the processor. The following table shows what prompt characters may be displayed and the meaning of each:

Prompt | Meaning
> or >> | The processor is in real mode (you should never see this when debugging Windows 9x)
# or ## | The processor is in protected mode
- or -- | The processor is in virtual 8086 (V86) mode

The mode the processor is in will be a good indication of what code is being executed. For example, if the prompt is a "#" (number sign), protected mode code is running. This can be a Windows-based application, DLL, or even the system itself. Stopping in ring 0 code may or may not be desirable. It is useful for VxD developers who need to examine and control execution of their VxDs, but it is not particularly useful for application or DLL developers.

If you are in V86 mode, then a DOS app, DOS device driver or DOS TSR has gone bad. Use the .DOSMGR commands to identify where you are. Do not use the LN command since it won't provide correct V86 information.

If you are in protected mode, then the lower two bits of CS can be used to identify the ring of execution (zero indicates ring 0, 3 indicates ring 3).

CS | Area | CS | Area
0028 | VxD code (ring 0) | 013F | Win32® flat code
0030 | VxD data (ring 0) | 0147 | Win32 flat data
0048 | debugger code | 011F | Krnl386 code
 |  | 0137 | Krnl386 data

The above selectors may be subject to changes in the future. Device driver developers generally debug VxD code, so the corresponding code selector value is usually 0028.

When in ring 0, the EIP should be of the form Cxxxxxxx. If it is not, some code jumped to an invalid address. Use ds esp to attempt to find out who did it.

A Win32 application's EIP should be in the range of 0x00400000-0xBFFFFFFF.

Regardless of the state of the processor, you can use the following command keys and the debugger prompt:

Key | Action
CTRL+A | Repeats the previous command.
CTRL+C | Cancels the current command.
CTRL+S | Freezes a System Debugger display.
CTRL+Q | Restarts the display.

If the target system is executing code, CTRL+S and CTRL+Q are ignored.


Setting Breakpoints

You can set breakpoints using the bp and br commands. With each breakpoint, you can specify breakpoint commands, a string of debugger commands that are executed when a breakpoint is hit. For example, the following command sets a breakpoint that stops execution in the function _MyEntryPoint and displays the registers and stack:

bp _MyEntryPoint+346 "r;k"

Semicolons (;) separate commands from one another. All text is converted to uppercase except for text surrounded by single quotation marks ('). Two single quotation marks ('') or two double quotation marks ("") in a row act as an escape character and add one single quotation mark or one double quotation mark to the string. The maximum length of a breakpoint command is 80 characters. If the breakpoint has no breakpoint command string, debugger.exe executes the default (zd) command.

The conditional execution command (j) is very useful in breakpoint commands. This command executes the command list if the expression evaluates to TRUE (nonzero); otherwise, it continues to the next command in the command line (not including the ones in the command list parameter). If the command list contains more than one command, it must be enclosed in single or double quotation marks. Use a semicolon (;) to separate commands. No quotation marks are required if the command list contains zero or one command. The conditional execution command can be used in breakpoint commands to halt execution when an expression becomes true or in the default command.

Any operator, number, or symbol value can be used in the conditional expression. Always put a zero in front of a hexadecimal number that begins with a non-numeric character. Doing so will prevent the debugger from treating the number as a symbol and searching all the loaded symbol files. For example, using 0f000 is faster than f000.

For example, the following command stops execution and display registers only if the variable _MyVar is equal to 3 when control enters the _MyEntryPoint function. Otherwise, it displays the current value and continues:

bp _MyEntryPoint "j _MyVar == 3 r;'? "_MyVar=%x" _MyVar;g'"

Here are some additional breakpoint examples:

##bl
0 d %c02e9ba0 [VKD_Set_Focus + 33]
1 d %c012a57c [VKD_VM_Service_Phys]
2 d W4 %c012c4f8 [VKD_8042_cmd_table + 1e8]
3 e %c012ad8f [VKD_Chk_BIOS_Toggle_State + 21] "? 'BIOS %X',AL;G"
4 e %c02ea32d [Hot_Key_Ended + ae] "? 'PriNot %x', DW 0C012BC2D;G"
5 e %c012aaa4 [Update_Shift_State] "? '%X %X', DW 0C012BC2D, DW ESP;G"
6 e %c012a8b1 [Queue_Output + 1] "J DI==8 R;G"
7 e %c012a8b0 [Queue_Output] "J(AL==38 OR AL==0B8) '?''%X %X %X'',AL,DI,DW ESP;G';G"

Breakpoints zero and one are simple breakpoints; nothing much to say.

Breakpoint two is a write breakpoint, established via br w4 %0c012c4f8. This causes the debugger to halt whenever somebody (w)rites to the dword (4) at %c012c4f8. You can also set (r)ead and (e)xecute breakpoints. For read and write breakpoints, you also have to say the size of the object you want to break on, either 1, 2 or 4.

Breakpoint three is a simple command breakpoint. Whenever VKD_Chk_BIOS_Toggle_State+21 is hit, the command "? 'BIOS %X',AL;G" is executed. This command itself is in two parts. The first part is a ? command, which acts like printf. The print format is '%X' which means a hexadecimal value, and the argument is AL. So what the print command does is display the current value of the al register. The second command is G, which tells the debugger to resume execution after doing the requisite printing.

Breakpoint four is a minor extension of breakpoint three. Instead of printing AL, it prints DW 0C012BC2D. As noted above, the DW operator dereferences the dword at the specified location. So breakpoint four, when hit, displays the current dword value stored at address 0C012BC2D.

Breakpoint five is a minor extension of breakpoint four. A second value is printed, DW ESP. This displays the dword at the top of the stack, which is the address of the caller.

Breakpoint six is a simple conditional breakpoint. When the breakpoint is hit, the expression DI==8 is evaluated. If true, then R is executed (displaying registers); otherwise G is executed (resume execution). In other words, the breakpoint means Stop if DI==8.

Breakpoint seven combines all the tricks. The condition is (AL==38 OR AL==0B8). If the condition is met, then three values are printed, and execution continues. If the condition is not met, then execution continues without printing anything. Note first that quotation marks are used to enclose the commands to be executed if the condition is met. This needs to be done to protect the semicolon embedded within the command string from being interpreted as the end of the J command. Note second that the quotation marks that provide the print format are doubled, because they already live inside the quotation marks that are used to enclose the conditional command.

Debugger breakpoints can be "used" as markers by merely setting a (disabled) breakpoint at an address you will need to refer to frequently. For example:

## bp 12345678

## bd0 &qquad; assuming that 12345678 was bp0

## d br0+10 &qquad; dump at 12345688

If the code containing a breakpoint gets paged out to disk, you cannot remove that breakpoint until it is paged back in.


Using Symbols with debugger.exe

With debugger.exe, all symbols are maintained into one single namespace. Symbols are explicitly managed using w, wr, and wa. You can selectively enable and disable entire symbol files. When disabled, the debugger ignores all symbols that belong to a symbol file ("map").

Symbols not loaded by debugger.exe can be loaded remotely by rterm.exe. By default, rterm will look for symbols in the directory it is launched from. You can modify where rterm looks for symbol files by choosing Options from the Settings menu, and selecting the Symbol Search Paths tab in the options dialog. Alternately, you can use the !sympath command on the rterm command line to set this path – for example:

1##!sympath

Symbol path is c:\rterm

1##!sympath d:\symbols

Symbol path is d:\symbols

The w command lists all the maps that are loaded, both enabled and disabled.

The lm command can also be used to list all loaded maps

The wr command disables a symbol file ("removes a map").

The wa command enables a symbol file ("adds a map").

For example, wr explorer will remove the explorer map from the debugger's symbol table. Keeping only the maps relevant to your project is important because the debugger's symbol table doesn't understand memory contexts. For another example, wa d:\symbols\myapp would load the myapp symbol from d:\symbols and add it to the list of loaded symbols.

As a shortcut, the asterisk means "all maps". So wr * disables all maps, and wa * re-enables them. Disabling all maps is useful if you want to discard all the symbolic information because the user is running with the wrong symbols.

Every symbol is mapped to a linear address, and that becomes its identity. In particular, the memory context and CPU mode are not factors in looking up a matching symbol. As a consequence, if you are running Win32® code, and you try to resolve an address that happens to match that of a Win16 driver or a DOS application, then you get symbols displayed that are irrelevant to the context of your code.

To search the active maps for symbols, you can us the ls (list symbols) or lse (list symbols by regular expression) commands. The argument is either a DOS-style (ls) or a UNIX-style (lse) pattern that will be looked up in all active maps. These are useful if you have the same symbol in multiple files and the debugger keeps picking the wrong one, and you choose not to go and disable all the maps that contain the bogus ones.

If you type a partial symbol name (at least five characters) and no perfect match is found, debugger.exe will search for symbols that start with the characters you specify and present them in a list. You can then pick the one you really want and continue onwards.

If, in spite of everything, debugger.exe can't find a symbol to match your address, it will search internal operating system data structures, hoping to find something. If it has some Win16 address, it will walk the Win16 module list, checking to see if the selector is a code or data segment that belongs to any module in memory. If so, then it displays the address in the form MODULE!(n), where MODULE is the module name and n is the object number (1-based).

If the address lives in VxD space, then debugger.exe will look at the list of in-memory VxDs and try to figure out which (if any) VxD contains the address. If found, the address is given in the form DDB(n)+zzzz, where DDB is the VxD DDB name, n is the object number, and zzzz is the offset within the object.

If the selector lives on the 16-bit global heap, but debugger.exe can figure out which task allocated the memory, it will display the address in the form TASK!, where TASK! is the module name of the owner.

If the address lives in the Win32 memory space, then debugger.exe will look at the page table entries and figure out which module table entry the memory belongs to. It will then display the address in the form IMTEnnnn+zzzz, where nnnn is the module table entry index, and zzzz is the rva. If debugger.exe can find the Win32 module table on its own, then it will do the conversion of the IMTE into a module name and display the result in the form MODULE.DLL+zzzz, where MODULE.DLL is the name of the module and zzzz is the rva.

In summary:

· MODULE!(n) Win16 module selector

· TASK! Win16 global heap

· IMTEnnnn+rva Win32 module

· nnnnnnnn:DDB(n) VxD

If the symbol address is listed with an at sign (@), it means that the module associated with the symbol is not in memory (or at least, is not in memory as far as debugger.exe can determine). You can set a breakpoint on it. When the module finally gets loaded, debugger.exe will instantiate the breakpoint.


Setting the Default Command

The debugger runs the default command string when it reaches any breakpoint that you have set with the g (go), bp (Breakpoint), or br (Breakpoint Register) command. It also runs the default command when you run the p (program trace), t (trace), or zd command.

Initially, the default command string is set to the r (Register) command, but you can change it by using the zs (Set Default) command. If any errors occur (for example, if the command line is too long), the default command returns to the r command. The default command can be any sequence of debugger commands each separated by a semicolon (;). In the default command, j commands can be useful.

Here is the default command needed to continue execution each time the application or test program encounters an Interrupt 3:

zs "j (by cs:eip) == 0cc 'g'"

The following sample will trace until the doubleword at 137:00001234h is equal to 0EEDh (a primitive watchpoint). This operation must be started with a T, a P, or a ZD command so that the default command can be executed. If this operation is started by the G command, the default command will not execute unless execution is stopped on a go breakpoint or on a sticky breakpoint with no breakpoint command.

zs "j (dw 137:00001234) == 0eed 'r';t"

zd

The following sample will perform a trace that displays each instruction until control is returned to code segment or selector 137h. Notice that PN displays only the disassembly line and not the register set, saving line space on the debugger's terminal screen.

zs "u cs:eip l1; j cs == 0137 'r';pn"

zd

You can use the debugger default-command option to loop through a linked list (in this example, the next pointer is at offset 14), printing each packet on the list.

zs "?'%08.8x', eax; reax = dw (%(eax+14));zd"

It does destroy the contents of eax, but that can be restored. You can also replace the zd with a j eax != 0 'zd', and then it will stop at the end or some other condition to stop on. You need to set eax to the address of the first record and execute zd.

When finished, type zs "r" to restore the default-command to its normal value.


If You Stop in the Debugger

If You Don't Know Why You Stopped

If you do not see a reason why you stopped, the message may have been "lost in the noise". Disassemble backwards from the current location and see if any of the addresses pushed onto the stack are strings.

The following sample sessions indicate possible techniques to ferret out error message strings:

##u eip-0b L2
0028:........ push xxxxxxxx
0028:........ call dword ptr [__Debug_Out_Service (........)]
##da xxxxxxxx
0030:xxxxxxxx ... this is the error message...
##u eip-0a L2
0028:........ push xxxxxxxx
0028:........ call yyyyyyyy
##da xxxxxxxx
0030:xxxxxxxx ... this might be the error message...
##u eip-0d L3
0028:........ push xxxxxxxx
0028:........ call yyyyyyyy
0028:........ add esp, nn
##da xxxxxxxx
0030:xxxxxxxx ... this might be the error message...

Hard-Coded Traps into The Debugger

Different components react to errors or assertion failure differently. Note that the following remarks are general principles; exceptions are not uncommon. Always cross-reference against the source code to be sure.

VMM32 uses int 3 for code coverage, int 1 for fatal errors, Debug_Out for assertion failures.

IOS uses int 3 for code coverage and Debug_Out for assertion failures. (Though it occasionally uses int 3 for assertion failures, too.)

If Your Code Is at Fault

Disassemble near the faulting location to see if what you get is proper code or not. Don't forget that ASCII text may look deceptively valid. Another thing to check is whether ESP and EIP are very close to each other. If so, this suggests a stack-balancing problem (too many pushes or pops). Dump the stack back to find the last known sane location and start working forwards.

Type u cs:eip to see if what you get is proper code or not. If you see any of the following, then you do not have proper code:

  • Any instruction of the form db xx.
  • Any instruction of the form lock xx.
  • Any instruction whose opcode begins with the letter f (floating point).
  • The same instruction repeated over and over, especially if it is one of the following:

    add byte ptr [eax], al

    and byte ptr [edi], al

    add byte ptr [bx+si], al

    and byte ptr [bx], al

  • Anything else that obviously makes no sense.

If that quick test passes, then type db cs:eip-40 and check if you are in the middle of a data segment. One dead giveaway is that you see ASCII strings in the dump.

If Ln cs:eip Gives You a Name

The command Ln cs:eip can supply you with the name of the module or routine. However, if you die very near the beginning of a routine, or if you see a message (in DEBUG) like 'Invalid mumble passed to ProcedureName', then the error is not in ProcedureName but rather in the caller. Dump the stack back to find the caller.


Reference for Debugger Commands

  • Command Quick Reference

    Quick reference list of System Debugger commands, ordered by Command Type.

  • Command Details

    A list of DEBUGGER.EXE's commands.

  • Dot Commands


Command Quick Reference

The following is a quick reference list of System Debugger commands, ordered by Command Type:

Command | Command Type | Additional Arguments | Description
? |  |  | print help menu
? |  | <expr> | [h|d|t|o|q|b].<expr> | display expression (h = hex, d or t = decimal, o or q = octal, b = binary)
? |  | "printf string", <expr>, <expr>, | printf command
BC | Breakpoint/Step | [<bp list> | *] | clear breakpoint(s)
BD | Breakpoint/Step | [<bp list> | *] | disable breakpoint(s)
BE | Breakpoint/Step | [<bp list> | *] | enable breakpoint(s)
BL | Breakpoint/Step |  | list breakpoint(s)
BP | Breakpoint/Step | [<bp>] [<addr>] [<passcnt>] ["<bp cmds>"] | set a breakpoint
BR | Breakpoint/Step | [<bp>] E|W|R|1|2|4 [<addr>] [<passcnt>] ["<bp cmds>"] | set a Pentium processor debug register (hardware breakpoint).
C | Register, Memory, Port | <range> <addr> | compare bytes
D | Register, Memory, Port | [<range>] | dump memory
DA | Register, Memory, Port | [<range>] | dump asciiz string
DB | Register, Memory, Port | [<range>] | dump memory in bytes
DD | Register, Memory, Port | [<range>] | dump memory in dwords
DG[A] | 80386 Data Structure | [<range>] | dump GDT entries
DI[A] | 80386 Data Structure | [<range>] | dump IDT entries
DL[A|P|S|H] | 80386 Data Structure | [<range>] | dump LDT entries
DP[A|D] | 80386 Data Structure | [<range>] | dump page directory/table entries
DT | 80386 Data Structure | [<addr>] | dump TSS
DW | Register, Memory, Port | [<range>] | dump memory in words
DX | Miscellaneous |  | dump contents of loadall buffer
E | Register, Memory, Port | <addr> [<list>] | enter memory
F | Register, Memory, Port | <range> <list> | fill memory
G[S|H||T|Z] | Breakpoint/Step | [=<addr> [<addr> ...]] | go
H | Miscellaneous | <word> <word> | hexadd
I | Register, Memory, Port | <word> | input a byte from port
ID | Register, Memory, Port | <word> | input a dword from port
IW | Register, Memory, Port | <word> | input a word from port
J | Breakpoint/Step | <expr> [<cmds>] | execute <cmds> if <expr> is true (non-zero)
K[V|S|B] | Disassemble / Stack Trace | [<SS:BPaddr>] [<CS:IPaddr>] | stack trace
K[V|S|B]T | Disassemble / Stack Trace | [TDB] | task stack trace
KA | Disassemble / Stack Trace | <numargs> | set number of stack dump arguments
LA | Symbol, Symbol Map | [<mapname>] | list absolute symbols in active maps
LG | Symbol, Symbol Map | [<mapname>] | list groups in active maps
LM | Symbol, Symbol Map |  | list linked and active maps
LN | Symbol, Symbol Map | [<addr>] | list near symbols
LS | Symbol, Symbol Map | [<addr>] | list symbols in group
LSE | Symbol, Symbol Map | <re> | list symbols specified by regular expression
M | Register, Memory, Port | <range> <addr> | move
O | Register, Memory, Port | <word> <byte> | output a byte to port
OD | Register, Memory, Port | <word> <dword> | output a dword to port
OW | Register, Memory, Port | <word> <word> | output a word to port
P[N|T|Z] | Breakpoint/Step | [=<addr>] [<word>] | program step
R[T]|[<reg>] | Register, Memory, Port | [[=] <word>] | Register The values used in the R cmd for changing the flags register are:
S | Register, Memory, Port | <range> <list> | search
T[A|C|N|S|X|Z] | Breakpoint/Step | [=<addr>] [<word>] [<addr>] | trace
U | Disassemble / Stack Trace | [<range>] | unassemble
V | Miscellaneous |  | Display debugger version/date
V[1 | 3] | Interrupt Vector |  | specify rings to intercept a trap vector
V2 |  |  | enable/disable NMI trapping in Ring 0
VC[N|P|V|R|F] | Interrupt Vector | <byte> ... | stop intercepting trap vector
VL[N|P|V|R|F] | Interrupt Vector |  | list trap vectors intercepted
VO [N|P|R|V] | Interrupt Vector |  | lists interrupt vectors in the display format based on the newvec option.
VS[N|P|V|R|F] | Interrupt Vector | <byte> ... | intercept trap vector, ring 3 only
VT[N|P|V|R|F] | Interrupt Vector | <byte> ... | intercept trap vector, all rings
W | Symbol, Symbol Map | [<map name>] | make named map active
WA | Symbol, Symbol Map | [<mapname> | *] | add a map to the active list
WR | Symbol, Symbol Map | [<mapname> | *] | remove a map from the active list
X | Miscellaneous |  | Dumps a listing of the current execution environment (Bug report info).
Y[?] | Miscellaneous |  | display/modify debugger options
Z | Breakpoint/Step |  | zap the previous INT 1 or the current INT 3 with NOP's
ZD | Miscellaneous |  | execute the default command
ZL | Miscellaneous |  | list the default command
ZS | Miscellaneous |  | set the default command


Dot commands

Dot commands are commands that are directed to the debugger entry point of a corresponding VxD. "System dot commands" are those commands that are always available. There are dot commands for several debug binary VxDs. The "Required debug binary .VxD" column indicates the debug binary that must be loaded to use the corresponding dot command(s). Many of the following debugger dot commands first require the installation of their corresponding debug binary VXD version. The following system dot commands are applicable to Windows 9x Version B (OSR2), but are generally the same for Golden Windows 9x.

Command | Additional Argument(s) | Required debug binary .VxD | Description
..<cmd> - Pass "cmd" directly to the VMM
.? (system) Prints help message
.<dev_name> - Display device (VxD) specific info (if supported by the VxD)
..BIOS BIOS BIOS (space for help)?
a — Show all BIOS devnodes
e — Dump recent BIOS events
l — Show List (Show every PCI devnode)
s — Show selected devnode
y — Select devnode
z — Select devnode by index
.CSP | VMM | Toggles catch stray pointer flag
.DF | (system) | Dumps the free list
.DG | [handle | selector | arena(386)] | (system) | Dumps the global heap
.DH | [0 (from top) | -1 (from bottom)] | (system) | Dumps the local heap
.DM | (system) | Dumps the Win16 module list
.DOSMGR - Dumps various data structures related to real-mode DOS.
  • Display SFTs
  • Display DPBs
  • Display MCBs (dump the real-mode memory map)
  • Display CDSs
  • Display PDBs (dump the real-mode process map)
  • Display DEVs
  • Display BDSs
  • Display INT 21h status
.DQ | (system) | Dumps the task queue
.DS | (system) | Dumps protected mode stack with labels. Dumps the VMM stack. Shows the stack pointer value, the DWORD contents and tries to display a code label that is near to each DWORD value. The label dump is sometimes useful for determining what chain of procedures have been executed to get to the current point, but it sometimes displays labels for DWORD values that really don't apply (i.e. 80000028 might display VMM_TEXT:DEBUG_ValidateLinear, when the value may really be from pushing the segment value 28, because pushing a segment value just decrements ESP and doesn't force a zero word for the high word.) So, this command can be useful, but requires some programmer interpretation to identify the correct stack trace.
.DU | (system) | Dumps the LRU list
.I? | IOS | Help menu for IOS commands
.IDCB | <addr> | IOS | Dumps I/O Subsystem Device Control Block structure.
.IIOP | <addr> | IOS | Dumps I/O Subsystem I/O Packet structure.
.IMED | IOS | Dumps I/O Subsystem Memory Element Descriptor structures.
.IDV | DISKVSD & IOS | Display disk calldown/callup statistics
.ISAPNP | ISAPNP | Display current read data port, followed by information about each ISA bus card (if any).
.LQ | VMM | Displays the queue of messages queued with the macro Queue_Out.
.M | (system) | Dump assorted memory manager structures. Type '.M?' for a list of memory structures, and additional information.
.MEMCHECK - Display misc. memory layout
.NTKERN | NTKERN | OSR 2.1 & Windows 9x NT WDM (USB etc.) support. Typing this command supplies you with a menu, which includes the ability to dump its debug log ("D"). The debug log displays in LIFO order.
.P [?] DEBUGCMD Debugger tools when DEBUGCMD.VXD is installed (rename DEBUGCMD.TMP to DEBUGCMD.VXD, place it into \WINDOWS\SYSTEM, and load it by putting DEVICE=DEBUGCMD.VXD in the [386Enh] section of the SYSTEM.INI file):
.p? — Main help menu

.p<cmd>? — For more extensive help on a cmd

.p — lists threads in system

.p <*/thread id> — lists status of one thread

.pf — lists threads and their flags

.ps <Thread handle/id> — Dumps ring 0 stack with labels

.psx <Thread handle/id>Dumps 20 lines of ring0 stack and returns

.pdev <Address> — Finds nearest VXD name

.plog <flags>Set scheduler query logging flags

.pmtx <Mutex Address> — display mutex state

.psem <Semaphore Address>display semaphore state

.pthcb <Thread handle/id> — display thread control block

.pprdDisables the logging of priority changes

.ppre — Enables the logging of priority changes

.pprf <filter> — Logs only boosts changing these bits

.pprl <Thread handle/id> — Lists priority changes recorded

.pmax — Show thread and VM maximum DOS386 stack usage
.PCI PCI PCI debug utility. Note that to use .PCI you must remove debugcmd.vxd from the system because its .P command prevents .PCI from being recognized.
"Welcome to PCI's debugger"
A — show All; Show every PCI devnodes

B — show Busses; Show PCI bus structure

C — Config space; Toggle full/partial config space

D — Enter dwdata; Enter data in config space in dwords

E — Enter data; Enter data in config space

F — FindIRQRoute; Help find the IRQ routing

G — Global info; Show global PCI info

I — IDE Test; See if secondary IDE is enabled

L — show List; Show every PCI devnodes (short)

Q — Quit; Quit the debugger

R — show Rom; Show ROM of selected devnode

S — Show selected; Show selected devnode

T — Trace CS; Trace config space access

Y — select devnode; Select DevNode

Z — select devnode; Select DevNode by index
.R [#] - Displays the registers of the current thread. For example, if you used <ctrl c> to break into the system, this will show you the debugger's <ctrl c> handler.
.REBOOT | (system) | reboots machine
.S [#] VMM Displays short logged exceptions starting at #, if specified.
.SL [#] VMM Displays long logged exceptions just #, if specified.
.T | VMM | Toggles the trace switch.
.VC [#] ------ (system) Displays the current VMs control block
.VDMAD | VDMAD | Virtual DMA Device State Dump
.VDD VDD Virtual Display Device State Dump. Also offers additional options:
1 — display VM register states
2 — display VM memory usage
3 — dump video page info
4 — display msg mode register state
5 — display planar mode register state
6 — read DAC
7 — display VM DAC states
8 — enable Queue_Outs
9 — enable MemC debug event
.VFLATD | VFLATD | Virtual Flat Video Buffer Device statistics and event log
.VH [#] ------ (system) Displays a VMM linked list, given list handle
.VKD VKD Virtual Keyboard Device
[0] — General info
[1] — Hot Key info
[2] — Per VM info
[3] — Set VKD queue_outs
[ESC] — Exit VKD debug query
.VL | (system) | Displays a list of all valid VM handles
.VM [#] ------ (system) Displays complete VM status
.VMM (system) Menu VMM state information:
[A] — System time
[B] — Display Critical Section info
[C] — Display blocked thread information
[D] — Reset dyna-link profile counts
[E] — I/O port trap information
[F] — Reset I/O profile counts
[G] — Turn procedure call trace logging on
[H] — V86 interrupt hook information
[I] — PM interrupt hook information
[J] — Reset PM and V86 interrupt profile counts
[K] — Display event lists
[L] — Display device list (all VxDs)
[M] — Display V86 break points
[N] — Display PM break points
[O] — Display interrupt profile
[P] — Reset interrupt profile counts
[Q] — Display GP fault profile
[R] — Reset GP fault profile counts
[S] — Toggle verbose device call trace
[T] — Dyna-link service profile information
[U] — Fault Hook information
[V] — Display time out queues
[W] — PM CLI/STI trace info
[X] — DPMI info
.VPICD - Virtual PIC Device status (status of hardware interrupts)
[1] — Global PIC information (ring 0)
[2] — Per-VM PIC information (virtualized VM state)
[3] — IRQ handler information (hardware interrupts and who is responsible for each)
.VR [#] ------ (system) Displays the registers of the current VM (both the current and alternate registers). Used to examine both V86 mode and protected mode portions of the VM.
.VS [#] ------ (system) Displays the current VM's virtual mode stack
.VXDLDR - Displays the list of dynamically loaded devices
.Y <expr> CONFIGMG Displays CONFIGMG (Plug & Play) structures:
Welcome to CONFIGMG's debugger
A (Arbitrators) — Show the list of arbitrators
B (Block queue) — Prevent processing of events
C (Query remove) — Query removal at happy time
d (remove) — Removal at happy time
e (toggle Echo) — Set the echo to a specified level
f (show Free) — Show free resources
g (enumerate) — Enumerate a devnode
h (Reenable Appy) — Reenable checking of query remove
i (Show Log) — Show procedural logs
j (test walks) — Test our walk procedures
k (Show stack) — Show stack of procedure logs
l (show List) — Show devnode list
m (screen size) — Set screen size
n (Nuke logs) — Nuke the procedure logged
p (Problem) — List devnodes with problems
q (Quit) — Quit the debugger
r (show Range) — Show a Range
s (Show tree) — Show the hardware tree
t (toggle time) — Toggle the display of time
u (Unblock queue) — Restart processing of events
v (View status) — View the global status of CONFIGMG
w (show all range) — Show all the rangelists
x (eXclude) — Filter logging of procedure logs
y (force smthng) — Call some random HWProfile API
z (Allow DLL call) — Allow the DLLs to be called

Where…

<range> = [<addr>] [<word>] | <addr> [L <word>]

<addr> = [& | #][<word>:]<word> | %<dword> | %%<dword>

<list> = <byte> <byte> ... | "string"

<binary ops> = : | * / MOD + . - << >> < > >= <= AND XOR OR && ||

<unary ops> = &seg #sel %lin %%phy ! NOT SEG OFF BY WO DW POI PORT WPORT

(OFF=offset, BY=byte, WO=word/16-bit near proc, DW=dword/32-bit proc, POI=16-bit FAR addr, PORT=I/O byte port, WPORT=I/O word port)

Regular expressions <re>:

. any character, [] character class, [a-z], [^a], etc

* match zero or more, # match zero or one, + match one or more

Supported printf format characters are:

Character | Description
%% | %
%c | character
%[-][+][ ][0][width][.precision][p][n]d | decimal
%[-][0][width][.precision][p][n]u | unsigned decimal
%[-][#][0][width][.precision][p][n]x | hex
%[-][#][0][width][.precision][p][n]X | hex
%[-][0][width][.precision][p][n]o | octal
%[-][0][width][.precision][p][n]b | binary
%[-][width][.precision][a]s | string
%[-][width][.precision][a][p][n][L][H][N][Z]A | address
%[-][width][.precision][a][p][n][L][H][N][Z]S | symbol
%[-][width][.precision][a][p][n][L][H][N][Z]G | group:symbol
%[-][width][.precision][a][p][n][L][H][N][Z]M | map:group:symbol
%[-][width][.precision][a][p][n][L][H][N][Z]g | group
%[-][width][.precision][a][p][n][L][H][N][Z]m | map
a | pointer to a AddrS structure
H | 16 bit offset
L | 32 bit offset
N | offset only
Z | no address
p | gets the previous symbol, address or offset
n | gets the next symbol, address or offset

Prompts are:

> real mode

- or -- virtual 8086 mode

# or ## protected mode


Common Selector Values:

CS | Area
0028 | VxD code (ring 0)
013F | Win32 flat code
0030 | VxD data (ring 0)
0147 | Win32 flat data
0048 | debugger code
011F | Krnl386 code
0137 | Krnl386 data


Command Syntax

Commands consist of command names and parameters. Names and parameters are not case-sensitive.

If a syntax error occurs in a debugger command, the debugger redisplays the command line and indicates the error with a caret (^) and the word Error, as in the following example:

A100

^ Error


Parameters

You can separate command parameters with delimiters (spaces or commas), but a delimiter is required only between two consecutive hexadecimal values. The following commands are equivalent:

dCS:100 110

d CS:100 110

d,CS:100,110

Following are the parameters you can use with commands:

addr
Represents an address parameter in one of four forms. For more information about the operators shown in the following address forms, see Binary and Unary Operators.
Address form | Description
#1f:02C0 | Protected-mode address (selector:offset)
%31020 | Linear address
%%31020 | Physical address
&0100:02FF | Real-mode address (segment:offset)

Any of these specified address forms overrides the current address type.

byte
Specifies a two-digit hexadecimal value.
cmds
Specifies an optional set of debugger commands to be executed with the bp (Breakpoint) or j (Conditional) command.
count
Specifies a count. Valid values depend on the command with which this parameter is being used.
dword
Represents an eight-digit (4-byte) hexadecimal value. The DWORD data type is most commonly used as a physical address.
expr
Represents a combination of parameters and operators that evaluates to an 8-bit, 16-bit, or 32-bit value. An expr parameter can be used as a value in any command. An expr parameter can combine any symbol, number, or address with any of the binary and unary operators.
flags
Specifies one or more conditions. Valid conditions depend on the command with which this parameter is being used.
group-name
Specifies the name of a group that contains the map symbols you want to display.
list
Specifies a series of byte values or a string. The list parameter must be the last parameter on the command line. Following is an example of the f (Fill) command with a list parameter:

fCS:100 42 45 52 54 41

map-name
Specifies the name of a symbol map file.
name-chars
Specifies one or more characters.
number
Specifies a numeric value. Valid values depend on the command with which this parameter is being used.
object
Specifies a handle, a selector, or a heap address.
option
Specifies an option. Valid options depend on the command with which this parameter is being used.
range
Specifies the block of memory on which the command should operate. The range parameter can be two addresses (addr addr); or it can be one address and a length (addr L word, where word is the number of items on which the command should operate; 80h is the default value). Following are three valid examples:

CS:100 110

CS:100 L 10

CS:100

The limit for range is 10000h. To specify a word of 10000h using only four digits, use 0000h or 0h.

reg
Specifies the name of a microprocessor register.
string
Represents any number of characters enclosed in single quotation marks (') or double quotation marks ("). For quotation marks that must appear within string, you must use two sets of quotation marks. For example, the following strings are valid:

'This ''string'' is OK.'

\"This \"\"string\"\" is OK.\"

However, the following strings are not valid:

\"This \"string\" is not OK.\"

\"This 'string' is not OK.\"

The ASCII values of the characters in the string are used as a list of byte values.

word
Specifies a four-digit (2-byte) hexadecimal value.


Binary and Unary Operators

Following, in descending order of precedence, are the binary operators that can be used in commands:

Operator | Meaning
( ) | Parentheses
: | Address binder
* | Multiplication
/ | Integer division
MOD | Modulus (remainder)
+ | Addition
– | Subtraction
> | Greater-than relational operator
< | Less-than relational operator
>= | Greater-than/equal-to relational operator
<= | Less-than/equal-to relational operator
== | Equal-to relational operator
!= | Not-equal-to relational operator
AND | Bitwise Boolean AND
XOR | Bitwise Boolean exclusive OR
OR | Bitwise Boolean OR
&& | Logical AND
|| | Logical OR

Following, in descending order of precedence, are the unary operators that can be used in commands:

Operator | Meaning
&(seg) | Address of segment value
#(sel) | Address of selector value
%%(phy) | Address as a physical value
%(lin) | Address as a linear value
– | Two's complement
! | Logical NOT operator
NOT | One's complement
SEG | Segment address of operand
OFF | Address offset of operand
BY | Low-order byte from given address
WO | Low-order word from given address
DW | Doubleword from given address
POI | Pointer (4 bytes) from given address — this operator works only with 16:16 addresses
PORT | 1 byte from given port
WPORT | Word from given port


Regular Expressions

The set of regular expressions that the debugger supports for matching symbols is similar to the set supported by UNIX grep. The debugger set includes a few enhancements.

Following are the wildcards:

Wildcard | Description
. | Matches any single character.
[ ] | Defines a character class; matches a set or range of characters.
^ | Negates a character class.

Following are the postfix operators:

Operator | Description
* | Causes the previous wildcard or single character to match zero or more characters.
# | Matches zero or one.
+ | Plus sign, matches one or more.

Anywhere a symbol is accepted, a regular expression can be used. If there is more than one match, a list of matching symbols is displayed and you must select the proper symbol. The symbol match is not case-sensitive.

The asterisk (*), number sign (#), and plus sign (+) are already math expression operators. To be recognized as a regular expression operator, each of these characters must be immediately preceded by an escape character — the backslash (\). The period (.), opening bracket ([), and closing bracket (]) do not require escape characters. Anything inside the brackets of a character class does not have to be escaped. Following are valid character classes:

[a-z]

[;*+#]

Characters are escaped at two levels: in the expression evaluator and in the regular expression parser. A character special to the expression evaluator (*, #, +, or \) must be escaped to make it to the regular expression parser. If a character special to the regular expression parser must be escaped (for example, to match symbols with * or # in them), it must be escaped twice. If a backslash is needed in an expression, it must be double escaped.

Following are sample regular expressions:

Regular expression | Description
sym.\* | Matches any symbols beginning with the string sym.
sym\* | Matches sym alone and sym followed by any characters.
.\*sym.\* | Matches any symbols containing the string sym.
sym[0–9] | Matches sym0, sym1, sym2, and so on.
sym\\\* | Matches sym*.
sym\\\\ | Matches sym\.
sym\\\\.\* | Matches any symbols beginning with the string sym\.


DEBUGGER.EXE Command Details

The following is a list of DEBUGGER.EXE's commands.

? (Help)

The ? command with no arguments displays a list of commands and syntax recognized by the debugger.

? (Evaluate Expression)

? [option.]expr

? "string", expr, ...

The ? command evaluates an expression and displays the result.

expr
Expression to evaluate. Can be a combination of numbers, addresses, and operators. Numbers are assumed to be hexadecimal. Addresses can be 32-bit physical addresses or protected-mode addresses (selector:offset). The number sign (#) operator overrides the current address type. Operators can be any listed in Binary and Unary Operators.
option
Format in which to display the expression. Can be one of these:
h. | Hexadecimal
d. | Decimal
t. | Decimal
o. | Octal
q. | Octal
y. | Binary

By default, the command displays all formats: decimal, hexadecimal, octal, binary, ASCII, and Boolean.

string
Formatting string. Can be a combination of text and zero or more of the following formatting descriptors and escape sequences:
%% Displays a percent sign (%).
%A | Displays matching expr as an address.
%b | Displays matching expr in binary format.
%c | Displays matching expr as a character.
%d | Displays matching expr in decimal format.
%G | Evaluates matching expr as an address and displays the group and symbol associated with the address in group:symbol format.
%M | Evaluates matching expr as an address and displays the map file, group and symbol associated with the address in map:group:symbol format.
%o | Displays matching expr in octal format.
%S | Evaluates matching expr as an address and displays the map file, group and symbol associated with the address.
%s | Evaluates matching expr as an address and displays the string at that address.
%u | Displays matching expr in unsigned decimal format.
%X | Displays matching expr in hexadecimal format.
%x | Displays matching expr in hexadecimal format
\a | Inserts a bell (alert) character.
\b | Inserts a backspace character.
\n | Inserts a new line character.
\r | Inserts a carriage return character.
\t | Inserts a horizontal tab character.

One expression must be given for each formatting descriptor in the string. Multiple expressions can be separated with commas (,) or spaces.

Formatting descriptors can have these optional prefixes:

A | [-][width][.precision][a][p][n][L][H][N]
b | [-][0][width][.precision][p][n]
d | [-][+][ ][0][width][.precision][p][n]
G | [-][width][.precision][a][p][n][L][H][N]
M | [-][width][.precision][a][p][n][L][H][N]
o | [-][0][width][.precision][p][n]
s | [-][width][.precision][a]
S | [-][width][.precision][a][p][n][L][H][N]
u | [-][0][width][.precision][p][n]
X | [-][#][0][width][.precision][p][n]
x | [-][#][0][width][.precision][p][n]

Specifying an asterisk (*) for the width or precision parameter causes the field width or precision, respectively, to be picked up from the next parameter. Decimal values can also be specified for the width and precision parameters. The prefix letters have these meanings:

Prefix | Meaning
a | Address argument size
H | Display 16-bit offset
L | Display 32-bit offset
N | Display offset only
p | Get the previous symbol, symbol address, or offset
n | Get the next symbol, symbol address, or offset

The following examples show simple commands and corresponding output:

? ds:esi

013f:000001B3 %00098953 %%00098953

// display the value of the arithmetic expression 3*4:

? 3*4

0Ch 12T 14Q 00001100Y '.' TRUE

bc (Breakpoint Clear)

bc list | *

The bc command removes one or more defined breakpoints.

list
Specifies any combination of integer values in the range 0 through 9. If you specify list, the debugger removes the specified breakpoints.
*
Clears all breakpoints.

This example removes breakpoints 0, 4, and 8:

bc 0 4 8

bd (Breakpoint Disable)

bd list | *

The bd command temporarily disables one or more breakpoints. To restore breakpoints disabled by the bd command, use the be (Breakpoint Enable) command.

list
Specifies any combination of integer values in the range 0 through 9. If you specify list, the debugger disables the specified breakpoints.
*
Disables all breakpoints.

This example disables breakpoints 0, 4, and 8:

bd 0 4 8

be (Breakpoint Enable)

be list | *

The be command restores (enables) one or more breakpoints that have been temporarily disabled by a bd (Breakpoint Disable) command.

list
Specifies any combination of integer values in the range 0 through 9. If you specify list, the debugger enables the specified breakpoints.
*
Enables all breakpoints.

This example enables breakpoints 0, 4, and 8:

be 0 4 8

bl (Breakpoint List)

bl

The bl command lists current information about all breakpoints created by the bp (Breakpoint) command. For each existing breakpoint, the command displays the breakpoint number, the enabled status ('e' for enabled, 'd' for disabled, 'I' for invalid), the breakpoint address, the number of passes remaining (if any), the initial number of passes in parentheses (if any), and debugger commands to be executed when the breakpoint is reached (if any). An invalid "I" breakpoint typically indicates the code has been paged out to disk; it may come back later. You can't remove an invalid breakpoint until it pages back in.

The following example shows a typical list:

0 d %004010b5 [_MyTest] 4 (10) "db ds:edi"

1 eI %0040110f [_MyWndProc@16 + 5a]

bp (Breakpoint)

bp[number]addr [count] ["cmds"]

The bp command creates a software breakpoint at an address. When the application is running, software breakpoints stop execution and force the debugger to execute the default or optional command string. Unlike breakpoints created by the g (Go) command, software breakpoints remain in memory until you remove them with the bc (Breakpoint Clear) command or temporarily disable them with the bd (Breakpoint Disable) command.

number
Specifies which breakpoint is being created. No space is allowed between the bp and number. If number is omitted, the first available breakpoint number is used. The debugger allows up to 10 software breakpoints (0 through 9). If you specify more than 10 breakpoints, the debugger returns the message: "Too Many Breakpoints."
addr
Specifies any valid instruction address — the first byte of an operation code (opcode). The addr parameter is required for all new breakpoints.
count
Specifies the number of times the breakpoint is to be ignored before being executed. It can be any 16-bit value.
cmds
Specifies an optional list of debugger commands to be executed in place of the default command when the breakpoint is reached. You must enclose optional commands in quotation marks and separate optional commands with semicolons (;).

This example creates a breakpoint at address CS:401000:

bp 401000

This example creates breakpoint 8 at address given by the symbol _MyTest. When the breakpoint occurs, the debugger displays bytes at DS:SI:

bp8 _MyTest "db DS:SI"

You cannot set a breakpoint on memory that is not in context (however, you can set a hardware execution breakpoint on the linear address; see the br command).

br (Breakpoint Register)

br [number] flags [addr] [count] ["cmds"]

The Pentium processor contains four "hardware debug registers" that support hardware address breakpoints. Hardware debug registers allow the user to instruct the processor hardware to interrupt processor execution when specified addresses are read, written or executed. This is a very useful tool, for example, to find out what procedures are accessing or changing a specified memory variable.

The br command sets a Pentium debug register breakpoint, in order to "break" on data reads, writes and instruction execution. Up to four debug registers can be set and enabled at one time.

Hardware breakpoints take precedence over faults.

Since the four debug registers are global to the system, they should typically only be touched by a kernel mode debugger. See Knowledge Base Article Q137199, " PRB: Debuggers Cannot Reliably Use Debug Register Breakpoints" for more information.

See also the following MSDN Library CD article: Q105275, "Using the 'BR' Command in DEBUGGER.EXE.EXE".

number
Specifies which breakpoint is being created. No space is allowed between the br command and the number parameter. If number is omitted, the first available breakpoint number is used.
flags
Specifies the length and break conditions for the breakpoint. This parameter can be some combination of the following values:
Value | Description
1 | Set 1-byte length (default value).
2 | Set word length on word boundary.
4 | Set doubleword length on doubleword boundary.
E | Break on instruction execution only (1-byte length only).
W | Break on writes only.
R | Break on reads and writes.

addr
Specifies the address to be watched.
count
Specifies the number of times the breakpoint is to be ignored before being executed. It can be any 16-bit value.
cmds
Specifies an optional list of debugger commands to be executed in place of the default command when the breakpoint is reached. You must enclose the group of optional commands in quotation marks and separate optional commands with semicolons (;).

c (Compare)

c range addr

The c command compares one memory location with another memory location. If the two memory areas are identical, the debugger displays nothing and returns the debugger prompt. Differences, when they exist, are displayed in this form: addr1 byte1 byte2 addr2.

range
Specifies the block of memory that is to be compared with a block of memory starting at addr.
addr
Specifies the starting address of the second block of memory.

This example compares the bytes at addresses in the range 100h to 1FFh with the corresponding bytes at address from 300h to 3FFh:

c100 1FF 300

This example compares the same block of memory as the previous example but specifies the range by using the L (length) option.

c100 L 100 300

d (Display)

d [range]

The d command displays the contents of memory at a given address or in a range of addresses. The d command displays one or more lines, depending on the range given. Each line displays the address of the first item displayed. The command always displays at least one value. The memory display is in the format defined by a previously executed da, db, dd, or dw command. Each subsequent d (typed without parameters) displays the bytes immediately following those last displayed.

range
Specifies the block of memory to display. If you omit range, the d command displays the next byte of memory after the last one displayed. The d command must be separated by at least one space from any range value.

da (Display ASCII)

da [range]

The da command displays as ASCII characters the values of the bytes at a given address or in a given range. The display includes all bytes up to the first zero byte. Nonprinting characters and characters having values greater than 127 are denoted by a period (.).

db (Display Bytes)

db [range]

The db command displays the values of the bytes at a given address or in a given range.

The display is in two portions: a hexadecimal display (each byte is shown in hexadecimal format) and an ASCII display (the bytes are shown as ASCII characters). A nonprinting character is denoted by a period (.) in the ASCII portion of the display. Each display line shows 16 bytes, with a hyphen between the eighth and ninth bytes. Each displayed line begins on a 16-byte boundary.

range
Specifies the block of memory to display. If you omit range, 128 bytes are displayed beginning at the first address after the address displayed by the previous db command.

The following example displays 0Ah bytes of memory, beginning at the specified address:

db CS:100 0A

This example displays lines in a format similar to the following:

04BA:00000100 54 4F 4D 20 53 . . . 45 52 TOM SAWYER

Each line of the display begins with an address, incremented by 10h from the address on the previous line.

dd (Display Doublewords)

dd [range]

The dd command displays the hexadecimal values of the doublewords at the address specified or in the specified range of addresses. The dd command displays one or more lines, depending on the range given. Each line displays the address of the first doubleword in the line, followed by up to four hexadecimal doubleword values. The hexadecimal values are separated by spaces. The dd command displays values up to the end of the range or until the first 32 doublewords have been displayed.

range
Specifies the block of memory to display. If you omit range, 32 doubleword values are displayed beginning at the first address after the address displayed by the previous dd command.

The following example displays the doubleword values from CS:100 to CS:110:

dd CS:100 110

04BA:0100 7473:2041 676E:6972 5405:0104 0A0D:7865

04BA:0110 0000:002E

No more than four values per line are displayed.

dg (Display GDT)

dg[a] [range]

The dg command displays the specified range of entries in the global descriptor table (GDT).

a
Displays all entries in the table, not just the valid ones. By default, only the valid GDT entries are displayed. If range specifies a local descriptor table (LDT) selector, the command displays the appropriate LDT entry.
range
Specifies the range of entries to be displayed. If you omit range, the entire table is displayed.

The command displays the selector, descriptor type, base address, limit, privilege, and other descriptor flags.

di (Display IDT)

di[a] [range]

The di command displays the specified range of entries in the interrupt descriptor table (IDT).

a
Displays all entries in the table, not just the valid ones.
range
Specifies the range of entries to be displayed. If you omit range, the entire table is displayed.

The command displays the interrupt number, the interrupt type, the interrupt address, privilege, and descriptor flags.

dl (Display LDT)

dl[a | p | s | h] [range]

The dl command displays the specified range of entries in the local descriptor table (LDT).

a
Displays all entries in the table, not just the valid ones. By default, only the valid LDT entries are displayed. If range specifies a global descriptor table (GDT) selector, it displays the appropriate GDT entry.
p
Displays private segment selectors.
s
Displays shared segment selectors.
h
Displays huge segment selectors. To display the huge segment selectors, give the shadow selector followed by the maximum number of selectors reserved for that segment plus 1.
range
Specifies the range of entries to be displayed. If you omit range, the entire table is displayed.

The command displays the selector, descriptor type, base address, limit, privilege, and other descriptor flags.

dp (Display Page Directory and Tables)

dp[a|d] [range]

The dp command displays the page directory and page tables. Page tables are always skipped if the corresponding page directory entry is not present. Page directory entries appear with an asterisk next to the page frame.

a
Displays all present page directory and page table entries; by default, page directory and page table entries that are zero are skipped.
d
Displays only page directory entries. If a count is given as part of the optional range, it will be interpreted as a page directory entry count.
range
Specifies the range of linear addresses for page tables.

The command displays the entry address, frame, and entry flags. Page directory entries are marked with an asterisk (*). Entry flags have the following meanings:

Entry Flag | Meaning
A | Accessed
c | clean
CD | Cache Disable
D | Dirty
n | Not-present
P | Present
r | Read-only
s | Supervisor
U | User
u | Unaccessed
W | writeable
WT | Write Through

dt (Display Task State Segment)

dt [addr]

The dt command displays the current task state segment (TSS) or the selected TSS if you specify the optional address. More information about the TSS can be found in Intel's "Pentium Processor User's Manual, Volume 3" (1993). This command can be useful to view the register state at the time a double-fault occurs (dt 18:0).

addr
Specifies the address of the TSS to display. If no addr is given, dt displays the current TSS pointed to by the TR register.

dw (Display Words)

dw [range]

The dw command displays the hexadecimal values of the words at a given address or in a given range of addresses. The command displays one or more lines, depending on the range given. Each line displays the address of the first word in the line, followed by up to eight hexadecimal word values. The hexadecimal values are separated by spaces. The command displays values until the end of the range or until the first 64 words have been displayed.

range
Specifies the range of addresses to display. If you omit range, 64 words are displayed beginning at the first address after the address displayed by the previous dw command.

The following example displays the word values from CS:100 to CS:110:

dw CS:100 110

04BA:0100 2041 7473 6972 676E 0104 5404 7865 0A0D

04BA:0110 002E

dx (Display Loadall Buffer)

dx

Displays the contents of the loadall buffer.

e (Enter)

e addr [list]

The e command enters byte values into memory at a specified address. You can specify the new values on the command line or let the debugger prompt you for values.

addr
Specifies the address of the first byte to be entered.
list
Specifies the byte values used for replacement. These values are inserted automatically. If an error occurs when you are using the list form of the command, no byte values are changed.

If the debugger prompts you, it displays the address and its contents and then waits for you to perform one of the following actions:

  • Rplace a byte value with a value you type. Type the value after the current value. If the byte you type is an invalid hexadecimal value or contains more than two digits, the system does not echo the illegal or extra character.
  • Press the SPACEBAR to advance to the next byte. To change the value, type the new value after the current value. If, when you press the SPACEBAR, you move beyond an 8-byte boundary, the debugger starts a new display line with the address displayed at the beginning.
  • Type a hyphen (-) to return to the preceding byte. If you decide to change a byte before the current position, typing the hyphen returns the current position to the previous byte. When you type the hyphen, a new line is started with its address and byte value displayed.
  • Press ENTER to terminate the e command. You can press ENTER at any byte position.

The following example prompts you to change the value EB at CS:100:

eCS:100

04BA:0100 EB.

To step through the subsequent bytes without changing values, press the SPACEBAR. In the following example, the SPACEBAR is pressed three times:

04BA:0100 EB.41 10. 00. BC.

To return to a value at a previous address, type a hyphen, as shown in the following example:

04BA:0100 EB.41 10. 00. BC.-

04BA:0102 00.-

04BA:0101 10.

This example returns to the address CS:101.

f (Fill)

f range list

The f command fills the addresses in a specified range with the values in the specified list.

range
Specifies the block of memory to be filled. If range contains more bytes than the number of values in list, the debugger uses list repeatedly until all bytes in range are filled. If any of the memory in range is not valid (bad or nonexistent), an error occurs in all succeeding locations.
list
Specifies the list of values to fill the given range. If list contains more values than the number of bytes in range, the debugger ignores the extra values in list.

The following example fills memory locations 04BA:100 through 04BA:1FF with the bytes specified, repeating the five values until it has filled all 100h bytes:

f04BA:100 L 100 42 45 52 54 41

g (Go)

g[s|h|t|z] [=addr [addr[...]] ]

The g command executes the application currently in memory. If you type the g command by itself, the current application runs as if it had been run outside the debugger. If you specify =addr, execution begins at the specified address.

s
Shows the time, in microseconds, from when the system is started with gs until the next entry to the debugger. No attempt is made to calculate and remove debugger overhead from the measurement. Requires a timing card. See MSDN Library CD: Q85897, "DEBUGGER.EXE-Compatible Timing Card Available".
h
Displays the approximate debugger overhead in the s option. Requires a timing card.
t or z
Allows trapped exceptions to resume at the original trap handler address without having to unhook the exception. Use these options instead of the vcp d; t; vsp d commands. Use gt when the debugger catches a fault, in order to continue (resume) execution.
=addr
Specifies the address at which execution is to begin. The equal sign (=) is needed to distinguish the starting address from the breakpoint address.
addr
Specifies one or more breakpoint addresses where execution is to halt. You can specify up to 10 breakpoints, but only at addresses containing the first byte of an operation code (opcode). If you attempt to set more than 10 breakpoints, an error message is displayed.

Specifying an optional breakpoint address causes execution to halt at the first address encountered, regardless of the position of the address in the list of addresses that halts execution or application branching. When execution of the application reaches a breakpoint, the default command string is executed.

The stack (SS:SP) must be valid and have 6 bytes available for this command. The g command uses an iret instruction to cause a jump to the application being tested. The stack is set, and the user flags, CS register, and IP register are pushed on the user stack. (If the user stack is not valid or is too small, the operating system may crash.) An interrupt code (0CCh) is placed at the specified breakpoint addresses.

When the debugger encounters an instruction with the breakpoint code, it restores all breakpoint addresses listed with the g command to their original instructions. If you do not halt execution at one of the breakpoints, the interrupt codes are not replaced with the original instructions.

The following example executes the application currently in memory until address 7550 in the CS selector is executed. The debugger then executes the default command string, removes the int 3 trap from this address, and restores the original instruction. When you resume execution, the original instruction is executed.

gCS:7550

The command g dw esp can be used to go back to the flat 32-bit calling procedure.

The command g wo ss:sp can be used to go back to the 16-bit near calling procedure.

The command g poi ss:sp can be used to go back to the 16-bit far calling procedure.

h (Hex)

h word word

The h command performs hexadecimal arithmetic on the two specified parameters. The debugger adds, subtracts, and multiplies the two parameters; divides the second parameter by the first; and then displays the results on one line. The debugger does 32-bit multiplication and displays the result as doublewords. The debugger displays the result of division as a 16-bit quotient and a 16-bit remainder.

word
Specifies a 16-bit word parameter.

i (Input)

i word

The i command accepts and displays 1 byte (8 bits) from a specified port.

word
Specifies the 16-bit port address.

The following example displays the byte at port address 2F8h:

i2F8

id (Input)

id word

The id command accepts and displays 1 doubleword (32 bits) from a specified port.

word
Specifies the 16-bit port address.

The following example displays the doubleword at port address 2F8h:

i2F8

iw (Input)

iw word

The iw command accepts and displays 1 word (16 bits) from a specified port.

word
Specifies the 16-bit port address.

The following example displays the word at port address 2F8h:

i2F8

j (Conditional)

j expr [cmds-if-true][;cmds-if-false]

The j command executes selected commands based on whether the specified expression is TRUE or FALSE. The j command is useful in breakpoint commands to conditionally break execution when an expression becomes TRUE.

expr
Evaluates to a Boolean TRUE or FALSE.
cmds-if-true
Specifies a list of debugger commands to be executed when expr is TRUE. More than one command can be given, but the commands must be separated by semicolons and the complete list must be enclosed in single or double quotation marks.
cmds-if-false
Specifies a list of debugger commands to be executed when expr is FALSE. The preceding semicolon is required. More than one command can be given, but the commands must be separated by semicolons and the complete list must be enclosed in single or double quotation marks.

The following example causes execution to continue if EAX equals zero when the breakpoint is reached:

bp 167:1454 "J EAX == 0 G"

The following example displays the registers and continues execution when the byte pointed to by DS:SI +3 is equal to 40h; otherwise, it displays the descriptor table:

bp 167:1462 "J BY (DS:SI+3) == 40 'R;G';DG DS"

k (Stack Trace)

k[b|s|v] [addr] [addr]

This command displays the current (EBP-based) stack frame. Each line shows the name of a procedure, its arguments, and the address of the statement that called it. The command displays four 2-byte arguments by default. The ka command changes the number of arguments displayed by this command.

b
Indicates the stack frame is 32 bits wide.
s
Indicates the stack frame is 16 bits wide.
v
Displays the verbose version of stack information — that is, information about stack location and frame pointer values for each frame.
addr
Specifies an optional stack-frame address (SS:EBP) or an optional code address (CS:EIP).

Using the k command at the beginning of a function (before the function prolog has been executed) gives incorrect results. The command uses the BP register to compute the current backtrace, and this register is not correctly set for a function until its prolog has been executed.

ka (Stack Trace Arguments)

ka count

The ka command sets the number of arguments displayed for all subsequent stack trace commands. The initial default value is 4.

count
Specifies the number of arguments to be displayed. The count parameter must be in the range 0 through 1Fh.

kt (Stack Trace for Task)

k[b|s|v]t [addr]

This command displays the stack frame of the current task or the task specified by the addr parameter. Each line shows the name of a procedure, its arguments, and the address of the statement that called it. The command displays four 2-byte arguments by default. The ka command changes the number of arguments displayed by this command.

b
Indicates the stack frame is 32 bits wide.
s
Indicates the stack frame is 16 bits wide.
v
Displays the verbose version of stack information — that is, information about stack location and frame pointer values for each frame.
addr
Specifies the segment address of the process descriptor block (PDB) for the task to be traced. To obtain the addr value, use the .dq (Dump Task Queue) command. If addr is not supplied, the kt command displays the stack frame of the current task.

la (List Absolute Symbols)

la

The la command lists the absolute symbols in the active map.

lg (List Groups)

lg

The lg command lists the address and the name of each group in the active map.

lm (List Maps)

lm

The lm command lists the symbol files currently loaded and indicates which one is active. The last symbol file loaded is made active by default. Use the w (Change Map) command to change the active file.

ln (List Nearest Symbol)

ln [addr]

The ln command lists the symbol nearest the specified address. The command lists the nearest symbol before and after the specified addr parameter. This command also shows line-number information if it is available in the symbol file.

addr
Specifies any valid instruction address. The default value is the current disassembly address.

The ln command without the addr parameter displays the nearest symbols before and after the current disassembly address.

Example: ln dw(esp) Lists the nearest symbol with respect to the caller (pushed address on stack)

ls (List Symbols)

ls group-name | name-chars | *

The ls command lists the symbols in the specified group or lists names that match the search specification in all groups. The search specification uses DOS-style semantics. The only valid wildcard is a single asterisk (*) as the last character on the command line; all other characters are ignored.

group-name
Names the group that contains the symbols you want to list, for example ESDI_506.
name-chars
Specifies the beginning characters of the symbols you want to list.

lse (List Symbols by Regular Expression)

lse regular-expression

The lse command lists the symbols specified by the given regular expression. The search specification uses UNIX-style semantics.

regular-expression
Can be a regular expression as described in Command Syntax.

m (Move)

m range addr

The m command moves a block of memory from one memory location to another. If part of the destination block overlaps some of the source block, the move is always performed without loss of data. Addresses that could be overwritten are moved first.

range
Specifies the block of memory to be moved.
addr
Specifies the starting address at which the memory is to be relocated.

For moves from higher to lower addresses, the sequence of events is first to move the data at the block's lowest address and then to work toward the highest. For moves from lower to higher addresses, the sequence is first to move the data at the block's highest address and then to work toward the lowest.

The following example first moves the data at address CS:110 to CS:510 and then moves the data at CS:10F to CS:50F, and so on, until the data at CS:100 is moved to CS:500:

mCS:100 110 CS:500

o (Output)

o word byte

The o command writes a byte to a 16-bit port address.

word
Specifies the 16-bit port address to be written to.
byte
Specifies the 8-bit value to be written to the port.

The following example writes the byte value 4Fh to output port 2F8h:

o 2F8 4F

od (Output)

o word dword

The o command writes a dword to a 16-bit port address.

word
Specifies the 16-bit port address to be written to.
dword
Specifies the 32-bit value to be written to the port.

The following example writes the byte value 8000004Fh to output port 2F8h:

o 2F8 8000004F

ow(Output)

o word word

The o command writes a word to a 16-bit port address.

word
Specifies the 16-bit port address to be written to.
word
Specifies the 16-bit value to be written to the port.

The following example writes the word value 804Fh to output port 2F8h:

o 2F8 804F

p (Program Trace)

p[n|t|z] [=addr][count]

The p command executes the instruction at a specified address and displays the current values of all the registers and flags (whatever the zd command has been set to). It then executes the default command string, if any. The p command is identical to the t (Trace Instructions) command, except that it automatically executes and returns from any calls or software interrupts it encounters. The t command always stops after executing into the call or interrupt, leaving execution control inside the called routine.

n
Suppresses the register display so just the assembly line is displayed. The suppression results only if the default command, zd, is set to a normal setting, r.
t or z
Allows trapped exceptions to resume at the original trap handler address without having to unhook the exception.
addr
Specifies the starting address at which to begin execution. If you omit the optional addr parameter, execution begins at the instruction pointed to by the CS and IP registers. Use the equal sign (=) only if you specify addr.
count
Specifies the number of instructions to execute before stopping and executing the default command string. The command executes the default command string for each instruction before executing the next.

The following example executes the instruction pointed to by the current CS and IP register values before it executes the default command string:

p

The following example executes the instruction at address CS:120 before it executes the default command string:

p=120

Program tracing through popf or popfd usually does not work.

r (Register)

r[t][reg[=value]]

The r command displays the contents of one or more central processing unit (CPU) registers and allows the contents to be changed to new values. If you specify the reg parameter with the r command, the command displays the value of that register in hexadecimal format and prompts for a new value. If you specify a reg and a value, the command sets the register to the given value.

t
Displays registers in terse format.
reg
Specifies the register to be displayed. If you specify f or msw for reg, the debugger displays the flags in a row at the beginning of a new line and prompts for one or more flag values. If you omit reg, the debugger displays the contents of all registers and flags along with the next executable instruction.
value
Specifies the new value for the register. Can be a number or a combination of these flag values:
Flag | Description
OV | Overflow set
NV | Overflow clear
DN | Direction decrement
UP | Direction increment
EI | Interrupt enabled
DI | Interrupt disabled
NG | Sign negative
PL | Sign positive
ZR | Zero set
NZ | Zero clear
AC | Auxiliary carry set
NA | Auxiliary carry clear
PE | Parity even
PO | Parity odd
CY | Carry set
NC | Carry clear
NT | Nested task switch (on and off)
TS | Sets the task switch bit. (MSW only)
EM | Sets the emulation processor extension bit. (MSW only)
MP | Sets the monitor processor extension bit. (MSW only)
PM | Sets the protected-mode bit. (MSW only)

Flag values can be in any order. You do not have to leave spaces between these values.

If you type more than one value for a flag or enter an invalid flag name, the flags up to the error in the list are changed and those flags at and after the error are not changed. In addition, the debugger display the message: "Bad Flag."

Setting the protected-mode bit from within the debugger does not set the target system to run in protected mode. The debugger simulates the setting. To configure the target system to run in protected mode, you would have to set the PM bit in the MSW register and reset the target system to restart in protected mode.

See also the .r command.

s (Search)

s range list | "string"

The s command searches an address range for a specified list of bytes or an ASCII character string. You can include one or more bytes in list, but multiple bytes must be separated by a space or comma. When you search for more than one byte, the command returns the address of only the first byte in the string. When list contains only one byte, the debugger displays the addresses of all occurrences of the byte in range.

range
Specifies the block of memory to be searched.
list
Specifies one or more byte values to search for.
string
Specifies an ASCII character string to be searched for. The string must be enclosed in quotation marks.

The following example searches for byte 41h in the address range CS:100 to CS:110:

sCS:100 110 41

04BA:0104

04BA:010D

t (Trace)

t[a|c|n|s|x|z][=start_addr][count][addr]

The t command executes one or more instructions along with the default command string and then displays the decoded instruction. If you include the start_addr parameter, tracing starts at the specified address. Otherwise, the command steps through the next machine instruction and then executes the default command string. The t command uses the hardware trace mode of the Intel microprocessor. Consequently, you can also trace instructions stored in read-only memory (ROM).

a
Indicates that an ending address is specified for the trace. Instructions are traced until the address in addr is reached.
c
Suppresses all output and counts instructions traced. An ending address is required for this command. Instructions are traced until the address in addr is reached.
n
Suppresses the register display so just the assembly line is displayed. This works only if the default command, zd, is set to r (the normal setting).
s
Suppresses output; the instruction and count are displayed for each call and the return from that call.
x
Forces the debugger to trace regions of code known to be untraceable (_PGSwitchContext, for example).
z
Allows original trap handler address to be traced into without having to unhook the exception. Use this option instead of vcp d; t; vsp d.
start_addr
Specifies the instruction address at which to start tracing. The equal sign (=) is required.
count
Specifies the number of instructions to execute and trace.
addr
Specifies the instruction address at which to stop tracing.

The following command causes the debugger to execute 16 (10h) instructions beginning at 011A in the current selector:

t=011A 10

The debugger executes and displays the results of the default command string for each instruction. The display is scrolled until the last instruction is executed. Press the CTRL+S key combination to stop the scrolling and CTRL+Q to resume.

This command does not trace into INTs (but will trace out), and tracing through popf or popfd usually does not work.

u (Disassemble)

u [range]

The u command disassembles bytes and displays the source statements, with addresses and byte values that correspond to them. The display of disassembled code looks similar to a code listing for an assembled file. If you type the u command by itself, 20h bytes are disassembled at the first address after the one displayed by the previous u command.

range
Specifies the block of memory in which instructions are to be disassembled. If no range is given, the command disassembles the next 20h bytes.

v (Version Number)

v

The v command displays the current debugger version number and date.

vc (Vector Clear)

vc[n | p | r | v] number[,number [,...]]

The vc command clears the specified interrupt vector and reinstalls the previous interrupt vector.

n
Removes the beep from traps that beep when encountered; does not clear the traps.
p
Clears protected-mode vectors only.
r
Clears real-mode vectors only.
v
Clears virtual 8086 (V86) mode vectors only.
number
Specifies the interrupt vector to clear.

For protected-mode games, type vcp 1 3 before running the app, and vtp 1 3 after exiting the app, to avoid "unexpected trace interrupt" errors. For DOS apps, use vcv 1 3 and vsv 1 3. To recover from the error message, first remove the vector, then type gt.

vl (Vector List)

vl[n | p | r | v]

Lists the interrupt vectors that the debugger intercepts. Vectors that have been set with the vt command (as opposed to vs) are listed with an asterisk (*) following the vector number.

n
Lists the traps that beep when encountered.
p
Lists the protected-mode vectors only.
r
Lists the real-mode vectors only.
v
Lists the virtual 8086 (V86) mode vectors only.

vo (Vector List New)

vo[n | p | r | v]

The vo command lists interrupt vectors in the display format based on the newvec option. For details, see the y command.

n
Lists the traps that beep when encountered.
p
Lists the protected-mode vectors only.
r
Lists the real-mode vectors only.
v
Lists the virtual 8086 (V86) mode vectors only.

vs (Vector Trap Non-Supervisor)

vs[n | p | r | v] number[,number[,...]]

The vs command adds a new interrupt vector to the list of intercepted vectors. Vectors set by this command do not intercept interrupts that occur at ring 0.

n
Beep when trap encountered.
p
Set trap for protected-mode vectors only.
r
Set trap for real-mode vectors only.
v
Set trap for virtual 8086 (V86) mode vectors only.
number
Specifies the interrupt vector to intercept.

vt (Vector Trap)

vt[n | p | r | v] number[,number[,...]]

The vt command adds a new interrupt vector to the list of intercepted vectors.

n
Beep when trap encountered.
p
Set trap for protected-mode vectors only.
r
Set trap for real-mode vectors only.
v
Set trap for virtual 8086 (V86) mode vectors only.
number
Specifies the interrupt vector to intercept.

w (Change Map)

w [map-name]

The w command changes the active map file.

map-name
Specifies the name of the map file you want to make active. Use the lm (List Map) command to display a list of available map files.

If map-name is not specified, the loaded maps are displayed and the user is prompted to select a map by pressing its corresponding number.

wa (Activate Map)

wa map-name

The wa command adds the specified map to the list of active maps.

map-name
Specifies the map to add to the list of active maps.

wr (Deactivate Map)

wr map-name

The wr command removes the specified map from the list of active maps.

map-name
Specifies the map to remove from the list of active maps.

x (Dump Debug Report)

x

Dumps a listing of the current execution environment.

y (Debugger Options)

y[? | option]

The y command changes the debugger configuration. The following list describes the available configuration options. All settings are toggles.

?
Displays a list of supported options.
option
Following are the available configuration options:
/a | Controls automatic symbol loading. If this option is set, Windows will not load symbols automatically.
/n Sets the following options, listed in more detail further below:
codebytes dislwr int3line newprompt newreg newvec symaddrs
/v | Controls segment load notification messages. If this option is set, all segment load notifications will be displayed.
386env | Controls the size of addresses, registers, and so on when displayed. When this option is on, addresses, registers, and so on are shown in 32-bit format; otherwise, they are shown in 16-bit format.
codebytes | Causes code bytes to be displayed along with disassembled instructions.
crdelay = | Implements a delay between lines emitted to the debug terminal. Specify the number of ASCII nulls between lines (0-FFFFH).
disaddr | Causes addresses to be displayed with disassembled instructions.
disline | Causes filenames and line numbers to be displayed with disassembled instructions.
dislwr | Causes register and instruction names to be displayed in lowercase letters.
int3line | Causes the filename and line number to be displayed with int 3 instructions.
newprompt | Causes a double prompt when paging is enabled and a nesting level if the debugger is reentered.
newreg | Changes the format of the register display to the newer format accommodating 32 bit registers.
newvec | Controls the display format for the intercepted interrupt vectors.
regterse | Controls the number of registers displayed by the r (Register) command. When regterse is on, only the first three lines are displayed (instead of the normal six lines plus disassembly line).
scrncols | Sets the number of screen columns in the debug display. The default is 79 columns.
scrnlines | Sets the number of screen lines in the debug display. The default is 24 lines.
skipint3s | Causes the debugger to ignore inline int 3 instructions.
symaddrs | Causes symbol values to be displayed with the symbols.
teftibase | Sets the base port address for the timing card. See MSDN Library CD: Q85897, "DEBUGGER.EXE-Compatible Timing Card Available"

z (Zap)

z

Replaces the instruction bytes of the current int 3 instruction or the previous int 1 instruction with nop instructions. This allows the user to avoid int 1 or int 3 instructions that were assembled into the executable file by breaking into the debugger more than once.

You can also z)ap debug_out's; they will be automatically converted to trace_out, so they stop trapping..

zd (Execute Default)

zd

The zd command executes the default command string. The default command string is initially set to the r (Register) command by the debugger. The default command string is executed every time a breakpoint is encountered during execution of the application or whenever a p (Program Trace) or t (Trace) command is executed.

Use the zl command to display the default command string and the zs command to change the default command string.

zl (Display Default)

zl

The zl command displays the default command string.

zs (Set Default)

zs "string"

The zs command makes it possible for you to change the default command string.

string
Specifies the new default command string. The string must be enclosed in single or double quotation marks. You must separate the debugger commands within the string with semicolons.

The following example changes the current default command string to an r (Display Register) command followed by a c (Compare Memory) command:

zs "r;c100 L 100 300"

The following example begins execution whenever an int 3 instruction is executed in your test application. This example executes a g (Go) command every time an int 3 instruction is executed.

zs "j (by cs:ip) == cc 'g'"

You can use zs as follows to set up a watchpoint:

zs "j (wo 40:1234) == 0eeed;t"

This command traces until the word at 40:1234 is not equal to 0EEED. This does not work if you are tracing through the mode switching code in MS-DOS or other sections of code that cannot be traced.


.<dev_name> (Dot Device)

.dev_name

Directs the VMM to send a Debug_Query message to the given virtual device. If the virtual device supports a debugging interface, it displays information about its operating state.

dev_name
Can be the name of any virtual device.

Because virtual devices are not required to support the Debug_Query message, many do not produce debugging output. If a virtual device does generate output, it is typically device specific and not normally useful in a typical debugging situation.

Examine the sample virtual devices to determine how to use the Trace_Out macro, and the In_Debug_Chr service to generate useful debugging information.


.? (Help)

.?

The .? command displays a list of external commands. These commands are part of debugger, but they are specific to the environment in which the debugger is running.


.b (Baud Rate)

.b number [addr]

The .b command sets the baud rate for the debugging port (COM2).

number
Specifies the baud rate. It can be one of the following values: 150, 300, 600, 1200, 2400, 4800, 9600, or 19200. Because the default radix for the debugger is 16, you must type t after the number to indicate a decimal value.
addr
Specifies 1 for COM1 or 2 for COM2; anything else is taken as a base port address. If there is no COM2, the debugger checks for COM1 and then for any other COM port address in the read-only memory (ROM) data area to use as the console.

The following example sets the baud rate to 1200:

#.b 1200t


..bios (BIOS Debug Binary Utility)

The ..bios command displays the following menu:

BIOS (space for help)?

a Show all BIOS devnodes

e Dump recent BIOS events

l Show List (Show every PCI devnode)

s Show selected devnode

y Select devnode

z Select devnode by index


.csp (VMM Debug Binary Utility)

The .csp command toggles the "catch stray pointer flag".


.df (Display Free Memory)

.df

The .df command displays a list of the free global memory objects in the global heap. The list has the following form:

address: size owner [chain]

address
Specifies physical and heap addresses.
size
Specifies the size of the object, in bytes.
owner
Always specifies that the module is free.
chain
Specifies the previous and next addresses in the list of least recently used (LRU) objects. The debugger displays the addresses only if the segment is movable and discardable.


.dg (Display Global Memory)

.dg [object]

The .dg command displays a list of the global memory objects in the global heap. The command displays information in much the same way as the HEAPWALK application.

object
Specifies the first object to be listed. The object parameter can be a handle, a selector, or a heap address.

The list has the following form:

address: size segment-type owner [handle flags chain]

address
Specifies physical and heap addresses.
size
Specifies the size of the object, in bytes.
segment-type
Specifies the type of object. The type can be any one of the following:
Object | Description
CODE | Segment contains application code.
DATA | Segment contains application data and possible stack and local heap data.
FREE | Segment belongs to pool of free memory objects ready for allocation by an application.
PRIV | Segment contains private data.
SENTINAL | Segment marks the beginning or end of the global heap.

owner
Specifies the module name of the application or library that allocated the memory object. The acronym PDB is used for memory objects that represent process descriptor blocks. These blocks contain execution information about applications.
handle
Specifies the handle of the global memory object. If the debugger displays no handle, the segment is fixed.
flags
Specifies either of the following:
D | The segment is movable and discardable.
L | The segment is locked. If the segment is locked, the lock count appears to the right of the flag.

If the debugger displays a handle but no flag, the segment is movable but not discardable.

chain
Specifies the previous and next addresses in the list of least recently used (LRU) objects. Addresses are displayed only if the segment is movable and discardable (specified by the D flag).


.dh (Display Local Heap)

.dh

The .dh command displays a list of the local memory objects in the local heap (if any) belonging to the current data segment. The command uses the current value of the DS register to locate the data segment and check for a local heap.

The list of memory objects has the following form:

offset: size { BUSY | FREE }

offset
Specifies the address offset from the beginning of the data segment to the local memory object.
size
Specifies the size of the object, in bytes.

If BUSY is displayed, the object has been allocated and is currently in use. If FREE is displayed, the object is in the pool of free objects ready to be allocated by the application. A special memory object, SENTINAL, may also be displayed.


.dm (Display Modules)

.dm

The .dm command displays a list of the global Win16 modules in the global heap.

The list has the following form:

module-handle module-type module-name filename

module-handle
Specifies the handle of the module.
module-type
Specifies either a dynamic-link library (DLL) or the name of the application you are debugging.
module-name
Specifies the name of the module.
filename
Specifies the name of the file from which you loaded the application.


.dosmgr (Display Real Mode DOS structures)

Dumps various data structures related to real-mode MS-DOS®.

[1] Display SFTs

[2] Display DPBs

[3] Display MCBs (dump the real-mode memory map)

[4] Display CDSs

[5] Display PDBs (dump the real-mode process map)

[6] Display DEVs

[7] Display BDSs

[8] Display INT 21h status


.dq (Display Task Queues)

.dq

The .dq command displays a list containing information about the various task queues supported by the system. The list has the following form:

task-descriptor-block stack-segment:stack-pointer number-of-events

priority internal-messaging-information module

task-descriptor-block
Specifies the selector or segment address.

The task descriptor block is identical to the process descriptor block (PDB).

stack-segment:stack-pointer
Specifies the stack segment and pointer.
number-of-events
Specifies the number of events waiting for the segment.
priority
Specifies the priority of the segment.
internal-messaging-information
Specifies information about internal messages.
module
Specifies the module name.


.ds (Dump Stack)

.ds

Dumps the protected-mode stack and displays near code-segment labels (if available) next to each doubleword value from the stack. One important distinction that should be made is the difference between the k and the .ds commands. The k command will walk the Windows stack as long as the debugger is stopped in Windows-based application or dynamic-link library (DLL) code. However, if the debugger is tracing through ring 0 code, the k command will not produce any useful output. For this reason, the .ds command has been provided to display the ring 0 stack.


.du (Display Least Recently Used)

.du

The .du command displays a list of the least recently used (LRU) global memory objects in the global heap. The list has the following form:

address: size segment-type owner [handle flags chain]

address
Specifies physical and heap addresses.
size
Specifies the size of the object, in bytes.
segment-type
Specifies the type of object. The type can be any one of the following:
Object | Description
CODE | Segment contains application code.
DATA | Segment contains application data and possible stack and local heap data.
FREE | Segment belongs to pool of free memory objects ready for allocation by an application.
PRIV | Segment contains private data.
SENTINAL | Segment marks the beginning or end of the global heap.

owner
Specifies the module name of the application or library that allocated the memory object. The acronym PDB is used for memory objects that represent process descriptor blocks. These blocks contain execution information about applications.
handle
Specifies the handle of the global memory object.
flags
Specifies D, which means the segment is movable and discardable.
chain
Specifies the previous and next addresses in the LRU list.


.i? (IOS Debug Binary Utility)

Help menu for IOS commands:

.IDCB <addr> Dumps I/O Subsystem Device Control Block structure.

.IIOP <addr> Dumps I/O Subsystem I/O Packet structure.

.IMED Dumps I/O Subsystem Memory Element Descriptor structures.

.IDV (DISKVSD debug binary also required) Display disk calldown/callup statistics

.ISAPNP Display current read data port, followed by information about each ISA bus card (if any).


.lq (VMM Debug Binary Utility)

Displays the queue of messages queued with the macro Queue_Out. Normally the queued messages are viewed with the ".S" command so it is possible to see the messages interspersed with the fault information to get a better idea of the execution sequence, but occasionally it is nice to be able to look at the messages quickly to determine if the desired one ever occurred. This list also displays the fault entry index of when each were logged, so it is possible to search for a desired message and then use the ".S" command and specify the identified index as a list starting point.


.m (Memory)

.m[struct][link] [expression [L count]]

Displays information about memory and memory objects.

struct
Command option. Can be one of these letters.
Option | Description
a | Display arena record.
c | Display context descriptor
d | Display page directory entry
e | Toggle stopping in the debugger for memory manager errors (parameter validation errors as well as fatal errors).
f | With no arguments, dump page fault log. With arguments, set to log faults in a specific range (syntax: .MF <address> L<lengh in bytes>).
fb | Toggle stopping for each logged page fault.
ff | Toggle logging page faults to debug terminal.
g | Display pager descriptor
h [handle] | Displays heap information for the given handle or global information if no handle is given. Displays heap information. This was originally intended for debugging the VMM's memory manager, but may be useful for looking at heap allocations that a device driver makes. This command accepts an optional parameter that specifies the heap allocation handle whose information should be dumped.
hs [handle] | Dump statistics about a given heap.
hw | Toggle paranoid VMM32 heap checking.
hx [handle] | Check for corruption on given heap defaults to VMM32 fixed heap.
i Display Instance Data information. The first section lists which pages of V86 memory contain instance data. The second section lists the regions of instance data. A typical entry looks like:

VMAddr 00000413, Lead Byt 01, Algn Byt 29

This means that the instance region starts at 413h in V86 memory, that 1 byte exists before a DWORD boundary and 29h bytes exist after a DWORD boundary, for a total region length of 2Ah bytes. This command is useful for determining if a device has claimed instance data properly, or to just see what data is currently instanced.
l | Display (physical) page table info for a given linear address
m [address [l page-count]] | Attempts to force memory present. The address defaults to last page faulted upon (contents of cr2 register).
n | Force all unlocked memory not present
p | Display ALL Linear addresses that map the given PhysAddr. This command requires a physical address, so page A0h would be address A0000.
r | Display arena header
s | Dumps global memory manager statistics such as how system memory is being used, what sort of pager is being used etc.
t | Displays page table entry
u | Toggles computing checksums for page-outs and page-ins
v | Displays memory handle information for the memory handles that are allocated to the current VM. Originally used in debugging the VMM's memory manager. Also dumps out the list of routines that have used the global _Assign_Device_v86_Pages service.
w | Dumps allocators of all committed pages.
x | Displays all memory structures for an address.
y | Displays valid physical memory ranges.

If no letter is given, the command displays all the structures associated with a given linear address.

link
Direction to walk structures if dumping more than one. Can be b to walk backward or f to walk forward. If link is not given, the default is to walk adjacent entries.
expression
An expression identifying the structure to display. Can be a linear address, handle, array index, or other value as specified by the struct parameter.
count
Number of structures to display if the specified structures are linked.

The default address for the .m and .mx commands is the contents of the cr2 register (the last page fault) and for the other commands it is the first structure in the list. For example, .m displays information about the page that most recently faulted.

A word of caution about the .mm, .mhx, and .mhs commands. If you invoke these commands at the wrong time, you can crash your system. The only time it can be guaranteed safe is if you are currently executing ring 3 code. At other times we may be in the middle of another file system or memory manager operation.


.memcheck

Display list of internal memory checking routines


.ntkern (NTKERN Debug Binary Utility)

OSR 2.1 & Windows 98 NT WDM (USB etc.) support. Typing this command supplies you with a menu which includes the ability to dump its debug log ("D"). The debug log displays in LIFO order.


.p (DEBUGCMD Debug Binary Utility)

Debugger tools when DEBUGCMD.VXD is installed (rename DEBUGCMD.TMP to DEBUGCMD.VXD, place it into \WINDOWS\SYSTEM, and load it by putting DEVICE=DEBUGCMD.VXD in the [386Enh] section of the SYSTEM.INI file):

.p? Main help menu

.p<cmd>? For more extensive help on a cmd

.p lists threads in system

.p <*/thread id> lists status of one thread

.pf lists threads and their flags

.ps <Thread handle/id> Dumps ring 0 stack with labels

.psx <Thread handle/id> Dumps 20 lines of ring0 stack and returns

.pdev <Address> Finds nearest VXD name

.plog <flags> Set scheduler query logging flags

.pmtx <Mutex Address> display mutex state

.psem <Semaphore Address> display semaphore state

.pthcb <Thread handle/id> display thread control block

.pprd Disables the logging of priority changes

.ppre Enables the logging of priority changes

.pprf <filter> Logs only boosts changing these bits

.pprl <Thread handle/id> Lists priority changes recorded

.pmax Show thread and VM maximum DOS386 stack usage


.pci (PCI Debug Binary Utility)

Note that to use .PCI you must remove debugcmd.vxd from the system because its .P command prevents .PCI from being recognized.

"Welcome to PCI's debugger"

A show All; Show every PCI devnode

B show Busses; Show PCI bus structure

C Config space; Toggle full/partial config space

D Enter dwdata; Enter data in config space in dwords

E Enter data; Enter data in config space

F FindIRQRoute; Help find the IRQ routing

G Global info; Show global PCI info

I IDE Test; See if secondary IDE is enabled

L show List; Show every PCI devnodes (short)

Q Quit; Quit the debugger

R show Rom; Show ROM of selected devnode

S Show selected; Show selected devnode

T Trace CS; Trace config space access

Y select devnode; Select DevNode

Z select devnode; Select DevNode by index


.r (Display Registers of Current Ring 3 Thread)

.r [#]

Displays the registers of the current ring 3 thread. For example, if you used <ctrl c> to break into the system, .r will show you the debugger's <ctrl c> handler (corresponding to the current thread). To show the state of another thread, supply the thread's ring0 thread ID as the parameter.


.reboot (System Restart)

.reboot

The .reboot command causes the target system to restart.


.s (VMM Debug Binary Utility)

.s [#] displays short logged exceptions starting at #, if specified.

Displays a condensed version of logged exceptions (logging is enabled with the ".T" command described above). The ".S" command displays the log in brief format, most recent log entry first.

The first column is the log entry number.

The second column describes the reason for the log entry. If the log entry describes the beginning of a fault, it contains the fault number. If the log entry describes leaving ring 0 (for example, because fault

handling is complete), it contains the word "OUT".

The third column is the handle of the thread at the time of the fault.

The fourth column is the number of times the critical section was taken at the time the log entry was made.

The fifth column is "EI" if interrupts were enabled at the time the log entry was made; "DI" if interrupts were disabled.

The sixth column describes the processor mode at the time of the fault. It is "VMM" to indicate that the fault was encountered by a ring 0 component. It is "V86" to indicate that the fault was encountered

while in V86-mode. It is "PM" to indicate that the fault was encountered in ring 3 protected mode.

The seventh column is the address that caused the fault.

The remainder of the line contains auxiliary information related to the fault. If the fault was raised by a software interrupt or I/O port access, the faulting instruction is disassembled; in the case of a software interrupt, the value of the EAX register is also displayed following the disassembly. If the fault was caused by a callback or breakpoint, the address of the ring 0 handler for the callback or breakpoint is displayed.

Here follow some sample log entries with interpretation.

0000165A: OUT C1D9F08C 00 EI VMM C0011FDC

This is log entry number 0000165A. The system is leaving ring 0 ("OUT"). The current thread is C1D9F08C, the critical section is not taken ("00"), interrupts are enabled ("EI"), and the system is returning to interrupt code which happens also to be at ring 0 ("VMM"), at address C0011FDC.

00023131: 002A C359F08C 01 EI V86 FF03:5311 INT 2A 00008102

This is log entry number 000023131. The system is entering ring 0 due to software interrupt 002A. The current thread is C359F08C, the critical section is taken once ("01"), interrupts are enabled ("EI"), and the software interrupt was raised by V86-mode ("V86") at address FF03:5311. The faulting instruction was an "INT 2A", and the value of the EAX register was 00008102.

0002312B: 0006 C1D9F08C 00 DI V86 FEB7:1448 Hdl: C0087244:IFSMGR(01) + 86d

This is log entry number 00002312B. The system is entering ring 0 due to an invalid opcode (fault 0006). The current thread is C1D9F08C, the critical section is not taken ("00"), interrupts are disabled ("DI"),

and the software interrupt was raised by V86-mode ("V86") at address FEB7:1448. The faulting instruction was a callback or breakpoint; the handler for the callback of breakpoint is IFSMGR(01) + 86d.

00023118: 0055 C1D9F08C 00 EI VMM C0011FDC

This is log entry number 000023118. The system is entering ring 0 due to an IRQ 5 (50+5). The current thread is C1D9F08C, the critical section is not taken ("00"), interrupts are disabled ("EI"), and the hardware interrupt was raised while the system was in ring 0 ("VMM") at address C0011FDC.

The ".SL" command described below displays a complete dump to each logged entry, but takes much more screen space, so this command is used more often to get a quick look at the sequence of faults, and the ".SL" command is used when a more in-depth view is necessary, or when it is necessary to know what other registers were at the time of the fault.

".S" accepts an optional parameter that is the fault entry index. If this parameter exists, then the log is searched for the specified entry. If the entry is found, then the list starts from that entry and proceeded backwards to the oldest entry; if the entry is not found then a warning message is displayed and the list starts from the most resent.

The macro Queue_Out queues messages to a separate circular queue. Each message is linked to the current fault entry index, so the ".S" can show the queued messages interspersed with the fault information. This allows fault handlers to show information about how they handled the fault so that the list displayed by the ".S" command is a fairly complete execution history, which is particularly useful when debugging devices that are trying to virtualize I/O so that they simulate actual hardware, such as the PIC, DMA and video.

".S" always disables logging before it displays anything, so no more logging will be performed until ".T" is invoked again.


.sl (VMM Debug Binary Utility)

.sl [#] displays long logged exceptions just #, if specified. ".SL" like ".S" (above) displays information about logged exceptions, enabled with the ".T" command. ".SL" displays all of the registers at the time the entry was logged and also shows the system time (the time VMM started) of the entry. ".S" shows a condensed view and is used more often because more faults can be viewed at the same time and because most of the registers are of little importance to the fault.

".SL" also disables logging before it displays anything, so no more logging will be performed until ".T" is invoked again


.t (VMM Debug Binary Utility)

Toggles the trace switch. At start time the debugging VMM does not performing any fault logging, but when this command is invoked, then the message "start tracing" is displayed, at which point debugging code in the VMM starts logging each fault/exception that occurs. The logging includes the current registers, whether executing V86 client, PM client or VMM/VxD code, system time, fault #, etc. Both the fault entry into the VMM and the exit from the VMM are logged. The logged information can be viewed with the ".S" commands.

Invoking ".T" a second time displays the message "stop tracing", at which point the logging will stop, but any previously logged information can still be viewed. So, ".T" toggles the logging state between logging and not logging. Each time that logging is started, the current log is lost, so it is only possible to view the most recently logged session. The logging is done into a circular queue, so it will start overwriting at some point, but the queue is defined large enough to give a good view into the types of faults that are occurring.

This command is very useful for determining problems that are related to fault processing and sequencing, such as virtually handling I/O instructions being executed by the client. It is also useful for when the Windows/386 wants to blow-up; it may be possible to determine what happened just prior to the crash to find out what was at fault. It is often helpful to turn on procedure call tracing also. Refer to the ".VMM" command for details on call tracing. The debugging macro Queue_Out, logs messages into a separate circular queue. Each message is associated to a fault log item.


. v (Virtual Machine Commands)

.v[option]

Displays information about the current virtual machine (VM).

option
Command option. Can be one of these option letters:
Option | Description
c | Displays the standard fields from the current VM's control block (does not include device allocated fields.) This information is useful to determine the current state of the VM as the Windows/386 VMM sees it. It accepts the same optional parameter as ".VM".
h | Displays the current VM's handle. Useful for determining which VM is currently executing. It is also possible to look at device allocated fields of the VM's control block, if the offset to the first field is known, by adding the offset to the handle when dumping memory.
m | Displays the status of the current VM. Status information includes re-entry count, VM handle, critical section state, client registers, and top entries from the client's stack. This command is useful to see where the VM was/is trying to execute. It is then possible to set a break point at the client's CS:IP if it is necessary to step through a few instructions to determine what the client is trying to do. This command accepts an optional parameter that can be the VM handle or VM id of the VM whose status should be displayed.
r | If Ring 0 code was executing at the time that the debugger took control, then is command displays the client registers of the current VM. If the client was executing, then the debugger is showing the current registers, and this command will just display a warning message. This command shows just the register display portion of the ".VM" command. It accepts the same optional parameter as ".VM".
s | Displays the current VM's virtual mode stack if the debugger is running in protected mode.
l | Displays a list of all valid VM handles. The list shows the assigned scheduler priority and the execution status of each VM.


.vdd (VDD Debug Binary Utility)

VDD Virtual Display Device State Dump. Also offers additional options:

Select | Option
1 | display VM register states
2 | display VM memory usage
3 | dump video page info
4 | display msg mode register state
5 | display planar mode register state
6 | read DAC
7 | display VM DAC states
8 | enable Queue_Outs
9 | enable MemC debug event


vdmad (VDMAD Debug Binary Utility)

Virtual DMA Device State Dump.


.vflatd (VFLATD Debug Binary Utility)

Virtual Flat Video Buffer Device statistics and event log.


.vkd (VKD Debug Binary Utility)

Virtual Keyboard Device

[0] - General info

[1] - Hot Key info

[2] - Per VM info

[3] - Set VKD queue_outs

[ESC] - Exit VKD debug query

.vmm (Display VMM Commands)

.vmm

Displays a menu of subcommands. Pressing a single key causes the corresponding command to be carried out.

Service | Comments
[A] System time | Displays the current system time.
[B] Display Critical Section info |
[C] Display blocked thread information |
[D] Reset dyna-link profile counts |
[E] I/O port trap information | Displays information about I/O emulation handling. The first section displays general information about the hash table used to dispatch trapped I/O instructions. The second section lists each I/O port trapped, number of times trapped, percentage of total number if I/O traps, current trapping state, hash function result, table index, offset from ideal table index, and handler routine name. This information is useful for determining which ports are trapped frequently and thus need to be tuned for speed.
[F] Reset I/O profile counts | Reset the trap counts on all I/O ports. Useful for isolating the profile information to a particular section of execution, such as reading from a floppy drive, etc.
[G] Turn procedure call trace logging on/off | Toggles the state of call tracing. When on, each debugging code created by the BeginProc macro performs a Queue_Out of the routine name each time it is entered. Thus when ".S" is invoked to dump a fault log, the log will be interspersed with messages stating each routine name as it is called and who called it, so it is possible to get a complete execution log.
[H] V86 interrupt hook information | Displays the V86 interrupt table; showing the current vector assignment and which VMM/device driver routines have hooked the interrupt, if any. This command gives a look at which interrupts are looked at by the different device drivers, etc.
[I] PM interrupt hook information | This command is similar to "G" above, but show the logical PM interrupt table. It shows current vector assignments and routine names that are hooked into the interrupt chains.
[J] Reset PM and V86 interrupt profile counts |
[K] Display event lists | This command displays the list of current global events, and then of list of local events for each VM.
[L] Display device list | This command displays the list of loaded devices along with the information from each Device Descriptor Block. Type .VMM L={DDB}, where DDB is the name of the VxD, to list an explicit module.
[M] Display V86 break points | This command displays a list of all V86 break points that are currently allocated. This list shows that CS:IP of the break point, the Ring 0 callback address/label and the reference data.
[N] Display PM break points | This command displays a list of all PM break points that are currently allocated. This list shows that CS:IP of the break point, the Ring 0 callback address/label and the reference data.
[O] Display interrupt profile | Profiles the activity (counts) of V86 Ints, PM Ints and VMM Ints
[P] Reset interrupt profile counts |
[Q] Display GP fault profile | Profiles General Protection Fault activity
[R] Reset GP fault profile counts |
[S] Toggle verbose device call trace | Turn on verbose device tracing to displays the name of each VxD before it is called, and OK when the VxD returns.
[T] Dyna-link service profile information | Displays a list of all services (in VMM and all devices) that shows the number of times the service has been called, the service number, routine address, and routine name. This information is a pseudo profile of which services are used frequently and thus should be tuned for speed.
[U] Fault Hook information | Displays all V86 fault hooks, PM fault hooks and VMM fault hooks.
[V] Display time out queues | Displays all the time out queues including the Async time out queue and Global time out queue.
[W] PM CLI/STI trace info |
[X] DPMI info |


.VPICD (Virtual PIC Device Status)

Status of hardware interrupts:

[1] Global PIC information (ring 0)

[2] Per-VM PIC information (virtualized VM state)

[3] IRQ handler information (hardware interrupts and who is responsible for each)


.VXDLDR (List Loaded Dynamic VxDs)

Displays the list of dynamically loaded VxDs.


.Y (CONFIGMG Debug Binary Utility)

Displays CONFIGMG (Plug & Play) structures:

Welcome to CONFIGMG's debugger

A Arbitrators Show the list of arbitrators

B Block queue Prevent processing of events

C Query remove Query removal at happy time

d remove Removal at happy time

e toggle Echo Set the echo to a specified level

f show Free Show free resources

g enumerate Enumerate a devnode

h Reenable Appy Reenable checking of query remove

i Show Log Show procedural logs

j test walks Test our walk procedures

k Show stack Show stack of procedure logs

l show List Show devnode list

m screen size Set screen size

n Nuke logs Nuke the procedure logged

p Problem List devnodes with problems

q Quit Quit the debugger

r show Range Show a Range

s Show tree Show the hardware tree

t toggle time Toggle the display of time

u Unblock queue Restart processing of events

v View status View the global status of CONFIGMG

w show all range Show all the rangelists

x eXclude Filter logging of procedure logs

y force smthng Call some random HWProfile API


Other Tools

The Device Driver Kit includes several tools:

ADRC2VXD: Adds a resource to a VxD file.

HDR: Displays information about executable files.


ADRC2VXD

The ADRC2VXD command allows you to append a resource onto a VxD file. You can use this command to add version information to your VxDs.

Syntax

adrc2vxd vxdname resfilename

Parameters

vxdname
Specifies the VxD filename
resfilename
Specifies the resource filename.

Examples

The following example appends the resource version.res onto the VxD vtestd.vxd

adrc2vxd vtestd.vxd version.res


Creating a version resource

You can use the following template to create a version resource for your VxD file

/********************************************************************/

/* Version control data */

/********************************************************************/

#include <version.h>

#define VER_FILETYPE VFT_VXD

#define VER_FILESUBTYPE DEVICE_ID

#define VER_COMPANYNAME_STR "Company Name, Inc.\0"

#define VER_FILEDESCRIPTION_STR "Sample VxD\0"

#define VER_INTERNALNAME_STR "Sample\0"

#define VER_LEGALCOPYRIGHT_YEARS "1993-1995\0"

#define VER_ORIGINALFILENAME_STR "SAMPLE.VXD\0"

#include <common.ver>

In the example, DEVICE_ID is the VxD's Device ID or UNDEFINED_DEVICE_ID (defined in inc32\vmm.h) for dynaload VxDs. Use the resource compiler (rc.exe) to compile the above (the include files version.h and common.ver are in the inc16 include file subdirectory) and adrc2vxd to add it to your VxD.


HDR

Prints header information from executable files.

Syntax

hdr [ options ] filename

Parameters

-d
Prints data relocation records.
-f
Prepends the file name on every output line.
-h
Prints the file header (default).
-m
Print only memory segment table information.
-j[options]
Prints specified tables.
Option | Description
d | Prints debug table.
e | Prints entry table.
f | Prints extended attributes.
i | Prints import module table.
I | Prints import procedure table.
r | Prints resident name table.
R | Prints resource table.

-p
Prints file seek positions.
-R
Same as -r, but also follows relocation chains.
-r
Prints both text and data relocations.
-S
Prints the file segment table with a header.
-s
Prints the symbol table.
-T
Prints the file type.
-t
Prints the text relocation records.
-y
Dumps DOS .SYM file.
-v
Prints everything (verbose).
-?
Prints usage summary.
filename
Specifies the filename


Implementing Multiple Monitor Support

Multiple monitor support is a set of related features that support the use of more than one display device at a time. Many names have been used to describe this capability, including multiple displays, multiple adapters, and multimonitor. This document uses the name multimonitor. Support for multiple monitors is provided under the Microsoft® Windows® 98/Me and Windows® 2000 and later operating systems. Additional application programming interfaces and device driver interfaces are provided under Microsoft DirectX® 5.0. To support multiple monitors, see the Windows 2000 DDK available at the following web site:

http://www.microsoft.com/DDK/W2kDDK.htm

This section provides information on the following topics:

  • Implementing multimonitor support for Microsoft DirectX programming.
  • Implementing multimonitor support in Microsoft DirectDraw® and Direct3D® Hardware Abstraction Layer(HAL) drivers.
  • Implementing multimonitor support for Windows and Windows NT/Windows 2000 display drivers.


Configurations

Multimonitor support can be configured as multiple monitors, each connected to its own graphics adapter, or as multiple monitors connected to a single adapter that supports multiple outputs. Under either configuration, each display device can have a different size or position, and each device also can use a different color depth.

With multimonitor support, one monitor is the primary display and behaves the same as the VGA display under Windows® 95. The origin is at 0, 0 (upper left-hand corner) for the VGA device; other monitors can use negative origins (negative x, negative y, or negative x and y). System metrics and device capabilities refer to the primary display. The bounding rectangle is a virtual screen, but it does not need to be a rectangle. Each monitor has its own work area and can use different resolutions and different color depths.

Large Desktops

Independent Displays


Large Desktops

Multimonitor support allows users to create large desktops in which the Windows desktop spans multiple monitors, thereby creating more onscreen real estate. The user can use a new control panel to configure the size and relative position of each monitor. Applications can be moved from one monitor to another, or they can be on more than one monitor simultaneously.

When the desktop spans multiple monitors, the operating system keeps all related windows, dialog boxes, and menus together on the same monitor A window is maximized only to a single monitor. Pop-up menus never span across monitors. Dialog boxes are placed on the monitor that contains the application owning that window. Application compatibility is nearly complete, so existing applications will work without modification. (Exceptions are described later in this section.)


Independent Displays

Another use for multimonitor support is to allow multiple independent displays to be attached to a single computer. An independent display appears on one monitor for exclusive use by a single application and is not part of the desktop. Because the application has total control of the display device, independent displays are especially useful for games and presentation applications.


Support for Hardware

Users can freely mix and match display hardware because the graphics adapters don't need to be identical. Each display device and monitor combination is enumerated and configured separately and can have completely different hardware characteristics. This means that each monitor can have different x,y resolutions and different color depths. Hardware that supports multimonitor capabilities includes:

  • Non-VGA displays
  • Graphics adapters with multiple outputs
  • PCI graphics adapters (classes 0380, 0301, and so on)
  • PCI VGA graphics adapters (class 0300)

The basic required features for hardware that supports multimonitor capabilities include the following:

  • Can operate with VGA off.
  • Can use memory-mapped input/output (MMIO) or relocatable I/O.
  • Can use linear frame buffer.
  • Has no VGA I/O accesses.
  • Has no A000 – B000 resource usage.

With multimonitor support, the operating system still needs a VGA device, which becomes the primary display. The basic input/output system (BIOS) picks the VGA device based on slot order, unless the BIOS offers an option for picking which device is to be treated as the VGA device. Notice also that the VGA device cannot be stopped, which is an important consideration for docking units.


Application Compatibility and Multimonitor Support

Under Windows® 98/Me and Windows® 2000 and later, applications do not need to be changed to work with the new multimonitor support. Applications work as if there were only one display. For example, dialog boxes that are displayed as centered on the screen do not span two monitors. Full-screen applications appear automatically on the primary display. The operating system automatically handles minimum/maximum for the display.

Although most applications display correctly with no problems, some applications are not designed to be placed in negative space, while other applications clip or center windows to the primary monitor. In the worst case, a particular application may need to run on the primary display only and therefore will require disabling the secondary display. The following types of applications have display problems on systems using the new multimonitor capabilities:

  • Drivers or applications that patch Gdi.exe or the display driver
  • Asynchronous transfer mode (ATM) applications
  • Remote control applications


Multimonitor Recommendations for Graphics System Design

This section describes known problems with current graphics system designs, and offers suggestions for fixing these problems. It also summarizes PC 97 requirements for multimonitor support. As indicated in the suggested solutions, an important requirement is that a PCI graphics adapter on the motherboard behave the same as any other PCI graphics adapter.


Motherboard Graphics Adapters

The following two problems may prevent motherboard graphics devices from supporting multimonitor capabilities:

  • PCI motherboard graphics adapter is hidden from the enumerator.

    Some system vendors hide the motherboard graphics adapter from the PCI bus when another graphics adapter is detected in the system. Microsoft strongly recommends that the OEM enumerate the motherboard device as a disabled PCI device rather than hiding it.

  • Operating system cannot read the ROM from a motherboard graphics adapter.

    The ROM for the motherboard adapter should be accessible through the PCI ROM BAR, just as any other PCI device.

As an additional design recommendation, the OEM should provide an option in the system BIOS setup utility to force the motherboard graphics device to be used (that is, to ignore and leave disabled any nonmotherboard PCI graphics adapters). This option ensures that a user with a PCI hot-docking system will always be able to undock, because the VGA device will be in the mobile unit.


PC 97 Requirements

The PC 97 Hardware Design Guide (Microsoft Press, 1996; ISBN 1-572321-381-1) lists several requirements for graphics adapters. These requirements must be implemented by January 1, 1998 for any adapter or PC system that receives the Designed for Windows NT/Windows 2000 and Windows 95 logo. The following list summarizes these requirements as defined in Chapter 15, Graphics Adapters, of the PC 97 Hardware Design Guide:

  • Item #7: Graphics operations use relocatable registers only
  • Item #11: Graphics adapters support DDC 2.0 Level 2 monitor detection
  • Item #14: Plug and Play conflict resolution for multiple monitors/multiple adapters
  • Item #15: VGA resources can be disabled by software
  • Item #16: Alternative mechanism to Int 10 for initialization provided
  • Item #43: Plug and Play device identifier (including Subsystem ID and Subsystem Vendor ID for PCI devices)
  • Item #44: Conflict resolution, VGA compatibility, and extended register
  • Item #45: PCI base address registers populated correctly for PCI graphics devices


Supporting Multimonitor in a Windows Display Driver

For Windows® 98, a new driver must be created to support multimonitor features. This driver must be a DIBENG driver and it must adhere to the following guidelines:

  • It must recognize a new parameter for Enable.
  • It must not hook or issue Int 2Fh calls.
  • It must be unloadable.
  • It must not touch VGA registers, except with help from the main VDD.


Implementation Example Using CreateDC

CreateDC. The graphics device interface (GDI) call understands "\\.\DisplayX" and works with the VDD to load the right driver for the device. The same syntax is used for Windows NT/Windows 2000. This is all that is needed for independent displays. The operating system may need to force multiple copies of the driver to load.

DDML. The GDI Display Driver Management Layer (DDML) is used for large desktop support. DDML makes multiple display drivers look like a single device to the Windows GDI. Each driver gets only its own drawing commands, which are (0,0) based. The driver does nothing different, even if each device has a different size, position, or color depth. The following occurs for large desktop support:

  • Device bitmaps are turned off.
  • Physical objects are shared (DIB_Brush, DIB_Pen). Be sure your driver checks the PRIVATEDATA bit in DIB_Brush.
  • The mouse pointer appears on only a single device SetCursor, which is called when the pointer switches to another device.

CreateDC to PatBlt. For this support, the application calls CreateDC(0, "\\.\DisplayX",0,0). GDI gets the driver name from the registry, loads the display driver, forces a second instance by default, and calls OEMEnable with the device name. Driver calls VDD_OPEN to convert the name to a handle (EBX); 1 is the handle for the VGA device. The driver calls VDD_GET_DISPLAY_CONFIG to get the display settings and device node handles, and then uses the device node to get the resource assignment.

Important The driver must use these methods to get data. Do not read the registry directly, and do not query devices.

When the driver enables the device, it fills in pDevice, but does not hook Int 2Fh. After Enable returns success, GDI returns the device context to the application. The application calls PatBlt and OEMBitBlt.

To complete this, the application calls DeleteDC , GDI calls OEMDisable, and the driver calls VDD_CLOSE on the handle. Then, GDI unloads the driver.

Note To determine which driver to load, GDI gets the driver name from the software registry key for the device and then reads DRV2 (not DRV) in the registry. If DRV2 is not present, it is assumed the driver is not multimonitor aware. Device node does not start if DRV2 is missing.

The following list summarizes implementation rules for multimonitor drivers:

  • The driver must access the blitter and framebuffer through relocatable memory-mapped I/O (MMIO) and a relocatable linear framebuffer.
  • Never map a MMIO or framebuffer selector in the miniVDD; always map it in the driver.
  • Use the handle of the current device (in EBX) when making the VDD_GET_DISPLAY_CONFIG main VDD call. This gets the correct resolution for the particular display, whether primary or secondary.
  • Since you can never access VGA resources while running as the secondary driver, the driver may need to be altered to support a software cursor-only flag. This would have to be implemented if hardware cursor support needs to access VGA resources.
  • Never issue an Int 2f from a secondary driver.
  • Never hook Int 2f from a secondary driver. This ensures that most of the Sswitch.asm code is never executed.
  • Never call the GetProcAddress function with the DISPLAY module name. With multiple drivers loaded, they are all named DISPLAY so you do not know which address will be returned.


Implementation Example Using Drv2.c

Two files, drv2.c and minivdd.h, have been provided to assist driver writers in implementing drivers that support running a device as a secondary display. It is completely optional to use these support files in developing a multimonitor-aware driver. The drv2.c file includes the Enable, ReEnable, Disable, ValidateMode, ValidateDesk, SetPalette, and Control functions. These functions overlap the current driver entry point names, so be sure to rename these functions to Enable1, Disable1, and so on.

Add a function with the following prototype to your initialization code:

BOOL CanHWRunAsSecondary();

This routine is called before Enable1 is called. It returns TRUE if the driver can run as a secondary driver, and FALSE if it cannot. This routine is not called if the driver is running as the primary adapter. If required, enable your software cursor in this routine.

A DWORD global variable named dwDeviceHandle is defined and initialized by Enable to a value of 1 if on Primary, and to a value different from 1 if on Secondary. Use the dwDeviceHandle when making the VDD_GET_DISPLAY_CONFIG main VDD call. This gets the correct resolution for the particular secondary display. Use this initialized handle for any main VDD call (VDDEntryPoint).


Using Single-Instance or Multiple-Instance Drivers for Windows

By default, the Windows GDI component loads unique driver instances for each adapter present in the system, even if they are the same adapter/chip set types. This design decision was made due to the large number of global variables in a typical driver. However, the driver writer can prevent additional instances of a driver from being loaded. GDI checks the dpDCManage member of the GDIINFO structure to decide whether a second instance should be loaded. Therefore:

  • A value of DC_IGNOREDFNP forces a second driver to be loaded.
  • A value of zero causes the existing driver to be reused.

To support this, the driver should not use global variables. The driver needs to store all device states in lpPDevice and deDriverReserved should be used for this. However, some GDI functions do not take lpPDevice as a parameter. GDI passes lpPDevice in EDX for the following functions:

CheckCursor

GetPalette

GetPaletteTranslate

MoveCursor

SetCursor

SetPalette

SetPaletteTranslate

The ValidateMode function does not take an lpPDevice parameter. However, another function does, ValidateModeEx. It is exported by name and is passed an lpPDevice, which can be NULL. It is also passed an lpDEVMODE (Win32 device mode). In this process, be sure to check dmFields to query the color depth and refresh rate.


Implementing Multimonitor Support for DirectX Programming

Applications do not need to be rewritten to work with multimonitor support. Full emulation is provided in the operating system. Full-screen applications work in the manner that 3-Dfx applications currently do. No functions were added to DirectDraw for multimonitor support— DirectDrawEnumerate does it all. For windowed applications, however, the application needs to be aware of multimonitor support to take advantage of the new hardware. The changes include the following:

  • The application must use different DirectDraw objects and capability bits.
  • The application cannot share surfaces and it cannot blit between the displays.
  • The application must use device coordinates, not screen coordinates, as these are no longer the same.
  • The application must use emulation for windowed applications. This only applies to DirectDrawCreate(NULL) and is based on the first call to IDirectDraw::SetCooperativeLevel. The driver writer must use a GUID to use hardware.

DirectDrawEnumerate enumerates every active display in the system. It enumerates the primary display twice — once as NULL and once as a GUID — just as DirectSoundEnumerate does, but it will not do this on single monitor systems. DDCAPS_GDI is set for GDI drivers.

Win32 functions use device names, while DirectX functions use GUIDs. DirectDrawEnumerate enumerates the GUID and device name. For an example of how this works, see the sample STRETCH2 in the DirectX SDK.


Implementing Multimonitor Support in DirectDraw and Direct3D HAL

Although multiple instances of display drivers may be loaded, only one 32-bit DLL is loaded. The following implementation notes must be followed:

  • No VGA access is possible in the 32-bit DLL, only memory-mapped I/O (MMIO) and linear frame buffer (LFB) access.
  • No VGA flipping is possible.
  • VGA access can happen in 16-bit side (*.drv) because all access is done through Control.

One DLL has to handle many devices. No hardware state data can reside in the global data for the DLL. Shared data resides in the 16-bit driver side. Therefore, you should put all hardware state data in the miniVDD.

The following code shows how sData is shared in DriverInit:

LPVOID
  DriverInit(LPVOID ptr)
{
    sData = (LPS3THKINFO)MapSL(ptr);
    .
    .
    .
    return (LPVOID)sData;
}

For all other calls, this pointer is in the dwReserved3 member of the DDRAWI_DIRECTDRAW_GBL structure. One unique DDRAWI_DIRECTDRAW_GBL structure is provided for each enabled display.


VDD Changes in Windows 98

Under Windows® 95 the default configuration accommodates one display and one VGA-compatible monitor. Windows® 98 provides Plug and Play support for display class devices and multiple output devices, but it still requires at least one VGA device. VDD, the Windows 98 device loader for graphics adapters, supports the following:

  • New services for display drivers
  • Hot docking for video devices
  • Power-on self test (POST) for secondary PCI VGA devices
  • VGA device isolation
  • New registry settings for secondary displays (DRV2)

The following table summarizes the functions provided to support Plug and Play configuration for multiple display devices.

Function | Description
VDD_CLOSE | Closes the device associated with a particular handle. Each VDD_OPEN call must be balanced with an accompanying VDD_CLOSE call.
VDD_ENABLE | Enables or disables access to a device. Calls to video BIOS or VGA I/O must be bracketed with VDD_ENABLE calls. (Reads and writes to linear 8000 address, not physical 8000 address.)
VDD_OPEN | Opens a device with a given name, and returns a device handle to the device. The device handle is used in other main VDD calls.
VDD_OPEN_KEY | Opens a key in the registry.

For a VGA device, the multimonitor-enabled driver controls the three device states — OFF, VGA, and GUI mode — as summarized in the following table.

The following table lists the device states for a VGA device.

State | Description | Comments
OFF | Initial state | Set by OEMDisable, or if failure occurs in OEMEnable. Also set when ENABLE_NONE flag is used in VDD_ENABLE.
VGA | Used only for mode/palette set. | Set when ENABLE_ALL flag is used in VDD_ENABLE. ROM will be mapped in so that INT 10h can be used (then, turn it off before leaving the DDI call).
GUI mode | Typical Windows running mode | Set by OEMEnable on success. VGA resources must be turned off by the driver. VDD will check if you turned off the VGA. Set with VDD_ENABLE ENABLE_MEM.

The driver must use only MMIO and linear frame buffer access while drawing in GUI mode; it can use Int 10h to change modes. The driver can use VGA resources for these functions: ReEnable, Disable, ValidateMode/ValidateDesk, SetPalette, and Control.

Plug and Play support for PCI display devices in Windows 98 assigns VGA resources to the right device and supports video devices behind a PCI bridge. PCI configuration control bits are used to enable and disable access to a hardware device, as follows:

  • PCI 04 bit 0 — I/O enable/disable.
  • PCI 04 bit 1 — memory access enable/disable.
  • ROM is mapped in and out of C000.

The following table provides a sample PCI configuration for multiple display devices.

 | VGA #1 |  |  | VGA #21
 | I/O | Memory | ROM2 | I/O | Memory | ROM
System POST | on | on | on | off | off | off
Windows Logo | on | on | on | off | off | off
VGA #2 POST | off | off | off | on | on | on
Enable #1 | on | on | on | off | off | off
End Enable #1 | on | on | on | off | off | off
Enable #2 | off | off | off | on | on | on
End Enable #2 | on | on | on | off | on* | off
1VGA #2 has been programmed not to decode VGA resources (that is, GUI mode). 2At C000.

Two new miniVDD calls are provided to implement disabling the VGA: TURN_VGA_ON and TURN_VGA_OFF. This prevents the miniVDD from writing to the PCI configuration space.


Writing a Windows MiniVDD for a Secondary Display

The main job of a miniVDD is VGA virtualization. Secondary displays are not VGA devices, however, so most miniVDD code is not needed for a secondary display. You should use a secondary miniVDD only if you really need it.

The miniVDD for a secondary display is stored in the registry as Minivdd2. When a secondary miniVDD is used, the operating system does not load cardVDD2 and a single copy of the VxD is used.

The driver should implement PNP_NEW_DEVNODE and should use CM_Set_Driver_Private_DWORD for instance data. A user mode (ring 3) driver must use VDD_REGISTER_DISPLAY_DRIVER_INFO to communicate with the miniVDD.

VDD_Get_DISPLAYINFO gets the device node handle and uses the device node to get its resource assignment. On secondary devices, DEVICE_IS_NOT_VGA is set in diInfoFlags.

Do not hook VGA functions on non-VGA devices. Only the following miniVDD calls, listed in alphabetic order, should be hooked:

DISPLAY_DRIVER_DISABLING
GET_ADAPTER_POWER_STATE_CAPS
GET_MONITOR_POWER_STATE_CAPS
GET_NUM_UNITS
GET_TOTAL_VRAM_SIZE
MAKE_HARDWARE_NOT_BUSY
POST_CRTC_MODE_CHANGE
PRE_CRTC_MODE_CHANGE
PRE_INT_10_MODE_SET
REGISTER_DISPLAY_DRIVER
SET_ADAPTER_POWER_STATE
SET_MONITOR_POWER_STATE
TURN_VGA_OFF
TURN_VGA_ON
VESA_CALL_POST_PROCESSING
VESA_SUPPORT


Multiple Outputs

For both single-instance and multi-instance drivers, the miniVDD handles GET_NUM_UNITS and creates multiple pDevices. The miniVDD uses VDD_GET_DISPLAY_CONFIG to get the unit number (diUnitNumber). One, both, or none of the devices can be active at once. If the specific hardware has restrictions on modes when both units are active, then ValidateModeEx needs to reflect this in the miniVDD.

Note In this case, the user might have to detach a device to change modes.


Installing a Multimonitor Driver for Windows 98

The following shows the INF changes, shown in bold, required for installing a multimonitor driver for Windows® 98:

[OEM.AddReg]
    HKR,,Ver,,4.0
    HKR,,DevLoader,,*vdd
    HKR,DEFAULT,Mode,,"8,640,480"
    HKR,DEFAULT,drv,,oem.drv
    HKR,DEFAULT,drv2,,oem.drv
    HKR,DEFAULT,vdd,,"*vdd,*vflatd"
    HKR,DEFAULT,minivdd,,oem.vxd
    HKR,DEFAULT,minivdd2,,oem.vxd
    HKR,DEFAULT,RefreshRate,,-1

The following code is used to determine whether the display device is a primary or secondary display:

WORD
  OEMEnable( LPVOID lpDevice,
             WORD wAction,
             LPSTR lpDestDevType,
             LPSTR lpOutputFile,
             LPVOID lpData)
{
// Is the display device primary or secondary display?
    if (lpDestDevType == NULL)
    {  // running on Primary Display device
       dwDeviceHandle = 1;
    }
    else
    {  // running on Secondary Display device
       dwDeviceHandle = VDDOpenDevice(lpDestDevType);
    }
}


Adding Multimonitor Support

For users, the addition of multimonitor support in the operating system means more room for displaying applications. For developers who provide drivers for traditional graphics adapters and multiple output devices, multimonitor support means that new multimonitor-aware device drivers must be written for Windows 98/Me and Windows® 2000 and later.


Writing Windows 98 Drivers

To write a miniVDD for Windows 98, you must have the most recent version of the Windows 98 DDK. Follow these recommendations for ensuring that you have up-to-date information for writing and testing display device drivers for Windows 98:

  • Participate in Windows 98 display driver development.

    If you are developing hardware for computers running Windows 95 or Windows 98, you should be developing drivers based on the support defined in the DirectX® Device Driver Kit (DDK). New features in Windows 98, such as multiple monitor support, OnNow power management, and refresh rate support, require driver modifications. To register, send e-mail to directx@microsoft.com with "DDK Request" in the subject line. Please include your name, title, company name, and phone and fax numbers, and provide a complete description of your hardware driver, including which device class it falls under.

  • Participate in Windows 98 beta testing.

    To participate in beta testing for Windows 98, please send e-mail to memreq@microsoft.com. Please include your name, title, company name, company type (IHV, ISV, ISP, or OEM), and phone and fax numbers.

  • Submit hardware to the Windows Platform Group for testing.

    You must ensure that the Windows 98 product team has the appropriate hardware to test your driver, either by having Windows Hardware Quality Labs (WHQL) deliver the hardware to the Windows 98 product team at the completion of logo testing, or by providing compatible hardware directly to the Windows 98 product team. If you are not already working with a program manager in the Windows Platform Group, please send e-mail to nt5req@microsoft.com to submit hardware. Please include your name, title, company name, company type (IHV, ISV, ISP, or OEM), and phone and fax numbers.

  • Submit new drivers to WHQL for testing.

    If you are developing new hardware or making changes that result in a new binary, be sure to submit your drivers, INF files, and hardware to WHQL for testing. For information, please send e-mail to whqlinfo@microsoft.com.


Writing Windows 2000 Drivers

Information about writing drivers for Windows 2000 is provided in the documentation. Follow those recommendations for ensuring that you have up-to-date information for writing and testing display device drivers for Windows 2000:

  • Provide evaluation equipment for testing during Windows 2000 development.

    Be sure to also provide the complete specifications for the equipment, including component specifications. This greatly speeds the problem identification and resolution process. To provide systems to Microsoft for development with Windows 2000, please send e-mail to nt5req@microsoft.com. Please include your name, title, company name, company type (IHV, ISV, ISP, or OEM), and phone and fax numbers.

  • Submit new drivers to WHQL for testing.

    If you are developing new hardware or making changes that result in a new binary, be sure to submit your drivers, INF files, and hardware to WHQL for testing. For information, please send e-mail to whqlinfo@microsoft.com.


Multimonitor Reference

This section presents the added or extended function call definitions that enable multiple monitor support. The following topics are discussed:

Win32 API Functions for Multimonitor Support

New VDD Entry Points

New MiniVDD Entry Points

Failure Codes


Win32 API Functions for Multimonitor Support

The following Win32® API functions have been added for multimonitor support:

EnumDisplayMonitors

GetSystemMetrics

GetMonitorInfo

MonitorEnumProc

MonitorFromPoint

MonitorFromRect

MonitorFromWindow

SystemParametersInfo

This section also contains the following existing Win32 function:

Enable

Each physical display device is represented to the application by a monitor handle called an HMONITOR. A physical device has the same HMONITOR value throughout its lifetime, even across changes to display settings, as long as it remains a part of the desktop. When a WM_DISPLAYCHANGE message is broadcast, any HMONITOR can have its settings changed in some way, or can be removed from the desktop and become invalid.

A valid HMONITOR is guaranteed to be non-NULL.


Enable

The Enable function returns information about the driver or initializes the driver. GDI calls this function when it creates a device or information context for an application, or when it restores the context after Windows returns from a full-screen application.

Every graphics driver must export an Enable function.

WORD
  Enable(
    LPVOID  lpDevInfo,
    WORD  wStyle,
    LPSTR  lpDestDevType,
    LPSTR  lpOutputFile,
    LPVOID  lpStuff
    );

Parameters

lpDevInfo
Points to a PDEVICE or GDIINFO structure depending on the value of the wStyle parameter.
wStyle
Specifies whether to return information or initialize the driver and device. This parameter can be one of the following values.
Value | Meaning
0x0000 | Initializes the driver and associated hardware, then copies device-specific information needed by the driver to the PDEVICE structure pointed to by the lpDevInfo parameter.
0x0001 | Copies the device driver information to the GDIINFO structure pointed to by lpDevInfo.
0x8000 | Initializes the PDEVICE structure pointed to by the lpDevInfo parameter, but does not initialize the driver and peripheral hardware.
0x8001 | Means the same as the 0x0001 value.

lpDestDevType
NULL if the lpDevInfo represents the primary display surface.

Points to a zero-terminated string that represents the secondary device being enabled. Pass this pointer to a VDD_OPEN call. Typically this string is in the form of \\Display X, where X will be 1, 2, 3, .... 9.

lpOutputFile
lpStuff


EnumDisplayMonitors

The EnumDisplayMonitors function has been added so applications can revise their code to take advantage of the different color depths on different displays.

This function lets the application paint into a DC that spans more than one display. The function calls back for each monitor that intersects the specified window and gives an HDC that is appropriate to that monitor. The capabilities and color depth information from that HDC will match those of the monitor. The application can then paint the piece of its window on that monitor into that DC.

For example, this is how Microsoft PowerPoint uses this function. Assume that half of a slide show window is on a 256-color monitor and the other half is on a 24-bit true color monitor. The function calls PowerPoint once for the 256-color monitor piece. PowerPoint sees that it only has 256 colors and dithers the wash for the background. The function then calls PowerPoint a second time for the piece on the 24-bit display. PowerPoint can take advantage of all of the colors to draw.

Again, no application must do this; applications can continue to paint assuming the whole screen is the color depth of the primary monitor. The display will look fine. However, a graphical photo editing application, for example, can paint optimally for its particular current display.

BOOL
  WINAPI EnumDisplayMonitors(
    HDC hdc,
    LPCRECT lprcClip,
    MONITORENUMPROC lpfnEnum,
    LPARAM dwData
    );

Parameters

hdc
A handle to a DC with a particular visible region. The hdcMonitor passed to MonitorEnumProc has the capabilities of that monitor, with its visible region clipped to the monitor and hdc. If hdc is NULL, the hdcMonitor passed to MonitorEnumProc is NULL.
lprcClip
Points to a rectangle to which the area may be clipped. If hdc is non-NULL, the coordinates have the origin of hdc. If hdc is NULL, the coordinates are virtual screen coordinates. If lprcClip is NULL, no clipping is performed.
lpfnEnum
Pointer to the enumeration function.
dwData
Application-defined data that is passed through to the enumeration function.

Comments

Following are some examples of how to use EnumDisplayMonitors:

  • To paint in response to a WM_PAINT message using the capabilities of each monitor, an application would write the following in its window procedure:
    case WM_PAINT:
    hdc = BeginPaint(hwnd, &ps);
    EnumDisplayMonitors(hdc, NULL, MyPaintEnumProc, 0);
    EndPaint(hwnd, &ps);
  • To paint the top half of a window using the capabilities of each monitor, an application would write the following:
    GetClientRect(hwnd, &rc);
rc.bottom = (rc.bottom - rc.top) / 2;
hdc = GetDC(hwnd);
EnumDisplayMonitors(hdc, &rc, MyPaintEnumProc, 0);
ReleaseDC(hwnd, hdc);
  • To paint the entire screen using the capabilities of each monitor, the application would call the following:
    hdc = GetDC(NULL);
EnumDisplayMonitors(hdc, NULL, MyPaintScreenEnumProc, 0);
ReleaseDC(NULL, hdc);
  • To get information on all the displays on the desktop, the application would call the following:
    EnumDisplayMonitors(NULL, NULL, MyInfoEnumProc, 0);


GetMonitorInfo

GetMonitorInfo allows applications to get metric information relevant to a particular monitor: It enables applications to position themselves correctly on monitors other than the primary monitor.

BOOL
  GetMonitorInfo(
    HMONITOR  hmonitor,
    LPMONITORINFO  lpmi
    );

Parameters

hmonitor
Specifies the handle of the monitor for which to get the information.
lpmi
Points to a MONITORINFO or MONITORINFOEX structure (both defined in the Platform SDK documentation) that will receive the information.


GetSystemMetrics

int
  GetSystemMetrics(
    int  nIndex
    );

Parameters

nIndex
Specifies the system metric or configuration setting to retrieve.

The following metrics refer only to the primary monitor:

Metric | Description
SM_CXSCREEN, SM_CYSCREEN | Width and height, in pixels, of the screen. Same as GetDeviceCaps(hdcPrimaryMonitor, HORZRES/VERTRES).
SM_CXFULLSCREEN, SM_CYFULLSCREEN | Width and height of the client area for a full-screen window.
SM_CXMAXIMIZED, SM_CYMAXIMIZED | Default dimensions, in pixels, of a maximized top-level window.

The following metrics refer to the entire desktop:

Metric | Description
SM_CXMAXTRACK, SM_CYMAXTRACK | Default maximum dimensions, in pixels, of a window that has a caption and sizing borders. The user cannot drag the window frame to a size larger than these dimensions. A window can override these values by processing the WM_GETMINMAXINFO message.

The following metrics have been added so the user can get the dimensions of the virtual screen:

Metric | Description
SM_XVIRTUALSCREEN |  | Left of the virtual screen.
SM_YVIRTUALSCREEN |  | Top of the virtual screen.
SM_CXVIRTUALSCREEN |  | Width of the virtual screen.
SM_CYVIRTUALSCREEN |  | Height of the virtual screen.

The following metric has been added to help an application optimize color management:

Metric | Description
SM_SAMEDISPLAYFORMAT |  | Returns true if all the monitors have the same color format. Note that two displays can have the same bit depth, but different color formats, if the red, green, and blue pixels have different sizes or are located in different places in a pixel.

The following metric has been added for its general usefulness:

SM_CMONITORS Returns the number of monitors on the desktop.


MonitorEnumProc

BOOL
  CALLBACK MonitorEnumProc(
    HMONITOR  hmonitor,
    HDC  hdcMonitor,
    LPRC  lprcMonitor,
    DWORD  dwData
    );

Parameters

hmonitor
Monitor. The callback is called only if it intersects the visible region of hdc, if non-NULL, and lprcClip, if non-NULL.
hdcMonitor
An HDC with capabilities specific to the monitor, and clipping set to the intersection of hdc, lprcClip, and the dimensions of the monitor. If hdc is NULL, hdcMonitor is NULL.
lprcMonitor
Points to a clipping area that intersects that monitor. If hdcMonitor is non-NULL, the coordinates have the origin of hdcMonitor. If hdcMonitor is NULL, the coordinates are virtual screen coordinates.
dwData
Application-defined data that was passed in EnumDisplayMonitors.


MonitorFromPoint

HMONITOR
  MonitorFromPoint(
    POINT  pt,
    DWORD  dwFlags
    );

Parameters

pt
To be provided.
dwFlags
To be provided.

Return Values

Returns the monitor that contains pt. If no monitor contains pt, the return value depends upon the dwFlags field:

Value | Description
MONITOR_DEFAULTTONULL | Returns NULL.
MONITOR_DEFAULTTOPRIMARY | Returns the HMONITOR of the primary monitor.
MONITOR_DEFAULTTONEAREST | Returns the HMONITOR nearest to the point.


MonitorFromRect

HMONITOR
  WINUSERAPI MonitorFromRect(
  LPCRECT  lprc,
  DWORD  dwFlags
    );

Parameters

lprc
To be provided.
dwFlags
To be provided.

Return Values

Returns the monitor that intersects lprc. If no monitor intersects lprc, the return value depends upon the dwFlags field as in MonitorFromPoint.


MonitorFromWindow

HMONITOR
  WINUSERAPI MonitorFromWindow(
    HWND  hwnd,
    DWORD  dwFlags
    );

Parameters

hwnd
To be provided.
dwFlags
To be provided.

Return Values

Returns the monitor to which a window belongs. If a window does not belong to any monitor, the return value depends upon the dwFlags field as in MonitorFromPoint .


SystemParametersInfo

BOOL
  SystemParametersInfo(
    UINT  uiAction,  // system parameter to query or set
    UINT  uiParam,   // depends on action to be taken
    PVOID  pvParam,  // depends on action to be taken
    UINT  fWinIni    //
    );

Parameters

uiAction
Specifies the system parameter to query or set.
uiParam
Is a value that depends on the action to be taken.
pvParam
To be provided.
fWinIni
Specifies the user profile update flag.
Value | Description
SPI_GETWORKAREA | Retrieves the size of the working area. The working area is the portion of the screen not obscured by the tray. The pvParam parameter points to the RECT structure that receives the coordinates of the working area.
SPI_SETWORKAREA | Sets the size of the work area. The work area is the portion of the screen not obscured by the task bar. The pvParam parameter points to the RECT structure that contains the coordinates of the work area.

SPI_SETWORKAREA has been modified to change the work area of the monitor that pvParam belongs to. If pvParam is NULL, the work area of the primary monitor is modified. SPI_GETWORKAREA always returns the work area of the primary monitor. If an application needs the work area of a monitor other than the primary, it can call GetMonitorInfo.


New VDD Entry Points

The following ring 3 Protected Mode API entry points can be called by ring 3 16-bit code:

VDD_CLOSE

VDD_ENABLE

VDD_GET_DISPLAY_CONFIG

VDD_OPEN

VDD_OPEN_KEY


VDD_CLOSE

VDD_CLOSE closes a device.

Entry | Meaning
Client_EAX | VDD_CLOSE equate from Minivdd.inc or Minivdd.h.
Client_EBX | Device handle to close.

Exit | Meaning
Client_EAX | Handle of device that was opened. Also called the DEVNODE of this device, this is the value used in a VDD_CLOSE call to close the device. Also the value used in a VDD_GET_DISPLAY_CONFIG call.
VDD_CLOSE | Indicates that the call was unsuccessful or that an error occurred.


VDD_ENABLE

VDD_ENABLE enables access to this device.

Note Only one device at a time can have VGA memory, I/O, or ROM access. All other devices are disabled if a secondary device has VGA access.

Entry | Meaning
Client_EAX | VDD_ENABLE equate from Minivdd.inc or Minivdd.h.
Client_EBX | Device handle.
Client_EDX | Enable flags: ENABLE_ALL - enable all access to this device ENABLE_IO - enable IO ENABLE_MEM - enable memory ENABLE_NONE - disable device ENABLE_ROM - enable ROM at C000 ENABLE_VGA - enable VGA

Exit | Meaning
Client_EAX | Previous enable state or ENABLE_ERROR. ENABLE_ERROR - enable fail code


VDD_GET_DISPLAY_CONFIG

VDD_GET_DISPLAY_CONFIG gets a DISPLAYINFO structure for a given device handle.

Entry | Meaning
Client_EAX | VDD_GET_DISPLAY_CONFIG equate from Minivdd.inc or Minivdd.h.
Client_EBX | Device handle.
Client_ECX | Size of the DISPLAYINFO structure.
Client_ES:EDI | Points to place to store the DISPLAYINFO structure.


VDD_OPEN

VDD_OPEN opens a device for a given name.

Entry | Meaning
Client_EAX | VDD_OPEN equate from Minivdd.inc or Minivdd.h.
Client_ES:EDI | Device name.
Client_EDX | Flag.

Exit | Meaning
Client_EAX | Handle of device that was opened. Also called the DEVNODE of this device, this is the value used in a VDD_CLOSE call to close the device. Also the value used in a VDD_GET_DISPLAY_CONFIG call.
VDD_OPEN | Indicates that the call was unsuccessful or that an error occurred.


VDD_OPEN_KEY

VDD_OPEN_KEY opens the setting key in the registry for the given device. The caller must close this key using the RegCloseKey function.

Entry | Meaning
Client_EAX | VDD_OPEN_KEY equate from Minivdd.inc or Minivdd.h.
Client_EBX | Device handle.
Client_ECX | Size of ES:EDI, Must be 4, or sizeof (HKEY)
Client_EDX Flags:

VDD_OPEN_KEY_GLOBAL - open the global (not per-user) settings.
VDD_OPEN_KEY_READ - will only be reading settings.
VDD_OPEN_KEY_USER - open the per-user settings.
VDD_OPEN_KEY_WRITE - will be writing settings.

Note If neither VDD_OPEN_KEY_USER nor VDD_OPEN_KEY_GLOBAL is specified, then the correct global/per user settings key will be opened.
Client_ES:EDI | Points to location to store the opened registry key.

Exit | Meaning
Client_EAX | Zero for success, or Win32 error code.


New MiniVDD Entry Points

The following sections contain the new miniVDD entry points.

GET_ADAPTER_POWER_STATE_CAPS

GET_MONITOR_POWER_STATE_CAPS

GET_NUM_UNITS

SET_ADAPTER_POWER_STATE

SET_MONITOR_POWER_STATE

TURN_VGA_OFF


GET_ADAPTER_POWER_STATE_CAPS

GET_ADAPTER_POWER_STATE_CAPS returns the valid power states of the display adapter or chip set.

Entry | Meaning
ESP+4 | Device node.

Exit | Meaning
EAX | Bitmask of the following: CM_POWERSTATE_D0 CM_POWERSTATE_D1 CM_POWERSTATE_D2 CM_POWERSTATE_D3


GET_MONITOR_POWER_STATE_CAPS

GET_MONITOR_POWER_STATE_CAPS returns the valid power states of the monitor. If this function is not implemented, the VDD assumes the monitor can implement Video Electronics Standards Association (VESA) Display Power Management Signaling (DPMS) functionality. It then calls the display BIOS to query the VESA DPMS support directly.

Entry | Meaning
ESP+4 | Device node.

Exit | Meaning
EAX | Bitmask of the following: CM_POWERSTATE_D0 CM_POWERSTATE_D1 CM_POWERSTATE_D2 CM_POWERSTATE_D3


GET_NUM_UNITS

GET_NUM_UNITS gets the number of "display units" that one device (or chip set) can support as separate display surfaces. Implement this function only if your device implements two or more units.

Entry | Meaning
ESP+4 | Device node.

Exit | Meaning
EAX | Number of display units.


SET_ADAPTER_POWER_STATE

SET_ADAPTER_POWER_STATE sets the adapter's power state to a new state.

Entry | Meaning
ESP+4 | Device node.
ESP+8 | Power state to set. One of: CM_POWERSTATE_D0 CM_POWERSTATE_D1 CM_POWERSTATE_D2 CM_POWERSTATE_D3

Exit | Meaning
EAX | CR_DEFAULT Routine did nothing. CR_SUCCESS Routine set the appropriate power state for the adapter/display chip set.


SET_MONITOR_POWER_STATE

SET_MONITOR_POWER_STATE sets the power state of the monitor. If this function is not implemented, the VDD assumes that the monitor can implement VESA DPMS functionality, and calls the display BIOS to set the power state of the monitor directly.

Entry | Meaning
ESP+4 | Device node.
ESP+8 | Power state to set. One of: CM_POWERSTATE_D0 CM_POWERSTATE_D1 CM_POWERSTATE_D2 CM_POWERSTATE_D3

Exit | Meaning
EAX | CR_DEFAULT Routine did nothing and the main VDD should do a VESA DPMS call to set the monitor power state. CR_SUCCESS Routine set the appropriate power state for the monitor.


TURN_VGA_OFF

TURN_VGA_OFF is an optional function that is called to allow the miniVDD to turn off access to the VGA resources on the given device.

Implement this function only if your device cannot be turned off using the PCI configuration registers, or if your device needs to access hardware registers while its VGA resources are off. An example would be a card that is processing hardware interrupts, and the interrupt service routine needs to touch non-VGA resources on the device. Another example would be for a multifunction card, capable of emulating multiple types of devices. Note, however, that the following caveats apply:

  • If this function is implemented, the decode of the VGA resources must be OFF. That is, reading 3c4h, 3c5h, 3d4h, 3d4h, 3ceh, 3cfh all return 0FFh.
  • If the miniVDD has virtualized interrupts and does not implement TURN_VGA_OFF, then the VDD will never start a secondary display device.
Entry | Meaning
ESP+4 | Device node.


Failure Codes

If a display device fails to start, usually indicated by a yellow '!' in the device manager (and usually a code 10 error code in the device manager), the VDD writes a more detailed error code in the registry. This code is contained in the hardware key of the display device ( HKLM\Enum\PCI\deviceid\instance). The following failure codes are provided:

FAIL_ANOTHER_VGA
Plug and Play subsystem allocated VGA resources to two devices.
FAIL_BAD_NUM_UNITS
GET_NUM_UNITS return value from the miniVDD was invalid (usually too large).
FAIL_BIGROM
After-POST size of the display BIOS is greater than 64K.
FAIL_BIGROMDP
VDD shows this error if the after-POST BIOS size is greater than 64K, and paging is using MS-DOS.
FAIL_CANT_OFF_VGA
After disabling the device, the VDD detected that the device was still decoding VGA resources. Multimonitor support requires that all PCI devices be capable of being disabled through PCI or the TURN_VGA_OFF function.
FAIL_CANT_READ_ROM
Common error with display devices on system motherboards. The system ROM has disabled the ROM of the device, but not the device itself. The VDD tries to POST the device, but it cannot read the ROM, usually off of the motherboard. In motherboard display systems, the VDD will write the ROM image to the registry if it can read the ROM. On motherboard display systems, the only way to read the ROM, in most cases, is to boot Windows 98 with the motherboard display as the only display system. The VDD then writes the ROM image to the registry. When it tries to POST the device and cannot read the ROM itself, the VDD gets the ROM image out of the registry.
FAIL_ISA_VGA
Some or all devices were detected as ISA devices. Multimonitor support assumes that all secondary devices are PCI devices.
FAIL_MINIVDD
MiniVDD returned an error when trying to load.
FAIL_MINIVDD_VGA
MiniVDD hooked a call that is reserved for the miniVDD of the main VGA device.
FAIL_NO_DRV2
Device has not started because there is no DRV2 entry in the software key of the registry..
FAIL_NON_PHYS_C000
Display BIOS does not exist at C000-C7FF.
FAIL_NONE
Fail code when the device is operating properly.
FAIL_POST_ASD
POST=0 is in the software key of the device, meaning that the last time the VDD tried to POST the device, it failed, hung the machine, or crashed the machine.
FAIL_TOO_LATE
VDD has started the system and it cannot start the main VGA after Windows has been started. This usually happens when the main Windows device is not a VGA and a VGA card is enabled by the user as a secondary display.
FAIL_VGA_NOT_PCI
Device was started, but it was detected as not being on a PCI bus.


Windows 98 Multimonitor Support for NEC PC-9800 Series

This documentation summarizes the development notes for NEC PC-9800 series display drivers that support the new multimonitor feature of Microsoft® Windows® 98.

For more information on the NEC PC-9800 series, refer to http://www.pc98.com.

To support the NEC PC-9800 Series monitors, see the DirectX 5.0 DDK available at the following web site:

http://www.microsoft.com/msdownload/directx/dxf/ddk/default.htm


Operating Environment

Hardware candidates for the new multimonitor feature include the PC-9801/9821 series models that are equipped with PCI expansion slots. In addition, the models must be capable of running Windows 98. To use the multimonitor feature, several display adapters must be available for multiple monitors.

The mulitmonitor feature operates on Windows 98 and requires a display driver that supports the multimonitor environment.


Multimonitor Capability

The multimonitor feature lets a single machine connect to multiple display adapters and monitors and also use multiple, independent desktop displays.

The multimonitor feature can be used for the following purposes:

  • Desktop publishing
  • Presentations: Multimonitor display can be used to prepare and deliver presentations
  • Games: Navigator and status can be displayed on separate monitors
  • Business: Several applications can be displayed by tasks on different monitors
  • Monitor matrix display: Nine monitors (3x3) can be used to create a mammoth display

To fully support a 3x3 monitor matrix display, the final version of Windows® 98 is expected to support up to nine monitors.


Multimonitor Support on the PC-9800 Series

The following topics describe the different scenarios of multimonitor support with respect to the PC-9800 series.

Multimonitor Support for Display Adapters

CRT Connection

Windows 98 Driver Operation on Windows 95

Display Adapters with Multiple Outputs


Multimonitor Support for Display Adapters

Multimonitor support for display adapters is determined by the display driver. In the PC-9800 series, the VGA resource has been controlled by each display minidriver (miniVDD). This is the case in Windows 98 as well. However, resource conflict must be avoided, because all display adapters must be enabled for the multimonitor feature at the same time.


CRT Connection

When using multiple adapters, display problems resulting from cable connections need to be circumvented by the user for the following reasons:

  • The cable connection cannot be detected by the software.
  • A similar problem may result, not only for multimonitor use, but in setups, including Windows® 95 (display card used is unknown).


Windows 98 Driver Operation on Windows 95

For the Windows 98 driver to operate on Windows 95, the driver must operate as a current Windows 95 driver. The following describes the driver operation switching method.

To determine whether the operating system is Windows 98 or Windows 95, the driver verifies the Virtual Machine Manager (VMM) version prior to miniVDD registration using the following call to the VMMCall macro.

VMMCall Get_VMM_Version
EAX Value | Meaning
< 040Ah | The driver operates as a current Windows 95 driver. NBR_MINI_VDD_FUNCTIONS_40 is set as the function value (ECX) when the VDD_Register_Mini_VDD service call is made in miniVDD registration.
≥ 040Ah | The driver operates as a Windows 98 driver. NBR_MINI_VDD_FUNCTIONS_41 is set as the function value (ECX) when the VDD_Register_Mini_VDD service call is made in miniVDD registration.


Display Adapters with Multiple Outputs

When the display adapter has a CHIP with more than one independent monitor output, or multiple CHIPs, the multimonitor feature can be supported by the following two methods:

  • Load the same driver in multiple instances
  • Load a driver that supports multiple outputs


BaseVDD Requirement

The following topic describes the process involved in loading the primary and secondary miniVDD.

Loading MiniVDD


Loading MiniVDD

Loading the Primary MiniVDD

The primary loading begins after verification of the multimonitor support level. This is given as a parameter during the miniVDD registration. The handling by baseVDD differs, depending on the following support levels.

Support Level | Description
Not supported (0). | Load as a standard driver (secondary cannot be used as a desktop).
Exclusive for primary (1) or dual usage (3). | OK.
Other than (0), (1), (3). | Loading failure (fallback mode).

Loading the Secondary miniVDD

When a driver passes all of the following, it is loaded as a secondary driver.

Note: If a problem is detected during one of the verification processes, loading is terminated and the monitor is set as a desktop monitor. It displays "!" in the device manager.

Verification Process | Result | Meaning
DEFAULT\Drv2 Check
 | Described | OK
 | Not described | Driver is not loaded. ("!" is displayed.)
Multimonitor support condition check at miniVDD registration
 | Not supported (0) or exclusive for primary (1) | Driver is not loaded. ("!" is displayed.)
 | Exclusive for secondary (2) or dual usage (3) | OK


Accelerator Requirement

The following topics describe the requirements for making previous drivers support the multimonitor feature.

INF Description

MiniVDD Registration

Protected Mode API in Multimonitor Environments

Windows Driver Model Interface


INF Description

Display Driver Description for the Secondary Monitor

As in AT-compatible machines, the name of the driver and the miniVDD must be entered for the secondary display driver.

  • The secondary driver must be entered in drv2 entry as follows:

    HKR, DEFAULT, drv2, , [driver name]

  • The name of the miniVDD must be entered in the minivdd2 entry as follows.

    HKR, DEFAULT, minivdd2, , [miniVDD name]


MiniVDD Registration

Due to the changes made in certain parts of the VDD_Register_Mini_VDD service parameter, which registers the miniVDD, the following conditions must be met.

  • Change miniVDD function value.

    Since the miniVDD function has been added for Windows 98, NBR_MINI_VDD_FUNCTIONS_41 must be set for the entry value (ECX) of the miniVDD function table. (The current entry value NBR_MINI_VDD_FUNCTIONS is NBR_MINI_VDD_FUNCTIONS_40.)

  • Add multimonitor support information.

    Information must be set for EAX that describes the multimonitor support level, whether the accelerator is functional for each of the primary and the secondary monitors.

  • Get device node handle.

    When loading the miniVDD, the baseVDD stores in EDX and returns the device node handle to access the PCI configuration by the GOFIGMG function.

    (After the display driver is loaded, use the device node handle from the display driver.)

<VDD_Register_Mini_VDD>

Entry | Description
EAX | Multimonitor support level Bits 1:0 have the following meanings: 00 - Multimonitor cannot be used, and cannot use simultaneously with another accelerator. 01 - Exclusive for the primary. Shared resource with Core Graph. Shared CRT output with Core Graph. 10 - Exclusive for the secondary. No switching feature for Core Graph. 11 - Primary and secondary enabled. Bits 31:2 are reserved and set to 0.
ECX | Function table entry number
ESI | Function table address
EDI | I/O trap table address

Exit | Value
AH | MiniVDD ID: 0 for the primary and a value > 1 for the secondary. Independent of device handle and device name (X in \\.\DisplayX) used by the display driver.
EDX | Device node handle
ESI | Offset to baseVDD control block
EDI | Common data area address for baseVDD


Protected Mode API in Multimonitor Environments

To identify which display driver is making the protected mode (PM) API call in a multimonitor environment, each display adapter identification number must be set when the protected mode API call is made.

Protected Mode API

 | Register | Meaning
Entry
 | AX | Function number
 | EBX | Display adapter ID number
 | Other | Used by each function.
Exit
 | All | Used by each function.


Windows Driver Model Interface

The following miniVDD functions have been added for communication purposes between the Windows Driver Model (WDM) driver and the miniVDD. The details are based on the specifications by Microsoft Corporation.

COPYPROTECTION_ACCESS

GPIO_ACCESS

GPIO_OPEN

I2C_ACCESS

I2C_OPEN


Differences Between AT Compatibles and the PC-9800 Series

Multimonitor Feature in AT Compatible Machines Differences in the PC-9800 Series
Defining Display Adapters

All display adapters must be connected to the PCI bus, since each accelerator's VGA resources are controlled exclusively. The display adapters are divided into the following two main categories:

 Same specification as AT machines.
Primary Display Adapter

This display adapter is the only one that has the VGA resource that enables startup/shutdown screen and full-screen command prompt display (MS-DOS mode) in addition to the graphical user interface (GUI) display.

 Previously provided (desktop GUI display, startup/shutdown screen display, and full-screen MS-DOS prompt) display functions are available (see , PC-9801/9821-Series Display Adapter).
Secondary Display Adapter

This display adapter is one that does not have any VGA resources other than for the primary display adapter that only displays GUI.

The secondary display adapter supports up to eight devices. With the addition of the primary display adapter, it supports up to nine devices.

 The Core Graph is used for full-screen command prompt for the primary display adapter. Therefore, it will not become the secondary display adapter because it is always a part of the primary display adapter. (see , Secondary Display Adapter).
Determining the Primary Display Adapter

Plug and Play BIOS differentiates the primary and secondary display adapters. That is, it assigns the VGA resources. The operating system is not involved in this process. Generally, the display adapter on the motherboard becomes the secondary display adapter when another display card is added. In some cases, however, the adapter may be unusable because it has become disconnected, or because ROM access has been denied (depending on the motherboard and BIOS).

 Register which display adapter is the primary in the registry. See Determining the Primary Display Adapter.
Display Driver

A compatible display driver for the secondary display adapter is necessary to use the multimonitor feature.

 To use the multimonitor feature, the display driver must be primary/secondary compatible (see Display Driver).
Primary

The current display driver for Windows 95 may be used. If a Windows 3.1 driver or a VGA driver is used, the multimonitor feature cannot be utilized even if another secondary display adapter exists.

 The current display driver for Windows 95 cannot be used as a primary display adapter.
Secondary

A compatible display driver is necessary to use the secondary display adapter.

 Same specification as AT machines.
Operation When Several Identical Boards are Installed

By default, a single instance of a driver is loaded for each adapter in the system, even if a board has the same display adapter and the same chip set installed. However, it is possible to program it to load the driver for every instance of the device in order to make it operate in a single instance.

 Same specification as AT machines.
Accessing the Adapter from the Driver

Control the PCI setting from baseVDD, enable the I/O resource of the board to be used, and disable all other boards so the driver may operate without identifying the multiple boards that are installed.

 Access the PCI configuration from the display driver and disable the resource when the driver is not accessing the adapter.

Accessing the PCI Configuration When multiple identical boards are installed, it is difficult for the PCI BIOS to identify the boards. Therefore, the PCI configuration must be accessed.

The system function:

CONFIGMG_Call_Enumerator_Function Must be called from the miniVDD to access the PCI configuration. However, the call cannot be made directly from the display driver; the interface between the display driver and miniVDD must be used.

Refer to the Index section and the Help in DDK regarding information about CONFIGMG_Call_Enumerator_Function.

User Interface

Settings for Determining if the Secondary is Used

By default, the primary display adapter is used as a desktop and the secondary display adapter is not used as a desktop (setting equivalent to current single monitor).

The multimonitor environment is enabled by setting the secondary display adapter to be used as a desktop. (The secondary adapter is not initialized when the machine is booted. Thus the BIOS is initialized at startup and the copyright information is displayed. If the secondary display adapter is not being used as a desktop, this display remains.)

No interface can change the primary display adapter because it is determined by the BIOS (VGA resource allocation).

 The primary display adapter is generally the last adapter to be detected. However, the internal accelerators may be set as the primary display adapter by the user. To do this, open the Device Manager dialog box, click the General tab, click Device Usage, and then select the Use as Primary Display Adapter check box.

(Reference 1: Property dialog)

* The appearance of the dialog is subject to change because the provided sample dialog is only in the development stage.

Settings for each monitor

In the Control Panel, select a display adapter to view its Display Properties dialog box. Click the Settings tab to view the options for detail settings, such as screen resolution and the number of colors. There are no limitations to the resolution and refresh rate settings. Each monitor can be used with any specified settings.

 Same specification as AT machines.
Setting the relative position of each monitor

By dragging each monitor in the upper portion of the following properties dialog, the relative position of each monitor can be changed. The transition of the mouse between monitors and displaying a spanned windows display is determined according to the specified position relationship. (The monitors cannot be separated or overlap each other. The display is auto-saved in an adjacent arrangement with the mouse enabled to move between monitors where the adjacent parts meet.)

Same specification as AT machines.
Task bar and icons placements

In the US version Developer Release, the task bar and the icon can only be displayed in the primary display adapter. The next BETA version release is expected to support arbitrary placements of the task bar and the icons on any monitor.
Full-screen command prompt

The full-screen command prompt (MS-DOS mode) can be used only in the primary display adapter (during window display, a full-screen command prompt can be used in any monitor).

Same specification as AT machines.
Direct X application

Full-screen display is enabled in any monitor.

 Same specification as AT machines.

Display Adapter Property Dialog

Display Properties for Multimonitor


PC-9801/9821-Series Display Adapter

The following three types of display adapters can be used for the PC-9801/9821 series:

  • Currently compatible graphics
  • Multiple color extension graphics
  • Window accelerator
  • 98 Core Graphics

Currently Compatible Graphics (Compatible Graph)

This type of display adapter is pre-installed in the PC-9801/9821 series and has the following features:

  • Plain format, 640 x 200/400, 8/16 colors
  • Overlapping with text is enabled

Multiple Color Extension Graphics (Extension Graph)

This type of display adapter is pre-installed starting from the PC-9821 series and has the following features (not installed in the PC-9821B series):

  • Packed pixel format, 640 x 400/480, 256 colors
  • Overlapping with text is enabled

Window Accelerator

The following three types of window accelerators can be used for the PC-9801/9821 series.

  • Internal window accelerator
  • NEC window accelerator board
  • IHV window accelerator board

98 Core Graphic (Core Graph)

This type of adapter includes all standard video systems (memory, I/O, etc.) in the PC9801/9821 series. This refers to the currently compatible graphics, the multiple color extension graphics, and text. The windows accelerator is not included.


Secondary Display Adapter

Accelerators other than the primary will be the secondary. However, they may not be used for the desktop due to the following limitations:

  • Limitations due to shared resources

    Accelerators that share resources, such as VRAM, with the core graph cannot be used at the same time as the core graph. This means the accelerator cannot be used as a secondary display adapter.

  • Limitations due to a common CRT output

    Accelerators that share the CRT output (CRT connector) with the core graph cannot be used as a secondary display adapter because they cannot be used at the same time as the core graph.

    (If an external accelerator is set as the primary display adapter, the internal accelerator cannot be used because the core graph output needs to be allocated to the external accelerator.)

  • Accelerators that use Vflatd.vxd

    When accessing VRAM, accelerators that use vflatd.vxd to switch banks cannot be used as secondary, according to the accelerator CHIP specification.

For secondary display adapters that cannot be used as a desktop due to the reasons previously listed, a "!" is displayed in the device manager.

Core graph with the primary as the accelerator does not display "!" or "x" in the device manager.


Determining the Primary Display Adapter

During setup, display adapters are detected in the order of primary priority, and the first display adapter found is loaded set as the primary display adapter.

When upgrading, the display adapter in use is set as the primary display adapter.

If a new display adapter is detected after a new display adapter is inserted, it is set as the primary display adapter and all other drivers are set as secondary display adapters. However, the setting that determines if it is used as a desktop remains.

As a result, the display adapter that was used as a primary display adapter is now a secondary display adapter. If this is exclusively a primary display adapter, such as the internal accelerator, its ability to be used as the desktop is automatically disabled ("!" is displayed in the device manager).

Abnormalities

When a display adapter that was stored in memory as a primary display adapter does not exist (for example, the display card has been removed), it starts up in fallback mode. (In fallback mode, the display adapter starts in Fail Safe mode display driver (640x400 16 color; 640x480 expected in Windows 98) and the hardware wizard boots the system.

If several display adapters are stored in memory as primary display adapters, the first one reported by Plug and Play is designated as the primary display adapter and the rest become secondary display adapters.


Display Driver

When using a Windows 95 driver or a driver that does not support the multimonitor feature for Windows 98, the following limitations apply:

  • When a driver that does not support multimonitor is used as the primary, "Use as desktop" cannot be set for other display adapters (secondary).
  • When a driver that does not support multimonitor is used as a secondary "Use as desktop" cannot be set for the display adapter that uses this driver. (Other display adapters can use the multimonitor feature.)

In addition, it must be determined which display driver is calling the function within the baseVDD interface, because several display drivers are operating simultaneously in a multimonitor environment.


Interface Between BaseVDD/MiniVDD/Display Drivers

The following table indicates the functions that must be supported by each display driver/miniVDD for the primary and secondary display adapters or usable services.

MiniVDD Functions

baseVDD —> miniVDD

No. | Function |  | Pri | Sec | Notes
1 | REGISTER_DISPLAY_DRIVER | Interface between miniVDD and driver | 2 | 2 |
2 | PRE_HIRES_TO_VGA | Switch to core graph | 1 | 3 |
3 | SAVE_REGISTERS | Save registers | 2 | 3 |
4 | RESTORE_REGISTERS | Restore registers | 2 | 3 |
5 | ENABLE_TRAPS | Enable I/O traps | 2 | 3 |
6 | DISABLE_TRAPS | Disable I/O traps | 2 | 3 |
7 | DISPLAY_DRIVER_DISABLING | Disable display | 1 | 1 |
8 | ENABLE_ACCELERATER | Enable display | 1 | 3 |
9 | DISABLE_ACCELERATER |  | 3 | 3 | Not Used
10 | CHECK_UPDATE |  | 3 | 3 | Not Used
11 | CHECK_WINDOWED |  | 3 | 3 | Not Used
12 | ACC_VBE_PM | VBE/PM | 2 | 2 |
13 | ACC_VBE_DDC | VBE/DDC | 2 | 2 |
14 | ACC_INT_10 | ESA BIOS (VGA BIOS) | 4 | 3 |
15 | ACC_GET_CAPABILITIES | Accelerator BIOS | 4 | 3 |
16 | ACC_GET_EXT_MODE_INFO | Accelerator BIOS | 4 | 3 |
17 | ACC_GET_FLAT_SELECTOR | Accelerator BIOS | 4 | 3 |
18 | ACC_ENABLE_BIOS | Accelerator BIOS | 4 | 3 |
19 | ACC_DISABLE_BIOS | Accelerator BIOS | 4 | 3 |
20 | ACC_SET_PALETTE | Accelerator BIOS | 4 | 3 |
21 | ACC_GET_PALETTE | Accelerator BIOS | 4 | 3 |
22 | ACC_SET_CURSOR | Accelerator BIOS | 4 | 3 |
23 | ACC_SHOW_CURSOR | Accelerator BIOS | 4 | 3 |
24 | ACC_HIDE_CURSOR | Accelerator BIOS | 4 | 3 |
26 | ACC_GET_CURSOR_POS | Accelerator BIOS | 4 | 3 |
27 | GET_NUM_UNITS | Obtain # of monitor units available for connection | 2 | 2 | New Feature (not yet supported)
28 | SET_ADAPTER_POWER_STATE |  | 2 | 2 | New Feature (not yet supported)
29 | GET_ADAPTER_POWER_ STATE_CAPS |  | 2 | 2 | New Feature
30 | SET_MONITOR_POWER_STATE |  | 2 | 2 | New Feature
31 | GET_MONITOR_POWER_ STATE_CAPS |  | 2 | 2 | New Feature
32 | ET_MONITOR_INFO |  | 2 | 2 | New Feature
33 | I2C_OPEN |  | 2 | 2 | New Feature
34 | I2C_ACCESS |  | 2 | 2 | New Feature
35 | GPIO_OPEN |  | 2 | 2 | New Feature
36 | GPIO_ACCESS |  | 2 | 2 | New Feature
37 | COPYPROTECTION_ACCESS |  | 2 | 2 | New Feature
1: Support is necessary 2: Support may be necessary 3: Support is unnecessary (not in use) 4: Necessary for accelerator BOS support (this function may not be supported in the future)

Protected Mode API Functions

Display driver (Windows kernel) —> baseVDD

The following miniVDD related protected mode API call interface will be changed partially.

Display drivers to be created in the future must follow these guidelines.

Multimonitor support does not function — even if a candidate for the secondary display adapter exists — if a display driver that does not meet the following calling guidelines is set as the primary, nor can it be used as a secondary.

No | Function |  | Pri | Sec | Notes
1 | VDD_DRIVER_REGISTER | register VDD driver | 1 | 1 |
2 | VDD_DRIVER_UNREGISTER | unregister VDD driver | 1 | 1 |
3 | VDD_SAVE_DRIVER_STATE |  | 3 | 3 | Not Used
4 | VDD_REGISTER_DISPLAY_ DRIVER_INFO | interface between miniVDD and driver | 2 | 2 |
5 | VDD_REGISTER_SSB_FLAGS |  | 3 | 3 | Not Used
6 | VDD_GET_DISPLAY_CONFIG | Obtain display settings | 2 | 2 |
7 | VDD_PRE_MODE_CHANGE |  | 3 | 3 | Not Used
8 | VDD_POST_MODE_CHANGE |  | 3 | 3 | Not Used
9 | VDD_SET_USER_FLAGS |  | 3 | 3 | Not Used
10 | VDD_SET_BUSY_FLAG_ADDR |  | 3 | 3 | Not Used
11 | VDD_VBE_PM | power management (—> ACC_VBE_PM) | 2 | 2 |
12 | VDD_ENABLE | resource control | 3 | 3 | New Feature
13 | VDD_GETMEMBASE | obtain memory address | 3 | 3 | New Feature
14 | VDD_OPEN | open device | 2 | 2 | New Feature
15 | VDD_CLOSE | close device | 2 | 2 | New Feature
16 | VDD_OPEN_KEY | open settings key | 2 | 2 | New Feature
17 | VDD_SET_POWER_STATE | power management (—> ACC_VBE_PM) | 2 | 2 | New Feature
1: Support is necessary 2: Can be used 3: Cannot be used

VDD Service Functions

miniVDD —> baseVDD

No | Function | Pri | Sec | Notes | Notes
1 | VDD_Get_Special_VM_IDs | Obtain Message VM ID | 1 | 1 |
2 | VDD_Register_Mini_VDD | Register miniVDD | 1 | 1 | Modified
3 | VDD_Install_IO_Handler | I/O trap | 3 |  |
4 | VDD_Install_Mult_IO_Handlers | I/O trap | 3 |  |
5 | VDD_Enable_Local_Trapping | I/O trap | 3 |  |
6 | VDD_Disable_Local_Trapping | I/O trap | 3 |  |
7 | Test_Vid_VM_Handle | Display owner VM check | 1 | 1 |
8 | VDD_Trap_Suspend | Interrupt process | 1 | 1 |
9 | VDD_Map_VRAM | Accelerator BIOS | 3 | 2 |
1: Can be used 2: Cannot be used 3: Cannot be used due to possible discontinuation of support in the future (supported in Windows 98 for compatibility with current drivers)


Reference

This section describes the following functions that have been added in Windows 98:

miniVDD

GET_ADAPTER_POWER_STATE_CAPS

GET_MONITOR_INFO

GET_MONITOR_POWER_STATE_CAPS

GET_NUM_UNITS

SET_ADAPTER_POWER_STATE

SET_MONITOR_POWER_STATE

Protected Mode

VDD_CLOSE

VDD_OPEN

VDD_OPEN_KEY

VDD_SET_POWER_STATE


GET_ADAPTER_POWER_STATE_CAPS

The GET_ADAPTER_POWER_STATE_CAPS function obtains the power saver mode supported by the display adapter.

ULONG get_adapter_power_state_caps(
  DEVNODE dn
  );

Parameters

dn
Device node of the display adapter.

Return Value

Returns the supported mode.
(0:supported, 1:not supported)

bit 0: STAND BY

bit 1: SUSPEND

bit 2: OFF

bit 3: REDUCED ON

bit 4-bit 31:Reserved


GET_MONITOR_INFO

The GET_MONITOR_INFO function obtains the EDID of the monitor.

CONFIGRET get_monitor_info(
  DEVNODE dn,
  int UnitNum,
  VESA_EDID *pedid
  );

Parameters

dn
Device node of the display adapter.
UnitNum
Monitor number.
*pedid
Pointer to the buffer that obtains the EDID information.

Return Value

Returns CR_SUCCESS if successful, or CR_FAILURE if an error has occurred, or *pedid to copy the EDID block content to the buffer.


GET_MONITOR_POWER_STATE_CAPS

The GET_MONITOR_POWER_STATE_CAPS function obtains the power saver mode supported by the monitor.

ULONG get_monitor_power_state_caps(
  DEVNODE dn
  );

Parameters

dn
Device node of the display adapter.

Return Value

Returns the supported mode.
(0:supported, 1:not supported)

bit 0: STAND BY

bit 1: SUSPEND

bit 2: OFF

bit 3: REDUCED ON

bit 4-bit 31:Reserved


GET_NUM_UNITS

The GET_NUM_UNITS function obtains the number of monitors that can be connected to the display adapter.

int get_num_units(
  DEVNODE dn
  );

Parameters

dn
Device node of the display adapter.

Return Value

Returns the number of connectable monitors.


SET_ADAPTER_POWER_STATE

The SET_ADAPTER_POWER_STATE function manages power for the display adapter.

CONFIGRET set_adapter_power_state(
  DEVNODE dn,
  DWORD PowerState
  );

Parameters

dn
Device node of the display adapter.
PowerState
Mode setting. One of the following:

00h: ON

01h: STAND BY

02h: SUSPEND

04h: OFF

08h: REDUCED ON

Return Value

Returns CR_SUCCESS if successful, or CR_FAILURE if an error has occurred.


SET_MONITOR_POWER_STATE

The SET_MONITOR_POWER_STATE function manages the power of the monitor.

CONFIGRET set_monitor_power_state(
  DEVNODE dn,
  DWORD PowerState
  );

Parameters

dn
Device node of the display adapter.
PowerState
Mode setting. One of the following:

00h: ON

01h: STAND BY

02h: SUSPEND

04h: OFF

08h: REDUCED ON

Return Value

Returns CR_SUCCESS if successful, or CR_FAILURE if an error has occurred.


VDD_CLOSE

The VDD_CLOSE function closes an open device.

Parameters

EDX: flags

EBX: device ID

Return Value

EAX: 0


VDD_OPEN

The VDD_OPEN function opens a device, given a name.

Parameters

ES:EDI: device name

EDX: flags

VDD_OPEN_EXIST
Checks whether the device name is valid.
VDD_OPEN_ENUM
Returns the Nth device.
VDD_OPEN_LOCK
Locks the device (default).

EBX: device ID

Return Value

EAX: device handle


VDD_OPEN_KEY

The VDD_OPEN_KEY function opens the registry key of the specified device.

Parameters

ECX: size

ES:EDI: phkey

EDX: flags

EBX: device ID

Return Value

EAX: zero for success


VDD_SET_POWER_STATE

The VDD_SET_POWER_STATE function controls power management settings.

Parameters

EDX: PowerState

01h: ON

02h: STANDBY

03h: SUSPEND

04h: OFF

EBX: device ID

Return Value

EAX:

CR_SUCCESS

CR_FAILURE


Using the CONFIGMG_Call_Enumerator_Function

VxDCall CONFIGMG_Call_Enumerator_Function

Description

Call the enumerator function about a child device node.

VxDCall CONFIGMG_Call_Enumerator_Function Get Device Info

For the input, the parameter name is the same as DDK help references.

Parameters

dnDevNode
Device node of the adapter.
efFunc = PCI_ENUM_FUNC_GET_DEVICE_INFO
Function number (obtain device information).
ulRefData
Offset within PCI configuration (number of bytes from head).
pBuffer
Pointer to the buffer to obtain information.
ulBufferSiz
Size to be obtained.
ulFlags
0.

Return Value

pBuffer
Points to the buffer in which the information is placed.

Sample Code

include     CONFIGMG.INC
include    PCI.INC

public    ReadPCI
BeginProc    ReadPCI, RARE, CCALL

Buf    dd    0

ArgVar    DevNode, DWORD
ArgVar    off, DWORD

EnterProc

SaveReg <ebx>

lea    ebx, Buf

VxDCall _CONFIGMG_Call_Enumerator_Function,<DevNode, PCI_ENUM_FUNC_GET_DEVICE_INFO, off, ebx, 4, 0>

mov    eax, [ebx]

RestoreReg <ebx>

LeaveProc
Return

EndProc        ReadPCI

VxDCall CONFIGMG_Call_Enumerator_Function Set Device Info

Parameters

dnDevNode
Device node of the adapter.
efFunc = PCI_ENUM_FUNC_SET_DEVICE_INFO
Function number (device information setting).
ulRefData
Offset within PCI configuration (number of bytes from head).
pBuffer
Pointer to the buffer which stores the setting information.
ulBufferSize
Setting size.
ulFlags
0.

Return Value

None.

Sample Code

include     CONFIGMG.INC
include    PCI.INC

public    WritePCI
BeginProc    WritePCI, RARE, CCALL

ArgVar    DevNode, DWORD
ArgVar    off, DWORD
ArgVar    setdata, DWORD

EnterProc

SaveReg <ebx, ecx>

lea    ebx, setdata
mov    ecx, size setdata

VxDCall _CONFIGMG_Call_Enumerator_Function,<DevNode, PCI_ENUM_FUNC_SET_DEVICE_INFO, off, ebx, ecx, 0>

RestoreReg <ecx, ebx>

LeaveProc
Return

EndProc    WritePCI


Process Flow

Overview of Switching between Primary/Secondary loading

Overview of Primary Loading

Overview of Secondary loading process


Setting the INFO Subkey

The following information pertains to the OEM Service Release (OSR) 2 release of the Microsoft® Windows® 95 operating system, as well as later versions of the operating system.

When the user clicks on the Advanced Properties tab in the Display Control Panel, it will read the INFO subkey in the registry to provide more specific information about the video chip set. A display driver should write this extra information into the registry at the end of PhysicalEnable. Thus, in addition to boot time, the registry is written to whenever a mode switch occurs.

The following is a list of fields, their types, and a description of their contents.

\\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Class\Display\

Field | Data type | Description
ChipType | string | Chip name.
DACType | string | DAC name.
VideoMemorySize | ulong | In bytes.
MMIO | bool | TRUE if device is using memory-mapped input/output (MMIO) predominantly. This is not invariant.
LinearAccess | bool | TRUE if device provides linear access to frame buffer.
HWCursor | bool | TRUE if device supports hardware cursor.

Sample code to write these values into the registry can be found in the Windows 98 Device Driver Kit (DDK). This file contains a function called RegistryLog that takes the device node handle and writes the information into the corresponding registry location.

The values written here should be the current settings. These values may vary depending on the desktop resolution and other variables, which is why the values are written to the registry at the end of PhysicalEnable.

The S3 Virge sample calls the RegistryLog entry point (reglog.c) from vga.asm, in the AdapterInfo entry point.


Custom Refresh Rates

The OEM Service Release (OSR) 2 release of the Microsoft® Windows® 95 operating system introduced custom refresh rates for video displays. For this feature to function properly with OEM-provided control panels, refresh rate information must be stored in the registry in a consistent manner. This section describes the correct method for storing custom refresh rate information in the registry.

Note If you implement custom refresh rates, the format of INF files for display driver installation and registry settings should be implemented as specified in the Windows® 98 Device Driver Kit (DDK).

If you implement a custom control panel, follow the guidelines defined in the Windows® 98 Platform SDK documentation. The specific references are provided in this documentation under the topic Reference Sources. Also, manufacturer-provided control panel applications should not disable default Windows functionality, including refresh rate setting. (This is a PC 97 requirement.)

When custom refresh rates are implemented for a display driver, the Windows 98 Display Control Panel applet is responsible for setting five registry entries in the locations summarized in this documentation.

Registry Entry 1

\\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Class\Display
    \<display #>\DEFAULT\RefreshRate

This entry should only contain one of two possible values. A value of zero selects the default refresh rate. A value of –1 selects the optimal refresh rate. This value is superseded if a custom refresh rate has been specified in Entry 2 for the current mode.

Registry Entry 2

\\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Class\Display
    \<display#>\MODES\<bit depth>
    \<horizontal resolution>,<vertical resolution>\RefreshRate

For each specific mode, this entry contains the custom rate to be used in that mode. If the entry does not exist, the display's DEFAULT\RefreshRate value in Entry 1 will be used. The entry should not exist if the user has never selected a custom refresh rate for that particular mode. Note that a separate custom refresh rate is maintained for every mode and specific rates should not be stored in the DEFAULT\RefreshRate key.

The Class Installer is responsible for setting Entry 3 through Entry 5 as follows, based on information in the INF files for the display adapter and monitor:

Registry Entry 3

Set by Windows when calling ChangeDisplaySettings with CDS_UPDATEREGISTRY specified.

\\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Class\Display
    \<display #>\MODES\8
    \<horizontal resolution>,<vertical resolution>\DEFAULT

For each resolution, this entry contains a comma-delimited list of valid refresh rates for that resolution. Note that this list is usually specified only for 8-bit modes, because refresh rates are usually independent of color depth. This entry is read by the control panel when giving the user a list of custom refresh rates.

If the refresh rates supported by your display device are not independent of color depth, you can specify additional registry entries for each mode for which this is true. In other words, for each mode, Windows uses the refresh rates listed for that exact resolution and color depth if the registry entry is present. If the registry entry for that mode is not present, Windows uses the refresh rates specified for the mode with the same resolution and 8-bit color depth.

The following shows the registry entry for modes that are not 8 bits per pixel (bpp) that support a different set of refresh rates than the 8-bpp mode at the same resolution:

\\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Class\Display
    \<display #>\MODES\<color depth>
    \<horizontal resolution>,<vertical resolution>\DEFAULT

The refresh rates offered to the user as custom refresh rates depend on information stored in the registry under Entry 3. The INF file of the display adapter should list all refresh rates it is capable of supporting. If a monitor is installed on the system, the list of available refresh rates should be limited by the maximum rate supported by the monitor in the given resolution.

Registry Entry 4

Used for multiple hardware configurations.

\\HKEY_LOCAL_MACHINE\Config\<config #>\Display\Settings\RefreshRate

Registry Entry 5

Contains currently active settings.

\\HKEY_CURRENT_CONFIG\Display\Settings\RefreshRate


Sample

The following sample was taken from the S3 ViRGE INF file. It is a partial listing of the AddReg section for the S3 driver. This sample defines custom refresh rates for 640x480, 800x600, 1024x768, 1152x864, and 1280x1024.

Because 1600x1200 has no custom refresh rates specified, only "Adapter Default" is available to the user at that resolution. Modes at 16 bpp and higher color depths use the same custom refresh rates specified for their 8 bpp counterparts.

HKR,"MODES\8\640,480",,,"60,72,75,85"
HKR,"MODES\8\800,600",,,"56,60,72,75,85"
HKR,"MODES\8\1024,768",,,"43,60,70,75,85"
HKR,"MODES\8\1152,864",,,"43,60,70,75,85"
HKR,"MODES\8\1280,1024",,,"45,60,72,75"
HKR,"MODES\8\1600,1200"
HKR,"MODES\16\640,480"
HKR,"MODES\16\800,600"
HKR,"MODES\16\1024,768"
HKR,"MODES\16\1152,864"
HKR,"MODES\16\1280,1024"
HKR,"MODES\16\1600,1200"
HKR,"MODES\24\640,480"
HKR,"MODES\24\800,600"
HKR,"MODES\24\1024,768"
HKR,"MODES\24\1280,1024"
HKR,"MODES\24\1600,1200"
HKR,"MODES\32\640,480"
HKR,"MODES\32\800,600"
HKR,"MODES\32\1024,768"
HKR,"MODES\32\1152,864"
HKR,"MODES\32\1600,1200"

As an example, if this part does not support 75 Hz at 1024x768x16bpp, the line HKR,"MODES\16\1024,768 is replaced by HKR,"MODES\16\1024,768",,,"43,60,70,85"

This new set of custom refresh rates overrides the 8-bpp rates for this mode only.


Reference Sources

If you provide a custom control panel, be sure that refresh rate information is stored in the registry in a manner consistent with the information defined in the preceding section. Documentation providing more details and examples is available on the Microsoft web site at http://www.microsoft.com/hwdev/devdes/


Video Drivers and the I2C Bus

Microsoft® Windows® 98 uses a Win32® driver model (WDM) streaming class driver to control video cards. Certain components on the video card (such as television tuners, video decoders, and video crossbars) are controlled by drivers that work with the class driver called minidrivers. Using minidrivers allows hardware vendors to create video drivers for various cards by simply installing the minidrivers that work with the devices on the card.

Several hardware manufacturers have adopted a modular approach to the building of video cards. This approach uses the I2C bus to connect devices to a master device. The master device sends commands to the devices for setting and reading the properties of the devices.

For video cards that use the I2C bus, the minidrivers tell the master device which device and what command to send on the I2C bus. The video class driver provided with Windows 98 provides an interface to minidrivers that handles the details of controlling the I2C bus.

To support Video Drivers and the I2C Bus, see the current DirectX DDK.

The following topics describe how to develop miniVDD interfaces for display devices that are I2C masters.


Writing an I2C Master MiniVDD

The miniVDD is the vendor-specific code that supports the display chip set. When the VGA chip set is the I2C master, this I2C support must be added to the miniVDD. The miniVDD exports two new entry points, I2C_OPEN and I2C_ACCESS. These entry points are called directly by the slave minidrivers and are exported by the miniVDD through the IRP_MN_QUERY_INTERFACE request.


Exporting the I2C Interface

The miniVDD can use the standard MiniVDDDispatch macro to export the I2C_ACCESS and I2C_OPEN functions, as shown in the following code sample:

MiniVDDDispatch    I2C_ACCESS, i2c_access

The miniVDD can also load the function table directly, in the following manner:

mov     [edi+(I2C_OPEN*4)], OFFSET32 i2c_openfunc


Implementing the I2C Interface

The I2C_OPEN function that the miniVDD exports to the slave minidriver opens or closes a channel for the slave minidriver to use when communicating with the I2C bus. The slave passes a pointer to its DEVICE_OBJECT, a flag indicating if the call is to open or close a channel, and a pointer to a I2CControl structure. The I2CControl structure contains information that the miniVDD needs to identify the channel and process commands for the I2C bus. This structure is defined in the I2C.h include file.

The following example shows a partial implementation of an I2C_OPEN function. You should add the code required to open and close a channel for your particular hardware.

NTSTATUS
STDMETHODCALLTYPE
  I2C_OPEN(PDEVICE_OBJECT DO,
           ULONG OpenClose,
           PI2CControl TheControl)
{
    if(OpenClose)    // True means open the channel
    {
        // Put a unique identifier in the Cookie field
        TheControl->Cookie = inc(Unique);
    }
    else    // Close the channel
    {
    }
}

The I2C_ACCESS function sends and receives data using the I2C bus. Its arguments are the DEVICE_OBJECT of the slave minidriver and the I2CControl structure used with the I2C_OPEN call. The Command member of the I2CControl structure indicates the action to take. The following example shows the basic structure of a I2C_ACCESS function. You should add the code that controls that I2C bus for your particular hardware where indicated.

NTSTATUS
STDMETHODCALLTYPE
  I2C_ACCESS(PDEVICE_OBJECT DO,
             PI2CControl TheControl)
{
    switch(TheControl->Command)
    {
        case I2C_COMMAND_READ:
            // Read a byte from the I2C bus and put it in
            // TheControl->Data
            break;
        case I2C_COMMAND_WRITE:
            // Send the byte in TheControl->Data to the I2C bus
            break;
    }
}


MiniVDD INF File

The INF file for the miniVDD has to include references to the INF files for the slave minidrivers so Plug and Play can load the slave minidrivers.

Adding the following lines in the INF AddReg section of the miniVDD INF file informs Plug and Play of a slave minidriver:

HKR,"ENUM\deviceN",pnpid,,"<actualpnpid>"

In this example N is a number ranging from 1 to N, and <actualpnpid> is the ID of the slave minidriver.

For example:

HKR,"ENUM\Device1",pnpid,,"testdevice1"
HKR,"ENUM\Device2",pnpid,,"testdevice2"


I2C Devices and Multimonitor Configuration

When the VGA is running I2C devices in a Windows 98 multiple monitor configuration, the miniVDD must be installed as a miniVDD2 to support I2C on the secondary device.

During the I2C_OPEN call, the miniVDD2 must translate the physical device object to a device node by using the _NtKernPhysicalDeviceObjectToDevNode function.


OnNow Power Management for Display Device Class Drivers

OnNow moves power management decision making from the basic input/output system (BIOS) into the operating system to allow for a greater degree of interoperability between the hardware and software. Display drivers need to be updated to support OnNow by responding to power state commands and by providing information on what power states are supported by the hardware device.

In Microsoft® Windows® 98, the virtual display driver (VDD) handles OnNow calls and passes them to the virtual display minidriver (miniVDD). The miniVDD handles the mechanics of saving and restoring state in the hardware during power transitions. If the miniVDD does not hook up to any of the OnNow functions (in the case of legacy drivers), the VDD makes Video Electronics Standards Association (VESA) calls.

Four states, which roughly correspond to the VESA states, can be supported by display hardware. These are as follows.

VESA Power State | OnNow Power State
On | D0
Standby | D1
Suspend | D2
Off | D3

In Advanced Configuration and Power Interface (ACPI) hardware, the physical removal of power is handled entirely by ACPI.

In Advanced Power Management (APM) controlled hardware, the removal of power is handled by the APM BIOS.

In desktop computers, power can still be removed from the display hardware if the computer is able to hibernate (save memory to disk and power off).

In all cases, the miniVDD does not need to do anything to physically alter the power consumption of the hardware. However, if the display hardware supports some form of power conservation that cannot be controlled by either of the above methods, the miniVDD can touch the hardware directly to reduce power consumption.

All hardware, regardless of ACPI or APM, will re-POST the device during a boot or when resuming from a hibernate state. When returning to the DO state on machines that can hibernate, the display driver must redo any initialization that happens after the power-on self test (POST)

Power transitions occur only between D0 and other states. In other words, there are no transitions between D1, D2, and D3.

The following occurs during power transitions:

  • For the primary (VGA) device, an INT 2F AX=4001 interrupt is sent when powering down; Windows sets text mode. When a wake-up event occurs, an INT 2F AX=4002 interrupt is sent; the driver internally calls ResetHiResMode. The operating system then repaints the screen.
  • For secondary displays (not the primary VGA), the operating system calls Disable when powering down and it calls Enable when powering up. The operating system then repaints the screen.

Note If a driver passes the "Magic School Bus" test in the Display Compatibility Test (DCT), then it works correctly.


Function Specifications

The latest version of minivdd.h for use with the Microsoft Windows 98 operating system has four new functions that a miniVDD can hook:

GET_ADAPTER_POWER_STATE_CAPS

GET_MONITOR_POWER_STATE_CAPS

SET_ADAPTER_POWER_STATE

SET_MONITOR_POWER_STATE


GET_ADAPTER_POWER_STATE_CAPS

The GET_ADAPTER_POWER_STATE_CAPS function should return the power states supported by the display adapter.

DWORD __cdecl
  GetAdapterPowerStateCaps(
    DEVNODE  devnode
  );

Parameters

devnode
Specifies the device node for the device.

Return Value

Bitmask of:

CM_POWERSTATE_D0
CM_POWERSTATE_D1
CM_POWERSTATE_D2
CM_POWERSTATE_D3


GET_MONITOR_POWER_STATE_CAPS

The GET_MONITOR_POWER_STATE_CAPS function returns the power states that are supported by the monitor and invoked explicitly by the display driver. If this function is not hooked, the VDD uses VESA calls to get the capabilities for the monitor.

GET_MONITOR_POWER_STATE_CAPS does not need to be hooked by most display drivers. It is provided as a convenience for special cases where the miniVDD needs to do something proprietary to control the monitor's power states.

DWORD __cdecl
  GetMonitorPowerStateCaps(
    DEVNODE  devnode
  );

Parameters

devnode
Specifies the device node for the device.

Return Value

Bitmask of:

CM_POWERSTATE_D0
CM_POWERSTATE_D1
CM_POWERSTATE_D2
CM_POWERSTATE_D3


SET_ADAPTER_POWER_STATE

The SET_ADAPTER_POWER_STATE function saves and restores whatever state is necessary to place the device into the power state specified in the PowerState parameter. The driver remains in memory at all times. Display memory contents do not need to be saved because the operating system resets the display mode during a return to the D0 state.

The default action defined by CR_DEFAULT is to re-POST the device if it is changing state from D3 to D0. Any other state transition results in no action. If the display driver is capable of initializing the device from a power-off without a POST, then this function returns CR_SUCCESS during the D3 to D0 transition.

DWORD __cdecl
  SetAdapterPowerState(
    DEVNODE  devnode,
    DWORD  PowerState
  );

Parameters

devnode
Specifies the device node for the device.
PowerState
One of the following:

CM_POWERSTATE_D0
CM_POWERSTATE_D1
CM_POWERSTATE_D2
CM_POWERSTATE_D3

Return Value

The following values are provided.

Value | Description
CR_SUCCESS | Power state was changed successfully. No further action needs to be taken by the operating system.
CR_DEFAULT | Operating system should perform its default action for the power state transition. (That is, re-POST for D3 to D0. Otherwise, it should do nothing.) This should also be returned if PowerState is something other than one of the four CM_POWERSTATE_Dx values.


SET_MONITOR_POWER_STATE

The SET_MONITOR_POWER_STATE function places the monitor into the power state specified in the PowerState parameter. If your driver makes only a VESA call, it should simply return CR_DEFAULT and let the operating system carry out the state change.

SET_MONITOR_POWER_STATE does not need to be hooked by most display drivers. It is provided as a convenience for special cases where the miniVDD needs to do something proprietary to control the monitor's power states.

DWORD __cdecl
  SetMonitorPowerState(
    DEVNODE  devnode,
    DWORD  PowerState
  );

Parameters

devnode
Specifies the device node for the device.
PowerState
One of the following:

CM_POWERSTATE_D0
CM_POWERSTATE_D1
CM_POWERSTATE_D2
CM_POWERSTATE_D3

Return Value

The following values are provided.

Value | Description
CR_SUCCESS | Power state was changed successfully. No further action needs to be taken by the operating system.
CR_DEFAULT | Operating system should perform its default action for the power state transition (a VESA BIOS call). This should also be returned if PowerState is something other than one of the four CM_POWERSTATE_DX values.


Reference Sources

The Device Class Power Management Reference Specification for the Display Device Class, plus general information about OnNow power management can be found at http://www.microsoft.com/hwdev/onnow.htm.


Device Power Management for VxDs

This section describes the requirements and the implications for virtual device drivers (VxDs) in an OnNow power-managed system. Preliminary descriptions of the driver interfaces are presented.

The OnNow design initiative aims to make desktop computers more convenient to access and more energy-efficient by integrating fundamental power management capabilities with the users' environment. The OnNow architecture provides a fully integrated power management system. This system defines what is required so the various components of the computer work together to deliver consistent, intuitive, and effective power management to the user.

OnNow defines power management requirements for device and system hardware to implement power states and controls, for applications to participate in system power management, and for the operating system to direct power management and provide the necessary interfaces. The device driver is the key component where the hardware and software come together to produce energy savings and intuitive system behavior.

Microsoft designed support for OnNow power management in VxDs. It is the responsibility of driver writers to implement power management support in their VxDs.

In Windows® 98, the configuration manager provides services and sends messages that VxDs use to participate in the device and system power management schemes defined by the OnNow initiative.

VxDs listen for messages and call services in order to accomplish tasks such as supplying device capabilities for power management, switching a device to a low power state, and turning on a device.

A reference to all the configuration manager power management services and messages is also previewed in this section.

Important The configuration manager services and messages documented in this section are still under development and any service or message described in this section may change.


Device Power Management

Devices that are not in use should be put into low power states to conserve power. Under OnNow, the responsibility for managing power to devices is divided into three parts:

  • Policy Owners decide when a device should switch power states.
  • Device Drivers save and restore any hardware context lost by switching to a low power state.
  • Bus Drivers use standard interfaces to signal hardware to switch to a low power state and possibly remove power from the device. This includes the Advanced Configuration and Power Interface (ACPI) driver.

The following topics describe the roles of policy owners, device drivers, and bus drivers in device power management.


Power Management Policies

OnNow determines when to switch power states based on the activity of devices. The policy owner for a given device class may be any where in the operating system or device driver stack. Most of the time, this is the device driver because it knows if the device has any open handles. If the device does have any open handles, it should be on. To be most effective, the owner must be the code that has the most knowledge regarding when a device is needed.

The power policies for audio, communications, display, input, network, PC Card, and storage device classes are in the Device Power Management specifications available on http://www.microsoft.com/hwdev/onnow.htm


Implementing Power Management Policies

The following topics describe how to manage power to a device once the decision has been made to change its power state.

Implementing the policy can be as simple as a few lines of code. For example, in the OEM Service Release 2 (OSR2) release of Windows® 98, VCOMM is the power management policy owner for COM ports. When an application opens a COM port, VCOMM calls the configuration manager to turn on the COM port. When an application closes the COM port, VCOMM calls configuration manager to turn off the COM port.


Determining Device Capabilities for Power Management

Before managing the power to a device, the policy owner and device driver need to determine which power states the platform supports. The hardware and the software (device driver) each have their own capabilities. To determine which power states the platform supports, the device driver must determine the capabilities of the hardware and then merge those capabilities with its own.

Device drivers can determine the supported power states using the following procedure:

When the bus driver creates a device node, it interrogates the hardware for its capabilities using industry standard mechanisms and sets those capabilities using the configuration manager service Set_DevNode_PowerCapabilities.

Note Prior to this, the configuration manager initializes the capabilities to indicate that only D0 is supported.

When loading, a driver (and policy holder) should decide which power states can be used on a system.

The ACPI driver listens for the new device's CONFIG_START message and may add additional capabilities to the new device node.

When the device driver receives a CONFIG_START message, it calls the configuration manager service Get_DevNode_PowerCapabilities to determine which capabilities the hardware supports.

The device driver takes the result of Get_DevNode_PowerCapabilities, combines this with its own capabilities, and then calls Set_DevNode_PowerCapabilities to store the combined capabilities in the device node.

In summary, bus drivers call Set_DevNode_PowerCapabilities to set the initial capabilities when they create a device node. After loading, device drivers call Get_DevNode_PowerCapabilities, combine the resulting capabilities with the capabilities of the driver, and call Set_DevNode_PowerCapabilities with the final set of capabilities.


Switching to Low Power State

When the policy owner decides to put a device in a low power state, the following actions occur:

The policy owner calls the configuration manager service Set_DevNode_PowerState on the target device and tells it to go into one of the following low power states:

CM_POWERSTATE_D1
CM_POWERSTATE_D2
CM_POWERSTATE_D3

If any child devices are in a higher power state than the target's power state, the configuration manager sends those devices a message CONFIG_SET_POWERSTATE_Dx, where x indicates the target device's power state. .

In response to the Set_DevNode_PowerState call, the configuration manager sends a CONFIG_SET_POWERSTATE_Dx message to the driver (where x = the power state to go into).

Note The configuration manager never sends CONFIG_SET_POWERSTATE_Dx for a power state that is not supported, according to the device's current capabilities mask. Instead, the configuration manager calls the driver with the next highest power state supported in the capabilities mask.

The device driver saves any hardware context that it needs to later restore the device to D0. If any proprietary commands are required to put the device in the low power state and these commands are not offered by bus standards, the device driver can send the proprietary commands at this time.

The configuration manager sends a CONFIG_SET_POWERSTATE_Dx message for the target device to the device's parent drivers (in sequence from the device toward the root) to allow the parent drivers to signal hardware to go into the target low power state.

In summary, the policy holder calls Set_DevNode_PowerState to set the device's power state. The driver handles CONFIG_SET_POWERSTATE_Dx messages and saves device context.


Turning on a Device

When the policy owner or device driver decides to turn on a device, the following actions occur

  1. The policy owner or device driver calls the configuration manager service Set_DevNode_PowerState specifying CM_POWERSTATE_D0 for the device node associated with the target device.
  2. If any parent devices are not in the D0 state, the configuration manager sends CONFIG_SET_POWERSTATE_D0 messages to those devices to turn them on.
  3. The configuration manager sends a CONFIG_SET_POWERSTATE_D0 message for the target device to parent drivers (in sequence from the root toward the target driver) to allow the parent drivers to signal hardware to turn on.
  4. The configuration manager sends a CONFIG_SET_POWERSTATE_D0 message to the device driver.
  5. The driver restores any hardware context needed to completely restore the device to D0. If any proprietary commands not handled by bus standards are required to turn on the device , the device driver can send them at this time.

In summary, the policy holder or device driver calls Set_DevNode_PowerState to turn on the device. The driver handles CONFIG_SET_POWERSTATE_D0 messages and restores device context.


System Power Management

Computers can be put into low power sleep states in response to a user command, or when the computer has been idle for some period of time. When a computer goes into a system sleeping state, most of the devices in the computer must either be turned off or put in a low power state. Devices go into low power states using the process described in Switching to Low Power State.

The following topics describe the processes used for system power management.


System Sleep States and Device Drivers

From the device driver's perspective, the operating system puts the computer into a sleeping state in the following stages:

  • Query Phase

    The configuration manager asks each driver whether it can go to sleep.

  • Sleep Phase

    The configuration manager tells each driver to go into a low power state.

  • Signal Hardware

    The ACPI driver or the Advanced Power Management (APM) driver signals the core logic to go to sleep.


Query Phase

During the query phase, the configuration manager interrogates each currently loaded device driver to determine whether its device can be turned off (or put into some other low power state).

The configuration manager queries each driver (in sequence from children toward the root) by sending a CONFIG_TEST_SET_POWERSTATE_Dx message. The configuration manager determines which power state to use (x = 1, 2, or 3) by looking at the capabilities for each device.

If the device is enabled for wake up, the configuration manager attempts to put the device in the lowest power state from which the device can support wake up.

If the device is not enabled for wake up, the configuration manager puts the device in the lowest power state that the device supports.

Upon receiving a CONFIG_TEST_SET_POWERSTATE_Dx message, each driver determines whether it can go into a system sleep state and returns success or failure accordingly.

Devices should only fail this query if user data loss will occur when the system goes to sleep.

If a driver returns success, it must stop any activity on the device that would prevent the machine from going to sleep (any activity that would cause the driver to report failure to a CONFIG_TEST_SET_POWERSTATE_Dx message).

If any device driver fails a query, the configuration manager attempts higher device power states (which may require higher system power states) until it finds a state that works, or it runs out of states. If the configuration manager runs out of power states, it gives up and sends a CONFIG_TEST_SET_POWERSTATE_Dx_FAILED message to inform drivers that the system is not going to sleep. When drivers receive this message, they can resume normal activity.


Sleep Phase

During the sleep phase, the configuration manager tells each loaded device driver to put its child devices into low power states.

The configuration manager calls each driver (in sequence from children toward the root) with a CONFIG_SET_POWERSTATE_Dx message corresponding to the CONFIG_TEST_SET_POWERSTATE_Dx message which the driver responded to successfully.

Upon receiving a CONFIG_SET_POWERSTATE_Dx message, each driver saves hardware context, as described in Switching to Low Power State.

In summary, device drivers must listen for and respond to CONFIG_TEST_SET_POWERSTATE_Dx messages. Device drivers must listen for CONFIG_SET_POWERSTATE_Dx messages and call the configuration manager Set_DevNode_PowerState service to put their devices into the correct power state. (For more information, see Switching to Low Power State.)


System Wake Up and Device Drivers

From the device driver's perspective, the operating system wakes the machine in one pass, as follows:

  • The configuration manager calls each driver (in sequence from the root to children) with CONFIG_APM_RESUME_SUSPEND or CONFIG_APM _RESUME_CRITICAL.
  • CONFIG_APM_RESUME_CRITICAL is sent when the system is waking from an emergency sleep (one in which the drivers were not told the system was sleeping). A power failure is one possible cause of an emergency sleep.
  • CONFIG_APM_RESUME_SUSPEND is sent when the system is waking normally.

Upon receiving one of these messages, the driver may turn on the device. The driver should wait until the device needs to be turned on according to its power policy.

Bus drivers put their buses in a power state that is high enough to detect device insertions and removals. Bus drivers do not automatically perform re-enumeration at this time. If re-enumeration is required, the configuration manager sends a CONFIG_ENUMERATE message.

In summary, device drivers must listen for CONFIG_APM_RESUME_SUSPEND and CONFIG_APM _RESUME_CRITICAL and turn on their devices as needed.


Wake-Up Devices

Some devices can wake the system in response to some event. By default, this wake-up feature is disabled in each device until an application requests it. The following topics are discussed in this section:

Enabling Wake Up

System Sleep States and Devices with Wake Up Enabled

Signaling System Wake Up


Enabling Wake Up

Applications can request that devices wake the machine by calling the RequestDeviceWakeup Win32 function, which calls the configuration manager Enable_DevNode_Wakeup service, as follows

  1. The component that wants to enable wake up on a device calls Enable_DevNode_Wakeup.
  2. The configuration manager sets a flag in the device node to indicate that the device associated with the device node is enabled for wake up.
  3. The configuration manager then sends a CONFIG_ENABLE_WAKEUP message to the device driver.
  4. Upon receiving the CONFIG_ENABLE_WAKEUP message, the device driver can prepare any internal status it needs in order to enable wake up.

The process for disabling wake up is similar to the preceding. A system component calls Disable_DevNode_Wakeup, which results in a CONFIG_DISABLE_WAKEUP message being sent to the device driver.

In summary, components that want to enable device wake up should call Enable_DevNode_Wakeup. Device drivers that support wake up must listen for and handle CONFIG_ENABLE_WAKEUP and CONFIG_DISABLE_WAKEUP messages.


System Sleep States and Devices with Wake Up Enabled

The system sleep process proceeds exactly as described in System Sleep States and Device Drivers. The configuration manager determines that the device supports wake up and uses low power states that support wake up. When going to sleep, a device driver that has wake up enabled should set any registers in its device that are needed to enable wake up in the hardware, and then put itself in the lowest power state that supports wake up.

Bus drivers that have a wake-up device enabled on their bus are themselves a wake-up device. They set themselves in the lowest power state that supports wake up.

In this manner, all the various device states required for enabled wake-up devices to wake the computer are set.


Signaling System Wake Up

When the system wakes, the configuration manager and device drivers work together to determine the source of the wake up as follows

  1. When a bus driver finds that its bus is signaling wake up (either by hardware mechanisms or by receiving a CONFIG_WAKEUP message itself), it uses the mechanisms defined in the standard for that type of bus to determine which children are signaling wake up.
  2. For each child device that is signaling wake up, the bus driver calls the configuration manager service Device_Wakeup.
  3. The configuration manager then sends a CONFIG_WAKEUP message to the device.
  4. Upon receiving a CONFIG_WAKEUP message, the device driver begins handling the wake-up event. This may require turning the device on by calling the configuration manager Set_DevNode_PowerState service. If the device driver is a bus driver, it should repeat the process at step 1.

In summary, at system wake up, bus drivers call Device_Wakeup on any of their children that are signaling wake up. Device and bus drivers must listen and handle CONFIG_WAKEUP messages.


Bus Drivers

The preceding topics describe how to perform device and system power management. Bus drivers have some additional steps, as described in this topic, that they should take to enable the power management architecture to function. The following topics are discussed:

Creating Device Nodes

Handling CONFIG_START Messages

Bus Power Policy

Handling System Wake Events

ACPI Driver Responsibilities


Creating Device Nodes

When a bus driver creates a device node, it must use the bus standards to determine the power capabilities of the new device and set the capabilities in the device node using the configuration manager Set_DevNode_PowerCapabilities service.


Handling CONFIG_START Messages

When the bus driver receives a CONFIG_START message for itself, it must call Set_DevNode_PowerState on itself to supply enough power to the bus to enumerate devices.


Bus Power Policy

The power policy for most buses is the same: the bus will be in the same power state as the highest power state of its children. For example, if all the devices on a bus are in either D2 or D3, the bus can be put in D2.

Because most buses can be handled in the same manner, the configuration manager automatically handles this policy as follows

  1. After putting a device in a low power state, the configuration manager automatically puts the bus in a power state that matches the highest of the power states set for the devices on that bus.
  2. Before turning on a device, the configuration manager automatically turns on the bus that the device is attached to, if not already on.

Note that this policy does not work for all buses. For example, the Personal Computer Memory Card International Association (PCMCIA) bus should not be turned off when its devices have all reached the D3 state. Doing so would prevent the hardware from detecting new devices that have been added.


Handling System Wake Events

When bus drivers receive a CONFIG_RESUME_SUSPEND message, they must put their buses into the lowest power state needed to detect insertions and removals. Bus drivers must not do any re-enumeration at this time. If re-enumeration is needed, the configuration manager sends a CONFIG_ENUMERATE message.


ACPI Driver Responsibilities

Since the Advanced Configuration and Power Interface (ACPI) driver is the parent of all other devices in the system, as well as the motherboard driver, there are additional actions it must take:

At every system wake, the ACPI driver must check the ACPI general-purpose status (GP_STS) bits for any wake-up device and call the configuration manager Device_Wakeup service accordingly.

The ACPI driver must listen to CONFIG_START messages for any device in the system. If the ACPI driver has information about that device, it must update the capabilities bitmap by calling Get_DevNode_PowerCapabilities, adding additional capabilities, and calling Set_DevNode_PowerCapabilities to set the device node's capabilities.

The ACPI driver must also provide the system power with a state-to-device power state mapping table for any devices it controls by calling Set_DevNode_PowerStateTable. (Bus drivers other than the ACPI driver do not need to handle this table because the configuration manager copies the parent's table to a new device node by default).

When the ACPI driver receives a CONFIG_START message for any device configured using ACPI, the driver must first power on the device before running any Plug and Play control methods.


Configuration Manager Power Management Services

Device drivers can call a number of configuration manager power management services. These services are discussed in the following topics:

Getting and Setting Power Capabilities

Getting and Setting Power State

Enabling, Disabling, and Signaling Device Wake Up

Enabling Idle Detection


Getting and Setting Power Capabilities

Drivers can get and set power capabilities of their device using the following configuration manager services:

Get_DevNode_PowerCapabilities

Set_DevNode_PowerCapabilities

Set_DevNode_PowerStateTable


Get_DevNode_PowerCapabilities

Device drivers call the Get_DevNode_PowerCapabilities service to determine the capabilities mask for their device. Initially, this mask is set to the capabilities as reported by the hardware using standard mechanisms. That is, the mechanisms used by the device driver's parent drivers.

CONFIGRET
  CONFIGMG_Get_DevNode_PowerCapabilities(
    DEVNODE  dnDevNode,
    PFARULONG  pulPowerCapabilities,
    ULONG  ulFlags
    );

Parameters

dnDevNode
Handle to the device node from which to get the capabilities.
pulPowerCapabilities
Pointer to a ULONG that receives the device's capabilities. Pointer must be one of the following values as defined in configmg.h.
Flag | Meaning
CM_POWERSTATE_D0 | Device supports the D0 state.
CM_POWERSTATE_D1 | Device supports the D1 state.
CM_POWERSTATE_D2 | Device supports the D2 state.
CM_POWERSTATE_D3 | Device supports the D3 state.

ulFlags
Flags indicating the power capabilities for the device. Must be one of the following:
Flag | Meaning
CM_CAPABILITIES_NORMAL | Capabilities evoked normally (default)
CM_CAPABILITIES_FOR_WAKEUP | Capabilities evoked on device power wake up


Set_DevNode_PowerCapabilities

Device drivers call the Set_DevNode_PowerCapabilities service to set the capabilities mask for their device after combining the capabilities of the device with that of the hardware (originally found by calling Get_DevNode_PowerCapabilities).

CONFIGRET
  CONFIGMG_Set_DevNode_PowerCapabilities(
    DEVNODE  dnDevNode,
    ULONG  ulPowerCapabilities,
    ULONG  ulFlags
    );

Parameters

dnDevNode
Handle to the device node from which to get the capabilities.
ulPowerCapabilities
Pointer to a ULONG that receives the device's capabilities. Pointer ust be one of the following values as defined in configmg.h.
Flag | Meaning
CM_POWERSTATE_D0 | Device supports the D0 state.
CM_POWERSTATE_D1 | Device supports the D1 state.
CM_POWERSTATE_D2 | Device supports the D2 state.
CM_POWERSTATE_D3 | Device supports the D3 state.

ulFlags
Flags indicating the power capabilities for the device. Must be one of the following.
Flag | Meaning
CM_CAPABILITIES_NORMAL | Capabilities usually evoked (default).
CM_CAPABILITIES_FOR_WAKEUP | Capabilities evoked on device power wake up.

Note New power capabilities are only accepted for a device the first time CONFIGMG_Set_DevNode_PowerCapabilities is called for a given devnode. Subsequent calls result in a logical AND of ulPowerCapabilities with the device's prior power capabilities. This means subsequent calls can only remove power capabilities.


Getting and Setting Power State

Drivers can get and set the current power state of their device using the following configuration manager services:

Get_DevNode_PowerState

Set_DevNode_PowerState


Get_DevNode_PowerState

Device drivers call the Get_DevNode_PowerState service to get the current power state of a device.

CONFIGRET
  CONFIGMG_Get_DevNode_PowerState(
    DEVNODE  dnDevNode,
    PFARULONG  pulPowerState,
    ULONG  ulFlags
    );

Parameters

dnDevNode
Handle to the device node from which the configuration manager returns the current power state.
pulPowerState
Pointer to a ULONG that receives the device's power state. The result is one of the following:

CM_POWERSTATE_D0
CM_POWERSTATE_D1
CM_POWERSTATE_D2
CM_POWERSTATE_D3

ulFlags
Reserved. Currently must be zero.


Set_DevNode_PowerState

Device drivers and policy owners call the Set_DevNode_PowerState service to set the power state of a device.

CONFIGRET
  CONFIGMG_Set_DevNode_PowerState(
    DEVNODE  dnDevNode,
    ULONG  ulPowerState,
    ULONG  ulFlags
    );

Parameters

dnDevNode
Handle to the device node in which the configuration manager sets the current power state.
ulPowerState
Power state to set. Must be one of the following:

CM_POWERSTATE_D0
CM_POWERSTATE_D1
CM_POWERSTATE_D2
CM_POWERSTATE_D3

ulFlags
Reserved. Currently must be zero.

Comments

Device drivers and policy owners call the Set_DevNode_PowerState service to set the power state of a device. When it receives this request, the configuration manager synchronizes it with other requests that may be going on in the system and sends an appropriate CONFIG_SET_POWERSTATE_Dx message to the device driver and all the device driver's parent drivers.

If the requested power state is lower than the current power state, the configuration manager sends the message in order from the target device toward the root. If any child devices are in a higher power state than the target state, the configuration manager puts those devices in the target power state before setting the power state of the target device.

If the target power state is higher than the current state, the configuration manager sends the message in order from the root toward the target device. If any parent devices are in a power state that is lower than the target state, the configuration manager puts those devices in the target power state before setting the power state of the target device.


Enabling, Disabling, and Signaling Device Wake Up

Device drivers can call the following services to manage device wake up:

Disable_DevNode_Wakeup

Enable_DevNode_Wakeup

Device_Wakeup


Disable_DevNode_Wakeup

Components that want to disable wake up on a device call the Disable_DevNode_Wakeup service. Calling this service causes the configuration manager to clear the flag in the device node to indicate that the device is enabled for wake up and to send a CONFIG_DISABLEWAKEUP message to the device.

CONFIGRET
  CONFIGMG_Disable_DevNode_Wakeup(
    DEVNODE  dnDevNode,
    ULONG  ulFlags
    );

Parameters

dnDevNode
Handle to the device node in which the configuration manager disables wake up.
ulFlags
Reserved. Currently must be zero.


Enable_DevNode_Wakeup

Components that want to enable wake up on a device call the Enable_DevNode_Wakeup service. This service causes the configuration manager to set a flag in the device node to indicate that the device is enabled for wake up and to send a CONFIG_ENABLEWAKEUP message to the device. The configuration manager returns failure if the device does not support wake up.

CONFIGRET
  CONFIGMG_Enable_DevNode_Wakeup(
    DEVNODE  dnDevNode,
    ULONG  ulFlags
    );

Parameters

dnDevNode
Handle to the device node in which the configuration manager enables wake up.
ulFlags
Reserved. Currently must be zero.


Device_Wakeup

Device drivers call the Device_Wakeup service for each child device that is signaling wake up. The configuration manager sends a CONFIG_APM_WAKEUP message to the child device driver to inform the driver that the device needs to handle the wake up event.

CONFIGRET
  CONFIGMG_Device_Wakeup(
    DEVNODE  dnDevNode,
    ULONG  ulFlags
    );

Parameters

dnDevNode
Handle to the device node that identifies the driver to which the configuration manager sends the CONFIG_APM_WAKEUP message.
ulFlags
Reserved. Currently must be zero.


Enabling Idle Detection

Drivers can use the configuration manager Register_DevNode_For_Idle_Detection service to have the configuration manager automatically detect idle child devices of the driver.


Register_DevNode_For_Idle_Detection

Device drivers can register to have the configuration manager automatically send the driver a CONFIG_SET_POWERSTATE_Dx message after some period of inactivity on a child device. Device drivers indicate activity by periodically clearing the counter pointed to by pulCounterVariable.

CONFIGRET
  CONFIGMG_Register_DevNode_For_Idle_Detection(
    DEVNODE  dnDevNode,
    ULONG  ulConservationTime,
    ULONG  ulPerformanceTime,
    PFARULONG  pulCounterVariable,
    ULONG  ulState,
    ULONG  ulFlags
    );

Parameters

dnDevNode
Handle to the device node that identifies the driver to which the configuration manager sets idle detection.
ulConservationTime
Time-out (in seconds) to be used when the system is optimizing for power consumption.
ulPerformanceTime
Time-out (in seconds) to be used when the system is optimizing for performance.
pulCounterVariable
Pointer to a ULONG to hold the timer counter.
ulState
Power state to go into when the time-out threshold is reached.
ulFlags
Reserved. Currently must be zero.


Configuration Manager Power Management Messages

The configuration manager can send three types of power management messages to device drivers and/or bus drivers:

System Power Management Messages

Device Power Management Messages

Device Wake-Up Messages


System Power Management Messages

The configuration manager can send the following system power messages:

CONFIG_TEST_ SET_POWERSTATE_Dx

CONFIG_TEST_SET_POWERSTATE_Dx_FAILED

CONFIG_APM_RESUME_CRITICAL

CONFIG_APM_RESUME_SUSPEND


CONFIG_TEST_ SET_POWERSTATE_Dx

The configuration manager sends the CONFIG_TEST_ SET_POWERSTATE_D message to a device driver when the system goes to sleep to ask whether the device can go to sleep. Device drivers should return with success if the system can go to sleep, and return with failure if it cannot. Devices should fail this query only if user data loss will occur if the system goes to sleep.

If a driver returns success, it must stop any activity on the device that would prevent the system from going to sleep. That is, any activity that would cause the driver to return failure.


CONFIG_TEST_SET_POWERSTATE_Dx_FAILED

The configuration manager sends the CONFIG_TEST_SET_POWERSTATE_Dx_FAILED message to device drivers to indicate that the system is not going to sleep.


CONFIG_APM_RESUME_CRITICAL and CONFIG_APM_RESUME_SUSPEND

The configuration manager sends the CONFIG_APM_RESUME_CRITICAL and CONFIG_APM_RESUME_SUSPEND messages to inform device drivers and bus drivers that the system has awakened.

The CONFIG_APM_RESUME_SUSPEND message is sent when the system is waking normally. CONFIG_APM _RESUME_CRITICAL is sent when the system is waking after an emergency sleep in which the drivers were not told the system was sleeping (for example, due to power failure).

Device drivers should do nothing and wait until the device needs to be turned on according to its power policy.

Bus drivers should put their buses in a power state that is high enough to detect device insertions and removals. This may require turning on the bus (with Set_DevNode_PowerState) and doing a re-enumeration.


Device Power Management Messages

The configuration manager sends CONFIG_SET_POWERSTATE_Dx messages to tell the driver to enter a particular device power state.


CONFIG_SET_POWERSTATE_D0

The configuration manager sends the CONFIG_SET_POWERSTATE_D0 message to a device driver to tell it to switch to the D0 (fully on) power state. By the time the device driver receives this message, its parent drivers have already been sent the message and signaled the physical hardware to turn on.

When the device driver receives this message, it must restore any hardware context needed to completely restore the device to D0. If any proprietary commands are required to turn on the device and they are not handled by bus standards, the device driver can send them at this time.


CONFIG_SET_POWERSTATE_D1, CONFIG_SET_POWERSTATE_D2, and CONFIG_SET_POWERSTATE_D3

The configuration manager sends the CONFIG_SET_POWERSTATE_D1, CONFIG_SET_POWERSTATE_D2, and CONFIG_SET_POWERSTATE_D3 messages to a device driver to tell it to switch to a low power state. After the device driver completes this message, the configuration manager sends this message to the device driver's parent drivers so they can signal the physical hardware to go into the specified low power state and possibly remove power from the device.

The configuration manager never sends CONFIG_SET_POWERSTATE_Dx for a power state not supported according to the device's current capabilities mask. Instead, the configuration manager calls the driver with the next highest power state supported in the capabilities mask.


Device Wake-up Messages

The configuration manager can send the following messages to manage device wake up:

CONFIG_DISABLEWAKEUP

CONFIG_ENABLEWAKEUP

CONFIG_WAKEUP


CONFIG_DISABLEWAKEUP

The configuration manager sends CONFIG_ENABLE_WAKEUP to indicate to the device driver that it is no longer enabled for wake up. The device driver can return to its normal mode of operation.


CONFIG_ENABLEWAKEUP

The configuration manager sends CONFIG_ENABLE_WAKEUP to indicate to the device driver that it is enabled for wake up. The device driver can prepare any internal status it needs in order to enable wake up.


CONFIG_WAKEUP

The configuration manager sends CONFIG_WAKEUP to a driver to indicate that its device is signaling wake up. Upon receiving this message, the device driver can begin handling the wake up event. This may require turning the device on by calling Set_DevNode_PowerState. If the device driver is a bus driver, it should check to see whether its children are signaling wake up and, if so, call Device_Wakeup accordingly.


Backward Compatibility of Power Management Messages

For compatibility with Windows 98 drivers, some of the preceding messages are defined to be the same as older messages.

#define CONFIG_SET_POWERSTATE_D1                CONFIG_APM_STANDBY
#define CONFIG_SET_POWERSTATE_D2                CONFIG_APM_SUSPEND
#define CONFIG_TEST_SET_POWERSTATE_D1           CONFIG_APM_TEST_STANDBY
#define CONFIG_TEST_SET_POWERSTATE_D2           CONFIG_APM_TEST_SUSPEND
#define CONFIG_TEST_SET_POWERSTATE_D1_FAILED    CONFIG_APM_TEST_STANDBY_FAILED
#define CONFIG_TEST_SET_POWERSTATE_D2_FAILED    CONFIG_APM_TEST_SUSPEND_FAILED


TCP/IP VxD Interface

The interface to the Microsoft® TCP/IP-32 VxD is a variant of the Transport Device Interface (TDI) defined for Microsoft® Windows NT®/Windows® 2000. The primary difference between the two interfaces is that under Windows NT/Windows 2000, requests are made using IRPs, while in the VxD environment requests are made by pushing parameters on the stack and calling a function indirectly through a pointer. The primitives in the interface are substantially the same.

This documentation summarizes the differences, though minor, between the two environments and describes the VxD calling conventions.

This documentation also assumes that the reader has a basic familiarity with VxD programming issues such as VxD services and the use of the VMM. For information on these topics, refer to the Windows 3.1 DDK documentation.

The following topics are provided:

Structures

Binding with the MS TCP/IP-32 VxD

Communication Using the TDI interface

Descriptions of TDI Functions


Structures

There are several structures used on the interface. Some of the more important ones are described in this documentation:

TDI_REQUEST

NDIS_BUFFER

TRANSPORT_ADDRESS

TA_ADDRESS

TDI_ADDRESS_IP

TDI_CONNECTION_INFORMATION

EventRcvBuffer

ConnectEventInfo

TdiDispatchTable

The following typedefs are used:

typedef unsigned long ulong;
typedef unsigned short ushort;
typedef unsigned char uchar;
typedef unsigned int uint;
typedef void    (*CTEReqCmpltRtn)(void *Context, TDI_STATUS FinalStatus, uint ByteCount);


TDI_REQUEST

The TDI_REQUEST structure is defined in the file TDI.H.

typedef struct _TDI_REQUEST {
  union {
  HANDLE  AddressHandle;
  CONNECTION_CONTEXT  ConnectionContext;
  HANDLE  ControlChannel;
  } Handle;
  PVOID  RequestNotifyObject;
  PVOID  RequestContext;
  TDI_STATUS  TdiStatus;
} TDI_REQUEST, *PTDI_REQUEST;

Comments

A pointer to a TDI_REQUEST structure is passed into every VxD TDI call. The VxD TDI client must fill in the structure before invoking the VxD. The handle field will contain either an address object handle or a connection context, depending on the call. The RequestNotifyObject field is set to be a pointer to a client-supplied callback function that TCP will call when the request finally completes, if and only if the request returned TDI_PENDING when it was first invoked. Note that a callback can happen before the call to the function returns. The RequestContext field will be passed back unchanged as a parameter to the callback function when it is called. The TdiStatus field is unused.

Following is the prototype for the callback function:

void
  Callback(
    PVOID  Context,
    TDI_STATUS  FinalStatus,
    unsigned long  ByteCount
    );

Parmeters

Context
RequestContext originally specified by the client in the TDI_REQUEST.
FinalStatus
Completion status of the command.
ByteCount
Number of bytes sent or received. This final parameter is unused for some commands. The type CTEReqCmpltRtn is defined as a pointer to a callback routine.

Comments

TDI_REQUEST structures are ephemeral. The VxD will copy any needed information out of them before the initial invocation completes, and the client may reuse them immediately.


NDIS_BUFFER

The NDIS_BUFFER structure is defined in NDIS.H. In Windows NT/Windows 2000, NDIS_BUFFER structures are MDLs, but in the VxD environment, they are essentially buffer descriptors consisting of a length, pointer, and a next field. Chains of NDIS_BUFFER structures may be used to pass in scatter/gather lists of buffers for sending and receiving. NDIS_BUFFER chains must be NULL terminated. Both the NDIS_BUFFER structure itself and the buffer pointed to by the NDIS_BUFFER structure must be locked down and validated before being passed to the transport. VxD TDI clients may use the macros and functions for managing buffers provided by the NDIS wrapper (ndis.386) and described in the NDIS 3.0 specification, or they may create and initialize NDIS_BUFFER structures themselves. NDIS_BUFFER chains submitted to the transport must not be altered while the request with which they were submitted is outstanding.


TRANSPORT_ADDRESS

The TRANSPORT_ADDRESS structure is used for describing transport addresses passed to the VxD transport. It is defined in TDI.H.

typedef struct _TRANSPORT_ADDRESS {
  LONG  TAAddressCount;
  TA_ADDRESS  Address[1];
} TRANSPORT_ADDRESS, *PTRANSPORT_ADDRESS;

Members

TAAddressCount
Number of addresses available.
Address[1]
Actual number of TAAddressCount elements.

Comments

A TRANSPORT_ADDRESS is a counted array of TA_ADDRESSs. Each TA_ADDRESS describes one address.


TA_ADDRESS

The TA_ADDRESS structure is used for describing transport addresses passed to the VxD transport. It is defined in TDI.H.

typedef struct _TA_ADDRESS {
  USHORT  AddressLength;  // length in bytes of Address[] in this
  USHORT  AddressType;  // type of this address
  UCHAR  Address[1];  // actually AddressLength bytes long
} TA_ADDRESS, *PTA_ADDRESS;

Members

AddressLength
Length in bytes of Address[1].
AddressType
Type of this address.
Address[1]
Length in bytes of AddressLength.

Comments

For the TCP VxD, the AddressType field should be TDI_ADDRESS_IP, which is defined in TDI.H.

#define TDI_ADDRESS_TYPE_IP        ((USHORT)2)  // internetwork: UDP, TCP, etc.

Then, the AddressLength field of the TA_ADDRESS should be set to TDI_ADDRESS_LENGTH_IP, and the Address field is a structure of type TDI_ADDRESS_IP.


TDI_ADDRESS_IP

The TDI_ADDRESS_IP structure is defined in TDI.H.

typedef struct _TDI_ADDRESS_IP {
  USHORT  sin_port;
  ULONG  in_addr;
  UCHAR  sin_zero[8];
} TDI_ADDRESS_IP, *PTDI_ADDRESS_IP;
#define TDI_ADDRESS_LENGTH_IP sizeof (TDI_ADDRESS_IP)

Comments

The TDI_ADDRESS_IP structure is similar to the sockaddr structure used in Windows Sockets.


TDI_CONNECTION_INFORMATION

A TDI_CONNECTION_INFORMATION structure is used for passing in and out information used for establishing connections. They are not copied by the transport and must be preserved intact until the request with which they are issued completes. This structure is defined in TDI.H.

typedef struct _TDI_CONNECTION_INFORMATION {
  LONG  UserDataLength;
  PVOID  UserData;
  LONG  OptionsLength;
  PVOID  Options
  LONG  RemoteAddressLength;
  PVOID  RemoteAddress;
} TDI_CONNECTION_INFORMATION, *PTDI_CONNECTION_INFORMATION;

Members

UserDataLength
Reserved. Do not use.
UserData
Reserved. Do not use.
OptionsLength
Length of the buffer containing IP options. If there are no options, this must be set to zero.
Options
Pointer to a buffer containing IP options. If there are no options, this must be set to NULL.
RemoteAddressLength
Length of the TRANSPORT_ADDRESS structure.
RemoteAddress
Pointer to the TRANSPORT_ADDRESS structure.


EventRcvBuffer

An EventRcvBuffer is a structure used to pass information about buffers and completion routines for data delivered through a receive indication. A pointer to an EventRcvBuffer (ERB) structure is passed to the client as a parameter to the indication routine. The client may elect to fill in the ERB with the appropriate information and return TDI_MORE_PROCESSING. In this case, the transport will examine the ERB and take the appropriate actions. The EventRcvBuffer structure is defined in TDIVXD.H.

typedef struct EventRcvBuffer {
  PNDIS_BUFFER  erb_buffer;
  uint  erb_size;
  CTEReqCmpltRtn  erb_rtn;
  PVOID  erb_context;
  ushort  *erb_flags;
} EventRcvBuffer;

Members

erb_buffer
Pointer to an NDIS_BUFFER chain describing the buffers that the received data will be placed in.
erb_size
Maximum amount of data that may be copied into the buffer chain. The total of the sizes of all the NDIS_BUFFER structures in the chain must be greater than or equal to erb_size. If the total is greater than erb_size, only erb_size bytes will be copied. The NDIS_BUFFER chain must remain intact until the request completes.
erb_rtn
Pointer to a callback routine that will be called when the request is complete. The prototype for the routine is the same as for the Callback routine previously described.
erb_context
The context passed to the callback routine.
erb_flags
Pointer to a short of flags. This will be altered by the transport when the request completes to provide the client with the output flags. The flags pointer must not be NULL.

For this release, erb_flags must point at a 16-bit value of zero. When the request completes, the flags will be set to (TDI_RECEIVE_NORMAL | TDI_RECEIVE_ENTIRE_MESSAGE) for normal data, and (TDI_RECEIVE_EXPEDITED | TDI_RECEIVE_ENTIRE_MESSAGE) for urgent data.


ConnectEventInfo

The ConnectEventInfo structure is a structure passed by the transport to the client during a connect event indication.

typedef struct ConnectEventInfo {
  CTEReqCmpltRtn  cei_rtn;
  PVOID  cei_context;
  PTDI_CONNECTION_INFORMATION  cei_acceptinfo;
  PTDI_CONNECTION_INFORMATION  cei_conninfo;
} ConnectEventInfo;

Members

cei_rtn
Pointer to a callback routine. The routine will be called when the connect completes.
cei_context
Pointers to a callback context for that routine.
cei_acceptinfo
Pointer providing information for use in accepting the connection. The only fields used in this structure are the OptionsLength and Options fields. This field may be NULL.
cei_conninfo
Points to information regarding the remote peer when the connection is complete. This field may be NULL.


TdiDispatchTable

The TdiDispatchTable is a structure that the client gets from the VTDI VxD. This structure is a table of entry points into the TCP VxD. An entry point may be called by calling indirectly through the corresponding function pointer in the TdiDispatchTable. The table is defined in TDIVXD.H.

struct TDIDispatchTable {
    TDI_STATUS    (*TdiOpenAddressEntry)(PTDI_REQUEST, PTRANSPORT_ADDRESS, uint,
                PVOID);
    TDI_STATUS    (*TdiCloseAddressEntry)(PTDI_REQUEST);
    TDI_STATUS    (*TdiOpenConnectionEntry)(PTDI_REQUEST, PVOID);
    TDI_STATUS    (*TdiCloseConnectionEntry)(PTDI_REQUEST);
    TDI_STATUS    (*TdiAssociateAddressEntry)(PTDI_REQUEST, HANDLE);
    TDI_STATUS    (*TdiDisAssociateAddressEntry)(PTDI_REQUEST);
    TDI_STATUS    (*TdiConnectEntry)(PTDI_REQUEST, PVOID,
                PTDI_CONNECTION_INFORMATION,
                PTDI_CONNECTION_INFORMATION);
    TDI_STATUS    (*TdiDisconnectEntry)(PTDI_REQUEST, PVOID, ushort,
                PTDI_CONNECTION_INFORMATION,
                PTDI_CONNECTION_INFORMATION);
    TDI_STATUS    (*TdiListenEntry)(PTDI_REQUEST, ushort,
                PTDI_CONNECTION_INFORMATION,
                PTDI_CONNECTION_INFORMATION);
    TDI_STATUS    (*TdiAcceptEntry)(PTDI_REQUEST, PTDI_CONNECTION_INFORMATION,
                PTDI_CONNECTION_INFORMATION);
    TDI_STATUS    (*TdiReceiveEntry)(PTDI_REQUEST, ushort *, uint *, PNDIS_BUFFER);
    TDI_STATUS    (*TdiSendEntry)(PTDI_REQUEST, ushort, uint, PNDIS_BUFFER);
    TDI_STATUS    (*TdiSendDatagramEntry)(PTDI_REQUEST,
                PTDI_CONNECTION_INFORMATION,
                uint, uint *, PNDIS_BUFFER);
    TDI_STATUS    (*TdiReceiveDatagramEntry)(PTDI_REQUEST,
                PTDI_CONNECTION_INFORMATION,
                PTDI_CONNECTION_INFORMATION, uint, uint *, PNDIS_BUFFER);
    TDI_STATUS    (*TdiSetEventEntry)(PVOID, int, PVOID, PVOID);
    TDI_STATUS    (*TdiQueryInformationEntry)(PTDI_REQUEST, uint,
                PNDIS_BUFFER, uint *, uint);
    TDI_STATUS    (*TdiSetInformationEntry)(PTDI_REQUEST, uint,
                PNDIS_BUFFER, uint, uint);
    TDI_STATUS    (*TdiActionEntry)(PTDI_REQUEST, uint,
                PNDIS_BUFFER, uint);
    TDI_STATUS    (*TdiQueryInformationExEntry)(PTDI_REQUEST,
                struct TDIObjectID *, PNDIS_BUFFER, uint *, void *);
    TDI_STATUS    (*TdiSetInformationExEntry)(PTDI_REQUEST,
                struct TDIObjectID *, void *, uint);
};
typedef struct TDIDispatchTable TDIDispatchTable;


Binding with the MS TCP/IP-32 VxD

In order to communicate with the TCP/IP VxD, a client must first get a pointer to the TdiDispatchTable for the VxD. This is done by communicating with the VTDI VxD. This VxD provides a service (VTDI_Get_Info) that takes in a protocol name and returns a pointer to a TdiDispatchTable. VTDI is device ID 0x488. A client VxD should call this service during Device_Init time. In order to initialize properly, a client VxD should have an initialization order of at least 0xc000 + VNETBIOS_Init_Order.

VTDI_Get_Info takes the name of the protocol VxD as a parameter on the stack (as a case-sensitive NULL-terminated ASCII string), and returns the pointer to the TdiDispatchTable in EAX. EAX will be zero if the named protocol does not exist. The name of the MS TCP/IP-32 VxD is MSTCP.

The following assembly code illustrates how to get the dispatch table:

VTDI_Device_ID    equ    0488h
include    vtdi.inc
VxD_IDATA_SEG
TCPName    db    'MSTCP', 0
VxD_IDATA_ENDS
VxD_ICODE_SEG
BeginProc GetTCPDispatchTable

; Make sure VTDI is present
    VxDcall    VTDI_Get_Version
    jc short Failure

; VTDI is present. Get a pointer to the TCP dispatch table
    push    OFFSET32 TCPName
    VxDcall    VTDI_Get_Info
    add    esp, 4

; EAX contains a pointer to the DispatchTable, or 0 if TCP isn't available.
    ret

Failure:
; VTDI isn't present.
    sub    eax, eax
    ret

EndProc GetTCPDispatchTable
VxD_ICODE_END


Communication Using the TDI Interface

Communications through TDI centers around two abstractions: the address object and the connection. An address object is the representation of a local address (IP address/port number/protocol ID). An address object is opened through the TdiOpenAddress primitive, which specifies the necessary information. The IP address specified may be zero, indicating a wildcard local address. The TdiOpenAddress call returns a HANDLE that the client uses to identify the address object in subsequent calls.

An address object may have one or more event handlers associated with it. An event handler is a client-specified routine that the TCP VxD will call when certain events occur. The most popular event handlers are connect event handlers, receive data and receive datagram event handlers, and disconnect event handlers. Connect event handlers are routines that the TCP VxD will call when an incoming connect request (a TCP frame with the SYN bit set with no ACK) is received. The client may inspect the remote address and accept or reject the connection. Receive data and datagram handlers are routines that are called when incoming data or datagrams are received. Disconnect event handlers are called when a TCP connection is being torn down, either gracefully through receipt of a FIN or abortively due to a RST or time-out. Clients specify event handlers through the TdiSetEvent primitive. More information on event handlers may be found in the Windows NT/Windows 2000 TDI documentation and in TdiSetEvent.

An address object handle is all that is needed for UDP traffic. A client may send and receive through UDP without opening a connection. Datagrams are sent with TdiSendDatagram, and may be received with either TdiReceiveDatagram or through a receive datagram event handler.

A connection represents the local side of a TCP connection. Connections are opened through TdiOpenConnection. Initially, the connection is "blank" and unassociated with any local address. Clients associate a connection with a local address through TdiAssociateAddress. This routine takes as input a connection context and an address object handle, and associates the connection with the local address represented by the address object. After this is done, a connection to a remote host may be established through TdiConnect, or the connection may be placed into the listening state through TdiListen. As an alternative to TdiListen, clients may set a connect event handler on the associated address object. This is the recommended alternative for VxD TDI clients.

After a connection is established, data may be sent with TdiSend. Data may be received with either TdiReceive or a receive data event handler. TCP connections are torn down with TdiDisconnect. This primitive specifies whether the disconnection is to be graceful or abortive. A graceful disconnect results in a FIN being sent. The disconnect will complete when this FIN is successfully acknowledged. The connection will not be completely gone until this remote peer has sent a FIN and this FIN has been successfully acknowledged. Receipt of a FIN from the remote side will result in a DisconnectWait request being complete, or a disconnect event handler being called. If there is no disconnect event handler set or DisconnectWait primitive outstanding, the client will not be notified. A client may receive a graceful disconnect notification before issuing a disconnect request.

An abortive disconnect destroys the connection immediately by sending a RST. Receiving a RST will result in a client being notified through event handler or DisconnectWait primitives.

Connections are closed through TdiCloseConnection. Closing an established connection will result in a RST being sent. Closing a connection is different from disconnecting a connection. A disconnected connection is still around, associated with an address, and may be connected again through TdiConnect. Closing a connection results in the connection object itself being destroyed.


Descriptions of TDI Functions

This section provides a description of the available TDI functions, and notes where there are differences between the VxD version and the Windows NT/Windows 2000 version. For more detailed information on these functions, refer to the Windows NT/Windows 2000 TDI documentation.

TdiOpenAddress

TdiCloseAddress

TdiOpenConnection

TdiCloseConnection

TdiAssociateAddress

TdiDisAssociateAddress

TdiConnect

TdiDisconnect

TdiListen

TdiAccept

TdiReceive

TdiSend

TdiSendDatagram

TdiReceiveDatagram

TdiSetEvent

TDI_EVENT_CONNECT

TDI_EVENT_DISCONNECT

TDI_EVENT_ERROR

TDI_EVENT_RECEIVE

TDI_EVENT_RECEIVE_DATAGRAM

TDI_EVENT_RECEIVE_EXPEDITED

TdiSetInformation

TdiActionInformation

TdiQueryInformationEx

TdiSetInformationEx

TdiSetInformationEx


TdiOpenAddress

The TdiOpenAddress function is called through the TdiOpenAddressEntry pointer in the TdiDispatchTable structure. This function is called to open an address object.

TDI_STATUS
  TdiOpenAddress(PTDI_REQUEST Request,
    TRANSPORT_ADDRESS  *AddrList,
    uint  Protocol,
    void  *Ptr
    );

Parameters

AddrList
Points to a TRANSPORT_ADDRESS structure.
Protocol
Protocol number for the protocol with which the address is to be associated. Protocol is 17 (decimal) for UDP and 6 (decimal) for TCP.
Ptr
Pointer to a byte string of options for the opening of this address object. Ptr may be NULL. The options are:
#define    TDI_OPTION_EOL            0
#define    TDI_ADDRESS_OPTION_REUSE  1
#define    TDI_ADDRESS_OPTION_DHCP   2
TDI_OPTION_EOL
Terminates the list.
TDI_ADDRESS_OPTION_REUSE
Allows the address to be reused, as in the manner of the Windows Sockets REUSE_ADDR option.
TDI_ADDRESS_OPTION_DHCP
Allows the client to override the usual interpretation of 0.0.0.0 as the wildcard address.

Comments

If the client specifies this option, then 0.0.0.0 will be the actual address transmitted. If this option is specified, then the client must specify 0.0.0.0 in the AddrList structure. If this option is not specified and the client is opening 0.0.0.0, then the open is interpreted as a wildcard open and IP will choose an appropriate IP address as needed. The address selection in this case is done on a per request basis (for example, each time a datagram send is submitted or a connection using the address object is established). TDI_ADDRESS_OPTION_DHCP is intended for use by DHCP clients. Most clients do not need to set this option.

Opening an address object with a sin_port of zero causes the transport to select an unused port. This port selection is done only once, at the time the address object is opened.

This function will return an address object handle in the Request->Handle.AddressHandle field.


TdiCloseAddress

The TdiCloseAddress function is called through the TdiCloseAddressEntry pointer in the TdiDispatchTable structure.

TDI_STATUS
  TdiCloseAddress(PTDI_REQUEST Request
    );

Comments

This function is called to close an address object. The address object to be closed is specified in the Request->Handle.AddressHandle field. Closing an address object abortively disconnects any active connections associated with the address object and disassociates all associated connections. Receive datagram requests are aborted. The request does not complete until all pending datagram sends are completed. However, no new datagram sends may be submitted after a CloseAddress request has been submitted.


TdiOpenConnection

TdiOpenConnection is called though the TdiOpenConnectionEntry pointer in the TdiDispatchTable structure. This primitive opens a connection object. The connection object is initially unassociated with an address object.

TDI_STATUS
  TdiOpenConnection(PTDI_REQUEST Request,
    PVOID  Context
    );

Parameters

Context
Context value that is passed back to the client on receive data and disconnect events. This function returns the connection handle in the Request->Handle.ConnectionContext field.


TdiCloseConnection

The TdiCloseConnection function is called through the TdiCloseConnectionEntry pointer in the TdiDispatchTable structure.

This primitive is called to close a TDI connection. The connection to be closed is specified through the Request->Handle.ConnectionContext field. If a TCP connection is active through the connection being closed, it will be abortively disconnected and a RST will be sent.

TDI_STATUS
  TdiCloseConnection(PTDI_REQUEST Request
    );


TdiAssociateAddress

The TdiAssociateAddress function is called through the TdiAssociateAddressEntry pointer in the TdiDispatchTable structure.

This primitive associates a connection object with an address object. An association must be done before a TCP connection can be established through a connection object. The connection to be associated is specified in the Request->Handle.ConnectionContext field.

TDI_STATUS
  TdiAssociateAddress(PTDI_REQUEST Request,
    HANDLE  AddrHandle
    );

Parameters

AddrHandle
Identifies the address object with which the connection is to be associated. A connection object may not be associated with an address object if it is already associated with another address object.


TdiDisAssociateAddress

The TdiDisAssociateAddress function is called through the TdiDisAssociateAddressEntry pointer in the TdiDispatchTable structure.

This is a primitive to disassociate a connection object from an address object. The connection object must not be connected to a remote peer when this primitive is called. Request->Handle.ConnectionContext identifies the connection to be disassociated.


TdiConnect

The TdiConnect function is called through the TdiConnectEntry pointer in the TdiDispatchTable structure.

This functions establishes a TCP connection through the connection object identified in Request->Handle.ConnectionContext. The connection object must be associated with an address object before calling this function.

TDI_STATUS
  TdiConnect(PTDI_REQUEST Request,
    void  *TO,
    PTDI_CONNECTION_INFORMATION  RequestAddr,
    PTDI_CONNECTION_INFORMATION  ReturnAddr
    );

Parameters

TO
Points to a time-out value indicating how long to keep trying to connect before giving up. This value must be a 32-bit unsigned integer. The units are in milliseconds. TO may be NULL, indicating that the transport is to pick a suitable time-out. Pointing TO at a value of zero is the same as setting TO to NULL.
RequestAddr
Specifies the remote address to be connected. It must specify a valid, unicast IP address. RequestAddr may also specify IP options, such as source route.
ReturnAddr
Filled in by TCP with the remote address actually connected. For TCP, this will always be the same as RequestAddr. ReturnAddr also indicates which IP options (if any) are actually in use on the established connection.


TdiDisconnect

The TdiDisconnect function is called through the TdiDisconnectEntry pointer in the TdiDispatchTable structure.

TDI_STATUS
  TdiDisconnect(PTDI_REQUEST Request,
    void  *TO,
    ushort  Flags,
    PTDI_CONNECTION_INFORMATION  DiscConnInfo,
    PTDI_CONNECTION_INFORMATION  ReturnInfo
    );

Parameters

TO
Time-out value indicating how long to wait for the disconnection to complete. It has the same semantics as the TO value for TdiConnect.
Flags
Identifies the disconnect type. It may take on one of the following values:
TDI_DISCONNECT_ABORT
Specifies that this is to be an abortive disconnect.
TDI_DISCONNECT_WAIT
Specifies that this is a disconnect wait request. This type of request results in no protocol action. The disconnect request is in a pending state until the remote peer issues a disconnect. This command may be used to receive disconnect notifications without a disconnect event handler, although the event handler approach is the recommended mechanism.

If neither of these flags is set, the disconnect is considered to be graceful.

DiscConnInfo
Unused and may be set to NULL.
ReturnInfo
Unused and may be set to NULL.

Comments

The TdiDisconnect function is called through TdiDisconnectEntry pointer in the TdiDispatchTable structure.

This is the primitive to disconnect an established connection. The connection to be disconnected is specified through Request->Handle.ConnectionContext. A connection may be abortively or gracefully disconnected. An abortive disconnect results in a RST being sent. A graceful disconnect results in a FIN being sent, and the graceful disconnect will not complete until the FIN is successfully acknowledged. or the disconnect times out.

If a connection is being gracefully disconnected, the disconnection is not complete until both sides have disconnected. A client may be notified of the remote peers disconnect through a DisconnectWait request or a disconnect event notification. After a client has been notified that the remote side has disconnected and had a graceful disconnect of its own complete, the connection is gone. An abortive disconnect, however, is unilateral. Once either side has issued an abortive disconnect, the connection is terminated.

A disconnect results in all outstanding requests on the connection completing. A graceful disconnect does not complete until all outstanding send requests have been sent and acknowledged, or until the disconnect time-out occurs.


TdiListen

The TdiListen is called through the TdiListenEntry pointer in the TdiDispatchTable structure.

This primitive puts a connection (specified through Request->Handle.ConnectionContext) into the listening state. Incoming connection requests are first matched against possible connections in the listening state. If no match is found the connection request is passed to the Connect Event handler, if there is one. Most VxD clients should use the TDI_CONNECT_EVENT event handler instead of using this primitive.

TDI_STATUS
  TdiListen(PTDI_REQUEST Request,
    ushort  Flags,
    PTDI_CONNECTION_INFORMATION  AcceptableAddr,
    PTDI_CONNECTION_INFORMATION  ConnectedAddr
    );

Parameters

Flags
May be set to zero or TDI_QUERY_ACCEPT. If TDI_QUERY_ACCEPT is set, the listen will complete with success and the ConnectedAddr field filled in when an acceptable connection request is received, but the connection will not actually be established. The client must then call TdiAccept to complete the connection or TdiDisconnect (with TDI_DISCONNECT_ABORT set) to reject the connection. If TDI_QUERY_ACCEPT is not set, the connection is completely established when the TdiListen request completes successfully.
AcceptableAddr
Specifies the possible acceptable remote addresses that might connect to the listening connection. The address portion may contain a wildcard (0.0.0.0) IP address, meaning that any remote IP address with the specified port may connect. The Options and OptionsLength fields may specify IP options to be used on this connection. These options will override any specified by the remote peer.
ConnectedAddr
Filled in with the address which connected and the IP options (if any) active on this connection if (and only if) the connection completes successfully.


TdiAccept

The TdiAccept function is called through the TdiAcceptEntry pointer in the TdiDispatchTable structure.

This primitive accepts a connection on a connection object that previously had a TdiListen request with TDI_QUERY_ACCEPT completed successfully.

TDI_STATUS
  TdiAccept(PTDI_REQUEST Request,
    PTDI_CONNECTION_INFORMATION  AcceptInfo,
    PTDI_CONNECTION_INFORMATION  ConnectedInfo
    );

Parameters

AcceptInfo
Used to provide IP options to the transport. These options, if present, will override any specified by the remote peer. AcceptInfo may be set to NULL.
ConnectedInfo
Filled in by the transport when the request completes and provides the client with the remote address connected and IP options active on the connection.


TdiReceive

The TdiuReceive function is called through the TdiReceiveEntry pointer in the TdiDispatchTable structure.

This request receives data on a connected connection. If no data is currently available on the connection the request will pend until there is data. A receive request may specify whether normal data, urgent data, or either may be placed in the given buffer. The connection on which a receive is issued must be connected and must not have received a FIN.

TDI_STATUS
  TdiReceive(PTDI_REQUEST Request,
    ushort  *Flags,
    uint  *RcvLength,
    PNDIS_BUFFER  Buffer
    );

Parameters

Flags
Used both to specify the type of data which may be placed in the buffer and to return the type of data actually placed in the buffer. On input, Flags may be zero, TDI_RECEIVE_NORMAL, TDI_RECEIVE_EXPEDITED, or (TDI_RECEIVE_NORMAL | TDI_RECEIVE_EXPEDITED). If Flags is zero, MSTCP will interpret it as TDI_RECEIVE_NORMAL. Flags must not be set to NULL.

If Flags is set to TDI_RECEIVE_EXPEDITED, only urgent data will be placed in the buffer. When the request completes successfully, Flags will be set to either TDI_RECEIVE_NORMAL or TDI_RECEIVE_URGENT. Also, the TDI_RECEIVE_ENTIRE_MESSAGE bit is set in Flags on completion. The transport will not combine urgent and normal data into one buffer chain. See the Windows NT/Windows 2000 TDI documentation for more details on the flags.

RcvLength
Specifies the total length in bytes of data that may be placed in the buffer chain pointed to by Buffer. This length may be less than the sum of the sizes of the individual buffers in the chain, but it may not be greater than this sum. If the RcvLength is smaller than the actual size of the buffer chain, only RcvLength bytes will be placed in the buffer.

For example, if Buffer points to a chain of three 100-byte buffers but RcvLength is set to 100 on input, only the first buffer in the chain would be used. If the TdiReceive requests completes immediately with success, RcvLength will be set by the transport to the actual number of bytes received. If the request pends or fails, RcvLength is unused. Thus, RcvLength needs to be valid only for the duration of the actual call to TdiReceive, and not until the time the receive completes. If the receive request pends, the number of bytes received will be returned as the ByteCount parameter passed to the request completion callback routine.

Buffer
Points to an NDIS_BUFFER chain into which data will be copied. The individual buffers in this chain must be locked before submitting them.


TdiSend

The TdiSend function is called through the TdiSendEntry pointer in the TdiDispatchTable structure.

This primitive causes data to be sent on the connection identified by Request->Handle.ConnectionContext. The specified connection must be established and must not have been disconnected. A send request does not complete until the remote peer has successfully acknowledged the data. The number of bytes of data sent is returned as the ByteCount parameter to the completion callback routine. This value will always be equal to SendLength if the send completes successfully.

TDI_STATUS
  TdiSend(PTDI_REQUEST Request,
    ushort  Flags,
    uint  SendLength,
    PNDIS_BUFFER  SendBuffer
    );
Flags
May be set to zero or TDI_SEND_EXPEDITED. If TDI_SEND_EXPEDITED is set, the specified data is sent as urgent data. By default, MSTCP uses BSD style urgent data, and thus allows only one byte of urgent data to be sent. If more than one byte is submitted as urgent, only the last byte of the send is marked as such. A connection may be configured to use RFC 1122 style urgent data, in which case all data will be sent as urgent.
SendLength
Specifies the length in bytes of the data to be sent. This value must be equal to the sum of the sizes of the individual NDIS_BUFFER structures in the SendBuffer chain.
SendBuffer
Points to a chain of NDIS_BUFFER structures to be sent. All buffers in this chain must be locked before the send is submitted and the data in the buffers must not be altered until the send completes.


TdiSendDatagram

The TdiSendDatagram function is called through the TdiSendDatagramEntry pointer in the TdiDispatchTable structure.

This request submits a datagram send request on the address object identified by Request->Handle.AddressHandle. The local address for the datagram is derived from the specified address object. If the address object was opened with a local IP address of 0.0.0.0 the transport will choose an appropriate valid local address. The maximum size of a datagram send is 0xffff - sizeof(UDP Header). The transport will fail a send attempt with a size larger than this. The datagram send is not buffered by the transport and does not complete until the underlying link layer is finished sending the data.

TDI_STATUS
  TdiSendDatagram(PTDI_REQUEST Request,
    PTDI_CONNECTION_INFORMATION  ConnInfo,
    uint  DataSize,
    uint  *BytesSent,
    PNDIS_BUFFER  Buffer
    );

Parameters

ConnInfo
Specifies the remote address to which the datagram is to be sent. The address must be fully specified without wildcards. ConnInfo is not used to specify IP options for the send. These options may only be set on a per-address object basis, and not on a per send basis.
DataSize
Specifies the size in bytes of the data to be sent. This size must be equal to the sum of the sizes of the NDIS_BUFFER structures in the Buffer chain.
BytesSent
Pointer to where the transport may fill in the bytes of data sent in the event that the request completes immediately with TDI_SUCCESS. If the request pends for later completion, the bytes of data sent will be returned as the ByteCount parameter to the completion callback routine. This parameter will always be equal to DataSize if the request completes successfully.
Buffer
Points to a chain of NDIS_BUFFER structures to be sent. All buffers in this chain must be locked before the send is submitted, and the data in the buffers must not be altered until the send completes.


TdiReceiveDatagram

The TdiReceiveDatagram function is called through the TdiReceiveDatagramEntry pointer in the TdiDispatchTable structure.

This request submits a receive datagram request on the address object identified by Request->Handle.AddressHandle. MSTCP does not buffer incoming datagrams — if a datagram arrives and there is neither a receive datagram request posted nor a receive datagram event handler to be called, the datagram is dropped.

TDI_STATUS
  TdiReceiveDatagram(PTDI_REQUEST Request,
    PTDI_CONNECTION_INFORMATION  ConnInfo,
    PTDI_CONNECTION_INFORMATION  ReturnInfo,
    uint  RcvSize,
    uint  *BytesRcvd,
    PNDIS_BUFFER  Buffer
    );

Parameters

ConnInfo
Points to a structure describing remote addresses from which remote datagrams may be received. The addresses specified may contain wildcards. Incoming datagrams are only placed in receive datagram buffers that have matching remote addresses or wildcards in the ConnInfo structure. ConnInfo may be NULL, in which case any incoming datagram may use the buffer.
ReturnInfo
Points to a structure that will be filled in with the address of the remote entity that sent the datagram, as well as any IP options received with the datagram.
RcvSize
Maximum size in bytes of data that may be received. If RcvSize is less than the sum of the sizes of the buffers in the Buffer chain, only the first RcvSize bytes of the chain will be filled in.
BytesRcvd
Pointer to where the transport may fill in the bytes of data sent in the event that the request completes immediately with TDI_SUCCESS. If the request pends for later completion, the bytes of data sent will be returned as the ByteCount parameter to the completion callback routine.
Buffer
Pointer to a NULL-terminated list of NDIS_BUFFER structures of data to be sent. All buffers in the chain must be locked, and the chain must not be altered while the request is outstanding.


TdiSetEvent

The TdiSetEvent function is called through the TdiSetEventEntry pointer in the TdiDispatchTable structure.

This primitive sets a TDI event handler. These event handlers are pointers to routines that the VxD TCP stack will call when certain conditions occur, such as data arriving or a connection being disconnected. Event handlers are set on a per address object basis. The address object on which the handler is being set is identified by Handler.

TDI_STATUS
  TdiSetEvent(PVOID Handle,
    int  Type,
    PVOID  Handler,
    PVOID  Context
    );

Parameters

Type
Specifies which TDI event handler is being set. The valid types are TDI_EVENT_CONNECT, TDI_EVENT_DISCONNECT, TDI_EVENT_ERROR, TDI_EVENT_RECEIVE, TDI_EVENT_RECEIVE_DATAGRAM, and TDI_EVENT_RECEIVE_EXPEDITED.
Handler
Function pointer for the function to be called when an event of type Type occurs. Setting an event handler to NULL disables that event.
Context
Client-supplied value that is passed to the function identified by Handler when it is called. This Context is not used by all events.


TDI_EVENT_CONNECT

The event handler for TDI_EVENT_CONNECT is called when an incoming connection request arrives (a SYN frame) for a local address represented by the specified address object and there is no connection in the listening state that could handle the request. The called client must indicate either acceptance or rejection of the connection by the return code from the call. If the client returns TDI_MORE_PROCESSING, the connection will be accepted. Returning any other return code will cause the connection to be rejected.

TDI_STATUS
  ConnectEvent(
    PVOID  EventContext,
    uint  AddressLength,
    PTRANSPORT_ADDRESS  Address,
    uint  UserDataLength,
    PVOID  UserData,
    uint  OptionsLength,
    PVOID  Options,
    PVOID  *AcceptingID,
    ConnectEventInfo  *EventInfo
    );

Parameters

EventContext
Context value supplied on the TdiSetEvent call.
AddressLength
Length in bytes of the structure pointed to by Address.
Address
Pointer to a TRANSPORT_ADDRESS structure identifying the remote peer that is attempting to connect. This structure is valid only for the duration of the call to the event handler.
UserDataLength
Length is the length is bytes of UserData. This is zero for MSTCP.
UserData
Pointer to connect data. This is NULL for MSTCP.
OptionsLength
Length in bytes of Options.
Options
Pointer to a buffer containing IP options received with the SYN. This buffer is valid only for the duration of the call to the event handler, and may be NULL.
AcceptingID
Pointer to where the called client should store the ConnectionContext of a connection on which to accept the incoming request, if it is to be accepted. This connection must be associated with the address object that received the connect request.
EventInfo
Pointer to a ConnectEventInfo structure. The client may fill in this structure with pointers to information that the transport will use in accepting the connection, and fill in with information about the remote peer when the connect completes. If the connection is accepted, the client must minimally fill in the cei_rtn field to a pointer to a callback routine and set the cei_acceptinfo and cei_conninfo fields to NULL.


TDI_EVENT_DISCONNECT

The TDI_EVENT_DISCONNECT event handler is called when a connection is disconnecting, either gracefully or abortively. If the connection is gracefully closing, the called client must issue a graceful TdiDisconnect to complete the disconnection, if it has not already done so. If the connection is abortively closing, the connection is gone at the time the event handler is called and the client need take no further action. An abortive disconnect may occur because an RST was received or because of a time-out.

TDI_STATUS
  DisconnectEvent(
    PVOID  EventContext,
    PVOID  ConnectionContext,
    uint  DisconnectDataLength,
    PVOID  DisconnectData,
    uint  OptionsLength,
    PVOID  Options,
    ulong  Flags
    );

Parmeters

EventContext
Context value supplied on the TdiSetEvent call.
ConnectionContext
Context for the disconnection connection object. This context was supplied by the client as a parameter to the TdiOpenConnection call that opened the connection.
DisconnectDataLength
Unused and set to zero and NULL, respectively.
DisconnectData
Unused and set to zero and NULL, respectively.
OptionsLength
Length in bytes of the Options parameter.
Options
Pointer to a buffer containing IP options received with the frame containing the FIN or RST, if the disconnect was triggered by an incoming frame. This buffer is valid only for the duration of the call to the event handler, and may be NULL.
Flags
Identifies the type of disconnect. It is either TDI_DISCONNECT_RELEASE or TDI_DISCONNECT_ABORT.


TDI_EVENT_ERROR

The TDI_EVENT_ERROR event handler is unused by MSTCP and should not be set.


TDI_EVENT_RECEIVE

The TDI_EVENT_RECEIVE event handler is called when incoming data arrives for a connection. The called client may take all, some, or none of the indicated data during the call to the handler, and may also optionally pass back a pointer to a buffer to receive remaining or newly arrived data. There are some intricacies relating to when a receive event handler will be called if it has recently been called or there is a receive buffer outstanding. For more information, refer to the Windows NT/Windows 2000 TDI documentation.

Since TCP is a stream-oriented protocol, there is no restriction on the minimum number of bytes that will be indicated in a receive event call.

TDI_STATUS
  RcvEvent(
    PVOID  EventContext,
    PVOID  ConnectionContext,
    ulong  Flags,
    uint  Indicated,
    uint  Available,
    uint  *Taken,
    uchar  *Data,
    EventRcvBuffer  *Buffer
    );

Parameters

EventContext
Context value supplied on the TdiSetEvent call.
ConnectionContext
Context for the connection object receiving the data. This context was supplied by the client as a parameter to the TdiOpenConnection call that opened the connection.
Flags
Supplies information about the receive indication. The most interesting flag is TDI_RECEIVE_ENTIRE_MESSAGE. If this flag is set, the PUSH bit was set on the segment containing the data being delivered. See the Windows NT/Windows 2000 TDI documentation for more details on the flags.
Indicated
Count of the number of bytes of data being indicated (for example, the number of bytes in the buffer pointed to by Data).
Available
Count of the total number of bytes of data available in the transport. This value will always be greater than or equal to Indicated. If Available is greater than Indicated, then there is data available that is not being passed up in the event handler, and the called client will need to supply a receive buffer to retrieve it. The receive buffer may be supplied either by returning a pointer in the EventRcvBuffer structure or by calling TdiReceive.
Taken
Pointer to a location where the client may fill in the total number of bytes taken on the indication. The client may set Taken to zero if no data was consumed. The maximum value to which Taken may be set is Available. Note that this may be greater than indicated, which allows the client to skip data that has arrived but not been indicated if it needs. Taken is only examined if TDI_MORE_PROCESSING or TDI_SUCCESS is returned. In these cases, the transport assumes that the first Taken bytes of data were consumed by the client and will not copy this data into a client buffer.
Data
Pointer to a buffer of received data. The length of the buffer is given by Indicated.
Buffer
Pointer to an EventRcvBuffer structure. The client may fill in this structure to give the transport a buffer into which to place data. This structure is only examined if the status TDI_MORE_PROCESSING is returned. The buffer returned by the client may be larger than the size indicated by Available. In this case, the buffer will be retained for more arriving data.

Comments

There are three relevant status codes that the client can return from the call to the event handler.

Status Code | Description
TDI_MORE_PROCESSING | Indicates that the client has taken some or all of the data and has returned a buffer for more data through the EventRcvBuffer structure.
TDI_NOT_ACCEPTED | Indicates that the client has taken none of the data and has not returned a receive buffer.
TDI_SUCCESS | Indicates that the client has taken some or all of the data, but has not returned a receive buffer.

Note If TDI_MORE_PROCESSING or TDI_SUCCESS is returned, the client must set Taken to be the count of the number of bytes consumed. If there is data that the client does not consume and there is no receive buffer provided, the VxD transport will make a best effort attempt to buffer the data for later consumption. However, if the transport is unable to allocate memory, the data is dropped and will need to be retransmitted.


TDI_EVENT_RECEIVE_DATAGRAM

The TDI_EVENT_RECEIVE_DATAGRAM event handler is called when an incoming datagram is received. As with the TDI_EVENT_RECEIVE event, the called client may take all, some, or none of the data, and may optionally pass back a buffer for unconsumed data. Unlike stream data, datagrams are not buffered, so any data the client does not consume is lost if no buffer is provided on the return. Also, MSTCP will not queue datagram receive buffers for later use if they are returned from an event handler. Thus, if a client consumes all the datagram and passes back a buffer, the buffer will be completed immediately with a length of zero.

TDI_STATUS
  RcvDGEvent(
    PVOID  EventContext,
    uint  AddressLength,
    PTRANSPORT_ADDRESS  Address,
    uint  OptionsLength,
    PVOID  Options,
    uint  Flags,
    uint  Indicated,
    uint  Available,
    uint  *Taken,
    uchar  *Data,
    EventRcvBuffer  **Buffer    );

Parameters

EventContext
Context value supplied on the TdiSetEvent call.
AddressLength
Length in bytes of the structure pointed to by Address.
Address
Pointer to a TRANSPORT_ADDRESS structure identifying the remote peer that sent the datagram. This structure is valid only for the duration of the call to the event handler.
OptionsLength
Length in bytes of Options.
Options
Pointer to a buffer containing IP options received with the datagram. This buffer is valid only for the duration of the call to the event handler, and may be NULL if there were no options.
Flags
Set of TDI flags providing more information about the event. In the VxD environment, they are largely meaningless and may be ignored. See the Windows NT/Windows 2000 TDI documentation for more details on the flags.
Indicated
Is a cCount of the number of bytes of data being indicated (for example, the number of bytes in the buffer pointed to by Data).
Available
Count of the total number of bytes of data available in the transport. This value will always be greater than or equal to Indicated. If Available is greater than Indicated, then there is data available that is not being passed up in the event handler, and the called client will need to supply a receive buffer to retrieve it. The receive buffer must be supplied either by returning a pointer to an EventRcvBuffer structure. If Available is greater than Indicated and the client does not provide an EventRcvBuffer structure, the additional data will be lost.
Taken
Pointer to a location where the client may fill in the total number of bytes taken on the indication. The client may set Taken to zero if no data was consumed. The maximum value to which Taken may be set is Indicated. This is different from the TDI_EVENT_RECEIVE handler, where the maximum value of Taken is Available. If a client wants to consume the indicated data and discard the rest, it should return TDI_SUCCESS. Taken is only examined if TDI_MORE_PROCESSING is returned. In this case, the transport assumes that the first Taken bytes of data were consumed by the client and will not copy this data into a client buffer.
Data
Is a pointer to a buffer of received data. The length of the buffer is given by Indicated.
Buffer
Pointer to a pointer to an EventRcvBuffer structure If the client wants to return a receive buffer, it should set Buffer to a pointer to a filled in EventRcvBuffer structure describing the buffer chain and providing a callback routine. Note that this is different from the TDI_EVENT_RECEIVE case, where the transport provides the EventRcvBuffer structure and the client merely fills it in. This structure is only examined if the status TDI_MORE_PROCESSING is returned. The client-provided EventRcvBuffer structure must remain valid until the completion routine is called. The completion routine is generally called immediately.

Comments

The status codes that can be returned from a receive datagram event are TDI_MORE_PROCESSING, TDI_NOT_ACCEPTED, and TDI_SUCCESS. They have the same meaning as when they are returned from an ordinary TDI_EVENT_RECEIVE handler.


TDI_EVENT_RECEIVE_EXPEDITED

The TDI_EVENT_RECEIVE_EXPEDITED event is called to receive urgent data. It is nearly identical to the TDI_EVENT_RECEIVE event; the only difference between the two is that TDI_EVENT_RECEIVE receives only normal data and TDI_EVENT_RECEIVE_EXPEDITED receives only urgent data. The prototypes for the two event handlers are the same. Note that the two event handlers are not serialized by the transport.


TdiQueryInformation

The TdiQueryInformation function is called through the TdiQueryInformationEntry pointer in the TdiDispatchTable structure.

TDI_STATUS
  TdiQueryInformation( PTDI_REQUEST Request,
    uint  QueryType,
    PNDIS_BUFFER  Buffer,
    uint  *BufferSize,
    uint  IsConn
    );

Parameters

QueryType
Indicates which information is being queried. The following values are supported.
Value | Description
TDI_QUERY_PROVIDER_INFO | Queries the transport about provider information. A structure of type TDI_PROVIDER_INFO (see TDI.H) will be copied into the buffer chain pointed to by Buffer.
TDI_QUERY_ADDRESS_INFO | Queries the transport about the local transport of an address object or connection. The query is for a connection if IsConn is TRUE (nonzero), and for an address object if IsConn is FALSE (zero). The address object or connection being queried is specified by Request->Handle. A structure of type TDI_ADDRESS_INFO (see TDI.H) will be copied into the buffer chain pointed to by Buffer.
TDI_QUERY_CONNECTION_INFO | Queries MSTCP for information about the connection identified by Request->Handle.ConnectionContext. A structure of type TDI_CONNECTION_INFO (see TDI.H) will be copied into the buffer chain pointed to by Buffer.
TDI_QUERY_PROVIDER_STATISTICS | Queries the transport for certain statistics. Not all the defined statistics are kept by MSTCP. A structure of type TDI_PROVIDER_STATISTICS (see TDI.H) will be copied into the buffer chain pointed to by Buffer.

Buffer
Points to an NDIS_BUFFER chain into which the information is copied.
BufferSize
Points to the size of the input buffer chain in bytes. On return, BufferSize is set to the size of the information copied into Buffer. If the NDIS_BUFFER chain pointed to by Buffer is too small to contain the requested data, only the amount that fits is copied and TDI_BUFFER_OVERFLOW is returned.
IsConn
Boolean used to provide additional information for the TDI_QUERY_ADDRESS_INFO call. If IsConn is nonzero, than information about a connection is returned. If IsConn is zero, information about an address object is returned.


TdiSetInformation

The TdiSetInformation function is called through the TdiSetInformationEntry pointer in the TdiDispatchTable structure.

TDI_STATUS
  TdiSetInformation(PTDI_REQUEST Request,
    uint  SetType,
    PNDIS_BUFFER  Buffer,
    uint  *BufferSize,
    uint  IsConn
    );

Parameters

SetType
To be provided.
Buffer
To be provided.
BufferSize
To be provided.
IsConn
To be provided.

CommentsThis call is not supported in MSTCP and always fails.


TdiActionInformation

The TdiActionInformation function is called through the TdiActionEntry pointer in the TdiDispatchTable structure.

TDI_STATUS
  TdiAction( PTDI_REQUEST Request,
    uint  ActionType,
    PNDIS_BUFFER  Buffer,
    uint  *BufferSize
    );

Parameters

ActionType
To be provided.
Buffer
To be provided.
BufferSize
To be provided.

Comments

This call is not supported in MSTCP and always fails.


TdiQueryInformationEx

The TdiQueryInformationEx function is called through the TdiQueryInformationExEntry in the TdiDispatchTable structure.

TDI_STATUS
  TdiQueryInformationEx( PTDI_REQUEST Request,
    TDIObjectID  *ID,
    PNDIS_BUFFER  Buffer,
    uint  *Size,
    void  *Context
    );

Parameters

ID
To be provided.
Buffer
To be provided.
Size
To be provided.
Context
To be provided.


TdiSetInformationEx

The TdiSetInformationEx function is called through the TdiQueryInformationExEntry in the TdiDispatchTable structure.

TDI_STATUS
  TdiSetInformationEx( PTDI_REQUEST Request,
    TDIObjectID  *ID,
    void  *Buffer,
    uint  Size
    );

Parameters

ID
To be provided.
Buffer
To be provided.
Size
To be provided.


VxDs for Windows 98

This section lists the VxDs new to Windows® 98. The following topics are included:

Heap Functions

IFSMgr Functions

VMM Functions

VPOWERD Functions and Structures


Heap Functions

The following calls are new to Windows 98:

HeapAllocateEx

HeapFreeEx

HeapGetSizeEx

HeapReAllocateEx


HeapAllocateEx

HeapAllocateEx allocates a block of RAM from a heap.

PVOID HeapAllocateEx(
  ULONG   cBytes,
  PVOID   CallBack,
  PVOID   Reference,
  ULONG   flags
 );

Parameters

cBytes
Number of bytes required
CallBack
To be provided.
Reference
To be provided.
flags
One or more of HEAPxxx as defined in VMM.H.

Return Values

The return value is a pointer to allocated memory, or is NULL if no memory is allocated.


HeapFreeEx

HeapFreeEx frees a block of RAM to a heap.

VOID HeapFreeEx(
  PVOID   mem,
  PVOID   Reserved1
 );

Parameters

mem
Pointer to a piece of memory previously returned by HeapAllocateEx or HeapReAllocateEx.
Reserved1
Reserved. Must be NULL.

Return Values

No value is returned.


HeapGetSizeEx

HeapGetSizeEx gets the actual size of a block of memory.

ULONG HeapGetSizeEx(
  PVOID   pmem,
  PVOID   Reserved1
 );

Parameters

pmem
Pointer to memory previously returned by HeapAllocateEx.
Reserved1
Reserved. Must be NULL.

Return Values

The return value is the size of the block of memory pointed to by the pmem parameter.


HeapReAllocateEx

HeapReAllocateEx reallocates a block of memory. This function always allocates a new block even if the new block is smaller than the old block and is on the same heap.

PVOID HeapReAllocateEx(
  PVOID   pmem,
  ULONG   cBytes,
  PVOID   Reserved1,
  PVOID   Reserved2,
  ULONG   Flags
 );

Parameters

pmem
Pointer to memory previously returned by HeapAllocateEx.
cBytes
Size of the resized block.
Reserved1
Reserved for future use.
Reserved2
Reserved for future use.
Flags
One or more of HEAPxxx as defined in VMM.H.

Return Values

No value is returned.


IFSMgr Functions

The following functions are new to Windows 98:

  • IFSMgr_GetRing0FileHandle
  • IFSMgr_DeregisterFSD


IFSMgr_GetRing0FileHandle

IFSMgr_GetRing0FileHandle gets the IFS ring 0 handle from an IOREQ. This function is called to obtain the IFSMgr's ring 0 file handle associated with an IFSMgr IOREQ. This function does not support IOREQs associated with path-based or find-handle-based APIs.

pfhandle IFSMgr_GetRing0FileHandle (
  pifsreq   pir
 );

Parameters

pir
Pointer to IFS IOREQ.

Return Values

The return value is a pointer to the IFS ring 0 file handle associated with this IOREQ. If NULL is returned, this indicates that either the IOREQ or the handle associated with the IOREQ is invalid.


IFSMgr_DeregisterFSD

IFSMgr_DeregisterFSD unloads a previously registered FSD. This routine is called to dynamically unload an FSD that has already been loaded. Note there is no need for this function to be called when the system is shutting down. This call can handle the unloading of all the various types of FSDs that can be present in the system. A force level can also be specified to indicate what level of cleanup is allowed. If the specified force level is not high enough for all the cleanup to be done, the unload operation will be failed.

NTSTATUS IFSMgr_DeregisterFSD(
  DWORD   FSDType,
  DWORD   ProID,
  DWORD   Force,
  DWORD   Version
 );

Parameters

FSDType
Type of FSD being deregistered.
ProID
Provider ID of FSD.
Force
Force level to use.
Version
Version of IFSMgr used by FSD.

Return Values

The return value is NTSUCCESS if successful. Otherwise, the appropriate error code is returned.


VMM Functions

The following function is new to Windows 98:

  • VMMCreateThreadEx


VMMCreateThreadEx

VMMCreateThreadEx creates a protected mode thread in the system VM and then starts it executing at the ring 3 cs:eip passed in. This service initiates the following:

  1. Sends the Create_Thread message to all VXDs to allow them to create and initialize any data structures necessary to support another thread. This message passes the new thread handle in EDI. Interrupt simulation is not yet permitted in the new thread. The call can be failed by returning the carry set. In this case, no system resources should have been allocated.
  2. The client registers are initialized to the values specified by the parameter list.
  3. The timeslicer is notified to start scheduling the thread.
  4. The new thread sends a Thread_Init system control message to all the VXDs. The VXDs can then complete any initialization that must take place in the context of the new thread. The new thread handle is in EDI, as well as being the current thread handle. Interrupt simulation is not permitted since interrupt simulation is not permitted in noninitial threads. The call cannot be failed.
NTSTATUS VMMCreateThreadEx(
  DWORD   ClientSS,
  DWORD   ClientESP,
  DWORD   ClientCS,
  DWORD   ClientEIP,
  DWORD   ClientDS,
  DWORD   ClientES,
  DWORD   ThreadType,
  DWORD   InitCallback,
  DWORD   RefData
 );

Parameters

ClientSS
Ring 3 protected mode registers used to start the thread.
ClientESP
Ring 3 protected mode registers used to start the thread.
ClientCS
Ring 3 protected mode registers used to start the thread.
ClientEIP
Ring 3 protected mode registers used to start the thread.
ClientDS
Ring 3 protected mode registers used to start the thread.
ClientES
Ring 3 protected mode registers used to start the thread.
ThreadType
Any arbitrary DWORD value the creator can use to uniquely identify threads it creates from the threads that another VxD creates. The ThreadType can be a pointer to the DDB of the creator VxD, because this will always be unique between two different VxDs. ThreadType may also be zero if the type is irrelevant to the usage. This value is stored in the TCB_ThreadType field in the thread's control block.
InitCallback
A ring 0 initialization routine that will be called if nonzero. After the Thread_Init broadcast, the RefData will be passed in the EDX register. The return address from the callback will be Return_To_VM. Thus, once initialization is complete, the thread will start executing ring 3 code. It is possible to block the thread in this initialization routine so it never returns from this initialization routine, if the thread is only used to execute ring 0 code.
RefData
Handle of the created thread. This is zero if a thread cannot be created (from resources).

Return Values

The return value is NTSUCCESS. if successful. Otherwise, the appropriate error code is returned.


VPOWERD Functions and Structures

The following calls are new for Windows 98:

VPOWERD_W32_Get_System_Power_Status

VPOWERD_W32_Set_System_Power_State

VPOWERD_Get_Capabilities

VPOWERD_Enable_Resume_On_Ring

VPOWERD_Disable_Resume_On_Ring

VPOWERD_Set_Resume_Timer

VPOWERD_Get_Resume_Timer

VPOWERD_Disable_Resume_Timer

VPOWERD_Enable_Timer_Based_Requests

VPOWERD_Disable_Timer_Based_Requests

VPOWERD_W32_Get_Power_Status

VPOWERD_Get_Timer_Based_Requests_Status

VPOWERD_Get_Ring_Resume_Status

VPOWERD_Get_Battery_Unit_Status

VPOWERD_Get_Battery_Unit_Presence

VPOWERD_Disable_APM_Idle

VPOWERD_Enable_APM_Idle

VPOWERD_Get_Mode

The following topic contains the structures used with the VPOWERD functions:

APM_CAPABILITIES

WIN32_SYSTEM_POWER_STATUS

POWERTIME

POWER_STATUS


VPOWERD_W32_Get_System_Power_Status

VPOWERD_W32_Get_System_Power_Status retrieves the power status of the system.

POWERRET VPOWERD_W32_Get_System_Power_Status(
  Win32_System_Power_Status   *pWin32_System_Power_Status
 );

Parameters

pWin32_System_Power_Status
Structure that is completed with the relevant system information.

Return Values

The return value is TRUE, is successful. Otherwise, the return value is FALSE.


VPOWERD_W32_Set_System_Power_State

VPOWERD_W32_Set_System_Power_State sets the power state of the system.

POWERRET VPOWERD_W32_Set_System_Power_State(
  boolean   dwSuspendFlag,
  boolean   dwForceFlag
 );

Parameters

dwSuspendFlag
Set to TRUE if APM standby is not required.
dwForceFlag
Set to TRUE to suspend. By default, this should be FALSE.

Return Values

The return value is POWERRET. This is PR_SUCCESS if the call successfully completes. Otherwise, an appropriate error message is returned.


VPOWERD_Get_Capabilities

VPOWERD_Get_Capabilities retrieves the APM bios capabilities bit mask. BIOS capabilities do not change while the system is running, so these values are stored in the reference data structure passed up from Real Mode Init.

POWERRET VPOWERD_Get_Capabilities(
  APM_CAPABILITIES   *pAPM_CAPABILITIES
);

Parameters

pAPM_CAPABILITIES
Structure that is completed with the relevant capabilities.

Return Values

The return value is POWERRET. This is PR_SUCCESS if the call successfully completes. Otherwise, an appropriate error message is returned.


VPOWERD_Enable_Resume_On_Ring

VPOWERD_Enable_Resume_On_Ring enables the Resume on Ring capability in the BIOS.

POWERRET VPOWERD_Enable_Resume_On_Ring( VOID );

Parameters

None.

Return Values

The return value is POWERRET. This is PR_SUCCESS if the call successfully completes. Otherwise, an appropriate error message is returned.


VPOWERD_Disable_Resume_On_Ring

VPOWERD_Disable_Resume_On_Ring disables the Resume on Ring capability of the BIOS.

POWERRET VPOWERD_Disable_Resume_On_Ring( VOID );

Parameters

None.

Return Values

The return value is POWERRET. This is PR_SUCCESS if the call successfully completes. Otherwise, an appropriate error message is returned.


VPOWERD_Set_Resume_Timer

VPOWERD_Set_Resume_Timer should only be used within KERNEL32.dll since the list of users requesting to set and use the timer functions is maintained there.

POWERRET VPOWERD_Set_Resume_Timer(
  LPPOWERTIME   pPowerTime
 );

Parameters

pPowerTime
Sets the wake-up time for the machine.

Return Values

The return value is POWERRET. This is PR_SUCCESS if the call successfully completes. Otherwise, an appropriate error message is returned.


VPOWERD_Get_Resume_Timer

VPOWERD_Get_Resume_Timer should only be used within KERNEL32.dll since the list of users requesting to set and use the timer functions is maintained there.

POWERRET VPOWERD_Get_Resume_Timer(
  LPPOWERTIME   pPowerTime
 );

Parameters

pPowerTime
Retrieves the wake-up time of the machine.

Return Values

The return value is POWERRET. This is PR_SUCCESS if the call successfully completes. Otherwise, an appropriate error message is returned.


VPOWERD_Disable_Resume_Timer

VPOWERD_Get_Resume_Timer should only be used within KERNEL32.dll since the list of users requesting to set and use the timer functions is maintained there.

POWERRET VPOWERD_Disable_Resume_Timer( VOID );

Parameters

None.

Return Values

The return value is POWERRET. This is PR_SUCCESS if the call successfully completes. Otherwise, an appropriate error message is returned.


VPOWERD_Enable_Timer_Based_Requests

VPOWERD_Enable_Timer_Based_Requests allows the BIOS to initiate timer-based changes in the power state. It is used only in APM mode.

POWERRET VPOWERD_Enable_Timer_Based_Requests( VOID );

Parameters

None.

Return Values

The return value is POWERRET This is PR_SUCCESS if the call successfully completes. Otherwise, an appropriate error message is returned.


VPOWERD_Disable_Timer_Based_Requests

VPOWERD_Disable_Timer_Based_Requests prevents the BIOS from initiating timer-based changes in the power state. It is used only in APM mode.

POWERRET VPOWERD_Disable_Timer_Based_Requests( VOID );

Parameters

None.

Return Values

The return value is POWERRET. This is PR_SUCCESS if the call successfully completes. Otherwise, an appropriate error message is returned.


VPOWERD_W32_Get_Power_Status

VPOWERD_W32_Get_Power_Status retrieves the current power status of the device.

POWERRET VPOWERD_W32_Get_Power_Status(
  DWORD   Power_Device_ID,
  Win32_System_Power_Status   pWin32_System_Power_Status
);

Parameters

Power_Device_ID
ID of the device to be polled.
pWin32_System_Power_Status
Structure to be completed with the relevant statuses.

Return Values

The return value is POWERRET. This is PR_SUCCESS if the call successfully completes. Otherwise, an appropriate error message is returned.


VPOWERD_Get_Timer_Based_Requests_Status

VPOWERD_Get_Timer_Based_Requests_Status gets the status of the timer-based requests flag in the BIOS. It is used only in APM mode.

POWERRET VPOWERD_Get_Timer_Based_Requests_Status(
  DWORD   *pStatusVOID
);

Parameters

pStatus
Retrieves the time request status with CAPABILITY_ENABLED or CAPABILITY_DISABLED.

Return Values

The return value is POWERRET. This is PR_SUCCESS if the call successfully completes. Otherwise, an appropriate error message is returned.


VPOWERD_Get_Ring_Resume_Status

VPOWERD_Get_Ring_Resume_Status determines whether or not the current Resume on ring is enabled in the BIOS. It is used only in APM mode.

POWERRET VPOWERD_Get_Ring_Resume_Status(
   DWORD   *pStatus
);

Parameters

*pStatus
Retrieves the time request status with CAPABILITY_ENABLED or CAPABILITY_DISABLED.

Return Values

The return value is POWERRET. This is PR_SUCCESS if the call successfully completes. Otherwise, an appropriate error message is returned.


VPOWERD_Get_Battery_Unit_Status

VPOWERD_Get_Battery_Unit_Status returns the current battery status.

POWERRET VPOWERD_Get_Battery_Unit_Status(
  DWORD   BatteryDeviceObject,
  Power_Status   pPower_Status
);

Parameters

BatteryDeviceObject
WDM DeviceObject for the battery.
pPower_Status
Structure to be completed with the relevant statuses.

Return Values

The return value is POWERRET. This is PR_SUCCESS if the call successfully completes. Otherwise, an appropriate error message is returned.


VPOWERD_Get_Battery_Unit_Presence

VPOWERD_Get_Battery_Unit_Presence tests for the presence of a battery slot.

POWERRET VPOWERD_Get_Battery_Unit_Presence(
  DWORD   BatteryDeviceObject
);

Parameters

BatteryDeviceObject
WDM DeviceObject for the battery.

Return Values

The return value is zero if a battery slot is found, and -1 for any other condition.


VPOWERD_Disable_APM_Idle

VPOWERD_Disable_APM_Idle disables the APM idle.

POWERRET VPOWERD_Disable_APM_Idle( VOID );

Parameters

None

Return Values

The return value is POWERRET. This is PR_SUCCESS if the call successfully completes. Otherwise, an appropriate error message is returned.


VPOWERD_Enable_APM_Idle

VPOWERD_Enable_APM_Idle enables the APM idle.

POWERRET VPOWERD_Enable_APM_Idle( VOID );

Parameters

None.

Return Values

The return value is POWERRET. This is PR_SUCCESS if the call successfully completes. Otherwise, an appropriate error message is returned.


VPOWERD_Get_Mode

VPOWERD_Get_Mode retrieves the operational mode of VPOWERD.

POWERRET VPOWERD_Get_Mode(
  PULONG   pulMode
 );

Parameters

pulMode
Indicates the power mode. This will be zero for APM mode and 1 for ACPI mode.

Return Values

The return value is POWERRET. This is PR_SUCCESS if the call successfully completes. Otherwise, an appropriate error message is returned.


APM_CAPABILITIES

The APM_CAPABILITIES contains flags and information to set the APM capabilities of the device.

typedef struct APM_CAPABILITIES_S {
   WORD   Capabilities;
   BYTE   BatteryCount;
   BYTE   Reserved;
} APM_CAPABILITIES, *PAPM_CAPABILITIES;

Members

Capabilities
Sets the capabilities of the device. The field can be set to the capabilities listed in the following table. Unused capabilities must be set to zero.
Flag Name Description
GLOBAL_STANDBY_
SUPPORTED_BIT 		System can enter global standby state. Indicates BIOS will post standby and standby-resume events. If used, it must be set to GLOBAL_STANDBY_SUPPORTED.
GLOBAL_SUSPEND_
SUPPORTED_BIT 		System can enter global suspend state. Indicates BIOS will post suspend and suspend-resume events. If used, it must be set to GLOBAL_SUSPEND_SUPPORTED.
WAKE_ON_TIMER_
STANDBY_BIT 		Resume timer will wake up from standby. If used, it must be set to WAKE_ON_TIMER_STANDBY.
WAKE_ON_TIMER_
SUSPEND_BIT 		Resume timer will wake up from suspend. If used, it must be set to WAKE_ON_TIMER_SUSPEND.
RING_RESUME_
INTERNAL_STANDBY_
BIT 		Resume on ring indicator (internal COM or modem) will wake up from standby. If used, it must be set to RING_RESUME_INTERNAL_STANDBY.
RING_RESUME_
INTERNAL_SUSPEND_
BIT 		Resume on ring indicator (internal COM or modem) will wake up from suspend. If used, it must be set to RING_RESUME_INTERNAL_SUSPEND.
RING_RESUME_
PCMCIA_STANDBY_BIT 		PCMCIA ring indicator will wake up from standby. If used, it must be set to RING_RESUME_PCMCIA_STANDBY.
RING_RESUME_
PCMCIA_SUSPEND_BIT 		PCMCIA ring indicator will wake up from suspend. If used, it must be set to RING_RESUME_PCMCIA_SUSPEND.

BatteryCount
Number of batteries present.
Reserved
Reserved. Do not use.


WIN32_SYSTEM_POWER_STATUS

The WIN32_SYSTEM_POWER_STATUS contains detailed information about the power supply and its status for the device.

typedef struct _WIN32_SYSTEM_POWER_STATUS {
    BYTE    W32PS_AC_Line_Status;
    BYTE    W32PS_Battery_Flag;
    BYTE    W32PS_Battery_Life_Percent;
    BYTE    W32PS_Reserved1;
    DWORD   W32PS_Battery_Life_Time;
    DWORD   W32PS_Battery_Full_Life_Time;
}   WIN32_SYSTEM_POWER_STATUS;

Members

W32PS_AC_Line_Status
Indicates the state of the AC power input line. The following values are provided:

APM_GPS_AC_LINE_OFFLINE

APM_GPS_AC_LINE_ONLINE

APM_GPS_AC_LINE_BACKUP_POWER

APM_GPS_AC_LINE_UNKNOWN

W32PS_Battery_Flag
Indicates the presence of a battery and its charging state. This value may be one of the following values, or a combination:

APM_GPS_BATTERY_STATUS_HIGH

APM_GPS_BATTERY_STATUS_LOW

APM_GPS_BATTERY_STATUS_CRITICAL

APM_GPS_BATTERY_STATUS_CHARGING

APM_GPS_BATTERY_STATUS_UNKNOWN

APM_GPS_BATTERY_FLAG_HIGH

APM_GPS_BATTERY_FLAG_LOW

APM_GPS_BATTERY_FLAG_CRITICAL

APM_GPS_BATTERY_FLAG_CHARGING

APM_GPS_BATTERY_FLAG_NO_BATTERY

APM_GPS_BATTERY_FLAG_UNKNOWN

The following value is applicable to APM version 1.2 or later:

APM_GPS_BATTERY_NOT_PRESENT

W32PS_Battery_Life_Percent
Remaining expected life of the battery, in percent amount. It may also be APM_GPS_BATTERY_PERCENTAGE_UNKNOWN.
W32PS_Reserved1
Reserved. Do not use.
W32PS_Battery_Life_Time
Remaining expected life of the battery, in seconds.
W32PS_Battery_Full_Life_Time
Expected life of the battery. This value is not returned by the APM BIOS, so it is calculated by using the current battery lifetime and the percentage of battery life remaining, if available. This value may be BATTERY_LIFE_W32_UNKNOWN.


POWERTIME

The POWERTIME structure is used to set and retrieve time functions.

typedef struct _POWERTIME {
    WORD   Year;
    WORD   Month;
    WORD   DayOfWeek;
    WORD   Day;
    WORD   Hour;
    WORD   Minute;
    WORD   Second;
    WORD   Milliseconds;
} POWERTIME;

Members

Year
Indicates the year.
Month
Indicates the month, 1 (January) through 12 (December).
DayOfWeek
Indicates the day of the week, zero (Sunday) through 6 (Saturday).
Day
Indicates the day of the month, 1 through 31.
Hour
Indicates the hour of the day, zero through 23.
Minute
Indicates the minutes, zero through 59.
Second
Indicates the seconds, zero through 59.
Milliseconds
Indicates the milliseconds, zero through 999.


POWER_STATUS

The POWER_STATUS structure is used to set and retrieve time functions

typedef struct _POWER_STATUS {
    BYTE   PS_AC_Line_Status;
    BYTE   PS_Battery_Status;
    BYTE   PS_Battery_Flag;
    BYTE   PS_Battery_Life_Percentage;
    WORD   PS_Battery_Life_Time;
}   POWER_STATUS;

Members

PS_AC_Line_Status
Indicates the state of the AC power input line.
PS_Battery_Status
Indicates the status of the battery.
PS_Battery_Flag
Indicates the presence of a battery and its charging state.
PS_Battery_Life_Percentage
Remaining expected life of the battery, in percent amount.
PS_Battery_Life_Time
Expected remaining life of the battery, in seconds.


Enabling MTRR Support

MTRR support is the enabling of the Write Combining feature in the Intel Pentium Pro microprocessor. For both the Microsoft® Windows® 95 and Windows® 98 operating systems, this support is enabled by two function calls exported by Mtrr.vxd: MTRR_Get_Version and MTRRSetPhysicalCacheTypeRange.

To enable MTRR support, see the DirectX 5.0 DDK available at the following web site:

http://www.microsoft.com/msdownload/directx/dxf/ddk/default.htm


MTRR_Get_Version

Parameters

None.

Return Values

ASM:
STC, not supported; CLC, supported.
C:
AX = FALSE, not supported; TRUE, supported.

Use in ASM:

Include:
Mtrr.inc
VxDCall:
_MTRR_Get_Version
Jc:
No_MTRR_Support

Use in C

    #include <mtrr.h>
    if (MTRRGetVersion())
        /* Set appropriate cache type */
    else
        /* No MTRR support */


MTRRSetPhysicalCacheTypeRange

The MTRRSetPhysicalCacheTypeRange function sets a physical range to a particular cache type and requires the caller to be at nonhardware interrupt time. If the system does not support setting cache policies based on physical ranges, no action is taken.

Parameters

PhysicalAddress
Starting address of the range being set.
NumberOfBytes
Length, in bytes, of the range being set.
CacheType
Caching type for which the physical range is to be set to. The following values are provided.
Value | Description
NonCached | Setting ranges to be NonCached are done for bookkeeping reasons. A return of SUCCESS when setting a range as NonCached does not mean it has been physically set to NonCached. The caller must use a cache-disabled virtual pointer for any NonCached range.
Cached | Successful return indicates that the physical range has been set to cache.
FrameBuffer | Successful return indicates that the physical range has been set to be frame buffer cached.

Return Values

STATUS_SUCCESS
If successful, the cache attributes of the physical range have been set.
STATUS_NO_SUCH_DEVICE
FrameBuffer type has been requested but is not supported.
STATUS_UNSUCCESSFUL STATUS_INTERNAL_ERROR
Requested physical range is below 1 MB, or another error has occurred.


Printer Driver Additions

This documentation discusses materials and samples related to printer drivers and includes the following topics:

Glyphs

Image Color Management

Installing and Using USB Printers with Microsoft Windows

Internet Printing Protocol


Glyphs

This section discusses glyph and special font support.

Printer drivers can use TrueType service functions to retrieve information about TrueType fonts, to retrieve bitmaps of individual glyphs in the fonts, and to realize a complete font, retrieving both information and bitmaps. Following are the service functions and a brief description of each.

The driver evokes EngineEnumerateFont whenever GDI calls the driver's EnumDFonts. The font engine returns an enumerated list of the available TrueType fonts having the specified font. Likewise, the driver can call EngineRealizeFont whenever GDI calls the driver's RealizeObject function. This gives the TrueType font engine an opportunity to generate a physical font that matches the specified logical font. When the engine realizes a font, it fills a FONTINFO structure with information about the font as well as the bitmap data for the individual glyphs. A driver can use this information to create a downloadable font in the format recognized by the printer.

In general, a printer driver should call EngineRealizeFont and EngineEnumerateFont before processing its own device fonts (if any). If GDI requests that the driver delete a realized TrueType font (by calling RealizeObject), the driver must call EngineDeleteFont to delete the font.

A printer driver can retrieve character width information for a realized TrueType font by using EngineGetCharWidth. It can retrieve bitmaps for individual glyphs in the font by using EngineSetFontContext and EngineGetGlyphBmp. The driver must call EngineSetFontContext first to set the font before calling EngineGetGlyphBmp. Drivers for printers that accept individual glyph definitions (as opposed to full font definitions) can use the character width information and bitmap data to download individual glyphs.


Glyph Reference

The following functions are available to retrieve, send, or evaluate font and glyph information:

Function | Description
EngineDeleteFont | Deletes a realized TrueType font.
EngineEnumerateFont | Enumerates TrueType fonts.
EngineGetCharWidth | Retrieves character widths for TrueType fonts.
EngineGetGlyphBmp | Retrieves the bitmap for a rasterized glyph.
EngineGetGlyphBmpExt | Retrieves the bitmap for a glyph indexed rasterized glyph.
EngineRealizeFont | Realizes a TrueType font.
EngineRealizeFontExt | Realizes a glyph indexed TrueType font.
EngineSetFontContext | Sets the context for rasterizing glyphs.
RealizeObject | Creates or deletes a physical object.


CallbackFunction

EngineEnumerateFont calls the callback function once for each font. It continues to call the callback function until there are no more fonts or the callback function returns zero.

WORD
  CallbackFunction(
    LPLOGFONT lpLogFont,
    LPTEXTMETRICS lpTextMetrics,
    WORD wFontType,
    LPVOID lpClientData
    );

Parameters

lpLogFont
Points to a LOGFONT structure (defined in the Platform SDK documentation) defining the logical attributes of a font.
lpTextMetrics
Points to a TEXTMETRIC structure containing the same values that would be returned by the GetTextMetrics function. (The structure and the function are described in the Platform SDK documentation.)
wFontType
Specifies the type of the font. It can be one of the following values.
Value | Description
RASTER_FONTTYPE | Indicates that the font is composed of a raster bitmap rather than vector strokes.

lpClientData
Points to the user-supplied data passed to EngineEnumerateFont. Sizes are in device units.

Return Value

The callback function must return a nonzero value to continue to receive information about the fonts. If the callback function returns zero, EngineEnumerateFont stops enumerating the fonts and returns to its caller.

If the engine can generate scaled, emboldened, or italicized fonts, EngineEnumerateFont passes only information about the base font to the callback function.

The callback function is responsible for inquiring about the engine's text transformation abilities to determine which additional fonts are available directly from the engine.


EngineDeleteFont

The EngineDeleteFont function deletes an engine font. A driver calls this function, while processing a call to its RealizeObject function, to delete a font that was previously realized using the EngineRealizeFont function.

BOOL
  EngineDeleteFont(
    LPFONTINFO lpFont
    );

Parameters

lpFont
Points to a structure containing information defining the font to delete.

Return Value

The EngineDeleteFont function returns TRUE if it successfully deletes the font. Otherwise, it returns FALSE.


EngineEnumerateFont

The EngineEnumerateFont function returns information about TrueType fonts by passing the information to the specified callback function. A driver calls this function when processing its EnumDFonts function to determine what TrueType fonts are available.

WORD
  EngineEnumerateFont(
    LPSZ lpFaceName,
    lFARPROC pCallbackFunc,
    LPVOID lpClientData
    );

Parameters

lpFaceName
Points to the null-terminated string specifying the name of a font face. If lpFaceName points to a name, EngineEnumerateFont calls the callback function with information for the fonts having the same font face name. If there are no fonts of that face, the function returns 1. If lpFaceName is NULL, EngineEnumerateFont selects one font of each face at random and calls the callback function with information for these fonts. If there are no fonts, the function returns 1.
pCallbackFunc
Points to a user-supplied callback function. See CallbackFunction.
lpClientData
Points to a buffer containing user-supplied data. EngineEnumerateFont does not use this data. Instead, it passes the data back to application through the callback function pointed to by pCallbackFunc.

Return Value

The EngineEnumerateFont function returns the last value returned by the callback function. The function returns 1 if there are no fonts having the specified font face name.


EngineGetCharWidth

The EngineGetCharWidth function returns, for the specified font, the widths of the characters within the given range.

WORD
  EngineGetCharWidth(
    LPFONTINFO lpFontInfo,
    WORD wFirstChar,
    WORD wLastChar,
    LPINT  lpWidths
    );

Parameters

lpFontInfo
Points to a FONTINFO structure specifying an engine font. The structure must have been previously filled using the EngineRealizeFont function.
wFirstChar
Specifies the first character in the range.
wLastChar
Specifies the last character in the range.
lpWidths
Points to the array that receives the character width values. The number of elements in the array must be at least the same number as characters in the specified character range.

Return Value

The EngineGetCharWidth function returns 1 if it successfully retrieved the character widths. Otherwise, it returns zero on an error.

Comments

A driver calls this function, when processing its GetCharWidth function, to retrieve widths for characters in the specified engine font.


EngineGetGlyphBmp

The EngineGetGlyphBmp function retrieves a bitmap for the glyph specified by the given character and font.

WORD
  EngineGetGlyphBmp(
    LPPDEVICE lpDestDev,
    LPFONTINFO lpFont,
    WORD ch,
    WORD wQueryType,
    LPSTR lpBits,
    DWORD dwSizeBmp,
    LPBITMAPMETRICS lpbmm
    );

Parameters

lpDestDev
Points to a PDEVICE or PBITMAP structure specifying the device or bitmap for which the physical object is created.
lpFont
Points to a FONTINFO structure specifying the font containing the glyph. This structure must have been previously filled using the EngineRealizeFont function.
ch
Specifies the character value of the glyph to retrieve.
wQueryType
Specifies whether to retrieve the glyph as a bitmap. This parameter can be one of the following values.
Value | Description
FD_QUERY_CHARIMAGE | Retrieves bitmap. The bitmap is a monochrome bitmap with scan lines aligned on 32-bit boundaries. If the glyph bitmap is greater than 64k bytes, the scan lines may straddle segment boundaries. That is, this function does not attempt to align scan lines on segment boundaries. The width of the glyph may be less than the bitmap itself. If this is the case, any extra bits at the end of each scan line are undefined.
FD_QUERY_BITMAPMETRICS | Retrieves bitmap metrics.

lpBits
Points to the buffer to receive the glyph bitmap.
dwSizeBmp
Specifies the size, in bytes, of the buffer to receive the glyph bitmap. If the bitmap is larger than the buffer, the function returns an error.
lpbmm
Points to a BITMAPMETRICS structure that receives the width, height, and position of the bitmap relative to the character origin.

Return Value

The EngineGetGlyphBmp function returns the actual number of bytes copied to the buffer. If an error occurs or the buffer is too small, the function returns zero.

Comments

The given font (specified by lpFont) must be the current engine font. That is, it must have been previously set using the EngineSetFontContext function.


EngineGetGlyphBmpExt

The EngineGetGlyphBmpExt function is the glyph index version of the EngineGetGlyphBmp. If you call EngineRealizeFontExt to enable glyph index support, you should call EngineGetGlyphBmpExt and not EngineGetGlyphBmp.

WORD
  EngineGetGlyphBmpExt(
    LPPDEVICE lpDestDev,
    LPFONTINFO lpFont,
    WORD ch,
    WORD wQueryType,
    LPSTR lpBits,
    DWORD dwSizeBmp,
    LPBITMAPMETRICS lpbmm
    );

Parameters

lpDestDev
Points to a PDEVICE or PBITMAP structure specifying the device or bitmap for which the physical object is created.
lpFont
Points to a FONTINFO structure specifying the font containing the glyph. This structure must have been previously filled using the EngineRealizeFont function.
ch
Specifies the character value of the glyph to retrieve.
wQueryType
Specifies whether to retrieve the glyph as a bitmap. This parameter can be one of the following values.
Value | Description
FD_QUERY_CHARIMAGE | Retrieves bitmap. The bitmap is a monochrome bitmap with scan lines aligned on 32-bit boundaries. If the glyph bitmap is greater than 64k bytes, the scan lines may straddle segment boundaries,. That is, this function does not attempt to align scan lines on segment boundaries. The width of the glyph may be less than the bitmap itself. If this is the case, any extra bits at the end of each scan line are undefined.
FD_QUERY_BITMAPMETRICS | Retrieves bitmap metrics.
lpBits
Points to the buffer to receive the glyph bitmap.
dwSizeBmp
Specifies the size, in bytes, of the buffer to receive the glyph bitmap. If the bitmap is larger than the buffer, the function returns an error.
lpbmm
Points to a BITMAPMETRICS structure that receives the width, height, and position of the bitmap relative to the character origin.

Return Value

The EngineGetGlyphBmpExt function returns the actual number of bytes copied to the buffer. If an error occurs or the buffer is too small, the function returns zero.


EngineRealizeFont

The EngineRealizeFont function creates an engine font having attributes and an appearance that matches those specified by the given logical font and text appearance information. A driver calls this function, while processing calls to its RealizeObject function, to determine whether a suitable TrueType font exists.

WORD
  EngineRealizeFont(
    LPLOGFONT lplf,
    LPTEXTXFORM lpTextXForm,
    LPFONT lpFont
    );

Parmeters

lplf
Points to a LOGFONT structure specifying the attributes of the font to create.
lpTextXForm
Points to a TEXTXFORM structure specifying additional attributes of the font to create.
lpFont
Points to a FONTINFO structure or is NULL. If this parameter points to a structure, the function fills the structure with information about the engine font. Otherwise, the function returns the size (in bytes) of this information but does not return the information.

Return Value

The EngineRealizeFont function returns either a size or a Boolean value, depending on the value of the lpFont parameter. If lpFont is NULL, the function returns the size (in bytes) of the FONTINFO structure and any additional information needed to describe the engine font. If the return value is zero, the driver should not attempt to realize the engine font. If lpFont points to a FONTINFO structure, the function returns TRUE if it successfully realizes the engine font. Otherwise, it returns FALSE.

Comments

A driver must call this function twice: first to retrieve the size (in bytes) of the font information to be returned, and second to realize the engine font and retrieve the corresponding FONTINFO structure. The driver should then compare its own device fonts with the realized engine font (if any) to determine which font most closely matches the given logical font attributes.

A driver can use the high byte of the dfType field and the dfBitsOffset and dfBitsPointer fields for its own purpose. For example, a driver can set the dfBitsOffset field to point to additional information after the end of the FONTINFO structure and set the bits in the high byte of the dfType field to specify whether the font passed is an engine or device font. A driver can use this information when GDI returns the FONTINFO structure in a call to the StrBlt or ExtTextOut function.


EngineRealizeFontExt

The EngineRealizeFontExt function enables a Glyph Index and creates a glyph indexed engine font having attributes and an appearance that matches those specified by the given logical font and text appearance information. A driver calls this function, while processing calls to its RealizeObject function, to determine whether a suitable TrueType font exists.

PVOID
  EngineRealizeFontExt (
    LPPDEVICE lpDestDev,
    LPLOGFONT lplf,
    LPTEXTXFORM lpTextXForm,
    LPFONT lpFont,
    BOOL Reserved
    );

Parameters

lpDestDev
Points to a PDEVICE or PBITMAP structure specifying the device or bitmap for which the physical object is created.
lplf
Points to a LOGFONT structure specifying the attributes of the font to create.
lpTextXForm
Points to a TEXTXFORM structure specifying additional attributes of the font to create.
lpFont
Points to a FONTINFO structure or is NULL. If this parameter points to a structure, the function fills the structure with information about the engine font. Otherwise, the function returns the size (in bytes) of this information but does not return the information.
Reserved
Reserved. Do not set.

Return Value

The EngineRealizeFontExt function returns either a size or a Boolean value, depending on the value of the lpFont parameter. If lpFont is NULL, the function returns the size (in bytes) of the FONTINFO structure and any additional information needed to describe the engine font. If the return value is zero, the driver should not attempt to realize the engine font. If lpFont points to a FONTINFO structure, the function returns TRUE if it successfully realizes the engine font. Otherwise, it returns FALSE.

Comments

A driver must call this function twice: first to retrieve the size (in bytes) of font information to be returned, and second to realize the engine font and retrieve the corresponding FONTINFO structure. The driver should then compare its own device fonts with the realized engine font (if any) to determine which font most closely matches the given logical font attributes.

A driver can use the high byte of the dfType field and the dfBitsOffset and dfBitsPointer fields for its own purpose. For example, a driver can set the dfBitsOffset field to point to additional information after the end of the FONTINFO structure and set bits in the high byte of the dfType field to specify whether the font passed is an engine or device font. A driver can use this information when GDI returns the FONTINFO structure in a call to the StrBlt or ExtTextOut function.

EngineRealizeFontExt should never be called with an ATM font. Therefore, call GetModuleHandle (ATM) to determine if ATM is running before making the Engine call.


EngineSetFontContext

The EngineSetFontContext sets the current engine font to the given font. The function directs GDI and the TrueType rasterizer to precompute values to be used with this font. A driver must call this function prior to calling the EngineGetGlyphBmp function.

void
  EngineSetFontContext(
    LPFONTINFO lpFont,
    WORD wCharRot
    );

Parameters

lpFont
Points to a FONTINFO structure specifying the font to be set. The structure must have been previously filled using the EngineRealizeFont function.
wCharRot
Specifies the angle of rotation (in tenths of a degree, counterclockwise) for the current font.

Return Value

The EngineSetFontContext function has no return value.


RealizeObject

The RealizeObject function creates or deletes a physical object. The function creates a physical object by filling a structure provided by GDI with device-specific data that corresponds to the attributes of a given logical pen, brush, bitmap, or font. It deletes the physical object by removing any memory or resources it allocated when creating the object.

WORD
  RealizeObject(
    LPPDEVICE lpDestDev,
    WORD wStyle,
    LPVOID lpInObj,
    LPVOID lpOutObj,
    LPTEXTXFORM lpTextXForm
    );

Parameters

lpDestDev
Points to a PDEVICE or PBITMAP structure specifying the device or bitmap to create the physical object for.
wStyle
Specifies the type of object to be realized. This parameter can be one of the following values.
Value | Description
OBJ_PEN | Realizes a physical pen.
OBJ_BRUSH | Realizes a physical brush.
OBJ_FONT | Realizes a device font. If the device has no device fonts or cannot realize the requested font, the RealizeObject function returns zero.
OBJ_PBITMAP | Realizes a device bitmap. GDI passes this value only if the RC_DEVBITS value is set in the dpRaster member of the driver's GDIINFO structure.

If the wStyle parameter is negative, the function deletes the specified object.

lpInObj
Points to an LPEN, LBRUSH, LFONT, or PBITMAP structure specified by the wStyle parameter. The structure describes the logical attributes of the object to be realized.

If wStyle is negative, the lpInObj parameter points to the PPEN, PBRUSH, FONTINFO, or PBITMAP structure, specifying the physical object to be deleted.

lpOutObj
Points to a buffer to receive the realized object, or points to the physical object to delete. Its meaning depends on the value of the wStyle parameter.

If wStyle is positive, the lpOutObj parameter points to a buffer. The function fills the buffer with device-specific data that defines a physical object corresponding to the logical object pointed to by the lpInBuf parameter. If lpOutObj is NULL, the function returns the size, in bytes, of the physical object.

If wStyle is negative, lpOutBuf points to the physical object to delete. Although GDI frees the memory pointed to by lpOutBuf when the function returns, the RealizeObject function must free any other memory or resources associated with the physical object.

lpTextXForm
Points to a TEXTXFORM structure or specifies a POINT structure as specified by the wStyle parameter.

If wStyle is OBJ_BRUSH, the lpTextXForm parameter is a POINT structure containing the x and y coordinates (relative to an 8-bit boundary) on which to align the start of the brush's pattern.

If wStyle is OBJ_FONT, lpTextXForm points to a TEXTXFORM structure containing information about the appearance of a realized font. Both the realized font and the contents of the TEXTXFORM structure are later passed to the ExtTextOut function, allowing more capable devices to make changes to the standard font.

Return Values

If unsuccessful, the RealizeObject function returns zero. If successful and if lpOutObj is NULL, it returns the size in bytes of the physical object. If successful and if lpOutObj is not NULL, it returns one of the following values.

Condition | Return value
For solid brushes for a monochrome DC | 8001h
For solid brushes for a color DC | 8002h
For all other brush styles and objects | 8000h

Comments

When GDI is just requesting the size of the font, use EngineRealizeFont which returns the size of the font.

The return value after realization of the font is 0x8000. In any event, EngineRealizeFontExt should never be called with an ATM font. Therefore, call GetModuleHandle ("ATM") to determine if ATM is running before making the Engine call.

Value | Description
GetCharWidth: | If the font is a glyph indexed font, the PF_GLYPH_INDEX flag will be set in the FontInfo->dfType.
ExtTextOut: | To ensure complete compatibility, check that both wOptions is set to ETO_GLYPH_INDEX and FontInfo->dfType is set for glyph indexes fonts in the PF_GLYPH_INDEX flag.

Since Glyph ID 32 (the space character) may now be an actual character, call GetFontData for return value data for a glyph. If it does not, then do not download an empty glyph.

If you choose to support downloading TrueType fonts as Bitmaps, be aware that ATM causes problems with glyph index fonts. Therefore, it is recommended that Windows® 95 and Windows® 98 print drivers always call the new EngineGetGlyphBmpExt function for TrueType fonts. The parameters for EngineGetGlyphBmpExt are the same as for EngineGetGlyphBmp.

The 32-bit resource compiler must be used with a flag (-40) to make it a Windows 95 only driver.


Image Color Management

The following topics discuss how Image Color Management (ICM) support may be added to Windows® 95 and Windows® 98 print drivers.

Overview of ICM

INF File Syntax for Profile Installation

Initiating Image Color Management

System-Controlled Color Management

ICM-Enabled Printer Drivers

Partial ICM Support in the Driver

ICM-Aware Applications (Windows 98 only)

Windows 95 Compatibility

Sample Code for Printer Profiles

Image Color Management Reference


Overview of ICM

The International Color Consortium (ICC) has specified an industry standard file format for device color characterization information. ICM technology in Windows uses these ICC profiles to move color into and out of device color space to produce more accurate colors in output devices.

In order to take advantage of ICM, printer vendors should ship ICC profiles that characterize their devices. These profiles are specified as dependent files in the INF file and are installed in the system as part of the INF-based printer installation. An example is provided in INF File Syntax For Profile Installation.

If the printer vendor is providing an installation program, this program should copy the profiles to the COLOR directory and call standard Win32® APIs to install the profiles in the system. It should also associate those profiles with the printer being installed.


INF File Syntax For Profile Installation

In the following example , the printer named "My printer model" has two ICM profiles: profile1.icm and profile2.icm. Note that the destination directory for color profiles is 23, which refers to the COLOR directory.

[Version]
Signature="$CHICAGO$"
Class=Printer
Provider="My Company"

[My Company]
"My printer model" = MYDRIVER,My_Printer_Model

[MYDRIVER]
DriverFile=DRVR.DRV
DataFile=DRVR.DRV
CopyFiles=@DRVR.DRV,MY COLOR PROFILES
DataSection=MYDATA

[MYDATA]
HelpFile=DRVR.HLP
DefaultDataType=EMF

[MY_COLOR_PROFILES]
profile1.icm
profile2.icm

[DestinationDirs]
DefaultDestDir=11
MY_COLOR_PROFILES =23


Initiating Image Color Management

There are two ways in which ICM can be initiated:

  • An application calls SetICMMode(hdc, ICM_ON), which begins the ICM for the device context specified by hdc. SetICMMode is described in the Platform SDK documentation.
  • An application or printer driver sets the dmICMMethod member of the DEVMODE to DMICMMETHOD_SYSTEM, DMICMMETHOD_DRIVER, or DMICMMETHOD_DEVICE. The application must do this at CreateDC time or by the printer driver at DevEnable time. If ICM is initiated this way, only device independent bitmaps (DIBs) are color corrected.

When ICM begins for a printer DC, the system checks to see if any color profiles are associated with that printer instance. If there are profiles associated, the operating system looks through each one of them to find the most appropriate profile for the current device settings as specified by the DEVMODE structure. The operating system specifically tries to match the current resolution, media type, and dithering mode to find a match. If more than one profile is found to match the current settings, the first profile is used. If no match is found or there are no profiles associated with the device instance, it uses the system supplied sRGB profile.


System-Controlled Color Management

The recommended approach for printer vendors is to let the operating system handle color management. This is the default situation if the driver does not fully conform to ICM. In this case, if ICM is turned on, the operating system automatically corrects the colors of all pens, brushes, and DIBs. These automatic decisions are based on the input and output color spaces before passing these objects to the device driver. This results in vastly improved color reproduction on the printer. By having the operating system control these functions, the print driver is not required.


ICM-Enabled Printer Drivers

If a printer vendor believes there is added value in providing ICM functionality in the driver or in the device hardware, the driver can inform the GDI device that it is an ICM-enabled printer driver. It does this by setting the C1_ICM bit in the dpCaps1 field of the GDIINFO structure during a DevEnable call.

In this case, the printer driver needs to define and export the functions in the following list. Except for CMColorInfo, these functions are described in the Platform SDK documentation.

CMCheckColorsInGamut

CMColorInfo

CMCreateTransform

CMDeleteTransform

CMGetInfo

CMTranslateRGB

CMTranslateRGBs

These functions are called by the operating system to allow the driver to provide the necessary ICM support. Whenever any of these functions are called, the driver checks the dmICMMethod member of the DEVMODE structure to determine whether ICM on the host has been selected. If it has been selected, the driver calls the GDI device using the following helper functions. The operating system continues to perform the color management. If the driver itself is ICM enabled, its functions are always called instead.

The following is a list of valid GDI callback functions.

ICMCheckColorsInGamut

ICMCreateTransform

ICMDeleteTransform

ICMGetInfo

ICMTranslateRGB

ICMTranslateRGBs

If the dmICMMethod member of the DEVMODE structure specifies that ICM should be done in the driver or the graphics device, the driver should not call GDI but should instead manage its own color transform and translate the colors as requested by the operating system. When a drawing call comes to the driver, the ICMCXform member of the DRAWMODE structure contains the driver-created transform function that performs the color transformations.


Partial ICM Support in the Driver

It is sometimes desirable for a printer driver to report that it is ICM enabled simply for performance reasons. If the operating system is to color correct large DIBs, it needs to allocate a memory buffer. The color correction occurs in this buffer and is passed to the driver. This can result in performance loss. To alleviate this problem, a printer driver can report that it is ICM enabled, and the DIB pointer is passed to the driver first. The driver can then allocate a small amount of memory and use the operating system to color correct bands of the image.

This is achieved by returning 2 when queried for CMS_DRIVER_LEVEL by the CMGetInfo function. Such drivers are called Level 2 ICM-enabled drivers. This condition supercedes the operating system and allows the driver to color correct the DIB. Pens and brushes are already corrected by the operating system before calling the driver.

Level 2 drivers export all the CM Xxx functions except CMColorInfo. As the driver does not perform it own color correction, it should call back into GDI through helper functions to actually perform the desired task and return this back to the caller.

When the driver's StretchDIB function is called, it needs to allocate the required memory and call ICMTranslateRGBs to color correct the DIB (in bands if desired) before sending it to the printer. The ICMCXform field of the DRAWMODE structure that comes in this DDI should be used as the hcmTransform parameter of the ICMtranslateRGBs function.

When the system needs to create a color transform, the system calls the driver's CMCreateTransform function. The driver in turn calls the operating system's ICMCreateTransform function. If a pen or a brush color needs correction, the operating system calls CMTranslateRGB or CMTranslateRGBs. The driver in turns calls the operating system's helper function which then initiates the intended action. When a DIB needs to be drawn, the operating system passes the color transformation into the hcmTransform field of the DRAWMODE structure and calls the driver's StretchDIB function. At that point, the driver then color corrects the DIB by calling ICMTranslateRGBs.complete this.


ICM-Aware Applications

Windows 98 only

Some printer drivers do proprietary color manipulation if ICM is not turned on. In some cases where an application has already color corrected the drawing objects (using ICM outside the DC), the driver needs to make sure it does not perform any correction on these colors. The application calls SetICMMode(hdc, ICM_DONE_OUTSIDEDC) or SetICMMode(hdc, ICM_OFF) to specify that no more color correction takes place. This call is conveyed to the printer driver by the system using the Control DDI as follows:

#define ICMMODESTATUS 5000
Control(LPPDEVICE, ICMMODESTATUS, lpInData, NULL);

The lpInData parameter points to a WORD, which is set to the fEnableICM parameter of the SetICMMode function.


Windows 95 Compatibility

In Windows® 95, ICM profiles are implicitly associated with printer models. This is different from Windows® 98 and later, where ICM profiles are explicitly associated with printer instances using the AssociateColorProfileWithDevice function. The implicit association is accomplished with the following procedure. When looking for profiles associated with a printer model, the operating system computes a four-byte manufacturer ID and a four-byte model ID from the model name of the printer using the algorithm in Sample Code for Printer Profiles. It then assumes that all profiles which specify this combination of manufacturer ID and model ID in their header belong to this model.

There are often situations where multiple models from the same manufacturer have similar color characteristics and the same color profile(s) can be used for these models. This is a problem due to the implicit association done by the operating system, since the manufacturer needs to duplicate the profiles but have different model IDs. This leads to wasted disk space. To circumvent this problem, Windows 95 allows the printer driver to specify the manufacturer ID and model ID by calling DeviceCapabilities(DC_ICC_MANUFACTURER) and DeviceCapabilities(DC_ICC_MODEL) before it does its automatic computation.

If the driver specifies these IDs, then Windows 95 searches for profiles with these IDs. This allows a driver supporting different models with the same color profiles to always return the IDs specified in the profiles. Windows 95 uses the same set of profiles for both printer models.

To support Windows 95 drivers that have this behavior, Windows 98 continues to call DeviceCapabilities, and if a manufacturer and model ID is returned, it mimics Windows 95 behavior to search for profiles. However, this results in loss of functionality in Windows 98:

  • Profiles are associated with printer models instead of printer instances
  • Profiles explicitly associated by the user with the printer instance are ignored.

Therefore, printer vendors writing drivers that run on Windows 95/98/Me should support these device capabilities but return a failure code at run time if they are running on Windows 98/Me.


Sample Code for Printer Profiles

The following sample code searches for printer profiles and the corresponding four-bytes manufacturer ID and model IDs.

void GetManuAndModelIDs( PTSTR pModelname,
                         PTSTR pManu,
                         PTSTR pModel )
{
  DWORD  dwCheckSum, dwSize;
  int    i;
  WORD wCRC16a[16]={
     0000000,    0140301,    0140601,    0000500,
     0141401,    0001700,    0001200,    0141101,
     0143001,    0003300,    0003600,    0143501,
     0002400,    0142701,    0142201,    0002100,
  };
  WORD wCRC16b[16]={
     0000000,    0146001,    0154001,    0012000,
     0170001,    0036000,    0024000,    0162001,
     0120001,    0066000,    0074000,    0132001,
     0050000,    0116001,    0104001,    0043000,
  };
  char  *pByte;
  char   temp;
  BYTE   bTmp;

  /*
   * Define the manufacturer to be the first 4 characters of the
   * device name. A space or a hyphen end the string, and the
   * remaining part of the string is filled with spaces.
   */
  pByte = pModelname;
  for (i=0; i<4; i++, pByte++)
  {
    if (*pByte == ' ' || *pByte == '-')
    {
       for (; i<4; i++)
       {
          pManu[i] = ' ';
       }
    }
    else
    {
       temp =  *pByte;
       if (temp >= 'a' && temp <= 'z')
           temp = temp + 'A' - 'a';
       pManu[i] = temp;
    }
  }
  pManu[4] = '\0';

  /*
   * Define the model to be a CRC of the complete DriverDesc
   * string. We use the same method that the PnP LPT
   * enumerator uses to create unique ID's.
   */
  dwCheckSum = 0;
  dwSize = lstrlen(pModelname);

  for (pByte=pModelname; dwSize; dwSize--, pByte++)
  {
     // Xor CRC with new char
     bTmp = (BYTE)(((WORD)*pByte)^((WORD)dwCheckSum));
     dwCheckSum = (dwCheckSum >> 8) ^ wCRC16a[bTmp & 0x0F] ^ wCRC16b[bTmp >> 4];
  }
  wsprintf(pModel, __TEXT("%X"), dwCheckSum);

  return;
}


Image Color Management Reference

The following function is supported.

CMColorInfo


CMColorInfo

The CMColorInfo function converts a logical color (a ColorRef value) to a physical color (a physical color value), or converts a physical color to a logical color, depending on the value of the lpPColor parameter.

COLORREF WINAPI
  CMColorInfo(
    LPPDEVICE  lpDestDev,
    DWORD  dwColorin,
    LPPCOLOR  lpPColor,
    HCMTRANSFORM  hcmTransform
    );

Parameters

lpDestDev
Points to a PDEVICE or PBITMAP structure specifying the destination device or bitmap.
dwColorin
Specifies either a logical or physical color, depending on the value of the lpPColor parameter.
lpPColor
Points to a PCOLOR structure or is NULL. If lpPColor points to a PCOLOR structure, the function assumes that dwColorin specifies a logical color (an RGB value) and copies the physical color value that most closely matches the logical color to this structure. If lpPColor is NULL, the function assumes that dwColorin specifies a physical color and returns the logical color that matches the physical color.
hcmTransform
Handle of color transform to be used in transforming dwColorin.

Return Value

The return value is the logical color that most closely matches the physical color either specified by dwColorin, or copied to the PCOLOR structure pointed to by lpPColor.

Comments

The export ordinal for the CMColorInfo function is 33.

The CMColorInfo function is identical to ColorInfo. The added parameter refers to the transform to apply to the logical color in order to obtain the physical color.

When converting a logical color, CMColorInfo chooses the best possible physical color to match the logical color and returns the ColorQuad value that corresponds to this physical color.

GDI uses the physical colors returned by CMColorInfo to set text colors, background colors, and pixel colors using the Pixel function.

If dwColorin is a logical color, it will never specify color index.


Installing and Using USB Printers with Microsoft Windows

The following topics provide information that driver writers can use to support USB printers on Microsoft® Windows® 2000, Windows® Millennium Edition (Windows Me), Windows® 98, and Windows® 98 Second Edition.

Introduction to USB Printing with Microsoft Windows

USB and Parallel Port Printing Architecture on Windows Operating Systems

The USB Printer Installation Process

INFs for Installing USB Printing on Windows Operating Systems

Installing USB Printing on Windows Me and Windows 98

Writing a Cross-Platform INF to Install USB Printer Drivers

FAQ for USB Printer Installation


Introduction to USB Printing with Microsoft Windows

Microsoft® Windows® 2000 and Windows Millennium Edition (Windows Me) supply a general kernel-mode USB print driver, usbprint.sys, which works with the system-supplied port monitor usbmon.dll to provide end-to-end connectivity between USB printers and high-level printer drivers. Together these components make up the Microsoft USB printing solution.

Vendors are encouraged to write high-level printer drivers that rely on usbprint.sys rather than writing their own kernel-mode USB print drivers. Printer vendors can now redistribute usbprint.sys and usbmon.dll for installation on Windows 98 and Windows 98 Second Edition, making their Windows Me printing solutions backward-compatible with Windows 98. For information, contact Microsoft at USBWinPrint@microsoft.com.

Usbprint.sys greatly simplifies the task of writing a high-level printer driver:

  • Usbprint.sys handles kernel-mode operations such as power management on behalf of the high-level printer driver.
  • Usbprint.sys provides an interface very similar to that used by parallel printers, so it is possible for a single printer driver to work correctly on both USB and parallel port printers, without modification.
  • Usbprint.sys has been extensively tested with numerous printers, dongles, PCs, and mobile systems on the Windows 2000 operating system.

For maximum cross-platform compatibility, vendor-supplied printer drivers should not depend on proprietary device-control commands or any parallel port IOCTLs except for IOCTL_PAR_QUERY_DEVICE_ID. A printer driver that follows these guidelines can drive printers over both USB and a parallel port on Microsoft Windows 2000, Windows 98, Windows 98 Second Edition, and Windows Me operating systems.

Procedures for writing a printer driver are described in the Windows 2000 DDK documentation and in the Windows 98 DDK documentation. If such a driver is correctly implemented as described in the DDK documentation, the driver should "just work," because the printer driver installation mechanisms are the same on all three operating systems, over any bus.

Note usbprint.sys and usbmon.dll work together to simplify the task of writing a vendor-supplied language monitor. If a language monitor uses only the WritePort, ReadPort functions, and the IOCTL_PAR_QUERY_DEVICE_ID interface, it will be portable between USB and parallel port.


USB and Parallel Port Printing Architecture on Windows Operating Systems

The following figure shows the system-supplied and vendor-supplied components that can be involved in printing over USB and parallel ports on Windows operating systems.

Windows USB and Parallel Port Printing Architecture

The only required vendor-supplied component is the high-level printer driver, which is in the layer above the spooler. A vendor can optionally supply a language monitor that is in the layer between the spooler and usbmon.dll (for USB) or localmon.dll (for parallel port).

The preceding figure shows a vendor-supplied kernel-mode USB print driver (labeled IHV-supplied USB Print Driver) that is in the layer above the USB driver stack, and which consists of usbhub.sys, usbd.sys, and some layers underneath. In the past, a vendor-supplied USB print driver was needed for USB printing on Windows 98 operating systems, which did not include an in-box kernel-mode USB print driver.

Printer vendors can now redistribute the Microsoft-supplied USB print driver and port monitor, usbprint.sys and usbmon.dll, for installation on Windows 98 systems. Microsoft is encouraging vendors to redistribute usbprint.sys and usbmon.dll rather than writing their own USB print drivers and port monitors.


The USB Printer Installation Process

USB printer installation varies slightly over Windows 98, Windows Me, and Windows 2000 and later. This section gives the differences between the three operating systems in the context of the general USB printer installation process.

Driver selection is also influenced by digital signature and the driver signing policy in effect on the system. For information, see: http://whpg/hwdev/desinit/digitsign.htm.

In the USB printer installation process

  1. The user connects a USB printer to the PC for the first time.

    All systems The system displays the "Found New Hardware" message.

  2. The kernel-mode USB print driver is loaded.

    Windows 2000 On the basis of the USB printer's compatible ID (USB class code Class_07), Setup locates the system-supplied usbprint.inf and uses it to load usbprint.sys silently.

    Windows Me The Add Hardware Wizard appears. The user points to a vendor-supplied usbprint.inf or requests Windows Me to perform an automatic search for this file. After usbprint.inf is found, Setup uses it to install usbprint.sys.

    Windows 98 The Add Hardware Wizard appears. The user points to a vendor-supplied usbprint.inf. After usbprint.inf is found, Setup uses it to install usbprint.sys from the vendor-supplied product media.

  3. The high-level printer driver is installed.

    Windows 2000 Setup looks through ntprint.inf for a matching Hardware ID. If Setup finds an exact match in ntprint.inf, it installs the corresponding in-box driver. The user sees a message that lists the vendor name and model of the printer.

    Otherwise, the Add Hardware Wizard pops up again. The user points to the location of the vendor-supplied INF and driver files, which Setup uses to install the vendor-supplied printer driver.

    Windows Me Setup looks for a matching in-box printer driver and, if it finds one, loads that driver without prompting the user.

    Otherwise, the Add Hardware Wizard pops up again. The user points to the location of the vendor-supplied INF and driver files, which Setup uses to install the vendor-supplied printer driver.

    Windows 98 The Add Hardware Wizard appears and prompts the user to complete installation. The default installation point is the original vendor file location. Setup uses the vendor-supplied printer INF file to install the printer driver.

  4. The printer is fully installed and ready to print.


INFs for Installing USB Printing on Windows Operating Systems

This section presents two sample INF files that can be modified to install USB printing on Windows 98/Windows Me and Windows 2000 and later.

Vendors should supply unique Plug and Play hardware IDs (VID/PID) for their devices and modify the following examples as needed before including them in their driver packages.

Vendors should also prepare INFs as follows before submitting their driver packages to WHQL for testing and digital signature:

  • Use the ChkINF and INFCatReady utilities to validate the INFs for digital signature.

    ChkINF is provided in the Windows DDK. For information, see:
    http://www.microsoft.com/ddk/ddkdocs/win2k/chkinf.htm.

    INFCatReady can be downloaded from the WHQL web site. For information, see
    http://www.microsoft.com/hwtest

  • Submit the INFs with your driver package to WHQL for testing and digital signature. For information, see:
    http://www.microsoft.com/hwdev/desinit/digitsign.htm


Installing USB Printing on Windows Me and Windows 98

To ensure that USB printers continue to work correctly when a user upgrades from Windows 98 to Windows Me, usbprint.sys is supplied with the system but is not automatically installed on Windows Me. This avoids any possible incompatibility with a vendor-supplied kernel-mode USB print driver that might already be installed on the user's system.

To install Microsoft USB printing support on Windows 98 operating systems, printer vendors can use the same usbprint.inf file as for Windows Me and can redistribute the files usbprint.sys and usbmon.dll with their driver packages. (On Windows 2000, usbprint.inf is already on the system, so a vendor-supplied usbprint.inf is not needed.)

The following example shows a usbprint.inf file that can be used to install usbprint.sys on Windows 98 or Windows Me. Notice the following [CopyFiles] section in the INF:

[USBPRINT_Inst.CopyFiles]
usbprint.sys,,,16

This entry uses the COPYFLG_NO_OVERWRITE flag (hexadecimal 10, or decimal 16) to instruct Setup not to copy this file if it already exists on the system. This causes Setup to install usbprint.sys on Windows 98 and Windows 98 SE, but not on Windows Me. Usbprint.sys on Windows Me is a system-protected file and is already present, so this file does not need to be installed by a driver package.

[Version]
Signature="$CHICAGO$"
Class=USB
ClassGUID={36FC9E60-C465-11CF-8056-444553540000}
Provider=%MSFT%
DriverVer=12/17/1999
CatalogFile=print9x.cat

[ControlFlags]
ExcludeFromSelect = *
[DestinationDirs]
DefaultDestDir = 10,system32\drivers

[Manufacturer]
%MSFT%=Microsoft

[Microsoft]
%USBPRINT.DeviceDesc% = USBPRINT_Inst,USB\Class_07

[USBPRINT_Inst]
Copyfiles = USBPRINT_Inst.CopyFiles
AddReg    = USBPRINT.AddReg
DriverVer=12/17/1999

[USBPRINT_Inst.CopyFiles]
usbprint.sys,,,16

[USBPRINT.AddReg]
HKR,,DevLoader,,*ntkern
HKR,,NTMPDriver,,"usbprint.sys"

[SourceDisksNames]
1 = "USB disk",,,""

[SourceDisksFiles]
usbprint.sys = 1

[strings]
MSFT                  = "Microsoft"
USBPRINT.DeviceDesc   = "USB Printing Support"


Writing a Cross-Platform INF to Install USB Printer Drivers

This section describes a cross-platform printer INF that will install a USB or parallel printer driver on Windows 2000 or later, Windows Me, or Windows 98. This generic INF can also be used to install a parallel printer on Windows 95. Notice the following about this INF:

  • In the [DRIVER.DRV] section, the following entry ensures that the Microsoft-provided USB port monitor is installed under Windows 98:
    PortMonitor=usbmon.dll,usbmon.dll
  • In the [MONITOR] section, the following entry instructs Setup not to copy this file if it already exists on the system:
    usbmon.dll,,,16

    This entry uses the COPYFLG_NO_OVERWRITE flag (hexadecimal 10) to instruct Setup not to copy this file if it already exists on the system. This causes Setup to install usbmon.dll on Windows 98 and Windows 98 SE, but not on Windows Me. Usbmon.dll on Windows Me is a system-protected file that is already present, so this file does not need to be installed by a driver package.

.

[Version]
Signature="$CHICAGO$"
Class=Printer
ClassGUID={4d36e979-e325-11ce-bfc1-08002be10318}
Provider=%MS%
CatalogFile=print9x.cat
CatalogFile.NT=print2K.cat
DriverVer=1/1/2000,4.00.2450.1

; The Manufacturer section lists all of the manufacturers that we will
; display in the Dialog box

[Manufacturer]
"Man"

[HP]
"Man printer" = DRIVER.DRV,MYPNPID

[DRIVER.DRV.NT]
; Windows 2000 printer driver installation entries go here.

[DRIVER.DRV]
; Windows 95/98/Me printer driver installation entries go here.

CopyFiles=@DRIVER.DRV,UNICLR,FINSTALL,MONITOR
DataSection=UNI_DATA
PortMonitor=usbmon.dll,usbmon.dll
DriverVer=1/1/2000,4.00.2450.1

[MONITOR]
usbmon.dll,,,16

[FINSTALL]
finstall.dll
finstall.hlp

[UNICLR]
iconlib.dll
dmcolor.dll
unidrv.dll
unidrv.hlp

[UNI_DATA]
HelpFile=unidrv.hlp
DefaultDataType=EMF

[DestinationDirs.NT]
DefaultDestDir=66000

[DestinationDirs]
DefaultDestDir=11

[SourceDisksNames.NT]
2  =  %Disk2%,,,""

[SourceDisksNames]
1  =  %Disk1%,,,""

[SourceDisksFiles.NT]
;NT files to install

[SourceDisksFiles]
printer.inf  = 1
finstall.dll = 1
finstall.hlp = 1
driver.drv   = 1
iconlib.dll  = 1
dmcolor.dll  = 1
unidrv.dll   = 1
unidrv.hlp   = 1
usbmon.dll   = 1

[Strings]
MS="Microsoft"
Disk1="Win9x disk"
Disk2="Win2000 disk"


FAQ for USB Printer Installation

This section provides answers to some frequently asked questions about USB printer installation.

Q. If a user has installed my company's USB printing solution for Windows Me, what happens if a second vendor's solution tries to load?
A. The two solutions might conflict with each other and interfere with successful printing on the user's system. The operating system cannot detect or prevent such conflicts. It is recommended that vendors use the Microsoft USB printing solution.
Q. If my company supplies a top-to-bottom USB printing solution for Windows 98 and Windows Me, what is the mechanism for upgrading to the Microsoft USB printing solution?
A. Uninstall the vendor-supplied solution completely and then install the Microsoft solution. It should be possible for an update program to uninstall the vendor-supplied solution transparently, without requiring specific action on the part of the user. However, it is recommended that an update include instructions in case the user wants to perform these steps manually.
Q. If my company wants to use the Microsoft USB printing solution for Windows 98, what is the process for redistributing those files?
A. Contact Microsoft at USBWinPrint@microsoft.com for information about redistributing these files.
Q. My company has a USB printing solution for Windows Me. What is the process for driver signing? What files do I have to submit?
A. Submit your entire driver package to WHQL for testing and digital signature, as described at:
http://www.microsoft.com/hwdev/desinit/digitsign.htm
Q. If my company uses the Microsoft USB printing solution for Windows 98, what happens when the user upgrades to Windows Me or Windows 2000 or later?
A. The printer will continue to work. The user will not have to reinstall the printer after upgrading.
Q. If my company wants to redistribute usbprint.sys and usbmon.dll for Windows 98, do I have to resubmit the driver package to WHQL for testing?
A. A driver's digital signature is generated from the complete set of binaries in the driver package. Adding files or changing existing files in the package invalidates the existing digital signature. The driver package must be resubmitted to WHQL for testing and a new digital signature.


Internet Printing Protocol

Windows® Millennium Edition (Windows Me) ships with an Internet Printing Protocol (IPP) client. The IPP client is located in the Add-Ons directory of the CD, and is named IPPClient.exe. The IPP client can be selectively installed.

The Internet Printing Protocol client supports the industry-standard IPP 1.0 protocol and allows a user to print over the Internet. With the IPP client, your Windows computer can print to any IPP-enabled printer or to any printer running on a Windows 2000 or later print server over the Internet. Microsoft's IPP 1.0 client uses standard Internet protocols (HTTP on TCP port 80), so no special configuration of proxies or firewalls is required. If you can browse to the print server, you can also use IPP to print to it.

To install the Internet Printing Protocol client

  1. Double click IPPClient.exe.
  2. Click OK to reboot your machine.

    After you have installed the Internet Printing Protocol client, you can connect to a printer in either of two ways:

  3. Using a browser.
  4. Using the Add Printer Wizard.

To connect to a printer using a browser

  1. From your browser, go to the URL of the printer you want to connect to. (If you are connecting to a printer on a Windows 2000 or later print server, you can go to http://servername/printers to browse through a list of all the printers on that server.
  2. Click the name of the printer you want to connect to.
  3. Under Printer Actions on the left hand side, click Connect.

To connect to a printer using the Add Printer Wizard

  1. Open the Printers Folder.
  2. Double-click the Add Printer Wizard.
  3. Click Next on the welcome screen.
  4. Select Networked Printer, and then click Next.
  5. In the Network path or queue name text box, type the URL of the printer (i.e., http://servername/printers/myprinter), and then click Next.
  6. Select the manufacturer and model of the printer you are connecting to, and then click Next.
  7. Select Yes to print a test page, if you wish, then click Next.
  8. Click Finish.


WBEM/WMI SMBIOS Provider

SMBIOS (formerly known as DMI BIOS) provides information configured by the manufacturer about a PC. The SMBIOS entry point is in the F0000-FFFFF address block, which contains the 32-bit address of the SMBIOS structure data. The structure data can reside anywhere in the 0–4G address space. One of the last problems to solve in terms of supplying system instrumentation and management data for Web-Based Enterprise Management (WBEM) is surfacing the information present in SMBIOS.

Unfortunately, the BIOS ROM memory is inaccessible to user-mode applications on the Microsoft® Windows NT®/Windows® 2000 platform. To alleviate this, Microsoft modified the operating system. Windows® 2000 (from build 1773 onward) contains the relevant changes that provide access to the SMBIOS data as part of WBEM. The changes in Windows NT/Windows 2000 are designed to support SMBIOS 2.1, but also support SMBIOS 2.0 with some caveats:

  • If only the SMBIOS 2.0 calling mechanism is available, the aggregate size of all of the tables must be less than 4 KB. Only the first 4 KB is surfaced by way of Windows Management Instrumentation (WMI).
  • If only the SMBIOS 2.0 calling mechanism is available, any strings for tables other than tables zero to 22 are not collected. This is because tables 23 and higher are not defined; the SMBIOS 2.0 component cannot determine whether strings are present because the SMBIOS specification does not have a defining mechanism.

These restrictions do not apply if the SMBIOS data is presented using the SMBIOS 2.1 memory table format.

OEMs, IHVs, and ISVs can write a WBEM application that retrieves and parses data from the RawSMBiosTables Class from the WBEM WMI schema. An excerpt from the managed object format (MOF) file for the SMBIOS data is provided in the table in SMBIOS Table.

For information about MOF files and how to write WBEM applications, see the WBEM SDK, which was provided on the Windows NT/Windows 2000 WinHEC Special Edition DDK CD and will become part of the Microsoft Platform SDK.


SMBIOS Example

The schema for the raw SMBIOS information is reproduced in the following code extract.

// SMBIOS data classes
//
[abstract]
class WMISMmBios
{
};

[Dynamic, Provider("WMIProv"),
 WMI,
 Description("Raw SMBIOS Tables"),
 guid("{8F680850-A584-11d1-BF38-00A0C9062910}"),
 locale("MS\\0x409")

]
class RawSMBiosTables : WMISmBios
{
    [key, read]
     string InstanceName;
    [read] boolean Active;

    [WmiDataId(1),
     read
    ] uint32 Size;

    [WmiDataId(2),
     WmiSizeIs("Size"),
     read
    ] uint8 SMBiosData[];

};


SMBIOS Table

A representative list of information residing within SMBIOS is presented in the following table. This is not an exhaustive list.

Attr. ID | Description | Type
DMTF|ComponentID|001 |  |
 | 1. Component Id Group MIF Description |
1 | Manufacturer | String
2 | Product | String
3 | Version | String
4 | Serial Number | String
DMTF|System BIOS|001 |  |
DMTF|System BIOS|001 |  |
 | 4. System BIOS Group MIF Definition |
3 | Version | String
4 | BIOS ROM Size | Integer
5 | BIOS Starting Address | INT64
6 | BIOS Ending Address | INT64
8 | BIOS Release Date | DATE
DMTF|BIOS Characteristic|003 |  |
 | 5. BIOS Characteristic Group Definition |
1 | BIOS Characteristic Index | Integer
2 | BIOS Number | Integer
3 | BIOS Characteristics | ENUM
4 | BIOS Characteristics Description | String
 | Type |
 | Processor Family | ENUM
 | Processor Upgrade | ENUM
 | Number of Expansion Slots | Integer
 | 10. System Cache |
1 | System Cache Index | Integer
3 | System Cache Speed | Integer
4 | System Cache Size | Integer
5 | System Cache Write Policy | ENUM
 | 11. Parallel Ports |
5 | Connector Type | ENUM
6 | Connector Pinout | ENUM
8 | Parallel Port Capabilities | Integer
 | 19. System Slots |
1 | Slot Index | Integer
2 | Slot Type | INT64
3 | Slot Width | ENUM
4 | Current Usage | Integer
5 | Slot Description | String
6 | Slot Category | ENUM
7 | Virtual Slot | ENUM
8 | Resource User ID | Integer


Resources for WBEM/WMI SMBIOS Provider

  • For information about WBEM, WMI, and Win32® Extensions schema, see http://www.microsoft.com/management/wbem/ and http://wbem.freerange.com
  • See the overview of WMI and the white paper titled Adding WMI Code to a Driver in the Windows 98 DDK.
  • Windows Hardware Instrumentation Implementation Guide (WHIIG) from Intel and Microsoft. This documents the design requirements and recommendations for hardware developers who want to provide custom instrumentation data using the new Windows manageability infrastructure, including WBEM and WMI.
  • For information about this document, please send e-mail to whiig@microsoft.com with your name, e-mail name, company name, and address. You will be notified when this document is available.


Windows Management Instrumentation

This documentation contains an introduction to Windows Management Instrumentation (WMI), a kernel-level instrumentation technology for the Microsoft® Windows® platform.

WMI provides the basis for hardware instrumentation in future Windows environments. Close coupling of WMI with services developed to conform to the Web-Based Enterprise Management (WBEM) initiative will allow Microsoft to simplify instrumentation and provide consistent, open access to management data.

Both WMI and WBEM are key components in Microsoft's manageability and total cost of ownership containment efforts. WMI is integrated into both the Windows® 98 and Windows® 2000 kernel to provide driver data and events. WMI is an extensible design, and an original equipment manufacturer (OEM) or independent hardware vendor (IHV) can extend the instrumented data set.

The following topics are contained in this documentation:

What WMI Does

WMI and WBEM

WMI and DMI

WMI Support

Implementing WMI and WBEM

Reference Information


What WMI Does

WMI publishes information, configures device settings, and supplies event notification from device drivers. WMI is part of the Win32® Driver Model (WDM) architecture. However, it has broad utility and can be used with other types of drivers as well (such as SCSI and NDIS). WMI distributes the following data:

  • Published data — A standard set of WMI data will be built into the Windows 2000-supplied port/class drivers.
  • Custom data — Provided through OEM/IHV driver extensions.
  • Secure data — Provided through Windows NT®/Windows® 2000 security descriptors for a designated usage.
  • Expensive data (optional) — Some data collection activity can significantly affect the performance of the driver. Thus, this data should only be collected when the management application specifically requests it. By default, a driver will not collect the expensive data. When a management application using WBEM expresses interest in that expensive data, WMI signals the driver to start collecting the data. WMI also keeps a reference count and signals the driver to stop collecting the data when the last WBEM application interested in that data terminates. An important point to note is that the driver writer, not WMI, decides what data is expensive to collect. The mechanism for indicating that data is expensive to collect is extremely simple.
  • Event Notifications — Event notification is a key feature of WMI, allowing drivers to detect hardware events and/or errors. An event can then be passed to WBEM for corrective action based on the specific event that occurred. For example, a disk driver has an abnormally high amount of disk write/read errors, and it sends an event notification to a disk management utility. As another example, a Network Interface Card (NIC) detects the loss of the Ethernet signal and sends notification to a consumer of management data that is watching for events affecting the network.

WMI also allows a management application to configure a device, which may need to do this because of some driver-raised event or because of the data collected by the management application.

Note that the two key features of WMI are its extensibility and its event notification mechanism. WMI allows an IHV to extend the instrumentation data set and add value to a hardware/software solution. In addition, WMI provides a means for the driver writer to provide adequate notification of driver events. This eliminates situations where the driver detects a potentially disastrous situation and can only write an entry to the event log.


WMI and WBEM

WMI provides WBEM with yet another means for collecting and setting data and events. WBEM is a unifying architecture that allows access to data from a variety of underlying technologies — including Win32, WMI, the Desktop Management Interface (DMI), and the Simple Network Management Protocol (SNMP). WBEM is based upon the Common Information Model (CIM) schema, which is an industry standard driven by the Desktop Management Task Force (DMTF). WBEM details can be obtained from http://www.wbem.freerange.com.

WBEM provides a three-tiered approach for collecting and providing management data. This approach consists of a standard mechanism for storing data (a CIM-compliant database), a standard protocol for obtaining and disseminating management data (COM/DCOM; other protocols are also possible and under investigation), and a Win32 DLL known as a WBEM provider.

A WBEM provider supplies instrumentation data for parts of the CIM schema. Microsoft has written a WBEM provider (the WMI provider) that interfaces with the kernel mode WMI component. The kernel mode WMI component provides services that allow WMI-enabled drivers to implement WMI, and also acts as an interface to the WMI provider.

The specifications for writing a WBEM provider are freely available, as are code examples. An IHV/OEM that manufactures hardware and software for end users (for example, still-image scanner manufacturers and printer manufacturers) should consider writing a WBEM provider. For kernel components, the IHV/OEM should implement WMI.

The following diagram provides an overview of the WBEM/WMI architecture.


WMI and DMI

WMI was developed to provide a set of instrumentation capabilities that are tightly linked to the driver models found in the Windows family of operating systems. Additionally, because WMI uses the same schema as WBEM, it integrates extremely well into the three-tiered approach to instrumentation infrastructure. As WMI is focused on the task of instrumenting data, it uses WBEM both as the central management data repository and as the access point for management applications to this data. This fact makes it more appropriate to compare DMI to WBEM, rather than to WMI, as discussed in the following paragraphs.

Existing instrumentation technologies, such as DMI and SNMP, provide more of a two-tiered approach to instrumenting data and providing it to consumers of management data (these data consumers are typically management applications). The difficulty with this approach is that for a single consumer of management data to understand both DMI and SNMP data, the developer of the management application must do twice as much work — he or she must write an application that can understand two different systems of communicating and representing instrumented data. However, in the WBEM/CIM environment, the WBEM services provide an abstraction layer. Data from many sources can be provided to the CIM schema managed by WBEM (sources could include WMI, Win32, DMI, SNMP, and CMIP), and a management application can use WBEM to access all this data.

Besides the lack of a common abstraction layer, DMI does not provide a set of programming interfaces that are tightly integrated with the Windows operating system and its driver models. DMI was not designed with Windows Plug and Play and Power Management in mind. However, Microsoft understands that smooth migration of existing instrumentation technologies and management applications is key to the success of WBEM.

The WBEM infrastructure will provide a facility that maps DMI information into the CIM schema managed by WBEM. This capability is facilitated by WBEM's ability to support multiple instrumentation data providers — sample providers include those for WMI and Win32 data. Intel Corporation is developing the functionality to allow DMI data to be mapped into CIM, and conversely, to allow CIM data to be accessible to existing DMI- or WMI-based management applications.


WMI Support

The following topics describe the division of labor for supporting WMI between Microsoft, independent software vendors (ISVs), IHVs, and OEMs:

Microsoft

Management Application Vendors and Other ISVs

IHVs and OEMs


Microsoft

Microsoft will ship core WMI support in the operating system kernel and in a WMI driver for Windows® 98 and for Windows® 2000. These kernel and driver pieces will support WMI services for the benefit of other drivers. Microsoft will also instrument the bus, port, and class drivers, as well as other drivers shipping with Windows 2000, and will instrument the NDIS class driver shipping with Windows 98.

This instrumentation will allow these components to provide instrumentation data and will create a mapping mechanism for the class or port driver, if needed. The NDIS class driver uses a similar mapping mechanism to map I/O request packets (IRPs) to object identifiers (OIDs), and the SCSI port driver uses a mapping mechanism to map IRPs to stream request blocks (SRBs).

Microsoft's goal is to allow miniport driver writers to work with a familiar model]. For example, NDIS miniport driver writers can continue to work with OIDs, and SCSI miniport driver writers can continue to work with SRBs. The port/class driver maps these models to WMI as required.

Microsoft is also providing a WMI driver that maps Advanced Configuration and Power Interface (ACPI) data on Windows 2000. In addition, Windows 2000 will include a driver that exports SMBIOS 2.1 tables into WBEM in Windows 2000.


Management Application Vendors and Other ISVs

Management application vendors need to adopt WBEM and the industry standard CIM schema that WBEM implements. These vendors should pay particular attention to the Win32 portion of the CIM schema. This is the part of the schema that WBEM data providers, including WMI, populate with instrumentation information.

Some ISVs may be interested in writing a WBEM provider that can extend the instrumentation data set. The WBEM architecture encourages the writing of new providers. All required specifications and code samples are freely available.


IHVs and OEMs

IHVs and OEMs should see WMI as a technology that can add value to their hardware and differentiate it from that of a competitor. For example, NIC vendors can use WMI to send an event if a loosely plugged-in cable falls free and the Ethernet signal is lost. The NIC vendor can accomplish this by merely adding code to the NDIS miniport driver. The vendor does not need to write any WMI code. Other examples include sending temperature alerts, or detecting when the number of bad blocks or sectors on a hard disk drive have crossed a critical limit, or sending the appropriate notification. An IHV/OEM can write a new class driver, for example, to report temperature, fan control data, and so on, and can populate WBEM with the appropriate instrumentation information.


Implementing WMI and WBEM

The following topics describe the implementation process for WMI and WBEM:

Driver Writer Support

WMI Location

WBEM Location


Driver Writer Support

Any driver that receives IRPs (IRP_MJ_SYSTEM_CONTROL in particular) can be a WMI driver. Microsoft will add WMI support to the class or drivers so miniports can effectively benefit from WMI with very little extra work on the part of the miniport driver writer. Thus, the following types of drivers can have WMI code:

  • A driver that receives IRPs
  • A minidriver whose class or port driver has been modified (either by Microsoft or an IHV, ISV, or OEM) to support WMI

Note that IRP_MJ_SYSTEM_CONTROL must be supported by all devices. If a device does not use WMI, it must forward the IRP. If it does use WMI, it should process the IRP.

In Windows 98, the core WMI functionality exists. However, WMI support has been integrated into the NDIS class driver only. If a driver receives IRPs, then an OEM/IHV device driver writer can integrate WMI code into his or her driver in Windows 98.


WMI Location

The core infrastructure for supporting WMI for a WDM driver will ship with Windows® 98. Windows 98 will also include WMI support in the NDIS class driver. This means that NDIS miniport driver writers (such as NIC hardware vendors) can leverage WMI. An IHV or OEM writing a Windows 98 driver that receives IRPs can also leverage WMI.

The Windows 2000 Beta 1 shipped with core WMI support as well as WMI support in the NDIS class driver and the SCSI port driver. The diskperf driver, which shipped with the Windows NT® 4.0 DDK, has been updated to report its data using WMI.


WBEM Location

Microsoft has implemented a program whereby an IHV, OEM, or ISV can freely distribute WBEM binaries with their offerings, without incurring a royalty. This means that a single management solution is possible for all Win32 platforms. It also means that vendors do not need to wait until Windows 2000 becomes a significant contributor to their sales effort before they adopt WBEM and WMI. The WBEM Win32 provider provides significant instrumentation data by itself in the Windows 95 and Windows NT 4.0 environments. Later, OEMs and IHVs can add significantly to this data set by using WMI to provide custom instrumentation data for their customers who upgrade to Windows® 98 and Windows 2000.


Reference Information

You can address questions about WMI to wmiinfo@microsoft.com.

For current information on Windows 2000 Server, refer to http://www.microsoft.com/ntserver/ or the Windows 2000 Server Forum on the Microsoft Network (GO WORD: MSNTS).


Adding WMI Code to a Driver

This documentation describes what a driver must do in order to be WMI aware. For complete documentation on implementing these capabilities in a driver, refer to the Microsoft® Windows® 2000 DDK.


Introduction

Windows Management Instrumentation (WMI) is a middleware layer that allows measurement and instrumentation information to be collected from kernel mode data providers and then to be provided to local or remote user-mode data consumers through the use of a common set of interfaces (Web-based enterprise management called WBEM). WMI is a data-independent pipeline between the data consumer and the data provider and makes no assumptions about the format of the data sets.

WMI allows both a push and pull model for data delivery; data consumers can poll or register for events generated by the data provider. Data consumers are user-mode applications or services, while data providers can be kernel-mode drivers. This documentation describes what a WDM-compliant device driver needs to do in order to provide data and events to WMI.

WMI provides mechanisms for:

  • Publishing instrumentation data
  • Configuring device settings

    WMI allows method execution and setting of data blocks in the device driver. For example, an IR device driver can define a data block that has information about how the IR device is configured. The IR device can be reconfigured by performing a WMI set or executing a WMI method.

  • Publishing custom data
  • Event notification
  • Efficient data collection

    WMI provides a mechanism for a driver to efficiently collect data that is expensive to collect. Driver writers who are implementing WMI within their code can decide which data is expensive to collect. By default, data blocks that are marked as expensive to collect are not enabled for collection. When a management application accesses one of these data blocks, WMI signals the driver to start collecting data. When the last management application accessing an expensive data block closes access to the data block, WMI signals the driver to stop collecting data.

  • Data security

    WMI provides a security mechanism for the data. An administrator can configure security such that certain data generated through WMI is only available to certain users or groups.

The WMI architecture allows the device driver flexibility in defining and naming the data to be provided. However, this flexibility imposes some complexity. To simplify the task of the driver writer, WMILIB provides support routines for handling most of the WMI functionality. Most devices do not need the complete flexibility of writing directly to WMI and can use WMILIB instead.


WMI Considerations for Drivers that Receive IRPs

Any driver that receives and processes IRPs can be a WMI driver. Microsoft will modify some, but not all, of the class/port drivers that ship with Windows® 98 and Windows® 2000 to provide WMI support. These class/port drivers receive IRPs and have a private interface to their miniport drivers. The private interface will be extended to support WMI.

A driver that receives IRPs needs to meet the following requirements in order to provide WMI functionality:

  • The driver needs to register its device object with WMI.
  • The driver needs to publish its schema to indicate the nature of the data the driver will provide.
  • The driver needs to handle WMI IRP_MJ_SYSTEM_CONTROL IRPs.
  • The driver needs to manage instance names for the data blocks it provides.

Notice that those device drivers that do not register with WMI to provide data still must forward the IRP_MJ_SYSTEM_CONTROL_IRPs to the next device in the device stack. The following topics describe these IRPs in detail.


Device Registration Requirements

Any driver that has a device object and wants to be a WMI data provider must register its device object with WMI. After the device has been initialized enough to handle receiving WMI IRPs, the driver should call IoWMIRegistrationControl, passing the device object and setting Action to WMIREG_ACTION_REGISTER.

When the device no longer wishes to be a WMI data provider, possibly at the point a device realizes that it is going away, the driver should call IoWMIRegistrationControl with Action set to WMIREG_ACTION_DEREGISTER.

If a device changes radically and wants to completely reregister the set of GUIDs that it supports, it should call IoWMIRegistrationControl with Action set to WMIREG_ACTION_REREGISTER.

If the device wants to change the static instance names of the GUIDs already supported or to add or remove support for GUIDs, it should call IoWMIRegistrationControl with Action set to WMIREG_ACTION_UPDATE_GUID.


IoWMIRegistrationControl

The IoWMIRegistrationControl routine informs WMI of the existence and disappearance of a device object that would support WMI.

NTSTATUS IoWMIRegistrationControl(
    IN PDEVICE_OBJECT  DeviceObject,
    IN WMIREGACTION    Action
)

Parameters

DeviceObject
Pointer to device object that supports WMI.
Action
Registration action code. The following codes are provided.
Code | Description
WMIREG_ACTION_REGISTER | If set action is to inform WMI that the device object supports and is ready to receive WMI IRPS.
WMIREG_ACTION_DEREGISTER | If set action is to inform WMI that the device object no longer supports and is not ready to receive WMI IRPS.
WMIREG_ACTION_REREGISTER | If set action is to requery the device object for the GUIDs that it supports. This has the effect of deregistering, followed by registering.
WMIREG_ACTION_UPDATE_GUIDS | If set action is to query for information that is used to update already registered GUIDs.

Return Value

Returns a status code.


Schema Publication Requirements

WMI requires a driver to provide schema information in the managed object format (MOF) syntax by including it directly as a resource in the device driver file. The resource should be of type RT_RCDATA and have a name consistent with that passed to WMI when the device registers its WMI information. If no name is passed, WMI will assume that the resource name is WmiMOF. WMI will read the MOF information from the resource and install it into the WBEM schema database automatically the first time that the device driver registers its data blocks.

The device driver should only include MOF for data blocks that are unique to that driver. Standard blocks whose schema and GUID are defined by WMI are automatically installed to the WMI schema database by WMI and should not be included in the driver's schema definition.

A driver writer should create a.MOF file that contains the MOF description for all the data blocks it provides. The driver's build process should then use the MOFComp tool to compile the MOF into a binary file and then reference that binary file from the .RC file.

Important If the MOF is not provided with the operating system or the device driver, then data consumers will not be able to access the data.

For detailed information on schema and schema design considerations, see WMI Schema Description.


IRP Support Requirements

WMI defines 10 minor IRP codes for IRP major code IRP_MJ_SYSTEM_CONTROL. These IRPS are used to interface with device drivers that register as WMI data providers. Each minor code represents a different action that the driver can perform and can take up to four pointers, which are members of the WMI structure, that are passed in the IRP stack. All WMI IRPs are dispatched at PASSIVE_LEVEL.

struct {
    UINT_PTR  ProviderId;
    PVOID     DataPath;
    ULONG     BufferSize;
    PVOID     Buffer;
} WMI

Members

ProviderId
Designates the device within the device stack to which the IRP is targeted. Upon reception of the IRP, the driver should inspect ProviderId. If it does not match the WMI provider ID of the device, then the driver must forward this request to the next device in the stack because this indicates that the IRP is intended for a device residing lower in the driver stack. If ProviderId matches that of the device, the driver should process the request and complete the IRP returning success or an error, as appropriate.
DataPath
Pointer to the GUID representing the data block being enabled, disabled, queried, or set. WMI sets the WNODE_FLAG_STATIC_INSTANCE_NAME flag for static instance data blocks and passes instance names as indexes into the list registered by the data provider. WMI resets the flag and passes the full instance name text for data blocks registered as dynamic instance name providers.
Buffersize
Specifies the actual or maximum length of the buffer respectively, depending on the minor function code. If BufferSize is smaller than what is needed to fill the appropriate WNODE response, the data provider should instead fill in a WNODE_TOO_SMALL. If BufferSize is smaller than sizeof(WNODE_TOO_SMALL), then the driver should return an error of STATUS_BUFFER_TOO_SMALL.
Buffer
Pointer to the input and/or output buffer. This buffer is always nonpaged.


IRP_MN_QUERY_ALL_DATA

The driver receives an IRP_MN_QUERY_ALL_DATA to query for all instances of a data block. It is passed a GUID as the DataPath. If DataPath is valid, the driver should fill the WNODE_ALL_DATA appropriately and complete the IRP.

Members

ProviderId
Contains the WMI provider ID of the device that should respond to this request.
DataPath
Points to a GUID that represents the data to be returned.
BufferSize
Specifies the maximum size available to fill the WNODE_DATA_ALL into the output buffer.
Buffer
Points to the buffer to return WNODE_ALL_DATA.

Return Value

Returns STATUS_SUCCESS or STATUS_WMI_GUID_NOT_FOUND.


IRP_MN_QUERY_SINGLE_INSTANCE

The driver receives an IRP_MN_QUERY_SINGLE_INSTANCE to query for a single instance of a data block.

Members

ProviderId
Contains the WMI provider ID of the device that should respond to this request.
DataPath
Points to a GUID that represents the data to be returned.
BufferSize
Specifies the maximum size available to write the WNODE_SINGLE_INSTANCE into the buffer.
Buffer
Points to a WNODE_SINGLE_INSTANCE that the driver should fill in with the result of the query.

Return Value

Returns STATUS_SUCCESS, STATUS_WMI_INSTANCE_NOT_FOUND, or STATUS_WMI_GUID_NOT_FOUND.


IRP_MN_CHANGE_SINGLE_INSTANCE

The driver receives an IRP_MN_CHANGE_SINGLE_INSTANCE to change all data items in a single instance of a data block. The driver should use new values passed in the WNODE_SINGLE_INSTANCE to change the values of the data block and complete the IRP. The driver should ensure that any attempt to modify data items that are read-only are ignored.

Members

ProviderId
Contains the WMI provider ID of the device that should respond to this request.
DataPath
Points to a GUID that represents the data to be returned.
BufferSize
Specifies the size of the WNODE_SINGLE_INSTANCE that contains the new values for the data block.
Buffer
Points to a WNODE_SINGLE_INSTANCE that contains the new values for the data block.

Return Value

Returns STATUS_SUCCESS, STATUS_WMI_INSTANCE_NOT_FOUND, STATUS_WMI_GUID_NOT_FOUND, STATUS_WMI_READ_ONLY, or STATUS_WMI_SET_FAILURE.


IRP_MN_EXECUTE_METHOD

The driver receives an IRP_MN_EXECUTE_METHOD to execute a method associated with a data block.

Members

ProviderId
Contains the WMI provider ID of the device that should respond to this request.
DataPath
Points to a buffer that specifies the GUID that identifies the method to be executed.
BufferSize
Specifies the maximum size available to fill the WNODE_METHOD_ITEM that is returned from the method invocation.
Buffer
Points to the WNODE_METHOD_ITEM that on entry describes the method called and contains the input data block. On exit, it is filled with the returned data block. If the WnodeMethodItem->DataBlockOffset is zero on entry, then no data is passed as input to the method. If it is set to zero on return, then no data is returned from the method call.

Return Value

Returns STATUS_SUCCESS, STATUS_WMI_INSTANCE_NOT_FOUND, or STATUS_WMI_GUID_NOT_FOUND.


IRP_MN_CHANGE_SINGLE_ITEM

The driver receives an IRP_MN_CHANGE_SINGLE_ITEM to change a single data item in a single instance of a data block. The driver should use new values passed in the WNODE_SINGLE_ITEM to change the value of the data item and complete the IRP. The driver should ensure that any attempt to modify data items that are read-only are ignored.

Members

ProviderId
Contains the WMI provider ID of the device that should respond to this request.
DataPath
Points to a GUID that represents the data to be returned.
BufferSize
Specifies the size of the buffer that contains the new value for the data item in the data block.
Buffer
Points to a WNODE_SINGLE_ITEM that contains the new value for the data item in the data block.

Return Value

Returns STATUS_SUCCESS, STATUS_WMI_INSTANCE_NOT_FOUND, STATUS_WMI_INSTANCE_ID_NOT_FOUND, STATUS_WMI_GUID_NOT_FOUND, STATUS_WMI_READ_ONLY, or STATUS_WMI_SET_FAILURE.


IRP_MN_ENABLE_EVENTS

When the driver receives an IRP_MN_ENABLE_EVENTS, the driver should verify that the GUID pointed to by the DataPath is a valid GUID representing an event and, if so, enable the event and complete the IRP. Support for this IRP is required for all drivers that support generating events.

WMI will manage any reference counting issues in the case that multiple data consumers have requested notification for events associated with the data item. The driver should not expect a second enable without having received an intervening disable. Also, a driver only needs to generate an event once; WMI will ensure that any data consumer who has registered for that event notification will receive the event.

Members

ProviderId
Contains the WMI provider ID of the device that should respond to this request.
DataPath
Points to the GUID of the event to enable.

Return Value

Returns STATUS_SUCCESS, STATUS_WMI_GUID_NOT_FOUND, or STATUS_INVALID_DEVICE_REQUEST.


IRP_MN_DISABLE_EVENTS

When the driver receives an IRP_MN_DISABLE_EVENTS, the driver should verify that the GUID pointed to by DataPath is a GUID representing a valid event and, if so, disable the event and complete the IRP. Support for this IRP is required for all drivers that support generating events.

WMI will manage any reference counting issues in the case that multiple data consumers have requested notification for events associated with the data item. The driver should not expect a second disable without having received an intervening enable. Also, a driver only needs to generate an event once; WMI will ensure that any data consumer who has registered for that event notification will receive the event.

Members

ProviderId
Contains the WMI provider ID of the device that should respond to this request.
DataPath
Points to the GUID of the event to enable.

Return Value

Returns STATUS_SUCCESS, STATUS_WMI_GUID_NOT_FOUND, or STATUS_INVALID_DEVICE_REQUEST.


IRP_MN_ENABLE_COLLECTION

The driver receives an IRP_MN_ENABLE_COLLECTION to inform it that it should begin data collection of data for the data block specified by DataPath. Only those devices that register data blocks with the WMIREG_FLAG_EXPENSIVE flag will receive this IRP. DataPath points at a GUID for the data block being collected and the driver should enable collection for all instances of the data block. The driver should verify that the DataPath is valid and, if so, enable collection for data blocks and continue.

WMI will manage any reference counting issues in the case that multiple data consumers have requested that collection for a data block be enabled. The driver should not expect a second enable without having received an intervening disable, with the exception that an enable for all instances of a data block may be received after receiving an enable for a single instance of a data block.

Members

ProviderId
Contains the WMI provider ID of the device that should respond to this request.
IrpStack->Parameters.WMI.DataPath
Points to the GUID of the data block to begin collecting.

Return Value

Returns STATUS_SUCCESS, STATUS_WMI_GUID_NOT_FOUND, or STATUS_INVALID_DEVICE_REQUEST.


IRP_MN_DISABLE_COLLECTION

The driver receives an IRP_MN_DISABLE_COLLECTION to inform it that it should cease collection of data for the data block specified by DataPath. Only those devices that register data blocks with the WMIREG_FLAG_EXPENSIVE flag will receive this IRP. DataPath points at a GUID for the data block and the driver should disable collection for all instances of the data block. The driver should verify that the DataPath is valid and, if so, disable collection for data blocks and continue.

WMI will manage any reference counting issues in the case that multiple data consumers have requested that collection for a data block be enabled. The driver should not expect a second disable without having received an intervening enable.

Members

ProviderId
Contains the WMI provider ID of the device that should respond to this request.
DataPath
Points to the GUID of the data block to stop collecting.

Return Value

Returns STATUS_SUCCESS, STATUS_WMI_GUID_NOT_FOUND, or STATUS_INVALID_DEVICE_REQUEST.


IRP_MN_REGINFO

The driver receives an IRP_MN_REGINFO to query for registration or registration update information. If the ProviderId passed is that of the device, then the driver should check DataPath to determine if registration or update information is being requested.

If DataPath is set to WMIREGISTER, then registration information is being queried. If it is set to WMIUPDATE, then registration update information is being queried. The driver should then fill the buffer passed in Buffer with one or more WMIREGINFO structures. If BufferSize passed is less than the size needed for all of the queried information, then Buffer should be filled with a DWORD specifying the size needed and an STATUS_BUFFFER_TOO_SMALL error returned.

Members

ProviderId
Contains the WMI provider ID of the device that should respond to this request.
DataPath
Contains the value WMIREGISTER or WMIUPDATE.
BufferSize
Contains the maximum size available in Buffer to which the provider can write its registration information.
Buffer
Points to a buffer that the data provider should use to fill in the registration information (WMIREGINFO structure).

Return Value

Returns STATUS_SUCCESS or STATUS_BUFFER_TOO_SMALL.


Supporting Structures

The following data structures describe the list of data blocks that the device driver registers.

WMIREGINSTANCEREF

typedef struct {
    UINT_PTR ProviderId;     // Provider ID (or device object pointer) of the data
                             // provider whose instance names are to be copied.
    GUID Guid;               // Guid of data block provided by ProviderId whose
                             // instance names are copied.
} WMIREGINSTANCEREF;

WMIREGGUID

typedef struct {
    GUID Guid;             // Guid of data block being registered or updated
    ULONG Flags;           // Flags
    ULONG InstanceCount;   // Count of static instances names registered for the GUID
    UINT_PTR InstanceInfo; // Offset from beginning of the WMIREGINFO structure to
                           // more information about the static instance names being
                           // registered.
                           // If WMIREG_FLAG_INSTANCE_PDO is set then InstanceInfo
                           // has the PDO whose device instance path will become
                           // the instance name.
                           // If WMIREG_FLAG_INSTANCE_LIST then this is an offset to a
                           // list of InstanceCount counted UNICODE strings placed
                           // end to end.
                           // If WMIREG_FLAG_INSTANCE_BASENAME then this is an offset to a
                           // single counted UNICODE string that has the basename
                           // for the instance names.
} WMIREGGUID, *PWMIREGGUID;

#define WMIREG_FLAG_EXPENSIVE          0x00000001 // Set if collection must be enabled
#define WMIREG_FLAG_INSTANCE_LIST      0x00000004 // Set if static instance names
#define WMIREG_FLAG_INSTANCE_BASENAME  0x00000008 // Set if static instance names created
                                                  // with a base name and index
#define WMIREG_FLAG_INSTANCE_PDO       0x00000020

// These flags are only valid in a response to WMI_GUID_REGUPDATE
#define WMIREG_FLAG_REMOVE_GUID       0x00001000  // Remove support for this GUID

WMIREGINFO

typedef struct {
    ULONG BufferSize;         // Size of entire WMIREGINFO structure including this
                              // ULONG and any static instance names that follow
    ULONG NextWmiRegInfo;     // Offset to next WMIREGINFO structure
    ULONG RegistryPath;       // Offset from beginning of WMIREGINFO structure to a
                              // counted Unicode string containing the driver
                              // registry path (under HKLM\CCS\Services). This
                              // must be filled only by kernel-mode data providers.
    ULONG MofResourceName;    // Offset from beginning of WMIREGINFO structure to a
                              // counted Unicode string containing the name of
                              // resource in driver file containing MOF info
    ULONG GuidCount;          // Count of WMIREGGUID structures immediately following
    WMIREGGUID WmiRegGuid[];  // array of GuidCount WMIREGGUID structures
    // Variable length data including :
    //     Instance Names
} WMIREGINFO;

Comments

When a device receives an IRP_MN_REGINFO, it must return one or more WMIREGINFO structures. To return multiple WMIREGINFO structures, NextWmiRegInfo must be filled in with the offset from the beginning of the buffer to the beginning of the next WMIREGFINFO structure being returned.

The RegistryPath and MofResourceName fields are only filled in response to a registration query (DataPath set to WMIREGISTER); the flag WMIREG_FLAG_REMOVE_GUID is only used in response to a registration update query (DataPath set to WMIUPDATE).

In responding to a registration query, the driver must fill the RegistryPath field of the WMIREGINFO structure so WMI can determine the path of the device driver image file. As an example, consider a driver named DriverName; each device supported by that driver must pass "DriverName" in the RegistryPath field. WMI uses the standard rules for finding the path name of a device driver.

If the value ImagePath exists under the driver's registry key (HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\DriverName), then it specifies the fully-qualified path to the driver's image file. If this value is not specified, the default path is %SystemRoot%\system32\drivers\DriverName.Sys.

The response to a registration query should contain all the GUIDs representing the data and event blocks supported by the device and the number and names of the instances of the data block represented by the GUID (for a static instance data block).

It is recommended that the device driver register using the WMIREG_FLAG_PDO_INSTANCENAMES flag to allow WMI to generate instance names based upon the device instance ID for the PDO.

To specify that the instance names for a data block are static, a provider should set one of these flags: WMIREG_FLAG_INSTANCE_LIST, WMIREG_FLAG_INSTANCE_BASENAME or WMIREG_FLAG_PDO_INSTANCENAMES; InstanceCount should be set to the number of instances that are provided for the GUID. If WMIREG_FLAG_INSTANCE_LIST is set, then the data provider passes a list of instance names pointed to by InstanceInfo.

If WMIREG_FLAG_INSTANCE_BASENAME is set, then InstanceInfo points to a base name to which an instance count is appended. For example, if a GUID is registered with an InstanceCount of 3 and a base name of ToasterPort, then the instance names would be ToasterPort1, ToasterPort2, and ToasterPort3. If a driver registers or updates a data block to have static instance names, it must not place instance names in the WNODE_ALL_DATA structures when responding to a query for instances of that data block. It must also expect that WNODE_SINGLE_INSTANCEs and WNODE_SINGLE_ITEMs received do not have the actual text of the instance name, but have an index into the list of instances registered. Any requests sent to a data provider that registered static instance names have the WNODE_FLAG_STATIC_INSTANCE_NAME flag set in the flags of the WNODE header.

In responding to a registration update query, the data provider can use the WMIREG_FLAG_REMOVE_GUID flag. If WMIREG_FLAG_REMOVE_GUID is set, the GUID specified in the WMIREGGUID structure is removed from the list of data blocks supported by the device. If WMIREG_FLAG_REMOVE_GUID is not set, the GUID information specified in the WMIREGGUID is used to update the information previously maintained by WMI about the data block or to add the GUID to the list of data blocks supported by the device. This can be used to update the static instance names and static data blocks of a data block. Note that if no flag is set then and there is no change to the GUID registration, no action is taken with respect to the GUID specified. This allows the same WMIREGINFO structure to be used for both registration and registration update queries.

There may be a case in which a class driver handles the WMI registration request on behalf of a miniport driver, and both the class driver and miniport want to register GUIDs. There will be one IRP_MN_REGINFO request received by the class driver that will need to return two WMIREGINFO structures: one for the common GUIDs of the class driver and one for the specific GUIDs of the miniport. This situation is handled by building both WMIREGINFO structures in the returned buffer and placing the offset to the second WMIREGINFO structure from the beginning of the buffer in the NextWmiRegInfo field of the first WMIREGINFO structure. Within the last WMIREGINFO structure, or the only WMIREGINFO structure in the case of only one being returned as a result of the query, the NextWmiRegInfo field must be set to zero to indicate the end of the chain.


Managing Expensive Statistics

Some data blocks are expensive to maintain when no data consumers are actively interested in the information. If collection of a data block impacts the performance of a driver, WMI requires that a data provider specify that the data block be told when to begin and end data collection.

When the driver registers the data block, it should set the WMIREG_FLAG_EXPENSIVE flag in the Flags field of the WMIREGGUID structure. This will cause WMI to notify the driver when a data consumer is interested in the data block. WMI will manage any reference-counting issues in the case of multiple data consumers being interested in a data block. The notification is done using WMI IRPs with minor codes IRP_MN_ENABLE_COLLECTION and IRP_MN_DISABLE_COLLECTION.


Generating Events

An event is considered to be a query result pushed by the data provider to any data consumer who has registered to accept it. Any data block can be an event; WMI makes no distinction between data blocks and event blocks. Events should be used for exceptional events in the life of a device, because there are a limited number of events that can be queued at one time.

Event items should be defined as small-sized data types because there is a fixed size limit of 1Kb for the entire WNODE_EVENT_ITEM containing the generated event, although this can be overridden using the registry. For very large notifications, a WNODE_EVENT_REFERENCE can be fired. WNODE_EVENT_REFERENCE specifies a single instance of a data block that is queried by WMI to obtain the actual event data. Also, there is no guarantee for the timeliness for delivery of events to the user-mode data consumer. Events may only be fired at a level equal to or less than DPC level.

Drivers should be designed so their events are off by default. When a data consumer registers for an event associated with an event item within a data block, it will register with WMI and WMI will send an IRP_MN_ENABLE_EVENTS containing the DataPath of the GUID that represents the event. When all data consumers have unregistered for the event, WMI will send an IRP_MN_DISABLE_EVENTS with the DataPath of the data item that is the event to disable it. WMI will manage any reference counting issues in the case that multiple data consumers register for event items from the same GUID.

Events are fired in a WNODE_EVENT_ITEM data structure that can contain WNODE_ALL_DATA, WNODE_SINGLE_INSTANCE, or WNODE_SINGLE_ITEM. A device driver can fire an event by calling the kernel-mode IoWMIWriteEvent function at PASSIVE_LEVEL or DPC_LEVEL. This function queues the WNODE_EVENT_ITEM passed for delivery to all user-mode agents that have registered for the event. A data provider should only need to fire the same event once.


IoWMIWriteEvent

The IoWMIWriteEvent routine queues the passed WNODE_EVENT_ITEM for delivery to the user-mode agent. Once the event is delivered, the WNODE_EVENT_ITEM buffer will be returned to the nonpaged pool. This routine must be called at a level equal to or less than DPC_LEVEL.

NTSTATUS IoWMIWriteEvent(
    IN PVOID WnodeEventItem
    )

Parameters

WnodeEventItem
Pointer to WNODE_EVENT_ITEM that contains event information. This must be allocated from nonpaged pool if this routine is called at a level higher than PASSIVE.

The ProviderID and the Wnode size, which is the BufferSize field in the WNODE_HEADER structure, must be specified in the WNODE_HEADER structure passed in WnodeEventItem.

Return Value

Returns STATUS_SUCCESS or an error code.


WMILib

WMILib is a set of functions that manage the IRP_MJ_SYSTEM_CONTROL IRPs and the WNODE data formats. WMILIB is appropriate only for those devices that do not need the flexibility of dynamic instance names. WMILib is only available on Windows NT/Windows 2000.

The device should build a WMILIBINFO structure that contains information about the GUIDs being registered, the device stack in which it resides, and callbacks for various WMI functions. The QueryWmiRegInfo and QueryWmiDataBlock callbacks must be implemented. However, if the other callbacks are set to NULL, then WMILIB will return an appropriate error message.


Supporting WMILib Structures

The WMILIB_INFO structure is a control block that allows WMILIB to register the correct GUIDs, and call back the right WMI functions.

WMILIB_INFO

typedef struct _WMILIB_INFO {

// Next device lower in the stack
    PDEVICE_OBJECT LowerDeviceObject;

// PDO associated with device
    PDEVICE_OBJECT LowerPDO;

// WMI data block GUID registration info
    ULONG GuidCount;
    PGUIDREGINFO GuidList;

// WMI functionality callbacks
    PQUERY_WMI_REGINFO       QueryWmiRegInfo;
    PQUERY_WMI_DATABLOCK     QueryWmiDataBlock;
    PSET_WMI_DATABLOCK       SetWmiDataBlock;
    PSET_WMI_DATAITEM        SetWmiDataItem;
    PEXECUTE_WMI_METHOD      ExecuteWmiMethod;
    PWMI_FUNCTION_CONTROL    WmiFunctionControl;
} WMILIB_INFO, *PWMILIB_INFO;

GUIDREGINFO

typedef struct {
    GUID Guid;            // Guid to registered
    ULONG InstanceCount;  // Count of Instances of Datablock
    ULONG Flags;          // Additional flags (see WMIREGINFO in wmistr.h)
} GUIDREGINFO, *PGUIDREGINFO;


PQUERY_WMI_REGINFO

The PQUERY_WMI_REGINFO routine is a callback into the driver to retrieve information about the GUIDs being registered. Unlike any of the other WMILib callbacks, this routine should not complete the IRP.

typedef NTSTATUS (*PQUERY_WMI_REGINFO) (
    IN PDEVICE_OBJECT DeviceObject,
    OUT PULONG RegFlags,
    OUT PUNICODE_STRING Name,
    OUT PUNICODE_STRING *RegistryPath
    );

Parameters

DeviceObject
Device whose registration information is needed.
RegFlags
Returns with a set of flags that describe the GUIDs being registered for this device. If the device wants enable and disable collection callbacks before receiving queries for the registered GUIDs, then it should return the WMIREG_FLAG_EXPENSIVE flag. Also, the returned flags may specify WMIREG_FLAG_INSTANCE_PDO, in which case the instance name is determined from the PDO associated with the device object. Note that the PDO must have an associated devnode. If WMIREG_FLAG_INSTANCE_PDO is not set, then Name must return a unique name for the device.
Name
Returns with the instance name for the GUIDs if WMIREG_FLAG_INSTANCE_PDO is not set in the returned RegFlags. The caller will call ExFreePool with the buffer returned.
RegistryPath
Returns with the registry path of the driver.

Return Value

Returns a status code.


PQUERY_WMI_DATABLOCK

The PQUERY_WMI_DATABLOCK routine is a callback into the driver to query for the contents of all instances of a data block. When the driver has finished filling the data block, it must call IoWMICompleteRequest to complete the IRP. The driver can return STATUS_PENDING if the IRP cannot be completed immediately.

typedef NTSTATUS (*PQUERY_WMI_DATABLOCK) (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN ULONG GuidIndex,
    IN ULONG InstanceIndex,
    IN ULONG InstanceCount,
    IN OUT PULONG InstanceLengthArray,
    IN ULONG BufferAvail,
    OUT PUCHAR Buffer
    );

Parameters

DeviceObject
Device whose data block is being queried is the IRP that makes this request.
Irp
To be provided.
GuidIndex
Index into the list of GUIDs provided when the device registered.
InstanceIndex
Index that denotes which instance of the data block is being queried.
InstanceCount
Number of instances of the data block expected to be returned for the data block.
InstanceLengthArray
Pointer to an array of ULONG that returns the lengths of each instance of the data block. If this is NULL, then there was not enough space in the output buffer to fulfill the request so the IRP should be completed with the buffer needed.
BufferAvail
On entry, has the maximum size available to write the data blocks.
Buffer
On return, is filled with the returned data blocks. Note that each instance of the data block must be aligned on an eight-byte boundary. If this is NULL, then there was not enough space in the output buffer to fulfill the request. Thus, the IRP should be completed with the buffer needed.

Return Value

Returns a status code.


PSET_WMI_DATABLOCK

The PSET_WMI_DATABLOCK routine is a callback into the driver to set the contents of a data block. When the driver has finished filling the data block, it must call IoWMICompleteRequest to complete the IRP. The driver can return STATUS_PENDING if the IRP cannot be completed immediately.

typedef NTSTATUS (*PSET_WMI_DATABLOCK) (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN ULONG GuidIndex,
    IN ULONG InstanceIndex,
    IN ULONG BufferSize,
    IN PUCHAR Buffer
    );

Parameters

DeviceObject
Device whose data block is being set.
Iro
IRP that makes this request.
GuidIndex
Index into the list of GUIDs provided when the device registered.
InstanceIndex
Index that denotes which instance of the data block is being set.
BufferSize
Size of the data block passed.
Buffer
New values for the data block.

Return Value

Returns a status code.


PSET_WMI_DATAITEM

The PSET_WMI_DATAITEM routine is a callback into the driver to set the contents of a single data item within a data block. When the driver has finished filling the data block, it must call IoWMICompleteRequest to complete the IRP. The driver can return STATUS_PENDING if the IRP cannot be completed immediately.

typedef NTSTATUS (*PSET_WMI_DATAITEM) (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN ULONG GuidIndex,
    IN ULONG InstanceIndex,
    IN ULONG DataItemId,
    IN ULONG BufferSize,
    IN PUCHAR Buffer
    );

Parameters

DeviceObject
Device whose data block is being set.
Irp
IRP that makes this request.
GuidIndex
Index into the list of GUIDs provided when the device registered.
InstanceIndex
Index that denotes which instance of the data block is being set.
DataItemId
Has the ID of the data item being set.
BufferSize
Size of the data item passed.
Buffer
New values for the data item.

Return Value

Returns a status code.


PEXECUTE_WMI_METHOD

The PEXECUTE_WMI_METHOD routine is a callback into the driver to execute a method. When the driver has finished filling the data block, it must call IoWMICompleteRequest to complete the IRP. The driver can return STATUS_PENDING if the IRP cannot be completed immediately.

typedef NTSTATUS (*PEXECUTE_WMI_METHOD) (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN ULONG GuidIndex,
    IN ULONG InstanceIndex,
    IN ULONG MethodId,
    IN ULONG InBufferSize,
    IN ULONG OutBufferSize,
    IN OUT PUCHAR Buffer
    );

Parameters

DeviceObject
Device for whose data block a method is being executed.
Irp
IRP that makes this request.
GuidIndex
Index into the list of GUIDs provided when the device registered.
InstanceIndex
Index that denotes which instance of the data block is being called.
MethodId
ID of the method being called.
InBufferSize
Size of the data block passed in as the input to the method.
OutBufferSize
On entry has the maximum size available to write the returned data block.
Buffer
On entry has the input data block and on return has the output data block.

Return Value

Returns a status code.


WMIENABLEDISABLEFUNCTION

typedef enum {
    WmiEventGeneration,
    WmiDataBlockCollection
} WMIENABLEDISABLEFUNCTION;


PWMI_FUNCTION_CONTROL

The PWMI_FUNCTION_CONTROL routine is a callback into the driver to enable or disable event generation or data block collection. A device should only expect a single enable when the first event or data consumer enables events or data collection, and a single disable when the last event or data consumer disables events or data collection. Data blocks will only receive collection enable/disable if they were registered as requiring it.

typedef NTSTATUS (*PWMI_FUNCTION_CONTROL) (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN ULONG GuidIndex,
    IN WMIENABLEDISABLEFUNCTION Function,
    IN BOOLEAN Enable
    );

Parameters

DeviceObject
Device whose data or event block is being enabled or disabled.
Irp
To be provided.
GuidIndex
Index into the list of GUIDs provided when the device registered.
Function
Specifies which functionality is being enabled or disabled.
Enable
If TRUE, then the function is being enabled. Otherwise, it is disabled.

Return Value

Returns a status code.


IoWMICompleteRequest

The IoWMICompleteRequest routine completes a WMI IRP. Depending on the WMI request, this routine will fix the returned WNODE appropriately.

NTSTATUS IoWMICompleteRequest(
    IN PWMILIB_INFO WmiLibInfo,
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN NTSTATUS Status,
    IN ULONG BufferUsed,
    IN CCHAR PriorityBoost
    );

Parameters

WmiLibInfo
WMI information control block.
DeviceObject
Supplies a pointer to the device object for this request.
Irp
Supplies the IRP making the request.
Status
Return status code for the IRP
BufferUsed
Number of bytes needed by the device to return the data requested in any query. In the case that the buffer passed to the device is too small, this has the number of bytes needed for the return data. If the buffer passed is large enough, then this has the number of bytes actually used by the device.
PriorityBoost
Value used for the IoCompleteRequest call.

Return Value

Returns a status code.


IoWMISystemControl

The IoWMISystemControl routine is the dispatch routine for IRP_MJ_SYSTEM_CONTROL. This routine processes all WMI requests received and forwards them if they are not for this driver. Otherwise, the routine determines if the GUID is valid and, if so, passes it to the driver-specific function for handing WMI requests. This routine may only be called at PASSIVE_LEVEL.

NTSTATUS IoWMISystemControl(
    IN PWMILIB_INFO WmiLibInfo,
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    );

Parameters

WmiLibInfo
WMI information control block.
DeviceObject
Supplies a pointer to the device object for this request.
Irp
Supplies the IRP making the request.

Return Value

Returns a status code.


IoWMIFireEvent

The IoWMIFireEvent routine will fire a WMI event using the data buffer passed. This routine may be called at or below DPC_LEVEL.

NTSTATUS IoWMIFireEvent(
    IN PWMILIB_INFO WmiLibInfo,
    IN PDEVICE_OBJECT DeviceObject,
    IN ULONG GuidIndex,
    IN ULONG EventDataSize,
    IN PVOID EventData
    );

Parameters

WmiLibInfo
WMI information control block.
DeviceObject
Supplies a pointer to the device object for this event.
GuidIndex
Index into the GUID List within the WmiLibInfo control block for the GUID of the event.
EventDataSize
Number of bytes of data that is being fired with the event.
EventData
Data that is fired with the events.

Return Value

Returns a status code.


Data Set Organization

WMI data is organized into components (typically one per device driver), each of which may have multiple sets of data items. A set of data items is referred to as a data block. Each data block is assigned a unique GUID that is the mechanism by which WMI distinguishes blocks. Individual data items within a block are identified by a data item ID that is unique within the block.

A data provider can provide zero or more instances of a data block. An instance of a data block is a separate set of data items for the identical block. For example, a network driver might provide a standard block of data and could provide two instances of it: one instance for connection1 and one for connection2. Multiple data providers can also supply different instances of the same data block, particularly in the case of a standard data block. Therefore, each data provider is assigned a provider ID that WMI uses to distinguish the different data providers. A driver should use the pointer to its device object as its provider ID.

All instances of a data block have an instance name. Instance names for data blocks that are represented by the same GUID must be unique. Data providers should register data blocks whose instance names are static or slow changing as a static instance name data block. If a data block is not registered as a static instance name data block, then it is registered as a dynamic instance name data block.

Data blocks can contain both data and event items. A data item is a dynamic value that can be one of the following types: 32-bit integer, 64-bit integer, Unicode string, octet string (buffer of BYTE), timestamp (LARGE_INTEGER or string based), or an array of the preceding types. Unicode strings (or WCHAR arrays) are always preceded by a USHORT value that contains the count of characters in the string. These strings do not need to be NULL terminated and the count does not include any NULL terminator.

The LARGE_INTEGER timestamp format is in units of 100 nanoseconds since January 1, 1601. The string-based timestamp format is a fixed format string that specifies an exact date and time or interval. Data items may be read-only and the device driver must ensure that they are not overwritten because WMI does not enforce read-only attributes for specific data items.

WMI makes no assumptions about the contents of the data item other than its size. An event item is identical to a data item with the exception that a data provider can also push the changed value of the event item back to any data consumer that registered for the notification change, while a data item is only polled for by a data consumer.

WMI forwards queries and changes to data providers in WDM device drivers using IRPs. Data consumers assume that each call will return consistent data. For example, a request for multiple data items or multiple instances must return consistent information; the sum over all instances of % processor time should be N*100, where N is the number of processors. Data consumers also expect that requests to device drivers be completed with minimal overhead because performance monitors may be sampling the data items. Data providers should only provide raw data values and leave it to the data consumers to perform any calculations.

For more information, see Data Item Data Format.


Instance Name Management Requirements

Instance names are used by management applications to associate the information returned in a data block to the physical device or software component that generated the information. WMI uses the instance name to determine to which device a request should be routed. Therefore, it is required that all instance names for different instances of a data block be unique. Because instances of a data block may come from different drivers, WMI automatically detects an instance name collision and mangles the instance name in some cases.

A data provider can register or update each data block that it provides to have either dynamic or static instance names. A data provider should register a data block to have static instance names when the number of instances or their names change slowly because a data provider must call IoWMIRegistrationControl for each change. Static instance names optimize WMI requests because the data provider does not need to return the instance names in the WNODE_ALL_DATA query results. Also, rather than a full instance name being specified in the WNODE_SINGLE_INSTANCE and WNODE_SINGLE_ITEM, an instance index is specified. When registering, a data provider can specify the full instance names for each instance or a base name to which WMI appends an index. WMI detects instance name collisions for static instance data blocks at registration and automatically mangles their names.

A data block should be registered with dynamic instances when the count of instances or their names change frequently. Examples might be data blocks whose instances names are the process ID of a process or the IP address of a TCP/IP connection. When the instance names or count change, no notification of WMI is required. However, all WNODEs passed to the data provider or returned from the data provider must have the full instance name specified. In addition, the data provider must ensure that each instance name is unique among all providers of that dynamic data block because WMI does not detect instance name collisions for dynamic instance data blocks.

WMI provides the IoWMIAllocateInstanceIds function to let devices that provide dynamic instance names allocate a range of instance IDs for a GUID that are guaranteed to be unique. A data provider can use this function if it is concerned that the dynamic instance names chosen by it for a particular GUID might not be unique.

For example, the first time this function is called with a GUID of {C8FF15D0-7402-11d0-A839-00AA0060D45C}, it is also passed with InstanceCount set to 3 and *FirstInstanceId returns 1. The next time this function is called with that GUID, it is passed InstanceCount set to 1 and *FirstInstanceId returns 4. The first caller must append 1 to its first instance name, 2 to its second, and 3 to its third, while the second caller would append 4 to its instance name.


IoWMIAllocateInstanceIds

The IoWMIAllocateInstanceIds routine allocates a range of instance IDs that are unique to the GUID. This routine is to be called only at PASSIVE_LEVEL.

NTSTATUS IoWMIAllocateInstanceIds(
    IN GUID *Guid,
    IN DWORD InstanceCount,
    OUT DWORD *FirstInstanceId
    )

Parameters

Guid
Pointer to GUID for which instance IDs are needed.
InstanceCount
Count of instance IDs to allocate.
*FirstInstanceId
Returns first instance ID in the range.

Return Value

Returns a status code.

If not using WMIREG_FLAG_PDO_INSTANCENAMES, great care should be taken in determining the instance names for a data block. This is because these names are used as part of the UI for management and performance monitoring applications. Instance names should be consistent with instance names of related data blocks and names used in other UI for configuring or viewing the device. Instance names should also be as descriptive as possible.

For example, if two joysticks are installed in a machine and each chose an instance name of "Joystick" you might end up with instance names of "Joystick1" and "Joystick2" (WMI automatically mangled the instance name suffix). A better approach would be for one joystick driver to register an instance name of "Sidewinder 3D Joystick" and the other "XYZ Joystick". In the former case, it would be difficult for a management application to determine which joystick was the Sidewinder 3D.

The best approach for assigning static instance names is to use WMIREG_FLAG_PDO_INSTANCENAMES. This allows WMI to use the device instance ID of the PDO for the device as a base name. This approach promotes unique instance names and allows the caller to query a related GUID that will retrieve all the plug and play device information for the device, including a friendly name.

WMI provides the IoWMISuggestInstanceName function that can be used by a driver to help pick an appropriate instance base name. If specified, the function uses the physical device object (PDO) passed to obtain a friendly name or a device description name as the suggested instance name. Or if SymbolicLinkName is passed, the function uses it to obtain the friendly name for the device that was assigned that symbolic link name and uses that as the suggested instance name. If both are passed and CombineNames is TRUE, then the function will combine the names and return the combined name as the suggested instance name.


IoWMISuggestInstanceName

The IoWMISuggestInstanceName routine is used by a device driver to suggest a base name that may be used to build WMI instance names for the device. A driver is not bound to follow the instance name returned.

NTSTATUS IoWMISuggestInstanceName(
    IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
    IN PUNICODE_STRING SymbolicLinkName OPTIONAL,
    IN BOOLEAN CombineNames,
    OUT PUNICODE_STRING SuggestedInstanceName
    )

Parameters

PhysicalDeviceObject
PDO of device for which a suggested instance name is being requested
SymbolicLinkName
Symbolic link name returned from IoRegisterDeviceClassAssociation.
CombineNames
If TRUE, then the suggested names arising from the PhysicalDeviceObject and the SymbolicLinkName are combined to create the resultant suggested name.
SuggestedInstanceName
Supplies a pointer to an empty (that is, Buffer field set to NULL) UNICODE_STRING structure which, upon success, will be set to a newly-allocated string buffer containing the suggested instance name. The caller is responsible for freeing SuggestedInstanceName->Buffer when it is no longer needed.

Note If CombineNames is TRUE, then both PhysicalDeviceObject and SymbolicLinkName must be specified. Otherwise, only one of them must be specified.

Return Value

Returns a status code.


WMI Considerations for Class/Port Drivers

Class drivers are drivers that receive IRPs and translate the IRPs into a private interface with miniport drivers. An example is the ScsiPort class driver that receives IRPs and translates the IRPs into SRBs.

In order to provide the extensibility functionality that is at the heart of WMI, a class driver needs to interrogate its miniport drivers for WMI data blocks that they want to support and make the IoWMIxxxx call on their behalf.


WMI Considerations for Miniport Drivers

Miniport drivers do not receive IRPs and cannot directly support WMI. Miniport drivers that "plug" into class drivers supporting WMI can publish WMI data with the support of the class driver.

The following topics provide details for various miniport drivers. However, list is not exhaustive.


Tape MiniClass Drivers

Information to be provided in a future release..


SCSI Miniport WMI Requests

The new SRB function value SRB_FUNCTION_WMI will be added to support WMI requests. If the miniport supports this request, it should execute the request and notify the port driver when it has completed using the normal mechanism of ScsiPortNotification with RequestComplete and Next(Lu)Request. WMI requests will not be sent to the miniport unless WmiDataProvider is set to TRUE by the miniport in PORT_CONFIGURATION_INFORMATION.

This function overloads several of the fields in the SRB to contain WMI-specific parameters. In an SRB_FUNCTION_WMI request, the SRB's SenseInfoBuffer contains a pointer to the WMI data path for this request. The ScsiStatus field contains a WMI subfunction code indicating the type of WMI request being issued. The QueueAction field contains WMI-specific flags for this request.

If the flag SRB_WMI_FLAGS_ADAPTER_REQUEST is set in the WMI-specific flags, the WMI request is for the adapter. In this case, the PathId, TargetId, and Lun fields are reserved. Otherwise, the request is for a specific target device and the PathId, TargetId, and Lun fields contain the device's address.

The pointer in DataBuffer is mapped into kernel memory and can be used for direct access whether or not the miniport set MapBuffers during initialization. The miniport cannot transfer data directly into this buffer using DMA. Only the SRB Function, ScsiStatus, SrbFlags, QueueAction, TimeOutValue, DataBuffer, DataTransferLength, SenseInfoBuffer, SrbExtension, and the PathId, TargetId and Lun fields are valid.


SCSI Miniport WMI Events

The port driver will also support WMI event notification. The new notification type, WMIEvent, will be added to ScsiPortNotification. The third argument to ScsiPortNotification is a pointer to the WMI event and the fourth argument should be the size of that event. The fifth argument is 0xFF if the event is for the adapter, or the PathId of the event's target device. If the event is for a target device, arguments six and seven will be the TargetId and Lun of the device.

Note that the miniport driver cannot post events that have not been previously enabled. Also, if events are posted too quickly, some of them might be lost.

The miniport can indicate to WMI that the data items it supports have changed by calling ScsiPortNotification with a notification type of WMIReregister. This notification can be used if the number of instances that a miniport supports have changed. The third argument should be 0xFF if the adapter is being reregistered, or the PathId of the target device being reregistered. If the notification is for a target device, the fourth and fifth arguments should be the TargetId and Lun of that device.


SCSI Miniport Constants and Enumerated Types

// SRB Functions
#define SRB_FUNCTION_WMI        0x17

// WMI Flag Bits
#define SRB_WMI_FLAGS_ADAPTER_REQUEST 0x0001

// Port driver error codes
#define SP_LOST_WMI_MINIPORT_REQUEST 0x000b

// Notification Event Types
typedef enum _SCSI_NOTIFICATION_TYPE {
RequestComplete,
NextRequest,
NextLuRequest,
ResetDetected,
CallDisableInterrupts,
CallEnableInterrupts,
RequestTimerCall,
BusChangeDetected,       /* New */
WMIEvent,                /* New */
WMIReregister            /* New */
} SCSI_NOTIFICATION_TYPE, *PSCSI_NOTIFICATION_TYPE;


ScsiPortNotification

The only changes to ScsiPortNotification are in the number and definition of the variable arguments.

VOID ScsiPortNotification(
IN SCSI_NOTIFICATION_TYPE NotificationType,
IN PVOID HwDeviceExtension,
...
/* Additional parameters as required by the notification type.
   Only the new notification types are shown */

/* For BusChangeDetected, add */
IN UCHAR PathId

/* For WMIEvent, add */
IN PVOID WMIEvent,
IN UCHAR PathId,
/* If PathId != 0xFF also add */
IN UCHAR TargetId,
IN UCHAR Lun

/* For WMIReregister, add */
IN UCHAR PathId,
/* If PathId != 0xFF also add
IN UCHAR TargetId,
IN UCHAR Lun
);


HwScsiStopAdapter

VOID HwScsiStopAdapter(
IN PVOID HwDeviceExtension
);


HW_INITIALIZATION_DATA

typedef struct HW_INITIALIZATION_DATA {
ULONG HwInitializationDataSize;
INTERFACE_TYPE AdapterInterfaceType;
PHW_INITIALIZE HwInitialize;
PHW_STARTIO HwStartIo;
PHW_INTERRUPT HwInterrupt;
PHW_FIND_ADAPTER HwFindAdapter;
PHW_RESET_BUS_BUS HwResetBus;
PHW_DMA_STARTED HwDmaStarted;
PHW_ADAPTER_STATE HwAdapterState;
ULONG DeviceExtensionSize;
ULONG SpecificLuExtensionSize;
ULONG SrbExtensionSize;
ULONG NumberOfAccessRanges;
PVOID Reserved;
BOOLEAN MapBuffers;
BOOLEAN NeedPhysicalAddresses;
BOOLEAN TaggedQueuing;
BOOLEAN AutoRequestSense;
BOOLEAN MultipleRequestPerLu;
BOOLEAN ReceiveEvent;
USHORT VendorIdLength;
PVOID VendorId;
USHORT ReservedUshort;
USHORT DeviceIdLength;
PVOID DeviceId;
BOOLEAN Dma64BitAddresses;            /* New */
PHW_STOP_ADAPTER HwStopAdapter;       /* New */
} HW_INITIALIZATION_DATA, *PHW_INITIALIZATION_DATA;


PORT_CONFIGURATION_INFORMATION

typedef struct _PORT_CONFIGURATION_INFORMATION {
ULONG Length;
ULONG SystemIoBusNumber;
INTERFACE_TYPE AdapterInterfaceType;
ULONG BusInterruptLevel;
ULONG BusInterruptVector;
KINTERRUPT_MODE InterruptMode;
ULONG MaximumTransferLength;
ULONG NumberOfPhysicalBreaks;
ULONG DmaChannel;
ULONG DmaPort;
DMA_WIDTH DmaWidth;
DMA_SPEED DmaSpeed;
ULONG AlignmentMask;
ULONG NumberOfAccessRanges;
ACCESS_RANGE (*AccessRanges)[];
PVOID Reserved;
UCHAR NumberOfBuses;
UCHAR InitiatorBusId[8];
BOOLEAN ScatterGather;
BOOLEAN Master;
BOOLEAN CachesData;
BOOLEAN AdapterScansDown;
BOOLEAN AtdiskPrimaryClaimed;
BOOLEAN AtdiskSecondaryClaimed;
BOOLEAN Dma32BitAddresses;
BOOLEAN DemandMode;
BOOLEAN MapBuffers;
BOOLEAN NeedPhysicalAddresses;
BOOLEAN TaggedQueuing;
BOOLEAN AutoRequestSense;
BOOLEAN MultipleRequestPerLu;
BOOLEAN ReceiveEvent;
BOOLEAN RealModeInitialized;
BOOLEAN BufferAccessScsiPortControlled;
UCHAR MaximumNumberOfTargets;
UCHAR ReservedUchars[2];
ULONG SlotNumber;
ULONG BusInterruptLevel2;
ULONG BusInterrutVector2;
KINTERRUPT_MODE InterruptMode2;
ULONG DmaChannel2;
ULONG DmaPort2;
DMA_WIDTH DmaWidth2;
DMA_SPEED DmaSpeed2;
ULONG DeviceExtensionSize;
ULONG SpecificLuExtensionSize;
ULONG SrbExtensionSize;
BOOLEAN Dma64BitAddresses;           /* New */
BOOLEAN ResetTargetSupported;        /* New */
UCHAR MaximumNumberOfLogicalUnits;   /* New */
BOOLEAN WmiDataProvider;             /* New */
} PORT_CONFIGURATION_INFORMATION, *PPORT_CONFIGURATION_INFORMATION;


SCSI_WMI_REQUEST_BLOCK

The SCSI_WMI_REQUEST_BLOCK structure is presented only to show the fields in the SCSI_REQUEST_BLOCK structure that are overloaded when processing an SRB_FUNCTION_WMI request.

typedef struct _SCSI_WMI_REQUEST_BLOCK {
USHORT Length;
UCHAR Function;      /* = SRB_FUNCTION_WMI */
UCHAR SrbStatus;
UCHAR WMISubFunction;
UCHAR PathId;        /* if SRB_WMI_FLAGS_ADAPTER_REQUEST is set in */
UCHAR TargetId;      /* WMIFlags then PathId, TargetId, and Lun are */
UCHAR Lun;           /* reserved fields.  */
UCHAR Reserved1;
UCHAR WMIFlags;
UCHAR Reserved2[2];
ULONG SrbFlags;
ULONG DataTransferLength;
ULONG TimeOutValue;
PVOID DataBuffer;
PVOID DataPath;
PVOID Reserved3;
PVOID OriginalRequest;
PVOID SrbExtension;
ULONG Reserved4;
UCHAR Reserved5[16];
} SCSI_WMI_REQUEST_BLOCK;


NDIS Miniport

NDIS miniport drivers need only support the OID model described in the Windows NT® 4.0 DDK. The class driver maps the OIDs to WMI.


Data Item Data Format

WMI uses a set of standard data structures called WNODEs for passing queries, returning results from queries, and delivering events. The WNODE formats are designed to efficiently pass both tabular data of an arbitrary size and single data items. A feature of the WNODE_ALL_DATA format is the ability to quickly locate data items for individual instances within the data. Depending upon the amount of data needed, a data consumer will fill in the beginning of one of the WNODE structures and the driver will then fill in the end of the WNODE with the data requested.

Each WNODE format has a common header defined by WNODE_HEADER. WNODE_ALL_DATA is used to query for and return all data items for all instances of the block. WNODE_SINGLE_INSTANCE is used to query for and return all data items for a specific instance of the block. WNODE_SINGLE_ITEM is used to change the value of a single data item for a single instance of the block.

WMI itself maintains no additional information on the definition, content, or size of the data items other than what is stored in the WNODE and cannot interpret the data within a WNODE. Note that all strings are Unicode and are immediately preceded by a WORD that specifies the length of the string. The string does not need to be null terminated and the count does not include the null terminator. All WNODEs are aligned on an eight-byte basis.

WNODEs represent instance names differently, depending upon whether the data block was registered with static or dynamic instance names. WNODEs for dynamic instance name data blocks always contain the instance name strings. WNODEs for static instance name data blocks contain instance name indexes into the list of instance names that was registered for the data block. WMI sets the WNODE_FLAG_STATIC_INSTANCE_NAMES flag in the WNODE header appropriately in case the data provider does not remember how it registered its data block.


WNODE_HEADER

typedef struct _WNODE_HEADER {
    ULONG BufferSize;     // Size of entire buffer inclusive of this ULONG
    ULONG ProviderId;     // Provider ID of driver returning this buffer
    ULONG Reserved1; Union {
        ULONG Linkage;           // Linkage field reserved for WMI
        ULONG HistoricalContext; // Logger use
    };
    LARGE_INTEGER TimeStamp; // Timestamp as returned in units of 100ns since 1/1/1601
    GUID Guid;               // Guid for data block returned with results
    ULONG Reserved;
    ULONG Flags;             // Flags, see below
} WNODE_HEADER, *PWNODE_HEADER;

// WNODE_HEADER flags are defined as follows:
#define WNODE_FLAG_ALL_DATA        0x00000001 // set for WNODE_ALL_DATA
#define WNODE_FLAG_SINGLE_INSTANCE 0x00000002 // set for WNODE_SINGLE_INSTANCE
#define WNODE_FLAG_SINGLE_ITEM     0x00000004 // set for WNODE_SINGLE_ITEM
#define WNODE_FLAG_EVENT_ITEM      0x00000008 // set for WNODE_EVENT_ITEM

// set if data block size is identical for all instances
// (used with  WNODE_ALL_DATA only)
#define WNODE_FLAG_FIXED_INSTANCE_SIZE   0x00000010

#define WNODE_FLAG_TOO_SMALL           0x00000020 // set for WNODE_TOO_SMALL

// Set when a data provider returns a WNODE_ALL_DATA in which the number of
// instances and their names returned are identical to those returned from the
// previous WNODE_ALL_DATA query. Only data blocks registered with dynamic instance
// names should use this flag.
#define WNODE_FLAG_INSTANCES_SAME  0x00000040

// Instance names are not specified in WNODE_; values specified at
// registration are used instead. Always set for guids registered with static
// instance names
#define WNODE_FLAG_STATIC_INSTANCE_NAMES   0x00000080

#define WNODE_FLAG_INTERNAL      0x00000100  // Used internally by WMI

// timestamp should not be modified by a historical logger
#define WNODE_FLAG_USE_TIMESTAMP 0x00000200

#define WNODE_FLAG_EVENT_REFERENCE 0x00002000

// Set if Instance names are ansi. Only set when returning from
// WMIQuerySingleInstanceA and WMIQueryAllDataA
#define WNODE_FLAG_ANSI_INSTANCENAMES 0x00004000

// Set if WNODE is a method call
#define WNODE_FLAG_METHOD_ITEM     0x00008000

// Set if instance names originated from a PDO
#define WNODE_FLAG_PDO_INSTANCE_NAMES  0x00010000

// The second byte, except the first bit is used exclusively for tracing
#define WNODE_FLAG_TRACED_GUID   0x00020000   // denotes a trace

#define WNODE_FLAG_LOG_WNODE     0x00040000   // request to log Wnode

// Set for events that are WNODE_EVENT_REFERENCE
// Mask for event severity level. Level 0xff is the most severe type of event
#define WNODE_FLAG_SEVERITY_MASK   0xff000000


WNODE_ALL_DATA

typedef struct tagWNODE_ALL_DATA {
    struct _WNODE_HEADER WnodeHeader;

    ULONG DataBlockOffset;  // Offset from begin of WNODE to first data block

    ULONG InstanceCount;    // Count of instances whose data follows.

                            // Offset to an array of offsets to the instance names
    ULONG OffsetInstanceNameOffsets;

    // If WNODE_FLAG_FIXED_INSTANCE_SIZE is set in Flags then FixedInstanceSize
    // specifies the size of each data block. In this case there is one ULONG
    // followed by the data blocks. If WNODE_FLAG_FIXED_INSTANCE_SIZE is not set
    // then OffsetInstanceDataAndLength is an array of OFFSETINSTANCEDATAANDLENGTH
    // that specifies the offsets and lengths of the data blocks for each instance.
    union
    {
        ULONG FixedInstanceSize;
        OFFSETINSTANCEDATAANDLENGTH OffsetInstanceDataAndLength[];
                                    /* [InstanceCount] */
    };

    // padding so that first data block begins on a 8 byte boundry

    // data blocks and instance names for all instances

} WNODE_ALL_DATA, *PWNODE_ALL_DATA;

Comments

A WNODE is defined to be a WNODE_ALL_DATA by setting the WNODE_FLAG_ALL_DATA in the Flags field of the WNODE_HEADER. The sizes of each instance of the data block is described as contained in a union, but is not a union in the true sense.

If WNODE_FLAG_FIXED_INSTANCE_SIZE is set in the Flags field of the WNODE_HEADER, then there is only a DWORD that specifies the size of every instance of the data block that is part of the WNODE_ALL_DATA. If WNODE_FLAG_FIXED_INSTANCE_SIZE is not set, then there are InstanceCount OFFSETINSTANCEDATAANDLENGTH structures and each one specifies the offset and size of the data block for a particular instance. It is required that each instance of a data block be aligned on an eight-byte boundary.

Data blocks that were registered as static instance name data blocks should ignore the OffsetInstanceNames array. Before passing the WNODE to the data provider, WMI will set the WNODE_FLAG_STATIC_INSTANCE_NAMES flag. Before returning to the data consumer, WMI will automatically fill in the OffsetInatanceNames array and append the instance names. Data blocks that did not register as having static instance names are defined to have registered as having dynamic instance names. In this case, WMI will not set the WNODE_FLAG_STATIC_INSTANCE_NAMES and the data provider must fill in the OffsetInstanceNames array and include the instance names in the WNODE_ALL_DATA returned.

If a data provider can keep track of when the number or names of the instances change for a dynamic instance name data block, it should set the WNODE_FLAG_INSTANCES_SAME flag appropriately. If this flag is set, WMI will avoid extra work to detect changed dynamic instance names and update its tables. A data provider that does not track changes in instances that it provides should always leave the flag reset. Use of this flag is optional, but highly recommended to improve performance. The flag is ignored for data blocks registered as having static instance names. Calling the WMI registration APIs described in the following topics changes static instance names.


WNODE_SINGLE_INSTANCE

struct WNODE_SINGLE_INSTANCE {
    struct WNODE_HEADER WNODE_header;
    DWORD OffsetInstanceName;   // Offset from beginning of WNODE_SINGLE_INSTANCE
                                // to instance name. Use when
                                // WNODE_FLAG_STATIC_INSTANCE_NAMES is reset.
    DWORD InstanceIndex;        // Instance index. Use when
                                // WNODE_FLAG_STATIC_INSTANCE_NAMES is set.
    DWORD DataBlockOffset;      // Offset from beginning of WNODE to data block
    DWORD SizeDataBlock;        // Size of data block for instance

    // instance names and padding so data block begins on 8-byte boundary

    // data block
}


WNODE_SINGLE_ITEM

struct WNODE_SINGLE_ITEM {
    struct WNODE_HEADER WNODE_header;
    DWORD OffsetInstanceName;  // Offset from beginning of WNODE_SINGLE_ITEM
                               // to instance name. Use when
                               // WNODE_FLAG_STATIC_INSTANCE_NAMES is reset
    DWORD InstanceIndex;       // Instance index. Use when
                               // WNODE_FLAG_STATIC_INSTANCE_NAMES is set
    DWORD ItemId;              // Item ID for data item being set
    WORD DataBlockOffset;      // offset from beginning of WNODE to data item value
    DWORD SizeDataItem;        // Size of data item

    // instance names and padding so data value begins on 8 byte boundary

    // data item value
}

Comments

A WNODE_EVENT_ITEM is built by a data provider and used to deliver event information to all data consumers who have registered for the specific event being generated. A WNODE is a WNODE_EVENT_ITEM when the WNODE_FLAG_EVENT_ITEM flag is set in the WNODE_HEADER. Depending upon the flag set in the WNODE_HEADER, the event data could be a WNODE_SINGLE_ITEM, WNODE_SINGLE_INSTANCE, WNODE_ALL_DATA, or WNODE_EVENT_REFERENCE. A data provider can attach a severity level from zero to 256 by placing the severity level in the top 8 bits of the Flags in the WNODE_HEADER.


WNODE_EVENT_ITEM

typedef struct tagWNODE_EVENT_ITEM {
    struct _WNODE_HEADER WnodeHeader;

    // Different data could be here depending upon the flags set in the
    // WNODE_HEADER above. If the WNODE_FLAG_ALL_DATA flag is set then the
    // contents of a WNODE_ALL_DATA  (excluding WNODE_HEADER) is here. If the
    // WNODE_FLAG_SINGLE_INSTANCE flag is set then a WNODE_SINGLE_INSTANCE
    // (excluding WNODE_HEADER) is here. Lastly if the WNODE_FLAG_SINGLE_ITEM
    // flag is set then a WNODE_SINGLE_ITEM (excluding WNODE_HEADER) is here.
} WNODE_EVENT_ITEM, *PWNODE_EVENT_ITEM;

Comments

The WNODE_EVENT_REFERENCE is used to specify the GUID and possibly the instance of the GUID that contains the full information about the event. For example, an FTP server data provider can fire an event to indicate that a connection disappeared and include the GUID for the connection information data block along with the instance name that was disconnected.


WNODE_EVENT_REFERENCE

typedef struct tagWNODE_EVENT_REFERENCE {
    struct _WNODE_HEADER WnodeHeader;
    GUID TargetGuid;
    ULONG TargetDataBlockSize;
    Union {
        ULONG TargetInstanceIndex;
        WCHAR TargetInstanceName[];
    };
} WNODE_EVENT_REFERENCE, *PWNODE_EVENT_REFERENCE;

Comments

In the case of a call where the data buffer passed was too small, the data provider should return success with a WNODE_TOO_SMALL. This is composed of a filled in WNODE_HEADER with the WNODE_FLAG_TOO_SMALL flag set directly followed by a DWORD that specifies the size needed to contain the entire result.


WNODE_TOO_SMALL

typedef struct tagWNODE_TOO_SMALL {
    struct _WNODE_HEADER  Wnode_Header;
    ULONG                 SizeNeeded;        // Size needed to build WNODE result
} WNODE_TOO_SMALL, *PWNODE_TOO_SMALL;


Data Block Versioning Requirements

There is a simple rule that must be followed when a data provider wants to publish a new format for an existing data block. The data provider must define a new GUID and a new MOF class name because versioning is not supported by WBEM.


WMI Schema Description

All device drivers must provide a description for the data items provided by each data or event block. Collectively, this information is referred to as a schema. By making the schema available, a device driver allows general-purpose management and performance monitoring applications to access the data provided by the device driver and present it in an intelligible way. Schema information can be conveniently described in the managed object format (MOF) developed for the WBEM project.

MOF syntax is described extensively in the WBEM documentation. The MOF syntax allows classes to be defined that are used to describe data blocks. Classes are similar to C language structure definitions in that they contain definitions for the properties or data items contained within them. Both classes and data items can have qualifiers associated with them. Qualifiers are contained within brackets ([]) and placed before the class or data item definition that they qualify. A qualifier may also have a value associated with it. WMI uses these qualifiers to provide additional information about the schema.

All WMI classes have a class property named Active. This property is not part of the data block provided by the driver, but is exposed to clients of the WBEM data consumer. Active is a Boolean that denotes whether WMI is able to return data for the data block. Also note that each individual class definition must have a class property named InstanceName to hold the instance name for the data block returned in the WNODE data structure. It should be defined to be a key property so data consumers can select among the different instances of the data block.

Properties can be a basic data type, an embedded class, or a fixed or variable length array of a basic data type or embedded class.

MOF information is kept as a resource on the device driver's image file. The resource is built by creating a text file containing the definitions for the data blocks associated with the GUIDs registered by the data provider. Next, this text file is compiled by the MofComp tool, which creates a binary representation of it in another file. If the WMI flag is specified, the binary file is run through the Wmimofck tool, which will verify that all class definitions are valid for WMI. Any MOF resource that is not valid will be completely rejected by Wmimofck and the binary MOF file deleted. This binary file should be referenced by the data provider's resource script when building the data providers binary image. Following is the syntax for compiling File.mof into File.bmf:

MofComp –WMI –B:file.bmf file.mof
  • For this example, you need to add the following line to the resource script (.rc) file:
MofResource MOFDATA file.bmf
  • Here is an example of a class definition:
// Standard class for reporting serial port information
//
[WMI, guid("85F64E01-5A9B-11d0-A838-00AA0060D45C"),
Dynamic, Provider("WMIProv"),
WmiExpense(1),
Locale("MS\\0x409"),
Description("Description of class"]
class StandardSerialInformation {

// InstanceName and Active are the required properties for WBEM to be able to
// manage WMI data blocks. They must not have ID's associated with them.
    [key, read]
     string InstanceName;

    [read]
     boolean Active;

// This is the first data item in the blob and is a 64 bit integer and is readonly
    [read,
     WmiDataId(1),
     WmiScale(0),
     WmiCounterType(0x00000000),
     WmiComplexity(1),
     WmiVolatility(1000),
     Description("Description of property")]
    uint64 BytesSent;                          // bytes sent on port

//
// This is the second data item in the blob and is also a 64 bit integer and is
// readable or writable.
    [read,
     write,
     WmiDataId(2),
     WmiScale(0),
     WmiCounterType(0x00000000),
     WmiVolatility(1000)]
    uint64 BytesReceived;                      // Bytes received on port

//
// This data item is the
// fourth data item in the data block. It is a read only counted unicode string.
    [read,
     WmiDataId(4),
     WmiScale(0),
     WmiCounterType(0x00000b00),
     WmiVolatility(60000)]
    string Owner;                       // Who owns the port

//
// This is the third data item in the data block
// It is a fixed length array of 16 bytes. Note that the order in
// the MOF class definition is not relevant to the order in the data block
    [read, write,
     WmiDataId(3),
     WmiScale(0),
    WmiCounterType(0x00000300)]
    byte Status[16];                             // Status bit array

    //
    // This the fifth data item in the data block
    [read,
     WmiDataId(5),
     WmiScale(0),
     WmiCounterType(0x00000000),
     WmiComplexity(1),
     WmiVolatility(1000)]
    uint32 XmitDescriptorCount;

    //
    // This the sixth data item in the data block
    // It is a variable length array of XmitDescriptor structures.
    // The number of elements in the array can be found in the XmitDescriptorCount
    // property.
    [read,
     WmiDataId(6),
     WmiSizeIs("XmitDescriptorCount"),
     WmiScale(0),
     WmiCounterType(0x00000000),
     WmiComplexity(1),
     WmiVolatility(1000)]
    XmitDescriptor XmitBufferSize[];
}

//
// Note that this class does not have InstanceName or Active properties since it is
// only used as an embedded class.
[WMI, guid("85F64E03-5A9B-11d0-A838-00AA0060D45C"),
class XmitDescriptor {
    [read, WmiDataId(1)] int32 DestinationIndex;
    [read, WmiDataId(2)] int32 DestinationTarget;
}

 [WMI, guid("85F64E02-5A9B-11d0-A838-00AA0060D45C"),
 Dynamic, Provider("WMIProv"),
 locale("MS\\0x409"),
 Description("Serial Send Event"),
 WmiExpense(1)]
class SerialSendEvent : WMIEvent
{
//
// InstanceName and Active are the required properties for WBEM to be able to
// manage WMI data blocks. The must not have ID's associated with them.
    [key, read]
     string InstanceName;              // Instance name returned from WMI

    [read]
     boolean Active;

//
// This data item is an event that can be enabled by a data consumer. The
// SendEventTrigger data item can be used to set or read the trigger for event
// generation while the SendEventRate data item can be set or read to regulate the
// event generation rate.
    [read,
     WmiDataId(1),
     WmiScale(0),
     WmiCounterType(0x00000000),
     WmiEventTrigger("SendEventTrigger"),
         WmiEventRate("SendEventRate")]
        sint32 SendEventValue;

    [read,
     write,
     WmiDataId(2)]
    sint32 SendEventRate;

    [read,
     write,
     WmiDataId(3)]
    sint32 SendEventTrigger;
}

Class Qualifiers

A class may have the following qualifiers.

Qualifier | Description
[guid("guid-string")] | Declares the GUID that represents the class within WMI. This qualifier is required.
[Description("description-text")] | Specifies the description text for the class or property in the locale specified for the locale qualifier.
[WmiExpense(expense-value)] | Specifies how much system resources is required in order to collect data in the data block. And, expense-value is defined to be the average number of CPU cycles needed to collect the data block. If this qualifier is not specified, then the expense-value is assumed to be zero.
[Dynamic] | Specifies that the class is dynamic. This is required.
[Provider("WMIProv")] | Specifies that the provider of the class is wmiprov.dll. This is required.
[WMI] | Specifies that this is a WMI class. This is required.

Data Qualifiers

A data item may have the following qualifiers.

Qualifier | Description
[read] | Specifies that the data item may be read.
[write] | Specifies that the data item may be written.
[WmiDataId(data-item-id)] | Specifies the data item ID for the data item. This qualifier is required.
[WmiScale(scale-factor)] | Specifies the scaling factor to use when displaying the data. Before displaying the data returned from a query of the data item it is multiplied by 10 to the power of scale-factor. If this qualifier is not specified, then the scale-factor is assumed to be zero.
[WmiTimeStamp] | Specifies that the 64-bit data item is really a timestamp in units of 100 nanoseconds since January 1, 1601. This qualifier is only valid for 64 bit data items.
[WmiEventTrigger("data-item-name")] | Specifies the name of the data item that can be used to trigger the event. And, data-item-name is the name of a data item that could be a trigger for the event. In the previous example, SendEventValue will fire an event when SendEventTrigger is reached. This is an optional qualifier and may only be used on those data items that have the [WmiEvent] qualifier.
[WmiEventRate("data-Item-name")] | Specifies the name of the data item that can be used to specify a rate for the event. This is an optional qualifier and may only be used on those data items which have the [WmiEvent] qualifier.
[WmiComplexity("complexity-category")] | Specifies the level of detail associated with the counter. And, complexity-category can have the value of "Novice" for the information that anyone can understand, "Advanced" for information that is useful for advanced users, "Expert" for information that is useful to only expert users, and "Wizard" for information that is useful for the data provider designer. If this qualifier is not specified, then a complexity-category of "Novice" is assumed.
[WmiVolatility(validity-interval)] | Specifies how often the this data item value is updated internally. And, validity-interval is defined in units of milliseconds so a validity-interval of 1000 would mean that the data item is updated internally every second. Data consumers can use this measure to determine how frequently it should poll for changes in a data item. If this qualifier is not specified, then no assumption on the length of validity for a data item can be made.
[WmiSizeIs("property-name")] | Specifies the property within the current class that has the count of the number of array elements (not bytes) contained in a variable length array.

The order that the data items are laid out in the data block is controlled by the data item ID. Data item IDs must be allocated contiguously, starting with data item ID 1. The data item order specified in the MOF is not relevant. Data items must be aligned within the data block along natural alignment boundries — bytes on a byte boundary, words on a word boundary, and so on.

The following table shows the different data types that MOF supports. MOF also supports arrays of these types as well. A variable sized array must have a WmiSizeIs qualifier that specifies the property that has number of elements in the array.

Data Types | Data Format
string | Counted Unicode string.
sint32 | Signed 32-bit integer.
uint32 | Unsigned 32-bit integer.
sint16 | Signed 16-bit integer.
uint16 | Unsigned 16-bit integer.
sint64 | Signed 64-bit integer.
uint64 | Unsigned 64-bit integer.
sint8 | Signed 8-bit character.
uint8 | Unsigned 8-bit integer.
datetime | 25-character string used to specify absolute dates or time intervals. See the following discussion.
bool | Byte where zero is FALSE and != 0 is TRUE.

The Date property type is a fixed-length Unicode string and is not preceded by a count value. It is in the following fixed format:

yyyymmddhhmmss.mmmmmmsutc

Where yyyy is a 4-digit year, mm is the month, dd is the day, hh is the hour (24-hour clock), mm is the minute, ss is the second, and mmmmmm is the number of microseconds (typically all zeros). S is a plus (+) or a minus (-) sign indicating the sign of the UTC correction field, and utc is the offset from UTC in minutes (using the sign indicated by S). For example, Wednesday, May 25, 1994, at 1:30:15 PM EDT would be represented as:

19940525133015.0000000-300

Values must be zero padded so the entire string is always the same 25-character length. Fields that are not significant must be replaced with asterisk (*) characters. Similarly, intervals use the same format, except that the interpretation of the fields is based on elapsed time. For example, an elapsed time of 1 day, 13 hours, 23 minutes, and 12 seconds would be:

00000001132312.000000+000

An UTC offset of zero is always used for interval properties.


Schema Design Recommendations

The performance of WMI and the data consumer applications that use it are greatly affected by the design of a device driver's schema. The following are guidelines for schema organization.

  • Separate data items into blocks containing data items that are operationally grouped together. For example, the i8042 port controller may maintain information about both the keyboard and mouse port states. Rather than have one large data block with all mouse and keyboard information, it would make sense to have two data blocks — one for mouse information and one for keyboard information.
[WMI,
Provider("WMIProv"), Dynamic,
Description("Keyboard port information"),
[guid("{85F64E01-5A9B-11d0-A838-00AA0060D45C}")]
class KeyboardPortInformation
{
    [key, read]
    string InstanceName;

    [read] boolean Active;

    [read,write,WmiDataId(1)]
     int32 KeyRepeatRate;

    [read,write,WmiDataId(2)]
     int32 KeyRepeatDelay;
}

[WMI,
Provider("WMIProv"), Dynamic,
Description("Keyboard port information"),
[guid("{85F64E02-5A9B-11d0-A838-00AA0060D45C}")]
class MousePortInformation
{
    [key, read]
    string InstanceName;
    [read] boolean Active;

    [read,write,WmiDataId(1)]
     boolean SwapButtons;
}
  • Separate an often-used data item into its own block, particularly if it would normally be grouped with other infrequently used data items. This is useful because data consumers cannot query for a single data item; they can only query for all data items for all instances or all data items of a single instance. For example, it would make sense to separate the CPU utilization data item into its own data block so queries for information to track only CPU utilization will not cause extra work by returning extra rarely used information.
  • Fixed sized data items should be placed at the beginning of a data block and variable sized data items should be placed after them. This will allow a data consumer to easily pick out fixed sized data items within the data. For example, a data block that has three DWORD data items and one variable length string should put the three DWORDs first and then the variable length string.
  • If there is a standard data block that contains the data items that a device wants to expose, the driver writer should use the standard block. If there are additional data items that are not part of the standard data block, then a custom data block can be created.


Standard Data Blocks Requirements

In order to provide a consistent mechanism for management and performance monitoring applications to obtain standard blocks of data, a set of data blocks are defined and must be supported by various driver types. For example, a required block for a serial driver might include bytes sent and bytes received and might be assigned a fixed GUID. All WMI-compliant serial drivers would be required to support this GUID.


Global Blocks

Information to be provided in a future release.


Device Specific Blocks

Information to be provided in a future release.


Implementing TV Support in Windows 98

This documentation describes a software interface to television control hardware that resides in a video graphics chip set. This documentation describes both the interface that the operating system exposes to Win32® applications and the interface that the display driver must expose to the operating system.

The following topics are included:

Win32 Application Interface

Windows 98 Display Driver Interface


Win32 Application Interface

The Win32 API ChangeDisplaySettingsEx has been modified to contain both a structure to control television parameters and a flag to indicate that the structure is present. CDS_VIDEOPARAMETERS is the flag that indicates that the lParam element is actually a pointer to a VIDEOPARAMETERS structure. This structure can be used for both querying the television capabilities of a driver and hardware set, and for adjusting supported features of the hardware through the driver. Possible features supported are TV standard adjustment, flicker filter adjustment, scaling, positioning, brightness and contrast adjustment, and copy protection support.

The following example queries the current video parameter settings:

#include "tvout.h"
dm.dmSize = sizeof(DEVMODE);
vp.Guid = vpguid;
vp.dwCommand = VP_COMMAND_GET;
if (ChangeDisplaySettingsEx("\\\\.\\Display1",&dm,0,CDS_VIDEOPARAMETERS,&vp) ==  DISP_CHANGE_SUCCESSFUL)
{
   // process good return code here
}

The possible return values include:

Value | Description
DISP_CHANGE_BADPARAM | The ChangeDisplaySettingEx calling parameters were incorrect.
DISP_CHANGE_BADESC | Driver does not support functionality, or the driver returned an error.
DISP_CHANGE_SUCCESSFUL | Driver interface succeeded correctly.


Windows 98 Display Driver Interface

The Windows® 98 display driver interface has been modified to support the VIDEOPARAMETERS structure. The interface is through the Control function, with an ESC Escape code of 3077(0x0c05).

WORD Control(
  LPPDEVICE lpDestDev,
  WORD      wFunction,
  LPSTR     lpInData,
  LPSTR     lpOutData
 );

Parameters

lpDestDev
Address of a PDEVICE structure that specifies the destination device.
wFunction
Escape to be carried out. If set to VIDEO_PARAMETER, it indicates that lpInData is a VIDEOPARAMETERS structure.
lpInData
Address of escape-specific input data. May be a pointer to a VIDEOPARAMETERS structure.
lpOutData
Address of escape-specific output data. When using a VIDEOPARAMETERS structure, this value is NULL.

Return Value

A positive value indicates success, while a negative value indicates an error. Zero can indicate either an unimplemented escape or a general error condition.


Windows 95 Documentation Release Notes

This documentation contains material relevant primarily to the Windows 95 DDK. It is included here to address hardware technologies that are not supported by WDM. While some information may be outdated or made obsolete by newer material contained in the Windows 98 DDK, other information may still be pertinent. Programmers are encouraged to refer to this material as required and to supplement the Windows 98 DDK (WDM) documentation with the information contained here.

This section makes occasional references to the file paths and file names that are unique to the Windows 95 DDK CD-ROM. If those exact files or folders are needed, you will have to refer to the original Windows 95 DDK CD-ROM, since the content of the Windows 98 DDK is not the same.

The Windows 98 DDK contains updates to the original source code samples originally contained in the Windows 95 DDK. The updated Windows 98 header files should be of interest to developers of drivers targeted specifically to Windows 98. Build all sample drivers, including legacy Windows 95 samples, using the instructions provided in the Windows 98 DDK documentation.


Introduction

The Programmer's Guide contains the following information:

Overview of Windows® 95 Device Drivers | Introduction to writing device drivers for Microsoft® Windows® 95. The overview includes information for the Microsoft® Windows NT®/Windows® 2000 and Windows for Workgroups operating systems.
Introduction to Virtual Device Drivers | Introduction to writing virtual device drivers. This overview also includes information on message macros (which isolate your VxD text strings, so they can be translated into foreign languages) and on registering statistics with the System Monitor (which allows you to present performance information from the System Monitor).
Device Installation and .INF Files | Mechanics of installing device drivers using .INF files. This overview includes sections on printer, modem, multifunction device, network, multimedia, and display device classes.
Plug and Play | Description of how Plug and Play works and how to implement it in your devices. This overview is important because Plug and Play is a requirement for hardware to receive certification from Microsoft.
Utilities | Description of the Windows System Debugger (WDEB386) and other utilities included with the DDK.
Device Driver Certification | Information about the Windows Hardware Quality Labs (WHQL), which certifies drivers and acts as a repository for tools and new drivers. This overview describes the tests included with the DDK and how to obtain (from the Internet) the latest versions of the WHQL's tests and tools.
Windows 95 Image Color Matching | Description of the image color matching (ICM) technology available in Windows® 95. ICM provides consistent, predictable color rendering from input, through monitor preview, to output. This overview is of particular interest to printer, display, and digital image device driver writers whose devices are used in desktop publishing.
Graphics Device Drivers | Information about how the graphics device interface (GDI) and device drivers interact. This overview is especially useful for printer driver and display driver writers.
Internationalization | Information about making drivers compatible with different versions of Windows® 95 for the global market.


Installers, Device Manager, and Control Panel

The Windows® 95 Device Manager is the central component of device installation and configuration. A set of default device installers and Control Panel applets, which work with Device Manager, are supplied with Windows 95. There are several development requirements and opportunities for customizing the installation and configuration of your device. Device developers have the option of creating an installer, creating a Control Panel applet, or extending a default Control Panel applet. Device developers must create a device information (INF) file for their device.

This section describes the tools and interfaces you can use to customize the installation and configuration of your device.


About Class and Device Installers

Class and device installers are dynamic-link libraries that work in conjunction with the Device Manager to install, configure, and remove devices or classes of devices in the system. Windows® 95 provides a set of default installers that the Device Manager can use to install devices belonging to the default classes. Additionally the Device Manager supports a set of default device installation functions that can be used on a device of any class. If your device or class of device has features that are not supported by the default installers, you can create a new installer for your device or class and direct Device Manager to use the installer whenever the user installs your device or class.

This section describes class and device installers and explains how create and register new installers for use by the Device Manager.


Classes and Installers

Windows 95 has a large number of subsystems to control various classes of devices. Classes identify logical device types such as display, keyboard, and network. Because each subsystem has a different driver architecture, different user options, and different compatibility constraints, it is impossible to have a single utility support installation of all possible devices. Instead, each class is responsible for providing its own installer.

A single installer can support installation of both the class and individual devices. However, this depends on the class and in some cases separate device installers are used. Typically, the installer is combined with the control panel applet (.CPL) for the given class, although this is not a requirement. Whether the installer is combined with the applet or is a separate dynamic-link library, the Device Manager controls and directs the action of the installer.

The Device Manager, itself a control panel applet, is responsible for displaying dialog boxes to the user to prompt for information about adding and modifying device drivers. It is also responsible for installing any drivers for any devices enumerated by the configuration manager.

The Device Manager relies on the class and device installers to display the appropriate dialog boxes or carry out appropriate installation tasks. Although the Device Manager gives the installer full control of the installation process, in most cases, the installer simply directs the Device Manager to complete the task for it. The installer can insert additional configuration dialogs, hardware detection, and other features into the process as is appropriate for the class.


Default Classes and Class Installers

Windows 95 defines a set of default device classes and provides corresponding class installers for these classes. The Device Manager uses the default installers to install devices belonging to the default classes. There are these default classes:

Adapter | Default device install
Printer | MSPRINT.DLL
CDROM | Default device install
Disk Drives | Default device install
Sound video and game controllers mmci.cpl | Default device install
Keyboard | Default device install
System Devices | sysclass.dll
Multi Functions Cards | Default device install
Modem | Modem.Cpl
Monitor | Default device install
Display adapters | SetupX.Dll
Floppy disk controllers | Default device install
Hard disk controllers | Default device install
Mouse | SetupX.Dll
Ports (COM & LPT) | Default device install
Network adapters | netdi.dll
PCMCIA Socket | PCCard.dll
SCSI controllers | Default device install
Unknown Hardware | sysdm.cpl

If your device belongs to a default class but the default installer does not provide the installation support you need for your device, you can create your own installer and direct the Device Manager to use that installer whenever the user installs a device of that class.

By default, the Device Manager adds any new classes to the system if the given INF specifies a [ClassInstall] section, and the class has not been previously installed. You can specify the Class installer for this new class in this section of the INF file, and the Device Manager will load and call this installer when appropriate.


Installer Function

Every installer exports an installer function named ClassInstall. The Device Manager dynamically links to and calls this function whenever it needs the installer to carry out a specific installation task.

ClassInstall receives two arguments: an integer that identifies the installation task to carry out, and the address of a DEVICE_INFO structure that contains information about the device to install. The function either carries out the requested task, using the information in the structure, or directs the Device Manager to carry out the task for it.

To direct the Device Manager to carry out the task, the function must return the ERR_DI_DO_DEFAULT value. The Device Manager has default actions for each request.

If the function carries out its own tasks, it must return the value OK to notify the Device Manager that the task completed successfully. If an error occurs while carrying out a task, the function must return one of the RETERR values given in Constants.


Installation Requests

The Device Manager sends requests to the installer whenever it needs the installer to carry out installation tasks, such as determining whether to install a detected device, selecting a device to install, and installing a selected device.

A DIF_SELECTDEVICE request directs the installer to choose a driver for a new device or a new driver for an existing device. The installer either makes the selection, prompts the user to make the selection, or directs the Device Manager to prompt the user (the default action).

A DIF_INSTALLDEVICE request directs the installer to install the given driver. The installer either installs the driver or directs the Device Manager to do it (the default action). In some cases, an installer may carry out pre-processing, such as copying support drivers and prompting for user input, before requesting the default action.

A DIF_PROPERTIES request directs the installer to display the properties sheet for the selected device. The Device Manager send this request when the user presses the Properties... button. The installer can display the property sheet or direct the Device Manager to display the default property sheet (the default action).

The Device Manager sends a DIF_REMOVE request to direct the installer to remove the given device. The installer typically removes the corresponding registry entries for the device.

A DIF_FIRSTTIMESETUP request directs the installer to carry out any class-specific installation tasks that need to be complete during initial installation of the operating system. The Device Manager sends this request only when the user installs Windows 95 for the first time.

A DIF_CALCDISKSPACE request directs the installer to calculate the disk space requirements for installing a driver for the given device. By default action, the Device Manager calculates the disk requirements based on the contents of the INF file.

A DIF_DESTROYPRIVATEDATA request directs the installer to free any memory or resources it has allocated and stored in the private data portion of the DEVICE_INFO structure. The Device Manager sends this function just before destroying the structure.

The Device Manager provides a set of requests (DIF_SELECTCLASSDRIVERS, DIF_VALIDATECLASSDRIVERS, AND DIF_INSTALLCLASSDRIVERS) that an installer can use to install a multiple set of drivers instead of a single driver. For example, a network installer may process these requests so that it can install the many different layers of drivers needed to support a network. An installer should process these requests only if it intends to carry out the complete installation on its own.

The DIF_SELECTCLASSDRIVERS request directs the installer to select the driver or drivers to install for the given class; DIF_VALIDATECLASSDRIVERS directs the installer to validate all settings for the given devices; and DIF_INSTALLCLASSDRIVERS directs the installer to install the selected and validated drivers. The default action for these requests is to do nothing.


Device Installation Functions

Installers can use the device installation functions, provided by the SetupX dynamic-link library, to carry out installation tasks. The device installation functions allow installers to search INF files for compatible drivers, display driver choices to the user through selection dialogs, and perform the actual driver installation.

Nearly all the device installation function rely on the information in the DEVICE_INFO structure to carry out the request tasks. You can create a linked list of these structures for the devices in the given class by using the DiGetClassDevs function. This function fills each structure with information about the individual devices. You can also create a single copy of a structure by using the DiCreateDeviceInfo function. This function lets you explicitly define the content of the structure and is useful for adding devices to the list that the DiGetClassDevs function may not have found. You can free all DEVICE_INFO structures in a list by using the DiDestroyDeviceInfoList function. This function also frees any compatible device and class device lists that may have been added to the structure.

You can generate a list of selections from which the installer or the user can choose the drivers or device to install by using the DiBuildCompatDrvList and DiBuildClassDeviceList functions. DiBuildCompatDrvList creates a list of compatible drivers and DiBuildClassDeviceList creates a list of all devices of a given class. These functions create linked lists of DRIVER_NODE structures that contain information about the drivers and devices the function located in a search of all the INF files on a given path.

Once you have a list of compatible drivers or devices, you can prompt the user to select from the list by using the DiSelectDevice function. This function displays a dialog box to that contains information about each device in the linked list of structures. You can install a selected driver by using the DiInstallDevice function. This function uses information in the given INF file to create any new registry entries required for the device, set the configuration of the device hardware, and copy the driver files to the appropriate directories.

An installer may need to examine and set values under the registry key for a device that is about to be installed. You can open the hardware or driver key for a device by using the DiOpenRegKey function.

You can install a new class of device in the registry by using the DiInstallClass function. This function requires an INF file that contains a valid [ClassInstall] section.

Some device installation functions are intended to be used by system and may not be useful for ordinary installers. You can call the installer for a given class by using the DiCallClassInstaller function. This function is useful if a device installer needs support from the corresponding class installer to complete installation. The function uses the class name to locate, load, and call the appropriate class installer.

You can remove a device entry from the registry by using the DiRemoveDevice function.


Installer Registration

The Device Manager requires that you register your class or device installers by adding Installer and Icon entries to the registry for the given class. The system maintains a System\CurrentControlSet\Services\Class branch under HKEY_LOCAL_MACHINE for information about each class. The value of the key contains the localized description of the class.

The Installer and Icon entries have this form:

Installer=installer-DLL-name[,Installer Entry Point]

Icon=index [, icon-DLL-name]

The Device Manager uses the icon to represent your installer to the user. If you fail to register include a Installer entry, the Device Manager takes the default actions in all cases.


Enumerated Devices

When an enumerator detects a new device, it relies on the Configuration Manager and Device Manager to locate the installer for the given device and install the appropriate drivers. Typically, the Device Manager generates a list of compatible drivers for the device and sends a DIF_SELECTDEVICE, followed by a DIF_INSTALLDEVICE request to the installer. If the Device Manager is in silent mode, it may send a DIF_INSTALLDEVICE request only.


Using Control Panel Extensions

A control-panel extension is an OLE 2 server DLL. You must supply a device-information (INF) file that copies your DLL to the Windows \SYSTEM directory and creates two registry keys, one that defines the extension's globally unique identifier (GUID), and the other that declares the GUID as a control-panel extension. The INF file format and the registry keys are described in more detail later in this topic. For an example of a control-panel extension, including source files, see the CPLX directory in the Windows 95 DDK.

Some of the Control Panel applications in Windows 95 can be extended by adding property-sheet pages or by making interface changes in existing property-sheet pages. This is an alternative to developing an entirely new Control Panel. Using Control Panel extensions has the following advantages:

  • •Enables an IHV to develop a user interface for the unique characteristics of a device without having to develop an entirely new Control Panel.
  • •Enables Windows 95 users to find all the settable characteristics of a device in the Control Panel that already exists for that device; a user is more likely to find an additional property-sheet page in the Display Control Panel , for example, than they are to find an entirely new Control Panel. Adding a new Control Panel also changes the pattern of displayed Control Panel icons from what the user is accustomed to.

When no existing Control Panel addresses your needs, you can create your own Control Panel. (For example, this could be necessary for BIOS setup interfaces.) For information about creating your own Control Panel, see Control Panel Applications in the Win32® Programmer's Reference.

As mentioned earlier, not all of the Control Panel applications in Windows 95 can be extended by adding property-sheet pages or by making interface changes in existing property-sheet pages. The following table lists the standard Control Panels and describes their extensibility:

Control Panel | Extensibility
Accessibility | Not extensible.
Add New Hardware | An application can add classes and devices to lists, using a .INF file.
Add/Remove Program | Net administrators can add a list of central company software to be installed by setting a registry key and creating a data file on a common server. This procedure is documented in the Resource Kit. The Install/Uninstall property sheet contains a list of software that can be uninstalled by Windows. An application that uses the uninstall utility of the InstallShield application will be included in this list. InstallShield is included with the Windows 95 SDK. For more information, see the InstallShield documentation.
Date/Time | Not extensible.
Display | An application can add property sheet pages, using the IShellPropSheetExt::AddPage interface and adding a Controls Folder\Display key to the registry.
Joystick | Not extensible.
Keyboard | Although the Speed page is replaceable, it should not be necessary to do so. Replacing this page can affect the accuracy of existing Help files. An application can add property sheet pages, using the IShellPropSheetExt::AddPage interface and adding a Controls Folder\Keyboard key to the registry.
Modems | Not extensible.
Mouse | Although the Motion and Button pages are replaceable, it should not be necessary to do so. Replacing these pages can affect the accuracy of existing Help files. An application can add property sheet pages, using the IShellPropSheetExt::AddPage interface and adding a Controls Folder\Mouse key to the registry.
Multimedia | Not extensible.
Network | Most network drivers and software can fully specify their installation requirements and files by using network .INF files. For more information about network .INF files, see Network Driver Installer in the DDK.
Passwords | An application can add property sheet pages, using the IShellPropSheetExt::AddPage interface and adding a Controls Folder\Passwords key to the registry. For more information, see Passwords Control Panel in the Windows 95 Programming Guide.
PCMCIA | Not extensible.
Power Management | An application can add property sheet pages, using the IShellPropSheetExt::AddPage interface and adding a Controls Folder\Power key to the registry
Regional Settings | Not extensible.
Sounds | Not extensible.
System | Not extensible.


Registry Keys

Your INF file must create two registry keys, one that defines the extension's globally unique identifier (GUID), and the other that declares the GUID as a control-panel extension. The appropriate part of your INF file should look like this:

[DriverPagesAddReg]
HKEY_CLASSES_ROOT,"CLSID\{Your GUID}\InProcServer32",,,yourdll

HKLM,"Software\Microsoft\Windows\CurrentVersion\Controls Folder
    \ControlPanel\shellex\PropertySheetHandlers\DriverPages",,,
    "{Your GUID}"

You should always use the OLE2 utility, GUIDGEN.EXE, to produce a new GUID.

For more information about INF files, see Device Information Files in the DDK.


Using the IShellPropSheetExt::AddPage Function

You can use the AddPage member function of the IShellPropSheetExt interface to add property-sheet pages to Control Panels. The system calls AddPages when it is about to display a property sheet. The system calls each property-sheet handler registered to the file type to allow the handlers to add pages to the property sheets. This technique is explained in the Shell Extensions section of the Windows 95 Guide to Programming.


Using the IShellPropSheetExt::ReplacePage Function

You can use the ReplacePage member function of the IShellPropSheetExt interface to replace property-sheet pages in Control Panels. This technique is explained in the Shell Extensions section of the Windows 95 Guide to Programming. This section gives only a brief overview of the procedure. Most developers will not replace property-sheet pages in Control Panels, because new functionality is often better exposed in a new page (rather than a replacement page), and because replacing a page can make the built-in Help information incorrect.

The ReplacePage member function is called only by control panels. The uPageID parameter of this function contains the identifier of the property-sheet page to be replaced. The CPLEXT.H header file defines the following identifiers:

Constant | Meaning
CPLPAGE_MOUSE_BUTTONS | Identifier for the mouse control panel's Buttons page
CPLPAGE_MOUSE_PTRMOTION | Identifier for the mouse control panel's Motion page
CPLPAGE_KEYBOARD_SPEED | Identifier for the keyboard control panel's Speed page.


Using Property Page Providers

Property page providers are dynamic-link libraries (DLLs) that work in conjunction with the Device Manager to display property sheets for examining and modifying the settings and configuration of a device. The Device Manager provides a default property page provider that gives access to typical device properties. If your device has properties that are not supported by the default provider, you can extend the capabilities of the default property page provider by creating a custom property provider. With a custom provider you can add new and replace existing property pages in the default property sheets.

This section describes property page providers and explains how to create and register custom providers. For more information about creating and managing property sheets, see the Microsoft Win32 Programmer's Reference.


User Requests for Properties

A user requests access to the properties or a device or class by pressing the Properties button presented by the Device Manager. The Device Manager always gives the class installer for the device or class the first opportunity to carry out the request by sending a DIF_PROPERTIES request to the ClassInstall function of the installer. The installer either processes the request completely, displaying and handling its own property sheets, or it returns the ERR_DI_DO_DEFAULT value directing the Device Manager to build a default property sheet to complete the request. (For more information about the class installer, see .)

If the Device Manager builds a property sheet, it relies on custom and default property page providers for the property pages. The Device Manager uses the property pages from the default property page provider if no custom property pages are available for the device. The default property pages, called default general property page and the default resource property page, let the user view and set the general and resource properties of a device. If a custom property page provider exists, the Device Manager gives that provider the opportunity to replace the default property pages or provide new property pages in addition to the default pages. The custom provider must be registered in order for the Device Manager to use it.


Default General Property Page

The default general property page displays the name of the device and the device driver, and also offers these actions to the user:

Enable/Disable Device | Enables or disables the device. The action taken to enable or disable depends on the capabilities of the device.
Remove Device | Removes the hardware and driver keys from the registry in preparation of the user physically removing the device.
Remove Driver | Removes the driver key in the registry but leaves the device configured.
Change Driver | Installs a new device driver for the device.
Hardware Profile Settings | Lets the user specify how to deal with hardware when the machine is docked or undocked.


Default Resource Property Page

The default resource property page shows the basic system resources consumed by a given device, such as memory addresses, I/O ports, IRQ, and DMA channels. It also lets the user view current resource settings and set a forced configuration for the device.


Custom Property Page Providers

A custom property page provider adds new property pages or replaces default property pages for a specific device or class. A provider can be a separate DLL or it can be combined with the class installer or the control panel applet for the device. If combined with the installer, the provider must be distinct from any properties handling provided by the ClassInstall function of the installer.

Every property page provider exports the property page enumeration function, usually named EnumPropPages. The Device Manager dynamically links and calls this function just before displaying the default property sheet to give the provider a chance to add pages or replace the default pages.

A provider must export dialog procedures to support the property pages it adds to the default property sheet. The dialog procedures process initialize values and process user input for the property pages when the Device Manager displays the property sheet. The Device Manager uses the PropertySheet function to display the properties sheet, so the dialog procedures for the individual pages must be prepared to process the messages and notifications associated with this function.


Property Page Enumeration Function

When the Device Manager calls EnumPropPages, it passes three arguments: the address of a DEVICE_INFO structure, the address of a AddPropSheetPageProc function, and a 32-bit value. The DEVICE_INFO structure identifies the device or class that the user has requested properties for. The 32-bit value is used by the Device Manager to keep track of internal processing and must not be changed.

You use the AddPropSheetPageProc function to add property pages to the default property sheet. The function requires two parameters: a handle of a valid property sheet page and the supplied 32-bit value. You create a valid property sheet page and retrieve its handle by using the CreatePropertySheetPage function. The AddPropSheetPageProc function returns TRUE if it added the page, FALSE otherwise.

To replace one or both default property pages, you add the replacement pages using AddPropSheetPageProc, then set one or both of these values in the Flags member of the DEVICE_INFO structure:

DI_GENERALPAGE_ADDED | Replaces the default general property page.
DI_RESOURCEPAGE_ADDED | Replaces the default resources property page.

If you replace a default page, your replacement page must provide all the basic functions provided by that default page. If you do not replace a default page, the Device Manager uses the default page for the class or device as appropriate.

The EnumPropPages function returns TRUE to direct the Device Manager to display the property sheet or FALSE to prevent display.


Property Page Dialog Procedure

Property page dialog procedures support property pages added by a provider. The procedures must adhere to the guidelines given for property sheets in the Microsoft Win32 Programmer's Reference. In particular, a dialog procedure must process any WM_NOTIFY messages appropriately.

A property page dialog procedure should also save the address of the DEVICE_INFO structure sent as the lParam parameter with the WM_INITDIALOG message. The Device Manager sends this structure to help the dialog procedure determine the device or class. Dialog procedures typically use the SetWindowLong to store this value in the DWL_USER portion of the window handle, then retrieve the address using the GetWindowLong function on subsequent messages.

If a reboot or restart is necessary due to the settings provided by the user, a dialog procedure show always set an appropriate value in the Flags member of the DEVICE_INFO structure. It must not send a PSN_GUISTART or PSN_REBOOT notification to the property sheet dialog procedure.


Provider Registration

The Device Manager requires that you register your property page provider by adding appropriate entries to the registry. You register a provider by using the EnumPropPages entry in either the class branch for a class provider or the device driver branch (one level below the class branch) for a device provider. The entry has this form:

EnumPropPages=DLL-name,[EnumPropPagesName]

The EnumPropPagesName must be the name of a function exported by the given DLL. If no name is given, the Device Manager searches the given DLL for an exported function having the name EnumPropPages.

If you register a provider of a device, the Device Manager uses that provider only if the user requests access to the properties of that specific device. If you register for a class, the Device Manager uses it whenever the user requests access to properties of a device in that class for which no device-specific provider exists.

You should always register a property page provider by specifying the appropriate registry commands in the INF file for your device or class of devices.


Class Provider

The Device Manager calls the class property page provider to provide property pages for both class properties and device properties. This allows the class provider to add property pages to every device in its class.

The class provider is responsible for determining whether the request is for class properties or device properties by checking for the DI_CLASSONLY value in the Flags member in the DEVICE_INFO structure. If the value is present, the request is for class properties; otherwise, for device properties.

When DI_CLASSONLY is set, the provider cannot replace the default resource property page. This means the Device Manager ignores the DI_RESOURCEPAGE_ADDED value even if set.

If the class provider adds or replaces property pages on a request for device properties, it must follow the same rules as the device property provider.


Device Provider

The Device Manager calls the device property sheet provider to provide property pages for a specific device. The Device Manager determines the device provider by checking for the EnumPropPages entry under the device driver branch in the registry. A device provider can add new property pages or replace one or both of the default property pages.


Using the Device Information (INF) File Editor

Device information (INF) files contribute to the goal of providing customers and developers with an easier way to install hardware devices. The information in an INF file brings together one or more devices, device drivers, and the operating system's installation procedure to ensure an easy and complete hardware setup and installation.

If you are providing hardware or plug hardware for Windows 95 computers, you must create an INF file that enables your device to be installed and to work in the Windows 95 environment. The Windows 95 DDK contains a tool, Infedit, that enables you to build an INF file by responding to the Infedit user interface. The topic Getting Started Using Infedit contains the requirements for a sample INF file, XSCSI.INF, and walks through the process of using Infedit to turn those requirements into a working INF file.

For more information about how Windows 95 uses INF files, use the Programs command from the Windows 95 Start menu to open the Windows 95 DDK and then select the Plug and Play Reference. Use the Find tab on the displayed property sheet to find instances of the word INF in the Plug and Play topics.


Limits of the INF File Editor

Note that several classes of devices -- namely printers and network adapters -- have INF file extensions specific to those devices which are not described in this section. For a description of the printer INF extensions, see the topic Router and Local Print Provider in the Windows 95 DDK help reference for the print spooler and printer drivers. For a description of the network INF extensions, see the topic Network Driver Installer in the Windows 95 DDK help reference for networks.

There are also some special cases of INF files, such as INF files for multifunction boards, that require you to add items to the INF file you create with Infedit.


Introducing INF Files

In order to become immediately productive with Infedit, it helps to have a model of the parts of an INF file in mind. Infedit builds an INF file one section and one item at a time.

An INF file is made up of a set of named sections. To be used by the operating system installer, a section must contain one or more items.

Each section begins with the section name enclosed in square brackets. In this way, INF files are similar to Windows INI files. There can be any number of sections in an INF file, but there are only about two dozen types of sections that can be in an INF file, and about eight of these types of sections appear far more often than other types in INF files.

Each type of section has a particular purpose; for example, to copy files or to add entries to the registry. Each of the items in a section contributes to that section's purpose and the syntax of each type of item that can be used in a particular type of section reflects that.

Three sections from a sample INF file are shown in the following, so you can more easily visualize an INF file being made up of sections and each section being made up of one or more items. The section named SourceDisksNames contains one item, the section named SourceDisksFiles contains two items, and the section named Strings contains three items.

[SourceDisksNames]
1=CX2590 Windows 95 Installation Disk,Instd1,0000-0000

[SourceDisksFiles]
CX2590.MPD=1
SRSutil.exe=1

[Strings]
String1="Corporation X"
String2="Corporation X"
String3="CX2590 SCSI Adapter"


Introducing the INF Editor

The easiest way to create an INF file is to run the INF Editor, Infedit. After the Windows95 DDK is installed, Infedit can be found in the directory %DDKROOT%\BIN. You can use Infedit to either build an INF file from scratch or edit an existing INF file for the same class of device as your device.

After Windows 95 is installed on a computer, a large number of INF files can be found in the directory %WINROOT%\INF. When you first start using Infedit, it is instructive to use Infedit to open some of these INF file and browse their contents using the Infedit user interface. After opening and browsing several INF files, you will be quite familiar with the Infedit user interface and may have gotten some ideas for your INF file by example. Look for INF files of the same device class as your device and open and browse them. You may be able to edit one of them instead of building your INF file from scratch.

Following is a list of the hardware class names that are built into Windows 95:

CD-ROM Controllers
Display Adapters
Floppy disk controllers
Hard disk controllers
Keyboard
Memory Technology Drivers (MTDs)
Modem
Mouse
Multifunction adapters
Network adapters
Other devices
PCMCIA sockets
Ports (COM & LPT)
Printer
SCSI Controllers
Sound, video and game controllers
System devices

When you run Infedit to create a new INF file, select New from the Infedit File menu. Infedit presents a screen that enables you to build and name INF file sections, and to fill each of those sections with one or more items:

On the left side of the screen, Infedit maintains a graphic representation of the current structure and content of your INF file. The folders represent all the types of INF file sections you can create and are containers for sub folders that represent the sections. The section sub folders, in turn, are containers for items.

On the right side of the screen is an edit area where you compose items. Each item has a name and a value. In general, when you double-click on a section subfolder on the left of the screen, the items currently in that subfolder are displayed in the edit area on the right. Double-click on an item name displayed in the edit area to display a dialog box that enables you to change the value of the item.

See the topic Reference for detailed information items that can be put into each of the INF file sections you can build with Infedit. (The Reference section is organized by INF file section type.) Note that if you need to build a section in your INF file that is not explicitly shown as a folder in the Infedit user interface, you can use the Miscellaneous Sections folder in the Infedit user interface to build those type of sections. An example of such a section is the HW section, which is only used in INF files for multifunction devices.


Types of INF File Sections

All the types of sections that can be in an INF file and the purpose of each type of section is listed in the following table.

Type of INF File Section | Purpose | Comment
INF file header. | The standard header for all INF files. | The INF file header items are contained in the folder labeled NEWINF.INF in the preceding illustration . The syntax and meaning of the INF file header items is defined in the Reference topic under the section name Version.
ClassInstall section | Installs a new class for a device in the Class section of the registry on a Windows 95 machine. |
Disk Names section | Identifies and names the disk(s) that are the source of files that are copied to the hard disk during installation. Also names the files that are on each of the installation disk(s). | The syntax and meaning of items that are contained in a Disk Names section are documented in the Reference topic under the topics SourceDisksNames section and SourceDisksFiles section.
Manufacturer | Identifies the manufacturer of one or more devices defined in the INF file, describes the device(s), and identifies the Install section that contains the script for installing each device. |
Install sections | Identifies the other sections in the INF file that describe the resource requirements of a device and which add entries to the registry, copy files, etc. |
CopyFiles sections | Names the files copied from the source disk(s) to the destination directories during device installation. | Infedit puts the destination directory information into a DestinationDirs section.
Rename Files sections | Names the files to be renamed when they are copied from the source disk(s) to the destination directories during device installation. Also gives the new filenames on the destination directories. | Infedit puts the destination directory information into a DestinationDirs section.
DelFiles sections | Names the files to be deleted from destination directories during device installation. | Used, for example, to delete obsolete versions of device drivers. Infedit puts the destination directory information into a DestinationDirs section.
Add Registry sections | Adds subkeys or value names to the registry, optionally setting values. |
Delete Registry sections | Deletes subkeys or value names from the registry. |
Log configuration sections | Defines device configuration details such as IRQs, memory address ranges, I/O address ranges, and/or DMA channels. |
Update Autoexec.bat sections | Manipulates lines in the AUTOEXEC.BAT file. |
Update config.sys sections | Manipulates lines in the CONFIG.SYS file. |
Ini File to Registry sections | Moves lines or sections from an INI file to the registry, creating or replacing an entry under a specific key in the registry. |
Update Ini File sections | Replaces, adds, and deletes entries in an INI file. |
Update Ini Fields sections | Replaces, adds, and deletes fields in the value of a given entry in an INI file. |
Strings section | Defines one or more names that represent a string of displayable characters. |
HW section | A special case of an Install section. The only type of section that allows entries to be made to the Hardware branch of the registry. | Build an HW section using the Miscellaneous Sections folder of the Infedit user interface. See the Reference section for the items that appear in an HW section and their syntax.
NoResDup section | Provides a method for the installing devices that use no resources. | If needed, can be built as part of a Device subsection of a Manufacturer section.
PosDup section | Provides a method for identifying devices that may appear to be separate devices but are in fact the same device. | If needed, can be built as part of a Device subsection of a Manufacturer section.


Getting Started Using Infedit

This topic illustrates the use of Infedit by starting with a list of Windows® 95 installation and operating requirements for a fictitious hardware device (a SCSI adapter) and then showing how to use Infedit to build an INF file that meets these requirements. A listing of the completed INF file produced by Infedit is shown at the end of the section.

After the Windows 95 DDK is installed, you can run Infedit from the Windows 95 Run dialog. Infedit is installed in the directory %DDKROOT%\BIN.

To build a new INF file, select the New option from the File menu.

The opening screen is displayed, which shows all the types of INF file sections you can build with Infedit. To get started on a new INF file, build the Manufacturer section first. Once you have put a Company Name item into the Manufacturer section, you can save the INF file and reopen it at any time to build the other sections.

This section shows how to build an INF file for a SCSI adapter made by Corporation X. To put a Company Name item with the value "Corporation X" into the Manufacturer section, do the following with Infedit:

  1. Right-click on the Manufacturer folder to display a pop-up menu.
  2. From the pop-up menu, select the New Manufacturer option. A New Manufacturer sub folder is displayed.
  3. Double-click on the new sub folder to get an opportunity to edit the Company Name item. On the right side of the screen, in the Item column of the edit area, the item name Company Name appears.
  4. Double-click on the item Company Name and an Edit String dialog will be displayed that enables you to enter "Corporation X" as the value for the New Company item.

Once you have put the Company Name item into the Manufacturer section, you can save and name the INF file using the Save As option from the File menu. The example INF file discussed in this section is named XSCSI.INF.

The operations shown previously that are used to navigate the Infedit interface in the process of putting the Company Name item into the New Manufacturer subfolder are used to put other types of items into other types of sub folders. Each subfolder represents an INF file section. The general operations used repeatedly in the Infedit user interface are:

  • •Right-click on a folder or sub folder to display a pop-up menu that enables you to operate on the folder or sub folder.
  • •Double-click on a user interface object to get a chance to edit it.

The Infedit interface also presents a screen area dedicated to editing item values. This screen area is organized as two columns. The left-most column lists the names of all the items that can be in the section you are editing. The right-most column lists the current value of each item. Double-click on an item name to display the edit dialog you need to change the current value of the item.

Note that once you have built the Manufacturer section of the INF file, you can build the rest of the sections in almost any sequence. You do not have to completely finish building a section before you start on another one, either. The following example will show the INF file sections being built in a particular sequence, but that is not the only sequence that can be used.


Sample INF File Requirements

When you build the first version of an INF file for your device, the operating characteristics of the device are well known — even if you are building the INF file to test a hardware prototype on a Windows 95 machine.

For example. consider a fictitious piece of hardware, a SCSI Host Adapter which is built by Corporation X. The name of the device is the CX2590 SCSI Adapter and its Windows 95 device ID is *CX2590. There are no compatible device IDs for this device. All this information can be put into the INF file in a Manufacturer section.

The board has the following resource requirements:

  • Four contiguous IO ports based at 180H, 190H, 1A0h or 1B0h.
  • One exclusive IRQ chosen from 4,5,9,10,11.
  • One DMA channel, although the board will work without one.

All of this resource requirements information can be put into the INF file in one or more Log Config-type sections. Use the Infedit Log Config Sections folder to do this.

Corporation X is providing two files to support the device on one installation diskette:

  • A SCSI miniport driver with the filename CX2590.MPD, which must be copied from a device installation diskette to the directory %WINROOT%\SYSTEM\IOSUBSYS on the Windows 95 computer.
  • A utility program with the filename SRSUTIL.EXE, which must be copied from a device installation diskette to the BIN sub directory of the Windows 95 computer boot directory. The BIN sub directory of the computer boot directory is the default subdirectory for this installation process.
  • Both CX2590.MPD and SRSUTIL.EXE fit on one installation diskette. The descriptive name of a device installation diskette is "CX2590 Windows 95 Installation Disk" (this is the name of the installation diskette that is displayed to the user during the device installation procedure). The installation diskette label is Instd1 and there is no serial number on the installation diskette.

All of the filename information and the source and destination information for copying the files can put into the INF file in one or more CopyFiles-type sections. Use the Infedit CopyFiles folder to do this.

Two entries must be made under the HKR key of the registry:

  • An entry that specifies the device loader the CX2590; for a block device like a SCSI adapter the device loader is the I/O Supervisor (IOS).
  • An entry that specifies the filename of the minport driver for the device; in this example, that is the file named CX2590.MPD.

The information that causes these two registry entries to be made at installation time can all be put into the INF file in one or more Add Registry-type sections. Use the Infedit Add Registry Sections folder to do this.


Building the Sample INF File

This topic walks through the process of using Infedit to build each of the INF file sections necessary to satisfy the requirements listed in Sample INF File Requirements. The procedures used to build several types of INF file sections with Infedit are shown.

  • To see an example of building a Manufacturer section, see Completing the Manufacturer Section.
  • To see an example of building a Logical Configuration section, which specifies the resource requirements of a device such as IRQs and I/O addresses, see Specifying Resource Requirements.
  • To see an example of building an Add Registry section, see Adding Registry Entries.
  • To see an example of building a Copy Files section, see Copying Files.
  • To see an example of editing an INF file header section, see Completing the INF File Header Section.
  • To see information about adding strings to a Strings section, see Adding Strings to the Strings Section.


Completing the Manufacturer Section

The first step in creating a Manufacturer section, creating a Company Name item, is described in the topic Getting Started Using Infedit. Besides the company name of the device manufacturer, device description information goes into the Manufacturer section. To add these device description items:

  1. Right-click on the company name sub folder (labeled Corporation X in this example) and select the New Device option from the pop-up menu. This creates a device description sub folder.
  2. Double-click the device description sub folder to display the items you can edit in this sub folder.

You can edit up to six items in the device description sub folder. As stated in the topic Sample INF File Requirements, the descriptive name of the device is the CX2590 SCSI Adapter, the Windows 95 device ID (also called the hardware ID) is *CX2590, and there are no compatible device IDs. To put these values into the appropriate INF file items, double-click in turn on the Item names Device Description, Hardware ID, and Compat ID(s) in the edit area of the Infedit screen. Double-clicking on each item name displays the String Edit dialogs that enable you to put these values into the INF file.

You can also name the INF file install section for the CX2590 at this time, even though you haven't built the install section yet. Each install section in an INF file contains the script for copying files, adding registry entries, etc. during installation of a device. The name of the install section, which you have an opportunity to enter now, is up to you but a self-documenting name has the form device.Install. For example, in this case, name the install section CX2590.Install.

When you enter an install section name value in the device description subfolder, Infedit automatically creates a subfolder under the Install Sections folder named, for example in this case, CX2590.Install (the name you entered).

After this is done, the edit display will look like this:

The Exclude from Select and Copy Files Only items are not used in this example. For more information about these items, see the Reference section Manufacturer topic, where Control Flags are discussed.

Note that there can be more than one device description sub folder in a Manufacturer folder, even though this sample INF file has only one. The only constraint on the device description sub folders you use in an INF file is that all the devices described must be of the same device class. For example, in this sample INF file, there could be device description folders for other SCSI Adapter devices.


Specifying Resource Requirements

The resource requirements and constraints of the CX2590 are listed in the following:

  • Four contiguous IO ports based at 180H, 190H, 1A0h or 1B0h.
  • One exclusive IRQ chosen from 4,5,9,10,11.
  • One DMA channel, although the board will work without one.

Use Infedit to put this logical configuration information into the Log Config Sections folder:

  1. Right-click on the Log Config Sections folder and then select the New Logical Configuration Section option from the pop-up menu to create a new subfolder under the Log Config folder.
  2. Double-click on the new subfolder to display the items you can edit.

You are given the opportunity to edit two items: Section Name and Priority.

  • Double-click on the item name Section Name in the edit area to display an Edit String dialog. You can name the new logical configuration section anything; for this example the section name "CX2590_DMA" was entered into the dialog box.
  • Since it is normal to run the CX2590 with a DMA channel (although it will run without one), the Priority item should be set to NORMAL. This may already be set as the default Priority value. If not, double-click on the Priority label of the Item column in the Infedit interface edit area and use the drop-down list in the dialog box. For more information about the meaning of each of the priority options in the drop-down list, see the Log Config Sections topic in the Reference section.

To enter the I/O port, IRQ, and DMA channel requirements, right-click on the subfolder you just named (in this example, that subfolder is named CX2590_DMA). At this point, the relevant part of the Infedit screen will look like this, with the pop-up menu:


Adding the I/O Description Item

The I/O port requirements for the CX2590 are four contiguous I/O ports based at I/O addresses 180H, 190H, 1A0h and 1B0h.

To add the I/O port requirements for the CX2590:

  1. Select the Add I/O Descriptor option from the pop-up menu to add an I/O descriptor subfolder.
  2. If you double-click on the new subfolder in order to edit items, the edit area on the right side of the Infedit screen does not give you an opportunity to edit any items. This indicates that there is another pop-up menu available, so right-click in the new subfolder to display the pop-up.

The pop-up menu gives you two options for edit displays: Add Type 1 I/O Range and Add Type 2 I/O Range. These are just two different ways of entering the same information, but for some I/O port requirements (such as the ones used in this example), the Type 2 form is quicker to use. See the Log Config Sections topic in References for details about the two different ways of expressing I/O port requirements.

To continue with the example, after you select the Add Type 2 I/O Range option an Input/Output Range 0 subfolder is created. Double-click on the new subfolder to display the items you can edit in the edit area.

Since the I/O port requirements for the CX2590 are four contiguous I/O ports based at I/O addresses 180H, 190H, 1A0h and 1B0h you can double-click on each of the items in the edit display, except Alias Offset and Attributes, and use the Edit String dialogs to produce an edit display that looks like the screen shown in the following. When you enter a value into the Edit String dialog, you do not need to enter the entire hexadecimal expression. For example, when you enter the value for the Size item, just enter 4 instead of 0x0004.

Note that when you double-click the Attributes item, no Edit String dialog box is displayed. That is because the Attributes item is reserved for future use.


Adding the IRQ Description Item

The IRQ requirements for the CX2590 are one exclusive IRQ chosen from IRQ 4, 5, 9, 10, or 11.

To add the IRQ requirements to the XSCSI.INF file for the CX2590:

  1. Right-click on the CX2590_DMA subfolder under the Log Config Sections folder and select the Add IRQ Descriptor option. This will create an IRQ Descriptor subfolder.
  2. Double-click on the new subfolder.

An array of IRQs and Yes/No values appears in the edit area. Double-click on individual IRQ item names to set IRQs 4, 5, 9, 10, and 11 to Yes and all other IRQs to No. When you are done, the IRQ array in the edit area will look like this:

Item             Value
  IRQ Sharable     No
  IRQ  0           No
  IRQ  1           No
  IRQ  2           No
  IRQ  3           No
  IRQ  4           Yes
  IRQ  5           Yes
  IRQ  6           No
  IRQ  7           No
  IRQ  8           No
  IRQ  9           Yes
  IRQ 10           Yes
  IRQ 11           Yes
  IRQ 12           No
  IRQ 13           No
  IRQ 14           No
  IRQ 15           No


Adding the DMA Description Item

The CX2590 requires one DMA channel for NORMAL operation. The CX2590 can use either DMA channel zero, 1, 2, or 3 and the DMA bus width is eight bits.

To add the DMA requirements to the XSCSI.INF file for the CX2590:

  1. Right-click on the CX2590_DMA subfolder under the Log Config Sections folder and select the Add DMA Descriptor option. This will create an DMA Descriptor subfolder.
  2. Double-click on the new subfolder.

An array of DMAs and Yes/No values appears in the edit area. Double-click on individual DMA item names to set DMA channels zero, 1, 2, and 3 to Yes and all other DMAs to No. In this example, there is no need to change the default DMA bus width of 8 bits. When you are done, the DMA array will look like this:

Item             Value
  DMA Bus Width    8 bits
  DMA  0           Yes
  DMA  1           Yes
  DMA  2           Yes
  DMA  3           Yes
  DMA  4           No
  DMA  5           No
  DMA  6           No
  DMA  7           No

Note that given the requirements in this example, adding this DMA descriptor to the INF file does not satisfy all the DMA requirements for this example. The DMA requirements are:

"One DMA channel, although the board will work without one."

In order to meet the requirement "the board will work without one," you will have to add another logical configuration section to the INF file, with priority set to SUBOPTIMAL and with no DMA item. The method for doing this is shown in the next section.


Adding a Suboptimal Logical Configuration Section

To add a second logical configuration section to the INF file XSCSI.INF

  1. Right-click on the Log Config Sections folder and select the New Logical Configuration Section option from the pop-up menu. A new subfolder will be displayed with no section name (the displayed section name will be <Section name>.
  2. Double-click on the new folder to display the items you can edit.

You are given the opportunity to edit two items: Section Name and Priority.

  • Double-click on the item name Section Name in the edit area to display an Edit String dialog. You can name the new logical configuration section anything; for this example the self-documenting section name "CX2590_NoDMA" was entered in the dialog box.
  • Since the board will run without a DMA channel, but sub optimally relative to when it runs with a DMA channel, set the Priority item value to SUBOPTIMAL. Double-click on the Priority item label in the edit area and select the value SUBOPTIMAL from the drop-down list in the Edit List dialog box.

To enter the IO port and IRQ requirements, right-click on the subfolder you just named and follow the same procedures as shown in the earlier topics Adding the I/O Description Item and Adding the IRQ Description Item.

Note that you will not add a DMA description item to this logical configuration section because it describes the device configuration where the device is running sub optimally, without a DMA channel.


Adding the Logical Configuration Sections to the Install Section

For the logical configuration sections you have built (named CX2590_DMA and CX2590_NoDMA) to be recognized by the operating system installer, the names of the two sections have to be added to the Install section. To do this

  1. Double-click on the Install sections subfolder named CX2590.Install. A list of all the types of sections that can be referred to in an Install section will be displayed in the edit area on the right side of the screen.
  2. Since you want to add logical configuration names to the install section, double-click the Log Config item in the edit box list. The Edit Section List dialog is displayed with the a list section names displayed in the Available Sections list box on the left-hand side of the dialog.
  3. Highlight the names of both logical configuration sections, CX2590_DMA and CX2590_NoDMA, and select the Add> button to move both section names to the Included Sections list on the right of the dialog. Then click the OK button.

At this point, the edit display looks like this:

This display reflects that the two logical configuration sections have been put into the INF file and added to the install section script. Other types of sections have to be built to complete the INF file requirements stated in Sample INF File Requirements. Entries have to added to the registry and device driver files have to be copied from a device installation diskette to the appropriate sub directories on the hard drive.


Adding Registry Entries

For a block device such as the CX2590 SCSI adapter,

  • The Windows I/O Supervisor (IOS) must be specified as the device loader in a registry entry.
  • A registry entry must be made that holds the name of the block device miniport driver, which in this example is named CX2590.MCD.


Creating the AddReg-type Section for the DevLoader

To put a new AddRef-type section into the INF file that makes one of these registry entries at the time the CX2590 adapter is installed, you can use Infedit in the following way:

  1. To add an AddReg-type subfolder to the INF file, right-click on the AddRegistry Sections folder and then select the New Add Registry Section option from the pop-up menu. In the Infedit user interface, this creates a new unnamed subfolder under the Add Registry folder.
  2. To name the new subfolder (section), double-click on the new subfolder and then double-click on the Section Name label in the Item column of the edit area. Use the Edit String dialog to enter the name. You can use any name; in this example, StdIOS_RegEntries is the name used.
  3. To add an item to the new AddReg-type section, right-click on the folder that represents the section (the folder named StdIOS_RegEntries). Then select the Add Section Value option from the pop-up menu. This creates a new subfolder, named Item 0, to hold the new item.
  4. To add the item to the section, double-click on the Item 0 folder. The edit region of the Infedit interface displays the items that can be put in an item that goes into an AddReg-type INF file section.
  5. Double-click on the Value Name in the Item column of the display and use the Edit String dialog to enter the string DevLoader. Then double-click on Value in the Item column and use the Edit String dialog to enter the string IOS.

When you are done, the edit region display will look like this:


Creating the AddReg-type Section for the Miniport Driver

You can use the same method to add an AddReg-type section to the INF file that creates a registry entry for the Miniport driver at installation time. In this example, that section is named CX2590_RegEntries, but can be named anything as long as it is a unique section name in the INF file. The filename of the miniport driver is CX2590.MPD.

The AddReg-type section items that must be put into an INF file vary between classes of devices. One way to find out what entries are required is to look at the AddReg-type sections in the INF files for your class of device that are in the %WINROOT%\INF directory after Windows 95 is installed on your machine.

Adding References to the AddReg-Type Sections to the Install Section

For the AddReg-type sections you have built (named StdIOS_RegEntries and CX2590_RegEntries) to be recognized by the operating system installer, the names of the two sections have to be added to the Install section. To do this

  1. Double-click on the Install sections subfolder named CX2590.Install. A list of all the types of sections that can be referred to in an Install section will be displayed in the edit area on the right side of the screen.
  2. Since you want to add the names of AddReg-type sections to the Install section of the INF file, double-click the AddReg item in the edit box list. Use the Edit Section List dialog to move the two AddReg-type section names (StdIOS_RegEntries and CX2590_RegEntries in this example) from the Available Sections list box to the Included Sections list box and then click OK.

At this point, the edit display looks like this:

This display reflects that the two AddReg-type sections and two logical configuration sections have been put into the INF file and the names of all four sections have been added to the Install section script. Sections that enable files to be copied from an installation diskette to specific hard disk directories have to added to the INF file also.


Copying Files

One or more sections must be put into the INF file that causes the files on an installation diskette to be copied to specific sub directories on the hard disk, and these section names must be listed in the CX2590.Install section in the INF file. Corporation X is providing two files to support the device on one installation diskette:

  • A SCSI miniport driver with the filename CX2590.MPD, which must be copied from a device installation diskette to the directory %WINROOT%\SYSTEM\IOSUBSYS on the Windows 95 computer.
  • A utility program with the filename SRSUTIL.EXE, which must be copied from a device installation diskette to the BIN sub directory of the Windows 95 computer boot directory. The BIN subdirectory of the computer boot directory is the default destination directory for this installation.
  • Both CX2590.MPD and SRSUTIL.EXE fit on one installation diskette. The descriptive name of a device installation diskette is "CX2590 Windows 95 Installation Disk" (this is the name of the installation diskette that is displayed to the user during the device installation procedure). The installation diskette label is Instd1 and there is no serial number on the installation diskette.

The following sections walk through the procedure of using Infedit to add the required sections and Install section items to the INF file. Note that in this example case, no files have to be renamed when they are copied from the diskette to the hard disk; if renaming was required, a Rename Files-type section would have to be put into the INF file. Also note that for this example CX2590 installation, no preexisting files on the hard drive, such as obsolete drivers, have to be deleted as part of the overall file copying strategy; if there were such requirements, a DelFiles-type section would have to be put in the INF file.


Specifying the Default Destination Directory

The default destination directory for an installation is specified in the INF file header section. (The header section of an INF file is also called the Version section.) To use Infedit to specify the default destination directory:

  1. Double-click on the root folder of the Infedit display (the folder at the top of the tree in the Infedit user interface, which is labeled C:\sampinf\xscsi.inf in this example).
  2. Double-click on the label Default Destination Directory in the Item column of the edit area of the Infedit user interface. This causes the Edit Destination dialog to be displayed.
  3. In the Edit Destination dialog, select LDID_BOOT from the LDID drop-down list, and then enter BIN in the Subdirectory Relative to LDID Path edit box.
  4. Select the OK button on the dialog box and the path C:\BIN appears in the Default Destination Directory value column in the edit area (if, as in this example, the computer boot directory is C:\).


Specifying the Files to Copy and Their Destination

To put the names of the two files to be copied and their directory destinations on the hard disk of the computer, you can use the Infedit interface in the following way:

  1. To create a CopyFiles-type section in the INF file, right-click on the CopyFiles Sections folder and select the New Copy Files Section option. This creates a new subfolder labeled NewFileSection that represents the new CopyFiles-type section in the INF file.
  2. To enter the name of the new CopyFiles-type section and the destination directory for the files listed in that section, double-click on the new subfolder.
  3. To change the section name, double-click on Section Name in the Item column and use the Edit String dialog to enter a section name. You can use any section name, as long as it is a unique section name in the INF file. For this example, the section name MoveMiniport is used because this is the section that will contain the destination directory for the file CX2590.MPD.
  4. To change the destination directory to C:\WINDOWS\SYSTEM\IOSUBSYS, double-click on Destination Directory in the Item column of the edit area and use the Edit Destination Directory dialog. From the LDID list box, select LDID_IOS. Notice that at the bottom of the dialog, you can see the complete path that corresponds to the LDID value you selected and it is C:\WINDOWS\SYSTEM\IOSUBSYS. Note that you may need to blank out the Subdirectory Relative to LDID Path edit box. For more information about LDID values, see the topic DestinationDirs Section topic in Reference.

Now you need to specify all the files on the installation diskette(s) that will be copied into the LDID_IOS sub directory. In this example, there is only one: CX2590.MCD. To use the Infedit interface to add this filename as an item to the MoveMiniport section:

  1. Right-click on the subfolder named MoveMiniport and select Add File Name from the pop-up menu. This will cause a File Name item to be added to the edit area:

  2. Double-click on File Name in the Item column of the edit area and use the Edit String dialog to enter the filename CX2590.MCD.

You can repeat steps 1 and 2 as many times as necessary to list all the files that are to be copied into the sub directory whose complete path is the value of the Destination Directory item in this section. If you make a mistake with a File Name item, right-click on File Name for the mistaken item and select Delete from the pop-up menu.

To put the file copy information into the INF file for the other file on the installation diskette, the file named SRSUTIL.EXE, repeat the process you used for CX2590.MPD. Start by right-clicking the CopyFiles Sections folder and selecting the New Copy Files Section item from the pop-up menu. Note that the name of the default destination directory path which you set earlier in the INF file header section (C:\BIN in this example) is displayed in the edit area. Since that is the destination directory for SRSUTIL.EXE, it is not necessary to use the Edit Destination dialog in this case. You can also accept the default value for the Name item, which is the value NewFileSection, as long as it is a unique section name in the INF file.


Specifying the Source Diskette(s)

CX2590.MPD and SRSUTIL.EXE are on an installation diskette. with the descriptive name of "CX2590 Windows 95 Installation Disk." The installation diskette label is Instd1 and there is no serial number on the installation diskette.

To use Infedit to add a Disk Names-type section to the INF file, you can:

  1. Right-click on the Disk Names Section folder and select the Add Diskname option. This creates a new subfolder labeled with the logical disk number, 1.
  2. To add items to the new Disk Names-type section, double-click on the new subfolder. The items that can be put into a Disk Names-type section are displayed in the edit area of the Infedit screen.
  3. To enter the descriptive name of the installation diskette, double-click on the Disk Description label in the Item column of the edit area and use the Edit String dialog to enter the string "CX2590 Windows 95 Installation Disk."
  4. To enter the label of the installation diskette, double-click on the Disk label in the Item column of the edit area and use the Edit String dialog to enter the string Instd1.
  5. To add the filenames of all the files on the installation diskette to the INF file, double-click on the File Name(s) label in the Items column of the edit area and use the Edit Disk File List dialog. Move the two filenames, CX2590.MPD and SRSUTIL.EXE, from the Available Files list to the Included Files list.

When you are done with these steps, the edit area looks like this:

At this point, all the sections necessary to copy the files from the installation diskette to the appropriate sub directories on the hard disk have been added to the INF file, except for adding references in the install section to the two new CopyFiles-type sections that have just been built.


Adding References to the CopyFiles-Type Sections to the Install Section

For the CopyFiles-type sections you have built (named MoveMiniPort and NewFileSection) to be recognized by the operating system installer, the names of the two sections have to be added to the Install section.

  1. Double-click on the Install sections subfolder named CX2590.Install. A list of all the types of sections that can be referred to in an Install section will be displayed in the edit area on the right side of the screen.
  2. Since you want to add the names of CopyFiles-type sections to the Install section of the INF file, double-click the Copy File Sections item in the edit area. Then use the Edit Section List dialog to move the two CopyFiles-type section names from the Available sections list box to the Included Sections list box and then click OK.

At this point, the edit display looks like this:

This display reflects that the two CopyFiles-type sections have been put into the INF file and the names of the two sections have been added to the Install section. At this point, the Install section is complete. It refers to two Copy File Sections names, two AddReg section names, and two LogConfig section names.


Completing the INF File Header Section

Every INF file has a header. Infedit creates a default header when you open a new INF file. To look at the header on the example INF file, double-click on the top-most folder in the Infedit interface, the folder just to the left of the INF file name (which in the example case is XSCSI.INF).

To complete this header, you must supply a value for the Class item. In the example case of the CX2590, the class name is the string "SCSIAdapter." For a list of all the device classes recognized by Windows 95, see the topic Introducing the INF Editor. If your device is not in a class recognized by Windows 95, then in addition to setting the Class item value here in the INF file header, you will also have to put a Class Install section into your INF file. Use the Class Install folder in the Infedit interface to do that. See the Class Install Section topic in the Reference section for information about the items that go into a Class Install section.

You may also want to supply a value for the Provider item in the header. This is the name of the organization that builds and tests the INF file. For example, in this case it might be Corporation X.

You also must ensure that the INF file signature value is correct. It must be $CHICAGO$. If the Signature item has any value other than $CHICAGO$, change it. The code that checks this signature in the installer uses a case-insensitive string comparison on the Signature item value, so you can use $Chicago$, for example.

A layout file is an alternative way to specify the file and directory structure on the installation media. In the example case, where there are only two files on one installation diskette and they are both in the root directory, there is no need to use a layout file.

Note that the Default Destination Directory item has the value that was put into the INF file header section earlier (in this example, the value is C:\BIN).


Adding Strings to the Strings Section

The values of all the items in the Strings section of an INF file are strings that appear in the user interface when the device is installed. Having all these strings in one section of the INF file makes it easier to translate them for international markets.

Infedit automatically puts a Strings section in any INF file it is building and adds items to it as needed. For example, when you add the device description item to the Manufacturer section, Infedit automatically puts that string, "CX2590 SCSI Adapter" in the sample INF file, into the Strings section. You never directly edit the strings put into the Strings section in this way by Infedit.

To add strings to the Strings section in addition to the strings Infedit automatically places there, right-click on the Strings folder and select the Add String Value option from the pop-up menu. In the edit area, two items are displayed: String Name and Replacement Value. For the String Name value, use a name of a form other than %Stringn% where n is an integer value. The Replacement Value value is the actual string that will be displayed at the user interface when the INF file is used.

In the example case of XSCSI.INF, there are no strings to add to the Strings section. In other INF files, it may be necessary for you to add strings to the Strings section. In particular, after you have built an AddReg. Ini File to Registry, Update Ini File, or Update Ini Fields type of section, ask yourself if any of the string values in these types of sections will be displayed at the user interface. If you identify such strings, you are responsible for making an entry in the Strings section for each one. It is important to note that you will have to change the item value in the other section (such as the AddReg type section) the String Name value that you use in the Strings section (String Name values have the form %string-name%). For a look at the relationship between string name values in the Strings section and the other sections of an INF file, see the topic Sample INF File Listing.


Sample INF File Listing

The INF file that is built when you use Infedit in the way previously described is listed as:

[Version]
Signature="$CHICAGO$"
Class=SCSIAdapter
Provider=%String0%

[DestinationDirs]
DefaultDestDir=30,BIN
MoveMiniPort=12

[Manufacturer]
%String1%=SECTION_0

[SECTION_0]
%String2%  = CX2590.Install,*CX2590

[CX2590.Install]
Copyfiles=MoveMiniPort,NewFileSection
AddReg=StdIOS_RegEntries,CX2590_RegEntries
LogConfig=CX2590_DMA,CX2590_NoDMA

[MoveMiniPort]
CX2590.MPD

[NewFileSection]
srsutil.exe

[StdIOS_RegEntries]
HKR,,DevLoader,0,IOS

[CX2590_RegEntries]
HKR,,Miniport,0,CX2590.MPD

[CX2590_DMA]
ConfigPriority=NORMAL
IOConfig=4@180-1B3%fff0(3::)
IRQConfig=4,5,9,10,11
DMAConfig=0,1,2,3

[CX2590_NoDMA]
ConfigPriority = SUBOPTIMAL
IOConfig = 4@180-1B3%fff0(3::)
IRQConfig = 4,5,9,10,11

[ControlFlags]

[SourceDisksNames]
1=CX2590 Windows 95 Installation disk,Instd1,0000-0000

[SourceDiskSFiles]
CX2590.MPD=1
srsutil.exe=1

[Strings]
String0="Corporation X"
String1="Corporation X"
String2="CX2590 SCSI Adapter"


Special Uses of INF Files

There are several device installation requirements that can be met by INF files, but which are not part of the installation requirements for the sample INF file, XSCSI.INF. These special requirements of INF files are:

  • Installing a multifunction device.
  • Installing a property provider.
  • Overriding PCMCIA tuples on PC card devices.


MultiFunction Card INF Description

A multifunction card is any card which is enumerated as a single device but is actually more than one device on a single card. Typical would be a sound card which is a CD-ROM interface and a sound controller on the same card. During installation, the device installer will execute both the install section for this device and the InstallSection.HW as described previously. The following special HW section items have been created for multifunction devices:

  • HardwareID List
  • Resource Map

A HardwareID List item is a text item that is added with an AddReg-type section. Hardware ID items cause the Configuration Manager to create devnodes for every HardwareID item used. The Configuration Manager enumerates these devices. An example HardwareID item looks like this:

HKR,Child0000,HardwareID,,MF\ID

A Resource Map item is used in an INF file when installing an EISA multifunction card. Resources are not really assigned to the parent but rather to the independent functions. The EISA enumerator, however, reports only the parent device and reports all resources as belonging to the common parent. A Resource Map item tells the Configuration Manager how to divide the parent resource between the children. The resource map is a binary format record added using an AddReg-type entry, where each byte represents the ordinal of the EISA resource record belonging to the child. This is not a bit map, it is a list of ordinals. There is a limit of 256 EISA ordinal values. An example Resource Map item looks like this:

HKR,,ResourceMap,,1,01,04,26


Installing a Property Provider

Class property providers can be registered in the class install section. A property provider entry point specified the class section of the registry will be called any time properties are displayed for a device of the appropriate class. A property provider can be registered by using the following addreg entry in the class AddReg section.

hkr,,EnumPropPages,,"DLL,Entrypoint"

Similarly a property providers can be registered for a specific device by using the following addreg entry in the device install section. Doing this makes HKR relative to the driver section and thus is invoked only for the specific device.

hkr,,EnumPropPages,,"DLL,Entrypoint"


PCMCIA Configuration Tuple Overrides

On occasion, the tuples found on a PCMCIA card are not correct. When this happens, an override can be specified in the INF and will be installed into the registry during device installation. Overrides are Logical Config sections in binary format specified using an AddReg entry.

HKR,Override,0000,1,<Ascii binary logical config entry>


Device Installer Reference

This section describes the functions and structures that support the device installer.


Functions

The following topics describe the functions that support the device installer.


DiBuildClassDrvList

Builds a list of all drivers for a specified class of devices.

RETERR
  DiBuildClassDrvList(
    LPDEVICE_INFO lpdi
    );

Return Value

Returns OK if successful, otherwise an ERR_DI_xxx error code will be returned. If the return is OK, the lpdi->lpClassDrvList field will point to a list of supported drivers for the class. If there are no class drivers, this pointer will be NULL.

Parameters

lpdi
Pointer to the device for which a class driver list should be built.

Comments

The lpdi->szClassName field should be filled in with the class name to be used when building the class driver list. If this field is not filled in, DiBuildClassDrvList will build a list of drivers for all classes. Note this API will build a full DRIVER_NODE struct for each driver in the class. Building full DRIVER_NODES requires memory overhead for each DRIVER_NODE and is slow, especially if the list of drivers is large.


DiBuildClassDrvListFromOldInf

Builds a class driver list from an old (Windows 3.1) style INF file.

RETERR
  DiBuildClassDrvListFromOldInf(
    LPDEVICE_INFO  lpdi,
    LPCSTR  lpszSection,
    OLDINFPROC  lpfnOldInfProc,
    LPARAM  lParam
    );

Return Value

  • OK

Parameters

lpdi
Pointer to a device info structure for a device that is being installed.
lpszSection
The install section in the old INF to be converted
lpfnOldInfProc
Callback function to fill in content of INF file.
lParam
Reference data passed to the callback proc.

Comments

The atDriverPath field of the lpdi must be set to a valid OEM INF file, which is type INF_TEXT. This function will generate an appropriate Windows 95 INF header, and then call the supplied callback proc to convert the specified section into Windows 95 specific data. After the new INF is generated, this function will build a class driver list much like the DiBuildClassDrvList API does.


DiBuildClassInfoList

This API will build a list of CLASS_INFO structs. There will be one CLASS_INFO struct added to the list for each installed class in the user's system.

RETERR
  DiBuildClassInfoList(
    LPLPCLASS_INFO  lplpci
    );

Return Value

This function returns OK if the list is build successfully.

Parameters

lplpci
A buffer to receive a pointer to a list of CLASS_INFO structs.

Comments

This function will return OK, even if the list is empty. The call must change the content of the passed in buffer to determine if the list is empty. If the value NoUseClass is present in the class's registry branch, the class will automatically be excluded from the list. This behavior cannot be overridden.

See Also

DiBuildClassInfoListEx, DiDestroyClassInfoList


DiBuildClassInfoListEx

This API will build a list of CLASS_INFO structures.

RETERR
  DiBuildClassInfoListEx(
    LPLPCLASS_INFO  lplpci,
    DWORD  dwFlags
    );

Return Value

This function returns OK if the list is build successfully.

Parameters

lplpci
A buffer to receive a pointer to a list of CLASS_INFO structures.
dwFlags
Flags used to control exclusion of classes from the list. The following flags are defined:
DIBCI_NOINSTALLCLASS | Exclude a class if it has the value NoInstallClass present in its registry branch.
DIBCI_NODISPLAYCLASS | Exclude a class if it has the value NoDisplayClass present in its registry branch.

Comments

This API is similar to DiBuildClassInfoList, except it allows more control over what classes will be included in the list.

See Also

DiBuildClassInfoList, DiDestroyClassInfoList


DiBuildCompatDrvList

Builds a Compatible Driver list for a specified device.

RETERR
  DiBuildCompatDrvList(
    LPDEVICE_INFO  lpdi
    );

Return Value

Returns OK if successful, otherwise an ERR_DI_xxx error code will be returned. If the return is OK, the lpdi->lpCompatDrvList field will point to a list of compatible drivers. If there are no compatible drivers, this pointer will be NULL.

Parameters

lpdi
Pointer to the device for which a compatible driver list should be built.

Comments

The device specified must have a hardware registry key (for example, an entry in HKLM\ENUM), and should have either, or both, a REGSTR_VAL_HARDWAREID and REGSTR_VAL_COMPATIBLEIDS value. The values should contain comma delimited lists of device ID's. Note the device ID's cannot contain comma's themselves.

See Also

DiBuildCompatDrvList

Built on Wednesday, July 11, 2001


DiCallClassInstaller

Call the appropriate class installer with the specified installer function.

RETERR
  DiCallClassInstaller(
   DI_FUNCTIONS  diFctn,
   LPDEVICE_INFO  lpdi
   );

Return Value

Returns OK if successful, otherwise an ERR_DI_xxx error code will be returned.

Parameters

diFctn
Class installer function to call. This can be one of the following:
DIF_SELECTDEVICE | Select a driver to be installed for the device.
DIF_INSTALLDEVICE | Install the driver for the device.
DIF_PROPERTIES | Display a properties dialog for the device.
DIF_REMOVE | Remove the device.
DIF_FIRSTTIMESETUP | Perform first time setup initialization. This message is sent during the first boot of Windows 95 and contains only class information.
DIF_SELECTCLASSDRIVERS | Select drivers for all devices of the class specified by the lpdi.
DIF_VALIDATECLASSDRIVERS | Ensure all devices of the class specified by the lpdi are ready to be installed.
DIF_INSTALLCLASSDRIVERS | Install drivers for all devices of the class specified by the lpdi.
DIF_CALCDISKSPACE | Compute the amount of disk space required by drivers for the device.
DIF_DESTROYPRIVATEDATA | Destroy any private date referenced by the lpdi->dwClassInstallReserved.
DIF_MOVEDEVICE | The device is being moved to a new location in HKLM\ENUM.
DIF_DETECT | Detect any devices of class specified by the lpdi.
DIF_INSTALLWIZARD | Add any pages necessary to the New Device Wizard for the class specified by the lpdi.
DIF_DESTROYWIZARDDATA | Destroy any private data allocated due to a DIF_INSTALLWIZARD message.
DIF_PROPERTYCHANGE | The device's properties are changing. The device is being enabled, disabled, or has had a resource change.
DIF_DETECTVERIFY | The class installer should verify any devices it previously detected. Non verified devices should be removed.
DIF_INSTALLDEVICEFILES | The class installer should only install the driver files for the selected device.

lpdi
Pointer to a DEVICE_INFO structure for the device who's class installer is to be called.

Comments

This function will attempt to load and call the class installer for the class listed in the lpdi->szClassName field. If there is no class installer, or the class installer returns ERR_DI_DO_DEFAULT, then this function will call a default procedure for the specified class installer function.


DiChangeState

This API is used to change the state of an installed device. It is the default handler for the DIF_PROPERTYCHANGE class installer message.

RETERR
  DiChangeState(
    LPDEVICE_INFO  lpdi,
    DWORD  dwStateChange,
    DWORD  dwFlags,
    LPARAM  lParam
    );

Return Value

This function returns OK if that are files that need to be copied. ERR_DI_NOFILECOPY will be returned if no files need to be copied.

Parameters

lpdi
Device Info for device who's properties are being changed.
dwStateChange
Flag indicating which state is being changed.
DICS_ENABLE | The device is being enabled.
DICS_DISABLE | The device is being disabled.
DICS_PROPCHANGE | The properties of the device have changed, for example, it is getting a new resource assignment.
DICS_START | The device is being started. If the device also disabled it will be enabled as well.
DICS_STOP | The device is being stopped.

dwFlags
Flags specific to the action specified by dwChangeState.
DICS_FLAG_GLOBAL | The action should be applied globally to all configurations.
DICS_FLAG_CONFIGSPECIFIC | The action should be applied only to the configuration specified by lParam.

lParam
If dwFlags has the DICS_FLAG_CONFIGSPECIFIC bit set then this param contains the configuration number which the changes should be applied to. Specifying zero indicates that the current configuration should be used.


DiCreateDeviceInfo

Creates a DEVICE_INFO structure and initializes it with specified information.

RETERR
  DiCreateDeviceInfo(
    LPLPDEVICE_INFO  lplpdi,
    LPCSTR lpszDescription,
    DWORD  dnDevnode,
    HKEY  hkey,
    LPCSTR  lpszRegsubkey,
    LPCSTR  lpszClassName,
    HWND  hwndParent
    );

Return Value

Returns OK if successful, otherwise an ERR_DI_xxx error code will be returned.

Parameters

lplpdi
Pointer to a pointer to a DEVICE_INFO structure. This pointer receives the pointer to the allocated DEVICE_INFO structure created by this function.
lpszDescription
If non-null, the description of the device.
dnDevnode
If nonzero, the value of the devnode of the device.
hkey
The registry HKEY which the lpszRegsubkey is located in. This is usually HKEY_LOCAL_MACHINE.
lpszRegsubkey
If non-null, the registry subkey string where the hardware information of the device is stored. This subkey is relative to the hkey described previously.
lpszClassName
If non-null, the class name of the device.
hwndParent
If non-null, the window handle of the top level window use for any U/I related to installing the device.

Comments

The DEVICE_INFO structure is allocated zero-init in SETUPX's private heap, and so must be destroyed using DiDestroyDeviceInfoList

See also DiDestroyDeviceInfoList


DiDeleteDevRegKey

This API will delete one or both to the registry keys for the specified device.

RETERR
  DiDeleteDevRegKey(
    LPDEVICE_INFO  lpdi,
    int  iFlags
    );

Return Value

OK if the registry key(s) are deleted

Parameters

lpdi
A device info structure for the device that is being removed.
iFlags
Flags indicating which registry key(s) to remove.
DIREG_DEV | Delete the hardware registry key for the device. This is a key that exists in the \ENUM\ROOT branch.
DIREG_DRV | Delete the software, or Driver, registry key for the device. This is a key that is in the HKLM\System\CurrentControlSet\Services\Class registry subkey.
DIREG_BOTH | Delete both registry keys for the device.


DiDestroyClassInfoList

This API will delete a single, or list of, CLASS_INFO structure(s).

RETERR
  DiDestroyClassInfoList(
    LPCLASS_INFO  lpci
    );

Return Value

OK

Parameters

lpci
A pointer to a single or list of CLASS_INFO structure(s).

Comments

This function will free any memory associated with the passed in lpci. This function will free any DEVICE_INFO structures also associated with this CLASS_INFO.

See Also

DiBuildClassInfoList, DiBuildClassInfoListEx


DiDestroyDeviceInfoList

Destroys a list of DEVICE_INFO structures.

RETERR
  DiDestroyDeviceInfoList(
    LPDEVICE_INFO  lpdi
    );

Return Value

OK

Parameters

lpdi
Pointer to a list of DEVICE_INFO structures.

Comments

The list can contain only 1 structure. This function will free any compatible and/or class driver lists created using the lpdi(s) as well. Any class installer DLL's or property provider DLL's associated with the lpdi(s) list be freed also.

See Also

DiCreateDeviceInfo, DiGetClassDevs, DiGetClassDevsEx


DiGetClassDevs

Returns a list of DEVICE_INFO structures for all of the installed devices of a specified class.

RETERR
  DiGetClassDevs(
    LPLPDEVICE_INFO  lplpdi,
    LPCSTR  lpszClassName,
    HWND  hwndParent,
    int  iFlags
    );

Return Value

Returns OK if successful, otherwise an ERR_DI_xxx error code will be returned.

Parameters

lplpdi
Pointer to a pointer to a DEVICE_INFO structure. This pointer receives the pointer to the beginning of the list of DEVICE_INFO structures created by this function.
lpszClassName
If non-null, the class name to use when creating the list of devices.
hwndParent
If non-null, the window handle of the top level window use for any U/I using the resulting DEVICE_INFO structures.
iFlags
Control options for building the device list.
DIGCF_PRESENT | Return only devices which are present. This flag is only valid if Config Manager is running and has created devnodes for the installed devices.
DIGCF_ALLCLASSES | Return a list of installed devices for all classes. If set, this flags will cause lpszClassName to be ignored.
DIGCF_PROFILE | Return only devices which are present in the current configuration.

Comments

This function build a list of device that have been previously installed. This function uses the HKLM\ENUM branch of the registry to build its list.

See Also

DiGetClassDevsEx


DiGetClassDevsEx

Returns a list of DEVICE_INFO structures for all of the installed devices of a specified class.

RETERR
  DiGetClassDevsEx(
    LPLPDEVICE_INFO  lplpdi,
    LPCSTR  lpszClassName,
    LPSTR  lpszEnumerator,
    HWND  hwndParent,
    int  iFlags
    );

Return Value

Returns OK if successful, otherwise an ERR_DI_xxx error code will be returned.

Parameters

lplpdi
Pointer to a pointer to a DEVICE_INFO structure. This pointer receives the pointer to the beginning of the list of DEVICE_INFO structures created by this function.
lpszClassName
If non-null, the class name to use when creating the list of devices.
lpszEnumerator
If specified this API will retrieve devices created by the specified enumerator. If NULL then this functions works like DiGetClassDevs. For example. this parameter could specify ROOT, and only device in the ENUM\ROOT branch would be returned.
hwndParent
If non-null, the window handle of the top level window use for any U/I using the resulting DEVICE_INFO structures.
iFlags
Control options for building the device list.
DIGCF_PRESENT | Return only devices which are present. This flag is only valid if Config Manager is running and has created devnodes for the installed devices.
DIGCF_ALLCLASSES | Return a list of installed devices for all classes. If set, this flags will cause lpszClassName to be ignored.
DIGCF_PROFILE | Return only devices which are present in the current configuration.

Comments

This function build a list of device that have been previously installed. This function uses the HKLM\ENUM branch of the registry to build its list.

See Also

DiGetClassDevs


DiInstallClass

Install the [ClassInstall] section of the specified INF.

RETERR
  DiInstallClass(
    LPCSTR  lpszInfFileName,
    DWORD  dwFlags
    );

Return Value

Returns OK if successful, otherwise an ERR_DI_xxx error code will be returned.

Parameters

lpszInfFileName
The name of the INF file containing a [ClassInstall] section.
dwFlags
Flags to control the geninstall operation.
DI_NOVCP | This flag should be specified if a VCP queue is already opened.
DI_NOBROWSE | This flag should be specified if no file browsing should be allowed in the event a copy operation cannot find a specified file.

Comments

This API is generally called the Device Manager when it installs a device of a new class.


DiInstallDevice

Install the device specified by lpdi.

RETERR
  DiInstallDevice(
    LPDEVICE_INFO  lpdi
    );

Return Value

Returns OK if successful, otherwise an ERR_DI_xxx error code will be returned. lpdi->Flags will be set to indicate if the system needs to be rebooted or restarted for the device to be started.

Parameters

lpdi
Pointer to a DEVICE_INFO structure for the device being installed. If lpdi->lpSelectedDriver is NULL this function will install a NULL driver for the device, otherwise it installs the driver specified in the driver node.

Comments

This API is the default handler for the DIF_INSTALLDEVICE class installer function. This API will install a device by GenInstalling the install section specified by the lpid->lpSelectedDriver DRIVER_NODE. If Config Manager is running, this API will attempt to dynamically start the device.


DiOpenClassRegKey

Open the class registry key, and optionally a specific class's subkey.

RETERR
  DiOpenClassRegKey(
    LPHKEY  lphk,
    LPCSTR  lpszClassName
    );

Return Value

Returns OK if successful, otherwise an ERR_DI_xxx error code will be returned.

Parameters

lphk
Buffer to receive the opened registry key.
lpszClassName
The name of a specific class. If non NULL the specified class's subkey will be opened are returned if it exists. If this parameter is NULL, the registry key of the class branch (HKLM\System\CurrentControlSet\Services\Class) will be returned.


DiOpenDevRegKey

This API will open either of the registry keys associated with a device.

RETERR
  DiOpenDevRegKey(
    LPDEVICE_INFO  lpdi,
    LPHKEY  lphk,
    int  iFlags
    );

Return Value

OK

Parameters

lpdi
A device info structure for device who's registry key is being opened.
lphk
Buffer to receive the opened registry key.
iFlags
Flags indicating which type of regkey to create.
DIREG_DEV | Open the hardware registry key for the device. This is a key that exists in the \ENUM\ROOT branch.
DIREG_DRV | Open the software, or Driver, registry key for the device. This is a key that is in the HKLM\System\CurrentControlSet\Services\Class registry subkey.

Comments

Note that it is the callers responsibility to close the returned registry key when it is finished with it.


DiRemoveDevice

Removes a device from the computer

RETERR
  DiRemoveDevice(
    LPDEVICE_INFO  lpdi
    );

Return Value

OK

Parameters

lpdi
Pointer to a DEVICE_INFO structure for the device to be removed.

Comments

This function will remove the device from the system, deleting both of its registry keys, and dynamically stopping the device if it has a Devnode. If the device cannot be dynamically stopped, then flags will be set in the lpdi->Flags field that will eventually cause the user to be prompted to shut the system down. The removal is either global to all configurations, or specific to one configuration depending on the content of the lpdi->lpClassInstallParams field.


DiSelectDevice

This is the default handle for the DIF_SELECTDEVICE class installer message.

RETERR
  DiSelectDevice(
    LPDEVICE_INFO  lpdi
    );

Return Value

OK if a driver is selected successfully, otherwise one of the ERR_DI_ error codes will be returned

Parameters

lpdi
A device info structure for the device that is having a driver selected.

Comments

This routine will handle the UI for allowing a user to select a driver for the device defined by the passed in lpdi. By using the Flags field of the lpdi structure, the caller can specify special handling of the UI, such as allowing selecting from OEM disks.


Structures

The following topics describe the structures that support the device installer.


DEVICE_INFO

This is the basic data structure for most Device installation APIs. A DEVICE_INFO represents a device that is being installed on the system, or an installed device that is being modified in some way.

typedef struct {
  UINT  cbSize;
  struct  _DEVICE_INFO FAR *lpNextDi;
  char  szDescription[LINE_LEN];
  DWORD  dnDevnode;
  HKEY  hRegKey;
  char  szRegSubkey[MAX_DEVNODE_ID_LEN];
  char  szClassName[MAX_CLASS_NAME_LEN];
  DWORD  Flags;
  HWND  hwndParent;
  LPDRIVER_NODE  lpCompatDrvList;
  LPDRIVER_NODE  lpClassDrvList;
  LPDRIVER_NODE  lpSelectedDriver;
  ATOM  atDriverPath;
  ATOM  atTempInfFile;
  HINSTANCE  hinstClassInstaller;
  HINSTANCE  hinstClassPropProvidor;
  HINSTANCE  hinstDevicePropProvidor;
  HINSTANCE  hinstBasicPropProvidor;
  FARPROC  fpClassInstaller;
  FARPROC  fpClassEnumPropPages;
  FARPROC  fpDeviceEnumPropPages;
  FARPROC  fpEnumBasicProperties;
  DWORD  dwSetupReserved;
  DWORD  dwClassInstallReserved;
  GENCALLBACKPROC  gicpGenInstallCallBack;
  LPARAM  gicplParam;
  UINT  InfType;
  HINSTANCE  hinstPrivateProblemHandler;
  FARPROC  fpPrivateProblemHandler;
  LPARAM  lpClassInstallParams;
  struct _DEVICE_INFO FAR  *lpdiChildList;
  DWORD  dwFlagsEx;
  LPDRIVER_INFO  lpCompatDrvInfoList;
  LPDRIVER_INFO  lpClassDrvInfoList;
} DEVICE_INFO;

Members

cbSize
Size of the DEVICE_INFO structure.
*lpNextDi
Pointer to the next DEVICE_INFO structure in a linked list.
szDescription[LINE_LEN]
Buffer containing the description of the device.
dnDevnode
If set, this contains the address of the DevNode associated with the device.
hRegKey
An opened registry key that contains the device's registry subkey. This is usually HKEY_LOCAL_MACHINE.
szRegSubkey[MAX_DEVNODE_ID_LEN]
Buffer containing the device's hardware registry subkey. This is key is rooted in hRegKey, and is ususally some place in the \ENUM branch.
szClassName[MAX_CLASS_NAME_LEN]
Buffer containing the device's class name.
Flags
Flags for controlling installation and U/I functions. Some flags can be set prior to calling device installer APIs, and other are set automatically during the processing of some APIs.
DI_SHOWOEM | Set if OEM disk support should be allowed
DI_SHOWCOMPAT | Will be set if only a compatible driver list is being displayed by DiSelectDevice.
DI_SHOWCLASS | Will be set if only a Class driver list is is being displayed by DiSelectDevice.
DI_SHOWALL | Will be set if both a compatible driver list and a class driver list are being shown by DiSelectDevice.
DI_NOVCP | Set if no VCP (Virtual Copy Procedure) is desired during DiInstallDevice.
DI_DIDCOMPAT | Will be set if DiBuildCompatDrvList has been done, and lpCompatDrvList points to this device's compatible driver list.
DI_DIDCLASS | Will be set if DiBuildClassDrvList has been done, and lpClassDrvList points to this device's class driver list.
DI_AUTOASSIGNRES | Unused.
DI_NEEDRESTART | Will be set if the device requires a restart of Windows after installation or a state change.
DI_NEEDREBOOT | Will be set if the device requires a reboot of the machine after installation or a state change.
DI_NOBROWSE | Set to disable browsing when selecting an OEM disk path.
DI_MULTMFGS | Will be set if a class driver list, or class info list contains multiple manufactures.
DI_DISABLED | Unused.
DI_GENERALPAGE_ADDED | Set by a property page provider if a general properties page has been added to the device's property sheet.
DI_RESOURCEPAGE_ADDED | Set by a property page provider if a resource properties page has been added to the device's property sheet.
DI_PROPERTIES_CHANGE | Set if a device's properties have been changed and require an update of the Device Manager's U/I.
DI_INF_IS_SORTED | Set if the INF containing drivers for this device is in sorted order.
DI_ENUMSINGLEINF | Set if DiBuildCompatDrvList and DiBuildlassDrvList should only search the INF file specified by atDriverPath.
DI_DONOTCALLCONFIGMG | Set if the configuration manager should not be called during DiInstallDevice.
DI_INSTALLDISABLED | Set if the device should be installed in a disabled state by default.
DI_CLASSONLY | Set if this DEVICE_INFO structure contains only a class name.
DI_CLASSINSTALLPARAMS | Set if the lpClassIntallParams field points to a class install parameter block.
DI_NODI_DEFAULTACTION | Set if DiCallClassInstaller should not perform any default action if the class installer return ERR_DI_DO_DEFAULT, or there is not class installer.
DI_QUIETINSTALL | Set if device install API should be as silent as possible using default choices wherever possible.
DI_NOFILECOPY | Set if DiInstallDevice should skip file copying.
DI_FORCECOPY | Set if DiInstallDevice should always copy file, even if they are present on the system.
DI_DRIVERPAGE_ADDED | Set by a property page provider if a driver properties page has been added to the device's property sheet.
DI_USECI_SELECTSTRINGS | Set if class installer provided strings should be used during DiSelectDevice.
DI_OVERRIDE_INFFLAGS | Unused.
DI_PROPS_NOCHANGEUSAGE | Set if there should be no Enable/Disable capability on the device's general property page.
DI_NOSELECTICONS | Set if no small icons should be used during DiSelectDevice.
DI_NOWRITE_IDS | Set if DiInstallDevice should not write the device's hardware and compatible IDs to the registry.

hwndParent
Window handle that will own U/I dialogs related to this device.
lpCompatDrvList
Pointer to a linked list of DRIVER_NODES representing the compatible drivers for this device.
lpClassDrvList
Pointer to a linked list of DRIVER_NODES representing all drivers of this device's class.
lpSelectedDriver
Pointer to a single DRIVER_NODE that has been selected as the driver for this device.
atDriverPath
Global ATOM containing the path to this device's INF file. This is set only of the driver came from an OEM INF file. This will be zero if the INF is a standard Windows INF file.
atTempInfFile
Global ATOM containing the name of a temporary INF file for this device's drivers. This is set if the drivers came from an old style INF file and have been converted.
hinstClassInstaller
Class installer module instance.
hinstClassPropProvidor
Class Property Provider module instance.
hinstDevicePropProvidor
Device Property Provider module instance.
hinstBasicPropProvidor
Basic Property Provider module instance.
fpClassInstaller
Procedure address of class install function.
fpClassEnumPropPages
Procedure address of the Class property provider page enumeration function.
fpDeviceEnumPropPages
Procedure address of the Device property provider page enumeration function.
fpEnumBasicProperties
Procedure address of the Basic device property provider page enumeration function.
dwSetupReserved
Reserved for use by Setup.
dwClassInstallReserved
Reserved for use by Class Installers.
gicpGenInstallCallBack
Procedure address of a GenInstall call back function. This would be set if the class installer wanted to handle GenInstall callbacks during DiInstallDevice.
gicplParam
lParam for the GenInstall Callback.
InfType
The type of INF file being used. This will be INFTYPE_TEXT or INFTYPE_EXECUTABLE.
hinstPrivateProblemHandler
Module handle for the device's private problem procedure.
fpPrivateProblemHandler
Procedure address of the device's private problem handler.
lpClassInstallParams
Pointer to a class install parameter block. Class installer parameters are specific to the class install functions.
*lpdiChildList
Pointer to a linked list of DRIVER_INFO structures representing children of this device.
dwFlagsEx
Additional control flags.
DI_FLAGSEX_USEOLDINFSEARCH | Set if INF Search functions should not use indexed searching.
DI_FLAGSEX_AUTOSELECTRANK0 | Set if DiSelectDevice should automatically select rank zero match drivers.
DI_FLAGSEX_CI_FAILED | Will be set internally if there was a failure to load or call a class installer.
DI_FLAGSEX_FILTERCLASSES | If set, DiBuildClassDrvList will check for Class inclusion filters. This means devices will not be included in the list, if their class is marked as a NoInstallClass class.
DI_FLAGSEX_SETFAILEDINSTALL | If set, then if DiInstallDevice installs a NULL driver, it will also set the FAILEDINSTALL configuration flag
DI_FLAGSEX_DEVICECHANGE | If set, the device manager will rebuild its tree of devices after the device property sheet is closed.
DI_FLAGSEX_ALWAYSWRITEIDS | If set, and the flag, DI_NOWRITE_ID is clear (for example, that flag takes higher precedence) then always write Hardware and Compat IDs, even if they already exist
DI_FLAGSEX_ALLOWEXCLUDEDDRVS | If set, DiSelectDevice will display drivers that have the Exclude From Select state

lpCompatDrvInfoList
Pointer to a linked list of DRIVER_INFO structures that are compatible with this device.
lpClassDrvInfoList
Pointer to a linked list of DRIVER_INFO structures representing all drivers for this device's class.


DRIVER_INFO

This structure contains the information necessary to present the user with a select device dialog.

typedef struct {
  WORD  cbSize;
  struct  _DRIVER_INFO FAR *lpNextInfo;
  LPSTR  lpszDescription;
  LPSTR  lpszMfgName;
  LPSTR  lpszProviderName;
  WORD  Rank;
  DWORD  dwFlags;
  LPARAM  lpReserved;
  DWORD  dwPrivateData;
} DRIVER_INFO;

Members

cbSize
Size of this structure in bytes.
*lpNextInfo
Pointer to the next DRIVER_INFO structure in a linked list.
lpszDescription
Pointer to the description of the device being supported by this driver.
lpszMfgName
Pointer to the name of the manufacture of this driver.
lpszProviderName
Pointer to provider of this driver if the lpdi->Flags has the DI_MULTMFGS flag set.
Rank
The Rank match of this driver. Ranks go from zero to n, where zero is the most compatible.
dwFlags
Flags that control the use of this driver node. These are the same as the flags defined for a DRIVER_NODE.
DNF_DUPDESC | This driver has the same device description from by more than one provider.
DNF_OLDDRIVER | Driver node specifies old/current driver
DNF_EXCLUDEFROMLIST | If set, this driver node will not be displayed in any driver select dialogs.
DNF_NODRIVER | Set if we want to install no driver, e.g. no mouse.drv
DNF_CONVERTEDLPINFO | Set if this Driver Node was converted from an Info Node. Setting this flag will cause the cleanup functions to explicitly delete it.

lpReserved
Reserved for use by the Device Installer.
dwPrivateData
Reserved for use by the Device Installer.


DRIVER_NODE

This structure represents a driver which can be installed for a specific device.

typedef struct {
  struct _DRIVER_NODE FAR*  lpNextDN;
  UINT  Rank;
  UINT  InfType;
  unsigned  InfDate;
  LPSTR  lpszDescription;
  LPSTR  lpszSectionName;
  ATOM  atInfFileName;
  ATOM  atMfgName;
  ATOM  atProviderName;
  DWORD  Flags;
  DWORD  dwPrivateData;
  LPSTR  lpszDrvDescription;
  LPSTR  lpszHardwareID;
  LPSTR  lpszCompatIDs;
} DRIVER_NODE;

Members

lpNextDN
Pointer to the next driver node in a list.
Rank
The Rank match of this driver. Ranks go from zero to n, where zero is the most compatible.
InfType
Type of INF this driver cam from. This will be either INFTYPE_TEXT or INFTYPE_EXECUTABLE
InfDate
DOS date stamp of the INF file.
lpszDescription
Pointer to a the description of the device being supported by this driver.
lpszSectionName
Pointer to the name of INF install section for this driver.
atInfFileName
Global ATOM containing the name of the INF file.
atMfgName
Global ATOM containing the name of this driver's manufacture.
atProviderName
Global ATOM containing the name of this driver's provider.
Flags
Flags that control functions using this DRIVER_NODE
DNF_DUPDESC | This driver has the same device description from by more than one provider.
DNF_OLDDRIVER | Driver node specifies old/current driver
DNF_EXCLUDEFROMLIST | If set, this driver node will not be displayed in any driver select dialogs.
DNF_NODRIVER | Set if we want to install no driver e.g no mouse driver.

dwPrivateData
Reserved
lpszDrvDescription
Pointer to a driver description.
lpszHardwareID
Pointer to a list of Plug and Play hardware IDs for this driver.
lpszCompatIDs
Pointer to a list of Plug and Play compatible IDs for this driver.


ENABLECLASS_PARAMS

DIF_ENABLECLASS class install parameters

typedef struct {
  UINT  cbSize;
  LPSTR  szClass;
  WORD  wEnableMsg;
} ENABLECLASS_PARAMS;

Members

cbSize
Size of the ENABLECLASS_PARAMS structure.
szClass
The class that is being enabled.
wEnableMsg
Specifies the stage of enabling. Can be one of:
ENABLECLASS_QUERY | The class is about to be enabled. Return ERR_DI_DO_DEFAULT to allow the class to be enabled, or ERR_DI_FAIL_QUERY to prevent the class from being enabled.
ENABLECLASS_SUCCESS | The enabling of the class has succeeded, return ERR_DI_DO_DEFAULT.
ENABLECLASS_FAILURE | The enabling of the class has failed, return ERR_DI_DO_DEFAULT.


INSTALLWIZARDDATA

DIF_INSTALLWIZARD class install parameters. This structure is used by class installers to extend the operation of the hardware installation wizard by adding custom pages.

typedef struct {
  UINT  cbSize;
  LPDEVICE_INFO  lpdiOriginal;
  LPDEVICE_INFO  lpdiSelected;
  DWORD  dwFlags;
  LPVOID  lpConfigData;
  WORD  wAnalyzeResult;
  HPROPSHEETPAGE hpsDynamicPages[MAX_INSTALLWIZARD_DYNAPAGES];
  WORD  wNumDynaPages;
  DWORD  dwDynaWizFlags;
  DWORD  dwPrivateFlags;
  LPARAM  lpPrivateData;
  LPSTR  lpExtraRunDllParams;
  HWND  hwndWizardDlg;
} INSTALLWIZARDDATA;

Members

cbSize
Size of the INSTALLWIZARDDATA structure.
lpdiOriginal
Pointer to the Original DEVICE_INFO structure at the start of the manual installation.
lpdiSelected
Pointer to the current DEVICE_INFO structure that is being manually selected.
dwFlags
Flags that control the operation of the hardware installation wizard. There are currently none defined.
lpConfigData
Pointer to configuration data for analysis to determine if the selected device can be installed with no conflicts.
wAnalyzeResult
Results of analysis to determine if the device can be installed with no problems. The following values are defined:
ANALYZE_FACTDEF_OK | The device can be installed using its factory default settings.
ANALYZE_STDCFG_OK | The device can be installed using a configuration specified in one if its basic logical configurations. The user will probably have to set jumpers or switches on the hardware to match the settings determined by the install wizard.
ANALYZE_CONFLICT | The device cannot be installed without causing a conflict with another device.
ANALYZE_NORESOURCES | The device does not require any resources, so it can be installed witth no conflicts.
ANALYZE_ERROR | There was an error during analysis.
ANALYZE_PNP_DEV | The device has at least one softsettable logical configurations, allowing it to be automatically configured. Additionally the device will be enumerated by one of the standard bus enumerators, so it does not require manual installation, except to pre-copy driver files.

hpsDynamicPages[MAX_INSTALLWIZARD_DYNAPAGES]
An array of property sheet page handles. The class installer would use this array to create custom wizard pages, and insert their handles into this array.
wNumDynaPages
The number of pages inserted into the hpsDynamicPages array.
dwDynaWizFlags
Flags that control the behavior of the installation wizard when dynamic pages have been added.
DYNAWIZ_FLAG_PAGESADDED | Will be set by the install wizard if the class installer adds custom pages.
DYNAWIZ_FLAG_INSTALLDET_NEXT | If set, the install wizard will allow going forward from the detected devices page, otherwise finish will be the default option for the detected devices page.
DYNAWIZ_FLAG_INSTALLDET_PREV | If set, the install wizard will allow going back from the detected devices page.
DYNAWIZ_FLAG_ANALYZE_HANDLECONFLICT | If set, the class installer will handle the case where the selected device cannot be installed because of a conflict.

dwPrivateFlags
Flags that may be defined and used by the class installer.
lpPrivateData
Pointer to private reference data defined and set by the class installer.
lpExtraRunDllParams
Pointer to a string containing extra parameters passed to the hardware install rundll function.
hwndWizardDlg
Window handle of the install wizard top level window.


MOVEDEV_PARAMS

DIF_MOVEDEVICE class install parameters

typedef struct {
  UINT  cbSize;
  LPDEVICE_INFO  lpdiOldDev;
} MOVEDEV_PARAMS;

Members

cbSize
Size of the MOVDEV_PARAMS structure.
lpdiOldDev
Pointer to the device that is being moved.


PROPCHANGE_PARAMS

DIF_PROPCHANGE class install parameters

typedef struct {
  UINT  cbSize;
  DWORD  dwStateChange;
  DWORD  dwFlags;
  DWORD dwConfigID;
} PROPCHANGE_PARAMS;

Members

cbSize
Size of the PROPCHANGE_PARAMS structure.
dwStateChange
State change action. See DiChangeState for details.
dwFlags
Flags specific to the type of state change.
dwConfigID
Configuration ID for configuration-specific changes.

See Also

DiChangeState


REMOVEDEVICE_PARAMS

DIF_REMOVE class install parameters

typedef  struct {
  UINT  cbSize;
  DWORD  dwFlags;
  DWORD  dwConfigID;
} REMOVEDEVICE_PARAMS;

Members

cbSize
Size of the REMOVEDEVICE_PARAMS structure.
dwFlags
Flags indicating the type of removal to perform.
DI_REMOVEDEVICE_GLOBAL | The device will be removed globally.
DI_REMOVEDEVICE_CONFIGSPECIFIC | The device will be removed from only the specified configuration.

dwConfigID
If DI_REMOVEDEVICE_CONFIGSPECIFIC is set, then this is the configuration the device will be removed from. Zero means the current configuration.


SELECTDEVICE_PARAMS

DIF_SELECTDEVICE class install parameters

typedef struct {
  UINT  cbSize;
  char  szTitle[MAX_TITLE_LEN];
  char  szInstructions[MAX_INSTRUCTION_LEN];
  char  szListLabel[MAX_LABEL_LEN];
} SELECTDEVICE_PARAMS;

Members

cbSize
Size of the SELECTDEVICE_PARAMS structure.
szTitle[MAX_TITLE_LEN]
Buffer containing a class installer provided title for the Select Device dialogs.
szInstructions[MAX_INSTRUCTION_LEN]
Buffer containing class installer provided Select Device instructions.
szListLabel[MAX_LABEL_LEN]
Buffer containing a label of the Select Device list of drivers.


Constants

The following topics describe the constants that are used to support device installation.


Error Values

typedef enum {
  ERR_DI_INVALID_DEVICE_ID,
  ERR_DI_INVALID_COMPATIBLE_DEVICE_LIST,
  ERR_DI_REG_API,
  ERR_DI_LOW_MEM,
  ERR_DI_BAD_DEV_INFO,
  ERR_DI_INVALID_CLASS_INSTALLER,
  ERR_DI_DO_DEFAULT,
  ERR_DI_USER_CANCEL,
  ERR_DI_NOFILECOPY,
  ERR_DI_BAD_CLASS_INFO,
  ERR_DI_BAD_INF,
  ERR_DI_BAD_MOVEDEV_PARAMS,
  ERR_DI_NO_INF,
  ERR_DI_BAD_PROPCHANGE_PARAMS,
  ERR_DI_BAD_SELECTDEVICE_PARAMS,
  ERR_DI_BAD_REMOVEDEVICE_PARAMS,
  ERR_DI_BAD_ENABLECLASS_PARAMS,
  ERR_DI_FAIL_QUERY,
  ERR_DI_API_ERROR,
  ERR_DI_BAD_PATH
} _ERR_DEVICE_INSTALL;

ERR_DI_INVALID_DEVICE_ID | Incorrectly formed device ID.
ERR_DI_INVALID_COMPATIBLE_DEVICE_LIST | Invalid compatible device list.
ERR_DI_REG_API | Error returned by one of the registry API.
ERR_DI_LOW_MEM | Insufficient memory to complete.
ERR_DI_BAD_DEV_INFO | A passed in DEVICE_INFO structure is invalid.
ERR_DI_INVALID_CLASS_INSTALLER | The class installer is listed incorrectly in the registry, or points to an invalid class installer.
ERR_DI_DO_DEFAULT | Do the default action for the requested operation.
ERR_DI_USER_CANCEL | The user canceled the operation.
ERR_DI_NOFILECOPY | No need to copy files (in install).
ERR_DI_BAD_CLASS_INFO | A passed in CLASS_INFO structure is invalid.
ERR_DI_BAD_INF | An invalid INF file was encountered.
ERR_DI_BAD_MOVEDEV_PARAMS | A passed in MOVEDEVICE_PARAMS structure was invalid.
ERR_DI_NO_INF | No INF found on supplied OEM path.
ERR_DI_BAD_PROPCHANGE_PARAMS | A passed in PROPCHANGE_PARMS structure was invalid.
ERR_DI_BAD_SELECTDEVICE_PARAMS | A passed in SELECTEDEVICE_PARAMS structure was invalid.
ERR_DI_BAD_REMOVEDEVICE_PARAMS | A passed in REMOVEDEVICE_PARAMS structure was invalid.
ERR_DI_BAD_ENABLECLASS_PARAMS | A passed in ENABLECLASS_PARAMS structure was invalid.
ERR_DI_FAIL_QUERY | The queried action should not take place.
ERR_DI_API_ERROR | One of the Device installation APIs was called incorrectly or with invalid parameters.
ERR_DI_BAD_PATH | An OEM path was specified incorrectly


Dynamic Hardware Install Wizard Constants

Following are the constants that are used when adding custom pages to the hardware install wizard.

MAX_INSTALLWIZARD_DYNAPAGES | The maximum number of dynamic hardware installation wizard pages that can be added by a class installer.
IDD_DYNAWIZ_FIRSTPAGE | Resource ID for the first page that the install wizard will go to after adding the class installer pages.
IDD_DYNAWIZ_SELECT_PREVPAGE | Resource ID for the page that the Select Device page will go back to.
IDD_DYNAWIZ_SELECT_NEXTPAGE | Resource ID for the page that the Select Device page will go forward to.
IDD_DYNAWIZ_ANALYZE_PREVPAGE | Resource ID for the page that the Analyze page will go back to. This will only be used in the event that there is a problem (e.g. a conflict), and the user selects Back from the analyze page.
IDD_DYNAWIZ_ANALYZE_NEXTPAGE | Resource ID for the page that the Analyze page will go to if it continues forward. The wAnalyzeResult in the INSTALLWIZARDDATA structure will contain the analysis results.
IDD_DYNAWIZ_INSTALLDETECTED_PREVPAGE | Resource ID for that page that the Install detected devices page will go back to.
IDD_DYNAWIZ_INSTALLDETECTED_NEXTPAGE | Resource ID for the page that the Install detected devices page will go forward to.
IDD_DYNAWIZ_INSTALLDETECTED_NODEVS | Resource ID for the page that the Install detected devices page will go to in the event that no devices are detected.
IDD_DYNAWIZ_SELECTDEV_PAGE | Resource ID of the hardware install wizard's select device page. This ID can be used to go directly to the hardware install wizard's select device page.
IDD_DYNAWIZ_ANALYZEDEV_PAGE | Resource ID of the hardware install wizard's device analysis page. This ID can be use to go directly to the hardware install wizard's analysis page.
IDD_DYNAWIZ_INSTALLDETECTEDDEVS_PAGE | Resource ID of the hardware install wizard's install detected devices page. This ID can be use to go directly to the hardware install wizard's install detected devices page.
IDD_DYNAWIZ_SELECTCLASS_PAGE | Resource ID of the hardware install wizard's select class page. This ID can be use to go directly to the hardware install wizard's select class page.


Property Page Provider Reference

This section describes the functions and constants used to support device property pages. For overview information about Property Page Providers, see Device Manager and Control Panel.


Functions

The following topics describe the functions that are used with property pages.


AddPropSheetPageProc

Adds a property page to the default property sheet. This function is supplied by the Device Manager and called by a property page provider.

BOOL
  AddPropSheetPageProc(
    HPROPSHEETPAGE  hPage,
    LPARAM  lParam
    );

Return Value

Returns TRUE if the page is added, FALSE otherwise.

Parameters

hPage
Handle of a valid property sheet page as created by the CreatePropertySheetPage function.
lParam
Data passed to the EnumPropPages function. This value must not be modified in any way.


EnumPropPages

Adds property pages to the default property sheet. This provider-supplied function is called by the Device Manager before the default property sheet is displayed.

BOOL
  EnumPropPages(
    LPDEVICE_INFO  lpdi,
    <     LPFNADDPROPSHEETPAGE  AddPropSheetPageProc,
    <     LPARAM  lParam
    );

Return Value

Returns TRUE to display the property sheet, FALSE otherwise.

Parameters

lpdi
Address of a DEVICE_INFO structure that contains information about the device or class that the user has requested properties for.
AddPropSheetPageProc
Address of the system-supplied callback function. For more information about this callback, see the AddPropSheetPageProc function.
lParam
System-supplied data. This data must be passed unchanged to the AddPropSheetPageProc function.


Constants

The following topics describe the constants that are used with property pages.


Dynamic Hardware Install Wizard Constants

Following are the constants that are used when adding custom pages to the hardware install wizard.

Constants

MAX_INSTALLWIZARD_DYNAPAGES
The maximum number of dynamic hardware installation wizard pages that can be added by a class installer.
IDD_DYNAWIZ_FIRSTPAGE
Resource ID for the first page that the install wizard will go to after adding the class installer pages.
IDD_DYNAWIZ_SELECT_PREVPAGE
Resource ID for the page that the Select Device page will go back to.
IDD_DYNAWIZ_SELECT_NEXTPAGE
Resource ID for the page that the Select Device page will go forward to.
IDD_DYNAWIZ_ANALYZE_PREVPAGE
Resource ID for the page that the Analyze page will go back to. This will only be used in the event that there is a problem (for example, a conflict), and the user selects Back from the analyze page.
IDD_DYNAWIZ_ANALYZE_NEXTPAGE
Resource ID for the page that the Analyze page will go to if it continues forward. The wAnalyzeResult in the INSTALLWIZARDDATA structure will contain the analysis results.
IDD_DYNAWIZ_INSTALLDETECTED_PREVPAGE
Resource ID for that page that the Install detected devices page will go back to.
IDD_DYNAWIZ_INSTALLDETECTED_NEXTPAGE
Resource ID for the page that the Install detected devices page will go forward to.
IDD_DYNAWIZ_INSTALLDETECTED_NODEVS
Resource ID for the page that the Install detected devices page will go to in the event that no devices are detected.
IDD_DYNAWIZ_SELECTDEV_PAGE
Resource ID of the hardware install wizard's select device page. This ID can be used to go directly to the hardware install wizard's select device page.
IDD_DYNAWIZ_ANALYZEDEV_PAGE
Resource ID of the hardware install wizard's device analysis page. This ID can be use to go directly to the hardware install wizard's analysis page.
IDD_DYNAWIZ_INSTALLDETECTEDDEVS_PAGE
Resource ID of the hardware install wizard's install detected devices page. This ID can be use to go directly to the hardware install wizard's install detected devices page.
IDD_DYNAWIZ_SELECTCLASS_PAGE
Resource ID of the hardware install wizard's select class page. This ID can be use to go directly to the hardware install wizard's select class page.


Device Information (INF) File Reference

This section describes the syntax and meaning of the items used in each of the various types of INF file sections.


Add Registry Sections

[<add-registry-section>]
<reg-root-string>, [<subkey>], [<value-name>], [<flag>], [<value>]
[<reg-root-string>, [<subkey>], [<value-name>], [<flag>], [<value>]]
   .
   .
   .

Adds subkeys or value names to the registry, optionally setting the value. The add-registry-section name must appear in an AddReg-type item in an Install section.

reg-root-string
Registry root name. Can be one of these value:
HKCR | Same as HKEY_CLASSES_ROOT
HKCU | Same as HKEY_CURRENT_USER
HKLM | Same as HKEY_LOCAL_MACHINE
HKU | Same as HKEY_USERS.
HKR Means relative from the Key passed into GenInstallEx

HKR is always context sensitive to the install section the AddReg/DelReg/etc directives are processed from.

Specifically, HKR is relative to a context specific key, in context of any services installs, it's the service key.

In context of [DDInstall] it's the software key - same as SetupDiOpenDevRegKey(…DIREG_DRV…)

In context of [DDInstall.HW] it's the hardware key - same as SetupDiOpenDevRegKey(…DIREG_DEV…)

subkey
Optional. Identifies the subkey to set. Has the form key1\key2\key3.... This parameter can be expressed as a replaceable string. For example, you could use %Subkey1% where the string to replace %Subkey1% is defined in the Strings section of the INF file.
value-name
Optional. Identifies the value name for the subkey. For string type, if the value-name parameter is left empty, the value of the subkey specified in the subkey parameter is set to a NULL string. Note that the value-name parameter can be expressed as a replaceable string. For example, you could use %Valname1% where the string to replace %Valname1% is defined in the Strings section of the INF file.
flag
Optional. Determines both the value type and whether the registry key is replaced if it already exists. The flag value is a bit map where:
Bit | Value | Meaning
0 | 0 | (Default) Value is an ANSI string.
0 | 1 | Value is a hexadecimal number.
1 | 0 | (Default) Replace key if it exists.
1 | 1 | Do not replace key if it exists.

value
Optional. Value to set. Can be either an ANSI string or a number in hexadecimal notation and Intel format. Any item containing a binary value can be extended beyond the 128-byte line maximum by using a backslash (\) character. A string key of the form %strkey% can also be given. The strkey must be defined in the Strings section of the INF file. To use a % character in the line, use %%.

At least two fields are required, however one can be null thus at least one comma is required when using this form.

The two items in the example AddReg-type section, which is named MOD1, add two value names to the registry, DevLoader and Miniport, if not already present. It also sets the value of these names to IOS and CX2590.MCD.

[MOD1]
HKR,,DevLoader,,IOS
HKR,,Miniport,,CX2590.MCD


Class Install Section

[ClassInstall]
AddReg=<Add-registry-section>[,<Add-registry-section>]...
Copyfiles=<file-list-section>[,<file-list-section>]...
Delfiles=<File-list section>[,<File-list-section>]...
DelReg=<Del-registry-section>[,<Del-registry-section>]...
Renfiles=<File-list-section>[,<File-list-section>]...
UpdateInis=<Update-ini-section>[,<Update-ini-section>]...
UpdateIniFields=<Update-inifields-Section>[,<Update-inifields-section>]...

Installs a new class for a device in the class section of the registry.

Not all the item types shown in the preceding syntax are needed or required. Typically a ClassInstall section will use AddReg-type items to add a class description and a class icon to the registry. These will be visible in the Windows 95 user interface.

In addition a class install section can specify a property provider and exert control over how the class is handled in the Windows 95 user interface.

Every device installed in Windows 95 has a class associated with it even if the class is UNKNOWN and every class has a class installer associated with it.

The installer processes the ClassInstall section if one of the devices defined in an INF file is about to be installed and the class is not built into Windows 95. Following is a list of the hardware class names that are built into Windows 95:

  • CD-ROM Controllers
  • Display Adapters
  • Floppy disk controllers
  • Hard disk controllers
  • Keyboard
  • Memory Technology Drivers (MTDs)
  • Modem
  • Mouse
  • Multifunction adapters
  • Network adapters
  • Other devices
  • PCMCIA sockets
  • Ports (COM & LPT)
  • Printer
  • SCSI Controllers
  • Sound, video and game controllers
  • System devices

The relative key is your class section. The Device Manager will create a class entry then you have a normal install section in here.

This example creates the class Sample and registers the description, installer, and icon for the class:

[ClassInstall]
Addreg=SampleClassReg
CopyFiles=@Sample.cpl

[SampleClassReg]
HKR,,,,%SampleClassDesc%
HKR,,Installer,,Sample.cpl
HKR,,Icon,HEX,00,00

[Strings]
SampleClassDesc=Sample

The following special controls over the class can be registered by adding one or more of the following items in the AddReg-type item referred to by the ClassInstall section:

HKR,,NoUseClass,,1        ;Class will not be seen anywhere
HKR,,NoInstallClass,,1    ;Class is not shown in New Device Wizard
HKR,,NoDisplayClass,,1    ;Class will not be displayed by Device Manager
HKR,,SilentInstall,,1    ;Class is installed without any user interaction


CopyFiles Sections

[<CopyFiles-section-name>]
<destination-file-name>[, <source-file-name>][, <temporary-file-name>][,<flag>]
[<destination-file-name>[, <source-file-name>][, <temporary-file-name>]][,<flag>]
   .
   .
   .

Lists the names of files to be copied from a source disk to a destination directory. The source disk and destination directory associated with each file are specified in other sections of the INF file. The file-list-section name must appear in the CopyFiles item of an Install section.

Note that you can specify the copying of a single file in the CopyFiles item of the Install section itself, without building a Copy Files section. To do this, use the special character @ to force a single file copy. An example of using the @ character in a CopyFiles-type item is in the Install section reference topic. Copying a single file in this way is somewhat limited because the source and destination filenames must be the same in this case and you cannot use a temporary file.

destination-file-name
Name of the destination file. If no source filename is given, this is also the name of the source file.
source-file-name
Name of the source file. If the source and destination filenames for the file copy operation are the same, this is not required.
temporary-file-name
Name of a temporary file for the file copy operation. The installer copies the source file but gives it the temporary file name. The next time the operating system starts, it renames the temporary file to the destination file name. This is useful for copying files to a destination which is currently open or in use by Windows.
flag
Optional parameter used to indicate a file that is critical to the installation process. For those files that the copy operation cannot be skipped during the installation process, set the flag parameter value to 2.

This example copies three files:

[CopyTheseFilesSec]
file11                     ; copies file11
file21, file22, file23     ; copies file22, temporarily naming it file23
file31, file32             ; copies file32 to file31

All the source filenames used in this example must be defined in a SourceDisksFiles section and the logical disk numbers that appear in the SourceDisksFiles section must have been defined in a SourceDisksNames section. As an alternative, you can use a LAYOUT.INF file to supply this information.


Delete Registry Sections

[<del-registry-section>]
<reg-root-string>, <subkey>, [<value-name>]
[<reg-root-string>, <subkey>, [<value-name>]]
    .
    .
     .

Deletes a subkey or value name from the registry. The del-registry-section name must appear in an DelReg item in an Install section.

reg-root-string
Registry root name. Can be one of these values:
HKCR | Same as HKEY_CLASSES_ROOT
HKCU | Same as HKEY_CURRENT_USER
HKLM | Same as HKEY_LOCAL_MACHINE
HKU | Same as HKEY_USERS.
HKR Means relative from the Key passed into GenInstallEx

HKR is always context sensitive to the install section the AddReg/DelReg/etc directives are processed from.

Specifically, HKR is relative to a context specific key, in context of any services installs, it's the service key.

In context of [DDInstall] it's the software key - same as SetupDiOpenDevRegKey(…DIREG_DRV…)

In context of [DDInstall.HW] it's the hardware key - same as SetupDiOpenDevRegKey(…DIREG_DEV…)

subkey
Identifies the subkey to delete. Has the form key1\key2\key3... This parameter can be expressed as a replaceable string. For example, you could use %Subkey1% where the string to replace %Subkey1% is defined in the Strings section of the INF file.
value-name
Optional. Identifies the value name for the subkey. Note that the value-name parameter can be expressed as a replaceable string. For example, you could use %Valname1% where the string to replace %Valname1% is defined in the Strings section of the INF file.

This type of section can contain any number of items. Each item deletes one subkey or value name from the registry.


DelFiles Sections

[<file-list-section>]
<file-name>[,,,<flag>]
    .
    .
    .

A DelFiles section lists the names of files to be deleted. The file-list-section name must appear in the Delfiles item of an Install section.

file-name
Identifies a file to be deleted.
flag
Optional parameter used to force Windows 95 to delete the file named in the item if it is in use during the installation process. Set the flag parameter value to 1 to cause Windows 95 to queue the file deletion operation until the system has restarted. If a file marked with the flag=1 parameter setting cannot be deleted because it is in use, a system restart will occur after the device installation is complete.

If you do not use the flag parameter value equal to 1 along with a file-name parameter, then if that file is in use when the DelFiles section is executed that file will not be deleted from the system.

This example deletes three files:

[DeleteOldFilesSec]
file1
file2
file3

All the filenames used in this example must be defined in a SourceDisksFiles section and the logical disk numbers that appear in the SourceDisksFiles section must have been defined in a SourceDisksFiles section.


DestinationDirs Section

[DestinationDirs]
<file-list-section>=<ldid>[, <subdir> ]
    .
    .
    .
[DefaultDestDir=<ldid>[, <subdir> ]]

The DestinationDirs section defines the destination directories for the operations specified in file-list sections, which are either CopyFiles, RenFiles, or DelFiles sections. Optionally, a default destination directory may be specified for any CopyFiles, RenFiles, or DelFiles sections in the INF file that are not explicitly named in the DestinationDirs section.

file-list-section
Name of a CopyFiles, RenFiles, or DelFiles section. This name must be referred to in a Copyfiles, RenFiles, or DelFiles item in an Install section.
ldid
A logical disk identifier (LDID). Can be one of these values:
00 | Null LDID. This LDID can be used to create a new LDID
01 | Source Drive:\pathname
02 | Temporary setup directory. This is valid only during setup
03 | Uninstall directory
04 | Backup directory
10 | Windows directory
11 | System directory
12 | IOSubsys directory
13 | Command directory
14 | Control Panel directory
15 | Printer directory
16 | Workgroup directory
17 | INF Directory
18 | Help directory
19 | Administration
20 | Fonts
21 | Viewers
22 | VMM32
23 | Color directory
25 | Shared directory
26 | Winboot
27 | Machine specific
28 | Host Winboot
30 | Root directory of the boot drive
31 | Root directory for Host drive of a virtual boot drive
33 | Old Windows directory if it exists
34 | Old Dos directory if it exists

subdir
Name of the directory, within the directory named by ldid, to be the destination directory.

The optional DefaultDestDir item provides a default destination for any CopyFiles items that use the direct copy (@filename) notation or any CopyFiles, RenFiles, or DelFiles sections not specified in the DestinationDirs section. If a DefaultDestDir is not used in a DestinationDirs section, then the default directory is set to LDID_WIN.

This example sets the destination directory for the MoveMiniPort section to WINDOWS\IOSUBSYS and sets the default directory for other sections to be the BIN directory on the boot drive:

[DestinationDirs]
MoveMiniPort=12         ; Destination for MoveMiniPort Section is
                        ; windows\iosubsys
DefaultDestDirs=30,bin  ; Direct copies go to Boot:\bin


Disk Names Section

For information about this type of section, see the SourceDisksNames Section and SourceDisksFiles Section topics.


HW Section

[InstallSection.HW]

The HW section is a special case of an Install section. It is the only type of section that enables entries to be made to the Hardware branch of the registry.

The only types of items that can appear in a HW section are AddReg and DelReg items. Using the HKR designation in the AddReg and DelReg items adds and deletes registry entries directly into the registry hardware branch. This is useful for multifunction devices.


Ini File to Registry Sections

[<ini-to-registry-section>]
<ini-file>, <ini-section>, [<ini-key>], <reg-root-string>, <subkey>[,<flags>]
    .
    .
    .

Moves lines or sections from an INI file to the registry, creating or replacing a registry entry under the given key in the registry. The section name ini-to-registry-section must appear in an Ini2Reg item in an Install section of the INF file.

ini-file
Name of the INI file containing the key to copy. For more information about specifying the INI filename, see the comments in the Reference topic about the Update Ini File Section.
ini-section
Name of the section in the INI file containing the key to copy.
ini-key
Name of the key in the INI file to copy to the registry. If ini-key is empty the whole section is transferred to the specified registry key.
reg-root-string
Registry root name. Can be one of these values:
HKCR | Same as HKEY_CLASSES_ROOT
HKCU | Same as HKEY_CURRENT_USER
HKLM | Same as HKEY_LOCAL_MACHINE
HKU | Same as HKEY_USERS.
HKR Means relative from the Key passed into GenInstallEx

HKR is always context sensitive to the install section the AddReg/DelReg/etc directives are processed from.

Specifically, HKR is relative to a context specific key, in context of any services installs, it's the service key.

In context of [DDInstall] it's the software key - same as SetupDiOpenDevRegKey(…DIREG_DRV…)

In context of [DDInstall.HW] it's the hardware key - same as SetupDiOpenDevRegKey(…DIREG_DEV…)

subkey
Identifies the subkey to receive the value. Has the form key1\key2\key3...
flags
Indicates whether to delete the INI key after transfer to the registry and whether to overwrite the value in the registry if the registry key already exists. Can be one of these values:
Bit | Value | Meaning
0 | 0 | (Default) Do not delete the INI entry from the INI file after moving the information in the entry to the registry.
0 | 1 | Delete the INI entry from the INI file after moving the information in the entry to the registry.
1 | 0 | (Default) If the registry subkey already exists, do not replace its current value.
1 | 1 | If the registry subkey already exists, replace its current value with the value from the INI file entry.

For example, suppose the following entry exists in the WIN.INI file:

[Windows]
CursorBlinkRate=15

If a CursorBlinkRate subkey does not exist under the Control Panel\Desktop, then the following item in an Ini File to Registry section creates the subkey, sets the value of the subkey to 15, and leaves the original line in WIN.INI unchanged:

win.ini,Windows,CursorBlinkRate,HKCU,"Control Panel\Desktop"

If the subkey already exists, the INF file item sets the value of the subkey to 15, and leaves the original line in WIN.INI unchanged.


Install Sections

[<install-section-name>]
LogConfig = <log-config-section-name>[, <log-config-section-name>]...
Copyfiles=<file-list-section>[,<file-list-section>]...
Renfiles=<file-list-section>[,<file-list-section>]...
Delfiles=<file-list-section>[,<file-list-section>]...
UpdateInis=<update-ini-section>[,<update-ini-section>]...
UpdateIniFields=<update-inifields-section>[,<update-inifields-section>]...
AddReg=<add-registry-section>[,<add-registry-section>]...
DelReg=<del-registry-section>[,<del-registry-section>]...
Ini2Reg=<ini-to-registry-section>[,<ini-to-registry-section>]...
UpdateCfgSys=<update-config-section>
UpdateAutoBat=<update-autoexec-section>
Reboot | Restart

Identifies the additional sections in the INF file that contain descriptions of the device and instructions for installing files and information needed by the device driver(s). The name of the section, install-section-name, must be defined in a Device section that is associated with a Manufacturer section.

Not all the types of items shown in the preceding syntax are needed or required in an Install section. If an item type is used, it must specify the name of a section in the INF file. (An exception to this is the CopyFiles item, which may use the @ character along with a filename to copy a single file without specifying a section name.) The section name must consist of printable characters.

Only one of each type of item can be used in any one Install section. More than one section name can be listed in an item, but each additional name must be preceded with a comma.

The Reboot or Restart items can be added to an Install section to force the system to either restart or to reboot the machine after carrying out the Install section script.

This example shows a typical Install section. It contains a LogConfig item that identifies two logical configuration sections for this device. It also contains Copyfiles and AddReg items that identify the sections containing information about which files to install.

[SuperSCSI]
; SCSI Are Us Model 01 - SuperSCSI+
Log_Config = With_Dma, WithoutDMA
Copyfiles=MoveMiniPort, @SRSutil.exe
AddReg=MOD1

The CopyFiles item provides a special notation which will allow a single file to be copied directly from the copy line. An individual file can be copied by prefixing the file name with an @ symbol. The destination for any file copied using this notation will be the DefaultDestDir as defined in the DestinationDirs section. The following example shows how to copy individual files:

CopyFiles=FileSection1,@myfile.txt,@anotherfile.txt,LastSectionName


Log Config Sections

[<log-config-section-name>]
ConfigPriority = <priority-value>
[DMAConfig = <dma-list>]
[IOConfig = <io-range-list>]
[IRQConfig = <irq-list>]
[MemConfig = <mem-range-list>]

A Log Config section defines device configuration details, such as interrupt request lines, memory ranges, I/O ports, and DMA channels. The name of the section, log-config-section-name, must be used in the LogConfig item in an Install section of the INF file.

Not all types of items shown in the preceding syntax are needed or required in a Log Config section. The syntax and meaning of each of the item types that can be used in a Log Config section are given later in this topic.

Each item can specify more than one resource. However, during installation one and only one resource from an item is used. If a device needs multiple resources of the same type, multiple items of that type must be used in the Log Config section. For example, to ensure two IRQs for a device, two IRQConfig items must be used in the Log Config section. If a device does not require an IRQ, no IRQConfig item should be used.

An INF file can contain any number of Log Config sections, as many as are needed to describe the device dependencies. However, each section must contain complete details for installing one device. More than one Log Config section can be specified for device. If this is done, only one of the Log Config sections will be used during installation.

For each Log Config section item, the installer builds binary logical configuration records and adds these to the driver section of the registry.

The syntax of each of the following types of Log Config section items is shown in subsequent sections.

ConfigPriority Item
DMAConfig Item
IOConfig Item
IRQConfig Item
MemConfig Item


ConfigPriority Item

ConfigPriority = <Priority_Value>

Sets the priority value for the logical configuration. Only one ConfigPriority item can be used in a LogConfig section.

Priority_Value
Can be one of these values:
Value | Meaning
HARDWIRED | Cannot be reset in any way
DESIRED | Soft Configurable most optimal
NORMAL | Soft Configured medium optimal
SUBOPTIMAL | Soft Configured least optimal
DISABLED | Hardware disabled
RESTART | Requires Windows restart to affect
REBOOT | Requires system reboot to affect
POWEROFF | Requires power cycle to affect
HARDRECONFIG | Requires Jumper setting


DMAConfig Item

DMAConfig = [<DMAattrs>:]<DMANum>[,<DMANum>]

Sets the DMA channel numbers for the logical configuration.

DMAattrs
Optional. Can be the letter D for 32-bit channels or W for 16-bit channels. These are specific to the appropriate bus. If no value is given, the default is 8-bit channels.
DMANum
DMA channel number in decimal notation.


IOConfig Item

IOConfig = <io-range>[,<io-range>]...

Sets the IO range(s) for the logical configuration. More than one io-range can be given, but each additional value but be preceded with a comma.

Note EISA adapters which use their slot-specific ports do not need to include those ports in their logical configuration.

io-range
This value has two forms, called Type 1 I/O Range and Type 2 I/O Range.

Type 1 I/O Range Value

<start>-<end>[([<decode-mask>]:[<alias-offset>]:[<attr>])]
start | Starting address of the IO port region. This is a 16-bit value in hexadecimal notation.
end | Ending address of the IO port region. This is a 16-bit value in hexadecimal notation. The start and end values must be separated with a hyphen.
decode-mask | Optional. Bit mask to indicate number of bits of IO address the device decodes. This is a 16-bit value in hexadecimal notation which is the most-significant byte of the actual decode mask. The most-likely values for this field are either 3FF (for 10-bit decode) or FFFF (for 16 bit decode.)
alias-offset | Optional. Value to indicate additional ports decoded by the adapter. The additional ports are calculated by adding multiples of this offset to the base IO port region. Leaving this field blank indicates that driver software will only access the ports in the base IO region and never access any of the aliases.
attr | Optional. Reserved; do not use.

Type 2 I/O Range Value

<size>@<min>-<max>[%<align-mask>][([<decode-mask>]:[<alias-offset>]:[<attr>])]
size | Size of the required IO port region in bytes. This is a 16-bit value in hexadecimal notation. The start and end values must be separated with a hyphen.
min | Smallest possible starting IO port. This is a 16-bit value in hexadecimal notation.
max | Largest possible ending IO port. This is a 16-bit value in hexadecimal notation. The min and max values must be separated with a hyphen.
align-mask | Optional. This 16-bit hexadecimal mask is applied to range specified by min and max to determine legal starting addresses for the IO region. To construct the mask, all bits which must be zero in the starting address must be zero in the mask. All other bits should be 1.
decode-mask | Optional. Bit mask to indicate number of bits of IO address the device decodes. This is a 16-bit value in hexadecimal notation which is the most-significant byte of the actual decode mask. The most-likely values for this field are either 3FF (for 10-bit decode) or FFFF (for 16 bit decode.)
alias-offset | Optional. Value to indicate additional ports decoded by the adapter. The additional ports are calculated by adding multiples of this offset to the base IO port region. Leaving this field blank indicates that driver software will only access the ports in the base IO region and never access any of the aliases.
attr | Optional. Reserved; do not use.

Note In order to avoid conflicts with older cards, all adapters in ISA slots which use IO ports must allocate ports which fall in the 100-3FF range, even if they only use the 10-bit aliases of those ports. Adapters in PCI slots which use the 10 bit aliases of ports in the 100-3FF range do not need to allocate the ports in the 100-3FF range because those addresses will not appear on the ISA bus.

The following examples illustrates the use of a list of three Type 1 I/O range values in an IOConfig item. This specifies an IO port region of 8 bytes which can start at 1F8, 2F8, or 3F8. Additionally, the device decodes 10 bits of its address and does not use any of its aliases.

IOConfig=1F8-1FF(3FF::), 2F8-2FF(3FF::), 3F8-3FF(3FF::)

The following example shows the use of a Type 2 I/O range value in an IOConfig item. This specifies an IO port region of 8 bytes which can start at 300, 308, 310, 318, 320, or 328. The device decodes 10 bits of its address and does not use any of its aliases.

IOConfig=8@300-32F%FF8(3FF::)

The following example shows the use of a Type 1 I/O range value in an IOConfig item. This specifies 16 IO port regions of 1 byte each, where each region starts at x2E8 where x is 0-Fh.

IOConfig=2E8-2E8(FFFF:4:)


IRQConfig Item

<k>IRQConfig = </k>[<e>IRQattrs</e><k>:</k>]<e>IRQNum</e>[<k>,</k><e>IRQNum</e>]

Sets the interrupt request (IRQ) numbers for the logical configuration.

IRQattrs
Optional. Can be the letter S to indicate a sharable interrupt. If no value is given, the default is a nonshareable interrupt. If used, this flag only appears once in an IRQConfig item and affects all IRQs listed in that item.
IRQNum
IRQ number in decimal notation. More than one IRQ number can be used in a IRQConfig item, but each must be preceded with a comma.


MemConfig Item

MemConfig = <mem-range>[,<mem-range>]...

Sets the memory range(s) for the logical configuration. More than one mem-range can be given, but each additional value but be preceded with a comma.

mem-range
This value has two forms:
<start>-<end>[(<attr>)]

<size>@<min>-<max>[%<align-mask>][(<attr>)]
start | Starting address of the physical memory region. This is a 32-bit value in hexadecimal notation. The start and end values must be separated with a hyphen.
end | Ending address of the physical memory region. This is a 32-bit value in hexadecimal notation.
size | Size of the required region in bytes. This is a 32-bit value in hexadecimal notation.
min | Smallest possible starting address of the memory region. The min and max values must be separated with a hyphen.
max | Largest possible ending address of the memory region.
alignMask | Optional. A 32-bit hexadecimal mask applied to range specified by min and max to determine legal starting addresses for the memory region. To construct the mask, all bits which must be zero in the starting address must be zero in the mask. All other bits should be 1.
attr | Optional. Reserved; do not use.

The following examples illustrate the MemConfig item.

MemConfig = C0000-C7FFF, D0000-D7FFF

This specifies a memory region of 32K bytes which can start at either C000:0000 or D000:0000.

MemConfig = 8000@C0000-D7FFF%F0000

This specifies exactly the same region (32K range starting on 64K boundaries only).

See Also

sec_infinstall


Manufacturer

[Manufacturer]
<manufacturer-name> | %<strings-key>%=<device-section-name>

The Manufacturer section identifies a manufacturer of a device that can be installed using the INF file and names a Device section that describes that device.

manufacturer-name
Name of the device manufacturer. This name can be any combination of printable characters, but must uniquely identify the manufacturer and must be enclosed in double quotation marks.
strings-key
Name of a string defined in the Strings section of the INF file.
device-section-name
Name of the Device section. This name can be any combination of printable characters, but must uniquely identify another section in the INF file. The Device section:
  • Specifies a device description string for a device (device description strings may be displayed at the user interface by the New Device Wizard and/or by the Device manager).
  • Specifies the name of the Install section for each of the devices (the Install section for a device gives the primary script for installing the device).
  • Specifies the device ID (also called the hardware ID) of the device and, optionally, a list of compatible device IDs for the device.

The device ID specified in the Device section may be used in a ControlFlags section to modify the way the New Device Wizard and/or the Device Manager use the device description. The syntax and meaning of items that can be in a Device section and in a ControlFlags section are described later in this topic.

The syntax of a Device section is:

[<device-section>]
<device-description>=<install-section-name,device-id>[,<compatible-device-id>]...
[<device-description>=<install-section-name,device-id>[,<compatible-device-id>]...]

Each Device section item gives the device description, identifies the install-type section, and specifies the device ID for a device. Optionally, a Device section item may specify one or more device IDs of compatible devices.

There may be one or more items in the Device section, depending upon how many devices the INF file installs for a manufacturer.

device-description | Description of a device to install. This can be any combination of printable characters or a strings key.
install-section-name | Name of the Install section for this device.
device-id | Identifier for this device.
compatible-device-id | Identifier of a compatible device. More than one compatible-device identifier can be given, but each must be preceded with a comma.

This example shows a typical Device section containing one item. The name of the Install section for this device is SuperSCSI. The device-id is *PNPA000 and it is compatible with devices identified as *PnPA001.

[SCRUS]
%DevDesc1%  = SuperSCSI, *PNPA000, *PnPA001

For each driver installed using this INF file, the Device Manager and the New Device Wizard will use the information in the Manufacturer and Device sections to generate Driver Description, Manufacturer Name, DeviceID, and Compatibility List entries in the registry.

The device ID specified in the Device section may be used in a ControlFlags section to modify the way the New Device Wizard and/or the Device Manager use the device description. The syntax of the items that can be contained in a ControlFlags section is shown in the following:

[ControlFlags]
CopyfilesOnly=<Device-id>[,<device-id>]...
ExcludeFromSelect=<Device-id>[,<device-id>]...

The ControlFlags section provides a way to control how a device is handled both during installation and by the Device Manager. The Windows 95 New Device Wizard builds its list of installable devices by searching through INF files. The Device Manager also displays information about devices which originates in INF files.

CopyFilesOnly | Listing a device-id in a CopyFilesOnly item will allow the user to choose the device in the New Device Wizard but will stop the Wizard from actually doing the installation. When the user chooses the device from the Wizard will only copy files to the destination directory. Typically, devices which are enumerated should be listed in a CopyFilesOnly item.
ExcludeFromSelect | Listing the device-id of a device in an ExcludeFromSelect item will remove the device completely from the New Device Wizard. Optionally, an asterisk (*) can be specified in place of the id list. Doing this will set ExcludeFromSelect for all devices listed in this INF file.


NoResDup Section

[InstallSection.Noresdup]
<Device-id>[,<device-id>]...

The NoResDup section is similar to the NoPosDup section except it works for devices which use no resources. When the Device Manager installs a device, it always looks for a NoResDup section. If the section is found the Device Manager will search the \enum\root branch of the registry for devices whose Device-ID matches any Device-ID in the NoResDup Device-ID list. If a match is found, the Device Manager will assume it has found a duplicate entry and will move the \enum\root entry to the enumerator branch and remove the root node. Listing an ID in this section can have unintended side affects as there is no way to tell the difference between a duplicate and a second instance of the device.


PosDup Section

[Device-id.posdup]
<Device-id>[,<device-id>]...

The Posdup section provides a method for identifying devices which can may appear to be separate devices but in fact are the same device. This can occur when a device is detected and is also enumerated. Typically, detection cannot identify the device exactly but enumeration can. In these cases the Device Manager will detect a conflict. The Device Manager will look at this list and search the root branch of the registry for devices listed in this section. If one is found and the resource in use by these devices overlap, the device manager will assume it has detected a duplicate and will move the root branch entry to the enumerator branch.


Rename Files Sections

[<rename-files-section-name>]
<new-file-name>, <old-file-name>
    .
    .
    .

Lists the names of files to be renamed. The name of the section must appear in a Renfiles item in an Install section of the INF file.

new-file-name
New name of the file.
old-file-name
Old name of the file.

This example renames the files file42 to file41, file52 to file51, and file62 to file61:

[RenameOldFilesSec]
file41, file42
file51, file52
file61, file62

All the old filenames used in this example (file42, file52, and file62) must be defined in a SourceDisksFiles section and the logical disk numbers that appear in the SourceDisksFiles section must have been defined in a SourceDisksNames section.


SourceDisksFiles Section

[SourceDisksFiles]
<filename>=<disk-number>[,<subdir>]
    .
    .
    .

Names the source files used during installation and identifies the source disks that contain the files.

filename
Name of the file on the source disk.
disk-number
Ordinal of the source disk that contains the file. This ordinal must be defined in the SourceDisksNames section, and must have a value greater than or equal to 1 (zero is not a valid disk-number parameter value).
subdir
Optional parameter that specifies the subdirectory on the source disk where the file resides. If this parameter is not used, the source disk root directory is the default.

This example SourceDisksFiles section identifies a single source file, SRS01.386, on the disk having ordinal 1:

[SourceDisksFiles]
SRS01.386 = 1


SourceDisksNames Section

[SourceDisksNames]
<disk-ordinal>="<disk-description>",<disk-label>,<disk-serial-number>
    .
    .
    .

Identifies and names the disk(s) that contain the source files for file copying and renaming operations.

disk-ordinal
A unique number that identifies a source disk. If there is more tan one source disk, each must have a unique ordinal.
disk-description
A string or a strings key describing the contents or purpose of the disk. The installer displays this string to the user to identify the disk. The description is enclosed in double quotation marks.
disk-label
Volume label of the source disk that is set when the source disk is formatted.
disk-serial-number
Serial number for the source disk that is set when the source disk is formatted. The default value is 0000-0000.

This example identifies one source disk and assigns it ordinal 1. The disk description is given as a strings key:

[SourceDisksNames]
0 = %ID1%, Instd1, 0000-0000

[Strings]
ID1=CX2590 SCSI Adapter Installation Disk 1


Strings Section

[Strings]
strings-key=value
    .
    .
    .

Defines one or more strings keys. A strings key is a name that represents a string of printable characters. Although the Strings section is generally the last section in the INF files, a string key defined in this section may be used anywhere in the INF file that the corresponding string would be used. The Installer expands the string key to the given string and uses it for further processing. Using a strings key requires that it be enclosed in percent signs (%).

strings-key
A unique name consisting of letters and digits.
value
A string consisting of letters, digits, or other printable characters. It should be enclosed in double-quotation marks if the corresponding strings key is used in a type of item that requires double quotation marks.

The Strings section makes translation of strings for international markets easier by placing all strings that can be displayed at the user interface when the INF file is used in a single section of the INF file. Strings keys should be used whenever possible.

The following example shows the strings section for a sample INF file.

[Strings]
String0="Corporation X"
String1="Corporation X"
String2="CX2590 SCSI Adapter"


Update Autoexec.bat Sections

[<update-autoexec-section>]
CmdAdd=<command-name>[,<command-parameters>]
CmdDelete=<command-name>
PrefixPath=<ldid>[,<ldid>]
RemOldPath=<ldid>[,<ldid>]
TmpDir=<ldid>[,<subdir>]
UnSet=<env-var-name>

Provides commands to manipulate lines in the AUTOEXEC.BAT file. The section name, update-autoexec-section-name, must appear in the UpdateAutoBat item in an Install section of the INF file.

Not all item types shown in the preceding syntax are needed or required in an Update Autoexec.bat section. The section can contain as many CmdAdd, CmdDelete and UnSet items as needed, but only one PrefixPath, RemOldPath and TmpDir items can be used in an INF file. The syntax and meaning of each of the item types is described in subsequent sections.

The installer processes all CmdDelete items before any CmdAdd items.


CmdAdd Item

CmdAdd=<command-name>[<,"command-parameters">]

Adds the given command and optional command parameters to the AUTOEXEC.BAT file, at the end of the file.

command-name
Name of an executable file, with or without an extension. If the filename is also defined in the SourceDisksFiles and DestinationDirs sections of the INF file, the installer adds the appropriate path to the filename before writing it to the AUTOEXEC.BAT file.
command-parameters
A string enclosed in double quotation marks or a replaceable string like %String1% or %Myparam%, where the strings that replace %String1% and %Myparam% are defined in the Strings section of the INF file. The installer appends the string to the command-name before appending the line to the end of the AUTOEXEC.BAT file. The format of this line is dependent on the command line requirements of the given executable file.


CmdDelete Item

CmdDelete=<command-name>

Deletes any lines from AUTOEXEC.BAT that include the given command name. The installer searches for and deletes any occurrence of the given name that has a filename extension of .EXE, .COM, and .BAT.

command-name
Name of an executable file without an extension.


PrefixPath Item

PrefixPath=<ldid>[,<ldid>]...

Appends the path associated with the given LDID to the path command.

ldid
Can be any of the predefined LDID values or a new value defined in the INF. For a definition of all the predefined LDID values, see the Reference topic about the DestinationDirs section.


RemOldPath Item

RemOldPath=<ldid>[,<ldid>]

Removes the path associated with the given LDID from the path command.

ldid
Can be any of the predefined LDID values or a new value defined in the INF. For a definition of all the predefined LDID values, see the Reference topic about the DestinationDirs section.

For example, if the user installs the new version of Windows into c:\newwin and has an old copy of Windows in c:\windows, the following INF file item removes c:\windows from the path environmental variable:

RemOldPath=10


TmpDir Item

TmpDir=<ldid>[,<subdir>]

Creates a temporary directory within the directory given by the LDID, if it does not already exist.

ldid
Can be any of the predefined LDID values or a new value defined in the INF. For a definition of all the predefined LDID values, see the Reference topic about the DestinationDirs section.
subdir
A path name. If ldid\subdir does not already exist, it is created.


UnSet Item

UnSet=<env-var-name>

Removes any set command from the AUTOEXEC.BAT file that includes the given environment variable name.

env-var-name
Name of an environment variable.


Update Config.sys Sections

[<update-config-section>]
Buffers=<legal-dos-buffer-value>
DelKey=<key>
DevAddDev=<driver-name>,<configkeyword>[,<flag>][,<param-string>]
DevDelete=<device-driver-name>
DevRename=<current-dev-name>,<new-dev-name>
Files=<legal-dos-files-value>
PrefixPath=<ldid>[,<ldid>]
RemKey=<key>
Stacks=<dos-stacks-values>

Provides commands to add, delete, or rename commands in the CONFIG.SYS file. The section name, update-config-section-name, must appear in the UpdateConfigSys item in an Install section of the INF file.

Not all item types shown in the preceding syntax are needed or required. An Update Config.sys section may contain as many DevRename, DevDelete, DevAddDev, DelKey, and RemKey items as needed, but the Buffers, Files, and Stacks items may only be used once in a section. When processing an Update Config.sys section, the Installer processes all DevRenames items first, all DevDelete items second, and all DevAddDev items last. The syntax and meaning of each of the types of items that can be used in an Update Config.sys section are given in subsequent sections.


Buffers Item

Buffers=<legal-dos-buffer-value>

Sets the number of file buffers. As it does with the Stacks item, the Installer compares the existing value with the proposed value and always sets the file buffers to the larger of the two values.

legal-dos-buffers-value
A legal MS-DOS buffers value.


DelKey Item

DelKey=<key>

Causes the CONFIG.SYS command with the specified key to be remarked out in the CONFIG.SYS file.

key
The key of the CONFIG.SYS command to be remarked out.

For example, the INF file item

DelKey=Break

would cause a Break=on command to be remarked out in the CONFIG.SYS file.

The DelKey item has the same effect as the RemKey item. There can be multiple DelKey and/or RemKey items in a section of the INF file.


DevAddDev Item

DevAddDev=<driver-name>,<configkeyword>[,<flag>][,<param-string>]

Adds a device or install command to the CONFIG.SYS file.

driver-name
Name of the driver or executable file to add. The installer validates the filename extension, ensuring that it is .SYS or .EXE.
configkeyword
Command name. Can be device or install.
flag
Optional placement flag. If zero, the command is placed at the bottom of the file. If 1, it is placed at the top. If flag is not given, zero is used by default.
param-string
Optional command parameters. Must be valid for the given device driver or executable file.


DevDelete Item

DevDelete=<device-driver-name>

Deletes any line containing the specified filename from the CONFIG.SYS file.

device-driver-name
Name of a file or device driver. The Installer searches the CONFIG.SYS file for the name and deletes any line containing it. Because MS-DOS does not permit implicit filename extensions in CONFIG.SYS, each device-driver-name must explicitly specify the filename extension.

This example DevDelete item in an Update Config.sys section deletes lines 1 and 3 but not line 2 of the example CONFIG.SYS file:

DevDelete=Foo.sys

;; lines in CONFIG.SYS
Device=Foo.sys               ;; line #1
Install=foo.exe              ;; line #2
Device=Foo.sys /d:b800 /I:3  ;; line #3


DevRename Item

DevRename=<current-dev-name>,<new-dev-name>

Renames a device driver in the CONFIG.SYS file.

current-dev-name
Name of the device driver or executable file to rename. The installer looks for the name on the right side of a device or install command in the CONFIG.SYS.
new-dev-name
New name for driver or executable file.


Files Item

Files=<legal-dos-files-value>

Sets the maximum number of open files in the CONFIG.SYS file. As it does with the Stacks item, the Installer compares the existing value with the proposed value and always sets the maximum number of open files to the larger of the two values.

legal-dos-files-value
A legal MS-DOS files value.


RemKey Item

RemKey=<key>

Causes the CONFIG.SYS command with the specified key to be remarked out in the CONFIG.SYS file.

key
The key of the CONFIG.SYS command to be remarked out.

For example, the INF file item

RemKey=Break

would cause a Break=on command to be remarked out in the CONFIG.SYS file.

The RemKey item has the same effect as the DelKey item. There can be multiple RemKey and/or DelKey items in a section of the INF file.


Stacks Item

Stacks=<dos-stacks-values>

Sets the number and size of stacks in the CONFIG.SYS file. The Installer compares the existing value with the proposed value and always sets the stacks to the larger of the two values. For example, if CONFIG.SYS contains stacks=9,218 and an INF contains stacks=5,256, the installer sets to new value to stacks=9,256.

legal-dos-stacks-value
A legal MS-DOS stacks value.


Update INI Fields Sections

[<update-inifields-section-name>]
<ini-file>, <ini-section>, <profile-name>, [<old-field>], [<new-field>],[<flags>]
    .
    .
    .

Replaces, adds, and deletes fields in the value of a given INI entry. Unlike the Update INI File section type, this type of section replaces, adds, or deletes portions of a value in an INI file entry rather than the whole value. The section name, update-inifields-section-name, must appear in the UpdateIniFields item in an Install section of the INF file.

ini-file
Name of the INI file containing the entry to change. For more information about specifying the INI filename, see the topic that describes the Update INI File section type.
ini-section
Name of the INI file section containing the entry to change.
profile-name
Name of the entry to change.
old-field
Field value to delete.
new-field
Field value to add, if not already there.
flags
Specifies whether to treat the old-field and new-field parameters as if they have a wild card character or not and/or what separator character to use when appending a new field to an INI file entry. Can be any of these values:
Bit | Value | Meaning
0 | 0 | (Default) Treat "*" character literally when matching fields, and not as a wild card character.
0 | 1 | Treat "*" character as a wild card character when matching fields.
1 | 0 | (Default) Use blank (" ") as a separator when adding a new field to an entry.
1 | 1 | Use comma (",") as a separator when adding a new field to an entry.

Any comments in the INI file line are removed as they might not be applicable after changes. When looking for fields in the line in the INI file, spaces, tabs and commas are used as field delimiters. However, a space is used as the separator when the new field is appended to the line.

See also ,


Update INI File Sections

[<update-ini-section-name>]
<ini-file>, <ini-section>, [<old-ini-entry>], [<new-ini-entry>], [<flags>]
    .
    .
    .

Replaces, deletes, or adds complete entries in the given INI file. The section name, update-ini-section-name, must appear in the UpdateInis item in an Install section of the INF file.

ini-file
Name of the INI file containing the entry to change. For more information about specifying the INI filename, see the following comments.
ini-section
Name of the section containing the entry to change.
old-ini-entry
Optional. Usually in the form Key=Value.
new-ini-entry
Optional. Usually in the form Key=Value. Either the key or value may specify replaceable strings. For example, either the key or value specified in the new-ini-entry parameter may be %String1%, where the string that replaces %String1% is defined in the Strings section of the INF file.
flags
Optional action flags. Can be one of these values:
0 Default. If old-ini-entry key is present in an INI file entry, that entry is replaced with new-ini-entry. Note that only the keys of the old-ini-entry parameter and the INF file entry must match, the value of each entry is ignored.

To add new-ini-entry to the INI file unconditionally, set old-ini-entry to NULL. To delete old-ini-entry from the INI file unconditionally, set new-ini-entry to NULL.

1 | If both key and value of old-ini-entry exist in an INI file entry, that entry is replaced with new-ini-entry. Note that the old-ini-entry parameter and the INF file entry must match on both key and value for the replacement to be made (this is in contrast to using an action flag value of zero, where only the keys must match for the replacement to be made).
2 If the key in the old-ini-entry parameter does not exist in the INI file, then no operation is performed on the INI file.

If the key in the old-ini-entry parameter exists in an INI file entry and the key in the new-ini-entry parameter exists in an INI file entry, then the INI file entry that matches the key in the new-ini-entry parameter is deleted and the INI file entry that matches the old-ini-entry parameter is operated on in the following way: the key of the INI file entry is replaced with the key in the new-ini-entry parameter.

If the key in the old-ini-entry parameter exists in an INI file entry and the key in the new-ini-entry parameter does not exist in an INI file entry, then an entry is added to the INI file made up of the key in the new-ini-entry parameter and the old value.

Note that the match of the old-ini-entry parameter and an INI file entry is based on key alone, not key and value.

3 | Same as flag parameter value of 2 described previously, except match of the old-ini-entry parameter and an entry in the INF file is based on matching both key and value, not just the key.

The wild card character (*) can be used in specifying the key and value and they will be interpreted correctly.

The ini-file name can be a string or a strings key. A strings key has the form %strkey% where strkey is defined in the Strings section in the INF file. In either case, the name must be a valid filename.

The name should include the name of the directory containing the file, but the directory name should be given as a logical directory identifier (LDID) rather than an actual name. The installer replaces an LDID with an actual name during installation.

An LDID has the form %ldid% where ldid is one of the predefined identifiers or an identifier defined in the DestinationDirs section. Note that when the constants LDID_BOOT and LDID_BOOTHOST are replaced, the backslash is included in the path. For example LDID_BOOT may be replaced with C:\. However, in your INF file you can either use the backslash character or not. For example, either %30%boot.ini and %30%\boot.ini can be used to reference BOOT.INI in the root of the boot drive.

The following examples illustrate individual items in an Update INI File section of an INF file:

%11%\sample.ini, Section1,, Value1=2           ; adds new entry
%11%\sample.ini, Section2, Value3=*,           ; deletes old entry
%11%\sample.ini, Section4, Value5=1, Value5=4  ; replaces old entry

The following set of items in an Update INI File-type section of an INF file work together to operate on the Boot section of SYSTEM.INI. The conditionality built into the flags parameter of the INF file items is used to add the entry "comm.drv=comm.drv" to the Boot section unless the entries "comm.drv=*vcoscomm.drv" or "comm.drv=*r0dmdcom.drv" exist in the Boot section, in which case the existing entry is preserved and the entry "comm.drv=comm.drv" is not added to the INI file. In other words, after the four INF file entries shown in the following are executed, there will be one "comm.drv=" entry in the Boot section of the INI file: "comm.drv=*vcoscomm.drv" or "comm.drv=*r0dmdcom.drv" or "comm.drv=comm.drv."

system.ini, boot, "comm.drv=*vcoscomm.drv","~CommDrvTemp~=*", 3
system.ini, boot, "comm.drv=*r0dmdcom.drv","~CommDrvTemp~=*", 3
system.ini, boot,,"comm.drv=comm.drv"
system.ini, boot, "~CommDrvTemp~=*","comm.drv=*", 3

See also , , ,


Version Section

[Version]
Signature="$Chicago$"
Class=<class-name>
Provider=<INF-Creator>
LayoutFile=<filename.inf>

Defines the standard header for all Windows 95 INF files. Note that if the signature is not $Chicago$ then Windows 95 will not accept the INF file as an INF file for any of the classes of devices recognized by Windows 95. For a list of all the device classes recognized by Windows 95, see the topic Introducing the INF Editor.

Note the signature string recognition is case-insensitive. So, for example, you can use either $Chicago$ or $CHICAGO$.

class-name
Defines the class in the registry for any device installed from this INF.
INF-creator
Identifies the creator of the INF file. Typically this is the name of the organization that creates the INF file.
filename.inf
Names the INF file that contains the layout information (source disks and files) required fro installing this driver software. This line is optional. If not given, the SourceDisksNames and SourceDisksFiles sections must be given in this INF.

This example shows a typical Version section:

[Version]
Signature="$CHICAGO$"
Class=SCSIAdapter
Provider=%String0%

[Strings]
String0="Corporation X"

See also , ,


Display INF File Extensions

The installation disk for your Windows® 95 display driver must contain:

  • •A Windows® 95 format INF text file
  • •All DRV and VxD files copied and used by the INF

Display INF files use the standard format defined for all device types in Windows 95. For general information about the INF format and syntax, see Using the Device Information (INF) File Editor. This section documents entries specific to display driver INF files.


Sample Display INF File

Following is a sample documented display INF file which describes the contents of a display INF file. This corresponds to SAMPLE.INF in the display driver samples directory, which you should use as a starting point for your Windows 95 INF file.

; INF file for Sample Win95 display driver
; Copyright 1995, Sample Company Name, Inc.

The header should contain semicolon comments identifying the driver name, manufacturer, copyright, etc.

[version]
Class=DISPLAY
signature="$CHICAGO$"
Provider=%Mfg%

The [version] section should be as described in the preceding.

[DestinationDirs]
DefaultDestDir  = 11    ; LDID_SYS
Driver.Copy = 11

The [DestinationDirs] section associates file copy sections in the INF with destination directories on the hard disk. The number 11 is used for the subdirectory WINDOWS \SYSTEM, where most display driver files are copied to.

[SourceDisksNames]
1="Windows 95 Sample Driver Disk",,0

The [SourceDisksNames] section provides a description of the installation disk(s) used to install the display driver files, one line per disk. Each line should have a unique disk ID value on the left hand side. Usually, display driver disks will have only one line. Change the description string so that it matches the label on your driver installation disk.

[SourceDisksFiles]
sample.drv=1
sample.vxd=1

The [SourceDisksFiles] section associates driver files copied by the INF file with disk ID values defined in [SourceDisksNames].

[Manufacturer]
%Mfg%=Mfg

The [Manufacturer] section contains one line per manufacturer name (usually only one). The left hand side is a string identifier contained in the [Strings] section. The right hand side is the name of a section listing drivers for the manufacturer.

[Mfg]
%Sample1.DeviceDesc%=Driver.Install, Display_Sample1
%PCI\VEN_9999&DEV_9999.DeviceDesc%=Driver.Install, PCI\VEN_9999&DEV_9999

[Mfg] is an example of a driver section. Driver sections contain one line per unique device/driver combination. This example list two device types. The left hand side references string identifiers contained in the [Strings] section. The right hand side specifies the name of an install section, followed by corresponding device ID's.

The first line in this example is for a non-Plug and Play device (for example, ISA or VLB adapter) which does not have a Plug and Play device ID. "Display_Sample1" is a dummy ID that is used in place of a real device ID. Dummy Ids are required for non-Plug and Play devices, so that the driver will be preserved if the user runs Windows Setup again in the future. Do not use "Display_Sample1", rather invent a dummy ID unique to your company and the driver, for example, "Display_ACME-123VLB".

The second line is for a PCI display adapter, with device ID "PCI\VEN_0000&DEV9999".

Note that both devices use the same install section, Driver.Install (in the following).

[Driver.Install]
CopyFiles=Driver.Copy
DelReg=Prev.DelReg
AddReg=Driver.AddReg

[Driver.Install] is an example install section. Install sections contain lines which tell the Windows device installer how to install the driver, that is, what files to copy, which registry keys to add or delete, which INI files to modify, etc.

The CopyFiles line points to one or more sections that contain files that need to be copied from the driver installation disk.

The DelReg line points to one or more sections that contain registry keys that need to be deleted.

The AddReg line points to one or more sections that contain registry keys that need to be added.

Install sections can also contain UpdateInis and UpdateIniFields sections, but these are usually not used for Windows 95 display drivers.

[Driver.Copy]
sample.drv
sample.vxd

[Driver.Copy] is an example file copy section. File copy sections contain one line for each driver file to be copied from the driver disk to the hard disk. The destination of the files (for example, the WINDOWS \SYSTEM subdirectory) is specified for the section in the [DestinationDirs] section.

[Prev.DelReg]
HKR,,Ver
HKR,,DevLoader
HKR,DEFAULT
HKR,MODES
HKR,CURRENT

[Prev.DelReg] should be include as is in all display driver INF files. It deletes old keys and values already present in the registry if the user is changing from an old driver to a new one using this INF.

[Driver.AddReg]
HKR,,Ver,,4.0

[Driver.AddReg] is an example of an AddReg section for a display driver. It writes registry values used by Windows to load and configure your driver.

HKR is always the registry root value for display AddReg lines. (See the general INF documentation for an explanation of what HKR means.)

Ver should be 4.0 for Windows 95 compatible display drivers. For Windows 3.x compatible drivers, it should be 3.x.

HKR,,DevLoader,,*vdd

*VDD is always the Plug and Play dev loader for Windows 95 display drivers, so this line is required. If your driver does not use the main Windows 95 VDD (for example, if it is a Windows 3.1 version driver), then change *vdd to *configmg.

HKR,DEFAULT,Mode,,"8,640,480"

DEFAULT is a subkey of the display driver software key. It contains the following values, described in the following: drv, vdd, minivdd, cardvdd, RefreshRate, DDC, and ExtModeSwitch.

The Mode value of the DEFAULT subkey specifies the default video mode that Windows Setup will use after this driver is installed. Usually, this is 640x480, 8 bits per pixel.

HKR,DEFAULT,drv,,sample.drv

The drv value specifies the main DRV file that should be loaded for the modes supported by your display driver. Usually, there is only one DRV file (for example, a DIB engine minidriver), but in some cases different DRV files may be used for different video modes, especially planar VGA modes. For example, VGA.DRV is always used for 640x480x4bpp. SUPERVGA.DRV is often used for 800x600x4bpp. The MODES subkey explains this in more detail in the following.

HKR,DEFAULT,vdd,,"*vdd,*vflatd"

The vdd value specifies what should be written to the "display=" line in the [386Enh] section of SYSTEM.INI. Windows 95 drivers should always have *VDD. Minidrivers that require VFLATD should also include *vflatd here, as shown in the preceding. If your driver does not use VFLATD, then this line can have the value *vdd.

HKR,DEFAULT,minivdd,,sample.vxd

The minivdd value specifies the mini-VDD VxD that the VDD should load for this display driver.

HKR,DEFAULT,carddvdd,,cardsamp.vxd

The cardvdd value specifies a secondary, optional mini-VDD VxD that the VDD should load, in addition to the mini-VDD. Card VDD's can add to and/or override functions supported by the mini-VDD, such as adding refresh rate support, etc. If your driver uses a card VDD, remember to include it in the [SourceDisksFiles] and file copy sections.

HKR,DEFAULT,RefreshRate,,-1

The "RefreshRate = -1" value is required to cause VDD to return monitor information in the DISPLAYINFO structure returned by VDD_GetDisplayInfo. Include this line if your driver/mini-VDD/card VDD needs this information to set the refresh rate.

HKR,DEFAULT,DDC,,1

The "DDC = 1" value is required to cause the VDD to detect VESA DDC compatible monitors during Windows start up. Include this line if your driver supports DDC compatible display adapters.

HKR,DEFAULT,ExtModeSwitch,,0

The ExtModeSwitch value controls whether the VDD will allow users to switch away from full-screen MS-DOS programs running in extended and VESA graphics modes. By default, the VDD allows switching, assuming that your mini-VDD can properly save and restore the extended mode when the user returns to the MS-DOS program.

If your mini-VDD does not properly save and restore extended and VESA graphics modes, then you must include this line in your INF. This will cause the VDD to just beep if the user attempts to use ALT-TAB or ALT-ENTER to switch away from a full-screen virtual machine running in an extended graphics mode.

HKR,"MODES\4\640,480",drv,,vga.drv
HKR,"MODES\4\640,480",vdd,,*vdd
HKR,"MODES\4\800,600",drv,,supervga.drv
HKR,"MODES\4\800,600",vdd,,*vdd

MODES is a subkey of the display driver software key. It contains subkeys for all of the video modes supported by your driver. Pixel depths are specified as subkeys under MODES, and resolutions as subkeys under pixel depths. For example, using REGEDIT this would appear as:

MODES
    \8
        \640,480
        \800,600
        \1024,768

Under the resolution subkeys, there may be optional values included to override the default DRV and VDD values specified in the DEFAULT subkey.

All display drivers must support 640x480, 4 bits per pixel using the standard Windows VGA driver. VGA.DRV is used to override the default DRV, and *VDD overrides the default VDD (since *VFLATD is not needed by VGA.DRV).

Optionally, drivers may support 800x600, 4 bits per pixel using the standard Windows Super VGA driver (SUPERVGA.DRV), as shown in the preceding lines. If this driver does not work on your display adapters, then do not include these lines in your INF.

HKR,"MODES\8\640,480"
HKR,"MODES\8\800,600"
HKR,"MODES\8\1024,768"
HKR,"MODES\8\1152,900"
HKR,"MODES\8\1280,1024"
HKR,"MODES\16\640,480"
HKR,"MODES\16\800,600"
HKR,"MODES\16\1024,768"
HKR,"MODES\24\640,480"
HKR,"MODES\24\800,600"
HKR,"MODES\24\1024,768"
HKR,"MODES\32\640,480"
HKR,"MODES\32\800,600"

The preceding lines demonstrate example modes supported by the fictional SAMPLE.DRV installed by this INF file. Add and/or remove lines as appropriate for your driver. This list should be the superset of modes supported by the driver, regardless of variations on different adapters that the DRV supports. Your driver's ValidateMode function will be called for each entry under the MODES subkey. If for some reason the driver cannot support one or more of these modes on the current adapter, (for example, due to video memory or DAC limitations) it should fail the ValidateMode call, and the modes will not be available to the user.

[Strings]
Mfg="Sample Multimedia Visual Computer Technology Systems, Inc."
Sample1.DeviceDesc="Sample WhizKid 4000 VLB"
PCI\VEN_9999&DEV_9999.DeviceDesc="Sample WhizKid 4000 PCI"

The [Strings] section contains manufacturer and device description strings visible to users, and referenced in other sections in the INF. There should be one description per driver line in the driver section(s).

Note, for each Plug and Play ID, there should a line <device ID>.DeviceDesc, as shown in the preceding for the PCI device.


Modem INF File Extensions

The INF file extensions for modem devices are extensive. See the Modems part of the Windows 95 DDK Design and Implementation Guide for complete documentation of the modem INF file extensions.


Multifunction Device INF File Extensions

This section describes how multifunction devices get installed and configured by the Windows® 95 Plug and Play architecture. Multifunction devices are physical devices which incorporate multiple logical devices. For example a board incorporating a SCSI controller and a sound chip is considered a multifunction device, a DSP board that can behave as a modem, a sound device or both is considered a multifunction device as well.

The following devices/scenarios are covered:

  • PNP - Multiple logical devices on a single board consuming nonoverlapping resources. (Resources refers to use of IRQs, I/O ranges, memory ranges, or DMA channels.)
  • PNP - Multiple logical devices on a single board consuming overlapping resources
  • PNP - Multiple devices incorporated in a parent/daughter card configuration
  • PNP - Multiple devices incorporated in a master/slave configuration via a proprietary bus
  • PNP - A multipersonality board (for example, a DSP with multiple functions but only one available at a time)
  • Legacy multifunction devices

This section assumes that the reader is familiar with the Windows® 95 Plug and Play architecture and the relevant sections in the Windows 95 Device Driver Development Kit (DDK). One of the most important aspects of installing and configuring a multifunction card is having a proper INF file. The Beta 2 INF format has been extended to support the different flavors of multifunction cards. Sample INF files are included in this documentation.


Considerations for Logical Grouping of Devices

Note that many audio devices have dependencies which fall outside of the normal hardware resource sharing idiom, that is, IRQ, I/O, DMA, or memory ranges. For example, FM synthesizer chips often have an internal dependency on the mixer device of the card. In this example the devices should not be treated as separate logical device even though functionally they are somewhat independent of each other.

Other considerations for how to logically group the devices of a multifunction board:

  • Functionally independent but tightly coupled devices

    Example: An audio card that includes an FM synthesizer and a digital audio (wave) playback device both connected to a mixer device.

    Although these devices are somewhat functionally independent, they still have important interconnections. There must be a way to associate the synthesizer, wave, and mixer devices with each other. If such an association cannot be made, then an application would not, for example, be able to determine which mixer device to utilize in order to alter the audio being produced by a given synthesizer device. In some cases, this association cannot be accomplished in a bus-independent manner. By grouping the resources of all the devices as a single logical device (with a single devnode) the association can be made more easily.

  • Devices providing compatibility modes

    Example: An audio card that provides Sound Blaster compatibility. However, the device can only operate in compatibility mode or native mode, but not both simultaneously.

    Such a device would typically implement two register planes (one native and a second "compatibility plane" for Sound Blaster emulation) which are connected to a single DAC/ADC. Obviously these register planes are not functionally independent, they are in fact mutually exclusive. The device should not be designed as two logical devices (one using a native PNP ID and another using the Sound Blaster PNP ID). Instead, to properly handle this case, a single devnode should be created containing all required resources including both the native registers and the Sound Blaster compatible registers. The supporting drivers must handle the hardware contention between the separate register sets at the I/O level.


Multiple Logical Devices - Non-Overlapping Resources

Previous Next

Multiple Logical Devices - NonOverlapping Resources

This is the most common flavor of multifunction cards and the one recommended for full Windows 95 Plug and Play compatibility. The Plug and Play ISA specification and the PCI specifications define a standard way for identifying and configuring the various logical devices on a given physical board. The logical devices included in these boards must be functionally independent, electrically isolated, consume different resources and are treated as separate devices with independent INFs and drivers.

For example a display adapter that has video acceleration functions on a separate chip will specify two separate logical devices with distinct device IDs. Each logical device will be supported by a dedicated driver. The two drivers may interact among themselves via a private interface.


Multiple Logical Devices - Overlapping Resources

If the logical devices must share certain resources such as memory or I/O regions, one of the logical devices may claim the shared resources for the others and make them available through a private interface. This will also ensure that proper initialization and clean-up is not impacted by driver load sequence.

For example, a display adapter with built-in MPEG support will specify two logical devices. The display device will claim the frame buffer which is shared by both devices and make it available to the MPEG driver via a private interface. If the frame buffer is accessed via a dedicated port which is used only by the MPEG driver, that port should be claimed by the MPEG device. This will ensure the port is available to other devices if the MPEG device is disabled for some reason. If there are multiple drivers accessing the shared memory regions through the same ports, those ports should be claimed by the display device and made available to the other drivers through a private interface.


Multiple Logical Devices - Parent/Daughter Card Configuration

In this case some logical devices may not be always physically present on the parent board at all time. The recommended Plug and Play solution is to tie the device information and configuration logic to the presence of the daughter card. This will enable Windows 95 to correctly enumerate and configure the devices when they are present. If this is not possible, another alternative is to always report all the possible logical devices. Windows 95 will install all these devices and configure them. This will require the board vendor to provide device drivers and INF files for all the possible devices. The drivers will be loaded by Windows 95 at boot time. If the driver(s) for the daughter card device(s) don't find their respective devices they can return DEVICE_NOT_THERE to the configuration manager. This will enable the configuration manager to re-use the resources the daughter card would ordinarily require. When the daughter card is plugged in, the drivers will initialize successfully and retain their assigned resources. If installing all the drivers is not possible, the user will be forced to select "don't use device" for each of the missing logical devices. In this case, when the daughter card is added to the system, the user will need to re-enable the daughter card's logical devices via the device manager.

See the next section for discussion on the case in which the driver for the parent card needs to be replaced when the daughter card is added.


Multiple Logical Devices - Master/Slave Card Configuration

This case is similar to the parent/daughter card configuration. The main difference is the ability to off-load the enumeration and configuration responsibility from the parent to the slave in this case. If the slave card is not present Windows 95 will not enumerate it and the drivers won't be installed or loaded for the card. When the slave card is installed it will be detected by one of the Windows 95 enumerators and its drivers will be installed. The responsibility for establishing the communication between the master and slave card will typically lie on the master card.

This poses an interesting problem: the master card may be driven by a default Windows 95 driver which doesn't have the enumeration/communication capabilities for the bus that's connecting the two boards. For example a display adapter with a VESA Media Channel (VMC) on board may work perfectly fine with a generic display driver. But when the slave card is installed the driver for the parent card needs to be replaced with a VMC aware driver so it can communicate with the slave. Currently there is no method to accommodate this scenario unless the display driver is already VMC aware.


Legacy Multifunction Devices

Windows 95 provides a mechanism which allows mapping a single physical device to multiple logical devices even when the appropriate identification and configuration structures are missing or lacking. In this case the Windows 95 configuration manager creates the various logical devices based on information included in the INF file of the physical device. The class for these cards is defined in the INF as Multifunction and the IDs and the specific driver and configuration information for each of the logical devices is included in the INF as well. When Windows 95 detects a multifunction device it will install each of the logical devices listed in the INF separately, then enumerate each of them every boot or whenever the physical device is plugged in (in the case of hot plug-able devices). The following section describes the structure of the INF file for multifunction devices and provides an example of a multifunction PCMCIA card.


Multifunction Legacy Devices - Registry

A legacy multifunction card is enumerated by the relevant Windows 95 enumerator as a single device with all resources allocated to that device. When a legacy multifunction card is detected, the configuration manager will act as the default enumerator for its children (the logical devices on the device). This is depicted in the registry by listing CONFIGMG as the enumerator and device loader for child devices. The following example shows how a multifunction sound/SCSI card will appear in the registry:

[HKEY_LOCAL_MACHINE\Enum\Root\ACM1234\0000]
InfName=ACMAMF.INF
DeviceDesc=ACMA Audio card with SCSI
Class=MEDIA
HardwareID=ACM1234
Driver=MEDIA\0000
Mfg=ACMA Corp.
ConfigFlags=hex:00,00,00,00

[HKEY_LOCAL_MACHINE\Enum\Root\ACM1234\0000\LogConfig]
0=<logical configuration 0>
1=<logical configuration 1>

[HKEY_LOCAL_MACHINE\Enum\Root\ACM1234\0000\Child0000]
HardwareID=MF\ACM1234_Dev0
ResourceMap=hex:00,01,02,03,04,05,06,07,0c,0e

[HKEY_LOCAL_MACHINE\Enum\Root\ACM1234\0000\Child0001]
HardwareID=MF\ACM1234_Dev1
ResourceMap=hex:01,05,06,08,09,0a,0b,0d

In the preceding example, a legacy multifunction card by ACMA has two child devices. The driver branch for the parent device MEDIA\0000 includes information about the parent driver which may be used for initialization/configuration of the physical card as well as coordination between the children. The child branches include information about the simulated hardware Ids and indexes of the parent's logical configurations.

[HKEY_LOCAL_MACHINE\Enum\MF\CHILD0000\ROOT&ACM1234&0000]
HardwareID=MF\ACM1234_Dev0
Class=MEDIA
Driver=MEDIA\0001
Mfg=ACMA Corp.
DeviceDesc= ACMA Audio card with SCSI (Audio)
ConfigFlags=hex:00,00,00,00

[HKEY_LOCAL_MACHINE\Enum\MF\CHILD0001\ROOT&ACM1234&0000]
HardwareID=MF\ACM1234_Dev1
Class=SCSIAdapter
Driver=SCSIAdapter\0000
Mfg=ACMA Corp.
DeviceDesc= ACMA Audio card with SCSI (SCSI)
ConfigFlags=hex:00,00,00,00

The device information of the child devices is kept under the Enum\MF (for multifunction). Beside the location, these entries look exactly the same as standard single function device entries. Each of the devices specifies an independent device class and device descriptions.

[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Class\MEDIA\0000]
DevLoader=*CONFIGMG
Enumerator=*CONFIGMG
DeviceDriver=acma.vxd
InfPath=ACMAMF.INF
InfSection=ACM1234_Device
DriverDesc= ACMA Audio card with SCSI

[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Class\MEDIA\0001]
DevLoader=mmdevldr.vxd
Driver=acmaudio.vxd
InfPath=ACMAUDIO.INF
InfSection=ACM1234_Dev0_Device
DriverDesc= ACMA Audio card with SCSI (Audio)

[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Class\SCSIAdapter\0000]
DevLoader=*IOS
PortDriver=acma.mpd
InfPath=ACMASCSI.INF
InfSection= acm1234.drv
DriverDesc= ACMA Audio card with SCSI (SCSI)

The device loader and enumerator for the multifunction parent is CONFIGMG. The driver itself is provided by the vendor for initialization and coordination purposes.


Multifunction Legacy Devices - INF Definition

The new information in the registry will be communicated via the INF file. During installation, the device installer will install not only the section pointed at by the section name in a device line but will also look for a section, named InstallSection.MF and will execute this section too. The device personalities will be installed through separate INFs. This is because an INF can only contain descriptions of a single class and the device personalities will be of multiple classes.


[InstallSection.MF]

This is a standard installation section except that Addreg relative (HKR) commands will refer to the Hardware branch. In this section, the ChildList can be generated as well as the resource map.


Resource Map

This entry in the INF is used in the [InstallSection.mf] section. When installing an EISA Multifunction Card, the resources are not really assigned to the parent board but rather to the independent functions. The EISA enumerator, however, reports only the parent device and reports all resources as belonging to the common parent. This section will tell the configuration manager how to divide the parent resource between the children. the resource map is a binary format record added using an addreg command, where each byte represents the ordinal of the EISA resource record belonging to the child. This is not a bitmap, it is a list of ordinals. There is a limit of 256 EISA ordinal values.

HKR,,ResourceMap,,1,01,04,26


Child List

This entry is a text entry that, like the resource map, is added via the addreg command from an [InstallSection.MF] section. These entries cause the configuration manager to create devnodes for every logical device contained in the child list. Configuration Manager, enumerates these devices. The INF entry would look like the following example.

HKR,ChildList,LogicalDeviceID1,,CompatibilityIDList


PCMCIA Multifunction Card Example

The following example shows the main INF file for a multifunction modem\network PCMCIA card. The child INFs are not shown since they are not different than standard single function device INFs.

INF File

[Version]
LayoutFile=layout.inf
Signature="$WINDOWS 95$"
Provider=%MS%
Class=MultiFunction

;
; Table of Contents
;
[Manufacturer]
%CARDWIZ%=CARDWIZ

[CARDWIZ]
%CARDWIZ10BT%=CARDWIZ10BT.mf,PCMCIA\CARDWIZ-CREDITCARD_ETHERNET+MODEM_10BASE-T-XXXX2

[CARDWIZ10BT.mf]
AddReg=StandardMF.Reg,ADDREG_CARDWIZ.reg

[CARDWIZ10BT.mf.HW]
AddReg=CARDWIZ10BT.mf.RegHW

[CARDWIZ10BT.mf.RegHW]
HKR,Child0000,HardwareID,,MF\CARDWIZCEM_DEV0
HKR,Child0000,ResourceMap,1,00,01,02,04
HKR,Child0001,HardwareID,,MF\CARDWIZCEM_DEV1
HKR,Child0001,ResourceMap,1,01,02,03,04

[StandardMF.Reg]
HKR,,DevLoader,,*CONFIGMG
HKR,,Enumerator,,*CONFIGMG
HKR,,CMDrivFlags,01,03,00,00,00     ; Sets flags as described
                                    ; in CM_Register_DeviceDriver call
                                    ; Mark device as
                                    ;    Can be removed
                                    ;    Can be configured

[ADDREG_CARDWIZ.reg]
HKR,Override,0000,1, \
;
; CONFIGMG_VERSION
;
00,04,00,00, \
;
; PRIORITY
;
00,00,00,00, \
;
; I/O Resource Descriptor 0
;
<<resource information here>>
;
; I/O Resource Descriptor 1
;
<<resource information here>>
;
; IRQ Resource Descriptor
;
<<resource information here>>
;
; MEM Resource Descriptor 0
;
<<resource information here>>
;
; MEM Resource Descriptor 1
;
<<resource information here>>
;
; REQUEST_CONFIG_PKT Descriptor
;
<<refer to the DDK for information about this section>>
;
; TERMINATOR
;
00,00,00,00

;
; Translatable strings
;
[Strings]
MS="Microsoft"
;
; Manufacturer names
;
CARDWIZ="Cardwiz"
; Adapter names
;
CARDWIZ10BT="Cardwiz CreditCard Ethernet+Modem 10Base-T"

The calculation of this checksum is described in the PCMCIA section of the DDK. A tool called DTPL.EXE is provided to help card developers create device Ids and configuration information for their cards.


Multimedia INF File Extensions

IHVs who develop a multimedia hardware device for Windows® 95 must provide a device information file (.INF) file on the device driver installation diskette for the device.


Multimedia Device Information (INF) Files

There are two DDK sample INF files for multimedia hardware devices that you can use as models for your INF file. They are located in the directory \DDK\MMEDIA\SAMPLES\INF. The sample INF files are:

  • MIDI.INF, which is used to install a MIDI device.
  • WAVE.INF, which is used to install a waveform-audio device.

These sample INF files are both relatively straightforward. The DDK topic, Device Information Files in the Plug and Play section of the Windows 95 DDK documentation gives you enough information to interpret the sample INF files and make any necessary changes to fit your device. The following topics give information specific to multimedia hardware device INF files that is not found in the Device Information Files section. Information about INF files for multimedia software components will be provided in a future release of the Windows 95 DDK documentation.


Multimedia Device Hardware Class

Hardware multimedia devices, of which MIDI and waveform-audio devices are two examples, are all members of the MEDIA class of devices for Windows 95. In the [Version] section of the INF file for your device, you should use the following key:

Class = MEDIA


Multimedia Device Class Registration

Every INF file should contain a device-class registration section, because a particular Windows 95 user may have never previously installed a device of that class on their Windows 95 machine. (For more information, see the topic ClassInstall Section in the Device Information Files section.)

For example, in the sample MIDI.INF file, the ClassInstall section and sections associated with it contain the following lines:

[ClassInstall]
AddReg=MidiReg

[MidiReg]
HKR,,,,%MediaClassName%
HKR,,Icon,,1
. . .
[Strings]
MediaClassName="Media Devices"

The sample WAVE.INF file contains a ClassInstall section and associated sections with lines that are shown in the following:

[ClassInstall]
AddReg=Class.AddReg

[Class.AddReg]
HKR,,,,%MediaClassName%
HKR,,Icon,,1
. . .
[Strings]
MediaClassName="Media Devices"

These INF file sections from both the MIDI.INF and WAVE.INF sample INF files register a descriptive string for a MEDIA class device: Media Devices. All multimedia hardware device INF files must register this same descriptive string, Media Devices, in this way. This descriptive string is displayed by Windows 95 in the user interface to describe the group of all MEDIA class devices.

Note that the descriptive string itself (Media Devices) is in the [Strings] section of the INF file along with other displayable strings. Putting all displayable strings in one section of an INF file makes it easier for translators to locate the words and phrases they have to translate for world markets.


Device Loader for Windows 95 Multimedia Devices

All multimedia device drivers must be loaded by the Windows 95 device loader MMDEVLDR.VXD, which establishes the device driver(s) in Ring 3, as described previously in this section. All of the sample multimedia INF files have the following line in the section that adds the device to the registry:

HKR,,DevLoader,,mmdevldr.vxd

For example, in the MIDI.INF sample file, such a line is found in both the [MPU401.AddReg] and [ADLIB.addreg] sections. Your INF file must use the same line in the comparable section that adds your device to the registry.


Internal/External Switch for MIDI Devices

For MIDI devices, one statement type that can be used in an INF file is not documented in the Device Information Files section. (For multimedia hardware devices other than MIDI devices, there are no INF file statement types other than those documented in the Device Information Files section; no special switches have to be set for non-MIDI devices.)

If your MIDI device drives a synthesizer that is not on the device, include a statement that sets an External switch in the Drivers key of the registry for your device by using an INF file statement of the form:

HKR,Drivers\midi\msmpu401.drv,External,1,01,00,00,00

Following is an example of such a statement, in the context of the entire section that puts values into the Drivers key for the device (note that this example section is not taken from the sample MIDI.INF file).

[MPU401.AddReg]
HKR,,Driver,,msmpu401.vxd
HKR,Drivers\midi\msmpu401.drv,Driver,,msmpu401.drv
; following is the statement to use for external synthesizer
HKR,Drivers\midi\msmpu401.drv,External,1,01,00,00,00
HKR,Drivers,SubClasses,,"midi"


Network INF File Extensions

The Microsoft® Windows® 95 Setup program, the Control Panel, and the Plug and Play system use class installer dynamic-link libraries (DLLs) to install, remove, and configure hardware drivers for all types of hardware on the system. The network class installer (Netdi.dll) handles all network drivers and software components. The network components are divided into four types: network adapter drivers, transport drivers, client software, and other network services. Each type corresponds to a Windows 95 device class described by a Plug and Play INF file. The corresponding device class names are Net, NetTrans, NetClient, and NetService. Each network driver or software component must be specified in an INF file tagged as one of the four network classes.

The network class installer handles installation of all network drivers and components for all network hardware and software vendors. Both Microsoft internal components and third-party vendors should use the Microsoft network driver class installer for network driver installation in order to maintain maximum interoperability with other network components and with Windows 95 Plug and Play.

Most network drivers and software can fully specify their installation requirements and files by using network INF files. These requirements include the list of files to copy, registry entries to make, requirements and restrictions for interoperability and compatibility as well as scripts to describe user-modifiable parameters. Also, network INF files can manipulate text file and .ini files to add drivers to the configuration.

Drivers that have more complex requirements than the INF scripts can describe, such as custom user-interfaces or installation procedures, may register a Network Driver Installer (NDI) procedure to handle NDI messages. The NDI procedure allows you to customize many installation and configuration actions. A custom NDI procedure is optional: the default NDI procedure handles all configuration and installation functions based on information provided in the INF file. In this way, the custom procedure can pass any message along to the default procedure that it does not wish to handle, or it can perform special processing and then call the default handler. (This is a similar arrangement to a window procedure and the DefWindowProc.)


Network INF Files

The INF file format for network drivers follows the same general format as all Windows 95 Plug and Play hardware INF files. NETDI adds to this format by specifying network-installer-specific registry entries. These entries are specified in the INF scripts using the AddReg keyword; they are therefore added to the registry where NETDI stores them along with other driver-related information. Each INF file has the following general format. Many sections entries are omitted so that the general structure of the file can be seen. Boldface type indicates defined keywords.

[version]
signature=$Windows95$
Provider=%V_PROVIDER%
; Class = Net | NetTrans | NetClient | NetService
Class=Net

[manufacturer]
%V_ACME%=acme_drivers

[acme_drivers]
%*PNPF007.desc%=acme007_ndi, *PNPF007
%*PNPF008.desc%=acme008_ndi, *PNPF008

[acme007_ndi]
AddReg=acme00X_ndi_reg

[acme008_ndi]
AddReg=acme00X_ndi_reg

[acme00X_ndi_reg]
; the contents of this section are described later in this document
...

[strings]
V_ACME="ACME, Inc."
V_PROVIDER="ACME, Inc."
; Plug and Play drivers must have a pnp-id + .desc entry in the strings section.
*PNPF007.desc="ACME Ethernet 007"
*PNPF008.desc="ACME Ethernet 008"

Note The files Net.inf, Nettrans.inf, Netcli.inf, and Netservr.inf contain an extra section, the [ClassInstall] section, that are not in other INFs. These files are the only INF files that should have [ClassInstall] sections.

Each software component has three main INF file sections. The main section is executed whenever the user selects a component from the Select Device dialog. It contains all the registration information required by NETDI. This information, described in the next section describes the network interfaces used by the component, compatibility rules, and general PnP driver parameters. It is also used to copy any third-party NDI DLLs. This section defines the other two important INF file sections, the Install and Remove sections. The registration section for the Microsoft NetBEUI protocol is shown in the following:

[NETBEUI.ndi]
AddReg=NETBEUI.ndi.reg
;Unique PnP ID, entry need to be present so that setup can back track
;
the device name from the driver
DeviceID=NETBEUI
;Specify if the device can be installed more than once
;if not specify, default is MaxInstance=1
MaxInstance=1

[NETBEUI.ndi.reg]
HKR,Ndi,DeviceID,,NETBEUI
; NDIS Info
HKR,NDIS,LogDriverName,,NETBEUI
HKR,NDIS,MajorNdisVersion,1,03
HKR,NDIS,MinorNdisVersion,1,0A
HKR,NDIS\NDIS2,DriverName,,"NETBEUI$"
HKR,NDIS\NDIS2,FileName,,"*netbeui"
; Interfaces
HKR,Ndi\Interfaces,DefUpper,,"netbios"
HKR,Ndi\Interfaces,DefLower,,"ndis2,ndis3,odi"
HKR,Ndi\Interfaces,UpperRange,,"netbios"
HKR,Ndi\Interfaces,LowerRange,,"ndis2,ndis3,odi"
; Install sections
HKR,Ndi\Install,,,"NETBEUI.Install"
HKR,Ndi\Remove,,,"NETBEUI.Remove"
;Sessions Parameter (global)
HKR,Ndi\params\sessions,location,,"System\CurrentControlSet\Services\Vxd\NetBeui"
HKLM,System\CurrentControlSet\Services\VxD\NETBEUI\Ndi\params\sessions,ParamDesc,,%NETBEUI_PARAM_SESSIONS%
HKLM,System\CurrentControlSet\Services\VxD\NETBEUI\Ndi\params\sessions,default,,10
HKLM,System\CurrentControlSet\Services\VxD\NETBEUI\Ndi\params\sessions,type,,int
HKLM,System\CurrentControlSet\Services\VxD\NETBEUI\Ndi\params\sessions,min,,3
HKLM,System\CurrentControlSet\Services\VxD\NETBEUI\Ndi\params\sessions,max,,117
;NCBS Parameter (global)
HKR,Ndi\params\ncbs,location,,"System\CurrentControlSet\Services\Vxd\NetBeui"
HKLM,System\CurrentControlSet\Services\VxD\NETBEUI\Ndi\Params\ncbs,ParamDesc,,%NETBEUI_PARAM_NCBS%
HKLM,System\CurrentControlSet\Services\VxD\NETBEUI\Ndi\Params\ncbs,default,,12
HKLM,System\CurrentControlSet\Services\VxD\NETBEUI\Ndi\Params\ncbs,type,,int
HKLM,System\CurrentControlSet\Services\VxD\NETBEUI\Ndi\Params\ncbs,min,,7
HKLM,System\CurrentControlSet\Services\VxD\NETBEUI\Ndi\Params\ncbs,max,,255
; Context help
HKR,Ndi,HelpText,,%NETBEUI_HELP%

If your INF file refers to other INF files, there are some additional steps you must take in this registration section. See Referring to Other INFs.

The Install section is executed when the Network Control Panel (or Setup) saves all changes. This section should copy all the files needed for the software component. It should make any registry or .ini file entries that need to be made to start the software beyond the entries NETDI makes in the Plug and Play tree.

For example, the Install section for NetBEUI is:

[NETBEUI.Install]
AddReg=NETBEUI.AddReg
CopyFiles=NETBEUI.CopyFiles
[NETBEUI.AddReg]
HKR,,DevLoader,,*ndis
HKR,,DeviceVxDs,,netbeui.vxd
; RPC
HKLM,"Software\Microsoft\Rpc\ClientProtocols",ncacn_nb_nb,,rpcltc5.dll
HKLM,"Software\Microsoft\Rpc\ServerProtocols",ncacn_nb_nb,,rpclts5.dll
[NETBEUI.CopyFiles]
netbeui.vxd
; RPC
rpcltc5.dll
rpclts5.dll

The Remove section is executed when the user removes a software component. This section should remove any registry or .ini file entries that refer to the software and optionally delete the software from the hard disk. The NETBEUI Remove section is:

[NETBEUI.Install]
AddReg=NETBEUI.AddReg
CopyFiles=NETBEUI.CopyFiles
 [NETBEUI.AddReg]
HKR,,DevLoader,,*ndis
HKR,,DeviceVxDs,,netbeui.vxd
; RPC
HKLM,"Software\Microsoft\Rpc\ClientProtocols",ncacn_nb_nb,,rpcltc5.dll
HKLM,"Software\Microsoft\Rpc\ServerProtocols",ncacn_nb_nb,,rpclts5.dll
[NETBEUI.CopyFiles]
netbeui.vxd
; RPC
rpcltc5.dll
rpclts5.dll


NDI Object Registrations

NETDI gets all of the driver-specific information for a driver or network component (referred to generically as NDI objects) either from the registry section for the driver or from a custom NDI installer procedure. The registry section for the object is initially populated based on the driver install section in the INF file.


General Driver Information

Driver Sub Key | Value Name | Value | Description
(null) | DriverDesc | driver description | A string that describes the driver.
(null) | DevLoader | *ndis | A VxD that is the device loader for this node. The driver should be *ndis unless your device has a different device loader.
(null) | DeviceVxD | driver list | A comma-separated list of VxDs. The drivers are loaded in the order listed.


NDI Registration Parameters

Driver Sub Key | Value Name | Value | Description
Ndi | DeviceID | device ID | The device ID for this driver.
Ndi | NdiInstaller | dllname,procname | The custom NDI procedure for this driver. The DLL name is required; the default proc name is NdiInstaller if none is specified. Note, this DLL must be copied in the registration section rather than the install section. (See the following)
Ndi | InfFile | filename | The InfFile value is maintained by NETDI and should not be specified in the INF file.
Ndi | InfSection | section name | The InfSection value is maintained by NETDI and should not be specified in the INF file.
Ndi | InstallInf | list of INFs | The list of INF files to add to the INF database when this component is selected. These INFs must be copied in the registration section. See Referring to other INFs in the following.

If your component requires a custom NDI procedure DLL, this DLL must be copied before any of the other files are copied. This allows the DLL to display any custom UI before the user clicks the OK button in the Network Control Panel to cause NETDI to save the configuration. Furthermore, INF files that are not included with Windows 95 should copy themselves to the hard disk. To do this, copy the DLL and INFs by using a CopyFiles command in your registration section, as shown in the following example:

[MYDEVICE.ndi]
AddReg=MYDEVICE.ndi.addreg
CopyFiles=MYDEVICE.ndi.copyfiles,MYDEVICE.inf.copyfiles

[MYDEVICE.ndi.addreg]
HKR,Ndi,DeviceID,,MYDEVICE
HKR,Ndi,Installer,,"MyNDI.DLL,MyNDIProc"
; ...other registration info...
HKR,Ndi\Install,,,"MYDEVICE.Install"
[MYDEVICE.ndi.copyfiles]
MyNDI.DLL
[MYDEVICE.inf.copyfiles]
MyNDI.INF

[MYDEVICE.Install]
AddReg=MYDEVICE.Install.addreg
CopyFiles=MYDEVICE.Install.copyfiles

[MYDEVICE.Install.addreg]
; Registry keys needed to start this component
[MYDEVICE.Install.copyfiles]

[DestinationDirs]
MYDEVICE.ndi.copyfiles = 11 ; System directory
MYDEVICE.inf.coypfiles = 17 ; INF directory


Files Needed by Component.PCMCIA and Plug and Play Drivers

Any network card that has a hardware enumerator (PCMCIA, EISA, PCI, ISAPNP, and so on) must have a special parameter set in the registration section to indicate that the card is a PnP card. The registration section for these cards should have a CardType parameter to indicate what the type of the card is:

Driver Sub Key | Value Name | Value | Description
Ndi | CardType | cardtype | The type of the card:
 |  |  | PCMCIA - for PCMCIA cards
 |  |  | PNP - for PnP cards (as defined in the preceding)
 |  |  | LEGACY - for other cards (default)
 |  |  | Note: Cardtype=PCMCIA implies PNP.


Install Section Parameters

Statically loaded VxDs must also be stored in the HKLM\System\CurrentControlSet\Services\VxD\VXDNAME key, where VXDNAME is the name of the driver (usually the base name of the VxD file). Under this key, the following value must be set:

Driver Sub Key | Value Name | Value | Description
(null) | StaticVxD | /driver list/ | A comma-separated list of VxDs that are loaded statically by the Configuration Manager.


Help Text

The Network Control Panel has an area on the bottom of the Configuration tab used to give the user a description of the selected object. By default, when the user selects an object, the help area simply displays a description of the class of the selected device. You can override this default and have the Network Control Panel display text specific to your device when the user selects it. This text is specified in the HelpText parameter:

Driver Sub Key | Value Name | Value | Description
Ndi | HelpText | text to appear | This specifies the string to appear in the help text box when the user selects this device.

This help text should be written to describe how the selected object benefits the user (such as, what can the user do with the object). For example, the help text for a client should not just say what the client is, but what it allows the user to connect to.


Driver Interface Rules

NETDI uses upper and lower interfaces to describe the possible relations between the layered drivers in the network system. The lower interface is the software or hardware interface that the driver talks to. For example, a network adapter driver might talk to Ethernet or token ring. The upper interface is the software interface that the driver provides. For example, an NDIS 3.1 network adapter driver provides ndis3 as an upper interface; an NDIS 3.1 transport driver has ndis3 as a lower interface and might provide NetBios or ipx as its upper interface.

The following interface names are predefined to cover the most common interfaces; however, any string of alphanumeric characters is a legal interface name. This allows you to create private interfaces between components. When defining your own interface, include the manufacturer name in the interface name to avoid conflicts with other vendors.

ethernet | lower edge for an Ethernet network adapter
tokenring | lower edge for a token ring network adapter
serial | lower edge for a serial network adapter
fddi | lower edge for an FDDI network adapter
baseband | lower edge for a baseband network adapter
broadband | lower edge for a broadband network adapter
arcnet | lower edge for an ARCNET network adapter
odi | ODI
ndis2 | NDIS 2.1
ndis3 | NDIS 3.X
netbios | NetBIOS
ipx | IPX
tdi | TDI interface to TCP/IP
winsock | the Windows Sockets interface
winnet31 | upper edge for a Windows 3.1 compatible WinNet driver
multinet31 | upper edge for a Windows for Workgroups multinetwork compatible WinNet driver
winnet4 | upper edge for a Window 4.0 network provider

NETDI matches the upper and lower interfaces of drivers to validate bindings between drivers. In addition, NETDI also checks for other required or excluded interfaces down the chain of bound driver and in the entire network subsystem. If an object has a lower edge that does not match the upper edge of any of the installed components, NETDI will attempt to install a component that does match the interface. For example, the Client for Windows Networks has a lower edge of NetBIOS. If the user tries to install this client without a NetBIOS protocol, NETDI will automatically install a protocol to match the required interface. In this case it would install NetBEUI.

The following list shows the registry entries for specifying interfaces requirements for a network driver. An interface list is a comma-separated list of interface names, for example, ndis2, ndis3, odi.

Driver Sub Key | Value Name | Value | Description
Ndi\Interfaces | DefUpper | interface list | These are the currently available upper interfaces.
Ndi\Interfaces | DefLower | interface list | These are the currently available lower interfaces.
Ndi\Interfaces | UpperRange | interface list | These are all possible upper interfaces. This value is maintained by NETDI and should not be set in an INF file.
Ndi\Interfaces | LowerRange | interface list | These are all possible lower interfaces. This value is maintained by NETDI and should not be set in an INF file.
Ndi\Interfaces | RequireAny | interface list | The driver requires that any driver in the system supports this interface.
Ndi\Interfaces | ExcludeAny | interface list | The driver requires that no driver in the system supports this interface.

The current upper and lower interfaces are queried in an NDI procedure by sending the appropriate NDI_GET_UPPER_INTERFACES and NDI_GET_LOWER_INTERFACES messages. The default NDI procedure reads the interface list from the registry. A custom NDI procedure can therefore enable or disable interfaces by returning a different interface list.


Device Compatibility Rules

A driver can specify compatibility or incompatibility with other drivers in the system by specifying lists of device IDs. These can specify required or excluded devices. The following list shows the registry entries for specifying compatibility with other devices. A device is a Plug and Play device ID; a device list is a comma-separated list of device IDs. (Note that for nonhardware devices, the Plug and Play device ID is either the NDIS logical driver name or the base file name of the VxD or driver.)

Driver Sub Key | Value Name | Value | Description
Ndi\Compatibility | RequireAll | device list | All of the devices in device list must be present in the network system.
Ndi\Compatibility | RequireAny | device list | At least one of the devices in device list must be present in the network system.
Ndi\Compatibility | ExcludeAll | device list | None of the device in device list can be present in the network system.


Referring to Other INFs

Using the Ndi\Compatibility keys described previously, it is possible for an INF to install other devices. These devices may be described in other INFs. To accomplish this, an INF must do the following:

  • Copy any other INFs that have devices that are referenced. This must be done in the registration section of the INF. (Note: all INFs must be distributed in the same directory)
  • Add the InstallInf key to the registry to have the other INFs added to the INF database.

For example, if MYDEVICE in Myndi.inf required OTHERDEVICE in Other.inf, MYNDI should look like the following:

[MYDEVICE.ndi]
AddReg=MYDEVICE.ndi.addreg
CopyFiles=MYDEVICE.ndi.copyfiles,MYDEVICE.inf.copyfiles

[MYDEVICE.ndi.addreg]
HKR,Ndi,DeviceID,,MYDEVICE
HKR,Ndi,InstallInf,,"OTHER.INF"
; ...other registration info...
HKR,Ndi\Install,,,"MYDEVICE.Install"
[MYDEVICE.inf.copyfiles]
MyNDI.INF
OTHER.INF

[MYDEVICE.Install]
AddReg=MYDEVICE.Install.addreg
CopyFiles=MYDEVICE.Install.copyfiles

[MYDEVICE.Install.addreg]
; Registry keys needed to start this component
[MYDEVICE.Install.copyfiles]

[DestinationDirs]
MYDEVICE.inf.copyfiles = 17 ; INF directory


Install and Remove Information

When the driver is actually to be installed or removed, NETDI uses this information to tell which sections from the drivers INF files to execute. The install and remove entries can specify a base section that gets executed unconditionally whenever the driver is added or removed. The unconditional entries use the NULL value name. In addition, one can also specify interface-specific install and remove sections so only files or registrations that are a needed for the given upper interface are installed.

When installing, NETDI executes the base (null) section first, and then any interface-specific sections. When removing, NETDI executes interface-specific sections first and executes the base (null) section last.

Driver Sub Key | Value Name | Value | Description
Ndi\Install | (null) | section name | Specifies the section name to execute for installing the driver. If this value exists, it is executed for all interfaces.
Ndi\Install | interface name | section name | Specifies the section name to execute for installing the driver. It is only executed if interface name is among the current upper interfaces for the driver.
Ndi\Remove | (null) | section name | Specifies the section name to execute for removing the driver. If this value exists, it is executed for all interfaces.
Ndi\Remove | interface name | section name | Specifies the section name to execute for installing the driver. It is only executed if interface name is among the current upper interfaces for the driver.


Hardware Resources

For NDIS3 network adapter drivers, hardware resources for the card memory base address, base I/O address, DMA channel, and IRQ level are specified by a Logical Configuration entry in the INF file. These Logical Configuration entries are documented in the Windows 95 Device Information Files specification.

NDIS2 network adapter drivers store hardware resources in the parameters section (described in the following). The parameter key must be the same as the one used in Protocol.ini.

Note: On computers, IRQ2 and IRQ9 are really the same. For this reason PnP always refers to IRQ2 as IRQ9. If the network adapter driver requires that a 2 be passed to it for IRQ2, it must set the IRQ2 parameter flag (described in the next section).


Driver Parameters

You can specify any number of software parameters to be saved under the driver's registry key. For NDIS2 drivers, these are also saved in PROTOCOL.INI. The parameter descriptions are saved under the Ndi\params subkey; their current values are saved at the root of the driver key. For NDIS drivers, the NDIS wrapper can read these parameters from the root of the driver key and report them back to the driver. The user views and edits the parameters from the Advanced property sheet page provided by NETDI. Parameters can be numeric (int, long, word, dword), or text (edit, enum). For numeric types, you can specify the minimum, maximum and, optionally, the interval value. For the enum type, you must specify a list of values and descriptions. For the edit type, you can specify certain edit control options: maximum length, OEM-text compatibility, and upper case.

Driver Sub Key | Value Name | Value | Description
Ndi\Params\ParamKey | ParamDesc | string | Specifies the parameter description that will be shown in the Advanced dialog.
Ndi\Params\ParamKey | Type | type | The parameter type. Can be: int, long, word, dword, enum, edit. The type is edit if type is not specified.
Ndi\Params\ParamKey | Default | default value | Specifies the default value if no current value is specified.
Ndi\Params\ParamKey | Optional | 0|1 | Marks the parameter as optional. An optional parameter can have no current value. The user can mark it as Not Present in the Advanced dialog. If Optional is not specified, the user must use the default value or supply a value the parameter.

Range information for numeric types

Ndi\Params\ParamKey | Min | numeric value | The minimum value.
Ndi\Params\ParamKey | Max | numeric value | The maximum value.
Ndi\Params\ParamKey | Step | numeric value | The step between valid value, based from the minimum value.
Ndi\Params\ParamKey | Base | 10|16 | Display and save values as decimal or hexadecimal. 10 if not specified.

Range information for enum types

Ndi\Params\ParamKey\Enum value description A multiple value key. The value name is saved as the parameter value in the registry. The RHS value is shown to the user in drop-down list box as the parameter value description.

Hardware resource parameters for NDIS2 network card drivers:

Ndi\Params\ParamKey | resc | BYTE:1-4 | This binary value is required for all hardware resource parameters. It indicates what type of hardware resource the parameter represents:
 |  |  | 1 - Memory address
 |  |  | 2 - I/O Address
 |  |  | 3 - DMA channel
 |  |  | 4 - IRQ

Use the following parameter to tell NETDI to store the parameter in some other location in the registry. Note, for this parameter, this will be the only value listed under Ndi\Params. The rest of the preceding parameters must be located in the desired registry key. (See the sessions parameter for NETBEUI listed in the preceding example.)

Storing parameters in an arbitrary registry location:

Ndi\Params\ParamKey location registry key This tells NETDI what arbitrary registry key to store the value of this parameter.

Parameter flags:

Ndi\Params\ParamKey | flag | BYTE:value | This binary DWORD value specifies flags for the parameter. The value is created by bitwise ORing the desired flags:
 |  |  | 0x10 - Used by NDIS2 only
 |  |  | 0x20 - Used by NDIS3 only
 |  |  | 0x40 - Card uses IRQ 2
 |  |  | 0x08 - Required parameter (UI will force the user to set this value).
 |  |  | Note: This parameter is written in the INF file as a DWORD using Intel(r) byte ordering. For example, 0x30 would be written in the INF file as 30,00,00,00.


Text File Processing

NETDI has the ability to search text files such as Autoexec.bat and Config.sys and insert or remove lines from them. It does this by using the following registry values in the registration section of your INF. The key name under the Ndi key is the name of the file to process. Each line to insert in this file is given a name (specified in the KeyOrder) value. For each line, you can insert or replace text in the file. Replacing a line with a null string effectively deletes the line.

NETDI executes these operations when it is committing changes to the disk.

Driver Sub Key | Value Name | Value | Description
Ndi\filename\Order | KeyOrder | list of line names | This is a list of names (subkeys under Ndi\filename) to process and the order to process the lines in.
Ndi\filename\name | Line | line to insert | This string is the line to insert according to the specified search rules.
Ndi\filename\name | Search | search pattern | The pattern to search in the file. Line will be placed before or after this line (determined by Position) For example, *ndis* searches for any line with ndis in it.
Ndi\filename\name | Replace | replace string | Text to replace in the found line. For example, to replace net start with net stop, set Search to *net start* and Replace to *net stop*.
Ndi\filename\name | Skip | search pattern | Do not process lines that match this pattern.
Ndi\filename\name | Position | DWORD:position | Where to place the string in Line relative to the line found by the Search parameter:
 |  |  | 0 - insert at top of file or before the line
 |  |  | 1 - insert at end of file or after the line


NDIS 3 Driver Information

The NDIS 3 wrapper uses this information to load and bind NDIS 3.x drivers.

Driver Sub Key | Value Name | Value | Description
NDIS | LogDriverName | driver name | The NDIS 3 driver's logical driver name.
NDIS | MajorNdisVersion | BYTE:major | The NDIS major driver version. It is a byte HEX value: 03 for NDIS 3.X. (Not applicable for NDIS 2.X drivers.)
NDIS | MinorNdisVersion | BYTE:minor | The NDIS driver version. It is a byte HEX value: 0A for NDIS 3.1, 00 for NDIS 3.0. (Not applicable for NDIS 2 drivers.)


NDIS 2 Driver Information

The device loader and NDIS 3 wrapper use this information to check if the real-mode NDIS 2 driver is in memory and to load the appropriate mapper if necessary.

Driver Sub Key | Value Name | Value | Description
NDIS/NDIS2 | DriverName | driver name | The NDIS 2 driver's base DriverName.
NDIS/NDIS2 | AdapterName | adapter name | The NDIS 2 actual adapter name and Protocol.ini section name. The AdapterName changes for multiple instances of the adapter.
NDIS/NDIS2 | FileName | driver file name | The name of the NDIS 2 driver.

Note: NETDI automatically copies the file specified in FileName, therefore it is not necessary to explicitly copy the file in a CopyFiles section in the INF file. You only need a CopyFiles section for NDIS2 if you have additional support files for your driver.


ODI Driver Information

The device loader and NDIS 3 wrapper use this information to check if the real-mode ODI driver is in memory and to load the appropriate mapper if necessary.

Driver Sub Key | Value Name | Value | Description
NDIS/ODI | DriverName | LinkDriver name | The ODI driver's LinkDriver name and the NET.CFG section name. This can be a comma separated list of driver names if more than one MLID can support this card. If Setup finds one of these MLIDs loaded, it will use that MLID rather than the one specified in FileName.
NDIS/ODI | FileName | driver file name | The name of the primary ODI driver. (not a list)

Note: NETDI automatically copies the file specified in FileName, therefore it is not necessary to explicitly copy the file in a CopyFiles section in the INF file. You only need a CopyFiles section for ODI if you have additional support files for your driver.


Other Notes for Network Card Drivers

Since they specify information for hardware devices, INF files for network cards also need all the other information a standard PnP INF file needs. This includes using approved PnP device IDs and having LogConfig sections for non-PnP cards. LogConfig sections are not needed for PCMCIA, EISA, MCA, and PCI devices.


Network Driver Installer Procedure API

A network driver can register a custom NDI procedure. This section describes the programmer's interface for the NDI procedure. If your network driver does not need a custom installer procedure, then you need only supply an NDI-compatible INF file for the driver.


Windows 95 Class Installers and Network Driver Installers

Windows 95 uses Class Installers to install drivers for all hardware classes. The system Plug and Play and the Device Manager send messages to the various class installers to tell them to add, remove or configure specific hardware. The network class installer (Netdi.dll) is provided by Windows 95 to install all network-related hardware and software components. The network installer also allows an individual driver to have its own private installer function--so that when messages are sent from the system to the network class installer, the network class installer can in turn send specific messages to individual NDIs. The messaging interface between the network class installer and the NDIs is called NDI.

You can use a custom NDI procedure to do any or all of the following:

  • Provide custom property sheet pages for configuring your driver
  • Save your custom driver configuration information out to the registry or other system files
  • Perform driver-specific configuration validation that can't be specified in INF files, such as verifying that certain other system drivers or applications are also installed.
  • Parse setup batch script parameters.


Building an NDI Procedure DLL

To build an installer DLL, write a 16-bit Windows DLL. Include the header file Netdi.h and link to the import library Netdi.lib. Netdi.dll is the class installer for all network devices and exports the NDI interface.

Because Windows 95 Setup runs under Windows 3.1, your installer DLL must be a 16-bit DLL and must be Windows 3.1-compatible. Define WINVER as 0x030a before including Windows.h to ensure Windows 3.1 compatibility. It also recommended that you link your DLL to a Windows 3.1 version of Libw.dll so that you don't accidentally import any other Windows 95 function. Note that all necessary Windows 95 registry and property sheet APIs are exported in Setupx.dll as SUfunctionname for use by setup modules; you must use these rather that the actual Windows 95 functions. Even though your DLL must be 3.1 compatible, it must be marked as a 4.0 DLL by specifying /40 on the RC line.

The installer procedure is registered as described in General Driver Information.

Notes:

  • You can call the default message handler, DefNdiProc for any messages you do not want to handle specifically in your code.
  • By default, NETDI assumes that changes in an object do not require the machine to be rebooted. If the object does need a reboot, the Ndi dll for that object must call NdiNeedReboot, described in the following.

Here is an example custom NDI procedure that shows its own settings dialog box, performs specific bindings checks, and has custom installation work. Note that most messages should get forwarded to the default procedure.

#define WINVER 0x030a    // Must be Win 3.1 compatible
#define STRICT            // Recommended for strict type checking
#include <windows.h>    // Windows
#include <netdi.h>        // Network driver installer

RETERR _loadds CALLBACK MyNdiProc
(
    HNDI        hndi,        // NDI handle
    UINT         uMsg,         // NDI message
    WPARAM     wParam,    // 1st message specific parameter
    LPARAM     lParam        // 2nd message specific parameter
)
{
    RETERR        reterr;    // return code

    switch (uMsg)
    {
    case NDI_CREATE:
        // Read in my properties and attach them to this object
        // using NdiSetProperties.
        return MyNdiCreate(hndi);

    case NDI_HASPROPPAGES:
        // Tell the installer that I have my own property pages to add.
        return TRUE;

    case NDI_ADDPROPPAGES:
        // Add my own property sheet page(s) to the properties dialog.
        // My property page dialog proc gets the properties that
        // I read in during NDI_CREATE using NdiGetProperties and
        // saves them back to my properties structure in memory. I
        // write them out during the NDI_INSTALL message.
        return MyNdiAddPropPages(hndi,(LPNDIADDPROPPAGES)lParam);

    case NDI_QUERY_BIND:
        // Check if this binding is ok and pass to the default handler
        if ((reterr = MyNdiQueryBind(hndi,(HNDI)wParam,lParam)) != OK)
            return reterr;
        break;

    case NDI_INSTALL:
        // Write out my properties values and let NDI finish up
        // with the default install.
        if ((reterr = MyNdiInstall(hndi)) != OK)
            return reterr;
        break;

    case NDI_DESTROY:
        // Destroy my properties memory
        return MyNdiDestroy(hndi);

    default:    // call the default handler for all other messages
        break;
    }

    // Let NDI do default handling...
    return DefNdiProc(hndi, uMsg, wParam, lParam);
}

Note The following message must be forwarded to the default handler: NDI_INSTALL, NDI_REMOVE, NDI_QUERY_BIND, and NDI_VALIDATE.


NDI Error Codes

The following error return codes are returned from NDI procedures and messages.

Value | Description
OK | Success
ERR_NDI_ERROR | General NDI error
ERR_NDI_INVALID_HNDI | Invalid NDI handle
ERR_NDI_INVALID_DEVICE_INFO | Invalid DEVICE_INFO pointer
ERR_NDI_INVALID_DRIVER_PROC | Invalid external driver procedure (could not load the DLL or find the exported function name)
ERR_NDI_LOW_MEM | Not enough memory to complete the given action
ERR_NDI_REG_API | Error accessing the registry
ERR_NDI_NOTBOUND | The two NDI objects are not bound or the binding does not exist
ERR_NDI_NO_MATCH | The specified interfaces do not match
ERR_NDI_INVALID_NETCLASS | The network class is invalid
ERR_NDI_CANCEL | The user canceled the dialog or operation


NdiProc

RETERR _loadds CALLBACK NdiProc(hndi, uMsg, wParam, lParam)
HNDI hndi;        // NDI handle
UINT uMsg;        // message
WPARAM wParam;    // first message parameter
LPARAM lParam;    // second message parameter

The NdiProc is a custom DLL-defined callback function that processes messages sent to an NDI object. If an NDI object does not have a custom installer procedure, the default installer procedure will be used.

hndi
Identifies the NDI object.
uMsg
Specifies the message.
wParam
Specifies 16 bits of additional message-dependent information.
lParam
Specifies 32 bits of additional message-dependent information.
  • •The return value is zero (OK) if successful; otherwise it is a nonzero NDI error value.

The NdiProc name is a placeholder for the DLL-defined function name. The actual name must be exported by including it in an EXPORTS statement the DLL's module-definition file.

See Aalso

DefNDIProc


NDI Messages

The following messages can be received by an NDI procedure.

Message | Description
NDI_CREATE | Sent when an NDI object is being created and all internal structures have been initialized.
NDI_DESTROY | Sent when an NDI object is being destroyed.
NDI_VALIDATE | Sent when the system sends DIF_VALIDATECLASSDRIVERS so the NDI procedure can verify its parameters and prompt the user if there is a problem.
NDI_INSTALL | Sent when NETDI is installing the device (when the Install INF section is called)
NDI_HASPROPPAGES | Sent to determine if the NDI procedure has any custom property pages.
NDI_ADDPROPPAGES | Sent to display the properties dialog for the driver.
NDI_REMOVE | Sent when the driver is being removed from the system
NDI_FIRSTTIMESETUP | Sent when the system sends DIF_FIRSTTIMESETUP to allow the NDI procedure to do any upgrade or first-time configuration operations.
NDI_QUERY_BIND | Sent to inform the NDI procedure that a binding is about to be added by NdiBind()
NDI_NOTIFY_BIND | Sent to inform the NDI procedure that a binding has been added by NdiBind().
NDI_NOTIFY_UNBIND | Sent to inform the NDI procedure that a binding has been removed by NdiUnbind().
NDI_SYSTEMCHANGE | Notification that an object was added or removed from the system.
NDI_NDICREATE | Sent before allocating the NDI object.
NDI_NDIDESTROY | Sent before deallocating the NDI object.


NDI_HASPROPPAGES

NDI_ADDPROPPAGES

The NDI_HASPROPPAGES message is sent to determine if their driver installer has any custom property pages.

  • •The driver installer returns TRUE if it has property pages of its own, or FALSE if it does not.


NDI_ADDPROPPAGES

NDI_ADDPROPPAGES
lpnapp = (LPNDIADDPROPPAGES)lParam;    // pointer to ADDPROPPAGES

The NDI_PROPERTIES message is sent to display the properties dialog box for the driver.

lpnapp
Value of lParam. Provides callback function information for adding a property sheet.
  • •A driver installer that processes this message should return OK if pages were successfully added. Otherwise it should return nonzero NDI error value.

The message handler should fill out a PROPSHEETPAGE structure (psp) and pass it back as

(*lpnapp->lpfnAddNdiPropPage)(&psp,lpnapp->lParam,FALSE);

The last Boolean parameter specifies whether you want this page to be the initial page displayed on the property sheet.


NDI_CREATE

NDI_CREATE

The NDI_CREATE message is sent when a new NDI object is being created and all internal structures have been initialized.

flags
Value of lParam. Flags about how Setup is being run:

NDI_CREATE_BATCHMODE - Setup is being run with a setup batch script

NDI_CREATE_NODISPLAY - do not display any UI (Setup is running automated)

hinfBatchFile
Value of wParam. If NDI_CREATE_BATCHMODE is set, wParam is a handle that can be used to process setup batch scripts.

The parameters to NDI_CREATE can be used to process options in a setup batch script. See the Network Setup Batch Scripts section later in this documentation.

  • •An installer procedure that processes this message should return OK to continue creating the object. If the procedure returns nonzero, the NDI object will be destroyed and NdiCreate will return the same return code.


NDI_DESTROY

NDI_DESTROY

The NDI_DESTROY message is sent to an NDI object when it is being destroyed.

This message has no parameters.

  • •An installer procedure should return OK if it processes this message.


NDI_FIRSTTIMESETUP

NDI_FIRSTTIMESETP
dwSetupFlags = (DWORD)lParam;    // Setup flags

The NDI_FIRSTTIMESETUP message is sent whenever the system sends the DIF_FIRSTTIMESETUP message to the network class installer. This allows the driver to perform any special upgrade or first-time configuration operations.

dwSetupFlags
The current setup flags from the SUGetSetSetupFlags. See Setupx.h.
  • •The return value is zero (OK) if successful; otherwise it is a nonzero NDI error value.


NDI_INSTALL

NDI_INSTALL
dwFlags = (DWORD)lParam;    // NDI flags

The NDI_INSTALL message is sent when the NDI manager needs to copy the NDI files and perform registry and system file modifications for the driver.

dwFlags
The current NDI object flags. See NdiGetFlags.
Value | Meaning
NDIF_ADDED | The driver has been added.
NDIF_REMOVED | The driver has been removed.
NDI_MODIFIED _BINDINGS | The driver's bindings have been changed.
NDI_MODIFIED _PROPERTIES | The driver's properties have been changed.

  • •The return value is zero (OK) if successful; otherwise it is a nonzero NDI error value.

A driver installer that handles this message must also call NdiDefProc to perform common installation. The default handler calls DiInstallDevice and performs other necessary registry updates.


NDI_REMOVE

NDI_REMOVE

This message is sent when a driver is being removed from the system.

This message has no parameters.

  • •A driver procedure that processes this message should return OK.

A driver installer that handles this message must also call NdiDefProc to perform common driver removal. The default handler calls DiRemoveDevice and performs other necessary updates.


NDI_NOTIFY_BIND

NDI_NOTIFY_BIND
hndiBound = (HNDI)wParam;      // handle of NDI object
wBindType = LOWORD(lParam);    // type of binding

The NDI manager sends NDI_NOTIFY_BIND to inform the driver installer that an upper or lower binding has been added by the NdiBind function. The NDI_NOTIFY_BIND message is sent after NDI_QUERY_BIND and before NdiBind returns.

hndiBound
Value of wParam. Identifies the NDI object that was bound to this NDI object.
wBindType
Value of the low-order word of lParam. Specifies which edge of the NDI that hndiBound was added to.
Value | Meaning
NDIBIND_UPPER | Specifies that hndiBound was added to the upper bindings of the given NDI object.
NDIBIND_LOWER | Specifies that hndiBound was added to the lower bindings of the given NDI object.

  • •A driver procedure that processes this message should return OK.


NDI_NOTIFY_UNBIND

NDI_NOTIFY_UNBIND
hndiUnbound = (HNDI)wParam;    // handle of NDI object
wBindType = LOWORD(lParam);    // type of binding

The NDI manager sends NDI_NOTIFY_UNBIND to inform the driver installer that an upper or lower binding has been removed by NdiUnbind. The NDI_NOTIFY_UNBIND message is sent before NdiUnbind returns.

hndiUnbound
Value of wParam. Identifies the NDI object that was unbound from this NDI object.
wBindType
Value of the low-order word of lParam. Specifies which edge of the NDI that hndiUnbound was removed from.
Value | Meaning
NDIBIND_UPPER | Specifies that hndiUnbound was removed from the upper bindings of the given NDI object.
NDIBIND_LOWER | Specifies that hndiUnbound was removed from the lower bindings of the given NDI object.

  • •A driver procedure that processes this message should return OK.


NDI_QUERY_BIND

NDI_QUERY_BIND
hndiBind = (HNDI)wParam;       // handle of NDI object
wBindType = LOWORD(lParam);    // type of binding

The NDI manager sends NDI_QUERY_BIND to inform the driver installer that an upper or lower binding is about to be added by NdiBind. The NDI_QUERY_BIND is sent before NdiBind returns.

hndiBind
Value of wParam. Identifies the NDI object that is to be unbound from this NDI object.
wBindType
Value of the low-order word of lParam. Specifies which edge of the NDI that hndiBind is to be added to.
Value | Meaning
NDIBIND_UPPER | Specifies that the given NDI object should validate that hndiBind can be added to its upper bindings.
NDIBIND_LOWER | Specifies that the given NDI object should validate that hndiBind can be added to its lower bindings.

  • •A driver procedure that processes this message should return OK to complete the binding. Otherwise, it should present a warning message and return a nonzero NDI_ERROR result.

A driver installer that handles this message must also call NdiDefProc to perform standard bindings checking.


NDI_VALIDATE

NDI_VALIDATE
hwndParent = (HWND)wParam;    // handle of parent dialog window

The NDI_VALIDATE message is sent when Setup sends the DIF_VALIDATECLASSDRIVERS to the network class installers. The driver installer should check that all properties are correctly set or have valid default values; if a required parameter is not known and cannot be defaulted, then the installer should prompt the user for the value.

This message has no parameters.

  • •The return value is zero (OK) if successful; otherwise it is a nonzero NDI error value. If the user is prompted for a value and selects cancel, it should return ERR_NDI_CANCEL.

A driver installer may call NdiProperties during this message. A driver installer that handles this message must also call NdiDefProc to perform standard validation.


NDI_SYSTEMCHANGE

NDI_SYSTEMCHANGE
uTypeOfChange = (UINT)wParam;    // type of change made.

The NDI_SYSTEMCHANGE message is sent whenever an object was added or removed from the system. The NDI procedure should validate its settings and bindings.

uTypeOfChange
Indicates the type of change that has occurred. It must be one of the following values:

NDISYSTEMCHANGE_ADD - an object was added to the system.

NDISYSTEMCHANGE_REMOVE - an object was removed from the system.

  • •The return value is zero (OK) if successful; otherwise it is a nonzero NDI error value.


NDI_NDICREATE

NDI_NDICREATE

The NDI_NDICREATE message is sent when NETDI is about to allocate the object.

This message has no parameters.

  • •The return value is zero (OK) if successful; otherwise it is a nonzero NDI error value.


NDI_NDIDESTROY

NDI_NDIDESTROY

The NDI_NDIDESTROY message is sent when NETDI is about to deallocate the object.

This message has no parameters.

  • •The return value is zero (OK) if successful; otherwise it is a nonzero NDI error value.


NDI API

The NDI procedure can call the following functions in NETDI.

API | Description
NdiGetFirst() | Returns a handle to the first NDI object in the system.
NdiGetNext() | Returns the next NDI object list after a given NDI object.
NdiFindNdi() | Enumerates NDI objects in the system.
NdiIsNdi() | Determines whether the given NDI handle is valid.
NdiCallInstaller() | Calls the NDI procedure for a given object.
CreateNdiFromDeviceId() | Installs the specified device (replaces NdiAddNewDriver())
NdiValidate() | Sends the given object an NDI_VALIDATE message.
NdiInstall() | Installs the NDI object's driver.
NdiRemove() | Removes the NDI object's driver.
NdiProperties() | Displays the properties for an NDI object.
NdiBind() | Binds two NDI objects.
NdiUnbind() | Removes the binding between two NDI objects.
NdiIsBound() | Determines if two NDI objects are bound.
NdiGetBinding() | Finds an NDI object through the binding of a given NDI object.
NdiGetText() | Returns the driver description for an NDI object.
NdiSetText() | Sets the driver description for an NDI object.
NdiGetDeviceInfo() | Returns a pointer to the DEVICE_INFO structure for the given object.
NdiGetClass() | Returns the network class number for an NDI object.
NdiGetProperties() | Returns the properties data for a particular NDI object.
NdiSetProperties() | Sets the properties data for a particular NDI object.
NdiGetOwnerWindow() | Returns the window handle of the owner of the NDI window.
NdiGetDeviceId() | Returns the PnP device ID for an NDI object.
NdiCompareInterface() | Compares two interface lists.
NdiGetInterface() | Returns an interface list for the object.
NdiAddInterface() | Adds an interface to the interface list.
NdiRemoveInterface() | Removes an interface from the interface list.
NdiRegOpenKey() | Equivalent to RegOpenKey().
NdiRegCreateKey() | Equivalent to RegCreateKey().
NdiRegCloseKey() | Equivalent to RegCloseKey().
NdiRegQueryValue() | Equivalent to RegQueryValue().
NdiRegSetValue() | Equivalent to RegSetValue().
NdiRegDeleteValue() | Equivalent to RegDeleteValue().
NdiSystemChange() | Notifies other components that a component has been added or removed from the system.
NdiQueryBind() | Queries NETDI to determine if the NDI object can bind to another.
NdiGetFlags() | Gets the flags for an NDI object.
NdiNeedReboot() | Tells NETDI that the user has made changes that require a reboot.


CreateNdiFromDeviceId

RETERR
 CreateNdiFromDeviceId(lpszId)
LPCSTR lpszId;    // address of the device ID to install

The CreateNdiFromDeviceId function creates an NDI object and installs the given device. To install NetBEUI, for example, the call would be: CreateNdiFromDeviceId(NETBEUI);

lpszId
Points to a string containing the device ID for the device to install.
  • •The return value is zero (OK) if successful; otherwise it is a nonzero NDI error value. If no compatible driver is found, it returns ERR_NDI_INVALID_HNDI.

This function causes a NDI_CREATE message to be sent to the newly created NDI object.


NdiGetFirst

HNDI NdiGetFirst()

The NdiGetFirst function returns a handle to the first NDI object in the system.

This function has no parameters.

  • •The return value is the NDI object handle if the function is successful. Otherwise it is NULL.


NdiGetNext

HNDI NdiGetNext(hndi)
HNDI hndi;    // NDI handle

The NdiGetNext function returns the next NDI object list after the given NDI object.

hndi
Identifies the original NDI object.
  • •The return value is the NDI object handle if the function is successful. Otherwise it is NULL.


NdiIsNdi

RETERR NdiIsNdi(hndi)
HNDI hndi;    // NDI handle

The NdiIsNDI procedure determines whether the given NDI handle is valid.

hndi
Identifies an NDI object.
  • •The return value is zero (OK) if the NDI handle is valid. Otherwise it is ERR_NDI_INVALID_HNDI.


NdiCallInstaller

RETERR
 NdiCallInstaller(hndi,uMsg,wParam,lParam)
HNDI hndi;        // NDI handle
UINT uMsg;        // message
WPARAM wParam;    // first message parameter
LPARAM lParam;    // second message parameter

The NdiCallInstaller function calls the installer function for the given NDI object.

hndi
Identifies the NDI object.
uMsg
Specifies the message.
wParam
Specifies 16 bits of additional message-dependent information.
lParam
Specifies 32 bits of additional message-dependent information.
  • •The return value is zero (OK) if successful; otherwise it is a nonzero NDI error value.


NdiFindNdi

HNDI NdiFindNdi(ndiRelation, wNetClass, lpszDeviceId)
HNDI ndiRelation;       // NDI handle
WORD wNetClass;         // network class
LPCSTR lpszDeviceID;    // pointer to string

The NdiFindNDI procedure used for finding or enumerating the NDI objects in the system. For example, you can enumerate all drivers of a certain class, or look up a specific device ID.

ndiRelation
Identifies an NDI object. Pass NULL to search from all NDI objects. Pass in the return value from a previous call to NdiFindNdi to find the next object that matches your criteria.
wNetClass
Specifies the network object class to look for. If zero, all classes match.
Value | Meaning
NDI_CLASS_NET | Network adapter (Net)
NDI_CLASS_TRANS | Network transport (NetTrans)
NDI_CLASS_CLIENT | Network client (NetClient)
NDI_CLASS_SERVICE | Network service (NetService)

lpszDeviceID
Points to a buffer that contains the device ID to match. If NULL, all device IDs match.
  • •The return value is the NDI handle that was found. If none was found, the return value is NULL.

Note that when searching for device IDs, more that one instance of that device ID may be installed, so you will want to call NdiFindNdi successively.


NdiInstall

RETERR
 NdiInstall(hndi)
HNDI hndi;    // NDI handle

The NdiInstall function installs the NDI object by copying the NDI files and performing registry and system file modifications for the driver.

hndi
Identifies the NDI object.
  • •The return value is zero (OK) if successful; otherwise it is a nonzero NDI error value.

This function causes the NDI_INSTALL message to be sent to the given NDI object.


NdiProperties

RETERR
 NdiProperties(hndi, hwndParent)
HNDI hndi;          // NDI handle
HWND hwndParent;    // window handle

The NdiProperties function displays the properties dialog box for the driver.

hndi
Identifies the NDI object.
hwndParent
Identifies the parent window for the properties dialog box.
  • •The return value is zero (OK) if successful; otherwise it is a nonzero NDI error value. Returns ERR_NDI_CANCEL if the user cancels the properties dialog box.

This function causes the NDI_ADDPROPPAGES message to be sent to the given NDI object.


NdiRemove

RETERR
 NdiRemove(hndi)
HNDI hndi;    // NDI handle

The NdiRemove function removes the NDI driver from the system.

hndi
Identifies the NDI object.
  • •The return value is zero (OK) if successful; otherwise it is a nonzero NDI error value.

This function causes the NDI_REMOVE message to be sent to the given NDI object.


NdiGetText

RETERR
 NdiGetText(hndi,lpszText,cbText)
HNDI hndi;         // NDI handle
LPSTR lpszText;    // address of buffer
UINT cbText        // size of buffer

The NdiGetText function returns the driver description text for the NDI in lpszText.

hndi
Identifies the NDI object.
lpszText
Points to the buffer to receive the text.
cbText
Specifies the maximum number of bytes to be copied, including the terminating null character.
  • •The return value is zero (OK) if successful; otherwise it is a nonzero NDI error value.


NdiSetText

RETERR
 NdiSetText(hndi,lpszText)
HNDI hndi;          // NDI handle
LPCSTR lpszText;    // address of buffer

The NdiSetText function sets the text associated with the driver.

hndi
Identifies the NDI object.lpszText Points to a null-terminated string that is the new NDI text.
  • •The value is NDI_ERR_LOW_MEM if insufficient memory is available to set the text in the NDI. Otherwise it is zero (OK).

A driver installer would want to call NdiSetText to distinguish two different instances of the same driver. For example, the TCP/IP transport driver installer changes the text whenever the IP address for the driver changes using the device description from the DEVICE_INFO and the current IP address setting. In this way, the user can distinguish between the different TCP/IP transport instances.


NdiValidate

RETERR
 NdiValidate(hndi, hwndParent)
HNDI hndi;
HWND hwndParent;

The NdiValidate function calls the given object with an NDI_VALIDATE message.

hndi
Identifies the object to send NDI_VALIDATE to
hwndParent
Identifies the parent window

This function is supported only for Net class objects.

  • •The return value is zero (OK) if successful; otherwise it is a nonzero NDI error value.


NdiBind

RETERR
 NdiBind(hndiLower, hndiUpper)
HNDI hndiLower;    // NDI handle
HNDI hndiUpper;    // NDI handle

The NdiBind function binds the lower NDI object to the upper NDI object. The lower NDI object must have a lower network class number than the upper NDI object (see NdiGetNetClass). The NDI_QUERY_BIND message is sent to both the lower and upper NDI object to validate the binding.

hndiLower
Identifies the lower NDI object to be bound to hndiUpper.
hndiUpper
Identifies the upper NDI object to be bound with hndiLower.
  • •The return value is zero (OK) if successful; otherwise it is a nonzero NDI error value.


NdiIsBound

RETERR
 NdiIsBound(hndiLower, hndiUpper)
HNDI hndiLower;    // NDI handle
HNDI hndiUpper;    // NDI handle

The NdiIsBound function determines if the two given NDI objects are bound.

hndiLower
Identifies the lower NDI object.
hndiUpper
Identifies the upper NDI object.
  • •The return value is zero (OK) if the two are bound; otherwise it is a nonzero NDI error value.

Note that (NdiIsBound(lower,upper) == OK) implies that (NdiIsBound(upper,lower) != OK).


NdiUnbind

RETERR
 NdiUnbind(hndiLower, hndiUpper)
HNDI hndiLower;    // NDI handle
HNDI hndiUpper;    // NDI handle

The NdiUnbind function unbinds the lower NDI object from the upper NDI object.

hndiLower
Identifies the lower NDI object to be bound to hndiUpper.
hndiUpper
Identifies the upper NDI object to be bound with hndiLower.
  • •The return value is zero (OK) if successful; otherwise it is a nonzero NDI error value. It is ERR_NDI_NOTBOUND if the two were not already bound.


NdiGetBinding

RETERR
 NdiGetBinding(hndi, lphndi, uBindType)
HNDI hndi;           // NDI handle
HNDI FAR* lphndi;    // address of NDI handle
UINT uBindType;      // binding type

The NdiGetBinding function retrieves the handle of an NDI object that has the specified relationship to the given NDI object.

hndi
Identifies the NDI object.
lphndi
Points to an NDI object handle. At entry the handle contains the current binding; at exit it contains the resultant binding.
uBindType
Specifies the binding relationship.
Value | Meaning
NDIBIND_UPPER_FIRST | Return the first upper binding.
NDIBIND_UPPER_NEXT | Return the next upper binding after *lphndi.
NDIBIND_LOWER_FIRST | Return the first lower binding.
NDIBIND_LOWER_NEXT | Return the next lower binding after *lphndi.

  • •The return value is zero (OK) if successful and the requested binding exists; otherwise it is a nonzero NDI error value.


NdiQueryBind

RETERR
 CALLBACK NdiQueryBind(hndiLower, hndiUpper, uBindType)
HNDI hndiLower    // handle to lower object
HNDI hndiUpper    // handle to upper object
UINT uBindType    // type of binding

The NdiQueryBind function is used to query NETDI to determine if a binding can occur between the two given NDI objects.

hndiLower
A handle to the lower object in the binding
hndiUpper
A handle to the upper object in the binding
uBindType
The type of binding to perform.
  • •The return value is zero (OK) if the message is not handled or is handled successfully. The return value is always an NDI-defined error value.


NdiGetClass

RETERR
 NdiGetClass(hndi, lpwNetClass)
HNDI hndi;             // NDI handle
LPWORD lpwNetClass;    // address of net class

The NdiGetClass function returns the network class number in lpwNetClass.

lpwNetClass
Points to a WORD to receive the network class number.
Value | Meaning
NDI_CLASS_NET | Network adapter (Net)
NDI_CLASS_TRANS | Network transport (NetTrans)
NDI_CLASS_CLIENT | Network client (NetClient)
NDI_CLASS_SERVICE | Network service (NetService)

  • •The return value is zero (OK) if successful; otherwise it is a nonzero NDI error value.


NdiGetDeviceID

RETERR
 NdiGetDeviceID(hndi,lpszDeviceID,cbDeviceID)
HNDI hndi;             // NDI handle
LPSTR lpszDeviceID;    // address of buffer for device ID
UINT cbDeviceID;       // number of bytes to copy

The NdiGetDeviceID function copies the Plug and Play device ID for the given NDI object to lpszDeviceID.

hndi
Identifies the NDI object.
lpszDeviceID
Points to the buffer that is to receive the text.
cbDeviceID
Specifies the maximum number of bytes to be copied, including the terminating null character.
  • •The return value is zero (OK) if successful; otherwise it is a nonzero NDI error value.


NdiGetDeviceInfo

RETERR
 NdiGetDeviceInfo(hndi, lplpdi);
HNDI hndi;                 // NDI handle
LPLPDEVICE_INFO lplpdi;    // address of pointer to structure

The NdiGetDeviceInfo function retrieves the address of the DEVICE_INFO structure associated with the NDI object.

hndi
Identifies the NDI object.
lplpdi
Points to a far pointer to receive the address of the DEVICE_INFO structure.
  • •The return value is zero (OK) if successful; otherwise it is a nonzero NDI error value.


NdiGetFlags

RETERR
 CALLBACK NdiGetFlags(HNDI hndi, LPDWORD lpdwFlags)
HNDI hndi            // handle to NDI object to query
LPDWORD lpdwFlags    // a point to the buffer to return the flags

The NdiGetFlags function is used to get the flags of a particular NDI object.

hndi
A handle to the object to query
lpdwFlags
The address of a buffer to hold the returned flags. These flags are:
Flag | Description
NDIF_ADDED | The object has just been added.
NDIF_REMOVED | The object has just been removed.
NDIF_MODIFIED_BINDINGS | The bindings of the object have just been changed.
NDIF_MODIFIED_PROPERTIES | The properties of the object have just been changed.
NDIF_DEFAULT | This object is the default object for its class.
NDIF_INVISIBLE | This object does not appear in the Configuration page UI.
NDIF_HAS_PARAMS | This object has an Advanced properties tab.

  • •The return value is zero (OK) if the message is not handled or is handled successfully. The return value is always an NDI-defined error value.


NdiGetOwnerWindow

RETERR
 NdiGetOwnerWindow(hndi, lphwnd)
HNDI hndi;           // NDI handle
HWND FAR* lphwnd;    // address of window handle

The NdiGetOwnerWindow function returns the window handle of owner of the NDI in lphwnd.

lphwnd
Points to an HWND to receive the owner window handle.
  • •The return value is zero (OK) if successful; otherwise it is a nonzero NDI error value.


NdiGetProperties

RETERR
 NdiGetProperties(hndi,lplpvProperties)
HNDI hndi;                    // NDI handle
LPVOID FAR* lpvProperties;    // address of properties pointer

The NdiGetProperties function returns the properties data associated with the given NDI object.

lplpvProperties
Points to an LPVOID pointer to receive the properties pointer.
  • •The return value is zero (OK) if successful; otherwise it is a nonzero NDI error value.


NdiSetProperties

RETERR NdiSetProperties(hndi,lpvProperties)
HNDI hndi;               // NDI handle
LPVOID lpvProperties;    // far pointer to properties data

The NdiSetProperties function sets the properties data associated with the given NDI object.

lpvProperties
An LPVOID value to associate with the NDI object.
  • •The return value is zero (OK) if successful; otherwise it is a nonzero NDI error value.


NdiCompareInterface

RETERR NdiCompareInterface(hndi, uRelation, hndi2, uRelation2)
HNDI hndi;
UINT uRelation;
HNDI hndi2;
UINT uRelation2;

The NdiCompareInterface compares two interface lists. An interface must exist in both lists for NdiCompareInterface to be successful.

hndi
Identifies the first object
uRelation
Identifies which type of interface to compare
hndi2
Identifies the second object
uRelation2
Identifies which type of interface to compare

uRelation and uRelation2 must be one of the following:

NDI_EDGE_UPPER NDI_EDGE_LOWER

NDI_EDGE_UPPERRANGE NDI_EDGE_LOWERRANGE

NDI_EDGE_REQUIRELOWER NDI_EDGE_REQUIREANY NDI_EDGE_EXCLUDELOWER NDI_EDGE_EXCLUDEANY

NDI_COMPATIBLE_REQUIREDUPPER NDI_COMPATIBLE_REQUIREDLOWER

NDI_COMPATIBLE_REQUIREDALL NDI_COMPATIBLE_EXCLUDEUPPER

NDI_COMPATIBLE_EXCLUDELOWER NDI_COMPATIBLE_EXCLUDEALL

  • •NdiCompareInteface returns OK if an interface exists in uRelation that is in uRelation2. Otherwise, ERR_NDI_NO_MATCH is returned.


NdiGetInterface

RETERR NdiGetInterface(hndi, uRelation, index, lpszRetInterface, cbRetInterface)
HNDI  hndi;
UINT  uRelation;
UINT  index;
LPSTR lpszRetInterface;
UINT  cbRetInterface;

The NdiGetInterface function places an item in a interface list into a return string buffer.

hndi
Indicates which object to use.
uRelation
Indicates what type of interface to get.
index
Indicates which interface will be returned. Zero corresponds to the first interface, one to the second and so on.
lpszRetInterface
The address of the buffer which holds the interface asked for by index.
cbRetInterface
The size of the lpszRetInterface buffer.
  • •If the index points to within a interface list, then OK is returned. If the index points outside the interface list, ERR_NDI_NO_MATCH is returned.


NdiAddInterface

RETERR NdiAddInterface(hndi, uRelation, lpsz)
HNDI hndi;
UINT uRelation;
LPCSTR lpsz;

NdiAddInterface adds an interface to a interface list of type uRelation.

hndi
Indicates which object to add to.
uRelation
Indicates what type of interface to add.
lpsz
The interface to be added.
  • •Returns OK if successful.


NdiRemoveInterface

RETERR NdiRemoveInterface(hndi, uRelation, lpsz)
HNDI hndi;
UINT uRelation;
LPCSTR lpsz;

NdiRemoveInterface removes an interface from an interface list of type uRelation.

hndi
Indicates which object to modify.
uRelation
Indicates what type of interface modify.
lpsz
The interface to be removed.
  • •If the interface is successfully removed from the interface list, OK is returned. ERR_NDI_NO_MATCH is returned if the interface to be removed was not found in the list.


NdiRegOpenKey

RETERR NdiRegOpenKey(HNDI hndi, LPCSTR lpszSubKey, LPHKEY lphk)
HNDI hndi;            // NDI handle
LPCSTR lpszSubKey;    // address of buffer
LPHKEY lphk;          // address of key handle

The NdiRegOpenKey function returns a key to the NDI object's registry section. If lpszSubKey is specified, then it returns a subkey under the NDI object's registry section. This function does not create the subkey if it does not already exist.

hndi
Identifies the NDI object.
lpszSubKey
Points to a buffer that contains the null-terminated subkey string. May be NULL or empty.
lphk
Points to an HKEY handle to receive the opened registry key.
  • •The return value is zero (OK) if successful; otherwise it is ERR_NDI_REG_API.

The registry key opened if lpszSubKey is NULL is the following:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Class\
    {network class name}\{driver number}\

where network class name is Net, NetTrans, NetClient, NetServer or NetService; and driver number is the driver number assigned by the Device Manager. The driver number has no meaning other than to distinguish it from other drivers of the same class.

NdiRegOpenKey calls SURegOpenKey ensuring compatibility during setup from within Windows 3.1.


NdiRegCreateKey

RETERR NdiRegCreateKey(HNDI hndi, LPCSTR lpszSubKey, LPHKEY lphk)
HNDI hndi;            // NDI handle
LPCSTR lpszSubKey;    // address of buffer
LPHKEY lphk;          // address of key handle

The NdiRegOpenKey function returns a key to the NDI object's registry section. If lpszSubKey is specified, then it returns a subkey under the NDI object's registry section. This function creates the subkey if it does not already exist.

hndi
Identifies the NDI object.
lpszSubKey
Points to a buffer that contains the null-terminated subkey string. May be NULL or empty.
lphk
Points to an HKEY handle to receive the opened registry key.
  • •The return value is zero (OK) if successful; otherwise it is ERR_NDI_REG_API.

The registry key opened if lpszSubKey is NULL is the following:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Class\
    {network class name}\{driver number}\

where network class name is Net, NetTrans, NetClient, NetServer, or NetService; and driver number is the driver number assigned by the Device Manager. The driver number has no meaning other than to distinguish it from other drivers of the same class.

NdiRegOpenKey calls SURegCreateKey ensuring compatibility during setup from within Windows 3.1.


NdiRegCloseKey

RETERR NdiRegCloseKey(hkey)
HKEY hkey;    // registry key

The NdiRegCloseKey function closes a key opened with NdiRegOpenKey.

hkey
Identifies an opened registry key.
  • •The return value is zero (OK) if successful; otherwise it is ERR_NDI_REG_API.


NdiRegQueryValue

RETERR NdiRegQueryValue(hndi, lpszSubKey, lpszValueName, lpValue, cbValue)
HNDI hndi;                // NDI handle
LPCSTR lpszSubKey;        // address of subkey buffer
LPCSTR lpszValueName;     // address of value name buffer
LPSTR lpValue;            // address of return value buffer
DWORD cbValue;            // number of bytes in return buffer

The NdiRegQueryValue function opens a registry subkey for the NDI object and returns the specified value and closes the key.

hndi
Identifies the NDI object.
lpszSubKey
Points to a buffer that contains the null-terminated subkey string. May be NULL or empty.
lpszValueName
Points to a buffer that contains the null-terminated value name string. May be NULL or empty.
lpValue
Points to a buffer to receive the registry value.
cbValue
Specifies the maximum number of bytes to be copied into lpValue, including the terminating the null character if it is a string value.
  • •The return value is zero (OK) if successful; otherwise it is ERR_NDI_REG_API.


NdiRegSetValue

RETERR NdiRegSetValue(hndi, lpszSubKey, lpszValueName, dwType, lpValue, cbValue)
HNDI hndi;               // NDI handle
LPCSTR lpszSubKey;       // address of subkey buffer
LPCSTR lpszValueName;    // address of value name buffer
DWORD dwType;            // value type
LPCSTR lpValue;          // address of value buffer
DWORD cbValue;           // number of bytes in value buffer

The NdiRegSetValue function sets a registry value under the given NDI object's registry section.

hndi
Identifies the NDI object.
lpszSubKey
Points to a buffer that contains the null-terminated subkey. May be NULL or empty.
lpszValueName
Points to a buffer that contains the null-terminated value name. May be NULL or empty.
dwType
REG_SZ for string values, REG_BINARY for binary values.
lpValue
Points to a buffer that contains the value to set.
cbValue
Specifies the number of bytes in lpValue. If dwType is REG_SZ, then cbValue is ignored.
  • •The return value is zero (OK) if successful; otherwise it is ERR_NDI_REG_API.


NdiSystemChange

RETERR CALLBACK NdiSystemChange(uTypeOfChange)
UINT uTypeOfChange;    // indicates the type of change

The NdiSystemChange function is used to post an NDI_SYSTEMCHANGE message to other NDI procedures.

uTypeOfChange
Indicates the type of change that has occurred. It must be one of the following values:

NDISYSTEMCHANGE_ADD - an object was added to the system.

NDISYSTEMCHANGE_REMOVE - an object was removed from the system.

  • •The return value is zero (OK) if the message is not handled or is handled successfully. The return value is always an NDI-defined error value.


NdiNeedReboot

RETERR NdiNeedReboot(hndi, wRebootType)
HNDI hndi;            // handle to the object that requires a reboot
DWORD wRebootType;    // indicates whether a reboot or restart is needed

By default, NETDI assumes that any changes made to a component do not need a reboot. The NdiNeedReboot function informs NETDI that the given object requires a reboot. If this function is called, users will be prompted to reboot the computer when they close the Network Control Panel.

hndi
A handle to the object that requires a reboot
wRebootType
Indicates the type of reboot that is required. It must be one of the following values:

DI_NEEDRESTART - the Windows protected mode components are restarted

DI_NEEDREBOOT - the computer will be rebooted

  • •The return value is zero (OK) if the message is not handled or is handled successfully. The return value is always an NDI-defined error value.


DefNdiProc

RETERR CALLBACK DefNdiProc(hndi, uMsg, wParam, lParam)
HNDI hndi;        // NDI handle
UINT uMsg;        // message
WPARAM wParam;    // first message parameter
LPARAM lParam;    // second message parameter

The DefNdiProc is the default NDI procedure that processes messages sent to an NDI object. If an NDI object does not have a custom installer procedure, the default installer procedure will be used. If an NDI object has a custom NDI procedure, it should pass messages to DefNdiProc for default handling.

hndi
Identifies the NDI object.
uMsg
Specifies the message.
wParam
Specifies 16 bits of additional message-dependent information.
lParam
Specifies 32 bits of additional message-dependent information.
  • •The return value is zero (OK) if the message is not handled or is handled successfully. The return value is always an NDI-defined error value.


Network Setup Batch Scripts

The Windows® 95 Setup program can be fully automated using batch scripts. These scripts, which are very similar to INF files, specify what components to install and the parameters for those components. For a description of the standard setup batch script parameters, see the Windows 95 Resource Kit.

Installer DLL developers can add their own parameters to setup batch scripts using an NDI procedure. The function is passed a handle script that they can use to parse the setup script.

When Setup runs, it copies any setup script the user gave to Msbatch.inf in their c:\WINDOWS\INF directory. Whenever Setup or the Network Control Panel runs, it reads parameters out of this setup script. The NDI procedure is passed a handle to this setup script in the NDI_CREATE message. The function can call IpGetProfileString() to read parameters from the INF file.

#include <netdi.h>      // also includes setupx.h
RETERR _loadds WINAPI TcpNdiProc(HNDI ndi, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    RETERR      reterr;
    char        szBuf[16];
    switch (uMsg) {

    case NDI_CREATE:
        if ( lParam & NDI_CREATE_BATCHMODE ) {
                // Read "MyParam=<string>" from "MyComponent" section
                // in the batch inf file.
                reterr = IpGetProfileString( (HINF) wParam,
                                "MyComponent",
                                "MyParam",
                                szBuf,
                                sizeof(szBuf) );
        }
        else {
                // read from the registry or ini file ...
        }

    break;

     // .... other messages ....

      default:
    CallDefProc:
        return DefNdiProc(ndi,uMsg,wParam,lParam);
    }
}


IpGetProfileString

RETERR  WINAPI IpGetProfileString(HINF hInf, LPCSTR lpszSec,
    LPCSTR lpszKey, LPSTR lpszBuf, int iBufSize)
HINF hInf;       // handle to the setup script
LPCSTR lpszSec;  // section name
LPCSTR lpszKey;  // key name
LPSTR lpszBuf;   // buffer to receive the string
int iBufSize;    // size of the lpszBuf buffer

IpGetProfileString is a SETUPX call used to read parameters out of a setup script. It functions very much like the standard Windows API GetPrivateProfileString.

hInf
The handle to the setup script (passed in as a parameter to the NDI_CREATE message).
lpszSec
The address of a string containing the section name in the setup script.
lpszKey
The address of a string containing the name of the parameter to read from the setup.
lpszBuf
The address of a buffer to receive the value of the parameter.
iBuffSize
The size of the buffer pointed to by lpszBuf.
  • •The return value is zero (OK) if the message is not handled or is handled successfully. The return value is always an NDI-defined error value.


Sample INF Files

For examples of INF files for each of the four network driver classes, see the INF files that are installed in the Inf subdirectory of the Windows directory. The four INF files are:

Netcli.inf | Network clients (class NetClient)
Nettrans.inf | Network protocols (class NetTrans)
Netservr.inf | Network services (class NetService)
Net*.inf | Network cards (class Net)

Note: these INF files contain a section, [ClassInstall], that is not required by other INF files. This section is used during setup to register the four classes with PnP.


Printer INF File Extensions

Windows® 95 supplies a default port monitor, language monitor, and print processor. The topic Spooler Components and IHV Development Opportunities in gives the reasons you may want to develop one or more of these components for your device and package each component as a separate DLL. Once you have developed such a DLL, there are two methods of installing the component so it will be part of the spooler's environment:

  • Use Win32 APIs such as AddPrintProcessor and AddMonitor.
  • Use the printer-specific extensions to INF files provided by the Windows 95 printer installer.

Although this part of the Windows 95 DDK is about the print spooler subsystem (of which print processors, language monitors, and port monitors are part), it is not possible to discuss vendor-provided monitor and print processor installation without discussing Windows 95 printer installation in general and printer driver installation in particular. There are several ways to install a printer under Windows 95:

  • A printer which is not locally attached may be selected from the Explorer and have support (drivers) installed. For more information, see .
  • Any Win32 application can call AddPrinter, AddPrinterDriver, AddPrintProcessor, and AddMonitor and other such functions to install printer support explicitly. Under Windows 95, applications should not attempt to install printer support by writing directly to WIN.INI. For more information, see .
  • The printer may be detected via Plug and Play if it is locally attached and supports the IEEE 1284 specification for supplying a device ID value. For more information, see .
  • Printer support (drivers) may be manually installed using the icon labeled Add Printer in the Printers folder. For more information, see and .


Point and Print Installation of Printers Over a Network

Point and Print installation of printers over a network is a possibility with Windows 95. For printers being shared by other computers, Windows 95 provides the ability to fully install printer drivers from the print server directly, with correct initial driver settings, without requiring the client machine to provide diskettes containing printer driver files.

In order to do this, a Windows 95 Network Print Provider must be installed on the client machines.

Windows 95 supports Point and Print installation for the following Server/Client configurations:

  • Windows 95 server and Windows 95 clients.
  • Netware 3.x and 4.x server and Windows 95 clients.


Windows 95 Server and Windows 95 Client Installation

On the server, install the Windows 95 printer driver and share the printer.

On a client, a user can use either of two methods, which are summarized in the following table:

Windows 95 User Interface Component to Use | User Action
Use the Windows Explorer to navigate the network. | When the shared printer is found, either double-click on the printer icon; or drag the printer icon into the Printer folder or on to the Desktop; or right-click on the printer icon and select Install from the menu. Using any one of these methods will complete the installation.
Use the Add Printer icon. | Either provide the name of the network path to the printer (its queue name) or use the Browse control from within the Add Printer dialog box to select the printer.


Netware 3.x and 4.x Server and Windows 95 Client Installation

The server may either be a Windows 95 machine running the Netware compatible server or it may be a Novell Netware server.

In the case of a Windows 95 machine running the Netware compatible server, the procedure is the same as that described in the section Windows 95 Server and Windows 95 Client Installation.

If the server is a Novell Netware server, you will have to use a Windows 95 machine to log on to the Novell Netware server with privileges to administer the Novell server and then use the following procedure:

  1. On the Windows 95 machine, use the Explorer to find the Netware server.
  2. Double-click on the Netware server icon to see the Netware print queue.
  3. Right-click on the print queue and then select Configure from the Point and Print Setup menu.
  4. Follow the prompts through the steps required to configure the server to support point and print printer installation from the server for other Windows 95 Netware clients. It is important to set the driver path before you select the model.

Installation from Windows 95 client machines running Windows 95 Netware client services is just as described in the preceding section, Windows 95 Server and Windows 95 Client Installation.


Using the API Installation Method

Under Windows 3.1, the only way other than using the Control Panel to install a printer driver was for an application to modify WIN.INI directly. But under Windows 95, the printer subsystem does not get any information about an installed printer driver from WIN.INI. Windows 95 applications wishing to install their own printer driver should either:

  • Call the necessary Win32 printing APIs (AddPrinter, AddPrinterDriver, AddPrintProcessor, AddMonitor, etc.), or
  • Use the printer-specific INF file extensions provided by the Windows 95 printer installer utility.
  • Launch the Add Printer Wizard using WinHelp.

The relative advantages and disadvantages of each method are summarized in the following table.

Installation Method | Advantages | Disadvantage
Use Win32 APIs such as AddPrintProcessor or AddMonitor. | Offers flexibility, compared to the .INF file extension method. | Difficult to code and test, compared to the .INF file extension method.
Use printer-specific .INF file extensions. | Relatively inflexible. | Easy to code and test.

This section describes how to use the Win32 APIs to install printer support. For information on how to use the printer-specific INF file extensions, see the section Using the Printer-Specific Windows 95 INF File Extensions.

The topics of printer-specific INF file extensions and using Win32® APIs in a DLL to install printer support are not completely independent. If you decide to develop a DLL to install some level of printer support, you will have to name the DLL in either a VendorSetup or VendorInstaller statement in an INF file in order for your DLL to be known by the Windows 95 printer installer. The VendorSetup and VendorInstaller printer-specific INF file extensions are described in the section Printer-Specific INF File Extensions Reference.


Plug and Play Printer Installation

The first time Windows 95 detects a printer connected locally to the Windows 95 computer through a parallel port, Windows 95 attempts a device ID negotiation with the printer as described in the IEEE 1284 specification. If the printer is a bi-directional printer and responds appropriately, Windows 95 will install the required printer drivers as listed in the INF file for the device.

The required printer drivers are determined by finding a match between the values returned by the device and the values in an INF file containing information about the required printer support.


Benefits of Printer Plug and Play Installation

For the Windows 95 computer user, installing printer support is as easy as it gets. Windows 95 will detect a newly attached printer when Windows 95 starts up, or when the user requests Windows 95 to detect new devices, and use the INF file contents as a script for automatically installing printer support. Depending upon the INF file contents, Windows 95 may prompt the user during this process.

A user requests detection of new devices by using the Add New Hardware icon in the Windows 95 Control Panel.


Printer Plug and Play Installation Requirements

This section outlines the minimum hardware and software requirements for parallel port devices to obtain Plug and Play support under Windows 95. The term Plug and Play is defined here as the ability to attach an I/O device to a host and enable the host to determine that the device has been added, identify it, and either automatically install the necessary device drivers or prompt the user for a diskette containing them.

To offer parallel port Plug and Play capability, the host

  • Must have a parallel port capable of supporting nibble mode as defined by IEEE-P1284.
  • May support ECP mode as defined by the IEEE 1284 specification in order to enjoy the improved performance ECP mode provides.

To support Plug and Play, the device connected to the parallel port must offer capabilities in three different areas:

  • Hardware
  • Software
  • Device identification

Device Hardware Capabilities

To participate in Windows 95 Plug and Play, a parallel port device

  • Must provide a parallel interface which conforms to the IEEE 1284 specification. This interface may be 1284-I compliant (using 1284-A or 1284-B connectors) or 1284-II compliant (using 1284-C connectors).
  • Must support nibble mode as described in the IEEE 1284 specification.
  • To receive Microsoft Plug and Play certification, the device must also report the minimal device ID key values as described in IEEE 1284.
  • May support ECP mode as defined in the IEEE 1284 specification in order to obtain improved performance.

Device Software Capabilities

To participate in Plug and Play, a parallel port device

  • Must return a device ID string in nibble mode, as defined by the IEEE 1284 specification.

Device Identification Capabilities

To participate in Plug and Play, in general a parallel port device

  • Must return device ID strings to the host made up of ASCII values between 32 and 127 (between 0x20 and 0x7F), inclusive.
  • Must provide MANUFACTURER, MODEL, CLASS, and COMPATIBLE ID key values that remain static. Multiple-personality devices are an exception to this, as is described in the section Multiple Emulation Devices.
  • Must provide MANUFACTURER and MODEL key values that are unique from each manufacturer.

Requirements for reporting device IDs are described in Section 6.6 of the IEEE 1284 specification. Six keys that can be returned by a device are described and these are identified in the following table:

Key | Abbreviation | Comment
MANUFACTURER | MFG | The MFG key value is used in combination with the MDL key value to generate a unique device ID for Plug and Play parallel devices for Windows 95. For more information about this, see the section Generating Unique Plug and Play Device IDs.
COMMAND SET | CMD | This key is ignored by Windows 95 for parallel port devices.
MODEL | MDL | See the comment about the MFG key.
CLASS | CLS | PRINTER is one value this key can have in Windows 95.
DESCRIPTION | DES | The DES key value is a string, up to 128 characters long, that may be presented to the user to describe the device if an INF file cannot be found for the device.
COMPATIBLE ID | CID | The value(s) in this key effectively identifies device drivers that are compatible with the device being identified. If the device is not compatible with another device or the device manufacturer does not want to use a compatible device driver with the device, this key will be empty. For more information, see the section Using CID Values.


Generating Unique Plug and Play Device IDs

The Windows 95 parallel port enumerator (LPTENUM) generates a unique Plug and Play device ID by combining the MANUFACTURER and MODEL key values that are always returned by the device:

  1. The MANUFACTURER key value and MODEL key values are concatenated and a 4-digit checksum generated from the resulting string.
  2. After the checksum is generated, the concatenated string is truncated to 20 characters if necessary.
  3. The checksum is converted to a 4-character string and appended to the concatenated, and possibly truncated, string resulting in a device ID string of not more than 24 characters.

For example, if a printer MFG key value is Hewlett-Packard and the MDL key value is HP LaserJet 4P then the device ID that is generated is Hewlett-PackardHP_La7EE2. (The algorithm used to calculate the checksum is beyond the scope of this documentation.)

When LPTENUM\ is prepended to the device ID such as the one given in the preceding example, this is the device's Plug and Play ID value used by the Windows 95 parallel port enumerator. The example Plug and Play ID is LPTENUM\Hewlett-PackardHP_La7EE2.

The Plug and Play ID is used to search all known device information files (INF files) on a particular host for a driver that will support the device. The order in which device IDs are listed in the INF file is important in determining which device driver named in the INF file is the best match for the device. For examples of how to order the lists of device IDs in INF files, see the section Ordering of Device ID and Compatible Device ID Values.


Using CID Values

The value returned in the COMPATIBLE ID (CID) key by a printer may have any value listed in an INF file, as described in the section Generating Unique Plug and Play Device IDs. Plug and Play IDs assigned to legacy parallel port devices which have driver support in Windows 95 may also be returned.

The CID values returned by a printer should be carefully chosen by printer vendors. If your device returns a CID which is an exact match for a device ID for another vendor's device, ensure you have license rights from the device driver manufacturer to install the compatible device driver. Microsoft will provide CID values for many of the printer drivers shipped with Windows 95 and vendors are encouraged to freely use those values in the CID keys returned by their printers.

The syntax of the string returned from a printer as a CID value is important and will differ slightly depending upon what the printer is reporting itself being compatible with:

  • If your printer is reporting a CID value for the exact device ID of another physical device, then the value returned from your printer must contain the enumerator name.
  • If your printer is reporting one of the CID values provided by Microsoft, then the CID value will not require the enumerator name.

For example, suppose the INF file contains the following entry:

"Sample Printer"=X.DRV,LPTENUM\Sample_Printer_CompaAAA2

This INF file entry describes a printer that displays the printer name Sample Printer, is supported by the driver X.DRV. The procedure described in the section Generating Unique Plug and Play Device IDs generates the device ID Sample_Printer_CompaAAA2. The Plug and Play device ID has the enumerator prepended to it, resulting in LPTENUM\Sample_Printer_CompaAAA2.

For another parallel port device to report itself as compatible with the device described in this INF file entry, it must report a CID keyword value of

LPTENUM\Sample_Printer_CompaAAA2

If the INF file entry had the alternate form of

"Sample Printer"=X.DRV,LPTENUM\Sample_Printer_CompaAAA2, Sample_Printer_CompaAAA2

then the device could alternately report itself as

Sample_Printer_CompaAAA2

Note that the very first time Windows 95 is started on a computer, the way CID values are handled differs from the way they are handled for all subsequent start ups. For more information, see the section Ordering of Device ID and Compatible Device ID Values.

A printer which is compatible with the HP LaserJet 4L, and for which the vendor has the necessary rights to use a driver provided by another vendor, returns the following CID key value:

LPTENUM\Hewlett-PackardLaserC029

In order to use this CID value, you must have legal rights to install the printer driver provided by the other vendor (in this example case, Hewlett-Packard).

A printer which is compatible with the HP LaserJet 4L and which uses the driver provided by Microsoft returns the following CID key value:

HP_LaserJet_4L


Multiple Emulation Device Requirements

It is becoming more common for printers to support multiple page description languages (for example, both HP-PCL and PostScript). Each of these page description languages require separate printer drivers. It is also possible for devices to have multiple functions, such as printer and fax or printer and SCSI drive.

In general, however, Windows 95 Plug and Play maps a single device ID for a given device to a single device driver. This section describes how a single device ID can be mapped to multiple device drivers.

Multiple Device Drivers Installed with the Printer Class Installer

The Windows 95 printer class installer provides a way for device vendors to supply their own DLLs to install multiple drivers for one device. There are two methods, each of which requires the use of a printer-specific extension in the INF file for the device.

  • In the first method, the Windows 95 Printer class installer installs one printer driver (the driver that is mapped to the printer by the Plug and Play device ID in the INF file) and then calls a vendor-supplied 32-bit DLL to install additional printer drivers or call other Windows 95 class installers to install additional device drivers as needed. The filename of the vendor-supplied DLL is specified in a VendorSetup statement in the INF file (see the section Printer-Specific INF File Extensions Reference for specific information about VendorSetup).
  • In the second method, the Windows 95 Printer class installer does nothing more than copy files from the printer installation diskette, under direction of the INF file on the diskette, and then calls a vendor-supplied 32-bit DLL to perform all the functionality required to install all the drivers the device needs. The filename of the vendor-supplied DLL is specified in a VendorInstaller statement in the INF file (see the section Printer-Specific INF File Extensions Reference for more information about VendorInstaller).

Multiple Device Drivers Installed with the Serial Port Bus Enumerator

The serial port bus enumerator provides a way for a device to report multiple device ID values, each of which maps to a specific device driver.

The parallel port bus enumerator does not support the ability to enumerate multiple device ID values.


Ordering of Device ID and Compatible Device ID Values

As described earlier, the compatible device ID (CID) for a printer provides the IDs of the other devices with which the printer is compatible. The operating system uses this information to load compatible device drivers, if necessary. There can be several CIDs for each logical device. The order in which these CIDs are listed in an INF file may be used by the operating system as a criteria for determining which driver to search for and load first.

The ordering scheme assigns a numeric rank value to each CID value and a driver with lower rank-order CID is considered by the operating system to be a better match for the device than a driver with a CID of higher-rank order. A driver with a CID with rank order of zero is considered an exact match to the printer and when the driver identified by this CID is found it is automatically installed without prompting the user.

If a rank order zero match is not found and a higher-order rank match is found, then the user is prompted with the information that a compatible device driver is available. At this point, the user is responsible for installing the most compatible driver available. If the user has a diskette with the rank order zero driver on it, or some other driver the user believes is more compatible than the one found on the system and identified in the user dialog, then the user can insert that diskette and specify the driver to be installed from there. If the user does not have a more compatible driver on a diskette, the user may either OK the installation of the most compatible driver the system could find or select another printer driver from a list of printer drivers found by the system.

Note that there may be an extra step in the procedure previously described if the device being installed does not provide the information about what class of devices it belongs to. In that case, the user will be prompted to provide the device class and the procedure previously described will occur after the user responds that a printer is being installed.

Rank ordering is determined as follows:

  1. Assign device rank orders to the device IDs returned by the device. The device ID derived from the MFG and MDL key values returned by the device is assigned device rank order 0, the first CID returned by the device is assigned rank device order 1, the second CID returned by the device is assigned device rank order 2, and so on.
  2. The contents of the INF files on the host are searched for any matches with any of the device IDs returned by the device.
  3. Each time an exact match is found between a device ID in an INF file and a device ID returned by the device, an INF rank order is determined using the following rule: if the matching device ID in the INF file is the first one listed after the INF file Install section name, then the INF rank order is zero; if the matching device ID in the INF file is the second one listed after the Install section name, then the INF rank order is 1; and so on.
  4. After all the INF files are searched and all the matches are found and each match is assigned a device ID rank order and an INF file rank order, add the values of the two rank orders for each match.
  5. If this is the very first time the Windows 95 system has started up on this host, then automatically load the driver with the lowest-valued rank order sum without prompting the user. If this is not the very first time Windows 95 has started up, if one of the resulting rank order sums is zero, install that driver without prompting the user. Otherwise, prompt the user with the identity of the driver with the lowest-valued rank order sum and give the user a chance to provide a better matched driver on a diskette or select another printer from a list presented by the system. If the user does not provide a diskette, either the driver with the lowest-valued rank order is installed or the driver for the printer the user selects is installed.

For example, suppose an INF file on the host contains the following statements:

"Sample Printer 1" = X1.DRV,LPTENUM\Sample_Printer_CompaAAA2,Sample_Printer_CompaBBB2
"Sample Printer 2" = X2.DRV,LPTENUM\Sample_Printer_CompaCCC2,LPTENUM\Sample_Printer_CompaDDD2,Sample_Printer_CompaEEE2

And suppose the device returns the following Plug and Play device ID (derived from the MFG and MDL key values returned by the device as described in section Generating Unique Plug and Play Device IDs) and CIDs:

Device ID="LPTENUM\Sample_Printer_CompaCCC2"
CID=LPTENUM\Sample_Printer_CompaAAA2,Sample_Printer_CompaBBB2

The result of applying the matching and rank ordering rules to the preceding example is that Sample_Printer_2 has a device ID rank order of zero and an INF rank order of zero, so the driver X2.DRV is automatically loaded without prompting the user.

For another example, suppose an INF file on the host contains the following statements:

"Sample Printer 1" = X1.DRV,LPTENUM\Sample_Printer_CompaAAA2,Sample_Printer_CompaBBB2
"Sample Printer 2" = X2.DRV,LPTENUM\Sample_Printer_CompaCCC2,LPTENUM\Sample_Printer_CompaDDD2,Sample_Printer_CompaEEE2
"Sample Printer 3" = X3.DRV,LPTENUM\Sample_Printer_CompaFFF2,LPTENUM\Sample_Printer_CompaGGG2,Sample_Printer_CompaHHH2

And suppose the device returns the following Plug and Play device ID (derived from the MFG and MDL key values returned by the device) and CIDs:

Device ID="LPTENUM\Sample_Printer_CompaDDD2"
CID=LPTENUM\Sample_Printer_CompaHHH2,Sample_Printer_CompaBBB2

The result of applying the matching and rank ordering rules to the preceding example is that there is no rank order zero match found. Sample_Printer_2 (X2.DRV) has a rank order sum value of 1, Sample_Printer_1 (X1.DRV) has a rank order sum of 3, and Sample_Printer_3 (X3.DRV) has a rank order sum of 3.

If this is the very first time Windows 95 is run on the host, then X2.DRV is automatically installed without prompting the user. Otherwise, the user is prompted that X2.DRV will be installed as the printer driver unless the user inserts a diskette with a driver better matched to the printer (this diskette will probably have been provided by the printer vendor).


Using the Printer-Specific Windows 95 INF File Extensions

Your monitor or print processor DLLs can be installed using statements in the INF file Windows 95 uses to install your printer driver. Printer extension statements for INF files are defined for Windows 95 and this section describes how these printer extension statements are used and provides reference material for each statement. This section also describes how these INF file printer extensions statements are used in the context of Windows 95 device Plug and Play.

Under Windows 3.1x, the Control Panel Printers applet has some limitations on installing printer drivers. This caused some printer vendors to develop their own installation utilities to work around these limitations.

Under Windows 95, the mechanism for installing printer drivers is different, removing the Windows 3.1x limitations. A new user interface is also provided in Windows 95 that corrects the problems users have reported with the Windows 3.1x Control Panel Printers applet.

In order to support the automatic Plug and Play printer installation described in the section Plug and Play Printer Installation and to support the manual printer installation method for non-Plug and Play printers that is described in this section, the printer INF file format for Windows 95 differs from the INF file format used with Windows 3.1x. This section defines the printer-specific changes to the INF file format and content. If you are developing a Windows 95 INF file for your printer installation, you must read tWindows 95 INF Files in addition to this section to get all the information you need to do the job.

Note that the OEMSETUP.INF file format for printer drivers from Windows 3.1x will continue to be supported in Windows 95 for backwards compatibility, but all printer vendors are strongly encouraged to use the new INF file format described here and in Windows 95 INF Files.

For Plug and Play printer installation and to use any of the new options for manual printer installation using the Add Printer icon, you will have to use the new INF file format and statements.

All of the printer-specific Windows 95 INF file extensions are individual lines that can be added to the simple text INF file. Each line has the form key=value. There are just over a dozen printer-specific keys that can be used and you only need to use a key to override the default. The following table lists the keys and defaults.

Key | Description | Default Value
ConfigFile | Names the DLL to call to configure the printer. | The file named in the DriverFile statement.
DataFile | Names a file that contains printer-specific information. For example, this may be the mini driver data file or, for Post Script printers, the .SPD file. | Install section name.
DataSection | Names another section of the INF file that contains printer-specific key=value statements that can be used by more than one Install section in the INF file. | There does not have to be a Data section in an INF file or any DataSection statements in any of the INF file installer sections. See the section Printer INF File Data Section for an example of how to use a Data section to reduce typing and clerical errors while you are developing a printer INF file.
DefaultDataType | Default datatype used by the printer and print processor associated with the printer. | Raw
DriverFile | Names the printer driver (.DRV) file to install. | Install section name.
HelpFile | Names the help file associated with the printer model. | No help file.
LanguageMonitor | User-displayable name and DLL filename of language monitor used by the printer model. | No language monitor.
NoTestPage | Instructs the Windows 95 printer installation process to not prompt the user with a test page printing option as the last step of a successful printer installation. | The user is prompted with a test page printing option, unless a VendorInstaller or VendorSetup statement is used in the INF file.
NotSelectedTimeOut | Not-selected timeout value for the printer, measured in seconds. | 45 seconds.
PortMonitor | User-displayable name and DLL filename of port monitor used by the printer model. | Default port monitor, which is provided by Microsoft as part of SPOOLSS.DLL..
PrintProcessor | User-displayable name and DLL filename of the print processor used by the printer model. | Default print processor, which is provided by Microsoft as part of SPOOLSS.DLL.
RetryTimeout | Retry timeout value for the printer, measured in seconds. | 15 seconds.
VendorInstaller | Names a vendor-provided Win32 DLL that performs the entire printer installation process, and the exported entry-point to call in that DLL. Can only be used for Plug and Play devices. | No vendor installer DLL.
VendorSetup | Names a vendor-provided Win32 DLL to be run after normal printer installation is accomplished, and the exported entry-point to call in the DLL. | No vendor setup DLL.


Printer INF File Install Sections

Regardless of which of the printer extension keys you use, always put them in the INF file Install section for the printer, or in a Data section referred to by the Install section. This is illustrated in the following sections from a printer INF file:

[Manufacturer]
"HP"

[HP]
"HP LaserJet 4ML"  = HPPCL5MS.DRV.BIDI,HP_LaserJet_4ML,Hewlett-PackardLaserECF6
"HP LaserJet 4ML Postscript" = HP4ML_V4.SPD,LPTENUM\Hewlett-PackardHP_LaECF6,Hewlett-Packard HP_LaECF6,HP_LaserJet_4ML_PostScript,Hewlett-PackardLaserC029
;
; Install Sections
;
[HP4ML_V4.SPD]
CopyFiles=@HP4ML_V4.SPD,PSCRIPT
DataSection=PSCRIPT_DATA

[HPPCL5MS.DRV.BIDI]
CopyFiles=@HPPCL5MS.DRV,@PJLMON.DLL,UNI,FINSTALL
DataSection=UNI_DATA
DriverFile=HPPCL5MS.DRV
DataFile=HPPCL5MS.DRV
LanguageMonitor=%PJL_MONITOR%
;
; Copy Sections
;
[FINSTALL]
FINSTALL.DLL
FINSTALL.HLP

[PSCRIPT]
PSCRIPT.DRV
PSCRIPT.HLP
PSCRIPT.INI
TESTPS.TXT
APPLE380.SPD
FONTS.MFM
ICONLIB.DLL
PSMON.DLL

[UNI]
UNIDRV.DLL
UNIDRV.HLP
ICONLIB.DLL
;
; Data Sections
; These sections contain data that is shared between devices
;
[PSCRIPT_DATA]
DriverFile=PSCRIPT.DRV
HelpFile=PSCRIPT.HLP
LanguageMonitor=%PS_MONITOR%

[UNIDATA]
HelpFile=UNIDRV.HLP
DefaultDataType=EMF
;
; Localizable strings
;
[Strings]
PJL_MONITOR="PJL Language Monitor,PJLMON.DLL"
PS_MONITOR="PostScript Language Monitor,PSMON.DLL"

This INF file is used in the installation of several different Hewlett-Packard printers. The manufacturer's name section, [HP], names the two printer product-names that can be installed using this INF file: HP LaserJet 4ML and HP LaserJet 4ML Postscript.

Also specified in the section named [HP] are the Install sections where the printer-specific keys like DriverFile, DataFile, and LanguageMonitor will be found. The names of the two Install sections in this INF file are HPPCL5MS.DRV.BIDI and HP4ML_V4.SPD.


Printer INF File Data Section

Data sections contain only printer extension keys. There may be any number of Data sections in a printer INF file, from zero to a maximum number which matches the number of Install sections that are in the INF file. More than one Install section in an INF file can reference the same Data section.

To be recognized by the printer installer, a Data section must be named in a DataSection statement in an Install section of the INF file.

If a key is used in both an Install section and the Data section that Install section references, the value in the Install section takes precedence.


Examples of Install and Data Section Relationships

It is instructive to look at the two Install sections, [HPPCL5MS.DRV.BIDI] and [HP4ML_V4.SPD], just to see how many of the dozen or so printer keys are used in each one. The [HPLJP_V4.SPD] section is the simplest:

[HP4ML_V4.SPD]
CopyFiles=@HP4ML_V4.SPD,PSCRIPT
DataSection=PSCRIPT_DATA

The CopyFiles key is common to all INF file install sections, so the [HP4ML_V4.SPD] section has only one statement with a printer-specific key:

DataSection=PSCRIPT_DATA

This statement names the only other section in the INF file that can contain printer-specific keys, the Data section. In fact, the Data section will contain only printer-specific keys, as is shown in the following:

[PSCRIPT_DATA]
DriverFile=PSCRIPT.DRV
HelpFile=PSCRIPT.HLP
LanguageMonitor=%PS_MONITOR%

[Strings]
PS_MONITOR="PostScript Language Monitor,PSMON.DLL"

Note that since only four printer-specific keys are used in the Install section for this printer model and in its Data section, defaults are used for the other keys during printer installation. Following is a list of the default values that are used:

ConfigFile=PSCRIPT.DRV      ; default is driver filename
DataFile=HPLJP_V4.SPD       ; default is install section name
DefaultDataType=RAW         ;
NoTestPage=1                ; prompt user with Test Page opportunity
NotSelectedTimeOut=45       ; measured in seconds
PortMonitor=PORTMON.DLL     ; Microsoft-provided port monitor
PrintProcessor=WINPRINT.DLL ; Microsoft-provided print processor
RetryTimeout=15             ; measured in seconds
VendorInstaller=""          ; no vendor-provided installer
VendorSetup=""              ; no vendor-provided post-installation
                            ; step

The other Install section, [HPPCL5MS.DRV.BIDI], also uses a Data section, named [UNIDATA]. The [HPPCL5MS.DRV.BIDI] Install section looks like this:

[HPPCL5MS.DRV.BIDI]
CopyFiles=@HPPCL5MS.DRV,@PJLMON.DLL,UNI,FINSTALL
DataSection=UNI_DATA
DriverFile=HPPCL5MS.DRV
DataFile=HPPCL5MS.DRV
LanguageMonitor=%PJL_MONITOR%

[Strings]
PJL_MONITOR="PJL Language Monitor,PJLMON.DLL"

The Data section [UNI_DATA] contains two printer-specific keys, HelpFile and DefaultDataType.

[UNI_DATA]
HelpFile=UNIDRV.HLP
DefaultDataType=EMF

Printer-specific statements can be distributed between an Install section and a Data section any way that is convenient for you, with the exception that if a DataSection key is used it must be used in the Install section. Note that it is not necessary to use a Data section in your printer INF file, even though both of the preceding example Install sections do use a Data section.


Printer-Specific INF File Extensions Reference

This section gives more details about each of the fourteen printer-specific keys that can be used in the Install and/or Data section of a printer INF file.


ConfigFile

ConfigFile = filename

Specifies the configuration file for the installed printer.

filename Identifies the DLL that configures the printer model installed by the INF file Install section.

If no ConfigFile statement is used in the Install section (or a Data section it refers to), then the DLL named in a DriverFile statement in the Install section (or a Data section it refers to) is used to configure the printer, and must support the necessary DDI.


DataFile

DataFile = filename

Specifies the file that contains the mini driver data for the installed printer.

filename Names the file that contains the printer-specific information for the printer model installed by the INF file Install section. For example, this may be the name of a file that contains minidriver data for the printer or, for PostScript printers, the name of an SPD file.

If no DataFile statement is used in the Install section or a Data section it refers to, then the name of the Install section is used as the name of the file that contains the printer-specific information.


DataSection

DataSection = sectionname

sectionname Specifies a section in the INF file that contains other printer extension statements to be used in normal installation of the printer.

A Data section in the INF file that contains other printer-specific extension statements to be used when the printer is installed by the INF file Install section.

A DataSection statement is optional in an Install section.

The total list of printer-specific extensions used to install the printer is all the printer-specific statements in the Install section plus all the statements in the Data section. If a key is used in both sections, the value of the key in the Install section is the one that is used in installing the printer.


DefaultDataType

DefaultDataType = datatype

datatype Specifies the default data type used by the installed printer.

To be valid, the value of datatype must be one of the data types enumerated by a print processor already installed on the Windows 95 computer or a print processor installed along with the printer.

If no DefaultDataType statement is used in the Install section or a Data section it refers to then the default datatype value is Raw. Enhanced metafiles (EMFs) are a datatype supported by the default print processor that is installed when Windows 95 is installed. (The default print processor is part of SPOOLSS.DLL.)


DriverFile

DriverFile = filename

Specifies the driver for the installed printer.

filename Names the file that contains the printer driver for the printer model installed by the Install section. The filename must include an explicit extension; for example, MYPRINTR.DRV.

If no DriverFile statement is in the Install section or a Data section it refers to, then the Install section name is used as the filename of the driver.


HelpFile

HelpFile = filename

Specifies the help file for the installed printer model.

filename The name of the help file; for example MYPRINTR.HLP.

If no HelpFile statement is used in the Install section or a Data section it refers to, then no help file is installed for the printer.


LanguageMonitor

LanguageMonitor = display-name, filename

Specifies a language monitor that supports the installed printer model.

display-name | A user-displayable, descriptive name for the language monitor. This string may not contain commas.
filename | Names a DLL that is the language monitor that supports the printer model installed by the Install section of the INF file.

If no LanguageMonitor statement is used in the Install section or a Data section it refers to, then no language monitor is installed for the printer model. In general, language monitors are only useful with bi-directional printers.

It is a good idea to put the display-name string in the [Strings] section of the INF file, along with all the other strings that may be displayed to the user.


NoTestPage

NoTestPage = flag

Determines whether or not an option to print a test page is presented to the user as the last step of a successful printer installation.

flag Can be set to any value. If a NoTestPage statement is in the Install section (or a Data section it refers to) the user will not be given the opportunity to print a test page. The value of the flag parameter adds no extra information to this and is simply a place holder.

If a VendorSetup or VendorInstaller statement is used in the Install section (or a Data section it refers to), then no test page will be presented, and a NoTestPage statement in either of those two sections is redundant.


NotSelectedTimeout

NotSelectedTimeout = n

Specifies the duration of the not-selected timeout for the installed printer.

n The number of seconds in the not-selected timeout period.

If a NotSelectedTimeout statement is not used in the Install section or a Data section it refers to, then a timeout duration of 45 seconds is used.


PortMonitor

PortMonitor = display-name, filename

Specifies a port monitor that supports the installed printer model.

display-name | A user-displayable, descriptive name for the port monitor. This string may not contain commas.
filename | Names a DLL that is the print monitor that supports the printer model installed by the Install section of the INF file.

If no PortMonitor statement is used in the Install section or a Data section it refers to, then the default port monitor installed as part of Windows 95 is used to support the installed printer. (The default port monitor is part of SPOOLSS.DLL.)

It is a good idea to put the display-name string in the [Strings] section of the INF file, along with all the other strings that may be displayed to the user, in case displayable strings have to be translated for international markets.


PrintProcessor

PrintProcessor = display-name, filename

Specifies a print processor that supports the installed printer model.

display-name | A user-displayable, descriptive name for the print processor. This string may not contain commas.
filename | Names a DLL that is the print processor that supports the printer model installed by the Install section of the INF file.

If no PrintProcessor statement is used in the Install section or a Data section it refers to, then the default print processor installed as part of Windows 95 is used to support the installed printer. (The default print processor is part of SPOOLSS.DLL).

It is a good idea to put the display-name string in the [Strings] section of the INF file, along with all the other strings that may be displayed to the user, in case displayable strings have to be translated for international markets.


RetryTimeout

RetryTimeout = n

Specifies the duration of the retry timeout for the installed printer.

n The number of seconds in the retry timeout period.

If a RetryTimeout statement is not used in the Install section or a Data section it refers to, then a timeout duration of 15 seconds is used.


VendorInstaller

VendorInstaller = filename, function-name

Names a vendor-provided Win32 DLL that performs the entire printer installation process, and the exported entry-point to call in that DLL. Can only be used for Plug and Play devices.

filename | Name of the vendor-supplied installer DLL.
function-name | Name of the function exported by the DLL to call to begin the vendor-supplied printer installation process.

Use of a VendorInstaller statement in the Install section or a Data section it refers to indicates that the printer vendor has a custom printer installation process to be used instead of the normal installation process. Note that a custom printer installation process is only supported for Plug and Play printers, that is, printers that generate a device ID value. The normal installation process must be able to match the generated device ID with a device ID in the INF file before the normal installation process will call the entry-point exported by the vendor-supplied installer DLL.

The vendor-supplied DLL must be a Win32 DLL and the function identified by function-name must have the following prototype:

VOID FAR PASCAL functionname (HWND      hWnd,
                              HINSTANCE hInstance,
                              LPSTR     lpszCmdLine,
                              int       nCmdShow
                             );

When the normal installation process calls the exported function, lpszCmdLine points to the registry key, relative to HKEY_LOCAL_MACHINE, that has been created by Windows 95 Plug and Play and which contains information about the printer to be installed by the vendor-supplied DLL. The DLL is then responsible for carrying out all aspects of printer installation, except copying files that are specified in INF file sections named in the Install section CopyFiles statement -- the normal installation process carries out the CopyFiles directive before the DLL is called.

In general, the vendor-supplied DLL should add a registry value under the passed-in key named ConfigFlags and set its value to zero (a DWORD of type REG_BINARY). Then the DLL should call the Win32 print subsystem APIs AddPrinter, AddPrinterDriver, etc. as needed.

If a VendorInstaller statement is used in the Install section (or a Data section it refers to), then Windows 95 will not prompt the user with the opportunity to print a test page at the end of the printer installation.


VendorSetup

VendorSetup = filename, function-name

Names a vendor-provided Win32 DLL that performs a custom installation step after the normal installation process is successfully completed.

filename | Name of the vendor-supplied DLL that performs the extra installation step.
function-name | Name of the function exported by the DLL to call to begin the vendor-supplied installation step.

Use of a VendorSetup statement in the Install section or a Data section it refers to indicates that the printer vendor has a custom installation step to perform after normal printer installation is successfully completed. Note that the custom installation step DLL will never be called if the normal installation process does not go to successful completion.

The vendor-supplied DLL must be a Win32 DLL and the function identified by function-name must have the following prototype:

VOID FAR PASCAL functionname (HWND      hWnd,
                              HINSTANCE hInstance,
                              LPSTR     lpszCmdLine,
                              int       nCmdShow
                             );

When the normal installation process calls the exported function, lpszCmdLine points to user-displayable (friendly) name of the printer that has just been installed. The vendor DLL can use that printer name as a parameter in Win32 print subsystem functions to obtain all necessary printer and driver information about the installed printer.

If a VendorSetup statement is used in the Install section (or a Data section it refers to), then Windows 95 will not prompt the user with the opportunity to print a test page at the end of the printer installation.


Graphics Device Interface

A Windows® 95 graphics driver is a dynamic link library (DLL) that Windows uses to carry out operations on a graphics device. There are two categories of graphics devices: video and printer (or light-emitting and ink-based). Although the technology found in these two categories differs significantly, the Windows 95 interface used to control them is nearly identical. This overview describes the common elements found in both types of graphics drivers.


Full Drivers and Minidrivers

There are two subsets within each category of graphics driver: old-model drivers and minidrivers. Microsoft supports and strongly encourages the development of minidrivers for graphics devices. A display minidriver is a graphics driver that uses the Microsoft device independent bitmap (DIB) engine to accomplish most or all of actual drawing. For display minidrivers, most of the thirty or so required functions call directly into the DIB engine. For printer minidrivers, even less coding is required. Printer-driver developers use the Microsoft Windows UniTool application to initialize required structures and rely on a second Microsoft-supplied DLL, UNIDRV.DLL, to make calls into the DIB engine.

For specific details about creating a display driver, see Part 5, "Display Drivers"; for specific details about creating a printer driver, see Part 6, "Printer Drivers".


Initialization

Windows loads a graphics driver when it calls the kernel LoadLibrary function. After loading the driver, Windows initializes the DLL by calling the driver's Enable function. Windows calls this function twice: the first time with a pointer to a GDIINFO structure; the second time with a pointer to a PDEVICE structure. The first structure, GDIINFO, describes the device's capabilities and related metrics (such as the dimension of the display or printable region). The second structure, PDEVICE, contains driver-dependent data (unless the driver is a minidriver).

The overview of display drivers describes a special PDEVICE structure that is required for minidrivers. It is called a DIBENGINE structure. A minidriver must initialize this structure (instead of a private PDEVICE structure) when it processes the second call to the Enable function.

Windows disables a graphics driver when it is no longer needed by the system, when an application deletes a corresponding device or information context, or when it saves a display DC in preparation for switching to a full-screen application. Windows disables the driver by calling the driver's Disable function.

See Also

Disable, Enable, GDIINFO, PDEVICE


Object Management

When Windows calls the Enable function the first time, a graphics driver should initialize the members of the GDIINFO structure that contain information about brushes, pens, fonts, and bitmaps that the device supports. The following table identifies these members and their purpose:

GDIINFO member | Purpose
dpNumBrushes | Specifies the number of brushes supported by device.
dpNumPens | Specifies the number of pens supported by device.
dpNumFonts | Specifies the number of fonts supported by device.
dpRaster | Specifies whether or not device bitmaps are supported by the device. The RC_DEVBITS value should be set if device bitmaps are supported.

Depending on the type of resident objects, a graphics driver should support as many as three object management functions: EnumDFonts, EnumObj, and RealizeObject. The EnumDFonts function returns information about device fonts. The EnumObj function returns information about device pens and brushes. The RealizeObject function creates or deletes a pen, brush, font, or bitmap.

If a device provides onboard fonts, the driver should set the dpNumFonts member of the GDIINFO structure and support the EnumDFonts function. If a device provides onboard pens and brushes, the driver should set the dpNumPens and dpNumBrushes members of the GDIINFO structure and support the EnumObj function. If a device supports onboard bitmaps, the driver should set the RC_DEVBITS value for the dpRaster member of the GDIINFO structure. If a device provides onboard fonts, pens, brushes, or bitmaps, it must support the RealizeObject function in addition to the other functions described in this paragraph.

See Also

Enable, GDIINFO, EnumDFonts, RealizeObject


Lines, Curves, and Geometric Shapes

When Windows calls the Enable function the first time, a graphics driver should initialize the members of the GDIINFO structure that contain information about the lines, curves, and geometric shapes that the device can draw. The following table identifies these members and their purpose:

GDIINFO member | Purpose
dpCurves | Specifies the types of curves and curved objects (circles, pies, chords, and ellipses) that a device can draw.
dpLines | Specifies the types of lines that a device can draw.
dpPolygonals | Specifies the types of geometric shapes (polygons, rectangles, and filled shapes) that a device can draw.

Depending on the line, curve, and geometric-shape capabilities of a device, the graphics driver should support as many as thirteen variations of the Output function. If a device can draw arcs, ellipses, pies, chords, circles, Bezier splines or rectangles with rounded corners, the driver should set the appropriate values for the dpCurves member of the GDIINFO structure and support the corresponding calls to the Output function. (For example, if a driver sets the CC_ELLIPSES value for dpCurves, it must support the call to Output when the wStyle parameter is OS_ELLIPSE). If a device can draw lines or polylines of various widths and styles, the driver should set the appropriate values for the dpLines member of the GDIINFO structure and support the corresponding calls to the Output function. If a device can draw polygons, rectangles, or filled shapes, the driver should set the appropriate values for the dpPolygonals member of the GDIINFO structure and support the corresponding calls to the Output function.

See Also

Enable, GDIINFO, Output(OS_ALTPOLYGON), Output(OS_ARC), Output(OS_BEGINNSCAN), Output(OS_CHORD), Output(OS_CIRCLE), Output(OS_ELLIPSE), Output(OS_ENDNSCAN), Output(OS_PIE), Output(OS_POLYBEZIER), Output(OS_POLYLINE), Output(OS_POLYPOLYGON), Output(OS_POLYSCANLINE), Output(OS_RECTANGLE), Output(OS_ROUNDRECT), Output(OS_SCANLINES), Output(OS_WINDPOLYGON)


Bitmaps

When Windows calls the Enable function the first time, a graphics driver should initialize the members of the GDIINFO structure that contain information about the device's bitmap technology and capabilities. The following table identifies these members and their purpose:

GDIINFO member | Purpose
dpTechnology | Specifies the device technology (vector, raster, metafile, and so on).
dpHorzRes | Specifies the horizontal resolution of the device.
dpVertRes | Specifies the vertical resolution of the device.
dpBitsPixel | Specifies the number of adjacent bits required to define a single pixel.
dpPlanes | Specifies the number of planes required to define a single pixel.
dpRaster | Specifies the raster capabilities (if any) of the device.
dpAspectX | Specifies the width of a device pixel.
dpAspectY | Specifies the height of a device pixel.
dpAspectXY | Specifies the diagonal width of a device pixel.
dpCaps1 | Specifies additional raster capabilities.

If the device is a raster printer or a video display, it must set the appropriate GDIINFO members and support the following bitmap functions: BitBlt, BitmapBits, CreateDIBitmap, Pixel, SaveScreenBitmap, SelectBitmap, SetDIBitsToDevice, StretchBlt, StretchDIBits, and ScanLR. In addition, if the device provides device bitmaps, it must support the DeviceBitmap and DeviceBitmapBits functions.

The BitBlt function transfers bits of color data that correspond to a rectangle of pixels on the display from one location in video memory to another location in video memory (the new location corresponds to a second rectangle of pixels). This function is one of the most frequently called display-driver functions and is typically handled by hardware accelerators. The BitmapBits function has multiple purposes, GDI calls it to set bits on a device, to copy bits from a device to a buffer, and to copy bits from a buffer to a device. The three device-independent bitmap (DIB) functions, CreateDIBitmap, SetDIBitsToDevice, and StretchDIBits, perform common operations on DIBs. If a device supports DIBs, it should set the RC_DI_BITMAP value for the dpRaster member of the GDIINFO structure and support each of these functions. The Pixel function sets or retrieves the color of a single pixel with the specified coordinates. The SaveScreenBitmap function is called frequently to save parts of the screen that have been covered by a menu, a dialog box, or some other control or window. The SelectBitmap function is called when an application selects a bitmap into its device context. The StretchBlt function is called to compress or expand the color data for a bitmap that is being copied from one location to another. If a device supports device-dependent bitmaps, it should set the RC_DI_BITMAP value for the dpRaster member of the GDIINFO structure and support the two device-dependent bitmap functions: DeviceBitmap and DeviceBitmapBits.

See Also

Enable, GDIINFO, BitBlt, BitmapBits, BITMAPINFO, BITMAPINFOHEADER, CreateDIBitmap, DeviceBitmap, DeviceBitmapBits, Pixel, SaveScreenBitmap, SelectBitmap, SetDIBitsToDevice, StretchBlt, StretchDIBits, ScanLR


Text

When Windows calls the Enable function the first time, a graphics driver should initialize the members of the GDIINFO structure that contain information about the device's text-output capabilities. The following table identifies these members and their purpose:

GDIINFO member | Purpose
dpText | Specifies the level of text support provided by the device.
dpRaster | Specifies whether or not the device supports the ExtTextOut and GetCharWidth functions.
dpCaps1 | Specifies whether or not the device is capable of drawing TrueType fonts as raster fonts..

If the device supports text output, it must set the appropriate members of the GDIINFO structure and support the following three functions: ExtTextOut and GetCharWidth.

The ExtTextOut function is called to draw a string of text on the device or to draw a string of text on a bitmap that's associated with the device. The GetCharWidth function is called to compute the width of a string of characters.

See Also

Enable, GDIINFO, ExtTextOut, GetCharWidth


Color

When Windows calls the Enable function the first time, a graphics driver should initialize the members of the GDIINFO structure that contain information about the device's color capabilities. The following table identifies these members and their purpose:

GDIINFO member | Purpose
dpNumColors | Specifies the number of colors (or pens, in the case of plotters) supported by the device.
dpRaster | Specifies whether or not the device is palette capable.
dpNumPalReg | Specifies the total number of simultaneous colors which can be displayed on a palette-capable device.
dpPalReserved | Specifies the number of palette entries that are reserved for system colors. (This member is only required for palette capable devices.)
dpColorRes | Specifies the number of bits required to identify an entry in the palette.

As a minimum, all drivers must specify the number of supported colors by setting the dpNumColors member of the GDIINFO structure; in addition, all drivers must specify whether or not the device is palette capable by setting the appropriate value for the dpRaster member. However, the remaining members of the GDIINFO structure should only be set by drivers that support palette-capable devices.

In addition to setting the appropriate members of the GDIINFO structure, every graphics driver must support the ColorInfo function. However, only drivers for palette-capable devices must support the remaining five color functions: GetPalette, GetPalTrans, SetPalette, SetPalTrans, and UpdateColors.

The ColorInfo function converts an RGB value into a physical color value or converts a physical color-value into an RGB value. A physical color value is an index into a device's color table. The GetPalette function retrieves the RGB values that correspond to a specified range of indices in a device's palette. The GetPalTrans function retrieves a copy of the driver's palette-translation table. The SetPalette function sets one or more entries in a device's palette. The SetPalTrans function creates an inverse of the driver's palette translation table. The UpdateColors function uses the current translation-table colors to update a rectangular region on a video display.


Miscellaneous

There are two functions that do not fit any of the above categories: Control and ExtDeviceMode. Both of these functions are supported primarily by printer drivers. The Control function processes device-specific extensions which are called escapes at the application level. The ExtDeviceMode function displays a driver-supplied dialog box which allows the user to configure the device.


Reference

This section provides detailed reference information for the graphics driver functions and structures.


Functions

The following topics describe the functions that are provided.


BitBlt

BOOL BitBlt(
  LPPDEVICE lpDestDev,
  WORD wDestX,
  WORD wDestY,
  LPPDEVICE lpSrcDev,
  WORD wSrcX,
  WORD wSrcY,
  WORD wXext,
  WORD wYext,
  long Rop3,
  LPBRUSH lpPBrush,
  LPDRAWMODE lpDrawMode
 );

Transfers bits from a rectangle on a source device to a rectangle that has the same dimensions on a destination device. The transfer is controlled by a ternary raster operation value that specifies how corresponding bits from the source, destination, and pattern in a brush are combined to form the final bits in the destination.

Returns TRUE if successful, FALSE otherwise.

lpDestDev
Address of PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
wDestX and wDestY
The x- and y-coordinate, in device units, of the origin of the rectangle on the destination device that receives the transferred bits.
lpSrcDev
Address of PDEVICE or PBITMAP structure that specifies the source device or bitmap.
wSrcX and wSrcY
The x- and y-coordinate, in device units, of the origin of the rectangle on the source device that contains the bits to transfer.
wXext and wYext
Width and height, in device units, of the rectangles on both the source and destination devices.
Rop3
A ternary raster-operation value. This value determines how BitBlt combines corresponding pixels from the source, destination, and brush that is used to produce the final pixels in the destination rectangle. This parameter can be any one of 256 ternary raster-operation values; the following lists the most common values.
Value | Meaning
SRCCOPY (0x00CC0020) | Copies source bits to the destination rectangle: Destination = Source.
SRCPAINT (0x00EE0086) Combines the source and destination bits using the bitwise OR operator:

Destination = Source | Destination.

SRCAND (0x008800C6) Combines the source and destination bits using the bitwise AND operator:

Destination = Source & Destination.

SRCINVERT (0x00660046) Combines the source and destination bits using the bitwise exclusive OR operator:

Destination = Source ^ Destination.

SRCERASE (0x00440328) Combines the source and inverse of destination bits using the bitwise AND operator:

Destination = Source & (~ Destination).

NOTSRCCOPY (0x00330008) Copies the inverse of the destination bits to the destination rectangle:

Destination = ~ Destination.

NOTSRCERASE (0x001100A6) Combines the inverse of the source and destination bits using the bitwise AND operator:

Destination = (~ Source) & (~ Destination).

MERGECOPY (0x00C000CA) Combines the source and brush bits using the bitwise AND operator:

Destination = Source & Pattern.

MERGEPAINT (0x00BB0226) Combines the destination and inverse of the source bits using the bitwise OR operator:

Destination = (~ Source) | Destination.

PATCOPY (0x00F00021) Copies the brush bits to the destination rectangle:

Destination = Pattern.

PATPAINT (0x00FB0A09) Combines the destination, pattern, and the inverse of source bits using the bitwise OR operator:

Destination = (~ Source) | Pattern | Destination.

PATINVERT (0x005A0049) Combines the pattern and destination bits using the bitwise exclusive OR operator:

Destination = Pattern ^ Destination.

DSTINVERT (0x00550009) Copies the inverse of the destination bits:

Destination = ~ Destination.

BLACKNESS (0x00000042) | Set all destination bits to black.
WHITENESS (0x00FF0062) | Set all bits to white.

lpPBrush
Address of a PBRUSH structure that specifies a physical brush. BitBlt uses this brush only if the Rop3 parameter specifies a ternary raster operation that requires the brush that is used to be combined with source or destination or both.
lpDrawMode
Address of a DRAWMODE structure that specifies the color information BitBlt needs to determine patterned brush colors and to carry color conversions and transparent copy operations.

The export ordinal for this function is 1.

A graphics driver must export the BitBlt function if the RC_BITBLT value is set in the dpRaster member of the driver's GDIINFO structure.

The lpDestDev and lpSrcDev parameters can specify the same device, and transferring bits from one part of a device to another is a valid operation. If the source and destination rectangle overlap, BitBlt must carefully transfer bits so that the transfer does not inadvertently overwrite source bits before they have been transferred to the destination.

The Rop3 parameter specifies whether bits from the source, destination, and brush are used in the transfer. If the ternary raster operation specified by Rop3 does not include the source, BitBlt ignores the source bits. If the operation does not include the destination, BitBlt replaces the original destination bits without using them to form the final bits.

If Rop3 does not include the brush, BitBlt ignores the brush. If Rop3 does include the brush, BitBlt must determine whether the brush is solid or patterned (that is, has an associated bitmap). If the brush has a bitmap, BitBlt must combine the corresponding bits of the bitmap with the source and destination bits (as specified by the raster operation) to form the final destination bits.

If the source and bitmap associated with the brush do not have the same color format as the destination, BitBlt must convert the source and brush bitmap to the destination's color format before transferring bits. BitBlt uses the text (foreground) and background colors specified by the lpDrawMode parameter to convert colors.

To convert a monochrome bitmap to a color bitmap, BitBlt converts white bits (1) to the background color and converts black bits (0) to the text (foreground) color.

To convert a color bitmap to a monochrome bitmap, BitBlt converts all pixels that match the background color to white (1), and converts all other pixels to black (0).

In some device drivers, BitBlt must check the bkMode member of the DRAWMODE structure pointed to by the lpDrawMode parameter as well as the Rop3 parameter to determine how to carry out the transfer. If the bkMode member specifies the background mode TRANSPARENT1, BitBlt must not transfer source and brush bits that have the same color as the destination's background color (as specified by the bkColor member of the DRAWMODE structure pointed to by lpDrawMode). In other words, the corresponding destination bits must be left unchanged. Other background modes do not affect the transfer. Only device drivers that have set the C1_TRANSPARENT value in the dpCaps1 member of the GDIINFO structure are required to check the background mode.

See Also

PDEVICE, PBITMAP, DRAWMODE


BitmapBits

BOOL BitmapBits(
  LPPDEVICE lpDevice,
  DWORD fFlags,
  DWORD dwCount,
  LPSTR lpBits
 );

Sets, retrieves, or copies bitmap data.

Returns the number of bits copied.

lpDevice
Address of a PDEVICE or PBITMAP structure that specifies a device or memory bitmap.
fFlags
Flag that specifies whether to set, retrieve, or copy bitmap data. Can be one of these values:
DBB_SET (1) | Sets bitmap bits by copying data from the buffer pointed to by the lpBits parameter to the specified device.
DBB_GET (2) | Retrieves bitmap bits by copying data from the specified device to the buffer pointed to by lpBits.
DBB_COPY (4) | Copies bitmap bits from the bitmap pointed to by lpBits to the specified device.
DBB_SETWITHFILLER (8) | Identical to DDB_SET unless the bitmap is larger than 64K bytes (as specified by the lpDevice member of the PBITMAP structure). If the bitmap is larger than 64K bytes, scanlines are never broken across segments. Instead, the last bytes of each segment are used for padding and should be ignored by the driver.

dwCount
Number of bits to copy.
lpBits
Address of a buffer or a bitmap, depending on the value of the fFlags parameter. If fFlags is DBB_SET or DBB_GET, this parameter points to a buffer that contains or receives the bits for the specified bitmap. If fFlags is DBB_COPY, this parameter points to a device bitmap.

The export ordinal for this function is 30.

A graphics driver must export a BitmapBits function if the RC_DEVBITS bit is set in the dpRaster member of the device driver's GDIINFO structure.

When the fFlags parameter is set to DBB_COPY (4), the dwCount parameter passed from GDI is set to 0 and should be ignored by the driver. In this case, the driver should copy all of the bitmap pointed to by lpBits to the bitmap that lpDevice points to.

See Also

PDEVICE, PBITMAP, GDIINFO


ColorInfo

COLORREF ColorInfo(
  LPPDEVICE lpDestDev,
  DWORD dwColorin,
  LPPCOLOR lpPColor
 );

Converts a logical color (an RGB value) to a physical color (a physical color value) or converts a physical to a logical color, depending on the value of the lpPColor parameter.

Every graphics device driver must export a ColorInfo function.

Returns the logical color (RGB value) that most closely matches the physical color either specified by dwColorin or copied to the PCOLOR structure pointed to by lpPColor.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
dwColorin
A logical or physical color, depending on the value of lpPColor parameter.
lpPColor
Address of a PCOLOR structure or is NULL. If lpPColor points to a PCOLOR structure, the function assumes that dwColorin specifies a logical color (an RGB value) and copies the physical color value that most closely matches the logical color to this structure. If lpPColor is NULL, the function assumes that dwColorin specifies a physical color and returns the logical color that matches the physical color.

The export ordinal for this function is 2.

When converting a logical color, ColorInfo chooses the best possible physical color to match the logical color and returns the RGB color value that corresponds to this physical color.

GDI uses the physical colors returned by ColorInfo to set text colors, background colors, and pixel colors using the Pixel function.

If dwColorin is a logical color, it may specify either an RGB value or a color index. If dwColorin specifies a color index (high-order byte is 0xFF), ColorInfo should return the index without carrying out a conversion. If dwColorin is a physical color, ColorInfo should return an RGB value only for static colors and return color indices for all other colors. If GDI receives a color index from ColorInfo, it uses other functions to determine the corresponding logical color.

See Also

PDEVICE, PBITMAP


Control

WORD Control(
  LPPDEVICE lpDestDev,
  WORD  wFunction,
  LPSTR lpInData,
  LPSTR lpOutData
 );

Carries out the device-specific extension specified by the wFunction parameter.

Depends on the escape function specified by the wFunction parameter. In general, positive values indicate success, negative values indicate an error, and zero can indicate either an unimplemented escape or a general error condition.

lpDestDev
Address of a PDEVICE structure that specifies the destination device.
wFunction
Escape to carry out. Although the number of wFunction values and the meaning of each value depends on the driver, GDI reserves a number of values to specify predefined escapes.
lpInData
Address of escape-specific input data.
lpOutData
Address of escape-specific output data.

The export ordinal for this function is 3.

GDI calls Control when an application calls the Escape function (GDI.38). For this reason, the device-specific extensions are also called escapes.

Every graphics driver must export a Control function.

The Control function should always return zero for escapes that are unimplemented or unrecognized. The function should return the number of bytes copied if it copies data to a buffer pointed to by the lpOutData parameter, or if the lpOutData parameter is NULL, it should return the size in bytes of the buffer it requires to copy data.

GDI modifies some escapes before calling the Control function.

See Also

PDEVICE


CreateDIBitmap

WORD CreateDIBitmap(void);

Creates a DIB.

No return value.

The export ordinal for this function is 20.

A graphics-device driver must export the CreateDIBitmap function if the RC_DI_BITMAP value is set in the dpRaster member of the driver's GDIINFO structure.

Because GDI does not currently use CreateDIBitmap, implement the function as a stub function that carries out no action and always returns zero.

See Also

GDIINFO


DeviceBitmap

WORD DeviceBitmap(
  LPPDEVICE lpDestDev,
  WORD wCommand,
  LPBITMAP lpBitmap,
  LPSTR lpBits
 );

Performs the specified action on a device bitmap.

Always returns zero.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
wCommand
Command identifier that specifies the action to take.
lpBitmap
Address of a PBITMAP structure that contains a description of the device bitmap.
lpBits
Address of a buffer that contains the bits for the device bitmap.

The export ordinal for this function is 16.

Every graphics driver must export a DeviceBitmap function.

Because GDI does not currently use DeviceBitmap, implement the function as a stub function that carries out no action and always returns zero.

See Also

PDEVICE, PBITMAP


DeviceBitmapBits

void DeviceBitmapBits(
  LPPDEVICE lpBitmap,
  WORD fGet,
  WORD iStart,
  WORD cScans,
  LPSTR lpDIBits,
  LPBITMAPINFO lpBitmapInfo,
  LPDRAWMODE lpDrawMode,
  LPINT lpTranslate
 );

Either copies DIB to a device-specific bitmap or copies a device-specific bitmap to a DIB. The fGet parameter specifies which operation to carry out.

Returns one of these values:

>0 | Number of scanlines set or retrieved.
0 | Error.
-1 | Bits cannot be set or retrieved.

lpBitmap
Address of a PBITMAP structure that specifies a device-specific memory bitmap.
fGet
Flag that specifies whether the function sets or retrieves bitmap bits. If this parameter is zero, the function sets the bits; if the parameter is 1, the function retrieves the bits.
iStart
Starting scan number.
cScans
Number of scans to set or retrieve.
lpDIBits
Address of a buffer that contains or receives the bitmaps bits. If the fGet parameter is zero, the function copies data from the buffer into the bitmap; if fGet is 1, the function copies the bits to the buffer from the bitmap. If this parameter is NULL, the function fills the biSizeImage member in the BITMAPINFO structure pointed to by the lpBitmapInfo parameter, but does not copy bitmap bits.
lpBitmapInfo
Address of a BITMAPINFO structure that specifies the dimensions and format of the DIB.

The function must check the biPlanes and the biBitCount members. If biPlanes is not 1 or biBitCount is not 1, 4, 8, or 24, the function returns an error value.

The function compares the widths of the device-specific bitmap and the DIB. If the widths are not equal, the function clips to the smaller of the two bitmaps.

If the RLE_FORMAT_4 or RLE_FORMAT_8 values are set in the biCompression member of the BITMAPINFO structure, the DIB is in RLE format. In this case, the function must encode each scan line as it copies the scan line data to the buffer pointed to by lpDIBits or the function must decode the data as it retrieves it from the buffer.

lpDrawMode
Address of a DRAWMODE structure that specifies the text (foreground) and background colors to use if color conversion is required.
lpTranslate
Address of an array of color translation values for converting palette colors to actual device colors. This parameter is ignored by devices that do not use color palettes.

The export ordinal for this function is 19.

A graphics driver must export a DeviceBitmapBits function if the RC_DI_BITMAP value is set in the dpRaster member of the driver's GDIINFO structure.

Depending on the operation specified by the fGet parameter, DeviceBitmapBits either converts the bits pointed to by lpDIBits to the format required by the bitmap specified by the lpBitmap parameter or converts the bits pointed to by lpDIBits to the format required by lpBitmap. To convert the bits, the function computes the width and height of the bitmap to copy, determines if color conversion is necessary, and prepares for scan lines that cross the 64K boundaries.

DeviceBitmapBits checks the color formats of the bitmap specified by lpBitmap and the DIB specified by lpBitmapInfo. If the color formats are not the same, the function must convert the bitmap pixels to the same format as the destination. For example, if the function copies a DIB to a monochrome bitmap, the function must convert color pixels to monochrome. In this case, DeviceBitmapBits converts all pixels that match the background color (as specified by the lpDrawMode parameter) to white (1), and converts all other pixels to black (0).

To prepare for color conversion when fGet is zero, the function maps color-table information (if any) provided in the BITMAPINFO structure to the device-specific colors. If the biClrUsed member is zero, the function must use a default color table. The size of the default table depends on the number of bits per pixel (that is, 16 colors for 4 bits-per-pixel, 256 colors for 8 bits-per-pixel, and so on). However, if biClrUsed is nonzero, the member specifies the size of the table; this size cannot be more than the default size. Because the default color table for a bitmap having 24 bits per pixel is exceptionally large, the function carries out the color mapping as it converts the bits rather than generating a table.

To prepare for color conversion when fGet is 1, the function creates the logical-color table and copies it to the BITMAPINFO structure. If the device driver does not support a color palette, the function fills the logical-color table with whatever color it supports and use the corresponding indices in the bitmap. It must also set the number of colors it is using in the biClrUsed member of the BITMAPINFO structure. For example, if the display device is a four-plane device (16 colors) but the request is for a DIB that has 8 bits-per-pixel (256 colors), the function can specify just 16 colors and set the biClrUsed member to 16, or it can set remaining colors (entries 16 through 255) to zero and set the biClrUsed member to zero.

See Also

PBITMAP, BITMAPINFO, DRAWMODE


Disable

void Disable(
  LPPDEVICE lpDestDev
 );

Disables the specified device. Every graphics driver must export a Disable function.

No return value.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.

The export ordinal for this function is 4.

GDI calls this function when it deletes a device or information context for an application, or when it saves the context in preparation for Windows to switch to a full-screen application.

See Also

Enable, PDEVICE, PBITMAP


Enable

WORD Enable(
  LPVOID lpDevInfo,
  WORD wAction,
  LPSTR lpDestDevType,
  LPSTR lpOutputFile,
  LPVOID lpData
 );

Initializes software and hardware for the specified driver. Every graphics driver must export an Enable function.

Returns TRUE if successful, FALSE otherwise.

lpDevInfo
Address of a PDEVICE or GDIINFO structure depending on the value of the wAction parameter.
wAction
The initialization action. Can be one of these values:
0x0000 | Initializes the driver and associated hardware and then copies device-specific information needed by the driver to the PDEVICE structure pointed to by lpDevInfo.
0x0001 | Copies the device driver information to the GDIINFO structure pointed to by lpDevInfo.
0x8000 | Initializes the PDEVICE structure pointed to by lpDevInfo, but does not initialize the driver and peripheral hardware.
0x8001 | Same as 0x0001.

GDI sets the high order bit of wAction only if an application has requested an information context.

lpDestDevType
Address of a string that specifies the device name. This string applies only to device drivers that support more than one model of the same device. This parameter can be NULL if only one model is supported.
lpOutputFile
Address of a string that specifies the name of the output port or file to receive output from the driver. The string must be a valid MS-DOS filename. This parameter must be NULL for the display.
lpData
Address of DEVMODE structure that contains information Enable uses to initialize the device. This parameter must be NULL for the display.

The export ordinal for this function is 5.

In some cases, GDI may request a raster device to write to a memory bitmap without enabling the device first. This occurs only with raster devices that can write to memory bitmaps.

GDI calls this function when it creates a device or information context for an application, or when it restores the context after Windows returns from a full-screen application.

For most devices, GDI calls Enable twice: first, to retrieve the driver's GDIINFO structure, and second, then to initialize the device and the PDEVICE structure.

See Also

DEVMODE, Disable, GDIINFO, PDEVICE


EnumDFonts

WORD EnumDFonts(
  LPPDEVICE lpDestDev,
  LPSZ lpFaceName,
  FARPROC lpCallbackFunc,
  LPVOID lpClientData
 );

Returns information about device fonts by passing the information to the specified callback function.

Returns the last value that the callback function returned. If there are no fonts with the specified name, the function returns 1.

lpDestDev
Address of a PDEVICE or PBITMAP structure.
lpFaceName
Address of the null-terminated string that specifies the name of a font. If this parameter points to a name, EnumDFonts calls the callback function with information for the fonts having the same font name. If there are no fonts of that name, the function returns 1.

If lpFaceName is NULL, EnumDFonts randomly selects one font of each name and calls the callback function with information for these fonts. If there are no fonts, the function returns 1.

lpCallbackFunc
Address of a user-supplied callback function.
lpClientData
Address of a buffer that contains user-supplied data. EnumDFonts does not use this data; instead, it passes the data back to the application through the callback function.

The export ordinal for this function is 6.

GDI calls this function when processing the EnumDFonts function to determine what device fonts are available.

Every graphics driver must export an EnumDFonts function.

EnumDFonts calls the callback function once for each font. It continues to call the callback function until there are no more fonts, or the callback function returns zero.

If the device can generate scaled, bold, or italic fonts, EnumDFonts should pass only the information about the base font to the callback function. EnumDFonts should then leave it to the application to inquire about the device's text transformation capabilities.

See Also

PDEVICE, PBITMAP, EnumDFontsCallback


EnumDFontsCallback

WORD EnumDFontsCallback(
  LPLOGFONT lpLogFont,
  LPTEXTMETRICS lpTextMetrics,
  WORD wFontType,
  LPVOID lpClientData
 );

Enumerates the available fonts on a device.

Returns a nonzero value to continue enumeration; to stop enumeration, it must return zero.

lpLogFont
Address of an LOGFONT structure defining the logical attributes of a font. All sizes are in device units.
lpTextMetrics
Address of a TEXTMETRIC structure that contains the same values that would be returned by the GetTextMetrics (GDI.93) function. All sizes are in device units.
wFontType
Font type. Can be one of these values:
RASTER_FONTTYPE (1) | Font consists of raster bitmaps rather than vector strokes.
DEVICE_FONTTYPE (2) | Font is provided by the device rather than GDI.
ENGINE_FONTTYPE (4) | Font is provided by TrueType rather than GDI or device.

Bit 3 in the wFontType parameter is reserved; must be zero.

lpClientData
Address of the user-supplied data passed to EnumDFonts.

The callback function must return a nonzero value to continue to receive information about the fonts. If the callback function returns zero, EnumDFonts stops enumerating the fonts and returns to GDI.

See Also

EnumDFonts, LOGFONT, TEXTMETRIC


EnumObj

WORD EnumObj(
  LPPDEVICE lpDestDev,
  WORD wStyle,
  FARPROC lpCallbackFunc,
  LPVOID lpClientData
 );

Enumerates the pens and brushes available on the device.

Returns the last value that the callback function returned if successful. Otherwise it is 1.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
wStyle
Object type. Can be one of these values:
OBJ_PEN (1) | Pen
OBJ_BRUSH (2) | Brush
OBJ_FONT (3) | Font

EnumObj enumerates all objects of the given type. If there are no objects of the given type, the function must return 1.

lpCallbackFunc
Address of the user-supplied callback function.
lpClientData
Address of the user-supplied data.

The export ordinal for this function is 7.

GDI calls the EnumObj function when an application calls the EnumObjects function. For each object having the given style, EnumObj calls the callback function with the logical information for that object. EnumObj continues to call the callback function until there are no more objects or the callback function returns zero.

Every graphics driver must export an EnumObj function.

Before calling the callback function, EnumObj must fill the LOGPEN or LOGBRUSH structure with the logical colors and other values that correspond to a given physical pen or brush.

To support some older applications (such as Microsoft Excel versions earlier than 2.1), EnumObj specifies the 8 default EGA colors in the first 8 objects it enumerates:

EGA color | RGB value
Black | 0,0,0
White | 0xFF,0xFF,0xFF
Red | 0xFF,0,0
Green | 0,0xFF,0
Blue | 0,0,0xFF
Yellow | 0xFF,0xFF,0
Magenta | 0xFF,0,0xFF
Cyan | 0,0xFF,0xFF

If the driver supports additional colors, EnumObj can specify those colors in any order. Because some applications end after enumerating the first 16 colors, the second 8 colors to be enumerated should be the most desirable colors for the device.

EnumObj should enumerate solid pens before styled lines. Enumerating styled pens is optional. The function should enumerate: solid pens, styled pens (optional), solid brushes (no dithered colors), and hatched brushes.

EnumObj does not need to specify the background colors for hatched brushes.

See Also

PDEVICE, PBITMAP, LOGBRUSH, LOGPEN, EnumObjCallback


EnumObjCallback

WORD EnumObjCallback(
  LPVOID lpLogObj,
  LPSTR lpClientData
 );

Enumerates the logical objects requested by the EnumObj function.

Returns a nonzero value to continue enumeration; to stop enumeration, it must return zero.

lpLogObj
Address of a LOGPEN or LOGBRUSH structure, depending on the wStyle parameter.
lpClientData
Address of the user-supplied data passed to EnumObj.

See Also

LOGBRUSH, LOGPEN


ExtDeviceMode

int ExtDeviceMode(
  HWND hWnd,
  HANDLE hDriver,
  LPDEVMODE lpDevModeOutput,
  LPSTR lpDeviceName,
  LPSTR lpPort,
  LPDEVMODE lpDevModeInput,
  LPSTR lpProfile,
  WORD  wMode
 );

Retrieves or modifies device-initialization information for a given graphics driver, or displays a driver-supplied dialog box for configuring the graphics driver. Applications call the ExtDeviceMode function when the user requests setting up the printer as part of preparing for a print job.

All printer drivers must export the ExtDeviceMode function.

If the wMode parameter is zero, the return value is the size of the DEVMODE structure required to contain the printer-driver initialization data. If the function displays the initialization-dialog box, the return value is either IDOK or IDCANCEL, depending on which button the user chose. If the function does not display the dialog box and was successful, the return value is IDOK. The return value is less than zero if the function failed.

hWnd
Parent window for the dialog box.
hDriver
Module instance of the device driver.
lpDevModeOutput
Address of a DEVMODE structure. The driver writes the initialization information supplied in the lpDevModeInput parameter to this structure.
lpDeviceName
Address of a null-terminated string that contains the name of the device, such as PCL/HP LaserJet.
lpPort
Address of a null-terminated string that contains the name of the port to which the device is connected, such as LPT1.
lpDevModeInput
Address of a DEVMODE structure that contains initialization information set by the application.
lpProfile
Address of a null-terminated string that contains the name of the initialization file in which initialization information is recorded and read from. If this parameter is NULL, the [Model Name, Port] section of the WIN.INI file is the default.
wMode
Which operations the function will perform. If the wMode parameter is zero, ExtDeviceMode returns the number of bytes required by the device driver's DEVMODE structure. Otherwise, wMode can be a combination of the following values:
DM_UPDATE (1) | Writes the driver's current settings to the environment and the WIN.INI initialization file.
DM_COPY (2) | Writes the driver's current settings to the DEVMODE structure identified by the lpDevModeOutput parameter. The calling application must allocate a buffer sufficiently large to contain the information. If this bit is clear, lpDevModeOutput can be NULL.
DM_PROMPT (4) | Presents the driver's dialog box and then changes the current settings according to user specifications.
DM_MODIFY (8) | Changes the printer driver's current settings to match the partial initialization data in the DEVMODE structure identified by lpDevModeInput before prompting, copying, or updating the printer driver's setting.

The export ordinal for this function is 90.

If wMode includes DM_PROMPT, the ExtDeviceMode function creates an application-modal dialog box using the DialogBox function (USER.240). The dialog box must provide options for the user to set the various settings of the device.

ExtDeviceMode does the following

  1. Initializes the dialog box settings by using the environment specified by lpDevModeInput, by retrieving the current environment using the GetEnvironment function (GDI.133), or by reading the environment from the corresponding, device-specific section in the WIN.INI file.
  2. Calls the DialogBox box to display the dialog box, then waits for the user to complete their changes. When the value returns from DialogBox, check the return value. Make subsequent updates only if the return value is IDOK.
  3. Updates the current device environment by using the SetEnvironment function (GDI.132). Also, it updates the corresponding device-specific section in the WIN.INI file (or specified initialization file) if wMode includes DM_UPDATE.
  4. Sends a WM_DEVMODE message to all applications informing them of a change to the device's operating modes.

The dialog box must provide at least a title bar and OK and Cancel buttons in addition to controls for the various operating modes. The title bar should contain the name of the current printer model (if the driver supports several models), but no other printer model information should be presented in the dialog box. (The ExtDeviceMode dialog box cannot permit the user to change device models.)

If a device has too many options to fit in a single dialog box, ExtDeviceMode can provide nested dialog boxes, using buttons in the first dialog box to access the others. In all cases, a dialog function for a ExtDeviceMode dialog box must close the dialog box if it receives a WM_COMMAND message with the wParam parameter set to IDCANCEL. This message occurs when the user presses the ESC key, chooses the Cancel button in the dialog box, or when Windows Help needs to close the dialog box in order to respond to a request for help from another application.


ExtTextOut

DWORD ExtTextOut(
  LPPDEVICE lpDestDev,
  WORD wDestXOrg,
  WORD  wDestYOrg,
  LPRECT lpClipRect,
  LPSZ lpString,
  int wCount,
  LPFONTINFO lpFontInfo,
  LPDRAWMODE lpDrawMode,
  LPTEXTXFORM lpTextXForm,
  LPSHORT lpCharWidths,
  LPRECT lpOpaqueRect,
  WORD wOptions
 );

Writes text strings by converting characters in a given string into raster, vector, or outline glyphs and copying the glyphs to the given device or bitmap.

If the wCount parameter is negative, this function returns the x and y extents of the string's bounding rectangle; the x extent is in the low-order 16 bits and the y extent in the high-order 16 bits. If the x extent exceeds the maximum value for an extent (0x7FFF), the function returns 0x7FFF in the low-order 16 bits and wDestXorg in the high-order 16 bits.

If wCount is zero, the return value is TRUE if the specified rectangle was filled with the background color. If wCount is positive, the return value is TRUE if the text was output successfully. In all other cases, the return value is 0x80000000L if an error occurred or no output was generated.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the device or bitmap to receive the text output.
wDestXOrg and wDestYOrg
Coordinates, in device units, of the starting point for the string.
lpClipRect
Address of a RECT structure that specifies the clipping rectangle.
lpString
Address of a null-terminated character string that specifies the characters to display.
wCount
Action to carry out. Can be one of these values:
<0 | Compute the x and y extents of the smallest rectangle that completely encloses the displayed string, but do not generate output. In this case, the absolute value of wCount specifies the number of characters in the string. The function uses the current font, text justification, and other factors to compute the bounding rectangle, but does not apply the clipping rectangle. The function must update the BreakErr member specified by the lpDrawMode parameter.
0 | Fill the rectangle specified by lpOpaqueRect but only if wOptions is ETO_OPAQUE. In this case, the function does not generate text output.
>0 | Draw the characters in the string. wCount specifies the number of characters to draw. The function uses the current font, text justification, escapement, rotation, and other factors to draw the characters, and it applies the clipping and opaque rectangles if specified. If the function modifies the BreakErr member specified by the lpDrawMode parameter, it must restore the member to its original value.

lpFontInfo
Address of a structure that specifies the physical font to use. If either the ETO_BYTE_PACKED or ETO_BIT_PACKED wOptions flag is set, lpFontInfo points to a NewFontSeg structure. Otherwise, lpFontInfo points to a FONTINFO structure. A display driver indicates that it is capable of handling the NewFontSeg format as well as the FONTINFO format by setting the C1_BYTE_PACKED or C1_BIT_PACKED bit in dpCaps1 of the GDIINFO structure at enable time.
lpDrawMode
Address of a DRAWMODE structure that specifies the current text color, background mode, background color, text justification, and character spacing.
lpTextXForm
Address of a TEXTXFORM structure that specifies additional information about the appearance of the characters when drawn.
lpCharWidths
Address of an array of character widths. If this parameter is not NULL, each element in the array is the advance width, in device units, of the corresponding character in the string. The function uses these widths (instead of the default character widths) to compute the position of the next character in the string. There must be one advance width for each character in the string.
lpOpaqueRect
Address of a RECT structure that specifies the opaquing rectangle. This parameter can be NULL.
wOptions
Action to carry out. Can be a combination of these values:
ETO_OPAQUE (2) | Fills the rectangle specified by the lpOpaqueRect parameter (and clipped to the lpClipRect parameter) with the background color specified by the lpDrawMode parameter. The function fills the rectangle regardless of the whether lpDrawMode specifies opaque or transparent background mode.
ETO_CLIPPED (4) | Creates a new clipping rectangle by intersecting the rectangles specified by lpOpaqueRect and lpClipRect.
ETO_GLYPH_INDEX | For fonts in the format defined by the FONTINFO structure, if this flag is set, lpString points to a word array of glyph indexes into the character offset table. For fonts in the format defined by the FONTINFO structure, if this flag is clear, lpString points to a byte array and the index to the glyph in the character offset table must be computed by subtracting the index of the first character in the table. For fonts in the format defined by the NewFontSeg structure, if this flag is set, lpString points to a word array of glyph indexes into the character offset table. For fonts in the format defined by the NewFontSeg structure, if this flag is clear, lpString points to a byte array of glyph indexes into the character offset table.
ETO_BYTE_PACKED | Indicates the font is in the format defined by the NewFontSeg structure. The glyphs are byte-packed, meaning they are stored in rows where each row is padded out to a byte boundary.
ETO_BIT_PACKED | Indicates the font is in the format defined by the NewFontSeg structure. The glyphs are bit-packed, meaning they are stored in rows with no padding.
ETO_LEVEL_MODE | Indicates that the background mode specified in lpDrawMode ->bkMode is set to one of the blending levels used for anti-aliasing.

If neither ETO_BYTE_PACKED or ETO_BIT_PACKED is set, the font is in the format defined by the FONTINFO structure.

The export ordinal for this function is 14.

Depending on the value of its parameters, the ExtTextOut function also computes the x and y extents of the bounding rectangle of the displayed string, clips the text to fit a given clipping rectangle, fills a given rectangle with the specified background color before copying glyphs, and overrides the default spacing of the glyphs using values specified in an array of character widths.

GDI may call ExtTextOut if an application calls the TextOut function, the ExtTextOut function, or GetTextExtent function.

A graphics driver must export the ExtTextOut function.

ExtTextOut places the upper-left corner of the string at the point defined by the DestYOrg parameter. This means that the characters in the string appear below and to the right of the starting point. In some cases, character glyphs may overlap, especially if widths specified in lpCharWidths are less than the default widths or are negative.

ExtTextOut uses the drawing mode specified by lpDrawMode to determine the current text color, the background mode, and the background color. The background mode determines whether ExtTextOut draws an opaque bounding box before drawing the characters. The background color determines what color that box must be. The text color determines the color of the text in the box. For raster glyphs, all 1 bits must be the text color; for vector and outline glyphs, lines and filled areas must be the text color. ExtTextOut does not use the binary-raster operation mode (specified by the Rop2 member in the DRAWMODE structure pointed to by the lpDrawMode parameter) when drawing text.

ExtTextOut clips text to the rectangle specified by lpClipRect, or to the intersection of lpClipRect and lpOpaqueRect if wOptions specifies ETO_CLIPPED. Only pixels within the rectangle are drawn. (Pixels that have the same x-coordinate as the rectangle's right edge, or the same y-coordinate as the rectangle's bottom edge are not in the rectangle.) For example, no pixels are drawn if the clipping rectangle is empty (zero width and height), and only one pixel is drawn if it has a width and height of 1.

ExtTextOut uses the lpTextXForm parameter only if the device supports the additional text transformation capabilities. For example, if lpTextXForm specifies a point size different from the one specified by lpFontInfo, ExtTextOut should ignore the lpTextXForm point size unless the function can size characters. Text transformation capabilities are specified in the dpText member of the driver's GDIINFO structure.

If the TBreakExtra or CharExtra members in the DRAWMODE structure pointed to by the lpDrawMode parameter is nonzero, ExtTextOut must adjust widths of break characters or other characters using the following or similar algorithm:

int width;  // width of character

for (i=0; i<wCount; i++) {

    // Set width here using the default character for lpString[i].
    // The default width and how to retrieve it depends
    // on the font.

  if ((lpDrawMode->TBreakExtra != 0) &&
      (lpString[i]==lpFont->dfBreakChar)) {
      width = width + lpDrawMode->BreakExtra;
      lpDrawMode->BreakErr=lpDrawMode->BreakErr-lpDrawMode->BreakRem;
      if (lpDrawMode->BreakErr <= 0) {
              width = width ++
              BreakErr = BreakErr + BreakCount
      }
  }
  width = width + lpDrawMode->CharExtra;
}

See Also

DRAWMODE, FONTINFO, PDEVICE, PBITMAP, TEXTXFORM, RECT


GetCharWidth

WORD GetCharWidth(
  LPPDEVICE lpDestDev,
  LPWORD lpBuffer,
  WORD wFirstChar,
  WORD wLastChar,
  LPFONTINFO lpFontInfo,
  LPDRAWMODE lpDrawMode,
  LPTEXTXFORM lpFontTrans
 );

Computes the widths of each character within the given range, and copies the widths to the buffer pointed to by the lpBuffer parameter.

The return value is 1 if the function is successful, otherwise it is zero.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
lpBuffer
Address of the buffer that receives the character widths. The buffer must be an array of 16-bit elements. There must be one element for each character in the range.
wFirstChar and wLastChar
First and last characters of the range.
lpFontInfo
Address of a FONTINFO structure that specifies the physical font from which to compute the character widths.
lpDrawMode
Address of a DRAWMODE structure that specifies the current text color, background mode, background color, text justification, and character spacing that may need to be applied to the font to compute a character width.
lpFontTrans
Address of a TEXTXFORM structure that specifies the any font transformations, such as scaling and italicizing, that may need to be applied to the font to compute a character width.

The export ordinal for this function is 15.

GDI calls this function when an application calls the GetCharWidth function (GDI.350).

A graphics driver must export the GetCharWidth function if the RC_GDI20_OUTPUT value is set in the dpRaster member of the driver's GDIINFO structure.

The function assigns the default character to characters outside of the font's range.

GetCharWidth is an optional function for printers, but highly recommended.

See Also

PDEVICE, PBITMAP, FONTINFO, DRAWMODE, TEXTXFORM


GetPalette

VOID GetPalette(
  WORD nStartIndex,
  WORD nNumEntries,
  RGBQUAD lpPalette
 );

Retrieves the logical colors (RGB values) for the given color indices. The function copies color values in the RGB structure to the buffer pointed to by the lpPalette parameter.

No return value.

nStartIndex
Color index of the first color to retrieve.
nNumEntries
Total number of entries to retrieve from the device's hardware palette.
lpPalette
Address of the buffer to receive the RGB colors.

The export ordinal for this function is 23.

A graphics driver must export the GetPalette function if the RC_PALETTE value is set in the dpRaster member of the driver's GDIINFO structure.


GetPalTrans

void GetPalTrans(
  LPWORD lpIndexes
 );

Copies the driver's translation table into the array pointed to by the lpIndexes parameter.

No return value.

lpIndexes
Address of the array to receive color indices. The number of indices in the array is specified by the dpNumPalReg member in the device's GDIINFO structure.

The export ordinal for this function is 25.

A graphics driver must export the GetPalTrans function if the RC_PALETTE value is set in the dpRaster member of the driver's GDIINFO structure.


Output

WORD Output(
  LPPDEVICE lpDestDev,
  WORD wStyle,
  WORD wCount,
  LPPOINT lpPoints,
  LPPEN lpPPen,
  LPPBRUSH lpPBrush,
  LPDRAWMODE lpDrawMode,
  LPRECT lpClipRect
 );

Draws the lines and figures specified by the wStyle parameter.

Returns one of these values:

1 | Function was successful.
0 | Unrecoverable error occurred.
-1 | Function does not support the specified style.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
wStyle
Type of output to draw. Can be one of these values:
OS_ALTPOLYGON (22) | Draws a polygon and fills it using the alternate-filling method.
OS_ARC (3) | Draws an arc.
OS_BEGINNSCAN (80) | Begins a series of scan lines.
OS_CHORD (39) | Draws a closed figure consisting of an arc and the chord connecting the endpoints of the arc.
OS_CIRCLE (55) | Draws a circle.
OS_ELLIPSE (7) | Draws an ellipse.
OS_ENDNSCAN (81) | Ends a series of scan lines.
OS_PIE (23) | Draws a closed figure consisting of an arc and two line segments connecting the endpoints of the arc to the centerpoint of the arc's bounding rectangle.
OS_POLYBEZIER (1) | Draws a Bezier spline.
OS_POLYLINE (18) | Draws a set of connected line segments.
OS_POLYSCANLINE (5) | Draws a set of horizontal line segments.
OS_RECTANGLE (6) | Draws a rectangle.
OS_ROUNDRECT (72) | Draws a rectangle with round corners.
OS_SCANLINES (4) | Draws a set of horizontal line segments.
OS_WINDPOLYGON (20) | Draws a polygon and fill it using the winding-number-filling method.

For a full description of each style, see the following Output descriptions.

wCount
Number of POINT structures in the array pointed to by the lpPoints parameter.
lpPoints
Address of an array of POINT structures. The array has wCount elements. For most output styles, this parameter contains the device coordinates for each point in the figure.
lpPPen
Address of a PPEN structure that specifies the physical pen that is used to use to draw lines and borders. This parameter is NULL if no lines or borders are to be drawn.
lpPBrush
Address of a PBRUSH structure that specifies the physical brush that is used to use to fill the interiors of figures and draw scan lines. This parameter is NULL if no interiors or scan lines are to be drawn.
lpDrawMode
Address of a DRAWMODE structure that contains information to use when drawing, such as binary-raster operation, background mode, and foreground and background color.
lpClipRect
Address of a RECT structure that contains coordinates for the clipping rectangle. If this parameter is NULL, the clipping rectangle is the entire display surface.

The export ordinal for this function is 8.

GDI calls this function when an application calls functions, such as LineTo, Rectangle, and Ellipse.

Every graphics driver must export an Output function.

Output uses the binary-raster operation, background mode, and background color specified by the DRAWMODE structure to draw lines and scan lines. Output uses the binary-raster operation to determine how to combine pen or brush colors with the existing color on the display surface. The function uses background mode to determine how to fill gaps in styled lines or hatched brushes. If the background mode is OPAQUE, Output combines the background color with the existing color in the gaps. If the background mode is TRANSPARENT, Output leaves the existing color unchanged. For all pen or brush styles other than styled lines and hatched brushes, Output draws as if the background mode is OPAQUE regardless of the actual background mode.

Output uses the lpClipRect parameter only if the driver has set either the CP_RECTANGLE or CP_REGION value in the dpClip member of the GDIINFO structure. Output ensures that the coordinates specified by the lpClipRect parameter do not extended beyond the boundaries of the display surface.

See Also

DRAWMODE, PDEVICE, PBITMAP, POINT, RECT


Output(OS_ALTPOLYGON)

WORD Output(
  LPPDEVICE lpDestDev,
  WORD wStyle,
  WORD wCount,
  LPPOINT lpPoints,
  LPPEN lpPPen,
  LPPBRUSH lpPBrush,
  LPDRAWMODE lpDrawMode,
  LPRECT lpClipRect
 );

Draws a polygon and fills it using the alternate-filling method.

Returns one of these values:

1 | Function was successful.
0 | Unrecoverable error occurred.
-1 | Function does not support specified style.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
wStyle
Must be OS_ALTPOLYGON.
wCount
Count of POINT structures in the array pointed to by lpPoints.
lpPoints
Address of an array of POINT structures that contains wCount elements. Each point represents a vertex of the polygon.
lpPPen
Address of a PPEN structure that specifies the physical pen that is used to draw the border of the polygon.
lpPBrush
Address of a PBRUSH structure that specifies the physical brush that is used to fill the polygon.
lpDrawMode
Address of a DRAWMODE structure that contains the drawing information to draw and fill the polygon.
lpClipRect
Address of a RECT structure that contains coordinates for the clipping rectangle. If the lpClipRect parameter is NULL, the clipping rectangle is the entire display surface.

Output fills the interior of the polygon first, then draws the border.

To fill the polygon, Output calculates the polygon outline and fills it according to the alternate-filling method. Alternate filling typically fills every other closed area within a polygon. In general, a given area should be filled if a horizontal ray, starting in the area and continuing through the left edge of the polygon, crosses an odd number of polygon sides.

To draw the border, Output draws a line segment from the first point in the array to the second, from the second to the third, and so on. If the last line segment does not end at the first point, Output draws this line segment to ensure a closed figure.

Although Output can use device hardware to draw and fill polygons, the function either must provide the same capability when drawing to a main memory bitmap, or return a value of -1 to direct GDI to simulate the output using polylines and scan lines.

GDI calls Output with this style when an application calls functions, such as the Polygon function (GDI.36), and the current polygon-filling mode is ALTERNATE.

The graphics driver can support the OS_ALTPOLYGON style if the PC_ALTPOLYGON bit is set in the dpPolygonals member of the GDIINFO structure.

See Also

Output(OS_POLYPOLYGON), Output(OS_WINDPOLYGON), PDEVICE, PBITMAP, DRAWMODE, RECT, POINT


Output(OS_ARC)

WORD Output(
  LPPDEVICE lpDestDev,
  WORD wStyle,
  WORD wCount,
  LPPOINT lpPoints,
  LPPPen lpPPen,
  LPPBRUSH lpPBrush,
  LPDRAWMODE lpDrawMode,
  LPRECT lpClipRect
 );

Draws the arc that lies between calculated endpoints on the specified ellipse.

Returns any of the following values:

1 | Function was successful.
0 | Unrecoverable error occurred.
-1 | Function does not support specified style.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
wStyle
Must be OS_ARC.
wCount
Must be 5.
lpPoints
Address of an array that contains five POINT structures:
Index | Description
0 | Upper-left corner of the bounding rectangle.
1 | Lower-right corner of the bounding rectangle.
2 | Starting point for the arc.
3 | Ending point for the arc.
4 | Start and stop angles. Reserved; do not use.

lpPPen
Address of a PPEN structure that specifies the physical pen that is used to draw the arc.
lpPBrush
Address of a PBRUSH structure. This parameter is not used to draw an arc.
lpDrawMode
Address of a DRAWMODE structure that contains drawing information that is used to draw the arc.
lpClipRect
Address of a RECT structure that contains coordinates for the clipping rectangle. If the lpClipRect parameter is NULL, the clipping rectangle is the entire display surface.

Output draws an arc by drawing a portion of the ellipse contained in the specified bounding rectangle. The function calculates the endpoints of the arc using the starting and ending points; each endpoint is the intersection of the ellipse and a ray drawn from the center of the bounding rectangle through the specified starting or ending point. Output draws the arc in a counterclockwise direction, from starting point up to, but not including, the ending point.

A graphics driver must support the OS_ARC style if the CC_ELLIPSES or CC_CIRCLES value is set in the dpCurves member of the GDIINFO structure.

See Also

PDEVICE, PBITMAP, DRAWMODE, RECT, POINT


Output(OS_BEGINNSCAN)

WORD Output(
  LPPDEVICE lpDestDev,
  WORD wStyle,
  WORD wCount,
  LPPOINT lpPoints,
  LPPPen lpPPen,
  LPPBrush lpPBrush,
  LPDRAWMODE lpDrawMode,
  LPRECT lpClipRect
 );

Prepares for a subsequent series of calls to the Output function in which the OS_SCANLINES or OS_POLYSCANLINE style is specified.

Returns 1 if the function is successful.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
wStyle
Must be OS_BEGINNSCAN
wCount
Must be 0.
lpPoints
Must be NULL.
lpPPen
Address of a PPEN structure that specifies the physical pen that is used to draw subsequent scan lines. If it is NULL, no pen is used.
lpPBrush
Address of a PBRUSH structure that specifies the physical brush that is used to draw subsequent scan lines. If it is NULL, no brush is used.
lpDrawMode
Address of a DRAWMODE structure that contains drawing information when drawing subsequent scan lines.
lpClipRect
Must be NULL.

Every graphics driver (for Windows versions 2.0 and later) should support the OS_BEGINNSCAN style.

GDI uses the OS_BEGINNSCAN and OS_ENDNSCAN styles to mark the beginning and end of a series of scan lines that use the same pen, brush, and drawing mode. GDI calls Output with the OS_BEGINNSCAN style to let the driver prepare the drawing mode and the physical pen and brush for use in subsequent calls that contains the OS_SCANLINE style. Drivers that preserve these objects between calls to Output can improve performance by minimizing the number of times the objects need to be set up. All subsequent calls using the OS_SCANLINE style will use the same objects until GDI calls with a matching OS_ENDNSCAN style.

If a driver does not support the OS_BEGINNSCAN style, the driver can ignore the style. In all cases, GDI passes the physical pen, physical brush, and drawing mode upon each subsequent call to Output regardless of whether the driver previously prepared these objects.

See Also

Output(OS_ENDNSCAN), PDEVICE, PBITMAP, DRAWMODE, RECT, POINT


Output(OS_CHORD)

WORD Output(
  LPPDEVICE lpDestDev,
  WORD wStyle,
  WORD wCount,
  LPPOINT lpPoints,
  LPPPEN lpPPen,
  LPPBRUSH lpPBrush,
  LPDRAWMODE lpDrawMode,
  LPRECT lpClipRect
 );

Draws an arc and the chord connecting the endpoints of the arc.

Returns one of these values:

1 | Function was successful.
0 | Unrecoverable error occurred.
-1 | Function does not support specified style.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
wStyle
Must be OS_CHORD.
wCount
Must be 5.
lpPoints
Address of an array that contains five POINT structures:
Index | Description
0 | Upper-left corner of the bounding rectangle.
1 | Lower-right corner of the bounding rectangle.
2 | Starting point for the arc.
3 | Ending point for the arc.
4 | Start and stop angles (reserved; do not use).

lpPPen
Address of a PPEN structure that specifies the physical pen that is used to draw the border.
lpPBrush
Address of a PBRUSH structure that specifies the physical brush that is used to fill the figure.
lpDrawMode
Address of a DRAWMODE structure that contains information that is used to draw the border and fill the interior.
lpClipRect
Address of a RECT structure that contains coordinates for the clipping rectangle. If the lpClipRect parameter is NULL, the clipping rectangle is the entire display surface.

Because the resulting figure is closed, Output fills the figure and draws the border. GDI specifies OS_CHORD when an application calls the Chord function (GDI.348).

A graphics driver must support this style if the CC_CHORD value is set in the dpCurves member of the GDIINFO structure.

Output draws the arc and chord by first filling the interior then drawing the border.

Output draws an arc by drawing a portion of the ellipse contained in the specified bounding rectangle. The function calculates the endpoints of the arc using the starting and ending points; each endpoint is the intersection of the ellipse and a ray drawn from the center of the bounding rectangle through the specified starting or ending point. Output draws the arc in a counterclockwise direction, from starting point up to, but not including, the ending point.

See Also

PDEVICE, PBITMAP, DRAWMODE, RECT, POINT


Output(OS_CIRCLE)

WORD Output(
  LPPDEVICE lpDestDev,
  WORD wStyle,
  WORD wCount,
  LPPOINT lpPoints,
  LPPPEN lpPPen,
  LPPBRUSH lpPBrush,
  LPDRAWMODE lpDrawMode,
  LPRECT lpClipRect
 );

Draws a circle.

Returns one of these values:

1 | Function was successful.
0 | Unrecoverable error occurred.
-1 | Function does not support specified style.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
wStyle
Must be OS_CIRCLE.
wCount
Must be 2.
lpPoints
Address of an array that contains two POINT structures:
Index | Description
0 | Upper-left corner of the bounding rectangle
1 | Lower-right corner of the bounding rectangle

lpPPen
Address of a PPEN structure that specifies the physical pen that is used to draw the border.
lpPBrush
Address of a PBRUSH structure that specifies the physical brush that is used to fill the circle.
lpDrawMode
Address of a DRAWMODE structure that contains information when drawing the border and filling the interior.
lpClipRect
Address of a RECT structure that contains coordinates for the clipping rectangle. If this parameter is NULL, the clipping rectangle is the entire display surface.

Because the resulting figure is closed, Output fills the figure and draws the border. GDI calls this function when an application calls the Ellipse function (GDI.24) with a bounding rectangle that is square.

A graphics driver must support this style if the CC_CIRCLES value is set in the dpCurves member of the GDIINFO structure.

Output draws the circle by first filling the interior and then drawing the border. The center of the circle is at the center of the bounding rectangle; the radius is equal to half the width of the rectangle.

If a graphics driver can draw ellipses and has set the CC_ELLIPSES value in the dpCurves member, it does not need to set the CC_CIRCLES value in the dpCurves member. In such cases, GDI calls Output with the OS_ELLIPSE style when an application draws a circle.

See Also

PDEVICE, PBITMAP, DRAWMODE, RECT, POINT


Output(OS_ELLIPSE)

WORD Output(
  LPPDEVICE lpDestDev,
  WORD wStyle,
  WORD wCount,
  LPPOINT lpPoints,
  LPPPEN lpPPen,
  LPPBRUSH lpPBrush,
  LPDRAWMODE lpDrawMode,
  LPRECT lpClipRect
 );

Draws an ellipse.

Returns one of these values:

1 | Function was successful.
0 | Unrecoverable error occurred.
-1 | Function does not support the specified style.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
wStyle
Must be OS_ELLIPSE.
wCount
Must be 2.
lpPoints
Address of an array that contains two POINT structures. The elements of the array are defined as follows.
Index | Description
0 | Upper-left corner of the bounding rectangle.
1 | Lower-right corner of the bounding rectangle.

lpPPen
Address of a PPEN structure that specifies the physical pen that is used to draw the border.
lpPBrush
Address of a PBRUSH structure that specifies the physical brush that is used to fill the ellipse.
lpDrawMode
Address of a DRAWMODE structure that contains information that is used to draw the border and fill the interior.
lpClipRect
Address of a RECT structure that contains coordinates for the clipping rectangle. If this parameter is NULL, the clipping rectangle is the entire display surface.

Because the resulting figure is closed, Output fills the figure and draws the border. GDI calls this function when an application calls the Ellipse function (GDI.24).

A graphics driver must support this style if the CC_ELLIPSES value is set in the dpCurves member of the GDIINFO structure.

Output draws the ellipse by first filling the interior then drawing the border. The center of the ellipse is at the center of the bounding rectangle; the semi-major and semi-minor axes of the ellipse are equal to half the width and height of the rectangle.

See Also

PDEVICE, PBITMAP, DRAWMODE, RECT, POINT


Output(OS_ENDNSCAN)

WORD Output(
  LPPDEVICE lpDestDev,
  WORD wStyle,
  WORD wCount,
  LPPOINT lpPoints,
  LPPPEN lpPPen,
  LPPBRUSH lpPBrush,
  LPDRAWMODE lpDrawMode,
  LPRECT lpClipRect
 );

Carries out any action needed to complete a series of scan line output.

The return value is 1.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
wStyle
Must be OS_ENDNSCAN
wCount
Must be 0.
lpPoints
Must be NULL.
lpPPen
Must be NULL.
lpPPBrush
Must be NULL.
lpDrawMode
Must be NULL.
lpClipRect
Must be NULL.

GDI calls this function to mark the end of a series of calls to the Output function in which the OS_SCANLINES style is specified. GDI marks the start of the series with a matching OS_BEGINNSCAN style.

Every graphics driver (for Windows versions 2.0 and later) should support the OS_ENDNSCAN style.

See Also

Output(OS_BEGINNSCAN), PDEVICE, PBITMAP, DRAWMODE, RECT, POINT


Output(OS_PIE)

WORD Output(
  LPPDEVICE lpDestDev,
  WORD wStyle,
  WORD wCount,
  LPPOINT lpPoints,
  LPPPEN lpPPen,
  LPPBRUSH lpPBrush,
  LPDRAWMODE lpDrawMode,
  LPRECT lpClipRect
 );

Draws an arc and two line segments that connect the endpoints of the arc to the center of the arc's bounding rectangle.

Returns one of these values:

1 | Function was successful.
0 | Unrecoverable error occurred.
-1 | Function does not support the specified style.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
wStyle
Must be OS_PIE.
wCount
Must be 5.
lpPoints
Address of an array that contains five POINT structures:
Index | Description
0 | Upper-left corner of the bounding rectangle.
1 | Lower-right corner of the bounding rectangle.
2 | Starting point for the arc.
3 | Ending point for the arc.
4 | Start and stop angles. Reserved; do not use.

lpPPen
Address of a PPEN structure that specifies the physical pen that is used to draw the arc and line segments.
lpPBrush
Address of a PBRUSH structure that specifies the brush that is used to fill the figure.
lpDrawMode
Address of a DRAWMODE structure that contains drawing information that is used to draw the border and fill the figure.
lpClipRect
Address of a RECT structure that contains coordinates for the clipping rectangle. If the lpClipRect parameter is NULL, the clipping rectangle is the entire display surface.

Since the resulting figure is closed, Output fills the figure as well as draws the border. GDI calls this function when an application calls the Pie function (GDI.26).

A graphics driver must support the OS_PIE style if the CC_PIE value is set in the dpCurves member of the GDIINFO structure.

Output draws the pie-shaped figure by first filling the interior then drawing the border.

Output draws an arc by drawing a portion of the ellipse contained in the specified bounding rectangle. The function calculates the endpoints of the arc using the starting and ending points; each endpoint is the intersection of the ellipse and a ray drawn from the center of the bounding rectangle through the specified starting or ending point. Output draws the arc in a counterclockwise direction, from starting point up to, but not including, the ending point.

Output draws the two line segments from the endpoints of the arc to the point at the center of the bounding rectangle.

See Also

PDEVICE, PBITMAP, DRAWMODE, RECT, POINT


Output(OS_POLYBEZIER)

WORD Output(
  LPPDEVICE lpDestDev,
  WORD wStyle,
  WORD wCount,
  LPPOINT lpPoints,
  LPPPEN lpPPen,
  LPPBRUSH lpPBrush,
  LPDRAWMODE lpDrawMode,
  LPRECT lpClipRect
 );

Draws a set of Bezier curves.

Returns one of these values:

1 | Function was successful.
0 | Unrecoverable error occurred.
-1 | Function does not support the specified style.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
wStyle
Must be OS_POLYBEZIER.
wCount
Must be at least 4.
lpPoints
Specifies endpoints and control points.
lpPPen
Address of a PPEN structure that specifies the physical pen that is used to draw lines.
lpPBrush
Must be NULL.
lpDrawMode
Address of a DRAWMODE structure that contains information that is used when drawing, such as binary raster operation, background mode, and foreground and background color.
lpClipRect
Address of a RECT structure that contains coordinates for the clipping rectangle. If the lpClipRect parameter is NULL, the clipping rectangle is the entire display surface.

Every graphics driver (for Windows version 2.0 and later) must support the OS_POLYBEZIER style.

Because Output does not use a physical brush to draw the lines, the lpPBrush parameter is usually NULL.


Output(OS_POLYLINE)

WORD Output(
  LPPDEVICE lpDestDev,
  WORD wStyle,
  WORD wCount,
  LPPOINT lpPoints,
  LPPPEN lpPPen,
  LPPBRUSH lpPBrush,
  LPDRAWMODE lpDrawMode,
  LPRECT lpClipRect
 );

Draws a set of line segments.

Returns one of these values:

1 | Function was successful.
0 | Unrecoverable error occurred.
-1 | Function does not support the specified style.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
wStyle
Must be OS_POLYLINE.
wCount
The number of POINT structures in the array pointed to by the lpPoints parameter. The wCount parameter must be at least two.
lpPoints
Address of an array of POINT structures that specifies the endpoints of the lines segments. The array has wCount elements.
lpPPen
Address of a PPEN structure that specifies the physical pen that is used to draw lines.
lpPBrush
Must be NULL.
lpDrawMode
Address of a DRAWMODE structure that contains information that is used when drawing, such as binary raster operation, background mode, and foreground and background color.
lpClipRect
Address of a RECT structure that contains coordinates for the clipping rectangle. If the lpClipRect parameter is NULL, the clipping rectangle is the entire display surface.

Although the line segment may create a closed figure, Output never fills the figure. GDI calls this function when an application calls functions such as the Polyline function (GDI.37).

Every graphics driver (for Windows version 2.0 and later) must support the OS_POLYLINE style.

Output draws each line segment from its starting point up to, but not including, its ending point. If more than one line segment is drawn, each new segment starts at the ending point of the previous segment.

Because Output does not use a physical brush to draw the lines, the lpPBrush parameter is usually NULL.

See Also

PDEVICE, PBITMAP, DRAWMODE, RECT, POINT


Output(OS_POLYPOLYGON)

WORD Output(
  LPPDEVICE lpDestDev,
  WORD wStyle,
  WORD wCount,
  LPPOINT lpPoints,
  LPPPEN lpPPen,
  LPPBRUSH lpPBrush,
  LPDRAWMODE lpDrawMode,
  LPRECT lpClipRect
 );

Draws a series of polygons. Use the OR operator to combine this style with either OS_ALTPOLYGON to specify alternate mode or OS_WINDPOLYGON to specify winding mode.

Returns 1 if the function is successful, zero otherwise.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
wStyle
Must be OS_POLYPOLYGON.
wCount
The number of polygons described by the OSPOLYPOLY structure pointed to by the lpPoints parameter.
lpPoints
Address of an OSPOLYPOLY structure that contains the number of points in each polygon and a pointer to the list of points.
lpPPen
Address of a PPEN structure that specifies the physical pen that is used to draw scan lines.
lpPBrush
Address of a PBRUSH structure that specifies the physical brush that is used to draw the scan lines.
lpDrawMode
Address of a DRAWMODE structure that contains information to use when drawing, such as binary-raster operation, background mode, and foreground and background color.
lpClipRect
Address of a RECT structure that contains coordinates for the clipping rectangle. If this parameter is NULL, the clipping rectangle is the entire display surface.

Output draws a scan line from the starting point up to, but not including, the ending point. The function draws all lines with the brush pointed to by lpPBrush, or by the pen pointed to by lpPPen if lpPBrush is NULL. If Output uses the pen to draw the scan lines, it should not dither the pen color.

See Also

DRAWMODE, OSPOLYPOLY, Output(OS_ALTPOLYGON), Output(OS_WINDPOLYGON), PBITMAP, PDEVICE, POINT, RECT


Output(OS_POLYSCANLINE)

WORD Output(
  LPPDEVICE lpDestDev,
  WORD wStyle,
  WORD wCount,
  LPPOINT lpPoints,
  LPPPEN lpPPen,
  LPPBRUSH lpPBrush,
  LPDRAWMODE lpDrawMode,
  LPRECT lpClipRect
 );

Draws a series of horizontal line segments at a specified vertical position. GDI calls this function when simulating output, such as when filling a polygon. Unlike OS_SCANLINES, it is not necessary that every graphics driver support the OS_POLYSCANLINE style.

Returns 1 if the function is successful, zero otherwise.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
wStyle
Must be OS_POLYSCANLINE.
wCount
The number of SCAN structures in the array pointed to by the lpPoints parameter.
lpPoints
Address of an array of SCAN structures that contain the information needed to draw the scanlines. The driver must draw every SCAN structure in the array.
lpPPen
Address of a PPEN structure that specifies the physical pen that is used to draw scan lines.
lpPBrush
Address of a PBRUSH structure that specifies the physical brush that is used to draw the scan lines.
lpDrawMode
Address of a DRAWMODE structure that contains information to use when drawing, such as binary-raster operation, background mode, and foreground and background color.
lpClipRect
Address of a RECT structure that contains coordinates for the clipping rectangle. If this parameter is NULL, the clipping rectangle is the entire display surface.

Output draws a scan line from the starting point up to, but not including, the ending point. The function draws all lines with the brush pointed to by lpPBrush, or by the pen pointed to by lpPPen if lpPBrush is NULL. If Output uses the pen to draw the scan lines, it should not dither the pen color.

Vector device drivers need not support OS_POLYSCANLINE. Since OS_SCANLINES and OS_POLYSCANLINE are functionally equivalent, vector devices lose nothing by omitting this support.

See Also

DRAWMODE, Output(OS_BEGINNSCAN), Output(OS_ENDNSCAN), Output(OS_SCANLINES), PBITMAP, PDEVICE, POINT, RECT, SCAN


Output(OS_RECTANGLE)

WORD Output(
  LPPDEVICE lpDestDev,
  WORD wStyle,
  WORD wCount,
  LPPOINT lpPoints,
  LPPPEN lpPPen,
  LPPBRUSH lpPBrush,
  LPDRAWMODE lpDrawMode,
  LPRECT lpClipRect
 );

Draws a rectangle and fills it using a specified brush.

Returns one of these values:

1 | Function was successful.
0 | Unrecoverable error occurred.
-1 | Function does not support the specified style.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
wStyle
Must be OS_RECTANGLE.
wCount
Must be 2.
lpPoints
Address of an array of two POINT structures that represents the corners of the rectangle.
lpPPen
Address of a PPEN structure that specifies the physical pen that is used to draw the border of the rectangle.
lpPBrush
Address of a PBRUSH structure that specifies the physical brush that is used to fill the rectangle.
lpDrawMode
Address of a DRAWMODE structure that contains the drawing information to draw and fill the rectangle.
lpClipRect
Address of a RECT structure that contains coordinates for the clipping rectangle. If the lpClipRect parameter is NULL, the clipping rectangle is the entire display surface.

GDI calls this function when an application calls the Rectangle function (GDI.27).

The graphics driver must support the OS_RECTANGLE style if the PC_RECTANGLE value is set in the dpPolygonals member of the GDIINFO structure.

The Output function fills the interior of the rectangle first and then draws the border. Before filling and drawing, Output must subtract one from the bottom and right coordinates. GDI requires that rectangles are drawn so that the border lies one pixel within the specified right and bottom edges.

See Also

PDEVICE, PBITMAP, DRAWMODE, RECT, POINT


Output(OS_ROUNDRECT)

WORD Output(
  LPPDEVICE lpDestDev,
  WORD wStyle,
  WORD wCount,
  LPPOINT lpPoints,
  LPPPEN lpPPen,
  LPPBRUSH lpPBrush,
  LPDRAWMODE lpDrawMode,
  LPRECT lpClipRect
 );

Draws and fills a rectangle that have rounded corners.

Returns one of these values:

1 | Function was successful.
0 | Unrecoverable error occurred.
-1 | Function does not support the specified style.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
wStyle
Must be OS_ROUNDRECT.
lpPoints
Address of an array of three POINT structures that represents the corners of the rectangle and the width and height of the ellipse used to draw the corners.
lpPPen
Address of a PPEN structure that specifies the physical pen that is used to draw the border of the rectangle.
lpPBrush
Address of a PBRUSH structure that specifies the physical brush that is used to fill the rectangle.
lpDrawMode
Address of a DRAWMODE structure that contains the drawing information that is used to draw and fill the rectangle.
lpClipRect
Address of a RECT structure that contains coordinates for the clipping rectangle. If the lpClipRect parameter is NULL, the clipping rectangle is the entire display surface.

GDI calls this function when an application calls the RoundRect function (GDI.28).

The graphics driver must support the OS_ROUNDRECT style if the CC_ROUNDRECT value is set in the dpCurves member of the GDIINFO structure.

The Output function fills the interior of the rectangle first, then draw the border. Before filling and drawing, Output must subtract one from the bottom and right coordinates. GDI requires that rectangles are draw so that the border lies one pixel within the specified right and bottom edges.

See Also

PDEVICE, PBITMAP, DRAWMODE, RECT, POINT


Output(OS_SCANLINES)

WORD Output(
  LPPDEVICE lpDestDev,
  WORD wStyle,
  WORD wCount,
  LPPOINT lpPoints,
  LPPPEN lpPPen,
  LPPBRUSH lpPBrush,
  LPDRAWMODE lpDrawMode,
  LPRECT lpClipRect
 );

Draws a series of horizontal line segments at a specified vertical position. GDI calls this function when simulating output such as filling a polygon.

Every graphics driver should support the OS_SCANLINES style.

Returns 1 if the function is successful, zero otherwise.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
wCount
The number of POINT structures in the array pointed to by the lpPoints parameter.
lpPoints
Address of an array of POINT structures that contains the scan line coordinates. The y member in the first POINT structure specifies the y-coordinate to draw the scan lines. In each subsequent structure, the x member specifies the x-coordinate of a scan line's starting point and the y member specifies the x-coordinate of the ending point.
lpPPen
Address of a PPEN structure that specifies the physical pen that is used to draw scan lines.
lpPBrush
Address of a PBRUSH structure that specifies the physical brush that is used to draw the scan lines.
lpDrawMode
Address of a DRAWMODE structure that contains information to use when drawing, such as binary-raster operation, background mode, and foreground and background color.
lpClipRect
Address of a RECT structure that contains coordinates for the clipping rectangle. If this parameter is NULL, the clipping rectangle is the entire display surface.

Output draws a scan line from the starting point up to, but not including, the ending point. The function draws all lines with the brush pointed to by lpPBrush, or by the pen pointed to by lpPPen if lpPBrush is NULL. If Output uses the pen that is used to draw the scan lines, it should not dither the pen color.

See Also

Output(OS_POLYSCANLINE), PDEVICE, PBITMAP, DRAWMODE, RECT, POINT


Output(OS_WINDPOLYGON)

WORD Output(
  LPPDEVICE lpDestDev,
  WORD wStyle,
  WORD wCount,
  LPPOINT lpPoints,
  LPPPEN lpPPen,
  LPPBRUSH lpPBrush,
  LPDRAWMODE lpDrawMode,
  LPRECT lpClipRect
 );

Draws a polygon and fills it using the winding-number-filling method.

Returns one of these values:

1 | Function was successful.
0 | Unrecoverable error occurred.
-1 | Function does not support the specified style.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
wCount
The number of POINT structures in the array pointed to by the lpPoints parameter.
lpPoints
Address of an array of POINT structures that contains wCount elements. Each point represents a vertex of the polygon.
lpPPen
Address of a PPEN structure that specifies the physical pen that is used to draw the border of the polygon.
lpPBrush
Address of a PBRUSH structure that specifies the physical brush that is used to fill the polygon.
lpDrawMode
Address of a DRAWMODE structure that contains the drawing information that is used to draw and fill the polygon.
lpClipRect
Address of a RECT structure that contains coordinates for the clipping rectangle. If the lpClipRect parameter is NULL, the clipping rectangle is the entire display surface.

GDI calls Output with this style when an application calls functions, such as the Polygon function (GDI.36), and the current polygon-filling mode is WINDING.

The graphics driver must support the OS_WINDPOLYGON style if the PC_WINDPOLYGON value is set in the dpPolygonals member of the GDIINFO structure.

The Output function should fill the interior of the polygon first and then draw the border.

To fill the polygon, Output calculates the polygon outline and filling according to the winding-number-filling method. Winding-number filling depends on the direction (down or up) that each side of the polygon is drawn. With winding-number filling, a given closed area within a polygon should be filled if a horizontal ray, starting in the area and continuing through the left edge of the polygon, crosses an unequal number of upwardly and downwardly drawn sides.

To draw the border, Output draws a line segment from the first point in the array to the second, from the second to the third, and so on. If the last line segment does not end at the first point, Output draws this line segment to ensure a closed figure.

Although the Output function can use device hardware to draw and fill polygons, the function must either provide the same capability when drawing to a main memory bitmap or return -1 to direct GDI to simulate the output using polylines and scan lines.

See Also

Output(OS_ALTPOLYGON), Output(OS_POLYPOLYGON), PDEVICE, PBITMAP, DRAWMODE, RECT, POINT


Pixel

DWORD Pixel(
  LPPDEVICE lpDestDev,
  WORD X,
  WORD Y,
  DWORD dwPhysColor,
  LPDRAWMODE lpDrawMode
 );

Sets or retrieves the color of the specified pixel. The function sets the given pixel to the color given by the dwPhysColor parameter if the lpDrawMode parameter specifies a binary-raster operation. The Pixel function returns the physical color of the pixel if the lpDrawMode parameter is NULL. Every graphics driver must export a Pixel function.

Returns either the physical color of the specified pixel or 1 if the function is successful, 0x80000000L otherwise.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
X and Y
x- and y-coordinate of the pixel to retrieve or set.
dwPhysColor
Physical color value used to set the pixel.
lpDrawMode
Address of a DRAWMODE structure that specifies the binary-raster operation to use to combine the physical color with the existing pixel color.

If lpDrawMode is NULL, the Pixel function returns the current color of the specified pixel.

The export ordinal for this function is 9.

GDI calls this function when simulating output or when an application calls the SetPixel or GetPixel function (GDI.31 or GDI.83).


RealizeObject

WORD RealizeObject(
  LPPDEVICE lpDestDev,
  WORD wStyle,
  LPVOID lpInObj,
  LPVOID lpOutObj,
  LPTEXTXFORM lpTextXForm
 );

Creates or deletes a physical object. The function creates a physical object by filling a structure provided by GDI with device-specific data that corresponds to the attributes of a given logical pen, brush, bitmap, or font; it deletes the physical object by removing any memory or resources it allocated when creating the object.

If successful and if lpOutObj is NULL, returns the size in bytes of the physical object. If successful and if lpOutObj is not NULL, returns one of the following values :

Condition | Return value
For solid brushes for a monochrome DC | 8001h
For solid brushes for a color DC | 8002h
For all other brush styles and objects | 8000h

If unsuccessful, returns zero.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the device or bitmap to create the physical object for.
wStyle
One of the following objects:
Value | Meaning
OBJ_PEN (1) | Realizes a physical pen.
OBJ_BRUSH (2) | Realizes a physical brush.
OBJ_FONT (3) | Realizes a device font. If the device has no device fonts or cannot realize the requested font, the RealizeObject function returns zero.
OBJ_PBITMAP (5) | Realizes a device bitmap. GDI passes this value only if the RC_DEVBITS value is set in the dpRaster member of the driver's GDIINFO structure.

If the wStyle parameter is negative, the function deletes the specified object.

lpInObj
Address of an LOGPEN, LOGBRUSH, LOGFONT, or PBITMAP structure specified by the wStyle parameter. The structure describes the logical attributes of the object to be realized.

If wStyle is negative, the lpInObj parameter points to the PPEN, PBRUSH, FONTINFO, or PBITMAP structure that specifies the physical object to be deleted.

lpOutObj
Address of a buffer to receive the realized object, or points to the physical object to delete. The meaning of this parameter depends on the value of the wStyle parameter.

If wStyle is positive, the lpOutObj parameter points to a buffer. The function fills the buffer with device-specific data that defines a physical object corresponding to the logical object pointed to by the lpInObj parameter. If lpOutObj is NULL, the function returns the size, in bytes, of the physical object.

If wStyle is negative, lpOutObj points to the physical object to delete. Although GDI frees the memory pointed to by lpOutObj when the function returns, the RealizeObject function must free any other memory or resources associated with the physical object.

lpTextXForm
Address of a TEXTXFORM structure or specifies a POINT structure as specified by the wStyle parameter.

If wStyle is OBJ_BRUSH, the lpTextXForm parameter is a POINT structure that contains the x- and y-coordinates (relative to an 8-bit boundary) on which to align the start of the brush's pattern.

If wStyle is OBJ_FONT, lpTextXForm points to a TEXTXFORM structure that contains information about the appearance of a realized font. Both the realized font and the contents of the TEXTXFORM structure are later passed to the ExtTextOut function, allowing more capable devices to make changes to the standard font.

The export ordinal for this function is 10.

GDI may call this function when an application calls functions such as CreateDC, SelectObject, and DeleteObject.

Every graphics driver must export the RealizeObject function.

GDI manages the physical object and makes the object available to the device driver as necessary to draw output. When GDI no longer needs the object, it directs RealizeObject to delete the object.

To create an object, GDI calls this function twice. It first requests the size, in bytes, of the physical object. Then it allocates space for the object and calls RealizeObject again passing a pointer to the allocated space. The lpOutObj parameter specifies which action to take. If it is NULL, the function returns the size; if it is not NULL, the function fills the corresponding structure.

The format and content of a physical object depends entirely on the device driver. For pens and brushes, the recommended formats are the PPEN and PBRUSH structures. For fonts, the structure must contain the dfType through dfFace members of the FONTINFO structure, and dfDevice and dfFace must have valid pointers to device and font strings.

When realizing pens, GDI may request a width or styled line even though the driver does not support such pens. (The dpCurves and dpLines members of the driver's GDIINFO structure specify whether the driver supports wide and styled lines.) In such cases, the RealizeObject function should create a nominal pen, that is, a physical pen that is solid and one-pixel wide. GDI uses this nominal pen that is used to carry out its own styling and wide-line operations.

When realizing brushes, RealizeObject sets the foreground and background colors for hatch and solid brushes, but not for patterned brushes if the patterned brush uses a monochrome bitmap. For these patterned brushes, GDI provides a DRAWMODE structure that specifies the foreground and background colors for the brush. If the color specified for a solid brush does not exactly match a physical color, the function can create a dithered color for the brush. The function realizes hollow brushes. When a hollow brush is passed to a drawing routine, the driver does no filling at all.

If the lpTextXForm parameter specifies a POINT structure, it represents the physical object's pattern reference point. This reference point specifies where to start a patterned brush (relative to a 8-bit boundary) so that the brush pattern aligns with areas previously filled using the brush. The parameter contains values, in the range zero to 7, that specify on which bits to start the pattern.

Display drivers generally do not realize fonts. Instead, they require GDI to realize the fonts to be used with the display. In this case, the display driver's RealizeObject must returns zero whenever the wStyle parameter is OBJ_FONT.

When realizing bitmaps, RealizeObject must create a device bitmap, storing the bitmap bits in device memory (such as RAM on the device adapter) rather than main memory. When GDI requests the size of the physical bitmap, the function must include space for at least a PBITMAP structure, but any additional space is up to the driver. Although no space for the bitmap bits is required, RealizeObject must include some value to indicate the location of the bitmap bits in device memory. GDI intercepts all requests to create monochrome bitmaps. This means RealizeObject is never called to create a monochrome device bitmap.

If wStyle is OBJ_PBITMAP, the return value can be zero to direct GDI to create a main memory bitmap instead of a device bitmap. The return value will be 0x80000000L to indicate an error, and prevent GDI from creating a main memory bitmap.

See Also

PDEVICE, PBITMAP, LOGBRUSH, LOGFONT, LOGPEN, TEXTXFORM, POINT, FONTINFO


SaveScreenBitmap

WORD SaveScreenBitmap(
  LPRECT lpRect,
  WORD wCommand
 );

Saves a single bitmap from the display or restores a single, previously-stored bitmap to the display. The function is used, for example, when a menu is pulled down, to store the part of the screen that is "behind" the menu until the menu is closed.

Returns 1 if successful. It is zero for any of the following error conditions:

  • "Shadow memory" does not exist (save, restore, ignore).
  • "Shadow memory" is already in use (save).
  • "Shadow memory" is not in use (restore).
  • "Shadow memory" has been stolen or trashed (restore).
lpRect
Address of a RECT structure that contains the rectangle to use.
wCommand
Action to take. Can be one of these values:
0 | Saves the rectangle.
1 | Restores the rectangle.
2 | Discards the previously saved rectangle, if there was one.

The export ordinal for this function is 92.

Because SaveScreenBitmap can save only one bitmap at a time, the device driver must maintain a record of whether or not the save area is currently in use.

The bitmap is stored in "shadow memory" (that is, memory that the device allocates and controls). Therefore, the device can save the bitmap in whatever form is most convenient.

See Also

RECT


ScanLR

WORD ScanLR(
  LPPDEVICE lpDestDev,
  WORD X,
  WORD Y,
  PCOLOR dwPhysColor,
  WORD Style
 );

Scans the display surface horizontally from the given pixel, looking for the first pixel having the given color or a pixel that has any other color.

Returns one of these values:

>0 | Number of scanlines copied.
0 | Error or no scanlines copied.
-1 | GDI must simulate the operation

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
X and Y
Coordinate of the starting pixel.
dwPhysColor
Physical color value.
Style
Action to take. Can be a combination of these values:
0x0001 | Scans for a pixel with color matching the dwPhysColor parameter. If this value is not given, the function scans for a pixel with color that does not match.
0x0002 | Scans to the left. If this value is not specified, the function scans to the right.

The export ordinal for this function is 12.

The scan can be left or right. GDI calls this function when an application calls the FloodFill or ExtFloodFill function (GDI.25 or GDI.372).

A graphics driver must export the ScanLR function if it sets the DT_RASDISPLAY value in the dpTechnology member of the GDIINFO structure.


SelectBitmap

BOOL SelectBitmap(
  LPPDEVICE lpDevice,
  LPBITMAP lpPrevBitmap,
  LPBITMAP lpBitmap,
  DWORD fFlags
 );

Selects a bitmap into the specified device, replacing the previous bitmap.

Returns 1 if successful, zero otherwise.

lpDevice
Address of a PDEVICE structure that specifies the device for which the bitmap is to be selected.
lpPrevBitmap
Address of a PBITMAP structure that specifies the previously selected device bitmap.
lpBitmap
Address of a PBITMAP structure that specifies the device bitmap to select.
fFlags
Actions to take while selecting the bitmap. Support for this parameter is not currently implemented; the parameter must be zero.

The export ordinal for this function is 29.

If the driver supports device bitmaps, GDI calls this function when an application calls the SelectObject function (GDI.45) to select a bitmap.

A graphics device driver must export the SelectBitmap function if the RC_DEVBITS value is set in the dpRaster member of the driver's GDIINFO structure.

The lpPrevBitmap and lpBitmap parameters may point to either main memory or device bitmaps. The SelectBitmap function must determine the bitmap type and carry out any device-specific operations to select or cancel the selected device bitmaps.

See Also

PDEVICE, PBITMAP, GDIINFO


SetDIBitsToDevice

WORD SetDIBitsToDevice(
  LPPDEVICE lpDestDev,
  WORD X,
  WORD Y,
  WORD iScan,
  WORD cScans,
  LPRECT lpClipRect,
  LPDRAWMODE lpDrawMode,
  LPSTR lpDIBits,
  LPBITMAPINFO lpBitmapInfo,
  LPINT lpTranslate
 );

Copies DIB data directly to the given device. The function converts the bitmap data to the appropriate device-specific format and copies the resulting bits to the device.

Returns the number of scan lines copied if successful, zero otherwise.

lpDestDev
Address of a PDEVICE structure that specifies the device to receive the DIB.
X and Y
Coordinates, in device units, to receive the top left corner of the DIB.
iScan
Starting scan line.
cScans
Number of scan lines to copy.
lpClipRect
Address of a RECT structure that specifies the clip rectangle.
lpDrawMode
Address of a DRAWMODE structure that specifies the background mode and background color to use while copying the bitmap.
lpDIBits
Address of a buffer that contains the DIB bits.
lpBitmapInfo
Address of a BITMAPINFO structure that specifies the dimensions and format of the DIB.

If the RLE_FORMAT_4 or RLE_FORMAT_8 values are set in the biCompression member of the BITMAPINFO structure, the bitmap is in run-length-encoded (RLE) format. In this case, the function must decode the data as it retrieves it from the buffer pointed to by the lpDIBits parameter.

lpTranslate
Address of an array of color-translation values for converting palette colors to actual device colors. This parameter is ignored by devices that do not use color palettes.

The export ordinal for this function is 21.

GDI calls this function whenever an application calls the SetDIBitsToDevice function (GDI.443).

A graphics device driver must export the SetDIBitsToDevice function if the RC_DIBTODEV value is set in the dpRaster member of the driver's GDIINFO structure.

The function removes the cursor before copying the bitmap bits to the display device and restores the cursor after copying.

See Also

PDEVICE, RECT, DRAWMODE, BITMAPINFO


SetPalette

VOID SetPalette(
  WORD nStartIndex,
  WORD nNumEntries,
  RGBQUAD lpPalette
 );

Sets one or more entries in the hardware-color palette to the specified colors.

No return value.

nStartIndex
Zero-based, color-palette index. The function copies color values to the corresponding hardware-palette entry and to subsequent entries up to the number specified by the nNumEntries parameter.
nNumEntries
Number of entries to set in the hardware palette.
lpPalette
Address of an array of RGBQUAD structures that specifies the colors to which to set the hardware-palette entries.

The export ordinal for this function is 22.

A graphics driver must export the GetPalette function if the RC_PALETTE value is set in the dpRaster member of the driver's GDIINFO structure.


SetPalTrans

void SetPalTrans(
  LPWORD lpIndexes
 );

Copies the translation table pointed to by the lpIndexes parameter and creates a corresponding inverse translation table. The driver uses the translation tables for logical-to-physical, color-index mapping.

No return value.

lpIndexes
Address of the array that contains color indices. The number of indices in the array is specified by the dpNumPalReg member in the device's GDIINFO structure.

The export ordinal for this function is 24.

A graphics driver must export the GetPalette function if the RC_PALETTE value is set in the dpRaster member of the driver's GDIINFO structure.

If lpIndexes is not NULL, SetPalTrans copies the translation table into its own translation table and constructs an inverse of the table. The driver uses the inverse table whenever GDI requests block transfers from the screen to a memory bitmap. If lpIndexes is NULL, the function constructs the identity table.


StretchBlt

WORD StretchBlt(
  LPPDEVICE lpDestDev,
  WORD wDestX,
  WORD wDestY,
  WORD wDestXext,
  WORD wDestYext,
  LPPDEVICE lpSrcDev,
  WORD wSrcX,
  WORD wSrcY,
  WORD wSrcXext,
  WORD wSrcYext,
  DWORD Rop3,
  LPBRUSH lpPBrush,
  LPDRAWMODE lpDrawMode,
  LPRECT lpClip
 );

Transfers bits from a source-device rectangle to a destination-device rectangle. The function stretches or compresses the source bits to fit the destination rectangle. The transfer is controlled by a ternary raster operation value that specifies how corresponding bits from the source, destination, and pattern in a brush are combined to form the final bits in the destination.

Returns one of these values:

1 | Success.
0 | Error.
-1 | GDI should carry out the operation.

lpDestDev
Address of a PDEVICE or PBITMAP structure that specifies the destination device or bitmap.
wDestX and wDestY
x- and y-coordinate of the upper-left corner of the destination rectangle.
wDestXext and wDestYext
Width and height, in device units, of the destination rectangle.
lpSrcDev
Address of a PDEVICE or PBITMAP structure that specifies the source device or bitmap.
wSrcX and wSrcY
x- and y-coordinate of the upper-left corner of the source rectangle.
wSrcXext and wSrcYext
Width and height, in device units, of the source rectangle.
Rop3
Ternary raster operation value. This value determines how StretchBlt combines corresponding pixels from the source, destination, and brush that is used to produce the final pixels in the destination rectangle. This parameter can be any one of 256 ternary raster-operation values; the following lists the most common values.
SRCCOPY (0x00CC0020) | Copies source bits to the destination rectangle: Destination = Source.
SRCPAINT (0x00EE0086) Combines the source and destination bits using the bitwise OR operator:

Destination = Source | Destination.

SRCAND (0x008800C6) Combines the source and destination bits using the bitwise AND operator:

Destination = Source & Destination.

SRCINVERT (0x00660046) Combines the source and destination bits using the bitwise exclusive OR operator:

Destination = Source ^ Destination.

SRCERASE (0x00440328) Combines the source and inverse of destination bits using the bitwise AND operator:

Destination = Source & (~ Destination).

NOTSRCCOPY (0x00330008) Copies the inverse of the destination bits to the destination rectangle:

Destination = ~ Destination.

NOTSRCERASE (0x001100A6) Combines the inverse of the source and destination bits using the bitwise AND operator:

Destination = (~ Source) & (~ Destination).

MERGECOPY (0x00C000CA) Combines the source and brush bits using the bitwise AND operator:

Destination = Source & Pattern.

MERGEPAINT (0x00BB0226) Combines the destination and inverse of the source bits using the bitwise OR operator:

Destination = (~ Source) | Destination.

PATCOPY (0x00F00021) Copies the brush bits to the destination rectangle:

Destination = Pattern.

PATPAINT (0x00FB0A09) Combines the destination, pattern, and the inverse of source bits using the bitwise OR operator:

Destination = (~ Source) | Pattern | Destination.

PATINVERT (0x005A0049) Combines the pattern and destination bits using the bitwise exclusive OR operator:

Destination = Pattern ^ Destination.

DSTINVERT (0x00550009) Copies the inverse of the destination bits:

Destination = ~ Destination.

BLACKNESS (0x00000042) | Set all destination bits to black.
WHITENESS (0x00FF0062) | Set all bits to white.

lpPBrush
Address of a PBRUSH structure that specifies a physical brush. StretchBlt uses this brush only if Rop3 specifies a ternary-raster operation that requires the brush that is used to be combined with source or destination or both.
lpDrawMode
Address of a DRAWMODE structure that specifies the color information StretchBlt needs to determine patterned brush colors and to carry color conversions and transparent copy operations.
lpClip
Address of a RECT structure that specifies the clipping rectangle (in destination-device units).

The export ordinal for this function is 27.

A graphics device driver must export the StretchBlt function if the RC_STRETCHBLT value is set in the dpRaster member of the GDIINFO structure.

Graphics device drivers that support some StretchBlt operations, but not others, can return -1 to direct GDI to carry out the unsupported operations. This also applies to operations in which the StretchBlt function can affect the final output, such as when StretchBlt compresses a bitmap to fit a rectangle in a monochrome bitmap. Although the StretchBlt function must use the current bitmap-stretching mode when compressing or stretching bitmaps, GDI does not make the current mode available to drivers. In such cases, the function should assume that the current mode is COLORONCOLOR or it should return -1 to direct GDI use the proper mode when compressing bitmaps.

The lpDestDev and lpSrcDev parameters can specify the same device that is transferring bits from one part of a device to another is a valid operation. If the source and destination rectangle overlap, StretchBlt transfers bits carefully so that the transfer does not inadvertently overwrite source bits before they have been transferred to the destination.

The Rop3 parameter specifies whether bits from the source, destination, and brush are used in the transfer. If the ternary raster operation specified by Rop3 does not include the source, StretchBlt ignores the source bits. If it does not include the destination, StretchBlt replaces the destination bits without using them to form the final bits.

If Rop3 does not include the brush, StretchBlt ignores the brush. If Rop3 includes the brush, StretchBlt must determine whether the brush is solid or patterned (that is, has an associated bitmap). If the brush has a bitmap, StretchBlt must combine the corresponding bits of the bitmap with the source and destination bits (as specified by the raster operation) to form the final destination bits.

If the source and bitmap associated with the brush do not have the same color format as the destination, StretchBlt must convert the source and brush bitmap to the destination's color format before transferring bits. StretchBlt uses the text (foreground) and background colors specified by the lpDrawMode parameter to convert colors.

To convert a monochrome bitmap to a color bitmap, StretchBlt converts white bits (1) to the background color and converts black bits (0) to the text (foreground) color.

To convert a color bitmap to a monochrome bitmap, StretchBlt converts all pixels that match the background color to white (1), and converts all other pixels to black (0).

In some device drivers, StretchBlt must check the bkMode member of the lpDrawMode parameter as well as the Rop3 parameter to determine how to carry out the transfer. If the bkMode member specifies the background mode TRANSPARENT1, StretchBlt must not transfer source and brush bits that have the same color as the destination's background color (as specified by the bkColor member of lpDrawMode). In other words, the corresponding destination bits must be left unchanged. Other background modes do not affect the transfer. Only device drivers that have set the C1_TRANSPARENT value in the dpCaps1 member of the GDIINFO structure are required to check the background mode.

See Also

PDEVICE, PBITMAP, DRAWMODE, RECT


StretchDIBits

WORD StretchDIBits(
  LPPDEVICE lpPDevice,
  WORD fGet,
  WORD DestX,
  WORD DestY,
  WORD DestXE,
  WORD DestYE,
  WORD SrcX,
  WORD SrcY,
  WORD SrcXE,
  WORD SrcYE,
  LPSTR lpBits,
  LPBITMAPINFO lpBitmapInfo,
  LPINT lpTranslate,
  DWORD dwROP,
  LPBRUSH lpPBrush,
  LPDRAWMODE lpDrawMode,
  LPRECT lpClipRect
 );

Moves a source bitmap into a destination bitmap, stretching or compressing the source bitmap as necessary to fit the dimensions of the destination bitmap. The function either converts and copies a DIB to a given device or converts and copies a device-specific bitmap to a DIB. The fGet parameter specifies whether the source bitmap is a DIB or device-specific bitmap.

Returns one of these values:

>0 | Number of scanlines copied
=0 | Error or no scanlines copied
<0 | GDI must simulate operation

lpPDevice
Address of a PDEVICE or PBITMAP structure that specifies a device or a device-specific bitmap.
fGet
Flag that specifies whether the bitmap bits should be set or retrieved. If this parameter is zero, the function stretches or compresses the bitmap bits in the buffer pointed to by the lpBits parameter and copies them to the given device or bitmap. If this parameter is 1, the function retrieves bits from the device or bitmap.
DestX and DestY
Coordinates of the upper-left corner of destination bitmap.
DestXE and DestYE
Width and height of the destination bitmap in pixels. If DestYE is negative, the function must "flip" the bitmap, effectively displaying or printing it upside down. In this case, the height of the destination bitmap is the absolute value of the parameter.
SrcX and SrcY
Coordinates of the upper-left corner of source bitmap.
SrcXE and SrcYE
Width and height of the source bitmap in pixels.
lpBits
Address of the buffer that contains or receives the DIB bits. If the fGet parameter is zero, the buffer must contains the bitmap bits to be copied to the device or device-specific bitmap. If fGet is 1, the buffer receives bitmap bits copied from the device or bitmap.
lpBitmapInfo
Address of a BITMAPINFO structure that specifies the dimensions and format of the DIB.
lpTranslate
Address of an array of color translation values to convert palette colors to actual device colors. This parameter is ignored by devices that do not use color palettes.
dwRop
Raster operation to use during stretching and compressing. The dwRop parameter can be any one of 256 ternary raster-operation values; the following lists the most common values.
Value | Meaning
SRCCOPY (0x00CC0020) Copies source bits to the destination rectangle:

Destination = Source.

SRCPAINT (0x00EE0086) Combines the source and destination bits using the bitwise OR operator:

Destination = Source | Destination.

SRCAND (0x008800C6) Combines the source and destination bits using the bitwise AND operator:

Destination = Source & Destination.

SRCINVERT (0x00660046) Combines the source and destination bits using the bitwise exclusive OR operator:

Destination = Source ^ Destination.

SRCERASE (0x00440328) Combines the source and inverse of destination bits using the bitwise AND operator:

Destination = Source & (~ Destination).

NOTSRCCOPY (0x00330008) Copies the inverse of the destination bits to the destination rectangle:

Destination = ~ Destination.

NOTSRCERASE (0x001100A6) Combines the inverse of the source and destination bits using the bitwise AND operator:

Destination = (~ Source) & (~ Destination).

MERGECOPY (0x00C000CA) Combines the source and brush bits using the bitwise AND operator:

Destination = Source & Pattern.

MERGEPAINT (0x00BB0226) Combines the destination and inverse of the source bits using the bitwise OR operator:

Destination = (~ Source) | Destination.

PATCOPY (0x00F00021) Copies the brush bits to the destination rectangle:

Destination = Pattern.

PATPAINT (0x00FB0A09) Combines the destination, pattern, and the inverse of source bits using the bitwise OR operator:

Destination = (~ Source) | Pattern | Destination.

PATINVERT (0x005A0049) Combines the pattern and destination bits using the bitwise exclusive OR operator:

Destination = Pattern ^ Destination.

DSTINVERT (0x00550009) Copies the inverse of the destination bits:

Destination = ~ Destination.

BLACKNESS (0x00000042) | Set all destination bits to black.
WHITENESS (0x00FF0062) | Set all bits to white.

lpPBrush
Address of a PBRUSH structure that specifies the current brush. Depending on the specified raster operation, the brush may be used during the stretching or compressing of the bitmap.
lpDrawMode
Address of a DRAWMODE structure that specifies the color information the function needs to determine patterned brush colors and to carry color conversions and transparent copy operations.
lpClipRect
Address of a RECT structure that specifies the clipping rectangle.

The export ordinal for this function is 28.

GDI calls this function whenever an application calls the StretchDIBits function (GDI.439).

A graphics device driver must export the StretchDIBits function if the RC_STRETCHDIB value is set in the dpRaster member of the driver's GDIINFO structure.

For Windows version 3.x, the source bitmap will always be a DIB (with the fGet parameter set to zero). The destination bitmap can be either a memory bitmap or the actual device surface.

See Also

PDEVICE, PBITMAP, DRAWMODE, RECT, GDIINFO


UpdateColors

VOID UpdateColors(
  WORD wStartX,
  WORD wStartY,
  WORD wExtX,
  WORD wExtY,
  LPWORD lpTranslate
 );

Redraws all pixels in a region on the display surface using the colors specified in the given translation table. For each pixel in the region, the function reads the pixel's color index, translates the index, and writes the translated index back to the original position.

A graphics driver must export the GetPalette function if the RC_PALETTE bit is set in the dpRaster member of the driver's GDIINFO structure.

No return value.

wStartX and wStartY
Coordinates of the upper-left corner of the region to update.
wExtX and wExtY
Width of the rectangular region to update in pixels.
lpTranslate
Address of an array of color indices.

The export ordinal for this function is 26.

GDI assumes that the display origin is in the upper-left corner of the screen.


Structures

The following topics describe the structures that are provided.


BITMAPINFO

typedef struct tagBITMAPINFO {
    BITMAPINFOHEADER  bmiHeader;
    RGBQUAD           bmiColors[1];
} BITMAPINFO;

Defines the dimensions and color information for a Windows 3.x DIB.

bmiHeader
A BITMAPINFOHEADER structure that contains information about the dimensions and color format of a DIB.
bmiColors
An array of RGBQUAD structures that define the colors in the bitmap.

A Windows 3.x DIB consists of two distinct parts: a BITMAPINFO data structure that describes the dimensions and colors of the bitmap, and an array of bytes that define the pixels of the bitmap. The bits in the array are packed together, but each scan line must be padded with zeros to end on a 32-bit boundary. Segment boundaries, however, can appear anywhere in the bitmap. The origin of the bitmap is the lower-left corner.

The biBitCount member of the BITMAPINFOHEADER structure determines the number of bits which define each pixel and the maximum number of colors in the bitmap. This member may be set to one of these values:

1 | Bitmap is monochrome, and the bmiColors member must contain two entries. Each bit in the bitmap array represents a pixel. If the bit is clear, the pixel is displayed with the color of the first entry in the bmiColors member; if the bit is set, the pixel has the color of the second entry in the table.
4 | Bitmap has a maximum of 16 colors, and the bmiColors member contains up to 16 entries. Each pixel in the bitmap is represented by a 4-bit index into the color table.
 | For example, if the first byte in the bitmap is 0x1F, then the byte represents two pixels. The first pixel contains the color in the second table entry, and the second pixel contains the color in the sixteenth table entry.
8 | Bitmap has a maximum of 256 colors, and the bmiColors member contains up to 256 entries. In this case, each byte in the array represents a single pixel.
24 | Bitmap has a maximum of 2**24 colors. The bmiColors member is NULL, and each three bytes in the bitmap array represents the relative intensities of blue, green, and red, respectively, of a pixel.

Alternatively, for functions that use DIBs, bmiColors can be an array of 16-bit unsigned integers that specify an index into the currently realized, logical palette instead of explicit RGB values. In this case, an application using the bitmap must call DIB functions with the wColorUse parameter set to DIB_PAL_COLORS.

See Also

BITMAPINFOHEADER


BITMAPINFOHEADER

typedef struct tagBITMAPINFOHEADER {
    DWORD  biSize;          // size of structure, in bytes
    DWORD  biWidth;         // bitmap width, in pixels
    DWORD  biHeight;        // bitmap height, in pixels
    WORD   biPlanes;        // see below
    WORD   biBitCount;      // see below
    DWORD  biCompression;   // see below
    DWORD  biSizeImage;     // see below
    DWORD  biXPelsPerMeter; // see below
    DWORD  biYPelsPerMeter; // see below
    DWORD  biClrUsed;       // see below
    DWORD  biClrImportant;  // see below
} BITMAPINFOHEADER;

Contains information about the dimensions and color format of a Windows 95 DIB.

biPlanes
The number of planes for the target device. This value must be set to 1.
biBitCount
The number of bits per pixel. This value must be 1, 4, 8, or 24.
biCompression
The type of compression for a compressed bitmap. Can be one of these values:
BI_RGB | Specifies that the bitmap is not compressed.
BI_RLE8 | Specifies an RLE format for bitmaps with 8 bits per pixel. The compression format is a 2-byte format consisting of a count byte followed by a byte that contains a color index.
BI_RLE4 | Specifies an RLE format for bitmaps with 4 bits per pixel. The compression format is a two-byte format consisting of a count byte followed by two word-length color indices.
BI_BITFIELDS | Specifies that the bitmap is not compressed and that the color table consists of three doubleword color masks that specify the red, green, and blue components, respectively, of each pixel. This is valid when used with 16- and 32-bits-per-pixel bitmaps.

biSizeImage
Size, in bytes, of the image. This member can be set to zero if the bitmap is in the BI_RGB format. The size must then be calculated explicitly.
biXPelsPerMeter
Horizontal resolution in pixels-per-meter of the target device for the bitmap. An application can use this value to select a bitmap from a resource group that best matches the characteristics of the current device.
biYPelsPerMeter
Vertical resolution in pixels-per-meter of the target device for the bitmap.
biClrUsed
Number of color indices in the color table actually used by the bitmap. If this value is zero, the bitmap uses the maximum number of colors corresponding to the value of the biBitCount member.
biClrImportant
Number of color indices that are considered important for displaying the bitmap. If this value is zero, all colors are important.

The BITMAPINFO structure combines the BITMAPINFOHEADER structure and a color table to provide a complete definition of the dimensions and colors of a Windows 3.x DIB. Bitmap-Compression Formats

Windows supports formats for compressing bitmaps that define their colors with 8 bits per pixel and with 4 bits per pixel. Compression reduces the disk and memory storage required for the bitmap.

When the biCompression member is set to BI_RLE8, the bitmap is compressed using an RLE format for an 8-bit bitmap. This format may be compressed in either of two modes: encoded or absolute. Both modes can occur anywhere throughout a single bitmap.

Encoded mode consists of two bytes: the first byte specifies the number of consecutive pixels to be drawn using the color index contained in the second byte. In addition, the first byte of the pair can be set to zero to indicate an escape that denotes an end of line, end of bitmap, or a delta. The interpretation of the escape depends on the value of the second byte of the pair. The following list shows the meaning of the second byte.

Value | Meaning
0 | End of line.
1 | End of bitmap.
2 | Delta. The two bytes following the escape contain unsigned values indicating the horizontal and vertical offset of the next pixel from the current position.

Absolute mode is specified when the first byte is set to zero and the second byte set to a value between 03H and 0FFH. In absolute mode, the second byte represents the number of bytes which follow, each of which contains the color index of a single pixel. When the second byte is set to 2 or less, the escape has the same meaning as in encoded mode. In absolute mode, each run must be aligned on a 16-bit boundary.

The following example shows the hexadecimal values of an 8-bit compressed bitmap:

03 04 05 06 00 03 45 56 67 00 02 78 00 02 05 01
02 78 00 00 09 1E 00 01

This bitmap would expand as follows (two-digit values represent a color index for a single pixel):

04 04 04
06 06 06 06 06
45 56 67
78 78
move current position 5 right and 1 down
78 78
end of line
1E 1E 1E 1E 1E 1E 1E 1E 1E
end of RLE bitmap

When the biCompression member is set to BI_RLE4, the bitmap is compressed using a RLE format for a 4-bit bitmap, which also uses encoded and absolute modes. In encoded mode, the first byte of the pair contains the number of pixels to be drawn using the color indices in the second byte. The second byte contains two color indices, one in its high-order nibble (that is, its low-order 4 bits) and one in its low-order nibble. The first of the pixels is drawn using the color specified by the high-order nibble, the second is drawn using the color in the low-order nibble, the third is drawn with the color in the high-order nibble, and so on, until all the pixels specified by the first byte have been drawn.

In absolute mode, the first byte contains zero, the second byte contains the number of color indices that follow, and subsequent bytes contain color indices in their high- and low-order nibbles, one color index for each pixel. In absolute mode, each run must be aligned on a word boundary. The end-of-line, end-of-bitmap, and delta escapes also apply to BI_RLE4.

The following example shows the hexadecimal values of a 4-bit compressed bitmap:

03 04 05 06 00 06 45 56 67 00 04 78 00 02 05 01
04 78 00 00 09 1E 00 01

This bitmap would expand as follows (single-digit values represent a color index for a single pixel):

0 4 0
0 6 0 6 0
4 5 5 6 6 7
7 8 7 8
move current position 5 right and 1 down
7 8 7 8
end of line
1 E 1 E 1 E 1 E 1
end of RLE bitmap

See Also

BITMAPINFO


CHARRANGE

typedef struct tagCHARRANGE {
    BYTE chFirst; // character code of first character.
    BYTE chLast;  // character code of last character.
} CHARRANGE;

Contains character codes for the first and last characters in a range of characters.


COLORTABLE_STRUCT

typedef struct tagCOLORTABLE_STRUCT {
    WORD Index; // color-table index
    LONG rgb;   // RGB color value
} COLORTABLE_STRUCT;

Contains color information for an entry in the color table.


DEVMODE

typedef struct _devicemode {    // dvmd
    TCHAR  dmDeviceName[CCHDEVICENAME];
    WORD   dmSpecVersion;
    WORD   dmDriverVersion;
    WORD   dmSize;
    WORD   dmDriverExtra;
    DWORD  dmFields;
    short  dmOrientation;
    short  dmPaperSize;
    short  dmPaperLength;
    short  dmPaperWidth;
    short  dmScale;
    short  dmCopies;
    short  dmDefaultSource;
    short  dmPrintQuality;
    short  dmColor;
    short  dmDuplex;
    short  dmYResolution;
    short  dmTTOption;
    short  dmCollate;
    TCHAR  dmFormName[CCHFORMNAME];
    WORD   dmUnusedPadding;
    USHORT dmBitsPerPel;
    DWORD  dmPelsWidth;
    DWORD  dmPelsHeight;
    DWORD  dmDisplayFlags;
    DWORD  dmDisplayFrequency;
    WORD   dmICMMethod;
    WORD   dmICMIntent;
    WORD   dmMediaType;
    WORD   dmDitherType;
    DWORD  dmReserved1;
    DWORD  dmReserved2;
} DEVMODE;

Contains information about the device initialization and environment of a printer. An application passes this structure to the DeviceCapabilities and ExtDeviceMode functions.

dmDeviceName
Name of the device that the driver supports (for example, "PCL/HP LaserJet" in the case of PCL/HP LaserJet®). This name is unique among device drivers.
dmSpecVersion
Version number of the initialization data specification on which the structure is based. The current version is 0x0400
dmDriverVersion
Printer driver version number assigned by the printer driver developer.
dmSize
Size, in bytes, of the DEVMODE structure except the dmDriverData (device-specific) member. If an application manipulates only the driver-independent portion of the data, it can use this member to determine the length of the structure without having to account for different versions.
dmDriverExtra
Number of bytes of private driver data that follow this structure. If a device driver does not use device-specific information, this member should be zero.
dmFields
Array of flags that determine whether the printer driver uses or ignores the remaining members in the DEVMODE structure. If a flag is set, the driver uses the value in the corresponding member; otherwise, the driver ignores it. A printer driver supports only those members that are appropriate for the printer technology. Can be a combination of these values:
Value | Meaning
DM_ORIENTATION (0x00000001) | Use the dmOrientation member.
DM_PAPERSIZE (0x00000002) | Use the dmPaperSize member. If dmPaperSize is set to DMPAPER_USER, an application must also include the DM_PAPERWIDTH and DM_PAPERLENGTH flags .
DM_PAPERLENGTH (0x00000004) | Use the dmPaperLength member. Include this flag only if dmPaperSize is set to DMPAPER_USER.
DM_PAPERWIDTH (0x00000008) | Use the dmPaperWidth member. Include this flag only if dmPaperSize is set to DMPAPER_USER.
DM_SCALE (0x00000010) | Use the dmScale member.
DM_COPIES (0x00000100) | Use the dmCopies member.
DM_DEFAULTSOURCE (0x00000200) | Use the dmDefaultSource member.
DM_PRINTQUALITY (0x00000400) | Use the dmPrintQuality member.
DM_COLOR (0x00000800) | Use the dmColor member.
DM_DUPLEX (0x00001000) | Use the dmDuplex member.
DM_YRESOLUTION (0x00002000) | Use the dmYResolution member.
DM_TTOPTION (00004000) | Use the dmTTOption member.
DM_COLLATE (0x00008000) | Use the dmCollate member.
DM_FORMNAME (0x00010000) | Use the dmFormName member.
DM_UNUSED (0x00020000) | Use the dmUnusedPadding member.
DM_BITSPERPEL (0x00040000) | Use the dmBitsPerPel member.
DM_PELSWIDTH (0x00080000) | Use the dmPelsWidth member.
DM_PELSHEIGHT (0x00100000) | Use the dmPelsHeight member.
DM_DISPLAYFLAGS (0x00200000) | Use the dmDisplayFlags member.
DM_DISPLAYFREQUENCY (0x00400000) | Use the dmDisplayFrequency member.
DM_ICMMETHOD (0x02000000) | Use the dmICMMethod member.
DM_ICMINTENT (0x04000000) | Use the dmICMIntent member.
DM_MEDIATYPE (0x08000000) | Use the dmMediaType member.
DM_DITHERTYPE (0x10000000) | Use the dmDitherType member.
DM_RESERVED1 (0x00800000) | Use the dmReserved1 member.
DM_RESERVED2 (0x01000000) | Use the dmReserved2 member.

dmOrientation
Paper orientation. Can be either DMORIENT_PORTRAIT (1) or DMORIENT_LANDSCAPE (2).
dmPaperSize
Paper size. Can be one of these values:
Value | Meaning
DMPAPER_10X14 | 10 by 14 inch sheet
DMPAPER_11X17 | 11 by 17 inch sheet
DMPAPER_A3 | A3 sheet, 297 by 420 millimeters
DMPAPER_A4 | A4 sheet, 210 by 297 millimeters
DMPAPER_A4SMALL | A4 small sheet, 210 by 297 millimeters
DMPAPER_A5 | A5 sheet, 148 by 210 millimeters
DMPAPER_B4 | B4 sheet, 250 by 354 millimeters
DMPAPER_B5 | B5 sheet, 182 by 257 millimeter paper
DMPAPER_CSHEET | C sheet, 17 by 22 inches
DMPAPER_DSHEET | D sheet, 22 by 34 inches
DMPAPER_ENV_10 | #10 envelope, 4 1/8 by 9 1/2 inches
DMPAPER_ENV_11 | #11 envelope, 4 1/2 by 10 3/8 inches
DMPAPER_ENV_12 | #12 envelope, 4 3/4 by 11 inches
DMPAPER_ENV_14 | #14 envelope, 5 by 11 1/2 inches
DMPAPER_ENV_9 | #9 envelope, 3 7/8 by 8 7/8 inches
DMPAPER_ENV_B4 | B4 envelope, 250 by 353 millimeters
DMPAPER_ENV_B5 | B5 envelope, 176 by 250 millimeters
DMPAPER_ENV_B6 | B6 envelope, 176 by 125 millimeters
DMPAPER_ENV_C3 | C3 envelope, 324 by 458 millimeters
DMPAPER_ENV_C4 | C4 envelope, 229 by 324 millimeters
DMPAPER_ENV_C5 | C5 envelope, 162 by 229 millimeters
DMPAPER_ENV_C6 | C6 envelope, 114 by 162 millimeters
DMPAPER_ENV_C65 | C65 envelope, 114 by 229 millimeters
DMPAPER_ENV_DL | DL envelope, 110 by 220 millimeters
DMPAPER_ENV_ITALY | Italy envelope, 110 by 230 millimeters
DMPAPER_ENV_MONARCH | Monarch envelope, 3 7/8 by 7 1/2 inches
DMPAPER_ENV_PERSONAL | 6 3/4 envelope, 3 5/8 by 6 1/2 inches
DMPAPER_ESHEET | E sheet, 34 by 44 inches
DMPAPER_EXECUTIVE | Executive, 7 1/4 by 10 1/2 inches
DMPAPER_FANFOLD_LGL_GERMAN | German legal fanfold, 8 1/2 by 13 inches
DMPAPER_FANFOLD_STD_GERMAN | German standard fanfold, 8 1/2 by 12 inches
DMPAPER_FANFOLD_US | U.S. standard fanfold, 14 7/8 by 11 inches
DMPAPER_FOLIO | Folio, 8 1/2 by 13 inch paper
DMPAPER_LEDGER | Ledger, 17 by 11 inches
DMPAPER_LEGAL | Legal, 8 1/2 by 14 inches
DMPAPER_LETTER | Letter, 8 1/2 by 11 inches
DMPAPER_LETTERSMALL | Letter small, 8 1/2 by 11 inches
DMPAPER_NOTE | Note, 8 1/2 by 11 inches
DMPAPER_QUARTO | Quarto, 215 by 275 millimeter paper
DMPAPER_STATEMENT | Statement, 5 1/2 by 8 1/2 inches
DMPAPER_TABLOID | Tabloid, 11 by 17 inches
DMPAPER_USER | Programmer-defined paper size. The dmPaperLength and dmPaperWidth members must specify the size.

dmPaperLength
Length of the paper, in portrait mode. Use this member to define custom paper sizes or for devices such as dot-matrix printers, which can print on a page of arbitrary length. These values, along with all other values in this structure that specify a physical length, are in tenths of a millimeter. The dmPaperSize member must specify the DMPAPER_USER value; otherwise, this member is ignored.
dmPaperWidth
Width of the paper, in portrait mode. The dmPaperSize member must specify the DMPAPER_USER value; otherwise, this member is ignored.
dmScale
Factor by which the printed output is to be scaled. The apparent page size is scaled from the physical page size by a factor of dmScale/100. For example, a letter-sized page with a dmScale value of 50 would contain as much data as a page of 17- by 22-inches because the output text and graphics would be half their original height and width.
dmCopies
Number of copies printed if the device supports multiple-page copies.
dmDefaultSource
Default paper bin from which the paper is fed. Can be one of the following predefined values, or a driver defined value greater than the value of DMBIN_USER.
DMBIN_AUTO (7)
DMBIN_CASSETTE (14)
DMBIN_ENVELOPE (5)
DMBIN_ENVMANUAL (6)
DMBIN_LARGECAPACITY (11)
DMBIN_LARGEFMT (10)
DMBIN_LOWER (2)
DMBIN_MANUAL (4)
DMBIN_MIDDLE (3)
DMBIN_ONLYONE (1)
DMBIN_SMALLFMT (9)
DMBIN_TRACTOR (8)
DMBIN_UPPER (1)

dmPrintQuality
Printer resolution. There are four predefined device-independent values:
DMRES_HIGH (4)
DMRES_MEDIUM (3)
DMRES_LOW (2)
DMRES_DRAFT (1)

If a positive value is given, it specifies the number of dots per inch (DPI) and is, therefore, device dependent.

dmColor
Color flag. Selects either color or monochrome on color printers. Can be one of these values:
DMCOLOR_COLOR (2)
DMCOLOR_MONOCHROME (1)

dmDuplex
Duplex flag. Selects duplex or double-sided printing for printers capable of duplex printing. Can be one of these values:
DMDUP_SIMPLEX (1)
DMDUP_HORIZONTAL (3)
DMDUP_VERTICAL (2)

dmYResolution
Vertical resolution, in dots per inch, of the printer. If the printer initializes this member, the dmPrintQuality member specifies the horizontal resolution, in dots per inch, of the printer.
dmTTOption
TrueType® flag. Specifies how TrueType fonts should be printed. Can be one of these values:
Value | Meaning
DMTT_BITMAP (1) | Prints TrueType fonts as graphics. This value is the default action for dot-matrix printers.
DMTT_DOWNLOAD (2) | Downloads TrueType fonts as soft fonts. This value is the default action for Hewlett-Packard printers that use Printer Control Language (PCL).
DMTT_SUBDEV (3) | Substitutes device fonts for TrueType fonts. This value is the default action for PostScript® printers.
DMTT_DOWNLOAD_OUTLINE (4) | Downloads TrueType fonts as outline soft fonts.

dmCollate
Collate flag. Specifies whether collation should be used when printing multiple copies. Can be one of these values:
Value | Meaning
DMCOLLATE_TRUE (1) | Collates when printing multiple copies.
DMCOLLATE_FALSE (0) | Does not collate when printing multiple copies.

Using DMCOLLATE_FALSE provides faster, more efficient output, since the data is sent to a page printer just once, no matter how many copies are required. The printer is simply told to print the page again.

dmFormName
Name of the form to use (for example, "Letter" or "Legal"). A complete set of names can be retrieved by using the EnumForms function.
dmUnusedPadding
Reserved; used to align the structure to a doubleword boundary. This member should not be used or referenced. Its name and usage can change in future releases.
dmBitsPerPel
Color resolution, in bits per pixel, of the display device (for example, 4 bits for 16 colors, 8 bits for 256 colors, or 16 bits for 65536 colors).
dmPelsWidth
Width, in pixels, of the visible device surface.
dmPelsHeight
Height, in pixels, of the visible device surface.
dmDisplayFlags
Device display-mode flag. Can be one of these values:
Value | Meaning
DM_GRAYSCALE (0x00000001) | Display is a noncolor device. If this value is not specified, color is assumed.
DM_INTERLACED (0x00000002) | Display mode is interlaced. If the value is not specified, noninterlaced is assumed.

dmDisplayFrequency
Frequency, in hertz (cycles per second), of the display device in a particular mode.
dmICMMethod
ICM method flag. Determines how ICM is handled. For a non-ICM application, this member determines if ICM is enabled of disabled. For ICM applications, Windows examines this member to determine how to handle ICM support. Can be one of these values:
Value | Meaning
DMICMMETHOD_SYSTEM (1) | ICM is handled by Windows.
DMICMMETHOD_NONE (2) | ICM is disabled.
DMICMMETHOD_DRIVER (3) | ICM is handled by the device driver.
DMICMMETHOD_DEVICE (4) | ICM is handled by the destination device.

The printer driver must provide a user interface for setting this member. Most printer drivers support only the DCMICMMETHOD_SYSTEM or DCMICMMETHOD_NONE values. Drivers for PostScript printers support all values.

dmICMIntent
ICM-intent flag. Indicates which of the three possible color matching intents should be used by default. This member is primarily for non-ICM applications. ICM application can establish intent by using the ICM functions. Can be one of these values:
Value | Meaning
DMICM_SATURATE (1) | Color matching should optimize for color saturation. This is the most appropriate choice for business graphs, when dithering is not desired.
DMICM_CONTRAST (2) | Color matching should optimize for color contrast. This is the most appropriate choice for scanned or photographic images, when dithering is desired.
DMICM_COLORMETRIC (3) | Color matching should optimize to match the exact color requested. This is most appropriate for use with business logos or other images when an exact color match is desired.

dmMediaType
Type of media being printed on. Can be one of the following predefined values, or a driver defined value greater than the value of DMMEDIA_USER.
Value | Meaning
DMMEDIA_STANDARD (1) | Plain paper
DMMEDIA_GLOSSY (2) | Glossy paper
DMMEDIA_TRANSPARENCY (3) | Transparent film

dmDitherType
Dithering-type flag. Specifies how dithering is to be done. Can be one of the following predefined values, or a driver defined value greater than the value of DMDITHER_USER.
Value | Meaning
DMDITHER_NONE (1) | No dithering.
DMDITHER_COARSE (2) | Dither with a coarse brush.*/
DMDITHER_FINE (3) | Dither with a fine brush.*/
DMDITHER_LINEART (4) | Line art dithering; a special dither method that produces well-defined borders between black, white, and gray scalings. It is not suitable for images that include continuous graduations in intensity and hue, such as scanned photographs.
DMDITHER_GRAYSCALE (5) | Device does grayscaling.

dmReserved1
Not used; must be zero.
dmReserved2
Not used; must be zero.

A device driver's private data follows immediately after the end of the structure. The number of bytes of private data is specified by the dmDriverExtra member.

See Also

ExtDeviceMode


DRAWMODE

typedef struct tagDRAWMODE {
  short    Rop2;           // see below
  short    bkMode;         // see below
  unsigned long  bkColor;        // see below
  unsigned long  TextColor;      // see below
  short    TBreakExtra;    // see below
  short    BreakExtra;     // see below
  short    BreakErr;       // see below
  short    BreakRem;       // see below
  short    BreakCount;     // see below
  short    CharExtra;      // see below
  unsigned long  LbkColor;       // see below
  unsigned long  LTextColor;     // see below
  DWORD    ICMCXform;      // see below
  short    StretchBltMode; // see below
  DWORD    eMiterLimit;    // see below
} DRAWMODE;

Contains information used to draw lines, fill interiors, and write text.

Rop2
Binary-raster operation value. The value, in the range of 1 to 16, determines how to combine source and destination colors. Can be one of these values:
R2_BLACK (1) | Black: zero.
R2_NOTMERGEPEN (2) | Inverse of the bitwise OR of the source and destination colors: NOT (Source OR Dest).
R2_MASKNOTPEN (3) | Bitwise AND of the destination and the inverse of the source: Dest AND (NOT Source).
R2_NOTCOPYPEN (4) | Inverse of the source color: NOT Source.
R2_MASKPENNOT (5) | Bitwise AND of the source and the inverse of the destination: Source AND (NOT Dest).
R2_NOT (6) | Inverse of the destination color: NOT Dest.
R2_XORPEN (7) | Bitwise exclusive OR of the destination and source: Dest XOR Source.
R2_NOTMASKPEN (8) | Inverse of the bitwise AND of the destination and source colors: NOT (Dest AND Source).
R2_MASKPEN 9 | Bitwise AND of the destination and source colors: Dest AND Source.
R2_NOTXORPEN (10) | Inverse of the bitwise exclusive OR of the destination and source colors: NOT (Dest XOR Source).
R2_NOP 11 | Destination color: Dest.
R2_MERGENOTPEN (12) | Bitwise OR of the destination and the inverse of the source: Dest AND (NOT Source).
R2_COPYPEN (13) | Source color: Source.
R2_MERGEPENNOT (14) | Bitwise OR of the source and the inverse of the destination: Source OR (NOT Dest).
R2_MERGEPEN (15) | Bitwise OR of the source and the destination: Source OR Dest.
R2_WHITE (16) | White: 1.

bkMode
Background mode for styled lines, hatched brushes, brushes used for interiors and scan lines, bitmaps, and text. This member can be one of the following values:
BKMODE_TRANSPARENT (1) Also defined as TRANSPARENT | Leaves destination background unchanged.
BKMODE_OPAQUE (2) Also defined as OPAQUE | Replaces destination background with the color specified by the bkColor member.
BKMODE_LEVEL1 (3) | Use Level 1 transparent anti-aliasing. A 1 in the glyph bitmap means that the display driver should blend the color specified in the TextColor member with the current pixel's color. Level 1 is a 25% blend. The blend should be done on the brightness, not the RGB values, and so it must be gamma-corrected.
BKMODE_LEVEL2 (4) | Use Level 2 transparent anti-aliasing. A 1 in the glyph bitmap means that the display driver should blend the color specified in the TextColor member with the current pixel's color. Level 2 is a 50% blend. The blend should be done on the brightness, not the RGB values, and so it must be gamma-corrected.
BKMODE_LEVEL3 (5) | Use Level 3 transparent anti-aliasing. A 1 in the glyph bitmap means that the display driver should blend the color specified in the TextColor member with the current pixel's color. Level 3 is a 75% blend. The blend should be done on the brightness, not the RGB values, and so it must be gamma-corrected.
BKMODE_TRANSLATE (6) | For 8 bpp palettized surfaces only. The TextColor member is a far pointer to a byte array that is used to translate the existing pixel to a new pixel value. Use the current pixel byte as an index into the table to get the pixel's new value.

bkColor
Physical color value that specifies the background color.
TextColor
Physical color value that specifies the text (foreground) color.
TBreakExtra
Total amount of space, in pixels, to add to the break characters in a line of text. TBreakExtra is set to zero if no justification is required.
BreakExtra
Amount of space, in pixels, to add to each break character in a line of text. This value is equal to TBreakExtra divided by BreakCount.
BreakErr
Running error term: the amount of space, in pixels, not yet added to break characters in a line of text. This member is used in conjunction with the BreakRem member to determine which break characters receive the additional pixels specified by BreakRem. Initially, BreakErr is set to (BreakCount/2)+1.
BreakRem
Amount of space, in pixels, to add to one or more break characters in a line of text. This space is in addition to any extra space specified by the BreakExtra member and is intended to be distributed evenly across the line. The BreakRem value is equal to the remainder after dividing TBreakExtra by BreakCount.
BreakCount
Number of break characters in a line of text. If the TBreakExtra member is not zero, each break character must be drawn wider than its normal width. The BreakExtra member specifies the extra width, in pixels,. The BreakRem member may also specify additional pixels for one or more break characters.
CharExtra
Amount of space, in pixels, to add between characters in a line of text.
LbkColor
A COLORREF value that specifies the logical background color.
LTextColor
A COLORREF value that specifies the logical text (foreground) color.
ICMCXform
Transformation for image color matching. A color transform links an input color space to the device output color space. This field is used by drivers whenever a DIB is to be processed from GDI to the device, as in SetDIBitsToDevice, SetDIBits, and any other similar DIB function calls.
StretchBltMode
StretchBlt mode value. Can be one of the following values:
Value | Meaning
STRETCH_ANDSCANS (1) | Uses the AND operator to combine eliminated lines with the remaining lines. This mode preserves black pixels at the expense of colored or white pixels. It is the default mode. Also defined as SBM_BLACKONWHITE.
STRETCH_ORSCANS (2) | Uses the OR operator to combine eliminated lines with the remaining lines. This mode preserves colored or white pixels at the expense of black pixels. Also defined as SBM_WHITEONBLACK.
STRETCH_DELETESCANS (3) | Deletes the eliminated lines. Information in the eliminated lines is not preserved. Also defined as SBM_COLORONCOLOR.
STRETCH_HALFTONE (4) | Maps pixels from the source rectangle into blocks of pixels in the destination rectangle. The average color over the destination block of pixels approximates the color of the source pixels. Also defined as SBM_HALFTONE.

eMiterLimit
Miter limit value. The miter length is defined as the distance from the intersection of the line walls on the inside of the join to the intersection of the line walls on the outside of the join. The miter limit is the maximum allowed ratio of the miter length to the line width.

See Also

Output


FONTINFO

typedef struct tagFONTINFO {
    short dfType;
    short dfPoints;
    short dfVertRes;
    short dfHorizRes;
    short dfAscent;
    short dfInternalLeading;
    short dfExternalLeading;
    BYTE dfItalic;
    BYTE dfUnderline;
    BYTE dfStrikeOut;
    short dfWeight;
    BYTE dfCharSet;
    short dfPixWidth;
    short dfPixHeight;
    BYTE dfPitchAndFamily;
    short dfAvgWidth;
    short dfMaxWidth;
    BYTE dfFirstChar;
    BYTE dfLastChar;
    BYTE dfDefaultChar;
    BYTE dfBreakChar;
    short dfWidthBytes;
    unsigned long  dfDevice;
    unsigned long  dfFace;
    unsigned long  dfBitsPointer;
    unsigned long  dfBitsOffset;
    BYTE dfReserved;
    long  dfFlags;        // Windows 3.x fonts only
    short dfAspace;       // Windows 3.x fonts only
    short dfBspace;       // Windows 3.x fonts only
    short dfCspace;       // Windows 3.x fonts only
    long  dfReserved;     // reserved; do not use.
    long  dfReserved1[4]; // reserved; do not use.
} FONTINFO;

Contains information about a physical font. Depending on whether the font is realized by GDI or by a device driver, the FONTINFO structure may be immediately followed by a character-width table and by font bitmap or vector information.

The FONTINFO structure contains optional members (dfFlags through dfReserved1) that are present only if the font has been designed for Windows versions 3.x. If GDI realizes a font for a driver, the font's corresponding FONTINFO structure will not include these optional members unless the RC_BIGFONT bit is set in the dpRaster member of the driver's GDIINFO structure.

dfType
Font type. The low-order byte, reserved for exclusive GDI use, is a combination of these values:
PF_RASTER_TYPE (0x0000) | Font is a raster font.
PF_VECTOR_TYPE (0x0001) | Font is a vector font.
PF_BITS_IS_ADDRESS (0x0004) | The dfBitsOffset member specifies the absolute memory address of the font bitmap or vector information.
PF_DEVICE_REALIZED (0x0080) | Font has been realized by the device driver.
PF_GLYPH_INDEX (0x0020h) | Font is a large (two bytes) character set font.

All other values in the low-order byte are reserved. In particular, the value 0x0008 in the dfType member is reserved for use with Asian fonts.

The high-order byte is reserved for device use. GDI never inspects the high byte. If GDI realizes the font, it sets this byte to zero. If the device driver realizes the font, it can set this byte to any value.

dfPoints
Point size at which the character looks the best.
dfVertRes
Vertical resolution, in DPI, at which this character set was digitized.
dfHorizRes
Horizontal resolution, in DPI, at which this character set was digitized.
dfAscent
Distance from the top of a character definition cell to the baseline of the typographical font. This value is useful for aligning the baseline of fonts of different heights.
dfInternalLeading
Amount of leading inside the bounds set by the dfPixHeight member. Accent marks may occur in this area.
dfExternalLeading
Amount of extra leading that the designer requests the application add between rows. Because this area is outside of the font proper, it contains no marks and will not be altered by text output calls in either the OPAQUE or TRANSPARENT mode.
dfItalic
Italic flag that specifies whether the character-definition data represents an italic font. The low-order bit is 1 if the flag is set. All other bits are zero.
dfUnderline
Underline flag that specified whether the character-definition data represents an underlined font. The low-order bit is 1 if the flag is set. All other bits are zero.
dfStrikeOut
Strikeout flag that specifies whether the character definition data represents a struck-out font. The low-order bit is 1 if the flag is set. All other bits are zero.
dfWeight
Weight of the characters in the character-definition data, on a scale from 1 to 1000. A value of 400 specifies regular weight type; 700 is bold; and so on.
dfCharSet
Character set defined by this font. Can be one of these values:
0 | ANSI character set
2 | Symbol character set
255 | OEM hardware font

Character set values that support international versions of the operating system are also permitted.

dfPixWidth
Width of all characters in the font.

For vector fonts, the dfPixWidth member is the width of the grid on which the font was digitized.

For raster fonts, dfPixWidth is the width, in pixels, of each character bitmap. If that member is zero, the font has variable-width characters and these widths are specified in the character-width table immediately following this structure.

dfPixHeight
Height of all characters in the font.

For vector fonts, the dfPixHeight member is the height of the grid on which the font was digitized.

For raster fonts, dfPixHeight is the height, in scan lines, of each character bitmap.

dfPitchAndFamily
Pitch and font family. The pitch specifies whether the characters in the font have the same width or variable widths. The font family indicates, in a general way, the look of a font.

The dfPitchAndFamily member can be a combination of these values:
0x01 | Variable-pitch font. If this value is not given, the font is fixed pitch.
FF_ROMAN (0x10) | Proportionally spaced fonts with serifs.
FF_SWISS (0x20) | Proportionally spaced fonts without serifs.
FF_MODERN (0x30) | Fixed-pitch fonts.
FF_SCRIPT (0x40) | Cursive or script fonts.
FF_DECORATIVE (0x50) | Novelty fonts.

If the high-order 4 bits are set to FF_DONTCARE (0x00), the font does not belong to a specific family.

dfAvgWidth
Width of characters in the font. For fixed-pitch fonts, this value is the same as dfPixWidth. For variable-pitched fonts, this is the width of the uppercase character "X."
dfMaxWidth
Maximum pixel-width of any character in the font. For fixed-pitch fonts, this is simply dfPixWidth.
dfFirstChar
First-character code defined by this font. Character definitions are stored only for the characters actually present in a font, so this member should be used when calculating indices into the character-width table following this structure.
dfLastChar
Last-character code defined by this font. Note that all the characters with codes between the dfFirstChar and dfLastChar member must be present in the character-width table.
dfDefaultChar
Default character. A device driver uses this character as a substitute for any character in a string that is out of the range of the dfFirstChar through dfLastChar members. The character is given relative to dfFirstChar so that the actual value of the default character is the sum of dfDefaultChar and dfFirstChar. Ideally, the dfDefaultChar member should be a visible character in the current font--for example, a period (.).
dfBreakChar
Word-break character. Applications use this character to separate words when wrapping or justifying lines of text. The character is given relative to dfFirstChar so that the actual value of the word-break character is the sum of the dfBreakChar and dfFirstChar members. In many fonts, dfBreakChar is zero and dfFirstChar is 32. This means that the word-break character value is 32, an ASCII space.
dfWidthBytes
Number of bytes in each row of the font bitmap (raster fonts). This field is not used for vector fonts. The dfWidthBytes member is always an even quantity so that rows of the bitmap start on 16-bit boundaries.
dfDevice
Offset from the beginning of the segment that contains the FONTINFO structure to the null-terminated ASCII string that specifies the device name. For a generic font, this value is NULL.
dfFace
Offset from the beginning of the segment that contains the FONTINFO structure to the null-terminated ASCII string that specifies the name of the font face.
dfBitsPointer
Absolute machine address of the bitmap. This member is set by GDI. The dfBitsPointer member is guaranteed to be even.
dfBitsOffset
Offset from the beginning of the segment that contains the FONTINFO structure to the beginning of the bitmap information.

If the PF_BITS_IS_ADDRESS bit is set in dfType, dfBitsOffset is an absolute address of the bitmap or vector information. For example, this bit is set if the font bitmap or vector information is in ROM.

For raster fonts, dfBitsOffset points to a sequence of bytes that make up the bitmaps for each character in the font.

For vector fonts, dfBitsOffset points to a string of bytes or words (depending on the size of the grid on which the font was digitized) that specifies the strokes for each character of the font. The dfBitsOffset member must be even.

dfReserved
Reserved; do not use. This member is present only for raster fonts. In Windows 2.x fonts, this member ensures that the character-width table (which immediately follows this member) starts on a 16-bit boundary.
dfFlags
Format of the font bitmap information. Can be one of these values:
FSF_FIXED (0x0001) | Font is fixed pitch.
FSF_PROPORTIONAL (0x0002) | Font is proportional pitch
FSF_ABCFIXED (0x0004) | Font is an ABC fixed font. The advance width for each character in the font is the sum of the dfAspace, dfBspace, and dfCspace members.
FSF_ABCPROPORTIONAL (0x0008) | Font is an ABC proportional font.

This member is present only for Windows 3.x fonts.

dfAspace
Global A space, if any. This member is the distance from the current position to the left edge of the bitmap. This member is present only for Windows 3.x fonts.
dfBspace
Global B space, if any. This member is the width of the character. This member is present only for Windows 3.x fonts.
dfCspace
Global C space, if any. This member is the distance from the right edge of the bitmap to the new current position. This member is present only for Windows 3.x fonts.
dfReserved
This member is not used. This member is present only for Windows 3.x fonts.
dfReserved1
This member is not used. This member is present only for Windows 3.x fonts.

The FONTINFO structure may be immediately followed by one or more of the following items:

Item | Description
Character-width table | Specifies the widths of each character as well as specifies the offset to the corresponding bitmap or vector information.
Bitmaps | Specifies the bits defining the shape of the characters in a raster font. The size of this item is whatever length the total bitmaps occupy. Each row of a raster bitmap must start on a 16-bit boundary, which means that the end of each row must be padded to an even length.
Vectors | Specifies the set of coordinates that define the shape of the characters in a vector font.
Font name | Specifies a null-terminated ASCII character string that identifies the name of the font. The size of this field is the length of the string plus a terminating null character.
Device name | Specifies a null-terminated ASCII character string that specifies the name of the device if this font file is for a specific device. The size of this field is the length of the string plus a terminating null character.

All device drivers must support Windows 2.x fonts. If a device driver supports Windows 3.x fonts, it must set the RC_BIGFONT bit in the dpRaster member of its GDIINFO structure. Printer drivers can call the GetDeviceCaps function (GDI.80), and check for the RC_BIGFONT bit in the raster capabilities to determine whether the display driver uses Windows 3.x fonts.

When a device driver realizes a font by using the RealizeObject function, the dfFace and dfDevice members must point to valid character strings that contains the font and device names. Windows 2.x Fonts

For Windows 2.x fonts, the character-width table is either an array of integer values or an array of glyph-entry structures. The number of elements in the array is equal to:

dfLastChar - dfFirstChar + 2

That is, there is always one more element than the number of characters in the font. The extra entry is available for storing the size, in bytes, of the last character in a vector font. Although this extra entry applies only to vector fonts, it is present for all fonts.

For fixed-pitch vector fonts, the character-width table is an array of integer values. In this case, each element of the array is an offset (relative to the start of the segment that contains the FONTINFO structure) to the first byte or 16 bits of vector information for the given character. The number of bytes or words for a particular character is calculated by subtracting its character-width table entry from the entry for the next character.

For variable-pitch vector fonts, the character width table is an array of VECTORGLYPHENTRY structures. The VECTORGLYPHENTRY structure has the following form:

typedef struct tagVECTORGLYPHENTRY {
    short vgeOffset;  // offset to vectors relative to segment start
    short vgeWidth;   // width of character in pixels
} VECTORGLYPHENTRY;

The vgeOffset member specifies the offset (relative to the start of the segment that contains the FONTINFO structure) to the first byte or 16 bits of vector information for the given character. The vgeWidth member specifies the width for the character.

For raster fonts, the character-width table is an array of RASTERGLYPHENTRY structures.

The rgeWidth member specifies the width, in pixels, of the bitmap for the given character. The member also specifies the advance width for the given character. The rgeOffset member specifies the offset (relative to the start of the segment that contains the FONTINFO structure) to the first byte of bitmap information for the character.

Windows 2.x fonts cannot exceed 64K. Windows 3.x Fonts

Windows 3.x fonts are primarily designed for use on systems with sufficient memory and a microprocessor (such as an 80386) that has instructions using 32-bit address offsets.

For Windows 3.x fonts, the format of the character-width table is dependent on the value of the dfFlags member.

Value | Meaning
DFF_FIXED | Array of RASTERGLYPHENTRY structures.
DFF_PROPORTIONAL | Array of RASTERGLYPHENTRY structures.
DFF_ABCFIXED | Array of ABCGLYPHENTRY structures.
DFF_ABCPROPORTIONAL | Array of ABCGLYPHENTRY structures.

Windows presently supports only the DFF_FIXED and DFF_PROPORTIONAL values.

The rgeWidth member of the VECTORGLYPHENTRY structure specifies the width, in pixels, of the bitmap for the given character. The member also specifies the width for the character. The rgeOffset member specifies the offset (relative to the start of the segment that contains the FONTINFO structure) to the first byte of bitmap information for the character.

The ABCGLYPHENTRY structure has the following form:

typedef struct tagABCGLYPHENTRY {
    short ageWidth;   // width of character bitmap, in pixels
    long  ageOffset;  // pointer to the bits
    FIXED ageAspace;  // A space, in fractional pixels (16.16)
    FIXED ageBspace;  // B space, in fractional pixels (16.16)
    FIXED ageCspace;  // C space, in fractional pixels (16.16)
} ABCGLYPHENTRY;

The ageWidth member specifies the width, in pixels, of the bitmap for the given character. The ageOffset member specifies the offset (relative to the start of the segment that contains the FONTINFO structure) to the first byte of bitmap information for the character. The sum of the ageAspace, ageBspace, and ageCspace members specify the width of the character.

Windows 3.x fonts can exceed 64K.

See Also

GDIINFO


GDIINFO

typedef struct tagGDIINFO {
    short int           dpVersion;
    short int           dpTechnology;
    short int           dpHorzSize;
    short int           dpVertSize;
    short int           dpHorzRes;
    short int           dpVertRes;
    short int           dpBitsPixel;
    short int           dpPlanes;
    short int           dpNumBrushes;
    short int           dpNumPens;
    short int           dpCapsFE;
    short int           dpNumFonts;
    short int           dpNumColors;
    short int           dpDEVICEsize;
    unsigned short int  dpCurves;
    unsigned short int  dpLines;
    unsigned short int  dpPolygonals
    unsigned short int  dpText;
    unsigned short int  dpClip;
    unsigned short int  dpRaster;
    short int           dpAspectX;
    short int           dpAspectY;
    short int           dpAspectXY;
    short int           dpStyleLen;
    POINT               dpMLoWin;
    POINT               dpMLoVpt;
    POINT               dpMHiWin;
    POINT               dpMHiVpt;
    POINT               dpELoWin;
    POINT               dpELoVpt;
    POINT               dpEHiWin;
    POINT               dpEHiVpt;
    POINT               dpTwpWin;
    POINT               dpTwpVpt;
    short int           dpLogPixelsX;
    short int           dpLogPixelsY;
    short int           dpDCManage;
    unsigned short int  dpCaps1;
    long                dpSpotSizeX;
    long                dpSpotSizeY;
    short int           dpNumPalReg;
    short int           dpPalReserved;
    short int           dpColorRes;
} GDIINFO;

Contains information about the graphics device supported by a device driver. GDI retrieves this structure when it loads the driver and uses the information in the structure to initialize the driver.

dpVersion
Version number. The high-order byte specifies the major version, the low-order byte the minor version. For example, in a device driver developed for Windows® 3.1, this member should contain 0x030A.
dpTechnology
Device technology. Can be one of these values:
DT_PLOTTER (0) | Vector plotter
DT_RASDISPLAY (1) | Raster display
DT_RASPRINTER (2) | Raster printer

All other values are reserved.

dpHorzSize
Width, in millimeters, of the physical display surface.
dpVertSize
Height, in millimeters, of the physical display surface.
dpHorzRes
Width, in pixels, of the display surface. For nonraster devices, this width is equivalent to the number of vertical grid lines used by the device to plot points on the display surface. In such cases, a pixel is defined to be the smallest mark the device can draw.
dpVertRes
Height, in raster lines, of the display. For nonraster devices, this height is equivalent to the number of horizontal grid lines used by the device to plot points on the display surface. In such cases, a raster line is equivalent to a gridline.
dpBitsPixel
Number of adjacent bits on each plane required to define a single pixel.
dpPlanes
Number of planes required to define the pixels. For a typical raster device with red, green, and blue bit planes (such as a 3-plane EGA), this member is 3.
dpNumBrushes
Number of device-specific brushes supported by the device.
dpNumPens
Number of device-specific pens supported by the device.
dpCapsFE
Capability bits for East Asian fonts. Can be a combination of these values:
FEC_TT_DBCS (0x0020) | Can output DBCS True Type fonts
FEC_WIFE_ABLE (0x0080) | Can handle WIFE font as Engine font

dpNumFonts
Number of device-specific fonts supported by the device.
dpNumColors
Number of entries in the color table for the device or the number of reserved colors for a palette-capable device.
dpDEVICEsize
Size, in bytes, of the PDEVICE structure for this device. It must be at least two bytes.
dpCurves
Curve-drawing capabilities. This member specifies the types of curves a device can draw, whether the interior of those figures that can be handled can be brushed in, and whether the borders of those figures that can be handled can be drawn with wide lines, styled lines, or lines that are both wide and styled. Can be a combination of these values:
CC_NONE (0x0000) | Curves not supported.
CC_CIRCLES (0x0001) | Draws circles.
CC_PIE (0x0002) | Draws pie wedges.
CC_CHORD (0x0004) | Draws chord arcs.
CC_ELLIPSES (0x0008) | Draws ellipses.
CC_WIDE (0x0010) | Draws wide lines.
CC_STYLED (0x0020) | Draws styled lines.
CC_WIDESTYLED (0x0040) | Draws lines that are wide and styled.
CC_INTERIORS (0x0080) | Draws interiors.
CC_ROUNDRECT (0x0100) | Draws round rectangles.
CC_POLYBEZIER (0x0200) | Draws poly Bezier splines.

All other values are reserved.

dpLines
Polyline and line-drawing capabilities. This member also specifies the types of lines a device can draw, whether the interior of figures can be brushed in, and whether the borders of figures can be drawn with wide lines, styled lines, or lines that are both wide and styled. Can be a combination of these values:
LC_NONE (0x0000) | Lines not supported.
LC_POLYSCANLINE (0x0001) | Draws a group of scanlines.
LC_POLYLINE (0x0002) | Draws polylines.
LC_WIDE (0x0010) | Draws wide lines.
LC_STYLED (0x0020) | Draws styled lines.
LC_WIDESTYLED (0x0040) | Draws wide styled lines.
LC_INTERIORS (0x0080) | Draws interiors.

All other values are reserved. The high-order byte must be zero.

dpPolygonals
Polygon-, rectangle-, and scan-line drawing capabilities. This member also specifies whether the interior of those figures that can be handled can be brushed in, and whether the borders of those figures that can be handled can be drawn with wide lines, styled lines, or lines that are both wide and styled. Can be a combination of these values:
PC_NONE (0x0000) | Polygons not supported.
PC_ALTPOLYGON (0x0001) | Draws alternate-fill polygons.
PC_RECTANGLE (0x0002) | Draws rectangles.
PC_WINDPOLYGON (0x0004) | Draws winding-number-fill polygons.
PC_SCANLINE (0x0008) | Draws scan lines.
PC_WIDE (0x0010) | Draws wide borders.
PC_STYLED (0x0020) | Draws styled borders.
PC_WIDESTYLED (0x0040) | Draws borders that are wide and styled.
PC_INTERIORS (0x0080) | Draws interiors.
PC_POLYPOLYGON (0x0100) | Draws multiple polygons.
PC_PATHS (0x0200) | Draws paths.

All other values are reserved. The high byte must be zero.

dpText
Level of text support the device driver provides. Can be a combination of these values:
TC_OP_CHARACTER (0x0001) | Generates character-precision text. If this value is not given (or implied by the TC_OP_STROKE value), the driver can generate string-precision text only.
TC_OP_STROKE (0x0002) | Generates stroke-precision text. This value implies the TC_OP_CHARACTER value.
TC_CP_STROKE (0x0004) | Draws partially clipped characters. If this value is not given, the character must be entirely within the clip region to be drawn.
TC_CR_90 (0x0008) | Rotates characters in 90-degree increments. If this value is not given (or implied by the TC_CR_ANY value), the driver cannot rotate text.
TC_CR_ANY (0x0010) | Rotates characters to any angle. This value implies the TC_CR_90 value.
TC_SF_X_YINDEP (0x0020) | Scales characters independently along the x- and y-axes. If this value is not given, the driver may be able to scale characters but not independently along the axes.
TC_SA_DOUBLE (0x0040) | Scales characters by doubling. If this value is not given (or implied by the TC_SA_INTEGER or TC_SA_CONTIN values), the driver cannot scale text.
TC_SA_INTEGER (0x0080) | Scales characters by integral multiples. This value implies the TC_SA_DOUBLE value.
TC_SA_CONTIN (0x0100) | Scales characters by any multiple. This value implies the TC_SA_DOUBLE and TC_SA_INTEGER values.
TC_EA_DOUBLE (0x0200) | Generates bold characters by doubling the weight. If this value is not given, the driver cannot modify character weights.
TC_IA_ABLE (0x0400) | Generates italic characters by skewing.
TC_UA_ABLE (0x0800) | Generates underlined characters.
TC_SO_ABLE (0x1000) | Generates struck-out characters.
TC_RA_ABLE (0x2000) | Can use raster fonts to generate text.
TC_VA_ABLE (0x4000) | Can use vector fonts to generate text.
TC_RESERVED (0x8000) | Reserved; must be zero.

If one of these values is specified, the device must support that capability for all fonts, whether realized by the device or provided by GDI.

dpClip
Clipping capabilities. Can be one of these values:
CP_NONE (0) | Cannot clip.
CP_RECTANGLE (1) | Can clip using a single rectangle.
CP_REGION (2) | Not supported.
CP_REGION32 (4) | The driver will receive one of three values for lpClipRect: NULL (meaning cannot clip), or a far pointer to either a REGION or a RECT structure. (If rgn_id is 0x8000 it is a REGION structure; otherwise, it is a RECT structure.)

dpRaster
Raster capabilities. Can be a combination of these values:
RC_NONE (0x0000) | No raster capabilities.
RC_BITBLT (0x0001) | Can transfer bitmaps. The driver exports the BitBlt function.
RC_BANDING (0x0002) | Requires banding support.
RC_SCALING (0x0004) | Requires scaling support.
RC_SAVEBITMAP (0x0040) | Saves bitmaps locally in shadow memory. The driver exports the SaveScreenBitmap function.
RC_PALETTE (0x0100) | Does color-palette management.
RC_DIBTODEV (0x0200) | Transfers DIBs directly to device. The driver exports the SetDIBitsToDevice function.
RC_BIGFONT (0x0400) | Supports Windows 3.x fonts. If this value is not given, GDI ensures that the driver receives Windows 2.x fonts only.
RC_STRETCHBLT (0x0800) | Stretches and compresses bitmaps while transferring the bitmap. The driver exports the StretchBlt function.
RC_FLOODFILL (0x1000) | Perform flood filling. The driver exports the FloodFill function.
RC_STRETCHDIB (0x2000) | Stretches and compresses device-independent bitmaps while transferring the bitmap. The driver exports the StretchDIBits function.
RC_DEVBITS (0x8000) | Supports device bitmaps. Driver exports the BitmapBits and SelectBitmap function.

dpAspectX
Relative width of a device pixel. This value, in the range 1 through 1000, helps specify the device's aspect ratio.
dpAspectY
Relative height of a device pixel. This value, in the range 1 through 1000, helps specify the device's aspect ratio.
dpAspectXY
Relative diagonal width of a device pixel. This value, in the range 1 through 1000, helps specify the device's aspect ratio. It must be equal to the square root of the sum of the squares of dpAspectX and dpAspectY.
dpStyleLen
Minimum length of a dot generated by a styled pen. The length is relative to the width of a device pixel and should be given in the same units as dpAspectX. For example, if dpAspectX is 5 and the minimum length required is 3 pixels, dpStyleLen should be 15.
dpMLoWin
Width and height of the metric (low resolution) window. The width is dpHorzSize*10; the height is dpVertSize*10.
dpMLoVpt
Horizontal and vertical resolutions of the metric (low resolution) viewport. The horizontal resolution is dpHorzRes; the vertical resolution is –dpVertRes.
dpMHiWin
Width and height of the metric (high resolution) window. The width is dpHorzSize*100; the height is dpVertSize*100.
dpMHiVpt
Horizontal and vertical resolutions of the metric (high resolution) viewport. The horizontal resolution is dpHorzRes; the vertical resolution is –dpVertRes.
dpELoWin
Width and height of the English (low resolution) window. The width is dpHorzSize*1000; the height is dpVertSize*1000.
dpELoVpt
Horizontal and vertical resolutions of the English (low resolution) viewport. The horizontal resolution is dpHorzRes*254; the vertical resolution is –dpVertRes*254.
dpEHiWin
Width and height of the English (high resolution) window. The width is dpHorzSize*10,000; the height is dpVertSize*10,000.
dpEHiVpt
Horizontal and vertical resolutions of the English (high resolution) viewport. The horizontal resolution is dpHorzRes*254; the vertical resolution is –dpVertRes*254.
dpTwpWin
Width and height of the twip window. There are 20 twips per 1 printer's point and 72 printer's points per inch. The width is dpHorzSize*14400; the height is dpVertSize*14400.
dpTwpVpt
Horizontal and vertical resolutions of the twip viewport. The horizontal resolution is dpHorzRes*254; the vertical resolution is –dpVertRes*254.
dpLogPixelsX
Number of pixels per logical inch along a horizontal line on the display surface. This value is used to match fonts.
dpLogPixelsY
Number of pixels per logical inch along a vertical line on the display surface. This value is used to match fonts.
dpDCManage
Device-context management capabilities. Can be one of these values:
0x0000 | Driver allows multiple DCs. It creates a new PDEVICE structure for each DC that specifies a new device and filename pair, but uses the same PDEVICE structure for any subsequent DCs that specify the same device and filename pair.
DC_SPDEVICE (0x0001) | Driver allows multiple DCs but it creates a new PDEVICE structure for each DC regardless of whether the device and filename pairs are the same.
DC_1PDEVICE (0x0002) | Driver allows multiple DCs but only if all DCs have unique device and filename pairs. The driver creates a PDEVICE structure for each DC. The driver returns an error on any attempt to create a second DC with an existing device and filename pair.
DC_IGNOREDFNP (0x0004) | Driver allows multiple DCs but only creates one PDEVICE structure . All DCs share the same PDEVICE structure regardless of the device and filename pairs.
0x0006 | Driver allows only one DC. The driver returns an error on any attempt to create a second DC.

The values 0x0003, 0x0005, and 0x0007 are not valid and must not be used.

dpCaps1
Additional raster abilities. Can be one of these values:
C1_TRANSPARENT (0x0001) | Driver supports transparent BitBlts.
TC_TT_ABLE (0x0002) | Informs GDI that the driver is capable of producing TrueType as raster fonts. The driver must call the dmExtTextOut function to draw the raster font into the bitmap. The value is similar to TC_RA_ABLE.
C1_TT_CR_ANY (0x0004) | Driver can rotate TrueType fonts.
C1_EMF_COMPLIANT (0x0008) | Driver supports metafile spooling.
C1_DIBENGINE (0x0010) | Driver is DIB engine compliant.
C1_GAMMA_RAMP (0x0020) | Driver supports gamma ramp setting.
C1_ICM (0x0040) | Driver does some form of ICM support.
C1_REINIT_ABLE (0x0080) | Driver supports ReEnable call.
C1_GLYPH_INDEX (0x0100) | Driver supports glyph index fonts.
C1_BIT_PACKED (0x0200) | Driver supports bit-packed glyphs.
C1_BYTE_PACKED (0x0400) | Driver supports byte-packed glyphs.
C1_COLORCURSOR (0x0800) | Driver supports color-cursors and async SetCursors.
C1_CMYK_ABLE (0x1000) | Driver supports CMYK COLOREF structures.
C1_SLOW_CARD (0x2000) | Driver has little or no acceleration (for example, VGA).

All other values are reserved.

dpSpotSizeX
Horizontal spot size for TrueType fonts on this device.
dpSpotSizeY
Vertical spot size for TrueType fonts on this device.
dpNumPalReg
Number of entries in the device's palette. This is the total number of simultaneous colors available for palette-capable devices. Nonpalette-capable devices ignore this value.
dpPalReserved
Even number of reserved system colors available for palette-capable devices. Nonpalette-capable devices ignore this value.
dpColorRes
Palette resolution, which equals the number of bits going into video DACS. Nonpalette-capable devices ignore this value.

The dpText member requires that for each precision level the precision levels below are also set. For example, the TC_SA_INTEGER value requires that the TC_SA_DOUBLE value be set, and the TC_SA_CONTIN value requires that all three values be set. Because the lowest precision level of each capability be supported, no value is provided in dpText for the lowest level of each capability.

The dpAspectX, dpAspectY, and dpAspectXY members specify the relative width, height, and diagonal width of a device pixel and correspond directly to the device's aspect ratio. For devices whose pixels do not have integral diagonal widths, the member values can be multiplied by a convenient factor to preserve information. For example, pixels on a device with a 1 to 1 aspect ratio have a diagonal width of 1.414. For reasonable results, the aspect members should be set to 100, 100, and 141, respectively. For numerical stability, the member values should be kept under 1000.

The window/viewport pair members are the numerator and denominator of the scale fraction used to correct for the device aspect ratio, and to set to a fixed unit of measurement, either metric or English. These numbers should be integers in the range of -32768 through 32767. When calculating these constants, out-of-range values can be divided by some number to bring them back into range as long as the corresponding window or viewport constant is divided by the same number.

The dpRaster member is also used to specify scaling support. If the RC_SCALING value is set, the device does graphics scaling. Certain devices perform graphics at one resolution and text at another. Some applications require that character cells be an integral number of pixels. If a device reports that its graphics resolution is 75 dpi but its text resolution is 300 dpi, its character cells are not an integral number of pixels (because they are digitized at 300 dpi). To get around this problem, GDI uses scaling devices. The device driver registers itself as a 300 dpi device but all the graphics at 300 dpi are scaled to 75 dpi. Any device that scales must have the RC_SCALING value set. Scaling always reduces the resolution; it never increases it. GDI calls the Control function with GETSCALINGFACTOR escape before output to a device. The scaling factor is a shift count that is a power of two. Therefore, a scaling factor of 2 means "reduce by 4", and a scaling factor of 1 means "reduce by 2". Scaling devices are strongly discouraged because compatible bitmaps to scaling devices cannot image both graphics and text.

The number of reserved colors on the palette is always 20, with 16 corresponding to the VGA colors and 4 special colors. Half of the reserved palette colors are placed at the beginning and half at the end of the palette.

See Also

Enable, PDEVICE


LOGBRUSH

typedef struct tagLOGBRUSH {
    short  lbStyle;
    long   lbColor;
    short  lbHatch;
    long   lbBkColor;
    long   lbhcmXform;
} LOGBRUSH;

Contains style and color information for a brush.

lbStyle
Brush style. GDI requires that drivers support at least the following brush styles:
Value | Meaning
BS_SOLID (0) | Single solid or dithered color.
BS_HOLLOW (1) | No color or pattern.
BS_HATCHED (2) | A predefined pattern.
BS_PATTERN (3) | Pattern specified by a given bitmap.

lbColor
Foreground color for brushes having BS_SOLID and BS_HATCHED values. For BS_PATTERN values, this member is the address of a global memory object that contains the device-dependent bitmap. Brush colors are specified as physical colors. For palette-capable devices, this member specifies a physical-color index if the high-order byte is 0xFF. For the BS_HOLLOW value, this member is zero.
lbHatch
Brush pattern for brushes having the BS_HATCHED style, or the handle of the device-dependent pattern bitmap for brushes having the BS_PATTERN style. For BS_SOLID and BS_HOLLOW values, this member is zero.

For BS_HATCHED brushes, this member specifies a brush pattern. It can be one of these values:
Value | Meaning
HS_HORIZONTAL | Horizontal hatch
HS_VERTICAL | Vertical hatch
HS_FDIAGONAL | 45-degree upward hatch (left to right)
HS_BDIAGONAL | 45-degree downward hatch (left to right)
HS_CROSS | Horizontal and vertical cross hatch
HS_DIAGCROSS | 45-degree cross hatch

lbBkColor
Background color for brushes having the BS_HATCHED style. Brush colors are specified as physical colors. For palette-capable devices, this member specifies a physical color index if the high-order byte is 0xFF.
lbhcmXform
Transform for image color matching.

See Also

EnumObj


LOGFONT

typedef struct {
    short lfHeight;
    short lfWidth;
    short lfEscapement;
    short lfOrientation;
    short lfWeight;
    BYTE  lfItalic;
    BYTE  lfUnderline;
    BYTE  lfStrikeOut;
    BYTE  lfCharSet;
    BYTE  lfOutPrecision;
    BYTE  lfClipPrecision;
    BYTE  lfQuality;
    BYTE  lfPitchAndFamily;
    BYTE  lfFaceName [LF_FACENAME];
} LOGFONT;

Contains the logical attributes for a font.

lfHeight
Height of the font, in device units. If this member is greater than zero, the driver should choose a font with a cell height that matches the given height. If this member is zero, the driver should choose a font having a reasonable default size. If this member is less than zero, the driver should choose a font whose character height (that is, cell height less internal leading) matches the absolute value of this member. In all cases, the driver should choose the largest font that does not exceed the requested height and, if there is no such font, choose the next smallest font available.
lfWidth
Average width of characters in the font, in device units. If this member is zero, the driver should choose an available font with a digitization aspect ratio (the dfVertRes member of the FONTINFO structure) that most closely matches the aspect ratio of the device (the dpAspectY member in the GDIINFO structure). When comparing fonts, the driver should compare the absolute values of the differences between the digitization aspect ratio and the device aspect ratio.
lfEscapement
Angle, in tenths of a degree, counterclockwise from the x-axis of the vector passing through the origin of all the characters in the string.
lfOrientation
Angle, in tenths of a degree, counterclockwise from the x-axis of the baseline of the character.
lfWeight
Weight of the font ranging from 1 through 1000, with 400 being the value for the standard font. If this member is zero, the driver should choose a reasonable weight. The following values are defined:

FW_DONTCARE (0)

FW_THIN (100)

FW_EXTRALIGHT (200)

FW_LIGHT (300)

FW_NORMAL (400)

FW_MEDIUM (500)

FW_SEMIBOLD (600)

FW_BOLD (700)

FW_EXTRABOLD (800)

FW_HEAVY (900)

lfItalic
Italic flag. If TRUE, the font is to be italic; otherwise, it is not.
lfUnderline
Underline flag. If the low bit is set, the font is to be underlined. All other bits must be zero.
lfStrikeOut
Strikeout flag. If the low bit is set, the font is to be struck out. All other bits must be zero.
lfCharSet
Character-set to be used. Can be one of these values:
ANSI_CHARSET (0) | ANSI character set.
DEFAULT_CHARSET (1) | Default character set.
SYMBOL_CHARSET (2) | Symbol character set.
OEM_CHARSET (255) | OEM-specific character set. The characters and corresponding character codes depend on the computer.

Character set values that support international versions of the operating system are also permitted. The following are defined:

MAC_CHARSET (77)

SHIFTJIS_CHARSET (128)

HANGEUL_CHARSET (129)

CHINESEBIG5_CHARSET (136)

lfOutPrecision
Required output precision for text. Can be one of these values:
OUT_DEFAULT_PRECIS (0x00) | Chooses a reasonable font.
OUT_STRING_PRECIS (0x01) | Chooses the font with a size (height and width) most closely matches the requested size. The driver may disregard the requested orientation and escapement, but other attributes must match.
OUT_CHARACTER_PRECIS (0x02) | Chooses the font with a size (height and width) most closely matches the requested size. The driver may disregard the requested orientation, but other attributes must match.
OUT_STROKE_PRECIS (0x03) | Chooses a font with attributes exactly match the requested attributes.
OUT_TT_PRECIS (0x04) | Choose a True Type font when more than one type of font with a given name exits in the system.
OUT_DEVICE_PRECIS (0x05) | Choose a device font when more than one type of font with a given name exits in the system.
OUT_RASTER_PRECIS (0x06) | Choose a raster font when more than one type of font with a given name exits in the system.
OUT_TT_ONLY_PRECIS (0x07) | Always choose a True Type font even when the given name matches a raster or vector font.

lfClipPrecision
Required clipping precision for text. Can be one of these values:
CLIP_DEFAULT_PRECIS (0x00) | Chooses a reasonable font.
CLIP_CHARACTER_PRECIS (0x01) | Chooses a font that allows clipping of individual characters. The driver must be able to clip a character if any portion of it lies outside the clipping rectangle.
CLIP_STROKE_PRECIS (0x02) | Chooses a font that allows clipping of portions of a character. The driver must be able to clip any portion of a character that lies outside the clipping rectangle.
CLIP_MASK (0x0F)
CLIP_LH_ANGLES (0x10) | If the CLIP_LH_ANGLES bit is set, rotation for all fonts depends on whether the orientation of the coordinate system is left-handed or right-handed. If CLIP_LH_ANGLES is not set, device fonts always rotate counterclockwise, but the rotation of other fonts is dependent on the orientation of the coordinate system.
CLIP_TT_ALWAYS (0x20)
CLIP_EMBEDDED (0x80) | To use an embedded read-only font, applications must specify CLIP_EMBEDDED.

lfQuality
Required quality for text. Can be one of these values:
DEFAULT_QUALITY (0x00) | Chooses a reasonable font.
DRAFT_QUALITY (0x01) | Chooses a font that generates the most efficient, speediest output. The driver can sacrifice appearance if a speedier font has lower quality. GDI synthesizes bold, italic, underline, and strikethrough characters if needed.
PROOF_QUALITY (0x02) | Chooses a font that generates the highest-quality output. The driver should sacrifice speedy output if a slower font has higher quality. The driver should sacrifice output precision if a font that does not exactly match the requested attributes (such as size) is a higher quality. GDI synthesizes bold, italic, underline, and strikeout characters if needed.

lfPitchAndFamily
Font pitch and font family. This member is a combination of one pitch and one family value. The pitch value can be one of these values:
DEFAULT_PITCH (0x00) | Chooses a reasonable font.
FIXED_PITCH (0x01) | Chooses a fixed-pitch font.
VARIABLE_PITCH (0x02) | Chooses a variable-pitch font.

Font family, which describes in a general way the look of a font. Can be one of these values:
FF_DONTCARE (0x00) | Chooses a reasonable font.
FF_ROMAN (0x10) | Chooses a variable-pitch font with serifs.
FF_SWISS (0x20) | Chooses a variable-pitch fonts without serifs.
FF_MODERN (0x30) | Chooses a fixed-pitch font.
FF_SCRIPT (0x40) | Chooses a cursive or script font.
FF_DECORATIVE (0x50) | Chooses a novelty font.

lfFaceName
Null-terminated string that specifies the name of the font. The driver should choose a font having the given name. If the string is empty (the first byte is zero), the driver should choose a reasonable font. The string, including the null terminating character, does not exceed 32 bytes (LF_FACESIZE).

See Also

EnumObj, GDIINFO, FONTINFO


LOGPEN

typedef struct tagLOGPEN {
    unsigned short int  lopnStyle;
    POINT lopnWidth;
    unsigned long int  lopnColor;
    unsigned short int  lopnStyle2;
    unsigned long int  lopnhcmXform;
} LOGPEN;

Specifies a logical pen. Pens draw lines and borders.

lopnStyle
Pen style. GDI requires that drivers support at least the following pen styles:
Value | Meaning
LS_SOLID (0) | Draws solid lines.
LS_DASHED (1) | Draws dashed lines.
LS_DOTTED (2) | Draws dotted lines.
LS_DOTDASHED (3) | Draws lines with alternating dots and dashes.
LS_DASHDOTDOT (4) | Draws lines with a repeating pattern of a dash followed by two dots.
LS_NOLINE (5) | Nothing is drawn.
LS_INSIDEFRAME (6) | Creates a pen with which a line is drawn inside the frame of ellipses and rectangles. If the width of the pen is greater than 1 and the pen style is PS_INSIDEFRAME, the line is drawn inside the frame of all primitives except polygons and polylines; the pen is drawn with a logical (dithered) color if the pen color does not match an available RGB value. The PS_INSIDEFRAME style is identical to PS_SOLID if the pen width is less than or equal to 1.

lopnWidth
A POINT structure with an x member that contains the pen width in device units. A zero-width pen is drawn with the system's smallest width. Negative-width pens have no width and are NULL pens. The y member is ignored.
lopnColor
Color for the pen. Pen colors are specified as physical colors. For palette-capable devices, the value is a color index if the high byte is 0x0FFH.
lopnStyle2
Alternate pen style. May be one of the following:
Value | Meaning
LS_ENDCAP_FLAT (0x01) | End caps are flat.
LS_ENDCAP_ROUND (0x02) | End caps are round.
LS_ENDCAP_SQUARE (0x04) | End caps are square.
LS_JOIN_BEVEL (0x08) | Joins are beveled.
LS_JOIN_MITER (0x10) | Joins are mitered when they are within the current limit that the application set by the SetMiterLimit function. If it exceeds this limit, the join is beveled.
LS_JOIN_ROUND (0x20) | Joins are round.

lopnhcmXform
Transformation for image color matching.

See Also

EnumObj, POINT


OSPOLYPOLY

typedef struct tagOSPOLYPOLY {
    LPINT   lpNumPts; \\ number of POINT structures
    LPPOINT lppt;     \\ points describing the polygons
} OSPOLYPOLY;

Contains information about the polygons drawn by the OS_POLYPOLYGON style of the Output function.

See Also

Output(OS_POLYPOLYGON)


PBITMAP

typedef struct tagPBITMAP {
    short bmType;         // bitmap type; must be zero
    short bmWidth;        // width of the bitmap, in pixels
    short bmHeight;       // height of the bitmap, in pixels
    short bmWidthBytes;   // see below
    BYTE  bmPlanes;       // number of color planes
    BYTE  bmBitsPixel;    // number of color bits for each pixel
    long  bmBits;         // see below
    long  bmWidthPlanes;  // see below
    long  bmlpPDevice;    // see below
    short bmSegmentIndex; // see below
    short bmScanSegment;  // see below
    short bmFillBytes;    // see below
    short reserved1;      // reserved; do not use
    short reserved2;      // reserved; do not use
} PBITMAP;

Specifies the dimensions, attributes, and bits of a physical bitmap.

bmWidthBytes
Number of bytes in each raster line of the bitmap. The number of bytes must be even; all raster lines must be aligned on 16-bit boundaries.
bmBits
Address of an array of bits that specifies the pixels of the bitmap. The array must be aligned on a 16-bit boundary.
bmWidthPlanes
Size, in bytes, of each color plane. It is equal to the product of bmWidthBytes*bmHeight.
bmlpPDevice
Address of the PDEVICE structure that specifies the device for which this bitmap is compatible.
bmSegmentIndex
Segment or selector offset for segments in the bitmap array. If the bitmap is less than 64K, this member is zero.
bmScanSegment
The number of raster lines contained in each segment of the bitmap array. If the bitmap is less than 64K, this member is zero.
bmFillBytes
The number of extra bytes in each segment. GDI allocates storage for the bitmap array in 16-byte multiples.

If the bitmap bits exceed 64K, GDI allocates a two or more segments to store the bitmap. In such cases, the bmScanSegment member specifies the number of raster lines stored in each segment, with bmFillBytes that specifies any additional bytes needed to round the segment size out to a multiple of 16; no segment contains more than 64K. The total number of segments is equal to the quotient of bmHeight divided by bmScanSegment rounded up by one if the remainder is not zero. The selector (or segment address) for each segment is a multiple of bmSegmentIndex.

GDI stores the bits in the bitmap array as raster lines, with the raster line representing the top of the bitmap stored first. If the bitmap has more than one plane, GDI stores the first raster lines for all planes at the beginning of the array, stores the second raster lines next, and so on. The following shows the layout for a four-plane bitmap:

Plane 0, first raster line
Plane 1, first raster line
Plane 2, first raster line
Plane 3, first raster line
Plane 0, second raster line
        .
        .
        .
Plane 0, last raster line
Plane 1, last raster line
Plane 2, last raster line
Plane 3, last raster line

If the bitmap array exceeds 64K, GDI splits the raster lines across several segments but retains the storage order, placing the first raster lines in the first segment and the last raster lines in the last segment. When GDI splits the raster lines, it ensures that matching raster lines from the various planes are always in the same segment. If necessary, GDI leaves a number of empty bytes (as specified by bmFillBytes) at the end of the segment to round out the segment size to a multiple of 16.

See Also

PDEVICE


PDEVICE

typedef struct tagPDEVICE {
    short pdType;
} PDEVICE;

Contains information that a graphics driver uses to identify a device and the current state of the device.

pdType
Device type. If this member is nonzero, the structure identifies a device and all remaining members are driver specific. If this member is zero, the structure identifies a memory bitmap and all remaining members must be identical to a PBITMAP structure.

GDI allocates space for the PDEVICE structure when it calls the Enable function to initialize a device driver. The size of this structure must be specified in the dpDEVICEsize member of the GDIINFO structure.

The size and content of the structure depends entirely on the driver. For example, the structure may include the current pen, the current position, the communication port of a particular device, and other state information. However, the first member in every PDEVICE structure must be pdType.

See Also

Enable, GDIINFO, PBITMAP


POINT

typedef struct tagPOINT {
    short x;  // x-coordinate of a point
    short y;  // y-coordinate of a point
} POINT;

Contains the x- and y-coordinates of a point.


RECT

typedef struct tagRECT {
    short left;   // x-coordinate of top-left corner
    short top;    // y-coordinate of top-left corner
    short right;  // x-coordinate of bottom-right corner
    short bottom; // y-coordinate of bottom-right corner
} RECT;

Contains the coordinates of the top-left and bottom-right corners of a rectangle.

See Also

Output


REGION

typedef struct {
    WORD       id;        // if LPREGION 0x8000 else LPRECT
    WORD       cbSize;    // sizeof(REGION)
    LPRECT     lprcClip;  // NULL or region walking opt
    DWORD      dwUniq;    // region uniqueness value
    RECT       rcBBox;    // bounding box of region
    DWORD      cScans;    // count of scans in region
    LPSCAN     lpScan;    // ptr to first scan in region
} REGION;

Defines the attributes, bounding box, and scan lines of a region.


RGBQUAD

typedef struct tagRGBQUAD {
    BYTE rgbBlue;
    BYTE rgbGreen;
    BYTE rgbRed;
    BYTE rgbReserved;
} RGBQUAD;

Specifies a logical color or a 16-bit color index. A logical color specifies the color desired by an application. A color index indirectly specifies a logical color by identifying a color in an array (or table) of colors.

rgbBlue
Intensity of blue. It must be a value in the range of zero (no blue) to 255 (brightest blue).
rgbGreen
Intensity of green. It must be a value in the range of zero (no green) to 255 (brightest green).
rgbRed
Intensity of red. It must be a value in the range of zero (no red) to 255 (brightest red).
rgbReserved
Type of color that the RGBQUAD structure specifies, either an RGB color or a 16-bit color index. If this member is zero, this is an RGB color. If this member is 0xFF, then the low 16 bits (rgbBlue and rgbGreen members) is a color index, not an RGB color.

When the colors are at minimum intensity (0, 0, 0), the result is black; when at maximum intensity (255, 255, 255), the result is white; and when at half intensity (127, 127, 127), the result is gray.

Primary colors can be combined to form new colors. For example, solid red (0, 0, 255) and blue (255, 0, 0) can form purple (255, 0, 255). If a device cannot display all the possible RGB color combinations, the device driver must map given RGB color values to colors the device can display. For example, for a black-and-white display with only one bit per pixel, the driver uses a cutoff intensity at which all the RGB values above the intensity are white and all below are black. One method used to compute the cutoff intensity is to add the individual color intensities according to the following formula:

((5*rgbGreen+3*rgbRed+rgbBlue)+4)>>3

If the result is greater than 128, then all the RGB values above that intensity will be white, and those below it will be black.


SCAN

typedef struct {
    short scnPntCnt;    // count of x coordinates (not x pairs)
    short scnPntTop;    // top line in a group of scanlines (inclusive)
    short scnPntBottom; // bottom line (exclusive)
    short scnPntX[2];   // variable-length array of x pairs
                        // (inclusive-exclusive)
    short scnPntCntToo; // same as scnPntCnt
} SCAN;

Contains the drawing information for a group of scanlines. This is not a true structure, because the scnPntX member is a variable-length array.

See Also

Output(OS_POLYSCANLINE)


TEXTMETRIC

typedef struct tagTEXTMETRIC {
    short  tmHeight;           // see below
    short  tmAscent;           // see below
    short  tmDescent;          // see below
    short  tmInternalLeading;  // see below
    short  tmExternalLeading;  // recommended amount of leading
    short  tmAveCharWidth;     // avg. width of characters in font
    short  tmMaxCharWidth;     // max. width of any character in font
    short  tmWeight;           // weight of font
    BYTE   tmItalic;           // italic font if value is nonzero
    BYTE   tmUnderlined;       // underlined font if value is nonzero
    BYTE   tmStruckOut;        // struckout font if value is nonzero
    BYTE   tmFirstChar;        // value of first character for font
    BYTE   tmLastChar;         // value of last character for font
    BYTE   tmDefaultChar;      // see below
    BYTE   tmBreakChar;        // see below
    BYTE   tmPitchAndFamily;   // see below
    BYTE   tmCharSet;          // see below
    short  tmOverhang;         // see below
    short  tmDigitizedAspectX; // see below
    short  tmDigitizedAspectY; // see below
} TEXTMETRIC;

Contains a list of the basic metrics of a physical font.

tmHeight
Height of the character cell. This member is equal to the sum of the tmAscent and tmDescent members.
tmAscent
Ascent of the character cell (the height of the cell measured from the baseline).
tmDescent
Descent of the character cell (the height of the cell measured from the baseline to the bottom of the cell).
tmInternalLeading
Amount of internal leading. It is equal to the difference between the cell height (as expressed by the tmHeight member) and the maximum height of any character in the font (excluding the height of accent marks).
tmDefaultChar
Value of the character that is to be substituted for characters not in the font.
tmBreakChar
Value of the character used to define word breaks for text justification.
tmPitchAndFamily
Font pitch and font family. This member is a combination of one pitch and one family value. The pitch value can be one of these values:
DEFAULT_PITCH (0x00) | Chooses a reasonable font.
FIXED_PITCH (0x01) | Chooses a fixed-pitch font.
VARIABLE_PITCH (0x02) | Chooses a variable-pitch font.

The font-family value can be one of these values:
FF_DONTCARE (0x00) | Chooses a reasonable font.
FF_ROMAN (0x10) | Chooses a variable-pitch font with serifs.
FF_SWISS (0x20) | Chooses a variable-pitch fonts without serifs.
FF_MODERN (0x30) | Chooses a fixed-pitch font.
FF_SCRIPT (0x40) | Chooses a cursive or script font.
FF_DECORATIVE (0x50) | Chooses a novelty font.

tmCharSet
Character set of the font. Can be one of these values:
ANSI_CHARSET (0x00) | ANSI character set.
SYMBOL_CHARSET (0x02) | Symbol character set.
OEM_CHARSET (0xFF) | OEM-specific character set. The characters and corresponding character codes depend on the computer.

tmOverhang
Amount of additional, synthesized width of a character or character string. This member may be is nonzero if the driver synthesizes character attributes, such as bold or italic, by modifying an existing font.
tmDigitizedAspectX
Horizontal aspect ratio for which this font was designed. This member is equal to the dfHorizRes member of the FONTINFO structure.
tmDigitizedAspectY
Vertical aspect ratio for which this font was designed. This member is equal to the dfVertRes member of the FONTINFO structure.

GDI makes a string bold by expanding the intracharacter spacing and overstriking with an offset; the overhang is the distance by which the overstrike is offset. GDI italicizes a font by skewing the string, and the overhang is the amount the top of the font is skewed past the bottom of the font.


TEXTXFORM

typedef struct tagTEXTXFORM {
    short  ftHeight;
    short  ftWidth;
    short  ftEscapement;
    short  ftOrientation;
    short  ftWeight;
    BYTE  ftItalic;
    BYTE  ftUnderline;
    BYTE  ftStrikeOut;
    BYTE  ftOutPrecision;
    BYTE  ftClipPrecision;
    short  ftAccelerator;
    short  ftOverhang;
} TEXTXFORM;

Contains information describing the actual appearance of text as displayed by the device.

ftHeight
Height of characters (ascent + descent), in device units.
ftWidth
Width, in device units, of the bounding box of the uppercase character "X."
ftEscapement
Angle, in tenths of a degree, counterclockwise from the x-axis of the vector passing through the origin of all the characters in the string.
ftOrientation
Angle, in tenths of a degree, counterclockwise from the x-axis of the baseline of the character.
ftWeight
Weight of the font ranging from 1 through 1000, with 400 being the value for the standard font.
ftItalic
Italic flag. If the low bit is set, the font is to be italic. All the other bits must be zero.
ftUnderline
Underline flag. If the low bit is set, the font is to be underlined. All the other bits must be zero.
ftStrikeOut
Strikeout flag. If the low bit is set, the font is to be struck out. All the other bits must be zero.
ftOutPrecision
Output precision for text. Can be one of these values:
OUT_DEFAULT_PRECIS (0x00) | Chooses a reasonable font.
OUT_STRING_PRECIS (0x01) | Chooses the font with a size (height and width) that most closely matches the requested size. The driver may disregard the requested orientation and escapement, but other attributes must match.
OUT_CHARACTER_PRECIS (0x02) | Chooses the font with a size (height and width) that most closely matches the requested size. The driver may disregard the requested orientation, but other attributes must match.
OUT_STROKE_PRECIS (0x03) | Chooses a font with attributes that exactly match the requested attributes.

ftClipPrecision
Clipping precision for text. Can be one of these values:
CLIP_DEFAULT_PRECIS (0x00) | Chooses a reasonable font.
CLIP_CHARACTER_PRECIS (0x01) | Chooses a font that allows clipping of individual characters. The driver must be able to clip a character if any portion of it lies outside the clipping rectangle.
CLIP_STROKE_PRECIS (0x02) | Chooses a font that allows clipping of portions of a character. The driver must be able to clip any portion of a character that lies outside the clipping rectangle.

ftAccelerator
Specifies requested text modifications using the same format as the dpText member of the GDIINFO structure. Each bit in this member is set if the corresponding ability is required to modify the physical font into the requested font.
ftOverhang
Same as tmOverhang of the TEXTMETRIC structure.

Although most of the members in the TEXTXFORM structure correspond to the members in the LOGFONT structure, these members may not always exactly match. For example, if the logical font specified a 19-unit font at string precision and the closest available was a 9-unit font on a device capable of doubling, then the ftHeight member in the structure is 18.

See Also

LOGFONT


Windows 95 Image Color Matching

Microsoft® Windows® 95 includes Image Color Matching (ICM) support, providing consistent, predictable color rendering from digital image input, through monitor preview, to output. The Windows 95 Color Matching Module (CMM) supporting ICM is licensed from the Eastman Kodak company.

The key to ICM support is the use of a profile, which represents the color properties of a monitor, printer, or digital image input device (such as a scanner). Color profiles, which can be provided by a vendor as part of the software for a particular monitor, printer, or scanner, are installed in the \%Windows%\System\Color directory. For information on how to install a color profile along with a color printer device driver, see Introduction to Printer Drivers and Image Color Matching in the Windows 95 DDK Design and Implementation Guide.

The International Color Consortium (ICC) is made up of computer and imaging industry leaders (including Kodak, Microsoft, Apple Computer, Sun Microsystems, and Silicon Graphics, among others) and industry standard-setting bodies. Windows 95 ICM support uses color profiles that comply with the ICC Profile Format Specification. ICC maintains an Internet Web site at the URL http://www.color.org. A copy of the ICC Profile Format Specification, Version 3.2, can be downloaded from that site.


Windows 95 Multilingual IME

Windows 98 Multilingual IME Release Notes

Updated files may be found on the Windows® 98 DDK in the \src\IME folder. This includes a current sample project (fakeime) and additional notes for both user-level (SDK) and kernel-level (DDK) implementations.

In Windows® 95, IMEs are provided as dynamic link libraries (DLLs), in contrast to IMEs of Windows® 3.1 Asian Edition, and each IME runs as one of the multilingual keyboard layouts. Compared to the Windows 3.1 IME, the Windows 95 multilingual IMEs provide the following advantages:

  • Run as a component of the multilingual environment
  • Provide multiple input contexts for each application task
  • Provide one active IME for each application thread
  • Give information to an application through its message loop (message order is not changed)
  • Provide strong support for both IME-unaware and IME-aware applications

To take full advantage of IME, an application needs to support the Windows 95 IME application I/F.

This documentation describes the application I/F of the Windows 95 IME architecture.


Structure of IME

The Windows 95 IME must provide two components: the IME conversion interface and the IME user interface. The IME conversion interface is provided as a set of functions that are exported from the IME module. These functions are called by IMM. The IME user interface is provided as a set of windows. These windows receive messages and provide the IME's user interface.


IME Aware Applications

Following are the types of applications:

  • IME-unaware applications: This type of application never intends to control the IME. However, if the application accepts DBCS characters, the user can enter any DBCS character into the application using IME.
  • IME half-aware applications: This type of application typically controls various contexts of IME, such as open and closed, composition form, and so on, but it does not display any user interface for IME.
  • IME full-aware applications: This type of application is typically responsible for displaying any information given to it by IME.

In Windows 95, one IME-unaware application is supported with one default IME window and one default input context.

An IME half-aware application creates its own IME windows using the predefined IME class and may or may not handle its own input context.

An IME full-aware application handles the input context by itself. It displays any necessary information given by the input context. It does not use the IME window.


IME User Interface

The IME user interface includes the IME window, the user interface (UI) window, and the components of the UI window.


Features

The IME class is a predefined global window class that implements the user interface portion of the IME. The IME class has many of the same characteristics as the predefined common control windows. An IME window instance can be created by the CreateWindowEx function. Like static controls, the IME class window does not respond to user input by itself; instead, it receives various types of control messages to realize the entire user interface of the IME. An application can create its own IME windows by using the IME class, or it can obtain the default IME window by using the ImmGetDefaultIMEWnd function. An application that creates its own IME window or uses the default IME window is considered an IME-aware application and receives the following benefits (as compared to a similar application in Windows 3.1):

  • Including candidates listing windows, each application can have its own window instance of the user interface so the user can stop in the middle of any operation and change the focus to another application. In the Windows 3.1 Japanese Edition, the user must abandon an operation when changing to another application.
  • Because the IME user interface window has the application's window handle, it can provide default behavior for the application. For example, it can move automatically when the application moves, it can automatically trace the caret position of the window, and it can indicate the mode for each application.

Even though the system provides only one IME class, there are two types of IME window. One type is created by the system for IME-unaware applications. The DefWindowProc function processes messages for this window. The DefWindowProc function's IME user interface is shared by all IME-unaware windows of a thread. In this documentation, this is called the default IME window. The other windows are created by IME-aware applications. In this documentation, windows created by IME-aware applications are called application IME windows.


Default and Application IME Windows

The system creates the default IME window when a thread is initialized. That is, the default IME window is given to a thread automatically. The default IME window provides the IME user interface for IME-unaware applications. When the IME or IMM generates an IME message (WM_IME_*), an IME-unaware application passes the message to the DefWindowProc function. DefWindowProc sends the necessary messages to the default IME window, which provides the default IME user interface for the application. An IME-aware application can also use the default IME window when it does not hook messages from IME. The application can use its own application IME window only when necessary.


IME Class

The IME class is a predefined window class in Windows 95-FE, just as Edit is a predefined class. The predefined IME class handles the entire user interface of the IME and processes all control messages from IME and applications that include IMM functions. An application can create its own IME user Interface by using the IME class. The system IME class will not be replaced by any IME.

The window procedure associated with the IME class processes the WM_IME_SELECT message. This message includes the keyboard layout of the newly selected IME. The IME class uses the keyboard layout to retrieve the names of the classes defined by each IME. Using the class names, the IME class creates a user interface window for the current active IME.


UI Class from IME

Every IME must register its own user interface class (UI) with the system. The UI class provides IME-unique functionality. An IME registers its own class when the IME is attached to the process. That is, when the DllEntry function is called with DLL_PROCESS_ATTACH. The IME must specify the UI class name in a call to the ImeInquire function. The UI class should be registered with CS_IME style so every application can use the UI class. The UI class name (including the null terminator) can be up to 16 TCHAR characters. This limitation may be extended in future version of Windows.

When registering the user interface class, you should specify eight bytes of extra window data. That is, set the cbWndExtra member of the WNDCLASSEX structure to 2 * sizeof(LONG). The extra window data is used by the system.

An IME can register any class and create any window while performing tasks for an application.

The following example shows how to register the IME window class:

BOOL WINAPI DLLEntry (
    HINSTANCE    hInstDLL,
    DWORD        dwFunction,
    LPVOID       lpNot)
{
    switch (dwFunction) {
        case DLL_PROCESS_ATTACH:
            hInst= hInstDLL;

            wc.style          = CS_MYCLASSFLAG | CS_IME;
            wc.lpfnWndProc    = MyUIServerWndProc;
            wc.cbClsExtra     = 0;
            wc.cbWndExtra     = 2 * sizeof(LONG);
            wc.hInstance      = hInst;
            wc.hCursor        = LoadCursor( NULL, IDC_ARROW);
            wc.hIcon          = NULL;
            wc.lpszMenuName   = (LPSTR) NULL;
            wc.lpszClassName  = (LPSTR) szUIClassName;
            wc.hbrBackground  = NULL;

            if(!RegisterClass((LPWNDCLASS)&wc))
                return FALSE;

            wc.style          = CS_MYCLASSFLAG | CS_IME;
            wc.lpfnWndProc    = MyCompStringWndProc;
            wc.cbClsExtra     = 0;
            wc.cbWndExtra     = cbMyWndExtra;
            wc.hInstance      = hInst;
            wc.hCursor        = LoadCursor(NULL, IDC_ARROW);
            wc.hIcon          = NULL;
            wc.lpszMenuName   = (LPSTR) NULL;
            wc.lpszClassName  = (LPSTR) szUICompStringClassName;
            wc.hbrBackground  = NULL;

            if(!RegisterClass((LPWNDCLASS)&wc))
                return FALSE;

            break;

        case DLL_PROCESS_DETACH:
            UnregisterClass(szUIClassName,hInst);
            UnregisterClass(szUICompStringClassName,hInst);
            break;
    }
    return TRUE;
}


UI Window

The IME windows of the IME class are created by applications or by the system. When the IME window is created, the UI window that is provided by IME itself is created and owned by the IME window. Each UI window has the current input context. You can retrieve the input context by calling the GetWindowLong function and specifying the IMMGWL_IMC index value when the UI window receives an IME message (WM_IME_*). The UI window can refer to this input context and handle the messages. The UI window can retrieve the input context at any time except in response to the WM_CREATE message.

The IME must not alter the extra window data of a UI window. If you need extra window data for an instance of a UI window, you can use SetWindowLong and GetWindowLong with IMMGWL_PRIVATE. The IMMGWL_PRIVATE value provides access to a LONG value of extra data for an instance of a UI window. If you need more than one LONG value of extra data, you can store the handle of a memory block into the IMMGWL_PRIVATE area.

The UI window procedure can use the DefWindowProc function, but the UI window must not pass IME messages to DefWindowProc. Even if an IME message is not handled by the UI window procedure, the UI window must not pass it to DefWindowProc.

LRESULT UIWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    HIMC hIMC;
    HGLOBAL hMyExtra;

    switch(msg){
        case WM_CREATE:
            // Allocate the memory bloack for the window instance.
            hMyExtra = GlobalAlloc(GHND,size_of_MyExtra);
            if (!hMyExtra)
                MyError();

            // Set the memory handle into IMMGWL_PRIVATE
            SetWindowLong(hWnd, IMMGWL_PRIVATE, (LONG)hMyExtra);
                .
                .
                .
            break;

        case WM_IME_xxxx:
            // Get IMC;
            hIMC = GetWindowLong(hWnd,IMMGWL_IMC);

            // Get the memory handle for the window instance.
            hMyExtra = GetWindowLong(hWnd, IMMGWL_PRIVATE);

            lpMyExtra = GlobalLock(hMyExtra);
                .
                .
                .
            GlobalUnlock(hMyExtra);

            break;

            .
            .
            .

        case WM_DESTROY:
            // Get the memory handle for the window instance.
            hMyExtra = GetWindowLong(hWnd, IMMGWL_PRIVATE);

            // Free the memory block for the window instance.
            GlobalFree(hMyExtra);
            break;

        default:
            return DefWindowProc(hWnd, msg, wParam, lParam);

    }
}

The UI window must perform actions within the currently selected input context. When a window is activated, the UI window receives a message that provides the current input context. After this, the UI window runs on the currently selected input context. The input context must have all the information needed by the UI window for showing the composition window, the status window, and so on.

The UI window refers to the input context, but the window does not need to update the context by itself. When the UI window needs to update the input context, it should call IMM functions because the input context is managed by IMM. When the input context changes, IMM and IME receive a notification.

For example, sometimes the UI window needs to change the conversion mode of the input context when the mouse is clicked. To set the conversion mode, the UI window calls the ImmSetConversionMode function, which generates a notification for NotifyIME and sends the WM_IME_NOTIFY message to the UI window. If the UI window changes the display of the conversion mode, the UI window should wait for the WM_IME_NOTIFY message.


Components of UI Window

A UI window can register and show the composition window and the status window by referring to the current input context. The class style of the components of the UI window must include CS_IME. A window instance of the UI window receives information such as the composition string, font, position and so on from the current input context. When a window of the application is getting focus, the system receives the input context that is owned by the window and sets the current input context to the UI window. The system sends the WM_IME_SETCONTEXT message with the handle of its input context to the application and the application passes this message to the UI window. If the current input context is replaced, the UI window should repaint the composition window. Whenever the current context changes, the UI window shows a correct composition window and the status of IME can be assured.

A UI window may create its child windows or pop-up windows to show its status, composition string, or candidate lists. These windows must be the owned window of the UI window and created as disabled windows. Any windows created by IME should not get the focus.


Input Context

The system gives an input context to each thread by default. This context is shared by all IME-unaware windows of the thread.


Associating an Input Context with a Window

A window of an application can associate its window handle to an input context to maintain any status of IME, including the intermediate composition string. Once an application associates an input context to a window handle, the system automatically selects the context whenever the window is activated. Using this feature, an application can be free from the complicated in-out focus processing that was necessary under Windows 3.1.


Using an Input Context

When the application or system creates a new input context, the system prepares the new input context. The new input context already includes IMCC, the components of IMC consisting of hCompStr, hCandInfo, hGuideLine, hPrivate and hMsgBuf. Basically, the IME does not need to create the input context and the components of the input context. The IME can change their size and can retrieve a pointer to the components by locking them.


Access HIMC

To access the input context, an IME must call ImmLockIMC to retrieve a pointer to the input context. ImmLockIMC increments the IMM lock count for IMC, and ImmUnlockIMC decrements it.


Access HIMCC

To access one component of the input context, an IME must call ImmLockIMCC to get a pointer to IMCC. ImmLockIMCC increments the IMM lock count for IMCC, and ImmUnlockIMC decrements it. ImmReSizeIMCC may resize IMCC to the specified size.

Occasionally, an IME may need to create one component of the input context by itself. In this case, the IME can call the ImmCreateIMCC function and obtain the handle of IMCC. This IMCC can be members of the INPUTCONTEXT structure (hCompStr, hCandInfo, hGuideLine, hPrivate or hMsgBuf).

ImmDestroyIMCC destroys one component of the input context.


How to Use an Input Context

The following example shows how to use an input context:

LPINPUTCONTEXT lpIMC;
LPCOMOSITIONSTRING lpCompStr;
HIMCC hMyCompStr;

if (hIMC) { // It is not NULL context.
    lpIMC = ImmLockIMC(hIMC);

    if (!lpIMC) {
        MyError( "Can not lock hIMC");
        return FALSE;
    }

    // Use lpIMC->hCompStr.
    lpCompStr = (LPCOMPOSITIONSTRING) ImmLockIMCC(lpIMC->hCompStr);

    // Access lpCompStr.
    ImmUnlockIMCC(lpIMC->hCompStr);

    // ReSize lpIMC->hCompStr.
    if (!(hMyCompStr = ImmReSizeIMCC(lpIMC->hCompStr,dwNewSize)) {
        MyError("Can not resize hCompStr");
        ImmUnlockIMC(hIMC);
        return FALSE;
    }
    lpIMC->hCompStr = hMyCompStr;
    ImmUnlockIMC(hIMC);
}


Generating Messages

The IMEs need to generate IME messages. When the IME starts a conversion, the IME must generate the WM_IME_STARTCOMPOSITION message. If the IME changes the composition string, the IME must generate the WM_IME_COMPOSITION message. The events from IMEs are realized as generating messages to the window that is associated with the input context. Basically, the IMEs use the lpdwTransKey buffer that is provided by the parameter of the ImeToAsciiEx function to generate the message. The IME puts the messages into the lpdwTransKey buffer when ImeToAsciiEx is called. Even if ImeToAsciiEx is not called, the IME can generate the message to the window that is associated with the input context by using the message buffer of the input context. The input context has the message buffer as a handle of a memory block. The IME puts the messages into the memory block that is provided by the handle of the message buffer. Then, the IME calls ImmGenerateMessage. The ImmGenerateMessage function sends the messages that are stored in the message buffer to the proper window.


Using the Translation Buffer in ImeToAsciiEx

The following example shows how to generate messages by passing a buffer to the ImeToAsciiEx function:

UINT ImeToAsciiEx(uVirKey, uScanCode, lpbKeyState, lpdwTransBuf,
    fuState , hIMC )
{
    DWORD dwMyNumMsg = 0;

    .
    .
    .

    // Set the messages that the IME needs to generate.
    *lpdwTransBuf++ = (DWORD) msg;
    *lpdwTransBuf++ = (DWORD) wParam;
    *lpdwTransBuf++ = (DWORD) lParam;

    // Count the number of the messages that the IME needs to generate.
    dwMyNumMsg++;
    .
    .
    .

    return dwMyNumMsg;
}

The buffer that is specified by lpdwTransBuf is provided by the system. The ImeToAsciiEx function can put all of the messages into this buffer at one time. The number of messages that can be put in this buffer is given at the first double word of the buffer. If the ImeToAsciiEx function needs to generate more messages than the given number, the function can put all of the messages into hMsgBuf that is in the input context, and ImeToAsciiEx returns the number of the messages. When the return value of ImeToAsciiEx is larger than the specified value in lpdwTransBuf, the system does not pick up the messages from lpdwTransBuf. The system looks up the hMsgBuf of the input context that is passed as parameter of ImeToAsciiEx.


Using the Message Buffer

The following example shows how to use the message buffer:

MyGenerateMesage(HIMC hIMC, UINT msg, WPARAM wParam, LPARAMlParam)
{
    LPINPUTCONTEXT lpIMC;
    HGLOBAL hTemp;
    LPDWORD lpdwMsgBuf;
    DWORD dwMyNumMsg = 1;

    // Lock the input context.
    lpIMC = ImmLockIMC(hIMC);
    if (!lpIMC)
        // Error!

    // re-allocate the memory bloack for the message buffer.
    hTemp = ImmReSizeIMCC(lpIMC->hMsgBuf,
        (lpIMC->dwNumMsgBuf + dwMyNumMsg) * sizeof(DWORD) * 3);
    if (!hTemp)
        // Error!

    lpIMC->hMsgBuf = hTemp;

    // Lock the memory for the message buffer.
    lpdwMsgBuf = ImmLockIMCC(lpIMC->hMsgBuf);
    if (!lpdwMsgBuf)
        // Error!

    lpdwNumMsgBuf += 3 * lpIMC->dwNumMsgBuf.
    // Set the number of the messages.
    lpIMC->dwNumMsgBuf += dwMyNumMsg;

    // Set the messages that the IME needs to generate.
    *lpdwMsgBuf++ = (DWORD) msg;
    *lpdwMsgBuf++ = (DWORD) wParam;
    *lpdwMsgBuf++ = (DWORD) lParam;

    // Unlock the memory for the message buffer and the input context.
    ImmUnlockIMCC(lpIMC->hMsgBuf);
    ImmLockIMC(hIMC);

    // Call ImmGenerateMessage function.
    ImmGenerateMessage(hIMC);
}


WM_IME_COMPOSITION Message

When the IME generates the WM_IME_COMPOSITION message, it specifies the lParam as GCS bits. The GCS bits means the available member of the COMPOSITIONSTRING structure. Even if the IME does not update and the member is available now, the IME can set the GCS bit.


Service Definition for IME

When IME generates the WM_IME_COMPOSITION message, it may change the string, the attribute, and the clause information at once. The IME can use the follow definitions.

GCS_COMP

GCS_COMPREAD

GCS_RESULT

GCS_RESULTREAD


About ImeSetCompositionString

If the IME does not have the capability of ImeSetCompositionString, it does not specify any SCS capability in the IMEINFO structure. If the IME can handle ImeSetCompositionString, it sets the SCS_COMPSTR bit. If the IME can generate the reading string from the composition string, it may set the SCS_CAP_MAKEREAD bit.

If the IME has the SCS_CAP_COMPSTR capability, ImeSetCompositionString will be called. The IME takes the new composition string from the application and generates the WM_IME_COMPOSITION message.

If the IME has SCS_CAP_MAKEREAD capability, it can make the reading string from the composition string.


About SCS_SETSTR

If the dwIndex parameter of ImeSetCompositionString is SCS_SETSTR, the IME can clean up all of the COMPOSITIONSTR structure of hIMC.

If it is necessary, IME may update the candidate information and generate the candidate messages IMN_OPENCANDIDATE, IMN_CHANGECANDIDATE, or IMN_CLOSECANDIDATE.

If the lpRead parameter of ImeSetCompositionString is available, IME should make the composition string from the reading string that is in lpRead. Then, the IME makes the attribute and clause information for both the new composition string and the reading string of lpRead. The IME generates WM_IME_COMPOSITION with (GCS_COMP | GCS_COMPREAD). Sometimes IME needs to make it finalize automatically. In this case, the IME may generate WM_IME_COMPOSITION with (GCS_RESULT | GCS_RESULTREAD) instead of GCS_COMPxxx.

If the lpComp parameter of ImeSetCompositionString is available, the IME should make the composition attribute and clause information from the composition string in lpComp. The IME generates WM_IME_COMPOSITION with GCS_COMP. If the IME has the capability of SCS_CAP_MAKEREAD, the IME should make new reading string at the same time. The IME generates WM_IME_COMPOSITION with (GCS_COMP | GCS_COMPREAD). Sometimes, the IME needs to make it finalize automatically. In this case, the IME may generate WM_IME_COMPOSITION with (GCS_RESULT | GCS_RESULTREAD) instead of GCS_COMPxxx.

If both the lpRead and lpComp parameters are available, the IME should make the composition string and the reading string. At this time, IME does not need to follow lpComp and lpRead completely. If the IME cannot make the relation between lpRead and lpComp that is specified by the application, the IME should correct the composition string. The IME makes the attribute and clause information for both the new composition string and the reading string of lpRead. The IME generates WM_IME_COMPOSITION with (GCS_COMP | GCS_COMPREAD). Sometimes, the IME needs to make it finalize automatically. Then, the IME may generate WM_IME_COMPOSITION with (GCS_RESULT | GCS_RESULTREAD) instead of GCS_COMPxxx.


About SCS_CHANGEATTR

SCS_CHANGEATTR effects only attribute information. The IME should not update the composition string, the clause information of the composition string, the reading of the composition string, or the clause information of reading of the composition string.

First, the IME checks the new attribute to determine if it is acceptable. Second, the IME sets the new attribute in the COMPOSITIONSTRING structure of hIMC. At last, the IME generates the WM_IME_COMPOSITION message.

If it is necessary, IME may update the candidate information and generate the candidate messages IMN_OPENCANDIDATE, IMN_CHANGECANDIDATE, or IMN_CLOSECANDIDATE.

IME cannot finalize the composition string.

If the lpRead parameter of ImeSetCompositionString is available, the IME follows the new attribute in lpRead. The IME should also make a new attribute of the composition string for the current composition string. At this time, the clause information will not be changed.

The composition string, the attribute, the clause information, the reading string, the reading attribute, and the reading clause information must be available. The IME generates WM_IME_COMPOSITION with (GCS_COMP | GCS_COMPREAD). If the IME cannot accept the new attribute that is in lpRead, the IME does not need to generate any message and returns FALSE.

If the lpComp parameter of ImeSetCompositionString is available, the IME follows the new attribute in lpComp. At this time, the clause information will not change.

If the capability of the IME has SCS_CAP_MAKEREAD and the reading string is available, the IME should make a new attribute of the reading of the composition string for the current reading of the composition string.

If both lpRead and lpComp are available and if the IME can accept the new information, the IME sets the new information into the COMPOSITION structure of hIMC and generates WM_IME_COMPOSITION with (GCS_COMP | GCS_COMPREAD).


About SCS_CHANGECLAUSE

SCS_CHANGECLAUSE effects the string and attribute for both the composition string and the reading of the composition string.

If it is necessary, IME may update the candidate information and generate the candidate messages IMN_OPENCANDIDATE, IMN_CHANGECANDIDATE, or IMN_CLOSECANDIDATE.

IME cannot finalize the composition string.

If the lpRead parameter of ImeSetCompositionString is available, the IME follows the new reading clause information of lpRead. The IME must correct the attribute of the reading of the composition string. The IME may then update the composition string, the attribute, and the clause information of the composition string. The IME generates WM_IME_COMPOSITION with (GCS_COMP | GCS_COMPREAD).

If the lpComp parameter of ImeSetCompositionString is available, the IME follows the new clause information. The IME must correct the composition string and the attribute of the composition string. The IME may then update the reading attribute and the clause information of reading. The IME generates WM_IME_COMPOSITION with (GCS_COMPSTR | GCS_COMPREAD).

If both lpRead and lpComp are available and if the IME can accept the new information, the IME sets the new information into the COMPOSITION structure of hIMC and generates WM_IME_COMPOSITION with (GCS_COMP | GCS_COMPREAD).


Soft Keyboard

Some IMEs have special reading characters. For example, an IME may use bo po mo fo as its reading characters, and another IME may use some radials as its reading characters. An IME can provide a soft keyboard to show these special reading characters so the user will not need to remember the reading character for each key.

IME needs to change the reading characters of keys according to different conversion states. Using a soft keyboard can notify the user of the change of keys. At candidate selection time, an IME can show only those selection keys to the user.


Using a Soft Keyboard

The IME may need to create a better user interface for a soft keyboard, or it may need to use the system predefined soft keyboard. If the IME needs to use the system predefined soft keyboard, it needs to specify UI_CAP_SOFTKBD in the fdwUICaps member of the IMEINFO structure when calling ImeInquire.

The IME can call ImmCreateSoftKeyboard to create a window for the soft keyboard, and it can call ImmShowSoftKeyboard to show or hide it. The soft keyboard window is one component of the UI window, so the owner should be the UI window.

The IME may need to decide whether to destroy the window whenever the focus is gone. The soft keyboard may occupy some system resources.

There are different types of soft keyboard. One type may be designed for a specific country/region or for a special purpose. The way to change reading characters may be different for each type of soft keyboard. There are two ways to change reading characters: use IMC_SETSOFKBDSUBTYPE or IMC_SETSOFKBDDATA. Different types of soft keyboards have different window procedures and present different user interfaces to the user.


IME Interface

In Windows® 95, IMEs are provided as dynamic link libraries (DLLs) like device drivers. The Input Method Manager (IMM) should handle all the installed IMEs. Because IMEs are changeable at running time without rebooting, IMM will have a structure to maintain all entry points of each IME.

The list of IME functions is the description of all Asian common IME functions. These functions should not be called by an application directly.


IMM Functions in a UI Window

Following are the IMM functions that can be called from a UI window:

ImmGetCompositionWindow

ImmSetCompositionWindow

ImmGetCandidateWindow

ImmSetCandidateWindow

ImmGetCompositionString

ImmSetCompositionString

ImmGetCompositionFont

ImmSetCompositionFont

ImmGetNumCandidateList

ImmGetCandidateList

ImmGetGuideLine

ImmGetConversionStatus

ImmGetConversionList

ImmGetOpenStatus

ImmSetConversionStatus

ImmSetOpenStatus

ImmNotifyIME

ImmCreateSoftKeyboard

ImmDestroySoftKeyboard

ImmShowSoftKeyboard


File Format of IME

The IMEs need to specify the following members correctly:

The dwFileVersionMS member must be specified in root block of the version information. The upper word is the major Windows version of this IME, the lower word is the minor version.

The dwProductVersionMS member must be specified in the root block of the version information. The upper word is the major version of this IME, the lower word is the minor version.

The dwFileOS member must be set to VOS__WINDOWS32 for a Windows 95 IME.

The dwFileType member must be specified in the root block of the version information. The value is VFT_DRV.

The dwFileSubtype member must be specified in the root block of the version information. The value is VFT2_DRV_INPUTMETHOD.

The FileDescription member is specified in the language-specific block of the version information. This should include the IME name and the version. This string is for display purposes and is limited to 32 TCHARs (this limit may be extended in a future version of Windows).

The ProductName is specified in the language-specific block of version information.

The code page (character set identifier) and language identifier are specified in the variable information block of the version information resource. If many code pages (character set identifier) and language identifiers are specified in the block, the first code page is the IME used to show the text, and the first language identifier is the language for this IME.

The file name of IME is 8.3 in Windows 95-FE. A Windows 95 IME must be a 32-bit DLL.


Contents of IME Registry

The registry contains the Input Method key under HKEY_CURRENT_USER\Control Panel. The Input Method key has four value names: Perpendicular Distance, Parallel Distance, Perpendicular Tolerance, and Parallel Tolerance. The near caret operation IME can reference it. If these four value names are not specified, an near operation IME can set a default value.

Value Name | Value Data
Perpendicular Distance | The distance is perpendicular to the text escapement. This is the perpendicular distance, in pixels, from the caret position to the composition window without font height and width. The near caret operation IME adjusts the composition window position according to this value and Parallel Distance. It is in REG_DWORD format.
Parallel Distance | The distance, in pixels, is parallel to the text escapement. This is the parallel distance from caret position to composition window. It is in REG_DWORD format.
Perpendicular Tolerance | The tolerance, in pixels, is perpendicular to the text escapement. This is the perpendicular distance from caret position to composition window. The near caret operation IME will not refresh its composition window if the caret movement is within this tolerance. It is in REG_DWORD format.
Parallel Tolerance | The tolerance, in pixels, is parallel to the text escapement. This is the parallel distance from caret position to composition window. It is in REG_DWORD format.

An IME can put the per user setting into the following registry location:

HKEY_CURRENT_USER
    Software
        <CompanyName>
        Windows
            CurrentVersion
                <IME Name>.

An IME can put the per computer setting into the following registry location:

HKEY_LOCAL_MACHINE
    Software
        <Company Name>
            Windows
                CurrentVersion
                    <IME Name>.


IMM and IME Structures

The structures described in this section are used for communication with IME and IMM. IME may access these structures directly, but an application cannot.


INPUTCONTEXT

typedef struct tagINPUTCONTEXT {
    HWND   hWnd;
    BOOL   fOpen;
    POINT  ptStatusWndPos;
    POINT  ptSoftKbdPos;
    DWORD  fdwConversion;
    DWORD  fdwSentence;
    union {
        LOGFONTA  A;
        LOGFONTW  W;
    } lfFont;
    COMPOSITIONFORM  cfCompForm;
    CANDIDATEFORM    cfCandForm[4];
    HIMCC  hCompStr;
    HIMCC  hCandInfo;
    HIMCC  hGuideLine
    HIMCC  hPrivate;
    DWORD  dwNumMsgBuf;
    HIMCC  hMsgBuf;
    DWORD  fdwInit
    DWORD  dwReserve[3];
} INPUTCONTEXT;
hWnd
Handle of window that uses the input context. If the input context is shared, this must be the handle of the active window and will be reset by ImmSetActiveContext.
fOpen
Present status of the opened or closed IME.
ptStatusWndPos
Position of the status window.
ptSoftKbdPos
Position of the soft keyboard.
fdwConversion
Conversion mode used by the IME composition engine.
fdwSentence
Sentence mode used by the IME composition engine.
lfFont
LOGFONT structure used by the IME user interface to draw the composition string.
cfCompForm
COMPOSITIONFORM structure used by the IME user interface to create the composition window.
cfCandForm[4]
CANDIDATEFORM structures used by the IME user interface to create the candidate windows. This IMC supports four candidate forms.
hCompStr
Memory handle that points to the COMPOSITIONSTR structure. This handle is available when there is the composition string.
hCandInfo
Handle of a memory block that contains the CANDIDATEINFO structure and CANDIDATELIST structures. This handle is available when there are the candidate strings.
hGuideLine
Handle of a memory block that contains the GUIDELINE structure. This handle is available when there is the guideline information.
hPrivate
Handle of a memory block used by IME for its private date area.
dwNumMsgBuf
Number of messages stored in hMsgBuf.
hMsgBuf
Handle of the memory block that stores the messages. The format of this memory block is [Message1] [wParam1] [lParam1] {[Message2] [wParam2] [lParam2]{...{...{...}}}}. All values are double words.
fdwInit
Initialize flag. When IME initializes the members of the INPUTCONTEXT structure, IME must set the bits of the member indicated by this flag. It can be a combination of the following values:
The bit of fdwInit | Description
INIT_STATUSWNDPOS | Initialized ptStatusWndPos
INIT_CONVERSION | Initialized fdwConversion
INIT_SENTENCE | Initialized fdwSentence
INIT_LOGFONT | Initialized lfFont
INIT_COMPFORM | Initialized cfCompForm
INIT_SOFTKBDPOS | initialized ptSoftKbdPos

dwReserve[3]
Reserved; must be zero.

When calling ImeToAsciiEx, IME can generate the messages into the lpdwTransKey buffer, but when IME needs generate the messages to the applications out of ImeToAsciiEx, IME can store the messages in hMsgBuf and call ImmGenerateMessage, which sends the messages in hMsgBuf to the application.


COMPOSITIONSTR

typedef struct tagCOMPOSITIONSTR {
  DWORD  dwSize;
  DWORD  dwCompReadAttrLen;
  DWORD  dwCompReadAttrOffset;
  DWORD  dwCompReadClsLen;
  DWORD  dwCompReadClsOffset;
  DWORD  dwCompReadStrLen;
  DWORD  dwCompReadStrOffset;
  DWORD  dwCompAttrLen;
  DWORD  dwCompAttrOffset;
  DWORD  dwCompClsLen;
  DWORD  dwCompClsOffset;
  DWORD  dwCompStrLen;
  DWORD  dwCompStrOffset;
  DWORD  dwCursorPos;
  DWORD  dwDeltaStart;
  DWORD  dwResultReadClsLen;
  DWORD  dwResultReadClsOffset;
  DWORD  dwResultReadStrLen;
  DWORD  dwResultReadStrOffset;
  DWORD  dwResultClsLen;
  DWORD  dwResultClsOffset;
  DWORD  dwResultStrLen;
  DWORD  dwResultStrOffset;
  DWORD  dwPrivateSize;
  DWORD  dwPrivateOffset;
} COMPOSITIONSTR;

Contains composition information. During conversion, IME puts conversion information into this structure.

dwSize
Size, in bytes, of this structure.
dwCompReadAttrLen
Length of the attribute information of the reading string of the composition string.
dwCompReadAttrOffset
Offset from the beginning of this structure to the attribute information.
dwCompReadClsLen
Length of the clause information of the reading string of the composition.
dwCompReadClsOffset
Offset from the beginning of this structure to the clause information.
dwCompReadStrLen
Length of the reading string of the composition string.
dwCompReadStrOffset
Offset from the beginning of this structure to the reading string of the composition string.
dwCompAttrLen
Length of the attribute information of the composition string.
dwCompAttrOffset
Offset from the beginning of this structure to the attribute information.
dwCompClsLen
Length of the clause information of the composition string.
dwCompClsOffset
Offset from the beginning of this structure to the clause information.
dwCompStrLen
Length of the composition string.
dwCompStrOffset
Offset from the beginning of this structure to the composition string.
dwCursorPos
Cursor position in the composition string.
dwDeltaStart
Start position of change in the composition string. If the composition string has changed from the previous state, the first position of such a change is stored here.
dwResultReadClsLen
Length of the clause information of the reading string of the result string.
dwResultReadClsOffset
Offset from the beginning of this structure to the clause information of the reading string of the result string..
dwResultReadStrLen
Length of the reading string of the result string.
dwResultReadStrOffset
Offset from the beginning of this structure to the reading string of the result string.
dwResultClsLen
Length of the clause information of the result string.
dwResultClsOffset
Offset from the beginning of this structure to the clause information of the result string.
dwResultStrLen
Length of the result string.
dwResultStrOffset
Offset from the beginning of this structure to the result string.
dwPrivateSize
Private area in this memory block.
dwPrivateOffset
Offset from the beginning of this structure to the private area.

The attribute information is a single-byte array and specifies the attributes of the string. The contents of the array are as follows:

Value | Meaning
ATTR_xxxxxxxxxxxx | Specifies the status of the composition string.
ATTR_INPUT | Character currently being entered.
ATTR_TARGET_CONVERTED | Character currently being converted (already converted).
ATTR_CONVERTED | Character given from conversion.
ATTR_TARGET_NOTCONVERTED | Character currently being converted (yet to be converted).
ATTR_INPUT_ERROR | The character is an error character and cannot be converted by the IME.
Other than the preceding: | Reserved

Each content is as follows:

Value | Meaning
Character currently being entered: | The character the user is entering. In Japanese, this character is a hiragana, katakana, or alphanumeric, which is yet to be converted by the IME.
Character currently being converted (already converted): | The character that has been selected for conversion by the user and converted by the IME.
Character given from conversion: | The character to which the IME has converted.
Character currently being converted (yet to be converted): | The character that has been selected for conversion by the user and not yet converted by the IME. In Japanese, this character is a hiragana, katakana, or alphanumeric, which the user has entered.
Character is an error character and cannot be converted by the IME: | The character is an error character, the IME cannot convert this character. For example, some consonants cannot be put together.

The length of the attribute information is the same as the length of the string. Each byte corresponds to each byte of the string. Even if the string includes DBCS characters, the attribute information has the information bytes of both the lead byte and the second byte.

The clause information is a double word array and specifies the numbers that are the positions of the clause. The position of the clause is one of the positions of the composition string and this clause starts from this position. At a minimum, the length of this information is two double words. This means the length of the clause information is eight bytes. The first double word has to be zero. This is the starting position of the first clause. The last double word has to be the length of this string. For example, if the string has three clauses, the clause information has four double words. The first double word is zero. The second double word specifies the starting position of the second clause. The third double word specifies the starting position of the third clause. The last double word is the length of this string.

The dwCursorPos member specifies the character in the composition string where the cursor is located, in terms of the count of that character. The counting starts at zero. If the cursor is to be positioned immediately after the composition string, this value is equal to the length of the composition string. In case there is no cursor (if such a condition exists), a value -1 is specified here. If a composition string does not exist, this member is invalid.


CANDIDATEINFO

typedef struct tagCANDIDATEINFO {
  DWORD  dwSize;
  DWORD  dwCount;
  DWORD  dwOffset[32];
  DWORD  dwPrivateSize;
  DWORD  dwPrivateOffset;
} CANDIDATEINFO;

Contains candidate information. This structure can have up to 32 candidate lists, and these candidate lists must reside in the same memory block.

dwSize
Size, in bytes, of this structure.
dwCount
Number of candidate lists included in the memory block.
dwOffset[32]
Array offsets from the beginning of this structure to the beginning of each candidate list.
dwPrivateSize
Private area in this memory block.
dwPrivateOffset
Offset from the beginning of this structure to the private area.


GUIDELINE

typedef struct tagGUIDELINE {
  DWORD  dwSize;
  DWORD  dwLevel;    // the error level.
      // GL_LEVEL_NOGUIDELINE,
      // GL_LEVEL_FATAL,
      // GL_LEVEL_ERROR,
      // GL_LEVEL_WARNNING,
      // GL_LEVEL_INFORMATION
  DWORD  dwIndex;   // GL_ID_NODICTIONARY and so on.
  DWORD  dwStrLen;  // Error Strings, if this is 0,
                    //   there is no error string.
  DWORD  dwStrOffset;
  DWORD  dwPrivateSize;
  DWORD  dwPrivateOffset;
} GUIDELINE;
dwLevel
Can be one of these values:
Value | Meaning
GL_LEVEL_NOGUIDELINE | There is no guideline. If the old guideline is shown, the UI should hide the old guideline.
GL_LEVEL_FATAL | Fatal error occurred. Some data may be lost.
GL_LEVEL _ERROR | Error occurs. The handling may not continue.
GL_LEVEL _WARNING | IME warns the user. An unexpected event occurred, but the IME can continue to handle.
GL_LEVEL _INFORMATION | User information.

dwIndex
Can be one of these values:
Value | Meaning
GL_ID_UNKNOWN | Unknown Error. The application should refer to Error String.
GL_ID_NOMODULE | IME cannot find a needed module.
GL_ID_NODICTIONARY | IME cannot find or recognize the dictionary.
GL_ID_CANNOTSAVE | Dictionary or the statistic data cannot be saved.
GL_ID_NOCONVERT | IME cannot convert any more.
GL_ID_TYPINGERROR | Typing error. IME cannot handle this typing.
GL_ID_TOOMANYSTROKE | There are two many strokes for one character or one clause.
GL_ID_READINGCONFLICT | For example, some vowels cannot be put together.
GL_ID_INPUTREADING | IME prompts the user - now it is in inputting reading character state.
GL_ID_INPUTRADICAL | IME prompts the user. It is now inputting the radical character state.
GL_ID_INPUTCODE | IME prompts the user. It is now inputting the character code state.
GL_ID_CHOOSECANIDATE | IME prompts the user. It is now choosing the candidate string state.
GL_ID_REVERSECONVERSION | IME prompts the user - the information of reverse conversion. The information of reverse conversion can be retrieved by ImmGetGuideLine(hIMC, GGL_PRIVATE. lpBuf, dwBufLen).The information filled in lpBuf is in CANDIDATELIST format.
GL_ID_PRIVATE_FIRST | The identifier which is between GL_ID_PRIVATE_FIRST and GL_ID_PRIVATE_LAST is reserved for the IME. IME can freely use these identifiers for its own GUIDELINE.
GL_ID_PRIVATE_LAST | The identifier which is between GL_ID_PRIVATE_FIRST and GL_ID_PRIVATE_LAST is reserved for the IME. IME can freely use these identifiers for its own GUIDELINE.

dwPrivateSize
Private area in this memory block.
dwPrivateOffset
Offset from the beginning of this structure to the private area.


IME Management Structures

The following topics describe the structures for IME management.


IMEINFO

This structure is used internally by IMM and the IME interface.

typedef struct tagIMEInfo {
  DWORD  dwPrivateDataSize;  // byte count of private data
  DWORD  fdwProperty;        // IME property bits
  DWORD  fdwConversionCaps;  // IME conversion mode capability bits
  DWORD  fdwSentenceCaps;    // IME sentence mode capability
  DWORD  fdwUICaps;          // IME UI capability
  DWORD  fdwSCSCaps;         // ImeSetCompositionString capability
  DWORD  fdwSelectCaps;      // IME inherit IMC capability
} IIMEINFO;

The high-order word of fdwProperty has the following values. These properties are used by applications.

IME_PROP_AT_CARET
This bit on indicates the IME conversion window is at the caret position. This bit off indicates a near caret position operation IME.
IME_PROP_SPECIAL_UI
This bit on indicates the IME has a special UI. An IME should set this bit only if it has a UI that an application cannot display. Typically, an IME will not set this flag.
IME_PROP_CANDLIST_START_FROM_1
This bit on indicates the UI of the candidate list strings starts from zero or 1. An application can draw the candidate list string by adding 1, 2, 3, and so on, to the front of the candidate string.
IME_PROP_UNICODE
This bit on indicates the string contents of the input context are in UNICODE

The low-order word of fdwProperty has the follow values. These properties are used by the system.

Properties | Description
IME_PROP_END_UNLOAD | This bit on indicates the IME is unloaded when it is inactive.
IME_PROP_KBD_CHAR_FIRST | This bit on indicates the system translates the character by keyboard first. This character is passed to IME as aid information. No aid information is provided when this bit is off.
IME_PORP_NEED_ALTKEY | This IME needs the ALT key to be passed to ImeProcessKey.
IME_PROP_IGNORE_UPKEYS | This IME does not need up keys to be passed to ImeProcessKey.

The fdwConversionCaps member shares the same definition for the conversion mode. If the relative bit is off, this IME does not have the capability to handle either the corresponding bit of conversion mode is on or off.

Value | Meaning
IME_CMODE_KATAKANA | This bit on indicates IME is in KATAKANA mode. Otherwise, the IME is in HIRAGANA mode.
IME_CMODE_NATIVE | This bit on indicates IME is in NATIVE mode. Otherwise, the IME is in ALPHANUMERIC mode.
IME_CMODE_FULLSHAPE | This bit on indicates IME is in full shape mode. Otherwise, the IME is in SBCS mode.
IME_CMODE_ROMAN | This bit on indicates IME is in ROMAN input mode. Otherwise, the IME is in non-ROMAN input mode.
IME_CMODE_CHARCODE | This bit on indicates IME is in CODE input mode. Otherwise, the IME is in non-CODE input mode.
IME_CMODE_HANJACONVERT | This bit on indicates IME is in HANJA convert mode. Otherwise, the IME is in non-HANJA convert mode.
IME_CMODE_SOFTKBD | This bit on indicates IME is in soft keyboard mode. Otherwise, the IME is in nonsoft keyboard mode.
IME_CMODE_NOCONVERSION | This bit on indicates IME is in no conversion mode. Otherwise, the IME is in conversion mode.
IME_CMODE_EUDC | This bit on indicates IME is in EUDC mode. Otherwise, the IME is not in EUDC mode. Under this mode, if GCS_RESULTSTR is generated, the current reading string is valid and can be converted. In some IMEs, if the vowel is not included, it is not a valid reading string. The EUDC editor should not provide such a reading string. The result string may contain nothing under GCS_RESULTSTR generated, because the string is the EUDC string that EUDC editor is going to register.
IME_CMODE_SYMBOL | This bit on indicates IME is in SYMBOL mode. Otherwise, the IME is not in SYMBOL mode.

The fdwSentenceCaps member shares the same constant definition for the sentence mode. If the relative bit is off, this IME does not have the capability to handle either the corresponding bit of sentence mode is on or off.

Value | Meaning
IME_SMODE_PLAURALCLAUSE | This bit on indicates IME supports plural clause sentence mode.
IME_SMODE_SINGLECONVERT | This bit on indicates IME support single character sentence mode.
IME_SMODE_AUTOMETIC | This bit on indicates IME support automatic sentence mode.
IME_SMODE_PHRASEPREDICT | This bit on indicates IME support phrase predict sentence mode.

The fdwUICaps has the follow bits.

Value | Meaning
UI_CAP_2700 | The UI supports the escape in which the LogFont is zero or 2700.
UI_CAP_ROT90 | The UI supports the escape in which LogFont is zero, 900, 1800, or 2700.
UI_CAP_ROTANY | The UI supports any escape.
UI_CAP_SOFKBD | The IME uses soft keyboard provided by the system.

The fdwSCSCaps member has the follow values:

Value | Meaning
SCS_CAP_COMPSTR | This IME can generate the composition string by SCS_SETSTR.
SCS_CAP_MAKEREAD | When calling ImmSetCompositionString with SCS_SETSTR, the IME can create the reading of the composition string without lpRead. Under an IME that has this capability, the application does not need to set lpRead for SCS_SETSTR.

The fdwSelectCaps has the follow values:

Value | Meaning
SELECT_CAP_CONVMODE | The IME can inherit the conversion mode at ImeSelect.
SELECT_CAP_SENTENCE | The IME can inherit the sentence mode at ImeSelect.

This capability is for the application. When the user changes the IME, the application can know if the conversion mode will be inherited by seeing this capability. If the newly selected IME does not have this capability, the application cannot expect the new mode and it must retrieve the mode again.


IME Communication Structures

The following topics describe the structures for IME communication.


CANDIDATELIST

This structure is used by the ImmGetCandidateList function.

typedef struct tagCANDIDATELIST {
DWORD  dwSize;   // size of this data structure.
DWORD  dwStyle;  // style of candidate strings.
DWORD  dwCount;  // number of the candidate strings.
DWORD  dwSelection;  // index of a candidate string now selected.
DWORD  dwPageStart;  // index of the first candidate string in candidate
                     //   window. It can vary with the page up or page
                     //   down key.
DWORD  dwPageSize;   // preference number of candidate strings
                     //   in one page.
DWORD  dwOffset[];   // startng positions of first candidate strings.
// Start positions of other (2nd, 3rd, ..) candidate strings are
// appended after this field. IME can do this by reallocating the
// hCandInfo memory handle, so IME can access dwOffset[2] (3rd candidate
// string) or dwOffset[5] (6st candidate string). CHAR chCandidateStr[];
// the array of the candidate strings.
} CANDIDATELIST;
dwCandidateStyle
Can be a combination of these values:
Value | Meaning
IME_CAND_UNKNOWN | Candidates are in a style other style than that previously listed
IME_CAND_READ | Candidates are in same reading.
IME_CAND_CODE | Candidates are in a code range.
IME_CAND_MEANING | Candidates are in same meaning.
IME_CAND_RADICAL | Candidates use same radical character.
IME_CAND_STROKE | Candidates are in same number of strokes.

When the dwStyle is IME_CAND_CODE, this candidate list structure has the special case. There are two cases: one in which dwCount is 1, and the other in which dwCount is larger than 1.

When the dwCount equals 1:

dwSize is valid

dwStyle = IME_CAND_CODE

dwCount = 1

dwSelection = 0

dwPageStart = 0

dwPageSize is valid

dwOffset[0] is the offset of 'A140' (example code of a DBCS character)

At this time, the UI shows the candidate list, but the selected one is A140. For example, the UI may show the candidate list from A140 to A14F and the scroll bar at one page.

When the dwCount is larger than 1:

dwSize is valid

dwStyle = IME_CAND_CODE

dwCount is valid

dwSelection = index of dwOffset that is selected

dwPageStart = first index of dwOffset that is displayed

dwPageSize is valid

dwOffset[0] = offset of the first string

dwOffset[1] = offset of the second string

dwOffset[2] = offset of the third string

szCandStr[0] = "A140" string

szCandStr[1] = "A141" string

szCandStr[2] = "A142" string

At this time, the candidate list will be provided by the IME conversion engine. Using this, the IME can support the input like A1?3. When the user inputs A1?3, the IME provides the candidate list as follows.

dwCount = 0x10

dwSelection = index of dwOffset that is selected

dwPageStart = first index of dwOffset that is displayed

dwPageSize is valid

szCandStr[0x0] = "A103" string

szCandStr[0x1] = "A113" string

szCandStr[0x2] = "A123" string

.

.

.

szCandStr[0x0F] = "A1F3" string


COMPOSITIONFORM

typedef tagCOMPOSITIONFORM {
    DWORD  dwStyle;
    POINT  ptCurrentPos;
    RECT  rcArea;
}COMPOSITIONFORM;

The dwStyle member is specified by CFS_xxxx. The ptCurrentPos member specifies the size and position of the bounding rectangle and the start position of the composition window.

CFS_DEFAULT

The CFS_DEFAULT value moves the composition window out to the default position. The IME can display the composition window outside the client area. It might be on a floating window.

CFS_POINT

The CFS_POINT value displays the composition window at the upper left of the latter window, at the position indicated by ptCurrentPos. The ptCurrentPos member indicates the coordinates relative to the upper left of the latter window, with the low-order word representing the x coordinate and the high-order word the y coordinate.

CFS__FORCE_POSITION

The CFS_FORCE_POSITION value displays the composition window at the upper left of the window as designated by ptCurrentPos. The ptCurrentPos member indicates the coordinates relative to the upper left of the latter window, with the low-order word representing the x coordinate and the high-order word the y coordinate.

Some near caret operation IMEs show its conversion window by adjusting the position specified by the system or the application. The CFS_FORCE_POSITION informs IMEs to stop this adjustment.

If the CFS_FORCE_POSITION bit is off, some IMEs adjust their position according to the position specified in ptCurrentPos with CFS_POINT style.

CFS_RECT

The CFS_RECT value is the same as CFS_POINT except that the bounding rectangle is specified by rcCompArea. The coordinates are relative to the upper left of the window.

When the style of the COMPOSITIONFORM structure is CFS_POINT or CFS_FORCE_POINT, the IME starts to draw the composition string from the position that is specified by ptCurrentPos of the COMPOSITIONFORM structure that is given by the application. If the style has CFS_RECT, the composition string will be inside of the rectangle that is specified by rcArea. If not, rcArea is the client rectangle of the application window.

When the application specifies the composition font, the composition window is rotated as the escapement of the composition font. The direction of the composition string follows the escapement of the font in a composition window. IME starts to draw the composition string as follows.

The escapement of the composition font is zero

This is the typical case. The ptCurrentPos member of the composition form structure points to the left and top of the string. All IMEs support this type.

The escapement of the composition font is 2700.

This is a case of a vertical writing. When the application provides the vertical writing, the application may set the 2700 escapement in the composition font that is set by ImmCompositionFont. The composition string will be drawn downward. The IMEs that have UI_CAP_2700, UI_CAP_ROT90 or UI_CAP_ROTANY capability support this type of the composition window.

The escapement of the composition font is 900 or 1800

The IMEs that have UI_CAP_ROT90 or UI_CAP_ROTANY capability support this type of \composition window.

The escapement of the composition font is any value.

The IMEs that have UI_CAP_ROTANY capability support this type of the composition window.

UI_CAP_ROT90 and UI_CAPS_ANY are the options for the enhancement of the IME. UI_CAP_2700 is recommended.

This structure is used with the IMC_SETCOMPOSITIONWINDOW and IMC_SETCANDIDATEPOS messages.


CANDIDATEFORM

This structure is used with the IMC_GETCANDIDATEPOS and IMC_SETCANDIDATEPOS messages.

typedef tagCANDIDATEFORM {
    DWORD  dwIndex;
    DWORD  dwStyle;
    POINT  ptCurrentPos;
    RECT  rcArea;
} CANDIDATEFORM;
dwIndex
Identifier of the candidate list. Zero is the first candidate list, one (1) is the second one, up to 31.
dwStyle
Style flag. Can be one of the following values.
Value | Meaning
CFS_CANDIDATEPOS | The ptCurrentPos member specifies the recommended position where the candidate list window should be displayed.
CFS_EXCLUDE | The member ptCurrentPos specifies the current position of the point of interest (typically the caret position).

ptCurrentPos
Position. The meaning of this parameter depends on the value of dwStyle.
rcArea
Rectangle where no display is allowed for candidate windows. This member is used only if dwStyle is set to CFS_EXCLUDE.


STYLEBUF

Defines the style of a registered word.

typedef struct tagSTYLEBUF {
    DWORD  dwStyle;
    TCHAR  szDescription[32]
} STYLEBUF;
dwStyle
Style of a registered word. It can be IME_REGWORD_STYLE_EUDC, which indicates the string is in EUDC range. An ISV can use the constants from IME_REGWORD_STYLE_USER_FIRST to IME_REGWORD_STYLE_USER_LAST for private styles of the IME.
szDescription
Description string of this style.


SOFTKBDDATA Structure

typedef struct tagSOFTKBDDATA {
    UINT  uCount;
    WORD  wCode[][256]
} SOFTKBDDATA;
uCount
Number of 256-word virtual key mapping to the internal code array.
wCode[][256]
This is the 256-word virtual key mapping to the internal code array. There may be more than one 256-word array.

A soft keyboard can use two 256-word arrays: one for the nonshift state and the other for the shift state. The soft keyboard can use two internal codes for displaying one virtual key.


IMM Functions to Support IME

The following IMM functions support IME.


ImmGenerateMessage

BOOL WINAPI ImmGenerateMessage(hIMC)

An IME uses this function to generate messages stored in hMsgBuf of hIMC. This function sends the messages in the hMsgBuf to the hWnd of hIMC.

If the function succeeds, the return value is TRUE. Otherwise, it is FALSE.

hIMC
Handle of the input context that has hMsgBuf.

This is a general purpose function. Typically, an IME uses this function when it is notified about a context update with ImmNotifyIME from IMM. In this case, even if IME needs to provide messages to an application, there is no keystroke in the application's message queue.

An IME user interface should not use this function when it just needs to update the appearance of the UI. The IME user interface should have been updated when the IME is informed of the updated input context. This function should be used only when the IME changes the input context without any keystroke given and needs to inform an application of the change.


HIMC and HIMCC Management Functions

The following topics describe the HIMC and HIMCC management functions.


ImmLockIMC

LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC)

Retrieves the address of the INPUTCONTEXT structure for the input context. The IME uses the address to access the input context. This function increases the lock count for IMC.

The return value is the address of the INPUTCONTEXT structure if successful. Otherwise, it is NULL.

hIMC
Handle of the input context.


ImmUnlockIMC

BOOL WINAPI ImmUnlockIMC(HIMC hIMC)

Decrements the lock count for IMC.

If the lock count of IMC was decremented to zero, the return value is FALSE. Otherwise, it is TRUE.

hIMC
Handle of the input context.


ImmGetIMCLockCount

HIMCC WINAPI ImmGetIMCLockCount(hIMC)

Retrieves the lock count of the IMC.

The return value is the lock count.

hIMC
Handle of the input context.


ImmCreateIMCC

HIMCC WINAPI ImmCreateIMCC(DWORD dwSize)

Creates a new IMC component that can be the member of IMC.

If successful, the return value is HIMCC (IMC Component handle). Otherwise, the return value is zero.

dwSize
Size of the new IMC component.

The IMC component that is created by this function is initialized with zero.


ImmDestroyIMCC

HIMCC WINAPI ImmDestroyIMCC(HIMCC hIMCC)

Destroys an IMC component that can be the member of IMC.

If successful, the return value is NULL. Otherwise, it is equal to HIMCC.

hIMCC
Handle of IMC component.


ImmLockIMCC

LPVOID WINAPI ImmLockIMCC(HIMCC hIMCC)

Retrieves the address of the IMC component that can be the member of IMC, and increases the lock count for IMCC.

If successful, the return value is the address of the IMC component. Otherwise, the return value is NULL.

hIMCC
Handle of IMC component.


ImmUnlockIMCC

BOOL WINAPI ImmUnlockIMCC(HIMCC hIMCC)

Decrements the lock count for IMCC.

The return value is FALSE if the lock count of IMCC was decremented to zero. Otherwise, it is TRUE.

hIMCC
Handle of IMC component.


ImmReSizeIMCC

HIMCC WINAPI ImmReSizeIMCC(HMICC hIMCC, DWORD dwSize)

Changes the size of the IMC component.

If successful, the return value is the new HIMCC. Otherwise, it is zero.

hIMCC
Handle of IMC component.
dwSize
New size of IMC component.


ImmGetIMCCSize

DWORD WINAPI ImmGetIMCCSize(HIMCC hIMCC)

Retrieves the size of IMCC.

The return value is the size of IMCC.

hIMCC
Handle of IMC component.


ImmGetIMCCLockCount

DWORD WINAPI ImmGetIMCCLockCount(HIMCC hIMCC)

Retrieves the lock count of IMCC.

The return value is the lock count of IMCC.

hIMCC
Handle of IMC component.


IMM Functions to Manipulate IME Hot Keys

The IME hot key is used to changed the IME input mode or to switch the IME. The IME hot key for switching directly to an IME is called the direct switching hot key. The identifier of a direct switching hot key is in the range IME_HOTKEY_DSWITCH_FIRST to IME_HOTKEY_DSWITCH_LAST. It is registered by an IME or control panel if the IME or a user wants such a hot key. The IME hot key is effective in all IMEs, no matter which IME is active. In Windows 95-FE, several predefined hot keys are defined by IMM. The IMM itself provides the functionality (different handling routines) of those hot key functions. Every hot key in Windows 95-FE has a different hot key identifier in IMM, and each identifier has it own functionality according to the requirements of each country/region. An application has no way to add another predefined hot key identifier to the system.

Following are the predefined hot key identifiers.

Hot Key ID | Description
IME_CHOTKEY_IME_NONIME_TOGGLE | The hot key of Windows for Simplified Chinese Edition. This hot key toggles between IME and non-IME.
IME_CHOTKEY_SHAPE_TOGGLE | The hot key of Windows for Simplified Chinese Edition. This hot key toggles the shape conversion mode of IME.
IME_CHOTKEY_SYMBOL_TOGGLE | The hot key of Windows for Simplified Chinese Edition. This hot key toggles the symbol conversion mode of IME. The symbol mode indicates that the user can input Chinese punctuation and symbols (full shape characters) by mapping it to the punctuation and symbol keystrokes of keyboard.
IME_JHOTKEY_CLOSE_OPEN | The hot key of Windows for Japanese Edition. This hot key toggles between closed and opened.
IME_THOTKEY_IME_NONIME_TOGGLE | The hot key of Windows for (Traditional) Chinese Edition. This hot key toggles between IME and non-IME.
IME_THOTKEY_SHAPE_TOGGLE | The hot key of Windows for (Traditional) Chinese Edition. This hot key toggles the shape conversion mode of IME.
IME_THOTKEY_SYMBOL_TOGGLE | The hot key of Windows for (Traditional) Chinese Edition. This hot key toggles the symbol conversion mode of IME.

The other kind of hot key is the IME private hot key. There is no functionality for this kind of hot key. It is just a placeholder for a hot key value. An IME can get this value by using ImmGetHotKey. If an IME supports this functionality for one hot key identifier, the IME will perform the functionality every time it finds this key input.

Following are the current private IME hot key identifiers in Windows 95-FE.

Hot Key ID | Description
IME_ITHOTKEY_RESEND_RESULSTR | The hot key of Windows for (Traditional) Chinese Edition. This hot key should trigger the IME to resend the previous result string to an application. If the IME detects this hot key, it needs to resend the previous result string to this application.
IME_ITHOTKEY_PREVIOUS_COMPOSITION | The hot key of Windows for (Traditional) Chinese Edition. This hot key should trigger the IME to bring up the previous composition string to the application.
IME_ITHOTKEY_UISTYLE_TOGGLE | The hot key of Windows for (Traditional) Chinese Edition. This hot key should trigger the IME UI to toggle the UI style between caret unrelated UI and the caret related UI.


ImmGetHotKey

BOOL WINAPI ImmGetHotKey(DWORD dwHotKeyID, LPUINT lpuModifiers,
    LPUINT lpuVKey, LPHKL lphKL)

Gets the value of the IME hot key. This function is called by the control panel.

If successful, the return value is TRUE. Otherwise, it is FALSE.

dwHotKeyID
Hot key identifier.
lpuModifiers
Value that specifies the keys that must be combined with lpuVKey to trigger the hot key. Can be a combination of these values:
Value | Meaning
MOD_ALT | ALT key.
MOD_CONTROL | CTRL key.
MOD_SHIFT | SHIFT key.
MOD_LEFT | Use key on the left side of keyboard.
MOD_RIGHT | Use key on the right side of keyboard.
MOD_ON_KEYUP | Trigger hot key when hot key is released.
MOD_IGNORE_ALL_MODIFIER | Ignore modifier keys.

lpuVKey
Virtual key code of this hot key.
lphKL
Handle of the keyboard layout for the IME. If the return value of this parameter is NULL, this hot key can switch to the IME with this keyboard layout.


ImmSetHotKey

BOOL WINAPI ImmSetHotKey(DWORD dwHotKeyID, UINT uModifiers, UINT uVKey,
    HKL hKL)

Sets the value of the IME hot key. This function is called by control panel.

If successful, the return value is TRUE. Otherwise, it is FALSE.

dwHotKeyID
Hot key identifier.
uModifiers
Value that specifies the keys that must be combined with lpuVKey to trigger the hot key. Can be a combination of these values.
Value | Meaning
MOD_ALT | ALT key.
MOD_CONTROL | CTRL key.
MOD_SHIFT | SHIFT key.
MOD_LEFT | Use key on the left side of keyboard.
MOD_RIGHT | Use key on the right side of keyboard.
MOD_ON_KEYUP | Trigger hot key when hot key is released.
MOD_IGNORE_ALL_MODIFIER | Ignore modifier keys.

For a key that does not occur on both sides of the keyboard, uModifiers should specify both sides (MOD_LEFT | MODE_RIGHT).

uVKey
Virtual key code of this hot key.
hKL
Handle of the keyboard layout for the IME. If this parameter is specified, this hot key can switch to the IME with this keyboard layout.


IMM Soft Keyboard Functions

The following topics describe the IMM Soft Keyboard functions.


ImmCreateSoftKeyboard

HWND WINAPI ImmCreateSoftKeyboard(UINT uType, UINT hOwner, int x, int y)

Creates one type of soft keyboard window.

The return value is the window handle of the soft keyboard.

uType
Type of the soft keyboard. Can be one of these values.
Value | Meaning
SOFTKEYBOARD_TYPE_T1 | The type T1 soft keyboard. This kind of soft keyboard should be updated by IMC_SETSOFTKBDDATA.
SOFTKEYBOARD_TYPE_C1 | The type C1 soft keyboard. This kind of soft keyboard should be updated by IMC_SETSOFTKBDDATA with two sets of 256-word array data. The first set is for nonshift state, and the second is for shift state.

hOwner
Owner of the soft keyboard. It must be the UI window.
x
Initial horizontal position of the soft keyboard.
y
Initial vertical position of the soft keyboard.


ImmDestroySoftKeyboard

BOOL WINAPI ImmDestroySoftKeyboard(HWND hSoftKbdWnd)

Destroys the soft keyboard window.

If successful, the return value is TRUE. Otherwise, it is FALSE.

hSoftKbdWnd
Window handle of the soft keyboard to destroy.


ImmShowSoftKeyboard

BOOL WINAPI ImmShowSoftKeyboard(HWND hSoftKbdWnd, int nCmdShow)

Sets the given soft keyboard's show state.

If successful, the return value is TRUE. Otherwise, it is FALSE.

hSoftKbdWnd
Window handle of the soft keyboard.
nCmdShow
Show state of the window. SW_HIDE hides the soft keyboard; SW_SHOWNOACTIVATE displays the soft keyboard.


UI Window Messages

This section describes the messages that a UI window receives.


WM_IME_SETCONTEXT

The WM_IME_SETCONTEXT message is sent to an application when a window of the application is being activated. If the application does not have its application IME window, the application must pass this message to DefWindowProc and should return the return value of the DefWindowProc. If the application has its application IME window, the application should call ImmIsUIMessage.

Returns the return value of DefWindowProc or ImmIsUIMessage.

wParam
TRUE when the input context becomes active for the application. FALSE when the input context becomes inactive for the application.
lParam
Can be a combination of these values.
ISC_SHOWUICOMPOSITIONWINDOW | Show the composition window.
ISC_SHOWUIGUIDWINDOW | Show the guide window.
ISC_SHOWUISOFTKBD | Show the soft keyboard.
ISC_SHOWUICANDIDATEWINDOW | Show the candidate window of Index 0.
(ISC_SHOWUICANDIDATEWINDOW << 1) | Show the candidate window of Index 1.
(ISC_SHOWUICANDIDATEWINDOW << 2) | Show the candidate window of Index 2.
(ISC_SHOWUICANDIDATEWINDOW << 3) | Show the candidate window of Index 3.

The UI window receives this message after an application calls DefWindowProc or ImmIsUIMessage with WM_IME_SETCONTEXT. The UI window should show the composition, guide, or candidate window as indicated by lParam.

If the application draws the composition window by itself, the UI window does not need to show its composition window. The application must clear the ISC_SHOWUICOMPOSITIONWINDOW bit of lParam and pass the bit to DefWindowProc or ImmIsUIMessage.


WM_IME_CONTROL

The WM_IME_CONTROL message is a group of sub messages to control the IME user interface. An application uses this message to interact with the IME window created by the application.

The IMC_ messages list the submessages classified by the value of wParam.


IMC_GETCANDIDATEPOS

An application sends the IMC_GETCANDIDATEPOS message to the IME window to retrieve the position of the candidate window. IME can adjust the position of a candidate window. An application can get the real position of candidate window to decide whether it needs to reposition it.

If successful, the return value is zero. Otherwise, it is nonzero.

lParam
Address of a CANDIDATEFORM structure that receives the position of the candidate window.

The return value in the buffer specifies the client coordinates of the focus window of an application. The UI window receives this message.


IMC_GETCOMPOSITIONFONT

An application sends the IMC_GETCOMPOSITIONFONT message to the IME window retrieve the font to use for displaying intermediate characters in the composition window. The UI window does not receive this message.

If successful, the return value is zero. Otherwise, it is nonzero.

lParam
Address of a LOGFONT structure that defines the font.


IMC_GETCOMPOSITIONWINDOW

An application sends the IMC_GETCOMPOSITIONWINDOW message to the IME window to get the position of the composition window. An IME may adjust the position of a composition window regarding some concerns. An application can get the real position of composition window to decide whether it wants to reposition it to another position.

If successful, the return value is zero. Otherwise, it is nonzero.

lParam
Address of a COMPOSITIONFORM structure that receives the position of the composition window.

The return value in the buffer is in the client coordinates of the focus window of an application. The UI window receives this message.


IMC_GETSOFKBDFONT

An IME sends the IMC_GETSOFKBDFONT message to the soft keyboard window to get a font to be used for displaying reading characters of keys in the soft keyboard window.

If successful, the return value is zero. Otherwise, it is nonzero.

lParam
Address of a LOGFONT structure that defines the font.


IMC_GETSOFTKBDPOS

An IME sends the IMC_GETSOFTKBDPOS message to the soft keyboard window to get the position of the soft keyboard window.

The return value is a POINTS structure that contains the x and y coordinates of the position of the soft keyboard window. It is in screen coordinates.


IMC_GETSOFTKBDSUBTYPE

An IME sends the IMC_GETSOFTKBDSUBTYPE message to the soft keyboard window to get the subtype of the soft keyboard window set by IMC_SETSOFTKBDSUBTYPE.

The return value is the subtype of the soft keyboard set by IMC_SETSOFTKBDSUBTYPE if successful. Otherwise, it is -1.


IMC_GETSTATUSWINDOWPOS

An application sends the IMC_GETSTATUSWINDOWPOS message to the IME window to get the position of the status window. The UI window receives the message.

The return value is a POINTS structure that contains the x and y coordinates of the position of the soft keyboard window. It is in screen coordinates.


IMC_SETCANDIDATEPOS

An application sends the IMC_SETCANDIDATEPOS message to the IME window to specify the recommended position to display a candidate window. This message is intended to be sent by an application that displays composition characters without the IME UI, but uses the IME UI to display candidates. A UI window does not receive this message.

If successful, the return value is zero. Otherwise, it is nonzero.

lParam
Address of a CANDIDATEFORM structure.


IMC_SETCOMPOSITIONFONT

An application sends the IMC_SETCOMPOSITIONFONT message to the IME window to specify a font to be used for displaying intermediate characters in the composition window. A UI window does not receive this message.

If successful, the return value is zero. Otherwise, it is nonzero.

lParam
Address of a LOGFONT structure that defines the font.


IMC_SETCOMPOSITIONWINDOW

An application sends the IMC_SETCOMPOSITIONWINDOW message to the IME window to specify style of the composition window. In contrast to Windows 3.1, this message specifies the composition style of the current active input context. The IME user interface follows the style whenever it is given the input context.

If successful, the return value is zero. Otherwise, it is nonzero.

lParam
Address of a COMPOSITIONFORM structure.

The IME user interface has a default style of composition window that is equal to the CFS_POINT style. If an application has not specified any composition style in its input context, the IME user interface retrieves the current caret position and window client area when it opens the composition window. It is in client coordinates. The UI window does not receive this message.


IMC_SETSOFKBDDATA

An IME sends the IMC_SETSOFKBDDATA message to a the soft keyboard window to specify the character code to be used for displaying reading characters of key in the soft keyboard window. The UI window does not receive this message.

If successful, the return value is zero. Otherwise, it is nonzero.

lParam
Address of a SOFTKBDDATA structure.


IMC_SETSOFKBDSUBTYPE

An IME sends the IMC_SETSOFKBDSUBTYPE message to the soft keyboard window to specify the subtype to use for displaying the reading characters of a key in the soft keyboard window. It also can be used for an IME-specific purpose.

The return value is the previous subtype if successful. Otherwise, it is -1.

lParam
Soft keyboard subtype.

The UI window does not receive this message. The SOFTKEYBOARD_TYPE_T1 does not use this information. The IME sends the message to the soft keyboard. It not change the displaying of the reading characters. An IME that uses the SOFTKEYBOARD_TYPE_T1 soft keyboard can freely define the meaning of this message. The IME can get this data by using IMC_GETSOFTKBDSUBTYPE.


IMC_SETSOFKBDFONT

An IME sends the IMC_SETSOFKBDFONT message to the soft keyboard window to specify a font to be used to display the reading characters of keys in the soft keyboard window. The UI window does not receive this message.

If successful, the return value is zero. Otherwise, it is nonzero.

lParam
Address of a LOGFONT structure that defines the font.


IMC_SETSOFTKBDPOS

An UI window sends the IMC_SETSOFTKBDPOS message to the soft keyboard window to set the position of the soft keyboard window.

If successful, the return value is zero. Otherwise, it is nonzero.

lParam
A POINTS structure that contains the x and y coordinates of the position of the soft keyboard window. This is in screen coordinates.


IMC_SETSTATUSWINDOWPOS

An application sends the IMC_SETSTATUSWINDOWPOS message to the IME window to set the position of the status window.

If successful, the return value is zero. Otherwise, it is nonzero.

lParam
A POINTS structure that contains the x and y coordinates of the position of the status window. This is in screen coordinates.


WM_IME_COMPOSITION

Sent two bytes of composition characters to the application. The WM_IME_COMPOSITION message is sent when an IME changes composition status as a result of a user's keystroke. The IME user interface window changes its appearance when it processes this message. An application can call ImmGetCompositionString to obtain detailed composition status.

There is no return value.

wParam
Double byte character that is the latest change of composition character.
lParam
Flag that indicates how the composition string or character changed. An application checks this to retrieve the necessary information. It can be a combination of the following values:

GCS_COMPSTR

GCS_COMPATTR

GCS_COMPCLAUSE

GCS_COMPREADSTR

GCS_COMPREADATTR

GCS_COMPREADCLAUSE

GCS_TYPINGINFO

GCS_SETCURSORPOS

GCS_RESULTSTR

GCS_RESULTCLAUSE

GCS_RESULTREADSTR

GCS_RESULTREADCLAUSE

GCR_ERRORSTR

GCR_INFOSTR

The following values are special styles for WM_IME_COMPOSITION.

Value | Meaning
CS_INSERTCHAR | An IME specifies this value when wParam shows a composition character which should be inserted into the current insertion point. An application should display a composition character if it processes this bit flag.
CS_NOMOVECARET | An IME specifies this value to prevent an application from moving the caret position as a result of processing WM_IME_COMPOSITION. For example, if an IME specifies a combination of CS_INSERTCHAR and CS_NOMOVECARET, it means that an application should insert a character given by wParam into the current caret position, but should not move the caret. Subsequent WM_IME_COMPOSITION with GCS_RESULTSTR replaces this character.

An application that needs to display composition characters by itself should not pass this message to either the application IME user interface window or DefWindowProc, which passes the message to the default IME window. An IME should give this message to an application even when the IME simply cancels the current composition. An application or IME UI should use this message to erase the current composition string.


WM_IME_COMPOSITIONFULL

The WM_IME_COMPOSITIONFULL message is sent to an application when the IME user interface window finds no space to extend the area for the composition window. An application should specify the way to display the window for the IME UI.

There is no return value.

The IME user interface uses the SendMessage function to send this message. This is a notification.


WM_IME_ENDCOMPOSITION

The WM_IME_ENDCOMPOSITION message is sent to an application when the IME ends composition.

There is no return value.

An application that needs to display composition characters by itself should not pass this message to either the application IME user interface window or DefWindowProc, which passes it to the default IME window.


WM_IME_SELECT

The WM_IME_SELECT message will be sent to the UI window when the system is about to change the current IME.

There is no return value.

wParam
TRUE if the IME is newly selected; FALSE if the IME is not selected.
lParam
Handle of the keyboard layout for the IME.

The system IME class uses this message to create a new UI window and to destroy an old UI window for the application or the system. DefWindowProc responds to this message by passing information to the default IME window, which sends the message to its UI window.


WM_IME_STARTCOMPOSITION

The WM_IME_STARTCOMPOSITION message is sent immediately before an IME generates a composition string as a result of a user's keystroke. The UI window opens its composition window when it receives this message.

There is no return value.

An application that needs to display composition characters by itself should not pass this message to either the application IME window or DefWindowProc, which passes the message to the default IME window.


WM_IME_NOTIFY

The WM_IME_NOTIFY message notifies an application or the UI window of the IME status. The wParam parameter is an IMN_ notification that indicates the purpose of the message. See the description of the IMN_ values.


IMN_CLOSESTATUSWINDOW

The IMN_CLOSESTATUSWINDOW message is sent when an IME is about to close status window. The UI window closes the status window when it processes this message.

There is no return value.


IMN_OPENSTATUSWINDOW

The IMN_OPENSTATUSWINDOW message is sent when an IME is about to create a status window. An application uses this message to display the system window for the IME by itself. An application can use the ImmGetConversionStatus function to retrieve information about the system window. The UI window will create a status window when it processes this message.

There is no return value.


IMN_OPENCANDIDATE

The IMN_OPENCANDIDATE message is sent when an IME is about to open a candidate window. An application uses this message to call ImmGetCandidateCount and ImmGetCandidateList to display candidates. The UI window creates a candidate window when it processes this message.

There is no return value.

lParam
Shows which candidate list should be updated. For example, if bit0 is 1, the first candidate list should be updated. If bit31 is 1, the 32nd candidate list should be updated.


IMN_CHANGECANDIDATE

The IMN_CHANGECANDIDATE message is sent when an IME is about to change the content of the candidates window. An application uses this message to display candidates by itself. The UI window redraws a candidate window when it processes this message.

There is no return value.

lParam
Shows which candidate list should be updated. For example, if bit0 is 1, the first candidate list should be updated. If bit31 is 1, the 32nd candidate list should be updated.


IMN_CLOSECANDIDATE

The IMN_CLOSECANDIDATE message is sent when an IME is about to close a candidate window. It notifies an application of the end of candidate processing. The UI window destroys a candidate window when it processes this message.

There is no return value.

lParam
Shows which candidate list should be updated. For example, if bit0 is 1, the first candidate list should be updated. If bit31 is 1, the 32nd candidate list should be updated.


IMN_SETCONVERSIONMODE

The IMN_SETCONVERSIONMODE message is sent when the conversion mode of the input context is updated. An application or the UI window uses this message to retrieve information about the status window by calling the ImmGetConversionStatus function. The UI window redraws its status window, if the status window shows the conversion mode.

There is no return value.


IMN_SETSENTENCEMODE

The IMN_SETSENTENCEMODE message is sent when the sentence mode of the input context is updated. An application or the IME's UI uses this message to retrieve information about the status window by calling the ImmGetConversionStatus function. The UI window redraws its status window if the status window shows the sentence mode.

There is no return value.


IMN_SETOPENSTATUS

The IMN_SETOPENSTATUS message is sent when the open status of the input context was updated. The application or the UI window uses this message to retrieve the information by calling the ImmGetOpenStatus function. The UI window redraws its status window if the status window shows the open or close status.

There is no return value.


IMN_SETCANDIDATEPOS

The IMN_SETCANDIDATEPOS message is sent when an IME is about to move the candidate windows. Applications use this message to be notified about the end of candidate processing. The UI window moves a candidate window when it processes this message.

There is no return value.

lParam
Shows which candidate list should be moved. For example, if bit0 is 1, the first candidate list should be moved. If bit31 is 1, the 32nd candidate list should be moved.


IMN_SETCOMPOSITIONFONT

The IMN_SETCOMPOSITIONFONT message is sent when the font of the input context is changed. An application or the UI window uses this message to retrieve information about the composition font by calling the ImmGetCompositionFont function. The composition component of the UI window uses lfFont to draw the text of the composition string.

There is no return value.


IMN_SETCOMPOSITIONWINDOW

The IMN_SETCOMPOSITIONWINDOW message is sent when the composition form of the input context is updated. When the UI window receives this message, the new conversion mode can be retrieved from cfCompForm. The composition component of the UI windows uses cfCompForm to show the composition window.

There is no return value.


IMN_GUIDELINE

The IMN_GUIDELINE message is sent when an IME is about to show the error or information. The application or the UI window uses this message to retrieve guideline information by calling the ImmGetGuideLine function. The UI window may create an information window when it processes this message and shows the information string.

There is no return value.

lParam
Must be zero.


IMN_SOFTKBDDESTROYED

The IMN_SOFTKBDDESTROYED message is sent to the UI window when the soft keyboard is destroyed.

There is no return value.

lParam
Must be zero.


WM_IME_KEYDOWN / WM_IME_KEYUP

The WM_IME_KEYDOWN / WM_IME_KEYUP message is sent to an application when the IME needs to generate a WM_KEYDOWN or WM_KEYUP message. The form of the value to be sent is the same as the original English Windows WM_KEYDOWN and WM_KEYUP messages.

There is no return value.

wParam
Same as the English Windows WM_KEYDOWN or WM_KEYUP.
lParam
Same as the English Windows WM_KEYDOWN or WM_KEYUP.

An application can handle these messages in the same way it handles the WM_KEYDOWN and WM_KEYUP messages. It can pass these messages to DefWindowProc to generate WM_KEYDOWN and WM_KEYUP messages with the same wParam and lParam parameters. This message is usually generated by the IME to maintain message order.


WM_IME_CHAR

The WM_IME_CHAR message is sent to an application when the IME gets a character of the conversion result. The form of the value to be sent is similar to the English Windows WM_CHAR message. The difference is that wParam can specify a double-byte character.

There is no return value.

wParam
Double-byte FE character.
lParam
Similar to the English Windows version of the WM_CHAR message.
Bit | Value
0 - 15 | Repeat count: Since the first byte and second byte are continuous, this is always 1.
16 - 23 | Scan Code for an FE character.
24 - 28 | Not used.
29 | Context code.
31 | Conversion state.

DefWindowProc generates two WM_CHAR messages, each including one byte of a DBCS character, for a double-byte FE character. If the message includes a SBCS character, DefWindowProc generates one WM_CHAR message.


VK_PROCESSKEY

The VK_PROCESSKEY message is sent to an application as the wParam of a WM_KEYDOWN or WM_KEYUP message. When this virtual key is generated, the real virtual key is saved in the input context, if the messages generated by the IME are stored in the input context. The system restores the real virtual key or posts the messages that are stored in the message buffer of the input context.

lParam
Must be 1.


IME Interface Functions

The following topics describe the functions for the IME interface.


ImeInquire

BOOL ImeInquire(LPIMEINFO lpIMEInfo, LPTSTR lpszWndClass,
    LPCTSTR lpszData)

Handles initialization of the IME. It also returns an IMEINFO structure and the UI class name of the IME.

If successful, the return value is TRUE. Otherwise, it is FALSE

lpIMEInfo
Address of an IMEINFO structure.
lpszWndClass
Address of a buffer that receives the class name from the IME. This class name is the IME's UI class.
lpszData
Not used; must be NULL.


ImeConversionList

DWORD IMEConversionList(HIMC hIMC, LPCTSTR lpSource,
    LPCANDIDATELIST lpDest, DWORD dwBufLen, UINT uFlag)

Obtains the list of FE characters or strings from one character or string.

The return value is the number of bytes in the result string list.

hIMC
Handle of the input context.
lpSource
Character string to be converted.
lpDest
Address of the destination buffer.
dwBufLen
Length of the destination buffer.
uFlag
Can be one of these values.
Value | Meaning
GCL_CONVERSION | The reading string is in lpSource. The IME returns the result string in lpDest.
GCL_REVERSECONVERSION | The result string is in lpSource. The IME returns the reading string in the lpDest.
GCL_REVERSE_LENGTH | The result string is in lpSource. The IME returns the length that it can handle on a GCL_REVERSECONVERSION call. For example, one IME cannot reverse-convert a result string with a sentence period to a reading string, so it returns the string length, in bytes, without the sentence period.

This function is intended to be called by an application or an IME without generating the IME-related messages. The IME should not generate any IME related-messages in this function.


ImeConfigure

BOOL ImeConfigure(HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData )

Provides a dialog box to request optional information for an IME.

If successful, the return value is TRUE. Otherwise, it is FALSE.

hKL
Handle of the keyboard layout for the IME.
hWnd
Parent window handle
dwMode
Mode of the dialog box. It can be one of these values:
IME_CONFIG_GENERAL | The dialog box for general purpose configuration.
IME_CONFIG_REGWORD | The dialog box for registered word.
IME_CONFIG_SELECTDICTIONARY | The dialog box for selecting the dictionary of the IME.

lpData
Address of a REGISTERWORD structure if dwMode is IME_CONFIG_REGISTERWORD. Otherwise, lpData should be NULL.

This also can be NULL with IME_CONFIG_REGISTER mode if no initial string information is given.

An IME checks lpData as shown in the following pseudo code:

if (dwmode != IME_CONFIG_REGISTERWORD) {
         // Does original execution
} else if (IsBadReadPtr(lpdata, sizeof(REGISTERWORD))==FALSE) {
    if (IsBadStringPtr(PREGISTERWORD(lpdata)->lpReading,
            (UINT)-1)==FALSE) {
        // Set the reading string to word-registering dialog box
    }
   if (IsBadStringPtr(PREGISTERWORD(lpdata)->lpWord,
            (UINT)-1)==FALSE) {
        // Set the word string to word-registering dialog box
   }
}


ImeDestroy

BOOL ImeDestroy(UINT uReserved)

Terminates the IME.

If successful, the return value is TRUE. Otherwise, it is FALSE.

uReserved
Reserved, must be zero.


ImeEscape

LRESULT ImeEscape(HIMC hIMC, UINT uEscape, LPVOID lpData)

Allows an application to access the capabilities of a particular IME that are not directly available though other IMM functions. This is necessary mainly for country/region-specific functions or private functions in IME.

The return value depends on the escape function specified by uEscape. It is zero if the function fails.

hIMC
Handle of the input context.
uEscape
Escape function to perform. Each escape function should include parameter validation. Can be one of these values:
IME_ESC_QUERY _SUPPORT | Checks for implementation. If this escape is not implemented, the return value is zero.
IME_ESC_RESERVED_FIRST | The escape between IME_ESC_RESERVED_FIRST and IME_ESC_RESERVED_LAST is reserved by the system.
IME_ESC_RESERVED_LAST | The escape between IME_ESC_RESERVED_FIRST and IME_ESC_RESERVED_LAST is reserved by the system.
IME_ESC_PRIVATE_FIRST | The escape between IME_ESC_PRIVATE_FIRST and IME_ESC_PRIVATE_LAST is reserved for the IME. The IME can freely use these escape functions for its own purposes.
IME_ESC_PRIVATE_LAST | The escape between IME_ESC_PRIVATE_FIRST and IME_ESC_PRIVATE_LAST is reserved for the IME. The IME can freely use these escape functions for its own purposes.
IME_ESC_SEQUENCE_TO_INTERNAL | The escape is Chinese specific. An application that needs to run under all Asian platforms should not use it. It is for the Chinese EUDC editor. The lpData parameter is the sequence code, and the return value is the character code for this sequence code. Typically, the Chinese IME encodes its reading character codes into sequence 1 to n.
IME_ESC_GET_EUDC_DICTIONARY | The escape is Chinese specific. An application that needs to run under all Asian platforms should not use it. It is for the Chinese EUDC editor. On return from the function, the lpData is filled with the full path file name of the EUDC dictionary. The size of the buffer pointed to by lpData should be greater or equal to 80 * sizeof(TCHAR).
IME_ESC_SET_EUDC_DICTIONARY | The escape is Chinese specific. An application that needs to run under all Asian platforms should not use it. It is for the Chinese EUDC editor. On return from the function, the lpData is the full path file name of the EUDC dictionary. The path name should be less than 80 * sizeof(TCHAR).
IME_ESC_MAX_KEY | The escape is Chinese specific. An application that needs to run under all Asian platforms should not use it. It is for the Chinese EUDC editor. The return value is the maximum key stokes for an EUDC character.
IME_ESC_IME_NAME | The escape is Chinese specific. An application that needs to run under all Asian platforms should not use it. It is for the Chinese EUDC editor. On return from the function, the lpData is the IME name to be displayed on the EUDC editor. The size of the buffer pointed to by lpData should be greater or equal to 16 * sizeof(TCHAR).
IME_ESC_SYNC_HOTKEY | The escape is (Traditional) Chinese specific. An application that needs to run under all Asian platforms should not use it. It is to synchronize between different IMEs. The input parameter lpData is the IME private hot key ID. If this ID is zero, this IME should check every private hot key ID it concerns.
IME_ESC_HANJA_MODE | The escape is Korean specific. An application that needs to run under all Asian platforms should not use it. It is for conversion from Hangeul to Hanja. The input parameter lpData is filled with Hangeul character which will be converted to Hanja, and its null-terminated string. When the application needs to convert any Hangeul character to Hanja character in the same method of Hanja conversion with the composition character present, the application just requests this function and the IME sets itself as Hanja conversion mode.

lpData
Address of the data required for the escape function specified by uEscape.


ImeSetActiveContext

BOOL ImeSetActiveContext(HIMC hIMC , BOOL fFlag)

Activates or deactivates an input context and notifies the IME of the newly active input context. The IME can use the notification for initialization.

• If successful, the return value is TRUE. Otherwise, it is FALSE.

hIMC
Input context to be activated or deactivated.
fFlag
TRUE if activated, FALSE if deactivated.


ImeProcessKey

BOOL ImeProcessKey (HIMC hIMC, UINT uVirKey, DWORD lParam,
    CONST LPBYTE lpbKeyState)

Preprocesses keystrokes given through IMM.

The return value is TRUE if a key is necessary for the IME with the given input context. Otherwise, it is FALSE.

hIMC
Handle of the input context.
uVirKey
Virtual key to be processed.
lParam
lParam of a key message.
lpbKeyState
Address of a 256-byte array that contains the current keyboard state. The IME should not modify the keyboard state.

The system determines a key is handled by the IME by calling this function. When the function returns TRUE, the IME processes the key message before it is passed to an application. The system also calls the ImeToAsciiEx function. The function returns FALSE if the IME does not handle the key, in which case the system sends the key message to the target application.


NotifyIME

BOOL NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue )

Changes the status of the IME according to the given parameters.

If successful, the return value is TRUE. Otherwise, it is FALSE.

hIMC
Handle of the input context.
dwAction
Action flag. Can be one of these values:
Value | Meaning
NI_OPENCANDIDATE | An application requested that the IME open the candidate list. If the IME opens the candidate list, it sends the IMN_OPENCANDIDATE message. The dwIndex parameter is an index of a candidate list to open; dwValue is not used.
NI_CLOSECANDIDATE | An application requested that the IME close the candidate list. If IME closes the candidate list, it sends the IMN_CLOSECANDIDATE message. The dwIndex parameter is the index of the candidate list to close; dwValue is not used.
NI_SELECTCANDIDATESTR | An application selected one of the candidate lists. The dwIndex parameter is the index of the candidate list to be selected. The dwValue is the index of the candidate string in the selected candidate list.
NI_CHANGECANDIDATELIST | An application selected a different candidate list. The dwIndex parameter is the index of the candidate list to select; dwValue is not used.
NI_SETCANDIDATE_PAGESTART | An application changed the page starting index of a candidate list. The dwIndex parameter is the index of the candidate list to change. The dwValue parameter is the new page starting index.
NI_SETCANDIDATE_PAGESIZE | An application changed the page size of a candidate list. The dwIndex parameter is the index of the candidate list to change. The dwValue parameter is the new page size.
NI_CONTEXTUPDATED An application or the system updated the input context. If the dwValue parameter is IMC_SETCONVERSIONMODE, dwIndex is the previous conversion mode. If dwValue is IMC_SETSENTENCEMODE, dwIndex is the previous sentence mode. If dwValue contains any other value; dwIndex is not used. The dwValue parameter can be one of following values (used with WM_IME_CONTROL):

IMC_SETCANDIDATEPOS

IMC_SETCOMPOSITIONFONT

IMC_SETCOMPOSITIONWINDOW

IMC_SETCONVERSIONMODE

IMC_SETSENTENCEMODE

IMC_SETOPENSTATUS

NI_COMPOSITIONSTR | An application processes the composition string for the IME. This action is taken when the composition string is in the input context. The dwValue parameter is not used. The dwIndex parameter can be one of these values:
CPS_COMPLETE | Sets the composition string as the result string.
CPS_CONVERT | Converts the composition string.
CPS_REVERT | Cancels the current composition string and the unconverted string is set as the composition string.
CPS_CANCEL | Clears the composition string and sets the status as no composition string.

dwIndex
Depends on dwAction.
dwValue
Depends on dwAction.


ImeSelect

BOOL ImeSelect(HIMC hIMC, BOOL fSelect)

Initializes and uninitializes the IME's private context.

If successful, the return value is TRUE. Otherwise, it is FALSE.

hIMC
Handle of the input context.
fSelect
Initialization flag. Set to TRUE if initializing or FALSE if uninitializing (that is, freeing resources).


ImeSetCompositionString

BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex,
    LPCVOID lpComp, DWORD dwCompLen, LPCVOID lpRead, DWORD dwReadLen);

Causes the IME to arrange the composition string structure with the given data. This function causes the IME to send the WM_IME_COMPOSITION message.

If successful, the return value is TRUE. Otherwise, it is FALSE.

hIMC
Handle of the input context.
dwIndex
Can be one of these values:

SCS_SETSTR

SCS_CHANGEATTR

SCS_CHANGECLAUSE

lpComp
Address of the buffer that contains the updated string. The dwIndex parameter indicates the type of the string.
dwCompLen
Length of the buffer, in bytes.
lpRead
Address of the buffer that contains the updated string. The dwIndex parameter indicates the type of the string.
dwReadLen
Length of the buffer, in bytes.


ImeToAsciiEx

UINT ImeToAsciiEx(UINT uVirKey, UINT uScanCode,
    CONST LPBYTE lpbKeyState, LPDWORD lpdwTransBuf, UINT fuState,
    HIMC hIMC)

Translates messages using the IME conversion engine associated with the given input context.

The return value is the number of messages. If the number is greater than the length of the translated message buffer, the translated message buffer is not large enough. The system looks into the hMsgBuf to get the translation messages.

uVirKey
Virtual key code to be translated. When the property bit IME_PROP_KBD_CHAR_FIRST is on, the upper byte of the virtual key is the aid character code.
uScanCode
Hardware scan code of the key to be translated.
lpbKeyState
Address of a 256-byte array that contains the current keyboard state. The IME should not modify the keyboard state.
lpdwTransBuf
Address of a double word buffer to receive the translated result. The format is [Length of the pass in translated message buffer] [Message1] [wParam1] [lParam1] {[Message2] [wParam2] [lParam2]{...{...{...}}}}.
fuState
Active menu flag.
hIMC
Handle of the input context.


ImeRegisterWord

BOOL WINAPI ImeRegisterWord(LPCTSTR lpszReading, DWORD dwStyle,
    LPCTSTR lpszString)

Adds a new string to the dictionary of this IME.

If successful, the return value is TRUE. Otherwise, it is FALSE.

lpszReading
Address of the reading string for the new string.
dwStyle
Style of the new string. It can be a combination of these values:
Value | Meaning
IME_REGWORD_STYLE_EUDC | The string is in EUDC range.
IME_REGWORD_STYLE_USER_FIRST, IME_REGWORD_STYLE_USER_LAST | An ISV can use the constants in this range to define private styles for the IME.

lpszString
Address of the new string.


ImeUnregisterWord

BOOL WINAPI ImeUnregisterWord(LPCTSTR lpszReading, DWORD dwStyle,
    LPCTSTR lpszString)

Removes a string from the dictionary of this IME.

If successful, the return value is TRUE. Otherwise, it is FALSE.

lpszReading
Address of the reading string for the string to be removed.
dwStyle
Style of the string to be removed. It can be a combination of these values:
Value | Meaning
IME_REGWORD_STYLE_EUDC | The string is in EUDC range.
IME_REGWORD_STYLE_USER_FIRST, IME_REGWORD_STYLE_USER_LAST | An ISV can use the constants in this range to define private styles for the IME.

lpszString
Address of the string to be removed.


ImeGetRegisterWordStyle

UINT WINAPI ImeGetRegisterWordStyle(UINT nItem, LPSTYLEBUF lpStyleBuf)

Retrieves the available styles in this IME.

The return value is the number of styles copied to the buffer or, if nItems is zero, the buffer size, in array elements, needed to receive all available styles in this IME.

nItem
Maximum number of styles that the buffer can hold.
lpStyleBuf
Address of a STYLEBUF structure that receives the styles.


ImeEnumRegisterWord

UINT WINAPI ImeEnumRegisterWord(HKL hKL,
    REGISTERWORDENUMPROC lpfnEnumProc, LPCTSTR lpReading, DWORD dwStyle,
    LPCTSTR lpszString, LPVOID lpData)

Enumerates all strings that match the given reading string, style, or registered string.

If this function is successful, the return value is the last value returned by the callback function. Its meaning is defined by the application.

hKL
Handle of the keyboard layout for the IME.
lpfnEnumProc
Address of the callback function.
lpszReading
Address of the reading string to be enumerated. If lpszReading is NULL, the function enumerates all available reading strings that match with the specified dwStyle and lpszString.
dwStyle
Style to be enumerated. If dwStyle is NULL, the function enumerates all available styles that match the specified lpszReading and lpszString.
lpszString
Registered string to be enumerated. If lpszString is NULL, this function enumerates all registered strings that match with the specified lpszReading and dwStyle.
lpData
Address of application-supplied data.

If lpszReading, dwStyle, and lpszString are all NULL, the function enumerates all registered strings in the IME's dictionary. If any two of the input parameters are NULL, the function enumerates all registered strings that match the third parameter.


End User Defined Characters

In Asian versions of Windows® 95, there is a special code range or ranges in each DBCS character set (code page) in which the end user can define special characters called End User Defined Characters (EUDC). This section describes these code ranges and explains the affect of using these characters with Windows functions and structures.


Fonts

EUDC characters are available with two kinds of DBCS TrueType fonts: separate and integrated. A separate EUDC font contains only EUDC characters; an integrated font contains standard characters as well as EUDC characters.

A separate EUDC font may be either a typeface specific or nontypeface specific. If a separate EUDC font is explicitly associated with a DBCS TrueType or a WIFE font in the Windows 95 registry, the system treats the font as typeface specific and considers it part of the DBCS TrueType or WIFE font. If a separate EUDC font is defined as the system default EUDC font in the Windows 95 registry, Windows treats the font as nontypeface-specific EUDC and automatically associates it with all DBCS fonts except those DBCS TrueType or WIFE fonts that already have typeface-specific EUDC fonts. These definitions in Windows 95 registry are per DBCS character set (code page) and per user.

To have unique EUDC characters for each font, the end user must specify a separate EUDC or integrated font with each font. Otherwise, the end user may use a separate EUDC font as system default EUDC font.

In either case, the end user will be able to get fonts by purchasing font packages from font venders or creating fonts using an EUDC editor.

Separate EUDC font (DBCS TrueType font) |  |
Font Type | Typeface-specific EUDC font | Nontypeface-specific EUDC font (System default)
DBCS GDI raster font | N/A | X
DBCS TrueType font | X | X *1
DBCS TrueType font (integrated font) | N/A | N/A
WIFE font | X | X *1
DBCS Device font | N/A | X

Legend: X = available combination, N/A = not available combination

*1 If a DBCS TrueType font or a WIFE font has a separate EUDC font, the system default EUDC font will not be referred.

In Unicode, the End User Zone (U+E000 and higher locations) and Corporate User Zone (U+F8FF and lower locations) can be private use zones. Japanese Windows 3.1 and Windows NT® 3.1 have already reserved a space for Japanese EUDC characters (1880 characters) of the ShiftJIS character set in the End User Zone starting at U+E000, and Windows 95-J keeps the same space in the End User Zone. Windows 95 reserves a space for Chinese EUDC characters in the End User Zone.

Any Unicode-related objects and APIs need to recognize EUDC characters based on the definition of the character set (codepage) and the Unicode End User Zone.

  • TrueType EUDC fonts encoded in Unicode
  • NLS API


How EUDC Work

Previous Next

How EUDC Works

If a font is selected and an EUDC character is specified by a GDI function, GDI handles the EUDC character as follows:

  1. If the selected font is a DBCS TrueType or WIFE font that has a typeface-specific TrueType EUDC font associated with it, GDI retrieves character data from the typeface-specific EUDC font.
  2. If the selected font is a DBCS TrueType font that has its own EUDC characters, GDI retrieves the character data from the EUDC font. (GDI checks the Private Use Area bit in the aulUnicodeRange field of the Windows Metrics table to determine whether the DBCS TrueType font contains EUDC characters. If the character is not defined, GDI carries out the default character procedure for the selected font.
  3. If the selected font does not have a typeface-specific EUDC font associated with it, GDI retrieves character data from the system default EUDC font.
  4. If the EUDC character is not in the system default EUDC font, GDI carries out the default character procedure for the selected font.


How EUDC Works for Applications

Applications can use EUDC characters just as they do other characters in all functions except the following:

  • NLS functions
  • The EnableEUDC function


How EUDC Works for Drivers

If a device driver sets the TC_TT_ABLE value in the dpCaps1 member or the TC_RA_ABLE value in the dpText member of the GDIINFO structure, GDI handles each EUDC character as a DBCS character and sets the appropriate bitmap data in the physical font. The driver does not need to handle EUDC characters separately.

If a device driver does not set the TC_TT_ABLE and TC_RA_ABLE values, GDI processes EUDC characters by passing them to either the driver's raster or text function depending on whether the driver sets the FEC_EUDC_ABLE value in the dpCapsFE member of the GDIINFO structure.

Device capability | With TC_RA_ABLE or TC_TT_ABLE | Without TC_RA_ABLE and TC_TT_ABLE *1 |  |
Font Type | Standard characters | EUDC | Standard characters | EUDC
DBCS GDI font | ExtTextOut (FONTINFO) | BitBlt | N/A | N/A
DBCS TrueType font | ExtTextOut (FONTINFO) | BitBlt | ExtTextOut (Engine DDI) | BitBlt *2
 |  |  |  | ExtTextOut *3 (Engine DDI)
WIFE font | ExtTextOut (FONTINFO) | BitBlt | BitBlt | BitBlt
DBCS device font | N/A | N/A | ExtTextOut | BitBlt *2
 |  |  |  | ExtTextOut *3 (Engine DDI)
*1 For an engine realized DBCS TrueType font, an EUDC font belonging to the DBCS TrueType font will be selected. For all device fonts, an EUDC font belonging to System font will be selected. *2 If FEC_EUDC_ABLE of dpCapsFE isn't set, FE GDI calls driver BitBlt for EUDC characters. Note: FE Windows 3.1 drivers which can handle glyph indices will work under Windows 3.1 compatible layer. Only raster functions will be called for EUDC characters. *3 If FEC_EUDC_ABLE of dpCapsFE is set, FE GDI calls driver's ExtTextOut with glyph indices.


EUDC Code Ranges

The EUDCCodeRange key in the following Registry path contains entries that define the EUDC code ranges per code page.

HKEY_LOCAL_MACHINE\
    System\CurrentControlSet\Control\NLS\CodePage\EUDCCodeRange
CodePage  REG_SZ  FromTo{,FromTo}

Specifies an EUDC code range or ranges.

The value of CodePage is either 932 (Japan), 936 (Simplified Chinese), 949 (Unified Hangeul), or 950 (Traditional Chinese).

The FromTo must be a pair of four digit hexadecimal values separated by a hypen (-). To specify more than 2 code ranges, a comma (,) is a delimiter of each of the FromTo. Any EUDC-related functions do not work without this entry.

For example:

HKEY_LOCAL_MACHINE\
    System\CurrentControlSet\Control\NLS\CodePage\EUDCCodeRange
932=F040-F9FC
950=FA40-FEFE,8E40-A0FE,8140-8DFE,C6A1-C8FE


Parameters for EUDC

The EUDC key in the following Registry path contains entries that define the parameters for the EUDC.

HKEY_CURRENT_USER\EUDC\CodePage

The EUDC key contains a CodePage subkey. The values of the CodePage subkey is either 932 (Japan), 936 (Simplified Chinese), 949 (Unified Hangeul), or 950 (Traditional Chinese). The CodePage subkey may contain the following entries.

SystemDefaultEUDCFont  REG_SZ     TrueTypeEUDCFontFileName

Specifies the system default EUDC font. The TrueTypeEUDCFontFileName is the file name of a TrueType EUDC font. The system default EUDC font does not work without this entry.

TrueTypeFontTypeface    REG_SZ  TrueTypeEUDCFontFileName

Specifies a DBCS TrueType font typeface and its typeface-specific TrueType EUDC font file name. The TrueTypeFontTypeface is a DBCS TrueType font typeface and TrueTypeEUDCFontFileName is a typeface-specific TrueType EUDC font file name.

For example:

HKEY_CURRENT_USER\EUDC\932
SystemDefaultEUDCFont=EUDC.TTF
MS Mincho=MINEUDC.TTF
MS Gothic=GOTEUDC.TTF


NLS API

The following NLS API needs to recognize EUDC characters.


MultiByteToWideChar

  • WideCharToMultiByte
  • CompareStringA
  • LCMapStringA
  • GetStringTypeA

MultiByteToWideChar

If the multibyte character string contains an EUDC character, this function will map the EUDC character to a character position in the Unicode Private Use Zone.

MultiByteToWideChar will preserve the round trip mapping from a code page to Unicode and back to the original code page of EUDC characters. If a EUDC character from code page 932 is mapped to Unicode, and then mapped from Unicode to another code page with an EUDC range, it is likely that the original 932 EUDC character will be mapped to a different EUDC character in the destination code page. If Unicode data, which uses code points within the Unicode Private Use Zone, is mapped to a code page which has an EUDC range defined, it is possible that this Unicode data will be mapped into the code pages EUDC range.


WideCharToMultiByte

If the wide character string contains a character in the Unicode Private Use Zone, this function maps it to its multibyte character counterpart, if such a mapping exists. The code page specified in this function must contain an EUDC code range for the mapping to occur. If it does not, the function will return the default character for any characters in the Unicode Private Use Zone.

WideCharToMultiByte will preserve the round-trip mapping from a code page to Unicode and back to the original code page of EUDC characters. If an EUDC character from code page 932 is mapped to Unicode, and then mapped from Unicode to another code page with an EUDC range, it is likely that the original 932 EUDC character will be mapped to a different EUDC character in the destination code page. If Unicode data, which uses code points within the Unicode Private Use Zone, is mapped to a code page which has an EUDC range defined, it is possible that this Unicode data will be mapped into the code pages EUDC range.


CompareStringA

CompareStringA maps EUDC characters to character positions in the Unicode Private Use Zone and then CompareStringA deals the characters in the Unicode Private Use Zone according to the following schema.

There is a new script member value defined to represent all the code points in the Unicode Private Use Zone. This value should be greater than all other script membership values. The code points within this script membership will have alpha-numeric weights such that they will be sorted in numerical Unicode code point order. They will have no other linguistic weights associated with them. See the NLS API specification for more information on sorting.


LCMapStringA

Only LCMAP_SORTKEY effects for EUDC characters.


GetStringTypeA

Any CTYPE information about EUDC characters returns NULL.


GDI DDI

FEC_EUDC_ABLE of dpCapsFE

This flag indicates that the driver has the capability of processing EUDC characters as part of a downloadable font to a printer. This flag is valid for nonraster printer drivers.

dpCapsFE | Specifies abilities that are specific to Asian versions of the operating system. The member can be a combination of the following values.
 | Value | Meaning
 | FEC_TO_DEVICE(0x0010) | Indicates that the driver can appropriately process Gaiji as well when it outputs a device font. Requires support by the ExtTextOut and StrBlt functions. However, this bit is not currently supported. Therefore, be sure to include the support for this feature before setting this bit.
 | FEC_TT_DBCS(0x0020) | Indicates that the driver using a TrueType font as a device font can appropriately output a DBCS TrueType font. Requires support by the ExtTextOut and StrBlt functions. This bit need not be set if the driver has set either the dpText member's TC_RA_ABLE bit or the dpCaps1 member's TC_TT_ABLE bit.
 | FEC_EUDC_ABLE (0x0080) | Indicates that the driver has the capability of processing EUDC characters as part of device fonts. This flag is valid for nonraster printer drivers.
 | FEC_WIFE_ABLE (0x0100) | Indicates that the driver has the capability of processing a WIFE font as a downloadable font through TrueType service functions. This flag is useful for a printer driver which can download WIFE fonts.


GDI API

The system default TrueType EUDC and typeface-specific TrueType EUDC fonts are hidden fonts from applications. Thus, there is no way to handle the EUDC fonts in the applications, except the following special GDI functions.

Special applications like EUDC editors and Control Panel must call these special functions whenever the applications directly add, modify, or delete the EUDC fonts in real time without any help fromGDI.


EnableEUDC Function

BOOL EnableEUDC (fEnableEUDC )
BOOL fEnableEUDC;

The EnableEUDC function enables and disables the EUDC.

An application must call this function whenever the application adds, modifies, or deletes a TrueType EUDC font.

If the function succeeds in changing the EUDC status from enable to disable, or vice versa, the return value is TRUE. Otherwise, it is FALSE.

fEnableEUDC
If TRUE, this function enables EUDC and flushes the related contexts in GDI for all TrueType EUDC fonts registered in the Windows 95 registry.

After adding or deleting a TrueType EUDC font in the Windows 95 registry or modifying a TrueType EUDC font, an application must call this function.

If FALSE, this function disables EUDC and flushes the related contexts in GDI for all TrueType EUDC fonts registered in the Windows 95 registry.

Before adding or deleting a TrueType EUDC font to the Windows 95 registry or modifying a TrueType EUDC font, an application must call this function.


ControlEUDC Function [GDI (Windows 3.1J)]

int ControlEUDC(iControl)
int iControl;

The ControlEUDC function enables or disables all TrueType EUDC fonts.

A Windows 3.1J application may call this function whenever the application adds, modifies, or deletes a TrueType EUDC font.

If this function fails, the return value is zero.

iControl
Specifies the subfunction number.
CE_DISABLETTEUDC This subfunction disables all TrueType EUDC fonts and flushes the related contexts of the fonts in GDI.

Before adding, modifying, or deleting a TrueType EUDC font, an application must call this subfunction.

Once this subfunction is called, no GDI function effect for TrueType EUDC fonts.

CE_ENABLETTEUDC This subfunction enables all TrueType EUDC fonts.

After adding, modifying, or deleting a TrueType EUDC font, an application must call this subfunction.

After this subfunction is called, all GDI functions effect for TrueType EUDC fonts.


WIFE API

The following topics describe the WIFE API.


Escape Function

In Japanese Windows® 2.x, Japanese printer drivers have special escapes to support EUDC and Japanese applications called the Escape function to manipulate EUDC characters in the printers. Furthermore, some Japanese applications create EUDC characters and download them to the printers by calling the Escape function. In Japanese Windows 3.1, the system default EUDC font and the EUDC editor are supported so applications no longer manipulate EUDC characters by themselves. Only EUDC editors call the Escape function to manipulate EUDC characters.

Note In Asian versions of Windows 95, the subfunctions always fail since traditional EUDC functions are taken over by new TrueType EUDC functions.

int FAR PASCAL Escape (hFC, nEscape, nCount, lpInData, lpOutData)
HFC  hDC;
int  nEscape;
int  nCount;
LPSTR  lpInData;
LPSTR  lpOutData;
hDC
Specifies the target device context to be accessed.
nEscape
Specifies the subfunction number.

GAIJIFONTSIZE

GAIJIAREASIZE

GAIJISYSTEMGETFONT

GAIJISYSTEMSETFONT

GAIJITOCODE

GAIJIPHYSICALFONTSIZE

nCount
Specifies the size of memory that has been reserved in the area pointed to by the lpOutData argument.

Other parameters and the return value depend on each subfunction. However, if the return value is zero, an error has occurred or the function is not implemented.

When any of the following subfunctions is executed, GDI copies the value of the nCount parameter to the high-order word of lpInData. Therefore, the value to be set in the high-order word of lpInData in the description for each subfunction must also be set in the nCount parameter. Application programmers must make sure to do this.


GAIJIFONTSIZE

Returns the size of the typical EUDC character in the system default WIFE EUDC font.

Returns zero for failure. Windows 95 always returns zero.

lpInData
Not used.
lpOutData
A pointer to the POINT structure, which will contain the size of the typical EUDC character in the system default WIFE EUDC.

This subfunction returns the size that is specified by the StandardGaijiSize in the [UserFont] section of the userfont.ini file.

The format of the StandardGaijiSize key is as follows (units are physical dots):

StandardGaijiSize=<x-size>,<y-size>

The contents of a standard userfont.ini file is as follows:

[UserFont]

StandardGaijiSize=40,40


GAIJIAREASIZE

Returns the number of EUDC characters that can be used.

The return value is the total number of EUDC characters that can be used. Windows 95 always returns zero.

lpInData
Not used.
lpOutData
Not used.

This value must be determined from the EUDC character code range specified by WIFEMAN.INI.


GAIJISYSTEMGETFONT

Gets the bitmap data of the EUDC character from the system default WIFE font.

Returns zero for failure. Windows 95 always returns zero.

lpInData
The low-order word is the handle of the bitmap data.
lpOutData
A pointer to the memory block containing the EUDC character code.


GAIJISYSTEMSETFONT

Sets the bitmap data of the EUDC character to the system default WIFE EUDC font.

Returns zero for failure. The character code is returned in the area indicated by lpOutData. Windows 95 always returns zero.

lpInData
The high-order word is the index to the system default WIFE EUDC.

The low-order word is the handle of the bitmap.

lpOutData
A pointer to the memory block containing the EUDC character code.


GAIJITOCODE

Converts a EUDC index code to a character code.

Returns zero for failure. Windows 95 always returns zero.

lpInData
The high-order word is the index to the EUDC character.

The low-order word is unused.

lpOutData
A pointer to the memory block containing the character code.

The character code is returned in the area specified by lpOutData.


GAIJIPHYSICALFONTSIZE

Gets the size of bitmap specified by the index.

If successful, the return value is 1. Otherwise, it is zero for failure. Windows 95 always returns zero.

lpInData
The low-order word is the index to the system default WIFE EUDC font.

The high-order word always passes zero.

lpOutData
A pointer to the POINT structure, which will contain the size of the bitmap.


MiscGetEUDCLeadByteRange

USHORT FAR PASCAL MiscGetEUDCLeadByteRange(csCharSet );
CHAR_SET csCharSet;

Gets the lead byte range of EUDC characters.

The return value is the low-order word, lead byte start value. The high-order word is the lead byte end value. Zero is returned if there is no lead byte. For example, if the range of EUDC is from 0xF0xx to 0xF3xx, 0xF3F0 is returned.

Windows 95 always returns zero.

csCharSet
Specifies the character set.


Japanese EUDC

Japanese Windows 3.1 and Windows NT® 3.1 defined the EUDC code range (starting at F040) of the Japanese Microsoft Standard Character Set (ShiftJIS) in the End User Zone. The following table shows the mapping schema between the Japanese Microsoft Standard Character Set (starting at F040) and the Unicode (starting at U+E000).

Shift JIS | Unicode
F040 | U+E000
F041 | U+E001
F042 | U+E002
: | :
F9FA | U+E755
F9FB | U+E756
F9FC | U+E757


Korean EUDC

Unified Hangeul | Unicode
C9A1 - C9FE | U+E000 - U+E05D
FEA1 - FEFE | U+E05E - U+E0BB


Chinese EUDC

BIG-5 | Unicode
FA40 - FEFE | U+E000 - U+E310
8E40 - A0FE | U+E311 - U+EEB7
8140 - 8DFE | U+EEB8 - U+F6B0
C6A1 - C8FE | U+F6B1 - U+F848

GB 2312-80 | Unicode
9A41 - A0FE | U+E000 - U+E4DD
AA41 - AFFE | U+E4DE - U+E909
F8A1 - FEFE | U+E90A - U+EDE7


Windows Metrics

The Windows metrics table consists of a set of metrics that are required by Windows. The layout of this table is as follows:

USHORT   version
SHORT    xAvgCharWidth;
USHORT   usWeightClass;
USHORT   usWidthClass;
SHORT    fsType;
SHORT    ySubscriptXSize;
SHORT    ySubscriptYSize;
SHORT    ySubscriptXOffset;
SHORT    ySubscriptYOffset;
SHORT    ySuperscriptXSize;
SHORT    ySuperscriptYSize;
SHORT    ySuperscriptXOffset;
SHORT    ySuperscriptYOffset;
SHORT    yStrikeoutSize;
SHORT    yStrikeoutPosition;
SHORT    sFamilyClass;
PANOSE   panose;
ULONG    aulUnicodeRange[4];
CHAR     achVendID[4];
USHORT   fsSelection;
USHORT   usFirstCharIndex;
USHORT   usLastCharIndex;
USHORT   sTypoAscender;
USHORT   sTypoDescender;
USHORT   sTypoLineGap;
USHORT   usWinAscent;
USHORT   usWinDescent;
ULONG    aulCodePageRange[2];


aulUnicodeRange

Format: 32-bit unsigned long array (four elements) 128 bits.

Title: Unicode Character Range

Description: This field is used to specify the Unicode blocks encompassed by the font file in platform 3, encoding ID 1 (Microsoft platform.) If the bit is set (1), then the Unicode range is considered functional. If the bit is clear (zero), then the range is not considered functional. The determination of functional is left up to the font designer, although character set selection should attempt to be functional by ranges if at all possible. All reserved fields must be zero. See ISO/IEC 10646-1 for a the list of Unicode ranges and characters.

Bit | Description
0 | Basic Latin
1 | Latin-1 Supplement
2 | Latin Extended-A
3 | Latin Extended-B
4 | Ipa Extensions
5 | Spacing Modifier Letters
6 | Combining Diacritical Marks
7 | Basic Greek
8 | Greek Symbols And Coptic
9 | Cyrillic
1 | Armenian
11 | Basic Hebrew
12 | Hebrew Extended
13 | Basic Arabic
14 | Arabic Extended
15 | Devanagari
16 | Bengali
17 | Gurmukhi
18 | Gujarati
19 | Oriya
20 | Tamil
21 | Telugu
22 | Kannada
23 | Malayalam
24 | Thai
25 | Lao
26 | Basic Georgian
27 | Georgian Extended
28 | Hangul Jamo
29 | Latin Extended Additional
30 | Greek Extended
31 | General Punctuation
32 | Superscripts And Subscripts
33 | Currency Symbols
34 | Combining Diacritical Marks For Symbols
35 | Letterlike Symbols
36 | Number Forms
37 | Arrows
38 | Mathematical Operators
39 | Miscellaneous Technical
40 | Control Pictures
41 | Optical Character Recognition
42 | Enclosed Alphanumerics
43 | Box Drawing
44 | Block Elements
45 | Geometric Shapes
46 | Miscellaneous Dingbats
47 | Dingbats
48 | CJK Symbols And Punctuation
49 | Hiragana
50 | Katakana
51 | Bopomofo
52 | Hangul Compatibility Jamo
53 | CJK Miscellaneous
54 | Enclosed CJK Letters And Months
55 | CJK Compatibility
56 | Hangul
57 | Hangul Supplementary-A
58 | Hangul Supplementary-B
59 | CJK Unified Ideographs
60 | Private Use Area
61 | CJK Compatibility Ideographs
62 | Alphabetic Presentation Forms
63 | Arabic Presentation Forms-A
64 | Combining Half Marks
65 | CJK Compatibility Forms
66 | Small Form Variants
67 | Arabic Presentation Forms-B
68 | Halfwidth And Fullwidth Forms
69 | Specials
70-127 | Reserved for Unicode SubRanges


aulCodePageRange

Format: 32-bit unsigned long array (two elements) 64 bits.

Title: Code Page Character Range

Description: This field is used to specify the code pages encompassed by the font file in platform 3, encoding ID 1 (Microsoft platform.) If the bit is set (1), then the code page is considered functional. If the bit is clear (zero), then the code page is not considered functional. The determination of functional is left up to the font designer, although character set selection should attempt to be functional by code pages if at all possible. All reserved fields must be zero.

Bit | Codepage | Description
0 | 1252 | Latin 1
1 | 1250 | Latin 2: Eastern Europe
2 | 1251 | Cyrillic
3 | 1253 | Greek
4 | 1254 | Turkish
5 | 1255 | Hebrew
6 | 1256 | Arabic
7 | 1257 | Baltic
8-16 | Reserved for Alternate ANSI |
17 | 874 | Thai
18 | 932 | JIS/Japan
19 | 936 | Chinese: Simplified chars — PRC and Singapore
20 | 949 | Korean Unified Hangeul
21 | 950 | Chinese: Traditional chars — Taiwan and Hong Kong SAR
22-31 | Reserved for Alternate ANSI & OEM |
32-47 | Reserved for OEM |
48 | 869 | IBM Greek
49 | 866 | MS-DOS Russian
50 | 865 | MS-DOS Nordic
51 | 864 | Arabic
52 | 863 | MS-DOS Canadian French
53 | 862 | Hebrew
54 | 861 | MS-DOS Icelandic
55 | 860 | MS-DOS Portuguese
56 | 857 | IBM Turkish
57 | 855 | IBM Cyrillic; primarily Russian
58 | 852 | Latin 2
59 | 775 | Baltic
60 | 737 | Greek; former 437 G
61 | 708 | Arabic; ASMO 708
62 | 850 | WE/Latin 1
63 | 437 | US


Plug and Play Environment

The Plug and Play framework makes it easy for computer users to add new hardware. Plug and Play prevents conflicts between devices, allows hot docking, and enables the enumeration of devices on the system. Plug and Play does not create a new device-driver model. It specifies a set of API elements that are used in addition to, not in place of, existing driver architectures.

The Plug and Play framework has the following goals:

  • Easy installation and configuration of new devices.

    Plug and Play devices will be capable of identifying themselves and declaring their services and resource requirements. This information will enable the operating system to determine and set a working configuration and load the appropriate device drivers without any user intervention. Installing a new device will be as easy as plugging it in and copying a file to the driver directory.

  • Seamless dynamic configuration changes.

    The Plug and Play framework allows hot docking of portable computers, and hot insertion of devices. When an insertion event occurs, the operating system will recognize the new device, its services, and its requirements, and load the necessary drivers. Applications will be notified about dynamic events so they can take advantage of the new functionality or stop using unavailable devices. The user is prompted only when the required resources are not available to the new device.

  • Compatibility with installed base and old peripherals.

    Specific components in the Plug and Play framework hide the lack of a device reporting mechanism for devices that are not Plug and Play enabled. Information about these devices is kept in the registry. Devices which cannot be configured using software receive first priority in resource allocation. When unresolvable conflicts occur, the configuration manager may be accessed via a smart user interface which leverages information such as .INF-format files to guide the user through device configuration options.

  • Operating system and hardware independence.

    The Plug and Play framework defines several base components which can be implemented in any operating environment. Buses, devices, and resources are abstracted from the base components via hardware specific enumerators, arbitrators and device drivers. This ensures that this framework is extensible not only to other environments but also to future bus and device architectures.

  • Reduce complexity and increase flexibility of hardware.

    The Plug and Play framework includes guidelines for BIOS, system, and hardware vendors on building Plug and Play compatible hardware. An integral part of this documentation is the ISA Plug and Play design specification that defines a complete hardware and firmware design for ISA devices. Similar schemes are supported by architectures such as PCMCIA, SCSI, and PCI. The common denominator for all hardware devices is the device node (Dev_Node) defined by this framework. Hardware vendors will need to ensure that their devices, driver disks, and systems provide sufficient information to populate their device nodes if they want them to be Plug and Play!


Plug and Play System Components

The Plug and Play framework defines a single object that has several attributes. This object is called a device node. One of its attributes identifies devices that provide resources (buses). The collection of device nodes that describes a computer is called the devnode tree.

The Plug and Play framework defines several software components that have been added to the operating system: Configuration Manager, enumerators, and resource arbitrators.

Enumerators build the devnode tree and may participate in configuring the devices on their bus. The enumeration process takes place every time the computer starts. There are two phases of enumeration in the current implementation of the operating system: BIOS POST, and protected-mode. At the end of the enumeration process, the devnode tree includes information about available system resources, required device drivers, and resource requirements.

Configuration Manager uses resource arbitrators to find a working resource allocation which satisfies the overall requirements of currently enumerated devices. Device drivers are then notified of their assigned configuration.

Windows 95 accommodates dynamic system events by broadcasting system messages to applications and device drivers. When an event such as the insertion or removal of a device occurs, applications and device drivers are notified. They can then take any required action or, in some cases, veto the configuration change.

The Plug and Play framework also uses and extends the registry and device information files (with the .INF filename extension).

The registry stores information about all devices ever installed on a particular machine, including devices that are not Plug and Play enabled (but detected when the operating system was installed), Plug and Play devices which have been located by an enumerator, device-specific state information, bindings of devices to device drivers, and data about the last known configuration, which is used to accelerate the allocation of resources.

The device information files contain information about known devices and their configurations. The system provides some class-information files (for example, SCSI.INF and MODEM.INF); others are provided by the device manufacturer. When a new device is detected or enumerated, all known .INF files are searched for entries matching the device ID. When a match is found, the appropriate files are copied and the required data is copied into a newly created registry entry.


Interaction of Plug and Play Components

The following diagram shows how the Plug and Play components fit together. When the operating system is installed, detection modules are loaded based on the list in the MSDET.INF information file. When a device is detected that is not enabled for Plug and Play, information about it is retrieved from the appropriate device information file and stored in a new node created under the HKEY_LOCAL_MACHINE\ENUM\Root branch in the registry. On the first boot after initial installation (and on each subsequent boot) the system loads the enumerators and the same process occurs so that devices which can be enumerated rather than detected can be found, thus completing the list of known hardware. Enumerated devices appear under the relevant ENUM\enumerator name branch.

When the system starts, Configuration Manager loads enumerators to enumerate the devices in the system. Enumerators create a device node in the devnode tree for each enumerated device and populate it with information retrieved from the registry. The bus-specific naming schemes ensure that the root_key\device identifier is actually the device node's path in the registry. Drivers are loaded based on the driver information bound to each device in the registry, and are given a handle to their device node.


Plug and Play Boot Process

During the real-mode boot process, devices use only static configurations; no dynamic resource allocation or arbitration is provided. When a user adds a new device to the system, no software attempts to enable the device until the protect mode Configuration Manager has been able to set up the device successfully. One possible exception to this is that a Plug and Play BIOS may enable plug & play devices which are required for booting the system.

The boot process goes through four phases

  1. BIOS in control (Phase 0)
  2. MS-DOS compatibility driver and TSR loading (Phase 1)
  3. VMM32.VXD real-mode initialization (Phase 2)
  4. Operating system in Control in protected mode (Phase 3)


BIOS in Control (Phase 0)

There are two types of BIOS: non-Plug and Play BIOS and Plug and Play BIOS.

Non-Plug and Play BIOS

Computers that are not Plug and Play enabled behave as always. Plug and Play ISA cards that have option ROMs should power up with the option ROM enabled only if the ROM is actually required for proper functionality, for example a Plug and Play SCSI card which needs to boot from one of the attached hard drives. If the ROM is enabled and the device is active when Windows 95 protect mode initialization begins, that Plug and Play device will be treated as unmovable for purposes of resource allocation. This is because real mode drivers may have been loaded for the device in Phase 1 which would be unable to handle a shift in resource allocation. The phase 0 boot process for an old ROM acts exactly as it always has.

Plug and Play BIOS

Plug and Play enabled BIOSs will access non-volatile RAM to determine which Plug and Play ISA cards should be enabled and where their option ROMs should be mapped, and what I/O, DMA, and other assignments to give to the card. The BIOS will then program the Plug and Play cards prior to the power-on self test (POST). All cards that do not have a configuration stored in the BIOS will be disabled completely, eliminating the chance of a conflict.

The Plug and Play BIOS will also configure all devices on the motherboard. Some devices may have been disabled or assigned to different I/O, IRQ, or other resources by Configuration Manager.


Operating System in Control in Real Mode (Phase 1)

There is no automated device enumeration at this phase of the boot process. The hardware profile for docking purposes is computed. Drivers that need to be loaded must be explicitly specified in CONFIG.SYS or AUTOEXEC.BAT.

The following list gives the process for real-mode initialization:

  • Compute hardware profile.
  • Process CONFIG.SYS.
  • Process AUTOEXEC.BAT.
  • Start Windows 95 real mode loader (boot phase 2).


Windows 95 Real Mode Loader (Phase 2)

The final step before initializing the protected-mode Configuration Manager is to load static VxDs. For compatibility reasons, the real-mode loader will first load devices specified in SYSTEM.INI. This is the first phase of configuration management in which automated device enumeration takes place, and access to the registry is available, but there is still no automated resource assignment.

Based on the type of bus hardware detected by the real-mode Configuration Manager driver, the system loads the appropriate enumerator VxD. For example, the ISA enumerator will be loaded during this phase if an ISA bus exists on the system. If the machine has a Plug and Play BIOS, the BIOS enumerator loads. In all cases, the root enumerator loads during this phase.


Operating System in Control in Protected Mode (Phase 3)

Once VMM32.VXD has initialized, the full-featured protected-mode Configuration Manager is initialized. Configuration Manager imports device identifier information from the real-mode loader.

Drivers are loaded and initialized at this phase in exactly the same manner as with dynamic enumeration and device loading. Enumerators create device nodes, Configuration Manager calls the appropriate device loader, and the process continues.


Example Boot Sequence

This section describes the boot process for an ideal configuration: a computer with a new BIOS and new Plug and Play cards, but no non-Plug and Play hardware or real-mode device drivers.

Phase 0: BIOS Initialization

The BIOS configures all motherboard devices. Next it executes the ISA Plug and Play isolation algorithm and assigns configurations to all devices required for booting. It then checks the expansion card ROMs during the power-on self test and boot loads the operating system (phase 1).

Phase 1: Real Mode MS-DOS Driver Loading

CONFIG.SYS and AUTOEXEC.BAT are processed in the standard manner.

Phase 2: Real Mode VxD Loader

The system loads VxDs specified in SYSTEM.INI. The real mode loader loads the PnPBIOS enumerator if appropriate, as determined by detection at Windows 95 install time. If there is no PnPBIOS in the machine, the appropriate bus drivers are loaded based on what was detected at install time. In PnPBIOS machines, the BIOS is responsible for telling the operating system which busses are on the machine, which in turn drives the decision as to which bus drivers need to be loaded. The ISA enumerator, for example, is now loaded and enumerates all ISA devices, which, in turn, could have static VxDs that enumerate their children, and so on. Once all static VxDs have loaded, the system enters phase 3 of the boot process.

Phase 3: Protected Mode Operating System Initialization

Some VxDs are loaded during phase 2 of configuration management, but they initialize in protected mode during phase 3. Devices such as VPICD and VDMAD are passed a handle to the device node that caused them to load.

Resource arbitrators need to register with Configuration Manager during Sys_Critical_Init so that devices that register later in the boot process can allocate these resources.

Enumerators, such as the ISA bus enumerator, may add new device nodes to the in-memory devnode tree. Some of these nodes may also have children.

When all devices have been enumerated, all conflicts have been resolved, and all devices have been initialized, the system is ready to be used. The devnode tree will contain a complete description of every device connected to the machine as well as the resource requirements of those devices.


Configuration Manager

The Configuration Manager is the central component of the Plug and Play architecture. Working in conjunction with other components, the Configuration Manager finds workable configurations for all devices of the computer so that each device can use its assigned IRQ number, I/O port addresses, and other resources without conflict with other devices. The Configuration Manager also helps monitor the computer for changes in the number and type of devices present and manages the reconfiguration of the devices as needed when changes take place.

The Configuration Manager works in conjunction with enumerators, resource arbitrators, device loaders, and device drivers to create and maintain the configuration. It provides services and messages that these components use to carry out their configuration tasks. This section describes these services and messages and explains how they are used.


Hardware Tree, Device Nodes, and Device Identifiers

The hardware tree is a structure, in memory that is built and maintained by the Configuration Manager. The hardware tree contains configuration information for all devices in the computer and Configuration Manager uses it to keep track of the resources associated with each device, such as IRQs, IO ports and even non-sharable resources like SCSI identifiers. The hardware tree describes existing devices and resources, resource requirements, resource interdependencies, and current resource allocations.

A device node is a specific entry in the hardware tree. Each device node contains a unique device identifier and a list of resource requirements. The device identifier is a string which uniquely describes the device. The string typically identifies the component that found the device, but because it is also used as a key in the registry, it must be unique within the system so that information about the device can be retrieved reliably.

The requirements list identifies the type resources the device needs to successfully operate and any constraints associated with those resources. IRQs, IO ports, DMA channels and memory ranges are examples of types of resources. Constraints are often resource interdependencies; such a device requiring that it must use IRQ3 and IO port 02F8 in combination in order to operate successfully.

Although a device driver or other component cannot access the hardware tree or the device nodes directly, it can retrieve a handle to any device node and carry out tasks that retrieve and set information in the device node. The Configuration Manager provides these services to carry out tasks on a device node.

Service | Description
CONFIGMG_Create_DevNode | Adds a device node to the hardware tree.
CONFIGMG_Disable_DevNode | Disables a device node in the hardware tree.
CONFIGMG_Enable_DevNode | Enables a device node in the hardware tree.
CONFIGMG_Get_Child | Retrieves the first child of a given device node.
CONFIGMG_Get_Depth | Retrieves the depth of a device node in the hardware tree.
CONFIGMG_Get_Device_ID | Retrieves the device identifier for a device node.
CONFIGMG_Get_Device_ID_Size | Retrieves the size of a device identifier from a device node.
CONFIGMG_Get_DevNode_Status | Retrieves the status of a device node.
CONFIGMG_Get_Parent | Retrieves the handle of a parent of a device node.
CONFIGMG_Get_Sibling | Retrieves the sibling of a device node.
CONFIGMG_Locate_DevNode | Retrieves a pointer to the device node corresponding to a specified device driver.
CONFIGMG_Move_DevNode | Replaces a root enumerated devnode by the valid non-root enumerated devnode.
CONFIGMG_Query_Remove_SubTree | Checks whether a device node and its progeny can be removed.
CONFIGMG_Reenumerate_DevNode | Causes the enumerator of the specified device node to receive the CONFIG_ENUMERATE enumerator function.
CONFIGMG_Remove_SubTree | Removes a device node and its children.
CONFIGMG_Remove_Unmarked_Children | Removes any children of a device node that have the DN_HAS_MARK flag cleared.
CONFIGMG_Reset_Children_Marks | Resets the DN_HAS_MARK flag in the children of a specified device node.
CONFIGMG_Setup_DevNode | Reenables and configures a specified device node, or requests the enumerator to download information.

The device nodes in the hardware tree are arranged hierarchically. This means a device node is either at the root of the hardware tree or is the child of a parent device node. A device node can have child device nodes. The other children of a device node's parent are call siblings.

The hardware tree is built each time the computer is started. Furthermore, it is completely dynamic, changing even while the computer is running if a device is removed or added to the system.


Logical Configurations

A logical configuration is a description of the resources required by a device to operate successfully. Any given device can have several possible logical configurations. The Configuration Manager uses the logical configurations of a device to determine how to allocate resources among competing devices. The Configuration Manager provides services that device drivers, enumerators, and other components can use to examine and create logical configurations.

There are these logical configuration services.

Service | Description
CONFIGMG_Add_Empty_Log_Conf | Creates an empty logical configuration (this configuration has no resource descriptor).
CONFIGMG_Free_Log_Conf | Frees a logical configuration and all resource descriptors associated with it.
CONFIGMG_Query_Change_HW_Prof |
CONFIGMG_Get_Alloc_Log_Conf | Gets the allocated (or boot) resources in a table format.
CONFIGMG_Get_First_Log_Conf | Retrieves a handle of the first logical configuration of the specified type in a device node.
CONFIGMG_Get_Next_Log_Conf | Retrieves a handle to the next logical configuration following the given configuration.
CONFIGMG_ISAPNP_To_CM | Converts ISAPNP requirements and adds them to a specified device node.
CONFIGMG_Read_Registry_Log_Confs | Retrieves logical configurations from the registry.

Device drivers typically use the CONFIGMG_Add_Empty_Log_Conf service to create empty logical configurations in which they can fill their explicit resource requirements. Device drivers and other components use the CONFIGMG_Get_First_Log_Conf and CONFIGMG_Get_Next_Log_Conf services to check all logical configurations associated with a device node. A device driver uses the CONFIGMG_Get_Alloc_Log_Conf service to retrieve its assigned (allocated) resources.


Resource Descriptors

A resource descriptor describes the resources in a logical configuration. There are resource descriptors for memory, IO ports, DMA channels, and IRQs. Other resource descriptors can be created as needed to identifies other types of resources available to devices.

Memory resource descriptors identify memory address ranges. The descriptor contains a MEM_DES structure that describes the memory resource and an array of MEM_RANGE structures that identify the possible memory configurations.

I/O port resource descriptors identify IO port address ranges. The descriptor contains an IO_DES structure that describes the IO port resource and and array of IO_RANGE structures that identify the possible port configurations.

DMA channel resource descriptors identify a set of DMA channel alternatives. The descriptor is a DMA_DES structure that identifies the DMA channels that the device can use.

IRQ resource descriptors identify a set of IRQ alternatives. The descriptor is a IRQ_DES structure that identifies the IRQs the device can use and whether the IRQ can be shared.

The Configuration Manager provides services that device drivers and other components can use to examine and modify resource descriptors. There are these services.

Service | Description
CONFIGMG_Add_Res_Des | Adds a resource descriptor to a logical configuration.
CONFIGMG_Free_Res_Des | Destroys a resource descriptor.
CONFIGMG_Get_Next_Res_Des | Retrieves the handle of the next resource descriptor in a logical configuration.
CONFIGMG_Get_Res_Des_Data | Copies the data from a specified resource descriptor into a buffer.
CONFIGMG_Get_Res_Des_Data_Size | Retrieves the size of a resource descriptor, not including the resource-descriptor header.
CONFIGMG_Modify_Res_Des | Modifies a resource descriptor.

When working with IO port resource descriptors, the IOR_Alias and IOR_Decode values specify the port aliases that a device responds to. A port alias is an address that the device responds to as if it were the actual address of an IO port. Additionally, some cards will actually use additional ports for different purposes, but use a decoding scheme that makes it seem as though they were using aliases; for example, an ISA card may decode 10 bits and require port 03C0h. This card would need to specify an IOR_Alias offset of 04h and a IOR_Decode of 3 (no aliases are used as actual ports). For convenience, the alias field can be set to zero indicate no aliases are required; in this case, the decode field is ignored.

If the card were to use the ports at 7C0h, 0BC0h, and 0FC0h, where these ports have different functionality, the IOR_Alias value would be the same and the IOR_Decode value would be 0Fh, indicating that bits 11 and 12 of the port address were significant. Thus, the allocation is for all of the ports (PORT[i] + (n*alias*256)) & (decode*256 | 03FFh), where n is any integer and PORT is the range specified by the IOR_nPorts, IOR_Min, and IOR_Max fields. Note that the minimum alias is 4 and the minimum decode is 3.

Because of the history of the ISA bus, it is assumed that all EISA and ISA cards that use any port where PORT = n*400 + Z (where "Z" is a port in the range 100h - 3ffh, and "N" is greater than or equal to 1) will reserve port Z and treat the other port(s) as aliases. If a port that falls in this set is reserved but the driver does not reserve the "Z" address, it is assumed that the device is on a local bus (such as PCI) where the reserved port address is not presented on the ISA bus.


Device Loader Services and Messages

A device loader loads and manages device drivers and enumerators for a given device node. Device loaders are typically used when devices are managed by various layers of device drivers. The device loader coordinates the work of the various layers and carries out general configuration tasks that apply to all device drivers. The Configuration Manager provides services that device loaders can use to carry out their tasks.

There are these services.

Service | Description
CONFIGMG_Get_DDBs | Retrieves the device descriptor blocks of dynamically loadable VxDs for a devnode.
CONFIGMG_Get_Private_DWord | Retrieves the private value a device node has in another device node.
CONFIGMG_Load_DLVxD | Loads dynamically loadable VxDs for a devnode.
CONFIGMG_Register_DevLoader | Specifies that a static VxD is ready to be a device loader.
CONFIGMG_Set_Private_DWord | Sets the private value a device node has in another device node.

A device loader registers itself by using the CONFIGMG_Register_DevLoader service. This associates the device loader with the given device node. The device loader can also load an enumerator and device driver for the given device node or any child device nodes by using the CONFIGMG_Load_DLVxD service. It can also retrieve and assign private values to device nodes by using the CONFIGMG_Get_Private_DWord and CONFIGMG_Set_Private_DWord services.

You can retrieve the device descriptor block for any dynamically loaded virtual device associated with a device node by using the CONFIGMG_Get_DDBs service.


Enumerator Services and Messages

Enumerators locate and identify Plug and Play devices and retrieve information about these devices to use to construct the hardware tree. The Configuration Manager provides services for registering enumerators as well as services enumerators can use to carry out their enumeration tasks. In particular, an enumerator can register an enumeration handler function by using the CONFIGMG_Register_Enumerator service. The Configuration Manager sends an enumeration message to this handler whenever it needs the enumerator to carry out a task.

There are these enumeration services.

Service | Description
CONFIGMG_CallBack_Enumerator | Calls back to the device driver, once per devnode.
CONFIGMG_Get_Bus_Info | Gets bus information from the devnode.
CONFIGMG_Register_Enumerator | Registers the enumerator handler for the device node.
CONFIGMG_Set_Bus_Info | Sets bus information in the devnode.

There are these enumeration messages.

Message | Description
CONFIG_ENUMERATE | Directs a driver to enumerate its immediate children. This message is sent when a device is inserted or removed.
CONFIG_FILTER | Directs a driver to process a new device or changes to the configuration of a device.
CONFIG_REMOVE | Notifies the driver that the associated device node is being removed from the hardware tree.
CONFIG_START | Notifies the driver that a configuration has been allocated for the device node; the driver can retrieve the configuration and begin to use it.
CONFIG_STOP | Directs the driver to stop using its currently allocated configuration.
CONFIG_TEST | Requests permission from the driver to invalidate the assigned configuration or remove the given device node; the driver should not grant permission if it cannot stop using the current configuration or is not prepared for the device to be removed from the system.

The enumeration handler must return CR_DEFAULT for any messages it does not not process.

Enumerators are responsible for creating device identifiers for the devices they locate. Each identifier must be unique and be consistently the same on each system boot. The string must be constructed so that it can serve to identify a unique entry in the registry. The string must start with the enumerator's name followed by a backslash. For example, the ISA Plug and Play enumerator starts all device identifiers with "ISAPNP\".


Device Driver Services and Messages

A device driver controls and manages the device hardware. Device drivers are responsible for identifying the specific resource requirements of the given device and for setting the device to operate with the configuration assigned by the Configuration Manager. The Configuration Manager provides services and messages that a device driver can use to carry out its tasks. In particular, a device driver can register a configuration handler function by using the CONFIGMG_Register_Device_Driver service. Once the handler is registered, the Configuration Manager sends it configuration messages whenever it needs the device driver to carry out a configuration task.

These are the device driver services.

Service | Description
CONFIGMG_CallBack_Device_Driver | Calls back to the device driver, once per devnode, with CONFIGMG_Register_Device_Driver.
CONFIGMG_Get_Device_Driver_Private_DWord | Retrieves the private value for a device driver in a device node.
CONFIGMG_Register_Device_Driver | Registers a configuration handler for a device node.
CONFIGMG_Set_Device_Driver_Private_DWord | Sets the private value for a device driver in a device node.

These are the configuration messages.

Message | Description
CONFIG_ENUMERATE | Directs a driver to enumerate its immediate children. This message is sent when a device is inserted or removed.
CONFIG_FILTER | Directs a driver to process a new device or changes to the configuration of a device.
CONFIG_REMOVE | Notifies the driver that the associated device node is being removed from the hardware tree.
CONFIG_START | Notifies the driver that a configuration has been allocated for the device node; the driver can retrieve the configuration and begin to use it.
CONFIG_STOP | Directs the driver to stop using its currently allocated configuration.
CONFIG_TEST | Requests permission from the driver to invalidate the assigned configuration or remove the given device node; the driver should not grant permission if it cannot stop using the current configuration or is not prepared for the device to be removed from the system.

The device driver must return CR_DEFAULT for any configuration messages it does not process.


Resource Arbitrator Services and Messages

Resource arbitrators resolve resource conflicts between devices. An arbitrator reviews a list of requirements for devices and finds the best allocation of resources to satisfy all devices. The Configuration Manager provides services and messages to support the operation of resource arbitrators. In particular, arbitrators register an arbitrator handler function with the Configuration Manager by using the CONFIGMG_Register_Arbitrator service. Once registered, this handler receives arbitration messages from the Configuration Manager whenever resolution of a conflict for the corresponding resource is needed.

There are these arbitrator services.

Service | Description
CONFIGMG_Deregister_Arbitrator | Removes a resource arbitrator.
CONFIGMG_Query_Arbitrator_Free_Data | Retrieves arbitrator-specific free information.
CONFIGMG_Query_Arbitrator_Free_Size | Retrieves the size of the free information the arbitrator would return in a call to the CONFIGMG_Query_Arbitrator_Free_Data function.
CONFIGMG_Register_Arbitrator | Registers a resource arbitrator.

There are this arbitration message.

Message | Description
ARB_FORCE_ALLOC | Directs the arbitrator to retest, without failure, the given resource allocations.
ARB_QUERY_FREE | Requests information about free resources for a logical configuration.
ARB_RELEASE_ALLOC | Directs the arbitrator to clean up after a failed test allocation.
ARB_REMOVE | Sent when the device node associated with the arbitration handler is being removed.
ARB_RETEST_ALLOC | Directs the arbitrator to retest the given resource allocations.
ARB_SET_ALLOC | Directs the arbitrator to make a test allocation the real allocation.
ARB_TEST_ALLOC | Directs the arbitrator to test the given resource allocations.

The arbitration handler must return CR_DEFAULT for any messages it does not process.


Range Lists

A range list is a sorted list of IO port or memory address ranges (in DWORD form) in which no two ranges overlap. Resource arbitrators that manage I/O and memory resources use the range list services to discover whether a given IO or memory range conflicts with any other range. These services detect attempts to create range lists containing overlaps and either fail or create merged ranges where there would have been overlaps. Each range must specify a continguous range of addresses, but the range list itself can contain multiple ranges, none of which necessarily need to be contiguous with any other range in the list.

There are these range list services.

Service | Description
CONFIGMG_Add_Range | Adds a memory range to a range list.
CONFIGMG_Create_Range_List | Creates a list of memory ranges.
CONFIGMG_Delete_Range | Deletes a memory range from a range list.
CONFIGMG_Dump_Range_List | Dumps a range list to a debugging terminal.
CONFIGMG_Dup_Range_List | Copies a range list.
CONFIGMG_First_Range | Retrieves the first range element in a range list.
CONFIGMG_Free_Range_List | Frees the specified range list and memory allocated to it.
CONFIGMG_Intersect_Range_List | Creates a range list from the intersection of two specified range lists.
CONFIGMG_Invert_Range_List | Creates a range list that is the inverse of a specified range list; all claimed memory ranges in the new list are specified as free in the old list, and vice versa.
CONFIGMG_Next_Range | Retrieves the next range element in a range list.
CONFIGMG_Test_Range_Available | Checks a memory range against a range list to ensure no conflicts exist.


Registry Services

Device drivers and other components can store information about a given device node in the registry as well as retrieve information about a device node stored in the registry by the Configuration Manager. There are these registry services.

Service | Description
CONFIGMG_Get_DevNode_Key | Retrieves the string of a registry key from a device node.
CONFIGMG_Get_DevNode_Key_Size | Retrieves the size of the registry key from a device node.
CONFIGMG_Read_Registry_Value | Retrieves a value from the registry.
CONFIGMG_Write_Registry_Value | Sets a value in the registry.


Hardware Profile Services

A hardware profile is a set of information that defines the hardware present in the system. Hardware profiles are typically used in docking systems in which the number and type of devices may be different with each docking station. The typical docking system has one hardware profile for each docking station and one for when it is not docked.

When the system boots, docks or undocks, each enumerator reenumerates its hardware, determining what is available and creating or removing device nodes to reflect that availability. The enumerator uses the hardware-profile services to create and maintain the hardware profiles for the system. There are these services.

Service | Description
CONFIGMG_Fail_Change_Config | Cancels preparation for changing the current Hardware Profile.
CONFIGMG_Get_HW_Prof_Flags | Retrieves the configuration-specific configuration flags for a devnode/hardware profile combination.
CONFIGMG_Recompute_HW_Prof | Calculates the current hardware profile based on the docking station identifier and the docking station serial ID.
CONFIGMG_Set_HW_Prof | Sets the current hardware profile.
CONFIGMG_Set_HW_Prof_Flags | Sets the configuration-specific configuration flags for a devnode/hardware profile combination.

The hardware-profile flags apply to each device node and identify whether the device node should be created for a given profile. You can get and set the flags by using the CONFIGMG_Get_HW_Prof_Flags and CONFIGMG_Set_HW_Prof_Flags services.


Miscellaneous Services

Device drivers and other components use the miscellaneous services to carry out various support tasks or debugging. There are these services.

Service | Description
CONFIGMG_Call_At_Appy_Time | Configuration Manager will call back the handler at app time.
CONFIGMG_Get_CRC_CheckSum | Computes a CRC for a specific buffer.
CONFIGMG_Get_Version | Retrieves the version number of the Configuration Manager.
CONFIGMG_Lock | Prevents Configuration manager from sending events.
CONFIGMG_Process_Events_Now | Forces event processing to occur immediately.
CONFIGMG_Set_Private_Problem | Causes Configuration Manager to call the private API with the specified devnode and reference data.
CONFIGMG_Unlock | Reenables Configuration manager events after a call to the CONFIGMG_Lock function.
CONFIGMG_Yield | Waits a specfied number of microsoeconds.


Plug and Play Device Drivers

An ideal Plug and Play driver has the following capabilities:

  • Retrieves configuration information from Configuration Manager.
  • Is dynamically loadable.
  • Is dynamically reconfigurable.
  • Requires minimal user interaction to select the proper driver.
  • Reacts to system messages about the insertion or removal of new devices.
  • May need to understand state information; that is, the settings for the device may need to change based on which user is logged in, whether the machine is docked or undocked (in the case of a docking station architecture) or both.

Most of the Plug and Play work required for device drivers is producing a callback entry point that the system uses to assign a configuration. For information about this entry point, see Driver Callback Entry Point. For a sample Plug and Play device driver, see Sample Plug and Play Driver.

Many Plug and Play system components, such as enumerators and arbitrators, will not be written by the majority of device driver writers. However, a basic understanding of what each of these components does is important for a complete understanding of how they interact.

Drivers for different architectures will interact with Plug and Play in different ways. Many VxDs will interact directly with Configuration Manager, but drivers that are a part of a layered driver model may get configuration information through another layer. For example, Windows 95 network drivers are based on the NDIS driver model, with extensions for Plug and Play capabilities. The net wrapper interacts with the Windows 95 configuration manager and routes the appropriate configuration information to the extended NDIS drivers. Windows 95 disk and SCSI drivers are based on the Windows NT®/Windows® 2000 SCSI mini-port model, with extensions for Plug and Play. IOS routes configuration information to these drivers. VxDs such as Virtual Display Devices can interact directly with Configuration Manager. For each of these driver models, the interface with Configuration Manager is different. However, the basic requirements are the same.


Components of Plug and Play Architecture

All configuration management in the Plug and Play system is directed by the Configuration Manager, which is implemented as a VxD. Configuration Manager manipulates three major data stores:

  • Device nodes
  • Devnode tree
  • Registry

Configuration Manager works with four major software components:

  • Enumerators
  • Arbitrators
  • Device loaders
  • Device drivers


Device Nodes

A device node is the basic in-memory representation of a device that is physically present on the system. This data structure contains information relating to the device and its drivers. The major information stored in a device node is:

  • Device ID
  • Currently assigned configuration
  • Possible logical configurations
  • Status information
  • Device driver entry point
  • Enumerator entry point (optional)
  • Arbitrator entry point(s) (optional)

Device nodes are created only by enumerators. The creation of a device node causes the appropriate driver to be loaded. Driver writers typically need not concern themselves with creating device nodes or device IDs.

Device ID

A device ID is a unique ASCII string. This string can be used to cross-reference data about the device stored in the registry. Examples of device IDs are:

  • Root\*PNP0000\0
  • ISAPNP\ADP1522_DEV0000\E8124123
  • BIOS\*PNP0100\0
  • PCMCIA\MEGAHERTZ-XJ124FM-936B

For more information about device IDs, see

Assigned Configuration

Drivers examine this portion of the device node to determine which resources have been allocated for the device. For Plug and Play cards, the assigned resources for a given device may change from one boot to the next, or even while the computer is running (dynamically).

Logical Configurations

Logical configurations describe the various configurations that are valid for a given piece of hardware. Most driver writers will not need to examine or modify the logical configuration list for a given device node. Enumerators are responsible for creating the appropriate logical configurations when they create a device node.

Status Information

Information about the state of a device, such as whether it is disabled or configured, is maintained by Configuration Manager in each device node. Drivers can query this information.

Device Driver Entry Point

When a driver is loaded for a specific device node, it registers with Configuration Manager, passing an entry point that will be called to assign or change hardware configurations.

Enumerator Entry Point

Device nodes that have child nodes will have enumerators. Enumerators are the components of Plug and Play that identify installed hardware and create device nodes. Most driver writers will not need to write an enumerator.

Arbitrator Entry Point(s)

Arbitrators are the components of Plug and Play that assign ownership of various resources, such as IRQs and I/O ports. Most driver writers will not need to write an arbitrator.


Devnode Tree

The devnode tree is a hierarchical tree of device nodes. Any device node that has an enumerator can create new child device nodes. Any of these child device nodes can have an enumerator that creates further children of that device node. Normally, drivers do not know or care about their exact location within the tree. Drivers typically are only concerned with their own hardware device or device node, and are oblivious to the layers above or below them in the tree.

The devnode tree has two purposes:

  • Describe all hardware that is present in the system.
  • Provide a mechanism for enumerators to configure their children's hardware, allowing bus-independent drivers.

The distinction between the devnode tree and the registry is important. In a fully Plug and Play system, the devnode tree will be an accurate hierarchical representation of the currently installed devices. By contrast, the registry contains information for all devices ever installed (even if they are not currently present) and the location of a device in the registry does not fully reflect the hierarchical structure described in the devnode tree. (In the registry, devices are located beneath their enumerator but all enumerators are kept in a flat list.) The devnode tree exists in memory only, whereas the registry is saved on disk.

Sample Devnode Tree

The following sample devnode tree shows the device IDs of some typical devices and where in the hierarchy one might expect to find them. The actual contents of each device node other than the device ID are not shown.

Htree\Root\0 - Root node of devnode tree
     \Root\*PNP0801\0 - Old-style Sound Blaster compatible sound device
     \Root\*PNP0C00\0 - Plug and Play BIOS
         \BIOS\*PNP0901\0 - Super VGA compatible display adapter
         \BIOS\*PNP0000\0 - AT Interrupt Controller
         \BIOS\*PNP0100\0 - AT Timer
         \BIOS\*PNP0200\0 - AT DMA Controller
         \BIOS\*PNP0301\0 - PS/2 Style Keyboard Contoller
         \BIOS\*PNP0400\0 - Standard LPT printer port
         \BIOS\*PNP0400\1 - Standard LPT printer port
         \BIOS\*PNP0501\0 - 16550 COM port
         \BIOS\*PNP0501\1 - 16550 COM port
         \BIOS\*PNP0700\0 - PC standard floppy disk controller
         \BIOS\*PNP0800\0 - AT style speaker sound
         \BIOS\*PNP0901\0 - SVGA compatible display adapter
         \BIOS\*PNP0B00\0 - AT Real Time Clock
         \BIOS\*PNP0C01\0 - System memory
         \BIOS\*PNP0E00\0 - PCMCIA Controller
             \PCMCIA\3C08AF\0 - Network adapter


Registry

The registry is a system-wide database, accessed in both Windows® 95 and Windows NT®/Windows® 2000 through the Microsoft Win32® API set. Additionally, Windows 95 provides real-mode access to the registry to allow its use during boot-up prior to the switch to protected mode.

The registry stores a hierarchical tree of "Keys" and "Values," similar to entries in Windows 3.1-format .INI files (except that Windows 3.1 .INI files have a flat structure, as opposed to the tree structure of the registry.) Windows 95 Plug and Play uses the registry to store information about which drivers should be loaded when a particular device is enumerated, as well as such information as the driver revision number, manufacturer, and potential logical configurations of the device.

Most Plug and Play registry entries are stored in the ENUM tree. (That is, \\HKEY_LOCAL_MACHINE\ENUM.) Under ENUM, each enumerator gets its own branch, with one child under the enumerator for each device it has ever enumerated and set up. There is one special enumerator branch called ENUM\ROOT which contains the registry entries for old-style, non-Plug and Play hardware for which there is no enumerator but which can be detected using other means. The Device Installer creates new registry entries when an enumerator detects a device for which there is no registry entry. Most of the information is provided either by the .INF file provided with the device or directly by the device's setup module.

The registry also stores configuration-specific information (that is, information which is relevant to whether a capable portable computer is docked or undocked) as well as user-specific information. For any particular setting, the application or device driver must determine whether it is configuration-aware or user-aware, and write the entries to the registry in the proper location.

General configuration-specific information is stored in the \\HKEY_LOCAL_MACHINE\CONFIG\configname branch of the registry. The rules for storing information in these configuration specific branches should be the same as the rules for their grandparents. Typically, creators and consumers of config- and user-specific information read and write to the predefined keys HKEY_CURRENT_CONFIG\ and HKEY_CURRENT_USER which automatically selects the appropriate subbranch of the CONFIG and HKEY_USERS trees.

Since information about static devices (that is, non-Plug and Play hardware) is stored in \\HKEY_LOCAL_MACHINE\ENUM\ROOT\*, information about static devices that only applies to a particular configuration is stored in: \\HKEY_LOCAL_MACHINE\CONFIG\xxxx\ENUM\ROOT.


Sample Registry Entries

ENUM\ROOT\*PNP0000\0000
     DrvDesc="Programmable Interrupt Controller"
     Class="System"
     BootConfig=(I/O ports 20h, 21h, A0h, and A1h - Binary resource data)
     Driver="System\0000"
     HardwareID="*PNP0000"
     InfName="MACHINE.INF"
     Mfg="Microsoft"
     NoSetupUI="1"
 ENUM\BIOS\*PNP0000\0000\LogConfig
     0=(Binary resource data, in this case same as BootConfig above)
 SYSTEM\CurrentControlSet\Services\Class\System\0000
     DriverDesc="Programmable Interrupt Controller"
     DevLoader="*VPICD"
     EnumPropPages="Sysclass.dll,EnumPropPages"


Device IDs

Device IDs are unique ASCII strings that are created by enumerators to identify a hardware device. IDs are made up of three distinct parts, separated by a backslash. The first part of the ID identifies the enumerator that created the ID. The second part is the ID itself.

If this part of the string begins with an asterisk ("*"), this is an EISA-format ID, which are three letters followed by four hexadecimal digits. The 3-letter prefixes are assigned on a per-company basis and hardware vendors must only use those letters assigned to their company, or the PNPxxxx identifiers discussed in the following. EISA identifiers may be obtained from:

If you are a hardware manufacturer building ISA Plug and Play adapter boards, you are expected to procure your own three letter EISA identifier and assign your own IDs for your hardware. EISA identifiers may be obtained from:

BCPR Services, Inc.
< P.O. Box 11137
< Spring, Texas  77391-1137
< (713)251-4770 (phone)
< (713)251-4832 (fax)

Many enumerators generate EISA IDs when enumerating devices, and the "*" indicates that the ID comes from this generic pool, thus allowing setup to select the appropriate driver regardless of which enumerator created the ID. An ID that does not start with an "*" will require setup information specific to the enumerator that created the ID to find the appropriate driver. The third part of the ID is a unique instance number for this computer. This is used to distinguish two or more identical devices in a single computer from one another. For example, two COM ports require two unique instances.

Since many devices do not have an EISA ID, Microsoft has defined IDs for every device that Windows 95 supplies drivers for. We have reserved the EISA manufacturer's ID "PNP" and defined a set of IDs for base system components:

  • PNP0000 AT interrupt controller
  • PNP0100 AT timer
  • PNP0200 AT DMA controller

Other base system components are numbered in the same way. The complete current list of compatibility IDs is available on Compuserve in the PLUGPLAY forum, under the filename DEVIDS.ZIP.

ISA device IDs have the following form:

ISAPNP\device ID+_DEV0000, 0001, ...\serial number

In this example, device ID is taken from the first four bytes of the card. The entries for _DEV numbers are required only if there are many devices on the card.

The following table gives some sample ISA device IDs.

Device ID | Description
ISAPNP\FDC0000\00000012 | future domain
ISAPNP\ADP1522_DEV0000\E8124123 | Adaptec SCSI device (function 0)
ISAPNP\ADP1522_DEV0001\E8124123 | Adaptec floppy device (function 1)

For PCMCIA, the device ID is created from tuple information on the card. The goal is to create a unique ID for each card.

The ID is created by concatenating the PCMCIA prefix, the manufacturer-name string, the product-name string, a 16-bit CRC, and the instance value for the card.

PCMCIA\manufacturer_name-product_name-crc\instance

A PCMCIA device identifier might look like the following example:

PCMCIA\MEGAHERTZ-XJ124FM-936B

The CRC is created from the following tuple data:

  • CISTPL_CFTABLE_ENTRY
  • CISTPL_CONFIG
  • CISTPL_DEVICE
  • CISTPL_MANFID
  • CISTPL_VERS_1

If the CISTPL_VERS_1 tuple is not available or the manufacturer name is NULL, the string "UNKNOWN_MANUFACTURER" is used for the manufacturer name.

PCMCIA\UNKNOWN_MANUFACTURER_crc\instance

The total length of the device ID string is limited to 128 characters, including the null terminator. The manufacturer and product name are truncated, if necessary, to maintain this length restriction in the ID string.

The characters in the manufacturer and product name strings that are greater than or equal to a space (0x20) or less than (0x7F) will be copied into the name string. Any characters outside this range are skipped. This restriction makes it easier to include these characters in the .INF files for the device.


Dynamic Driver Loading During System Boot

Many Windows 95 driver models, such as IOS and the network driver models, support dynamically loaded device drivers. These VxDs are not loaded by the MS-DOS real mode loader. In the case of IOS, some drivers are true dynamically loaded VxDs, and others are mini-port SCSI drivers that are Windows NT/Windows 2000-binary compatible. IOS loads all drivers dynamically. The process used to load these drivers is identical to the process used to dynamically load the same drivers at run-time, except that the sequence of events that starts the load process is slightly different.

Dynamically loaded drivers are required to have a device loader. A device loader is responsible for loading the drivers at the correct time and in the correct order, and for making the proper initialization calls. In the case of SCSI adapter miniport drivers this device loader is IOS. A typical registry driver section for a SCSI adapter looks something like this:

Enum\ISAPNP\*ABC0507\0A35BF46
     DeviceDesc=ABC SCSI Vendor ISA Adapter
     Class="SCSIAdapter"
     Driver="SCSIAdapter\0000"
 System\CurrentControlSet\Services\Class\ScsiAdapter\0000
     DevLoader=*IOS
     MiniPortDriver=ABC.MPD

Since there is no StaticVxD=xxx line in this registry entry, the VMM32 real mode loader will do nothing when the ISAPNP enumerator identifies this device. IOS is a statically loaded base driver; it receives a Device_Init system control message. During this message, IOS calls Configuration Manager to load any drivers that have a DevLoader=IOS entry by calling CONFIGMG_Register_DevLoader with the following parameters:

CM_Register_DevLoader(IOS_DDB, 0);

From within this function, Configuration Manager walks the devnode tree and attempts to find any device node that has a DevLoader=IOS entry in the registry. In this example, it would find the ABC adapter. This causes Configuration Manager to call back to IOS with a system control call to load the driver.

DirectedSysControl("IOS", PNP_NEW_DEVNODE, DLVXD_LOAD_DEVLOADER, LoadDevNode)

IOS then examines the registry and finds the MiniPortDriver=ABC.MPT, loads the driver and any associated support drivers, initializes the adapter, and returns from the function.


Driver Callback Entry Point

A new callback entry point is the most significant Plug and Play work required for new device drivers. This entry point is used by Configuration Manager to assign configurations. For sample code showing this entry point, see Sample Plug and Play Driver.


VxD Initialization

Most VxDs simply call CM_Register_Device_Driver to get their configuration. The VxD's entry point must be able to respond to dynamic configuration calls, particularly CONFIG_START, CONFIG_STOP, CONFIG_TEST, and CONFIG_REMOVE.


Sample Plug and Play Driver

Drivers are informed about their device node through a system control call issued by Configuration Manger.

/*
  *  DRIVER.C - NewDriver Support for SAMPLE
  *  This file processes the Driver requests.
  */

 #include <basedef.h>
 #include <vmm.h>
 #include <debug.h>
 #include <configmg.h>
 #include <pnpdrvs.h>
 #include <misc.h>
 #include <driver.h>

 #pragma VxD_LOCKED_CODE_SEG

 IO_RESOURCE    Res1=
 {
  {2, IOType_Range, 0, 0, 0, 0, 0},
  {
     {0xFFFF, 1, 0x103, 0x103, 0, 0xFF, 0xFF},
     {0xFFFF, 1, 0x203, 0x203, 0, 0xFF, 0xFF},
  }
 };

 IO_RESOURCE    Res2=
 {
  {2, IOType_Range, 0, 0, 0, 0, 0},
  {
     {0x0300, 6, 0x200, 0x307, 0, 3, 3},
     {0x03F0, 4, 0x300, 0x313, 0, 3, 3},
  }
 };

 /*****************************************************************
  *
  *    ConfigHandler - Handler of the Configuration Manager
  *    configuration call
  *
  *    Exported.
  *
  *    ENTRY:    Standard config handler.
  *    EXIT:    Standard Configuration Manager return value.
  *
  ****************************************************************/
 CONFIGRET CM_HANDLER
 ConfigHandler(CONFIGFUNC cfFuncName, SUBCONFIGFUNC scfSubFuncName,
     DEVNODE dnToDevNode, DEVNODE dnAboutDevNode, ULONG ulFlags)
 {
     LOG_CONF    lc;
     RES_DES    rd;
     CONFIGRET    status;

     switch (cfFuncName) {

         case CONFIG_FILTER:

             // Get the first filtered logical configuration.

             status=CM_Get_First_Log_Conf(&lc,
                             dnAboutDevNode,
                             FILTERED_LOG_CONF);
             // For all logical configuration (we stopped when
             // the status is not CR_SUCCESS since it can only
             // become CR_NO_MORE_LOG_CONF).

             while (status==CR_SUCCESS) {

                 // For all resource descriptors

                 rd=(RES_DES)lc;
                 while (CM_Get_Next_Res_Des(&rd,
                                 rd,
                                 ResType_Mem,
                                 NULL, 0)==CR_SUCCESS) {

                     // For all memory resource
                     // (for instance) do some
                     // checking (like ISA impose
                     // <16Meg)
                 }

                 // Next logical configuration.

                 status=CM_Get_Next_Log_Conf(&lc,
                                 lc,
                                 0);

             }

             return(CR_SUCCESS);

         case CONFIG_START:

             // You may or may not treat CONFIG_START_FIRST_START
             // different from CONFIG_START_DYNAMIC_START.

             // As far as CM goes, the first time it would
             // have called with CONFIG_START_DYNAMIC_START;
             // it will call with CONFIG_START_FIRST_START
             // instead.

             return(CR_SUCCESS);

         case CONFIG_TEST:
             return(CR_SUCCESS);

         case CONFIG_STOP:
             return(CR_SUCCESS);

         case CONFIG_REMOVE:
             // deallocate per instance data.

             return(LeaveInstance(CR_SUCCESS));

         default:
             return(CR_DEFAULT);
     }
 }

 /*****************************************************************
  *
  *    NewDriver - Register a new driver for the new device node
  *
  *    Exported.
  *
  *    ENTRY: DevNode is the new device node that has just been created.
  *
  *    EXIT:  Standard Configuration Manager return value.
  *
  ****************************************************************/
 CONFIGRET CM_INTERNAL
 NewDriver(DEVNODE DevNode)
 {
     LOG_CONF    lc;
     RES_DES     rd1, rd2;

     // Any failure should use LeaveInstance to unload the DLVxD if
     // it is the only instance. Only if it is success will we not
     // return with an "OR"ed CR_UNLOAD.

     // BUGBUG error checking

     CM_Add_Empty_Log_Conf(&lc, DevNode, 0, BASIC_LOG_CONF);

     CM_Add_Res_Des(&rd1, lc, ResType_IO, &Res1, SIZEOF_IORANGE(2), 0);

     CM_Add_Res_Des(&rd2, lc, ResType_IO, &Res2, SIZEOF_IORANGE(2), 0);

     CM_Register_Device_Driver(DevNode, ConfigHandler, 0);

     // Allocate per instance data

     return(CR_SUCCESS);
 }


New Services in the VMM32 Real Mode Loader

Several new capabilities have been added to the real mode VxD loader. This section briefly discusses the services that have been added.


Parameters to Real Mode Initialization

New parameters to the real mode initialization portions of VxDs will be added to allow a driver to determine where in the registry it was loaded from (and therefore where to look for switch settings.) This mechanism is still under definition.


Registry Access

In Windows 95, several functions have been added both to the real-mode VxD loader and to the Virtual Machine Manager to allow VxDs full access to the registry during initialization and during normal run time. Many of the standard Win32 and 16-bit registry access functions are also supported.

In most cases, VxDs can write to the registry in protected mode. However, VxDs cannot write to the registry during the real-mode initialization phase, nor can they gain access to the HKEY_CURRENT_USER key until following the Init_Complete phase.


Passing a Block of Data to Protected Mode

The Windows Virtual Machine Manager versions 3.1 and later provides a Loader Services entry point. LoaderServices' 16:16 address is passed to a VxD's real-mode initialization routine in the ECX register to provide various services.

Windows 95 (that is, VMM version 4.0 and later, which is passed to the VxDs real-mode entry point in AX) provides a new service, LDRSRV_Copy_Extended_Memory, which allocates a block of extended memory in the specified data group (init, locked, or pageable) to the size requested and initializes the block with the given data.

Installation On Windows 95

The setup information contained in the .INF portion of the driver cross-references hardware IDs and drivers, so Setup can determine which piece of hardware a given driver corresponds to.

Hardware devices can list compatible IDs as part of their .INF portion, or in the PNP ISA case, the hardware can return the compatibility information directly as part of the device identification sequence. (Other enumeration schemes, such as PCMCIA, may also be able to return the compatible IDs directly from hardware interrogation.) For example, if a SVGA adapter is compatible with standard VGA, that can be specified as part of the .INF file. The same is true for drivers which implement a superset of a standard driver. At installation, setup will attempt to use the best match of hardware to software driver as the default choice.

Driver Setup Process

Assume that an enumerator identifies a new device. If the registry entry does not exist, Configuration Manager runs the device installer and calls back to the enumerator to ask for additional information. This additional information is for the use of the device installer and can include a device description and a list of compatible device IDs. For example, an SVGA card might return the generic Windows VGA or SVGA device IDs (PNP0900 and/or PNP0901 respectively). The device installer then searches .INF files to find any driver(s) that work on this device, and copies the appropriate information to the registry. When this process is complete, Configuration Manager continues with the device node as usual.

New PCMCIA Card Example

If the user inserts an XYZ PCMCIA card, the tuples allow the PCMCIA enumerator to determine a device ID of "PCMCIA\XYZ\0". If Configuration Manager does not find any registry entry for this card, it launches the device installer. The device installer would then ask the PCMCIA enumerator for additional information, such as compatible Device IDs. If no additional information was available, the device installer would then open all .INF files searching for matches of "PCMCIA\XYZ." It might find setup information in a file named XYZ.INF. Setup may optionally ask for user confirmation of the device identification at this point. The device installer would then update the registry with the appropriate information for the card (including the name of the driver to load). The driver would be dynamically loaded, and the device would be enabled.

New ISA P&P Sound Card Example

At boot time the ISAPNP enumerator might detect a card with the "ISAPNP\*FSC0407\28AF363" device ID. If Configuration Manager could not find an appropriate entry in the registry, it would launch the device installer after protected-mode startup. The device installer would ask ISAPNP for additional information about the new card. It might receive the following:

  • Description="Fred's Sound Card"
  • CompatIDs=*SBD0400 (Sound blaster)

Device installer might find a match of the compatible ID with an existing Sound Blaster driver and prompt the user as follows:

"You have installed a new Fred's Sound Card. Windows can make this
< device work, however if this device has an installation diskette, you
< should place it in drive A:"

The user would then put the disk supplied with the card in drive A, and choose a "Use setup diskette" button. The device installer might find an exact match of ID *FSC0407 in the file "FREDCARD.INF" and use this as the driver. The rest of the process proceeds as in "New PCMCIA Card Example."


Loader Services

These services are provided by the real-mode VxD loader.


LDRSRV_Copy_Extended_Memory

VOID LDRSRV_Copy_Extended_Memory()

Allocates a block of extended memory in the specified data group (init, locked, or pageable) to the size requested and initializes the block with the given data.

  • CY flag is clear and EAX contains the linear address of the memory block if the service is successful. CY is set if the allocation failed and no memory block is allocated
AX
0006h, the function number for this service.
CX
Number of bytes to allocate.
DX
Type of data being allocated. It can be one of the following values:
Value | Meaning
LDRSRV_COPY_INIT | INIT data
LDRSRV_COPY_LOCKED | LOCKED data
LDRSRV_COPY_PAGEABLE | PAGEABLE data

DS:SI
Address of data to be copied.

This service is provided by the real-mode VxD loader. It provides a convenient way for a VxD to pass more than a single DWORD of data to their protected-mode portions. The VxD can simply create a block of extended memory and pass its linear address through the VxD reference DWORD (that is, the value of EDX on exit from real-mode initialization).

Actual sizes of blocks are always rounded up to the nearest DWORD. Multiple blocks allocated by a single VxD are guaranteed to be contiguous in linear address space, but not necessarily in physical address space.

PAGEABLE data may actually be allocated as LOCKED data, at the loader's discretion. Initialization (INIT) data is always locked, and is discarded after all VxD initialization phases are completed.


Windows 95 Registry Services and Real-Mode Registry Functions

The registry services give virtual devices access to the keys and values of the Windows 95 registry. This section describes the registry services and explains how to use them in your virtual devices to retrieve and set values in the Windows 95 registry. This section does not describe the registry keys and values that are used to support hardware devices in Windows 95. For more information about device registry keys and values, see .


Root Keys, Subkeys, and Values

The registry consists of a hierarchically arranged set of keys. Each key has a name and can have associated subkeys and values. A key represents a branch in the registry hierarchy. A root key is a predefined value that identifies a topmost branch in the registry hierarchy. For example, the HKEY_LOCAL_MACHINE key identifies the branch that contains hardware and software information about the given computer. The keys and values you access are always within a branch of a root key.

To access keys and values in the registry you must open a key. Opening a key creates a handle that you can use to open other keys or to examine and set values. The predefined root keys are always considered to be open.

You can create new keys and new values in any open key. Each value has a corresponding value name and data type. The value name identifies the value and the data type specifies the format of the data, whether a null-terminated string (REG_SZ) or binary data (REG_BINARY). Other values such as REG_DWORD are valid as well, although internally any value that is not REG_SZ is treated as REG_BINARY. Any You can also delete keys and values, but you cannot delete the root keys.


Registry Services

Virtual devices can open, read, write, create, and delete registry keys and values using the registry services provide by the VMM. There are these registry services:

_GetRegistryKey

_GetRegistryPath

_RegCloseKey

_RegCreateKey

_RegDeleteKey

_RegDeleteValue

_RegEnumKey

_RegEnumValue

_RegFlushKey

_RegOpenKey

_RegQueryValue

_RegQueryValueEx

_RegSetValue

_RegSetValueEx

During the protected-mode initialization phases, the registry may be written to but the data will not be flushed to disk until the end of the Device_Init phase. Until the end of this phase, virtual devices may only access the HKEY_LOCAL_MACHINE key. No other predefined keys are available.

The registry services can be called from either assembly-language or C-language source in a VxD. To call the registry from a Ring 3 driver or application, refer to the SDK documentation for Win32 registry services. Assembly-language calls have this form:

include vmmreg.inc

< VMMCall _RegCloseKey    <phKey>
< cmp     eax,ERROR_SUCCESS
< jnz     CreateFail

C-language calls have this from:

include <vmmreg.h>

< if (VMM_RegCloseKey(phKey) != ERROR_SUCCESS) {
<     MyErrorHandler("RegCloseKey Failed");
< }


Real-mode Registry Functions

Static virtual devices can open and retrieve values from the registry during real-mode initialization. During this time, the registry is read-only and only the keys and values under the HKEY_LOCAL_MACHINE key are accessible. Virtual devices call these functions by filling registers and calling the loader services function or by using one of these real-mode registry function macros:

LDR_RegCloseKey

LDR_RegEnumKey

LDR_RegEnumValue

LDR_RegOpenKey

LDR_RegQueryValue

LDR_RegQueryValueEx


Device Registry Keys and Values

Windows 95 uses the registry to store information that identifies detected or enumerated devices and the device drivers that support them. The system relies on this information to reliably allocate resources for "legacy" devices (those without Plug and Play circuitry) and to install appropriate device drivers and other supporting components.

This section describes the registry keys and values used to support devices and device drivers. However, it does not describe how to access these keys and values. For more information about accessing the registry, see the .


Root Keys and Branches

Windows 95 stores information about devices and device drivers in the branches of the HKEY_LOCAL_MACHINE key (sometimes abbreviated HLM). Initially, the system creates this information during system setup in response to detecting or enumerating a device. The setup utility copies information about the given device or a compatible device from a matching .INF file to the registry. The INF file provides the instructions needed to add resource requirements, driver-specific data, and switch settings to the appropriate branches of the registry.

The HLM\ENUM branch contains information about all the devices that are presently and were previously installed in the system. The system uses this branch during system startup to retrieve information about enumerated devices. If the system cannot find information about the device in this branch, it assumes that new hardware has been installed and automatically invokes the device installer to create the necessary entries and to install the drivers. Information remains in this branch, even if the corresponding device is removed, so that the necessary information is present if the device is reinstalled.

The HLM\CONFIG branch contains information about hardware profiles. A hardware profile is a set of information that defines the hardware present in the system. Hardware profiles are typically used in docking systems in which the number and type of devices may be different with each docking station. The typical docking system has one hardware profile for each docking station and one for when it is not docked.

The HLM\SYSTEM branch contains detailed information about the available devices and their current configuration. This includes information about each class of device as well as individual devices.

Unlike Windows NT/Windows 2000, Windows 95 does not use the HLM\HARDWARE branch to store device information. Instead, Windows 95 leaves this branch empty.

Windows 95 uses the HLM\SOFTWARE branch to store information about applications and system components. It is recommend that all applications, including those that provide support for device drivers, use this branch to store version-specific information. Each application should store information under its own subkey. The subkey should have this general form: SOFTWARE\manufacturer\product\version.

Windows 95 also stores information in the branches of the HKEY_USERS key. While Windows 95 is not currently expected to be a true-multiuser system, this key and the associated key HKEY_CURRENT_USER key (sometimes abbreviated HCU) are available so that applications may take advantage of future enhancements. Currently, the HKEY_CURRENT_USER key maps to a single default user branch under HKEY_USERS, but eventually it will map to the user's login name, giving applications the ability to store user-specific profile information on a network server and letting users work at multiple workstations without requiring them to maintain multiple profiles. In general, applications should store user-specific information under HCU\SOFTWARE rather than under HLM\SOFTWARE.


HKEY_LOCAL_MACHINE

The HKEY_LOCAL_MACHINE branch contains all device information relevant to the given machine, including information about devices found by detection modules during system setup, devices enumerated by Plug and Play enumerators, and devices manually identified by the user.

The following keys identify branches of HKEY_LOCAL_MACHINE that contain device information.

CONFIG\profile | Contains configuration information for a specific hardware profile. The profile subkey is a 4-digit, hexadecimal number identifying a specific hardware profile. Although the CONFIG branch is in HKEY_LOCAL_MACHINE, the predefined key HKEY_CURRENT_CONFIG can also be used to open the branch.
CONFIG\profile\ENUM\ROOT\device-id\instance-number | Contains configuration information for a specific legacy device for a specific hardware profile. The profile subkey is a 4-digit, hexadecimal number identifying a specific hardware profile. The device-id and instance-number specify the device's ID and an instance number that uniquely identifies the device. This branch may contain an CSConfigFlags value, which is a bitmapped field defined as follows:
 | Bit 0: Device is disabled
 | Bit 1: Device is removed
 | Bit 2: Do Not Start
ENUM | Contains information for all legacy, Plug and Play, and user-installed devices. Initially, this branch receives subkeys and values during system setup. Setup records information for each device found by hardware detection modules in the ROOT branch, Plug and Play enumerators record information about devices stored by that enumerator in another enumerator specific branch as described in the following.
ENUM\enumerator | Contains a permanent record of all hardware that has been installed, whether currently present or not. The information includes the list of devices, their resource requirements, and driver bindings. The enumerator subkey uniquely identifies an enumerator; there is one subkey for each Plug and Play enumerator installed in the system.
ENUM\ROOT | Contains information for all detected legacy devices. Because it is not possible to redetect all existing legacy devices each time the system starts, the root enumerator uses this information to load the drivers for this hardware. If ENUM\ROOT identifies a device, the system loads the corresponding driver. It is the responsibility of the driver to unload itself if the device is not available.
ENUM\enumerator\device-id\instance | Contains device-specific information. The enumerator uniquely identifies the enumerator associated with the device. The device-id is the device identifier for the device, and instance is a string that uniquely identifies a particular instance of this device. This branch contains values such as DeviceDesc, Class, CompatibleIDs, and Driver.
ENUM\ROOT\device-id\device-number | Contains information for a specific legacy device. The device-id is the device identifier for the device and and device-number is a 4-digit, hexadecimal number that uniquely identifies an instance of that device. This branch contains values such as DeviceDesc, Class, CompatibleIDs, BootConfig, and Driver.
ENUM\ROOT\device-id\device-number\LogConfig | Contains logical configuration information for a legacy device. The device-id is the device identifier for the device and and device-number is a 4-digit, hexadecimal number that uniquely identifies an instance of that device.
 | This branch contains one or more binary values that contain the configuration information. The name for each value is a decimal digit.
SOFTWARE\vendor-name\product-name\version | Contains information about the given version of an given application. The vendor-name must be a unique name identifying the manufacturer. The product-name also must uniquely identify the application. The version identifies the given version of the application or can be CurrentVersion to indicate the most recent current version if multiple versions are on the system. This branch contains zero or more application-specific subkeys and values.
SYSTEM\CurrentControlSet\Control\IDCONFIGDB | Identifies the hardware profile database. This branch contains one or more keys that identify instances of hardware-profile information. This branch contains values such as CurrentConfig, FriendlyNamexxxx, and Map.
SYSTEM\CurrentControlSet\Services\Class | Contains information about detected or enumerated hardware. This branch contains zero or more subkeys. Each corresponds to the registry-path given in the Driver value of a corresponding ENUM\enumerator\device-id\instance or ENUM\ROOT\device-id\instance branch.
SYSTEM\CurrentControlSet\Services\Class\device-class | Contains information about a specific device class. The device-class is the unlocalized name for the class. This branch contains values such as Installer, Icon, and EnumPropPages. This branch also contains an unnamed value that specifies the localized name of the class to present to the user during device installation.
SYSTEM\CurrentControlSet\Services\Class\device-class\instance | Contains information about a specific device within the given class. The device-class is the class name; the instance is a 4-digit, hexadecimal number. This branch contains values such as DriverDesc, DevLoader, and Enumerator.
SYSTEM\CurrentControlSet\Services\VxD | Contains information about static virtual devices, that is, virtual devices that are loaded with the system rather than dynamically loaded. This branch is used to identify virtual devices, such CONFIGMG, that are not associated with a specific device. This branch supersedes the corresponding entries in the [386Enh] section of the SYSTEM.INI file. To avoid loading duplicate virtual devices, Windows 95 loads all virtual devices identified in this branch first, then loads virtual devices from SYSTEM.INI, giving preference to virtual devices loaded from the registry. This guarantees that new drivers specified in this branch take precedence over old drivers specified in SYSTEM.INI.
SYSTEM\CurrentControlSet\Services\VxD\device-class | Contains information about drivers and other system components that do not necessarily have corresponding devices. The device-class is the class name of the virtual device. This branch contains values such as Start and StaticVxD.


Reference

This section describes the values used in the various registry branches to support device drivers.


BootConfig

BootConfig=binary-data

Identifies the boot configuration for a device. The binary-data is configuration data, in binary format, that specifies the IRQ, I/O ports, and other resources used by this device.

This value is used in HLM\ENUM\ROOT\device-id\instance.


Class

Class=string

Identifies the name of the device class. The string can be any character string.

This value is used in HLM\ENUM\enumerator\device-id\instance and HLM\ENUM\ROOT\device-id\instance.


CompatibleIDs

CompatibleIDs=device-id

Identifies a list of compatible device IDs for a device that can be used for purposes of loading a default driver when a specific one from the vendor is not available. The device-id is a multiple-string value that specifies one or more valid device identifiers.

This value is used in HLM\ENUM\enumerator\device-id\instance and HLM\ENUM\ROOT\device-id\instance.


CurrentConfig

CurrentConfig=profile

Identifies the current hardware profile. The profile is a 4-digit, hexadecimal number that corresponds to one of the profile keys in the IDCONFIGDB branch. The system sets this number when it starts or when the user docks, undocks, or forces a switch between hardware profiles by using the docking control panel.

This value is used in HLM\SYSTEM\CurrentControlSet\Control\IDCONFIGDB.


DeviceDesc

DeviceDesc=string

Identifies the localized name of the device. This name is typically presented to the user when the device is installed. The string can be any character string.

This value is used in HLM\ENUM\enumerator\device-id\instance and HLM\ENUM\ROOT\device-id\instance.


DevLoader

DevLoader=name

Identifies the device loader associated with this device. The name is the file name of the virtual device that serves as the device loader.

This value is used in the appropriate subbranch of HLM\SYSTEM\ CurrentControlSet\Services\Class.


Driver

Driver=registry-path

Identifies the branch (under the SYSTEM\CurrentControlSet\Service\Class branch) that contains information about the device driver to load for the new device. The registry-path is a subkey that typically consists of a class name and a 4-digit, hexadecimal, device-instance number.

This value is used in HLM\ENUM\enumerator\device-id\instance and HLM\ENUM\ROOT\device-id\instance.


DriverDesc

DriverDesc=string

Identifies the localized name of the device driver. This name is typically presented to the user when the driver is installed. The string can be any character string.

This value is used in HLM\SYSTEM\CurrentControlSet\Services\Class\device-class.


Enumerator

Enumerator=name

Identifies the enumerator associated with this device. The name is the filename of the virtual device that serves as the enumerator.

This value is used in HLM\SYSTEM\CurrentControlSet\Services\Class\device-class.


EnumPropPages

EnumPropPages=module-and-entry-point-name

Specifies the name of the property page handling function for this device class. The module-and-entry-point-name is a character string that specifies the name of the dynamic-link library containing the handler and optionally the exported name of the handler. If the name of the function is given, it is given after the DLL name and is preceded by a comma.

This value is used in HLM\SYSTEM\CurrentControlSet\Services\Class\device-class.


FriendlyName

FriendlyName number=string

Specifies a user-defined name for the given hardware profile. The number is a 4-digit, hexadecimal value identifying the hardware profile. The string can be any null-terminated string.

This value is used in SYSTEM\CurrentControlSet\Control\IDCONFIGDB.


Icon

Icon=number

Identifies the icon used to represent the class installer in the control panel. The number is a string representing a signed, decimal number.

This value is used in HLM\SYSTEM\CurrentControlSet\Services\Class\device-class.


Installer

Installer=module[,entry point]

Specifies the name of the class installer for this device class. The module-and-entry-point-name is a character string that specifies the name of the dynamic-link library containing the installation function and optionally the exported name of the installation function. If the name of the function is given, it is given after the DLL name and is preceded by a comma.

This value is used in HLM\SYSTEM\CurrentControlSet\Services\Class\device-class.


MAP

MAP=binary-data

Specifies the ID-to-Hardware-Profile mapping for a system. The binary-data is an array of dock-serial/hardware-checksum tuples and hardware profile identifiers, given as a single binary value.

This value is used in HLM\SYSTEM\CurrentControlSet\Control\IDCONFIGDB.


Start

Start=value

Currently this value is ignored. The system always loads the given virtual device.

Indicates whether the given virtual device should be started. If value is 0, the system loads the virtual device identified by the StaticVxD value in the same branch. If value is 4, the system does not load the given virtual device. If the Start value is not present in a branch, its value is assumed to be 0.

This value is in HLM\SYSTEM\CurrentControlSet\Services\VxD\device-class.


StaticVxD

StaticVxD=name

Identifies a static virtual device. The name is a string specifying the name of a static virtual device, that is, one loaded with the system rather than dynamically loaded. Such names typically start with an asterisk (*). This value replaces the corresponding DEVICE entry in the [386Enh] section of the SYSTEM.INI file.

This value is used in HLM\SYSTEM\CurrentControlSet\Services\VxD\device-class.


Windows 95 Dynamic Registry Keys

The Registry has become the central repository for all the configuration information in the Microsoft 32 bit operating systems. Both Windows NT/Windows 2000 and Windows 95 store configuration information for hardware and software components in the registry.

The Windows 95 registry supports both static data and dynamic data. A static value is one that is actually stored within the registry on disk. Dynamic data is data that changes very often, such as performance data. It is not practical to store such data in the registry; it would obviously not be a good idea for the system to continually update the registry with current values. Thus, a different mechanism was designed to support dynamic data.

Note Windows NT 3.5 supports dynamic data differently than Windows 95. Windows NT 3.5 uses Volatile keys, which Windows 95 does not support.

Dynamic keys were introduced in Windows 95 to handle dynamic registry data. Rather than storing the actual values, the registry stores a pointer to a function that returns a value or values. When a registry call is made to query a value or values associated with a dynamic key, that function is called to return the desired value(s). From the point of view of the consumer of registry data (the caller of the registry API's), dynamic keys appear and behave like any other keys in registry name space (except that they are read-only).


Overview

Each dynamic key has a provider (also called handler) associated with it. A provider is a piece of code that, when requested by the OS registry code, provides one or more values that are associated with that dynamic key. Windows 95 supports only VxD providers. Future versions of Windows will support Win32 providers as well. Windows NT/Windows 2000 does not support either VxD or Win32 dynamic key providers, but will in future versions. The ring 0 for Windows NT/Windows 2000 will be different than the Windows 95 VxD interface. However, the Win32 interface should be the same for future versions of Windows 95 and Windows NT/Windows 2000.

Note This documentation describes only the Windows 95 VxD interface for dynamic keys.

Following are some issues that implementors of dynamic keys should be aware of:

  • All dynamic keys are stored under the HKEY_DYN_DATA registry hive. Thus, all child keys of dynamic keys must also be dynamic.
  • Dynamic keys are not restored across boots. If HKEY_DYN_DATA is unloaded, all dynamic keys in it are deleted.
  • One provider manages all of the values under one dynamic key.
  • One provider can manage multiple dynamic keys.
  • Values of a dynamic key cannot be added or deleted dynamically. In order to add (or delete) values from a dynamic key, the key must be deleted and recreated with the new set of values.
  • The value lengths can be maintained either by the provider or by the registry code. If the value lengths are maintained by the system Registry code, they need to be passed into the system when the key is created.
  • Dynamic keys are typically created by the VxD provider at VxD initialization time. They cannot be created until Init_Complete.

A single provider handles multiple keys and/or values via the notion of a context. A context is just a 32-bit value that is meaningful only to the provider; the system registry code never tries to evaluate it. When the provider is called, it can examine the key context that was passed in to determine which key is being queried, and the value context to figure out which value is being queried. Thus the key context is only necessary when one provider function is handling multiple dynamic keys. Likewise, the value context is only needed when the same provider function is handling a key or keys with multiple values.

There is an additional Win32 registry API that has been defined in Windows 95, in part to support dynamic keys, called RegQueryMultipleValues. This allows an application to atomically query multiple values of one registry key. Please consult the Win32 documentation for more information about this API.


RegCreateDynamicKey

When a component wants to add a dynamic key to the Registry namespace, it calls the RegCreateDynamicKey VxD service.

Notes

  • Dynamic keys are like volatile keys in that they disappear when the hive they are in is unloaded
  • Providers have no knowledge of the sub-keys under their dynamic keys. They just provide data for their key/values
  • RegNotifyChangeKeyValue will return ERROR_NOT_SUPPORTED when called against a dynamic key
  • For dynamic keys, the lastWriteTime parameter in RegQueryInfoKey returns the time when the key was created


Sample Code

In this example, the provider handles one dynamic key, under which there are 2 values. This provider will handle both values. The provider is keeping track of the value lengths instead of the registry. Note there is a static number (2) of values under this dynamic key. If the number of values under a dynamic key will change, then the key must be deleted and readded in order to do so.

The path of the dynamic key in this example is HKEY_DYN_DATA\Keyname1\Keyname2. There are two values under this key. One value is called "First Valuename", and the other is called "Second Valuename".

  /*****************************************************************************
  *
  *   (C) Copyright MICROSOFT Corp., 1994-1995
  *
  *****************************************************************************/

 #include <vmm.h>
 #include <vxdwraps.h>
 #include <vmmreg.h>

 #define MODULE_NAME "Dynamic Keys example"
 #define LEN 100
 #define DYNKEY_PATH        "Keyname1\\Keyname2"
 // This path is passed to RegCreateDynKey.
 // The registry will create Keyname1 (if it does not exist) and Keyname2; the provider
 // will only be queried for values under Keyname2.

 #define REGVAL_DATA1  "First Valuename"
 #define REGVAL_DATA2  "Second Valuename"

 #pragma VxD_PAGEABLE_CODE_SEG
 #pragma VxD_PAGEABLE_DATA_SEG

 // Structure for registry value context pointers.
 // This allows quick return of data for our dynamic registry key.
 // NOTE: This structure is being used as the value context because this sample has values
 // with varying lengths. If this were not the case,
 // PROVIDER_KEEPS_VALUE_LENGTH could be set, and the value pointer
 // itself used as the value context.
 typedef struct
 {
     PVOID pData;    // Pointer to the data
     PUINT pcbData;  // Pointer to the size of the data
 } REGVAL_CONTEXT, *PREGVAL_CONTEXT;

 DWORD fData1;
 DWORD cbfData1 = sizeof(fData1);
 char szData2[LEN + 1];
 unsigned cbData2;

 // Assign values to data1 and data2. These are of course not normally static
 // values - they would change dynamically. However, they are being set here in
 // order to complete this example.
 fData1= 100;
 szData2 = "This is the string for the second value";

 // declarations used below
 const REGVAL_CONTEXT rvcData1 = {&fData1, &cbfData1};
 const REGVAL_CONTEXT rvcData2 = {szData2, &cbData2};

 // RegKeyHandler - The handler function that must be defined in your VxD
 VMMREGRET __cdecl
 RegKeyHandler(
     PVOID pvKeyContext,
     PVALCONTEXT pValueContext,
     DWORD cValueContext,
     PBYTE pbBuffer,
     DWORD *pcbBuffer,
     DWORD fFlags)
 {
     VMMREGRET status = 0;
     PVALCONTEXT pvcCurrent;
     DWORD cbBufRemaining;

     // Save the input buffer size and initialize the return buffer size
     assert(pcbBuffer != NULL);
     cbBufRemaining = *pcbBuffer;
     *pcbBuffer = 0;

     // Since this function handles only one key, the key context is unused
     assert(pvKeyContext == NULL);

     // Walk the list of requested values, filling them in the buffer if
     // there's room.
     for (pvcCurrent = pValueContext;
          cValueContext > 0;
          pvcCurrent++, cValueContext--)
     {
         PREGVAL_CONTEXT prvcCurrent = pvcCurrent->value_context;
         pvcCurrent->valuelen = *prvcCurrent->pcbData;

         if (cbBufRemaining >= (DWORD) pvcCurrent->valuelen)
         { // value fits, copy it in
             memcpy(pbBuffer, prvcCurrent->pData, pvcCurrent->valuelen);

             *pcbBuffer += pvcCurrent->valuelen;
             pvcCurrent->val_buff_ptr = pbBuffer;

             ((PBYTE) pbBuffer) += pvcCurrent->valuelen;
             cbBufRemaining -= pvcCurrent->valuelen;
         }
         else
         {
             pvcCurrent->val_buff_ptr = NULL;
             status = ERROR_MORE_DATA;
         }
     }

     return status;
 }

 // *** Init code and data is below here ***
 #pragma VxD_INIT_CODE_SEG
 #pragma VxD_INIT_DATA_SEG

 // This structure is used as the 3rd parameter to RegCreateDynKey
 struct provider_info RegKeyHandlerInfo =
 {
     RegKeyHandler,   // pointer to the VxD handler function for query of one value
     RegKeyHandler,   // pointer to the VxD handler function for query of multiple values
     NULL,    // Should be NULL for Win95; reserved for future pointer to Win32 handler fn
     NULL,    // Should be NULL for Win95; reserved for future pointer to Win32 handler fn
     PROVIDER_KEEPS_VALUE_LENGTH,
       // Provider will keep track of value lengths
     NULL    // Key context; not used in this example since handler only manages 1 key
 };

 // A Pvalue struct that is passed as 4th parameter to RegCreateDynKey
 PVALUE RegKeyValueInfo[] =
 {
     {REGVAL_DATA1,    sizeof(DWORD),  (PVOID) &rvcData1,   REG_BINARY},
     {REGVAL_DATA2,   0, (PVOID) &rvcData2,  REG_SZ},
 };

 #define RegKeyValueCount (sizeof(RegKeyValueInfo) / sizeof(*RegKeyValueInfo))

 int __stdcall
 CreateDynamicKey(void)
 {

     // Note:  We never delete the key
     VMMHKEY hkeyDynamicConfig;
     int uStatus;

     cbData2 = strlen(szData2) + 1;
     if (uStatus = _RegCreateDynKey(DYNKEY_PATH,
                                    NULL,    // No key context is needed
                                    &RegKeyHandlerInfo,
                                    RegKeyValueInfo,
                                    RegKeyValueCount,
                                    &hkeyDynamicConfig))
     {
 #ifdef DEBUG
         Out_Debug_String(MODULE_NAME
                          ": Cannot create dynamic registry key "
                          DYNKEY_PATH
                          "\r\n");
 #endif

         return uStatus;
     }

     // We're never going to use this key, so we can close it
     // BUG - The dyn-key code relies on this being kept open, so we leave it open
     //_RegCloseKey(hkeyDynamicConfig);

     return 0;
 }


Plug and Play Scenarios

This section describes the scenarios that involve the Plug and Play components. Two scenarios are described: the Windows 95 system boot process and the handling of device insertion/removal while the system is running.


Boot Process

The boot process has several distinct steps, each of which provides different services, driver models, and requirements.

The full Windows 95 boot sequence can be broken down as

  1. BIOS Bootstrap
  2. MS-DOS Configuration Management Pre-Config.Sys
  3. Process Config.Sys and Autoexec.Bat
  4. VMM32 Real Mode Loader
  5. Pre-Sys_Critical_Init Processing
  6. VxD Initialization
  7. Windows GUI Driver Initialization
  8. (Post-boot) Dynamic Events


BIOS Bootstrap

Microsoft has worked with several OEMs to define a new Plug and Play BIOS specification. This specification discusses the interactions between a Plug and Play BIOS and Plug and Play devices and option ROMs.


MS-DOS Configuration Management Pre-CONFIG.SYS

The following sections describe the configuration management carried out during early initialization of the operating system and before the statements of the CONFIG.SYS file are processed.


Hardware Profile Detection

Hardware profile detection determines the computer's hardware profile. Although most desktop computers will have only one hardware profile, dockable portables typically have one hardware profile for the undocked state and another for each dock to which they connect.

Hardware profile detection runs before the CONFIG.SYS file is executed during MS-DOS startup. Hardware profile detection combines interrupt checksums, BIOS COM/LPT data, BIOS machine identification data, Plug and Play BIOS Docking Station data, and, if possible, docking station data which is unique to each OEM and builds a 2 byte value known as the current hardware profile (or the current configuration).

Each hardware profile has a "friendly name." If the current hardware profile's friendly name exactly matches a top-level menu item in a multi-configured CONFIG.SYS file, that menu item or submenu is automatically selected.

The registry uses the current hardware profile to point the predefined key HKEY_CURRENT_CONFIG to the correct location (subsidiary to the predefined key HKEY_LOCAL_MACHINE). For example, if the current hardware profile were 0x5107, HKEY_CURRENT_CONFIG would be initialized to HKEY_LOCAL_MACHINE\CONFIG\5107.


Select Appropriate Boot Configuration

Windows 95 expands on the MS-DOS 6.0 ability to allow multiple-configuration boots. Windows 95 allows Windows applications and drivers to be configuration-aware. By examining a DockSerialID returned by a Plug and Play BIOS, the system will attempt to automatically determine the appropriate state to boot the system in. If the appropriate state can not be determined, the user will be prompted to select the correct state from several configurations with the same DockSerialID. If a new DockSerialID is generated that the user has not had before (for example, if the user plugs into a new docking station in a friend's office), the user is asked to run full-scale hardware detection and associate a friendly name (for example, "Docked in Jane's office,") with the new DockSerialID.


Processing CONFIG.SYS and AUTOEXEC.BAT

In Windows 95, CONFIG.SYS and AUTOEXEC.BAT are processed similarly to the way they are processed under MS-DOS 6.x. MS-DOS drivers and TSRs are loaded in real mode. Any hardware drivers that load at this point should use the MS-DOS configuration management services to determine how their hardware has been configured.

The difference between the Windows 95 implementation and the process with MS-DOS 6.0 is that the system attempts to calculate the current configuration if the computer is a docking system. A hardware profile is selected before CONFIG.SYS is processed. If the "friendly name" of the hardware profile matches a multi-configuration menu item name (that is, the long text in the menu, not the section name enclosed in square brackets), the system automatically selects that multi-configuration menu item and automatically process the corresponding section of CONFIG.SYS.

For more information about hardware profiles, see Hardware Profile Detection.


VMM32 Real Mode Loader

All VxDs were loaded under Windows 3.x by the real-mode VxD loader. Windows 95 supports both dynamically loaded drivers and static VxDs. Static VxDs can have a real-mode initialization portion.

Windows 95 has added several new capabilities for statically loaded VxDs:

  • Access to the registry
  • Ability to enumerate devices
  • Can pass a block of data from real mode to protected mode
  • VxDs can be loaded from the registry

The VMM32 loader loads VxDs in three distinct steps

  1. Base drivers specified in the registry
  2. Static VxDs for devices enumerated by other VxDs
  3. Static VxDs specified in SYSTEM.INI


Loading Base Drivers Specified in the Registry

VMM32 examines the registry branch SYSTEM\CurrentControlSet\Services\VxD and enumerates all keys under this branch. ("Enumerate" here refers to the enumeration of registry keys, not to Plug and Play enumeration.) If it finds a value "StaticVxD=", it will load that static VxD and execute its real mode initialization portion. For example:

SYSTEM\CurrentControlSet\Services\VxD\V86MemoryManger
         Description=MS-DOS Virtual 8086 Memory Manager
         Manufacturer=Microsoft
         StaticVxD=*V86MMGR
         Start=0
         EMMEXCLUDE=E000-EFFF
 SYSTEM\CurrentControlSet\Services\VxD\ConfigMG
         Description=Plug and Play Configuration Manager
         Manufacturer=Microsoft
         StaticVxD=*CONFIGMG
         Start=0
 SYSTEM\CurrentControlSet\Services\VxD\IOServices
         Description=IO Services Driver Version 4.0
         Manufacturer=Microsoft
         StaticVxD=*IOS
         Start=0

Entries exist in this section of the registry for every VxD that is not directly associated with any hardware. These drivers used to be specified under [386ENH] in SYSTEM.INI. Examples of these devices are DOSMGR, V86MMGR, Reboot, VMPoll, and BiosXlat.

Device specific information can be stored in the registry under the same key as the driver. In the preceding example, the V86MemoryManager key contains the value EMMEXCLUDE=E000-EFFF, which is a setting specific to the V86MMGR VxD. Any other VxD-specific information can be grouped with the driver it is associated with in the same way. VxDs can use the VMM services _GetRegistryKey or _GetRegistryPath to discern the location from which they were loaded, and then use this information to read any associated values. Although loading VxDs from SYSTEM.INI (and the associated ReadProfileString and WriteProfileString functions) will still be supported for compatibility with older drivers and setup programs, driver writers are encouraged to use this location and load method for new VxDs and associated switch settings.


Real Mode Enumeration

Most driver writers will not write enumerators. However, most drivers will be loaded as the result of an enumerator identifying a hardware device. Enumerators are also responsible for configuring devices on the relevant bus.

The following sections discuss some specific enumerators.

Root Enumerator

The root enumerator is part of Configuration Manager. This enumerator contains no special detection logic and relies on the registry to determine whether a device exists. If there is an entry in the registry, the root enumerator assumes that it exists and the appropriate drivers are loaded. This is the method by which old hardware is supported, since it is usually impossible to determine with complete accuracy and safety that a particular ISA card is installed.

BIOS Enumerator

The BIOS enumerator is responsible for identifying all hardware devices on the motherboard of the computer. The BIOS enumerator supports the Plug and Play BIOS API which allows all Plug and Play computers to be queried in a common manner.

ISAPNP Enumerator

This enumerator uses the ISA Plug and Play card detection mechanism to detect with complete accuracy and safety any ISA Plug and Play-compliant cards in the system.

PCI Enumerator

This enumerator uses the PCI BIOS and the PCI device configuration space to detect and configure any PCI-compliant cards in the system.

PCMCIA Enumerator

This enumerator uses a Socket Services driver to determine whether a PCMCIA cards is inserted in each socket in the system, and for those which are present, the tuple space of the card is read to identify which card is inserted and what resources are required.

EISA Enumerator

This enumerator queries the EISA CMOS to discern which EISA devices are installed and what resources they consume. This enumerator will not reconfigure EISA devices.

COM Enumerator

This enumerator follows the Plug & Play COM specification for identifying compliant devices attached to a serial port.

LPT Enumerator

This enumerator uses the IEEE P1284 specification for identifying devices attached to P1284-capable parallel ports.


VxDs Loaded from [386ENH] Section of SYSTEM.INI

In Windows 3.x, all VxDs are loaded from the [386ENH] section of SYSTEM.INI. Windows 95 has moved most VxD loading to the registry, in order to better encapsulate driver-specific information and to enable driver loading from automated device enumeration. However, once all drivers have been loaded from the registry, any "device=" lines in SYSTEM.INI will be executed unless the device specified conflicts with a device loaded from the registry. In the case of a conflict, the device specified in the registry takes precedence and the device specified in SYSTEM.INI will not be loaded.


Processing Before Sys_Critical_Init Message

The devnode tree is constructed after entering protected mode, and after VXDLDR.VXD's early Device_Init. (VXDLDR is very early in the load order.) The root enumerator (which is part of Configuration Manager) creates device nodes for every device it can enumerate. Any static VxD that was loaded for a given device node is then sent a system control call with the following parameters:

EAX = PNP_NEW_DEVNODE
 EBX = DEVNODE
 EDX = LOAD_DLVXD_DEVLOADER

At this point, most VxDs return CR_DEVLOADER_NOT_READY. When a static VxD reaches the device initialization stage, it should call the CONFIGMG_Register_DevLoader function. The system will make another PNP_NEW_DEVNODE system control call, at which point the VxD can load the device driver or enumerator. (Often, the device driver and enumerator are in the same binary file, as in the case of ISAPNP.386.) A typical driver must call CONFIGMG_Register_Device_Driver, and an enumerator must additionally call CONFIGMG_Register_Enumerator. Some VxDs will also register arbitrators at this point, using the CONFIGMG_Register_Arbitrator function. Arbitrators should be loaded at SYS_CRITICAL_INIT if they are global.

Configuration Manager will then call any enumerator that has been registered to further enumerate devices. All devices that were enumerated in real mode will have been allocated a complete device node by the end of this process, and any VxD that was loaded for a particular device will have been notified through the new Plug and Play system control call.

Once all device nodes have been created, Configuration Manager will assign resources to each device and call the driver entry point to inform it of its new configuration.


Example

Plug and Play processing early in the system's entry to protected mode might follow a series of steps like this

  • Configuration Manager initializes, creates root device node.
  • Enumerates children, creates device node for PnP BIOS.
  • Notifies BIOSENUM VxD that its device node exists.
  • DirectedSysCtrl("BIOSENUM", PNP_NEW_DEVNODE, STATIC_DRIVER, DevNodeHandle)
  • BIOSENUM registers as enumerator.
  • Configuration Manager calls BIOSENUM to enumerate. It creates device nodes and the process continues.


Run-Time Processing

The following sections describe various run-time or dynamic events and features that may be useful to plug and play drivers.


Application Time "Appy Time" Processing

A dynamic hardware event can cause many configuration changes. For example, if the user inserts a PCMCIA card that is a SCSI interface, then I/O, IRQ, and DMA resources need to be allocated, drivers need to be loaded, and the SCSI drives need to be enumerated.

Although the event that starts this process is triggered by a hardware interrupt to the PCMCIA socket driver, the remainder of the processing needs to take place when the file system can be accessed, memory can be allocated, and so on. The Windows 95 SHELL VxD has implemented a set of services that allow this processing to be deferred, to a point termed "application time."

Code that runs at application time is essentially a subroutine executed on behalf of a Windows application. At application time, code can be unlocked, memory can be allocated, and any call that an application can make is also valid for a VxD.

All Configuration Manager events are processed at application time. When an enumerator detects the addition of hardware to the system, it calls CONFIGMG_Reenumerate_DevNode(DEVNODE_TO_BE_ENUMERATED, 0) which causes Configuration Manager to wait until application time and then call the enumerator back.


Run-Time Dynamic Device Loading

Plug and Play permits devices to be loaded dynamically after the system is already running when

  1. An enumerator detects the addition of a device to the system and calls Configuration Manger to reenumerate its own device node, using CONFIGMG_Reenumerate_DevNode as follows:
    CM_Reenumerate_DevNode(DevNode, 0);
  2. CONFIGMG_Reenumerate_DevNode causes Configuration Manager to call back the enumerator at application time. When called back, the enumerator detects the new hardware and constructs a device ID (for example, PCMCIA\3C08AF\0). The enumerator creates a new child device node with this ID and returns from the enumeration function.
  3. Configuration Manager uses the device ID to determine which key in the registry to inspect. In this example, Configuration Manager will look in HARDWARE\ENUM\PCMCIA\3C08AF\0\DRV\, where it will find DEVLOADER=NetWrap.386. If this VxD is not already loaded, Configuration Manager dynamically loads NetWrap.386.
  4. Once the device loader is available, Configuration Manager sends a system control call to the network wrapper, passing it the device node for which it is the device loader, as follows:
    DirectedSysCtrl("NetWrap", PNP_NEW_DEVNODE, DEVLOADER, pdnNew)
  5. NetWrap registers as the enumerator for this node, and then examines the registry to find the appropriate NDIS driver to load. In our example, NetWrap would find
    SYSTEM\CurrentControlSet\Services\Class\PCMCIA
< NdisDriver=XYZ.VXD
  6. Once loaded, XYZ.VXD registers as the device driver for the device node, forcing Configuration Manager to assign resources to it. Configuration Manager informs the NDIS driver of the assigned configuration, thus enabling the network adapter.


Windows GUI Driver Initialization

Ring 3 Windows drivers may still be loaded from SYSTEM.INI for compatibility purposes, but individual subsystems such as the display may create methods to load their drivers from the registry instead. Refer to the documentation for the particular subsystem to determine the appropriate load method.


Run-Time Dynamic Events

A new feature of Windows 95 is the ability of device drivers and applications to query and notify each other about changes in the state of the system, particularly changes in the system hardware. Although Windows applications have been able to broadcast messages to other Windows applications in all releases of Windows subsequent to 3.0, it was not possible for VxDs to do so, nor was it possible to query other system components before taking action. Applications can use Windows 95's new capabilities to take appropriate action for such events as the addition or removal of a device; for example, an application that is using a floppy disk can use these API elements to receive a notification if the floppy disk is removed.

The SHELL_BroadcastSystemMessage function broadcasts a message to one or more of the following classes of system components:

  • Windows applications
  • Virtual device drivers (VxDs)
  • Installable Windows ring 3 device drivers
  • Network drivers

The counterpart to the SHELL_BroadcastSystemMessage function that is used by Windows applications is the BroadcastSystemMessage function. Windows applications receive broadcast system messages through their normal message procedure. The message is not sent to child windows.

The WM_DEVICECHANGE message identifies a change in the status of the system hardware; it can be used with SHELL_BroadcastSystemMessage to inform system components of hardware changes. WM_DEVICECHANGE includes a number of query notifications; an application can return QUERY_VETOED to a query notification to veto the specified action.


Processing System Broadcasts from a VxD

Virtual device drivers can send and receive system broadcast messages under Windows 95. The notification services are provided by the shell VxD. To receive system broadcast messages, VxDs must call the SHELL_HookSystemBroadcast function.

Between the sending of Sys_Critial_Init and when a VxD receives the WM_STARTSESSION notification, application time events are not processed. Also, during this time, broadcasts are sent only to VxDs (since other Windows system components are not loaded). This rule also applies to the time between a successful WM_ENDSESSION notification and Sys_Critical_Exit. During these phases of system operations, VxDs must send notifications only during times when other VxDs can safely respond to them.

During all other times, SHELL_BroadcastSystemMessage must only be called at application time.


WM_STARTSESSION

WM_STARTSESSION
 reserved = wParam // undefined
 reserved = lParam // undefined

Informs VxDs that the Windows user interface component is now active and that the SHELL_CallAtAppyTime services will now work.


Special Notifications for VxDs

VxDs receive WM_QUERYENDSESSION and WM_ENDSESSION messages when the Windows user interface component is shut down. These notifications have the same purpose as the WM_ENDSESSION message received by Windows applications. VxDs can refuse to allow Windows to shut down during the WM_QUERYENDSESSION broadcast. For more details on the wParam values for these broadcasts, refer to the Windows software development kit (SDK).

VxDs may also receive WM_STARTSESSION, a special notification that is not sent to Windows applications or drivers.


Plug and Play and PCMCIA

This documentation describes the architecture of PCMCIA in Windows 95 and its interaction with the Plug and Play environment. It addresses the three major aspects of PCMCIA: PC cards, device drivers for those cards, and PCMCIA system software. The Plug and Play framework enables tighter integration and better support of the dynamic nature of the PCMCIA interface. In this framework, a PCMCIA adapter will be controlled by the PCMCIA bus enumerator (PCCARD.386). PCCARD incorporates the Card Services functions as well as the PCMCIA bus enumeration and configuration functions.

The primary goal of PCMCIA in Windows 95 is to configure PC cards so that any Plug and Play device driver can be used to control the device, without any special provisions for PCMCIA. Another goal of the system is to support PCMCIA 2.x Card Services Clients and Drivers and to provide an environment for 32-bit protected mode Card Services clients, which may be required to support PC cards and their drivers.

The tighter integration of PCMCIA with the operating system eliminates the need for the guesswork which Card Services otherwise uses to find which resources are available in a given system. The PCMCIA enumerator also enables automatic device installation via the Windows Device Installer. Since configuration management is actually done by Configuration Manager, resources are allocated and reclaimed dynamically. This enables the easy addition of static devices and support for new scenarios such as hot or warm docking. The PCMCIA bus enumerator uses the information tuples described in this documentation to identify the card, load the correct device driver, and indicate all the possible configurations to Configuration Manager. Configuration Manager dynamically assigns a valid configuration based on this information.

To support true Plug and Play functionality, PC cards must fully support the identification and configuration tuples described in this documentation.

Device drivers must be modified to support the Windows 95 dynamic loading mechanism and the Plug and Play configuration functions. Since Windows 95 Plug and Play seamlessly configures devices in the system, it enables card vendors to write a single driver for the ISA, EISA, PCI and PCMCIA implementations of a given I/O card. Protected mode Card Services clients will be supported in Windows 95 as well, but will not have the same level of flexibility as Windows 95 Plug and Play drivers. This documentation describes three different types of PC card drivers which will be supported in Windows 95.

The following diagram illustrates how Card Services is integrated into the Windows 95 Plug and Play framework. Card Services is incorporated with the PCMCIA bus enumerator in the PCCARD module. This module interacts with Configuration Manager and the registry when a card is inserted or removed.


PC Card Tuples

To support a PC card as a typical Plug and Play device, the card must contain tuples that identify the card and define how it should be configured.


Preferred Tuples

A device in the Windows 95 Plug and Play system can be configured only when the system can create a unique identifier for the device. This identifier is used to locate device-specific information in an INF file for installation purposes and in the registry for initialization and configuration purposes. The registry and the INF files contain information about the drivers that are needed for the device and may also contain configuration information or even previous settings for the device.

Each PC card must contain the information required to create this unique device ID. This is done through the use of tuples on the card.

The following table lists the preferred tuples used by PCCARD to create a device ID for a PC card.

Tuple | Comments
Level 1 Version/ Product Information | Product Information String Product Name Product Number Other Manufacturer Information
Manufacturer ID | Card manufacturer ID code - Defines manufacturer for this card.
Device | Device size and type are used by Card Services to configure the socket interface.
Configuration | Indicates last configuration entry in the configuration entry table for configurable cards. Indicates location of configuration registers.
Configuration Entry | Configuration requirements should be specified for I/O space, interrupts, memory, and so on.

These tuples have the following codes and ID values.

Tuple | Tuple Code | Tuple ID
Level 1 Version/ Product Information | CISTPL_VERS_1 | 15H
Manufacturer ID | CISTPL_MANFID | 20H
Device | CISTPL_DEVICE | 01H
Configuration | CISTPL_CONFIG | 1AH
Configuration Entry | CISTPL_CFTABLE_ENTRY | 1BH

The device ID string is of the form: PCMCIA\Manufacturer-Product-CRC16. The Manufacturer and Product portions are derived from from the Level 1 Version tuple with non-printable characters removed and spaces converted to underscores. The 16-bit CRC is created from the DEVICE, VERS_1, CONFIG, CFTABLE_ENTRY, and MANFID tuples. The PCMCIA device ID string is one of the outputs from the included utility DTPL.EXE. Refer to the DTPL section for more information about this utility.


Device Configuration Tuples

Each device is configured based on a set of logical configurations. These are the possible configurations that can be used by the device. A logical configuration must be determined for a PC card that a device ID has been created for and this configuration must be passed to Configuration Manager. The configuration information for a PC card is derived from the Configuration and Configuration Table Entry tuples. The order of the Configuration Table Entry tuples specifies the preference for each configuration.

To support devices that do not have valid (or correct) configuration tuples, the registry may contain overriding logical configurations for the device. This overriding configuration is located using the device ID and may be set up based on information in the INF file when the device is first installed.


PCMCIA Device Drivers

Device driver writers have three possible implementation schemes for device drivers supporting PCMCIA cards. They can write a standard protected mode Plug and Play driver, they can rely on standard Windows 95 drivers for certain devices, or they can write a 32-bit protected mode Card Services client. Device driver writers can still add Card Services calls to their Plug and Play drivers, but these drivers will not be bus-independent. The choice depends on several factors, including the completeness of the Card Information Structure (CIS) on the PC card, whether the driver needs memory services, and whether the driver is expected to support the same type of hardware on another bus (that is, whether it is a bus-insensitive driver).

Generally, you should write standard Plug and Play device drivers for your PC Card. For LAN cards, write NDIS 3.x-compliant drivers. For SCSI cards, write miniport drivers. For modems, use the VCOMM driver and include the appropriate AT command strings in the INF file for the Windows 95 Remote Network Access (RNA) software.


Standard Plug and Play Device Driver

A Plug and Play device driver may be any driver that follows the Plug and Play architecture. These drivers handle dynamic configuration and removal. They receive their configuration from Configuration Manager and have no direct interaction with the PCMCIA components. Therefore, they may be run as the device drivers for a PC card without any knowledge of the card existing in a PCMCIA bus. These are the preferred drivers for PCMCIA devices. Once Plug and Play assigns IRQ, memory and I/O, access and operation of the card will be done using the assigned resources.

This approach is recommended if the device driver does not require the Card Services functions. All resource allocation for the driver will be done by Configuration Manager, based on the table of required resources supplied by the device. The actual configuration of the card will be done by Config Manager through the PCMCIA bus enumerator after the resources have been allocated. This will allow the same device driver to support ISA/EISA/PCI and PCMCIA implementations of the same device. Note that this approach cannot be used for PC cards which do not contain the tuples required to identify the PC card and allow a device ID to be created. Cards with invalid or missing configuration tuples can still benefit through the CIS override mechanism, whereby the INF file lists the correct logical configuration possibilities for the device. See the section on Windows INF files for further information on the override mechanism.

A device driver that supports a card that uses the correct tuples (as defined in "PC Card Tuples" earlier in this section) but needs to access the Card Services memory functions should choose a mixed approach: it can be both a Plug and Play and a Card Services device driver. The structure of the driver is the same, except that it calls Card Services functions when necessary. If the driver needs a client handle, it may register with Card Services as a Card Services client.The card would still be automatically configured at insertion time by the PCMCIA bus enumerator, but any access to the PC card's tuples or memory window manipulation would be performed by the driver calling Card Services functions.

Details on writing a standard Plug and Play device driver are found in other sections of the Device Driver Kit (DDK). Note that existing driver architectures such as NDIS3 for network adapters, and Windows NT/Windows 2000 miniports for SCSI devices are already Plug and Play, as the underlying subsystems handle the PnP requirements for their client drivers.


Generic Windows 95 Device Driver

Certain devices, such as modems and disk drives, are automatically supported by Windows 95. Note that in the case of modems, Windows provides generic drivers but it is recommended that manufacturers provide specific INFs for their modems with the appropriate AT commands. If the configuration information on the PC card is complete, the PCMCIA bus enumerator will initialize the device and Configuration Manager will pass the configuration information to one of these drivers. For example, if the PC card is an IDE drive, Configuration Manager may assign I/O port 1F0h and IRQ 14 (representing the primary IDE controller) and will pass this information to the Windows 95 I/O sub-system (IOS). Specialized functions on the cards may be implemented using mini drivers (refer to other sections in the Windows 95 DDK for more information).

Device classes that do not have standard configurations (for example, network or SCSI adapters) are not automatically supported by Windows 95 — the drivers must be supplied by the hardware manufacturer.


Card Services Client Device Driver

Several different types of device drivers are Card Services clients. Any 32-bit protect mode device driver that uses Card Services 2.x will work under Windows 95. However, without some changes, resource allocation may not be optimized, and the device driver does not participate in any resource balancing. Because the device driver makes the requests for resources and configuring the card, this may be the only option to support cards with an incomplete card information structure (CIS).

For cards with complete CIS information, these drivers can still benefit from an optimized initial resource allocation. Upon card insertion, the PCMCIA bus enumerator reads the card's CIS to determine the card's resource requirements. If the PCMCIA bus enumerator is successful (that is, if the CIS is complete), it builds the resource request list on behalf of the client driver. This enables the Configuration Manager to find a working resource allocation. Once the Card Services portion of the PCCARD module is told what resources were allocated, it simply filters the client driver's resource requests until it requests the correct preallocated resources.


Memory Technology Driver

Memory technology drivers enable memory card vendors to support cards featuring new memory technologies. These drivers use the Card Services 2.x MTD functions.


PCMCIA System Software

The Windows 95 support of PCMCIA provides the Card Services 2.x level of functionality. This is integrated with the Windows 95 Plug and Play architecture so that Configuration Manager provides the resource allocation instead of the Card Services module. This is done by adding a PCMCIA bus enumerator to Card Services and changing Card Services to accept configurations from Configuration Manager instead of tracking the resources itself. This implementation provides support for existing PCMCIA Card Services clients as well as new Plug and Play drivers on Windows 95.

The following diagram is an expanded illustration of the architecture of PCMCIA in Windows 95.


Card Services

The Card Services component is a protected mode VxD module that is linked with the PCMCIA bus enumerator. It provides a protected mode PCMCIA Card Services 2.x interface for protected mode Card Services clients. Card Services passes the event notification from Socket Services to the PCMCIA bus enumerator, provides information from the PC cards to the PCMCIA bus enumerator, and sets up the configuration for PC cards in the adapter sockets.


Interface for VxDs

This section describes the Card Services binding for VxD clients. The calling mechanism is the VxD service interface — any VxDs requiring access to Card Services must include PCCARD.INC. This include file contains the PCCARD service-access table that allows the client VxD to use the VxDCall macro to call Card Services.

The VxD Card Services interface is not available during system initialization. Clients should register with Card Services while processing the Init_Complete message. Clients registering at this point still have the opportunity to abort loading if Card Services is not present.

MASM version 6.x is required for the structure definitions in the Card Services interface.


Card Services API Elements

PCCARD.386 offers two services: PCCARD_Get_Version and PCCARD_Card_Services. Access to all Card Services is through the PCCARD_Card_Services service. As with all VxD services, clients should call PCCARD_Get_Version to ensure that PCCARD is loaded before attempting to call PCCARD_Card_Services.


Card Services Argument Binding

Parameters are passed in registers following the recommended binding in the PCMCIA Standards manual for 0:32 protected mode clients.

Register | Description
[AL] | Function
[DX] | Handle
[ESI] | Pointer (32 bit offset)
[CX] | ArgLength
[EBX] | ArgPointer (32 bit offset)
[AX] | Status
[CF] | Reset to zero when request was successful, set to one when request has failed.

All calls and returns are near.

All entry registers are preserved unless the same register is used for a return value.

The following table gives the arguments for callback handlers.

Register | Description
[AL] | Function
[CX] | Socket
[DX] | Info
[DI] | First word of RegisterClient argument packet ClientData field
[ESI] | Third and fourth word of RegisterClient argument packet ClientData field
[EBP] | MTD request
[EBX] | Buffer
[BX] | Misc. (when no buffer is specified)
[AX] | Status on return to Card Services
[CF] | Returned reset to zero when the callback completed successfully, set to one if Status is not SUCCESS.


Card Services RegisterClient Function

The following table gives the register_client argument packet ClientData field.

Offset | Description
0 | 16 bit data determined by client
2 | 16 bit reserved (reset to zero)
4 | 32 bit offset determined by client

For detailed information on the other functions, see the PCMCIA Standards manual.


Socket Services

The Socket Services component is a protected mode VxD module that manages the PCMCIA adapter hardware. It is the driver that controls the specific PCMCIA hardware components. It provides a protected mode PCMCIA Socket Services 2.x interface for use by Card Services. A Socket Services driver must be implemented for each separate PCMCIA controller that could be used.

The Socket Services driver registers with Card Services using the add_socket_services function.

The PCCARD module contains the device loader for the Socket Services driver.

Windows 95 will provide Socket Services drivers for the Intel 82365 controller and the DataBook controller. Contact Microsoft Hardware Vendor Support for information on writing Windows 95 compatible Socket Services drivers for other controllers.


PCMCIA Hardware-Tree

When the PCMCIA bus enumerator is called at its enumeration entry point, it will create a subtree that represents everything subordinate to the PCMCIA adapter. The following diagram shows the location and possible representation of a PCMCIA hardware tree:

The PCMCIA bus enumerator handles two levels of device nodes: the adapter device node and the card device node. The adapter device node contains the configuration information for the PCMCIA adapter. The card device node contains the configuration information for the PC card in the adapter's socket. These device nodes are created through the sequence of operations discussed in the following sections.


The Enumeration Process

When the system starts, a bus enumerator for a bus device node (such as the system board BIOS) will enumerate its bus and detect the PCMCIA adapter. The bus enumerator will create an adapter device node for the adapter and add a logical configuration for the adapter at its current configured I/O address. Configuration Manager will load the device loader, based on information in the registry. The device loader for the adapter is contained in the PCMCIA bus enumerator - along with the Card Services component. The device loader is called at its PNP_NEW_DEVNODE control entry point. The device loader loads the Socket Services driver for the adapter device node, based on the Driver= entry in the registry for the adapter device node. The device loader registers an enumerator for the adapter device node.

Configuration Manager calls the Socket Services driver to filter the logical configuration for the adapter. The Socket Services driver will then be called by Configuration Manager to configure the adapter's IRQ, I/O, and a memory window.

Configuration Manager then calls the bus enumerator for the adapter device node to enumerate the devices on the PCMCIA bus. The bus enumerator enumerates each PC card in the sockets on the adapter. A device ID for each PC card is generated from the tuples on the card. The bus enumerator creates the device nodes for the cards in the sockets. Logical configurations will be created based on the configuration tuples on the PC card. If a card does not have configuration tuples, an empty logical configuration is added for the card. Overriding configurations may be defined in the registry to handle this case, or the driver for the card may define the logical configuration during the call to the CONFIG_FILTER configuration handler function. For this to happen, a valid Manufacturer ID tuple must exist on the card.


Setup on First Insertion

The registry is set up when the device is first installed and recognized by the bus enumerator. This is initiated by Configuration Manager when a device node is created for which a device ID is not contained in the registry. If the device has not been previously configured, Configuration Manager calls the Device Manager to set up the registry for the device. The Device Manager will look up the Device ID entry in the appropriate device information (.INF) file and the resource information in the drivers which already exist in the default driver directory. If a default driver is found, its configuration information is copied to the registry and the driver is loaded. If no driver is found the user will be prompted to initiate an installation process.

When the Device Manager has completed the setup of the registry, the Configuration Manager will complete the setup of the device node for the device. If an overriding logical configuration exists in the registry it will be used for the device, and the logical configuration that was defined by the PCMCIA bus enumerator will be discarded.


Configuration Process

Configuration Manager will load the device loader for the card based on information in the registry. The device loader may be a Plug and Play device loader, or, to support Card Services clients, the PCMCIA bus enumerator may be the device loader. If the PCMCIA bus enumerator is the device loader, the driver will be a Card Services client, the device node will be handled specially, and a default device driver will be registered for the card by the device loader.

Configuration Manager calls the CONFIG_FILTER function in the adapter driver where it filters the PC card configurations so that they can be mapped by the adapter for the socket. Any logical configurations that cannot be supported by the adapter will be removed from the filtered logical configuration list.

Finally, when the configuration has been determined by Configuration Manager, the CONFIG_START function will be called and the PCMCIA bus enumerator will map the IRQ, I/O, and memory windows for the PC card by calling the Card Services module. Card Services configures the adapter to support the defined configuration and sets the configuration index in the cards registers.


Overriding Logical Configurations

To allow support for PnP cards that have invalid logical configs defined on the card, overriding logical configs are supported. These overriding logical configs are defined in the INF file for the device and transfered to the registry when the device is installed. When an overriding logical config is defined for a device, the config manager will replace the logical configs created by the enumerator with the overriding config defined in the registry. Refer to the Device Installation section for detailed information about the general case of overriding configurations.

The logical config created by the PCMCIA Bus Enumerator is an extended version of the normal logical config defined by the configuration manager. This logical config contains an additional DWORD flags value on the end of the I/O and IRQ resource descriptor, an additional DWORD flags value and DWORD card address value on the end of the memory resource desciptor, and an ignored resource descriptor which contains the REQUEST_CONFIG_PKT structure.

The extension to the I/O Range is a dword flags value. A single flag bit is defined (0x40), when set indicates the I/O ports are 16-bit I/O ports, otherwise they are 8-bit ports.

The extension to the IRQ List is a dword flags value. A single flag bit is defined IRQI_LEVEL (0x20), when set indicates the IRQ is level triggered. Currently, this bit must be set for the card to be configured.

The extension to the Memory Range is a dword flags value followed by a dword card offset. The flags value must be set to either WDWA_ATTRIB_MEM (0x02), or WDWA_16BIT (0x08). When it is set to WDWA_ATTRIB_MEM it indicates the memory window is in attribute memory. When it is set to WDWA_16BIT it indicates the memory window is in common memory. The card offset is the offset on the PC card for the memory window to be mapped.

PCMCIA PC Cards require an additional resource type. This resource is defined as type 0x897C. The data in the resource is the same as the PCMCIA Card Services RequestConfiguration argument structure (REQUEST_CONFIG_PKT). The Socket field in this structure does not need to be filled in.

The following is an example of the overriding logical config that may be defined for PCMCIA Cards in the INF file.

[SAMPLEOVERRIDE]
HKR,Override,0000,HEX, \
;
00,04,00,00, \            ; CONFIGMG_VERSION
00,00,00,00, \            ; PRIORITY
;
; I/O Resource Descriptor
;
24,00,00,00, \            ; Total length of I/O Resource Descriptor
02,00,00,00, \            ; ResType_IO = 0x00000002
01,00, \                 ; IOD_Count;
0C,00, \                 ; IOD_Type;    // IOType_Range = 0x000C
00,00, \                 ; IOD_Alloc_Base;
00,00, \                 ; IOD_Alloc_End;
00,00, \                 ; IOD_DesFlags;
00, \                     ; IOD_Alloc_Alias;
00, \                     ; IOD_Alloc_Decode;
F0,FF, \                 ; IOR_Align;    // Mask for base alignment
10,00, \                 ; IOR_nPorts;    // Number of ports
00,00, \                 ; IOR_Min;    // Min port address
FF,FF, \                 ; IOR_Max;    // Max port address
00,00, \                 ; IOR_RangeFlags;  // Flags
00, \                     ; IOR_Alias;    // Alias offset
00, \                     ; IOR_Decode;    // Address specified
40,00,00,00, \            ; PCCARD flags, 0x40 = 16-bit port
;
; Memory Resource Descriptor
;
34,00,00,00, \            ; Total length of Memory Descriptor
01,00,00,00, \            ; ResType_Mem = 0x00000001
01,00, \                 ; MD_Count;
14,00, \                 ; MD_Type;    // MType_Range = 0x0014
00,00,00,00, \            ; MD_Alloc_Base;
00,00,00,00, \            ; MD_Alloc_End;
00,00, \                 ; MD_Flags;
00,00, \                 ; MD_Reserved;
00,F0,FF,FF, \            ; MR_Align;    // Mask for base alignment
00,10,00,00, \            ; MR_nBytes;    // Count of bytes
00,00,00,00, \            ; MR_Min;    // Min Address
FF,FF,FF,FF, \            ; MR_Max;    // Max Address
00,00, \                 ; MR_Flags;    // Flags
00,00, \                 ; MR_Reserved;
02,00,00,00, \            ; PCCARD flags, 0x02 = attribute mem, or
                        ;    0x08 = 16-bit common mem
00,10,00,00, \            ; Memory card address
;
; IRQ Resource Descriptor
;
14,00,00,00, \            ; Total length of IRQ Resource Descriptor
04,00,00,00, \            ; ResType_IRQ = 0x00000004
00,00, \                 ; IRQD_Flags;
00,00, \                 ; IRQD_Alloc_Num;  // Allocated IRQ number
FF,FF, \                 ; IRQD_Req_Mask;  // Mask of possible IRQs
00,00, \                 ; IRQD_Reserved;
20,00,00,00, \            ; PCCARD flags, 0x20 = Level mode int's
;
; REQUEST_CONFIG_PKT Descriptor
;
19,00,00,00, \            ; Length of REQUEST_CONFIG_PKT Descriptor
7C,89,00,00, \        ; ResType_Ignored_Bit+PCCARD_DEVICE_ID= 0x897C
00,00, \                 ; Socket;
02,00, \                 ; Attributes;
32, \                     ; Vcc;
00, \                     ; Vpp1;
00, \                     ; Vpp2;
02, \                     ; IntType;
00,02,00,00, \            ; ConfigBase;
00, \                     ; Status;
00, \                     ; Pin;
00, \                     ; Copy;
01, \                     ; ConfigIndex;
0F, \                     ; Present;
;
00,00,00,00              ; TERMINATOR
<ex>

<h2>Display Tuple Utility (DTPL.EXE)

<p>DTPL.EXE is a tool designed for interpreting the tuples on a PC Card. This tool is intended to help you design or verify CIS for use with Microsoft's PCMCIA support in Windows. DTPL runs in realmode on MS-DOS using realmode Card Services and Socket Services implementations. It is intended to be run on PC Cards that have not been configured by a card services client, or enabler. Therefore card services clients and PC Card enablers should not be loaded or active when using this tool.

<p>This tool displays information derived from the tuples on the PC Card. This includes the PnP Device ID, the PnP Logical Configurations, and a display of each tuple on the card.

<p>The tool has the following syntax:

<ex>DTPL [-f <filename>] [-i] [-l] [-r] [-t] [<socket#>]

-f filename | Defines a filename to take the tuple input from instead of calling CS.
-i | Displays the PNP Device ID for the PC Card.
-l | Displays the PNP logical configurations for the PC Card.
-r | Displays raw tuple data bytes, formatted for input file.
-t | Displays all of the tuples on the PC Card.
socket# | An optional socket to display, otherwise all sockets will be displayed.

The -f option allows the tuple input to be taken from a file. This allows tuples to be interpreted with out the need for a realmode Card Services driver and also allows tuples to be tested before they are placed on a PC Card. The tuples in this file must be defined in an ASCII HEX format. Each hex value must have two digits, the parser for this is very simple. Comments may be placed in the tuple file using a semicolon (;).

For example the following tuple is a config entry tuple for a comm port.

; This is a COM1 port
1B 11  ; Config entry and link values.
E0 01 1D 48 D5 02 1D FC
14 A0 60 F8 03 07 30 3C 00

The optional socket# is ignored when the -f option is used and the socket for the tuples will be set to 0xFF.

The -i option displays the PnP Device ID for the PC Card.The PnP Device ID is the ID that will be generated by the PCMCIA Bus Enumerator for the device and used by the Plug and Play system. This ID should be used when generating the .INF file for a device. The device ID is created from the manufacturer name string, the product name string, and a 16-bit CRC of a set of tuples. The ID is created by concatinating the PCMCIA prefix, the manufacturer name string, the product name string, and a 16-bit CRC. The Device ID has the following format:

PCMCIA\manuf_name-prod_name-crc

The manuf_name and prod_name are obtained from the CISTPL_VERS_1 tuple. If the CISTPL_VERS_1 tuple is not available or the manufacturer name is NULL, the string "UNKNOWN_MANUFACTURER" will be included in its place.

The CRC will be created from the following tuple data: CISTPL_DEVICE, CISTPL_VERS_1, CISTPL_CONFIG, CISTPL_CFTABLE_ENTRY, CISTPL_MANFID.

Only the first two strings in the CISTPL_VERS_1 tuple, the manufacturer and product name strings, are included in the CRC. This is because serial numbers are occasionally placed in the additional strings of this tuple. These serial numbers would cause the CRC to be different for each card even though they are the same.

The total length of the device ID string is limited to 128 characters, including the null terminator. The manufacturer and product name will be truncated to maintain this length restriction in the ID string.

The characters in the manufacturer and product name strings that are greater than or equal to a space (0x20) or less than (0x7F) will be copied into the name string. Any other characters outside this range will be skipped. This makes it easier to include these characters in the .INF files for the device. Spaces and commas in the device ID will be converted to underscores (_).

The -l option displays the PnP Logical Configurations for the PC Card. The PnP Logical Configurations are generated by the PCMCIA Bus Enumerator from the Config and Config Entry tuples. The display of these configurations is intended to provide some feedback on the interpretation of the configuration tuples on the PC Card. The logical configuration will be used by the Plug and Play Configuration Manager to determine the configuration for the PC Card. The information displayed includes I/O, IRQ, and Memory resource data, along with the contents of a Card Services RequestConfiguration argument structure.

The -r option displays each tuple as its raw data bytes. This is in a format that can be easily edited and feed back to the DTPL tool as an input file using the -f option. Note that any strings that are not data bytes must be commented out with a semicolon (;) or removed from the input file.

The -t option displays each tuple in a more readable format. Many of the tuples are interpreted and displayed in an expanded form. For example this is done for the configuration entry tuples which are difficult to understand without such expansion. Following the expanded information for each tuple is a dump of the tuple data bytes in an ASCII HEX format followed by an ASCII dump of each byte in the tuple. Non-printable bytes are diplayed as a period (.) in the ASCII dump. Tuples that are not expanded are displayed in an ASCII HEX format only.


Configuration Manager Reference

This section describes the Configuration Manager services, callback functions, messages, structures, and constants.


Services

This section describes the Configuration Manager services.


CONFIGMG_Add_Empty_Log_Conf

CONFIGRET CONFIGMG_Add_Empty_Log_Conf(PLOG_CONF plcLogConf, DEVNODE dnDevNode, PRIORITY Priority, ULONG ulFlags)

Creates an empty logical configuration. This configuration has no resource descriptor.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_PRIORITY, CR_INVALID_POINTER or CR_OUT_OF_MEMORY.
plcLogConf
Address that receives the handle of the logical configuration.
dnDevNode
Address of a device node. This address is typically retrieved by a call to CONFIGMG_Locate_DevNode or CONFIGMG_Create_DevNode.
Priority
Priority of the logical configuration. This parameter can be one of the following values.
LCPRI_FORCECONFIG | Coming from a forced config.
LCPRI_BOOTCONFIG | Coming from a boot config.
LCPRI_HARDWIRED | Like VPICD's IO range.
LCPRI_DESIRED | Preferable set (better performance).
LCPRI_NORMAL | Workable (acceptable performance).
LCPRI_SUBOPTIMAL | Not desired but will work (like PIO).
LCPRI_RESTART | Need to restart Windows.
LCPRI_REBOOT | Need to reboot Windows.
LCPRI_POWEROFF | Need to shutdown Windows.
LCPRI_HARDRECONFIG | Need to change a jumper.

ulFlags
Either BASIC_LOG_CONF or FILTERED_LOG_CONF, combined with either PRIORITY_EQUAL_FIRST or PRIORITY_EQUAL_LAST.
BASIC_LOG_CONF | Specifies the requirements list.
FILTERED_LOG_CONF | Specifies the filtered requirements list.
PRIORITY_EQUAL_FIRST | Same priority, new one is first.
PRIORITY_EQUAL_LAST | Same priority, new one is last.

Note Calling CONFIGMG_Add_Empty_Log_Conf or CONFIGMG_Free_Log_Conf from within a CONFIGMG_Get_First_Log_Conf/CONFIGMG_Get_Next_Log_Conf loop may have unwelcome side effects. Drivers should end the loop before adding or freeing a logical configuration and start it again when the operation is finished.

See Also

CONFIGMG_Create_DevNode, CONFIGMG_Free_Log_Conf, CONFIGMG_Get_First_Log_Conf, CONFIGMG_Get_Next_Log_Conf, CONFIGMG_Locate_DevNode


CONFIGMG_Add_ID

CONFIGRET CONFIGMG_Add_ID(DEVNODE dnDevNode, PFARCHAR pszID, ULONG ulFlags)

Add an hardware or compatible id during CONFIG_SETUP.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_POINTER or CR_INVALID_FLAG.
dnDevNode
Handle of a device node.
pszID
Points to a id to add.
ulFlags
Must be CM_ADD_ID_HARDWARE or CM_ADD_ID_COMPATIBLE.


CONFIGMG_Add_Range

CONFIGRET CONFIGMG_Add_Range(ULONG ulStartValue, ULONG ulEndValue, RANGE_LIST rlh, ULONG ulFlags)

Adds a memory range to a range list.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_FAILURE, CR_INVALID_FLAG, CR_INVALID_RANGE, CR_INVALID_RANGE_LIST or CR_OUT_OF_MEMORY
ulStartValue
Low end of the range.
ulEndValue
High end of the range.
rlh
Handle of a range list.
ulFlags
Flags specifying options for memory ranges that conflict with ranges already in the list. This parameter must be one of the following values.
CM_ADD_RANGE_ADDIFCONFLICT | New range is merged with the ranges it conflicts with.
CM_ADD_RANGE_DONOTADDIFCONFLICT | Function returns CR_FAILURE if there is a conflict.

See Also

CONFIGMG_Delete_Range, CONFIGMG_Delete_Range


CONFIGMG_Add_Res_Des

CONFIGRET CONFIGMG_Add_Res_Des(PRES_DES prdResDes, LOG_CONF lcLogConf, RESOURCEID ResourceID, PFARVOID ResourceData, ULONG ResourceLen, ULONG ulFlags)

Adds a resource descriptor to a logical configuration.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_LOG_CONF, CR_INVALID_POINTER, CR_INVALID_RESOURCE_ID or CR_OUT_OF_MEMORY.
prdResDes
Address that receives a handle of the resource descriptor.
lcLogConf
The logical configuration to which the resource descriptor is added.
ResourceID
The type of the resource. This parameter can be one of the following.
ResType_DMA | DMA channels 0-3 resource
ResType_IO | Physical IO address resource
ResType_IRQ | IRQ 0-15
ResType_Mem | Physical address resource

ResourceData
Address of a resource data structure.
ResourceLen
The size, in bytes, of the structure pointed to by ResourceData.
ulFlags
Must be zero.

The new resource descriptor is added to the beginning of the logical configuration's resource-descriptor list. This means that a loop using CONFIGMG_Get_Next_Res_Des will not reveal this resource descriptor unless the loop is started after the resource descriptor has been added.

The logical configuration being modified must be either BASIC_LOG_CONF or FILTERED_LOG_CONF. Typically, BASIC_LOG_CONF is added to during device driver initialization or enumeration, whereas FILTERED_LOG_CONF is added to during a CONFIG_FILTER device-driver configuration function.

See Also

CONFIGMG_Free_Res_Des


CONFIGMG_Call_At_Appy_Time

CONFIGRET CONFIGMG_Call_At_Appy_Time(CMCALLBACKHANDLER Handler, ULONG ulRefData, ULONG ulFlags)

CONFIGMG will call back the handler at appy time.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG.
Handler
is the function to be called at appy time.
ulRefData
is the parameter to the function to be called back at appy time.
ulFlags
Must be zero.

This function is functionally equivalent to SHELL_CallAtAppyTime, but allow CONFIGMG to know that it is appy time.

This function is asynchronous (that is, callable at interrupt time), reentrant, and fast.


CONFIGMG_Call_Enumerator_Function

CONFIGRET CONFIGMG_Call_Enumerator_Function(DEVNODE dnDevNode, ENUMFUNC efFunc, ULONG ulRefData, PFARVOID pBuffer, ULONG ulBufferSize, ULONG ulFlags)

Call the enumerator function about a child devnode.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_POINTER, CR_INVALID_FLAG or CR_INVALID_API. Furthermore, the enumerator may return the result CR_FAILURE.
dnDevNode
Handle of a device node.
efFunc
Is the function number.
ulRefData
Is a reference data (can't be a pointer).
pBuffer
Points to a buffer for the function.
ulBufferSize
Is the size of the buffer.
ulFlags
Must be zero.


CONFIGMG_CallBack_Device_Driver

CONFIGRET CONFIGMG_CallBack_Device_Driver(CMCONFIGHANDLER Handler, ULONG ulFlags)

Call back the device driver, once per devnode. with a CONFIGMG_Register_Device_Driver.

Handler
The configuration handler that was registered in a call to the CONFIGMG_Register_Device_Driver function.
ulFlags
Must be zero.
  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_API or CR_INVALID_FLAG.

A device driver calls this function when it needs to be called back once per devnode.

See Also

CONFIGMG_Register_Device_Driver


CONFIGMG_CallBack_Enumerator

CONFIGRET CONFIGMG_CallBack_Enumerator(CMENUMHANDLER Handler, ULONG ulFlags)

Call back the device driver, once per devnode.

Handler
is the routine that was register with a CONFIGMG_Register_Enumerator.
ulFlags
must be zero.
  • Returns CR_SUCCESS if the function was successful. Otherwise, one of the following errors is returned:
CR_INVALID_FLAG
if ulFlags is not zero.
CR_INVALID_API
if called from ring 3.

An enumerator calls this function when it needs to be called back once per devnode.

This function is synchronous and must not be called from within an interrupt handler.


CONFIGMG_Create_DevNode

CONFIGRET CONFIGMG_Create_DevNode(PDEVNODE pdnDevNode, DEVNODEID pDeviceID, DEVNODE dnParent, ULONG ulFlags)

Adds a device node to the hardware tree.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_ALREADY_SUCH_DEVNODE, CR_INVALID_DEVICE_ID, CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_POINTER, CR_OUT_OF_MEMORY or CR_CREATE_BLOCKED.
pdnDevNode
Address that receives a handle to the new device node. Can be NULL.
pDeviceID
Device identifier. If this parameter is NULL, Configuration Manager does not attempt to find a device loader for the device.
dnParent
Handle of the device node that is the parent of the device node being created.
ulFlags
Must be zero.

Typically, an enumerator calls this function while it is enumerating new devices (during the CONFIG_ENUMERATE event). Configuration Manager allocates the device node and puts the device node in the sibling list of the child device node of dnParent. All fields are initialized to their default values. After this function returns successfully, the enumerator should fill in the fields it can, particularly the resource descriptors. When the enumerator returns from the event, Configuration Manager attempts to load a device driver for the new descendant of the enumerator's device node (if pDeviceID is not NULL).

This function returns CR_ALREADY_SUCH_DEVNODE if there is already a device node corresponding to pDeviceID in the tree. (This error is not returned when pDeviceID is NULL, because there can be multiple NULL device identifiers. These cannot be found using CONFIGMG_Locate_DevNode, however.) When this error is returned, the DN_HAS_MARK flag is set, and pdnDevNode is updated to the handle of the preexisting device node.


CONFIGMG_Create_Range_List

CONFIGRET CONFIGMG_Create_Range_List(PRANGE_LIST prlh, ULONG ulFlags)

Creates a list of memory ranges.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_POINTER or CR_OUT_OF_MEMORY.
prlh
Address that receives the handle of a range list.
ulFlags
Must be zero.

See Also

CONFIGMG_Test_Range_Available


CONFIGMG_Delete_Range

CONFIGRET CONFIGMG_Delete_Range(ULONG ulStartValue, ULONG ulEndValue, RANGE_LIST rlh, ULONG ulFlags)

Deletes a memory range from a range list.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_FAILURE, CR_INVALID_FLAG, CR_INVALID_RANGE, CR_INVALID_RANGE_LIST or CR_OUT_OF_MEMORY.
ulStartValue
Low end of the range.
ulEndValue
High end of the range.
rlh
Handle of a range list.
ulFlags
Must be zero.

Doing a delete range with [0, ULONG_MAX] is special cased: it will empty the whole range and is guarantied not to run out of memory.

See Also

CONFIGMG_Add_Range


CONFIGMG_Deregister_Arbitrator

CONFIGRET CONFIGMG_Deregister_Arbitrator(REGISTERID id, ULONG ulFlags)

Removes a resource arbitrator. This function is rarely called.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_API, CR_INVALID_ARBITRATOR or CR_INVALID_FLAG.
id
The identifier of the resource arbitrator. This identifier must have been created by a call to the CONFIGMG_Register_Arbitrator function.
ulFlags
Must be zero.

This function deregisters an arbitrator and its resource but is not typically used for this purpose. If an arbitrator is global and registers with a NULL device node, it typically is never deregistered (for example, IO, IRQ, DMA and memory). If the arbitrator is local to a specific device node (for example, a PCMCIA socket), it is called automatically by the ARB_REMOVE arbitrator function when its device node is removed.

See Also

CONFIGMG_Register_Arbitrator


CONFIGMG_Disable_DevNode

CONFIGRET CONFIGMG_Disable_DevNode(DEVNODE dnDevNode, ULONG ulFlags)

Disables a device node.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_NOT_DISABLEABLE, CR_INVALID_DEVNODE or CR_NOT_SYSTEM_VM.
dnDevNode
Handle of a device node.
ulFlags
Must be either CM_DISABLE_POLITE (where we ask the driver and give it a chance to stop) or CM_DISABLE_ABSOLUTE (where the driver will be stop even if it does not support stopping).

This function increments a counting semaphore. Any attempt to disable the device node increments the semaphore. The function return CR_NOT_DISABLEABLE if the devnode does not have the DN_DISABLEABLE flag set or failed the CONFIG_TEST/CONFIG_TEST_CAN_STOP message.

See Also

CONFIGMG_Enable_DevNode


CONFIGMG_Dump_Range_List

CONFIGRET CONFIGMG_Dump_Range_List(RANGE_LIST rlh, ULONG ulFlags)

Dumps a range list on a debugging terminal.

  • The return value for this function is undefined.
rlh
Handle of a range list.
ulFlags
Must be zero.


CONFIGMG_Dup_Range_List

CONFIGRET CONFIGMG_Dup_Range_List(RANGE_LIST rlhOld, RANGE_LIST rlhNew, ULONG ulFlags)

Copies a range list.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_RANGE_LIST or CR_OUT_OF_MEMORY.
rlhOld
Handle of the range list to copy.
rlhNew
Handle of a valid range list into which rlhOld is copied. Anything contained in the rlhNew range list is removed by the copy operation.
ulFlags
Must be zero.


CONFIGMG_Enable_DevNode

CONFIGRET CONFIGMG_Enable_DevNode(DEVNODE dnDevNode, ULONG ulFlags)

Enables a device node.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_DEVNODE or CR_NOT_SYSTEM_VM.
dnDevNode
Handle of a device node.
ulFlags
Must be zero.

This function decrements a counting semaphore. The device node is enabled only if the count has returned to zero and the device node does not have any other problem.

See Also

CONFIGMG_Disable_DevNode


CONFIGMG_Fail_Change_Config

CONFIGRET CONFIGMG_Fail_Change_Config(ULONG ulFlags)

Cancel preparation for changing the current Hardware Profile.

  • Returns CR_SUCCESS, CR_FAILURE, CR_NOT_SYSTEM_VM or CR_INVALID_FLAG.
ulFlags
Must be zero.

This function should only be called by a Plug and Play BIOS Enumerator if it makes a successful call to CONFIGMG_Query_Change_HW_Prof but later finds some other reason to cancel the docking or undocking action.

See Also

CONFIGMG_Recompute_HW_Prof, CONFIGMG_Query_Change_HW_Prof


CONFIGMG_First_Range

CONFIGRET CONFIGMG_First_Range(RANGE_LIST rlh, PULONG pulStart, PULONG pulEnd, PRANGE_ELEMENT preElement, ULONG ulFlags)

Retrieves the first range element in a range list.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_FAILURE, CR_INVALID_FLAG, CR_INVALID_POINTER or CR_INVALID_RANGE_LIST.
rlh
Handle of a range list.
pulStart
Address that receives the starting value of the first range element.
pulEnd
Address that receives the ending value of the first range element.
preElement
Address that receives the handle of the next range element.
ulFlags
Must be zero.

See Also

CONFIGMG_Next_Range


CONFIGMG_Free_Log_Conf

CONFIGRET CONFIGMG_Free_Log_Conf(LOG_CONF lcLogConfToBeFreed, ULONG ulFlags)

Frees a logical configuration and all resource descriptors associated with it.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_DEVNODE or CR_INVALID_LOG_CONF.
lcLogConfToBeFreed
Handle that was retrieved by a call to the CONFIGMG_Add_Empty_Log_Conf function.
ulFlags
Must be zero.

Note Calling CONFIGMG_Add_Empty_Log_Conf or CONFIGMG_Free_Log_Conf from within a CONFIGMG_Get_First_Log_Conf/CONFIGMG_Get_Next_Log_Conf loop may have unwelcome side effects. Drivers should end the loop before adding or freeing a logical configuration and start it again when the operation is finished.

See Also

CONFIGMG_Add_Empty_Log_Conf, CONFIGMG_Get_First_Log_Conf, CONFIGMG_Get_Next_Log_Conf


CONFIGMG_Free_Range_List

CONFIGRET CONFIGMG_Free_Range_List(RANGE_LIST rlh, ULONG ulFlags)

Frees the specified range list and the memory allocated for it.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG or CR_INVALID_RANGE_LIST.
rlh
Handle of a range list.
ulFlags
Must be zero.

See Also

CONFIGMG_Create_Range_List


CONFIGMG_Free_Res_Des

CONFIGRET CONFIGMG_Free_Res_Des(PRES_DES prdResDes, RES_DES rdResDes, ULONG ulFlags)

Destroys a resource descriptor.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_POINTER, CR_INVALID_RES_DES, CR_INVALID_DEVNODE or CR_NO_MORE_RES_DES.
prdResDes
Address that receives the handle of the previous resource descriptor. If rdResDes is the handle of the first resource descriptor, this address receives the handle of the logical configuration.
rdResDes
Handle of the resource descriptor to be destroyed.
ulFlags
Must be zero.

This function returns CR_NO_MORE_RES_DES if rdResDes specifies the last resource descriptor.

See Also

CONFIGMG_Add_Res_Des


CONFIGMG_Get_Alloc_Log_Conf

CONFIGRET CONFIGMG_Get_Alloc_Log_Conf(PCMCONFIG pccBuffer, DEVNODE dnDevNode, ULONG ulFlags)

Get the allocated (or boot) resources in a nice table format.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_POINTER, or CR_NO_MORE_LOG_CONF.
pccBuffer
is a pointer to a CMCONFIG struct (which can be on the stack) to be filled by this function with the currently allocated config.
dnDevNode
Device node that a device driver wants to know what are the allocated (or boot) resources.
ulFlags
must be one of CM_GET_ALLOC_CONFIG_ALLOC or CM_GET_ALLOC_CONFIG_BOOT_ALLOC.
  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_POINTER, CR_INVALID_DEVNODE or CR_INVALID_FLAG.

This call is done when a device driver wants to easily know what its configuration is.

This function is synchronous and must not be called from within an interrupt handler.


CONFIGMG_Get_Bus_Info

CONFIGRET CONFIGMG_Get_Bus_Info(DEVNODE dnDevNode, PCMBUSTYPE pbtBusType, PFARULONG pulSizeOfInfo, PFARVOID pInfo, ULONG ulFlags)

Get bus info of the devnode.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_DEVNODE, CR_INVALID_POINTER, CR_BUFFER_SMALL.
dnDevNode
Handle of a device node.
pbtBusType
Will receive the bus type.
pulSizeOfInfo
Points to the dword that is originally the size of the info buffer and will return the size of the info put in the buffer (minimum of the real info size and the given value). If this points to a 0, pInfo is not touched and the real info size is put in *pulSizeOfInfo.
pInfo
A pointer to the bus-specific buffer to be filled.
ulFlags
Must be zero.

This function appends to the devnode some bus specific info. This function is to be used solely by the immediate parent enumerator of a devnode.

See Also

CONFIGMG_Get_Bus_Info

Built on Wednesday, July 11, 2001


CONFIGMG_Get_Child

CONFIGRET CONFIGMG_Get_Child(PDEVNODE pdnDevNode, DEVNODE dnDevNode, ULONG ulFlags)

Retrieves the first child of a given device node.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_POINTER or CR_NO_SUCH_DEVNODE.
pdnDevNode
Address that receives the handle of the device node.
dnDevNode
Handle of the parent device node.
ulFlags
Must be zero.

This function is called by any device driver that needs to walk the hardware tree.

See Als

CONFIGMG_Get_Parent, CONFIGMG_Get_Sibling


CONFIGMG_Get_CRC_CheckSum

CONFIGRET CONFIGMG_Get_CRC_CheckSum(PFARVOID pBuffer, ULONG ulSize, PFARULONG pulSeed, ULONG ulFlags)

Computes a CRC for a specific buffer.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG or CR_INVALID_POINTER.
pBuffer
Address of the buffer buffer to be "CRC"ed.
ulSize
Length of pBuffer.
pulSeed
As input, it is the seed which should be 0 on the first call. As output, it contains the result which can be used as seed for the next call.
ulFlags
Must be zero.

For now, we just do CRC-16 bits.

See Also

CONFIGMG_Load_DLVxDs


CONFIGMG_Get_DDBs

CONFIGRET CONFIGMG_Get_DDBs(PPPVMMDDB pppDDB, PFARULONG pulCount, LOAD_TYPE LoadType, DEVNODE dnDevNode, ULONG ulFlags)

Retrieves the device descriptor blocks (DDBs) of dynamically loadable VxDs for a devnode.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_API, CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_LOAD_TYPE or CR_INVALID_POINTER.
pppDDB
Address of a pointer that receives the address of the DDBs table. If the pppDDB is NULL when the function returns, the VxD that controls the device node specified in the dnDevNode where not loaded via CM_Load_DLVxDsdynamically loadable VxD. Otherwise the DDBs are stored as an array at the given address.
pulCount
Returns the number of DDBs in the table.
LoadType
Type of the VxD being loaded. This parameter can be one of the values listed for the LoadType parameter in the CONFIGMG_Load_DLVxDs function.
dnDevNode
Device node identifying the dynamically loadable VxD.
ulFlags
Must be zero.

See Also

CONFIGMG_Load_DLVxDs


CONFIGMG_Get_Depth

CONFIGRET CONFIGMG_Get_Depth(PFARULONG pulDepth, DEVNODE dnDevNode, ULONG ulFlags)

Retrieves the depth of a device node in the hardware tree.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG or CR_INVALID_POINTER.
pulDepth
Address that receives the depth of the device node. This value is 0 to designate the root of the tree, 1 to designate a child of the root, and so on.
dnDevNode
Handle of a device node.
ulFlags
Must be zero.

This function can be used to optimize the handling of device nodes. For example, a device driver could determine the relative depths of two device nodes before processing only its immediate children.


CONFIGMG_Get_Device_Driver_Private_DWord

CONFIGRET CONFIGMG_Get_Device_Driver_Private_DWord(DEVNODE dnDevNode, PFARULONG pulDWord, ULONG ulFlags)

Retrieves the private value for a device driver in a device node.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG or CR_INVALID_POINTER.
dnDevNode
Handle of the device node in which the private value will be stored.
pulDWord
Address that receives the private value.
ulFlags
Must be zero.

This function is typically used by a device driver to retrieve information that was cached (usually a pointer to memory). The value is the same as passed when Config Manager call the device driver.

See Also

CONFIGMG_Set_Device_Driver_Private_DWord


CONFIGMG_Get_Device_ID

CONFIGRET CONFIGMG_Get_Device_ID(DEVNODE dnDevNode, PFARVOID Buffer, ULONG BufferLen, ULONG ulFlags)

Retrieves the device identifier for a device node.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_BUFFER_SMALL, CR_INVALID_DEVNODE, CR_INVALID_FLAG or CR_INVALID_POINTER.
dnDevNode
Handle of a device node we want the device ID of.
Buffer
Address of buffer that receives the device identifier. If this buffer is larger than the device identifier, the function appends a null-terminating character to the data. If it is smaller than the device identifier, the function fills it with as much of the device identifier as will fit and returns CR_BUFFER_SMALL.
BufferLen
The size, in bytes, of the buffer for the device identifier.
ulFlags
Must be zero.

To ensure that the buffer pointed to by the Buffer parameter is large enough to hold the entire device identifier, device drivers can call the CONFIGMG_Get_Device_ID_Size function.

Example

Code that retrieves a device identifier might look like the following example:

CM_Get_Device_ID_Size(&size, dnDevNode, 0);
if (p=malloc(size+1))
        CM_Get_Device_ID(dnDevNode, p, size+1, 0);

See Also

CONFIGMG_Get_Device_ID_Size


CONFIGMG_Get_Device_ID_Size

CONFIGRET CONFIGMG_Get_Device_ID_Size(PFARULONG pulLen, DEVNODE dnDevNode, ULONG ulFlags)

Retrieves the size of a device identifier from a device node.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG or CR_INVALID_POINTER.
pulLen
Address that receives the length of the device identifier. This length does not include the null-terminating character. This address is filled with zeroes if there is no identifier. The length is always less than or equal MAX_DEVICE_ID_LEN.
dnDevNode
Handle of a device node.
ulFlags
Must be zero.

The device node's device identifier is built from the identifier of the enumerator immediately above this device in the hardware tree, this device's identifier, and this device's instance. For example, the device identifier for an Adaptec 1540c might be \isaenum\aha1540c\1. This string is used as the direct key for access into the registry. The device identifier is limited to MAX_DEVICE_ID_LEN bytes.

See Also

CONFIGMG_Get_Device_ID


CONFIGMG_Get_DevNode_Key

CONFIGRET CONFIGMG_Get_DevNode_Key(DEVNODE dnDevNode, PFARCHAR pszSubKey, PFARVOID Buffer, ULONG BufferLen, ULONG ulFlags)

Retrieves the string of registry key from a device node.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_POINTER, CR_BUFFER_SMALL or CR_NO_REGISTRY_HANDLE.
dnDevNode
Handle of a device node.
pszSubKey
Name of the subkey. Can be NULL if none.
Buffer
Address of the buffer that receives the registry key. The length is always less than or equal MAX_VMM_REG_KEY_LEN.
BufferLen
Size of the buffer.
ulFlags
Must be a combination of the following.
CM_REGISTRY_HARDWARE | Select the hardware branch.
CM_REGISTRY_SOFTWARE | Select the software branch.
CM_REGISTRY_USER | Use HKEY_CURRENT_USER.
CM_REGISTRY_CONFIG | Use HKEY_CURRENT_CONFIG.

See Also

CONFIGMG_Get_DevNode_Key_Size


CONFIGMG_Get_DevNode_Key_Size

CONFIGRET CONFIGMG_Get_DevNode_Key_Size(PFARULONG pulLen, DEVNODE dnDevNode, PFARCHAR pszSubKey, ULONG ulFlags)

Retrieves the size of the registry key from a device node.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_POINTER, or CR_NO_REGISTRY_HANDLE.
pulLen
Address that receives the length of the registry key. This length does not include the null-terminating character. This address is filled with zeroes if there is no identifier. The length is always less than or equal MAX_VMM_REG_KEY_LEN.
dnDevNode
Handle of a device node.
pszSubKey
Name of the subkey. Can be NULL if none.
ulFlags
Must be a combination of the following.
CM_REGISTRY_HARDWARE | Select the hardware branch.
CM_REGISTRY_SOFTWARE | Select the software branch.
CM_REGISTRY_USER | Use HKEY_CURRENT_USER.
CM_REGISTRY_CONFIG | Use HKEY_CURRENT_CONFIG.

See Also

CONFIGMG_Get_DevNode_Key


CONFIGMG_Get_DevNode_Status

CONFIGRET CONFIGMG_Get_DevNode_Status(PFARULONG pulStatus, PFARULONG pulProblemNumber, DEVNODE dnDevNode, ULONG ulFlags)

Retrieves the status of a device node.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG or CR_INVALID_POINTER.
pulStatus
Address that receives the status flags of the device node. These flags can be a combination of the following values.
DN_DRIVER_LOADED | CONFIGMG_Register_Device_Driver has been called for this device node.
DN_ENUM_LOADED | CONFIGMG_Register_Enumerator has been called for this device node.
DN_HARDWARE_ENUM | Enumeration generates hardware identifier.
DN_HAS_MARK | CONFIGMG_Create_DevNode has failed in a call for this device node.
DN_HAS_PROBLEM | The device installer is required to resolve conflicts.
DN_LIAR | Device node reported reconfiguration falsely once.
DN_NEED_TO_CONFIG | Device node may need reconfiguration. This flag can be changed asynchronously.
DN_NEED_TO_ENUM | Device node may need reenumeration. This flag can be changed asynchronously.
DN_NOT_FIRST_TIME | Device node has received a configuration.
DN_ROOT_ENUMERATED | Device node was enumerated by the root.
DN_STARTED | Device node is currently configured.

pulProblemNumber
Address that receives an identifier indicating the problem. This identifier can be one of the following.
CM_PROB_BOOT_CONFIG_CONFLICT | Conflict in boot configuration.
CM_PROB_DEVICE_NOT_THERE | Specified device does not exist.
CM_PROB_DEVLOADER_FAILED | Device loader failed.
CM_PROB_DEVLOADER_NOT_READY | Device loader is not ready.
CM_PROB_DISABLED | Device is disabled.
CM_PROB_ENTRY_IS_WRONG_TYPE | Registry value has different type.
CM_PROB_FAILED_FILTER | Filter failed.
CM_PROB_NO_CONFIGURED | No configuration for this device.
CM_PROB_NORMAL_CONFLICT | Configuration conflict.
CM_PROB_OUT_OF_MEMORY | Out of memory.
CM_PROB_REGISTRY | Unable to access the registry.
CM_PROB_VXDLDR | Failure using the VxD loader.

dnDevNode
Device node for which the status flags are retrieved.
ulFlags
Must be zero.


CONFIGMG_Get_First_Log_Conf

CONFIGRET CONFIGMG_Get_First_Log_Conf(PLOG_CONF plcLogConf, DEVNODE dnDevNode, ULONG ulFlags)

Returns a handle to the first logical configuration of the specified type in a device node.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_POINTER or CR_NO_MORE_LOG_CONF.
plcLogConf
Address that receives the handle of the logical configuration.
dnDevNode
Device node for which the logical configuration is retrieved.
ulFlags
One of the following values.
ALLOC_LOG_CONF | Specifies the Alloc Element.
BASIC_LOG_CONF | Specifies the requirements list.
BOOT_LOG_CONF | Specifies the boot Alloc Element.
FILTERED_LOG_CONF | Specifies the filtered requirements list.

An initializing device driver typically requests the BASIC_LOG_CONF to verify the work of the enumerator. Sometimes the initializing driver may also check BOOT_LOG_CONF. Drivers typically check FILTERED_LOG_CONF while processing the CONFIG_FILTER device-driver configuration function. ALLOC_LOG_CONF is typically checked while processing CONFIG_DYNAMIC_START, CONFIG_DYNAMIC_STOP, CONFIG_FIRST_CONFIG and CONFIG_REMOVE.

Note Calling CONFIGMG_Add_Empty_Log_Conf or CONFIGMG_Free_Log_Conf from within a CONFIGMG_Get_First_Log_Conf/CONFIGMG_Get_Next_Log_Conf loop may have unwelcome side effects. Drivers should end the loop before adding or freeing a logical configuration and start it again when the operation is finished.

See Also

CONFIGMG_Add_Empty_Log_Conf, CONFIGMG_Free_Log_Conf, CONFIGMG_Get_Next_Log_Conf


CONFIGMG_Get_Hardware_Profile_Info

CONFIGRET CONFIGMG_Get_Hardware_Profile_Info(ULONG ulIndex, PHWPROFILEINFO pHWProfileInfo, ULONG ulFlags)

Get inpormation about a hardware profile.

  • Returns CR_SUCCESS if the function is successful, CR_NO_MORE_DEVNODES if ulIndex is larger than the number of hardware profiles on the computer. Otherwise, the return value can be CR_INVALID_POINTER or CR_INVALID_FLAG.
ulIndex
The index of the hardware profile to examine. Hardware profiles go from 0 to the number of hardware profiles-1. A ulIndex value of 0xFFFFFFFF is the same as the index of the current hardware profile.
pHWProfileInfo
Structure to be filled.
ulFlags
Must be zero.


CONFIGMG_Get_HW_Prof_Flags

CONFIGRET CONFIGMG_Get_HW_Prof_Flags(PCHAR szDevNodeName, ULONG ulConfig, PULONG pulValue, ULONG ulFlags)

Get the Config-Specific Config flags for a devnode/hardware profile combination.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_POINTER or CR_REGISTRY_ERROR.
szDevNodeName
The name of the devnode to query.
ulConfig
The hardware profile number to query. A ulConfig value of 0 indicates the current hardware profile should be queried.
pulValue
Points to the location to store the Config-Specific Config flags.
ulFlags
Must be zero.

See Also

CONFIGMG_Set_HW_Prof_Flags


CONFIGMG_Get_Next_Log_Conf

CONFIGRET CONFIGMG_Get_Next_Log_Conf(PLOG_CONF plcLogConf, LOG_CONF lcLogConf, ULONG ulFlags)

Returns a handle to the next logical configuration following the given configuration.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_LOG_CONF, CR_INVALID_POINTER or CR_NO_MORE_LOG_CONF.
plcLogConf
Address receiving the handle of the next logical configuration.
lcLogConf
Logical configuration prior to the configuration whose handle is being retrieved. Note that the logical configurations are in priority order.
ulFlags
Must be zero.

When this function is called with a logical configuration that was obtained using the CONFIGMG_Get_First_Log_Conf function with either the ALLOC_LOG_CONF or BOOT_LOG_CONF flag it necessarily returns CR_NO_MORE_LOG_CONF. (There is only one active boot or currently allocated logical configuration.)

Note Calling CONFIGMG_Add_Empty_Log_Conf or CONFIGMG_Free_Log_Conf from within a CONFIGMG_Get_First_Log_Conf/CONFIGMG_Get_Next_Log_Conf loop may have unwelcome side effects. Drivers should end the loop before adding or freeing a logical configuration and start it again when the operation is finished.

See Also

CONFIGMG_Add_Empty_Log_Conf, CONFIGMG_Free_Log_Conf, CONFIGMG_Get_First_Log_Conf


CONFIGMG_Get_Next_Res_Des

CONFIGRET CONFIGMG_Get_Next_Res_Des(PRES_DES prdResDes, RES_DES rdResDes, RESOURCEID ForResource, PRESOURCEID pResourceID, ULONG ulFlags)

Retrieves the handle of the next resource descriptor in a logical configuration.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_POINTER, CR_INVALID_LOG_CONF, CR_INVALID_RES_DES or CR_NO_MORE_RES_DES.
prdResDes
Address that receives the handle of the next resource descriptor.
rdResDes
Handle of the current resource descriptor or the handle of a logical configuration. (Both are 32-bit numbers; Configuration Manager can distinguish between them.)
ForResource
One of the resource identifiers listed in the ResourceId parameter of the CONFIGMG_Add_Res_Des function, or ResType_All. If this parameter is ResType_All, the function returns the handle of the next resource descriptor, no matter what its type. Otherwise, the function retrieves the handle of the first resource descriptor of the specified type.
pResourceID
Address that receives the resource type, when ForResource specifies ResType_All. (When ForResource is not ResType_All, this parameter can be NULL.)
ulFlags
Must be zero.

See Also

CONFIGMG_Get_Res_Des_Data, CONFIGMG_Get_Res_Des_Data_Size


CONFIGMG_Get_Parent

CONFIGRET CONFIGMG_Get_Parent(PDEVNODE pdnDevNode, DEVNODE dnDevNode, ULONG ulFlags)

Retrieves the handle of the parent of a device node.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_POINTER or CR_NO_SUCH_DEVNODE.
pdnDevNode
Address that receives a handle to the parent device node.
dnDevNode
Handle of the child device node.
ulFlags
Must be zero.

This function is called by any device driver that needs to walk the hardware tree.

See Also

CONFIGMG_Get_Child, CONFIGMG_Get_Sibling


CONFIGMG_Get_Performance_Info

CONFIGRET CONFIGMG_Get_Performance_Info(PCMPERFINFO pPerfInfo, ULONG ulFlags)

This API works only in MAXDEBUG. It returns or reset performance info in a buffer.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_FAILURE (CM_PERFORMANCE_INFO was not defined) or CR_INVALID_POINTER.
pPerfInfo
Address that will receive the size (in bytes) of the resource-descriptor header.
ulFlags
Must be one of CM_PERFORMANCE_INFO_GET_DATA CM_PERFORMANCE_INFO_RESET, CM_PERFORMANCE_INFO_START or CM_PERFORMANCE_INFO_STOP.


CONFIGMG_Get_Private_DWord

CONFIGRET CONFIGMG_Get_Private_DWord(PFARULONG pulPrivate, DEVNODE dnInDevNode, DEVNODE dnForDevNode, ULONG ulFlags)

Retrieves the private value a device node has in another device node.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG or CR_INVALID_POINTER.
pulPrivate
Address that receives the private value.
dnInDevNode
Handle of the device node in which the private value will be stored.
dnForDevNode
Handle of the device node that will use this information. This device node must be either the same as dnInDevNode or an ancestor of dnInDevNode.
ulFlags
Must be zero.

Neither dnInDevNode nor dnForDevNode may specify the root of the hardware tree.

This function is typically used by an enumerator to retrieve information that was cached in a one of their children's device nodes using the CONFIGMG_Set_Private_DWord function. The private double-word value is typically a pointer to a structure.

Note The device node specified by the dnForDevNode parameter is responsible for cleaning up when the device node is removed.

See Also

CONFIGMG_Set_Private_DWord


CONFIGMG_Get_Res_Des_Data

CONFIGRET CONFIGMG_Get_Res_Des_Data(RES_DES rdResDes, PFARVOID Buffer, ULONG BufferLen, ULONG ulFlags)

Copies the data from a specified resource descriptor into a buffer.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_BUFFER_SMALL, CR_INVALID_FLAG, CR_INVALID_POINTER or CR_INVALID_RES_DES.
rdResDes
Resource descriptor from which data is copied.
Buffer
Address of buffer that receives the data.
BufferLen
Size of Buffer, in bytes.
ulFlags
Must be zero.

Typically the size of the buffer is determined by a previous call to CONFIGMG_Get_Res_Des_Data_Size. If the value given in the BufferLen parameter is too small, the data is truncated, and the function returns CR_BUFFER_SMALL.

See Also

CONFIGMG_Get_Res_Des_Data_Size


CONFIGMG_Get_Res_Des_Data_Size

CONFIGRET CONFIGMG_Get_Res_Des_Data_Size(PFARULONG pulSize, RES_DES rdResDes, ULONG ulFlags)

Retrieves the size of a resource descriptor, not including the resource-descriptor header.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_POINTER or CR_INVALID_RES_DES.
pulSize
Address that receives the size, in bytes, of the resource descriptor's data.
rdResDes
Handle of the resource descriptor whose size is being queried.
ulFlags
Must be zero.

See Also

CONFIGMG_Get_Res_Des_Data


CONFIGMG_Get_Sibling

CONFIGRET CONFIGMG_Get_Sibling(PDEVNODE pdnDevNode, DEVNODE dnDevNode, ULONG ulFlags)

Retrieves the sibling of a device node.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_POINTER or CR_NO_SUCH_DEVNODE.
pdnDevNode
Address that receives a handle to the sibling device node.
dnDevNode
Handle of a device node.
ulFlags
Must be zero.

This function can be called in a loop to retrieve all the siblings of a device node. When the function returns CR_NO_SUCH_DEVNODE, the device node has no more siblings.

See Also

CONFIGMG_Get_Child, CONFIGMG_Get_Parent


CONFIGMG_Get_Version

CONFIGRET CONFIGMG_Get_Version()

Retrieves Configuration Manager's version number.

  • The high byte of the return value is the major revision number and the low byte is the minor revision number. The high word is not used. This is the only service where the result is not a CR_ something.

For example, version 4.0 of Configuration Manager returns 0x0400. This function currently returns 0x0400.


CONFIGMG_Initialize

CONFIGRET CONFIGMG_Initialize(ULONG ulFlags)

Ensures that Configuration Manager is ready to accept function calls, by creating the root node of the hardware tree and installing and allocating the required resources. This function is typically called only by VMM and VXDLDR. No other VxD should call this function.

  • Returns CR_SUCCESS if the function is successful. Does not return otherwise.
ulFlags
Must be either CM_INITIALIZE_VMM (the VMM is initializing Configuration Manager prior to Sys_Critical_Init) or CM_INITIALIZE_VXDLDR (VXDLDR is ready).

Only internal Windows 95 components use this function.


CONFIGMG_Intersect_Range_List

CONFIGRET CONFIGMG_Intersect_Range_List(RANGE_LIST rlhOld1, RANGE_LIST rlhOld2, RANGE_LIST rlhNew, ULONG ulFlags)

Creates a range list from the intersection of two specified range lists.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_RANGE_LIST or CR_OUT_OF_MEMORY.
rlhOld1
Handle of a range list to be used as part of the intersection.
rlhOld2
Handle of a range list to be used as part of the intersection.
rlhNew
Handle of a valid range list that represents the intersection of rlhOld1 and rlhOld2. Anything contained in the rlhNew range list is removed by the operation.
ulFlags
Must be zero.

If this function returns CR_OUT_OF_MEMORY, rlhNew is the handle of a valid but empty range list.

See Also

CONFIGMG_Merge_Range_List


CONFIGMG_Invert_Range_List

CONFIGRET CONFIGMG_Invert_Range_List(RANGE_LIST rlhOld, RANGE_LIST rlhNew, ULONG ulFlags, ULONG ulFlags)

Creates a range list that is the inverse of a specified range list; all claimed memory ranges in the new list are specified as free in the old list, and vice-versa.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_RANGE_LIST or CR_OUT_OF_MEMORY.
rlhOld
Handle of the range list to be inverted.
rlhNew
Handle of a valid range list that receives the inverted copy of rlhOld. Anything contained in the rlhNew range list is removed by the operation.
ulFlags
Uppermost value of the inverted range list.
ulFlags
Must be zero.

For example, the inversion of {[2, 4], [6, 8]} when the ulMaxValue parameter is 15 is {[0, 1], [5, 5], [9, 15}.

If this function returns CR_OUT_OF_MEMORY, rlhNew is the handle of a valid but empty range list.


CONFIGMG_ISAPNP_To_CM

CONFIGRET CONFIGMG_ISAPNP_To_CM(PBYTE pBuffer, DEVNODE dnDevNode, ULONG ulLogDev, ULONG ulFlags)

Converts ISAPNP requirements and adds them to a specified device node.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_DEVNODE_HAS_REQS, CR_INVALID_DATA, CR_INVALID_DEVNODE, CR_OUT_OF_MEMORY, CR_NO_SUCH_LOG_DEV, CR_INVALID_FLAG or CR_INVALID_POINTER.
pBuffer
Address of a buffer that contains the ISAPNP requirement information. This information normally starts with a Plug and Play version number tag.
dnDevNode
Device node that receives the converted requirements. This device node must not already contain a logical configuration (requirements).
ulLogDev
Logical device number starting with 0.
ulFlags
Must be either CM_ISAPNP_ADD_RES_DES if using this API to convert resource data into a BASIC_LOG_CONF, CM_ISAPNP_ADD_BOOT_RES_DES if using this API to convert resource data into a BOOT_LOG_CONF. Otherwise it must be CM_ISAPNP_SETUP to do a setup on those values.


CONFIGMG_Load_DLVxDs

CONFIGRET CONFIGMG_Load_DLVxDs(DEVNODE dnDevNode, PFARCHAR FileNames, LOAD_TYPE LoadType, ULONG ulFlags)

Loads dynamically loadable VxDs for a devnode.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_LOAD_TYPE, CR_INVALID_POINTER, CR_FAILURE, CR_OUT_OF_MEMORY, CR_NOT_SYSTEM_VM or CR_DLVXD_NOT_FOUND.
dnDevNode
Device node for which a device driver or enumerator should be loaded.
FileNames
Filenames for the dynamically loadable VxD. Note that the .386 extension is required. If no path is specified, the function searches for the files the same way OpenFile does. The files can be space or comma delimited.
LoadType
Type of the VxD being loaded. This parameter can be one of the following values.
DLVXD_LOAD_DEVLOADER | Load as a device loader. (This type is rarely used.)
DLVXD_LOAD_DRIVER | Load as a device driver.
DLVXD_LOAD_ENUMERATOR | Load as an enumerator.

ulFlags
Must be zero.


CONFIGMG_Locate_DevNode

CONFIGRET CONFIGMG_Locate_DevNode(PDEVNODE pdnDevNode, DEVNODEID pDeviceID, ULONG ulFlags)

Retrieves a pointer to the device node corresponding to a specified device identifier.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVICE_ID, CR_INVALID_FLAG, CR_INVALID_POINTER or CR_NO_SUCH_DEVNODE.
pdnDevNode
Address that receives the handle of a device node.
pDeviceID
Address of a null-terminated string specifying a device identifier. This string is also the name of the corresponding registry key. If this parameter is NULL, the function retrieves a handle to the device node at the root of the hardware tree.
ulFlags
Must be zero.


CONFIGMG_Lock

CONFIGRET CONFIGMG_Lock(ULONG ulFlags)

Prevents Configuration Manager from sending events.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG.
ulFlags
Must be zero.

This function increments a counting semaphore that prevents Configuration Manager from sending events. Since Configuration Manager processes events during the system task time but with interrupts disabled at the critical places, there is little need to bracket a linear piece of VxD code or an interrupt handler.

This function is asynchronous (that is, callable at interrupt time), reentrant, and fast.

See Also

CONFIGMG_Process_Events_Now, CONFIGMG_Unlock


CONFIGMG_Merge_Range_List

CONFIGRET CONFIGMG_Merge_Range_List(RANGE_LIST rlhOld1, RANGE_LIST rlhOld2, RANGE_LIST rlhNew, ULONG ulFlags)

Creates a range list from the union of two specified range lists.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_RANGE_LIST or CR_OUT_OF_MEMORY.
rlhOld1
Handle of a range list to be used as part of the union.
rlhOld2
Handle of a range list to be used as part of the union.
rlhNew
Handle of a valid range list that represents the union of rlhOld1 and rlhOld2. Anything contained in the rlhNew range list is removed by the operation.
ulFlags
Must be zero.

If this function returns CR_OUT_OF_MEMORY, rlhNew is the handle of a valid but empty range list.

See Also

CONFIGMG_Intersect_Range_List


CONFIGMG_Modify_Res_Des

CONFIGRET CONFIGMG_Modify_Res_Des(PRES_DES prdResDes, RES_DES rdResDes, RESOURCEID ResourceID, PFARVOID ResourceData, ULONG ResourceLen, ULONG ulFlags)

Modifies a resource descriptor.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_POINTER, CR_INVALID_RES_DES, CR_INVALID_DEVNODE or CR_OUT_OF_MEMORY.
prdResDes
Address that receives the handle of the modified resource descriptor.
rdResDes
Handle of the resource descriptor to be modified.
ResourceID
One of the resource identifiers given in the ResourceId parameter of the CONFIGMG_Add_Res_Des function, ResType_All, or ResType_None. If this parameter is a resource type, the resource descriptor changes to have this type. If it is ResType_All, the previous resource type is preserved. If it is ResType_None, the resource descriptor is ignored, because arbitrators for ResType_None always succeed.
ResourceData
Address of a resource data structure.
ResourceLen
The size, in bytes, of the new resource data structure. (The new size can be different from the size before the modifications were made.)
ulFlags
Must be zero.

This function retrieves a handle to the new resource descriptor. This may or may not be the handle of the unmodified resource descriptor. The previous resource descriptor is invalid after calling this function.

See Also

CONFIGMG_Add_Res_Des


CONFIGMG_Move_DevNode

CONFIGRET CONFIGMG_Move_DevNode(DEVNODE dnFromDevNode, DEVNODE dnToDevNode, ULONG ulFlags)

Replace a root enumerated devnode by the valid non-root enumerated devnode.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_DEVNODE, CR_OUT_OF_MEMORY or CR_NOT_SYSTEM_VM.
dnFromDevNode
Handle of the device node that has been root enumerated.
dnToDevNode
Handle of the device node that is a reenumeration of a root devnode.
ulFlags
Must be zero.

This function is used by the device installer when it detects that a non-root enumerate devnode is really the same as its root enumerated counterpart. This function rename the root-enumerated devnode with the new name (so that for the current session, people using CONFIGMG_Read/Write_Registry go to the appropriate place) and mark the root enumerated devnode has having a problem.


CONFIGMG_Next_Range

CONFIGRET CONFIGMG_Next_Range(PRANGE_ELEMENT preElement, PULONG pulStart, PULONG pulEnd, ULONG ulFlags)

Returns the next range element in a range list.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_FAILURE, CR_INVALID_FLAG, CR_INVALID_POINTER or CR_INVALID_RANGE.
preElement
Address of the handle of a range element. If this function is successful, this parameter points to the handle of the next range element when the function returns.
pulStart
Address that receives the starting value of the first range.
pulEnd
Address that receives the ending value of the first range.
ulFlags
Must be zero.

This function returns CR_FAILURE if there are no more elements in the range list.

See Also

CONFIGMG_First_Range


CONFIGMG_Process_Events_Now

CONFIGRET CONFIGMG_Process_Events_Now(ULONG ulFlags)

Forces event processing to occur immediately.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG or CR_NOT_SYSTEM_VM.
ulFlags
Must be zero.

There is no reason a standard device driver would ever call this function. It is meant to localize the event processing when debugging Configuration Manager using a Windows application. The application would call CONFIGMG_Lock, any required Configuration Manager functions, CONFIGMG_Process_Events_Now, and CONFIGMG_Unlock. Note that this function overides the locking mechanism.

See Also

CONFIGMG_Lock, CONFIGMG_Unlock


CONFIGMG_Query_Arbitrator_Free_Data

CONFIGRET CONFIGMG_Query_Arbitrator_Free_Data(PFARVOID pData, ULONG DataLen, DEVNODE dnDevNode, RESOURCEID ResourceID, ULONG ulFlags)

Returns arbitrator-specific free information.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_BUFFER_SMALL, CR_FAILURE, CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_POINTER, CR_INVALID_RESOURCEID or CR_NO_ARBITRATOR.
pData
Address of a buffer that receives the free information. This information is arbitrator specific.
DataLen
The size (in bytes) of the data buffer.
dnDevNode
Device node associated with the arbitrator. This is most meaningful for local arbitrators. (Although any device node can be used for global arbitrators, this parameter should specify the root or NULL in that case.)
ResourceID
One of the resource identifiers listed in the ResourceId parameter of the CONFIGMG_Add_Res_Des function. This function returns CR_INVALID_RESOURCEID if this value is ResType_All or ResType_None.
ulFlags
Must be zero.

This function succeeds even when it returns CR_BUFFER_SMALL. To avoid this error, call CONFIGMG_Query_Arbitrator_Free_Size before calling this function.

See Also

CONFIGMG_Add_Res_Des, CONFIGMG_Query_Arbitrator_Free_Size


CONFIGMG_Query_Arbitrator_Free_Size

CONFIGRET CONFIGMG_Query_Arbitrator_Free_Size(PFARULONG pulSize, DEVNODE dnDevNode, RESOURCEID ResourceID, ULONG ulFlags)

Retrieves the size of the free information the arbitrator would return in a call to the CONFIGMG_Query_Arbitrator_Free_Data function.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_FAILURE, CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_POINTER, CR_INVALID_RESOURCEID, CR_FAILURE or CR_NO_ARBITRATOR.
pulSize
Address that receives the size information.
dnDevNode
Device node associated with the arbitrator. This is most meaningful for local arbitrators. (Although any device node can be used for global arbitrators, this parameter should specify the root or NULL in that case.)
ResourceID
One of the resource identifiers listed in the ResourceId parameter of the CONFIGMG_Add_Res_Des function. This function returns CR_INVALID_RESOURCEID if this value is ResType_All or ResType_None.
ulFlags
Must be zero.

See Also

CONFIGMG_Add_Res_Des, CONFIGMG_Query_Arbitrator_Free_Data


CONFIGMG_Query_Change_Config

CONFIGRET CONFIGMG_Query_Change_Config(ULONG ulDock, ULONG ulSerialNo, ULONG ulFlags)

Determine if it is okay to change the current Hardware Profile.

  • Returns CR_SUCCESS if it is okay to change the hardware profile, CR_FAILURE if it is not okay. Otherwise, the return value can be CR_INVALID_FLAG, CR_NOT_SYSTEM_VM or CR_REGISTRY_ERROR.
ulDock
The Docking Station Identifier of the dock that the computer is attempting to connect to, 0 if unknown or if this is a request to undock.
ulSerialNo
The Docking Station Serial Number of the dock that the computer is attempting to connect to, 0 if unknown or if this is a request to undock.
ulFlags
Must be one of the following.
CM_HW_PROF_UNDOCK | The computer is attempting to undock.
CM_HW_PROF_DOCK | The computer is attempting to dock to an unidentified dock.
CM_HW_PROF_DOCK_KNOWN | The computer is attempting to dock to a known dock, which is identified by the ulDock and ulSerialNo paramters.

This function should only be called by a Plug and Play BIOS Enumerator. This function leaves some Root enumerated devnodes in an inactive state. After calling this function either CONFIGMG_Recompute_HW_Prof or CM_Fail_Change_HW_Prof must be called to return the Root enumerated devnodes to a normal state.

See Also

CONFIGMG_Recompute_HW_Prof


CONFIGMG_Query_Remove_SubTree

CONFIGRET CONFIGMG_Query_Remove_SubTree(DEVNODE dnAncestor, ULONG ulFlags)

Checks whether a device node and its progeny can be removed.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_REMOVE_VETOED, or CR_NOT_SYSTEM_VM.
dnAncestor
The root of the subtree whose removal is being queried.
ulFlags
Must be zero.

If the hardware can only detect removal, the enumerator should call CONFIGMG_Remove_SubTree; this is problematic, because it does not give applications the opportunity to close their files. If the hardware has an indication that the user wants to remove it (that is, if it is software-eject capable), the enumerator should follow the steps shown in this example:

if (CM_Query_Remove_Subtree(dnDevNode, 0)==CR_SUCCESS)
     CM_Remove_SubTree(dnDevNode, 0);

See Also

CONFIGMG_Remove_Subtree


CONFIGMG_Read_Registry_Log_Confs

CONFIGRET CONFIGMG_Read_Registry_Log_Confs(DEVNODE dnDevNode, ULONG ulFlags)

Retrieves logigal configuarations from the registry.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_OUT_OF_MEMORY, CR_INVALID_DATA, or CR_REGITRY_ERROR.
dnDevNode
Handle of a device node.
ulFlags
Must be zero.

This API is for the root enumerator, MCA and EISA bus driver. Instead of hardwarely detect the possible logical configurations, those enumerators rely on this API to read logical configurations from the hardware LogConfig subkey into the BASIC_LOG_CONF list.


CONFIGMG_Read_Registry_Value

CONFIGRET CONFIGMG_Read_Registry_Value(DEVNODE dnDevNode, PFARCHAR pszSubKey, PFARCHAR pszValueName, ULONG ulExpectedType, PFARVOID Buffer, PFARULONG pulLength, ULONG ulFlags)

Retrieves a value in the registry.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_POINTER, CR_NO_SUCH_VALUE, CR_WRONG_TYPE, CR_REGITRY_ERROR or CR_BUFFER_SMALL.
dnDevNode
Handle of a device node. The devnode can have a NULL device ID, but in this case, CR_NO_SUCH_VALUE is returned.
pszSubKey
Name of the subkey. Can be NULL if none.
pszValueName
Name of the value.
ulExpectedType
Either REG_SZ if a string is wanted or REG_BINARY if a binary value is wanted.
Buffer
Address of the buffer that receives the registry data. This can be NULL if you just want to get the size of the value.
pulLength
The length of the buffer (both input and output).
ulFlags
Must be a combination of the following.
CM_REGISTRY_HARDWARE | Select the hardware branch.
CM_REGISTRY_SOFTWARE | Select the software branch.
CM_REGISTRY_USER | Use HKEY_CURRENT_USER.
CM_REGISTRY_CONFIG | Use HKEY_CURRENT_CONFIG.

See Also

ONFIGMG_Write_Registry_Value


CONFIGMG_Recompute_HW_Prof

CONFIGRET CONFIGMG_Recompute_HW_Prof(ULONG ulDock, ULONG ulSerialNo, ULONG ulFlags)

Calculate the current Hardware Profile based on the Docking Station Identifier and the Docking Station Serial ID.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_FAILURE, CR_NOT_SYSTEM_VM or CR_REGISTRY_ERROR.
ulDock
The Docking Station Identifier if the computer is docked, 0 if the computer is undocked.
ulSerialNo
The Docking Station Serial Number if the computer is docked, 0 if the computer is undocked.
ulFlags
Must be one of the following.
CM_HW_PROF_UNDOCK | The computer is undocked.
CM_HW_PROF_DOCK | The computer is docked.

This function should only be called by a Plug and Play BIOS Enumerator, after a successful dock change.

See Also

CONFIGMG_Set_HW_Prof


CONFIGMG_Reenumerate_DevNode

CONFIGRET CONFIGMG_Reenumerate_DevNode(DEVNODE dnDevNode, ULONG ulFlags)

Causes the enumerator of the specified device node to receive the CONFIG_ENUMERATE enumerator function.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG. There is no checking of a valid devnode until later.
dnDevNode
The device node whose enumerator will be called.
ulFlags
Must be zero.

This function is asynchronous (that is, callable at interrupt time), reentrant, and fast.


CONFIGMG_Register_Arbitrator

CONFIGRET CONFIGMG_Register_Arbitrator(PREGISTERID pRid, RESOURCEID id, CMARBHANDLER Handler, ULONG ulDWordToBePassed, DEVNODE dnArbitratorNode, ULONG ulFlags)

Registers a resource arbitrator.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_API, CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_POINTER, CR_INVALID_RESOURCEID, CR_INVALID_ARBITRATOR or CR_OUT_OF_MEMORY.
pRid
Address that receives the registration identifier of the resource arbitrator.
id
The unique resource number as given or defined by Microsoft Corporation.
Handler
Arbitrator entry point. This is the routine that will handle all arbitrator functions. This parameter cannot be NULL.
ulDWordToBePassed
The value that is passed when calling the arbitrator.
dnArbitratorNode
Handle of the device node that owns this resource. This value is important for local arbitrators, but it can be NULL for a global arbitrator. This value is passed when calling the arbitrator.
ulFlags
Specifies whether the resource is global. If it is ARB_LOCAL, the resource is local to only the children of dnArbitratorNode. Otherwise, it is ARB_GLOBAL.

This function returns CR_INVALID_RESOURCEID if the ResType_Ignored_Bit set in the device identifier.

See Also

CONFIGMG_Deregister_Arbitrator


CONFIGMG_Register_Device_Driver

CONFIGRET CONFIGMG_Register_Device_Driver(DEVNODE dnDevNode, CMCONFIGHANDLER Handler, ULONG ulRefData, ULONG ulFlags)

Registers a configuration handler for a device node.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG or CR_NOT_SYSTEM_VM.
dnDevNode
Handle of a device node. This handle must have been created by a call to the CONFIGMG_Locate_DevNode or CONFIGMG_Create_DevNode function.
Handler
Device-driver entry point. This is the routine that will handle all device-driver configuration functions. This parameter can be NULL if the device driver does not need to monitor configuration events.
ulRefData
Data that will be passed back to the Handler.
ulFlags
Must be either CM_REGISTER_DEVICE_DRIVER_STATIC or a combination of CM_REGISTER_DEVICE_DRIVER_DISABLEABLE and/or CM_REGISTER_DEVICE_DRIVER_REMOVABLE.

This function must be called by any Plug and Play device that owns a device node. It should be called only when the initializing device driver is ready to start handling the device. Note that this API can be called from ring 3 but the handler needs to be NULL in that case.

See Also

CONFIGMG_Create_DevNode, CONFIGMG_Locate_DevNode


CONFIGMG_Register_DevLoader

CONFIGRET CONFIGMG_Register_DevLoader(PVMMDDB pDDB, ULONG ulFlags)

Specifies that a static VxD is ready to be a device loader.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_API or CR_INVALID_FLAG.
pDDB
The static VxD which is ready to be a device loader.
ulFlags
Must be zero.

If the DDB parameter is NULL or not valid, the function returns CR_SUCCESS but takes no action. Also, any PNP_NEW_DEVNODE will necessarily occur after this function returns (ie, on the next appy time).


CONFIGMG_Register_Enumerator

CONFIGRET CONFIGMG_Register_Enumerator(DEVNODE dnDevNode, CMENUMHANDLER Handler, ULONG ulFlags)

Registers the enumerator handler for a device node.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_API, CR_INVALID_DEVNODE or CR_INVALID_FLAG.
dnDevNode
Handle of a device node. This handle must have been created by a call to the CONFIGMG_Locate_DevNode or CONFIGMG_Create_DevNode function.
Handler
Enumerator entry point. This is the routine that will handle all enumerator calls. If this parameter is NULL, no enumerator is loaded.
ulFlags
CM_REGISTER_ENUMERATOR_HARDWARE iff the enumerator does hardware detection (ie know for sure the device is there or not. Otherwise, must be CM_REGISTER_ENUMERATOR_SOFWARE.

This function must be called whenever a device driver needs to be the enumerator for a device. This function should be called near the end of the initialization of an enumerator.

The Handler parameter is NULL when the device cannot be enumerated (as with VPICD, for example).

See Also

CONFIGMG_Create_DevNode, CONFIGMG_Locate_DevNode


CONFIGMG_Register_Enumerator_Function

CONFIGRET CONFIGMG_Register_Enumerator_Function(DEVNODE dnDevNode, CMENUMFUNCTION Handler, ULONG ulFlags)

Register a handler to handle enumerator specific functions.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_API or CR_INVALID_FLAG.
dnDevNode
Handle of a device node.
Handler
The callback address.
ulFlags
Must be zero.


CONFIGMG_Remove_SubTree

CONFIGRET CONFIGMG_Remove_SubTree(DEVNODE dnAncestor, ULONG ulFlags)

Removes a device node and its children.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG or CR_NOT_SYSTEM_VM.
dnAncestor
Handle of the device node that is being removed.
ulFlags
Must be zero.

Configuration Manager notifies each device node in the subtree of the dnAncestor parameter of its imminent termination and then, if possible, frees the device nodes. If a PCMCIA SCSI card were removed, for example, the PCMCIA driver would use this function to remove the entire subtree from the hardware tree.

See Also

CONFIGMG_Query_Remove_SubTree


CONFIGMG_Remove_Unmarked_Children

CONFIGRET CONFIGMG_Remove_Unmarked_Children(DEVNODE dnDevNode, ULONG ulFlags)

Removes any children of a device node for which the DN_HAS_MARK flag is cleared.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_NOT_SYSTEM_VM or CR_INVALID_FLAG.
dnDevNode
Device node that is the parent of the device nodes which are removed if their DN_HAS_MARK flag is cleared.
ulFlags
Must be zero.

See Also

CONFIGMG_Reset_Children_Marks


CONFIGMG_Reset_Children_Marks

CONFIGRET CONFIGMG_Reset_Children_Marks(DEVNODE dnDevNode, ULONG ulFlags)

Resets the DN_HAS_MARK flag in the children of a specified device node.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE or CR_INVALID_FLAG.
dnDevNode
Device node that is the parent of the device nodes whose DN_HAS_MARK flags are reset.
ulFlags
Must be zero.

See Also

CONFIGMG_Remove_Unmarked_Children


CONFIGMG_Run_Detection

CONFIGRET CONFIGMG_Run_Detection(ULONG ulFlags)

Ask CONFIGMG to spawn the detection DLL and run it.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG.
ulFlags
Must be zero.

This API will be used by devloader that detects a legacy card has been inserted.


CONFIGMG_Set_Bus_Info

CONFIGRET CONFIGMG_Set_Bus_Info(DEVNODE dnDevNode, CMBUSTYPE btBusType, ULONG ulSizeOfInfo, PFARVOID pInfo, ULONG ulFlags)

Set bus info in the devnode.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_DEVNODE, CR_INVALID_POINTER, CR_OUT_OF_MEMORY.
dnDevNode
Handle of a device node.
btBusType
The bus valud (one of BusType*).
ulSizeOfInfo
The size of the info buffer pointed by pInfo.
pInfo
A pointer to the bus-specific info.
ulFlags
Must be zero.

This function appends to the devnode some bus specific info. This function is to be used solely by the immediate parent enumerator of a devnode.

See Also

CONFIGMG_Get_Bus_Info


CONFIGMG_Set_Device_Driver_Private_DWord

CONFIGRET CONFIGMG_Set_Device_Driver_Private_DWord(DEVNODE dnDevNode, PFARULONG pulDWord, ULONG ulFlags)

Retrieves the private value for a device driver in a device node.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE or CR_INVALID_FLAG.
dnDevNode
Handle of the device node in which the private value will be stored.
pulDWord
Address that receives the private value.
ulFlags
Must be zero.

This function is typically used by a device driver to set information in this devnode cached (usually a pointer to memory).

Note The initial value is set by the parameter on the CONFIGMG_Register_Device_Driver (the value is zero before that call).

See Also

CONFIGMG_Get_Device_Driver_Private_DWord


CONFIGMG_Set_HW_Prof

CONFIGRET CONFIGMG_Set_HW_Prof(ULONG ulConfig, ULONG ulFlags)

Set the current Hardware Profile.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG CR_FAILURE, CR_NOT_SYSTEM_VM or CR_REGISTRY_ERROR.
ulConfig
The current hardware profile number.
ulFlags
Must be zero.

This function updates the HKEY_CURRENT_CONFIG predefined key in the registry, broadcasts a DBT_CONFIGCHANGED message, and reenumerates the Root devnode. It should only be called by the configuration manager and the control panel.

See Also

CONFIGMG_Recompute_HW_Prof


CONFIGMG_Set_HW_Prof_Flags

CONFIGRET CONFIGMG_Set_HW_Prof_Flags(PCHAR szDevNodeName, ULONG ulConfig, ULONG ulValue, ULONG ulFlags)

Set the Config-Specific Config flags for a devnode/hardware profile combination.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_NOT_SYSTEM_VM, CR_INVALID_POINTER or CR_REGISTRY_ERROR.
szDevNodeName
The name of the devnode to modify.
ulConfig
The hardware profile number to modify. A ulConfig value of zero indicates the current hardware profile should be modified.
ulValue
The new CSConfigFlags value. It may contain the following flags.
CSCONFIGFLAG_DISABLE | Disable the devnode in this hardware profile.
CSCONFIGFLAG_DO_NOT_CREATE | Do not allow this devnode to be created in this hardware profile.

ulFlags
Must be zero.

If the CONFIGFLAG_DO_NOT_CREATE bit is set for an existing devnode in the current hardware profile, it will be removed. If the CSCONFIGFLAG_DO_NOT_CREATE bit is cleared in the current hardware profile, the entire hardware tree will be reenumerated, so that the devnode's parent has the chance to create the devnode if necessary.

See Also

CONFIGMG_Set_HW_Prof_Flags

Built on Wednesday, July 11, 2001


CONFIGMG_Set_Private_DWord

CONFIGRET CONFIGMG_Set_Private_DWord(DEVNODE dnInDevNode, DEVNODE dnForDevNode, ULONG ulValue, ULONG ulFlags)

Sets the private value a device node has in another device node.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE or CR_INVALID_FLAG.
dnInDevNode
Handle of the device node in which the private value will be stored.
dnForDevNode
Handle of the device node that will use this information. This device node must be either the same as dnInDevNode or an ancestor of dnInDevNode.
ulValue
The private value to be stored. is the value to store.
ulFlags
Must be zero.

Neither dnInDevNode nor dnForDevNode may specify the root of the hardware tree.

This function is typically used by an enumerator to set information that will be retrieved using the CONFIGMG_Get_Private_DWord function. The private double-word value is typically a pointer to a structure.

The device node specified by the dnForDevNode parameter is responsible for cleaning up when the device node is removed.

See Also

CONFIGMG_Get_Private_DWord


CONFIGMG_Set_Private_Problem

CONFIGRET CONFIGMG_Set_Private_Problem(DEVNODE dnDevNode, ULONG ulRefData, ULONG ulFlags)

Make CONFIGMG call the Private API with that devnode and the reference data.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE or CR_INVALID_FLAG.
dnDevNode
Handle of a device node.
ulRefData
Reference data to pass to the class installer.
ulFlags
Must be zero.

This API does not disable the devnode.


CONFIGMG_Setup_DevNode

CONFIGRET CONFIGMG_Setup_DevNode(DEVNODE dnDevNode, ULONG ulFlags)

Reenables and configures a specified device node, or ask the enumerator to download information.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_DEVNODE, CR_NOT_SYSTEM_VM, CR_OUT_OF_MEMORY or CR_FAILURE.
dnDevNode
Device node which may be reconfigured.
ulFlags
Must be either CM_SETUP_DEVNODE_READY (for reenabling a devnode that had a problem) or CM_SETUP_DOWNLOAD (to ask the enumerator to download information).


CONFIGMG_Sort_NodeList

CONFIGRET CONFIGMG_Sort_NodeList(NODELIST_HEADER nlhNodeListHeader, ULONG ulFlags)

Sorts a list of nodes that has been passed to the handler of to a resource arbitrator.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_API, CR_INVALID_FLAG or CR_INVALID_NODELIST.
nlhNodeListHeader
Address of a NODELISTHEADER_S structure containing the elements to sort.
ulFlags
Must be zero.

This function is normally used by an arbitrator to sort the nodelist it is given during a call to the arbitrator's handler. Normally, an arbitrator sorts the nodelist by increasing ease of configuration; for example, an element that had only one possible IRQ would come before an element with 2 possible IRQs, and so on. The arbitrator must first do a linear scan of the nodelist initializing nl_ulSortDWord (the lower the value, the more at the begining the element will be).


CONFIGMG_Test_Range_Available

CONFIGRET CONFIGMG_Test_Range_Available(ULONG ulStartValue, ULONG ulEndValue, RANGE_LIST rlh, ULONG ulFlags)

Checks a memory range against a range list to ensure that no conflicts exist.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_FAILURE, CR_INVALID_FLAG, CR_INVALID_RANGE or CR_INVALID_RANGE_LIST.
ulStartValue
Low end of the range.
ulEndValue
High end of the range.
rlh
Handle of a range list.
ulFlags
Must be zero.


CONFIGMG_Unlock

CONFIGRET CONFIGMG_Unlock(ULONG ulFlags)

Reenables Configuration Manager events after a call to the CONFIGMG_Lock function.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG.
ulFlags
Must be zero.

This function decrements the counting semaphore that prevents Configuration Manager from sending events. If the count is zero, Configuration Manager begins sending events again. This function is asynchronous (that is, callable at interrupt time), reentrant, and fast.

See Also

CONFIGMG_Lock, CONFIGMG_Process_Events_Now


CONFIGMG_Write_Registry_Value

CONFIGRET CONFIGMG_Write_Registry_Value(DEVNODE dnDevNode, PFARCHAR pszSubKey, PFARCHAR pszValueName, ULONG ulType, PFARVOID Buffer, ULONG ulLength, ULONG ulFlags)

Sets a value in the registry.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_POINTER or CR_REGITRY_ERROR.
dnDevNode
Handle of a device node. The devnode cannot have a NULL device ID.
pszSubKey
Name of the subkey. Can be NULL if none.
pszValueName
Name of the value.
ulType
Either REG_SZ if a string is to be written or REG_BINARY if a binary value is to be written.
Buffer
Address of the buffer that contains the registry data to write.
ulLength
The length of the buffer.
ulFlags
Must be a combination of the following.
CM_REGISTRY_HARDWARE | Select the hardware branch.
CM_REGISTRY_SOFTWARE | Select the software branch
CM_REGISTRY_USER | Use HKEY_CURRENT_USER.
CM_REGISTRY_CONFIG | Use HKEY_CURRENT_CONFIG.

See Also

CONFIGMG_Read_Registry_Value


CONFIGMG_Yield

CONFIGRET CONFIGMG_Yield(ULONG ulMicroseconds, ULONG ulFlags)

Waits a specified number of microseconds.

  • Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INTERRUPTS_DISABLED or CR_INVALID_FLAG.
ulMicroseconds
The number of microseconds to wait. This value cannot be larger than 60000000L (60 seconds).
ulFlags
Flags controlling the resumption of execution. This parameter can be one of the following.
CM_YIELD_RESUME_EXEC | Enable software simulation of interrupts.
CM_YIELD_NO_RESUME_EXEC | Ensures no other VxD gets control (other than hardware interrupts).

A device driver calls this function during any configuration-handler function in which the adapter needs a delay. For example, some PCMCIA IO cards require a delay of several seconds before being configured or reconfigured to a specified IO space.


Callback Functions

This section describes the Configuration Manager functions.


ArbitrationHandler

CONFIGRET ArbitrationHandler(ARBFUNC afcFunc, ULONG ulRefData,
    DEVNODE dnDevNode, NODELIST_HEADER pnlhNodeListHeader);

An arbitrator-supplied function that processes arbitration messages for a device node.

  • Returns CR_SUCCESS if successful, or one of the error values given in Constants.
afcFunc
Arbitration message. Can be one of these values.
ARB_TEST_ALLOC | Check if requested allocation works.
ARB_RETEST_ALLOC | Check if previous allocation works.
ARB_SET_ALLOC | Set the tested allocation.
ARB_RELEASE_ALLOC | Release the tested allocation.
ARB_QUERY_FREE | Return free resource.
ARB_REMOVE | Device node is gone.
ARB_FORCE_ALLOC | Force previous TEST_ALLOC

ulRefData
32-bit reference data value. This is the 32-bit value specified in the call to the CONFIGMG_Register_Arbitrator service when the handler was registered.
dnDevNode
Handle of the device node associated with this arbitrator.
pnlhNodeListHeader
Address of a NODELIST_HEADER structure that contains information about the logical configurations of all devices to be be configured.


ConfigHandler

CONFIGRET ConfigHandler(CONFIGFUNC cfFunc,
    SUBCONFIGFUNC scfSubFunc, DEVNODE dnDevNode,
    DWORD dwRefData, ULONG ulFlags);

A driver-supplied function that processes configuration messages for a device node.

  • Returns CR_SUCCESS if successful, or one of the error values given in Constants.
cfFunc
Function identifier. Can be one of these values.
CONFIG_APM | APM functions.
CONFIG_CALLBACK | Devnode is being called back.
CONFIG_ENUMERATE | Devnode must enumerated.
CONFIG_FILTER | Ancestors must filter requirements.
CONFIG_PREREMOVE | Devnode must stop using config.
CONFIG_PREREMOVE2 | Devnode must stop using config.
CONFIG_READY | The devnode has been setup.
CONFIG_REMOVE | Devnode must stop using config.
CONFIG_SETUP | Devnode should download driver.
CONFIG_SHUTDOWN | We are shutting down.
CONFIG_START | Devnode dynamic initialization.
CONFIG_STOP | Devnode must stop using config.
CONFIG_TEST | Can devnode change state now.
CONFIG_TEST_FAILED | Continue as before after a TEST.
CONFIG_TEST_SUCCEEDED | Prepare for the STOP/REMOVE.
CONFIG_VERIFY_DEVICE | Insure the legacy card is there.

scfSubFunc
Subfunction identifier.
dnDevNode
Handle of the device node to process messages for.
dwRefData
32-bit reference data value. This is the 32-bit value passed to the CONFIGMG_Register_Device_Driver service when the handler was registered.
ulFlags
Reserved; must be 0.


EnumerationHandler

CONFIGRET EnumerationHandler(CONFIGFUNC cfFunc,
    SUBCONFIGFUNC scfSubFunc, DEVNODE dnToDevNode,
    DEVNODE dnAboutDevNode, ULONG ulFlags);

An enumerator-supplied function that processes enumeration messages for a device node.

  • Returns CR_SUCCESS if successful, or one of the error values given in Constants.
cfFunc
Function identifier. Can be one of these values.
CONFIG_APM | APM functions.
CONFIG_CALLBACK | Devnode is being called back.
CONFIG_ENUMERATE | Devnode must enumerated.
CONFIG_FILTER | Ancestors must filter requirements.
CONFIG_PREREMOVE | Devnode must stop using config.
CONFIG_PREREMOVE2 | Devnode must stop using config.
CONFIG_READY | The devnode has been setup.
CONFIG_REMOVE | Devnode must stop using config.
CONFIG_SETUP | Devnode should download driver.
CONFIG_SHUTDOWN | We are shutting down.
CONFIG_START | Devnode dynamic initialization.
CONFIG_STOP | Devnode must stop using config.
CONFIG_TEST | Can devnode change state now.
CONFIG_TEST_FAILED | Continue as before after a TEST.
CONFIG_TEST_SUCCEEDED | Prepare for the STOP/REMOVE.
CONFIG_VERIFY_DEVICE | Insure the legacy card is there.

scfSubFunc
Subfunction identifier.
dnToDevNode
Handle of the device node to process messages for.
dnAboutDevNode
Handle of the device node to which processing applies. This is typically a child of the device node specified by dnToDevNode.
ulFlags
Reserved; must be 0.


Messages

This section describes the Configuration Manager messages.


ARB_TEST_ALLOC

Sent to direct the arbitrator to test the given resource allocations. The arbitrator should attempt to satisfy all allocation requests contained in the node list for the resource. Depending on the result, the Configuration Manager subsequently sends either a ARB_SET_ALLOC or ARB_RELEASE_ALLOC message.

  • Returns CR_SUCCESS if allocation requests are satisfied, CR_FAILURE if not, or CR_OUT_OF_MEMORY if not enough memory to complete the test.

Generally, the arbitrator sorts the list according to most likely successful allocation order, makes a copy of the current allocation structure(s), releases all resources currently allocated to device nodes on the list, then attempts to satisfy allocation requests by passing through the entire list. The arbitrator tries all possible combinations of allocations and saves the successful allocations in both the node list for the device and the copy of the allocation data structure.


ARB_RETEST_ALLOC

Sent to direct the arbitrator to retest the given resource allocations. The arbitrator attempts to satisfy all allocation requests contained in the node list for the resource. Depending on the result, the Configuration Manager subsequently sends either a ARB_SET_ALLOC or ARB_RELEASE_ALLOC message.

  • Returns CR_SUCCESS if successful allocation, CR_FAILURE if unsuccessful allocation, or CR_OUT_OF_MEMORY if not enough memory.

The arbitrator starts with the result of a previous ARB_TEST_ALLOC message. Without sorting the node list, the arbitrator makes a copy of the current allocation structure(s), releases all resources currently allocated to device nodes on the list, then attempts to satisfy the allocations from the previous ARB_TEST_ALLOC message. The arbitrator saves the successful allocations in the allocation data structure.


ARB_FORCE_ALLOC

Sent to direct the arbitrator to retest, without failure, the given resource allocations. The arbitrator must satisfy all allocation requests contained in the node list for the resource. The Configuration Manager subsequently sends either a ARB_SET_ALLOC or ARB_RELEASE_ALLOC message.

  • Returns CR_SUCCESS or CR_OUT_OF_MEMORY if not enough memory to complete the test.

The arbitrator starts with the result of a previous ARB_TEST_ALLOC message. Without sorting the node list, the arbitrator makes a copy of the current allocation structure(s), releases all resources currently allocated to device nodes on the list, then attempts to satisfy the allocations from the previous ARB_TEST_ALLOC message. The arbitrator saves the successful allocations in the allocation data structure.


ARB_SET_ALLOC

Sent to direct the arbitrator to make a test allocation the real allocation. The arbitrator makes the copy of the allocation data structure the current valid allocation.

  • Returns CR_SUCCESS.


ARB_RELEASE_ALLOC

Sent to direct the arbitrator to clean up after a failed test allocation. The arbitrator should free all allocations made during the previous ARB_TEST_ALLOC message.

  • Returns CR_SUCCESS.


ARB_QUERY_FREE

Sent to request information about free resources for a logical configuration. The arbitrator should return resource-specific data on the free element.

  • Returns CR_SUCCESS if successful, CR_FAILURE if the request makes no sense, or CR_OUT_OF_MEMORY if not enough memory.
pnlhNodeListHeader
Address of an arbitfree_s structure.


ARB_REMOVE

Sent when the device node associated with the arbitration handler is being removed. The arbitrator should carry out appropriate clean up.

  • Returns CR_SUCCESS.


CONFIG_APM

Sent to notify a driver of a power management event. The driver should determine the type of event and take appropriate action.

  • Return CR_SUCCESS. On a request for permission, return CR_SUCCESS to grant permission, CR_FAILURE to deny it.
scfSubFunc
APM subfunction number. Can be one of these values.
CONFIG_APM_TEST_STANDBY | Request for permission to change to standby operation.
CONFIG_APM_TEST_SUSPEND | Request for permission to change to suspend operation.
CONFIG_APM_TEST_STANDBY_FAILED | Standby request denied.
CONFIG_APM_TEST_SUSPEND_FAILED | Suspend request denied.
CONFIG_APM_TEST_STANDBY_SUCCEEDED | Standby request granted.
CONFIG_APM_TEST_SUSPEND_SUCCEEDED | Suspend request granted.
CONFIG_APM_RESUME_STANDBY | Standby operation resuming.
CONFIG_APM_RESUME_SUSPEND | Suspend operation resuming.
CONFIG_APM_RESUME_CRITICAL | Critical operation resuming.

In standby operation, all devices remain generally responsive although in a lower power state. In suspend operation, you should assume that power and state of the device may be lost.


CONFIG_CALLBACK

Sent to a driver in a response to a request to be called back. The driver can carry out appropriate tasks.

  • Return CR_SUCCESS.


CONFIG_ENUMERATE

Sent to direct a driver to enumerate its immediate children. This message is sent in response to the insertion or removal of a device. An enumerator should create a device node for each child by using the CONFIGMG_Create_DevNode service or remove children by using the CONFIGMG_Remove_SubTree service as appropriate.

  • Return CR_SUCCESS.

The enumerator should add logical configurations for each newly created device node.


CONFIG_FILTER

Previous Next

CONFIG_FILTE

Sent to direct a driver to process a new device or changes to the configuration. Enumerators should retrieve the filtered logical configuration for the indicated device node and modify the requirements as needed. For example, the PCMCIA driver removes unsupported IRQs and pre-allocates IO port and memory ranges.

  • Return CR_SUCCESS.

Initially, the filtered requirements are identical to the basic requirements. An enumerator may alter the requirements of its own device node as well those of the indicated device node. When a device driver processes this message, it should look only at the filtered requirements list only.

Use the CONFIGMG_Get_First_Log_Conf or CONFIGMG_Get_Alloc_Log_Conf to retrieve the filtered logical configuration (FILTERED_LOG_CONF) for this device node.


CONFIG_PREREMOVE

Sent to direct the driver to stop using its allocated configuration. This message is intended to give the driver the chance to prepare for the removal of its device.

  • Return CR_SUCCESS.


CONFIG_PREREMOVE2

Sent to direct the driver to stop using its allocated configuration. This message is intended to give the driver the chance to prepare for the removal of its device.

  • Return CR_SUCCESS.


CONFIG_READY

Sent to notify the driver that the associated device node has been set up.

  • Return CR_SUCCESS.


CONFIG_REMOVE

Sent to notify the driver that the associated device node is being removed from the hardware tree. The driver should deallocate any instance data for the device node and take whatever other measures are necessary to stop using the device node, the associated hardware, and the allocated configuration.

  • Return CR_SUCCESS.
scfSubFunc
Subfunction number. Can be one of these values.
CONFIG_REMOVE_DYNAMIC | Removes a dynamically-loaded driver.
CONFIG_REMOVE_SHUTDOWN | Removes a driver as part of system shutdown.

This message is not always preceded by the CONFIG_TEST_CAN_REMOVE message.

Use the CONFIGMG_Get_First_Log_Conf or CONFIGMG_Get_Alloc_Log_Conf to retrieve the allocated logical configuration (ALLOC_LOG_CONF) for this device node.


CONFIG_SETUP

Sent to notify the driver that the device node has been setup. The driver should load additional drivers if possible. For example, the driver could load appropriate drivers from device ROM, such as for ISA_RTR, PCI and PCMCIA device.

  • Return CR_SUCCESS.


CONFIG_SHUTDOWN

Sent when the system is shutting down. The driver should free resources and shutdown its device.

  • Return CR_SUCCESS.


CONFIG_START

Sent when a configuration has been allocated for the device node. The driver can retrieve the allocated configuration and begin to use it.

CONFIG_START_DYNAMIC_START | Starting dynamically-loaded driver.
CONFIG_START_FIRST_START | Starting system for the first time.

Use the CONFIGMG_Get_First_Log_Conf or CONFIGMG_Get_Alloc_Log_Conf to retrieve the allocated logical configuration (ALLOC_LOG_CONF) for this device node.


CONFIG_STOP

Sent to direct the driver to stop using its current allocated configuration. The driver should stop using the resources in its allocated configuration until it receives a subsequent CONFIG_START message.

  • Return CR_SUCCESS.
scfSubFunc
Subfunction number. Can be one of these value.
CONFIG_STOP_DYNAMIC_STOP | Directs the driver to stop using the allocated configuration.
CONFIG_STOP_CHILD_FAILED_START | Driver for child device node failed to start.
CONFIG_STOP_HAS_PROBLEM | Driver has a driver-specific problem.

Use the CONFIGMG_Get_First_Log_Conf or CONFIGMG_Get_Alloc_Log_Conf to retrieve the allocated logical configuration (ALLOC_LOG_CONF) for this device node.


CONFIG_TEST

Sent to request permission to invalidate the assigned configuration or remove the given device node. The driver should not grant permission if it cannot stop using its current configuration or is not prepared for the device to be removed from the system.

  • Return CR_SUCCESS to grant permission, CR_FAILURE otherwise.
scfSubFunc
Subfunction number. Can be one of these values.
CONFIG_TEST_CAN_STOP | Request for permission to invalidate the configuration currently assigned to the driver.
CONFIG_TEST_CAN_REMOVE | Request for permission to remove the given device node.


CONFIG_TEST_FAILED

Sent to notify driver that the previous CONFIG_TEST message was canceled by a driver. The driver should continue operation as before receiving the CONFIG_TEST message.

  • eturn CR_SUCCESS.


CONFIG_TEST_SUCCEEDED

Sent to notify driver that the previous CONFIG_TEST message succeeded. This gives the driver an opportunity to prepare for the subsequent CONFIG_STOP or CONFIG_REMOVE message.

  • Return CR_SUCCESS.


CONFIG_VERIFY_DEVICE

Sent to verify that the given legacy card is present.

  • Return CR_SUCCESS if the card is present, CR_DEVICE_NOT_THERE otherwise.


Structures

This section describes the structures used with Configuration Manager services.


arbitfree_s

struct arbitfree_s {
    PVOID *af_PointerToInfo;  // the arbitrator info
    ULONG af_SizeOfInfo;      // size of the info
};

Contains information about a free element.


CMCONFIG

struct Config_Buff_s {
    WORD wNumMemWindows;   // Num memory windows
    DWORD dMemBase[MAX_MEM_REGISTERS];    // memory window base
    DWORD dMemLength[MAX_MEM_REGISTERS];  // memory window length
    WORD wMemAttrib[MAX_MEM_REGISTERS];   // memory window attrib
    WORD wNumIOPorts;                     // num IO ports
    WORD wIOPortBase[MAX_IO_PORTS];       // IO port base
    WORD wIOPortLength[MAX_IO_PORTS];     // IO port length
    WORD wNumIRQs;                        // num IRQ info
    BYTE bIRQRegisters[MAX_IRQS];         // IRQ list
    BYTE bIRQAttrib[MAX_IRQS];            // IRQ attrib list
    WORD wNumDMAs;                        // num DMA channels
    BYTE bDMALst[MAX_DMA_CHANNELS];       // DMA list
    WORD wDMAAttrib[MAX_DMA_CHANNELS];    // DMA Attrib list
    BYTE bReserved1[3];                   // reserved
};
typedef struct Config_Buff_s CMCONFIG;

Contains information about an allocated configuration.


CMPERFINFO

struct cm_performance_info_s {
    CMTIME ctBoot;
    CMTIME ctAPI[NUM_CM_SERVICES];
    CMTIME ctRing3;
    CMTIME ctProcessTree;
    CMTIME ctAssignResources;
    CMTIME ctSort;
    CMTIME ctRegistry;
    CMTIME ctVxDLdr;
    CMTIME ctNewDevNode;
    CMTIME ctSendMessage;
    CMTIME ctShell;
    CMTIME ctConfigMessage[NUM_CONFIG_COMMANDS];
    CMTIME ctArbTime[ResType_Max+1][NUM_ARB_COMMANDS];
    DWORD  dwStackSize;
    DWORD  dwMaxProcessTreePasses;
};
typedef struct cm_performance_info_s CMPERFINFO;
typedef CMPERFINFO  CMFAR *PCMPERFINFO;

Contains performance information that may be used for debugging.


CMTIME

struct cmtime_s {
    DWORD   dwAPICount;
    VMMTIME vtAPITime;
};
typedef struct cmtime_s CMTIME;
typedef CMTIME *PCMTIME;

Contains time information used for performance monitoring.


DMA_DES

struct DMA_Des_s {
    BYTE DD_Flags;       // channel width; see below
    BYTE DD_Alloc_Chan;  // allocated channel number
    BYTE DD_Req_Mask;    // mask of requested channels; see below
    BYTE DD_Reserved;    // reserved; do not use
};
typedef struct DMA_Des_s DMA_DES;

Contains information about DMA descriptors.

Members

DD_Flags
Channel width flags. Can be one of these values.
fDD_BYTE | 8-bit channel
fDD_WORD | 16-bit channel
fDD_DWORD | 32-bit channel

DD_Req_Mask
Mask of requested DMA channels. Bit 0 is set to request channel 0, bit 1 to request channel 1, and so on. More than one bit is set to indicate alternative channel allocations.


DMA_RESOURCE

struct DMA_Resource_s {
    DMA_DES DMA_Header;
};
typedef struct DMA_Resource_s DMA_RESOURCE;

Contains information about a DMA resource.


IO_DES

struct IO_Des_s {
    WORD IOD_Count;         // count of IO_RANGE structures
    WORD IOD_Type;          // size of IO_RANGE structures
    WORD IOD_Alloc_Base;    // allocated base port address
    WORD IOD_Alloc_End;     // allocated end port address
    WORD IOD_DesFlags;      // descriptor flags
    BYTE IOD_Alloc_Alias;   // allocated port aliases
    BYTE IOD_Alloc_Decode;  // allocated alias decode key
};
typedef struct IO_Des_s IO_DES;

Contains information about the I/O descriptors. The full descriptor consists of this structure and an array of IO_RANGE structures.

Members

IOD_Count
Number of IO_RANGE structures in this resource descriptor.
IOD_Type
Size, in bytes, of each IO_RANGE structure in this resource descriptor.
IOD_Alloc_Base
Allocated base port address.
IOD_Alloc_End
Allocated end port address.


IO_RANGE

struct IO_Range_s {
    WORD IOR_Align;       // mask for base alignment
    WORD IOR_nPorts;      // number of ports
    WORD IOR_Min;         // min port address
    WORD IOR_Max;         // max port address
    WORD IOR_RangeFlags;  // flags
    BYTE IOR_Alias;       // alias offset
    BYTE IOR_Decode;      // alias decode key
};
typedef struct IO_Range_s IO_RANGE;

Contains information about a range of I/O port addresses.


IO_RESOURCE

struct IO_Resource_s {
    IO_DES   IO_Header;
    IO_RANGE IO_Data[];
};
typedef struct IO_Resource_s IO_RESOURCE;

Contains information about an IO resource.


IRQ_DES

struct IRQ_Des_s {
    WORD IRQD_Flags;       // flags; see below
    WORD IRQD_Alloc_Num;   // allocated IRQ number
    WORD IRQD_Req_Mask;    // mask for requested IRQs
    WORD IRQD_Alloc_Mask;  // allocated IRQ mask
};
typedef struct IRQ_Des_s IRQ_DES;

Contains information about the IRQ descriptors.

Members

IRQD_Flags
Flags. Can be fIRQD_Share to indicate IRQ can be shared.


IRQ_RESOURCE

struct IRQ_Resource_s {
 IRQ_DES   IRQ_Header;
};
typedef struct IRQ_Resource_s IRQ_RESOURCE;

Contains information about an IRQ resource.


MEM_DES

struct Mem_Des_s {
    WORD  MD_Count;       // count of MEM_RANGE structures
    WORD  MD_Type;        // size of MEM_RANGE structures
    ULONG MD_Alloc_Base;  // allocated start address
    ULONG MD_Alloc_End;   // allocated end address
    WORD  MD_Flags;       // descriptor flags
    WORD  MD_Reserved;    // reserved; do not use
};
typedef struct Mem_Des_s MEM_DES;

Contains information about a memory descriptor. The full descriptor consists of this structure and an array of MEM_RANGE structures.

Members

MD_Count
Number of MEM_RANGE structures in this resource descriptor.
MD_Type
Size, in bytes, of each MEM_RANGE structure in this resource descriptor.


MEM_RANGE

struct Mem_Range_s {
    ULONG MR_Align;     // mask for base alignment
    ULONG MR_nBytes;    // count of bytes
    ULONG MR_Min;       // min Address
    ULONG MR_Max;       // max Address
    WORD  MR_Flags;     // flags
    WORD  MR_Reserved;  // reserved; do not use
};
typedef struct Mem_Range_s MEM_RANGE;

Contains information about a range of memory addresses.


MEM_RESOURCE

struct MEM_Resource_s {
    MEM_DES   MEM_Header;
    MEM_RANGE MEM_Data[];
};
typedef struct MEM_Resource_s MEM_RESOURCE;

Contains information about a memory resource.


NODELIST

struct nodelist_s {
    struct nodelist_s *nl_Next;        // next node element
    struct nodelist_s *nl_Previous;    // previous node element
    struct devnode_s  *nl_ItsDevNode;  // device node represented
    struct Log_Conf   *nl_Test_Req;    // test resource alloc request
    ULONG  nl_ulSortDWord;             // sort order
};

Contains information about an element in a node list. Although additional members can be appended to this structure, the first three members must not be changed.


NODELIST_HEADER

struct nodelistheader_s {
    struct nodelist_s *nlh_Head;  // First node element
    struct nodelist_s *nlh_Tail;  // Last node element
};

Contains information about the elements in a node list.


VMMTIME

struct vmmtime_s {
    DWORD vmmtime_lo;
    DWORD vmmtime_hi;
};
typedef struct vmmtime_s VMMTIME;
typedef VMMTIME *PVMMTIME;

Contains time information used for performance montoring.


Constants

This section describes constants used with Configuration Manager services.


Configuration Manager Return Values

Configuration Manager functions return a CONFIGRET value. CONFIGRET is defined as either 16- or 32-bit, depending on the compiler option; 16-bit code returns a 16-bit value and 32-bit code returns a 32-bit value.

Configuration Manager functions return CR_SUCCESS when they are successful. Otherwise, they return one of the following values.

Value | Meaning
CR_ALREADY_SUCH_DEVNODE | Specified device node already exists
CR_BUFFER_SMALL | The operation succeeded, but the specified buffer was too small
CR_CREATE_BLOCKED | Flags specifies that the devnode should not be created
CR_DEFAULT | Return the default result
CR_DEVICE_NOT_THERE | Driver could not find device
CR_DEVLOADER_NOT_READY | Device loader was not ready
CR_DEVNODE_HAS_REQS | Device node already has requirements
CR_DLVXD_NOT_FOUND | Dynamically loadable VxD was not found
CR_FAILURE | Failure (Arbitrator/Enumerator)
CR_INTERRUPTS_DISABLED | Interrupts were disabled
CR_INVALID_API | The function cannot be called from ring 3
CR_INVALID_ARBITRATOR | Arbitrator's registration identifier is invalid or there is already such a global arbitrator
CR_INVALID_DATA | ISA data is invalid
CR_INVALID_DEVICE_ID | Length of device identifier is greater than MAX_DEVICE_ID_LEN
CR_INVALID_DEVNODE | Device node is invalid
CR_INVALID_FLAG | Flags parameter is invalid
CR_INVALID_LOAD_TYPE | Load type is greater than MAX_DLVXD_LOAD_TYPE
CR_INVALID_LOG_CONF | Logical configuration is invalid
CR_INVALID_NODELIST | Nodelist header is invalid
CR_INVALID_POINTER | Specified pointer is invalid
CR_INVALID_PRIORITY | Priority number>MAX_LCPRI
CR_INVALID_RANGE | End range less than start range
CR_INVALID_RANGE_LIST | Range list not valid
CR_INVALID_RES_DES | Resource descriptor is invalid
CR_INVALID_RESOURCEID | The resource identifier is ResType_All
CR_NEED_RESTART | The config handler could not dynamically start the device, but will be able too the next boot
CR_NO_ARBITRATOR | Resource has no arbitrator
CR_NO_MORE_HW_PROFILES | No more hardware profiles
CR_NO_MORE_LOG_CONF | No more logical configurations
CR_NO_MORE_RES_DES | No more resource descriptors
CR_NO_REGISTRY_HANDLE | Operation will not produce registry entry
CR_NO_SUCH_DEVNODE | Device node could not be located
CR_NO_SUCH_LOGICAL_DEV | Logical device not found in ISAPNP conversion
CR_NO_SUCH_VALUE | Registry value does not exist
CR_NOT_DISABLEABLE | That devnode cannot be disable right now
CR_NOT_SYSTEM_VM | The service must be coming from the system VM
CR_OUT_OF_MEMORY | Out of memory
CR_REGISTRY_ERROR | Registry failed
CR_REMOVE_VETOED | The hardware tree should not be removed
CR_WRONG_TYPE | Registry value is of other type


Registry Services Reference

This section describes the registry services, real-mode functions, and constants.


Services

This section describes the registry services. All services have corresponding C-callable VMM functions.


_GetRegistryKey

DWORD _GetRegistryKey(DWORD dwType, LPSTR lpszDevName,
       DWORD dwFlags, LPHKEY lphKey);

Gets a registry key handle for the given device name under the given branch of the HKEY_LOCAL_MACHINE key.

  • Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Error Values.
dwType
Parent registry branch in which to open the key. Can be one of these values.
REGTYPE_CLASS | \System\CurrentControlSet\Services\Class
REGTYPE_ENUM | \ENUM

lpszDevName
Address of a null-terminated string specifying the device-name subkey.
dwFlags
Action flags. Can be 0 or REGKEY_CREATE_IFNOTEXIST to indicate the key should be created if it does not already exist.
lphKey
Address of the variable that receives the handle of the opened key.


_GetRegistryPath

DWORD _GetRegistryPath(DDB ddb, LPSTR lpszPath, DWORD cbPath);

Gets the registry path for the device driver associated with the given virtual device descriptor block (DDB).

  • Returns the number of bytes copied to the buffer or the buffer size, in bytes, needed to receive the complete path. This service returns 0 if no registry path exists.
ddb
Device descriptor block for the virtual device for which to retrieve the registry path.
lpszPath
Address of the buffer that receives the null-terminated registry path. This buffer receives the path only if buffer is large enough to hold the complete path.
cbPath
Size, in bytes, of the lpszPath buffer.


_RegCloseKey

DWORD _RegCloseKey(HKEY hKey)

Closes a previously opened key.

  • Returns ERROR_SUCCESS if successful; otherwise, ERROR_BADKEY, ERROR_KEY_DELETED, or other errors indicating the given hKey is invalid.
hKey
Handle of a previously opened key.


_RegCreateKey

DWORD _RegCreateKey(HKEY hKey, LPSTR lpszSubKey, LPHKEY lphKey)

Creates or opens the registry key for the given registry path.

  • Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Error Values.
hKey
Handle of a previously opened key or one of the predefined root keys given in Predefined Keys.
lpszSubKey
Subkey string to be opened. Can be NULL. Can also be NULL-string only if hKey is a predefined key.
lphKey
Address of the returned HKEY for a successful open/create.


_RegDeleteKey

DWORD _RegDeleteKey(HKEY hKey, LPSTR lpszSubKey)

Deletes the given registry key including its subkeys from the registry database.

  • Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Error Values.
hKey
Handle of a previously opened key.
lpszSubKey
Address of a null-terminated string specifying the subkey to delete.

This service also marks all other open references to the key being deleted as deleted, so that all accesses through these other open references will fail with an ERROR_KEY_DELETED error. But a virtual device could create a new key with the same name, even before these open references are closed, without any conflict.


_RegDeleteValue

DWORD _RegDeleteValue(HKEY hKey, LPSTR lpszValue)

Deletes the value for the given registry key and the given value name.

  • Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Error Values.
hKey
Handle of a previously opened key or one of the predefined root keys given in Predefined Keys.
lpszValue
Address of a null-terminated string specifying the value name to delete. Can be NULL or an empty string.

Each key can have one value for which the value name is NULL. This is treated as the value for the key itself. This value can be deleted by passing a NULL or a null string for lpszValue parameter.


_RegEnumKey

DWORD _RegEnumKey(HKEY hKey, DWORD iSubKey, LPSTR lpszBuffer, DWORD cbBuffer)

Enumerates the subkeys of a given registry key.

  • Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Error Values.
hKey
Handle of a previously opened key or one of the predefined root keys given in Predefined Keys.
iSubKey
Index of the subkey to retrieve. This should be zero for the first call to this service.
lpszBuffer
Address of a buffer that receives the name of the subkey.
cbBuffer
Size, in bytes, of the lpszBuffer buffer.

The virtual device should initially set iSubKey to zero, then increment it on successive calls.


_RegEnumValue

DWORD _RegEnumValue(HKEY hKey, DWORD iValue, LPSTR lpszValue,
      LPDWORD lpcbValueName, LPDWORD lpdwReserved, LPDWORD lpdwType,
      LPBYTE lpbData, LPDWORD lpcbData)

Enumerates the value names and values of a given registry key.

  • Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Error Values.
hKey
Handle of a previously opened key or one of the predefined root keys given in Predefined Keys.
iValue
Index of the value name to retrieve. This should be zero for the first call to this service.
lpszValue
Address of a buffer that receives the name of the value. Can be NULL if value name is not required.
lpcbValueName
Address of a 32-bit variable that contains the size, in bytes, of the lpszValue buffer. The variable receives the size, in bytes, of the retrieved value name. Can be NULL only if lpszValue is NULL.
lpdwReserved
Reserved; should be set to NULL by the caller.
lpdwType
Address of a 32-bit variable that receives the data type for the given value name. Can be NULL if data type is not needed.
lpbData
Address of a buffer that receives the value data for the given value name. Can be NULL if value data is not required.
lpcbData
Address of a 32-bit variable that contains the size, in bytes, of the lpbData buffer. This variable receives the size, in bytes, of the retrieved value data. Can be NULL only if lpbData parameter is also NULL.

The virtual device should initially set iValue to zero, then increment it on successive calls.


_RegFlushKey

DWORD _RegFlushKey(HKEY hKey)

Flushes the data for the given Registry Key.

  • Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Error Values.
hKey
Handle of a previously opened key or one of the predefined root keys given in Predefined Keys.

This is a time consuming operation and should not be used under normal circumstances. This service returns only after the registry file is flushed to disk. This may also flush data for other keys in the same registry file. Note that the registry is periodically flushed to the disk by VMM.


_RegOpenKey

DWORD _RegOpenKey(HKEY hKey, LPSTR lpszSubKey, LPHKEY lphKey)

Opens the registry key for the given registry path.

  • Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Error Values.
hKey
Handle of a previously opened key or one of the predefined root keys given in Predefined Keys.
lpszSubKey
Address of a null-terminated string specifying the subkey to be open. May also be NULL or NULL-string.
lphKey
Address of the variable that receives the handle of the opened key.


_RegQueryValue

DWORD _RegQueryValue(HKEY hKey, LPSTR lpszSubKey, LPBYTE lpbData,
      LPDWORD lpcbData)

Retrieves the value for the given registry key.

  • Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Error Values.
hKey
Handle of a previously opened key or one of the predefined root keys given in Predefined Keys.
lpszSubKey
Address of a null-terminated string specifying the subkey for which to retrieve the value. Can be NULL or point to a NULL-string.
lpbData
Address of a buffer that receives the value data for given registry key.
lpcbData
Address of a 32-bit variable that contains the size, in bytes, of the lpbData buffer. This variable receives the size, in bytes, of the retrieved data.


_RegQueryValueEx

DWORD _RegQueryValueEx(HKEY hKey, LPSTR lpszValueName,
      LPDWORD lpdwReserved, LPDWORD lpdwType, LPBYTE lpbData,
      LPDWORD lpcbData)

Retrieves the value for the given registry key for the given value name.

  • Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Error Values.
hKey
Handle of a previously opened key or one of the predefined root keys given in Predefined Keys.
lpszValueName
Address of a null-terminated string specifying the value name to for which to retrieve the value. Can be NULL or point to a NULL-string.
lpdwReserved
Reserved; set to NULL.
lpdwType
Address of a 32-bit variable that receives the data type for the given value. Can be NULL if data type is not needed.
lpbData
Address of a buffer that receives the value data for given registry key.
lpcbData
Address of a 32-bit variable that contains the size, in bytes, of the lpbData buffer. This variable receives the size, in bytes, of the retrieved data.


_RegSetValue

DWORD _RegSetValue(HKEY hKey, LPSTR lpszSubKey, DWORD fdwType,
      LPBYTE lpbData, DWORD cbData)

Sets the value for the given registry key.

  • Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Error Values.
hKey
Handle of a previously opened key or one of the predefined root keys given in Predefined Keys.
lpszSubKey
Address of a null-terminated string specifying the subkey for which to set the value. Can be NULL.
fdwType
Value data type to set. Must be REG_SZ.
lpbData
Address of a buffer that contains the value data to set.
cbData
Size in bytes of the value data buffer (lpbData). Can be zero, in which case, the value length is automatically calculated.


_RegSetValueEx

DWORD _RegSetValueEx(HKEY hKey, LPSTR lpszValueName, DWORD dwReserved,
      DWORD fdwType, LPBYTE lpbData, DWORD cbData)

Sets the value for the given registry key and the given value name.

  • Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Error Values.
hKey
Handle of a previously opened key or one of the predefined root keys given in Predefined Keys.
lpszValueName
Address of a null-terminated string specifying the value name for which to set the value. Can be NULL or point to a NULL-string.
dwReserved
Reserved; set to NULL.
fdwType
Value data type to set. Must be one of REG_SZ or REG_BINARY. Must be REG_SZ if lpszValueName is NULL or points to a NULL-string. See Registry Value Types.
lpbData
Address of a buffer that contains the value data to set.
cbData
Size in bytes of the value data buffer (lpbData). Can be zero for REG_SZ, in which case, the value length is automatically calculated.


Real-mode Functions

This section describes the real-mode registry function macros. These macros expand to calls to the loader service function. Access is restricted to the HKEY_LOCAL_MACHINE key and is read-only.


LDR_RegCloseKey

DWORD LDR_RegCloseKey(HKEY hKey)

Closes a previously opened key.

  • Returns ERROR_SUCCESS if successful; otherwise, ERROR_KEY_DELETED, ERROR_BADKEY, or other errors to indicate the given hKey is invalid.
hKey
Handle of a previously opened key.


LDR_RegEnumKey

DWORD LDR_RegEnumKey(HKEY hKey, DWORD iSubKey, LPSTR lpszBuffer,
      DWORD cbBuffer)

Enumerates the subkeys of a given registry key.

  • Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Error Values.
hKey
Handle of a previously opened key or is the HKEY_LOCAL_MACHINE key.
iSubKey
Index of the subkey to retrieve. This should be zero for the first call to this API.
lpszBuffer
Address of a buffer that receives the name of the subkey.
cbBuffer
Specifies the size, in bytes, of lpszBuffer.

The virtual device should initially set the iSubKey to zero, then increment it on successive calls.


LDR_RegEnumValue

DWORD LDR_RegEnumValue(HKEY hKey, DWORD iValue, LPSTR lpszValue,
      LPDWORD lpcbValueName, LPDWORD lpdwReserved, LPDWORD lpdwType,
      LPBYTE lpbData, LPDWORD lpcbData)

Enumerates the value names and values of a given registry key.

  • Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Error Values.
hKey
Handle of a previously opened key or is the HKEY_LOCAL_MACHINE key.
iValue
Index of the value name to retrieve. This should be zero for the first call to this function.
lpszValue
Address of a buffer that receives the name of the value. Can be NULL if value names are not required.
lpcbValueName
Address of a variable that contains the size, in bytes, of buffer. This variable receives the size, in bytes, of the retrieved value name. Can be NULL only if lpszValue is NULL.
lpdwReserved
Reserved; set to NULL.
lpdwType
Address of a 32-bit variable that receives the data type of the given value name. Can be NULL if data type is not needed.
lpbData
Address of a buffer that receives the value of the given value name. Can be NULL if value data is not required.
lpcbData
Address of a 32-bit variable buffer that contains the size, in bytes, of the lpbData buffer. This variable receives the size, in bytes, of the retrieved data. Can be NULL only if lpbData parameter is also NULL.

The virtual device should initially set iValue to zero, then increment it on successive calls.


LDR_RegOpenKey

DWORD LDR_RegOpenKey(HKEY hKey, LPSTR lpszSubKey, LPHKEY lphKey)

Open the registry key for the given registry path.

  • Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Error Values.
hKey
Handle of a previously opened key or is the HKEY_LOCAL_MACHINE key.
lpszSubKey
Address of a null-terminated string specifying the subkey to open. May be NULL or point a Null-string.
lphKey
Address of a variable that receives the handle to the open key.


LDR_RegQueryValue

DWORD LDR_RegQueryValue(HKEY hKey, LPSTR lpszSubKey, LPBYTE lpbData,
      LPDWORD lpcbData)

Retrieves the value for the given registry key.

  • Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Error Values.
hKey
Handle of a previously opened key or is the HKEY_LOCAL_MACHINE key.
lpszSubKey
Address of a null-terminated string specifying the subkey to retrieve the value from. Can be NULL or point to a NULL-string.
lpbData
Address of a buffer that receives the value data for given registry key.
lpcbData
Address of a 43-bit variable that contains the size, in bytes, of the lpbData buffer. This variable receives the size, in bytes, of the retrieved data.


LDR_RegQueryValueEx

DWORD LDR_RegQueryValueEx(HKEY hKey, LPSTR lpszValueName,
      LPDWORD lpdwReserved, LPDWORD lpdwType, LPBYTE lpbData,
      LPDWORD lpcbData)

Retrieves the value for the given registry key for the given value name.

  • Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Error Values.
hKey
Handle of a previously opened key or is the HKEY_LOCAL_MACHINE key.
lpszValueName
Address of a null-terminated string specifying the value name for which to retrieve value data. Can be NULL or point to a NULL-string.
lpdwReserved
Reserved; set to NULL.
lpdwType
Address of a 32-bit variable that receives the data type for the value. Can be NULL if data type is not needed.
lpbData
Address of a buffer that receives the value data for given value name.
lpcbData
Address of a 32-bit variable that contains the size, in bytes, of the lpbData buffer. This variable receives the size, in bytes, of the retrieved data.


Constants

This section describes the constants used with the registry services.


Predefined Keys

HKEY_LOCAL_MACHINE | Contains information about the hardware and software on the computer.
HKEY_USERS | Contains information about the users of the computer. In particular, this contains any user-specific information associated with hardware or software is stored.
HKEY_CURRENT_USER | Contains information about the current user. This is mapped to the default user branch under the HKEY_USERS key.
HKEY_CURRENT_CONFIG | Contains information about the hardware configuration of the computer. This typically
HKEY_CLASSES_ROOT | Contains information about OLE classes.
HKEY_PERFORMANCE_DATA | Contains information about system performance.
HKEY_DYN_DATA | Contains information about dynamic data.


Registry Value Types

REG_SZ | Null-terminated string
REG_BINARY | Binary data consisting of a specified number of bytes.
All other types | Valid, but treated as binary internally.


Error Values

ERROR_SUCCESS | Completed successfully.
ERROR_CANNOT_OPEN_REGFILE | Cannot find the required registry hive file or possibly the file is kept open by another application.
ERROR_INSUFFICIENT_MEMORY | Not enough memory to open this registry key or not enough memory to load the required data from the registry file, or the given buffer is not enough to hold the data.
ERROR_INVALID_PARAMETER | lpszDevName is an invalid address, or dwFlags is incorrect.
ERROR_REGFILE_READERROR | Error reading the registry file. Possibly, the file is corrupt.
ERROR_REGFILE_WRITEERROR | Error writing the registry file. Possibly, the file is corrupt.
ERROR_REGKEY_INVALIDKEY | The lpszSubKey string contains an invalid character or the given hKey is invalid.
ERROR_FILE_NOT_FOUND | No more subkeys, or the key specified is not found in the registry database.
ERROR_VALUE_NOT_FOUND | No more values to enumerate, or the given value name is not present for the given registry key.


Dynamic Registry Key Services Reference

This section describes the Windows 95 dynamic registry key services.


Functions

The following topics describe the functions.


_RegCreateDynKey

VMMREGRET _RegCreateDynKey (PCHAR lpszSubKey, PVOID pvKeyContext,
      PPROVIDER pprovHandlerInfo, PPVALUE ppvalueValueInfo,
      DWORD cpvalueValueInfo, PVMMHKEY phkResult);

Creates a dynamic key. It is defined in VXDWRAPS.H. This function makes copies of pprovKeyHandlerInfo and ppvalueValueInfo.

  • Returns ERROR_SUCCESS if the function succeeds; otherwise returns one of the error values which can be returned by RegCreateKeyEx. In addition if the key already exists the function will return ERROR_REGISTRY_CANNOT_CREATE.
lpszSubKey
Pointer to the name of key to be created. The name is relative to HKEY_DYN_DATA. For example, suppose the new dynamic key will be HKEY_DYN_DATA\Keyname1\Keyname2. Then lpszSubKey="Keyname1\\Keyname2". The registry will create Keyname1 if it does not exist, and Keyname2. The provider will only be queried for values under the lowest level key (Keyname2).
pvKeyContext
The key context. This is a 32-bit value that is only meaningful to the provider. It is only necessary when the same provider is handling multiple dynamic keys. If the provider is only going to handle one dynamic key, then this parameter can be NULL.
pprovHandlerInfo
A pointer to a provider_info structure.
ppvalueValueInfo
An array of Pvalue structures. There must be one structure for each value under the dynamic key to be created.
cpvalueValueInfo
The number of structures in the ppvalueValueInfo array, which is equal to the number of values under this dynamic key.
phkResult
Pointer in which the function will return the open handle of the newly created dynamic key.


PQUERYHANDLER

typedef VMMREGRET (_cdecl *PQUERYHANDLER)(PVOID pvKeyContext,
      PVALCONTEXT pvalcontextValues, DWORD cvalcontextValues,
      PBYTE pbData, DWORD* pcbData, DWORD dwReserved);

This is the type definition for the provider, or handler function.

pvKeyContext
This is the key context; it is an input paramater that lets the provider know which key is being queried, if this handler function handles multiple keys.
pvalcontextValues
This is an array of val_context structures; one structure per value. Parts of the val_context structure are input parameters, and parts are output parameters - please see the comments for the val_context structure.
cvalcontextValues
This is the number of val_context structures in the array of the previous argument; it is an input parameter.
pbData
This is a buffer, supplied by the registry to the provider, in which the provider stores the value or values that are queried. If the registry is keeping track of the value lengths, this buffer should always be large enough.
pcbData
A pointer to the length of the pbData buffer. On input, it contains the size of the available buffer. On output, it should contain the size of the buffer that is actually used / filled.
dwReserved
Reserved.


Structures

The structures described in this section are defined in Vmmreg.h in the Windows 95 DDK.


PVALUE

#define PROVIDER_KEEPS_VALUE_LENGTH  0x1
  typedef struct pvalue {
      PCHAR pv_valuename;       // The value name pointer
      DWORD pv_valuelen;        // The length of the value in bytes.
      PVOID pv_value_context;   // The context for this value
      DWORD pv_type;            // Registry type of this vallue.
  } PVALUE;
  typedef struct pvalue *PPVALUE;

An array of these structures is passed to RegCreateDynKey, one structure per value under that key.

Members

pv_valuename
The name of the value. The provider must fill this in when it calls _RegCreateDynKey.
pv_valuelen
The length (in bytes) of the value. If the registry is keeping value lengths, then this must be filled in by the provider when it calls _RegCreateDynKey.
pv_value_context
The value-context. This is a 32-bit value that is only meaningful to the provider; it is never evaluated by the registry code. This is a value in some way uniquely identifies this particular value so that when the provider is called, it knows which value is being queried. This is what enables one provider to handle multiple values. The provider must fill this in when it calls _RegCreateDynKey.
pv_type
The registry type of this value. In Windows 95, this can be REG_BINARY or REG_SZ. The provider must fill this in when it calls _RegCreateDynKey.


PROVIDER

typedef struct provider_info {
      PQUERYHANDLER pi_R0_1val;     // pointer to VxD handler
                                    //  single value
      PQUERYHANDLER pi_R0_allvals;  // pointer to VxD handler,
                                    //  multiple values
      PQUERYHANDLER pi_R3_1val;     // Should be NULL in Win95
      PQUERYHANDLER pi_R3_allvals;  // Should be NULL in Win95
      DWORD pi_flags;               // capability flags
  } PROVIDER;
  typedef PROVIDER *PPROVIDER;

This structure must be passed as parameter to _RegCreateDynKey

Members

pi_R0_1val
Pointer to the VxD handler function that should be called when this dynamic key is queried for one of its values. The provider must fill this in when it calls _RegCreateDynKey.
pi_R0_allvals
Pointer to the VxD handler function that should be called when the dynamic key is queried for all of its values (via RegQueryMultipleValues). If the handler function does not support multiple values, this should be set to NULL. In this case the registry code calls pi_R0_1val repeatedly, once for each value, when RegQueryMultipleValues is called for this key. Having this handler is useful in the case where the key is being queried remotely, because this would reduce the number of Remote Procedure Calls. The provider must fill this in when it calls _RegCreateDynKey (if it has a handler that responds to a query of multiple values).
pi_R3_1val
Win32 providers are not supported in Windows 95. This should be NULL.
pi_R3_allvals
Win32 providers are not supported in Windows 95. This should be NULL.
pi_flags
Capability flags. These are used to tell the registry code whether the provider is handling certain kinds of housekeeping, or whether the registry code should do this housekeeping. Currently, there is one such flag: PROVIDER_KEEPS_VALUE_LENGTH. If this flag is set, then the provider has the responsibility for maintaining and providing the value length when needed. If it is not set, then the registry code keeps track of the value lengths. This flag is useful if the value lengths are not static. If any of the value lengths can change dynamically, then the provider must do the work of keeping the value lengths. Note this flag is per-key, not per-value.


val_context

struct val_context {
      int valuelen;    // the total length of this value
      PVOID value_context;  // the value context
      PVOID val_buff_ptr;  // where in the ouput buffer the value is.
  };
  typedef struct val_context *PVALCONTEXT;

An array of these structures is passed to the handler function. There is one structure for each value. This structure should not be confused with a value_context, which is one of the fields in this structure.

Membes

valuelen
The length of the value. It includes the null terminating character for strings. If the provider keeps value lengths, then this needs to be filled in by the provider in the handler function. (It is sometimes an "output" parameter).
value_context
The value context for this value - the 32-bit value that is meaningful only to the provider. It is provided to the handler function by the registry code (it is an "input" parameter)
val_buff_ptr
A pointer to the place in the buffer where the value is. It must be filled by the provider in the handler function. (It is an "output" parameter)


WDEB386 System Debugger

Microsoft® Windows® System Debugger (WDEB386.EXE) is used to test and debug Windows applications, dynamic-link libraries (DLLs), and virtual device drivers (VxDs) running with the Microsoft Windows operating system. You use System Debugger commands to inspect and manipulate memory and registers, control the execution of code, and perform other debugging operations. This section describes the debugger, explains how to start and use the debugger, and provides detailed information about the debugger commands.


Setting up the Microsoft Windows System Debugger

This section is a list of frequently asked questions about setting up kernel debugging for Microsoft® Windows® 95. You'll find answers here about getting started with the System Debugger (WDEB386). Additional information can be found in the MSDN Library CD (check out the Additional Resources section, located at the beginning of this documentation).


How to Get Started

You need a computer with a serial port, and you'll need to buy or make a null-modem cable. You only need a three-line null modem cable (transmit, receive, and ground). You don't need one with handshaking lines because WDEB386 doesn't use handshaking. You should also disable handshaking on your computer (Handshaking allows slower receivers to keep up with the amount of data being transmitted by telling the transmitter to stop sending data until it has a chance to catch up).


How to Handle Transmission Speed Issues without Handshaking?

Previous Next

How to Handle Transmission Speed Issues without Handshaking

Because handshaking is disabled, it is possible that WDEB386 could send characters to the terminal faster than the terminal can display them. If you find that characters are dropped, you should increase the delay between lines (often a terminal drops characters while scrolling). Use the y CRDELAY=delay debugger command where "value" ranges from 0 (no delay) to FFFF (maximum delay). Increase the delay until your terminal stops dropping characters. You can also lower the speed of the connection. To do this, use the /c: command-line option with WDEB386 to set the baud rate.


How to Change the COM Port

Use the /r: command-line option with WDEB386 to change the COM port. By default, WDEB386 uses COM1 at 19200 bits per second (bps).


What is a Null-modem Serial Cable

Typically with serial ports, you connect a computer to something like a modem. This is how serial ports are designed: you connect a computer, or Data Terminal Equipment (DTE), to a modem, or Data Communication Equipment (DCE). When you connect a computer to another computer, or DTE to DTE, you need a special cable called a null-modem cable. WDEB386 requires only the most basic null-modem cable, the three-line null-modem cable. The following illustration shows the null-modem cable's connectors. (The pin numbering would be backwards if you were looking at the computer's ports.)

The following table shows the pin numbers and names of the cable's three lines.

Pin | Name
Pin 2 | Receive
Pin 3 | Transmit
Pin 5 | Ground


Using a Laplink V Serial Cable with WDEB386

You can use a Laplink V serial cable with WDEB386. The blue Laplink cable works well. Remember to disable handshaking.


Disabling Handshaking on Windows 95

To disable handshaking

  1. Using your right mouse button, click My Computer, and then click Properties.
  2. In the System Properties dialog box, click the Device Manager tab.
  3. In the list of device types, double-click Ports (COM & LPT).
  4. Double-click the name of the port the cable is connected to, usually Communications Port (COM2).
  5. In the Communications Port Properties dialog box, click the Port Settings tab.
  6. In the Flow Control list, click None.
  7. Click OK.


How to Set Up WDEB386

To set up WDEB386

  1. Install the Windows 95 Device Driver Kit (DDK).
  2. At the command prompt, go to the Debug subdirectory of the directory you installed the DDK in.
  3. Follow the instructions in the section in this documentation titled Installing Debug Environment.


How to Start Up WDEB386

The Ddkdebug batch file creates Runwdeb.bat in the System subdirectory of your Windows directory. Runwdeb.bat is a batch file that starts WDEB386.

To use this batch file to start WDEB386

  1. Click the Start button, and then click Shut Down.
  2. In the Shut Down Windows dialog box, click the option that enables you to restart the computer in MS-DOS mode, and then click Yes.
  3. If you want to change the COM port or baud rate, edit runwdeb.bat. The /c: option determines the COM port, and the /r: option determines the baud rate.
  4. At the command prompt, go to the System subdirectory of your Windows directory, type the following, and then press ENTER:

    runwdeb.


WDEB386 Commands

See the topic titled Reference.


What to Do If Another Computer with a Serial Port is Not Available

You can use screen swapping. This requires that you set the resolution of your computer to 640 x 480 with 16 colors and add the following line to the [386Enh] section of System.ini:

debugvga=1

To start the debugger, press the F12 key.


Windows 2000 Developers and Windbg for Kernel Debugging on Windows 95

Windows NT/Windows 2000 developers cannot use windbg for kernel debugging on Windows 95. They can only use only WDEB386 or a third-party debugger such as SoftIce/W for kernel debugging.


When WDEB386 Does Not Work

  • Make sure you are using the WDEB386 contained in the Windows 95 DDK (build 950). You need this version to work with the retail version of Windows 95.
  • Run Direct Cable Connection (DCC) to make sure your null-modem cable works. DCC is optionally installed with Windows 95. To see if it is installed, click the Start button, point to Accessories, and then look for Direct Cable Connection in the menu. If it is not there, use the Add/Remove Programs Control Panel to install it.
  • Make sure handshaking is disabled on your computer.
  • If the debugger stops responding partway through boot, this could be because you have a debugcom or debugbaud line in your system.ini file. These entries override the values provided on the wdeb386 command line.
  • If the debugger is dropping characters or if you see garbage characters when doing large output, type y crdelay=8000 to slow down the delay between lines. The value of crdelay is a hex value from 0000 to FFFF. You may have to experiment with the crdelay value.
  • If you are running out of memory with the debugger, use the command line option /L, which will have the effect of shrinking symbol files by a factor of three.
  • Each symbol file uses an XMS handle. If you run out of handles, edit CONFIG.SYS to contain
    device=himem.sys /NUMHANDLES=32.


Using WDEB386 as a VxD

You can use WDEB386 as a vxd and also save about 90K of conventional memory. You will not, however, be able to access symbols until after the Device_Init message is sent to your VxDs (during Windows 95 startup). So, if you use the /b option with WDEB386 to break in VMM32 initialization, the debugger will have no knowledge of symbols until Device_Init is sent.


Setting Up WDEB386 as a VxD

The Ddkdebug.bat batch file creates a file called WDEBVXD.INS (the original file name is WDEBVXD.TMP) in the Debug subdirectory of the directory you installed the DDK in. You should insert the contents of this file into the [386Enh] section of System.ini. Make sure you comment out the following WDEB386 device lines from the [Enh386] section of System.ini when you restore the retail version of Windows 95:

Device=WDEB386.EXE
Device=DEBUGCMD.VXD

For information about restoring the retail version of Windows 95, see "How do I set up WDEB386?"


Changing the Baud Rate or COM Port with the VxD Version of WDEB386

To change the COM port, change the value in the debugcom= line in the [386Enh] section of System.ini. The following entry sets the COM port to COM2:

debugcom=2

To change the baud rate, change the value in the debugbaud= line. The following entry sets the baud rate to 19,200:

debugbaud=19200

Note The values in System.ini will override prior WDEB386 command-line settings for the baud rate and COM port.


Preparing to Start

You can start the System Debugger as an application from the real-mode command line or as a virtual device driver by specifying it in the SYSTEM.INI file. Before you start, however, you prepare for debugging by carrying out these steps:

  • Connect a serial terminal or other computer by serial cable to a serial port on your debugging computer.
  • Create symbol files for the applications, DLLs, and VxDs you intended to debug (see Creating Symbol Files).
  • Install the system debug environment if available (see Installing Debug Environment). These are debugging versions of the system DLLs and VxDs and their symbol files that can make debugging easier. These files are available in the Windows 95 Device Driver Development Kit.


Connecting the Null-modem Serial Cable

The debugger displays output and receives user input through a serial communication port of the computer on which it runs. To use the debugger, you must connect the null-modem cable from this serial port to either a serial terminal or the serial port of another computer. A three-wire null modem cable is the minimum cable requirement for this connection. Typically, users connect the cable to a second computer and use their favorite serial communications software to connect to the serial port and interact with the debugger. The Windows 95 operating system comes with the serial communication program Hyperterminal.


Creating Symbol Files

Symbol files provide the information the debugger needs to display functions, structures, variables, and absolute symbols by name rather than number. To prepare symbol files, perform the following steps:

  1. Compile or assemble your source files, using the appropriate command-line option to generate object files with line-number information. For more information about compiler and assembler options, see the documentation that accompanied your compiler and assembler.
  2. Link the compiled code with the standard libraries (as needed), using the appropriate linker option to create a symbol map (.MAP) file that includes PUBLIC symbols. You may also want to use the linker option for display of line-number information. For more information about linker options, see the documentation that accompanied your linker.
  3. Run the Microsoft Symbol File Generator (MAPSYM.EXE) to create a symbol file for symbolic debugging. MAPSYM converts the contents of your application's symbol map (.MAP) file into a form suitable for loading with the debugger; then MAPSYM copies the result to a symbol (.SYM) file.

Following is the command-line syntax for MAPSYM:

mapsym [/l][/n] mapfilename

/l | Directs MAPSYM to display information on the screen about the conversion. The information includes the names of groups defined in the application, the application start address, the number of segments, and the number of symbols per segment.
/n | Directs MAPSYM to ignore line-number information in the map file. The resulting symbol file contains no line-number information.
mapfilename | Specifies the filename for a symbol map file that was created during linking. If you do not give a filename extension, .MAP is assumed. If you do not give a full path, the current directory and drive are assumed. MAPSYM creates a new symbol file having the same name as the map file but with the .SYM extension.

In the following example, MAPSYM uses the symbol information in FILE.MAP to create FILE.SYM in the current directory on the current drive:

mapsym /l file.map

Information about the conversion is sent to the screen. MAPSYM always places the new symbol file in the current directory on the current drive. MAPSYM can process up to 10,000 symbols for each segment in the application and up to 1024 segments. If you have many components to debug, you can combine multiple symbol files into a single file by using the Symbol File Librarian (SYMLIB.EXE). This creates a symbol library file and lets you add, remove, or replace .SYM files in it.


Debug Binaries

Debug binaries are Windows 95 kernel VxDs that are typically compiled with the DEBUG=1 statement contained in the corresponding makefile. Note the historic difference in nomenclature between Windows and Windows NT®/Windows® 2000 documentation.

Windows 3.x, Windows 9x | Windows NT/Windows 2000 | Meaning
"Retail" | "Free build" | Normal retail code build
"Debug binary" | "Checked build" | Debug code build

You do not need to use the debug binaries in order to run and use the debugger. However, debug binaries are extremely helpful when troubleshooting your VxD:

  • Debug binaries contain additional code that issues message(s) to the debugger terminal. These messages contain valuable information, warning information, and/or error information.
  • Debug binaries frequently contain special debugger "dot command" handling code, not present in the retail drivers (See System Dot Commands). Dot commands are intended to reveal the contents of internal data structures unique to the driver that support the Dot command.
  • Debug binaries perform additional verification of data and pointers (using ASSERT functions for example). For example, if a pointer is found to be null and it shouldn't be, debug binaries may contain an INT1 or INT 3 breakpoint, causing the debugger to automatically halt at that point (see Breaking Into the Debugger).
  • If symbol files are provided with the debug binary VxD, use them, to make it easier to navigate through the code.


Installing Debug Environment

Do not depend on using the DDK's DDKDEBUG.BAT batch file to copy debug binaries to their proper locations. Instead, copy debug binaries to the locations indicated in KB article Q163358.

The DDKDEBUG.BAT file was originally intended to, among other things, allow the customer to copy debug binaries from the DDK to the windows environment. The user was to type ddkdebug set to install the debug binaries, and ddkdebug restore to remove them.

However, there is a bug in the ddkdebug.bat file, described in the following paragraphs.

Note The KB Article, Q163358, "PRB: DDKDEBUG.BAT Copies Some Drivers to the Wrong Directory", describes a problem in the DDKDEBUG.BAT file. A summary of this KB article follows:

If you use the \ddk\debug\ddkdebug.bat file to set the debug environment, it does not work correctly.

CAUSE

=====

When you use the ddkdebug.bat file to set the debug environment, the batch file simply copies all the *.vxd files to the \windows\system\vmm32 directory. This directory is not the proper location for some of these drivers.

RESOLUTION

==========

Here are the correct target locations to copy the debug drivers. If debugging Golden Windows 95, the debug binaries are located in the \ddk\debug directory. If debugging Windows 95 version OSR2 ("version "B"), see the following for instructions on how to obtain the OSR2 debug binaries.

Driver file name | Required target directory | Comments
bios.vxd configmg.vxd ios.vxd vdd.vxd vdmad.vxd vflatd.vxd vkd.vxd vmcpd.vxd vmm.vxd vpicd.vxd vxdldr.vxd | \windows\system\vmm32 | Replacements for components that were originally "bound" into vmm32.exe.
cdtsd.vxd cdvsd.vxd disktsd.vxd diskvsd.vxd scsiport.pdr | \windows\system\iosubsys | IOS layered hierarchy drivers
eisa.vxd isapnp.vxd lptenum.vxd ndis.vxd pccard.vxd pci.vxd | \windows\system | All other VxDs
debugcmd.tmp | \windows\system\debugcmd.vxd | Installed for additional debugger dot commands (see System Dot Commands, .P). Note that the file extension needs to be renamed from ".tmp" to ".vxd".

Windows 95 Version OSR 2.1 (USB Support)

Driver file name | Required target directory | Comments
VMM.VXD VPICD.VXD VXDLDR.VXD NTKERN.VXD | \windows\system\vmm32 | Replacements for components that were originally "bound" into vmm32.exe.
USBD.SYS OPENHCI.SYS UHCD.SYS USBHUB.SYS | \windows\system | WDM driver components

WIN.COM starts VMM32.VxD (formerly DOS386.EXE). During setup, many standalone VxDs are bound into one large file named VMM32.VxD. The number of VxDs bound can vary from machine to machine. This is done for quicker loading. However, there is still a separate, smaller VxD called VMM32.VxD, whose job is to load static system VxDs. The "bigger" VMM32.VxD contains it. The loader VMM32.VxD will first search for and load standalone VxDs located in the path \windows\system\vmm32. These VxDs replace VxDs by the same name that were bound into VMM32.VxD at setup time. Therefore, debug binary vxds that are placed into \windows\system\vmm32 will replace their (retail build) counterparts located in the bound VMM32.VxD. Within the registry or in SYSTEM.INI, an asterisk preceding a driver name (e.g. *VPICD, *VDMAD) indicates the driver is a "child" VxD located within VMM32.VxD. The driver replacement rules, just described, also apply to these child device references.

The Windows 95 path \windows\system\iosubsys contains I/O Supervisor (IOS) drivers. IOS is a layered hierarchy of drivers, implementing protected-mode 32 bit disk I/O. The drivers in this path are loaded by *IOS during its DEVICE_INIT phase.

The Windows 95 path \windows\system contains all other VxDs.

If you manually copy debug binary drivers, we recommend that you back up or rename any VxD's that go by the same name in the target path, so you can restore the normal VxDs later.

The original debug binaries in the original Windows 95 DDK are intended for the use with the original (Golden) version of Windows 95. If debugging Windows 95 version b (OSR2), or version 2.1 (USB / WDM support) obtain the OSR2 or OSR21 debug binaries, located at the following Microsoft web site:

http://support.microsoft.com/support/ddk_hardware/winddk/tools/

Alternatively, go to the Microsoft Support site (http://support.microsoft.com/support) and search using the following keys:

My search is about: Device Drivers

I want to search for: osr2 debug binaries

You can also use DDKDEBUG.BAT to remove the system debug environment and restore the original system files, by typing ddkdebug restore. However, the same problem regarding the ddkdebug set issue still needs to be addressed.

The RUNWDEB.WRF file contains command-line options for the debugger. This file along with RUNWDEB.BAT is copied to the WINDOWS\SYSTEM directory (provided that files with these names are not already present in that directory).

Before you can use RUNWDEB.BAT, you may need to edit it to contain the correct debug settings. These settings are:

/c: | Number that represents the COM port to which debug terminal is attached. For example: /c:1
/r: | Baud rate at which debug terminal will be operating. For example: /r:19200

You can add any other desired command line options to this file.

You will likely need to edit the RUNWDEB.WRF to add /s: options for the symbol files of the components you intended to debug. Remember that the symbol file(s) installed must match the corresponding binary, both in (Windows 95) version and the distinction between retail or debug versions.

Once you have completed editing these files and verifying settings, you can start the debugger by running RUNWDEB.BAT (with one optional WDEB386 command line parameter) from the WINDOWS\SYSTEM directory.

Debugging WDM Drivers

All WDM debugging under Windows 95/98 should be done with a standard Windows 95 system debugger such as WDEB386 or SoftIce. Debug output from WDM drivers such as a USB driver will not be displayed in real-time, unlike other Windows 95 debug components such as VxDs. Instead all WDM debug output is written to a debug log. To view this log you must use the debug interface of NTKERN.VXD. This is accomplished by breaking into the debugger and then typing ".NTKERN". You then type "D" to dump the NTKERN debug log. Note that the log is dumped in reverse order, meaning the first debug message displayed in the log is the one most recently logged. No debug binaries are required to use the debug log in NTKERN.VXD.


Starting from the Command Line

You can start the debugger from the real-mode command line by using the WDEB386 command line. (You cannot start the debugger from the command line after WIN.COM has started. To get the real-mode command line, press the F8 key as Windows starts and choose the Command Prompt Only option.) The command line has this syntax:

wdeb386 [/A] [/B] [/C:comport] [/D:"commands"] [/E] [/F:filename] [/H] [/I] [/L] [/N] [/T:hhhh] [/S:symfile] [/V[P]] [/X] winfile [parameters]

Following are the command-line options and parameters:

/A | Specifies that symbol files should not be automatically loaded.
/B | Specifies that the debugger should stop just prior to VMM initialization, after all virtual devices have been loaded and the processor is running in protected mode. This option is useful if you want to install breakpoints early. Also, if you use the debugger's .VMM s command at this stop point, you can turn on verbose device tracing which displays the name of each VxD before it is called, and OK when the VxD returns.
/C:comport | Specifies a COM port for debugger output. You can specify "1", "2", "3", or "4" for comport. If this option is not specified, The debugger checks first for COM2. If COM2 is not found, the debugger then checks for COM1. If neither COM1 nor COM2 exists, the debugger checks for any other COM port in the read-only memory (ROM) data area (40:0).
/D:"commands" | Carries out the debugger command line specified by the string enclosed in quotation marks. Spaces, semicolons (;), and other punctuation can be included in the command string. To use a single quote (') on the command line, use double quotation marks (") before and after the single quotation mark.
 | The commands specified in this option are carried out after symbols are loaded. This means you can set breakpoints in code even before the code has been loaded. Before a segment or module has been loaded or defined, breakpoints can be set on the logical address (a combination of map number and group number) until the segment or module is defined, at which point the breakpoint turns into a real breakpoint.
/E | Specifies that the debugger should stop at real-mode entry.
/F: filename | Specifies a file containing command-line options for the debugger. Maximum file size is 4K, and the input file cannot contain the /F option.
/H | Specifies that the debugger should be loaded as a VxD.
/I | Specifies that the debugger should be invisible to int 41.
/L | Specifies that line numbers should not be included in the .SYM file. This can make a large difference in memory use, and may be required on a machine with 4 megabytes of RAM.
/N | Sets the following options:

dislwr
codebytes
symaddrs
int3line
newvec
newreg
newprompt

 | For information about these options, see the y command in Reference.
/R:dddd | Sets the baud rate for the debugging terminal.
/S: symfile | Specifies a symbol file to be loaded. This option can be repeated to load more than one symbol file. If the symbol files are not in your current directory, you must supply a full path, because the debugger does not use the PATH environment variable to locate any of the files supplied on the command line. When memory is low, you can use more symbol files by running the Debugger in the Windows directory and specifying the full path of VMM32.VXD (such as \WINDOWS\SYSTEM\VMM32.VXD) instead of WIN.COM.
/T:hhhh | Sets the port number for the timing card (The default number is 250h.). See MSDN Library CD: Q85897, "WDEB386-Compatible Timing Card Available"
/V | Enables verbose mode, which displays messages indicating which segments are being loaded.
/VP | Enables verbose mode, which displays messages indicating which segments are being loaded. This option displays the messages for applications only.
/X | Causes symbols to be loaded into Extended Memory Specification (XMS) memory.
winfile | Specifies the Windows application to run under debugger control. You will usually specify WIN.COM.
parameters | Specifies any parameters to be passed to the application.

The length of the command line cannot exceed 128 characters.

The following example shows a valid command line:

wdeb386 /C:1 /R:9600 /F:RUNWDEB.WRF /V \windows\win.com


Starting as a VxD

Running WDEB386 as a VxD requires approximately 90KB less of conventional memory than running it from the command line. Its only disadvantage is that loaded symbols aren't available until after SYS_CRITICAL_INIT. You can start the debugger as a virtual device driver by placing the following line in your CONFIG.SYS file:

device=c:\windev\wdeb386.exe

You must specify the full path to the WDEB386.EXE file. You can specify any command-line options on the device line with (for example, you can load symbol files), or you can set options by adding one or more of the following debug settings to the [386Enh] section of SYSTEM.INI:

DebugCom=comport | Sets the communications port that the debugger uses for input and output. The comport can be 1, 2, 3 or 4, as described for the /C command line option.
DebugBaud=baudrate | Sets the baud rate for the communications port used by the debugger.
DebugCmd=parameters | Lists the debugger commands to execute as the debugger starts. This is typically used to set command-line parameters. For example, use DebugCmd=y /n /b to enable new options and to initially break into debugger at SYS_CRITICAL_INIT. Multiple commands must be separated by semicolons (;).
DebugSym=symbol-files | Specifies the symbol file or files to load.
DebugSymCmd=cmds | Lists the debugger commands to execute immediately after all symbols have been loaded. Multiple commands must be separated by semicolons (;).
BreakInDebugVxD=value | Sets the behavior of the CTRL+C key when pressed on the debug terminal or the CTRL+ALT+SYSREQ key combination when pressed on the computer on which the debugger is running. If value is TRUE, pressing the key stops execution at the current instruction regardless of the privilege (ring) of the code. If FALSE, pressing the keys stops execution in ring 3 code only. The default setting if this entry is not given is TRUE.

If you have the Windows 95 Device Driver Development Kit, you can use the DDKDEBUG.BAT batch file to create a WDEBVXD.INS file that contains the statements that you need to add to the [386Enh] section of SYSTEM.INI. In particular, DDKDEBUG.BAT includes the DEBUGCMD.VXD file that provides additional debugging support. You may need to set the DebugCom and other options to appropriate values.

When you no longer want to run the debugger as a VxD, insert a semicolon before the device=WDEB386.EXE (and device=DEBUGCMD.VXD if present) entry in the SYSTEM.INI file. Any debug options settings you added to the file do not need a semicolon; they will be ignored on subsequent loads of Windows 95.


Using the System Debugger

Throughout this documentation, there are many references to debugger dot commands (those commands that begin with a period, such as .VMM). Many of these dot commands only work when the supporting debug binary is installed. Refer to the topic entitled Reference for more information on how to install debug binaries, in order to make debug-VxD-specific dot commands available.

There are many situations in which the WDEB386 debugger is the best or even the only debugger you should use. For example, you might use WDEB386 to diagnose problems such as the following:

  • Tracing through low-level code
  • Viewing virtual/linear/physical memory
  • Viewing advanced 386 processor data, such as the GDT, LDT, IDT, and all of the PMODE registers
  • Tracing hardware interrupt handlers
  • Tracing terminate-and-stay-resident (TSR) programs, or MS-DOS device drivers
  • Displaying the status of virtual machines (VMs)
  • Monitoring all interrupts and exceptions
  • Developing and debugging virtual devices (VxDs)

This section gives information about how to use WDEB386 commands and features.


Breaking into the Debugger

To execute debugging commands, you need to break into the debugger and have it display its command prompt. You can automatically break into the debugger as Windows starts by specifying /B option on the WDEB386 command line or in a y command with the DebugCmd setting in the SYSTEM.INI file. The debugger stops execution just after loading VxDs and just prior to initialization. Breaking in at Windows start time is useful if you want to setup breakpoints or use the ".VMM S" command to turn on verbose device tracing (which displays the name of each VxD before it is called, and OK when the VxD returns)

To break into the debugger at any time interrupts are not disabled, press the CTRL+C key combination on the debugging terminal. Alternately, press the CTRL+ALT+SYSRQ key combination on the computer running the debugger. This stops execution at the next convenient location in ring 0 or ring 3 code.

To break into the debugger when interrupts are disabled, you use hardware to generate a nonmaskable interrupt (NMI). This usually means having an external "STOP" button connected to a debugging card installed in computer running the debugger. Some machines may have the capability of connecting a front panel button to the NMI line on the machine bus. In any case, using NMI has the advantage of being able to break into a machine that has hung with interrupts disabled. (You can disable the breaking on nonmaskable interrupts by using the v2 command.)

You can have your application, DLL, or VxD break into the debugger by adding an int 1 or int 3 instruction or a call to the DebugBreak function to your code. The int 1 instruction produces an "Unexpected trace interrupt" message and stops on the instruction after the int 1. This message does not indicate an error condition and can be ignored. An int 3 will break directly on the int instruction and not produce the message. The int 3 is used in system components to stop execution on an error.

Once an int instruction is hit, you can remove it by using the z (Zap) command. This command replaces the int instruction with a nop instruction. For programmers developing virtual device drivers (VxDs), the Debug_Out macro is available to send an ASCII string to the debug terminal and execute an int 1, which will break to the debugger.

Once you have broken into the debugger, you can set additional breakpoints by using the bp or br command. For example, the following command sets a breakpoint at beginning of the function _MyEntryPoint:

bp _MyEntryPoint

The system also breaks into the debugger if an application or DLL causes a general protection fault (GPF) by attempting to read or write memory with a bad selector, beyond a selector limit, or with a selector set to 0. The debugger receives control immediately if it traps interrupt vector 0Dh (the default setting). If you disable this trap (by using the vs command), Windows first displays a dialog box notifying the user of a problem. The user can click the Debug button to pass control to the debugger at the instruction that caused the fault.


Determining the State of the Processor

Once control has been given to the debugger, the prompt character used will provide the protected mode status of the processor. The following list shows what prompt characters may be displayed and the meaning of each:

> or >> | The processor is in real mode (you should never see this when debugging Windows 9x)
# or ## | The processor is in protected mode
- or -- | The processor is in virtual 8086 (V86) mode

The mode the processor is in will be a good indication of what code is being executed. For example, if the prompt is a "#" (number sign), protected mode code is running. This can be a Windows-based application, DLL, or even the system itself. Stopping in ring 0 code may or may not be desirable. It is useful for VxD developers who need to examine and control execution of their VxDs, but it is not particularly useful for application or DLL developers.

If you are in V86 mode, then a DOS app, DOS device driver or DOS TSR has gone bad. Use the .DOSMGR commands to identify where you are. Do not use the LN command since it won't provide correct V86 information.

If you are in protected mode, then the lower two bits of CS can be used to identify the ring of execution (zero indicates ring 0, 3 indicates ring 3).

CS | Area | CS | Area
0028 | VxD code (ring 0) | 013F | Win32 flat code
0030 | VxD data (ring 0) | 0147 | Win32 flat data
0048 | debugger code | 011F | Krnl386 code
 |  | 0137 | Krnl386 data

The preceding selectors may be subject to changes in the future. Device driver developers generally debug VxD code, so the corresponding code selector value is usually 0028.

When in ring 0, the EIP should be of the form Cxxxxxxx. If it is not, some code jumped to an invalid address. Use ds esp to attempt to find out who did it.

A Win32 app's EIP should be in the range of 0x00400000-0xBFFFFFFF.

Regardless of the state of the processor, you can use the following command keys and the debugger prompt:

Key | Action
CTRL+A | Repeats the previous command.
CTRL+C | Cancels the current command.
CTRL+S | Freezes a System Debugger display.
CTRL+Q | Restarts the display.

If the target system is executing code, CTRL+S and CTRL+Q are ignored.


Setting Breakpoints

You can set breakpoints using the bp and br commands. With each breakpoint, you can specify breakpoint commands, a string of debugger commands that are executed when a breakpoint is hit. For example, the following command sets a breakpoint that stops execution in the function _MyEntryPoint and displays the registers and stack:

bp _MyEntryPoint+346 "r;k"

Semicolons (;) separate commands from one another. All text is converted to uppercase except for text surrounded by single quotation marks ('). Two single quotation marks ('') or two double quotation marks ("") in a row act as an escape character and add one single quotation mark or one double quotation mark to the string. The maximum length of a breakpoint command is 80 characters. If the breakpoint has no breakpoint command string, WDEB386 executes the default (zd) command.

The conditional execution command (j) is very useful in breakpoint commands. This command executes the command list if the expression evaluates to TRUE (nonzero). Otherwise, it continues to the next command in the command line (not including the ones in the command list parameter). If the command list contains more than one command, it must be enclosed in single or double quotation marks. Use a semicolon (;) to separate commands. No quotation marks are required if the command list contains zero or one command. The conditional execution command can be used in breakpoint commands to halt execution when an expression becomes true or in the default command.

Any operator, number, or symbol value can be used in the conditional expression. Always put a zero in front of a hexadecimal number that begins with a nonnumeric character. Doing so will prevent the debugger from treating the number as a symbol and searching all the loaded symbol files. For example, using 0f000 is faster than f000.

For example, the following command stops execution and display registers only if the variable _MyVar is equal to 3 when control enters the _MyEntryPoint function. Otherwise, it displays the current value and continues:

bp _MyEntryPoint "j _MyVar == 3 r;'? "_MyVar=%x" _MyVar;g'"

Here are some additional breakpoint examples:

##bl
0 d  %c02e9ba0 [VKD_Set_Focus + 33]
1 d  %c012a57c [VKD_VM_Service_Phys]
2 d  W4 %c012c4f8 [VKD_8042_cmd_table + 1e8]
3 e  %c012ad8f [VKD_Chk_BIOS_Toggle_State + 21] "? 'BIOS %X',AL;G"
4 e  %c02ea32d [Hot_Key_Ended + ae] "? 'PriNot %x', DW 0C012BC2D;G"
5 e  %c012aaa4 [Update_Shift_State]  "? '%X %X', DW 0C012BC2D, DW ESP;G"
6 e  %c012a8b1 [Queue_Output + 1] "J DI==8 R;G"
7 e  %c012a8b0 [Queue_Output] "J(AL==38 OR AL==0B8) '?''%X %X %X'',AL,DI,DW ESP;G';G"

Breakpoints zero and one are simple breakpoints; nothing much to say.

Breakpoint two is a write breakpoint, established via br w4 %0c012c4f8. This causes the debugger to halt whenever somebody (w)rites to the dword (4) at %c012c4f8. You can also set (r)ead and (e)xecute breakpoints. For read and write breakpoints, you also have to say the size of the object you want to break on, either 1, 2 or 4.

Breakpoint three is a simple command breakpoint. Whenever VKD_Chk_BIOS_Toggle_State+21 is hit, the command "? 'BIOS %X',AL;G" is executed. This command itself is in two parts. The first part is a ? command, which acts like printf. The print format is '%X' which means a hexadecimal value, and the argument is AL. So what the print command does is display the current value of the al register. The second command is G, which tells the debugger to resume execution after doing the requisite printing.

Breakpoint four is a minor extension of breakpoint three. Instead of printing AL, it prints DW 0C012BC2D. As previously noted, the DW operator dereferences the dword at the specified location. So breakpoint four, when hit, displays the current dword value stored at address 0C012BC2D.

Breakpoint five is a minor extension of breakpoint four. A second value is printed, DW ESP. This displays the dword at the top of the stack, which is the address of the caller.

Breakpoint six is a simple conditional breakpoint. When the breakpoint is hit, the expression DI==8 is evaluated. If true, then R is executed (displaying registers); otherwise G is executed (resume execution). In other words, the breakpoint means Stop if DI==8.

Breakpoint seven combines all the tricks. The condition is (AL==38 OR AL==0B8). If the condition is met, then three values are printed, and execution continues. If the condition is not met, then execution continues without printing anything. Note first that quotation marks are used to enclose the commands to be executed if the condition is met. This needs to be done to protect the semicolon embedded within the command string from being interpreted as the end of the J command. Note second that the quotation marks that provide the print format are doubled, because they already live inside the quotation marks that are used to enclose the conditional command.

Debugger breakpoints can be "used" as markers by merely setting a (disabled) breakpoint at an address you will need to refer to frequently. For example:

## bp 12345678
## bd0 &qquad;assuming that 12345678 was bp0
## d br0+10 &qquad;    dump at 12345688

If the code containing a breakpoint gets paged out to disk, you cannot remove that breakpoint until it is paged back in.


Using Symbols with WDEB386

With WDEB386, all symbols are maintained into one single namespace. Symbols are explicitly manageed using w, wr, and wa. You can selectively enable and disable entire symbol files. When disabled, the debugger ignores all symbols that belong to a symbol file ("map").

The w command lists all the maps that are loaded, both enabled and disabled.

The wr command disables a symbol file ("removes a map").

The wa command enables a symbol file ("adds a map").

For example, wr explorer will remove the explorer map from the debugger's symbol table. Keeping only the maps relevant to your project is important because the debugger's symbol table doesn't understand memory contexts.

As a shortcut, the asterisk means "all maps". So wr * disables all maps, and wa * re-enables them. Disabling all maps is useful if you want to discard all the symbolic information because the user is running with the wrong symbols.

Every symbol is mapped to a linear address, and that becomes its identity. In particular, the memory context and CPU mode are not factors in looking up a matching symbol. As a consequence, if you are running Win32 code, and you try to resolve an address that happens to match that of a Win16 driver or a DOS application, then you get symbols displayed that are irrelevant to the context of your code.

To search the active maps for symbols, you can us the ls (list symbols) or lse (list symbols by regular expression) commands. The argument is either a DOS-style (ls) or a UNIX-style (lse) pattern that will be looked up in all active maps. These are useful if you have the same symbol in multiple files and the debugger keeps picking the wrong one, and you choose not to go and disable all the maps that contain the bogus ones.

If you type a partial symbol name (at least five characters) and no perfect match is found, Wdeb386 will search for symbols that start with the characters you specify and present them in a list. You can then pick the one you really want and continue onwards.

If, in spite of everything, Wdeb386 can't find a symbol to match your address, it will search internal OS data structures, hoping to find something. If it has some Win16 address, it will walk the Win16 module list, checking to see if the selector is a code or data segment that belongs to any module in memory. If so, then it displays the address in the form MODULE!(n), where MODULE is the module name and n is the object number (1-based).

If the address lives in VxD space, then Wdeb386 will look at the list of in-memory VxDs and try to figure out which (if any) VxD contains the address. If found, the address is given in the form DDB(n)+zzzz, where DDB is the VxD DDB name, n is the object number, and zzzz is the offset within the object.

If the selector lives on the 16-bit global heap, but Wdeb386 can figure out which task allocated the memory, it will display the address in the form TASK!, where TASK! is the module name of the owner.

If the address lives in the Win32 memory space, then Wdeb386 will look at the page table entries and figure out which module table entry the memory belongs to. It will then display the address in the form IMTEnnnn+zzzz, where nnnn is the module table entry index, and zzzz is the rva. If Wdeb386 can find the Win32 module table on its own, then it will do the conversion of the IMTE into a module name and display the result in the form MODULE.DLL+zzzz, where MODULE.DLL is the name of the module and zzzz is the rva.

In summary:

  • MODULE!(n) Win16 module selector
  • TASK! Win16 global heap
  • IMTEnnnn+rva Win32 module
  • nnnnnnnn:DDB(n) VxD

If the symbol address is listed with an @-sign, it means that the module associated with the symbol is not in memory (or at least, is not in memory as far as Wdeb386 can determine). You can set a breakpoint on it. When the module finally gets loaded, Wdeb386 will instantiate the breakpoint.


If You Stop in the Debugger

If you do not see a reason why you stopped, the message may have been "lost in the noise." Disassemble backwards from the current location and see if any of the addresses pushed onto the stack are strings.

The following sample sessions indicate possible techniques to ferret out error message strings:

##u eip-0b L2
0028:........ push xxxxxxxx
0028:........ call dword ptr [__Debug_Out_Service (........)]
##da xxxxxxxx
0030:xxxxxxxx ... this is the error message...

##u eip-0a L2
0028:........ push xxxxxxxx
0028:........ call yyyyyyyy
##da xxxxxxxx
0030:xxxxxxxx ... this might be the error message...

##u eip-0d L3
0028:........ push xxxxxxxx
0028:........ call yyyyyyyy
0028:........ add esp, nn
##da xxxxxxxx
0030:xxxxxxxx ... this might be the error message...


Hard-coded Traps into the Debugger

Different components react to errors or assertion failure differently. Note that the following remarks are general principles; exceptions are not uncommon. Always cross-reference against the source code to be sure.

VMM32 uses int 3 for code coverage, int 1 for fatal errors, Debug_Out for assertion failures.

IOS uses int 3 for code coverage and Debug_Out for assertion failures. (Though it occasionally uses int 3 for assertion failures, too.)


If Your Code is at a Fault

Disassemble near the faulting location to see if what you get is proper code or not. Don't forget that ASCII text may look deceptively valid. Another thing to check is whether ESP and EIP are very close to each other. If so, this suggests a stack-balancing problem (too many pushes or pops). Dump the stack back to find the last known sane location and start working forwards.

Type u cs:eip to see if what you get is proper code or not. If you see any of the following, then you do not have proper code:

  • Any instruction of the form db xx.
  • Any instruction of the form lock xx.
  • Any instruction whose opcode begins with the letter f (floating point).
  • The same instruction repeated over and over, especially if it is one of the following:

    add byte ptr [eax], al

    and byte ptr [edi], al

    add byte ptr [bx+si], al

    and byte ptr [bx], al

  • Anything else that obviously makes no sense.

If that quick test passes, then type db cs:eip-40 and check if you are in the middle of a data segment. One dead giveaway is that you see ASCII strings in the dump.


If Ln cs:eip Gives You a Name

The command Ln cs:eip can supply you with the name of the module or routine. However, if you die very near the beginning of a routine, or if you see a message (in DEBUG) like 'Invalid mumble passed to ProcedureName', then the error is not in ProcedureName but rather in the caller. Dump the stack back to find the caller.


Reference

The following is a quick reference list of System Debugger commands, in order of Command Type.

Command | Command Type | Additional Arguments | Description
? |  |  | print help menu
? |  | <expr> | [h|d|t|o|q|b].<expr> | display expression (h = hex, d or t = decimal, o or q = octal, b = binary)
? |  | "printf string", <expr>, <expr>, | printf command
BC | Breakpoint/Step | [<bp list> | *] | clear breakpoint(s)
BD | Breakpoint/Step | [<bp list> | *] | disable breakpoint(s)
BE | Breakpoint/Step | [<bp list> | *] | enable breakpoint(s)
BL | Breakpoint/Step |  | list breakpoint(s)
BP | Breakpoint/Step | [<bp>] [<addr>] [<passcnt>] ["<bp cmds>"] | set a breakpoint
BR | Breakpoint/Step | [<bp>] E|W|R|1|2|4 [<addr>] [<passcnt>] ["<bp cmds>"] | set a Pentium processor debug register (hardware breakpoint).
C | Register, Memory, Port | <range> <addr> | compare bytes
D | Register, Memory, Port | [<range>] | dump memory
DA | Register, Memory, Port | [<range>] | dump asciiz string
DB | Register, Memory, Port | [<range>] | dump memory in bytes
DD | Register, Memory, Port | [<range>] | dump memory in dwords
DG[A] | 80386 Data Structure | [<range>] | dump GDT entries
DI[A] | 80386 Data Structure | [<range>] | dump IDT entries
DL[A|P|S|H] | 80386 Data Structure | [<range>] | dump LDT entries
DP[A|D] | 80386 Data Structure | [<range>] | dump page directory/table entries
DT | 80386 Data Structure | [<addr>] | dump TSS
DW | Register, Memory, Port | [<range>] | dump memory in words
DX | Miscellaneous |  | dump contents of loadall buffer
E | Register, Memory, Port | <addr> [<list>] | enter memory
F | Register, Memory, Port | <range> <list> | fill memory
G[S|H||T|Z] | Breakpoint/Step | [=<addr> [<addr> ...]] | go
H | Miscellaneous | <word> <word> | hexadd
I | Register, Memory, Port | <word> | input a byte from port
ID | Register, Memory, Port | <word> | input a dword from port
IW | Register, Memory, Port | <word> | input a word from port
J | Breakpoint/Step | <expr> [<cmds>] | execute <cmds> if <expr> is true (non-zero)
K[V|S|B] | Disassemble / Stack Trace | [<SS:BPaddr>] [<CS:IPaddr>] | stack trace
K[V|S|B]T | Disassemble / Stack Trace | [TDB] | task stack trace
KA | Disassemble / Stack Trace | <numargs> | set number of stack dump arguments
LA | Symbol, Symbol Map | [<mapname>] | list absolute symbols in active maps
LG | Symbol, Symbol Map | [<mapname>] | list groups in active maps
LM | Symbol, Symbol Map |  | list linked and active maps
LN | Symbol, Symbol Map | [<addr>] | list near symbols
LS | Symbol, Symbol Map | [<addr>] | list symbols in group
LSE | Symbol, Symbol Map | <re> | list symbols specified by regular expression
M | Register, Memory, Port | <range> <addr> | move
O | Register, Memory, Port | <word> <byte> | output a byte to port
OD | Register, Memory, Port | <word> <dword> | output a dword to port
OW | Register, Memory, Port | <word> <word> | output a word to port
P[N|T|Z] | Breakpoint/Step | [=<addr>] [<word>] | program step
R[T]|[<reg>] | Register, Memory, Port | [[=] <word>] | Register The values used in the R cmd for changing the flags register are: FLAG SET CLEAR OverFlow OV NV Direction DN(Decr.) UP(Incr) Interrupt EI(Enabled) DI(Disabled) Sign NG(Neg) PL(Plus) Zero ZR NZ Aux Carry AC NA Parity PE (Even) PO(Odd) Carry CY NC Nested Task NT (toggles)
S | Register, Memory, Port | <range> <list> | search
T[A|C|N|S|X|Z] | Breakpoint/Step | [=<addr>] [<word>] [<addr>] | trace
U | Disassemble / Stack Trace | [<range>] | unassemble
V | Miscellaneous |  | Display debugger version/date
V[1 | 3] | Interrupt Vector |  | specify rings to intercept a trap vector
V2 |  |  | enable/disable NMI trapping in Ring 0
VC[N|P|V|R|F] | Interrupt Vector | <byte> ... | stop intercepting trap vector
VL[N|P|V|R|F] | Interrupt Vector |  | list trap vectors intercepted
VO [N|P|R|V] | Interrupt Vector |  | lists interrupt vectors in the display format based on the newvec option.
VS[N|P|V|R|F] | Interrupt Vector | <byte> ... | intercept trap vector, ring 3 only
VT[N|P|V|R|F] | Interrupt Vector | <byte> ... | intercept trap vector, all rings
W | Symbol, Symbol Map | [<map name>] | make named map active
WA | Symbol, Symbol Map | [<mapname> | *] | add a map to the active list
WR | Symbol, Symbol Map | [<mapname> | *] | remove a map from the active list
X | Miscellaneous |  | Dumps a listing of the current execution environment (Bug report info).
Y[?] | Miscellaneous |  | display/modify debugger options
Z | Breakpoint/Step |  | zap the previous INT 1 or the current INT 3 with NOP's
ZD | Miscellaneous |  | execute the default command
ZL | Miscellaneous |  | list the default command
ZS | Miscellaneous |  | set the default command

Dot commands

Dot commands are commands that are directed to the debugger entry point of a corresponding VxD. "System dot commands" are those commands that are always available There are dot commands for several debug binary VxDs. The "Required debug binary .VxD" column indicates the debug binary that must be loaded to use the corresponding dot command(s). Many of the following debugger dot commands first require the installation of their corresponding debug binary VXD version. The following system dot commands are applicable to Windows 95 Version B (OSR2), but are generally the same for Golden Windows 95.

Command | Additional Argument(s) | Required debug binary .VxD | Description
..<cmd> - Pass "cmd" directly to the VMM
.? (system) Prints help message
.<dev_name> - Display device (VxD) specific info (if supported by the VxD)
.B | <baud rate> [<port addr>] | (system) | Set COM baud rate/port addr (1 = COM1, 2 = COM2)
..BIOS BIOS BIOS (space for help)?

a Show all BIOS devnodes

e Dump recent BIOS events

l Show List (Show every PCI devnode)

s Show selected devnode

y Select devnode

z Select devnode by index
.CSP | VMM | Toggles catch stray pointer flag
.DF | (system) | Dumps the free list
.DG | [handle | selector | arena(386)] | (system) | Dumps the global heap
.DH | [0 (from top) | -1 (from bottom)] | (system) | Dumps the local heap
.DM | (system) | Dumps the Win16 module list
.DOSMGR - Dumps various data structures related to real-mode DOS.

[1] Display SFTs

[2] Display DPBs

[3] Display MCBs (dump the real-mode memory

map)

[4] Display CDSs

[5] Display PDBs (dump the real-mode process

map)

[6] Display DEVs

[7] Display BDSs

[8] Display INT 21h status
.DQ | (system) | Dumps the task queue
.DS | (system) | Dumps protected mode stack with labels. Dumps the VMM stack. Shows the stack pointer value, the DWORD contents and tries to display a code label that is near to each DWORD value. The label dump is sometimes useful for determining what chain of procedures have been executed to get to the current point, but it sometimes displays labels for DWORD values that really don't apply (i.e. 80000028 might display VMM_TEXT:DEBUG_ValidateLinear, when the value may really be from pushing the segment value 28, because pushing a segment value just decrements ESP and doesn't force a zero word for the high word.) So, this command can be useful, but requires some programmer interpretation to identify the correct stack trace.
.DU | (system) | Dumps the LRU list
.I? | IOS | Help menu for IOS commands
.IDCB | <addr> | IOS | Dumps I/O Subsystem Device Control Block structure.
.IIOP | <addr> | IOS | Dumps I/O Subsystem I/O Packet structure.
.IMED | IOS | Dumps I/O Subsystem Memory Element Descriptor structures.
.IDV | DISKVSD & IOS | Display disk calldown/callup statistics
.ISAPNP | ISAPNP | Display current read data port, followed by information about each ISA bus card (if any).
.LQ | VMM | Displays the queue of messages queued with the macro Queue_Out.
.M | (system) | Dump assorted memory manager structures. Type '.M?' for a list of memory structures, and additional information.
.MEMCHECK - Display misc. memory layout
.NTKERN | NTKERN | OSR 2.1 & Windows® 98 WDM (USB etc.) support. Typing this command supplies you with a menu, which includes the ability to dump its debug log ("D"). The debug log displays in LIFO order.
.P [?] DEBUGCMD Debugger tools when DEBUGCMD.VXD is installed (rename DEBUGCMD.TMP to DEBUGCMD.VXD, place it into \WINDOWS\SYSTEM, and load it by putting DEVICE=DEBUGCMD.VXD in the [386Enh] section of the SYSTEM.INI file):

.p? Main help menu

.p<cmd>? For more extensive help on a cmd

.p lists threads in system

.p <*/thread id> lists status of one thread

.pf lists threads and their flags

.ps <Thread handle/id> Dumps ring 0 stack with labels

.psx <Thread handle/id> Dumps 20 lines of ring0 stack and returns

.pdev <Address> Finds nearest VXD name

.plog <flags> Set scheduler query logging flags

.pmtx <Mutex Address> display mutex state

.psem <Semaphore Address> display semaphore state

.pthcb <Thread handle/id> display thread control block

.pprd Disables the logging of priority changes

.ppre Enables the logging of priority changes

.pprf <filter> Logs only boosts changing these bits

.pprl <Thread handle/id> Lists priority changes recorded

.pmax Show thread and VM maximum DOS386 stack usage
.PCI PCI PCI debug utility. Note that to use .PCI you must remove debugcmd.vxd from the system because its .P command prevents .PCI from being recognized.

"Welcome to PCI's debugger"

A show All; Show every PCI devnodes

B show Busses; Show PCI bus structure

C Config space; Toggle full/partial config space

D Enter dwdata; Enter data in config space in dwords

E Enter data; Enter data in config space

F FindIRQRoute; Help find the IRQ routing

G Global info; Show global PCI info

I IDE Test; See if secondary IDE is enabled

L show List; Show every PCI devnodes (short)

Q Quit; Quit the debugger

R show Rom; Show ROM of selected devnode

S Show selected; Show selected devnode

T Trace CS; Trace config space access

Y select devnode; Select DevNode

Z select devnode; Select DevNode by index
.R [#] - Displays the registers of the current thread. For example, if you used <ctrl c> to break into the system, this will show you the debugger's <ctrl c> handler.
.REBOOT | (system) | reboots machine
.S [#] VMM Displays short logged exceptions starting at #, if specified.
.SL [#] VMM Displays long logged exceptions just #, if specified.
.T | VMM | Toggles the trace switch.
.VC [#] ------ (system) Displays the current VMs control block
.VDMAD | VDMAD | Virtual DMA Device State Dump
.VDD VDD Virtual Display Device State Dump. Also offers additional options:

Select Option

1 - display VM register states

2 - display VM memory usage

3 - dump video page info

4 - display msg mode register state

5 - display planar mode register state

6 - read DAC

7 - display VM DAC states

8 - enable Queue_Outs

9 - enable MemC debug event
.VFLATD | VFLATD | Virtual Flat Video Buffer Device statistics and event log
.VH [#] ------ (system) Displays a VMM linked list, given list handle
.VKD VKD Virtual Keyboard Device

[0] - General info

[1] - Hot Key info

[2] - Per VM info

[3] - Set VKD queue_outs

[ESC] - Exit VKD debug query
.VL | (system) | Displays a list of all valid VM handles
.VM [#] ------ (system) Displays complete VM status
.VMM (system) Menu VMM state information:

[A] System time

[B] Display Critical Section info

[C] Display blocked thread information

[D] Reset dyna-link profile counts

[E] I/O port trap information

[F] Reset I/O profile counts

[G] Turn procedure call trace logging on

[H] V86 interrupt hook information

[I] PM interrupt hook information

[J] Reset PM and V86 interrupt profile counts

[K] Display event lists

[L] Display device list (all VxDs)

[M] Display V86 break points

[N] Display PM break points

[O] Display interrupt profile

[P] Reset interrupt profile counts

[Q] Display GP fault profile

[R] Reset GP fault profile counts

[S] Toggle verbose device call trace

[T] Dyna-link service profile information

[U] Fault Hook information

[V] Display time out queues

[W] PM CLI/STI trace info

[X] DPMI info
.VPICD - Virtual PIC Device status (status of hardware interrupts)

[1] Global PIC information (ring 0)

[2] Per-VM PIC information (virtualized VM state)

[3] IRQ handler information (hardware interrupts and who is responsible for each)
.VR [#] ------ (system) Displays the registers of the current VM (both the current and alternate registers). Used to examine both V86 mode and protected mode portions of the VM.
.VS [#] ------ (system) Displays the current VM's virtual mode stack
.VXDLDR - Displays the list of dynamically loaded devices
.Y <expr> CONFIGMG Displays CONFIGMG (Plug & Play) structures:

Welcome to CONFIGMG's debugger

A Arbitrators Show the list of arbitrators

B Block queue Prevent processing of events

C Query remove Query removal at happy time

d remove Removal at happy time

e toggle Echo Set the echo to a specified

level

f show Free Show free resources

g enumerate Enumerate a devnode

h Reenable Appy Reenable checking of query

remove

i Show Log Show procedural logs

j test walks Test our walk procedures

k Show stack Show stack of procedure logs

l show List Show devnode list

m screen size Set screen size

n Nuke logs Nuke the procedure logged

p Problem List devnodes with problems

q Quit Quit the debugger

r show Range Show a Range

s Show tree Show the hardware tree

t toggle time Toggle the display of time

u Unblock queue Restart processing of events

v View status View the global status of

CONFIGMG

w show all range Show all the rangelists

x eXclude Filter logging of procedure

logs

y force smthng Call some random HWProfile API

z Allow DLL call Allow the DLLs to be called

Where…

<range> = [<addr>] [<word>] | <addr> [L <word>]

<addr> = [& | #][<word>:]<word> | %<dword> | %%<dword>

<list> = <byte> <byte> ... | "string"

<binary ops> = : | * / MOD + . - << >> < > >= <= AND XOR OR && ||

<unary ops> = &seg #sel %lin %%phy ! NOT SEG OFF BY WO DW POI PORT WPORT

(OFF=offset, BY=byte, WO=word/16-bit near proc, DW=dword/32-bit proc, POI=16-bit FAR addr, PORT=I/O byte port, WPORT=I/O word port)

Regular expressions <re>:

. any character, [] character class, [a-z], [^a], etc

* match zero or more, # match zero or one, + match one or more

Supported printf format characters are:

   %%                                             %
   %c                                             character
   %[-][+][ ][0][width][.precision][p][n]d        decimal
   %[-][0][width][.precision][p][n]u              unsigned decimal
   %[-][#][0][width][.precision][p][n]x           hex
   %[-][#][0][width][.precision][p][n]X           hex
   %[-][0][width][.precision][p][n]o              octal
   %[-][0][width][.precision][p][n]b              binary
   %[-][width][.precision][a]s                    string
   %[-][width][.precision][a][p][n][L][H][N][Z]A  address
   %[-][width][.precision][a][p][n][L][H][N][Z]S  symbol
   %[-][width][.precision][a][p][n][L][H][N][Z]G  group:symbol
   %[-][width][.precision][a][p][n][L][H][N][Z]M  map:group:symbol
   %[-][width][.precision][a][p][n][L][H][N][Z]g  group
   %[-][width][.precision][a][p][n][L][H][N][Z]m  map
     a - pointer to a AddrS structure
     H - 16 bit offset
     L - 32 bit offset
     N - offset only
     Z - no address
     p - gets the previous symbol, address or offset
     n - gets the next symbol, address or offset

Prompts are:  > real mode
              - or -- virtual 8086 mode
              # or ## protected mode

COMMON SELECTOR VALUES:

CS | Area | CS | Area
0028 | VxD code (ring 0) | 013F | Win32 flat code
0030 | VxD data (ring 0) | 0147 | Win32 flat data
0048 | debugger code | 011F | Krnl386 code
 |  | 0137 | Krnl386 data


Parameters

You can separate command parameters with delimiters (spaces or commas), but a delimiter is required only between two consecutive hexadecimal values. The following commands are equivalent:

dCS:100 110
d CS:100 110
d,CS:100,110

Following are the parameters you can use with commands:

addr Represents an address parameter in one of four forms. For more information about the operators shown in the following address forms, see Binary and Unary Operators.

#1f:02C0 | Protected-mode address (selector:offset)
%31020 | Linear address
%%31020 | Physical address
&0100:02FF | Real-mode address (segment:offset)

Any of these specified address forms overrides the current address type.
byte | Specifies a two-digit hexadecimal value.
cmds | Specifies an optional set of debugger commands to be executed with the bp (Breakpoint) or j (Conditional) command.
count | Specifies a count. Valid values depend on the command with which this parameter is being used.
dword | Represents an eight-digit (four-byte) hexadecimal value. The DWORD data type is most commonly used as a physical address.
expr | Represents a combination of parameters and operators that evaluates to an 8-bit, 16-bit, or 32-bit value. An expr parameter can be used as a value in any command. An expr parameter can combine any symbol, number, or address with any of the binary and unary operators.
flags | Specifies one or more conditions. Valid conditions depend on the command with which this parameter is being used.
group-name | Specifies the name of a group that contains the map symbols you want to display.
list Specifies a series of byte values or a string. The list parameter must be the last parameter on the command line. Following is an example of the f (Fill) command with a list parameter:
fCS:100 42 45 52 54 41
map-name | Specifies the name of a symbol map file.
name-chars | Specifies one or more characters.
number | Specifies a numeric value. Valid values depend on the command with which this parameter is being used.
object | Specifies a handle, a selector, or a heap address.
option | Specifies an option. Valid options depend on the command with which this parameter is being used.
range Specifies the block of memory on which the command should operate. The range parameter can be two addresses (addr addr); or it can be one address and a length (addr L word, where word is the number of items on which the command should operate; 80h is the default value). Following are three valid examples:
CS:100 110
CS:100 L 10
CS:100

The limit for range is 10000h. To specify a word of 10000h using only four digits, use 0000h or 0h.

reg | Specifies the name of a microprocessor register.
string Represents any number of characters enclosed in single quotation marks (') or double quotation marks ("). For quotation marks that must appear within string, you must use two sets of quotation marks. For example, the following strings are valid:
'This ''string'' is OK.'
\"This \"\"string\"\" is OK.\"

However, the following strings are not valid:
\"This \"string\" is not OK.\"
\"This 'string' is not OK.\"

The ASCII values of the characters in the string are used as a list of byte values.

word | Specifies a four-digit (2-byte) hexadecimal value.


Binary and Unary Operators

Following, in descending order of precedence, are the binary operators that can be used in commands:

Operator | Meaning
( ) | Parentheses
: | Address binder
* | Multiplication
/ | Integer division
MOD | Modulus (remainder)
+ | Addition
– | Subtraction
> | Greater-than relational operator
< | Less-than relational operator
>= | Greater-than/equal-to relational operator
<= | Less-than/equal-to relational operator
== | Equal-to relational operator
!= | Not-equal-to relational operator
AND | Bitwise Boolean AND
XOR | Bitwise Boolean exclusive OR
OR | Bitwise Boolean OR
&& | Logical AND
|| | Logical OR

Following, in descending order of precedence, are the unary operators that can be used in commands:

Operator | Meaning
&(seg) | Address of segment value
#(sel) | Address of selector value
%%(phy) | Address as a physical value
%(lin) | Address as a linear value
– | Two's complement
! | Logical NOT operator
NOT | One's complement
SEG | Segment address of operand
OFF | Address offset of operand
BY | Low-order byte from given address
WO | Low-order word from given address
DW | Doubleword from given address
POI | Pointer (four bytes) from given address — this operator works only with 16:16 addresses
PORT | One (1) byte from given port
WPORT | Word from given port


Command Details

The following is a list of WDEB386 commands.


? (Help)

The ? command with no arguments displays a list of commands and syntax recognized by the debugger.


? (Evaluate Expression)

? [option.]expr
? "string", expr, ...

The ? command evaluates an expression and displays the result.

expr
Expression to evaluate. Can be a combination of numbers, addresses, and operators. Numbers are assumed to be hexadecimal. Addresses can be 32-bit physical addresses or protected-mode addresses (selector:offset). The number sign (#) operator overrides the current address type. Operators can be any listed in Binary and Unary Operators.
option
Format in which to display the expression. Can be one of these:
h. | Hexadecimal
d. | Decimal
t. | Decimal
o. | Octal
q. | Octal
y. | Binary

By default, the command displays all formats: decimal, hexadecimal, octal, binary, ASCII, and Boolean.

string
Formatting string. Can be a combination of text and zero or more of the following formatting descriptors and escape sequences:
%% Displays a percent sign (%).
%A | Displays matching expr as an address.
%b | Displays matching expr in binary format.
%c | Displays matching expr as a character.
%d | Displays matching expr in decimal format.
%G | Evaluates matching expr as an address and displays the group and symbol associated with the address in group:symbol format.
%M | Evaluates matching expr as an address and displays the map file, group and symbol associated with the address in map:group:symbol format.
%o | Displays matching expr in octal format.
%S | Evaluates matching expr as an address and displays the map file, group and symbol associated with the address.
%s | Evaluates matching expr as an address and displays the string at that address.
%u | Displays matching expr in unsigned decimal format.
%X | Displays matching expr in hexadecimal format.
%x | Displays matching expr in hexadecimal format
\a | Inserts a bell (alert) character.
\b | Inserts a backspace character.
\n | Inserts a new line character.
\r | Inserts a carriage return character.
\t | Inserts a horizontal tab character.

One expression must be given for each formatting descriptor in the string. Multiple expressions can be separated with commas (,) or spaces.

Formatting descriptors can have these optional prefixes:
A | [-][width][.precision][a][p][n][L][H][N]
b | [-][0][width][.precision][p][n]
d | [-][+][ ][0][width][.precision][p][n]
G | [-][width][.precision][a][p][n][L][H][N]
M | [-][width][.precision][a][p][n][L][H][N]
o | [-][0][width][.precision][p][n]
s | [-][width][.precision][a]
S | [-][width][.precision][a][p][n][L][H][N]
u | [-][0][width][.precision][p][n]
X | [-][#][0][width][.precision][p][n]
x | [-][#][0][width][.precision][p][n]

Specifying an asterisk (*) for the width or precision parameter causes the field width or precision, respectively, to be picked up from the next parameter. Decimal values can also be specified for the width and precision parameters. The prefix letters have these meanings:
a | Address argument size
H | Display 16-bit offset
L | Display 32-bit offset
N | Display offset only
p | Get the previous symbol, symbol address, or offset
n | Get the next symbol, symbol address, or offset

The following examples show simple commands and corresponding output:

? ds:esi
013f:000001B3 %00098953 %%00098953

// display the value of the arithmetic expression 3*4:
? 3*4
0Ch 12T 14Q 00001100Y '.' TRUE


bc (Breakpoint Clear)

bc list | *

The bc command removes one or more defined breakpoints.

list
Specifies any combination of integer values in the range 0 through 9. If you specify list, the debugger removes the specified breakpoints.
*
Clears all breakpoints.

This example removes breakpoints 0, 4, and 8:

bc 0 4 8


bd (Breakpoint Disable)

bd list | *

The bd command temporarily disables one or more breakpoints. To restore breakpoints disabled by the bd command, use the be (Breakpoint Enable) command.

list
Specifies any combination of integer values in the range 0 through 9. If you specify list, the debugger disables the specified breakpoints.
*
Disables all breakpoints.

This example disables breakpoints 0, 4, and 8:

bd 0 4 8


be (Breakpoint Enable)

be list | *

The be command restores (enables) one or more breakpoints that have been temporarily disabled by a bd (Breakpoint Disable) command.

list
Specifies any combination of integer values in the range 0 through 9. If you specify list, the debugger enables the specified breakpoints.
*
Enables all breakpoints.

This example enables breakpoints 0, 4, and 8:

be 0 4 8


bl (Breakpoint List)

bl

The bl command lists current information about all breakpoints created by the bp (Breakpoint) command. For each existing breakpoint, the command displays the breakpoint number, the enabled status ('e' for enabled, 'd' for disabled, 'I' for invalid), the breakpoint address, the number of passes remaining (if any), the initial number of passes in parentheses (if any), and debugger commands to be executed when the breakpoint is reached (if any). An invalid "I" breakpoint typically indicates the code has been paged out to disk; it may come back later. You can't remove an invalid breakpoint until it pages back in.

The following example shows a typical list:

0 d  %004010b5 [_MyTest] 4 (10) "db ds:edi"
1 eI %0040110f [_MyWndProc@16 + 5a]


bp (Breakpoint)

bp[number]addr [count] ["cmds"]

The bp command creates a software breakpoint at an address. When the application is running, software breakpoints stop execution and force the debugger to execute the default or optional command string. Unlike breakpoints created by the g (Go) command, software breakpoints remain in memory until you remove them with the bc (Breakpoint Clear) command or temporarily disable them with the bd (Breakpoint Disable) command.

number
Specifies which breakpoint is being created. No space is allowed between the bp and number. If number is omitted, the first available breakpoint number is used. The debugger allows up to 10 software breakpoints (0 through 9). If you specify more than 10 breakpoints, the debugger returns the message: "Too Many Breakpoints."
addr
Specifies any valid instruction address — the first byte of an operation code (opcode). The addr parameter is required for all new breakpoints.
count
Specifies the number of times the breakpoint is to be ignored before being executed. It can be any 16-bit value.
cmds
Specifies an optional list of debugger commands to be executed in place of the default command when the breakpoint is reached. You must enclose optional commands in quotation marks and separate optional commands with semicolons (;).

This example creates a breakpoint at address CS:401000:

bp 401000

This example creates breakpoint 8 at address given by the symbol _MyTest. When the breakpoint occurs, the debugger displays bytes at DS:SI:

bp8 _MyTest "db DS:SI"

You cannot set a breakpoint on memory that is not in context (however, you can set a hardware execution breakpoint on the linear address; see the br command).


br (Breakpoint Register)

br [number] flags [addr] [count] ["cmds"]

The Pentium processor contains four "hardware debug registers" that support hardware address breakpoints. Hardware debug registers allow the user to instruct the processor hardware to interrupt processor execution when specified addresses are read, written or executed. This is a very useful tool, for example, to find out what procedures are accessing or changing a specified memory variable.

The br command sets a Pentium debug register breakpoint, in order to "break" on data reads, writes and instruction execution. Up to four debug registers can be set and enabled at one time.

Hardware breakpoints take precedence over faults.

Since the four debug registers are global to the system, they should typically only be touched by a kernel mode debugger. See Knowledge Base Article Q137199, " PRB: Debuggers Cannot Reliably Use Debug Register Breakpoints" for more information.

See also the following MSDN Library CD article: Q105275, "Using the 'BR' Command in WDEB386.EXE".

number
Specifies which breakpoint is being created. No space is allowed between the br command and the number parameter. If number is omitted, the first available breakpoint number is used.
flags
Specifies the length and break conditions for the breakpoint. This parameter can be some combination of the following values:
1 | Set 1-byte length (default value).
2 | Set word length on word boundary.
4 | Set doubleword length on doubleword boundary.
E | Break on instruction execution only (1-byte length only).
W | Break on writes only.
R | Break on reads and writes.

addr
Specifies the address to be watched.
count
Specifies the number of times the breakpoint is to be ignored before being executed. It can be any 16-bit value.
cmds
Specifies an optional list of debugger commands to be executed in place of the default command when the breakpoint is reached. You must enclose the group of optional commands in quotation marks and separate optional commands with semicolons (;).


c (Compare)

c range addr

The c command compares one memory location with another memory location. If the two memory areas are identical, the debugger displays nothing and returns the debugger prompt. Differences, when they exist, are displayed in this form: addr1 byte1 byte2 addr2.

range
Specifies the block of memory that is to be compared with a block of memory starting at addr.
addr
Specifies the starting address of the second block of memory.

This example compares the bytes at addresses in the range 100h to 1FFh with the corresponding bytes at address from 300h to 3FFh:

c100 1FF 300

This example compares the same block of memory as the previous example but specifies the range by using the L (length) option.

c100 L 100 300


d (Display)

d [range]

The d command displays the contents of memory at a given address or in a range of addresses. The d command displays one or more lines, depending on the range given. Each line displays the address of the first item displayed. The command always displays at least one value. The memory display is in the format defined by a previously executed da, db, dd, or dw command. Each subsequent d (typed without parameters) displays the bytes immediately following those last displayed.

range
Specifies the block of memory to display. If you omit range, the d command displays the next byte of memory after the last one displayed. The d command must be separated by at least one space from any range value.


da (Display ASCII)

da [range]

The da command displays as ASCII characters the values of the bytes at a given address or in a given range. The display includes all bytes up to the first zero byte. Nonprinting characters and characters having values greater than 127 are denoted by a period (.).


db (Display Bytes)

db [range]

The db command displays the values of the bytes at a given address or in a given range.

The display is in two portions: a hexadecimal display (each byte is shown in hexadecimal format) and an ASCII display (the bytes are shown as ASCII characters). A nonprinting character is denoted by a period (.) in the ASCII portion of the display. Each display line shows 16 bytes, with a hyphen between the eighth and ninth bytes. Each displayed line begins on a 16-byte boundary.

range
Specifies the block of memory to display. If you omit range, 128 bytes are displayed beginning at the first address after the address displayed by the previous db command.

The following example displays 0Ah bytes of memory, beginning at the specified address:

db CS:100 0A

This example displays lines in a format similar to the following:

04BA:00000100 54 4F 4D 20 53  . . . 45 52 TOM SAWYER

Each line of the display begins with an address, incremented by 10h from the address on the previous line.


dd (Display Doublewords)

dd [range]

The dd command displays the hexadecimal values of the doublewords at the address specified or in the specified range of addresses. The dd command displays one or more lines, depending on the range given. Each line displays the address of the first doubleword in the line, followed by up to four hexadecimal doubleword values. The hexadecimal values are separated by spaces. The dd command displays values up to the end of the range or until the first 32 doublewords have been displayed.

range
Specifies the block of memory to display. If you omit range, 32 doubleword values are displayed beginning at the first address after the address displayed by the previous dd command.

The following example displays the doubleword values from CS:100 to CS:110:

dd CS:100 110
04BA:0100 7473:2041 676E:6972 5405:0104 0A0D:7865
04BA:0110 0000:002E

No more than four values per line are displayed.


dg (Display GDT)

dg[a] [range]

The dg command displays the specified range of entries in the global descriptor table (GDT).

a
Displays all entries in the table, not just the valid ones. By default, only the valid GDT entries are displayed. If range specifies a local descriptor table (LDT) selector, the command displays the appropriate LDT entry.
range
Specifies the range of entries to be displayed. If you omit range, the entire table is displayed.

The command displays the selector, descriptor type, base address, limit, privilege, and other descriptor flags.


di (Display IDT)

di[a] [range]

The di command displays the specified range of entries in the interrupt descriptor table (IDT).

a
Displays all entries in the table, not just the valid ones.
range
Specifies the range of entries to be displayed. If you omit range, the entire table is displayed.

The command displays the interrupt number, the interrupt type, the interrupt address, privilege, and descriptor flags.


dl (Display LDT)

dl[a | p | s | h] [range]

The dl command displays the specified range of entries in the local descriptor table (LDT).

a
Displays all entries in the table, not just the valid ones. By default, only the valid LDT entries are displayed. If range specifies a global descriptor table (GDT) selector, it displays the appropriate GDT entry.
p
Displays private segment selectors.
s
Displays shared segment selectors.
h
Displays huge segment selectors. To display the huge segment selectors, give the shadow selector followed by the maximum number of selectors reserved for that segment plus one (1).
range
Specifies the range of entries to be displayed. If you omit range, the entire table is displayed.

The command displays the selector, descriptor type, base address, limit, privilege, and other descriptor flags.


dp (Display Page Directory and Tables)

dp[a|d] [range]

The dp command displays the page directory and page tables. Page tables are always skipped if the corresponding page directory entry is not present. Page directory entries appear with an asterisk next to the page frame.

a
Displays all present page directory and page table entries; by default, page directory and page table entries that are zero are skipped.
d
Displays only page directory entries. If a count is given as part of the optional range, it will be interpreted as a page directory entry count.
range
Specifies the range of linear addresses for page tables.

The command displays the entry address, frame, and entry flags. Page directory entries are marked with an asterisk (*). Entry flags have the following meanings:

A | Accessed
c | clean
CD | Cache Disable
D | Dirty
n | Not-present
P | Present
r | Read-only
s | Supervisor
U | User
u | Unaccessed
W | writeable
WT | Write Through


dt (Display Task State Segment)

dt [addr]

The dt command displays the current task state segment (TSS) or the selected TSS if you specify the optional address. More information about the TSS can be found in Intel's "Pentium Processor User's Manual, Volume 3" (1993). This command can be useful to view the register state at the time a double-fault occurs (dt 18:0).

addr
Specifies the address of the TSS to display. If no addr is given, dt displays the current TSS pointed to by the TR register.


dw (Display Words)

dw [range]

The dw command displays the hexadecimal values of the words at a given address or in a given range of addresses. The command displays one or more lines, depending on the range given. Each line displays the address of the first word in the line, followed by up to eight hexadecimal word values. The hexadecimal values are separated by spaces. The command displays values until the end of the range or until the first 64 words have been displayed.

range
Specifies the range of addresses to display. If you omit range, 64 words are displayed beginning at the first address after the address displayed by the previous dw command.

The following example displays the word values from CS:100 to CS:110:

dw CS:100 110
04BA:0100 2041 7473 6972 676E 0104 5404 7865 0A0D
04BA:0110 002E


dx (Display Loadall Buffer)

dx

Displays the contents of the loadall buffer.


e (Enter)

e addr [list]

The e command enters byte values into memory at a specified address. You can specify the new values on the command line or let the debugger prompt you for values.

addr
Specifies the address of the first byte to be entered.
list
Specifies the byte values used for replacement. These values are inserted automatically. If an error occurs when you are using the list form of the command, no byte values are changed.

If the debugger prompts you, it displays the address and its contents and then waits for you to perform one of the following actions:

  • Replace a byte value with a value you type. Type the value after the current value. If the byte you type is an invalid hexadecimal value or contains more than two digits, the system does not echo the illegal or extra character.
  • Press the SPACEBAR to advance to the next byte. To change the value, type the new value after the current value. If, when you press the SPACEBAR, you move beyond an 8-byte boundary, the debugger starts a new display line with the address displayed at the beginning.
  • Type a hyphen (-) to return to the preceding byte. If you decide to change a byte before the current position, typing the hyphen returns the current position to the previous byte. When you type the hyphen, a new line is started with its address and byte value displayed.
  • Press ENTER to terminate the e command. You can press ENTER at any byte position.

The following example prompts you to change the value EB at CS:100:

eCS:100
04BA:0100 EB.

To step through the subsequent bytes without changing values, press the SPACEBAR. In the following example, the SPACEBAR is pressed three times:

04BA:0100 EB.41  10. 00. BC.

To return to a value at a previous address, type a hyphen, as shown in the following example:

04BA:0100  EB.41    10. 00. BC.-
04BA:0102  00.-
04BA:0101  10.

This example returns to the address CS:101.


f (Fill)

f range list

The f command fills the addresses in a specified range with the values in the specified list.

range
Specifies the block of memory to be filled. If range contains more bytes than the number of values in list, the debugger uses list repeatedly until all bytes in range are filled. If any of the memory in range is not valid (bad or nonexistent), an error occurs in all succeeding locations.
list
Specifies the list of values to fill the given range. If list contains more values than the number of bytes in range, the debugger ignores the extra values in list.

The following example fills memory locations 04BA:100 through 04BA:1FF with the bytes specified, repeating the five values until it has filled all 100h bytes:

f04BA:100 L 100 42 45 52 54 41


g (Go)

g[s|h|t|z] [=addr [addr[...]] ]

The g command executes the application currently in memory. If you type the g command by itself, the current application runs as if it had been run outside the debugger. If you specify =addr, execution begins at the specified address.

s
Shows the time, in microseconds, from when the system is started with gs until the next entry to the debugger. No attempt is made to calculate and remove debugger overhead from the measurement. Requires a timing card. See MSDN Library CD: Q85897, "WDEB386-Compatible Timing Card Available".
h
Displays the approximate debugger overhead in the s option. Requires a timing card.
t or z
Allows trapped exceptions to resume at the original trap handler address without having to unhook the exception. Use these options instead of the vcp d; t; vsp d commands. Use gt when the debugger catches a fault, in order to continue (resume) execution.
=addr
Specifies the address at which execution is to begin. The equal sign (=) is needed to distinguish the starting address from the breakpoint address.
addr
Specifies one or more breakpoint addresses where execution is to halt. You can specify up to 10 breakpoints, but only at addresses containing the first byte of an operation code (opcode). If you attempt to set more than 10 breakpoints, an error message is displayed.

Specifying an optional breakpoint address causes execution to halt at the first address encountered, regardless of the position of the address in the list of addresses that halts execution or application branching. When execution of the application reaches a breakpoint, the default command string is executed.

The stack (SS:SP) must be valid and have 6 bytes available for this command. The g command uses an iret instruction to cause a jump to the application being tested. The stack is set, and the user flags, CS register, and IP register are pushed on the user stack. (If the user stack is not valid or is too small, the operating system may crash.) An interrupt code (0CCh) is placed at the specified breakpoint addresses.

When the debugger encounters an instruction with the breakpoint code, it restores all breakpoint addresses listed with the g command to their original instructions. If you do not halt execution at one of the breakpoints, the interrupt codes are not replaced with the original instructions.

The following example executes the application currently in memory until address 7550 in the CS selector is executed. The debugger then executes the default command string, removes the int 3 trap from this address, and restores the original instruction. When you resume execution, the original instruction is executed.

gCS:7550

The command g dw esp can be used to go back to the flat 32-bit calling procedure.

The command g wo ss:sp can be used to go back to the 16-bit near calling procedure.

The command g poi ss:sp can be used to go back to the 16-bit far calling procedure.


h (Hex)

h word word

The h command performs hexadecimal arithmetic on the two specified parameters. The debugger adds, subtracts, and multiplies the two parameters; divides the second parameter by the first; and then displays the results on one line. The debugger does 32-bit multiplication and displays the result as doublewords. The debugger displays the result of division as a 16-bit quotient and a 16-bit remainder.

word
Specifies a 16-bit word parameter.


i (Input)

i word

The i command accepts and displays 1 byte (8 bits) from a specified port.

word
Specifies the 16-bit port address.

The following example displays the byte at port address 2F8h:

i2F8


id (Input)

id word

The id command accepts and displays 1 doubleword (32 bits) from a specified port.

word
Specifies the 16-bit port address.

The following example displays the doubleword at port address 2F8h:

i2F8


iw (Input)

iw word

The iw command accepts and displays 1 word (16 bits) from a specified port.

word
Specifies the 16-bit port address.

The following example displays the word at port address 2F8h:

i2F8


j (Conditional)

j expr [cmds-if-true][;cmds-if-false]

The j command executes selected commands based on whether the specified expression is TRUE or FALSE. The j command is useful in breakpoint commands to conditionally break execution when an expression becomes TRUE.

expr
Evaluates to a Boolean TRUE or FALSE.
cmds-if-true
Specifies a list of debugger commands to be executed when expr is TRUE. More than one command can be given, but the commands must be separated by semicolons and the complete list must be enclosed in single or double quotation marks.
cmds-if-false
Specifies a list of debugger commands to be executed when expr is FALSE. The preceding semicolon is required. More than one command can be given, but the commands must be separated by semicolons and the complete list must be enclosed in single or double quotation marks.

The following example causes execution to continue if EAX equals zero when the breakpoint is reached:

bp 167:1454 "J EAX == 0 G"

The following example displays the registers and continues execution when the byte pointed to by DS:SI +3 is equal to 40h; otherwise, it displays the descriptor table:

bp 167:1462 "J BY (DS:SI+3) == 40 'R;G';DG DS"


k (Stack Trace)

k[b|s|v] [addr] [addr]

This command displays the current (EBP-based) stack frame. Each line shows the name of a procedure, its arguments, and the address of the statement that called it. The command displays four 2-byte arguments by default. The ka command changes the number of arguments displayed by this command.

b
Indicates the stack frame is 32 bits wide.
s
Indicates the stack frame is 16 bits wide.
v
Displays the verbose version of stack information — that is, information about stack location and frame pointer values for each frame.
addr
Specifies an optional stack-frame address (SS:EBP) or an optional code address (CS:EIP).

Using the k command at the beginning of a function (before the function prolog has been executed) gives incorrect results. The command uses the BP register to compute the current backtrace, and this register is not correctly set for a function until its prolog has been executed.


ka (Stack Trace Arguments)

ka count

The ka command sets the number of arguments displayed for all subsequent stack trace commands. The initial default value is 4.

count
Specifies the number of arguments to be displayed. The count parameter must be in the range 0 through 1Fh.


kt (Stack Trace for Task)

k[b|s|v]t [addr]

This command displays the stack frame of the current task or the task specified by the addr parameter. Each line shows the name of a procedure, its arguments, and the address of the statement that called it. The command displays four 2-byte arguments by default. The ka command changes the number of arguments displayed by this command.

b
Indicates the stack frame is 32 bits wide.
s
Indicates the stack frame is 16 bits wide.
v
Displays the verbose version of stack information — that is, information about stack location and frame pointer values for each frame.
addr
Specifies the segment address of the process descriptor block (PDB) for the task to be traced. To obtain the addr value, use the .dq (Dump Task Queue) command. If addr is not supplied, the kt command displays the stack frame of the current task.


la (List Absolute Symbols)

la

The la command lists the absolute symbols in the active map.


lg (List Groups)

lg

The lg command lists the address and the name of each group in the active map.


lm (List Maps)

lm

The lm command lists the symbol files currently loaded and indicates which one is active. The last symbol file loaded is made active by default. Use the w (Change Map) command to change the active file.


ln (List Nearest Symbol)

ln [addr]

The ln command lists the symbol nearest the specified address. The command lists the nearest symbol before and after the specified addr parameter. This command also shows line-number information if it is available in the symbol file.

addr
Specifies any valid instruction address. The default value is the current disassembly address.

The ln command without the addr parameter displays the nearest symbols before and after the current disassembly address.

Example: ln dw(esp) Lists the nearest symbol with respect to the caller (pushed address on stack)


ls (List Symbols)

ls group-name | name-chars | *

The ls command lists the symbols in the specified group or lists names that match the search specification in all groups. The search specification uses DOS-style semantics. The only valid wildcard is a single asterisk (*) as the last character on the command line; all other characters are ignored.

group-name
Names the group that contains the symbols you want to list, for example ESDI_506.
name-chars
Specifies the beginning characters of the symbols you want to list.


lse (List Symbols by Regular Expression)

lse regular-expression

The lse command lists the symbols specified by the given regular expression. The search specification uses UNIX-style semantics.

regular-expression
Can be a regular expression as described in Command Syntax.


m (Move)

m range addr

The m command moves a block of memory from one memory location to another. If part of the destination block overlaps some of the source block, the move is always performed without loss of data. Addresses that could be overwritten are moved first.

range
Specifies the block of memory to be moved.
addr
Specifies the starting address at which the memory is to be relocated.

For moves from higher to lower addresses, the sequence of events is first to move the data at the block's lowest address and then to work toward the highest. For moves from lower to higher addresses, the sequence is first to move the data at the block's highest address and then to work toward the lowest.

The following example first moves the data at address CS:110 to CS:510 and then moves the data at CS:10F to CS:50F, and so on, until the data at CS:100 is moved to CS:500:

mCS:100 110 CS:500


o (Output)

o word byte

The o command writes a byte to a 16-bit port address.

word
Specifies the 16-bit port address to be written to.
byte
Specifies the 8-bit value to be written to the port.

The following example writes the byte value 4Fh to output port 2F8h:

o 2F8 4F


od (Output)

o word dword

The o command writes a dword to a 16-bit port address.

word
Specifies the 16-bit port address to be written to.
dword
Specifies the 32-bit value to be written to the port.

The following example writes the byte value 8000004Fh to output port 2F8h:

o 2F8 8000004F


ow(Output)

o word word

The o command writes a word to a 16-bit port address.

word
Specifies the 16-bit port address to be written to.
word
Specifies the 16-bit value to be written to the port.

The following example writes the word value 804Fh to output port 2F8h:

o 2F8 804F


p (Program Trace)

p[n|t|z] [=addr][count]

The p command executes the instruction at a specified address and displays the current values of all the registers and flags (whatever the zd command has been set to). It then executes the default command string, if any. The p command is identical to the t (Trace Instructions) command, except that it automatically executes and returns from any calls or software interrupts it encounters. The t command always stops after executing into the call or interrupt, leaving execution control inside the called routine.

n
Suppresses the register display so just the assembly line is displayed. The suppression results only if the default command, zd, is set to a normal setting, r.
t or z
Allows trapped exceptions to resume at the original trap handler address without having to unhook the exception.
addr
Specifies the starting address at which to begin execution. If you omit the optional addr parameter, execution begins at the instruction pointed to by the CS and IP registers. Use the equal sign (=) only if you specify addr.
count
Specifies the number of instructions to execute before stopping and executing the default command string. The command executes the default command string for each instruction before executing the next.

The following example executes the instruction pointed to by the current CS and IP register values before it executes the default command string:

p

The following example executes the instruction at address CS:120 before it executes the default command string:

p=120

Program tracing through popf or popfd usually does not work.


r (Register)

r[t][reg[=value]]

The r command displays the contents of one or more central processing unit (CPU) registers and allows the contents to be changed to new values. If you specify the reg parameter with the r command, the command displays the value of that register in hexadecimal format and prompts for a new value. If you specify a reg and a value, the command sets the register to the given value.

t
Displays registers in terse format.
reg
Specifies the register to be displayed. If you specify f or msw for reg, the debugger displays the flags in a row at the beginning of a new line and prompts for one or more flag values. If you omit reg, the debugger displays the contents of all registers and flags along with the next executable instruction.
value
Specifies the new value for the register. Can be a number or a combination of these flag values:
OV | Overflow set
NV | Overflow clear
DN | Direction decrement
UP | Direction increment
EI | Interrupt enabled
DI | Interrupt disabled
NG | Sign negative
PL | Sign positive
ZR | Zero set
NZ | Zero clear
AC | Auxiliary carry set
NA | Auxiliary carry clear
PE | Parity even
PO | Parity odd
CY | Carry set
NC | Carry clear
NT | Nested task switch (on and off)

TS | Sets the task switch bit. (MSW only)
EM | Sets the emulation processor extension bit. (MSW only)
MP | Sets the monitor processor extension bit. (MSW only)
PM | Sets the protected-mode bit. (MSW only)

Flag values can be in any order. You do not have to leave spaces between these values.

If you type more than one value for a flag or enter an invalid flag name, the flags up to the error in the list are changed and those flags at and after the error are not changed. In addition, the debugger display the message: "Bad Flag."

Setting the protected-mode bit from within the debugger does not set the target system to run in protected mode. The debugger simulates the setting. To configure the target system to run in protected mode, you would have to set the PM bit in the MSW register and reset the target system to restart in protected mode.

See also the .r command.


s (Search)

s range list | "string"

The s command searches an address range for a specified list of bytes or an ASCII character string. You can include one or more bytes in list, but multiple bytes must be separated by a space or comma. When you search for more than one byte, the command returns the address of only the first byte in the string. When list contains only one byte, the debugger displays the addresses of all occurrences of the byte in range.

range
Specifies the block of memory to be searched.
list
Specifies one or more byte values to search for.
string
Specifies an ASCII character string to be searched for. The string must be enclosed in quotation marks.

The following example searches for byte 41h in the address range CS:100 to CS:110:

sCS:100 110 41
04BA:0104
04BA:010D


t (Trace)

t[a|c|n|s|x|z][=start_addr][count][addr]

The t command executes one or more instructions along with the default command string and then displays the decoded instruction. If you include the start_addr parameter, tracing starts at the specified address. Otherwise, the command steps through the next machine instruction and then executes the default command string. The t command uses the hardware trace mode of the Intel microprocessor. Consequently, you can also trace instructions stored in read-only memory (ROM).

a
Indicates that an ending address is specified for the trace. Instructions are traced until the address in addr is reached.
c
Suppresses all output and counts instructions traced. An ending address is required for this command. Instructions are traced until the address in addr is reached.
n
Suppresses the register display so just the assembly line is displayed. This works only if the default command, zd, is set to r (the normal setting).
s
Suppresses output; the instruction and count are displayed for each call and the return from that call.
x
Forces the debugger to trace regions of code known to be untraceable (_PGSwitchContext, for example).
z
Allows original trap handler address to be traced into without having to unhook the exception. Use this option instead of vcp d; t; vsp d.
start_addr
Specifies the instruction address at which to start tracing. The equal sign (=) is required.
count
Specifies the number of instructions to execute and trace.
addr
Specifies the instruction address at which to stop tracing.

The following command causes the debugger to execute 16 (10h) instructions beginning at 011A in the current selector:

t=011A 10

The debugger executes and displays the results of the default command string for each instruction. The display is scrolled until the last instruction is executed. Press the CTRL+S key combination to stop the scrolling and CTRL+Q to resume.

This command does not trace into INTs (but will trace out), and tracing through popf or popfd usually does not work.


u (Disassemble)

u [range]

The u command disassembles bytes and displays the source statements, with addresses and byte values that correspond to them. The display of disassembled code looks similar to a code listing for an assembled file. If you type the u command by itself, 20h bytes are disassembled at the first address after the one displayed by the previous u command.

range
Specifies the block of memory in which instructions are to be disassembled. If no range is given, the command disassembles the next 20h bytes.


v (Version Number)

v

The v command displays the current debugger version number and date.


vc (Vector Clear)

vc[n | p | r | v] number[,number [,...]]

The vc command clears the specified interrupt vector and reinstalls the previous interrupt vector.

n
Removes the beep from traps that beep when encountered; does not clear the traps.
p
Clears protected-mode vectors only.
r
Clears real-mode vectors only.
v
Clears virtual 8086 (V86) mode vectors only.
number
Specifies the interrupt vector to clear.

For protected-mode games, type vcp 1 3 before running the app, and vtp 1 3 after exiting the app, to avoid "unexpected trace interrupt" errors. For DOS apps, use vcv 1 3 and vsv 1 3. To recover from the error message, first remove the vector, then type gt.


vl (Vector List)

vl[n | p | r | v]

Lists the interrupt vectors that the debugger intercepts. Vectors that have been set with the vt command (as opposed to vs) are listed with an asterisk (*) following the vector number.

n
Lists the traps that beep when encountered.
p
Lists the protected-mode vectors only.
r
Lists the real-mode vectors only.
v
Lists the virtual 8086 (V86) mode vectors only.


vo (Vector List New)

vo[n | p | r | v]

The vo command lists interrupt vectors in the display format based on the newvec option. For details, see the y command.

n
Lists the traps that beep when encountered.
p
Lists the protected-mode vectors only.
r
Lists the real-mode vectors only.
v
Lists the virtual 8086 (V86) mode vectors only.


vs (Vector Trap Non-Supervisor)

vs[n | p | r | v] number[,number[,...]]

The vs command adds a new interrupt vector to the list of intercepted vectors. Vectors set by this command do not intercept interrupts that occur at ring 0.

n
Beep when trap encountered.
p
Set trap for protected-mode vectors only.
r
Set trap for real-mode vectors only.
v
Set trap for virtual 8086 (V86) mode vectors only.
number
Specifies the interrupt vector to intercept.


vt (Vector Trap)

vt[n | p | r | v] number[,number[,...]]

The vt command adds a new interrupt vector to the list of intercepted vectors.

n
Beep when trap encountered.
p
Set trap for protected-mode vectors only.
r
Set trap for real-mode vectors only.
v
Set trap for virtual 8086 (V86) mode vectors only.
number
Specifies the interrupt vector to intercept.


w (Change Map)

w [map-name]

The w command changes the active map file.

map-name
Specifies the name of the map file you want to make active. Use the lm (List Map) command to display a list of available map files.

If map-name is not specified, the loaded maps are displayed and the user is prompted to select a map by pressing its corresponding number.


wa (Activate Map)

wa map-name

The wa command adds the specified map to the list of active maps.

map-name
Specifies the map to add to the list of active maps.


wr (Deactivate Map)

wr map-name

The wr command removes the specified map from the list of active maps.

map-name
Specifies the map to remove from the list of active maps.


x (Dump Debug Report)

x

Dumps a listing of the current execution environment.


y (Debugger Options)

y[? | option]

The y command changes the debugger configuration. The following list describes the available configuration options. All settings are toggles.

?
Displays a list of supported options.
option
Following are the available configuration options:
/a | Controls automatic symbol loading. If this option is set, Windows will not load symbols automatically.
/n | Sets the following options, listed in more detail in the following:

codebytes dislwr int3line newprompt newreg newvec symaddrs

/v | Controls segment load notification messages. If this option is set, all segment load notifications will be displayed.
386env | Controls the size of addresses, registers, and so on when displayed. When this option is on, addresses, registers, and so on are shown in 32-bit format; otherwise, they are shown in 16-bit format.
codebytes | Causes code bytes to be displayed along with disassembled instructions.
crdelay = | Implements a delay between lines emitted to the debug terminal. Specify the number of ASCII nulls between lines (0-FFFFH).
disaddr | Causes addresses to be displayed with disassembled instructions.
disline | Causes filenames and line numbers to be displayed with disassembled instructions.
dislwr | Causes register and instruction names to be displayed in lowercase letters.
int3line | Causes the filename and line number to be displayed with int 3 instructions.
newprompt | Causes a double prompt when paging is enabled and a nesting level if the debugger is reentered.
newreg | Changes the format of the register display to the newer format accommodating 32 bit registers.
newvec | Controls the display format for the intercepted interrupt vectors.
regterse | Controls the number of registers displayed by the r (Register) command. When regterse is on, only the first three lines are displayed (instead of the normal six lines plus disassembly line).
scrncols | Sets the number of screen columns in the debug display. The default is 79 columns.
scrnlines | Sets the number of screen lines in the debug display. The default is 24 lines.
skipint3s | Causes the debugger to ignore inline int 3 instructions.
symaddrs | Causes symbol values to be displayed with the symbols.
teftibase | Sets the base port address for the timing card. See MSDN Library CD: Q85897, "WDEB386-Compatible Timing Card Available"


z (Zap)

z

Replaces the instruction bytes of the current int 3 instruction or the previous int 1 instruction with nop instructions. This allows the user to avoid int 1 or int 3 instructions that were assembled into the executable file by breaking into the debugger more than once.

You can also z)ap debug_out's; they will be automatically converted to trace_out, so they stop trapping..


zd (Execute Default)

zd

The zd command executes the default command string. The default command string is initially set to the r (Register) command by the debugger. The default command string is executed every time a breakpoint is encountered during execution of the application or whenever a p (Program Trace) or t (Trace) command is executed.

Use the zl command to display the default command string and the zs command to change the default command string.


zl (Display Default)

zl

The zl command displays the default command string.


zs (Set Default)

zs "string"

The zs command makes it possible for you to change the default command string.

string
Specifies the new default command string. The string must be enclosed in single or double quotation marks. You must separate the debugger commands within the string with semicolons.

The following example changes the current default command string to an r (Display Register) command followed by a c (Compare Memory) command:

zs "r;c100 L 100 300"

The following example begins execution whenever an int 3 instruction is executed in your test application. This example executes a g (Go) command every time an int 3 instruction is executed.

zs "j (by cs:ip) == cc 'g'"

You can use zs as follows to set up a watchpoint:

zs "j (wo 40:1234) == 0eeed;t"

This command traces until the word at 40:1234 is not equal to 0EEED. This does not work if you are tracing through the mode switching code in MS-DOS or other sections of code that cannot be traced.


Dot Commands

The following topics describe the Dot commands.


.df (Display Free Memory)

.df

The .df command displays a list of the free global Win16 memory objects in the global heap. The list has the following form:

address: size owner [chain]

address
Specifies physical and heap addresses.
size
Specifies the size of the object, in bytes.
owner
Always specifies that the module is free.
chain
Specifies the previous and next addresses in the list of least recently used (LRU) objects. The debugger displays the addresses only if the segment is movable and discardable.


.dg (Display Global Memory)

.dg [object]

The .dg command displays a list of the global memory objects in the global heap. The command displays information in much the same way as the HEAPWALK application.

object
Specifies the first object to be listed. The object parameter can be a handle, a selector, or a heap address.

The list has the following form:

address: size segment-type owner [handle flags chain]

address | Specifies physical and heap addresses.
size | Specifies the size of the object, in bytes.
segment-type | Specifies the type of object. The type can be any one of the following:

CODE | Segment contains application code.
DATA | Segment contains application data and possible stack and local heap data.
FREE | Segment belongs to pool of free memory objects ready for allocation by an application.
PRIV | Segment contains private data.
SENTINAL | Segment marks the beginning or end of the global heap.

owner | Specifies the module name of the application or library that allocated the memory object. The acronym PDB is used for memory objects that represent process descriptor blocks. These blocks contain execution information about applications.
handle | Specifies the handle of the global memory object. If the debugger displays no handle, the segment is fixed.
flags | Specifies either of the following:

D | The segment is movable and discardable.
L | The segment is locked. If the segment is locked, the lock count appears to the right of the flag.

 | If the debugger displays a handle but no flag, the segment is movable but not discardable.
chain | Specifies the previous and next addresses in the list of least recently used (LRU) objects. Addresses are displayed only if the segment is movable and discardable (specified by the D flag).


.dosmgr (Display Real Mode DOS structures)

Dumps various data structures related to real-mode DOS.

[1] Display SFTs

[2] Display DPBs

[3] Display MCBs (dump the real-mode memory map)

[4] Display CDSs

[5] Display PDBs (dump the real-mode process map)

[6] Display DEVs

[7] Display BDSs

[8] Display INT 21h status


.du (Display Least Recently Used)

.du

The .du command displays a list of the least recently used (LRU) global memory objects in the global heap. The list has the following form:

address: size segment-type owner [handle flags chain]

address
Specifies physical and heap addresses.
size
Specifies the size of the object, in bytes.
segment-type
Specifies the type of object. The type can be any one of the following:
CODE | Segment contains application code.
DATA | Segment contains application data and possible stack and local heap data.
FREE | Segment belongs to pool of free memory objects ready for allocation by an application.
PRIV | Segment contains private data.
SENTINAL | Segment marks the beginning or end of the global heap.

owner
Specifies the module name of the application or library that allocated the memory object. The acronym PDB is used for memory objects that represent process descriptor blocks. These blocks contain execution information about applications.
handle
Specifies the handle of the global memory object.
flags
Specifies D, which means the segment is movable and discardable.
chain
Specifies the previous and next addresses in the LRU list.


.m (Memory)

.m[struct][link] [expression [L count]]

Displays information about memory and memory objects.

struct
Command option. Can be one of these letters.
a | Display arena record.
c | Display context descriptor
d | Display page directory entry
e | Toggle stopping in the debugger for memory manager errors (parameter validation errors as well as fatal errors).
f | With no arguments, dump page fault log. With arguments, set to log faults in a specific range (syntax: .MF <address> L<lengh in bytes>).
fb | Toggle stopping for each logged page fault.
ff | Toggle logging page faults to debug terminal.
g | Display pager descriptor
h [handle] | Displays heap information for the given handle or global information if no handle is given. Displays heap information. This was originally intended for debugging the VMM's memory manager, but may be useful for looking at heap allocations that a device driver makes. This command accepts an optional parameter that specifies the heap allocation handle whose information should be dumped.
hs [handle] | Dump statistics about a given heap.
hw | Toggle paranoid VMM32 heap checking.
hx [handle] | Check for corruption on given heap defaults to VMM32 fixed heap.
i Display Instance Data information. The first section lists which pages of V86 memory contain instance data. The second section lists the regions of instance data. A typical entry looks like:

VMAddr 00000413, Lead Byt 01, Algn Byt 29

This means that the instance region starts at 413h in V86 memory, that 1 byte exists before a DWORD boundary and 29h bytes exist after a DWORD boundary, for a total region length of 2Ah bytes. This command is useful for determining if a device has claimed instance data properly, or to just see what data is currently instanced.
l | Display (physical) page table info for a given linear address
m [address [l page-count]] | Attempts to force memory present. The address defaults to last page faulted upon (contents of cr2 register).
n | Force all unlocked memory not present
p | Display ALL Linear addresses that map the given PhysAddr. This command requires a physical address, so page A0h would be address A0000.
r | Display arena header
s | Dumps global memory manager statistics such as how system memory is being used, what sort of pager is being used etc.
t | Displays page table entry
u | Toggles computing checksums for page-outs and page-ins
v | Displays memory handle information for the memory handles that are allocated to the current VM. Originally used in debugging the VMM's memory manager. Also dumps out the list of routines that have used the global _Assign_Device_v86_Pages service.
w | Dumps allocators of all committed pages.
x | Displays all memory structures for an address.
y | Displays valid physical memory ranges.

If no letter is given, the command displays all the structures associated with a given linear address.

link
Direction to walk structures if dumping more than one. Can be b to walk backward or f to walk forward. If link is not given, the default is to walk adjacent entries.
expression
An expression identifying the structure to display. Can be a linear address, handle, array index, or other value as specified by the struct parameter.
count
Number of structures to display if the specified structures are linked.

The default address for the .m and .mx commands is the contents of the cr2 register (the last page fault) and for the other commands it is the first structure in the list. For example, .m displays information about the page that most recently faulted.

A word of caution about the .mm, .mhx, and .mhs commands. If you invoke these commands at the wrong time, you can crash your system. The only time it can be guaranteed safe is if you are currently executing ring 3 code. At other times we may be in the middle of another file system or memory manager operation.


.ntkern (NTKERN Debug Binary Utility)

OSR 2.1 and Windows® 98 WDM (USB) support. Typing this command supplies you with a menu which includes the ability to dump its debug log ("D"). The debug log displays in LIFO order.


.s (VMM Debug Binary Utility)

.s [#] displays short logged exceptions starting at #, if specified.

Displays a condensed version of logged exceptions (logging is enabled with the ".T" command described previously). The ".S" command displays the log in brief format, most recent log entry first.

The first column is the log entry number.

The second column describes the reason for the log entry. If the log entry describes the beginning of a fault, it contains the fault number. If the log entry describes leaving ring 0 (for example, because fault

handling is complete), it contains the word "OUT".

The third column is the handle of the thread at the time of the fault.

The fourth column is the number of times the critical section was taken at the time the log entry was made.

The fifth column is "EI" if interrupts were enabled at the time the log entry was made; "DI" if interrupts were disabled.

The sixth column describes the processor mode at the time of the fault. It is "VMM" to indicate that the fault was encountered by a ring 0 component. It is "V86" to indicate that the fault was encountered

while in V86-mode. It is "PM" to indicate that the fault was encountered in ring 3 protected mode.

The seventh column is the address that caused the fault.

The remainder of the line contains auxiliary information related to the fault. If the fault was raised by a software interrupt or I/O port access, the faulting instruction is disassembled; in the case of a software interrupt, the value of the EAX register is also displayed following the disassembly. If the fault was caused by a callback or breakpoint, the address of the ring 0 handler for the callback or breakpoint is displayed.

Here follow some sample log entries with interpretation.

0000165A: OUT C1D9F08C 00 EI VMM C0011FDC

This is log entry number 0000165A. The system is leaving ring 0 ("OUT"). The current thread is C1D9F08C, the critical section is not taken ("00"), interrupts are enabled ("EI"), and the system is returning to interrupt code which happens also to be at ring 0 ("VMM"), at address C0011FDC.

00023131: 002A C359F08C 01 EI V86 FF03:5311 INT 2A 00008102

This is log entry number 000023131. The system is entering ring 0 due to software interrupt 002A. The current thread is C359F08C, the critical section is taken once ("01"), interrupts are enabled ("EI"), and the software interrupt was raised by V86-mode ("V86") at address FF03:5311. The faulting instruction was an "INT 2A", and the value of the EAX register was 00008102.

0002312B: 0006 C1D9F08C 00 DI V86 FEB7:1448 Hdl: C0087244:IFSMGR(01) + 86d

This is log entry number 00002312B. The system is entering ring 0 due to an invalid opcode (fault 0006). The current thread is C1D9F08C, the critical section is not taken ("00"), interrupts are disabled ("DI"),

and the software interrupt was raised by V86-mode ("V86") at address FEB7:1448. The faulting instruction was a callback or breakpoint; the handler for the callback of breakpoint is IFSMGR(01) + 86d.

00023118: 0055 C1D9F08C 00 EI VMM C0011FDC

This is log entry number 000023118. The system is entering ring 0 due to an IRQ 5 (50+5). The current thread is C1D9F08C, the critical section is not taken ("00"), interrupts are disabled ("EI"), and the hardware interrupt was raised while the system was in ring 0 ("VMM") at address C0011FDC.

The ".SL" command described in the following displays a complete dump to each logged entry, but takes much more screen space, so this command is used more often to get a quick look at the sequence of faults, and the ".SL" command is used when a more in-depth view is necessary, or when it is necessary to know what other registers were at the time of the fault.

".S" accepts an optional parameter that is the fault entry index. If this parameter exists, then the log is searched for the specified entry. If the entry is found, then the list starts from that entry and proceeded backwards to the oldest entry; if the entry is not found then a warning message is displayed and the list starts from the most resent.

The macro Queue_Out queues messages to a separate circular queue. Each message is linked to the current fault entry index, so the ".S" can show the queued messages interspersed with the fault information. This allows fault handlers to show information about how they handled the fault so that the list displayed by the ".S" command is a fairly complete execution history, which is particularly useful when debugging devices that are trying to virtualize I/O so that they simulate actual hardware, such as the PIC, DMA and video.

".S" always disables logging before it displays anything, so no more logging will be performed until ".T" is invoked again.


.sl (VMM Debug Binary Utility)

.sl [#] displays long logged exceptions just #, if specified. ".SL" like ".S" displays information about logged exceptions, enabled with the ".T" command. ".SL" displays all of the registers at the time the entry was logged and also shows the system time (the time VMM started) of the entry. ".S" shows a condensed view and is used more often because more faults can be viewed at the same time and because most of the registers are of little importance to the fault.

".SL" also disables logging before it displays anything, so no more logging will be performed until ".T" is invoked again


. v (Virtual Machine Commands)

.v[option]

Displays information about the current virtual machine (VM).

option
Command option. Can be one of these option letters:
c | Displays the standard fields from the current VM's control block (does not include device allocated fields.) This information is useful to determine the current state of the VM as the Windows/386 VMM sees it. It accepts the same optional parameter as ".VM".
h | Displays the current VM's handle. Useful for determining which VM is currently executing. It is also possible to look at device allocated fields of the VM's control block, if the offset to the first field is known, by adding the offset to the handle when dumping memory.
m | Displays the status of the current VM. Status information includes re-entry count, VM handle, critical section state, client registers, and top entries from the client's stack. This command is useful to see where the VM was/is trying to execute. It is then possible to set a break point at the client's CS:IP if it is necessary to step through a few instructions to determine what the client is trying to do. This command accepts an optional parameter that can be the VM handle or VM id of the VM whose status should be displayed.
r | If Ring 0 code was executing at the time that the debugger took control, then is command displays the client registers of the current VM. If the client was executing, then the debugger is showing the current registers, and this command will just display a warning message. This command shows just the register display portion of the ".VM" command. It accepts the same optional parameter as ".VM".
s | Displays the current VM's virtual mode stack if the debugger is running in protected mode.
l | Displays a list of all valid VM handles. The list shows the assigned scheduler priority and the execution status of each VM.


.vdd (VDD Debug Binary Utility)

VDD Virtual Display Device State Dump. Also offers additional options:

Select Option

1 - display VM register states

2 - display VM memory usage

3 - dump video page info

4 - display msg mode register state

5 - display planar mode register state

6 - read DAC

7 - display VM DAC states

8 - enable Queue_Outs

9 - enable MemC debug event


.vkd (VKD Debug Binary Utility)

Virtual Keyboard Device

[0] - General info

[1] - Hot Key info

[2] - Per VM info

[3] - Set VKD queue_outs

[ESC] - Exit VKD debug query


.vmm (Display VMM Commands)

.vmm

Displays a menu of subcommands. Pressing a single key causes the corresponding command to be carried out.

Service | Comments
[A] System time | Displays the current system time.
[B] Display Critical Section info |
[C] Display blocked thread information |
[D] Reset dyna-link profile counts |
[E] I/O port trap information | Displays information about I/O emulation handling. The first section displays general information about the hash table used to dispatch trapped I/O instructions. The second section lists each I/O port trapped, number of times trapped, percentage of total number if I/O traps, current trapping state, hash function result, table index, offset from ideal table index, and handler routine name. This information is useful for determining which ports are trapped frequently and thus need to be tuned for speed.
[F] Reset I/O profile counts | Reset the trap counts on all I/O ports. Useful for isolating the profile information to a particular section of execution, such as reading from a floppy drive, etc.
[G] Turn procedure call trace logging on/off | Toggles the state of call tracing. When on, each debugging code created by the BeginProc macro performs a Queue_Out of the routine name each time it is entered. Thus when ".S" is invoked to dump a fault log, the log will be interspersed with messages stating each routine name as it is called and who called it, so it is possible to get a complete execution log.
[H] V86 interrupt hook information | Displays the V86 interrupt table; showing the current vector assignment and which VMM/device driver routines have hooked the interrupt, if any. This command gives a look at which interrupts are looked at by the different device drivers, etc.
[I] PM interrupt hook information | This command is similar to G, but show the logical PM interrupt table. It shows current vector assignments and routine names that are hooked into the interrupt chains.
[J] Reset PM and V86 interrupt profile counts |
[K] Display event lists | This command displays the list of current global events, and then of list of local events for each VM.
[L] Display device list | This command displays the list of loaded devices along with the information from each Device Descriptor Block. Type .VMM L={DDB}, where DDB is the name of the VxD, to list an explicit module.
[M] Display V86 break points | This command displays a list of all V86 break points that are currently allocated. This list shows that CS:IP of the break point, the Ring 0 callback address/label and the reference data.
[N] Display PM break points | This command displays a list of all PM break points that are currently allocated. This list shows that CS:IP of the break point, the Ring 0 callback address/label and the reference data.
[O] Display interrupt profile | Profiles the activity (counts) of V86 Ints, PM Ints and VMM Ints
[P] Reset interrupt profile counts |
[Q] Display GP fault profile | Profiles General Protection Fault activity
[R] Reset GP fault profile counts |
[S] Toggle verbose device call trace | Turn on verbose device tracing to displays the name of each VxD before it is called, and OK when the VxD returns.
[T] Dyna-link service profile information | Displays a list of all services (in VMM and all devices) that shows the number of times the service has been called, the service number, routine address, and routine name. This information is a pseudo profile of which services are used frequently and thus should be tuned for speed.
[U] Fault Hook information | Displays all V86 fault hooks, PM fault hooks and VMM fault hooks.
[V] Display time out queues | Displays all the time out queues including the Async time out queue and Global time out queue.
[W] PM CLI/STI trace info |
[X] DPMI info |


Other Tools

The Device Driver Kit includes several tools:

  • ADRC2VXD Adds a resource to a VxD file.
  • DEVLIB Manages W4 compressed VxD libraries.
  • EXE2BIN Converts a small-model .EXE file to a .COM file.
  • HDR Displays information about executable files.
  • INFEDIT Edits .INF files.
  • SYMLIB Manages symbol files (.SYM files).


ADRC2VXD

The ADRC2VXD command allows you to append a resource onto a VxD file. You can use this command to add version information to your VxDs.

Syntax

adrc2vxd vxdname resfilename

Parameters

vxdname | Specifies the VxD filename
resfilename | Specifies the resource file name.

Examples

The following example appends the resource version.res onto the VxD vtestd.vxd

adrc2vxd vtestd.vxd version.res

Creating a version resource

You can use the following template to create a version resource for your VxD file

/********************************************************************/
/*        Version control data                                      */
/********************************************************************/
#include <version.h>

#define VER_FILETYPE                    VFT_VXD
#define VER_FILESUBTYPE                 DEVICE_ID
#define VER_COMPANYNAME_STR             "Company Name, Inc.\0"
#define VER_FILEDESCRIPTION_STR         "Sample VxD\0"
#define VER_INTERNALNAME_STR            "Sample\0"
#define VER_LEGALCOPYRIGHT_YEARS        "1993-1995\0"
#define VER_ORIGINALFILENAME_STR        "SAMPLE.VXD\0"

#include <common.ver>

In the example, DEVICE_ID is the VxD's Device ID or UNDEFINED_DEVICE_ID (defined in inc32\vmm.h) for dynaload VxDs. Use the resource compiler (rc.exe) to compile the preceding (the include files version.h and common.ver are in the inc16 include file subdirectory) and adrc2vxd to add it to your VxD.


DEVLIB

The command DEVLIB manages the new, compressed W4 format VxD libraries (like VMM32.VXD).

Syntax

devlib [-c | -d | -p | -a] libname [ filename ]

Parameters

-c | Creates a VxD library.
-d | Dumps (prints a table of contents) for the VxD library specified by libname. The library must be unpacked first. You can use the optional filename argument to extract a VxD in the library.
-p | Pack (compresses) a VxD library.
-u | Unpacks (uncompresses) a VxD library.
-a | Appends the VxD filename to the library. The -a is optional.
libname | Specifies the library name.
filename | Specifies the VxD filename.


EXE2BIN

Strips the .EXE header from an executable file. You can use EXE2BIN to create .COM files.

Syntax

exe2bin filename

Parameters

filename Specify the name of the file to strip.

Restrictions

  • The executable file must not contain a stack segment.
  • The combined size of code and data must not exceed 64K


HDR

Prints header information from executable files.

Syntax

hdr [ options ] filename

Parameters

-d | Prints data relocation records.
-f | Prepends the file name on every output line.
-h | Prints the file header (default).
-m | Print only memory segment table information.
-j[options] | Prints specified tables.

d | Prints debug table.
e | Prints entry table.
f | Prints extended attributes.
i | Prints import module table.
I | Prints import procedure table.
r | Prints resident name table.
R | Prints resource table.

-p | Prints file seek positions.
-R | Same as -r, but also follows relocation chains.
-r | Prints both text and data relocations.
-S | Prints the file segment table with a header.
-s | Prints the symbol table.
-T | Prints the file type.
-t | Prints the text relocation records.
-y | Dumps DOS .SYM file.
-v | Prints everything (verbose).
-? | Prints usage summary.
filename | Specifies the filename


INFEDIT

The INFEDIT command is covered in the Device Installation section. See the documentation DEVINST.DOC for more information.


SYMLIB

You can use SYMLIB to manage symbol libraries (.SYM files). With SYMLIB you can create new symbol files, add symbols, remove symbols, and update symbols.

Syntax

symlib symlib1{+symlib2|-{symlib2|symbol}| symlib2|-+symlib2}

Parameters

symlib1 | Specifies the symbol library (.SYM file) to be created or modified.
symlib2 | Specifies the symbol library (.SYM file) to be added to or updated in symlib1
symbol | Specifies the symbol to be removed from symlib1

Note There should be no space between the '+' or '-' and the following argument.

Examples

The following example adds vmm.sym to win386.sym.

symlib win386.sym vmm.sym

or

symlib win386.sym+vmm.sym

The following example updates the symbols in win386.sym with those in vmm.sym.

symlib win386.sym-+vmm.sym

The following example deletes the symbol vmm from win386.sym.

symlib win386.sym-vmm.sym


Introduction to Virtual Device Drivers

It is important to understand the architecture of the Microsoft Windows® 95 operating system as a whole, in order to understand the role of Windows 95 device drivers.

The Microsoft® Windows® 95 operating system supports multithreaded multitasking for applications. Windows provides a virtual machine manager (VMM) which, in conjunction with virtual devices, processes interrupts and carries out I/O operations for a given application without disrupting the execution of other applications. This section describes the Virtual Machine Manager (VMM), virtual devices, and other components of the operating environment for Windows.


Operating Environment

The operating environment for Windows® 95 consists of a computer's hardware devices and the following software components:

  • Virtual machine manager (VMM32.VXD)
  • Virtual devices (.VXD files)
  • 16- and 32-bit protected-mode installable device drivers for peripheral devices
  • 16- and 32-bit Windows dynamic-link libraries, such as USER.EXE and USER32.DLL
  • Windows-based and other applications

The virtual machine manager forms the core of this operating environment. It provides the service functions (also called services) needed to create and manage the virtual machines in which applications run. The virtual devices support the device-independent VMM by managing the computer's hardware devices and supporting software. Virtual devices manage software as well as the hardware devices to ensure that no application disrupts the operation of another. The Windows dynamic-link libraries provide the functions and graphical resources that all Windows applications use.


Virtual Machines

A virtual machine is an executable task consisting of an application, supporting software (such as ROM BIOS and MS-DOS), memory, and CPU registers. The VMM can create multiple virtual machines. The first virtual machine created, called the system virtual machine, contains 16-bit Windows-based applications, Win32® applications and threads created by Win32 applications. Other virtual machines are created for MS-DOS-based applications as they are started.

MS-DOS-based applications in a virtual machine run in virtual 8086 mode (also called V86 mode). In V86 mode, applications run as if they were running on an Intel 8086, or compatible microprocessor. V86 mode provides the registers, instructions, and 1-megabyte address space that real-mode applications are designed to use. This means an MS-DOS-based application in a virtual machine will run successfully without modification. V86 mode also permits execution of protected-mode applications in a virtual machine.

Each virtual machine has its own address space, I/O port space, and interrupt-vector table. The VMM also maps ROM BIOS, MS-DOS, device drivers, and TSRs to the address space of the virtual machine so that the application has access to MS-DOS system functions and ROM BIOS routines. Virtual machines with protected-mode applications also have their own local descriptor table (LDT).

Virtual machines provide memory protection, virtual memory, and privilege checking. If an application in a virtual machine reads or writes memory addresses that have not been mapped into its virtual machine or manipulates I/O ports to which it has not been allowed access, an exception (fault) is generated, and the VMM regains control. The VMM and virtual devices can then provide the requested memory, carry out the intended I/O operation, or terminate the application. In a virtual machine, V86-mode applications run at privilege level 3; protected-mode applications run at privilege level 1, 2, or 3.


Virtual Machine Manager

The VMM is a 32-bit protected-mode operating system. Its primary responsibility is to create, run, monitor, and terminate virtual machines. The VMM provides services that manage memory, tasks, interrupts, and protection faults. The VMM works with virtual devices, 32-bit protected-mode dynamic-link libraries, to allow the virtual devices to intercept interrupts and faults in order to control the access an application has to hardware devices and installed software.

Both the VMM and the virtual devices run in a single, 32-bit, flat model address space at privilege level zero (also called ring 0). The system creates two global descriptor table (GDT) selectors, one for code and the other for data, and uses these selectors in the CS, DS, SS, and ES segment registers. Both selectors have a base address of zero and a limit of four gigabytes, so all the segment registers point to the same address space. The VMM and virtual devices never change these registers.

The VMM provides single-threaded, preemptive multitasking. It runs multiple applications simultaneously by sharing CPU time between the virtual machines in which the applications run. The VMM is also nonreentrant. This means virtual devices must synchronize access to the VMM services. The VMM provides services, such as semaphores and events, to help virtual devices prevent re-entering the VMM.

The VMM creates and initializes the system virtual machine when it first starts. Initially, the WIN.COM program loads VMM32.VXD which contains the VMM and the default virtual devices. The VMM, loaded into extended memory allocated using an XMS driver, initializes itself and the virtual devices, and switches to protected-mode execution. When initializing, virtual devices typically install callback procedures for interrupts and faults, and allocate memory for resources associated with the system virtual machine. The virtual shell device (SHELL), typically the last virtual device to be initialized, starts Windows in the system virtual machine by loading the Windows kernel, KRNL386.EXE. The kernel loads all other required pieces of Windows which culminates in the starting of Windows 95 Shell.


Virtual Machine Handle, Control Block, and Client Registers

Every virtual machine has a virtual machine handle and control block. The handle, created by the VMM when it creates the virtual machine, uniquely identifies the virtual machine. The VMM and virtual devices use the handle when calling services to specify for which virtual machine to carry out the action.

The handle is actually the 32-bit linear address of the virtual machine's control block. The control block is a structure that contains data used by the VMM and virtual devices to manage the virtual machine. The control block specifies the virtual machine status, such as whether the virtual machine is being created or destroyed, is running or suspended, and is in V86 mode or protected mode. The control block also specifies the virtual machine's handle, identifier, high linear address, and address of the virtual machine client registers. Virtual devices add device-specific data to the control block by allocating space in the control block with the _Allocate_Device_CB_Area service. A virtual device typically keeps information about the state of the physical hardware in this block.

Every virtual machine has its own set of client registers. These registers specify the current state of the processor registers for the application running in the virtual machine. Saved on the ring 0 stack when the VMM receives control from an application, the client registers can be examined and modified by virtual devices. The address of the client registers is specified in the CB_Client_Ptr field of the control block. This address is also frequently passed to virtual device procedures in the EBP register. A virtual device uses this address and the fields of the Client_Reg_Struc structure to access the individual registers.

The high linear address of a virtual machine, specified by the CB_High_Linear field in the control block, is an alternate address for the physical memory containing the application and supporting software in the virtual machine. A virtual machine's physical memory is mapped to the low 1 megabyte of the linear address space only when the virtual machine is running. The VMM and virtual devices use the high linear address to examine and modify the physical memory when the virtual machine is not running.


Virtual Devices Overview

Virtual devices support all hardware devices for a typical computer, including the programmable interrupt controller (PIC), timer, direct-memory-access (DMA) device, disk controller, serial ports, parallel ports, keyboard device, and display adapter. A virtual device is required for any hardware device that has operating modes that can be set or retains data over any period of time. In other words, if the state of the hardware device can be disrupted by switching between multiple applications, the device must have a corresponding virtual device.

Many hardware devices use interrupts to signal when data is ready or the device is available. Virtual devices rarely intercept these hardware interrupts directly. Instead, a virtual device relies on the virtual programmable interrupt controller device (VPICD) to process hardware interrupts. The virtual device installs a callback procedure which the VPICD calls when a hardware interrupt occurs. The callback procedure typically services the interrupting device, or requests the VPICD to reflect the interrupt into the ROM BIOS or other code that services the device. A virtual device can also register callback procedures to handle other phases of interrupt processing such as the execution of the iret instruction. Virtual devices must not modify descriptors in the interrupt descriptor table (IDT).

Most hardware devices provide memory-mapped or I/O-port registers through which applications can set the operating mode of the device and read or write data. Virtual devices typically trap access to these registers to record changes to the state of the device and to simulate the reading or writing of data. If a hardware device uses memory buffers, such as video memory for a display adapter, the virtual device usually takes ownership of the physical memory to prevent the system from attempting to use it. The virtual device also maps the memory to prevent applications that run in the background from overwriting the current contents.

Many hardware devices have corresponding ROM BIOS or installable device driver routines (collectively called the API) that set and record the state of the device. In most cases, applications call these routines by using a software interrupt. Virtual devices usually install callback procedures to intercept these software interrupts. This allows the virtual device to either simulate the requested action, or prepare the parameters in the call for execution in V86 mode. Preparing parameters (called API translation or mapping) is required when a protected-mode application passes an address to a ROM BIOS or device driver routine that runs in V86 mode.

Some virtual devices support software, but no corresponding hardware device. For example, the virtual shell device provides access to the Windows MessageBox function. In general, a virtual device can provide any kind of services for the VMM and other virtual devices. It can also provide API functions for V86 and protected-mode applications. These API functions potentially give 16-bit applications direct access to the features of the virtual device.


Interrupt and Fault Handling

The VMM manages all interrupt and protection fault processing for the virtual devices. A VMM fault handler receives control whenever an interrupt or protection fault occurs, such as when an application executes a software interrupt, attempts to access a protected I/O port, or attempts to access a protected or unavailable segment or page of memory. The VMM fault handler calls the callback procedures installed by the virtual devices, allowing the callbacks the opportunity to process the interrupt or fault.

A VMM fault handler usually processes an interrupt and protection fault as follows:

  1. The application in the virtual machine executes a software interrupt, or performs an operation that generates a fault.
  2. The CPU transitions to ring 0 and calls the corresponding VMM fault handler as specified by the IDT. Virtual devices must never replace the VMM fault handler descriptors in the IDT.
  3. The VMM fault handler dispatches the interrupt to any installed callback procedure(s) using a call instruction.
  4. A callback procedure can either process or ignore the interrupt or fault, but must always return to the VMM fault handler by using the ret instruction. In most cases, a virtual device uses the Schedule_Global_Event or Schedule_VM_Event service to schedule an event, and specify the event callback procedure that processes the current fault.
  5. When control returns to the VMM fault handler, it checks for scheduled global or virtual machine events. If any events are outstanding, the VMM calls the corresponding event callback procedures.
  6. If no callback procedure has processed the interrupt or fault, the VMM fault handler reflects the interrupt or fault back into the virtual machine allowing the V86-mode interrupt handler to process it.
  7. The VMM executes an iret instruction to transition back to the virtual machine's privilege level, and return execution control to the application in the virtual machine.


Multitasking

The VMM uses a time-slice scheduler and execution priority to carry out preemptive multitasking for virtual machines. The VMM grants time slices to the virtual machines that have the highest execution priority. Virtual machines with execution priorities lower than the highest priority do not receive time slices. The VMM assigns an execution priority to a virtual machine when it creates the virtual machine. The VMM and virtual devices can subsequently raise or lower the execution priority to cause task switching between virtual machines. The VMM often raises the execution priority for a virtual machine that needs to service a high-priority device event, such as an interrupt that must be serviced in a timely manner.

The VMM relies on time-slice priorities and flags to determine how much CPU time it grants to the virtual machines. Every virtual machine has a foreground and a background time-slice priority in addition to the virtual machine's execution priority. The virtual machine with the largest time-slice priority receives a greatest share of CPU time. The VMM uses the foreground priority to determine the amount of CPU time to grant a virtual machine if the virtual machine has the execution focus (is the foreground virtual machine). Otherwise, the VMM uses the background priority. If a virtual machine is not the foreground virtual machine, it receives no time slices unless the CB_VM_Status field in its control block specifies the VMStat_Background or VMStat_High_Pri_Back values. If a virtual machine has the VMStat_Exclusive value, no other virtual machine receives time slices while the exclusive virtual machine has the execution focus.


Virtual Devices

This section introduces the purpose of virtual devices. You create a virtual device for your hardware device or your 16-bit or 32-bit software if the standard virtual devices provide by Microsoft® Windows® 95 does not provide 100 percent, compatible support for your device or software. You also create a Windows virtual device if you want to offer Windows users access to unique features of your device or software.

This section explains how to write and build virtual devices. It describes the structures, procedures, and services you write to create a virtual device, and defines the steps you take to build and test the virtual device. Virtual devices can be either static or dynamically loadable. The following sections specifically describe static virtual devices, but information about the format and function apply generally to both.


What Is a Virtual Device

A virtual device is a 32-bit executable that manages a system resource, such as a hardware device or installed software, so that more than one application can use the resource at the same time. Windows uses virtual devices to allow multitasking for Windows-based applications. The virtual devices work in conjunction with Windows to process interrupts, and carry out I/O operations for a given application without disrupting the execution of other applications.

Most virtual devices manage a hardware device, and many also manage or replace corresponding software such as ROM BIOS routines. A virtual device can contain the device-specific code needed to carry out actions on the device, or it can rely on the other software to carry out these operations. In all cases, the virtual device keeps track of the state of the device for each application, and ensures that the device is in the correct state whenever an application continues execution.

Some virtual devices manage only installed software, such as an MS-DOS device driver or a TSR program. Such virtual devices often contain code that either emulates the software or ensures that the software uses data that applies only to the currently running application. Virtual devices are sometimes used to improve the performance of installed software; the Intel-compatible microprocessors can execute the 32-bit code of a virtual device more efficiently than the 16-bit code of an MS-DOS device driver or TSR.


Standard Virtual Devices

Windows includes a wide variety of virtual devices to support common hardware devices and installable software. In some cases, a virtual device may need to be modified to accommodate new features or to support nonstandard hardware.

Windows provides many other virtual devices that are not intended to be modified, but help support other virtual devices. For example, many virtual devices use the services provided by the V86 memory manager (V86MMGR) and the virtual programmable interrupt controller device (VPICD) to reserve V86 mode memory and enable interrupt requests (IRQs) for their hardware.

To help with you develop virtual devices, the Microsoft Windows 95 Device Driver Development Kit includes source code for fully operational virtual devices.


Creating Virtual Devices

You create a virtual device either by modifying a sample device or by writing a device from scratch. You can write virtual devices in assembly language, and you may be able to write some portions of your virtual device in a high-level language such as the C language.

To create a virtual device, you need to:

  1. Read the section in this documentation that describes the virtual device for your type of hardware device.
  2. Write the required control procedures, virtual device services, and API functions.
  3. Create a module-definition file that identifies the appropriate module name for your virtual device, and exports the required device description block.
  4. Assemble and link your device.
  5. Test your virtual device using the debugging version of Windows 95. For information about debugging virtual devices, see .
  6. Create an installation file (*.INF) for your virtual device and related files. You install a virtual device by specifying settings for the registry and copying files to the Windows SYSTEM or related directories.
  7. Create your final distribution disk or disks.


What You Need to Get Started

This documentation assumes that you are an experienced assembly-language programmer, and that you are familiar with the instruction sets and system architecture of Intel and Intel-compatible microprocessors. In particular, you should understand:

  • Protected and virtual 8086 mode operation
  • Flat memory model
  • Interrupt and exception processing
  • Protection and privilege levels
  • Segment and page memory management and fault handling
  • Input and output protection and fault handling

This documentation also assumes that you are well acquainted with the features of your hardware device and any corresponding ROM BIOS routines or other installable software.


Writing a Virtual Device

Many virtual devices are written to replace one of the standard virtual devices, that is, one of the virtual devices provided with the Microsoft Windows 95 operating system. However, most virtual devices are written to support new hardware devices or software. In such cases, it is often easier to write a virtual device from scratch than to modify an existing virtual device, because so much of a virtual device is device-specific. Nevertheless, the sources for existing virtual devices should be carefully examined whenever possible because they can reveal the general format and structure of virtual devices, as well as illustrate how to use VMM and virtual device services to carry out useful tasks.

Use the following guidelines when writing a virtual device:

  1. Start with a skeletal virtual device containing the virtual device segments, a virtual device declaration, a device control procedure, stubs for the procedures that process the system control messages, and stubs for the API procedures.
  2. Add a real-mode initialization procedure (optional).
  3. Fill out the procedures that process the initialization messages. These procedures should initialize the control block, allocate global memory, and install callback procedures for interrupts, I/O traps, and page faults.
  4. Fill out the callback procedures that handle the various interrupts and faults.
  5. Add a service table declaration and definitions for the services (optional).
  6. Fill out the API procedures (optional).
  7. Fill out the procedures that process system control messages for creating and destroying virtual machines.

At each stage in writing a virtual device, you can install the virtual device and run Windows under the control of the debugger. Setting breakpoints in your virtual device and monitoring the various interrupts managed by your virtual device can help you determine whether your virtual device is operating correctly.


Virtual Device Segments

Virtual devices can have any combination of the following five segments.

Segment | Description
VxD_CODE | Specifies the protected-mode code segment. This required segment contains the device control procedure, callback procedures, services, and API procedures of the virtual device. Use the VxD_CODE_SEG and VxD_CODE_ENDS macros to define the start and end of definitions for this segment. This segment is also named _LTEXT.
VxD_DATA | Specifies the protected-mode data segment. This required segment contains the device descriptor block, service table, and any global data for the virtual device. Use the VxD_DATA_SEG and VxD_DATA_ENDS macros to define the start and end of definitions for this segment. This segment is also named _LDATA.
VxD_ICODE | Specifies the protected-mode initialization code segment. This optional segment usually contains the procedures and services that are used only during initialization of the virtual device. The VMM discards this segment after the Init_Complete message. Use the VxD_ICODE_SEG and VxD_ICODE_ENDS macros to define the start and end of definitions for this segment. This segment is also named _ITEXT.
VxD_IDATA | Specifies the protected-mode initialization data segment. This optional segment usually contains the data used by the initialization procedures and services. The VMM discards this segment after the Init_Complete message. Use the VxD_IDATA_SEG and VxD_IDATA_ENDS macros to define the start and end of definitions for this segment. This segment is also named _IDATA.
VxD_REAL_INIT | Specifies the real-mode initialization segment. This optional segment contains the real-mode initialization procedure and data. The VMM calls this procedure before loading the rest of the virtual device, then discards this segment after the procedure returns. Use the VxD_REAL_INIT_SEG and VxD_REAL_INIT_ENDS macros to define the start and end of definitions for the real-mode initialization segment. This segment is also named _RTEXT.

All code and data segments, except the real-mode initialization segment, are 32-bit, flat model, protected-mode segments. This means procedures and data defined in the protected-mode segments have 32-bit offsets. When the VMM loads the virtual device, it fixes all offsets according to the virtual device's actual position in memory. For this reason, the OFFSET32 macro should be used in the protected-mode segments wherever the OFFSET directive would ordinarily be used. The OFFSET32 macro defines offsets for which the linker produces correct offset fix-up information.

Virtual devices cannot change the CS, DS, ES, or SS segment registers. Virtual devices can use the FS and GS segment registers.


Protected-Mode Instructions

The source files for a virtual device must start with the .386p directive to inform the assembler that protected-mode instructions are permitted. Although virtual devices have ring 0 privilege, they should not use protected instructions to modify the operation of the CPU, to change descriptors in the global or interrupt descriptor table, or to modify task state segments or registers. Such modifications can adversely affect the operation of Windows. The only exception to this is the virtual math coprocessor device (VMCPD), which is allowed to change the 80387 bits in the CR0 register.


Include Files

The include files define macros, structures, symbols, and service tables needed by the virtual device to declare segments and procedures, and use VMM and other virtual device services. The following is a list of include files containing definitions for commonly used service, macro, and symbol definitions.

Filename | Description
VMM.INC | Contains definitions for all VMM services, as well as required macros and symbols such as Declare_Virtual_Device and VMMCall.
DEBUG.INC | Contains useful macros for writing messages at a debugging terminal and performing checks on various data. The macros provided by this file produce code only when the virtual device is assembled with the DEBUG symbol defined.
VPICD.INC | Contains definitions of all services, macros, and symbols for the virtual programmable interrupt controller device (VPICD). The VPICD handles all interrupts; therefore, most virtual devices require VPICD services.
SHELL.INC | Contains definitions of the public services provided by the virtual shell device. The shell device provides access to the Windows functions such as MessageBox. This lets virtual devices display dialog boxes to the user.


Virtual Device Declaration

Every virtual device must declare a name, a version number, an initialization order, and a device control procedure. Many virtual devices also declare a device identifier and API procedures. Virtual devices typically use the Declare_Virtual_Device macro to make these declarations as in the following example:

Declare_Virtual_Device VSAMPLED, 4,0, VSAMPLED_Control, \
    VSAMPLED_Device_ID, VSAMPLED_Init_Order, \
    VSAMPLED_V86_API_Handler, \
    VSAMPLED_PM_API_Handler

This example declares the sample virtual device, VSAMPLED, version 4.0. The device control procedure, which must be defined in the same source file, is named VSAMPLED_Control. The symbols VSAMPLED_Device_ID and VSAMPLED_Init_Order specify the nonstandard virtual device identifier and initialization order. This virtual device supports both V86-mode and protected-mode API procedures.

The VMM uses the information declared by this macro to initialize the virtual device, send system control messages to it, and allow MS-DOS applications, device drivers, and TSRs to call it. To grant access of this information to the VMM, the macro creates a device descriptor block (DDB) and stores it in the protected-mode data segment. (The DDB has the same format as a VxD_Desc_Block structure.) The macro creates a label for the DDB, which must be explicitly exported when the virtual device is linked. In the previous example, the name for the DBB is VSAMPLED_DBB.


Virtual Device Identifier

A virtual device provides a virtual device identifier to help distinguish it from all other virtual devices. The VMM dynamic-linking routine uses virtual device identifiers to help it link service calls to the appropriate virtual device. A virtual device needs a unique identifier if it provides services, provides a V86-mode or protected-mode API procedure, or in some other way needs to be uniquely identified.

Although standard virtual devices use the predefined virtual device identifiers (symbols defined in VMM.INC), virtual devices that support new devices or software interfaces must have entirely new identifiers. To help prevent conflicts with other new virtual devices, Microsoft assigns new identifiers on request, registering the identifiers to ensure that no other manufacturer uses the identifier for its own virtual devices. Microsoft reserves all virtual device identifiers from zero through 01FFh for its own use.

Virtual devices that do not provide services or API procedures, or that do not require a unique identifier should use the Undefined_Device_ID symbol to define the virtual device identifier.


Initialization Order

Each virtual device has an initialization order value that specifies when the VMM should initialize the virtual device. The VMM initializes the virtual machine with the lowest value first and highest value last. If two or more devices have the same value, the VMM may initialize them in the order they appear in the SYSTEM.INI file; however, a specific order is not guaranteed.

The initialization order is important for virtual devices that need to call services in other virtual devices, or that need to intercept specified interrupts before other virtual devices. If a virtual device needs to be initialized before or after a standard virtual device, its initialization order value is created by adding or subtracting a small value from the standard virtual device's predefined initialization order symbol (defined in the VMM.INC or VMM.H file).

If a virtual device does not require a specific initialization order, it should use the Undefined_Init_Order symbol for its initialization order value.


Device Control Procedure

Every virtual device needs a device control procedure. The VMM calls this procedure to send the virtual device system control messages. The system control messages direct the virtual device to carry out actions, such as initializing itself, and to notify the virtual device of changes to virtual machines, such as a virtual machine is being created. Most virtual devices define the device control procedure by using the Begin_Control_Dispatch, Control_Dispatch, and End_Control_Dispatch macros as in the following example:

Begin_Control_Dispatch VSAMPLED
    Control_Dispatch   Sys_Critical_Init,  VSAMPLED_Crit_Init
    Control_Dispatch   Device_Init, VSAMPLED_Device_Init
    Control_Dispatch   Sys_Critical_Exit, VSAMPLED_Crit_Exit
End_Control_Dispatch VSAMPLED

In this example, the macros create a device control procedure, named VSAMPLED_Control, and generate instructions that check for the messages Sys_Critical_Init, Device_Init, and Sys_Critical_Exit. When these messages are sent to the procedure, the procedure passes control to a corresponding procedure, such as VSAMPLE_Device_Init, to process the messages. These message-processing procedures must be defined by the virtual device.


System Control Messages

The VMM sends system control messages to a virtual device to notify it of changes that affect the system and virtual machines. Most virtual devices need to track the creation and status of virtual machines, so the VMM sends messages to the virtual device whenever a virtual machine is created, initialized, or terminated. It also sends a message when the execution focus moves to or from the virtual machine, or when the virtual shell device needs to display a message box to the user.

The following is a list of the most common messages and recommendations for how the virtual devices should process the messages.

Message | Recommended Action
Begin_Message_Mode | A virtual device receives this message when the virtual shell device needs to display a message box to the user but cannot use the system virtual machine and Windows functions to do so. The virtual keyboard, mouse, and display devices save their current state, enable any message mode services, and initialize the corresponding device for message mode processing.
Create_VM | This is the first message the virtual device receives when a new virtual machine is created. The virtual devices should initialize data associated with the virtual machine, especially the control block.
Debug_Query | A virtual device receives this message from the debugger, WDEB386. The virtual device can display a list of debugging, and read user commands from the debugging terminal.
Destroy_VM | This is the third termination message a virtual device receives for a virtual machine. The Simulate_Int and Exec_Int services are not available for the given virtual machine.
Device_Init | This is the second message a virtual device receives. Interrupts are enabled. Most virtual devices allocate and copy the initial state to a device-specific section in the system virtual machine's control block, install callback procedures for interrupts and I/O protection faults, and specify instance data. At this point, the Simulate_Int and Exec_Int services are available.
End_Message_Mode | A virtual device receives this message when the virtual shell device no longer needs to display a message box. The virtual keyboard, mouse, and display devices restore the previously saved state of the given virtual machine, and disable any message mode services.
Init_Complete | This is the third message a virtual device receives and is the last message associated with system initialization. Although most virtual devices do not process this message, virtual devices that use V86 memory should locate and claim this memory before returning. After a virtual device returns this message, the VMM discards the initialization code and data segments of the virtual device.
Query_Destroy | A virtual device receives this message when the virtual shell device needs to determine whether a virtual machine can be destroyed. The virtual device can set the carry flag, and return to prevent the virtual machine from being destroyed. In such cases, the virtual device should notify the user of the problem by using the SHELL_Message service.
Reboot_Processor | A virtual device receives this message when the user attempts to restart the computer. A virtual device, such as the keyboard device, that can restart the computer should do so.
Set_Device_Focus | A virtual device receives this message when the execution focus moves from one virtual machine to another. The virtual device restores the hardware device to the state associated with the virtual machine. If the virtual device used I/O trapping to manage the virtual machine when it did not have the execution focus, the virtual device should remove as much I/O trapping as possible, and let the virtual machine run as fast as possible.
Sys_Critical_Exit | This is the last message sent to a virtual device. Interrupts are disabled and the Simulate_Int and Exec_Int services are not available. Virtual devices should reset their associated hardware device to ensure a trouble-free return to real mode.
Sys_Critical_Init This is the first message a virtual device receives. Interrupts are not yet enabled, so the virtual device should carry out its tasks as quickly as possible. Most virtual devices do the following:

• Install and initialize any functions needed to support hardware interrupts from the device and software interrupts from the VMM or other virtual devices.

• Claim for exclusive use any V86-mode memory pages needed for the device. For example, the virtual display device claims the video memory.

• Initialize any data needed by the virtual device's services. This may include reading settings from the SYSTEM.INI file.

While processing this message, the Simulate_Int and Exec_Int services must not be used.

Sys_VM_Init | A virtual device receives this message after the Init_Complete message. The virtual device should initialize the state of the hardware and software in the system virtual machine. If the virtual device sets the carry flag and returns, the VMM terminates all further processing and exits Windows.
Sys_VM_Terminate | This is the first termination message a virtual device receives for the system virtual machine. The virtual device can begin preparing for termination of the virtual machine. The Simulate_Int and Exec_Int services are available. The system virtual machine is always the last virtual machine to be terminated.
System_Exit | This is the first message a virtual device receives when the system is terminating. The VMM sends it after sending the Sys_VM_Terminate message. Interrupts are enabled, but the Simulate_Int and Exec_Int services are not available. If this message was sent as a result of a fatal error, the virtual device can modify the system virtual machine memory to restore the system state and allow Windows to terminate without hanging.
VM_Critical_Init | This is the second message the virtual device receives when a new virtual device is created. The virtual device can set the carry flag and return to prevent the virtual machine from being created. Interrupts are disabled and the Simulate_Int and Exec_Int services are not available.
VM_Init | This is the third message the virtual device receives when a new virtual device is created. The virtual device should initialize the state of the hardware and software in the virtual machine. For example, the virtual display device executes an Interrupt 10h function to set the initial display mode.
VM_Not_Executeable | This is the second termination message a virtual device receives for a virtual machine. (If the virtual machine is being destroyed by the virtual shell device, this is the first message received.) The virtual device can determine the cause of the termination by checking the flags in the EDX register. The Simulate_Int and Exec_Int services are not available for the given virtual machine.
VM_Resume | A virtual device receives this message when execution of the virtual machine is resumed, such as when switched to the foreground. The virtual device should lock any resources, and prepare internal structures for resumption of the virtual machine. If the virtual device sets the carry flag and returns, the VMM does not resume execution of the virtual machine.
VM_Suspend | A virtual device receives this message when execution of the virtual machine has been suspended, such as when switched to the background. The virtual device should unlock any resources associated with the virtual machine.
VM_Terminate | This is the first termination message a virtual device receives for a virtual machine. The virtual device can begin preparing for termination of the virtual machine. The Simulate_Int and Exec_Int services are available.


Virtual Device Initialization

The VMM initializes a virtual device by doing the following:

  1. Loads the real-mode initialization segment and calls the real-mode initialization procedure. The procedure can prevent the virtual device from being loaded, prevent Windows from starting, specify instance data for the device, and select pages in memory for its exclusive use.
  2. Loads the rest of the virtual device segments in 32-bit, flat-model protected-mode memory and discards the real-mode initialization segment.
  3. Sends a Sys_Critical_Init message to the device control procedure. Hardware interrupts are disabled, so the virtual device should spend as little time as possible initializing itself.
  4. Sends a Device_Init message to the device control procedure. Hardware interrupts are enabled, so the virtual device must be prepared to manage interrupts from its own device.
  5. Sends an Init_Complete message to the device control procedure.
  6. Discards the initialization code and data segments, freeing this memory for other uses. The virtual device must not attempt to access the procedures and data in these segments after it has processed the Init_Complete message.

At any time during initialization, a virtual device can set the carry flag and return to the VMM to prevent the virtual device from loading. Some VMM services, such as the Initialization Information services, are available only during initialization.


Real-Mode Initialization

Any static virtual device can provide real-mode initialization procedures to carry out initialization tasks before Windows switches to protected mode. The VMM calls the procedure as it loads the virtual device. The procedure typically checks the Windows environment, including relevant settings in the registry and initialization files, to determine whether the virtual device should be loaded. The procedure may also return information to Windows to specify physical pages to reserve for the device's exclusive use and addresses of data items to instance for each virtual machine. For more information about real-mode initialization, see the topic Real-Mode Initialization Procedure.


Virtual Device Services

A virtual device can provide service functions for use by the VMM and other virtual devices. The services give other virtual devices direct access to the features of the virtual device, allowing the operation and capabilities of the virtual device to be examined and modified.

Virtual devices do not export functions as Windows DLLs do. Instead, the VMM provides dynamic linking to virtual device services through Interrupt 20h. The interrupt handler uses a service number to determine which virtual device supports the service. The interrupt handler also uses the service number to look up the address of the service in the service table of the virtual device.

The following sections describe how to define services for a virtual device, declare the virtual device's service table, and import services from one virtual device into another.


Defining Services

A virtual device defines its services by using the BeginProc and EndProc macros and the Service or Async_Service options. The macros mark the start and end of the procedure code for the service. The options identify the procedure as a service. The following example shows the definition for the service VSAMPLED_Get_Version:

BeginProc VSAMPLED_Get_Version, Service
    mov   ax, 030Ah
    clc
    ret
EndProc VSAMPLED_Get_Version

The Async_Service option is for services that can be called asynchronously, that is, during processing of an interrupt. Asynchronous services must be re-entrant and must not call VMM or virtual device services that are not also asynchronous.

The VMM and standard virtual devices use two calling conventions for their services: register-based and 32-bit C-language based. These calling conventions specify the spelling for the service name, the method for passing parameters and returning values, and the registers to preserve.

For register-based services, the service name should not begin with an underscore (_). All the parameters are passed in registers, and results are returned in registers. Typically, the service preserves all registers it does not explicitly use to return values in.

For C-language-based services, the service name must begin with an underscore (_). All parameters are passed as 32-bit values on the stack. Results (if any) are returned in the EAX register (for 32-bit values), or the EAX and EDX registers (for 64-bit values). The service preserves the EBX, ES, FS, and GS registers as well as the ESI and EDI registers. Only the flags and the EAX, ECX, and EDX registers are modified.


Declaring Services

A virtual device uses the Begin_Service_Table and End_Service_Table macros to declare its services. The macros mark the start and end of a list containing the names of the services and optionally the names of the segments containing the services. The declaration must be made in the same file as the virtual device declaration (that is, in the file containing the Declare_Virtual_Device macro) and must be preceded with the definition of a device-specific symbol. The following example shows service table declaration for the sample virtual device, VSAMPLED:

Create_VSAMPLED_Service_Table   equ   1

Begin_Service_Table VSAMPLED
    VSAMPLED_Service     VSAMPLED_Get_Version, LOCAL
    VSAMPLED_Service     VSAMPLED_Service_1
    VSAMPLED_Service     VSAMPLED_Service_2, VxD_ICODE
End_Service_Table VSAMPLED

In this example, the Create_VSAMPLED_Service_Table symbol, defined just before the service table declaration, directs the Begin_Service_Table macro to create a service table for VSAMPLED. Once the declaration starts, the VSAMPLED_Service macro actually declares the services. This required macro is created by the Begin_Service_Table macro, and is only available within the service table declaration. The name of each service must exactly match the service's defined name, that is, the name given with the BeginProc macro.

When declaring a service, the LOCAL option must be given after the service name if the service is defined in the same source file containing the service table declaration. In other words, the service table automatically declares a service as an external service unless the LOCAL option is given. In the previous example, the VSAMPLED_Get_Version service is defined in the same file containing the service table.

Similarly, a segment name must be given after the service name if the service is not defined in the VxD_CODE segment. In the previous example, the VSAMPLE_Service_2 service is defined in the VxD_ICODE segment.

The order in which services are declared is important. The first declared service for a virtual device must be the Get_Version service. (This service clears the carry flag and returns with the virtual device's version number in the AX register.) Also, any new services added to the virtual device must be declared at the end of the table (or in explicitly reserved slots in the table). Since the VMM relies on the order of the services in the table to correctly link to the services, inserting a new service in the middle of the table requires that all virtual devices using the virtual device's service be rebuilt. For convenience, the service table declaration should be placed in an include file so that other virtual devices can import the services by including the file rather than recreating the declaration.


Importing Services

A virtual device can import services from another virtual device by including the virtual device's service table declaration. In such cases, the service table declaration must not be preceded with the device-specific symbol (as described in the previous section). For example, a virtual device that includes the file VSAMPLED.INC, which contains the service table declaration for VSAMPLED services, can call those services. A virtual device calls VMM services using the VMMCall macro, and calls virtual device services using the VxDCall macro.

Depending on a computer's configuration, a virtual device may fail to load when Windows starts. This means a virtual device that uses services provided by another virtual device must verify that the other virtual device services are available before calling them. To verify the services, the calling virtual device must attempt to call the Get_Version service of the virtual device providing the services. If the virtual device has not been loaded, the VMM sets the carry flag and returns zero in the AX register.


Virtual Device API Procedures

A virtual device provides V86-mode and protected-mode API procedures to allow applications and other software running in a virtual machine access to the features of the virtual device. To make these optional procedures available, the virtual device must declare them as parameters in the Declare_Virtual_Device macro. If not declared, the VMM assumes that the virtual device has no API procedures.

An application or other software running in a virtual machine retrieves an entry-point address for an API procedure for a given virtual machine by calling the Get Device Entry Point Address function (Interrupt 2Fh Function 1684h) and setting the BX register to the identifier for the virtual device. The VMM returns an address to the application to indirectly enter the API procedure.

When an application calls the entry-point address, the VMM saves the application's registers and calls the virtual device's corresponding API procedure, placing the handle of the current virtual machine in the EBX register and the address of a Client_Reg_Struc structure in the EBP register. The API procedure must examine the client registers (using the Client_Reg_Struc) to determine which API call was made.

By convention, most API procedures use the AH register to specify the major function number and the AL register to specify the minor function number, with other client registers being used for additional parameters. The API procedure returns values by modifying the client registers. An API procedure may modify the EAX, EBX, ECX, EDX, ESI, and EDI registers.

The following example shows the sample API procedure VSAMPLED_API_Get_Version:

BeginProc VSAMPLED_API_Get_Version
    movzx eax, [ebp.Client_AX]          ; get function number
    or   eax, eax
    jnz Undefined

Get_Version:
    mov [ebp.Client_AX], 030Ah          ; return version in client's AX
    and [ebp.Client_Flags], NOT CF_Mask ; clear carry flag
    ret

Undefined:
    or [ebp.Client_Flags], CF_Mask      ; set carry flag
    ret
EndProc VSAMPLED_API_Get_Version


Virtual Device Interrupt 2Fh Functions

A virtual device can provide Interrupt 2Fh functions by installing a callback procedure for this interrupt. Interrupt 2Fh functions allow applications and other software running in a virtual machine access to the virtual device without requiring the virtual device to provide API procedures. For example, the standard virtual display supports a set of Interrupt 2Fh functions with which it communicates with the Windows display driver.

Windows installs its own Interrupt 2Fh handler and supports a variety of functions to allow MS-DOS device drivers and TSRs to specify actions to take when Windows starts or while a virtual machine runs. For more information about these functions, see the topic Windows Interrupt 2Fh Interface.


Building a Virtual Device

You build a virtual device by doing the following:

  1. Create the virtual device source files and assemble the sources using MASM.EXE, the 32-bit flat-model assembler.
  2. Create a module definition file (.DEF) and link the object files using LINK.EXE, the 32-bit flat model linker. By convention, the resulting executable file should have the same filename as the virtual device, but with the filename extension .VXD.
  3. Create a debugging symbol file for the executable file using MAPSYM.EXE.

A virtual device is not compatible with Windows dynamic-link libraries. Windows-based applications cannot load and use virtual devices directly. However, Win32-based applications can use the CreateFile and DeviceIoControl functions to load and interact with dynamically loadable VxDs.

The module definition file for a virtual device has the following form:

LIBRARY  VSAMPLED

DESCRIPTION 'VSAMPLED Device  (Version 4.0)'

EXETYPE  DEV386

SEGMENTS
             _LTEXT PRELOAD NONDISCARDABLE
             _LDATA PRELOAD NONDISCARDABLE
             _ITEXT CLASS 'ICODE' DISCARDABLE
             _IDATA CLASS 'ICODE' DISCARDABLE
             _TEXT  CLASS 'PCODE' NONDISCARDABLE
             _DATA  CLASS 'PCODE' NONDISCARDABLE

EXPORTS
             VSAMPLED_DDB  @1

The LIBRARY statement must specify the name of the virtual device, as given in the device description block (DBB) and the EXPORTS statement must specify the name of the DBB. In all cases, the export ordinal for the DDB is 1.


Windows-Based Device Drivers

This section describes the purpose and function of Windows-based device drivers. You should create a Windows-based device driver for your device if it is not 100 percent compatible with the devices supported by the Windows retail device drivers, or if you want to offer Windows users access to unique features of your device.

A Windows-based device driver is a dynamic-link library (DLL) that Windows uses to interact with a hardware device such as a display or a keyboard. Rather than access devices directly, Windows loads device drivers and calls functions in the drivers to carry out actions on the device. Each device driver exports a set of functions; Windows calls these functions to complete an action, such as drawing a circle or translating a keyboard scan code. The driver functions also contain the device-specific code needed to carry out actions on the device.

Windows requires device drivers for the display, keyboard, communication ports, mouse, and network. Printer, pen, and modem drivers are required if the user adds these optional devices to the system.


Creating a Device Driver

You create a device driver either by adapting a sample driver, or writing a driver from scratch. You can write Windows device drivers in assembly language or in a high-level language such as the C language. Assembly language programmers can use the CMACROS assembly-language macro package.

To create a device driver, you need to:

  1. Read the section in this documentation that describes the driver for your type of device.
  2. Write the required driver functions.
  3. Create and compile the required resources.
  4. Every device driver must have at least a VERSIONINFO resource that contains the version stamp for the driver. Setup and Control Panel both look for this resource when installing drivers.
  5. Create a module-definition file that identifies the appropriate module name for your driver, and export the required functions.
  6. Assemble and link your driver.
  7. Test your driver using the debugging version of Windows.
  8. Create an installation file (*.INF) for your driver and related files.
  9. Create your final distribution disk or disks.


Guidelines for Designing and Writing a Driver

When designing and writing your device driver, follow these guidelines:

  • Make every effort to make your device driver as small as possible; reserve system memory for applications.
  • Use multiple, discardable code segments to help reduce the amount of driver code needed in memory at any given time.
  • Use an automatic data segment only if necessary.
  • Make resources discardable, and lock them in memory only when needed.
  • Use the stack sparingly. Because device drivers use the stack of the application that initiated the call to the driver, there is no way for the driver to determine how much available space is on the stack.
  • Check for NULL pointers to avoid a general protection fault from using an invalid selector.
  • Check the segment limits when reading from or writing to allocated segments to avoid a general protection fault from attempting to access data beyond the end of a segment.
  • Use the __ahincr constant when creating selectors for huge memory (allocated memory greater than 64 kilobytes). Other methods of selector arithmetic can create invalid selectors and cause general protection faults.
  • Create code-segment aliases for any code to be executed from data segments. Attempting to call or jump to a data segment address generates a general protection fault.


Windows Calling Conventions

This documentation presents the syntax of most functions in C-language notation. All such functions are assumed to be declared as FAR PASCAL functions, and Windows will call these functions as such. In general, exported functions in a device driver must execute the standard Windows prolog on entry and epilog on exit.

The following list highlights the calling conventions:

  • Set the DS register to the selector of the driver's automatic data segment.
  • Save and restore the following registers if used: SS, SP, BP, SI, DI, and DS.
  • Clear the direction flag if it has been set or modified.
  • Place 16-bit return values in the AX register; 32-bit values in the DX:AX register pair.
  • Execute a FAR return.

Windows pushes all parameters on the stack in a left to right order (the last parameter shown in the function syntax is closest to the stack pointer). Windows also passes pointer parameters as 32-bit quantities, pushing the selector first then the offset. This allows exported functions to use the lds or les instructions to retrieve pointers from the stack.


Real-Mode Initialization Procedure

This section describes the real-mode initialization procedure for static VxDs and defines the real-mode initialization services. Real-mode initialization does not apply to dynamically loadable VxDs.

The VMM calls the real-mode initialization procedure once only, and then discards the segment containing the procedure. It is not possible to have a real-mode procedure that permanently remains in the virtual machine.

The VMM requires the real-mode initialization procedure to start at offset zero in the virtual device's real-mode initialization segment. Before calling this address, the VMM sets the CS, DS, and ES registers to the address of this segment. The VMM requires that the code or data for the procedure be defined within the real-mode segment, or in fixed memory (for example, in the ROM BIOS at segment address 40h). In general, the procedure should not attempt to access code or data outside the real-mode segment.

The procedure can use most ROM BIOS routines and MS-DOS system functions to examine memory and check the computer's configuration. It must not attempt to call any MS-DOS program termination function; this will hang the computer. Also, the procedure must close any files it opens before it returns to the VMM. The procedure must return to the VMM by executing a near ret instruction.

The real-mode procedure can modify all other registers except the SS:SP register pair.


Real-Mode Initialization Parameters

The VMM passes the following parameters to the real-mode initialization procedure.

Parameter | Description
AX | Specifies the version number of the virtual machine manager. The AH register contains the major version number, and the AL register contains the minor version number.
BX | Specifies the loading flags. This register contains one of the following values:

Duplicate_Device_ID | Device with same device identifier already loaded.
Duplicate_From_INT2F | Duplicate device identifier already loaded from Interrupt 2Fh device list.
Loading_From_INT2F | This device was specified in the Interrupt 2Fh device list.

ECX | Specifies the 32-bit address (segment:offset) of the entry point for real-mode initialization services. Virtual devices can call these services to retrieve settings from the registry and the SYSTEM.INI file.
EDX | Specifies a pointer to reference data provided in the Interrupt 2Fh. This register contains zero if there is no reference data.
SI | Specifies the segment address of the environment passed from MS-DOS.
SS:SP | Specifies the 32-bit address (segment:offset) of the stack.


Return Value, Instanced Data, and Excluded Pages

The real-mode initialization procedure uses return values to direct the VMM to carry out specific actions, such as instancing data items and reserving physical pages. The procedure must return values in each of the following registers.

Register | Description
AX | Contains the return value. It can be one of the following values:

Abort_Device_Load | Directs the VMM to prevent the virtual device from loading. This does not affect the loading of other the virtual devices.
Abort_Win386_Load | Specifies a fatal error and directs the VMM to end Windows.
Device_Load_Ok | Directs the VMM to load and initialize the rest of the virtual device.
No_Fail_Message | When combined with the Abort_Device_Load or Abort_Win386_Load value, directs the VMM to carry out its error handling without displaying a message. If this value is not given, the VMM displays an error message when a virtual device fails.

BX | Points to a null-terminated array of page numbers specifying the physical pages to reserve for exclusive use by the virtual device. The pages must be in low memory (that is, page numbers must be in the range zero through 100h). This register must be set to zero if the virtual device does not reserve pages.
EDX | Specifies a 32-bit value representing reference data to be passed through the EDX register to the virtual device's device control procedure when the VMM sends the Sys_Critical_Init message. This value can be a linear address to ROM BIOS data, a constant, or some other value. For example, an EBIOS device can pass the EBIOS page number, so that the procedure that processes the message does not need to look for the page again.
SI | Points to a null-terminated array of instance data items. Each element in the array has the following form: ItemAddress dd ? ; segment:offset of item to instance Length dw ? ; length in bytes of data item The VMM allocates a unique copy of the instanced data for each virtual machine. This register must be set to zero if the virtual device does not instance data. Note that the virtual device must not attempt to instance the interrupt vector table; the VMM automatically instances this table.

In some rare cases, a virtual device consists of nothing more than a real-mode initialization procedure that reserves exclusive pages and declares instance data. Such a virtual device always returns 8001h to prevent the VMM from loading any other portion of the virtual device, or displaying an error message.


Real-Mode Initialization Example

The following example shows a typical real-mode initialization procedure:

;*********************************************************************
; Real-mode initialization code
;*********************************************************************

VxD_REAL_INIT_SEG

BeginProc ebios_init
    mov    ah, 0C0h
    int    15h
    test    es:[bx.SD_feature1], EBIOS_allocated
    jz    short no_ebios_fnd
    mov    ah, 0C1h                  ; get segment adr of EBIOS
    int    15h
    jc    short no_ebios_fnd
    mov    ax, es                    ; get EBIOS segment address
    shr    ax, 8                     ; convert to a page number
    movzx    edx, ax                 ; return EBIOS page as reference
                                     ;  data
    mov    bx, OFFSET exc_ebios_page ; pointer to exclusion table
    mov    [bx], ax                  ; 1 entry, to exclude EBIOS page
                                     ; from memory manager use
    xor    si, si                    ; no instance data to declare
    mov    ax, Device_Load_Ok        ; go ahead and load the device
    jmp    short init_exit           ; return to loader

no_ebios_fnd:
    mov    ah, 9
    mov    dx, OFFSET no_ebios_msg   ; print message through MS-DOS
    int    21h
    xor    bx, bx                    ; no exclusion table
    xor    si, si                    ; no instance data table
    xor    edx, edx                  ; no reference data
    mov    ax, Abort_Device_Load + No_Fail_Message
                                     ; don't load protected-mode
                                     ; portion and don't display a
                                     ; failure message
init_exit:
    ret

exc_ebios_page    dw  0, 0

no_ebios_msg  db 'PS/2 type EBIOS not detected', 13, 10, '$'

EndProc ENDP

VxD_REAL_INIT_ENDS


Reference

This section is an alphabetical list of the real-mode initialization services.

LDRSRV_COPY_EXTENDED_MEMORY

mov   ax, 0006h             ; Copy_Extended_Memory
call  dword ptr [_ServiceEntry]  ; service entry point passed to
                                 ; real-mode initialization procedure

Allocates a block of extended memory in the specified data group (init, locked, or pageable) to the size requested and initializes the block with the given data.

  • If the carry flag is clear, EAX contains the linear address of the memory block. Otherwise, the allocation failed and no memory block is allocated
AX
Must be 0006h.
CX
Number of bytes to allocate. Actual size is rounded up to the nearest DWORD.
DX
Type of data being allocated. Can be one of these values.
LDRSRV_COPY_INIT | INIT data
LDRSRV_COPY_LOCKED | LOCKED data
LDRSRV_COPY_PAGEABLE | PAGEABLE data

DS:SI
Address of data to be copied.

This service provides a way for VxDs to pass data to their protected-mode portions. The VxD creates a block of extended memory and passes its linear address through the VxD reference DWORD (that is, the value of EDX on exit from real-mode initialization). Multiple blocks allocated by a single VxD are guaranteed to be contiguous in linear address space, but not necessarily in physical address space. PAGEABLE data may actually be allocated as LOCKED data, at the loader's discretion. Initialization (INIT) data is always locked, and is discarded after all VxD initialization phases are completed.

LDRSRV_GET_MEMORY_INFO

mov   ax, 0007h                  ; Get_Memory_Info
call  dword ptr [_ServiceEntry]  ; service entry point passed to
                                 ; real-mode initialization procedure

Retrieves information about computer memory.

LDRSRV_GET_NEXT_PROFILE_STRING

mov    ax, 0001h         ; Get_Next_Profile_String
call  dword ptr [_ServiceEntry]  ; service entry point passed to
                                 ; real-mode initialization procedure

Retrieves the address of a null-terminated string representing the next value for a specified setting in the SYSTEM.INI file. This service is used by virtual devices that have multiple entries with the same setting name. Uses EAX, EDX, ES, Flags.

  • If the carry flag is clear, the ES:DX register pair contains the address of a null-terminated string representing the next value of the requested setting. Otherwise, the ES:DX contents are undefined, and no more matching entries are found.
AX
Must be 0001h.
DS:DI
Points to a null-terminated string specifying the name of the setting to search for.
ES:DX
Contains an address that was previously retrieved using the Get_Profile_String or Get_Next_Profile_String service.

LDRSRV_GET_PROFILE_BOOLEAN

mov    ax, 0003h         ; Get_Profile_Boolean
call  dword ptr [_ServiceEntry]  ; service entry point passed to
                                 ; real-mode initialization procedure

Returns a Boolean value from the SYSTEM.INI file. Uses ECX, Flags.

  • If the carry flag is clear, the ECX register contains either 0FFFFFFFFh or 0h depending on the value of the setting as follows.
Setting | Value
0 | 0h
1 | 0FFFFFFFFh
False | 0h
No | 0h
Off | 0h
On | 0FFFFFFFFh
True | 0FFFFFFFFh
Yes | 0FFFFFFFFh

If both the carry and zero flags are set, the setting has no current value and ECX contains the default value. If just the carry flag is set, the specified setting cannot be found.

AX
Must be 0003h.
ECX
Specifies the default value if the setting has no current value. The default value must be either 0FFFFFFFFh or 0h.
DS:SI
Points to a null-terminated string specifying the name of the section to search. If the SI register is zero, the service searches the [386Enh] section.
DS:DI
Points to a null-terminated string specifying the name of the setting to search for.

LDRSRV_GET_PROFILE_DECIMAL_INT

mov    ax, 0004h         ; Get_Profile_Decimal_Int
call  dword ptr [_ServiceEntry]  ; service entry point passed to
                                 ; real-mode initialization procedure

Returns a decimal integer value from the SYSTEM.INI file. Uses ECX, Flags.

  • If the carry flag is clear, the ECX register contains the value of the specified setting. In the SYSTEM.INI file, the value can optionally begin with a plus (+) or minus (-) sign, but must contain all decimal digits with no embedded spaces or decimal points.

    If both the carry and zero flags are set, the setting has no current value and ECX contains the default value. If just the carry flag is set, the specified setting cannot be found.

AX
Must be 0004h.
ECX
Specifies the default value if the setting has no current value.
DS:SI
Points to a null-terminated string specifying the name of the section to search. If the SI register is zero, the service searches the [386Enh] section.
DS:DI
Points to a null-terminated string specifying the name of the setting to search for.

LDRSRV_GET_PROFILE_HEX_INT

mov    ax, 0005h         ; Get_Profile_Hex_Int
call  dword ptr [_ServiceEntry]  ; service entry point passed to
                                 ; real-mode initialization procedure

Returns a hexadecimal integer value from the SYSTEM.INI file. Uses ECX, Flags.

  • If the carry flag is clear, the ECX register contains the value of the specified setting. In the SYSTEM.INI file, the value is zero or more hexadecimal digits (0–9, A-F) followed by a terminating character or an uppercase or lowercase letter H.

    If both the carry and zero flags are set, the setting has no current value, and the ECX register contains the default value. If just the carry flag is set, the specified setting cannot be found.

AX
Must be 0005h.
ECX
Specifies the default value if the setting has no current value.
DS:SI
Points to a null-terminated string specifying the name of the section to search. If the SI register is zero, the service searches the [386Enh] section.
DS:DI
Points to a null-terminated string specifying the name of the setting to search for.

LDRSRV_GET_PROFILE_STRING

mov    ax, 0000h         ; Get_Profile_String
call  dword ptr [_ServiceEntry]  ; service entry point passed to
                                 ; real-mode initialization procedure

Searches the SYSTEM.INI file for the specified entry, and returns a pointer to a string. Uses EAX, EDX, ES, Flags.

  • If the carry flag is clear, the ES:DX register pair contains the address of a null-terminated string representing the value of the requested setting. Otherwise, the register pair points to the default string.
AX
Must be 0000h.
DS:SI
Points to a null-terminated string specifying the name of the section to search. If the SI register is zero, the service searches the [386Enh] section of the SYSTEM.INI file.
DS:DI
Points to a null-terminated string specifying the name of the setting to search for.
ES:DX
Points to null-terminated string specifying the default value if the requested setting is not found.

The real-mode initialization procedure must not modify the returned string. The address returned points to the initialization file data area and is read only.


Windows Interrupt 2Fh Interface

The Microsoft® Windows® Interrupt 2Fh services and notifications help Windows device drivers and related MS-DOS device drivers and terminate-and-stay-resident (TSR) programs manage their operations in the multitasking environment of Windows. The services let drivers carry out actions such as relinquishing the CPU time slice. The notifications let drivers respond to events, such as starting up Windows, that Windows broadcasts using Interrupt 2Fh.


Services and Notifications

The Interrupt 2Fh services are a set of functions that MS-DOS drivers and TSRs call to direct Windows to carry out specific actions. The notifications are a set of functions that Windows calls to notify drivers and programs of Windows-related events. Although these functions were initially designed for use by MS-DOS drivers and TSRs, some Windows device drivers, such as display drivers and grabbers, also use them to manage the multitasking features of Windows.

A driver can call the service functions using the MS-DOS multiplex interrupt, Interrupt 2Fh. The driver sets one or more registers to specified values, sets the AX register to the desired function number, and issues the interrupt using the int instruction.

A driver can receive notifications by installing its own interrupt-handling routine in the Interrupt 2Fh interrupt chain. Once the interrupt handler is installed, the driver checks the AX register on each interrupt for function numbers that match the notifications. When the driver matches a notification, it can carry out any related actions.


Service Functions

The service functions let drivers and TSRs obtain the Windows version number, obtain the current virtual-machine (VM) identifier, set critical sections, and retrieve the addresses of the entry points for virtual-device service functions. There are the following service functions:

  • Get Windows Installed State (Interrupt 2Fh Function 1600h)
  • Get Windows Entry-Point Address (Interrupt 2Fh Function 1602h)
  • Release Current VM Time-Slice (Interrupt 2Fh Function 1680h)
  • Begin Critical Section (Interrupt 2Fh Function 1681h)
  • End Critical Section (Interrupt 2Fh Function 1682h)
  • Get Current Virtual Machine ID (Interrupt 2Fh Function 1683h)
  • Get Device Entry Point Address (Interrupt 2Fh Function 1684h)
  • Switch VMs and CallBack (Interrupt 2Fh Function 1685h)
  • Detect Interrupt 31h Services (Interrupt 2Fh Function 1686h)

Windows issues Windows Initialization Notification (Interrupt 2Fh Function 1605h) and Windows Termination Notification (Interrupt 2Fh Function 1606h). These notifications gives MS-DOS drivers and TSR programs in either Windows environment the opportunity to free extended memory before Windows starts, and reallocate the memory when Windows stops.

Windows also support Detect Interrupt 31h Services. Supporting these services lets MS-DOS drivers and TSR programs check for and use these service functions.

If the user starts a TSR program after Windows starts, the TSR program can always use Get Windows Installed State (Interrupt 2Fh Function 1600h) to determine whether Windows is running.


Notification Functions

Windows broadcasts the notification functions by setting registers and issuing Interrupt 2Fh. Drivers and TSRs use the notifications to load Windows installable devices, free extended memory, and enable or disable various device services or features. There are the following notification functions:

  • Windows Initialization Notification (Interrupt 2Fh Function 1605)
  • Windows Termination Notification (Interrupt 2Fh Function 1606h)
  • Device Call Out (Interrupt 2Fh Function 1607h)
  • Windows Initialization Complete Notification (Interrupt 2Fh Function 1608h)
  • Windows Begin Exit (Interrupt 2Fh Function 1609h)

MS-DOS device drivers, such as network drivers, use Windows Initialization Notification to direct Windows to load a protected-mode installable device that provides 32-bit support for the real-mode driver while Windows runs. Other MS-DOS drivers (for example, disk-cache drivers) use the same notification to free any extended memory before Windows starts. The TSRs also use Windows Termination Notification to reclaim the extended memory when Windows stops.

If an MS-DOS driver or TSR programs installs a corresponding virtual device, that device can send notifications of its own to the driver or TSR using Device Call Out.


Critical Section Handling

Occasionally, an MS-DOS driver or TSR program may need to run for a period of time that may exceed its regular time slice. In such cases, the driver can create a critical section that prevents Windows from switching the CPU away from the driver or program.

A driver starts a critical section by using Begin Critical Section (Interrupt 2Fh Function 1681h). While the critical section is in effect, only device interrupts can divert execution from the driver. A driver ends the critical section by using End Critical Section (Interrupt 2Fh Function 1682h). In general, a driver should end the critical section as soon as possible to ensure that all drivers and programs in the system receive CPU time. If a driver starts a critical section n times, it must end the critical section n times before the critical section is actually released.

Ordinarily, Windows prevents rescheduling of the current virtual machine if the one-byte, MS-DOS InDOS flag is nonzero. One exception is when a driver or program issues the MS-DOS Idle interrupt (Interrupt 28h). In such cases, Windows may reschedule regardless of the value of the InDOS flag. The only way to prevent this rescheduling is to start a critical section using Begin Critical Section. While in a critical section, Windows disregards Interrupt 28h.

In previous versions of Windows, service functions to support critical sections were not supplied. Drivers and programs achieved a similar effect by incrementing and decrementing the MS-DOS InDOS flag. Although this method was acceptable for previous versions of Windows, drivers should not use this method in versions of Windows that supply Begin Critical Section and End Critical Section (Interrupt 2Fh Function 1682h).

Drivers and programs that use the InDOS flag method retrieve the address of the InDOS flag using Get InDOS Flag Address (Interrupt 21h Function 34h). The function returns the address in the ES:BX register pair. When using this method, drivers and programs check the flag value before decrementing because some error conditions (such as when the user types CTRL+C) set the InDOS flag to zero regardless of its current value. Decrementing the InDOS flag to a number less than zero is a serious error.


Releasing the Time Slice

MS-DOS applications can also use the Interrupt 2Fh service functions. In particular, applications can use Release Current VM Time Slice (Interrupt 2Fh Function 1680h) to release the current virtual machine's time slice. An MS-DOS application typically uses this function when waiting for user input. This function helps Windows multitask more efficiently by letting it reschedule the CPU for other work immediately, rather than waiting for the idle application to spend its entire time slice.


Virtual-Display Device Services and Notifications

The virtual display device for Windows also provides Interrupt 2Fh service and notification functions. Windows display drivers use these functions to check for and manage screen switching. There are the following functions:

  • Enable VM-Assisted Save/Restore (Interrupt 2Fh Function 4000h)
  • Notify Background Switch (Interrupt 2Fh Function 4001h)
  • Notify Foreground Switch (Interrupt 2Fh Function 4002h)
  • Enter Critical Section (Interrupt 2Fh Function 4003h)
  • Exit Critical Section (Interrupt 2Fh Function 4004h)
  • Save Video Register State (Interrupt 2Fh Function 4005h)
  • Restore Video Register State (Interrupt 2Fh Function 4006h)
  • Disable VM-Assisted Save/Restore (Interrupt 2Fh Function 4007h)


Functions

The following topics contain an alphabetical listing of the Interrupt 2Fh functions.


Interrupt 2Fh Function 1600h

mov     ax, 1600h   ; Get Windows Installed State
int     2Fh         ; multiplex interrupt

test    al, 7Fh
jz      No_EM_Win   ; Windows not running

Get Installed State (Interrupt 2Fh Function 1600h) determines whether Windows is running. If a program intends to use a Windows function, it must first use this function to make sure that Windows is running.

This function has no parameters.

The return value is 00h or 80h in the AL register if Windows is not running. If Windows is running, the return value is the major version number in the AL register, and the minor version number in the AH register.


Interrupt 2Fh Function 1602h

mov  ax, 1602h            ; Get Windows Entry Point
int  2Fh                  ; multiplex interrupt

mov  word ptr [WinAddr], di
mov  word ptr [WinAddr+2], es ; es:di contains entry-point address

Get Windows Entry Point (Interrupt 2Fh Function 1602h) returns the address of the Windows entry-point procedure. Applications can call this procedure to direct Windows/386 version 2.x to carry out specific actions.

This function is obsolete. Do not use.

This function has no parameters.

The return value contains the Windows entry-point address in the ES:DI registers.

See Also

Interrupt 2Fh Function 1683h Get Current Virtual Machine ID


Interrupt 2Fh Function 1605h

xor     bx, bx
mov     es, bx          ; es:bx contains 0000h:0000h

mov     cx, 0000h
mov     dx, [Flags]     ; bit 0 clear if Windows 95

mov     di, [Ver_Num]   ; major/minor version numbers
                        ; (in high/low bytes)

xor     si, si
mov     ds, si          ; ds:si contains 0000h:0000h

mov     ax, 1605h       ; Windows Initialization Notification
int     2fh             ; multiplex interrupt

cmp     cx, 0
jne     no_initialize   ; if nonzero, don't continue initialization

Windows Initialization Notification (Interrupt 2Fh Function 1605h) notifies MS-DOS device drivers and TSRs that Windows is starting. Windows calls this function as it starts allowing MS-DOS device drivers and TSRs that monitor Interrupt 2Fh the opportunity to prepare for running in the Windows environment.

Flags
Specifies whether Windows 95 is initializing. Bit 0 set to zero for Windows 95; bit 0 set to 1 for other, previous versions of Windows. Only bit 0 is used; all other bits reserved and undefined.
Ver_Num
Specifies the version number of Windows. The major version number is in the high-order byte, the minor version number in low-order byte.

The return value is zero in the CX register if all MS-DOS device drivers and TSRs monitoring Interrupt 2Fh can run in the Windows environment, and Windows can proceed with initialization. Otherwise, the CX register is nonzero and Windows must terminate.

Any MS-DOS device driver or TSR that either cannot run in the Windows environment, or must adapt its operation when in the Windows environment should add itself to the Interrupt 2Fh chain and watch for this function.

If the device driver or TSR cannot run in the Windows environment, it should set the CX register to a nonzero value, display a message informing the user of its incompatibility with Windows, and return. Windows does not print a message of its own. Instead, it calls Windows Termination Notification (Interrupt 2Fh Function 1606h) and returns to MS-DOS.

If the device driver or TSR can run in the Windows environment, it should do the following:

  1. Call the next device driver or TSR in the Interrupt 2Fh chain to allow all device drivers and TSRs in the chain an opportunity to respond to this function.
  2. Upon return from the interrupt chain, carry out the following actions:
    • Free any extended memory. The device driver or TSR takes this action only if it has previously allocated extended memory using the Extended Memory Specification (XMS) interface.
    • Switch the processor to real mode, or set the DS:SI register pair to the address of an Enable/Disable Virtual 8086 Mode callback function. The device driver or TSR takes this action only if it has previously switched the processor to virtual 8086 mode. If standard-mode Windows is starting, the device driver or TSR must switch the processor to real mode - the callback function is permitted for Windows only.
    • Initialize a Win386_Startup_Info_Struc structure, and copy the address of the structure to the ES:BX register pair. The device driver or TSR carries out this action only if Windows is starting.
  3. Return (using the iret instruction) but without changing the CX register.

The device driver or TSR must preserve all registers and restore the original values before returning. The only exceptions to this rule are changes made to the BX, CX, DS, ES, and SI registers as a result of following the previous procedure.

Enable/Disable Virtual 8086 Mode CallBack Function

Some device drivers and TSRs, such as expanded memory emulators, switch the processor to virtual 8086 mode. Because Windows cannot start successfully while the processor is in this mode, any device driver or TSR that switches to virtual 8086 mode must either switch back to real mode or supply the address of a callback function that can switch between real and virtual 8086 modes.

Windows uses the callback function to disable virtual 8086 mode before Windows itself enters protected mode. Windows calls the callback function again to enable virtual 8086 mode after Windows exits protected mode. Windows calls the callback function using a far call instruction, and it specifies which action to take by setting the AX register to zero or 1.

To disable virtual 8086 mode, Windows sets the AX register to 0, disables interrupts, and calls the callback function. The function should switch the processor to real mode, clear the carry flag to indicate success, and return. If an error occurs, the function sets the carry flag and returns. Windows checks the carry flag and terminates if it is set.

To enable virtual 8086 mode, Windows set the AX register to 1, disables interrupts, and calls the callback function. The function should switch the processor to virtual 8086 mode, clear the carry flag, and return. If an error occurs, the function sets the carry flag and returns. However, Windows ignores the carry flag, so if an error occurs no action is taken and the processor is left in real mode.

Whether an error occurs when enabling or disabling virtual 8086 mode, it is up to the callback function to display any error message to the user. Also, the callback function must not enable interrupts unless an error occurs, and the function sets the carry flag.

A device driver or TSR supplies a callback function by copying the address of the function to the DS:SI register pair when it processes the Windows Initialization Notification (Interrupt 2Fh Function 1605h). Windows permits only one callback function, so the device driver or TSR should first check to make sure that the DS and SI registers are both zero. If they are nonzero, the device driver or TSR should set the CX register to a nonzero value and return, directing Windows to terminate without starting.

Initializing a Win386_Startup_Info_Struc Structure

An MS-DOS device driver or TSR initializes a Win386_Startup_Info_Struc structure to direct Windows to load the virtual device and to reserve the instance data the device driver or TSR needs to operate in the Windows environment. The device driver or TSR is also responsible for establishing a chain of startup structures by copying the contents of the ES:BX register pair to the Next_Dev_Ptr member. It is assumed that any other device driver or TSR in the Interrupt 2Fh chain will have set the ES:BX register pair to the address of its own startup structure prior to returning.

Any device driver or TSR can use a Windows virtual device to help support its operation in the Windows environment. To specify a virtual device, the device driver or TSR sets the SIS_Virt_Dev_File_Ptr member to the address of the virtual device's filename. The device file is assumed to be in the Windows SYSTEM directory. The device driver or TSR can also set the SIS_Reference_Data member to specify additional data to be passed to the virtual device when loaded.

Any device driver or TSR can reserve instance data for itself. Instance data is one or more blocks of memory used by the device or TSR, and managed by Windows. For device drivers or TSRs loaded before Windows starts, reserving instance data allows the device driver or TSR to keep separate data for each virtual machine. Whenever Windows switches virtual machines, it saves the previous VMs instance data and loads the current VMs instance data. If a device driver or TSR does not specify instance data, the same data is used for all virtual machines.

A device driver or TSR reserves instance data by appending an array of Instance_Item_Struc structures to the Win386_Startup_Info_Struc structure. The last structure in the array must be set to zero. Each Instance_Item_Struc structure specifies the starting address and size (in bytes) of an instance data block.

The device driver or TSR must copy the address of its startup structure to the ES:BX register pair before returning.

See Also

Interrupt 2Fh Function 1606h Windows Termination Notification


Interrupt 2Fh Function 1606h

Note Windows 98 no longer uses this Interrupt. Attempts at invoking it will have no effect. However, the related Interrupt 2Fh Function 1605h Windows start up notification is still supported and applicable.

mov     dx, [Flags]  ; bit 0 clear

mov     ax, 1606h    ; Windows Termination Notification
int     2fh          ; multiplex interrupt

Windows Termination Notification (Interrupt 2Fh Function 1606h) notifies MS-DOS device drivers and TSRs that Windows is terminating. Windows calls this function as it terminates allowing MS-DOS device drivers and TSRs that monitor Interrupt 2Fh the opportunity to prepare for leaving the Windows environment.

Flags
Specifies whether Windows 95 is terminating. Bit 0 set to zero for Windows 95; bit 0 to 1 for other, previous versions of Windows. Only bit 0 is used; all other bits reserved and undefined.

This function has no return value. Windows calls this function when the processor is in real mode.

See Also

Interrupt 2Fh Function 1605h Windows Initialization Notification


Interrupt 2Fh Function 1607h

mov     bx, [DeviceID]  ; device identifier

mov     ax, 1607h       ; Device Call Out
int     2fh             ; Multiplex Interrupt

Device Call Out (Interrupt 2Fh Function 1607h) directs an MS-DOS device driver or TSR to provide information to the calling virtual device. Although the BX register specifies a device identifier, other registers may be used to specify the action to take.

DeviceID
Specifies the device identifier for a virtual device.

The return value depends on the specific action requested.

This function typically is used by a virtual device to communicate with the driver or TSR that explicitly loaded the virtual device. It is up to the virtual device to supply a correct device identifier and any other parameters that specify what action to take. It is up to the driver or TSR to monitor Interrupt 2Fh, and respond to the function appropriately.

A virtual device can call this function at any time, either in real mode or after Windows has started.

See Also

Interrupt 2Fh Function 1684h Get Device Entry Point Address


Interrupt 2Fh Function 1608h

mov     ax, 1608h   ; Windows Initialization Complete Notification
int     2Fh         ; multiplex interrupt

Windows Initialization Complete Notification (Interrupt 2Fh Function 1608h) notifies MS-DOS device drivers and TSRs that Windows has completed its initialization. Windows calls this function after it has installed and initialized all virtual devices allowing MS-DOS device drivers and TSRs that monitor Interrupt 2Fh the opportunity to identify instance data and perform other functions that are restricted to Windows initialization.

This function has no parameters.

This function has no return value.

When Windows calls this function, all virtual-device initialization is complete, so a device driver or TSR can call virtual-device entry points.

Windows does not necessarily call this function immediately after calling Windows Initialization Notification (Interrupt 2Fh Function 1605h). In particular, virtual devices may call Device Call Out (Interrupt 2Fh Function 1607h) or other functions prior to Windows calling this function. In such cases, any MS-DOS device driver or TSR responding to these calls is responsible for detecting and properly handling these calls.

See Also

Interrupt 2Fh Function 1605h Windows Initialization Notification


Interrupt 2Fh Function 1609h

mov     ax, 1609h   ; Windows Begin Exit
int     2fh         ; multiplex interrupt

Windows Begin Exit (Interrupt 2Fh Function 1609h) notifies MS-DOS device drivers and TSRs that Windows is about to terminate. Windows calls this function when it first begins termination to allow a device driver or TSR to prepare for a return to a non-Windows environment.

This function has no parameters.

This function has no return value.

Windows calls this function at the start of the Sys_VM_Terminate device control call. All virtual devices still exist, so a device driver or TSR can call a virtual device's entry point if necessary.

Windows does not call this function in the event of a fatal system crash.

Windows may execute real-mode code after this function has been called and before Windows returns to real mode. It is the responsibility of the device driver or TSR to detect and properly handle these situations.


Interrupt 2Fh Function 1680h

mov     ax, 1680h   ; Release Current VM Time-Slice
int     2Fh         ; multiplex interrupt

Release Current VM Time-Slice (Interrupt 2Fh Function 1680h) directs Windows to suspend the time slice of the current VM and start a new time slice for another VM. MS-DOS programs use this function when they are idle, such as when waiting for user input, to allow Windows to run other programs that are not idle.

This function has no parameters.

The return value is 00h in the AL register if the function is supported. Otherwise, AL is unchanged (contains 80h).

Only non-Windows programs should use Release Current VM Time-Slice; Windows applications should yield by calling the WaitMessage function. A program can call this function at any time, even when running in environments other than Windows environment. If the current environment does not support the function, the function returns and the program continues execution.

Windows suspends the current VM only if there is another VM scheduled to run. If no other VM is ready, the function returns to the program and execution continues. A program should call the function frequently (for example, once during each pass of the program's idle loop) to give Windows ample opportunity to check for other VMs that are ready for execution.

Before calling this function, a program should check that the Interrupt 2Fh address is not zero.

Example

The following example checks for a valid Interrupt 2Fh address, then releases the current VM time slice:

    mov     ax, 352Fh       ; Get Interrupt Vector
    int     21h

    mov     ax, es
    or      ax, bx
    jz      Skip_Idle_Call  ; es:bx is equal to 0:0

    mov     ax, 1680h       ; otherwise, Release Current VM Time-Slice
    int     2Fh
Skip_Idle_Call:


Interrupt 2Fh Function 1681h

mov     ax, 1681h   ; Begin Critical Section
int     2Fh         ; multiplex interrupt

Begin Critical Section (Interrupt 2Fh Function 1681h) prevents Windows from switching execution from the current VM to some other. MS-DOS device drivers and TSRs use this function to prevent a task-switch from occurring.

This function has no parameters.

This function has no return value.

When a virtual machine is in a critical section, no other task will be allowed to run except to service hardware interrupts. For this reason, the critical section should be released using End Critical Section (Interrupt 2Fh Function 1682h) as soon as possible.

See Also

Interrupt 2Fh Function 1682h End Critical Section


Interrupt 2Fh Function 1682h

mov     ax, 1682h   ; End Critical Section
int     2Fh         ; multiplex interrupt

End Critical Section (Interrupt 2Fh Function 1682h) releases the critical section previously started using Begin Critical Section (Interrupt 2Fh Function 1681h). Every call to Begin Critical Section must be followed by a matching call to End Critical Section.

This function has no parameters.

This function has no return value.

See Also

Interrupt 2Fh Function 1681h Begin Critical Section


Interrupt 2Fh Function 1683h

mov     ax, 1683h   ; Get Current Virtual Machine ID
int     2Fh         ; multiplex interrupt

Get Current Virtual Machine ID (Interrupt 2Fh Function 1683h) returns the identifier for the current virtual machine. MS-DOS device drivers, TSRs, and other programs use this function to determine which virtual machine is running. This is especially important for programs that independently manage separate data or execution contexts for separate virtual machines.

This function has no parameters.

The return value is the current virtual-machine identifier in the BX register.

Each virtual machine has a unique, nonzero identifier. Although Windows currently runs in virtual machine 1, programs should not rely on this. Windows assigns the identifier when it creates the virtual machine, and releases the identifier when it destroys the virtual machine. Since Windows may reuse identifiers from previous destroyed virtual machines, programs should monitor changes to virtual machines to ensure no mismatches.


Interrupt 2Fh Function 1684h

mov     bx, [DeviceID]  ; Device identifier

mov     ax, 1684h       ; Get Device Entry Point Address
int     2Fh             ; multiplex interrupt

mov     word ptr [DevAddr], di
mov     word ptr [DevAddr+2], es    ; es:di contains entry point address

Get Device Entry Point Address (Interrupt 2Fh Function 1684h) retrieves the entry point address for a virtual device's service functions. MS-DOS device drivers or TSRs typically use this function to communicate with virtual devices they have explicitly loaded.

DeviceID
Identifies a virtual device. If this value is zero, then the ES:DI registers point to an 8 character space-padded case-sensitive device name (Windows 95).

The return value is the entry-point address contained in the ES:DI register pair if the function is supported. Otherwise, ES:DI contain zero.

Any virtual device can provide service functions to be used by MS-DOS programs. For example, the virtual-display device provides services that the Windows old application program uses to display MS-DOS programs in a window. It is the responsibility of the MS-DOS program to provide the appropriate virtual-device identifier. The function returns a valid address if the virtual device supports the entry point.

MS-DOS programs call the entry point using a far call instruction. The services provided by the virtual device depend on the device. It is the responsibility of the MS-DOS program to set registers to values that are appropriate to the specific virtual device.

For versions of Windows prior to version 3.0, the program must set the ES:DI register pair to zero before calling this function.

Examples

The following example retrieves the entry point address for the virtual device identified by My_Device_ID:

xor     di, di              ; set es:di to zero for version 2.x
mov     es, di
mov     bx, My_Device_ID

mov     ax, 1684h
int     2Fh

mov     ax, es
or      ax, di
jz      API_Is_Not_Supported

The following Windows 95 example retrieves the entry point address for the virtual device identified by specifying an 8-character space padded device name:

xor   bx, bx      ; bx = 0 indicates name-based
les   di, lpName  ; Name of device being queried
int   2Fh

mov   word ptr [DevAddr], di
mov   word ptr [DevAddr+2], es ; ES:DI contains entry point addr
or    di, word ptr [DevAddr+2] ; or contains 0:0 on error
jz    Error


Interrupt 2Fh Function 1685h

mov     bx, [VM_Id]             ; virtual-machine identifier
mov     cx, [Flags]             ; switch conditions

mov     dx, word ptr [Priority+2]
mov     si, word ptr [Priority] ; dx:si contains 32-bit priority boost

mov     es, seg [CallBack]
mov     di, offset [CallBack]   ; es:di contains callback function address

mov     ax, 1685h   ; Switch VMs and CallBack
int     2Fh         ; multiplex interrupt

Switch VMs and CallBack (Interrupt 2Fh Function 1685h) directs Windows to switch to a specific virtual machine and begin execution. After Windows switches, it calls the specified callback function allowing a device driver or TSR to access the data associated with the specified virtual machine. This function is typically used by MS-DOS device drivers and TSRs that support networks, and that need to perform functions in a specific virtual machine.

VM_Id
Identifies the virtual machine to switch to.
Flags
Specifies when to switch. This parameter is a combination of the following bit value.
Bit | Meaning
0 | Set to 1 to wait until interrupts are enabled.
1 | Set to 1 to wait until critical section is released.

All other bits are reserved and must be zero.

Priority
Specifies the priority boost for the virtual machine. It can be one of the following values.
Value | Meaning
Critical_Section_Boost | VM priority is boosted by this value when Begin_Critical_Section is called.
Cur_Run_VM_Boost | Time-slice scheduler boosts each VM in turn by this value to force them to run for their allotted time slice.
High_Pri_Device_Boost | Time critical operations that should not circumvent the critical section boost should use this boost.
Low_Pri_Device_Boost | Used by virtual devices that need an event to be processed in a timely fashion but that are not extremely time critical.
Reserved_High_Boost | Reserved; do not use.
Reserved_Low_Boost | Reserved; do not use.
Time_Critical_Boost | Events that must be processed even when another VM is in a critical section should use this boost. For example, VPICD uses this when simulating hardware interrupts.

The DX register contains the high-order word, the SI register the low-order word.

CallBack
Points to the callback function.

The return value is a cleared carry flag if successful. Otherwise, the function sets the carry flag and sets the AX register to one of the following error values.

Value | Meaning
0001h | Invalid VM ID
0002h | Invalid priority boost
0003h | Invalid flags

Windows calls the callback function as soon as the conditions specified by the Flags parameter are met. This may be before or after Switch VMs and CallBack returns.

The callback function can carry out any action, but must save and restore all registers it modifies. The function must execute an iret instruction to return to Windows. The priority for the virtual machine remains at the level specified by Priority until the callback function executes the iret instruction.

See Also

Interrupt 2Fh Function 1605h Windows Initialization Notification


Interrupt 2Fh Function 1686h

mov     ax, 1686h   ; Detect Interrupt 31h Services
int     2Fh         ; multiplex interrupt

or      ax,0
jz      int31_avail ; ax is zero if interrupt 31h services available

Detect Interrupt 31h Services (Interrupt 2Fh Function 1686h) determines whether a set of protected-mode functions are available for use by protected-mode applications. Applications use the Interrupt 31h services to allocate and manage protected-mode memory.

This function has no parameters.

The return value is zero in the AX register if the Interrupt 31h services are available. Otherwise, the AX register contains a nonzero value.

Both standard- and Windows support the Interrupt 31h services. Interrupt 31h services are only supported for protected-mode programs.


Interrupt 2Fh Function 4000h

mov ax, 4000h             ; Enable VM-Assisted Save/Restore
int 2fh

mov [ModesSupported], al  ; video modes supported while in background

Enable VM-Assisted Save/Restore directs the virtual-display device (VDD) to notify the virtual machine (VM) application whenever the VDD needs to access the video hardware registers. The VDD returns a value specifying the number and type of video modes the VDD supports when the VM application is in the background.

A VM application calls this function during its initialization.

This function has no parameters.

The return value is one of the following values, if successful. Otherwise, the function returns zero in the AL register if virtualization is not supported.

Value | Meaning
01h | No modes virtualized in background.
02h | Only text modes virtualized in background.
03h | Only text and single-plane graphics modes virtualized.
04h | Only text, single-plane, and VGA multiplane graphics modes virtualized.
0FFh | All supported video modes virtualized.

When a VM application calls this function, the VDD disables I/O trapping of unreadable registers. Thereafter, the VDD calls Save Video Register State and Restore Video Register State (Interrupt 2Fh Functions 4005h and 4006h) if it needs to access the video registers. The VM application must provide an appropriate interrupt handler to process these functions.

When an VM application calls this function, the VDD saves the current state of the video registers. The VDD uses this saved state later to restore video registers before it calls Notify Foreground Switch and Restore Video Register State (Interrupt 2Fh Functions 4002h and 4006h).

After a VM application calls Enable VM-Assisted Save/Restore, the VDD no longer saves video memory across screen switches; it becomes the application's responsibility to completely reinitialize video memory after a Notify Foreground Switch request.

See Also

Interrupt 2Fh Function 4002h Notify Foreground Switch,
Interrupt 2Fh Function 4005h Save Video Register State,
Interrupt 2Fh Function 4006h Restore Video Register State


Interrupt 2Fh Function 4001h

mov ax, 4001h   ; Notify Background Switch
int 2fh

Notify Background Switch notifies a VM application that it is being switched to the background. The VM application can carry out any actions, but should do so within 1000ms. This is the amount of time the system waits before switching the application.

This function has no parameters.

This function has no return value.

After switching to the background, the application continues to run unless it attempts to access video memory. If the video adapter is in a video mode that the virtual display device (VDD) does not support in the background, the VDD freezes the application until the application can be switched back to the foreground.

VM applications that have called Enable VM-Assisted Save/Restore (Interrupt 2Fh Function 4000h) should avoid accessing video memory and registers to avoid being frozen. Applications that have not called Enable VM-Assisted Save/Restore, call access video memory and registers since the VDD saves theses after this function returns.

See Also

Interrupt 2Fh Function 4000h Enable VM-Assisted Save/Restore,
Interrupt 2Fh Function 4002h Notify Foreground Switch


Interrupt 2Fh Function 4002h

mov ax, 4002h       ; Notify Foreground Switch
int 2fh

Notify Foreground Switch notifies a VM application that it has been switched to the foreground and can now access the video memory and registers without being frozen.

The virtual-display device (VDD) calls this function.

This function has no parameters.

This function has no return value.

If the VM application has called Enable VM-Assisted Save/Restore (Interrupt 2Fh Function 4000h), VDD restores the video registers to their state prior to the call to Enable VM-Assisted Save/Restore; the application is responsible for restoring video memory. If the VM application has not called Enable VM-Assisted Save/Restore (Interrupt 2Fh Function 4000h), the VDD automatically restores both video memory and registers.

Under certain error conditions, the VDD may call this function without calling a corresponding Notify Background Switch (Interrupt 2Fh Function 4001h).

See Also

Interrupt 2Fh Function 4000h Enable VM-Assisted Save/Restore,
Interrupt 2Fh Function 4001h Notify Background Switch


Interrupt 2Fh Function 4003h

mov ax, 4003h       ; Enter Critical Section
int 2fh

Enter Critical Section notifies the virtual-display device that the VM application has entered a critical section and cannot respond to Save Video Register State (Interrupt 2Fh Function 4005h).

A VM application calls this function when it has started critical section processing.

This function has no parameters.

This function has no return value.

After the VM application enters the critical section, the virtual-display device postpones calling Save Video Register State for up to 1000ms or until the VM application calls Exit Critical Section (Interrupt 2Fh Function 4004h), whichever comes first.

If time elapses without the VM application calling Exit Critical Section, the virtual-display device reprograms the video hardware anyway and, when its operation is complete, calls Notify Foreground Switch (Interrupt 2Fh Function 4002h) in an attempt to reinitialize the application properly.

See Also

Interrupt 2Fh Function 4002h Notify Foreground Switch,
Interrupt 2Fh Function 4004h Exit Critical Section,
Interrupt 2Fh Function 4005h Save Video Register State


Interrupt 2Fh Function 4004h

mov ax, 4004h       ; Exit Critical Section
int 2fh

Exit Critical Section notifies the virtual-display device that a VM application has completed a critical section and can now respond to Save Video Register State (Interrupt 2Fh Function 4005h).

A VM application calls this function when it has completed critical section processing.

This function has no parameters.

This function has no return value.

Calls to Exit Critical Section not preceded by a corresponding call to Enter Critical Section (Interrupt 2Fh Function 4003h) are ignored.

See Also

Interrupt 2Fh Function 4003h Enter Critical Section,
Interrupt 2Fh Function 4005h Save Video Register State


Interrupt 2Fh Function 4005h

mov ax, 4005h       ; Save Video Register State
int 2fh

The Save Video Register State function notifies VM applications that the virtual-display device (VDD) requires access to the video hardware registers. The VDD calls this function, for example, when preparing to copy the entire screen to the clipboard.

This function has no parameters.

This function has no return value.

The VDD calls this function only if the VM application has called Enable VM-Assisted Save/Restore (Interrupt 2Fh Function 4000h). VM applications that receive Save Video Register State must save any data necessary to restore the current video state and must return within 1000ms. If the application fails to return in time, the virtual-display device accesses the video hardware anyway. After accessing the video hardware registers, the VDD calls Restore Video Register State (Interrupt 2Fh Function 4006h) to notify the application that it can restore its video state.

The VDD calls Save Video Register State only at times when the hardware must be reprogrammed for what are essentially brief and nonvisible operations. For example, the VDD does not call this function prior to calling Notify Background Switch (Interrupt 2Fh Function 4001h).

See Also

Interrupt 2Fh Function 4000h Enable VM-Assisted Save/Restore,
Interrupt 2Fh Function 4001h Notify Background Switch,
Interrupt 2Fh Function 4006h Restore Video Register State


Interrupt 2Fh Function 4006h

mov ax, 4006h   ; Restore Video Register State
int 2fh

Restore Video Register State notifies a VM application that the virtual-display device (VDD) has relinquished its access to the video registers. The VM application should restore the video registers to any state necessary to continue uninterrupted foreground operation.

This function has no parameters.

This function has no return value.

The VDD calls this function only if the VM application has called Enable VM-Assisted Save/Restore (Interrupt 2Fh Function 4000h). Before calling this function, the VDD restores any registers it modified to the values they had when the VM application originally called Enable VM-Assisted Save/Restore. In other words, every register is guaranteed to be either unchanged or reset to a previous state; precisely which registers may be reset is undefined, but the set is restricted to those Sequencer and Graphics Controller registers that do not affect the display.

See Also

Interrupt 2Fh Function 4000h Enable VM-Assisted Save/Restore


Interrupt 2Fh Function 4007h

mov ax, 4007h       ; Disable VM-Assisted Save/Restore
int 2fh

Disable VM-Assisted Save/Restore directs the virtual-display device (VDD) to discontinue notifying the VM application when it needs access to video registers.

VM applications call this function when they terminate.

This function has no parameters.

This function has no return value.

This function directs the VDD to restore I/O trapping of unreadable registers and to discontinue calling Save Video Register State and Restore Video Register State (Interrupt 2Fh Functions 4005h and 4006h) when it needs access to the registers. Furthermore, the VDD ignores any subsequent calls to Enter Critical Section and Exit Critical Section (Interrupt 2Fh Functions 4003h and 4004h).

This function does not disable Notify Background Switch and Notify Foreground Switch (Interrupt 2Fh Functions 4001h and 4002h).

See Also

Interrupt 2Fh Function 4001h Notify Background Switch,
Interrupt 2Fh Function 4002h Notify Foreground Switch,
Interrupt 2Fh Function 4003h Enter Critical Section,
Interrupt 2Fh Function 4004h Exit Critical Section,
Interrupt 2Fh Function 4005h Save Video Register State,
Interrupt 2Fh Function 4006h Restore Video Register State


Structures

The following is a listing of structures used by the Interrupt 2Fh notification functions.


Win386_Startup_Info_Struc

Win386_Startup_Info_Struc STRUC
SIS_Version                     db      3, 0
SIS_Next_Dev_Ptr                dd      ?
SIS_Virt_Dev_File_Ptr           dd      0
SIS_Reference_Data              dd      ?
SIS_Instance_Data_Ptr           dd      0
SIS_Opt_Instance_Data_Ptr       dd      0
Win386_Startup_Info_Struc ENDS

The Win386_Startup_Info_Struc structure contains information that Windows uses to prepare an MS-DOS device driver or TSR program for operation with Windows.

SIS_Version
Specifies the version number of the structure. Windows uses this member to determine the size of the structure. This member should contain 3 in the low-order byte and 10 in the high-order byte to indicate that it is version 3.1.
SIS_Next_Dev_Ptr
Points to the next structure in the list. The address of the next structure must be supplied by the next handler in the Interrupt 2Fh chain. A driver or TSR calls the next handler, then sets this member to the address returned by the handler in the ES:BX register pair.
SIS_Virt_Dev_File_Ptr
Points to a null-terminated string that contains the name of a Windows virtual device file. MS-DOS devices such as networks use this to force a special Windows virtual device to be loaded. If this member is zero, no device is loaded.
SIS_Reference_Data
Specifies reference data for the virtual device. This member, used only when SIS_Virt_Dev_File_Ptr is nonzero, is passed to the virtual device when it is initialized. The member can contain any value and often contains a pointer to some device-specific structure.
SIS_Instance_Data_Ptr
Points to a list of data to be instanced, that is, allocated uniquely for each new virtual machine. If the member is zero, then no data is instanced. Each entry in the list is an Instance_Item_Struc structure. The list is terminated with a 32-bit zero.
SIS_Opt_Instance_Data_Ptr
Points to a list of data to be optionally instanced. Available only if SIS_Version is 4.0.

See Also

Interrupt 2Fh Function 1605h Windows Initialization Notification


Instance_Item_Struc

Instance_Item_Struc STRUC
    IIS_Ptr     dd  ?
    IIS_Size    dw  ?
Instance_Item_Struc ENDS

The Instance_Item_Struc structure specifies the starting address and size of a block of instance data.

IIS_Ptr
Points to the starting address of a block of instance data.
IIS_Size
Specifies the size (in bytes) of the block of instance data pointed to by the IIS_Ptr member.


Message Macros

This section describes the message macros and explains how to use the macros with your VxD. Message macros let you create text strings for display by your VxD that can easily be translated without requiring recompilation of the VxD. Message macros make the job of localizing your VxD for foreign-language markets easier.


Message Declarations

You declare messages by using the message declaration macros. These macros specify the data segment in which the messages are to be defined as well as define the actual message text and the message identifiers used to uniquely identify messages.

You typically place message declaration macros in one or more include files, called message declaration files. To access the messages from your VxD source files, you include the message declaration files directly into your VxD sources. Including the files does not cause the assembler to generate code for the message text. Instead, the assembler assigns unique integer values to the message identifiers. You can then use the message identifiers, in conjunction with the message usage macros, to identify the specific message to process or display.

For each language you intend to support, you must create a unique message declaration file or set of files. The order of the message declarations and names of the message identifiers must be exactly the same from language to language. The VxD relies on the declaration order to locate the appropriate messages.


Message Processing

You process messages by using the message usage macros. These macros let you retrieve the addresses of the message strings and optionally modify the content of the strings by replacing parameter placeholders with current values. In general, you must process messages to prepare them for displaying.

Messages that are intended to be displayed as declared are called static messages. You process a static message by simply retrieving the address of the message using the GET_MESSAGE_PTR macro.

Messages that contain parameter placeholders are intended to be modified before being displayed. A parameter placeholder is a character sequence that starts with a percent sign (%) and includes a parameter number and a format code. You process such messages by using the PUSH_SPRINTF macro, supplying the message identifier and the values to modify the string with. The macro uses the original message to create a new string in which each parameter placeholder is replaced with the corresponding value. The macro places the new string on the stack and returns the address of the string.

You should display any string you create using PUSH_SPRINTF as soon as possible, then remove the string by using the POP_SPRINTF macro. If necessary, you can retrieve the length of the new string by using the PUSHED_SPRINTF_LENGTH macro, but you must do this before push any other item on the stack and certainly before removing the string from the stack.

See Also

GET_MESSAGE_PTR, POP_SPRINTF, PUSH_SPRINTF, PUSHED_SPRINTF_LENGTH


Message Table File

The message table file contains the assembled strings used by the VxD. To adapt a VxD for a given country/region, you create and assemble a message table source file. The file includes the VMM.INC and MSGMACRO.INC files and sets the constant CREATE_MESSAGE to TRUE before including the message declaration file. Because the message macros do not support creating a message table from a source file that contains references, your message table source file must not include references to the macros.

Note VxD access to the message table files is not currently implemented.


Using Message Macros

This section explains how to perform the following tasks:

  • Declare messages.
  • Process messages.
  • Build a message table file.

To use the message macros, you must include both the VMM.INC and MSGMACRO.INC files in your VxD source files.


Declaring Messages

You declare messages using the DECLARE_MESSAGE and LONG_MESSAGE macros to specify the message text and identifiers, and by using the VxD_IMESSAGE_SEG, VxD_PMESSAGE_SEG, and VXD_MESSAGE_SEG macros to specify which data segment receives the message data. The following example shows how to declare messages for a VxD:

; Message table for initialization data segment

VxD_IMESSAGE_SEG
    DECLARE_MESSAGE <MSG_BootErrorMsg>, \
        <"Error interrupt conflict, please reinstall">
VxD_IMESSAGE_ENDS

; Messages table for locked data segment

VxD_MESSAGE_SEG
    DECLARE_MESSAGE <MSG_DiskPlease>, \
        <"Please reinsert the original disk.">
    DECLARE_MESSAGE <MSG_CantOpen>, \
        <'Error: Can't open file "%0s" on drive "%1s".'>
    ; A long message
    LONG_MESSAGE_START <MSG_MyLongMessage>
        LONG_MESSAGE <"Messages too long to fit on one line ">
        LONG_MESSAGE <"can be divided among several lines.", 10, 13>
        LONG_MESSAGE <"You can include control characters, such as ">
        LONG_MESSAGE <"new line and carriage return", 10, 13>
    LONG_MESSAGE_END
VxD_MESSAGE_ENDS

This example declares four messages. The MSG_BootErrorMsg, MSG_DiskPlease, and MSG_MyLongMessage messages are static messages. The MS_CantOpen message contains two parameter placeholders. The message macros automatically append a terminating null byte. Not illustrated is a pageable message segment, which uses the PMESSAGE type.

See Also

DECLARE_MESSAGE, LONG_MESSAGE, VXD_IMESSAGE_SEG, VXD_MESSAGE_SEG


Processing Messages

You process and prepare static messages for display by using the GET_MESSAGE_PTR macro. The following example shows how to retrieve the addresses of two static messages declared in the file USAMSG.INC:

include usamsg.inc

GET_MESSAGE_PTR MSG_BootErrorMsg eax
  ; address of MSG_BootErrorMsg message now in eax

GET_MESSAGE_PTR MSG_DiskPlease edx
  ; address of MSG_DiskPlease message now in edx

You process messages containing parameter placeholders by using the PUSH_SPRINTF macro. Because this macro places a new string on the stack, you must use the POP_SPRINTF macro to remove the string from the stack after displaying it.

Of course, since the message is on the stack, it goes away once you call POP_SPRINTF. A common error is passing the pointer to a pushed string to another procedure (such as SHELL_Message), then popping the string before the called procedure is finished with it. If you need a message to be placed somewhere other than the stack, use the LOCALIZED_SPRINTF macro instead.

The following example shows how to process the MSG_CantOpen message:

include usamsg.inc

PUSH_SPRINTF MSG_CantOpen, eax, <offset32 DriveBuf>
  ; address of new string now in eax

PUSHED_SPRINTF_LENGTH ebx
  ; string length now in ebx

; Call output function here

POP_SPRINTF     ; Remove the string from stack

In this example, the EAX register contains the address of a null-terminated string specifying a filename and the DriveBuf variable contains a null terminated string specifying the drive letter. The parameter placeholders are assumed to be %0s and %1s. The macro creates a new string by replacing the parameter placeholders in the original message with the filename and driver letter. The macro leaves the new string on the stacks copies its address to the EAX register.

See Also

GET_MESSAGE_PTR, POP_SPRINTF, PUSH_SPRINTF, PUSHED_SPRINTF_LENGTH


Building the Message Table File

You build a message table file by including your message declaration files into a message source file that declares the CREATE_MESSAGES constant to be TRUE. The following example shows the content of the source file that can be used to create a message table file.

.386

INCLUDE VMM.INC
include MSGMACRO.INC
CREATE_MESSAGES EQU TRUE

include usamsg.inc    ; contains message declarations

END

In this example, the USAMSG.INC file contains the message declarations for US English messages. Assembling this file creates the message table file for use with the VxD executable to be shipped to the US market.


Reference

This section provides detailed reference information for the message macros. The information is separated into the following functional groups.

Group | Elements
Message Declaration Macros | DECLARE_MESSAGE, LONG_MESSAGE, LONG_MESSAGE_END, LONG_MESSAGE_START, VxD_IMESSAGE_ENDS, VxD_IMESSAGE_SEG, VxD_MESSAGE_ENDS, VxD_MESSAGE_SEG
Message Usage Macros | GET_MESSAGE_PTR, POP_SPRINTF, PUSH_SPRINTF, PUSHED_SPRINTF_LENGTH


Message Declaration Macros

The following contains information on macros for declaring messages.


DECLARE_MESSAGE

DECLARE_MESSAGE MsgIdentifier, String

Creates a single message having the given message identifier.

This macro has no return value.

MsgIdentifier
Message identifier. This must be a unique constant name.
String
Null-terminated string specifying the message. The string may contain parameter placeholders as described in PUSH_SPRINTF.

See Also

PUSH_SPRINTF


LONG_MESSAGE

LONG_MESSAGE String

Declares a portion of a long message. This macro can be used consecutively any number of times, but all uses for a particular string must be contained within a single long message block, as defined by a LONG_MESSAGE_START and LONG_MESSAGE_END macro pair.

This macro has no return value.

String
Message string.

See Also

LONG_MESSAGE_END, LONG_MESSAGE_START


LONG_MESSAGE_END

LONG_MESSAGE_END MsgIdentifier

Completes the message started with the LONG_MESSAGE_START macro.

This macro has no return value.

MsgIdentifier
Message identifier. This must be the same name given with the matching LONG_MESSAGE_START macro.

See Also

LONG_MESSAGE_START


LONG_MESSAGE_START

LONG_MESSAGE_START MsgIdentifier

Starts a long message declaration block. The block must end with a LONG_MESSAGE_END macro and may contain one or more LONG_MESSAGE macros.

This macro has no return value.

MsgIdentifier
Message identifier. This must be a unique constant name.

See Also

LONG_MESSAGE, LONG_MESSAGE_END


VxD_IMESSAGE_ENDS

VxD_IMESSAGE_ENDS

Ends the message table in the initialization data segment. Subsequent VXD_IMESSAGE_SEG macros are not valid.

See Also

VXD_IMESSAGE_SEG


VxD_IMESSAGE_SEG

VxD_IMESSAGE_SEG

Starts a message table in the initialization data segment of a VxD. The messages in the table must be defined using DECLARE_MESSAGE and LONG_MESSAGE macros. These messages are discarded after the VxD has been initialized. The VxD_IMESSAGE_ENDS macro must be used to end the message table.

See Also

VXD_IMESSAGE_ENDS


VXD_MESSAGE_ENDS

VXD_MESSAGE_ENDS

Ends the message table in the locked data segment. Subsequent VXD_MESSAGE_SEG macros are not valid.

See Also

VXD_MESSAGE_SEG


VXD_MESSAGE_SEG

VXD_MESSAGE_SEG

Starts a message table in the locked data segment of a VxD. The messages in the table must be defined using DECLARE_MESSAGE and LONG_MESSAGE macros. The VxD_MESSAGE_ENDS macro must be used to end the message table.

See Also

DECLARE_MESSAGE, LONG_MESSAGE, VXD_IMESSAGE_ENDS


VXD_PMESSAGE_ENDS

VXD_PMESSAGE_ENDS

Ends the message table in the pageable data segment. Subsequent VXD_PMESSAGE_SEG macros are not valid.

See Also

VXD_MESSAGE_SEG


VXD_PMESSAGE_SEG

VXD_PMESSAGE_SEG

Starts a message table in the pageable data segment of a VxD. The messages in the table must be defined using DECLARE_MESSAGE and LONG_MESSAGE macros. The VxD_PMESSAGE_ENDS macro must be used to end the message table.

See Also

DECLARE_MESSAGE, LONG_MESSAGE, VXD_IMESSAGE_ENDS


Message Usage Macros

The following is a list of macros for using messages.


GET_MESSAGE_PTR

GET_MESSAGE_PTR MsgIdentifier, Reg

Returns the address of the given message. The macro carries out no other processing.

The return value is the message address in the given register.

MsgIdentifier
Message identifier of the message to retrieve.
Reg
Name of register that receives the message address.

A register name can also be given for the MsgIdentifier parameter. If a register name is given, the register value is checked at runtime to determine which table to look in for the message. Because this requires additional code to support, this register-based version of the macro should be avoided.

The overhead of the register-based version can be avoided by an alternate form of the GET_MESSAGE_PTR macro:

Get_Message_Ptr MsgIdentifier, Reg1, Reg2

This alternative form places into Reg1 a pointer to the message string whose identifier is MsgIdentifier + Reg2. No range checking is performed; the value MsgIdentifier + Reg2 must be of the same message type as MsgIdentifier. For example, if you have a series of three messages, declared contiguously:

VxD_MESSAGE_SEG
DECLARE_MESSAGE MsgFirst, <"First message">
DECLARE_MESSAGE MsgSecond, <"Second Message">
DECLARE_MESSAGE MsgThird, <"Third message">
VxD_MESSAGE_ENDS

then the line:

GET_MESSAGE_PTR MsgFirst, eax, esi

would load into the EAX register a pointer to MsgFirst, if ESI = 0, a pointer to MsgSecond if ESI = 1, and a pointer to MsgThird if ESI = 2. Any other value for ESI is an error and will load garbage or possibly even page fault.


LOCALIZED_SPRINTF

LOCALIZED_SPRINTF pOutBuf, MsgIdentifier, Param1, Param2, ..., ParamX

Acts the same way as PUSH_SPRINTF except that the generated string is placed in the buffer specified by pOutBuf instead of being pushed onto the stack. Uses EAX.

This does not have a return value.

pOutBuf
Location of output buffer.
MsgIdentifier
Message identifier of the message to process.
Parm1, Parm2, through ParmX
Parameter values.

Currently, there is no way to determine the necessary output buffer size; you just have to hope that the generated message fits. This may be remedied in a future version of Windows.


POP_SPRINTF

POP_SPRINTF

Pops a string off the stack. The string must have been previously pushed on the stack by the PUSH_SPRINTF macro. The address of the string is not longer valid and must not be used.

This does not have a return value.

See Also

PUSH_SPRINTF


PUSH_SPRINTF

PUSH_SPRINTF MsgIdentifier, Param1, Param2, ..., ParamX

Processes the given message and parameters to create a new string. Parameter placeholders in the original message are replaced in the new string with the corresponding parameter values. This macro places the new string on the stack.

The return value is the address of the new string in the EAX register.

MsgIdentifier
Message identifier of the message to process.
Parm1, Parm2, through ParmX
Parameter values. The number of parameters depends on the highest parameter number given in the parameter placeholders in the original message.

A parameter placeholder consists of a percent sign (%), a parameter number, and a format character.

A parameter number can be any integer value in the range zero to 9. This number identifies which parameter passed to the PUSH_SPRINTF macro replaces the given placeholder. This means the order in which parameter values are inserted is not determined order in which they are passed to the macro. Instead, the parameter number in the parameter placeholders determine where a given parameter is inserted and how often it is inserted.

The format character specifies the format of the parameter to be displayed. It can be one of these letters:

s | Null terminated string.
u | 16-bit unsigned decimal integer in the range zero to 999.
x | 16-bit unsigned hexadecimal integer.

The parameter type must match the formatting specified by the corresponding parameter placeholder.


PUSHED_SPRINTF_LENGTH

PUSHED_SPRINTF_LENGTH Reg

Returns the length, in bytes, of the string most recently pushed on the stack. This macro is not valid if any other item has been pushed on the stack since the most recent string. This macro is not valid and must not be used if the string has already been popped off the stack.

The return value is the string length in the given register. The length does not include the terminating null character.

Reg
Name of register that receives the string length.


Registering Statistics with System Monitor

System Monitor is a tool in Windows® 95 that graphically displays a number of system performance statistics. This documentation describes how other drivers can report data to the System Monitor.

Any VxD can report statistics that will be displayed in the System Monitor user interface. To do so, the VxD must do the following:

  1. Register itself as a stat server by calling the PERF_Server_Register (usually done at VxD load time)
  2. Register one or more statistics by calling PERF_Server_Add_Stat for each statistic (usually done immediately after calling PERF_Server_Register)
  3. Unregister the stat server when the VxD unloads

Both static and dynamic VxDs may use the service; stat servers and statistics may be added and removed at any time.

Statistics are obtained in one of two ways, depending on information passed in the PERF_Server_Add_Stat call. Normally the pst0_pStatFunc contains a ring 0 pointer to a DWORD that contains the data to be displayed. The PERF VxD simply dereferences the pointer and retrieves the data whenever it is requested by the UI client. This places the lowest overhead on the stat server VxD and on the system. If the PSTF_FUNCPTR flag is set, however, the pst0_pStatFunc member should be a ring 0 pointer to a function with no parameters that returns the data value in EAX. This is useful if data is expensive to calculate; then the data is only calculated when requested.

Another useful flag in stat creation is PSTF_RATE, which causes the client to automatically differentiate the reported value by time. For instance, if a driver wishes to report throughput in bytes/sec, it can keep a counter of the bytes it processes in a DWORD and increment the DWORD whenever it processes data. If the PSTF_RATE flag is set then UI clients will divide by elapsed time to arrive at bytes/sec. This is also useful because it allows multiple clients to poll for data at different times and always get correct data.

The perf.h header file and example code example.asm (as shown in the following) illustrate the details of how to implement this.

/*********************************************************************
 *   (C) Copyright MICROSOFT Corp., 1993-1995
 *   Title:     PERF.H - Include file for perf monitor
 *   Version:   1.00
 *   Date:
 *   Author:  FCF
 *----------------------------------------------------------------------
 *   Change log:
 *   DATE        REV DESCRIPTION
 *   ----------- --- ---------------------------------------------------
 */

/* defines */

#define MAXNAMELEN      50  /* maximum number of characters in
                   service name, stat name, or key names */
#define MAXCOMPLEXSUBSTAT  8  /* maximum number of stats making
                   up a complex stat */

/* structures and flags used for the ring-0 interface */

struct perf_server_0 {
    unsigned long  psrv0_Level;  /* Must be zero for this level */
    unsigned long  psrv0_Flags;
    char          *psrv0_pszServerName;
    char         *psrv0_pszServerNodeName;
    void         *psrv0_pControlFunc;
};

struct perf_stat_0 {
    unsigned long  pst0_Level;  /* Must be zero for this level */
    unsigned long  pst0_Flags;
    char         *pst0_pszStatName;
    char         *pst0_pszStatNodeName;
    char         *pst0_reserved;      // must be NULL
    char         *pst0_pszStatDescription;
    void         *pst0_pStatFunc;
  unsigned long  pst0_ScaleFactor;  // set PSTF_FACTOR_xxx flag to use
};

/* Values for psrv0_Flags follow */

/* Values for pst0_Flags follow */

/* pst0_pStatFunc points either directly to data (always a DWORD for now) */
/* or, if PSTF_FUNCPTR_BIT is set, to a _cdecl function.  This function   */
/* accepts a stat handle as it's argument and returns the stat in eax     */

#define PSTF_FUNCPTR    0x00000001

The data referenced by this stat is always a counter, for example, number of bytes read. It is up to the client to differentiate this into a rate. If PSTF_RATE is set, then the text associated with this stat assumes that the stat will be differentiated with respect to time. It's possible that two stats will refer to the same data - one with this bit set and one without, with help text appropriate for each.

#define PSTF_COUNT    0x00000000
#define PSTF_RATE    0x00000002

/* If either of these flags are set, then the output will be scaled
   (either multiplied or divided) by pst0_ScaleFactor.  */
#define PSTF_FACTOR_MULTIPLY  0x00000040
#define PSTF_FACTOR_DIVIDE    0x00000080

/* XLATOFF */

unsigned long PERF_Server_Register( struct perf_server_0 * );
void PERF_Server_Deregister( unsigned long hReg );
unsigned long PERF_Server_Add_Stat( unsigned long hReg, struct perf_stat_0 );
void PERF_Server_Remove_Stat( unsigned long hStat );

/* XLATON */

Control messages sent to perf server's control function. The control function is optional, set it to NULL if you don't want any control messages. Perf servers are free to ignore any messages they want. Control functions take two DWORD parameters; a message (dwMsg) and a DWORD of message-dependent data (dwData).

The following defines are values for dwMsg:

#define PMSG_START_STAT        0x11
#define PMSG_STOP_STAT        0x12

PMSG_START_STAT: Notifies that a perf client is going to start watching this stat. dwData contains the stat handle.

PMSG_STOP_STAT: Notifies that a perf client is no longer watching this stat. dwData contains the stat handle. Stats that are expensive to maintain should only be kept while some- one is watching them. Note that there can be more than one stat client, so do not simply stop keeping track of a stat if you receive a PMSG_STOP_STAT. The server should keep a counter of the number of PMSG_START_STAT's it receives for a particular counter, decrement it for each PMSG_STOP_STAT and stop keeping track of the stat when the counter reaches zero. Most stats are trivial to maintain and just involve incrementing a counter. For stats like these, perf servers should always increment the counter and ignore messages to start and stop.

/* ASM

; Ring-0 macros to aid stat registration

Reg_Perf_Srv MACRO level:REQ, flags:REQ, servername:REQ, nodename:REQ, controlfunc:REQ
  local  nothere
  VxDCall  PERF_Get_Version
  or  eax, eax
  jz  nothere

  IF (OPATTR(controlfunc)) AND 00010000y   ;; register
    push  controlfunc
  ELSE
    push  OFFSET32 controlfunc
  ENDIF

  IF (OPATTR(nodename)) AND 00010000y    ;; register
    push  nodename
  ELSE
    push  OFFSET32 nodename
  ENDIF

  IF (OPATTR(servername)) AND 00010000y    ;; register
    push  servername
  ELSE
    push  OFFSET32 servername
  ENDIF

  push  flags
        push  level
  push  esp
  VxDCall  PERF_Server_Register
  add  esp, 6*4
nothere:
  ENDM

Reg_Perf_Stat MACRO srvhandle:REQ, level:REQ, flags:REQ, name:REQ, nodename:REQ, reserved:REQ, desc:REQ, func:REQ
  IF (OPATTR(func)) AND 00010000y    ;; register
    push  func
  ELSE
    push  OFFSET32 func
  ENDIF

  IF (OPATTR(desc)) AND 00010000y    ;; register
    push  desc
  ELSE
    push  OFFSET32 desc
  ENDIF

  IF (OPATTR(reserved)) AND 00010000y  ;; register
    push  reserved
  ELSE
    push  OFFSET32 reserved
  ENDIF

  IF (OPATTR(nodename)) AND 00010000y  ;; register
    push  nodename
  ELSE
    push  OFFSET32 nodename
  ENDIF

  IF (OPATTR(name)) AND 00010000y    ;; register
    push  name
  ELSE
    push  OFFSET32 name
  ENDIF

  push  flags
  push  level
  push  esp
  push  srvhandle
  VxDCall  PERF_Server_Add_Stat
  add  esp, 9*4
  ENDM

Begin_Service_Table PERF
PERF_Service PERF_Get_Version, LOCAL
PERF_Service PERF_Server_Register, LOCAL
PERF_Service PERF_Server_Deregister, LOCAL
PERF_Service PERF_Server_Add_Stat, LOCAL
PERF_Service PERF_Server_Remove_Stat, LOCAL
End_Service_Table PERF

*/

#define HKEY_PERF_ROOT      HKEY_LOCAL_MACHINE
#define PERF_REG_KEY      "System\\CurrentControlSet\\Control\\PerfStats\\Enum"
#define PERF_REG_OTHER_KEY    "System\\CurrentControlSet\\Control\\PerfStats\\Other"
#define PERF_REG_NAME_SRV_NAME    "Name"
#define PERF_REG_NAME_VXD_NAME    "VxDName"
#define PERF_REG_NAME_STAT_NAME    "Name"
#define PERF_REG_NAME_STAT_COMPLEX  "Complex"
#define PERF_REG_NAME_STAT_DESC    "Description"
#define PERF_REG_NAME_STAT_DIFF    "Differentiate"

#define PERF_REG_VAL_STAT_TRUE    "TRUE"
#define PERF_REG_VAL_STAT_FALSE    "FALSE"
#define PERF_STAT_PREFIX      "STAT"

/* complex stat defines */

#define PSTF_COMPLEX    0x00000100

PSTF_COMPLEX specifies that this is a complex stat. Complex stats have no data of their own, they specify a list of handles to other stats. The values of the other stats in the list are retrieved and added together and the resulting sum displayed. The pst0_pStatFunc member points to an array of stat handles, where the handle values were obtained by previous calls to PERF_Server_Add_Stat. The array is terminated by a NULL handle.

  PAGE 58,132
;***************************************************************
TITLE Example.Asm - VxD performance gathering component
;***************************************************************

  .386p

;***************************************************************
;            I N C L U D E S
;***************************************************************

  .XLIST
  INCLUDE VMM.Inc
  INCLUDE Debug.Inc
  INCLUDE OptTest.Inc

  Create_FakeStat_Service_Table EQU VMM_TRUE

  INCLUDE Perf.Inc
        INCLUDE VWin32.Inc
  INCLUDE WinError.Inc

  .LIST

;**********************************************************************
;    V I R T U A L  D E V I C E   D E C L A R A T I O N
;**********************************************************************

Begin_Service_Table FAKESTAT
FAKESTAT_Service FAKESTAT_Get_Version, LOCAL
End_Service_Table FAKESTAT

FakeStat_Device_ID EQU 44h
FakeStat_Init_Order EQU 06500000h

Declare_Virtual_Device FAKESTAT, 4, 00h, FakeStat_Control, FakeStat_Device_ID, \
           FakeStat_Init_Order, ,

;**********************************************************************
;            E Q U A T E S
;**********************************************************************

;**********************************************************************
;**********************************************************************

VxD_IDATA_SEG
  ; NOTE: Strings are not int'l correct for brevity of this example.
        ; Windows 95 VxDs should use message tables and message macros
        ; for strings.

        ; UI names
  szSrvName    db  "Fake Performance Data",0
        szStatNameRead    db  "Fake Reads/sec",0
        szStatNameWrite    db  "Fake Writes/sec",0
        szStatNameTotal    db  "Total Fake Stuff/sec",0

  ; stat explanations (optional)
        szReadDesc    db  "Fake stuff read per second.",0
        szWriteDesc    db  "Fake stuff written per second.",0
        szTotalDesc    db  "Fake stuff read and written per second.",0

  ; registry key names
        szStatSrvKeyname  db  "FAKE",0
  szStatKeynameRead  db  "FReadSec",0
  szStatKeynameWrite  db  "FWriteSec",0
  szStatKeynameTotal  db  "FTotalSec",0

VxD_IDATA_ENDS

VxD_PAGEABLE_DATA_SEG
  ALIGN 4
  hPerfID    DWORD   0  ; perf server handle

        dwReadCounter  DWORD  1024  ; perf stat counters
        dwWriteCounter  DWORD  4096

VxD_PAGEABLE_DATA_ENDS

VxD_LOCKED_DATA_SEG

VxD_LOCKED_DATA_ENDS

;**********************************************************************

  .SALL

  PAGE
;**********************************************************************
;      R E A L   M O D E   I N I T  C O D E
;**********************************************************************

VxD_REAL_INIT_SEG

BeginProc FakeStat_Real_Init

  xor  si, si

  test  bx, Duplicate_From_INT2F OR Duplicate_Device_ID
  jnz  SHORT RI_Abort_Load

  xor  bx, bx
  xor  edx, edx
  mov  ax, Device_Load_Ok
  ret

RI_Abort_Load:
  xor  bx, bx
  mov  ax, Abort_Device_Load + No_Fail_Message
  ret

EndProc FakeStat_Real_Init

VxD_REAL_INIT_ENDS

  PAGE
;**********************************************************************
;         P R O T E C T E D   M O D E   I N I T   C O D E
;**********************************************************************

VxD_ICODE_SEG

BeginProc FAKESTAT_Sys_Critical_Init

  clc
  ret

EndProc FAKESTAT_Sys_Critical_Init

BeginProc FAKESTAT_Device_Init
        LocalVar hStatNull, DWORD
        LocalVar hStat2, DWORD
  LocalVar hStat1, DWORD
  EnterProc

ifdef DEBUG
  Trace_Out "FAKESTAT: Loading"
endif

        ; register us as a perf client
  Reg_Perf_Srv 0,PSTF_RATE,szSrvName,szStatSrvKeyname,FakeStat_StatControl
  or eax,eax
        jz fdi10
  mov hPerfId,eax

  ; register 1st stat  (reads/sec)
        Reg_Perf_Stat eax,0,PSTF_RATE,szStatNameRead,szStatKeynameRead,0,szReadDesc,dwReadCounter
  mov [hStat1],eax

  ; register 2nd stat  (writes/sec)
  mov eax,hPerfID
        Reg_Perf_Stat eax,0,PSTF_RATE,szStatNameWrite,szStatKeynameWrite,0,szWriteDesc,dwWriteCounter
  mov [hStat2],eax

        ; register 3rd stat  (total/sec)
        ; this is a complex stat made up of reads/sec + writes/sec--
        ; specified by list of stats (hStat1 & hStat2)
        mov eax,hPerfID
        mov [hStatNull],0  ; null-terminate list of stats
        lea edx,hStat1
        Reg_Perf_Stat eax,0,PSTF_RATE | PSTF_COMPLEX,szStatNameTotal,szStatKeynameTotal,0,szTotalDesc,edx

fdi10:
  clc
        LeaveProc
  Return

EndProc FAKESTAT_Device_Init

VxD_ICODE_ENDS

  PAGE
;**********************************************************************
;        P R O T E C T E D   M O D E   R E S I D E N T   C O D E
;**********************************************************************

VxD_LOCKED_CODE_SEG

BeginProc FakeStat_Control

  Control_Dispatch Sys_Critical_Init,   FAKESTAT_Sys_Critical_Init
  Control_Dispatch Device_Init,    FAKESTAT_Device_Init
        Control_Dispatch Sys_Dynamic_Device_Init, FAKESTAT_Device_Init
        Control_Dispatch Sys_Dynamic_Device_Exit, FAKESTAT_System_Exit
  Control_Dispatch System_Exit,    FAKESTAT_System_Exit

IFDEF DEBUG
  Control_Dispatch Debug_Query, FAKESTAT_Debug_Query
ENDIF

  clc
  ret

EndProc FakeStat_Control

VxD_LOCKED_CODE_ENDS
VxD_PAGEABLE_CODE_SEG

;**********************************************************************
;           S E R V I C E S
;**********************************************************************

BeginProc FAKESTAT_System_Exit

  ; De-register perf client (this will also de-register stats)
ifdef DEBUG
        Trace_Out "FAKESTAT: Unloading"
endif

  ; make sure perf.386 is still there, if we're loaded dynamically and
        ; "stuck" (caller died or failed to unload us) we can unload after
        ; perf
  VxDCall  PERF_Get_Version
  or  eax, eax
  jz  fse40
         mov eax,hPerfID
  cmp eax,0
        je  fse40
        push eax
        VxDCall PERF_Server_Deregister
        add esp,4
fse40:
        clc
  ret

EndProc FAKESTAT_System_Exit

BeginProc FAKESTAT_Get_Version, Service

  mov  eax, 400h      ; Version 4.0
  clc
  ret

EndProc FAKESTAT_Get_Version

Control function for our perf server. Receives stat turn-on and turn-off notification messages when client is interested in looking at stat. If it's cheap and easy to just always update the stat, you can ignore these messages or not register a control function. For stats that are expensive to update, it's best to only update them while someone is looking at them. Since there can be more than one perf client, if you process control functions you should keep a counter for each stat and increment it with every PMSG_START_STAT and decrement it for each PMSG_STOP_STAT that that stat receives (and stop updating the stat when the client count reaches zero).

BeginProc FakeStat_StatControl
  ArgVar  dwMsg, DWORD  ; the control message (PMSG_xxx)
  ArgVar  dwData, DWORD   ; stat handle

  EnterProc

  cmp dwMsg,PMSG_START_STAT
        jnz fsc10

  Trace_Out "FAKESTAT: Got stat start msg"
  ; do stat-starting stuff here

        jmp fsc20

fsc10:
        ; PMSG_STOP_STAT

  Trace_Out "FAKESTAT: Got stat stop msg"
  ; do stat-stopping stuff here

fsc20:  LeaveProc
        Return

EndProc FakeStat_StatControl

VxD_PAGEABLE_CODE_ENDS

  PAGE
;***************************************************************
;     D E B U G G I N G   C O D E
;***************************************************************

IFDEF DEBUG
VxD_LOCKED_CODE_SEG

;***************************************************************
;
;   FakeStat_Debug_Query
;
;   DESCRIPTION:
;
;   ENTRY:
;
;   EXIT:
;
;   USES:
;
;=======================================================================

BeginProc FakeStat_Debug_Query

PF_DQ_Exit:
  clc
  ret

EndProc FakeStat_Debug_Query

VxD_LOCKED_CODE_ENDS
ENDIF

  END FakeStat_Real_Init


Windows Hardware Quality Labs Testing

Windows Hardware Quality Labs (WHQL) distributes Windows® 95 compatibility tests (CTs) and instructions for using them. Third-party engineers use the CTs to test hardware devices and drivers at their site before submitting them to WHQL for compatibility testing. All the compatibility tests are used by WHQL during the testing process at Microsoft Corporation.

The CTs are not included on this release of the Windows 95 DDK, and you must not use any of the CTs distributed on either of the two previous releases of the Windows 95 DDK.


How to Obtain the Latest Compatibility Tests

The current CTs and documentation kits are now distributed on the Internet, at two sites:

  • An FTP site (ftp://ftp.microsoft.com/services/whql).
  • A Web site (http://www.microsoft.com/windows/thirdparty/whql.htm).

The files available for downloading are always the same on both sites. The most recent version of the compatibility tests for different device classes, instructions for using the tests, device class-specific Setup programs, and any special test tools you need to carry out the tests are in compressed files on both sites.

To give you an idea of the CTs available on the Internet sites, when this version of the Windows 95 DDK was released, compatibility tests were on the sites for the following device classes:

  • Audio adapters.
  • Display adapters and monitors.
  • Gaming devices.
  • Input devices.
  • ISDN and WAN.
  • Keyboards.
  • Modems.
  • Network LAN.
  • Printers.
  • Storage devices and adapters.
  • System (complete platforms).
  • Video adapters.


Other Compatibility Test Information

If you have any questions about WHQL's program or the compatibility tests after looking at the FTP sites and/or reading the faxed-back instructions, e-mail whqlinfo@microsoft.com.

Contact Microsoft Developer Support Services to answer technical questions about device driver development, not WHQL. For example, sites that have a support contract with Microsoft, such as a Premier, Priority, or MSDN Level II support contract, should call their regular support number and ask for DDK support for OEMs and IHVs. After you have submitted your device and device driver for WHQL testing, WHQL test engineers will take the initiative to contact you about specific problems your device is having with the WHQL tests.

If your site does not have a support contract with Microsoft, or for answers to general questions about the Microsoft support options, telephone 1-800-936-3500.


DDK Documentation Errors About the Compatibility Tests

If the documentation for this release of the Windows® 95 DDK states that the WHQL tests and tools are included in the DDK, that is not the case. Download the compatibility tests, test documentation, and test tools from one of the Internet sites. That way, you know you are always getting the most recent versions.

If the DDK documentation states that you must run a Setup program called Ctsetup.exe from the \Ct directory of the DDK to install the compatibility tests and tools, that is not the case. Ctsetup.exe is not included in this version of the DDK. When you download the compatibility tests for a device class from one of the Internet sites, a device class-specific Setup program is downloaded along with the tests, test instructions, and tools. Run that Setup program to install the tests and tools for your device class.

If the DDK documentation states that Ct setup instructions are on the DDK, that is not the case.


Introduction to the Design Guide

The Design Guide is subdivided into sections; with each section corresponding to a hardware device or adapter class. Most users of the Microsoft® Windows® 95 Device Driver Kit (DDK) are interested in just one, or at most two, of these sections and can ignore the others. For example, when device driver engineers use the DDK, they are usually building a driver for one specific device or adapter class and are only interested in that section in the guide. For example, an engineer developing a driver for a display adapter is only interested in the Display Drivers section of the guide.

Topics of interest to device driver developers for all classes of devices, such as Plug and Play and device installation, are in the Programmer's Guide.

Sections in the Design Guide correspond roughly to the Windows Hardware Quality Labs (WHQL) hardware categories. The WHQL hardware categories are changing and evolving as more and more certification tests are developed by WHQL. One goal for the guide is to make it clear which WHQL certification tests apply to a device or adapter driver developed with the help of a particular section of the guide.

The following table shows the relationship between the sections of the Driver Design Guide and the WHQL hardware categories.

WHQL hardware category | Design Guide section
Audio adapters | Multimedia
Display adapters and monitors | Display
Input devices | Multimedia (joystick), Keyboard, Mouse, and Pen
Modems | Modems
Network adapters | Networks and Infrared
Printers | Printers
Storage adapters and devices | Storage
Computer Systems | Communications
Video capture adapters | Multimedia

The Communications section covers writing drivers for serial (COM) and parallel (LPT) ports; the WHQL Computer Systems hardware category includes entire platforms, not just the serial and parallel ports. WHQL has a hardware category called Microprocessors (mother boards); there is no comparable section in the Design Guide.

The catch-all Multimedia section may disappear in the future, both as a WHQL device class category and a DDK Design Guide section, as WHQL develops certification tests for display, audio, joystick, and modem devices that use hardware designs recommended for running DirectX software.


About Windows Hardware Compatibility Labs

The Windows Hardware Compatibility Labs (WHQL) group exists to ensure quality computer hardware, both systems and peripherals, for users of Windows® 95. Devices that pass WHQL certification tests are qualified to display the "Designed for Microsoft Windows 95" logo, and are included in the Windows Hardware Compatibility List (HCL). In addition, device drivers are distributed for free through the Windows Driver Library (WDL).

For the information about working with WHQL to certify hardware devices and device drivers, see Device Driver Certification.


Contents of the Design Guide

The Design Guide is organized into the following sections:

Audio Device Drivers | Describes how to write the different types of audio device drivers, including wave drivers, MIDI drivers, mixer drivers, and audio compression drivers.
Communications Device Drivers | Serial ports, parallel ports, FAX machines, and modems are examples of communications devices, providing a single asynchronous data stream. The central communications component in Windows 95, the virtual communications driver (VCOMM), is a virtual device (VxD) that manages all access to communications devices. VCOMM relies on port drivers, which are separate VxDs, to access communications devices. A port driver may need to be written to support a nonstandard communications port.
Display Drivers | Windows® 95 display drivers are dynamic-link libraries (DLLs) that translate device-independent commands from the graphic-device interface (GDI) into commands that a display adapter uses to draw graphics on the screen. The device-independent bitmap (DIB) engine is a DLL that contains most of the functions needed to translate GDI commands, enabling the display driver to be a relatively simple display minidriver.
Infrared Device Drivers | Infrared (IR) communications is an optional component in the Windows 95. IR communications drivers can be built to support add-on IR adapters connected to serial or parallel ports and built-in IR devices running up to 115.2 kilobytes per second (Kbps).
Keyboard Drivers | A keyboard driver processes all keyboard input for the Windows 95 operating system and applications. The driver directly accesses the keyboard hardware, and provides hardware-independent keyboard input by translating scan codes to virtual-key codes.
Modems | The Windows 95 Modem Development Kit (MDK) provides the tools, sample INF files, and information needed to build and test INF files for AT and AT+V command modems. AT command modems are data modems, and AT+V command modems are voice modems.
Mouse and Pointing Device Drivers | Software components that support the mouse in Windows 95 include the virtual mouse device, optional mouse minidrivers, optional virtual cursor drivers, and the Windows mouse driver.
Multimedia Device Drivers | Windows 95 uses a generic, extensible approach of interacting with different multimedia devices, which uses both standard MCI features of MCI and extensions to MCI to provide access to new devices and new device features. Windows 95 also supports for waveform input and output devices, MIDI input and output and MIDI synthesizer devices, mixer devices, video capture devices, and joystick devices. Windows 95 also supports both audio and video compression and decompression (codec) drivers.
Network Device Drivers | Windows 95 supports network device drivers having either the network driver interface specification (NDIS) miniport or Full NDIS media access control model. The preferred driver model is the miniport model, as described in the Windows NT®Device Driver Development Kit (DDK) version 3.51. Developers of miniport drivers should obtain the Windows NT 3.51 DDK and use it to develop a driver that is binary-compatible between Windows 95 and Windows NT version 3.51. It is important to note that for network adapter card drivers, an NDIS 3.1-compliant Full NDIS media access control driver can be built by compiling an existing NDIS 3.0 Full media access control driver sources with the Windows 95 DDK tools. The NDIS 3.1 specification is specific to Windows 95 and is essentially the NDIS 3.0 specification with Plug and Play capability added. A miniport driver is by definition NDIS 3.1-compliant, that is, the driver is a Plug and Play device.
Pen Device Drivers | Windows 95 provides a pen device driver and a pen calibration application that extends the Windows 95 Control Panel. The pen device driver, which supports digitizing pen hardware from various manufacturers, is a unidriver. The pen calibration application enables the user to calibrate a digitizer by touching targets on the digitizer; the calibration information obtained is used by the driver in reporting pen position coordinates to Windows 95.
Printer Device Drivers | To simplify the task of building a printer driver, the Windows 95 DDK provides a universal printer driver (a unidriver for printers). The unidriver is capable of carrying out requests (such as printing text, rendering bitmaps, or advancing a page) on most types of printers. To build a driver for a particular printer, a developer builds a minidriver, which accepts requests from GDI and then, in most cases, passes the request to the unidriver along with information that describes the capabilities, commands, and resident fonts of the particular printer. To simplify the task of building a minidriver, the Windows 95 DDK provides Unitool, a tool that provides a graphical user interface for building minidrivers. The Windows 95 spooler is the component of the Windows 95 printer subsystem that enables print jobs to be routed to local and network printers. The spooler itself has numerous components, some of which can be written or modified by independent hardware vendors (IHVs).
Storage Device and Adapter Drivers | Layered block device drivers are 32-bit, flat-model device drivers that execute in protected mode. Windows 95 uses layered block device drivers to manage input and output to block devices, such as disks and CD-ROM devices. These drivers support partitioned and non-partitioned removable media as well as conventional, SCSI, and floptical floppy drives. Windows 95 uses a variety of device driver components to support different types of devices and software. Each component corresponds to a specific layer and has specific responsibilities and requirements.


Overview of Audio Device Drivers

For information about how to build device drivers for audio adapters running under Microsoft® Windows® 95, see Audio Device Drivers in the Multimedia section of this guide.

For information about how to certify your audio device driver with the Windows Hardware Quality Labs, see Device Driver Certification in the Microsoft Windows 95 DDK Programmer's Guide. Devices that pass WHQL's certification tests are qualified to display the "Designed for Microsoft Windows 95" logo. This logo is your customer's assurance that your product will work with the Windows 95 family of products. Audio adapters that pass WHQL's certification tests are also identified in the Windows Hardware Compatibility List (HCL), and the audio adapter drivers are distributed free through the Windows Driver Library (WDL).

For information about how to obtain a copy of the DirectSound DDK Beta release, send e-mail to directx@microsoft.com.


Virtual Communications Device Drivers

A communications resource is a physical or logical device that provides a single asynchronous data stream. Serial ports, parallel ports, FAX machines, and modems are examples of communications resources. The central communications component in Windows 95 is the virtual communications driver (VCOMM), a virtual device (VxD) that manages all access to communications resources.

VCOMM relies on separate VxDs, called port drivers, to access communications resources. This design makes VCOMM easily extensible. To support a nonstandard communications port, you can create a port driver. You may also need to create a port-virtualization VxD to virtualize the port for MS-DOS® – based applications. Under no circumstances should you replace VCOMM itself. Nor should you replace COMM.DRV, as was often necessary with previous versions of Microsoft® Windows™.

The following table briefly describes each component.

Component | Description
VCOMM.386 | The virtual communications driver. VCOMM is a nonreplaceable system component that manages all access to communications resources. For more information, see About VCOMM.
COMM.DRV | The Windows communications driver. COMM.DRV provides a set of exported functions that USER.EXE calls to implement the Windows communications API. COMM.DRV uses the VCOMM protected-mode API, and is therefore not tied to any specific communications hardware. Hardware vendors should not replace COMM.DRV, as was done in previous versions of Windows, but should create a port driver instead.
Client VxDs | Any VxDs that use the VCOMM client VxD services to access communications resources. Port-virtualization VxDs can be VCOMM client VxDs. Certain applications might install VCOMM client VxDs, bypassing the Windows communications API.
Port drivers | Installable VxDs that VCOMM uses to access communications devices. Hardware vendors create port drivers to enable Windows applications and VxDs to use their communications ports. For more information, see About Communications Port Drivers.

Port-virtualization VxDs Installable VxDs that virtualize communications hardware for applications running in nonsystem virtual machines (VMs). Communications hardware vendors can create port-virtualization VxDs to virtualize their devices for MS-DOS applications.


Virtual Communications Driver

The virtual communications driver (VCOMM) is a non-replaceable system component that manages all access to communications devices. Port drivers use VCOMM services to register themselves and block access to communications hardware. Other virtual devices (VxDs), referred to as client VxDs, use VCOMM services to access communications resources. Finally, the Microsoft® Windows™ communications driver (COMM.DRV) uses VCOMM's protected-mode application programming interface (API) to access communications resources. VCOMM uses port drivers to carry out all hardware operations on communications resources.


Port Driver Services

Port drivers use port driver services to initialize and block access to hardware. A port driver calls the _VCOMM_Register_Port_Driver service when it is loaded. A port driver calls the _VCOMM_Add_Port service once for each port it supports.

The _VCOMM_Acquire_Port and _VCOMM_Release_Port services enable port drivers to acquire and release exclusive access to communications devices. A port driver should acquire a port when its PortOpen function is called, and release a port when its PortClose function is called. Other VxDs that access communications hardware directly should also call these services.

VCOMM relies on the virtual communications device (VCD) to block access to communications devices. The _VCOMM_Acquire_Port service has no effect when used with communications resources that VCD does not support, although the service still returns a handle in such cases.

See Also

_VCOMM_Acquire_Port, _VCOMM_Add_Port, _VCOMM_Register_Port_Driver, _VCOMM_Release_Port


Client Virtual Device Services

VCOMM client VxD services enable VxDs to use any communications resource for which a port driver is installed. VCOMM provides services for opening and closing a communications resource, configuring a port, reading from and writing to a communications resource, processing communications events, and calling a port driver's extended functions. The following topics describe the VCOMM client VxD services.


VCOMM Client VxDs

VxDs use the VCOMM client VxD services for a variety of reasons. Following are some examples of VCOMM client VxDs:

  • Application-defined VxDs. An application can install a private VxD that calls the VCOMM services directly, bypassing the Windows communications API. This approach can be useful for implementing time-critical protocols (such as FAX) that require interrupt-time processing.

    Because creating a private VxD ties your application to Windows 95, you should do so only if necessary. Microsoft(r) Win32(r) applications are scheduled regularly enough to meet the timing requirements of most protocols, such as those for file transfer.

  • Port virtualization VxDs. Port virtualization VxDs simulate communications hardware for applications running in VMs. By using the VCOMM client VxD services, a port virtualization VxD can redirect the virtualized device to any communications resource for which a port driver is installed.
  • Many modems are external, attaching to standard serial ports, or are internal but emulate a standard serial UART. Modem drivers for such devices typically do not duplicate the functionality of an existing port driver, but instead call VCOMM client VxD services to perform their input and output.


Open and Close Services

Before performing any other operations on a communications resource, a client VxD must call the _VCOMM_OpenComm service to open the resource. This service initializes the communications device and the port driver associated with it, and returns a communications handle that is used in subsequent calls to VCOMM client VxD services.

The _VCOMM_CloseComm service closes a communications resource. If the transmit queue is not empty, the close property of the port determines whether the remaining data is sent before the port is closed: if it is PORTCLOSE_WAIT, the service does not close the port and does not return until the characters in the transmit queue have been sent; if it is PORTCLOSE_FLUSH, the service discards the data in the transmit queue and closes the port immediately. You can query and set the close property using the _VCOMM_EscapeCommFunction service.

Client VxDs must close any communications resources they open. A VxD that opens a communications resource for use in a virtual machine (VM) must process the VM_Not_Executeable event so that it can close the resource if the VM terminates.

See Also

_VCOMM_CloseComm, _VCOMM_EscapeCommFunction, _VCOMM_OpenComm


Configuration Services

You can use VCOMM services to configure a communications resource and initialize its receive and transmit queues. The _DCB (device control block) structure specifies the configuration settings for a communications resource - for example, the baud rate, the number of data bits per byte, and the number of stop bits per byte. Additional fields specify parity, handshaking options, and special characters used for handshaking or for signaling events.

When you open a communications resource, the port driver initializes it using a default configuration. You can determine the current configuration by calling the _VCOMM_GetCommState service, that fills in a _DCB structure. Before configuring the communications resource, you can determine which settings it supports by calling the _VCOMM_GetCommProperties service; this service fills in a _COMMPROP structure. To configure the communications resource, call the _VCOMM_SetCommState service.

To initialize the receive and transmit queues for a communications resource, call the _VCOMM_SetupComm service. The previous state of the receive queue is returned in the specified _QSB structure. If you do not call this service, the port driver uses default queues. The _COMMPROP structure specifies the default and maximum sizes of the receive and transmit queues. Note that port drivers for some devices, such as LPT ports, do not use queues.

See Also

_COMMPROP, _DCB, _QSB, _VCOMM_GetCommProperties, _VCOMM_GetCommState, _VCOMM_SetCommState, _VCOMM_SetupComm


Read and Write Services

To write to a communications resource, call the _VCOMM_WriteComm service. This service writes the specified data to the transmit queue and returns immediately. Always check both the return value of this service and the number of bytes written. If there is insufficient space in the transmit queue, the number of bytes written is less than the number requested - yet the return value is TRUE. In this case, call the _VCOMM_ClearCommError service to detect and reset any communications errors that may have occurred.

For communications devices that do not use transmit queues, such as LPT ports, _VCOMM_WriteComm actually writes the data to the device before returning. If a write time-out occurs, the number of bytes written is less than the number requested and the return value is FALSE.

To send high-priority characters, such as event characters, you can use the _VCOMM_TransmitCommChar service. This service sends a single character ahead of any data in the transmit queue. Until the hardware is ready to send the character, most port drivers store it in a special one-character buffer. If a character specified in a previous call to this service is still waiting to be sent, the service returns FALSE.

To read from a communications resource, call the _VCOMM_ReadComm service. This service reads the specified amount of data from the receive queue and returns immediately. Always check both the return value of this service and the number of bytes read. If the receive queue does not contain enough data, the number of bytes read is less than the number requested - yet the return value is TRUE. If the number of bytes read is zero, call _VCOMM_ClearCommError to detect and reset any communications errors that may have occurred.

For output-only devices, such as LPT ports, _VCOMM_ReadComm returns TRUE with zero bytes read. For other communications devices that do not uses receive queues, _VCOMM_ReadComm actually reads the data from the device before returning. If a read time-out occurs, the number of bytes read is less than the number requested and the return value is FALSE.

You can check the status of the transmit and receive queues by calling the _VCOMM_GetCommQueueStatus service; this service fills in a _COMSTAT structure. You can discard the contents of the transmit or receive queue by calling the _VCOMM_PurgeComm service.

See Also

_COMSTAT, _VCOMM_ClearCommError, _VCOMM_GetCommQueueStatus, _VCOMM_PurgeComm, _VCOMM_ReadComm, _VCOMM_TransmitCommChar, _VCOMM_WriteComm


Event Services

A VCOMM client can receive notifications when communications events occur or when the receive and transmit queues pass specified thresholds. To receive notifications for events, call the _VCOMM_EnableCommNotification service. To receive notifications when queue thresholds are reached, call the _VCOMM_SetReadCallback and _VCOMM_SetWriteCallback services. All three services register client-defined callback functions with the port driver. For information about the callback functions, see the description of the CommNotifyProc function.

You receive notifications for communications events only if the events are enabled. To enable events, call the _VCOMM_SetCommEventMask service; this service specifies the event mask and, optionally, the address of the event variable. The event mask is a 32-bit variable that specifies the combination of enabled events. The event variable is a 32-bit variable that specifies the enabled events that were detected; the port driver updates the event variable at interrupt time when events occur. To determine which enabled events have occurred, call the _VCOMM_GetCommEventMask service; this service retrieves the detected events and clears the corresponding bits in the event variable.

If a hardware handshaking signal causes a notification, the parameters for CommNotifyProc identify the signal that changed but not the current state of the signal. To determine the current state of the clear to send (CTS), data set ready (DSR), receive line signal detect (RLSD), and ring signals, call the _VCOMM_GetModemStatus service.

See Also

CommNotifyProc, _VCOMM_EnableCommNotification, _VCOMM_GetCommEventMask, _VCOMM_GetModemStatus, _VCOMM_SetCommEventMask, _VCOMM_SetReadCallback, _VCOMM_SetWriteCallback


Extended Functions

You can use the _VCOMM_EscapeCommFunction service to direct the port driver to carry out an extended function. Constants defined in VCOMM.INC identify several extended functions that can be used - for example, to get or set the close property, set or clear hardware handshaking lines, or reset an LPT port. Individual port drivers may support only a subset of the extended functions defined in VCOMM.INC.

To expose unique features of a communications device, port drivers can define driver-specific extended functions not in VCOMM.INC.

See Also

_VCOMM_EscapeCommFunction


Protected-Mode Application Programming Interface

The VCOMM protected-mode API (PM API) provides a set of functions that COMM.DRV calls to access communications resources. In general, Windows-based applications should use the communications functions in the Windows API.

Before calling any VxD's PM API, an application must determine the address to call by using Interrupt 2Fh Function 1684h (Get Device API Entry Point Address). The following example retrieves the calling address for the VCOMM PM API, and saves it in the 32-bit variable _VCOMMCallAddr.

xor     di, di                           ;zero in DI
mov     es, di                           ;zero in ES
mov     ax, 1684h                        ;function number
mov     bx, VCOMM_Device_ID              ;device ID
int     2Fh                              ;get API entry point
mov     word ptr [_VCOMMCallAddr], di    ;segment in high-order word
mov     word ptr [_VCOMMCallAddr+2], es  ;offset in low-order word

To call a PM API function, place the function number in AX and call the API entry point address. Parameters are placed in other registers or on the stack. Most of the PM API functions thunk to a corresponding client VxD service.

For PM API functions that return an error value, the error value is the low 16 bits of the error that would be returned by the _VCOMM_GetLastError service. That is, it is the low 16 bits of the dwLastError field of _PortData.

See Also

_VCOMM_GetLastError, VCOMM_PM_API_cevt, VCOMM_PM_API_cevtget, VCOMM_PM_API_cextnfcn, VCOMM_PM_API_cFlush, VCOMM_PM_API_ctx, VCOMM_PM_API_EnableNotify, VCOMM_PM_API_OPENCOM, VCOMM_PM_API_ReadString, VCOMM_PM_API_SetCom, VCOMM_PM_API_SetMSRShadow, VCOMM_PM_API_Setup, VCOMM_PM_API_StaCom, VCOMM_PM_API_TrmCom, VCOMM_PM_API_WriteString


Installation and the Registry

A VCOMM device (such as a COM port, LPT port, or modem) is installed into Windows 95 in one of the following ways:

  • It is detected during Windows 95 Setup.
  • It is Plug and Play, and detected by it respective "bus enumerator" when first physically installed.
  • It is detected or manually installed by the Hardware Installation Wizard or Modem Installation Wizard in the Control Panel.

Each installed VCOMM device is represented by two separate registry keys: one hardware key and one software key (also known as a "driver key").

The hardware key is located under the HKEY_LOCAL_MACHINE\Enum branch, along with hardware keys for all other devices that have been detected or enumerated in the system. Hardware keys for non-Plug and Play VCOMM devices are found under Enum\Root. Plug and Play device keys are found in their respective bus enumerator branches, for example, Enum\ISA, Enum\PCMCIA, Enum\PCI, and Enum\SERENUM. Examples of common Windows 95 VCOMM hardware keys are:

Enum\Root\*PNP0500\0000 | The first COM port detected by Setup, usually COM1. Subsequent detected COM ports would be enumerated as *PNP0500\0001, and so on.
Enum\Root\*PNP0400\0000 | The first LPT port detected by Setup in the system, usually LPT1.
Enum\Root\Ports\0000 | A manually installed port, either COM or LPT.
Enum\SERENUM\PNP0F0A\ROOT&*PNP0500&0000 | A Plug and Play serial Microsoft Mouse, detected on port COM1 by SERENUM.VXD, the serial port bus enumerator.
Enum\LPTENUM\ABC1234\ROOT&*PNP0400&0000 | A Plug and Play parallel port device, with Plug and Play device ID "ABC1234", detected on port LPT1 by LPTENUM.VXD, the parallel port bus enumerator.

Hardware keys have a variety of subkeys and values. Most of these are created by the Plug and Play subsystem for its internal usage, and are common to all device classes. See the Plug and Play documentation for information about these. However, VCOMM stores two values in the hardware key for its use:

FriendlyName | User-readable description of the device, for example, "Communications Port (COM1)" or "Hayes compatible modem". Created either by the INF or by VCOMM. Can be used in device open calls to obtain a handle to the device.
PortName | Short-style device port name, for example, "COM1" or "LPT1". These are assigned by VCOMM. It can be used in device open calls to obtain a handle to the device.

When a VCOMM device is installed from an INF into Windows 95, its software key is created under HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Class. For each installed COM or LPT port, there is a software key created under \ports, for example, \ports\0000. For each installed modem, there is a key under \modem; for example, \modem\0000. A pointer to a device's software key is stored in its hardware key as the value "Driver".

The software key contains subkeys and values installed by the device's INF file, class installer, and driver. The following values are common to all or most VCOMM devices in the software key:

ConfigDialog | Specifies the DLL called to service Win32® comm API functions CommConfigDialog, GetDefaultCommConfig, and SetDefaultCommConfig. For COM ports, this is "serialui.dll". For modems, this is "modemui.dll". LPT ports currently do not support these functions, so do not have this value.
Contention | Specifies the static VxD (loaded at boot time from system.ini or the registry) that handles contention and virtualization for the device. This is "*vcd" for COM ports and PCMCIA modems, and "*vpd" for parallel ports. Non-standard port types can install their own contention VxD.
DCB | This binary value is a DCB data structure stored by the configuration DLL for devices that use serial.vxd as their port driver (for example, COM ports and PCMCIA modems). It is created by the configuration dialog DLLs serialui.dll and modemui.dll, in response to SetDefaultCommConfig() calls.
DevLoader | Always "*vcomm"
DriverDesc | The name of the device specified by its INF file; for example, "Communications Port", "Printer Port", or "Hayes compatible modem".
Enumerator | Specifies a Plug and Play enumerator that VCOMM will load at boot time to detect devices attached to the port device. This is "serenum.vxd" for COM ports, and "lptenum.vxd" for parallel ports. Non-standard port types can install their own enumerator VxD. Modems do not have an enumerator, since they do not have attached devices.
EnumPropPages | Specifies the DLL and entry point name called to provide property sheet pages for the device in the System control panel Device Manager. For COM ports, this is "serialui.dll,EnumPropPages". For modems, this is "modemui.dll,EnumPropPages". LPT ports currently do not have property pages.
FriendlyDriver | The VCOMM port driver loaded when the device is opened by a VCOMM client by its "FriendlyName" (located in the hardware key). If FriendlyDriver is not present, its PortDriver will be used instead. For modems, FriendlyDriver is always "unimodem.vxd".
PortDriver | The VCOMM port driver loaded when the device is opened by a VCOMM client by its "PortName" (located in the hardware key). This is "serial.vxd" for COM ports, "lpt.vxd" for LPT ports. For internal and external modems, this is not used. However, UART-compatible PCMCIA modems have this set to "serial.vxd".
PortSubClass | "00" for parallel ports, "01" for serial ports, "02" for modems.

See the modem section of the Windows 95 DDK documentation for more information about registry values used for the Universal Modem Driver ("Unimodem").


VCOMM Device Initialization

VCOMM is a static VxD always loaded at boot time in Windows 95. It functions as the Plug and Play "device loader" for installed devices of class "ports" or "modem". This means VCOMM is called to load these devices when they are enumerated by the Plug and Play Configuration Manager. This is usually at boot time for COM ports, LPT ports, and internal and external modems. However, PCMCIA ports and modems can be enumerated "on the fly" when inserted at any time during a Windows 95 session.

When the Plug and Play Configuration Manager calls VCOMM to load an enumerated device, it passes a handle to the "devnode" data structure for the device. The devnode contains information about the device, including its resource allocation and registry key locations. When called to load a device, VCOMM does the following:

  1. Remembers the PortName and FriendlyName strings specified in the device's hardware key. Later, when called to open the device by one of these names, VCOMM will match it to the software key for this device to determine the port driver VxD to load. Note that the port driver is not loaded immediately when the device is enumerated. Rather, it is only loaded when opened by a VCOMM client such as Remote Access or a communications application. This speeds boot time, and prevents unnecessary consumption of system resources until the device is actually opened.
  2. Assigns a "PortName" to the device in its hardware key, if its devnode contains system resources. For COM ports (PortSubClass="01") and PCMCIA modems (PortSubClass="02"), PortName is assigned according to the base I/O port address, as shown in the following. Devices with non-standard base addresses receive port names starting at COM5 and higher.
03F8 | COM1
02F8 | COM2
03E8 | COM3
02E8 | COM4
3220 | COM3 (PS/2)

For LPT ports (PortSubClass="00"), PortName is assigned according to the relative location of the base address in the BIOS data table at 40:8. That is, if the base address is the first entry in the table, it is assigned PortName="LPT1", and so on. PortName is not assigned if the base address is not contained in the BIOS data table.

Note Internal and external modems devnodes do not have resources, so are not assigned PortNames.

In addition to creating the PortName key, VCOMM writes a new string value for FriendlyName and DeviceDesc, by appending the device's PortName to its DriverDesc (taken from the software key); for example, "Communications Port (COM1)" and "Printer Port (LPT1)". This serves two functions: to make the FriendlyName unique in the system, and to cause the port name to appear in the Device Manager page of the System control panel.

  3. Calls the contention handler specified by the Contention value in the software key, if present; for example, "*vcd" for serial ports and PCMCIA modems. This causes the contention handler to begin virtualization of the device, using the I/O ports, IRQ, and so on, passed to it by VCOMM. Note that unlike previous versions of Windows, contention handler VxDs such as VCD and VPD no longer virtualize ports based on entries in the BIOS data table and SYSTEM.INI. This has been made dynamic to accommodate the Plug and Play architecture, especially dynamic insertion and removal of PCMCIA ports and modems.
  4. Loads the Plug and Play enumerator VxD for the device specified by the Enumerator value in the software key, if present. The enumerator VxD subsequently registers with the Configuration Manager, and is called at some later point to detect devices attached to the port, such as modems and printers.

When a device is removed (for example, a PCMCIA port or modem is removed), the Configuration Manager notifies VCOMM. VCOMM unloads the port driver, if necessary, and calls the device's contention handler VxD, if any, to end virtualization of its resources.


VCOMM Open - Matching Names to Drivers

When VCOMM receives a call to open a device, it receives a string from the client which identifies the device to open. This is either a PortName string or a FriendlyName string. VCOMM searches the list of devices it has been called to load, attempting to match the string against their hardware key PortName and FriendlyName values.

If VCOMM matches the string to a device's PortName (for example, "COM1"), it will load the port driver VxD specified by that device's PortDriver value (for example, "serial.vxd"). Similarly, if VCOMM matches on FriendlyName (for example, "Hayes compatible modem"), it will load the port driver VxD specified by that device's FriendlyDriver key (for example, "unimodem.vxd"). In the FriendlyName case, if FriendlyDriver is not present, VCOMM will use the PortDriver instead. If no match is found, VCOMM fails the open call.

If the port driver is already loaded, VCOMM increments the open count for the driver. When a port is closed, VCOMM decrements the driver's open count. When a driver's open count reaches 0, it is unloaded from memory.


Port Contention

A VxD must use the VCOMM contention services (VCOMM_Get_Contention_Handler, ACQUIRE_RESOURCE, RELEASE_RESOURCE, and so on) to coexist properly with other drivers in the system that write to parallel ports (for example, LPT.VXD for printing and LPTENUM.VXD for enumeration).

This section describes services for managing contention for COM ports, LPT ports, and other VCOMM devices by VxDs and VMs. This section also explains how multiple VxD device drivers can simultaneously access dongles and other passthrough devices attached to a parallel port.

A VCOMM resource is any device that has a VCOMM driver installed (for example, COM1 and LPT1). A VCOMM resource is also any device for which VCOMM is the device loader.

A contention handler is the VxD that provides acquiring and releasing services for a VCOMM resource.

The INF file for a VCOMM device driver specifies the name of its contention handler VxD. For COM ports, this is *VCD, and for LPT ports, this is *VPD. If no contention handler is specified for a device, VCOMM is used by default.


Contention Management by Contention Managers

A contention manager is associated with each device. The contention manager is essentially a VxD that guards against simultaneous access to a device by different sources at the same time. VCOMM looks for the "contention" entry in the software section for the devnode of the device and then loads it at boot time and calls its control procedure with eax = GET_CONTENTION_ENTRY. The contention VxD returns with the address of the procedure to call in eax. If VCOMM does not find the entry or if the VxD does not respond to the GET_CONTENTION_ENTRY call, VCOMM uses its internal contention handling function in place of the contention VxD. However, this function does not manage contention between different VMs (and other system components); it just manages contention between different VxDs trying to access the same device.

The function returned by GET_CONTENTION_ENTRY is a C-style function that accepts a variable number of parameters, depending on the desired action. The basic subfunctions provided by the contention VxD are as follows (VCOMM provides a common channel to clients for accessing all these services):

  • Acquire a resource. Given a resource, the contention VxD acquires it for the caller. In the case of port drivers, the resource is the base address of the port array. If the resource is acquired without errors, a valid handle is returned. The caller can set various modes of acquiring a resource:
    • Acquire the resource and do not allow it to be stolen.
    • Acquire the resource and allow it to be stolen, but notify when it is stolen and also notify when it is returned.
  • Release a resource. Given a handle, the contention VxD releases the resource.
  • Steal a resource. Given a handle, the contention VxD steals the resource.
  • Give a name. Given a name, the contention VxD returns the resource associated with it.

VCOMM provides a common way for all clients to use these services.


Contention Management by Port Drivers

Port drivers also do contention handling. By default, port drivers do not allow a caller to open an open port. However, the owner of a port can send ioctls to the port driver to "unlock" access to the port. In this case, if another caller calls to open a port, the port driver will notify the original owner and give the port to the new caller. When the port is closed, the original owner will be notified again that the port has now been released. The port drivers keep a stack of such owners; all of them are notified one by one when the port is released. If one of the owners reopens the port during the callback, the earlier owners are not notified.


Windows 95 LPT Contention Handler

The role of the Windows 95 LPT contention handler (VPD) is to manage contention for LPT ports by VMs.

A VM is automatically granted port access if the port is not currently owned by another VM or VxD.

If there is a VxD owner, VPD sends it RESOURCE_STEAL_REQUEST. If this request succeeds, the port is assigned to the VM. Otherwise, the request fails and is reported to the user with a dialog message.

When a VxD or another VM attempts to steal a VM-owned port, VPD responds as follows:

  • Warn: VPD displays a dialog box asking if the port should be assigned to the requesting VxD or VM.
  • Fail: If the request is made by a VM, port access is silently trapped. If the request is made by a VxD, the acquire or steal call fails.
  • Idle: The port is reassigned automatically if the port has been idle longer for a time-out period specified in Control Panel. Otherwise, the acquire/release request fails for a VxD, or port access is silently trapped for a VM. This is the default setting, with a default time-out period of 2 seconds.


Windows 95 LPT Enumerator

The Windows 95 LPT enumerator (LPTENUM.VXD) does not call VCOMM to detect LPT devices; instead, it writes directly to the port. When called to enumerate devices attached to an LPT port, the enumerator calls ACQUIRE_RESOURCE with ACQUIRE_NO_STEAL, so that it does not inadvertently interfere with another program using the port.

Unlike the COM enumerator, LPTENUM calls RELEASE_RESOURCE when it is done checking a port, because it cannot detect a device attach or device detach operation.


Windows 95 LPT Driver

Windows 95 LPT driver (LPT.VXD) calls ACQUIRE_RESOURCE with ACQUIRE_STEAL. This service will steal ports owned by VMs, if stealing has been allowed by the user in Control Panel.

When LPT.VXD receives a RESOURCE_STEAL_REQUEST notification, it saves the state of the LPT or ECP port and returns TRUE. If the state cannot be saved at the current time, LPT.VXD returns FALSE.

After its port is stolen, LPT.VXD periodically attempts to steal back the port by calling STEAL_RESOURCE. This enables it to cooperate with periodic access by the VM for dongles, and so on.


MS-DOS Print Spooler

The MS-DOS print spooler, which redirects print jobs sent by applications using Interrupt 17h or Interrupt 21h, is not required to manage contention, because it does not call VCOMM or write to LPT ports. It routes print jobs to the Windows 95 print spooler, which contends for the port using the Win32 communications API.


Dongles

Dongle access should be made using a VxD in Windows 95. A dongle VxD calls ACQUIRE_RESOURCE with ACQUIRE_STEAL. If this call fails, the dongle VxD can try again later or return failure to its client. A dongle VxD accessing a port only causes a warning message if the user has set VPD to "warn" in the Control Panel. While it owns a port, the dongle VxD should fail RESOURCE_STEAL_REQUEST calls.

A dongle VxD should call RELEASE_RESOURCE as soon as it is done accessing the dongle. That is, it should not hold the acquire handle for the duration of its client application and release to RESOURCE_STEAL_REQUEST calls during idle periods. The reason for this is to enable more than two VxD clients to share a port. For example, imagine a system with the following devices installed: LPT1, dongle, Xircom adapter, and printer. The Xircom adapter and LPT.VXD could not share LPT1 while the dongle VxD is holding an acquire handle, because there can only be one current owner and one waiting owner at a time per resource (not including VMs).


Parallel SCSI Devices and Disks

Layered block device drivers for devices attached to LPT ports should behave as dongle VxDs, as described in "Dongles." That is, the drivers only acquire the port for as long as necessary to complete a read/write operation to the device.


Tape Backup

Tape backup applications should access devices using a VxD in Windows 95, and behave as dongle VxDs, as described in "Dongles." That is, applications only acquire the port for as long as necessary to complete a read/write operation to the device.


Parallel Network Interface Connectors

(An example of parallel network interface connectors is Xircom.) NDIS drivers for parallel port network adapters behave as dongle VxDs. That is, they call ACQUIRE_RESOURCE with ACQUIRE_STEAL, and RELEASE_RESOURCE as soon as they are done accessing the adapter.


Windows 95 COM Contention Handler (VCD)

The role of VCD is to manage contention for COM ports by VMs. It behaves identically to VPD, as described earlier.


Windows 95 COM Enumerator

The COM enumerator does not call VCOMM to detect COM devices, rather it writes directly to the port. When called to enumerate a device on a COM port, COMENUM calls ACQUIRE_RESOURCE with ACQUIRE_NO_STEAL, so that it does not inadvertently interfere with another program using the port.

The COM enumerator always returns TRUE for RESOURCE_STEAL_REQUEST.

When it receives a RESOURCE_RETURN_NOTIFY, the enumerator resumes its watch COM device attach/detach on the port.

The COM enumerator never calls RELEASE_RESOURCE.


Windows 95 COM Driver (SERIAL.VXD)

SERIAL.VXD calls ACQUIRE_RESOURCE with ACQUIRE_STEAL. This will steal ports owned by VMs, if allowed by the user in Control Panel.

When it receives a RESOURCE_STEAL_REQUEST notification, SERIAL.VXD saves the state of the COM port and returns TRUE.

Unlike LPT.VXD, SERIAL.VXD does not periodically attempt to steal back the port by calling STEAL_RESOURCE. Rather, it does this in response to a call from VCOMM on behalf of the device's client. This still enables it to share a port with a VM.


MS-DOS Communications Applications

In Windows 3.1, it is common practice for users to share a modem between an MS-DOS application and Windows. For example, Terminal and ProComm/Plus can use a modem simultaneously, with VCD switching control silently back and forth based on an idle timeout on the VM.

Windows 95 continues to support this capability. When SERIAL.VXD is using a port and a VM attempts to access it, VCD sends RESOURCE_STEAL_REQUEST to SERIAL.VXD, which returns TRUE. The VM will use the port and then go idle on it. After this, the next call from Windows to use the port will cause SERIAL.VXD to call STEAL_RESOURCE, which succeeds because the VM has gone idle on the port.


Parallel Port IRQs

A VxD should use port resources (I/O port addresses, IRQs, DMA channels, and so on) specified in the device node for the parallel port. If the VxD is a VCOMM port driver, a device node handle will be passed in when the device is opened. Otherwise, a VxD must use configuration manager services to obtain the device node handle.

However, non-Plug and Play parallel port device nodes usually will not specify an IRQ because Windows 95 detection does not assign these nodes by default to avoid resource conflicts with sound cards and other devices that commonly overlap LPT port settings. If the user does not manually select an IRQ in the Device Manager page of the System control panel, the device node will have only I/O port addresses assigned.

When a VxD driver requires an IRQ, but none is specified in the port device node, the driver should follow this procedure to find the proper IRQ:

  1. Use the IRQ recorded for the port the last time that it was used.
  2. If no IRQ was recorded or the device is not found at that IRQ, the driver should check the most common default IRQ for the port (for example, IRQ7 for LPT1).
  3. If the device is not found using the common default, the driver should try other IRQs as appropriate.

When the device is located, the driver should record the IRQ for future use. "Touched" IRQs should be allocated and deallocated properly using VPICD services. A side-effect of allocating an IRQ in a "touched" fashion is that it becomes unavailable for assignment to Plug and Play devices that arrive during the remainder of the Windows session (for example, PCMCIA cards). This is why it is important to minimize the number of "touched" IRQs using the procedure previously documented.


Reference

This section describes the services and protected-mode API functions provided by VCOMM, and their related structures.

The following services are for internal use only by Windows 95 components: _VCOMM_SetWriteRequest, _VCOMM_SetReadRequest, and _VCOMM_Dequeue_Request.

This information is separated into the following functional groups:

Group | Elements
Port-driver services | _VCOMM_Add_Port, _VCOMM_Map_Ring0DCB_To_Win32, _VCOMM_Map_Win32DCB_To_Ring0, _VCOMM_Register_Port_Driver
Client VxD services | CommNotifyProc, _COMMPROP, _COMSTAT, _DCB, _QSB, _VCOMM_ClearCommError, _VCOMM_CloseComm, _VCOMM_EnableCommNotification, _VCOMM_Enumerate_Devnodes, _VCOMM_EscapeCommFunction, _VCOMM_GetCommEventMask, _VCOMM_GetCommProperties, _VCOMM_GetCommQueueStatus, _VCOMM_GetCommState, _VCOMM_GetSetCommTimeouts, _VCOMM_GetLastError, _VCOMM_GetModemStatus, _VCOMM_OpenComm, _VCOMM_PurgeComm, _VCOMM_ReadComm, _VCOMM_SetCommEventMask, _VCOMM_SetCommState, _VCOMM_SetupComm, _VCOMM_TransmitCommChar, _VCOMM_WriteComm
Protected-mode API | VCOMM_PM_API_cevt, VCOMM_PM_API_cevtget, VCOMM_PM_API_cextnfcn, VCOMM_PM_API_cFlush, VCOMM_PM_API_ctx, VCOMM_PM_API_EnableNotify, VCOMM_PM_API_OPENCOM, VCOMM_PM_API_ReadString, VCOMM_PM_API_SetCom, VCOMM_PM_API_SetMSRShadow, VCOMM_PM_API_Setup, VCOMM_PM_API_StaCom, VCOMM_PM_API_TrmCom, VCOMM_PM_API_WriteString
Contention Management Functions | _VCOMM_Get_Contention_Handler, VCOMM_Map_Name_To_Resource
Legacy Contention Management Functions | _VCOMM_Acquire_Port, _VCOMM_Release_Port, _VCOMM_Steal_Port


Port-Driver Services

Use port driver services to register port drivers and to acquire and release exclusive access to a port. Some port driver services are used only by port drivers. Others are used by any VxDs that directly access communications hardware.


_VCOMM_Add_Port

include vcomm.inc

VxDCall _VCOMM_Add_Port, <ReferenceData, <OFFSET32 PortOpen>, \
    <OFFSET32 PortName>>
or     eax, eax
jz     error_handler

Registers a port. Uses the C calling convention.

  • Returns TRUE if successful, FALSE otherwise.
ReferenceData
32-bit value that VCOMM passed to the port driver's DriverControl function.
PortOpen
Address of the port driver's PortOpen function.
PortName
Address of a null-terminated string specifying the name of the port.


_VCOMM_Map_Ring0DCB_To_Win32

include vcomm.inc

mov     edx, Win32_DCB
mov     eax, Ring0_DCB
VxDCall _VCOMM_Map_Ring0DCB_To_Win32

The port driver functions PortGetCommConfig and PortSetCommConfig are called from Win32 and use a Win32-style DCB, not a Ring0 DCB. These port driver functions call _VCOMM_Map_Ring0DCB_To_Win32 to convert the DCBs.

  • No return value.
Win32_DCB
Address of a Win32-style DCB structure.
Ring0_DCB
Address of a Ring0 (or Win16-style) DCB structure.


_VCOMM_Map_Win32DCB_To_Ring0

include vcomm.inc

mov     eax, Win32_DCB
mov     edx, Ring0_DCB
VxDCall _VCOMM_Map_Win32DCB_To_Ring0

The _VCOMM_Map_Win32DCB_To_Ring0 function can be called to convert a Win32-style DCB to a Ring 0 DCB.

  • No return value.
Win32_DCB
Address of a Win32-style DCB structure.
Ring0_DCB
Address of a Ring0 (or Win16-style) DCB structure.


_VCOMM_Register_Enumerator

include vcomm.inc

VxDcall _VCOMM_Register_Enumerator, <OFFSET32 Enumerator>

Registers an enumerator for the currently active device node. This function is called only by plug-and-play enumerators. Uses the C calling convention.

  • Returns TRUE if successful, FALSE otherwise.
Enumerator
Address of a function that, given a device node, enumerates the devices attached to the corresponding port.

For information about plug-and-play enumerators, see "Configuration Manager."


_VCOMM_Register_Port_Driver

include vcomm.inc

VxDCall _VCOMM_Register_Port_Driver, <OFFSET32 DriverControl>
or      eax, eax
jz      error_handler

Registers a port driver VxD. Uses the C calling convention.

  • Returns TRUE if successful, FALSE otherwise.
DriverControl
Address of the port driver's DriverControl function. VCOMM calls this function to initialize a port.


Client VxD Services

Use the VCOMM client VxD services to access communications resources in a device-independent manner. For extended error information about each client VxD service, call the _VCOMM_GetLastError service.


CommNotifyProc

cCall [CommNotifyProc], <hPort, lReferenceData,     lEvent, lSubEvent>

Client-defined callback function that VCOMM calls when the transmit or receive queue passes a specified threshold or a communications event occurs.

  • No return value.
hPort
Handle of the communications resource.
lReferenceData
32-bit variable passed to _VCOMM_EnableCommNotification.
lEvent
Event type. Can be one of these values:
Value | Meaning
CN_RECEIVED | The number of bytes in the receive queue has reached the notification threshold for the receive queue.
CN_TRANSMIT | The number of bytes in the transmit queue has fallen below the notification threshold for the transmit queue.
CN_EVENT | An enabled communications event occurred.

Notification thresholds are set by the _VCOMM_EnableCommNotification service. Events are enabled by the _VCOMM_SetCommEventMask service.

lSubEvent
Enabled communications events that were detected, if the lEvent parameter is CN_EVENT. Otherwise, this parameter is ignored. Can be one or more of these values:
Value | Meaning
EV_BREAK | BREAK received.
EV_CTS | CTS changed state.
EV_CTSS | CTS state, as reported in Windows 3.1. To accurately identify the CTS state, use EV_CTSS2.
EV_CTSS2 | CTS state.
EV_DSR | DSR changed state.
EV_DSRS | DSR state, as reported in Windows 3.1. To accurately identify the DSR state, use EV_DSRS2.
EV_DSRS2 | DSR state.
EV_ERR | Line status error occurred.
EV_PERR | Printer error occurred.
EV_RING | Ring signal detected, as reported in Windows 3.1. To accurately identify the ring signal event, use EV_RING2.
EV_RING2 | Ring signal detected.
EV_RingTe | Ring trailing edge indicator.
EV_RLSD | RLSD changed state.
EV_RLSDS | RLSD state.
EV_RXCHAR | Any character received.
EV_RXFLAG1 | Received the event character specified by the EvtChar1 field of _DCB.
EV_RXFLAG2 | Received the event character specified by the EvtChar2 field of _DCB.
EV_TXEMPTY | Transmit queue empty.
EV_TXCHAR | Any character transmitted.

This function is called at interrupt time with interrupts enabled. Therefore, it must call only asynchronous VxD services and must be reentrant. If you need to disable interrupts, do so for as short a time as possible; otherwise, system performance deteriorates and characters may be lost. For time-consuming operations, it is best to schedule events and have event handlers do most of the processing.

The name CommNotifyProc is a placeholder; this function may have any name. For more information, see _VCOMM_EnableCommNotification.

See Also

_VCOMM_EnableCommNotification, _VCOMM_SetCommEventMask


_COMMPROP

include vcomm.inc

_COMMPROP   STRUC
wPacketLength       DW  ?           ;length of structure, in bytes
wPacketVersion      DW  ?           ;version of structure
dwServiceMask       DD  ?           ;see below
dwReserved1         DD  ?           ;reserved; do not use
dwMaxTxQueue        DD  ?           ;max transmit queue size. 0=not used
dwMaxRxQueue        DD  ?           ;max receive queue size. 0=not used
dwMaxBaud           DD  ?           ;maximum baud supported
dwProvSubType       DD  ?           ;see below
dwProvCapabilities  DD  ?           ;see below
dwSettableParams    DD  ?           ;see below
dwSettableBaud      DD  ?           ;see below
wSettableData       DW  ?           ;see below
wSettableStopParity DW  ?           ;see below
dwCurrentTxQueue    DD  ?           ;transmit queue size. 0=unavailable
dwCurrentRxQueue    DD  ?           ;receive queue size. 0=unavailable
dwProvSpec1         DD  ?           ;see below
dwProvSpec2         DD  ?           ;see below
wcProvChar          DW  1 DUP (?)   ;see below
_COMMPROP   ENDS

Contains information about a communications port driver. This structure is filled by the _VCOMM_GetCommProperties service.

Members

dwServiceMask
One or more values specifying the services that are implemented by the port driver. The SP_SERIALCOMM bit is always set for communications devices.
dwProvSubType
Communications provider subtype. Can be one of these values:
Value | Meaning
PST_UNSPECIFIED | Unspecified
PST_RS232 | RS-232 serial port
PST_PARALLELPORT | Parallel port
PST_RS422 | RS-422 port
PST_RS423 | RS-423 port
PST_RS449 | RS-449 port
PST_FAX | FAX device
PST_SCANNER | Scanner device
PST_NETWORK_BRIDGE | Unspecified network bridge
PST_LAT | LAT
PST_TCPIP_TELNET | TCP/IP Telnet(r)
PST_X25 | X.25 port

dwProvCapabilities
Port driver capabilities. Can be one or more of these values:
Value | Meaning
PCF_DTRDSR | Data terminal ready (DTR)/data set ready (DSR) handshaking supported.
PCF_RTSCTS | Request to send (RTS)/clear to send (CTS) handshaking supported.
PCF_RLSD | Receive line signal detect (RLSD) handshaking supported.
PCF_PARITY_CHECK | Parity checking supported.
PCF_XONXOFF | XON/XOFF handshaking supported.
PCF_SETXCHAR | Settable XON/XOFF supported.
PCF_TOTALTIMEOUTS | Total (elapsed) time-outs supported.
PCF_INTTIMEOUTS | Interval time-outs supported.
PCF_SPECIALCHARS | Special character support provided.
PCF_16BITMODE | Special 16-bit mode supported.

dwSettableParams
Communications settings that can be set. Can be one or more of these values:
Value | Meaning
SP_PARITY | Parity
SP_BAUD | Baud rate
SP_DATABITS | Data bits
SP_STOPBITS | Stop bits
SP_HANDSHAKING | Handshaking
SP_PARITY_CHECK | Parity checking
SP_RLSD | RLSD

dwSettableBaud
Available baud rates. Can be one or more of these values:
Value | Meaning
BAUD_075 | 75 bps
BAUD_110 | 110 bps
BAUD_134_5 | 134.5 bps
BAUD_150 | 150 bps
BAUD_300 | 300 bps
BAUD_600 | 600 bps
BAUD_1200 | 1200 bps
BAUD_1800 | 1800 bps
BAUD_2400 | 2400 bps
BAUD_4800 | 4800 bps
BAUD_7200 | 7200 bps
BAUD_9600 | 9600 bps
BAUD_14400 | 14,400 bps
BAUD_19200 | 19,200 bps
BAUD_38400 | 38,400 bps
BAUD_56K | 56K bps
BAUD_128K | 128K bps
BAUD_USER | Programmable baud rates available

wSettableData
Available settings for data bits per byte. Can be one or more of these values:
Value | Meaning
DATABITS_5 | 5 data bits
DATABITS_6 | 6 data bits
DATABITS_7 | 7 data bits
DATABITS_8 | 8 data bits
DATABITS_16 | Special wide path via serial hardware lines

wSettableStopParity
Available settings for stop bits and parity. Can be one or more of these values:
Value | Meaning
STOPBITS_10 | 1 stop bit
STOPBITS_15 | 1.5 stop bits
STOPBITS_20 | 2 stop bits
PARITY_NONE | No parity
PARITY_ODD | Odd parity
PARITY_EVEN | Even parity
PARITY_MARK | Mark parity
PARITY_SPACE | Space parity

dwProvSpec1, dwProvSpec2, and wcProvChar
Provider-specific data that port drivers can set in various ways. Clients should ignore these fields unless they know how the specific port driver uses them.

See Also

_VCOMM_GetCommProperties


_COMSTAT

include vcomm.inc

_COMSTAT    STRUC
BitMask         DD  ?
cbInque         DD  ?
cbOutque        DD  ?
_COMSTAT    ENDS

Contains information about the status of a communications channel and the amount of data in the receive and transmit queues. This structure is filled by _VCOMM_ClearCommError and _VCOMM_GetCommQueueStatus.

BitMask
The communications state. Can be zero or more of these values:
Value | Meaning
fCtsHold | Transmission is suspended because CTS is off.
fDsrHold | Transmission is suspended because DSR is off.
fRlsdHold | Transmission is suspended because RLSD is off.
fXoffHold | Transmission is suspended because the XOFF character was received.
fXoffSent | An XOFF handshaking character has been sent.
fEof | The end-of-file (EOF) character was received.
fTxim | An "immediate" character, specified in a previous call to the _VCOMM_TransmitCommChar service, is waiting to be transmitted.

cbInque and cbOutque
Number of characters in the receive and transmit queues.

See Also

_VCOMM_ClearCommError, _VCOMM_GetCommQueueStatus, _VCOMM_TransmitCommChar


COMMTIMEOUTS

include vcomm.inc

COMMTIMEOUTS STRUC
ReadIntervalTimeout           DD  ?  ; time-out between chars; see below
ReadTotalTimeoutMultiplier    DD  ?  ; see below
ReadTotalTimeoutConstant      DD  ?  ; see below
WriteTotalTimeoutMultiplier   DD  ?  ; see below
WriteTotalTimeoutConstant     DD  ?  ; see below
COMMTIMEOUTS ENDS

Specifies the read and write time-outs for a communications device.

Members

ReadIntervalTimeout
The maximum time, in milliseconds, allowed to elapse between the arrival of any two characters. Can be MAXDWORD, in which case a time-out occurs immediately for every read operation.
ReadTotalTimeoutMultiplier and ReadTotalTimeoutConstant
Multiplier and constant used to calculate the total time-out for a read operation. The total time-out is the number of bytes times the multiplier plus the constant. If both these values are zero, total time-outs are not used for read operations.
WriteTotalTimeoutMultiplier and WriteTotalTimeoutConstant
Multiplier and constant used to calculate the total time-out for a write operation. The total time-out is the number of bytes times the multiplier plus the constant. If both these values are zero, total time-outs are not used for write operations.


_DCB

include vcomm.inc

_DCB    STRUC
DCBLength       DD ?    ;size of the structure, in bytes
BaudRate        DD ?    ;see below
BitMask         DD ?    ;see below
XonLim          DD ?    ;see below
XoffLim         DD ?    ;see below
dwReserved      DW ?    ;reserved
ByteSize        DB ?    ;data bits per character (4-8)
Parity          DB ?    ;see below
StopBits        DB ?    ;see below
XonChar         DB ?    ;XON character for transmit and receive
XoffChar        DB ?    ;XOFF character for transmit and receive
ErrorChar       DB ?    ;parity-error replacement character
EofChar         DB ?    ;character used to signal the end of data
EvtChar1        DB ?    ;event-generating character
EvtChar2        DB ?    ;additional event character
bReserved       DB ?    ;reserved; do not use
RlsTimeout      DD ?    ;max. milliseconds to wait for RLSD
CtsTimeout      DD ?    ;max. milliseconds to wait for CTS
DsrTimeout      DD ?    ;max. milliseconds to wait for DSR
TxDelay         DD ?    ;milliseconds between transmission of chars
_DCB    ENDS

Defines the control settings for a communications resource.

Members

BaudRate
Baud rate or baud rate index. Can be one of these values:
CBR_110 | CBR_4800 | CBR_56000
CBR_300 | CBR_9600 | CBR_128000
CBR_600 | CBR_14400 | CBR_256000
CBR_1200 | CBR_19200
CBR_2400 | CBR_38400

BitMask
Communications options. Can be one or more of these values:
Value | Meaning
fBinary | Specifies binary mode. In binary mode, the character specified by the EofChar field is not recognized as ending the data stream.
fCh1Evt | Specifies that reception of the character specified by the EvtChar1 field signals an event.
fCh2Evt | Specifies that reception of the character specified by the EvtChar2 field signals an event.
fDtrDisable | Disables the DTR line. If this flag is specified, DTR is disabled when the device is opened, and remains disabled. Otherwise, DTR is enabled when the device is opened and remains enabled.
fDtrflow | Enables DTR handshaking for input. If this flag is set, DTR is turned off when the XOFF limit is reached and is turned back on when the XON limit is reached.
fEnqAck | Enables enquiry (ENQ)/acknowledgment (ACK) handshaking.
fEtxAck | Enables end-of-text (ETX)/acknowledgment (ACK) handshaking.
fInX | Enables XON/XOFF handshaking for input. If this flag is set, the XOFF character is sent when the XOFF limit is reached, and the XON character is sent when the XON limit is reached.
fNull | Specifies that received null characters are to be discarded.
fOutX | Enables XON/XOFF handshaking for output. If this flag is set, transmission is suspended when the XOFF character is received, and resumes when the XON character is received.
fOutxCtsFlow | Enables CTS handshaking for output. If this flag is set, transmission is suspended whenever CTS is off.
fOutxDsrFlow | Enables DSR handshaking for output. If this flag is set, transmission is suspended whenever DSR is off.
fParity | Enables parity checking.
fPeChar | Enables parity error replacement. If set, characters received with parity errors are replaced with the character specified by the ErrorChar field.
fRtsDisable | Disables the RTS line. If this flag is specified, RTS is disabled when the device is opened, and remains disabled. Otherwise, RTS is enabled when the device is opened and remains enabled.
fRtsflow | Enables RTS handshaking for input. If this flag is set, RTS is turned off when the XOFF limit is reached and is turned back on when the XON limit is reached.

XonLim
The XON limit. If input handshaking is enabled, handshaking signals (for example, the XON character) are sent when the number of characters in the receive queue falls below this value.
XoffLim
The XOFF limit. If input handshaking is enabled, handshaking signals (for example, the XOFF character) are sent when the number of free bytes in the receive queue falls below this value.
Parity
The type of parity to perform on input and output: NOPARITY, ODDPARITY, EVENPARITY, MARKPARITY, or SPACEPARITY.
StopBits
Specifies the number of stop bits: ONESTOPBIT, ONE5STOPBITS, or TWOSTOPBITS.

See Also

_VCOMM_GetCommState, _VCOMM_SetCommState


_QSB

include vcomm.inc

_QSB    STRUC
ReceiveQueueGetPtr      DD  ?
ReceiveQueueCount       DD  ?
_QSB    ENDS

Contains information about the receive queue. This structure is filled by the _VCOMM_SetupComm service.

Members

ReceiveQueueGetPtr
Offset, relative to the start of the queue, of the first byte of data.
ReceiveQueueCount
Number of bytes in the queue.

See Also

_VCOMM_SetupComm


_VCOMM_ClearCommError

include vcomm.inc

VxDCall _VCOMM_ClearCommError, <hPort, <OFFSET32 cmst>, \
    <OFFSET32 dwErrors>>
or      eax, eax
jz      error_handler

Reenables a port after a communications error. Uses the C calling convention. This is an asynchronous service.

  • Returns TRUE if successful, FALSE otherwise. For extended error information, use _VCOMM_GetLastError.
hPort
Handle of a communications resource.
cmst
Address of a _COMSTAT structure that receives information about the current communications state. This parameter can be NULL.
dwErrors
Address of a 32-bit variable that receives communications errors that occurred since the last call. Can be zero or more for the following values:
Value | Meaning
CE_BREAK | The hardware detected a break condition.
CE_CTSTO | CTS time-out. Transmission was suspended due to CTS for the duration specified by the CtsTimeout field of _DCB.
CE_DNS | The parallel device is not selected.
CE_DSRTO | DSR time-out. Transmission was suspended due to DSR for the duration specified by the DsrTimeout field of _DCB.
CE_FRAME | The hardware detected a framing error.
CE_IOE | An input/output (I/O) error occurred.
CE_MODE | A requested mode is not supported, or the hPort parameter is invalid. If this flag is set, this is the only valid error.
CE_OOP | The parallel device signaled that it is out of paper.
CE_OVERRUN | Character-buffer overrun. The next character is lost.
CE_PTO | Time-out on a parallel device.
CE_RLSDTO | RLSD time-out. Transmission was suspended due to RLSD for the duration specified by the RlsdTimeout field of _DCB.
CE_RXOVER | Receive queue overflow. There is either no room in the receive queue, or a character was received after the EOF character was received.
CE_RXPARITY | The hardware detected a parity error.
CE_TXFULL | The _VCOMM_WriteComm service was called when the transmit queue was full.
CE_Unused1 | Reserved; do not use.
CE_Unused2 | Reserved; do not use.

See Also

_COMSTAT, _DCB, _VCOMM_GetLastError


_VCOMM_CloseComm

include vcomm.inc

VxDCall _VCOMM_CloseComm, <hPort>
or      eax, eax
jz      error_handler

Closes a communications resource, freeing it for use by other VCOMM clients. Uses the C calling convention.

  • Returns TRUE if successful, FALSE otherwise. For extended error information, use _VCOMM_GetLastError.
hPort
Handle of a communications resource.

This service fails if the close property is PORTCLOSE_WAIT and the data remaining in the transmit queue could not be sent.

See Also

_VCOMM_GetLastError, _VCOMM_OpenComm


_VCOMM_EnableCommNotification

include vcomm.inc

VxDCall _VCOMM_EnableCommNotification, <hPort, \
    <OFFSET32 CommNotifyProc>, lReferenceData>
or      eax, eax
jz      error_handler

Registers a callback function for event notification. Uses the C calling convention.

  • Returns TRUE if successful, FALSE otherwise. For extended error information, use _VCOMM_GetLastError.
hPort
Handle of a communications resource.
CommNotifyProc
Address of a client-defined callback function that the port driver calls when an event enabled by the _VCOMM_SetCommEventMask service occurs. For more information, see CommNotifyProc. Can be NULL to disable notification.
lReferenceData
A client-defined 32-bit value that is passed to the notification function.

See Also

CommNotifyProc, _VCOMM_GetLastError, _VCOMM_SetCommEventMask


_VCOMM_Enumerate_DevNodes

include vcomm.inc

VxDCall _VCOMM_Enumerate_DevNodes
or      eax, eax
jz      NoMoreDevNodes:
mov     esi, eax
VMMCall List_Get_First
jz      NoMoreDevNodes

DevNodeLoop:
mov     ecx, [eax]
;
; Do something with devnode in ecx, preserve eax, esi
;
VMMCall List_Get_Next
jnz     DevNodeLoop

NoMoreDevNodes:

Returns the handle of the Port_instance list. A VCOMM client can use this list to find out all the current VCOMM device nodes. The caller must not delete or modify any element of this list.

  • Returns the list handle, or zero if there is an error.


_VCOMM_EscapeCommFunction

include vcomm.inc

VxDCall _VCOMM_EscapeCommFunction, <hPort, lFunc, \
    InData, <OFFSET32 OutData>>
or      eax, eax
jz      error_handler

Directs the communications port driver to carry out an extended function. Uses the C calling convention. This is an asynchronous service.

  • Returns TRUE if successful, FALSE otherwise. For extended error information, use _VCOMM_GetLastError.
hPort
Handle of a communications resource.
lFunc
Value identifying the extended function to carry out. The following common extended functions are defined in VCOMM.INC.
Value | Meaning
CLEARBREAK | Clears break condition, resuming transmission.
CLRDTR | Clears the DTR signal.
CLRRTS | Clears the RTS signal.
DUMMY | Performs no action.
GETCLOSEPROP | Returns the close property of the port driver in the address specified by the OutData parameter.
RESET | Asserts a signal on the reset line of an LPT port, if available. This can be used to reset a printer. No action is taken if the hPort parameter identifies a COM port.
SETBREAK | Sets the break condition, halting transmission.
SETCLOSEPROP | Sets the close property of the port driver to the InData parameter. The previous close property is returned in the address specified by the OutData parameter.
SETDTR | Sets the DTR signal.
SETRTS | Sets the RTS signal.
SETXOFF | Causes transmission to act as if an XOFF character has been received.
SETXON | Causes transmission to act as if an XON character has been received.

Port drivers can define additional extended functions to expose device-specific features. Extended functions can be used in conjunction with driver-defined events to facilitate two-way message passing between an application and port driver.

InData
Function-specific 32-bit parameter.
OutData
Address to receive function-specific data.

Except for GETCLOSEPROP and SETCLOSEPROP, the extended functions defined in VCOMM.INC ignore the InData and OutData parameters.

See Also

_VCOMM_CloseComm, _VCOMM_GetLastError


_VCOMM_GetCommEventMask

include vcomm.inc

VxDCall _VCOMM_GetCommEventMask, <hPort, dwMask, <OFFSET32 dwEvents>>
or      eax, eax
jz      error_handler

Retrieves and clears the specified event flags for a port. Uses the C calling convention. This is an asynchronous service.

  • Returns TRUE if successful, FALSE otherwise. For extended error information, use _VCOMM_GetLastError.
hPort
Handle of a communications resource.
dwMask
One or more of values specifying the events to retrieve and clear. For a list of events, see CommNotifyProc.
dwEvents
Address of a 32-bit variable that receives the combination of enabled events that were detected since the last call to this service.

See Also

CommNotifyProc, _VCOMM_GetLastError, _VCOMM_SetCommEventMask


_VCOMM_GetCommProperties

VxDCall _VCOMM_GetCommProperties, <hPort, <OFFSET32 cmmp>>
or      eax, eax
jz      error_handler

Gets the hardware and software capabilities and limitations of a communications resource. Uses the C calling convention.

  • Returns TRUE if successful, FALSE otherwise. For extended error information, use _VCOMM_GetLastError.
hPort
Handle of a communications resource.
cmmp
Address of a _COMMPROP structure that receives information about the supported communications settings.

See Also

_COMMPROP, _VCOMM_GetLastError


_VCOMM_GetCommQueueStatus

include vcomm.inc

VxDCall _VCOMM_GetCommQueueStatus, <hPort, <OFFSET32 cmst>>
or      eax, eax
jz      error_handler

Retrieves information about the status of a communications channel and the amount of data in the receive and transmit queues. Uses the C calling convention. This is an asynchronous service.

  • Returns TRUE if successful, FALSE otherwise. For extended error information, use _VCOMM_GetLastError.
hPort
Handle of a communications resource.
cmst
Address of a _COMSTAT structure that receives status information.

See Also

_COMSTAT, _VCOMM_GetLastError


_VCOMM_GetCommState

include vcomm.inc

VxDCall _VCOMM_GetCommState, <hPort, <OFFSET32 dcbPort>>
or      eax, eax
jz      error_handler

Gets the current communications settings for a communications resource. Uses the C calling convention.

  • Returns TRUE if successful, FALSE otherwise. For extended error information, use _VCOMM_GetLastError.
hPort
Handle of a communications resource.
dcbPort
Address of a _DCB structure that receives the current communications settings.

See Also

_DCB, _VCOMM_GetLastError, _VCOMM_SetCommState


_VCOMM_GetLastError

include vcomm.inc

VxDCall _VCOMM_GetLastError, <hPort>
mov     dwError, eax

Gets the error for the last VCOMM client VxD service called for the given port. Uses the C calling convention. This is an asynchronous service.

  • Returns the error value if successful, or zero if hPort is invalid. See the following.
hPort
Handle of a communications resource.

The following error values are defined:

Value | Meaning
IE_BADID | A bad handle was used as a parameter.
IE_BAUDRATE | The specified baud rate is not supported. This error is specific to the _VCOMM_SetCommState service.
IE_BYTESIZE | The specified number of data bits is not supported. This error is specific to the _VCOMM_SetCommState service.
IE_CHARWAITING | A character specified in a previous call to the _VCOMM_TransmitCommChar service is waiting to be transmitted. This error is specific to the _VCOMM_TransmitCommChar service.
IE_DEFAULT | Some general error occurred.
IE_EXTINVALID | The port driver does not support the specified extended function. This error is specific to the _VCOMM_EscapeCommFunction service.
IE_TIMEOUT | The port could not be closed because the remaining data in the transmit queue could not be sent. This error is specific to the _VCOMM_CloseComm service.

See Also

_VCOMM_CloseComm, _VCOMM_EscapeCommFunction, _VCOMM_SetCommState, _VCOMM_TransmitCommChar, _VCOMM_WriteComm


_VCOMM_GetModemStatus

include vcomm.inc

VxDCall _VCOMM_GetModemStatus, <hPort, <OFFSET32 dwModemStatus>>
or      eax, eax
jz      error_handler

Retrieves the current value of the modem-status register. Uses the C calling convention. This is an asynchronous service.

  • Returns TRUE if successful, FALSE otherwise. For extended error information, use _VCOMM_GetLastError.
hPort
Handle of a communications resource.
dwModemStatus
Address of a 32-bit variable to receive the modem status. This can be a combination of the following values:
Value | Meaning
MS_CTS_ON | CTS is on.
MS_RING_ON | Ring indicator is on.
MS_RLDS_ON | RLSD is on.
MS_DSR_ON | DSR is on.

See Also

_VCOMM_GetLastError


_VCOMM_GetSetCommTimeouts

VxDCall _VCOMM_GetSetCommTimeouts, <hPort, <OFFSET32 cmto>, \
        dwAction>
or      eax, eax
jz      error_handler

Gets or sets the read and write time-outs for a communications resource.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Handle of a communications resource.
cmto
Address of a COMMTIMEOUTS structure that receives the read and write time-outs for the port, or specifies new time-outs.
dwAction
Value specifying whether to get or set the time-outs: 0 to get and 1 to set.

See Also

COMMTIMEOUTS


_VCOMM_OpenComm

include vcomm.inc

VxDCall _VCOMM_OpenComm, <<OFFSET32 PortName>, VMId>
mov     hPort, eax

Opens a communications resource. Uses the C calling convention.

  • Returns a communications resource handle, if successful. Otherwise, returns one of these values:
Value | Meaning
IE_BADID | The port does not exist or no port driver is registered for it.
IE_OPEN | The port is already open.

PortName
Address of a null-terminated string that specifies the port name.
VMId
Handle of the VM to which ownership of the port is assigned, or -1 to open the port in exclusive mode. This parameter is ignored unless a VxD is installed that virtualizes the port and detects contention. For COMM ports 1 through 4, VCD.386 detects contention.

To close the communications resource, use the _VCOMM_CloseComm service. You must close any communications resource you open. A VxD that opens a communications resource for use in a virtual machine (VM) must process the VM_Not_Executeable event to close the resource if the VM terminates.

See Also

_VCOMM_CloseComm


_VCOMM_PurgeComm

include vcomm.inc

VxDCall _VCOMM_PurgeComm, <hPort, dwQueueType>
or      eax, eax
jz      error_handler

Discards information in the receive or transmit queue, and cancels pending read or write operations. Uses the C calling convention.

  • Returns TRUE if successful, FALSE otherwise. For extended error information, use _VCOMM_GetLastError.
hPort
Handle of a communications resource.
dwQueueType
The queue to purge: 0 for transmit queue, 1 for receive queue.

See Also

_VCOMM_GetLastError


_VCOMM_ReadComm

include vcomm.inc

VxDCall _VCOMM_ReadComm, <hPort, <OFFSET32 achBuffer>, \
    cchRequested, <OFFSET32 cchReceived>>
or      eax, eax
jz      error_handler

Reads characters from the receive queue for the specified port, and returns immediately. Uses the C calling convention. This is an asynchronous service.

  • Returns TRUE if successful, FALSE otherwise. For extended error information, use _VCOMM_GetLastError.
hPort
Handle of a communications resource.
achBuffer
Address of a buffer that receives the data.
cchRequested
Number of characters to read from the receive queue.
cchReceived
Address of a 32-bit variable that receives the number of characters to read. This value is less than cchRequested if the receive queue does not contain enough characters; it is zero if a communications error occurs.

If a communications error has occurred, the service returns TRUE, but doesn't read any characters. In this case, call _VCOMM_ClearCommError.

See Also

_VCOMM_ClearCommError, _VCOMM_GetLastError


_VCOMM_SetCommEventMask

include vcomm.inc

VxDCall _VCOMM_SetCommEventMask, <hPort, dwMask, <OFFSET32 dwEvents>>
or      eax, eax
jz      error_handler

Sets the event mask and the location of the event variable.

  • Returns TRUE if successful, FALSE otherwise. For extended error information, use _VCOMM_GetLastError.
hPort
Handle of a communications resource.
dwMask
The event mask for the communications resource. For a list of events, see CommNotifyProc.
dwEvents
Address of the event variable. Because the port driver updates the event variable at interrupt time, it must be in locked memory. If this parameter is NULL, the location of the event variable is not changed.

See Also

CommNotifyProc, _VCOMM_GetCommEventMask, _VCOMM_GetLastError


_VCOMM_SetCommState

include vcomm.inc

VxDCall _VCOMM_SetCommState, <hPort, <OFFSET32 dcbPort>, ActionMask>
or      eax, eax
jz      error_handler

Sets the hardware and software state of a communications resource. Uses the C calling convention. This is an asynchronous service.

  • Returns TRUE if successful, FALSE otherwise. For extended error information, use _VCOMM_GetLastError.
hPort
Handle of a communications resource.
dcbPort
Address of a _DCB structure that contains device control information.
ActionMask
One or more values specifying the communications settings to change. To change a setting, specify the flag with the same name (plus the f prefix) as the corresponding _DCB field.
fBaudRate | fStopBits | fEvtChar2
fBitMask | fXonChar | fRlsTimeout
fXonLim | fXoffChar | fCtsTimeout
fXoffLim | fErrorChar | fDsrTimeout
fByteSize | fEofChar | fTxDelay
fParity | fEvtChar1

See Also

_DCB, _VCOMM_GetCommState, _VCOMM_GetLastError


_VCOMM_SetReadCallback

VxDCall _VCOMM_SetReadCallback, <hPort, RxTrigger, \
    <OFFSET32 CommNotifyProc>, lReferenceData>
or      eax, eax
jz      error_handler

Sets the notification threshold for the receive queue and registers a callback function for receive-queue threshold notification.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Handle of a communications resource.
RxTrigger
Receive-queue notification threshold. When the number of bytes in the receive queue reaches this value, the port driver calls the function specified by the CommNotifyProc parameter. Can be -1 to disable receive-queue notification.
CommNotifyProc
Address of the callback function for receive-queue notification. Can be different from the notification function for event notification and transmit-queue notification. For more information, see the CommNotifyProc function.
lReferenceData
A client-defined 32-bit value that is passed to the callback function. Can be different from the reference data specified for event notification and transmit-queue notification.

See Also

CommNotifyProc


_VCOMM_SetupComm

include vcomm.inc

VxDCall _VCOMM_SetupComm, <hPort, <OFFSET32 RxQueue>, cbRxQueue, \
    <OFFSET32 TxQueue>, cbTxQueue>
or      eax, eax
jz      error_handler

Sets the receive and transmit queues for a communications resource. Any characters in the previous receive and transmit queues are discarded. Uses the C calling convention.

  • Returns TRUE if successful, FALSE otherwise. For extended error information, use _VCOMM_GetLastError.
hPort
Handle of a communications resource.
RxQueue and cbRxQueue
Base address and size of the receive queue.
TxQueue and cbTxQueue
Base address and size of the transmit queue.

See Also

_VCOMM_GetLastError, _QSB


_VCOMM_SetWriteCallback

VxDCall _VCOMM_SetWriteCallback, <hPort, TxTrigger, \
    <OFFSET32 CommNotifyProc>, lReferenceData>
or      eax, eax
jz      error_handler

Sets the notification threshold for the transmit queue and registers a callback function for transmit-queue threshold notification.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Handle of a communications resource.
TxTrigger
Transmit-queue notification threshold. When the number of bytes in the transmit queue reaches this value, the port driver calls the function specified by the CommNotifyProc parameter. Can be -1 to disable transmit-queue notification.
CommNotifyProc
Address of the callback function for transmit-queue notification. Can be different from the notification function for event notification and receive-queue notification. For more information, see the CommNotifyProc function.
lReferenceData
A client-defined 32-bit value that is passed to the callback function. Can be different from the reference data specified for event notification and receive-queue notification.

See Also

CommNotifyProc


_VCOMM_TransmitCommChar

include vcomm.inc

VxDCall _VCOMM_TransmitCommChar, <hPort, ch>
or      eax, eax
jz      error_handler

Sends a high-priority character to a port, ahead of any data in the transmission queue. Uses the C calling convention. This is an asynchronous service.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Handle of a communications resource.
ch
Character to transmit.

With most port drivers, this service does not actually send the character before returning, but instead stores it in a special one-character buffer. The service fails if a character specified in a previous call to _VCOMM_TransmitCommChar has not yet been sent.

See Also

_VCOMM_GetLastError


_VCOMM_WriteComm

include vcomm.inc

VxDCall _VCOMM_WriteComm, <hPort, <OFFSET32 achBuffer> \
    cchRequested, <OFFSET32 cchWritten>>
or      eax, eax
jz      error_handler

Writes characters to the transmit queue for the specified communications resource, and returns immediately. Uses the C calling convention. This is an asynchronous service.

  • Returns TRUE if successful, FALSE otherwise. For extended error information, use _VCOMM_GetLastError.
hPort
Handle of a communications resource.
achBuffer
Address of an array of characters to write.
cchRequested
Number of characters to write.
cchWritten
Address of a 32-bit variable that receives the number of characters actually written. This can be less than the cchRequested parameter if the transmit queue does not contain enough free bytes, or a communications error has occurred.

See Also

_VCOMM_ClearCommError, _VCOMM_GetLastError


Protected-Mode Application Programming Interface Functions

You can use the VCOMM protected-mode API (PM API) to call VCOMM from within a protected-mode VM. This API is intended for use by COMM.DRV. In general, applications should use the communications functions in the Windows API.


VCOMM_PM_API_cevt

include vcomm.inc

mov     ebx, hPort
mov     cx, evmask
les     dx, mymask
mov     ax, VCOMM_PM_API_cevt
call    [_VCOMMCallAddr]

Calls the _VCOMM_SetCommEventMask service. Uses AX.

  • Returns zero in AX if successful, or an error value otherwise.
hPort
Communications resource handle.
evmask
The low word of event mask, which contains the bits that duplicate the Windows 3.1 functionality. VCOMM sets the high word to zero.
mymask
Address of the event variable in the client's VM. Because the port driver updates this value at interrupt time, it must be in locked memory.

See Also

_VCOMM_SetCommEventMask


VCOMM_PM_API_cevtget

include vcomm.inc

mov     ebx, hPort
mov     cx, evmask
les     dx, oldmask
mov     ax, VCOMM_PM_API_cevtget
call    [_VCOMMCallAddr]

Calls the _VCOMM_GetCommEventMask service. Uses AX.

  • Returns zero in AX if successful, or an error value otherwise.
hPort
Communications resource handle.
evmask
The low word of event mask, which contains the bits that duplicate the Windows 3.1 functionality. VCOMM sets the high word to zero.
oldmask
Address of a 32-bit variable that receives the combination of enabled events that were detected since the last call to this service.

See Also

CommNotifyProc, _VCOMM_GetCommEventMask


VCOMM_PM_API_cextnfcn

include vcomm.inc

mov     ebx, hPort
mov     cx, func
mov     ax, VCOMM_PM_API_cextnfcn
call    [_VCOMMCallAddr]

Calls the _VCOMM_EscapeCommFunction service. Uses AX and DX.

  • Returns a function-specific 32-bit value in AX:DX (low word in AX).
hPort
Communications resource handle.
func
Function to carry out.

VCOMM assumes zero for the InData parameter and NULL for the OutData parameter for _VCOMM_EscapeCommFunction.

See Also

_VCOMM_EscapeCommFunction


VCOMM_PM_API_cFlush

include vcomm.inc

mov     ax, VCOMM_PM_API_cFlush     ;function number
mov     ebx, hPort
mov     cx, queue
call    [_VCOMMCallAddr]

Calls the _VCOMM_PurgeComm service. Uses AX.

  • Returns zero in AX if successful, or an error value otherwise.
hPort
Communications resource handle.
queue
The queue to purge: 0 for transmit queue, 1 for receive queue.

See Also

_VCOMM_PurgeComm


VCOMM_PM_API_ctx

include vcomm.inc

mov     ebx, hPort
mov     cl, chx
mov     ax, VCOMM_PM_API_ctx
call    [_VCOMMCallAddr]

Calls the _VCOMM_TransmitCommChar service.

  • Returns zero in AX if successful, or an error value otherwise.
hPort
Communications resource handle.
chx
Character to transmit.

See Also

_VCOMM_TransmitCommChar


VCOMM_PM_API_EnableNotify

include vcomm.inc

mov     ebx, hPort
mov     di, Selector                   ;segment address of notification
shl     edi, 16                        ;  function in high word of EDI
mov     di, OFFSET CommNotifyProc      ;  and offset address in low word
mov     cx, hwnd                       ;reference data (window handle)
mov     dx, recvt
mov     si, sendt
mov     ax, VCOMM_PM_API_EnableNotify  ;function number
call    [_VCOMMCallAddr]

Calls the _VCOMM_EnableCommNotification service.

  • Returns zero in AX if successful, or an error value otherwise.
hPort
Communications resource handle.
CommNotifyProc
Address of a notification function in the VM. For more information, see CommNotifyProc.
hwnd
Reference data that is passed to the notification function. COMM.DRV specifies the handle of the window to receive notification messages.
recvt
Receive-queue notification threshold.
sendt
Transmit-queue notification threshold.

Because the notification function is in a VM, VCOMM does not pass its address to the port driver. Instead, it passes the address of an internal function. When the port driver calls the internal function, it schedules an event and the event handler uses the nested execution mechanism to call the notification function.

See Also

CommNotifyProc, _VCOMM_EnableCommNotification


VCOMM_PM_API_OPENCOM

include vcomm.inc

mov     ax, VCOMM_PM_API_OPENCOM    ;function number
mov     bx, PortNum                 ;port number
call    [_VCOMMCallAddr]            ;protected-mode API address

Calls _VCOMM_OpenComm to opens a communications resource.

  • Returns a communications resource handle if successful, otherwise, returns IE_BADID or IE_OPEN.
PortNum
The number of the port to open.

See Also

_VCOMM_OpenComm


VCOMM_PM_API_ReadString

include vcomm.inc

mov     ax, VCOMM_PM_API_ReadString  ;function number
mov     ebx, hPort
les     dx, buf
mov     cx, cnt
mov     si, es            ;address of buffer in si:dx
les     di, res           ;address to receive count in es:di
call    [_VCOMMCallAddr]

Calls the _VCOMM_ReadComm service.

  • Returns zero in AX if successful, or an error value otherwise.
hPort
Communications resource handle.
buf
Address of buffer that receives the data.
cnt
Number of characters to read.
res
Address of a 32-bit variable that receives the number of characters read.

See Also

_VCOMM_ReadComm


VCOMM_PM_API_SetCom

include vcomm.inc

mov     ax, VCOMM_PM_API_SetCom     ;function number
mov     ebx, hPort
les     dx, pDcb                    ;ES:DX -> DCB
call    [_VCOMMCallAddr]            ;protected-mode API address

Sets the state of a communications resource.

  • Returns zero in AX if successful, or an error value otherwise.
hPort
Communications resource handle.
pDcb
Address of a _DCB structure that receives the current communications settings.

See Also

_DCB, _VCOMM_SetCommState


VCOMM_PM_API_SetMSRShadow

include vcomm.inc

mov     ebx, hPort
les     dx, myshadow
mov     ax, VCOMM_PM_API_SetMSRShadow
call    [_VCOMMCallAddr]

Sets the address of the modem status shadow. There is no corresponding VCOMM service. VCOMM calls the PortSetModemStatusShadow port-driver function when this function is called.

  • Returns zero in AX if successful, or an error value otherwise.
hPort
Communications resource handle.
myshadow
Address of the modem status shadow.


VCOMM_PM_API_Setup

include vcomm.inc

mov     ax,VCOMM_PM_API_Setup       ;function number
cCall   [_VCOMMCallAddr], <hPort, InQueue, InSize, OutQueue, OutSize>
add     sp, 16

Calls the _VCOMM_SetupComm service.

  • Returns zero in AX if successful, or an error value otherwise.
hPort
Communications resource handle.
InQueue and InSize
Base address and size of the receive queue.
OutQueue and OutSize
Base address and size of the transmit queue.

See Also

_VCOMM_SetupComm


VCOMM_PM_API_StaCom

include vcomm.inc

mov     ax, VCOMM_PM_API_StaCom     ;function number
mov     ebx, hPort
les     dx, pstat
call    [_VCOMMCallAddr]
pop     ebx

Calls the _VCOMM_ClearCommError service.

  • Returns zero in AX if successful, or an error value otherwise.
hPort
Communications resource handle.
pstat
Address of a _COMSTAT structure that receives information about the current communications state.

See Also

_VCOMM_ClearCommError


VCOMM_PM_API_TrmCom

include vcomm.inc

mov     ebx, hPort
mov     ax, VCOMM_PM_API_TrmCom     ;function number
call    [_VCOMMCallAddr]

Calls the _VCOMM_CloseComm service.

  • Returns zero in AX if successful, or an error value otherwise.
hPort
Communications resource handle.

See Also

_VCOMM_CloseComm


VCOMM_PM_API_WriteString

include vcomm.inc

        les     dx, buf               ;string to write in ES:DX
        mov     cx, cnt               ;count in CX
        cmp     cx, 1
        jne     @F
        mov     di, dx
        movzx   si, byte ptr es:[di]
@@:     mov     ebx, hPort
        mov     ax, VCOMM_PM_API_WriteString  ;function number
        call    [_VCOMMCallAddr]

Calls the _VCOMM_WriteComm service.

  • Returns zero in AX if successful, or an error value otherwise.
hPort
Communications resource handle.

See Also

_VCOMM_WriteComm


Contention Management Functions

This section describes the _VCOMM_Get_Contention_Handler function, the VCOMM_Map_Name_To_Resource function, and the functions used to call a contention handler. The _VCOMM_Get_Contention_Handler service retrieves a pointer to one of the functions documented in this section.


_VCOMM_Get_Contention_Handler

include vcomm.inc

VxDCall _VCOMM_Get_Contention_Handler<OFFSET32 PortName>
or      eax, eax
jz      error_handler
mov     dwContentionHandler, eax

Returns a pointer to a function used to call a contention handler. The function is either in VCOMM itself or another VxD that manages contention for a VCOMM resource. It is used with the resource handle returned by VCOMM_Map_Name_To_Resource to make requests of the contention handler. The contention management requests are described in the following.

  • Returns a pointer to a function used to call a contention handler if successful, or an error otherwise. To get extended error information, use _VCOMM_GetLastError.
PortName
Buffer that contains the address of a null-terminated string specifying the name of the port or the friendly name of the port.

See Also

ACQUIRE_RESOURCE, VCOMM_Map_Name_To_Resource, RELEASE_RESOURCE, STEAL_RESOURCE, VCOMM_Map_Name_To_Resource


VCOMM_Map_Name_To_Resource

include vcomm.inc

VxDCall VCOMM_Map_Name_To_Resource<OFFSET32 PortName>
or      eax, eax
jz      error_handler
mov     dwResourceHandle, eax

Returns a handle to a named resource. This handle is used in calls to the contention manager of a VCOMM resource.

  • Returns a handle to a named resource if successful, or zero otherwise.
PortName
Buffer that contains the address of a null-terminated string specifying the name of the port or the friendly name of the port.

See Also

ACQUIRE_RESOURCE, VCOMM_Map_Name_To_Resource, RELEASE_RESOURCE, STEAL_RESOURCE, _VCOMM_Get_Contention_Handler


ACQUIRE_RESOURCE

include vcomm.inc

cCall   dwContentionHandler<ACQUIRE_RESOURCE, dwResourceHandle, dwNotify,
        dwRefData, fSteal>
or      eax, eax
jz      error_handler
mov     dwAcquireHandle, eax

Requests access to a VCOMM resource, stealing from a current owner if necessary.

  • Returns a handle to an acquired resource. This is often the same as the handle specified by dwResourceHandle, but it does not have to be.
dwResourceHandle
Handle returned by VCOMM_Map_Name_To_Resource for the resource.
dwNotify
Address of a callback function that receives steal and return notifications.
dwRefData
Address of data that is private to the caller and passed to the notification function.
fSteal
One of the following flags:
ACQUIRE_STEAL | Attempt to steal from current owner, if any.
ACQUIRE_NO_STEAL | Acquire only if there is no current owner.

ACQUIRE_RESOURCE fails if there are already two clients sharing the resource, one active and one waiting.

A client's callback function is called as follows:

cCall   [<e>dwNotify</e>],<[<e>dwRefData</e>],<e>dwNotification</e>

A client's callback function may receive any of the following notifications, specified in dwNotification:

0 = RESOURCE_STEAL_REQUEST | Notifies the client that another client is attempting to acquire or steal the resource specified in dwRefData. The client should save the resource state, if necessary, and return TRUE to allow the resource to be stolen. Otherwise, it should return FALSE to prevent it from being stolen. A client can optionally release the resource before returning TRUE.
1 = RESOURCE_STEAL_NOTIFY | Notifies the client that a previously stolen resource has been returned to it. The client must restore the state of the device, if necessary.

See Also

_VCOMM_Get_Contention_Handler, VCOMM_Map_Name_To_Resource


RELEASE_RESOURCE

include vcomm.inc

cCall   dwContentionHandler<RELEASE_RESOURCE, dwAcquireHandle, dwNotify>

Releases a previously acquired resource.

  • Returns FALSE if dwAcquireHandle or lpfnNotify are not valid, or TRUE if the release is successful.
dwAcquireHandle
Handle returned by the original ACQUIRE_RESOURCE call.
lpfnNotify
Function pointer provided to ACQUIRE_RESOURCE for notification.

See Also

_VCOMM_Get_Contention_Handler, VCOMM_Map_Name_To_Resource


STEAL_RESOURCE

include vcomm.inc

cCall   dwContentHandler<STEAL_RESOURCE, dwAcquireHandle, dwNotify>
or      eax, eax
jz      not_yet
mov     dwAcquireHandle, eax

not_yet:

Attempts to reacquire a previously stolen resource. The caller must have successfully acquired the resource with an earlier ACQUIRE_RESOURCE call.

  • Returns FALSE if the resource is not reacquired, or TRUE if the resource is stolen from the current owner or if dwAcquireHandle is already the current owner.
dwAcquireHandle
Handle returned from the original ACQUIRE_RESOURCE call.
dwNotify
Function pointer provided to ACQUIRE_RESOURCE for notification.

See Also

_VCOMM_Get_Contention_Handler


Legacy Contention Functions

These functions are provided for backward compatibility with Windows 3.x and should be used only for that purpose. These functions use only VCD for contention management and apply, therefore, only to ports managed by VCD. In general, the contention management functions specified earlier in "Contention Management Functions" are recommended.


_VCOMM_Acquire_Port

include vcomm.inc

VxDCall _VCOMM_Acquire_Port, <OFFSET32 szVxDName>, \
    lPortNum, VMId, lFlags>
mov     PortHandle, eax

Blocks access to a port by applications running in virtual machines (VMs). A port driver should call this service when its PortOpen function is called.

  • Returns a port handle if successful, or zero if the port is already in use.
szVxDName
Address of a null-terminated string specifying the name of the port driver.
lPortNum
Hardware port number. Port numbers 0-7Fh specify COM ports 1-80h.
VMId
Handle of the VM to which ownership of the port is assigned (-1 means the owner is a VxD).
lFlags
Must be zero.


_VCOMM_Release_Port

include vcomm.inc

VxDCall _VCOMM_Release_Port<PortHandle, VMID>

Releases the blocking of access to the specified port by other VxDs and applications.

  • No return value.
PortHandle
Port handle returned by the original call to _VCOMM_Acquire_Port.
VMId
Handle of the VM that owns the port (-1 means the owner is a VxD).


_VCOMM_Steal_Port

include vcomm.inc

VxDCall _VCOMM_Steal_Port <PortHandle, VMId>

Steals a port, if possible, from other owners. Before the caller steals a port, it must acquire it by calling _VCOMM_Acquire_Port.

  • Returns TRUE if successful, or zero for failure.
PortHandle
Port handle returned by the original call to _VCOMM_Acquire_Port.
VMId
Handle of the VM that owns the port (-1 means the owner is a VxD).


Communications Port Drivers

Port drivers are virtual devices (VxDs) that the Windows 95 virtual communications driver (VCOMM) uses to access communications ports. Port drivers for common serial and LPT devices are included with Windows 95. Hardware vendors can create additional port drivers to enable Microsoft® Windows™-based applications and VxDs to use other communications devices.


Driver Loading and Unloading

Port drivers are loaded either at boot time or upon demand, depending on the version of Windows and whether the port driver is plug-and-play compliant.

Port drivers that do not comply with plug-and-play are loaded statically at boot time. (The same is true for all port drivers under versions of Windows prior to Windows 95.) In such cases, the port driver must have an entry in the [386Enh] section of the SYSTEM.INI file. With Windows 95, this section causes a device node to be created. Static port drivers are unloaded only when Windows 95 exits.

Windows 95 loads plug-and-play port drivers when a VCOMM client attempts to open a port that the driver supports. Plug-and-play port drivers are unloaded when all ports supported by the driver are closed.


Port Enumeration

At boot time, enumerators create device nodes for each plug-and-play communications device in the system, specifying VCOMM as the device loader. The system calls VCOMM for each device, specifying the corresponding device node. VCOMM is also called if plug-and-play communications are added to the system at run time. If the device node specifies an enumerator, VCOMM loads the enumerator.

After being loaded, the enumerator registers itself with VCOMM by calling the CONFIGMG_Register_Enumerator service. It then adds device nodes for any plug-and-play devices attached to the port. The enumerator and port driver should be separate components because the enumerator is always present, but the port driver is present only when needed. However, the enumerator should use the port driver to access the device.

The following registry entries exist for plug-and-play devices supported by VCOMM and port drivers.

[...\PNPID\Instance_Num]
DeviceDesc=Description of device (optional)
BootConfig=Configuration (I/O ports and IRQs found at boot time)
Class=Device class (optional)
PortName=Port name of the form COMx, LPTx, and so on
FriendlyName=Friendly name by which the port can be opened

[...\PNPID\Instance_Num\DRV]
DevLoader=VCOMM
PortDriver=Driver name
FriendlyDriver=Friendly name of port driver (optional)
Enumerator=Name of detection module for plug-and-play devices
    attached to the port (optional)
DeviceType=Type of device. Can be a combination of flags, such
    as PST_RS232, PST_LPT, and PST_MODEM

[...\PNPID\Instance_Num\logConfig]
0=Preferred logical configuration
1=Allowed logical configuration 1 (optional)
    .
    .
    .
n=Allowed logical configuration n (optional)

See Also

CONFIGMG_Register_Enumerator


Initialization

At load time, a port driver must register itself with VCOMM by calling the _VCOMM_Register_Port_Driver service. Static port drivers register when they receive the Sys_Device_Init control message. Dynamic (plug-and-play) port drivers register when they receive the Sys_Dynamic_Device_Init control message.

Before the _VCOMM_Register_Port_Driver service returns, VCOMM calls the port driver's DriverControl function, specifying the DC_InitializePort action. For plug-and-play port drivers, VCOMM calls the function once for each port supported by the driver. For other port drivers, VCOMM calls the function exactly once. The port driver must check for the existence of the port (or ports), and then calls the _VCOMM_Add_Port service.

See Also

DriverControl, _VCOMM_Add_Port, _VCOMM_Register_Port_Driver


Requests

VCOMM requests that a port driver carry out specific operations by calling port driver functions — that is, callback functions provided by the port driver. Most port driver functions correspond to specific VCOMM services. A port driver may support a subset of the port driver functions. The following sections briefly describe the various port driver functions.


Open and Close Functions

To open the port, VCOMM calls the PortOpen function for the port driver that best supports the device. If successful, the PortOpen function returns the address of a _PORTINFORMATION structure. This address is used to identify the open port in all subsequent calls to port driver functions. The first field of the _PORTINFORMATION structure must be a _PORTDATA structure, but additional fields can be defined by the port driver. The _PORTDATA structure contains information about an open communications device that is used by VCOMM, the port driver, or both. It includes a pointer to the port driver's _PORTFUNCTIONS structure, that contains the addresses of all the port driver functions except Enumerator, Inquire, and PortOpen.

To close a communications port, VCOMM calls the port driver's PortClose function.

See Also

PortClose, _PORTDATA, _PORTFUNCTIONS, _PORTINFORMATION, PortOpen


Configuration Functions

When a port driver opens a communications port, it initializes it using a default configuration. A port's configuration is defined by its device control block, a _DCB structure. To enable a client to get and set the current configuration, a port driver provides the PortGetCommState and PortSetCommState functions.

The communications settings supported by a communications device are defined by a _COMMPROP structure. To enable a client to determine the available configuration settings, you must provide the PortGetProperties function.

A port driver initializes a port's receive and transmit queues to default sizes it specifies. To enable a client to override these, the port driver must provide the PortSetup function.

See Also

_COMMPROP, _DCB, PortGetCommState, PortGetProperties, PortSetCommState, PortSetup


Read and Write Functions

To enable communications output, a port driver should provide a PortWrite function. For port drivers that use a transmit queue, the PortWrite function writes to the queue and returns immediately; an interrupt service routine actually sends the data. For port drivers that do not use a transmit queue, the PortWrite function sends the data and then returns. To enable a VCOMM client to resume transmission after a communications error, a port driver should provide a PortClearError function.

A port driver's PortTransmitChar function sends a high-priority character, such as an event character, ahead of any characters in the transmit queue. Typically, the port driver does not send the character immediately, but stores it in a special one-character buffer. The function can fail (return FALSE) if a character specified in a previous call is still waiting to be sent.

To enable communications input, a port driver should provide a PortRead function. For output-only devices, such as LPT ports, the PortRead function should simply return TRUE (success), and indicate zero bytes read. For port drivers that use a receive queue, the PortRead function should retrieve data from the receive queue and return immediately; an interrupt service routine actually reads data into the receive queue. The amount of data retrieved from the queue may be less than the amount requested. For port drivers that do not use a receive queue, the PortRead function actually reads data from the device. The amount of data read is less than the amount requested only if a read time-out occurs, in which case the return value is FALSE.

A port driver's PortGetQueueStatus function retrieves the status of the receive and transmit queues. A port driver's PortPurge function discards the contents of the transmit or receive queue.

See Also

PortClearError, PortGetQueueStatus, PortPurge, PortRead, PortTransmitChar, PortWrite


Event Functions and Extended Functions

VCOMM clients can request that they be notified when communications events occur or when queue thresholds reach specified limits. In addition, VCOMM clients can enable or disable specific events and specify the location of the event variable.

To support event notification, a port driver provides the PortEnableNotification function. This function registers a callback function that the port driver calls when enabled events occur. Enabled events are specified by a 32-bit variable called the event mask. A port driver's PortSetEventMask and PortGetEventMask functions set and retrieve the event mask, and may also specify the location of the event variable. The PortSetModemStatusShadow function may also set the event mask.

To support queue threshold notifications, a port driver provides the PortSetReadCallback and PortSetWriteCallback functions. These functions set the notification thresholds for the receive and transmit queues, respectively, and register callback functions that the port driver calls when these thresholds are reached.

The PortEscapeFunction function enables port drivers to define extended functions. A set of common extended functions is defined in VCOMM.INC in the Windows 95 DDK. By defining additional extended functions, a port driver can expose capabilities of a device that are not otherwise defined by the communications API. Extended functions can be used in conjunction with driver-defined events to facilitate two-way message passing between a VCOMM client and a port driver.

See Also

_PORTDATA, PortEnableNotification, PortEscapeFunction, PortGetEventMask, PortSetEventMask, PortSetModemStatusShadow, PortSetReadCallback, PortSetWriteCallback, _VCOMM_GetModemStatus


Notifications

When communications events occur or queue thresholds are reached, port drivers may notify VCOMM clients by calling client-defined callback functions. If possible, port drivers should also maintain the values of two variables: the modem status shadow and the event variable.

The modem status shadow is a byte that contains the current state, and the change in state, of the modem control lines: clear to send (CTS), data set ready (DSR), ring indicator, and receive line signal detect (RLSD). The value of the modem status shadow is the same as the value of the modem status register for an 8250 or similar UART.

The event variable is a 32-bit variable that contains enabled communications events that have been detected. For a list of communications events, see the description of the CommNotifyProc function.

A client application or VxD enables a specific type of notification by calling a VCOMM service, causing VCOMM to call the appropriate port driver function: PortEnableNotification, PortSetReadCallback, or PortSetWriteCallback. These functions register callback functions that the port driver is to call at interrupt time under the appropriate circumstances. For non-VxD clients, the callback function is a function within VCOMM that notifies the appropriate Windows application.

See Also

CommNotifyProc, PortEnableNotification, PortSetReadCallback, PortSetWriteCallback


Interrupt Handlers

Port drivers must install hardware interrupt handlers if they are to perform their input and output operations using queues. This is the most appropriate mechanism for interrupt-driven devices such as serial ports.

When it opens a port, a port driver installs a hardware interrupt handler by using the VPICD_Virtualize_IRQ service. When it closes the port, the port driver uses the VPICD_Force_Default_Behavior service to remove the interrupt handler.

An interrupt handler must be in locked memory, must only call functions that are in locked memory, and must only call services that are asynchronous.


Build Specifics

In general, port drivers should not provide any services. The device ID of a port driver should be Undefined_Device_ID and the initialization order should be Undefined_Init_Order.


Reference

The port driver functions and structures are separated into the following functional groups.

Group | Elements
Open and close functions | DriverControl, PortClose, _PORTDATA, _PORTFUNCTIONS, _PORTINFORMATION, PortOpen
Port configuration functions | PortGetCommConfig, PortGetCommState, PortGetProperties, PortSetCommConfig, PortSetCommState, PortGetWin32Error, PortSetup
Read and write functions | PortClearError, PortGetQueueStatus, PortPurge, PortRead, PortTransmitChar, PortWrite
Event functions and extended functions | PortEnableNotification, PortEscapeFunction, PortGetEventMask, PortGetModemStatus, PortSetEventMask, PortSetModemStatusShadow, PortSetReadCallback, PortSetWriteCallback


Open and Close Functions

The open and close functions query which communications ports a port driver supports and in what manner, as well as opening and closing communications ports.


DriverControl

cCall [pDriverControl], <DriverFunction, hDevNode, ReferenceData [,...]>

Called by the VCOMM to perform various actions. Uses the C calling convention.

  • No return value.
DriverFunction
32-bit value specifying the action to carry out. For more information, see the following.
hDevNode
Handle of the device node. This parameter is zero for port drivers that are not plug-and-play compliant, and on versions of Windows prior to Windows 95.
ReferenceData
32-bit value to pass to the _VCOMM_Add_Port service.

Additional parameters are defined for specific driver-control functions. The only function currently defined is DC_InitializePort. At registration time, VCOMM calls this function once for each port the driver supports. If a port driver does not support plug-and-play, VCOMM calls the function exactly once. The port driver should check for the existence of the port, and then call the _VCOMM_Add_Port service. Following are the parameters specific to the DC_InitializePort driver-control function:

Name | Address of a null-terminated string specifying the port name.
AllocIOBase | Base I/O address allocated to the port.
AllocIrq | Interrupt request line (IRQ) allocated to the port.

See Also

_VCOMM_Add_Port


Enumerator

cCall [pEnumerator], hDevNode

Enumerates the device nodes attached to the specified port. Uses the C calling convention.

  • No return value.
hDevNode
Handle of the device node for which the port driver appears as the enumerator in the registry.

A port driver registers itself as a device enumerator by using the _VCOMM_Register_Enumerator service.

See Also

_VCOMM_Register_Enumerator


PortClose

cCall   [pPortClose], hPort
or      eax, eax
jz      error_handler

Called by the _VCOMM_CloseComm service to close a port. Uses the C calling convention.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Address of a _PORTINFORMATION structure returned by the PortOpen function.

If the PortOpen function calls the _VCOMM_Acquire_Port service, the PortClose function must call the _VCOMM_Release_Port service.

See Also

_PORTINFORMATION, PortOpen, _VCOMM_CloseComm


_PORTDATA

include vcomm.inc

_PortData STRUC
PDLength            DW  ?  ; size of this structure
PDVersion           DW  ?  ; version of this structure
PDfunctions         DD  ?  ; address of _PORTFUNCTIONS
PDNumFunctions      DD  ?  ; last supported function
dwLastError         DD  ?  ; see below
dwClientEventMask   DD  ?  ; see below
lpClientEventNotify DD  ?  ; see below
lpClientReadNotify  DD  ?  ; see below
lpClientWriteNotify DD  ?  ; see below
dwClientRefData     DD  ?  ; see below
dwWin31Req          DD  ?  ; reserved
dwClientEvent       DD  ?  ; see below
dwCallerVMID        DD  ?  ; reserved
dwDetectedEvents    DD  ?  ; see below
dwCommError         DD  ?  ; detected I/O errors; see below
bMSRShadow          DB  ?  ; see below
wFlags              DW  ?  ; reserved
LossByte            DB  ?  ; reserved
QInAddr             DD  ?  ; base address of receive queue
QInSize             DD  ?  ; size of receive queue
QOutAddr            DD  ?  ; base address of transmit queue
QOutSize            DD  ?  ; size of transmit queue
QInCount            DD  ?  ; num. bytes in receive queue
QInGet              DD  ?  ; see below
QInPut              DD  ?  ; see below
QOutCount           DD  ?  ; num. bytes in transmit queue
QOutGet             DD  ?  ; see below
QOutPut             DD  ?  ; see below
ValidPortData       DD  ?  ; reserved
lpLoadHandle        DD  ?  ; see below
cmto COMMTIMEOUTS <>       ; see below
lpReadRequestQueue  DD  ?  ; reserved
lpWriteRequestQueue DD  ?  ; reserved
dwLastReceivedTime  DD  ?  ; time of last reception of data
dwReserved1         DD  ?  ; reserved
dwReserved2         DD  ?  ; reserved
_PortData ENDS

Contains information about an open port. Some of the information in this structure is used by VCOMM, and some by the port driver. The port driver is responsible for initializing the fields whose names begin with PD.

Members

dwLastError
Error value for the last operation. The port driver sets this value during each call to a port-driver function.
dwClientEventMask
Zero or more values specifying enabled communications events. VCOMM sets this value when the _VCOMM_SetCommEventMask service is called. For a list of events, see the PortGetEventMask function.
lpClientEventNotify, lpClientReadNotify, and lpClientWriteNotify
Addresses of client-defined callback functions for event notification, receive-queue threshold notification, and transmit-queue threshold notification.
dwClientRefData
Reference data for event notification (not for threshold notifications). The port driver sets this value when the PortEnableNotification function is called.
dwClientEvent
One or more values specifying detected events that VCOMM is waiting to sent to a non-VxD client. Port drivers should ignore this field.
dwDetectedEvents
One or more values specifying enabled events that were detected. The port driver maintains this value. For a list of events, see the PortGetEventMask function.
dwCommError
Value specifying detected I/O errors. The port driver maintains this value. For a list of possible values, see the _VCOMM_ClearCommError service.
bMSRShadow
The initial location of the modem status shadow. The port driver must update this value whenever the register changes. The PortSetModemStatusShadow function sets the location of the modem status shadow.
QInGet and QInPut
Current read and write offsets within the receive queue. The first character in the queue is at the location specified by QInGet. Additional characters are added to the queue starting at the location specified by QInPut. Both VCOMM and the port driver modify these values.
QOutGet and QOutPut
Current read and write offsets within the transmit queue. The first character in the queue is at the location specified by QInGet. Additional characters are added to the queue starting at the location specified by QInPut. Both VCOMM and the port driver modify these values.
lpLoadHandle
Load handle of the port-driver VxD. This field is used by VCOMM only.
cmto
A COMMTIMEOUTS structure specifying the read and write time-outs for the communications port.

See Also

commtimeouts, PortEnableNotification, _PORTFUNCTIONS, PortGetEventMask, PortSetModemStatusShadow, _VCOMM_ClearCommError, _VCOMM_SetCommEventMask


_PORTFUNCTIONS

include vcomm.inc

_PortFunctions STRUC
pPortSetState               DD  ?  ; address of PortSetState
pPortGetState               DD  ?  ; address of PortGetState
pPortSetup                  DD  ?  ; address of PortSetup
pPortTransmitChar           DD  ?  ; address of PortTransmitChar
pPortClose                  DD  ?  ; address of PortClose
pPortGetQueueStatus         DD  ?  ; address of PortGetQueueStatus
pPortClearError             DD  ?  ; address of PortClearError
pPortSetModemStatusShadow   DD  ?  ; address of PortSetModemStatusShadow
pPortGetProperties          DD  ?  ; address of PortGetProperties
pPortEscapeFunction         DD  ?  ; address of PortEscapeFunction
pPortPurge                  DD  ?  ; address of PortPurge
pPortSetEventMask           DD  ?  ; address of PortSetEventMask
pPortGetEventMask           DD  ?  ; address of PortGetEventMask
pPortWrite                  DD  ?  ; address of PortWrite
pPortRead                   DD  ?  ; address of PortRead
pPortEnableNotification     DD  ?  ; address of PortEnableNotification
pPortSetReadCallback        DD  ?  ; address of PortSetReadCallback
pPortSetWriteCallback       DD  ?  ; address of PortSetWriteCallback
pPortGetModemStatus         DD  ?  ; address of PortGetModemStatus
pPortGetCommConfig          DD  ?  ; address of PortGetCommConfig
pPortSetCommConfig          DD  ?  ; address of PortSetCommConfig
pPortGetWin32Error          DD  ?  ; address of PortGetWin32Error
_PortFunctions ENDS

Contains the addresses of port-driver functions. If a port driver does not provide a particular function, the corresponding field should be NULL. The _PORTDATA structure contains the address of the _PORTFUNCTIONS structure for a port driver.

See Also

PortClearError, PortClose, _PORTDATA, PortEnableNotification, PortEscapeFunction, PortGetCommState, PortGetEventMask, PortGetModemStatus, PortGetProperties, PortGetQueueStatus, PortPurge, PortRead, PortSetCommState, PortSetEventMask, PortSetModemStatusShadow, PortSetReadCallback, PortSetup, PortSetWriteCallback, PortTransmitChar, PortWrite


_PORTINFORMATION

include vcomm.inc

_PortInformation STRUC
pData _PortData <>   ; must be first field
    .
    .                ; additional fields specific to port driver
    .
_PortInformation ENDS

Contains information about an open port. The first field must be a _PORTDATA structure; additional fields can contain information specific to a particular port driver. The PortOpen function returns the address of this structure and VCOMM specifies the address in subsequent calls to port-driver functions.

See Also

_PORTDATA, PortOpen


PortOpen

cCall [pPortOpen], <<OFFSET32 PortName>, VMId, <OFFSET32 dwError>>
mov     pPortInformation, eax

Called by _VCOMM_OpenComm to open a port. Uses the C calling convention.

  • Returns the address of a _PORTINFORMATION structure if successful, NULL otherwise. VCOMM specifies the address in all subsequent calls to port-driver functions for the port.
PortName
Address of a null-terminated string specifying the port name, or NULL if the port should be opened by number.
VMId
Handle of the virtual machine (VM) that owns the port.
dwError
Address of a 32-bit value that receives an error code if the return value is NULL. This parameter is ignored if the return value is not NULL.

A port driver should call the _VCOMM_Acquire_Port service to block access to the port when this function is called. If the service fails, the port is already in use and the port driver should not attempt to open it.

The communications resource handle returned by _VCOMM_OpenComm is not necessarily the same as the address returned by this function.

See Also

_PORTINFORMATION, _VCOMM_Acquire_Port, _VCOMM_OpenComm


Port Configuration

The port configuration functions get and set the capabilities and configuration of an open communications device.


PortGetCommConfig

cCall   [pPortGetCommConfig], <hPort, <OFFSET32 dcbPort, \
           <OFFSET32 dwSize>>
or      eax, eax
jz      error_handler

Called by the _VCOMM_GetCommConfig service to get the Win32 device control block (_DCB) of a port. Uses the C calling convention. Fills the dcbPort buffer with the Win32 DCB and fills dwSize with the size of the Win32 DCB. If dwSize is less than the size of the port's Win32 DCB structure on entry, the function does not copy the DCB into the buffer and returns FALSE.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Address of a _PORTINFORMATION structure returned by the PortOpen function.
dcbPort
Address of a buffer that is filled with the Win32 _DCB structure.
dwSize
Address of the size, in bytes, of the dcbPort buffer.

See Also

_DCB, _PORTINFORMATION, PortOpen, _VCOMM_GetCommConfig


PortGetCommState

cCall   [pPortGetCommState], <hPort, <OFFSET32 dcbPort>>
or      eax, eax
jz      error_handler

Called by the _VCOMM_GetCommState service to get the device control block (_DCB) of a port. Uses the C calling convention.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Address of a _PORTINFORMATION structure returned by the PortOpen function.
dcbPort
Address of a _DCB structure that is filled in.

See Also

_DCB, _PORTINFORMATION, PortOpen, _VCOMM_GetCommState


PortGetProperties

cCall [pPortGetProperties], <hPort, <OFFSET32 cmmp>>
or      eax, eax
jz      error_handler

Called by the _VCOMM_GetCommProperties service to get the hardware and software capabilities and limitations of a port. Uses the C calling convention.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Address of a _PORTINFORMATION structure returned by the PortOpen function.
cmmp
Address of a _COMMPROP structure that is filled in.

See Also

_COMMPROP, _PORTINFORMATION, PortOpen, _VCOMM_GetCommProperties


PortSetCommConfig

cCall   [pPortGetCommConfig], <hPort, <OFFSET32 dcbPort, \
           <OFFSET32 dwSize>>
or      eax, eax
jz      error_handler

Called by the _VCOMM_SetCommConfig service to set the hardware state of a port and the software state of the associated port driver. Uses the C calling convention. Must be callable at interrupt time. Like PortGetCommConfig, on entry dwSize is the size of the dcbPort buffer and must be greater than or equal to the size of the port's Win32 DCB.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Address of a _PORTINFORMATION structure returned by the PortOpen function.
dcbPort
Address of a _DCB structure containing device control information.
dwSize
The size, in bytes, of the _DCB structure.

See Also

_DCB, _PORTINFORMATION, PortOpen, _VCOMM_SetCommConfig


PortSetCommState

cCall [pPortSetCommState], <hPort, <OFFSET32 dcbPort>, \
    ActionMask>
or      eax, eax
jz      error_handler

Called by the _VCOMM_SetCommState service to set the hardware state of a port and the software state of the associated port driver. Uses the C calling convention. Must be callable at interrupt time.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Address of a _PORTINFORMATION structure returned by the PortOpen function.
dcbPort
Address of a _DCB structure containing device control information.
ActionMask
One or more values specifying the communications settings to change. For more information, see the _VCOMM_SetCommState service.

See Also

_DCB, _PORTINFORMATION, PortOpen, _VCOMM_SetCommState


PortGetWin32Error

cCall   [pPortGetWin32Error], <hPort, <OFFSET32 dwError>>
or      eax, eax
jz      error_handler

Returns a Win32 error.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Address of a _PORTINFORMATION structure returned by the PortOpen function.
dwError
Error word filled by a function.

See Also

_PORTINFORMATION, PortOpen


PortSetup

cCall [pPortSetup], <hPort, <OFFSET32 RxQueue>, cbRxQueue, \
    <OFFSET32 TxQueue>, cbTxQueue>
or      eax, eax
jz      error_handler

Called by the _VCOMM_SetupComm service to set the receive and transmit queues for a port, and retrieve the status of previous receive queue. Uses the C calling convention.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Address of a _PORTINFORMATION structure returned by the PortOpen function.
RxQueue and cbRxQueue
Base address and size of the receive queue.
TxQueue and cbTxQueue
Base address and size of the transmit queue.

Any characters in the receive and transmit queues are discarded.

See Also

_PORTINFORMATION, PortOpen, _VCOMM_SetupComm


Read and Write Functions

The read and write functions read from and write to a communications device, determine communications errors, and determine the status of the transmit and receive queues.


PortClearError

cCall _VCOMM_ClearCommError, <hPort, <OFFSET32 cmst>, \
    <OFFSET32 dwErrors>>
or      eax, eax
jz      error_handler

Called by the _VCOMM_ClearCommError service to reenable a port after a communications error. Uses the C calling convention. Must be callable at interrupt time.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Address of a _PORTINFORMATION structure returned by the PortOpen function.
cmst
Address of a _COMSTAT structure that receives information about the state of the communications channel. Can be NULL.
dwErrors
Address of a 32-bit variable that receives communications errors. For a list of communications errors, see the _VCOMM_ClearCommError service.

See Also

_COMSTAT, _PORTINFORMATION, PortOpen, _VCOMM_ClearCommError


PortGetQueueStatus

cCall [pPortGetQueueStatus], <hPort, <OFFSET32 cmst>>
or      eax, eax
jz      error_handler

Called by _VCOMM_GetCommQueueStatus to retrieve information about the status of a communications channel and the amount of data in the receive and transmit queues. Uses the C calling convention. Must be callable at interrupt time.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Address of a _PORTINFORMATION structure returned by the PortOpen function.
cmst
Address of a _COMSTAT structure that receives status information.

See Also

_COMSTAT, _PORTINFORMATION, PortOpen, _VCOMM_GetCommQueueStatus


PortPurge

cCall [pPortPurge], <hPort, dwQueueType>
or      eax, eax
jz      error_handler

Called by the _VCOMM_PurgeComm service to discard information in the receive or transmit queue, and cancel pending reads or writes. Uses the C calling convention.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Address of a _PORTINFORMATION structure returned by the PortOpen function.
dwQueueType
The queue to purge: 0 if transmit queue, 1 if receive queue.

See Also

_PORTINFORMATION, PortOpen, _VCOMM_PurgeComm


PortRead

cCall [pPortRead], <hPort, <OFFSET32 achBuffer>, \
    cchRequested, <OFFSET32 cchReceived>>
or      eax, eax
jz      error_handler

Called by the _VCOMM_ReadComm service to read characters from the receive queue for the specified port. Uses the C calling convention. Must be callable at interrupt time.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Address of a _PORTINFORMATION structure returned by the PortOpen function.
achBuffer
Address of a buffer that receives the characters.
cchRequested
Number of characters to read from the receive queue.
cchReceived
Address of a 32-bit variable that receives the number of characters actually read.

The port driver must update the QInGet field of the _PORTDATA structure. The port driver may need to issue flow-control signals if the number of characters in the receive queue drops below the XON limit. The XON limit is specified by the device control block (_DCB structure) for the port.

See Also

_DCB, _PORTDATA, _PORTINFORMATION, PortOpen, _VCOMM_ReadComm


PortTransmitChar

cCall [pPortTransmitChar], <hPort, ch>
or      eax, eax
jz      error_handler

Called by the _VCOMM_TransmitCommChar service to send an "immediate" character to a port. The port driver must transmit the specified character before any characters in the transmit queue. Uses the C calling convention. Must be callable at interrupt time.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Address of a _PORTINFORMATION structure returned by the PortOpen function.
ch
Character to transmit.

See Also

_PORTINFORMATION, PortOpen, _VCOMM_TransmitCommChar


PortWrite

cCall [pPortWrite], <hPort, <OFFSET32 achBuffer> \
    cchRequested, <OFFSET32 cchWritten>>
or      eax, eax
jz      error_handler

Called by the _VCOMM_WriteComm service to write characters to the transmit queue for the specified port. Uses the C calling convention. Must be callable at interrupt time.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Address of a _PORTINFORMATION structure returned by the PortOpen function.
achBuffer
Address of an array of characters to write.
cchRequested
Number of characters to write.
cchWritten
Address of a 32-bit variable that receives the number of characters actually written.

See Also

_PORTINFORMATION, PortOpen, _VCOMM_WriteComm


Communications Events

The communications event functions enable a VCOMM client to receive notifications when communications events occur or when the transmit and receive queues reach specified thresholds.


PortEnableNotification

cCall [pPortEnableNotification], <hPort, <OFFSET32 CommNotifyProc>, \
    lReferenceData>
or      eax, eax
jz      error_handler

Called by the _VCOMM_EnableCommNotification service to register a callback function for event notification. Uses the C calling convention.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Address of a _PORTINFORMATION structure returned by the PortOpen function.
CommNotifyProc
Address of a client-defined callback function that the port driver calls when an event enabled by the PortSetEventMask function occurs. For more information, see CommNotifyProc. Can be NULL to disable notification.
lReferenceData
A client-defined 32-bit value that is passed to the callback function.

See Also

CommNotifyProc, _PORTINFORMATION, PortOpen, PortSetEventMask, _VCOMM_EnableCommNotification


PortEscapeFunction

cCall   [pPortEscapeFunction], <hPort, lFunc, InData, <OFFSET32 OutData>>
or      eax, eax
jz      error_handler

Called by _VCOMM_EscapeCommFunction to carry out an extended function. Uses the C calling convention. Must be callable at interrupt time.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Address of a _PORTINFORMATION structure returned by the PortOpen function.
lFunc
Value identifying the extended function to carry out, or DUMMY to perform no action. Common extended functions are defined in VCOMM.INC. For more information, see the _VCOMM_EscapeCommFunction service. Port drivers can define additional extended functions.
InData
Function-specific 32-bit parameter.
OutData
Address to receive function-specific data.

A port driver that is designed specifically to emulate a common port type should return success for extended functions that apply to the emulated port type, even if the function does not apply to the hardware used for emulation.

There are several predefined extended functions. Microsoft reserves the first 200 non-negative extended function values (0 through 199). Developers who create new extended functions should enumerate their values beginning with STARTNONSTESCAPES defined in VCOMM.INC. The following escapes are currently defined:

Escape | Description
DUMMY | This value is never used and a port driver should never receive this escape.
SETXOFF | Sets the XOFFReceived flag. This puts the serial driver in the XOFF state.
SETXON | Resets the XOFFReceived flag. This puts the serial driver in the XON state.
SETRTS | Sets the Ready To Send (RTS) bit in the Modem Control Register.
CLRRTS | Resets the Ready To Send bit in the Modem Control Register.
SETDTR | Sets the Data Terminal Ready (DTR) bit in the Modem Control Register.
CLRDTR | Resets the Data Terminal Ready (DTR) bit in the Modem Control Register.
RESETDEV | Asserts the RESET line on an LPT port.
GETLPTMAX | Returns the maximum LPT port identifier supported by the system. This value ranges from 0x80 to 0xFF, such that 0x80 corresponds to LPT1, 0x81 corresponds to LPT2, 0x82 corresponds to LPT3, and so on.
GETCOMMAX | Returns the maximum COM port identifier supported by the system. This value ranges from 0x00 to 0x7F, such that 0x00 corresponds to COM1, 0x01 corresponds to COM2, 0x02 corresponds to COM3, and so on.
GETCOMBASEIRQ | Returns the IRQ and base I/O address of the port. The IRQ value is in the upper-word of the 32-bit value and the base I/O address is in the lower-word.
GETCOMBASEIRQ1 | This escape is equivalent to GETCOMBASEIRQ.
SETBREAK | Sets the break condition. Suspends character transmission and places the data transmission line in a break state until the CLEARBREAK escape is received.
CLEARBREAK | Clears the break condition. Releases any BREAK clamp on the data transmission line.
GETPORTHANDLE | Returns the 32-bit Ring 0 handle of the port.
GETEXTENDEDFNADDR | .
CLRTIMERLOGIC | Disables the periodic notification checks. VCOMM sends this escape when it opens a port for a Win32 application.
GETDEVICEID | Gets the IEEE P1284 device ID for the connected peripheral device.
SETECPADDRESS | Sets the IEEE P1284 channel address. The IEEE P1284 specification uses a channel addressing scheme that provides 128 forward and reverse channel addresses. Channel addresses are device-specific and are defined in the specification.
SETUPDATETIMEADDR | VCOMM uses this escape to set a pointer to a DWORD that the port driver uses to store the most recently updated system time each time new character(s) arrive at the port.
IGNOREERRORONREADS | Normally the PortRead function returns an error if an error condition normally exists. This escape sets the IgnoreCommError miscellaneous flag so the PortRead function on the serial port does not check for an existing error condition before transferring characters.
ENABLETIMERLOGIC | Enables periodic notification checks. This escape is useful when notification is enabled and non-zero trigger level is implemented. Checking for notifications periodically allows an application to be notified of incoming characters in a timely manner even when the number of received characters is below the trigger level.
IGNORESELECT | Sets the IgnoreSelect bit in the LPT driver flags. The select bit is not set under normal circumstances, but the select bit is incorrectly implemented on some parallel devices. This escape allows an LPT port driver to be consistent with the DOS/BIOS on some machines.
STARTNONSTDESCAPES | Developer-assigned port escapes should begin with this value.
PEEKCHAR | Returns the current character in the input queue if the queue is non-empty; returns zero otherwise.

The port drivers Microsoft supplies with Windows 95 (Serial.vxd and Lpt.vxd) each support a subset of the escapes listed in the preceding text.

Port Driver | Supported Escapes
Serial.vxd | SETXOFF, SETXON, SETRTS, CLRRTS, SETDTR, CLRDTR, GETCOMBASEIRQ, GETCOMBASEIRQ1, SETBREAK, CLEARBREAK, GETPORTHANDLE, CLRTIMERLOGIC, ENABLETIMERLOGIC, SETUPDATETIMEADDR, IGNOREERRORONREADS, PEEKCHAR.
Lpt.vxd | RESETDEV, GETDEVICEID, SETECPADDRESS.

See Also

_PORTDATA, _PORTINFORMATION, _VCOMM_EscapeCommFunction


PortGetModemStatus

cCall [pPortGetModemStatus], <hPort, <OFFSET32 dwModemStatus>>
or      eax, eax
jz      error_handler

Called by the _VCOMM_GetModemStatus service to retrieve the current value of the modem status register. Uses the C calling convention. Must be callable at interrupt time.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Address of a _PORTINFORMATION structure returned by the PortOpen function.
dwModemStatus
Address of a 32-bit variable to receive the modem status. For a list of possible values, see the _VCOMM_GetModemStatus service.

See Also

_PORTINFORMATION, _VCOMM_GetModemStatus


PortGetEventMask

cCall [pPortGetEventMask], <hPort, dwMask, <OFFSET32 dwEvents>>
or      eax, eax
jz      error_handler

Called by the _VCOMM_GetCommEventMask service to retrieve and clear the specified event flags for a port. Uses the C calling convention. Must be callable at interrupt time.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Address of a _PORTINFORMATION structure returned by the PortOpen function.
dwMask
One or more values specifying the events to retrieve and clear. For a list of events, see _VCOMM_GetCommEventMask.
dwEvents
Address of the event variable. Can be NULL, in which case the location of the event variable is unchanged.

See Also

_PORTINFORMATION, PortOpen, _VCOMM_GetCommEventMask


PortSetEventMask

cCall [pPortSetEventMask], <hPort, dwMask, <OFFSET32 dwEvents>>
or      eax, eax
jz      error_handler

Called by the _VCOMM_SetCommEventMask service to set the value of the event mask and the location of the event variable.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Address of a _PORTINFORMATION structure returned by the PortOpen function.
dwMask
The event mask for the communications resource. The event mask is a combination of values specifying enabled events. For a list of events, see _VCOMM_GetCommEventMask. If notification is enabled, an enabled event triggers a call to the notification function.
dwEvents
Address of the event variable. Can be NULL, in which case the location of the event variable is unchanged.

See Also

_PORTINFORMATION, PortOpen, _VCOMM_GetCommEventMask, _VCOMM_SetCommEventMask


PortSetModemStatusShadow

cCall [pPortSetModemStatusShadow], <hPort, dwEventMask
    <OFFSET32 MSRShadow>>
or      eax, eax
jz      error_handler

Sets the location of the modem status shadow for a port. The port driver updates the byte at this location whenever the modem status register changes. Uses the C calling convention.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Address of a _PORTINFORMATION structure returned by the PortOpen function.
dwEventMask
Specifies the new event mask for the port.
MSRShadow
Address of the modem status shadow.

When a port is opened, the modem status shadow is the bMSRShadow field of the _PORTDATA structure.

VCOMM calls this function when the VCOMM_PM_API_SetMSRShadow protected-mode API is called. This enables the 16-bit Windows communications driver to set the modem status shadow to a location in the system VM. There is no equivalent VCOMM service.

See Also

_PORTDATA, _PORTINFORMATION, PortOpen, VCOMM_PM_API_SetMSRShadow


PortSetReadCallback

cCall [pPortSetReadCallback], <hPort, RxTrigger, \
    <OFFSET32 CommNotifyProc>, lReferenceData>
or      eax, eax
jz      error_handler

Called by the _VCOMM_SetReadCallback service to set the notification threshold for the receive queue and register a callback function for receive-queue threshold notification.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Address of a _PORTINFORMATION structure returned by the PortOpen function.
RxTrigger
Receive-queue notification threshold. When the number of bytes in the receive queue reaches this value, the port driver calls the function specified by CommNotifyProc. Can be –1 to disable receive-queue notification.
CommNotifyProc
Address of the callback function for receive-queue notification. Can be different from the notification function for event notification and transmit-queue notification. For more information, see the CommNotifyProc function.
lReferenceData
A client-defined 32-bit value that is passed to the callback function. Can be different from the reference data specified for event notification and transmit-queue notification.

See Also

CommNotifyProc, _PORTINFORMATION, PortOpen, _VCOMM_SetReadCallback


PortSetWriteCallback

cCall [pPortSetWriteCallback], <hPort, TxTrigger, \
    <OFFSET32 CommNotifyProc>, lReferenceData>
or      eax, eax
jz      error_handler

Called by the _VCOMM_SetWriteCallback service to set the notification threshold for the transmit queue, and register a callback function for transmit-queue threshold notification.

  • Returns TRUE if successful, FALSE otherwise.
hPort
Address of a _PORTINFORMATION structure returned by the PortOpen function.
TxTrigger
Transmit-queue notification threshold. When the number of bytes in the transmit queue reaches this value, the port driver calls the function specified by CommNotifyProc. Can be –1 to disable transmit-queue notification.
CommNotifyProc
Address of the callback function for transmit-queue notification. Can be different from the notification function for event notification and receive-queue notification. For more information, see the CommNotifyProc function.
lReferenceData
A client-defined 32-bit value that is passed to the callback function. Can be different from the reference data specified for event notification and receive-queue notification.

See Also

CommNotifyProc, _PORTINFORMATION, PortOpen, _VCOMM_SetWriteCallback


Display Drivers

A display driver for the Microsoft® Windows® 95 operating system is a dynamic-link library (DLL) that translates device-independent commands from the graphic-device interface (GDI) into commands and actions that the display adapter uses to draw graphics on the screen. The display driver also gives information to Windows regarding the display hardware, such as color resolution, graphics capabilities, screen size and resolution, and other display features.

To help you create more efficient display drivers, Microsoft supplies the DIB engine, which is a DLL that contains most of the functions needed to translate GDI commands. A display driver that uses the DIB engine is called a display minidriver. The minidriver only contains hardware-specific code for your display adapter and redirects the non-device specific calls from GDI to the DIB engine.

To display output from a non-system virtual machine (typically a MS-DOS application), Windows needs a virtual display device (VDD). Microsoft supplies a standard VDD and only requires you to create a virtual display minidriver (mini-VDD) to handle your adapter's hardware-specific virtualization. The VDD is called by the grabber (VGAFULL.3GR) whenever a windowed virtual machine needs to display output. The VDD enables the smooth transition from Windows hi-resolution mode to full screen VGA mode and back again. The VDD also receives information from the display minidriver, which it can pass along to the mini-VDD.

To help manage the frame buffer for your display adapter, Microsoft supplies the virtual flat frame buffer device (VFLATD). This virtual device provides support for bank-switched frame buffers larger than 64K.

The following illustration shows the Windows 95 display-driver architecture.


Display Minidriver Components

The Windows display driver interface (DDI) consists of the following major components.

Component | Contents
display minidriver | Hardware-specific DLL to draw output on a video display; written by you. For more information on display minidrivers, see About Display Minidrivers.
DIB engine | Generic DLL used by the display minidriver to draw output; supplied by Microsoft. For more information on the DIB engine, see About the Device Independent Bitmap Engine.
VFLATD.VXD | Generic VxD to virtualize frame buffers larger than 64K; supplied by Microsoft. For more information on the virtual flat frame buffer device (VFLATD), see About Virtual Flat-Frame Buffer Device.
mini-VDD | Hardware-specific VxD to virtualize the video hardware so that more than one virtual machine (VM) can share the same display; written by you. For more information on the virtual display minidriver (mini-VDD), see About Virtual Display Minidrivers.
virtual display device (VDD.VXD) | Generic VxD used to virtualize the VGA hardware; supplied by Microsoft. For more information on the virtual display device (VDD), see About Virtual Display Device.


What's New for Display Drivers

Writing display drivers for previous versions of Windows required you to write a large amount of assembly code covering a variety of display tasks. In Windows 95, the DIB engine supplies most of the code necessary to create a display driver. All your minidriver needs is the hardware-specific code for your display; you simply redirect the non-device specific calls from GDI to the DIB engine. If you cannot use the DIB engine, you must write a full display driver that supplies the new display functions Windows 95 requires.

Similarly, you have far less code to write for display virtualization. Windows 95 supplies the virtual display driver (VDD) which will make hardware-specific calls to a small virtual display minidriver (mini-VDD) that you write.

The VDD now allows four-plane VGA applications to run in a Window with some standard SVGA display adapters.

The grabber is no longer a component that should be modified, since it handles all interaction between WINOA386.MOD and the VDD, both of which are now Microsoft-supplied components.

Note If you have written display drivers for previous versions of Windows, you should use the DIB engine and the VDD because your minidrivers will be simpler, smaller, easier to write, and less likely to have bugs.


Display Driver Installation Disk

When you are ready to release your driver, it must be on a Windows 95 format installation disk. The installation disk for your Windows 95 display driver must contain:

  • A Windows 95 format INF text file
  • All DRV and VxD files copied and used by the INF


Display Minidrivers

A display minidriver for the Microsoft® Windows® 95 operating system is a DLL that you write to support the translation of graphics commands between GDI and the display adapter. Your minidriver will follow the same general format as a full device driver, but will reroute most GDI calls to the DIB engine. If you cannot use the DIB engine, you must write a full display driver.

This section describes how to create display minidrivers and provides information necessary to create a full display driver. For more information about the DIB engine, see About the Device Independent Bitmap Engine.


Using the DIB Engine

There are two ways you can use the DIB engine with your display minidriver:

  • Display operations
  • Memory operations


Display Operations

The DIB engine requires your display device to use a packed-pixel format. The screen bits must be stored in a single plane with each pixel having 1, 4, 8, 15 (a special case of 16), 16, 24, or 32 bits defining the pixel color. For Windows 95, most display devices will use this format, but if your device uses a planar format (where screen bits are stored in separate bitmap planes, one plane for each color), you cannot use the DIB engine and must write a full display device driver. Note that some planar devices can still use the DIB engine if their memory bitmaps use a packed-pixel format. In this case the device must translate between the packed-pixel format and the planar format.


Memory Operations

Even if your display adapter does not use a standard frame buffer, you can use the DIB engine for direct memory bitmap operations. For more information about direct memory bitmap operations using the DIB engine, see About the Device Independent Bitmap Engine.


Display Driver Overview

This section provides information that is necessary for implementing a full display driver but is also relevant if implementing a minidriver.


Display Driver Initialization

Display driver initialization occurs when Windows first boots. When booting, Windows loads the display driver and calls the driver's initialization routine.

The only requirement for the initialization routine is that it must return one in the AX register; otherwise, Windows will fail to load. Although the initialization routine can carry out any task, many drivers do the following:

  • Initialize display hardware
  • Read private system.ini values (if any)

Typically, drivers wait until GDI calls the driver's Enable function before fully initializing the video hardware.

The initialization routine returns one if the initialization was successful. Otherwise, it returns zero and Windows immediately terminates.


GDI Information Structure

Every display driver has a GDIINFO structure that specifies the display's capabilities and characteristics. GDI uses this information to determine what the display driver can do and what GDI must simulate. The GDI information can be classified as follows:

  • Driver management
  • Driver capabilities
  • Device dimensions

The driver-management information specifies the version of Windows for which the driver was written and the type of technology the display uses to generate output. The driver-management information also specifies the size in bytes of the PDEVICE structure and the number of device contexts the driver can manage at the same time. The version number specifies a Windows version (not the display driver version). For example, a display driver written for Windows 95 should set the dpVersion member to 0x400.

The driver-capabilities information specifies the capabilities of the display device, such as whether the display hardware can draw polygons and ellipses, scale text, or clip output. Driver capabilities also specify the number of brushes, pens, fonts, and colors available on the display and whether the display can handle bitmaps and color palettes.

The device-dimension information specifies the maximum width and height of the screen in both millimeters and device units, the number of color bits or planes, the aspect ratio, the minimum length of a dot in a styled line, and the number of device units (or pixels per inch).

The subsequent sections of this section describe the GDIINFO structure more fully. Each section describes the capabilities associated with given members and explains how to determine what capabilities a display driver can support.


Enabling and Disabling the Physical Device

GDI enables the display driver by calling the Enable function and directing the driver to initialize a physical device for subsequent graphics output. A physical device is a PDEVICE structure that represents the display and its current operating state. A display driver uses the physical device information to determine how to carry out specific tasks, such as which display mode to use. The display driver initializes the physical device by copying information to the PDEVICE structure.

During initialization, GDI calls Enable twice: once to retrieve a copy of the driver's GDIINFO structure, and another time to initialize the PDEVICE structure. GDI allocates memory for the PDEVICE structure and calls Enable, passing a pointer to the structure. At this point, the driver initializes the display hardware and the structure.

Although only the display driver initializes and uses the PDEVICE structure, it is GDI that allocates memory for the structure, determines when to pass it to the driver's output functions, and deletes the structure when it is no longer needed.

Each minidriver has to create a PDEVICE structure in a format recognized by the DIB Engine. If the surface being drawn to is video memory, a device-independent bitmap (DIB), or a color device-dependent bitmap (DDB), the PDEVICE is in the format of a DIBENGINE structure. If the surface is a monochrome bitmap, the PDEVICE is in the format of a PBITMAP structure. The deType member of the PDEVICE identifies the format of the structure; it must be either TYPE_DIBENG (0x5250) if in the DIBENGINE format or 0 if in the PBITMAP format.

In some cases, for example, when a full-screen .AVI file is played, GDI calls Enable once to have the driver reinitialize the display hardware, the PDEVICE structure, and any screen data that may have been discarded. Additionally, Enable is called when a dynamic resolution change occurs.

Note that it is possible that a Windows® 3.1 application may call the driver directly passing it a Windows 3.1 style PBITMAP structure. If the deType member is zero, but the deBitsPixel member is not equal to one, then the structure is a Windows 3.1 style PBITMAP structure. In this case, if the driver is using the DIB engine, it should pass the structure to the DIB engine and let the DIB engine handle the call.

GDI calls the Disable function in a variety of cases, such as when a full-screen .AVI file is played, or when Windows quits. GDI disables the display driver by calling the Disable function. If the driver has allocated any memory or selectors, it must free them in the Disable function. After the driver returns from the Disable function, GDI frees the memory it allocated for the PDEVICE structure and frees the driver, removing any driver code and data from memory.


Hardware Initialization

A display driver sets the display mode and registers for the display hardware whenever GDI calls the Enable and Disable functions. The driver is also responsible for saving and restoring the display mode and registers whenever Windows is switching between Windows applications and non-Windows applications.

Enabling and Disabling the Display Hardware

A display driver prepares the display hardware for Windows whenever GDI calls the Enable function. To prepare the hardware, the display driver sets the display hardware to graphics mode and initializes the hardware registers as needed. This should include setting the refresh rate based on the current monitor. For more information on refresh rates, see About Refresh Rate Support. Although GDI calls the BitBlt function to clear the screen as Windows starts, many display drivers eliminate the possibility of the user seeing any random data by also clearing the screen as they initialize the display hardware.

A display driver restores the display hardware to a text mode whenever GDI calls the Disable function.

Screen Switching

The display driver works with the Virtual Display Device (VDD) to reenable the display hardware for Windows high resolution (hi-res) mode after returning from a full-screen MS-DOS virtual machine. To accomplish this task, the display driver must call the VDD function VDD_DRIVER_REGISTER to register the function ResetHiResMode immediately after the Windows hi-res mode has been set by the display driver during initialization. ResetHiResMode is a required display driver function that is called by the VDD to place the screen back into Windows hi-res mode after a user switches away from a full screen MS-DOS session.

See Also

ResetHiResMode, VDD_DRIVER_REGISTER


Physical Objects

Physical objects define the attributes (such as color, width, and style) of lines, patterns, and characters drawn by a display driver. Physical objects correspond to the logical pens, brushes, and fonts that Windows applications create but contain device-dependent information that the display driver needs to generate output. A display driver creates physical objects when GDI calls the RealizeObject function. The driver uses physical objects when GDI calls output functions such as Output, BitBlt, and ExtTextOut.

If using the DIB engine, the minidriver should forward the RealizeObject call to the DIB engine function DIB_RealizeObject and let the DIB engine realize the object. GDI calls RealizeObject twice: once to get the size of the object and a second time to actually realize the object. If needed, a minidriver may add extra data at the end of the object. To do this, when the DIB engine returns from the first call to DIB_RealizeObject, the driver should change the size value that it returns to GDI. After the return from the second call to DIB_RealizeObject, the driver may add on any extra data that it needs at the end of the structure. Because the user can change the Graphics Performance settings, in some cases GDI may bypass the driver and call directly into the DIB engine to realize an object. Because of this, the driver must not rely on the extra data being in the object structure during output functions.

The dpNumPens, dpNumBrushes, and dpNumFonts members in the GDIINFO structure specify the number of pens, brushes, and fonts a display driver supports. A display driver must supply information about these objects whenever GDI requests it. GDI calls the EnumObj function to request information about pens and brushes; it calls the EnumDFonts function to request information about device fonts. For each pen, brush, or font, the display driver calls the callback function. GDI pass a LPEN, LBRUSH, or LFONT structure to the callback function. These structures specify the attributes of the object.

Although a display driver can use display hardware to support objects, the driver must be able to generate the same output both on the screen and in memory bitmaps.

Physical Pens

A physical pen specifies the color, style, and width of polylines and borders drawn by a display driver. A display driver realizes a physical pen by filling a PPEN structure with information about the pen. The content and format of the PPEN structure depends entirely on the display driver. In general, the driver copies all the information the Output function needs to draw lines.

The DIB engine supports the standard GDI pen styles solid, empty, dashed, dotted, dot-dashed, and dash-dot-dotted. A display driver must support the empty style, although it is not required to supply information about it when GDI calls EnumObj. When drawing with an empty pen, the pen itself does not contribute to the output, but the driver may still draw a line if, for example, the raster operation combines the destination with itself using the XOR operator (DDx) or inverts the destination (Dn).

A display driver that supports wide and styled lines must use the same drawing algorithms for lines drawn on the screen and in memory bitmaps. Because GDI efficiently synthesizes both wide and styled lines, some display drivers do not support them.

Under certain conditions, GDI may pass the display driver a request to realize a wide or styled line even though the display driver has specified that it does not support them. In such cases, the driver should realize a solid, one-pixel wide (or nominal) pen. GDI will use this pen to simulate styled and wide lines.

Physical Brushes

A physical brush specifies the color and style of patterns used to fill figures drawn by the Output function and to combine with bitmaps drawn by the BitBlt function. A display driver realizes a physical brush by filling a PBRUSH structure with information about the brush. The content and format of the PBRUSH structure depends entirely on the display driver.

A display driver should support the standard GDI brush styles: solid, hatched, patterned, and hollow. A display driver must support hollow brushes, although it is not required to provide information about it when GDI calls the EnumObj function. When drawing with a hollow brush, the brush itself does not contribute to the output, but other factors, such as a raster operation that combines the destination with itself or inverts the destination, can cause the driver to generate output.

The display driver can dither solid brushes if the specified color does not exactly match a physical color. Otherwise, it should choose the closest available color for the brush.

The display driver should support the standard hatched brush styles: horizontal, vertical, forward diagonal, backward diagonal, cross, and diagonal crosshatch. On raster displays, a driver typically implements these styles as predefined, 8-by-8 bit patterns.

On color displays, the display driver should support both monochrome and color bitmaps for patterned brushes. When drawing monochrome bitmaps, the driver sets 1 bit to the current text color and zero bits to the current background color. The text and background colors are specified in the DRAWMODE structure passed to these functions. A display driver is not required to provide information about patterned brushes when GDI calls the EnumObj function.


Physical Colors

A display driver is responsible for translating logical colors (RGB values) into physical colors that are appropriate to the display hardware. Similarly, it must translate physical colors to logical colors. GDI calls the ColorInfo function whenever it needs a translated color.

If the display device provides a color palette, the driver converts colors to palette indexes. To indicate a palette index, the driver always sets the high byte of the index to 0xFF.

To indicate an RGB color value, the display driver sets the high byte to zero.


Screen Metrics

The screen metrics, specified by the GDIINFO structure, define such items as width and height in millimeters, screen resolution, aspect ratio, and standard mapping modes. GDI uses screen metrics to generate coordinate data that is appropriate for the display hardware. The only screen metrics that a display driver must set are the dpHorzRes and dpVertRes members to specify the width and height of the screen in pixels. GDI reads the values for dpLogPixelsX and dpLogPixelsY from the registry so drivers should not set these values. All other screen metrics, dpHorzSize, dpVertSize, dpAspectX, dpAspectY, dpAspectXY, and the various mapping mode members are calculated by GDI.

The driver must set the dpStyleLen member. The styled-line length specifies the length of the smallest line segment the display driver uses to build the dots and dashes of a styled line. GDI uses this number when it draws into bitmaps and on displays. To ensure consistency between displays and printers, the styled line segment length is always two times the value of the dpAspectXY member.


Lines, Curves, and Polygons

GDI requires all display drivers to provide an Output function that supports a minimum set of line, curve, and polygon drawing capabilities. In particular, a display driver must be able to draw scan lines and polylines. A scan line is a horizontal line that is exactly one pixel wide and which can be either solid or styled. A polyline is a sequence of solid lines, each one pixel wide and each connected at an endpoint to the next line in the sequence.

GDI may call the Output function whenever an application calls a function that draws lines, curves, or polygons. If the display driver supports all capabilities, GDI calls the Output function for each request. Otherwise, GDI simulates output that the driver does not support by combining scan lines and polylines.

Since GDI can use scan lines and polylines to simulate all other line, curve, and polygon output, many display drivers do not support additional capabilities unless the display hardware can produce faster and higher-quality results than GDI. The only drawback to using display hardware is that the display driver must be able to produce the same results in memory bitmaps as on the screen.

GDI checks the dpCurve, dpLines, and dpPolygonals members of the GDIINFO structure to determine what line, curve, and polygon capability the display driver has.

Curves

GDI checks the dpCurve member to determine whether the display driver supports circles, ellipses, pie wedges, chord arcs, and Bezier splines. This member also specifies whether the display driver can draw wide or styled borders for curves and fill the interiors of curves.

If a display driver does not support circles, GDI can use an ellipse to draw a circle. If the display hardware can fill ellipses, the display driver should set the interiors bit. GDI can use an alternate-fill polygon to draw wide borders (both solid and styled) just as efficiently as if the driver supported them correctly.

Polylines

GDI checks the dpLines member to determine whether the display driver supports polylines. This member also specifies whether the display driver can draw wide or styled lines and fill the interiors of wide lines. A display driver must support polylines.

If a display driver supports styled lines, the line segments drawn by the display hardware must be as specified by the dpStyleLen member.

Polygons

GDI checks the dpPolygonals member to determine whether the display driver supports rectangles, scan lines, alternate-fill polygons, and winding-number-fill polygons. This member also specifies whether the display driver can draw wide or style borders for polygons, and fill the interiors of polygons. The display driver must support scan lines.

If the display driver does not draw its own wide borders, GDI simulates wide borders using alternate-fill polygons. Some display drivers intentionally take advantage of this by supporting alternate-fill polygons, but not wide borders.

Hardware Capabilities

The hardware for some displays supports many of the line, curve, and polygon capabilities that Windows itself supports or expects the display driver to support. A display driver should take advantage of display hardware whenever possible because it often dramatically improves performance.

The only disadvantage to using display hardware is if the hardware cannot produce its output both on the screen and in memory bitmaps. Windows requires that for any figure drawn on the screen, the display driver must also be able to draw it in a memory bitmap. If the hardware cannot access memory bitmaps, the display driver must include code that emulates the algorithms used by the display hardware. Depending on the complexity of the hardware code, this may be a difficult and costly task.

Partial Support for Capabilities

A display driver does not have to provide complete support for a given capability. Instead, a driver's Output function can provide support for a few specific cases and return all others to GDI for simulation. In such cases, the display driver sets bits in the GDIINFO structure as if it provided complete support, but the driver's Output function returns -1 to GDI for all cases that need simulation.

For example, if display hardware can draw polygons with 256 vertices but not with 257, the Output function can use the display hardware to draw the smaller polygons and return -1 to let GDI simulate the rest.


Text and Fonts

Drivers should set the TC_CP_STROKE and TC_RA_ABLE bits in the dpText member of the GDIINFO structure. The DIB engine sets these bits for minidrivers. Drivers do not need to set any other values. If not using the DIB engine, a driver must implement the ExtTextOut function to provide text-drawing capabilities. If using the DIB engine, implementing ExtTextOut is optional because the minidriver may forward ExtTextOut calls to the DIB engine functions DIB_ExtTextOut or DIB_ExtTextOutExt.

The new physical font format and implementation in Windows 95 is different than in previous versions of Windows. Additionally, the ExtTextOut function has been simplified so that display drivers that choose to implement this function will contains less code. For more information, see About The New Font Format and ExtTextOut.

See Also

DIB_ExtTextOut, DIB_ExtTextOutExt


Clipping

A display driver or display hardware can clip if it can discard output that would be outside of a specified rectangle or region if drawn on the screen. GDI checks the dpClip member in the GDIINFO structure to determine whether the display driver can clip output generated by the Output function. If a display driver can clip, it should set the bits in this member to specify clipping for rectangles or regions. If the display driver does not support clipping, GDI will simulate clipping. Drivers for Windows 95 typically set the dpClip member to CP_RECTANGLE. The DIB engine sets this bit for minidrivers.

Although dpClip only applies to output generated by the driver's Output function, other members in the GDIINFO structure specify clipping for other graphics output. For example, the dpText member specifies whether the display driver clips text.


Bitmaps

GDI requires a display driver to support bit-block transfers by providing the BitBlt and related bitmap functions. A display driver must provide a BitBlt function that can carry out bitmap operations on the screen, color bitmaps, and monochrome bitmaps. The brute functions provided by GDI and used by many printer drivers require monochrome bitmap support.

Bitmap Format

Most display devices are either planar or packed-pixel devices. A planar device stores screen bits in separate bitmap planes, each representing a distinct color. A packed-pixel device stores screen bits in a single plane, but each pixel on the screen has a set of four or more corresponding bits that define the pixel color.

A display driver specifies the type of display device by setting the dpBitsPixel and dpPlanes members to appropriate values. For a planar device, dpBitsPixel is 1 and dpPlanes specifies the number of planes. For a packed-pixel device, dpPlanes is 1 and dpBitsPixel specifies the number of bits per pixel. The DIB engine provides support for only the packed-pixel format.

These values also help determine the number of nondithered colors available for the screen. A device with four planes is capable of 16 colors. A device with 8 bits per pixel is capable of 256 colors. However, the exact color specified by a combination of bits depends on whether the device supports a color palette.

Pixel Output

A display driver must support setting and getting individual pixels by providing the Pixel function. GDI uses Pixel to support a variety of simulations. It also calls the function whenever an application calls SetPixel (GDI.31) and GetPixel (GDI.83).

Bit-Block Transfers

A display driver must support bit-block transfers by setting the dpRaster member to RC_BITBLT and providing a BitBlt function. GDI uses BitBlt to copy a rectangular block of bits from bitmap to bitmap, possibly applying a raster operation to the source and destination bits as it copies. GDI calls BitBlt whenever an application calls GDI functions such as BitBlt (GDI.34) and PatBlt (GDI.29).

A display driver can provide additional bit-block transfers by providing a StretchBlt function. GDI uses StretchBlt to stretch or compress a block of bits to fit a given rectangle in a bitmap. Stretching and compressing requires either adding or removing bits as defined by a stretching mode. GDI checks the RC_STRETCHBLT value in dpRaster to determine whether the driver provides the StretchBlt function. GDI calls the function whenever an application calls StretchBlt (GDI.35).

If a display driver can carry out bit-block transfers on bitmaps that are larger than 64K, it should set the RC_BITMAP64 value in the dpRaster member. GDI checks this bit to determine whether large bitmaps are permitted. Windows 95 drivers should set this or use the DIB engine which sets this.

A display driver must handle screen-to-screen bit-block transfers and bit-block transfers from a monochrome bitmap to the screen. If using the DIB engine, the minidriver may rely on the DIB engine for bit-block transfers involving just memory bitmaps or from color memory bitmaps to the screen.

Saved Bitmaps

A display driver can permit Windows to temporarily save bitmaps in off-screen video memory by providing the SaveScreenBitmap function. This function allows the driver to take advantage of unused video memory and to speed up drawing operations that require restoring a portion of the screen that was previously overwritten.

GDI checks the RC_SAVEBITMAP value in the dpRaster member to determine whether the driver supports SaveScreenBitmap.


Device-Independent Bitmaps

A device-independent bitmap (DIB) is a color bitmap in a format that eliminates the problems that occur when transferring device-dependent bitmaps to devices having difference bitmap formats. DIBs provide color and bitmap information that any display or printer driver can translate into the proper format for its corresponding device.

A display driver can support DIBs by providing the following device-independent bitmap functions. Because the DIB engine provides support for DIBs, the following functions are optional for a minidriver to implement.

Function | Description
DeviceBitmapBits | Copies a DIB to a device-dependent bitmap or a device-dependent bitmap to a DIB.
SetDIBitsToDevice | Copies any portion of a DIB to the screen. This function copies the bits directly without applying a raster operation.
StretchDIBits | Moves a source rectangle into a destination rectangle, stretching or compressing the bitmap if necessary to fit the dimensions of the destination rectangle.

These functions receive and operate on BITMAPINFO, BITMAPINFOHEADER, and RGBQUAD structures.

A display driver that supports DIBs must provide the CreateDIBitmap function as well. The function should do nothing more than return zero, indicating that the creation of a DIB is not supported at the driver level.

If a display driver supports DIBs, it must set one or more of the RC_DI_BITMAP, RC_DIBTODEV, and RC_STRETCHDIB values in the dpRaster member of the GDIINFO structure. If a driver does not set the RC_DI_BITMAP value, GDI simulates DIB conversions using monochrome bitmaps. The DIB engine supports of these capabilities and minidrivers may rely on the DIB engine for these functions.

Logical-Color Tables

Drivers use a logical-color table when translating a device-specific bitmap into a DIB. The table resides in the DIB header block. Because color mapping is a complex process, minidrivers should let the DIB engine create the logical color table.

DIB to Device

A display driver can copy a DIB directly to the screen using the SetDIBitsToDevice function or call the DIB engine function DIB_DibToDevice. SetDIBitsToDevice saves the trouble of first converting the DIB into the device-dependent format and then, transferring it onto the screen. However, only a direct copy of the DIB is provided. Moreover, only one direction of copy (DIB to screen) is provided.


Device Bitmaps

A device bitmap is any bitmap whose bitmap bits are stored in device memory (such as RAM on a display adapter) instead of main memory. Device bitmaps can significantly increase the performance of a graphics driver as well as free main memory for other uses. To realize these benefits, the corresponding graphics device must have ample video memory in addition to the video memory used to generate the current display. The device should also have efficient routines for copying bits to video memory.

The DIB engine sets the RC_DEVBITS value in the dpRaster member and all minidrivers are device-bitmap capable. Note that the DIB engine allocates the bitmaps in system memory.

Graphics drivers that set the RC_DEVBITS value in the dpRaster member of the GDIINFO structure support device bitmaps. GDI checks this bit to determine how to carry out requests to create and select bitmaps. If a driver sets the RC_DEVBITS value, it must export the following functions. Minidrivers may forward these calls to the DIB engine:

  • BitmapBits
  • RealizeObject
  • SelectBitmap

BitmapBits copies bitmap data to and from device bitmaps. GDI calls this function when initializing the bitmap bits after creating the bitmap. It also calls the function when an application calls the functions such as GetBitmapBits (GDI.74) and SetBitmapBits (GDI.106).

RealizeObject creates or deletes a device bitmap. GDI calls this function when creating the bitmap, specifying the OBJ_BITMAP style. RealizeObject is responsible for allocating memory to the device as well as filling a physical PBITMAP structure that GDI will use to identify the device bitmap. If the bitmap is to be deleted, RealizeObject must free the device memory.

SelectBitmap associates a device bitmap with the given PDEVICE structure. GDI passes the physical PBITMAP structures of both the currently selected bitmap and the new bitmap so that SelectBitmap can carry out any special processing to enable or disable access to the device bitmaps.

Device bitmaps cannot be monochrome bitmaps. GDI intercepts all requests to create monochrome bitmaps and creates main memory bitmaps instead. This means a graphics driver that supports device bitmaps must also be able to support main memory monochrome bitmaps.

Note If the display driver supports device bitmaps, it must not fail any calls to the SelectBitmap, BitmapBits, or RealizeObject functions. If the driver cannot allocate more video memory for a requested bitmap, it must use GlobalAlloc to allocate system memory instead.


Color Palettes

Display devices that are capable of displaying 256 or more simultaneous colors using a palette need to provide support for color palettes. A display driver specifies that it has palette support by setting the RC_PALETTE value in the dpRaster member in the GDIINFO structure. The display driver also must set the dpPalColors, dpPalReserved, and dpPalResolution members.

The number of reserved colors on the palette is always 16, corresponding to the VGA colors. Half of the reserved palette colors are placed at the beginning and half at the end of the palette.

If a display driver supports color palettes, it must export the SetPalette, GetPalette, SetPalTrans, and GetPalTrans functions.

Hardware-Palette Initialization

A display driver does not need to initialize the hardware palette when the driver initializes the rest of the display hardware. GDI initializes the palette.

Palette -Translation Table

The driver has to maintain a palette-translation table to translate the logical color indexes passed to it by GDI into the actual physical color indexes. The translation has to occur before any raster operation (ROP) is performed. ROPs are always applied to physical colors.

Whenever a display driver function receives a DRAWMODE, LPEN, PBRUSH, or PBITMAP structure, the driver may need to translate the logical colors in these structures to physical colors before using the colors.

An application has to perform color translation only when the physical device is involved. In other words, if a line is drawn into a memory bitmap or a bitmap is block transferred into another memory device, no color translation is required. On the other hand, if a bitmap is transferred to or from the screen into a memory bitmap or a line is drawn directly onto the screen, color translation is required. In the case of a block transfer from the screen to the screen (where the physical device is both the source and destination of the block transfer), color translation is not needed, since all the color indexes are already translated into physical indexes.

Color specifications are passed to display drivers as either color indexes or RGB values. A color index is a 32-bit value in which the high 16 bits is set to 0xFF00 and the low 16 bits is the actual index. An RGB value is a 32-bit value as specified by the RBGQUAD structure. If using the DIB engine, when an RGB value is specified, the driver should call DIB_ColorInfo to match the color as closely as possible among the 16 reserved colors.

A palette-translation table is an array of 16-bit indexes, each mapping a logical color index to a physical color index. A display driver uses the translation table to translate color indexes in physical pens and brushes and in the DRAWMODE structure to the actual color indexes used by the hardware palette.

GDI calls the GetPalTrans and SetPalTrans functions to get and set the translation table. The translation table has the number of elements specified by the dpPalColors member. Because color mapping is complex, drivers using the DIB engine should forward these calls to the DIB engine functions DIB_GetPaletteTranslateExt and DIB_SetPaletteTranslateExt. The function DIB_SetPaletteTranslateExt sets or clears the PALETTE_XLAT bit in the deFlags field of the DIBENGINE structure. When a non-identity palette translate is being set, this function sets the bit. This function clears the PALETTE_XLAT bit when an identity translate is set. Drivers and the DIB engine may use this bit to decide whether palette translation is needed or not. For BitBlt, bypassing color translation results in substantial performance improvements.

UpdateColors Function

If a display driver supports color palettes, it must include the UpdateColors function. GDI calls this function to direct the driver to redraw a region on the screen using the translation table passed to the function. For each pixel in the region, the function retrieves the pixel's color index, translates the index, and writes the translated index back to the given pixel.

Black-and-White Palette Entries

Display drivers that support color palettes must make sure that the index for the palette entry that corresponds to black must be the one's complement of the index for the palette entry for white. Black and white must be static palette entries, meaning the driver sets the indexes for these colors during initialization and does not change the indexes.


Stub Functions

Although the SetAttribute and DeviceBitmap functions are not currently supported in GDI, a display driver must provide these functions. In all drivers, these functions are implemented as stub functions that do nothing more than always return a -1.


Cursors

The USER module requires all display drivers to provide cursor support. A display driver must provide the following functions. Note that the DIB engine provides cursor support and that minidrivers may forward these calls to the DIB engine.

Function | Description
CheckCursor | Draws the cursor if drawing is not disabled.
InquireCursor | Retrieves information about the cursor.
MoveCursor | Moves the cursor to a specified position on the display.
SetCursor | Sets the cursor shape.

When Windows first starts, USER calls the InquireCursor function to retrieve information about the cursor. It then sets a system timer to call the CheckCursor function on each timer interrupt and enables the mouse driver, allowing the Windows mouse-event routine to call MoveCursor at each mouse interrupt occurrence. USER and Windows applications subsequently set the shape of the cursor using SetCursor.

Because USER calls MoveCursor on each mouse interrupt, MoveCursor should set a semaphore to prevent the function from being called before it can complete the current call. The function should set the semaphore using a noninterruptable instruction, such as the bts instruction. Once the semaphore is set, MoveCursor should retrieve the x and y coordinates and draw the cursor in the new position. When finished, MoveCursor should clear the flag with a non-interruptable instruction such as and. Whenever MoveCursor is called, it should check this flag before continuing the request.

The CheckCursor function is called on each timer interrupt. The function should determine whether the cursor needs redrawing and whether drawing is enabled. If so, the function should redraw the cursor.

For displays that do not have a hardware cursor, the display driver should exclude the cursor from the screen before carrying out drawing operations in functions such as BitBlt, Output, and ExtTextOut. The driver should check the current x and y coordinates and exclude the cursor if any part of the cursor lies within the drawing region, as specified in the following.

Operation | Region
Bit-block transfer | Destination rectangle
Ellipse | Bounding rectangle
Other line drawing | Bounding rectangle
Polygon | Clip rectangle
Polyline | Clip rectangle
Scan line | Whole scan line
Text | Bounding rectangle and/or opaquing rectangle


Display-Driver Escapes

A display driver may provide the Control function to give applications direct access the display driver. If using the DIB engine a minidriver should pass any escapes that it has not implemented directly to the DIB engine (using the DIB_Control function) and let the DIB engine determine how to handle the escape. Most display drivers only provide support for the following escapes:

  • GETCOLORTABLE
  • MOUSETRAILS
  • QUERYESCSUPPORT

Applications call the QUERYESCSUPPORT escape to determine whether the display driver supports a given escape.


Mouse Trails

Display drivers can improve mouse cursor visibility (especially on liquid crystal displays) by supporting mouse trails. A mouse trail is a sequence of two or more cursor images that mark current and previous mouse cursor positions. A display driver creates a mouse trail by drawing a cursor at each new mouse position and leaving additional cursors at previous positions. The driver delays erasing the previous cursors until a specified number of cursors are visible.

A display driver provides support for mouse trails by processing the MOUSETRAILS escape in its Control function. The MOUSETRAILS escape enables or disables mouse trails. It also sets the maximum number of cursors to be displayed in the trail. The display driver must also process the QUERYESCSUPPORT escape, returning the status of the mouse trails if the requested escape is MOUSETRAILS.

The display driver draws the mouse trail when it processes the MoveCursor function. Any trailing cursors must have the same shape as the current cursor. The display driver should provide mouse trails for system cursors, such as the pointer and hourglass, and for application-specific cursors as well. Currently, support is not provided for mouse trails for XOR-only cursors, such as the I-beam and the cross-hair cursor used by PaintBrush.

The display driver is responsible for recording the mouse trail status by maintaining the MouseTrails value in the registry. The driver switches this setting to a positive value to indicate that mouse trails capability is enabled. The value also specifies the number of cursors to display. The driver switches this setting to a zero or a negative value when mouse trails capability is disabled. The absolute value specifies the number of cursors to display prior to being disabled.

Users can turn mouse trails on or off by using Control Panel. The mouse settings dialog box displays a Mouse Trails option.

Applications should not enable or disable mouse trails. However, third-party mouse configuration programs could.


Multiple-Resolution Drivers

All Windows 95 drivers support multiple-resolutions. At boot time, the driver must call the VDD function VDD_GET_DISPLAY_CONFIG to get the current color depth, resolution, and other information provided in the DISPLAYINFO structure. If a user wants to change the resolution, the system calls the display driver function ValidateMode multiple times to obtain a list of resolutions that the driver supports. ValidateMode allows the driver to accept or reject the specified resolution. Once the user has picked a resolution from the list, the system calls the function ReEnable and at this point the driver must obtain the latest DISPLAYINFO.

See Also

VDD_GET_DISPLAY_CONFIG, DISPLAYINFO, ValidateMode


Changing the Resolution with a Hot Key

To initiate a dynamic resolution change when the user presses a hot key to switch between the LCD panel of a laptop and an external monitor (CRT), you must write a virtual device (VxD) that has the following capabilities:

  • Enables and disables the LCD and CRT appropriately. The basic input/output system (BIOS) should not handle the hot key.
  • Calls the service BROADCAST_DEVICE_CHANGE and sends the WM_DEVICECHANGE message with the DBT_MONITORCHANGE value as the wParam parameter and the lParam set to zero or to the resolution.

In response to the monitor change message, Windows 95 calls the current display driver to find out if the resolution in the registry is still valid. Because the resolution in the registry is likely to be higher than the resolution that the LCD can handle (typically 640- by 480-pixels), the driver should fail at resolutions set higher than 640 by 480 if the LCD is being enabled. Windows 95 should then call the driver to set 640- by 480-pixels as the resolution. The system will automatically adjust windows and icons and notify applications of the resolution change. This scenario is identical to the user changing the resolution to 640- by 480-pixels using the Display Properties dialog box.

Note When the resolution changes dynamically, the resolution setting in the registry does not change. If the user later presses the hot key to change back to CRT-only mode, the high resolution setting in the registry will be validated by the driver, and Windows 95 will change back to it.

The display driver should not attempt to change the resolution itself since the Windows 95 shell must track resolution changes to maintain the appearance of the desktop and to notify applications. Display drivers should wait for the system to request a change in resolution.

A VxD has the option of specifying a particular resolution in a call to BROADCAST_DEVICE_CHANGE. One reason for specifying one is to support LCD panels capable of resolutions up to 800- by 600-pixels. If the VxD does not specify 800 by 600 as the resolution when enabling the LCD, Windows 95 will automatically specify the highest resolution the device is configured for, (usually 640- by 480-pixels) as the resolution for the display driver to validate and switch to.

Note For Windows 95, the Display Properties dialog box is unable to track the monitor type when the user switches between the LCD and CRT by pressing a hot key. This limitation will be addressed in future versions of Windows.


Display Minidriver Guidelines

If you have created display drivers for earlier versions of Windows, you may prefer to start over again to take advantage of the display minidriver architecture. Your new minidriver will be much smaller and easier to write.

To write a display minidriver, use the following steps to take advantage of the DIB engine

  1. Implement the Enable Display Driver Interface (DDI) and create the PDEVICE structure for the driver. The PDEVICE structure must have the same format as the DIBENGINE structure.
  2. Add code for Disable and Reenable.
  3. Add VDD communication code.
  4. Add hardware acceleration code if necessary.
  5. Add hardware cursor code if applicable.
  6. Add code for the Control DDI.
  7. Process all calls as if they went to the DIB engine.
  8. Add private data for PDEVICE, brushes, and pens if necessary.


Step 1: Minidriver Initialization

There are three stages of minidriver initialization:

  • When the minidriver is first loaded into memory by the kernel.
  • When GDI calls Enable to get the GDIINFO table.
  • When GDI calls Enable to initialize the video hardware.

Note that the parameters passed to the Enable DDI indicate whether the driver should initialize the GDIINFO structure or the video hardware. Drivers should not rely on the order of the Enable calls.

Init Routine (Before GDI)

The kernel calls the display driver's initialization routine when it first loads the driver. At this point, neither GDI nor USER have been loaded, so no graphics operations are required. Instead, you can carry out initialization procedures that do not affect the display adapter. For an example of init code, see the INIT.ASM file in the display driver samples.

Enable GDIINFO

GDI calls Enable twice whenever it creates or restores a display DC. One of the calls is to get the GDIINFO block from your minidriver. For a code example, see the ENABLE.ASM file in the display driver samples.

You must set the following fields in the GDIINFO structure for your adapter. Do this after using the DIB_Enable function to get the information from the DIB engine.

dpVersion | dpNumBrushes
dpHorzRes | dpNumPens
dpVertRes | dpNumFonts
dpBitsPixel | dpNumColors
dpPlanes |

Note that the DIB engine may set capability bits in GDIINFO in addition to those set by the display minidriver. The driver should not modify the bits set by the engine. To achieve this, the driver should use the logical OR operator when setting bits. Minidrivers that do not have an accessible frame buffer should set the NOT_FRAMEBUFFER bit in the deFlags member of the DIBENGINE structure.

If your adapter does not provide a hardware graphics accelerator, set the C1_SLOW_CARD bit in the dpCaps1 member.

When your minidriver has completed initializing the GDIINFO structure, return it to GDI.

Initializing the Hardware

Minidrivers initialize the video hardware and create their PDEVICE structure on one of the calls to Enable.

Use the following steps to initialize your hardware

  1. Initialize the graphics adapter to be in the correct graphics mode. This should include setting the refresh rate based on the current monitor. For more information on refresh rates, see About Refresh Rate Support.
  2. A minidriver should not call FatalExit if it is not possible to enable the hardware. Instead, the Enable function should return zero, indicating failure. This causes the system to reboot into clean Windows with the default VGA driver.
  3. Create the driver's PDEVICE structure by calling the CreateDIBPDevice entry point in the DIB engine with a BITMAPINFO definition of its display surface. The DIB engine will create a PDEVICE structure.
  4. If display memory is banked switched, the driver should call VFLATD to register the frame buffer. The driver must provide a code template that performs bank switching to VFLATD so that the virtual display will work properly. VFLATD will return a selector for accessing the screen. This value is stored in the deBits field of the PDEVICE structure. If the display memory is linear, this step is not necessary. Instead, the driver must create a selector to its linear display memory and store it into the PDEVICE structure. The driver should use MS-DOS protected mode interface (DPMI) services to create the linear selector. Using VFLATD, the driver can ignore the system-memory limitations and obtain an address to a logical frame buffer that is large enough to store the color data for an entire screen.
  5. If the display adapter registers itself as requiring bank switching, whenever a page fault occurs during a drawing operation, the VxD maps the required block of memory from the logical frame buffer to A000:0000. By calling the VxD's Create_Virtual_Frame_Buffer function, a driver registers its bank-switching procedure and obtains a selector identifying the logical frame buffer. For more information about the VFLATD, see About Virtual Flat-Frame Buffer Device.
  6. Route all GDI calls to the DIB engine by including DIBLINK.ASM and DIBENG.LIB in your driver build environment. Note that the Enable call is not routed. Also note that cursor-related calls are handled by the DIB engine.

You now have a generic display minidriver. You need to follow the remaining steps in order to customize your minidriver for your display adapter.


Step 2: Add Code for Disable and ReEnable

Add the hardware-specific code for Disable and ReEnable for your display adapter. For an example of Disable and ReEnable, see the ENABLE.ASM and DISABLE.ASM files in the display driver samples.


Step 3: Add VDD Communication Code

Implement the function ResetHiResMode which is used by the Windows 95 VDD to cause the video hardware to be reinitialized after returning to Windows from a full-screen MS-DOS session.

Drivers must register the address of ResetHiResMode with the Windows 95 VDD module by calling the VDD function VDD_DRIVER_REGISTER. Subsequently, every time that the user switches to a full-screen MS-DOS session, ResetHiResMode is called to do the work. For more information see About Virtual Display Device and About Virtual Display Minidrivers.

See Also

ResetHiResMode, VDD_DRIVER_REGISTER


Step 4: Add Hardware Acceleration Code

Because the DIB engine uses highly-efficient software acceleration routines, it is not necessary to write any software accelerators. To improve display performance, your display adapter may be able to implement specific DDI calls through hardware. If you can use hardware to accelerate some driver drawing calls, performance will be greatly enhanced. The following operations are suggested, in order of importance:

  • Screen to screen blts with the SRCCOPY ROP.
  • Blts with the PATCOPY ROP. Recommended brushes are solid, dithered, pattern, and hatch.
  • The DDI ExtTextOut.
  • Blts with the following ROPS: DSTINVERT, PATINVERT, WHITENESS, BLACKNESS, DPx, DPa (with a mono brush)
  • Solid color lines.
  • PolyScanLine for solid color

For each call you replace with hardware acceleration, take the corresponding line out of DIBLINK.ASM. For example, if you replace StretchBlt with hardware acceleration, remove:

DIBLINK StretchBlt, DIB_StretchBlt

Note If the driver can support multiple chipsets, the Enable section should detect the chipset and set flags for specific accelerators. Only add the detection you need; for example, don't add code to detect bus types if your hardware acceleration code does nothing unusual for a particular type of bus.


Step 5: Add Hardware Cursor Code

If your display adapter has hardware cursor capability, the display minidriver should have code to implement this. Note that color/animated cursors are handled by the DIB engine and the driver must coordinate which cursor is currently visible -either the color (software) cursor or the monochrome (hardware) cursor.


Step 6: Add Code for the Control DDI

Display minidrivers should always use the Control DDI to pass any unrecognized escapes directly to the DIB engine to let the engine determine how to handle the escape.


Step 7: Process All Calls

Even if your display adapter has acceleration code, you must still be able to process all calls (except Enable, Disable, ReEnable, SetPalette, and GetPalette) as if they went to the DIB engine. This is because the DIB engine can draw directly on the display surface when the user sets the Graphics Performance setting to "None". In this case, the system will never call the driver's drawing functions. Instead it will call the DIB engine directly to draw onto the display surface. For this reason, all physical objects (brushes, pens, bitmaps, and the PDEVICE structure) must be complete and in the format defined for the DIB engine. For more information about the DIB engine, see About the Device Independent Bitmap Engine.


Step 8: Add Private Data for PDEVICE, Brushes, and Pens

The size of the PDEVICE structure that the DIB engine expects is declared in the dpDeviceSize field of the GDIINFO block returned by the DIB engine. If the driver needs private data in the PDEVICE, it can allocate it. The dpDeviceSize bytes must be in the DIB engine format and must be built using CreateDIBPDevice. Any private data should go after this in the structure and the minidriver must initialize the data itself.

The sizes of the brushes and pens that the DIB engine uses can be found by hooking the first call to RealizeObject and looking at the return value (for size) from the DIB engine. Any private data should go after this in the structure. The minidriver can set a bit in the Flags field to indicate that the pen or brush has additional data.


Adapters Without Frame Buffers

If you have a display adapter that does not have a frame buffer, you cannot use most of the DIB engine's capabilities. However, you can still use the DIB engine for drawings into memory bitmaps. For more information about using the DIB engine even if you don't have a frame buffer, see About the Device Independent Bitmap Engine.


Device Independent Bitmap Engine

The device-independent bitmap (DIB) engine is a dynamic link library provided by Microsoft. Minidrivers call the functions in this library to perform bitmap operations, manage graphics objects, manage color palettes, and draw lines, curves, filled shapes, and text. Display drivers written for video adapters that do not allow direct access to the frame buffer can also use the DIB engine to perform memory-bitmap operations.


Initialization

If you are writing a minidriver or a display driver that uses the DIB engine to perform memory-bitmap operations, you must call the DIB_Enable function when the Enable function is called to get the capability bits. DIB_Enable initializes the dpCurves through dpStyleLen members of the GDIINFO structure. You must call the DIB_Enable function before the Enable function initializes the members of the GDIINFO structure. Minidrivers that do not have an accessible frame buffer should set the NOT_FRAMEBUFFER bit in deFlags.

Each minidriver has to create a PDEVICE structure in a format recognized by the DIB Engine. If the surface being drawn to is video memory, a DIB, or a color device-dependent bitmap (DDB), the PDEVICE is in the format of a DIBENGINE structure. If the surface is a monochrome bitmap, the PDEVICE is in the format of a PBITMAP structure.

A minidriver should call the CreateDIBPDevice function to initialize the PDEVICE except for monochrome bitmaps. In order to call CreateDIBPDevice, you must first allocate and initialize a BITMAPINFO structure and the DIB bits. GDI allocates memory for the PDEVICE. Use the dpDeviceSize field in the GDIINFO structure to obtain the size in bytes of the PDEVICE. A minidriver should call CreateDIBPDevice the when the Enable function is called to enable the adapter.

A minidriver should not call FatalExit if it is not possible to enable the hardware. Instead, the Enable function should return a value indicating failure. This causes the system to reboot into clean Windows with the default VGA driver.

See Also

DIB_Enable


Color Support

The DIB engine supports drawing on 256-color palettized devices. The color data for these devices is specified in a BITMAPINFO structure. The header section of this structure defines the dimensions and color format of the device's DIB. The array of RGBQUAD structures which follows the header corresponds to the device's palette. The members of the BITMAPINFO structure are initialized by a minidriver or display driver when the Enable function is called.

Drivers do not need to initialize their color table. At boot time, GDI calls SetPalette to initialize the device's color table. The display driver should first forward the call to the DIB engine which will store the colors into the color table. After the DIB engine call returns, the driver should set the contents of the color table into the hardware DAC.

To ensure that colors used in background drawing operations match the current system palette, GDI maintains a palette-translation table. When GDI calls a minidriver's SetPaletteTranslate function for a palettized device, you should call the DIB engine's DIB_SetPaletteTranslateExt function to create an inverse translation table that GDI can use for mapping logical color indices to physical color indices. When GDI calls a minidriver's GetPaletteTranslate function for a palettized device, you should call the DIB_GetPaletteTranslateExt function to retrieve a copy of the current translation table. When GDI calls the UpdateColors function, you should call the DIB_UpdateColorsExt function to update the colors in a given window using the colors in the translation table.

When a non-identity palette translation is set, the DIB engine function DIB_SetPaletteTranslateExt sets the PALETTE_XLAT bit in the deFlags field of the DIBENGINE structure. This function clears the PALETTE_XLAT bit when an identity translate is set. Minidrivers and the DIB engine may use this bit to decide whether palette translation is needed or not. When applicable, this bit is set or cleared for palette translation for bitmaps, brushes, pens, foreground color, background color and text color.

If all palette calls from GDI are routed to the DIB engine, all that is needed to check for palette translation in a function call such as BitBlt is to test the PALETTE_XLAT bit in the deFlags of the PDEVICE parameter. For functions that take one PDEVICE and the PALETTE_XLAT bit is set, the call should be routed to the DIB Engine. For functions that take two PDEVICE structures, the minidriver should check the PALETTE_XLAT bit in both PDEVICE structures. If the bit is set in one, but not both, the call must be routed to the DIB engine. If the bit is set in both PDEVICE structures and the ROP code is SRCCOPY, the operation is a screen-to-screen draw and the minidriver should handle it; no palette translation needs to be done. Otherwise, the call should be routed to the DIB engine because it may need to translate the colors in a brush.

See Also

DIB_SetPaletteExt, DIB_GetPaletteExt, DIB_SetPaletteTranslateExt, DIB_GetPaletteTranslateExt, DIB_UpdateColorsExt


Bitmap Support

You can use the following functions to take advantage of the DIB engine's bitmap support.

Function | Description
DIB_BitBlt | Performs bit block transfers for minidrivers written for video adapters that do not provide bitblt accelerators.
DIB_DibBltExt | Performs a blt operation for a device-independent bitmap to or from a DDB.
DIB_DibToDevice | Performs a blt operation for a device-independent bitmap to the display.

The DIB Engine supports both 5:5:5 and 5:6:5 formats for 16 bits per pixel (bpp) DIBs. The 5:5:5 format means the most significant bit is undefined, the next five bits are red, followed by five bits of green, followed by five bits of blue (R:G:B). The 5:6:5 format means the most significant five bits are red, followed by 6 bits of green followed by 5 bits of blue.

The 5:6:5 format is enabled by setting the FIVE6FIVE bit in the deFlags field of the driver's PDEVICE. A better method is to call CreateDIBPDevice with a BITMAPINFO structure defined for a 5:6:5 DIB.

The DIB Engine supports 32 bits per pixel DIBs. This format is very similar to 24 bpp, except that each pixel is a dword (four bytes) with the most significant byte being undefined. The next significant byte is red, followed by green followed by blue.

The 32 bpp format is enabled by storing the value 32 into the deBitsPixel field of the driver's PDEVICE.

See Also

DIB_BitBlt, DIB_SelectBitmap, DIB_CreateDIBitmap, DIB_DibToDevice


Line-, Curve- and Filled-Shape Support

If you are writing a minidriver that does not provide accelerators for lines, curves, or filled shapes, you should use the DIB_Output function to draw these objects. To draw lines and curves, the OS_POLYLINE style should be specified for the wStyle parameter. To draw filled shapes the OS_BEGINNSCAN should be specified first, followed by multiple OS_SCANLINES. Once the appropriate number of scan lines have been drawn, the OS_ENDSCAN is specified, followed by OS_POLYLINE to draw the outline of the shape.

See Also

DIB_Output


Text Support

To draw text strings, minidrivers should call either DIB_ExtTextOut or DIB_ExtTextOutExt. Call the DIB_GetCharWidth function to retrieve character-width data for a string of text.

Minidrivers can forward ExtTextOut calls from GDI to the DIB engine function DIB_ExtTextOutExt by providing two additional parameters to the argument list. These two parameters are:

lpDrawTextBitmap

lpDrawRect

Both parameters are callback functions provided by the driver that the DIB engine calls to draw the text string and opaquing rectangle.

A minidriver has three options when receiving ExtTextOut calls from GDI:

  • Forward all calls to ExtTextOut to the DIB engine.
  • Forward all calls to ExtTextOut to the DIB engine function DIB_ExtTextOutExt with the lpDrawTextBitmap and lpDrawRect parameters set to the driver's callback functions.
  • Handle the text output directly.

With most accelerators, handling the text output directly will result in the highest performance. However, the callback function specified by lpDrawTextBitmap may be faster for small point-size fonts, depending on the per-character overhead in the driver.

In Windows 95, almost all fonts are converted to the new format specified by the NewFontSeg structure if the driver sets the C1_BYTE_PACKED or C1_BIT_PACKED bit of the dpCaps1 field of the GDIINFO structure. However, it is still possible for the driver to receive an old style font; this is indicated if neither of the ExtTextOut wOptions flags ETO_BYTE_PACKED or ETO_BIT_PACKED is set. In this case, the minidriver should let the DIB engine handle the text output.

See Also

DIB_ExtTextOut, DIB_ExtTextOutExt, DIB_GetCharWidth


Escape Support

Display minidrivers should pass any escapes that they have not implemented directly to the DIB engine (using the DIB_Control function) and let the DIB engine determine how to handle the escape, as shown in the following example:

lds     di,lpInData  ;Get pointer to the data
mov     bx,function
cmp     bx,GETCOLORTABLE
je      C_GetColorTable
cmp     bx,QUERYROPSUPPORT
je      C_QueryRopSupport
push    lpDevice
push    function
push    lpInData
push    lpOutData
call    DIB_Control  ;Let the DIB Engine handle the rest.


Cursor Support

Minidrivers for display adapters that do not support a hardware cursor can use the DIB engine cursor functions to set, move, and manage a software cursor. There is one DIB engine cursor function for each of the cursor functions a driver is required to export. In most cases, the driver simply passes the parameters received by its cursor function to the corresponding DIB engine function, adding the driver's PDEVICE as the first parameter. The following table maps the DIB engine cursor functions to the corresponding GDI cursor functions.

Call this | From
DIB_SetCursorExt | SetCursor
DIB_CheckCursorExt | CheckCursor
DIB_MoveCursorExt | MoveCursor
DIB_Inquire | InquireCursor


Color Cursors

The DIB Engine's software cursor supports color cursors. A color cursor consists of a monochrome AND mask followed by an XOR device dependent bitmap. For example, on an 8 bpp display, the color cursor passed to the display driver on the SetCursor call would look like:

csHotX        DW    ?
csHotY        DW    ?
csWidth       DW    ?
csHeight      DW    ?
csWidthBytes  DW    ?
csColor       DW    ?            ; 0101h = mono, 0801h = 8bpp, etc.
csANDBits     DB    4*8 dup (?)  ; 32x32 bit mask = 4 bytes/row
                                 ; with 8 rows
csXORBitS     DB    32*8 dup (?)    ; 32x32 pixels = 32 bytes/row
                                 ; with 8 rows

Note that the device dependent portion of the cursor is still XORed onto the screen.

A driver informs the system that it is color-cursor capable by setting the C1_COLORCURSOR bit in the dpCaps1 field of the GDIINFO structure passed back to GDI Enable is called to get the capability bits. The DIB engine does not set this bit even though it supports color cursors. Minidrivers must set this bit explicitly.

If the driver does not set this bit, it will never be passed a color cursor. If the driver sets this bit, it can receive either monochrome or color cursors.

Most minidrivers should just let the DIB Engine's software cursor code handle the drawing of the color cursor. This presents special problems for drivers that have hardware monochrome cursors. A driver has to dynamically "turn off" its hardware cursor and "turn on" the DIB Engine's software cursor.


Animated Cursors

There is little driver involvement to support animated cursors. If the driver sets the C1_COLORCURSOR bit in the dpCaps1 field of the GDIINFO structure, this also implies that the driver can handle an animated cursor. Windows 95 implements cursor animation by calling SetCursor with a new image at a set time interval. To handle cursor animation, a driver needs to insure that:

  • SetCursor does not flicker.
  • SetCursor can be called at an asynchronous time.

With previous versions of Windows, SetCursor could not interrupt MoveCursor or CheckCursor. This is no longer the case for animated cursors. SetCursor can now fail and return a 0 in the AX register. This is useful if, for example, the cursor is "busy" and the image cannot be changed.


Mouse Trails

The DIB Engine's software cursor supports mouse trails. To use this, a driver needs to make sure that it chains escape calls to the DIB Engine to allow activation and deactivation of mouse trails. In addition, drivers with hardware cursors need to know when to shift to the DIB Engine's cursor to make mouse trails visible. This is done by hooking the mouse trail escape call. On the mouse trails escape, the driver may need to switch from hardware to software cursor.


Frame Buffer and Cursor Access

The DIB engine provides the DIB_BeginAccess and DIB_EndAccess functions to support exclusion and restoration of the software cursor implemented by the DIB engine. These functions are also used to support controlled access to the frame buffer of the display adapter.

The minidriver excludes cursor drawing by specifying the exclusion rectangle in a call to the DIB_BeginAccess function. In this case, the Flags parameter of the function must be set to CURSOREXCLUDE. The minidriver removes the exclusion rectangle by calling the DIB_BeginAccess function with the CURSOREXCLUDE value.

To support controlled access to the frame buffer, the minidriver must set the deBeginAccess and deEndAccess fields of its PDEVICE structure to the addresses of its BeginAccess and EndAccess callback functions. If these fields are non-zero, the DIB engine calls the callback functions before and after accessing the device's frame buffer with the FB_ACCESS value. The purpose of the BeginAccess and EndAccess callback functions is to allow an accelerator to become idle before letting the DIB engine touch the screen.

The return value and parameters for the BeginAccess and EndAccess callback functions are identical to those for the DIB_BeginAccess and DIB_EndAccess functions.

Drivers use the BUSY bit to disable the frame buffer when switched away to a non-Windows application running in the full screen. In addition, drivers should set this bit whenever exclusive access to the frame buffer is needed. For example, a driver might have to put the adapter into a special mode to handle a fast bit-block transfer. While in this mode, the driver should set the BUSY bit so that no asynchronous event (for example, a software cursor in the DIB engine) attempts to write to the screen. The driver does not need to set the BUSY bit when BeginAccess is called. The BUSY bit must only be set when the system VM is switched to the background or when it is necessary to protect the screen from asynchronous drawing.

Note Future versions of the DIB engine may draw directly on the display framebuffer. The busy bit in deFlags will be the only mechanism to determine if the frame buffer is accessible. If your driver does not set this bit correctly, it may not work with future versions of the DIB engine. New drawing code in the DIB engine is not necessarily limited to synchronous, new DDI-type functions. Asynchronous drawing code (for example, a second cursor) may be added, which means a driver may need to set or clear the busy bit even if it is running with a hardware cursor.


Brush Support

DIB_RealizeObject converts logical drawing objects to physical drawing objects. For brushes, the logical brush structure, LOGBRUSH, has two colors in it, lbColor and lbBkColor. The member lbColor is a logical color. This is the color that the display driver should use to generate a solid brush. Since the display driver may not be able to directly support this logical color (for example, it might not be one of the 16 colors that a driver running in 16 color mode can support), it should create a dither pattern that closely approximates this color. From GDI's perspective, this is still a solid brush because the brush style lbStyle is BS_SOLID.

Brushes have three sections: the color part, the monochrome part, and the transparency mask (which is used with hatched brushes). The color part is used to draw on the screen or DDB, and the monochrome part is used to draw on old-style monochrome bitmaps.

The member lbBkColor is only used when a hatched brush is realized. The lbBkColor member is a physical color that has been previously converted from logical to physical with a call to DIB_ColorInfo.

When the DIB Engine realizes a hatched brush, it maps all 1 bits in the pattern to the foreground color and all 0 bits in the pattern to the background color and puts the results into the dp8BrushBits member of the DIB_Brush8 structure. During realization the DIB engine also converts the logical foreground color into a physical color and stores it into dp8FgColor member. The DIB engine does this so that drivers that have hardware acceleration can draw fast hatched brushes by loading the color in dp8FgColor into their foreground color register, loading the color in dp8BgColor into their background color register, and then drawing with the bit pattern in the dp8BrushMask portion of the brush. Common video hardware has color expand capability that will automatically map the 1 bits to the contents of their foreground color register and the 0 bits to the contents of their background color register.

In summary, the dp8FgColor member contains a logical color if the brush style is BS_SOLID or BS_PATTERN (although it is not used for pattern brushes). If the brush style is BS_HATCHED, dp8FgColor contains a physical color. The dp8BgColor member is only used with BS_HATCHED style brushes and it is a physical color.

See Also

DIB_Brush


New Font Format and ExtTextOut

The new physical font format and implementation in Windows® 95 is different than in previous versions of Windows. Additionally, the ExtTextOut function has been simplified so that display drivers contains less code. This section describes the new font format and highlights the changes to ExtTextOut for display drivers in Windows 95.


The New Font Format

Handling the new font format is optional for display drivers. A display driver indicates that it is capable of handling the new font format as well as the Windows 3.x font format by setting the C1_BYTE_PACKED or C1_BIT_PACKED bit in dpCaps1 of the GDIINFO structure at enable time.

The NewFontSeg structure defines the new font format and replaces the old FONTINFO structure.

typedef struct _NewFontSeg
{
    WORD  nfVersion;      // version of the font header
    WORD  nfFormat;          // format flags for font
    WORD  nfNumGlyphs;    // number of glyphs in the font
    DWORD nfGlyphOffset;  // offset to array of glyph pointers
    DWORD nfAWTable;      // offset to array of glyph advance widths
    WORD  nfHeight;          // windows font height
    WORD  nfAscent;          // distance from top of font to baseline
    DWORD nfUniqueID;     // unique value that identifies this font
} NewFontSeg;

The new header is simpler than the old FONTINFO structure. Only the information needed to locate the glyph bitmaps and do font caching in the driver is available. All other information is maintained by GDI.

The main differences between the old format and the new format are:

  • Simplified font header as defined by the NewFontSeg structure.
  • Movable glyph offset table.
  • Movable advance width table.
  • Multiple glyph bitmap representations.
  • Unique ID to help font caching.
  • Full glyph metrics.
  • Simplified ExtTextOut device driver interface (DDI).
  • Only the black box of the glyph is stored. No 0 bits are stored on the left, right, top or bottom of the character.
  • Glyphs are row ordered.
  • Glyphs can be stored in byte-packed or bit-packed format.

Byte-packed glyphs are stored in rows where each row is padded out to a byte boundary. For example, a glyph that is 1 pixel wide and 10 pixels tall would require 10 bytes [int((1+7)/8)* 10] of storage. Each glyph bitmap is preceded by a header.

typedef struct _SMALLROWGLYPH
{
  SBYTE srgOrgX;  // distance from glyph org to left edge of blackbox
  SBYTE srgOrgY;  // distance from glyph org to top of glyph blackbox
  BYTE  srgWidth; // width of glyph's blackbox
  BYTE  srgHeight; // height of glyph's blackbox
} SMALLROWGLYPH;

typedef struct _LARGEROWGLYPH
{
  SHORT lrgOrgX;  // distance from glyph org to left edge of blackbox
  SHORT lrgOrgY;  // distance from glyph org to top of glyph blackbox
  USHORT  lrgWidth;  // width of glyph's blackbox
  USHORT  lrgHeight; // height of glyph's blackbox
} LARGEROWGLYPH;

Bit-packed glyphs are stored in rows with no padding. For example, the same 1x10 glyph would only require 2 bytes [int((1*10+7)/8)] of storage. Bit-packed format yields the highest memory savings and highest performance provided the display hardware can accept data in this format. Each glyph bitmap is preceded by a header.

typedef struct _SMALLBITGLYPH
{
  SBYTE sbgOrgX; // distance from glyph org to left edge of blackbox
  SBYTE sbgOrgY;  // distance from glyph org to top of glyph blackbox
  BYTE  sbgWidth;  // width of glyph's blackbox
  BYTE  sbgHeight; // height of glyph's blackbox
  BYTE  sbgPixels; // number of bits in glyph (width * height)
} SMALLBITGLYPH;

typedef struct _LARGEBITGLYPH
{
  SHORT lbgOrgX;  // distance from glyph org to left edge of blackbox
  SHORT lbgOrgY;  // distance from glyph org to top of glyph blackbox
  USHORT  lbgWidth;  // width of glyph's blackbox
  USHORT  lbgHeight; // height of glyph's blackbox
  USHORT  lbgPixels; // number of bits in glyph (width * height)
} LARGEROWGLYPH;

See Also

NewFontSeg, SMALLROWGLYPH, LARGEROWGLYPH, SMALLBITGLYPH, LARGEBITGLYPH


ExtTextOut

The ExtTextOut function has been simplified in Windows 95 so that display drivers contains less code. The meaning of some of the parameters and how the driver should draw the text has changed slightly from previous versions of Windows.

If either the ETO_BYTE_PACKED or ETO_BIT_PACKED wOptions flag is set, the font pointed to by the lpFontInfo parameter is in the new format defined by the NewFontSeg structure. These flags specify the format of the glyph header and the glyphs as either byte-packed or bit-packed. If neither of these flags is set, lpFontInfo points to the old font format defined by the FONTINFO structure.

Both the old and new font formats have been adapted for large (2 bytes) character set fonts. If the font used in ExtTextOut is a large font, for old style fonts, the PF_GLYPH_INDEX bit is set in the dfType field of the FONTINFO structure pointed to by the lpFontInfo parameter. For large fonts in both old and new formats, the ETO_GLYPH_INDEX bit in the wOptions parameter of ExtTextOut is set.

When ExtTextOut is passed a font in the old format and the flag ETO_GLYPH_INDEX is set, the lpString parameter points to a word array of glyph indexes specifying which glyphs to draw. Invalid characters will point to the default character so no range checking is required in the driver. Each index can be used directly and does not require subtraction of the first character index.

When ExtTextOut is passed a font in the new format, the lpString parameter points to an array of glyph indexes, not character codes. Glyph indexes are simple indexes in the nfGlyphOffset and nfAWTable arrays and are not language specific. Using glyph indexes allows the same driver to be used for all languages. The ETO_GLYPH_INDEX flag for the ExtTextOut wOptions parameter indicates whether the glyph index array is a BYTE array or WORD array. If this flag is set, the glyph index array is a WORD array; otherwise it is a BYTE array.

A display driver declares itself as Glyph Index capable by setting the C1_GLYPH_INDEX bit in the dpCaps1 field of GDIINFO. If the driver sets just the C1_GLYPH_INDEX flag and not C1_BIT_PACKED or C1_BYTE_PACKED, bitmap fonts are passed to the driver with the ETO_GLYPH_INDEX flag clear and TrueType fonts are passed to the driver with the ETO_GLYPH_INDEX flag set. If the driver does not set C1_GLYPH_INDEX, C1_BIT_PACKED, or C1_BYTE_PACKED, the fonts are always in the old font format and lpString always points to a byte array where the index into the character offset table must be computed by subtracting the index of the first character from lpString[ i ].

The ExtTextOut parameter lpOpaqueRect points to a NULL-terminated list of rectangles. The driver should opaque all of the rectangles given in this list if lpOpaqueRect is non-NULL. The lpTextXform parameter points to a rectangle structure defining the text bounding box of the string. In opaque mode, the lpTextXform rectangle is included in the list of rectangles pointed to by lpOpaqueRect.

Display drivers should draw the rectangles specified in lpOpaqueRect using the background color specified in the lpDrawMode parameter. Next, the driver should draw the text transparently on top using the text color specified in lpDrawMode. The driver should clip all output to the rectangle specified by the lpClipRect parameter. The driver does not have to check for the flags ETO_OPAQUE and ETO_CLIPPED.

In Windows 95, the wDestXOrg and wDestYOrg parameters point to the origin of the first glyph, not the upper left corner of the text bounding box as it did in previous versions of Windows.

The driver no longer needs to process any of the fields in the DRAWMODE structure to determine character placement. All special spacing information is computed in GDI and passed to the driver in the ExtTextOut lpDx parameter. The lpDx parameter points to an array of words that defines the number of pixels to advance after drawing each character. The first character advances by the first value in the lpDx array, the second character advances by the second value in the lpDx array and so on.

If no special spacing is necessary, the lpDx parameter will be NULL, indicating to the driver that it should use the nfAWTable array in the NewFontSeg structure to move to the next glyph origin. This table defines the number of pixels to advance by for each glyph. This table is indexed by the glyph index.

See Also

NewFontSeg, SMALLROWGLYPH, LARGEROWGLYPH, SMALLBITGLYPH, LARGEBITGLYPH


Virtual Display Device

The Windows® 95 Virtual Display Device is composed of two VxD's. The first is VDD.VXD, supplied by Microsoft, and is combined by the Windows 95 Setup program into the file VMM32.VXD. This is referred to as the Main VDD, and it contains all virtual device functionality for standard VGA compatible devices. If your display adapter has hardware-specific needs that the Main VDD does not meet, you must write a virtual display minidriver (mini-VDD) to perform additional virtualization. The Main VDD and your mini-VDD are the two VxDs that make up the Virtual Display Device.

This section provides an overview of the Virtual Display subsystem and describes the Ring 3 function calls that a display driver can make into the Main VDD. For information about implementing a mini-VDD, see About Virtual Display Minidrivers. For information about VDD services available to mini-VDDs see About Virtual Display Device Services.


Overview of the Windows 95 VDD

The Main VDD serves as the control point where all calls into the Virtual Display subsystem go. A Ring 3 display driver or a Ring 0 VxD (such as SHELL.VXD) would always call the Main VDD in order to accomplish a task; they never call a mini-VDD directly. If necessary, the Main VDD calls the device-dependent mini-VDD. The mini-VDD contains all of the functionality needed to virtualize high resolution Super VGA hardware such as those made by S3, ATI, Western Digital, or Cirrus. The device driver kit contains many sample mini-VDD sources that you can use as examples when writing your own mini-VDD.

You should utilize the new VDD interface for Windows 95 rather than using an old Windows 3.x VDD. The new VDD interface contains many functions that a Windows 95 compliant mini-VDD can take advantage of. For example:

  • Automatic MS-DOS session support for East Asian double byte character set (DBCS) and Middle Eastern right-to-left languages. The mini-VDD is totally language independent and all DBCS and right-to-left dependencies are implemented in the Main VDD.
  • High resolution VESA game support. Playing a VESA game in a MS-DOS session would cause a Windows® 3.1 VDD to crash.
  • Supports VGA 4 plane graphics modes in a window. This support is easy to implement in the mini-VDD. The Main VDD takes care of all of the hard work.
  • Faster windowed text mode support.
  • Easier to maintain than a Windows 3.x VDD. A mini-VDD consists of approximately 50 easy to implement functions. The Main VDD takes care of all of the hard work.
  • The Windows 95 VDD works in concert with the Windows 95 Mini Display Driver interface to provide a much more reliable full-screen windowed MS- DOS interface.
  • Plug and Play automatic loading of the display components including your display driver, mini-VDD, and monitor support. Your mini-VDD can automatically set monitor refresh rates using the Plug & Play interfaces.
  • The Main VDD calls the ROM BIOS on the video card, and provides reliable mode changes between Windows graphics mode and MS-DOS sessions.

Included in the Device Driver Kit (DDK) are a number of mini-VDD samples, and the files VDD.VXD and VDD.SYM that you can use in debugging your mini-VDD. Because the Main VDD is a Windows 95 core component, the source code is not included in the DDK. However, some of the basic concepts are similar to the VDDVGA.386 sources included in the Windows 3.1 DDK. So if you have a Windows 3.1 DDK, you can follow those sources as a rough guide.

The mini-VDD is closely intertwined with the display driver. You should implement a Windows 95 Mini-Display-Driver and mini-VDD together although a Windows 3.1 display driver can also use the Windows 95 VDD interface with just a few modifications to the display driver's Enable code.


VDD Functions

There are currently ten function calls that a display driver can make into the VDD subsystem. Any Ring 3 Windows program can call these functions, but their use outside of Windows core components such as the display driver are limited. You must include MINIVDD.INC in your source files if you want to call these functions.

Before using any of the VDD functions from a Ring 3 driver you must call the following Interrupt 2Fh functions.

  • Call Interrupt 2Fh, Function 1684h passing device ID 0Ah (0Ah is the device ID for the VDD) in the BX register. This will return the entry point that the ring 3 driver can call whenever it wants to call a VDD function. You should save this Selector:Offset address which is returned in ES:DI. If you get a NULL pointer back, it means that the VDD has not been loaded and that the system is in an unstable state.
  • Call Interrupt 2Fh, Function 1683h. This returns a magic number in the BX register that you should save because you must use this number whenever calling the VDD's entry point. This documentation will refer to the return value from this call as the Magic number.


Virtual Display Minidriver

The Main VDD supplied by Microsoft provides virtual device support for standard VGA compatible devices. A virtual display minidriver (mini-VDD) is a VxD that allows a video hardware manufacturer to add virtual device support for hardware extensions beyond standard VGA capabilities. This section provides detailed information on how to implement a mini-VDD. For an overview of the Virtual Display subsystem and information on VDD functions for use by display drivers, see About Virtual Display Device. For information about VDD services available to mini-VDDs see About Virtual Display Device Services.

The sample mini-VDDs that come with the Device Driver Kit (DDK) provide a good starting point for building your own mini-VDD. This section is intended to augment the information that can be found in the sample source and header files. This section and the samples use the following terminology.

CB data structure | Windows creates the CB data structure for each VM started in the system. Your mini-VDD allocates space in the CB data area to save register and mode states on a per-VM basis. The data that your mini-VDD saves in the CB data area in the space that you have allocated varies for every mini-VDD.
CRTC owner and MemC owner | The CRTC owner VM is the VM that owns the screen mode. If you are running on the Windows desktop, then the Windows VM is the CRTC owner. If you are running a full-screen MS-DOS session, then that MS-DOS session's VM is the CRTC owner. If you are running a MS-DOS session in a window, then the CRTC owner is Windows but the MemC owner is the MS-DOS VM. This distinction is necessary when restoring register states. When you restore the register state of a MS-DOS VM running in a window, it means that you are getting ready to virtualize the VGA by using the off-screen memory. Your VGA hardware must be setup to write to this memory in exactly the same way as if the VGA was running in native VGA mode. But you must also preserve the appearance of the Windows screen which is being displayed on the visible screen. Thus, the screen looks like it is running in Windows hi-res packed pixel mode from the user's perspective, but the CPU sees the video memory as a 4 plane VGA. Therefore, you can restore those states from the CRTC owner that preserve the appearance of the screen while restoring those states from the MemC owner that control how the CPU sees the video memory.
Magic number | The VDD's entry point that is returned in the BX register from the call Interrupt 2Fh, Function 1683h.


Mini-VDD Overview

The Main VDD provides approximately fifty functions that a mini-VDD can hook out to provide functionality other than what is supplied by the Main VDD. When a function is hooked out, the Main VDD does not call its default function, and instead calls the mini-VDD function. Most of the mini-VDD functions are easy to implement (such as changing banks on a video card). The big challenge in writing a mini-VDD is to decide what functions your hardware needs in order to get good full-screen and windowed MS-DOS support.


Initialization

The loading and initialization of the mini-VDD is done very early in the boot sequence of Windows 95 at the Device_Init stage of VxD initialization. Your mini-VDD must implement the function MiniVDD_Dynamic_Init. MiniVDD_Dynamic_Init is called as soon as the mini-VDD is dynamically loaded by the Windows 95 Plug & Play subsystem.

One of the main tasks that the function MiniVDD_Dynamic_Init must perform is hooking out the mini-VDD functions. To hook out the functions, first get the 32 bit flat address of the dispatch table from the Main VDD via the VxDCall VDD_Get_Mini_Dispatch_Table. After obtaining the address of the dispatch table, use the MiniVDDDispatch macro found in MINIVDD.INC to hook out the functions that you need. Refer to any of the example mini-VDDs to see how to call VDD_Get_Mini_Dispatch_Table and how to hook out functions.

There are several other tasks that MiniVDD_Dynamic_Init must perform. See MiniVDD_Dynamic_Init for complete details.


CardVDD

Just as you can let the Main VDD do most of the work and only implement functions in the mini-VDD that add unique functionality, you can let one of the standard chipset mini-VDDs do most of the work and only implement unique functionality in a CardVDD. Suppose that you are a video card maker who uses a standard chipset for which there is already mini-VDD support provided by a chipset manufacturer (such as S3, Cirrus, Western Digital etc.). Suppose you have implemented your particular card in a unique way that the chipset designer did not anticipate when writing their mini-VDD. You can implement an additional VDD module called a CardVDD which is loaded after the mini-VDD, and can hook out mini-VDD functions that your card needs to implement after the mini-VDD has already hooked out its functions. Therefore, you can implement unique added functionality without having to reimplement all of the functions already in the mini-VDD.

For example, suppose your new card is based on the S3 chipset, and that the card's functionality is identical to the standard S3 functionality, except that your card sets monitor refresh rates in a different way. The S3.VXD, the mini-VDD for all S3 chipsets, implements PRE_CRTC_MODE_CHANGE in order to set monitor refresh rates using the standard S3 interface. You can create a CardVDD that hooks out PRE_CRTC_MODE_CHANGE so that your function is called instead of the one in S3.VXD. However, all other functions are called in S3.VXD and you do not have to reimplement all of the functionality in S3.VXD just because your card is unique in this one way.

CardVDDs are loaded in the same way as mini-VDDs. To distinguish your CardVDD from a mini-VDD, change the registry key in your .INF file to be "cardvdd=xxxx.vxd" instead of "minivdd=xxxx.vxd.


VESA Support

The Windows 95 VDD now has built in support for running VESA hi-res mode applications full-screen. If your mini-VDD allows it, the user can press ALT-TAB and switch away from the VESA hi-res mode application back into Windows or another MS-DOS window. Your mini-VDD can also support proprietary hi-res modes for hi-res applications that have drivers for your hardware. As part of your testing effort, you should obtain games and other applications that run in VESA hi-res modes.

The Main VDD calls helper functions that your mini-VDD hooks out. If your mini-VDD has not hooked out a helper function (or if it fails the call), then the Main VDD will attempt to make the appropriate VESA calls to accomplish the tasks that it needs to (such as changing banks, getting the amount of VRAM on your card, etc.). You should implement as much VESA support in your mini-VDD as possible since this will assure stability when running VESA hi-res mode applications under Windows 95.

You can implement all the VESA support entirely in your mini-VDD. Doing so will cause VESA applications to run more efficiently since all of the VESA support is done at Ring 0. You can expect a 20% speed increase by implementing VESA functionality in your mini-VDD over using a real mode VESA driver.

Following are the VESA functions you can implement in your mini-VDD:

CHECK_HIRES_MODE
CHECK_SCREEN_SWITCH_OK
GET_BANK_SIZE
GET_CURRENT_BANK_READ
GET_CURRENT_BANK_WRITE
GET_TOTAL_VRAM_SIZE
POST_HIRES_SAVE_RESTORE
PRE_HIRES_SAVE_RESTORE
SET_BANK
SET_HIRES_MODE
VESA_CALL_POST_PROCESSING
VESA_SUPPORT


Refresh Rate Support

When called to set the video mode in Enable, ReEnable, etc., display drivers written for Windows® 95 should set the refresh rate based on the current monitor selected in the Display control panel. The sample XGA driver source code in the Device Driver Kit (DDK) demonstrates how to do this.

When refresh rate support is enabled for a driver, the virtual display device (VDD) provides the following information about the current monitor in the DISPLAYINFO structure (defined in MINIVDD.INC) returned by VDD_GetDisplayInfo:

  • Pre-calculated maximum vertical refresh rate: If there is a VESA DDC EDID monitor identifier for the current monitor in the registry, the VDD returns the highest standard refresh rate supported for the current resolution. Otherwise, it calculates an estimated maximum refresh rate for the current resolution using the frequency ranges in the software registry key for the current monitor.
  • Horizontal and vertical frequency ranges: When the user selects the monitor type in the Display control panel, these ranges are written to the software registry key by the monitor INF file. If a monitor supports multiple timing ranges, the VDD returns the optimal range for the current resolution.
  • VESA DDC EDID structure: If Windows 95 is configured to detect VESA DDC monitors, and a DDC monitor is detected, its 128-byte EDID structure is stored in the monitor's hardware registry key. The DISPLAYINFO structure returned by the VDD contains a handle for the current monitor that can be passed to the registry API to return the EDID structure. For more information, see the section Reading the EDID for the Current Monitor.

The most simple display driver would set the refresh rate based on the pre-computed refresh rate value returned for #1. Depending on the video BIOS services available to it, a more sophisticated driver might use the horizontal and vertical ranges specified by #2. An even more optimized driver can read the EDID data directly from the registry, using the handle returned in the DISPLAYINFO structure, and optimize display timings based on it.


Enabling Refresh Rate Support

The VDD returns monitor values in the DISPLAYINFO structure only if the RefreshRate value is present in the display driver's software registry key. If your display driver supports setting refresh rate based on DISPLAYINFO or EDID, the driver's INF file should include the following lines in its AddReg section:

HKR,DEFAULT,RefreshRate,,-1
HKR,DEFAULT,DDC,,1

The first line sets the RefreshRate value for the driver to -1, which tells the VDD to return a pre-computed refresh rate based on the EDID or registry timing ranges for the current monitor. If RefreshRate is set to a positive integer value, the VDD will return this override value instead (intended for future use with a refresh rate user interface).

The second line tells VDD to make the VESA DDC BIOS function call at boot time to attempt to detect the monitor and store the EDID returned by it, if any, in the registry. If DDC=1 is not present, VDD will not attempt to read the monitor EDID structure.

For more information about the INF file format, see the "Display Driver Install Disk" section.


VESA DDC Support Overview

The VDD has the ability to detect DDC compatible monitors at boot time. However, in the retail upgrade version of Windows 95, this support is disabled by default. To enable DDC, the value "DDC=1" must be added to the Windows 95 registry in the software key for the current display driver. The installation disk for the display driver should add this value if the driver supports refresh rates via DISPLAYINFO or EDID, as described in the section Enabling Refresh Rate Support.

When DDC support is enabled, Windows 95 detects and installs DDC monitors as follows

Note Because it is the Windows 95 VDD that calls the DDC BIOS, Windows 95 DDC support requires a Windows 95 compatible display driver. Display drivers and virtual display drivers written for Windows 3.1 cannot use the DDC support in Windows 95.

  1. At boot time, the main VDD makes the VESA DDC BIOS function call to check for a DDC compatible monitor.
  2. If the ReadEDID call succeeds, a hardware key for the monitor is written to the Windows 95 registry, using the hardware ID generated from the manufacturer and product ID values found in the EDID. The hardware key is created as follows:
    HKEY_LOCAL_MACHINE
  \Enum
    \Monitor
      \<Device ID, e.g. ABC1234>
        \<instance value, e.g. 0001, 0002, etc.>

          HardwareID=<device id>, *PNP09FF
          EDID=<128-bypte structure returned from VESA BIOS>
  3. The VDD calls the Plug and Play Configuration Manager to create a dev node for the monitor in the current Windows session. "Dev nodes" are internal data structures which represent a device and contain information such as their ID, resource usage (null for monitors), and registry location.
  4. If the monitor has previously been detected and installed, the enumeration process is complete at this step. If this is a new ID not previously seen on this computer, then the installation process begins. Configuration Manager calls the Device Installer to create a software key for the monitor.
  5. A "New Hardware Found" dialog will appear while the Windows 95 Device Installer searches all of the INF files in the Windows 95 \INF subdirectory (hidden) to find a match for the monitor's device ID. If it finds the ID in one of its INF files, the dialog will be updated to indicate the name of the monitor, and Windows 95 will automatically create the monitor's software key in the registry using information from that INF file, including its manufacturer and model names, maximum resolution, DPMS support, and horizontal and vertical frequency ranges.

Because not many DDC monitors shipped at the time of Windows 95 retail release, it is likely that a monitor's ID will not be recognized by Windows 95. To address this issue, when the VDD created the hardware key for the DDC monitor, it appended "*PNP09FF" to the HardwareID value. This is a secondary ID that is used to install unrecognized DDC monitors. This ID matches against a generic monitor type in the Windows 95 MONITOR.INF file called "Plug and Play Monitor (VESA DDC)". In the Display control panel, users can change to a more specific monitor type by selecting from the list of supported monitors, or by using a Windows 95 configuration disk supplied by the monitor manufacturer.


Reading the EDID for the Current Monitor

Your display driver or mini-VDD can use the EDID structure returned to the VDD at boot time by retrieving this structure from the registry. This can be done once your display driver (or mini-VDD) has called VDD_GET_DISPLAY_CONFIG (or VDD_GetDisplayInfo if your mini-VDD is issuing the call from ring 0).

To retrieve the EDID for the current monitor

  1. Get and save the diMonitorDevNodeHandle member of the DISPLAYINFO structure.
  2. Call CONFIGMG_Read_Registry_Value. Make sure that you have CONFIGMG.INC in your include directory. The parameters for the call should be as follows.
Parameter | Value
dnDevNode | diMonitorDevNodeHandle retrieved from the DISPLAYINFO
pszSubKey | NULL (no subkey needed)
pszValueName | A pointer to the ASCIIz string "EDID"
ulExpectedType | REG_BINARY
Buffer | A pointer to a 128 byte buffer (the EDID plus the null terminator) which will receive the EDID data back
pulLength | Size of Buffer (129 bytes or longer)
ulFlags | CM_REGISTRY_HARDWARE

If CONFIGMG_Read_Registry_Value returns CR_SUCCESS, the EDID structure for the current monitor will be in your Buffer, available for use by your driver or mini-VDD to determine appropriate timings from it.

If the call fails, then there is no EDID structure for the monitor present in the registry. In this case your driver should use an alternate means for setting monitor timings.


Virtual Display Device Services Reference

The virtual display device (VDD) is a VxD supplied by Microsoft that performs all standard virtualization of display adapters. This section provides detailed descriptions of the VDD services that a virtual display minidriver (mini-VDD) may use. For an overview of the Virtual Display subsystem and information on VDD functions for use by display drivers for information, see about implementing a mini-VDD, see About Virtual Display Minidrivers.

This section provides detailed reference information for the VDD services. For the most part, a Windows 95 mini-VDD will only need the new Windows 95 VDD services. However, some of the Windows 3.x VDD services are still available for use by mini-VDDs.


Windows 95 Services

Previous Next

Windows 95 Services\

The following topics document the Windows 95 services.


VDD_Do_Physical_IO

Call With

EAX: Contains the value to send out the port (writes only).

EBX: Contains the VM handle that is doing the I/O.

ECX: Contains the I/O type (see VMM.INC for details).

EDX: Contains the port to do the I/O to.

Client registers contain the I/O parameters if ECX indicates that the VM wants to do string I/O.

Return Values

Nothing.

Remarks

This service may be used, not only by mini-VDDs, but by any Ring 0 VxD that wishes to perform physical I/O on behalf of a VM client. This service provides all types of I/O to the caller. For string I/O, the parameters of the I/O (for example, Selector:Offset, number of bytes, words, or doublewords to move etc.) are provided in the client registers.

If a mini-VDD or VxD decides that it wants to just allow the I/O that it has trapped to be sent to the actual hardware, it calls this service. This routine then performs the I/O, updates the client registers as appropriate and then returns so that it appears to the VM that the I/O operation has been successfully completed. The VxD caller does not have to make any decisions on doing I/O on its own. The Main VDD understands and accomplishes the physical I/O on behalf of the VM.


VDD_Get_DISPLAYINFO

Call With

EAX: Points to a DISPLAYINFO structure to fill.

ECX: Contains the size in bytes of the DISPLAYINFO structure that is passed to this service.

Return Values

All registers are destroyed by the call. EAX = 0 means that the caller's DISPLAYINFO structure has been successfully filled with data. EAX = -1 means that there was an error and that the structure is invalid.

Remarks

This is the Ring 0 equivalent of the function VDD_GET_DISPLAY_CONFIG. All remarks that apply to that function are valid for this service.


VDD_Get_Mini_Dispatch_Table

Call With

None

Return Values

ECX contains the number of mini-VDD Hookable Functions in the table. EDI contains the 32 bit linear address of the mini-VDD dispatch table. All other registers are preserved.

Remarks

This function can only be called up to and including the Init_Complete phase of VxD initialization. It will cause a fatal page fault if called after Init_Complete.

This service is used by all mini-VDD's in order to hook the callouts that the Main VDD provides to the mini-VDD. The mini-VDD calls this service and then uses the MiniVDDDispatch macro (found in MINIVDD.INC) to install the addresses of the routines that it wants to hook. The mini-VDD that calls this service should check the value returned in ECX against the number of functions that it intends to hook. If the value returned in ECX is less than the number of functions that the mini-VDD intends to hook, the mini-VDD should fail to load since trying to set a hook that the Main VDD does not understand would cause a GP Fault. If the value returned in ECX is greater than or equal to the number of functions that the mini-VDD intends to hook, then the mini-VDD can proceed to hook functions safely. Thus, the value returned in ECX can be used as a version check against using a Main VDD that is older than the MINIVDD.INC that the mini-VDD was compiled with. Refer to any of the example mini-VDD's to see how a mini-VDD installs its hook functions.


VDD_Get_Special_VM_IDs

Call With

Nothing.

Return Values

EDI contains the VM handle of the Blue Screen Message Mode pseudo-VM. ESI contains the VM handle of the Forced Planar Mode pseudo-VM.

Remarks

This function can only be called up to and including the Init_Complete phase of VxD initialization. It will cause a fatal page fault if called after Init_Complete.

The VDD has two special "pseudo-VM's" that are used by the VDD to set special states. The first is used to contain the states for the blue-screen message mode VM which is displayed when Windows encounters a serious problem. This blue-screen message mode is displayed in VGA mode 3 in non-East Asian versions of Windows 95 and in Mode 12h in East Asian DBCS versions of Windows 95. The second is a VM containing the 4 plane MemC state (such as that in Mode 12h). These "pseudo VM" handles are sometimes passed to the mini-VDD during RESTORE_REGISTERS calls. The mini-VDD should retrieve these special VM handles at MiniVDD_Dynamic_Init time and then compare against them during the RESTORE_REGISTERS calls. The VIDEO7.VXD sample mini-VDD contains an example of how these pseudo-VM's have their register states saved at Init_Complete time and how RESTORE_REGISTERS uses the pseudo VM handles to properly restore the state of the blue screen message mode.


VDD_Get_VM_Info

Call With

Nothing.

Return Values

EDI contains the VM handle of the CRTC owner. ESI contains the VM handle of the MemC owner.

Remarks

This is an information service that is used by mini-VDDs to decide whether to virtualize or pass through I/O when virtualizing extended registers. See the S3 example mini-VDD routine mini-VDD VirtualCRTCOut for an example of how VDD_Get_VM_Info is used during virtualization.


VDD_Register_Extra_Screen_Selector

Call With

EAX contains the Selector Number to register.

Return Values

All registers except EBX are destroyed. CY returned if the Main VDD's extra selector array is filled that is, if more than 8 different selectors have been registered.

Remarks

VDD_Register_Extra_Screen_Selector allows the display driver to register extra selectors that it might use to draw onto the display hardware. Some modern display cards use memory mapped registers that are accessed using a different screen selector than the one provided by VFLATD. Other display cards do not use VFLATD to obtain a selector; they either use DPMI or have the mini-VDD obtain a selector for them. In this case, they access the display memory as a flat, linear frame buffer whose physical address may be mapped in by the hardware at very high addresses such as above 2 gigabytes. See the ATI mini-VDD's routine MiniVDD_RegisterDisplayDriver for an example of how to do this.

A display driver may also use the screen selectors provided by the Windows 95 Kernel. These selectors are often called KernelsScreenSelector or __A000H in display driver code. Whenever the display driver uses a screen selector other than the one that is provided by VFLATD, it must be registered with the Main VDD so that the Main VDD knows when to switch the MemC state back to that required by the Windows VM when virtualizing VGA 4 plane graphics in a window. FRAMEBUF.DRV is an example of a display driver that uses KernelsScreenSelector

This function is called by the mini-VDD on behalf of the display driver. Typically, the sequence of events is as follows: At physical enable time, the display driver calls VDD_REGISTER_DISPLAY_DRIVER_INFO which in turn calls the mini-VDD function REGISTER_DISPLAY_DRIVER. The mini-VDD may allocate an LDT selector on behalf of the display driver or it may pass an LDT selector (such as KernelsScreenSelector) to the VDD_Register_Extra_Screen_Selector service. At the correct time, the Main VDD uses this registered information to correctly set the MemC state and does not need the mini-VDD or display driver to intervene.

The selector passed in EAX (actually in AX, the top word of EAX should be zero) must be a GDT or LDT selector which is used only by the Windows VM. It should only be registered once per Windows session (in other words, if the display driver calls the mini-VDD function REGISTER_DISPLAY_DRIVER whenever the display driver runs through Enable, it should try to not register the same selector twice). Up to 8 selectors can be registered using this function.

For background information on how the VDD handles virtualization of VGA planar modes in the background or in a window, see the service VDD_Register_Virtual_Port. See the ATI mini-VDD for an example of how to allocate an LDT selector and call VDD_Register_Extra_Screen_Selector to register it with the Main VDD.


VDD_Register_Virtual_Port

Call With

CL contains the equate WORD_LENGTHED or BYTE_LENGTHED depending on how wide the port is. See the following for instructions on registering doubleword length ports. EDX contains the port number to register

Return Values

Uses EDX and ESI. No data is returned to the caller.

Remarks

This function can only be called up to and including the Init_Complete phase of VxD initialization. It will cause a fatal page fault if called after Init_Complete.

Many modern display cards have hardware BLTers in them that are accessed via I/O ports that are not just extensions to VGA ports. For example, the S3 hardware uses many I/O ports such as BEE8h, 9AE8h etc. to draw onto the display hardware. Many display operations (such as drawing a rectangle) are accomplished on the hardware by the display driver setting values into these I/O ports. The shared memory aperture (such as that at A000:0) is never touched.

When virtualizing a VGA 4 plane graphics application in a window, the VDD changes the MemC state (that is, how the CPU sees the card's Video RAM) from the packed pixel state that the card is running in to a 4 plane state. It then uses off-screen memory as a "pseudo 4 plane VGA" and draws into it in order to take advantage of the VGA's rudimentary BLT engine (such as the latches, SetReset registers, and write modes). The VDD then maps some of this off-screen memory to the VM's A000:0h address. Applications may write to address A000:0h but it is actually writing to a piece of off-screen memory that the VDD has virtually mapped. As a result of this process, the VDD must determine whether to set the MemC state to the packed pixel state that Windows is running in, or the "pseudo planar" state that the VGA 4 plane application is running in.

If the display driver and the VGA 4 plane application were both using the memory aperture at A000:0h as their only method of talking to the video hardware, the VDD's determination of which MemC state to set into the hardware would be easy. If this was the case, when the VGA 4 plane application first touched memory at A000:0h, it would cause a page fault that the VDD would intercept. The Main VDD would then set the MemC state to the "pseudo 4 plane" mode and unmap all of the pages that the Windows VM owned at A000:0h. Then, when the Windows display driver touched memory at A000:0h, it would cause a page fault to the VDD. The VDD would then set the MemC state back to the packed pixel state and unmap all of the 4 plane VGA application pages. This would continue and each VM (the Windows VM where the display driver was running and the MS-DOS VM where the 4 plane VGA application was running) would alternate MemC states and each VM would talk to the video hardware in the correct way.

However, modern display hardware may draw within the Windows VM by setting I/O ports to the correct values and using a hardware BLTer, and never touch address A000:0h. So, the VDD needs an alternate method to know when to switch back to the Windows MemC state. To accomplish this task, the VDD traps the BLTer registers that the display driver may talk to in order to draw to the screen. When the VDD sets the VGA 4 plane MemC state, it also notifies the mini-VDD to enable trapping on the BLTer registers which have been registered via VDD_Register_Virtual_Port. Subsequently, when the Windows display driver next touches one of the ports, the VDD automatically sets the MemC state back to Windows.

Any non-VGA port that your display driver touches during its drawing routines should be registered using VDD_Register_Virtual_Port. If your display card's BLTer registers are extensions to the standard VGA registers, they will be taken care of without calling this service.

So, a mini-VDD must register each port, telling the Main VDD whether it is word lengthed or byte lengthed (by passing the equated flag from MINIVDD.INC in CL) and then hook the ENABLE_TRAPS and DISABLE_TRAPS services to enable and disable trapping for each port that has been registered using VDD_Register_Virtual_Port. Within your ENABLE_TRAPS and DISABLE_TRAPS routines, you must call Enable_Global_Trapping or Disable_Global_Trapping once for each port. If you have a word lengthed port (such as BEE8h), you must call Enable_Global_Trapping for both BEE8h and BEE9h.

There is no support for doubleword lengthed ports. Therefore, if you have a 32 bit wide port, you should call VDD_Register_Virtual_Port twice, once for each half of the doubleword lengthed port registering each half as WORD_LENGTHED.

See the S3 or ATI sample mini-VDD 's for examples of how this BLTer port trapping works .


VDD_Set_Sleep_Flag_Addr

Call With

EAX contains the Ring 0 linear address of the display driver's "InSrcBLT flag".

Return Values

No registers are destroyed. Nothing is returned.

Remarks

Many hardware BLTers cannot be interrupted for physical hardware changes while their BLT engine is waiting for data to be fed to it from the host CPU (for example, during a Memory-To-Screen bitblt operation). Because the VDD operates pre-emptively, it may be asked to change the hardware state of the card while the display driver is feeding data to the hardware BLTer. If this is the case on your display hardware, your mini-VDD must register the address of a byte lengthed flag which is referred to as InSrcBLT.

InSrcBLT must be in your display driver's fixed data segment. It should be set to 0 when not performing a memory-to-screen BLT, but should be set to FFh right before the hardware BLTer will become busy waiting for data from the host. It should then be reset to 0 after the hardware BLTer is done receiving data and is again "not busy". Your display driver should pass the address of this flag to the VDD_REGISTER_DISPLAY_DRIVER_INFO function when it first enables. Then the mini-VDD should hook REGISTER_DISPLAY_DRIVER and get the address of InSrcBLT. It should convert this address from a ring 3 Selector:Offset address to a ring 0 linear address using the VMM service Map_Flat. It should then call VDD_Set_Sleep_Flag_Addr with the linear address in EAX. The Main VDD will then check this flag and will disallow other VM's from running when the InSrcBLT flag indicates that the display hardware is busy. In this way, hardware lockups due to the BLTer being unexpectedly interrupted are avoided.


VDD_Takeover_VGA_Port

Call With

EDX contains the VGA port number to takeover (in the range 3C0h through 3DFh). ECX contains the address of the routine in the mini-VDD that will be the handler for this I/O port.

Return Values

ECX is returned with the address of the old port handling routine. EDX and ECX are destroyed by this call. The carry flag is set on failure.

Remarks

The Main VDD at Device_Init time takes over accesses to all of the standard VGA ports from port 3C0h up to and including port 3DFh. Some of these ports are not really used by the standard VGA or may be used in different ways by the mini-VDD. Sometimes, the mini-VDD may need to handle all aspects of virtualizing these ports instead of letting the Main VDD do any handling. In this case, the mini-VDD can call this service in order to have all virtualized I/O for the port vectored to the mini-VDD's handler. The Main VDD will not do any virtualization or interact in any way when the port is virtualized. The Main VDD will however, decide when to enable and disable trapping on the VGA port in question. The mini-VDD's handler is passed the usual port virtualization information in the registers (that is, EAX contains the value, EBX contains the VM Handle, ECX contains the I/O type, EDX contains the port number).

If you need some virtualization assistance from the Main VDD, do not use this function. For example, if the mini-VDD needs to virtualize some extensions to the CRTC ports and wants to let the Main VDD handle accesses to the standard VGA indices, it would hook VIRTUALIZE_CRTC_IN and/or VIRTUALIZE_CRTC_OUT which would let it get first crack at virtualizing the CRTC registers. Only use this function if the mini-VDD does not need any virtualization assistance from the Main VDD.

The mini-VDD can also chain back to the Main VDD's handler for a VGA port. Using the S3 sample mini-VDD as an example, suppose you need to collect states for a VGA port that there's no mini-VDD virtualization hook for (in the case of S3, we need to virtualize the Miscellaneous Output Port 3CCH).You can call this service at Dynamic_Init time, but save the value returned in ECX. Then, your virtualization routine (in the S3 example, see MiniVDD_VirtualMiscOutput for details) can collect all of the necessary states that it needs, or modify the default virtualization, and then jump back to the old handler whose address was saved. This provides maximum flexibility in handling VGA ports.


Supported Windows 3.x Services

The following topics document the supported Windows 3.x services.


VDD_Check_Update_Soon

The VDD_Check_Update_Soon service forces the VDD to check to see if a page of video memory has been changed.

Parameters

EBX: Contains the VM handle of the VM to check updates for.

Return Values

Nothing returned, Nothing used.

Remarks

When running a windowed VM, the VDD is responsible for detecting when an application has updated the screen. Every few timer ticks, the VDD checks to see if a page of video memory has been changed. However, a VxD such as the Virtual Keyboard Device (VKD) may want the VDD to immediately and synchronously check for screen updates when the VKD detects a keyboard event. This service provides a way to force the VDD to make this check immediately.


VDD_Get_GrabRtn

    include minivdd.inc
    VxDCall VDD_Get_GrabRtn

The VDD_Get_GrabRtn service returns address of video grab routine. The grab routine is called by the virtual shell device when the appropriate hot key is pressed by the user. It makes a copy of the visible screen and controller state of the current virtual machine. The copy is accessible using the VDD_Get_GrbState and VDD_Get_GrbMem services.

Parameters

This service has no parameters.

Return Values

The ESI register contains the address of the grab routine.

Uses

Flags, ESI


VDD_Get_ModTime

    include minivdd.inc
    VxDCall VDD_Get_ModTime

The VDD_Get_ModTime service specifies whether any video activity has occurred. The virtual poll device uses it to determine if the virtual machine is idle.

Parameters

EBX Specifies the virtual machine handle.

Return Values

The EAX register contains the system time at last video modification.

Uses

Flags, EAX


VDD_Get_Version

    include minivdd.inc
    VxDCall VDD_Get_Version

The VDD_Get_Version service returns the VDD version number and device identifier.

Parameters

This service has no parameters.

Return Values

The AH register contains the major version number.

The AL register contains the minor version number.

The ESI register contains the address of the 8-byte identifier string for the VDD.

Uses

Flags, AX, ESI


VDD_Hide_Cursor

    include minivdd.inc
    VxDCall VDD_Hide_Cursor

The VDD_Hide_Cursor service sets or clears the hide-cursor flag. The virtual mouse device uses this service to turn on and off the hardware cursor such as when the virtual machine is windowed.

Parameters

EAX | Specifies whether the cursor should be hidden (nonzero) or displayed (zero).
EBX | Specifies a pointer to the control block.

Return Values

This service has no return value.

Uses

Flags


VDD_Msg_BakColor

    include minivdd.inc
    VxDCall VDD_Msg_BakColor

The VDD_Msg_BakColor service sets up the background attribute for messages displayed when in message mode.

Parameters

EAX | Specifies the color. For EGA/VGA driver, this parameter is a text mode attribute.
EBX | Specifies the virtual machine handle.

Return Values

This service has no return value.

Remarks

A virtual device that uses this service must issue a Begin_Message_Mode control message before calling this service.

Uses

Flags


VDD_Msg_ClrScrn

    include minivdd.inc
    VxDCall VDD_Msg_ClrScrn

The VDD_Msg_ClrScrn service initializes the screen for messages displayed when in message mode. If the focus virtual machine is the current virtual machine, this service clears the screen immediately. Otherwise, it initializes the screen when the focus changes.

The virtual shell device uses this service.

Parameters

EBX | Specifies the virtual machine handle.
EAX | Specifies the background attribute.

Return Values

The EAX register contains the width in columns.

The EDX register contains the height in rows.

Remarks

A virtual device that uses this service must issue a Begin_Message_Mode control message before calling this service.

Uses

Flags, EAX, EDX


VDD_Msg_ForColor

    include minivdd.inc
    VxDCall VDD_Msg_ForColor

The VDD_Msg_ForColor service sets the foreground attribute for messages displayed when in message mode.

Parameters

EAX | Specifies the color. For EGA/VGA drivers, this parameter is a text mode attribute.
EBX | Specifies the virtual machine handle.

Return Values

This service has no return value.

Remarks

A virtual device that uses this service must issue a Begin_Message_Mode control message before calling this service.

Uses

Flags


VDD_Msg_SetCursPos

    include minivdd.inc
    VxDCall VDD_Msg_SetCursPos

The VDD_Msg_SetCursPos service sets the cursor position for messages displayed when in message mode.

Parameters

EAX | Specifies the row position.
EDX | Specifies the column position.
EBX | Specifies the virtual machine handle.

Return Values

This service has no return value.

Remarks

A virtual device that uses this service must issue a Begin_Message_Mode control message before calling this service.

Uses

Flags


VDD_Msg_TextOut

    include minivdd.inc
    VxDCall VDD_Msg_TextOut

The VDD_Msg_TextOut service writes the specified text to the screen using the foreground and background colors specified by the VDD_Msg_BakColor and VDD_Msg_ForColor services.

Parameters

ESI | Specifies the address of the string to display.
ECX | Specifies the length in bytes of the string.
EAX | Specifies the row position for the start of the displayed string.
EDX | Specifies the column position for the start of the displayed string.
EBX | Specifies the virtual machine handle

Return Values

This service has no return value.

Remarks

A virtual device that uses this service must issue a Begin_Message_Mode control message before calling this service.

Uses

Flags


VDD_PIF_State

    include minivdd.inc
    VxDCall VDD_PIF_State

The VDD_PIF_State service informs the VDD about PIF bits for virtual machine just created.

Parameters

EBX | Specifies the virtual machine handle.
AX | Specifies the PIF bits.

Return Values

This service has no return value.

Uses

Flags


VDD_Query_Access

    include minivdd.inc
    VxDCall VDD_Query_Access

The VDD_Query_Access service specifies whether video memory can be accessed. Virtual devices that call software in the virtual machine use this service to determine whether a video display error will occur if the software attempts to access video memory.

Parameters

EBX Specifies the address of the control block.

Return Values

The carry flag is clear if a virtual device can access video memory.

Remarks

The virtual device should call this service just before returning to the virtual machine such as while processing a virtual machine event. If the video memory cannot be accessed, the virtual device should avoid calling software that may attempt access even if not calling the software causes another error, such as leaving the mouse cursor on when the virtual machine runs in a window.

Uses

Flags


VDD_Set_HCurTrk

    include minivdd.inc
    VxDCall VDD_Set_HCurTrk

The VDD_Set_HCurTrk service sets the flag passed to VMDOSAPP indicating that VMDOSAPP should maintain cursor position within display window for this application. The keyboard driver calls this service when a keyboard interrupt is simulated into a virtual machine.

Parameters

EBX Specifies the virtual machine handle.

Return Values

This service has no return value.

Uses

Flags


VDD_Set_VMType

    include minivdd.inc
    VxDCall VDD_Set_VMType

The VDD_Set_VMType service informs the VDD of a virtual machine's type. The system calls this service prior to running the virtual machine and each time any of the virtual machine parameters are modified.

Parameters

EAX | Specifies the state flag. This parameter is nonzero if the virtual machine is running in a window.
EBX | Specifies the virtual machine handle. This handle can be used to examine the virtual machine status flags such as the exclusive and background flags.

Return Values

This service has no return value.

Remarks

For a system critical Set_Focus this service may not be called before the Set_Focus. In that case, the VDD is responsible for doing an implied call to the VDD_Set_VMType service.

Uses

Flags


Virtual Flat-Frame Buffer Device Reference

The virtual flat-frame buffer device (VFLATD) helps manage the video frame buffer for a display driver. VFLATD virtualizes the buffer for display adapters that use bank-switching techniques to access their video memory by mapping it into a smaller block of memory addresses.

See Also

VflatD_Query, VflatD_Create_Virtual_Frame_Buffer


Registration

A display driver registers itself with VFLATD by first calling the VflatD_Query function to verify that the correct version of VFLATD has been loaded, then calling the VflatD_Create_Virtual_Frame_Buffer function to register itself and obtain a selector identifying the logical frame buffer.

A display adapter must also specify a bank-switch procedure when it calls the VflatD_Create_Virtual_Frame_Buffer function. Thereafter, whenever a page fault occurs during a drawing operation, VFLATD calls the bank-switch procedure, directing it to map a block of video data into the physical frame buffer. The procedure must be written using 32-bit code and must be a maximum of 100 bytes in length. When the procedure is called, EAX identifies the new bank to be swapped into the physical frame buffer. The procedure must save all registers except EAX and EDX and must not return a value.

This section is a reference to the virtual flat-frame buffer device.


VflatD_Query

include vflatd.inc

mov   dx, VflatD_Query          ; Function number
call  VFlatDApiProcAdr
jz    errorhandler
mov   VerNum, eax
mov   FrameBufSelector, ebx
mov   FrameBufSize, ecx
mov   FrameBufBase, edx

Retrieves the VFLATD version number and other information. Uses Flags.

Returns the following information and clears the carry flag if successful; otherwise, sets the carry flag.

EAX | VFLATD version
EBX | GDT selector to the frame buffer
ECX | Size of frame buffer
EDX | Linear base of frame buffer. (if linear mode)


VflatD_Create_Virtual_Frame_Buffer

include vflatd.inc

mov    dl, VflatD_Create_Virtual_Frame_Buffer  ; Function number
mov    dh, Flags                        ; Must be zero
mov    eax, FrameBufSize                ; Size of frame buffer in bytes
mov    ebx, BankSize                    ; Size of bank, in bytes
mov    esi, BankLocation                ; Location of bank
push   ds
pop    es
lea    di, BankSwitchProc               ; Bank switch code
movzx  edi, di
mov    cx, BankSwitchProcLength         ; Length of bank switch code
call   VFlatDApiProcAdr
jc     errorhandler
mov    VideoSelector, ax
mov    VideoAddress, edx

Registers a display driver's bank-switch function and retrieves a selector for a logical frame buffer. Uses Flags.

Returns a selector for the logical frame buffer in AX, returns a linear address for that frame buffer in EDX, and clears the carry flag if successful; otherwise, sets the carry flag.

Flags
Options flags. Currently, no flags are defined; this parameter must be zero.
FrameBufSize
Size of frame buffer, in bytes.
BankSize
Size of bank, in bytes.
BankLocation
Location of bank, for example, A0000h.
BankSwitchProc
Address of display driver's bank switch procedure.
BankSwitchProcLength
Length of display driver's bank-switch procedure.

The bank-switch procedure must be written using 32-bit code and must be a maximum of 100 bytes in length. When the procedure is called, EAX will identify the new bank to be swapped into the physical frame buffer. The procedure must save all registers except EAX, EDX, and Flags, and it must not have a ret instruction (since the code is copied inline).


VflatD_Create_Physical_Frame_Buffer

include vflatd.inc

mov   dl, VflatD_Create_Physical_Frame_Buffer  ; Function number
mov   dh, Flags                         ; Must be zero
mov   eax, FrameBufBase                 ; Physical base of frame buffer
mov   ecx, FrameBufSize                 ; Size of frame buffer, in bytes
call  VFlatDApiProcAdr
jc    errorhandler
mov   VideoSelector, ax
mov    VideoAddress, edx

Retrieves a GDT selector to a flat video buffer. Uses Flags.

Returns a selector for the logical frame buffer in AX, returns a linear address for that frame buffer in EDX, and clears the carry flag if successful; otherwise, sets the carry flag.

Flags
Options flags. Currently, no flags are defined; this parameter must be zero.
FrameBufBase
Physical base of frame buffer. The physical base is the address of the frame buffer in physical memory.
FrameBufSize
Size of frame buffer, in bytes.


VflatD_Get_Video_Base

This function is obsolete and has been replaced with the function VflatD_Create_Virtual_Frame_Buffer.


VflatD_Reset

include vflatd.inc

mov   dx, VflatD_Reset          ; Function number
call  VFlatDApiProcAdr
jc    errorhandler

Called when Video hardware has been changed by someone other than VFLATD. A display driver typically does not call this service. Uses EAX, and Flags.

Returns with the carry flag clear if successful; otherwise sets the carry flag.


VflatD_Begin_Linear_Access

include vflatd.inc

mov   dx, VflatD_Begin_Linear_Access  ; Function number
call  VFlatDApiProcAdr
jc    errorhandler
mov AccessCount, eax

Start linear access to the frame buffer. The frame buffer can be accessed via its linear address (by default the frame buffer must be accessed with the default selector). The frame buffer will remain in linear access mode until VflatD_End_Linear_Access is called. This call can be nested.

Returns the access count in EAX and clears the carry flag if successful.

The access count is incremented each time VflatD_Begin_Linear_Access is called, and is decremented with each call to VflatD_End_Linear_Access. Linear access mode is turned off when the access count is zero.

See Also

VflatD_End_Linear_Access


VflatD_End_Linear_Access

include vflatd.inc

mov   dx, VflatD_End_Linear_Access    ; Function number
call  VFlatDApiProcAdr
jc    errorhandler
mov AccessCount, eax

Stops linear access to the frame buffer. This function must be called the same number of times as VflatD_Begin_Linear_Access to leave linear mode.

Returns the access count in EAX and clears the carry flag is successful.

The access count is incremented each time VflatD_Begin_Linear_Access is called, and is decremented with each call to VflatD_End_Linear_Access. Linear access mode is turned off when the access count is zero.

See Also

VflatD_Begin_Linear_Access


Display Minidrivers Reference

This section provides detailed reference information for display-driver specific functions and structures. For more information about graphics-driver functions and structures see the section Graphics Device Interface.


ResetHiResMode

FAR PROC ResetHiResMode()

Used by the Windows 95 VDD to cause the video hardware to be reinitialized after returning to Windows from a full-screen MS-DOS session.

This function has no return value.

This function must be placed in a FIXED code segment, preferably the TEXT segment as defined in your display driver's .DEF file.

Drivers must register the address of ResetHiResMode with the Windows 95 VDD module by calling the VDD function VDD_DRIVER_REGISTER. Subsequently, every time that the user switches to a full-screen MS-DOS session, ResetHiResMode is called to do the work.

When ResetHiResMode is called, the DS register will not be pointing to the driver's data segment. The driver should be very careful to establish the segment registers when ResetHiResMode is called.

ResetHiResMode has several tasks:

It must set the display hardware back into the Windows running mode that it was in before running the full-screen MS-DOS session.

It must reinitialize and reenable the hardware cursor. Because the SetCursor function will not be called in response to returning from a full-screen VM, the display driver should save the complete lpCursorShape data structure in its data segment every time SetCursor is called. Then, if the user switches to full-screen and then returns, the cursor can be restored from this saved lpCursorShape data structure.

It must reinitialize the Windows palette. Again, the display driver should save a copy of the Windows palette (if running at 8 BPP) and track all of its updates in its data segment so that it can be restored during ResetHiResMode.

It must clear the BUSY bit in the driver's PDEVICE structure so that the drawing routines can access the hardware again.

It should call the VDD VDD_DRIVER_REGISTER function just as was done at the initial PhysicalEnable routine when Windows was first started. This will allow the VDD and mini-VDD to reinitialize themselves for running Windows again.

It should call the VDD VDD_SAVE_DRIVER_STATE function after the hardware has been completely re-setup for Windows. This allows the VDD to snapshot the hardware state and make sure it is accurate for running the Windows VM again.

See Also

VDD_DRIVER_REGISTER


ValidateMode

include valmode.inc
UINT WINAPI ValidateMode(DISPLAYINFO FAR *lpValMode);

Allows display drivers to accept or reject a mode selected by the user.

Returns any of the following values.

Value | Meaning
VALMODE_YES | Valid mode.
VALMODE_NO_WRONGDRV | Driver does not work on adapter.
VALMODE_NO_NOMEM | Not enough video memory for settings.
VALMODE_NO_NODAC | DAC can not handle selected colors.
VALMODE_NO_UNKNOWN | Unknown problem.

lpValMode
Address of a DISPLAYINFO structure that specifies the mode information such as resolution and color depth selected by the user.

All mode validation must be done in a manner that does not affect the screen.

ValidateMode can be called even if the driver is not the currently running display driver. If the user specifies a resolution/color depth that requires Windows to switch to a new driver, Windows will first call LoadLibrary on the new driver and call ValidateMode to verify that the new color depth/resolution is possible.

Display drivers must use the name "ValidateMode" in the .DEF file; since Windows dyna-links to this function by name, not by ordinal.

Ordinal 700 is the recommended value for this function.

See Also

DISPLAYINFO


Device Independent Bitmap Engine Reference

This section provides detailed reference information for the DIB engine functions and structures. Some functions have been modified to accept a PDEVICE. The names of these functions end in "Ext". The functions are separated into the following groups.

Group | Elements
Initialization | DIB_Enable, CreateDIBPDevice,
Object-management | DIB_EnumObj, DIB_EnumObjExt, DIB_EnumObjCallback, DIB_RealizeObjectExt
Lines, curves, and geometric-shapes | DIB_Output
Bitmaps | DIB_BitBlt, DIB_BitmapBits, DIB_DibBltExt, DIB_DibToDevice, DIB_Pixel, DIB_ScanLR, DIB_SelectBitmap, DIB_StretchBlt
Text | DIB_ExtTextOut, DIB_ExtTextOutExt, DIB_GetCharWidth
Color | DIB_ColorInfo, DIB_GetPaletteExt, DIB_GetPaletteTranslateExt, DIB_SetPaletteExt, DIB_SetPaletteTranslateExt, DIB_UpdateColorsExt
Escape | DIB_Control
Cursor | DIB_CheckCursorExt, DIB_Inquire, DIB_MoveCursorExt, DIB_SetCursorExt
Frame Buffer and Cursor Access | DIB_BeginAccess, DIB_EndAccess
Miscellaneous | DIB_CreateDIBitmap, DIB_DeviceBitmap, DIB_DeviceMode, DIB_Disable, DIB_EnumDFonts, DIB_SetAttribute, DIB_StrBlt

The following functions are exported but minidrivers should not call them.

DIB_DibBlt
DIB_GetPalette
DIB_GetPaletteTranslate
DIB_RealizeObject
DIB_SetPalette
DIB_SetPaletteTranslate
DIB_UpdateColors


Initialization Functions

Use the DIB_Enable function to enable the DIB engine and to set the dpCurves through dpStyleLen members of a GDIINFO structure.


CreateDIBPDevice

CreateDIBPDevice(LPBITMAPINFO lpInfo, LPPDEVICE lpDevice,
     VOID *lpBits, WORD wFlags);

Creates a PDEVICE structure for the DIB engine using the specified BITMAPINFO structure and DIB bits.

It returns the size in bytes of the bits buffer (based on the width, height, and bpp in the specified BITMAPINFO structure) if successful; otherwise returns zero.

lpInfo
Address of a BITMAPINFO structure that contains information about the DIB. The PDEVICE that is created contains a pointer to this block of memory in its deBitmapInfo field.
lpDevice
Address of buffer (allocated by the caller) to receive the PDEVICE structure. The size of the PDEVICE structure can be obtained from the dpDeviceSize field of the DIB engine's GDIINFO definition.
lpBits
Address of the DIB bits, which are stored as an array of bytes. If NULL, the function fills in the offset part of the deBits field and the minidriver must allocate a 0-based buffer and fill in the selector part of the deBits field.
wFlags
Value used to initialize the PDEVICE's deFlags field.

The function fails for DIB formats that the DIB engine does not support.

The deDriverUse field in the DIBENGINE structure is reserved for use by minidrivers. CreateDIBPDevice initializes this field to zero, but minidrivers can subsequently place any value in this field for their own use. The DIB engine does not use this field.

The DIB engine initializes the deBeginAccess and deEndAccess members of the PDEVICE structure to zero. The minidriver needs to initialize these fields after the call to CreateDIBPDevice.

The export ordinal for this function is 300.


DIB_Enable

WORD DIB_Enable (LPVOID lpDevInfo, WORD wAction, LPSTR lpDestDevType,
    LPSTR lpOutputFile, LPVOID lpData)

Enables the DIB engine and initializes the dpCurves through dpStyleLen members of a GDIINFO structure. The minidriver must call this function when initializing the members of the GDIINFO structure. This function must be called before CreateDIBPDevice.

It returns TRUE if successful, FALSE otherwise.

lpDevInfo
Address of a GDIINFO structure.
wAction
One of the following actions.
Value | Meaning
0x0001 | Initialize the dpCurves through dpStyleLen members of the GDIINFO structure pointed to by lpDevInfo.
0x8001 | Same as 0x0001. The high bit is set if an application has requested an information context.

lpDestDevType
Address of a string specifying the device name. This string only applies to device drivers that support more than one model of the same device. The parameter can be NULL if only one model is supported.
lpOutputFile
Address of a string specifying the name of the output port or file to receive output from the driver. The string must be a valid MS-DOS filename. If the lpOutputFile parameter is NULL, the output device is the system display.
lpData
Address of DEVMODE structure containing information the minidriver's Enable function uses to initialize the device. It can be NULL if no such information is needed.

The export ordinal for this function is 5.

Because the DIB engine support features in addition to those supported by the display minidriver, the DIB engine may set bits in the GDIINFO structure other than were set by the minidriver. In such cases, the display minidriver must leave those bits set.


Object Management Functions

Use the DIB engine's object-management functions to manage pens, brushes, fonts, and bitmaps.


DIB_EnumObj

WORD DIB_EnumObj(LPPDEVICE lpDestDev, WORD wStyle,
    FARPROC lpCallbackFunc, LPVOID lpClientData);

This function has been superseded by DIB_EnumObjExt.

The export ordinal for this function is 7.

See Also

DIB_EnumObjExt


DIB_EnumObjExt

WORD DIB_EnumObjExt(LPPDEVICE lpDestDev, WORD wStyle,
    FARPROC lpCallbackFunc, LPVOID lpClientData, LPPDEVICE lpDisplayDev)

Enumerates the pens and brushes available on the device. The minidriver calls the DIB_EnumObjExt function when GDI calls the minidriver's EnumObjects function. For each object having the given style, DIB_EnumObjExt calls the callback function with the logical information for that object. DIB_EnumObjExt continues to call the callback function until there are no more objects or the callback function returns zero.

It returns the last value returned by the callback function if the callback function succeeds. Otherwise, it returns 1.

lpDestDev
Address of a PDEVICE or PBITMAP structure specifying the destination device or bitmap.
wStyle
One of the following object types.
Value | Meaning
1 | Pen
2 | Brush

DIB_EnumObjExt enumerates all objects of the given type. If there are no objects of the given type, the function must return 1.

lpCallbackFunc
Address of the user-supplied callback function.
lpClientData
Address of the user-supplied data.
lpDisplayDev
Address of PDEVICE structure that specifies color data for the display surface.

Before calling the callback function, DIB_EnumObjExt must fill the LPEN or LBRUSH structure with the logical colors and other values that correspond to a given physical pen or brush.

The export ordinal for this function is 402

See Also

DIB_EnumObjCallback


DIB_EnumObjCallback

WORD DIB_EnumObjCallback(LPVOID lpLogObj, LPSTR lpClientData)

Callback function supplied by the minidriver that processes pens and brushes enumerated by DIB_EnumObjExt.

It returns zero to stop the enumeration; return non-zero to continue the enumeration.

lpLogObj
Address of a LPEN or LBRUSH structure, depending on the wStyle parameter of the DIB_EnumObjExt function.
lpClientData
Address of the user-supplied data passed to DIB_EnumObjExt.

See Also

DIB_EnumObjExt


DIB_RealizeObject

DWORD DIB_RealizeObject(LPPDEVICE lpDestDev, WORD wStyle,
    LPVOID lpInObj, LPVOID lpOutObj, LPTEXTXFORM lpTextXForm);

Minidrivers should not call DIB_RealizeObject. This function has been superseded by DIB_RealizeObjectExt.

The export ordinal for this function is 10.

See Also

DIB_RealizeObjectExt


DIB_RealizeObjectExt

WORD DIB_RealizeObjectExt(LPPDEVICE lpDestDev, WORD wStyle,
    LPVOID lpInObj, LPVOID lpOutObj, LPTEXTXFORM lpTextXForm,
    LPPDEVICE lpDisplayDev);

Creates or deletes a physical object. The function creates a physical object by filling a structure provided by the minidriver with device-specific data that corresponds to the attributes of a given logical pen, brush, bitmap, or font; it deletes the physical object by removing any memory or resources it allocated when creating the object.

If successful and if lpOutObj is NULL, returns the size in bytes of the physical object. If successful and if lpOutObj is not NULL, returns one of the following values.

Condition | Return Value
For solid brushes for a monochrome PDEVICE | 8001h
For solid brushes for a color PDEVICE | 8002h
For all other brush styles and objects | 8000h

If unsuccessful, returns zero.

lpDestDev
Address of a PDEVICE or PBITMAP structure specifying the device or bitmap to create the physical object for.
wStyle
A negative value to delete an object, or one of the following values.
Value | Meaning
OBJ_PEN | Realize a physical pen.
OBJ_BRUSH | Realize a physical brush.
OBJ_FONT | Realize a device font. If the device has no device fonts or cannot realize the requested font, the RealizeObject function returns zero.
OBJ_PBITMAP | Realize a device bitmap. GDI passes this value only if the RC_DEVBITS value is set in the dpRaster member of the driver's GDIINFO structure.

lpInObj
Address of a LPEN, LBRUSH, LFONT, or PBITMAP structure (depending on the wStyle parameter). The structure describes the logical attributes of the object to be realized.

If wStyle is negative, the lpInObj parameter points to the PPEN, PBRUSH, FONTINFO, or PBITMAP structure identifying the physical object to be deleted.

lpOutObj
Address of a buffer to receive the realized object, or points to the physical object to delete, depending on the value of the wStyle parameter.

If wStyle is positive, the lpOutObj parameter points to a buffer. The function fills the buffer with device-specific data that defines a physical object corresponding to the logical object pointed to by the lpInBuf parameter. If lpOutObj is NULL, the function returns the size (in bytes) of the physical object.

If wStyle is negative, lpOutBuf points to the physical object to delete. Although GDI frees the memory pointed to by lpOutBuf when the function returns, the RealizeObject function must free any other memory or resources associated with the physical object.

lpTextXForm
Address of a TEXTXFORM structure or specifies a POINT structure, depending on the wStyle parameter.
lpDisplayDev
Address of PDEVICE structure that specifies color data for the display surface.

If wStyle is OBJ_BRUSH, the lpTextXForm parameter is a POINT structure containing the x- and y-coordinates (relative to an 8-bit boundary) on which to align the start of the brush's pattern.

If wStyle is OBJ_FONT, lpTextXForm points to a TEXTXFORM structure containing information about the appearance of a realized font. Both the realized font and the contents of the TEXTXFORM structure are later passed to the ExtTextOut function, allowing more capable devices to make changes to the standard font.

The export ordinal for this function is 400.


Lines, Curves, and Geometric Shapes

Use the following functions to draw lines, curves, polygons, ellipses, and other geometric shapes.


DIB_Output

WORD DIB_Output(LPPDEVICE lpDestDev, WORD wStyle, WORD wCount,
    LPPOINT lpPoints, LPPPEN lpPPen, LPPBRUSH lpPBrush,
    LPDRAWMODE lpDrawMode, LPRECT lpClipRect)

Draws the specified lines and figures.

Returns any of the following values.

Value | Meaning
1 | Function was successful.
0 | Unrecoverable error occurred.
-1 | Function does not support specified style.

lpDestDev
Address of a PDEVICE or PBITMAP structure specifying the destination device or bitmap.
wStyle
One of the following values specifying the type of output.
Value | Meaning
OS_BEGINNSCAN | Begins a series of scan lines.
OS_ENDNSCAN | Ends a series of scan lines.
OS_POLYLINE | Draws a set of connected line segments. Although the line segments may create a closed figure, the function never fills the figure.
OS_SCANLINES | Draws a set of horizontal line segments at a specified vertical position. GDI calls this function when simulating output (such as filling a polygon).

wCount
The number of POINT structures in the array pointed to by the lpPoints parameter, or zero, depending on the wStyle parameter.
Value | Meaning
OS_BEGINNSCAN | Must be zero.
OS_ENDNSCAN | Must be zero.
OS_POLYLINE | Number of POINT structures. This value must be at least 2.
OS_SCANLINES | Number of POINT structures.

lpPoints
Address of an array of POINT structures or NULL, depending on the wStyle parameter. The array, if present, has wCount elements.
Value | Meaning
OS_BEGINNSCAN | Must be NULL.
OS_ENDNSCAN | Must be NULL.
OS_POLYLINE | Array of POINT structures specifying the endpoints of the line segments.
OS_SCANLINES | Array of POINT structures containing the scan line coordinates. The y member in the first POINT structure specifies the y-coordinate to draw the scan lines. In each subsequent structure, the x member specifies the x-coordinate of a scan line's starting point and the y member specifies the x-coordinate of the ending point.

lpPPen
Address of a PPEN structure specifying a physical pen, or NULL if no lines or borders are to be drawn.
Value | Meaning
OS_BEGINNSCAN | Pen used to draw subsequent scan lines, or NULL for no pen.
OS_ENDNSCAN | Must be NULL.
OS_POLYLINE | Pen used to draw lines.
OS_SCANLINES | Pen used to draw scan lines.

lpPBrush
Address of a PBRUSH structure specifying a physical brush, or NULL if no interiors or scan lines are to be drawn.
Value | Meaning
OS_BEGINNSCAN | Brush used to draw subsequent scan lines, or NULL for no brush.
OS_ENDNSCAN | Must be NULL.
OS_POLYLINE | Must be NULL.
OS_SCANLINES | Brush used to draw scan lines.

lpDrawMode
Address of a DRAWMODE structure containing information to use when drawing, such as binary-raster operation, background mode, and foreground and background color.
Value | Meaning
OS_BEGINNSCAN | Contains information about subsequent scan lines.
OS_ENDNSCAN | Must be NULL.
OS_POLYLINE | Contains information about drawing lines.
OS_SCANLINES | Contains information about scan lines.

lpClipRect
Address of a RECT structure containing coordinates for the clipping rectangle or NULL, depending on the wStyle parameter. If the lpClipRect parameter is NULL, the clipping rectangle is the entire display surface.
Value | Meaning
OS_BEGINNSCAN | Must be NULL.
OS_ENDNSCAN | Must be NULL.
OS_POLYLINE | Clipping rectangle.
OS_SCANLINES | Clipping rectangle.

The export ordinal for this function is 8.


Bitmaps

Use the following DIB engine functions to manage bitmap operations for your minidriver.


DIB_BitBlt

BOOL DIB_BitBlt(LPPDEVICE lpDestDev, WORD wDestX, WORD wDestY,
    LPPDEVICE lpSrcDev, WORD wSrcX, WORD wSrcY, WORD wXext,  WORD wYext,
    long Rop3, LPBRUSH lpPBrush, LPDRAWMODE lpDrawMode)

Transfers bits from a rectangle on a source device to a rectangle having the same dimensions on a destination device. The transfer is controlled by a ternary raster operation value that specifies how corresponding bits from the source, destination, and pattern in a brush are combined to form the final bits in the destination.

Returns TRUE if successful, or FALSE otherwise.

lpDestDev
Address of PDEVICE or PBITMAP structure specifying the destination device or bitmap.
wDestX and wDestY
The x- and y-coordinates (in device units) of the origin of the rectangle on the destination device to receive the transferred bits.
lpSrcDev
Address of PDEVICE or PBITMAP structure specifying the source device or bitmap.
wSrcX and wSrcY
The x- and y-coordinates in device units of the origin (the upper-left corner) of the rectangle on the source device containing the bits to transfer.
wXext and wYext
The width and height in device units of the rectangles on both the source and destination devices.
Rop3
Specifies a ternary raster-operation value. This value determines how BitBlt combines corresponding pixels from the source, destination, and brush to produce the final pixels in the destination rectangle. The Rop3 parameter can be any one of 256 ternary raster-operation values. The following table lists the most common values.
Value | Meaning
BLACKNESS (0x00000042) | Set all destination bits to black.
DSTINVERT (0x00550009) | Copy the inverse of the destination bits: Destination = ~ Destination.
MERGECOPY (0x00C000CA) | Combine the source and brush bits using the bitwise AND operator: Destination = Source & Pattern.
MERGEPAINT (0x00BB0226) | Combine the destination and inverse of the source bits using the bitwise OR operator: Destination = (~ Source) | Destination.
NOTSRCCOPY (0x00330008) | Copy the inverse of the destination bits to the destination rectangle: Destination = ~ Destination.
NOTSRCERASE (0x001100A6) | Combine the inverse of the source and destination bits using the bitwise AND operator: Destination = (~ Source) & (~ Destination).
PATCOPY (0x00F00021) | Copy the brush bits to the destination rectangle: Destination = Pattern.
PATINVERT (0x005A0049) | Combine the pattern and destination bits using the bitwise exclusive OR operator: Destination = Pattern ^ Destination.
PATPAINT (0x00FB0A09) | Combine the destination, pattern, and the inverse of source bits using the bitwise OR operator: Destination = (~ Source) | Pattern | Destination.
SRCAND (0x008800C6) | Combine the source and destination bits using the bitwise AND operator: Destination = Source & Destination.
SRCCOPY (0x00CC0020) | Copy source bits to the destination rectangle: Destination = Source.
SRCERASE (0x00440328) | Combine the source and inverse of destination bits using the bitwise AND operator: Destination = Source & (~ Destination).
SRCINVERT (0x00660046) | Combine the source and destination bits using the bitwise exclusive OR operator: Destination = Source ^ Destination.
SRCPAINT (0x00EE0086) | Combine the source and destination bits using the bitwise OR operator: Destination = Source | Destination.
WHITENESS (0x00FF0062) | Set all bits to white.

lpPBrush
Address of a PBRUSH structure specifying a physical brush. BitBlt uses this brush only if the Rop3 parameter specifies a ternary raster operation that requires the brush to be combined with the source, destination, or both.
lpDrawMode
Address of a DRAWMODE structure specifying the color information BitBlt needs to determine patterned brush colors and to carry color conversions and transparent copy operations.

The export ordinal for this function is 1.


DIB_BitmapBits

BOOL DIB_BitmapBits(LPPDEVICE lpDevice, DWORD fFlags, DWORD dwCount,
    LPSTR lpBits)

Sets, retrieves, or copies bitmap data.

Returns the number of bits copied.

lpDevice
Address of a PDEVICE or PBITMAP structure specifying a device or memory bitmap.
fFlags
Flag specifying whether data is set, retrieved, or copied.
Value | Meaning
DBB_SET | Sets bitmap bits by copying data from the buffer pointed to by the lpBits parameter to the specified device.
DBB_SETWITHFILLER | Identical to DDB_SET unless the bitmap is larger than 64K bytes (as specified by the lpDevice member of the PBITMAP structure). If the bitmap is larger than 64K bytes, scanlines are never broken across segments. Instead, the last bytes of each segment are used for padding and should be ignored by the driver.
DBB_GET | Retrieves bitmap bits by copying data from the specified device to the buffer pointed to by lpBits.
DBB_COPY | Copies bitmap bits from the bitmap pointed to by lpBits to the specified device.

dwCount
The number of bits to copy.
lpBits
Address of a buffer or a bitmap, depending on the value of the fFlags parameter. If fFlags is DBB_SET or DBB_GET, this parameter points to a buffer that contains or receives the bits for the specified bitmap. If fFlags is DBB_COPY, this parameter points to a device bitmap.

The export ordinal for this function is 30.


DIB_DibBlt

void DIB_DibBlt(LPPDEVICE lpBitmap, WORD fGet, WORD iStart,
    WORD cScans, LPSTR lpDIBits, LPBITMAPINFO lpBitmapInfo,
    LPDRAWMODE lpDrawMode, LPINT lpTranslate)

Minidrivers should not call DIB_DibBlt. This function has been superseded by DIB_DibBltExt.

The export ordinal for this function is 19.

See Also

DIB_DibBltExt


DIB_DibBltExt

void DIB_DibBltExt(LPPDEVICE lpBitmap, WORD fGet, WORD iStart,
    WORD cScans, LPSTR lpDIBits, LPBITMAPINFO lpBitmapInfo,
    LPDRAWMODE lpDrawMode, LPINT lpTranslate, USHORT fPalettized)

Either copies a device-independent bitmap (DIB) to a device-dependent bitmap (DDB) or copies a DDB to a DIB. The fGet parameter specifies which operation to carry out.

Returns any of the following values.

Value | Meaning
Count of scan lines set or retrieved | Function was successful
0 | An error occurred
-1 | Bits cannot be set or retrieved

lpBitmap
Address of a PBITMAP structure specifying a device-dependent memory bitmap.
fGet
Flag specifying whether the function copies DIB bits to DDB bits or copies DDB bits to DIB bits. If this parameter is zero, the function copies the bits from lpDIBits into lpBitmap. If the parameter is 1, the function copies the bits from lpBitmap into lpDIBits.
iStart
The starting scan-line number.
cScans
The number of scan lines to set or retrieve.
lpDIBits
Address of a buffer that contains or receives the bitmap bits. If the fGet parameter is zero, the function copies data from the buffer into the bitmap; if fGet is 1, the function copies the bits to the buffer from the bitmap. If the lpDIBits parameter is NULL, the function fills the biSizeImage member in the BITMAPINFO structure pointed to by the lpBitmapInfo parameter, but does not copy bitmap bits.
lpBitmapInfo
Address of a BITMAPINFO structure specifying the dimensions and format of the device-independent bitmap. If the biPlanes member is not 1 or the biBitCount member is not 1, 4, 8, 16, 24 or 32, the function returns an error.
lpDrawMode
Address of a DRAWMODE structure specifying the text (foreground) and background colors to use if color conversion is required.
lpTranslate
Address of an array of color translation values for converting palette colors to actual device colors. This parameter is ignored by devices that do not use color palettes.
fPalettized
Flag indicating if the display driver is palettized or not. If this parameter is one, the display driver is palettized; if zero, the display driver is not.

The function compares the widths of the device-specific bitmap and the device-independent bitmap. If the widths are not equal, the function clips to the smaller of the two bitmaps.

If the RLE_FORMAT_4 or RLE_FORMAT_8 values are set in the biCompression member of the BITMAPINFO structure, the device-independent bitmap is in run-length-encoded (RLE) format. In this case, the function must encode each scan line as it copies the scan line data to the buffer pointed to by lpDIBits or the function must decode the data as it retrieves it from the buffer.

The export ordinal for this function is 401.


DIB_DibToDevice

WORD DIB_DibToDevice(LPPDEVICE lpDestDev, WORD X, WORD Y, WORD iScan,
    WORD cScans, LPRECT lpClipRect, LPDRAWMODE lpDrawMode,
    LPSTR lpDIBits, LPBITMAPINFO lpBitmapInfo, LPINT lpTranslate)

Copies device-independent bitmap data directly to the given device. The function converts the bitmap data to the appropriate device-specific format and copies the resulting bits to the device.

The number of scan lines copied if the function is successful, or zero otherwise.

lpDestDev
Address of a PDEVICE structure specifying the device to receive the device-independent bitmap.
X and Y
The x- and y-coordinates in device units to receive the top left corner of the device-independent bitmap.
iScan
The starting scan line.
cScans
The number of scan lines to copy.
lpClipRect
Address of a RECT structure specifying the clip rectangle.
lpDrawMode
Address of a DRAWMODE structure specifying the background mode and background color to use while copying the bitmap.
lpDIBits
Address of a buffer containing the device-independent bitmap bits.
lpBitmapInfo
Address of a BITMAPINFO structure specifying the dimensions and format of the device-independent bitmap. If the RLE_FORMAT_4 or RLE_FORMAT_8 values are set in the biCompression member, the bitmap is in run-length-encoded (RLE) format. In this case, the function must decode the data as it retrieves it from the buffer pointed to by the lpDIBits parameter.
lpTranslate
Address of an array of color-translation values for converting palette colors to actual device colors. This parameter is ignored by devices that do not use color palettes.

The export ordinal for this function is 21.


DIB_Pixel

DWORD DIB_Pixel(LPPDEVICE lpDestDev, WORD X, WORD Y, DWORD dwPhysColor,
    LPDRAWMODE lpDrawMode)

Sets or retrieves the color of the specified pixel. The function sets the given pixel to the color given by the dwPhysColor parameter if the lpDrawMode parameter specifies a binary raster operation. DIB_Pixel returns the physical color of the pixel if the lpDrawMode parameter is NULL.

Returns any of the following values.

Value | Meaning
Physical color | lpDrawMode was NULL and function succeeded
0x00000001L | lpDrawMode was not NULL and function succeeded
0x80000000L | Error

lpDestDev
Address of a PDEVICE or PBITMAP structure specifying the destination device or bitmap.
X and Y
The x- and y-coordinates of the pixel to retrieve or set.
dwPhysColor
The physical color value used to set the pixel.
lpDrawMode
Address of a DRAWMODE structure specifying the binary raster operation to use to combine the physical color with the existing pixel color. If lpDrawMode is NULL, Pixel retrieves and returns the current color of the specified pixel.

The export ordinal for this function is 9.


DIB_ScanLR

WORD ScanLR(LPPDEVICE lpDestDev, WORD X, WORD Y, PCOLOR dwPhysColor,
    WORD Style)

Scans the display surface horizontally from the given pixel, looking for the first pixel having the given color or a pixel that has any other color.

Returns any of the following values.

Value | Meaning
Number of scan-lines copied | Function succeeded.
0x0000 | An error occurred and no scan lines were copied.
0xFFFF | GDI must simulate the operation.

lpDestDev
Address of a PDEVICE or PBITMAP structure specifying the destination device or bitmap.
X and Y
The x- and y-coordinates of the starting pixel.
dwPhysColor
Specifies a physical color value.
Style
The action to take. This parameter can be a combination of the following values.
Value | Meaning
0x0001 | Scans for a pixel with color matching the dwPhysColor parameter. If this value is not given, the function scans for a pixel with color that does not match.
0x0002 | Scans to the left. If this value is not specified, the function scans to the right.

The export ordinal for this function is 12.


DIB_SelectBitmap

BOOL DIB_SelectBitmap(LPPDEVICE lpDevice, LPBITMAP lpPrevBitmap,
    LPBITMAP lpBitmap, DWORD fFlags)

Selects a bitmap into the specified device, replacing the previous bitmap.

Returns one if successful, or zero otherwise.

lpDevice
Address of a PDEVICE structure specifying the device for which the bitmap is to be selected.
lpPrevBitmap
Address of a PBITMAP structure specifying the previously selected device bitmap.
lpBitmap
Address of a PBITMAP structure specifying the device bitmap to select.
fFlags
The actions to take while selecting the bitmap. Support for this parameter is not currently implemented; the value must be zero.

The export ordinal for this function is 29.


DIB_StretchBlt

BOOL DIB_StretchBlt(LPPDEVICE lpDestDev, WORD wDestX, WORD wDestY,
    WORD wDestWidth, WORD wDestHeight, LPPDEVICE lpSrcDev,
    WORD wSrcX, WORD wSrcY, WORD wSrcWidth,  WORD wtSrcHeight,
    DWORD dwRop3, LPBRUSH lpPBrush, LPDRAWMODE lpDrawMode,
    LPRECT lpClipRect)

Transfers bits from a rectangle on a source device to a rectangle on a destination device, stretching or compressing the bitmap to fit the dimensions of the destination rectangle. The transfer is controlled by a ternary raster operation value that specifies how corresponding bits from the source, destination, and pattern in a brush are combined to form the final bits in the destination.

Returns TRUE if successful, or FALSE otherwise.

lpDestDev
Address of PDEVICE or PBITMAP structure specifying the destination device or bitmap.
wDestX and wDestY
The x- and y-coordinates (in device units) of the upper left corner of the rectangle on the destination device to receive the transferred bits.
wDestWidth and wDestHeight
The width and height of the destination rectangle.
lpSrcDev
Address of PDEVICE or PBITMAP structure specifying the source device or bitmap.
wSrcX and wSrcY
The x- and y-coordinates (in device units) of the upper left corner of the rectangle on the source device containing the bits to transfer.
wSrcWidth and wSrcHeight
The width and height (in device units) of the rectangles on the source device.
dwRop3
Specifies a ternary raster-operation value. This value determines how StretchBlt combines corresponding pixels from the source, destination, and brush to produce the final pixels in the destination rectangle. The Rop3 parameter can be any one of 256 ternary raster-operation values. See DIB_BitBlt for a table listing the most common values.
lpPBrush
Address of a PBRUSH structure specifying a physical brush. StretchBlt uses this brush only if the Rop3 parameter specifies a ternary raster operation that requires the brush to be combined with the source, destination, or both.
lpDrawMode
Address of a DRAWMODE structure specifying the color information StretchBlt needs to determine patterned brush colors and to carry color conversions and transparent copy operations.
lpClipRect
Address of a RECT structure specifying the dimensions of a rectangle in device units that is used for clipping.

The export ordinal for this function is 27.


DIB_StretchDIBits

BOOL DIB_StretchDIBits(LPPDEVICE lpDestDev, WORD fGet,
    WORD wDestX, WORD wDestY, WORD wDestWidth, WORD wDestHeight,
    WORD wSrcX, WORD wSrcY, WORD wSrcWidth, WORD wSrcHeight,
    VOID *lpBits, LPBITMAPINFO lpInfo, LPINT lpTranslate,
    DWORD dwRop3, LPBRUSH lpPBrush, LPDRAWMODE lpDrawMode,
    LPRECT lpClipRect)

Moves a source bitmap into a destination bitmap, stretching or compressing the source bitmap as necessary to fit the dimensions of the destination bitmap. The function either converts and copies a device-independent bitmap (DIB) to a given device or converts and copies a device-dependent bitmap (DDB) to a DIB. The fGet parameter specifies whether the source bitmap is a DIB or a DDB.

Returns TRUE if successful, or FALSE otherwise.

lpDestDev
Address of PDEVICE or PBITMAP structure specifying the destination device or bitmap.
fGet
Flag specifying whether to set or retrieve bitmap bits. If this parameter is zero, the function stretches or compresses the bitmap bits in the buffer pointed to by the lpBits parameter and copies them to the given device or bitmap. If this parameter is 1, the function retrieves bits from the device or bitmap.
wDestX
The x-coordinate, in device units, of the upper left corner of the destination rectangle.
wDestY
The y-coordinate, in device units, of the upper left corner of the destination rectangle.
wDestWidth
The width, in device units, of the destination rectangle.
wDestHeight
The height, in device units, of the destination rectangle.
wSrcX
The x-coordinate, in device units, of the source rectangle in the DIB.
wSrcY
The y-coordinate, in device units, of the source rectangle in the DIB.
wSrcWidth
The width, in device units, of the source rectangle in the DIB.
wSrcHeight
The height, in device units, of the source rectangle in the DIB.
lpBits
Address of the DIB bits, which are stored as an array of bytes.
lpInfo
Address of a BITMAPINFO structure that contains information about the DIB.
lpTranslate
Address of an array of color translation values for converting palette colors to actual device colors. This parameter is ignored by devices that do not use color palettes.
dwRop3
Specifies a ternary raster-operation value. This value determines how StretchBlt combines corresponding pixels from the source, destination, and brush to produce the final pixels in the destination rectangle. The Rop3 parameter can be any one of 256 ternary raster-operation values. See DIB_BitBlt for a table listing the most common values.
lpPBrush
Address of a PBRUSH structure specifying a physical brush. StretchBlt uses this brush only if the dwRop3 parameter specifies a ternary raster operation that requires the brush to be combined with the source, destination, or both.
lpDrawMode
Address of a DRAWMODE structure specifying the color information StretchBlt needs to determine patterned brush colors and to carry color conversions and transparent copy operations.
lpClipRect
Address of a RECT structure specifying the dimensions of a rectangle in device units that is used for clipping.

The export ordinal for this function is 28


Text Functions

Use the following text functions and structures to support text output in a minidriver.


DIB_ExtTextOut

DWORD DIB_ExtTextOut(LPPDEVICE lpDestDev, WORD wDestXOrg,
    WORD wDestYOrg, LPRECT lpClipRect, LPSZ lpString, int wCount,
    LPFONTINFO lpFontInfo, LPDRAWMODE lpDrawMode,
    LPTEXTXFORM lpTextXForm, LPSHORT lpCharWidths,
    LPRECT lpOpaqueRect, WORD wOptions);

Writes text strings by converting characters in a given string into raster, vector, or outline glyphs and copying the glyphs to the given device or bitmap. Depending on the value of its parameters, DIB_ExtTextOut also computes the x- and y-extents of the bounding rectangle of the displayed string, clips the text to fit a given clipping rectangle, fills a given rectangle with the specified background color before copying glyphs, and overrides the default spacing of the glyphs using values specified in an array of character widths.

Returns any of the following values.

Value | Meaning
x- and y-extents of string's bounding rectangle | wCount was negative and the function succeeded. The x-extent is in the low-order 16 bits and the y-extent is in the high-order 16 bits.
x-extent is 0x7FFF and y-extent is wDestXOrg | wCount was negative; the function failed because the x-extent was too large.
TRUE | wCount was zero and the specified rectangle was filled with the background color.
TRUE | wCount was positive and the text was output successfully.
0x80000000L | An error occurred; no output was generated.

lpDestDev
Address of a PDEVICE or PBITMAP structure specifying the device or bitmap to receive the text output.
wDestXOrg and wDestYOrg
The x- and y-coordinates (in device units) of the starting point for the string.
lpClipRect
Address of a RECT structure specifying the clipping rectangle.
lpString
Address of a null-terminated string specifying the characters to display.
wCount
Specifies which action to carry out. It can be one of the following values.
Value | Meaning
Negative | Compute the x- and y-extents of the smallest rectangle that completely encloses the displayed string, but do not generate output. In this case, the absolute value of wCount specifies the number of characters in the string. The function uses the current font, text justification, and other factors to compute the bounding rectangle, but does not apply the clipping rectangle. The function must update the BreakErr member of the DRAWMODE structure specified by the lpDrawMode parameter.
0 | Fill the rectangle specified by lpOpaqueRect but only if wOptions is ETO_OPAQUE. In this case, the function does not generate text output.
Positive | Draw the characters in the string. wCount specifies the number of characters to draw. The function uses the current font, text justification, escapement, rotation, and other factors to draw the characters, and it applies the clipping and opaque rectangles if specified. If the function modifies the BreakErr member of the DRAWMODE structure specified by the lpDrawMode parameter, it must restore the member to its original value.

lpFontInfo
Address of a FONTINFO structure specifying the physical font to use.
lpDrawMode
Address of a DRAWMODE structure specifying the current text color, background mode, background color, text justification, and character spacing.
lpTextXForm
Address of a TEXTXFORM structure specifying additional information about the appearance of the characters when drawn.
lpCharWidths
Address of an array of character widths. If this parameter is not NULL, each element in the array is the advance width (in device units) of the corresponding character in the string. The function uses these widths (instead of the default character widths) to compute the position of the next character in the string. There must be one advance width for each character in the string.
lpOpaqueRect
Address of a RECT structure specifying the opaquing rectangle. This parameter can be NULL.
wOptions
Action to carry out. It can be a combination of the following values.
ETO_OPAQUE (2) | Fills the rectangle specified by the lpOpaqueRect parameter (and clipped to the lpClipRect parameter) with the background color specified by the lpDrawMode parameter. The function fills the rectangle regardless of the whether lpDrawMode specifies opaque or transparent background mode.
ETO_CLIPPED (4) | Creates a new clipping rectangle by intersecting the rectangles specified by lpOpaqueRect and lpClipRect.
ETO_GLYPH_INDEX | For fonts in the format defined by the FONTINFO structure, if this flag is set, lpString points to a word array of glyph indexes into the character offset table. For fonts in the format defined by the FONTINFO structure, if this flag is clear, lpString points to a byte array and the index to the glyph in the character offset table must be computed by subtracting the index of the first character in the table. For fonts in the format defined by the NewFontSeg structure, if this flag is set, lpString points to a word array of glyph indexes into the character offset table. For fonts in the format defined by the NewFontSeg structure, if this flag is clear, lpString points to a byte array of glyph indexes into the character offset table.
ETO_BYTE_PACKED | Indicates the font is in the format defined by the NewFontSeg structure. The glyphs are byte-packed, meaning they are stored in rows where each row is padded out to a byte boundary.
ETO_BIT_PACKED | Indicates the font is in the format defined by the NewFontSeg structure. The glyphs are bit-packed, meaning they are stored in rows with no padding.
ETO_LEVEL_MODE | Indicates that the background mode specified in lpDrawMode ->bkMode is set to one of the blending levels used for anti-aliasing and is neither transparent or opaque.

The export ordinal for this function is 14.

See Also

DIB_ExtTextOutExt


DIB_ExtTextOutExt

DWORD DIB_ExtTextOutExt(LPPDEVICE lpDestDev, WORD wDestXOrg,
    WORD wDestYOrg, LPRECT lpClipRect, LPSZ lpString, int wCount,
    LPFONTINFO lpFontInfo, LPDRAWMODE lpDrawMode,
    LPTEXTXFORM lpTextXForm, LPSHORT lpCharWidths,
    LPRECT lpOpaqueRect, WORD wOptions, LPVOID *lpDrawTextBitmap,
    LPVOID *lpDrawRect);

This function is the same as DIB_ExtTextOut with the exception of the last two parameters. See DIB_ExtTextOut for details.

lpDrawTextBitmap
A minidriver-defined callback function. The DIB engine calls this function to draw the text string.
lpDrawRect
A minidriver-defined callback function. The DIB engine calls this function to draw the opaquing rectangle.

The export ordinal for this function is 403.

See Also

DIB_ExtTextOut, DrawTextBitmapProc, DrawOpaqueRectProc


DIB_GetCharWidth

WORD DIB_GetCharWidth(LPPDEVICE lpDestDev, LPWORD lpBuffer,
    WORD wFirstChar, WORD wLastChar, LPFONTINFO lpFontInfo,
    LPDRAWMODE lpDrawMode, LPTEXTXFORM lpFontTrans)

Computes the widths of each character within the given range and copies the widths to the buffer pointed to by the lpBuffer parameter.

Returns 1 if successful, or zero otherwise.

lpDestDev
Address of a PDEVICE or PBITMAP structure specifying the destination device or bitmap.
lpBuffer
Address of the buffer to receive the character widths. The buffer must be an array of 16-bit elements. There must be one element for each character in the range.
wFirstChar
The first character of the range.
wLastChar
The last character of the range.
lpFontInfo
Address of a FONTINFO structure that specifies the physical font from which to compute the character widths.
lpDrawMode
Address of a DRAWMODE structure that specifies the current text color, background mode, background color, text justification, and character spacing that may need to be applied to the font to compute a character width.
lpFontTrans
Address of a TEXTXFORM structure that specifies any font transformations, such as scaling and italicizing, that may need to be applied to the font to compute a character width.

The export ordinal for this function is 15.


DrawOpaqueRectProc

BOOL CALLBACK DrawOpaqueRectProc(LPPDEVICE lpDestDev,
    DWORD BgColor, WORD x, WORD y, WORD xExt, WORD yExt);

A minidriver-defined callback function specified in the lpDrawRect parameter to DIB_ExtTextOutExt. The DIB engine calls this function to draw the opaquing rectangle.

Returns TRUE if successful; otherwise FALSE.

lpDestDev
Address of a PDEVICE or PBITMAP structure specifying the destination device or bitmap.
BgColor
Background color to use for opaquing.
x
Left origin of rectangle to opaque.
y
Top origin of rectangle to opaque.
xExt
Width of rectangle to opaque.
yExt
Height of rectangle to opaque.

See Also

DIB_ExtTextOutExt


DrawTextBitmapProc

BOOL CALLBACK DrawTextBitmapProc(LPPDEVICE  lpDestDev,
    LPSTR lpMonoBuffer, WORD Flags, DWORD BgColor, DWORD FgColor,
    WORD x, WORD y, WORD WidthBytes, WORD Height, DWORD lpClipRect);

A minidriver-defined callback function specified in the lpDrawTextBitmap parameter to DIB_ExtTextOutExt. The DIB engine calls this function to draw the text string.

Returns TRUE if successful; otherwise FALSE.

lpDestDev
Address of a PDEVICE or PBITMAP structure specifying the destination device or bitmap.
lpMonoBuffer
Address of a buffer containing a monochrome bitmap of the text string to be drawn.
Flags
Specifies the background mode. This parameter can be either of the following modes.
Value | Description
OPAQUE | Background is filled with the current background color before the text, hatched brush, or pen is drawn.
TRANSPARENT | Background remains untouched.

BgColor
Background color to use for opaquing.
FgColor
Foreground color to use for the text output.
x
Left origin of string bitmap.
y
Top origin of string bitmap.
WidthBytes
Width of string bitmap in bytes.
Height
Height of string bitmap in bytes.
lpClipRect
Clipping rectangle.

See Also

DIB_ExtTextOutExt


DIB_StrBlt

DWORD DIB_StrBlt(LPPDEVICE lpDestDev, WORD wDestXOrg,
    WORD wDestYOrg, LPRECT lpClipRect, LPSZ lpString, int wCount,
    LPFONTINFO lpFontInfo, LPDRAWMODE lpDrawMode,
    LPTEXTXFORM lpTextXForm);

This function has been superseded by DIB_ExtTextOut.

The export ordinal for this function is 11.

See Also

DIB_ExtTextOut, DIB_ExtTextOutExt


Color and Color-Palette Functions

Use the following color and color-palette functions to support color operations in a minidriver.


DIB_ColorInfo

COLORREF DIB_ColorInfo(LPPDEVICE lpDestDev, DWORD dwColorin,
    LPPCOLOR lpPColor)

Converts a logical color (an RGB value) to a physical color (a physical color value) or converts a physical to a logical color, depending on the value of the lpPColor parameter.

Returns the logical color (RGB value) that most closely matches the physical color specified by dwColorin, or the color copied structure addressed by lpPColor, if successful.

lpDestDev
Address of a PDEVICE or PBITMAP structure specifying the destination device or bitmap.
dwColorin
Either a logical or physical color, depending on the value of lpPColor parameter.
lpPColor
Address of a PCOLOR structure or NULL. If lpPColor points to a PCOLOR structure, the function assumes that dwColorin specifies a logical color (an RGB value) and copies the physical color value that most closely matches the logical color to this structure. If lpPColor is NULL, the function assumes that dwColorin specifies a physical color and returns the logical color that matches the physical color.

The export ordinal for this function is 2.


DIB_GetPalette

VOID DIB_GetPalette(WORD nStartIndex, WORD nNumEntries,
    RGBQUAD lpPalette)

This function has been superseded by DIB_GetPaletteExt.

The export ordinal for this function is 23.

See Also

DIB_GetPaletteExt


DIB_GetPaletteExt

VOID DIB_GetPaletteExt(WORD nStartIndex, WORD nNumEntries,
    RGBQUAD lpPalette, LPPDEVICE lpDIBEngine);

Retrieves the logical colors (RGB values) for the given color indices. The function copies RGB structure color values to the buffer pointed to by the lpPalette parameter.

No return value.

nStartIndex
The color index of the first color to retrieve.
nNumEntries
The total number of entries to retrieve from the device's hardware palette.
lpPalette
Address of the buffer to receive the RGB colors.
lpDIBEngine
Address of PDEVICE structure that specifies color data for the display surface.

The export ordinal for this function is 406.


DIB_GetPaletteTranslate

void DIB_GetPaletteTranslate(LPWORD lpIndexes);

This function has been superseded by DIB_GetPaletteTranslateExt.

The export ordinal for this function is 25.

See Also

DIB_GetPaletteTranslateExt


DIB_GetPaletteTranslateExt

void DIB_GetPaletteTranslateExt(LPWORD lpIndexes,
    LPPDEVICE lpDIBEngine);

Copies the driver's translation table into the array pointed to by the lpIndexes parameter.

No return value.

lpIndexes
Address of the array to receive color indices. The number of indices in the array is specified by the dpPalColors member in the device's GDIINFO structure.
lpDIBEngine
Address of PDEVICE structure that specifies color data for the display surface.

The export ordinal for this function is 408.


DIB_SetPalette

VOID DIB_SetPalette(WORD nStartIndex, WORD nNumEntries,
    RGBQUAD lpPalette)

This function has been superseded by DIB_SetPaletteExt.

The export ordinal for this function is 22.

See Also

DIB_SetPaletteExt


DIB_SetPaletteExt

VOID DIB_SetPaletteExt(WORD nStartIndex, WORD nNumEntries,
    RGBQUAD lpPalette, LPPDEVICE lpDIBEngine)

Sets one or more entries in the hardware color palette to the specified colors.

No return value.

nStartIndex
A zero-based color-palette index. The function copies color values to the corresponding hardware-palette entry and to subsequent entries up to the number specified by the nNumEntries parameter.
nNumEntries
The number of entries to set in the hardware palette.
lpPalette
Address of an array of RGBQUAD structures specifying the colors to which to set the hardware-palette entries.
lpDIBEngine
Address of PDEVICE structure that specifies color data for the display surface.

The export ordinal for this function is 405.


DIB_SetPaletteTranslate

void DIB_SetPaletteTranslate(LPWORD lpIndexes)

This function has been superseded by DIB_SetPaletteTranslateExt.

The export ordinal for this function is 24.

See Also

DIB_SetPaletteTranslateExt


DIB_SetPaletteTranslateExt

void DIB_SetPaletteTranslateExt(LPWORD lpIndexes,
    LPPDEVICE lpDIBEngine);

Copies the translation table pointed to by the lpIndexes parameter and creates a corresponding inverse translation table. The driver uses the translation tables for mapping logical color indices to physical color indices.

No return value.

lpIndexes
Address of the array containing color indices. The number of indices in the array is specified by the dpPalColors member in the device's GDIINFO structure.
lpDIBEngine
Address of PDEVICE structure that specifies color data for the display surface.

When a non-identity palette translate is being set, this function sets the PALETTE_XLAT bit in the deFlags field of the DIBENGINE structure. This function clears the PALETTE_XLAT bit when an identity translate is set. Minidrivers and the DIB engine may use this bit to decide whether palette translation is needed or not. When applicable, this bit is set or cleared for palette translation for bitmaps, brushes, pens, foreground color, background color and text color.

The export ordinal for this function is 407.


DIB_UpdateColors

VOID DIB_UpdateColors(WORD wStartX, WORD wStart, WORD wExtX,
    WORD wExtY, LPWORD lpTranslate)

This function has been superseded by DIB_UpdateColorsExt.

The export ordinal for this function is 26.

See Also

DIB_UpdateColorsExt


DIB_UpdateColorsExt

VOID DIB_UpdateColorsExt(WORD wStartX, WORD wStart, WORD wExtX,
    WORD wExtY, LPWORD lpTranslate, LPPDEVICE lpDIBEngine);

Redraws all pixels in a region on the display surface using the colors specified in the given translation table. For each pixel in the region, the function reads the pixel's color index, translates the index, and writes the translated index back to the original position.

No return value.

wStartX and wStartY
The x- and y-coordinates of the upper-left corner of the region to update.
wExtX and wExtY
The width and height (in pixels) of the rectangular region to update.
lpTranslate
Address of an array of color indices.
lpDIBEngine
Address of PDEVICE structure that specifies color data for the display surface.

The export ordinal for this function is 404.


Cursor Functions

Use these functions to draw and manage the cursor.


DIB_SetCursorExt

void DIB_SetCursorExt(LPPDEVICE lpDevice, LPVOID lpCursorShape);

Sets the cursor shape.

No return value.

lpDevice
Address of the PDEVICE structure for the driver.
lpCursorShape
Address of the structure that contains information about the new shape of the cursor.

The ordinal values for this function is 102.


DIB_CheckCursorExt

void DIB_CheckCursorExt(LPPDEVICE lpDevice);

Checks if the cursor needs to be drawn or not and if so, draws it. This function is used primarily for software cursors where the driver has removed the cursor before doing a blt or some other drawing operation.

No return value.

lpDevice
Address of the PDEVICE structure for the driver.

The ordinal values for this function is 104.


DIB_MoveCursorExt

void DIB_MoveCursorExt(LPPDEVICE lpDevice, WORD absX, WORD absY);

Moves the cursor to the given point on the screen.

No return value.

lpDevice
Address of the PDEVICE structure for the driver.
absX
Absolute x-coordinate of the new cursor position.
absY
Absolute y-coordinate of the new cursor position.

The ordinal values for this function is 103.


DIB_Inquire

void DIB_Inquire(LPVOID lpCursorInfo);

Copies information about the cursor to the given structure.

No return value.

lpCursorInfo
Address of a structure that receives the cursor information.

The ordinal values for this function is 101.


Frame Buffer and Cursor Access Functions

Use the following functions to control access to the display adapter memory and to exclude the cursor.


DIB_BeginAccess

void DIB_BeginAccess(LPDEVICE lpDevice, WORD Left, WORD Top, WORD Right,
    WORD Bottom, WORD Flags);

Grants direct access to the frame buffer or excludes the cursor from the given rectangle.

lpDevice
Address of the PDEVICE structure.
Flags
Can be one of these values.
FB_ACCESS | Grant direct access to the framebuffer.
CURSOREXCLUDE | Exclude the cursor (if a software cursor) from the given rectangle.

The ordinal value for this function is 105.

See Also

DIB_EndAccess


DIB_EndAccess

void DIB_EndAccess(LPDEVICE lpDevice, WORD Flags);

Ends direct access to the frame buffer or removes the exclusion rectangle for the cursor.

lpDevice
Address of the PDEVICE structure.
Flags
Can be one of these values.
FB_ACCESS | Ends direct access to the frame buffer.
CURSOREXCLUDE | Releases the cursor exclusion rectangle previously set by DIB_BeginAccess.

The ordinal value for this function is 106.

See Also

DIB_BeginAccess


Miscellaneous Functions

The following functions are exported by the DIB engine but are stub functions that carry out no action and are provided to be consistent with the device driver interface (DDI).


DIB_CreateDIBitmap

WORD CreateDIBitmap(void)

This function is implemented as a stub function that carries out no action. It is provided to be consistent with the device driver interface.

Always returns zero.

The export ordinal for this function is 20.


DIB_DeviceBitmap

WORD DIB_DeviceBitmap(LPPDEVICE lpDestDev, WORD wCommand,
    LPBITMAP lpBitmap, LPSTR lpBits);

This function is implemented as a stub function that carries out no action. It is provided to be consistent with the device driver interface.

Always returns zero.

The export ordinal for this function is 16.


DIB_DeviceMode

DIB_DeviceMode(HWND hWnd, HINSTANCE hInst, LPVOID lpDeviceType
    LPVOID lpOutputFile);

This function is implemented as a stub function that carries out no action. It is provided to be consistent with the device driver interface.

Always returns one.

The export ordinal for this function is 13.


DIB_Disable

void Disable(LPPDEVICE lpDestDev));

This function is implemented as a stub function that carries out no action. It is provided to be consistent with the device driver interface.

Always returns one.

The export ordinal for this function is 4.

See Also

DIB_Enable


DIB_EnumDFonts

WORD DIB_EnumDFonts(LPPDEVICE lpDestDev, LPSZ lpFaceName,
    FARPROC lpCallbackFunc, LPVOID lpClientData);

In other drivers, this function returns information about device fonts by passing the information to the specified callback function. However, the DIB Engine has no fonts to enumerate. This function is implemented as a stub function that carries out no action. It is provided to be consistent with the device driver interface.

Always returns one; the export ordinal for this function is 6.


DIB_SetAttribute

DIB_SetAttribute(LPPDEVICE lpDevice, WORD wStateNum, WORD wIndex,
    DWORD dwAttribute);

This function is implemented as a stub function that carries out no action. It is provided to be consistent with the device driver interface.

Always returns zero; the export ordinal for this function is 18.


Structures

Following are the structures used by the DIB engine.


DIBENGINE

typedef struct {
    WORD         deType;
    WORD         deWidth;
    WORD         deHeight;
    WORD         deWidthBytes;
    BYTE         dePlanes;
    BYTE         deBitsPixel;
    DWORD        deReserved1;
    DWORD        deDeltaScan;
    LPBYTE       delpPDevice;
    DWORD        deBitsOffset;
    WORD         deBitsSelector;
    WORD         deFlags;
    WORD         deVersion;
    LPBITMAPINFO deBitmapInfo;
    void         (FAR *deBeginAccess)();
    void         (FAR *deEndAccess)();
    DWORD        deDriverReserved;
} DIBENGINE;

Specifies the dimensions, attributes, and bits of the PDEVICE for the DIB engine.

Members

deType
The type of drawing surface. Must be either TYPE_DIBENG (0x5250) or 0. If TYPE_DIBENG, the surface being drawn to is video memory, a DIB, or a color device-dependent bitmap (DDB). If 0, the surface is a monochrome bitmap, and the PDEVICE must be in the format of a PBITMAP structure, not a DIBENGINE structure.
deWidth
Width of DIB in pixels.
deHeight
Height of DIB in pixels.
deWidthBytes
Number of bytes in each raster line. The number of bytes must be a DWORD multiple; all raster lines must be aligned on 16-bit boundaries.
dePlanes
Number of planes in the bitmap. Must be one.
deBitsPixel
Number of bits per pixel.
deReserved1
Reserved, do not use
deDeltaScan
The number of bytes to the next scan line.
delpPDevice
Address of the physical device. This can be a pointer to either video memory, a device-dependent bitmap, or a device-independent bitmap.
deBits
Offset to an array of bits that specifies the pixels in the DIB. The array must be aligned on a 16-bit boundary.
deFlags
Additional flags. May be a combination of the following.
Value | Meaning
MINIDRIVER (0x0001) | Display driver
PALETTIZED (0x0002) | Palletized device
SELECTEDDIB (0x0004) | DIB Section
OFFSCREEN (0x0008) | Offscreen surface (use with VRAM)
BUSY (0x0010) | Disable the frame buffer
NOT_FRAMEBUFFER (0x0020) | Example: 8514/a or ATIM8
FIVE6FIVE (0x0040) | 16 bpp, 565 color format.
NON64KBANK (0x0080) | Bank size is not 64K
VRAM (0x8000) | Physical surface (video memory)
BANKEDVRAM (0x4000) | VFlatD simulated
BANKEDSCAN (0x2000) | VFlatD simulated (rasters may cross bank boundary)
PALETTE_XLAT (0x1000) | Background palette xlat
VGADITHER (0x0800) | Dither to VGA colors (first 8, and last 8)
CTCHANGE (0x0400) | Color table has been changed
DITHER256 (0x0200) | Dither to 256 fixed colors

deVersion
Version number. The least significant bit is the minor version number and the most significant bit is the major version number. For Windows 95 (Windows 4.0) the version number is 0400h.
deBitmapInfo
Pointer to the BITMAPINFOHEADER
deBeginAccess
Begin surface access call back.
deEndAccess
End surface access call back.
deDriverReserved
Reserved for minidriver use.


DIBColorEntry

typedef struct {
    BYTE dceBlue
    BYTE dceGreen
    BYTE dceRed
    BYTE dceFlags
} DIBColorEntry;

Describes a color entry in the palette consisting of relative intensities of blue, green, and red.

Members

dceBlue
Blue intensity value in the range 0..255.
dceGreen
Green intensity value in the range 0..255.
dceRed
Red intensity value in the range 0..255.
dceFlags
Flag specifying how the color entry is to be used. Can be either NONSTATIC or MAPTOWHITE.


DIB_Brush

Specifies the attributes, mask, and bits of brushes for the DIB engine. There are separate structures for 1bpp, 4bpp, 8bpp, 16bpp, 24bpp, and 32bpp displays.

typedef struct {
    BYTE  dp1BrushFlags;
    BYTE  dp1BrushBpp;
    WORD  dp1BrushStyle;
    DWORD dp1FgColor;
    WORD  dp1Hatch;
    DWORD dp1BgColor;
    BYTE dp1BrushMono [BRUSHSIZE*4];
    BYTE dp1BrushMask [BRUSHSIZE*4];
    BYTE dp1BrushBits [BRUSHSIZE*4];
} DIB_Brush1;

typedef struct {
    BYTE  dp4BrushFlags;
    BYTE  dp4BrushBpp;
    WORD  dp4BrushStyle;
    DWORD dp4FgColor;
    WORD  dp4Hatch;
    DWORD dp4BgColor;
    BYTE dp4BrushMono [BRUSHSIZE*4];
    BYTE dp4BrushMask [BRUSHSIZE*4];
    BYTE dp4BrushBits [BRUSHSIZE*4];
} DIB_Brush4;

typedef struct {
    BYTE  dp8BrushFlags;
    BYTE  dp8BrushBpp;
    WORD  dp8BrushStyle;
    DWORD dp8FgColor;
    WORD  dp8Hatch;
    DWORD dp8BgColor;
    BYTE dp8BrushMono [BRUSHSIZE*4];
    BYTE dp8BrushMask [BRUSHSIZE*4];
    BYTE dp8BrushBits [BRUSHSIZE*8];
} DIB_Brush8;

typedef struct {
    BYTE  dp16BrushFlags;
    BYTE  dp16BrushBpp;
    WORD  dp16BrushStyle;
    DWORD dp16FgColor;
    WORD  dp16Hatch;
    DWORD dp16BgColor;
    BYTE dp16BrushMono [BRUSHSIZE*4];
    BYTE dp16BrushMask [BRUSHSIZE*4];
    BYTE dp16BrushBits [BRUSHSIZE*16];
} DIB_Brush16;

typedef struct {
    BYTE  dp24BrushFlags;
    BYTE  dp24BrushBpp;
    WORD  dp24BrushStyle;
    DWORD dp24FgColor;
    WORD  dp24Hatch;
    DWORD dp24BgColor;
    BYTE dp24BrushMono [BRUSHSIZE*4];
    BYTE dp24BrushMask [BRUSHSIZE*4];
    BYTE dp24BrushBits [BRUSHSIZE*24];
} DIB_Brush24;

typedef struct {
    BYTE  dp32BrushFlags;
    BYTE  dp32BrushBpp;
    WORD  dp32BrushStyle;
    DWORD dp32FgColor;
    WORD  dp32Hatch;
    DWORD dp32BgColor;
    BYTE dp32BrushMono [BRUSHSIZE*4];
    BYTE dp32BrushMask [BRUSHSIZE*4];
    BYTE dp32BrushBits [BRUSHSIZE*32];
} DIB_Brush32;

Members

dpxBrushFlags
Flags describing the brush. Must be one of the following.
COLORSOLID | Color part is solid.
MONOSOLID | Monochrome part is solid.
PATTERNMONO | Pattern brush came from a monochrome bitmap.
MONOVALID | Monochrome part is valid.
MASKVALID | Transparency mask part is valid.
PRIVATEDATA | Vendor specific bit for pens and brushes.

dpxBrushBpp
The number of bits per pixel. Must be 1, 4, 8, 16, 24, or 32.
dpxBrushStyle
Style of the brush. Must be one of the following.
Value | Meaning
BS_SOLID (0) | Solid brush.
BS_NULL (1) | Same as BS_HOLLOW.
BS_HOLLOW (1) | Hollow brush.
BS_HATCHED (2) | Hatched brush.
BS_PATTERN (3) | Pattern brush defined by a memory bitmap.
BS_INDEXED (4) | Indexed brush.
BS_DIBPATTERN (5) | A pattern brush defined by a device-independent bitmap (DIB) specification.
BS_DIBPATTERNPT (6) | A pattern brush defined by a device-independent bitmap (DIB) specification.
BS_PATTERN8X8 (7) | Same meaning as BS_PATTERN.
BS_DIBPATTERN8X8 (8) | Same meaning as BS_DIBPATTERN.

dpxFgColor
Foreground color. For the dp8FgColor member of DIB_Brush8, the color is a logical color if the brush style is BS_SOLID or BS_PATTERN. If the brush style is BS_HATCHED, dp8FgColor contains a physical color.
dpxHatch
Specifies a hatch style. The meaning depends on the brush style defined by dpxBrushStyle.

If dpxBrushStyle is BS_DIBPATTERN, the dpxHatch member contains a handle to a packed DIB. If dpxBrushStyle is BS_DIBPATTERNPT, the dpxHatch member contains a pointer to a packed DIB.

If dpxBrushStyle is BS_HATCHED, the dpxHatch member specifies the orientation of the lines used to create the hatch. It can be one of the following values.
Value | Meaning
HS_BDIAGONAL | A 45-degree upward, left-to-right hatch
HS_CROSS | Horizontal and vertical cross-hatch
HS_DIAGCROSS | 45-degree crosshatch
HS_FDIAGONAL | A 45-degree downward, left-to-right hatch
HS_HORIZONTAL | Horizontal hatch
HS_VERTICAL | Vertical hatch

If dpxBrushStyle is BS_PATTERN, dpxHatch is a handle to the bitmap that defines the pattern.

If dpxBrushStyle is BS_SOLID or BS_HOLLOW, dpxHatch is ignored.

dpxBgColor
Background color. This member is only used with BS_HATCHED style brushes and it is a physical color.
dpxBrushMono
Bits describing monochrome version of the brush.
dpxBrushMask
Bits describing the transparency mask (hatch pattern) portion of the brush.
dpxBrushBits
The bits describing the brush. The size is 8 rows by 8 columns with either 1, 4, 8, 16, 24, or 32 bits per pixel.


DIB_Pen

typedef struct {
    WORD  dpPenStyle;
    BYTE  dpPenFlags;
    BYTE  dpPenBpp;
    DWORD dpPenMono;
    DWORD dpPenColor;
} DIB_Pen;

Specifies the attributes of a pen.

Members

dpPenStyle
Style of the pen. Can be one of the following values.
Value | Meaning
PS_SOLID | Pen is solid.
PS_DASH | Pen is dashed.
PS_DOT | Pen is dotted.
PS_DASHDOT | Pen has alternating dashes and dots.
PS_DASHDOTDOT | Pen has dashes and double dots.
PS_NULL | Pen is invisible.
PS_INSIDEFRAME | Pen is solid. When this pen is used in any graphics device interface (GDI) drawing function that takes a bounding rectangle, the dimensions of the figure are shrunk so that it fits entirely in the bounding rectangle, taking into account the width of the pen. This applies only to geometric pens.

dpPenFlags
Flags describing the pen. Currently none are defined.
dpPenBpp
The number of bits per pixel. Must be either 1, 4, 8, 16, 24, or 32.
dpPenMono
Bits specifying the monochrome version of the pen.
dpPenColor
Bits specifying the color version of the pen.


New Font Format and ExtTextOut Reference

This section provides detailed reference information for structures that define the new font format.


NewFontSeg

NewFontSeg  struct
   nfVersion      dw  0
   nfFormat       dw  0
   nfNumGlyphs    dw  0
   nfGlyphOffset  dd  0
   nfAWTable      dd  0
   nfHeight       dw  0
   nfAscent       dw  0
   nfUniqueID     dd  0
NewFontSeg  ends

Contains information about a physical font. This structure replaces the FONTINFO structure.

Members

nfVersion
Font version. For Windows 95, the version number is 0x0400.
nfFormat
Font format flags. Can be one of the following.
NF_BYTE_PACKED (0001h) | Indicates that the font header is in the format of either the LARGEROWGLYPH or SMALLROWGLYPH structure and the glyphs are in byte-packed (padded to byte boundaries) row format.
NF_BIT_PACKED (0002h) | Indicates that the font header is in the format of either the LARGEBITGLYPH or SMALLBITGLYPH structure and the glyphs are in bit-packed row format.
NF_FROM_BMP (0040h) | Indicates that the font is derived from a bitmap font. If this bit is set, the driver can assume the glyphs do not overlap if there is no DX array.
NF_LARGE (0080h) | Indicates that the glyph offset table is an array of DWORD offsets and that the glyphs have either LARGEROWGLYPH or LARGEBITGLYPH headers.

nfNumGlyphs
Number of glyphs in font.
nfGlyphOffset
Offset from the beginning of the font segment to an array of WORDs (DWORDs if NF_LARGE is set) which point to the glyph bitmaps.
nfAWTable
Offset from the beginning of the font segment to an array of signed 16-bit values that specify the distance from one glyph's origin to the next.
nfHeight
Height of the font in pixels.
nfAscent
Distance from baseline to the top of the font's opaquing rectangle.
nfUniqueID
Unique identifier for this physical font. This value can be used by display drivers that perform font caching to keep track of the fonts in its cache.

See Also

SMALLROWGLYPH, LARGEROWGLYPH, SMALLBITGLYPH, LARGEBITGLYPH


SMALLROWGLYPH

SMALLROWGLYPH  struc
   srgOrgX    db  0
   srgOrgY    db  0
   srgWidth   db  0
   srgHeight  db  0
SMALLROWGLYPH  ends

Specifies the header for a glyph stored in byte-packed, row-oriented format. The glyph bitmap is stored immediately after this structure.

Members

srgOrgX
Distance from glyph origin to left edge of the glyph bitmap.
srgOrgY
Distance from glyph origin to top edge of the glyph bitmap.
srgWidth
Width of glyph bitmap in pixels.
srgHeight
Height of glyph bitmap in pixels.

See Also

NewFontSeg


LARGEROWGLYPH

LARGEROWGLYPH  struc
   lrgOrgX    dw  0
   lrgOrgY    dw  0
   lrgWidth   dw  0
   lrgHeight  dw  0
LARGEROWGLYPH  ends

Specifies the header for a glyph stored in byte-packed, row-oriented format. The glyph bitmap is stored immediately after this structure.

Members

lrgOrgX
Distance from glyph origin to left edge of the glyph bitmap.
lrgOrgY
Distance from glyph origin to top edge of the glyph bitmap.
lrgWidth
Width of glyph bitmap in pixels.
lrgHeight
Height of glyph bitmap in pixels.

See Also

NewFontSeg


SMALLBITGLYPH

SMALLBITGLYPH  struc
   sbgOrgX    db  0
   sbgOrgY    db  0
   sbgWidth   db  0
   sbgHeight  db  0
   sbgPixels  dw  0
SMALLBITGLYPH  ends

This structure is the header for a glyph stored in bit-packed row-oriented format. The glyph bitmap is stored immediately after this structure. Bit-packed format means that the glyph rows are packed together end-to-end. There is no padding out to byte boundaries at the end of a row.

Members

sbgOrgX
Distance from glyph origin to left edge of the glyph bitmap.
sbgOrgY
Distance from glyph origin to top edge of the glyph bitmap.
sbgWidth
Width of glyph bitmap in pixels.
sbgHeight
Height of glyph bitmap in pixels.
sbgPixels
Total number of pixels in the glyph.

See Also

NewFontSeg


LARGEBITGLYPH

LARGEBITGLYPH  struc
   lbgOrgX    dw  0
   lbgOrgY    dw  0
   lbgWidth   dw  0
   lbgHeight  dw  0
   lbgPixels  dd  0
LARGEBITGLYPH  ends

This structure is the header for a glyph stored in bit-packed row-oriented format. The glyph bitmap is stored immediately after this structure. Bit-packed format means that the glyph rows are packed together end-to-end. There is no padding out to byte boundaries at the end of a row.

Members

lbgOrgX
Distance from glyph origin to left edge of the glyph bitmap.
lbgOrgY
Distance from glyph origin to top edge of the glyph bitmap.
lbgWidth
Width of glyph bitmap in pixels.
lbgHeight
Height of glyph bitmap in pixels.
lbgPixels
Total number of pixels in the glyph.

See Also

NewFontSeg


Virtual Display Device Reference

This section provides detailed reference information for the following VDD functions.

VDD_DRIVER_REGISTER
VDD_DRIVER_UNREGISTER
VDD_SAVE_DRIVER_STATE
VDD_REGISTER_DISPLAY_DRIVER_INFO
VDD_REGISTER_SSB_FLAGS
VDD_GET_DISPLAY_CONFIG
VDD_PRE_CRTC_MODE_CHANGE
VDD_POST_CRTC_MODE_CHANGE
VDD_SET_USER_FLAGS
VDD_SET_BUSY_FLAG_ADDR
VDD_PC98_RESERVED


VDD_DRIVER_REGISTER

Call With

EAX = VDD_DRIVER_REGISTER equate (80H)

EBX = Magic Number

ECX = Total bytes used by the visible Windows screen

EDX = 0 if the mini-VDD supports VGA 4 plane virtualization in a window or -1 if the display requires that VGA 4 plane graphics programs run full-screen and can not be windowed.

ES:DI Pointer to ResetHiResMode which is a required Display driver function which will be called by the VDD in order to reenable the display hardware for Windows high resolution mode after returning from a full-screen MS-DOS virtual machine.

Return Values

EAX = Total bytes of memory used by the screen (as passed in ECX to the function) plus the number of bytes used by the VDD for virtualizing VGA 4 plane graphics in a window.

EAX = VDD_DRIVER_REGISTER if you are running with a Windows 3.1 VDD and not the Windows 95 VDD. This means that the user somehow has installed the wrong VDD.

Remarks

This routine should be called immediately after the Windows high resolution (hi-res) mode has been set by the display driver. The mini-VDD's function GET_VDD_BANK is called by this routine.

ResetHiResMode is a required display driver entry point which must be placed in a FIXED code segment in the display driver. It is called by the Windows 95 VDD in order to place the screen back into Windows hi-res mode after a user presses ALT-TAB or ALT-ENTER to switch away from a full screen MS-DOS session. ResetHiResMode typically is a simplified Enable call which reinitializes the hardware including the palette DAC and hardware cursor so that Windows will run again.

To support East Asian DBCS, the display hardware and mini-VDD should be able to support VGA graphics in a window. The VDD supports VGA graphics in a window by allocating a 32K or 64K block of video memory right below the visible Windows screen. The mini-VDD then sets access to this memory (usually by banking it into physical address A000h) and allows planar access to this memory while maintaining the packed pixel Windows screen visibly. However, some hardware cannot simultaneously have the VGA data pathway and the packed-pixel hi-res pathway running. If your hardware cannot, set EDX to -1 and the VDD will not attempt VGA virtualization in a window.

This function calls the mini-VDD function GET_VDD_BANK.

See Also

GET_VDD_BANK


VDD_DRIVER_UNREGISTER

Call With

EAX = VDD_DRIVER_UNREGISTER equate (81H)

EBX = Magic Number

All other registers can contain private communication information which is passed directly to the mini-VDD function DISPLAY_DRIVER_DISABLING.

Return Values

Nothing destroyed.

Remarks

This function does an Interrupt 10h, function 0 call to set the hardware into text mode 3. It should be called during the display driver's Disable routine, right before the driver leaves Windows hi-res mode and returns to VGA mode.

This function calls the mini-VDD function DISPLAY_DRIVER_DISABLING which allows the mini-VDD to release I/O port trapping or memory traps that it may have set while running Windows.

This function calls the mini-VDD function DISPLAY_DRIVER_DISABLING.

See Also

DISPLAY_DRIVER_DISABLING


VDD_SAVE_DRIVER_STATE

Call With

EAX = VDD_SAVE_DRIVER_STATE equate (82H)

EBX = Magic Number

Return Values

Nothing destroyed.

Remarks

This routine should be called at the end of the display driver's physical Enable routine and after ResetHiResMode is finished putting the screen into Windows hi-res mode. It allows the mini-VDD to save the Windows running state of the standard VGA registers. It also calls the mini-VDD function SAVE_REGISTERS to allow the mini-VDD to save the Windows running state of the extended registers.

This function calls the mini-VDD function SAVE_REGISTERS.

See Also

SAVE_REGISTERS


VDD_REGISTER_DISPLAY_DRIVER_INFO

Call With

EAX = VDD_REGISTER_DISPLAY_DRIVER_INFO equate (83H)

EBX = Magic Number

All other registers can contain private communication information which will be passed directly to the mini-VDD function REGISTER_DISPLAY_DRIVER.

Return Values

Whatever the mini-VDD and the display driver have arranged between themselves.

Remarks

This routine sets up the close communication between the display driver and the mini-VDD. This function is sometimes called before and after the display driver sets the hardware into the Windows hi-res state. You could setup sub-functions of this call in the ECX register and call each of the sub-functions any time during display driver initialization depending on the needs of the display subsystem.

One possible use for this function would be for the display driver to pass a Selector:Offset of one or more flags to the mini-VDD. Suppose that the display hardware cannot change its hardware state in the middle of a memory to screen bitblt and that the VDD has to wait until this operation is finished before making a hardware state change such as running a windowed 4 Plane VGA application. The display driver could pass the address of an "InSrcBLT" flag to the mini-VDD in the ES:DI registers. The mini-VDD would then convert this Selector:Offset address to a linear address by means of the VMM function Map_Flat. Then the mini-VDD would pass this linear address to the Main VDD function VDD_Set_Sleep_Flag_Addr.

Another possible use for this function would be for the display driver to pass the address of a non-VFLATD screen selector to the mini-VDD. The mini-VDD could use this selector to access Memory Mapped Registers or the video RAM as a flat linear frame buffer. In order for windowed VGA virtualization to correctly take place, the Main VDD has to know about all ways that the display driver will access the video hardware (for example, via a hardware BLTer using I/O ports, via a hardware BLTer using memory mapped registers, via a flat linear selector that the display has allocated independently from VFLATD, or via a VFLATD selector). Thus, the display driver could pass down the selector of its memory mapped or flat linear selector to the mini-VDD via this function. The mini-VDD would then call the Main VDD function VDD_Register_Extra_Screen_Selector in order to register this selector.

Yet another possible use for this function would be to allow the mini-VDD to partially or fully place the video hardware into hi-res mode. It may be desirable to do this if port trapping by the VMM is of concern as it is in time-critical programming of the video hardware.

This function calls the mini-VDD function REGISTER_DISPLAY_DRIVER.

See Also

VDD_Set_Sleep_Flag_Addr, REGISTER_DISPLAY_DRIVER, VDD_Register_Extra_Screen_Selector


VDD_REGISTER_SSB_FLAGS

Call With

EAX = VDD_REGISTER_SSB_FLAGS equate (84H)

EBX = Magic Number

DS:SI = Pointer to SaveScreenBitmap flag byte.

Return Values

Nothing destroyed.

Remarks

Because many display drivers implement the SaveScreenBitmap function and because they want to maximize the amount of off-screen memory available for SaveScreenBitmap, the Main VDD allows the display driver to register the address of a byte flag in the display driver's fixed data segment which controls the operation of SaveScreenBitmap.

This flag has three bits that the VDD and/or SaveScreenBitmap interact with.

Bit 0 | (called SHADOW_EXISTS in VGA.DRV) flags that the display driver could potentially use off-screen memory for SaveScreenBitmap use. This flag is ignored by the VDD at this time.
Bit 1 | (called SHADOW_IN_USE in VGA.DRV) flags that SaveScreenBitmap has something saved in the off-screen memory area. The VDD checks this flag before setting the SHADOW_TRASHED flag to see if SaveScreenBitmap is using that area.
Bit 2 | (called SHADOW_TRASHED in VGA.DRV) flags that someone other than SaveScreenBitmap (in our case the VDD's VGA virtualization routines) has destroyed a bitmap which SaveScreenBitmap has saved in the off-screen area. The VDD sets this bit when it uses the off-screen memory for VGA virtualization.

No mini-VDD functions are called during this function.


VDD_GET_DISPLAY_CONFIG

Call With

EAX = VDD_GET_DISPLAY_CONFIG equate (85H)

EBX = Magic Number

ECX = Size of DISPLAYINFO structure that is being passed.

ES:EDI = Pointer to DISPLAYINFO structure to fill (see MINIVDD.INC)

Return Values

EAX = Return Code (0 for success, -1 for failure).

Remarks

This is the display Plug & Play interface for Windows 95. This call returns a DISPLAYINFO data structure to the caller. The caller should allocate a DISPLAYINFO structure and then pass its address in the ES:EDI registers when making this call.

No mini-VDD functions are called during this function.


VDD_PRE_CRTC_MODE_CHANGE

Call With

EAX = VDD_PRE_CRTC_MODE_CHANGE equate (86H)

EBX = Magic Number

All other registers can contain private communication information which is passed directly to the mini-VDD function PRE_CRTC_MODE_CHANGE.

Return Values

Whatever the mini-VDD and the display driver have arranged between themselves.

Remarks

The purpose of this function and for VDD_POST_CRTC_MODE_CHANGE is to set monitor refresh rates on the display card prior to the setting the video hardware into Windows hi-res mode. Some display cards require the refresh rate to be set before the video mode change, others require it after the video mode change. These routines allow that to happen.

This function calls the mini-VDD function PRE_CRTC_MODE_CHANGE.

See Also

PRE_CRTC_MODE_CHANGE


VDD_POST_CRTC_MODE_CHANGE

Call With

EAX = VDD_POST_CRTC_MODE_CHANGE equate (87H)

EBX = Magic Number

All other registers can contain private communication information which is passed directly to the mini-VDD function POST_CRTC_MODE_CHANGE.

Return Values

Whatever the mini-VDD and the display driver have arranged between themselves.

Remarks

See VDD_PRE_CRTC_MODE_CHANGE for details.

This function calls the mini-VDD function POST_CRTC_MODE_CHANGE.

See Also

VDD_PRE_CRTC_MODE_CHANGE


VDD_SET_USER_FLAGS

Call With

EAX = VDD_SET_USER_FLAGS equate (88H)

EBX = Magic Number

DX:CX = Selector:Offset address of optional EnabledFlag in display driver's data segment. This is a byte flag which is set to 0 when it is safe for the display driver to draw, and 1 when the display driver should not draw, for example, when in a full-screen MS-DOS session.

Return Values

AX contains zero upon success or -1 upon failure.

Remarks

This function is for display drivers that do not use the BUSY flag in the Windows 95 DIB Engine to determine whether the Windows hi-res screen is enabled or a full-screen MS-DOS session is enabled. This function is not recommended, the preferred method is to use the DIB engine. Although this function is not recommended for Windows 95 drivers, it allows display drivers to register the Selector:Offset address of a byte lengthed BUSY flag which is set by the Main VDD to 1 whenever the video focus is set to a full-screen MS-DOS session and to 0 whenever the video focus is on Windows.

The BUSY flag is one of the flags that may be set in the deFlags member of the DIB engine's PDEVICE structure. When set, it indicates that the display hardware cannot be accessed. The address of the BUSY flag is set by the Windows 95 GDI using the VDD_SET_BUSY_FLAG_ADDR function. This flag is automatically set by the Main VDD whenever the screen group is switched away from the Windows hi-res screen to a full-screen MS-DOS session. When this flag is set, the display driver must not draw on the display surface since the video focus is on a full-screen MS-DOS session and doing so would corrupt the appearance of the MS-DOS session. This protocol is necessary since Windows may call display driver functions such as SetCursor, MoveCursor, BitBlt, ExtTextOut, etc. even after the video focus is set onto a full-screen MS-DOS session.

This function calls no mini-VDD functions.

See Also

VDD_SET_BUSY_FLAG_ADDR


VDD_SET_BUSY_FLAG_ADDR

Call With

EAX = VDD_SET_BUSY_FLAG_ADDR equate (89H)

EBX = Magic Number

CX = the bitmask (set to 1) for the BUSY bit within the byte.

SI:DI = Selector:Offset address of byte containing the DIB engine BUSY bit in the display driver's PDEVICE structure.

Return Values

Nothing returned.

Remarks

This function is for internal use by GDI only. Any other use will cause Windows and the display subsytem to become unstable.

This function calls no mini-VDD functions.


VDD_PC98_RESERVED

Call With

EAX = VDD_PC_98_RESERVED equate (8AH)

EBX = Magic Number

Remarks

Reserved; do not use. If called, returns an error.


DISPLAYINFO

DISPLAYINFO  struc
  diHdrSize    dw  size DisplayInfo
  diInfoFlags    dw  ?
  diDevNodeHandle    dd  ?
  diDriverName    db  16 dup(?)
  diXRes      dw  ?
  diYRes      dw  ?
  diDPI      dw  ?
  diPlanes    db  ?
  diBpp      db  ?
  diRefreshRateMax  dw  ?
  diRefreshRateMin  dw  ?
  diLowHorz    dw  ?
  diHighHorz    dw  ?
  diLowVert    dw  ?
  diHighVert    dw  ?
  diMonitorDevNodeHandle  dd  ?
  diHorzSyncPolarity  db  ?
  diVertSyncPolarity  db  ?
DISPLAYINFO

Specifies the display information selected by the user. The information in this structure is obtained by calling either the ring 3 function VDD_GET_DISPLAY_CONFIG or the ring 0 function VDD_GetDisplayInfo.

Members

diHdrSize
Size in bytes of the DISPLAYINFO structure.
diInfoFlags
Informational flags, may be one of the following.
RETURNED_DATA_IS_STALE | Indicates that the data in the DISPLAYINFO structure was read in a previous call to VDD_GET_DISPLAY_CONFIG instead of directly from the Registry. If this flag is set, you may want to call VDD_GET_DISPLAY_CONFIG (or VDD_GetDisplayInfo) again to attempt to obtain data directly from the registry.
MINIVDD_FAILED_TO_LOAD | Indicates that the mini-VDD did not load, possibly because the mini-VDD did not match the chipset installed in the machine.
MINIVDD_CHIP_ID_DIDNT_MATCH | Indicates that although the mini-VDD did load successfully, when the ChipID that the mini-VDD calculated was compared against the value saved in the registry, they did not match. For example, suppose the user is using an S3-911 card and then decides to upgrade the display card to an S3-864. Because both cards use S3.VXD, the mini-VDD will load. But because the card model is different, the VDD will return a defect to configuration manager and set this flag.
REGISTRY_BPP_NOT_VALID | Indicates that the VDD was unable to obtain a bits-per-pixel value from the Registry.
REGISTRY_RESOLUTION_NOT_VALID | Indicates that the VDD was unable to obtain a resolution value from the Registry.
REGISTRY_DPI_NOT_VALID | Indicates that the VDD was unable to obtain a DPI value from the Registry.
MONITOR_DEVNODE_NOT_ACTIVE | Indicates that a call to the function GET_DISPLAY_CONFIG was made before the monitor DevNode handle had been created. This means that the monitor refresh rate information in the DISPLAYINFO structure is invalid.
MONITOR_INFO_NOT_VALID | Indicates that the values in diRefreshRateMax, diRefreshRateMin, diLowHorz, diHighHorz, diLowVert, diHighVert, diHorzSyncPolarity, and diVertSyncPolarity are not valid.
MONITOR_INFO_DISABLED_BY_USER | Indicates that either the "RefreshRate=" string in SYSTEM.INI had a negative number in it or that the string in the display software key "RefreshRate =" string was 0 or a negative number.
REFRESH_RATE_MAX_ONLY | Indicates that there was no data in the Registry for diLowHorz, diHighHorz, diLowVert, diHighVert, diHorzSyncPolarity, or diVertSyncPolarity and that the value returned in diRefreshRateMax is the only refresh rate data available and it was derived either from either the "RefreshRate=" string in SYSTEM.INI or the display software key "RefreshRate =" string in the Registry.
CARD_VDD_LOADED_OK | Indicates that a card VDD was successfully loaded and initialized.

diDevNodeHandle
Handle used to access information in the Registry about the display subsystem and passed to configuration management function calls.
diDriverName
Address of a null-terminated string containing the name of the driver.
diXRes
Width in pixels, of the display.
diYRes
Height in pixels, of the display.
diDPI
Number of dots per inch of the display.
diPlanes
Number of color planes.
diBpp
Number of adjacent color bits for each pixel.
diRefreshRateMax
Maximum refresh rate.
diRefreshRateMin
Minimum refresh rate.
diLowHorz and diHighHorz
Horizontal sync polarity ranges.
diLowVert and diHighVert
Vertical sync polarity ranges.
diMonitorDevNodeHandle
Handle used to access Registry information about the monitor.
diHorzSyncPolarity and diVertSyncPolarity
Sync polarity monitor settings.

See Also

ValidateMode, VDD_GET_DISPLAY_CONFIG


Virtual Display Minidriver Reference

The following topic contains reference information for the virtual display minidriver.


MiniVDD_Dynamic_Init

Call With

EBX: Contains the System (Windows) VM Handle

Return Values

You should preserve EBX; all other registers can be destroyed. Return with the carry flag clear to indicate that Dynamic_Init succeeded and that the mini-VDD did not detect any problems with the video hardware. Return with the carry flag set to indicate an error.

Remarks

Early in the Windows® 95 boot sequence, the Main VDD reads the Registry to get the correct mini-VDD to load and then proceeds to load the mini-VDD. As soon as the VxD loader loads the mini-VDD, MiniVDD_Dynamic_Init is called. The mini-VDD performs several checks of the video hardware at this time. If the mini-VDD does not detect any problems with the video hardware, the mini-VDD is successfully loaded. If the mini-VDD finds a problem such as running on the wrong hardware, MiniVDD_Dynamic_Init returns with the carry flag set indicating that there is a problem, and the Main VDD returns an error to the Plug & Play subsystem. The Plug & Play subsystem then displays an error message dialog box to the user concerning the problem with the display settings, and allows the user to run a hardware detection program to correct the problem.

The mini-VDD must do several things during MiniVDD_Dynamic_Init

  1. It must check to make sure that it is running on the proper hardware by doing a non-destructive detection. If it is not running on a supported chipset, the mini-VDD should return immediately with the carry flag set to report the error.
  2. If the same mini-VDD is used on different chipsets, it should identify what chipset it is running on and save this chipset ID. For more information, see the description of the mini-VDD hook function GET_CHIP_ID as well as the ATI example mini-VDD.
  3. It should allocate space in the CB data area to save register and mode states on a per-VM basis. The data that your mini-VDD saves in the allocated space in the CB data area varies for every mini-VDD. For example, the Windows VM may set CRTC register 42h to one value and a MS-DOS VM might set register 42h to another value. Your register virtualization routines must virtualize CRTC register 42h and save each of its values in the CB data area. When called upon to restore the register 42h for a certain VM, it can restore the correct value for each VM's required state. If the CB data area allocation fails, then the system is in an unstable state and MiniVDD_Dynamic_Init should return with the carry flag set to indicate an error.
  4. It should obtain the address of the mini-VDD hook dispatch table using the service VDD_Get_Mini_Dispatch_Table. Then, the mini-VDD can install the address of the routines that it needs to hook in this table by using the MiniVDDDispatch macro found in MINIVDD.INC. See the example mini-VDDs included in the DDK for proper use of the MiniVDDDispatch macro. +The mini-VDD should also perform a version check at this point by comparing the total number of mini-VDD hook functions using the equate NBR_MINI_VDD_FUNCTIONS (included in MINIVDD.INC) to the number returned in ECX by the service VDD_Get_Mini_Dispatch_Table. If the NBR_MINI_VDD_FUNCTIONS is greater than the value returned in ECX, then it means that the mini-VDD has hook functions that the Main VDD does not know about. This would indicate that the mini-VDD is newer than the Main VDD. In this case, the mini-VDD should fail.
  5. The mini-VDD should get and save the special VM handles, Blue Screen Message Mode and Forced Planar Mode, that the Main VDD has setup. The mini-VDD function RESTORE_REGISTERS uses these handles to properly restore the blue-screen-message mode state or the forced planar state. See RESTORE_REGISTERS for details.


Mini-VDD Hook Functions

Following are the functions that the mini-VDD can hook out.

Note In all functions, preserve the registers EBX and EBP unless otherwise noted.


ACCESS_LINEAR_MEMORY_MODE (Function 12)

Call With

EBX: Contains the VM handle to modify state for.

Return Values

Save anything that you use.

Remarks

Certain pieces of display hardware are "modal" and must have some of their extended registers set to certain values depending on whether the application is accessing memory at one of the VGA apertures (such as A000h:xxxx) or if it is accessing memory using a flat linear frame buffer. This routine is called by the Main VDD to explicitly tell the mini-VDD to setup for accessing the flat linear frame buffer. See the sample S3 mini-VDD for an example of how this function is used.


ACCESS_VGA_MEMORY_MODE (Function 11)

Call With

EBX: Contains the VM handle to modify state for.

Return Values

Save anything that you use.

Remarks

Certain pieces of display hardware are "modal" and must have some of their extended registers set to certain values depending on whether the application is accessing memory at one of the VGA apertures (such as A000h:xxxx) or if it is accessing memory using a flat linear frame buffer. This routine is called by the Main VDD to explicitly tell the mini-VDD to setup for accessing at the VGA 64K aperture. See the sample S3 mini-VDD for an example of how this function is used.


CHECK_HIRES_MODE (Function 35)

Call With

AL: Contains the Interrupt 10h video mode.

EBX: Contains the VM handle to inquire about.

EBP: Points to the Windows VM's Client Registers.

Return Values

Save everything that you use. CY returned means that the VM is in a hi-res mode. NC returned means that the VM is in a standard VGA mode.

Remarks

In many cases, a hi-res video BIOS does not indicate that it is running in a hi-res mode except by reading states contained in extended registers. For example, the BIOS data area of a VM (at virtual address 0:449H) might indicate that the VM is in VGA mode 3 (80x25 text mode) while the hardware is actually in 1024x768 graphics mode. Therefore, whenever the Main VDD needs to know if a VM is running in hi-res mode, it checks first for a VESA mode, then for an Interrupt 10h BIOS mode above 13h, and then queries the mini-VDD to see if it is running a hi-res mode.

If you determine whether or not you are running in a hi-res mode by looking at the ROM BIOS mode number at 0:449H, you should use the value passed in AL rather than reading 0:449H yourself since East Asian Windows changes the data passed in AL to compensate for Japanese text modes 72H and 73H. If the Main VDD sees that Japanese Windows 95 is running, it passes these modes as modes 02H and 03H instead of 72H and 73H. By using the data in AL, you can avoid "false readings" of hi-res mode in Japanese Windows 95

See the ATI mini-VDD for a sample of how this routine works.


CHECK_SCREEN_SWITCH_OK (Function 43)

Call With

EAX: Contains -1 if running in a known VESA mode.

EBX: Contains the VM handle (always the Windows VM).

ECX: Contains the video mode number (if known).

EBP: Points to the Windows VM's Client Registers.

Return Values

CY indicates that the hi-res application may not be switched away from. NC indicates that it is safe to switch away from the hi-res application.

Remarks

The Main VDD calls this routine whenever a user presses ALT-ENTER or ALT-TAB to switch away from a full-screen MS-DOS prompt. The mini-VDD should determine if it knows how to restore this mode. If it is a VESA mode or standard VGA mode, the Main VDD knows how to restore it and unless the mini-VDD has special considerations, it should return NC. Otherwise, it should return CY causing the system to beep to alert the user that the hi-res VM cannot be switched away from. This notification is not given if a user presses CTRL-ALT-DEL to terminate a full-screen application. In this case, no save of the screen is attempted and it will be impossible to restore the screen if the user tries to switch back. In this case, if the user tries to switch back, the system terminates the application.


DISABLE_TRAPS (Function 14)

The parameters and return values for this function are the same as for ENABLE_TRAPS. See ENABLE_TRAPS for details.

See also ENABLE_TRAPS.


DISPLAY_DRIVER_DISABLING (Function 26)

Call With

EBX: Contains a Windows VM Handle.

EBP: Points to the Windows VM's Client Registers.

Return Values

Save anything that you use.

Remarks

This routine is called during the display driver's call to the Main VDD function VDD_DRIVER_UNREGISTER. This routine allows the mini-VDD to unhook trapping and/or set flags when the display driver's Disable routine is called by Windows, either during Windows shutdown, or in response to a Windows application wanting to go full-screen (the Windows MediaPlayer application is an example of this). Also, this function is called when going into single-MS-DOS-application mode. The mini-VDD should free all of its trapping and set flags so that RESTORE_REGISTERS and SAVE_REGISTERS do not do anything so that the application has free and clear access to the hardware.


ENABLE_TRAPS (Function 13)

Call With

Undefined.

Return Values

Save anything that you use.

Remarks

ENABLE_TRAPS and DISABLE_TRAPS gives the mini-VDD the opportunity to enable or disable traps that it has previously setup I/O handler trapping for (see the S3 mini-VDD's Dynamic_Init routine for an example of how to setup I/O handlers for BLTer registers using Install_IO_Handler and VDD_Register_Virtual_Port). It is an empirical process to decide which ports to trap and which not to.

Notes on BLTer port trapping:

If you plan to support virtualization of 4 plane VGA modes in the background or in a window, you will need to support trapping of all the BLTer and extended register ports that your display driver might use during the course of running Windows. Note that the Main VDD does most of the work in handling the virtualization and all that the mini-VDD needs to do is to use the VDD service VDD_Register_Virtual_Port for each of the BLTer and extended ports that the display driver might use and then respond to ENABLE_TRAPS and DISABLE_TRAPS calls from the Main VDD. Within your ENABLE_TRAPS and DISABLE_TRAPS routines, you must call Enable_Global_Trapping or Disable_Global_Trapping once for each port.

The reason that 4 plane VGA virtualization requires the port trapping is because the Main VDD monitors accesses to the ports to know when to switch the hardware state from 4 plane virtualization mode to Windows hi-res mode. For more information, see GET_VDD_BANK. The Main VDD only traps these ports when a 4 plane VGA application is running (or during a mode change) and then only when the execution focus is set to the 4 plane VGA application.

Again, the Main VDD uses ports registered using the function VDD_Register_Virtual_Port only to be notified when the Windows display driver is accessing the hardware and to tell the mini-VDD to instigate a hardware state change back to the Windows hi-res MemC state.

The main reason for trapping extended ports is to prevent them from being written while a mode change is being virtualized in a window. In this case, your mini-VDD must provide its own I/O handler for these ports. See the S3.VXD's virtualization of port 4AE8h for an example of why and how to trap certain ports.


GET_BANK_SIZE (Function 37)

Call With

EBX: Contains the VM handle (always the currently executing VM).

ECX: Contains the VESA BIOS mode number that is currently running.

EBP: Points to the Windows VM's Client Registers.

Return Values

Save everything that you use. CY returned means that mini-VDD handled the call. EDX contains the current bank size. EAX contains the physical address of the memory aperture or zero to indicate a standard memory aperture at physical address A000:0h.

Remarks

This routine is called during the save process of a VESA hi-res screen. It tells the Main VDD how large each bank is (so that during the save and restore process, it will know how many bytes to process per pass of the save/restore loop). It also informs the Main VDD where to access the VRAM. Most VESA programs currently set their VRAM at A000:0h. However, VESA version 2 does allow for flat linear apertures. The mini-VDD should determine if the VESA program is using an aperture and return the correct data to the Main VDD.


GET_CHIP_ID (Function 42)

Call With

EBX: Contains the VM handle (always the Windows VM).

EBP: Points to the Windows VM's Client Registers.

Return Values

Save everything that you use. EAX contains the ChipID.

Remarks

Several mini-VDD's support multiple chipsets that utilize different display drivers. For example, ATI's mini-VDD supports the VGA Wonder which uses SUPERVGA.DRV, the Mach8 which uses ATIM8.DRV, the Mach32 which uses ATIM32.DRV, and the Mach64 which uses ATIM64.DRV. Therefore, the detection for each of these chipsets is included in the ATI mini-VDD. GET_CHIP_ID is the only way the Main VDD Plug & Play support code can differentiate between display cards that use the same mini-VDD.

The Main VDD calls the function MiniVDD_Dynamic_Init when the mini-VDD is loaded. If MiniVDD_Dynamic_Init returns with the carry flag clear (indicating success), the Main VDD calls GET_CHIP_ID as a second check to make sure that the user has not changed the video card since the last time Windows was run. The Main VDD compares the value returned by GET_CHIP_ID with the value stored in the registry and if they are different, it reports the error to the Plug & Play subsystem.

If the mini-VDD fails to detect one of the cards it supports, MiniVDD_Dynamic_Init returns with the carry flag set (indicating failure) and the Windows 95's Plug & Play code loads the standard VGA driver.

If the value returned by GET_CHIP_ID is different than the value stored in the registry, or if MiniVDD_Dynamic_Init returns failure, the system displays an error message to the user concerning the problem with the display settings and allows the user to run hardware detection to re-detect the video card.


GET_CURRENT_BANK_READ (Function 33)

The parameters and return values for this function are the same as for GET_CURRENT_BANK_WRITE. See GET_CURRENT_BANK_WRITE for details.

See Also

GET_CURRENT_BANK_WRITE


GET_CURRENT_BANK_WRITE (Function 32)

Call With

EBX: Contains the VM handle (always the currently executing VM).

EBP: Points to the Windows VM's Client Registers.

Return Values

Save everything that you use. CY returned means that the mini-VDD handled the call. NC returned means that Main VDD should use a VESA call to retrieve the bank. If successful, EDX contains the current bank (write or read) as set in hardware.

Remarks

GET_CURRENT_BANK_WRITE and GET_CURRENT_BANK_READ are made when the user presses ALT-TAB to switch away from a VESA hi-res application. The Main VDD uses GET_CURRENT_BANK_WRITE to retrieve the current state of the banking registers (which are "Windows" in VESA terminology). It then saves these for later restoration when the user presses ALT-TAB back to the VESA hi-res application. The Main VDD uses VESA function 4F05h to get the bank if the mini-VDD fails this call.


GET_TOTAL_VRAM_SIZE (Function 36)

Call With

EBX: Contains the VM handle (always the currently executing VM).

EBP: Contains the Windows VM's Client Registers.

Return Values

Save everything that you use. CY returned means that mini-VDD handled the call. ECX contains the total size of VRAM on the card.

Remarks

Whenever the VDD saves a hi-res mode, it saves all of the card's video memory to the swap file. This is because VESA applications have full access to the total memory on the card, even if their visible screen size is less than the total VRAM size on the card. Therefore, the Main VDD must know the total VRAM size. If the mini-VDD does not handle this call, the Main VDD will do a time-consuming call to VESA BIOS function 4F00h to obtain this information. For performance reasons, you should implement this function.


GET_VDD_BANK (Function 1)

Call With

EBX: Contains the Windows VM Handle.

ECX and Client ECX: Contain the byte offset of the start of the 32K or 64K VGA 4 plane virtualization area.

EBP: Contains the Windows VM's Client Registers.

Return Values

AH contains the page offset from the start of the VDD bank of the virtualization area. ECX must be preserved. EDX contains the amount of video memory that is devoted to the VGA 4 plane virtualization area. If not allowing VGA 4 plane virtualization, set EDX = ECX or Client_ECX. If allowing VGA 4 plane virtualization, set EDX to either the value 64K or 32K.

Remarks

This function allows the mini-VDD to prepare to implement 4 plane VGA virtualization in a window or in background VM's. In order to allow running VGA 4 plane graphics in a window, your hardware must allow the VGA data pathway while you are in your hi-res packed pixel configuration. The Main VDD sets the hardware up so that the CPU communicates to a 64K piece of memory located below the Windows visible screen just as it would to a 4 plane VGA at address A000h. The VGA 4 plane program draws to this off-screen memory using the VGA's rudimentary BLTer (that is, the VGA write modes and set/reset support). The VDD then reads back the 4 planes and sends the video data back to the Grabber which converts the 4 plane image to a device-independent bitmap and sends it to GDI for display in a window.

Because the off-screen piece of memory is mapped to its A000h segment, the VGA 4 plane application communicates with it just as it would to a real VGA. The Main VDD decides when to map the memory in and out and when to change from the 4 plane state back to packed pixel state. The only thing that the mini-VDD must do is to set to the 64K bank when requested to by the Main VDD and set any hardware registers to their necessary configuration to simulate 4 plane VGA graphics to the program while displaying packed pixel graphics on the monitor.

This functionality is very important to East Asian DBCS Windows implementations since they use VGA mode 12h (640x480x4 planes) to implement their DBCS text mode MS-DOS window. This functionality also allows VGA games to run windowed under Windows 95.

The following scenario describes how the Main VDD determines when to do VGA virtualization

  1. A VGA 4 plane application writes to memory address A000h:xxxx.
  2. The Main VDD gets a page fault from a VM other than the Windows VM.
  3. The Main VDD determines that it is running 4 plane VGA graphics in a window or in the background.
  4. The Main VDD calls RESTORE_REGISTERS in the mini-VDD to setup the hardware for planar VGA support. The appearance of the screen must not change when this state is setup. The mini-VDD should also make sure that banking is accessible on the hardware at this time and not when the Main VDD calls SET_VDD_BANK.
  5. The Main VDD calls SET_VDD_BANK to set to the 64K or 32K off-screen VGA virtualization area. The mini-VDD responds by setting the banking registers to values that it determined when the Main VDD called GET_VDD_BANK.
  6. The Main VDD maps A000h and returns to the VGA 4 plane application which now has a block of memory that it believes is at address A000:0, but in reality is the off-screen memory that the VDD has setup the hardware to access.
  7. The VGA 4 plane application draws to this off-screen memory until Windows 95 decides to switch back to the Windows VM.
  8. Windows 95 does a pre-emptive task switch to the Windows VM. Next the Windows display driver accesses memory at address A000h or flat linear memory; or it uses the I/O registers or memory mapped BLTer registers to access memory. The Main VDD takes either a page fault, register trap or memory fault depending on how the display driver accessed the memory. The Main VDD may at this time read the 4 plane image from the VGA virtualization area and deliver it to the Grabber.
  9. The Main VDD calls the mini-VDD function RESET_BANK to reset the banking registers back to their previous value. The mini-VDD verifies that the banking registers have not been changed and restores them. (The banking registers may be changed if they are not virtualized by the mini-VDD).
  10. The Main VDD calls the mini-VDD function RESTORE_REGISTERS to set the hardware registers back to the Windows running state.
  11. The Main VDD maps A000h or the flat linear buffer, or the memory mapped registers back into the Windows VM. In the case of memory-mapped BLTer or I/O registers, it simulates the I/O on behalf of the VM.
  12. The Windows VM runs until the VGA 4 plane application runs again.

Currently, your card must be able to map in a 32K or 64K bank of video memory at A000h. The mini-VDD, in response to this call, should determine if it has enough memory to do this, and setup the hardware register states to accomplish this. The sample mini-VDDs provide examples of how to do this. If your video card uses a flat linear address space and cannot bank its video memory in at A000h, you cannot do VGA 4 plane graphics in a window or in the background. In case you decide that your current configuration cannot do VGA 4 plane graphics in a window, you should set EDX equal to the entry value of ECX (or Client_ECX) and return. This will indicate to the Main VDD not to allow VGA 4 plane graphics in a window. You can however, still do text (although not DBCS text) in a window and the non-planar graphics modes (such as mode 13H) in a window.

You should allocate the 32K or 64K block of virtualization memory on an even bank boundary. However, the VDD allows you to allocate it on 16K page boundaries (4K per page * 4 planes) by returning a page offset value in AH. For example, if a mini-VDD wants to allocate the last 32K of bank 12 to VGA virtualization, it would return a 2 in AH. This would tell the Main VDD to start halfway down the bank when it maps video memory into the VGA 4 plane VM.

The Main VDD calls this function in response to the display driver calling VDD_DRIVER_REGISTER. It is not called if the display driver passed Client_EDX == -1 (indicating that the display driver decided not to allow VGA 4 plane virtualization).


MAKE_HARDWARE_NOT_BUSY (Function 15)

Call With

EAX: Contains the CRTC owner's VM handle.

EBX: Contains the currently running VM handle.

ECX: Contains the MemC owner's VM handle.

EDX: Contains the CRTC index register (which must be saved over call).

Return Values

Save anything that you use.

Remarks

If your hardware must complete a BLTer drawing operation before having its MemC state switched from Windows hi-res mode to VGA planar mode, then you must implement MAKE_HARDWARE_NOT_BUSY. Many cards (especially those based on IBM's 8514 architecture) have a command FIFO and drawing engine which should not be disturbed while drawing. This routine gives the mini-VDD notice that a switch of the MemC state will be occurring and allows it to delay that switch until the drawing engine has completed its work.

Note that many chipsets cannot be interrupted while waiting for source data to be delivered to the BLTer during a memory to screen BLT. In this case, MAKE_HARDWARE_NOT_BUSY will never show the hardware to be not busy if it happens to be called when the display driver is delivering data to the BLTer from system memory. To take care of this situation, the mini-VDD, display driver, and Main VDD must implement VDD_Set_Sleep_Flag_Addr which tells the main VDD to hold-off switching the MemC state of a MS-DOS VM until the display driver has finished delivering source data to the hardware. See VDD_Set_Sleep_Flag_Addr for more details.

See Also

VDD_Set_Sleep_Flag_Addr


MODIFY_REGISTER_STATE (Function 10)

Call With

EBX: Contains the VM handle to modify state for.

CL: Contains 0 if it is desired to access memory at A000h. It contains 1 if it is desired to access flat linear memory.

Return Values

Save anything that you use.

Remarks

This function is obsolete and its use is not recommended.

Certain pieces of display hardware are "modal" and must have some of their extended registers set to certain values depending on whether the application is accessing memory at one of the VGA apertures (such as A000h:xxxx) or if it is accessing memory using a flat linear frame buffer. This routine is called by the Main VDD to explicitly tell the mini-VDD which way to set its extended registers. The recommended method to do this task is to use the functions ACCESS_LINEAR_MEMORY_MODE and ACCESS_VGA_MEMORY_MODE.


POST_CRTC_MODE_CHANGE (Function 29)

The parameters and return values for this function are the same as for PRE_CRTC_MODE_CHANGE. See PRE_CRTC_MODE_CHANGE for details.

See Also

PRE_CRTC_MODE_CHANGE


POST_HIRES_SAVE_RESTORE (Function 40)

Call With

EBX: Contains the VM handle (always the currently executing VM).

EBP: Points to the Windows VM's Client Registers.

Return Values

Save everything that you use. No values or flags need to be returned.

Remarks

This function is very similar to POST_HIRES_TO_VGA in that it allows the mini-VDD to modify port trapping, set flags, etc. after the mode change into the VESA/hi-res mode. The S3 example mini-VDD dispatches this call to the exact same routine as POST_HIRES_TO_VGA.


POST_HIRES_TO_VGA (Function 5)

The parameters and return values for this function are the same as for PRE_HIRES_TO_VGA. See PRE_HIRES_TO_VGA for details.

See Also

PRE_HIRES_TO_VGA


POST_VGA_TO_HIRES (Function 7)

The parameters and return values for this function are the same as for PRE_HIRES_TO_VGA. See PRE_HIRES_TO_VGA for details.

See Also

PRE_HIRES_TO_VGA


PRE_CRTC_MODE_CHANGE (Function 28)

Call With

EBX: Contains a Windows VM Handle.

EBP: Points to the Window VM's Client Registers. Client registers may be used to pass any data between the display driver and the mini-VDD (besides Client EAX and Client EBX which contain the sub-function code for VDD_PRE_CRTC_MODE_CHANGE and VDD_POST_CRTC_MODE_CHANGE and the magic numbers respectively).

Return Values

Anything the display driver and mini-VDD agree upon.

Remarks

The Main VDD calls these routines when the display driver calls the Main VDD VDD_PRE_MODE_CHANGE and VDD_POST_MODE_CHANGE functions. If you look at the example display driver and the S3 or CIRRUS mini-VDD, you can see that these calls are mainly used to setup the monitor refresh rate prior to or after the display driver SetMode routine during Enable. However, these routines can be called for any convenient purpose similar to the REGISTER_DISPLAY_DRIVER function.


PRE_HIRES_SAVE_RESTORE (Function 39)

Call With

EBX: Contains the VM handle (always the currently executing VM).

EBP: Points to the Windows VM's Client Registers.

Return Values

Save everything that you use. No values or flags need to be returned.

Remarks

This call is very similar to PRE_HIRES_TO_VGA in that it allows the mini-VDD to modify port trapping, set flags, etc. in preparation for the mode change into the VESA/hi-res mode. In fact, the S3 example mini-VDD dispatches this call to the exact same routine as PRE_HIRES_TO_VGA.


PRE_HIRES_TO_VGA (Function 4)

Call With

EBX: Contains the handle of the VM that is being switched to.

EBP: May or may not point to the Client registers for the VM in EBX.

Return Values

Save anything that you use.

Remarks

The Main VDD calls the routines PRE_HIRES_TO_VGA, POST_HIRES_TO_VGA, PRE_VGA_TO_HIRES, and POST_VGA_TO_HIRES whenever it changes the video focus between Windows and a full-screen MS-DOS prompt. During PRE_HIRES_TO_VGA or PRE_VGA_TO_HIRES, remove trapping on your device's extended registers or make sure that they are not virtualized (meaning that any register I/O that the VM does during the mode change is actually written to the physical hardware). During POST_HIRES_TO_VGA or POST_VGA_TO_HIRES, reestablish the trapping.

Following are the steps when switching from Windows to a full-screen MS-DOS prompt

  1. The Main VDD responds to a Set_Focus message from the SHELL VxD.
  2. The Main VDD enters the routine that causes the VM to go full-screen. It suspends all VM's and cleans up any "dirty" pages in the VGA virtualization area. That is, it prevents data loss by ensuring that all of the data that a windowed 4 plane VGA application may have written to the off-screen 32K or 64K virtualization area has been delivered to the Grabber.
  3. The Main VDD disables all trapping on the standard VGA ports 3B0h through 3DFh. It also sets the DIB engine's BUSY bit and any Enabled flags that the display driver set with the VDD_SET_USER_FLAGS call. This tells the display driver that it can no longer draw on the hardware.
  4. The Main VDD calls the function PRE_HIRES_TO_VGA in the mini-VDD. The mini-VDD may if it needs to set the screen out of hi-res mode. It should also set flags and/or remove traps on any extended registers that it's trapping.
  5. The Main VDD saves some data from the BIOS data area of the VM that's going to get the video focus, including cursor position, BIOS mode, etc. It also saves off the Interrupt 43h vector which is used by some video BIOS's.
  6. The Main VDD executes an Interrupt 10h, function 0 mode change to enter the mode that the VM is running in. If this is sufficient to get the hardware out of hi-res mode and back to a standard VGA mode, then the mini-VDD need not explicitly set the screen into VGA mode (see step 4).
  7. The Main VDD then restores the BIOS data area of the VM, calls POST_HIRES_TO_VGA, and restores trapping to the proper state for the standard VGA registers.

Following are the steps switching back to Windows from a full-screen MS-DOS prompt

  1. The Main VDD responds to a Set_Focus message from the SHELL VxD.
  2. The Main VDD enters the routine that causes the VM to go back to Windows. It suspends all VM's and cleans up any "dirty" pages in the VGA virtualization area. That is, it prevents data loss by ensuring that all of the video data that a background 4 plane VGA application may have written to the off-screen 32K or 64K virtualization area has been delivered to the Grabber. It also saves all of the visible full-screen video memory at this time.
  3. The Main VDD disables all trapping on the standard VGA ports 3B0h through 3DFh.
  4. The Main VDD calls the mini-VDD function PRE_VGA_TO_HIRES. The mini-VDD should set flags and/or remove traps on any extended registers that it is trapping.
  5. The Main VDD calls the display driver's ResetHiResMode routine which was registered by the display driver during the function VDD_DRIVER_REGISTER. The display driver runs through all the code necessary to reestablish Windows hi-res mode on the hardware. It also restores the palette DAC, hardware cursor, and font cache if any. The display driver is also responsible for clearing the BUSY bit that was set by the Main VDD when going to full-screen mode.
  6. The Main VDD calls the mini-VDD function POST_VGA_TO_HIRES and restores trapping to the proper state for the standard VGA registers.

Note: If the mini-VDD needs to make calls to Exec_Int or Exec_VxD_Int in order to set the hardware from hi-res mode back to VGA mode during a PRE_HIRES_TO_VGA call, it should make sure that EBP points to client registers for the Current VM. The Main VDD does not guarantee this when it calls the mini-VDD. Since all calls to Exec_Int and Exec_VxD_Int happen in the context of the current VM, you must make the call to the function Get_Cur_VM_Handle and then establish EBP to point to the client registers for that VM before making any calls to the BIOS.


PRE_VGA_TO_HIRES (Function 6)

The parameters and return values for this function are the same as for PRE_HIRES_TO_VGA. See PRE_HIRES_TO_VGA for details.

See Also

PRE_HIRES_TO_VGA


REGISTER_DISPLAY_DRIVER (Function 0)

Call With

EBX: Contains the Windows VM handle.

EBP: Contains the Windows VM's Client Registers.

All other registers are via agreement between the display driver and the mini-VDD.

Return Values

Whatever is agreed upon by the display driver and mini-VDD.

Remarks

This function is called in response to a display driver call to the Main VDD function VDD_REGISTER_DISPLAY_DRIVER_INFO.

See Also

VDD_REGISTER_DISPLAY_DRIVER_INFO


RESET_BANK (Function 3)

Call With

EBX: Contains the Windows VM Handle.

EBP: Contains the Windows VM's Client Registers.

Return Values

Save anything that you use.

Remarks

The Main VDD requests that the mini-VDD restore the previous bank so that the Windows display driver will draw in the correct place on the screen. The previous bank should have been saved off by SET_VDD_BANK. Before resetting the bank, make sure that the bank that is currently set into the hardware is still the VDD bank determined when GET_VDD_BANK was called. If it is not, you must not reset the bank since a program (such as the Windows display driver) may have set it to another value without notifying the VDD.


RESET_LATCH_BANK (Function 23)

Call With

EBX: Contains a Windows VM Handle.

EBP: Points to the Windows VM's Client Registers.

Return Values

Save anything that you use.

Remarks

The mini-VDD should restore the bank saved when SET_LATCH_BANK was called. Since manipulation of the latches is a synchronous operation, there is no need to check whether the bank was reset (with RESET_BANK) without the Main VDD being notified.


RESTORE_LATCHES (Function 25)

Call With

EBX: Contains a Windows VM Handle.

EBP: Points to the Windows VM's Client Registers.

Return Values

Save anything that you use. You must not fail this call. If it is hooked, it must be implemented.

Remarks

If you implement SAVE_LATCHES, you must also implement RESTORE_LATCHES. Many chipsets have a method by which the VGA processor latches can be directly saved and/or restored. If your hardware can do this, it increases the performance of your 4 plane VGA virtualization greatly if you implement SAVE_LATCHES and RESTORE_LATCHES.


RESTORE_REGISTERS (Function 9)

Call With

EBX: Is undefined but must be saved over this call.

ESI: Contains the VM handle for the MemC owner VM.

ECX: Contains the VM handle for the CRTC owner VM.

EBP: May or may not be pointing to the VM's client registers.

Return Values

Save anything that you use.

Remarks

The VDD has two special "pseudo-VM's" that are used by the VDD to set special states. The Blue Screen Message Mode pseudo-VM contains the states when Windows encounters a serious problem and displays a blue screen with an error message. This blue-screen message mode is displayed in VGA mode 3 in non-East Asian versions of Windows 95 and in Mode 12h in East Asian DBCS versions of Windows 95. The Forced Planar Mode pseudo-VM is a VM containing the 4 plane MemC state (such as that in Mode 12h). These "pseudo VM" handles are sometimes passed to the mini-VDD during calls to the RESTORE_REGISTERS. The mini-VDD should retrieve and save these special VM handles at MiniVDD_Dynamic_Init time, and then compare them against the handles passed to RESTORE_REGISTERS.

Use caution when restoring the two special VDD pseudo-VM. The VIDEO7.VXD sample mini-VDD contains an example of how these pseudo-VM's have their register states saved at Init_Complete time and how RESTORE_REGISTERS uses the pseudo VM handles to properly restore the state of the blue screen message mode.


SAVE_FORCED_PLANAR_STATE (Function 46)

Call With

EBX: Contains the VM handle (always the Windows VM).

EBP: Points to the Windows VM's Client Registers.

Return Values

Save everything that you use.

Remarks

This routine is similar to SAVE_MESSAGE_MODE_STATE but saves the other "special" VM which is the forced planar state. Immediately before calling this function, the Main VDD will have executed a call to Interrupt 10h to setup Mode 12h. To restore the forced planar state during mode changes, this function copies all of the virtualized states to a special data segment CB data structure. Use this data structure to restore the state whenever you see the VDD's forced planar pseudo-VM handle (this is obtainable via the VDD service VDD_Get_Special_VM_IDs). All registers that are needed to restore for forced planar mode should be trapped at this time. For a description of the pseudo VM handles, see RESTORE_REGISTERS.

See Also

RESTORE_REGISTERS


SAVE_LATCHES (Function 24)

Call With

EBX: Contains a Windows VM Handle.

EBP: Points to the Windows VM's Client Registers.

Return Values

Save anything that you use. You must not fail this call. If it is hooked, it must be implemented.

Remarks

This function gives the mini-VDD the opportunity to save the VGA processor latches. The Main VDD goes through a lengthy process to save and restore the latches during 4 plane virtualization. Many new VGA cards can read the latches directly through CRTC port 22h and this routine gives them the opportunity to do so. If you implement this function (along with RESTORE_LATCHES), you need not implement SET_LATCH_BANK and RESET_LATCH_BANK. You should save the latches in the mini-VDD's CB data area.


SAVE_MESSAGE_MODE_STATE (Function 45)

Call With

EBX: Contains the VM handle (always the Windows VM).

EBP: Points to the Windows VM's Client Registers.

Return Values

Save everything that you use.

Remarks

Before this function is called, the Main VDD has called ENABLE_TRAPS to cause the mini-VDD to turn on its register virtualization code. When ENABLE_TRAPS is called, you should unconditionally virtualize all of the necessary registers and not allow physical writes to occur to them, even in the Windows VM. Subsequently, the Main VDD executes a totally virtualized mode change to the blue-screen message mode state (this is Mode 3 in single byte character set Windows and Mode 12h in double byte character set Windows). Even though no screen changes are evident, because the virtualized mode change occurred when the Windows VM was the currently executing VM, the message mode state for all of the virtualized Registers have been saved in the CB data structure for the Windows VM.

This function copies the virtualized states from the CB data structure and saves them in a special Message Mode state data structure which is located in the mini-VDD's data segment. The Message Mode structure should be an exact copy of the actual CB data structure. See the Video7 mini-VDD for an example of how to use this function.


SAVE_REGISTERS (Function 8)

Call With

EBX: Contains the VM handle to save.

EBP: May or may not be pointing the VM's client registers.

Return Values

Save anything that you use.

Remarks

The mini-VDD should save any register states that it needs to in the CB data area for the VM in EBX. You will have to use empirical data when deciding which extended registers to save, restore and virtualize.


SELECT_PLANE (Function 27)

Call With

EBX: Contains a Windows VM Handle.

EBP: Points to the Windows VM's Client Registers.

DL: Contains the VGA read plane number (0, 1, 2, 3)

DH: Contains the VGA write plane mask (1 for plane 0, 2 for plane 1, 4 for plane 2, and 8 for plane 3).

Return Values

Save anything that you use.

Remarks

This function is called when the Main VDD is asked to restore VRAM for a full screen VM. It allows mini-VDD's operating on non-standard hardware to set the VGA read and write planes.


SET_BANK (Function 34)

Call With

EAX: Contains the read bank to set.

EBX: Contains the VM handle (always the currently executing VM).

EDX: Contains the write bank to set.

EBP: Points to the Windows VM's Client Registers.

Return Values

Save everything that you use. CY returned means that the mini-VDD handled the call. NC returned means that the Main VDD should use a VESA call to set the bank.

Remarks

This call requests the mini-VDD to set the read/write bank passed in EAX/EDX. The mini-VDD simply needs to set the bank into hardware and return CY to the Main VDD.


SET_HIRES_MODE (Function 38)

Call With

EAX: Contains hi-res mode number to set (may be a VESA or non-VESA mode).

EBX: Contains the VM handle (always the currently executing VM).

EBP: Points to the Windows VM's Client Registers.

Return Values

Save everything that you use. CY returned means that the mini-VDD handled the call. NC returned indicates that the mini-VDD did not handle the call.

Remarks

This routine is called by the VESA/hi-res restore routine in the Main VDD when the user switches back to a full screen VESA/hi-res mode VM. If you are only interested in being able to restore VESA standard hi-res modes, then you do not need to implement this function since the Main VDD will call Interrupt 10h Function 4F02h in order to set the VESA mode number. You should only implement this function if you are going to save/restore chipset specific modes that are not VESA modes.

If the mode number passed in EAX is a VESA mode number, you should return NC and let the Main VDD set the mode. If the mode number passed in EAX is a non-VESA hi-res mode that is particular to your card, if possible, this function should not touch VRAM since this could cause page faults and confuse the register state of the mode set. In other words, try not to erase the screen during the mode set if possible.


SET_LATCH_BANK (Function 22)

Call With

EBX: Contains a Windows VM Handle.

EBP: Points to the Windows VM's Client Registers.

Return Values

Save anything that you use.

Remarks

This function is called directly before the Main VDD virtualizes the VGA processor latches when doing 4 plane VGA virtualization in a window. The mini-VDD should save the current bank register state (for later restoration by RESET_LATCH_BANK) and set to the VGA virtualization bank which was determined at GET_VDD_BANK.


SET_VDD_BANK (Function 2)

Call With

EBX: Contains the Windows VM Handle.

EBP: Contains the Windows VM's Client Registers.

Return Values

Save anything that you use.

Remarks

The mini-VDD sets to the bank determined when GET_VDD_BANK was called in preparation for 4 plane virtualization. See the sample mini-VDDs to determine how to save the current bank so that it can be restored at when RESET_BANK is called.


VESA_CALL_POST_PROCESSING (Function 47)

Call With

EBX: Contains the VM handle in which the VESA call was made.

EDX: The low word contains the VESA function code that was just done. The high word contains the VESA mode number if a VESA mode change (function 4F02h) has just occurred.

EBP: Points to the VM's client registers. The client registers contain the return values from the VESA call.

Return Values

Save everything that you use. Nothing is returned to the caller.

Remarks

This function allows a mini-VDD to perform any necessary processing after a VESA call . For example, this function could fix up the hardware that might have been put in an unexpected state by the VESA call, or it could readjust register trapping. The S3 sample mini-VDD has an example of how this hook could be used to by a mini-VDD.


VESA_SUPPORT (Function 41)

Call With

EBX: Contains the VM handle (always the currently executing VM).

EBP: Points to the Windows VM's Client Registers. Client registers contain the VESA call values.

Return Values

Save everything that you use. CY returned means that the mini-VDD completely handled the VESA call and that the VESA.COM or VESA BIOS should not be called. NC returned means that the mini-VDD did not completely handle the call and that the VESA.COM or VESA BIOS should be called. The client registers contain the return values from the VESA call if the mini-VDD handles the call.

Remarks

This routine is the "hook" by which a mini-VDD could implement an entire Ring 0 protected mode VESA support. This is recommended, since it eliminates all of the problems of old VESA.COM programs. It also allows much faster VESA performance since the functions are supported at 32 bit Ring 0.

The mini-VDD's VESA support decides what to do based on values in the Client registers. For example, Client_AX will contain 4Fxx indicating what VESA call the application is doing. Then, the mini-VDD can handle the call, filling in return structures (such as those returned by VESA function 4F00h), etc., and return CY to the Main VDD.

This routine could also be used to setup a VESA call while still letting the Ring 3 VESA BIOS handle the call. The mini-VDD would do what it wants to do, and then return NC indicating that the Main VDD should call the Ring 3 VESA BIOS or VESA.COM program.


VIRTUALIZE_BLTER_IO (Function 44)

Call With

EAX: Contains the value to be written to port (OUT operations only).

EBX: Contains the VM handle for which the I/O is being done.

ECX: Contains the I/O type flags (see VMM.INC for details).

EDX: Contains the port number for which I/O is being done.

EBP: Points to the VM's Client Registers.

Return Values

EAX contains the result of an IN operation. NC indicates that the Main VDD should handle the I/O. All registers should be preserved in this case. CY indicates that the mini-VDD handled the I/O. In this case, only preserve EBX.

Remarks

A mini-VDD can hook this routine if it needs to examine or virtualize I/O to ports which were previously registered with the Main VDD via the VDD_Register_Virtual_Port service. Normally, the Main VDD uses ports registered with this service simply to notify it of when to restore the Windows VM state when running a VGA application in a window. Then, I/O to these ports is always done physically (the I/O request is always done to the hardware). However, in some cases (see S3.VXD for an example), the mini-VDD needs to perform special handling or virtualization of these BLTer ports. By hooking this service, the mini-VDD will have the chance to virtualize the I/O to all ports previously registered by VDD_Register_Virtual_Port. If the mini-VDD has no interest in the port, it simply returns NC. If the mini-VDD handles the port and completes the I/O virtualization, it returns CY causing the Main VDD not to do its normal physical I/O to the port.


VIRTUALIZE_CRTC_IN (Function 16)

Call With

EAX: Contains the value to output to port (on an OUT call).

EBX: Contains the VM handle for which the I/O is being done.

ECX: Contains the I/O flags (documented in VMM.INC).

EDX: Contains the port that the I/O is to be done to or from.

EBP: Points to VM's client registers.

Return Values

CY set indicates that the mini-VDD has done the I/O and that the Main VDD should take no further action. In this case, AL should contain the return value from the IN call and all registers except EBX and EBP may be destroyed.

NC set indicates that the mini-VDD may have taken some action but wants the Main VDD to do the default action. In this case the mini-VDD must not have destroyed ANY registers.

Remarks

Many chipsets tack their extended registers onto the standard VGA ports. These routines allow the mini-VDD to perform special actions on these ports. The VIDEO7 mini-VDD is a good example of virtualizing extensions to the Sequencer ports while the S3 and Cirrus mini-VDD's show how virtualization and notification via the VGA ports are implemented in a mini-VDD. Note that the action taken by the Main VDD is undefined for port indices which are greater than the standard VGA ports (0-18h for CRTC, 0-4 for Sequencer, 0-9 for GCR, and 0-255 for DAC ports).


VIRTUALIZE_CRTC_OUT (Function 17)

The parameters and return values for this function are the same as for VIRTUALIZE_CRTC_IN. See VIRTUALIZE_CRTC_IN for details.

See Also

VIRTUALIZE_CRTC_IN


VIRTUALIZE_DAC_IN (Function 31)

The parameters and return values for this function are the same as for VIRTUALIZE_CRTC_IN. See VIRTUALIZE_CRTC_IN for details.

See Also

VIRTUALIZE_CRTC_IN


VIRTUALIZE_DAC_OUT (Function 30)

The parameters and return values for this function are the same as for VIRTUALIZE_CRTC_IN. See VIRTUALIZE_CRTC_IN for details.

See Also

VIRTUALIZE_CRTC_IN


VIRTUALIZE_GCR_IN (Function 20)

The parameters and return values for this function are the same as for VIRTUALIZE_CRTC_IN. See VIRTUALIZE_CRTC_IN for details.

See Also

VIRTUALIZE_CRTC_IN


VIRTUALIZE_GCR_OUT (Function 21)

The parameters and return values for this function are the same as for VIRTUALIZE_CRTC_IN. See VIRTUALIZE_CRTC_IN for details.

See Also

VIRTUALIZE_CRTC_IN


VIRTUALIZE_SEQUENCER_IN (Function 18)

The parameters and return values for this function are the same as for VIRTUALIZE_CRTC_IN. See VIRTUALIZE_CRTC_IN for details.

See Also

VIRTUALIZE_CRTC_IN


VIRTUALIZE_SEQUENCER_OUT (Function 19)

The parameters and return values for this function are the same as for VIRTUALIZE_CRTC_IN. See VIRTUALIZE_CRTC_IN for details.

See Also

VIRTUALIZE_CRTC_IN


Infrared Communications for Windows 95 Product Description

The PC connectivity world today is mostly wired and the cable type dictates the application. A link over a parallel cable means printing, while a link over a serial cable serves a modem. Right now, a user needs consciously to start a connection over the cable that matches the application. Starting a connection is a hassle that many potential computer users just won't put up with.

Wireless communications are going to play an increasingly important role in computers, particularly for mobile users. As more and more wireless PC connectivity hardware and software become available, applications will provide new connectivity features. Applications will initiate connectivity on an as-needed basis and a user will not even need to know the connection type in order to use it.

Because of its low-cost and simple implementation, the first widely-available wireless connectivity medium for PCs is infrared (IR). The engineering requirements are straight-forward and the component cost is under $5 per device. Computer system and peripheral makers are already integrating infrared devices with computers and printers.


Microsoft Releases IR Products

A Microsoft development team that focuses on mobile computing issues has just released its first products: the Infrared (IR) Communications for Windows 95 device driver, and the IR Communications for Windows 95 device driver kit (DDK), which was developed with Hewlett-Packard. The driver is also part of the DDK.

Software developers can get the IR Communications device driver from the Windows Driver Library (WDL) and can install the driver on computers with IR ports to add IR capability to Windows® 95.

Communicating applications that use serial and parallel cable links can then be tested over the new IR link, which can operate at speeds up to 115.2 kilobits per second (Kbps).

Hardware vendors (IHVs) and computer platform makers (OEMs) can get the Windows 95 IR Communications DDK from the MSDN Development Platform CD or by contacting their Microsoft OEM sales representative. IHVs and OEMs can use the sample IR driver source code as a starting point to build IR drivers that operate with their IR-capable devices. Examples of such IR-capable devices are IR ports built into computer platforms and IR adapters that plug into serial and/or parallel ports built into computer platforms, LAN-access points, remote keyboards, printers, cellular and land-line phones, digital cameras, pagers, home entertainment center equipment, and kitchen appliances.

Based on feedback from computer manufacturers, Microsoft predicts that the majority of new portable PC systems will ship with built-in IR ports which are compatible with Windows 95. For systems without IR ports built-in, Microsoft is working with IHVs that make IR adapters that plug into Windows 95 computer serial ports and provide IR capability.

Companies that have not thought of themselves as makers of computer peripherals, such as manufacturers of kitchen appliances, home entertainment centers, and cameras will likely build IR into their devices and become potential Windows 95 IHVs.

The Infrared Data Association (IrDA) has already developed Infrared communications standards that are accepted by the computer, communications, home entertainment, and semiconductor industries. For a description of the standards, see The IrDA and Its Standards.) As long as the makers of these different devices strive to comply with the IrDA standards, all these different types of IR devices will be able to communicate with each other and with computers running the IR Communications for Windows 95 IR device driver. In the rest of this article, the term IrDA-compliant is used to refer to all these types of IR devices.


Microsoft and IrDA

Microsoft has been an executive member of IrDA since its founding and promotes the IrDA effort to standardize infrared communications protocols across the industry. Microsoft's infrared products are designed to comply with the IrDA specifications. This insures interoperability between IR-capable computers running Windows 95 and all the other devices that support the IrDA specifications.

If you are an independent software vendor (ISV) writing applications for IR-capable computers running Windows 95, IR drivers built with the Windows 95 IR DDK enable you to use standard Win32® communications APIs to transfer data between IrDA-compliant devices. Many existing applications that communicate over serial and/or parallel cables using these APIs will communicate over IrDA-compliant IR links without any reprogramming.

Microsoft's future IR products will also be designed to comply with the evolving IrDA standards which will take advantage of the dynamic, ad-hoc nature of the media and hardware advances (such as fast IR data exchange at speeds up to 4.0 Mbps).


The IrDA and Its Standards

The Infrared Data Association (IrDA) is a group of computer, telecommunications, and semiconductor manufacturers and consumer products companies that have worked together to define the IrDA specification as an industry standard. By implementing the IrDA standard, member and non-member companies can create devices that cooperate with each other to share the IR spectrum in a cooperative fashion. For more information about IrDA, contact

Infrared Data Association
P O Box 3883
Walnut Creek, CA 94598
510-943-6546, Fax 510-943-5600
e-mail irda@netcom.com

For a description of the current IrDA standards, see Current IrDA Standards. For a description of future IrDA standards, see Future IrDA Standards.


Current IrDA Standards

Current IrDA standards are:

  • Serial Infrared (SIR) physical layer specification, which provides for serial infrared links running up to 115.2 Kbps. High speed physical layer specifications have been approved by IrDA that will support link speeds of 1.152 Mbps and 4.0 Mbps.
  • IR Link Access Protocol (IrLAP) provides a reliable point-to-point link, which effectively replaces a three-wire serial cable connection.
  • IR Link Management Protocol (IrLMP) provides for multiple sessions over the single point-to-point link.
  • An Information Access Service (IAS) is also specified through which a device can learn about the services offered by another device.


Future IrDA Standards

IrDA standards currently under development are:

  • IR COMM which provides full emulation of three-wire, nine-wire, null modem, and parallel connections. The emulation sends the state information that is normally maintained by signals on the Carrier Detect (CD), Data Terminal Ready (DTR), Clear To Send (CTS), and other communication control lines.
  • Tiny TP, which provides a tiny transport protocol to provide session-level flow control on a link.
  • Object Exchange, which provides a protocol that transfers generic data objects (such as a business card or an address book entry) between applications running on different machines.


Scenarios with IrDA-Capable Devices

People will be able to use their computers in new ways when IR communications are added to Windows 95 and IrDA-compliant devices abound. For a tale that illustrates some uses of IR communications at work and on business trips, see Work Place and Business Trip Scenarios. For a continuation of the tale that illustrates some uses of IR communications by a family and at home, see Family and Home Scenarios.


Work Place and Business Trip Scenarios

Most workers will have an IR-capable desktop computer and an IR-capable portable computer. The portable is either "docked" to the desktop or carried with the worker as she roams between office buildings and labs.

To prepare for a meeting, the portable owner downloads the departmental project schedule information from a LAN database to the desktop, adds some late-breaking information that is only on her desktop PC, and then squirts a filtered set of schedule information to the portable using the IR link.

When she arrives at the meeting in a nearby building, all the attendees have IR-capable laptops loaded with their department's part of the schedule. During the beginning of the meeting each worker uses the laptop to check schedule facts, take notes, revise the dependencies in their schedules, and squirt schedule facts to each other as needed.

During the break, workers with access to an IR-capable LAN access point, which will be available in most meeting rooms, can use laptops to send and receive e-mail messages relevant to the meeting.

After the break, the attendees collaborate on a new schedule using IR-capable conferencing software on their portables. When a realistic schedule is hammered out, one worker with the agreed-upon schedule on her portable leaves immediately for the airport and flies to a board meeting to present the schedule.

In transit, she uses the laptop to continue exchanging e-mail messages in the airport and hotel using an IR-capable public phone. While in transit, she receives detailed messages about the upcoming board meeting on her IR-capable pager and organizes the messages by squirting them into the IR-capable personal information manager (PIM) application on her laptop.

In a hotel room, she uses the laptop to add the latest schedule information to an electronic slide presentation. In the hotel business service center she uses the IR-capable presentation graphics software to squirt the slide images to an IR-capable laser printer, producing handouts for the meeting.

At the board meeting, she displays the electronic slides to an audience by squirting them one at a time from the laptop to a high-speed IR-capable large screen video projector (some slides have digital video and audio clips that demonstrate the physical processes underlying the schedule dependencies she is presenting).


Family and Home Scenarios

After the board meeting, a business traveler takes her family's IR-capable digital camera and one of the family's IR-capable handheld computers out of her luggage and heads for the sprawling combination super mall/amusement park.

She doesn't have much time so she immediately goes to an IR-capable information kiosk and downloads a user interface onto her handheld through the IR port (she has her choice of languages to have the interface presented in, and chooses English). She uses the interface to navigate symbolically through the acres of attractions and query the information kiosk for squirts of detailed information about some of the attractions.

When she locates an attraction her kids are interested in, she walks there and takes some snapshots. When she gets back to the hotel, she squirts the best of the snapshots from her IR-capable digital camera to the IR-capable laptop. She uses the hotel business center to send an e-mail message home that asks her son to pick her up at the airport, with the digital snapshots as attachments.

While waiting at the airport for his mom's late flight, her son plays another episode of interactive Cyberdoom with a friend. Each has an IR-capable handheld PC.

She then drops the two young men off at the local college campus in time for a lecture. In the lecture hall, they use their handhelds to download the class handouts and the next homework assignment from the professor's IR-capable portable computer. They collaborate on the assignment during the lecture and on the way out squirt the completed assignment back onto the professor's computer.

In the off-campus CyberCafe, they start going over the lecture notes they downloaded and surf the Internet using the cafe's IR access point, looking for information that will invalidate what they have just been told by their professor.

Meanwhile, Mom gets home and joins her daughter in the room with the family's IR-capable entertainment center. Her daughter is using her new IR-capable power glove to draw stick figures and choreograph them dancing to the beat of a commercial rap song and Mom offers a few new twists.

In the meantime, they've forgotten all about getting dinner ready. Luckily, they have a kitchen full of IR-capable appliances and a meal-preparation sequence pre-programmed on one of the family handhelds.


Getting into IR

For scenarios that illustrate work and home use of IR communications with computers, see Work Place and Business Trip Scenarios and Family and Home Scenarios. All of the uses described in these scenarios will become possible. And Microsoft has plans to develop extensions to Windows for other wireless media in addition to IR. Can you imagine other scenarios, especially when other forms of wireless communication, like radio frequency (RF) or cellular data, are integrated with computers?

Here are some basic suggestions for getting started with the low-cost IR media that is available today:

  • Purchase a couple IR-capable devices designed to be IrDA compliant.
  • Start experimenting with the Microsoft IrDA-compliant Windows 95 IR Communications device driver.


Purchasing IR-Capable Devices

Current infrared devices designed to be IrDA-compliant operate over a minimum range of one meter between transmitter and receiver, and within a 30-degree angled cone. The current IrDA specification is optimized for point-to-point links between two or more devices. Keeping the cone angle narrow minimizes problems associated with interference and "hidden transmitters." The first revision of the IrDA specification provides for serial infrared links operating at speeds up to 115.2 Kbps. Several notebook computers already include built-in IR ports with these characteristics. These machines include the

Digital HiNote Ultra CT475; Gateway 2000 Liberty and Gateway Solo; HP Omnibook 600CT and HP Omnibook 4000C; IBM ThinkPad 701C, which is known as the Butterfly; most configurations of the IBM ThinkPad 755; Midwest Micro Elite and Midwest Micro Elite p90; Sharp PC 3050; TI TravelMate 5000; and the Toshiba Satellite Pro 400 CDT.

IR adapters that add IR capability to Windows computers by plugging into a serial port are available for as little as US$35 from numerous peripheral manufacturers. For the names and addresses of the manufacturers of IR adapters that have been tested using the Windows 95 IR communications driver, see IR Adapter Manufacturers.

Printer manufacturers are also supporting IR communications. New printer models such as the Hewlett-Packard Laserjet 5MP feature an IR port in addition to the usual serial and parallel interfaces. These printers can communicate wirelessly with portable PCs and other infrared devices.


Experimenting with the IR Communications Products

Once you have a couple IR devices that are designed to meet the IrDA specifications, you can use the Windows 95 IR communications driver to start exchanging data between applications using the IR devices. To work with the IR Communications driver, applications can use the Windows communications APIs. To learn more about the IR Communications driver, see Windows 95 IR Communications Driver Version 1.0 Release Notes.

IHVs and OEMs can use the sample C-language source code in the Windows 95 IR Communications DDK to develop an IR device driver for new IR-capable devices. The DDK documentation pinpoints the few lines of code you will have to change in the sample IR driver source code to implement your own low-level driver. The IR Communications DDK is available on the MSDN Development Platform CD or from your Microsoft OEM sales representative. To learn more about the IR Communications driver, see Windows 95 Infrared Communications Device Driver Kit (DDK) Release Notes.

Looking ahead, the Windows 95 IR Communications SDK is slated for release around the second quarter of 1996. The SDK will provide a set of APIs and protocols for IR links that go beyond the Win32 communications APIs. These include:

  • IR Sockets APIs, which enable application developers to quickly port existing Windows Sockets applications to use IR links.
  • Object Exchange protocol, which enables developers to transfer small units of information (objects) such as business cards, address book entries, or sales transaction records over IR links and keep the objects on different computers in synchronization with each other.
  • IrLAN protocol, which enables applications to access information on networks of many different protocols and addressing schemes through an IR port.


IR Adapter Manufacturers

The names and addresses of manufacturers of IR adapters that have been successfully tested with the Windows 95 IR communications driver are listed in the following.

ActiSys, Inc.
1507 Fulton Place
Fremont CA 94539
tel: 510-490-8024
fax: 510-623-7268
email: corp@actisys.com

Adaptec, Inc.
691 South Milpitas Blvd,
Milpitas CA 95035
tel: 1-800-959-7274
fax: 1-408-957-7223

AMP Product Information Center
AMP Incorporated
Harrisburg PA 17105
tel: 1-800-522-6752

Extended Systems, Inc.
5777 North Meeker Ave
Boise ID 83704-1520
tel: 208-322-7575
fax: 208-377-1906

The Parallax IR adapter distributor in North America is:
TSC Electronics
1610 Lockness Place
Torrance CA 90501
tel: 310 534 2738
fax: 310 534 3216
email: dtsaitsc@aol.com
contact person: Daniel Tsai

The Parallax IR adapter distributor outside North America is:
Parallax Research
201 Innovation Centre
NTU
Nanyang Drive
Singapore 639798
Republic of Singapore
tel: +65 793 0855
fax: +65 793 0775
email: parallax@technet.sg


Introduction to the Windows 95 Infrared Communications DDK

Infrared communications is an optional component of the Windows® 95 system. It is added to a Windows 95 computer by running a Setup program on a Windows 95 Infrared Communications driver installation diskette. For IR adapters distributed by IHVs, the installation diskette is distributed by the IHV (the IR adapter manufacturer). For IR devices built into computer platforms by OEMs, the OEM typically uses the installation diskette image to install Infrared Communications on the platform in the factory and then distributes the installation diskette with the platform so the end user can remove and reinstall Infrared Communications as needed.

The Windows 95 Infrared (IR) Communications driver is the set of software executable components that manufacturers of IrDA-compatible infrared devices distribute with their devices to run on Windows 95 computers. The driver is available as a separate product and is also included in this IR Communications DDK, in the RETAIL subdirectory of the DDK.

In addition to the executable driver, this IR Communications DDK includes sample source code and build tools that enable an IHV or OEM to create a new version of the IR Communications driver. The sample source code, libraries, and MAKEFILE are in the DDK subdirectory of the DDK.

With this release of IR Communications DDK you can build a driver that supports add-on IR adapters and built-in IR devices running up to 115.2 Kbps. A future release of IR Communications DDK will also support OEMs who build high-speed IR devices into Windows 95 computers. High-speed IR devices run at 1.152 Mbps and 4.0 Mbps.


IR Communications DDK Features

The major features of this DDK are summarized in the following.


Instant Support for Some IR Hardware in Individual VxDs

The following devices are supported by the IR communications driver binaries supplied in this DDK:

  • ACTiSYS ACT-200L Infrared Wireless Interface (ACT200L.VXD)
  • ACTiSYS ACT-220L Infrared Wireless Interface (ACT220L.VXD)
  • Adaptec(tm) AIRport APA-9320 External Infrared Adapter; this adapter is also called the Adaptec AIRport 2000 (ADAPTEC.VXD)
  • Adaptec AIRport 1000 (ADAPTEC.VXD)
  • AMP PhasIR Serial Adapter (CRYSTAL.VXD)
  • Extended Systems JetEye PC Infrared PC Interface, ESI-9680 (ESI.VXD)
  • Parallax IR Adapter LiteLink PRA9500A (PARALLAX.VXD)

For any limitations of the adapters previously listed, see Troubleshooting.

Microsoft has tested the Infrared Communications driver binaries that are in the DDK with the following laptop computers that have built-in IR devices:

  • Digital® HiNote Ultra CT475
  • Gateway® 2000 Liberty
  • Gateway Solo
  • HP® Omnibook™ 600CT
  • HP Omnibook 4000C
  • IBM® ThinkPad® 701C (Butterfly)
  • IBM ThinkPad 755 (most configurations)
  • Midwest Micro Elite
  • Midwest Micro Elite p90
  • Sharp® PC 3050
  • TI® TravelMate™ 5000
  • Toshiba® Satellite Pro 400 CDT

For any limitations of the laptop computers previously listed, see Troubleshooting.

The IR communications driver binaries have also been tested with the IrDA-compatible HP 5P printer.


OEM-Provided Support for Other IR Devices Built as a Dynamically-Loaded VxD

A VxD must be provided to support IR devices other than the devices previously listed. Sample source code for an OEM-provided VxD that supports the ACTiSYS ACT200L Infrared Wireless Interface is in the DDK, in the file OEMDONGL.C. OEMs and IHVs can adapt this code to their device. Also, a wrapper that IHVs and OEMs can link to their OEMDONGL.C module is provided that will make the OEM-provided part of the IrFramer an independent dynamic-load VxD. This will allow the driver for the IR adapter to be dynamically loaded and unloaded.

The IR Communications core architecture, and the place of the optional OEM-provided part of the serial IrFramer component in it, are shown in the following illustration.

  • Infrared Monitor (IrMon) implements the user interface for IR. Using IrMon, the user can see what devices are in range, determine the link quality, and enable or disable the IR communication features.
  • IrEnum is used during discovery to enumerate all visible devices on the "IR bus," thus providing Plug and Play support.
  • IrComm simulates three-wire and nine-wire serial connections and parallel port connections of the IR media. By simulating the status connections available in a standard nine-wire RS-232 connection, software can operate as if IR is a 100% compatible serial cable.
  • IrLMP provides for multiple sessions over the single link provided by IrLAP.
  • IrLAP implements a reliable link (single session) between two IrDA devices.
  • IrFramer provides for packetization and control of IR adapters.


Infrared is a Part of Windows 95 Plug and Play

An Infrared device class has been added to the set of Windows 95 Plug and Play classes and IrEnum has been extended to be the enumerator for the "Infrared bus" on a Windows 95 machine. If your device provides a way for Windows 95 to retrieve a Plug and Play ID for the device, then your version of the Windows 95 Infrared Communications software will be Plug and Play-enabled.


IR Communications Driver Install and Uninstall is Simple

Setup minimizes the number of questions that must be answered during the installation process to the minimum. The goal is to make IR installation as simple as possible. Please be sure to set up from a floppy, local drive or mapped network drive. Setup does not currently support UNC path names for the source of installation.

The Uninstall feature of Setup enables you to remove an installed version of the IR Communications driver by using the Add/Remove Programs icon in the Windows 95 Control Panel, rather than manually deleting files and registry keys.


Product Support is Available from Microsoft

Sites that have a support contract with Microsoft, such as a Premier, Priority or MSDN Level II support contract, should call their regular Product Support number and ask for PS DDK support for OEMs and IHVs.


IR Communications DDK Contents

The Infrared Communications for Windows 95 Device Driver Kit (DDK) includes the following:

  • Documentation
    • README.TXT, which gives a quick overview of the contents of the IR Communications DDK and how the DDK can be used.
    • PRODUCT.DOC, which describes Microsoft's current and future infrared communications products for Windows 9x.
    • DDKRELNO.DOC (this documentation), which contains instructions on how to use the IR Communications DDK to customize the IR communications device driver.
    • DRVRELNO.DOC, which contains instructions on how to install the IR communications device driver that is part of the DDK, and how to test the driver installation.
  • Software on diskette
    • A complete set of Windows 95 IR communications driver binary files. For a list of the infrared devices supported by these binary files, see Instant Support for Some IR Hardware in Individual VxDs.
    • Windows 95 IR communications Setup program and the device information files (INF files) used by the setup program.
    • A set of on-line Help files for the Infrared Monitor (IrMon) application that is bundled with the IR communications driver.
    • Sample source code for the OEM-provided part of the serial IrFramer. This is the source code for ACT200L.VXD, which is shipped with the DDK to support the OEM-provided part of IrFramer for ACTiSYS ACT-220L Infrared Wireless Interface infrared dongles.
  • Other Required Software Components Not Included in This DDK
    • Microsoft Windows 95
    • Microsoft Windows 95 Device Driver Kit (DDK)
    • Microsoft Win32 Software Development Kit (SDK)
    • Microsoft Visual C, version 1.5x (for 16-bit development), Microsoft Visual C, version 2.x (for 32-bit development), and Microsoft Assembler, version 6.11c.

The Microsoft Windows 95 DDK provides header files for the creation of IR Communications for Windows 95. The Windows 95 DDK is available from MSDN.

The files necessary to build applications that use Infrared Communications for Windows 95, such as include files, are in the Win32 SDK. The Microsoft Win32 SDK is available from MSDN. For information on how to obtain a copy of the latest MSDN CD-ROM, contact:

  • Microsoft Developer Network
  • One Microsoft Way
  • Redmond, WA 98052-6399
  • Fax: (425) 936-7329, Attn: Developer Network
  • Internet: devnetwrk@microsoft.com
  • Compuserve: Microsoft Developer Network forum (GO MSDNLIB)

The Microsoft Windows 95 retail release disks are required to test any OEM modifications made to the Infrared communications driver. You may obtain Windows 95 disk images for testing purposes only, which in no way constitutes a license to distribute Windows 95. A license agreement with Microsoft is required to ship Windows 95, or any components of Windows 95. Contact your OEM Account Manager for more information regarding this point if you are unsure as to the scope and nature of your Windows 95 license agreement with Microsoft.


Two Different Ways of Using the IR Communications DDK

You can use the files in the DDK tree structure in two ways:

  • You can use the DDK to simply install the IR Communications driver and start running IR-capable applications. OEMs or IHVs that want to test their device for compatibility with one of the IR devices listed in Instant Support for Some IR Hardware in Individual VxDs may use the DDK in this way. Complete instructions for using the DDK in this way are in the DDK documentation file DRVRELNO.DOC, which is in the RETAIL subdirectory of the DDK.
  • IHVs and OEMs with IR devices that are not listed in Instant Support for Some IR Hardware in Individual VxDs, or OEMs and IHVs who are listed but want to build a new version of their IR communications driver, can use the DDK to build a new dynamically-loadable VxD that will enable their device to run with the IR Communications driver. Such IHVs and OEMs can also use the DDK to build IR Communications driver installation diskettes they can distribute with their IR devices.

The rest of these DDK Release Notes documentation is structured as a road map. A road map is a sequence of steps you carry out to accomplish your goals with the DDK.


Road Map for Building an IR Communications Driver

The Infrared Communications for Windows 95 installation disk image is distributed in two ways by OEMs:

  • OEMs who produce add-on IR devices such as IR dongles for computers running Windows 95 will distribute the installation disk with their IR dongle. End users who purchase the IR dongle for a computer running Windows 95 use the installation diskette to add the IR Communications software when they install the IR dongle.
  • OEMs who produce Windows 95 systems with built-in IR devices use the installation diskette to create a reference system for adding IR Communications for Windows 95 in the factory. In this case, the installation disk image will be used to create an IR Communications installation diskette to ship with the systems in case reinstallation is ever necessary.

The following steps are required to adapt Windows 95 Infrared Communications to your hardware

  1. Install the Windows 95 Infrared Communications DDK; see Step 1. Installing the Infrared Communications DDK.
  2. Adapt the sample source code in OEMDONGL.C, which is part of the IrFramer, to your hardware; see Step 2. Adapting the OEMDONGL.C Source Code.
  3. Build a version of OEMDONGL.VXD, the OEM-provided part of the IrFramer, that is adapted to your infrared hardware; Step 3. Building Your Version of OEMDONGL.VXD.
  4. Create an Infrared Communications for Windows 95 installation diskette; see Step 4. Creating an Installation Diskette and Installing the IR Communications Software.
  5. Install IR Communications on two Windows 95 computers that have your dongles attached and then experiment with your hardware, using different transmission speeds and framer capability settings. See Step 5. Using the IR Communications Software to Experiment with Your IR Device.


Step 1. Installing the Infrared Communications DDK

Once you use the MS-DOS XCOPY command to copy the IR Communication DDK tree to your hard disk, your hard disk contains all the files you need to develop an OEM-provided IrFramer VxD and build a Windows 95 IR Communications installation diskette that includes your VxD. Use the files in the subdirectory named DDK to build the VxD for your infrared device.

The files you need to put on a Windows 95 IR Communications installation diskette along with your VxD are in the DDK RETAIL subdirectory. The files in the RETAIL subdirectory are described in the DDK documentation file DRVRELNO.DOC.

The contents of the DDK subdirectory is shown in the following:

%IRDDKROOT%
  |
  |
  |----\DDK
          |--CVXDCTRL.ASM    // Sample VxD stub
          |--DONGLE.LIB      //
          |--IRDA.H          // Contains definitions used by the
          |                  // IRDA modules
          |--IRLAMP.INC      // Definitions for the IrLAMP VxD
          |--MAKEFILE        // Sample OEM MAKEFILE, will have to be
          |                  // adapted to the IHV's
          |                  // or OEM's development environment
          |--OEMDONGL.C      // Sample OEM dongle driver
          |--PORT.H          //
          |--PRINTF.INC      //
          |--_DONGLE.H       // Contains definitions for supporting
                             // dongles in the IrLAP framer.

The DDK subdirectory also contains the documentation file DDKRELNO.DOC (this file).


Step 2. Adapting the OEMDONGL.C Source Code

The DDK supplied with the DDK has VxD support for the following IR devices:

  • ACTiSYS ACT-200L Infrared Wireless Interface (ACT200L.VXD)
  • ACTiSYS ACT-220L Infrared Wireless Interface (ACT220L.VXD)
  • Adaptec(tm) AIRport APA-9320 External Infrared Adapter; this adapter is also called the Adaptec AIRport 2000 (ADAPTEC.VXD)
  • Adaptec AIRport 1000 (ADAPTEC.VXD)
  • AMP PhasIR Serial Adapter (CRYSTAL.VXD)
  • Extended Systems JetEye PC Infrared PC Interface, ESI-9680 (ESI.VXD)
  • Parallax IR Adapter LiteLink PRA9500A (PARALLAX.VXD)

If your IR device is not one previously listed or is not compatible with one of those devices, then you must modify the OEMDONGL.C source code to support your device and create a new VxD. In order to produce a VxD that works with the generic serial IrFramer to support your device, adapt the OEMDONGL.C sample source code to your dongle hardware, compile it, and link it to DONGLE.LIB and CVXDCTRL.ASM.


Establishing the Microsoft Infrared Communications for Windows 95 Build Environment

The first step in creating your own IrFramer is to establish a build environment. In order to build binary files that are comparable with the current shipping versions, you will need to use the same tools that were used to build the shipping versions. The build environment includes a C Compiler, Assembler, Linker, include files and libraries - all of the tools necessary to build executable modules from the sample source code provided in this DDK.

If you install both the Win32 SDK and Windows 95 DDK on your development system, then you will have all the header files and libraries you need. You also have to install a set of compilers and an assembler.

Follow this sequence of steps in establishing your build environment

  1. Install the compilers and assembler. The following are all necessary: Microsoft Visual C, version 2.x (for 32-bit development), Microsoft Visual C, version 1.5x (for 16-bit development), and Microsoft Assembler, version 6.11c.
  2. Next, install the Win32 SDK.
  3. Lastly, install the Windows 95 DDK.


Introducing the Sample Source Code

The sample source code for your VxD is in the DDK subdirectory. The source code modules in the DDK subdirectory that you must modify are described in the following table:

File | Description | Comment
OEMDONGL.C Contains the OEMDongleTable which is an array of DONGLE_TYPE structures that list the supported dongles and their support functions.

Contains the OEMDongleTableLen variable that specifies the number of dongles that support is being added for.

Contains the functions to support initializing the dongle, setting the dongle's speed (from 2400 baud to 115,200 baud), and turning off the dongle.

The functions currently in OEMDONGL.C are for the ACTiSYS 200L dongle, except the content of the OEMDongleTable array and the names of the type_Init, type_SetSpeed, and type_Deinit functions have been changed to highlight the parts of the code you must change. Note that the name of the OEMDongleTable array and the OEMDongleTableLen variable must not be changed. More details about this are given in the following.
CVXDCTRL.ASM | Wrapper that can be linked with OEMDONGL.C to produce a dynamically loadable VxD. | The sample CVXDCTRL.ASM source code is for the ACTiSYS 200L dongle. You will have to edit this code to establish the name of your VxD.


Editing the OEMDongleTable Array and Registry

To add a dongle type that can be used by the framer, add the dongle type's identifying string and pointers to its type_Init, type_SetSpeed, and type_Deinit functions to the OEMdongleTable array. The sample source code that defines the array in OEMDONGLE.C looks like this:

    DONGLE_TYPE OEMDongleTable[] =
    {
        {"OEM", OEM_Init, OEM_SetSpeed, OEM_Deinit }
    };

    U32 OEMDongleTableLen = (sizeof(OEMDongleTable)/sizeof(DONGLE_TYPE));

The DONGLE_TYPE structure is defined in _DONGLE.H:

    // Data structure used to hold Dongle information
    typedef struct _DONGLE_TYPE
    {
        char*                  typeName; // Name of dongle in the registry
        IRLAPFRM_DONGLE_INIT   init;     // Pointer to init function
        IRLAPFRM_DONGLE_SET    set;      // Pointer to setSpeed function
        IRLAPFRM_DONGLE_DEINIT deinit;   // Pointer to deinit function
    } DONGLE_TYPE, *PDONGLE_TYPE;

So, for example, if your IR dongle device model is named the REDEYE-88 you could edit the OEMDongleTable array in OEMDONGLE.C to look like this:

    DONGLE_TYPE OEMDongleTable[] =
    {
      {"RED88", RED88_Init, RED88_SetSpeed, RED88_Deinit}
    };

You also have to write the name of your dongle type into the registry. The framer gets the names of the dongle types installed on a Windows 95 computer by reading the registry. To add your own dongle type name to the registry during development, you will have to adapt the INFRARED.INF file shipped with the DDK or use the Regedit utility. Continuing with the example, your dongle type name is "RED88." At the registry path HKEY_LOCAL_MACHINE\Enum\Infrared\Framer add the following key and value:

DongleType="RED88"

You must also add the name of your VxD to the registry. For example, if the name of your VxD is RED88.VXD, then at the registry path HKEY_LOCAL_MACHINE\Enum\Infrared\Framer you must add the following key and value:

SpeedDriver="RED88.VXD"

For information on editing the INFRARED.INF file to accomplish these changes to the registry when your VxD is installed using Setup, see Creating an Installation Diskette and Installing the IR Communications Software.


Adapting the Interface Exposed to the IrFramer

The interface that a specific dongle-type source code module exposes to the generic IrFramer (through the function pointer table in OEMDONGLE.C) can have three functions:

Function | Description
type_Init | Initializes your IR hardware and returns the capabilities mask.
type_SetSpeed | Sets the send and receive speed of your IR hardware and sets VCOMM to handle that speed.
type_Deinit | Powers down or deinitializes your IR hardware.

Using the Available Support Functions

A number of functions are available to the OEMDONGL.C module. You have the option of using the VCOMM functions directly and/or indirectly through the functions listed in the following. It is strongly recommended that you not use the VCOMM functions directly for two-way communication with the dongle. Use the provided functions wherever applicable. The function prototypes are in _DONGLE.H and are shown in the following:

//************************************************************************
//
// Function prototypes of utility functions that should be used by
// dongle functions.

// IrLapFrmSetSpeed will set the speed of the UART to the given speed
// using VCOMM calls.

BOOL IrLapFrmSetSpeed(U32 hCom, LM_BAUD_RATE speed);

// IrLapFrmReadChar is used to read a character from the UART using VCOMM calls
// It assumes that events are turned off so it polls. If no character is read in
// in 12 ms it will return FALSE. If a VCOMM error occurs it will return false.
// If it returns TRUE the character read is placed in the variable pointed to by
// c.

BOOL IrLapFrmReadChar(U32 hCom, PU8 c);

// IrLapFrmWriteChar is used to write a character to the UART using VCOMM calls.
// It returns TRUE if successful otherwise it returns FALSE.

BOOL IrLapFrmWriteChar(U32 hCom, U8 c);

// VMM_GetSystemTime returns the number of milliseconds since Windows started. It is
// accurate to 1ms. This is the standard VMM call.

UINT VMM_GetSystemTime( VOID );

Adapting the type_Init Function

The type_Init function is called by the framer to initialize your IR hardware and to get the dongle capabilities masks. When type_Init is called, the hCom (VCOMM handle) will be set for 9600 baud, 8 data bits, no parity, and 1 stop bit. When type_Init returns, the dongle must be active and ready to receive and send data and the VCOMM handle must be set to 9600 baud, 8 data bits, no parity, and 1 stop bit.

If the dongle cannot be initialized type_Init must return IRDA_STATUS_FAILED.

The syntax of the function call is:

BOOL type_Init(
                   U32 hCom,
                   PDONGLE_CAPABILITIES cap
    )

type_Init assumes

  • The hCom parameter identifies a port that has been opened and is set to 9600 baud, 8 data bits, no parity, and 1 stop bit.
  • The framer has set no VCOMM event callbacks on the port so type_Init can send and receive characters without interference from the framer.

The cap parameter points to the DONGLE_CAPABILITIES structure that type_Init returns to the framer; type_Init can, as an option, set bits in the masks that make up this structure to register Baud Rate, Minimum Turn Around Time, and Number of BOFs capabilities with the framer.

The DONGLE_CAPABILITIES structure is defined in _DONGLE.H and is shown in the following:

// DONGLE_CAPABILITIES - is a structure that contains the IrDA
    // capabilities a dongle can effect. The order of the elements in
    // this structure must be the same as those in the IRLAPFRM_CAPABILITIES
    // structure.

    typedef struct
    {
      U32 supportedSpeeds;    // Supported speeds of the dongle
      U32 minTurnAroundTime;  // Min turn around time on the dongle
      U32 additionalBOFs;     // Additional BOFs required by the dongle.
    } DONGLE_CAPABILITIES, *PDONGLE_CAPABILITES;

The meaning of the pattern of bit settings in the three capabilities bit masks is defined fully in Infrared Data Association Serial Infrared Link Access Protocol (IrLAP), but summary tables are presented here.

Baud Rate

The bit settings in the baud rate mask indicate the speed(s) at which the IR device can transmit over the data link:

bit 0 = | 2400 bps (LSB, transmitted first)
bit 1 = | 9600 bps
bit 2 = | 19200 bps
bit 3 = | 38400 bps
bit 4 = | 57600 bps
bit 5 = | 115200 bps
bit 6 = | reserved and must be set to 0
bit 7 = | reserved and must be set to 0

Minimum Turn Around Time

Minimum turn around time is the time delay required by the IR device from the time it receives the last byte from one device until it is ready to receive the first byte from another device.

bit 0 = | 10 ms (LSB, transmitted first)
bit 1 = | 5 ms
bit 2 = | 1 ms
bit 3 = | 0.5 ms
bit 4 = | 0.1 ms
bit 5 = | 0.05 ms
bit 6 = | 0.01 ms
bit 7 = | 0.005 ms

Number of BOFs

These bit settings indicate the number of additional flags needed at the beginning of every frame to provide a delay at the beginning of each frame for devices with long interrupt latency. The bit settings in this mask depend on the baud rate. See Infrared Data Association Serial Infrared Link Access Protocol (IrLAP) for all the different possible values.

The following shows an example of adapting the OEMDONGLE.C sample source code function OEM_Init. The supportedSpeeds mask is set to support all speeds between 9600 baud and 115.2 baud and is set for a 1 ms turnaround, using the following code:

#define  CRYSTAL_SPEEDMASK  0x3F     /*supported speeds 115.2Kbps->9600 Kbps*/
        #define  CRYSTAL_MINTURN    0x00     /*0 turn around*/
         .
         .
         .
    //*********************************************************************
    BOOL OEM_Init(U32 hCom, PDONGLE_CAPABILITIES cap)
    {
          .
          .
               .

        cap->supportedSpeeds &= CRYSTAL_SPEEDMASK;
          .
               .
               .
    }

Suppose your RED88 dongle only supports 9600, 19200, and 115200 baud. You can change the supportedSpeeds mask to reflect that by changing two lines of the sample code:

    #define RED88_SPEEDMASK      0x00000026
        .
          .
               .

        cap->supportedSpeeds &= RED88_SPEEDMASK;
          .
               .
               .

Adapting the type_SetSpeed Function

The type_SetSpeed function is called by the framer IRLAPFRM_SetSpeed function to set the send and receive speed of your IR hardware. type_SetSpeed must also set VCOMM to handle the new speed because IRLAPFRM_SetSpeed does not do that.

The syntax of the type_SetSpeed function call is:

BOOL type_SetSpeed(
                      U32 hCom,
                      LM_BAUD_RATE speed
   )

type_SetSpeed can send and receive characters with no interference from the IR framer because IRLAPFRM_SetSpeed disables VCOMM event callbacks before it calls type_SetSpeed.

type_SetSpeed can also assume that the framer will not reset the VCOMM speed setting. Therefore, when type_SetSpeed is called, the VCOMM speed setting is either the same as the last time type_SetSpeed set it, or 9600 baud immediately after a call to type_Init.

When type_SetSpeed returns, the framer assumes it can start sending or receiving data at the new speed and restores the VCOMM event callbacks. If it fails to set the IR device speed or the VCOMM speed setting, type_SetSpeed must return IRDA_STATUS_FAILED.

It is not particularly useful to make up an example here for the hypothetical RED88 dongle device. The convention that notifies each particular dongle device of a speed change differs from device to device. Two things to notice about the sample code, however, are:

  • The IrLapFrmSetSpeed function in OEMDONGLE.C can be called from your type_SetSpeed function to set the UART to a new speed.
  • VCOMM_EscapeCommFunction is used to set the dongle hardware into and out of command mode (see the ACT200LSetCommandMode and ACT200LClearCommandMode functions in OEMDONGL.C). Using the VCOMM functions is quite acceptable in this case.

Adapting the type_Deinit Function

The type_Deinit function is called to power down or otherwise deactivate your hardware. It is called by the framer just before it calls VCOMM_CloseComm to close the port.

The type_Deinit function can send and receive characters with no interference from the IR framer because VCOMM event callbacks are disabled before the call to the dongle function.

The syntax of the type_Deinit function call is:

BOOL type_Deinit(
                      U32 hCom
     )

The OEM_Deinit function in OEMDONGL.C (which uses the Crystal chip in the ACTiSYS 200L as an IR device) does the following:

  • Resets the IR device.
  • Sets the speed to 9600 baud (the discovery speed).
  • Puts the IR chip in low-power mode.
  • Makes sure the IR device is not in command mode.


Step 3. Building Your Version of OEMDONGL.VXD

When you are comfortable with the changes you have made to the OEMDONGL.C source code, it is time to build your version of OEMDONGL.VXD. A MAKEFILE in the DDK subdirectory contains all the directives the compiler, assembler, and linker need to create OEMDONGL.VXD. Before you run the MAKEFILE, you have to match it to your the build environment by carrying out the steps in the following.


A. Editing the MAKEFILE

First, check the lines in the MAKEFILE that define the build environment to make sure the variable settings match your build environment. The lines of the MAKEFILE you must check are right at the beginning of the MAKEFILE and are shown in the following:

#Change the following variables for your environment
####################################################
CC=..\..\..\..\dev\tools\c932\bin\cl.exe
LINK=..\..\..\..\dev\tools\c932\bin\link.exe
MASM=..\..\..\..\dev\tools\masm611c\mlx
DDKLIB=..\..\..\..\dev\ddk\lib
DDKINCLUDE=..\..\..\..\dev\ddk\inc
H2INC=..\..\..\..\dev\tools\common\h2inc.exe
MAPSYM=..\..\..\..\..\dev\tools\common\mapsym

You may have to edit one or more of these seven lines in order to match the paths in your build environment.


B. Renaming the VxD by Editing the MAKEFILE and CVXDCTRL.ASM

You may also want to edit the MAKEFILE in order to name your VxD something other than OEMDONGL.VXD. Using the REDEYE-88 project as an example again, you would replace all the instances of the case-insensitive string "OEMDONGL" in the MAKEFILE with "RED88" if you wanted the VxD executable file to be named RED88.VXD.

If you edit the MAKEFILE to name the VxD the MAKEFILE produces to something other than OEMDONGL.VXD, then you must also edit the VxD wrapper source code in CVXDCTRL.ASM to reflect that name change. Using the REDEYE-88 example again, you would replace all instances of the case-insensitive string "OEMDONGL" in CVXDCTRL.ASM with "RED88."


C. Running the MAKEFILE

When you are sure the MAKEFILE matches your build environment and the VxD will have the name you want, you can build your VxD. To build a retail version of your VxD, change the current directory to the DDK subdirectory and then enter the command

nmake retail

To build a debug version of your VxD, change the current directory to the DDK subdirectory and then enter the command

    nmake debug

You can also build a debug version by simply using the command

    nmake

To build both a retail and debug version, use the command

    nmake all


D. Testing Your VxD

Creating an installation diskette that includes your VxD is described in Creating an Installation Diskette and Installing the IR Communications Software.

After you complete this step, you can use the installation diskette to install IR Communications for Windows 95 on one or more Windows 95 computers and try it out.


Step 4. Creating an Installation Diskette and Installing the IR Communications Software

When you reach this step of the roadmap, step 4, all the files you need to copy to a Windows 95 installation diskette for your device are in the RETAIL subdirectory on your development system hard disk. If you complete steps 2 and 3 of the Road Map procedure, the installation diskette you create in this step will contain your OEM-provided part of the serial IrFramer that supports your infrared device(s).


A. Copying Files to Your Installation Diskette

To create an installation diskette, do the following

  1. Format a 3.5" 1.44 Mb diskette, giving it the volume label "SIR Install."
  2. Copy all the files from %IRDDKROOT%\BIN into the root directory of the installation diskette.
  3. Copy your VxD into the root directory of the installation diskette.


B. Editing the INFRARED.INF File

Windows 95 Setup gets directives from INFRARED.INF for:

  • Installing a particular device (or devices) from a particular manufacturer.
  • Copying files from your installation diskette to the appropriate directories on the Windows 95 computer hard disk.
  • Displaying information about the device being installed and the manufacturer of that device in the Setup UI during the installation process.
  • Adding keys and values to the Windows 95 registry that describe the IrFramer for your device.

The INFRARED.INF file that is shipped in the DDK has instructions for doing these things for all the IR devices supported by the DDK. The manufacturers and infrared device models supported by the INFRARED.INF file supplied with the DDK are reflected in the [Strings] section of the INF file:

 [Strings]
String1="(Standard infrared devices)"
String2="Extended Systems"
String3="Adaptec"
String4="Texas Instruments"
String5="ACTiSYS"
String6="Built-in Infrared port on laptop or desktop"
  .
  .
  .
String9="JetEye PC Infrared PC Interface (ESI-9680)"
String10="AIRport APA-9320 External Infrared Adapter"
String11="TI TravelMate 5000 Laptop"
String12="ACT-IR200L Infrared Wireless Interface"
String13="ACT-IR220L Infrared Wireless Interface"
String14="Parallax"
String15="LiteLink PRA9500A"
String16="AMP"
String17="PHASIR"
String18="Adaptec AIRport 1000"

If you are a completely different manufacturer (for example, you are working for the Redeye Corporation on the REDEYE-88 IR adapter product), you will have to add information about your company and product in the INFRARED.INF file on the installation diskette for your product. Use the INFEDIT.EXE tool in the Windows 95 DDK to edit the INF file. Use the parts of the INFRARED.INF file that install the ACT_IR200L device as examples and add a similar set of information for your dongle.

For developers who are not familiar with using the INFEDIT.EXE tool, a detailed set of instructions follows for using Infedit to add an example IR device, the REDEYE-88, to INFRARED.INF.

The INFEDIT.EXE user interface shows the different parts of INFRARED.INF as folders (containers) on the left side of the screen. When you open a folder by double-clicking on it, the contents of the folder appear on the right side of the screen. The contents of a folder are one or more named items, each with a value (which may be null).

Adding a New Manufacturer

To add a new manufacturer

  1. Right-click on the Manufacturer folder and select the New Manufacturer option from the popup menu.
  2. When a folder labeled New Manufacturer appears, double-click on it to see its contents.
  3. Double-click on the item Company Name and (for this example) enter "Redeye Corporation" (without the quotes) in the Edit String dialog box.

Adding a New Device

To add a new device

  1. Right-click on the Manufacturer\Redeye Corporation folder and select the New Device option from the popup menu.
  2. When a subfolder labeled <Device Description> is displayed under the Redeye Corporation folder, double-click on it to edit its contents.
  3. Double-click on Device Description and enter the value "Redeye-88 Infrared Adapter" (or whatever the advertised name of your device is).
  4. Double-click on Install Section and enter "Redeye_Install" (or any other self-documenting Install section name).
  5. Double-click on Hardware ID and enter "Infrared\Redeye."

Adding a Copy Files Section for the New Device

You need to add a section to INFRARED.INF that copies both the generic serial IrFramer, IRLAPFRM.VXD, and the device-dependent VxD you created from the installation diskette to the \%WINDOWS%\SYSTEM subdirectory on the Windows 95 computer hard disk.

To add a Copy Files section for the new device

  1. Right-click on the Copy Files folder and select the New Copy Files Section option from the pop-up menu.
  2. When a subfolder labeled NewFileSection is displayed in the following the Copy Files folder, double-click on it to edit the contents.
  3. Double-click on Section Name and enter the value "Redeye_Framer." You do not have to change the Destination Directory value since the default destination directory for INFRARED.INF is the \%WINDOWS%\SYSTEM directory.
  4. Right-click on the subfolder that is now labeled Redeye_Framer and select the Add Filename option from the popup menu.
  5. Double-click on the item label File Name and in the Destination Name field of the edit dialog enter the filename of the generic serial IrFramer, IRLAPFRM.VXD.
  6. Right-click again on the subfolder labeled Redeye_Framer and select the Add Filename option.
  7. Double click on the item label File Name and in the Destination Name field of the edit dialog enter the filename the VxD you created in earlier steps of this Road Map. In this example, that is RED88.VXD.

Adding an Add Registry Section for the New Device

You need to add a section for INFRARED.INF that writes the named of the generic serial IrFramer VxD, the name of your device-specific VxD, and the name that identifies your device to the Registry. You can use the contents of the existing ACTiSYS-IR200L_AddReg folder in INFRARED.INF as a model.

To add an Add Registry section for the new device

  1. Right-click on the Add Registry Sections folder and select the New Add Registry Section option from the pop-up menu.
  2. When a subfolder labeled <Section Name> is displayed in the following the Add Registry Sections folder, double-click on it so you can edit the contents.
  3. Double-click on Section Name and enter the value "Redeye_AddReg."
  4. Right-click on the folder that is now labeled Redeye_AddReg and select the Add Section Value option from the popup menu.
  5. When a new subfolder labeled Item0 is displayed under the Redeye_AddReg folder, double-click on it to edit its contents to add a registry entry for the generic serial IrFramer.
  6. Double-click on the RegistryRoot item label and enter the value "HKLM" (without the quotes).
  7. Double-click on the Subkey item label and enter the value "\Enum\Infrared\Framer" (without the quotes).
  8. Double-click on the Value Name item label and enter the value "Driver" (without the quotes).
  9. Double-click on the Value item label and enter the value "IRLAPFRM.VXD" (without the quotes).

Repeat steps 4 through 9, except this time the new subfolder will be labeled Item1. Set the RegistryRoot and Subkey items to the same values as for Item0. Set the Value Name item value to "DongleType" and the Value to "RED88."

Repeat steps 4 through 9 again, except this time the new subfolder will be labeled Item2. Set the RegistryRoot and Subkey items to the same values as for Item0 and Item1. Set the Value Name item value to "SpeedDriver" and the Value to the name of the VxD you created (in this example, RED88.VXD).

Adding an Install Section for Your Device

An INF file Install section names all the other sections in the INF file that Windows 95 Setup is to run to do a complete installation of your device. You can use the existing folder ACTiSYS-IR200L_Install as a model for your new Install folder.

Your Install section has to name two Copy Files sections and two Add Registry sections. One Copy Files section copies the two Framer files (you created this section in an earlier step and in this example named the section Redeye_Framer). The other Copy Files section copies all the IR Communications for Windows 95 component files except the two Framer files off the Installation diskette; that section already exists in INFRARED.INF and is named Driver_Copy.

Your Install section also has to name the Add Registry section you just created, which in this example is named Redeye_AddReg, and the Add Registry section that registers all the other IR Communications for Windows 95 components (this folder already exists in INFRARED.INF and is named IRCOMMON_AddReg.

To add the Install section for your device, do the following in the INFEDIT.EXE interface

  1. Right-click on the folder labeled Install Sections and select the New Install Section option from the popup.
  2. When a new subfolder labeled NewInstallSection is displayed under the Install Sections folder, click on it to edit its contents.
  3. Double-click on the item labeled Copy File Sections. A dialog box displays the names of all the Copy Files sections in INFRARED.INF. Select Driver_Copy and add it to the list on the right of the dialog box. The select Redeye_Framer and add it to the list on the right. Then click OK.
  4. Double-click on the item labeled AddReg. A dialog box lists the names of all the sections in INFRARED.INF that add items to the Registry. Select IRCOMMON_AddReg and add it to the list on the right. Then select Redeye_AddReg and add it to the list of names on the right and click OK.


C. Testing Your Installation Diskette

Important Before you use the installation disk you have created to install the Infrared Communications on a Windows 95 computer, make sure your infrared device is connected to the computer and powered-up.

Install Windows 95 Infrared Communications driver by inserting the installation diskette in a Windows 95 computer and running the Setup program on the diskette. The Setup program will install the required files in the Windows System and Inf directories, add required entries to the Registry, and launch the Windows 95 Add Hardware Wizard. The Wizard prompts will lead you through the rest of the installation process.

Note For a detailed description of how the installation procedure works, see the documentation file DRVRELNO.DOC which is part of this DDK.


D. Checking the Windows 95 Registry

If you are installing a dongle other than the JetEye PC Infrared PC Interface (ESI-9680), then you need to check the contents of the following key in the registry of the Windows 95 computer on which you installed the dongle: HKEY_LOCAL_MACHINE\Enum\Infrared\Framer. Use the Windows 95 REGEDIT.EXE tool to do this.

For dongles other than the JetEye PC Infrared PC Interface (ESI-9680), the HKEY_LOCAL_MACHINE\Enum\Infrared\Framer key must contain four values:

  • DongleType
  • Driver
  • PortName
  • SpeedDriver

For example, for an ACTiSYS ACT-IR200L Infrared Wireless Interface dongle installed on physical COM port COM1:, the required values look like this:

DongleType="ACT-IR200L"
Driver="irlapfrm.vxd"
PortName="COM1"
SpeedDriver="act200l.vxd"

The DongleType value is used by IRLAPFRM.VXD to determine which manufacturer's dongle is currently installed. The SpeedDriver value is used to dynamically load the OEM-supplied part of the framer.

If one of the required values is missing from the registry Framer key, add it using REGEDIT.EXE.


Step 5. Using the IR Communications Software to Experiment with Your IR Device

You can test your VxD by experimenting with changing the speeds at which your dongles transmit and receive. You can use the baud rate negotiation logic that is built into the IR communications software. When two dongles recognize each other, they start communicating at 9600 baud and then tryout higher speeds until the highest baud rate each dongle is capable of is reached. By changing the values in the baud rate mask in the type_Init function of your OEMDONGL.C source code between sessions, you can experiment with higher and higher baud rates in each communications session between your two dongles.

For example, here is one experimental scenario:

  1. Set the baud rate mask to 9600 baud in OEMDONGL.C by editing the SpeedMask constant. For example, if your dongle type is "RED88" then you could edit the following line of code in OEMDONGL.C to look like this:
    #define RED88_SPEEDMASK      0x00000002
  2. Rebuild your version of OEMDONGL.VXD.
  3. Reinstall IR Communications for Windows 95 on each machine that has your IR dongle attached.
  4. With the two dongles facing each other and less than 3 feet apart, run the IR Monitor application on each machine. The two dongles will recognize each other and negotiate a communication speed of 9600 baud.
  5. Set the baud rate mask to include the next highest baud rate both dongles are capable of. For example, if the two dongles are capable of 19200 baud as well as 9600 baud, edit the line of code to look like this:
    #define RED88_SPEEDMASK      0x00000006
  6. Repeat steps B through D so the dongles can negotiate the jump from 9600 to 19200 baud.

You can use this same process to try the dongles at other baud rates all the way up to 115200, if they are capable of it. The bit pattern settings in the baud rate capabilities mask for all these baud rates are shown in Adapting the type_Init Function.


Introduction to the Windows 95 IR Communications Driver

Congratulations! You are the proud owner of the Microsoft® Windows® 95 Infrared (IR) communications driver. After you install the IR communications driver you can start replacing your serial and parallel cable connections with wireless IR links.

Wireless communications between computers is a new thing. And you're part of it! Have fun experimenting with wireless IR links between your computers and printers.

The Version 1.0 IR communications driver is a set of software components that you can add to a Windows 95 computer to enable that computer to send and receive data over IR communications links. Installing the IR communications driver is as simple as running the Setup program that is one of the driver components.

The IR communications driver supports IR communications links running up to 115.2 kilobytes per second (Kbps). The infrared hardware can be built into your Windows 95 computer or added by attaching an infrared adapter to a serial or parallel port. A future release of the IR communications driver will add support for high-speed IR devices which run at 1.152 and 4.0 megabytes per second (Mbps).


Installing the IR Communications Driver

Note You must always remove any previously installed version of the IR communications driver every time you install the driver. For example, if you have an earlier (Beta) version of the IR communications driver already installed you must remove it before you install Version 1.0

An overview of the IR Communications driver installation procedure is

  1. If you are using an IR adapter (rather than a built-in IR device), make sure the adapter is physically attached to a COM port and note which COM port it is (COM1, COM2, and so on). If you are using a computer with a built-in IR device, note which COM port that device is assigned to.
  2. Start the setup program SETUP.EXE, which is one of the IR communications components, to invoke the Windows 95 Add Infrared Device Wizard. Respond to the wizard's prompts for physical COM port information, IR device manufacturer and model information, and so on.
  3. If the wizard announces New Hardware Found events for the IR serial and parallel ports, you can enable the IR device immediately after the wizard is finished. Enable the IR device by double-clicking on the Infrared device icon in the Control Panel. If the wizard does not announce New Hardware Found events before it is finished, you must restart the computer before you use the Control Panel icon to activate the IR device.

For a detailed description of each of these steps, see Roadmap for Installing and Using the IR Communications Driver.


Using the IR Communications Driver

End-users can install the IR communications device driver on their Windows 95 computer and run applications using wireless infrared communications instead of serial or parallel cables. The driver has been successfully tested on the following Windows 95 notebook computers, which have built-in IR ports:

  • Digital® HiNote Ultra CT475
  • Gateway® 2000 Liberty
  • Gateway Solo
  • HP® Omnibook™ 600CT
  • HP Omnibook 4000C
  • IBM® ThinkPad® 701C (Butterfly)
  • IBM ThinkPad 755 (most configurations)
  • Midwest Micro Elite
  • Midwest Micro Elite p90
  • Sharp® PC 3050
  • TI® TravelMate(tm) 5000
  • Toshiba® Satellite Pro 400 CDT

In addition, the driver has been successfully tested on Windows 95 platforms with the following IR adapters connected to serial ports:

  • ACTiSYS ACT-200L Infrared Wireless Interface
  • ACTiSYS ACT-220L Infrared Wireless Interface
  • Adaptec™ AIRport APA-9320 External Infrared Adapter (this adapter is also called the Adaptec AIRport 2000)
  • Adaptec AIRport 1000
  • AMP PhasIR Serial Adapter
  • Extended Systems JetEye PC Infrared PC Interface (ESI-9680)
  • Parallax IR Adapter LiteLink PRA9500A

To obtain any of the IR adapters previously listed, contact the adapter manufacturer. The addresses of these manufacturers are listed in IR Adapter Manufacturer Names and Addresses.

The following applications have been run successfully over an IR communications link, using the IR communications driver and the hardware previously listed:

  • Windows 95 Direct Cable Connection (DCC).
  • Various Windows communications applications, including HyperTerminal, DynaComm, and Carbon Copy.

Because the IR link is simulating a serial communications link, some communications applications may not perform as expected after they connect over the IR link. For more information, see Troubleshooting.

For instructions on running DCC over an IR link, see Notes on Running the Direct Cable Connection Application Over an IR Link.

Numerous Windows 95 applications have successfully printed over an IR link to an HP(r) Laserjet(r) 5P or 5MP printer, which have built-in IR ports.


Troubleshooting

Some general troubleshooting tips are:

  • To get two IR devices to discover each other, you may have to realign the IR devices so they point right at each other, move them closer together, and/or change the batteries in an IR adapter or plug the AC power into an IR adapter. The devices must be three feet apart, or less, and the angle of the cone of IR transmission is 30 degrees. Some devices work best if kept at least six inches apart.
  • You must always remove any previously installed version of the IR communications driver every time you install the driver. For example, if you have an earlier (Beta) version of the IR communications driver already installed you must remove it before you install Version 1.0. You may also need to remove an installation of the Version 1.0 driver. For example, if you change the IR adapter model that is connected to your computer, you must remove the installed IR communications driver and reinstall it, specifying the new IR adapter type. Instructions for removing the IR communications driver are in An Optional Step: Removing the IR Communications Driver.
  • If your IR adapter is attached to a COM port that is using an 8250 UART instead of a 16550 UART, or if your IR adapter is connected to a relatively slow computer (such as a 386 running at 20 MHz), you might need to use the Limit Connection Speed To option in the Infrared Monitor Options tab to limit the connection speed to 19.2 Kbps.

Some troubleshooting tips related to using particular applications over IR links are:

  • If you use the Windows 95 application HyperTerminal to transfer files, you may have trouble doing file transfers successfully over an IR link.
  • When you run the Windows 95 application Direct Cable Connection (DCC) and establish the connection between the host and guest computers, the guest computer may display the message "Direct Cable Connection was unable to display shared folders of the host computer" and prompt you to enter the computer name of the host computer. A convenient way to find the computer name of the host computer is on the Status tab of the Infrared Monitor interface screen.

Troubleshooting tips related to specific infrared hardware are:

  • The Adaptec AIRport 2000 infrared adapter can be powered by either the serial port, installed AA batteries, or an external power supply. In some cases, the serial port may not provide sufficient power for the operation of the adapter. This can cause reduced operating range and/or a failure to find another IR device which is nearby and aligned correctly. If you suspect such a problem, connect an AC adapter or add four AA batteries to the battery compartment in the infrared adapter. This will assure sufficient power. In some instances, you may need to separate the adapter by at least six inches from the other IR device.
  • If you have an ActiSys 220L IR adapter attached to your computer and print to a printer that is using an Extended Systems ESI-9580 printer IR adapter, or you are printing to the HP DeskJet 340, you must use the Options tab in the Infrared Monitor to limit the connection speed to 19.2 Kbps to print successfully. If you allow the IR devices to automatically negotiate the connection speed without setting this limit, they will negotiate a higher connection speed and your application will not be able to print.
  • The TI TravelMate 5000 may communicate over an IR link only at very low speeds (9600 baud).
  • The Sharp PC 3050 may communicate over an IR link only at speeds between 9600 baud and 19.2 Kbps.
  • If you have an HP Omnibook 4000C or an HP Omnibook 600CT, you must install a special echo-canceling serial driver in addition to the components that make up the IR communications driver. The echo-canceling driver, along with instructions on how to install it, are available from Hewlett-Packard.


Product Support

Microsoft's end-user support offerings for the IR Communications driver range from no-cost and low-cost electronic information services (available 24 hours a day, 7 days a week) to annual support plans and CD-ROM subscription programs. Please check the SUPPORT.TXT on-line documentation that comes with Windows 95 for detailed information. Note that Microsoft support services are subject to Microsoft's then-current prices, terms, and conditions, which are subject to change without notice.

In the United States, no-charge support from Microsoft support engineers is available via a toll call between 6:00 A.M. and 6:00 P.M. Pacific time, Monday through Friday, excluding holidays. For all issues except networking issues, this support is available for 90 days after your first call to a support engineer. Networking issues are defined as server-based setup, network administration, dialing into a computer, or connecting to the Internet via a service provider, and using e-mail and fax from within Windows 95.

For fee-based support for these networking issues, see the information in SUPPORT.TXT.

  • For technical support for Windows 95, call (425) 635-7122.
  • In Canada, support engineers are available via a toll call between 8:00 A.M. and 8:00 P.M. Eastern time, Monday through Friday, excluding holidays. Call (905) 568-4494. This support is available for 90 days after your first call to a support engineer.

When you call, you should be at your computer and have the appropriate product documentation at hand. Be prepared to give the following information:

  • The version number of the Microsoft product that you are using.
  • The type of hardware that you are using.
  • The exact wording of any messages that appeared on your screen.
  • A description of what happened and what you were doing when the problem occurred.
  • A description of how you tried to solve the problem.


Road Map for Installing and Using the IR Communications Driver

You must carry out a three-step process to use the IR communications driver

  1. Install the Windows 95 IR Communications driver.
  2. Validate the installation by using an application to transfer data over the IR link.
  3. Start running other communicating applications over the IR link.

After you install the driver, you can remove it at any time by running the Windows 95 Control Panel Add/Remove Programs feature.

Each of these steps, including the driver removal step, is presented in detail in the following.


Step 1. Installing the IR Communications Driver

You must always remove any previously installed version of the IR communications driver every time you install the driver. For example, if you have an earlier (Beta) version of the IR communications driver already installed you must remove it before you install Version 1.0. You may also need to remove an installation of the Version 1.0 driver. For example, if you change the IR adapter model that is connected to your computer, you must remove the installed IR communications driver and reinstall it, specifying the new IR adapter type. Instructions for removing the IR communications driver are in An Optional Step: Removing the IR Communications Driver.

To install the IR communications driver, do the following

  1. Click the Start button and select the Run option.
  2. In the Run dialog, open the Setup program (SETUP.EXE) from the Infrared setup location. After the Setup program copies some files, it starts the Add Infrared Device Wizard.
  3. When the wizard prompts you to choose a manufacturer's name for your IR device, choose "(Standard Infrared Devices)" if you have a computer with a built-in device, or choose the name of the manufacturer and the model of the adapter if you have an IR adapter attached to the computer.
  4. When the wizard prompts you to choose the communications port that the IR device is physically connected to, click the port from the list. If you are not certain which physical communications port the IR device is using, make your best guess.
  5. When you are done with the wizard, click the Finish button to complete the IR device installation. The wizard should have briefly displayed New Hardware Found messages. If the wizard did not display these messages, then restart the computer.
  6. Activate the IR device by clicking the Start button, pointing to Settings, and then clicking Control Panel. Double-click the Infrared icon. If you chose the correct port in Step 4, the Infrared Monitor interface screen appears. If you did not choose the correct port, a message appears telling you that the port you have chosen is being used by another program. Click OK. When the Infrared Monitor interface appears, click the Options tab, and then choose a different communications port (for example, COM1 instead of COM2). Repeat this step until you have chosen the correct port.

For general information about how to use the Infrared Monitor, click the Help button in the lower-right corner of the Infrared Monitor interface screen. To get information about individual items in the Infrared Monitor interface, such as check boxes, click the question-mark (?) button in the upper-right corner of the screen and then click the item you want information about.

The Options tab of the Infrared Monitor interface contains the following two particularly useful items:

  • The Enable Infrared Communication On check box, which enables and disables the IR device.
  • The Limit Connection Speed To option, which limits the link speed the IR device can negotiate.

You might want to use the Limit Connection Speed To option if an adapter is attached to a COM port that is using an 8250 UART instead of a 16550 UART, or if an adapter is connected to a relatively slow computer (such as a 386 running at 20 MHz). In these cases, you could use this option to limit the connection speed to 19.2 Kbps.


Step 2. Validating the IR Communications Driver Installation

To validate your IR communications driver installation, you can either:

  • Print from an application over an IR link to an IR-capable printer.
  • Exchange data between two IR-capable computers over an IR link, using a communications application.


Printing to an IR-Capable Printer

If you are testing the printing capability of a Windows 95 application over an IR link to an IrDA-compliant printer such as the HP 5P, then you need to carry out the installation step for the IR communications driver on one computer and then try the Print option in an application. Make sure you have the correct printer driver installed for your IR-capable printer and that you have selected the infrared printing port (virtual LPT port) as the printer port. If the application prints on the IR-capable printer, you have validated the link.

If you have trouble printing, for more information see Troubleshooting for more information.


Exchanging Data Between Two Computers

To validate a link between two computers running Windows 95, you must install the IR communications driver on both computers. To do this, carry out the procedure in Step 1. Installing the IR Communications Driver.

Note that the IR devices on the two computers do not have to be made by the same manufacturer as long as both devices are IrDA-compliant. For example, you could have a JetEye PC Infrared PC Interface (ESI-9680) attached to one desktop computer and an Adaptec AIRport APA-9320 External Infrared Adapter attached to the other desktop and the IR link will work.

One way to validate an IR link is to run the HyperTerminal application on both computers and send characters from the keyboard of each computer over the IR link. HyperTerminal is installed on a Windows 95 computer as part of the typical installation that is recommended for most computers.

To validate your installation of the IR driver on both computers, carry out the following procedure

  1. On both computers, click the Start button, point to Settings, and then click the Control Panel. Double-click the Infrared icon. Then move the IR devices within 3 feet of each other, and make sure they're pointing at each other. When the two IR devices discover each other, the message "Available infrared devices in range" will appear on the Status tab of the Infrared Monitor interface screen. Make sure Infrared Monitor reports both IR devices have the appropriate infrared device within range before you proceed. You might have to realign the IR devices so they point right at each other, move them closer together, and/or change the batteries in an IR adapter or plug the AC power into an IR adapter. For more information, see Troubleshooting.
  2. On one of the computers, click the Options tab in the Infrared Monitor interface and find the information that starts with "Providing application support on ...". Write down the name of the COM port you find there. This is the name of the simulated serial port that the IR link using. The name of this virtual serial port might be COM4 or COM5 and it will differ from the name of the physical communications port your IR device is running on (which is typically named COM1 or COM2).
  3. Run HyperTerminal on the computer for which you have the virtual serial port name by clicking the Start button, pointing to Programs, pointing to Accessories, and then clicking the HyperTerminal folder. In the window that appears, double-click the Hypertrm.exe icon.
  4. In the Connection Description dialog box, type a descriptive name (such as "Direct IR") for the new connection, and then click OK.
  5. In the Phone Number dialog box, use the Connect Using drop-down list to click the "Direct to Comx" entry, where x is the number of the virtual COM port that you wrote down in step 2. Then click OK. You are ready to start using HyperTerminal on one of the computers.
  6. Repeat steps 2. through 5. for the other computer.
  7. In HyperTerminal on either computer, type any characters at the keyboard. If the characters you type appear in the HyperTerminal window on the other computer, then you have confirmed that the IR link works in that direction. Repeat this step on the other computer. If the IR link works in both directions using HyperTerminal, you have confirmed the successful installation of the IR communications driver on the two computers.

    Note The changes in status that are displayed in the Status tab of the Infrared Monitor interface while you type characters in HyperTerminal.

  8. Disconnect the HyperTerminal direct IR connection by exiting the HyperTerminal application on both computers. When you are prompted to save the session, click Yes. This saves the direct IR connection setup information as an icon in the HyperTerminal main folder. You can double-click this icon to restart one side of the HyperTerminal direct IR connection.


Step 3. Running Other IR-Capable Applications

Most applications that can communicate over a null modem cable that connects serial ports on two Windows 95 computers should also be able to communicate over an IR link. The procedure for setting up and using the IR link in these other communicating applications will probably be similar to the procedure you use in Step 2 of the Roadmap, when you use the HyperTerminal application to validate the installation of the IR communications driver. The procedure for running the Windows 95 Direct Cable Connection application is given in detail in Notes on Running the Direct Cable Connection Application Over an IR Link.


An Optional Step: Removing the IR Communications Driver

To remove the IR communications driver, including all the files and registry entries, carry out the following procedure

  1. Make sure the Infrared Monitor (Irmon.exe) is not running. If it is running, you must restart the computer, or you can close the Infrared Monitor dialog box, press CTRL+ALT+DEL, click Irmon, and then click End Task.
  2. Click the Start button, point to Settings, and then click the Control Panel.
  3. Double-click the Add/Remove Programs icon, and then click the Install/Uninstall tab.
  4. In the list of installed software, click the name of the IR communications entry, and then click the Add/Remove button. For this release of the IR communications driver, the entry in the software list to click is "Infrared Support for Windows 95 Version 1.0."
  5. When you are prompted to restart the computer, click Yes. The Infrared icon will no longer appear in the Control Panel folder.


Notes on Running the Direct Cable Connection Application Over an IR Link

With Direct Cable Connection (DCC), you can establish a direct serial or parallel cable connection between two computers to share the resources of the computer designated as the host. DCC can also be used over an IR link.


Preparing to Use DCC

The computer that contains the folder you want to share is the host, and the other computer is the guest. Share a folder on the host, granting access rights to anyone using the guest computer, by carrying out the procedure given in the following.

Note The following procedure is just one of many that could be used to share files in a folder on the host computer. For example, there is user-level access control as well as share-level access control. The following procedure is one of the simplest access control procedures, which is all that is needed to get you started using DCC.

To get information about all the ways files, folders, and printers can be shared, use the Windows 95 Help

  1. Double-click on the My Computer icon.
  2. Double-click on the icon of the drive that contains the folder you want to share (for example, double-click on the icon for the C: drive).
  3. Right-click on the icon of the folder you want to share and then select Properties.
  4. In the folder properties dialog, select the Sharing tab and then select the Shared As option, enter a share name, enter a comment, and add user access rights (Full or Read-Only).
  5. The picture of a hand is added to the folder icon to indicate the selected folder is now a shared resource.


Making Sure DCC Is Installed on Both Computers

DCC is not installed with the typical Windows 95 installation recommended for most computers.

So you must check whether DCC is installed on both of the two computers that will be using the IR link. To do this, click the Start button, point to Programs, and then point to Accessories. Direct Cable Connection appears in this menu of it is installed on the computer you are checking.

If you find that DCC is installed on the host and DCC is installed on the guest, then you can skip the next step.


(Optional) Installing DCC

Before you can establish a DCC connection, DCC must be installed on both the host and guest. The procedure for installing DCC on either the host or the guest is given in the following.

If you find that DCC is not installed on the host and is also not installed on the guest, then you must run the following procedure twice (once on each machine)

  1. Click the Start button, point to Settings, and then click the Control Panel. Double-click the Add/Remove Programs icon.
  2. In the Add/Remove Program Properties, click the Windows Setup tab.
  3. In the Components list, click Communications, and then click the Details button.
  4. In the Communications dialog box, make sure Direct Cable Connection is checked and then click OK.


Establishing and Using the DCC IR Link Between Host and Guest

To run DCC over an IR link, carry out the following procedure

  1. Make sure the IR communications driver is properly installed and the IR devices are enabled by carrying out the procedures in Step 1. Installing the IR Communications Driver and Step 2. Validating the IR Communications Driver Installation.

    Note You might want to use the Limit Connection Speed To option on the Infrared Monitor Options tab to limit the IR connection speed to 9600 bps for the first test of DCC over the IR link (and then increase the speed later).

  2. On the host computer, click the Start button, point to Accessories, and then click Direct Cable Connection.
  3. Follow the steps in the Direct Cable Connection Wizard to set up the host computer. When the wizard prompts you, select the Host option. When the wizard prompts you to choose a port, use the same virtual port as you used in the procedure Step 2. Validating the IR Communications Driver Installation earlier in this documention. The wizard will also offer password protection. You do not need to establish password protection on the host for this test of the IR link. When you are done with the wizard, click the Finish button. DCC will start running on the IR link and display the message "Status: Waiting to connect via Serial cable on Comx," where Comx is the name of the virtual port the IR link is using.
  4. Repeat steps 2 and 3 for the guest computer, except select the Guest option instead of the Host option. When you are done with the wizard, click the Finish button. The DCC connection is automatically made over the IR link, and all the shared folders on the host are displayed on the guest's screen.
  5. Working on the guest computer, to copy a shared folder from the host to the guest over the IR link select the folder's icon in the window that displays all the shared folders that are on the host and drag the icon to the desktop. To work on a shared folder on the host without copying it to the guest, double-click on the folder in the display on the guest. Note that if the host is connected to a network, the guest can reach shared resources on the network through the DCC connection to the host.


IR Communications Driver Components

The files that make up the IR communications driver are:

Filename | Description
ACT200L.VXD | Support for the ACTiSYS ACT-IR200L IR adapter.
ACT220L.VXD | Support for the ACTiSYS ACT-IR220L IR adapter.
ADAPTEC.VXD | Support for Adaptec IR adapter.
CRYSTAL.VXD | Support for AMP PhasIR Serial Adapter.
ESI.VXD | Support for Extended Systems JetEye PC Infrared Interface (ESI9680).
INFRARED.CNT | Table of contents for Infrared Monitor on-line help.
INFRARED.CPL | Infrared device in the Windows 95 Control Panel.
INFRARED.DLL | Infrared device class installer.
INFRARED.INF | IR device information file for Windows 95 Setup.
INFRARED.HLP | On-line help topics for Infrared Monitor.
IRCOMM.VXD | Top layer of IR communications for Windows 95.
IRENUM.VXD | Enumerator for the "IR bus."
IRLAMP.VXD | Generic infrared framer, lower layer of IR communications for Windows 95.
IRMON.EXE | Infrared Monitor.
IRMONHLP.EXE | IR Monitor on-line help utility.
IR_BEGIN.WAV | Sound for Infrared Monitor user interface.
IR_END.WAV | Sound for Infrared Monitor user interface.
IR_INTER.WAV | Sound for Infrared Monitor user interface.
MSPORTS.INF | IR port information file for Windows 95 Setup.
PARALLAX.VXD | Support for Parallax IR Adapter, LiteLink PRA9500A.
SETUP.EXE | Installs the Windows 95 Infrared communications driver.
W_IR.CNT | Table of contents for Infrared Monitor on-line help.

The documentation files supplied with the IR device driver are:

Filename | Description
DRVRELNO.DOC | This documentation.


IR Adapter Manufacturer Names and Addresses

The names and addresses of IR adapter manufacturers that have been successfully tested with the IR driver in the Windows 95 IR Communications DDK are:

ActiSys, Inc.
1507 Fulton Place
Fremont CA 94539
tel: 510-490-8024
fax: 510-623-7268
email: corp@actisys.com

Adaptec, Inc.
691 South Milpitas Blvd,
Milpitas CA 95035
tel: 1-800-959-7274
fax: 1-408-957-7223

AMP Product Information Center
AMP Incorporated
Harrisburg PA 17105
tel: 1-800-522-6752

Extended Systems, Inc.
5777 North Meeker Ave
Boise ID 83704-1520
tel: 208-322-7575
fax: 208-377-1906

The Parallax IR adapter distributor in North America is:
TSC Electronics
1610 Lockness Place
Torrance CA 90501
tel: 310 534 2738
fax: 310 534 3216
email: dtsaitsc@aol.com
contact person: Daniel Tsai

The Parallax IR adapter distributor outside North America is:
Parallax Research
201 Innovation Centre
NTU
Nanyang Drive
Singapore 639798
Republic of Singapore
tel: +65 793 0855
fax: +65 793 0775
email: parallax@technet.sg


Windows 95 Keyboard Driver

The Microsoft® Windows® keyboard driver processes all keyboard input for Windows and Windows applications. It directly accesses the keyboard hardware, yet provides hardware-independent keyboard input by translating scan codes to virtual-key codes.

The Windows keyboard driver consists of the following:

  • Keyboard-interrupt handler
  • Virtual-key translation functions and
  • ANSI-character translation functions
  • Keyboard-service functions

Windows requires the keyboard to generate an interrupt whenever the user presses or releases a key. In response to an interrupt, the driver's keyboard-interrupt handler translates corresponding scan codes (and corresponding shift state) to Windows virtual-key codes. The keyboard passes both scan codes and virtual-key codes to Windows for generating keyboard messages, or for initiating some other action.


Initializing the Driver

Windows initializes the keyboard driver by calling the driver's initialization routine when it first loads the driver. Windows also calls the driver's InquireEx function to retrieve information about the driver. When Windows calls InquireEx with the INQEX_KBDINFO flag, the driver must fill a KBINFO structure with information used to support double-byte character sets (DBCS). The function also specifies the number of bytes of key-state information that Windows must support (that is, the size of the state block). The ToAsciiEx function fills the state block when Windows calls the function to translate scan codes to ANSI character codes.

For more information about your keyboard and ROM BIOS, see the documentation from your computer manufacturer.

See Also

InquireEx, KBINFO, ToAsciiEx


Enabling and Disabling the Driver

When Windows is ready to receive keyboard input, it enables the driver by calling the Enable function. When Windows no longer requires keyboard input (when terminating or switching to a full-screen MS-DOS application, for example), it disables the driver by calling the Disable function.

The Enable function is responsible for:

  • Saving the address of the keyboard-event callback function
  • Initializing the Windows virtual-key state array
  • Installing the keyboard-interrupt handler
  • Installing the language-specific keyboard layouts

When Windows calls Enable, it passes the address of the keyboard-event callback function. Enable saves this address - the keyboard-interrupt handler uses it to pass scan and virtual-key codes back to Windows.

Windows also passes the address of its 256-element, virtual-key state array (sometimes called the keyboard-state vector) to Enable. The elements in this array specify the state of the virtual keys. Windows sets bit 7 in an element if the corresponding virtual key is down, and clears the bit if the key is up. Similarly, Windows toggles bit zero each time the virtual key is pressed. Although Windows maintains the key-state array, Enable initializes the array to reflect to current state of the SHIFT, CTRL, ALT, NUMLOCK, CAPSLOCK, and SCROLLLOCK keys as specified by the keyboard flags in the RAM area used by the ROM BIOS. (On most computers, the keyboard flags are at address 40h:17h.)

Note If the keyboard driver reads data from the ROM BIOS, it must use the special segment selector, __ROMBIOS, to create ROM BIOS addresses. The selector (exported by the Windows kernel as KERNEL.173) corresponds to ROM BIOS address 0F0000H.

To install the driver's own keyboard-interrupt handler, the Enable function first saves the existing keyboard-interrupt handler. (On most computers, the keyboard interrupt is Interrupt 9.) The original handler address is saved to allow the Disable function to restore it as well as to allow the driver to call the original handler for certain actions. Enable should also save the address of the Keyboard Service routine (Interrupt 16h). The Enable and other functions use this address to set the keyboard lights.

Note To support computers in which the keyboard and mouse use the same interrupt, Windows disables and enables both the keyboard and mouse drivers when switching to and from a full-screen MS-DOS application. Windows always enables the drivers in the reverse order in which it disables the drivers.

See Also

Disable, Enable


Keyboard-Interrupt Handler

The keyboard-interrupt handler services hardware interrupts generated by the keyboard. The handler retrieves scan codes from the keyboard, translates the scan codes into virtual-key codes, and passes the scan and virtual-key codes to Windows through the keyboard-event callback function. It also updates the keyboard flags (usually at 40h:17h in the RAM area of the ROM BIOS) and checks for special keys or key combinations.

When the interrupt handler receives control, such as when the user presses or releases a key, the handler retrieves the current input from the keyboard data port and determines whether the input is a scan code or a command byte. If it is a command byte, it passes control to the original keyboard-interrupt handler. Otherwise, it continues to process the scan code.

When processing the scan code, the handler checks for key combinations, such as CTRL+ALT+DELETE, and passes control to the original keyboard-interrupt handler to carry out the corresponding actions. It also checks for the ALT+PRINTSCREEN and SHIFT+PRINTSCREEN key combinations and translates these into the VK_SNAPSHOT virtual-key code. When Windows receives this virtual-key code, it takes a snapshot of the active window or the entire screen. The handler indicates which snapshot to take by setting the BX register to zero for the active window (ALT+PRINTSCREEN) and to 1 for the entire screen (SHIFT+PRINTSCREEN).

To support debugging, the interrupt handler checks for the CTRL+ALT+SYSREQ key and eithers simulates a nonmaskable interrupt (NMI) (to pass control to a debugger) or jumps to the CVWBreak function (KERNEL.205) to carry out a controlled break.

To complete processing the scan code, the handler sets the interrupt flag using the SetInterruptFlag (sti) instruction. Before doing so, it makes sure a subsequent keyboard interrupt does not invoke the handler again as only one interrupt can be handled at a time. If Windows is running in enhanced mode, this may require masking out the keyboard interrupt (usually IRQ1) at the interrupt controller.

See Also

ScreenSwitchEnable


Keyboard-Event Callback Function

The keyboard-interrupt handler calls the keyboard-event callback function when it has scan and virtual-key codes to pass back to Windows. The registers must be set as follows:

Register | Value
AL | Virtual key code. For more information about the specific values, see Section 6.1.7, "Virtual-Key Codes."
AH | 80h if the key is up, or 00h if the key is down.
BL | Scan code. This is an OEM-dependent value.
BH | 01h if the key is an enhanced key (that is, if the prefix 0E0h preceded this scan code), or 00h if the key is not enhanced.
DI:SI | Address of extra message information. If extra message information isn't used, set the DI and SI registers to 0.

An enhanced key is one of a set of duplicate keys, such as the ENTER, INSERT, DELETE, and direction keys, found on some keyboards such as the IBM enhanced keyboard. On the IBM keyboard, an enhanced key has the same scan code as its corresponding nonenhanced key, but the keyboard inserts the 0E0h prefix byte to indicate that the enhanced key generated the code. In this case, the keyboard-interrupt handler sets the BH register to 1 before calling the keyboard-event callback function. On the IBM enhanced keyboard, the following are enhanced keys: Direction keys, INSERT, HOME, PAGE UP, DELETE, END, PAGE DOWN, DIVIDE (on numeric keypad), and ENTER (on numeric keypad).

For keyboards that have extended keys with special scan codes instead of prefixes, Windows will not generate the proper WM_KEYUP or WM_KEYDOWN message unless the interrupt handler converts the scan codes to the corresponding IBM scan codes on the IBM enhanced keyboard and sets the BH register to 1 before calling the keyboard-event callback function.


Translations

The keyboard driver carries out the following translations:

  • Scan codes to virtual-key codes (keyboard-interrupt handler)
  • Virtual-key codes to ANSI characters (ToAsciiEx)
  • ANSI characters to OEM characters (AnsiToOem and AnsiToOemBuff)
  • OEM characters to ANSI characters (OemToAnsi and OemToAnsiBuff)
  • OEM or ANSI characters to virtual-key codes (OemKeyScan, VkKeyScanEx, and MapVirtualKeyEx)
  • Virtual-key codes to scan codes (MapVirtualKeyEx)

The keyboard-interrupt handler converts scan codes to virtual-key codes before sending keystrokes to Windows. Windows calls the ToAsciiEx function to convert virtual-key codes to ANSI characters when generating WM_CHAR messages. Windows applications call the AnsiToOem and OemToAnsi functions to convert ANSI characters to OEM-specific characters, and OEM-specific characters to ANSI characters. Windows and Windows applications call OemKeyScan and VkKeyScanEx to generate scan and virtual-key codes for given OEM or ANSI characters.

See Also

ToAsciiEx, AnsiToOem, AnsiToOemBuff, MapVirtualKeyEx, OemToAnsi, OemToAnsiBuff, VkKeyScanEx


Virtual-Key Codes

The virtual-key codes provide a hardware- and language-independent method of identifying keyboard keys. Each virtual-key code represents a unique keyboard key and also identifies the purpose of that key. The keyboard driver must provide one or more keyboard layouts that maps keyboard scan codes to the appropriate virtual-key codes.


Required Virtual Keys

The complete virtual-key code set consists of 256 byte values in the range 0 to 255. Most, but not all, of the values used by standard drivers are in the range 0 to 127. There is a loose distinction between "standard" keys, which do not vary much, and "OEM" keys, which do vary from keyboard to keyboard.

For full Windows functionality, a keyboard driver must provide the following virtual keys:

Virtual-key code | Description
VK_0 through VK_9 | Number keys (not on numeric keypad): 0 through 9
VK_A through VK_Z | Letter keys: A through Z
VK_BACK | BACKSPACE key
VK_CONTROL | CTRL key
VK_DELETE | DELETE key
VK_DOWN | Down direction key
VK_END | END key
VK_ESCAPE | ESC key
VK_F1 through VK_F10 | F1 through F10 keys
VK_HOME | HOME key
VK_INSERT | INSERT key
VK_LEFT | Left direction key
VK_MENU | ALT key
VK_NEXT | PAGE DOWN key
VK_PRIOR | PAGE UP key
VK_RIGHT | Right direction key
VK_SHIFT | Left and right SHIFT keys
VK_SNAPSHOT | PRINTSCREEN key
VK_SPACE | SPACE key
VK_TAB | TAB key
VK_UP | Up direction key

Shift keys must be available in the combinations unshifted, SHIFT, CTRL, and CTRL+ALT.

Most keyboards, the virtual-key codes VK_INSERT, VK_DELETE, VK_HOME, VK_END, VK_PRIOR, and VK_NEXT are generated on the numeric keypad only if NUMLOCK is off.


Optional Virtual Keys

If a keyboard has a numeric pad, the numeric keys are frequently used as cursor-control and editing keys if NUMLOCK is off. If NUMLOCK is on, the virtual-key codes VK_NUMPAD0 through VK_NUMPAD9 are used for the digits. Keyboards with a DELETE key that also generates the decimal point (period or comma) use VK_DELETE and VK_DECIMAL to distinguish between the two uses of the key.

Keyboards commonly contain various "lock" keys, such as VK_CAPITAL and VK_NUMLOCK. If a keyboard driver generates ANSI characters on the numeric keypad using ALT + numeric-pad keys, it must do this translation only if NUMLOCK is on. The cursor and editing keys on IBM-compatible keyboards do not produce this translation.

Other keys may vary from keyboard to keyboard. The following set of virtual-key codes is generally used for punctuation keys, accented letter keys, and dead keys in the main section of a keyboard:

VK_OEM_1 ... VK_OEM_8

VK_OEM_102

VK_OEM_PLUS, VK_OEM_MINUS, VK_OEM_COMMA, VK_OEM_PERIOD

If a keyboard has more than 16 function keys, the virtual-key codes in the range VK_F17 through VK_F24 should be used for the extra function keys.

Windows internally generates the mouse-button virtual-key codes VK_LBUTTON, VK_RBUTTON, VK_MBUTTON, and VK_CANCEL. These virtual-key codes are generated internally by Windows and are never generated by keyboard or mouse drivers.

Keyboard drivers should not generate VK_EXECUTE or VK_SEPARATER.


Virtual Keys for 122-Key Keyboards

For keyboards with 122 keys, the mapping for the first 101 keys is the same as described in previous sections.

The function keys F13 through F24 should use VK_F13 through VK_F24.

The remaining keys should be mapped to the following virtual-key codes:

VK_ATTN | VK_OEM_CLEAR
VK_CRSEL | VK_PA1
VK_EREOF | VK_PLAY
VK_EXSEL | VK_ZOOM
VK_NONAME |


Virtual-Key Code Definitions

The following table includes the virtual-key codes that are defined for Windows. The key code values 0 and 0FFh are not used.

Name | Value | Comment
VK_LBUTTON | 01h | Left mouse button.
VK_RBUTTON | 02h | Right mouse button.
VK_CANCEL | 03h | Used for control-break processing.
VK_MBUTTON | 04h | Middle mouse button (3-button mouse).
 |  | 05h through 07h undefined.
VK_BACK | 08h |
VK_TAB | 09h |
 |  | 0Ah and 0Bh undefined.
VK_CLEAR | 0Ch |
VK_RETURN | 0Dh |
 |  | 0Eh and 0Fh undefined.
VK_SHIFT | 10h |
VK_CONTROL | 11h |
VK_MENU | 12h |
VK_PAUSE | 13h |
VK_CAPITAL | 14h |
 |  | 15h through 1Ah undefined.
VK_ESCAPE | 1Bh |
 |  | 1Ch through 1Fh undefined.
VK_SPACE | 20h |
VK_PRIOR | 21h | Page up.
VK_NEXT | 22h | Page down.
VK_END | 23h |
VK_HOME | 24h |
VK_LEFT | 25h |
VK_UP | 26h |
VK_RIGHT | 27h |
VK_DOWN | 28h |
VK_SELECT | 29h |
VK_PRINT | 2Ah | Only used by Nokia.
VK_EXECUTE | 2Bh | Never used.
VK_SNAPSHOT | 2Ch | SYSREQ key starting with Windows 3.0.
VK_INSERT | 2Dh |
VK_DELETE | 2Eh |
VK_HELP | 2Fh |
VK_0 | 30h |
VK_1 | 31h |
VK_2 | 32h |
VK_3 | 33h |
VK_4 | 34h |
VK_5 | 35h |
VK_6 | 36h |
VK_7 | 37h |
VK_8 | 38h |
VK_9 | 39h |
 |  | 3Ah though 40h undefined.
VK_A | 41h |
VK_B | 42h |
VK_C | 43h |
VK_D | 44h |
VK_E | 45h |
VK_F | 46h |
VK_G | 47h |
VK_H | 48h |
VK_I | 49h |
VK_J | 4Ah |
VK_K | 4Bh |
VK_L | 4Ch |
VK_M | 4Dh |
VK_N | 4Eh |
VK_O | 4Fh |
VK_P | 50h |
VK_Q | 51h |
VK_R | 52h |
VK_S | 53h |
VK_T | 54h |
VK_U | 55h |
VK_V | 56h |
VK_W | 57h |
VK_X | 58h |
VK_Y | 59h |
VK_Z | 5Ah |
 |  | 5Bh through 5Fh undefined.
VK_NUMPAD0 | 60h |
VK_NUMPAD1 | 61h |
VK_NUMPAD2 | 62h |
VK_NUMPAD3 | 63h |
VK_NUMPAD4 | 64h |
VK_NUMPAD5 | 65h |
VK_NUMPAD6 | 66h |
VK_NUMPAD7 | 67h |
VK_NUMPAD8 | 68h |
VK_NUMPAD9 | 69h |
VK_MULTIPLY | 6Ah |
VK_ADD | 6Bh |
VK_SEPARATER | 6Ch | Never generated by keyboard driver.
VK_SUBTRACT | 6Dh |
VK_DECIMAL | 6Eh |
VK_DIVIDE | 6Fh |
VK_F1 | 70h |
VK_F2 | 71h |
VK_F3 | 72h |
VK_F4 | 73h |
VK_F5 | 74h |
VK_F6 | 75h |
VK_F7 | 76h |
VK_F8 | 77h |
VK_F9 | 78h |
VK_F10 | 79h |
VK_F11 | 7Ah |
VK_F12 | 7Bh |
VK_F13 | 7Ch |
VK_F14 | 7Dh |
VK_F15 | 7Eh |
VK_F16 | 7Fh |
VK_F17 | 80h |
VK_F18 | 81h |
VK_F19 | 82h |
VK_F20 | 83h |
VK_F21 | 84h |
VK_F22 | 85h |
VK_F23 | 86h |
VK_F24 | 87h |
 |  | 88h through 8Fh unassigned.
VK_NUMLOCK | 090h | NUMLOCK on all keyboards.
VK_OEM_SCROLL | 091h | SCROLL LOCK on all keyboards.
 |  | 92h through B9h unassigned.
VK_OEM_1 | 0BAh | Punctuation.
VK_OEM_PLUS | 0BBh | Punctuation.
VK_OEM_COMMA | 0BCh | Punctuation.
VK_OEM_MINUS | 0BDh | Punctuation.
VK_OEM_PERIOD | 0BEh | Punctuation.
VK_OEM_2 | 0BFh | Punctuation.
VK_OEM_3 | 0C0h | Punctuation.
 |  | C1h through DAh unassigned.
VK_OEM_4 | 0DBh | Punctuation.
VK_OEM_5 | 0DCh | Punctuation.
VK_OEM_6 | 0DDh | Punctuation.
VK_OEM_7 | 0DEh | Punctuation.
VK_OEM_8 | 0DFh | Punctuation.
VK_F17 | 0E0h | F17 key on Olivetti extended keyboard (internal use only).
VK_F18 | 0E1h | F18 key on Olivetti extended keyboard (internal use only).
VK_OEM_102 | 0E2h | < or | on IBM-compatible 102 enhanced keyboard (non-U.S.).
VK_ICO_HELP | 0E3h | Help key on Olivetti extended keyboard (internal use only).
VK_ICO_00 | 0E4h | 00 key on Olivetti extended keyboard (internal use only).
 |  | E5h unassigned.
VK_ICO_CLEAR | 0E6h | Olivetti extended keyboard (internal use only).
 |  | E7h and E8h unassigned.
VK_OEM_RESET | 0E9H | Only used by Nokia.
VK_OEM_JUMP | 0EAH | Only used by Nokia.
VK_OEM_PA1 | 0EBH | Only used by Nokia.
VK_OEM_PA2 | 0ECH | Only used by Nokia.
VK_OEM_PA3 | 0EDH | Only used by Nokia.
VK_OEM_WSCTRL | 0EEH | Only used by Nokia.
VK_OEM_CUSEL | 0EFH | Only used by Nokia.
VK_OEM_ATTN | 0F0H | Only used by Nokia.
VK_OEM_FINNISH | 0F1H | Only used by Nokia.
VK_OEM_COPY | 0F2H | Only used by Nokia.
VK_OEM_AUTO | 0F3H | Only used by Nokia.
VK_OEM_ENLW | 0F4h | Only used by Nokia.
VK_OEM_BACKTAB | 0F5h | Only used by Nokia.
VK_ATTN | 0F6H |
VK_CRSEL | 0F7H |
VK_EXSEL | 0F8H |
VK_EREOF | 0F9H |
VK_PLAY | 0FAH |
VK_ZOOM | 0FBH |
VK_NONAME | 0FCH |
VK_PA1 | 0FDH |
VK_OEM_CLEAR | 0FEH |


ANSI Characters

Windows and Windows applications call the ToAsciiEx function to translate virtual-key codes to ANSI characters. The keyboard driver translate these key codes by checking the state of the virtual-shift keys (such as the VK_SHIFT, VK_CONTROL, and VK_MENU) and mapping the virtual-key code and shift state to the appropriate character. For example, on most U.S. keyboards if the VK_SHIFT key is up, the VK_2 virtual key code maps to the number 2 (ANSI 50); if VK_SHIFT is down, VK_2 maps to the at sign (@) (ANSI 64). For foreign-language keyboards, the keyboard also checks for a previously typed dead key before translating the virtual-key code.

Windows passes the address of the key-state array to the ToAsciiEx function, giving the keyboard driver access to the current state of all virtual keys including the shift keys. The key-state array also contains the shift state of the mouse buttons (that is, the corresponding virtual-key codes VK_LBUTTON, VK_RBUTTON, VK_CANCEL, and VK_MBUTTON).

The keyboard driver must provide keyboard layouts to map virtual keys to ANSI characters. Since the meaning of a virtual key depends on the state of the shift keys, the driver should provide layouts for each possible shift-key combination (for example, no shift key, VK_SHIFT, VK_CONTROL, and VK_MENU and VK_CONTROL combined). Windows does not require that all virtual keys map to ANSI characters for all shift-key combinations. Therefore, not all keyboard layouts need to map the complete virtual-key set.

See Also

ToAsciiEx


OEM Characters

Windows and Windows applications call the AnsiToOem and OemToAnsi functions to convert ANSI characters to OEM characters and OEM characters to ANSI characters. The functions allow Windows applications to prepare text for the MS-DOS environment.

The keyboard code page affects the translation of ANSI and OEM characters. The keyboard driver must adapt its translation tables for specific code pages by loading translation tables from the corresponding translation-table file. Windows specifies the translation table to load using the OEMANSI.BIN setting in the [Keyboard] section of the SYSTEM.INI file.

See Also

AnsiToOem, OemToAnsi


Scan Codes

Windows applications send characters to other Windows applications with the WM_KEYDOWN and WM_KEYUP messages. These messages are expected to get the appropriate virtual-key codes to send by using the VkKeyScanEx, OemKeyScan, or MapVirtualKeyEx function. The applications must not assume any fixed translation of the VK_OEM_* keys. To support these functions, the keyboard driver can scan existing keyboard layouts to locate the given ANSI or OEM character code and subsequently identify the scan code.

See Also

MapVirtualKeyEx, OemKeyScan, VkKeyScanEx


Keyboard Layouts

A keyboard layout is a data file that consists of a header block and the keyboard layout data. A keyboard driver uses the keyboard layout to map scan codes to virtual key codes and vice versa. A keyboard layout file is a binary data file with the filename extension KBD.


Creating a Keyboard Layout File

When Windows calls the InquireEx function with the INQEX_NLCID flag, the driver must return the number of keyboard layouts that it supports. The driver fills a buffer with a list of the keyboard layouts when the INQEX_LPLCID flag is specified.

The format of a keyboard layout file is as follows.

// Header block
typedef struct     {
    BYTE  KbdDesc[2];   // set to 'DS'
    DWORD DefaultLCID;  // base language locale identifier
    WORD  Version;      // set to zero
    DWORD pKbdStart;    // start of the layout data
    WORD  kbdSize;      // number of bytes in the data
    DWORD pDibData;     // must be zero
    WORD  dibSize;      // must be zero
    DWORD pUnicode      // must be zero
    DWORD nUnicode      // must be zero
} HeaderBlock;

The keyboard layout data begins at the location indicated by the pKbdStart field; typically, it follows immediately after the header. The KBDOFFSET values are offsets from the start of the header block, not the start of the file.

typedef struct {
    WORD Flags;
    WORD nStateKeys;
    WORD nStates;
    WORD nDeadKeys;
    WORD nLigKeys
    KBDOFFSET pkbdxxStates;            // STATE_LIST
    KBDOFFSET pkbdxxToAscStates;       //   TOASC_STATES
    KBDOFFSET pkbdxxToAscStateTables;  //   STATETABLES
    KBDOFFSET pkbdxxToAscVkeyList;     // VKEY_LISTS
    KBDOFFSET pkbdxxToAscVKeyListLens; //   VKEY_LIST_LENS
    KBDOFFSET pkbdxxVKShiftStates;     //   VK_STATES
    KBDOFFSET pkbdxxScanToIdx;         // SCANTOIDX
    KBDOFFSET pkbdxxVKeyToIdx;         //   VKEYTOIDX
    WORD      ScanSize;                //   SCAN_SIZE
    KBDOFFSET pkbdxxVKeyToAnsi;        // VKEYTOANSI
    KBDOFFSET pkbdxxDeadKeyTable;      // DEAD_KEYS
    KBDOFFSET pkbdxxDeadTrans;         //   DEAD_KEYTRANS
    KBDOFFSET pkbdxxLigKeys;           // LIG_KEYS KBDOFFSET
    KBDOFFSET pkbdxxCapsBits;          // VKEY CAPSLOCK Table
    KBDOFFSET pkbdxxKanaNormal;        // DBCS platforms (optional)
} KbdDataHeader;

The entries in the Vkey and character table pairs must be in the same order. Also the scancode table (pkbdxxScanToIdx) is in the same order as the main Vkey table (pkbdxxVKeyToIdx).

The wFlags field can have one of these values:

Value | Meaning
ALTGRUSED | The keyboard layout has ALTGR keys (normal, shifted or both). CAPS LOCK here uses the same CAPS LOCK bitmap as the normal and shifted (non-ALTGR) layout layers.
CAPSNORMAL | The CAPS LOCK key assumes its normal function; that is, it converts alphabetic characters to upper or lower case. Only those keys which are enabled in the CAPS LOCK bitmap will be operated on.
SHIFTLOCKUSED | The keyboard layout does not have a CAPS LOCK key, but does have a SHIFT LOCK key. In the SHIFTLOCKED state all keys are placed in the shifted state, unlike the CAPS LOCK key which would operate only on specific keys.
DEADCOMBOS | Declares that the alternative deadkey list is being used, which allows specification of VKEY and shift states for each deadkey entry in the list.

The CAPSNORMAL and SHIFTLOCKUSED flags are mutually exclusive.

CAPS LOCK BITMAP

The pKbdCapsBits field points to an array of 32 bytes (consisting of 256 bits) where each bit is indexed by the VKEY. If a VKEY's corresponding bit is not set in this CAPS LOCK bitmap, then the CAPS LOCK function will not operate on that VKEY. The CAPSNORMAL flag must be set to enable this bitmap. If the CAPSNORMAL flag is not set then a separate capitalization VKEY and ANSI table must be used. The standard US bitmap is shown in the following, where only the A through Z keys are capitalized.

pkbdxxCapsBits label byte        ; CAPSNORMAL flag must be = 1
  db  0,0,0,0,0,0,0,0            ; Controls & Numerals
  db  0FEh,0FFh,0FFh,07h,0,0,0,0 ; VK_A -> VK_Z & Numpad & Function Keys
  db  0,0,0,0,0,0,0,0            ; Function Keys & OEM Keys
  db  0,0,0,0,0,0,0,0            ; OEM Keys, OEM Controls

Note A CAPS LOCK enabled VKEY is operated on by the CAPS LOCK function even in the ALTGR states, so that ALTGR keys will appear as ALTGR-SHIFT keys when operated on by the CAPS LOCK function.

STATE TABLES

The State list table indicates which basic states are enabled. Only the VK_CAPITAL state is optional (used only when CAPSNORMAL = 0, when the CAPS LOCK bitmap is not used).

pkbdxxStates    label byte
  db  VK_MENU,    080H  ; 1 - Alt state
  db  VK_SHIFT,   080H  ; 2 - Shift state
  db  VK_CONTROL, 080H  ; 4 - Control state
  db  VK_CAPITAL, 001H  ; 8 - CapsLock state (optional)
NSTATEKEYS equ ($ - pkbdxxStates) shr 1

The following two state tables are associated with the state list. The first table provides a list of the state indices. The second table provides the states themselves. State indices 8 through 15 are rarely used because the CAPS LOCK bitmap is usually adequate to provide character capitalization options.

  db  0    ; Normal (must be outside the label)
pkbdxxToAscStates  label byte
  db  1    ; Alt
  db  2    ; Shift
  db  3    ; Alt+Shift
  db  4    ; Control
  db  6    ; Control+Shift
  db  5    ; AltGr
  db  7    ; AltGr+Shift
  db  8    ; CapsLock
  db  9    ; CapsLock + Alt
  db  10   ; CapsLock + Shift
  db  11   ; CapsLock + Alt + Shift
  db  12   ; CapsLock + Control
  db  14   ; CapsLock + Control + Shift
  db  13   ; CapsLock + AltGr
  db  15   ; CapsLock + AltGr + Shift
kbdxx_NSTATES equ $-pkbdxxToAscStates  (total states - 1)

pkbdxxVKShiftStates label byte
  db  0    ; unshifted
  db  0    ; alt                        - (same as unshifted)
  db  1    ; shifted
  db  1    ; alt+shift                  - (same as shifted)
  db  2    ; Control
  db  3    ; Control + Shift
  db  6    ; AltGr                      - \ Alternative characters
  db  7    ; AltGr+Shift                - /
  db  4    ; CapsLock                   - (selective keys shifted)
  db  4    ; CapsLock + Alt             - (same as capslock)
  db  5    ; CapsLock + Shift           - (same as unshifted)
  db  5    ; CapsLock + Alt + Shift     - (same as AltGr)
  db  2    ; CapsLock + Control         - (capslock not applicable)
  db  3    ; CapsLock + Control + Shift - (capslock not applicable)
  db  6    ; CapsLock + AltGr           - (same as shifted AltGr)
  db  7    ; CapsLock + AltGr + Shift   - (same as unshifted AltGr)

LIGATURE TABLES

This allows a ligature codepoint to be unravelled into it's component parts by the keyboard driver prior to being sent to the application.

The format of each entry is shown in the following, where the first four bytes holds the base defining element feature, followed by a count and 16-bit words holding the subsequent characters. There is no limit to the extent of ligatures. The table must be terminated with two zero bytes.

   "1st-codepoint|VKEY|SHIFTSTATE|0|WLength|2nd-codepoint|0|...."

pkbdxxLigKeys label byte
    db 0E1H, VK_A, 0, 0, 1, 0C7H, 0     ;
    db 0E1H, VK_A, 2, 0, 1, 0C2H, 0     ;
    db 0F8H, VK_Q, 5, 0, 1, 0F3H, 0     ;
      db 0,0                              ;table terminator

The ligature itself is identified by the VKEY, associated shiftstate, and the initial character forming the ligature.

DEADKEY TABLES

Non-spacing diacritics are supported with two tables: the first table offers a list of diacritics in one of two forms. The second table offers the combination and resultant tables back-to-back.

pkbdxxDeadKeyTable a list of diacritic keys. Where there is no ambiguity the first table form is used. Where multiple keys are used for the same diacritic then the VKEYs and their associated shift states must be shown in the second form of the deadkey table. The DEADCOMBOS bit must be set in the wFlags field to signal use of the second table form.
    form #1    pkbdxxDeadKeyTable  label byte
       db  GRAVE
       db  UMLAUT
    NDEADKEYS  equ ($ - pkbdxxDeadKeyTable)

    form #2    pkbdxxDeadKeyTable
       db CIRCUMFLEX, VKEY1, 005H, 000H ;
       db RING,       VKEY2, 005H, 000H ;
       db RING,       VKEY3, 002H, 000H ;
    NDEADKEYS  equ  (($ - pkbdxxDeadKeyTable) shr 2)
The deadKey table with shift state, where each DWORD entry is as follows:
        "diacritic-char | Vkey | shiftState | 0"
Legal Shift states are: Normal=0, Shifted=2, AltGr=5, AltGrShift=7
pkbdxxDeadTrans A pair of tables back-to-back. The first table gives the legal diacritic and letter codepoint value combinations. The second table provides the resultant codepoint. The tables must have the same order, and pkbdxxDeadList1 and pkbdxxDeadList2 must be back-to-back.
    pkbdxxDeadTrans label byte ;combination list
      dw  NDEADLIST
    pkbdxxDeadList1 label byte ;(legal diacritic/codepoint combinations)
      db  acute,      'a'
      db  acute,      'A'
      db  acute,      ' '   ;allows spacing acute
      db  tilde,      'N'
      db  tilde,      'N'
      db  tilde,      ' '   ;allows spacing tilde
    NDEADLIST  equ  (($-pkbdxxDeadTrans) shr 1)-1

    pkbdxxDeadList2 label byte ;(resultant accented character codepoint)
      db  0E1h      ;a-acute
      db  0C1h      ;A-acute
      db  acute     ;allows standalone acute
      db  0e3h      ;n-tilde
      db  0c3h      ;N-tilde
      db  tilde     ;allows standalone tilde


Selecting a Keyboard Layout ID

Each keyboard layout must be identified with a unique ID in the registry. The layout ID number is a DWORD (32 bit). The low word bits should be one of the predefined locales found in the NLSAPI specification. The high word should start out as 0000 and be incremented if the ID already exists in the registry.

As an example of how your unique keyboard layout ID could be determined, suppose you have developed a keyboard layout for the former Portuguese colony of Macao. This is basically a Portuguese language keyboard layout with a few changes to adapt Portuguese to the dialect used in the business community of Macao, with its unique Chinese and Indian influences. The lower word of the keyboard layout ID should be 0816 (from the NLSAPI specification). The high word will start out as 0000, but since 0816 already exists, it will become 0001. Thus the final keyboard ID will be 00010816.

You will now need to enumerate the registry at the following location and find the next available ID number. The ID numbers are three (3) digits.

HKEY_LOCAL_MACHINE, "system\currentcontrolset\control\keyboard layouts\<language identifier>\layout id


Keyboard Layout Installation Procedure

If you want your keyboard layout loaded each time the user boots their system, you will need to enumerate the registry at: HKEY_CURRENT_USER, "keyboard layout\preload\#" to find the next available # and then make the following entry:

HKEY_CURRENT_USER,"keyboard layout\preload\#",,<language identifier>

Using our preceding example:

HKEY_CURRENT_USER,"keyboard layout\preload\2",,00010816

If you want to immediately load your keyboard layout for the user you need to use the Win32® LoadKeyboardLayout function.

  • Copy your keyboard layout file (KBD file) to the Windows system directory.
  • Enter the filename of your KBD file and the unique language identifier associated with it in the Windows 95 registry

This cannot be done using an INF file, so you will have to develop an installation program that uses the Win32 functions to copy files and add a key to the registry.

The installation program needs to add to the Registry location HKLM,"system\currentcontrolset\control\keyboard layouts\<language identifier>" the string keys Layout File and Layout Text. Also, if the <language identifier> does not have 0000 in the high word, you will need the to add the layout ID key. The Layout File value should be the filename of the keyboard layout file and Layout Text should be a description of the keyboard layout that can be displayed in the Windows 95 user interface. Using the Portuguese (Macao) example, after your installation program runs the following values and keys should be added to the registry (assuming the name of your keyboard layout file is KBDPM.KBD:

HKLM,"system\currentcontrolset\control
    \keyboard layouts\00010816","layout file",,kbdpm.kbd
HKLM,"system\currentcontrolset\control
    \keyboard layouts\00010816","layout text",,"Portuguese (Macao)"
HKLM,"system\currentcontrolset\control
    \keyboard layouts\00010816","layout id",,013


New Keyboard Layout User Documentation

You should provide documentation to the users of the new keyboard layout that the user can select any language they want, but should then select Properties to access the new keyboard layout.


Miscellaneous Keyboard Services

The keyboard driver provides a number of additional services to Windows and Windows applications. These miscellaneous services are provided by the following functions:

EnableKBSysReq | GetKeyboardType
GetBIOSKeyProc | GetKeyNameText
GetKBCodePage | SetSpeed

See Also

EnableKBSysReq, GetKeyboardType, GetKeyNameText, GetKBCodePage, SetSpeed


Reference

The following topics contain the reference information.


AnsiToOem

WORD AnsiToOem(
  LPSTR lpSrc,
  LPSTR lpDst
 );

Translates a string in the ANSI character set to a string in the OEM character set. For most computers, the OEM character set is code page 437.

  • Return 0FFFF in AX if successful.
lpSrc and lpDst
Address of the input ANSI string, and address of the output OEM string.

The export ordinal for this function is 5.

The lpSrc and lpDst parameters may point to the same buffer.

The code page used to translate the character depends on the current code page. For most drivers, the default translation is code page 437 (the standard U.S. IBM-PC character set).

Strings longer than 64K may be translated.

See Also

AnsiToOemBuff, Enable, OemToAnsi


AnsiToOemBuff

void AnsiToOemBuff(
  LPSTR lpSrc,
  LPSTR lpDst,
  WORD nCount
 );

Translates a string of ANSI characters to OEM. However, use this function to translate fixed-length byte arrays, such as database records, which may contain null characters.

  • This function has no return value.
lpSrc and lpDst
Address of the input ANSI string, and address of the output OEM string.
nCount
Byte count.

The export ordinal for this function is 134.

The lpSrc and lpDst parameters may point to the same buffer.

See Also

AnsiToOem, OemToAnsiBuff


Disable

void Disable(void)

Restores the original keyboard-interrupt handler when exiting Windows.

  • No return value.

The export ordinal for this function is 3.

The Disable function restores the keyboard-interrupt vector (usually Interrupt 9) to the keyboard handler that was previously installed.

Disable is called when exiting Windows and before starting or switching to a full-screen, MS-DOS application running under standard-mode Windows.

When Disable is called, the BIOS keyboard flags (40h:17h in most IBM-compatible systems) must reflect the state of the SHIFT LOCK, NUMLOCK, and SCROLL LOCK keys. Normally, the keyboard driver's hardware-interrupt handler will handle this.

The keyboard and mouse Enable functions are always called in the reverse order of the keyboard and mouse Disable functions because some mouse drivers may hook into the keyboard interrupt.

See Also

Disable, Enable


Enable

void Enable(
  FARPROC eventProc,
  LPBYTE lpKeyState
 );

Installs the hardware interrupt for Windows, and performs the necessary initialization of the driver.

  • No return value.
eventProc
Address if Windows keyboard-event function.
lpKeyState
Address of the 256-byte, Windows virtual key-state array.

The export ordinal for this function is 2.

The Enable function saves the address of the original keyboard hardware-interrupt handler in static memory. The driver maintains the shift and numeric lock state, and the state of indicator lights. Linkage with a language-specific keyboard library should be established (if one exists).

Enable is called once when you start Windows. It is also called when returning to Windows from a full-screen application for which the keyboard was disabled.

See Also

Disable


EnableKBSysReq

WORD EnableKBSysReq(
  WORD fWord
 );

Enables and disables the CTRL+ALT+SYSREQ trap to the debugger or Microsoft CodeView® (CVW).

  • Returns the state of the SYSREQ key traps. The return value consists of the following bit values.
Bit | Meaning
0 | Set to 1 to indicate Interrupt 2 enabled; 0 indicates that INT 2 is disabled.
1 | Set to 1 to indicate CVW Break enabled; 0 indicates that CVW Break is disabled.

All other bits are reserved.

fWord
Specifies the action to take. This parameter can be one of the following values.
Value | Meaning
01h | Enables Interrupt 2
02h | Disables Interrupt 2
04h | Enables CVW Break
08h | Disables CVW Break

The export ordinal for this function is 136.

The initial behavior is to ignore CTRL+ALT+SYSREQ. If both Interrupt 2 and CVW are enabled, then CVW overrides.


GetBIOSKeyProc

FARPROC GetBIOSKeyProc(void)

Retrieves the address of the BIOS keyboard interrupt service routine.

  • Returns the address of the BIOS routine.

The export ordinal for this function is 137.


GetKBCodePage

WORD GetKBCodePage(void)

Identifies which OEM/ANSI translation table and code page the keyboard driver is using.

  • Returns the current code page in AX. The code page indicates which OEM/ANSI translation-table file is loaded.

The export ordinal for this function is 132.

The following lists the possible code pages and corresponding OEM/ANSI translation-table files.

Value | Meaning and Filename
437 | Default (U.S., most countries/regions. No OEMANSI.BIN file)
860 | Portugal (XLATPO.BIN)
863 | French Canada (XLATCA.BIN)
865 | Norway/Denmark (XLATNO.BIN)
850 | International code page (XLAT850.BIN)

If the OEMANSI.BIN setting in the [Keyboard] section of the SYSTEM.INI file specifies an OEMANSI translation-table file, the keyboard driver loads the file and sets the code page to the specified code page.

Because code page 437 is the default, if the OEMANSI.BIN setting is blank, the keyboard driver uses the default translation table and code page. For most drivers, the default code page is 437.


GetKeyboardType

WORD GetKeyboardType(
  WORD wWhich
 );

Identifies the type of keyboard.

  • Returns a keyboard type or an OEM subtype, depending on the value of the wWhich parameter.
wWhich
Flag that specifies whether the function returns a keyboard type or an OEM subtype. If the parameter is 0, the function returns the basic type. If the parameter is 1, the function returns the OEM subtype.

The export ordinal for this function is 130.

If a keyboard type is requested (wWhich is 0), the function returns one of these keyboard types:

Value | Meaning
1 | IBM PC, XT or compatible (83 key)
2 | Olivetti M24 "ICO" (102 key)
3 | IBM AT (84 keys) or similar
4 | IBM Enhanced (101 or 102 keys)
5 | Nokia 1050
6 | Nokia

If a keyboard subtype is requested (wWhich is 1), the function returns a nonzero OEM-dependent subtype or zero to indicate that no subtypes are available.


GetKeyNameText

int GetKeyNameText(
  DWORD lParam,
  LPSTR lpstr,
  WORD wSize
 );

Retrieves a string that represents the name of a key.

  • Returns the length of the string, in characters, not counting the terminating null character.
lParam
Second parameter of the keyboard message (such as WM_KEYDOWN) to be processed. The function interprets the following portions of lParam:
Bits | Meaning
16-23 | Scan code.
24 | Extended-key flag. Distinguishes some keys on an enhanced keyboard.
25 | "Don't care" bit. Indicates the function should not distinguish between left and right CTRL and SHIFT keys, for example.

lpstr
Address of a buffer that receives the key name.
wSize
Maximum length, in characters, of the key name, not including the terminating null character (this parameter should be one less than the size of the buffer pointed to by the lpstr parameter).

The export ordinal for this function is 133.


Inquire

int Inquire(
  LPKBINFO  lpKBInfo
 );

Fills a KBINFO structure with information about the keyboard hardware.

  • Returns the number of bytes copied to lpKBInfo.
lpKBInfo
Address of the KBINFO structure that receives the keyboard information.

The export ordinal for this function is 1.

New keyboard drivers should support both the Inquire and InquireEx functions.

See Also

KBINFO, InquireEx


InquireEx

int InquireEx(
  WORD wAction,
  LPKBINFO lpKBInfo,
  int nCount
 );

Sets and retrieves keyboard information.

  • Returns a value that depends on the wAction parameter.
wAction
Action flag. Can be one of these values:
Value | Meaning and return value
INQEX_KBDINFO (1) | Retrieves keyboard information. Returns, in AX, the number of bytes copied to the buffer.
INQEX_NLCID (2) | Retrieves the number of layouts currently in the driver. Returns the number in AX.
INQEX_LPLCID (3) | Retrieves the list of layouts currently installed in the driver. Returns the number of layouts in in the list.
INQEX_KEYBOARDTYPE (4) | Retrieves the keyboard type.
INQEX_KEYBOARDSUBTYPE(5) | Retrieves the keyboard sub-type.
INQEX_NFUNCKEYS(6) | Retrieves the number of function keys.
INQEX_SETBASELOCALE (7) | Sets the current locale. No return value.
INQEX_SETSYSLOCALE (8) | Sets the system locale. No return value.

lpKBInfo
Value depends on wAction. Can be one of these values:
Value of wAction | Meaning of lpKBInfo
INQEX_KBDINFO (1) | Address of a KBINFO structure that that receives the information.
INQEX_LPLCID (3) | Address of a buffer containing an array of layout identifiers.
INQEX_SETBASELOCALE (7) | Locale identifier.
INQEX_SETSYSLOCALE (8) | Locale identifier

The lpKBInfo parameter is not used if wAction specifies any other value.

nCount
Number of layout identifiers in the lpKBInfo buffer. This parameter is used only if wAction specifies INQEX_LPLCID.

The export ordinal for this function is 9.

New keyboard drivers should support both the InquireEx and Inquire functions.

See Also

Inquire


Keyboard_Event

mov     ah, UpDownFlag   ; 00h for down stroke, 80h for up stroke
mov     al, VirtualKey   ; Windows virtual-key code
mov     bh, PrefixFlag   ; 00h if no prefix, 1 if 0E0h prefix byte
mov     bl, ScanCode     ; hardware scan code

mov     si, word ptr [ExtraInfo]
mov     di, word ptr [ExtraInfo+2]  ; extra information

call    [Keyboard_Event]            ; keyboard-event function

Records a keystroke. The keystroke may subsequently be used to generate a WM_KEYUP or WM_KEYDOWN message. The keyboard driver's interrupt handler calls this function.

  • No return value.
UpDownFlag
Key up or down flag. The parameter is 0x00h for a down stroke and 80h for an up stroke.
VirtualKey
Virtual-key code. The code must be a value in the range 1 to 254.
PrefixFlag
Flag that specifies whether the scan code was preceded by the 0E0h prefix byte. The parameter is 00h if there was no prefix byte, and is 1 if there was a prefix byte.
ScanCode
Hardware-scan code.
ExtraInfo
32-bit value associated with the key stroke.

Although the keyboard driver passes the hardware-scan code (which is OEM-dependent) to Windows, Windows does not use the code. Instead, Windows subsequently passes the scan code to the ToAscii function, which may use it for special purposes. The interrupt handler sets the up/down bit in the scan code to 0.

This interrupt handler may process some keystrokes without passing them to Windows through the keyboard-event callback function. In particular, the handler processes CTRL+ALT+SYSREQ keytrokes and generates a nonmaskable interrupt (NMI). Under certain circumstances, the driver's interrupt handler passes keystrokes to the original keyboard-interrupt handler. This is the case for CTRL+ALT+DELETE key combination and for the PAUSE key.

Use the PRINTSCREEN key to take a screen snapshot, which is saved in the Windows clipboard. This is handled in the interrupt routine by calling the event procedure with VK_SNAPSHOT in AL, with the value equal to 0 (for full-screen snapshot) or 1 (for active-window snapshot) in BL.

See Also

Enable, ToAscii


MapVirtualKey

int MapVirtualKey(
  WORD  wCode,
  WORD  wMapType
 );

Maps scan codes to virtual-key codes, and virtual-key codes to either scan codes or ANSI character. This function is intended to be used by the Program Information File (PIF) Editor and Windows to get information about keyboard mapping.

  • Returns, in AX, a nonzero scan code or virtual-key code, if successful. Returns zero if mapping cannot be performed.
wCode
Input scan code or virtual-key code.
wMapType
Mapping to carry out. Can be one of these values.
Value | Meaning
0 | Map virtual key to scan code.
1 | Map scan code to virtual key.
2 | Map virtual key to ASCII character.

The export ordinal for this function is 131.

For the first two mappings, the scan code to virtual-key code translation table is examined to determine the translations. Some valid codes may not be translated in this table.

For the third type of mapping, uppercase letters A through Z are returned for VK_A through VK_Z. ASCII characters are returned for the top-row numeric keys VK_0 through VK_9. For punctuation and dead keys in the main part of the keyboard, the unshifted character will be returned.

New keyboard drivers should support both MapVirtualKey and MapVirtualKeyEx. To support MapVirtualKey, call MapVirtualKeyEx with the lcid parameter set to the system locale id.

See Also

AnsiToOem, OemToAnsi, MapVirtualKeyEx


MapVirtualKeyEx

int MapVirtualKeyEx(
  WORD wCode,
  WORD wMapType,
  DWORD lcid
 );

Maps scan codes to virtual-key codes, and virtual-key codes to either scan codes or ANSI character. The mapping is based on the specified locale. This function is intended to be used by the Program Information File (PIF) Editor and Windows to get information about keyboard mapping.

  • Returns, in AX, a nonzero scan code or virtual-key code, if successful. Returns zero if mapping cannot be performed.
wCode
Input scan code or virtual-key code.
wMapType
Mapping to carry out. Can be one of these values.
Value | Meaning
0 | Map virtual key to scan code.
1 | Map scan code to virtual key.
2 | Map virtual key to ASCII character.

lcid
Layout identifier. This must be a valid identifier as passed to the driver via the NewtableEx function.

The export ordinal for this function is 12.

For the first two mappings, the scan code to virtual-key code translation table is examined to determine the translations. Some valid codes may not be translated in this table.

For the third type of mapping, uppercase letters A through Z are returned for VK_A through VK_Z. ASCII characters are returned for the top-row numeric keys VK_0 through VK_9. For punctuation and dead keys in the main part of the keyboard, the unshifted character will be returned.

See Also

NewTableEx


NewTable

The NewTable function is obsolete. New keyboard drivers should return FALSE to a call to this function, and they should support the NewTableEx function.

See Also

NewTableEx


NewTableEx

void NewTableEx(
  LPSTR lpszFileName,
  DWORD dwLayout
 );

Loads a new keyboard layout and and associates it with the specified language, or or removes the specified keyboard layout.

  • Returns nonzero if the function succeeds, zero otherwise.
lpszFileName
Name of keyboard layout to load, or NULL to remove a layout.
dwLayout
Identifier of the layout to associate with the new keyboard layout, if lpszFileName is not NULL.; otherwise, dwLayout specifies the identifier of the keyboard layout to remove.

The export ordinal for this function is 13.

If the language of the keyboard layout exists, the layout associated with the language is replaced with the new layout.

See Also

NewTable


OEMKeyScan

DWORD OEMKeyScan(
  WORD wOemChar
 );

Maps OEM codes (0 through 0FFH) into scan codes and shift states. This function provides information that enables a program to send OEM text to another program by simulating keyboard input. Windows, when running in 386 enhanced mode, uses it specifically for this purpose.

  • Returns the scan code in AX and the shift state in DX. If the character is not defined in the tables, the return value is -1 in both DX and AX.
wOemChar
ASCII character.

The export ordinal for this function is 128.

The bits in the shift state returned in DX have the following meaning.

Bit | Value
1 | 1 if the SHIFT key is down; 0 otherwise.
2 | 1 if CTRL and SHIFT is down; 0 otherwise.

This function does not provide translations for characters that require the CTRL+ALT key combination or dead keys.

This function calls VkKeyScan.

See Also

VkKeyScan


OemToAnsi

int OemToAnsi(
  LPSTR lpSrc,
  LPSTR lpDst
 );

Translates a string in the current OEM character set to ANSI.

  • Returns 0FFFF in AX.
lpSrc and lpDst
Address of the input ANSI string, and the output OEM string.

The export ordinal for this function is 6.

The lpSrc and lpDst parameters may point to the same buffer.

The code page used to translate the character depends on the current code page (as set when Windows calls the Enable function). For most drivers, the default translation is code page 437 (the standard U.S. IBM-PC character set).

Strings longer than 64K may be translated.

See Also

AnsiToOem, Enable, OemToAnsiBuff


OemToAnsiBuff

void OemToAnsiBuff(
  LPSTR lpSrc,
  LPSTR lpDst,
  WORD nCount
 );

Translates a string of OEM characters to ANSI. However, use this function to translate fixed-length byte arrays, such as database records, which may contain NULL bytes.

  • This function has no return value.
lpSrc and lpDst
Address of the input ANSI string, and the output OEM string.
nCount
Length, in bytes, of the input string.

The export ordinal for this function is 135.

The lpSrc and lpDst parameters may point to the same buffer.

The code page used to translate the character depends on the current code page (as set when Windows calls the Enable function). For most drivers, the default translation is code page 437 (the standard U.S. IBM-PC character set).

See Also

Enable, OemToAnsi, AnsiToOemBuff


ScreenSwitchEnable

void ScreenSwitchEnable(
  WORD wEnable
 );

Obsolete. Always returns a non-zero value under Windows 95.


SetSpeed

int SetSpeed(
  int Rate
 );

Sets the repeat rate of the keyboard. This function is intended to be used by Control Panel and by the initialization of Windows.

  • Returns the repeat rate, or a value specifying whether the repeat rate can be set.

    If Rate is a repeat rate (not -1), the return value is the repeat rate actually set on the keyboard if it is successful. If it could not set a new rate, the return value is -1.

    If Rate is -1, the return value is 0 if the repeat rate speed can be set. Otherwise, it is -1.

Rate
Repeat rate. The lowest 5 bits define the desired repeat rate. If Rate is -1, the return value is a value indicating speed-setting capability.

The export ordinal for this function is 7.

This function is used in conjunction with Control Panel for setting the keyboard repeat rate.

If the keyboard speed cannot be set from software, this function may be reduced to a stub which always returns -1. In that case, Control Panel will not display a menu selection for setting keyboard speed.


ToAscii

New keyboard drivers should support the ToAscii function by calling the ToAsciiEx function with lcid set to the system locale id.

See Also

ToAsciiEx, KBINFO


ToAsciiEx

int ToAscii(
  WORD VirtKey,
  WORD Scancode,
  LPSTR lpKeyState,
  LPSTR lpState,
  WORD KeyFlags,
  DWORD lcid
 );

Translates the virtual-key code passed to it, along with the current keyboard state, to an ANSI character. The translation is based on the specified layout.

  • Returns the number of characters returned in the state block. The number of characters is returned in AX. The lpState parameter receives the address of the state block. Returns one of the following values.
Value | Description
AX > 0 | The lpState parameter is the address of a buffer that contians the number of characters specified in AX. These are "standard" characters and will be processed with WM_CHAR messages. The usual values are one and two. Normally, when two characters are returned they are an accent and a dead-key character, when a dead key cannot be translated otherwise.
0 | This virtual-key code has no translation (for the current state of shift keys, and so on).
AX < 0 | Dead keys. The characters returned are ANSI accent characters representing the dead keys.

VirtKey
Virtual-key code.
Scancode
Hardware-scan code and shift state. The scan code is in the low-order byte, and the shift state is in the high-order byte. The bits in the shift state have the following meaning.
Bit | Meaning
15 | 1 if the key is up; 0 if the key is down.
14 | 1 if the key was previously up; 0 if the key was previously down.
13 | 1 if the ALT key is down.
12 | 1 if Windows displays a menu.
11 | 1 if Windows displays a dialog box.
10 | Not used.
9 | Not used.
8 | 1 if the key is extended; 0 if it is not.

Bits 0 through 6 are the hardware-scan code (used mainly in the translation of ALT+number-pad character code input). Bit 7 is generally 0.

lpKeyState
Address of the virtual key-state array maintained by Windows.
lpState
Address of the state block. It is used mainly for the output of ANSI characters.
KeyFlags
Specifies duplicate shift-state information. The bits have the following meaning.
Bit | Meaning
0 | 1 if a menu is displayed, 0 if not.
1 | 1 if an extended key, 0 if not.

lcid
Layout identifier.

The export ordinal for this function is 10.

The ToAsciiEx function is called mainly whenever TranslateMessage is called to translate a virtual-key code (for example, for WM_KEYDOWN messages).

The given parameters of ToAsciiEx are not necessarily sufficient to translate the virtual-key code. This is because a previous dead key is stored internally in the driver. Also, the MS-DOS shift-state byte is accessed by ToAsciiEx.

ToAsciiEx is responsible for maintaining the state of the keyboard LED indicator lights. For most AT-compatible computers, this is done by making a ROM BIOS interrupt 16H call; for others, I/O must be done directly through the keyboard.

ToAsciiEx also has a special case which, if it is called with the virtual-key code equal to 0, will only set the keyboard lights according to the state of the appropriate entries in the keyboard-state vector. This function is intended to be called from the SetKeyboardState function and not directly used by applications. The Scancode parameter is ignored. The vector pointed to by lpState should be different from the one used by ToAsciiEx calls in the USER module. The vector should be at least 4 bytes long.

Most translations are made on the basis of the Windows virtual-key code. However, the Scancode parameter's sign bit is used to distinguish key depressions (sign cleared) from key releases (sign set). Also, the scan code is used in the translation of ALT + number-key translations.

The lpKeyState parameter Address of a 256-byte array indexed by the virtual-key code. In each byte, the high-order bit indicates the state of the key and the low-order bit is toggled each time the key is pressed. The CAPSLOCK key is handled in a special manner for some European keyboards.

The lpState parameter Address of a data buffer that contains the translated character(s) and state information. The InquireEx function in the KBINFO structure returns the size required for this state buffer.

See Also

KBINFO


VkKeyScan

The VkKeyScan function is obsolete. New keyboard drivers should support the VkKeyScan function by calling the VkKeyScanEx function with the layout identifier set to the system locale layout identifier.

See Also

OEMKeyScan, VkKeyScanEx


VkKeyScanEx

int VkKeyScanEx(
  WORD wChar,
  DWORD lcid
 );

Translates an ANSI character code into a virtual-key code and a shift state. The translation is based on the specified locale. It is intended for applications that send text to other applications by simulating keyboard input.

  • Returns a virtual-key code in AL and a shift state AH, if successful; otherwise, returns 1 in AX.
wChar
ANSI character to translate.
lcid
Locale identifier.

The export ordinal for this function is 11.

The returned shift state is one of the following values:

Value | Meaning
0 | No shift.
1 | Character is shifted.
2 | Character is CTRL character.
6 | Character is CTRL + ALT.
7 | Character is SHIFT + CTRL + ALT.

The values 3, 4, and 5 are not used.

Virtual-key codes applying to the numeric pad (VK_NUMPAD0 through VK_DIVIDE) are not returned. This is done to force a translation for the main keyboard, if it exists.

See Also

OEMKeyScan


KBINFO

typedef struct tagKBINFO {
    BYTE  Begin_First_range;  /* see below */
    BYTE  End_First_range;    /* see below */
    BYTE  Begin_Second_range; /* see below */
    BYTE  End_Second_range;   /* see below */
    int   StateSize;          /* size, in bytes of ToAscii state block*/
} KBINFO;

Contains information about the keyboard.

Begin_First_range
Low value in the range of valid lead-byte values for double-byte character sets (DBCS).
End_First_range
High value in the range of valid lead-byte values for double-byte character sets (DBCS).
Begin_Second_range
Low value in the range of valid second-byte values for double-byte character sets (DBCS).
End_Second_range
High value in the range of valid second-byte values for double-byte character sets (DBCS).

See Also

Inquire


OEMANSI

OEMANSI struct
    oaLength    dw ?          ; count of bytes that follow (must be 258)
    oaCodePage  dw ?          ; see below
    oaTable     db 256 dup(?) ; OEM/ANSI translation table
OEMANSI ends

Contains information needed to translate OEM character values, in a given code page, to their corresponding ANSI character values.

oaCodePage
Code page of the given translation table. Can be one of these values:
Value | Description
437 | Default (U.S.)
860 | Portugal
863 | French Canada
865 | Norway/Denmark
850 | International code page

oaTable

Array of translation values.


Virtual Keyboard Device

The virtual keyboard device virtualizes keyboard input, supports Windows shell hotkeys, provides for pasting text into a virtual machine, and manages keyboard input when in message mode.

The VKD provides the following services:

VKD_API_Force_Key

VKD_API_Get_Version

VKD_Cancel_Hot_Key_State

VKD_Cancel_Paste

VKD_Define_Hot_Key

VKD_Define_Paste_Mode

VKD_Disable_Keyboard

VKD_Enable_Keyboard

VKD_Filter_Keyboard_Input

VKD_Flush_Msg_Key_Queue

VKD_Force_Keys

VKD_Get_Kbd_Owner

VKD_Get_Msg_Key

VKD_Get_Shift_State

VKD_Get_Version

VKD_Local_Disable_Hot_Key

VKD_Local_Enable_Hot_Key

VKD_Peek_Msg_Key

VKD_Put_Byte

VKD_Reflect_Hot_Key

VKD_Remove_Hot_Key

VKD_Set_Shift_State

VKD_Start_Paste


Reference

The following topics contain an alphabetic listing of the virtual keyboard (VKD) services.


VKD_API_Force_Key

include vkd.inc
mov     ebx, VMHandle
mov     ch, ScanCode
mov     cl, RepeatCount
mov     edx, ShiftState
VxDCall VKD_API_Force_Key
jc      errorhandler

Forces a key into a virtual machine as if it were typed on the keyboard. Because the VKD scans these forced keys for hot keys, forcing VKD hot keys is allowed. Uses Flags. Clears the carry flag upon success, sets it upon failure.

  • No return value.
VMHandle
Handle of the virtual machine, or 0 for the virtual machine that currently has the focus.
ScanCode
Scan code.
RepeatCount
Repeat count (1 or more).
ShiftState
Shift state (1 means no change).

This service is currently limited to the focus virtual machine, so the service fails if VMHandle is not zero or not the focus virtual machine handle.


VKD_API_Get_Version

include vkd.inc

VxDCall VKD_API_Get_Version
mov     byte ptr [MajorVersion], ah
mov     byte ptr [MinorVersion], al

Retrieves the version number of the VKD. Uses EAX and Flags; clears the carry flag.

  • Returns the major version number in AH and the minor version number in AL.


VKD_Cancel_Hot_Key_State

include vkd.inc

VxDCall VKD_Cancel_Hot_Key_State

Cancels the hot key state.

  • No return value.


VKD_Cancel_Paste

include vkd.inc

mov     ebx, VMHandle
VxDCall VKD_Cancel_Paste

Cancels the paste that was started in the virtual machine by the VKD_Start_Paste service. Uses EAX and Flags.

  • No return value.
VMHandle
Handle of the virtual machine.

See Also

VKD_Start_Paste


VKD_Define_Hot_Key

include vkd.inc

mov     al, ScanCode
mov     ah, type
mov     ebx, ShiftState
mov     cl, flag
mov     esi, OFFSET32 HotKeyProc
mov     edx, OFFSET32 refdata
mov     edi, max_delay
VxDCall VKD_Define_Hot_Key
jc      errorhandler

Defines a hot-key-notification callback function. Hot keys are detected by ANDing the shift state mask with the global shift state, then comparing the resulting state with the shift state compare value. If this matches and the key code matches, the callback function is called with the specified reference data in EDX. Uses EAX, ESI, and Flags. Clears the carry flag upon success, sets it upon failure.

  • Returns the definition handle in EAX if successful.
ScanCode
Scan code of the main key.
type
Type of scan code. Can be one of these values:
Value | Meaning
0 | Normal code
1 | Extended code (ExtendedKey_B)
0FFh | Either normal or extended (AllowExtended_B)

ShiftState
Shift state. The high word is a mask that is ANDed with the global shift state when checking for this hot key. The low word is the masked-shift-state-compare value.
flag
Operation flag. Can be one of these values:
Value | Meaning
CallOnAll | Calls on press, release, and repeats of hot keys.
CallOnComplete | Calls callback when the hot key state is ended (all shift modifier keys are released), or when a different hot key is entered. For example, assume that both ALT+1 and ALT+2 are hot keys. If the user holds the ALT key down, then presses and releases the 1 key and presses the 2 key, the callback for ALT+1 is called even though the ALT key has not been released.
CallOnPress | Calls callback when key press is detected.
CallOnRelease | Calls callback when key release is detected. Keyboard may still be in hot-key hold state.
CallOnRepeat | Calls callback when repeated press is detected.
CallOnUpDwn | Calls on both press and release of hot keys.
Local_Key | Specifies that the key can be locally enabled or disabled.
Monitor_Key | Automatically reflects the hot key. This value can be used only with the CallOnPress, CallOnRelease, and PriorityNotify values.
PriorityNotify | Specifies that the callback can only be called when interrupts are enabled and the critical section is not owned. This value can be combined with any other value in this list.

HotKeyProc
Address of the callback function. For more information about the callback function, see the following comments.
refdata
Address of the reference data to pass to the callback function.
max_delay
Maximum notification delay in milliseconds if the flag specifies the PriorityNotify value. If this parameter is zero, the callback function is always notified.

The callback function is called when a hot key is detected, and detection meets mask requirements. The callback function receives the following input parameters:

AL    ; scan code of key
AH    ; 0 if key just pressed (Hot_Key_Pressed)
      ; 1 if key just released (Hot_Key_Released)
      ; 2 if key is an auto-repeat press (Hot_Key_Repeated)
      ; 3 hot key state ended (Hot_Key_Completed)

EBX   ; hot key handle
ECX   ; global shift state
EDX   ; points to the reference data
EDI   ; elapsed time for delayed notification in milliseconds

The EDI register normally contains zero, but if the PriorityNotify value is specified this value could be larger.

The high bit of AH is set if the hot key is a priority hot key, and the virtual machine which had the keyboard focus at the time the hot key was recognized was suspended or not executable. In this case, the priority event was scheduled for the system virtual machine rather than the keyboard owner. The Hot_Key_SysVM_Notify value can be used to check this bit.

The callback function can modify EAX, EBX, ECX, EDX, ESI, EDI, and Flags


VKD_Define_Paste_Mode

include vkd.inc

mov     ah, interrupt
mov     ebx, VMHandle
VxDCall VKD_Define_Paste_Mode

Selects the virtual-machine paste mode and specifies whether Interrupt 16h pasting can be attempted or not. Some applications hook Interrupt 09h which often disallows pasting using Interrupt 16h. The VKD can detect this by setting a time out to see if any Interrupt 16h handling is being done by the application. If not, the VKD switches to Interrupt 09h paste.

If an application does some Interrupt 16h handling, but cannot support the Interrupt 16h paste operation, a PIF bit can be set to indicate that only Interrupt 09h pasting should be used. Uses Flags.

  • No return value.
interrupt
Interrupt flag that specifies whether to use Interrupt 16h or Interrupt 09h to paste. Can be one of these values:
Value | Meaning
0 | Allows Interrupt 16h paste attempts
1 | Forces Interrupt 09h pasting

VMHandle
Handle of the virtual machine.


VKD_Disable_Keyboard

include vkd.inc

mov     ebx, VMHandle
VxDCall VKD_Disable_Keyboard

Masks IRQ 1, sends a disable command to the keyboard, and disables trapping of ports 60h and 64h. This service is mainly for use by the virtual mouse device while it is initializing PS/2 style mice. Uses EAX, EDX, and Flags.

  • No return value.
VMHandle
Handle of the virtual machine.

See Also

VKD_Enable_Keyboard


VKD_Enable_Keyboard

include vkd.inc

VxDCall VKD_Enable_Keyboard

Enables the keyboard after it has been disabled by a previous call to the VKD_Disable_Keyboard service. This service is mainly for use by VMOUSE while it is initializing a PS/2 style mouse. Uses EAX, EDX, and Flags.

  • No return value.

See Also

VKD_Disable_Keyboard


VKD_Filter_Keyboard_Input

include vkd.inc

VxDCall VKD_Filter_Keyboard_Input
mov     ScanCode, cl

Allows a virtual device to monitor keyboard input and either modify or reject keyboard keystrokes. To monitor keyboard input, a virtual device must hook this service. The virtual device sets the carry flag to reject a keystroke , or clears the carry flag to continue processing the keystroke. Uses Flags.

  • Returns the scan code of the keystroke in CL, if if the carry flag is clear.


VKD_Flush_Msg_Key_Queue

include vkd.inc

mov     ebx, VMHandle
VxDCall VKD_Flush_Msg_Key_Queue

Flushes any available keys from the special message-mode input buffer. Uses Flags

  • No return value.
VMHandle
Handle of the virtual machine.


VKD_Force_Keys

include vkd.inc

mov     esi, OFFSET32 ScanCodes
mov     ecx, num_ScanCodes
VxDCall VKD_Force_Keys
jc      errorhandler

Forces scan codes into the keyboard buffer just as if they had been typed on the physical keyboard. These keys are processed in the context of the focus virtual machine. Uses Flags. Clears the carry flag upon success, sets it if the keyboard buffer overflows.

  • Returns, in ECX, the number of remaining scan codes that did not fit in the keyboard buffer.
ScanCodes
Address of the buffer that contains scan codes.
num_ScanCodes
Number of scan codes in the buffer.


VKD_Get_Kbd_Owner

include vkd.inc

VxDCall VKD_Get_Kbd_Owner
mov     VMHandle, ebx

Retrieves the virtual machine handle of the keyboard focus virtual machine. Uses EBX and Flags.

  • Returns the handle in EBX.


VKD_Get_Msg_Key

include vkd.inc

VxDCall VKD_Get_Msg_Key
jz      no_key_avaliable

Returns the next available key from the special message mode input buffer, and removes it from the buffer. The zero flag is clear if a key is available; otherwise, it is set. This service does not block. Uses EAX and Flags.

  • Returns the scan code in AL if the zero flag is clear, and a combination of these flags in AH:
Value | Meaning
MK_Alt | An ALT key is down.
MK_Ctrl | A CTRL key is down.
MK_Extended | The key is an extended key.
MK_Shift | A SHIFT key is down.

VMHandle
Handle of the virtual machine.


VKD_Get_Shift_State

include vkd.inc

mov     ebx, VMHandle
VxDCall VKD_Get_Shift_State
mov     ShiftState, ax

Retrieves the shift state for the given virtual machine. Uses EAX and Flags.

  • Returns the shift state in AX. For the meanings of the bits in the shift state, see the VKD.INC include file.
VMHandle
Handle of the virtual machine.

See Also

VKD_Set_Shift_State


VKD_Get_Version

include vkd.inc

VxDCall VKD_Get_Version
mov     byte ptr [MajorVersion], ah
mov     byte ptr [MinorVersion], al

Retrieves the version number of the VKD. Uses EAX and Flags.

  • Returns the major version number in AH and the minor version number in AL.


VKD_Local_Disable_Hot_Key

include vkd.inc

mov     eax, hHotKey
mov     ebx, VMHandle
VxDCall VKD_Local_Disable_Hot_Key

Disables a hot key in the specified virtual machine. Uses Flags.

  • No return value.
hHotKey
Handle of the hot key.
VMHandle
Handle of the virtual machine.


VKD_Local_Enable_Hot_Key

include vkd.inc

mov     eax, hHotKey
mov     ebx, VMHandle
VxDCall VKD_Local_Enable_Hot_Key

Enables a hot key in the specified virtual machine. Uses Flags.

  • No return value.
hHotKey
Handle of the hot key.
VMHandle
Handle of the virtual machine.


VKD_Peek_Msg_Key

include vkd.inc

mov     ebx, VMHandle
VxDCall VKD_Peek_Msg_Key
jz      no_key_avaliable

Retrieves the next available key from the special message-mode input buffer without removing it from the buffer. The zero flag is clear if a key is available; otherwise, it is set. Uses EAX andFlags.

  • Returns the scan code in AL if the zero flag is clear, and a combination of these flags in AH:
Value | Meaning
MK_Alt | An ALT key is down.
MK_Ctrl | A CTRL key is down.
MK_Extended | The key is an extended key.
MK_Shift | A SHIFT key is down.

VMHandle
Handle of the virtual machine.


VKD_Put_Byte

include vkd.inc

mov al, MsgByte
VxDCall VKD_Put_Byte
jc      queue_full

Puts a byte into the system message queue, if possible. Sets the carry flag is set if the message queue is full; otherwise, it is clear. Uses Flags.

  • No return value.
MsgByte
Byte of data to put into the system message queue.


VKD_Reflect_Hot_Key

include vkd.inc

mov     eax, hHotKey
mov     ebx, VMHandle
mov     cx, shift
VxDCall VKD_Reflect_Hot_Key

Reflects a hot key into a specified virtual machine and cancels the hot key state. This service is normally called by a hot-key-notification callback procedure. It allows the callback to send the hot key into a virtual machine and without processing it as a hot key. VKD simulates the required key strokes to get the virtual machine into the specified shift state, then it simulates the key strokes for the hot key itself, and finally simulates key strokes to get the virtual machine to match the current global shift state. Uses Flags

  • No return value.
hHotKey
Handle of the hot key.
VMHandle
Handle of the virtual machine.
ShiftState
Required shift state.


VKD_Remove_Hot_Key

include vkd.inc

mov     eax, hHotKey
VxDCall VKD_Remove_Hot_Key

Removes a defined hot key. Uses Flags.

  • No return value.
hHotKey
Handle of the hot key to remove. This handle must have been previously created using the VKD_Define_Hot_Key service.

See Also

VKD_Define_Hot_Key


VKD_Set_Shift_State

include vkd.inc

mov     ebx, VMHandle
mov     ax, ShiftState
VxDCall VKD_Set_Shift_State
jc      errorhandler

Sets the shift state for the given virtual machine. Use caution when calling this service; it causes the shift state to disagree with the physical state of the keyboard SHIFT keys. Uses Flags. Clears the carry flag upon success, sets it if an error occurs.

  • No return value.
VMHandle
Handle of the virtual machine.
ShiftState
Shift state.

See Also

VKD_Get_Shift_State


VKD_Start_Paste

include vkd.inc

mov     eax, OFFSET32 paste_buf
mov     ebx, VMHandle
mov     ecx, entries
mov     esi, OFFSET32 PasteProc
mov     edx, refdata
VxDCall VKD_Start_Paste
jc      errorhandler

Puts a virtual machine into paste mode by simulating keyboard activity with key strokes taken from the specified paste buffer. Depending on the mode set with the VKD_Define_Paste_Mode service, VKD waits for the virtual machine to poll the keyboard BIOS through its Interrupt 16h interface. If the virtual machine does keyboard input through the BIOS, then VKD simulates the keyboard input at this high level (plugging in ASCII codes). If the virtual machine fails to perform any Interrupt 16h within in a time-out period, or the mode has been set to avoid Interrupt 16h pasting, the VKD simulates the necessary hardware interrupts to perform the pasting. Hot keys are still processed while pasting is in progress. Uses Flags. The carry flag is clear if the paste is started; otherwise, the carry flag is set to indicate an error, such as insufficient memory to copy from the buffer.

  • No return value.
paste_buf
Address of a paste buffer that contain an array of key structures having the following form:
OEM_ASCII_value     db  ?
scan_code           db  ?
shift_state         dw  ?

The shift_state field is 02h if a shift key is down and 04h is a CTRL key is down.

The scan_code is 0FFh and the shift_state 0FFFFh, if the VKD should convert the key to a ALT+numpad sequence. This information is identical to what is given by the Window's keyboard routine OEMKeyScan.

WMHandle
Handle of the virtual machine.
entries
Number of paste entries in the paste buffer.
PasteProc
Points to callback procedure. This parameter can be 0. For more information about the callback procedure, see the following Comments section.
refdata
Address of reference data to pass to the callback procedure.

The callback procedure is called when the paste is complete or canceled. The callback receives the following input parameters:

EAX     ; Completion flags
        ; Paste_Complete - paste completed successfully
        ; Paste_Aborted  - paste canceled by user
        ; Paste_VM_Term  - paste canceled because virtual machine terminated
EBX     ; handle of virtual machine receiving the paste
EDX     ; reference data

The procedure can modify EAX, EBX, ECX, EDX, ESI, EDI, and Flags.

See Also

VKD_Define_Paste_Mode, OEMKeyScan


Overview of the Modem Development Kit

You can find information on Modem device driver development under Modem Devices in the Windows DDK documentation.

See the section, Overview of Modem INF Files.


Mouse Overview

The software components involved in supporting the mouse in Windows® 95 include the virtual mouse device, optional mouse minidrivers, optional virtual cursor drivers, and the Windows mouse driver.


Virtual Mouse Device

The virtual mouse device (VMOUSE) is a nonreplaceable system component that virtualizes the mouse hardware, making it possible for all VMs to share the mouse. It supports the mouse for non-system VMs as well as for the system VM. VMOUSE provides built-in support for Microsoft compatible pointing devices, including the Microsoft BallPoint, attached to COM1, COM2, PS/2 mouse ports, and Microsoft InPort adapters. Together, VMOUSE and the Windows Shell provide the following features for all devices supported by VMOUSE:

  • Mouse tracking speed (sensitivity)
  • Swapping of left and right mouse buttons
  • Mouse trails (with display driver support)
  • Color cursor
  • Sizeable cursor
  • MouseKeys (numeric keypad controls cursor movement)
  • SerialKeys (alternative input device controls cursor and mouse buttons)

VMOUSE automatically draws the mouse cursor for non-system VMs. (The Windows display driver draws the cursor for Windows.) It supports VGA modes 0 through 7 and 0Dh through 13h. In graphics modes, VMOUSE draws an arrow cursor; in text modes, it draws a block cursor.

VMOUSE supports Functions 0 through 39 of the Interrupt 33h mouse application programming interface (API) for applications running in non-system VMs.


Mouse Minidriver

A mouse minidriver is a VxD that handles interrupts from the mouse hardware, converts them into mouse-event messages, and posts the messages to VMOUSE. You should provide a mouse minidriver if VMOUSE does not support your mouse hardware, or if you need to provide features that VMOUSE does not.


Virtual Cursor Driver

A virtual cursor driver is a VxD that draws the cursor for non-system VMs. You should provide a cursor VxD if you need to support cursor styles or video modes that VMOUSE does not automatically support.


Windows Mouse Driver

In Windows 95, mouse support is provided by VMOUSE and, if needed, a mouse minidriver. A Windows mouse driver is required only for backward compatibility with Windows version 3.x utilities.


Compatibility

Existing mouse drivers written for Windows version 3.x will run with Windows 95, including MOUSE.COM, MOUSE.SYS, MOUSE.DRV, VMOUSE, and OEM setup files (.INF). When the system starts, it detects whether a device driver written for Windows 3.x is installed and, if so, does not load VMOUSE.


Windows Mouse Driver

The Microsoft® Windows® mouse driver is a dynamic-link library (DLL) that Windows uses to detect, enable and retrieve information about the mouse. This section describes the mouse-driver functions.

Note that a Windows mouse driver is required only for backward compatibility with Windows version 3.x utilities.


Mouse Initialization and the Virtual Mouse Device

Windows initializes the mouse driver by calling the driver's initialization routine, and subsequently calling the driver's Enable function. The initialization routine calls the virtual mouse device (VMOUSE) to determine whether a mouse is present. If a mouse is present, the routine retrieves information about the mouse, including its type (serial, bus, InPort, and so on), and the number of the port it is using. The initialization routine writes this information to the [Mouse] section of the SYSTEM.INI file. Whenever the system restarts, VMOUSE uses the information in SYSTEM.INI to speed up the mouse initialization process.

If the initialization routine returns a nonzero value, Windows assumes the mouse is present and calls the Inquire function to retrieve additional information about the mouse hardware, including the number of buttons and the rate at which the mouse generates interrupts. Inquire returns the mouse information in the form of a MOUSEINFO structure.

Windows calls Enable when it is ready to receive mouse input. Enable passes the address of the Windows mouse-event callback function to VMOUSE. Whenever VMOUSE receives mouse input for Windows, it passes the input to the mouse-event callback function. Windows disables mouse input by calling the Disable function, which passes NULL to VMOUSE instead of the address of a valid mouse-event callback function.

The mouse driver includes the MouseGetIntVect function that Windows or utilities can call to retrieve the interrupt vector number used by the mouse interrupt handler.

See also Disable, Enable, Inquire, MouseGetIntVect, MOUSEINFO


Windows for Pen Computing Compatibility

Microsoft Windows for Pen Computing includes tablet drivers for input from a handwriting stylus device. An application can use the GetMessageExtraInfo function to distinguish between a mouse-generated event and a stylus-generated mouse event. For more information about GetMessageExtraInfo, see the Microsoft Win32 Programmer's Reference.

Tablet drivers use the SI and DI registers to pass extended event information to Windows. For this reason, mouse drivers should set these registers to zero before a function calls the Mouse_Event function in the Windows USER module. This allows Windows – based and Pen Computing – based applications to distinguish between mouse and tablet events.

See also Mouse_Event


Reference

The following functions and structures are associated with the mouse driver.


Disable

VOID Disable(VOID)

Disables mouse input to Windows. The export ordinal for this function is 3.

  • No return value.


Enable

VOID Enable(LPFN lpEventProc)

Passes the address of the Windows mouse-event callback function to VMOUSE. When VMOUSE receives mouse input for Windows, it passes the input to the callback function. The export ordinal for this function is 2.

  • No return value.
lpEventProc
Address of the mouse-event callback function. For more information about this function, see Mouse_Event.

See also Mouse_Event


Inquire

WORD Inquire(LPMOUSEINFO lpMouseInfo)

Retrieves information about the mouse hardware. The export ordinal for this function is 1.

  • Returns the size, in bytes, of a MOUSEINFO structure.
lpMouseInfo
Address of a MOUSEINFO structure that contains information about the mouse hardware that is present, including the number of buttons on the mouse, and the rate at which the mouse can issue interrupts.

See also MOUSEINFO


Mouse_Event

mov     ax, [Status]
mov     bx, [deltaX]
mov     cx, [deltaY]
mov     dx, [ButtonCount]
xor     di,di
xor     si,si
call    [Mouse_Event]

Records mouse motion and button clicks. VMOUSE calls this function when it has a new mouse event to report.

  • No return value.
Status
Combination of values indicating whether the user moved the mouse, pressed a mouse button, or released a mouse button:
Value | Meaning
SF_MOVEMENT (0001h) | Movement occurred.
SF_B1_DOWN (0002h) | Button 1 changed to down.
SF_B1_UP (0004h) | Button 1 changed to up.
SF_B2_DOWN (0008h) | Button 2 changed to down.
SF_B2_UP (0010h) | Button 2 changed to up.
SF_ABSOLUTE (8000h) | BX and CX contain normalized absolute coordinates.

The values specifying the button status are set to indicate a change in status of an ongoing condition. For example, if button 1 is pressed and held down, SF_B1_DOWN is set only when button 1 is first pressed but not for subsequent motions. Similarly, SF_B1_UP is set only when the button is first released.

deltaX and deltaY
Amount of motion along the x and y axes. The amount is either the number of mickeys moved (for relative devices), or the actual x and y coordinates (for absolute devices).
ButtonCount
Number of buttons on the mouse.

If there has been mouse motion (bit 0 of AX is set), BX and CX hold the integer values of motion since the last mouse interrupt was generated for x and y, respectively.

If the SF_ABSOLUTE value is not specified in Status, BX and CX specify relative motions from the last reported position. If this value is specified in Status, BX and CX contain normalized absolute coordinates in the range 0 through 65,535. These coordinates will be mapped by the event procedure onto the display surface.

DI and SI must be zero to ensure compatibility with Microsoft Windows for Pen Computing.


MouseGetIntVect

int MouseGetIntVect(VOID);

Retrieves the interrupt vector number used by the mouse interrupt handler. The export ordinal for this function is 4.

  • Returns the interrupt-vector number, or – 1 if no mouse exists.


MouseRedetect

int MouseRedect(VOID);

Causes VMOUSE to redetect the mouse.

  • Returns 1 if a mouse is detected; 0 otherwise.


MOUSEINFO

typedef struct {
    byte msExist;      // TRUE if mouse exists, FALSE otherwise
    byte msRelative;   // see below
    word msNumButtons; // number of buttons on mouse
    word msRate;       // see below
    word msXThreshold; // horizontal threshold before acceleration
    word msYThreshold; // vertical threshold before acceleration
    word msXRes;       // horizontal resolution
    word msYRes;       // vertical resolution
} MOUSEINFO;

Contains information about the mouse, such as the type of coordinates and the number of buttons.

msRelative
Mouse-coordinate flag. It is 0 if the mouse returns absolute coordinates, or 1 if it returns relative coordinates.
msRate
Maximum number of hardware interrupts, per second, that the mouse can generate.


Virtual Mouse Device

The virtual mouse device (VMOUSE) is the main component of Windows® 95 for supporting the mouse. It is a nonreplaceable virtual device (VxD) that virtualizes the mouse hardware so it can be shared among all virtual machines (VMs). VMOUSE also provides the Interrupt 33h application programming interface (API) and draws the cursor for non-system VMs. This section describes the services that VMOUSE provides.

During initialization, VMOUSE allocates memory for storing mouse-related variables, and initializes many of these variables by reading mouse settings from the registry. These settings include mouse sensitivity, acceleration, and rotation angle. VMOUSE also installs interrupt handlers for Interrupt 10h and Interrupt 33h. The Interrupt 10h handler monitors video-mode changes so VMOUSE can correctly draw the mouse cursor for non-system VMs. The Interrupt 33h handler implements the standard Interrupt 33h mouse application programming interface (API) for use by non-system VMs.

VMOUSE supports a variety of pointing devices, and they can be connected to a variety of system ports. VMOUSE's initialization procedure checks the various ports for the presence of a supported pointing device. If it detects one, VMOUSE installs the appropriate interrupt handler, which interprets the raw input from the pointing device and passes it to the current VM.


Mouse Messaging Services

A mouse minidriver is a small VxD that supports mouse hardware that is not automatically supported by VMOUSE. A minidriver uses the VMD_Set_Mouse_Data service to pass information about the mouse hardware to VMOUSE, including the mouse-type identifier, the number of the interrupt request line (IRQ) the mouse is using, the number of buttons on the mouse, and the number of the port the mouse is using. A mouse minidriver's interrupt handler converts raw input from the mouse into event messages and uses the VMD_Post_Pointer_Message or VMD_Post_Absolute_Pointer_Message service to post the messages to VMOUSE.

By hooking the VMD_Manipulate_Pointer_Message service, a virtual device can install a hook procedure that manipulates mouse pointer data. VMOUSE passes raw mouse data to the hook procedure before it is posted to an application. The data includes the x and y delta values, and the status of the mouse buttons. The hook procedure can manipulate the mouse data as needed. A virtual device that needs to manipulate pointer data should hook the VMD_Manipulate_Pointer_Message service instead of the VMD_Post_Pointer_Message service. A virtual device uses the Hook_Device_Service VMM service to install the hook procedure.

VMOUSE does not automatically support the middle mouse button. Instead, a mouse minidriver can support the middle button by hooking the VMD_Set_Middle_Button service. To hook the service, a mouse minidriver calls the Hook_Device_Service VMM service, specifying the address of a programmer-defined callback function. VMOUSE calls the callback function whenever a mouse event occurs, allowing the callback function to set the status of the middle mouse button.

See also VMD_Manipulate_Pointer_Message, VMD_Post_Pointer_Message, VMD_Set_Middle_Button, VMD_Set_Mouse_Data


Virtual Cursor Driver Services

VMOUSE draws the cursor for non-system VMs, but it supports only standard VGA modes. Also, VMOUSE supports only one cursor style for text mode (a block cursor) and one for graphics mode (an arrow cursor). A virtual cursor driver (cursor VxD) provides support for additional video modes and cursor styles for non-system VMs.

A virtual cursor driver (cursor VxD) contains a callback function that VMOUSE calls whenever an event occurs that affects the cursor. To install a cursor callback function, a cursor VxD fills the CURSORPROCINFO structure with information about the support it provides, including the address of the callback function, and uses the VMD_Set_Cursor_Proc function to pass the structure to VMOUSE. To notify the cursor VxD of an event, VMOUSE (or another VxD) uses the VMD_Call_Cursor_Proc function to call the cursor VxD's callback function.

See also CURSORPROCINFO, VMD_Call_Cursor_Proc, VMD_Set_Cursor_Proc


Information Services

VMOUSE provides three services that other VxDs can use to retrieve information from VMOUSE. The VMD_Get_Version service retrieves the version number of VMOUSE. A VxD can call this service to determine whether VMOUSE is loaded. This is the only service that will not cause an invalid link error to occur if VMOUSE is not loaded.

A virtual device can use the VMD_Get_Mouse_Data service to retrieve information about the mouse that a mouse minidriver has registered using a previous call to the VMD_Set_Mouse_Data service. The information includes the mouse-type identifier, the number of the interrupt request line (IRQ) the mouse is using, the number of buttons on the mouse, and the number of the port the mouse is using.

The VMD_Get_Mouse_Owner service retrieves the handle of the VM that is currently receiving mouse input.

See also VMD_Get_Mouse_Data, VMD_Get_Mouse_Owner, VMD_Get_Version


Application Programming Interface Functions

VMOUSE provides a number of API functions that applications can call. Most are intended to be used only by the Windows mouse driver (MOUSE.DRV).

An application can call the VMDAPI_GET_VERSION function to retrieve the version number of VMOUSE. This is the only API function that can be called from a nonsystem VM.

Windows calls the VMDAPI_QUERY_WINDOWED_MOUSE_SUPPORT function to determine whether VMOUSE provides mouse support from nonsystem VM applications running in a window. The VMDAPI_GET_MOUSE_INFO function retrieves information about the mouse hardware, including the mouse-type identifier, the number of the IRQ that the mouse is using, and the number of the port that the mouse is using.

VMOUSE passes mouse events to the Windows USER module through the Mouse_Event callback function. Windows can use the VMDAPI_SET_MOUSE_EVENT_CALLBACK function to pass the address of a new callback function to VMOUSE.

Windows uses the VMDAPI_SET_MOUSE_FOCUS function to capture mouse input. After calling this function, VMOUSE directs all mouse input to the system VM.

See also VMDAPI_GET_VERSION, VMDAPI_GET_MOUSE_INFO, VMDAPI_QUERY_WINDOWED_MOUSE_SUPPORT, VMDAPI_SET_MOUSE_EVENT_CALLBACK, VMDAPI_SET_MOUSE_FOCUS, VMDAPI_UPDATE_MOUSE_STATE


Reference

VMOUSE provides the following groups of services.

Group | Elements
Mouse minidriver services | VMD_Enable_Disable_Mouse_Events, VMD_Manipulate_Pointer_Message, VMD_Post_Pointer_Message, VMD_Post_Absolute_Pointer_Message, VMD_Set_Middle_Button, VMD_Set_Mouse_Data, VMD_Set_Mouse_Type
Cursor VxD services | CURSORPROCINFO, VMD_Call_Cursor_Proc, VMD_Set_Cursor_Proc
Mouse information services | VMD_Get_Mouse_Data, VMD_Get_Mouse_Owner, VMD_Get_Version
Mouse API functions | VMDAPI_DETECT_MOUSE, VMDAPI_GET_MOUSE_INFO, VMDAPI_GET_VERSION, VMDAPI_MOUSEDRV_CONSISTENT, VMDAPI_QUERY_WINDOWED_MOUSE_SUPPORT, VMDAPI_SET_MOUSE_EVENT_CALLBACK, VMDAPI_SET_MOUSE_FOCUS, VMDAPI_SET_MOUSE_TYPE, VMDAPI_UPDATE_MOUSE_STATE


Mouse Minidriver Services

Mouse minidrivers use the following services to provide VMOUSE with information about the pointing device and to pass input from the device to VMOUSE.


Mouse_Instance

include VMD.INC

Mouse_Instance  STRUC
MI_Flags       DW 0  ; see below
MI_IO_Base     DW 0  ; base to read
MI_IRQNumber   DB 0  ; number of the IRQ
MI_PortNum     DB 0  ; port number (serial mice)
MI_MouseType   DW 0  ; type of mouse (defined above)
MI_Reference   DD 0  ; reference data
MI_hDevNode    DD 0  ; handle of the device node
MI_hIRQ        DD 0  ; handle of the IRQ used by VPICD
MI_HWINT       DD 0  ; hardware interrupt procedure
MI_Reset       DD 0  ; reset routine
MI_Disable     DD 0  ; see below
MI_Initialize  DD 0  ; see below
MI_LoadHandle  DD 0  ; load handle of loaded VxD.
Mouse_Instance  ENDS

Describes a mouse device. When loading a mouse minidriver, VMOUSE passes the address of this structure to the control procedure of a minidriver. If the minidriver detects the mouse device, it sets the appropriate flags in the MI_Flags field, and then fills the appropriate fields of the structure. This structure is also passed to the VMD_Post_Pointer_Message and VMD_Manipulate_Pointer_Message services.

MI_Flags
Status flags. Can be a combination of these values:
Value | Meaning
MIF_Alloc | Instance is allocated
MIF_Active | Interrupt is active
MIF_Detected | Device detected
MIF_BadDevNode | Device not detected
MIF_NewConfig | No DevNode for device
MIF_BadIO | Wrong IO in DevNode
MIF_BadIRQ | Wrong IRQ in DevNode
MIF_NoIRQ | Do not virtualize IRQ
MIF_BUSMOUSE | BUSMOUSE
MIF_INPMOUSE | INPORT
MIF_AUXMOUSE | AUX (PS/2) mouse
MIF_OTHERMOUSE | 3rd party mouse

MI_Disable
Address of a function in the mouse minidriver that VMOUSE calls when the mouse is about to be disabled; for example, when the machine is put into a docking station. Set this field to zero if the minidriver has no disable function.
MI_Initialize
Address of the mouse minidriver's initialization function. The function detects and virtualizes the mouse hardware.

See also VMD_Manipulate_Pointer_Message, VMD_Post_Pointer_Message


VMD_Enable_Disable_Mouse_Events

include vmd.inc

mov     eax, Enable_Flag
mov     ebx, VMHandle
VxDcall VMD_Enable_Disable_Mouse_Events

Enables or disables mouse events for the given virtual machine.

  • No return value.
Enable_Flag
Flag that, if TRUE, enables mouse events and, if FALSE, disables them.
VMHandle
Handle of the virtual machine.


VMD_Manipulate_Pointer_Message

include vmd.inc

mov     esi, DeltaX
mov     edi, DeltaY
mov     al, RawButtonStatus
mov     edx, OFFSET32 MouseInstance
VxDcall VMD_Manipulate_Pointer_Message
mov     ScaledRotatedX, esi
mov     ScaledRotatedY, edi
mov     MappedButtonStatus, al

Allows a virtual device to install a hook procedure that manipulates mouse pointer data. A virtual device that needs to manipulate pointer data should hook this service instead of the VMD_Post_Pointer_Message service. A virtual device uses the Hook_Device_Service VMM service to install the hook procedure. Uses all registers.

  • Returns values in these registers:
al Bit flags that specify the button status. A flag is set if the corresponding button is down. The meaning of the flags is as follows:

Bit | Meaning
0, 1 | Undefined
2 | Status of button 4
3 | Status of button 2
4 | Status of button 3
5 | Status of button 1
6 | Undefined
7 | Button-map flag. A hook procedure should set this flag if it maps the mouse buttons, otherwise it should clear it.

esi | Scaled or rotated horizontal delta value.
edi | Scaled or rotated vertical delta value.

DeltaX and DeltaY
Amount, in mickeys, of horizontal and vertical mouse movement.
ButtonStatus
Bit flags that specify the new status of the mouse buttons.
MouseInstance
Address of a MOUSE_INSTANCE structure that contains information describing the mouse device.

See also MOUSE_INSTANCE, VMD_Post_Pointer_Message


VMD_Post_Absolute_Pointer_Message

include vmd.inc

mov     esi, AbsoluteX
mov     edi, AbsoluteY
mov     al, ButtonStatus
VxDcall VMD_Post_Absolute_Pointer_Message

Informs VMOUSE of a mouse event generated by an absolute pointing device, specifying the absolute coordinates the device and the status of the buttons. VMOUSE simply passes the information to the Windows USER module through the Mouse_Event callback function. This service does nothiing if called from a non-system VM. A mouse minidriver uses the VMD_Post_Absolute_Pointer_Message service. Uses Flags; clears carry flag.

  • No return value.
AbsoluteX and AbsoluteY
Absolute horizontal and vertical coordinates.
ButtonStatus
Bit flags that specify the status of the buttons. For more information about the bit flags, see the description of the VMD_Post_Pointer_Message service.

See also VMD_Post_Pointer_Message


VMD_Post_Pointer_Message

include vmd.inc

mov     esi, DeltaX
mov     edi, DeltaY
mov     al, ButtonStatus
mov     edx, OFFSET32 MouseInstance
VxDcall VMD_Post_Pointer_Message

Informs VMOUSE of a mouse event, specifying the amount of mouse movement and the status of the mouse buttons. A mouse minidriver uses this service. Uses Flags; clears carry flag.

  • No return value.
DeltaX and DeltaY
Amount, in mickeys, of horizontal and vertical mouse movement.
ButtonStatus
Bit flags that specify the status of the mouse buttons. A flag is set if the corresponding button is down. The meaning of the flags is as follows:
Bit | Meaning
0, 1 | Undefined
2 | Status of button 4
3 | Status of button 2
4 | Status of button 3
5 | Status of button 1
6, 7 | Undefined

MouseInstance
Address of a MOUSE_INSTANCE structure that contains information describing the device that produced the mouse event.

See also MOUSE_INSTANCE, VMD_Manipulate_Pointer_Message, VMD_Post_Absolute_Pointer_Message


VMD_Set_Middle_Button

#include vmd.inc

mov     bl, ButtonStatus
VxDcall VMD_Set_Middle_Button

Allows a virtual device to install a hook procedure that supports the middle mouse button. VMOUSE calls the procedure whenever the status of the middle mouse button must be set. A virtual device uses the Hook_Device_Service VMM service to install the hook procedure. Uses BH.

  • Returns 4 in BH to indicate the middle button is down, otherwise returns 0 in BH.
ButtonStatus
Bit flags that specify the status of the mouse buttons. For the meaning of the flags, see the description of the VMD_Post_Pointer_Message service.

See also VMD_Post_Pointer_Message


VMD_Set_Mouse_Data

include vmd.inc

mov     ah, MouseType
mov     al, IRQ
mov     ebx, BallPointFlag
mov     ecx, BallPointID
mov     dh, ButtonCount
mov     dl, PortNumber
VxDcall VMD_Set_Mouse_Data

Allows a mouse minidriver to provide information to VMOUSE about the type of mouse hardware the minidriver supports. VMOUSE stores information for only one mouse at a time. Uses EAX and Flags.

  • No return value.
MouseType
One of the following mouse-type identifiers:
VMD_Type_Bus | VMD_Type_PS2
VMD_Type_Serial | VMD_Type_Serial_w_port
VMD_Type_InPort | VMD_Type_Undefined
VMD_Type_HP

IRQ
IRQ the mouse is using.
BallPointFlag
Microsoft BallPoint support. Bit zero is 1 if the mouse minidriver supports BallPoint; otherwise, it is 0.
BallPointID
Identifier of BallPoint if bit zero of BallPointFlag is 1.
ButtonCount
Number of buttons on the mouse supported by the mouse minidriver.
PortNumber
Port to which the mouse is connected, if the mouse is a serial or InPort mouse.

See also VMD_Get_Mouse_Data


VMD_Set_Mouse_Type

This service is a stub in version 4.0 of VMOUSE. It is provided for backward compatibility. Use the VMD_Set_Mouse_Data service instead.

See also VMD_Set_Mouse_Data


Virtual Cursor Device Services

The services in this section support virtual cursor devices (cursor VxDs).


CURSORPROCINFO

include vmd.inc

CursorProcInfo Struc
CursorProcAddress   dd ?  ; address of cursor callback function
NextCursorProcInfo  dd ?  ; address of next callback function
Video_Mode_Low      dw ?  ; video mode, low resolution
Video_Mode_High     dw ?  ; video mode, high resolution
Priority            db ?  ; priority of cursor callback function
Flags               dw ?  ; see below
CursorProcInfo Ends

Contains information about the cursor-drawing callback function provided by a cursor VxD.

Flags
Video-mode override flag. A cursor VxD that provides enhanced cursor-drawing capablities for the video modes specified in Video_Mode_Low and Video_Mode_High should set this flag to DC_SupportsOverride. When the video mode changes, VMOUSE calls all cursor drivers that have this flag set and selects the one with the highest priority.

See also VMD_Set_Cursor_Proc


VMD_Call_Cursor_Proc

include vmd.inc

mov     eax, FunctionIndex
mov     ebx, VMHandle
VxDcall VMD_Call_Cursor_Proc
jc      errorhandler

Calls the cursor-drawing callback function registered by a cursor VxD. Uses EAX and Flags.

  • Clears the carry flag if the cursor-drawing callback function supports FunctionIndex; otherwise, sets the carry flag.
FunctionIndex
Index of the function that the cursor-drawing callback functions is to execute. It can be one of these values:
GETDISPLAYMODEINFO | SETCONDITIONALREGION
MOVECURSOR | SETCURSORTRAIL
QUERYDISPLAYMODE | SETDISPLAYMODE
QUERYMEMORYUNDERCURSOR | SETDISPLAYPAGE
REMOVECURSOR | SETGRAPHICSCURSOR
RESETCURSORDRIVER | SETTEXTCURSOR
SAVERESTORESTATE

For more information about the cursor-drawing callback function, see .

VMHandle
Handle of the virtual machine.


VMD_Set_Cursor_Proc

include vmd.inc

mov     eax, OFFSET32 CursorProcInfo
VxDcall VMD_Set_Cursor_Proc

Sets the address of the procedure that draws the cursor. A cursor-drawing VxD uses this service.

  • No return value.
CursorProcInfo
Address of a CURSORPROCINFO structure that contains information about the cursor-drawing callback function.

See also CURSORPROCINFO


Mouse Information Services

The services in this section retrieve infomation from VMOUSE.


VMD_Get_Mouse_Data

include vmd.inc

VxDcall VMD_Get_Mouse_Data
mov     MouseType, ah
mov     IRQ, al
mov     BallPointID, ecx
mov     ButtonCount, dh
mov     PortNumber, dl

Allows a virtual device to retrieve information about the mouse that a mouse minidriver has registered using a previous call to the VMD_Set_Mouse_Data service. VMOUSE stores information for only one mouse at a time. Uses EAX, ECX, and EDX.

  • No return value.
MouseType
Mouse-type identifier. For a lost of possible values, see the descripton of the VMD_Set_Mouse_Data service.
IRQ
IRQ the mouse is using.
BallPointID
Identifier of BallPoint, or zero if the mouse is not a BallPoint.
ButtonCount
Number of buttons on the mouse supported by the mouse minidriver.
PortNumber
Serial port to which the mouse is connected, if the mouse is a serial or InPort mouse; otherwise zero.

See also VMD_Set_Mouse_Data


VMD_Get_Mouse_Owner

include vmd.inc

VxDcall VMD_Get_Mouse_Owner
mov     VMHandle, ebx

Identifies the virtual machine currently receiving input from the mouse. Uses EBX and Flags.

  • Returns the handle in EBX.


VMD_Get_Version

include vmd.inc

VxDcall VMD_Get_Version
mov     byte ptr [MajorVersion], ah
mov     byte ptr [MinorVersion], al

Retrieves the version number of VMOUSE. Uses EAX and Flags; clears the carry flag.

  • Returns the major version number in AH and the minor version number in AL.

A VxD can use this service to determine whether VMOUSE is loaded. This is the only service that will not cause an invalid link error to occur if VMOUSE is not loaded.


Mouse Application Programming Interface Functions

This section describes the API functions provided by VMOUSE. Note that the following functions are intended only for the system virtual machine:

VMDAPI_GET_MOUSE_INFO

VMDAPI_QUERY_WINDOWED_MOUSE_SUPPORT

VMDAPI_SET_MOUSE_EVENT_CALLBACK

VMDAPI_SET_MOUSE_FOCUS

VMDAPI_UPDATE_MOUSE_STATE

If a nonsystem virtual machine calls the preceding functions, the functions simply set the carry flag and return.


VMDAPI_DETECT_MOUSE

include vmd.inc

mov     ax, VMDAPI_DETECT_MOUSE
call    pVMD_API_Entry

Detects and initializes all mouse devices listed in the registry. VMOUSE calls the initialization routine of each mouse minidriver. Uses EAX and Flags.

  • Clears the carry flag.


VMDAPI_GET_MOUSE_INFO

include vmd.inc

mov     ax, VMDAPI_GET_MOUSE_INFO
call    pVMD_API_Entry
jc      errorhandler
mov     MouseType, al
mov     IRQ, ah
mov     PortNumber, cx

Retrieves information about the mouse hardware. Uses AX, CX, and Flags. Clears the carry flag upon success, sets it upon failure.

  • Returns the mouse-type identifier in AL, the IRQ that the mouse is using in AH, and the port to which the mouse is connected in CX (if the mouse is a serial or InPort mouse). The mouse-type identifier can be one of the following values:
VMD_Type_Bus | VMD_Type_PS2
VMD_Type_Serial | VMD_Type_Serial_w_port
VMD_Type_InPort | VMD_Type_Undefined
VMD_Type_HP |


VMDAPI_GET_VERSION

include vmd.inc

mov     ax, VMDAPI_GET_VERSION
call    pVMD_API_Entry
mov     VersionNumber, ax

Retrieves the version number of VMOUSE. Uses AX and Flags; clears the carry flag.

  • Returns the version number in AX.


VMDAPI_MOUSEDRV_CONSISTENT

include vmd.inc

mov     ax, VMDAPI_MOUSEDRV_CONSISTENT
call    pVMD_API_Entry

Discovers whether the current mouse driver has registered its mouse-event callback function with VMOUSE. Uses EAX and Flags.

  • Returns one in AL if the driver has registered the callback function, zero otherwise.


VMDAPI_QUERY_WINDOWED_MOUSE_SUPPORT

include vmd.inc

mov     ax, VMDAPI_QUERY_WINDOWED_MOUSE_SUPPORT
call    pVMD_API_Entry
jc      errorhandler

Discovers whether VMOUSE supports the mouse in nonsystem virtual-machine applications running in a window. Uses Flags.

  • Clears the carry flag, indicating that the mouse is supported in windowed, non-system virtual-machine applications.


VMDAPI_SET_MOUSE_EVENT_CALLBACK

include vmd.inc

mov     dx, OFFSET MouseEventProc
mov     cx, SEG MouseEventProc
mov     ax, VMDAPI_SET_MOUSE_EVENT_CALLBACK
call    pVMD_API_Entry
jc      errorhandler

Provides VMOUSE with the address of the function to call whenever a mouse event occurs. Uses Flags. Clears the carry flag upon success, sets it upon failure.

  • No return value.
MouseEventProc
Address of mouse-event callback function. For more information about the function, see Mouse_Event.

See also VMDAPI_UPDATE_MOUSE_STATE


VMDAPI_SET_MOUSE_FOCUS

include vmd.inc

mov     ax, VMDAPI_SET_MOUSE_FOCUS
call    pVMD_API_Entry

Sets the focus of VMOUSE so that subsequent mouse events are directed to the calling virtual machine. Uses Flags. Clears carry flag upon success, sets it upon failure.

  • No return value.


VMDAPI_SET_MOUSE_TYPE

This API function is a stub in version 4.0 of VMOUSE. The function simply clears the carry flag and returns.


VMDAPI_UPDATE_MOUSE_STATE

include vmd.inc

mov     ax, VMDAPI_UPDATE_MOUSE_STATE
call    pVMD_API_Entry

Retrieves the current state of the mouse buttons and the current position of the mouse pointer, and then passes the information to the mouse-event callback function. Uses Flags. Clears carry flag upon success, sets it upon failure.

  • No return value.

See also VMDAPI_SET_MOUSE_EVENT_CALLBACK


Mouse Minidrivers

You must provide a VxD, called a mouse minidriver, if VMOUSE does not include built-in support for your mouse hardware or if you need to provide features that VMOUSE does not provide. This section describes the purpose and requirements of a mouse minidriver.


Minidriver Requirements

There are no requirements for naming a mouse minidriver, and there are no services that a minidriver must provide to other VxDs in the system. A minidriver can have any version number, its identifier should be set to Undefined_Device_Id, and its initialization order should be set to Undefined_Init_Order.


Handling Mouse Interrupts

A mouse minidriver installs an interrupt handler to process hardware interrupts from the mouse. To install an interrupt handler, a mouse minidriver must use services provided by the virtual programmable interrupt controller device (VPICD).

After installing the interrupt handler, the mouse minidriver must call the VMD_Set_Mouse_Data service to provide VMOUSE with information about the mouse, including the mouse-type identifier, the number of the interrupt request (IRQ) the mouse is using, the number of the port the mouse is using, and the number of buttons on the mouse. VMOUSE uses this information to respond to various Interrupt 33H functions.

The interrupt handler translates the raw data from the mouse into messages and posts them to VMOUSE by calling the VMD_Post_Pointer_Message service. Each message includes the horizontal and vertical delta values and a value indicating the status of the mouse buttons. The horizontal and vertical delta values indicate the amount, in mickeys, of horizontal and vertical mouse movement that occurred since posting the last message to VMOUSE. A mickey is the distance the mouse must move to generate a mouse-movement signal.

The button-status value is a byte-size array of bits that indicate the status of each mouse button; that is, whether each is pressed or released. A bit is 1 if the corresponding button is pressed; otherwise, it is 0. The button status value has the following form:

Bit | Meaning
0, 1 | Undefined
2 | Status of button 4
3 | Status of button 2
4 | Status of button 3
5 | Status of button 1
6, 7 | Undefined

VMOUSE interprets the data in the mouse messages based on user-defined settings such as the rotation angle, acceleration, and sensitivity and then passes the data to the appropriate VM. If the system VM has the mouse focus, VMOUSE passes the data to the Mouse_Event function in the Windows USER module. If an application in a non-system VM has the mouse focus, VMOUSE passes the data to the application's mouse callback function. The application installs the callback function by calling Interrupt 33h, Function 0Ch.

See also Mouse_Event, VMD_Post_Pointer_Message, VMD_Set_Mouse_Data


Absolute Pointing Devices

VMOUSE provides limited support for absolute pointing devices through the VMD_Post_Absolute_Pointer_Message service. An absolute device uses this service to pass the absolute position of the device, and the status of the device's buttons, to the Windows USER module through the Mouse_Event callback function. The service fails silently (does nothing) when called from a non-system VM. The mouse minidriver for the absolute device must make the mouse work in conjunction with setting the mouse position by calling an Interrupt 33h fuction when the system VM starts, and then calling VMD_Post_Pointer_Message with the relative motion.

See also Mouse_Event, VMD_Post_Absolute_Pointer_Message, VMD_Post_Pointer_Message


Initializing a Mouse Minidriver

Information about a mouse device is stored in the SOFTWARE section of the registry. One of the entries in the registry is the statement mousedriver=name.vxd, where name is the name of a mouse minidriver. VMOUSE searches the registry for occurrences of this statement and loads the corresponding minidrivers. VMOUSE loads the minidrivers when the system is started, or whenever the VMAPI_DETECT_MOUSE API function is called.

When loading a mouse minidriver, VMOUSE sends the SYS_DYNAMIC_DEVICE_INIT message to the minidriver's control procedure. The ECX register contains the address of a Mouse_Instance structure. The minidriver should respond to the SYS_DYNAMIC_DEVICE_INIT message by attempting to detect the mouse device. If it detects the mouse, the minidriver should set the MI_Flags field of the Mouse_Instance structure to MIF_DETECTED, and fill the other fields with information about the mouse device. The minidriver should also set the MIF_DISABLE flag and copy the address of its "disable" function into the MI_Disable field. VMOUSE calls the disable routine whenever the mouse device is disabled and the minidriver should release resources; for example, when a portable machine is placed in a docking station.

The control procedure of a mouse minidriver receives a SYS_DYNAMIC_DEVICE_EXIT message when it is about to be unloaded. A minidriver should respond to the message by freeing any system resources it isusing.

See also Mouse_Instance, VMAPI_DETECT_MOUSE


Testing Your Minidriver

To test your minidriver, you must copy VMOUSE.VXD and VMOUSE.SYM to your WINDOWS\SYSTEM directory. Next, change the "mouse=" line in the [386Enh] section of SYSTEM.INI from "mouse=*vmouse" to "mouse=vmouse.vxd". Changing the "mouse=" line causes Windows to load the newer version of VMOUSE.VXD you just copied, instead of its built-in version. Finally, add another "device=" line in the [386Enh] section to cause Windows to load your minidriver VxD. For example:

device=mydriver.vxd


Providing a Device Information File

The setup disk for your pointing device must contain a device information file (.INF). The file provides information that the Windows 95 operating system needs to install your device driver software and to support your pointing device. The Windows 95 device driver kit (DDK) includes a sample mouse minidriver and accompanying device information file. You should use the sample device information file as a model for creating one of your own. For general information on device information files, including a description of each section and entry, see .


Modifying the Mouse Property Sheet

Windows 95 includes a property sheet that allows the user to change mouse settings and properties such as the tracking speed, button configuration, and double-click speed. If the contents of the mouse property sheet do not meet the needs of your device, you'll need to provide a shell extension dynamic-link library (DLL) that implements a property sheet handler. The control panel calls the property sheet handler whenever it is about to display the mouse property sheet, allowing the handler to replace existing property sheet pages and add new pages. For information about creating a shell extension that implements a property sheet handler, see the Microsoft Programmer's Guide to Windows 95.


Virtual Cursor Drivers

The virtual mouse device (VMOUSE) draws the mouse cursor for non-system virtual machines (VMs). It supports VGA modes 0 through 7 and 0Dh through 13h. In graphics modes, VMOUSE draws an arrow cursor; in text modes, it draws a block cursor.

A display vendor can enhance VMOUSE's cursor-drawing capabilities for non-system VMs by providing a virtual cursor driver (cursor VxD). For example, a cursor VxD might provide additional cursor styles or add support for other video modes. Any number of cursor VxDs can be loaded at a time, each supporting one or more video modes. This section describes the requirements of a cursor VxD.


Cursor Callback Function

A cursor VxD must register itself with VMOUSE. This provides VMOUSE with information about the VxD, including the address of the VxD's cursor callback function. VMOUSE calls the VxD's callback function whenever an event occurs in the system that affects the appearance or position of the cursor. VMOUSE also calls the callback function to retrieve information about the cursor support provided by the VxD. Although the cursor callback function can have any name, the name CursorProc is used for convenience throughout this section.

Every cursor VxD must provide a set of 12 functions. VMOUSE directs the VxD to perform a function.by calling the CursorProc function, passing the identifier of the function in the EAX register. VMOUSE also passes the handle of the current VM in the EBX register. The contents of the other registers depend on the function, as does the return value. The remaining sections of this section describe the required functions.

A cursor VxD registers itself in response to the Device_Init message sent by the virtual machine manager (VMM) during VxD initialization. The VxD fills a CURSORPROCINFO structure and passes the address of the structure to VMOUSE by using the VMD_Set_Cursor_Proc service. VMOUSE stores the information provided in the CURSORPROCINFO structure.

See also CursorProc, CURSORPROCINFO, VMD_Set_Cursor_Proc


Video Modes

Whenever the video mode changes, VMOUSE searches for a cursor VxD that supports the new video mode. VMOUSE calls the CursorProc function of each registered cursor VxD, requesting the VxD's SETDISPLAYMODE function. A VxD that supports the new video mode returns 1 in the EAX register. If more than one VxD supports the new mode, VMOUSE examines the priority value associated with the VxDs and selects the one with the highest value. A VxD specifies the priority value in the Priority member of the CURSORPROCINFO structure that it passes to VMOUSE during registration.

VMOUSE calls a cursor VxD's QUERYDISPLAYMODE function to determine which video mode the VxD is supporting. To retrieve detailed information about the video mode, VMOUSE calls the GETDISPLAYMODEINFO function, passing the address of a DISPLAYMODEINFO structure. The cursor VxD fills the structure with information about the video mode, including the screen dimensions, the dimensions of a character cell, the bits-per-pixel ratio, and so on.

See also CursorProc, CURSORPROCINFO, DISPLAYMODEINFO, GETDISPLAYMODEINFO, QUERYDISPLAYMODE, SETDISPLAYMODE


Cursor Types

A cursor VxD must draw the cursor appropriately for each video mode it supports. The VxD must draw a graphics cursor in graphics mode and a text cursor in text mode. A graphics cursor is a bitmapped image that moves over the images on the screen and can move to any pixel position on the display. A text cursor is typically either a block the size of a character cell, or a horizontal line that is one character-cell wide and one or more scan lines tall. A text cursor can occupy any character cell on the display. By default, VMOUSE displays a block cursor in text modes and an arrow cursor in graphics modes.


Graphics Cursors

To set a new graphics cursor, VMOUSE passes the address of a GRAPHICSCURSOR structure to the cursor VxD's SETGRAPHICSCURSOR function. The cursor VxD sets a new graphics cursor based on the information in the structure.

A graphics cursor is a bitmapped image that moves over the images on the screen. The width and height of the cursor image is expressed in pixels and is defined by the wWidth and wHeight members of the GRAPHICSCURSOR structure.

The pixels in the cursor image interact with the pixels on the display in a manner defined by the screen mask and the cursor mask. The screen mask determines whether the cursor pixels are part of the cursor's shape or part of the background; the cursor mask determines how the pixels under the cursor contribute to the color of the cursor.

To create the cursor, a cursor VxD operates on the bits in the computer's video memory that correspond to the image under the cursor. First, the VxD must expand each bit in the screen and cursor masks to match the number of bits in video memory required for each screen pixel's color information. Next, the VxD does a logical AND operation between the expanded screen-mask bits and the color-information bits. The color of the pixels under the cursor remains unchanged wherever a screen-mask bit is 1 and changes wherever the screen-mask bit is 0. Finally, the VxD does a logical XOR operation between the pixel bits and the expanded bits from the cursor mask. Where the cursor mask is 0, the screen pixels are unchanged. Where the mask is 1, the color of the pixels is inverted.

The dwOffset32Masks member of the GRAPHICSCURSOR structure specifies the offset from the beginning of the structure to the screen and cursor masks. The cursor mask must follow the screen mask.

A graphics cursor must have a hot spot, a single pixel in the cursor used to identify the cursor's location on the screen. The wHotX and wHotY members of GRAPHICSCURSOR define the coordinates of the hot spot relative to the upper-left corner of the cursor bitmasks.

See also GRAPHICSCURSOR, SETGRAPHICSCURSOR


Text Cursors

To set a new text cursor, VMOUSE calls the cursor VxD's SETTEXTCURSOR function, passing the address of a TEXTCURSOR structure. The cursor VxD sets a new text cursor based on the information in the structure.

The bFlags member of TEXTCURSOR indicates whether the new cursor is a hardware or software text cursor. If bFlags is 1, the new cursor is a hardware text cursor, and the XORMask and ANDMask members specify the first and last scan lines of the cursor. The VxD draws the cursor by directing the display adapter to turn on the specified scan lines in the character cell that contains the cursor. A scan line that is turned on typically appears as a bar in the character cell.

If the bFlags member of TEXTCURSOR is 0, the new cursor is a software text cursor. In this case, the XORMask and ANDMask members specify the cursor mask and screen mask, respectively. The cursor and screen masks are bitmasks that define how the cursor affects the character and attributes of the character cell it occupies. The screen mask is a 16-bit value that determines which of the character cell's attributes are preserved; the cursor mask is a 16-bit value that determines how the preserved attributes change to yield the cursor.

To draw the cursor, the VxD operates on the screen data that defines the attributes of the character cell occupied by the cursor. The screen data for a character cell has the following format.

Bits | Purpose
15 | Sets blinking or nonblinking character
12 – 14 | Sets background color
11 | Sets intensity
8 – 10 | Sets foreground color
0 – 7 | Specifies ASCII value of character

The VxD first does a logical AND operation between the screen mask and the screen data for the character cell. Next, it does a logical XOR operation between the cursor mask and the result of the AND operation, producing the cursor's appearance on the display.

See also SETTEXTCURSOR, TEXTCURSOR


Cursor Position and Appearance

As the user moves the mouse, the mouse generates hardware interrupts. VMOUSE handles the interrupts by calling the cursor VxD's MOVECURSOR function, directing the cursor VxD to move the cursor to a particular position on the display. VMOUSE specifies the position by passing the VxD a Point_Struc structure in the ECX register. The structure specifies the new position in screen coordinates; that is, x and y coordinates relative to the upper-left corner of the display.

VMOUSE hides the cursor by calling the cursor VxD's REMOVECURSOR function. A subsequent call to the MOVECURSOR function makes the cursor visible again.

VMOUSE can direct a cursor VxD to create a conditional-off region by calling the VxD's SETCONDITIONALREGION function. A conditional-off region is a rectangular area on the display where the cursor is hidden. VMOUSE specifies the coordinates of the upper left and lower right corners of the region by passing the coordinates in Point_Struc structures.

See also MOVECURSOR, Point_Struc, REMOVECURSOR, SETCONDITIONALREGION


Cursor VxD State

VMOUSE calls the cursor VxD's SAVERESTORESTATE function whenever an application uses Interrupt 33h, Functions 15h (Get State Storage Requirements), 16h (Save Mouse Driver State), and 17h (Restore Mouse Driver State). An application that uses the mouse can use functions 15h and 16h to save the state of the cursor VxD before temporarily transfering control to another application that also uses the mouse. When the first application regains control, it uses function 17h to restore the VxD's state.

VMOUSE calls a cursor VxD's RESETCURSORDRIVER function to reset the VxD. Typically, a cursor VxD sets all variables that control the position and appearance to default values.

See also RESETCURSORDRIVER, SAVERESTORESTATE


Reference

This section provides details about the functions a cursor VxD must support. The functions can be divided into five groups, as shown in the following list.

Group | Elements
Cursor callback function | CursorProc
Video modes | DISPLAYMODEINFO, GETDISPLAYMODEINFO, QUERYDISPLAYMODE, SETDISPLAYMODE, SETDISPLAYPAGE
Cursor types | GRAPHICSCURSOR, SETGRAPHICSCURSOR, SETTEXTCURSOR, TEXTCURSOR
Cursor position and appearance | MOVECURSOR, REMOVECURSOR, SETCONDITIONALREGION, SETCURSORTRAIL
Cursor VxD state | RESETCURSORDRIVER, SAVERESTORESTATE


Cursor Callback Function

A cursor VxD must have a callback function that VMOUSE calls to draw the cursor and to retrieve information about the VxD.


CursorProc

include vmd.inc

mov     eax, FunctionNumber
mov     ebx, VMHandle
.
. ;use other registers as needed
.
Call    CursorProc

Serves as the entry point for functions provided by a cursor VxD. VMOUSE calls this entry point to control the cursor's position and appearance and to retrieve information about the cursor. The name of the entry point is programmer defined.

  • Returns value in EAX, depending on FunctionNumber.
FunctionNumber
One of the following functions:
GETDISPLAYMODEINFO | SETCONDITIONALREGION
MOVECURSOR | SETCURSORTRAIL
QUERYDISPLAYMODE | SETDISPLAYMODE
REMOVECURSOR | SETDISPLAYPAGE
RESETCURSORDRIVER | SETGRAPHICSCURSOR
SAVERESTORESTATE | SETTEXTCURSOR

VMHandle
Handle of the current virtual machine.

See Also

GETDISPLAYMODEINFO, MOVECURSOR, QUERYDISPLAYMODE, REMOVECURSOR, RESETCURSORDRIVER, SAVERESTORESTATE, SETCONDITIONALREGION, SETCURSORTRAIL, SETDISPLAYMODE, SETDISPLAYPAGE, SETGRAPHICSCURSOR, SETTEXTCURSOR


Video Modes

VMOUSE calls the following functions to set and retrieve information about the current video mode.


DISPLAYMODEINFO

include vmd.inc

DISPLAYMODEINFO Struc
wSize                       dw ?  ;size of structure, in bytes
wFlags                      dw ?  ;see below
DMI_Virtual_Cursor_Maximum  db (SIZE Point_Struc) DUP (?)  ;see below
XChar                       db ?  ;width, in pixels, of character cells
YChar                       db ?  ;height, in pixels, of character cells
DMI_Cell_Dimensions         db (SIZE Point_Struc) DUP (?)  ;see below
cBitsPerPixel               db ?  ;bits-per-pixel ratio
wPageSize                   dw ?  ;size, in bytes, of each video page
MaxBlocks                   db ?  ;maximum number of cursor blocks
XCursorMax                  db ?  ;see below
YCursorMax                  db ?  ;see below
bMaxTrail                   db ?  ;see below
cDrawPages                  db ?  ;see below
DISPLAYMODEINFO Ends

Contains information about the current video mode.

wFlags
One of the following values:
Value | Meaning
MI_COLORCURSOR | Color cursors are supported.
MI_GRAPHICSCURSOR | Display is currently in graphics mode.
MI_NOCURSOR | No mouse cursor supported.

DMI_Virtual_Cursor_Maximum
Address of a Point_Struc structure that contains the maximum horizontal and vertical screen coordinates for the current video mode.
DMI_Cell_Dimensions
Dimensions, in pixels, of a character cell in the current video mode.
xCursorMax and yCursorMax
Maximum width and height of a graphics cursor.
bMaxTrail
Maximum length of the cursor trail, or 0 if cursor trails are not supported.
cDrawPages
Number of pages of video memory supported by the video adapter in the current video mode.

See also Point_Struc


GETDISPLAYMODEINFO

include vmd.inc

mov     eax, GETDISPLAYMODEINFO
mov     edi, OFFSET32 DisplayModeInfoStruc
Call    CursorProc

Provides VMOUSE with information about the current video mode.

  • No return value.
DisplayModeInfoStruc
Address of a DISPLAYMODEINFO structure to fill with video mode information.

See also DISPLAYMODEINFO


QUERYDISPLAYMODE

include vmd.inc

mov     eax, QUERYDISPLAYMODE
Call    CursorProc

Retrieves the current video mode.

  • Returns the mode in EAX.

See also SETDISPLAYMODE


SETDISPLAYMODE

include vmd.inc

mov     eax, SETDISPLAYMODE
mov     cl, VideoMode
Call    CursorProc

Reports whether the specified video mode is supported and, if so, prepares to display the cursor in the new mode. VMOUSE calls this function whenever the video mode changes.

  • Returns 1 in EAX if the specified video mode is supported; otherwise, returns 0.
VideoMode
Number of the new video mode.

See also QUERYDISPLAYMODE


SETDISPLAYPAGE

include vmd.inc

mov     eax, SETDISPLAYPAGE
mov     cl, DisplayPage
Call    CursorProc

Sets the number of the video page on which the cursor VxD displays the cursor.

  • No return value.
DisplayPage
Number of the new video page.


Cursor Types

An application can request a particular style of cursor for use in text or graphics mode. VMOUSE intercepts such requests and calls the current cursor VxD to implement them. This section describes the functions a cursor VxD must provide for setting the cursor style.


GRAPHICSCURSOR

include vmd.inc

GRAPHICSCURSOR Struc
cbSize           dw ?    ;size of structure, in bytes
dwOffset32Masks  dd ?    ;see below
wWidth           dw ?    ;width, in pixels, of the cursor bitmasks
wHeight          dw ?    ;height, in pixels, of the cursor bitmasks
wHotX            dw ?    ;see below
wHotY            dw ?    ;see below
wType            dw ?    ;1 if monochrome, 0 if not
GRAPHICSCURSOR Ends

Contains information that a cursor VxD uses to draw the cursor in graphics mode.

dwOffset32Masks
Offset from the beginning of the structure to the AND and XOR bitmasks. The XOR bitmask must follow the AND bitmask.
wHotX and wHotY
Horizontal and vertical coordinates of the pixel to serve as the hot spot. The coordinates are relative to the upper-left corner of the cursor bitmasks.

VMOUSE sets only 16-pixel by 16-pixel monochrome graphics cursors. A mouse hardware VxD that supports other sizes and multiple colors can call this function to set a cursor of a different size or color(s).

See also SETGRAPHICSCURSOR


SETGRAPHICSCURSOR

include vmd.inc

mov     eax, SETGRAPHICSCURSOR
mov     edi, OFFSET32 GraphicsCursorStruc
Call    CursorProc

Sets a new cursor style for use in graphics mode.

  • No return value.
GraphicsCursorStruc
Address of a GRAPHICSCURSOR structure that contains information about the new graphics cursor. A cursor VxD uses the information to draw the cursor in graphics mode.

See also GRAPHICSCURSOR


SETTEXTCURSOR

include vmd.inc

mov     eax, SETTEXTCURSOR
mov     edi, OFFSET32 TextCursorStruc
Call    CursorProc

Sets a new cursor style for use in text mode.

  • No return value.
TextCursorStruc
Address of a TEXTCURSOR structure that contains information about the new text cursor. A cursor VxD uses the information to draw the cursor in text mode.

See also TEXTCURSOR


TEXTCURSOR

include vmd.inc

TEXTCURSOR Struc
cbSize            dw ?  ;size of structure, in bytes
dwOffset32Blocks  dd ?  ;see below
bFlags            db ?  ;see below
cBlocks           db ?  ;see below
XORMask           dw ?  ;see below
ANDMask           dw ?  ;see below
TEXTCURSOR Ends

Contains information that a cursor VxD uses to draw the cursor in text mode.

dwOffset32Blocks
Offset from the beginning of the structure to an array of cursor blocks. The cursor VxD uses the blocks to display a cursor trail, making a moving cursor easier to see on liquid crystal displays (LCDs).
bFlags
Cursor type. This field is BF_HARDWARE if the hardware text cursor is selected; otherwise, the software text cursor is selected.
cBlocks
Count of blocks in the array of cursor blocks.
XORMask and ANDMask
Line numbers of the first and last scan lines in the character cell, if bit zero of bFlags is 1; otherwise, the XOR and AND bitmasks for the software text cursor.

See also SETTEXTCURSOR


Cursor Position and Appearance

VMOUSE directs a cursor VxD to move or hide the cursor by calling the cursor position and appearance functions.


MOVECURSOR

include vmd.inc

mov     eax, MOVECURSOR
mov     ecx, OFFSET32 Point_Struc
Call    CursorProc

Moves the cursor to the specified position on the display.

  • No return value.
Point_Struc
Address of a Point_Struc structure that contains the new x and y screen coordinates for the cursor.

See also Point_Struc


Point_Struc

include vmd.inc

Point_Struc STRUC
PS_Y  dw  ?  ;vertical coordinate of cursor
PS_X  dw  ?  ;horizontal coordinate of cursor
Point_Struc ENDS

Contains the x and y screen coordinates of the cursor.


REMOVECURSOR

include vmd.inc

mov     eax, REMOVECURSOR
Call    CursorProc

Hides the cursor.

  • No return value.


SETCONDITIONALREGION

include vmd.inc

mov     eax, SETCONDITIONALREGION
mov     edi, ActionFlag
mov     ecx, UpperLeft
mov     esi, LowerRight

Defines a conditional-off region on the display. The cursor VxD hides the cursor when it moves into the region.

  • No return value.
ActionFlag
Action to perform. If this flag is 0, reset the conditional-off region; if it is 1, set the region as specified by UpperLeft and LowerRight.
UpperLeft
Screen coordinates of the upper left corner of the conditional-off region. The x coordinate is in the high word, the y coordinate is in the low word.
LowerRight
Screen coordinates of the lower right corner of the conditional-off region. The x coordinate is in the high word, the y coordinate is in the low word.


SETCURSORTRAIL

Currently not implemented.


Cursor VxD State

VMOUSE calls the following functions to save, restore, or reset the state of a cursor VxD.


RESETCURSORDRIVER

include vmd.inc

mov     eax, RESETCURSORDRIVER
Call    CursorProc

Resets variables maintained by the cursor VxD to their default values.

  • No return value.


SAVERESTORESTATE

include vmd.inc

mov     eax, SAVERESTORESTATE
mov     cx,  ActionFlag
mov     edi, OFFSET32 SaveBuf
mov     esi, OFFSET32 RestoreBuf
Call    CursorProc

Saves or restores the state of the cursor VxD, or reports the required size, in bytes, of the buffer used to save the VxD's state information.

  • If ActionFlag is 0, returns the buffer size, in bytes, in EAX.
ActionFlag
One of the following actions:
Action | Meaning
0 | Returns the required size, in bytes, of the buffer used to save the cursor state
1 | Saves state information in the buffer pointed to by EDX
2 | Restores state information from the buffer pointed to by ESI

SaveBuf
Address of the buffer in which the cursor VxD saves its state information. Used only if ActionFlag is 1.
RestoreBuf
Address of the buffer from which the cursor VxD restores its state information. Used only if ActionFlag is 2.


Multimedia Device Drivers

Microsoft® Windows® provides low-level services for multimedia applications. Applications use these services to control multimedia devices such as synthesizers, waveform-audio hardware, and video-capture cards.

This topic explains the Microsoft Windows interface for multimedia drivers, including the following topics:

  • Information about a variety of audio and video devices.
  • General techniques for writing multimedia device drivers.
  • When appropriate, specific information about writing device drivers for particular devices.

This topic is an overview that relates to multimedia device drivers in general. Other parts of this help file provide specific information about writing drivers for individual multimedia devices.

  • Audio Device Drivers describes support for waveform input and output devices, MIDI input and output and MIDI synthesizer devices, and mixer devices.
  • MCI Device Drivers describes a generic, extensible approach for interacting with different multimedia devices. This section also describes how to develop drivers that use the standard features of MCI and how to extend MCI to provide access to new devices and new device features.
  • Video Capture Device Drivers describes support for video capture devices.
  • Joystick Device Drivers describes support for joystick devices.
  • Audio Compression Manager Drivers describes how to write audio compression and decompression (codec) drivers.
  • Video Compression and Decompression Drivers describes how to write video compression and decompression (codec) drivers.
  • Describes the applications for testing different types of drivers. These applications use a common shell that automates tests and lets testers manage the test suite without writing and editing batch files. This section describes the test shell and the test applications.

Before using the information in this topic , you should be familiar with the basic multimedia services available in Windows and with the Windows installable-driver interface. For information about these topics, see the Microsoft Windows Programmer's Reference.


Types of Multimedia Device Drivers

As used in this documentation, the term audio device refers to MIDI, waveform, mixer, and auxiliary devices. Audio-compression drivers and video-compression drivers support these devices. Audio-compression drivers compress and decompress audio sequences. This section includes certain information about the Audio Compression Manager (ACM) as it applies to certain audio devices.

The term video device refers to devices that process and play video images. Video-compression drivers compress and decompress both still and motion video sequences. These drivers can support hardware-assisted and software-only compression and decompression.

The Windows multimedia services support the following types of multimedia devices and drivers:

  • Auxiliary audio devices - to support audio data that gets mixed MIDI and waveform audio in a multimedia computer.
  • Waveform input devices - to convert analog audio signals into digital information.
  • Waveform output devices - to convert digital audio information into analog audio signals.
  • MIDI input ports - to receive MIDI information from external MIDI devices like keyboards and drum machines.
  • MIDI output ports - to send MIDI information to external MIDI devices.
  • Internal MIDI synthesizers - to synthesize music from MIDI information sent by applications.
  • Mixer devices - to control multiple audio lines.
  • Video-capture devices - to digitize still images and motion video images. Some video-capture devices can also overlay and play video images.
  • Audio compression and decompression drivers - to support a variety of audio data formats and files for playback and recording.
  • Video compression and decompression drivers, and video draw drivers - to support a variety of video formats and files for displaying and creating.

Internal MIDI synthesizer devices and MIDI output ports are both MIDI output devices. They use the same entry-point function and receive the same messages.

The approach to writing drivers for each of the various types of audio devices is the same. Each type of driver requires a different entry-point function, but the structure of these functions is identical. They all have similar messages to process, although some types have unique messages for operations exclusive to that particular type of device.


Sample Multimedia Device Drivers

Device drivers must be written to control a specific device. For this reason, samples that illustrate device-specific commands and functions are not practical in the DDK. However, the kit does illustrate how to communicate with the standardized Windows installable-driver interface, in such samples as IMAADPCM.

The IMAADPCM.C file contains routines that encode and decode according to the IMA-ADPCM format. This is the same format used in Intel's DVI standard. The IMA has endorsed this format as a standard for audio compression, and Intel has released it as public-domain software. The files for this sample are in the IMAADPCM directory.


Structure of Multimedia Device Drivers

Multimedia device drivers and other installable drivers are dynamic-link libraries (DLLs), usually written in C, assembly language, or a combination of the two languages. The filenames for device-driver DLLs are not required to have a filename extension of .DLL. You can name your driver using any filename extension you like. For drivers that do not use the ACM, the extension .DRV conforms to Windows development conventions. For drivers that use the ACM, the extension .ACM is the Windows convention.

Installable drivers provide a DriverProc entry point to process system messages. The DriverProc entry point processes messages sent by the system to the driver as the result of an application call to a low-level function. For example, when an application opens a video-capture device, the system sends the specified device driver a DRV_OPEN message. The DriverProc function receives and processes this message.

For general information about installable drivers, the DriverProc entry point, and system messages sent to this entry point, see the Microsoft Windows Programmer's Reference. The device-specific main topics in this documentation include supplemental information for many system messages. This information describes specifically how multimedia drivers should respond to the system messages that are critical to their operation.

Note Your driver should respond to all system messages, not just those described in this main topic. For messages not included in this main topic, use the definitions provided in the Microsoft Windows Programmer's Reference.

Video drivers use the DriverProc entry point to process messages specifically for video operation. Information about how drivers use the DriverProc entry point to process these messages is contained in the device-specific main topic.

Audio drivers supplement the DriverProc entry point with the wodMessage, widMessage, modMessage, midMessage, and auxMessage entry points to process messages specifically for audio operation. Device-specific main topics include information about how drivers use these entry points to process audio messages.


Header Files for Multimedia Device Drivers

Audio and video device drivers use the following header files to define functions, messages, data structures, error returns, and constants.

Header file | Used for
MSVIDEO.H | Video-capture device drivers
MSVIDDRV.H | Video-capture device drivers and applications
COMPDDK.H | Video compression and decompression drivers
MSACM.H | Audio compression and decompression functions, structures, and constants
MSACMDRV.H | Functions, structures, and constants for writing audio compression or decompression drivers
MMREG.H | Registration database information, such as registration ID
MSACMDLG.H | Functions, structures, and constants for using the Audio Compression Manager (ACM) standard dialog box
MSACMDLG.DLG | The template for the ACM dialog box


Interacting with Multimedia Device Drivers

An application that controls a multimedia driver is an integral part of the driver operation. For example, a video-capture application that doesn't use the AVICap window class allocates the memory used for audio and video capture and manages the data buffers used to transfer data. If audio is to be captured simultaneously with video, the application also controls the audio driver used for capturing the input audio. Once the video and audio drivers capture the data, the application has the responsibility for any post-processing of this data. For example, for the application to save the data as an AVI file, it must add the appropriate headers and create the AVI RIFF structure saved in the disk file.

Windows provides the interface between applications and device drivers - applications do not call the drivers directly. When an application calls a function, Windows translates the call into a message and sends the message to the appropriate device driver. When a device driver must notify a client of an event, it calls MMSYSTEM with a message, and MMSYSTEM routes the message back to the client application.

The term client application is sometimes used to describe the Windows interface from the device driver's perspective. The client application can include the Windows environment as well as the application that is controlling multimedia operation.

The following table summarizes the DLLs Windows requires to provide access to multimedia audio and video device drivers.

This DLL | Provides an interface to these drivers
MMSYSTEM.DLL | Waveform MIDI Auxiliary
MSVIDEO.DLL | Video capture, compression and decompression, rendering
MSACM.DRV | Audio compression and decompression mapper
MSACM.DLL | Compression and system management for the ACM


Initializing and Configuring Multimedia Device Drivers

To activate an installed driver, the multimedia driver must receive an initialization message, DRV_OPEN. The DRV_OPEN message sets up an initial session in which the instance information is NULL. This session keeps the driver active as long as it is installed. Because this session remains open for a long time, it is important that no critical resources be allocated and left allocated for the life of the session.

If your device driver supports more than one interrupt-level or port assignment, it should allow user configuration through the Multimedia option in the Control Panel. Through the DRV_CONFIGURE message, installable drivers can supply a configuration dialog box for this purpose. The dialog box should display the name and version number of your device driver.

In addition to the DRV_CONFIGURE message, device drivers might support driver-specific messages. For example, video-capture drivers also use the DVM_DIALOG message to display dialog boxes for configuring various channels. For more information about the messages for displaying additional dialog boxes, see the main topics describing specific device drivers.

Installable drivers can supply a configuration dialog box for users to access through the Drivers option in the Control Panel. The Multimedia option sends the DRV_CONFIGURE message to your driver to display the dialog box. The dialog box should display the name and version number of your device driver. If your device driver supports different interrupt-level and port assignments, it should also support user configuration through the Multimedia option in the Control Panel.


Introduction

This topic contains information that pertains to non-Plug and Play devices. Configuration and loading information for Plug and Play devices is stored in the registry.

The SYSTEM.INI file contains information for loading and configuring device drivers. Your device driver must be identified in the [drivers] section. Your device driver might also have entries in the [386enh] section if it requires any VxDs for operation. Your driver might also reserve a device-specific section in the SYSTEM.INI to store configuration information. When you install or remove a device, the installation program updates the [drivers] and [386enh] sections.


Interrupt-Level and Port Assignments

Interrupt-level and port assignments, and any other hardware-related settings, can be stored in a section with the same name as the driver in the user's SYSTEM.INI file. (Alternatively, your driver might use its own .INI file for this information.)

For example, the following SYSTEM.INI section, created by the Bravado driver, specifies interrupt level 9 and memory base E:

[Bravado.drv]
Interrupt=9
MemoryBase=E

To conform to other Windows drivers, use the keynames int and port to specify interrupt-level and port assignments. For example, the following SYSTEM.INI section specifies interrupt level 3 and port 0x220 for the Sound Blaster(tm) driver:

[Sound Blaster]
int=3
port=220

Note Software-only codecs do not require interrupt and port settings, but hardware-assisted codecs do. Interrupt and port settings for hardware-assisted codecs are similar to those used by wave and capture drivers. The ACM is like software-only codecs in that it does not require specific interrupt and port settings. The installation program for any audio hardware in a system should create the appropriate entries for that hardware.


Support for Driver Installation

The Multimedia option in the Control Panel is the preferred method for installing device drivers. The Multimedia option uses information in the OEMSETUP.INF file for your driver to add the entries in the [drivers] section, as well as entries in the [386enh] section, to install any VxDs you require.

The entry that identifies your driver in the [drivers] section lets Windows load the driver. If this entry is absent, your driver won't be recognized. While installation programs usually add the necessary entry for completed device drivers, you might have to manually add it while you are developing your device driver. You might also have to manually add any [386enh] entries you need. The final version of your device driver should use an installation program to create and delete the entries in these two sections. The following table identifies the keynames for various multimedia drivers.

Use this keyname | For the following driver types
MSVideo | Video-capture device drivers.
wave | Waveform device drivers.
midi | MIDI device drivers.
vidc.nnnn | Video compression or decompression device driver. In this case, nnnn represents the four-character code for the driver.
msacm.nnnn | Audio compression or decompression device driver. In this case, nnnn represents the four-character code for the driver.
vids.nnnn | Video stream compression driver. In this case, nnnn represents the four-character code for the driver.

If there is more than one wave or MIDI driver, append a number from 1 to 9 after the keyname. When you have multiple drivers, use sequential numbers to identify them.

For example, the following [drivers] section extract identifies one waveform device driver named SNDBLST2.DRV, two MIDI device drivers named ADLIB.DRV and MPU401.DRV, and one video-capture device driver named BRAVADO.DRV.

[drivers]
timer=timer.drv
joystick=ibmjoy.drv
wave=*.drv
midi=*.drv
midimapper=midimap.drv
wavemapper=msacm.drv
MSVideo=bravado.drv

Note After installing an audio driver with the Multimedia option in the Control Panel, Windows must be restarted to load the driver.


Video-Capture Drivers

You can have more than one driver of the MSVideo type in the [drivers] section. The following example shows a [drivers] section with entries for five video-capture drivers:

[drivers]
MSVideo=targa16.drv
MSVideo1=testdrv.drv
MSVideo2=bravado.drv
MSVideo3=vblaster.drv
MSVideo4=MYDRVR.DRV

If you are using the VidCap video-capture application, you can select the video-capture driver it uses with the -d command-line option. The integer specified after the -d corresponds to the video-capture driver entry. For example, the command VidCap -d0 uses the TARGA16.DRV driver associated with the MSVideo entry. VidCap -d3 uses the VBLASTER.DRV associated with the MSVideo3 entry.

Note Video-capture device drivers are loaded only when needed by an application.


Video Compression and Decompression Drivers

Video compression and decompression drivers can use an entry in the [Installable Compressors] section of the SYSTEM.INI file for loading and configuring the driver. Identify your driver in the [drivers] section if you want to use the Multimedia option of the Control Panel to install or configure it. Identify your driver in the [Installable Compressors] section if you want to use a custom-installation application. If you use a custom-installation application, it should update the [Installable Compressors] section when your driver is installed or removed.

Video compression and decompression drivers are identified by the keyname VIDC., followed by its four-character code identifier. For example, the following [Installable Compressors] section of SYSTEM.INI identifies one video compression and decompression driver:

[Installable Compressors]
VIDC.SAMP = ICSAMPLE.DRV

SAMP is the four-character code identifier of the compressor. This driver has a file name of ICSAMPLE.DRV.

The four-character code identifier must be unique. If you want to create a new four-character code identifier, register it with Microsoft to set up a standard definition and avoid any conflicts with other codes that might be defined. To register a code for a compression and decompression driver, request a Multimedia Developer Registration Kit from the following group:

Microsoft Corporation
Advanced Consumer Technology Group
Product Marketing
One Microsoft Way
Redmond, WA 98052-6399

For more information about four-character codes, see the Microsoft Windows Programmer's Reference.


Multimedia Device Information (INF) Files

IHVs who develop a multimedia hardware device for Windows 95 must provide a device information file (.INF) file on the device driver installation diskette for the device. There are two DDK sample INF files for multimedia hardware devices that you can use as models for your INF file. They are located in the directory \DDK\MMEDIA\SAMPLES\INF. The sample INF files are:

  • MIDI.INF, which is used to install a MIDI device.
  • WAVE.INF, which is used to install a waveform-audio device.

These sample INF files are both relatively straightforward. The DDK section Device Information (INF) File Reference in the Plug and Play section of the Windows 95 DDK documentation gives you enough information to interpret the sample INF files and make any necessary changes to fit your device. The following topics give information specific to multimedia hardware device INF files that is not found in the Device Information (INF) File Reference section. Information about INF files for multimedia software components will be provided in a future release of the Windows 95 DDK documentation.


Multimedia Device Class Registration

Every INF file should contain a device-class registration section, because a particular Windows 95 user may have never previously installed a device of that class on their Windows 95 machine. (For more information, see the Class Install Section)

For example, in the sample MIDI.INF file, the ClassInstall section and sections associated with it contain the following lines:

[ClassInstall]
AddReg=MidiReg

[MidiReg]
HKR,,,,%MediaClassName%
HKR,,Icon,,1
. . .
[Strings]
MediaClassName="Media Devices"

The sample WAVE.INF file contains a ClassInstall section and associated sections with lines that are shown below:

[ClassInstall]
AddReg=Class.AddReg

[Class.AddReg]
HKR,,,,%MediaClassName%
HKR,,Icon,,1
. . .
[Strings]
MediaClassName="Media Devices"

These INF file sections from both the MIDI.INF and WAVE.INF sample INF files register a descriptive string for a MEDIA class device: "Media Devices." All multimedia hardware device INF files must register this same descriptive string, "Media Devices," in this way. This descriptive string is displayed by Windows 95 in the user interface to describe the group of all MEDIA class devices.

Note that the descriptive string itself ("Media Devices") is in the [Strings] section of the INF file along with other displayable strings. Putting all displayable strings in one section of an INF file makes it easier for translators to locate the words and phrases they have to translate for world markets.


Device Loader for Windows 95 Multimedia Devices

All multimedia device drivers must be loaded by the Windows 95 device loader MMDEVLDR.VXD, which establishes the device driver(s) in Ring 3, as described earlier in this section. All of the sample multimedia INF files have the following line in the section that adds the device to the registry:

HKR,,DevLoader,,mmdevldr.vxd

For example, in the MIDI.INF sample file, such a line is found in both the [MPU401.AddReg] and [ADLIB.addreg] sections. Your INF file must use the same line in the comparable section that adds your device to the registry.


Internal/External Switch for MIDI Devices

For MIDI devices, one statement type that can be used in an INF file is not documented in the Device Information (INF) File Reference section. (For multimedia hardware devices other than MIDI devices, there are no INF file statement types other than those documented in the Device Information (INF) File Reference section; no special switches have to be set for non-MIDI devices.)

If your MIDI device drives a synthesizer that is not on the device, include a statement that sets an "External" switch in the Drivers key of the registry for your device by using an INF file statement of the form:

HKR,Drivers\midi\msmpu401.drv,External,1,01,00,00,00

Following is an example of such a statement, in the context of the entire section that puts values into the Drivers key for the device (note that this example section is not taken from the sample MIDI.INF file).

[MPU401.AddReg]
HKR,,Driver,,msmpu401.vxd
HKR,Drivers\midi\msmpu401.drv,Driver,,msmpu401.drv
; following is the statement to use for external synthesizer
HKR,Drivers\midi\msmpu401.drv,External,1,01,00,00,00
HKR,Drivers,SubClasses,,"midi"


Writing Multimedia Device Drivers

The following topics describe the process for writing multimedia device drivers.


Entry-Point Functions

Following is an example of a DriverProc function. Regardless of how many types of audio devices a driver supports, the driver always has a single DriverProc function. The following example is the DriverProc function from the DRVPROC.C file, which supports four types of audio devices. While this example focuses heavily on ACM examples, the concepts are similar to those used for other types of drivers as well.

//  DWORD DriverProc
//
//  Description:
//      The entry point for an installable driver.
//
//  Parameters:
//      DWORD dwDriverID
//
//      For most messages, dwDriverId is the DWORD
//      value that the driver returns in response to a DRV_OPEN message.
//      Each time that the driver is opened, through the DrvOpen API,
//      the driver receives a DRV_OPEN message and can return an
//      arbitrary, nonzero value. The installable driver interface
//      saves this value and returns a unique driver handle to the
//      application. Whenever the application sends a message to the
//      driver using the driver handle, the interface routes the message
//      to this entry point and passes the corresponding dwDriverId.
//      This mechanism allows the driver to use the same or different
//      identifiers for multiple opens but ensures that driver handles
//      are unique at the application interface layer.
//
//      The following messages are not related to a particular open
//      instance of the driver. For these messages, the dwDriverId
//      will always be zero.
//
//         DRV_LOAD, DRV_FREE, DRV_ENABLE, DRV_DISABLE, DRV_OPEN
//
//      HANDLE hDriver
//
//      This is the handle returned to the application by the driver
//      interface.
//
//      WORD wMessage
//
//      The requested action to be performed. Message values
//      below DRV_RESERVED are used for globally defined messages.
//      Message values from DRV_RESERVED to DRV_USER are used for
//      defined driver protocols. Messages above DRV_USER are used
//      for driver specific messages.
//
//      DWORD dwParam1
//
//      Data for this message.  Defined separately for each message
//
//      DWORD dwParam2
//
//      Data for this message.  Defined separately for each message
//
//  Return (DWORD):
//      Defined separately for each message.

DWORD FAR PASCAL _loadds DriverProc
(
    DWORD           dwDriverID,
    HANDLE          hDriver,
    WORD            wMessage,
    DWORD           dwParam1,
    DWORD           dwParam2
)
{
   switch (wMessage)
   {
      case DRV_LOAD:

         // Sent to the driver when it is loaded. Always the first
         // message received by a driver.
         //
         // dwDriverID is 0L.
         // lParam1 is 0L.
         // lParam2 is 0L.
         //
         // Return 0L to fail the load.
         //
         // DefDriverProc will return nonzero so we don't have to
         // handle DRV_LOAD
         //

         DPF( 1, "DRV_LOAD" ) ;

#if 0
         // Make sure we're running on Windows 95...

         if (GetWindowsVersionCorrectly() < 0x0400)
         {
            AlertBox( NULL, SR_ALERT_31 ) ;
            return 0L ;
         }
#endif

         return 1L ;

      case DRV_FREE:

         //
         // Sent to the driver when it is about to be discarded. This
         // will always be the last message received by a driver before
         // it is freed.
         //
         // dwDriverID is 0L.
         // lParam1 is 0L.
         // lParam2 is 0L.
         //
         // Return value is ignored.
         //

         DPF( 1, "DRV_FREE" ) ;

         return 1L ;

      case DRV_OPEN:

         //
         // Sent to the driver when it is opened.
         //
         // dwDriverID is 0L.
         //
         // lParam1 is a far pointer to a zero-terminated string
         // containing the name used to open the driver.
         //
         // lParam2 is passed through from the drvOpen call.
         //
         // Return 0L to fail the open.
         //
         // DefDriverProc will return ZERO so we do have to
         // handle the DRV_OPEN message.
         //

         DPF( 1, "DRV_OPEN" ) ;

         // No longer in initialization

#pragma message( REMIND( "bJustStart used???" ) )

         // bJustStart = 0 ;
         return 1L ;

      case DRV_CLOSE:

         //
         // Sent to the driver when it is closed. Drivers are unloaded
         // when the close count reaches zero.
         //
         // dwDriverID is the driver identifier returned from the
         // corresponding DRV_OPEN.
         //
         // lParam1 is passed through from the drvOpen call.
         //
         // lParam2 is passed through from the drvOpen call.
         //
         // Return 0L to fail the close.
         //
         // DefDriverProc will return ZERO so we do have to
         // handle the DRV_CLOSE message.
         //

         DPF( 1, "DRV_CLOSE" ) ;

         return 1L ;

      case DRV_ENABLE:

         //
         // Sent to the driver when the driver is loaded or reloaded
         // and whenever Windows is enabled. Drivers should only
         // hook interrupts or expect any part of the driver to be in
         // memory between enable and disable messages
         //
         // dwDriverID is 0L.
         // lParam1 is 0L.
         // lParam2 is 0L.
         //
         // Return value is ignored.
         //

         DPF( 1, "DRV_ENABLE" ) ;

         if (DrvInit())
            return 0L ; // error

         // Load the volume settings, etc.

#pragma message( REMIND( "Need to load settings from registry" ) )

//         DrvLoadVolumeFromIni();

         // No longer in initialization

#pragma message( REMIND( "bJustStart used???" ) )

         // bJustStart = 0 ;
         return 1L ;

      case DRV_DISABLE:

         //
         // Sent to the driver before the driver is freed.
         // and whenever Windows is disabled
         //
         // dwDriverID is 0L.
         // lParam1 is 0L.
         // lParam2 is 0L.
         //
         // Return value is ignored.
         //

         DPF( 1, "DRV_DISABLE" ) ;

#pragma message( REMIND( "Need to save settings to registry" ) )

//         DrvSaveVolumeToIni () ;

         DrvEnd() ;

         return 1L ;

      case DRV_QUERYCONFIGURE:

         //
         // Sent to the driver so that applications can
         // determine whether the driver supports custom
         // configuration. The driver should return a
         // nonzero value to indicate that configuration
         // is supported.
         //
         // dwDriverID is the value returned from the DRV_OPEN
         // call that must have succeeded before this message
         // was sent.
         //
         // lParam1 is passed from the app and is undefined.
         // lParam2 is passed from the app and is undefined.
         //
         // Return 0L to indicate configuration NOT supported.
         //

         DPF( 1, "DRV_QUERYCONFIGURE" ) ;

#pragma message ( REMIND( "configure if not operational???" ) )

#if 0
         return (fEnabled != 0) ;        // we do configuration
#endif
         return TRUE ;

      case DRV_CONFIGURE:

         //
         // Sent to the driver so that it can display a custom
         // configuration dialog box.
         //
         // lParam1 is passed from the app. and should contain
         // the parent window handle in the loword.
         // lParam2 is passed from the app and is undefined.
         //
         // Return value is REBOOT, OK, RESTART.
         //

         DPF( 1, "DRV_CONFIGURE" ) ;

#if 0
         if (fEnabled)
            return DrvConfig( LOWORD( dwParam1 ), ghModule ) ;
#endif
         // else, default */
            break;

      case DRV_INSTALL:
         DPF( 1, "DRV_INSTALL" ) ;
         return DRV_OK ;

      case DRV_REMOVE:
         DPF( 1, "DRV_REMOVE" ) ;
         return 0 ;

      case DRV_POWER:
         DPF( 1, "DRV_POWER" ) ;

         switch (dwParam1)
         {
            case PWR_SUSPENDREQUEST:

               // If we decided we wanted to try to cause the machine to
               // not suspend, we would return PWR_FAIL. However, the
               // machine may still be suspended - (the APM BIOS may
               // override the driver's wishes).

               break ;

            case PWR_SUSPENDRESUME:

               // This notification is just for information.  PWR_OK
               // should be returned regardless of what the driver does
               // to resume normal hardware operations.

               break ;

            case PWR_CRITICALRESUME:

               // This notification is just for information.  This
               // message indicates that the APM BIOS suspended the
               // system without prior notice.  PWR_OK should be
               // returned regardless of what the driver does to resume
               // normal hardware operations.
               break ;
         }
         return PWR_OK ;
   }

   return DefDriverProc( dwDriverID, hDriver, wMessage,
                         dwParam1, dwParam2 ) ;

} // DriverProc()


Enabling and Disabling Drivers

The DriverProc function calls two functions, Enable and Disable, to enable and disable the driver. These functions are part of the driver. Their implementation is dependent upon the target hardware and the structure of the driver.

Generally, when a driver is enabled, you initialize the hardware, hook interrupts, allocate any memory you need, and set a flag to indicate that the driver is enabled. The exact sequence your device driver follows is determined by the requirements and structure of your device driver. For example, the Bravado device driver uses interrupts only for streaming data. When enabled, it will hook its interrupts only if it was disabled while streaming data.

If your driver has not been enabled by MMSYSTEM, or if it failed the enable process, the driver should return MMSYSERR_NOTENABLED for any messages it receives from client applications. When a driver is disabled, you free any memory you allocated, unhook interrupts, reset the hardware, and set a flag to indicate the driver is not enabled.

It's possible for a driver to receive a DRV_DISABLE message while it is sending or receiving audio data, resulting in a DRV_DISABLE/DRV_ENABLE message pair. For example, this can happen when the user switches to an MS-DOS application while Windows is running in standard mode.

The following table indicates how audio and video device drivers should respond to a DRV_DISABLE/DRV_ENABLE message pair.

Driver type | Responds as if
Waveform output | The driver is paused with a WODM_PAUSE message, and then restarted with a WODM_RESTART message.
Waveform input | The driver is stopped with a WIDM_STOP message, and then restarted with a WIDM_START message.
MIDI output | The driver is disabled, and then re-enabled. If the driver is asynchronous, output stops when the driver is disabled and continues when the driver is re-enabled.
MIDI input | The driver is stopped with a MIDM_STOP message, and then restarted with a MIDM_START message.
Video capture | The driver is stopped with a DVM_STREAM_STOP message, and then restarted with a DVM_STREAM_START message.


Combining Device Drivers

Audio hardware that has waveform, MIDI, and mixer capabilities typically uses one driver to access its hardware functions. While the driver has separate entry-points for each audio function, the driver can use a single DriverProc entry point to handle the system messages.

If the same hardware supports video capture as well as video compression, you can combine both of these functions into one DLL and use a single DriverProc entry point to service them. The shared entry point simplifies the coordination of the different functions.


Additional Entry-Point Functions for Audio Device Drivers

In addition to the installable-driver entry-point function, DriverProc, an audio device driver must have at least one of the following entry-point functions:

  • The wodMessage function for waveform output drivers
  • The widMessage function for waveform input drivers
  • The modMessage function for MIDI output drivers and internal-synthesizer drivers
  • The midMessage function for MIDI input drivers
  • The auxMessage function for auxiliary audio drivers

Drivers that service more than one type of audio device must have one of these entry-point functions for each type of device serviced.

Note ACM compression and decompression drivers use only the DriverProc entry point.

These functions process messages sent by MMSYSTEM to the driver as the result of an application call to a low-level audio function. For example, when an application opens a waveform output device with the waveOutOpen function, MMSYSTEM sends the specified waveform-output device driver a WODM_OPEN message. The driver's wodMessage function receives and processes this message. For the exact syntax of each of these entry-point functions, see the sections about writing drivers for specific types of audio devices, later in this main topic.


Reentrancy Considerations with Entry-Point Functions

The auxMessage, widMessage, wodMessage, and midMessage entry-point functions are not called at interrupt time and therefore do not have to be written to be reentrant. However, the entry-point function for MIDI output devices, modMessage, can be called at interrupt time.


Transferring Multimedia Data to and from Device Drivers

The primary purpose of a multimedia device driver is to transfer data between an application and the audio or video device. The data-transfer model used depends on the data transferred and the device involved. For example, the model for data transfer is different for waveform devices than it is for MIDI devices because of the nature of the data. Auxiliary audio devices don't require the transfer of audio data, just control information.


Single-Frame Data Capture

Single-frame data capture supports simple video capture. Applications might use this form of data capture to record animated sequences created frame-by-frame or, to capture a single still image, such as a photograph.

This data transfer model typically involves a high data-transfer rate. It is similar to streaming data, except it does not require the continuous transfer of data.

The following sequence of operations occurs when a client application requests the transfer of a single video frame

  1. The client allocates the memory for the data buffer.
  2. The client sets a pointer to the empty data buffer in a data structure and sends the device driver a pointer to it.
  3. When the device driver receives the messages to capture data, it fills the data buffer with information from the frame buffer and updates the data structure.
  4. When the device driver has filled a data buffer, it returns control to the client.
  5. After the client has finished with the data, it frees the memory used for the data.


Streaming Data Transfer

Waveform and video streams involve the continuous flow of real-time audio and video data. Typically, these streams involve a high data-transfer rate and require significant processor time.

The data-transfer model for streaming audio and video input is similar. If you have worked with waveform or video-capture device drivers, many of the concepts you already understand apply to the other type of driver.

The following sequence of operations occurs when streaming waveform or video data between a device driver and a client application

  1. The client allocates the memory buffers for the audio or video data.
  2. If required, the client initializes the data stream.
  3. The client requests that the driver prepare the data buffers.
  4. The client sends the empty data buffers to the driver.
  5. The driver puts the data buffers in its input queue.
  6. When the streaming operation begins, the driver fills a data buffer and sets the done bit for the data buffer. The driver then releases the buffer from its queue and proceeds to fill the next buffer.
  7. When the client is ready for data, it uses the done bit or a callback to see if the data in the buffer is ready.
  8. After the client empties the buffer, it resets the done bit and sends the empty buffer back to the driver for it to add to its queue.

Once the stream starts, the client application and the audio and video device driver do not communicate directly. The device driver fills the data buffers at the data rate specified by the client application. It fills the buffers without waiting for any synchronization signal from the application, as long as buffers are available and it is not paused or stopped by the application. The buffers are filled in the order that the driver receives them from the application. (If the device driver runs out of buffers, it should set an error flag. A client video application can use the DVM_STREAM_GETERROR message to test for this condition.)

The client application expects the buffers back in the order that it sends them to the device driver. When it is ready for more data, it checks the done bit of the next buffer it expects to receive from the device driver. If the done bit is set, the application continues operation with that buffer. If the done bit is not set, the application periodically checks the done bit while it waits for the buffer.

Streaming continues until it is stopped by the application.

The following sequence of operations occurs when the application has finished capturing data

  1. When the client stops the streaming operation, the driver stops filling buffers.
  2. If the client wants to restart streaming, it sends a message to restart streaming. If the client is finished streaming, it requests that the driver unprepare the data buffers.
  3. The client releases the data stream and frees the memory allocated for the data.

Preparing Data Buffers

Because audio and video data buffers must be accessed at interrupt time, the memory allocated for them is subject to the requirements mentioned in . Rather than have the client application prepare the memory before sending data blocks to the driver, the client requests that the driver make the preparations.

This request involves two messages, in the form of _PREPARE and _UNPREPARE. Most drivers can respond to these messages by returning a MMSYSERR_NOTSUPPORTED error. Then, MMSYSTEM prepares the data block by page-locking it so the driver can access it at interrupt time. For example, most drivers can respond to the DVM_STREAM_PREPAREHEADER and DVM_STREAM_UNPREPAREHEADER messages by returning a DV_ERR_UNSUPPORTED error. When a driver returns the DV_ERR_UNSUPPORTED error, MMSYSTEM prepares the data block by page-locking the header and data sections so the driver can access them at interrupt time.

If a device driver does not need page-locked data (for example, if the application immediately copies the data to an on-card buffer) or if the buffer requires additional preparation, the application can respond to these messages directly instead of letting MMSYSTEM handle them. An application should respond to both messages, or to neither.

The following table identifies the drivers that use these messages, and the name of the prepare and unprepare messages.

Driver type | Prepare/unprepare message
MIDI input | MIDM_PREPARE MIDM_UNPREPARE
MIDI output | MODM_PREPARE MODM_UNPREPARE
Waveform audio input | WIDM_PREPARE WIDM_UNPREPARE
Waveform audio output | WODM_PREPARE WODM_UNPREPARE
Video capture | DVM_STREAM_PREPAREHEADER DVM_STREAM_UNPREPAREHEADER
Audio compression and decompression | ACMDM_STREAMPREPARE ACMDM_STREAMUNPREPARE


Data Transfer Using the Audio Compression Manager

If the Audio Compression Manager (ACM) is involved in the transfer, the data transfer model is as follows:

  1. The client allocates the memory for the source and destination buffers. The ACMDM_STREAM_PREPARE message prepares the buffers.
  2. The client sends both source and destination data blocks to the driver.
  3. The driver processes the data blocks.
  4. The driver (codec) returns the data to the client. The ACMDM_STREAM_UNPREPARE message releases the buffers, reversing the preparations made earlier by the ACMDM_STREAM_PREPARE message.
  5. The client then frees the memory for both data blocks.


Data Transfer Using Waveform Device Drivers

The following sequence of operations occurs when transferring audio data between a client application and a waveform-output device driver:

  1. The client allocates the memory for the data block.
  2. The client requests that the driver prepare the data block.
  3. The client sends the data block to the driver.
  4. The driver puts the data block in its output queue.
  5. The client can send additional data blocks, which the driver also puts in its output queue.
  6. When the driver has sent a data block from its output queue to its output device, it returns the data block to the client by sending the client a message.
  7. The client requests that the driver clean up the preparation previously done on the data block.
  8. The client then frees the memory for the data block.

In addition, the driver must transfer the data it receives from the client to the waveform hardware. This transfer takes place in the background, as an interrupt-driven process. The driver can transfer data directly, or it can use the computer's DMA controller to transfer the data. Whether you choose to transfer data directly or use DMA depends on the capabilities of your target hardware.

For input devices, the model is similar, except the client sends the driver an empty buffer. The buffer is directly filled with audio data by the driver or with DMA. The driver notifies the client when the buffer is filled.


Data Transfer Using MIDI Device Drivers

With MIDI system-exclusive events, data transfer between a client application and a MIDI device driver is identical to the sequence described for waveform and video drivers. However, for all other MIDI events, the driver uses a different transfer mechanism. Because all other MIDI events are 3 bytes or fewer in size, they are packed into a DWORD and sent directly to the driver for output. The driver parses the event to determine its size, and sends the individual bytes to the MIDI output hardware. If the driver is for an internal synthesizer, it parses the event and responds accordingly. MIDI-input device drivers wait until receiving a complete MIDI event before packing the event into a DWORD and sending it to the client application through its callback.


Module-Definition Files

To build a device-driver DLL, you must have a module-definition (.DEF) file. From this file, you export entry-point functions. Note that the DriverProc entry point must be exported for all drivers. If you are writing a waveform, MIDI, mixer, or auxiliary driver, you must export additional entry-point functions, as specified in the following list:

  • The DriverProc function must be exported for all audio device drivers.
  • The wodMessage function must be exported for waveform output drivers.
  • The widMessage function must be exported for waveform input drivers.
  • The modMessage function must be exported for MIDI output drivers.
  • The midMessage function must be exported for MIDI input drivers.
  • The auxMessage function must be exported for auxiliary audio drivers.
  • The mxdMessage function must be exported for mixer drivers.


Example .DEF File

The .DEF file exports entry-point functions, as shown in the following example taken from the MSSB16.DEF file:

LIBRARY     MSSB16

DESCRIPTION 'wave,aux,mixer:Creative Labs Sound Blaster 16 Driver'

EXETYPE     WINDOWS
PROTMODE

CODE        MOVEABLE DISCARDABLE LOADONCALL
DATA        FIXED SINGLE PRELOAD

SEGMENTS    _TEXT     FIXED                PRELOAD
            WEP_TEXT  FIXED                PRELOAD
            INIT      MOVEABLE DISCARDABLE PRELOAD
            COMMON    MOVEABLE DISCARDABLE PRELOAD
            MIXER     MOVEABLE DISCARDABLE PRELOAD
            WAVE      MOVEABLE DISCARDABLE PRELOAD

HEAPSIZE    2048

EXPORTS     WEP             @1          RESIDENTNAME
            DriverProc      @2          RESIDENTNAME
            wodMessage      @3          RESIDENTNAME
            widMessage      @4          RESIDENTNAME
            auxMessage      @5          RESIDENTNAME
            mxdMessage      @6          RESIDENTNAME

For more information about the entry-point function listed in this example, see .

In this example, functions are exported by ordinal. The actual ordinal values you assign to each exported function are not significant, though each must be unique within the DLL.


Module-Name Line

The module-name line should specify a unique module name for your device driver. Windows will not load two different modules with the same module name. It's a good idea to use the base of your driver filename because, in certain instances, LoadLibrary assumes that to be your module name. For example, here's the module-name line from the first example in the previous section:

LIBRARY     MSSB16


Module-Description Line

The module-description line in the module-definition file should specify the type of device the driver supports. The content of this line varies for each type of driver.

The Multimedia option in the Control Panel uses the name in the module-description line to identify different types of drivers and to create the entry in the [drivers] section of SYSTEM.INI when installing a driver.

Module-Description Line for Video-Capture Drivers

To indicate that a driver is a video-capture driver, use MSVIDEO followed by a colon (:) in the module-description line.

The Bravado driver is an example of a video-capture driver. The module-description line from the Bravado driver is the following:

DESCRIPTION 'MSVIDEO: Truevision Bravado Driver'

Module-Description Line for Video-Compression Drivers

To specify a video-compression driver, include the keyname of VIDC, a period (.), and the four-character code for your driver in the DESCRIPTION entry. Use a colon (:) to separate this entry from the text description.

The ICSAMPLE.DRV driver is an example of a video-compression driver. The module-description line from this driver is the following:

DESCRIPTION 'VIDC.SAMP:Sample Decompression Driver'

If you are using a custom-installation application instead of assuming installation through the Multimedia option in Control Panel, you do not need to include this description information.

Module-Description Line for Audio Compression Drivers

It is not necessary to include a keyword to specify an ACM driver. Instead, use a text string that fully describes the driver. For example, the following is the module-description line for the IMA ADPCM driver:

DESCRIPTION 'Microsoft Audio Compression Manager IMA ADPCM CODEC'


Considerations for Interrupt-Driven Drivers

Most audio device drivers are interrupt-driven. For example, a waveform output device interrupts when the device needs another data block. A MIDI input device interrupts when the device receives a MIDI event at its input port. Driver code accessed during an interrupt service routine must adhere to the guidelines discussed in the following sections.

Note Audio and video compression and decompression drivers are not typically accessed during interrupts.


Fixing Code and Data Segment

Any code segments or data segments a driver accesses at interrupt time must be fixed segments. For best overall system performance, you should minimize the amount of code and data in fixed segments. To minimize the amount of fixed code, isolate all interrupt-time code in a few source modules and put this code into a single fixed-code segment. Unless your driver has a large amount of data not accessed at interrupt time, use a single fixed-data segment.

The data segment _TEXT is used as a safety measure. The compiler places code for which you do not specify a segment in the _TEXT segment. This way, any code that is missed will be placed into a single segment, preventing possible problems at interrupt time. If you use fixed segments, you should check your segmentation to ensure that only code that is required to be FIXED goes into the FIXED code segment.

The Bravado video-capture driver is a medium-model DLL, using a single data segment and multiple code segments. The following example fragment is from the module-definition file for the Bravado device driver:

CODE        MOVEABLE  DISCARDABLE  LOADONCALL
DATA        FIXED  SINGLE  PRELOAD

SEGMENTS    _TEXT   FIXED                    PRELOAD
            INIT    MOVEABLE   DISCARDABLE   PRELOAD
            VCAP    MOVEABLE   DISCARDABLE   PRELOAD

This example fixes the data segment and the code segment named _TEXT. All other code segments are moveable.


Allocating and Using Memory

You can allocate either local memory or global memory for use at interrupt time.

Local Memory

To allocate local memory for use at interrupt time, follow these steps:

  1. Use LocalAlloc with the LMEM_FIXED flag to get a handle to the memory block. (This assumes fixed data segments.)
  2. Pass this handle to LocalLock to get a near pointer to the memory block.

Global Memory

Any global memory a driver uses at interrupt time must be page-locked. To allocate and page-lock global memory, follow these steps:

  1. Use GlobalAlloc with the GMEM_MOVEABLE and GMEM_SHARE flags to get a handle to the memory block.
  2. Pass this handle to GlobalLock to get a far pointer to the memory block.
  3. Pass the high-order word of the far pointer to GlobalPageLock to page-lock the memory block.


Calling Windows Functions at Interrupt Time

The only Windows functions a driver can call at interrupt time are:

  • PostMessage
  • PostAppMessage
  • DriverCallback
  • timeGetSystemTime
  • timeGetTime
  • timeSetEvent
  • timeKillEvent
  • midiOutShortMsg
  • midiOutLongMsg
  • OutputDebugStr


Opening and Closing Devices

Client applications must open an audio device before using it, and close the device after using it so the device will be available to other applications. It is possible for a device driver to support more than one client simultaneously.

If the driver supports multiple clients, the appropriate _GETNUMDEVS message can return a value other than 1. In some cases, returning a value of 1 is the best option. For example, if the device driver supports multiple clients for simultaneous PCM waveform playback, you might want the WODM_GETNUMDEVS message to return 1 and allow multiple WODM_OPEN messages. However, if your driver supports completely different playback formats (or routing to different playback hardware), it might be better for WODM_GETNUMDEVS to return the number of formats. In this case, remember to always check the uDeviceID parameter to determine which device is being accessed. Also remember to set the appropriate DEVCAPS structure so that clients can tell the difference between the devices. For example, a MIDI output driver might support both an external MIDI port and an internal synthesizer. It makes sense for the MDOM_GETNUMDEVS message to return 2 - where the port is device 0, and the synthesizer is device 1.

Auxiliary audio devices are handled differently from waveform and MIDI devices. They don't have to be opened, because they don't have the same resource allocation requirements. Also, there is no interrupt level or continuous data transfer associated with auxiliary audio devices.

When a driver receives an open request with a WODM_OPEN, WIDM_OPEN, MODM_OPEN, or MIDM_OPEN message, the dwUser parameter of its entry-point function points to a location that the driver can fill with a DWORD of instance data. This instance data is returned to the driver in the same dwUser parameter when other messages are sent to the driver. Drivers should use this instance data for information related to the client that opened a device. The following code fragment illustrates how the modMessage MIDI output entry-point function might handle the MODM_OPEN message:

typedef struct portalloc_tag {
    DWORD       dwCallback;     /* client's callback        */
    DWORD       dwInstance;     /* client's instance data   */
    HMIDIOUT    hMidi;          /* handle for stream        */
    DWORD       dwFlags;        /* allocation flags         */
} PORTALLOC;

PORTALLOC gMidiOutClient;
         case MODM_OPEN:
            /*  Attempt to 'acquire' the MIDI output hardware. If the
             *  output port is already in use by another client or
             *  another VM owns the Sound Blaster hardware, then
             *  return MMSYSERR_ALLOCATED. */
            if ( modAcquireHardware() )
                return MMSYSERR_ALLOCATED
             /*  Save client information */
            gMidiOutClient.dwCallback =
                    ((LPMIDIOPENDESC)dwParam1)->>dwCallback<R>
             gMidiOutClient.dwInstance =
                     ((LPMIDIOPENDESC)dwParam1)->>dwInstance
             gMidiOutClient.hMidi = ((LPMIDIOPENDESC)dwParam1)->>hMidi;
             gMidiOutClient.dwFlags    = dwParam2;
             /*  Reset running status...*/
             gbMidiOutCurrentStatus = 0;
             /*  Notify client...*/
             midiCallback(&gMidiOutClient, MOM_OPEN, 0L, 0L);
             /*  Return success. */
             return 0L;


Handling Errors

For a description of the error return values from DriverProc, see the discussion of installable drivers in the documentation for the Microsoft Windows Software Development Kit. The following table lists the general error return values from auxMessage, mxdMessage, wodMessage, widMessage, midMessage, and midMessage.

In addition to the general error return values, there are error return values unique to each type of audio device. The following list identifies these device-specific error return values.

Category | Error | Meaning
General | MMSYSERR_NOERROR | No error.
 | MMSYSERR_ERROR | Unspecified error.
 | MMSYSERR_NOTENABLED | Driver is not enabled.
 | MMSYSERR_ALLOCATED | Requested device is already allocated.
 | MMSYSERR_NOMEM | Memory allocation error.
 | MMSYSERR_NOTSUPPORTED | Driver does not support specified operation.
Device-specific | MIDIERR_UNPREPARED | MIDI data block has not been prepared
 | MIDIERR_NOTREADY | MIDI output hardware is busy.
 | MIDIERR_STILLPLAYING | Driver is still playing MIDI data.
 | WAVERR_BADFORMAT | Unsupported waveform data format.
 | WAVERR_STILLPLAYING | Driver is still playing waveform data.
 | WAVERR_UNPREPARED | Specified waveform data block has not been prepared.


DriverCallback Function

Audio-device drivers need to notify clients when certain events occur, such as when a waveform data block has been played, or when a MIDI input event is received. Clients must be notified when the following conditions occur:

  • When a device is opened.
  • When a device is closed.
  • hen the driver is finished with a data block.
  • When the driver receives data that should be passed directly back to the application, such as when a MIDI input driver receives a MIDI event from an input port.

When the client opens a device, the client specifies how it wants to be notified. There are three ways a driver can notify a client application:

  • By calling a client-specified callback function.
  • By sending a message to a client-specified window.
  • By unblocking a client-specified task.

To make the job of notifying clients easier, MMSYSTEM provides the DriverCallback function. DriverCallback takes information supplied by the client when it opened a device and notifies the client accordingly. A MIDI driver can use the function as shown in the following example to call DriverCallback:

void FAR PASCAL midiCallback(
   NPPORTALLOC pPortalloc,
   WORD msg,
   DWORD dwParam1,
   DWORD dwParam2)
{
   if (pPortalloc->dwCallback)
      DriverCallback
      (  pPortalloc->dwCallback,       /* users callback DWORD */
         HIWORD(pPortalloc->dwFlags),  /* callback flags */
         pPortalloc->hMidi,            /* handle to the wave device */
        msg,                           /* message from the driver */
        Portalloc->dwInstance,         /* user's instance data */
        dwParam1,                      /* message-dependent parameter */
         dwParam2                      /* message-dependent parameter */
      );
}

The parameter pPortalloc points to a structure containing the MIDI device handle, callback flags, and user instance data passed to the driver with the MODM_OPEN message. For an example of how to handle the MODM_OPEN message, see . The parameters msg, dwParam1, and dwParam2 specify the message and message-dependent parameters the driver is sending to the client.


Multimedia Plug and Play

Instead of using a configuration dialog box to ask the user to supply I/O port addresses, IRQ levels, and DMA channels, Plug and Play devices obtain hardware configuration information from the Configuration Manager system component. Most of the requirements for implementing Plug and Play in a multimedia device driver are the same as for any other device driver; this section only discusses the procedures that are unique to multimedia devices. For more information about Plug and Play, see "Plug and Play Introduction," elsewhere in the Microsoft Windows 95 Device Driver Programmer's Reference.


Driver Architecture

Windows 95 extends the Windows® 3.1 multimedia driver architecture by including support for Plug and Play configuration and device arrival or removal notifications. Although Windows 95 requires a supporting virtual device driver (VxD) to interact with the Configuration Manager, the implementation of the primary functionality of Windows 95 multimedia drivers uses 16-bit protected-mode code.

The term "virtual device driver" often suggests the concept of device virtualization. However, Windows 95 also uses VxDs to implement 32-bit "supervisor mode" or "trusted mode" code. For multimedia device drivers, VxDs serve two primary purposes: interacting with the Configuration Manager and managing hardware contention between Windows applications and MS-DOS applications.

Although it is not required, you may also decide to implement some of the core driver functionality in the supporting VxD and create a private interface from the 16-bit driver to the VxD.


Plug and Play Driver Notification

The Configuration Manager (CONFIGMG.VXD) controls the creation, deletion, and resource allocation of the Device Nodes.

When a bus enumerator requests a new device node, the Configuration Manager locates the device ID of the device node in the system registry and loads the driver(s) using the registered device loader, if the necessary entries are present. After loading the device driver, the Configuration Manager sends a PnP_New_DevNode message to the driver's control procedure.

Note If the new device node is the result of the "first insertion" event, the device node is setup during "appy-time." After successful installation of the device software, the Configuration Manager continues the startup sequence.

On receipt of the PnP_New_DevNode message, the device driver registers a "Config Handler" procedure with the multimedia device loader (MMDEVLDR.VXD), using the MMDEVLDR_Register_Device_Driver service. The Config Handler processes all subsequent CONFIG_ type messages from the Configuration Manager.

The Configuration Manager attempts to satisfy the resource requirements of the new device. If the device is a "floating" configuration, it may filter its logical configurations during the CONFIG_FILTER message processing. When the Configuration Manager can satisfy the resource requirements for the device node, it starts the device by sending a CONFIG_START message to the Config Handler.

A typical Config Handler processes the configuration state messages and applies the configuration by allocating resources such as IRQ virtualization, I/O trapping and memory space from the virtual machine manager (VMM).

The following procedure is a portion of the Config Handler used by MSMPU401.VXD. During the CONFIG_START message processing, the Config Handler queries the Configuration Manager for the allocated resources and then calls MSMPU401_Set_Config (an external private function defined by the specific device) to put the configuration into effect.

//---------------------------------------------------------------------
//
// MSMPU401_Config_Handler
//
//---------------------------------------------------------------------

CONFIGRET MSMPU401_Config_Handler
(
    CONFIGFUNC      cfFuncName,
    SUBCONFIGFUNC   scfSubFuncName,
    DEVNODE         dn,
    DWORD           dwRefData,
    ULONG           ulFlags
)
{
   // Switch the function (aka command)

   DPF( "MSMPU401: Config_Handler\r\n" ) ;

   switch (cfFuncName)
   {
      // In this code snippet, we've removed all function processing
      // except CONFIG_START, please see the DDK samples for the
      // complete example.

      case CONFIG_START:
      {
         // This command is sent to instruct the driver that
         // it can start using the resources that have been
         // allocated to it. This is the meat of this
         // DriverConfigMan.
         //
         // We get our resource allocation by calling the
         // configuration manager (CM) using the devnode that
         // was passed to us.
         //
         // If all has gone well, we should not have been given
         // a resource allocation that we can't use. Ideally
         // this command should always succeed. However, every
         // now and then life throws you a curve ball, so we
         // should still verify that we are happy with the
         // resources we have been given.

         CMCONFIG    ccb ;
         CONFIGRET   cr ;
         WORD        wBaseMPU401 ;
         WORD        wIRQ ;

         // Get our resource allocation from CM. if
         // this fails, we have no choice but to fail
         // the CONFIG_START. We'll return the same
         // error that the CM_Get_Alloc_Config returned.

         if (CR_SUCCESS !=
               (cr = CM_Get_Alloc_Log_Conf( &ccb, dn, 0 )))
            return cr ;

         // Extract the information of interest from the config buffer
         // that we got from CM_Get_Alloc_Config.

         wBaseMPU401 = (WORD) -1 ;

         if (ccb.wNumIOPorts != 1)
         {
            DPF( "MSMPU401: Invalid config.\r\n" ) ;
            return CR_FAILURE ;
         }

         wBaseMPU401 = ccb.wIOPortBase[ 0 ] ;

         if (ccb.wNumIRQs)
            wIRQ = ccb.bIRQRegisters[ 0 ] ;
         else
            wIRQ = (WORD) -1 ;

         if (-1 == wBaseMPU401)
            return CR_FAILURE ;

         // OK, now do whatever else is necessary to put this
         // configuration into effect.

         cr = MSMPU401_Set_Config( dn, wBaseMPU401, wIRQ ) ;

         return cr ;
      }
   }
} // MSMPU401_Config_Handler()


Multimedia Subsystem Driver Notification

After the VxD has successfully processed the CONFIG_START message, the multimedia device loader notifies the multimedia subsystem (MMSYSTEM.DLL) that a device node has successfully started. MMSYSTEM loads each of the associated ring-3 drivers and sends a device arrival notification. The ring-3 drivers query the supporting VxD for configuration information and complete the initialization necessary to support the device. The multimedia subsystem is designed to accommodate device nodes that have multiple function traits, such as music synthesis, digital sound support, hardware compression and/or decompression, and mixer support. When a device node is started, MMSYSTEM locates the registry entries for device node and loads the drivers for each supported class.

Note The changes and additions to the Window 3.1 multimedia device driver model as described below are specific to Windows 95 Plug and Play device drivers. Multimedia drivers loaded using the Windows 3.1 SYSTEM.INI entries will not experience these changes.

A device node might support four driver classes: wave, midi, aux and mixer. Each class may have multiple drivers. MMSYSTEM loads all drivers for all active classes when the device successfully starts. MMSYSTEM loads each module only once and increments reference counts as necessary (standard LoadLibrary() behavior); therefore, a multimedia ring-3 device driver's DriverProc() receives only one DRV_LOAD message when it is first loaded and only one DRV_FREE message when the last reference to the device is released.

A ring-3 device driver should maintain separate data structures for each device node and if the device driver supports multiple classes it should maintain reference counts for each active class. To assist in this task, Windows 95 introduces new parameters for the xxxx_INIT, xxxx_GETNUMDEVS, xxxx_GETDEVCAPS and xxxx_OPEN messages, and introduces new messages: DRVM_ENABLE, DRVM_DISABLE and DRVM_EXIT.

MMSYSTEM sends the xxxx_INIT, DRVM_ENABLE, DRVM_DISABLE and DRVM_EXIT message to each message procedure of each class of device when the corresponding activity has taken place for the device node.

Below is a description of these messages and the appropriate driver response:

  • MMSYSTEM issues the xxxx_INIT message when the device is first started. Generally, a device driver allocates the instance structure or increments a usage reference count for this message.
  • MMSYSTEM issues the DRVM_ENABLE message when the device node becomes active. The device driver should increment an enable count. The first time the device driver receives this notification it should perform hardware initialization as well as allocate other device support structures such as mixer structures, interrupt service thunks and so.
  • MMSYSTEM issues the DRVM_DISABLE message when the device node becomes disabled. The device driver should decrement the enable count and when the enable count is zero, it should release hardware resources and free the structures allocated during the DRVM_ENABLE message processing. MMSYSTEM halts all application to driver message traffic is except xxxx_UNPREPARE, xxxx_RESET, xxxx_STOP and xxxx_CLOSE messages, allowing a driver to clean up remaining data associated with the device handle The Configuration Manager unloads the device node's VxD when the device enable count is zero and after the driver responds to this message.
  • MMSYSTEM issues the DRVM_EXIT message after the device has been disabled and when there are no open handles to the device driver. The device driver should free the instance structure when the usage reference count is zero. Additionally, MMSYSTEM may dispatch another DRVM_ENABLE and DRVM_DISABLE pair before dispatching the DRVM_EXIT. This is particularly true for the case of device reconfiguration or PCMCIA removal and immediate re-insertion.

When the driver vendor follows the appropriate handling of these messages it is possible to accomplish any or all of the following:

  • Change the configuration of software configurable hardware when a device handle remains open by a passive application (such as a mixer application).
  • Seamlessly respond to portable docking and undocking situations.
  • Handle PCMCIA hot-plugging events without additional code.

The code example below is the output wave device message handler from the Windows Sound System ring-3 driver. It demonstrates the appropriate handling of these new and modified messages.

DWORD FAR PASCAL _loadds wodMessage
(
    UINT            uDevId,
    WORD            msg,
    DWORD           dwUser,
    DWORD           dwParam1,
    DWORD           dwParam2
)
{
   NPWAVEALLOC         pClient ;
   PHARDWAREINSTANCE   phwi ;

   // take care of init time messages...

   switch (msg)
   {
      case WODM_INIT:
      {
         DPF( 3, "WODM_INIT" ) ;

         if (gwGlobalStatus)
         {
            DisplayConfigErrors() ;
            return 0L ;
         }
         else
         {
            // dwParam2 == PnP DevNode

            return (AddDevNode( dwParam2 )) ;
         }
      }
      break ;

      case DRVM_ENABLE:
      {
         DPF( 3, "WODM_ENABLE" ) ;

         // dwParam2 == PnP DevNode

         return (EnableDevNode( dwParam2 )) ;

      }
      break ;

      case DRVM_DISABLE:
      {
         DPF( 3, "WODM_DISABLE" ) ;

         // dwParam2 == PnP DevNode

         return (DisableDevNode( dwParam2 )) ;

      }
      break ;

      case DRVM_EXIT:
      {
         DPF( 3, "WODM_EXIT" ) ;

         // dwParam2 == PnP DevNode

         return (RemoveDevNode( dwParam2 )) ;

      }
      break ;

      case WODM_GETNUMDEVS:
      {
         DPF( 3, "WODM_GETNUMDEVS" ) ;

         if (NULL == (phwi = DevNodeToHardwareInstance( dwParam1 )))
            return MAKELONG( 0, MMSYSERR_INVALPARAM ) ;

         if (dwParam1)
         {
            if (phwi -> fEnabled)
               return 1L ;
            else
               return 0L ;
         }
         else
            return 0L ;
      }
      break ;

      case WODM_OPEN:
      {
         DWORD  dn ;

         DPF( 3, "WODM_OPEN" ) ;

         if (uDevId > 1)
            return MMSYSERR_BADDEVICEID ;

         dn = ((LPWAVEOPENDESC) dwParam1) -> dnDevNode ;

         if (NULL ==
               (phwi = DevNodeToHardwareInstance(dn)))
         {
            DPF( 1, "devnode not associated with hardware instance???" ) ;
            return MMSYSERR_BADDEVICEID ;
         }

         if (!phwi -> fEnabled)
            return MMSYSERR_NOTENABLED ;

         return (wodOpen(phwi,
                         dwUser,
                         (LPWAVEOPENDESC) dwParam1,
                         dwParam2 )) ;
      }
      break ;

      case WODM_GETDEVCAPS:
      {
         DPF( 3, "WODM_GETDEVCAPS" ) ;

         if (uDevId > 1)
            return MMSYSERR_BADDEVICEID ;

         if (NULL ==
               (phwi = DevNodeToHardwareInstance( dwParam2 )))
         {
            DPF( 1, "devnode not associated with hardware instance???" ) ;
            return MMSYSERR_BADDEVICEID ;
         }

         if (!phwi -> fEnabled)
            return MMSYSERR_NOTENABLED ;

         wodGetDevCaps( phwi, (MDEVICECAPSEX FAR *) dwParam1 ) ;
         return MMSYSERR_NOERROR ;
      }
      break ;
   }
}
   // Note that the remaining cases for this procedure have
   // been removed from this code example. Please see the
   // MSSNDSYS.DRV example in the DDK for a complete sample.

The procedure of unloading the drivers for a device node is the inverse of the load procedure. That is, the ring-3 drivers are notified and unloaded and then MMDEVLDR issues the CONFIG_STOP message to the virtual device driver.


Multiple Hardware Instances

The device driver samples shipped with Windows 95 support multiple instances of the hardware in a single machine. For example, it is possible to install three sound cards in the same machine. If there are enough free resources, all three devices will start and use the same driver set but remain independently installed devices.

MMSYSTEM considers each device node a separate device installation. The device driver should respond with the appropriate information for that specific instance of the hardware. For example, given two sound cards and each supports one wave output device, the driver should respond with "1" to the WODM_GETNUMDEVS message for each device node.

Additionally, to properly support multiple device instances the device drivers must perform the following tasks:

  • Maintain hardware instance specific data structures using the device node as the key.
  • "Thunk" I/O trapping procedures to easily determine device node association.
  • Create copies of the ring-3 ISR code for each hardware instance.
  • Modify private interfaces to understand multiple hardware instances.
  • Avoid the use of global variables.

The DDK code samples demonstrate all of these techniques. Most developers will use one of the sample device drivers and associated VxDs as their device driver base.


Hardware Design

When designing ISA Plug and Play, Plug and Play BIOS's, or other Plug and Play compatible hardware, the vendor must consider the supporting software requirements. The primary rule is that a logical device must be functionally independent.

If you need to maintain compatibility with existing driver sets, you must use the logical device breakdown and resource sets described in the following topics.


Logical Devices

The defined resource sets of the supported multimedia devices provide a logical device breakdown and account for the sometimes hidden dependencies inherent in the hardware design.

To determine if you should define a logical device, you must answer the question: "Does the resource set describe an independently functional device?" If yes, create a logical device. If no, you will need to merge these resources with the other components required to start and/or support this device.

The reason for this requirement is that there is no bus-independent method for a driver to determine the association of one logical device with another or which physical device contains the logical device. This reasserts the definition of a logical device: a logical device is functionally independent.

For example, a sound card could contain many functions: a 16-bit audio component (including internal FM synthesis and external MIDI), a joystick adapter, a SCSI adapter, and a second independent DAC for compatibility with other cards. The immediate response is to define a logical device for each of the functionally independent components. This is not necessary if the device is software-configurable, however. Instead of allowing each child component to configure the device independently, the parent retrieves the entire resource set and applies the configuration to the hardware. The Configuration Manager creates the child devices using subsets of the resources of the parent. Although this example is a special case, it serves the purpose of demonstrating the sometimes subtle dependencies of hardware devices.

Following is a list of general rules to use when determining if a resource set is an independent logical device:

Internal hardware mixer dependencies | The most common example of this is the support of the FM synthesis device. Plug and Play devices most often include this I/O resource with the "audio" logical device. Most of the legacy device drivers shipped with Windows 95 adjust their mixer resources on the basis of whether an associated FM device is present. The determination of the FM association is the inclusion or exclusion of the I/O resource for the FM synthesis chip in "audio" logical device resource set.
Interrupt sharing | An example of this strategy is Creative Lab's Sound Blaster 16-bit audio series. The MPU-401, 8-bit ADC/DAC and 16-bit ADC/DAC share a single interrupt. Consequently, the logical device descriptor for the Sound Blaster 16 includes the resources for the MPU-401 and wave audio devices.
Multiple register planes using a single I/O path | The dependency of these designs is the I/O path (ADC/DAC). For example, the register planes provide the hardware interface for Sound Blaster compatibility and Windows Sound System compatibility, but are mutually exclusive such that register planes contend for the I/O path. Thus, the register planes are not functionally independent. Appropriate management of these register planes requires hardware contention management per device node.
DSP based solutions | These devices require special consideration when designing the logical device structure. For more information, see .


Resource Organization

The following table contains specific resource ordering for specific components of each device.

Note The resource sets for following multimedia devices are order dependent, particularly within a class of resource. The drivers included with Windows 95 parse the resource set based on class, size and ordinal of the resource.

The location of these components in I/O space is not a criterion for the parsing algorithm. This allows the device to "float" in I/O space when all optimal resource settings are in conflict.

Device ID | Manufacturer | Product | Resource Descriptor | Example
*AZT1605 | Aztech Labs | Sound Galaxy Nova 16 | I/O size 16 microcontroller I/O size 8 WSS compatible I/O size 4 YMF262 IRQ (SB compat.) IRQ (WSS compat.) DMA (SB compat.) DMA (WSS compat.) | 220-22F 530-537 388-38B 3, 5, 7 or 9 7, 9, 10 or 11 0, 1 or 3 0, 1 or 3
*AZT1608 | Aztech Labs | Sound Galaxy Pro 16 | TBD |
*AZT2316 | Aztech Labs | Sound Galaxy Washington 16 | same as *AZT1605 |
*ESS1481 | ESS Technology, Inc. | ES1488 AudioDrive | I/O size 16 microcontroller I/O size 2 or 4 Yamaha 3812 or YMF262 IRQ DMA | 220-22F 388-38B 3, 5, 7. or 9 1 or 3
*ESS1681 | ESS Technology, Inc. | ES1688 AudioDrive | I/O size 16 microcontroller I/O size 4 YMF262 compat. I/O size 2 MPU-401 compat IRQ IRQ (MPU-401 compat) DMA | 220-22F 388-38B 330-331 5, 7, 9 or 10 5, 7, 9, 10, or 11 1 or 3
*ESS4881 | ESS Technology, Inc. | ES488 AudioDrive | I/O size 16 microcontroller I/O size 2 or 4 Yamaha 3812 or YMF262 compat. IRQ DMA | 220-22F 388-38B 3, 5, 7 or 9 1 or 3
*ESS6881 | ESS Technology, Inc. | ES688 AudioDrive | I/O size 16 microcontroller I/O size 4 YMF262 compat. IRQ DMA | 220-22F 388-38B 5, 7, 9 or 10 1 or 3
*PNPB000 | Creative Labs | Sound Blaster 1.0 | I/O size 16 microcontroller I/O size 16 (alias of 220-22F) IRQ DMA | 220-22F 380-38F 3, 5, 7 or 9 1
*PNPB001 | Creative Labs | Sound Blaster 2.0 | I/O size 16 microcontroller I/O size 2 Yamaha 3812 IRQ DMA | 220-22F 388-389 3, 5, 7 or 9 1
*PNPB002 | Creative Labs | Sound Blaster Pro | I/O size 16 microcontroller I/O size 2 or 4 Yamaha 3812 or YMF262 IRQ DMA | 220-22F 388-38B 3, 5, 7 or 9 1
*PNPB003 | Creative Labs | Sound Blaster 16 / AWE 32 | I/O size 16, microcontroller I/O size 2 MPU-401 compat. I/O size 4 YMF262 IRQ DMA (byte) DMA (word) | 220-22F 330-331 388-38B 5, 7, 9 or 10 0, 1 or 3 5, 6 or 7
*PNPB004 | Media Vision | Thunder Board | same as *PNPB001 |
*PNPB005 | Ad Lib | Ad Lib OPL2 (Yamaha 3812) | I/O size 2 | 388-389
*PNPB006 | Roland | MPU-401 | I/O size 2 IRQ | 330-331 3, 4, 5, 7, 9 or 10
*PNPB007 | Microsoft | Windows Sound System | I/O size 4 or 8 I/O size 4 IRQ DMA | 534-537 388-38B 7, 9, 10 or 11 0, 1 or 3
*PNPB008 | Compaq | Business Audio | same as *PNPB007 |
*PNPB00B | Media Vision | Pro Audio 3D | I/O size 1 wake-up port / joystick I/O size 2 ID & control registers I/O size 16 microcontroller I/O size 4 YMF 262 I/O size 2 MPU-401 compat. IRQ IRQ (MPU-401 compat.) DMA (byte) DMA (word) | 201-201 380-381 220-22F 388-38B 330-331 3, 5, 7, 9 or 10 3, 5, 7 or 9 1 or 3 5 or 7
*PNPB00D | Media Vision | Pro Audio Spectrum 16 | contact Microsoft |
*PNPB00E | Media Vision | Pro Audio Spectrum 16 with SCSI (Zilog chip set) | contact Microsoft |
*PNPB00F | Media Vision | Jazz - 16 or Pro Audio Deluxe | same as *PNPB00B |
*PNPB010 | Orchid | Vidiola | I/O size 2 memory size 32k IRQ | 500-501 d8000-dffff 5, 7, 10, 11, 12, 14 or 15
*PNPB020 | Ad Lib / Yamaha | YMF262 (OPL3) | I/O size 4 | 388-38B
*PNPB02F | Microsoft | Generic Joystick | I/O size 1 | 201-201

Windows Sound System Resource Descriptors

Plug and Play implementations of the Windows Sound System designs should not include the "AutoSelect" range (for example: 530-533) in the base I/O resource descriptor. The reported range for the base address should be the CODEC only. Thus, a resource set for an ISA Plug and Play implementation of a WSS compatible device would contain:

  • I/O size 4 for AD1848/CS4248 or compatible CODEC (534-537)
  • I/O size 4 for YMF262 (388-38B)
  • IRQ and DMA.

If the implementation provides additional hardware support for Sound Blaster compatibility and shares the DAC/ADC I/O path and IRQ/DMA resources with the WSS register plane (such as the Crystal Semiconductor CS4232 design), the resource set should contain both the CODEC and the Sound Blaster compatibility resources, as follows:

  • I/O size 4 for AD1848/CS4248 or compatible CODEC (534-537)
  • I/O size 4 for YMF262 (388-38B)
  • I/O size 16 for Sound Blaster compatibility (220-22F)
  • IRQ and DMA.

Again, please note that the above I/O resources structures are order-dependent. The standard device drivers shipped with Windows 95 handle the above cases correctly.

ESS AudioDrive Resource Descriptors

If your hardware implementation uses the ESS reference designs without modification, you may use the listed ESS device IDs as compatible device tags. However, if your implementation deviates from the ESS reference design, particularly with IRQ and DMA steering, you will need to create your own .INF files and include special IRQ/DMA steering information in these files. Please contact ESS Technology, Inc. or the Microsoft Hardware Vendor Relations Group for further information.


Shared Resources

When a design requires shared resources between functions such as an IRQ between the audio and SCSI functions on a PCMCIA design, the .INF file for the device implements multiple function definitions which allow child devices to be created from subsets of the parent's resources.


DSP Based Solutions

DSP-based solutions face numerous obstacles when implemented as ISA Plug and Play devices:

  • The devices on a DSP based design tend to be dependent on the "parent" DSP device such that code must be present on the DSP for the various register planes to respond properly.
  • DSPs are dynamic in nature. However, ISAPNP establishes a device with a static resource set.
  • Because of the nature of Plug and Play, separate functions cannot have dependencies on other functions, because ISAPNP does not guarantee initialization order of the enumerated devices. The following statements support this claim:
    • Logical devices are, by definition, independent. There is no bus independent method to determine the association of a device node with a parent board.
    • Dependent components cannot determine when the supporting DSP initializes or relocates.
    • Dependent components do not receive notification when a supporting device is disabled.

The solution to these problems is to include all the resources in a single device function and using the multiple function support in Windows 95 to create the child devices from a subset of the resources. The "multiple function" specification, as described elsewhere in the Windows 95 DDK, allows a parent/child relationship between device nodes.

For an example of multiple function support, please investigate the parent/child relationships established in WAVE.INF for the Media Vision Pro Audio Spectrum 16 cards (device IDs *PNPB00D and *PNPB00E).

An alternative solution is to write a private enumerator for your DSP based device. Please contact the Microsoft Hardware Vendor Relationship Group for details.


Plug and Play BIOS Considerations

Be sure to register appropriate device IDs and resource structures in your Plug and Play BIOS for machines with on-board multimedia devices. In other words, just because an on-board device is compatible with Sound Blaster does not mean that the BIOS should report the *PNPB001 device ID.

To determine the appropriate IDs, first determine the chip set manufacturer (such as Analog Devices, Creative Labs, ESS, and so on) and then match the resource IDs using the table provided in . You may report the device ID from this table or you may register your own ID and report the device ID from the table as a compatible ID. However, if you register your own device ID and this ID is not included in the standard .INF files or is not included in the OEM's implementation of Windows 95, the user will be prompted with a dialog box and given the option to select the compatible device or select from a list of other devices.

If the device is partially software configurable (such as the Windows Sound System or ES688 and ES1688 reference designs), you have some options for the reported device structure:

  • You may report only the fixed resources in the boot configuration and allow the Configuration Manager to fill in the remaining required resources determined by the dependent functions. The Configuration Manager will determine the highest priority and most feasible dependent function to fill.
  • You may report all of the resources in the boot configuration and require a restart to apply a new configuration (this option is not recommended).

Note that BIOS is expected to configure these software configurable resources to match the resulting configuration.


Device Registry

Please refer to "Device Information Files," elsewhere in the Windows 95 DDK, for details regarding general .INF structure. The following topics contain samples for a multimedia single function PCMCIA card, with a description of multimedia-specific entries.


Auxiliary, PCM, MIDI, and Mixer Drivers

For all multimedia devices, the Class entry in the [Version] section of the .INF file must be set to MEDIA. This associates the device with the multimedia class installer, which provides the necessary interfaces to the multimedia control panel and multimedia subsystem.

[Version]
Signature="$CHICAGO$"
Class=MEDIA
provider=%NMCMfgName%

The [Manufacturer] section specifies the manufacturer name and section name for the manufacturer's device(s). In the following example, the string "New Media Corporation" is associated with the [NewMediaCorp] section and contains a single PCMCIA device descriptor.

[Manufacturer]
%NMCMfgName%=NewMediaCorp

[NewMediaCorp]
%PCMCIA\New_Media_Corporation-.WAVjammer-6B54.DeviceDesc%=PNPB007_Device,PCMCIA\New_Media_Corporation-.WAVjammer-6B54

In the section above, the device identifier string "PCMCIA\New_Media_Corporation-.WAVjammer-6B54" is assigned to the [PNPB007_Device] section. The device description that is visible to the user is the string referred to by the identifier %PCMCIA\New_Media_Corporation-.WAVjammer-6B54.DeviceDesc%.

The device section [PNPB007_Device] describes the files to delete and copy, the strings to remove from SYSTEM.INI, and the sections to add to the registry.

[PNPB007_Device]
DelFiles=WSS.DelList
CopyFiles=WSS.CopyList
AddReg=WAVE.AddReg, MIXER.AddReg, PNPB007.AddReg, WSS.AddReg
UpdateInis=WSS.UpdateInis

[WSS.UpdateInis]
system.ini,386Enh,"device=vsndsys.386"
system.ini,drivers,"wave*=sndsys.drv",,1
system.ini,drivers,"midi*=sndsys.drv",,1
system.ini,drivers,"aux*=sndsys.drv",,1
system.ini,drivers,"mixer*=sndsys.drv",,1

[WSS.CopyList]
mssndsys.vxd,,
mssndsys.drv,,
msopl.drv,,

[WSS.DelList]
vsndsys.386,,,1
sndsys.drv,,,1

The following section adds the multimedia specific entries to the registry. The Driver entry is used by the multimedia device loader and is the supporting VxD for the device. Each of the subclasses (wave, mixer, aux and midi) contain driver entries and descriptions for each of the subclass drivers.

[PNPB007.AddReg]
HKR,,Driver,,mssndsys.vxd
HKR,Drivers\wave\mssndsys.drv,Driver,,mssndsys.drv
HKR,Drivers\wave\mssndsys.drv,Description,,%*PNPB007.DeviceDesc%
HKR,Drivers\mixer\mssndsys.drv,Driver,,mssndsys.drv
HKR,Drivers\mixer\mssndsys.drv,Description,,%*PNPB007.DeviceDesc%
HKR,Drivers\aux\mssndsys.drv,Driver,,mssndsys.drv
HKR,Drivers\aux\mssndsys.drv,Description,,%*PNPB007.DeviceDesc%
HKR,Drivers\midi\msopl.drv,Driver,,msopl.drv
HKR,Drivers\midi\msopl.drv,Description,,%V_INTERNAL%
HKR,Drivers,SubClasses,,"wave,midi,aux,mixer"

The following sections are standard registry modifications. The [MIXER.AddReg] section automatically starts the system tray for the tray volume control. If your device has a supporting mixer driver, you should reference this section as demonstrated above. The [WAVE.AddReg] section cleans up any previous driver entries for the device node and sets the device loader to MMDEVLDR.VXD.

[MIXER.AddReg]
HKLM,Software\Microsoft\Windows\CurrentVersion\Run,SystemTray,,"SysTray.Exe"

[WAVE.AddReg]
HKR,,DevLoader,,mmdevldr.vxd
HKR,Drivers,MIGRATED,,0
HKR,Drivers\midi,,,
HKR,Drivers\wave,,,
HKR,Drivers\mixer,,,
HKR,Drivers\aux,,,

The following section describes the disk names and file layout on the disks.

[SourceDisksNames]
1="New Media .WAV Jammer Driver Disk ",, 0001

[SourceDisksFiles]
mssndsys.drv=1
msopl.drv=1
mssndsys.vxd=1

For multimedia devices, the default destination directory is the SYSTEM directory. The [Strings] section contains the localizable strings for the .INF file.

[DestinationDirs]
DefaultDestDir = 11    ; LDID_SYS

[Strings]

;Localizable strings

NMCMfgName="New Media Corporation"
PCMCIA\New_Media_Corporation-.WAVjammer-6B54.DeviceDesc="New Media .WAVjammer audio adapter"
*PNPB007.DeviceDesc="MS Windows Sound System Compatible"
V_INTERNAL="Internal OPL2/OPL3 FM Synthesis"


Multiple Port MIDI Drivers

If MIDI drivers support more than one port in a driver, additional registry entries must be made for each port, as shown below. This allows each port to be configured independently from the Control Panel. Following is a sample [MULTMIDI.Addreg] section for a MIDI driver supporting more than one MIDI port:

[MULTMIDI.AddReg]
HKR,Drivers\midi\MultiPort_Port_0000,Description,,%Port0.DeviceDesc%
HKR,Drivers\midi\MultiPort_Port_0000,Driver,, multmidi.drv
HKR,Drivers\midi\MultiPort_Port_0000,External,1,01,00,00,00
HKR,Drivers\midi\MultiPort_Port_0000,NumPorts,1,03,00,00,00
HKR,Drivers\midi\MultiPort_Port_0000,Port,1,00,00,00,00

HKR,Drivers\midi\MultiPort_Port_0001,Description,,%Port1.DeviceDesc%
HKR,Drivers\midi\MultiPort_Port_0001,Driver,,multmidi.drv
HKR,Drivers\midi\MultiPort_Port_0001,External,1,01,00,00,00
HKR,Drivers\midi\MultiPort_Port_0001,NumPorts,1,03,00,00,00
HKR,Drivers\midi\MultiPort_Port_0001,Port,1,01,00,00,00

HKR,Drivers\midi\MultiPort_Port_0002,Description,,%Port2.DeviceDesc%
HKR,Drivers\midi\MultiPort_Port_0002,Driver,,multmidi.drv
HKR,Drivers\midi\MultiPort_Port_0002,External,1,01,00,00,00
HKR,Drivers\midi\MultiPort_Port_0002,NumPorts,1,03,00,00,00
HKR,Drivers\midi\MultiPort_Port_0002,Port,1,02,00,00,00

[Strings]
Port0.DeviceDesc="Multiport MIDI Driver: MIDI Port 0"
Port1.DeviceDesc="Multiport MIDI Driver: MIDI Port 1"
Port2.DeviceDesc="Multiport MIDI Driver: MIDI Port 2"


MIDI Filter Drivers

Windows 95 provides the capability to connect MIDI filter drivers to the system using the device registry. MIDI filters are installed in SYSTEM.INI. This is similar to the way non-Plug and Play MIDI drivers are installed. Following is a sample INF file for installing a MIDI Filter. Note that the [FILTER] section defines MediaType=Software. This is necessary for proper installation of any software device. A reboot is always required for software-device installations. More that one MIDI filter can be installed. One next boot the MIDI Filters are installed in SYSTEM.INI as "MIDIFilter=x.drv", "MIDIFilter1=y.drv", "MIDIFilter2=z.drv", and so on.

[Version]
Signature="$CHICAGO$"
Class=MEDIA

[Manufacturer]
%MfgName%=Generic

[Generic]
%Filter.DeviceDesc%=FILTER
[FILTER]
AddReg=FILTER.AddReg
CopyFiles=FILTER.Copy
MediaType=Software

[FILTER.Copy]
msthru.drv

[FILTER.AddReg]
HKLM,SYSTEM\CurrentControlSet\Control\MediaResources\newdrivers\midi\msthru.drv,,,
HKLM,SYSTEM\CurrentControlSet\Control\MediaResources\newdrivers\midi\msthru.drv,Description,,%Filter.DeviceDesc%
HKLM,SYSTEM\CurrentControlSet\Control\MediaResources\newdrivers\midi\msthru.drv,Driver,,msthru.drv
HKLM,SYSTEM\CurrentControlSet\Control\MediaResources\newdrivers\midi\msthru.drv,Parameters,,
HKLM,SYSTEM\CurrentControlSet\Control\MediaResources\newdrivers\midi\msthru.drv,MIDIFilter,1,01


Installation of Software devices

Software devices such as MCI drivers and Video and Audio codecs are installed in SYSTEM.INI. The registry is used to store additional information about the device - for example, the description string. This area of the registry can be used by vendors to store any other information needed by the drivers. This area of the registry is removed when the device is removed from the Control Panel.

Following are two sample INF files. The first installs an MCI device, and the second installs a Video codec. Note that the [QA] and [VIDC.MSVC] sections define Mediatype=Software. This is necessary for proper installation of any software device. A reboot is always required for software-device installations.

;---------------------------------------------------------------;
;; Sample MCI driver INF file
;
;---------------------------------------------------------------

[Version]
Signature="$CHICAGO$"
Class=MEDIA

[Manufacturer]
%MfgName%=Generic

[Generic]
%*SAMPLE.DeviceDesc%=QA

[QA]
CopyFiles=QA.Copy
Updateinis=QA.UpdateIni
AddReg=QA.AddReg
MediaType=Software

;; The 'MediaType' entry must be set to software. Otherwise
;; this INF section will be treated as an INF section for a PNP
;; device.

[QA.Copy]
mciqa.drv

[QA.UpdateIni]
system.ini,mci,,"other=mciqa.drv"
;; This adds the new line in [mci] section.

[QA.AddReg]
;; This adds additional information required by the control
;; panel. The 'Description' and 'Driver' entries must be made.
;; Other entries private to the driver can also be added here

HKLM,SYSTEM\CurrentControlSet\Control\MediaResources\mci\other,
    Description,,%*SAMPLE.DeviceDesc%
HKLM,SYSTEM\CurrentControlSet\Control\MediaResources\mci\other,
    Driver,,mciqa.drv

;; The key name (vidc.MSVC) under the classname (icm) must match
;; the key name used in SYSTEM.INI.

[DestinationDirs]
DefaultDestDir = 11    ; LDID_SYS

[SourceDisksNames]
1="OEM Multimedia Disk",, 0001

[SourceDisksFiles]
mciqa.drv=1

[Strings]
MfgName="OEM"
*SAMPLE.DeviceDesc="MCIQA Driver"

;---------------------------------------------------------------;
;; Sample Video codec INF file
;
;---------------------------------------------------------------

[Version]
Signature="$CHICAGO$"
Class=MEDIA

[Manufacturer]
%MSVIDCMfgName%=Media.Software.Devs.VIDC

[Media.Software.Devs.VIDC]
%V_VIDC.MSVC%=VIDC.MSVC

[VIDC.MSVC]
CopyFiles=msvc.cf
UpdateInis=msvc.inis
AddReg=msvc.Reg
MediaType=Software

;; The 'MediaType' entry must be set to software. Otherwise
;; this INF section will be treated as an INF section for a PNP
;; device.

[msvc.inis]
system.ini,drivers,"vidc.MSVC="
system.ini,drivers32,,"vidc.MSVC=msvidc32.dll"

;; The first line removes the old entry from [drivers] section.
;; The second line adds the new line in [drivers32] section.

[msvc.Reg]
;; This adds additional information required by the control
;; panel. The 'Description' and 'Driver' entries must be made.
;; Other entries private to the driver can also be added here

HKLM,SYSTEM\CurrentControlSet\Control\MediaResources\icm\
    vidc.MSVC,Description,,%V_VIDC.MSVC%
HKLM,SYSTEM\CurrentControlSet\Control\MediaResources\icm\
    vidc.MSVC,Driver,,msvidc32.dll

;; The key name (vidc.MSVC) under the classname (icm) must match
;; the key name used in SYSTEM.INI.

[msvc.cf]
msvidc32.dll

[DestinationDirs]
DefaultDestDir = 11    ; LDID_SYS

[SourceDisksNames]
1="OEM Multimedia Disk",, 0001

[SourceDisksFiles]
msvidc32.dll=1

[Strings]
MSVIDCMfgName="Microsoft Video Codecs"
V_VIDC.MSVC="Video 1"


Reference

The driver messages in this section are intercepted by the system and handled without ever being passed to the driver. Most drivers will not use these messages.


DRV_QUERYDEVNODE

Queries the devnode associated with this device. If there is no devnode, this message returns a NULL devnode.

The system intercepts this message and returns the appropriate value without sending the message to the device driver. Most drivers will not use this message.

  • Returns MMSYSERR_NOERROR if successful; otherwise, returns an error value.
dwParam1
Pointer to a buffer to place the DevNode in.
dwParam2
Set to zero.


DRV_QUERYDRIVERIDS

Returns the list of VxD identifiers associated with this device. Typically, a Plug and Play device has only one VXD associated with it.

The system intercepts this message and returns the appropriate value without sending the message to the device driver. Most drivers will not use this message.

  • Returns MMSYSERR_NOERROR if successful; otherwise, returns an error value.
dwParam1
Pointer to a buffer to fill with the list of IDs.
dwParam2
Initially contains a pointer to a DWORD with the number of IDs (WORDs) which can be placed in the buffer. The system copies the number of IDs actually copied into the buffer to this variable.


DRV_QUERYDRVENTRY

Queries the driver-entry text in the registry for this device (typically the name of the Ring3 driver). If this is not a Plug and Play device, this is the name of the key in SYSTEM.INI that the driver is registered under (wave1, midi, aux4, mixer5).

The system intercepts this message and returns the appropriate value without sending the message to the device driver. Most drivers will not use this message.

  • Returns MMSYSERR_NOERROR if successful; otherwise, returns an error value.
dwParam1
Pointer to a buffer to fill with the string.
dwParam2
Buffer size, in bytes.


DRV_QUERYMAPPABLE

Returns whether or not the specified device will be used by a mapper.

The system intercepts this message and returns the appropriate value without sending the message to the device driver. Most drivers will not use this message.

  • Returns MMSYSERR_NOERROR if the device is mappable; otherwise, returns an error value.
dwParam1
Set to zero.
dwParam2
Set to zero.


DRV_QUERYNAME

Queries the driver-description text.

The system intercepts this message and returns the appropriate value without sending the message to the device driver. Most drivers will not use this message.

  • Returns MMSYSERR_NOERROR if successful; otherwise, returns an error value.
dwParam1
Pointer to a buffer to fill with the string.
dwParam2
Size of the buffer.


DRVM_MAPPER_RECONFIGURE

Sent to a mapper to indicate a system configuration change has occurred. This message is use primarily by Control Panel applications and internal system components.

The system intercepts this message and returns the appropriate value without sending the message to the device driver. Most drivers will not use this message.

  • Returns MMSYSERR_NOERROR if the device is mappable; otherwise, returns an error value.
dwParam1
Depends on the flag in dwParam2.
dwParam2
Specifies the type of change plus the optional flag DRV_F_PARAM_IS_DEVNODE.
DRV_F_ADD | A new device has been added. dwParam1 contains either the SYSTEM.INI entry, or the devnode if the DEVNODE flag is set.
DRV_F_REMOVE | A device has been removed. dwParam1 contains either the SYSTEM.INI entry, or the devnode if the DEVNODE flag is set.
DRV_F_CHANGE | A device has been change. dwParam1 contains either the SYSTEM.INI entry, or the devnode if the DEVNODE flag is set.
DRV_F_PROP_INSTR | New MIDI instrument settings have been applied. dwParam1 is set to zero.
DRV_F_NEWDEFAULTS | New mapper defaults have been applied due to a change or because of a new logon. dwParam1 is set to zero.


Audio Device Drivers

Windows provides low-level audio services for multimedia applications. Applications and MCI device drivers can use these services to control audio devices such as MIDI synthesizers and waveform audio hardware. Audio devices must have a corresponding audio device driver to be used with Windows. This topic shows you how to write audio device drivers for different types of audio hardware. It covers the following topics:

  • The different types of audio devices
  • General information about writing an audio device driver
  • Specific information about writing device drivers for the different types of audio devices
  • An alphabetical reference to the functions, messages, and structures used to write audio device drivers

Before reading this section, you should be familiar with the audio services available with Windows, and with digital audio and MIDI. For information about the audio services of Windows, see the Multimedia Programmer's Reference in the Microsoft Windows Software Development Kit.


Sample Device Drivers

The DDK includes sample device drivers for audio hardware. These samples illustrate how to write drivers for waveform input and output devices, MIDI input and output devices, auxiliary devices, and mixer devices. There are also samples of virtual devices (VxDs). You should refer to these samples while using the documentation, to clarify the use and organization of the functions, messages, and structures.


Different Types of Audio Devices

The audio functions support seven types of audio devices:

  • Auxiliary audio devices which get mixed with MIDI and waveform audio in a multimedia computer.
  • Waveform input devices to convert analog audio signals into digital information.
  • Waveform output devices to convert digital audio information into analog audio signals.
  • MIDI input ports to receive MIDI information from external MIDI devices.
  • MIDI output ports to send MIDI information to external MIDI devices like keyboards and drum machines.
  • Internal MIDI synthesizers to synthesize music from MIDI information sent by applications.
  • Mixer devices to control multiple audio sources.

Internal MIDI synthesizer devices and MIDI output ports are both MIDI output devices. They use the same entry-point function and receive the same messages. However, instead of sending MIDI data to an output port, an internal synthesizer device converts the MIDI data into music or sound.


Writing an Audio Device Driver

The approach to writing drivers for each of the various types of audio devices is the same. Each type of driver requires an entry-point function with a different name, but the structure of each of these functions is identical. They all have similar messages to process, although some types have unique messages for operations exclusive to that particular type of device. This section presents information that applies to writing device drivers for all types of audio devices. Other sections later in the help file give an overview of the required and optional messages for each particular type of audio device and an overview of the structures associated with the messages.


Structure of an Audio Device Driver

Audio device drivers are dynamic-link libraries (DLLs) written in C, assembly language, or a combination of the two languages. You can combine drivers for different types of audio devices in a single DLL. For example, the Sound Blaster driver module, MSSB16.DRV, has drivers for waveform input and output as well as auxiliary and mixer devices.


How Applications Communicate with Audio Device Drivers

The MMSYSTEM module of Windows provides the interface between client applications and audio device drivers-applications do not call the drivers directly. When a client application calls a low-level audio function, MMSYSTEM translates the call into a message and sends the message to the appropriate device driver. When a device driver must notify a client, it calls MMSYSTEM with a message, and MMSYSTEM routes the message back to the client application, as shown in the following illustration:


Naming Audio Device Drivers

The filenames for device driver DLLs are not required to have a file extension of .DLL-you can name your driver using any file extension you want. It is suggested that you use the extension .DRV for your device drivers to follow the convention set by Windows.


Registry Entries for Audio Device Drivers

char  szDevNodeCfg[256];
HKEY  hkSW;

// Retrieve the name of the device node's registry key.

if (CM_Get_DevNode_Key(pDevNode, NULL,
        szDevNodeCfg, sizeof(szDevNodeCfg), CM_REGISTRY_SOFTWARE))
return MMSYSERR_KEYNOTFOUND;

// Combine the registry key name and string for new key name.

strcat(szDevNodeCfg, "\\Config");

// Open or create the new key.

if (RegOpenKey(HKEY_LOCAL_MACHINE, szDevNodeCfg, &hkSW)) {
   if (RegCreateKey(HKEY_LOCAL_MACHINE, szDevNodeCfg, &hkSW))
      return MMSYSERR_BADDB ;
}

// Set a value for the new key.

RegSetValueEx(hkSW, gszValueName, 0, REG_BINARY,
    (LPBYTE) pCustomData, sizeof(DWORD)) ;


Module-Definition File

To build a device-driver DLL, you must have a module-definition (.DEF) file. In the module-definition file, you must export at least two of the following entry-point functions:

  • DriverProc must be exported for all audio device drivers.
  • wodMessage must be exported for waveform output drivers.
  • widMessage must be exported for waveform input drivers.
  • modMessage must be exported for MIDI output drivers.
  • midMessage must be exported for MIDI input drivers.
  • auxMessage must be exported for auxiliary audio drivers.
  • mxdMessage must be exported for auxiliary audio drivers.

Functions are exported by ordinal, as shown in the following example MSSB16.DEF file:

LIBRARY     MSSB16

DESCRIPTION 'wave,aux,mixer:Creative Labs Sound Blaster 16 Driver'

EXETYPE     WINDOWS
PROTMODE

CODE        MOVEABLE DISCARDABLE LOADONCALL
DATA        FIXED SINGLE PRELOAD

SEGMENTS
    _TEXT       FIXED                          PRELOAD
    WEP_TEXT    FIXED                          PRELOAD
    INIT        MOVEABLE    DISCARDABLE        PRELOAD
    COMMON      MOVEABLE    DISCARDABLE        PRELOAD
    MIXER       MOVEABLE    DISCARDABLE        PRELOAD
    WAVE        MOVEABLE    DISCARDABLE        PRELOAD

HEAPSIZE    2048

EXPORTS
            WEP               @1       RESIDENTNAME
            DriverProc        @2       RESIDENTNAME
            wodMessage        @3       RESIDENTNAME
            widMessage        @4       RESIDENTNAME
            auxMessage        @5       RESIDENTNAME
            mxdMessage        @6       RESIDENTNAME

The actual ordinal values you assign to each exported function are not significant, though each must be unique within the DLL.


Module Name Line

The module name line should specify a unique module name for your device driver. Windows will not load two different modules with the same module name. It's a good idea to use the base of your driver filename since, in certain instances, LoadLibrary will assume that to be your module name. For example, the previous fragment used LIBRARY MSSB16.


Module Description Line

The module description line in the module-definition file should specify the type of device the driver supports. For example, here is the module description line from the module-definition file for the Sound Blaster driver:

DESCRIPTION 'wave,aux,mixer:Creative Labs Sound Blaster 16 Driver'

The beginning of the module description indicates the driver supports waveform, auxiliary, and mixer devices. Use one of the following device-type names, followed by a colon (:) to indicate the type of device your driver supports. If the driver supports more than one type of device, separate each device-type name with a comma (,).

  • wave for waveform audio devices
  • midi for MIDI audio devices
  • aux for auxiliary audio devices
  • mixer for mixer devices


Installable Driver Interface

All audio device drivers are installable drivers and must provide a DriverProc entry point. Installable drivers and the DriverProc entry point are described in the Microsoft Windows Software Development Kit.


Driver Configuration

Installable drivers can supply a configuration dialog box for users to access through an application (such as a Control Panel application).

Interrupt-level and port assignments, and any other hardware-related settings, should be stored in the registry, in the appropriate subkey of the following registry key:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\control\MediaResources


DriverProc Entry-Point Function

Regardless of how many types of audio devices a driver supports, the driver will always have a single DriverProc function.

Generally, when a driver is enabled, you initialize the hardware, hook interrupts, allocate any memory that you need, and set a flag to indicate the driver is enabled. If your driver has not been enabled by MMSYSTEM, or if it failed the enable process, the driver should return MMSYSERR_NOTENABLED from any messages it receives from client applications. When a driver is disabled, you free any memory that you allocated, unhook interrupts, reset the hardware, and set a flag to indicate the driver is not enabled.


Handling the DRV_DISABLE Message

It is possible for a driver to receive a DRV_DISABLE message while it is in the process of sending or receiving audio data. Audio device drivers should follow the behavior specified in the following table when they receive a DRV_DISABLE/DRV_ENABLE message pair:

Driver Type | Disable/Enable Behavior
waveform output | As if the driver were paused with a WODM_PAUSE message and then restarted with a WODM_RESTART message.
waveform input | As if the driver were stopped with a WIDM_STOP message and then restarted with a WIDM_START message.
MIDI output | If the driver is asynchronous, stop output when disabled and continue when re-enabled.
MIDI input | As if the driver were stopped with a MIDM_STOP message and then restarted with a MIDM_START message.

Most audio device drivers will be interrupt-driven. For example, a waveform output device interrupts when the device needs another data block. A MIDI input device interrupts when the device receives a MIDI event at its input port.


Fixing Code and Data Segments

Any code segments or data segments a driver accesses at interrupt-time must be fixed segments. For best overall system performance, you should minimize the amount of code and data in fixed segments. To minimize the amount of fixed code, isolate all interrupt-time code in a few source modules and put this code into a single fixed code segment. Unless your driver has a large amount of data not accessed at interrupt time, use a single fixed data segment.

For example, the Sound Blaster sample driver is a medium-model DLL, using a single data segment and multiple code segments. This example fixes the data segment and the code segments named _TEXT and WEP_TEXT. All other code segments are moveable. The code segment _TEXT is used as a safety measure. The compiler places code for which you do not specify a segment in the _TEXT segment. This way, any code that is missed will be placed into a fixed segment, preventing possible problems at interrupt time. However, you should check your segmentation to ensure that only code that is required to be FIXED goes into the FIXED code segment.


Allocating and Using Memory

You can allocate either local memory or global memory for use at interrupt time.

To allocate local memory for use at interrupt time, follow these steps:

  1. Use LocalAlloc with the LMEM_FIXED flag to get a handle to the memory block.
  2. Pass this handle to LocalLock to get a near pointer to the memory block.

Any global memory a driver uses at interrupt-time must be page-locked. To allocate and page-lock global memory, follow these steps:

  1. Use GlobalAlloc with the GMEM_MOVEABLE and GMEM_SHARE flags to get a handle to the memory block.
  2. Pass this handle to GlobalLock to get a far pointer to the memory block.
  3. Pass the high-order word of the far pointer to GlobalPageLock to page-lock the memory block.


Calling Windows Functions at Interrupt Time

The only Windows functions a driver can call at interrupt time are PostMessage, PostAppMessage, DriverCallback, timeGetSystemTime, timeGetTime, timeSetEvent, timeKillEvent, midiOutShortMsg, midiOutLongMsg, and OutputDebugStr.


Writing a VxD

Unlike devices such as printers and hard disk drives, audio devices do not necessarily have to be shareable between applications. However, if applications exist (or will exist in the future) that access your audio hardware directly, you should write a VxD to prevent these applications from doing so while Windows is using the device. For an example VxD, see the Microsoft Sound System sample device driver.

Note Audio and video compression and decompression drivers, including ACM drivers, do not directly access hardware and therefore do not require VxDs.


Entry-Point Functions

In addition to the installable driver entry-point function, DriverProc, an audio device driver must have at least one of the following entry-point functions:

  • wodMessage for waveform output drivers
  • widMessage for waveform input drivers
  • modMessage for MIDI output drivers and internal synthesizer drivers
  • midMessage for MIDI input drivers
  • auxMessage for auxiliary audio drivers
  • msdMessage for mixer drivers

Drivers that service more than one type of audio device must have one of the above entry-point functions for each type of device serviced. These functions process messages sent by MMSYSTEM to the driver as the result of an application call to a low-level audio function. For example, when an application opens a waveform output device with the waveOutOpen function, MMSYSTEM sends the specified waveform output device driver a WODM_OPEN message. The driver's wodMessage function receives and processes this message.


Reentrancy Considerations with Entry-Point Functions

The auxMessage, widMessage, wodMessage, and midMessage entry-point functions are not called at interrupt time and therefore do not have to be written to be reentrant. However, the entry-point function for MIDI output devices, modMessage, can be called at interrupt time. For details on making this entry-point function reentrant, see .


Opening and Closing Devices

Client applications must open an audio device before using it and close the device when finished using it, so the device will be available to other applications. If your device driver will support more than one client simultaneously, you must decide whether the device will return more than one in response to a _GETNUMDEVS message. For example, if your device driver supports multiple clients for simultaneous PCM waveform playback, the device driver might return one for the WODM_GETNUMDEVS message and allow multiple WODM_OPEN messages. Or, if your driver supports completely different playback formats (or routing to different playback hardware), the architecture might be cleaner if each format is treated as a separate device. If you choose to implement your driver as separate devices, you must always check the uDeviceID parameter to determine which device is being accessed. It is also important to set the appropriate DEVCAPS structure so that clients can tell the difference between your devices. For example, a MIDI output driver might support both an external MIDI port and an internal synthesizer. It would make sense to return two for the MODM_GETNUMDEVS message and consider device zero to be the port and device one the synthesizer.

Auxiliary audio devices are handled differently from waveform and MIDI devices. They do not have to be opened, because they do not have the same resource allocation requirements. Also, there is no interrupt level or continuous data transfer associated with auxiliary audio devices.

When a driver receives an open request with one of the_OPEN messages, the dwUser parameter of its entry-point function points to a location that the driver can fill with a DWORD of instance data. This instance data is returned to the driver in the same dwUser parameter when other messages are sent to the driver. Drivers should use this instance data for information related to the client that opened a device.


Data Transfer Model

The primary purpose of an audio device driver is to transfer audio data (waveform or MIDI) between an application and an audio device. The model for data transfer is a little different for waveform devices than it is for MIDI devices because of the nature of the data. Auxiliary audio devices do not require the transfer of audio data, just control information.


Data Transfer with Waveform Device Drivers

The following sequence of operations occurs when transferring audio data between a client application and a waveform output device driver:

  1. The client allocates the memory for the data block.
  2. The client requests that the driver prepare the data block.
  3. The client sends the data block to the driver.
  4. The driver puts the data block in its output queue.
  5. The client can send additional data blocks, which the driver also puts in its output queue.
  6. When the driver has sent a data block from its output queue to its output device, it returns the data block to the client by sending the client a message.
  7. The client requests that the driver clean up the preparation previously done on the data block.
  8. The client then frees the memory for the data block.

In addition, the driver must transfer the data it receives from the client to the waveform hardware. This transfer takes place in the background, as an interrupt-driven process. The driver may transfer data directly, or it may use the computer's DMA controller to transfer the data. Whether you choose to transfer data directly or use DMA depends on the capabilities of your target hardware. For input devices, the model is similar, except the client sends the driver an empty buffer. The buffer is filled with audio data directly by the driver or with DMA. The driver notifies the client when the buffer is filled.


Data Transfer with MIDI Device Drivers

With MIDI system-exclusive events, data transfer between a client application and a MIDI device driver is identical to the sequence described previously for waveform drivers. However, for all other MIDI events, the driver uses a different transfer mechanism. Because all other MIDI events are three bytes or less in size, they are packed into a DWORD and sent directly to the driver for output. The driver parses the event to determine its size and sends the individual bytes to the MIDI output hardware. If the driver is for an internal synthesizer, it parses the event and responds accordingly. MIDI input device drivers wait until receiving a complete MIDI event before packing the event into a DWORD and sending it to the client application through its callback.


Preparing Data Blocks

Because audio data blocks must be accessed at interrupt time, the memory allocated for them is subject to the requirements mentioned in . Rather than have the client application prepare the memory before sending data blocks to the driver, the client requests that the driver do the preparation. Most drivers can respond to this request (the appropriate _PREPARE and _UNPREPARE messages) by returning a MMSYSERR_NOTSUPPORTED error. Then, MMSYSTEM will perform the necessary preparation on the data block. This preparation consists of page locking the data block so the driver can access it at interrupt time.

If your device driver does not need the data to be page locked (for example, if you immediately copy the data to an on-card buffer) or if you have additional preparation to do to the buffer, you might respond to these messages yourself instead of having MMSYSTEM handle them. You should either respond to both the _PREPARE and _UNPREPARE message or to neither.


Handling Errors

For a description of the error return values from DriverProc, see the discussion of installable drivers in the Microsoft Windows Software Development Kit. The following table lists the general error return values from auxMessage, wodMessage, widMessage, midMessage, and midMessage.


General Error Return Values

MMSYSERR_ALLOCATED | Requested device is already allocated.
MMSYSERR_ERROR | Unspecified error.
MMSYSERR_NOERROR | No error.
MMSYSERR_NOMEM | Memory allocation error.
MMSYSERR_NOTENABLED | Driver is not enabled.
MMSYSERR_NOTSUPPORTED | Driver does not support specified operation.

In addition to these general error return values, there are error return values unique to each type of audio device. The following table lists these device-specific error return values.


Device-Specific Error Return Values

MIDIERR_NOTREADY | MIDI output hardware is busy.
MIDIERR_STILLPLAYING | Driver is still playing MIDI data.
MIDIERR_UNPREPARED | MIDI data block has not been prepared.
WAVERR_BADFORMAT | Unsupported waveform data format.
WAVERR_STILLPLAYING | Driver is still playing waveform data.
WAVERR_UNPREPARED | Specified waveform data block has not been prepared.


Notifying Clients with the DriverCallback Function

Audio device drivers need to notify clients when certain events occur, such as when a waveform data block has been played or when a MIDI input event is received. When the client opens a device, the client specifies how it wants to be notified. There are three ways a driver can notify a client application:

  • By calling a client-specified callback function
  • By sending a message to a client-specified window
  • By unblocking a client-specified task

To make the job of notifying clients easier, MMSYSTEM provides the DriverCallback function. DriverCallback takes information supplied by the client when it opened a device and notifies the client accordingly.

Clients must be notified when the following conditions occur:

  • When a device is opened.
  • When a device is closed.
  • When the driver is finished with a data block.
  • When the driver receives data that should be passed directly back to the application, such as when a MIDI input driver receives a MIDI event from an input port.


Writing a Waveform Output Driver

To write a waveform output driver, first create the initialization part of the driver-the part that includes the LibEntry, WEP, and DriverProc entry-point functions. Next, create the wodMessage entry-point function and the rest of the support code required to implement the driver. Be sure to process all of the required messages for waveform output device drivers. For each message you process, use the information provided in the reference at the end of this section to ensure you did everything required to correctly process the message.


The Entry Point for Waveform Output Drivers

A waveform output driver must have an entry-point function named wodMessage to process messages sent by MMSYSTEM. Waveform audio data is often passed to waveform device drivers in multiple data blocks. If a driver is playing a waveform data block and it receives additional data blocks, it must be able to play these contiguous data blocks without audible gaps in the audio output.


Waveform Output Driver Messages

This section gives the required and optional messages for waveform output device drivers. For detailed information on these messages, see the reference section later in this section.

The wodMessage entry-point function for waveform output drivers must support the following messages.


Required Messages for Waveform Output Device Drivers

WODM_BREAKLOOP | Breaks a playback loop.
WODM_CLOSE | Closes and deallocates a waveform output device.
WODM_GETDEVCAPS | Requests the capabilities of a waveform output device.
WODM_GETNUMDEVS | Requests the number of waveform output devices a driver supports.
WODM_GETPOS | Requests the current playback position for a waveform.
WODM_OPEN | Opens and allocates a waveform output device.
WODM_PAUSE | Pauses waveform playback on a waveform output device.
WODM_RESET | Stops playback and returns all data blocks to the client application.
WODM_RESTART | Continues playback after playback has been paused.
WODM_WRITE | Sends a data block for playback.

The wodMessage entry-point function for waveform output drivers can optionally support the following messages, depending on the capabilities of the target hardware.


Optional Messages for Waveform Output Device Drivers

WODM_GETPITCH | Requests the current pitch rate setting.
WODM_GETPLAYBACKRATE | Requests the current playback rate setting.
WODM_GETVOLUME | Requests the current volume level setting.
WODM_PREPARE | Requests that the driver prepare a data block for playback.
WODM_SETPITCH | Sets the pitch rate.
WODM_SETPLAYBACKRATE | Sets the playback rate.
WODM_SETVOLUME | Sets the volume level.
WODM_UNPREPARE | Requests that a driver clean up the preparation previously done on a data block.

In addition to receiving messages, drivers must notify clients when certain events occur. Waveform output drivers notify clients by sending one of the following messages using the DriverCallback function.


Client Notification Messages for Waveform Output Drivers

WOM_CLOSE | Notifies a client application when a device is closed.
WOM_DONE | Notifies a client application when the driver is finished with a data block and is returning it to the client.
WOM_OPEN | Notifies a client application when a device is opened.


Waveform Output Driver Structures

Each message received by the wodMessage function comes with two DWORD parameters. For some messages, one of these parameters points to a structure containing additional information from the client or to an empty structure for the driver to fill with information for the client.

Waveform output device drivers use the structures listed in the following table. For detailed information on these messages, see the reference section later in this section.

PCMWAVEFORMAT | A client-filled structure providing specific information about the format for PCM waveform data.
WAVEFORMAT | A client-filled structure providing general information about the format of waveform data.
WAVEHDR | A client-filled structure identifying a waveform data block.
WAVEOPENDESC | A client-filled structure providing information about opening a waveform device.
WAVEOUTCAPS | A driver-filled structure providing a client with information about the capabilities of a waveform output device.


Writing a Waveform Input Driver

To write a waveform input driver, first create the initialization part of the driver-the part that includes the LibEntry, WEP, and DriverProc entry-point functions. Next, create the widMessage entry-point function and the rest of the support code required to implement the driver. Be sure to process all of the required messages for waveform input device drivers. For each message you process, use the information provided in the reference at the end of this section to ensure you did everything required to correctly process the message.


Entry Point for Waveform Input Drivers

A waveform input driver must have an entry-point function named widMessage to process messages sent by MMSYSTEM.


Waveform Input Driver Messages

This section gives the required and optional messages for waveform input device drivers. For detailed information on these messages, see the reference section later in this section.


Required Messages for Waveform Input Drivers

The widMessage entry-point function for waveform input drivers must support the following messages.

WIDM_ADDBUFFER | Adds a buffer to the input queue.
WIDM_CLOSE | Closes and deallocates a waveform input device.
WIDM_GETDEVCAPS | Requests the capabilities of a waveform input device.
WIDM_GETNUMDEVS | Requests the number of waveform input devices a driver supports.
WIDM_GETPOS | Requests the current input recording position.
WIDM_OPEN | Opens and allocates a waveform input device.
WIDM_RESET | Stops waveform input and returns all data buffers to the client application.
WIDM_START | Begins waveform input.
WIDM_STOP | Ends waveform input.


Optional Messages for Waveform Input Drivers

The widMessage entry-point function for waveform input drivers can optionally support the following messages, depending on whether the driver requires any special preparation to client data buffers.

WIDM_PREPARE | Requests that the driver prepare a data buffer for input.
WIDM_UNPREPARE | Requests that a driver clean up the preparation previously done on a data buffer.


Client Notification Messages for Waveform Input Drivers

In addition to receiving messages, drivers must notify clients when certain events occur. Waveform input drivers notify clients by sending one of the following messages using the DriverCallback function.

WIM_CLOSE | Notifies a client application when a device is closed.
WIM_DATA | Notifies a client application when the driver is finished with a data buffer and is returning it to the client.
WIM_OPEN | Notifies a client application when a device is opened.


Waveform Input Driver Structures

Each message received by the widMessage function comes with two DWORD parameters. For some messages, one of these parameters points to a structure containing additional information from the client, or to an empty structure for the driver to fill with information for the client.

Waveform input device drivers use the structures listed in the following table. For detailed information on these structures, see the reference section later in this section.

PCMWAVEFORMAT | A client-filled structure providing specific information about the format for PCM waveform data.
WAVEFORMAT | A client-filled structure providing general information about the format of waveform data.
WAVEHDR | A client-filled structure identifying a waveform data block.
WAVEINCAPS | A driver-filled structure providing a client with information about the capabilities of a waveform input device.
WAVEOPENDESC | A client-filled structure providing information about opening a waveform device.

With the exception of WAVEINCAPS, these are the same structures used by waveform output drivers.


Writing a MIDI Output Driver

Internal MIDI synthesizer devices and MIDI output ports are both MIDI output devices. They use the same entry-point function and receive the same messages. However, instead of sending MIDI data to an output port, an internal synthesizer device converts the MIDI data into music or sound.

To write a MIDI output driver, first create the initialization part of the driver-the part that includes the LibEntry, WEP, and DriverProc entry-point functions. Next, create the modMessage entry-point function and the rest of the support code required to implement the driver. Be sure to process all of the required messages for MIDI output device drivers. For each message you process, use the information provided by the reference at the end of this section to ensure you did everything required to correctly process the message.

Note For information on the content of MIDI data, see the MIDI specification published by the International MIDI Association.


Entry Point for MIDI Output Drivers

A MIDI output driver must have an entry-point function named modMessage to process messages sent by MMSYSTEM.


Synchronous Versus Asynchronous Message Processing

MIDI output device drivers can process the MODM_DATA and MODM_LONGDATA messages either synchronously or asynchronously. If a driver processes these messages synchronously, it waits until all the data has been sent to the hardware before returning from the modMessage function. An asynchronous driver puts the data in a queue and returns immediately. The data is then sent to the hardware in the background.

Whether a driver is written to be synchronous or asynchronous usually depends on the hardware being supported. An asynchronous driver is desirable because it lets foreground applications run while it processes data; however, some hardware may not support asynchronous data transfer. The Sound Blaster sample driver processes the MODM_DATA and MODM_LONGDATA messages synchronously.


Interrupt-Time and Reentrancy Considerations for modMessage

The midiOutShortMsg and midiOutLongMsg functions can be called by applications (and by device drivers) at interrupt time. Thus, the modMessage entry-point function in a MIDI output device driver can be accessed at interrupt time and must be written to be reentrant for the MODM_DATA and MODM_LONGDATA messages.

Note For internal MIDI synthesizer drivers, the interrupt-time reception of the MODM_DATA and MODM_LONGDATA messages has an additional consequence: The driver cannot access the disk at interrupt-time to load patch data if it receives a MIDI program-change request.

An example of the reentrancy situation is illustrated by an application that takes incoming MIDI events and sends them to a MIDI output port. The application's low-level callback function for MIDI input receives a MIDM_DATA message, accompanied by the incoming MIDI data. The callback function calls midiOutShortMsg to send the data to a MIDI output port. The modMessage entry-point function in the output port driver is called with a MODM_DATA message. This all happens at interrupt time. While modMessage is processing the MODM_DATA message, another MIDI event arrives at the input port, and the process starts again, with modMessage being reentered with another MODM_DATA message.

To handle being called at interrupt time, the modMessage entry-point function must follow these guidelines:

  • modMessage must reside in a FIXED code segment. Any functions called during processing of the MODM_DATA and MODM_LONGDATA messages must also be in a FIXED code segment.
  • modMessage can access only data in FIXED data segments when processing the MODM_DATA and MODM_LONGDATA messages.

One way for synchronous drivers to be reentrant is to detect when modMessage is reentered and return a MIDIERR_NOTREADY error.

Note A good way for a synchronous driver to handle being reentered is for the driver to maintain a small buffer to hold data received when it's reentered, instead of returning MIDIERR_NOTREADY. Before the driver returns from the original modMessage call (the one that was reentered), it makes sure that all data in this buffer is sent to the hardware.


Handling Running Status Output

If a driver receives MIDI events with the MODM_DATA message and these events do not include a status byte, the driver must assume running status is being used. When you parse the event to determine its length, the driver must assume the most recently received status byte applies to the current event. The driver does not have to transmit the running status byte to the hardware.


Required MIDI Messages for Internal Synthesizers

Device drivers for internal MIDI synthesizers are required to respond to certain MIDI messages, such as note-on and note-off messages. In addition, it is recommended that they respond to MIDI messages (such as the main volume controller message). The following table identifies these required and recommended messages for internal synthesizer drivers. Support for all messages not listed in this table is optional.

Required Messages | Recommended Messages
Note-On with Velocity | Damper Pedal (Controller Number 64)
Note-Off | Main Volume (Controller Number 7)
Program Change |
Pitch Bend |

Note it is strongly recommended that internal synthesizers respond to the main volume message. This message is used in standard MIDI files to control the relative volume of each instrument used in the piece of music.


MIDI Output Driver Messages

This section gives the required and optional messages for MIDI output device drivers. For detailed information on these messages, see the reference section later in this section. The modMessage entry-point function for MIDI output drivers must support the following messages.


Required Messages for MIDI Output Device Drivers

MODM_CLOSE | Closes and deallocates a MIDI output device.
MODM_DATA | Sends a MIDI event to the driver for output. This message is used for all MIDI events, except system-exclusive events.
MODM_GETDEVCAPS | Requests the capabilities of a MIDI output device.
MODM_GETNUMDEVS | Requests the number of MIDI output devices a driver supports.
MODM_LONGDATA | Sends a MIDI data block to the driver for output. The data block can contain one or more MIDI events, including system-exclusive events.
MODM_OPEN | Opens and allocates a MIDI output device.
MODM_RESET | Stops playback and returns all data blocks to the client application.


Optional Messages for MIDI Output Device Drivers

The modMessage entry-point function for MIDI output drivers can optionally support the following messages, depending on the capabilities of the target hardware.

MODM_GETVOLUME | Requests the current volume level setting. This message is used only by internal synthesizer devices.
MODM_PREPARE | Requests that the driver prepare a data block for playback.
MODM_SETVOLUME | Sets the volume level. This message is used only by internal synthesizer devices.
MODM_UNPREPARE | Requests that a driver clean up the preparation previously done on a data block.


Client Notification Messages for MIDI Output Drivers

In addition to receiving messages, drivers must notify clients when certain events occur. MIDI output drivers notify clients by sending one of the following messages using the DriverCallback function.

MOM_CLOSE | Notifies a client application when a device is closed.
MOM_DONE | Notifies a client application when the driver finishes with a system-exclusive data block and returns it to the client.
MOM_OPEN | Notifies a client application when a device is opened.


MIDI Output Driver Structures

Each message received by the modMessage function comes with two DWORD parameters. For some messages, one of these parameters points to a structure containing additional information from the client, or to an empty structure for the driver to fill with information for the client.

MIDI output device drivers use the structures listed in the following table. For detailed information on these structures, see the reference section later in this section.

MIDIHDR | A client-filled structure identifying a MIDI data block.
MIDIOPENDESC | A client-filled structure providing information about opening a MIDI device.
MIDIOUTCAPS | A driver-filled structure providing a client with information about the capabilities of a MIDI output device.


Writing a MIDI Input Driver

To write a MIDI input driver, first create the initialization part of the driver-the part that includes the LibEntry, WEP, and DriverProc entry-point functions. Next, create the midMessage entry-point function and the rest of the support code required to implement the driver. Be sure to process all of the required messages for MIDI input device drivers. For each message you process, use the information provided by the reference at the end of this section to ensure you did everything required to correctly process the message.

Note For information on the content of MIDI data, see the MIDI specification published by the International MIDI Association.


Entry Point for MIDI Input Drivers

A MIDI input driver must have an entry-point function named midMessage to process messages sent by MMSYSTEM.


Time Stamping MIDI Input

MIDI input drivers must time-stamp incoming MIDI events. The time stamp is the number of milliseconds since MIDI input was started.

The MIDM_START message resets time stamps to zero. When your midMessage entry-point function receives a MIDM_START message, use timeGetTime to get a reference time stamp. Then, each time you receive an incoming MIDI event, call timeGetTime to get the current system time. Subtract the reference time stamp from the current system time to get a time stamp for the MIDI event. For multi-byte MIDI events, the time stamp specifies when the first byte (the MIDI status byte) was received.

Note If the target hardware supports time stamping, you can use its capabilities to generate time stamps more efficiently than calling the timeGetTime function. However, time stamps must still specify the time in milliseconds since MIDI input was started with the MIDM_START message.


Handling Running Status Input

If you receive a data byte as the first byte of an incoming MIDI event, you must assume running status is being used. With running status, the most recently received status byte applies to the current event. When sending the event to the client application, include the running status byte. Never send an incoming event to a client without a status byte.


MIDI Input Driver Messages

This section gives the required and optional messages for MIDI input device drivers. For detailed information on these messages, see the reference section later in this section. The midMessage entry-point function for MIDI input drivers must support the following messages.


Required Messages for MIDI Input Device Drivers

MIDM_ADDBUFFER | Adds a buffer to the input queue.
MIDM_CLOSE | Closes and deallocates a MIDI input device.
MIDM_GETDEVCAPS | Requests the capabilities of a MIDI input device.
MIDM_GETNUMDEVS | Requests the number of MIDI input devices a driver supports.
MIDM_OPEN | Opens and allocates a MIDI input device.
MIDM_RESET | Stops output and returns all data blocks to the client application.
MIDM_START | Begins MIDI input and resets the time stamp to zero.
MIDM_STOP | Ends MIDI input.


Optional Messages for MIDI Input Device Drivers

The midMessage entry-point function for MIDI input drivers may support the following messages, depending on whether the driver requires special preparation to client data buffers.

MIDM_PREPARE | Requests that the driver prepare a data block for playback.
MIDM_UNPREPARE | Requests that a driver clean up the preparation previously done on a data block.


Client Notification Messages for MIDI Input Drivers

In addition to receiving messages, drivers must notify clients when certain events occur. MIDI input drivers notify clients by sending one of the following messages using the DriverCallback function.

MIM_CLOSE | Notifies a client application when a device is closed.
MIM_DATA | Notifies a client application when the driver receives a complete MIDI event and is sending the event to the client.
MIM_ERROR | Notifies a client application when the driver receives an incomplete MIDI event.
MIM_LONGDATA | Notifies the client application when the driver returns a buffer with system-exclusive data to the client.
MIM_LONGERROR | Notifies the client application when the driver encounters an error while receiving system-exclusive data.
MIM_OPEN | Notifies a client application when a device is opened.


MIDI Input Driver Structures

Each message received by the midMessage function comes with two DWORD parameters. For some messages, one of these parameters points to a structure containing additional information from the client, or to an empty structure for the driver to fill with information for the client.

MIDI input device drivers use the structures listed in the following table. For detailed information on these structures, see the reference section later in this section.

MIDIHDR | A client-filled structure identifying a MIDI data block.
MIDIINCAPS | A driver-filled structure providing a client with information about the capabilities of a MIDI input device.
MIDIOPENDESC | A client-filled structure providing information about opening a MIDI device.


Writing a MIDI Throughput Device Driver

You can create a special form of MIDI output device called a throughput device driver. An application could connect a MIDI input device to this throughput device driver and then connect the MIDI throughput device to as many MIDI output devices as needed. To implement a throughput device, use the DRVM_ADD_THRU, DRVM_REMOVE_THRU, and DRVM_IOCTL messages.


Writing an Auxiliary Audio Device Driver

Auxiliary audio devices are audio sources, such as CD_ROM audio, mixed with the audio from waveform and internal MIDI synthesizers in a multimedia computer.

To write an auxiliary audio device driver, first create the initialization part of the driver-the part that includes the LibEntry, WEP, and DriverProc entry-point functions. Next, create the auxMessage entry-point function and the support code required to implement the driver. Be sure to process all of the required messages for auxiliary audio device drivers. For each message you process, use the information provided by the reference at the end of this section to ensure you did everything required to correctly process the message.


Entry Point for Auxiliary Audio Device Drivers

A auxiliary audio device driver must have an entry-point function named auxMessage to process messages sent by MMSYSTEM.


Auxiliary Audio Device Driver Messages

This section gives the required and optional messages for auxiliary audio device drivers. For detailed information on these messages, see the reference section later in this section.


Required Messages for Auxiliary Audio Device Drivers

The auxMessage entry-point function for auxiliary audio device drivers must support the following messages.

AUXDM_GETDEVCAPS | Requests the capabilities of an auxiliary input device.
AUXDM_GETNUMDEVS | Requests the number of auxiliary input devices a driver supports.


Optional Messages for Auxiliary Audio Device Drivers

The auxMessage entry-point function for auxiliary audio device drivers can optionally support the following messages, depending on the capabilities of the target hardware.

AUXDM_GETVOLUME | Requests the current volume level setting on an auxiliary audio device.
AUXDM_SETVOLUME | Sets the volume level on an auxiliary audio device.


Auxiliary Audio Device Driver Structures

Each message received by the auxMessage function comes with two DWORD parameters. For some messages, one of these parameters points to a structure containing additional information from the client, or to an empty structure for the driver to fill with information for the client.

Auxiliary audio device drivers use the structures listed in the following table. For detailed information on this structure, see the reference section later in this section.

AUXCAPS A driver-filled structure providing a client with information about the capabilities of an auxiliary audio device.


Writing a Mixer Device Driver

A software-controlled audio mixer allows applications to control various aspects of the audio mix, such as the relative volume level of each audio source. To write a mixer device driver, first create the initialization part of the driver-the part that includes the LibEntry, WEP, and DriverProc entry-point functions. Next, create the mxdMessage entry-point function and the support code required to implement the driver. Be sure to process all of the required messages for mixer device drivers. For each message you process, use the information provided by the reference at the end of this section to ensure you did everything required to correctly process the message.


Entry Point for Mixer Device Drivers

A mixer device driver must have an entry-point function named mxdMessage to process messages sent by MMSYSTEM.


Mixer Device Driver Messages

This section gives the messages for mixer device drivers. For detailed information on these messages, see the reference section later in this section.


Required Messages for Mixer Device Drivers

The mxdMessage entry-point function for mixer device drivers must support the following messages.

MXDM_CLOSE | Requests the driver to deallocate a specified driver instance.
MXDM_GETCONTROLDETAILS | Requests the state of one or more items for a control.
MXDM_GETDEVCAPS | Requests the capabilities of an mixer device.
MXDM_GETLINECONTROLS | Requests the controls associated with a specified line.
MXDM_GETLINEINFO | Requests information about a specified line.
MXDM_GETNUMDEVS | Requests the number of mixer devices a driver supports.
MXDM_INIT | Informs the driver that all mixer drivers have been loaded and enabled by the audio mixer manager.
MXDM_OPEN | Requests the driver to allocate a specified device for use by a client application.
MXDM_SETCONTROLDETAILS | Requests the driver to set the state of one or more items for a control.

An audio mixer driver may provide custom-defined messages beginning with the MXDM_USER value. All messages below this value are reserved for system use. Before sending a custom message to a mixer driver, the calling application should verify that the mixer driver can process the message correctly. The calling application should retrieve the following mixer capabilities and confirm the values of the driver for the following members of MIXERCAPS: wMid, wPid, vDriverVersion and szPname


Reference

This section lists the functions, messages, and structures provided by Windows for use by audio device drivers.

Windows communicates with audio device drivers through messages sent to the driver. The driver processes these messages with its wodMessage, widMessage, modMessage, midMessage, or auxMessage entry-point function. The function used depends on the type of device the driver supports. Drivers can also send messages to client applications with the DriverCallback function.

This section contains an alphabetical list of all messages that can be received and sent by audio device drivers. Each message name contains a prefix, identifying the type of the message. The following list identifies the prefixes used for audio device driver messages:

Prefix | Description
AUXDM | Sent by MMSYSTEM to an auxiliary audio device driver's auxMessage function.
MIDM | Sent by MMSYSTEM to a MIDI input driver's midMessage function.
MIM | Sent by MIDI input drivers to notify client applications.
MODM | Sent by MMSYSTEM to a MIDI output driver's modMessage function.
MOM | Sent by MIDI output drivers to notify client applications.
MXDM | Sent by MMSYSTEM to a mixer driver's mxdMessage function
WIDM | Sent by MMSYSTEM to a waveform input driver's widMessage function.
WIM | Sent by waveform input drivers to notify client applications.
WODM | Sent by MMSYSTEM to a waveform output driver's wodMessage function.
WOM | Sent by waveform output drivers to notify client applications.

A message consists of three parts: a message number and two DWORD parameters. Message numbers are identified by predefined message names. The two DWORD parameters contain message-dependent values.

The stream buffer enhancement to the MIDI device architecture not only affects the MIDI SDK functions, data structures, and messages, but also reaches to the DDK level as driver messages. Many of the new MIDI driver messages documented in this section support the block data transfer of the stream buffer.


Functions

The following topics describe the functions provided by Windows for use by audio device drivers.


auxMessage

DWORD auxMessage(uDevice, uMsg, dwUser, dwParam1, dwParam2)

This function is the entry point for an auxiliary audio device driver.

  • Unless specified otherwise under a specific message, the driver should return an MMSYSERR_ or AUXERR_ error code.
UINT uDevice
Specifies the ID of the target device. Device IDs are sequential, starting at zero and ending at a value equal to one less than the number of devices the driver supports.
UINT uMsg
Specifies the message being sent to the driver.
DWORD dwUser
Not used.
DWORD dwParam1
Specifies a message-dependent parameter.
DWORD dwParam2
Specifies a message-dependent parameter.

The driver should return MMSYSERR_NOTSUPPORTED if it does not support the specified message.


DriverCallback

BOOL DriverCallback(dwCallBack, uFlags, hDevice, uMsg, dwUser, dwParam1, dwParam2)

This function notifies a client application by sending a message to a window or callback function or by unblocking a task.

  • Returns TRUE if the callback was performed, else FALSE if an invalid parameter was passed, or the task's message queue was full.
DWORD dwCallBack
Specifies either the address of a callback function, a window handle, or a task handle, depending on the flags specified in the wFlags parameter.
UINT uFlags
Specifies how the client application is notified, according to one of the following flags.
DCB_NOSWITCH | Use this if you know you have enough stack space for the callback; otherwise MMSYSTEM will switch your stack for you.
DCB_FUNCTION | The application is notified by sending a message to a callback function. The dwCallback parameter specifies a procedure-instance address.
DCB_WINDOW | The application is notified by sending a message to a window. The low-order word of the dwCallback parameter specifies a window handle.
DCB_TASK | The application is notified by sending a message to the application or task. The low-order word of the dwCallback parameter specifies a task handle.

HANDLE hDevice
Specifies a handle to the device associated with the notification. This is the handle assigned by MMSYSTEM when the device was opened.
UINT uMsg
Specifies a message to send to the application.
DWORD dwUser
Specifies the DWORD of user instance data supplied by the application when the device was opened.
DWORD dwParam1
Specifies a message-dependent parameter.
DWORD dwParam2
Specifies a message-dependent parameter.

This function can be called at interrupt time.

The client specifies how it wants to be notified when it opens the device. The flags DCB_FUNCTION and DCB_WINDOW are equivalent to the high-order word of the corresponding flags CALLBACK_FUNCTION and CALLBACK_WINDOW specified in the dwParam2 parameter of the _OPEN message when the device was opened.

If notification is done with a callback function, hDevice, uMsg, dwUser, dwParam1, and dwParam2 are passed to the callback. If notification is done with a window, only uMsg, hDevice, and dwParam1 are passed to the window.


midMessage

DWORD midMessage(uDeviceID, uMsg, dwUser, dwParam1, dwParam2)

Entry point for a MIDI input device driver. This function is supplied by the user.

  • Unless specified otherwise under a specific message, the driver should return an MMSYSERR_ or MIDIERR_ error code.
UINT uDeviceID
Specifies the ID of the target device. Device IDs are sequential, starting at zero and ending at a value equal to one less than the number of devices the driver supports.
UINT uMsg
Specifies the message being sent to the driver.
DWORD dwUser
For the MIDM_OPEN message, the driver should fill this location with its instance data. For any other messages, the instance data is returned to the driver. Drivers supporting multiple clients can use this instance data to keep track of which client is associated with the message.
DWORD dwParam1
Specifies a message-dependent parameter.
DWORD dwParam2
Specifies a message-dependent parameter.

The driver should return MMSYSERR_NOTSUPPORTED if it does not support the specified message.


modMessage

DWORD modMessage(uDeviceID, uMsg, dwUser, dwParam1, dwParam2)

Entry point for a MIDI output device driver. This function is supplied by the user.

  • Unless specified otherwise under a specific message, the driver should return an MMSYSERR_ or MIDIERR_ error code.
UINT uDeviceID
Specifies the ID of the target device. Device IDs are sequential, starting at zero and ending at a value equal to one less than the number of devices the driver supports.
UINT uMsg
Specifies the message being sent to the driver.
DWORD dwUser
For the MODM_OPEN message, the driver should fill this location with its instance data. For any other messages, the instance data is returned to the driver. Drivers supporting multiple clients can use this instance data to keep track of which client is associated with the message.
DWORD dwParam1
Specifies a message-dependent parameter.
DWORD dwParam2
Specifies a message-dependent parameter.

The driver should return MMSYSERR_NOTSUPPORTED if it does not support the specified message.


mxdMessage

DWORD mxdMessage(uDeviceID, uMsg, dwUser, dwParam1, dwParam2)

Entry point for a mixer device driver. This function is supplied by the user.

  • Unless specified otherwise under a specific message, the driver should return an MMSYSERR_ or MIXERR_ error code.
UINT uDeviceID
Specifies the ID of the target device. Device IDs are sequential, starting at zero and ending at a value equal to one less than the number of devices the driver supports.
UINT uMsg
Specifies the message being sent to the driver.
DWORD dwUser
For the MXDM_OPEN message, the driver should fill this location with its instance data. For any other messages, the instance data is returned to the driver. Drivers supporting multiple clients can use this instance data to keep track of which client is associated with the message.
DWORD dwParam1
Specifies a message-dependent parameter.
DWORD dwParam2
Specifies a message-dependent parameter.

The driver should return MMSYSERR_NOTSUPPORTED if it does not support the specified message.


widMessage

DWORD widMessage(uDeviceID, uMsg, dwUser, dwParam1, dwParam2)

This user-supplied function is the entry point for a waveform input device driver.

  • Unless specified otherwise under a specific message, the driver should return an MMSYSERR_ or WAVERR_ error code.
UINT uDeviceID
Specifies the ID of the target device. Device IDs are sequential, starting at zero and ending at a value equal to one less than the number of devices the driver supports.
UINT uMsg
Specifies the message being sent to the driver.
DWORD dwUser
For the WIDM_OPEN message, the driver should fill this location with its instance data. For any other messages, the instance data is returned to the driver. Drivers supporting multiple clients can use this instance data to keep track of which client is associated with the message.
DWORD dwParam1
Specifies a message-dependent parameter.
DWORD dwParam2
Specifies a message-dependent parameter.

The driver should return MMSYSERR_NOTSUPPORTED if it does not support the specified message.


wodMessage

DWORD wodMessage(uDeviceID, uMsg, dwUser, dwParam1, dwParam2)

This user-supplied function is the entry point for a waveform output device driver.

  • Unless specified otherwise under a specific message, the driver should return an MMSYSERR_ or WAVERR_ error code.
UINT uDeviceID
Specifies the ID of the target device. Device IDs are sequential, starting at zero and ending at a value equal to one less than the number of devices the driver supports.
UINT uMsg
Specifies the message being sent to the driver.
DWORD dwUser
For the WODM_OPEN message, the driver should fill this location with its instance data. For any other messages, the instance data is returned to the driver. Drivers supporting multiple clients can use this instance data to keep track of which client is associated with the message.
DWORD dwParam1
Specifies a message-dependent parameter.
DWORD dwParam2
Specifies a message-dependent parameter.

The driver should return MMSYSERR_NOTSUPPORTED if it does not support the specified message.


Messages

The following topics describe the messages provided by Windows for use by audio device drivers.


AUXDM_GETDEVCAPS

Sent to an auxiliary audio device driver to request the capabilities of a specific auxiliary audio device.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

DWORD dwParam1
For Plug and Play drivers, specifies a pointer to an MDEVICECAPSEX structure. The driver fills this structure with the capabilities of the device.

For non-Plug and Play drivers, specifies a far pointer to an AUXCAPS data structure. The driver fills this structure with the capabilities of the device.

DWORD dwParam2
For Plug and Play drivers, specifies a device node.

For non-Plug and Play drivers, specifies the size of the AUXCAPS structure, in bytes.

For non-Plug and Play drivers, the driver should only write dwParam2 or less bytes to the location pointed to by dwParam1. If dwParam2 is zero, write nothing and return MMSYSERR_NOERROR.


AUXDM_GETNUMDEVS

Sent to an auxiliary audio device driver to request the number of auxiliary audio devices the driver supports.

  • Returns the number of auxiliary audio devices the driver supports.
DWORD dwParam1
Unused.
DWORD dwParam2
Unused.


AUXDM_GETVOLUME

Sent to an auxiliary audio device driver to request the current volume level setting for a device.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | Function is not supported.

DWORD dwParam1
Specifies a far pointer to a DWORD location. The driver fills this location with the current volume level setting. The high-order word contains the right channel setting and the low-order word contains the left channel setting. A value of zero is silence, and a value of 0xFFFF is full volume. If the driver does not support both left and right channel volume changes, it returns the volume in the low-order word.
DWORD dwParam2
Unused.

Drivers do not have to support volume level changes. However, if a driver supports changes to the volume level with the AUXDM_SETVOLUME message, it must support queries with the AUXDM_GETVOLUME message.


AUXDM_SETVOLUME

Sent to an auxiliary audio device driver to set the volume level for an auxiliary audio device.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The driver does not support changes to volume level.

DWORD dwParam1
Specifies the new volume level. The high-order word contains the right channel setting and the low-order word contains the left channel setting. A value of zero is silence, and a value of 0xFFFF is full volume. If the driver does not support both left and right channel volume changes, it uses the volume specified in the low-order word. The driver will probably not support the full 16 bits of volume control and should truncate the lower bits if necessary. However, the original value requested with AUXDM_SETVOLUME should be returned with AUXDM_GETVOLUME.
DWORD dwParam2
Unused.

Support for volume level changes is optional. Drivers must indicate whether they support volume level changes when they receive the AUXDM_GETDEVCAPS message.

If a driver supports changes to the volume level with the AUXDM_SETVOLUME message, it must support queries with the AUXDM_GETVOLUME message.


DRVM_ADD_THRU

Sent to a MIDI input device driver to add a given device to the list of output devices that receive MIDI throughput messages. If the MIDI input driver returns MMSYSERR_NOTSUPPORTED, the system will simulate throughput to one MIDI output or MIDI throughput device. This message is not intended to be sent directly by an application; instead, it is sent implicitly when an application calls the midiConnect function.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTSUPPORTED | The driver does not support MIDI throughput. Returning this value causes the system to simulate throughput on behalf of the driver.
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MIDIERR_NOTREADY | The MIDI hardware is busy with other data.

DWORD dwParam1
Specifies the handle of the MIDI output device to be added to the throughput list.
DWORD dwParam2
Address of user-instance data. This parameter can be NULL.


DRVM_IOCTL

Sent to a MIDI throughput device driver with information the driver uses to filter MIDI throughput data. This message is sent to a device driver when an application calls the midiOutMessage function.

  • The return value is driver dependent.
DWORD dwParam1
Specifies the handle of the MIDI output device to which configuration information is intended to apply. This parameter may be NULL.
DWORD dwParam2
NULL or the address of a DRVM_IOCTL_DATA structure. (If this parameter is not zero, it is translated by the thunking layer as a pointer.) The meaning of the contents of this structure is driver-dependent.

See Also

DRVM_ADD_THRU, DRVM_IOCTL_DATA, DRVM_REMOVE_THRU


DRVM_REMOVE_THRU

Sent to a MIDI input device driver to remove a given device from the list of output devices that receive MIDI throughput data. This message is sent to a device driver when an application calls the midiDisconnect function.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MIDIERR_NOTREADY | The MIDI hardware is busy with other data.

DWORD dwParam1
Specifies the handle of the MIDI output device to be removed from the throughput list.
DWORD dwParam2
Address of user-instance data. This parameter can be NULL.

See Also

DRVM_ADD_THRU, DRVM_IOCTL


MIDM_ADDBUFFER

Sent to a MIDI input device driver to add a buffer to the input queue.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The driver does not support this message.
MIDIERR_UNPREPARED | The specified data buffer has not been prepared for input.

DWORD dwParam1
Specifies a far pointer to a MIDIHDR data structure identifying the buffer.
DWORD dwParam2
Specifies the size of the MIDIHDR structure.

The driver should clear the MHDR_DONE bit and set the MHDR_INQUEUE bit in the header structure, and place the data block in its input queue. Then the driver should return control to the client by returning MMSYSERR_NOERROR.

Input to the buffer should occur as an interrupt-driven process. Only system-exclusive data should be placed in the buffer. Other MIDI events should be sent directly to the client application by sending a MIM_DATA message with the DriverCallback function.

Recording begins when the driver receives a MIDM_START message. Once the data block has been filled with data, the driver should set the MHDR_DONE bit and clear the MHDR_INQUEUE bit before notifying the client by using DriverCallback to send a MIM_DATA message.

If the driver receives data with no buffers in its input queue, it should ignore the data without notifying the client.


MIDM_CLOSE

Sent to a MIDI input device driver to deallocate a specified device.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MIDIERR_STILLPLAYING | There are still buffers in the queue.

DWORD dwParam1
Unused.
DWORD dwParam2
Unused.

If there are input buffers that have been received with the MIDM_ADDBUFFER message and have not been returned to the application, the driver should fail the close operation by returning MIDIERR_STILLPLAYING. If the close operation is successful, the driver should use the DriverCallback function to send the client a MIM_CLOSE message.

See Also

MIDM_OPEN


MIDM_GETDEVCAPS

Sent to a MIDI input driver to request the capabilities of a specific MIDI input device.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

DWORD dwParam1
For Plug and Play drivers, specifies a pointer to an MDEVICECAPSEX structure. The driver fills this structure with the capabilities of the device.

For non-Plug and Play drivers, specifies a far pointer to a MIDIINCAPS data structure. The driver fills this structure with the capabilities of the device.

DWORD dwParam2
For Plug and Play drivers, specifies a device node.

For non-Plug and Play drivers, specifies the size of the MIDIINCAPS structure in bytes.

For non-Plug and Play drivers, the driver should only write dwParam2 or less bytes to the location pointed to by dwParam1.


MIDM_GETNUMDEVS

Sent to a MIDI input device driver to request the number of MIDI input devices available.

  • Returns the number of input devices the driver supports.
DWORD dwParam1
Unused.
DWORD dwParam2
Unused.


MIDM_GETPOS

Requests that the driver return its current position in a stream of data. The position is reported as elapsed time relative to the start of the first byte that was received.

  • Returns zero if the operation is successful. Otherwise, it returns an error number. Possible error values include the following:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

dwParam1
Specifies a far pointer to an MMTIME structure cast to a DWORD.
dwParam2
Specifies the length of the MMTIME structure in bytes.

The driver should return the position in the time format specified in the wType member of MMTIME. If the time format specified in wType is not supported, the driver should change wType to the default time format and return the position in that format.


MIDM_OPEN

Sent to a MIDI input driver to allocate a specified device for use by a client application.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_ALLOCATED | The device is already allocated by the maximum number of clients the driver supports or the device cannot be opened because of system resource limitations other than memory.
MMSYSERR_NOMEM | The device cannot be opened because of a failure allocating or locking memory.

DWORD dwParam1
Specifies a far pointer to a MIDIOPENDESC structure. This structure contains additional information for the driver such as instance data from the client and a callback for the client.
DWORD dwParam2
Specifies option flags for opening the device.
CALLBACK_EVENT | If this flag is specified, dwCallback in the MIDIOPENDESC structure is assumed to be an event handle.
CALLBACK_FUNCTION | If this flag is specified, dwCallback in the MIDIOPENDESC structure is assumed to be the address of a callback function.
CALLBACK_THREAD | If this flag is specified, dwCallback in the MIDIOPENDESC structure is assumed to be a handle to a thread.
CALLBACK_WINDOW | If this flag is specified, dwCallback in the MIDIOPENDESC structure is assumed to be a window handle.

It is up to the driver to determine the number of clients allowed to use a particular device. Once a device is opened for the maximum number of clients the driver supports, the driver should return MMSYSERR_ALLOCATED for any additional open requests. If the open operation is successful, the driver should use the DriverCallback function to send the client a MIM_OPEN message.

See Also

MIDIOPENDESC, MIDM_CLOSE


MIDM_PREPARE

Sent to a MIDI input device driver to request the driver to prepare a system-exclusive data buffer for input. If data buffers are accessed at interrupt time, they must be page locked to ensure that the memory is not swapped out to disk.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The driver does not support this message.

DWORD dwParam1
Specifies a far pointer to MIDIHDR structure identifying the data block.
DWORD dwParam2
Specifies the size of the MIDIHDR structure.

Driver support for this message is optional. If a driver supports this message, then it must also support MODM_UNPREPARE.

The default response for this message is to return MMSYSERR_NOTSUPPORTED. In this case, MMSYSTEM will page lock the memory for the driver. If a driver requires other operations to prepare a data buffer for input, it should set the MHDR_PREPARED bit in the dwFlags field of the MIDIHDR structure and return MMSYSERR_NOERROR. In this case, MMSYSTEM assumes the driver has prepared the data buffer and does not page lock the memory.

See Also

MIDM_UNPREPARE


MIDM_PROPERTIES

Sent to a MIDI input device driver to change properties of the input stream.

  • Returns zero if the operation is successful. Otherwise, it returns an error number. Possible error values include the following:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_INVALPARAM | The property or property value was invalid.

dwParam1
Contains a far pointer to a structure containing information about the stream.
dwParam2
Contains flags specifying the operation and property.
MIDIPROP_SET | Tells the driver to set the given property.
MIDIPROP_GET | Tells the driver to read the given property.

For a description of the stream properties, see the documentation for the midiStreamProperties function, and the MIDIPROPTIMEDIV, MIDIPROPTEMPO, and MIDIPROPCBTIMEOUT structures in the MIDI SDK documentation


MIDM_RESET

Sent to MIDI input device drivers to stop recording and return all buffers in the input queue to the client.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

DWORD dwParam1
Unused.
DWORD dwParam2
Unused.

The driver should stop recording and set the MHDR_DONE bit and clear the MHDR_INQUEUE bit in the dwFlags field of the MIDIHDR structure for each buffer in the input queue. It should also be sure the dwBytesRecorded field contains the number of bytes recorded for each buffer. The driver should then notify the client by using DriverCallback to send a MIM_LONGDATA message for each buffer.

If a buffer in the input queue contains system-exclusive data but the buffer is incomplete, the driver should follow the same procedure outlined in the preceding paragraph (including setting the dwBytesRecorded field), but should return the buffer to the client using the MIM_LONGERROR message, not MIM_LONGDATA.

See Also

MIDM_STOP


MIDM_START

Sent to a MIDI input driver to begin MIDI input.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

DWORD dwParam1
Unused.
DWORD dwParam2
Unused.

This message should reset the time stamp to zero. If this message is received after input has been started, the driver should just return MMSYSERR_NOERROR.


MIDM_STOP

Sent to a MIDI input device driver to end recording of incoming MIDI data.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

DWORD dwParam1
Unused.
DWORD dwParam2
Unused.

If there is a buffer in the input queue that contains any system-exclusive data, the driver should set the MHDR_DONE bit and clear the MHDR_INQUEUE bit in the dwFlags field of the MIDIHDR structure identifying the buffer. It should then record the number of actual bytes recorded in the dwBytesRecorded field and return the buffer to the client by sending a MIM_LONGDATA message with the DriverCallback function. Any empty buffers should remain in the queue.

If a buffer in the input queue contains system-exclusive data but the buffer is incomplete, the driver should follow the same procedure outlined in the preceding paragraph (including setting the dwBytesRecorded field), but should return the buffer to the client using the MIM_LONGERROR message, not MIM_LONGDATA.

If this message is received and recording is already stopped, the driver should return MMSYSERR_NOERROR.


MIDM_UNPREPARE

Sent to a MIDI input device to clean up the preparation performed by the MIDM_PREPARE message.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

DWORD dwParam1
Specifies a far pointer to MIDIHDR structure identifying the data buffer.
DWORD dwParam2
Specifies the size of the MIDIHDR structure.

Driver support for this message is optional. If a driver supports the MIDM_PREPARE message, then it must also support MIDM_UNPREPARE.

The default response for this message is to return MMSYSERR_NOTSUPPORTED. In this case, MMSYSTEM will clean up the preparation previously done on the memory buffer. If a driver performs the preparation itself, it must clean up the preparation and reset the MHDR_PREPARED flag in the dwFlags field of the MIDIHDR structure.

See Also

MIDM_PREPARE


MIM_CLOSE

Sent by a MIDI input driver to a client application when a MIDI input device is closed.

  • There is no return value.
DWORD dwParam1
Not used.
DWORD dwParam2
Not used.


MIM_DATA

Sent by a MIDI input driver to a client application when a MIDI event other than a system-exclusive event is received by the device.

  • There is no return value.
DWORD dwParam1
Specifies the MIDI data that was received. The message is packed into a DWORD with the first byte of the message in the low-order byte.
DWORD dwParam2
Specifies the time that the message was received by the input device driver. The time stamp is specified in milliseconds, beginning at zero when the driver received the MIDM_START message.

The driver should generate a status byte for events received with running status.

See Also

MIM_LONGDATA


MIM_ERROR

Sent by a MIDI input driver to a client application when an invalid MIDI event is received.

  • There is no return value.
DWORD dwParam1
Specifies the invalid MIDI data that was received. The message is packed into a DWORD with the first byte of the message in the low-order byte. Unused bytes should be set to zero.
DWORD dwParam2
Specifies the time that the message was received by the input device driver. The time stamp is specified in milliseconds, beginning at zero when the driver received the MIDM_START message.

See Also

MIM_LONGERROR


MIM_LONGDATA

Sent by a MIDI input driver to a client application to return a system-exclusive input buffer to the application.

  • There is no return value.
DWORD dwParam1
Specifies a far pointer to a MIDIHDR structure identifying the input buffer.
DWORD dwParam2
Specifies the time that the data was received by the input device driver. The time stamp is specified in milliseconds, beginning at zero when the driver received the MIM_START message.

See Also

MIM_DATA


MIM_LONGERROR

Sent by a MIDI input driver to a client application when an invalid MIDI system-exclusive event is received.

  • There is no return value.
DWORD dwParam1
Specifies a pointer to a MIDIHDR structure identifying the buffer containing the invalid data.
DWORD dwParam2
Specifies the time that the data was received by the input device driver. The time stamp is specified in milliseconds, beginning at zero when the driver received the MIDM_START message.


MIM_OPEN

Sent by a MIDI input driver to a client application when a MIDI input device is opened.

  • There is no return value.
DWORD dwParam1
Not used.
DWORD dwParam2
Not used.


MODM_CACHEDRUMPATCHES

Sent to a MIDI output driver to request that it cache or uncache the specified drum keys. This allows internal synthesizer drivers to load the patches needed by a client application.

  • Returns zero if the operation is successful. Otherwise, it returns an error number. Possible error values include the following:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | Function is not supported.

dwParam1
Specifies a far pointer to a KEYARRAY array indicating which patches should be cached or uncached.
dwParam2
The high-order word specifies which bank of patches the array is referring to. The low-order word specifies whether the patches should be cached or uncached according to one of the following flags:
MIDI_CACHE_ALL | All patches specified in the array should be cached. If the synthesizer cannot cache all the patches, it should cache none at all, clear the KEYARRAY and return MMSYSERR_NOMEM.
MIDI_CACHE_BESTFIT | If the driver can cache all of the patches specified in the array, it should do so. Otherwise, it should cache as many as it can (selection of which patches to cache is at the discretion of the driver), alter the KEYARRAY to reflect what it has actually cached, and return MMSYSERR_NOMEM.
MIDI_CACHE_QUERY | The KEYARRAY should be changed to reflect which patches the driver actually has cached.
MIDI_UNCACHE | Patches specified in the array should be uncached and the KEYARRAY should be cleared.

Only drivers for internal synthesizer devices can support patch caching. Drivers for MIDI output ports should return a MMSYSERR_NOTSUPPORTED error for this message. Support for patch caching is optional for internal synthesizer devices. When a driver receives a MODM_GETDEVCAPS message, it should indicate support for patch caching by setting or clearing the MIDICAPS_CACHE bit in the dwSupport field of the MIDIOUTCAPS data structure.


MODM_CACHEPATCHES

Sent to a MIDI output driver to request that it cache or uncache the specified patches. This allows internal synthesizer drivers to load the patches needed by a client application.

  • Returns zero if the operation is successful. Otherwise, it returns an error number. Possible error values include the following:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | Function is not supported.

dwParam1
Specifies a far pointer to a PATCHARRAY array indicating which patches should be cached or uncached.
dwParam2
The high-order word specifies which bank of patches the array is referring to. The low-order word specifies whether the patches should be cached or uncached according to one of the following flags:
MIDI_CACHE_ALL | All patches specified in the array should be cached. If the synthesizer cannot cache all the patches, it should cache none at all, clear the PATCHARRAY and return MMSYSERR_NOMEM.
MIDI_CACHE_BESTFIT | If the driver can cache all of the patches specified in the array, it should do so. Otherwise, it should cache as many as it can (selection of which patches to cache is at the discretion of the driver), alter the PATCHARRAY to reflect what it has actually cached, and return MMSYSERR_NOMEM.
MIDI_CACHE_QUERY | The PATCHARRAY should be changed to reflect which patches the driver actually has cached.
MIDI_UNCACHE | Patches specified in the array should be uncached and the PATCHARRAY should be cleared.

Only drivers for internal synthesizer devices can support patch caching. Drivers for MIDI output ports should return a MMSYSERR_NOTSUPPORTED error for this message. Support for patch caching is optional for internal synthesizer devices. When a driver receives a MODM_GETDEVCAPS message, it should indicate support for patch caching by setting or clearing the MIDICAPS_CACHE bit in the dwSupport field of the MIDIOUTCAPS data structure.


MODM_CLOSE

Sent to a MIDI output device driver to deallocate a specified device.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MIDIERR_STILLPLAYING | There are still buffers in the queue.

DWORD dwParam1
Unused.
DWORD dwParam2
Unused.

If there are output buffers that have been received with the MODM_LONGDATA message and have not been returned to the application, the driver should fail the close operation by returning a MIDIERR_STILLPLAYING error. If the close operation is successful, the driver should use the DriverCallback function to send the client a MOM_CLOSE message.

See Also

MODM_OPEN


MODM_DATA

Sent to a MIDI output device driver to output a single MIDI event.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MIDIERR_NOTREADY | The MIDI hardware is busy with other data.

DWORD dwParam1
Specifies the MIDI event. The low-order byte is the first byte of the event.
DWORD dwParam2
Unused.

This message is used to output all MIDI events, except system-exclusive events. System-exclusive events are output with the MODM_LONGDATA message. MIDI events output with MODM_DATA can be either one, two, or three bytes long. The driver must parse the event to determine how many bytes to output. Unused bytes are not guaranteed to be zero.

The driver can choose not to return until the message has been sent to the output device, or the driver can return immediately and output the MIDI data in the background.

See Also

MODM_LONGDATA


MODM_GETDEVCAPS

Sent to a MIDI output driver to request the capabilities of a specific MIDI output device.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

DWORD dwParam1
For Plug and Play drivers, specifies a pointer to an MDEVICECAPSEX structure. The driver fills this structure with the capabilities of the device.

For non-Plug and Play drivers, specifies a far pointer to a MIDIOUTCAPS data structure. The driver fills this structure with the capabilities of the device.

DWORD dwParam2
For Plug and Play drivers, specifies a device node.

For non-Plug and Play drivers, specifies the size of the MIDIOUTCAPS structure in bytes.

For non-Plug and Play drivers, the driver should only write dwParam2 or less bytes to the location pointed to by dwParam1.


MODM_GETNUMDEVS

Sent to a MIDI output device driver to request the number of MIDI output devices available.

  • Returns the number of output devices the driver supports.
DWORD dwParam1
Unused.
DWORD dwParam2
Unused.

Drivers can be structured in several ways. The simplest and most common drivers will use one physical device to support one logical device. Drivers can also support multiple logical devices using a single physical device. For example, it can use a single DSP to support two different types of internal synthesizers. Such a driver would return a value of 2 for this message.


MODM_GETPOS

Requests that the driver return its current position in a stream of data.

  • Returns zero if the operation is successful. Otherwise, it returns an error number. Possible error values include the following:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

dwParam1
Specifies a far pointer to an MMTIME structure (cast to a DWORD).
dwParam2
Specifies the size, in bytes, of the MMTIME structure.

The driver should return the position in the time format specified in the wType member of MMTIME. If the time format specified in wType is not supported, the driver should change wType to the default time format and return the position in that format.

Time is measured relative to the start of the first buffer that was sent in the last stopped state. The stopped state is entered whenever a MODM_OPEN, MODM_RESET, or MODM_STOP message is received. Time spent between a MODM_PAUSE and the matching MODM_RESTART is not counted, but the clock should not be reset. Likewise, time while starved for data should not be counted; the returned time should be as if the stream played perfectly with no interruptions or pauses.

The time returned if the device is paused or starved should be the time of the last event played.


MODM_GETVOLUME

Sent to a MIDI output device driver to request the current volume level setting for a device.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The driver does not support changes to volume level.

DWORD dwParam1
Specifies a far pointer to a DWORD location. The driver fills this location with the current volume level setting. The high-order word contains the right channel setting

and the low-order word contains the left channel setting. A value of zero is silence, and a value of 0xFFFF is full volume. If the driver does not support both left and right channel volume changes, it returns the volume in the low-order word.

DWORD dwParam2
Unused.

Only drivers for internal synthesizer devices can support volume level changes. Drivers for MIDI output ports should return a MMSYSERR_NOTSUPPORTED error for this message. Support for volume level changes by internal synthesizer devices is optional. However, if a driver supports changes to the volume level with the MODM_SETVOLUME message, it must support queries with the MODM_GETVOLUME message.

See Also

MODM_SETVOLUME


MODM_LONGDATA

Sent to a MIDI output device driver to output a MIDI data block containing one or more MIDI events, including system-exclusive events. If the data block contains more than one MIDI event, the events are packed into the data block with no padding.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MIDIERR_UNPREPARED | The data block has not been prepared.
MIDIERR_NOTREADY | The hardware is busy with other data.

DWORD dwParam1
Specifies a far pointer to MIDIHDR data structure identifying the data block.
DWORD dwParam2
Specifies the size of the MIDIHDR structure.

The driver should first check the MHDR_PREPARED bit in the dwFlags field of the MIDIHDR structure. If the bit is not set, the driver should return MIDIERR_UNPREPARED. The driver should clear the MHDR_DONE bit and set the MHDR_INQUEUE bit and place the data block in its output queue. Then the driver should return control to the client by returning MMSYSERR_NOERROR.

Once the data block has been output, the driver should set the MHDR_DONE bit and clear the MHDR_INQUEUE bit before notifying the client by using DriverCallback to send a MOM_DONE message.

The driver can choose not to return until the message has been sent to the output device, or the driver can return immediately and output the MIDI data in the background. The driver should maintain MIDI status across multiple MODM_DATA and MODM_LONGDATA calls.

See Also

MODM_DATA


MODM_OPEN

Sent to a MIDI output driver to allocate a specified device for use by a client application.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_ALLOCATED | The device is already allocated by the maximum number of clients the driver supports or the device cannot be opened because of system resource limitations other than memory.
MMSYSERR_NOMEM | The device cannot be opened because of a failure allocating or locking memory.

DWORD dwParam1
Specifies a far pointer to a MIDIOPENDESC structure. This structure contains additional information for the driver such as instance data from the client and a callback for the client.
DWORD dwParam2
Specifies option flags for opening the device.
CALLBACK_EVENT | If this flag is specified, dwCallback in the MIDIOPENDESC structure is assumed to be an event handle.
CALLBACK_FUNCTION | If this flag is specified, dwCallback in the MIDIOPENDESC structure is assumed to be the address of a callback function.
CALLBACK_THREAD | If this flag is specified, dwCallback in the MIDIOPENDESC structure is assumed to be a handle to a thread.
CALLBACK_WINDOW | If this flag is specified, dwCallback in the MIDIOPENDESC structure is assumed to be a window handle.
MIDI_IO_COOKED | If this flag is specified, the device is being opened in stream mode. In stream mode, the driver may receive all Windows 3.1 messages as well as the stream messages. The device driver must be able to handle any contingencies which arise; for example, it must be able to play short messages and system exclusive messages asynchronously to the stream.
MIDI_IO_PACKED | If this flag is specified, the driver is being opened in compatibility mode. (Compatibility mode is supported for applications written for the Windows 3.1 platform).

It is up to the driver to determine the number of clients allowed to use a particular device. Once a device is opened for the maximum number of clients the driver supports, the driver should return MMSYSERR_ALLOCATED for any additional open requests. If the open operation is successful, the driver should use the DriverCallback function to send the client a MOM_OPEN message.

See Also

MODM_CLOSE, MIDIOPENDESC


MODM_PAUSE

Sent to a MIDI output device driver to temporarily pause output. Playback of streams stops but no buffers are marked as done.

  • Returns zero if the operation is successful. Otherwise, it returns an error number. Possible error values include the following:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

dwParam1
Unused.
dwParam2
Unused.

The driver should halt MIDI playback in the current position. The driver should issue note-off messages all notes that are currently on.


MODM_PREPARE

Sent to a MIDI output device driver to request the driver to prepare a system-exclusive data block for output. If data blocks are accessed at interrupt time, they must be page locked to ensure that the memory is not swapped out to disk.

  • If successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The driver does not support this message.

DWORD dwParam1
Specifies a far pointer to MIDIHDR structure identifying the data block.
DWORD dwParam2
Specifies the size of the MIDIHDR structure.

Driver support for this message is optional. If a driver supports this message, then it must also support MODM_UNPREPARE.

The default response for this message is to return MMSYSERR_NOTSUPPORTED. In this case, MMSYSTEM will page lock the memory for the driver. If a driver requires other operations to prepare a data block for output, it should set the MHDR_PREPARED bit in the dwFlags field of the MIDIHDR structure and return MMSYSERR_NOERROR. In this case, MMSYSTEM assumes the driver has prepared the data block and does not page lock the memory.

See Also

MODM_UNPREPARE


MODM_PROPERTIES

Sent to a MIDI output device driver to change properties of the output stream.

  • Returns zero if the operation is successful. Otherwise, it returns an error number. Possible error values include the following:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_INVALPARAM | The property or property value was invalid.

dwParam1
Contains a far pointer to a structure containing information about the stream.
dwParam2
Contains flags specifying the operation and property. The property flags are set in the low 30 bits of the value. These property bits are combined with one of the following, using the logical OR operator:
MIDIPROP_SET | Tells the driver to set the given property.
MIDIPROP_GET | Tells the driver to read the given property.

For a description of the stream properties, see the documentation for the midiStreamProperties function, and the MIDIPROPTIMEDIV, MIDIPROPTEMPO, and MIDIPROPCBTIMEOUT structures in the MIDI SDK documentation

See Also

MODM_UNPREPARE


MODM_RESET

Sent to a MIDI output device driver to stop output from the output queue and to turn off any notes that are playing.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

DWORD dwParam1
Unused.
DWORD dwParam2
Unused.

If the driver's output queue is not empty, it should stop and mark all pending data blocks as done by setting the MHDR_DONE bit in the dwFlags field of the MIDIHDR structure for each block. The driver should then notify the client by using DriverCallback to send a MOM_DONE message for each data block.

If the device is an output port, the driver should send a MIDI note-off event for all 128 notes on all 16 channels. Optionally, the driver can keep track of which notes are turned on and send note-off events only for those notes. In addition, the driver should send a damper pedal off event (controller 0x40) for each channel. If the device is an internal synthesizer, the driver should turn off any notes that are playing.


MODM_RESTART

Sent to a MIDI output device driver to restart playback after a MODM_PAUSE.

  • Returns zero if the operation is successful. Otherwise, it returns an error number. Possible error values include the following:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

dwParam1
Unused.
dwParam2
Unused.

The driver should resart MIDI playback at the current position.

MODM_PAUSE/MODM_RESTART pairs cannot be nested. MODM_PAUSE messages received while already in the paused state should be ignored; playback will start on the first MODM_RESTART message received regardless of how many MODM_PAUSE messages where received. Likewise, MODM_RESTART messages received while already playing should be ignored. MMSYSERR_NOERROR should be returned in either case.


MODM_SETVOLUME

Sent to a MIDI output device driver to set the volume for a device.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The driver does not support changes to volume level.

DWORD dwParam1
Specifies the new volume level. The high-order word contains the right channel setting and the low-order word contains the left channel setting. A value of zero is silence, and a value of 0xFFFF is full volume. If the driver does not support both left and right channel volume changes, it uses the volume specified in the low-order word. The driver will probably not support the full 16 bits of volume control and should truncate the lower bits if necessary. However, the original value requested with MODM_SETVOLUME should be returned with MODM_GETVOLUME.
DWORD dwParam2
Unused.

This volume message is not the same as the MIDI volume controller message which will be used by sequencers and the mapper. This volume is the final output volume on the card; therefore, only drivers for internal synthesizer devices can support volume level changes. Drivers for MIDI output ports should return a MMSYSERR_NOTSUPPORTED error for this message. Support for volume level changes is optional for internal synthesizer devices. When a driver receives a MODM_GETDEVCAPS message, it should indicate support for volume level changes by setting or clearing the MIDICAPS_VOLUME and MIDICAPS_LRVOLUME bits in the dwSupport field of the MIDIOUTCAPS data structure. If a driver supports the MODM_SETVOLUME message, then it must also support MODM_GETVOLUME.

See Also

MODM_GETVOLUME


MODM_STOP

Sent to a MIDI output device driver to stop output from the output queue and to turn off any notes that can be playing.

  • Returns zero if the operation is successful. Otherwise, it returns an error number. Possible error values include the following:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

dwParam1
Unused.
dwParam2
Unused.

If the driver's output queue is not empty, it should stop and mark all pending data blocks as done by setting the MHDR_DONE bit in the dwFlags field of the MIDIHDR structure for each block. The driver should then notify the client by using DriverCallback to send a MOM_DONE message for each data block.

The driver should send a note off for all notes which are currently turned on. In addition, the driver should send a damper pedal off event (controller 0x40) for each channel. If the device is an internal synthesizer, the driver should turn off any notes playing.


MODM_STRMDATA

Sent to a MIDI output device to send stream data.

DWORD dwParam1
Specifies a far pointer to MIDIHDR structure containing data in the stream buffer format.
DWORD dwParam2
Specifies the size, in bytes, of the MIDIHDR structure.

The dwStreamID member of the MIDIEVENT structure is documented as reserved in the SDK documentation. This member actually contains the destination of the given event. The device driver should process the event only if dwStreamID either matches one of the stream identifiers given in the array specified by the rgIds member of the MIDIOPENDESC structure (specified in the MODM_OPEN message), or if it contains a -1 (0xFFFFFFFFL).

If dwStreamID matches a relevant stream identifier from rgIds, the driver should process the event on the port which the stream identifier was bound to by means of a device identifier in the MODM_OPEN message.

If dwStreamID contains a -1, the driver should process the event for all ports which are open on this stream.


MODM_UNPREPARE

Sent to a MIDI output device to clean up the preparation performed by the MODM_PREPARE message.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

DWORD dwParam1
Specifies a far pointer to MIDIHDR structure identifying the data block.
DWORD dwParam2
Specifies the size of the MIDIHDR structure.

Driver support for this message is optional. If a driver supports the MODM_PREPARE message, then it must also support MODM_UNPREPARE.

The default response for this message is to return MMSYSERR_NOTSUPPORTED. In this case, MMSYSTEM will clean up the preparation previously done on the memory block. If a driver performs the preparation itself, it must clean up the preparation and reset the MHDR_PREPARED flag in the dwFlags field of the MIDIHDR structure.

See Also

MODM_PREPARE


MOM_CLOSE

Sent by a MIDI output driver to a client application when a MIDI output device is closed.

  • There is no return value.
DWORD dwParam1
Not used.
DWORD dwParam2
Not used.


MOM_DONE

Sent by a MIDI output driver to a client application to return a system-exclusive data block to the application.

  • There is no return value.
DWORD dwParam1
Specifies a far pointer to a MIDIHDR structure identifying the data block.
DWORD dwParam2
Not used.


MOM_OPEN

Sent by a MIDI output driver to a client application when a MIDI output device is opened.

  • There is no return value.
DWORD dwParam1
Not used.
DWORD dwParam2
Not used.


MXDM_CLOSE

Sent to an audio mixer device driver to deallocate a specified open instance. This message is normally sent to an audio mixer driver in response to a mixerClose call.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. A mixer driver should never fail the MXDM_CLOSE message.
dwParam1
Unused.
dwParam2
Unused.

An audio mixer driver must support this message. Note that the MXDM_CLOSE message will only be sent to a mixer driver if the corresponding MXDM_OPEN message succeeded.


MXDM_GETCONTROLDETAILS

Sent to an audio mixer device driver to get the state of one or more items for a control. This message is normally sent to an audio mixer driver in response to a mixerGetControlDetails call.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MIXERR_INVALCONTROL | The audio mixer device control reference is invalid.
MIXERR_INVALLINE | The audio mixer device line reference is invalid.
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The specified query type is not supported by the driver.

dwParam1
Specifies a pointer to a MIXERCONTROLDETAILS structure, which in turn references one or more MIXERCONTROL structures containing the control details.
dwParam2
Specifies flags for getting the line control details. This argument is identical to the fdwDetails argument passed to the mixerGetControlDetails function. For additional information about the flag settings, see the mixerGetControlDetails function listed in the SDK documentation.

An audio mixer driver must support this message. The Mixer Manager will validate the following parameters for the MXDM_GETCONTROLDETAILS message before calling the driver. Your driver does not need to check for the following conditions:

  1. dwParam1 contains a valid pointer to a MIXERCONTROLDETAILS structure. This structure will be at least large enough to hold the base MIXERCONTROLDETAILS structure members. This buffer has also been validated to insure it is big enough to hold at least cbStruct bytes of information.
  2. All members of the MIXERCONTROLDETAILS structure have been validated to contain proper structure sizes and a valid pointer to one or more mixer control details structures.
  3. dwParam2 will be a valid combination of flags.

A mixer driver should validate the control identifier and should verify that the size of the details buffer for a custom mixer control is correct.

A mixer driver should verify that the cChannels member of the MIXERCONTROLDETAILS structure is correct for the control. This member must be zero for custom mixer controls and nonzero for standard mixer controls.

If the calling application specifies cChannels equal to one for a multi-channel control, the driver must combine the channel values into one value using the following rules:

MIXERCONTROL_CT_CLASS_CUSTOM | This class of mixer controls cannot be coalesced; cChannels must always be zero.
MIXERCONTROL_CT_CLASS_FADER | This class of mixer controls should use the largest absolute value of all channels as the return value.
MIXERCONTROL_CT_CLASS_LIST | This class of mixer controls should logically or all values of all channels as the return value. For single selection lists, the left channel information should be returned.
MIXERCONTROL_CT_CLASS_METER | This class of mixer controls should use the largest absolute value of all channels as the return value.
MIXERCONTROL_CT_CLASS_NUMBER | This class of mixer controls should use the largest absolute value of all channels as the return value.
MIXERCONTROL_CT_CLASS_SLIDER | This class of mixer controls should use the largest absolute value of all channels as the return value.
MIXERCONTROL_CT_CLASS_SWITCH | This class of mixer controls should logically OR all values of all channels as the return value.
MIXERCONTROL_CT_CLASS_TIME | This class of mixer controls should use the largest absolute value of all channels as the return value.

A mixer driver should verify that the cMultipleItems member of the MIXERCONTROLDETAILS structure is correct for the control. It is invalid to specify any number for cMultipleItems other than the value given in the cMultipleItems member of the MIXERCONTROL structure.

An application can generate two types of queries for a mixer control's details. A driver must use the bitwise AND operator with dwParam2 and the MIXER_GETCONTROLDETAILSF_QUERYMASK constant to obtain the query type.

  • If the result matches the MIXER_GETCONTROLDETAILSF_VALUE constant, the query is a request for the control's current value.
  • If the result matches the MIXER_GETCONTROLDETAILSF_LISTTEXT constant, the request is to get the list text and instance data for list or banded controls.

All mixer drivers must support these queries. If a query other than the above list is sent that the mixer device does not know how to handle, MMSYSERR_NOTSUPPORTED must be returned.


MXDM_GETDEVCAPS

Sent to an audio mixer device driver to request the capabilities of a specific mixer device. This message is normally sent to an audio mixer driver in response to a mixerGetDevCaps call.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

dwParam1
For Plug and Play drivers, specifies a pointer to an MDEVICECAPSEX structure. The driver fills this structure with the capabilities of the device.

For non-Plug and Play drivers, specifies a pointer to a MIXERCAPS data structure. The driver fills this structure with the capabilities of the device.

dwParam2
For Plug and Play drivers, specifies a device node.

For non-Plug and Play drivers, specifies the size, in bytes, of the MIXERCAPS data structure.

For non-Plug and Play drivers, the driver should only write dwParam2 or less bytes to the location pointed to by dwParam1. If dwParam2 is zero, write nothing and return MMSYSERR_NOERROR. The Mixer Manager handles this case for your driver.

An audio mixer driver must support this message. The Mixer Manager will validate the following parameters for the MXDM_GETDEVCAPS message before calling the driver. Your driver does not need to check for the following conditions:

  1. dwParam1 contains a valid pointer to a MIXERCAPS. This structure will be at least large enough to hold the specified number of bytes passed in dwParam2.
  2. dwParam2 must be nonzero. If the caller requests zero bytes of mixer device capabilities, the mixer manager handles this case for your driver.


MXDM_GETLINECONTROLS

Sent to an audio mixer device driver to get one or all controls associated with the specified line. This message is normally sent to an audio mixer driver in response to a mixerGetLineControls call.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MIXERR_INVALLINE | The audio mixer device line reference is invalid.
MIXERR_INVALCONTROL | The audio mixer device control reference is invalid.

dwParam1
Specifies a pointer to a MIXERLINECONTROLS structure that references the MIXERCONTROL structures to receive the line controls information being requested.
dwParam2
Specifies flags for getting the line controls information. This argument is identical to the fdwControls argument passed to the mixerGetLineControls function. For additional information about the flag settings, see the mixerGetLineControls function listed in the SDK documentation.

An audio mixer driver must support this message. The Mixer Manager will validate the following parameters for the MXDM_GETLINECONTROLS message before calling the driver. Your driver does not need to check for the following conditions:

  1. dwParam1 will contain a valid pointer to a MIXERLINECONTROLS structure. This structure will be at least large enough to hold the base MIXERLINECONTROLS structure members. This buffer has also been validated to insure it is big enough to hold at least cbStruct bytes of information.
  2. All members of the MIXERLINECONTROLS structure have been validated to contain proper structure sizes and a valid pointer to one or more MIXERCONTROL structures.
  3. dwParam2 will be a valid combination of flags.

A mixer device driver must validate the dwControlID, dwLineID and dwControlType members of the MIXERLINECONTROLS structure if they apply to the query type being requested. The driver must also verify that the cControls member is valid for the MIXER_GETLINECONTROLSF_ALL query. The other two query types MIXER_GETLINECONTROLSF_ONEBYID and MIXER_GETLINECONTROLSF_ONEBYTYPE will cause the mixer manager to validate the cControls member to be one.

An application can generate three types of queries for a mixer line control. A driver must use the bitwise AND operator with dwParam2 and the MIXER_GETLINECONTROLSF_QUERYMASK constant to obtain the query type.

  • If the result matches the MIXER_GETLINECONTROLSF_ALL constant, the query is a request for all controls associated with the specified line (dwLineID).
  • If the result matches the MIXER_GETLINECONTROLSF_ONEBYID constant, the request is to retrieve the control specified in dwControlID.
  • If the result matches the MIXER_GETLINECONTROLSF_ONEBYTYPE constant, the query is a request for the first control on the specified line (dwLineID) that matches the type specified in dwControlType..

All mixer drivers must support these queries. If a query other than those previously mentioned is sent, the mixer driver must return MMSYSERR_NOTSUPPORTED.


MXDM_GETLINEINFO

Sent to an audio mixer device driver to get information on the specified line. This message is normally sent to an audio mixer driver in response to a mixerGetLineInfo call.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MIXERR_INVALLINE | The audio mixer device line reference is invalid.

dwParam1
Specifies a pointer to a MIXERLINE structure that is to receive the line information being requested.
dwParam2
Specifies flags for getting the line information. This argument is identical to the fdwInfo argument passed to the mixerGetLineInfo function. Refer to the description for mixerGetLineInfo for specific flag information.

An audio mixer driver must support this message. The Mixer Manager will validate the following parameters for the MXDM_GETLINEINFO message before calling the driver. Your driver does not need to check for the following conditions:

  1. dwParam1 will contain a valid pointer to a MIXERLINE structure. This structure will be at least large enough to hold the base MIXERLINE structure members. This buffer has also been validated to insure it is big enough to hold at least cbStruct bytes of information.
  2. dwParam2 will be a valid combination of flags.

A mixer device driver must validate the dwDestination, dwSource and dwLineID members of the MIXERLINE structure when they apply to the query request. The driver must also verify that the dwComponentType and Target structure members are valid for the MIXER_GETLINEINFOF_COMPONENTTYPE and MIXER_GETLINEINFOF_TARGETTYPE queries.

An application can generate the following queries for retrieving mixer line information. A driver must use the bitwise AND operator with dwParam2 and the MIXER_GETLINEINFOF_QUERYMASK constant to obtain the query type.

  • If the result matches the MIXER_GETLINEINFOF_DESTINATION constant, the query requests information about the destination line specified by MIXERLINE.dwDestination.
  • If the result matches the MIXER_GETLINEINFOF_SOURCE constant, the query requests information about the source line (specified by MIXERLINE.dwSource) associated with the destination line specified by MIXERLINE.dwDestination.
  • If the result matches the MIXER_GETLINEINFOF_LINEID constant, the query requests information about the line specified by MIXERLINE.dwLineID.
  • If the result matches the MIXER_GETLINEINFOF_COMPONENTTYPE constant, the query requests information about the first component of the specified type (MIXERLINE.dwComponentType) on the specific line.
  • If the result matches the MIXER_GETLINEINFOF_TARGETTYPE constant, the query requests information for a line that matches the specified audio line type in MIXERLINE.Target.dwType. For example, if the value of MIXERLINE.Target.dwType is wPid, the query would search for a wave input audio line.

All mixer drivers must support these queries. If a query other than those previously mentioned is sent, the mixer driver must return MMSYSERR_NOTSUPPORTED.


MXDM_GETNUMDEVS

Sent to an audio mixer device driver to request the number of mixer devices available through the mixer driver. This message is normally sent once after the driver has been booted and enabled by the mixer manager. The number of available devices returned for the MXDM_GETNUMDEVS message is added to the total number of mixer devices available in the system. It is this total value that is returned to an application that calls mixerGetNumDevs.

  • Returns the number of audio mixer devices the driver supports. If the driver fails to enable for any reason, the return value should be zero to indicate no devices are available.
dwParam1
Unused.
dwParam2
Unused.

Audio mixer drivers can be structured in several ways. The simplest and most common drivers will use one physical device to support one logical device. Drivers can also support multiple logical devices using a single physical device. For example, some audio cards allow more than one card to be installed in a single machine. If the device driver can simultaneously support more than one card, the driver should return the number of physical cards that are currently available.

The value returned by a mixer driver for the number of devices it supports cannot exceed MAXMIXERDRIVERS. Also note that the total number of mixer devices returned by all mixer drivers cannot exceed this same value.


MXDM_INIT

Sent to an audio mixer device driver after all mixer drivers have been loaded and enabled by the audio mixer manager. A mixer driver may use this message to inform the user of configuration problems (it is sent only once to each mixer device).

  • An audio mixer device should return zero (MMSYSERR_NOERROR) if it processes this message. The MMSYSERR_NOTSUPPORTED error code should be returned if this message is not processed by the device.
dwParam1
Unused.
dwParam2
Unused.


MXDM_OPEN

Sent to an audio mixer device driver to allocate a specified device for use by a client application. This message is normally sent to an audio mixer driver in response to a mixerOpen call. Applications using the audio mixer functions are not required to open a device to use it, but they must do so if they desire line and control notification callbacks.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_ALLOCATED | The device is already allocated by the maximum number of clients the driver supports, or the device cannot be opened because of system resource limitations other than memory.
MMSYSERR_NOMEM | The device cannot be opened because of a failure allocating memory.
MMSYSERR_NOTENABLED | The driver failed to load or initialize.

dwParam1
Specifies a pointer to a MIXEROPENDESC structure. This structure contains additional information for the driver, such as instance data and a callback for the client.
dwParam2
Specifies option flags for opening the device.
CALLBACK_EVENT | Specifies that MIXEROPENDESC.dwCallback is an event handle.
CALLBACK_FUNCTION | Specifies that MIXEROPENDESC.dwCallback is a callback procedure address.
CALLBACK_THREAD | Specifies that MIXEROPENDESC.dwCallback is a thread handle.
CALLBACK_WINDOW | Specifies that MIXEROPENDESC.dwCallback is a window handle.

The driver must determine the number of clients allowed to use a particular device. Once a device is opened for the maximum number of clients that it supports, that driver should return MMSYSERR_ALLOCATED for any additional open requests.

A mixer driver must be written to allow multiple opens on a single device (thus allowing more than one client to receive notifications).

An audio mixer driver must support this message. The Mixer Manager will validate the following parameters for the MXDM_OPEN message before calling the driver. Your driver does not need to check for the following conditions:

  1. dwParam1 will contain a valid pointer to a MIXEROPENDESC structure. This structure will be at least large enough to hold the base MIXEROPENDESC structure members. All members of this structure will be valid.
  2. dwParam2 will be a valid combination of flags.

Note The Mixer Manager might combine several opens and closes from many applications. During debugging, if you notice that only one MXDM_OPEN message gets sent even if more than one application opens the device, the Mixer Manager probably has combined the open requests.


MXDM_SETCONTROLDETAILS

Sent to an audio mixer device driver to set the state of one or more items for a control. This message is normally sent to an audio mixer driver in response to a mixerSetControlDetails call.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MIXERR_INVALCONTROL | The audio mixer device control reference is invalid.
MIXERR_INVALLINE | The audio mixer device line reference is invalid.
MIXERR_INVALVALUE | The value specified for the mixer control is not within the limits for the control.
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The specified query type is not supported by the driver.

dwParam1
Specifies a pointer to a MIXERCONTROLDETAILS structure that references the MIXERCONTROLDETAILS structures to set the controls details to.
dwParam2
Specifies flags for setting the line control details. This argument is identical to the fdwDetails argument passed to the mixerSetControlDetails function. For additional information about the flag settings, see the mixerSetControlDetails function listed in the SDK documentation.

An audio mixer driver must support this message. The Mixer Manager will validate the following parameters for the MXDM_SETCONTROLDETAILS message before calling the driver. Your driver does not need to check for the following conditions:

  1. dwParam1 will contain a valid pointer to a MIXERCONTROLDETAILS structure. This structure will be at least large enough to hold the base MIXERCONTROLDETAILS structure members. This buffer has also been validated to insure it is big enough to hold at least cbStruct bytes of information.
  2. All members of the MIXERCONTROLDETAILS structure have been validated to contain proper structure sizes and a valid pointer to one or more mixer control details structures.
  3. dwParam2 will be a valid combination of flags.
  4. If the request is for MIXER_SETCONTROLDETAILSF_CUSTOM, then the hwndOwner of the MIXERCONTROLDETAILS structure is a valid window handle (which can be NULL) to use as the owner for the custom mixer control's dialog box.

However, a mixer driver should verify the following:

  • The control identifier.
  • The size of the details buffer for a custom mixer control.
  • All control values to insure they are in the correct ranges for the specified control.
  • MIXERCONTROLDETAILS.cChannels. This member must be zero for custom mixer controls. This member must be nonzero for standard mixer controls.
  • If the calling application specifies cChannels equal to one for a multi-channel control, then the driver must set all channel values to the specified single value.
  • MIXERCONTROLDETAILS.cMultipleItems. It is invalid to specify any number for cMultipleItems other than the value given in the cMultipleItems member of the MIXERCONTROL structure.

If the user cancels a custom mixer control dialog, then the mixer driver should return the current state of the mixer control and succeed the call with MMSYSERR_NOERROR.

An application can set details for standard and custom controls. A driver must use the bitwise AND operator with dwParam2 and the MIXER_SETCONTROLDETAILSF_QUERYMASK constant to identify the type of information being set.

  • If the result matches the MIXER_SETCONTROLDETAILSF_VALUE constant, the details for a standard control are set to the specified state.
  • If the result matches the MIXER_SETCONTROLDETAILSF_CUSTOM constant, the details for a customer control are set to the specified state.

All mixer drivers must support these queries. If a query other than those previously mentioned is sent, the mixer driver must return MMSYSERR_NOTSUPPORTED.


WIDM_ADDBUFFER

Sent to a waveform input device driver to add a buffer to the input queue.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
WAVERR_UNPREPARED | The specified data buffer has not been prepared for input.

DWORD dwParam1
Specifies a far pointer to a WAVEHDR data structure identifying the buffer.
DWORD dwParam2
Specifies the size of the WAVEHDR structure.

The driver should first check the WHDR_PREPARED bit in the dwFlags field of the WAVEHDR structure. If the bit is not set, the driver should return WAVERR_UNPREPARED. The driver should clear the WHDR_DONE bit and set the WHDR_INQUEUE bit in the header structure, and place the data block in its play queue. Then the driver should return control to the client by returning MMSYSERR_NOERROR. Input to the buffer should occur as an interrupt-driven process. If data is received without any buffers in the input queue, the data should be ignored without notifying the client.

Recording begins when the driver receives a WIDM_START message. Once the data block has been filled with data, the driver should set the WHDR_DONE bit and clear the WHDR_INQUEUE bit before notifying the client by using DriverCallback to send a WIM_DATA message.


WIDM_CLOSE

Sent to a waveform input device driver to deallocate a specified device.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
WAVERR_STILLPLAYING | There are still buffers in the queue.

DWORD dwParam1
Unused.
DWORD dwParam2
Unused.

If there are input buffers that have not been returned to the application, the driver should fail the close operation by returning a WAVERR_STILLPLAYING error. If the close operation is successful, the driver should use the DriverCallback function to send the client a WIM_CLOSE message.

See Also

WIDM_OPEN


WIDM_GETDEVCAPS

Sent to a waveform input device driver to request the capabilities of a specific waveform input device.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

DWORD dwParam1
For Plug and Play drivers, specifies a pointer to an MDEVICECAPSEX structure. The driver fills this structure with the capabilities of the device.

For non-Plug and Play drivers, specifies a far pointer to a WAVEINCAPS data structure. The driver fills this structure with the capabilities of the device.

DWORD dwParam2
For Plug and Play drivers, specifies a device node.

For non-Plug and Play drivers, specifies the size of the WAVEINCAPS data structure in bytes.

For non-Plug and Play drivers, the driver should only write dwParam2 or less bytes to the location pointed to by dwParam1. If dwParam2 is zero , write nothing and return MMSYSERR_NOERROR.


WIDM_GETNUMDEVS

Sent to a waveform input device driver to request the number of waveform input devices available.

  • Returns the number of input devices the driver supports.
DWORD dwParam1
Unused.
DWORD dwParam2
Unused.


WIDM_GETPOS

Sent to a waveform input device driver to request the current input position for a waveform. The input position is relative to the first recorded sample of the waveform.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

DWORD dwParam1
Specifies a far pointer to an MMTIME structure.
DWORD dwParam2
Specifies the size of the MMTIME structure.

The wType field of the MMTIME structure indicates the time format requested by the client. If the driver cannot support the requested format, it should return the position in a format that it does support, and change the wType field accordingly.


WIDM_OPEN

Sent to a waveform input device driver to allocate a specified device for use by a client application.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_ALLOCATED | The device is already allocated by the maximum number of clients the driver supports, or the device cannot be opened because of system resource limitations other than memory.
MMSYSERR_NOMEM | The device cannot be opened because of a failure allocating or locking memory.
WAVERR_BADFORMAT | The device cannot be opened using the specified data format.

DWORD dwParam1
Specifies a far pointer to a WAVEOPENDESC structure. This structure contains additional information for the driver such as the waveform data format, instance data from the client, and a callback for the client.
DWORD dwParam2
Specifies option flags for opening the device.
WAVE_FORMAT_QUERY | If this flag is specified, the device driver determines if it supports the format specified by lpFormat in the WAVEOPENDESC structure, but does not actually open the device. If the driver supports the requested format, it should return MMSYSERR_NOERROR, otherwise it should return WAVERR_BADFORMAT.
CALLBACK_EVENT | If this flag is specified, dwCallback in the WAVEOPENDESC structure is assumed to be the handle of an event.
CALLBACK_FUNCTION | If this flag is specified, dwCallback in the WAVEOPENDESC structure is assumed to be the address of a callback function.
CALLBACK_THREAD | If this flag is specified, dwCallback in the WAVEOPENDESC structure is assumed to be a handle of a thread.
CALLBACK_WINDOW | If this flag is specified, dwCallback in the WAVEOPENDESC structure is assumed to be a window handle.

It is up to the driver to determine the number of clients allowed to use a particular device. Once a device is opened for the maximum number of clients the driver supports, the driver should return MMSYSERR_ALLOCATED for any additional open requests. If the open operation is successful, the driver should use the DriverCallback function to send the client a WIM_OPEN message.

See Also

WIDM_CLOSE, WAVEOPENDESC


WIDM_PREPARE

Sent to a waveform input device driver to request the driver to prepare a data block for input. If data blocks are accessed at interrupt time, they must be page locked to ensure that the memory is not swapped out to disk.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The driver does not support this message.

DWORD dwParam1
Specifies a far pointer to WAVEHDR structure identifying the data block.
DWORD dwParam2
Specifies the size of the WAVEHDR structure.

Driver support for this message is optional. If a driver supports this message, then it must also support WIDM_UNPREPARE.

The default response for this message is to return MMSYSERR_NOTSUPPORTED. In this case, MMSYSTEM will page lock the memory for the driver. If a driver requires other operations to prepare a data block for playback, it should set the WHDR_PREPARED bit in the dwFlags field of the WAVEHDR structure and return MMSYSERR_NOERROR. In this case, MMSYSTEM assumes the driver has prepared the data block and does not page lock the memory. If a data block has already been prepared, MMSYSERR_NOERROR should be returned.

See Also

WIDM_UNPREPARE


WIDM_RESET

Sent to waveform input device drivers to stop waveform recording and return all buffers in the input queue to the client.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

DWORD dwParam1
Unused.
DWORD dwParam2
Unused.

The driver should stop recording even if in the paused state. It should set the WHDR_DONE bit and clear the WHDR_INQUEUE bit in the dwFlags field of the WAVEHDR structure for each buffer in the input queue. It should also be sure the dwBytesRecorded field contains the number of bytes recorded for each buffer and reset the position count to zero. The driver should then notify the client by using DriverCallback to send a WOM_DONE message for each buffer.

See Also

WIDM_STOP


WIDM_START

Sent to a waveform input device driver to begin waveform recording.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

DWORD dwParam1
Unused.
DWORD dwParam2
Unused.

Buffers are returned to the client either when full or when a WIDM_RESET message is received. The driver should place the actual length of data in the dwBytesRecorded field in the header. If input is already started, just return MMSYSERR_NOERROR.

See Also

WIDM_STOP


WIDM_STOP

Sent to a waveform input device driver to stop waveform recording.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

DWORD dwParam1
Unused.
DWORD dwParam2
Unused.

If the current buffer is partially full, it should be marked as done and returned to the client. Any empty buffers in the queue should remain there. Calling this function when input is not started should have no effect and MMSYSERR_NOERROR should be returned.

See Also

WIDM_START, WIDM_RESET


WIDM_UNPREPARE

Sent to a waveform input device to clean up the preparation performed by the WIDM_PREPARE message.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
WAVERR_STILLPLAYING | The specified data block is still in the input queue.

DWORD dwParam1
Specifies a far pointer to WAVEHDR structure identifying the data block.
DWORD dwParam2
Specifies the size of the WAVEHDR structure.

Driver support for this message is optional. If a driver supports the WIDM_PREPARE message, then it must also support WIDM_UNPREPARE.

The default response for this message is to return MMSYSERR_NOTSUPPORTED. In this case, MMSYSTEM will clean up the preparation previously done on the memory block. If a driver performs the preparation itself, it must clean up the preparation and reset the WHDR_PREPARED flag in the dwFlags field of the WAVEHDR structure. If a data block has not been prepared, MMSYSERR_NOERROR should be returned.

See Also

WIDM_PREPARE


WIM_CLOSE

Sent by a waveform input driver to a client application when a waveform input device is closed.

  • There is no return value.
DWORD dwParam1
Not used.
DWORD dwParam2
Not used.


WIM_DATA

Sent by a waveform input driver to a client application to return an input buffer to the application.

  • There is no return value.
DWORD dwParam1
Specifies a far pointer to a WAVEHDR structure identifying the buffer.
DWORD dwParam2
Not used.


WIM_OPEN

Sent by a waveform input driver to a client application when a waveform input device is opened.

  • There is no return value.
DWORD dwParam1
Not used.
DWORD dwParam2
Not used.


WODM_BREAKLOOP

Sent to a waveform output device to break a playback loop.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

DWORD dwParam1
Unused.
DWORD dwParam2
Unused.

The driver should play to the end of the current iteration of the loop before breaking.

Waveform looping is controlled by the dwLoops and dwFlags fields in the WAVEHDR structures passed to the driver with the WODM_WRITE message. The WHDR_BEGINLOOP and WHDR_ENDLOOP flags in the dwFlags field specify the beginning and ending data blocks for looping. The dwLoops field in the WAVEHDR structure for the first block in the loop specifies the number of loops.

Calling this function when nothing is playing or looping should have no effect and the driver should return MMSYSERR_NOERROR.


WODM_CLOSE

Sent to a waveform output device driver to deallocate a specified device.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
WAVERR_STILLPLAYING | There are still buffers in the queue.

DWORD dwParam1
Unused.
DWORD dwParam2
Unused.

If there are output buffers that have been received with the WODM_WRITE message and have not been returned to the application, the driver should fail the close operation by returning a WAVERR_STILLPLAYING error. If the close operation is successful, the driver should use the DriverCallback function to send the client a WOM_CLOSE message.

See Also

WODM_OPEN


WODM_GETDEVCAPS

Sent to a waveform output device driver to request the capabilities of a specific waveform output device.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

DWORD dwParam1
For Plug and Play drivers, specifies a pointer to an MDEVICECAPSEX structure. The driver fills this structure with the capabilities of the device.

For non-Plug and Play drivers, specifies a far pointer to a WAVEOUTCAPS data structure. The driver fills this structure with the capabilities of the device.

DWORD dwParam2
For Plug and Play drivers, specifies a device node.

For non-Plug and Play drivers, specifies the size of the WAVEOUTCAPS data structure in bytes.

For non-Plug and Play drivers, the driver should only write dwParam2 or less bytes to the location pointed to by dwParam1. If dwParam2 is zero , write nothing and return MMSYSERR_NOERROR.


WODM_GETNUMDEVS

Sent to a waveform output device driver to request the number of waveform output devices available.

  • Returns the number of output devices the driver supports.
DWORD dwParam1
Unused.
DWORD dwParam2
Unused.

Drivers can be structured in several ways. The simplest and most common drivers use one physical device to support one logical device. Drivers can also support multiple logical devices using a single physical device. For example, it can use a single DSP to support playback of both PCM and ADPCM data. Such a driver would return a value of 2 for this message.


WODM_GETPITCH

Sent to a waveform output device driver to request the current pitch rate setting for a device.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The driver does not support changes to the pitch rate.

DWORD dwParam1
Specifies a far pointer to a DWORD location. The driver fills this location with the current pitch rate setting. The rate is specified as a fixed-point value. The high-order word of the DWORD contains the signed integer part of the number, and the low-order word contains the fractional part. The fraction is expressed as a WORD in which a value of 0x8000 represents one half, and 0x4000 represents one quarter. For example, the value 0x00010000 specifies a multiplier of 1.0 (no pitch change), and a value of 0x000F8000 specifies a multiplier of 15.5.
DWORD dwParam2
Unused.

Drivers do not have to support pitch rate changes. However, if a driver supports changes to the pitch rate with the WODM_SETPITCH message, it must support queries with the WODM_GETPITCH message.

See Also

WODM_SETPITCH


WODM_GETPLAYBACKRATE

Sent to a waveform output device driver to request the current playback rate setting for a device.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The driver does not support changes to the pitch rate.

DWORD dwParam1
Specifies a far pointer to a DWORD location. The driver fills this location with the current playback rate setting. The rate is specified as a fixed-point value. The high-order word of the DWORD contains the signed integer part of the number, and the low-order word contains the fractional part. The fraction is expressed as a WORD in which a value of 0x8000 represents one half, and 0x4000 represents one quarter. For example, the value 0x00010000 specifies a multiplier of 1.0 (no playback rate change), and a value of 0x000F8000 specifies a multiplier of 15.5.
DWORD dwParam2
Unused.

Driver support for playback rate changes is optional. However, if a driver supports changes to the playback rate with the WODM_SETPLAYBACKRATE message,

it must support queries with the WODM_GETPLAYBACKRATE message.

See Also

WODM_SETPLAYBACKRATE


WODM_GETPOS

Sent to a waveform output device driver to request the current playback position for a waveform file. The playback position is relative to the beginning of the waveform file and is reset with the WODM_OPEN and WODM_RESET messages.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

DWORD dwParam1
Specifies a far pointer to an MMTIME structure.
DWORD dwParam2
Specifies the size of the MMTIME structure.

The wType field of the MMTIME structure indicates the time format requested by the client. If the driver cannot support the requested format, it should return the position in a format that it does support, and change the wType field accordingly.


WODM_GETVOLUME

Sent to a waveform output device driver to request the current volume level setting for a device.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The driver does not support changes to volume level.

DWORD dwParam1
Specifies a far pointer to a DWORD location. The driver fills this location with the current volume level setting. The high-order word contains the right channel setting and the low-order word contains the left channel setting. A value of zero is silence, and a value of 0xFFFF is full volume. If the driver does not support both left and right channel volume changes, it returns the volume in the low-order word.
DWORD dwParam2
Unused.

Drivers do not have to support volume level changes. However, if a driver supports changes to the volume level with the WODM_SETVOLUME message, it must support queries with the WODM_GETVOLUME message.

See Also

WODM_SETVOLUME


WODM_OPEN

Sent to a waveform output device driver to allocate a specified device for use by a client application.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_ALLOCATED | The device is already allocated by the maximum number of clients the driver supports, or the device cannot be opened because of system resource limitations other than memory.
MMSYSERR_NOMEM | The device cannot be opened because of a failure allocating or locking memory.
WAVERR_BADFORMAT | The device cannot be opened using the specified data format.

DWORD dwParam1
Specifies a far pointer to a WAVEOPENDESC structure. This structure contains additional information for the driver, such as the waveform data format, instance data from the client, and a callback for the client.
DWORD dwParam2
Specifies option flags for opening the device.
WAVE_FORMAT_QUERY | If this flag is specified, the device driver determines if it supports the format specified by lpFormat in the WAVEOPENDESC structure, but does not actually open the device. If the driver supports the requested format it should return MMSYSERR_NOERROR, otherwise it should return WAVERR_BADFORMAT.
CALLBACK_EVENT | If this flag is specified, dwCallback in the WAVEOPENDESC structure is assumed to be the handle of an event.
CALLBACK_FUNCTION | If this flag is specified, dwCallback in the WAVEOPENDESC structure is assumed to be the address of a callback function.
CALLBACK_THREAD | If this flag is specified, dwCallback in the WAVEOPENDESC structure is assumed to be a handle of a thread.
CALLBACK_WINDOW | If this flag is specified, dwCallback in the WAVEOPENDESC structure is assumed to be a window handle.

It is up to the driver to determine the number of clients allowed to use a particular device. Once a device is opened for the maximum number of clients the driver supports, the driver should return MMSYSERR_ALLOCATED for any additional open requests. If the open operation is successful, the driver should use the DriverCallback function to send the client a WOM_OPEN message.

See Also

WODM_CLOSE, WAVEOPENDESC


WODM_PAUSE

Sent to a waveform output device driver to pause playback of a waveform.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

DWORD dwParam1
Unused.
DWORD dwParam2
Unused.

If a waveform is currently playing, the driver should stop playing immediately without resetting

its position. If playback has not yet begun, the driver should remember that it is in a paused state and delay playback until it receives a WODM_RESTART message. Data blocks received with the WODM_WRITE message should be placed in the output queue. If output is already paused, this message should have no effect, and the driver should return MMSYSERR_NOERROR.


WODM_PREPARE

See also WODM_UNPREPARE

Sent to a waveform output device driver to request the driver to prepare a data block for playback. If data blocks are accessed at interrupt time, they must be page locked to ensure that the memory is not swapped out to disk.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The driver does not support this message.

DWORD dwParam1
Specifies a far pointer to WAVEHDR structure identifying the data block.
DWORD dwParam2
Specifies the size of the WAVEHDR structure.

Driver support for this message is optional. If a driver supports this message, then it must also support WODM_UNPREPARE.

The default response for this message is to return MMSYSERR_NOTSUPPORTED. In this case, MMSYSTEM will page lock the memory for the driver. If a driver requires other operations to prepare a data block for playback, it should set the WHDR_PREPARED bit in the dwFlags field of the WAVEHDR structure and return MMSYSERR_NOERROR. In this case, MMSYSTEM assumes the driver has prepared the data block and does not page lock the memory. If a data block has already been prepared, MMSYSERR_NOERROR should be returned.


WODM_RESET

Sent to a waveform output device driver to stop playback of a waveform and return all data blocks in the playback queue to the client.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

DWORD dwParam1
Unused.
DWORD dwParam2
Unused.

If the driver is playing or paused, it should stop playback immediately and mark all pending data blocks as done by setting the WHDR_DONE bit in the dwFlags field of the WAVEHDR structure for each block. The driver should then notify the client by using DriverCallback to send a WOM_DONE message for each data block. If playback was paused, the driver should take itself out of the paused state. The driver should reset its position count to zero.


WODM_RESTART

Sent to a waveform output device driver to continue playback of a waveform after playback has been paused with the WODM_PAUSE message.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

DWORD dwParam1
Unused.
DWORD dwParam2
Unused.

If the output is not paused, this message should have no effect, and the driver should return MMSYSERR_NOERROR.


WODM_SETPITCH

Sent to a waveform output device driver to set the pitch rate for a device.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The driver does not support changes to the pitch rate.

DWORD dwParam1
Specifies the new pitch rate setting. The rate is specified as a fixed-point value. The high-order word of the DWORD contains the signed integer part of the number, and the low-order word contains the fractional part. The fraction is expressed as a WORD in which a value of 0x8000 represents one half, and 0x4000 represents one quarter. For example, the value 0x00010000 specifies a multiplier of 1.0 (no pitch change), and a value of 0x000F8000 specifies a multiplier of 15.5.
DWORD dwParam2
Unused.

Driver support for pitch rate changes is optional. When a driver receives a WODM_GETDEVCAPS message, it should indicate support for pitch rate changes

by setting or clearing the WAVECAPS_PITCH bit in the dwSupport field of the WAVEOUTCAPS data structure. If a driver supports the WODM_SETPITCH

message, then it must also support WODM_GETPITCH.

Changes to the pitch rate alter the pitch of a waveform during playback and are usually performed by the waveform output hardware. If the hardware does not support this feature, the driver can choose to implement playback rate changes instead.

See Also

WODM_GETPITCH, WODM_SETPLAYBACKRATE


WODM_SETPLAYBACKRATE

Sent to a waveform output device driver to set the playback rate for a device.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The driver does not support changes to the playback rate.

DWORD dwParam1
Specifies the new playback rate setting. The rate is specified as a fixed-point value. The high-order word of the DWORD contains the signed integer part of the number, and the low-order word contains the fractional part. The fraction is expressed as a WORD in which a value of 0x8000 represents one half, and 0x4000 represents one quarter. For example, the value 0x00010000 specifies a multiplier of 1.0 (no playback rate change), and a value of 0x000F8000 specifies a multiplier of 15.5.
DWORD dwParam2
Unused.

Driver support for playback rate changes is optional. When a driver receives a WODM_GETDEVCAPS message, it should indicate support for playback rate

changes by setting or clearing the WAVECAPS_PLAYBACKRATE bit in the dwSupport field of the WAVEOUTCAPS data structure. If a driver supports the WODM_SETPLAYBACKRATE message, then it must also support WODM_GETPLAYBACKRATE.

Changes to the playback rate alter the pitch of a waveform during playback and are usually implemented by the driver by skipping or repeating samples. For example, if the playback rate was 2.0, the driver would play every second sample, at the original playback rate.

See Also

WODM_GETPLAYBACKRATE, WODM_SETPITCH


WODM_SETVOLUME

Sent to a waveform output device driver to set the volume for a device.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The driver does not support changes to volume level.

DWORD dwParam1
Specifies the new volume level. The high-order word contains the right channel setting and the low-order word contains the left channel setting. A value of zero is silence, and a value of 0xFFFF is full volume. If the driver does not support both left and right channel volume changes, it uses the volume specified in the low-order word. The driver will probably not support the full 16 bits of volume control and should truncate the lower bits if necessary. However, the original value requested with WODM_SETVOLUME should be returned with WODM_GETVOLUME.
DWORD dwParam2
Unused.

Driver support for volume level changes is optional. When a driver receives a WODM_GETDEVCAPS message, it should indicate support for volume level changes by setting or clearing the WAVECAPS_VOLUME and WAVECAPS_LRVOLUME bits in the dwSupport field of the WAVEOUTCAPS data structure. If a driver supports the WODM_SETVOLUME message, then it must also support WODM_GETVOLUME.

See Also

WODM_GETVOLUME


WODM_UNPREPARE

Sent to a waveform output device to clean up the preparation performed by the WODM_PREPARE message. If a driver supports this message, then it must also support WODM_PREPARE.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
WAVERR_STILLPLAYING | The specified data block is still in the output queue.

DWORD dwParam1
Specifies a far pointer to WAVEHDR structure identifying the data block.
DWORD dwParam2
Specifies the size of the WAVEHDR structure.

Driver support for this message is optional. If a driver supports the WODM_PREPARE message, then it must also support WODM_UNPREPARE.

The default response for this message is to return MMSYSERR_NOTSUPPORTED. In this case, MMSYSTEM will clean up the preparation previously done on the memory block. If a driver performs the preparation itself, it must clean up the preparation and reset the WHDR_PREPARED flag in the dwFlags field of the WAVEHDR structure. If a data block has not been prepared, MMSYSERR_NOERROR should be returned.

See Also

WODM_PREPARE


WODM_WRITE

Sent to a waveform output device driver to write a waveform data block to the device.

  • The return value is an error code, or zero (MMSYSERR_NOERROR) if the operation is successful. Possible error codes are:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
WAVERR_UNPREPARED | The data block has not been prepared.

DWORD dwParam1
Specifies a far pointer to a WAVEHDR structure identifying the data block.
DWORD dwParam2
Specifies the size of the WAVEHDR structure.

The driver should first check the WHDR_PREPARED bit in the dwFlags field of the WAVEHDR structure. If the bit is not set, the driver should return WAVERR_UNPREPARED. The driver should clear the WHDR_DONE bit and set the WHDR_INQUEUE bit and place the data block in its play queue. Then the driver should return control to the client by returning MMSYSERR_NOERROR. Unless the device has been paused with a WODM_PAUSE message, playback should begin when the first data block is received.

Once the data block has been played, the driver should set the WHDR_DONE bit and clear the WHDR_INQUEUE bit before notifying the client by using DriverCallback to send a WOM_DONE message.


WOM_CLOSE

Sent by a waveform output driver to a client application when a waveform output device is closed.

  • There is no return value.
DWORD dwParam1
Not used.
DWORD dwParam2
Not used.


WOM_DONE

Sent by a waveform output driver to a client application to return an output buffer to an application. The message shouldn't be sent until all data contained in the buffer has been played unless the buffers are being returned as a result of a WODM_RESET message.

  • There is no return value.
DWORD dwParam1
Specifies a far pointer to a WAVEHDR structure identifying the buffer.
DWORD dwParam2
Not used.


WOM_OPEN

Sent by a waveform output driver to a to a client application when a waveform output device is opened.

  • There is no return value.
DWORD dwParam1
Not used.
DWORD dwParam2
Not used.


Structures

The following topics describe the structures provided by Windows for use by audio device drivers.


AUXCAPS

typedef struct auxcaps_tag {
    UINT  wMid;
    UINT  wPid;
    VERSION  vDriverVersion;
    char  szPname[MAXPNAMELEN];
    UINT  wTechnology;
    DWORD  dwSupport;
} AUXCAPS;

The AUXCAPS structure describes the capabilities of an auxiliary output device.

Members

wMid
Specifies a manufacturer ID for the device driver for the auxiliary audio device. Manufacturer IDs are defined in the Multimedia Programmer's Reference in the Microsoft Windows Software Development Kit.
wPid
Specifies a product ID for the auxiliary audio device. Manufacturer IDs are defined in the Multimedia Programmer's Reference in the Microsoft Windows Software Development Kit.
vDriverVersion
Specifies the version number of the device driver for the auxiliary audio device. The high-order byte is the major version number, and the low-order byte is the minor version number. The numbering is up to the driver developer but should be changed with each driver release.
szPname[MAXPNAMELEN]
Specifies the product name in a NULL-terminated string.
wTechnology
Describes the type of the auxiliary audio output according to one of the following flags:
AUXCAPS_CDAUDIO | Audio output from an internal CD-ROM drive.
AUXCAPS_AUXIN | Audio output from auxiliary input jacks.

dwSupport
Describes optional functionality supported by the auxiliary audio device.
AUXCAPS_VOLUME | Supports volume control.
AUXCAPS_LRVOLUME | Supports separate left and right volume control.

If a device supports volume changes, the AUXCAPS_VOLUME flag will be set for the dwSupport field. If a device supports separate volume changes on the left and right channels, both the AUXCAPS_VOLUME and the AUXCAPS_LRVOLUME flags will be set for this field.


DRVM_IOCTL_DATA

typedef struct {
    DWORD  dwSize; // size of this structure (inclusive)
    DWORD  dwCmd;  // IOCTL command code
} DRVM_IOCTL_DATA, FAR * LPDRVM_IOCTL_DATA;

Defines codes used by a MIDI throughput driver with the DRVM_IOCTL message.

Members

dwCmd
Driver-specific code used to filter MIDI throughput data. Drivers can use command codes greater than DRVM_IOCTL_CMD_USER and less than DRVM_IOCTL_CMD_SYSTEM. Codes equal to or greater than DRVM_IOCTL_CMD_SYSTEM are reserved for use by the system.

See Also

DRVM_IOCTL


KEYARRAY

typedef WORD KEYARRAY[MIDIPATCHSIZE];

Specifies drum-key patches to be cached or uncached. Used by the MODM_CACHEDRUMPATCHES message.

See Also

MODM_CACHEDRUMPATCHES


MDEVICECAPSEX

typedef struct {
    DWORD cbSize;
    LPVOID pCaps;
} MDEVICECAPSEX ;

Contains device-capability information for Plug and Play device drivers.

Members

cbSize
Size of the structure, in bytes.
pCaps
Device capabilities. The format of this data is device-specific.


MIDIHDR

typedef struct midihdr_tag {
    LPSTR  lpData;
    DWORD  dwBufferLength;
    DWORD  dwBytesRecorded;
    DWORD  dwUser;
    DWORD  dwFlags;
    struct midihdr_tag far *  lpNext;
    DWORD  reserved;
} MIDIHDR;

Defines the header used to identify a MIDI long message data buffer. For input, this is system exclusive; for output, this is any valid MIDI data.

Members

lpData
Specifies a far pointer to the system-exclusive data buffer.
dwBufferLength
Specifies the length of the data buffer.
dwBytesRecorded
When the header is used in input, this specifies how much data is in the buffer.
dwUser
Specifies user data.
dwFlags
Specifies flags giving information about the data buffer.
MHDR_DONE | Set by the device driver to indicate that it is finished with the data buffer and is returning it to the application.
MHDR_PREPARED | Set by the device driver to indicate that the data buffer has been prepared with midiInPrepareHeader or midiOutPrepareHeader.
MHDR_INQUEUE | Set by the device driver to indicate that the data buffer is queued for playback.

lpNext
Reserved for use by the device driver to point to the next MIDIHDR structure in the queue.
reserved
Reserved for use by the device driver. This field can be used to store a pointer to a structure containing information about the client.


MIDIINCAPS

typedef struct midiincaps_tag {
    UINT  wMid;
    UINT  wPid;
    VERSION  vDriverVersion;
    char  szPname[MAXPNAMELEN];
} MIDIINCAPS;

Describes the capabilities of a MIDI input device.

Members

wMid
Specifies a manufacturer ID for the device driver for the MIDI input device. Manufacturer IDs are defined in the Multimedia Programmer's Reference in the Microsoft Windows Software Development Kit.
wPid
Specifies a product ID for the MIDI input device. Product IDs are defined in the Multimedia Programmer's Reference manual in the Microsoft Windows Software Development Kit.
vDriverVersion
Specifies the version number of the device driver for the MIDI input device. The high-order byte is the major version number, and the low-order byte is the minor version number. The numbering is up to the driver developer but should be changed with each driver release.
szPname[MAXPNAMELEN]
Specifies the product name in a NULL-terminated string.

See Also

MIDM_GETDEVCAPS


MIDIOPENDESC

typedef struct midiopendesc_tag {
    HMIDI          hMidi;
    DWORD          dwCallback;
    DWORD          dwInstance;
    WORD           uReserved;    // reserved; do not use
    DWORD          dnDevNode;
    DWORD          cIds;
    MIDIOPENSTRMID rgIds;
} MIDIOPENDESC;

Contains information needed by a MIDI input or MIDI output device driver when devices are opened with a MODM_OPEN or MIDM_OPEN message.

Members

hMidi
Specifies the client's handle to the device, assigned by MMSYSTEM. Use this handle when notifying the client with the DriverCallback function.
dwCallback
Specifies either the address of a callback function, a window handle, or a task handle, depending on the flags specified in the dwParam2 parameter of the MODM_OPEN or MIDM_OPEN message. If this field contains a handle it is contained in the low-order word. The driver uses this information to notify the client using the DriverCallback function.
dwInstance
Specifies a DWORD of instance information for the client. This instance information is returned to the client whenever the driver notifies the client using the DriverCallback function.
dnDevNode
Specifies a device node for the device (if the device is Plug and Play).
cIds
Specifies the number of stream identifiers, if a stream is open.
rgIds
Specifies an array of device identifiers. The number of identifiers is given by the cIds member.

See Also

MIDIOPENSTRMID, MODM_OPEN, MIDM_OPEN


MIDIOPENSTRMID

typedef struct midiopenstrmid_tag {
    DWORD  dwStreamID;
    WORD   wDeviceID;
} MIDIOPENSTRMID;

Contains a stream identifier and an associated device identifier.

Members

dwStreamID
Identifier of a stream of MIDI data.
wDeviceID
Identifier of the device that is associated with the specified stream of MIDI data.

See Also

MIDIOPENDESC


MIDIOUTCAPS

typedef struct midioutcaps_tag {
    UINT  wMid;
    UINT  wPid;
    VERSION  vDriverVersion;
    char  szPname[MAXPNAMELEN];
    UINT  wTechnology;
    UINT  wVoices;
    UINT  wNotes;
    UINT  wChannelMask;
    DWORD  dwSupport;
} MIDIOUTCAPS;

Describes the capabilities of a MIDI output device.

Members

wMid
Specifies a manufacturer ID for the device driver for the MIDI output device. Manufacturer IDs are defined in the Multimedia Programmer's Reference in the Microsoft Windows Software Development Kit.
wPid
Specifies a product ID for the MIDI output device. Product IDs are defined in the Multimedia Programmer's Reference in the Microsoft Windows Software Development Kit.
vDriverVersion
Specifies the version number of the device driver for the MIDI output device. The high-order byte is the major version number, and the low-order byte is the minor version number. The numbering is up to the driver developer but should be changed with each driver release.
szPname[MAXPNAMELEN]
Specifies the product name in a NULL-terminated string.
wTechnology
Describes the type of the MIDI output device according to one of the following flags:
MOD_MIDIPORT | Indicates the device is a MIDI hardware port.
MOD_SQSYNTH | Indicates the device is a square wave synthesizer.
MOD_FMSYNTH | Indicates the device is an FM synthesizer.
MOD_MAPPER | Indicates the device is the Microsoft MIDI Mapper.

wVoices
Specifies the number of voices supported by an internal synthesizer device. If the device is a port, the field is not meaningful and should be set to zero .
wNotes
Specifies the maximum number of simultaneous notes that can be played by an internal synthesizer device. If the device is a port, the field should be set to zero .
wChannelMask
Specifies the channels that an internal synthesizer device responds to, where the least significant bit refers to channel 0 and the most significant bit to channel 15. Port devices transmit on all channels and should set this field to 0xFFFF.
dwSupport
Specifies optional functionality supported by the device.
MIDICAPS_CACHE | Supports patch caching.
MIDICAPS_VOLUME | Supports volume control.
MIDICAPS_LRVOLUME | Supports separate left and right volume control.
MIDICAPS_STREAM
Supports MIDI streams natively.

If a device supports volume changes, the MIDICAPS_VOLUME flag should be set for the dwSupport field. If a device supports separate volume changes on the left and right channels, both the MIDICAPS_VOLUME and the MIDICAPS_LRVOLUME flags should be set for this field.

See Also

MODM_GETDEVCAPS


PATCHARRAY

typedef WORD PATCHARRAY[MIDIPATCHSIZE];

Specifies patches to be cached or uncached. Used by the MODM_CACHEPATCHES message.

See Also

MODM_CACHEPATCHES


PCMWAVEFORMAT

typedef struct pcmwaveformat_tag {
    WAVEFORMAT  wf;
    WORD  wBitsPerSample;
} PCMWAVEFORMAT;

The PCMWAVEFORMAT structure describes the data format for PCM waveform data.

Members

wf
Specifies a WAVEFORMAT structure containing general information about the format of the waveform data.
wBitsPerSample
Specifies the number of bits per sample.

See Also

WAVEFORMAT


WAVEFORMAT

typedef struct waveformat_tag {
    WORD  wFormatTag;
    WORD  nChannels;
    DWORD  nSamplesPerSec;
    DWORD  nAvgBytesPerSec;
    WORD  nBlockAlign;
} WAVEFORMAT;

The WAVEFORMAT structure describes the format of waveform data. Only format information common to all waveform data formats is included in this structure. For formats that require additional information, this structure is included as a field in another data structure along with the additional information.

Members

wFormatTag
Specifies the format type. Currently defined format types are as follows:
WAVE_FORMAT_PCM Waveform data is PCM.

nChannels
Specifies the number of channels in the waveform data. Mono data uses 1 channel and stereo data uses 2 channels.
nSamplesPerSec
Specifies the sample rate in samples per second.
nAvgBytesPerSec
Specifies the required average data transfer rate in bytes per second.
nBlockAlign
Specifies the block alignment in bytes. The block alignment is the minimum atomic unit of data. For PCM data, the block alignment is the number of bytes used by a single sample, including data for both channels if the data is stereo. For example, the block alignment for 16-bit stereo PCM is 4 bytes (2 channels, 2 bytes per sample).

See Also

PCMWAVEFORMAT


WAVEHDR

typedef struct wavehdr_tag {
    LPSTR  lpData;
    DWORD  dwBufferLength;
    DWORD  dwBytesRecorded;
    DWORD  dwUser;
    DWORD  dwFlags;
    DWORD  dwLoops;
    struct wavehdr_tag far *  lpNext;
    DWORD  reserved;
} WAVEHDR;

The WAVEHDR structure defines the header used to identify a waveform data buffer.

Members

lpData
Specifies a far pointer to the waveform data buffer.
dwBufferLength
Specifies the length of the data buffer.
dwBytesRecorded
When the header is used in input, this specifies how much data is in the buffer.
dwUser
Specifies 32 bits of user data.
dwFlags
Specifies flags giving information about the data buffer.
WHDR_DONE | Set by the device driver to indicate that it is finished with the data buffer and is returning it to the application.
WHDR_BEGINLOOP | Specifies that this buffer is the first buffer in a loop. This flag is only used with output data buffers.
WHDR_ENDLOOP | Specifies that this buffer is the last buffer in a loop. This flag is only used with output data buffers.
WHDR_PREPARED | Set by the device driver to indicate that the data buffer has been prepared with waveInPrepareHeader or waveOutPrepareHeader.
WHDR_INQUEUE | Set by the device driver to indicate that the data buffer is queued for playback.

dwLoops
Specifies the number of times to play the loop. This parameter is used only with output data buffers.
lpNext
Is reserved for use by the device driver to point to the next WAVEHDR structure in the queue.
reserved
Is reserved for use by the device driver. This field can be used to store a pointer to a structure containing information about the client.

Use the WHDR_BEGINLOOP and WHDR_ENDLOOP flags in the dwFlags field to specify the beginning and ending data blocks for looping. To loop on a single block, specify both flags for the same block. Use the dwLoops field in the WAVEHDR structure for the first block in the loop to specify the number of times to play the loop.


WAVEINCAPS

typedef struct waveincaps_tag {
    UINT  wMid;
    UINT  wPid;
    VERSION  vDriverVersion;
    char  szPname[MAXPNAMELEN];
    DWORD  dwFormats;
    UINT  wChannels;
} WAVEINCAPS;

The <k>WAVEINCAPS</k> structure describes the capabilities of a waveform input device.
<parm>
<i><k>wMid</k>
<d>Specifies a manufacturer ID for the device driver for the waveform input device. Manufacturer IDs are defined in the <e>Multimedia Programmer's Reference</e> in the Microsoft Windows Software Development Kit.
<i><k>wPid</k>
<d>Specifies a product ID for the waveform input device. Product IDs are defined in the <e>Multimedia Programmer's Reference</e> in the Microsoft Windows Software Development Kit.
<i><k>vDriverVersion</k>
<d>Specifies the version number of the device driver for the waveform input device. The high-order byte is the major version number, and the low-order byte is the minor version number. The numbering is up to the driver developer but should be changed with each driver release.
<i><k>szPname[MAXPNAMELEN]</k>
<d>Specifies the product name in a NULL-terminated string.
<i><k>dwFormats</k>
<d>Specifies which standard formats are supported. The supported formats are specified with a logical OR of the following flags:
<list>
<i>WAVE_FORMAT_1M08
<d>11.025 kHz, Mono, 8-bit
<i>WAVE_FORMAT_1S08
<d>11.025 kHz, Stereo, 8-bit
<i>WAVE_FORMAT_1M16
<d>11.025 kHz, Mono, 16-bit
<i>WAVE_FORMAT_1S16
<d>11.025 kHz, Stereo, 16-bit
<i>WAVE_FORMAT_2M08
<d>22.05 kHz, Mono, 8-bit
<i>WAVE_FORMAT_2S08
<d>22.05 kHz, Stereo, 8-bit
<i>WAVE_FORMAT_2M16
<d>22.05 kHz, Mono, 16-bit
<i>WAVE_FORMAT_2S16
<d>22.05 kHz, Stereo, 16-bit
<i>WAVE_FORMAT_4M08
<d>44.1 kHz, Mono, 8-bit
<i>WAVE_FORMAT_4S08
<d>44.1 kHz, Stereo, 8-bit
<i>WAVE_FORMAT_4M16
<d>44.1 kHz, Mono, 16-bit
<i>WAVE_FORMAT_4S16
<d>44.1 kHz, Stereo, 16-bit
</list>
<i><k>wChannels</k>
<d>Specifies whether the device supports mono (1) or stereo (2) input.
</parm>

<cmt>Drivers can support other formats in addition to those specified in the <k>dwFormats</k> field.
</cmt></ref>
<ref id=WAVEOPENDESC>WAVEOPENDESC
<sa>WODM_OPEN, WIDM_OPEN</sa>

<syn>typedef struct waveopendesc_tag {
    HWAVE  hWave;
    LPWAVEFORMAT  lpFormat;
    DWORD  dwCallback;
    DWORD  dwInstance;
} WAVEOPENDESC;

This structure contains information needed by a waveform input or waveform output device driver when devices are opened with a WODM_OPEN or WIDM_OPEN message.

Members

hWave
Specifies the client's handle to the device, assigned by MMSYSTEM. Use this handle when notifying the client with the DriverCallback function.
lpFormat
Specifies a far pointer to a WAVEFORMAT structure, indicating the waveform data format requested by the client.
dwCallback
Specifies either the address of a callback function, a window handle, or a task handle, depending on the flags specified in the dwParam2 parameter of the WODM_OPEN or WIDM_OPEN message. If this field contains a handle it is contained in the low-order word. The driver uses this information to notify the client using the DriverCallback function.
dwInstance
Specifies a DWORD of instance information for the client. This instance information is returned to the client whenever the driver notifies the client using the DriverCallback function.

See Also

WIDM_GETDEVCAPS


WAVEOUTCAPS

typedef struct waveoutcaps_tag {
    UINT  wMid;
    UINT  wPid;
    VERSION  vDriverVersion;
    char  szPname[MAXPNAMELEN];
    DWORD  dwFormats;
    UINT  wChannels;
    DWORD  dwSupport;
} WAVEOUTCAPS;

The WAVEOUTCAPS structure describes the capabilities of a waveform output device.

Members

wMid
Specifies a manufacturer ID for the device driver for the waveform output device. Manufacturer IDs are defined in the Multimedia Programmer's Reference in the Microsoft Windows Software Development Kit.
wPid
Specifies a product ID for the waveform output device. Product IDs are defined in the Multimedia Programmer's Reference in the Microsoft Windows Software Development Kit.
vDriverVersion
Specifies the version number of the device driver for the waveform output device. The high-order byte is the major version number, and the low-order byte is the minor version number. The numbering is up to the driver developer but should be changed with each driver release.
szPname[MAXPNAMELEN]
Specifies the product name in a NULL-terminated string.
dwFormats
Specifies which standard formats are supported. The supported formats are specified with a logical OR of the following flags:
WAVE_FORMAT_1M08 | 11.025 kHz, Mono, 8-bit
WAVE_FORMAT_1S08 | 11.025 kHz, Stereo, 8-bit
WAVE_FORMAT_1M16 | 11.025 kHz, Mono, 16-bit
WAVE_FORMAT_1S16 | 11.025 kHz, Stereo, 16-bit
WAVE_FORMAT_2M08 | 22.05 kHz, Mono, 8-bit
WAVE_FORMAT_2S08 | 22.05 kHz, Stereo, 8-bit
WAVE_FORMAT_2M16 | 22.05 kHz, Mono, 16-bit
WAVE_FORMAT_2S16 | 22.05 kHz, Stereo, 16-bit
WAVE_FORMAT_4M08 | 44.1 kHz, Mono, 8-bit
WAVE_FORMAT_4S08 | 44.1 kHz, Stereo, 8-bit
WAVE_FORMAT_4M16 | 44.1 kHz, Mono, 16-bit
WAVE_FORMAT_4S16 | 44.1 kHz, Stereo, 16-bit

wChannels
Specifies whether the device supports mono (1) or stereo (2) output.
dwSupport
Specifies optional functionality supported by the device.
WAVECAPS_PITCH | Supports pitch control.
WAVECAPS_PLAYBACKRATE | Supports playback rate control.
WAVECAPS_VOLUME | Supports volume control.
WAVECAPS_LRVOLUME | Supports separate left and right volume control.

Drivers can support other formats in addition to those specified in the dwFormats field. If a device supports volume changes, the WAVECAPS_VOLUME flag will be set for the dwSupport field. If a device supports separate volume changes on the left and right channels, both the WAVECAPS_VOLUME and the WAVECAPS_LRVOLUME flags will be set for this field.

See Also

WODM_GETDEVCAPS


MCI Device Drivers

This section discusses the contents of an MCI device driver and how to add to and extend the MCI command set. This section covers the following topics:

  • Using the DriverProc entry point for MCI messages
  • Handling MCI messages
  • Responding to the required and basic commands
  • Responding to commands for specific device types
  • Responding to the wait and notify flags
  • Adding new MCI commands
  • Functions available for use with MCI device drivers


MCI Sample Device Drivers

The DDK includes several sample MCI device drivers. While one sample illustrates how to write MCI device drivers for VCR devices, you can use it to understand how MCI device drivers work and adapt it for other devices. The following samples are included with the DDK:

MCI Device Driver | Description
MCIVISCA | A device driver for VCR devices
MCIQA | A device driver shell

The MCIQA sample provides a shell for an MCI device driver. This shell provides the basic structure needed for MCI operation.

Note Sample code for the MCIWAVE, MCISEQ, and MCICDA device drivers is not included with the DDK. These MCI drivers are written to be device independent by using standard calls to the audio drivers and the MSCDEX drivers.


MCI Driver Entry Point

MCI uses the DriverProc entry point to handle its messages for MCI services. MCI augments the messages needed by the system to install, initialize, and configure the driver with MCI specific messages. This section contains a description of the messages added by MCI. While this section will reference the messages used by the system, it will only reference them in relation to the MCI messages. The Microsoft Windows Software Development Kit provides the complete definition and use of the messages used by the system.

The DriverProc entry point has the following syntax:

LRESULT WINAPI DriverProc(DWORD dwDriverID,
    HDRVR hDriver,
    UINT uMsg,
    LPARAM lParam1,
    LPARAM lParam2)

MCI drivers use the following definitions for the parameters of this entry point:

Parameter | Definition
dwDriverID | Contains the driver ID created by the device driver in the low-order word.
hDriver | Contains a handle to the device driver
uMsg | Contains the joystick message
lParam1 | Contains message-dependent data. Most messages define flags for this parameter.
lParam2 | Contains message-dependent data. Most messages define structures for this parameter

When you add this entry point to your device driver, remember that you must export it. For more information on the DriverProc entry point and the system messages it handles, see the description of installable device drivers in the Microsoft Windows Software Development Kit.


Error Return Values

The return values for the low-order word of DriverProc are listed in the function and message reference for MCI commands included with the Microsoft Windows Software Development Kit. General error returns are listed with the mciSendCommand function. Error returns specific to opening a device are listed with the MCI_OPEN message. (The error returns listed with mciSendString are returned by MCI; your device driver does not need to return them.)

The return values for the low-order word of DriverProc are listed in the function and message reference for MCI commands included with the Microsoft Windows Software Development Kit. General error returns are listed with the mciSendCommand function. Error returns specific to opening a device are listed with the MCI_OPEN message, later in this section. (The error returns listed in the SDK as being specific to mciSendString are returned by MCI; your device driver does not need to return them.)

The high-order word of DriverProc return value is used by mciSendString to translate information returned in structure used with lParam2. For information on the contents of the high-order word of the DriverProc return value, see Returning Information in an MCI Structure.


MCI Functions that Call DriverProc

MCI calls the entry point DriverProc in response to the mciSendCommand or mciSendString functions. With the exception of system messages (MCI_SOUND, MCI_BREAK, and MCI_SYSINFO) and the MCI_OPEN and MCI_CLOSE messages, MCI sends the mciSendCommand parameters directly to DriverProc.

For mciSendString, MCI translates the string parameters to parameters used by DriverProc. MCI uses the information stored in the MCI command tables to convert MCI command strings to MCI command messages.


Types of MCI Messages

The MCI commands divide into the following categories:

  • Required commands are supported by all MCI device drivers.
  • Basic commands are optionally supported by some devices.
  • Extended commands are specific to a device type or device class; for example, videodisc players. These commands contain both unique commands and extensions to the required and basic commands.
  • System commands are interpreted directly by MCI rather than being relayed to a device.

Your device driver must support all required command messages. These messages represent the minimum command set for an MCI device driver.

While your device driver might optionally support the basic commands, it must recognize and respond to all of them. If your device driver does not support one of these messages, it must respond to it by returning the error code MCI_UNSUPPORTED_FUNCTION. If your device driver does support a basic command message, it must also respond to all of its basic options.

Your device driver might add options to the required or basic command sets, or create new command messages to form an extended command set. If your device driver extends the command set for an existing device type, you should base your extended command set on one already defined. (For example, if you are developing a device driver for a new videodisc player, you should base your extended commands on the commands already defined for videodisc players.)

Your device driver does not respond to system commands. MCI manages these messages.


Required Command Messages for All Drivers

The following table summarizes the messages that correspond to the required command messages an application can send to your device driver. Your device driver must support all of these command messages.

MCI Message | Description
DRV_CLOSE (MCI_CLOSE_DRIVER) | Closes the device. MCI translates the MCI_CLOSE sent by an application into the MCI_CLOSE DRIVER and DRV_CLOSE messages it sends to your device driver.
DRV_OPEN (MCI_OPEN_DRIVER) | Initializes the device. MCI translates the MCI_OPEN message sent by an application into the DRV_OPEN and MCI_OPEN_DRIVER messages it sends to your device driver.
MCI_GETDEVCAPS | Obtains information about the capabilities of the device.
MCI_INFO | Obtains information from a device driver.
MCI_STATUS | Returns status information from the device driver.

The following table identifies the flags and structures of the required MCI command messages:

MCI Command | Command Flags | Structure
DRV_CLOSE |  |
DRV_OPEN |  | MCI_OPEN_DRV_PARMS
MCI_CLOSE_DRIVER | MCI_NOTIFY MCI_WAIT MCI_TEST | MCI_GENERIC_PARMS
MCI_GETDEVCAPS | MCI_GETDEVCAPS_ITEM MCI_NOTIFY MCI_WAIT MCI_TEST | MCI_GETDEVCAPS_PARMS
MCI_INFO | MCI_INFO_PRODUCT MCI_WAIT MCI_NOTIFY MCI_TEST | MCI_INFO_PARMS
MCI_OPEN_DRIVER | MCI_OPEN_ALIAS MCI_OPEN_ELEMENT MCI_OPEN_ELEMENT_ID MCI_OPEN_SHAREABLE MCI_OPEN_TYPE MCI_OPEN_TYPE_ID MCI_NOTIFY MCI_WAIT MCI_TEST | MCI_OPEN_PARMS MCI_ANIM_OPEN_PARMS MCI_OVLY_OPEN_PARMS MCI_WAVE_OPEN_PARMS
MCI_STATUS | MCI_STATUS_ITEM MCI_STATUS_START MCI_NOTIFY MCI_WAIT MCI_TEST | MCI_STATUS_PARMS

Your device driver might create extended commands by adding new flags and structure members to those already defined. When you extend a command message, your device driver must still support the required flags and members.


Basic Command Messages

In addition to the required command messages, each driver supports a set of command messages specific to its device type. Where possible, these type-specific (or basic) commands are identical between types. For example, the basic MCI_PLAY command is identical for videodisc and videotape players.

The basic command messages are summarized in the following list. MCI does not modify any of these messages or the data associated with them. MCI relays all information received from the calling application to your device driver.

MCI Message | Description
MCI_LOAD | Loads a device element from disk.
MCI_PAUSE | Suspends playing or recording.
MCI_PLAY | Starts transmitting output data.
MCI_RECORD | Starts recording data.
MCI_RESUME | Resumes a paused device.
MCI_SAVE | Saves the current file. Drivers should not destroy the original copy of a file until they receive this message.
MCI_SEEK | Seeks forward or backward.
MCI_SET | Sets device information.
MCI_STATUS | Returns status information from the device. MCI_STATUS as a basic command has additional flags not present for the required message.
MCI_STOP | Stops playing, with no video shown and no audio played.

The following table identifies the flags and structures of the basic MCI commands. If a device driver supports any of these commands, it must support the associated set of flags indicated in the table. If your device driver does not support one of these messages, it must respond to it by returning the error code MCI_UNSUPPORTED_FUNCTION.

MCI Command | Command Flags | Structure
MCI_LOAD | MCI_LOAD_FILE MCI_NOTIFY MCI_WAIT MCI_TEST | MCI_LOAD_PARMS MCI_OVLY_LOAD_PARMS
MCI_PAUSE | MCI_NOTIFY MCI_WAIT MCI_TEST | MCI_GENERIC_PARMS
MCI_PLAY | MCI_FROM MCI_TO MCI_NOTIFY MCI_WAIT MCI_TEST | MCI_PLAY_PARMS MCI_ANIM_PLAY_PARMS MCI_VD_PLAY_PARMS
MCI_RECORD | MCI_FROM MCI_TO MCI_RECORD_INSERT MCI_RECORD_OVERWRITE MCI_NOTIFY MCI_WAIT MCI_TEST | MCI_RECORD_PARMS
MCI_RESUME | MCI_NOTIFY MCI_WAIT MCI_TEST | MCI_GENERIC_PARMS
MCI_SAVE | MCI_SAVE_FILE MCI_NOTIFY MCI_WAIT MCI_TEST | MCI_SAVE_PARMS
MCI_SEEK | MCI_SEEK_TO_END MCI_SEEK_TO_START MCI_TO MCI_NOTIFY MCI_WAIT MCI_TEST | MCI_SEEK_PARMS
MCI_SET | MCI_SET_AUDIO MCI_SET_DOOR_CLOSED MCI_SET_DOOR_OPEN MCI_SET_TIME_FORMAT MCI_SET_VIDEO MCI_SET_ON MCI_SET_OFF MCI_NOTIFY MCI_WAIT MCI_TEST | MCI_SET_PARMS MCI_SEQ_SET_PARMS MCI_WAVE_SET_PARMS
MCI_STATUS | MCI_STATUS_ITEM MCI_STATUS_CURRENT_TRACK MCI_STATUS_LENGTH MCI_TRACK MCI_STATUS_IN_TRACK MCI_STATUS_NUMBER_OF_TRACKS MCI_NOTIFY MCI_WAIT MCI_TEST | MCI_STATUS_PARMS
MCI_STOP | MCI_NOTIFY MCI_WAIT MCI_TEST | MCI_GENERIC_PARMS

Your device driver might add flags and parameters to create extended commands. When you extend a command message, your device driver must still respond to the basic flags and parameters.


Extended Command Messages

Extended command messages apply to particular device types such as animation devices. Device types with extended commands have capabilities that are not present in most types of MCI devices. Many of the required and basic commands are extended to use the capabilities of a device. MCI has the following types of extended commands:

  • Extended command messages for working with MCI element files
  • Extended command messages for device operation and positioning
  • Extended command messages for windowed video devices

The extended commands are summarized in this section. The details of operation are included in the MCI reference section of this section. Use these commands only if they apply to your device. If you do use an extended command, it must support the flags that are common to all devices using the command. If your device driver does not support an extended command, return MCIERR_UNRECOGNIZED_COMMAND.


Extended Commands for Working with MCI Element Files

MCI devices that let you edit data can have extended commands for manipulating data. Applications send the following commands to devices that support editing:

MCI Message | Description
MCI_COPY | Copies data from the MCI element to the Clipboard.
MCI_CUT | Moves data from the MCI element to the Clipboard.
MCI_DELETE | Removes data from the MCI element.
MCI_PASTE | Pastes data from the Clipboard to the MCI element.


Extended Commands for Device Operation and Positioning

MCI devices can have operating capabilities that apply only to a device type or that apply to a device with unique features. Applications send the following commands to devices that have specialized operating capabilities:

MCI Message | Description
MCI_CUE | Cue a device for playback or recording.
MCI_ESCAPE | Sends a string command directly to a device handler.
MCI_RESUME | Continue playback or recording previously paused.
MCI_SPIN | Start or stop spinning a rotating media device such as a laserdisc.
MCI_STEP | Step a device one or more frames.


Extended Command for Windowed Video Devices

Video devices that display data in a window on the computer display can have MCI commands for controlling the video display and window. These devices include animation movie players and video overlay devices. Applications send the following commands video devices that display images in a window:

MCI Message | Description
MCI_FREEZE | Stops video capture.
MCI_PUT | Defines a source or destination clipping rectangle.
MCI_REALIZE | Has a graphic device to realize its palette.
MCI_UNFREEZE | Restores video capture.
MCI_UPDATE | Has a graphic device update or paint the current frame.
MCI_WHERE | Determines the extent of a clipping rectangle.
MCI_WINDOW | Specifies a window and the window characteristics used for display.


MCI Structures

The members in the structures used for the lParam2 parameter all have similar organizations. All the members in these structures are the size of DWORDs.Their first member is dwCallback and it is used for the window function associated with the MCI_NOTIFY flag. If the structure is used to return data from the device driver, the data-return members immediately follow the first member. If the structure is used to pass data to the device driver from the application, the data-transfer members immediately follow any return members.

There are four possible arrangements for return members:

  • If a command message does not have return data, the structure does not have any return members.
  • If a command message returns integer data, the second member of the structure is reserved for the data.
  • If a command message returns string data, the second and third members of the structure are reserved. The second member is reserved for a pointer to the zero-terminated return string. The third member is reserved for the size of return buffer. The application is responsible for creating the buffer for the return string.
  • If a command message returns RECT data, the data occupies the second and third members of the structure. The second member is reserved for the top-left values of the RECT data. The third member is reserved for the bottom-right values of the RECT data.

Any data passed to your device driver follows the return members. Your device driver should not read data from a member in these structures unless the member is validated with a flag. Without the flag, your device driver is not guaranteed of finding valid data in the structure. For example, the MCI_OPEN_ELEMENT flag validates the lpstrElementName member of the MCI_OPEN_PARMS structure.

If an application does not use any of the members of a structure, it can specify NULL for lParam2.

Commands that extend the structures will add new members to the end of the existing structures. The names used for extended structures add the device type to the name of the data type. For example, the extended MCI_OPEN_PARMS structure for animation devices uses MCI_ANIM_OPEN_PARMS as the name.


Using MCI Device Drivers

This section describes the commands that require special action from a device driver or are generally applicable to MCI drivers. Most MCI commands require obvious actions from the drivers (for example, MCI_STOP) and drivers can follow the behavior described in the MCI command specification.

This section also describes the procedures for adding new command messages or extending the existing ones. If you are writing a device driver that uses a command set already defined for the device type, you can use an existing command table to convert the command strings to command messages. When using a command table that is already defined, you only need to create the handler for the command messages. MCI will automatically translate the command strings to the command messages. In this case, the information you need to know is contained in the sections on handling MCI messages.

If your device driver extends command messages or adds new command messages, then you will need to write the message handler and extend the command tables. Writing the message handler is described in the sections on handling MCI messages. Creating a new message or extending a message is described in .


Opening a Device Driver

Before using a device, an application must open the device driver with the MCI_OPEN command message. When MCI receives this message, MCI uses Windows to open your device driver. Windows checks if the device driver is loaded, and, if not, it sends the DRV_LOAD and DRV_ENABLE messages to DriverProc to prepare the driver for use. Your device driver will use the DRV_LOAD message to load custom command tables. (These tables and how to load them are described later in this section.) Other actions your device driver should take for the DRV_LOAD and DRV_ENABLE messages are those expected for a Windows installable device driver. When the device driver is loaded, Windows sends the DRV_OPEN message to DriverProc.

For the DRV_OPEN message, Windows sets dwDriverIdentifier to 0L and sets hDriver to the driver handle it creates. Windows sets lParam1 to a pointer to a zero-terminated string. The string contains the information following the entry for the device driver in the SYSTEM.INI file or registry. Windows sets lParam2 to a pointer to an MCI_OPEN_DRIVER_PARM structure.

MCI creates the device ID and passes it to your driver in the wDeviceID member of MCI_OPEN_DRIVER_PARM. Your device driver should return this value when it successfully finishes with the DRV_OPEN message. MCI applications use this ID to identify an MCI device driver. (MCI applications and drivers do not use the handle Windows creates for hDriver. MCI intercepts this handle and does not pass it back to the calling application.)

MCI places a pointer to a zero-terminated string in the lpstrParams member of MCI_OPEN_DRIVER_PARM. (This information duplicates the information in the lParam1 parameter of DriverProc.) The string contains the parameters following the definition of the device driver in the SYSTEM.INI file. For many device drivers, no additional information is placed after the definition of the device drive. Some device drivers will include a small amount of configuration data after the definition.

In addition to the tasks your device driver needs to perform for the DRV_OPEN message, it must assign data to the remaining members of the MCI_OPEN_DRIVER_PARMS structure.

If your device driver has registered a custom command table, set the wCustomCommandTable member to its handle. (See Registering the Command Tables with MCI for more information on this table and obtaining the handle to it.) If your driver does not have a custom command table, set the wCustomCommandTable member to MCI_NO_COMMAND_TABLE.

Your driver must also set the value for the wType member. This value tells the system which device type specific parsing table to use to parse the command strings. Select the value used from the following list of MCI_DEVTYPE identifiers. Use the MCI_DEVTYPE_OTHER identifier if your device type is not listed in the table.

Device Type | Identifier | Description
cdaudio | MCI_DEVTYPE_CD_AUDIO | CD audio player
dat | MCI_DEVTYPE_DAT | Digital audio tape player
digitalvideo | MCI_DEVTYPE_DIGITAL_VIDEO | Digital video in a window
mmmovie | MCI_DEVTYPE_ANIMATION | Animation
other | MCI_DEVTYPE_OTHER | Nonstandard MCI device type
overlay | MCI_DEVTYPE_OVERLAY | Overlay device (analog video in a window)
scanner | MCI_DEVTYPE_SCANNER | Image scanner
sequencer | MCI_DEVTYPE_SEQUENCER | MIDI sequencer
vcr | MCI_DEVTYPE_VCR | Videotape recorder or player
videodisc | MCI_DEVTYPE_VIDEODISC | Videodisc player
waveaudio | MCI_DEVTYPE_WAVEFORM_AUDIO | Audio device that plays digitized waveform files

In addition to filling in the MCI_OPEN_DRIVER_PARMS structure, your device driver should complete any other tasks it needs for operation. For example, it might allocate any global memory it needs. When you allocate memory that is specific to the driver instance, allocate it with the GMEM_SHARE option. This prevents the memory from being freed if the calling application exits without closing your device.

MCI sends the MCI_OPEN_DRIVER message as the next message generated by MCI_OPEN. MCI sets the dwDriverID parameter of DriverProc to the same identifier created when your device driver was opened with DRV_OPEN. MCI also sets hDriver to the handle the system created for DRV_OPEN. The lParam1 parameter contains any flags set by the application opening your device driver. The following list summarizes these flags:

Command Flag | Description
MCI_NOTIFY | Directs the device driver to return immediately as usual as well as post the MM_MCINOTIFY message to a window function when the requested action is complete.
MCI_OPEN_TYPE | Specifies that the lpstrDeviceType member of the structure contains a pointer to a zero-terminated string containing the device type.
MCI_OPEN_TYPE_ID | Specifies that the lpstrDeviceType member of the structure contains an integer device type identifier rather than a string identifier.
MCI_OPEN_ELEMENT | Specifies that the lpstrElementName member of the structure contains a pointer to a zero-terminated string containing the device element name.
MCI_OPEN_ELEMENT_ID | Specifies that the lpstrElementName member of the structure contains an element ID.
MCI_OPEN_ALIAS | Specifies that the lpstrAlias member of the structure contains a device alias.
MCI_OPEN_SHAREABLE | Specifies that the device or element is to be opened as shareable.
MCI_WAIT | Directs the device driver to wait until the requested action is complete before returning to the user.

Your device driver can ignore the MCI_OPEN_TYPE, MCI_OPEN_TYPE_ID, and MCI_OPEN_ALIAS flags. MCI uses these flags to select and manage MCI device drivers. The other flags used for MCI_OPEN_DRIVER are described in subsequent sections or are described with the structure members associated with them.

The lParam2 parameter is of type LPMCI_OPEN_PARMS and points to the structure containing the open parameters. The members of the MCI_OPEN_PARMS structure should be filled in as follows.

The dwCallback member specifies the handle to the window currently used for the MCI_NOTIFY flag. This member is part of every structure sent with MCI command messages.

The wDeviceID member contains the value returned by the DRV_OPEN message. This will usually correspond to the device ID.

Only compound device drivers will use the lpstrElementName member. This member contains the name of the device element the application associates with this instance of the driver. The MCI_OPEN_ELEMENT flag validates this member. (Simple device drivers should fail an open with this flag.)

An application might open a compound device driver without the MCI_OPEN_ELEMENT flag to query it with the MCI_GETDEVCAPS or MCI_INFO message. Your driver should fail any messages that are not supported when a compound device is opened as a simple device by returning MCIERR_UNSUPPORTED_FUNCTION.

Both simple and compound devices should allocate any memory needed for operation and associate it with the dwDriverID value when they are opened.

Your device driver can ignore the lpstrDeviceType and lpstrAlias members of the MCI_OPEN_PARMS structure.

Unless the application uses the MCI_WAIT flag, your device driver should return to the application as soon as it verifies that it can open successfully. During the verification, your device driver should check for any conditions that might prevent it from completing the open. If your device driver returns to the application before it is fully open, your checks should be complete enough to avoid the contradiction of returning a no error value for MCI_OPEN_DRIVER and then later posting the MM_MCINOTIFY message with MCI_NOTIFY_FAILURE flag. (The MM_MCINOTIFY message is described in the section on handling the MCI_NOTIFY flag.) For example, a device driver might need to load a large file from CD-ROM for its operation. To return to the application as soon as possible, the checks performed for the open sequence might verify only that the file can be loaded. The actual loading of the file could wait until after the device driver returns to the application. Some of the checks required would include verifying that enough memory can be allocated, verifying that the CD-ROM is functional, and verifying that the file exists on the CD-ROM.


Responding to the MCI_OPEN_SHAREABLE Flag

The MCI_OPEN_SHAREABLE flag requests that your device driver allow itself to be shared. For simple devices, this lets multiple applications have unrestricted access to your device driver. As a shared device, your device driver needs to create only one context for the mode and position of the MCI device for all the applications using it. The shared context lets each application change the mode and position of the MCI device. MCI will create a unique device ID for each shared instance of the device driver.

If your simple device cannot be shared, fail the open by returning MCIERR_UNSUPPORTED_FUNCTION. If your device driver is initially opened as shareable, return MCIERR_MUST_USE_SHAREABLE to fail any subsequent opens without the MCI_OPEN_SHAREABLE flag. If your device driver is initially opened as nonshareable, fail any subsequent opens by returning MCIERR_MUST_USE_SHAREABLE.

For compound devices, the MCI_OPEN_SHAREABLE flag applies to the device element. (Compound device drivers opened without a device element should ignore the MCI_OPEN_SHAREABLE flag.) A shared element lets multiple applications access the same context for the file element. All applications accessing the shared context have equal control over the element. If your compound device driver cannot support a shared element context, fail the open by returning MCIERR_UNSUPPORTED_FUNCTION. (The compound device drivers shipped with Windows do not support MCI_OPEN_SHAREABLE.)

If an element of your device driver is initially opened as a shared context, return MCIERR_MUST_USE_SHAREABLE to fail subsequent opens of that element context that do not include the MCI_OPEN_SHAREABLE flag. If an element context is initially opened as nonshareable, fail any subsequent opens with MCIERR_MUST_USE_SHAREABLE.

Your device driver might also let applications open a single device element (file) multiple times without using the MCI_OPEN_SHAREABLE flag. In this case, your device driver should treat each instance of the device element as a totally separate device element. You device driver should maintain separate position and status information for each instance.


Closing a Device Driver

An application sends the MCI_CLOSE message to relinquish access to a driver. MCI interprets the MCI_CLOSE message and substitutes the MCI_CLOSE_DRIVER and DRV_CLOSE messages.

For nonshared simple devices, a close message directly corresponds to an open message. These device drivers should prepare to terminate when they receive a close message.

For nonshared compound devices, a close message for a device element directly corresponds to an open message for that element. These device driver should close the element corresponding to the dwDriverID. Even when all device elements are closed, the driver can remain open if an application had also opened it without a device element. Nonshared compound device drivers need to be aware of when they are opened this way. They should not prepare for termination until all applications have closed them.

Shared devices and device elements also need to be aware of being opened by multiple applications. The close messages received for these cases indicates only that an application is finished using the device or device element. Other applications can have these devices and device elements open and will continue to access them. These device drivers should not prepare for termination until they know that all applications that have opened them have closed them. Your device driver might keep track of the using applications by maintaining a count of the number of times it has been opened.

The system will send the DRV_FREE message when all applications have closed a device driver. Use this message to ensure that your device driver is properly closed before it terminates. If your device driver registered a custom command table, it should free it at this time.


Responding to the Wait Flag

Normally, your device driver returns control to the application immediately after processing the command message. For many devices, control returns to the application even if it takes several minutes for the hardware to complete the action initiated by the command.

If an application uses the MCI_WAIT flag, your device driver needs to delay returning to the calling application while the device completes the action requested. While your device driver waits for the device to finish, it should periodically call mciDriverYield to let Windows process other tasks and to let it check for the MCI break key.


Responding to the Notify Flag

The MCI_NOTIFY flag directs the device driver to return immediately as usual and to post the MM_MCINOTIFY message when the requested action is complete. When the action is complete, use mciDriverNotify to notify the window function specified by the application.

Specify the handle to the window associated with the callback window function in the hCallback parameter of mciDriverNotify. You can obtain this handle from the low-order word of the dwCallBack member of the structure sent with the message. Specify the device ID in the uDeviceID parameter. Specify the status of the notification in the wStatus parameter. Four possibilities exist for the status:

  • MCI_NOTIFY_SUCCESSFUL
  • MCI_NOTIFY_SUPERSEDED
  • MCI_NOTIFY_ABORTED
  • MCI_NOTIFY_FAILURE

Your device driver sends MCI_NOTIFY_SUCCESSFUL when it successfully completes the actions requested by the command with MCI_NOTIFY set.

Your device driver sends MCI_NOTIFY_SUPERSEDED when an application sends another MCI message with the MCI_NOTIFY flag before the conditions for the first notify are met. In this case, your device driver calls the pending callback function and resets the callback conditions to correspond to the new command requesting notification.

Your device driver sends MCI_NOTIFY_ABORTED when an application sends a command that prevents the callback conditions from being satisfied. For example, the stop command would abort a notification pending for the "play to 500 notify" command.

Your device driver sends MCI_NOTIFY_FAILURE when a hardware failure prevents the callback conditions from being satisfied. When your driver receives a command with MCI_NOTIFY, it should verify that it can successfully complete the command before it returns to the application. If your driver anticipates an error, it should fail and not return any notification status.

Your device driver will perform the following tasks for handling the MCI_NOTIFY flag:

  • Determine if the MCI_NOTIFY flag is set.
  • Set up the appropriate mechanism (such as a timer or interrupt) to determine when the device has finished the specified task.
  • Return control to the application while notification is pending.
  • Determine when the task is complete and notify the application-specified window function of the status of the notify using mciDriverNotify.

A simple example of determining if the MCI_NOTIFY flag is set in lParam1 is shown in the following code fragment:

wStatus = MCI_NOTIFY_SUCCESSFUL;
if (lParam1 & MCI_NOTIFY)
        mciDriverNotify (hCallBack, uDeviceID, wStatus);

This fragment checks for the MCI_NOTIFY flag and, if found, calls mciDriverNotify to send the status message to the application-specified window function. This fragment is appropriate if the time to complete the action requested of your driver is insignificant. For example, the time required to determine and return information requested by the MCI_INFO and MCI_GETDEVCAPS is the execution time of your device driver (that is, there are no processing or hardware delays). Because there is no delay, the fragment does not need a timer or interrupt to determine when the device completes the action.

Actions that have a noticeable delay associated with them require a more sophisticated approach to determine when the device finishes. One possible way your driver might achieve this is by setting a timer to periodically call a timer function that interrogates the status of the device. Once your device driver sets the timer and timer function, it can return control to the calling application. If your MCI device has the capability of generating hardware interrupts, your device driver might use these interrupts rather than the timer.


Responding to the Test Flag

The MCI_TEST flag lets applications interrogate your driver to determine if it can execute a command and its flags. Applications can add this flag to any MCI command except MCI_OPEN and MCI_CLOSE. If the device driver determines that it can execute the command, it exits without processing the command and without returning an error. If an application supplies a return buffer for a command that returns data, the device returns zero for integer return values and an empty string for string return values. If the device cannot handle the command, it returns a suitable error.

If a device cannot execute the command because the requested function is not supported, the device should return MCIERR_UNSUPPORTED_FUNCTION for the error. If the device supports a command but it cannot execute it because the device is not in a suitable state, the device should return the error MCIERR_NONAPPLICABLE_FUNCTION.


Returning Information in an MCI Structure

When you use an MCI structure to return integer information that also has a string equivalent, MCI needs the string ID to find it in the resource table. The high-order word of the return member is set to the string ID. The low-order word of the return member is set to the return value. You can use the MAKEMCIRESOURCE macro to combine these values. For example, the following statement assigns information for the song-pointer format to the return member:

lpStatus->dwReturn = MAKEMCIRESOURCE(MCI_SEQ_FORMAT_SONGPTR,
    MCI_SEQ_FORMAT_SONGPTR_S);

Many of the return values defined in MMSYSTEM.H also have a string resource ID defined in MMDDK.H. Identifiers which are only used for return values and are not input parameters will normally have only one version (they do not have a resource identifier with the _S suffix). The following string resource IDs are defined by MMDDK.H:

String Resource ID | MCI Constant
MCI_FORMAT_BYTES_S | MCI_FORMAT_BYTES
MCI_FORMAT_FRAMES_S | MCI_FORMAT_FRAMES
MCI_FORMAT_HMS_S | MCI_FORMAT_HMS
MCI_FORMAT_MILLISECONDS_S | MCI_FORMAT_MILLISECONDS
MCI_FORMAT_MSF_S | MCI_FORMAT_MSF
MCI_FORMAT_SAMPLES_S | MCI_FORMAT_SAMPLES
MCI_FORMAT_SMPTE_24_S | MCI_FORMAT_SMPTE_24
MCI_FORMAT_SMPTE_25_S | MCI_FORMAT_SMPTE_25
MCI_FORMAT_SMPTE_30_S | MCI_FORMAT_SMPTE_30
MCI_FORMAT_SMPTE_30DROP_S | MCI_FORMAT_SMPTE_30DROP
MCI_FORMAT_TMSF_S | MCI_FORMAT_TMSF
MCI_SEQ_FILE_S | MCI_SEQ_FILE
MCI_SEQ_FORMAT_SONGPTR_S | MCI_SEQ_FORMAT_SONGPTR
MCI_SEQ_MAPPER_S | MCI_SEQ_MAPPER
MCI_SEQ_MIDI_S | MCI_SEQ_MIDI
MCI_SEQ_NONE_S | MCI_SEQ_NONE
MCI_SEQ_SMPTE_S | MCI_SEQ_SMPTE
MCI_VD_FORMAT_TRACK_S | MCI_VD_FORMAT_TRACK
MIDIMAPPER_S | MIDIMAPPER
WAVE_FORMAT_PCM_S | WAVE_FORMAT_PCM
WAVE_MAPPER_S | WAVE_MAPPER

MCI uses the high-order word of the DriverProc return value to tell mciSendString how to convert the information returned in the MCI structure into string form. (The mciSendString function translates the string interface used by an application to the command interface used by your device driver.) The following flags are defined for the high-order word of the DriverProc return value:

Flag | Meaning
MCI_RESOURCE_RETURNED | Indicates the high-order word of the value in the return member is a string resource ID. This ID is translated by mciSendString by loading the specified resource.
MCI_RESOURCE_DRIVER | Indicates the high-order word of the value in the return member is a string resource ID defined by the device driver. This flag requires MCI_RESOURCE_RETURNED.
MCI_COLONIZED3_RETURN | MCI_COLONIZED4_RETURN | Indicates that when the DWORD value in the return member is converted into a string, its individual bytes should be separated by colons.
MCI_INTEGER_RETURNED | Indicates that the value in a structure that allows either integer or string returns is an integer value.

Integer return values which have resource string equivalents are indicated by setting the MCI_RESOURCE_RETURNED bit in the error return. This indicates that the high-order word of the value in the return member is a string ID to load. An application that uses mciSendCommand to call your driver will not see the high-order word of the return value when you return MCI_RESOURCE_RETURNED. When this flag is set, MCI will clear the high-order word of the return member before it returns to the application. Using the high-order word for resource data restricts the integer return value to the 16-bits of the low-order word. The following code fragment sets the MCI_RESOURCE_RETURNED bit for the DriverProc return value:

lpStatus-dwReturn = MAKEMCIRESOURCE(MCI_SEQ_FORMAT_SONGPTR,
    MCI_SEQ_FORMAT_SONGPTR_S);
return MCI_RESOURCE_RETURNED;

If your device driver defines the resource string, use the MCI_RESOURCE_DRIVER flag with the MCI_RESOURCE_RETURNED flag.

If your device driver returns information in the return member that should be separated by colons when it is displayed, use the MCI_COLONIZED3_RETURN or MCI_COLONIZED4_RETURN flag. For example, 0x01020304 is "colonized" as "4:3:2" for MCI_COLONIZED3_RETURN or "4:3:2:1" for MCI_COLONIZED4_RETURN.

If the return member of the structure can return either integer or string values, and your device driver is returning an integer value, use the MCI_INTEGER_RETURNED flag in the DriverProc return value. For example, the sysinfo command can return both string and integer data. When this flag is set, the returned integer is converted into a string equivalent by mciSendString.

Structures that return string data or RECT data do not require that you set any flags in the return value for DriverProc.


Responding to the MCI_INFO Message

Applications use the MCI_INFO message to obtain string information from a device. An application will supply a pointer to a MCI_INFO_PARMS structure. Your device driver should fill out the members of this structure as follows.

The lpstrReturn member of this structure contains a pointer to an application supplied buffer. Its size is indicated by the dwRetSize member. Use this buffer to return a zero-terminated string containing the information from your device driver.

Flags specified in the lParam1 parameter of DriverProc specify the type of information your driver should return. The MCI_INFO_PRODUCT flag requests the product information from the device driver. This information should include the manufacturer of the hardware and, if possible, the model information. If your device driver applies to a device type rather than a specific device, you should return the long name of the device type. Other flags can extend the MCI_INFO message to request other information; however, MCI_INFO should not be used to return information available with the MCI_STATUS message.


Responding to the MCI_GETDEVCAPS Message

Applications use the MCI_GETDEVCAPS message to determine the capabilities of a device and its device driver. An application will supply a pointer to a MCI_GETDEVCAPS_PARMS structure. Your device driver should fill out the members of this structure as follows.

Use the dwReturn member to return the information indicated by the constant in dwItem. The MCI_GETDEVCAPS_ITEM flag sent by the application validates the dwItem member of this structure. The contents of dwItem specify the type of information requested. The following constants are always defined for MCI_GETDEVCAPS:

MCI Constant | Description
MCI_GETDEVCAPS_CAN_RECORD | Return TRUE if device has recording capabilities. This implies the driver also has stop and pause capabilities.
MCI_GETDEVCAPS_HAS_AUDIO | Return TRUE if the device has audio capabilities.
MCI_GETDEVCAPS_HAS_VIDEO | Return TRUE if the device has video capabilities.
MCI_GETDEVCAPS_USES_FILES | Return TRUE if the device driver uses files. This implies the driver is also a compound device.
MCI_GETDEVCAPS_COMPOUND_DEVICE | Return TRUE if the device driver uses device elements.
MCI_GETDEVCAPS_DEVICE_TYPE | Return the device driver type.
MCI_GETDEVCAPS_CAN_EJECT | Return TRUE if the device can eject the media.
MCI_GETDEVCAPS_CAN_PLAY | Return TRUE if the device has playback capabilities. This implies the driver also has stop and pause capabilities.
MCI_GETDEVCAPS_CAN_SAVE | Return TRUE if the device driver can save data.


Responding to the MCI_STATUS Message

Applications use the MCI_STATUS message to determine the status of a device and device driver. An application will supply a pointer to a MCI_STATUS_PARMS structure. Your device driver should fill out the members of this structure as follows.

Use the dwReturn member to return the information indicated by the constant in dwItem. The MCI_STATUS_ITEM flag sent by the application validates the dwItem member of this structure. The contents of dwItem specify the type of information requested. The dwTrack member is used for the basic and extended commands. The following constants are always defined for MCI_STATUS:

MCI Constant | Description
MCI_STATUS_MODE | Requests the current mode of the device. The modes your driver can return include: MCI_MODE_NOT_READY MCI_MODE_PAUSE MCI_MODE_PLAY MCI_MODE_STOP MCI_MODE_OPEN MCI_MODE_RECORD MCI_MODE_SEEK
MCI_STATUS_READY | Requests if the device is ready. Return TRUE if the device is ready.


Responding to MCI_PAUSE, MCI_PLAY, MCI_RECORD, MCI_RESUME, and MCI_STOP Messages

The MCI_PLAY and MCI_RECORD messages request that a device start playing or recording. Without any flags, your driver should assume the current position is the start position and the end of the media is the stop position. The MCI_FROM and MCI_TO flags will override the default positions. The units assigned to these position values depend on the device and the options set with the MCI_SET command message.

The MCI_STOP command stops the playing or recording of a device. If MCI_STOP applies to your device driver, your device driver should also support the MCI_PAUSE command. If possible, MCI_PAUSE should only suspend operation and leave the device ready to resume playing or recording immediately.

Your device driver can include the MCI_RESUME command message to restart a paused device. This command does not change the stop position. An application can use MCI_PLAY or MCI_RECORD to resume operation from a stopped or paused state for the respective modes. These commands resume operation under the following conditions:

  • If the MCI_FROM flag is absent or it specifies the current position
  • If the MCI_TO flag specifies the position set previously
  • If the play or recording direction does not change

Pausing and resuming a device does not change notification for the play and recording commands. These command messages do not prevent a device from obtaining the notification conditions-they only delay the command. Thus, a paused device can reach the notification conditions after it is resumed.


Creating New Files for MCI_RECORD

If your compound device supports recording, you might want to let an application open your device without specifying a name for the device element. In this case the application will use the MCI_OPEN_ELEMENT flag and use a zero-length zero-terminated string for the element name. Recorded data is not saved in a permanent file until the application explicitly saves it with the MCI_SAVE command. The MCI_SAVE command will specify the name of the destination file.

If your device driver does not support recording without a device element being defined, it should detect the zero length element name and return MCIERR_FILENAME_REQUIRED.


Responding to the MCI_SET Message

An application uses the MCI_SET command message to set device information. An application will supply a pointer to an MCI_SET_PARMS structure. Your device driver should fill in the members of this structure as follows.

The MCI_SET_TIME_FORMAT flag sent by the application validates the dwTimeFormat member of MCI_SET_PARMS. The contents of dwTimeFormat specify the time format or position indicator the device wants to use with your device. If possible, your device driver should support the MCI_FORMAT_MILLISECONDS format in addition to any format that is conventionally used with the device.

When a time format is not specified, your device driver should assume a default time format. The following table lists the default formats for MCI device drivers:

MCI Device Type | Default Time Format
cdaudio | MSF
mmmovie | Frames
overlay | Not applicable
sequencer | Specified by the MIDI file element
videodisc | HMS for CLV, Frames for CAV
waveaudio | Milliseconds

The MCI_SET_AUDIO flag sent by the application validates the dwAudio member of this structure. The contents of this member identify the audio channel affected by the MCI_SET_ON or MCI_SET_OFF flags. Constants defined for dwAudio include MCI_SET_AUDIO_ALL, MCI_SET_AUDIO_LEFT, and MCI_SET_AUDIO_RIGHT to indicate both channels, the left channel, and the right channel. Your device driver can use other values for additional channels.


Responding to the Basic MCI_STATUS Message

Applications use the basic flags of the MCI_STATUS message to determine the statistics for the device media. An application will supply a pointer to a MCI_STATUS_PARMS structure. The MCI_STATUS_PARMS structure was introduced with the required command messages. The following constants are defined for the dwItem member of the MCI_STATUS_PARMS structure in addition to the constants defined previously:

MCI Constant | Description
MCI_STATUS_CURRENT_TRACK | Requests the current track number. MCI uses continuous track numbers.
MCI_STATUS_LENGTH | Requests the total media or track length.
MCI_STATUS_NUMBER_OF_TRACKS | Requests the total number of playable tracks.
MCI_STATUS_POSITION | Requests the current position in the media or track.
MCI_STATUS_READY | Requests if the device is ready. Returns TRUE if the device is ready.
MCI_STATUS_TIME_FORMAT | Requests the current time format of the device. The time formats your driver can return include: MCI_FORMAT_BYTES MCI_FORMAT_FRAMES MCI_FORMAT_HMS MCI_FORMAT_MILLISECONDS MCI_FORMAT_MSF MCI_FORMAT_SAMPLES MCI_FORMAT_TMSF

The MCI_STATUS_START flag requests that the position of the start of the media should be returned. This flag will be accompanied by the MCI_STATUS_ITEM flag and the dwItem member will contain MCI_STATUS_POSITION.

The MCI_TRACK flag validates the dwTrack member of the structure. This flag modifies the meaning of the MCI_STATUS_POSITION or MCI_STATUS_LENGTH constants. When used with MCI_STATUS_POSITION, the application is requesting the starting position of the specified track. When used with MCI_STATUS_LENGTH, the application is requesting the length of the specified track.


Adding New MCI Commands

This section applies to your driver only if you need to add new MCI commands or provide extensions to the MCI command set.

Do the following to add or extend a command set

  1. Define the new MCI messages you plan to support with your driver.
  2. Define new structures and flags for this command to use with mciSendCommand.

    MCI messages use lParam2 as a pointer to a structure, and use lParam1 as a bit member for the flags associated with the message. A flag exists for each member in the structure that accepts data from the calling application. The application sets the flag in the bit member of lParam1 to indicate a value is assigned to a particular member. Flags also specify options without parameters and these flags do not correspond to a member in the structure.

  3. Create a command table that MCI will use to translate string commands sent through mciSendString into the command messages and structures used by your driver.
  4. Support the new messages in your driver's DriverProc.
  5. Register the new command table with MCI in your driver's DRV_LOAD procedure.


Define the New Messages for Your Driver

Suppose you are writing a driver for a videodisc player and this player supports a new command, "reset." This command is invoked by the string "reset program_number." The command sets all player parameters to their default settings or one of several predefined states indicated by the program_number.

You would add the following message to the list of messages you must support in DriverProc:

#define    MCI_VDISC_RESET    1000

MCI_USER_MESSAGES is the first integer you can use for custom messages. Since the resource compiler does not accept mathematical expressions in the RCDATA resource type, you must indicate the specific value you want to use.

Now that you have defined the message ID, you must define the structure and the command table, and create the code to handle this message in DriverProc.


Defining the Structure

The members of the structure for an MCI message are always 32 bits long - the size of double-word values. The number of members in the structure depends on the particular message. The first member must be reserved for a handle to a window function used with the MCI_NOTIFY flag. The next members in the structure depend on the type of data returned for the message:

  • If no data is returned, no return members are reserved in the structure. Any data members for passing information to the device driver immediately follow the dwCallback member.
  • If integer data is returned, the second member of the structure is reserved for the return data. Any data members for passing information to the device driver start in the third member.
  • Return data. The second DWORD is assigned to a member reserved for a pointer to the zero-terminated return string. The third DWORD is assigned to a member reserved for the size of return buffer. The application is responsible for creating the buffer for return string. Any data members for passing information to the device driver start in the fourth member.
  • If RECT data is returned, the second and third members of the structure are reserved for the return data. The first DWORD position is reserved for the top-left values of the RECT data. The second DWORD position is reserved for the bottom-right values of the RECT data. Any data members for passing information to the device driver start in the fourth DWORD position. Rather than specifying two DWORDs for the RECT data, most structure definitions use one RECT data member to obtain an equivalent structure.


Assigning Flag Values

In addition to indicating the members used in a structure, flags can indicate an option that does not use any parameters. For example, the wait flag does not use any parameters.

When you add new flags, you must ensure they do not conflict with the flags already used. Bits 0 through 15 of the 32-bit DWORD are reserved for MCI. Bit 16 (0x00010000) is the first bit that a driver can use for its flags. If your command is a new command, you can start with this bit position. If your command extends a command, you must choose bit positions that do not conflict with the flags already defined for that command. Any unused bits in the new flag must be set to zero. For example, if a new command for videodisc players uses flags 16 through 20, a custom extension to the new command could use flags 21 through 31.

To continue the example for adding a "reset" command to a videodisc driver, the following code fragment defines a structure, a corresponding pointer for it, and the flag corresponding to the program member of the structure:

typedef struct {
    DWORD    dwCallback;
    DWORD    dwProgram;
} MCI_VDISC_RESET_PARMS;

typedef      MCI_VDISC_RESET_PARMS FAR * LPMCI_VDISC_RESET_PARMS;

#define      MCI_VDISC_RESET_PROGRAM        0x00010000L

When the application sets the MCI_VDISC_RESET_PROGRAM flag in lParam1, it indicates that a value is assigned in the dwProgram member.

Now that you have created the message command, flags and structure, you need to create the command table that tells MCI how to translate the equivalent string command into the message command form. Creating the command table is explained in the following section.


Creating the MCI Command Tables

The MCI parser used by mciSendString uses the command tables to tell it how to translate an MCI command string into parameters used by DriverProc. Most of these tables are stored as resources within the device driver. The resource type is RCDATA.

To allow applications to use mciSendString with any new or extended commands that your driver supports, you must create a command table to indicate how to map the string commands to the message commands.

Contents of the Command Table

A command table consists of three columns:

  • The first column contains the commands and flags used in the string form of the command. Each entry in the first column must be terminated with \0 to form a zero-terminated string.
  • The second column is a DWORD and contains the commands and flags used in the message form of the command.
  • The third column is a WORD and contains the identifiers that tell the MCI parser how to interpret each entry.

The following example shows a partial command table:

/*************************************************************/
/*   Sample command table for the MCI core command set       */
/*************************************************************/
core RCDATA
BEGIN
"open\0",              MCI_OPEN, 0,                  MCI_COMMAND_HEAD,
"\0",                MCI_INTEGER, 0,                 MCI_RETURN,
"notify\0",          MCI_NOTIFY,                     MCI_FLAG,
"wait\0",            MCI_WAIT,                       MCI_FLAG,
"test\0",            MCI_TEST,                       MCI_FLAG,
"type\0",            MCI_OPEN_TYPE,                  MCI_STRING,
"element\0",         MCI_OPEN_ELEMENT,               MCI_STRING,
"alias\0",           MCI_OPEN_ALIAS,                 MCI_STRING,
"shareable\0",       MCI_OPEN_SHAREABLE,             MCI_FLAG,
"\0",                0L,                             MCI_END_COMMAND,

"close\0",             MCI_CLOSE, 0,                 MCI_COMMAND_HEAD,
"notify\0",          MCI_NOTIFY,                     MCI_FLAG,
"wait\0",            MCI_WAIT,                       MCI_FLAG ,
"test\0",            MCI_TEST,                       MCI_FLAG,
"\0",                0L,                             MCI_END_COMMAND,

"play\0",              MCI_PLAY, 0,                  MCI_COMMAND_HEAD,
"notify\0",          MCI_NOTIFY,                     MCI_FLAG,
"wait\0",            MCI_WAIT,                       MCI_FLAG ,
"test\0",            MCI_TEST,                       MCI_FLAG,
"from\0",            MCI_FROM,                       MCI_INTEGER,
"to\0",              MCI_TO,                         MCI_INTEGER,
"\0",                0L,                             MCI_END_COMMAND,
                     .
                     .
                     .
"capability\0",        MCI_GETDEVCAPS, 0,            MCI_COMMAND_HEAD,
"\0",                MCI_INTEGER, 0,                 MCI_RETURN,
"notify\0",          MCI_NOTIFY,                     MCI_FLAG,
"wait\0",            MCI_WAIT,                       MCI_FLAG ,
"test\0",            MCI_TEST,                       MCI_FLAG,
"\0",                MCI_GETDEVCAPS_ITEM,            MCI_CONSTANT
"can record\0",      MCI_GETDEVCAPS_CAN_RECORD,      MCI_INTEGER,
"has audio\0",       MCI_GETDEVCAPS_HAS_AUDIO,       MCI_INTEGER,
"has video\0",       MCI_GETDEVCAPS_HAS_VIDEO,       MCI_INTEGER,
"uses files\0",      MCI_GETDEVCAPS_USES_FILES,      MCI_INTEGER,
"compound device\0", MCI_GETDEVCAPS_COMPOUND_DEVICE, MCI_INTEGER,
"device type\0",     MCI_GETDEVCAPS_DEVICE_TYPE,     MCI_INTEGER,
"can eject\0",       MCI_GETDEVCAPS_CAN_EJECT,       MCI_INTEGER,
"can play\0",        MCI_GETDEVCAPS_CAN_PLAY,        MCI_INTEGER,
"can save\0",        MCI_GETDEVCAPS_CAN_SAVE,        MCI_INTEGER,
"\0",                0L,                             MCI_END_CONSTANT,
"\0",                0L,                             MCI_END_COMMAND,
"resume\0",          MCI_RESUME, 0,                  MCI_COMMAND_HEAD,
"notify\0",          MCI_NOTIFY,                     MCI_FLAG,
"wait\0",            MCI_WAIT,                       MCI_FLAG,
"\0",                0L,                             MCI_END_COMMAND,
"\0",                0L,                             MCI_END_COMMAND_LIST

END

When you build your command table, ensure that the entries in the second column are DWORDs, and the entries in the third columns are WORDs. If you use any WORDs in the second columns, pad them with a comma and a zero. For example, the MCI_PLAY message in the example is followed by a comma and a zero. The zero is used as a filler to keep the command list properly aligned. Forgetting the zero after a WORD causes the remainder of the command table to be misaligned by one WORD.

A command table consists of command lists. A command list defines how to parse a particular command. For example, the following is a command list for the play command:

"play\0",            MCI_PLAY, 0,                    MCI_COMMAND_HEAD,
"notify\0",          MCI_NOTIFY,                     MCI_FLAG,
"wait\0",            MCI_WAIT,                       MCI_FLAG ,
"test\0",            MCI_TEST,                       MCI_FLAG,
"from\0",            MCI_FROM,                       MCI_INTEGER,
"to\0",              MCI_TO,                         MCI_INTEGER,
"\0",                0L,                             MCI_END_COMMAND,

This command list tells the parser which flags are valid and how to create the associated structure for the message command.

Command List and Command Table Delimiters

The first entry in a command list must have the MCI_COMMAND_HEAD delimiter in the third column. The MCI_COMMAND_HEAD delimiter designates the verb portion of the string command. For example, the play command list starts with this entry:

"play\0",            MCI_PLAY, 0,                    MCI_COMMAND_HEAD,

The last entry in a command list must have the MCI_END_COMMAND delimiter. For this last entry, the first and second columns contain "\0" and 0L. For example, all command lists end with this entry:

"\0",                0L,                             MCI_END_COMMAND,

The last entry of the command table must have the MCI_END_COMMAND_LIST delimiter. The first and second columns for this entry also contain "\0" and 0L. For example, the example command table ends with this entry:

"\0",                0L,                            MCI_END_COMMAND_LIST

Return Values

If your want to return data in your structure, you can reserve a member by having an entry in the command list with the MCI_RETURN in the third column. If you use MCI_RETURN, you must use it for the entry immediately following the MCI_COMMAND_HEAD. You can use MCI_RETURN only once in a command list. For example, the MCI_GETDEVCAPS command list starts with the following entries:

"capability\0",      MCI_GETDEVCAPS, 0,              MCI_COMMAND_HEAD,
"\0",                MCI_INTEGER, 0,                 MCI_RETURN,

The string in the first column of an entry with MCI_RETURN is "\0". (This column is ignored when you use MCI_RETURN.)

The second column of the MCI_RETURN entry specifies the type of data returned. The parser recognizes the MCI_INTEGER, MCI_STRING, and MCI_RECT keywords for the data type returned.

If you want to return an integer value, use MCI_INTEGER,0 in the second column. For integers, MCI reserves the second DWORD in the structure for the return value.

If you want to return a string value, use MCI_STRING,0 in the second column. For strings, MCI reserves the second and third DWORDs in the structure for the return value. These DWORDs correspond to a pointer to a buffer for the zero-terminated return string and the size of the buffer supplied by the application.

If you want to return a RECT value, use MCI_RECT,0 in the second column. For rectangles, MCI reserves the second and third DWORDs in the structure for the return value.

The following example adds an integer return value to the reset command:

"reset\0",           MCI_VDISC_RESET, 0,             MCI_COMMAND_HEAD,
"\0",                MCI_INTEGER, 0,                 MCI_RETURN,
"notify\0",          MCI_NOTIFY,                     MCI_FLAG,
"wait\0",            MCI_WAIT,                       MCI_FLAG,
"test\0",            MCI_TEST,                       MCI_FLAG,
"program\0",         MCI_VDISC_RESET_PROGRAM,        MCI_INTEGER,
"\0",                0L,                             MCI_END_COMMAND

The corresponding structure for the reset command using a return value is as follows:

typedef struct {
   DWORD   dwCallback;
   DWORD   dwReturn
   DWORD   dwProgram;
} MCI_VDISC_RESET_PARMS;

Command Flag Keywords

MCI interprets an entry with MCI_FLAG in the third column as a flag that is not associated with any member of the structure. For example, all commands have the following entry for the MCI_NOTIFY flag:

"notify\0",          MCI_NOTIFY,                     MCI_FLAG

The first column of this entry contain the string command used for the flag. The second column contains the value used for the flag.

Associating Command List Entries to Structures

MCI associates a command list entry with a structure member when the command list entry has MCI_INTEGER, MCI_STRING, or MCI_RECT in the third column. The order of the entries in the command list implies the order of the members in a structure. That is, the command list does not explicitly name the members of a structure.

When assigning members, MCI reserves the first member in the structure for the handle to a callback function. Thus, MCI uses the second member of the structure for data associated with the first entry needing space in the structure. MCI then assigns the third data member to the second entry needing it. This continues for the rest of the list. This association assumes that all the data members in the structure are DWORDS. You can intersperse entries that are not modified with values with those that are. For example, a command designated as an MCI_FLAG will not be associated with a member in a structure. Instead, it will designate a bit flag used in lParam1. If the MCI_FLAG entry separates two entries designated MCI_INTEGER, it would not affect the structure member assignment.

For example, the "reset" videodisc player command example would have the following form:

"reset\0",           MCI_VDISC_RESET, 0,             MCI_COMMAND_HEAD,
"notify\0",          MCI_NOTIFY,                     MCI_FLAG,
"wait\0",            MCI_WAIT,                       MCI_FLAG,
"test\0",            MCI_TEST,                       MCI_FLAG,
"program\0",         MCI_VDISC_RESET_PROGRAM,        MCI_INTEGER,
"\0",                0L,                             MCI_END_COMMAND

If you specify "\0" in the first column, it designates that entry a default entry. Any flags entered as part of a string command that does not match any entry in the command list will assume the default value. Only one default value can exist in each command list.

Using Constants

MCI uses the MCI_CONSTANT and MCI_END_CONSTANT keywords to associate a range of constants to a flag. The MCI_CONSTANT keyword reserves a DWORD in the associated structure and delimits the start of a list of constants. The following entries contain the constants. Each constant entry has the MCI_INTEGER keyword in the third column. The list of constants is ended with an entry with the MCI_END_CONSTANT keyword. For example, the set command has the following entries for the audio channel constants:

"audio\0",           MCI_SET_AUDIO,                  MCI_CONSTANT,
"all\0",             MCI_SET_AUDIO_ALL,              MCI_INTEGER,
"left\0",            MCI_SET_AUDIO_LEFT,             MCI_INTEGER,
"right\0",           MCI_SET_AUDIO_RIGHT,            MCI_INTEGER,
"\0",                0L,                             MCI_END_CONSTANT,

The constant list is actually defining a list of pre-defined integers that can be used in a string command. These pre-defined integers will be passed to your device driver in the member reserved for the flag in the structure. If the parser finds an integer following a flag rather than one of flag's pre-defined constants, the parser will assign the integer to the structure member. This lets your device driver use both constants and integers as data for a flag.

Types of Entries

The following table summarizes the keywords used to identify the type of entry in the command table:

Keyword | Description
MCI_COMMAND_HEAD | Indicates the zero-terminated string in the first column corresponds to the verb portion of the string command. The DWORD following the command corresponds to the message command passed to DriverProc as uMsg. This entry must be the first entry in the command list and it must be unique to the table.
MCI_CONSTANT | Indicates an MCI flag validating constant data. The second column contains the flag name. The structure must reserve a DWORD to hold the integer values representing the constants. A list of constants defined for the integer data immediately follows this entry.
MCI_END_COMMAND | Indicates the end of a command list. The first and second columns for this entry must contain "\0" and 0L.
MCI_END_COMMAND_LIST | Indicates the end of the command table. The first and second columns for this entry must contain "\0" and 0L.
MCI_END_CONSTANT | Indicates the end of a list of constants. The first and second columns for this entry must contain "\0" and 0L.
MCI_FLAG | Indicates an MCI flag that does not validate data. The second column contains the flag name.
MCI_INTEGER | Indicates an MCI flag validating integer data. The second column contains the flag name. The structure must reserve a DWORD to hold the integer value.
MCI_RECT | Indicates an MCI flag validating RECT data. The second column contains the flag name. The structure must reserve two DWORDs to hold the RECT value.
MCI_RETURN | Indicates a structure associated with a command has data members reserved for return information. If used, the data entry must be the second entry in the command list. The first column of the entry contains "\0". The second column contains the type of return value. If MCI_INTEGER is specified as the return type, the second DWORD in the structure is reserved for an integer return value. If MCI_STRING is specified, the second DWORD is reserved for a pointer to the return string. The third DWORD is reserved for the length of the string. If MCI_RECT is specified, the second and third DWORDs are reserved for the RECT data.
MCI_STRING | Indicates an MCI flag validating string data. The second column contains the flag name. The structure must reserve a DWORD to hold a pointer to the string data.

How the Parser Uses the Command Tables

The following description tells how the MCI parser uses the command table entries to interpret the command string "play videodisc1 notify from 10 to 20." The MCI parser reads the string to obtain the command and its destination device. The parser uses the destination to determine the device ID and assigns it to dwDeviceID of DriverProc. The parser also uses this information to determine which command table to search.

When the parser searches the command tables for "play," it searches the command tables in this order: the device-specific table (your custom command table), then the device-type table (such as the cdaudio command table), and finally the core command table.

When searching the command table, the parser searches the tables for the MCI_COMMAND_HEAD keyword. When found, the parser compares the command listed in the first column with the command from the input string. If the two commands match, the parser uses the DWORD in the second column (in this case MCI_PLAY) as the uMsg parameter for DriverProc.

The parser tries to match each subsequent parameter in the command string with a corresponding entry in the current command list. For the example, the next parameter is "notify." If the parser does not find this, it reports an error. If the parser does find it, it looks in the third column and finds MCI_FLAG. This tells the parser to use the bitwise or operation to add the second column flag MCI_NOTIFY with the bit member for the lParam1 parameter.

If the example command contained "wait" rather than notify, the parser would behave the same as for the "notify" example except that it would combine MCI_WAIT with the bit member for the lParam1 parameter.

When the parser interprets the "from" parameter, the MCI_INTEGER keyword indicates that additional data is available from the command string. The parser obtains the string value, converts it to an integer, and stores it in the DWORD of the structure corresponding to the MCI_FROM flag. The parser also combines the MCI_FROM flag in the bit member for the lParam1 parameter.

The parser processes the "to" parameter exactly as the "from" parameter except that the integer modifier is stored in DWORD of the structure corresponding to the MCI_TO flag.

The parser knows it has finished translating a command when it has reached the end of the input command string. The parser can now call DriverProc with the proper parameters.

Because the parser maps the string commands to message commands and structures passed to the driver, the order of the flags in a command string is irrelevant. The command string "play videodisc1 to 20 from 10 notify" maps exactly to the same command derived from "play videodisc1 notify from 10 to 20".

The parser checks only for syntax errors. It does not check the input string for invalid combinations of flags. Before handling any MCI command, your device driver should determine if there are invalid combinations of flags.


Providing Support for New Messages in DriverProc

When you have finished your command table, you must prepare DriverProc to handle the messages you have created. The procedures for this are the same as preparing it for existing messages.


Registering the Command Tables with MCI

The final checklist item lets the MCI parser know that you have a custom command table. Do this by making the following call in your driver's DRV_LOAD message handler:

wTableEntry = mciLoadCommandResource (hInstance, "pioneer", 0);

This example loads the resource named "pioneer," registers it with MCI, and returns a handle to that table.

If you have created a custom command table, your device driver must free the table when your device driver terminates. To free the table, include the following call in your device driver's DRV_FREE message handler:

fResult = mciFreeCommandResource (wTableEntry);

Use the table index number returned from mciLoadCommandResource as the argument to this function. This function returns TRUE if the table index number is valid.


Search Order for MCI Command Tables

MCI supports three types of tables: core, device-type, and device-specific. While parsing, the search order is from device-specific to device-type to core. When the command being searched for is found in a table, searching for that command is terminated. This means that if you have a play command in your device-specific command table, then the parser will use that one instead of the one in the device-type or core command tables.

Your command tables can reside in external files or you can bind them to your device driver. The external files are simply DLLs with only the compiled command table. A table for a device-specific command set must use the same table name used by the device driver in its mciLoadCommandResource call. They must use MCI for the extension. Avoid using the names of MCI device types as filenames. Using a device type name will prevent other devices from using the default MCI command tables.

If your device driver is a new device type and the command table it uses is type- specific (that is, it is not a custom or device-specific command table), you do not need to register the command table with mciLoadCommand Resource. When you return MCI_DEVTYPE_OTHER in the wType member of the MCI_OPEN_DRIVER_PARMS structure, MCI will automatically search for the type-specific command table. To obtain the filename, MCI searches the SYSTEM.INI file for the name of your device driver and will use this name to load your type-specific command table.

MCI gives priority to the command tables contained in external files. Thus, you can use the command tables in external files to supersede the bound command tables. For example, the command table bound with your driver could be the most commonly used table. For a foreign language version of the device driver, you could supersede the internal table with a foreign language command table by simply including it in an external file. Command tables must be in directory accessible by the Windows OpenFile function.

If you are using external files for the command tables, you might also place string resources in the file. MCI will also search for string resources in an external command files before searching for it in a bound resource.


Reference

This section contains an alphabetical list of the functions, macros, messages, and structures used by MCI device drivers. Each MCI function contains the prefix "mci" to identify the type of the function. Each MCI message contains the prefix "MCI_" to identify the type of the message.

Windows communicates with MCI device drivers through messages it sends to the driver. The driver processes these messages with its DriverProc entry-point function. A message consists of three parts: a message number and two LPARAM parameters. Message numbers are identified by predefined message names. The two LPARAM parameters contain message-dependent values.

Group | Elements
Opening a Device Driver | MCI_OPEN_DRIVER
Closing a Device Driver | MCI_CLOSE_DRIVER
Responding to the Wait Flag | mciDriverYield
Responding to the Notify Flag | mciDriverNotify
Returning Information in the MCI Structure | MAKEMCIRESOURCE
Registering Command Tables with MCI | mciFreeCommandResource mciLoadCommandResource
Using Instance Data | mciGetDriverData mciSetDriverData


Functions and Macros

The following topics describe the functions and macros used by MCI device drivers.


MAKEMCIRESOURCE

DWORD MAKEMCIRESOURCE(UINT wReturn, UINT wResource)

This macro creates an unsigned long integer by concatenating the two integer values specified by the wReturn and wResource parameters.

  • Returns an unsigned long-integer value.
wReturn
Specifies the low-order word of the new long value.
wResource
Specifies the high-order word of the new long value.

When you use an MCI structure to return integer information that also has a string equivalent, MCI needs additional information to find the string equivalent in the resource table. The high-order word of the return member is set to the resource string ID. The low-order word of the return member is set to the return value. The MAKEMCIRESOURCE macro will combine these values for the DWORD return value used in the structure.


mciDriverNotify

BOOL WINAPI mciDriverNotify(HANDLE hCallback, UINT uDeviceID,
    UINT uStatus)

This function is used by a driver to post a notification message. MCI devices use this function only when the MCI_NOTIFY flag is used with an MCI command message.

  • Returns TRUE if a notification was successfully sent.
hCallback
Specifies the handle of the window to notify.
uDeviceID
Specifies the device ID which triggered the callback.
uStatus
Specifies the status of the callback. Status values include:
MCI_NOTIFY_ABORTED | Specifies that the device received a command that prevented the current conditions for initiating the callback from being met. If a new command interrupts the current command and it also requests notification, send this message and not MCI_NOTIFY_SUPERSEDED.
MCI_NOTIFY_SUCCESSFUL | Specifies that the conditions initiating the callback have been met.
MCI_NOTIFY_SUPERSEDED | Specifies that the device received another command with the MCI_NOTIFY flag set and the current conditions for initiating the callback have been superseded.
MCI_NOTIFY_FAILURE | Specifies that a device error occurred while the device was executing the command.

This function is callable at interrupt time.

A device sends MCI_NOTIFY_SUCCESSFUL when the action for a command finishes. For example, a CD audio device uses this flag for notification for MCI_PLAY when the device finishes playing. The MCI_PLAY command completes successfully only when it reaches the specified end position or reaches the end of the media. Similarly, MCI_SEEK and MCI_RECORD do not return MCI_NOTIFY_SUCCESSFUL until they reach the specified end position or reach the end of the media.

A device sends MCI_NOTIFY_ABORTED only when it receives a command that prevents it from meeting the notification conditions. For example, the command MCI_PLAY would not abort notification for a previous play command provided that the new command does not change the play direction or change the ending position for the play command with an active notify. The MCI_RECORD and MCI_SEEK commands behave similarly.

Do not send MCI_NOTIFY_ABORTED when MCI_PLAY or MCI_RECORD is paused with MCI_PAUSE. The MCI_RESUME command delays completion of MCI_PLAY and MCI_RECORD but does not cancel the commands. The MCI_RESUME command will let them continue to meet the callback conditions.

If a device cannot execute a command, set the error return for the message but do not send a notification message.


mciDriverYield

UINT WINAPI mciDriverYield(UINT uDeviceID)

This function is used in a driver's idle loop to yield to Windows.

  • Returns a nonzero value if the driver should abort the operation because the break key was pressed.
uDeviceID
Device ID that is yielding.


mciFreeCommandResource

BOOL WINAPI mciFreeCommandResource(UINT wuable)

This function frees the memory used by the specified command table.

  • Returns FALSE if the table index is not valid.
uTable
The table index returned from a previous call to mciLoadCommandResource.


mciGetDriverData

DWORD WINAPI mciGetDriverData(uUINT DeviceID)

This function returns a pointer to the instance data associated with an MCI device.

  • Returns the driver instance data. On error, it returns zero. Since the driver data might be zero, this cannot be verified by the caller unless the instance data is known to be nonzero (for example, a pointer).
uDeviceID
Specifies the MCI device ID.


mciLoadCommandResource

UINT WINAPI mciLoadCommandResource(HANDLE hInstance, LPCSTR lpResName, UINT uType)

This function registers the indicated resource as an MCI command table. If a file with the resource name and the extension ".mci" is found in the path then the resource is taken from that file.

  • Returns the command table index number that was assigned or MCI_NO_COMMAND_TABLE on error.
hInstance
The instance of the module whose executable file contains the resource. This parameter is ignored if an external file is found.
lpResName
Specifies the name of the resource.
uType
Specifies the device type. Custom device-specific tables must give a type of zero.


mciSetDriverData

BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD dwData)

This function sets the instance data associated with an MCI device.

  • Returns zero if the device ID is not known or there is insufficient memory to load the device description.
uDeviceID
Specifies the MCI device ID.
dwData
Specifies the driver data to set.

Typically device drivers set the data when it is opened. The device driver will then retrieve the data with mciGetDriverData in response to subsequent messages.


Messages from the System

The following topics describe the system messages.


MCI_CLOSE_DRIVER

dwFlags = (DWORD) lParam1; // MCI flags
lpMCI_CLOSE_PARMS =
    (LPMCI_GENERIC_PARMS) lParam2; // Pointer to MCI_GENERIC_PARMS
                                   // structure.

This message is the version of the MCI_CLOSE command sent from MCI to an MCI device.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
lParam1
Contains the flags specified in the MCI_CLOSE message.
lParam2
Specifies a far pointer to the MCI_GENERIC_PARMS structure.

An MCI internal procedure intercepts the MCI_CLOSE message sent by an application. After processing, the procedure calls the device with MCI_CLOSE_DRIVER and DRV_CLOSE. Windows will always close the driver following the MCI_CLOSE_DRIVER message.

If an application sets the MCI_NOTIFY flag, a device driver should send MM_MCINOTIFY just before returning from MCI_CLOSE_DRIVER.


MCI_OPEN_DRIVER

dwFlags = (DWORD) lParam1; // MCI flags
lpMCI_OPEN_PARMS =
    (LPMCI_OPEN_PARMS) lParam2; // Pointer to MCI_OPEN_PARMS
                                // structure.

This message is the version of the MCI_OPEN command sent by MCI to an MCI device.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
lParam1
Contains the flags specified in the MCI_OPEN message.
lParam2
Specifies a far pointer to the MCI_OPEN_PARMS structure. This structure contains the information passed by the MCI_OPEN call from the application.

An MCI internal procedure intercepts the MCI_OPEN message sent by an application. After processing, the procedure calls the device with DRV_OPEN and MCI_OPEN_DRIVER.


Messages from Applications

The following topics describe the application messages.


MCI_CLOSE

Releases access to a device or device element. All devices respond to this message. MMSYSTEM translates this message to the DRV_CLOSE and MCI_CLOSE_DRIVER messages sent to the device driver.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following flags apply to all devices:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lpDefault. Device drivers should send MM_MCINOTIFY just before returning from MCI_CLOSE_DRIVER.
MCI_WAIT | Specifies that the close operation should finish before MCI returns control to the application.

LPMCI_GENERIC_PARMS lParam2
Specifies a far pointer to the MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Exiting an application without closing any MCI devices it has opened can leave the device opened and not accessible. Your application should explicitly close each device or device element when it is finished with it. MCI unloads the device when all instances of the device or all device elements are closed.

See Also

MCI_CLOSE_DRIVER, MCI_OPEN, MCI_OPEN_DRIVER


MCI_COPY

Copies data to the Clipboard. Support of this message by a device is optional. The parameters and flags for this message vary according to the selected device.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following flags apply to all devices supporting MCI_COPY:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lpCopy.
MCI_WAIT | Specifies that the copy should finish before MCI returns control to the application.

LPMCI_GENERIC_PARMS lParam2
Specifies a far pointer to an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

This command is not used by the device drivers supplied with the Microsoft Windows Software Development Kit.

See Also

MCI_CUT, MCI_DELETE, MCI_PASTE


MCI_CUE

Cues a device so that playback or recording begins with minimum delay. Support of this message by a device is optional. The parameters and flags for this message vary according to the selected device.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following flags apply to all devices supporting MCI_CUE:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lParam2.
MCI_WAIT | Specifies that the cue operation should finish before MCI returns control to the application.

LPMCI_GENERIC_PARMS lParam2
Specifies a far pointer to the MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Waveform Audio Extensions

The following additional flags for lParam1 apply to wave audio devices:

MCI_WAVE_INPUT | Specifies that a wave input device should be cued.
MCI_WAVE_OUTPUT | Specifies that a wave output device should be cued. This is the default flag if a flag is not specified.

Note that lParam2 specifies a far pointer to the MCI_GENERIC_PARMS structure.

See Also

MCI_PLAY, MCI_RECORD, MCI_SEEK


MCI_CUT

Removes data from the MCI element and copies it to the Clipboard. Support of this message by a device is optional. The parameters and flags for this message vary according to the selected device.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following flags apply to all devices supporting MCI_CUT:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lpCut.
MCI_WAIT | Specifies that the cut operation should finish before MCI returns control to the application.

LPMCI_GENERIC_PARMS lParam2
Specifies a far pointer to an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

This command is not used by the device drivers supplied with the Microsoft Windows Software Development Kit.

See Aso

MCI_COPY, MCI_DELETE, MCI_PASTE

Built on Wednesday, July 11, 2001


MCI_DELETE

Removes data from the MCI element. Support of this message by a device is optional. The parameters and flags for this message vary according to the selected device.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following flags apply to all devices supporting MCI_DELETE:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lParam2.
MCI_WAIT | Specifies that the delete operation should finish before MCI returns control to the application.

LPMCI_GENERIC_PARMS lParam2
Specifies a far pointer to an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Waveform Audio Extensions

The following extensions for lParam1 apply to wave audio devices:

MCI_FROM | Specifies that a beginning position is included in the dwFrom member of the structure identified by lParam2. The units assigned to the position values is specified with the MCI_SET_TIME_FORMAT flag of the MCI_SET command.
MCI_TO | Specifies that an ending position is included in the dwTo member of the structure identified by lParam2. The units assigned to the position values is specified with the MCI_SET_TIME_FORMAT flag of the MCI_SET command.

Note that lParam2 specifies a far pointer to an MCI_WAVE_DELETE_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

See Also

MCI_COPY, MCI_DELETE, MCI_PASTE


MCI_ESCAPE

Sends a string directly to the device. This message is part of the videodisc command set. The parameters and flags for this message vary according to the selected device.

  • Return value is zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following flags apply to all devices supporting MCI_COMMAND:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lpEscape
MCI_WAIT | Specifies that the operation should finish before MCI returns control to the application.
MCI_VD_ESCAPE_STRING | Indicates a command string is specified in the lpstrCommand member of the structure identified by lpEscape. This flag is required.

LPMCI_VD_ESCAPE_PARMS lParam2
Specifies a far pointer to the MCI_VD_ESCAPE_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

The data sent with MCI_ESCAPE is device dependent and is usually passed directly to the hardware associated with the device.


MCI_FREEZE

Freezes motion on the display. This command is part of the video overlay command set. The parameters and flags for this message vary according to the selected device.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following flags apply to all devices supporting MCI_FREEZE:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lpFreeze.
MCI_WAIT | Specifies that the freeze operation should finish before MCI returns control to the application.
MCI_OVLY_RECT | Specifies that the rc member of the structure identified by lpFreeze contains a valid rectangle. If this flag is not specified, the device driver will freeze the entire frame.

LPMCI_OVLY_RECT_PARMS lParam2
Specifies a far pointer to a MCI_OVLY_RECT_PARMS structure. (Devices with additional parameters might replace this structure with a device-specific structure.)

See Also

MCI_UNFREEZE


MCI_GETDEVCAPS

Used to obtain static information about a device. All devices must respond to this message. The parameters and flags available for this message depend on the selected device. Information is returned in the dwReturn member of the structure identified by lpCapsParms.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following standard and command-specific flags apply to all devices:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lpCapsParms.
MCI_WAIT | Specifies that the query operation should finish before MCI returns control to the application.
MCI_GETDEVCAPS_ITEM | Specifies that the dwItem member of the structure identified by lpCapsParms contains a constant specifying which device capability to obtain. The following constants define which capability to return in the dwReturn member of the structure:
MCI_GETDEVCAPS_CAN_EJECT | The dwReturn member is set to TRUE if the device can eject the media; otherwise, it is set to FALSE.
MCI_GETDEVCAPS_CAN_PLAY | The dwReturn member is set to TRUE if the device can play the media; otherwise, it is set to FALSE. <pIf a device specifies TRUE, it implies the device supports MCI_PAUSE and MCI_STOP as well as MCI_PLAY.
MCI_GETDEVCAPS_CAN_RECORD The dwReturn member is set to TRUE if the device supports recording; otherwise, it is set to FALSE.

If a device specifies TRUE, it implies the device supports MCI_PAUSE and MCI_STOP as well as MCI_RECORD.

MCI_GETDEVCAPS_CAN_SAVE | The dwReturn member is set to TRUE if the device can save a file; otherwise, it is set to FALSE.
MCI_GETDEVCAPS_COMPOUND_DEVICE | The dwReturn member is set to TRUE if the device uses device elements; otherwise, it is set to FALSE.
MCI_GETDEVCAPS_DEVICE_TYPE | The dwReturn member is set to one of the following values indicating the device type:

MCI_DEVTYPE_ANIMATION
MCI_DEVTYPE_CD_AUDIO
MCI_DEVTYPE_DAT
MCI_DEVTYPE_DIGITAL_VIDEO
MCI_DEVTYPE_OTHER
MCI_DEVTYPE_OVERLAY
MCI_DEVTYPE_SCANNER
MCI_DEVTYPE_SEQUENCER
MCI_DEVTYPE_VIDEODISC
MCI_DEVTYPE_VIDEOTAPE
MCI_DEVTYPE_WAVEFORM_AUDIO

MCI_GETDEVCAPS_HAS_AUDIO | The dwReturn member is set to TRUE if the device has audio output; otherwise, it is set to FALSE.
MCI_GETDEVCAPS_HAS_VIDEO | The dwReturn member is set to TRUE if the device has video output; otherwise, it is set to FALSE. For example, the member is set to TRUE for devices that support the animation or videodisc command set.
MCI_GETDEVCAPS_USES_FILES The dwReturn member is set to TRUE if the device requires a filename as its element name; otherwise, it is set to FALSE.

Only compound devices use files.

LPMCI_GETDEVCAPS_PARMS lParam2
Specifies a far pointer to the MCI_GETDEVCAPS_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Animation Extensions

The following extensions for lParam1apply to animation devices:

MCI_GETDEVCAPS_ITEM | Specifies that the dwItem member of the structure identified by lParam2 contains a constant specifying which device capability to obtain. The following additional device-capability constants are defined for animation devices and specify which value to return in the dwReturn member of the structure:
MCI_ANIM_GETDEVCAPS_CAN_REVERSE | The dwReturn member is set to TRUE if the device can play in reverse; otherwise, it is set to FALSE.
MCI_ANIM_GETDEVCAPS_CAN_STRETCH | The dwReturn member is set to TRUE if the device can stretch the image to fill the frame; otherwise, it is set to FALSE.
MCI_ANIM_GETDEVCAPS_FAST_RATE | The dwReturn member is set to the standard fast play rate in frames per second.
MCI_ANIM_GETDEVCAPS_MAX_WINDOWS | The dwReturn member is set to the maximum number of windows that the device can handle simultaneously.
MCI_ANIM_GETDEVCAPS_NORMAL_RATE | The dwReturn member is set to the normal rate of play in frames per second.
MCI_ANIM_GETDEVCAPS_PALETTES | The dwReturn member is set to TRUE if the device can return a palette handle; otherwise, it is set to FALSE.
MCI_ANIM_GETDEVCAPS_SLOW_RATE | The dwReturn member is set to the standard slow play rate in frames per second.

Note that lParam2 specifies a far pointer to the MCI_GETDEVCAPS_PARMS structure.

Videodisc Extensions

The following extensions for lParam1apply to videodisc devices:

MCI_GETDEVCAPS_ITEM | Specifies that the dwItem member of the structure identified by lParam2 contains a constant specifying which device capability to obtain. The following additional device-capability constants are defined for videodisc devices and specify which value to return in the dwReturn member of the structure:
MCI_VD_GETDEVCAPS_CAN_REVERSE | The dwReturn member is set to TRUE if the videodisc player can play in reverse; otherwise, it is set to FALSE.
 | Some players can play CLV discs in reverse as well as CAV discs.
MCI_VD_GETDEVCAPS_FAST_RATE | The dwReturn member is set to the standard fast play rate in frames per second.
MCI_VD_GETDEVCAPS_NORMAL_RATE | The dwReturn member is set to the normal play rate in frames per second.
MCI_VD_GETDEVCAPS_SLOW_RATE | The dwReturn member is set to the slow play rate in frames per second.
MCI_VD_GETDEVCAPS_CLV | Indicates the information requested applies to CLV format discs. By default, the capabilities apply to the current disc.
MCI_VD_GETDEVCAPS_CAV | Indicates the information requested applies to CAV format discs. By default, the capabilities apply to the current disc.

Note that lParam2 specifies a far pointer to the MCI_GETDEVCAPS_PARMS structure.

Video Overlay Extensions

The following extensions for lParam1 apply to video overlay devices:

MCI_GETDEVCAPS_ITEM | Specifies that the dwItem member of the structure identified by lParam2 contains a constant specifying which device capability to obtain. The following additional device-capability constants are defined for video overlay devices and specify which value to return in the dwReturn member of the structure:
MCI_OVLY_GETDEVCAPS_CAN_FREEZE | The dwReturn member is set to TRUE if the device can freeze the image; otherwise, it is set to FALSE.
MCI_OVLY_GETDEVCAPS_CAN_STRETCH | The dwReturn member is set to TRUE if the device can stretch the image to fill the frame; otherwise, it is set to FALSE.
MCI_OVLY_GETDEVCAPS_MAX_WINDOWS | The dwReturn member is set to the maximum number of windows that the device can handle simultaneously.

Note that lParam2 specifies a far pointer to the MCI_GETDEVCAPS_PARMS structure.

Waveform Audio Extensions

The following extended flag for lParam1 applies to waveform audio devices:

MCI_GETDEVCAPS_ITEM | Specifies that the dwItem member of the structure identified by lParam2 contains a constant specifying which device capability to obtain. The following additional device-capability constants are defined for waveform audio devices and specify which value to return in the dwReturn member of the structure:
MCI_WAVE_GETDEVCAPS_INPUT | The dwReturn member is set to the total number of waveform input (recording) devices.
MCI_WAVE_GETDEVCAPS_OUTPUT | The dwReturn member is set to the total number of waveform output (playback) devices.

Note that lParam2 specifies a far pointer to the MCI_GETDEVCAPS_PARMS structure.


MCI_INFO

Obtains string information from a device. All devices respond to this message. The parameters and flags available for this message depend on the selected device. Information is returned in the lpstrReturn member of the structure identified by lpInfo. The dwReturnSize member specifies the buffer length for the return data.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following standard and command-specific flags apply to all devices:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lpInfo.
MCI_WAIT | Specifies that the query operation should finish before MCI returns control to the application.
MCI_INFO_PRODUCT | Obtains a description of the hardware associated with a device. Devices should supply a description that identifies both the driver and the hardware used.

LPMCI_INFO_PARMS lParam2
Specifies a far pointer to the MCI_INFO_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Animation Extensions

The following additional flags for lParam1apply to animation devices:

MCI_INFO_FILE | Obtains the filename of the current file. This flag is only supported by devices that return TRUE to the MCI_GETDEVCAPS_USES_FILES query.
MCI_ANIM_INFO_TEXT | Obtains the window caption.

Note that lParam2specifies a far pointer to the MCI_INFO_PARMS structure.

Video Overlay Extensions

The following additional flags for lParam1apply to video overlay devices:

MCI_INFO_FILE | Obtains the filename of the current file. This flag is only supported by devices that return TRUE to the MCI_GETDEVCAPS_USES_FILES query.
MCI_OVLY_INFO_TEXT | Obtains the caption of the window associated with the overlay device.

Note that lParam2 specifies a far pointer to the MCI_INFO_PARMS structure.

Waveform Audio Extensions

The following additional flags for lParam1 apply to waveform audio devices:

MCI_INFO_FILE | Obtains the filename of the current file. This flag is supported by devices that return TRUE to the MCI_GETDEVCAPS_USES_FILES query.
MCI_WAVE_INPUT | Obtains the product name of the current input.
MCI_WAVE_OUTPUT | Obtains the product name of the current output.

Note that lParam2 specifies a far pointer to the MCI_INFO_PARMS structure.

If an application requests return-string information and it does not supply a buffer large enough to hold it, your device driver should fill the buffer and truncate the string. Return MCIERR_PARAM_OVERFLOW to indicate the information in the buffer was truncated.


MCI_LOAD

Loads a file. Support of this message by a device is optional. The parameters and flags for this message vary according to the selected device.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following flags apply to all devices supporting MCI_LOAD:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lpLoad.
MCI_WAIT | Specifies that the load operation should finish before MCI returns control to the application.
MCI_LOAD_FILE | Indicates the lpfilename member of the structure identified by lpLoad contains a pointer to a buffer containing the file name.

LPMCI_LOAD_PARMS lParam2
Specifies a far pointer to the MCI_LOAD_PARMS structure. (Devices with additional parameters might replace this structure with a device-specific structure.)

Video Overlay Extensions

The following additional flags for lParam1apply to video overlay devices supporting MCI_LOAD:

MCI_OVLY_RECT Specifies that the rc member of the structure identified by lParam2 contains a valid display rectangle that identifies the area of the video buffer to update.

Note that lParam2 specifies a far pointer to a MCI_OVLY_LOAD_PARMS structure.

See Also

MCI_SAVE


MCI_OPEN

Initializes a device or device element. All devices respond to this message. The parameters and flags available for this message depend on the selected device. MMSYSTEM translates this message to the DRV_OPEN and MCI_OPEN_DRIVER messages sent to the device driver.

  • Returns zero if the open is successful. If an error occurs, it returns the following values:
MCIERR_CANNOT_LOAD_DRIVER | Error loading media device driver.
MCIERR_DEVICE_OPEN | The device name is in use by this task. Use a unique alias.
MCIERR_DUPLICATE_ALIAS | The specified alias is an open device in this task.
MCIERR_EXTENSION_NOT_FOUND | Cannot deduce a device type from the given extension.
MCIERR_FILENAME_REQUIRED | A valid filename is required.
MCIERR_MISSING_PARAMETER | Required parameter is missing.
MCIERR_MUST_USE_SHAREABLE | The device is already open; use the shareable flag with each open.
MCIERR_NO_ELEMENT_ALLOWED | An element name cannot be used with this device.

DWORD lParam1
The following flags apply to all devices:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lpOpen.
MCI_WAIT | Specifies that the open operation should finish before MCI returns control to the application.
MCI_OPEN_ALIAS | Specifies that an alias is included in the lpstrAlias member of the structure identified by lpOpen.
MCI_OPEN_SHAREABLE | Specifies that the device or device element should be opened as shareable.
MCI_OPEN_TYPE | Specifies that a device type name or constant is included in the lpstrDeviceType member of the structure identified by lpOpen.
MCI_OPEN_TYPE_ID | Specifies that the low-order word of the lpstrDeviceType member of the associated structure contains a standard MCI device type ID and the high-order word optionally contains the ordinal index for the device. Use this flag with the MCI_OPEN_TYPE flag.

LPMCI_OPEN_PARMS lParam2
Specifies a far pointer to the MCI_OPEN_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Flags for Compound Devices

DWORD lParam1 The following additional flags apply to compound devices:

MCI_OPEN_ELEMENT | Specifies that an element name is included in the lpstrElementName member of the structure identified by lParam2.
MCI_OPEN_ELEMENT_ID | Specifies that the lpstrElementName member of the structure identified by lParam2 is interpreted as a DWORD and has meaning internal to the device. Use this flag with the MCI_OPEN_ELEMENT flag.

LPMCI_OPEN_PARMS lParam2 Specifies a far pointer to the MCI_OPEN_PARMS structure. (Devices with additional parameters might replace this structure with a device-specific structure.)

Animation Extensions

The following flags for lParam1apply to animation devices:

MCI_ANIM_OPEN_NOSTATIC | Specifies that the device should reduce the number of static (system) colors in the palette to two.
MCI_ANIM_OPEN_PARENT | Indicates the parent window handle is specified in the hWndParent member of the structure identified by lParam2. The parent window handle is required for some window styles.
MCI_ANIM_OPEN_WS | Indicates a window style is specified in the dwStyle member of the structure identified by lParam2. The dwStyle value specifies the style of the window that the driver will create and display if the application does not provide one. The style parameter takes an integer which defines the window style. These constants are the same as the ones in WINDOWS.H (such as WS_CHILD, WS_OVERLAPPEDWINDOW, or WS_POPUP).

Note that lParam2 specifies a far pointer to the MCI_ANIM_OPEN_PARMS structure.

Video Overlay Extensions

The following flags for lParam1 apply to video overlay devices:

MCI_OVLY_OPEN_PARENT | Indicates the parent window handle is specified in the hWndParent member of the structure identified by lParam2.
MCI_OVLY_OPEN_WS | Indicates a window style is specified in the dwStyle member of the structure identified by lParam2. The dwStyle value specifies the style of the window that the driver will create and display if the application does not provide one. The style parameter takes an integer that defines the window style. These constants are the same as those in WINDOWS.H (for example, WS_CHILD, WS_OVERLAPPEDWINDOW, or WS_POPUP).

Note that lParam2 specifies a far pointer to the MCI_OVLY_OPEN_PARMS structure.

Waveform Audio Extensions

The following flags for lParam1 apply to waveform audio devices:

MCI_WAVE_OPEN_BUFFER Indicates a buffer length is specified in the dwBuffer member of the structure identified by lParam2.

Note that lParam2 specifies a far pointer to the MCI_WAVE_OPEN_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

If MCI_OPEN_SHAREABLE is not specified when a device or device element is initially opened, then all subsequent MCI_OPEN messages to the device or device element will fail. If the device or device element is already open, and this flag is not specified, the call will fail even if the first open command specified MCI_OPEN_SHAREABLE. Files for the MCISEQ and MCIWAVE devices are nonshareable.

Case is ignored in the device name, but there must not be any leading or trailing blanks.

To use automatic type selection (via the [mci extensions] section of the WIN.INI file), assign the file name (including file extension) to the lpstrElementName member, assign a NULL pointer to the lpstrDeviceType member, and set the MCI_OPEN_ELEMENT flag.

See Also

MCI_CLOSE, MCI_CLOSE_DRIVER, MCI_OPEN_DRIVER


MCI_PASTE

Pastes data from the clipboard into a device element.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following flags apply to all devices supporting MCI_PASTE:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lpPaste.
MCI_WAIT | Specifies that the device should complete the operation before MCI returns control to the application.

LPMCI_GENERIC_PARMS lParam2
Specifies a far pointer to the MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

This command is not used by the MCI device drivers supplied with the Microsoft Windows Software Development Kit.

See Also

MCI_COPY, MCI_CUT, MCI_DELETE


MCI_PAUSE

Pauses the current action.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following flags apply to all devices supporting MCI_PAUSE:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lParam2.
MCI_WAIT | Specifies that the device should be paused before MCI returns control to the application.

LPMCI_GENERIC_PARMS lParam2
Specifies a far pointer to the MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

The difference between MCI_STOP and MCI_PAUSE depends upon the device. If possible, MCI_PAUSE suspends device operation but leaves the device ready to resume play immediately.

See Also

MCI_PLAY, MCI_RECORD, MCI_RESUME, MCI_STOP


MCI_PLAY

Signals the device to begin transmitting output data. Support of this message by a device is optional. The parameters and flags for this message vary according to the selected device.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following flags apply to all devices supporting MCI_PLAY:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lpPlay.
MCI_WAIT | Specifies that the play operation should finish before MCI returns control to the application.
MCI_FROM | Specifies that a starting position is included in the dwFrom member of the structure identified by lpPlay. The units assigned to the position values is specified with the MCI_SET_TIME_FORMAT flag of the MCI_SET command. If MCI_FROM is not specified, the starting position defaults to the current location.
MCI_TO | Specifies that an ending position is included in the dwTo member of the structure identified by lpPlay. The units assigned to the position values is specified with the MCI_SET_TIME_FORMAT flag of the MCI_SET command. If MCI_TO is not specified, the end position defaults to the end of the media.

LPMCI_PLAY_PARMS lParam2
Specifies a far pointer to an MCI_PLAY_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Animation Extensions

The following additional flags for lParam1apply to animation devices:

MCI_ANIM_PLAY_FAST | Specifies to play fast.
MCI_ANIM_PLAY_REVERSE | Specifies to play in reverse.
MCI_ANIM_PLAY_SCAN | Specifies to scan quickly.
MCI_ANIM_PLAY_SLOW | Specifies to play slowly.
MCI_ANIM_PLAY_SPEED | Specifies that the play speed is included in the dwSpeed member in the structure identified by lParam2.

Note that lParam2 specifies a far pointer to an MCI_ANIM_PLAY_PARMS structure.

Videodisc Extensions

The following additional flags for lParam1apply to videodisc devices:

MCI_VD_PLAY_FAST | Specifies to play fast.
MCI_VD_PLAY_REVERSE | Specifies to play in reverse.
MCI_VD_PLAY_SCAN | Specifies to scan quickly.
MCI_VD_PLAY_SLOW | Specifies to play slowly.
MCI_VD_PLAY_SPEED | Specifies that the play speed is included in the dwSpeed member in the structure identified by lParam2.

Note that lParam2 specifies a far pointer to an MCI_VD_PLAY_PARMS structure.

See Also

MCI_CUE, MCI_PAUSE, MCI_RECORD, MCI_RESUME, MCI_SEEK, MCI_STOP


MCI_PUT

Sets the source, destination, and frame rectangles. The parameters and flags for this message vary according to the selected device.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following flags apply to all devices supporting MCI_PUT:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lpDest.
MCI_WAIT | Specifies that the operation should finish before MCI returns control to the application.

LPMCI_GENERIC_PARMS lParam2
Specifies a far pointer to an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Animation Extensions

The following additional flags for lParam1 apply to animation devices supporting MCI_PUT:

MCI_ANIM_RECT | Specifies that the rc member of the structure identified by lParam2 contains a valid rectangle. If this flag is not specified, the default rectangle matches the coordinates of the image or window being clipped.
MCI_ANIM_PUT_DESTINATION | Indicates the rectangle defined for MCI_ANIM_RECT specifies the area of the client window used to display an image. The rectangle contains the offset and visible extent of the image relative to the window origin. If the frame is being stretched, the source is stretched to the destination rectangle.
MCI_ANIM_PUT_SOURCE | Indicates the rectangle defined for MCI_ANIM_RECT specifies a clipping rectangle for the animation image. The rectangle contains the offset and extent of the image relative to the image origin.

Note that lParam2 specifies a far pointer to a MCI_ANIM_RECT_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Video Overlay Extensions

The following additional flags for lParam1 apply to video overlay devices supporting MCI_PUT:

MCI_OVLY_RECT | Specifies that the rc member of the structure identified by lParam2 contains a valid display rectangle. If this flag is not specified, the default rectangle matches the coordinates of the video buffer or window being clipped.
MCI_OVLY_PUT_DESTINATION | Indicates the rectangle defined for MCI_OVLY_RECT specifies the area of the client window used to display an image. The rectangle contains the offset and visible extent of the image relative to the window origin. If the frame is being stretched, the source is stretched to the destination rectangle.
MCI_OVLY_PUT_FRAME | Indicates the rectangle defined for MCI_OVLY_RECT specifies the area of the video buffer used to receive the video image. The rectangle contains the offset and extent of the buffer area relative to the video buffer origin.
MCI_OVLY_PUT_SOURCE | Indicates that the rectangle defined for MCI_OVLY_RECT specifies the area of the video buffer used as the source of the digital image. The rectangle contains the offset and extent of the clipping rectangle for the video buffer relative to its origin.
MCI_OVLY_PUT_VIDEO | Indicates that the rectangle defined for MCI_OVLY_RECT specifies the area of the video source capture by the video buffer. The rectangle contains the offset and extent of the clipping rectangle for the video source relative to its origin.

Note that lParam2specifies a far pointer to a MCI_OVLY_RECT_PARMS structure.

See Also

MCI_WHERE


MCI_REALIZE

Tells a graphic device to realize its palette into a device context. This is part of the animation command set. The parameters and flags for this message vary according to the selected device.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following flags apply to all devices supporting MCI_REALIZE:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lpRealize.
MCI_WAIT | Specifies that the palette should be realized before MCI returns control to the application.
MCI_ANIM_PAL_BKGD | If this flag is set, the palette is realized as a background palette.
MCI_ANIM_PAL_NORM | If this flag is set, the palette is realized normally. This is the default action.

LPMCI_GENERIC_PARMS lParam2
Specifies a far pointer to a MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

This command is supported by devices that return true to the MCI_GETDEVCAPS_PALETTES query.


MCI_RECORD

Starts recording from the current position or from the specified position until the specified position. Support of this message by a device is optional. The parameters and flags for this message vary according to the selected device.

  • Returns zero if successful. Otherwise, it returns an MCI error code. MCISEQ returns MCIERR_UNSUPPORTED_FUNCTION for this command.
DWORD lParam1
The following flags apply to all devices supporting MCI_RECORD:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lpRecord.
MCI_WAIT | Specifies that recording should finish before MCI returns control to the application.
MCI_RECORD_INSERT | Indicates that newly recorded information should be inserted or pasted into the existing data. (Some devices may not support this.) If supported, this is the default.
MCI_FROM | Specifies that a starting position is included in the dwFrom member of the structure identified by lpRecord. The units assigned to the position values is specified with the MCI_SET_TIME_FORMAT flag of the MCI_SET command. If MCI_FROM is not specified, the starting position defaults to the current location.
MCI_RECORD_OVERWRITE | Specifies that data should overwrite existing data. MCIWAVE returns MCIERR_UNSUPPORTED_FUNCTION in response to this flag.
MCI_TO | Specifies that an ending position is included in the dwTo member of the structure identified by lpRecord. The units assigned to the position values is specified with the MCI_SET_TIME_FORMAT flag of the MCI_SET command. If MCI_TO is not specified, the ending position defaults to the end of the media.

LPMCI_RECORD_PARMS lParam2
Specifies a far pointer to the MCI_RECORD_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

This command is supported by devices that return TRUE to the MCI_GETDEVCAPS_CAN_RECORD query.

See Also

MCI_CUE, MCI_PAUSE, MCI_PLAY, MCI_RESUME, MCI_SEEK


MCI_RESUME

Resumes a paused device. Support of this message by a device is optional.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following flags apply to all devices supporting MCI_RESUME:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lParam2.
MCI_WAIT | Specifies that the device should resume before MCI returns control to the application.

LPMCI_GENERIC_PARMS lParam2
Specifies a far pointer to the MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

This command resumes playing and recording without changing the stop position set with MCI_PLAY or MCI_RECORD.

See Also

MCI_PLAY, MCI_RECORD, MCI_STOP


MCI_SAVE

Saves the current file. Devices which modify files should not destroy the original copy until they receive the save message. Support of this message by a device is optional. The parameters and flags for this message vary according to the selected device.

  • Returns zero if successful. Otherwise, it returns an MCI error code. MCISEQ returns MCIERR_UNSUPPORTED_FUNCTION.
DWORD lParam1
The following flags apply to all devices supporting MCI_SAVE:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lpSave.
MCI_WAIT | Specifies that the save operation should finish before MCI returns control to the application.
MCI_SAVE_FILE | Indicates the lpfilename member of the structure identified by lpSave contains a pointer to a buffer containing the destination filename.

LPMCI_SAVE_PARMS lParam2
Specifies a far pointer to the MCI_SAVE_PARMS structure. (Devices with additional parameters might replace this structure with a device-specific structure.)

Video Overlay Extensions

The following additional flags for lParam1 apply to video overlay devices supporting MCI_SAVE:

MCI_OVLY_RECT Specifies that the rc member of the structure identified by lParam2 contains a valid display rectangle indicating the area of the video buffer to save.

Note that lParam2specifies a far pointer to a MCI_OVLY_SAVE_PARMS structure.

This command is supported by devices that return true to the MCI_GETDEVCAPS_CAN_SAVE query. MCIWAVE supports this command.

See Also

MCI_LOAD


MCI_SEEK

Changes the current position of media as quickly as possible. Video and audio output are disable during the seek. After the seek is complete, the device will be stopped. Support of this message by a device is optional. The parameters and flags for this message vary according to the selected device.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following flags apply to all devices supporting MCI_SEEK:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lpSeek.
MCI_WAIT | Specifies that the seek operation should finish before MCI returns control to the application.
MCI_SEEK_TO_END | Specifies to seek to the end of the media.
MCI_SEEK_TO_START | Specifies to seek to the start of the media.
MCI_TO | Specifies a position is included in the dwTo member of the MCI_SEEK_PARMS structure. The units assigned to the position values is specified with the MCI_SET_TIME_FORMAT flag of the MCI_SET command. Do not use this flag with MCI_SEEK_END or MCI_SEEK_START.

LPMCI_SEEK_PARMS lParam2
Specifies a far pointer to the MCI_SEEK_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Videodisc Extensions

The following additional flag for lParam1 applies to videodisc devices.

MCI_VD_SEEK_REVERSE Specifies to seek backward.

Note that lParam2 specifies a far pointer to the MCI_SEEK_PARMS structure.

See Also

MCI_PLAY, MCI_RECORD


MCI_SET

Sets device information. Support of this message by a device is optional. The parameters and flags for this message vary according to the selected device.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following flags apply to all devices supporting MCI_SET:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lpSet.
MCI_WAIT | Specifies that the set operation should finish before MCI returns control to the application.
MCI_SET_AUDIO | Specifies an audio channel number is included in the dwAudio member of the structure identified by lpSet. This flag must be used with MCI_SET_ON or MCI_SET_OFF. Use one of the following constants to indicate the channel number:

MCI_SET_AUDIO_ALL | Specifies all audio channels.
MCI_SET_AUDIO_LEFT | Specifies the left channel.
MCI_SET_AUDIO_RIGHT | Specifies the right channel.

MCI_SET_DOOR_CLOSED | Instructs the device to close the media cover (if any).
MCI_SET_DOOR_OPEN | Instructs the device to open the media cover (if any).
MCI_SET_TIME_FORMAT | Specifies a time format parameter is included in the dwTimeFormat member of the structure identified by lpSet. Specifying MCI_FORMAT_MILLISECONDS indicates that subsequent commands that specify time will use milliseconds for both input and output. Other units are device dependent.
MCI_SET_VIDEO | Sets the video signal on or off. This flag must be used with either MCI_SET_ON or MCI_SET_OFF. Devices that do not have video return MCIERR_UNSUPPORTED_FUNCTION.
MCI_SET_ON | Enables the specified video or audio channel.
MCI_SET_OFF | Disables the specified video or audio channel.

LPMCI_SET_PARMS lParam2
Specifies a far pointer to the MCI_SET_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Animation Extensions

The following additional flags for lParam1apply to animation devices:

MCI_SET_TIME_FORMAT Specifies a time format parameter is included in the dwTimeFormat member of the structure identified by lParam2. The following constants are defined for the time format:

MCI_FORMAT_MILLISECONDS | Changes the time format to milliseconds.
MCI_FORMAT_FRAMES | Changes the time format to frames.

Note that lParam2 specifies a far pointer to the MCI_SET_PARMS structure.

CD Audio Extensions

The following additional flags for lParam1 apply to videodisc devices:

MCI_SET_TIME_FORMAT Specifies a time format parameter is included in the dwTimeFormat member of the structure identified by lParam2. The following constants are defined for the time format:

MCI_FORMAT_MILLISECONDS | Changes the time format to milliseconds.
MCI_FORMAT_MSF | Changes the time format to minutes, seconds, and frames.
MCI_FORMAT_TMSF | Changes the time format to tracks, minutes, seconds, and frames. (MCI uses continuous track numbers.)

Note that lParam2 specifies a far pointer to the MCI_SET_PARMS structure.

MIDI Sequencer Extensions

The following additional flags for lParam1 apply to MIDI sequencer devices:

MCI_SEQ_SET_MASTER Sets the sequencer as a source of synchronization data and indicates that the type of synchronization is specified in the dwMaster member of the structure identified by lParam2. MCISEQ returns MCIERR_UNSUPPORTED_FUNCTION. The following constants are defined for the synchronization type:

MCI_SEQ_MIDI | The sequencer will send MIDI format synchronization data.
MCI_SEQ_SMPTE | The sequencer will send SMPTE format synchronization data.
MCI_SEQ_NONE | The sequencer will not send synchronization data.
MCI_SEQ_SET_OFFSET | Changes the SMPTE offset of a sequence to that specified by the dwOffset member of the structure identified by lParam2. This only affects sequences with a SMPTE division type.
MCI_SEQ_SET_PORT | Sets the output MIDI port of a sequence to that specified by the MIDI device ID in the dwPort member of the structure identified by lParam2. The device will close the previous port (if any), and attempt to open and use the new port. If it fails, it will return an error and re-open the previously used port (if any). The following constants are defined for the ports:
MCI_SEQ_NONE | Closes the previously used port (if any). The sequencer will behave exactly the same as if a port were open, except no MIDI message will be sent.

MIDI_MAPPER | Sets the port opened to the MIDI Mapper.
MCI_SEQ_SET_SLAVE | Sets the sequencer to receive synchronization data and indicates that the type of synchronization is specified in the dwSlave member of the structure identified by lParam2.MCISEQ returns MCIERR_UNSUPPORTED_FUNCTION.The following constants are defined for the synchronization type:
MCI_SEQ_FILE | Sets the sequencer to receive synchronization data contained in the MIDI file.
MCI_SEQ_SMPTE | Sets the sequencer to receive SMPTE synchronization data.
MCI_SEQ_MIDI | Sets the sequencer to receive MIDI synchronization data.
MCI_SEQ_NONE | Sets the sequencer to ignore synchronization data in a MIDI stream.
MCI_SEQ_SET_TEMPO | Changes the tempo of the MIDI sequence to that specified by the dwTempo member of the structure pointed to by lParam2. For sequences with division type PPQN, tempo is specified in beats per minute; for sequences with division type SMPTE, tempo is specified in frames per second.
MCI_SET_TIME_FORMAT | Specifies a time format parameter is included in the dwTimeFormat member of the structure identified by lParam2. The following constants are defined for the time format:

MCI_FORMAT_MILLISECONDS | Changes the time format to milliseconds for both input and output.
MCI_FORMAT_SMPTE_24 | Sets the time format to 24 frame SMPTE.
MCI_FORMAT_SMPTE_25 | Sets the time format to 25 frame SMPTE.
MCI_FORMAT_SMPTE_30 | Sets the time format to 30 frame SMPTE.
MCI_FORMAT_SMPTE_30DROP | Sets the time format to 30 drop-frame SMPTE.
MCI_SEQ_FORMAT_SONGPTR | Sets the time format to song-pointer units.

Note that lParam2 specifies a far pointer to the MCI_SEQ_SET_PARMS structure.

Videodisc Extensions

The following additional flags for lParam1 apply to videodisc devices:

MCI_SET_TIME_FORMAT | Specifies a time format parameter is included in the dwTimeFormat member of the structure identified by lParam2. The following constants are defined for the time format:
MCI_FORMAT_CHAPTERS | Changes the time format to chapters.
MCI_FORMAT_FRAMES | Changes the time format to frames.
MCI_FORMAT_HMS | Changes the time format to hours, minutes, and seconds.
MCI_FORMAT_MILLISECONDS | Changes the time format to milliseconds for both input and output.
MCI_VD_FORMAT_TRACK | Changes the time format to tracks. MCI uses continuous track numbers.

Note that lParam2specifies a far pointer to the MCI_VD_SET_PARMS structure. (Devices with additional parameters might replace this structure with a device-specific structure.)

Waveform Audio Extensions

The following additional flags for lParam1 apply to waveform audio devices:

MCI_WAVE_INPUT | Sets the input used for recording to the wInput member of the structure identified by lParam2.
MCI_WAVE_OUTPUT | Sets the output used for playing to the wOutput member of the structure identified by lParam2.
MCI_WAVE_SET_ANYINPUT | Specifies that any wave input compatible with the current format can be used for recording.
MCI_WAVE_SET_ANYOUTPUT | Specifies that any wave output compatible with the current format can be used for playing.
MCI_WAVE_SET_AVGBYTESPERSEC | Sets the bytes per second used for playing, recording, and saving to the nAvgBytesPerSec member of the structure identified by lParam2.
MCI_WAVE_SET_BITSPERSAMPLE | Sets the bits per sample used for playing, recording, and saving to the nBitsPerSample member of the structure identified by lParam2.
MCI_WAVE_SET_BLOCKALIGN | Sets the block alignment used for playing, recording, and saving to the nBlockAlign member of the structure identified by lParam2.
MCI_WAVE_SET_CHANNELS | Specifies the number of channels is indicated in the nChannels member of the structure identified by lParam2.
MCI_WAVE_SET_FORMATTAG | Sets the format type used for playing, recording, and saving to the wFormatTag member of the structure identified by lParam2. Specifying WAVE_FORMAT_PCM changes the format to PCM.
MCI_WAVE_SET_SAMPLESPERSEC | Sets the samples per second used for playing, recording, and saving to the nSamplesPerSec member of the structure identified by lParam2.
MCI_SET_TIME_FORMAT | Specifies a time format parameter is included in the dwTimeFormat member of the structure identified by lParam2. The following constants are defined for the time format:

MCI_FORMAT_BYTES | Changes the time format to bytes for input or output.
MCI_FORMAT_MILLISECONDS | Changes the time format to milliseconds for input or output.
MCI_FORMAT_SAMPLES | Changes the time format to samples for input or output.

Note that lParam2specifies a far pointer to the MCI_WAVE_SET_PARMS structure. This parameter replaces the standard default parameter structure identified by lParam2.


MCI_SPIN

Starts the device spinning up or down. This command is part of the videodisc command set. The parameters and flags for this message vary according to the selected device.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following flags apply to all devices supporting MCI_SPIN:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lParam2.
MCI_WAIT | Specifies that the spin up or spin down operation should finish before MCI returns control to the application.
MCI_VD_SPIN_UP | Starts the disc spinning.
MCI_VD_SPIN_DOWN | Stops the disc from spinning.

LPMCI_GENERIC_PARMS lParam2
Specifies a far pointer to the MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)


MCI_STATUS

Used to obtain information about an MCI device. All devices respond to this message. The parameters and flags available for this message depend on the selected device. Information is returned in the dwReturn member of the structure identified by lpStatus.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following standard and command-specific flags apply to all devices:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lpStatus.
MCI_WAIT | Specifies that the status operation should finish before MCI returns control to the application.
MCI_STATUS_ITEM | Specifies that the dwItem member of the structure identified by lpStatus contains a constant specifying which status item to obtain. The following constants define which status item to return in the dwReturn member of the structure:
MCI_STATUS_CURRENT_TRACK | The dwReturn member is set to the current track number. MCI uses continuous track numbers.
MCI_STATUS_LENGTH | The dwReturn member is set to the total media length.
MCI_STATUS_MODE | The dwReturn member is set to the current mode of the device. The modes include the following:

MCI_MODE_NOT_READY
MCI_MODE_OPEN
MCI_MODE_PAUSE
MCI_MODE_PLAY
MCI_MODE_RECORD
MCI_MODE_STOP
MCI_MODE_SEEK

MCI_STATUS_NUMBER_OF_TRACKS | The dwReturn member is set to the total number of playable tracks.
MCI_STATUS_POSITION | The dwReturn member is set to the current position.
MCI_STATUS_READY | The dwReturn member is set to TRUE if the device is ready; otherwise, it is set to FALSE.
MCI_STATUS_TIME_FORMAT | The dwReturn member is set to the current time format of the device. The time formats include:

MCI_FORMAT_BYTES
MCI_FORMAT_FRAMES
MCI_FORMAT_HMS
MCI_FORMAT_MILLISECONDS
MCI_FORMAT_MSF
MCI_FORMAT_SAMPLES
MCI_FORMAT_TMSF

MCI_STATUS_START Obtains the starting position of the media. To get the starting position, combine this flag with MCI_STATUS_ITEM and set the dwItem member of the structure identified by lpStatus to MCI_STATUS_POSITION.
MCI_TRACK Indicates a status track parameter is included in the dwTrack member of the structure identified by lpStatus. You must use this flag with the MCI_STATUS_POSITION or MCI_STATUS_LENGTH constants.

When used with MCI_STATUS_POSITION, MCI_TRACK obtains the starting position of the specified track.

When used with MCI_STATUS_LENGTH, MCI_TRACK obtains the length of the specified track. MCI uses continuous track numbers.

LPMCI_STATUS_PARMS lParam2
Specifies a far pointer to the MCI_STATUS_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Animation Extensions

The following extensions for lParam1 apply to animation devices:

MCI_STATUS_ITEM Specifies that the dwItem member of the structure identified by lParam2 contains a constant specifying which status item to obtain. The following additional status constants are defined for animation devices and indicate which item to return in the dwReturn member of the structure:

MCI_ANIM_STATUS_FORWARD | The dwReturn member is set to TRUE if playing forward; otherwise, it is set to FALSE.
MCI_ANIM_STATUS_HPAL | The dwReturn member is set to the handle of the movie palette.
MCI_ANIM_STATUS_HWND | The dwReturn member is set to the handle of the playback window.
MCI_ANIM_STATUS_SPEED | The dwReturn member is set to the animation speed, in frames per second.

MCI_STATUS_MEDIA_PRESENT The dwReturn member is set to TRUE if the media is inserted in the device; otherwise, it is set to FALSE.

Note that lParam2 specifies a far pointer to the MCI_STATUS_PARMS structure.

CD Audio Extensions

The following extensions for lParam1 applies to CD audio devices:

MCI_STATUS_ITEM | Specifies that the dwItem member of the structure identified by lParam2 contains a constant specifying which status item to obtain. The following additional status constants are defined for CD audio devices and indicate which item to return in the dwReturn member of the structure:
MCI_STATUS_MEDIA_PRESENT | The dwReturn member is set to TRUE if the media is inserted in the device; otherwise, it is set to FALSE.

Note that lParam2 specifies a far pointer to the MCI_STATUS_PARMS structure. This parameter replaces the standard default parameter structure.

MIDI Sequencer Extensions

The following extensions for lParam1 apply to sequencers:

MCI_STATUS_ITEM | Specifies that the dwItem member of the structure identified by lParam2 contains a constant specifying which status item to obtain. The following additional status constants are defined for sequencers and indicate which item to return in the dwReturn member of the structure:
MCI_SEQ_STATUS_DIVTYPE | The dwReturn member is set to one of the following values indicating the current division type of a sequence: MCI_SEQ_DIV_PPQN
 | MCI_SEQ_DIV_SMPTE_24
 | MCI_SEQ_DIV_SMPTE_25
 | MCI_SEQ_DIV_SMPTE_30
 | MCI_SEQ_DIV_SMPTE_30DROP
MCI_SEQ_STATUS_MASTER | The dwReturn member is set to the synchronization type used for master operation.
MCI_SEQ_STATUS_OFFSET | The dwReturn member is set to the current SMPTE offset of a sequence.
MCI_SEQ_STATUS_PORT | The dwReturn member is set to the MIDI device ID for the current port used by the sequence.
MCI_SEQ_STATUS_SLAVE | The dwReturn member is set to the synchronization type used for slave operation.
MCI_SEQ_STATUS_TEMPO | The dwReturn member is set to the current tempo of a MIDI sequence in beats-per-minute for PPQN files, or frames-per-second for SMPTE files.
MCI_STATUS_MEDIA_PRESENT | The dwReturn member is set to TRUE if the media for the device is present; otherwise, it is set to FALSE.

Note that lParam2 specifies a far pointer to the MCI_STATUS_PARMS structure. This parameter replaces the standard default parameter structure.

Videodisc Extensions

The following additional flags for lParam1 apply to videodisc devices:

MCI_STATUS_ITEM | Specifies that the dwItem member of the structure identified by lParam2 contains a constant specifying which status item to obtain. The following additional status constants are defined for videodisc devices and indicate which item to return in the dwReturn member of the structure:
MCI_STATUS_MEDIA_PRESENT | The dwReturn member is set to TRUE if the media is inserted in the device; otherwise, it is set to FALSE.
MCI_VD_STATUS_DISC_SIZE | The dwReturn member is set to the size of the loaded disc in inches (8 or 12).
MCI_VD_STATUS_FORWARD | The dwReturn member is set to TRUE if playing forward; otherwise, it is set to FALSE.
MCI_VD_STATUS_MEDIA_TYPE | The dwReturn member is set to the media type of the inserted media. The following media types can be returned: MCI_VD_MEDIA_CAV
 | MCI_VD_MEDIA_CLV
 | MCI_VD_MEDIA_OTHER
MCI_STATUS_MODE | The dwReturn member is set to the current mode of the device. All devices can return the following constants to indicate the current mode: MCI_MODE_NOT_READY
 | MCI_MODE_PAUSE
 | MCI_MODE_PLAY
 | MCI_MODE_STOP
 | MCI_VD_MODE_PARK
 | The dwReturn member is set to park if the disc is parked. Not all videodisc devices support this flag.
MCI_VD_STATUS_SIDE | The dwReturn member is set to 1 or 2 to indicate which side of the disc is loaded. Not all videodisc devices support this flag.
MCI_VD_STATUS_SPEED | The dwReturn member is set to the play speed in frames per second.

Note that lParam2 specifies a far pointer to the MCI_STATUS_PARMS structure. This parameter replaces the standard default parameter structure.

Waveform Audio Extensions

The following additional flags for lParam1 apply to waveform audio devices:

MCI_STATUS_ITEM | Specifies that the dwItem member of the structure identified by lParam2 contains a constant specifying which status item to obtain. The following additional status constants are defined for waveform audio devices and indicate which item to return in the dwReturn member of the structure:
MCI_STATUS_MEDIA_PRESENT | The dwReturn member is set to TRUE if the media is inserted in the device; otherwise, it is set to FALSE.
MCI_WAVE_INPUT | The dwReturn member is set to the wave input device used for recording. If no device is in use and no device has been explicitly set, then the error return is MCI_WAVE_INPUTUNSPECIFIED.
MCI_WAVE_OUTPUT | The dwReturn member is set to the wave output device used for playing. If no device is in use and no device has been explicitly set, then the error return is MCI_WAVE_OUTPUTUNSPECIFIED.
MCI_WAVE_STATUS_AVGBYTESPERSEC | The dwReturn member is set to the current bytes per second used for playing, recording, and saving.
MCI_WAVE_STATUS_BITSPERSAMPLE | The dwReturn member is set to the current bits per sample used for playing, recording, and saving.
MCI_WAVE_STATUS_BLOCKALIGN | The dwReturn member is set to the current block alignment used for playing, recording, and saving.
MCI_WAVE_STATUS_CHANNELS | The dwReturn member is set to the current channel count used for playing, recording, and saving.
MCI_WAVE_FORMATTAG | The dwReturn member is set to the current format tag used for playing, recording, and saving.
MCI_WAVE_STATUS_LEVEL | The dwReturn member is set to the current record or playback level. The value is returned as an 8- or 16-bit value, depending on the sample size used. The right or mono channel level is returned in the low-order word. The left channel level is returned in the high-order word.
MCI_WAVE_STATUS_SAMPLESPERSEC | The dwReturn member is set to the current samples per second used for playing, recording, and saving.

Note that lParam2 specifies a far pointer to the MCI_STATUS_PARMS structure.

Video Overlay Extensions

The following additional flags for lParam1 apply to video overlay devices:

MCI_OVLY_STATUS_HWND | The dwReturn member is set to the handle of the window associated with the video overlay device.
MCI_STATUS_ITEM | Specifies that the dwItem member of the structure identified by lParam2 contains a constant specifying which status item to obtain. The following additional status constants are defined for video overlay devices and indicate which item to return in the dwReturn member of the structure:
MCI_STATUS_MEDIA_PRESENT | The dwReturn member is set to TRUE if the media is inserted in the device; otherwise, it is set to FALSE.

Note that lParam2 specifies a far pointer to the MCI_STATUS_PARMS structure.


MCI_STEP

Steps the player one or more frames.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following flags apply to all devices supporting MCI_STEP:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lpStep.
MCI_WAIT | Specifies that the step operation should finish before MCI returns control to the application.

Animation Extensions

The following additional flag for lParam1 applies to animation devices.

MCI_ANIM_STEP_FRAMES | Indicates that the dwFrames member of the structure identified by lpStep specifies the number of frames to step.
MCI_ANIM_STEP_REVERSE | Steps in reverse.

Note that lParam2specifies a far pointer to the MCI_ANIM_STEP_PARMS structure.

Videodisc Extensions

The following additional flag for lParam1 applies to videodisc devices.

MCI_VD_STEP_FRAMES | Indicates that the dwFrames member of the structure identified by lParam2 specifies the number of frames to step.
MCI_VD_STEP_REVERSE | Steps in reverse.

Note that lParam2 specifies a far pointer to the MCI_VD_STEP_PARMS structure.

Only devices that return TRUE to the MCI_GETDEVCAPS_HAS_VIDEO capability query support this command at present.

See Also

MCI_CUE, MCI_PLAY, MCI_SEEK


MCI_STOP

Stops all play and record sequences, unloads all play buffers, and ceases display of video images. Support of this message by a device is optional. The parameters and flags for this message vary according to the selected device.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following flags apply to all devices supporting MCI_STOP:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lpStop.
MCI_WAIT | Specifies that the device should stop before MCI returns control to the application.

LPMCI_GENERIC_PARMS lParam2
Specifies a far pointer to the MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

The difference between MCI_STOP and MCI_PAUSE depends upon the device. If possible, MCI_PAUSE suspends device operation but leaves the device ready to resume play immediately.

See Also

MCI_PAUSE, MCI_PLAY, MCI_RECORD, MCI_RESUME


MCI_UNFREEZE

Restores motion to an area of the video buffer frozen with MCI_FREEZE. This command is part of the video overlay command set. The parameters and flags for this message vary according to the selected device.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following flags apply to all devices supporting MCI_UNFREEZE:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lParam2.
MCI_WAIT | Specifies that the unfreeze operation should finish before MCI returns control to the application.
MCI_OVLY_RECT | Specifies that the rc member of the structure identified by lParam2 contains a valid display rectangle. This is a required parameter.

LPMCI_OVLY_RECT_PARMS lParam2
Specifies a far pointer to a MCI_OVLY_RECT_PARMS structure. (Devices with additional parameters might replace this structure with a device-specific structure.)

See Also

MCI_FREEZE


MCI_UPDATE

Updates the display rectangle. This command is part of the animation command set. The parameters and flags for this message vary according to the selected device.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following flags apply to all devices supporting MCI_UPDATE:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lParam2.
MCI_WAIT | Specifies that the palette should be realized before MCI returns control to the application.

LPMCI_GENERIC_PARMS lParam2
Specifies a far pointer to a device specific structure. For a description of this parameter, see the lParam2 description included with the device extensions.

Animation Extensions

The following flags additional flags for lParam1 apply to animation devices supporting MCI_UPDATE:

MCI_ANIM_RECT | Specifies that the rc member of the structure identified by lParam2 contains a valid rectangle. If this flag is not specified, the entire window is updated.
MCI_ANIM_UPDATE_HDC | Specifies that the hDC member of the structure identified by lParam2 contains a handle to the display context. This flag is required.

Note that lParam2 specifies a far pointer to a MCI_ANIM_UPDATE_PARMS structure.

See Also

MCI_PUT, MCI_WHERE


MCI_WHERE

Obtains the clipping rectangle for the video device. The top and left members of the returned rectangle contain the origin of the clipping rectangle, and the right and bottom members contain the width and height of the clipping rectangle. The parameters and flags for this message vary according to the selected device.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
Applies to all devices supporting MCI_WHERE:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lpQuery.
MCI_WAIT | Specifies that the operation should complete before MCI returns control to the application.

DWORD lpQuery
Specifies a far pointer to a device-specific structure. For a description of this parameter, see the lpQuery description included with the device extensions.

Animation Extensions

The following additional flags for lParam1 apply to animation devices supporting MCI_WHERE:

MCI_ANIM_WHERE_DESTINATION | Obtains the destination display rectangle. The rectangle coordinates are placed in the rc member of the structure identified by lpQuery.
MCI_ANIM_WHERE_SOURCE | Obtains the animation source rectangle. The rectangle coordinates are placed in the rc member of the structure identified by lpQuery.

Note that lParam2 specifies a far pointer to a MCI_ANIM_RECT_PARMS structure.

Video Overlay Extensions

The following additional flags for lParam1 apply to video overlay devices supporting MCI_WHERE:

MCI_OVLY_WHERE_DESTINATION | Obtains the destination display rectangle. The rectangle coordinates are placed in the rc member of the structure identified by lParam2.
MCI_OVLY_WHERE_FRAME | Obtains the overlay frame rectangle. The rectangle coordinates are placed in the rc member of the structure identified by lParam2.
MCI_OVLY_WHERE_SOURCE | Obtains the source rectangle. The rectangle coordinates are placed in the rc member of the structure identified by lParam2.
MCI_OVLY_WHERE_VIDEO | Obtains the video rectangle. The rectangle coordinates are placed in the rc member of the structure identified by lParam2.

Note that lParam2 specifies a far pointer to a MCI_OVLY_RECT_PARMS structure.

See Also

MCI_PUT


MCI_WINDOW

Specifies the window and the window characteristics for graphic devices. Graphic devices should create a default window when a device is opened but should not display it until they receive a command that causes data to be displayed. The window command is used to supply an application-created window to the device and to change the display characteristics of an application-supplied or default display window. If the application supplies the display window, it should be prepared to update an invalid rectangle on the window.

Support of this message by a device is optional. The parameters and flags for this message vary according to the selected device.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
DWORD lParam1
The following flags apply to all devices supporting MCI_WINDOW:
MCI_NOTIFY | Specifies that MCI should post the MM_MCINOTIFY message when this command completes. The window to receive this message is specified in the dwCallback member of the structure identified by lpWindow.
MCI_WAIT | Specifies that the operation should finish before MCI returns control to the application.

DWORD lpWindow
Specifies a far pointer to a device specific structure. For a description of this parameter, see the lpWindow description included with the device extensions.

Animation Extensions

The following additional flags for lParam1 apply to animation devices supporting MCI_WINDOW:

MCI_ANIM_WINDOW_HWND | Indicates the handle of the window to use for the destination is included in the hWnd member of the structure identified by lpWindow. Set this to MCI_ANIM_WINDOW_DEFAULT to return to the default window.
MCI_ANIM_WINDOW_STATE | Indicates the nCmdShow member of the MCI_ANIM_WINDOW_PARMS structure contains parameters for setting the window state. This flag is equivalent to calling ShowWindow with the state parameter. The constants are the same as those in WINDOWS.H (such as SW_HIDE, SW_MINIMIZE, or SW_SHOWNORMAL).
MCI_ANIM_WINDOW_TEXT | Indicates the lpstrText member of the MCI_ANIM_WINDOW_PARMS structure contains a pointer to a buffer containing the caption used for the window.

Note that lParam2 specifies a far pointer to a MCI_ANIM_WINDOW_PARMS structure. (Devices with additional parameters might replace this structure with a device-specific structure.)

Video Overlay Extensions

The following additional flags for lParam1 apply to video overlay devices supporting MCI_WINDOW:

MCI_OVLY_WINDOW_HWND | Indicates the handle of the window used for the destination is included in the hWnd member of the MCI_OVLY_WINDOW_PARMS structure. Set this to MCI_OVLY_WINDOW_DEFAULT to return to the default window.
MCI_OVLY_WINDOW_STATE | Indicates the nCmdShow member of the lParam2 structure contains parameters for setting the window state. This flag It is equivalent to calling showwindow with the state parameter. The constants are the same as those defined in WINDOWS.H (such as SW_HIDE, SW_MINIMIZE, or SW_SHOWNORMAL.)
MCI_OVLY_WINDOW_TEXT | Indicates the lpstrText member of the MCI_OVLY_WINDOWS_PARMS structure contains a pointer to buffer containing the caption used for the window.

Note that lParam2 specifies a far pointer to a MCI_OVLY_WINDOW_PARMS structure. (Devices with additional parameters might replace this structure with a device-specific structure.)


MM_MCINOTIFY

This message is sent to a window to notify an application that an MCI device has completed an operation. MCI devices send this message only when the MCI_NOTIFY flag is used with an MCI command message or when the notify flag is used with an MCI command string.

  • Returns zero if successful. Otherwise, it returns an MCI error code.
UINT wParam
Contains one of the following message:
MCI_NOTIFY_ABORTED | Specifies that the device received a command that prevented the current conditions for initiating the callback from being met. If a new command interrupts the current command and it also requests notification, the device will send only this message and not MCI_NOTIFY_SUPERSEDED.
MCI_NOTIFY_SUCCESSFUL | Specifies that the conditions initiating the callback have been met.
MCI_NOTIFY_SUPERSEDED | Specifies that the device received another command with the MCI_NOTIFY flag set and the current conditions for initiating the callback have been superseded.
MCI_NOTIFY_FAILURE | Specifies that a device error occurred while the device was executing the command.

LPARAM lParam
The low-order word specifies the ID of the device initiating the callback.

A device returns the flag MCI_NOTIFY_SUCCESSFUL with MM_MCINOTIFY when the action for a command finishes. For example, a CD audio device uses this flag for notification for MCI_PLAY when the device finishes playing. The MCI_PLAY command completes successfully only when it reaches the specified end position or reaches the end of the media. Similarly, MCI_SEEK and MCI_RECORD do not return MCI_NOTIFY_SUCCESSFUL until they reach the specified end position or reach the end of the media.

A device returns the flag MCI_NOTIFY_ABORTED with MM_MCINOTIFY only when it receives a command that prevents it from meeting the notification conditions. For example, the command MCI_PLAY would not abort notification for a previous play command provided that the new command does not change the play direction or change the ending position for the play command with an active notify. The MCI_RECORD and MCI_SEEK commands behave similarly.

MCI also does not send MCI_NOTIFY_ABORTED when MCI_PLAY or MCI_RECORD is paused with MCI_PAUSE. Sending the MCI_RESUME command will let them continue to meet the callback conditions.

When your application requests notification for a command, check the error return of mciSendMessage or mciSendCommand. If these functions encounter an error and return a nonzero value, MCI will not set notification for the command.


Structures

The following topics describe the structures.


MCI_ANIM_OPEN_PARMS

typedef struct {
    DWORD  dwCallback;
    UINT  wDeviceID;
    UINT  wReserved0;
    LPCSTR  lpstrDeviceType;
    LPCSTR  lpstrElementName;
    LPCSTR  lpstrAlias;
    DWORD  dwStyle;
    HWND  hWndParent;
    UINT  wReserved1;
} MCI_ANIM_OPEN_PARMS;

The MCI_ANIM_OPEN_PARMS structure contains information for MCI_OPEN message. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members. You can use the MCI_OPEN_PARMS structure in place of MCI_ANIM_OPEN_PARMS if you are not using the extended data members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
wDeviceID
Specifies the device ID returned to user.
wReserved0
Reserved member.
lpstrDeviceType
Specifies the name or constant ID of the device type.
lpstrElementName
Specifies the device element name (usually a path).
lpstrAlias
Specifies an optional device alias.
dwStyle
Specifies the window style.
hWndParent
Specifies the handle to use as the window parent.
wReserved1
Reserved.

See Also

MCI_OPEN


MCI_ANIM_PLAY_PARMS

typedef struct {
    DWORD  dwCallback;
    DWORD  dwFrom;
    DWORD  dwTo;
    DWORD  dwSpeed;
} MCI_ANIM_PLAY_PARMS;

The MCI_ANIM_PLAY_PARMS structure contains parameters for the MCI_PLAY message for animation devices. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members. You can use the MCI_PLAY_PARMS structure in place of MCI_ANIM_PLAY_PARMS if you are not using the extended data members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
dwFrom
Specifies the position to play from.
dwTo
Specifies the position to play to.
dwSpeed
Specifies the play rate in frames per second.

See Also

MCI_PLAY


MCI_ANIM_RECT_PARMS

typedef struct {
    DWORD  dwCallback;
    RECT  rc;
} MCI_ANIM_RECT_PARMS;

The MCI_ANIM_RECT_PARMS structure contains parameters for the MCI_PUT and MCI_WHERE messages for animation devices. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
rc
Specifies a rectangle.

See Also

MCI_PUT, MCI_WHERE


MCI_ANIM_STEP_PARMS

typedef struct {
    DWORD  dwCallback;
    DWORD  dwFrames;
} MCI_ANIM_STEP_PARMS;

The MCI_ANIM_STEP_PARMS structure contains parameters for the MCI_STEP message for animation devices. When assigning data the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
dwFrames
Specifies the number of frames to step.

See Also

MCI_STEP


MCI_ANIM_UPDATE_PARMS

typedef struct {
    DWORD  dwCallback;
    RECT  rc;
    HDC  hDC;
} MCI_ANIM_UPDATE_PARMS;

The MCI_ANIM_UPDATE_PARMS structure contains parameters for the MCI_UPDATE message for animation devices. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
rc
Specifies a window rectangle.
hDC
Specifies a handle to the device context.

See Also

MCI_UPDATE


MCI_ANIM_WINDOW_PARMS

typedef struct {
    DWORD  dwCallback;
    HWND  hWnd;
    UINT  wReserved1;
    UINT  nCmdShow;
    UINT  wReserved2;
    LPCSTR  lpstrText;
} MCI_ANIM_WINDOW_PARMS;

The MCI_ANIM_WINDOW_PARMS structure contains parameters for the MCI_WINDOW message for animation devices. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
hWnd
Specifies a handle to the display window.
wReserved1
Reserved.
nCmdShow
Specifies how the window is displayed.
wReserved2
Reserved.
lpstrText
Specifies a long pointer to a null-terminated string containing the window caption.

See Also

MCI_WINDOW


MCI_GENERIC_PARMS

typedef struct {
    DWORD  dwCallback;
} MCI_GENERIC_PARMS;

The MCI_GENERIC_PARMS structure contains the information for MCI command messages that have empty parameter lists. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.


MCI_GETDEVCAPS_PARMS

typedef struct {
    DWORD  dwCallback;
    DWORD  dwReturn;
    DWORD  dwItem;
} MCI_GETDEVCAPS_PARMS;

The MCI_GETDEVCAPS_PARMS structure contains parameters for the MCI_GETDEVCAPS message. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
dwReturn
Contains the return information on exit.
dwItem
Identifies the capability being queried.

See Also

MCI_GETDEVCAPS


MCI_INFO_PARMS

typedef struct {
    DWORD  dwCallback;
    LPSTR  lpstrReturn;
    DWORD  dwRetSize;
} MCI_INFO_PARMS;

The MCI_INFO_PARMS structure contains parameters for the MCI_INFO message. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
lpstrReturn
Specifies a long pointer to a user-supplied buffer for the return string.
dwRetSize
Specifies the size in bytes of the buffer for the return string.

See Also

MCI_INFO


MCI_LOAD_PARMS

typedef struct {
    DWORD  dwCallback;
    LPCSTR  lpfilename;
} MCI_LOAD_PARMS;

The MCI_LOAD_PARMS structure contains the information for MCI_LOAD message. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
lpfilename
Specifies a far pointer to a null-terminated string containing the filename of the device element to load.

See Also

MCI_LOAD


MCI_OPEN_DRIVER_PARMS

typedef struct {
    UINT   wDeviceID;
    LPCSTR  lpstrParams;
    UINT  wCustomCommandTable;
    UINT  wType;
 } MCI_OPEN_DRIVER_PARMS;

The MCI_OPEN_DRIVER_PARMS structure contains data for the DRV_OPEN message.

Members

wDeviceID
Specifies the MCI device ID.
lpstrParams
Specifies a long pointer to the entry parameter string obtained from the SYSTEM.INI file.
wCustomCommandTable
Specifies a handle to a custom command table for the MCI driver. Set to -1 if the device driver does not have a custom command table. The device driver must set this parameter.
wType
Specifies the type of device driver:
MCI_DEVTYPE_ANIMATION | Specifies an animation device type.
MCI_DEVTYPE_CD_AUDIO | Specifies a cdaudio device type.
MCI_DEVTYPE_DAT | Specifies a digital audiotape device type.
MCI_DEVTYPE_DIGITAL_VIDEO | Specifies a digital video device type.
MCI_DEVTYPE_OTHER | Specifies a device type not covered by other device types.
MCI_DEVTYPE_OVERLAY | Specifies a video overlay device type.
MCI_DEVTYPE_SEQUENCER | Specifies a sequencer device type.
MCI_DEVTYPE_SCANNER | Specifies a scanner device type.
MCI_DEVTYPE_VCR | Specifies a videotape device type.
MCI_DEVTYPE_VIDEODISC | Specifies a videodisc device type.
MCI_DEVTYPE_WAVEFORM_AUDIO | Specifies a waveaudio device type.


MCI_OPEN_PARMS

typedef struct {
    DWORD  dwCallback;
    UINT  wDeviceID;
    UINT  wReserved0;
    LPCSTR  lpstrDeviceType;
    LPCSTR  lpstrElementName;
    LPCSTR  lpstrAlias;
} MCI_OPEN_PARMS;

The MCI_OPEN_PARMS structure contains information for MCI open message. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
wDeviceID
Contains the device ID returned to user.
wReserved0
Reserved.
lpstrDeviceType
Specifies the name or constant ID of the device type.
lpstrElementName
Specifies the device element name (usually a path).
lpstrAlias
Specifies an optional device alias.

See Also

MCI_OPEN


MCI_OVLY_LOAD_PARMS

typedef struct {
    DWORD  dwCallback;
    DWORD  lpfilename;
    RECT  rc;
} MCI_OVLY_LOAD_PARMS;

The MCI_OVLY_LOAD_PARMS structure contains parameters for the MCI_LOAD message for video overlay devices. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
lpfilename
Specifies a far pointer to the buffer containing a null-terminated string.
rc
Specifies a rectangle.

See Also

MCI_LOAD


MCI_OVLY_OPEN_PARMS

typedef struct {
    DWORD  dwCallback;
    UINT  wDeviceID;
    UINT  wReserved0;
    LPCSTR  lpstrDeviceType;
    LPCSTR  lpstrElementName;
    LPCSTR  lpstrAlias;
    DWORD  dwStyle;
    HWND  hWndParent;
    UINT  wReserved1;
} MCI_OVLY_OPEN_PARMS;

The MCI_OVLY_OPEN_PARMS structure contains information for MCI_OPEN message for video overlay devices. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members. You can use the MCI_OPEN_PARMS structure in place of MCI_OVLY_OPEN_PARMS if you are not using the extended data members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
wDeviceID
Specifies the device ID returned to user.
wReserved0
Reserved.
lpstrDeviceType
Specifies the name or constant ID of the device type obtained from the SYSTEM.INI file.
lpstrElementName
Specifies the device element name (usually a path).
lpstrAlias
Specifies an optional device alias.
dwStyle
Specifies the window style.
hWndParent
Specifies the handle to use as the window parent.
wReserved1
Reserved.

See Also

MCI_OPEN


MCI_OVLY_RECT_PARMS

typedef struct {
    DWORD  dwCallback;
    RECT  rc;
} MCI_OVLY_RECT_PARMS;

The MCI_OVLY_RECT_PARMS structure contains parameters for the MCI_PUT and MCI_WHERE messages for video overlay devices. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
rc
Specifies a rectangle.

See Also

MCI_PUT, MCI_WHERE


MCI_OVLY_SAVE_PARMS

typedef struct {
    DWORD  dwCallback;
    DWORD  lpfilename;
    RECT  rc;
} MCI_OVLY_SAVE_PARMS;

The MCI_OVLY_SAVE_PARMS structure contains parameters for the MCI_SAVE message for video overlay devices. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
lpfilename
Specifies a far pointer to the buffer containing a null-terminated string.
rc
Specifies a rectangle.

See Also

MCI_SAVE


MCI_OVLY_WINDOW_PARMS

typedef struct {
    DWORD  dwCallback;
    HWND  hWnd;
    UINT  wReserved1;
    UINT  nCmdShow;
    UINT  wReserved2;
    LPCSTR  lpstrText;
} MCI_OVLY_WINDOW_PARMS;

The MCI_OVLY_WINDOW_PARMS structure contains parameters for the MCI_WINDOW message for video overlay devices. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
hWnd
Specifies a handle to the display window.
wReserved1
Reserved.
nCmdShow
Specifies how the window is displayed.
wReserved2
Reserved.
lpstrText
Specifies a long pointer to a null-terminated buffer containing the window caption.

See Also

MCI_WINDOW


MCI_PLAY_PARMS

typedef struct {
    DWORD  dwCallback;
    DWORD  dwFrom;
    DWORD  dwTo;
} MCI_PLAY_PARMS;

The MCI_PLAY_PARMS structure contains parameters for the MCI_PLAY message. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
dwFrom
Specifies the position to play from.
dwTo
Specifies the position to play to.

See Also

MCI_PLAY


MCI_RECORD_PARMS

typedef struct {
    DWORD  dwCallback;
    DWORD  dwFrom;
    DWORD  dwTo;
} MCI_RECORD_PARMS;

The MCI_RECORD_PARMS structure contains parameters for the MCI_RECORD message. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
dwFrom
Specifies the position to play from.
dwTo
Specifies the position to play to.

See Also

MCI_RECORD


MCI_SAVE_PARMS

typedef struct {
    DWORD  dwCallback;
    DWORD  lpfilename;
} MCI_SAVE_PARMS;

The MCI_SAVE_PARMS structure contains the information for MCI_SAVE message. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
lpfilename
Specifies a far pointer to the buffer containing a null-terminated string.

See Also

MCI_SAVE


MCI_SEEK_PARMS

typedef struct {
    DWORD  dwCallback;
    DWORD  dwTo;
} MCI_SEEK_PARMS;

The MCI_SEEK_PARMS structure contains parameters for the MCI_SEEK message. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
dwTo
Specifies the position to seek to.

See Also

MCI_SEEK


MCI_SEQ_SET_PARMS

typedef struct {
    DWORD  dwCallback;
    DWORD  dwTimeFormat;
    DWORD  dwAudio;
    DWORD  dwTempo;
    DWORD  dwPort;
    DWORD  dwSlave;
    DWORD  dwMaster;
    DWORD  dwOffset;
} MCI_SEQ_SET_PARMS;

The MCI_SEQ_SET_PARMS structure contains parameters for the MCI_SET message for MIDI sequencer devices. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
dwTimeFormat
Specifies the time format of the sequencer.
dwAudio
Specifies the audio output channel.
dwTempo
Specifies the tempo.
dwPort
Specifies the output port.
dwSlave
Specifies the type of synchronization used by the sequencer for slave operation.
dwMaster
Specifies the type of synchronization used by the sequencer for master operation.
dwOffset
Specifies the data offset.

See Also

MCI_SET


MCI_SET_PARMS

typedef struct {
    DWORD  dwCallback;
    DWORD  dwTimeFormat;
    DWORD  dwAudio;
} MCI_SET_PARMS;

The MCI_SET_PARMS structure contains parameters for the MCI_SET message. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
dwTimeFormat
Specifies the time format used by the device.
dwAudio
Specifies the audio output channel.

See Also

MCI_SET


MCI_STATUS_PARMS

typedef struct {
    DWORD  dwCallback;
    DWORD  dwReturn;
    DWORD  dwItem;
    DWORD  dwTrack;
} MCI_STATUS_PARMS;

The MCI_STATUS_PARMS structure contains parameters for the MCI_STATUS message. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
dwReturn
Contains the return information on exit.
dwItem
Identifies the capability being queried.
dwTrack
Specifies the length or number of tracks.

See Also

MCI_STATUS


MCI_VD_ESCAPE_PARMS

typedef struct {
    DWORD  dwCallback;
    LPCSTR  lpstrCommand;
} MCI_VD_ESCAPE_PARMS;

The MCI_VD_ESCAPE_PARMS structure contains parameters for the MCI_ESCAPE message for videodisc devices. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
lpstrCommand
Specifies a far pointer to a null-terminated buffer containing the command to send to the device.

See Also

MCI_ESCAPE


MCI_VD_PLAY_PARMS

typedef struct {
    DWORD  dwCallback;
    DWORD  dwFrom;
    DWORD  dwTo;
    DWORD  dwSpeed;
} MCI_VD_PLAY_PARMS;

The MCI_VD_PLAY_PARMS structure contains parameters for the MCI_PLAY message for videodiscs. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members. You can use the MCI_PLAY_PARMS structure in place of MCI_VD_PLAY_PARMS if you are not using the extended data members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
dwFrom
Specifies the position to play from.
dwTo
Specifies the position to play to.
dwSpeed
Specifies the playing speed in frames per second.

See Also

MCI_PLAY


MCI_VD_STEP_PARMS

typedef struct {
    DWORD  dwCallback;
    DWORD  dwFrames;
} MCI_VD_STEP_PARMS;

The MCI_VD_STEP_PARMS structure contains parameters for the MCI_STEP message for videodiscs. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
dwFrames
Specifies the number of frames to step.

See Also

MCI_STEP


MCI_WAVE_DELETE_PARMS

typedef struct {
    DWORD  dwCallback;
    DWORD  dwFrom;
    DWORD  dwTo;
} MCI_WAVE_DELETE_PARMS;

The MCI_WAVE_DELETE_PARMS structure contains parameters for the MCI_DELETE message for waveform audio devices. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
dwFrom
Specifies the starting position for the delete.
dwTo
Specifies the end position for the delete.

See Also

MCI_DELETE


MCI_WAVE_OPEN_PARMS

typedef struct {
    DWORD  dwCallback;
    UINT  wDeviceID;
    UINT  wReserved0;
    LPCSTR  lpstrDeviceType;
    LPCSTR  lpstrElementName;
    LPCSTR  lpstrAlias;
    DWORD  dwBufferSeconds;
} MCI_WAVE_OPEN_PARMS;

The MCI_WAVE_OPEN_PARMS structure contains information for MCI_OPEN message for waveform audio devices. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members. You can use the MCI_OPEN_PARMS structure in place of MCI_WAVE_OPEN_PARMS if you are not using the extended data members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
wDeviceID
Specifies the device ID returned to user.
wReserved0
Reserved.
lpstrDeviceType
Specifies the name or constant ID of the device type obtained.
lpstrElementName
Specifies the device element name (usually a path).
lpstrAlias
Specifies an optional device alias.
dwBufferSeconds
Specifies the buffer length in seconds.

See Also

MCI_OPEN


MCI_WAVE_SET_PARMS

typedef struct {
    DWORD  dwCallback;
    DWORD  dwTimeFormat;
    DWORD  dwAudio;
    UINT  wInput;
    UINT  wReserved0;
    UINT  wOutput;
    UINT  wReserved1;
    UINT  wFormatTag;
    UINT  wReserved2;
    UINT  nChannels;
    UINT  wReserved3;
    DWORD  nSamplesPerSec;
    DWORD  nAvgBytesPerSec;
    UINT  nBlockAlign;
    UINT  wReserved4;
    UINT  wBitsPerSample;
    UINT  wReserved5;
} MCI_WAVE_SET_PARMS;

The MCI_WAVE_SET_PARMS structure contains parameters for the MCI_SET message for waveform audio devices. When assigning data to the members in this structure, set the corresponding MCI flags in the lParam1 parameter of mciSendCommand to validate the members.

Members

dwCallback
The low-order word specifies a window handle used for the MCI_NOTIFY flag.
dwTimeFormat
Specifies the time format used by the device.
dwAudio
Specifies the channel used for audio output.
wInput
Specifies the channel used for audio input.
wReserved0
Reserved.
wOutput
Specifies the channel used for output.
wReserved1
Reserved.
wFormatTag
Specifies the interpretation of the waveform data.
wReserved2
Reserved.
nChannels
Specifies mono (1) or stereo (2).
wReserved3
Reserved.
nSamplesPerSec
Specifies the samples per second used for the waveform.
nAvgBytesPerSec
Specifies the sample rate in bytes per second.
nBlockAlign
Specifies the block alignment of the data.
wReserved4
Reserved.
wBitsPerSample
Specifies the number of bits per sample (PCM only).
wReserved5
Reserved.

See Also

MCI_SET, PCMWAVEFORMAT, WAVEFORMAT


Video Capture Device Drivers

Video capture device drivers provide low-level video capture services for Windows multimedia applications. These devices can provide services such as the following:

  • Single frame video capture
  • Real-time (streaming) video capture
  • Video overlay
  • Capture video frames in a standard or proprietary compressed format

Video capture devices must have a corresponding video capture device driver to be used with Windows. This section explains the Windows interface for video capture device drivers. It covers the following topics:

  • The different types of video capture channels
  • General information about writing a video capture device driver
  • How a video capture device driver handles the system messages for the installable driver interface and Plug and Play
  • How a video capture device driver handles device specific messages for video capture
  • An alphabetical reference to the messages and data structures used to write video capture device drivers

Before reading this section, you should be familiar with the video services available with Windows 95. You should also be familiar with the Windows installable driver interface. For information about the video services and the installable driver interface, see the Win32 Programmer's Reference.


Video Capture Driver Architecture

The Windows 95 operating system provides the interface between client-applications and video capture device drivers-applications do not call the drivers directly. Although capture drivers are fundamentally 16-bit DLLs, they can contain flat 32-bit code for efficiency. In addition, the Plug and Play portion of capture drivers are implemented as a 32-bit VxD.


New for Windows 95

The following enhancements have been made for Windows 95:

  • Support for 32-bit capture applications with improved performance using AVICap32.dll.
  • Allocate capture buffers on their device. This allows video frames to be saved directly to disk without copying to intermediate buffers, resulting in higher capture data rates.
  • Support for plug and play capture drivers.
  • Support for multiple instances of identical plug and play hardware in a single system. For additional information, see the dnDevNode member of the VIDEO_OPEN_PARMS structure.


Video Capture Device Driver Channels

Video capture device drivers can transfer data through four different logical channels. The destination or source of each channel is the frame buffer that is part of the video capture hardware. Although some capture devices may not implement a physical frame buffer capable of containing complete video frames, the four channels are still used to control the flow of video information. The four channels and the frame buffer are shown in the following illustration:

Data channels in the video capture driver.

The video capture channel (External In) is a source of video information placed in the frame buffer. The video source might be a video camera, video player, or television tuner. The format of both the incoming signal and the data placed in the frame buffer is controlled by the video capture hardware.

The video capture device can display the frame buffer data by using the video display channel (External Out). In practice, this could be with a second monitor or a video overlay device.

The device driver and application will use the video in channel (Video In) to transfer the video data to application supplied buffers.

The device driver and application can play captured data by using the video out channel (Video Out) to transfer data back into the frame buffer. Playback through this channel might be to review a sequence just captured or to play data from a file.

To supply minimum services, video capture drivers must support the External In and Video In channels.

Note The Video Out channel is not currently used. The interface for video compression and decompression drivers is currently used to display video output from an AVI file..


Video Capture Application

Video capture applications call the capture engine provided by AVICap32.dll. This DLL accepts high-level commands from client applications, and converts them into low-level messages that are sent to capture drivers. AVICap32.dll allows client applications access to a window of the AVICap class. The AVICap window class displays the incoming video signal, allocates buffers for the video data, generates and manipulates palettes, and stores video and audio to an AVI file. For a complete description of the application interface to AVICap32.dll, see the video capture section of the Microsoft Win32 Programmer's Reference.


Sample Device Drivers

The examples in this section were extracted from a sample device driver for the Orchid Vidiola video capture hardware. This device is similar to a number of capture cards which use the Auravision VxP500 capture and scaling chip. The driver for the Orchid Vidiola implements a subset of the Plug and Play specification.

The Orchid Vidiola sample driver consists of three components. Source files for each component are contained in subdirectories branching from ddk\mmedia\samples\auravis.

Directory | Component | 16 or 32 | Description
DRV | AVCapt.drv | 16 (some 32-bit flat segments) | The main capture driver which includes the DriverProc entry point
VXD | AVVXP500.vxd | 32 | Plug and play support VxD.
AVWIN | AVWin.dll | 16 | A support DLL which is entirely unique to the Auravision driver.

AVCapt.drv is the core capture driver. It is a Ring3 DLL. By convention, capture drivers use the DRV extension rather than DLL.

AVWin.dll is a separate support DLL called by AVCapt.drv. This functionality is separate from AVCapt.drv purely for historical reasons. Most drivers will have only a capture driver (*.drv) and an associated plug and play VxD. Therefore, AVWin.dll will not be described further in this document.

The Orchid Vidiola can only participate in Plug and Play to a limited extent. For example, the base port and IRQ are not software configurable, but must be manually configured by the user via jumpers. For this reason, the sample VxD does not implement the full range of plug and play functionality such as dynamic resource assignment.

Note The Video for Windows Developers Kit (VFWDK) included sample capture drivers for the Truevision Bravado and Creative Labs Video Blaster. While these drivers did not include PnP capabilities, they are generally simpler than the Vidiola driver and provide another useful reference when developing your own capture driver.


Video Capture Device Driver Structure

As installable driver DLLs, video capture drivers provide a DriverProc entry point used to process system messages and device driver specific messages. For general information about installable drivers, the DriverProc entry point, and system messages sent to this entry point, see the Microsoft Windows Programmer's Reference. This section includes supplemental information for the system messages. This information describes specifically how video capture drivers should respond to the system messages that are critical to their proper operation.


Combining Video Capture and Video Compression/Decompression Drivers

If the same hardware is required or used for a combination of video capture and video compression, you might combine both of these functions into a common DLL and use a single DriverProc entry point to service them. The common entry point will simplify the coordination of the different functions.

Note Because video capture drivers can rely on video compression and decompression drivers for efficient operation, a single driver can handle both video capture, and video compression and decompression services. Video capture drivers use the VIDEO_OPEN_PARMS data structure when they are opened. This structure has the same member definitions as the ICOPEN structure used by video compression and decompression drivers. By examining the fccType member, a combined driver can determine whether it is being opened as a video capture driver or a video compression and decompression driver. (Video capture devices contain the four-character code 'vcap' in this member.) For more information on video compression and decompression drivers, see Video Compression and Decompression Drivers.


Installable Driver Interface

The entry-point function, DriverProc, processes messages sent by the system to the driver as the result of an application call to a low-level video capture function. For example, when an application opens a video capture device, the system sends the specified video capture device driver a DRV_OPEN message. The driver's DriverProc function receives and processes this message. Each of the different capture channels will receive a separate DRV_OPEN message.

Note Your driver should respond to all system messages. If supplemental information is not provided for them in this section, use the definitions provided in the Microsoft Windows Programmer's Reference.


Handling the DRV_OPEN and DRV_CLOSE Messages

Like other installable drivers, client-applications must open a video capture device before using it and close it when finished using it, so the device will be available to other applications. When a driver receives an open request, it returns a value that the system will use for dwDriverID sent with subsequent messages. When your device driver receives other messages, it can use this value to identify instance data needed for operation. Drivers can use the instance data for information related to the client that opened a device.

It is up to you to decide if your device driver will support more than one client simultaneously. If you do this, though, remember to check the dwDriverID parameter to determine which channel is being accessed.

For DRV_OPEN, the lParam2 parameter contains a pointer to a VIDEO_OPEN_PARMS data structure containing information about the open. This structure has the following members:

typedef struct {
    DWORD   dwSize;        // Specifies the structure size
    FOURCC  fccType;       // Contains 'vcap'
    FOURCC  fccComp;       // Reserved; do not use
    DWORD   dwVersion;     // Command set version
    DWORD   dwFlags;       // Type of channel being opened
    DWORD   dwError;       // Error to return if open fails
    LPVOID  pV1Reserved;   // Reserved; do not use
    LPVOID  pV2Reserved;   // Reserved; do not use
    DWORD   dwDevNode;     // Registry device not for PNP devices
} VIDEO_OPEN_PARMS;

The fccType member of this structure will contain the four character code 'vcap'. Because of the four video capture channels, video capture drivers must examine the flags set in the dwFlags member of the VIDEO_OPEN_PARMS data structure to determine the type of channel being opened. Your driver should be prepared to open (and conversely, close) the video channels in any order.

The following flags are defined for the video channels:

Channel | Description
VIDEO_EXTERNALIN | An external input channel responsible for loading images into the frame buffer.
VIDEO_EXTERNALOUT | An external output channel responsible for displaying images in the frame buffer to an external or system monitor, or to an overlay device.
VIDEO_IN | A video input channel responsible for transferring images from the frame buffer to system memory. This might include a translation step or reformatting of the image. For example, reformatting a 16-bit RGB image to an 8 bit palette image.
VIDEO_OUT | A video output channel responsible for transferring images into the frame buffer from the CPU. (The sample driver does not use this channel type.)

The dwVersion member specifies the version of the video capture command set used by MSVIDEO.DLL. The version number lets your driver identify the command set to determine its capabilities. For the initial release of the video capture command set, your driver does not have to detect and adjust itself for multiple versions of the command set. Future versions of your driver can use this value to enable new features that depend on new capabilities of the video capture command set.

The dwError member specifies an error value the driver might return to the client-application if it fails the open.

The dwDevNode member specifies the Device Node for plug and play compatible drivers. For non-Plug and Play devices, this member will be NULL.


Ring3 DLL and VxD Communication

Although the Orchid sample capture driver uses the associated VxD merely to interract with the plug and play subsystem, you can optionally move portions of your capture functionality out of the Ring3 DLL and into the VxD. The actual vertical sync interrupt service routine is an obvious candiate for migration.

The VxD portion of the driver is loaded on system boot and receives configuration messages through the AVVXP500_Config_Handler entry point. When the Ring3 DLL is loaded on demand by a capture application, it first obtains the entry point to the VxD by calling the GetVxDEntry function. Next it requests the current resources via the GetVxDInfo function. When this function returns, the Ring3 DLL has a list of IRQ, and port resources previously acquired by the VxD.


Installing Your Capture Driver

Device information (INF) files provide the information that the Windows 95 operating system needs to install the software and information to support a given hardware device. Independent hardware vendors who develop Windows 95 device drivers must also create INF files to explicitly define the resources and files required to support each class of device.

Device information (INF) files provide the information that Windows 95 needs to install a given device and its associated software. IHVs who wish to install their devices and software using the Windows 95 built in installation support must create an INF to describe the device and its installation requirements.

Every INF is a collection of sections which describe a device, the resources required by that device and the installation procedure. Windows 95 New Device Wizard builds its list of installable devices by searching through the INFs. The Device Manager also displays information which originates in the INF. Every hardware INF follows the general organization described below.

Section name | Description
Version | Contains a simple header that identifies the INF and the class of device this INF supports.
Class | Defines a new class for this device. This section is optional only as long as the class is already defined
Manufacturer and Manufacturer Name | Lists all the individual manufacturers of the devices identified in this file and lists all the devices built by that manufacturer. These entries are displayed directly to the user and used to generate the appropriate registry entries. There must always be at least one manufacturer.
Install | Describes the device driver and physical attributes of the hardware device. It also identifies the names of all the Installation sections that contain information and instructions for installing this device.
Strings | Defines all localizable strings used in the INF file.
Miscellaneous Control Sections | Specifies how a device is handled by the Windows 95 user interface.

If you have a Win 3.1-compatible driver which you are not planning to upgrade for plug and play, it is still a good idea to update the INF file so the system can inform the user of possible resource conflicts during installation.

Note For details on how to create a Windows 95 INF file, refer to the Plug and Play documentation.Video Capture Driver Messages


Driver Configuration

Installable drivers that do not have plug and play capability can supply a configuration dialog box for users to access through the Drivers option in the Control Panel. The Drivers option sends the DRV_CONFIGURE message to your driver to display the dialog box.

The dialog box should display the name and version number of your device driver. If your device driver supports different interrupt-level and port assignments, it should also support user configuration through the Drivers option in the Control Panel.

Installable drivers that do not have plug and play capability can store interrupt-level and port assignments, and any other hardware-related settings, in a section with the same name as the driver in the user's SYSTEM.INI file. For example, the following SYSTEM.INI section created by the Bravado example driver specifies interrupt level 9 and memory base E:

[Bravado.drv]
Interrupt=9
MemoryBase=E

Alternatively, your driver might use its own INI file for this information. Hardware related settings for plug and play devices is stored in the registry.

Configuring the Channels of a Video Capture Driver

In addition to the Configuration dialog box displayed for the DRV_CONFIGURE message, video capture drivers can display a dialog box for each channel. These dialog boxes are the primary means of setting parameters in your device driver. The DVM_DIALOG message requests that the device driver display a dialog box.

When your device driver first gets this message, use the handle in lParam1 to determine which channel is being configured. The sample driver determines the channel from the flags used to open it. It saves these flags as part of its instance data created when it was opened.

The dialog box displayed for each channel sets the characteristics for each channel. If a channel does not support configuration, return DV_ERR_NOTSUPPORTED. The following table suggests the contents of each dialog box:

Channel | Dialog box description
VIDEO_EXTERNALIN | Displays a dialog box controlling how video (either analog or digital) is captured. The dialog box might set attributes such as contrast, brightness, NTSC,. PAL, .and input source
VIDEO_EXTERNALOUT | Displays a dialog box controlling how video is displayed on a second monitor or video adapter such as a video overlay card.
VIDEO_IN | Displays a dialog box controlling how video is transferred from the frame buffer. This includes options such as the format of the video, bit rate, and compression format.
VIDEO_OUT | Displays a dialog box controlling how video is transferred to the frame buffer.

When processing the DVM_DIALOG message, check lParam2 for the VIDEO_DLG_QUERY flag prior to displaying the dialog box. If an application uses this flag, it is only determining if a video channel supports a dialog box. For this flag, return DV_ERR_OK if the video channel supports a dialog box. If not, return DV_ERR_NOTSUPPORTED in response to the message.

Video capture drivers might save the settings from these dialog boxes in the section reserved for your device driver in the SYSTEM.INI file. Your driver should append this information to the entries created for the DVR_CONFIGURE messages to this section. For example, the Bravado driver might have this section in the SYSTEM.INI file:

[Bravado.drv]
Interrupt=9
MemoryBase=E
Hue=10
Saturation=6
InputChannel=2
Contrast=24

Alternatively, a device driver might implement its own method of storing configuration information for each channel.


Setting and Obtaining Video Capture Format

The video capture format globally defines the attributes of the images transferred from the frame buffer with the video in channel. Attributes include image dimensions, color depth, and the compression format of images transferred. Applications use the DVM_FORMAT message to set or retrieve the format of the digitized image.

The calling application must modify this message with flags to indicate its purpose. Your driver must examine the flags sent with the message to determine the proper response. The flags are specified in lParam1.

The VIDEO_CONFIGURE_GET or VIDEO_CONFIGURE_SET flag indicates if the DVM_FORMAT message is being used to obtain the format or set the format. The DVM_FORMAT message and these flags are sent to your driver when it is opened, and when it is configured with DVM_DIALOG.

When an application opens your driver, it retrieves the initial driver format. (Video capture drivers initially default to a format that efficiently uses the capabilities of the video capture hardware or, if they have been previously configured, they restore the last user specified configuration saved in a disk file.) If this format is acceptable, the application continues its operations. If the format is not acceptable, the application will either immediately close your driver or suggest a very limited format. If the limited format is not acceptable to your driver, the application closes it. (Typically, applications do not accept a format because they cannot allocate enough memory to capture video. A limited format might free enough memory for operation.)

Applications also get the format when the user changes the format. (Users change the format with the VIDEO_IN channel dialog box displayed with the DVM_DIALOG message.) In this case, applications get and retain a copy of the current format prior to sending the DVM_DIALOG message. After the user exits from the DVM_DIALOG dialog box, applications get the new format from your driver. If the application accepts the new format, it uses the VIDEO_CONFIGURE_SET flag to return the format back to your driver. (Your driver should verify that the application has not changed the format information.) If the application does not accept the new format, it restores the format it obtained prior to displaying the dialog box.

The DVM_FORMAT messages uses lParam2 to pass the format information. This parameter contains a pointer to a VIDEOCONFIGPARMS structure. This structure has the following members:

typedef struct tag_video_configure_parms {
    LPDWORD  lpdwReturn;
    LPVOID   lpData1;
    DWORD    dwSize1;
    LPVOID   lpData2;
    DWORD    dwSize2;
} VIDEOCONFIGPARMS;

The lpData1 member points to a BITMAPINFOHEADER data structure. The size of this structure is specified in dwSize1.

Changing the format can affect overall dimensions of the active frame buffer as well as bit depth and color space representation. Since changing between NTSC and PAL video standards can also affect image dimensions, applications should request the current format following display of the EXTERNAL_IN channel dialog box.

If an application just wants to know if your driver supports DVM_FORMAT, it sends the VIDEO_CONFIGURE_QUERY flag with the message. (Using the VIDEO_CONFIGURE_QUERY flag without VIDEO_CONFIGURE_GET or VIDEO_CONFIGURE_SET is invalid.) Your device driver should return DV_ERR_OK if it supports the message. Otherwise, it should return DV_ERR_NOTSUPPORTED.

If an application wants to determine the amount of memory it needs to allocate for the format information, it sends the DVM_FORMAT message with the VIDEO_CONFIGURE_GET and VIDEO_CONFIGURE_QUERYSIZE flags set. Your driver should specify the format size in the lpdwReturn member of the VIDEOCONFIGUREPARMS structure.


Setting and Obtaining the Video Source and Destination Rectangles

Video capture drivers might support a source rectangle to specify a portion of an image that is digitized or transferred to the display. External in ports use the source rectangle to specify the portion of the analog image digitized. External out ports use the source rectangle to specify the portion of frame buffer shown on the external output.

Similarly, video capture drivers might support a destination rectangle to specify the portion of the frame buffer or screen used to receive the image. External in ports can use a destination rectangle to specify the portion of the frame buffer used for the digitized video input. External out ports can use the rectangle to specify the client rectangle on the display.

The DVM_DST_RECT and DVM_SRC_RECT messages are used to set and obtain the video source and destination rectangles.The calling application must modify these messages with flags to indicate their exact meaning. Your driver must examine the flags sent with the messages to determine the proper response. The flags are specified in lParam2. The VIDEO_CONFIGURE_SET, VIDEO_CONFIGURE_GET, and VIDEO_CONFIGURE_QUERY flags define the meaning of the DVM_DST_RECT and DVM_SRC_RECT messages:

The VIDEO_CONFIGURE_SET flag indicates the application is setting a source or destination rectangle. The rectangle coordinates are specified in a RECT structure pointed to by lParam1.

If an application sets a source or destination rectangle for an external out channel, your driver will normally receive a series of messages. For these channels, applications normally send both DVM_SRC_RECT and DVM_DST_RECT to your driver to properly set the rectangles. The application follows these messages with DVM_UPDATE. Video overlay devices should paint their key color in response to DVM_UPDATE.

Applications use the VIDEO_CONFIGURE_GET flag to determine the coordinates of the source and destination rectangles. Applications use additional flags with VIDEO_CONFIGURE_GET to indicate if they want the coordinates of the rectangle currently defined, the maximum size of the rectangle, or the minimum size of the rectangle.

Your driver should return the coordinates for the appropriate rectangle in the RECT structure pointed to by lParam1.

An application use the VIDEO_CONFIGURE_QUERY flag to determine if your driver supports VIDEO_CONFIGURE_QUERY or VIDEO_CONFIGURE_SET. (The VIDEO_CONFIGURE_QUERY flag without VIDEO_CONFIGURE_GET or VIDEO_CONFIGURE_SET is invalid.) Your device driver should return DV_ERR_OK if it supports the flag. Otherwise, it should return DV_ERR_NOTSUPPORTED.


Determining Channel Capabilities

Channel capabilities include overlaying video, scaling of images with the source and destination rectangles, and clipping of images with the source and destination rectangles. The DVM_GET_CHANNEL_CAPS message retrieves the channel capabilities of a driver.

Applications use DVM_GET_CHANNEL_CAPS to obtain information about the capabilities of a channel. The lParam1 parameter specifies a far pointer to a

CHANNEL_CAPS data structure and the lParam2 parameter specifies its size. The CHANNEL_CAPS structure has the following members:

typedef struct channel_caps_tag {
    DWORD  dwFlags;
    DWORD  dwSrcRectXMod;
    DWORD  dwSrcRectYMod;
    DWORD  dwSrcRectWidthMod;
    DWORD  dwSrcRectHeightMod;
    DWORD  dwDstRectXMod;
    DWORD  dwDstRectYMod;
    DWORD  dwDstRectWidthMod;
    DWORD  dwDstRectHeightMod;
} CHANNEL_CAPS;

Your driver should use the dwFlags member to return flags indicating its capabilities for overlaying video, and clipping and scaling images with the source and destination rectangles.

If your driver supports changing the size and position of the source rectangle, it should indicate the finest granularity used for changes to the rectangle in the dwSrcRectXMod, dwSrcRectYMod, dwSrcRectWidthMod, and dwSrcRectHeightMod members.

If your driver supports changing the size and position of the destination rectangle, it should indicate the finest granularity used for changes to the rectangle in the dwDstRectXMod, dwDstRectYMod, dwDstRectWidthMod, and dwDstRectHeightMod members. If a channel supports arbitrarily positioned rectangles, with arbitrary sizes, the values above should all be set to 1.

Your driver returns DV_ERR_OK if the message was processed successfully. It returns DV_ERR_NOTSUPPORTED if the message is not supported.


Setting and Obtaining a Video Capture Palette

Applications can set and retrieve the palette used with captured video. This gives applications the ability to control and modify the palette used for video sequences. The palette messages apply only to the video in and video out channels. The DVM_PALETTE assigns or obtains palette information and the DVM_PALETTERGB555 message associates an RGB555 palette with a video device channel.

The calling application must modify these messages with flags to indicate their purpose. Your driver must examine the flags sent with the messages to determine the proper response. The flags are specified in lParam1.

The VIDEO_CONFIGURE_GET or VIDEO_CONFIGURE_SET flag modifies the DVM_PALETTE message to indicate that the driver should return the current palette or that the driver should set a new palette. The lParam2 parameter used with DVM_PALETTE contains a pointer to a VIDEOCONFIGPARMS data structure. This structure has the following members:

typedef struct tag_video_configure_parms {
    LPDWORD  lpdwReturn;
    LPVOID   lpData1;
    DWORD    dwSize1;
    LPVOID   lpData2;
    DWORD    dwSize2;
} VIDEOCONFIGPARMS;

If the VIDEO_CONFIGURE_SET flag is used with DVM_PALETTE, the lpData1 member points to a LOGPALETTE structure containing the new palette. The size of the memory allocated for the LOGPALETTE structure is specified in the dwSize1 member.

If the VIDEO_CONFIGURE_GET flag is used with DVM_PALETTE, the lpData1 member points to a LOGPALETTE structure used to retrieve the palette. The size of the memory allocated for the LOGPALETTE structure is specified in the dwSize1 member. Your driver should transfer the palette to the structure indicated by lpData1.

If an application just wants to determine the size of the palette, it sends the DVM_PALETTE message with both the VIDEO_CONFIGURE_GET and VIDEO_CONFIGURE_QUERYSIZE flags. Your driver should return the palette size in the lpdwReturn member.

If an application just wants to know if your driver supports DVM_PALETTE and its flags, it also sets the VIDEO_CONFIGURE_QUERY flag with VIDEO_CONFIGURE_GET or VIDEO_CONFIGURE_SET. (The VIDEO_CONFIGURE_QUERY flag without VIDEO_CONFIGURE_GET or VIDEO_CONFIGURE_SET is invalid.) Your device driver should return DV_ERR_OK if it supports the DVM_PALETTE message and the operation indicated with the set or get flag. Otherwise, it should return DV_ERR_NOTSUPPORTED.

DVM_PALETTE does not use the lpData2 and dwSize2 members.

Applications use the DVM_PALETTERGB555 message to associate an RGB555 palette with a video device channel. Only the VIDEO_CONFIGURE_SET and VIDEO_CONFIGURE_QUERY flags apply to this message. The VIDEO_CONFIGURE_SET flag modifies the DVM_PALETTERGB555 message to indicate that the driver should set a new palette. The lParam2 parameter used with DVM_PALETTERGB555 contains a pointer to a VIDEOCONFIGPARMS data structure.

When setting the palette, the lpData1 member points to a LOGPALETTE structure containing the new palette. The lpData2 member points to a 32 kilobyte RGB555 translation table. The device driver uses this table to translate the RGB555 triples into palette colors when capturing data in an 8 bit palette mode. The dwSize1 and dwSize2 members specify the size of the structures indicated by lpData1 and lpData2.

If an application just wants to know if your driver supports DVM_PALETTERGB555, it sends the VIDEO_CONFIGURE_QUERY flag with VIDEO_CONFIGURE_SET. (The VIDEO_CONFIGURE_QUERY flag without VIDEO_CONFIGURE_SET is invalid.) Your device driver should return DV_ERR_OK if it supports the DVM_PALETTERGB555 message. Otherwise, it should return DV_ERR_NOTSUPPORTED.


Obtaining the Device Driver Version

The DVM_GETVIDEOAPIVER message lets an application interrogate your device driver to determine the version of the video capture command set. Your driver should return VIDEOAPIVERSION in the DWORD buffer that lParam1 points to. This message does not have any flags associated with it.


Transferring Data From the Frame Buffer

The DVM_FRAME message lets an application obtain a single frame from the frame buffer.This message is the basis for the simplest form of video capture. Applications might use this to record animated sequences created frame-by-frame or to capture a single still image such as a photograph.

The following sequence of operations occurs when a client-application requests the transfer of a single video frame

  1. The client allocates the memory for the data buffer.
  2. The client sets a pointer to the empty data buffer in the VIDEOHDR data structure.
  3. The client sends the device driver a pointer to the VIDEOHDR data structure with the videoFrame function. (The destination channel must be a VIDEO_IN channel.)
  4. When the device driver receives the DVM_FRAME messages that Windows sends in response to videoFrame, it fills the data buffer with information from the frame buffer and updates the VIDEOHDR data structure. Note that the buffer might not have been prepared.
  5. When the device driver has filled a data buffer, it returns from the DVM_FRAME message. This returns control back to the client.
  6. After the client has finished with the data, it frees the memory used for the data.


Streaming Video Capture

Video capture device drivers use the DVM_STREAM messages sent to a VIDEO_IN channel to stream full motion video to the client-application. Your device driver will use the following messages while it is streaming video:

Message | Description
DVM_STREAM_INIT | Initializes a video input stream.
DVM_STREAM_ALLOCBUFFER | Lets devices with substantial on-board memory to allocate capture buffers
DVM_STREAM_FREEBUFFER | Frees buffers allocated in hardware
DVM_STREAM_PREPAREHEADER | Requests that the driver prepare a data buffer for input.
DVM_STREAM_ADDBUFFER | Adds a buffer to the video input stream queue.
DVM_STREAM_START | Begins streaming video input.
DVM_STREAM_STOP | Ends video input streaming.
DVM_STREAM_UNPREPAREHEADER | Requests that a driver clean up the preparation previously done on a data buffer.
DVM_STREAM_FINI | Closes and deallocates a video stream.


Data Transfer Model For Streaming Video Input

The data transfer model for streaming video input is similar to the model defined for the waveform device drivers. If you have worked with the waveform device drivers, many of the concepts used there will be usable with video capture device drivers.

The following sequence of operations occurs when streaming video data between a video capture device driver and a client-application

  1. The client allocates the memory buffers for the video data.
  2. The client initializes the data stream (DVM_STREAM_INIT).
  3. The client requests that the driver prepare the data buffers (DVM_STREAM_PREPAREHEADER).
  4. The client sends the empty data buffers to the driver (DVM_STREAM_ADDBUFFER).
  5. The driver puts the data buffers in its input queue.
  6. When the streaming operation begins with DVM_STREAM_START, the driver fills a data buffer and sets the done bit for the data buffer. The driver will then release the buffer from its queue and proceed to fill the next buffer.
  7. When the client is ready for data, it uses the done bit or callback to see if the data in the buffer is ready.
  8. After the client empties the buffer, it resets the done bit and sends the empty buffer back to the driver for it to add to its queue (DVM_STREAM_ADDBUFFER).

Once the stream starts, the client-application and the video capture driver do not communicate directly. The video capture driver fills the data buffers at the rate specified by the client-application using the frame rate information provided with the DVM_STREAM_INIT message. It fills the buffers without waiting for any synchronization signal from the application as long as buffers are available and it is not paused or stopped by the application. The buffers are filled in the order that the driver receives them from the application. (If the device driver runs out of buffers, it should set an error flag. A client-application can use the DVM_STREAM_GETERROR message to test for this condition.)

The client-application expects the buffers back in the order that it sends them to the device driver. When it is ready for more data, it will check the done bit of the next buffer it expects to receive from the device driver. If the done bit is set, the application continues operation with that buffer. If the done bit is not set, the application will periodically check the done bit while it waits for the buffer.

Streaming continues until it is stopped by the application.

The following sequence of operations occurs when the application has finished capturing data

  1. When the client stops the streaming operation with DVM_STREAM_STOP, the driver stops filling buffers.
  2. If the client wants to restart streaming, it sends DVM_STREAM_START. If the client is finished streaming, it requests that the driver unprepare the data buffers (DVM_STREAM_UNPREPAREHEADER).
  3. The client releases the data stream (DVM_STREAM_FINI) and frees the memory allocated for the video data.

Initializing the Data Stream

The DVM_STREAM_INIT message initializes a video device for data streaming. This message must precede all other streaming messages for a channel.

The lParam1 parameter of DVM_STREAM_INIT specifies a far pointer to a VIDEO_STREAM_INIT_PARMS structure and the lParam2 specifies its size in bytes. The VIDEO_STREAM_INIT_PARMS structure has the following members:

typedef struct tag_video_stream_init_parms {
    DWORD  dwMicroSecPerFrame;
    DWORD  dwCallback;
    DWORD  dwCallbackInst;
    DWORD  dwFlags;
    DWORD  hVideo;
} VIDEO_STREAM_INIT_PARMS;

The different channels handle the message and data structure in different ways.

For external in channels, DVM_STREAM_INIT enables capture of images into the frame buffer. External in channels should expect this message at any time. They can ignore the dwMicroSecPerFrame, dwCallback, and dwCallbackInst members. The dwFlags member must contain the VIDEO_ALLOWSYNC flag for synchronous devices.

For video in channels, DVM_STREAM_INIT sets the capture rate and callback information. The dwMicroSecPerFrame member specifies the number of microseconds between successive capture frames. The dwCallback member contains the address of a callback function or the handle to a window called during video streaming. (This parameter is set to NULL if a callback function or window is not used.) The callback procedure processes any messages related to the progress of recording. If a callback function address is specified, dwFlags is set to CALLBACK_FUNCTION. If the application has any data to pass to the callback function, it specifies the data in dwCallbackInst. If a callback window handle is specified, dwFlags is set to CALLBACK_WINDOW. Drivers can also use DriverCallback to send a message to a window or callback function.

For external out channels, DVM_STREAM_INIT enables overlay display. External out channels should expect this message at any time. They can ignore the dwMicroSecPerFrame, dwCallback, and dwCallbackInst members. The dwFlags member contains any flags that might affect the external out channel.

All channels return DV_ERR_OK if the message was processed successfully. All channels should return DV_ERR_ALLOCATED if the channel is already allocated or DV_ERR_NOMEM if they are unable to allocate or lock memory.

Preparing Data Buffers

Because video data buffers must be accessed at interrupt time, the memory allocated for them is subject to the requirements for interrupt driven drivers. Rather than have the client-application prepare the memory before sending data blocks to the driver, the client requests that the driver do the preparation.

Most drivers can respond to the DVM_STREAM_PREPAREHEADER and DVM_STREAM_UNPREPAREHEADER messages) by returning a DV_ERR_UNSUPPORTED error. When your driver returns DV_ERR_UNSUPPORTED, the system will perform the necessary preparation on the data block. This consists of page locking the header and data sections so the driver can access them at interrupt time.

If your device driver does not need the data to be page locked (for example, if you immediately copy the data to an on-card buffer) or if you have additional preparation to do to the buffer, you might respond to these messages yourself instead of having the system handle them. You should respond to both DVM_STREAM_PREPAREHEADER and DVM_STREAM_UNPREPAREHEADER, or to neither.

Starting and Stopping Streaming

DVM_STREAM_START starts a video stream. For video in channels, this message begins transferring the contents of the frame buffer to the system supplied buffers. In response to DVM_STREAM_START, your driver should enable the interrupts it needs and begin capturing the images and copying them to the application supplied buffers.

DVM_STREAM_STOP stops a video stream. When a video in channel receives this message, it stops filling buffers and retains any empty buffers remaining in the queue. Your driver can disable any interrupts it needs to capture data, however, it should be prepared to receive the DVM_STREAM_START message to resume capturing data. If data capture has not started, this message has no effect and the device driver returns DV_ERR_OK.

Neither DVM_STREAM_START nor DVM_STEAM_STOP use lParam1 or lParam2. Your driver should return DV_ERR_OK if it processed the message successfully. It should return DV_ERR_NOTSUPPORTED if it does not support the message.

Ending Capture

The DVM_STREAM_FINI message terminates data streaming. This should always be the last streaming message received by a channel.

For external in channels, DVM_STREAM_FINI disables capture of images into the frame buffer. External in channels should expect this message at any time. DVM_STREAM_FINI might not have a corresponding DVM_STREAM_INIT message.

For video in channels, DVM_STREAM_FINI finishes data streaming process. Your driver can free any resources that it used to capture data.

For external out channels, DVM_STREAM_FINI disables overlay display. External out channels should expect this message at any time. DVM_STREAM_FINI might not have a corresponding DVM_STREAM_INIT message.

All channels return DV_ERR_OK if the message was processed successfully. The video in channels should return DV_ERR_STILLPLAYING if there are still buffers in its queue.

Additional Stream Messages

The client-application uses DVM_STREAM_RESET to stop data streaming and release all buffers. When your driver gets this message it should return to the state set with DVM_STREAM_INIT.

The client-application uses DVM_STREAM_GETERROR to obtain the error status of a channel. The lParam1 and lParam2 parameters point to two DWORDS your driver should use to return error information. Fill the DWORD specified by lParam1 with the value of the most recent error. Typically, the error encountered is DV_ERR_NO_BUFFERS. If your driver has not encountered an error or if it receives this message when a stream is not initialized, set the DWORD to DV_ERR_OK. Fill the DWORD specified by lParam2 with the number of frames dropped because of the error.

After processing this message your driver should reset its error value and count of frames dropped. Drivers that do not have access to interrupts might use this message to trigger buffer processing.

Return DV_ERR_OK if your driver processes the message without an error. If your driver does not support this message, return DV_ERR_NOTSUPPORTED.

Applications use the DVM_STREAM_GETPOSITION message to retrieve the current position of the video in stream. The lParam1 parameter specifies a far pointer to a MMTIME data structure and the lParam2 parameter specifies its size. The MMTIME structure has the following members:

typedef struct mmtime_tag {
    UINT  wType;
    union {
        DWORD  ms;
        DWORD  sample;
        DWORD  cb;
        struct {
            BYTE  hour;
            BYTE  min;
            BYTE  sec;
            BYTE  frame;
            BYTE  fps;
            BYTE  dummy;
        } smpte;
        struct {
            DWORD  songptrpos;
        } midi;
    } u;
} MMTIME;

When your device gets DVM_STREAM_POSITION, it should check the wtype member. If your driver does not support the format specified, it specifies its current time format in the member. The application checks the format specified in this member when the message returns.

Video capture drivers typically return time in the millisecond format. Normally, your driver sets the position to zero when streaming starts with DVM_STREAM_START.

Your driver should returns DV_ERR_OK if it processed the message successfully. It can return DV_ERR_PARM1 if the data structure supplied for the format has invalid data or DV_ERR_SIZEFIELD if the data structure is too small.


Using Video Capture Device Drivers

This section illustrates the use of the ICM functions.


Handling the DRV_OPEN and DRV_CLOSE Messages

The following code fragment illustrates the routines the sample device driver uses to handle the DRV_OPEN and DRV_CLOSE messages. This device driver supports only one instance of each video channel.

PCHANNEL NEAR PASCAL VideoOpen(LPVIDEO_OPEN_PARMS lpOpenParms)
{
    PCHANNEL            pChannel;
    LPDEVICE_INIT       lpDI = &devInit;
    LPDWORD             lpdwError = &lpOpenParms->dwError;
    DWORD               dwFlags = lpOpenParms->dwFlags;

    // We're passed a DevNode in the VIDEO_OPEN_PARMS, which we'll pass
    // down to the VxD.  This is really only needed when multiple
    // instances of identical hardware are installed, and we want to
    // let the application select which instance to use.
    // The VxD must then compare the DevNode passed in with its internal
    // list of DevNodes and use the corresponding hardware.

    lpDI->dnDevNode = lpOpenParms->dnDevNode;

    //
    //  if this is the very first open then init the hardware.
    //
    AuxDebugEx (2, DEBUGLINE "VideoOpen, RefCount = %d\r\n", gwDriverUsage);

    *lpdwError = DV_ERR_OK;

    // Only initalize the first time opened
    if (!fDeviceInitialized) {

        // Acquire use of the capture hardware
        if (!(AcquireVXP500( gpVxDEntry, &devInit ))) {
            D1("AcquireFailed");
            *lpdwError = DV_ERR_NOTDETECTED;
        }

        // Perform hardware initialization
        if (!HardwareInit(lpDI)) {
            *lpdwError = DV_ERR_NOTDETECTED;
            return NULL;
        }

        ConfigGetSettings();   // Get global hue, sat, channel, zoom.

        if (ConfigInit(lpDI)) {
            if (TransInit()) {  // Allocate the YUV conversion tables
                *lpdwError = DV_ERR_NOMEM;
            } else
                fDeviceInitialized = TRUE;
        } else
            *lpdwError = DV_ERR_NOMEM;

        if (*lpdwError != DV_ERR_OK) {
            TransFini();
            HardwareFini();
            return NULL;
        }
    } // end if this is the first open.

    // get instance memory
    pChannel = (PCHANNEL)LocalAlloc (LPTR, sizeof(CHANNEL));
    if (pChannel == NULL)
        return (PCHANNEL) NULL;

    //
    //  make sure the channel is not already in use
    //
    switch (dwFlags &
        (VIDEO_EXTERNALIN | VIDEO_EXTERNALOUT | VIDEO_IN | VIDEO_OUT)) {

    case VIDEO_EXTERNALIN:
        if (gwCaptureUsage >= MAX_CAPTURE_CHANNELS)
            goto error;
        gwCaptureUsage++;
        break;

    case VIDEO_EXTERNALOUT:
        if ( gwDisplayUsage >= MAX_DISPLAY_CHANNELS)
            goto error;
        gwDisplayUsage++;
        break;

    case VIDEO_IN:
        if ( gwVideoInUsage >= MAX_IN_CHANNELS)
            goto error;
        gwVideoInUsage++;
        break;

    case VIDEO_OUT:
        if ( gwVideoOutUsage >= MAX_OUT_CHANNELS)
            goto error;
        gwVideoOutUsage++;
        break;

    default:
        goto error;
    }

    //
    // Now that the hardware is allocated init our instance struct.
    //
    pChannel->fccType = OPEN_TYPE_VCAP;
    pChannel->dwOpenType = (dwFlags
        &(VIDEO_EXTERNALIN | VIDEO_EXTERNALOUT | VIDEO_IN | VIDEO_OUT));
    pChannel->dwOpenFlags = dwFlags;
    pChannel->lpVHdr = NULL;
    pChannel->dwError = 0L;

    gwDriverUsage++;
    return pChannel;

error:
    if (pChannel)
        LocalFree((HLOCAL)pChannel);

    *lpdwError = DV_ERR_ALLOCATED;
    return NULL;
}

The following example shows the function used to close the example video capture device driver:

DWORD NEAR PASCAL VideoClose(PCHANNEL pChannel)
{
    // Decrement the channel open counters
    switch (pChannel->dwOpenType) {

    case VIDEO_EXTERNALIN:
        gwCaptureUsage--;
        break;

    case VIDEO_EXTERNALOUT:
        gwDisplayUsage--;
        break;

    case VIDEO_IN:
        // If started, or buffers in the queue,
        // don't let the close happen
        if (gfVideoInStarted || lpVHdrFirst)
            return DV_ERR_STILLPLAYING;
        gwVideoInUsage--;
        break;

    case VIDEO_OUT:
        gwVideoOutUsage--;
        break;

    default:
        break;
    }

    gwDriverUsage--;        // Decrement overall driver useage count.

    if (gwDriverUsage == 0) {
        HardwareFini();        // Shut down the device.
        TransFini();           // Free translation tables.
        ReleaseVXP500( gpVxDEntry, &devInit );
        fDeviceInitialized = FALSE;
    }

    // Free the instance data.
    LocalFree((HLOCAL)pChannel);
    return DV_ERR_OK;
}


Configuring the Channels of a Video Capture Driver

The sample driver uses the following function to handle the DVM_DIALOG message (this function is called from the VideoProcessMessage function):

DWORD NEAR PASCAL VideoDialog (DWORD dwOpenType, HWND hWndParent, DWORD dwFlags)
{

    switch (dwOpenType) {

        case VIDEO_EXTERNALIN:
            if (dwFlags & VIDEO_DLG_QUERY)
                return DV_ERR_OK;       // Channel has a dialog box
            DialogBox(ghModule, MAKEINTRESOURCE(DLG_VIDEOSOURCE),
                    (HWND)hWndParent, VideoSourceDlgProc);
            break;

        case VIDEO_IN:
            if (dwFlags & VIDEO_DLG_QUERY)
                return DV_ERR_OK;       // Channel has a dialog box
            DialogBox(ghModule, MAKEINTRESOURCE(DLG_VIDEOFORMAT),
                    (HWND)hWndParent, VideoFormatDlgProc);
            break;

        case VIDEO_OUT:
            return DV_ERR_NOTSUPPORTED; //Channel does not have a dialog
                                        // box

        case VIDEO_EXTERNALOUT:
            if (dwFlags & VIDEO_DLG_QUERY)
                return DV_ERR_OK;       // Channel has a dialog box
            DialogBox(ghModule, MAKEINTRESOURCE (DLG_VIDEODISPLAY),
                    (HWND)hWndParent, VideoMonitorDlgProc);
            break;

        default:
            return DV_ERR_NOTSUPPORTED;
    }
    return DV_ERR_OK;
}


Setting and Obtaining a Video Capture Palette

The following example shows how the sample device driver handles the DVM_PALETTE message. The structure for DVM_PALETTERGB555 is similar.

DWORD NEAR PASCAL VideoConfigureMessage(PCHANNEL pChannel, UINT msg,
    LONG lParam1, LONG lParam2)
{
    LPVIDEOCONFIGPARMS lpcp;
    LPDWORD     lpdwReturn;  // Return parameter from configure
    LPVOID      lpData1;     // Pointer to data1
    DWORD       dwSize1;     // size of data buffer1
    LPVOID      lpData2;     // Pointer to data2
    DWORD       dwSize2;     // size of data buffer2
    DWORD       dwFlags;

    if (pChannel-> dwOpenType != VIDEO_IN)
        return DV_ERR_NOTSUPPORTED;

    dwFlags = lParam1;

    lpcp = (LPVIDEOCONFIGPARMS) lParam2;
    lpdwReturn = lpcp-> lpdwReturn;
    lpData1 = lpcp-> lpData1;
    dwSize1 = lpcp-> dwSize1;
    lpData2 = lpcp-> lpData2;
    dwSize2 = lpcp-> dwSize2;

switch (msg) {

    case DVM_PALETTE:

        switch (dwFlags) {

            case (VIDEO_CONFIGURE_QUERY | VIDEO_CONFIGURE_SET):
            case (VIDEO_CONFIGURE_QUERY | VIDEO_CONFIGURE_GET):
                return DV_ERR_OK;

            case VIDEO_CONFIGURE_QUERYSIZE:
            case (VIDEO_CONFIGURE_QUERYSIZE | VIDEO_CONFIGURE_GET):
               *lpdwReturn = sizeof(LOGPALETTE) +
                    (palCurrent.palNumEntries-1) *
                    sizeof(PALETTEENTRY);
               break;

            case VIDEO_CONFIGURE_SET:
            case (VIDEO_CONFIGURE_SET | VIDEO_CONFIGURE_CURRENT):
                if (!lpData1)    // points to a LOGPALETTE structure.
                    return DV_ERR_PARAM1;
                return (SetDestPalette ( (LPLOGPALETTE) lpData1,
                   (LPBYTE) NULL));
                break;

            case VIDEO_CONFIGURE_GET:
            case (VIDEO_CONFIGURE_GET | VIDEO_CONFIGURE_CURRENT):
               return (GetDestPalette ( (LPLOGPALETTE) lpData1,
                        (WORD) dwSize1));
               break;

            default:
               return DV_ERR_NOTSUPPORTED;

        } // end of DVM_PALETTE switch

        return DV_ERR_OK;
        .
        .
        .

    default:        // Not a message that we understand
        return DV_ERR_NOTSUPPORTED;

    } // end of message switch

    return DV_ERR_NOTSUPPORTED;
}


Reference

This section is a reference to the messages and data structures provided by Windows for use by video capture device drivers. There are separate sections for messages and data structures.

Windows communicates with video capture device drivers through messages sent to the driver. The driver processes these messages with its DriverProc entry-point function. Each message name contains a prefix, identifying the type of the message. A message consists of three parts: a message number and two DWORD parameters. Message numbers are identified by predefined message names. The two DWORD parameters contain message-dependent values.

To | See these messages and data structures
Handle the DRV_OPEN message. | VIDEO_OPEN_PARMS
Configure the channels of a video capture driver. | DVM_DIALOG
Set and obtain video capture formats. | DVM_FORMAT
Set and obtain video source and destination rectangles. | DVM_DST_RECT DVM_SRC_RECT DVM_UPDATE VIDEO_CONFIGURE_GET
Determine channel capabilities. | DVM_GET_CHANNEL_CAPS CHANNEL_CAPS
Set and obtain a video capture palette. | DVM_PALETTE DVM_PALETTERGB555 VIDEOCONFIGPARMS
Obtain the device driver version. | DVM_GETVIDEOAPIVER
Transfer data from the frame buffer. | DVM_FRAME
Allocate and free capture buffers on the capture device | DVM_STREAM_ALLOCBUFFER DVM_STREAM_FREEBUFFER
Prepare and unprepare buffers for streaming video capture. | DVM_STREAM_PREPAREHEADER DVM_STREAM_ADDBUFFER DVM_STREAM_UNPREPAREHEADER
Initialize and terminate streaming video capture. | DVM_STREAM_FINI DVM_STREAM_INIT VIDEO_STREAM_INIT_PARMS
Start and stop video streaming capture. | DVM_STREAM_START DVM_STREAM_STOP
Reset, get error information, or get the current stream position. | DVM_STREAM_RESET DVM_STREAM_GETERROR DVM_GETERRORTEXT VIDEO_GETERRORTEXT_PARMS DVM_STREAM_GETPOSITION
Send messages to the video capture callback function. | MM_DRVM_CLOSE MM_DRVM_DATA MM_DRVM_ERROR MM_DRVM_OPEN


Messages

The following topics describe the messages.


DVM_DIALOG

Notifies a video capture driver to display a dialog box for setting the video parameters of a channel.

  • Returns DV_ERR_OK if successful or an error code otherwise. The following errors are defined:
DV_ERR_INVALHANDLE | Indicates the device handle is invalid.
DV_ERR_NOTSUPPORTED | Indicates the message is not supported.

dwParam1
Handle to the parent window.
dwFlags
Flags for the dialog box.

The VIDEO_DLG_QUERY flag indicates that the driver immediately returns DV_ERR_OK if it supplies a dialog box for the channel or DV_ERR_NOTSUPPORTED otherwise.

Typically, this dialog box lets the user configure a video channel. For example, a VIDEO_IN channel might supply a dialog box to let the user select image dimensions and bit depth. Each channel type (VIDEO_IN, VIDEO_OUT, VIDEO_EXTERNALIN, and VIDEO_EXTERNALOUT) can have a unique configuration dialog box.


DVM_DST_RECT

Notifies a video capture driver to set and retrieve the destination rectangle used by a video device channel.

  • Returns DV_ERR_OK if successful or an error code otherwise. The DV_ERR_NOTSUPPORTED error indicates this message is not supported.
lpDstRect
Address of a RECT structure.
dwFlags
Flags that indicate the type of transfer requested. The following flags are defined:
VIDEO_CONFIGURE_SET | Sends a rectangle to the device driver.
VIDEO_CONFIGURE_GET | Gets the current rectangle from the device driver.
VIDEO_CONFIGURE_MIN | Gets the minimum destination rectangle from the device driver.
VIDEO_CONFIGURE_MAX | Gets the maximum destination rectangle from the device driver.
VIDEO_CONFIGURE_CURRENT | Gets or sets the current destination rectangle.
VIDEO_CONFIGURE_QUERY | Interrogates the device driver to determine if it supports the message.

Either the VIDEO_CONFIGURE_SET or the VIDEO_CONFIGURE_GET flag must be set to specify the direction of the transfer.

The use of the destination rectangle for a channel depends on the channel type. For the VIDEO_EXTERNALIN channel, the destination rectangle specifies the location in the frame buffer used to digitize the image. This rectangle is specified in pixel coordinates.

For the VIDEO_EXTERNALOUT channel, the destination rectangle specifies the location used to display the overlay image. This rectangle is given in Windows screen coordinates.

For the VIDEO_IN and VIDEO_OUT channels, the destination rectangle is currently undefined.


DVM_FORMAT

Notifies a video capture driver to configure the format of the VIDEO_IN channel.

  • Returns DV_ERR_OK if successful or an error code otherwise. The DV_ERR_NOTSUPPORTED error indicates the message in not supported.
dwFlags
Flags to indicate the type of format transfer requested. The following flags are defined:
VIDEO_CONFIGURE_SET | Sets the current format.
VIDEO_CONFIGURE_GET | Gets the current format.
VIDEO_CONFIGURE_QUERY | Interrogates the driver to determine if it supports the message.
VIDEO_CONFIGURE_QUERYSIZE | Interrogates the driver for the size, in bytes, of the format information referenced by lpdwReturn. This flag must be used with VIDEO_CONFIGURE_GET.

lpVConfigParms
Address of a VIDEOCONFIGPARMS structure. This structure has the following members:
lpdwReturn | Address of a DWORD. If the VIDEO_CONFIGURE_QUERYSIZE flag is used, the driver fills this field with the size (in bytes) of the BITMAPINFOHEADER data structure.
lpData1 | Address of a BITMAPINFOHEADER structure.
dwSize1 | Size, in bytes, of the BITMAPINFOHEADER structure.
lpData2, dwSize2 | Not used.

Either the VIDEO_CONFIGURE_SET or the VIDEO_CONFIGURE_GET flag must be set to specify the direction of the transfer.

The DVM_FORMAT message globally defines the attributes of the frame buffer. This includes dimensions, color depth, and compression of images transferred with DVM_FRAME and buffers transferred during streaming capture. Changing the format may affect overall dimensions of the active frame buffer as well as bit depth and color space representation. Since changing between NTSC and PAL video standards can also affect image dimensions, applications should request the current format following display of the VIDEO_EXTERNALIN channel dialog box.

See Also

VIDEOCONFIGPARMS


DVM_FRAME

Notifies a video capture driver to transfer a single frame from the video device.

  • Returns DV_ERR_OK if successful or an error code otherwise.The DV_ERR_SIZEFIELD error indicates the field size is too small.
dwParam1
Address of a VIDEOHDR structure identifying the buffer.
dwParam2
Size, in bytes, of the VIDEOHDR structure.

This message returns immediately after transferring the frame. For a VIDEO_IN channel, this message transfers an image from the hardware frame buffer to the buffer specified in the VIDEOHDR. For a VIDEO_OUT channel, this message transfers an image from the buffer specified in the VIDEOHDR to the hardware frame buffer.


DVM_GET_CHANNEL_CAPS

Notifies a video capture driver to return the capabilities of a channel to the client application.

  • Returns DV_ERR_OK if successful or an error code otherwise. The DV_ERR_NOTSUPPORTED error indicates the message is not supported.
lpChannelCaps
Address of a CHANNEL_CAPS data structure.
dwSize
Size, in bytes, of the CHANNEL_CAPS data structure.


DVM_GETERRORTEXT

Notifies a video capture driver to retrieve the textual description of an error.

  • Returns DV_ERR_OK if successful or an error code otherwise. The DV_ERR_BADERRNUM error indicates the specified error number is out of range.
dwParam1
Address of a VIDEO_GETERRORTEXT_PARMS structure. The structure identifies the error number and return buffer.
dwParam2
Not used.

If the error description is longer than the specified buffer, the description is truncated. The returned error string is always zero-terminated. If the size of the return buffer is zero, a string description is not returned and DV_ERR_OK is used as the return value.


DVM_GETVIDEOAPIVER

Notifies a video capture driver to supply the version of the video capture command set it uses.

  • Returns DV_ERR_OK if successful.
dwParam1
Address of a DWORD to be filled with the version. Set this value to VIDEOAPIVERSION.
dwParam2
Not used.


DVM_PALETTE

Notifies a video capture driver to set and retrieve a logical palette used by a video device channel. This message applies only to VIDEO_IN and VIDEO_OUT channels.

  • Returns DV_ERR_OK if successful or an error code otherwise. The DV_ERR_NOTSUPPORTED error indicates the message is not supported.
dwFlags
Flags that indicate the type of palette transfer requested. The following flags are defined:
VIDEO_CONFIGURE_SET | Sends a palette to the driver.
VIDEO_CONFIGURE_GET | Obtains the current palette from the driver.
VIDEO_CONFIGURE_QUERY | Interrogates the driver to determine if it supports the message.
VIDEO_CONFIGURE_QUERYSIZE | Returns the size in bytes of the palette in lpdwReturn. This flag is only valid if the VIDEO_CONFIGURE_GET flag is also set.

lpVConfigParms
Address of a VIDEOCONFIGPARMS structure. The VIDEOCONFIGPARMS structure has the following members:
lpdwReturn | Address of a DWORD. If the VIDEO_CONFIGURE_QUERYSIZE flag is used, the driver fills this field with the size (in bytes) of the logical palette.
lpData1 | Address of a LOGPALETTE structure.
dwSize1 | Size, in bytes, of the LOGPALETTE structure.
lpData2, dwSize2 | Not used.

Either the VIDEO_CONFIGURE_SET or the VIDEO_CONFIGURE_GET flag must be set to specify the direction of the transfer.

A palette is used when converting between frame buffer internal data formats and 8-bit palettized DIBs.


DVM_PALETTERGB555

Notifies a video capture driver to associate an RGB555 palette with a video device channel. Applications can provide an RGB555 translation table to a driver for fast conversions between RGB formats and 8-bit palettized formats.

  • Returns DV_ERR_OK if successful or an error code otherwise. The following error codes are defined:
DV_ERR_NOTSUPPORTED | Indicates the message is not supported.
DV_ERR_CREATEPALETTE | Indicates the driver is not able to associate the palette with the video device channel.
DV_ERR_PARM1 | Indicates the information supplied for dwParam1 is invalid.
DV_ERR_PARM2 | Indicates the information supplied for dwParam2 is invalid.
DV_ERR_SIZEFIELD | Indicates the data structure supplied for the format is too small.

dwFlags
Flags indicating the type of palette transfer requested. The following flags are defined:
VIDEO_CONFIGURE_SET | Indicates values are being sent to the driver.
VIDEO_CONFIGURE_QUERY | This flag, when combined with VIDEO_CONFIGURE_SET is used to query the driver to determine if it supports the message.

lpVConfigParms
Address of a VIDEOCONFIGPARMS structure. The VIDEOCONFIGPARMS structure has the following members:
lpdwReturn | Not used.
lpData1 | Address of a LOGPALETTE structure.
dwSize1 | Size, in bytes, of the LOGPALETTE structure.
lpData2 | Address of a 32 kilobyte RGB555 translation table . This table is used by the device driver to translate from RGB555 triplets into palette colors when capturing in 8 bit palette mode.
dwSize2 | Size, in bytes, of the translate table. This value must be 32,768.

This message applies only to VIDEO_IN and VIDEO_OUT channels.

A translation table provides a fast method of converting between RGB and palettized color spaces. The palette index corresponding to an RGB color is found by indexing the translation table at xRRRRRGGGGGBBBBB (the five most significant bits of each color component is used to create the index).


DVM_SRC_RECT

Notifies a video capture driver to set and retrieve the source rectangle used by a video device channel.

  • Returns DV_ERR_OK if successful or an error code otherwise. The DV_ERR_NOTSUPPORTED error code indicates the message is not supported.
lpSrcRect
Address of a RECT structure.
dwFlags
Flags that indicate the type of transfer requested. The following flags are defined:
VIDEO_CONFIGURE_SET | Sends a source rectangle to the device driver.
VIDEO_CONFIGURE_GET | Gets the current source rectangle from the device driver.
VIDEO_CONFIGURE_MIN | Gets the minimum source rectangle from the device driver.
VIDEO_CONFIGURE_MAX | Gets the maximum source rectangle from the device driver.
VIDEO_CONFIGURE_CURRENT | Gets or sets the current source rectangle.
VIDEO_CONFIGURE_QUERY | Interrogates the driver to determine if it supports the message.

Either the VIDEO_CONFIGURE_SET or the VIDEO_CONFIGURE_GET flag must be set, specifying the direction of the transfer.

The use of the source rectangle for a channel depends on the channel type. For the VIDEO_EXTERNALOUT channel, the source rectangle specifies the portion of the frame buffer displayed in the overlay window, in pixel coordinates. For the VIDEO_IN, VIDEO_EXTERNALIN, and VIDEO_OUT channels, the source rectangle is currently undefined.


DVM_STREAM_ADDBUFFER

Notifies a video capture driver to fill an input buffer with video data and return the full buffer to the client application.

  • Returns DV_ERR_OK if successful or an error code otherwise. The following errors are defined:
DV_ERR_NONSPECIFIC | Indicates a buffer is not specified.
DV_ERR_UNPREPARED | Indicates the buffer was not prepared.

dwParam1
Address of a VIDEOHDR structure identifying the buffer.
dwParam2
Size, in bytes, of the VIDEOHDR structure.

The data buffer must be prepared with DVM_STREAM_PREPAREHEADER before it is passed with DVM_STREAM_ADDBUFFER. The VIDEOHDR data structure and the data buffer pointed to by its lpData field must be allocated with GlobalAlloc using the GMEM_MOVEABLE and GMEM_SHARE flags, and locked with GlobalLock.


DVM_STREAM_ALLOCBUFFER

Notifies a video capture driver to allocate a capture buffer from memory located on a video capture device.

  • Returns DV_ERR_OK if successful or an error code otherwise. The following errors are defined:
DV_ERR_INVALHANDLE | Indicates the specified device handle is not valid.
DV_ERR_NOMEM | Indicates the device is unable to allocate or lock memory.
DV_ERR_NOTSUPPORTED | Indicates the driver does no have on-board memory.

dwParam1
Address of a LPBYTE to return the address of the driver-allocated buffer.
dwParam2
Size, in bytes, of the buffer.

Normally, only devices that provide substantial on-board not included in the system heap should respond to this message. Devices that support this message can use faster capture rates because fewer data copy operations are needed during capture.

If the driver repsonds without error to this message, it must store the address of the allocated buffer in the location pointed to by dwParam1. The reference to memory outside the system heap must remain valid until the buffer is freed by the DVM_STREAM_FREEBUFFER message.

The buffer size can be larger than the dwBufferLength member of the VIDEOHDR structure to allow for sector alignment on the disk. (dwBufferLength specifies the amount of memory needed to store an image of maximum height, width, and color depth.)

If a 16-bit driver allocates buffers via this method, the buffer pointer returned must be a tiled 16:16 pointer, similar to that returned by GlobalAlloc and GlobalLock.

The buffer allocated must be accessible for DMA by the operating system.


DVM_STREAM_FREEBUFFER

Notifies a video capture driver to free data buffers on the capture device that were allocated using the DVM_STREAM_ALLOCBUFFER message.

  • Returns DV_ERR_OK if successful or an error code otherwise. The following errors are defined:
DV_ERR_INVALHANDLE | Indicates the specified device handle is not valid.
DV_ERR_NOTSUPPORTED | Indicates the device does not have on-board memory.

dwParam1
Address of the buffer to be freed.
dwParam2
Not used.


DVM_STREAM_FINI

Notifies a video capture driver to terminate streaming on a video channel.

  • Returns DV_ERR_OK if successful or an error code otherwise. The DV_ERR_STILLPLAYING error code Indicates there are still buffers in the queue.
dwParam1, dwParam2
Not used.

This message should always be the last streaming message received by a channel.

If all the input buffers sent with DVM_STREAM_ADDBUFFER have not been returned to the application, your driver should fail the message. Client applications should send DVM_STREAM_RESET to mark all pending buffers as done prior to sending DVM_STREAM_FINI.

For VIDEO_EXTERNALIN channels, this message halts capturing of data to the frame buffer.

For VIDEO_EXTERNALOUT channels that support overlay, this message disables the overlay video.


DVM_STREAM_GETERROR

Notifies a video capture driver to supply the status of a channel.

  • Returns DV_ERR_OK if no error occurred or an error code otherwise. The DV_ERR_NOTSUPPORTED error code indicates the message is not supported.
dwParam1
Address of a DWORD that the device will fill with the value of the most recent error.
dwParam2
Address of a DWORD that the device will fill with the number of frames dropped.

A device driver should reset its internal error values and count of frames dropped to zero after it processes this message.

Client applications should send this message frequently during capture since some device drivers that do not have access to interrupts use this message to trigger buffer processing.


DVM_STREAM_GETPOSITION

Notifies a video capture driver to retrieve the current position of the VIDEO_IN stream.

  • Returns DV_ERR_OK if successful or an error code otherwise. The following errors are defined:
DV_ERR_PARM1 | Indicates the data structure supplied for the format has invalid data.
DV_ERR_SIZEFIELD | Indicates the data structure supplied for the format is too small.

dwParam1
Address of a MMTIME structure.
dwParam2
Size, in bytes, of the MMTIME structure.

If a device does not support the format specified in the wtype field of the MMTIME data structure it specifies the current time format in the field. The application checks the format specified in this field when the message returns. Video capture drivers typically return time in the milliseconds format.

The device sets the position to zero when it receives the DVM_STREAM_START message.


DVM_STREAM_INIT

Notifies a video capture driver to initialize a video device for streaming.

  • Returns DV_ERR_OK if successful or an error code otherwise.. Otherwise, it returns an error number. The following errors are defined:
DV_ERR_ALLOCATED | Indicates the specified resource is already allocated.
DV_ERR_NOMEM | Indicates the driver is unable to allocate or lock memory.

dwParam1
Address of a VIDEO_STREAM_INIT_PARMS structure.
dwParam2
Size, in bytes, of the VIDEO_STREAM_INIT_PARMS structure.

This message must precede all other streaming messages for a channel.

If a window or callback function will receive callback messages, the device driver uses the following messages to indicate the progress of video input: MM_DRVM_OPEN, MM_DRVM_CLOSE, MM_DRVM_DATA, and MM_DRVM_ERROR.

If a callback function is used, it must reside in a DLL. You do not have to use MakeProcInstance to get a procedure-instance address for the callback function.

For VIDEO_EXTERNALIN channels, DVM_STREAM_INIT triggers capturing of data to the frame buffer.

For VIDEO_EXTERNALOUT channels with overlay capabilities, DVM_STREAM_INIT enables the overlay.

See Also

VIDEO_STREAM_INIT_PARMS


DVM_STREAM_PREPAREHEADER

Notifies a video capture driver to prepare an input buffer for video streaming.

  • Returns DV_ERR_OK if successful or an error code otherwise. The following errors are defined:
DV_ERR_NOMEM | Indicates the driver is unable to allocate or lock memory.
DV_ERR_NOTSUPPORTED | Unable to prepare data block. (This return lets MSVIDEO prepare the data block.)

dwParam1
Address of a VIDEOHDR structure identifying the buffer.
dwParam2
Size, in bytes, of the VIDEOHDR structure.

The VIDEOHDR data structure and the data block pointed to by its lpData field must be allocated with GlobalAlloc using the GMEM_MOVEABLE and GMEM_SHARE flags, and locked with GlobalLock. Preparing a header previously prepared will have no effect, and the message will return zero. Typically, this operation is used to ensure that the buffer will be available for use at interrupt time.


DVM_STREAM_RESET

Notifies a video capture driver to stop input of a video stream and reset the current position to zero .

  • Returns DV_ERR_OK if successful or an error code otherwise.The DV_ERR_NOTSUPPORTED error code indicates the message is not supported.
dwParam1, dwParam2
Not used.

All pending buffers are marked as done and returned to the application.

When a device driver receives this message, it should return to the state established for DVM_STREAM_INIT.


DVM_STREAM_START

Notifies a video capture driver to start a video stream.

  • Returns DV_ERR_OK if successful or an error code otherwise.. Otherwise, it returns an error number. The DV_ERR_NOTSUPPORTED error code indicates the message is not supported.
dwParam1, dwParam2
Not used.

For VIDEO_IN channels, this message begins transferring the contents of the frame buffer to the system supplied buffers.


DVM_STREAM_STOP

Notifies a video capture driver to stop a video stream.

  • Returns DV_ERR_OK if successful or an error code otherwise. The DV_ERR_NOTSUPPORTED error code indicates the message is not supported.
dwParam1, dwParam2
Not used.

When a device receives this message, it marks the current buffer as done and retains any empty buffers remaining in the queue. For the buffer marked as done, the device places the actual length of the data in the dwBytesUsed field of the VIDEOHDR structure.

If the input is not started, this message has no effect and the device driver returns DV_ERR_OK.


DVM_STREAM_UNPREPAREHEADER

Notifies a video capture driver to clean up the preparation performed by DVM_STREAM_PREPAREHEADER.

  • Returns DV_ERR_OK if successful or an error code otherwise. The following errors are defined:
DV_ERR_STILLPLAYING | Indicates the data buffer is still in the device driver's available queue.
DV_ERR_NOTSUPPORTED | Unable to handle data block preparation. (This return lets MSVIDEO unprepare the data block.)

dwParam1
Address of a VIDEOHDR structure identifying the buffer.
dwParam2
Size, in bytes, of the VIDEOHDR structure.

This message is the complementary message to DVM_STREAM_PREPAREHEADER. This message unlocks the data buffer. Unpreparing a buffer not previously prepared has no effect, and the device driver returns DRV_ERR_OK.


DVM_UPDATE

Notifies a video capture driver to update the portion of the display associated with a VIDEO_EXTERNALOUT channel.

  • Returns DV_ERR_OK if successful or an error code otherwise. The DV_ERR_NOTSUPPORTED error code indicates the message is not supported.
hWndClient
Handle to the client window in which the VIDEO_EXTERNALOUT channel is displayed.
hDC
Device context to be repainted.

This message is typically sent to an overlay device whenever its client window is moved, sized, or requires painting.

This message is sent to a driver when video overlay is enabled and the overlay key color might need updating. Painting the key color is the responsibility of the driver. An application initiates this message whenever it receives a WM_PAINT, WM_MOVE, WM_POSITIONCHANGED, or WM_SIZE message.

This message always follows DVM_SRC_RECT and DVM_DST_RECT messages for the VIDEO_EXTERNALOUT channel.

The DVM_STREAM_INIT and DVM_STREAM_FINI messages are used to enable and disable the overlay.


MM_DRVM_CLOSE

Notifies a video-callback function or window that the video capture driver has received a DVM_STREAM_FINI message.

  • No return value.
dwParam1, dwParam2
Not used.

This message is used by video capture drivers, installable compressors, and other types of installable drivers whenever a device is closed.


MM_DRVM_DATA

Notifies a video callback function or window that the video capture driver returned the specified buffer to the application.

  • No return value.
dwParam1
Address of a VIDEOHDR structure identifying the buffer.
dwParam2
Not used.

For VIDEO_IN channels, buffers are returned when they have been filled. For VIDEO_OUT channels, buffers are returned after they are displayed. All buffers are returned for the DVM_STREAM_RESET message.

This message is used by video capture drivers, installable compressors, and other types of installable drivers to signal an application that new data is available.


MM_DRVM_ERROR

Notifies a video callback function or window that an the video capture driver detected the occurrence of an error.

  • No return value.
dwParam1
Error ID.
dwParam2
Not used.

Although a device driver can send this message for any reason, it most often indicates that no more buffers are available for video streaming.

The MM_DRVM_ERROR message is used by video capture drivers, installable compressors, and other types of installable drivers to signal an application that an error occurred.


MM_DRVM_OPEN

Notifies a video callback function or window that the video capture driver received a DVM_STREAM_INIT message.

  • No return value.
dwParam1, dwParam2
Not used.

This message is used by video capture drivers, installable video compressors, and other types of installable drivers whenever a device is opened.


Structures

The following topics describe the structures that are included.


CHANNEL_CAPS

Contains the capabilities of a video capture channel.

typedef struct {
    DWORD dwFlags;              //see below
    DWORD dwSrcRectXMod;        //see below
    DWORD dwSrcRectYMod;        //see below
    DWORD dwSrcRectWidthMod;    //see below
    DWORD dwSrcRectHeightMod;   //see below
    DWORD dwDstRectXMod;        //see below
    DWORD dwDstRectYMod;        //see below
    DWORD dwDstRectWidthMod;    //see below
    DWORD dwDstRectHeightMod;   //see below
} CHANNEL_CAPS;

Members

dwFlags
Flags providing information about the channel. The following flags are defined:
VCAPS_OVERLAY | Indicates the channel is capable of overlay. This flag is used only for VIDEO_EXTERNALOUT channels.
VCAPS_SRC_CAN_CLIP | Indicates the source rectangle can be set smaller than the maximum dimensions.
VCAPS_DST_CAN_CLIP | Indicates the destination rectangle can be set smaller than the maximum dimensions.
VCAPS_CAN_SCALE | Indicates the source rectangle can be a different size than the destination rectangle.

dwSrcRectXMod, dwSrcRectYMod
Granularity allowed when positioning the source rectangle in the horizontal and vertical directions.
dwSrcRectWidthMod, dwSrcRectHeightMod
Granularity allowed when setting the width and height of the source rectangle.
dwDstRectXMod, dwDstRectYMod
Returns the granularity allowed when positioning the destination rectangle in the horizontal and vertical directions.
dwDstRectWidthMod, dwDstRectHeightMod
Returns the granularity allowed when setting the width and height of the destination rectangle.

Some channels can only use source and destination rectangles which fall on 2, 4, or 8 pixel boundaries. Similarly, some channels only accept capture rectangles widths and heights that are multiples of a fixed value. Rectangle dimensions indicated by modulus operators are considered advisory. When requesting a particular rectangle, the application must always check the return value to insure the request was accepted by the driver. For example, if dwDstRectWidthMod is set to 64, the application might try to set destination rectangles with widths of 64, 128, 192, 256, ..., and 640 pixels. The driver might actually support a subset of these sizes and indicates the supported sizes with the return value of the DVM_DST_RECT message. If a channel supports arbitrarily positioned rectangles, with arbitrary sizes, the values above should all be set to 1.


VIDEO_GETERRORTEXT_PARMS

Contains a text buffer to return a description of a specified error.

typedef struct {
    DWORD dwError;             // error number
    LPSTR lpText;              // address of error return buffer
    DWORD dwLength;            // size, in bytes, of lpText
} VIDEO_GETERRORTEXT_PARMS;


VIDEO_OPEN_PARMS

Contains information defining the channel type to open on a video capture device.

typedef struct {
    DWORD dwSize;         //size of this structure
    FOURCC fccType;       //see below
    FOURCC fccComp;       //reserved; not used
    DWORD dwVersion;      //see below
    DWORD dwFlags;        //see below
    DWORD dwError;        //see below
    LPVOID pV1Reserved;   //reserved; not used
    LPVOID pV2Reserved;   //reserved; not used
    DWORD dwDevNode;      //see below
} VIDEO_OPEN_PARMS;       //see below

Members

fccType
Four-character code identifying the type of channel being opened. For capture devices, this is set to "vcap".
dwVersion
Current version number of the video capture command being used. Set this to VIDEOAPIVERSION.
dwFlags
Flags identifying the type of channel. The following flags are defined:
VIDEO_EXTERNALIN | Specifies a channel that loads data from an external source into a frame buffer. This can also be called the capture channel.
VIDEO_IN | Specifies a channel that transfers data from the frame buffer to system memory.
VIDEO_OUT | Specifies a channel that transfers data from system memory to the frame buffer.
VIDEO_EXTERNALOUT | Specifies a channel that controls display of frame buffer images. Display might be either on a second monitor, or via overlay.

dwError
Error value the driver should return to the client application if it fails the open.
dwDevNode
Device node in the registry for the plug and play capture driver; the value refers to the section of the registry that contains configuration information for the driver.

This structure is identical to the ICOPEN structure used by installable compressors. This lets a driver handle both video capture and decompressor messages with a single DriverProc entry point.


VIDEO_STREAM_INIT_PARMS

Contains members used to initialize a video stream for video capture.

typedef struct {
    DWORD dwMicroSecPerFrame;  //see below
    DWORD dwCallback;          //see below
    DWORD dwCallbackInst;      //see below
    DWORD dwFlags;             //see below
    DWORD hVideo;              //handle to the video channel
} VIDEO_STREAM_INIT_PARMS;

Members

dwMicroSecPerFrame
Number of microseconds between the start of one frame capture and the start of the next.
dwCallback
Address of a callback function or a handle to a window called during video recording. The callback function or window processes messages related to the progress of recording. This parameter is optional.
dwCallbackInst
User instance data passed to the callback function. This parameter is not used with window callbacks.
dwFlags
Flags for the data capture. The following flags are defined:
VIDEO_ALLOWSYNC | If this flag is not specified, the device will fail to open if it is a synchronous device.
CALLBACK_WINDOW | Indicates dwCallback contains a window handle.
CALLBACK_FUNCTION | Indicates dwCallback contains a callback function address.


VIDEOCONFIGPARMS

Contains message-specific configuration parameters.

typedef struct {
    LPDWORD lpdwReturn;   // see below
    LPVOID lpData1;       // see below
    DWORD dwSize1;        // see below
    LPVOID lpData2;       // see below
    DWORD dwSize2;        // see below
} VIDEOCONFIGPARMS;       // see below

Members

lpdwReturn
Address of a DWORD to be filled with a message-specific return value.
lpData1, lpData2
Addresses of message-specific data.
dwSize1
Size, in bytes, of the message-specific data referenced by lpData1 and lpData2.


VIDEOHDR

Contains header information that identifies a video data buffer.

typedef struct {
    LPSTR lpData;            // address of video buffer
    DWORD dwBufferLength;    // size, in bytes, of the data buffer
    DWORD dwBytesUsed;       // see below
    DWORD dwTimeCaptured;    // see below
    DWORD dwUser;            // user-specific data
    DWORD dwFlags;           // see below
    DWORD dwReserved[4];     // reserved; do not use
} VIDEOHDR;

Members

dwBytesUsed
Number of bytes used in the data buffer.
dwTimeCaptured
Time, in milliseconds, when the frame was captured relative to the first frame in the stream.

Synchronization of audio and video in the resulting AVI file depends solely on this parameter, which should be derived directly from a counter (VSYNC_Count) incremented by a vertical sync interrupt. When using NTSC frame rates and frame-based interrupts, the returned value would be:

dwTimeCaptured = VSYNC_Count * 1/29.97.

The capture driver must maintain VSYNC_Count accurately by allowing recursive entry into the interrupt service routine (if only for the purpose of incrementing VSYNC_Count) and by not disabling interrupts for long periods of time.

dwFlags
Flags giving information about the data buffer. The following flags are defined for this field:
VHDR_DONE | Set by the device driver to indicate it is finished with the data buffer and it is returning the buffer to the application.
VHDR_PREPARED | Set by the system to indicate the data buffer has been prepared with videoStreamPrepareHeader.
VHDR_INQUEUE | Set by the system to indicate the data buffer is queued for playback.
VHDR_KEYFRAME | Set by the device driver to indicate a key frame.


Audio Compression Manager Drivers

The multimedia services of the Microsoft® Win32® application programming interface (API) provide extensible, device-independent audio support. The Audio Compression Manager (ACM) allows an application to convert data between different formats. The ACM is used by the WaveMapper, which automatically converts any wave file (even compressed files) into a format (usually PCM) which can be played by a sound card. In this way, an application can simply "play" a file without having to take its format or whether it is compressed into account. This makes compressed audio completely transparent to the user. Other applications can call the ACM to explicitly perform conversions.

By itself, the ACM is not capable of performing any conversions. Instead, it relies on installable drivers to perform specific conversions. These drivers are called codecs, converters, or filters. (Sometimes the term "codec" is used in a more generic sense, to refer to all three types of ACM drivers.) A codec converts from one format to another; for example, from PCM to MS-ADPCM. A converter converts between different types of the same format; for example; between 44 kHz PCM and 11 kHz PCM. A filter modifies the audio data without changing the format; for example, an echo filter might make a 44 kHz PCM wave file sound different, but it would still be a 44 kHz PCM file.

There are several ACM drivers which are automatically installed with the system. There are drivers which provide support for the compressed formats MS-ADPCM, IMA ADPCM, the GSM 6.10 standard, and the TrueSpeech voice coding format. There is also a PCM converter which converts between 8- and 16-bit PCM, between mono and stereo, and between different sampling frequencies. Other drivers can be installed at any time. The ACM provides API elements which allow an application to install a driver for its process only, preventing other processes from using it.


About ACM Drivers

An ACM driver typically performs a specific task for the ACM. For example, the MS-ADPCM codec can encode PCM data to MS-ADPCM and decode the resulting MS-ADPCM data. Each driver is small, simple, and easy to write; this makes it relatively simple to extend the audio capabilities of the system at any time. Sample ACM drivers are provided with this DDK.

An ACM driver conforms to the Installable Driver Interface. As such it must export a DriverProc function which supports a number of messages:

  • DRV_CLOSE
  • DRV_CONFIGURE
  • DRV_FREE
  • DRV_INSTALL
  • DRV_LOAD
  • DRV_OPEN
  • DRV_QUERYCONFIGURE
  • DRV_REMOVE

The DriverProc function must also support various ACM-specific messages which the ACM sends to the driver to request information about its capabilities or to perform a conversion. These messages are documented in detail in the reference section. Most of the code for responding to these messages is provided in the sample drivers; often, it is only necessary to substitute a few parameters. Generally, only the actual conversion routine (which is called in response to the ACMDM_STREAM_CONVERT message) must be completely rewritten for each driver.

An ACM driver must register itself with the ACM. It does this by putting an entry under the [Drivers32] section of the SYSTEM.INI file. The entry must have the following form:

msacm.alias=filename

In this example, alias must be a unique name. The ACM will only load one codec for each alias. Although not required, it is suggested that ACM codecs use the .ACM filename extension instead of the more typical .DLL extension.

For example, the Microsoft MS-ADPCM codec has the following entry:

msacm.msadpcm=msadp32.acm


Optional Features of ACM Drivers

An ACM driver must convert data and respond to certain messages. There are also several optional features which an ACM driver may support.

  • Custom icon. An ACM driver can provide the ACM with a custom icon. This icon must be compiled into the driver as part of the resource script. In response to the ACMDM_DRIVER_DETAILS message, the driver obtains a handle to the icon by calling the LoadIcon function, and returns the handle to the ACM in the hIcon member of the ACMDRIVERDETAILS structure. The ACM will then use the icon to represent the driver, in situations such as the default About dialog box (see below). If no icon is provided, the ACM will use the default driver icon, and the driver must return NULL in the hIcon member.
  • Custom About dialog box. An ACM driver can display a custom About dialog box in response to the ACMDM_DRIVER_ABOUT message. If queried for support, the driver returns MMSYSERR_NOERROR if it supports a custom About dialog box, and MMSYSERR_NOTSUPPORTED if it does not. If the driver responds positively to the query, it must display a driver-provided About dialog box when the ACMDM_DRIVER_ABOUT is passed with a valid window handle. Most ACM drivers should use the default About dialog box rather than providing their own; using the default About dialog box makes the driver code smaller and easier to write. The ACM uses the custom icon (if any) and the strings from the ACMDRIVERDETAILS structure to create an About dialog box which should be satisfactory for most drivers.
  • Configuration dialog box. An ACM driver may require configuration data; for example, the IMA ADPCM codec can perform real-time encoding and decoding on very powerful machines, but cannot on less powerful machines. In this case, the driver should allow the user to configure the codec. The driver should return a nonzero response to the DRV_QUERYCONFIGURE message to indicate that a configuration dialog is supported. When the driver receives the DRV_CONFIGURE message, it should display the configuration dialog box. For software codecs, the configuration information should be stored in the HKEY_CURRENT_USER section of the registry to allow each user to configure the driver as desired.


Writing ACM Drivers

The best way to write an ACM driver is to select one of the sample drivers provided with the DDK and modify the code as required to implement new conversions and features. The comments in the sample code provide a detailed explanation of the different responses to each message and indicate which parts need to be modified for a new driver.


Sample ACM Drivers

Three sample ACM drivers are provided with the DDK.

  • The imaadpcm sample provides a speed-optimized codec which converts between PCM and the IMA ADPCM format. This codec shows how to use several conversion routines to reduce computational requirements. It also supports a configuration dialog box, and it automatically configures itself the first time it is loaded.
  • The msfilter sample provides a simple volume and echo filter. (Both filters are supported within the same driver.) This driver supports a custom icon and a custom About dialog box. As noted earlier, the ACM provides a default icon and About dialog box for drivers which do not provide their own; using the default About dialog box is recommended, since the driver code is simpler and smaller.
  • The gsm610 sample implements the GSM 6.10 voice encoding standard, originally developed for digital cellular-telephone encoding. It supports a configuration dialog box and automatic-configuration code.


Tips for Writing ACM Drivers

This section provides some guidelines for writing ACM drivers.

  • Allocate driver-instance data in response to the DRV_OPEN message. You will usually need some data throughout the life of the driver; for example, you need the module-instance handle in order to load resource strings. Define a structure containing this data, and allocate it in response to DRV_OPEN. Do not save this structure as a global variable. Instead, return a pointer to the structure as the return value for the DRV_OPEN message. This pointer will be passed back to the driver in every subsequent message, as the first parameter of the DriverProc function. Remember to free this driver-instance data in response to the DRV_CLOSE message.
  • Allocate stream-instance data in response to the ACMDM_STREAM_OPEN message. You will usually need some instance data for each open stream. Since there could be several streams open at the same time, you shouldn't store this data as a global variable. Instead, define a structure containing the required data, and allocate it in response to ACMDM_STREAM_OPEN. In that message, the driver is passed a pointer to an ACMDRVSTREAMINSTANCE structure. Store a pointer to the stream-instance data in the dwDriver member, and it will be available on every call involving that stream. Remember to free the stream-instance data in response to the ACMDM_STREAM_CLOSE message.
  • Avoid using global variables. Defining a single DWORD of global data will use up 4K of memory in every process which uses the ACM, because your driver is loaded into each process. There is no need to use global data; instead, use the instance data, as described earlier.
  • Make sure that your driver processes the ACMDM_STREAM_CONVERT message as quickly as possible. Perform as much processing as possible in the ACMDM_STREAM_OPEN message.
  • Don't link to CRTDLL.DLL. This DLL cannot be loaded into all contexts, and therefore your codec will not function correctly. In particular, your codec may not work correctly for system sounds produced using the MessageBeep function. Use Win32 functions or link to a static C runtime library such as LIBC.LIB or LIBCMT.LIB.
  • Handle Win32 error conditions correctly. You cannot always depend on the success of calls to the USER module (such as LoadString and LoadIcon). In particular, when your codec is used to play system sounds, it may be loaded into a context in which these calls are unable to succeed. Although there will be no opportunity for your codec to display icons or strings in this context, your code must be prepared handle this situation.
  • Store configuration data on a per-user basis. Each user should be able to configure an ACM driver according to personal preferences. Therefore, configuration information should be stored in the HKEY_CURRENT_USER section of the registry.
  • Provide a valid default configuration. Configuration data will normally be stored on a per-user basis; however, in some contexts (such as when playing system sounds) there will be no defined current user. In these situations, calls to the registry will fail. You must provide a reasonable default configuration to handle this failure.


Writing Portable ACM Drivers

Most of the features of the ACM in Windows 95 are also provided in Windows NT 3.5. If written correctly, 32-bit ACM drivers written for Windows 95 will run unmodified on Windows NT 3.5; it should not even be necessary to recompile them. A developer can simply ship the Windows 95 driver as the x86 Windows NT 3.5 driver. All the sample ACM drivers provided in the DDK offer binary compatibility with Windows NT 3.5, and the ACM drivers shipping with Windows 95 offer binary compatibility with Windows NT 3.5.

To help maintain compatibility between Windows platforms, use the private LoadStringCodec function instead of the LoadString function. LoadStringCodec is a private function included in the sample ACM drivers. Using this function (together with the SIZEOFACMSTR macro) will solve most of your Unicode problems.

Features available in the ACM in Windows 95 that are not available in Windows NT 3.5 include support for asynchronous conversions and support for Plug-and-Play. Both of these features are useful only for drivers that rely on hardware support.


Hardware-Supported Drivers

ACM drivers are made up of three parts: hardware, a VxD, and a DLL. The VxD provides access to the driver's hardware and communicates with the driver DLL. The driver DLL processes messages from the ACM and communicates with the VxD for all hardware access. Most of the software logic of the driver should be contained in the VxD, which runs in the processor's ring 0. The DLL primarily provides the ring 3 interface between the ACM (which is also composed of ring 3 DLLs) and the driver VxD.

Drivers that utilize hardware should be designed as Plug and Play drivers. Furthermore, if appropriate hardware capabilities exist, the driver should be an asynchronous driver.


Synchronous and Asynchronous Drivers

When the ACM provides a buffer of audio data to a synchronous driver for conversion, the driver converts the buffer and then returns to the ACM. This is the most common type of driver. This driver typically converts audio data using software algorithms executing on the host processor.

On the other hand, an asynchronous driver queues the buffer and immediately returns to the application. The driver processes the queue of buffers and notifies the ACM as it finishes each buffer. This driver typically utilizes special hardware (for example, a DSP) to convert (compress or decompress) audio data.

An asynchronous driver notifies the ACM and applications of the progress of a conversion stream using callback messages. There are three callback messages related to ACM conversion streams: MM_ACM_OPEN, MM_ACM_DONE, and MM_ACM_CLOSE. For information about these messages, see the acmStreamConvertCallback function in the Win32 Multimedia Programmer's Reference.


Plug and Play Drivers

Some ACM drivers may utilize hardware to perform operations on audio data (for example, conversions, compression and decompression, and filtering). The manufacturer of the hardware and ACM driver should develop a Plug and Play driver.

To develop a Plug and Play ACM driver you must first become familiar with device nodes (DevNodes), the Configuration Manager, and the general architecture for multimedia Plug and Play drivers. You must develop a VxD that interacts with the system Configuration Manager, provides access to the hardware, and communicates with the ACM driver DLL. You must write the driver DLL so that it communicates with the VxD for all hardware access. For more information about Windows multimedia Plug and Play drivers, see .

The only detail specific to ACM drivers is the mechanism by which the driver DLL determines the DevNode for which it is being opened. When the ACM opens the driver DLL (even a non - Plug-and-Play DLL), it passes to the driver a pointer to an ACMDRVOPENDESC structure. The driver receives this pointer as the lParam2 parameter of the DRV_OPEN message to its DriverProc function. For Plug and Play drivers, the dnDevNode member of this structure contains an identifier that identifies a DevNode. A DevNode represents a particular instance of hardware in the system. The driver DLL uses this DevNode identifier when it communicates with the VxD. The VxD requires this information when it communicates with Configuration Manager.


ACM Support for Wave Drivers

Some waveform-audio devices may support wave formats other than PCM formats. For example, the hardare may allow direct playback or recording of a compressed format, such as IMAADPCM or alaw. In this case, the ACM does not have to send the data to an ACM driver once for conversion and then again to the wave driver for playback. Instead the compressed data is sent directly to the wave driver.

If a wave device supports compressed formats, the manufacturer may choose to provide a corresponding ACM driver that supports partial ACM functionality for enumerating formats. This ACM driver would not provide support for compression or decompression, but would instead allow the ACM to recognize that the compressed formats are supported by the wave device. This would allow users of the ACM to recognize that the compressed formats are supported directly by the wave device. The ACM driver messages that should be supported by such a driver are as follows:

  • ACMDM_DRIVER_DETAILS
  • ACMDM_FORMAT_DETAILS
  • ACMDM_FORMATTAG_DETAILS
  • ACMDM_HARDWARE_WAVE_CAPS_INPUT
  • ACMDM_HARDWARE_WAVE_CAPS_OUTPUT
  • DRV_CLOSE
  • DRV_FREE
  • DRV_LOAD
  • DRV_OPEN

The ACM driver can use the ACMDRIVERDETAILS_SUPPORTF_HARDWARE support flag to specify that the format is available for playback, recording, or both. This means that no stream-based operations can be performed. (The ACMDRIVERDETAILS_SUPPORTF_HARDWARE flag is specified in the fdwSupport member of the ACMDRIVERDETAILS structure.)

Some waveform-audio devices may also allow compression or decompression of audio data without requiring that the data be played back or recorded. In other words, it is possible to send data to the device to be compressed but not played. The compressed data can then be read back from the device. This is very similar to a hardware-supported ACM driver. The difference is that the hardware is shared between the wave driver and the ACM driver.

In this case, the wave device manufacturer should provide a VxD (just as for a wave driver or a hardware-supported ACM driver). The manufacturer also provides both a wave driver and an ACM driver (both DLLs). Both the wave driver and the ACM driver communicate with the VxD to allocate the hardware and perform any hardware access. The VxD is responsible for arbitrating hardware access between the wave driver and the ACM driver.


Reference

This section contains an alphabetic list of the messages and structures that relate to drivers, filters, formats, and conversion streams.


Messages

The following topics describe the messages that are provided.


ACMDM_DRIVER_ABOUT

ACMDM_DRIVER_ABOUT
lParam1 = (LPARAM) hwndAbout  // see below
lParam2 = reserved            // should be ignored

Sent to an Audio Compression Manager (ACM) driver to allow the driver to display a custom About dialog box. This message is usually sent by the Control Panel Sound Mapper option to an ACM driver.

  • Return MMSYSERR_NOERROR if the operation is successful or an error value otherwise. The following errors are possible:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The driver does not support a custom about box.

lParam1
Handle to the window owner for the custom About dialog box. This parameter will be equal to -1L if the caller is only interested in whether a custom About dialog box is supported by the driver; no dialog box should be displayed. All other values should be used as the owner window handle for the dialog box (a NULL handle is valid).

An ACM driver can optionally support a custom About dialog box. To do so, return MMSYSERR_NOTSUPPORTED and allow a default dialog box to be displayed by the Control Panel Sound Mapper option.

If the driver supports a custom About dialog box, MMSYSERR_NOERROR should be returned. If lParam1 is equal to -1L, no dialog should be displayed because the driver is only being queried for support.

Note that the ACM will validate all parameters to this message before calling the driver. It is not necessary for the driver to validate the lParam1 and lParam2 parameters.

See Also

ACMDM_DRIVER_DETAILS, ACMDM_DRIVER_NOTIFY, ACMDM_HARDWARE_WAVE_CAPS_INPUT, ACMDM_HARDWARE_WAVE_CAPS_OUTPUT


ACMDM_DRIVER_DETAILS

ACMDM_DRIVER_DETAILS
lParam1 = (LPARAM) pacmdd  // see below
lParam2 = reserved         // should be ignored

Sent to an Audio Compression Manager (ACM) driver to request details about the driver. This message is typically sent to an ACM driver in response to an acmDriverDetails call.

  • Return MMSYSERR_NOERROR if the operation is successful or an error value otherwise. The following errors are possible:
MMSYSERR_NOTENABLED The driver failed to load or initialize.

lParam1
Address of the ACMDRIVERDETAILS structure that should be filled in with various details describing the driver. The cbStruct member of the ACMDRIVERDETAILS structure will contain the desired size, in bytes, of the details that the driver should return.

An ACM driver must support this message. Note that this message should never fail unless the driver could not initialize. There are two possible error conditions:

  1. If lParam1 is not a valid pointer to a ACMDRIVERDETAILS structure.
  2. If the cbStruct member of the ACMDRIVERDETAILS structure is less than four; in this case, there is not enough room to return the number of bytes filled in.

Because these two error conditions are easily defined, the ACM will catch these errors and will not send the ACMDM_DRIVER_DETAILS message. The driver does not need to check for these conditions.

See Also

ACMDM_DRIVER_ABOUT, ACMDM_DRIVER_NOTIFY, ACMDM_HARDWARE_WAVE_CAPS_INPUT, ACMDM_HARDWARE_WAVE_CAPS_OUTPUT


ACMDM_DRIVER_NOTIFY

ACMDM_DRIVER_NOTIFY
lParam1 = reserved         // should be ignored
lParam2 = reserved         // should be ignored

Sent to an Audio Compression Manager (ACM) driver to notify the driver of changes that have taken place to one or more global drivers.

  • Returns MMSYSERR_NOERROR if successful.

An ACM driver can use the ACMDM_DRIVER_NOTIFY message to determine when changes are made to one or more global ACM drivers. This includes driver additions, removals, priorities, and enable or disable operations. If a driver has cached any information about other ACM drivers, it must refresh this cache completely each time the ACMDM_DRIVER_NOTIFY message is received.

See Also

ACMDM_DRIVER_ABOUT, ACMDM_DRIVER_DETAILS, ACMDM_HARDWARE_WAVE_CAPS_INPUT, ACMDM_HARDWARE_WAVE_CAPS_OUTPUT


ACMDM_FILTER_DETAILS

ACMDM_FILTER_DETAILS
lParam1 = (LPARAM) pacmFD          // see below
lParam2 = (LPARAM) fFilterDetails  // see below

Sent to an Audio Compression Manager (ACM) driver to request details about a filter for a specific filter tag. This message is usually sent to an ACM driver in response to an acmFilterDetails or acmFilterEnum call.

  • Returns MMSYSERR_NOERROR if successful or an error value otherwise. The following errors are possible:
ACMERR_NOTPOSSIBLE | The ACMFILTERDETAILS structure and query operation specify information that is not understood by the driver.
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The driver does not support filter operations or the specified query operation.

lParam1
Address of the ACMFILTERDETAILS structure that should be filled in with the filter details for the specified filter tag. The cbStruct member of the ACMFILTERDETAILS structure will contain the desired size, in bytes, of the details that the driver should return for the filter.
lParam2
Flags for getting the filter details for the specified filter tag. This parameter is identical to the fdwDetails parameter passed to acmFilterDetails.
ACM_FILTERDETAILSF_FILTER | Indicates that a WAVEFILTER structure pointed to by pwfltr of the ACMFILTERDETAILS structure was given and the remaining details should be returned. The dwFilterTag member of the ACMFILTERDETAILS will be initialized to the same filter tag as the pwfltr member specifies. This query type can be used to get a string description of an arbitrary filter structure.
ACM_FILTERDETAILSF_INDEX | Indicates that a filter index for the filter tag was given in the dwFilterIndex member of the ACMFILTERDETAILS structure. The filter details must be returned in the structure specified by lParam1. The index ranges from zero to one less than the cStandardFilters member returned in the ACMFILTERTAGDETAILS structure for a filter tag.

An ACM driver that supports filter operations must support this message. If a driver does not support filters, this message should not be handled (MMSYSERR_NOTSUPPORTED must be returned). Note that the following parameters for the ACMDM_FILTER_DETAILS message will be validated before calling the driver:

  • The lParam1 parameter will contain a valid pointer to an ACMFILTERDETAILS structure with the proper members initialized for the requested query operation. This structure will be at least the size of the base ACMFILTERDETAILS structure.
  • The cbStruct member of the ACMFILTERDETAILS structure will be set to at least the size in bytes of the base ACMFILTERDETAILS structure.
  • WAVEFILTER structure that is at least the size, in bytes, specified in the cbwfltr member of the ACMFILTERDETAILS structure.
  • No invalid flag combinations will be specified in lParam2.

The driver does not need to check for these conditions.

To enable the driver to successfully query for the filter of the specified filter tag, the cbStruct member of the ACMFILTERDETAILS structure should be set to the actual size, in bytes, of the details being returned. This size cannot exceed the requested size. Note that the smallest possible size is the size of the base ACMFILTERDETAILS structure.

See Also

ACMDM_FILTERTAG_DETAILS


ACMDM_FILTERTAG_DETAILS

lParam1 = (LPARAM) pacmFTD            // see below
lParam2 = (LPARAM) fFilterTagDetails  // see below

Sent to an Audio Compression Manager (ACM) driver to request details about a filter tag. This message is usually sent to an ACM driver in response to an acmFilterTagDetails or acmFilterTagEnum call.

  • Return MMSYSERR_NOERROR if the operation is successful or an error value otherwise. The following errors are possible:
ACMERR_NOTPOSSIBLE | The ACMFILTERTAGDETAILS structure and query operation specify information that is not understood by the driver.
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The driver does not support filter operations or the specified query operation.

lParam1
Address of the ACMFILTERTAGDETAILS structure that should be filled in with the filter tag details. The cbStruct member of the ACMFILTERTAGDETAILS structure will contain the desired size, in bytes, of the details that the driver should return for the filter tag.
lParam2
Flags for getting the filter tag details. This parameter is identical to the fdwDetails parameter passed to acmFilterTagDetails.
ACM_FILTERTAGDETAILSF_FILTERTAG | Indicates that a filter tag was given in the dwFilterTag member of the ACMFILTERTAGDETAILS structure. The filter tag details must be returned in the structure specified by lParam1.
ACM_FILTERTAGDETAILSF_INDEX | Indicates that a filter tag index was given in the dwFilterTagIndex member of the ACMFILTERTAGDETAILS structure. The filter tag and details must be returned in the structure specified by lParam1. The index ranges from zero to one less than the cFilterTags member returned in the ACMDRIVERDETAILS structure for this driver.
ACM_FILTERTAGDETAILSF_LARGESTSIZE | Indicates that the details on the filter tag with the largest filter size, in bytes, must be returned. The dwFilterTag member will either be WAVE_FILTER_UNKNOWN or the filter tag to find the largest size for.

An ACM driver must support this message if it supports filter operations. Note that the following parameters for the ACMDM_FILTERTAG_DETAILS message will be validated before calling the driver:

  • The lParam1 parameter will contain a valid pointer to an ACMFILTERTAGDETAILS structure with the proper members initialized for the requested query operation. This structure will be at least the size of the base ACMFILTERTAGDETAILS structure.
  • The cbStruct member of the ACMFILTERTAGDETAILS structure will be set to at least the size, in bytes, of the base ACMFILTERTAGDETAILS structure.
  • No invalid flag combinations will be specified in lParam2.

The driver does not need to check for these conditions.

To enable the driver to successfully query for the filter tag, the cbStruct member of the ACMFILTERTAGDETAILS structure should be set to the actual size, in bytes, of the details being returned. This size cannot exceed the requested size. Note that the smallest possible size is the size of the base ACMFILTERTAGDETAILS structure.


ACMDM_FORMAT_DETAILS

lParam1 = (LPARAM) pacmFD          // see below
lParam2 = (LPARAM) fFormatDetails  // see below

Sent to an Audio Compression Manager (ACM) driver to request details about a format for a specific format tag. This message is usually sent to an ACM driver in response to an acmFormatDetails or acmFormatEnum call.

  • Return MMSYSERR_NOERROR if the operation is successful or an error value otherwise. The following errors are possible:
ACMERR_NOTPOSSIBLE | The ACMFORMATDETAILS structure and query operation specify information that is not understood by the driver.
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The driver does not support the specified query operation.

lParam1
Address of the ACMFORMATDETAILS structure that should be filled in with the format details for the specified format tag. The cbStruct member of the ACMFORMATDETAILS structure will contain the desired size, in bytes, of the details that the driver should return for the format.
lParam2
Flags for getting the format details for the specified format tag. This parameter is identical to the fdwDetails parameter passed to acmFormatDetails.
ACM_FORMATDETAILSF_FORMAT | Indicates that a WAVEFORMATEX structure pointed to by the pwfx member of the ACMFORMATDETAILS structure was given and the remaining details should be returned. The dwFormatTag member of the ACMFORMATDETAILS will be initialized to the same format tag as the pwfx member specifies. This query type can be used to get a string description of an arbitrary format structure.
ACM_FORMATDETAILSF_INDEX | Indicates that a format index for the format tag was given in the dwFormatIndex member of the ACMFORMATDETAILS structure. The format details must be returned in the structure specified by lParam1. The index ranges from zero to one less than the cStandardFormats member returned in the ACMFORMATTAGDETAILS structure for a format tag.

An ACM driver must support this message. Note that the following parameters for the ACMDM_FORMAT_DETAILS message will be validated before calling the driver:

  • The lParam1 parameter will contain a valid pointer to an ACMFORMATDETAILS structure with the proper members initialized for the requested query operation. This structure will be at least the size of the base ACMFORMATDETAILS structure.
  • The cbStruct member of the ACMFORMATDETAILS structure will be set to at least the size in bytes of the base ACMFORMATDETAILS structure.
  • The pwfx member of the ACMFORMATDETAILS structure will be a valid pointer to a WAVEFORMATEX structure that is at least the size, in bytes, specified in the cbwfx member of the ACMFORMATDETAILS structure.
  • No invalid flag combinations will be specified in lParam2.

The driver does not need to check for these conditions.

To enable the driver to successfully query for the format of the specified format tag, the cbStruct member of the ACMFORMATDETAILS structure should be set to the actual size, in bytes, of the details being returned. This size cannot exceed the requested size. Note that the smallest possible size is the size of the base ACMFORMATDETAILS structure.

If an ACM driver returns a zero-length string for a format name, the ACM will create a format string for the format. The format string will specify the kHz, bit-depth, and channel setting (mono or stereo). This is strongly recommended if the driver will be used internationally, because it allows the ACM to automatically accommodate international differences. However, if you want to specify these values yourself, use the nSamplesPerSec, wBitsPerSample, and nChannels members of a WAVEFORMATEX structure to specify the kHz, bit-depth, and channel setting, respectively. If the wBitsPerSample member is zero and the driver returns a zero length string, the ACM will not include the bit depth in the string description.

See Also

ACMDM_FORMAT_SUGGEST, ACMDM_FORMATTAG_DETAILS, ACMDRVFORMATSUGGEST


ACMDM_FORMAT_SUGGEST

lParam1 = (LPARAM) pacmDFS  // see below
lParam2 = reserved          // should be ignored

Sent to an Audio Compression Manager (ACM) driver to suggest a destination format for a given source format for a conversion. This message is usually sent to an ACM driver in response to an acmFormatSuggest call.

  • Return MMSYSERR_NOERROR if the operation is successful or an error value otherwise. The following errors are possible:
ACMERR_NOTPOSSIBLE | The ACMDRVFORMATSUGGEST structure and suggestion restrictions specify information that cannot be satisfied by the driver.
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The driver does not support format suggestion operations.

lParam1
Address of the ACMDRVFORMATSUGGEST structure that defines how a destination format should be suggested, given a particular source format.

An ACM driver must support this message if it supports the ACMDM_STREAM_OPEN message and conversions other than filtering operations are available. Note that the following parameters for the ACMDM_FORMAT_SUGGEST message will be validated before calling the driver:

  • The lParam1 parameter will contain a valid pointer to an ACMDRVFORMATSUGGEST structure with all members initialized. This structure will be at least the size of the base ACMDRVFORMATSUGGEST structure.
  • The cbStruct member of the ACMDRVFORMATSUGGEST structure will be set to at least the size, in bytes, of the base ACMDRVFORMATSUGGEST structure.
  • The pwfxSrc member of the ACMDRVFORMATSUGGEST structure will be a valid pointer to a WAVEFORMATEX structure that is at least the size, in bytes, specified in the cbwfxSrc member of the ACMDRVFORMATSUGGEST structure.
  • The pwfxDst member of the ACMDRVFORMATSUGGEST structure will be a valid pointer to a WAVEFORMATEX structure that is at least the size, in bytes, specified in the cbwfxDst member of the ACMDRVFORMATSUGGEST structure.
  • No invalid flag combinations will be specified in lParam2.

The driver need not check for these conditions.

See Also

ACMDM_FORMAT_DETAILS, ACMDM_FORMATTAG_DETAILS, ACMDRVFORMATSUGGEST


ACMDM_FORMATTAG_DETAILS

lParam1 = (LPARAM) pacmFTD            // see below
lParam2 = (LPARAM) fFormatTagDetails  // see below

Sent to an Audio Compression Manager (ACM) driver to request details about a format tag. This message is usually sent to an ACM driver in response to an acmFormatTagDetails or acmFormatTagEnum call.

  • Return MMSYSERR_NOERROR if the operation is successful or an error value otherwise. The following errors are possible:
ACMERR_NOTPOSSIBLE | The ACMFORMATTAGDETAILS structure and query operation specify information that is not understood by the driver.
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The driver does not support the specified query operation.

lParam1
Address of the ACMFORMATTAGDETAILS structure that should be filled in with the format tag details. The cbStruct member of the ACMFORMATTAGDETAILS structure will contain the desired size, in bytes, of the details that the driver should return for the format tag.
lParam2
Flags for getting the format tag details. This parameter is identical to the fdwDetails parameter passed to acmFormatTagDetails.
ACM_FORMATTAGDETAILSF_INDEX | Indicates that a format tag index was given in the dwFormatTagIndex member of the ACMFORMATTAGDETAILS structure. The format tag and details must be returned in the structure specified by lParam1. The index ranges from zero to one less than the cFormatTags member returned in the ACMDRIVERDETAILS structure for this driver.
ACM_FORMATTAGDETAILSF_FORMATTAG | Indicates that a format tag was given in the dwFormatTag member of the ACMFORMATTAGDETAILS structure. The format tag details must be returned in the structure specified by lParam1.
ACM_FORMATTAGDETAILSF_LARGESTSIZE | Indicates that the details on the format tag with the largest format size, in bytes, must be returned. The dwFormatTag member will either be WAVE_FORMAT_UNKNOWN or the format tag to find the largest size for.

An ACM driver must support this message. Note that the following parameters for the ACMDM_FORMATTAG_DETAILS message will be validated before calling the driver:

  • The lParam1 parameter will contain a valid pointer to an ACMFORMATTAGDETAILS structure with the proper members initialized for the requested query operation. This structure will be at least the size of the base ACMFORMATTAGDETAILS structure.
  • Size, in bytes, of the base ACMFORMATTAGDETAILS structure.
  • No invalid flag combinations will be specified in lParam2.

The driver does not need to check for these conditions.

To enable the driver to successfully query for the format tag, the cbStruct member of the ACMFORMATTAGDETAILS structure should be set to the actual size, in bytes, of the details being returned. This size cannot exceed the requested size. Note that the smallest possible size is the size of the base ACMFORMATTAGDETAILS structure.

Note

An ACM driver should not return a name in the szFormatTag member of the ACMFORMATTAGDETAILS structure for WAVE_FORMAT_PCM formats; the ACM will provide the proper localized name for the driver.

See Also

ACMDM_FORMAT_DETAILS, ACMDM_FORMAT_SUGGEST, ACMDRVFORMATSUGGEST


ACMDM_HARDWARE_WAVE_CAPS_INPUT

lParam1 = (LPARAM) pWIC   // see below
lParam2 = (LPARAM) cbWIC  // see below

Sent to an Audio Compression Manager (ACM) driver that sets the ACMDRIVERDETAILS_SUPPORTF_HARDWARE in the fdwSupport member of the ACMDRIVERDETAILS structure. This message is sent each time the driver is loaded by the ACM.

  • Return MMSYSERR_NOERROR if the operation is successful or an error value otherwise. The following errors are possible:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The driver does not support waveform input.

lParam1
Address of a WAVEINCAPS structure to be filled with the waveform input device capabilities that the driver is associated with.
lParam2
Size, in bytes, of the WAVEINCAPS structure referenced by lParam1.

An ACM driver that sets the ACMDRIVERDETAILS_SUPPORTF_HARDWARE flag in the ACMDRIVERDETAILS structure must support one or both of the ACMDM_HARDWARE_WAVE_CAPS_INPUT and ACMDM_HARDWARE_WAVE_CAPS_OUTPUT messages. These messages are used by the ACM to determine what waveform device identifiers are associated with the driver. This device identifier is then returned to an application through the acmMetrics function when the ACM_METRIC_HARDWARE_WAVE_INPUT or ACM_METRIC_HARDWARE_WAVE_OUTPUT metric index is given.

See Also

ACMDM_DRIVER_ABOUT, ACMDM_DRIVER_DETAILS, ACMDM_DRIVER_NOTIFY, ACMDM_HARDWARE_WAVE_CAPS_OUTPUT, WAVEINCAPS


ACMDM_HARDWARE_WAVE_CAPS_OUTPUT

lParam1 = (LPARAM) pWOC   // see below
lParam2 = (LPARAM) cbWOC  // see below

Sent to an Audio Compression Manager (ACM) driver that sets the ACMDRIVERDETAILS_SUPPORTF_HARDWARE in the fdwSupport member of the ACMDRIVERDETAILS structure. This message is sent each time the driver is loaded by the ACM.

  • Return MMSYSERR_NOERROR if the operation is successful or an error value otherwise. The following errors are possible:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The driver does not support waveform output.

lParam1
Address of a WAVEOUTCAPS structure to be filled with the waveform output device capabilities that the driver is associated with.
lParam2
Size, in bytes, of the WAVEOUTCAPS structure referenced by lParam1.

If an ACM driver sets the ACMDRIVERDETAILS_SUPPORTF_HARDWARE flag in the ACMDRIVERDETAILS structure, the driver must support one or both of the ACMDM_HARDWARE_WAVE_CAPS_INPUT and ACMDM_HARDWARE_WAVE_CAPS_OUTPUT messages. These messages are used by the ACM to determine what waveform device identifiers are associated with the driver. This device identifier is then returned to an application through the acmMetrics function when the ACM_METRIC_HARDWARE_WAVE_INPUT or ACM_METRIC_HARDWARE_WAVE_OUTPUT metric index is given.

See Also

ACMDM_DRIVER_ABOUT, ACMDM_DRIVER_DETAILS, ACMDM_DRIVER_NOTIFY, ACMDM_HARDWARE_WAVE_CAPS_INPUT, WAVEOUTCAPS


ACMDM_STREAM_CLOSE

lParam1 = (LPARAM) pacmDSI  // see below
lParam2 = reserved          // should be ignored

Sent to an Audio Compression Manager (ACM) driver to close a previously opened conversion stream. This message is usually sent to an ACM driver in response to an acmStreamClose call.

  • Return MMSYSERR_NOERROR if the operation is successful or ACMERR_BUSY if the conversion stream is in a state that does not allow the stream to be closed. For example, this error should be returned if a driver is performing asynchronous conversions for the stream and pending buffers are in the queue. This error should only be possible for asynchronous drivers.
lParam1
Address of the ACMDRVSTREAMINSTANCE structure for the conversion stream that is to be closed.

An ACM driver must support this message if it supports the ACMDM_STREAM_OPEN message. Before calling the driver, the lParam1 parameter of the ACMDM_STREAM_CLOSE message will be validated. This parameter will contain a valid pointer to an ACMDRVSTREAMINSTANCE structure with the same information as the corresponding ACMDM_STREAM_OPEN message. The driver does not need to check for this condition.

See Also

ACMDM_STREAM_CONVERT, ACMDM_STREAM_OPEN, ACMDM_STREAM_PREPARE, ACMDM_STREAM_RESET, ACMDM_STREAM_SIZE, ACMDM_STREAM_UNPREPARE, ACMDRVOPENDESC, ACMDRVSTREAMHEADER, ACMDRVSTREAMINSTANCE, ACMDRVSTREAMSIZE


ACMDM_STREAM_CONVERT

lParam1 = (LPARAM) pacmDSI  // see below
lParam2 = (LPARAM) pacmDSH  // see below

Sent to an Audio Compression Manager (ACM) driver to request a conversion on a previously opened conversion stream. This message is usually sent to an ACM driver in response to an acmStreamConvert call.

  • Return MMSYSERR_NOERROR if the operation is successful or an error value otherwise. The following errors are possible:
MMSYSERR_NOMEM | Unable to allocate resources to perform the conversion request.
MMSYSERR_NOTENABLED | The driver failed to load or initialize.

lParam1
Address of the ACMDRVSTREAMINSTANCE structure for the conversion stream that the convert request is for.
lParam2
Address of the ACMDRVSTREAMHEADER structure identifying the source and destination data blocks that should be used for the conversion.

An ACM driver must support the ACMDM_STREAM_CONVERT message if it supports the ACMDM_STREAM_OPEN message.

If the specified conversion stream was opened for asynchronous conversions, the driver should queue the ACMDRVSTREAMHEADER structure and immediately return successfully. If the stream header cannot be queued for asynchronous conversions (due to resource limitations, for example), the driver should return an error code.

If the ACMDRVSTREAMHEADER for an asynchronous conversion was successfully queued, but the driver later determines that the conversion is not possible, the driver must set the cbDstLengthUsed member of the ACMDRVSTREAMHEADER to zero and perform the DriverCallback.

Note that the following parameters for the ACMDM_STREAM_CONVERT message will be validated before calling the driver:

  • The lParam1 parameter will contain a valid pointer to an ACMDRVSTREAMINSTANCE structure with the same information as the corresponding ACMDM_STREAM_OPEN message.
  • The lParam2 parameter will contain a valid pointer to an ACMDRVSTREAMHEADER structure with the proper members initialized for the conversion request. This structure will be at least the size of the base ACMDRVSTREAMHEADER structure.
  • The cbStruct member of the ACMDRVSTREAMHEADER structure will be set to at least the size, in bytes, of the base ACMDRVSTREAMHEADER structure.
  • The remaining members of the ACMDRVSTREAMHEADER structure will be within the bounds described in the documentation for the ACMDRVSTREAMHEADER structure.
  • The ACMDRVSTREAMHEADER structure will be properly prepared. The ACMSTREAMHEADER_STATUSF_PREPARED flag in the fdwStatus member of the ACMDRVSTREAMHEADER structure will be set.
  • No invalid flag combinations will be specified in the fdwConvert member.

The driver does not need to check for these conditions.

The fdwConvert member of the ACMDRVSTREAMHEADER structure will contain flags defining how the conversion should be performed on this conversion request:

ACM_STREAMCONVERTF_BLOCKALIGN | Specifies that only integral numbers of blocks should be converted. Converted data must end on block aligned boundaries. An application uses this flag for all conversions on a stream until there is not enough source data to convert to a block-aligned destination; in which case, the last conversion will be specified without this flag.
ACM_STREAMCONVERTF_END | Specifies that the conversion stream should begin returning pending instance data. For example, if a conversion stream maintains instance data, such as the tail end of an echo filter operation, this flag should tell the driver to start returning this remaining data with optional source data. Note that this flag can be specified with the ACM_STREAMCONVERTF_START flag.
ACM_STREAMCONVERTF_START | Specifies that the conversion stream should reinitialize its instance data. For example, if a conversion stream maintains instance data, such as delta or predictor information, this flag should reset the stream to starting defaults. Note that this flag can be specified with the ACM_STREAMCONVERTF_END flag.

See Also

ACMDM_STREAM_CLOSE, ACMDM_STREAM_OPEN, ACMDM_STREAM_PREPARE, ACMDM_STREAM_RESET, ACMDM_STREAM_SIZE, ACMDM_STREAM_UNPREPARE, ACMDRVOPENDESC, ACMDRVSTREAMHEADER, ACMDRVSTREAMINSTANCE, ACMDRVSTREAMSIZE


ACMDM_STREAM_OPEN

lParam1 = (LPARAM) pacmDSI  // see below
lParam2 = reserved          // should be ignored

Sent to an Audio Compression Manager (ACM) driver to either open a conversion stream or query the stream for support. This message is usually sent to an ACM driver in response to an acmStreamOpen call.

  • Return MMSYSERR_NOERROR if the operation is successful or an error value otherwise. The following errors are possible:
ACMERR_NOTPOSSIBLE | The ACMDRVSTREAMINSTANCE structure defines a conversion stream request that cannot be satisfied by the driver.
MMSYSERR_NOMEM | Unable to allocate resources to create the conversion stream.
MMSYSERR_NOTENABLED | The driver failed to load or initialize.

lParam1
Address of the ACMDRVSTREAMINSTANCE structure that the caller is trying to create or query for support.

An ACM driver must support this message if it supports conversion operations. Note that the following parameters for the ACMDM_STREAM_OPEN message will be validated before calling the driver:

  • The lParam1 parameter will contain a valid pointer to an ACMDRVSTREAMINSTANCE structure with all members validated. All members of this structure will be within the bounds defined in the documentation for the ACMDRVSTREAMINSTANCE structure.
  • The cbStruct member of the ACMDRVSTREAMINSTANCE structure will be set to at least the size, in bytes, of the base ACMDRVSTREAMINSTANCE structure.
  • No invalid flag combinations will be specified in the fdwOpen member.
  • A driver will never be called to open a conversion stream for conversions for the same format tag unless the driver sets the ACMDRIVERDETAILS_SUPPORTF_CONVERTER flag in the fdwSupport member of the ACMDRIVERDETAILS structure returned by the driver during the ACMDM_DRIVER_DETAILS message.
  • A driver will never be called to open a conversion stream for conversions between two different format tags unless the driver sets the ACMDRIVERDETAILS_SUPPORTF_CODEC flag in the fdwSupport member of the ACMDRIVERDETAILS structure returned by the driver during the ACMDM_DRIVER_DETAILS message.
  • A driver will never be called to open a conversion stream with a filter unless the driver sets the ACMDRIVERDETAILS_SUPPORTF_FILTER flag in the fdwSupport member of the ACMDRIVERDETAILS structure returned by the driver during the ACMDM_DRIVER_DETAILS message.
  • A driver will never be called to open an asynchronous conversion stream unless the driver sets the ACMDRIVERDETAILS_SUPPORTF_ASYNC flag in the fdwSupport member of the ACMDRIVERDETAILS structure returned by the driver during the ACMDM_DRIVER_DETAILS message.

The driver does not need to check for these conditions.

If the ACM_STREAMOPENF_QUERY flag is specified in the fdwOpen member of the ACMDRVSTREAMINSTANCE structure, the driver should only return whether the conversion stream can be opened by the driver; but the conversion stream will not be opened. The driver should not allocate any instance data in conjunction with this flag.

If the ACM_STREAMOPENF_NONREALTIME flag is not specified in the fdwOpen member of the ACMDRVSTREAMINSTANCE structure, the driver should only succeed the message if the conversion can be done in real time. The definition of real time is highly dependent on your interpretation, though good judgment should be used here. If the driver's conversion is computationally expensive, the driver should not succeed a real-time conversion stream open request. An example of a real-time conversion client is the wave mapper, where data is converted as it is being played or recorded.

See Also

ACMDM_STREAM_CLOSE, ACMDM_STREAM_CONVERT, ACMDM_STREAM_PREPARE, ACMDM_STREAM_RESET, ACMDM_STREAM_SIZE, ACMDM_STREAM_UNPREPARE, ACMDRVOPENDESC, ACMDRVSTREAMHEADER, ACMDRVSTREAMINSTANCE, ACMDRVSTREAMSIZE


ACMDM_STREAM_PREPARE

lParam1 = (LPARAM) pacmDSI  // see below
lParam2 = (LPARAM) pacmDSH  // see below

Sent to an Audio Compression Manager (ACM) driver to allow the driver to optionally prepare an ACMDRVSTREAMHEADER structure and corresponding data blocks for a conversion. This message is usually sent to an ACM driver in response to an acmStreamPrepareHeader call.

  • Return MMSYSERR_NOERROR if the operation is successful or an error value otherwise. The following errors are possible:
MMSYSERR_NOMEM | Unable to allocate resources to prepare the stream header and conversion buffers.
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The driver does not support this message.

lParam1
Address of the ACMDRVSTREAMINSTANCE structure for the conversion stream that the prepare request is for.
lParam2
Address of the ACMDRVSTREAMHEADER structure identifying the source and destination data blocks that will be used in subsequent conversions.

An ACM driver can optionally support the ACMDM_STREAM_PREPARE message if special preparations for a stream header and buffers are required. If a driver supports the ACMDM_STREAM_PREPARE message, it must also support the ACMDM_STREAM_UNPREPARE message.

The default response for the ACMDM_STREAM_PREPARE message is to return MMSYSERR_NOTSUPPORTED. In this case, the ACM will mark the stream header as being prepared (sets the ACMSTREAMHEADER_STATUSF_PREPARED flag in the fdwStatus member of the ACMDRVSTREAMHEADER structure).

If a driver requires other operations to prepare the header and data blocks for a conversion, it should perform these operations and return MMSYSERR_NOERROR. The ACM will then mark the stream header as being prepared (a driver should never modify the ACMSTREAMHEADER_STATUSF_PREPARED flag in the fdwStatus member of the ACMDRVSTREAMHEADER structure). If the required operations cannot be performed, an error other than MMSYSERR_NOTSUPPORTED should be returned (for example, MMSYSERR_NOMEM if resource allocation is a problem).

The ACM will always send the ACMDM_STREAM_PREPARE and ACMDM_STREAM_UNPREPARE messages to a driver even if the driver returns MMSYSERR_NOTSUPPORTED. This allows a driver to optionally perform minor preparations for the header and data buffers while still taking advantage of the default behavior performed by the ACM.

Note that the following parameters for the ACMDM_STREAM_PREPARE message will be validated before calling the driver:

  • The lParam1 parameter will contain a valid pointer to an ACMDRVSTREAMINSTANCE structure with the same information as the corresponding ACMDM_STREAM_OPEN message.
  • The lParam2 parameter will contain a valid pointer to an ACMDRVSTREAMHEADER structure with the proper members initialized for the prepare request. This structure will be at least the size of the base ACMDRVSTREAMHEADER structure.
  • The cbStruct member of the ACMDRVSTREAMHEADER structure will be set to at least the size, in bytes, of the base ACMDRVSTREAMHEADER structure.
  • The remaining members of the ACMDRVSTREAMHEADER structure will be within the bounds described in the documentation for the ACMDRVSTREAMHEADER structure.

The driver does not need to check for these conditions.

See Also

ACMDM_STREAM_CLOSE, ACMDM_STREAM_CONVERT, ACMDM_STREAM_OPEN, ACMDM_STREAM_RESET, ACMDM_STREAM_SIZE, ACMDM_STREAM_UNPREPARE, ACMDRVOPENDESC, ACMDRVSTREAMHEADER, ACMDRVSTREAMINSTANCE, ACMDRVSTREAMSIZE


ACMDM_STREAM_RESET

lParam1 = (LPARAM) pacmDSI  // address of ACMDRVSTREAMINSTANCE
lParam2 = reserved          // ignore

Sent to an Audio Compression Manager (ACM) driver to reset a previously opened asynchronous conversion stream. This message is typically sent to an ACM driver in response to a call to the acmStreamReset function.

  • Return MMSYSERR_NOERROR if the operation is successful or an error value otherwise. The following errors are possible:
ACMERR_NOTPOSSIBLE The ACMDRVSTREAMSIZE structure and query type specified information that cannot be satisfied by the driver.

lParam1
Address of the ACMDRVSTREAMINSTANCE structure for the asynchronous conversion stream that is to be reset.
lParam2
Reserved. Should be ignored.

An asynchronous ACM driver must support this message. If the driver is converting data, it should stop immediately and mark all pending stream headers as done by clearing the ACMSTREAMHEADER_STATUSF_INQUEUE bit in the fdwStatus member of the ACMDRVSTREAMHEADER structure for each buffer. The driver should set the cbSrcLengthUsed and cbDstLengthUsed members of the structure appropriately. The driver should then notify the client by using DriverCallback to send an MM_ACM_DONE message for each buffer.

Note that the following parameters for the ACMDM_STREAM_RESET message will be validated before calling the driver:

  • The lParam1 parameter will contain a valid pointer to an ACMDRVSTREAMINSTANCE structure, with the same information as the corresponding ACMDM_STREAM_OPEN message.
  • A driver will never be called to reset an asynchronous conversion stream unless the driver sets the ACMDRIVERDETAILS_SUPPORTF_ASYNC flag in the fdwSupport member of the ACMDRIVERDETAILS structure that is returned by the driver during the ACMDM_DRIVER_DETAILS message.
  • A driver will never be called to reset a conversion stream that was not opened for asynchronous conversions.

The driver does not need to check for these conditions.


ACMDM_STREAM_SIZE

lParam1 = (LPARAM) pacmDSI  // see below
lParam2 = (LPARAM) pacmDSS  // see below

Sent to an Audio Compression Manager (ACM) driver to query recommended buffer conversion sizes for a conversion stream. This message is usually sent to an ACM driver in response to an acmStreamSize call.

  • Return MMSYSERR_NOERROR if the operation is successful or an error value otherwise. The following errors are possible:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
ACMERR_NOTPOSSIBLE | The ACMDRVSTREAMSIZE structure and query type specified information that cannot be satisfied by the driver.
MMSYSERR_NOTSUPPORTED | The driver does not support the requested query type. A driver must always support the ACM_STREAMSIZEF_SOURCE and ACM_STREAMSIZEF_DESTINATION query types.

lParam1
Address of the ACMDRVSTREAMINSTANCE structure for the conversion stream that the conversion size request is for.
lParam2
Address of the ACMDRVSTREAMSIZE structure that defines the conversion stream size query attributes.

An ACM driver must support this message if it supports the ACMDM_STREAM_OPEN message. Note that the following parameters for the ACMDM_STREAM_SIZE message will be validated before calling the driver:

  • The lParam1 parameter will contain a valid pointer to an ACMDRVSTREAMINSTANCE structure with the same information as the corresponding ACMDM_STREAM_OPEN message.
  • The lParam2 parameter will contain a valid pointer to an ACMDRVSTREAMSIZE structure with the proper members initialized for the requested query operation. This structure will be at least the size of the base ACMDRVSTREAMSIZE structure.
  • The cbStruct member of the ACMDRVSTREAMSIZE structure will be set to at least the size, in bytes, of the base ACMDRVSTREAMSIZE structure.
  • The cbSrcLength will be nonzero if the ACM_STREAMSIZEF_SOURCE flag is specified.
  • The cbDstLength will be nonzero if the ACM_STREAMSIZEF_DESTINATION flag is specified.
  • No invalid flag combinations will be specified in the fdwSize member.

The driver does not need to check for these conditions.

See Also

ACMDM_STREAM_CLOSE, ACMDM_STREAM_CONVERT, ACMDM_STREAM_OPEN, ACMDM_STREAM_PREPARE, ACMDM_STREAM_RESET, ACMDM_STREAM_UNPREPARE, ACMDRVOPENDESC, ACMDRVSTREAMHEADER, ACMDRVSTREAMINSTANCE, ACMDRVSTREAMSIZE


ACMDM_STREAM_UNPREPARE

lParam1 = (LPARAM) pacmDSI  // see below
lParam2 = (LPARAM) pacmDSH  // see below

Sent to an Audio Compression Manager (ACM) driver to allow the driver to optionally unprepare an ACMDRVSTREAMHEADER structure and corresponding data blocks used for conversions. This message is usually sent to an ACM driver in response to an acmStreamUnprepareHeader call.

  • Return MMSYSERR_NOERROR if the operation is successful or an error value otherwise. The following errors are possible:
MMSYSERR_NOTENABLED | The driver failed to load or initialize.
MMSYSERR_NOTSUPPORTED | The driver does not support this message.

lParam1
Address of the ACMDRVSTREAMINSTANCE structure for the conversion stream that the prepare request is for.
lParam2
Address of the ACMDRVSTREAMHEADER structure identifying the source and destination data blocks that should be unprepared.

An ACM driver must support the ACMDM_STREAM_UNPREPARE message if it supports the ACMDM_STREAM_PREPARE message.

The default response for the ACMDM_STREAM_UNPREPARE message is to return MMSYSERR_NOTSUPPORTED. In this case, the ACM will mark the stream header as being unprepared (clears the ACMSTREAMHEADER_STATUSF_PREPARED flag in the fdwStatus member of the ACMDRVSTREAMHEADER structure).

If a driver requires other cleanup operations to unprepare the header and data blocks used for conversions, it should perform these operations and return MMSYSERR_NOERROR. The ACM will then mark the stream header as being unprepared (a driver should never modify the ACMSTREAMHEADER_STATUSF_PREPARED flag in the fdwStatus member of the ACMDRVSTREAMHEADER structure).

The ACM will always send the ACMDM_STREAM_PREPARE and ACMDM_STREAM_UNPREPARE messages to a driver even if the driver returns MMSYSERR_NOTSUPPORTED. This allows a driver to optionally perform minor preparations for the header and data buffers while still taking advantage of the default behavior performed by the ACM

Note that the following parameters for the ACMDM_STREAM_UNPREPARE message will be validated before calling the driver:

  • The lParam1 parameter will contain a valid pointer to an ACMDRVSTREAMINSTANCE structure with the same information as the corresponding ACMDM_STREAM_OPEN message.
  • The lParam2 parameter will contain a valid pointer to an ACMDRVSTREAMHEADER structure with the proper members initialized for the unprepare request. This structure will be at least the size of the base ACMDRVSTREAMHEADER structure.
  • The cbStruct member of the ACMDRVSTREAMHEADER structure will be set to at least the size, in bytes, of the base ACMDRVSTREAMHEADER structure.
  • The remaining members of the ACMDRVSTREAMHEADER structure will be within the bounds described in the documentation for the ACMDRVSTREAMHEADER structure.

The driver does not need to check for these conditions.

See Also

ACMDM_STREAM_CLOSE, ACMDM_STREAM_CONVERT, ACMDM_STREAM_OPEN, ACMDM_STREAM_PREPARE, ACMDM_STREAM_RESET, ACMDM_STREAM_SIZE, ACMDRVOPENDESC, ACMDRVSTREAMHEADER, ACMDRVSTREAMINSTANCE, ACMDRVSTREAMSIZE


ACMDRVFORMATSUGGEST

typedef struct {
    DWORD cbStruct;
    DWORD fdwSuggest;
    LPWAVEFORMATEX pwfxSrc;
    DWORD cbwfxSrc;
    LPWAVEFORMATEX pwfxDst;
    DWORD cbwfxDst;
} ACMDRVFORMATSUGGEST;

Contains information needed by an Audio Compression Manager (ACM) driver to respond to the ACMDM_FORMAT_SUGGEST message. The lParam1 parameter of the acmDriverProc function will contain a pointer to this structure during the ACMDM_FORMAT_SUGGEST message.

Members

cbStruct
Size, in bytes, of the ACMDRVFORMATSUGGEST structure. This member will be initialized by the ACM before calling the driver. This member can be greater than the size, in bytes, of the base ACMDRVFORMATSUGGEST structure. An ACM driver should ignore any members that are not contained in the base ACMDRVFORMATSUGGEST structure. This member should not be modified by the driver.
fdwSuggest
Flags for matching the desired destination format. This member should not be modified by the driver.
ACM_FORMATSUGGESTF_NCHANNELS | Specifies that the nChannels member of the pwfxDst member of the ACMDRVFORMATSUGGEST structure is valid. The driver should only suggest formats that can be converted from the format given in the pwfxSrc member of the ACMDRVFORMATSUGGEST structure matching the destination nChannels member, or fail.
ACM_FORMATSUGGESTF_NSAMPLESPERSEC | Specifies that the nSamplesPerSec member of the pwfxDst member of the ACMDRVFORMATSUGGEST structure is valid. The driver should only suggest formats that can be converted from the format given in the pwfxSrc member of the ACMDRVFORMATSUGGEST structure matching the destination nSamplesPerSec member, or fail.
ACM_FORMATSUGGESTF_WBITSPERSAMPLE | Specifies that the wBitsPerSample member of the pwfxDst member of the ACMDRVFORMATSUGGEST structure is valid. The driver should only suggest formats that can be converted from the format given in the pwfxSrc member of the ACMDRVFORMATSUGGEST structure matching the destination wBitsPerSample member, or fail.
ACM_FORMATSUGGESTF_WFORMATTAG | Specifies that the wFormatTag member of the pwfxDst member of the ACMDRVFORMATSUGGEST structure is valid. The driver should only suggest formats that can be converted from the format given in the pwfxSrc member of the ACMDRVFORMATSUGGEST structure matching the destination wFormatTag member, or fail.

pwfxSrc
Address of a WAVEFORMATEX structure that identifies the source format to suggest a destination format to be used for a conversion. This member should not be modified by the driver.
cbwfxSrc
Size, in bytes, of the WAVEFORMATEX structure pointed to by the pwfxSrc member of the ACMDRVFORMATSUGGEST structure. This member should not be modified by the driver.
pwfxDst
Address of a WAVEFORMATEX data structure to receive the suggested destination format for the source format pointed to by the pwfxSrc member of the ACMDRVFORMATSUGGEST structure. Note that, based on the fdwSuggest member, some members of the structure pointed to this member may be specified. The driver should use this buffer to return the suggested destination format.
cbwfxDst
Size, in bytes, of the WAVEFORMATEX structure pointed to by the pwfxDst member of the ACMDRVFORMATSUGGEST structure that is available for the suggested format. This member should not be modified by the driver.

See Also

ACMDM_FORMAT_DETAILS, ACMDM_FORMAT_SUGGEST, ACMDM_FORMATTAG_DETAILS


ACMDRVOPENDESC

typedef struct {
    DWORD cbStruct;
    FOURCC fccType;
    FOURCC fccComp;
    DWORD dwVersion;
    DWORD dwFlags;
    DWORD dwError;
    LPCWSTR pszSectionName;
    LPCWSTR pszAliasName;
    DWORD   dnDevNode;
} ACMDRVOPENDESC;

Contains information needed by an Audio Compression Manager (ACM) driver when opened with a DRV_OPEN message. The lParam2 parameter of the acmDriverProc function will contain a pointer to this structure during the DRV_OPEN message.

Members

cbStruct
Size, in bytes, of the ACMDRVOPENDESC structure. This member will be initialized by the ACM before calling the driver. This member can be greater than the size, in bytes, of the base ACMDRVOPENDESC structure. An ACM driver should ignore any members that are not contained in the base ACMDRVOPENDESC structure. This member should not be modified by the driver.
fccType
Four-character code identifying the type of driver that is attempting to be opened. This member will be ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC (audc) for ACM drivers. An ACM driver should examine this member first and fail the DRV_OPEN message by returning zero if it is not equal to ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC. In case of failure, all remaining members should be ignored and remain unmodified.
fccComp
Four-character code identifying the sub-type of the driver that is attempting to be opened. This member will currently be ACMDRIVERDETAILS_FCCCOMP_UNDEFINED (zero) for ACM drivers. An ACM driver should ignore this member. This member should not be modified by the driver.
dwVersion
Version of the ACM that is opening the driver. This member will be equivalent to the value returned by acmGetVersion. An ACM driver can modify its behavior based on this value, but should not fail unless absolutely necessary. Future versions of the ACM will be backward-compatible with drivers written for previous versions of the ACM. This member should not be modified by the driver.
dwFlags
This member defines flags used for opening an ACM driver. This member is identical to the fdwOpen parameter passed to acmDriverOpen. Currently, no flags are defined and this member should be ignored. This member should not be modified by the driver.
dwError
If an ACM driver needs to fail the DRV_OPEN message for other reasons than an incompatible fccType (that is, the DRV_OPEN is for an ACM driver), this member must be set to the desired nonzero error code. This error code will be the return value from acmDriverOpen. This member is ignored if the driver succeeds the DRV_OPEN message (returns nonzero).
pszSectionName
Address of a null-terminated string that specifies the name of the section in the SYSTEM.INI file where driver information is recorded.
pszAliasName
Address of a null-terminated string that specifies the driver name or an alias under which the driver was loaded.
dnDevNode
For plug-and-play drivers, this member identifies the device node for which the driver is being opened.

See Also

ACMDM_STREAM_CLOSE, ACMDM_STREAM_CONVERT, ACMDM_STREAM_OPEN, ACMDM_STREAM_PREPARE, ACMDM_STREAM_RESET, ACMDM_STREAM_SIZE, ACMDM_STREAM_UNPREPARE, ACMDRVSTREAMHEADER, ACMDRVSTREAMINSTANCE, ACMDRVSTREAMSIZE


ACMDRVSTREAMHEADER

typedef struct {
    DWORD cbStruct;
    DWORD fdwStatus;
    DWORD dwUser;
    LPBYTE pbSrc;
    DWORD cbSrcLength;
    DWORD cbSrcLengthUsed;
    DWORD dwSrcUser;
    LPBYTE pbDst;
    DWORD cbDstLength;
    DWORD cbDstLengthUsed;
    DWORD dwDstUser;
    DWORD fdwConvert;
    LPACMDRVSTREAMHEADER padshNext;
    DWORD fdwDriver;
    DWORD dwDriver;
    DWORD fdwPrepared;
    DWORD dwPrepared;
    LPBYTE pbPreparedSrc;
    DWORD cbPreparedSrcLength;
    LPBYTE pbPreparedDst;
    DWORD cbPreparedDstLength;
} ACMDRVSTREAMHEADER;

Defines the header used to identify an Audio Compression Manager (ACM) conversion source and destination buffer pair for a conversion stream. This structure is passed as the lParam2 parameter for the ACMDM_STREAM_PREPARE, ACMDM_STREAM_UNPREPARE, and ACMDM_STREAM_CONVERT ACM driver messages. Except where noted, no members of this structure can be modified by the driver, because they are intended for state information about a conversion stream and are maintained by the ACM.

Members

cbStruct
Size, in bytes, of the ACMDRVSTREAMHEADER structure. This member is initialized by the ACM before calling the driver. This member can be greater than the size, in bytes, of the base ACMDRVSTREAMHEADER structure. An ACM driver should ignore any members that are not contained in the base ACMDRVSTREAMHEADER structure. This member should not be modified by the driver.
fdwStatus
Flags giving information about the conversion buffers. This member should not be modified by the driver except as indicated below.
ACMSTREAMHEADER_STATUSF_DONE | Indicates that a conversion is complete.
ACMSTREAMHEADER_STATUSF_INQUEUE | Set by the driver to indicate that the data buffers are queued for an asynchronous conversion. If the conversion stream is not asynchronous, the driver should not modify this flag.
ACMSTREAMHEADER_STATUSF_PREPARED | Set by the ACM to indicate that the data buffers have been prepared with acmStreamPrepareHeader. This flag is always maintained by the ACM regardless of whether the driver supports preparing stream headers.

dwUser
32 bits of user data. This can be any instance data specified by the application. This member should not be examined or modified by the driver.
pbSrc
Address of the source data buffer. This pointer will always refer to the same location while the stream header remains prepared. If an application needs to change the source location, it will unprepare the header and re-prepare it with the alternate location. This member should not be modified by the driver. This pointer will always be non-NULL.
cbSrcLength
Length, in bytes, of the source data buffer pointed to by pbSrc. When the header is prepared, this member specifies the maximum size that will be used in the source buffer. Conversions can be performed on source lengths less than or equal to the original prepared size. However, this member will be reset to the original size when unpreparing the header. This member should not be modified by the driver. This length will always be nonzero.
cbSrcLengthUsed
Amount of data, in bytes, used for the conversion. This member must be set by the driver when the conversion is complete. Note that this value can be less than or equal to cbSrcLength. An application will use the cbSrcLengthUsed member when advancing to the next piece of source data for the conversion stream.
dwSrcUser
32 bits of user data. This can be any instance data specified by the application. This member should not be examined or modified by the driver.
pbDst
Address of the destination data buffer. This pointer will always refer to the same location while the stream header remains prepared. If an application needs to change the destination location, it will unprepare the header and re-prepare it with the alternate location. This member should not be modified by the driver. This pointer will always be non-NULL.
cbDstLength
Length, in bytes, of the destination data buffer pointed to by pbDst. When the header is prepared, this member specifies the maximum size that will be used in the destination buffer. This member should not be modified by the driver. This length will always be nonzero.
cbDstLengthUsed
Amount of data in bytes returned by the conversion. This member must be set by the driver when the conversion is complete. Note that this value can be less than or equal to cbDstLength. An application will use the cbDstLengthUsed member when advancing to the next destination location for the conversion stream.
dwDstUser
32 bits of user data. This can be any instance data specified by the application. This member should not be examined or modified by the driver.
fdwConvert
This member defines flags that should be used for preparing, unpreparing, and converting stream buffers. This member is identical to:
  • The fdwPrepare parameter passed to acmStreamPrepareHeader for the ACMDM_STREAM_PREPARE message.
  • The fdwUnprepare parameter passed to acmStreamUnprepareHeader for the ACMDM_STREAM_UNPREPARE message.
  • The fdwConvert parameter passed to acmStreamConvert for the ACMDM_STREAM_CONVERT message.

This member should not be modified by the driver.

Currently, neither acmStreamPrepareHeader nor acmStreamUnprepareHeader define flags. The acmStreamConvert function defines the following flags:
ACM_STREAMCONVERTF_BLOCKALIGN | Specifies that only integral numbers of blocks should be converted. Converted data must end on block-aligned boundaries. An application uses this flag for all conversions on a stream until there is not enough source data to convert to a block-aligned destination; in which case, the last conversion will be specified without this flag.
ACM_STREAMCONVERTF_END | Specifies that the conversion stream should begin returning pending instance data. For example, if a conversion stream maintains instance data, such as the tail end of an echo filter operation, this flag should tell the driver to start returning this remaining data with optional source data. Note that this flag can be specified with the ACM_STREAMCONVERTF_START flag.
ACM_STREAMCONVERTF_START | Specifies that the conversion stream should reinitialize its instance data. For example, if a conversion stream maintains instance data, such as delta or predictor information, this flag should reset the stream to starting defaults. Note that this flag can be specified with the ACM_STREAMCONVERTF_END flag.

padshNext
Specifies a pointer that can be used by a driver to maintain a list of queued asynchronous conversion buffers. This member is intended for drivers to use for driver-specific lists. However, this member can be any instance data specified by the driver. This member will not be valid after returning a header to the caller.
fdwDriver
32 bits of driver-defined flags. This member is intended for drivers to use for driver-specific flags. However, this member can be any instance data specified by the driver. Note that this member is set by the driver and can be modified during any ACMDM_STREAM_CONVERT message. This member will be passed back with all ACMDM_STREAM_CONVERT messages unmodified by the ACM while the stream header remains prepared.
dwDriver
32 bits of driver-defined data. This can be any instance data specified by the driver. Note that this member is set by the driver and can be modified during any ACMDM_STREAM_CONVERT message. This member will be passed back with all ACMDM_STREAM_CONVERT messages unmodified by the ACM while the stream header remains prepared.
fdwPrepared
This member is used by the ACM and should not be examined or modified by the driver.
dwPrepared
This member is used by the ACM and should not be examined or modified by the driver.
pbPreparedSrc
This member is used by the ACM and should not be examined or modified by the driver.
cbPreparedSrcLength
This member is used by the ACM and should not be examined or modified by the driver.
pbPreparedDst
This member is used by the ACM and should not be examined or modified by the driver.
cbPreparedDstLength
This member is used by the ACM and should not be examined or modified by the driver.

The source (pbSrc) and destination (pbDst) data buffers are allocated with GlobalAlloc using the GMEM_MOVEABLE and GMEM_SHARE flags, and locked with GlobalLock.

See Also

ACMDM_STREAM_CLOSE, ACMDM_STREAM_CONVERT, ACMDM_STREAM_OPEN, ACMDM_STREAM_PREPARE, ACMDM_STREAM_RESET, ACMDM_STREAM_SIZE, ACMDM_STREAM_UNPREPARE, ACMDRVOPENDESC, ACMDRVSTREAMINSTANCE, ACMDRVSTREAMSIZE


ACMDRVSTREAMINSTANCE

typedef struct {
    DWORD cbStruct;
    LPWAVEFORMATEX pwfxSrc;
    LPWAVEFORMATEX pwfxDst;
    LPWAVEFILTER pwfltr;
    DWORD dwCallback;
    DWORD dwInstance;
    DWORD fdwOpen;
    DWORD fdwDriver;
    DWORD dwDriver;
    HACMSTREAM has;
} ACMDRVSTREAMINSTANCE;

Contains instance information for an open Audio Compression Manager (ACM) driver conversion stream. This structure is passed as the lParam1 parameter for all ACM driver messages for conversion streams. Except where noted, no members of this structure can be modified by the driver, because they are intended for state information about a conversion stream and are maintained by the ACM.

Members

cbStruct
Size, in bytes, of the ACMDRVSTREAMINSTANCE structure. This member is initialized by the ACM before calling the driver. This member can be greater than the size, in bytes, of the base ACMDRVSTREAMINSTANCE structure. An ACM driver should ignore any members that are not contained in the base ACMDRVSTREAMINSTANCE structure. This member should not be modified by the driver.
pwfxSrc
Address of a WAVEFORMATEX structure that defines the source format for a conversion stream. This member will never be NULL. This member should not be modified by the driver.
pwfxDst
Address of a WAVEFORMATEX structure that defines the destination format for a conversion stream. This member will never be NULL. This member should not be modified by the driver.
pwfltr
Address of an optional WAVEFILTER structure that defines the filter to be used on a conversion stream. This member will be NULL if no filter is being used on the conversion stream. This member should not be modified by the driver.
dwCallback
Specifies the address of a callback function, a window handle, or a handle to an event, depending on the flags specified in the fdwOpen member. The driver uses this information to notify the client via the DriverCallback function. Note that this member is valid only for streams opened with the ACM_STREAMOPEN_ASYNC flag. If this member is zero, no callback should be performed on a open, close, or buffer-completion operation for a conversion stream.
dwInstance
Specifies 32 bits of instance information for the client. This instance information must be returned to the client whenever the driver notifies the client via the DriverCallback function.
fdwOpen
This member defines flags used for opening an ACM conversion stream. This member is identical to the fdwOpen parameter passed to acmStreamOpen. This member should not be modified by the driver.
ACM_STREAMOPENF_ASYNC | Specifies that conversion of the stream should be performed asynchronously. If this flag is specified, the application can use a callback to be notified when the conversion stream is opened and closed, and after each buffer is converted. In addition to using a callback, an application can examine the fdwStatus of the ACMSTREAMHEADER structure for the ACMSTREAMHEADER_STATUSF_DONE flag.
ACM_STREAMOPENF_NONREALTIME | Specifies that the driver should not consider time constraints when converting the data. By default, the driver should attempt to convert the data in real time. If the conversion cannot be performed in real time, the driver should fail to open the conversion stream by returning ACMERR_NOTPOSSIBLE for the ACMDM_STREAM_OPEN message.
ACM_STREAMOPENF_QUERY | Specifies that the driver is being queried to determine whether it supports the given conversion. A conversion stream will not be opened.
CALLBACK_EVENT | Specifies that dwCallback is a handle to an event.
CALLBACK_FUNCTION | Specifies that dwCallback is a callback procedure address. The function prototype must conform to the acmStreamConvertCallback convention.
CALLBACK_WINDOW | Specifies that dwCallback is a window handle.

fdwDriver
32 bits of driver-defined flags. This member is intended for drivers to use for driver-specific flags. However, this member can be any instance data specified by the driver. Note that this member is set by the driver and can be modified during any conversion-stream driver messages. This member will be passed back with all conversion-stream driver messages unmodified by the ACM while the conversion stream remains open.
dwDriver
32 bits of driver-defined data. This can be any instance data specified by the driver. Note that this member is set by the driver and can be modified during any conversion- stream driver messages. This member will be passed back with all conversion-stream driver messages unmodified by the ACM while the conversion stream remains open.
has
Client handle to the open conversion stream assigned by the ACM. This handle must be used when notifying the client with the DriverCallback function for asynchronous conversions.

The ACMDRVSTREAMINSTANCE structure is used to contain instance data for a conversion stream. This structure will be passed as the lParam1 parameter of all conversion-stream driver messages. No members of this structure will change from the initial state passed to the ACMDM_STREAM_OPEN message. Therefore, a driver never needs to validate information in this structure after succeeding the ACMDM_STREAM_OPEN message.

The fdwDriver and dwDriver members of the ACMDRVSTREAMINSTANCE structure can be modified by the driver at any time. All remaining members must not be modified by the driver under any circumstances.

See Also

ACMDM_STREAM_CONVERT, ACMDM_STREAM_OPEN, ACMDM_STREAM_PREPARE, ACMDM_STREAM_RESET, ACMDM_STREAM_SIZE, ACMDM_STREAM_UNPREPARE, ACMDRVOPENDESC, ACMDRVSTREAMHEADER, ACMDRVSTREAMSIZE


ACMDRVSTREAMSIZE

typedef struct {
    DWORD cbStruct;
    DWORD fdwSize;
    DWORD cbSrcLength;
    DWORD cbDstLength;
} ACMDRVSTREAMSIZE;

Contains information needed by an Audio Compression Manager (ACM) driver to respond to the ACMDM_STREAM_SIZE message. The lParam2 parameter of the acmDriverProc function will contain a pointer to this structure during the ACMDM_STREAM_SIZE message.

Members

cbStruct
Size, in bytes, of the ACMDRVSTREAMSIZE structure. This member will be initialized by the ACM before calling the driver. This member can be greater than the size, in bytes, of the base ACMDRVSTREAMSIZE structure. An ACM driver should ignore any members that are not contained in the base ACMDRVSTREAMSIZE structure. This member should not be modified by the driver.
fdwSize
Flags for the stream-size query. This member should not be modified by the driver.
ACM_STREAMSIZEF_DESTINATION | Indicates that the cbDstLength member contains the size of the application's destination buffer in bytes. The driver should return the recommended source buffer size, in bytes, in the cbSrcLength member. A driver should not modify the cbDstLength member if this query type is specified.
ACM_STREAMSIZEF_SOURCE | Indicates that the cbSrcLength member contains the size of the application's source buffer in bytes. The driver should return the recommended destination buffer size, in bytes, in the cbDstLength member. A driver should not modify the cbSrcLength member if this query type is specified.

cbSrcLength
Size, in bytes, of the source buffer. This member is an input parameter if the query type specified in the fdwSize member is ACM_STREAMSIZEF_SOURCE. This member is an output parameter if the query type specified in the fdwSize member is ACM_STREAMSIZEF_DESTINATION.
cbDstLength
Size, in bytes, of the destination buffer. This member is an input parameter if the query type specified in the fdwSize member is ACM_STREAMSIZEF_DESTINATION. This member is an output parameter if the query type specified in the fdwSize member is ACM_STREAMSIZEF_SOURCE.

See Also

ACMDM_STREAM_CLOSE, ACMDM_STREAM_CONVERT, ACMDM_STREAM_OPEN, ACMDM_STREAM_PREPARE, ACMDM_STREAM_RESET, ACMDM_STREAM_SIZE, ACMDM_STREAM_UNPREPARE, ACMDRVOPENDESC, ACMDRVSTREAMHEADER, ACMDRVSTREAMINSTANCE


Joystick Device Drivers

The joystick is an input device that provides absolute position information. It is an additional supported input device and not a replacement for the mouse. For this section, the term joystick refers to any absolute position device; for example, a light pen, digitizing tablet, or touch screen could all use the joystick driver interface.

All joystick function calls are routed through the operating system. The operating system loads the joystick driver and passes application requests to it. The joystick driver must handle the standard tasks handled by all installable drivers, as well as the following joystick-specific tasks:

  • Return the button configuration and movement range of the attached devices
  • Return position and button-press information
  • Accept calibration values and adjust position information accordingly

The joystick driver interface lets a driver to handle one or two devices. Each device can have one to three axes and one to four buttons. The IBMJOY joystick driver included with Windows can handle two joysticks, each with up to two axes and two buttons, or one joystick with up to three axes and four buttons. The joystick interface accommodates both analog and digital devices.


Joystick Driver Entry Point

A joystick driver must include the standard DriverProc entry point function. This function handles standard and joystick-specific messages sent by the operating system.

DriverProc has the following prototype:

LRESULT WINAPI DriverProc(DWORD dwDriverID,
    HANDLE hDriver,
    UINT uMsg,
    LPARAM lParam1,
    LPARAM  lParam2)

Joystick device drivers uses the following definitions for the parameters of this entry point:

Parameter | Definition
dwDriverID | Contains the driver identifier created by the device driver.
hDriver | Contains a handle to the device driver
uMsg | Contains the joystick message
lParam1 | Contains message-dependent data.
lParam2 | Contains message-dependent data.

For more information on the DriverProc entry point and the system messages it handles see the Microsoft® Win32™ Programmer's Reference.


Handling Errors

For a description of handling the error return values from DriverProc for system messages, see the description of installable device drivers in the Microsoft Windows Software Development Kit. The following table summarizes the error codes defined for joystick drivers:

Error code | Definition
MMSYSERR_NOERROR | No error.
MMSYSERR_NODRIVER | No joystick device driver is present.
JOYERR_PARMS | Invalid parameters were passed with the message.
JOYERR_NOCANDO | Driver cannot perform the requested task because some service is unavailable.
JOYERR_UNPLUGGED | Specified joystick is unplugged.


DRV_OPEN Message

On the DRV_OPEN system message, the lParam2 parameter specifies which device is being opened. This value is zero for the first device and 1 for the second device.

The value that DriverProc returns for the DRV_OPEN message becomes the dwDriverID parameter for all subsequent messages sent to this driver. The driver can use this value for its own purposes. For example, a driver can use it to identify a structure containing information about the client that opened it.


Returning the Number of Devices

MMSYSTEM sends a JDD_GETNUMDEVS message to a joystick driver to determine how many devices it supports. The lParam1 and lParm2 parameters are not used with this message. In response to the JDD_GETNUMDEVS message, the driver returns the maximum number of devices it supports.

The number of supported devices returned by a driver is not necessarily the same as the number of connected devices. This lets a user connect a device after the driver has been loaded. The joystick interface provides a JOYERR_UNPLUGGED error value that a driver should return when an application polls an unplugged device. For example, the IBMJOY.DRV driver returns 2 in response to this message, regardless of the number of joysticks actually connected to the adapter.


Providing Device Capability Information

MMSYSTEM sends the JDD_GETDEVCAPS message to request information about the coordinate range and button configuration of a joystick driver. In response to this message, a joystick driver fills in the JOYCAPS structure, a pointer to it is passed to the lParam1 parameter. The JOYCAPS structure members describe the coordinate range, button configuration, and manufacturer of the device.

The minimum and maximum position values should reflect a set of logical coordinates that is independent of minute differences between copies of a hardware device. For example, users of joystick services should always see a full range of logical coordinates returned from a calibrated joystick. Calibration values should not affect the minimum and maximum values returned by a joystick driver. The IBMJOY example device driver Windows returns coordinate values in the range of zero through 65535.

If a hardware device does not support a given axis, return zero values for the minimum and maximum coordinate values for that axis. For example, a driver for a two-dimensional device would set the wZmin and wZmax members to zero.


Accepting New Calibration Settings

The Joystick option of the Control Panel calculates calibration values for joysticks drivers. (If you need this program for developing a joystick driver, contact Microsoft Product Support Services and ask for the multimedia joystick control panel applet.) A joystick driver can use the calibration values to convert the actual values returned by the hardware device to the logical values expected by the joystick interface. A driver establishes the logical value range in its response to the JDD_GETDEVCAPS message.

The calibration settings consist of base and delta values for each coordinate. The base value represents the lowest logical value the driver returns; the delta value is the multiplier to use when converting the actual value returned by the device to a logical value appropriate for the established value range.

Immediately after MMSYSTEM loads the joystick driver, it reads the calibration values from the SYSTEM.INI file and sends them to the driver with the JDD_SETCALIBRATION message. MMSYSTEM sends the JDD_SETCALIBRATION message with two JOYCALIBRATE structures (pointers to them are passed in the lParam1 and lParam2 parameters). The first structure contains the new calibration settings the driver should adopt. The joystick driver should fill the second structure with the previous calibration settings.


Calculating Calibration Values

To calculate the base and delta calibration values, the Joystick option of the Control Panel sets the base value to zero and the delta values to 1. It then polls the joystick driver while the user holds the joystick at each corner of the device coordinate space. This produces the actual value range returned by the device for each coordinate.

After retrieving the coordinate ranges specified by the joyGetDevCaps function, the Joystick option uses the following formulas to calculate new base and delta values.

wDelta = (wTargetMax - wTargetMin) / (wActualMax - wActualMin)
wBase = (wActualMin * wDelta) - wTargetMin

In the following example, the joystick returned x coordinate values in the range 43 to 345, compared to a logical value range of zero to 65535:

wDelta = (65535-0) / (345-43)
       = 216

wBase  = 43 * 216 - 0
       = 9288


Providing Position and Button-State Information

The JDD_GETPOS message requests device coordinate and button information. A joystick driver fills in the JOYINFO structure and a pointer to it is passed in the lParam1 parameter.

The coordinate values should be within the range the driver established when responding to the JDD_GETDEVCAPS message. When calculating the coordinate values, use the base and delta-calibration values passed to the driver with the JDD_SETCALIBRATION message.

See "Sample Source Code," later in this section, for a detailed description of how the IBMJOY device driver handles the JDD_GETPOS message.


Driver Installation and Calibration

A joystick driver should use the DriverProc system messages for its installation and configuration routines. These messages are described in the documentation for the Microsoft Windows Software Development Kit.

The Joystick option of the Control Panel records the calibration settings in the [Joystick.Drv] section of the SYSTEM.INI file. After loading the joystick driver, MMSYSTEM reads the calibration information from SYSTEM.INI and sends it to the joystick driver with the JDD_SETCALIBRATION message.

The Joystick option program lists the calibration settings in the following format:

JoyCaln=xBase xDelta yBase yDelta zBase zDelta

Each number is a two-byte hexadecimal value. For example, a system with a single two-dimensional joystick might have the following entry:

[Joystick.Drv]
JoyCal0=0e64 0133 0c30 00f0 0000 0000
JoyCal1=0000 0001 0000 0001 0000 0001

If a joystick driver uses a custom calibration program, it should record the calibration information in this format.


Testing Joystick Device Drivers

The DDK includes JOYTST, a joystick device-driver testing application. JOYTST uses the standard DDK test shell.


Using Joystick Device Drivers

The DDK includes source code for the IBMJOY joystick driver. Most of the driver code is located in a C language file called, IBMJOY.C. An assembly language file, POLL.ASM, contains a single assembly language routine, Poll, that interrogates the joystick for button press and coordinate information.

The remainder of this section describes the parts of the IBMJOY device driver that calculate button state and joystick position information. It begins with a brief description of the IBM Game Control Adapter.


IBM Game Control Adapter Interface

The IBM Game Control Adapter provides four analog inputs and four digital inputs, supporting one 3-dimensional joystick or two 2-dimensional joysticks. All information is read from address 0x201. The layout of the address follows:

Bit | Input type | Contents
7 | Digital | Device B, button 2
6 | Digital | Device B, button 1
5 | Digital | Device A, button 2
4 | Digital | Device A, button 1
3 | Resistive | Device B, y coordinate
2 | Resistive | Device B, x coordinate
1 | Resistive | Device A, y coordinate
0 | Resistive | Device A, x coordinate

Button states are indicated on bits 7 through 4, which are cleared when the corresponding button is pressed and set when the button is released.

Bits 3 through zero are used to determine the joystick coordinates. Each joystick coordinate has a potentiometer whose resistance increases the further the joystick is pushed. When the adapter receives an OUT instruction to address 0x201, it sets bits 3 through zero and starts four one-shot timers, each corresponding to a single coordinate. The duration of each timer is proportional to the resistance of the respective potentiometer. The bits clear at different times, depending on the value for each coordinate; the larger the coordinate value, the longer the timeout period.


Polling the Joystick

This section describes the procedure that IBMJOY.C follows when retrieving the button states and coordinate values for an IBM-compatible joystick. The procedure differs depending on which joystick is being polled and whether a three-dimensional joystick is being polled.


Polling Routine

The POLL.ASM assembly language file contains a single routine, Poll, that interrogates the joystick for button press and coordinate information. Poll sets four global variables, wXpos, wYpos, wZpos, and wButtons to the coordinate and button values. The Poll function either polls the x and y axes or polls the z axis; for a three-dimensional joystick, IBMJOY.C calls Poll twice.

The Poll function is defined as follows:

extern UINT PASCAL Poll(UINT id, int zOnly)

The id parameter identifies the joystick number. The zOnly parameter identifies whether the z axis is being polled and if so, which axis of the second joystick interface is acting as the z axis. The zOnly parameter has one of the following values:

Value | Description
0 | Poll x and y axes
-1 | Poll z axis using the x axis of the second joystick interface
1 | Poll z axis using the y axis of the second joystick interface


Calling Poll to Retrieve Button and Position Information

In the following example, the GetPos function calls the Poll function to retrieve information about the joystick:

UINT GetPos(UINT id, JOYINFO FAR * lpInfo)
{
    if(id > 1)
            return JOYERR_PARMS;    // Error...bad parameter

    lpInfo->wZpos = 0;

    if(wcAxes == 3)                 // Poll 3-axis joystick?
    {
        if(id == 1)                 // If 3D, must be joystick 1
            return JOYERR_UNPLUGGED;
        else
        {
            if(!Poll(1, iZaxis))    // Poll z axis
                return JOYERR_UNPLUGGED;
            lpInfo->wZpos = wYpos;

            if(!Poll(0, 0))         // Poll x and y axes
                return JOYERR_UNPLUGGED;
        }
    }
    else if(!Poll(id, 0))           // Poll 2-axis joystick
        return JOYERR_UNPLUGGED;

    lpInfo->wButtons = wButtons;
    lpInfo->wXpos = wXpos;
    lpInfo->wYpos = wYpos;

    return JOYERR_NOERROR;
}


Reading Button-Press Information

The beginning of the Poll function retrieves status information for the joystick buttons. Poll retrieves the button status information by reading address 0x201. (For a description of address 0x201, see the table in IBM Game Control Adapter Interface earlier in this section.) The button state information is in bits 7 through 4. Poll inverts the bits and stores the resulting value in the wButtons global variable.

The following example shows the portion of the Poll routine that retrieves the button status information :

cProc Poll <PUBLIC> <si, di>

    parmW   id
    parmW   zOnly
    localW  wClear

    cBegin

    mov     dx,JOYPORT      ; Set joystick port address
    in      al,dx           ; Read the port

    mov     cl,4            ; Shift at least four bits
    cmp     id, 0           ; If second joystick, shift six bits
    jz      @f
    add     cl,2
@@:
    shr     al,cl           ; Shift flags
    and     ax,3            ; Clear the other bits just in case
    xor     ax,3            ; Invert the bits (port gives reverse logic)
    mov     _wButtons,ax    ; Save flags in global variable
    .
    .                       ; Sample continued in next section
    .


Reading Joystick Position Information

The following example examines the section of Poll where the driver calculates the coordinate values. In this section, Poll performs the following tasks:

  • Clears the interrupt flag.
  • Initializes the coordinate variables. It sets the position counter variables to a negative base value, since the first iteration of the polling loop occurs before the potentiometer timers are started. See the next section for more information on the first iteration of the polling loop.
  • Records the delta calibration value for the coordinates in general-purpose registers.
  • Establishes the bit masks used to check the resistive flags during the polling loop.

The following code fragment continues where the previous fragment ended:

pushf                           ; Push the flags register
    cli                             ; No interrupts allowed!

    mov     wClear, 1               ; Set stabilization loop flag

Real_Poll:

    mov     dx,JOYPORT              ; Set joystick port address
    mov     si,offset _JoyCal       ; Point to first JOYCALIBRATE structure

    mov     bx,JOY1_XY_MASK         ; Place bit mask in bx
    cmp     id,0                    ; Are we polling joystick 1?
    jz      @f                      ;    If so, use first structure
    cmp     zOnly, 0                ; Are we polling the z axis?
    jnz     @f                      ;    If so, use first structure

                                    ; Polling the second joystick
    add     si,(size JOYCALIBRATE)  ; Use second JOYCALIBRATE structure
    mov     bx,JOY2_XY_MASK         ; and bit mask

@@:
    ; Note zOnly values:
    ;       0   if polling x and y
    ;      -1   if z axis is on the second joystick's x potentiometer
    ;       1   if z axis is on the second joystick's y potentiometer

    cmp     zOnly, 0                ; Are we polling the z axis?
    jz      poll_setxy              ;   No
    jl      @f                      ;   Yes, on y potentiometer
                                    ;   Yes, on x potentiometer
    mov     ax,[si].jcal_wZbase     ; Set x-pos. counter to z base value
    neg     ax                      ; Start off negative
    cwd
    mov     _wXpos,ax
    mov     _wXpos_hi,dx            ; used to check for roll-over error

    mov     cx,[si].jcal_wZdelta    ; Establish z delta value
    mov     bx,JOY2_X_MASK          ; Put bit mask into dx
    jmp     poll_timers             ; Start the timers!
; Set up for z-axis poll, using joystick 2's y potentiometer

@@: mov     ax,[si].jcal_wZbase     ; Set y-pos. counter to z base value
    neg     ax
    cwd
    mov     _wYpos,ax
    mov     _wYpos_Hi,dx            ; used to check for roll-over error

    mov     di,[si].jcal_wZdelta    ; Establish z delta value
    mov     bx,JOY2_Y_MASK          ; Put bit mask into bx
    jmp     poll_timers             ; Start the timers!

    ; Set up for x- and y-axis poll

poll_setxy:

    mov     ax,[si].jcal_wXbase     ; Set x-pos. counter to x base value
    neg     ax
    cwd
    mov     _wXpos,ax
    mov     _wXpos_hi,dx            ; used to check for roll-over error

    mov     ax,[si].jcal_wYbase     ; Set y-pos. counter to y base value
    neg     ax                      ; Start off negative
    cwd
    mov     _wYpos,ax
    mov     _wYpos_Hi,dx            ; used to check for roll-over error

    mov     cx,[si].jcal_wXdelta    ; Establish x and y deltas
    mov     di,[si].jcal_wYdelta
    .
    .                               ; Sample continued in next section
    .


Polling Loop

After setting up the required registers and global variables, Poll starts the polling loop. The first iteration of the polling loop occurs before the OUT to address 0x201; this is to ensure that the joystick's monostable vibrators have stabilized since the last poll. After the first iteration, Poll starts the timers by outputting a zero byte to address 0x201.

Each iteration of the polling loop checks the resistive flags. If the flag for a given axis is still set, the timeout has not yet occurred. Poll adds the delta value for that axis to the appropriate position variable. When all the flags are clear, Poll exits the loop. The value returned by this process depends on CPU speed; a fast CPU will complete more polling loops during the timeout period and therefore return higher coordinate values. This is why the IBMJOY driver requires calibration.

An unplugged joystick continually returns high bits for the position values. If a position counter exceeds a certain value (hard-coded as 0x30000 in POLL.ASM), assume the joystick is unplugged. Because the position value is dependent on CPU speed, the use of a constant ceiling value can present a problem with a very fast CPU (for example, a 50-MHz i486).

The following code fragment continues where the previous fragment ended:

; Start the timers!

poll_timers:

    mov     dx,JOYPORT              ; Set joystick port address
    cmp     wClear, 1               ; Dummy loop?
    je      poll_skipout
    xor     ax,ax
    out     dx,al

poll_skipout:

    mov     ah,bl                   ; bl contains x-position bit mask
    or        ah,bh                   ; bh contains y-position bit mask

poll_loop:
    in      al,dx                   ; Get position info from joystick port
    and     al,ah                   ; Only watch bits of interest

    jz      poll_done               ; Counters cleared?

poll_x_test:
    test    al,bl                   ; If x bit is cleared, stop
    jz        poll_y_test             ; incrementing the x counter.

    add     _wXpos,cx               ; X still high, increment counter
    adc     _wXpos_Hi,0

    cmp     _wXpos_Hi,3             ; Check for overflow (unplugged)
    jl      poll_y_test

    xor     ax,ax                   ; Unplugged. Return 0 and exit loop
    jz      poll_sti
poll_y_test:
    test    al,bh                   ; If y bit clear, stop incrementing
    jz        poll_loop

    add     _wYpos,di               ; Y still high, increment counter
    adc     _wYpos_Hi,0
    cmp     _wYpos_Hi,3             ; Check for overflow (unplugged)

    jl      poll_loop               ; No overflow, loop again

    xor     ax,ax                   ; Unplugged (return 0 and exit loop)
    jz      poll_sti

poll_done:
    dec     wClear                  ; Loop again if this is the dummy poll
    jnz     poll_sti
    jmp     Real_Poll

poll_sti:
    pop bx                          ; Pop flags
    test bx,200h                    ; Was interrupt flag already clear?
    jz poll_fix_x                   ;    Yes; don't reset it
    sti                             ;    No; reset interrupt flag

poll_fix_x:                         ; Clean up final x position value
    xor     bx,bx
    cmp     _wXpos_Hi,bx            ; Check overflow variable
    jz        poll_fix_y              ; If wXpos_Hi == 0, wXpos is OK
    jl        @f                      ; If wXpos_Hi < 0, set wXpos = 0
    dec     bx                      ; If wXpos_Hi > 0, set wXpos = 65535
@@: mov     _wXpos,bx

poll_fix_y:                         ; Clean up final y position value
    xor     bx,bx
    cmp     _wYpos_Hi,bx
    jz        poll_fix_done
    jl        @f
    dec     bx
@@: mov     _wYpos,bx

poll_fix_done:
    mov     al,ah                   ; ax =  0 for unplugged joystick
    xor     ah,ah                   ; ax != 0 if good read

    cEnd                            ; All done


Reference

This section is an alphabetic reference to the messages and data structures for joystick device drivers. Each joystick message has the JDD_ prefix and each joystick data structure has the JOY prefix.

Windows communicates with joystick device drivers through messages it sends to the driver. The driver process these messages with its DriverProc entry-point function. A message consists of three parts: a message number and two LONG parameters. Message numbers are identified by predefined message names. The two LONG parameters contain message-dependent values.

Basic capture operations | JDD_GETNUMDEVS
Device capabilities | JDD_GETDEVCAPS JOYCAPS
Calibration | JDD_SETCALIBRATION JOYCALIBRATE
Position and button status | JDD_GETPOS JOYINFO


Messages

The following topics describes the messages that are provided.


JDD_GETDEVCAPS

JDD_GETDEVCAPS
lpJoycaps = (LPJOYCAPS) lParam1;
lsize = lParam2;

Fills a JOYCAPS structure with joystick capabilities information.

  • Returns MMSYSERR_NOERROR if successful or if lParam2 is zero. Returns JOYERR_PARMS otherwise.
lpJoycaps
Address of the JOYCAPS structure to hold the joystick capabilities information.
lsize
Size, in bytes, of JOYCAPS referenced by lpJoycaps.

Compare the structure size value in lsize with the size of the JOYCAPS structure with which the driver was compiled. If lsize is larger than the expected structure size, fill the remaining data with zeros.

If lsize is zero , MMSYSERR_NOERROR is returned without updating the JOYCAPS structure.

See Also

JOYCAPS


JDD_GETNUMDEVS

JDD_GETNUMDEVS
lParam1 = 0;
lParam2 = 0;

Determines the number of devices supported by the driver.

  • Returns the maximum number of devices supported by the driver. This value does not necessarily match the number of devices physically connected to the computer.


JDD_GETPOS

JDD_GETPOS
lpJoyInfo = (LPJOYINFO)lParam1;
lParam2 = 0;

Fills a JOYINFO structure with current joystick position and button status information.

  • Returns MMSYSERR_NOERROR if the driver successfully supplies the information or JOYERR_UNPLUGGED otherwise.
lpJoyInfo
Address of the JOYINFO structure to hold the current position and button status information.

Position information returned in the JOYINFO structure should be mapped into the coordinate range identified by the driver. Minimum and maximum values for each axis are defined in the JOYCAPS structure, which the driver fills out in response to the JDD_GETDEVCAPS message.

See Also

JOYINFO, JOYCAPS, JDD_GETDEVCAPS


JDD_SETCALIBRATION

JDD_SETCALIBRATION
lpJoyCalibrate1 = (LPJOYCALIBRATE) lParam1;
lpJoyCalibrate2 = (LPJOYCALIBRATE) lParam2;

Sets the calibration information for the driver.

  • Returns MMSYSERR_NOERROR if successful.
lpJoyCalibrate1
Address of a JOYCALIBRATE structure containing new calibration values to adopt.
lpJoyCalibrate2
Address of a JOYCALIBRATE structure. The driver should fill this structure with the existing calibration values.

The driver should use the calibration values referenced by lpJoyCalibrate1 to map the physical device coordinates to the logical coordinate range established by the driver.

See Also

JOYCALIBRATE


JOYCALIBRATE

typedef struct joycalibrate_tag {
    UINT  wXbase;       // x-axis base calibration value.
    UINT  wXdelta;      // x-axis delta calibration value.
    UINT  wYbase;       // y-axis base calibration value.
    UINT  wYdelta;      // y-axis delta calibration value.
    UINT  wZbase;       // z-axis base calibration value.
    UINT  wZdelta;      // z-axis delta calibration value.
} JOYCALIBRATE;

Calibration values for the three axes of an absolute position device. Use the base and delta values returned in this structure to convert values retrieved from the device to values within the logical range specified by the driver.

The logical value returned for any axis is expressed by the following formula:

LogicalValue = Delta * DeviceValue + Base

The following formula is used to calculate delta values:

Delta = (LogicalMax - LogicalMin) / (DeviceMax - DeviceMin)

LogicalMax and LogicalMin represent the maximum and minimum logical coordinate values that the driver supports for the axis, as defined by the JOYCAPS structure. DeviceMax and DeviceMin represent the actual values returned by the device.

The following formula is used to calculate the base values:

Base = DeviceMin * Delta - LogicalMin

DeviceMin represents the minimum value returned by the device, Delta represents the multiplier of the device value, and LogicalMin represents the minimum value returned by the driver as defined by the JOYCAPS structure.

See Also

JDD_SETCALIBRATION, JOYCAPS


JOYCAPS

typedef struct joycaps_tag {
    UINT  wMid;                  // manufacturer ID of joystick
    UINT  wPid;                  // product ID of joystick
    char  szPname[MAXPNAMELEN];  // product name of joystick
    UINT  wXmin;                 // x-axis minimum logical value
    UINT  wXmax;                 // x-axis maximum logical value
    UINT  wYmin;                 // y-axis minimum logical value
    UINT  wYmax;                 // y-axis maximum logical value
    UINT  wZmin;                 // z-axis minimum logical value
    UINT  wZmax;                 // z-axis maximum logical value
    UINT  wNumButtons;           // number of buttons on joystick
    UINT  wPeriodMin;            // see below
    UINT  wPeriodMax;            // see below
} JOYCAPS;

Describes the joystick capabilities.

Members

wPeriodMin, wPeriodMax
Smallest and largest supported polling intervals when the joystick is captured by joySetCapture.

The minimum logical value for each axis is the smallest value that the joystick driver returns for that axis. The maximum logical value for each axis is the greatest value that the joystick driver returns for that axis.


JOYINFO

typedef struct joyinfo_tag {
    UINT  wXpos;
    UINT  wYpos;
    UINT  wZpos;
    UINT  wButtons;
} JOYINFO;

Contains joystick position and button status information.

Members

wXpos, wYpos, wZpos
Current position of a joystick along the X, Y and Z axes. Values are expressed in logical units.
wButtons
Current status of joystick buttons. Zero or more of the following flags can be set:
JOY_BUTTON1 | Set if button 1 is pressed.
JOY_BUTTON2 | Set if button 2 is pressed.
JOY_BUTTON3 | Set if button 3 is pressed.
JOY_BUTTON4 | Set if button 4 is pressed.


Video Compression and Decompression Drivers

Video compression and decompression drivers provide low-level video compression and decompression services for Microsoft Video for Windows. The compression and decompression algorithms used can be hardware or software based. This section explains the Windows interface for these drivers. It covers the following topics:

  • General information about writing a video compression and decompression driver
  • Information on how a video compression and decompression driver handles the system messages for the installable driver interface
  • Information on how a video compression and decompression driver handles messages specific to compressing and decompressing video data
  • An alphabetical reference to the messages and data structures used to write video compression and decompression drivers

Before reading this section, you should be familiar with the video services available with Windows. You should also be familiar with the Windows installable driver interface. For information about these Windows topics, see the Microsoft(r) Win32(tm) Programmer's Reference.


Architecture of a Video Compression and Decompression Driver

The following two block diagrams show the architecture of a video compression and decompression driver. While the diagrams show separate compression and decompression drivers, an actual driver usually combines both functions. The following illustration shows the architecture of a decompression driver:


Architecture for a Decompression Driver

The following illustration shows a similar architecture for the compression driver:


Architecture for a Compression Driver

The decompression driver and compression driver blocks represent your compression and decompression driver. The client-application block represents the system and application software that uses the services of your compression and decompression driver. Application software will always use the system software to access compression and decompression drivers.

The source of information used for decompression is represented by the AVI file block. Other sources of images can be used in place of this block. AVI files are RIFF files that contain audio and video data. The client-application maintains the RIFF format when it reads and writes the file. (Your driver will send and receive video data. The client-application will add and remove the RIFF tags.)

Compression drivers receive uncompressed data from the video source. Typically the video source is a disk file but it could also come from other video sources such as a video capture device. The video data can be either still bitmaps or motion video frames.

While a previous block diagram showed the decompression driver returning the uncompressed video to the client-application, your driver can have the capability to write directly to the display or display driver. These devices can replace a Windows video driver or work in conjunction with it. The following illustration shows a decompression driver with the ability to write to the video display:


Architecture for a Decompression Video Driver

These drivers handle a set of messages, the ICM_DRAW messages, in addition to the decompression messages defined for the services that return the decompressed video to the client-application.


Structure of a Video Compression and Decompression Driver

Video compression and decompression drivers are dynamic-link libraries (DLLs) usually written in C or assembly language, or a combination of the two languages.

As installable drivers, these drivers will provide a DriverProc entry point. For general information about installable drivers, the DriverProc entry point, and system messages sent to this entry point, see .

This section includes supplemental information for the system messages. This information describes specifically how compression and decompression drivers should respond to the system messages that are critical to their proper operation.

Video compression and decompression drivers also use the DriverProc entry point to process messages specifically for video compression and decompression. Information on how drivers use the DriverProc entry point to process these messages is contained in this section.


Installing Video Compression and Decompression Drivers

Video compression drivers are listed in the [drivers] section of the SYSTEM.INI file. Driver entries have the form:

VIDC.FOURCC=driver_filename

The VIDC key word identifies the entry as a video compression or decompression driver. The FOURCC portion is typically the four-character code used to identify the driver but it is not restricted to it. (This entry must have one to four characters and a period "."separates it from the VIDC keyword.) The driver_filename portion of the entry is the filename of the driver.

Drivers can use an OEMSETUP.INF to install this entry.

When ICM locates a driver, it first uses the driver entry with the four-character code matching the four-character code specified by the application. If that driver is not suitable, ICM ignores the four-character code in the entry and will try other VIDC entries until it finds a suitable driver.


Installable Driver Interface

The entry-point function, DriverProc, processes messages sent by the system to the driver as the result of an application call to a video compression and decompression function. For example, when an application opens a video compression and decompression driver, the system sends the specified driver a DRV_OPEN message. The driver's DriverProc function receives and processes this message. Your DriverProc should return ICERR_UNSUPPORTED for any messages that it does not handle.

Note Your driver should respond to all system messages. If supplemental information is not provided for them in this section, use the definitions provided in the Microsoft Win32 Programmer's Reference.


Handling the DRV_OPEN and DRV_CLOSE Messages

Like other installable drivers, client applications must open a video compression and decompression driver before using it, and they must close it when finished using it so the driver will be available to other applications. When a driver receives an open request, it returns a value that the system will use for dwDriverID sent with subsequent messages. When your driver receives other messages, it can use this value to identify instance data needed for operation. Your drivers can use this data to maintain information related to the client that opened the driver.

Compression and decompression drivers should support more than one client simultaneously. If you do this, though, remember to check the dwDriverID parameter to determine which client is being accessed.

If the driver is opened for configuration by the Drivers option of the Control Panel, lParam2 contains zero. When opened this way, your driver should respond to the DRV_CONFIGURE and DRV_QUERYCONFIGURE messages.

If opened for compression or decompression services, lParam2 contains a far pointer to an ICOPEN data structure. The fccType member of ICOPEN specifies a four-character code representing the type of stream being compressed or decompressed. For video streams, this will be 'vidc'.

Because video capture drivers can rely on video compression and decompression drivers for efficient operation, a single driver can handle both video capture, and video compression and decompression services. Video capture drivers use the VIDEO_OPEN_PARMS data structure when it is opened. This structure has the same member definitions as the ICOPEN structure. By examining the fccType member, a combined driver can determine whether it is being opened as a video capture driver or a video compression and decompression driver. Video capture devices contain the four-character code 'vcap' in this member. For more information on video capture drivers, see .

Other drivers that require close coordination with video compression and decompression drivers can also be combined with video compression and decompression drivers if they use a similar interface.

The fccHandler member of ICOPEN specifies a four-character code identifying a specific compressor. The client-application obtains the four-character code from the entry in the SYSTEM.INI file used to open your driver. Your driver should not fail the open if it does not recognize the four-character code.

The dwVersion member of ICOPEN specifies the version of the compressor interface used to open the driver. Your driver can use this information to determine the capabilities of the system software when future versions of it are available.

The dwFlags member of ICOPEN contains a constant indicating the function of the driver. The following functions are defined for video compression drivers: compressing data, decompressing data, interrogation, and decompressing and draw directly to hardware.

The ICMODE_COMPRESS, ICMODE_DECOMPRESS, and ICMODE_DRAW flags indicate your driver is opened to compress or decompress data. Depending on the flag, your driver should prepare to handle ICM_COMPRESS, ICM_DECOMPRESS, ICM_DECOMPRESSEX, or ICM_DRAW messages. Your driver should also prepare to handle all messages used to configure and interrogate your driver.

The ICMODE_QUERY flag indicates your driver is opened to obtain information. It should prepare to handle the ICM_ABOUT, ICM_GETINFO, and ICM_GETDEFAULTQUALITY messages.


Compressor Configuration

Video compression and decompression drivers can receive a series of configuration messages. System configuration messages are typically sent by the Drivers option of the Control Panel to configure the hardware. Video compression and decompression specific configuration messages are typically initiated by the client-application or from dialog boxes displayed by your driver. Your driver should use these messages to configure the driver.

Configuration Messages Sent by the System

Installable drivers can supply a configuration dialog box for users to access through the Drivers option in the Control Panel. If your driver supports different options, it should allow user configuration. Any hardware-related settings should be stored in a section with the same name as the driver in the user's SYSTEM.INI file.

Like other installable drivers, your driver will receive DRV_CONFIGURE and DRV_QUERYCONFIGURE messages from the Drivers option of the Control Panel. If your driver controls hardware that needs to be configured, it should return a nonzero value for the DRV_QUERYCONFIGURE system message and display a hardware configuration dialog box for the DRV_CONFIGURE system message.

Messages for Configuring the Driver State

The video compression and decompression specific configuration messages are typically initiated by the client-application or from dialog boxes displayed by your driver. Your driver should use these messages to configure the driver.

If your driver is configurable, it should support the ICM_CONFIGURE message for driver configuration. In addition, it should also use this message to set parameters for compression or decompression. Any options the user selects in the dialog box displayed for ICM_CONFIGURE should be saved as part of the state information referenced by the ICM_GETSTATE and ICM_SETSTATE messages.

The ICM_GETSTATE and ICM_SETSTATE messages query and set the internal state of your compression or decompression driver. State information is device dependent and your driver must define its own data structure for it. While the client-application reserves a memory block for the information, it will obtain the size needed for the memory block from your driver. If your driver receives ICM_GETSTATE with a NULL pointer for dwParam1, the client-application is requesting that your driver return the size of its state information. Conversely, if your driver receives ICM_GETSTATE with dwParam1 pointing to a block of memory, and dwParam2 specifying the size of the memory block, the client-application is requesting that your driver transfer the state information to the memory block.

When your driver receives ICM_SETSTATE with dwParam1 pointing to a block of memory, and dwParam2 specifying the size of the memory block, the client-application is requesting that your driver restore its configuration from the state information contained in the memory block. Before setting the state, your driver should verify the state information applies to your driver. One technique for verifying the data is to reserve the first DWORD in the state data structure for the four-character code used to identify your driver. If you set this DWORD for data returned for ICM_GETSTATE, you can use it to verify the data supplied with ICM_SETSTATE. If ICM_SETSTATE has a NULL pointer for dwParam1, it indicates that your driver should return to its default state.

State information should not contain any data that is absolutely required for data decompression-any such data should be part of the format you return for the ICM_DECOMPRESS_GET_FORMAT message. For information on the ICM_DECOMPRESS_GET_FORMAT message, see .

Messages Used to Interrogate the Driver

The client-application sends the ICM_ABOUT message to display your driver's about box. If the client-application sets dwParam1 to -1, it wants to know if your driver supports display of an about box. Your driver returns ICERR_OK if it does, and it returns ICERR_UNSUPPORTED if it does not. Your driver should only display an about box if the client-application specifies a window handle in dwParam1. The window handle indicates the parent of the dialog box.

The client-application uses the ICM_GETINFO message to obtain a description of your driver. Your driver should respond to this message by filling in the ICINFO structure it receives with the message. The flags your driver sets in the structure tells the client-application what capabilities the driver supports.


Configuration Messages for Compression Quality

For the video compression and decompression interface, quality is indicated by an integer ranging from zero to 10,000. A quality level of 7,500 typically indicates an acceptable image quality. A quality level of zero typically indicates a very low quality level (possibly even a totally black image). As the quality level moves from an acceptable level to low quality, the image might have a loss of color as the colors in the color table are merged, or as the color resolution of each pixel decreases. If your driver supports temporal compression (it needs information from the previous frame to decompress the current frame), low and high quality might imply how much this type of compression can degrade image quality. For example, your driver might limit the compression of a high quality image to preserve sharp detail and color fidelity. Conversely, your driver might sacrifice these qualities to obtain very compressed output files.

If your driver supports quality values, it maps the values to its internal definitions used by the compression algorithms. Thus, the definition of image quality will vary from driver to driver, and, quite possibly, from compression algorithm to compression algorithm. Even though the values are not definitive, your driver should support as many individual values as possible.

The client-application obtains the capabilities for compression quality with the ICM_GETDEFAULTQUALITY and ICM_GETQUALITY messages. If your driver supports quality levels, it should respond to the ICM_GETDEFAULTQUALITY message by returning a value between zero and 10,000 that corresponds to a good default quality level for your compressor. Your should return the current quality level for the ICM_GETQUALITY message.

The client-application sends the ICM_SETQUALITY message to set the quality level of your driver. Your driver should pass the quality value directly to the compression routine.

If your driver supports quality levels, it should set the VIDCF_QUALITY flag when it responds to the ICM_GETINFO message.


Configuration Messages for Key Frame Rate and Buffer Queue

The client-application uses ICM_GETDEFAULTKEYFRAMERATE to obtain the drivers recommendation for the key frame spacing for compressing data. (A key frame is a frame in a video sequence that does not require information from a previous frame for decompression.) If the client-application does not specify another value, this value determines how frequently the client-application sends an uncompressed image to your driver with the ICM_COMPRESS_KEYFRAME flag set. If your driver supports this option, it should specify the key frame rate in the DWORD pointed to by dwParam1 and return ICERR_OK. If it does not support this option, return ICERR_UNSUPPORTED.

The client-application uses ICM_GETBUFFERSWANTED to determine if your driver wants to maintain a queue of buffers. Your driver might maintain a queue of buffers if it renders the decompressed data and it wants to keep its hardware pipelines full. If your driver supports this option, it should specify the number of buffers in the DWORD pointed to by dwParam1 and return ICERR_OK. If it does not support this option, return ICERR_UNSUPPORTED.


Video Compression and Decompression Messages

This driver specific messages for video compression and decompression drivers are covered by the three basic operations of these drivers: video compression, video decompression using the client-application, and video decompression directly to video hardware. Because video compression and decompression drivers typically use AVI files and bitmaps, this section includes a brief overview of the AVI RIFF format, the BITMAPINFO data structure, and the BITMAPINFOHEADER data structure.


About the AVI File Format

Many of the video compression and decompression messages rely on information embedded in the AVI RIFF file. Drivers do not typically access this information directly. They rely on the client-application to read and write the AVI file and maintain the RIFF file structure. While your driver should not have to manipulate an AVI file, understanding its structure helps identify the purpose of the information your driver will supply and receive.

AVI files have the following general structure:

RIFF('AVI'
    LIST('hdrl'
        avih(<<MainAVIHeader>>)
         LIST ('strl'
            strh(<<Stream header>>)
            strf(<<Stream format>>)
            strd(<<Stream data>>)
            strn(<<Stream name>>)
        )
    )

    LIST('movi'
     '00??'(<<driver Data>>)
        .
        .
        .
    '00??'(<<driver Data>>)
    )
   ' idx1'(<<AVIIndex>>)
)

The following table summarizes the entries in the AVI file:

RIFF Chunk | Description
RIFF 'AVI ' | Identifies the file as AVI RIFF file.
LIST 'hdrl' | Identifies a chunk containing subchunks that define the format of the data.
'avih' | Identifies a chunk containing general information about the file. This includes the number of streams and the width and height of the AVI sequence.
LIST 'strl' | Identifies a chunk containing subchunks that describe the streams in a file. This chunk exists for each stream.
'strh' | Identifies a chunk containing a stream header. This includes the type of stream.
'strf' | Identifies a chunk describing the format of the data in the stream. For video streams, the information in this chunk is a BITMAPINFO structure. It includes palette information if appropriate.
'strd' | Identifies a chunk containing information used by compressor and decompressors. For video compressors and decompressors, this includes the state formation.
'strn' | Identifies a chunk containing a zero-terminated string specifying the name of the stream.
LIST 'movi ' | Identifies a chunk containing subchunks used for the audio and video data.
'00??' | Identifies a chunk containing the audio or video data. For this example, both the zeros (00) and the question marks (??) are used as place holders. The zeros are replaced by stream numbers. The question marks are replaced by codes indicating the type of data in the chunk. For example, a stream for a compressed DIB might use '01dc'.
'idx1' | Identifies a chunk containing the file index.

Video compression and decompression drivers operate on the information in the 'strf', 'strd', and 'oo??' chunks.


Identifying Compression Formats

The BITMAPINFO data structure defined by Windows is used with many of the compression and decompression messages to pass information about the bitmaps being compressed and decompressed. This structure has the following members:

typedef struct tagBITMAPINFO {
     BITMAPINFOHEADER bmiHeader;  // BITMAPINFOHEADER data
     RGBQUAD bmiColors[];         // Color table
 } BITMAPINFO;

The bmiColors member is used for the color table. The BITMAPINFOHEADER data defined for the bmiHeader member is used to pass information about the format of the bitmaps being compressed and decompressed. This structure has the following members:

typedef struct tagBITMAPINFOHEADER {
     DWORD biSize;           // Structure size
     LONG  biWidth;          // Width of the bitmap
     LONG  biHeight;         // Heifht of the bitmap
     WORD  biPlanes;         // Planes of the target device
     WORD  biBitCount;       // Number of bits per pixel
     DWORD biCompression;    // Compression type
     DWORD biSizeImage;      // Bytes contained in the image
     LONG  biXPelsPerMeter;  // Horizontal resolution
     LONG  biYPelsPerMeter;  // Vertical resolutioni
     DWORD biClrUsed;        // Number of color indexes
     DWORD biClrImportant;   // Number of important colors
 } BITMAPINFOHEADER;

The biCompression member specifies the type of compression used or requested. Windows defines the following compression formats:

Format | Description
BI_RGB | Specifies the bitmap is not compressed.
BI_RLE8 | Specifies a run-length encoded format for bitmaps with 8 bits per pixel.
BI_RLE4 | Specifies a run-length encoded format for bitmaps with 4 bits per pixel.

Video for Windows extends the BI_RGB format to include 16 and 32 bits per pixel bitmap formats. These formats do not use a color table. They embed the colors in the WORD or DWORD representing each pixel.

The 16 bit BI_RGB format is identified by setting biCompression to BI_RGB and setting biBitCount to 16. For this format, each pixel is represented by a 16-bit RGB color value. The high-bit of this value is zero. The remaining bits are divided into 3 groups of 5-bits to represent the red, green, and blue color values.

The 32 bit BI_RGB format is identified by setting biCompression to BI_RGB and setting biBitCount to 32. For this format, each pixel is represented by a 32 bit (4 byte) RGB color value. One byte is used for each red, green, and blue color value. The fourth byte is set to zero.

Your driver should support the BI_RGB format for 8 bit per pixel bitmaps. If practical, it should also support this format for 16, 24, and 32 bits per pixel bitmaps.

In addition to the new BI_RGB formats, the BI_BITFIELD format adds new compression capabilities. This format specifies a bitmap is not compressed and color masks are defined in the bmiColors member of the BITMAPINFO data structure. The first DWORD in the bmiColors member is the red mask, the second DWORD is the green mask, and the third DWORD is the blue mask.

Your driver can also extend the format set by defining custom formats. Custom formats use a four character code for the format in the biCompression member in place of the standard constants. Your driver can use a custom format to support a unique or nonstandard compression type. When you define a custom format, you can specify values other than 1, 4, 8, 16, 24, or 32 for the biBitCount member.


Decompressing Video Data

The client-application sends a series of messages to your driver to coordinate decompressing video data. The coordination involves the following activities:

  • Setting the driver state
  • Specifying the input format and determining the decompression format
  • Preparing to decompress video
  • Decompressing the video
  • Ending decompression

The following messages are used by video compression and decompression drivers for these decompression activities:

Message | Description
ICM_DECOMPRESS | Decompresses a frame of data into a buffer provided by the client-application.
ICM_DECOMPRESS_BEGIN | Prepare a driver for decompressing data.
ICM_DECOMPRESS_END | Cleans up after decompressing.
ICM_DECOMPRESS_GET_FORMAT | Obtains a suggestion for a good format for the decompressed data.
ICM_DECOMPRESS_QUERY | Determines if a driver can decompress a specific input format.
ICM_DECOMPRESS_GET_PALETTE | Returns the color table of the output data structure.

The video decompressed with these messages is returned to the client-application and it handles the display of data. If you want your driver to control the video timing or directly update the display, use the ICM_DRAW messages explained in "Decompressing Directly to Video Hardware." If you return the decompressed video to the client-application, your driver can decompress data using either software or hardware with the ICM_DECOMPRESS messages.


Setting the Driver State

The client-application restores the driver state by sending ICM_SETSTATE. The client-application recalls the state information from the strd' data chunk of the AVI file. (The information was originally obtained with the ICM_GETSTATE message.) The client-application does not validate any data in the state information. It simply transfers the state information it reads from the 'strd' data chunk to your driver.

The client-application sends the information to your driver in a buffer pointed to by dwParam1. The size of the buffer is specified in dwParam2. The organization of the data in the buffer is driver dependent. If dwParam1 is NULL, your driver should return to its default state.

Note All information required for decompressing the image data should be part of the format data. Only optional compression parameters can be included with the state information.


Specifying the Input Format and Determining the Decompression Format

Depending on how the client-application will use the decompressed data, it will send either ICM_DECOMPRESS_GET_FORMAT or ICM_DECOMPRESS_QUERY to specify the input format and determine the decompression format. The client-application sends ICM_DECOMPRESS_GET_FORMAT if it wants your driver to suggest the decompressed format. The client-application sends ICM_DECOMPRESS_QUERY to determine if your driver supports a format it is suggesting.

Both messages send a pointer to a BITMAPINFO data structure in dwParam1. This structure specifies the format of the incoming compressed data. The input format was obtained by the client-application from the 'strf' chunk in the AVI file. While the output format is specified by dwParam2, your driver must use the message to determine how the parameter is defined.

If your driver gets ICM_DECOMPRESS_GET_FORMAT, both dwParam1 and dwParam2 point to BITMAPINFO data structures. The input format data is contained in the dwParam1 structure. Your driver should fill in the dwParam2 BITMAPINFO with information about the format it will use to decompress the data. If your driver can handle the format, return the number of bytes used for the dwParam2 structure as the return value. If your driver cannot handle the input format, or the input format from the 'strf' chunk is incorrect, your driver should return ICERR_BADFORMAT to fail the message.

If you have format information in addition to that specified in the BITMAPINFOHEADER structure, you can add it immediately after this structure. If you do this, update the biSize member to specify the number of bytes used by the structure and your additional information. If a color table is part of the BITMAPINFO information, it follows immediately after your additional information. Return ICERR_OK when your driver has finished updating the data format.

If your driver gets ICM_DECOMPRESS_QUERY, dwParam1 points to a BITMAPINFO data structure containing the input format data. The dwParam2 parameter will either be NULL or contain a pointer to a BITMAPINFO structure describing the decompressed format the client-application wants to use.

If dwParam2 is NULL, your decompression driver can use any output format. In this case, the client-application wants to know if you can decompress the input format and it doesn't care about the output format. If dwParam2 points to a BITMAPINFO structure, the suggested format will be the native or best format for the decompressed data. For example, if playback is on an 8-bit device, the client-application will suggest an 8-bit DIB.

If your driver supports the specified input and output format (which might also include stretching the image), or it supports the specified input with NULL specified for dwParam2, return ICERR_OK to indicate the driver accepts the formats.

Your driver does not have to accept the formats suggested. If you fail the message by returning ICERR_BADFORMAT, the client-application will suggest alternate formats until your driver accepts one. If your driver exhausts the list of formats normally used, the client-application requests a format with ICM_DECOMPRESS_GET_FORMAT.

If you are decompressing to 8-bit data, your driver will also receive the ICM_DECOMPRESS_GET_PALETTE message. Your driver should add a color table to the BITMAPINFO data structure and specify the number of palette entries in the biClrUsed member. The space reserved for the color table will always be 256 colors.


Preparing to Decompress Video

When the client-application is ready, it sends the ICM_DECOMPRESS_BEGIN message to the driver. The client-application sets dwParam1 and dwParam2 to the BITMAPINFO data structures describing the input and output formats. If either of the formats is incorrect, your driver should return ICERR_BADFORMAT. Your driver should create any tables and allocate any memory that it needs to decompress data efficiently. When done, return ICERR_OK.


Decompressing the Video

The client-application sends ICM_DECOMPRESS each time it has an image to decompress. The client-application uses the flags in the file index to ensure the initial frame in a decompression sequence is a key frame.

The ICDECOMPRESS data structure specified in dwParam1 contains the decompression parameters. The value specified in dwParam2 specifies the size of the structure.

The format of the input data is specified in a BITMAPINFOHEADER structure pointed to by the lpbiInput member of ICDECOMPRESS. The input data is in a buffer specified by lpInput member of ICDECOMPRESS. The lpbiOutput and lpOutput members of ICDECOMPRESS contain pointers to the format data and buffer used for the output data.

The client-application sets the ICDECOMPRESS_HURRYUP flag in the dwFlags member of ICDECOMPRESS if it wants your driver to try and decompress the data at a faster rate. The client-application will not display any data decompressed with this flag. This might let your driver avoid decompressing a frame or data, or let it minimally decompress when it needs information from this frame to prepare for decompressing a following frame.


Ending Decompression

Your driver receives ICM_DECOMPRESS_END when the client-application no longer needs data decompressed. For this message, your driver should free the resources it allocated for the ICM_DECOMPRESS_BEGIN message.


Other Messages Received During Decompression

Decompression drivers also receive the ICM_DRAW_START and ICM_DRAW_STOP messages. These messages tell the driver when the client-application starts and stops drawing the images. Most decompression drivers can ignore these messages.


Decompression Using the Extended Decompression Messages

Video for Windows 1.1 adds extended decompression capabilities. These messages let drivers decompress a frame of data directly to the screen, decompress to upside-down DIB, or decompress images described with source and destination rectangles. The following messages are used to obtain these capabilities:

Message | Description
ICM_DECOMPRESSEX | Decompresses a frame of data into a buffer provided by the client-application.
ICM_DECOMPRESSEX_BEGIN | Prepare a driver for decompressing data.
ICM_DECOMPRESSEX_END | Cleans up after decompressing.
ICM_DECOMPRESSEX_QUERY | Determines if a driver can decompress a specific input format.

These messages serve the same purpose as the ICM_DECOMPRESS messages except they use the ICDECOMPRESSEX structure. This structure contains the image input format and data, the output format and data, the source rectangle, and the destination rectangle.


Compressing Video Data

Similar to decompressing video data, your driver will receive a series of messages when it is used to compress data. The client-application will send messages to your driver to coordinate the following activities:

  • Obtaining the driver state
  • Specifying the input format and determining the compression format
  • Preparing to compress video
  • Compressing the video
  • Ending compression

The following messages are used by video compression drivers:

Message | Description
ICM_COMPRESS | Compresses a frame of data into the buffer provided by the client-application.
ICM_COMPRESS_BEGIN | Prepares for compressing data.
ICM_COMPRESS_END | Cleans up after compressing.
ICM_COMPRESS_GET_FORMAT | Obtains the driver's suggest the output format of the compressed data.
ICM_COMPRESS_GET_SIZE | Obtains the maximum size of one frame of data when it is compressed in the output format.
ICM_COMPRESS_QUERY | Determines if a driver can compress a specific input format.

The video compressed with these messages is returned to the client-application. When compressing data, your driver can use either software or hardware to do the compression.

Note When MSVideo recompresses a file, each frame is decompressed to a full frame before it is passed to the compressor.


Obtaining the Driver State

The client-application obtains the driver state by sending ICM_GETSTATE. The client-application determines the size of the buffer needed for the state information by sending this message with dwParam1 set to NULL. Your driver should respond to the message by returning the size of the buffer it needs for state information.

After it determines the buffer size, the client-application resends the message with dwParam1 pointing to a block of memory it allocated. The dwParam2 parameter specifies the size of the memory block. Your driver should respond by filling the memory with its state information. If your driver uses state information, include only optional decompression parameters with the state information. State information typically includes the setup specified by user with the ICM_CONFIGURE dialog box. Any information required for decompressing the image data must be included with the format data. When done, your driver should return the size of the state information.

The client-application does not validate any data in the state information. It simply stores the state information in the 'strd' data chunk of the AVI file.


Specifying the Input Format and Determining the Compression Format

The client-application uses the ICM_COMPRESS_GET_FORMAT or ICM_COMPRESS_QUERY message to specify the input format and determine the compression (output) format. The client-application sends ICM_COMPRESS_GET_FORMAT if it wants your driver to suggest the compressed format. The client-application sends ICM_COMPRESS_QUERY to determine if your driver supports a format it is suggesting.

Both messages have a pointer to a BITMAPINFO data structure in dwParam1. This structure specifies the format of the incoming uncompressed data. The contents of dwParam2 depends on the message.

If the client-application wants your driver to suggest the format, it determines the size of the buffer needed for the compressed data format by sending ICM_COMPRESS_GET_FORMAT. When requesting the buffer size, the client-application uses dwParam1 to point to a BITMAPINFO structure and sets dwParam2 to NULL. Based on the input format, your driver should return the number of bytes needed for the format buffer. Return a buffer size at least large enough to hold a BITMAPINFOHEADER data structure and a color table.

The client-application gets the output format by sending ICM_COMPRESS_GET_FORMAT with valid pointers to BITMAPINFO structures in both dwParam1 and dwParam2. Your driver should return the output format in the buffer pointed to by dwParam2. If your driver can produce multiple formats, the format selected by your driver should be the one that preserves the greatest amount of information rather than one that compresses to the most compact size. This will preserve image quality if the video data is later edited and recompressed.

The output format data becomes the 'strf' chunk in the AVI RIFF file. The data must start out like a BITMAPINFOHEADER data structure. You can include any additional information required to decompress the file after the BITMAPINFOHEADER data structure. A color table (if used) follows this information.

If you have format data following the BITMAPINFOHEADER structure, update the biSize member to specify the number of bytes used by the structure and your additional data. If a color table is part of the BITMAPINFO information, it follows immediately after your additional information.

If your driver cannot handle the input format, it returns ICMERR_BADFORMAT to fail the message.

If your driver gets ICM_COMPRESS_QUERY, the dwParam1 parameter points to a BITMAPINFO data structure containing the input format data. The dwParam2 parameter will either be NULL or contain a pointer to a BITMAPINFO structure describing the compressed format the client-application wants to use. If dwParam2 is NULL, your compression driver can use any output format. (The client-application just wants to know if your driver can handle the input.) If dwParam2 points to a BITMAPINFO structure, the client-application is suggesting the output format.

If your driver supports the specified input and output format, or it supports the specified input with NULL specified for dwParam2, return ICERR_OK to indicate the driver accepts the formats. Your driver does not have to accept the suggested format. If you fail the message by returning ICERR_BADFORMAT, the client-application suggests alternate formats until your driver accepts one. If your driver exhausts the list of formats normally used, the client-application requests a format with ICM_COMPRESS_GET_FORMAT.


Initialization for the Compression Sequence

When the client-application is ready to start compressing data, it sends the ICM_COMPRESS_BEGIN message. The client-application uses dwParam1 to point to the format of the data being compressed, and uses dwParam2 to point to the format for the compressed data. If your driver cannot handle the formats, or if they are incorrect, your driver should return ICERR_BADFORMAT to fail the message.

Before the client-application starts compressing data, it sends ICM_COMPRESS_GET_SIZE. For this message the client-application uses dwParam1 to point to the input format and uses dwParam2 to point to the output format. Your driver should return the worst case size (in bytes) that it expects a compressed frame to occupy. The client-application uses this size value when it allocates buffers for the compressed video frame.


Compressing the Video

The client-application sends ICM_COMPRESS for each frame it wants compressed. It uses dwParam1 to point to an ICCOMPRESS structure containing the parameters used for compression. Your driver uses the buffers pointed to by the members of ICCOMPRESS for returning information about the compressed data.

Your driver returns the actual size of the compressed data in the biSizeImage member in the BITMAPINFOHEADER data structure pointed to by the lpbiOutput member of ICCOMPRESS.

The format of the input data is specified in a BITMAPINFOHEADER structure pointed to by the lpbiInput member of ICDECOMPRESS. The input data is in a buffer specified by the lpInput member. The lpbiOutput and lpOutput members contain pointers to the format data and buffer used for the output data. Your driver must indicate the size of the compressed video data in the biSizeImage member in the BITMAPINFO structure specified for lpbiOutput.

The dwFlags member specifies flags used for compression. The client-application sets ICM_COMPRESS_KEYFRAME flag if the input data should be treated as a key frame. (A key frame is one that does not require data from a previous frame for decompression.) When this flag is set, your driver should treat the image as the initial image in a sequence.

The lpckid member specifies a pointer to a buffer used to return the chunk ID for data in the AVI file. Your driver should assign a two-character code for the chunk ID only if it uses a custom chunk ID.

The lpdwFlags member specifies a pointer to a buffer used to return flags for the AVI index. The client-application will add the returned flags to the file index for this chunk. If the compressed frame is a key frame (a frame that does not require a previous frame for decompression), your driver should set the AVIIF_KEYFRAME flag in this member. Your driver can define its own flags but they must be set in the high word only.

The lFrameNum member specifies the frame number of the frame to compress. If your driver is performing fast temporal compression, check this member to see if frames are being sent out of order or if the client-application is having a frame recompressed.

The dwFrameSize member indicates the maximum size (in bytes) desired for the compressed frame. If it specifies zero, your driver determines the size of the compressed image. If it is nonzero, your driver should try to compress the frame to within the specified size. This might require your driver to sacrifice image quality (or make some other trade-off) to obtain the size goal. Your driver should support this if it sets the VIDCF_CRUNCH flag when it responds to the ICM_GETINFO message.

The dwQuality member specifies the compression quality. Your driver should support this if it sets the VIDCF_QUALITY flag when it responds to the ICM_GETINFO message.

The format of the previous data is specified in a BITMAPINFOHEADER structure pointed to by lpbiPrev. The input data is in a buffer specified by lpPrev. Your driver will use this information if it performs temporal compression (that is, it needs the previous frame to compress the current frame). If your driver supports temporal compression, it should set the VIDCF_TEMPORAL flag when it responds to the ICM_GETINFO message. If your driver supports temporal compression and does not need the information in the lpbiPrev and lpPrev members, it should set the VIDCF_FASTTEMPORALC flag when it responds to the ICM_GETINFO message. The VIDCF_FASTEMPORALC flag can decrease the processing time because your driver does not need to access data specified in lpbiPrev and lpPrev.

When your driver has finished compressing the data, it returns ICERR_OK.


Ending Compression

Your driver receives ICM_COMPRESS_END when the client-application no longer needs data compressed, or when the client-application is changing the format or palette. After sending ICM_COMPRESS_END, the client-application must send ICM_COMPRESS_BEGIN to continue compressing data. Your driver should not expect the client-application to send a ICM_COMPRESS_END message for each ICM_COMPRESS_BEGIN message. The client-application can use ICM_COMPRESS_BEGIN to restart compression without sending ICM_COMPRESS_END.

When the driver is no longer needed, the system will close it by sending DRV_CLOSE.


Decompressing Directly to Video Hardware

Drivers that can render video directly to hardware should support the ICM_DRAW messages in addition to the ICM_DECOMPRESS messages. The ICM_DRAW messages decompress data directly to hardware rather than into a data buffer returned to the client-application by the decompression driver.

Your driver will receive a series of messages from the client-application to coordinate the following activities to decompress a video sequence:

  • Setting the driver state
  • Specifying the input format
  • Preparing to decompress video
  • Decompressing the video
  • Ending decompression

The following ICM_DRAW messages are used by video decompression drivers for these decompression activities:

Message | Description
ICM_DRAW | Decompresses a frame of data and draws it.
ICM_DRAW_BEGIN | Prepares to draw data.
ICM_DRAW_END | Clean up after decompressing an image to the screen.
ICM_DRAW_REALIZE | Realizes a palette.
ICM_DRAW_QUERY | Determines if the driver can render data in a specific format.
ICM_DRAW_SUGGESTFORMAT | Has the driver suggest and output format.

The video decompressed with the ICM_DRAW messages is retained by your driver and it handles the display of data. These messages control only the decompression process. The messages used to control the drawing are described separately. Your driver will receive the ICM_DRAW messages only if it sets the VIDCF_DRAW flag when it responds to the ICM_GETINFO message.


Setting the Driver State

The client-application restores the driver state by sending ICM_SETSTATE. The process for handling this message is the same as for the ICM_DECOMPRESS messages.


Specifying the Input and Output Formats

Because your driver handles the drawing of video, the client-application does not need to determine the output format. The client-application needs to know only if your driver can handle the input format. It sends ICM_DRAW_QUERY to determine if your driver supports the input format. The input format is specified with a pointer to a BITMAPINFO data structure in dwParam1. The dwParam2 parameter is not used.

If your driver supports the specified input format, return ICERR_OK to indicate the driver accepts the formats. If your driver does not support the format, return ICERR_BADFORMAT.

Your driver might also receive the ICM_DRAW_SUGGESTFORMAT message. Typically, this message is sent by the decompression portion of the driver to the drawing portion of the driver to obtain the best decompressed format for the data when the drawing portion can handle several formats. The dwParam1 parameter of ICM_DRAW_SUGGESTFORMAT points to a ICDRAWSUGGEST structure and the dwParam2 parameter specifies its size.

If returning format information, return ICERR_OK. If the lpbiSuggest member is NULL, return the amount of memory required for the suggested output format structure.


Preparing to Decompress Video

When the client-application is ready, it sends the ICM_DRAW_BEGIN message to the driver to prepare the driver for decompressing the video stream. Your driver should create any tables and allocate any memory that it needs to decompress data efficiently.

The client-application sets dwParam1 to the ICDRAWBEGIN data structure. The size of this structure is contained in dwParam2.

If the ICDRAW_QUERY flag is set in the dwFlags member, the client-application is interrogating your driver to determine if can decompress the data with the parameters specified in the ICDRAWBEGIN data structure. Your driver should return ICM_ERR_OK if it can accept the parameters. It should return ICM_ERR_NOTSUPPORTED if it does not accept them.

When the ICDRAW_QUERY flag is set, ICM_DRAW_BEGIN will not be paired with ICM_DRAW_END. Your driver will receive another ICM_DRAW_BEGIN without this flag to start the actual decompression sequence.

Your driver can ignore the palette handle specified in the hpal member.

The hwnd and hdc member specifies the handle of the window and DC used for drawing. These members are valid only if the ICDRAW_HDC flag is set in the dwFlags member.

The xDst and yDst members specify the x- and y-position of the upper-right corner of the destination rectangle. (This is relative to the current window or display context.) The dxDst and dyDst members specifies the width and height of the destination rectangle. These members are valid only if ICDRAW_HDC flag is set. The ICDRAW_FULLSCREEN flag indicates the entire screen should be used for display and overrides any values specified for these members.

The xSrc, ySrc, dxSrc, and dySrc members specify a source rectangle used to clip the frames of the video sequence. The source rectangle is stretched to fill the destination rectangle. The xSrc and ySrc members specify x- and y-position of the upper-right corner of the source rectangle. (This is relative to a full frame image of the video.) The dxSrc and dySrc members specify the width and height of the source rectangle.

Your driver should stretch the image from the source rectangle to fit the destination rectangle. If the client-application changes the size of the source and destination rectangles, it will send the ICM_DRAW_END message and specify new rectangles with a new ICM_DRAW_BEGIN message. For more information on handling the source and destination rectangles, see the Microsoft(r) Win32(tm) Programmer's Reference.

The lpbi member specifies a pointer to a BITMAPINFOHEADER data structure containing the input format.

The dwRate member specifies the decompression rate in an integer format. To obtain the rate in frames-per-second divide this value by the value in dwScale. Your driver will use these values when it handles the ICM_DRAW_START message.

If your driver can decompress the data with the parameters specified in the ICDRAWBEGIN data structure, your driver should return ICERR_OK and allocate any resources it needs to efficiently decompress the data. If your driver cannot decompress the data with the parameters specified, your driver should fail the message by returning ICERR_NOTSUPPORTED. When this message fails, your driver will not get an ICM_DRAW_END message so it should not prepare its resources for other ICM_DRAW messages.


Decompressing the Video

The client-application sends ICM_DRAW each time it has an image to decompress. (Your driver should use this message to decompress images. It should wait for the ICM_DRAW_START message before it begins to render them.) The client-application uses the flags in the file index to ensure the first frame in a series of frames decompressed starts with a key frame boundary. Your driver must allocate the memory it needs for the decompressed image.

The ICDRAW data structure specified in dwParam1 contains the decompression parameters. The value specified in dwParam2 specifies the size of the structure.

The format of the input data is specified in a BITMAPINFOHEADER structure pointed to by lpFormat member. The input data is in a buffer specified by the lpData member. The number of bytes in the input buffer is specified by the cbData member.

The client-application sets the ICDRAW_HURRYUP flag in the dwFlags member when it wants your driver to try to decompress data at a faster rate. For example, the client-application might use this flag when the video is starting to lag behind the audio. If your driver cannot speed up its decompression and rendering performance, it might be necessary to avoid rendering a frame of data. The client-application sets the ICDRAW_UPDATE flag and sets lpData to NULL if it wants your driver to update the screen based on data previously received.

When your driver has finished decompressing the data, it returns ICERR_OK. After the driver returns from this message, the client-application deallocates or reuses the memory containing the format and image data. If your driver needs the format or image data for future use, it should copy the data it needs before it returns from the message.


Ending Decompression

Your driver receives ICM_DRAW_END when the client-application no longer needs data decompressed or rendered. For this message, your driver should free the resources it allocated for the ICM_DRAW_BEGIN message. Your driver should also leave the display in the full screen mode.

After sending ICM_DRAW_END, the client-application must send ICM_DRAW_BEGIN to continue decompressing data. Your driver should not expect the client-application to send a ICM_DRAW_END message for each ICM_DRAW_BEGIN message. The client-application can use ICM_DRAW_BEGIN to restart decompression without sending ICM_DRAW_END.


Rendering the Data

The client-application sends the following messages to control the driver's internal clock for rendering the decompressed data:

Message | Description
ICM_DRAW_GETTIME | Obtains the value of the driver's internal clock if it is handling the timing of drawing frames.
ICM_DRAW_SETTIME | Sets the driver's internal clock if it is handling the timing of drawing frames.
ICM_DRAW_START | Starts the internal clock of a driver if it handles the timing of drawing frames.
ICM_DRAW_STOP | Stop the internal clock of a driver if it handles the timing of drawing frames.
ICM_DRAW_WINDOW | Informs the driver the display window has been moved, hidden, or displayed.
ICM_DRAW_FLUSH | Flushes any frames that are waiting to be drawn.
ICM_DRAW_RENDERBUFFER | Draws a frame waiting to be drawn.
ICM_DRAW_UPDATE | Redraws the image currently displayed.
ICM_DRAW_CHANGEPALETTE | Changes the palette.

The client-application sends ICM_DRAW_START to have your driver start (or continue) rendering data at the rate specified by the ICM_DRAW_BEGIN message. The ICM_DRAW_STOP message pauses the internal clock. Neither of these messages use dwParam1, dwParam2, or a return value.

The client-application uses ICM_DRAW_GETTIME to obtain the value of the internal clock. Your driver returns the current time value (this is normally frame numbers for video) in the DWORD indicated by the pointer specified by dwParam1. The current time is relative to the start of drawing.

The client-application uses ICM_DRAW_SETTIME to set the value of the internal clock. Typically, the client-application uses this message to synchronize the driver's clock to an external clock. Your driver should set its clock to the value (this is normally frame numbers for video) specified in the DWORD pointed to by dwParam1.

The client-application sends ICM_DRAW_FLUSH to have your driver discard any frames that have not been drawn.

The client-application sends ICM_DRAW_RENDERBUFFER to have your driver draw the image currently buffered.

The client-application sends ICM_DRAW_UPDATE to have your driver redraw an image.

The client-application sends ICM_DRAW_CHANGEPALETTE when the palette changes in the movie.


Notifying Applications of Compression and Decompression Status

A client-application sends the ICM_SET_STATUS_PROC message if it wants to receive notification messages about the progress of compression or decompression. When received, drivers should periodically send notification messages to the callback function specified with the message during compression or decompression. Support of this callback function is optional but highly recommended if compression or decompression takes longer than approximately one tenth of one second. The callback function prototype statement follows:

LONG MyStatusProc(LPARAM lParam, UINT message)

The lParam parameter specifies the constant specified in the lParam member of the ICSETSTATUSPROC structure.The message parameter specifies one of the following messages the driver sends:

Message | Description
ICSTATUS_START | Indicates the operation is starting.
ICSTATUS_STATUS | Indicates the operation is proceeding, and is l percent done.
ICSTATUS_END | Indicates the operation is finishing.
ICSTATUS_YIELD | Indicates a length operation is proceeding.


Using Installable Compressors for Non-video Data

Installable compressors are not necessarily limited to video data. By using a different value than 'vidc' in the fccType member, you can specify that your installable driver expects to handle a type of data that is not video. (Four-character codes for non-video data should also be registered. For information about registering four-character codes, see .

While VidEdit does not support data that is not audio or video, MCIAVI does provide limited support for other data types using installable renderers. If you create a stream with a four-character code type that does not represent audio or video, its type and handler information will be used to search for a driver capable of handling the data. The search will follow the same procedure used for installable compressor drivers.

Writing a driver to render non-video data is very similar to rendering video, with the following differences:

  • The format used is not a BITMAPINFO structure. The format is defined by the class of decompressor.
  • The ICM_DECOMPRESS messages are not used. All data is rendered using the ICM_DRAW messages because there is no defined decompressed form for arbitrary data.


Testing Video Compression and Decompression Drivers

You can exercise both the compression and decompression capabilities of a driver with the VidEdit editing tool. You can also exercise the decompression capabilities of a driver with MCIAVI. (One way to test the decompression capabilities is to preview an unedited file in VidEdit. For this function, VidEdit uses MCIAVI to decompress the file.)


Reference

This section is a reference to the messages and data structures provided by Windows 95 for use by video compression and decompression drivers. There are separate sections for messages and data structures.

Windows communicates with video compression and decompression drivers through messages sent to the driver. The driver processes these messages with its DriverProc entry-point function.

A message consists of three parts: a message number and two DWORD parameters. Message numbers are identified by predefined message names. The two DWORD parameters contain message-dependent values.

The following messages are used by video compression and decompression drivers for compressing data:

Functionality | Messages and Structures to Use
Open a video compression and decompression driver | DRV_OPEN, ICOPEN
Configure driver state | ICM_CONFIGURE, ICM_GETSTATE, ICM_SETSTATE
Interrogate driver | ICM_ABOUT, ICM_GETINFO, ICINFO
Configure compression quality | ICM_GETDEFAULTQUALITY, ICM_GETINFO, ICM_GETQUALITY, ICM_SETQUALITY
Determine key frame rate and buffer queue requirements | ICM_GETDEFAULTKEYFRAMERATE, ICM_COMPRESS_KEYFRAME, ICM_GETBUFFERSWANTED
Specify decompression input format and determine decompression format | ICM_DECOMPRESS_GET_FORMAT, ICM_DECOMPRESS_QUERY, ICM_DECOMPRESS_GET_PALETTE
Decompress data | ICM_DECOMPRESS, ICM_DECOMPRESS_BEGIN, ICM_DECOMPRESS_END, ICDECOMPRESS
Decompress using extended decompression messages | ICM_DECOMPRESSEX, ICM_DECOMPRESSEX_BEGIN, ICM_DECOMPRESSEX_END, ICM_DECOMPRESSEX_QUERY, ICDECOMPRESSEX
Specify compression input format and determine compressed format | ICM_COMPRESS_GET_FORMAT, ICM_COMPRESS_QUERY, ICM_COMPRESS_GET_SIZE
Compress data | ICM_COMPRESS, ICM_COMPRESS_BEGIN, ICM_COMPRESS_END, ICCOMPRESS
Specify decompression input/output formats for drawing data | ICM_DRAW_QUERY, ICM_DRAW_SUGGESTFORMAT, ICDRAWSUGGEST
Decompress data for drawing directly to screen | ICM_DRAW, ICM_DRAW_BEGIN, ICM_DRAW_END, ICDRAW, ICDRAWBEGIN
Rendering data directly to screen | ICM_DRAW_CHANGEPALETTE, ICM_DRAW_GETTIME, ICM_DRAW_SETTIME, ICM_DRAW_START, ICM_DRAW_STOP, ICM_DRAW_FLUSH, ICM_DRAW_RENDERBUFFER, ICM_DRAW_UPDATE, ICM_DRAW_WINDOW
Notify applications of compression/decompression status | ICM_SET_STATUS_PROC, ICSETSTATUSPROC


DRV_OPEN

System message that notifies a video compression driver each time it is opened.

  • Return zero to fail the call. A nonzero value is sent to the driver in the ID field each time DriverProc is sent a message with DrvSendMessage or DrvClose.
dwDriverIdentifier
Handle returned to the application opening the driver.
hDriver
Handle created by the system. This handle is returned to the application. A unique handle is created each time the driver is opened.
lParam1
Address of a zero-terminated string. The string contains any characters that follow the filename in the SYSTEM.INI file. If the device driver was opened by filename, or if there is no additional information, a NULL string or a NULL pointer is specified. Device drivers should verify that lParam1 is not NULL before dereferencing it.
lParam2
Address of an ICOPEN structure, or zero if the driver is opened only for configuration by the Multimedia property sheet of the Control Panel. If an ICOPEN structure is specified, the driver should verify the fccType member contains 'vidc'. This indicates the driver is opened as a video compressor.


ICM_ABOUT

wParam = (DWORD) (UINT) hwnd;
lParam = 0;

Notifies a video compression driver to display its About dialog box or queries a video compression driver to determine if it has an About dialog box.

  • Returns ICERR_OK if the driver supports this message or ICERR_UNSUPPORTED otherwise.
wParam
Handle of the parent window of the displayed dialog box.

You can also determine if a driver has an About dialog box by specifying -1 in this parameter, as in ICQueryAbout. The driver returns ICERR_OK if it has an About dialog box or ICERR_UNSUPPORTED otherwise.


ICM_COMPRESS

wParam = (DWORD) (LPVOID) &icc;
lParam = sizeof(ICCOMPRESS);

Notifies a video compression driver to compress a frame of data into an application-supplied buffer.

  • Returns ICERR_OK if successful or an error code otherwise.
wParam
Address of an ICCOMPRESS structure. The following members of ICCOMPRESS specify the compression parameters: lpbiInput, lpInput, lpbiOutput, lpOutput, lpbiPrev, lpPrev, lpckid, lpdwFlags, dwFrameSize, and dwQuality.

The driver should also use the biSizeImage member of the BITMAPINFOHEADER structure associated with lpbiOutput of ICCOMPRESS to return the size of the compressed frame.

lParam
Size, in bytes, of the ICCOMPRESS structure.

See Also

ICM_COMPRESS_BEGIN, ICM_COMPRESS_END, ICM_DECOMPRESS, ICM_DRAW


ICM_COMPRESS_BEGIN

wParam = (DWORD) (LPVOID) lpbiInput;
lParam = (DWORD) (LPVOID) lpbiOutput;

Notifies a video compression driver to prepare to compress data.

  • Returns ICERR_OK if the specified compression is supported or ICERR_BADFORMAT if the input or output format is not supported.
wParam
Address of a BITMAPINFO structure indicating the input format.
lParam
Address of a BITMAPINFO structure indicating the output format.

The driver should allocate and initialize any tables or memory that it needs for compressing the data formats when it receives the ICM_COMPRESS message.

VCM saves the settings of the most recent ICM_COMPRESS_BEGIN message. ICM_COMPRESS_BEGIN and ICM_COMPRESS_END do not nest. If your driver receives an ICM_COMPRESS_BEGIN message before compression is stopped with ICM_COMPRESS_END, it should restart compression with new parameters.

See Also

ICM_COMPRESS, ICM_COMPRESS_END, ICM_DECOMPRESS_BEGIN, ICM_DRAW_BEGIN


ICM_COMPRESS_END

wParam = 0;
lParam = 0;

Notifies a video compression driver to end compression and free resources allocated for compression.

  • Returns ICERR_OK if successful or an error otherwise.

VCM saves the settings of the most recent ICM_COMPRESS_BEGIN message. ICM_COMPRESS_BEGIN and ICM_COMPRESS_END do not nest. If your driver receives an ICM_COMPRESS_BEGIN message before compression is stopped with ICM_COMPRESS_END, it should restart compression with new parameters.

See Also

ICM_COMPRESS, ICM_COMPRESS_BEGIN, ICM_DECOMPRESS_END, ICM_DRAW_END


ICM_COMPRESS_FRAMES_INFO

wParam = (DWORD) (LPVOID) &icf;
lParam = sizeof(ICCOMPRESSFRAMES);

Notifies a compression driver to set the parameters for the pending compression.

  • Returns ICERR_OK if successful or an error otherwise.
wParam
Address of an ICCOMPRESSFRAMES structure. The GetData and PutData members of ICCOMPRESSFRAMES are not used with this message.
lParam
Size of the ICCOMPRESSFRAMES structure referenced by wParam.

A compressor can use this message to determine how much space to allocate for each frame while compressing.

See Also

ICCOMPRESSFRAMES, ICM_COMPRESS_BEGIN


ICM_COMPRESS_GET_FORMAT

See also ICM_COMPRESS_QUERY, ICM_DECOMPRESS_GET_FORMAT

wParam = (DWORD) (LPVOID) lpbiInput;
lParam = (DWORD) (LPVOID) lpbiOutput;

Requests the output format of the compressed data from a video compression driver.

  • Returns ICERR_OK if successful or an error otherwise.
wParam
Address of a BITMAPINFO structure indicating the input format.
lParam
Address of a BITMAPINFO structure to return the output format. You can specify zero for this parameter to request only the size of the output format.

If lParam is nonzero, the driver should fill the BITMAPINFO structure with the default output format corresponding to the input format specified for wParam. If the compressor can produce several formats, the default format should be the one that preserves the greatest amount of information.


ICM_COMPRESS_GET_SIZE

wParam = (DWORD) (LPVOID) lpbiInput;
lParam = (DWORD) (LPVOID) lpbiOutput;

Requests that the video compression driver supply the maximum size of one frame of data when compressed into the specified output format.

  • Returns the maximum number of bytes a single compressed frame can occupy.
wParam
Address of a BITMAPINFO structure indicating the input format.
lParam
Address of a BITMAPINFO structure indicating the output format.

Typically, applications send this message to determine how large a buffer to allocate for the compressed frame.

The driver should calculate the size of the largest possible frame based on the input and output formats.

See Also

ICM_COMPRESS_GET_FORMAT, ICM_COMPRESS_QUERY


ICM_COMPRESS_QUERY

wParam = (DWORD) (LPVOID) lpbiInput;
lParam = (DWORD) (LPVOID) lpbiOutput;

Queries a video compression driver to determine if it supports a specific input format or if it can compress a specific input format to a specific output format.

  • Returns ICERR_OK if the specified compression is supported or ICERR_BADFORMAT otherwise.
wParam
Address of a BITMAPINFO structure describing the input format.
lParam
Address of a BITMAPINFO structure describing the output format. You can specify zero for this parameter to indicate any output format is acceptable.

On receiving this message, the driver should examine the BITMAPINFO structure associated with wParam to determine if it can compress the input format.

See Also

ICM_COMPRESS_GET_FORMAT


ICM_CONFIGURE

wParam = (DWORD) (UINT) hwnd;
lParam = 0;

Notifies a video compression driver to display its configuration dialog box or queries a video compression driver to determine if it has a configuration dialog box.

  • Returns ICERR_OK if the driver supports this message or ICERR_UNSUPPORTED otherwise.
hwnd
Handle of the parent window of the displayed dialog box.

You can determine if a driver has a configuration dialog box by specifying

- 1 in this parameter. The driver returns ICERR_OK if it has a configuration dialog box or ICERR_UNSUPPORTED otherwise.

This message is different than the DRV_CONFIGURE message used for hardware configuration. The dialog box for this message should let the user set and edit the internal state referenced by ICM_GETSTATE and ICM_SETSTATE. For example, this dialog box can let the user change parameters affecting the quality level and other similar compression options.

See Also

ICM_ABOUT, ICM_GETINFO, ICM_GETSTATE, ICM_SETSTATE


ICM_DECOMPRESS

See also ICDecompress, ICM_COMPRESS_BEGIN, ICM_DECOMPRESS_BEGIN, ICM_DECOMPRESS_END, ICM_DRAW_BEGIN

wParam = (DWORD) (LPVOID) &icd;
lParam = sizeof(ICDECOMPRESS);

Notifies a video decompression driver to decompress a frame of data into an application-supplied buffer.

  • Returns ICERR_OK if successful or an error otherwise.
wParam
Address of an ICDECOMPRESS structure.
lParam
Size, in bytes, of the ICDECOMPRESS structure.

If you want the driver to decompress data directly to the screen, send the ICM_DRAW message.

The driver returns an error if this message is received before the ICM_DECOMPRESS_BEGIN message.

See Also

ICM_ABOUT, ICM_GETINFO, ICM_GETSTATE, ICM_SETSTATE


ICM_DECOMPRESS_BEGIN

wParam = (DWORD) (LPVOID) lpbiInput;
lParam = (DWORD) (LPVOID) lpbiOutput;

Notifies a video decompression driver to prepare to decompress data.

  • Returns ICERR_OK if the specified decompression is supported or ICERR_BADFORMAT otherwise.
wParam
Address of a BITMAPINFO structure describing the input format.
lParam
Address of a BITMAPINFO structure describing the output format.

When the driver receives this message, it should allocate buffers and do any time-consuming operations so that it can process ICM_DECOMPRESS messages efficiently.

If you want the driver to decompress data directly to the screen, send the ICM_DRAW_BEGIN message.

ICM_DECOMPRESS_BEGIN and ICM_DECOMPRESS_END do not nest. If your driver receives an ICM_DECOMPRESS_BEGIN message before decompression is stopped with ICM_DECOMPRESS_END, it should restart decompression with new parameters.

See Also

ICM_COMPRESS_BEGIN, ICM_DECOMPRESS, ICM_DECOMPRESS_END, ICM_DRAW_BEGIN


ICM_DECOMPRESS_END

wParam = 0;
lParam = 0;

Notifies a video decompression driver to end decompressing and free resources allocated for decompression.

  • Returns ICERR_OK if successful or an error otherwise.

The driver should free any resources allocated for ICM_DECOMPRESS_BEGIN.

ICM_DECOMPRESS_BEGIN and ICM_DECOMPRESS_END do not nest. If your driver receives ICM_DECOMPRESS_BEGIN before decompression is stopped with ICM_DECOMPRESS_END, it should restart decompression with new parameters.

See Also

ICM_COMPRESS_END, ICM_DECOMPRESS, ICM_DECOMPRESS_BEGIN, ICM_DRAW_END


ICM_DECOMPRESS_GET_FORMAT

wParam = (DWORD) (LPVOID) lpbiInput;
lParam = (DWORD) (LPVOID) lpbiOutput;

Requests the output format of the decompressed data from a video decompression driver.

  • Return ICERR_OK if successful or an error otherwise.
wParam
Address of a BITMAPINFO structure describing the input format.
lParam
Address of a BITMAPINFO structure to return the output format. You can specify zero to request only the size of the output format.

If lParam is nonzero, the driver should fill the BITMAPINFO structure with the default output format corresponding to the input format specified for wParam. If the compressor can produce several formats, the default format should be the one that preserves the greatest amount of information.

See Also

ICM_COMPRESS_GET_FORMAT, ICM_DECOMPRESS_GET_PALETTE, ICM_DECOMPRESS_QUERY


ICM_DECOMPRESS_GET_PALETTE

wParam = (DWORD) (LPVOID) lpbiInput;
lParam = (DWORD) (LPVOID) lpbiOutput;

Requests that the video decompression driver supply the color table of the output BITMAPINFOHEADER structure.

  • Return ICERR_OK if successful or an error otherwise.
wParam
Address of a BITMAPINFOHEADER structure indicating the input format.
lParam
Address of a BITMAPINFOHEADER structure to return the color table. The space reserved for the color table is always at least 256 colors. You can specify zero for this parameter to return only the size of the color table.

If lParam is nonzero, the driver sets the biClrUsed member of the BITMAPINFOHEADER structure to the number of colors in the color table. The driver fills the bmiColors members of the BITMAPINFO structure with the actual colors.

The driver should support this message only if it uses a palette other than the one specified in the input format.

See Also

ICM_DECOMPRESS_GET_FORMAT


ICM_DECOMPRESS_QUERY

wParam = (DWORD) (LPVOID) lpbiInput;
lParam = (DWORD) (LPVOID) lpbiOutput;

Queries a video decompression driver to determine if it supports a specific input format or if it can decompress a specific input format to a specific output format.

  • Returns ICERR_OK if the specified decompression is supported or ICERR_BADFORMAT otherwise.
wParam
Address of a BITMAPINFO structure describing the input format.
lParam
Address of a BITMAPINFO structure describing the output format. You can specify zero for this parameter to indicate any output format is acceptable.

See Also

ICM_COMPRESS_GET_FORMAT, ICM_COMPRESS_QUERY


ICM_DECOMPRESS_SET_PALETTE

wParam = (DWORD) (LPVOID) lpbiPalette;
lParam = 0;

Specifies a palette for a video decompression driver to use if it is decompressing to a format that uses a palette.

  • Returns ICERR_OK if the decompression driver can precisely decompress images to the suggested palette using the set of colors as they are arranged in the palette. Returns ICERR_UNSUPPORTED otherwise.
wParam
Address of a BITMAPINFOHEADER structure whose color table contains the colors that should be used if possible. You can specify zero to use the default set of output colors.

This message should not affect decompression already in progress; rather, colors passed using this message should be returned in response to future ICM_DECOMPRESS_GET_FORMAT and ICM_DECOMPRESS_GET_PALETTE messages. Colors are sent back to the decompression driver in a future ICM_DECOMPRESS_BEGIN message.

This message is used primarily when a driver decompresses images to the screen and another application that uses a palette is in the foreground, forcing the decompression driver to adapt to a foreign set of colors.

See Also

ICM_DECOMPRESS_BEGIN, ICM_DECOMPRESS_GET_FORMAT


ICM_DECOMPRESSEX

wParam = (DWORD) (LPVOID) &icdex;
lParam = sizeof(ICDECOMPRESSEX);

Notifies a video compression driver to decompress a frame of data directly to the screen, decompress to an upside-down DIB, or decompress images described with source and destination rectangles.

  • Returns ICERR_OK if successful or an error otherwise.
wParam
Address of an ICDECOMPRESSEX structure.
lParam
Size, in bytes, of the ICDECOMPRESSEX structure.

This message is similar to ICM_DECOMPRESS except that it uses the ICDECOMPRESSEX structure to define its decompression information.

If you want the driver to decompress data directly to the screen, send the ICM_DRAW message.

The driver returns an error if this message is received before the ICM_DECOMPRESSEX_BEGIN message.

See Also

ICDecompressEx, ICM_DECOMPRESSEX_BEGIN, ICM_DECOMPRESSEX_END, ICM_DRAW_BEGIN


ICM_DECOMPRESSEX_BEGIN

wParam = (DWORD) (LPVOID) &icdex;
lParam = sizeof(ICDECOMPRESSEX);

Notifies a video compression driver to prepare to decompress data.

  • Returns ICERR_OK if the specified decompression is supported or ICERR_BADFORMAT otherwise.
wParam
Address of a ICDECOMPRESSEX structure describing the input and output formats.
lParam
Size, in bytes, of a ICDECOMPRESSEX structure.

When the driver receives this message, it should allocate buffers and do any time-consuming operations so that it can process ICM_DECOMPRESSEX messages efficiently.

If you want the driver to decompress data directly to the screen, send the ICM_DRAW_BEGIN message.

ICM_DECOMPRESSEX_BEGIN and ICM_DECOMPRESSEX_END do not nest. If your driver receives an ICM_DECOMPRESSEX_BEGIN message before decompression is stopped with ICM_DECOMPRESSEX_END, it should restart decompression with new parameters.

See Also

ICM_DECOMPRESSEX, ICM_DECOMPRESSEX_END, ICM_DRAW_BEGIN


ICM_DECOMPRESSEX_END

wParam = 0;
lParam = 0;

Notifies a video decompression driver to end decompressing and free resources allocated for decompression.

  • Returns ICERR_OK if successful or an error otherwise.

The driver frees any resources allocated for ICM_DECOMPRESSEX_BEGIN.

ICM_DECOMPRESSEX_BEGIN and ICM_DECOMPRESSEX_END do not nest. If your driver receives ICM_DECOMPRESSEX_BEGIN before decompression is stopped with ICM_DECOMPRESSEX_END, it should restart decompression with new parameters.

See Also

ICM_DECOMPRESSEX, ICM_DECOMPRESSEX_BEGIN


ICM_DECOMPRESSEX_QUERY

wParam = (DWORD) (LPVOID) &icdex;
lParam = sizeof(ICDECOMPRESSEX);

Queries a video compression driver to determine if it supports a specific input format or if it can decompress a specific input format to a specific output format.

  • Returns ICERR_OK if the specified decompression is supported or ICERR_BADFORMAT otherwise.
wParam
Address of a ICDECOMPRESSEX structure describing the input format.
lParam
Size, in bytes, of the ICDECOMPRESSEX structure.


ICM_DRAW

wParam = (DWORD) (LPVOID) &icdraw;
lParam = sizeof(ICDRAW);

Notifies a rendering driver to decompress a frame of data and draw it to the screen.

  • Returns ICERR_OK if successful or an error otherwise.
wParam
Address of an ICDRAW structure.
lParam
Size, in bytes, of the ICDRAW structure.

If the ICDRAW_UPDATE flag is set in dwFlags member of the ICDRAW structure, the area of the screen used for drawing is invalid and needs to be updated. The extent of updating depends on the contents of the lpData member.

If lpData is NULL, the driver should update the entire destination rectangle with the current image. If the driver does maintain a copy of the image in an offscreen buffer, it can fail this message. If lpData is not NULL, the driver should draw the data and make sure the entire destination is updated.

If the ICDRAW_HURRYUP flag is set in the dwFlags member, the calling application wants the driver to proceed as quickly as possible, possibly not even updating the screen.

If the ICDRAW_PREROLL flag is set in the dwFlags member, this video frame is preliminary information and should not be displayed if possible. For example, if play is to start from frame 10, and frame 0 is the nearest previous keyframe, frames 0 through 9 will have the ICDRAW_PREROLL flag set.

If you want the driver to decompress data into a buffer, send the ICM_DECOMPRESS message.

See Also

ICDraw, ICM_DECOMPRESS, ICM_DRAW_BEGIN, ICM_DRAW_END, ICM_DRAW_START, ICM_DRAW_STOP


ICM_DRAW_BEGIN

wParam = (DWORD) (LPVOID) &icdrwBgn;
lParam = sizeof(ICDRAW);

Notifies a rendering driver to prepare to draw data.

  • Returns ICERR_OK if the driver supports drawing the data to the screen in the specified manner and format, or an error code otherwise. The following values are defined:
ICERR_OK | Indicates no error occurred.
ICERR_BADFORMAT | Indicates the input or output format is not supported.
ICERR_NOTSUPPORTED | Indicates the driver does not draw directly to the screen or does not support this message.

wParam
Address of an ICDRAWBEGIN structure describing the input format.
lParam
Size, in bytes, of the ICDRAWBEGIN structure.

If you want the driver to decompress data into a buffer, send the ICM_DECOMPRESS_BEGIN message.

ICM_DRAW_BEGIN and ICM_DRAW_END do not nest. If your driver receives ICM_DRAW_BEGIN before decompression is stopped with ICM_DRAW_END, it should restart decompression with new parameters.

See Also

ICDrawBegin, ICM_DECOMPRESS_BEGIN, ICM_DRAW, ICM_DRAW_END, ICM_DRAW_START


ICM_DRAW_CHANGEPALETTE

wParam = (DWORD) (LPVOID) lpbiInput;
lParam = 0;

Notifies a rendering driver that the movie palette is changing.

  • Returns ICERR_OK if successful or FALSE otherwise.
wParam
Address of a BITMAPINFO structure containing the new format and optional color table.

This message should be supported by installable rendering handlers that draw DIBs with an internal structure that includes a palette.

See Also

ICM_DRAW, ICM_DRAW_BEGIN


ICM_DRAW_END

wParam = 0;
lParam = 0;

Notifies a rendering driver to decompress the current image to the screen and to release resources allocated for decompression and drawing.

  • Returns ICERR_OK if successful or an error otherwise.

ICM_DRAW_BEGIN and ICM_DRAW_END do not nest. If your driver receives ICM_DRAW_BEGIN before decompression is stopped with ICM_DRAW_END, it should restart decompression with new parameters.

See Also

ICM_COMPRESS_END, ICM_DECOMPRESS_END, ICM_DRAW, ICM_DRAW_BEGIN, ICM_DRAW_STOP


ICM_DRAW_FLUSH

wParam = 0;
lParam = 0;

Notifies a rendering driver to render the contents of any image buffers that are waiting to be drawn.

  • Returns ICERR_OK if successful or an error otherwise.

This message is used only by hardware that performs its own asynchronous decompression, timing, and drawing.

See Also

ICM_DRAW, ICM_DRAW_BEGIN, ICM_DRAW_END, ICM_DRAW_START, ICM_DRAW_STOP, ICM_GETBUFFERSWANTED


ICM_DRAW_GET_PALETTE

wParam = 0;
lParam = 0;

Requests a rendering driver to return a palette.

  • The driver should return one of the following: a handle of the palette being used, NULL if it doesn't have a handle to return, or ICERR_UNSUPPORTED if it doesn't support palettes.


ICM_DRAW_GETTIME

wParam = (DWORD) (LPVOID) lplTime;
lParam = 0;

Requests a rendering driver that controls the timing of drawing frames to return the current value of its internal clock.

  • Returns ICERR_OK if successful or an errorr otherwise.
wParam
Address to contain the current time. The return value should be specified in samples.

This message is generally supported by hardware that performs its own asynchronous decompression, timing, and drawing. The message can also be sent if the hardware is being used as the synchronization master.

See Also

ICM_DRAW_SETTIME, ICM_DRAW_START, ICM_DRAW_STOP


ICM_DRAW_QUERY

wParam = (DWORD) (LPVOID) lpbiInput;
lParam = 0;

Queries a rendering driver to determine if it can render data in a specific format.

  • Returns ICERR_OK if the driver can render data in the specified format or ICERR_BADFORMAT otherwise.
wparam
Address of a BITMAPINFO structure describing the input format.

This message differs from the ICM_DRAW_BEGIN message in that it queries the driver in a general sense. ICM_DRAW_BEGIN determines if the driver can draw the data using the specified format under specific conditions, such as stretching the image.

See Also

ICM_DECOMPRESS_QUERY, ICM_DRAW_BEGIN


ICM_DRAW_REALIZE

wParam = (DWORD) (UINT) (HDC) hdc;
lParam = (DWORD) (BOOL) fBackground;

Notifies a rendering driver to realize its drawing palette while drawing.

  • Returns ICERR_OK if the drawing palette is realized or ICERR_UNSUPPORTED if the palette associated with the decompressed data is realized.
wParam
Handle of the DC used to realize the palette.
lParam
Background flag. Specify TRUE to realize the palette as a background task or FALSE to realize the palette in the foreground.

Drivers need to respond to this message only if the drawing palette is different from the decompressed palette.

See Also

ICM_DRAW_BEGIN


ICM_DRAW_RENDERBUFFER

wParam = 0;
lParam = 0;

Notifies a rendering driver to draw the frames that have been passed to it.

  • No return value.

Use this message with hardware that performs its own asynchronous decompression, timing, and drawing.

This message is typically used to perform a seek operation when the driver must be specifically instructed to display each video frame passed to it rather than playing a sequence of video frames.

See Also

ICM_DRAW, ICM_DRAW_END, ICM_DRAW_START


ICM_DRAW_SETTIME

wParam = (DWORD) lpTime;
lParam = 0;

Provides synchronization information to a rendering driver that handles the timing of drawing frames. The synchronization information is the sample number of the frame to draw.

  • Returns ICERR_OK if successful or an error otherwise.
wParam
Sample number of the frame to render.

Typically, the driver compares the specified value with the frame number associated with the time of its internal clock, and attempts to synchronize the two if the difference is significant.

Use this message when the hardware performs its own asynchronous decompression, timing, and drawing, and the hardware relies on an external synchronization signal (the hardware is not being used as the synchronization master).

See Also

ICM_DRAW_GETTIME, ICM_DRAW_START, ICM_DRAW_STOP


ICM_DRAW_START

wParam = 0;
lParam = 0;

Notifies a rendering driver to start its internal clock for the timing of drawing frames.

  • No return value.

This message is used by hardware that performs its own asynchronous decompression, timing, and drawing.

When the driver receives this message, it should start rendering data at the rate specified with ICM_DRAW_BEGIN.

ICM_DRAW_START and ICM_DRAW_STOP do not nest. If your driver receives ICM_DRAW_START before rendering is stopped with ICM_DRAW_STOP, it should restart rendering with new parameters.

See Also

ICM_DRAW, ICM_DRAW_BEGIN, ICM_DRAW_END, ICM_DRAW_STOP


ICM_DRAW_START_PLAY

wParam = (DWORD) lFrom;
lParam = (DWORD) lTo;

Provides the start and end times of a play operation to a rendering driver.

  • No return value.
wParam
Start time.
lParam
End time.

This message precedes any frame data sent to the rendering driver.

Units for wParam and lParam are specified with ICM_DRAW_BEGIN. For video data this is normally a frame number. For more information about the playback rate, see the dwRate and dwScale members of ICDRAWBEGIN.

If the end time is less than the start time, the playback direction is reversed.

See Also

ICM_DRAW, ICM_DRAW_BEGIN, ICM_DRAW_START, ICM_DRAW_STOP, ICM_DRAW_STOP_PLAY, ICDRAWBEGIN


ICM_DRAW_STOP

wParam = 0;
lParam = 0;

Notifies a rendering driver to stop its internal clock for the timing of drawing frames.

  • No return value.

This message is used by hardware that performs its own asynchronous decompression, timing, and drawing.

See Also

ICM_DRAW, ICM_DRAW_BEGIN, ICM_DRAW_END, ICM_DRAW_START


ICM_DRAW_STOP_PLAY

wParam = 0;
lParam = 0;

Notifies a rendering driver when a play operation is complete.

  • No return value.

Use this message when the play operation is complete. Use ICM_DRAW_STOP to end timing.

See Also

ICM_DRAW_START, ICM_DRAW_START_PLAY, ICM_DRAW_STOP


ICM_DRAW_SUGGESTFORMAT

wParam = (DWORD) (LPVOID) &icdrwSuggest;
lParam = sizeof(ICDRAWSUGGEST);

Queries a rendering driver to suggest a decompressed format that it can draw.

  • Returns ICERR_OK if successful. If the lpbiSuggest member of the ICDRAWSUGGEST structure is NULL, this message returns the amount of memory required to contain the suggested format.
wParam
Address of an ICDRAWSUGGEST structure.
lParam
Size, in bytes, of the ICDRAWSUGGEST structure.

The driver should examine the format specified in the lpbiIn member of the ICDRAWSUGGEST structure and use the lpbiSuggest member to return a format it can draw. The output format should preserve as much data as possible from the input format.

Optionally, the driver can use the installable compressor handle passed in the hicDecompressor member of ICDRAWSUGGEST to make more complex selections. For example, if the input format is 24-bit JPEG data, a renderer could query the decompressor to find out if it can decompress to a YUV format (which might be drawn more efficiently) before selecting the format to suggest.

See Also

ICDRAWSUGGEST


ICM_DRAW_WINDOW

wParam = (DWORD) (LPVOID) prc;
lParam = 0;

Notifies a rendering driver that the window specified for ICM_DRAW_BEGIN needs to be redrawn. The window has moved or become temporarily obscured.

  • Returns ICERR_OK if successful or an error otherwise.
wParam
Address of the destination rectangle in screen coordinates. If this parameter points to an empty rectangle, drawing should be turned off.

This message is supported by hardware that performs its own asynchronous decompression, timing, and drawing.

Overlay drivers use this message to draw when the window is obscured or moved. When a window specified for ICM_DRAW_BEGIN is completely hidden by other windows, the destination rectangle is empty. Drivers should turn off overlay hardware when this condition occurs.

See Also

ICM_DRAW_BEGIN


ICM_GET

wParam = (DWORD) (LPVOID) pv;
lParam = (DWORD) cb;

Retrieves an application-defined double word from a video compression driver.

  • Returns the amount of memory, in bytes, required to store the status information.
wParam
Address of a block of memory to be filled with the current state. You can also specify NULL determine the amount of memory required by the state information.
lParam
Size, in bytes, of the block of memory.

Client applications send this message with wParam set to NULL to determine the size of the memory block required for obtaining the state information.

The structure used to represent state information is driver specific and is defined by the driver.

See Also

ICM_SETSTATE


ICM_GETBUFFERSWANTED

wParam = (DWORD) (LPVOID) lpdwBuffers;
lParam = 0;

Queries a driver for the number of buffers to allocate.

  • Returns ICERR_OK if successful or ICERR_UNSUPPORTED otherwise.
wParam
Address to contain the number of samples the driver needs to efficiently render the data.

This message is used by drivers that use hardware to render data and want to ensure a minimal time lag caused by waiting for data buffers to arrive. For example, if a driver controls a video decompression board that can hold 10 frames of video, it could return 10 for this message. This instructs applications to try to stay 10 frames ahead of the frame it currently needs.

See Also

ICDraw


ICM_GETDEFAULTKEYFRAMERATE

wParam = (DWORD) (LPVOID) &dwICValue;
lParam = 0;

Queries a video compression driver for its default (or preferred) key-frame spacing.

  • Returns ICERR_OK if the driver supports this message or ICERR_UNSUPPORTED otherwise.
wParam
Address of a double word to return the preferred key-frame spacing.


ICM_GETDEFAULTQUALITY

wParam = (DWORD) (LPVOID) &dwICValue;
lParam = 0;

Queries a video compression driver to provide its default quality setting.

  • Returns ICERR_OK if the driver supports this message or ICERR_UNSUPPORTED otherwise. ICGetDefaultQuality returns the default quality value.
wParam
Address of a double word to return the default quality value. Quality values range from zero to 10,000.

See Also

ICM_GETQUALITY, ICM_SETQUALITY


ICM_GETINFO

wParam = (DWORD) (LPVOID) lpicinfo;
lParam = sizeof(icinfo);

Queries a video compression driver to return a description of itself in an ICINFO structure.

  • Returns the size, in bytes, of the ICINFO structure or zero if an error occurs.
wParam
Address of an ICINFO structure to return information.
lParam
Size, in bytes, of the ICINFO structure.

Typically, applications send this message to display a list of the installed compressors.

The driver should fill in all members of the ICINFO structure except szDriver.

See Also

ICINFO, ICM_ABOUT


ICM_GETQUALITY

wParam = (DWORD) (LPVOID) &dwICValue;
lParam = 0;

Queries a video compression driver to return its current quality setting.

  • Returns ICERR_OK if the driver supports this message or ICERR_UNSUPPORTED otherwise.
wParam
Address of a double word to return the current quality value. Quality values range from zero to 10,000.

See Also

ICM_GETDEFAULTQUALITY, ICM_SETQUALITY


ICM_GETSTATE

wParam = (DWORD) (LPVOID) pv;
lParam = (DWORD) cb;

Queries a video compression driver return its current configuration in a block of memory or to determine the amount of memory required to retrieve the configuration information.

  • Returns the amount of memory, in bytes, required by the state information.
wParam
Address of a block of memory to hold the current configuration information. You can specify NULL for this parameter to determine the amount of memory required for the configuration information
lParam
Size, in bytes, of the block of memory.

The structure used to represent configuration information is driver specific and is defined by the driver.

See Also

ICM_SETSTATE


ICM_SET

wParam = (DWORD) (LPVOID) pv;
lParam = (DWORD) cb;

Notifies a video compression driver to set the state of the compressor.

  • Returns the number of bytes used by the compressor or zero to indicate an error.
wParam
Address of a block of memory containing configuration data. You can also specify NULL for this parameter to reset the driver to its default state.
lParam
Size, in bytes, of the block of memory.

The information used by ICM_SETSTATE is private and specific to a given compressor. Client applications should use this message only to restore information previously obtained with the ICM_GETSTATE message.

See Also

ICM_GETSTATE


ICM_SET_STATUS_PROC

wParam = (DWORD) (LPVOID) icsetstatusProc;
lParam = sizeof(icsetstatusProc);

Provides a status callback function with the status of a lengthy operation.

  • Return ICERR_OK if successful or an error otherwise.
wParam
Address of an ICSETSTATUSPROC structure.
lParam
Size of the ICSETSTATUSPROC structure.

Support of this function is optional but strongly recommended if compression or decompression takes longer than approximately 0.1 seconds.

An application can send this message periodically to a status callback function during lengthy operations.

For information about status callback functions, see .

See Also

ICSETSTATUSPROC


ICM_SETQUALITY

wParam = (DWORD) (LPVOID) &dwICValue;
lParam = 0;

Provides a video compression driver with a quality level to use during compression.

  • Returns ICERR_OK if the driver supports this message or ICERR_UNSUPPORTED otherwise.
wParam
New quality value. Quality values range from zero to 10,000.

See Also

ICM_GETDEFAULTQUALITY, ICM_GETQUALITY


ICM_SETSTATE

wParam = (DWORD) (LPVOID) pv;
lParam = (DWORD) cb;

Notifies a video compression driver to set the state of the compressor.

  • Returns the number of bytes used by the compressor or zero to indicate an error.
wParam
Address of a block of memory containing configuration data. You can specify NULL for this parameter to reset the compressor to its default state.
lParam
Size, in bytes, of the block of memory.

The information used by ICM_SETSTATE is private and specific to a given compressor. Client applications should use this message only to restore information previously obtained with the ICM_GETSTATE message and should use ICM_CONFIGURE to adjust the configuration of a video compression driver.

See Also

ICM_CONFIGURE, ICM_GETSTATE


Structures

Applications use structures to transfer data in VCM messages and functions. The following structures are specific to VCM and provide support for VCM functions and messages.


COMPVARS

typedef struct {
    LONG cbSize;
    DWORD dwFlags;
    HIC hic;
    DWORD fccType;
    DWORD fccHandler;
    LPBITMAPINFO lpbiIn;       // Reserved; do not use
    LPBITMAPINFO lpbiOut;
    LPVOID lpBitsOut;          // Reserved; do not use
    LPVOID lpBitsPrev;         // Reserved; do not use
    LONG lFrame;               // Reserved; do not use
    LONG lKey;
    LONG lDataRate;
    LONG lQ;
    LONG lKeyCount;            // Reserved; do not use
    LPVOID lpState;            // Reserved; do not use
    LONG cbState;              // Reserved; do not use
} COMPVARS;

Describes compressor settings for functions such as ICCompressorChoose, ICSeqCompressFrame, and ICCompressorFree.

Members

cbSize
Size, in bytes, of this structure. This member must be set to validate the structure before calling any function using this structure.
dwFlags
Applicable flags. The following value is defined:
ICMF_COMPVARS_VALID Indicates the data in this structure is valid and has been manually entered. Set this flag before you call any function if you fill this structure manually. Do not set this flag if you let ICCompressorChoose initialize this structure.

hic
Handle of the compressor to use. You can open a compressor and obtain a handle of it by using ICOpen. You can also choose a compressor by using ICCompressorChoose. ICCompressorChoose opens the chosen compressor and returns the handle of the compressor in this member. You can close the compressor by using ICCompressorFree.
fccType
Type of compressor used. Currently only ICTYPE_VIDEO (VIDC) is supported. This member can be set to zero.
fccHandler
Four-character code of the compressor. Specify NULL to indicate the data is not to be recompressed. Specify DIB to indicate the data is an uncompressed, full frame. You can use this member to specify which compressor is selected by default when the dialog box is displayed.
lpbiOut
Address of a BITMAPINFO structure containing the image output format. You can specify a specific format to use or you can specify NULL to use the default compressor associated with the input format. You can also set the image output format by using ICCompressorChoose.
lKey
Key-frame rate. Specify an integer to indicate the frequency that keyframes are to occur in the compressed sequence or zero to not use key frames. You can also let ICCompressorChoose set the key-frame rate selected in the dialog box. ICSeqCompressFrameStart uses the value of this member for making key frames.
lDataRate
Data rate, in kilobytes per second. ICCompressorChoose copies the selected data rate from the dialog box to this member.
lQ
Quality setting. Specify a quality setting of 1 to 10,000 or specify ICQUALITY_DEFAULT to use the default quality setting. You can also let ICCompressorChoose set the quality value selected in the dialog box. ICSeqCompressFrameStart uses the value of this member as its quality setting.

You can let ICCompressorChoose fill the contents of this structure or you can do it manually. If you manually fill the structure, you must provide information for the following members: cbSize, hic, lpbiOut, lKey, and lQ. Also, you must set the ICMF_COMPVARS_VALID flag in the dwFlags member.


ICCOMPRESS

typedef struct {
    DWORD dwFlags;
    LPBITMAPINFOHEADER lpbiOutput;
    LPVOID lpOutput;
    LPBITMAPINFOHEADER lpbiInput;
    LPVOID lpInput;
    LPDWORD lpckid;
    LPDWORD lpdwFlags;
    LONG lFrameNum;
    DWORD dwFrameSize;
    DWORD dwQuality;                 // Quality setting
    LPBITMAPINFOHEADER lpbiPrev;
    LPVOID lpPrev;
} ICCOMPRESS;

Contains compression parameters used with the ICM_COMPRESS message.

Members

dwFlags
Flags used for compression. The following value is defined:
ICCOMPRESS_KEYFRAME Indicates the input data should be treated as a key frame.

lpbiOutput
Address of a BITMAPINFOHEADER structure containing the output (compressed) format. The biSizeImage member must contain the size of the compressed data.
lpOutput
Address of the buffer where the driver should write the compressed data.
lpbiInput
Address of a BITMAPINFOHEADER structure containing the format of the input (uncompressed) data.
lpInput
Address of the buffer containing input data.
lpckid
Address of a double word to return the chunk identifier for data in the AVI file. If the value of this member is not NULL, the driver should specify a two-character code for the chunk identifier corresponding to the chunk identifier used in the AVI file.
lpdwFlags
Address of a double word to return flags for the AVI index. If the returned frame is a key frame, the driver should set the AVIIF_KEYFRAME flag.
lFrameNum
Number of the frame to compress.
dwFrameSize
Desired maximum size, in bytes, for compressing this frame. The size value is used for compression methods that can make tradeoffs between compressed image size and image quality. Specify zero for this member to use the default setting.
dwQuality
Quality setting, if supported by the compression driver. Quality values range from zero to 10,000.
lpbiPrev
Address of a BITMAPINFOHEADER structure containing the format of the previous frame, which is normally the same as the input format.
lpPrev
Address of the buffer containing input data of the previous frame.

Drivers that perform temporal compression use data from the previous frame (found in the lpbiPrev and lpPrev members) to prune redundant data from the current frame.


ICCOMPRESSFRAMES

See also ICM_COMPRESS_FRAMES_INFO

typedef struct {
    DWORD dwFlags;
    LPBITMAPINFOHEADER lpbiOutput;
    LPARAM lOutput;                  // Reserved; do not use
    LPBITMAPINFOHEADER lpbiInput;
    LPARAM lInput;                   // Reserved; do not use
    LONG lStartFrame;
    LONG lFrameCount;
    LONG lQuality;                   // Quality setting
    LONG lDataRate;
    LONG lKeyRate;
    DWORD dwRate;
    DWORD dwScale;
    DWORD dwReserved;                // Reserved; do not use
    DWORD dwReserved1;               // Reserved; do not use
    LONG (CALLBACK* GetData) (LPARAM lInput, LONG lFrame,
        LPVOID lpBits, LONG len);
    LONG (CALLBACK* GetData) (LPARAM lInput, LONG lFrame,
        LPVOID lpBits, LONG len);
} ICCOMPRESSFRAMES;

Contains compression parameters used with the ICM_COMPRESS_FRAMES_INFO message.

Members

dwFlags
Applicable flags. The following value is defined:
ICDECOMPRESSFRAMES_PADDING Indicates padding is used with the frame.

lpbiOutput
Address of a BITMAPINFOHEADER structure containing the output format.
lpbiInput
Address of a BITMAPINFOHEADER structure containing the input format.
lStartFrame
Number of the first frame to compress.
lFrameCount
Number of frames to compress.
lDataRate
Maximum data rate, in bytes per second.
lKeyRate
Maximum number of frames between consecutive key frames.
dwRate
Compression rate in an integer format. To obtain the rate in frames per second, divide this value by the value in dwScale.
dwScale
Value used to scale dwRate to frames per second.
GetData
Reserved; do not use.
PutData
Reserved; do not use.


ICDECOMPRESS

typedef struct {
    DWORD dwFlags;
    LPBITMAPINFOHEADER lpbiInput;
    LPVOID lpInput;
    LPBITMAPINFOHEADER lpbiOutput;
    LPVOID lpOutput;
    DWORD ckid;
} ICDECOMPRESS;

Contains decompression parameters used with the ICM_DECOMPRESS message.

Members

dwFlags
Applicable flags. The following values are defined:
ICDECOMPRESS_HURRYUP | Tries to decompress at a faster rate. When an application uses this flag, the driver should buffer the decompressed data but not draw the image.
ICDECOMPRESS_UPDATE | Indicates the screen is being updated or refreshed.
ICDECOMPRESS_PREROLL | Indicates the current frame precedes the point in the movie where playback starts and, therefore, will not be drawn.
ICDECOMPRESS_NULLFRAME | Indicates the current frame does not contain data and the decompressed image should be left the same.
ICDECOMPRESS_NOTKEYFRAME | Indicates the current frame is not a key frame.

lpbiInput
Address of a BITMAPINFOHEADER structure containing the input format.
lpInput
Address of a data buffer containing the input data.
lpbiOutput
Address of a BITMAPINFOHEADER structure containing the output format.
lpOutput
Address of a data buffer where the driver should write the decompressed image.
ckid
Chunk identifier from the AVI file.


ICDECOMPRESSEX

typedef struct {
    DWORD dwFlags;
    LPBITMAPINFOHEADER lpbiSrc;
    LPVOID lpSrc;
    LPBITMAPINFOHEADER lpbiDst;
    LPVOID lpDst;
    int xDst;
    int yDst;
    int dxDst;
    int dyDst;
    int xSrc;
    int ySrc;
    int dxSrc;
    int dySrc;
} ICDECOMPRESSEX;

Contains decompression parameters used with the ICM_DECOMPRESSEX message

Members

dwFlags
Specifies applicable flags. The following values are defined:
ICDECOMPRESS_HURRYUP | Tries to decompress at a faster rate. When an application uses this flag, the driver should buffer the decompressed data but not draw the image.
ICDECOMPRESS_UPDATE | Indicates the screen is being updated or refreshed.
ICDECOMPRESS_PREROLL | Indicates the current frame precedes the point in the movie where playback starts and, therefore, will not be drawn.
ICDECOMPRESS_NULLFRAME | Indicates the current frame does not contain data and the decompressed image should be left the same.
ICDECOMPRESS_NOTKEYFRAME | Indicates the current frame is not a key frame.

lpbiSrc
Address of a BITMAPINFOHEADER structure containing the input format.
lpSrc
Address of a data buffer containing the input data.
lpbiDst
Address of a BITMAPINFOHEADER structure containing the output format.
lpDst
Address of a data buffer where the driver should write the decompressed image.
xDst, yDst
X- and Y-coordinates of the destination rectangle within the DIB specified by lpbiDst.
dxDst, dyDst
Width and height of the destination rectangle.
xSrc, ySrc
X- and Y- coordinates of the source rectangle within the DIB specified by lpbiSrc.
dxSrc, dySrc
Width and height of the source rectangle.


ICDRAW

typedef struct {
    DWORD dwFlags;
    LPVOID lpFormat;
    LPVOID lpData;
    DWORD cbData;
    LONG lTime;
} ICDRAW;

Contains parameters for drawing video data to the screen. This structure is used with the ICM_DRAW message.

Members

dwFlags
Flags from the AVI file index. The following values are defined:
ICDRAW_HURRYUP | Indicates the data is buffered and not drawn to the screen. Use this flag for fastest decompression.
ICDRAW_UPDATE | Updates the screen based on data previously received. In this case, the lpData parameter should be ignored.
ICDRAW_PREROLL | Indicates the current frame of video occurs before playback should start. For example, if playback will begin on frame 10, and frame 0 is the nearest previous keyframe, frames 0 through 9 are sent to the driver with the ICDRAW_PREROLL flag set. The driver needs this data to display frame 10 properly.
ICDRAW_NULLFRAME | Indicates the current frame does not contain any data, and the previous frame should be redrawn.
ICDRAW_NOTKEYFRAME | Indicates the current frame is not a key frame.

lpFormat
Address of a structure containing the data format. For video streams, this is a BITMAPINFOHEADER structure.
lpData
Address of the data to render.
cbData
Number of bytes of data to render.
lTime
Time, in samples, when this data should be drawn. For video data this is normally a frame number.

See Also

ICDRAWBEGIN, ICM_DRAW_BEGIN


ICDRAWBEGIN

typedef struct {
    DWORD dwFlags;
    HPALETTE hpal;
    HWND hwnd;
    HDC hdc;
    int xDst;
    int yDst;
    int dxDst;
    int dyDst;
    LPBITMAPINFOHEADER lpbi;
    int xSrc;
    int ySrc;
    int dxSrc;
    int dySrc;
    DWORD dwRate;
    DWORD dwScale;
} ICDRAWBEGIN;

Contains decompression parameters used with the ICM_DRAW_BEGIN message.

Members

dwFlags
Applicable flags. The following values are defined:
ICDRAW_QUERY | Determines if the decompressor can handle the decompression. The driver does not actually decompress the data.
ICDRAW_FULLSCREEN | Draws the decompressed data on the full screen.
ICDRAW_HDC | Draws the decompressed data to a window or a DC.
ICDRAW_ANIMATE | Indicates the application can animate the palette.
ICDRAW_CONTINUE | Indicates the drawing is a continuation of the previous frame.
ICDRAW_MEMORYDC | Indicates the DC is offscreen.
ICDRAW_UPDATING | Indicates the current frame is being updated rather than played.
ICDRAW_RENDER | Renders, but does not draw, the data.
ICDRAW_BUFFER | Buffers this data offscreen; it will need to be updated.

hpal
Handle of the palette used for drawing.
hwnd
Handle of the window used for drawing.
hdc
Handle of the DC used for drawing. Specify NULL to use a DC to the specified window.
xDst, yDst
X- and Y-coordinates of destination rectangle.
dxDst, dyDst
Width and height of destination rectangle.
lpbi
Address of a BITMAPINFOHEADER structure containing the input format.
xSrc, ySrc
X- and Y-coordinates of source rectangle.
dxSrc, dySrc
Width and height of source rectangle.
dwRate
Decompression rate in an integer format. To obtain the rate in frames per second, divide this value by the value in dwScale.
dwScale
Value used to scale dwRate to frames per second.


ICDRAWSUGGEST

typedef struct {
    DWORD dwFlags;                     // reserved; set to zero
    LPBITMAPINFOHEADER lpbiIn;
    LPBITMAPINFOHEADER lpbiSuggest;
    int dxSrc;
    int dySrc;
    int dxDst;
    int dyDst;
    HIC hicDecompressor;
} ICDRAWSUGGEST;

Contains compression parameters used with the ICM_DRAW_SUGGESTFORMAT message to suggest an appropriate input format.

Members

lpbiIn
Address of the structure containing the compressed input format.
lpbiSuggest
Address of a buffer to return a compatible input format for the renderer.
dxSrc, dySrc
Width and height of the source rectangle.
dxDst, dyDst
Width and height of the destination rectangle.
hicDecompressor
Handle of a decompressor that supports the format of data described in lpbiIn.

See Also

ICM_DRAW_SUGGESTFORMAT


ICINFO

typedef struct {
    DWORD dwSize;
    DWORD fccType;
    DWORD fccHandler;
    DWORD dwFlags;
    DWORD dwVersion;
    DWORD dwVersionICM;
    char szName[16];
    char szDescription[128];
    char szDriver[128];
} ICINFO;

Contains compression parameters supplied by a video compression driver. The driver fills or updates the structure when it receives the ICM_GETINFO message.

Members

dwSize
Size, in bytes, of the ICINFO structure.
fccType
Four-character code indicating the type of stream being compressed or decompressed. Specify VIDC for video streams.
fccHandler
Four-character code identifying a specific compressor.
dwFlags
Applicable flags. Zero or more of the following flgas can be set:
VIDCF_QUALITY | Indicates the driver supports quality values.
VIDCF_CRUNCH | Indicates the driver supports compressing to a frame size.
VIDCF_TEMPORAL | Indicates the driver supports inter-frame compression.
VIDCF_DRAW | Indicates the driver supports drawing.
VIDCF_FASTTEMPORALC | Indicates the driver can perform temporal compression and maintains its own copy of the current frame. When compressing a stream of frame data, the driver doesn't need image data from the previous frame.
VIDCF_FASTTEMPORALD | Indicates the driver can perform temporal decompression and maintains its own copy of the current frame. When decompressing a stream of frame data, the driver doesn't need image data from the previous frame.
VIDCF_COMPRESSFRAMES | Indicates the driver is requesting to compress all frames. For information about compressing all frames, see ICM_COMPRESS_FRAMES_INFO.

You can use the high-ordered word of this member for driver-specific flags.

dwVersion
Version number of the driver.
dwVersionICM
Version of VCM supported by this driver. This member should be set to ICVERSION.
szName
Short version of the compressor name. The name in the null-terminated string should be suitable for use in list boxes.
szDescription
Long version of the compressor name.
szDriver
Name of the module containing VCM compression driver. Normally, a driver does not need to fill this out.

See Also

ICM_COMPRESS_FRAMES_INFO


ICOPEN

typedef struct {
    DWORD dwSize;
    DWORD fccType;
    DWORD fccHandler;
    DWORD dwVersion;
    DWORD dwFlags;
    DWORD dwError;
} ICOPEN;

Contains information about the data stream being compressed or decompressed, the version number of the driver, and how the driver is used.

Members

dwSize
Size, in bytes, of the structure.
fccType
Four-character code indicating the type of stream being compressed or decompressed. Specify VIDC for video streams.
fccHandler
Four-character code identifying a specific compressor.
dwVersion
Version of the installable driver interface used to open the driver.
dwFlags
Applicable flags indicating why the driver is opened. The following values are defined:
ICMODE_COMPRESS | Indicates the driver is opened to compress data.
ICMODE_DECOMPRESS | Indicates the driver is opened to decompress data.
ICMODE_QUERY | Indicates the driver is opened for informational purposes, rather than for compression.
ICMODE_DRAW | Indicates the device driver is opened to decompress data directly to hardware.

dwError
Error return values.

This structure is passed to video capture drivers when they are opened. This allows a single installable driver to function as either an installable compressor or a video capture device. By examining the fccType member of the ICOPEN structure, the driver can determine its function. For example, a fccType value of VIDC indicates that it is opened as an installable video compressor.


ICSETSTATUSPROC

typedef struct {
    DWORD dwFlags;                     // reserved; set to zero
    LONG lParam;
    LONG (CALLBACK * ()) fpfnStatus;
} ICSETSTATUSPROC;

Contains status information used with the ICM_SET_STATUS_PROC message.

Members

lParam
Parameter that contains a constant to pass to the status procedure.
fpfnStatus
Address of the status function. Specify NULL if status messages should should not be sent.

See Also

ICM_SET_STATUS_PROC


Networking

This documentation answers frequently asked questions about Windows® 95 networking from a developer's point of view. Most of the answers point to resources on the Microsoft Development Library CD or in the Windows 95 DDK Network pamphlet.


How All the Network Components Fit Together

The following illustration from Inside Windows 95 shows how the various Windows® 95 network components fit together.

The following components are discussed in the Network pamphlet:

  • Multiple Provider Router
  • Network Provider
  • Transport API/SPI
  • NDIS


Where to Find More Information on Windows 95 Network Architecture

A good introduction to Windows 95 networking is in the Windows 95 Resource Kit. The CD-ROM version of Windows 95 contains the Windows 95 Resource Kit as a help file. The help file is located in the Admin\Reskit\Helpfile directory on the CD-ROM and is called Win95rk.hlp. Open this file and select the Windows 95 Reference section and then Windows 95 Network Architecture.

For a good overview of how the various components interface with the operating system, look in the MSDN Development Library CD.


What the Network Pamphlet Contains

  1. Windows 95 Network Device Drivers: An overview of the Network pamphlet, differences between Windows 95 and Windows for Workgroups and between Windows 95 and Windows NT/Windows 2000, and changes to the networking functions for Windows 95.
  2. Plug and Play Network Drivers: Plug and Play issues involving network drivers.
  3. Network Driver Installer: Writing of .INF files for network drivers.
  4. Multiple Provider Router: Discussion of the Multiple Provider Router layer, which unifies the interface to the network redirector across multiple network protocols.
  5. Network Provider SPI: Description of the Network Provider Service Provider Interface (SPI). Different network vendors can write network providers to provide a consistent interface to access network resources, such as printers and file servers.
  6. Windows 95 Password Providers: Description of a common means of using passwords with network resources.
  7. Windows 95 Session Management Modules: How to add new drivers to Dial-Up Networking.


Difference between a Full NIC Driver and a Miniport Driver

The older full NIC driver contained a lot of code that is common between drivers for different network cards. The developer would have to include the same code in any full NIC driver. With a miniport driver, much of the common code has been moved to the NDIS library so that the driver is smaller and easier to write. Windows 95 supports the use of a miniport network driver that is binary compatible with the Windows NT/Windows 2000 miniport driver.


Lower-edge Functions

From the Windows NT/Windows 2000 network documentation: When a network packet arrives from a remote network node, the NIC captures the packet and signals the local NIC driver. The NIC driver then makes a call to the NDIS library, which calls, in turn, transport driver lower-edge functions to notify bound transport drivers of the incoming packet and subsequently transfer the packet data. Transport driver function names are prefaced with "Protocol."


Upper-edge Functions

From the Windows NT/Windows 2000 network documentation: The NDIS library calls NIC driver upper-edge functions, which prepare the packet for transmission on the network and queue it to be transmitted by an underlying NIC. NIC driver function names are prefaced with "Miniport" or "Mac" (depending on the type of NIC driver).


How to Port a Network Driver to Windows 95

You will probably want to find out several things:

  • Differences between Windows for Workgroups and Windows 95. For more information, see Differences from Windows for Workgroups.
  • Miniport overview. For more information, look in the Microsoft Development Library CD.

Microsoft recommends that you write a miniport driver for Windows 95. However, you will need the Windows NT 3.51 DDK to do so.


NDIS

Network driver interface specification (NDIS) is Microsoft's standard for driver design. NDIS encapsulates the network driver so it is protocol-independent.


Differences between NDIS 3.0 and 3.1

From the Windows NT/Windows 2000 network documentation: From a NIC driver perspective, there is no difference between a well written NDIS 3.0 driver and an NDIS 3.1 driver for Windows 95. Sources from a driver compiled to run under Windows for Workgroups 3.11 can simply be recompiled under the Windows 95 DDK to take advantage of NDIS 3.1 functionality. There are no new driver functions in NDIS 3.1.

NDIS 3.1 means the following for Windows 95:

  • NIC drivers are dynamically loadable and unloadable.
  • NIC drivers use STD calling convention, as does Windows NT/Windows 2000.
  • NDIS 3.1 allows pageable code (all code marked previously as INIT should be made pageable instead).
  • Windows NT/Windows 2000 miniport NIC drivers can be used on Windows 95.

If your NDIS 3.0 NIC driver uses standard macro definitions from the samples, these macros have been redefined to fit the NDIS 3.1 dynamic loading/unloading scenario.

You should make all noncritical code pageable (typically INIT and removal/unload code).

In NDIS 3.0, the protocol loads first, and all adapters are bound to the protocols. In Windows 95, the adapter is detected and opened by the Configuration Manager and the NDIS interface library (wrapper) first, and protocols are bound to the available adapters. As a result, NdisOpenAdapter is no longer called from within NdisAddAdapter, so you should ensure no local variables are used to pass data between these two functions.


How to Obtain the NDIS Specification

On the Microsoft Development Library, you can find the specification in the following location:

DDKs
    Windows NT 3.51 DDK
        Network Drivers
            Reference
                NDIS


Transport Drivers

A transport driver implements a network protocol, such as TCP/IP or IPX.


What is TDI

TDI stands for Transport Driver Interface. TDI allows you to write new transport drivers that are independent of the network card. You can also write network applications to use TDI rather than relying on a certain protocol, such as NetBIOS or IPX.


Windows 95 Network Device Drivers

Windows 95 supports network device drivers having either the network driver interface specification (NDIS) miniport or Full NDIS media access control model. The preferred driver model is the miniport model, as described in the Windows NT Device Driver Development Kit (DDK) 3.51. Developers of miniport drivers should obtain the Windows NT 3.51 DDK and use it to develop a driver that is binary-compatible between Windows 95 and Windows NT 3.51.

The Windows 95 DDK describes a method for building a driver that fits the Full NDIS media access control driver model, see . This documentation, which originally appeared in the Windows NT 3.5 DDK, is included in the Windows 95 DDK for developers who must still use that model. Remember that the preferred driver model for a Windows 95 NDIS 3.1 driver is the miniport model.

The NDIS 3.1 specification is specific to Windows 95 and is essentially the NDIS 3.0 specification with Plug and Play capability added. For more information about Plug and Play networking, see .

It is important to note that for network adapter card drivers, an NDIS 3.1-compliant Full NDIS media access control driver can be built by compiling the NDIS 3.0 Full media access control driver sources with the Windows 95 DDK tools.

If you build a miniport driver, it is by definition NDIS 3.1-compliant, that is, the driver is a Plug and Play device.


Platform Differences

The following sections describe differences in network drivers between Windows 95 and Windows for Workgroups, and Windows 95 and Windows NT/Windows 2000.


Differences from Windows for Workgroups

The following sections describe differences in network drivers between Windows 95 and Windows for Workgroups.


Windows 2000 First, Windows 95 Second

If your media access control driver will have both Windows NT/Windows 2000 and Windows 95, it is best to develop and perfect the Windows NT/Windows 2000 version first. Code written for Windows NT/Windows 2000 easily translates to Windows 95, but the reverse is not necessarily true. Maintaining a common source base for both environments is painless and encouraged. Of course, the easiest course of action is to write an NDIS miniport that will run the same binary on both platforms.


NDIS 3.1 Driver Names

NDIS 3.1 drivers (not miniports) have changed extensions, from .386 to .vxd (for example, ne2000.386 is now ne2000.vxd). The Ndis.mk file included in this DDK will automatically build with this extension. The change is cosmetic, and the functionality has not changed. You could change the file names by using a simple file rename command at the command prompt. Make sure that your .inf files reflect this new naming convention. The reason for the naming convention is to distinguish Windows 95 drivers from Windows for Workgroups version 3.11 drivers.


Visual C++(r) 2.0 and Problems with the Default Code Segment

Windows 95 drivers built by using Visual C++ version 2.0 may have problems with page faults under stress. By default Visual C++ version 2.0 places all code in the .text code segment which is Win32 pageable code. (Previous versions of the compiler placed code in the locked _LTEXT segment by default.) If the ISR, DPC, or other code is pageable and this code gets swapped under heavy stress, calls to these routines are lost. To lock down code that is not pageable, you can place a single pragma "LCODE" line in front of all .C files that do not already have a pragma "PCODE" or pragma "ICODE" in place. Always check the .map file for the driver to make sure the .text segment does not contain code that should be locked.


Interrupt 2

Interrupt 2 is the same as interrupt 9 in computers. For Windows 95, this is being enforced as a requirement of Configuration Manager. Unfortunately, most users don't know these two interrupts are the same, and many drivers require a 2 in the UI. We have added a flag that allows the system to carry a 9 internally, but it passes a 2 to Protocol.ini (for ndis2 drivers) and to NDIS 3.1 drivers. To make this work, you need to change all occurrences of interrupt 2 in your LogConfig sections (IRQConfig) to interrupt 9, then add the flag 0x40 to your interrupt keyword. The following is an example:

HKR,NDI\params\Interrupt,resc,1,04,00,00,00
HKR,NDI\params\Interrupt,ParamDesc,,"Interrupt Level"
HKR,NDI\params\Interrupt,flag,1,50,00,00,00   ;0x40 - IRQ2/9 && 0x10 - NDIS 2 only


ISAPNP, EISA, PCI, PCMCIA and MCA Cards

The ISAPNP, EISA, PCI, PCMCIA and MCA bus types are enumerated explicitly by Configuration Manager. (MicroChannel is not hardware enumerated at this time, but it is in this list in case this is added in future releases.) Because of this characteristic, Setup needs to handle manual installations of these cards differently than legacy ISA cards. Ideally, these cards should be installed by simply plugging the card in and turning the computer on. The system automatically detects the card and its configuration, and installs it. However, it is possible to manually install the device through the New Hardware or Net Setup Control Panel. Special code was added to handle this situation. In order to invoke this code, a keyword needs to be added to the .inf file for these cards. The keyword is CardType, and the options are PCMCIA, EISA, PCI, ISAPNP, or MCA. The following example illustrates it's use:

HKR,NDI,CardType,,"PCMCIA"

Look at the .inf files that are included with Windows 95 to get an idea of where you want to place this line.


Differences between NDIS 3.0 and NDIS 3.1

From a Netcard driver perspective, there is no difference between a well-written NDIS 3.0 driver and an NDIS 3.1 driver. Sources from a driver compiled to run under Windows for Workgroups 3.11 can simply be recompiled under the Windows 95 DDK to take advantage of NDIS 3.1 functionality. There are no new driver functions in NDIS 3.1.

NDIS 3.1, for Windows 95, means the following:

  • Dynamically loadable and unloadable
  • Uses STD calling convention, as does Windows NT/Windows 2000
  • Allows pageable code (all code marked previously as init should be made pageable instead)
  • Allows the use of Windows NT/Windows 2000 miniports in Windows 95

If your NDIS 3.0 driver uses standard macro definitions from the samples, these macros have been redefined to fit the NDIS 3.1 dynamic loading/unloading scenario.

You should make all noncritical code pageable (typically Init and Removal/Unload code).

In NDIS 3.0, the protocol loads first, and all adapters are bound to the protocols. In Windows 95, the adapter is detected and opened by the Configuration Manager and the Wrapper first, and protocols are bound to the available adapters. As a result, OpenAdapter is no longer called from within the AddAdapter procedure. So, make sure no local variables are used to pass data between these two procedures.


INF Files

The .inf file format is described elsewhere in this DDK. For network adapters, it is best to use the .inf files that ship with Windows 95 as samples (most files beginning with Netxxx.inf are for network adapters)


Flags

The following flags are defined for use in Windows 95 (similar to their definition in Windows for Workgroups 3.11):

0x08 | Query By Default (forces the UI to ask the user to choose a value)
0x10 | NDIS 2 only
0x20 | NDIS 3.1 only
0x30 | Both NDIS 2 and NDIS 3.1

Example:

  HKR,NDI\params\ RINGSPEED,flag,1,38,00,00,00  ; 0x10 = NDIS 2
                ; 0x20 = NDIS 3.1
                ; 0x08 = Query by default

Optional parameters remain unwritten to the registry or the Protocol.ini until they are selected by the user, and are defined like the following example:

HKR,NDI\params\RXBUFFERSIZE,optional,,1


Memory Base Addresses

Because of a need to be consistent with Windows NT/Windows 2000 guidelines, Memory Base Addresses should be absolute (not paragraph) addresses. This is a change from Windows for Workgroups 3.11 guidelines, mandated specifically because Configuration Manager for Windows 95 maintains only absolute addresses.

Example:

IOBASE=0xD0000 (not 0xD000)

If the NDIS 2 driver requires paragraph addresses, the following line may be added to the .inf file, and is only used for values written to the Protocol.ini:

HKR,NDI\params\RamAddress,paragraph,,1

Example:

HKR,NDI\params\RamAddress,resc,1,01,00,00,00
HKR,NDI\params\RamAddress,ParamDesc,,"Memory Base Address"
HKR,NDI\params\RamAddress,paragraph,,1

In this sample, RamAddress would equal 0xD0000 in the registry, and would equal 0xD000 in the Protocol.ini


Differences from Windows NT 3.0 and 3.5

The following sections describe differences between network drivers for Windows 95 and Windows NT 3.0 and 3.5.


Large Integer Math

Windows 95 does not handle large integer math. Do not call a large integer function, such as RtlConvertUlongToLargeInteger, in your Windows 95 driver.


Windows NT and Windows 2000 Kernel Calls

Windows 95 cannot handle any Windows NT/Windows 2000 kernel calls, so avoid their use.


Spinlocks

Spinlocks are nonfunctional in Windows 95. In debug builds, they are equivalent to an ASSERT, so they are useful as debug flags. In retail builds, spinlocks are completely ignored by the compiler.


Initialization for EISA and MCA Cards

Windows NT/Windows 2000 and Windows 95 handle EISA and MCA cards differently at initialization. The Windows NT/Windows 2000 registry handles all card IDs and slot registration. In Windows 95, the driver must contain the actual MCA card ID.

If your Windows 95 driver supports more than one type of MCA card, list the ID for each card in your source code. See the NE2000 or the IBMTOK samples for examples of MCA cards. Lists of EISA cards are no longer required.

For Windows 95, SLOTNUMBER is not needed within the Protocol.ini file. For EISA cards, Windows 95 relies on the Configuration Manager to tell NDIS what slot the card is in. For MCA cards, NDIS will scan all the slots looking for an ID that matches. SLOTNUMBER may be used for MCA cards if more than one of a given card is used in a computer and a way to differentiate the two is needed.


NDIS 2 Keyword Compatibility

Windows 95 NDIS 3.1 drivers and miniports should be keyword compatible with existing equivalent NDIS 2 drivers. This is a change from the Windows NT/Windows 2000 model that is required for backwards compatibility with real mode (NDIS 2) drivers that may be running on the same Windows 95 computer.

In the Windows 95 model, it is possible to use two different keywords to refer to the same value (because the NDIS 2 keywords are written to the Protocol.ini, and the NDIS 3.1 keywords will be written to the registry). In practice, this should be avoided if possible, and (for purposes of maintaining compatibility with Windows NT/Windows 2000 NDIS miniport keywords) should only be used for the four resource types maintained by the system (InterruptNumber, IoBaseAddress, MemoryBaseAddress, and DMAChannel). In any case where the keywords are different, the values the keyword may take must be the same for both drivers.

Example from NETEE16..inf:

  ; Resources
  HKR,,InterruptNumber,1,04,00,00,00
  HKR,NDI\params\InterruptNumber,resc,1,04,00,00,00
  HKR,NDI\params\InterruptNumber,ParamDesc,,"Interrupt Level"
  HKR,NDI\params\InterruptNumber,flag,1,20,00,00,00    ; 0x20 = NDIS 3.1 only
  ;ndis2
  HKR,NDI\params\ IRQ,resc,1,04,00,00,00
  HKR,Ndi\params\ IRQ,ParamDesc,,"Interrupt Level"
  HKR,NDI\params\ IRQ,flag,1,10,00,00,00      ; 0x10 = NDIS 2 only

In this example, the resource is tied to the keyword InterruptNumber, which shows up only in the registry. The keyword IRQ will get written to the Protocol.ini. This sample would not work if the values for each keyword were different (for example, one looks for a hexadecimal number, the other looks for a string).

It is possible for either driver to have different, unique keywords (such as MAXMULTICAST), as long as this keyword is explicitly tagged as being NDIS 2 or NDIS 3.1 only.


Small Numeric Keywords

When a keyword requires a parameter that is a small number (such as DMA channel or IRQ number), use decimal, not hexadecimal, numbers. An exception to this rule would be if an NDIS 2 driver uses hexadecimal, then the NDIS 3.1 driver must as well.


NdisWriteErrorLogEntry Function

Use of this function is highly encouraged. For Windows 95, calls to this function provide users with a dialog box notifying them that an error occurred. In addition, information provided as part of the NdisWriteErrorLogEntry function is written to an error log file called Ndislog.txt.

Any troubleshooting documentation provided with the driver should list all error codes passed to this function. Because it is possible to uniquely number each call to NdisWriteErrorLogEntry, it should be relatively easy to design errors that isolate specific common installation and hardware problems.

It is mandatory that this function be used only in initialization code. Use of this function at any other time may cause unexpected results.


NdisStallExecution

Due to limitations in NdisStallExecution, it is possible that calls to this function of greater than 100 microseconds could cause slower background serial data transmissions to drop characters. For calls of 10 milliseconds or less, Ndis.386 will suspend interrupts on the card by default, regardless of whether or not interrupts were explicitly turned off prior to the call.

Because of these characteristics, do not call this function longer than 100 microseconds. If a wait for a longer period of time is desired, create a timer loop with an NdisStallExecution(100) within the loop.

This functionality will be reevaluated in future versions of Windows 95. Using this technique will guarantee compatibility with any changes in the future.


NDIS Netcard Driver Tester (TestProt)

To install the NDIS Netcard Driver Tester (TestProt), copy Nettpdrv.inf to the Inf subdirectory of your Windows directory, and copy the appropriate Tpdrvr.386 and Tpdrvr.sym to the System subdirectory of your Windows directory. Start Windows, and from the Network Control Panel, add the Microsoft NDIS Netcard Tester to your protocol list, binding it to the network card under test. Restart Windows, and Testprot will be ready to run.

This version of Testprot has been modified to meet the NDIS 3.1 addendum to the NDIS 3.0 spec, specifically to support the dynamic loading and unloading of media access control drivers. From the media access control developer's perspective, nothing has changed. This is a simple recompile of existing NDIS 3.0 sources with the new header files in this DDK. In addition, all NDIS function calls now use the standard calling convention, which is faster and allows binary compatibility with Windows NT 3.5 NDIS miniport drivers. The correct compiler flag to create standard calling convention components is included in the new Ndis.mk file.

The TestProt provided in this DDK may not fully support Arcnet or FDDI. The code is in, but has not been tested. TestProt also does not support QueryStatistics (which calls MacQueryGlobalStatistics). The test scripts included in this release contain support for this, but this support is disabled. This functionality will be provided in a future release.

For Token Ring testing, a cyclical test will require the packetsize variable be submitted as well. Current test functionality starts sending with packets set at the minimum packetsize, incrementing size by one up to packetsize. For Token Ring, packetsize is variable. Current scripts use 2028 as the max_frame_size, which is the minimum for the original IBM(r) 4MB Token Ring card. If the card under test has a different maximum packet size, set the max_frame_size accordingly. The corresponding log files will differ as well.

On Ethernet, one cyclical test will consist of 1459 packets. On Token Ring, one cyclical test will consist of 1987 packets (assuming a max_frame_size of 2028).

Stress testing in the TestProt environment can cause Windows 95 to do many strange things that are not real world. When running a test suite on a very fast computer, it is possible to get TestProt into a state that mimics driver failure. In any case where a script fails, rerun the specific failing script (for example, \1\2\3\1\5.tps) by itself after power cycling the computer. If the failure reproduces, then there is a genuine bug. In general, if TestProt crashes, Testprot.log and the Script.log files will probably be crosslinked. In these cases, run chkdsk to recover.

There is a new type of packetmakeup - ONE Buffer. A set of scripts can be created to add to the suite (window both on and off) that uses this, in order generate maximum stress on the card. For an example, using just such a stress test, the Ne3200.386 driver was able to peak out the theoretical maximum for Ethernet: 1000 packets/sec of 1514 bytes/packet.

When a stress test runs without the window on, the probability that one card may overflow the second card in the test increases. Use good judgment in choosing a set of cards for a given test. They should be matched for reasonably similar expected performance. If one card has a significant inherent architectural speed advantage, the other card in the test will be flooded and will not exercise good send/receive interaction. This is not poor design if the intent is to see how well a card performs under overwhelming stress. When packets are used from a pool, the throughput will increase as well. These factors will have an effect on the logs created, and they should be kept in mind when comparisons are drawn with the master logs.

Many of the speed differences between the Windows NT/Windows 2000 version of TestProt and the Windows 95 version are related to the Windows 95 version doing no memory allocations during the test if possible. Memory allocations are very expensive in Windows environments.

Because of the potentially large differences in expected and actual throughputs achieved by a card under test, the BETWEEN_VALUES parameters in the tps scripts may need to be modified. In general, for two evenly matched cards running without the window on and with packets from the pool, the second card (server in the stress test) should receive and echo back about 25 percent of all packets sent by the client. Likewise, when running the Acknowledgment (Ack) stress tests, the BETWEEN_VALUES may need to be examined to be sure that they are reasonable.


Windows 95 Networking API Changes

This documentation describes the changes between previous versions of Windows and Windows 95 in network API support.

A Windows networking API set was introduced in Windows 3.0 and Windows 3.1. The Windows 3.1 WinNet interface is a set of network-independent APIs that enables a network vendor to supply a DLL (a network provider) which implements the interface. Windows 3.1 will interact with that interface to extend itself to be network-aware. Applications were not allowed to use the APIs exported by the network provider DLL (with a few exceptions). The network provider DLL had to present dialogs to carry out its high-level functionality, and this resulted in a variety of user interfaces for the same functionality.


16-Bit LAN Manager APIs

LAN Manager 2.1 placed a layer (called the multinet DLL) above the Windows 3.1 WinNet interface which enable clients to simultaneously access NetWare and LAN Manager networks by routing requests to the appropriate network.

Windows 95 supports the 16-bit LAN Manager APIs in full (these are the APIs exported by Netapi.dll and Pmspl.dll). This includes support for network APIs, mailslots, and named pipes. Windows 95 uses the Client for Windows Networks to do this.


Windows for Workgroups APIs

In Windows for Workgroups 3.1, the common network dialogs were modified to use the WinNet interface, rather than be network-specific. An additional API set was added (the multi-net APIs) which enable specific networks to be targeted by these dialogs. The network dialogs were extended to support an arbitrary second network.

The 16-bit network APIs introduced in Windows for Workgroups (the multinet APIs, password caching, and others) are not supported in Windows 95. Following is a list of these obsolete APIs:

MNetGetLastTarget
MNetGetNetInfo
MNetGetResourceNet
MNetSetNextTarget
MNetNetworkEnum
WNetCachePassword
WNetEnumCachedPasswords
WNetExitConfirm
WNetGetCachedPassword
WNetGetLastConnection
WNetGetShareCount
WNetGetShareName
WNetGetSharePath
WNetRemoveCachedPassword
WNetServerBrowseDialog
WNetSetDefaultDrive
WNetShareAsDialog
WNetSharesDialog
WNetStopShareDialog

These APIs are not supported in Windows 95 because accessing these APIs requires loading the 16-bit network driver directly, and there is no 16-bit network driver present in the system.


Windows NT 3.5 32-Bit LAN Manager APIs

In Windows NT 3.5, the multinet layer was formalized to be a Multiple Provider Router (MPR) and the API set was expanded to provide network browsing capability using Win32 interfaces. The API set was also expanded to allow for some differences between networks (for example, different naming conventions and the NetWare server security model).

The 32-bit LAN Manager APIs exported from Netapi32.dll in Windows NT 3.5, are not supported in Windows 95 because they are Unicode-only APIs.


Windows NT 3.51 32-Bit Networking APIs

The tables in the following sections summarize the differences between the Windows 95 and the Windows NT 3.51 networking API sets.


Browsing Functions

Windows 95 supports all the browsing functions that are offered by Windows NT 3.51.

Networking API | Windows 95 | Windows 3.51
WNetCloseEnum | Yes | Yes
WNetEnumResource | Yes | Yes
WNetGetResourceInformation | Yes | No
WNetGetResourceParent | Yes | No
WNetOpenEnum | Yes | Yes


Connection Functions

Windows 95 supports all the connection functions offered by Windows NT 3.51. Windows 95 also offers the WNetSetConnection and WNetUseConnection functions, which are documented in Multiple Provider Router.

Networking API | Windows 95 | Windows 3.51
WNetAddConnection | Yes | Yes
WNetAddConnection2 | Yes | Yes
WNetAddConnection3 | Yes | Yes
WNetCancelConnection | Yes | Yes
WNetCancelConnection2 | Yes | Yes
WNetGetConnection | Yes | Yes
WNetGetUniversalName | Yes | Yes
WNetSetConnection | Yes | No
WNetUseConnection | Yes | No


Other Functions

Windows 95 supports all the miscellaneous network functions supported by Windows NT 3.51. Windows 95 also offers the WNetConnectionDialog1, WNetDisconnectDialog1, WNetGetNetworkInformation, and WNetGetProviderName functions, which are documented in Multiple Provider Router.

Networking API | Windows 95 | Windows 3.51
WNetConnectionDialog | Yes | Yes
WNetConnectionDialog1 | Yes | No
WNetDisconnectDialog | Yes | Yes
WNetDisconnectDialog1 | Yes | No
WNetGetLastError | Yes | Yes
WNetGetNetworkInformation | Yes | No
WNetGetProviderName | Yes | No
WNetGetUser | Yes | Yes


Authentication and Log On/Log Off

Windows 95 offers the following authentication and logon/logoff functions not offered by Windows NT 3.51. These functions are documented in Multiple Provider Router.

Networking API | Windows 95 | Windows 3.51
WNetLogoff | Yes | No
WNetLogon | Yes | No
WNetVerifyPassword | Yes | No


Multiple Provider Router

This documentation describes the Multiple Provider Router for Windows 95. The Multiple Provider Router (MPR) exports the general networking APIs in Win32, and interacts with the underlying Network Providers (NPs) and at most one Windows 3.1 compatible network (WinNet16 DLL) to provide these services. It additionally exports the additional interfaces needed by the explorer and the common dialog library to access the underlying networks. Any User Interface presented to the user by the MPR is outlined here.

The MPR is described by defining its interface with applications (the Win32 APIs), and an outline of its implementation. The description of a NP, including the interface between the MPR and a NP (i.e., the NP Interface or WinNet API in Windows 3.1 terminology), and the services the MPR provides for an NP are described in Network Provider SPI.

The reader is assumed to be familiar with the WinNet interface in Windows 3.1.

This documentation does not cover NETBIOS, Named Pipe, and Mailslot APIs or the mechanisms used for printing. The networking APIs in this documentation primarily refer to the functions needed to browse networks, and make/break network connections. The APIs dealing with authentication for those operations are also covered.


History

A Windows Networking API set was introduced in Windows 3.0 and enhanced in Windows 3.1. The Windows 3.1 WinNet Interface is set of network independent APIs where a network vendor supplies a DLL which implements the interface, and Windows will interact with exactly one such DLL (WinNet16 driver) to extend itself to be network aware. With a couple of exceptions, applications are not allowed use these APIs. The APIs are relatively high level, often requiring the NP DLL to bring up dialogs to perform operation resulting in a variety of UIs for the some functionality.

In LAN Manager 2.1, a layer was placed above the Windows 3.1 WinNet Interface (the multi-net DLL) which was used to allow the client to simultaneously access NetWare and LAN Manager networks by routing requests to the appropriate networks.

In Windows for Workgroups 3.1 the common network dialogs were modified to use the WinNet Interface rather than be network specific, an additional API set was added so that specific networks could be targeted via these dialogs (the multi-net APIs), and the dialogs supported an arbitrary second network. Installation and setup was extended to support a secondary network.

In Windows and Windows NT/Windows 2000, the multi-net layer was formalized to be the MPR and the API set was expanded to provide network browsing capability using Win32 interfaces, and to allow for some differences between networks (different naming conventions, and the NetWare server security model).

In Windows 95, the main goals of the MPR design are: allow the user seamless access to several networks at a time, and to expose a set of networking APIs callable by applications. This set, together with the other Win32 APIs should be able to provide all the commonly used capabilities required by applications.

To summarize the goals new to Windows 95:

Support for the Win32 WinNet APIs as defined in Windows NT/Windows 2000.

Provide an interface that allows seamless browsing of network resources into authenticated information (network directories, printers, and other network resources). This includes consistent handling of authentication requirements across multiple networks.

Backward compatibility with Window for Workgroups 3.11, namely to support at most one Windows 3.1 architecture network (i.e., a network which uses a Windows 3.1 WinNet16 DLL, and the file system is not implemented as a network IFS).


Exploring Network Resources

The explorer views networks hierarchically. There is a logical root of the network, and networks are located under this root. Details of each network are presented as a hierarchy. As a user "explores" down the network hierarchy, a connection to a network resource may be required to view further (for example, to view files). This connection may in turn require authentication.

Browsing APIs are provided to support exploring networks hierarchically. These APIs provide the ability to enumerate the network as a hierarchical set of objects, called net resources. Each net resource has a name that, together with its parent object names, uniquely identifies the resource on that network. Resources are given types that indicate the nature of the resource (e.g., server, file share point, directory). The APIs indicate whether or not access to a resource requires a network connection or authentication to be made. Access to directory resources is made in such a manner that the explorer can use FindFirst/FindNext calls to present file information for network files in the same fashion as for local files. The explorer does not, by default, use multiple windows for each network's connections but presents a single hierarchical view of the entire network.

From the explorer's standpoint, nodes that are returned by the enumeration are either containers or objects, which may or may not be connectable. If they are containers, they may be enumerated further; if they are connectable, the network name returned may then be used in WNetAddConnection() to make a connection. The explorer does not need to have any knowledge of servers vs. shares.

In order to present information to the user in a form that is natural to the network (rather than representing everything in UNC format), services are provided to provide display names for resources in edit controls, drop down lists, and hierarchical views.

The following is an extract from an example network hierarchy:

NETWORK_ROOT
  NT_NETWORK
    DOMAIN_00
      SERVER_000
        SHARE_A
        SHARE_B
      SERVER_001
        SHARE_A
        SHARE_B
    DOMAIN_01
      SERVER_010
        SHARE_A
        SHARE_B
      SERVER_011
        SHARE_A
        SHARE_B
  NETWARE_NETWORK
    SERVER_1
      VOLUME_A
        DIRECTORY A
      VOLUME_B
        DIRECTORY A
    SERVER 2
      VOLUME  A
        DIRECTORY A

The names displayed are the network names returned by the NPs. The browsing UI does not initially expand the entire tree, it just shows one level. As the user opens more branches, each node is enumerated. At the top level of the hierarchy, the names are returned by the MPR, which knows what NPs are available. At lower levels, each NP is responsible for its own subtree. Each NP returns unique names for each resource within its tree. Each resource may be a container, which indicates that the browsing API can be used to enumerate further network resources contained within the resource.

In the above example, there are some interesting network specific behaviors:

Firstly, the LAN Manager NP returns domains at the top level, servers at the next level, and shares last. The first two are non-connectable containers, whereas shares are connectable objects. When connecting to a resource, the domain is not specified, and is not part of the fully qualified resource name for a share.

Secondly, a NetWare 3.11 network has servers at the top level, volumes at the next level and directories at all lower levels. An 'attach' (in NetWare terminology) to a server must be made before the volumes can be enumerated. To enumerate the directories in a volume, the user must authenticate himself to the server.


Enumeration of Connected/Persistent Resources

These are performed in a similar fashion to enumerating network resources, i.e., by an Open/Enum/Close model. However, this enumeration results in a flat list of connected resources, and not a hierarchy.

Persistent connections are the same as in Windows 3.1. Instead of each network maintaining its own list, the MPR does it all. Deviceless connections may be persistent to enable authentication at logon time.


Authentication While Browsing and Connecting

One goal of browsing in the Explorer is to be able to browse individual directories and files on the network, and reach a desired file or directory before having to make a connection. The main problem in accomplishing this is that of authentication: you cannot browse the directories on a share, for example, if you don't supply the password for the share.

This is solved by having a new WNet API for authentication. When an application attempts to enumerate the contents of a container, or access an object of some type on the network, it may receive a "not authenticated" error code. The application can then call the WNetAddConnection3 or WNetUseConnection API to gain appropriate access. WNetAddConnection3 sets up a connection to the resource, obtaining security information from the password caching subsystem or from the user using a standard dialog. Once this connection is established, the application can continue normally with its operation. Similarly, WNetUseConnection can provide a counted connection (if supported by the network), so that when the operation is finished, the application can advise the NP that it no longer is using that connection by calling WNetCancelConnection2. The underlying network can also do expiration of idle connections by itself.


System Log On

In order to present a uniform system access model to the user when multiple networks are present, and to control access to certain generic system resources such as the password caching subsystem, a system logon facility is implemented in Windows 95. This has a dialog similar to the log on in Windows for Workgroups. Individual NPs have entrypoints which are called for log on and log off, which can perform network-specific operations, optionally using the same information (user name and password) provided for the system log on or providing additional UI. Since logging off may imply unloading the user's profile (user-specific registry keys), applications are shut down at log off exactly as if the user had chosen to exit Windows. System components and service applications can detect log on and log off by listening for the WM_USERCHANGED message to be broadcast.

Because a log on can fail, the user may be logged on to some networks but not others. If the user subsequently tries to use a resource on a network where log on was unsuccessful, the log on is handled as part of the authentication process for that resource.

The user may also have a User Profile (per-user portion of the registry) stored on a network server. Since log on to that network is probably required before the profile can be accessed, one NP can be designated the Primary Logon Provider. That NP is responsible for displaying the logon UI (a service is provided to display a standard dialog) and returning the user name and password to MPR. The user is logged on to that network, the profile is loaded, and then log on occurs for other networks.

Log on can also occur when a new network card or other transmission medium is made available to the system (for example, hot-docking a portable, inserting a PCMCIA card, or establishing a dial-up connection). All network providers are called to perform additional log on in these scenarios.


User Interface

This section describes the user interface common to all networks.

The description primarily aims to describe how the Explorer browses networks, makes and breaks connections to network resources and how authentication is done.

A goal is to have as much common presentation between networks as possible without preventing NPs from using their own dialogs where necessary for network specific operations (such as authentication or browsing). To this end dialogs are provided by the MPR which can be used by any NP for connecting and authentication.


Navigating Networks (Browsing)

Network browsing is achieved using the Shell Explorer. The top level entry for each network provider is the network provider's name. The explorer uses the enumeration APIs to browse the networks. Expanding a network resource that is a container will cause one level down to be expanded (enumerated). Each network resource displays an icon based upon its resource type. The icon can be taken from a standard icon set supplied by the Shell.


Making Connections Whilst Browsing in the Explorer

There are two ways to initiate connecting to a network resource while browsing:

  • For a network resource that is connectable, there is a connect verb in the network resource's context pane. The user can select the connect verb.
  • The user can try to expand a network resource that requires a connection to the network in order to browse the objects that it contains. Browsing in this context will typically be files and directories.

There are three methods for attempting a connection:

  • If demanded by the NP, the Shell can bring up an NP provided dialog. This takes precedence over any other method.
  • The connection is attempted with the minimum necessary interaction with the user by using default values. To change or see these values, the user does so through the connection's properties pages. This connection method occurs, if possible, when the user attempts to expand a network resource. The default values are targeted at the browsing user, and hence are: use any cached authentication information, not make the connection persistent, and not associate a local DOS device.
  • The connection is attempted where the user is given full control of the values. This method is attempted when the user selects the connect verb. If authentication is required, any cached authentication information is taken, but the user is given the opportunity to change his authentication information. The user is given the option of selecting a local DOS device to associate with the connection, as well as the option to select whether or not the connection is persistent.


Remembering a Network Resource on the Desktop

Only network resources that are containers or are children of connectable containers are remembered on the desktop in a fashion meaningful to the MPR. Opening a remembered container opens an Explorer window focused on the World, expanded down to that container, therefore showing its contents. Authentication (perhaps even multiple authentications) may be necessary to accomplish this.

An attempt to remember a network resource (typically by dragging the network resource to the desktop) will as a minimum remember the network and the resource name in a link. If the resource is currently connected to, or the user has some level of authentication to the resource, then the authentication information and local DOS device (if any) will also be remembered in the link.


Connecting to a Network Resource on the Desktop

An attempt to access a network resource through a desktop resource will first be done by establishing a connection to the resource. The connection is established using default values in the same manner as for browsing (using any information stored in the link, as described in the previous section).


Network Specific UI

Each NP can provide its own network specific information on a dialog using NPDeviceMode. This will be invoked as the properties of the network in the Shell Explorer hierarchy.


Persistent Connections

On Windows startup, Logon calls the MPR to restore persistent network connections. The MPR attempts to restore all connections. If a restore fails, the user is given the option to no longer keep the connection persistent. Subsequently, restore connection may be called on specific drives from within the Shell.


Showing Existing Network Connections

A single dialog is provided that lists all the network connections (the disconnect dialog in Win31).

The dialog contains a list box which contains the current drive connections as returned by all NPs. The list is sorted by drive letter and the rightmost column displays the network name as returned by the NP. Initial selection is on the first item of the listbox, which is a single-select listbox.

Hitting "OK" disconnects selected items in the listbox & dismisses the dialog.

Persistent but unavailable connections are specifically indicated as such. Deleting (removing) a connection removes the persistence of the connection. All deletions are attempted with no force, if that fails a warning is put up and user may proceed with force if so desired.


Most Recent Connections

Whenever a connection is successfully made for any reason other than browsing, the MPR adds it to a list of most recent connections. This list is available on the Add Connection Dialog. The list may be obtained using the enumeration APIs.


WinNet16 User Interface

This section briefly describes how the user interfaces for Windows 3.1 WinNet are supported in the Windows 95 user interface.


File Manager Property Dialog Extensions

In Windows 3.1, these extensions (WNetGetPropertyText, WNetPropertyDialog) were used to allow networks to show and operate upon network specific file and directory attributes.

These extensions are not employed by the Shell in Windows 95. Networks that require network specific properties do this using the Shell Extensions to implement their own property panes.


File Manager Directory Operation hooks

This refers to the ability for a WinNet16 driver to perform its own operations on directories associated with the network, rather than letting the File Manager do it (WNetDirectoryNotify).

It should, in general, be a two phase operation for multiple networks, but is only a one phase operation. This is because it is only used for WFWG server level functionality (shared local drives).

As for the property dialog extensions, the MPR does not add to this functionality.


File Manager Directory Icon Display Hooks

This refers to the ability for a WinNet16 driver to distinguish special network directories by exporting the function WNetGetDirectoryType.

The types returned by this routine are fixed types known to the Windows 3.1 File Manager, with icons assigned by File Manager.

The MPR does not call WNetGetDirectoryType for directories that are on the network of a WinNet16 driver. Networks that require custom icons do this using Shell Extensions.


Log On

The system network logon facility for Windows 95 presents a logon dialog identical to that in Windows for Workgroups, allowing the user to type a user name and password. Network providers may display additional dialogs to handle their log on, using the standard authentication dialog or their own.

System network log off produces a simple message box informing the user that all active network connections will be disconnected. Network providers only need to warn about specific hazards of log off not covered by this generic statement.


Reference

APIs are provided to browse, connect and disconnect from network resources, and to provide information about network resources and current connections. Services are provided for functions that are common to the NPs to ensure common behavior between networks (for example, when authenticating).


Browsing Functions

The following topics describe the browsing functions.


WNetOpenEnum

This API is used to open an enumeration of network resources or existing connections. It must be called to obtain a valid handle for enumeration.

DWORD WNetOpenEnum (
    DWORD dwScope,
    DWORD dwType,
    DWORD dwUsage,
    LPNETRESOURCE lpNetResource,
    LPHANDLE lphEnum
    );
dwScope
Determines the scope of the enumeration. This can be one of:
RESOURCE_CONNECTED | All currently connected resources - this does not include persistent connections that are not currently available.
RESOURCE_GLOBALNET | All resources on the network.
RESOURCE_REMEMBERED | All persistent connections.
RESOURCE_RECENT | The most recent connections made.
RESOURCE_CONTEXT | The resources associated with the user's current and default network context.

dwType
Used to specify the type of resources and level of detail of interest. This is a bit mask which may be any combination of:
RESOURCETYPE_DISK | All disk resources.
RESOURCETYPE_PRINT | All print resources.

If dwType is RESOURCETYPE_ANY, all types of resources are returned. If an NP does not have the capability to distinguish between print and disk resources at a level, it may return all resources.

dwUsage
Used to specify the usage of resources of interest. This is a bit mask which may be any combination of:
RESOURCEUSAGE_CONNECTABLE | All connectable resources.
RESOURCEUSAGE_CONTAINER | All container resources.
RESOURCEUSAGE_ALL | All resources.

This field is ignored if dwScope is not RESOURCE_GLOBALNET.

lpNetResource
This specifies the container upon which to perform the enumeration. The NETRESOURCE could have been obtained via WNetEnumResource, constructed by the caller, or NULL. If it is NULL, the logical root of the network is assumed. An application would normally start off by calling WNetOpenEnum with this parameter set to NULL, and then use the returned results for further enumeration. If the calling program knows exactly the NP and remote path to enumerate from, it may build its own NETRESOURCE structure to pass in, filling in the lpProvider and lpRemoteName fields.. If dwScope is RESOURCE_REMEMBERED, RESOURCE_CONNECTED, or RESOURCE_RECENT this parameter may be NULL to enumerate all networks, or an lpProvider may be used to specify a particular network, with lpLocalName and lpRemoteName being ignored.
lphEnum
If function call is successful, this will contain a handle that can then be used for WNetEnumResource.
  • WN_SUCCESS if the call is successful. Other error codes include:
WN_NOT_SUPPORTED | this call is specifically returned when lpNetResource specifies a provider, dwScope is RESOURCE_GLOBALNET, and the specified provider does not support browsing.
WN_NOT_CONTAINER | lpNetResource does not point to a container
WN_BAD_VALUE | Invalid dwScope or dwUsage or dwType, or bad combination of parameters is specified.
WN_FUNCTION_BUSY | The MPR or NP is busy (possibly initializing). The caller should retry.
WN_NO_NETWORK | network is not present
WN_EXTENDED_ERROR | a network specific error occurred. WNetGetLastError should be called to obtain a description of the error.
WN_NOT_AUTHENTICATED | authentication needs to occur before the network resource can be enumerated.
WN_NOT_LOGGED_ON | a system log on needs to occur before network enumeration is possible.
WN_ACCESS_DENIED | the user is authenticated to the network where the enumeration is being attempted, but does not have sufficient permissions (access rights).

If dwScope is set to RESOURCE_GLOBALNET and the lpNetResource parameter is NULL, each NETRESOURCE structure in the returned buffer will describe a network. Each entry's lpRemoteName field will be NULL (indicating the logical root of that network), and its lpProvider field will name the network. Passing such a NETRESOURCE to a further WNetOpenEnum will enumerate the top level of that particular network.

If dwScope is set to RESOURCE_CONTEXT, each NETRESOURCE structure in the returned buffer will describe a network resource that could be from any part of a network's global browse hierarchy. In addition, the first NETRESOURCE structure in the returned buffer represents a logical root for the network, and performing a WNetOpenEnum on this NETRESOURCE will enumerate the networks in the same way as above. Specifically, the NETRESOURCE structure has the following settings:

dwScope is RESOURCE_GLOBALNET
dwType is RESOURCETYPE_ANY
dwDisplayType is RESOURCEDISPLAYTYPE_ROOT
dwUsage is RESOURCEUSAGE_CONTAINER
lpLocalName, lpRemoteName, and lpProvider, are NULL
lpComment is set to a descriptive text for the root of the network


WNetEnumResource

Perform an enumeration based on handle returned by WNetOpenEnum.

DWORD WNetEnumResource (
    HANDLE hEnum,
    LPDWORD lpcCount,
    LPVOID lpBuffer,
    LPDWORD lpBufferSize
    );
hEnum
This must be a handle obtained from WNetOpenEnum call.
lpcCount
Specifies the number of entries requested. It may be 0xFFFFFFFF to request as many as possible. On successful call, this location will receive the number of entries actually read.
lpBuffer
A pointer to the buffer to receive the enumeration result, which are returned as an array of NETRESOURCE entries.
lpBufferSize
This specifies the size of the buffer passed to the function call. If the buffer is too small to receive even one entry, this variable receives the required size of the buffer.
  • WN_SUCCESS if the call is successful, the caller should continue to call WNetEnumResource to continue the enumeration.
WN_NO_MORE_ENTRIES | no more entries found (the contents of the return buffer is undefined). Other error codes include:
WN_MORE_DATA | the buffer is too small even for one entry
WN_BAD_HANDLE | hEnum is not a valid handle.
WN_FUNCTION_BUSY | The MPR or NP is busy (possibly initializing). The caller should retry.
WN_NO_NETWORK | network is not present. This condition is checked for before hEnum is tested for validity.
WN_EXTENDED_ERROR | a network specific error occurred. WNetGetLastError should be called to obtain a description of the error.


WNetCloseEnum

Closes an enumeration.

DWORD WNetCloseEnum (
    HANDLE hEnum
    );
hEnum
This must be a handle obtained from WNetOpenEnum call.
  • WN_SUCCESS if the call is successful. Other error codes include:
WN_FUNCTION_BUSY | The MPR or NP is busy (possibly initializing). The caller should retry.
WN_NO_NETWORK | network is not present. This condition is checked for before hEnum is tested for validity.
WN_BAD_HANDLE | hEnum is not a valid handle.
WN_EXTENDED_ERROR | a network specific error occurred. WNetGetLastError should be called to obtain a description of the error.


WNetGetResourceInformation

Called to find out enumeration information for a network resource. This is typically used when an object is typed in by a user. Calling this function in conjunction with WNetGetResourceParent determines the placement and nature of the resource in the browse hierarchy. Unlike WNetGetResourceParent, WNetGetResourceInformation always tries to determine the network provider that owns the resource and the type of the resource, although it may not be currently accessible (or even exist if the type of the resource was specified by the caller).

DWORD WNetGetResourceInformation (
    LPNETRESOURCE lpNetResource,
    LPVOID lpBuffer,
    LPDWORD cbBuffer,
    LPTSTR *lplpSystem
    );
lpNetResource
This specifies the network resource for which the information is required. The lpRemoteName field of the NETRESOURCE specifies the remote name of the network resource. This would have typically been typed in by a user. If the calling program knows the values for the lpProvider, and dwType fields, then it should fill them in, because this operation can be expensive, especially without the dwType . Otherwise, it should set them to NULL. All other fields in the NETRESOURCE are ignored and do not have to be filled in.
lpBuffer
A pointer to the buffer to receive the result. The first field in the buffer is a NETRESOURCE structure. The dwScope, lpRemoteName, lpProvider, dwType and dwUsage fields are returned, all other fields being set to NULL. The remote name returned is in the same syntax as that returned from an enumeration, so that the caller can do a case sensitive string compare to determine whether an enumerated resouce is this resource. The provider name is always returned when it is known which network the resource belongs to. If the resource cannot be found on any of the networks, then lpRemoteName is returned as NULL, and lpProvider may not be NULL if a parent for the resource is known to be on one of the networks. dwScope is returned as RESOURCE_CONTEXT if the network resource is part of the user's network context, otherwise it is returned as zero.
cbBuffer
This specifies the size of the buffer passed to the function call. If the buffer is too small to receive even one entry, this variable receives the required size of the buffer.
lplpSystem
Returned pointer to a string in the buffer pointed to by lpBuffer that specifies the part of the resource that is accessed through system resource type specific APIs rather than WNet APIs. For example, if the input remote resource name was "\\server\share\dir", then lpRemoteName is returned pointing to "\\server\share" and lplpSystem points to "\dir", both strings being stored in the buffer pointed to by lpBuffer.
  • WN_SUCCESS if the call is successful. Other error codes include:
WN_BAD_NETNAME | lpRemoteName is not an existing network resource for any network If the lpProvider field is not NULL, then a parent of the network resource does exist and can be accessed by calls to WNetGetResourceParent.
WN_MORE_DATA | the buffer is too small for the information
WN_NO_NETWORK | network is not present.
WN_EXTENDED_ERROR | a network specific error occurred. WNetGetLastError should be called to obtain a description of the error.


WNetGetResourceParent

This function can be called to navigate up from a resource, and enables browsing to commence based upon the name of a network resource. It also allows navigating up from a browsed resource to find connectable resources.

WNetGetResourceParent can be called for names that were returned from a call to WNetEnumResource. Unlike WNetGetResourceInformation, if the resource syntactically has a parent, then this is returned by WNetGetResourceParent, whether or not the parent actually exists or not.

DWORD WNetGetResourceParent(
    LPNETRESOURCE lpNetResource,
    LPVOID lpBuffer,
    LPDWORD lpBufferSize
    );
lpNetResource
This specifies the network resource for which the parent name is required. The NETRESOURCE could have been obtained via a previous WNetEnumResource, or constructed by the caller. The lpRemoteName field of the NETRESOURCE specifies the remote name of the network resource whose parent name is required. If the calling program knows the values for the lpProvider, and dwType fields (as it typically should, since it will have previously called WNetGetResourceInformation), then it should fill them in. Otherwise, it should set them to NULL. All other fields in the NETRESOURCE are ignored and do not have to be filled in.
lpBuffer
A pointer to the buffer to receive the result, which is returned as a single NETRESOURCE entry representing the parent resource. The lpRemoteName, lpProvider, dwType and dwUsage fields are returned, all other fields being set to NULL. The remote name returned is in the same syntax as that returned from an enumeration, so that the caller can do a case sensitive string compare to determine whether an enumerated resouce is this resource. The provider name is returned only if it is known which network the resource belongs to. If several networks could own the resource, (as may be the case for a resource such as "\\server"), then lpProvider will be set to NULL. If a resource has no parent on any of the networks, then lpRemoteName is returned as NULL. If it is known that a network owns a parent of the resource, but that the resource itself is not valid, then lpProvider is returned as a non-null value together with a return status of WN_BAD_NETNAME. Note that if a network thinks that the object is on the network, but has no parent (e.g. a server that is not part of a workgroup), then there is the possibility that this API may return with lpRemoteName and lpProvider both set to NULL. The RESOURCEUSAGE_CONNECTABLE value in the dwUsage field does not indicate that the resource can currently be connected to, but that the resource is connectable when it is available on the network.
lpBufferSize
This specifies the size in bytes of the buffer passed to the function call. If the result is WN_MORE_DATA, this will contain the buffer size required (in bytes) to hold the NETRESOURCE information.
  • WN_SUCCESS if the call is successful.
WN_MORE_DATA | if input buffer is too small.
WN_BAD_PROVIDER | lpProvider does not match any NP
WN_BAD_NETNAME | lpRemoteName is not a syntactically valid name for a remote resource for any network
WN_NOT_AUTHENTICATED | the caller does not have the necessary permissions to obtain the name of the parent.
WN_ACCESS_DENIED | the user is authenticated to the network, but does not have sufficient permissions (access rights).


Connection Functions

The following topics describe the connection functions.


WNetAddConnection

This function allows the caller to redirect (connect) a local device to a network resource. If successful, the connection will be made persistent.

DWORD WNetAddConnection(
    LPTSTR lpRemoteName,
    LPTSTR lpPassword,
    LPTSTR lpLocalName
    );
lpRemoteName
Specifies the network resource to connect to. This is limited to MAX_PATH.
lpPassword
Specifies the password to be used in making the connection.

The NULL value or string may be passed in to indicate that the caller wants the network to use the best password(s) it has available (such as no password, a default password, or an internally cached password).

lpLocalName
This should contain the name of a local device to be redirected, such as "F:" or "LPT1". The string is treated in a case insensitive manner, and may be the empty string (or NULL) to indicate the connection to the network resource is to be made without a device redirection (i.e., deviceless connection).
  • WN_SUCCESS if the call is successful. Other error codes include:
ERROR_BAD_DEV_TYPE | The device type and the resource type do not match.
WN_BAD_NETNAME | lpRemoteName is not acceptable to any NP
WN_BAD_LOCALNAME | lpLocalName is invalid.
WN_BAD_PASSWORD | invalid password, or the connection requires additional authentication not provided by the caller (for example, a user name)
WN_ALREADY_CONNECTED | lpLocalName is already connected to a network drive or is to a local drive that is already in use locally (e.g. is used for a hard drive or RAM drive).
WN_ACCESS_DENIED | access denied (user may need to log on)
WN_NO_NETWORK | network is not present
WN_CANNOT_OPEN_PROFILE | Unable to open the user profile to process persistent connections.
WN_BAD_PROFILE | The user profile is in an incorrect format.
WN_FUNCTION_BUSY | The MPR or NP is busy (possibly initializing). The caller should retry.
WN_NO_NET_OR_BAD_PATH | the operation could not be handled either because a network component is not started or the specified name could not be handled.
WN_EXTENDED_ERROR | a network specific error occurred. WNetGetLastError should be called to obtain a description of the error.


WNetAddConnection2

This function allows the caller to redirect (connect) a local device to a network resource. It is similar to WNetAddConnection, except that it takes a pointer to a NETRESOURCE structure to describe the network resource to connect to. It also takes the addition parameters lpUserID and dwFlags.

DWORD WNetAddConnection2(
    LPNETRESOURCE lpNetResource,
    LPTSTR lpPassword,
    LPTSTR lpUserID,
    DWORD dwFlags
    );
lpNetResource
Specifies the network resource to connect to. This structure is defined the section describing Enumeration APIs. The following fields must be set when making a connection, the others are ignored.
lpRemoteName | Specifies the network resource to connect to. This is limited to MAX_PATH.
lpLocalName | This specifies the name of a local device to be redirected, such as "F:" or "LPT1". The string is treated in a case insensitive manner, and may be the empty string (or NULL) in which case a connection to the network resource is made without making a redirection.
lpProvider | Specifies the NP to connect to. If NULL or empty string, Windows will try each NP in turn. The caller should set lpProvider only if it knows for sure which network it wants. Otherwise, it is preferable to let Windows determine which NP the network name maps to. If this is non NULL, Windows will try the named NP and no other.
dwType | Specifies the type of resource to connect to. It must be RESOURCETYPE_DISK or RESOURCETYPE_PRINT if lpLocalName is not the empty string. It may also be RESOURCETYPE_ANY if lpLocalName is the empty string.

lpPassword
Specifies the password to be used in making the connection, normally the password associated with lpUserID. A NULL value or string may be passed in to indicate to the function to use the current default password.
lpUserID
This specifies the identity of the user needed to make the connection. If NULL, a default will be applied. This is used when the user wishes to connect to a resource, but has a different user name or account assigned to him for that resource. This identification represents a security context, and is NP specific.
dwFlags
This is a bit mask which may have any of the following bits set:
CONNECT_UPDATE_PROFILE If the connection should be made persistent. If set, Windows automatically restores this connection when the user logs on to the network. A connection is only made persistent if the connection was successful.

  • WN_SUCCESS if the call is successful. Other error codes include:
ERROR_BAD_DEV_TYPE | The device type and the resource type do not match.
WN_BAD_PROVIDER | lpProvider does not match any NP
WN_BAD_NETNAME | lpRemoteName is not acceptable to any NP
WN_BAD_LOCALNAME | lpLocalName is invalid.
WN_BAD_PASSWORD | invalid password, or the connection requires additional authentication not provided by the caller (for example, a user name)
WN_ALREADY_CONNECTED | lpLocalName is already connected to a network drive or is to a local drive that is already in use locally (e.g. is used for a hard drive or RAM drive).
WN_ACCESS_DENIED | access denied (user may need to log on)
WN_CANNOT_OPEN_PROFILE | Unable to open the user profile to process persistent connections.
WN_BAD_PROFILE | The user profile is in an incorrect format.
WN_FUNCTION_BUSY | The MPR or NP is busy (possibly initializing). The caller should retry.
WN_NO_NETWORK | network is not present
WN_NO_NET_OR_BAD_PATH | the operation could not be handled either because a network component is not started or the specified name could not be handled.
WN_EXTENDED_ERROR | a network specific error occurred. WNetGetLastError should be called to obtain a description of the error.


WNetAddConnection3

This function is used to establish a connection to a network object The routine may optionally prompt the user for login or authentication.

DWORD WNetAddConnection3(
    HWND hwndOwner,
    LPNETRESOURCE lpNetResource,
    LPTSTR lpPassword,
    LPTSTR lpUserID,
    DWORD dwFlags
    );
hwndOwner
A handle to a window which should be the owner for any messages or dialogs the network provider might display. This is used if CONNECT_INTERACTIVE is set.
lpNetResource
Specifies the network resource to connect to. This structure is defined the section describing Enumeration APIs. The following fields must be set when making a connection, the others are ignored.
lpRemoteName | Specifies the network resource to connect to. This is limited to MAX_PATH.
lpLocalName | Pointer to a buffer that specifies the local device name that is to be redirected, such as "F:" or "LPT1".
The string is treated in a case insensitive manner, and may be the empty string (or NULL) in which case a connection to the network resource is made without making a redirection.
lpProvider | Specifies the NP to connect to. If NULL or empty string, Windows will try each NP in turn. The caller should set lpProvider only if it knows for sure which network it wants. Otherwise, it is preferable to let Windows determine which NP the network name maps to. If this is non NULL, Windows will try the named NP and no other.
dwType | Specifies the type of resource to connect to. It must be RESOURCETYPE_DISK or RESOURCETYPE_PRINT if lpLocalName is not the empty string. It may also be RESOURCETYPE_ANY if lpLocalName is the empty string.

lpPassword
Specifies the password to be used in making the connection, normally the password associated with lpUserID. A NULL value or string may be passed in to not specify the password. If the password is invalid or not specified, then the function tries to use the current default password. If this fails and CONNECT_INTERACTIVE is set, the function posts an appropriate dialog asking the user to type/retype the password.
lpUserID
This specifies the identity of the user needed to make the connection. If NULL, a default will be applied. This is used when the user wishes to connect to a resource, but has a different user name or account assigned to him for that resource. This identification represents a security context, and is NP specific.

This user specific information is stored to be subsequently used in re-establishing the connection (using a non-default user name or telephone number, for example).

dwFlags
Any combination of the following values:
CONNECT_TEMPORARY | The connection is being established for browsing purposes and can be released quickly.
CONNECT_INTERACTIVE | May have interaction with the user for authentication purposes.
CONNECT_PROMPT | Do no use any defaults for user names or passwords without offering user the chance to supply an alternative. This flag is only valid if CONNECT_INTERACTIVE is set.
CONNECT_UPDATE_PROFILE | If the connection should be made persistent. If set, the connection is automatically restored every time the user starts up and logs on to the network. A connection is only made persistent if the connection was successful. This flag is only valid if lpLocalName specifies a local device to redirect.
CONNECT_UPDATE_RECENT | If the connection should be put in the recent connection list. If set, and the connection is successfully added, it will be put in the recent connection list. This flag should typically have the opposite value to CONNECT_TEMPORARY.

  • WN_SUCCESS if the call is successful.
WN_CANCEL | the user cancelled the add connection attempt through some user interface.
WN_BAD_PROVIDER | lpProvider does not match any NP
WN_BAD_NETNAME | lpRemoteName is not acceptable to any NP
WN_BAD_LOCALNAME | lpLocalName is invalid.
WN_BAD_PASSWORD | bad password and CONNECT_INTERACTIVE is not set.
WN_NOT_AUTHENTICATED | the call failed because the connection requires additional authentication information (for example, a user name or a password), not provided by the caller or the user through a dialog.
WN_NOT_LOGGED_ON | a system log on needs to occur before a network connection can be added.
WN_ALREADY_CONNECTED | lpLocalName already connected or is to a local drive that is already in use locally (for example, is used for a hard drive or RAM drive).
WN_ACCESS_DENIED | access denied.
WN_CANNOT_OPEN_PROFILE | Unable to open the user profile to process persistent connections.
WN_BAD_PROFILE | The user profile is in an incorrect format.
WN_FUNCTION_BUSY | The MPR or NP is busy (possibly initializing). The caller should retry.
WN_NO_NETWORK | network is not present
WN_NO_NET_OR_BAD_PATH | the operation could not be handled either because a network component is not started or the specified name could not be handled.
WN_EXTENDED_ERROR | a network specific error occurred. WNetGetLastError should be called to obtain a description of the error.


WNetUseConnection

This function is used to establish a connection to a network object, especially for browsing . The function may optionally prompt the user for login or authentication. The connection is usually on a redirected local drive or a reference counted session (in which case this call increments the reference count to the session), although for some networks it may be on a non-reference counted session that does not have a local device redirection. See WNetCancelConnection2 for details on cancelling the connection

In addition, for file and disk resources, this API can return a name for the connection that can be pre-pended to file system requests on the network resource (e.g. "\\server\share" or "F:"). This enables directory service lookup. The API can also auto-pick a local device for redirecting local devices to networks that require local device redirection.

DWORD WNetUseConnection(
    HWND hwndOwner,
    LPNETRESOURCE lpNetResource,
    LPTSTR lpPassword,
    LPTSTR lpUserID,
    DWORD dwFlags,
    LPTSTR lpAccessName,
    LPDWORD lpBufferSize,
    LPDWORD lpResult
    );
hwndOwner
A handle to a window which should be the owner for any messages or dialogs the network provider might display. This is used if CONNECT_INTERACTIVE is set.
lpNetResource
Specifies the network resource to connect to. This structure is defined the section describing Enumeration APIs. The following fields must be set when making a connection, the others are ignored.
lpRemoteName | Specifies the network resource to connect to.
lpLocalName | Pointer to a buffer that specifies the local device name that is to be redirected, such as "F:" or "LPT1".
The string is treated in a case insensitive manner, and may be the empty string (or NULL) in which case either a connection to the network resource is made without making a redirection or, if CONNECT_REDIRECT is set or the network requires a redirected local device and none is specified a redirection is picked by the system which is returned in lpAccessName.
lpProvider | Specifies the NP to connect to. If NULL or empty string, Windows will try each NP in turn. The caller should set lpProvider only if it knows for sure which network it wants. Otherwise, it is preferable to let Windows determine which NP the network name maps to. If this is non NULL, Windows will try the named NP and no other.
dwType | Specifies the type of resource to connect to. It is most efficient to use a specific resource type (RESOURCETYPE_DISK or RESOURCETYPE_PRINT). It may be RESOURCETYPE_ANY if lpLocalName is the empty string and CONNECT_REDIRECT is not set.

lpPassword
Specifies the password to be used in making the connection, normally the password associated with lpUserID. A NULL value or string may be passed in to not specify the password. If the password is invalid or not specified, then the function tries to use the current default password. If this fails and CONNECT_INTERACTIVE is set, the function posts an appropriate dialog asking the user to type/retype the password.
lpUserID
This specifies the identity of the user needed to make the connection. If NULL, a default will be applied. This is used when the user wishes to connect to a resource, but has a different user name or account assigned to him for that resource. This identification represents a security context, and is NP specific.

This user specific information is stored to be subsequently used in re-establishing the connection (using a non-default user name or telephone number, for example).

dwFlags
Any combination of the following bit values:
CONNECT_TEMPORARY | The connection is being established for browsing purposes.
CONNECT_INTERACTIVE | May have interaction with the user for authentication purposes.
CONNECT_PROMPT | Do no use any defaults for user names or passwords without offering user the chance to supply an alternative. This flag is only valid if CONNECT_INTERACTIVE is set.
CONNECT_UPDATE_PROFILE | If the connection should be made persistent. If set, the connection is automatically restored every time the user starts up and logs on to the network. A connection is only made persistent if the connection was successful. This flag is only valid if lpLocalName specifies a local device to redirect, as otherwise it is ignored.
CONNECT_UPDATE_RECENT | If the connection should be put in the recent connection list. If set, and the connection is successfully added, it will be put in the recent connection list only if it has a redirected local device associated with it.
CONNECT_REDIRECT | If set, force the auto-picking of a local device for redirection when making the connection, otherwise only auto-pick a local device for redirection if the network requires it to make a connection.
This flag is ignored if lpLocalName specifies a local device to redirect (since a redirection will always be attempted to the local device name specified in lpLocalName). Otherwise, setting this flag is invalid if either lpAccessName does not point to a return buffer (since the caller will not readily know how to access the resource) or dwType is RESOURCETYPE_ANY.
CONNECT_CURRENT_MEDIA | If set, then do not start to use a new media to try to establish the connection (for example, do not initiate a new dial up connection).

lpAccessName
Points to a buffer to receive the name that can be used to make system requests on the connection. This conversion is useful for adding connections to aliased resources, such as through a directory service, and for autopicking of local devices for redirection.

If lpLocalName specifies a local device, then this buffer is optional, and if specified will have the local device name copied into it.Otherwise, if the network requires a local device redirection, or CONNECT_REDIRECT is set, then this buffer is required and the redirected local device is returned here. Otherwise, the name copied into the buffer is that of a remote resource, and if specified, this buffer must be at least as large as the string pointed to by lpRemoteName.

lpBufferSize
This is used to specify the size of the lpAccessName buffer passed in. If the call fails because the buffer is not big enough, this location will be used to return the required buffer size.
lpResult
Pointer to a DWORD in which is returned additional information about the connection. Currently has the following bit value:
CONNECT_REFCOUNT | The connection was made without using a local device redirection and is to a network that understands reference counted sessions. If this bit is not set, then calling WNetCancelConnection2 will end the session and possibly interfere with other threads or processes that may be using the session. If this bit is set then calling WNetCancelConnection2 with CONNECT_REFCOUNT set in the dwFlags parameter will decrement the reference count to the connection and not interfere with other threads that are using the session.
CONNECT_LOCALDRIVE | If set, the connection was made using a local drive redirection. If lpAccessName points to a buffer then the local drive is copied to the buffer.

  • WN_SUCCESS if the call is successful.
WN_CANCEL | the user cancelled the add connection attempt through some user interface.
WN_BAD_PROVIDER | lpProvider does not match any NP.
WN_BAD_NETNAME | lpRemoteName is not acceptable to any NP.
WN_BAD_LOCALNAME | lpLocalName is invalid.
WN_BAD_PASSWORD | bad password and CONNECT_INTERACTIVE is not set.
WN_BAD_VALUE | one of the following: lpRemoteName is NULL; lpRemoteName is not NULL, and lpBufferSize is either NULL or points to zero; dwType is neither RESOURCETYPE_DISK nor RESOURCETYPE_PRINT, and either CONNECT_REDIRECT is set in dwFlags or lpLocalName is not NULL or the connection is to a network that requires a local device redirection to make a connection;
WN_BAD_POINTER | lpAccessName does not point to a buffer and either CONNECT_REDIRECT is set in dwFlags or a connection is being attempted to a network that requires a local device redirection which is not specified in lpLocalName.
WN_MORE_DATA | the lpAccessName buffer is too small. If a local device is redirected, the buffer needs to large enough to contain the local device name. Otherwise the buffer needs to be large enough to contain either the string pointed to by lpRemoteName or the name of the connectable resource whose alias is pointed to by lpRemoteName. If this status is returned, then no connection has been made.
WN_NO_MORE_ENTRIES | a local redirection cannot be auto-picked because all of the valid local devices for the network are in use.
WN_NOT_AUTHENTICATED | the call failed because the connection requires additional authentication information (for example, a user name or a password), not provided by the caller or the user through a dialog.
WN_NOT_LOGGED_ON | a system log on needs to occur before a network connection can be added.
WN_ALREADY_CONNECTED | lpLocalName is already connected to a network drive or is to a local drive that is already in use locally (for example, is used for a hard drive or RAM drive).
WN_ACCESS_DENIED | access denied.
WN_CANNOT_OPEN_PROFILE | Unable to open the user profile to process persistent connections.
WN_BAD_PROFILE | The user profile is in an incorrect format.
WN_FUNCTION_BUSY | The MPR or NP is busy (possibly initializing). The caller should retry.
WN_NO_NETWORK | network is not present.
WN_NO_NET_OR_BAD_PATH | the operation could not be handled either because a network component is not started or the specified name could not be handled.
WN_EXTENDED_ERROR | a network specific error occurred. WNetGetLastError should be called to obtain a description of the error.

See Also

WNetCancelConnection2


WNetCancelConnection

This function breaks an existing network connection. This function is equivalent to WNetCancelConnection2 with CONNECT_UPDATE_PROFILE set for dwFlags, i.e., the list of persistent connections will be updated so that Windows will no longer restore this connection.

DWORD WNetCancelConnection(
    LPTSTR lpName,
    BOOL fForce
    );
lpName
The name of either the redirected local device or the remote network resource to disconnect from. In the former case, only the redirection specified is broken, in the latter case only the deviceless connection to the remote network resource is broken.
fForce
Used to indicate if the disconnect should be done forcefully in the event of open files or jobs on the connection. If FALSE is specified, the call will fail if there are open files or jobs.
  • WN_SUCCESS if the call is successful. If the connection does not exist for any of the NPs but is persistent and the MPR successfully deleted the persistent connection, this is treated as a successful call. Other error codes include:
WN_NOT_CONNECTED | lpName not a redirected (nor persistent) device, or not currently connected to lpName
WN_CANNOT_OPEN_PROFILE | Unable to open the user profile to process persistent connections.
WN_DEVICE_IN_USE | The device is in use by an active process and cannot be disconnected.
WN_BAD_PROFILE | The user profile is in an incorrect format.
WN_OPEN_FILES | there are open files and fForce was FALSE.
WN_FUNCTION_BUSY | The MPR or NP is busy (possibly initializing). The caller should retry.
WN_EXTENDED_ERROR | a network specific error occurred. WNetGetLastError should be called to obtain a description of the error.


WNetCancelConnection2

This function breaks an existing network connection. It may also be used to remove a persistent connection for which there is no existing network connection.

When WNetCancelConnection2 is called it removes the connection entirely if it is to a redirected local device or a non-reference counted session, or if CONNECT_REFCOUNT bit is not set in the dwFlags parameter. Otherwise WNetCancelConnection2 decrements the reference count to the session and removes the session when it is no longer being referenced.

DWORD WNetCancelConnection2(
    LPTSTR lpName,
    DWORD dwFlags,
    BOOL fForce
    );
lpName
The name of either the redirected local device or the remote network resource to disconnect from. In the former case, only the redirection specified is broken, in the latter case only the deviceless connection to the remote network resource is broken. If WNetUseConnection was called to make the connection with a non-empty lpLocalName field, then lpName is set to this, otherwise it should be the name that was returned in the lpAccessName field.
dwFlags
This is a bit mask which may have any of the following bits set:
CONNECT_UPDATE_PROFILE | If the disconnection should remain persistent. If set, Windows will no longer restore this connection when the user logs on.
CONNECT_REFCOUNT | If this bit is not set, the connection is to a redirected local device, or the connection is not reference counted, then the connection is cancelled completely (which will interfere with other threads or processes that are using the connection). If this bit is set and the connection supports reference counts then the reference count to the connection is descremented. When nothing is referencing the connection it is cancelled.

fForce
Used to indicate if the disconnect should be done forcefully in the event of open files or jobs on the connection. If FALSE is specified, the call will fail if there are open files or jobs. If TRUE is specified, then CONNECT_REFCOUNT must not be set in dwFlags.
  • WN_SUCCESS if the call is successful. If the connection does not exist for any of the NPs but is persistent and the MPR successfully deleted the persistent connection, this is treated as a successful call. Other error codes include:
WN_NOT_CONNECTED | lpName not a redirected or persistent device, or not currently connected to lpName.
WN_CANNOT_OPEN_PROFILE | Unable to open the user profile to process persistent connections.
WN_DEVICE_IN_USE | The device is in use by an active process and cannot be disconnected.
WN_BAD_PROFILE | The user profile is in an incorrect format.
WN_OPEN_FILES | there are open files and fForce was FALSE.
WN_FUNCTION_BUSY | The MPR or NP is busy (possibly initializing). The caller should retry.
WN_EXTENDED_ERROR | a network specific error occurred. WNetGetLastError should be called to obtain a description of the error.


WNetGetConnection

This function is used to determine the name of the network resource associated with a local device.

DWORD WNetGetConnection(
    LPTSTR lpLocalName,
    LPTSTR lpRemoteName,
    LPDWORD lpBufferSize
    );
lpLocalName
Contains the name of the local device the caller is interested in.
lpRemoteName
Points to a buffer to receive the remote name used to make the connection.
lpBufferSize
This is used to specify the size of the buffer passed in. If the call fails because the buffer is not big enough, this location will be used to return the required buffer size.
  • WN_SUCCESS if the call is successful. Other error codes include:
WN_BAD_LOCALNAME | lpLocalName is invalid
WN_NOT_CONNECTED | lpLocalName not a redirected device
WN_MORE_DATA | the buffer is too small
WN_CONNECTION_CLOSED | the device is not currently connected, but it is a persistent connection.
WN_FUNCTION_BUSY | The MPR or NP is busy (possibly initializing). The caller should retry.
WN_NO_NETWORK | network is not present
WN_EXTENDED_ERROR | a network specific error occurred. WNetGetLastError should be called to obtain a description of the error.


WNetSetConnection

This function is used to change the characteristics of a network connection.

DWORD WNetSetConnection(
    LPCTSTR lpName,
    DWORD dwProperty,
    LPVOID pvValue
    );
lpName
The name of either the redirected local device or a remote network resource.
dwProperty
A value representing the type of property to change. There is currently only one property type:
NETPROPERTY_PERSISTENT the persistent property. The corresponding property value is a DWORD. lpName must be the name of a redirected local device. If the property value is TRUE, the connection is made persistent with the current user authentication. . If the property value is FALSE, then the connection is made no longer persistent without breaking any current connection to the network (if not currently connected to the network, this is the same effect as cancelling the connection).

pvValue
Pointer to the property value for the property type supplied. The data type of the property value depends upon the property type.
  • WN_SUCCESS if the call is successful. Other error codes include:
WN_NOT_CONNECTED lpName not a redirected device


WNetGetUniversalName

This function is used to get Universal information about a network name which is referred to using a local device name. The following levels of information can be obtained about a network name.

DWORD WNetGetUniversalName (
    LPTSTR lpLocalPath,
    DWORD dwInfoLevel,
    LPVOID lpBuffer,
    LPDWORD lpBufferSize
    );
lpLocalPath
Contains the local path to an object on a network resource. This path is drive based path.
dwInfoLevel
The level of detail of information the caller is interested in as described above.
lpBuffer __
Points to a buffer to receive the info the user has requested. The specific structure returned is one of those described above.
lpBufferSize
This is used to specify the size, in bytes, of the buffer passed in. If the call fails because the buffer is not big enough, this location will be used to return the required buffer size.
  • WN_SUCCESS if the call is successful. Otherwise, GetLastError should be called for extended error information. Extended error codes include:
WN_BAD_LOCALNAME | lpLocalName is invalid
WN_NOT_CONNECTED | lpLocalName not a redirected device
WN_MORE_DATA | the buffer is too small
WN_CONNECTION_CLOSED | the device is not currently connected, but it is a remembered (persistent) connection.
WN_FUNCTION_BUSY | The router or provider is busy (possibly initializing). The caller should retry.
WN_NO_NETWORK | network is not present.
WN_NOT_SUPPORTED | This function is not supported by any of the providers.
WN_EXTENDED_ERROR | a network specific error occured. WNetGetLastError should be called to obtain a description of the error.


UNIVERSAL_NAME_INFO Structure

#define UNIVERSAL_NAME_INFO_LEVEL 1
#define REMOTE_NAME_INFO_LEVEL 2

typedef struct _UNIVERSAL_NAME_INFO {
    LPTSTR lpszUniversalName;
} UNIVERSAL_NAME_INFO, *LPUNIVERSAL_NAME_INFO;
lpszUniversalName
If the provider supports a Universal Name then it will return that here.


REMOTE_NAME_INFO Structure

typedef struct _REMOTE_NAME_INFO {
    LPTSTR lpszUniversalName;
    LPTSTR lpszConnectionName;
    LPTSTR lpszRemainingPath;
} REMOTE_NAME_INFO, *LPREMOTE_NAME_INFO;
lpszUniversalName
Points to the Universal Name if the provider supports that. Otherwise this element will be a NULL pointer.
lpszConnectionName
Points to the remote name used to make the connection. This does not have a backslash at the end of the name.
lpszRemainingPath
The remaining path that needs to be concatenated to drive letter once a connection is established using above ConnectionInfo, to refer to the same object again. This path starts with a backslash.


Other Functions

The following topics describe additional functions.


WNetGetUser

This is used to determine either the current default user name, or the user identification used to establish a network connection.

DWORD WNetGetUser(
    LPTSTR lpName,
    LPTSTR lpUserID,
    LPDWORD lpBufferSize
    );
lpName
Contains the name of the local device the caller is interested in, or the name of a remote network resource that the user has made a connection to, or the name of a network provider, or NULL or the empty string if the caller is interested in the name of the user currently logged on to the system.
lpUserID
Points to a buffer to receive the user profile name. This is an identification string that the user made to establish the connection (for example, a user name, or group name).

If the name passed in is a network provider and the network does not have a network wide log on, then an empty string is returned.

If a network resource name is passed in, and the user is connected to that resource using different names, it is possible that a NP cannot resolve which user profile name to return. In this case the NP may make an arbitrary choice amongst the possible user names.

lpBufferSize
  • This is used to specify the size of the buffer passed in. If the call fails because the buffer is not big enough, this location is used to return the WN_SUCCESS if the call is successful. Other error codes include:
WN_NOT_LOGGED_ON | the user is not logged on to the system (lpName empty) or network (lpName a valid provider name).
WN_NOT_CONNECTED | lpName not a redirected device nor a connected network name.
WN_NOT_SUPPORTED | lpName is the name of a network that does not support network wide log on.
WN_MORE_DATA | the buffer is too small
WN_FUNCTION_BUSY | The MPR or NP is busy (possibly initializing). The caller should retry.
WN_NO_NETWORK | network is not present.
WN_EXTENDED_ERROR | a network specific error occurred. WNetGetLastError should be called to obtain a description of the error.


WNetConnectionDialog

This function brings up a general browsing dialog for connecting to network resources.

DWORD WNetConnectionDialog (
    HWND hwnd,
    DWORD dwType
    );
hwnd
This specifies the HWND of the owning window.
dwType
Used to specify the type of resources of interest. Currently, this may be one of:
RESOURCETYPE_DISK | Connect to disk resources.
RESOURCETYPE_PRINT | Connect to print resources.

  • WN_SUCCESS if the call is successful in bringing up the dialog. Other error codes include the following. Typically this dialog will only return an error if the dialog could not be brought up since errors that occur thereafter are reported to the user directly.
WN_FUNCTION_BUSY | The MPR or NP is busy (possibly initializing). The caller should retry.
WN_NO_NETWORK | network is not present.
WN_OUT_OF_MEMORY | insufficient memory to bring up the dialog.
WN_EXTENDED_ERROR | a network specific error occurred. WNetGetLastError should be called to obtain a description of the error.


WNetConnectionDialog1

This function brings up a general browsing dialog for connecting to network resources.

DWORD WNetConnectionDialog1 (
    LPCONNECTDLGSTRUCT lpConnectDlgStruct
    );

typedef struct {
    DWORD cbStructure;
    HWND hwndOwner;
    LPNETRESOURCE lpConnRes;
    DWORD dwFlags;
    DWORD dwDevNum;
} CONNECTDLGSTRUCT, FAR *LPCONNECTDLGSTRUCT;
cbStructure
Contains the size of this structure in bytes.
hwndOwner
This specifies the HWND of the owning window.
lpConnRes
A NETRESOURCE structure. If lpConnRes.lpRemoteName is specified, this field will be entered into the path field of the dialog. All other fields must be set to NULL except lpConnRes.dwType which specifies the type of resources of interest, and must be one of:
RESOURCETYPE_DISK | Connect to disk resources.
RESOURCETYPE_PRINT | Connect to print resources.

dwFlags
Specifies variations in the dialog display. To simulate WNetConnectionDialog, set this to CONNDLG_USE_MRU. Currently, this may be one of:
CONNDLG_RO_PATH | Instead of allowing user to type in flag, have a read only path already inserted. This flag should only be set if lpConnRes.lpRemoteName is not NULL (or an empty string), and CONNDLG_USE_MRU is not set.
CONNDLG_CONN_POINT | Internal flag. Do not use.
CONNDLG_USE_MRU | Fill up the combobox, listing most recently used paths.
CONNDLG_HIDE_BOX | Show the checkbox allowing the user to select whether or not the connection should be restored at log on.
CONNDLG_PERSIST | Set if the connection is to be restored at log on.
CONNDLG_NOT_PERSIST | Set if the connection is not to be restored at log on.

dwDevNum
If call is successful, this returns the number of the device connected to.

If neither CONNDLG_RO_PATH or CONNDLG_USE_MRU is set in dwFlags, then the request defaults to CONNDLG_RO_PATH if lpConnRes.lpRemoteName does not specify a remote path and to CONNDLG_USE_MRU otherwise. CONNDLG_PERSIST and CONNDLG_NOT_PERSIST cannot both be set. If neither is set, then the dialog defaults to the last option that was selected on this dialog for the particular type of device being connected.

  • WN_SUCCESS if the call is successful in bringing up the dialog. Other error codes include the following. Typically this dialog will only return an error if the dialog could not be brought up since errors that occur thereafter are reported to the user directly. If the call is sucessful, dwDevNum will contain the number of the device connected to.
WN_BAD_VALUE | one of the following: CONNDLG_RO_PATH is set and either CONNDLG_USE_MRU is set or lpConnRes.lpRemoteName does not point to a remote name; both CONNDLG_PERSIST and CONNDLG_NOT_PERSIST are set.
WN_BAD_DEV_TYPE | lpConnRes.dwType is not set to either RESOURCETYPE_DISK or RESOURCETYPE_PRINT.
WN_FUNCTION_BUSY | The MPR or NP is busy (possibly initializing). The caller should retry.
WN_NO_NETWORK | network is not present.
WN_OUT_OF_MEMORY | insufficient memory to bring up the dialog.
WN_EXTENDED_ERROR | a network specific error occurred. WNetGetLastError should be called to obtain a description of the error.

See Also

NETRESOURCE


WNetDisconnectDialog

This function brings up a general dialog for disconnecting from network resources. When the dialog attempts to disconnect and an NP returns WN_OPEN_FILES, it prompts the user for confirmation.

DWORD WNetDisconnectDialog (
    HWND hwnd,
    DWORD dwType
    );
hwnd
This specifies the HWND of the owning window.
dwType
Used to specify the type of resources of interest. This must be one of:
RESOURCETYPE_DISK | Connect to disk resources.
RESOURCETYPE_PRINT | Connect to print resources.

  • WN_SUCCESS if the call is successful in bringing up the dialog. Other error codes include the following. Typically this dialog will only return an error if the dialog could not be brought up since errors that occur thereafter are reported to the user directly.
WN_FUNCTION_BUSY | The MPR or NP is busy (possibly initializing). The caller should retry.
WN_NO_NETWORK | network is not present.
WN_OUT_OF_MEMORY | insufficient memory to bring up the dialog.
WN_EXTENDED_ERROR | a network specific error occurred. WNetGetLastError should be called to obtain a description of the error.


WNetDisconnectDialog1

This function attempts to disconnect from a network resource. If an NP returns WN_OPEN_FILES, it prompts the user for confirmation. If there is any error, it informs the user.

DWORD WNetDisconnectDialog1(
      LPDISCDLGSTRUCT lpConnDlgStruct
    );
lpConnDlgStruct
Pointer to a structure that describes the required behavior for the diconnect attempt. This structure has the following format:


DISCDLGSTRUCT Structure

typedef struct _DISCDLGSTRUCT{
    DWORD cbStructure;
    HWND hwndOwner;
    LPSTR lpLocalName;
    LPSTR lpRemoteName;
    DWORD dwFlags;
} DISCDLGSTRUCT, *LPDISCDLGSTRUCT;
cbStructure
The size of the DISCDLGSTRUCT structure in bytes. This is filled in by the caller to indicate the size of the structure passed in.
hwndOwner | This specifies the HWND of the owning window.
lpRemoteName | Specifies the network resource to disconnect. This field may be set to NULL is lpLocalName is specified in which case the connection to the resource redirected from lpLocalName is disconnected.
lpLocalName | The local device name that is redirected to the network resource, such as "F:" or "LPT1".

dwFlags
Any combination of the following values:
DISC_UPDATE_PROFILE | If set, the connection will no longer be persistent (automatically restored every time the user logs on to the network). This flag is only valid if lpLocalName specifies a local device.
DISC_NO_FORCE | If not set, force will be applied when attempting the disconnect if this is required (typically because the user has open files). The user will be informed if there are open files to the connection and asked if he still wants to disconnect. If so, the disconnect will be reattempted with additional force.

  • WN_SUCCESS if the connection is successfully disconnected. Other error codes include the following.
WN_CANCEL | the user was asked if he really wanted to disconnect and elected not to disconnect.
WN_OPEN_FILES | unable to disconnect because the user is actively using the connection.
WN_FUNCTION_BUSY | The MPR or NP is busy (possibly initializing). The caller should retry.
WN_NO_NETWORK | network is not present.
WN_OUT_OF_MEMORY | insufficient memory to bring up the dialog.
WN_EXTENDED_ERROR | a network specific error occurred. WNetGetLastError should be called to obtain a description of the error.


WNetGetLastError

Like GetLastError, this returns extended error information, which is maintained on a per-thread basis. Unlike GetLastError, this function can also return a string for reporting errors that are not described by any existing error code. It is primarily used for returning network vendor specific errors, and should be called when GetLastError returns WN_EXTENDED_ERROR. It returns error information associated with the last NP that reported an error.

DWORD WNetGetLastError (
    LPDWORD lpError,
    LPTSTR lpErrorBuf,
    DWORD nErrorBufSize,
    LPTSTR lpNameBuf,
    DWORD nNameBufSize
    );
lpError
Pointer to DWORD that will receive the error reported by the NP.
lpErrorBuf
Pointer to buffer that will receive a null terminated string describing the error.
nErrorBufSize
DWORD indicating the size of lpErrorBuf. If the buffer is too small to receive an error string, the string will simply be truncated (it is still guaranteed to be null terminated). A buffer of at least 256 bytes is recommended.
lpNameBuf
Pointer to buffer that will receive a null terminated string identifying the NP that raised the error.
nNameBufSize
DWORD indicating the size of lpNameBuf. If the buffer is too small to receive the name, the string will simply be truncated (it is still guaranteed to be null terminated).
  • WN_SUCCESS if successfull.
WN_NO_ERROR | no error was previously reported by a network provider in this thread.
WN_BAD_POINTER | a pointer to a buffer or a buffersize is invalid.


WNetGetNetworkInformation

This returns extended information about a specific network whose name was returned by a network enumeration.

DWORD WNetGetNetworkInformation(
    LPTSTR lpProvider,
LPNETINFOSTRUCT lpNetInfoStruct
);
lpProvider
Pointer to the name of the provider for which information is required.
lpNetInfoStruct
Pointer to a structure that describes the behavior of the network. This structure has the following format:


NETINFOSTRUCT Structure

typedef struct _NETINFOSTRUCT{
    DWORD cbStructure;
    DWORD dwProviderVersion;
    DWORD dwStatus;
    DWORD dwCharacteristics;
    DWORD dwHandle;
    WORD wNetType;
    DWORD dwPrinters;
    DWORD dwDrives;
} NETINFOSTRUCT, *LPNETINFOSTRUCT;
cbStructure
The size of the NETINFOSTRUCT structure in bytes. This is filled in by the caller to indicate the size of the structure passed in. Upon return, it has the size of the structure filled in.
dwProviderVersion
The version number of the network.
dwStatus
The current status of the network provider software. This can have one of the following values:
WN_SUCCESS | The network is up and running.
WN_NO_NETWORK | The network is not currently running.
WN_BUSY | The network is not currently able to service requests, but should become available. This usually means that the network is starting up.

dwCharacteristics
Characteristics of the network provider software. This can have one or more of the following bit values:
NETINFO_DLL16 | The network provider is running as a 16 bit Winnet driver.
NETINFO_DISKRED | The network provider requires a local disk drive device redirected to access server file systems.
NETINFO_PRINTERRED | The network provider requires a local printer port redirected to access server file systems.

dwHandle
The instance handle for the network provider or 16 bit Winnet driver for the network.
wNetType
A network type unique to the network being run. This value is used to associate resources with a specific network when they are made persistent, or stored in links.
dwPrinters
A bit mask indicating the valid print numbers for redirecting local printer devices, with the lowest order bit correspondinding to LPT1. A network may support more print numbers than indicated here. This mask does not take into account non-network related reasons that could stop the local printer device from being redirected (for example, having a local printer connected to the device).
dwDrives
A 32 bit mask indicating the valid local disk devices for redirecting disk drives, with the lowest order bit correspondinding to A:. This mask does not take into account non-network related reasons that could stop the disk drive from being redirected (for example, having a RAM drive assigned to the device).
  • WN_SUCCESS if the call is successful.
WN_BAD_PROVIDER | lpProvider does not match any running NP.
WN_BAD_VALUE | cbStructure is not filled in with a valid structure size.


WNetGetProviderName

This is used to obtain the provider name for a specific type of network.

DWORD WNetGetProviderName(
    DWORD dwNetType,
    LPTSTR lpProvider,
    LPDWORD lpBufferSize
    );
dwNetType
The network type unique to the network. If two networks claim the same type, then the first network loaded is returned. Only the high word of the network type is used. If a network reports a subtype in the loword, then this is ignored.
lpProvider
Pointer to a buffer in which to return the provider name.
lpBufferSize
The size in bytes of the buffer passed to the function call. The buffer must be at least one byte long. If the result is WN_MORE_DATA, this will contain the buffer size required (in bytes) to hold the provider name.
  • WN_SUCCESS if the call is successful.
WN_MORE_DATA | the buffer is too small to hold the provider name.
WN_NO_NETWORK | wNetType does not match a running provider.
WN_BAD_POINTER | lpProvider or lpBufferSize is invalid.


Structures

The following structure is returned during enumeration of resources on the network, during enumeration of currently connected resources, and during enumeration of recently connected resources.


NETRESOURCE Structure

typedef struct _NETRESOURCE {
    DWORD dwScope;
    DWORD dwType;
    DWORD dwDisplayType;
    DWORD dwUsage;
    LPTSTR lpLocalName;
    LPTSTR lpRemoteName;
    LPTSTR lpComment;
    LPTSTR lpProvider;
} NETRESOURCE, *LPNETRESOURCE;
dwScope
This is one of:
RESOURCE_CONNECTED - a network resource that is currently connected or persistent (i.e., returns WN_SUCCESS from WNetGetConnection).
RESOURCE_GLOBALNET - a network resource (may or may not be connected).
RESOURCE_REMEMBERED - a persistent connection.
RESOURCE_RECENT - a recently connected remote resource.
RESOURCE_CONTEXT - the resources associated with the user's current and default network context.

dwType
This can be one of:

RESOURCETYPE_DISK

RESOURCETYPE_PRINT

RESOURCETYPE_ANY

The value RESOURCETYPE_ANY is used if the resource matches more than one (e.g., a container of both print and disk resources), or a resource which is neither print or disk.

dwDisplayType
This field is set to indicate what display type a User Interface uses to represent this resource. Currently defined types are:
RESOURCEDISPLAYTYPE_ROOT | The root of networks
RESOURCEDISPLAYTYPE_NETWORK | a network
RESOURCEDISPLAYTYPE_DOMAIN | collection of servers
RESOURCEDISPLAYTYPE_SERVER | a server
RESOURCEDISPLAYTYPE_SHARE | a share point RESOURCEDISPLAYTYPE_SHAREADMIN - an administrative share point
RESOURCEDISPLAYTYPE_DIRECTORY | a directory
RESOURCEDISPLAYTYPE_GENERIC | unspecified

dwUsage
This field is only defined if dwScope is RESOURCE_GLOBALNET or RESOURCE_CONTEXT.

The field is a bit mask which may contain any of:
RESOURCEUSAGE_CONNECTABLE | Can connect to resource by a call to WNetAddConnection or WNetAddConnection2. If dwType is RESOURCETYPE_DISK, then, once the resource is connected to, the file APIs (e.g., FindFirstFile, FindNextFile) can be used to enumerate any files and directories contained within it.
RESOURCEUSAGE_CONTAINER | Resource contains other resources that can be enumerated using the WNetOpenEnum, WNetEnumResource, and WNetCloseEnum APIs. The resource may not currently contain any resources (i.e. the first NPEnumResource call may return WN_NO_MORE_ENTRIES).
RESOURCEUSAGE_NOLOCALDEVICE | Resource can be connected to without associating a local device (such as D: or LPT1).
RESOURCEUSAGE_SIBLING | Resource is a sibling of the previous resource returned from the current enumeration (only set if dwScope is RESOURCE_CONTEXT, since resources are always siblings of each other if dwScope is RESOURCE_GLOBALNET).

lpLocalName
If dwScope is RESOURCE_CONNECTED or RESOURCE_REMEMBERED, this will contain the name of a redirected local device (NULL if the connection is a deviceless connection). It is undefined otherwise.
lpRemoteName
This contains a remote network name if the entry is a network resource. This name may be then passed to WNetAddConnection to make a network connection if dwUsage has RESOURCEUSAGE_CONNECTABLE. If the entry is a current or persistent connection, this field will refer to the name of the network resource which is redirected to lpLocalName.
lpComment
This may be any NP supplied comment.
lpProvider
Specifies the name of the NP owning this resource. It may be NULL if it is not known.


Errors

To be consistent with Windows 3.1, the functions continue to return error codes. However, they also set the last error so GetLastError can also be used when the return code is not WN_SUCCESS.

The Windows 3.1 WinNet WN_ xxx error symbols have been retained. However, their values are mapped to the corresponding error in the Win32 error range. The mappings are as follows:

#define WN_ACCESS_DENIED        ERROR_ACCESS_DENIED
#define WN_ALREADY_CONNECTED    ERROR_ALREADY_ASSIGNED
#define WN_BAD_HANDLE           ERROR_INVALID_HANDLE
#define WN_BAD_LOCALNAME        ERROR_BAD_DEVICE
#define WN_BAD_NETNAME          ERROR_BAD_NET_NAME
#define WN_BAD_PASSWORD         ERROR_INVALID_PASSWORD
#define WN_BAD_POINTER          ERROR_INVALID_ADDRESS
#define WN_BAD_PROFILE          ERROR_BAD_PROFILE
#define WN_BAD_PROVIDER         ERROR_BAD_PROVIDER
#define WN_BAD_USER             ERROR_BAD_USERNAME
#define WN_BAD_VALUE            ERROR_INVALID_PARAMETER
#define WN_CANCEL               ERROR_OPERATION_ABORTED
#define WN_CANNOT_OPEN_PROFILE  ERROR_CANNOT_OPEN_PROFILE
#define WN_CONNECTION_CLOSED    ERROR_CONNECTION_UNAVAIL
#define WN_DEVICE_ERROR         ERROR_GEN_FAILURE
#define WN_DEVICE_IN_USE        ERROR_DEVICE_IN_USE
#define WN_EXTENDED_ERROR       ERROR_EXTENDED_ERROR
#define WN_FUNCTION_BUSY        ERROR_BUSY
#define WN_MORE_DATA            ERROR_MORE_DATA
#define WN_NO_ERROR             NO_ERROR
#define WN_NO_MORE_ENTRIES      ERROR_NO_MORE_ITEMS
#define WN_NO_NET_OR_BAD_PATH   ERROR_NO_NET_OR_BAD_PATH
#define WN_NO_NETWORK           ERROR_NO_NETWORK
#define WN_NOT_AUTHENTICATED    ERROR_NETWORK_ACCESS_DENIED
#define WN_NOT_CONNECTED        ERROR_NOT_CONNECTED
#define WN_NOT_CONTAINER        ERROR_NOT_CONTAINER
#define WN_NOT_LOGGED_ON        ERROR_NOT_LOGGED_ON
#define WN_NOT_SUPPORTED        ERROR_NOT_SUPPORTED
#define WN_OPEN_FILES           ERROR_OPEN_FILES
#define WN_OUT_OF_MEMORY        ERROR_NOT_ENOUGH_MEMORY
#define WN_RETRY                ERROR_RETRY
#define WN_SUCCESS              NO_ERROR
#define WN_WINDOWS_ERROR        ERROR_UNEXP_NET_ERR


Authentication and Log On Functions

The following topics describe the Authentication and logon functions.


WNetLogoff

This function is used to log the user off from one or all of the networks. It will not perform system log off or unload the user's profile. The ExitWindowsEx() function must be used for system log off.

DWORD WNetLogoff(
    LPCTSTR lpProvider,
    HWND hwndOwner
    );
lpProvider
Specifies the network provider for which the log off should occur. If lpProvider is NULL, the network log off is done to all NPs.
hwndOwner
A handle to a window which should be the owner for any messages or dialogs the network provider might display. If this parameter is NULL, the network provider may not display any UI.
  • WN_SUCCESS if the call is successful. Otherwise, an error which includes:
WN_BAD_PROVIDER | the provider name specified is invalid.
WN_NOT_LOGGED_ON | the user is not logged on to this network.
WN_CANCEL | the user canceled the operation.


WNetLogon

This function is used to log the user on to one or all of the networks.

DWORD WNetLogon(
    LPCTSTR lpProvider,
    HWND hwndOwner
    );
lpProvider
Specifies the network provider for which the log on should occur. If lpProvider is NULL, the network log on is done to all NPs, even if system log on has already been performed.
hwndOwner
A handle to a window which should be the owner for any messages or dialogs the network provider might display. If this parameter is NULL, the network provider may not display any UI.
  • WN_SUCCESS if the call is successful. Otherwise, an error which includes:
WN_CANCEL the user canceled the operation.


WNetVerifyPassword

This function is used to verify that a given password is the Windows password. It is often used in conjunction with PwdGetPasswordStatus, which is described in Windows 95 Password Providers.

DWORD WNetVerifyPassword(
    LPCTSTR lpszPassword,
    BOOL FAR * pfMatch
    );
lpszPassword
Points to a password string that the caller wants verified as the Windows password.
pfMatch
Points to a flag that reports the results of the password verification. If the WNetVerifyPassword function returns WN_SUCCESS, this flag contains the results of the password verification. If the flag is set TRUE, then the password specified in lpszPassword is the Windows password. If the flag is set to FALSE, the specified password was not the Windows password.
  • WN_SUCCESS if the call is successful. Otherwise, an error which includes:
WN_BAD_POINTER lpszPassword or pfMatch is invalid.


WM_USERCHANGED

A WM_USERCHANGED (0x0054) message is sent via BroadcastSystemMessage to all top-level windows, installable drivers, and VxDs when the user logs on or off and user profiles are enabled. An application may determine the current user name by calling WNetGetUser.

Most ordinary applications are not affected by log on and log off, beyond the ordinary implications of active connections being disconnected and open files being closed. The primary purpose of this message is for network-specific applications which maintain internal state based on the current log on. For example, an application which receives messages from other stations might need to add a NetBIOS name (based on the current user name) when the user logs on.


Logoff

When log off is occurring, all applications are shut down. They receive the same messages that they would receive when the system is shut down: WM_QUERYENDSESSION followed by WM_ENDSESSION. The lParam parameter has the EWX_REALLYLOGOFF bit set indicating that this is a log off, not a shutdown. The messages are sent through BroadcastSystemMessage, so they are received by all top-level windows, installable drivers, and VxDs.

Most ordinary applications are not affected by log on and log off, beyond the ordinary implications of active connections being disconnected and open files being closed. The primary purpose of this message is for network-specific applications which maintain internal state based on the current log on. For example, an application which receives messages from other stations might need to delete a NetBIOS name when the user logs off.

A service process that needs to stay running when the user logs off can call the RegisterServiceProcess API to make itself exempt from the automatic shutdown of all applications at logoff time.


Network Provider SPI

The WinNet application programming interface (API) was introduced in Microsoft(r) Windows(r) version 3.0 to provide a generic network interface for the Windows shell and system utilities, providing an interface which is generally available across many networks. It was used only by Windows, and was not documented for third-party application developers. Major categories of functionality included making and breaking network connections, and printing.

In Windows for Workgroups 3.1, support was added so that two networks could coexist, each with their own implementation of the WinNet API. This was achieved by adding an extra layer of routing software that was used when two networks were running.

In Windows NT/Windows 2000, the layer of routing software (the Multiple Provider Router, or MPR) was made mandatory, even for one network. The layer contains the network-independent APIs that are generally available to all application writers and are documented in the Win32 API Specification. Making the layer mandatory simplifies writing the networking software for a specific network to interface to Windows (the network provider, or NP software).

Features that are common to all networks are implemented once in the MPR, which reduces the code base of each NP and ensures common behavior between networks. For example, NPs do not implement persistent connections. This feature is implemented in the MPR and is entirely transparent to an NP.

In Windows 95, the same approach is taken as in Windows NT/Windows 2000. Extensions have been added to the Windows NT/Windows 2000 interfaces to provide a greater level of integration between the shell, the desktop, and the networks. Particular features that are more tightly integrated are network browsing, viewing network specific information, and connecting to networks.

The set of interfaces that a network vendor implements in the NP to interface to Windows is the network service provider interface (SPI). Applications do not call these SPIs directly. Instead, the Win32 functions they call are routed by the MPR to the SPIs of the appropriate provider.

In summary, in Windows 95 each network implements a provider, and Windows handles communicating with all the providers present to provide an integrated network interface to the user. The integration is handled by the MPR Windows component, which is implemented as a DLL. The MPR calls an NP through the SPIs implemented by the NP.

This documentation describes how a network vendor should implement the SPIs in an NP to integrate its network into Windows 95.


Overview

This documentation begins with an overview of the new/changed features introduced in this version of WinNet beyond those in the Windows 3.1 WinNet specification. Familiarity with the Windows 3.1 WinNet specification is helpful.

Then, the provider SPIs are described and, finally, guidelines for error handling and implementation issues are presented.


Provider Realization

Each WinNet provider should be implemented as a dynamic-link library (DLL) that is specific to its underlying networking software. The MPR dynamically loads the DLL at startup and calls its entry points if the network it represents is active.

It is not necessary to have stub routines for unimplemented functions. However, the NPGetCaps function must be supported, and, if a provider supports resource enumeration, it must support all three Open/Enum/Close functions.


Reserved Ordinals

The following manifests define a reserved ordinal range for the user. The shell is guaranteed never to use ordinals in this range.

  WNNC_ORD_UserStart    500
  WNNC_ORD_UserEnd    599


Reserving New Constants

Network vendors wishing to define additional constants (for example, a new standard network object type) should contact Microsoft, and new constants will be allocated and included in future versions of the Software Development Kit (SDK).


Name Changes

All functions that begin with the WNet prefix and are implemented by an NP have been renamed with an NP prefix. This was done to avoid confusion with the Win32 functions that retain the WNet prefix. The NP prefix identifies the SPI to be a provider SPI which should be called only by the MPR.


Return Values/Reporting Errors

In Windows 3.1, most WNet functions return WN_SUCCESS on success, and unique nonzero values for various error conditions. Applications use the WNetGetError and WNetGetErrorText functions used to obtain network-specific error codes and text messages.

In Windows NT/Windows 2000, the WNet functions still return error codes, but applications can call GetLastError and WNetGetLastError to obtain error information. WNetGetError and WNetGetErrorText functions are no longer used.

Windows 95 is very much like Windows NT/Windows 2000. Applications can still call GetLastError and WNetGetLastError to obtain error information. A mechanism is also provided for an NP to specify custom error text for standard operations that the NP knows are targeted only to its network. See the function definition for WNetGetLastError for more information.

In general, function calls may return any errors (such as "insufficient memory") even if the error is not specifically mentioned in the API description.


Network Browsing

Vendor-specific network browsing dialog boxes do not have to be implemented in the NP. Instead, an NP can implement the enumeration SPIs that allow Windows to put up general network browsing capabilities that are common to all networks.


Provider Dialog Boxes

Providers should not put up vendor-specific dialog boxes except where explicitly permitted by this specification. Doing so may work well when running with the vendor's network alone, but may produce undesirable and, at best confusing, interaction with the user when multiple networks are running simultaneously.


Passing Buffers and Strings

A number of calls take the address and size of a buffer, into which the function will place a variable-sized structure. In each case, the mechanism used is the same. The caller allocates a buffer and passes its address to the function in lpBuffer, and the address of a word containing the buffer size in bytes via lpBufferSize. The function then copies as much of the requested structure as it can into the buffer. If it fits, the function returns success, but if it does not, the data may be left incomplete, and the function sets the WN_MORE_DATA error. When WN_MORE_DATA is returned, lpBufferSize is filled with the number of bytes actually required by the structure. This way, if the buffer passed in was too small and the function failed, the caller may allocate a new buffer of the required size and call the function again. The system takes a copy of the size so that an NP need only fill the size in correctly if it returns WN_MORE_DATA.

When the structure returned includes variable-length strings, the individual structures will usually contain a pointer to the string. The strings themselves should also be placed within the buffer (at the end) so that they will not throw off the ability to index to the Nth structure (all structures are located contiguously at the start of the buffer). Pointers to strings or variable-length data must be actual pointers, not offsets into the buffer.

Windows 95 uses DBCS ANSI/OEM character sets, so that when a buffer is used to pass in and return strings, lpBufferSize specifies the number of bytes that will fit, not the number of characters. This is different from Windows NT/Windows 2000, which uses Unicode and specifies the number of characters.


Persistent Connections

Persistent connections are connections remembered by Windows and are restored by Windows when (depending upon the network) the user starts up or logs in to a network.

Persistent connections are handled entirely by Windows to present a single, consistent model to the user. Providers should not maintain (explicitly remember or restore) persistent connections.


Internationalization

When characters are passed across the SPI interface, they are always in the Windows ANSI character set. The NP should convert to OEM character set internally where appropriate.


Security

When passwords are passed across the SPI interface, they should always be in the form that they were typed in by the user. If the NP uses case-insensitive passwords, then it should do its own case conversions. Following this convention is important for case-sensitive NPs and password synchronization to work properly.


Obsolete Functionality

All Printing APIs and Long File Names APIs defined in Windows 3.1 WinNet have no equivalent in the Windows 95 Provider API set. Also, the following Windows 3.1 WinNet APIs are not used by Windows 95:

WNetGetPropertyText
WNetPropertyDialog


New Functionality

In addition to the Windows 3.1 WinNet features, the parameters to the AddConnection and GetUser functions have been extended. A set of network resource enumeration functions have been added, as well as functions to tailor the Shell Explorer property list descriptions. Functions have been added to support connection with authentication and network-specific log on and log off.


Capabilities Functions

This section describes the calls for determining which SPIs are supported by the NP.


NPGetCaps

DWORD NPGetCaps(
  DWORD nIndex
  );
nIndex
Specifies the capability set that the caller is interested in.
  • A bit mask indicating what services are supported within the set queried.

Unlike all the other calls, this function does not return an error status. Instead, the nIndex parameter specifies a query, and that defines the type of value returned.

A few of the nIndex values cause a constant to be returned, but in most cases the nIndex parameter specifies which set of services are being queried, and the return value is a bit mask indicating which services in that set are supported. A zero value would indicate that none of the services in that set are supported. If NPGetCaps is called with values that the NP does not recognize, it must return zero. This is so that features can be safely added in future releases.

The symbols for the valid values of nIndex are listed below, together with the constants defining the bits in the returned mask. The values themselves are defined in the file Netspi.h.


SPI Version

WNNC_SPEC_VERSION

The high and low words of the return value contain the major and minor version numbers of the WinNet API specification to which the provider conforms.

For this version it should return the following:

WNNC_SPEC_VERSION51


Provider Type and Version

WNNC_NET_TYPE

Returns a DWORD value: the high word contains the network type, and the low word may contain a subtype. The following Net Type values are assigned:

WNNC_NET_MSNET
WNNC_NET_LANMAN
WNNC_NET_NETWARE
WNNC_NET_VINES
WNNC_NET_10NET
WNNC_NET_LOCUS
WNNC_NET_SUN_PC_NFS
WNNC_NET_LANSTEP
WNNC_NET_9TILES
WNNC_NET_LANTASTIC
WNNC_NET_AS400
WNNC_NET_FTP_NFS
WNNC_NET_PATHWORKS
WNNC_NET_LIFENET
WNNC_NET_POWERLAN

Vendors working on new networks should register their network type values with Microsoft.

WNNC_DRIVER_VERSION

Returns the provider version number.

Note: to assist in common versioning conventions for providers, the following macro is provided:

#define WNNC_DRIVER(major,minor) (major*WNNC_DRIVER_MAJOR1 + minor*WNNC_DRIVER_MINOR1)


User Information

WNNC_USER

Returns a mask of: WNNC_USR_GETUSER


Connections

WNNC_CONNECTION

Returns a mask of:

WNNC_CON_ADDCONNECTION
WNNC_CON_CANCELCONNECTION
WNNC_CON_GETCONNECTIONS
WNNC_CON_GETPERFORMANCE
WNNC_CON_GETUNIVERSALNAME
WNNC_CON_FORMATCONNECTION


Provider Specific User Interface

WNNC_DIALOG

Returns a mask of:

WNNC_DLG_FORMATNETWORKNAME
WNNC_DLG_GETRESOURCEPARENT
WNNC_DLG_GETRESOURCEINFORMATION


Enumeration

WNNC_ENUMERATION

Returns a mask of:

WNNC_ENUM_GLOBAL
WNNC_ENUM_LOCAL
WNNC_ENUM_CONTEXT

If one or more of these values is set, then the NP must export and support NPOpenEnum, NPEnumResource, and NPCloseEnum.


Startup

WNNC_START

Returns a value to indicate if the provider is likely to start. MPR may call this function during its startup to determine the state of the provider. For example, when MPR is trying to restore persistent connections, and a provider is not responding, it will use this to determine if it should retry and how long. A provider should return WNNC_START_WONT if it knows it will not start (for example, if it is in some unrecoverable failure mode) so MPR will not retry. Otherwise, it should either return the estimated start time in number of milliseconds, or WNNC_START_UNKNOWN to mean it doesn't know. If WNNC_START_UNKNOWN is returned, MPR will use some default time-out. If it turns out the provider has started by the time this call is issued, it can return WNNC_START_DONE. A provider should return WNNC_START_INACTIVE if it cannot access the network at the moment, but may be able to in the future (such as when the PCMCIA net card is removed from the computer, or the computer is undocked, essentially when the client is unable to run a transport).

WNNC_START_WONT
WNNC_START_INACTIVE
WNNC_START_UNKNOWN
WNNC_START_DONE


Network Resource Properties

WNNC_RESOURCE

Returns a mask of bit values that indicate specific behaviors of the NP and its underlying network. These behaviors are used by the MPR to provide intelligent processing for the NP. For example, if a network does not support deviceless connections, the MPR knows how to select a local when making connections.

WNNC_RES_VALIDLOCALDEVICE

These values have the following meanings:

WNNC_RES_VALIDLOCALDEVICE means that the NP has restrictions upon valid local device names (for example, only supporting "LPT1" to "LPT3" when the Windows 95 printing system supports more printer numbers). The NP must export NPValidLocalDevice if it sets this value.


Authentication and Log On

WNNC_AUTHENTICATION

Returns a mask of:

WNNC_AUTH_LOGON
WNNC_AUTH_LOGOFF
WNNC_AUTH_GETPOLICYPATH
WNNC_AUTH_GETHOMEDIRECTORY


User Identification Functions

These are calls for registering or obtaining the current user's network identification and password.


NPGetUser

This is used to determine either the current default user name, or the user identification used to establish a network connection.

DWORD NPGetUser(
  LPTSTR lpName,
  LPTSTR lpUserID,
  LPDWORD lpBufferSize
  );
lpName
Contains the name of the redirected local device the caller is interested in, or a network name that the user has made a connection to. This may be the empty string if the caller is interested in the name of the user currently logged on to the system. If a network name is passed in, and the user is connected to that resource using different names, it is possible that a provider cannot resolve which user identification to return. In this case the provider may make an arbitrary choice amongst the possible responses.
lpUserID
Points to a buffer to receive the user profile name. This is an identification string that the user made to establish the connection (for example, a user name, or group name). Whenever possible, this string should contain sufficient information to reestablish the connection with a call to NPAddConnection without posting a dialog box when a valid password is supplied.
lpBufferSize
This is used to specify the size of the buffer passed in, in bytes. If the call fails because the buffer is not big enough, this location will be used to return the required buffer size.
  • WN_SUCCESS if the call is successful. This status should be returned if lpName is asking for the network logon name and the network does not provide a network-wide log on to the user (the user must log on to each server individually). Otherwise, an error code is returned. which may include:
WN_NOT_LOGGED_ON | The user is not logged on to the network.
WN_NOT_CONNECTED | lpName not a redirected device nor a connected network name.
WN_NOT_SUPPORTED | lpName is a pointer to an empty string and the NP does not provide the capability for network-wide log on.
WN_MORE_DATA | The buffer is too small.
WN_NO_NETWORK | Network is not present.


Device Redirecting Functions

These are calls that redirect standard MS-DOS devices, drive letters and LPT ports, so that standard applications may use them, and so access the network in a totally transparent manner. Depending upon their architecture and implementation, networks may or may not require local MS-DOS devices associated with network devices.


Listing Local Devices

Before trying to add a network connection, the system may present to the user a list of local devices to select from. So that entries are not presented in this list that the NP would regard as invalid, the system will call NPValidLocalDevice first. If all of the valid devices for the network are described by the registry entry, then the NP does not need to support this routine. However, if the network has its own dynamic restrictions upon valid device ranges, then it should support NPValidLocalDevice to indicate this range to the system. If a device is currently in use, and the NP could form a connection to it were it not, the NP should return that the device is valid to ensure correct error reporting.


NPValidLocalDevice

Validates local devices.

DWORD NPValidLocalDevice(
  DWORD dwType,
  DWORD dwNumber
  );
dwType
Specifies the type of resource to connect to. It can be RESOURCETYPE_DISK, RESOURCETYPE_PRINT.
dwNumber Specifies the range of local devices being requested. Zero for the first 32 devices, one for the next 32 devices and so on.

  • A bit mask representing a range of 32 devices, with the lowest order bit being the lowest device number. For example, if dwNumber is 0, then devices "A:" to "Z:" for disk devices are assigned bits 0 to 25, and devices "LPT1" onwards for print devices are assigned bits 0 onwards.


NPAddConnection

This function is used to form a connection to a remote resource and optionally redirect (connect) a local device to the network resource. Note that if reference counted sessions are being used and this call is made requesting a user name when there is also a connection with a different user name, then the previous user name is preserved and WN_ALREADY_CONNECTED is returned, and the reference count is not incremented (the caller must make a decision as to whether the current user name on the resource is acceptable).

DWORD NPAddConnection(
  HWND hwndOwner,
  LPNETRESOURCE lpNetResource,
  LPTSTR lpUserID,
  LPTSTR lpPassword,
  DWORD dwFlags,
  LPTSTR lpAccessName,
  LPDWORD lpBufferSize,
  LPDWORD lpResult
  );
hwndOwner
A handle to a window that should be the owner for any messages or dialog boxes. This is valid only if CONNECT_INTERACTIVE is set, and should be used only to produce dialog boxes needed for authentication.
lpNetResource
Specifies the network resource being connected to. This structure is defined in the section describing Enumeration SPIs. The following fields are set, and the others should be ignored.
lpRemoteName | The name of the network resource. This is a fully qualified name either returned in a NETRESOURCE structure from an enumeration, or provided by the user (through an Open dialog box, for example). If this parameter is a pointer to an empty string, then authentication is required for the root of the network, and the provider must return WN_NOT_LOGGED_ON to allow MPR the opportunity to call WNetLogon and then retry the NPAddConnection call.
lpLocalName | This specifies the name of a local device to be redirected, such as "F:" or "LPT1". The string is treated in a case-insensitive manner, and may be a pointer to an empty string. In this case, a connection to the network resource is made without making a redirection.

dwType
Specifies the type of resource to connect to. It is RESOURCETYPE_DISK or RESOURCETYPE_PRINT if lpLocalName is not a NULL string. It may also be RESOURCETYPE_ANY if lpLocalName is a NULL pointer or string. On exit, this parameter is filled with a device type to indicate what type of device was connected.
lpUserID
This specifies the user identification used to make the connection. If NULL, the current authentication (currently logged on user) or any other defaults known to the NP should be applied. This is used when users wish to connect to a resource, but they have a different user name or account assigned to them for that resource. Whatever user identification is finally used is the lpUserID string returned from NPGetUserName after adding the connection. The NP implementation should consider keeping this information on the client to avoid generating unnecessary network traffic.
lpPassword
Specifies the password to be used in making the connection. The password is typically the one associated with lpUserProfileName. The NULL value may be passed in to indicate to the function to use the default password. An empty string may be used to indicate no password.
dwFlags
Any combination of the following values:
CONNECT_TEMPORARY | The connection is being established for browsing purposes and will probably be released quickly.
CONNECT_REFCOUNT | The connection is being made by an application that is able to delete the connection when it is done using it (by calling WNetCancelConnection2 with dwFlags set to the value of the CONNECT_RECOUNT bit returned in the lpResult field of this call). The application typically only does the deletion if a local device is redirected or lpResult returns with CONNECT_REFCOUNT set.
CONNECT_INTERACTIVE | May have interaction with the user for authentication purposes.
CONNECT_PROMPT | Do not use any defaults for user names or passwords without offering the user a chance to supply an alternative. This flag is valid only if CONNECT_INTERACTIVE is set.

lpAccessName
Points to a buffer to receive the name that can be used to make system requests on the connection. This conversion is useful for adding connections to aliased resources, such as through a directory service. If the provider does not support aliased connections, then lpAccessName and lpBufferSize may be ignored. If lpLocalName specifies a local device redirection, then lpAccessName is set to NULL by the caller.
lpBufferSize
This is used to specify the size of lpAccessName buffer passed in. If lpAccessName is NULL, then this field is ignored. If the call fails because the buffer is not big enough, this location is used to return the required buffer size and the connection should not be made.
lpResult
Pointer to a DWORD in which is returned additional information about the connection. This field is set to zero by the system before calling this function. Currently has the following bit value:
CONNECT_REFCOUNT The connection was made without using a local device redirection and is to a connection which can support reference counted sessions. If this bit is set, then calling NPCancelConnection will not interfere with other threads or processes that may be using the session and also called NPAddConnection themselves.

  • WN_SUCCESS if the call is successful. Otherwise, an error code is returned, which may include:
WN_BAD_NETNAME | lpRemoteName in the lpNetResource structure is not acceptable to this provider.
WN_BAD_LOCALNAME | lpLocalName in lpNetResource is invalid.
WN_ALREADY_CONNECTED | lpLocalName is already connected or there is already a deviceless connection to the network resource with a different user name.
WN_NO_NETWORK | The network is not present.
WN_NOT_LOGGED_ON | The user is not logged on to the network.
WN_NOT_AUTHENTICATED | The user is logged on, but is not authenticated to the part of the network containing the network resource.
WN_ACCESS_DENIED | Access denied. The user is logged on and authenticated, but does not have the necessary permissions to access the resource.
WN_BAD_PASSWORD | Invalid password and CONNECT_INTERACTIVE is not set.


NPCancelConnection

Breaks a network connection.

DWORD NPCancelConnection(
  LPTSTR lpName,
  BOOL fForce
  DWORD dwFlags
  );
lpName
The name of either the redirected local device or the remote network resource to disconnect from. In the former case, only the redirection specified is broken. In the latter case, only the deviceless connection to the remote network resource is broken.
fForce
Used to indicate if the disconnect should be done forcefully in the event of open files or jobs on the connection. If FALSE is specified, the call will fail if there are open files or jobs. If set, CONNECT_REFCOUNT will not be set.
dwFlags
Additional information about the connection. Currently has the following bit value:
CONNECT_REFCOUNT The connection has a reference count on the session and, if set, the caller is requesting that the reference count be decremented. Otherwise the caller is requesting that the session be removed entirely for all users.

  • WN_SUCCESS if the call is successful. Otherwise, an error code is returned, which may include:
WN_NOT_CONNECTED | lpName not a redirected device, or not currently connected to lpName.
WN_OPEN_FILES | There are open files, and fForce was FALSE.


NPGetConnection

Obtains information about a redirected device.

DWORD NPGetConnection(
  LPTSTR lpLocalName,
  LPTSTR lpRemoteName,
  LPDWORD lpBufferSize
  );
lpLocalName
Contains the name of the local device the caller is interested in.
lpRemoteName
Points to a buffer to receive the remote name used to make the connection.
lpBufferSize
This is used to specify the size, in bytes, of the buffer passed in. If the call fails because the buffer is not big enough, this location will be used to return the required buffer size.
  • WN_SUCCESS if the call is successful. Otherwise, an error code is returned, which may include:
WN_BAD_LOCALNAME | lpLocalName is invalid.
WN_NOT_CONNECTED | lpLocalName not a redirected device.
WN_MORE_DATA | The buffer is too small.
WN_NO_NETWORK | The network is not present.


NPGetConnectionPerformance

This function returns information about the expected performance of a connection used to access a network resource. The request can be only for a network resource to which there is currently a connection.

The information returned can be an estimate only. Note that if the network cannot obtain information about the resource on the network, then it can return information about the network adapter and its associated performance, setting dwFlags accordingly.

DWORD NPGetConnectionPerformance(
  LPTSTR lpRemoteName,
  LPNETCONNECTINFOSTRUCT lpNetConnectInfo
  );
lpRemoteName
Contains the remote name for a resource for which a connection exists.
lpNetConnectInfo
This is a pointer to a NETCONNECTINFOSTRUCT structure which is filled in by the NP if the provider has a connection to the network resource. With the exception of the cbStructure field, all other fields are zero filled before Mpr.dll passes the request on to the NPs, and the provider has to write to fields only for which it has information available. Also, for rate values, one means that the performance is better than can be represented in the unit.
  • WN_SUCCESS if the call is successful. Otherwise, an error code is returned, which may include:
WN_BAD_LOCALNAME | lpLocalName is invalid.
WN_NOT_CONNECTED | lpRemoteName not a connected network resource.
WN_NO_NETWORK | The network is not present.


NETCONNECTINFOSTRUCT

typedef struct _NETCONNECTINFOSTRUCT {
  DWORD cbStructure;
  DWORD dwFlags;
  DWORD dwSpeed;
  DWORD dwDelay;
  DWORD dwOptDataSize;
} NETCONNECTINFOSTRUCT. *LPNETCONNECTINFOSTRUCT;
cbStructure
The size of the NETCONNECTINFOSTRUCT structure in bytes. This is filled in by the caller to indicate the size of the structure passed in. The NP should leave this field unchanged, and can assume that the structure is large enough to contain all fields up to and including dwOptDataSize.
dwFlags
This is a bit mask, which may have any of the following bits set:
WNCON_FORNETCARD | If set, information is being returned for the performance of the network card being used for the connection, in the absence of having information about the actual connection. If clear, information is being returned for the current connection with the resource, with any routing degradation being taken into consideration.
WNCON_NOTROUTED | If clear, the connection may be going through routers that limit performance. Consequently, if WNCON_FORNETCARD is set, actual performance may be much less than the information returned. If WNCON_NOTROUTED is set, the connection is not being routed.
WNCON_SLOWLINK | If set, the connection is known at some point to be over a medium that is typically slow (such as a modem using a normal quality phone line). Providers that return a value in dwSpeed do not have to set this bit.
WNCON_DYNAMIC | If set, some of the information being returned is being dynamically recalculated, and reissuing this request upon the connection may return different, more current, information.

dwSpeed
The speed of the media to the network resource in units of 100 bps (for example, a 1,200 baud point to point link returns 12).
dwDelay
The delay introduced by the network when sending information (the time between starting sending data and the time that it starts being received) in units of a millisecond. This is in addition to any latency that was incorporated into the calculation of dwSpeed, so the value returned will be 0 for accessing most resources.
dwOptDataSize
A recommendation for the size of data in bytes that is most efficiently sent through the network when an application makes a single request to the network resource. For example, for a disk network resource, this value might be 2048 or 512 when writing a block of data.


NPGetUniversalName

This function returns the name used to access a directory or file on a redirected local device from the network. Its primary use is to return the information for directories that are part of a distributed file store (DFS), which are redirected from a directory below the root of the associated local device. Providers that do not support this type of feature do not have to support this function, as MPR provides default behavior for this case.

DWORD NPGetUniversalName(
  LPTSTR  lpLocalPath,
  DWORD   dwInfoLevel,
  LPVOID  lpBuffer,
  LPDWORD lpBufferSize
  );
lpLocalPath
Contains the local path to an object on a network resource. This path is a drive-based path.
dwInfoLevel
The level of detail of information the caller is interested in as described above. This may have the value UNIVERSAL_NAME_INFO_LEVEL or REMOTE_NAME_INFO_LEVEL, depending upon the level of information required.
lpBuffer
Points to a buffer to receive the information the user has requested. The buffer contains a UNIVERSAL_NAME_INFO structure or a REMOTE_NAME_INFO structure (depending upon the value of dwInfoLevel), followed by the return data pointed to from within the structure. The structures returned are described below.
lpBufferSize
This is used to specify the size, in bytes, of the buffer passed in. If the call fails because the buffer is not big enough, this location will be used to return the required buffer size.
  • WN_SUCCESS if the call is successful. Otherwise, an error code is returned, which may include:
WN_BAD_LOCALNAME | lpLocalPath does not start with a valid redirected local disk device name.
WN_BAD_LEVEL | dwInfoLevel is not set to a valid value.
WN_NOT_CONNECTED | lpLocalPath is not a connected network resource.
WN_MORE_DATA | lpBuffer is not a large enough buffer to return the result. lpBufferSize is returned with the required buffer size.
WN_NO_NETWORK | The network is not present.

The structures that can be returned have the following format: UNIVERSAL_NAME_INFO and REMOTE_NAME_INFO.


UNIVERSAL_NAME_INFO

typedef struct _UNIVERSAL_NAME_INFO {
   LPTSTR lpszUniversalName;
} UNIVERSAL_NAME_INFO, *LPUNIVERSAL_NAME_INFO;
lpszUniversalName
If the provider supports a Universal Name then it will return that here.


REMOTE_NAME_INFO

typedef struct _REMOTE_NAME_INFO {
  LPTSTR lpszUniversalName;
  LPTSTR lpszConnectionName;
  LPTSTR lpszRemainingPath;
} REMOTE_NAME_INFO, *LPREMOTE_NAME_INFO;
lpszUniversalName
Points to the Universal Name if the provider supports that. Otherwise this element will be a NULL pointer.
lpszConnectionName
Points to the remote name used to make the connection. This does not have a backslash at the end of the name.
lpszRemainingPath
The remaining path that needs to be concatenated to drive letter once a connection is established using above ConnectionInfo, to refer to the same object again. This path starts with a backslash.


Provider Specific Shell Interface

This section describes how an NP performs or displays network specific tasks or information associated with files in the Windows 95 Shell Explorer.


NPFormatNetworkName

DWORD NPFormatNetworkName(
  LPTSTR lpRemoteName,
  LPTSTR lpFormattedName,
  LPDWORD lpnLength,
  DWORD dwFlags,
  DWORD dwAveCharPerLine
  );
lpRemoteName
Network name to be formatted.
lpFormattedName
Pointer to string buffer that will receive the formatted name.
lpnLength
Pointer to DWORD that specifies the size of the buffer (in bytes) passed in. If the result is WN_MORE_DATA, this will contain the buffer size required (in bytes).
dwFlags
Bit mask indicating the type of format being requested. Can be one of the following:
WNFMT_MULTILINE (0x01) -
The provider should place the '\n' character where line breaks should appear in the name. The full name should be expressed.
WNFMT_ABBREVIATED (0x02) -
The provider should ellipsize or otherwise shorten the network name such that the most useful information will be available to the user in the space provided.

In addition, the following flags can be used with the logical OR operator to modify the flags listed above:

WNFMT_INENUM (0x10) - The network name is being presented in the context of an enumeration where the "container" of this object is presented immediately prior to this object. This may allow NPs to remove redundant information from the formatted name, providing a less cluttered display for the user.

WNFMT_CONNECTION (0x20) - The network name is in the form returned from NPGetConnection and is being formatted so that it can be returned as the result to a WNetGetConnection call. Note: this call is made only if the NP claims to have the WNNC_CON_FORMATCONNECTION capability. The purpose of this is so that an NP can have rich names for network connections and preserve compatibility with the existing WNetGetConnection return result, which some applications prepend to a file name before making a file system request.

dwAveCharPerLine
The maximum number of characters to try fit on a single line (including any ellipses added) where the network name is being presented. If this parameter is zero, then no character limit is being applied.
  • WN_SUCCESS if the call is successful.

    WN_MORE_DATA if input buffer is too small.

    All other errors will be ignored and the unformatted network name will be used.

This SPI allows network vendors to trim or modify network names before they are presented to the user. For example, in the File Open common dialog box, the Drives combo box presents all connected resources and the associated network name. Before each item is displayed, NPFormatNetworkName will be called and the NP will have the option of editing the name so it will fit in the combo box and more importantly, present the most significant portion of the network name to the user.

Note that NPFormatNetworkName is not routed to each NP as most of the other NP SPIs are. Each network vendor need worry about formatting only their own network name and can assume that only names produced by their NP driver will be passed to NPFormatNetworkName.


Showing Network File Properties

With the Windows 3.1 or Windows NT/Windows 2000 WinNet interfaces , showing dialog boxes for network-specific properties of files was achieved by the File Manager calling the functions WNetGetPropertyText, WNetPropertyDialog, or NPGetPropertyText, NPPropertyDialog respectively.

In Windows 95, this function is achieved by the NP hooking the Windows 95 Shell Extension mechanism for providing additional property sheet pages.

Clearly, the NP should show only properties for files associated with its own network.


Enumeration Functions

A provider should support these functions if it is to allow a user to browse its network resources. Refer to the Win32 API specification for the browsing model.


NETRESOURCE

The following structure is returned during enumeration of resources on the network, and during enumeration of currently connected resources.

typedef struct _NETRESOURCE {
  DWORD dwScope;
  DWORD dwType;
  DWORD dwDisplayType;
  DWORD dwUsage;
  LPTSTR lpLocalName;
  LPTSTR lpRemoteName;
  LPTSTR lpComment;
  LPTSTR lpProvider;
} NETRESOURCE, *LPNETRESOURCE;
dwScope
This is one of:
RESOURCE_CONNECTED | A network resource that is currently connected.
RESOURCE_GLOBALNET | A network resource (may or may not be connected).
RESOURCE_CONTEXT | The resources associated with the user's current and default network context.

dwType
This can be one of:
RESOURCETYPE_DISK
RESOURCETYPE_PRINT
RESOURCETYPE_ANY

The value RESOURCETYPE_ANY is used if the resource matches more than one (such as a container of both print and disk resources), or a resource which is neither print or disk.

dwDisplayType
This field is set by the provider to indicate what display type a user interface uses to represent this resource. Currently defined types are:
RESOURCEDISPLAYTYPE_NETWORK | A network.
RESOURCEDISPLAYTYPE_DOMAIN | A collection of servers.
RESOURCEDISPLAYTYPE_SERVER | A server.
RESOURCEDISPLAYTYPE_SHARE | A share point.
RESOURCEDISPLAYTYPE_DIRECTORY | A directory.
RESOURCEDISPLAYTYPE_GENERIC | Unspecified (for providers that don't know or don't care).

In addition, an NP may register additional types by supporting the NPDisplayLayout function. In this case, the NP can supply additional values here. See the NPDisplayLayout function for more details about assigning display types.

dwUsage
This field is defined only if dwScope is RESOURCE_GLOBALNET.

The field is a bit mask which may contain any of the following:
RESOURCEUSAGE_CONNECTABLE | Can connect to resource by a call to NPAddConnection. If dwType is RESOURCETYPE_DISK, then, once the resource is connected to, the file APIs (such as FindFirstFile, FindNextFile) can be used to enumerate any files and directories contained within it.
RESOURCEUSAGE_CONTAINER | Resource is a container for other resources that can be enumerated using the NPOpenEnum, NPEnumResource, and NPCloseEnum APIs. The resource may not currently contain any resources (for example, the first NPEnumResource call may return WN_NO_MORE_ENTRIES).
RESOURCEUSAGE_NOLOCALDEVICE | Resource can be connected to without associating a local device (such as D: or LPT1).
RESOURCEUSAGE_SIBLING | Resource is a sibling of the previous resource returned from the current enumeration (only set if dwScope is RESOURCE_CONTEXT, since resources are always siblings of each other if dwScope is RESOURCE_GLOBALNET).

lpLocalName
If dwScope is RESOURCE_CONNECTED this will contain the name of a redirected local device (NULL if the connection is a deviceless connection). It is undefined otherwise.
lpRemoteName
This contains a remote network name if the entry is a network resource. This name may be then passed to NPAddConnection to make a network connection if dwUsage has RESOURCEUSAGE_CONNECTABLE. If the entry is a current connection, this field will refer to the name of the network resource that is redirected to lpLocalName.
lpComment
This may be any NP-supplied comment.
lpProvider
Specifies the name of the provider owning this resource. The name is case-sensitive for matching in SPI calls.


NPOpenEnum

This SPI is used to open an enumeration of network resources or existing connections. It must be called to obtain a valid handle for enumeration.

DWORD NPOpenEnum (
  DWORD dwScope,
  DWORD dwType,
  DWORD dwUsage,
  LPNETRESOURCE lpNetResource,
  LPHANDLE lphEnum
  );
dwScope
Determines the scope of the enumeration. This can be one of the following:
RESOURCE_CONNECTED | All currently connected resources.
RESOURCE_GLOBALNET | All resources on the network.
RESOURCE_CONTEXT | The resources associated with the user's current and default network context (used for a "My Network" view).

dwType
Used to specify the type of resources and level of detail of interest. This is a bit mask which may be any combination of the following:
RESOURCETYPE_DISK | All disk resources.
RESOURCETYPE_PRINT | All print resources.
If dwType is RESOURCETYPE_ANY, all types of resources are returned. If an NP does not have the capability to distinguish between print and disk resources at a level, it may return all resources. If RESOURCETYPE_ANY is set, then the MPR also sets RESOURCETYPE_DISK and RESOURCETYPE_PRINT, so that if the NP enumerates only for printers and disks, then it need only test for RESOURCETYPE_DISK, and RESOURCETYPE_PRINT. It need not explicitly test for RESOURCETYPE_ANY.

dwUsage
Used to specify the usage of resources of interest. This is a bit mask which may be any combination of the following:
RESOURCEUSAGE_CONNECTABLE | All connectable resources.
RESOURCEUSAGE_CONTAINER | All container resources.
RESOURCEUSAGE_ALL | All resources.

lpNetResource
This specifies the container to perform the enumeration. The NETRESOURCE could have been obtained via a previous NPEnumResource, or constructed by the caller. If the lpRemoteName field of the NETRESOURCE is NULL, the NP should enumerate the top level of its network. A user would normally start off by calling NPOpenEnum with this parameter set to NULL, and then use the returned results for further enumeration. If the calling program knows exactly the provider and remote path to enumerate from, it may build its own NETRESOURCE structure to pass in, filling in the lpProvider and lpRemoteName fields. If dwScope is RESOURCE_CONNECTED lpNetResource is NULL.
lphEnum
If the function call is successful, this will contain a handle that can then be used for enumeration.
  • WN_SUCCESS if the call is successful. Otherwise, an error code is returned, which may include the following:
WN_NOT_SUPPORTED | The provider does not support the type of enumeration being requested, or the specific network resource cannot be browsed.
WN_NOT_CONTAINER | lpNetResource does not point to a container.
WN_BAD_VALUE | Invalid dwScope or dwUsage or dwType, or bad combination of parameters is specified.
WN_NO_NETWORK | The network is not present.
WN_NOT_AUTHENTICATED | Authentication needs to occur before the network resource can be enumerated.
WN_NOT_LOGGED_ON | Log on needs to occur before the network resource can be enumerated.
WN_ACCESS_DENIED | The user is authenticated to the network where the enumeration is being attempted, but does not have sufficient permissions (access rights).


NPEnumResource

NPEnumResource performs an enumeration based upon the handle returned by NPOpenEnum. On this call the NP fills the buffer with the requested number of entries (or the maximum that can fit). The returned NETRESOURCE structures must be located contiguously at the head of the buffer passed in (for example, an array of such structures), and the pointers in these structures must point to locations within the buffer. As such, data referenced by these pointers will be located at the end of the buffer, after the array of structures. It is the NP's responsibility to package this information correctly. Note that when returning an enumeration for dwScope set to RESOURCE_CONTEXT, all siblings must be returned together (contiguously, but may span buffers) with the RESOURCEUSAGE_SIBLING bit set in the dwUsage field for every sibling except the first.

DWORD NPEnumResource (
  HANDLE hEnum,
  LPDWORD lpcCount,
  LPVOID lpBuffer,
  DWORD cbBuffer,
  LPDWORD lpcbFree
  );
hEnum
This must be a handle obtained from NPOpenEnum call.
lpcCount
Specifies the number of entries requested. It may be 0xFFFFFFFF to request as many as possible. On successful call, this location will receive the number of entries actually read.
lpBuffer
A pointer to the buffer to receive the enumeration result, which are returned as an array of NETRESOURCE entries. The buffer is valid until the next call using hEnum.
cbBuffer
This specifies the size in bytes of the buffer passed to the function call.
lpcbFree
A pointer to a variable that the NP should set to the number of bytes remaining unused in the buffer. These bytes are the unused bytes immediately after the array of NETRESOURCE structures, and before the variable-length strings pointed to by those NETRESOURCE structures. When enumerating from multiple networks in turn, the MPR will pass the entire buffer to the first NP, then pass just the unused space to the next NP, and so on. If the NP cannot fit a single entry in the buffer, then the NP should set this variable to the number of bytes required to contain the next entry that it will return (including all variable-length strings, such as the provider name), and return a status of WN_MORE_DATA.
  • WN_SUCCESS if the call is successful, the caller may continue to call NPEnumResource to continue the enumeration.
WN_NO_MORE_ENTRIES | No more entries found. The enumeration completed successfully (the contents of the return buffer is undefined). Other error codes include:
WN_MORE_DATA | The buffer is too small even for one entry. lpcbFree gives the size of buffer required for the next entry.
WN_BAD_HANDLE | hEnum is not a valid handle.
WN_NO_NETWORK | The network is not present. This condition is checked for before hEnum is tested for validity.

The lpNetResource provided to NPOpenEnum is guaranteed by the system to not be NULL. The NP sets lpProvider to point to the name of the NP (the name returned from calling NPSGetProviderName) for all enumerations.

When returning remote names, the NP should provide the complete remote name (as opposed to the shorter name displayed in the Explorer, which is generated using NPFormatNetworkName). For example, an entry describing a share would be returned as \\server\SHARE, which is a format suitable for passing to WNetAddConnection.


NPCloseEnum

Closes an enumeration.

DWORD NPCloseEnum (
  HANDLE hEnum
  );
hEnum
This must be a handle obtained from NPOpenEnum call.
  • WN_SUCCESS if the call is successful. Otherwise, an error code is returned, which may include:
WN_NO_NETWORK | The network is not present. This condition is checked for before hEnum is tested for validity.
WN_BAD_HANDLE | hEnum is not a valid handle.


Navigating Up from an Enumeration

The enumeration tree can be navigated down from a resource by opening an enumeration upon a resource, as described above. To enumerate up from a resource, the NPGetResourceInformation function is called to obtain information about the resource, followed by the NPGetResourceParent function described below to obtain the name and type of the parents.

NPNetGetResourceInformation should determine if the resource actually is for the network, although it may not be currently accessible or fully valid.

For example: if the resource is \\server\share and dwType specifies a disk, then the provider should ensure that the server server exists on the network, but does not have to validate share. If the resource is \\server\share and dwType is not specified The function should not do purely syntactical checking as this will produce incorrect results when two networks are running on the client and the provider doing syntactic checking is called first.

NPGetResourceParent is typically called for names that were returned by the same NP from a call to NPEnumResource. However, the NP implementation should not assume that the name passed in is valid or references an existing network resource. If the resource syntactically has a parent, then this can be returned, whether or not the parent actually exists. The lpProvider field is filled in by the provider to indicate which behavior the provider is exhibiting. Note, however, the special case where the parent object is the network, where syntactic checking should be avoided if some checking (such as service advertising) can be done to correctly determine the provider.


NPGetResourceInformation

DWORD NPGetResourceInformation(
  LPNETRESOURCE lpNetResource,
  LPVOID lpBuffer,
  LPDWORD cbBuffer,
  LPTSTR *lplpSystem
  );
lpNetResource
This specifies the network resource for which the information is required. The lpRemoteName field of NETRESOURCE specifies the remote name of the network resource whose information is required. If the calling program knows the values for the lpProvider and dwType fields, then it should fill them in, otherwise, it should set them to NULL. All other fields in the NETRESOURCE are ignored and are not initialized.
lpBuffer
A pointer to the buffer to receive the result, which is returned as a single NETRESOURCE entry representing the parent resource. The lpRemoteName, lpProvider, dwType, and dwUsage fields are returned, all other fields being set to NULL. The remote name returned should be in the same syntax as that returned from an enumeration, so that the caller can do a case-sensitive string compare to determine whether an enumerated resource is this resource. If the provider owns a parent of the network resource, (in other words is known to be the correct network to respond to this request), then lpProvider should be filled in with a non-null entry. If it is known that a network owns a parent of the resource, but that the resource itself is not valid, then lpProvider is returned as a non-null value together with a return status of WN_BAD_VALUE. dwScope is returned as RESOURCE_CONTEXT if the network resource is part of the user's network context. Otherwise it is returned as zero.
cbBuffer
This specifies the size, in bytes, of the buffer passed to the function call. If the result is WN_MORE_DATA, this will contain the buffer size required (in bytes) to hold the NETRESOURCE information.
lplpSystem
Returned pointer to a string in the buffer pointed to by lpBuffer that specifies the part of the resource that is accessed through system resource type specific APIs rather than Wnet APIs. For example, if the input remote resource name was \\server\share\dir, then lpRemoteName is returned pointing to \\server\share and lplpSystem points to \dir, both strings being stored in the buffer pointed to by lpBuffer.
  • WN_SUCCESS if the call is successful.

    WN_MORE_DATA if input buffer is too small.

WN_BAD_VALUE | Invalid dwScope or dwUsage or dwType, or bad combination of parameters is specified (for example, lpRemoteName does not correspond to dwType).
WN_NOT_AUTHENTICATED | The caller does not have the necessary permissions to obtain the name of the parent.
WN_ACCESS_DENIED | The user is authenticated to the network, but does not have sufficient permissions (access rights).


NPGetResourceParent

DWORD NPGetResourceParent(
  LPNETRESOURCE lpNetResource,
  LPVOID lpBuffer,
  LPDWORD cbBuffer
  );
lpNetResource
This specifies the network resource for which the parent name is required. The NETRESOURCE could have been obtained via a previous NPEnumResource, or constructed by the caller. The lpRemoteName field of the NETRESOURCE specifies the remote name of the network resource whose parent name is required. If the calling program knows the values for the lpProvider and dwType fields, then it can fill them in, otherwise, they are set to NULL. If the lpProvider field is not NULL, then the network provider DLL can assume that the resource is owned by its network, but if it is NULL, then it must assume that the resource could be for some other network and do whatever checking is necessary to ensure that the result returned is accurate. For example, if being asked for the parent of a server, and the server is not part of a workgroup, then the network provider DLL should check to ensure that the server is part of its network and, if so, return its provider name. All other fields in the NETRESOURCE are ignored and are not initialized.
lpBuffer
A pointer to the buffer to receive the result, which is returned as a single NETRESOURCE entry representing the parent resource. The lpRemoteName, lpProvider, dwType, and dwUsage fields are returned, all other fields being set to NULL. lpProvider should be set to NULL if the provider has only done a syntactic check (i.e. does not know that the resource is specific to its network). If the provider owns a parent of the network resource, (in other words is known to be the correct network to respond to this request), then lpProvider should be filled in with a non-null entry, even if the status return is WN_BAD_VALUE. The remote name returned should be in the same syntax as that returned from an enumeration, so that the caller can do a case-sensitive string compare to determine whether an enumerated resource is this resource. If a resource has no browse parent on the network, then lpRemoteName is returned as NULL. The RESOURCEUSAGE_CONNECTABLE value in the dwUsage field does not indicate that the resource can currently be connected to, but that the resource is connectable when it is available on the network.
cbBuffer
This specifies the size in bytes of the buffer passed to the function call. If the result is WN_MORE_DATA, this will contain the buffer size required (in bytes) to hold the NETRESOURCE information.
  • WN_SUCCESS if the call is successful.

    WN_MORE_DATA if input buffer is too small.

WN_BAD_VALUE | Invalid dwScope or dwUsage or dwType, or bad combination of parameters is specified (e.g. lpRemoteName does not correspond to dwType).
WN_NOT_AUTHENTICATED | The caller does not have the necessary permissions to obtain the name of the parent.
WN_ACCESS_DENIED | The user is authenticated to the network, but does not have sufficient permissions (access rights).


Authentication Functions

The following topics describe the Authentication functions.


LOGONINFO

The following structure is passed to an NP when a log on or log off occurs.

typedef struct _LOGONINFO {
  LPTSTR lpUsername,
  LPTSTR lpPassword,
  DWORD cbUsername,
  DWORD cbPassword
} LOGONINFO, *LPLOGONINFO;
lpUsername
The name of the user logged on, as provided to the system logon dialog box.
lpPassword
The system logon password.
cbUsername
The size in bytes of the lpUsername buffer.
cbPassword
The size in bytes of the lpPassword buffer.


Logging On

This function is used to log the user on to this network. The NP may use the provided user name and password as defaults, obtain them and additional logon information from the password cache subsystem, or display a dialog box to the user. Displaying a dialog box is not recommended, since if multiple networks are loaded, the logon process could become quite lengthy.

NPLogon is actually called twice, once to log the user on to the network and once to indicate that the logon process is complete. NPs may use the two calls to maintain internal state in order to control different behavior during the course of a log on. Persistent connections are restored after the initial NPLogon call and before the corresponding call with the LOGON_DONE flag. If an NP does not maintain internal state in this way, it should ignore the call that has the LOGON_DONE flag set.

The user may have a User Profile (per-user portion of the registry) stored on a network server. Since log on to that network is probably necessary to gain access to that profile, the NP for that network may be designated the Primary Logon Provider (PLP). This NP's NPLogon entrypoint is called before the user profile is loaded, and is passed the LOGON_PRIMARY flag. The PLP is responsible for displaying the main logon dialog box, possibly with customizations such as a domain or server to log in to. When the user successfully logs on, the PLP should return the user name and password that the user typed into the dialog box in the lpUsername and lpPassword buffers of the LOGONINFO structure.

Because the system does not maintain logon state, this function may be called when the user is already logged on (for example, when the user inserts a removable network card). In this case, the provider should perform any logon operations necessary for the additional media. If all necessary logon operations have already been performed for an existing network adapter, the provider may simply return WN_SUCCESS. In these extra logon requests, the LOGON_PRIMARY flag will never be set. There will still be two notifications, one without LOGON_DONE and one with.

The provider should also check to see whether it is running on any active networks before taking any action. If no network adapters or other media are available, the provider should return WN_NO_NETWORK without displaying any UI. This way, the user will not receive a network logon dialog box when not connected to a network.


NPLogon

DWORD NPLogon(
HWND hwndOwner,
LPLOGONINFO lpAuthentInfo,
LPLOGONINFO lpPreviousAuthentInfo,
LPTSTR lpLogonScript,
DWORD dwBufferSize,
DWORD dwFlags
  );
hwndOwner
A handle to a window which should be the owner for any dialog boxes or messages which the provider might display.
lpAuthentInfo
A structure describing the user who logged on.
lpPreviousAuthentInfo
A structure describing the user's previous authentication information, if a password change was required during the logon process. If no password change was required, this parameter will be NULL.
lpLogonScript
Points to a buffer to which the NP may copy the path of an executable program or batch file which should be run upon successful log on. This buffer is initialized by the MPR to be a null string. If the NP leaves the buffer that way, no logon script will be executed for that network.
dwBufferSize
Size of the lpLogonScript buffer in bytes. This is guaranteed to be at least as long as the maximum length of a MS-DOS pathname. Since this entrypoint should not be called multiple times for a single logon phase, the NP may not return WN_MORE_DATA if the buffer is not large enough. In this case, the NP should just provide a null string, and no logon script will be executed for that network.
dwFlags
Any combination of the following values:
LOGON_DONE | Log on is completed.
LOGON_PRIMARY | This NP is the Primary Logon Provider. The provider should always display a user interface, and should return the user name and password in the lpAuthentInfo structure's buffers. The provider must return a non-blank user name; the password may or may not be blank.
LOGON_MUST_VALIDATE | If LOGON_PRIMARY is also set, the user must either be successfully authenticated with the network, or must cancel the log on. An "unconfirmed" log on is not permitted. If the provider returns WN_NOT_VALIDATED, MPR will display an appropriate warning message.

  • WN_SUCCESS if the call is successful. Otherwise, an error code is returned, which may include:
WN_CANCEL | The user canceled a logon dialog box displayed by the provider.
WN_NOT_VALIDATED | The call is successful, but the user has not been authenticated with a network entity. It is not certain that the user's credentials are correct.


NPLogoff

This function is used to log the user off from this network. The NP has the opportunity to confirm the log off, if its effects could reach beyond those of active connections being disconnected and open files being closed (the MPR will warn about these before calling any NPs).

NPLogoff is also called with the same sequence when the user chooses to shut down or restart the computer.

DWORD NPLogoff(
HWND hwndOwner,
LPLOGONINFO lpAuthentInfo
DWORD dwReason
  );
hwndOwner
A handle to a window which should be the owner for any dialog boxes or messages which the provider might display.
lpAuthentInfo
A structure describing the currently logged-on user.
dwReason
One of the following values:
LOGOFF_PENDING | Log off is beginning. The NP should display additional confirmations if necessary. If the user wishes to cancel the log on, the NP should return WN_CANCEL. The NP should not perform any logoff or cleanup operations until LOGOFF_COMMIT.
LOGOFF_COMMIT | Log off is approved. The NP should take whatever actions necessary to log the user off. The NP may not refuse the log off at this point.
LOGOFF_CANCEL | Passed only if this NP has been called with LOGOFF_PENDING for this log off. An NP or application has canceled the log off, so the log off is not happening after all.

  • WN_SUCCESS if the call is successful. Otherwise, an error code is returned, which may include:
WN_CANCEL The user wishes to cancel the log off.


NPGetHomeDirectory

This function is used to determine the home or personal directory associated with a user's account on a given network. Since the user's home directory is a typical place to store their User Profile (per-user registry settings), the directory should be one which the user (and network administrators) can write to, but which other users cannot write to.

DWORD NPGetHomeDirectory(
  LPTSTR lpDirectory,
  LPDWORD lpBufferSize
  );
lpDirectory
Points to a buffer to receive the directory path. This will be either in UNC or drive-relative form, whichever is supported by the network.
lpBufferSize
This is used to specify the size of the buffer passed in. If the call fails because the buffer is not big enough, this location is used to return the required buffer size.
  • WN_SUCCESS if the call is successful. Otherwise, GetLastError should be called for extended error information.
WN_NOT_LOGGED_ON | The user is not logged on to this network.
WN_NOT_SUPPORTED | The network does not support home directories, or the user does not have a home directory.
WN_MORE_DATA | The buffer is too small.


NPGetPolicyPath

This function is used to determine the default location and filename for a policy file on a given network. The path should be one which network administrators can write to, but users cannot. The directory should also allow unvalidated connections, since policies are retrieved prior to log on. (If unvalidated connections are not available, then policies will be downloaded after user log on and not all settings will take effect immediately.)

DWORD NPGetPolicyPath(
  LPTSTR lpPath,
  LPDWORD lpBufferSize,
  DWORD dwFlags
  );
lpPath
Points to a buffer to receive the path and filename of the policy file. This will be either in UNC or drive-relative form, whichever is supported by the network.
lpBufferSize
This is used to specify the size of the buffer passed in. If the call fails because the buffer is not big enough, this location is used to return the required buffer size.
dwFlags
Any combination of the following values:
GPP_LOADBALANCE The NP should pick a load-balancing policy path if it supports it. Normally the policy path should be to a known location on a single server, but if the load-balancing flag is set and the NP has a pool of servers that it may use, it should do so.

  • WN_SUCCESS if the call is successful. Otherwise, GetLastError should be called for extended error information.
WN_MORE_DATA The buffer is too small.


Error Handling

An NP returns standard error codes to report errors like insufficient memory. An NP can also use the error reporting services NPSSetCustomText or NPSSetExtendedError described below to report errors that contain provider specific information. An NP should not call SetLastError.

Also, because MPR can try several networks when attempting a network operation, NPs need to be very careful to not return a hard error code unless certain that the request is specifically for their network. This can cause MPR to terminate trying networks and report the error back to the user. When not certain that the error is for its network, an NP should return only one of the following errors (since any other error returned will cause MPR to stop trying other networks to satisfy the request):

  • WN_BAD_LOCALNAME
  • WN_BAD_NETNAME
  • WN_FUNCTION_BUSY
  • WN_NO_NETWORK
  • WN_NO_NET_OR_BAD_PATH
  • WN_NOT_CONNECTED
  • WN_NOT_CONTAINER
  • WN_NOT_LOGGED_ON

Note that, in particular, returning ERROR_BAD_NETPATH will cause MPR to stop trying other NPs, so this code could be returned, for example for a bad share name when the server name is known to exist. Used in conjunction with NPSSetCustomText this gives good performance, a descriptive error to the user, and the calling program good opportunity for intelligent error handling.


Standard Error Codes

Status codes include:

WN_SUCCESS | Success.
WN_NOT_SUPPORTED | Function not supported.
WN_MORE_DATA | Warning: buffer too small.
N_BAD_POINTER | Invalid pointer specified.
WN_BAD_VALUE | Invalid numeric value specified.
WN_BAD_PASSWORD | Incorrect password specified.
WN_ACCESS_DENIED | Security violation.
WN_FUNCTION_BUSY | This function cannot be reentered and is currently being used, or the provider is still initializing and is not ready to be called yet.
WN_WINDOWS_ERROR | A required Windows function failed.
WN_BAD_USER | Invalid user name specified.
WN_OUT_OF_MEMORY | Out of memory.
WN_NOT_CONNECTED | Device is not redirected.
WN_OPEN_FILES | Connection could not be canceled because files are still open.
WN_BAD_NETNAME | Network name is invalid.
ERROR_EXTENDED_ERROR | The NP has a text error message to report.
ERROR_UNEXP_NET_ERROR | The network encountered an error for which it cannot generate a specific error code.

One notable difference is that the WN_FUNCTION_BUSY code is also used to indicate that the provider is initializing and is not ready to be called yet. The provider should only return this if it is going to be available, since this return code is passed by MPR back to its caller and is likely to cause an application to retry.


Network Provider Services

Services are provided by MPR to relieve the NP from the burden of implementing code common to many or all NP implementations and to help ensure common behavior between NPs. These services are intended to be called by an NP rather than directly from an application. The services are:


Notification Functions

A general and extensible mechanism is provided so that any NP can monitor and have limited control over WNet operations being attempted by the MPR at the request of an application. This mechanism is currently provided for adding, canceling, and obtaining performance information about network connections. Notification for other services may be added in the future.

The NP can register a notification function for a specific type of WNet operation with MPR (by calling NPSNotifyRegister). Then, whenever the MPR is attempting the operation, it will call the notification function, both before and after attempting the operation (pre-notification and post-notification, respectively). The notification function can cancel the WNet operation, or, in the event of a failure, request the MPR to retry the operation. If the requesting application makes an invalid WNet request that is detected by MPR before attempting the operation (e.g. passing in bad parameters), then the notification is not performed.

Currently there is no mechanism for an NP to stop being notified once it has registered itself for notification. This is because currently the notification mechanism is only supported for use by network provider DLLs which are loaded and unloaded by MPR. In the future the notification mechanism may be extended for use by applications or other types of DLL, in which case a de-register function will also be provided.

When more than one NP wants notification for an operation, the pre-notification functions are called by MPR in the opposite order than that they were registered by the NP's and the post-notification functions are called in the reverse order to that of pre-notification.

Control of the operation is achieved by returning specific values from the notification function.

The pre-notification function must give the MPR a context to associate with a WNet operation if it is interested in post-notification, which the NP can use to track the progress of the operation (e.g. only retry failed operations once, or reverse some operation previously performed by the NP if the operation fails).

If an NP wants to communicate its notification context to its corresponding NP operation implementation (i.e. NPAddConnection, NPCancelConnection, or NPGetConnectionPerformance), then it can do so by calling NPSNotifyGetContext from within the NP operation implementation.

The registration function is as follows: NPSNotifyRegister.


NPSNotifyRegister

DWORD NPSNotifyRegister(
      enum NOTIFYTYPE NotifyType,
      NOTIFYCALLBACK NotifyCallBack
  );
NotifyType
The type of notification. This takes the values:
NotifyAddConnection | For adding connections.
NotifyCancelConnection | For canceling connections.
NotifyGetConnectionPerformance | For get connection performance estimates.

NotifyCallBack
The notification function to be called back in the context of the application making the WNet request. A different callback address should be given for each type of notification registered.
  • WN_SUCCESS - the notification function was successfully registered with MPR.
WN_BAD_VALUE | NotifyType is not a valid operation type, or NotifyCallBack is NULL.
WN_OUT_OF_MEMORY | MPR is out of memory, so the notification function was not registered.

The notification function takes the same form for notification of all operations:

DWORD  (FAR PASCAL *NOTIFYCALLBACK) pfNotifyCallback(
  LPNOTIFYINFO lpNotifyInfo,
  LPVOID lpOperationInfo
  );

lpNotifyInfo | Generic notification information common to all types of operation.
lpOperationInfo | Pointer to a structure containing information specific to the operation being attempted. The structure is given below for each type of notification function.

Returns WN_SUCCESS - the notification was processed without error. If dwNotifyStatus has the NOTIFY_PRE flag set, the operation will be attempted and *pfNotifyCallback called again with the NOTIFY_POST flag set in dwNotifyStatus. The return status in dwOperationStatus is returned to the user.

WN_RETRY | The operation failed and the notification function wants a retry. The operation will be retried by MPR and the pre-notification is not done a second time to this NP. This value should not be returned when being pre-notified or post-notified of a successful operation (if it is, it will be treated as WN_SUCCESS).
WN_CANCEL | The user canceled the operation in some user interface produced within *pfNotifyCallback. WN_CANCEL is returned to the caller and a subsequent post-notification is not done to this NP, so any memory allocated for the context should be freed by the NP. This value should not be returned when being post-notified of a successful operation (if it is, it will be treated as WN_SUCCESS).

Any other value is returned to the caller as the result of the operation attempt (unless in post-notification of a successful operation, in which case it is ignored), so should only be returned if there was some internal error in the notify function (such as WN_OUT_OF_MEMORY) or to alter the error return status code to the caller. If an error is returned in pre-notification, post-notification is not done to this NP. When in post-notification and an error is returned, NPSSetCustomText or NPSSetExtendedError may be called to specify the error text, but SetLastError does not need to be explicitly called.


NOTIFYINFO

The NOTIFYINFO structure, common to all notify functions, has the following form:

typedef struct _NOTIFYINFO {
  DWORD cbStructure;
  DWORD dwNotifyStatus;
  DWORD dwOperationStatus;
  LPVOID lpNPContext;
} NOTIFYINFO, *LPNOTIFYINFO;
cbStructure
The size of the NOTIFYINFO structure in bytes.
dwNotifyStatus
The status of the notification. The notification function should check this field to ensure that the notification is of a type that it is interested in, and always return WN_SUCCESS if not. Although in future versions other flags may be added to dwNotifyStatus, it will currently have one of the following flags set:
NOTIFY_PRE | The notification is being done before an attempt to perform the operation (pre-notification). dwOperationStatus is undefined and does not contain a valid value.
NOTIFY_POST | The notification is being done after an attempt to perform the operation (post-notification). dwOperationStatus contains a valid value.

dwOperationStatus
If dwNotifyStatus has the NOTIFY_POST flag set. dwOperationStatus contains the return status code of the operation being attempted after trying all requested providers. If dwNotifyStatus has the NOTIFY_PRE flag set. dwOperationStatus contains either WN_SUCCESS or WN_RETRY.
lpNPContext
This parameter is used by the NP to keep a context with respect to the operation across the several possible calls to the notification function that can be made. lpNPContext is passed in as a NULL pointer when the notification function is called for pre-notification of a particular operation. The notification function can return with lpNPContext still NULL, indicating that it is not interested in further notification for this specific operation, in which case the notification function will not be called again for post-notification of the operation. If the notification function returns a non-NULL value in lpNPContext, then when the notification function is called for post-notification of the same operation. lpNPContext will be the value returned from this call to the notification function.


NPSNotifyGetContext

The function to obtain notification context.

LPVOID NPSNotifyGetContext(
      NOTIFYCALLBACK NotifyCallBack
  );
NotifyCallBack
The notification function that was previously passed in to NPSNotifyRegister for the type of operation currently being attempted.
  • The lpNPContext field filled in the NOTIFYINFO structure by the notification callback function passed in the NotifyCallBack parameter is returned. If NPSNotifyRegister was not previously called with the callback function in NotifyCallBack, then the return value is NULL.


Add Connection Notification

This notification is done when an attempt to add a connection is made (specifically by WNetAddConnection, WNetAddConnection2, WNetAddConnection3, WNetUseConnection, or WNetRestoreConnection).


NOTIFYADD

The lpOperationInfo parameter of the notification function is a pointer to a NOTIFYADD structure which contains the add connection specific information as follows:

typedef struct _NOTIFYADD {
  DWORD cbStructure;
  HWND hwndOwner;
  NETRESOURCE NetResource;
  DWORD dwAddFlags;
  LPTSTR lpAccessName;         /* System name for connection */
      LPDWORD lpBufferSize;    /* Size of AccessName buffer */
  DWORD dwResult;              /* Information about connection */
  DWORD dwAddContext;          /* Context of add connection */
} NOTIFYADD, *LPNOTIFYADD;
cbStructure
The size of the NOTIFYADD structure in bytes.
hwndOwner
A handle to a window which should be the owner for any messages or dialog boxes the NP might display. This is only used if CONNECT_INTERACTIVE is set in dwAddFlags.
NetResource
Specifies the network resource to connect to. The following fields are valid:
lpRemoteName | The name of the network resource. If this parameter is a pointer to an empty string, then access has been attempted to the entire network, such as when starting browsing to a network.
lpLocalName | This specifies the name of a local device to be redirected, such as "F:" or "LPT1". The string is treated in a case-insensitive manner. lpLocalName may be a pointer to an empty string in which case, if lpRemoteName is pointer to a non-empty string, a connection to a network resource is being made without making a redirection.
lpProvider | On pre-notification, specifies which NPs the connect operation was applied to. If a pointer to an empty string, then MPR has tried all valid providers. On post-notification, if the add operation was successful, specifies the name of the NP that performed the add operation.

dwType
Specifies the type of resource connected. It is RESOURCETYPE_DISK or RESOURCETYPE_PRINT if lpLocalName is a pointer to a non-empty string. It may also be RESOURCETYPE_ANY if lpLocalName is a pointer to an empty string and the connection attempt has failed.
dwAddFlags
A combination of the following values:
CONNECT_TEMPORARY | The connection is being established for browsing purposes and will probably be released quickly.
CONNECT_INTERACTIVE | May have interaction with the user.
CONNECT_PROMPT | Do no use any defaults without offering user the chance to supply an alternative. This flag is only valid if CONNECT_INTERACTIVE is set.
CONNECT_UPDATE_PROFILE | If the connection is being made persistent.
CONNECT_UPDATE_RECENT | If the connection is being put in the recent connection list.
CONNECT_REDIRECT | If set, force the auto-picking of a local device for redirection when making the connection, otherwise only auto-pick a local device for redirection if the network requires it to make a connection.

lpAccessName
Pointer to buffer to receive the name that can be used to make system requests on the connection.
lpBufferSize
The size of the lpAccessName buffer.
dwResult
Returned information about the connection.
dwAddContext
The context under which the add is being made, a combination of the following values:
CONNECT_CTXT_RESTORE | The connection is being established to restore a persistent connection.
CONNECT_CTXT_GLOBAL | All persistent connections are being restored. This flag is only valid if CONNECT_CTXT_ RESTORE is set.
CONNECT_CTXT_PROVIDER | The persistent connections for a specific network alone are being restored. This flag is only valid if CONNECT_CTXT_ RESTORE is set.
CONNECT_CTXT_SINGLE | An individual persistent connection is being restored. This flag is only valid if CONNECT_CTXT_ RESTORE is set.


Cancel Connection Notification.

This notification is done when an attempt to cancel a connection is made (specifically by WNetCancelConnection or WNetCancelConnection2).


NOTIFYCANCEL

The lpOperationInfo parameter of the notification function is a pointer to a NOTIFYCANCEL structure which contains the cancel connection specific information as follows:

typedef struct _NOTIFYCANCEL {
  DWORD cbStructure;
  LPTSTR lpName;
      LPTSTR lpProvider;
      DWORD dwFlags;
      BOOL fForce;
} NOTIFYCANCEL, *LPNOTIFYCANCEL;
cbStructure
The size of the NOTIFYCANCEL structure in bytes.
lpName
The name of the local device or network resource whose connection is being canceled.
lpProvider
On pre-notification, not defined (MPR will try all valid providers). On post-notification, if the cancel operation was successful, specifies the name of the NP that canceled the connection.
dwFlags
Any combination of the following values:
CONNECT_UPDATE_PROFILE If the disconnection should remain persistent. If set, Windows will no longer restore this connection when the user logs on.

fForce
Indicates if the disconnect should be done forcefully in the event of open files or jobs on the connection. If FALSE is specified, the cancel connection will not be done if there are open files or jobs.


Get Connection Performance Notification

This notification is done when an attempt to obtain performance information about a connection is made (specifically by MultinetGetConnectionPerformance).

The lpOperationInfo parameter of the notification function is a pointer to a NOTIFYPERFORMANCE structure which contains the get connection performance specific information as follows:


NOTIFYPERFORMANCE

typedef struct _NOTIFYPERFORMANCE {
  DWORD cbStructure;
  LPTSTR lpRemoteName;
  LPNETCONNECTINFOSTRUCT lpNetConnectInfo;
} NOTIFYPERFORMANCE, *NOTIFYPERFORMANCE;
cbStructure
The size of the NOTIFYCANCEL structure in bytes.
lpRemoteName
Specifies the network resource being queried. This is the same value as passed to the providers in the lpRemoteName parameter of NPGetConnectionPerformance.
lpNetConnectInfo
Pointer to the buffer containing the NETCONNECTINFOSTRUCT structure where information is returned. This is the same value as passed to the providers in the lpNetConnectInfo parameter of NPGetConnectionPerformance.


Error Reporting Services

Generally, an NP does not have to do anything to handle standard error codes, as MPR always calls SetLastError on behalf of the NP and keeps text descriptions for standard error codes. However the error reporting services are provided to allow an NP to customize error text for the error messages reported back to the user. When MPR is responding to an application issuing a WNet API request, and an NP calls one of these services, then MPR takes this to mean that the WNet request is known to be specifically for that network and will not try to satisfy the request with other networks. Consequently, these services must only be called when the NP really knows that it owns the request (for example: an NPAddConnection request with a valid server but invalid share name). Doing otherwise will cause incorrect failures when more than one network is running at the same time.

There are two services, NPSSetCustomText and NPSSetExtendedError. Calling either of these services will cause MPR to stop trying other NPs as it is taken that the network is responding to the request.

NPSSetExtendedError is used to generate errors that contain network specific error codes and an optional custom text message. It must be called before an NP returns ERROR_EXTENDED_ERROR, and its results may be obtained by an application calling WNetGetLastError. See the description of WNetGetLastError in the MPR documentation for more details.

NPSSetCustomText is used when returning a standard error code for which an NP has a more specific description of the error than is provided by the default message associated with the error code (again, for example: an NPAddConnection request with a valid server but invalid share name).


NPSSetExtendedError

DWORD NPSSetExtendedError (
  DWORD NetSpecificError,
  LPTSTR lpExtendedErrorText
  );
NetSpecificError
A network specific error code indicating the error that occurred. This is the value that is returned in the lpdwErrorCode parameter of WNetGetLastError.
lpExtendedErrorText
Network specific string describing the error. This field should contain a valid description of the error, but if it is NULL or an empty string then the system will format it's own error text based upon the NetSpecificError number.
  • The return value is the error return status that the NP should return for the operation in error. It will typically be ERROR_EXTENDED_ERROR but may be some other value (such as WN_OUT_OF_MEMORY).

For example, when an NP wants to return ERROR_EXTENDED_ERROR:

// setup NetErrorCode and lpErrorText to be the error to be reported
Error = NPSSetExtendedError( NetErrorCode, lpErrorText) ;
return(Error) ;


NPSSetCustomText

VOID NPSSetCustomText (
  LPTSTR lpCustomErrorText
  );
lpCustomErrorText
Network specific string describing the error. This field must contain a description of the error, otherwise the request will fail, in which case the standard error message is used.

There is no return value.

To return net specific text with a standard Windows error code:

// setup Error and lpErrorString to be the error to be reported
NPSSetCustomText(lpErrorString);
return(Error);


Local Device Name Services

These services are to assist an NP in providing the same behavior as other networks with respect to local device naming and validation (for example, in recognizing that "LPT1:" and "LPT1" are the same device).

A provider can use the NPSDeviceGetNumber function to both validate a local print or disk device string and to convert it to a number.

A provider can use the NPSDeviceGetString function to take a local print or disk device number and convert it to a string.

Note that calling NPSDeviceGetNumber followed by NPSDeviceGetString validates and normalizes a device name.


NPSDeviceGetNumber

DWORD NPSDeviceGetNumber(
  LPTSTR lpLocalName,
  LPDWORD lpdwNumber,
  LPDWORD lpdwType
  );
lpLocalName
Contains the name of the local device the caller is interested in.
lpdwNumber
Returns the number associated with the local device. Devices "A:" to "Z:" for disk devices are assigned numbers 1 to 26, and devices "LPT1" onwards for print devices are assigned numbers 1 onwards.
lpdwType
Returns the type of device passed in. It can be RESOURCETYPE_DISK, RESOURCETYPE_PRINT.
  • WN_SUCCESS if the call is successful.
WN_BAD_LOCALNAME lpLocalName is not a valid disk or print device.


NPSDeviceGetString

DWORD NPSDeviceGetString (
  DWORD dwNumber,
  DWORD dwType,
  LPTSTR lpLocalName,
  LPDWORD lpBufferSize
  );
dwNumber
Specifies the number associated with the local device. Devices "A:" to "Z:" for disk devices are assigned numbers 1 to 26, and devices "LPT1" onwards for print devices are assigned numbers 1 onwards.
dwType
Specifies the type of device passed in. It can be RESOURCETYPE_DISK, RESOURCETYPE_PRINT.
lpLocalName
Returns the name of the local device the caller is interested in. The name will be capitalized with a trailing ":" for disk devices (e.g., "F:" or "LPT2").
lpBufferSize
Specifies the size of the lpLocalName buffer passed in, in bytes. If the call fails because the buffer is not big enough, this location will return the required buffer size.
  • WN_SUCCESS if the call is successful.
WN_BAD_LOCALNAME | dwNumber is not a valid number for a disk or print device.
WN_MORE_DATA | The lpLocalName buffer is too small.


Buffer Services

It is recommended that a provider use the NPSCopyString function to copy its string results into the buffers passed to it by MPR, because there are the various combinations of NULL pointers, zero length buffers, and buffer too small to be dealt with. Using NPSCopyString ensures the same behavior to the application for every NP.


NPSCopyString

DWORD NPSCopyString(
  LPCTSTR lpSourceString,
  LPVOID lpDestBuffer,
  LPDWORD lpBufferSize
  );
lpSourceString
Pointer to the string to copy into the destination buffer, or NULL if the NP has no string to copy.
lpDestBuffer
The destination buffer to copy the string.
lpBufferSize
The size of the destination buffer.
  • WN_SUCCESS if the call is successful.
WN_BAD_POINTER | lpBufferSize is not a valid pointer to a valid buffer size.
WN_MORE_DATA | The lpDestBuffer buffer is too small. lpBufferSize is returned with the required buffer size.


Password Cache Services

These services are to allow an NP to store authentication information, including passwords, in a persistent and secure store. This store is encrypted using the system logon user name and password. When a successful system log on has occurred, the password cache is available for use by NPs and applications.

There is a system configuration switch which disables password caching, for those sites which do not want it for extra security. An NP can also indicate that it does not want its passwords persistently cached, again for extra security. In both of these cases, the password caching subsystem will still store passwords in memory, but will not write them to disk.

For complete details on the password caching APIs, see the Windows for Workgroups SDK documentation. The changes to the APIs are as follows:

The WNetCachePassword API accepts an additional parameter which indicates whether the password should be permanent (i.e., written to disk).

The WNetEnumCachedPasswords API accepts an additional DWORD parameter which is application-defined. This parameter is passed to the enumeration callback function along with the entry being enumerated.


Authentication Dialog Service

This service allows an NP to obtain authentication information from the user in a manner consistent with other networks in the system. It displays a standard dialog box with several optional fields that the user may fill in.


NPSAuthenticationDialog

DWORD NPSAuthenticationDialog (
  LPAUTHDLGSTRUCT lpAuthDlgStruct
  );
lpAuthDlgStruct
Pointer to a structure that describes the required behavior and results of the authentication dialog box. This structure has the following format:


AUTHDLGSTRUCT

typedef struct _AUTHDLGSTRUCT{
    DWORD cbStructure;
    HWND hwndOwner;
    LPCSTR lpResource;
    LPTSTR lpUsername;
    DWORD cbUsername;
    LPTSTR lpPassword;
    DWORD cbPassword;
    LPTSTR lpOrgUnit;
    DWORD cbOrgUnit;
    LPCSTR lpOUTitle;
    LPCSTR lpExplainText;
    LPCSTR lpDefaultUserName;
    DWORD dwFlags;
} AUTHDLGSTRUCT. *LPAUTHDLGSTRUCT;
cbStructure
The size of the AUTHDLGSTRUCT structure in bytes. This is filled in by the caller to indicate the size of the structure passed in. Upon return, it has the size of the structure filled in.
hwndOwner
A handle to a window which should be the owner of the dialog box.
lpResource
The name of the resource being accessed, to be presented to the user.
lpUsername
On entry, the default user name to be displayed in the dialog box. On exit, this parameter is filled with the user name supplied. If this parameter is NULL, no user name field is displayed in the dialog box.
cbUserName
Specifies the size of the lpUsername buffer passed in, in bytes. If the call fails because the buffer is not big enough, this location will return the required buffer size.
lpPassword
On entry, the default password to be displayed in the dialog box. On exit, this parameter is filled with the password supplied.
cbPassword
Specifies the size of the lpPassword buffer passed in, in bytes. If the call fails because the buffer is not big enough, this location will return the required buffer size.
lpOrgUnit
On entry, the default organizational unit name (for example, a Windows NT/Windows 2000 domain) to be displayed in the dialog box. On exit, this parameter is filled with the organizational unit supplied. If this parameter is NULL, no organizational unit field is displayed in the dialog box.
cbOrgUnit
Specifies the size of the lpOrgUnit buffer passed in, in bytes. If the call fails because the buffer is not big enough, this location will return the required buffer size.
lpOUTitle
Specifies the label for the organizational unit field. If this parameter is NULL, a default title of "Domain:" is used. If the lpOrgUnit parameter is NULL, this parameter is ignored.
lpExplainText
Explanatory text at the top of the dialog box, NULL for default text.
lpDefaultUserName
The guest user name to be used if AUTHDLG_USE_DEFAULT_NAME is specified and the user checks that checkbox.
dwFlags
Contains any combination of the following values:
AUTHDLG_ENABLECACHE | Display and enable the check box which allows the user to choose whether or not to save the password in the password cache.
AUTHDLG_CHECKCACHE | If set, causes the password caching checkbox to be checked by default. On exit, this bit reflects the state of the checkbox as left by the user. This bit is ignored if AUTHDLG_ENABLECACHE is not set.
AUTHDLG_CACHEINVALID | If set, a specific dialog box is produced if the cached password was invalid.
AUTHDLG_USE_DEFAULT_NAME | If set, display and enable a check box which the user can check to use a default or "guest" log on.
AUTHDLG_CHECKDEFAULT_NAME | On entry, specifies the initial state of the "guest log on" check box. On exit, specified the final state of the check box.
AUTHDLG_LOGON | If set, causes the dialog box to appear as a logon dialog box instead of a password prompt dialog box. The chief difference is that a network icon is displayed in the logon dialog box. An NP should specify this flag when displaying a logon dialog box for its NPLogon entrypoint.

  • WN_SUCCESS if the call is successful.
WN_CANCEL The user chose the Cancel button in the dialog box.


Initialization/Configuration Services

The following topics describe the Initialization and Configuration services.


NPSGetProviderHandle

DWORD NPSGetProviderHandle(
  HPROVIDER FAR * phProvider
  );

This service provides a handle to an NP that it can subsequently use in interfacing to MPR. Currently, this handle is used in NPSGetProviderName. Calling this function is only valid in the process initialization of the NP DLL.

phProvider
Returns a handle that can be passed to MPR to refer to this instantiation of the NP DLL.
  • WN_SUCCESS if the call is successful.
WN_NOT_INITIALIZING lpdwType is not a valid type of device.


NPSGetProviderName

DWORD NPSGetProviderName(
  HPROVIDER hProvider,
  LPCSTR FAR * lpszProviderName
  );

This service allows a provider to obtain its name from MPR for use in supporting services.

hProvider
The handle returned from a previous call to NPSGetNPHandle.
lpszProviderName
Returns a pointer to the NP's name. This pointer is valid for the duration of the NP DLL being loaded.
  • WN_SUCCESS if the call is successful.
WN_BAD_HANDLE hProvider is not a valid NP handle.


NPSGetSectionName

DWORD NPSGetSectionName(
  HPROVIDER hProvider,
  LPCSTR FAR * lpszSectionName
  );
hProvider
The handle returned from a previous call to NPSGetNPHandle.
lpszSectionName
Returns a pointer to the NP's section name. This pointer is valid for the duration of the NP DLL being loaded.
  • WN_SUCCESS if the call is successful.
WN_BAD_HANDLE hProvider is not a valid NP handle.


Implementation Guidelines

Providers should follow the guidelines below as far as possible.


Speed

Providers should be as quick as possible when determining if it recognizes a resource to be its own, since the MPR may have to cycle through the providers. If it does not own a resource, it should return WN_BAD_NETNAME.


Validation

The order of validation is important. A provider should first check if its network is started, then check if it supports the operation. After these checks, if it receives any network resources it should check if it owns them, and then finally validate other parameters.

If the router is cycling through providers, it will assume a provider has handled a call if the error return is not one of the following:

WN_NO_NETWORK
WN_NOT_SUPPORTED
WN_BAD_NETNAME
WN_BAD_LOCALNAME
WN_NOT_CONNECTED


Function Summary

The table below lists entrypoints which NPs may export, and their ordinals. NPGetCaps must be exported by name. Its presence is used by the MPR to identify a DLL as a valid NP. All other NP entrypoints are loaded by the MPR using their ordinals. An NP may export those entrypoints by ordinal only in order to reduce the size of the NP DLL file.

Function Name | Ordinal
NPGetCaps | 13
NPGetUser | 16
NPAddConnection | 17
NPCancelConnection | 18
NPGetConnection | 12
NPOpenEnum | 33
NPEnumResource | 34
NPCloseEnum | 35
NPGetUniversalName | 36
NPGetResourceParent | 41
NPValidDevice | 42
NPLogon | 43
NPLogoff | 44
NPGetHomeDirectory | 45
NPFormatNetworkName | 46
NPGetConnectionPerformance | 49
NPGetPolicyPath | 50
NPGetResourceInformation | 52


Obsolete APIs

The following functions is Windows 3.1 WinNet are not implemented in a Windows 95 NP.

WNetGetError
WNetGetErrorText
WNetGetPropertyText
WNetPropertyDialog
WNetOpenJob
WNetCloseJob
WNetWriteJob
WNetAbortJob
WNetHoldJob
WNetReleaseJob
WNetCancelJob
WNetSetJobCopies
WNetWatchQueue
WNetUnwatchQueue
WNetLockQueueData
WNetUnlockQueueData
WNetViewQueueDialog
WNetPrintMgrChangeMenus
WNetPrintMgrExiting
WNetPrintMgrCommand
WNetPrintMgrMoveJob
WNetPrintMgrSelNotify
WNetPrintMgrPrinterEnum
WNetPrintMgrExtHelp
LFNFindFirst
LFNFindNext
LFNFindClose
LFNGetAttribute
LFNSetAttribute
LFNCopy
LFNMove
LFNDelete
LFNMKDir
LFNRMDir
LFNGetVolumeLabel
LFNSetVolumeLabel
LFNParse
LFNVolumeType


Installation/Configuration

The NPs are registered with the MPR by putting entries in the registry.

A REG_SZ value named Order is placed on the following key to list the NPs:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order

Order has a list of named values beneath it in the registry hierarchy, one for each NP. The MPR will load networks (NPs) in the order that the values are enumerated from the registry, which cannot be guaranteed to be any specific order. For example:

Order
  NetworkA
  NetworkB
  NetworkX

Each entry in the list corresponds to another key in the registry, specifically for that network. The subkey can be obtained from the MPR when the NP is loading by calling the NPSGetSectionName service. The entry is a subkey from the registry key:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services

Beneath the network specific key, there is a subkey called NetworkProvider under which named values define the NP.

An example network description for the layout of the values is as follows:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NetworkA\NetworkProvider  Name=network name
  ProviderPath=provider DLL filename
  Description=network full description
  NetID=network identifier
  CallOrder=MPR order to call

Other network specific entries may be placed in the section, but the first two letters of the names of such values should be SP to avoid conflict with future standard value names.

Each value has the following meaning:

Name - (REG_SZ) the name of the network being provided by the NP. This should be a short name (recommended to be 24 characters or less) that is unique to the network. It is the resource name returned by the MPR when enumerating networks.

ProviderPath - (REG_EXPAND_SZ) the name of the DLL that the NP is implemented within. The MPR will load this DLL and expect the NP functions to be exported from it.

Description - (REG_SZ) a long text description for the network. This is the comment returned by the MPR when enumerating networks, and is displayed as additional information when useful (for example, when installing networks).

NetID - (REG_DWORD) The identifier for the network. It is the high word of the provider type in the network capabilities returned by the NP, represented in hex. It is noted here so that the network does not have to be running to run multi-network aware configuration software (for example, to de-install a network, or to offer installation options when the user is not currently on the network).

Windows31DLL - (REG_DWORD) Set to 1 if the DLL is a (16 bit) Windows 3.1 Winnet Driver. If this value is not present then the DLL defaults to a 32 bit NP implementation as described throughout this documentation.

CallOrder - (REG_DWORD) A number indicating the order that the provider should be called relative to other NPs. Lower numbered providers are called before higher numbered providers. This value defaults to 0x80000000 for 32 bit NP implementations and to 0xc0000000 for Windows 3.1 Winnet driver implementations. Network providers with the same number are called in the opposite order to which they were loaded. After loading all of the network provider DLLs, MPR calls NPGetCaps for each DLL (for the first time since the DLL was loaded), honoring this call order.

PrinterRedirectionRequired - (REG_DWORD) Set to 1 if a network provider DLL requires a local printer port redirection to use a network printer queue.

ValidPrinters - (REG_DWORD) A 32 bit mask indicating the valid print numbers for redirecting local printer devices, with the lowest order bit corresponding to LPT1. If the NP supports NPValidLocalDevice, then this registry value will be ignored. If the NP does not support NPValidLocalDevice and this field is not present, then the system will assume that all non-used devices can be redirected.

DiskRedirectionRequired - (REG_DWORD) Set to 1 if a network provider DLL requires a local disk drive redirection to access file systems on network servers.

ValidDrives - (REG_DWORD) A 32 bit mask indicating the valid local disk devices for redirecting disk drives, with the lowest order bit corresponding to A:. If the NP supports NPValidLocalDevice, then this registry value will be ignored. If the NP does not support NPValidLocalDevice and this field is not present, then the system will assume that all non-used devices can be redirected.

NetLotLoading - (REG_DWORD) At startup, MPR sets this value to 1 if a network provider DLL fails to load, and deletes the value from the registry if the DLL does load successfully. MPR will not try to load NPs with this value set to 1 after startup, so installers that require a restart for a network to become active should set this value to 1 when installing the network.

ConnectButtonName - (REG_SZ) This is used for a (16 bit) Windows 3.1 Winnet driver that has its own connect or browse dialog boxes. When the network is run in conjunction with 32 bit networks, the common connect dialog box will have a button that brings up the network specific connect or browse dialog box exported from the Winnet driver. This should be a short name (recommended to be 10 characters or less) that fits within the connect dialog box's button. If this field is omitted, then the button text defaults to the value of the Name registry entry above.


Windows 95 Password Providers

Microsoft® Windows™ 95 introduces the idea of password providers. A password provider is a DLL that manages the changing of one or more passwords for a resource or a function.

The advantages of writing a password provider include:

  • Centralized user interface. Users can change any of their passwords in one location (the Passwords Control Panel). Applications can call a central password-change dialog box.
  • Password synchronization. When users change the Windows password, they can elect to have any or all of their other passwords changed at the same time. This relieves users from having to remember more than one password, yet it makes it easy to change passwords frequently.

A password is considered to be stored either locally or remotely. An example of a locally stored password is the Windows screen saver password; an example of remotely stored password is the Windows NT/Windows 2000 domain password. A remotely stored password is considered secure, while a locally stored password is not. Even an encrypted password is not very secure if it's stored locally because most common forms of encryption can be easily broken. Password providers need to identify their passwords as being stored locally or remotely through the PPGetPasswordStatus SPI.

A password is considered to be synchronized or not synchronized with the Windows password (if there is a Windows password). This is based on the user's selection in the Passwords Control Panel and the state can be determined by calling PwdGetPasswordStatus.

When the user changes a password through the Passwords Control Panel or common dialog box, the password provider is typically notified through the PPChangePassword SPI. The password provider is deliberately not notified in the following case, however: if the password is stored locally, and the password is synchronized with the Windows password. When verifying a typed password, the component that does password validation for a local password needs to call PwdGetPasswordStatus to determine whether the password is synchronized with the Windows password. If it is, the component should call WNetVerifyPassword with the typed password, which will determine if the user typed the Windows password. If the password is not synchronized with the Windows password, the component should compare the typed password with the password it stored locally when last notified by PPChangePassword.


Password SPIs

Password providers must implement and export two SPIs: PPChangePassword and PPGetPasswordStatus.


PPChangePassword

This function is used to inform the password provider that the user wishes to change the password for this provider.

DWORD PPChangePassword(
LPLOGONINFO lpAuthentInfo,
LPLOGONINFO lpPreviousAuthentInfo
DWORD dwAction
    );
lpAuthentInfo
A structure specifying the logged-on user's name and new password.
lpPreviousAuthentInfo
A structure specifying the user's name and old password.
dwAction
One of the following values:
PWDCHANGE_MASTERPWD_NOTIFY | The Windows password has changed. The provider may wish to take some action, such as giving the new password to a network redirector.
PWDCHANGE_PROVIDERPWD_PENDING | The user wants to change a password maintained by the provider. This message is a first-phase notification. The provider should not change the password at this time. The provider should do any pre-commit verification that is appropriate, such as pinging a server or checking that the old password is valid, if possible.
PWDCHANGE_PROVIDERPWD_COMMIT | Commit-phase notification, the provider should change the password in response to this message.
PWDCHANGE_PROVIDERPWD_CANCEL | A provider will receive this message if it has already received a first-phase notification (PWDCHANGE_PROVIDERPWD_ PENDING) and the password-change action has been canceled (for example, in response to another provider being unable to change its password).

  • WN_SUCCESS if the call is successful.


PPGetPasswordStatus

This function is used to query a password provider about the status of its password. The attributes an network provider can report are if it is on/off (enabled/disabled), if it requires typing in the old password to change it, and if the storage type is local or remote.

DWORD PPGetPasswordStatus(
DWORD     nIndex
    );
nIndex
Can be one of the following:
PS_ONOFF | Requests on/off status of password.
PS_HASOLDPWD | Requests "old password" status of password.
PS_STORAGETYPE | Requests storage type of password.

  • Can be a combination of the following bits, for each nIndex:
nIndex: | Valid return bits:
PS_ONOFF | PS_ONOFF_ON, PS_ONOFF_OFF
PS_HASOLDPWD | PS_HASOLDPWD_ON, PS_HASOLDPWD_OFF
PS_STORAGETYPE | PS_STORAGETYPE_LOCAL, PS_STORAGETYPE_NETWORK


Password APIs

These APIs may be called by applications or password providers that need to take actions or obtain information.


PwdChangePassword

This function is used to change the user's Windows password or a password provider's password. The MPR displays a dialog box for this purpose. If the Windows password is changed, the MPR re-encrypts the user's password cache with the new password. Password providers are notified through the PPChangePassword SPI.

DWORD PwdChangePassword(
    LPCTSTR lpProvider,
    HWND hwndOwner,
    DWORD dwFlags
    );
lpProvider
Specifies the provider to change the password for. If lpProvider is NULL, the logon password is changed. Changing the logon password can also result in other password providers being notified to change their passwords, if the user has selected to synchronize a provider's password with the logon password.
hwndOwner
A handle to a window which should be the owner for the dialog box displayed by the MPR.
dwFlags
Can be 0, or a combination of the following:
CHANGEPWD_OLDPWDONLY Displays a dialog that prompts only for the previous password. The current logon password is given to the password provider as the new password to use. This flag is ignored if PwdChangePassword is called to change the logon password (lpProvider is NULL). This flag is intended primarily for use by the system, it is not recommended that applications set this flag.

  • WN_SUCCESS if the call is successful. Otherwise, an error, which includes:
WN_CANCEL The user canceled the operation.


PwdGetPasswordStatus

This function is used to retrieve information about a password provider's password. The request is passed to the network provider through the PPGetPasswordStatus SPI.

DWORD PwdGetPasswordStatus(
    LPCTSTR lpProvider,
    DWORD dwIndex,
    LPDWORD lpStatus,
    );
lpProvider
Specifies the network provider who owns the password.
dwIndex
Type of information to retrieve. Can be one of the following:
PS_ONOFF | Returns whether password is active or "turned on". Upon return, the following bits can be set in lpStatus: PS_ONOFF_ON, PS_ONOFF_OFF.
PS_HASOLDPWD | Returns whether it is necessary to supply the previous password in order to change the current password. Upon return, the following bits can be set in lpStatus: PS_HASOLDPWD_ON, PS_HAS_OLDPWD_OFF.
PS_SYNCMASTERPWD | Returns whether the password should be kept in sync with the logon password. Upon return, the following bits can be set in lpStatus: PS_SYNCMASTERPWD_ON, PS_SYNCMASTERPWD_OFF.
PS_STORAGETYPE | Returns whether the password is stored locally, or in a network location. Upon return, the following bits can be set in lpStatus: PS_STORAGETYPE_LOCAL, PS_STORAGETYPE_NETWORK.

lpStatus
A pointer to a bit field that is filled in upon return, based upon the value of the dwIndex field passed in. See the dwIndex field above for the possible values.
  • WN_SUCCESS if the call is successful.


PwdSetPasswordStatus

This function is used to set information about a network provider's password. Currently, the only status information that can be set is whether or not the password should remain in sync with the logon password.

DWORD PwdSetPasswordStatus(
    LPCTSTR lpProvider,
    DWORD dwIndex,
    DWORD dwStatus,
    );
lpProvider
Specifies the network provider who owns the password.
dwIndex
Type of information to retrieve. Can be one of the following:

PS_SYNCMASTERPWD

dwStatus
Status bits to set. Can be one of the following:

PS_SYNCMASTERPWD_ON, PS_SYNCMASTERPWD_OFF

  • WN_SUCCESS if the call is successful.


Password Provider Registration

Password providers must register themselves in the registry to be installed. Every password provider must have a provider name, which should be short and does not appear in any UI. This name is used as the lpProvider parameter in API calls to identify which password provider to call. The provider's installer must create the following key in the registry:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\PwdProvider\<provider name>

In this key, the following values must be set:

ProviderPath=<file name of provider dll>
Description=<description string for UI>
ChangePassword=<exported name of PPChangePassword function>
GetPasswordStatus=<exported name of PPGetPasswordStatus function>

Additionally, the following value may optionally be set:

NetworkProvider=01 00 00 00 (REG_BINARY). This identifies the password provider as a network provider, which means that the password will not appear in the list unless the DLL is already loaded. This allows network providers to register themselves as password providers, but not appear in UI unless their network is installed and running.

An example registry section is as follows:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\PwdProvider\SCRSAVE
ProviderPath=password.cpl
Description="Windows Screen Saver"
ChangePassword="PPChangePassword"
GetPasswordStatus="PPGetPasswordStatus"


Remote Network Access SPI

This documentation lists and describes the interfaces exported by a service provider for remote network access.


RnaSessInitialize

DWORD APIENTRY RnaSessInitialize(LPSTR lpszType, LPRNA_FUNCS lpRnaFuncs)

is called by RNA after loading the SMM to request for SMM entry points for the specified SMM type which RNA can call during the session configuration. The function also allows the SMM to initialize itself and allocate any resource for the specified SMM type.

lpszType
An address to a null-terminated string for the SMM type.
lpRnaFuncs
An address to an RNA_FUNCS structure to receive the addresses for other SMM entry points. On entry, the first DWORD of this structure is filled by RNA with the size of the RNA_FUNCS structure.
  • SUCCESS if successful or one of the error codes.

This is the only function that must be exported from the SMM. Since it can be exported only once per an SMM module, the function can return different entry points in the RNA_FUNCS structure for different SMM types if the module supports different SMM types.


RNA_FUNCS

typedef struct {
  DWORD dwSize;
  SESSSTARTPROC lpfnStart;
  SESSSTARTSTOP lpfnStop;
} RNA_FUNCS;

The structure for SMM entry points for the specified SMM type.

Members

dwSize
The size in bytes of the RNA_FUNCS structure.
lpfnStart
An entry point to the RnaSessStart function.
lpfnStop
An entry point to the RnaSessStop function.


RnaSessStart

DWORD APIENTRY RnaSessStart(HANDLE hConn, LPSESS_CONFIGURATION_INFO lpSCI)

is called by RNA to start an asynchronous session configuration. When the session configuration is complete, the SMM must call the RnaSessComplete function to notify RNA of the result of the configuration.

hConn
A handle to the RNA connection for the SMM to start the session configuration.
lpSCI
An address to a SESS_CONFIGURATION_INFO structure containing the parameters for the session configuration. On entry, the first DWORD of this structure is filled by RNA with the size of the SESS_CONFIGURATION_INFO structure.
  • SUCCESS if the SMM can start the asynchronous session configuration successfully or one of the error codes.

The function should create another thread to continue the session configuration asynchronously. All other services including RnaSessComplete (see the Session Manager API) will be called from the SMM in the context of the SMM-owned thread. When the configuration is complete successfully, the SMM is responsible for terminating this thread.


SESS_CONFIGURATION_INFO

typedef struct {
  DWORD dwSize;
  char szEntryName[RAS_MaxEntryName+1];
  SESSTYPE stSessType;
  BOOL fUserSecurity;
  char szUserName[UNLEN+1];
  char szPassword[PWLEN+1];
  char szDomainName[DNLEN+1];
} SESS_CONFIGURATION_INFO;

The structure for the session configuration parameters.

Members

dwSize
The size in bytes of the SESS_CONFIGURATION_INFO structure.
szEntryName[RAS_MaxEntryName+1]
a null-terminated string for the session's name. This field is used by the initiator type only.
stSessType
Indicates one of the following session types.
SESSTYPE_INITIATOR | The session is started as an initiator (an RNA client.)
SESSTYPE_RESPONDER | The session is started as a responder (an RNA host.)

fUserSecurity
A flag indicating whether the session is the user-leveled security. This field is used by the responder type only.
szUserName[UNLEN+1]
a null-terminated string for the user's name. This field is used by the initiator type only.
szPassword[PWLEN+1]
a null-terminated string for the session password. This field is used by the initiator type only.
szDomainName[DNLEN+1]
a null-terminated string for the user's domain. This field is used by the initiator type only.


RnaSessStop

DWORD APIENTRY RnaSessStop(HANDLE hConn)

is called by RNA to terminate the session configuration asynchronously. When the session configuration is terminated, the SMM must call the RnaTerminate function to notify RNA of the result of the termination.

hConn
A handle to the RNA connection for which the session configuration is terminated.
  • SUCCESS if the SMM can start the asynchronous session termination successfully or one of the error codes.

The function should notify the session configuration thread to terminate all the pending operations, deallocate all the resources for the session, notify RNA of the termination result through the RnaTerminate call, and terminate the configuration thread itself.


RnaComplete

DWORD APIENTRY RnaComplete(HANDLE hConn, LPCOMPLETE_INFO lpci, LPPROJECTION_INFO lppi, DWORD cEntries)

is called by SMM to notify RNA of the result of the session configuration. SMM calls this function to response to the RnaSessStart call from RNA.

hConn
A handle to the RNA connection for the session.
lpci
An address to a COMPLETE_INFO structure containing the information for the result of the session configuration. On entry, the dwSize field must be filled with the size of the structure.
lppi
An address to an array of PROJECTION_INFO structure containing the information of the projected network protocol.
cEntries
The number of the PROJECTION_INFO structures in the array.
  • SUCCESS if the notification is valid or one of the following error codes:
ERROR_BUFFER_INVALID | The COMPLETE_INFO structure is invalid or missing.
ERROR_INVALID_HANDLE | The RNA connection handle is invalid.

If RNA sees an error code in dwResult other then SUCCESS, it will always call RnaSessStop to remove the SMM from the system.


COMPLETE_INFO

typedef struct {
  DWORD dwSize;
  DWORD dwResult;
  UINT idMsg;
  BOOL fUnload;
  HANDLE hThread;
} COMPLETE_INFO;

This structure contains the information for the result of the session configuration.

Members

dwSize
The size in bytes of the COMPLETE_INFO structure.
dwResult
The session configuration result. The result can be any error code or one of the following.
SUCCESS | The session configuration is successful. SMM can choose to unload itself from the system by setting the fUnload parameter to TRUE.
ERROR_WRONG_MODULE | The SMM detects that it is not the right module to configure the session. When RNA sees this result, it will call this SMM by calling RnaSessStop before it proceeds to the next SMM.

idMsg
A non-zero resource identifier for the description of the problem of the session configuration. The SMM should use this string to describe the details of the problem in case of failure. If the parameter is zero, RNA will use the default description for the dwResult value. In case of a SUCCESS return, this parameter is ignored.
fUnload
A boolean value notifying RNA whther to unload SMM if the dwResult is SUCCESS, otherwise this parameter is ignored.
hThread
The thread handle RNA will wait before it unloads the SMM module. If it is NULL, RNA will unload the SMM module immediately. This parameter is ignored if fUnload is FALSE.


PROJECTION_INFO

typedef struct {
  DWORD dwSize;
  RASPROJECTION RasProjection;
  union ProjInfo;
} PROJECTION_INFO;

This structure contains the information for the projected network protocol.

Members

dwSize
The size in bytes of the PROJECTION_INFO structure.
RasProjection
The type of projected protocol.
ProjInfo
The union fields of the following structures. The structure type corresponds to the projected protocol type in the RasProjection field.
RasAMB | The RASAMB structure containing the information for the RAS AMB (Authentication Message Block) projection used with NT 3.1 and OS/2 1.3 downlevel RAS servers.
RasPPPNBF | The RASPPPNBF structure containing the information for the PPP NBF (NetBEUI) projection.
RasPPPIPX | The RASPPPIPX structure containing the information for the PPP IPX (Internetwork Packet Exchange) projection.
RasPPPIP | The RASPPPIP structure containing the information for the PPP IP (Internet) projection.


RnaTerminate

DWORD WINAPI RnaTerminate(HANDLE hConn, HANDLE hThread)

This function is called by an SMM to notify RNA of the end of the session termination. SMM calls this function to response to the RnaSessStop call from RNA.

hConn
The RNA connection for the session.
hThread
The thread handle RNA will wait before it unloads the SMM. If it is NULL, RNA will unload the SMM immediately.
  • SUCCESS or one of the following error codes:
ERROR_INVALID_HANDLE The RNA connection handle is invalid.


RnaGetDevicePort

DWORD WINAPI RnaGetDevicePort(HANDLE hConn, LPDEVICE_PORT_INFO lpdpi)

This function is called by an SMM to get a device port information.

hConn
The RNA connection handle.
lpdpi
An address to a DEVICE_PORT_INFO structure to receive the device port informaiton. On entry, the dwSize field must be filled with the size of the structure.
  • SUCCESS or one of the following error codes:
ERROR_INVALID_HANDLE | The RNA connection handle is invalid.
ERROR_BUFFER_INVALID | The DEVICE_PORT_INFO structure is not valid or missing.


DEVICE_PORT_INFO

typedef struct {
  DWORD dwSize;
  HANDLE hDevicePort;
  DWORD dwLinkSpeed;
} DEVICE_PORT_INFO;

This structure contains the current information of the requested device port. These type of information varies from sessions to sessions.

Members

dwSize
The size in bytes of the DEVICE_PORT_INFO data structure.
hDevicePort
The device port handle for SMM to directly perform I/O operations by using the API set for the device class or pass it to the MAC driver.
dwLinkSpeed
a DWORD to receive the current data transfer rate (in bit-per-second.)


RnaOpenMac

DWORD WINAPI RnaOpenMac(HANDLE hConn, HANDLE * lphMAC, LPMAC_OPEN lpmo, DWORD dwSize, HANDLE hEvent)

This function is called by an SMM to request RNA to load the MAC and open the adapter port. The MAC is not activated to any protocol on a successful return. The SMM still needs to activate the MAC and the protocol using a private DeviceIOCTL call.

hConn
The RNA connection handle.
lphMAC
An address to a HANDLE buffer to receive a handle to the loaded MAC. The handle can be used as the device handle for a DeviceIOCTL call in the future.
lpmo
An address to a MAC_OPEN data structure to receive the information of the adapter port on a successful return.
dwSize
The size of the buffer that we get, need to verify that this is large enough to hold the MAC_OPEN data structure.
hEvent
A handle to an event to request for an asynchronous operation. The MAC is required to signal the event if the event is not NULL. If it is NULL, the MAC must perform the operation synchronously.
  • SUCCESS or one of the following error codes:
ERROR_INVALID_HANDLE | The RNA connection handle is invalid.
ERROR_INVALID_PORT_HANDLE | The RNA connection handle is invalid.
ERROR_NO_MAC_FOR_PORT | The MAC driver cannot be found or opened.


RnaCloseMac

DWORD WINAPI RnaCloseMac(HANDLE hConn)

This function is called by an SMM to request RNA to close the adapter port and to unload the MAC.

hConn
The RNA connection handle.
  • SUCCESS or one of the following error codes:
ERROR_INVALID_HANDLE | The RNA connection handle is invalid.
ERROR_INVALID_PORT_HANDLE | The RNA connection handle is invalid.


RnaGetUserProfile

DWORD WINAPI RnaGetUserProfile(HANDLE hConn, LPUSER_PROFILE lpUserProfile)

This function is called by an responder-type SMM to request from RNA the user profile.

hConn
The RNA connection handle.
lpUserProfile
An address to a USER_PROFILE structure to receive the profile of the user. On entry, the dwSize and szUserName fields must be filled with the size of the USER_PROFILE structure and the requested user name, respectively.
  • SUCCESS or one of the following error codes:
ERROR_INVALID_HANDLE | The RNA connection handle is invalid.
ERROR_BUFFER_INVALID | The RNA connection handle is invalid.
ERROR_INVALID_AUTH_STATE | The RNA connection handle is not in the session configuration state.


USER_PROFILE

typedef struct {
  DWORD dwSize;
  char szUserName[UNLEN+1];
  char szPassword[PWLEN+1];
  char szDomainName[DNLEN+1];
  BOOL fUseCallbacks;
} USER_PROFILE;

This structure contains the profile of the user requested through the RnaGetUserProfile function.

Members

dwSize
The size in bytes of the USER_PROFILE data structure.
szUserName[UNLEN+1]
This field must contain a null-terminated string for the requested user's name on entry.
szPassword[PWLEN+1]
a null-terminated string for the share-leveled security password. The field is ignored for the user-leveled security.
szDomainName[DNLEN+1]
a null-terminated string for the domain name. The empty string can be used for the local machine's domain name.
fUseCallbacks
A boolean indicating whether or not to use callback for this user.


RnaStartCallback

DWORD APIENTRY RnaStartCallback(HANDLE hConn, HANDLE hEvent)

is called by SMM to request RNA to start the callback process asynchronously. In the responder session, RNA terminates and re-establishes the physical connection. In the initiator session, RNA terminates the physical connection and waits for the RNA host to establish the connection.

hConn
A RNA connection handle.
hEvent
A handle to the event RNA signals when the callback succeeds.
  • SUCCESS if the callback starts successfully or one of the following error codes:
ERROR_INVALID_HANDLE The RNA connection handle is invalid.

If the physical connection cannot be re-established, RNA will not signal the completion event to the SMM. Instead, it will terminate the session configuration by calling SMM's RnaSessStop.


RnaUICallbackDialog

DWORD WINAPI RnaUICallbackDialog(HANDLE hConn, LPSTR lpszLocList, DWORD dwType, BOOL fOptional, LPINT lpuIndex, LPSTR lpszSelectLocation, UINT cbBuff)

This function is called by the initiator-type SMM to display a common callback dialog box. The dialog box allows the end-user to select the callback location or to enter a callback phone number, depending on the callback type.

hConn
The RNA connection handle.
lpszLocList
An address to a buffer containing a list of null-terminated strings for the callback locations. The list is terminated by an extra null character after the last location.
dwType
A DWORD value indicating one of the following callback types.
CALLBACK_SECURE | The RNA client can choose from the list of callback locations only.
CALLBACK_CONVENIENCE | The RNA client can choose from the list of the callback location or enter a callback phone number.

fOptional
A boolean indicating whether a callback is optional
lpuIndex
An address to an integer buffer to receive the index to the selected callback location in the 'lpszLocList' list. For CALLBACK_CONVENIENCE, the value is -1 if a phone number is entered.
lpszSelectLocation
An address to a buffer to receive the selected callback location or the phone number entered in the CALLBACK_CONVENIENCE type.
cbBuff
The size in bytes of the 'lpszSelectLocation' buffer.
  • SUCCESS or one of the following error codes:
ERROR_INVALID_HANDLE | The RNA connection handle is invalid.
ERROR_NO_RESPONSES | The end-user cancels the dialog box. In case the callback is optional, this means the end-user does not want the callback.


RnaUIUsernamePassword

DWORD WINAPI RnaUIUsernamePassword(HANDLE hConn, LPSTR lpszUsername, UINT cbUsername, LPSTR lpszPassword, UINT cbPassword, LPSTR lpszDomain, UINT cbDomain)

This function is called by the initiator-type SMM to display a common user-logon dialog box.

hConn
The RNA connection handle.
lpszUsername
An address to a buffer to receive a null-terminated string for the user name. The buffer can be filled with a default name on entry.
cbUsername
The size in bytes of the 'lpszUsername' buffer.
lpszPassword
An address to a buffer to receive a null-terminated string for the user's password. The buffer can be filled with a default password on entry.
cbPassword
The size in bytes of the 'lpszPassword' buffer.
lpszDomain
An address to a buffer to receive a null-terminated string for the user's logon domain. If the address is NULL, the dialog box do not allow the user to enter the logon domain. The buffer can be filled with a default logon domain on entry.
cbDomain
The size in bytes of the 'lpszDomain' buffer.
  • SUCCESS or one of the following error codes:
ERROR_INVALID_HANDLE | The RNA connection handle is invalid.
ERROR_NO_RESPONSES | The end-user cancels the dialog box.


Windows 95 Session Management Modules

Dial-Up Networking uses Session Management Modules to abstract the interface presented by the dial-up server. This allows new modules and drivers to be "plugged in" as necessary to support new servers.

Window 95 has built-in support for 4 session management modules: PPP, RAS, Netware Connect and SLIP.

Windows 95 Session Management Modules can also "overlay" other session management modules. This allows features such as scripting or security to be added to the product.


Session Management Module Overlays

Windows 95 Dial-Up Networking provides four built-in Session Management Modules (SMMs):

  • Point-to-Point Protocol (PPP) Session Management Module for Windows 95, Windows NT 3.5 and Internet providers
  • Remote Access Service Session Management Module for Windows for Workgroup and Windows NT 3.1
  • Netware Connect Session Management
  • SLIP and CSLIP protocols for Unix connections (this SMM is not enabled by default but can be installed from the Resource Kit).

However, in some Dial-Up environments, extra steps may be required to set up the dial-up session. Windows 95 Dial-Up Networking allows a third-party developer to provide these steps in a separate Session Management Module, referred to as Session Management Module Overlay, in addition to the default or other Session Management Modules, referred to as Overlaid Session Management Modules.

An overlaying Session Management Module is implemented and installed as a stand-alone SMM Dynamic-Linked Library. (See section 3 of this documentation for installation details). Dial-Up Networking and users see it as an additional SMM (or Dial-Up Server type) and associate it with the connection. However, when Dial-Up Networking requests the overlaying SMM to configure and manage the session, it may choose to perform additional steps or fail the configuration before handing off the control to the overlaid SMM. Once the hand-off occurs, the overlaying SMM will no longer control the session. All the interactions will occur directly between Dial-Up Networking and the overlaid SMM.


Setting Up the Session Management Module Overlay

The overlaying SMM can be installed for Windows 95 Dial-Up Networking as an external SMM. Dial-Up Networking treats the overlaying SMM as a separate SMM from the one it overlays. The user can choose to use the overlaying SMM by:

  • Open the connection icon's Property page.
  • Click on the Server Type button to bring up the Server type dialog.
  • Select the overlaying SMM from the list of Dial-Up Server type.


Loading the Session Management Module Overlay

When Dial-Up Networking completes the physical connection, it loads the overlaying SMM to manage the session. Only the Dial-Up Networking process attaches to the overlaying SMM DLL. At load time, the overlaying SMM DLL's entry point will be notified that the Dial-Up Networking process is attaching to the DLL. The SMM's process-attach handler should do the following:

  • Load the DLL of the SMM it is overlaying using LoadLibrary.
  • Use GetProcAddress to get the address of the RnaSessInitialize function from the overlaid SMM.
  • Allocate resources and initialize the internal data structure.

In the sample overlay SMM provided with the DDK , the sample SMM wants to overlay the PPP SMM so it loads RASAPI32.DLL which contains the PPPSMM and gets the entry point for the RnaSessInitialize function. It initializes the list for the session control block which will maintain the active session.


Unloading the Session Management Module Overlay

When Dial-Up Networking terminates the session, it unloads the SMM. The DLL's entry point will be notified that the Dial-Up Networking process is detaching from the DLL. The process-detach handler should do the following:

  • Deinitialize the internal data structures and frees the allocated resources.
  • Unload the DLL of the overlaid SMM using FreeLibrary.

In the sample, the SMM frees all the session control blocks left in the list and unloads RASAPI32.DLL .


RnaSessInitialize

This function is called by Dial-Up Networking to allow the SMM to initialize and prepare itself for managing the session. The overlaying SMM should do the following during this function.

  • Calls the overlaid SMM's RnaSessInitialize functions to obtain the dispatch function table. The function table would contain the entry points to Start and Stop functions.
  • Returns the entry points to the Start (RnaSessStart) and Stop (RnaSessStop) functions for the overlaying DLL.

In the sample, the SMM calls the PPPSMM's RnaSessInitialize function. If the function succeeds, the SMM successfully overlays the PPPSMM and returns the entry points to its RnaSessStart and RnaSessStop functions (SMMSessStart and SMMSessStop respectively) to Dial-Up Networking.


RnaSessGetErrorString

This function is called when Dial-Up Networking wants to get the displayable error string for the messages resource ID returned to Dial-Up Networking in the RnaComplete call. The overlaying SMM should do the following during this function.

  • If the overlaying SMM passes a message resource ID when it makes the RnaComplete call to Dial-Up Networking, it needs to return its own error string corresponding to the message ID.
  • If the overlaying SMM does not call RnaComplete, it means the overlaid SMM fails the session and calls RnaComplete, the overlaying should try to get the RnaSessGetErrorString entry point from the overlaid SMM and do the following:
  • If the RnaSessGetErrorString entry point exists, it should call the entry point and passes the return information from the overlaid SMM to Dial-Up Networking.
  • If the RnaSessGetErrorString entry point does not exist, it should use LoadString to get the error string from the overlaid SMM.

In the sample, the overlaying SMM does not own any error string/message ID. If this function is called it means that the SMM for PPP fails the session configuration and passes a message resource ID when it calls RnaComplete to Dial-Up Networking.


RnaSessStart

This function is called when Dial-Up Networking wants the SMM to start managing the session. The overlaying SMM should do the following during this function.

  • Call RnaGetDevicePort to get the information of the connection Dial-Up Networking wants to start the session. The device information contains the class of the device through which the connection was made. The overlaying SMM needs to verify that it can handle the device class.
  • The overlaying SMM also needs to verify all other conditions (for example the session types, etc.) to ensure that it wants to manage the session.
  • If the overlaying SMM does not want to manage the session, it calls the Start function of the overlaid SMM, and returns to Dial-Up Networking when the overlaid SMM returns.
  • If the overlaying SMM wants to it can proceed to manage the session. The SMM can manage the session in two ways:
  • If the overlaying wants to perform a short task, it can do so within the RnaSessStart function. When it finishes managing the session, it can hand off the control to the overlaid SMM by calling its Start function. When the overlaid SMM returns it can return to Dial-Up Networking.
  • If the overlaying wants to perform a long task, it should spawn a new thread to manage the session, and returns to Dial-Up Networking immediately after the thread starts. When the thread finishes managing the session, , it can hand off the control to the overlaid SMM by calling its Start function. In this case if the overlaid SMM returns failure, the overlaying SMM needs to terminate the session by calling the RnaComplete function.

In the sample, the function is named SMMSessStart. It verifies the session is for the "COM" device class and the "initiator" session type (client) before it spawns a session management thread to manage the session and returns to Dial-Up Networking. If either condition is not met, it hands off the control to the overlaid SMM (SMM for PPP) immediately.


RnaSessStop

This function is called when Dial-Up Networking wants to terminate the SMM. The overlaying SMM should do the following during this function.

  • If the overlaying SMM has not handed off the control to the overlaid SMM (by calling its Start function) when this function is called, it means the overlaying SMM is managing the session in a separate thread. The overlaying SMM must stop managing the session as soon as possible. When it can stop the task it needs to call the RnaTerminate function.
  • If the overlaying SMM already calls the overlaid SMM's Start function, it can simply call the overlaid SMM's Stop function and return immediately.

In the sample, SMMSessStop determines whether it has started managing the session by the existence of the session control block for the connection. If the session control block does not exist, it never manages the session, so it can bypass the Stop function to the PPPSMM immediately. Otherwise, it signals an event the session management thread to stops managing the session. When the thread detects the event, it terminates the session and calls RnaComplete or simply calls the PPPSMM to stop the session.


Accessing the Communications Port

Generally, the overlaying SMM wants to directly access and transfer raw data across the connected device. For instance, it may want to do the front-end user verification or run a script over the wire.

Dial-Up Networking provides a standard scheme for the SMM to access the device directly through the following steps

  1. During the RnaSessStart function, the SMM needs to verify that the connection was made through the class of the device it knows how to access. The SMM must call the RnaGetDeviceInfo function to obtain the device information and verify the device class contained in the device information. The device class identifies the API set that the SMM can use with the device. For instance the 'COM' device class is for the Win32 Comm API set.
  2. When the SMM wants to access the device, it uses the TAPI information in the device information (obtained from the RnaGetDeviceInfo call.) The TAPI information includes the TAPI line handle, the TAPI call handle and the address ID of the device.
  3. The SMM calls TAPI's lineGetID function with all the TAPI information for the known device class to obtain the device handle that the SMM can use to directly access the device.

In the sample the SMM obtains the Win32 Comm handle by calling the lineGetID function for the "data/modem" class. Them it uses this handle with the Win32 comm APIs to transfer data to/from the Dial-up Server.


Installing a Session Management Module

Session Management Modules are configured in the authentication key of the remote access branch of the registry. This section describes the layout of this key and how it is used.


Registry Layout

HKEY_LOCAL_MACHINE/SYSTEM/SERVICES/REMOTEACCESS/AUTHENTICATION
CLASS
<device class>
<Dial-Up Adapter name 0>
...
<Dial-Up Adapter name n>
...
DRIVERS
<Dial-Up Adapter name 0>
0 = <Session Management Module 0>
...
m = <Session Management Module m>
...
SMM_FILES
<Session Management Module 0>
Desc =
Path =
Options =
Protocols =
Usage =
...
  • CLASS key

    The key contains the subkeys for the classes of the devices that were installed for Dial-Up Networking. After Dial-Up Networking completes the physical connection via a TAPI device, it requests for the unique device class name for the physical device from the corresponding service provider (via the lineGetID call with the "ndis" class.)

  • CLASS\<device class> key

    This key contains the keys for the names of the Dial-Up adapters. Dial-Up Networking uses the names in this list to determine the adapter that can be used in this session. Each adapter will be tried sequentially until one successfully or all fail to configure the session.

  • CLASS\<device class>\<Dial-Up Adapter name x> key

    This key is the name of the Dial-Up adapter. Dial-Up Networking uses this name to determine the list of corresponding Session Management Modules (SMMs) that can be used for this session from the DRIVERS key. The name of this key must match one of the <Dial-Up Adapter name x> subkey of the DRIVERS key.

  • DRIVERS key

    This key contains the list of all the Dial-Up Adapters installed in the system. In a session, Dial-Up Networking will use only the adapters that matches the device class.

  • DRIVERS\<Dial-Up Adapter name x> key

    This key contains the values for the SMMs that can be used with the adapter. The value name is a zero-based integer signifying the order of the SMM Dial-Up Networking should attempt. The value is a string type for the SMM name which must match the name of one of the <Session Management Module x> subkeys of the SMM_FILES key.

  • SMM_FILES key

    This key contains the keys for all the SMMs that are installed for Dial-Up Networking. In a session, Dial-Up Networking will use only the SMMs that corresponds to the attempted adapters.

  • SMM_FILES\<Session Management Module x> key

    This key contains the information for the Session Management Module that Dial-Up Networking needs to starts the SMM properly. The information is stored in the following values:

    • Desc

      A string-type value contains the descriptive name of the SMM. The name is used to populate the list of SMM in the Server Type dialog in the connection icon's Property page.

    • Path

      A string-type value contains the pathname of the Dynamic Linked Library (DLL) for the SMM. The path can be relative or full pathname.

    • Options

      A four-byted binary value for a set of flags indicate the user-configurable options for the SMM. If the flag is set, Users can configure the option from the Server Type dialog in the connection icon's Property page. The current options are:
      SMMCFG_SW_COMPRESSION (0x00000001) | The SMM can negotiate the software compression scheme.
      SMMCFG_PW_ENCRYPTED (0x00000002) | The SMM can use the encrypted password.
      SMMCFG_NW_LOGON (0x00000004 ) | The SMM allows Dial-Up Networking to log onto the network on the Dial-Up server automatically.
      SMMCFG_SW_ENCRYPTION (0x00000010) | The SMM can use the software encryption.

    • Protocols

      A four-byted binary value for a set of flags indicate the network protocols that can be used by the corresponding Dial-Up adapter. If the flag is set, Users can specify the protocols to use for the connection from the Server Type dialog in the connection icon's Property page. The current protocols are:
      SMMPROT_NB (0x00000001) | NetBEUI
      SMMPROT_IPX (0x00000002) | IPX/SPX Compatible
      SMMPROT_IP (0x00000004) | TCP/IP

    • Usage

      A four-byted binary value for a set of flags indicate the type of the SMM. The current usage includes:
      INITIATOR_TYPE (0x00000001) | The SMM can be used for the client Dial-Up Networking
      RESPONDER_TYPE (0x00000002) | The SMM can be used for the Dial-Up Networking server.


How Dial-Up Networking Uses the Registry

The following is the default registry layout when Dial-Up Networking is first installed.

HKEY_LOCAL_MACHINE/SYSTEM/SERVICES/REMOTEACCESS/AUTHENTICATION
CLASS
COM
PPPMAC
DRIVERS
PPPMAC
0 = "PPP"
1 = "RAS"
2 = "NWC"
SMM_FILES
NWC
Desc = "NRN: Netware Connect"
Path = "rasapi32.dll"
Options = 04 00 00 00
Protocols = 02 00 00 00
Usage = 01 00 00 00
PPP
Desc = "PPP: Windows 95, Windows NT 3.5, Internet"
Path = "rasapi32.dll"
Options = 17 00 00 00
Protocols = 07 00 00 00
Usage = 03 00 00 00
RAS
Desc = "Windows for Workgroup and Windows NT 3.1"
Path = "rasapi32.dll"
Options = 04 00 00 00
Protocols = 01 00 00 00
Usage = 03 00 00 00

The default Dial-Up Adapter (Microsoft Dial-Up Adapter) is PPPMAC. PPPMAC handles a modem device and has three default Session Management Modules--NWC, PPP, and RAS. When the modem connection was established, Dial-Up Networking gets the device class of the modem from TAPI's lineGetID call for the "ndis" type. The Unimodem service provider returns the "COM" device class for the modem. Dial-Up Networking looks for the Dial-Up adapters from the .../REMOTEACCESS/AUTHENCATION/CLASS/COM key and finds PPPMAC as the only adapter. Then Dial-Up Networking enumerates the Session Management Modules for PPPMAC from the .../REMOTEACCESS/AUTHENCATION/-DRIVERS/PPPMAC key, starting from PPP type. When Dial-Up Networking is ready to hand off the control to the SMM, it looks up the Path value in the .../REMOTEACCESS/AUTHENCATION/SMM_FILES/PPP key for the DLL name, loads it and starts the session management phase.


Setting Up an External Session Management Module

Two elements are required to set up an external Session Management Module for Windows 95 Dial-Up Networking.


Session Management Module Setup Dynamic Linked Library (SMMSETUP.DLL)

SMMSetup.DLL contains a utility to modify the SMM order for a Dial-Up adapter in the registry layout. Since the order of the SMM for a particular Dial-Up adapter varies from one machine to the others, the integer order of the SMM cannot be specified statically in the setup INF file.

To run the utility, the setup utility in SMMSETUP.DLL must be invoked with the following command line:

Rundll32.exe SMMSETUP.DLL, SMM_Setup /a|i|d <Dial-Up adapter name> <Session Management Module>

Rundll32.exe will load SMMSETUP.DLL and starts executing the SMM_Setup entry point. Three options are available for the command.

a | The <Session Management Module> key will be appended at the end of the SMM list for the DRIVERS\<Dial-Up Adapter name x> key.
i | The <Session Management Module> key will be inserted at the beginning of the SMM list for the DRIVERS\<Dial-Up Adapter name x> key.
d | The <Session Management Module> key will be removed from the SMM list for the DRIVERS\<Dial-Up Adapter name x> key.

The command line is specified as a part of the setup INF file for the external SMM.


Session Management Module Setup INF File

Dial-Up Networking uses the standard Windows Setup program to add the Session Management Module into the Dial-Up Networking registry layout. The Windows Setup program requires a setup INF file. The following highlights the required sections in the INF file.

[DestinationDirs]
SMM_SYS_CopyFiles   =11

[Optional Components]
EXT_SMM

[EXT_SMM]
OptionDesc=%SMM_Desc%
Tip=%SMM_Tip%
CopyFiles=SMM_SYS_CopyFiles
AddReg=SMM_Reg
IconIndex= 21                   ;Dial-up networking mini-icon for dialogs

[SMM_SYS_CopyFiles]
extsmm.dll
smmsetup.dll

[SMM_Reg]
;
; Session Management Module registration
;
HKLM, SYSTEM\CurrentControlSet\Services\RemoteAccess\Authentication\SMM_Files\EXTSMM, Path,, "extsmm.dll"
HKLM, SYSTEM\CurrentControlSet\Services\RemoteAccess\Authentication\SMM_Files\EXTSMM, Desc,, %SMM_Desc%
HKLM, SYSTEM\CurrentControlSet\Services\RemoteAccess\Authentication\SMM_Files\EXTSMM, Usage,1,01,00,00,00
HKLM, SYSTEM\CurrentControlSet\Services\RemoteAccess\Authentication\SMM_Files\EXTHOOK, Options,1,17,00,00,00
HKLM, SYSTEM\CurrentControlSet\Services\RemoteAccess\Authentication\SMM_Files\EXTHOOK, Protocols,1,07,00,00,00
;
; RunOnce for SMMSetup utility
;
HKLM, Software\Microsoft\Windows\CurrentVersion\RunOnce,"%SMMSetup_Desc%",,"rundll32.exe smmsetup.dll,SMM_Setup /a MAC EXTHOOK"

;****************************************************************************
; User-visible strings
;****************************************************************************

[Strings]
SMM_Desc  = "External Session Management Module name"
SMM_Tip   = "Allows you to do additional session management over Dial-up Networking"
SMM_Desc      = "External Session Management Module"
SMMSetup_Desc = "External SMM Setup"

When a user wants to install an external SMM, this INF setup file, all the SMM modules and SMMSETUP.DLL should be on the provided diskettes.

To install an SMM

  1. Open the Windows Setup page in the "Add/Remove Programs" icon in Control Panel.
  2. Click on the Have Disk button
  3. Insert the diskettes with the INF setup file when prompted.
  4. The next page will display the external SMM item.
  5. Check the item and click the Install button.

The Windows Setup program uses the information from this INF setup file as follows:

[DestinationDirs] | "SMM_SYS_CopyFiles =11" This section tells setup to copy the external files to the Windows system directory.
[Optional Components] | This section lists the items that can be set up from this INF file. "EXT_SMM" is the only item.
[EXTHOOK] | This section contains the following values:

OptionDesc | The displayed string value for the item in the selection box.
Tip | The displayed string value for the description box when the item is selected.
CopyFiles | "SMM_SYS_CopyFiles" indicates the section that contains the list of file to copy.
AddReg | "SMM_Reg" indicates the set of registry keys and values to add during installation.
IconIndex | The integer value 21 is for a Dial-up networking mini-icon to be displayed in the selection box.

[SMM_SYS_CopyFiles] | This section contains the list of file to be copied to the Windows system directory.
[SMM_Reg] | The lines below the "Session Management Module registration" comment sets up the Dial-Up Networking registry layout for the Session Management Module except for the SMM order. The line below the "RunOnce for SMMSetup utility" comment tells the Windows Setup to execute the SMM setup utility during the installation.


Session Management Module Function Reference

The following topics describe the functions.


SESS_CONFIGURATION_INFO

typedef struct {
 DWORD dwSize;
 char szEntryName[RAS_MaxEntryName+1];
 SESSTYPE stSessType;
 BOOL fUserSecurity;
 char szUserName[UNLEN+1];
 char szPassword[PWLEN+1];
 char szDomainName[DNLEN+1];
} SESS_CONFIGURATION_INFO;

The structure for the session configuration parameters.

Members

dwSize
The size in bytes of the SESS_CONFIGURATION_INFO structure.
szEntryName[RAS_MaxEntryName+1]
a null-terminated string for the session's name. This field is used by the initiator type only.
stSessType
Indicates one of the following session types.
SESSTYPE_INITIATOR
The session is started as an initiator (an RNA client.)
SESSTYPE_RESPONDER
The session is started as a responder (an RNA host.)
fUserSecurity
A flag indicating whether the session is the user-leveled security. This field is used by the responder type only.
szUserName[UNLEN+1]
a null-terminated string for the user's name. This field is used by the initiator type only.
szPassword[PWLEN+1]
a null-terminated string for the session password. This field is used by the initiator type only.
szDomainName[DNLEN+1]
a null-terminated string for the user's domain. This field is used by the initiator type only.


COMPLETE_INFO

typedef struct {
 DWORD dwSize;
 DWORD dwResult;
 UINT idMsg;
 BOOL fUnload;
 HANDLE hThread;
} COMPLETE_INFO;

This structure contains the information for the result of the session configuration.

Members

dwSize
The size in bytes of the COMPLETE_INFO structure.
dwResult
The session configuration result. The result can be any error code or one of the following.
SUCCESS
The session configuration is successful. SMM can choose to unload itself from the system by setting the fUnload parameter to TRUE.
ERROR_WRONG_MODULE
The SMM detects that it is not the right module to configure the session. When RNA sees this result, it will call this SMM by calling RnaSessStop before it proceeds to the next SMM.
idMsg
A non-zero resource identifier for the description of the problem of the session configuration. The SMM should use this string to describe the details of the problem in case of failure. If the parameter is zero, RNA will use the default description for the dwResult value. In case of a SUCCESS return, this parameter is ignored.
fUnload
A boolean value notifying RNA whther to unload SMM if the dwResult is SUCCESS, otherwise this parameter is ignored.
hThread
The thread handle RNA will wait before it unloads the SMM module. If it is NULL, RNA will unload the SMM module immediately. This parameter is ignored if fUnload is FALSE.


PROJECTION_INFO

typedef struct {
 DWORD dwSize;
 RASPROJECTION RasProjection;
 union ProjInfo;
} PROJECTION_INFO;

This structure contains the information for the projected network protocol.

Members

dwSize
The size in bytes of the PROJECTION_INFO structure.
RasProjection
The type of projected protocol.
ProjInfo
The union fields of the following structures. The structure type corresponds to the projected protocol type in the RasProjection field.
RasAMB
The RASAMB structure containing the information for the RAS AMB (Authentication Message Block) projection used with NT 3.1 and OS/2 1.3 downlevel RAS servers.
RasPPPNBF
The RASPPPNBF structure containing the information for the PPP NBF (NetBEUI) projection.
RasPPPIPX
The RASPPPIPX structure containing the information for the PPP IPX (Internetwork Packet Exchange) projection.
RasPPPIP
The RASPPPIP structure containing the information for the PPP IP (Internet) projection.


RnaUICallbackDialog

DWORD
WINAPI RnaUICallbackDialog(HANDLE hConn,
   LPSTR lpszLocList, DWORD dwType, BOOL fOptional,
   LPINT lpuIndex, LPSTR lpszSelectLocation, UINT cbBuff)

This function is called by the initiator-type SMM to display a common callback dialog box. The dialog box allows the end-user to select the callback location or to enter a callback phone number, depending on the callback type.

hConn
The RNA connection handle.
lpszLocList
An address to a buffer containing a list of null-terminated strings for the callback locations. The list is terminated by an extra null character after the last location.
dwType
A DWORD value indicating one of the following callback types.
CALLBACK_SECURE
The RNA client can choose from the list of callback locations only.
CALLBACK_CONVENIENCE
The RNA client can choose from the list of the callback location or enter a callback phone number.
fOptional
A boolean indicating whether a callback is optional
lpuIndex
An address to an integer buffer to receive the index to the selected callback location in the 'lpszLocList' list. For CALLBACK_CONVENIENCE, the value is -1 if a phone number is entered.
lpszSelectLocation
An address to a buffer to receive the selected callback location or the phone number entered in the CALLBACK_CONVENIENCE type.
cbBuff
The size in bytes of the 'lpszSelectLocation' buffer.
  • SUCCESS or one of the following error codes:
ERROR_INVALID_HANDLE | The RNA connection handle is invalid.
ERROR_NO_RESPONSES | The end-user cancels the dialog box. In case the callback is optional, this means the end-user does not want the callback.


Pen Device Driver

Windows® 95 pen device support consists of a pen device driver and a pen calibration application that extends the Windows 95 control panel.

The pen device generates hardware interrupts at a rate of approximately 100 interrupts per second. At each hardware interrupt, the pen Unidriver collects pen data from the device and provides the data to Windows in the form of a pen packet. Generally, each interrupt produces a packet, which is the elemental form of raw pen data. Each packet contains the current pen coordinates, the pen state (up, down, in transition, etc.), a time stamp, and optional OEM information. Collectively, pen packets provide a digitized history of the pen's movements.


Pen Device Support Components

The Windows pen device driver supports digitizing pen hardware from various manufacturers, and is a Unidriver. The pen calibration application enables the user to calibrate a digitizer by touching targets on the digitizer; the calibration information obtained is used by the driver in reporting pen position coordinates to Windows. The executable pen device support components are listed in the following table.

Component | Filename | Description
Virtual device driver, VxD | VPENDC.VXD | Part of the pen Unidriver. A 32-bit virtual device driver with ring 0 privilege. Contains the pen device interrupt service routine.
Pen driver | PENC.DRV | Part of the pen Unidriver. A 16-bit installable device driver with ring 3 privilege. Handles messages from the Pen Services for Windows 95 system component (PENWIN.DLL) and other clients.
Pen driver interface | PENUI.DLL | Part of the pen Unidriver. Provides a user interface for configuring the pen Unidriver.
Pen calibration application | PENCAL.DLL | An application that extends the capability of the Pen icon in the Windows 95 Control Panel by providing a user interface for calibrating the pen device.

The terms pen Unidriver and pen device driver describe the combination of all three components. Pen system refers to the pen services of Microsoft Windows 95 provided by the PENWIN.DLL library.

After the Microsoft Windows 95 Device Driver Kit (DDK) is installed, the source code for the sample pen Unidriver components are in sub directories under the directory \PEN\SAMPLES. The virtual pen driver source code is in the \PEN\SAMPLES\VPEND sub directory, the pen driver source code is in the \PEN\SAMPLES\PEN sub directory, the pen driver interface source code is in the \PEN\SAMPLES\PENUI subdirectory, and the calibration application source code is in the \PEN\SAMPLES\PENCAL sub directory. The common header files for all the components are in \PEN\INC.

The Unidriver architecture allows the original equipment manufacturer (OEM) to quickly create a custom pen device driver tailored for a specific device. The OEM developer need only remove unnecessary portions from the code and optionally modify or enhance other portions.

Regardless of the pen driver an OEM develops, the OEM must ensure that its hardware supports the documented procedures of the pen Unidriver.


Pen Driver

The two main purposes of the pen driver (PENC.DRV) are to:

  • Receive pen data from the virtual pen driver and pass the data on to the system.
  • Respond to messages sent via the Windows SendDriverMessage function.

The pen driver is completely independent of the hardware. The OEM developer need not modify any portion of the PENC.DRV module.


Virtual Pen Driver

The virtual pen driver (VPENDC.VXD) handles hardware interrupts generated by the pen device. At each interrupt, the virtual pen driver organizes the raw data from the pen device and passes the organized data to the pen driver (PENC.DRV).

The virtual driver is the only component that communicates directly with the pen hardware. Therefore, the OEM developer can confine any modifications of the pen device driver to the virtual pen driver code.


Pen User Interface

The pen user interface (PENUI.DLL) library contains the user-interface functions of the pen Unidriver. These functions provide a simple configuration dialog box that queries for the pen device model, the COM port, and whether or not the pen device supports pressure sensitivity.

If desired, an OEM developer can replace or enhance the user interface, perhaps by providing a dialog box (for Windows version 3.1) or property sheet (for Windows 95), thus gaining additional marketability and user recognition. The pen Unidriver maintains its interface code as a separate library to facilitate such enhancements or a complete replacement of the library by the OEM.

The sample pen user interface source code that is in the directory \PEN\SAMPLES\PENUI of the installed Windows 95 DDK can be enhanced or used as a model for the source code of a DLL that completely replaces the pen user interface library.


Pen Calibration Application

The pen calibration application extends the capability of the Pen icon in the Windows 95 Control Panel by providing a user interface for calibrating the pen device. This application enables the user to calibrate non-opaque digitizers with 640x480 resolution and obtains the calibration information required by the set of digitizers supported by the pen Unidriver. To find out how to change this application for digitizers of different resolutions or digitizers whose drivers have different calibration data requirements, see About the Pen Calibration Application.


Initializing the Pen Unidriver

To initialize the pen Unidrive

  1. Initialize the virtual pen driver.
  2. Initialize the pen driver.
  3. Register the PENWIN.DLL callback function with the pen driver.


Initializing the Virtual Pen Driver

During startup, Windows reads the Windows 95 registry and loads the registered virtual device drivers. This happens before the wallpaper is displayed on the video screen. Just after the virtual pen driver (VPENDC.VXD) is loaded into memory, Windows sends it a Device_Init message.

Upon receiving this message, the virtual pen driver

  1. Initializes variables.
  2. Reads pen-specific information from the registry.
  3. Calls the cOEM_API_Proc function in the virtual driver with the VPEND_HWINIT, VPEND_PIINIT, and VPEND_COMMANDINIT messages. Code for the cOEM_API_Proc function is in the source file OEMAPI.C and is specific to the OEM hardware. This function determines how the driver should behave.
  4. Fills the global structures DRV_PENINFO and _HARDWAREINFO with default values from the registry.
  5. Acquires a COM port and virtualizes the interrupt request line (IRQ).
  6. Returns to Windows.

At this point, the tablet can start generating hardware interrupts. However, the virtual pen driver will not send pen packets to the pen driver in response to these interrupts until the pen driver enables the virtual pen driver with a VPEND_ENABLE message. For a description of all the VPEND_ messages, see the "Reference" section in About the Virtual Pen Driver.


Initializing the Pen Driver

After installing the virtual pen driver, Windows next reads the pen installable driver component from the installable driver line of the SYSTEM.INI file. It loads the specified pen driver by calling the OpenDriver function, using the PENC.DRV filename. When the driver successfully loads, Windows sends it three messages in the following order: DRV_LOAD, DRV_ENABLE, and DRV_OPEN. The PENC.DRV driver handles these messages in its DriverProc function.


Handling the DRV_LOAD Message

The pen driver responds to DRV_LOAD by calling the multiplex interrupt (interrupt 2Fh) to get the protect-mode entry point in the previously-loaded virtual pen driver. The following code illustrates this:

_asm {
         xor    di, di                          ; Initialize DI to zero.
         mov    ax, GET_VPEND_API_ENTRY_POINT   ; 1684h
         mov    bx, VPenD_Device_ID             ; Virtual Pen Driver ID
         int    2Fh                             ; Multiplex interrupt
; On return, ES:DI points to protect mode entry point in VxD.
         mov    word ptr vlpfnVpenD_API_Entry_Point+2, es;
         mov    word ptr vlpfnVpenD_API_Entry_Point, di
}

If the virtual pen driver does not respond, the pen driver will return a failure condition to Windows. However, if the virtual pen driver exists in memory and responds correctly to the call, the pen driver next fills in a VPEND_INIT structure with information for the virtual pen driver to use. The pen driver then calls the virtual pen driver entry point that is pointed to by ES:DI. The virtual pen driver records the information for future use and initializes the DRV_PENINFO structure pointed to by the lpPenInfo member of the VPEND_INIT structure. All the members of the VPEND_INIT and DRV_PENINFO structures are defined in the "Reference" section of About the Pen Driver.


Handling the DRV_ENABLE Message

When the pen driver receives the DRV_ENABLE message from Windows, it calls the virtual pen driver to begin reflecting interrupts into the system. The virtual pen driver then sets a callback timer for handling out-of-range packets and returns. For a definition of out-of-range packets and a description of how they are handled see the section "Time-Based Interrupts" in About the Virtual Pen Driver.


Handling the DRV_OPEN Message

When the pen driver receives the DRV_OPEN message, it returns the value DRV_SUCCESS unless

  • The pen driver cannot enable the virtual pen driver to deflect interrupts into the system.
  • The DRV_OPEN message is received during setup.


Registering the PENWIN.DLL Callback Function

When the PENWIN.DLL library loads, it opens the pen driver. PENWIN.DLL sends the pen driver a DRV_SetEntryPoints message, specifying a ProcessTabletEvents entry point in PENWIN.DLL. For a description of the ProcessTabletEvents function, see the "Reference" section in About the Pen Driver. This is the entry point the driver calls at interrupt time to provide pen packet information to its client, the PENWIN.DLL library.


Unloading the Pen Device Driver

The device driver's unloading process should ideally comply with the Plug and Play specifications. The Unidriver's exit code currently consists of only the function cVpenD_Device_Exit, which forms a shell for the exit procedure. The virtual pen driver receives a Sys_Critical_Exit message when the system unloads it. In handling this message, the virtual pen driver should place the hardware in a stable state and free any resources it holds.

The unloading process for the pen driver is also quite simple and straight forward. When the system unloads the pen driver, it sends the following three messages in the given order: DRV_CLOSE, DRV_DISABLE, and DRV_FREE. In processing the DRV_DISABLE message, the pen driver calls the virtual driver so it can turn off interrupts. The pen driver should return DRV_SUCCESS for all three messages.

As part of unloading the driver, the system sends a DRV_RemoveEntryPoints message so the system will receive no more pen packets.


Creating a Custom OEM Pen Driver

The sample Unidriver code supports the following pen hardware:

  • Compaq Concerto
  • Wacom Digitizer HD-648A
  • Wacom Digitizer SD-510C
  • Wacom Digitizer UD-0608R

For OEM hardware compatible with one of the above devices, a developer can literally create a custom pen device driver in a few hours or less. The simplest approach is to define a constant in the DEFINES.H file located in the \PEN\INC sub directory.

DEFINES.H defines the following values corresponding to the devices listed above:

Value | Supported Devices
CPQ | Compaq Concerto
WACOM2 | Wacom Digitizer HD-648A
WACOM2 | Wacom Digitizer SD 510C
WACOM4 | Wacom Digitizer UD0608R

To create a driver specifically for one of the devices in the list, simply remove the unneeded definitions in DEFINES.H. For example, to customize the pen Unidriver for the Wacom UD0608R device, keep these three lines in DEFINES.H:

#ifdef UNIDRV
#define WACOM4
#endif

Then run the MAKE file to build the Wacom UD0608R device driver.

You can also trim the source code, if desired, to remove distractions and improve compilation speed. To trim the source, remove the #ifdef blocks, #pragmas, and commented code for other devices from the OEM source files in the \PEN\SAMPLES\VPEND sub directory. The source files OEMs will want to work on are identified in the following table:

OEM Source File | Description
OEMAPI.C | OEM message handling.
OEMHWINT.C | OEM hardware interrupt servicing.
INITUTIL.C | Initializes the DRV_PENINFO and _HARDWAREINFO structures by reading values from the Windows 95 registry.
MISCUTIL.C | Miscellaneous OEM hardware-specific code. Hardware-specific code is also found in the source modules named for specific devices, such as CONCERTO.C.

If writing for a device other than a Wacom tablet, ignore the files VPEND.H and VPEND.INC in the \PEN\INC sub directory.


Purpose of the Pen Driver

The main purposes of the pen driver (PENC.DRV) are to:

  • Send data received from the virtual pen driver to Windows 95 clients, such as the Pen Services for Windows 95 system component, PENWIN.DLL.
  • Respond to messages sent by clients using the Windows SendDriverMessage function.

The pen driver is completely independent of the hardware. The OEM developer need not modify any portion of the PENC.DRV module so this section may be of little interest to a pen device OEM. The purpose of this section is to document the Windows messages that the pen driver recognizes in case the OEM wants to write a pen application (for example, an application that tests or demonstrates the vendor's pen device). The Windows messages recognized by the pen driver are documented in summary form in Appendix D of the Programmer's Guide to Pen Services for Microsoft Windows 95. This section of the Windows 95 DDK gives more details about each message.


Sending Pen Device Data to Windows

When the Pen Services for Windows 95 system component (PENWIN.DLL) loads and initializes the pen driver, the system component registers an entry point with the driver. At each pen hardware interrupt, the pen driver receives a packet of pen data from the virtual pen driver, as described below. It then calls the registered entry point, passing the pen data on to Windows.

Windows uses the pen data in one of the following ways, depending upon whether the pen is currently in writing mode or is functioning as a mouse:

  • If the pen is in writing mode, Windows displays ink on the screen corresponding to the new pen location. This creates a visible trail of pixels that simulates ink dropped by a real pen.
  • If the pen is functioning as a mouse, Windows requests the display driver to update the position of the pen cursor.


Receiving Windows Messages

The pen driver can also receive messages sent from Windows and from 16-bit pen-based applications. A pen driver message is generated by calling the SendDriverMessage function, identifying the pen driver as the recipient. Note that SendDriverMessage can access the 16-bit pen driver only from a 16-bit virtual machine. Thus, a 32-bit application cannot send messages to the pen driver directly. To communicate with the pen driver, a 32-bit application must provide its own 16-bit DLL to thunk calls to SendDriverMessage. A thunk is an implementation technique that allows 32-bit code to call 16-bit code (and vice versa, if necessary).


Loading and Unloading the Pen Driver

For information on how the pen driver is loaded and unloaded, see the section "Initializing the Pen Unidriver" in About the Pen Device Driver.


Message Processing

An OEM can change the behavior of the pen driver component by changing the driver's message interface. The sample pen driver supports two groups of messages:

  • Required messages, which any Windows 95 pen driver must support.
  • Other messages, which may be implemented by simply returning a NOT_SUPPORTED return code from the pen driver.


Required Pen Driver Messages

The pen driver must support a minimum set of required messages, which are listed in the table below.

Message | Description
DRV_CLOSE | Sent by the CloseDriver Windows function to close the driver.
DRV_CONFIGURE | Requests the driver to display its configuration dialog box.
DRV_DISABLE | Sent when the system unloads the pen driver.
DRV_ENABLE | Sent when the system loads the pen driver.
DRV_FREE | Sent when the system unloads the pen driver.
DRV_INSTALL | Informs the pen driver it should install itself on the system. The driver records the information the system needs at startup so that the next time Windows starts, the pen driver will be loaded.
DRV_LOAD | Sent to the pen driver when it is first loaded.
DRV_OPEN | Sent from the OpenDriver Windows function.
DRV_QUERYCONFIGURE | Checks if the driver provides a configuration dialog box.
DRV_REMOVE | Informs the pen driver it should uninstall itself from the system. The driver removes the information it recorded at startup and the references that the system uses to load the driver. The next time Windows starts, the pen driver will not be loaded.

Note that a fully functioning pen driver also supports the DRV_SetEntryPoints and DRV_RemoveEntryPoints messages. However, the pen driver can be used like a mouse driver, updating the pen cursor location, without supporting these two messages.

The pen driver must handle the standard messages that are sent to any installable Windows driver. Many of these standard messages have a counterpart message with a reverse effect-DRV_CLOSE is the counterpart of DRV_OPEN, for example. The following sections briefly describe the effects of each of the standard message pairs. At the end of this section, a table lists all the DRV_ messages recognized by the pen driver and gives a summary description of each message. For more complete descriptions of each of these required standard messages, see the "Reference" section.


DRV_LOAD and DRV_FREE

These two messages are the first and last messages an installable driver receives. When processing DRV_LOAD, the pen driver reads configuration information from the Windows 95 registry, configures associated hardware, and allocates memory if required.

To process DRV_FREE, the pen driver frees any allocations and notifies the virtual pen driver that the pen driver is being unloaded.


DRV_OPEN and DRV_CLOSE

The pen driver receives the DRV_OPEN message whenever a process opens the pen driver by calling the Windows OpenDriver function. The pen driver receives DRV_CLOSE when the process calls CloseDriver to close the driver.


DRV_ENABLE and DRV_DISABLE

When the pen driver receives DRV_ENABLE, it performs system operations such as hooking interrupts, initializing hardware, and so forth. It also calls the virtual pen driver to notify it to start sending pen packet information. Note that the tablet is in its default state at this point, having been set by the virtual device driver when it was initialized.

The DRV_DISABLE message reverses the process, telling the pen driver to restore the system back to its original state. When processing this message, the pen driver calls the virtual pen driver stop sending pen packet information.

The pen driver exists in memory between the DRV_ENABLE and DRV_DISABLE messages. The driver receives these messages only once during loading and unloading.


DRV_INSTALL and DRV_REMOVE

The DRV_INSTALL and DRV_REMOVE messages request the control panel to install, configure, and remove a driver from the system.


DRV_QUERYCONFIGURE and DRV_CONFIGURE

The pen driver responds to the DRV_QUERYCONFIGURE message by reporting whether or not it provides a custom-configuration dialog box. The sample pen driver does provide a pen configuration dialog box by calling PENUI.DLL. The custom-configuration dialog box is implemented by the source code in the \PEN\SAMPLES\PENUI directory, which produces PENUI.DLL.

The driver responds to the DRV_CONFIGURE message by displaying the custom-configuration dialog box.


Other Pen Driver Messages

The other messages the pen driver can receive are summarized in the following table. The pen driver should, at a minimum, respond to each of these messages by returning the code DRV_SUCCESS or DRV_FAILURE.

Message | Description
DRV_EXITSESSION | The sample pen driver ignores this message.
DRV_EXITAPPLICATION | The sample pen driver ignores this message.
DRV_GetCalibration | Instructs the pen driver to fill a calibration structure with the current calibration settings.
DRV_GetName | Returns the name of the pen driver.
DRV_GetPenSamplingRate | Returns the current sampling rate.
DRV_GetPenInfo | Fills a specified DRV_PENINFO structure with the current pen information.
DRV_GetVersion | Returns the driver version and the pen packet size.
DRV_PenPlayBack | Performs the playback of a specified number of pen packets from an array of pen packets.
DRV_PenPlayStart | Tells the pen driver the format of the pen packet data it will receive with the DRV_PenPlayBack message.
DRV_PenPlayStop | Forces the pen driver out of playback mode.
DRV_POWER | The sample pen driver ignores this message.
DRV_Query | Returns whether or not the pen driver supports the specified message.
DRV_RemoveEntryPoints | Removes an interrupt processing routine that was registered with a DRV_SetEntryPoints message.
DRV_SetEntryPoints | Registers a device or DLL to receive pen information (pen packets or any other OEM-specific information) at interrupt time.
DRV_SetPenSamplingRate | Instructs the pen hardware or software to report a specified number of points per second.
DRV_SetPenSamplingDist | Instructs the pen driver to filter out pen packets that have not moved a specified number of tablet units from the last reported locations.
DRV_SetCalibration | Instructs the pen drivers to calibrate the pen input to new tablet dimensions.

An OEM can define a list of custom messages. Custom messages must have defined values between DRV_RESERVED and DRV_USER, as set in the WINDOWS.H file.


Reference

This section gives reference information about each of the constants, data structures, functions, and messages used by the pen driver and virtual pen driver. This reference section has the following parts:

  • Constants
  • Data structures
  • Functions
  • Messages

Within each of these parts, the individual constants, data structures, etc. are listed in alphabetical order.


Constants

The following set of tables list the constants defined by the pen Unidriver. These constants are defined in the header file \PEN\INC\PENDRV.H.

Each table below lists a different functional group of constants. The functional groups are:

  • Driver return values.
  • Data type values (which indicate the various types of pen packets).
  • OEM return values.
  • Pen driver client return values.
  • Hardware flags.
  • Miscellaneous pen Unidriver constant definitions.


Driver Return Values

The driver return values are listed in the following table.

Constant | Description | Value
DRV_BADPARAM1 | Bad first parameter. | 0xFFFFFFFF
DRV_BADPARAM2 | Bad second parameter. | 0xFFFFFFFE
DRV_BADSTRUCT | Bad structure. | 0xFFFFFFFD
DRV_FAILURE | Message processing was not successful. | 0x00000000
DRV_SUCCESS | Message processing was successful. | 0x00000001


Data Type Values

Pen packet data types are identified by the constants in the following table.

Constant | Description | Value
DT_OEM | Indicates an interrupt-time message returned by the virtual pen driver to the pen driver if OEM-specific information needs to be serviced. | 0x00000400
DT_OORPENPACKET | Indicates an interrupt-time message returned by the virtual pen driver to the pen driver if an out-of-range pen packet generated the interrupt. | 0x00000004
DT_PENPACKET | Indicates an interrupt-time message returned by the virtual pen driver to the pen driver when the virtual pen driver gathers a complete pen packet. | 0x00000001
DT_TIMERTICK | Used internally by the timer tick callback routine. | 0x00000002
DT_UPDATEPENINFO | Sent to all pen driver clients if the pen information structure changes. | 0x00000008


OEM Return Values

The OEM-provided code in the cOEM_Hw_Int procedure may return the following values. The flags indicate the state of the pen-packet gathering process.

Constant | Description | Value
FF_COM_BASE | The base I/O address for the COM port is invalid in the _HARDWAREINFO structure and the virtual pen needs to access a COM port to gather pen information. This is an error code. | 0x00000002
FF_DATANOTREADY | There is no pen data to read from the hardware. This is an error code. | 0x00000400
FF_ERROR | There was an error. | 0x00000080
FF_EXPECTING_SYNC | Received data in the wrong order. A sync byte was expected and the byte received was not a sync byte. This is an error code. | 0x00000010
FF_INCOMPLETE | Data gathering is in process, but a complete packet has not been gathered yet. | 0x00000020
FF_OEMSPECIFIC | OEM-specific information. | 0x80000000
FF_OORPENPACKET | A complete out-of-range pen packet is ready. This is a success code. | 0x00000200
FF_OVERRUN | A data overrun occurred. This is an error code. | 0x00000004
FF_PENPACKET | A complete pen packet is ready. This is a success code. | 0x00000100
FF_RECORD_ERROR | The X point or the Y point in a received packet is invalid. This is an error code that is sent after a complete packet is gathered. | 0x00000008
FF_SUCCESS | A complete data packet is gathered and is ready to be serviced. | 0x00000001
FF_UNKNOWN | Unknown failure. This is an error code that is not used in the sample pen Unidriver code. | 0x00000000


Pen Driver Client Return Values

The following message can be returned by a client of the pen driver:

Constant | Description | Value
HR_STOP | Instructs the pen driver to not pass the information on to the next client of the pen driver. | 0x00000001
HR_CONTINUE | Instructs the pen driver to pass the information on to the next client. | 0x00000000


Hardware Capability Flags

Hardware flags are specific to the hardware and indicate the hardware's capabilities.

Constant | Description | Value
HW_BIOS | Indicates the hardware uses a BIOS interface to communicate with the tablet. | 0x00200000
HW_BUFFERZONE | If set, the driver creates a small zone around the tablet. | 0x00020000
HW_CALIBRATE | If set, the tablet uses the calibration structure to calibrate all in-range pen input. | 0x00010000
HW_PUSHMODEL | Instructs the virtual pen driver to report interrupt-time information to the pen driver for every pen packet that is gathered. | 0x00040000
HW_SERIAL | Indicates the hardware is connected to a serial port. The virtual driver behaves as a serial device. | 0x00100000
HW_TIMERMODEL | Instructs the virtual pen driver to report interrupt-time information to the pen driver when a timer tick occurs from the system timer instead of each time a pen packet is gathered. This can be used to reduce the number of ring transitions from the virtual pen driver to the pen driver. | 0x00080000


Miscellaneous Constant Definitions

Several other constants, which do not fit into the above categories of constants, are also important.

Constant | Description | Value
MAX_HOOKS | The maximum number of hooks allowed into the pen driver. | 0x00000004
PENREG_DEFAULT | Signifies that Pen Services is in the default state, handling pen packets from the digitizer. | 0x00000002
PENREG_WILLHANDLEMOUSE | Signifies that Pen Services will handle mouse movements and pass the mouse movement information to the Windows User library. | 0x00000001
PLAY_VERSION_10_DATA | Used with the pen playback functionality; set if the pen packet passed in has the format of a pen packet from Version 1.0 of Pen Services. | 0x00000000
PLAY_VERSION_20_DATA | Used with the pen playback functionality; set if the pen packet passed in has the format of a pen packet from Version 2.0 of Pen Services. | 0x00000001


Structures

This reference structure describes all the members of the major pen driver data structures.

The major pen driver data structures are listed in the following table. These data structures are defined in the PENDRV.H header file that is in the sub directory \PEN\INC after the Windows 95 DDK is installed, and the rightmost column of the following table identifies the header file that contains each structure definition.

Structure | Description
_HARDWAREINFO | Used by the virtual pen driver for hardware-specific information.
_VPenD_Register | Holds information that is critical to the functioning of the driver for a particular virtual machine (VM). All information in this structure will be updated if the current VM changes to a VM where there is a registered device to handle pen events.
DRV_CALBSTRUCT | The values in this structure are used to convert pen location values if point calibration is necessary.
DRV_OEMPENINFO | OEM-specific pen information structure that the virtual pen driver and pen driver use.
DRV_PENINFO | Pen information structure that the virtual driver and pen driver use.
DRV_PENPACKET | New pen-packet format for version 2.0 of the Pen API.
PPENPACKET | This version of the pen-packet format is from version 1.0 of the Pen API. It should not be used in drivers compliant with version 2.0 of the Pen API.
VPEND_INIT | Used when the pen driver initializes along with the virtual pen driver. VPEND_INIT contains the pointers and any other extra information that the virtual pen driver will need when pen hardware interrupts need to be serviced.


_HARDWAREINFO

typedef struct {
  DWORD ddCom_Port;
  DWORD com_base;
  DWORD ddIRQ_Number;
  DWORD ddPauseTime;
  DWORD ddReserved;
  DWORD ddOrientation;
  DRV_CALBSTRUCT calibrate;
  DWORD ddBufferZoneX;
  DWORD ddBufferZoneY;
  DWORD ddHardwarePacketSize;
  DWORD ddComPortSettings;
  DWORD dwHwFlags;
  DWORD ddHardwareType;
  DWORD ddTimerTickRate;
  DWORD ddDelayTime;
  DWORD ddVpenD_IRQ_Handle;
  DWORD ddSystemVMHandle;
} _HARDWAREINFO;

The hardware information structure is used by the virtual pen driver for hardware-specific information. The pen driver does not use this structure.

ddCom_Port
The COM port number used by the pen hardware. ddCom_Port is 0 if the hardware does not use a COM port, 1 for COM 1, 2 for COM 2, etc.
com_base
If ddCom_Port does not equal zero, com_base contains the base I/O address (in hexadecimal) that the port uses. For instance, the COM1 base I/O address is 3F8.
ddIRQ_Number
The IRQ number that the system uses. For instance, for COM1, the typical IRQ number is 4.
ddPauseTime
Time required to reset the digitizer during initialization.
ddReserved
Not used. Should be set to zero.
ddOrientation
Screen orientation. ddOrientation is an integer value from 0 to 3.
calibrate
A DRV_CALBSTRUCT structure that contains the current calibration information. The DRV_GetCalibration message is used to fill the DRV_CALBSTRUCT structure with calibration information.
ddBufferZoneX
Represents the number of units (in 0.001 inch) to reduce the active area in the x-direction. ddBufferZoneX applies only to opaque tablets. Creating a buffer zone around the edge of the active area makes it easier for the user to move the pen to the edge of the screen.
ddBufferZoneY
Represents the number of units (in 0.001 inch) to reduce the active area in the y-direction. See the definition of the ddBufferZoneX member for more information.
ddHardwarePacketSize
The number of bytes the serial device sends before the driver has received a complete pen packet.
ddComPortSettings
Defines the baud, parity, data, and stop bits of the serial transmission. The high-order word is baud divisor based on 19200. For example, 1 indicates 19200 and 2 indicates 9600. The low-order word is the control register values for parity, data, and stop bits.
dwHwFlags
A bitwise-OR combination of hardware flags. The hardware capability flag constants used by the sample pen virtual driver are defined in the in PENDRV.H.
ddHardwareType
Denotes the type of hardware. The hardware capability flag constants HW_PUSHMODEL and HW_TIMERMODEL in PENDRV.H define the types of hardware used by the sample pen driver. For more information, see About the Virtual Pen Driver.
ddTimerTickRate
Sets the rate in timer ticks at which the callback function receives control. For more information, see About the Virtual Pen Driver.
ddDelayTime
Sets the amount of time (in milliseconds) that must elapse waiting for a hardware interrupt before generating events from a timer tick. If ddDelayTime milliseconds elapse without receiving a hardware event, the VxD assumes the pen has moved beyond the tablet's range of sensitivity or has stopped moving. For more information, see About the Virtual Pen Driver.
ddVpenD_IRQ_Handle
The IRQ handle.
ddSystemVMHandle
The system VM handle.


_VpenD_Register

typedef struct {
  DWORD Device_VM_Handle;
  DWORD ibThis;
  DWORD ibThis_offset;
  DWORD ibNext;
  DWORD ibNext_offset;
  DWORD ibCurrent;
  DWORD iNumberOfPenPackets;
  DWORD wPDKLast;
  DWORD pDataType;
  DWORD piNumberOfPenPackets;
  DWORD piThis_Offset;
  DWORD piThis;
  LPDRV_PENPACKET pPenPacketBuffer;
  LPDRV_PENINFO pPenInfo;
  DWORD pOEMBuffer;
  DWORD pfnEntryPoint;
} _VpenD_Register;

Holds information that is critical to the functioning of the driver for a particular virtual machine (VM). All information in this structure will be updated if the current VM changes to a VM where there is a registered device to handle pen events. The state of the hardware should be preserved from VM to VM.

Device_VM_Handle
Handle of the virtual machine (VM) that receives the pen packet information. For the sample pen driver, the only handle in this member of the structure is the system VM handle.
ibThis
Index into the pen packet buffer to a pen packet location that has not been serviced.
ibThis_offset
Offset to pen packet that has not been serviced.
ibNext
Index to next available location.
ibNext_offset
Offset to next available location.
ibCurrent
Current index into the circular pen packet buffer.
iNumberOfPenPackets
Number of pen packets in the pen packet buffer that need to be serviced.
wPDKLast
State of last gathered pen packet.
pDataType
A pointer to the variable in the pen driver that will receive the data type values.
piNumberOfPenPackets
A pointer to the variable in the pen driver that will receive the number of pen packets that need to be serviced.
piThis_Offset
A pointer to the start of the buffer when pen packets are transferred.
piThis
TBD
pPenPacketBuffer
A pointer to the variable in the pen driver that will receive the pen packets.
pPenInfo
A pointer to a DRV_PENINFO structure in the pen driver.
pOEMBuffer
A pointer to an OEM-specific buffer. This is OEM defined.
pfnEntryPoint
The selector and offset of the routine that will service virtual pen driver interrupts in the pen driver.


DRV_CALBSTRUCT

typedef struct {
    DWORD dwOffsetX;
    DWORD dwOffsetY;
    DWORD dwDistinctWidth;
    DWORD dwDistinctHeight;
} DRV_CALBSTRUCT;

If points need to be calibrated after arriving from the hardware, the values in this structure are used to convert them.

dwOffsetX
The number of units (in 0.01 inch) to displace the x-value from the tablet. A negative number will shift it left. A positive number will shift it right.
dwOffsetY
The number of units (in 0.01 inch) to displace the y-value from the tablet. A negative number will shift it up. A positive number will shift it down.
dwDistinctWidth
The number of units (in 0.01 inch) that the hardware can generate in the x-direction.
dwDistinctHeight
The number of units (in 0.01 inch) that the hardware can generate in the y-direction.


DRV_OEMPENINFO

typedef struct {
  DWORD wPdt;
  DWORD wValueMax;
  DWORD wDistinct;
} DRV_OEMPENINFO;

OEM-specific pen information structure that the virtual pen driver and pen driver use.

wPdt
Pen data type. (See the description of PHW_ values in the Programmer's Guide to Pen Services for Windows 95 or the list in the PENWIN.H file.)
wValueMax
Largest returnable value by device; this value depends on the pen data type specified in the wPdt member.
wDistinct
Number of distinct reading possible; this value depends on the pen data type specified in the wPdt member.


DRV_PENINFO

typedef struct {
  DWORD cxRawWidth;
  DWORD cyRawHeight;
  DWORD wDistinctWidth;
  DWORD wDistinctHeight;
  DWORD nSamplingRate;
  DWORD nSamplingDist;
  DWORD dwSamplingRateMin;
  DWORD dwSamplingRateMax;
  DWORD fuOEM;
  DWORD lPdc;
  DWORD cPens;
  DWORD cbOemData;
  DRV_OEMPENINFO rgoempeninfo[MAXOEMDATAWORDS];
  DWORD rgwReserved[8];
} DRV_PENINFO;

Pen information structure that the virtual driver and pen driver use.

cxRawWidth
The width of the physical tablet in measured in units of 0.001 inch. For example, an 8-inch tablet would have a raw width of 8000 units.
cyRawHeight
The height of the physical tablet in measured in units of 0.001 inch. For example, a 6-inch-high tablet would have a height of 6000 units.
wDistinctWidth
The number of distinct x-values. For example, if an 8-inch-wide tablet supports 250 points-per-inch (ppi), then the distinct number of points would be 2000.
wDistinctHeight
The number of distinct y-values. For example, if a 6-inch-high tablet supports 200 ppi, then the distinct number of points would be 1200.
nSamplingRate
Number of pen packets per second.
nSamplingDist
The minimum distance between points that get processed.
dwSamplingRateMin
Minimum possible sampling rate.
dwSamplingRateMax
Maximum possible sampling rate.
fuOEM
A bit mask that specifies which pen information structure elements are reported in OEM units. (To see the format of the bit mask, refer to the description of PHW_ values in the Programmer's Guide to Pen Services for Windows 95 or the list in the PENWIN.H file.)
lPdc
Pen device capabilities.
cPens
Number of pens supported.
cbOemData
Width of an OEM data packet. This value is based on the bits set in the fuOEM member, which is described above.
rgoempeninfo[MAXOEMDATAWORDS]
OEM data. The structure of this data is defined by the DRV_OEMPENINFO structure.
rgwReserved[8]
Reserved.


DRV_PENPACKET

typedef struct {
  WORD wTabletX;
  WORD wTabletY;
  WORD wPDK;
  WORD rgwOemData[MAXOEMDATAWORDS];
  DWORD ddTimeStamp;
  DWORD ddSequential;
  DWORD ddProfile;
  DWORD ddDebug;
} DRV_PENPACKET;

New pen-packet format for version 2.0 of the Pen API.

wTabletX
The x-location of the tip of the pen relative to the tablet origin, measured in units of 0.001 inch.
wTabletY
The y-location of the tip of the pen relative to the tablet origin, measured in units of 0.001 inch.
wPDK
The state of the pen. (See the PDK_ flag values defined in PENWIN.H.)
rgwOemData[MAXOEMDATAWORDS]
The extra OEM-specific data.
ddTimeStamp
The time stamp when the pen packet was gathered.
ddSequential
A debug-only option. When running a debug version of the pen driver, the driver will report a sequential stamp with every pen packet.
ddProfile
A debug-only option. When running a debug version of the pen driver, the driver will report in this member the number of milliseconds if took from the time the virtual pen driver called the pen driver to when it returned. This effectively records the amount of time it took the pen driver to process all its clients (including the display driver).
ddDebug
A debug-only option. When running a debug version of the pen driver, the driver will report some common error conditions.


PPENPACKET

typedef struct {
  WORD wTabletX;
  WORD wTabletY;
  WORD wPDK;
  WORD rgwOemData[MAXOEMDATAWORDS];
} PPENPACKET;

This version of the pen-packet format is from version 1.0 of the Pen API. It should not be used in drivers compliant with version 2.0 of the Pen API.

wTabletX
The x-location of the tip of the pen after converting into increments of 0.001 inch.
wTabletY
The y-location of the tip of the pen after converting into increments of 0.001 inch.
wPDK
The state of the pen. (See the PDK_ flag values defined in the PENWIN.H header file.)
rgwOemData[MAXOEMDATAWORDS]
The extra OEM-specific data.


VPEND_INIT

typedef struct {
  LPDWORD lpDataType;
  LPDWORD lpNumberOfPenPackets;
  LPDWORD lpOffsetIntoBuffer;
  LPDWORD lpIndexIntoBuffer;
  LPDWORD lpPenPacketBuffer;
  LPDRV_PENINFO lpPenInfo;
  LPSTR lpOEMBuffer;
  LPDWORD lpfnEntryPoint;
} VPEND_INIT;

Used when the pen driver initializes along with the virtual pen driver. VPEND_INIT contains the pointers and any other extra information that the virtual pen driver will need when pen hardware interrupts need to be serviced.

lpDataType
A far pointer to a DWORD that is set with a data type value before the driver is called to service the pen interrupt. Data type values are used to indicate the interrupt-time driver event type.
lpNumberOfPenPackets
A far pointer to a DWORD that is set to the number of pen packets in the pen-packet buffer that need to be serviced when the pen interrupt occurs.
lpOffsetIntoBuffer
Not used.
lpIndexIntoBuffer
A far pointer to a DWORD that is set with the index location in the pen packet buffer where the first pen packet resides when the pen interrupt occurs.
lpPenPacketBuffer
A far pointer to a DRV_PENPACKET buffer of size 32 bytes.
lpPenInfo
A far pointer to a DRV_PENINFO structure that is filled with the current hardware capabilities when the driver requests it.
lpOEMBuffer
A far pointer to a buffer that holds OEM-specific data.
lpfnEntryPoint
A far pointer to the routine that processes the pen interrupts.


Functions

The only function described in this reference section is the callback function that a pen driver client registers with the pen driver so the client can receive pen information.


ProcessTabletEvents

void CALLBACK ProcessTabletEvents(WORD wHookID, WORD wEventType,
     WPARAM lParam1, LPARAM lParam2 );

Callback function, identified in the DRV_SetEntryPoints message, that receives data from the pen driver at the time of an interrupt. It must reside in a page-locked code segment because it functions as an interrupt handling routine.

ProcessTabletEvents is a place holder name representing the entry point. The entry point can have any name.

  • No return value.
wHookID
A single process can hook the pen driver more then once, providing the same entry point. When calling each entry point, the pen driver places the device ID in this parameter so the caller can determine what instance is being called. Note that this value is the value returned from the DRV_SetEntryPoints message.
wEventType
The type of event.
lParam1
Depends on the event type.
lParam2
Depends on the event type.

The entry point that receives the interrupt-time pen information should examine wEventType and handle the call accordingly.


Messages

The names of messages that are handled by the pen driver component of the pen Unidriver start with the characters "DRV_."


DRV_CLOSE

Sent by the CloseDriver Windows function.

  • Returns non-zero if successful; otherwise zero.
lParam1
Should be set to zero.
lParam2
Should be set to zero.


DRV_CONFIGURE

Requests the driver to display its configuration dialog box.

  • DRV_SUCCESS if successful; DRV_FAILURE if the windows handle is invalid.
lParam1
Low-order word contains the handle to a window that will own the dialog box.
lParam2
Should be set to zero.


DRV_DISABLE

Sent when the system unloads the pen driver.

  • Either DRV_FAILURE or DRV_SUCCESS.
lParam1
Should be set to zero.
lParam2
Should be set to zero.


DRV_ENABLE

Sent when the system loads the pen driver.

  • Either DRV_FAILURE or DRV_SUCCESS.
lParam1
Should be set to zero.
lParam2
Should be set to zero.


DRV_EXITAPPLICATION

The sample pen driver ignores this message.

  • DRV_FAILURE in all cases.
lParam1
Should be set to zero.
lParam2
Should be set to zero.


DRV_EXITSESSION

The sample pen driver ignores this message.

  • DRV_FAILURE in all cases.
lParam1
Should be set to zero.
lParam2
Should be set to zero.


DRV_FREE

Sent when the system unloads the pen driver.

  • Either DRV_FAILURE or DRV_SUCCESS.
lParam1
Should be set to zero.
lParam2
Should be set to zero.


DRV_GetCalibration

Instructs the pen driver to fill a calibration structure with the current calibration settings. The PDC_INTEGRATED flag is used to determine whether the hardware supports calibration.

  • One of these values:
DRV_FAILURE | Tablet does not support calibration (not integrated)
DRV_BADPARAM1 | The first parameter is not a valid pointer to a block of memory at least sizeof(CALBSTRUCT) in length
DRV_SUCCESS | The calibration structure was successfully filled

lParam1
Far pointer to a calibration structure that is filled if the hardware supports calibration.
lParam2
A far pointer to the PENINFO structure. (For a description of PENINFO, see the Programmer's Guide to Pen Services for Windows 95 or PENWIN.H.)


DRV_GetName

Returns the name of the pen driver. The buffer that receives the name (lParam2) should be at least 80 characters in length.

  • If successful, returns the number of characters copied to the buffer. This character count includes the string null termination character, so the value will be the number of characters in the pen driver name plus one. Otherwise, returns one of the following:
DRV_BADPARAM1 | The specified buffer length is not large enough to hold the pen driver name.
DRV_BADPARAM2 | The specified pointer does not point to a writeable block of memory of the size specified in lParam1.

lParam1
Length of buffer.
lParam2
Pointer to a character buffer that receives the pen driver name.


DRV_GetPenInfo

Fills a PENINFO structure with the current DRV_PENINFO structure information.

  • Returns one of the following:
DRV_SUCCESS | The PENINFO data structure was correctly filled.
DRV_BADPARAM1 | The lparam1 parameter does not point to a writeable block of memory of length sizeof(PENINFO).
DRV_FAILURE | No pen device is using the driver (no pen device is currently connected).

lParam1
A far pointer to the PENINFO structure. (For a description of PENINFO, see the Programmer's Guide to Pen Services for Windows 95 or PENWIN.H.)
lParam2
Should be set to zero.


DRV_GetPenSamplingRate

Returns the current sampling rate.

  • The low-order word of the return value is the current sampling rate.
lParam1
Should be set to zero.
lParam2
Should be set to zero.


DRV_GetVersion

Returns the driver version and pen packet size.

  • The high-order word of the return value contains the pen packet size in bytes. The low-order word of the return value contains the driver version information. The low-order byte is the major version number of the driver and the high-order byte is the minor version number.
lParam1
Should be set to zero.
lParam2
Should be set to zero.


DRV_INSTALL

Informs the pen driver it should install itself on the system. The driver records the information the system needs at startup so that the next time Windows starts, the pen driver will be loaded.

  • Either DRV_FAILURE or DRV_SUCCESS.
lParam1
Should be set to zero.
lParam2
Should be set to zero.


DRV_LOAD

Sent to the pen driver when it is first loaded.

  • Returns DRV_FAILURE or DRV_SUCCESS.
lParam1
Should be set to zero.
lParam2
Should be set to zero.

This is a system-only message that should only be generated from the system.


DRV_OPEN

Sent from the OpenDriver Windows function.

  • Returns a positive value if successful; otherwise zero.
lParam1
Should be set to zero.
lParam2
Should be set to zero.


DRV_PenPlayBack

Performs the playback of a specified number of pen packets from an array.

  • Returns DRV_SUCCESS if successful, DRV_FAILURE if already in playback mode. The driver must be taken out of playback mode by sending a DRV_PenPlayStop message before new packets can be played.
lParam1
A far pointer to an array of pen packets to be played through the system. The array of pen packets must conform to the data format of the DRV_PenPlayStart flags (PLAY_VERSION_10_DATA and PLAY_VERSION_20_DATA).
lParam2
The low-order word of lParam2 contains the number of pen packets to be played back. The high-order word is zero.

A pen driver client must send the DRV_PenPlayStart message before sending the DRV_PenPlayBack message. A DRV_PenPlayStart message must be accompanied by a corresponding DRV_PenPlayStop message to reset the playback mode.


DRV_PenPlayStart

Informs the pen driver of the format of the pen packet data it will receive after it receives the next DRV_PenPlayBack message. The driver does not actually start sending pen packets into the system until it receives the DRV_PenPlayBack message with the array of pen packets.

  • Returns DRV_SUCCESS if successful, or DRV_BADPARAM1 or DRV_BADPARAM2 if either of the parameters is invalid.
lParam1
Far pointer to a DWORD that will be updated when the driver is done playing back pen packets.
lParam2
Specifies the format of the data being passed to the driver. Set to PLAY_VERSION_10_DATA (or zero) for compatibility with version 1.0 of the Pen API. Set to PLAY_VERSION_20_DATA for version 2.0 functionality.

PLAY_VERSION_10_DATA is the default action when the driver is in playback mode. Because of this, the array of pen packets will be played back in the form of the PPENPACKET structure and not in the form of the DRV_PENPACKET structure.

A DRV_PenPlayStart message must be accompanied by a corresponding DRV_PenPlayStop message to reset the playback mode.


DRV_PenPlayStop

Forces the pen driver out of playback mode.

  • Always returns DRV_SUCCESS.
lParam1
Should be set to zero.
lParam2
Should be set to zero.

An application must send this message on completion of the playback or on playback failure. This resets the playback mode. A new playback cannot be started without resetting the playback mode.


DRV_POWER

Driver ignores this message.

  • Always returns DRV_FAILURE.
lParam1 | Should be set to zero.
lParam2 | Should be set to zero.


DRV_Query

Determines whether the version 2.0 driver supports a given message.

  • Returns DRV_SUCCESS if the message is supported; otherwise DRV_FAILURE.
lParam1
The low-order word contains the message that the sender is inquiring about.
lParam2
Should be set to zero.

The following example queries the driver to determine if it supports playback.

HDRVR hPenDrvr;
if( hPenDrvr=OpenDriver( "pen",0L,0L ) )
{
  if( !SendDriverMessage( hPenDrvr, DRV_Query, DRV_PenPlayBack, 0L ) )
  MessageBox( GetFocus(), "DRV_PenPlayBack not supported",
         "Querying Pen Driver", MB_OK);
  CloseDriver( hPenDrvr );
}


DRV_QUERYCONFIGURE

Checks if the driver provides a configuration dialog box.

  • Returns DRV_SUCCESS if the driver provides a dialog box that enables dynamic configuring; DRV_FAILURE if the driver does not support dynamic configuring.
lParam1
Should be set to zero.
lParam2
Should be set to zero.


DRV_REMOVE

Informs the pen driver it should uninstall itself from the system. The driver removes the information it recorded at startup and the references that the system uses to load the driver. The next time Windows starts, the pen driver will not be loaded.

  • Returns either DRV_FAILURE or DRV_SUCCESS.
lParam1
Should be set to zero.
lParam2
Should be set to zero.


DRV_RemoveEntryPoints

Removes the interrupt-processing routine that was registered with DRV_SetEntryPoints.

  • Returns either DRV_SUCCESS or DRV_FAILURE.
lParam1
Either the PENREG_WILLHANDLEMOUSE flag or the PENREG_DEFAULT flag.
lParam2
The hook ID value returned from DRV_SetEntryPoints.

This routine undoes the work of DRV_SetEntryPoints and must be called to remove the registration of the driver or DLL for receiving pen data. After the pen driver processes DRV_RemoveEntryPoints, the hook ID is no longer valid and should be set to NULL.

The following example code shows a call to SendDriverMessage that sends a DRV_RemoveEntryPoints message.

dwRetVal = SendDriverMessage( hPenDrv, DRV_RemoveEntryPoints, PENREG_DEFAULT, dwHookID);


DRV_SetCalibration

Instructs the drivers to calibrate the input to the new dimensions. This message has an effect only if the hardware supports calibration. The PDC_INTEGRATED flag is used to make this decision.

  • Can return one of these values:
DRV_SUCCESS | The calibration was done successfully.
DRV_BADPARAM1 | The lparam1 parameter is not a pointer to a calibration structure.
DRV_FAILURE | The tablet does not support calibration (not integrated).

lParam1
Far pointer to a calibration structure that the driver should use.
lParam2
Should be set to zero.


DRV_SetEntryPoints

Registers a device or DLL to receive pen data at each interrupt. Such pen data include pen packets and any OEM-specific information.

  • If the message processing is successful, the driver returns the device hook ID. The ID is a positive number that the sender should store. (To discontinue receiving pen events, the sender must provide the ID number with the DRV_RemoveEntryPoints message.) If the message processing is not successful, the driver returns DRV_FAILURE.
lParam1
Either the PENREG_WILLHANDLEMOUSE flag or the PENREG_DEFAULT flag.
lParam2
The address of a callback function to receive the pen data. This function must export the interface specified in the ProcessTabletEvents function specified elsewhere in this reference section.

The callback routine that handles tablet events must be in a page-locked code segment because it functions as an interrupt-handling routine.

Typically, only the PENWIN.DLL library sends the DRV_SetEntryPoints message to the pen driver. If another process needs to hook the interrupt data traffic, it should do so by sending DRV_SetEntryPoints. Possible reasons to hook the interrupt data include processing pen packets to determine hardware accuracy, recording interrupt-time information, or perhaps performing interrupt-time processing based on pen information.

The following example code shows a call to SendDriverMessage that sends a DRV_SetEntryPoints message.

dwHookID = SendDriverMessage( hPenDrv, DRV_SetEntryPoints,
              PENREG_DEFAULT, &ProcessTabletEvents );


DRV_SetPenSamplingDist

Adjusts the granularity of the pen packets sent by the pen driver. DRV_SetPenSamplingDist instructs the pen driver to filter out packets that have not moved a specified number of tablet units (called the sampling distance) from the last reported location.

  • If successful, returns the previous sampling distance; otherwise, the Windows SendDriverMessage function returns DRV_FAILURE.
lParam1
The low-order word contains the number of tablet units the pen should move before a new point is generated.
lParam2
Should be set to zero.

The default value for the sampling distance is zero. In other words, all points are reported. Note that the sampling rate is based on a sampling distance of zero. If the sampling distance is set to a value other then zero, pen packets will be filtered out of the data stream. Thus, the rate at which the system receives pen packets may be less than the specified sampling rate because the pen driver sends only packets that reflect minimum movement.


DRV_SetPenSamplingRate

Instructs the pen hardware or software to report a specified number of points per second.

  • If successful, the high-order word of the return value is zero and the low-order word is the previous sampling rate; otherwise, the Windows SendDriverMessage function returns DRV_FAILURE.
lParam1
High-order word should be zero; low-order word should be the desired new sampling rate.
lParam2
Should be set to zero.

The sampling rates provided by the pen driver are directly related to the capabilities of the hardware. If the hardware does not support the requested sampling rate, the sampling rate will be set to closest sampling rate supported by the hardware. If the requested sampling rate is larger than any sampling rate supported by the hardware, the sampling rate will be set to maximum rate supported by the hardware.


Virtual Pen Device Driver

The virtual pen driver (VPENDC.VXD) handles hardware interrupts generated by the pen device. At each interrupt, the virtual pen driver organizes the raw data from the pen device and passes the organized data to the pen driver (PENC.DRV).

The virtual driver is the only component of the pen Unidriver that communicates directly with the pen hardware. Therefore, the OEM developer can confine any modifications of the pen device driver to the virtual pen driver code.

The virtual pen driver also receives requests from the pen driver in the form of messages.


Processing Interrupts

The hardware passes pen information into the system by issuing a hardware interrupt. The handler routine in the virtual pen driver that services the interrupt is cVpenD_Hw_Int, which is in the sample driver source file HWINT.C.

The cVpenD_Hw_Int function calls the cOEM_Hw_Int function to gather the hardware-dependent information into a pen packet. (The cOEM_Hw_Int function is located in the sample driver source file OEMHWINT.C). The return codes from the cOEM_Hw_Int function indicate the status of the gathering process. A complete list of return codes implemented by the sample driver is in the following table. All return codes except FF_INCOMPLETE have either the FF_ERROR or FF_SUCCESS flag set. The other flags listed in the following table give more information about the type of error or type of success.

Constant | Use
FF_COM_BASE | The I/O base address for the COM port is invalid in the _HARDWAREINFO structure. The virtual pen driver needs to access a COM port to receive pen information. This is an error code.
FF_DATANOTREADY | There is no data to read from the hardware. This is an error code.
FF_ERROR | There is an error.
FF_EXPECTING_SYNC | Received data in wrong order. A sync byte was expected and the byte received was not a sync byte. This is an error code.
FF_INCOMPLETE | Data gathering is in process, but a complete packet has not been gathered yet.
FF_OEMSPECIFIC | OEM-specific information.
FF_OORPENPACKET | A complete out-of-range pen packet is ready. This is a success code.
FF_OVERRUN | A data overrun occurred. This is an error code.
FF_PENPACKET | A complete pen packet is ready. This is a success code.
FF_RECORD_ERROR | The X or Y point value in a received packet are invalid. This is an error code that is sent after a complete packet is gathered.
FF_SUCCESS | A data packet has been gathered and is ready to be serviced.
FF_UNKNOWN | Unknown failure. This is an error code.

If the cOEM_Hw_Int function returns one of the codes that indicates success, then pen data has been gathered for the cVpenD_HW_Int function to process and send on to the pen driver. When the cVpenD_Hw_Int function has a complete pen packet, it orients the point coordinates to the proper display orientation (either landscape or portrait) and calibrates the (x,y) point, converting it to a resolution of 0.001 inch.

The cVpenD_Hw_Int function also adds extra hardware-independent information to the packet, such as a time stamp. The debugging version of the virtual pen driver also adds to the packet a sequential number stamp, profile information, and other hardware-independent data pertinent to debugging. The virtual pen driver then schedules a callback to its cCall_Installable_Driver function (located in the TIMERCB.C source file) so the pen packet will be sent to the pen driver.

cCall_Installable_Driver determines the number of pen packets in the buffer waiting to be serviced and passes this number on to the pen driver along with the starting offset and index into the buffer. Finally, it calls the pen driver, which services the pen packet buffer.

When it receives control, the pen driver calls all its clients with the appropriate DT_ data type message. A complete list of DT_ data type messages is contained in the following table:

Constant | Use
DT_OEM | Indicates an interrupt-time message returned by the virtual pen driver to the pen driver if OEM-specific information needs to be serviced.
DT_OORPENPACKET | Indicates an interrupt-time message returned by the virtual pen driver to the pen driver if an out-of-range pen packet generated the interrupt.
DT_PENPACKET | Indicates an interrupt-time message returned by the virtual pen driver to the pen driver when the virtual pen driver gathers a complete pen packet.
DT_UPDATEPENINFO | Sent to all pen driver clients if the pen information structure changes. For example, the sample pen driver sends this data type to its clients if the sampling rate, sampling distance, distinct height, or distinct width values change.


Time-Based Interrupts

If the pen stops moving or is lifted beyond the tablet's range of sensitivity, many devices will stop generating hardware interrupts. This ends the normal flow of communication between the pen device and Windows.

However, the recognition model of the Pen API version 2.0 requires the pen driver to continuously call into the system even when there is no pen data available. If the pen hardware maintains its own clock mechanism, it can continue to pulse time-based interrupts even when the pen is out of range. When pen motion ceases, the time-based interrupts ensure the system continues to receive pen information.

If the pen device does not contain its own clock, the pen device driver must compensate by using the system timer. In this case, the driver provides a timer hook that activates at regular intervals. This enables the driver to continue its stream of system calls even if the normal hardware interrupts from the device have ceased.

The pen Unidriver sample code uses the system timer. If the OEM device generates its own time-based interrupts, the developer should remove the code that uses the system timer from the Unidriver source code. Such code is in the sample virtual pen driver source code modules HWINT.C, TIMERCB.C, and APIPROCS.C.

When enabled through the DRV_ENABLE message, the virtual pen driver sets up a callback timer function to use the system timer. The callback is named cTimer_Callback_Entry_Point in the TIMERCB.C source file. cTimer_Callback_Entry_Point receives control at each timer tick, which occurs every 55 milliseconds. If it determines that no pen data has arrived from the tablet since the last timer tick, cTimer_Callback_Entry_Point fabricates an out-of-range packet and schedules a callback to the function registered by PENWIN.DLL so the fabricated packet will be sent to the system. An out-of-range packet is a DRV_PENPACKET structure with the wPDK member set to the defined value PDK_OUTOFRANGE. After completing all this, cTimer_Callback_Entry_Point sets up another timer tick callback and waits.

Handling out-of-range pen packets is a virtual pen driver design issue.

All tablets run in what is called in this documentation shutup mode. In shutup mode, the tablet sends only one out-of-range packet when the pen goes out of range and then sends no more packets until the pen goes back into range. However, serial communications and tablets may be unreliable and the one out-of-range packet is never received by the driver. Sometimes such a lost out-of-range packet can cause Windows 95 to stop processing messages and force the user to restart Windows. For example, suppose the user employs the pen to move a window by dragging the window's title bar.

A possible sequence of important pen events during this window dragging operation are

  1. Pen is down at (x1, y1), which is on the title bar.
  2. Pen is up at (x2, y2), which establishes the new location of the window.
  3. Pen goes out of range because the user is finished moving the window.

If both the second and third events are lost because of unreliable communication between the tablet and the virtual pen driver, the user will eventually have to restart Windows.

To guard against this with tablets that run only in shutup mode, the sample virtual pen driver uses a timer function to constantly monitor the time interval between packet receipt events in the virtual pen driver. If the virtual pen driver does not receive a packet within this time interval, the time function generates an out-of-range packet, which gets sent to the pen driver which notifies Windows of the pen event.

Some OEM tablets (such as the Wacom tablets) enable the virtual pen driver to toggle the tablet between two modes:

  • Shutup mode, as described earlier, sends only one out-of-range packet when the pen goes out of range and then sends no more packets until the pen goes back into range.
  • Speakup mode sends pen information constantly, even when the pen is out of range. When the pen is out of range, the tablet sends one out-of-range packet after another.

For such tablets, the following strategy can be used to insure that unreliable pen packet communication between the tablet and the virtual pen driver do not force the user to restart Windows

  1. The tablet is kept in speakup mode until an out-of-range packet is received (that way, the virtual pen driver will always receive an out-of-range packet to mark the transition form in-range to out-of-range even if out-of-range packets are lost).
  2. When the virtual pen driver receives an out-of-range packet, it puts the tablet in shutup mode so it does not receive useless out-of-range packets).
  3. The next time the virtual pen driver receives a packet (it must be an in-range packet), it puts the tablet in speakup mode again.

If you are writing a virtual pen driver that supports both shutup and speakup modes, using the above strategy will put more responsive pens in the hands of the users than if you use the timer method.

The Windows95 DDK sample pen driver supports only the timer method of guarding against lost out-of-range pen packets. For sample code that implements the method that uses both speakup and shutup modes, see the sample pen driver in the Windows 3.1 DDK.

The timer strategy is implemented in the following blocks of code:

Source Module | Function | Comment
TIMERCB.C | cTimer_Callback_Entry_Point | This code determines whether it has been too long since receipt of the last packet and, if so, synthesizes an out-of-range packet.
APIPROCS.C | cVpenD_API_Enable | Registers the timer callback entry point and, if the HW_TIMERMODEL flag is set, causes monitoring of the interval between interrupts to begin.

Note that with tablets that support speakup mode, it can also be used to implement playback of stored pen packets. The virtual pen driver puts the tablet in speakup mode and every time it receives an out-of-range packet, the driver substitutes information from the next stored pen packet and sends it on to the pen driver as a pen packet. The blocks of code that implement this strategy in the sample virtual pen driver are:

Source Module | Function | Comment
APIPROC.C | cVpenD_API_Proc | See the VPEND_PENPLAYSTART case block in the dwMsg switch structure.
OEMAPI.C | cOEM_API_Proc | Sends the speak up and shut up command strings to the tablet.


Communications Port Conflicts

Solving communications port conflicts between the pen driver and other Windows 95 applications is a design issue. The pen driver uses a communications port (COM1, COM2, COM3, or COM4) to receiver pen packets from the digitizer. If another Windows application, such as a communications application, hooks the IRQ associated with the COM port the digitizer is using, either pen packets will stop flowing from the digitizer to the pen driver or when the communications application sends output to the communications device the same bytes will also be sent to the pen driver, and the bytes are not formatted as pen packets.

The sample virtual pen driver uses a VCD_Acquire_Port system function call to mitigate the port contention problem. This informs Windows 95 that a VxD has taken control of a particular COM port. Then, if a communications application tries to use the COM port with a standard Windows 95 API function call, the system will not allow the application to use the port that has been acquired by the virtual pen driver. Digitizers are not Plug and Play devices under Windows 95, so they cannot participate in dynamic reallocation of the COM port when it is requested by another application.

There is a problem with the VCD_Acquire_Port solution to the COM port contention problem: if an application does not use standard Windows 95 APIs to request the COM port, the system will display a modal dialog "Cannot write to COMx" every time the application attempts to write to the port, which interferes with the user's ability to get a lot of work done. When you write the virtual pen driver for your device, you may want to design a different way of handling the communications port contention issue. If you are using the sample driver source code as a starting point for your driver, this means that you will have to replace the VCD_Acquire_Port function call, which is in the source module INITUTIL.C in the Windows 95 DDK directory \DDK\PEN\SAMPLES\VPEND.


Unloading the Virtual Pen Device Driver

The unloading process for the virtual pen device driver should ideally comply with the Plug and Play specifications. The Unidriver's exit code currently consists of only the function cVpenD_Device_Exit, which forms a shell for the exit procedure. The virtual pen driver receives a Sys_Critical_Exit message when the system unloads it. In handling this message, the virtual pen driver should place the hardware in a stable state and free any resources it holds.


Virtual Driver Messages

The messages the virtual pen driver can receive are listed in the following table.

Message | Description
VPEND_DISABLE | Calls cVpenD_API_Disable to disable the tablet.
VPEND_ENABLE | Calls cVpenD_API_Enable to enable the tablet.
VPEND_FREE | Frees all resources used to monitor the pen device and decrements the number of installed drivers.
VPEND_GETCALIBRATION | Determines hardware calibration information and puts it into a DRV_CALBSTRUCT structure provided by the caller.
VPEND_GETPENINFO | For a pen driver that supports more than one virtual machine (VM), copies the pen information for the current VM to a DRV_PENINFO structure provided by the caller. The sample pen driver does not use a VPEND_GETPENINFO message.
VPEND_LOAD | Initializes variables so the tablet can later be enabled.
VPEND_OEM | An OEM-specific message which is passed through to the OEM-provided part of the virtual pen driver.
VPEND_PENPLAYBACK | Starts playing back an array of stored pen packets, substituting the stored pen packets for pen packets assembled from tablet interrupt information.
VPEND_PENPLAYSTART | Puts the virtual pen driver in playback mode by setting up all data structures necessary to act on the next VPEND_PENPLAYBACK message received.
VPEND_PENPLAYSTOP | Takes the virtual pen driver out of playback mode.
VPEND_SETCALIBRATION | Sets calibration values in the hardware information structure.
VPEND_SETSAMPLINGDIST | Sets the sampling distance. The sample virtual pen driver sets the new sampling distance value in the DRV_PENINFO structure but does not call an OEM-supplied code to set the sampling rate.
VPEND_SETSAMPLINGRATE | Calls OEM-supplied, device-specific code to set the tablet sampling rate.


Adapting the Virtual Pen Driver

If your pen device is one of those supported by the pen Unidriver, you can adapt the virtual pen driver simply be making changes to a header file, DEFINES.H. For instructions on how to do this and a list of the pen devices supported by the pen Unidriver, see the section "Creating a Custom OEM Driver" in About the Pen Device Driver.

If your pen device is not compatible with one of the pen devices supported by the pen Unidriver, you will have to change some of the source code in the virtual pen driver DDK directory and remake the virtual pen driver. The virtual pen driver source code is in the directory \PEN\SAMPLES\VPEND. The source files OEMs will want to work on are identified in the following table:

OEM Source File | Description
OEMAPI.C | OEM message handling.
OEMHWINT.C | OEM hardware interrupt servicing.
INITUTIL.C | Initializes the DRV_PENINFO and _HARDWAREINFO structures by reading values from the Windows 95 registry.
MISCUTIL.C | Miscellaneous OEM hardware-specific code. Hardware specific code is also found in the source modules named for specific devices, such as CONCERTO.C.

One reason for changing code in INITUTIL.C is to solving communications port conflicts between the pen driver and other Windows 95 applications is a design issue. The pen driver uses a communications port (COM1, COM2, COM3, or COM4) to receiver pen packets from the digitizer. If another Windows application, such as a communications application, hooks the IRQ associated with the COM port the digitizer is using, either pen packets will stop flowing from the digitizer to the pen driver or when the communications application sends output to the communications device the same bytes will also be sent to the pen driver, and the bytes are not formatted as pen packets.

The sample virtual pen driver uses a VCD_Acquire_Port system function call to mitigate the port contention problem. This informs Windows 95 that a VxD has taken control of a particular COM port. Then, if a communications application tries to use the COM port with a standard Windows 95 API function call, the system will not allow the application to use the port that has been acquired by the virtual pen driver. Digitizers are not Plug and Play devices under Windows 95, so they cannot participate in dynamic reallocation of the COM port when it is requested by another application.

There is a problem with the VCD_Acquire_Port solution to the COM port contention problem: if an application does not use standard Windows 95 APIs to request the COM port, the system will display a modal dialog "Cannot write to COMx" every time the application attempts to write to the port, which interferes with the user's ability to get a lot of work done. When you write the virtual pen driver for your device, you may want to design a different way of handling the communications port contention issue. If you are using the sample driver source code as a starting point for your driver, this means that you will have to replace any uses of the VCD_Acquire_Port function call in the source module INITUTIL.C.


Constants

The constants used by the virtual pen driver are documented in About the Pen Driver.


Structures

The data structures used by the virtual pen driver are documented in About the Pen Driver.


Messages

The names of the messages handled by the virtual pen driver component of the pen Unidriver start with the characters "VPEND_."


VPEND_DISABLE

Calls cVpenD_API_Disable to disable the tablet.

  • Return value from cVpenD_API_Disable.
lParam1
Should be set to zero.
lParam2
Should be set to zero.


VPEND_ENABLE

Calls cVpenD_API_Enable to activate tablet.

  • Return value from cVpenD_API_Enable.
lParam1
Should be set to zero.
lParam2
Should be set to zero.


VPEND_FREE

Frees all resources used to monitor the pen device and decrements the number of installed drivers.

  • Returns DRV_FAILURE or the number of installed devices.
lParam1
Should be set to zero.
lParam2
Should be set to zero.


VPEND_GETPENINFO

Copies the pen information for the current virtual machine (VM) into a DRV_PENINFO structure supplied by the caller.

  • Always returns DRV_SUCCESS.
lParam1
Pointer to the _PENINFO structure where the virtual pen driver must put the pen information.
lParam2
Should be set to zero.

For a definition of the members of the DRV_PENINFO structure see the "Reference" section in About the Pen Driver.

The sample pen driver does use a VPEND_GETPENINFO message to get the pen information for the current VM because the sample pen driver supports only one VM, the system VM. The sample pen driver can get the pen information for the system VM out of the DRV_PENINFO structure that it maintains.


VPEND_GETCALIBRATION

Determines hardware calibration information and puts it into a DRV_CALBSTRUCT structure provided by the caller.

  • Returns DRV_SUCCESS.
lParam1
Pointer to the DRV_CALBSTRUCT structure where the virtual pen driver must put the current calibration information.
lParam2
Should be set to zero.

For a definition of the members of the DRV_CALBSTRUCT structure see the "Reference" section in About the Pen Driver.

The VPEND_GETCALIBRATION message is sent by the pen driver code that handles the DRV_LOAD message, which is sent to the pen driver when the system loads it. Note that the pen driver code that handles the DRV_GetCalibration message does not send a VPEND_GETCALIBRATION message to the virtual pen driver; the pen driver handles the DRV_GetCalibration message itself by getting information out of the DRV_CALBSTRUCT structure.


VPEND_LOAD

Initializes variables so the tablet can later be enabled.

  • If successful, returns a handle that the driver uses when it needs to enable or disable interrupts to itself. (This handle is also in the EAX register.) The handle can also be used when the driver sends a subsequent DRV_FREE message. Otherwise, returns DRV_FAILURE.
lParam1
Pointer to a VPEND_INIT structure.
lParam2
Should be set to zero.

The virtual driver receives the VPEND_LOAD message every time a process registers to receive interrupt callbacks from the virtual pen driver. When sent from the ring 3 driver, the DS:SI registers (or SS:SI, if DS=SS) should contain a pointer to a VpenD_Init structure. The virtual driver stores all the information in the _VpenD_Register structure for future reference.

This routine can be called from either a driver in the system virtual machine (VM) or from a driver in some MS-DOS VM. Every time the user switches VMs, the system notifies the virtual pen driver. This enables the virtual pen driver to route pen packets to the current VM, if a device in that VM has registered to receive pen information. This functionality is not provided in the sample virtual pen driver code.

At this time, only one device in each VM can register to receive pen packet information. If a driver has already registered for the VM that this driver is currently requesting to serve, this routine will return DRV_FAILURE.


VPEND_PENPLAYBACK

Starts playing back an array of stored pen packets.

  • Returns DRV_SUCCESS or DRV_FAILURE if the virtual pen driver is not in playback mode (because, for example, the virtual pen driver did not receive a VPEND_PENPLAYSTART message prior to this VPEND_PENPLAYBACK message) or the virtual pen driver is already playing back pen packets.
lParam1
Size of each pen packet in the array of pen packets to play back.
lParam2
Number of pen packets to play back.

The stream of pen packets from the tablet is replaced by a stream of pen packets from an array of stored pen packets.


VPEND_PENPLAYSTART

Sets up the virtual pen driver to replace the current stream of pen packets from the tablet with pen packets stored in an array of pen packets.

  • DRV_SUCCESS or DRV_FAILURE if the virtual pen driver is already in playback mode or the tablet interrupts cannot be enabled.
lParam1
Pointer to a DWORD to receive a time stamp when play stops.
lParam2
Set to either PLAY_VERSION_10_DATA or PLAY_VERSION_20_DATA, which indicates the size and structure of the pen packets that are to be played back.

The VPEND_PENPLAYSTART message handler saves the two parameter values in global variables, sets a global variable that indicates the virtual pen driver is in playback mode, and then calls cOEM_API_Proc with a message that turns on tablet interrupts so the stream of pen packets from the tablet continues to flow.


VPEND_PENPLAYSTOP

Stops playback.

  • Returns DRV_SUCCESS or DRV_FAILURE if the virtual pen driver is not in playback mode.
lParam1
Should be set to zero.
lParam2
Should be set to zero.

If the virtual pen driver is in playback mode, but not actually playing back pen packets, then the VPEND_PENPLAYSTOP message takes the virtual pen driver out of playback mode. If the virtual pen driver is playing back pen packets when the VPEND_PENPLAYSTOP message is received, the driver will both stop playing pen packets and go out of playback mode.

In the sample virtual pen driver, the VPEND_PENPLAYSTOP message handler does its job by setting the pointer to the array of pen playback packets to NULL and turning off both the global flag that indicates the virtual pen driver is in playback mode and the global flag that indicates the virtual pen driver is playing back packets.


VPEND_SETCALIBRATION

Sets calibration values in the hardware information structure.

  • Returns DRV_FAILURE or DRV_SUCCESS.
lParam1
Pointer to a DRV_CALBSTRUCT structure that contains the calibration information to set in the hardware information structure.
lParam2
Should be set to zero.

For a definition of the members of the DRV_CALBSTRUCT structure see the "Reference" section in About the Pen Driver.


VPEND_SETSAMPLINGDIST

Sets the sampling distance on the digitizer hardware.

  • Previous sampling distance (the sampling distance before it was reset).
lParam1
The low word contains the new sampling distance (the value that the virtual pen driver applies to the hardware).
lParam2
Should be set to zero.


VPEND_SETSAMPLINGRATE

Calls OEM-supplied, device-specific code to set the sampling rate.

  • If successful, returns the new sampling rate; otherwise, returns DRV_FAILURE.
lParam1
The low word contains the new sampling rate (the value that the virtual pen driver applies to the hardware).
lParam2
Should be set to zero.

The sample virtual pen driver sends a message with the requested new sampling rate to cOEM_API_Proc.


Pen Driver User Interface

The pen user interface (PENUI.DLL) library contains the user-interface functions of the pen Unidriver. These functions provide a simple configuration dialog box that queries for the pen device model, the COM port, and whether to provide OEM-specific data (if the tablet supports it).

If desired, an OEM developer can replace or enhance the user interface, by providing a property sheet for Windows 95, thus gaining additional marketability and user recognition. The pen Unidriver maintains its interface code as a separate library to facilitate such enhancements or a complete replacement of the library by the OEM.

The sample pen user interface source code is in the directory \PEN\SAMPLES\PENUI of the installed Windows 95 DDK. This sample can be enhanced or used as a model for the source code of a DLL that completely replaces the pen user interface library.


Modifying the Pen Driver User Interface

The pen driver user interface is displayed as part of the installation process when Pen Services for Windows 95 is installed. After that, the interface is available to the user through the Pen icon in the Windows 95 Control Panel. When the user double-clicks on the Pen icon, the Pen Properties property sheet is displayed with several tabs. Click on the General tab and then click on the Pen Options button and the Pen Driver Configuration Dialog generated by PENUI.DLL will be displayed.

The version of PENUI.DLL supplied with the sample pen driver generates a dialog with three parts:

  • The Model drop down list displays the manufacturer and model of all the digitizers supported by the driver so the user can select the digitizer they are using. For the sample pen driver, this list has four choices: Wacom\SD-510C, Wacom\HD-648A, Wacom\HD-UD-0608-R, and Compaq\Concerto. There is also a choice that disables the tablet hardware.
  • The Serial Device buttons enable the user to specify which COM port the digitizer is connected to. In Windows 95, the digitizer is not a Plug and Play device, so the system does not detect which COM port a digitizer is connected to.
  • The Pressure check box enables the user to specify whether or not their digitizer senses stylus pressure and reports different levels of pressure to the pen driver.

If your pen driver needs the user to specify more information about the hardware than the three items above, then you will have to change the source code and produce a PENUI.DLL that displays a different dialog. For example, if your tablet does not have support for stylus pressure sensitivity, then you will probably want to eliminate the check box in the dialog that prompts the user to check the Pressure option. Or, if your tablet does support pressure sensitivity, you may want to change the prompt from "Pressure" to a more self-descriptive prompt such as "Pressure sensitivity" or "Pressure sensitivity support."

You may also want to change the items in the Model drop down list, so it includes the name of your digitizer and does not present the names of digitizers that are incompatible with yours.

This section gives more information about the source code in the DDK \PEN\SAMPLES\PENUI directory so it will be easier for you to make these changes.


Source Code Components

The source code components for the pen driver configuration user interface library are described in the following table.

Component | Description
DIALOGS.DLG | Defines the pen driver configuration dialog.
MAKEFILE | 16-bit makefile for the DLL.
PENUI.DEF | Definitions file.
PENUI.RCV | Contains version strings read by the operating system.
PENUI.H | Header file, found in the \PEN\INC directory.
PENUI.RC | Resource file.
EXPORTS.C | Contains all the exports for the DLL. In particular, exports the ConfigDialog function that is called by the pen driver and Windows 95 Control Panel to display the Pen Properties property sheet. Also exports the DLLMainCRTStartup, LibMain, and WEP functions.
WIN40DLG.C | Contains the dialog message handling routine. This module also contains the code that accesses the pen driver key in the registry and puts information from the dialog into the _HARDWAREINFO structure.


Changing the Model Drop Down List

To change the entries in the pen driver configuration dialog Model dropdown list, you do not need to change any source code. Since the list is populated by information from the Windows 95 registry, you can change the items that appear in the list by changing the .INF file used by Windows 95 startup to create the registry entries when Pen Services for Windows 95 is installed. For instructions on how to change the .INF file, see the Pen Services for Windows 95 OEM Adaptation Kit (OAK) Release Notes.


Changing the Number of Dialog Items

To make significant changes to the pen driver configuration dialog, you will have to change the code in WIN40DLG.C.


Reference

Any version of PENUI.DLL must export one function in order to be called by the pen driver when it is installed and by the Windows 95 Control Panel. If your PENUI.DLL does not export this function, it will never be called.


ConfigDialog

DWORD ConfigDialog(HDRVR hPenDriver, HANDLE hParent );

Provides an entry point which displays the pen driver configuration dialog.

  • Returns a positive value if successful; otherwise, returns a negative value.
hPenDriver | Not used; caller should set this parameter to NULL.
hParent | Handle to the window in which to display the pen driver configuration dialog box. If the caller sets this parameter to NULL, then the window with focus is used.

In the sample driver code, the ConfigDialog function calls the ConfigDlgProc function in WIN40DLG.C to handle the dialog messages, access the pen hardware information in the Windows 95 registry, and make any necessary changes to the _HARDWAREINFO structure. For a definition of the members of the _HARDWAREINFO structure, see the "References" section in About the Pen Driver.


Pen Calibration

The pen calibration application is an extension to the Windows 95 Control Panel pen icon. When the user opens the General panel of the Control Panel Pen property sheet, one of the controls on the panel is the Align Now button. The pen calibration applet (PENCAL.DLL) executes when the user selects the Align Now button.

The pen calibration source code is in the Windows 95 DDK directory \PEN\SAMPLES\PENCAL. In general, there are two reasons why you may need to change the pen calibration application:

  • Your digitizer may have resolutions other than 640x480; the pen calibration application is limited to aligning the pen for 640x480 digitizers only.
  • The calibration requirements for your digitizer may include gathering data items that are not part of the DRV_CALBSTRUCT structure the pen calibration applet uses to communicate calibration to the pen Unidriver. For a definition of the members of the DRV_CALBSTRUCT structure, see the "Reference" section in About the Pen Driver.

Note The purpose of pen calibration is to align the cursor display with the location of the pen tip on devices that have the display integrated with the digitizer. The pen calibration applet cannot be used on opaque tablets and the Align Now button is inactive in the Windows 95 Control Panel Pen property sheet when an opaque tablet is installed.


Structure of the Pen Calibration Applet Source Code

The functional structure of the pen calibration DLL is reflected in the entry points that it exports:

EXPORTS
WEP                @1 RESIDENTNAME
CalDlg             @2
Calibrate          @3
VerifyChangesDlg   @4
ErrMsgDlg          @5

The pen calibration application

  • Presents a calibration dialog to the user on the non-opaque tablet which prompts the user to touch targets displayed on the tablet.
  • Uses the touch input information to fill in a DRV_CALBSTRUCT data structure for use by the pen Unidriver.
  • Presents a calibration changes dialog and error message dialog to the user, if necessary.

The source modules that make up the pen calibration applet source code are listed in the following table along with a description of each module.

Module | Description
CAL.H | General header file for PENCAL.DLL
CALDLG.C | Conducts the calibration dialog with the user and writes the new configuration information to the pen driver key in the Registry.
CALERR.C | Calibration error handling routine.
CALERR.H | Defines the error messages that can be output by PENCAL.DLL; header file for CALERR.C.
CALINIT.C | Contains LibMain and WEP functions.
MAKEFILE | 16-bit makefile for the DLL.
PENCAL.DEF | Definitions file.
PENCAL.DLG | Defines the pen calibration dialog box.
PENCAL.RC | Resources file.
PENCAL.RCV | Contains version strings read by the operating system.
RES.H | Resource header file for PENCAL.DLL.
UMULDIV.ASM | Multiplies signed 16.16 by 16.16 and returns 16.16 result.
_CALDLG.H | Dialog header file for PENCAL.DLL


Reference

The two data structures used by the pen calibration application are _HARDWAREINFO and DRV_CALBSTRUCT. The DRV_CALBSTRUCT structure is contained in the _HARDWAREINFO structure. For a definition of the members of these two structures, see the "Reference" section in About the Pen Driver.


Printer Driver Overview

Microsoft simplifies the task of building a printer driver by providing, in the Windows® 95 DDK, a Universal Printer Driver (Unidriver). The Unidriver is capable of carrying out request (such as printing text, rendering bitmaps, or advancing a page) on most types of printers. This saves a printer driver developer from writing the code to carry out these requests. (This minidriver/Unidriver model is not new to Windows 95; it was also used in Windows 3.x.)

To build a driver for a particular printer, a developer builds a minidriver, which accepts requests from GDI and then, in most cases, passes the request to the Unidriver along with information that describes the capabilities, commands, and resident fonts of the particular printer. By building a minidriver that sends requests to the Unidriver, a driver developer who understands the hardware and command set for a printer can develop a driver with comparatively little effort.

To simplify the task of building a minidriver, a tool called Unitool is included in the Windows 95 DDK. You can develop a minidriver for your printer by running Unitool and responding to the user interface. For information about installing and running Unitool, see Installing the UniTool Application.

This section

  • Describes the methodology that can be used to develop most Windows 95 printer device drivers.
  • Summarizes what's new for printer drivers in Windows 95.
  • Describes the steps a printer vendor must take to insure their printer driver is compatible with Windows 95 and to get their driver included in the Microsoft Driver Library, which is distributed over various on-line services.


Creating a Printer Driver

Printer drivers are just one component of the Windows 95 printer subsystem. The architecture of the Windows 95 printer subsystem is best shown as a scenario in which each printer subsystem component contributes to moving a print job started by an application to a local printer or a network printer. Several such scenarios are presented in Typical Printing Process Scenario Using a Raw Spool File, Typical Printing Process Scenario Using an EMF Spool File, and Typical Printing Process Scenario Using an EMF Spool File.

As shown in the typical printing process scenarios, the primary function of a Windows 95 printer driver is to handle requests from GDI. In most cases, you will be able to write a printer mini driver, which is easier to do than writing a driver that contains all the code necessary to carry out all the GDI requests.

Microsoft provides in the Windows 95 DDK a printer driver called the Universal Printer Driver (Unidriver), which is capable of performing most GDI requests, such as printing text, rendering bitmaps, or advancing a page. Instead of developing code to support all the functions GDI supports, a printer vendor writes a mini driver that exports entry points that accept the GDI requests and then calls the Unidriver code to carry out the request. A mini driver also contains data that defines unique characteristics of the vendor's printer, which the Unidriver uses to adapt its actions to different printers.

For more information about writing a mini driver, see About Printer Minidrivers.

The Windows 95 Unidriver supports most types of printers and Microsoft provides generic printer drivers for the printer types not supported by the Unidriver. The types of printers not supported by the Unidriver are shown in the following table, along with the name of the Microsoft-provided printer driver that does support each of these printer types.

Printer Type | Approximate Number of Printer Models of That Type | File Name of Microsoft-Provided Drivers
Color Deskjets | A handful. | DESKJETC.DRV
Plotters | A dozen or so. | HPPLOT.DRV
PostScript | Numerous | PSCRIPT.DRV

If your color desk jet, plotter, and/or Postscript printer is compatible with the Microsoft-provided driver, then you will not have to write a printer driver because you can install the Microsoft-provided driver to support your color desk jet printer, plotter or PostScript printer.

If you are developing an advanced, next-generation printer, which is incompatible with the Windows 95 Unidriver or PSCRIPT.DRV, DESKJETC.DRV, or HPPLOT.DRV, then you will have to create a printer driver that fully implements all of the functions required by GDI. Documentation for doing this will be provided on the MSDN CD-ROM after initial shipment of the Windows 95 DDK. Some guidelines for developing a complete printer driver (instead of developing a minidriver that works with the Windows 95 Unidriver) are given in What's New for Printer Drivers in Windows 95.


What's New for Printer Drivers in Windows 95

With few exceptions, any printer driver that ran under Windows 3.1 should be able to run under Windows 95 without modifications. Exceptions are printer drivers that go beyond supporting the standard DDI interface to deliver functionality beyond a straight translation of DDI calls to printer commands.

Major differences in Windows 95 printer support are in the areas of

  • User interface for installing, configuring, and controlling printers is different than Windows 3.1. For more information, see User Interface Changes.
  • The printer subsystem API has changed from Windows 3.1 and the printer subsystem spooling efficiency and flexibility have been improved. For more information, see Print Subsystem Changes.
  • Printer installation has changed significantly from the way it was handled in Windows 3.1. For more information, see Printer Installation Changes.
  • For color printers, Windows 95 supports matching colors from the screen with colors on the printed page; this is called image color matching. For more information, see Image Color Matching Support.

There are also a number of changes in the printer driver DDI from Windows 3.1. For example,

  • Some DDI support that was recommended under Windows 3.1 is required in Windows 95.
  • Changes have been made to the DDI under Windows 95 to expand functionality.

For more information about changes in the printer driver DDI, see Printer Driver DDI Changes.


User Interface Changes

At the user interface level, the Windows 3.1 Print Manager and Control Panel Printers applet no longer exist. A Printer icon in the Windows 95 Control Panel launches the Printers folder and all the user interface for installing, configuring, and controlling printers is in the Printers folder.


Print Subsystem Changes

Windows 95 has a new print subsystem which supports the same Win32® APIs as are documented in the Windows NT®/Windows® 2000 SDK and DDK, with the exception of forms support which is not in Windows 95.

The new print subsystem supports spooling enhanced metafiles (EMFs) which enables the print subsystem to return control to the application more quickly after the application spools a document. The new printer subsystem also supports other spooling formats for printer vendors who are willing to develop alternate subsystem components.

For detailed information about the new print subsystem features in Windows 95, see About the Print Spooler and the topics that are referred to there.


Printer Installation Changes

Installing printers by adding data to WIN.INI is no longer recommended.

Through its Plug and Play components, Windows 95 supports automatically identifying and installing printers that report device IDs as described in the IEEE 1284 specification, or prompting the user for an installation diskette if needed). Printer extensions have been added to the Windows 95 INF file format to promote Plug and Play printer installation. The OEMSETUP.INF format for printer driver installation used in Windows 3.1 is supported in Windows 95, but all vendors are encouraged to use the new Windows 95 INF file format and the new printer extensions.

Win32 API support for installing printers is part of Windows 95.

Printers can be installed over a network by using the Windows 95 Point and Print feature.

For detailed information about all of these Windows 95 printer installation changes, see About the Router and the Local Print Provider.


Image Color Matching Support

The image color matching APIs and functionality available in Windows 95 are described in the documentation Intercolor 3.0 Specification, available from Microsoft. Device drivers that support image color matching will be able to obtain screen to printer color matching.


Printer Driver DDI Changes

There is a required set of DDIs that a Windows 95 printer driver must support in order to function in the Windows 95 environment. For information about these DDIs, DDIs That Must Be Supported.

There is another set of DDIs that is required of a printer driver if it wants to take full advantage of the new Windows 95 capabilities. For information about these DDIs, DDIs That Expand Functionality.


DDIs That Must Be Supported

The DDIs that a Windows 95 printer driver must support, at a minimum, are listed in the following sections.

ExtTextOut DDI Must Be Supported

Under Windows 95, the StrBlt DDI is no longer supported. Printer drivers are required to support the ExtTextOut DDI instead.

Big Fonts Support Has Changed

Big fonts are fonts that require more than 64K of data to express. Under Windows 95, all printer drivers that need raster fonts from GDI must support big fonts and report this capability by setting the RC_BIGFONTS bit in GDIINFO.dpRaster.

Printer drivers can no longer use GDI to convert a big font into several smaller fonts as was possible under Windows 3.x.

Windows 3.x GDI Priority Queue Functions Must Be Supported Internally

The GDI functions CreatePQ, DeletePQ, InsertPQ, MinPQ, SizePQ, and ExtractPQ that were available under Windows 3.x do not exist in Windows 95. Under Windows 95, printer drivers must internally implement the all the functionality that orders device-specific fonts correctly on the page without calling these GDI functions.

ExtDeviceMode DDI Should Be Supported

Under Windows 95, the DeviceMode DDI will continue to be supported, but will be dropped in a future Windows release. For this reason, and because the ExtDeviceMode offers more capability, device drivers should support ExtDeviceMode. The benefits of implementing ExtDeviceMode are described in DDIs That Expand Functionality.

DeviceCapabilities Should Be Supported

Under Windows 95, the DeviceCapabilities DDI is not required, but will be in a future release of Windows. The benefits of implementing DeviceCapabilities are described in DDIs That Expand Functionality.

Drivers Must Not Communicate Directly with the Device

Under Windows 95, printer drivers must not use the OpenComm function to communicate directly with the device. Printer drivers should communicate with the device by calling the DDI exported by a port monitor instead. For a description of the relationship between Windows 95 printer drivers and port monitors, see About the Print Spooler. For detailed information about the DDI exported by a Windows 95 port monitor, see About Port Monitors.

Printer Escapes Should Be Supported

Printer escapes provide graphics support that is otherwise not available through GDI. Applications use printer escapes to perform device-dependent operations not supported by GDI. Applications call the ExtEscape or Escape functions to initiate an escape and GDI calls the printer driver's Control function to complete the escape. In some cases, GDI may also perform some work during ExtEscape or Escape calls.

Windows 95 printer drivers should support all escapes that are reasonable for a given device. All drivers must support the QUERYESCSUPPORT escape which reports the escapes the driver supports.

Note the only way to ensure your printer driver will support any Windows 3.x application is to support all the 60 or so escapes documented in the Windows 3.x SDK.

There have been changes to the way GDI handles printer escapes in Windows 95 and these are documented below. Despite these changes at the interface between applications and GDI, the only way to ensure your printer driver will support any Windows 3.x application is to support all the 60 or so escapes documented in the Windows 3.x SDK.

At the interface between applications and GDI, the following changes have taken place:

  • In Windows 95, many Windows 3.x printer escape functions are supported as Win32 APIs and application developers are encouraged to use those functions.
  • If an application uses an escape, the application code should use the ExtEscape function to call GDI instead of an Escape function.
  • From 32-bit applications, GDI will accept a limited number of escapes in an Escape function call:
    BEGIN_PATH
CLIP_TO_PATH
CLOSECHANNEL
DOWNLOADHEADER
DOWNLOADFACE
ENCAPSULATED_POSTSCRIPT
END_PATH
GETCOLORTABLE
GETDEVICEUNITS
GETPHYSPAGESIZE
GETPRINTINGOFFSET
GETSCALINGFACTOR
NEXTBAND
OPENCHANNEL
PASSTHROUGH
POSTSCRIPT_PASSTHROUGH
POSTSCRIPT_DATA
POSTSCRIPT_IGNORE
QUERYESCSUPPORT
QUERYDIBSUPPORT
  • From 16-bit applications, GDI will accept the following escapes in an Escape function call:
    ABORTDOC
ENDDOC
NEWFRAME
SETABORTPROC
SETCOPYCOUNT
STARTDOC


DDIs That Expand Functionality

A printer driver that exploits all the Windows 95 functionality meet the requirements described in the following sections. These requirements are listed below in order of importance:

  • Expanded DEVMODE structure should be supported.
  • DrvGetPrinterData and DrvSetPrinterData calls should be used in a recommended way.
  • Modified ExtTextOut DDI should be supported.
  • New ExtDeviceModePropSheet DDI should be supported.
  • DeviceCapabilities DDI should be supported.
  • Enhanced Metafile (EMF) spooling should be supported.
  • New services are available from the Windows 95 DIB Engine component.
  • New Bezier curve Output DDI style should be supported.

Expanded DEVMODE Structure Should Be Supported

If your printer driver expects Windows 95 to provide Image Color Matching for a color printer, then the driver must support the new DEVMODE structure.

Other benefits that any printer driver gains by supporting the new DEVMODE structure are:

  • The driver is aware of friendly printer names.
  • The driver can structure its private portion of DEVMODE to separate the document-specific and printer-specific portions so only the portions of DEVMODE relevant to formatting documents will be passed to Win32 applications.

Any driver that supports the new Windows 95 DEVMODE structure and reports DEVMODE.dmSpecVersion = 0x0400 must support the new DrvSetPrinterData and DrvGetPrinterData DDIs, which are described below.

New DrvSetPrinterData and DrvGetPrinterData Functions Are Available

The new DrvSetPrinterData DDI enables 16-bit printer drivers to store DEVMODE structure data in the registry, where it is easy for 32-bit system component to access. If a printer driver caches DEVMODE data by calling DrvSetPrinterData, then Windows 95 print subsystem components can return DEVMODE data to Win32 APIs without having to call the device driver to get the data.

The DrvGetPrinterData DDI retrieves the DEVMODE data from the registry.

Note that any driver that supports the new Windows 95 DEVMODE structure and reports DEVMODE.dmSpecVersion = 0x0400 must also support the new DrvSetPrinterData and DrvGetPrinterData DDIs.

New ExtTextOut DDI Should Be Supported

Windows 95, unlike Windows 3.x, supports TrueType fonts that contain more than 256 characters. Windows 95 enumerates multiple character sets from a single TrueType font to applications. Windows 95 does this based on the contents of an individual TrueType font that has been installed.

In order to render these fonts on output devices, a printer device driver must report the capability to understand and support TrueType glyph indices, which are two-byte values, in addition to Windows ANSI characters, which are one-byte values. Device drivers which understand and support TrueType glyph indices will be able to automatically support TrueType fonts with multiple character sets, without having special knowledge of each of these character sets. This is a key requirement in products distributed in Europe and East Asia, where multi-lingual character issues are common.

New ExtDeviceModePropSheet DDI Should Be Supported

Windows 95 provides a new Property Sheet dialog box style for controlling the attributes of many system objects, including printers.

(To look at the property sheets for an installed printer in the Windows 95 user interface, do the following: Click the Start button; select Settings; select Printers; right-click on the installed printer icon; and then select Properties.)

Printer property sheets are used for configuring attributes of printer objects managed by the print subsystem (attributes such as spool settings, port settings, and peer-to-peer sharing). A print driver that supports the ExtDeviceModePropSheet DDI can provide additional property sheets displayed at the same level and will visually appear as better integrated into the system.

Drivers that do not support the ExtDeviceModePropSheet DDI have to support the Windows 3.x ExtDeviceMode DDI and the user will access the driver-controlled settings by pressing a button on one of the system-supplied property sheets.

DeviceCapabilities DDI Should Be Supported

For more information about the DeviceCapabilities function, see the Windows® 3.1 DDK.

Enhanced Metafile (EMF) Spooling Should Be Supported

For information about the benefits of using EMF spooling as well as implementation details, see About the Print Spooler.

New Windows 95 DIB Engine Component Services May Be Used

Printer drivers can use the services offered by the DIB Engine, which is a new Windows 95 component, to operate on DIB files. This saves writing and testing code in the device driver to perform these operations.

For more information about the services offered by the DIB engine, see About Display Minidrivers.

New Output DDI Style for Bezier Curves Can Be Supported

Printer drivers for devices that draw Bezier curves and that support the new Bezier curve style as part of their Output DDI will enable GDI to call the driver to render a Bezier curve with one call instead of a series of Output calls with the OS_POLYLINE flag set in the wStyle parameter.

Drivers that support the OS_POLYBEZIER flag in the Output DDI wStyle parameter must report this capability by setting the CC_POLYBEZIER bit in GDIINFO.dpCurves.


Printer Minidrivers

A printer minidriver is an executable file that provides device-driver support for a particular type or class of printer. It contains data that describes the capabilities, commands, and resident fonts of the printer. A printer minidriver also includes a set of required entry points that the Microsoft Windows® graphic device interface GDI calls to retrieve information about the printer and to send information to the printer.

Although it contains the required entry points, a minidriver does not actually carry out the actions requested by GDI. Instead, the minidriver calls the Universal Printer Driver (Unidriver), providing the information that the Unidriver needs to carry out the requested actions on the device (such as printing text, rendering bitmaps, or advancing a page).

The Unidriver greatly simplifies the task of developing a Windows printer driver. Instead of developing code to support all of the functions that GDI requires, a driver developer need only create a minidriver that provides the information about the printer. By using the Unidriver, a driver developer who understands the hardware and command set for a printer can develop a driver with comparatively little effort.

Note The Windows 95 Unidriver does not support color Desk jet printers, plotters, Adobe PostScript® printers, and printers that use printer-control languages which are similar to PostScript. For these devices, a vendor may use the Microsoft-provided drivers (see About Windows 95 Printer Drivers for a list of the names of these drivers). You may need to create a Windows printer driver that fully implements all of the functions required by GDI for these three types of printers, see About Windows 95 Printer Drivers for more information.


UniTool Application

A minidriver contains a collection of data structures that are referred to as the printer's data table. A data table contains data such as the printer's resolution, color capabilities, metrics for device fonts, and so on. A data table also contains the strings that correspond to various printer commands.

A developer creates a minidriver by using the UniTool application (UNITOOL.EXE), which provides an organized means of entering printer data and command strings that become part of a minidriver's data table. Using this application, its menus, and its dialog boxes, a driver developer specifies data such as the supported text resolutions, graphics resolutions, paper sizes, font metrics, and so on. In addition, a developer specifies the printer commands that begin a document, end a document, select a paper size, select a paper source, reset the printer to its default state, and so on. A developer can also use UniTool to create device-font files and character-translation tables.

The UniTool help file, UNITOOL.HLP, contains the documentation for the UniTool application. It is a Windows Help file that describes each of dialog boxes and control windows in the UniTool application, and provides examples based on the development of minidrivers for the Kodak Diconix 150 Plus, the Hewlett-Packard PaintJet, and the Hewlett-Packard LaserJet IIP printers. The Kodak Diconix printer is an ink-jet printer that uses a command set similar to that of Epson and IBM dot-matrix printers.. The HP PaintJet printer is a color ink-jet printer. The HP LaserJet IIP printer is a laser printer that uses the Hewlett-Packard printer-control language (PCL). Most of the examples in the help file are based on the Kodak Diconix minidriver and the HP LaserJet printers; however, the examples in the topics that describe color support are based solely on the HP PaintJet.


Minidriver Data Table

Most of the structures in the printer's data table correspond to one or more of the dialog boxes that appear in the UniTool application. By setting the controls in the dialog boxes, you actually initialize the members of these structures. The driver data table consists of the following data structures:

Structure | Description
BRUSHINFO | Describes a collection of creation and selection commands for brushes and fills.
CAROUSEL | Describes the characteristics of a carousel on a plotter.
COMPRESSMODE | Identifies a data-compression mode and specifies the printer-command strings that select this mode. This structure also contains the printer-command strings that select the specified compression mode.
CURSORMOVE | Specifies the limitations of the printer's cursor-movement commands. This structure also contains the command strings that move the printer's cursor.
DEVCOLOR | Specifies the printer's color capabilities. This structure also contains the command strings that enable color output.
DOWNLOADINFO | Specifies the printer-command strings that download fonts.
FONTCART | Identifies a font cartridge. This structure also contains the printer-command strings that select the specified cartridge and identifies the fonts on that cartridge.
FONTSIMULATION | Specifies the printer-command strings that enable and disable bold, italic, underline, and strike through font simulations.
LINEINFO | Describes a collection of creation and selection commands for lines.
MODELDATA | Specifies the characteristics of a single printer model. (A single minidriver may support several models of a manufacturer's printer.)
PAGECONTROL | Specifies the printer-command strings that initialize the printer, select the paper orientation, and so on.
PAPERDEST | Identifies a paper output bin that collects pages. This structure also contains the printer command strings that select the specified bin.
PAPERQUALITY | Specifies a media type (that is, plain paper, coated paper, or transparency) on which the printer is capable of printing. This structure also contains the printer-command strings that configure the printer for printing on a particular medium.
PAPERSIZE | Specifies the dimensions of a piece of paper on which the printer is capable of printing. This structure also contains the printer-command strings that configure the printer for the specified paper size.
PAPERSOURCE | Identifies a paper bin or feeding mechanism. This structure also contains the printer-command strings that select the specified paper bin or feeding mechanism.
PENINFO | Describes the characteristics of an available pen.
POLYVECTOUTPUT | Describes a set of graphic output drawing commands and ordering information for them.
RECTFILL | Specifies the printer's rectangle-fill capabilities. This structure also contains the command strings that fill rectangular regions.
RESOLUTION | Specifies a horizontal and vertical raster-graphics resolution that the printer supports. This structure also contains the printer-command strings that select the specified resolution.
TEXTQUALITY | Identifies a text quality that the printer supports (that is, draft, near letter, or letter). This structure also contains the printer-command strings that select the specified text quality.
VECTOUTPUT | Describes a set of graphic output drawing commands and ordering information for them.
VECTPAGE | Describes information about the vector page and vector capabilities of the printer.
VECTSUPPORT | Describes a set of graphic output support drawing commands.


Minidriver Resources

The minidriver contains four types of resources:

  • Printer-data resources
  • Font-data resources
  • CTT-data resources
  • String-table resources

The first three resource types correspond to the Printer Data, Fonts, and CTT command that appear in the UniTool application's main menu - when you enter values or printer commands in one of the application's dialog boxes, you're actually initializing or altering the data in one of these resources. The fourth resource type, string-table, contains strings that were specified in a number of the dialog boxes.

Note These resources are interrelated - when you alter one resource, it is likely that you will also need to alter another. For example, when you create a new font file using the Fonts menu and associated dialog boxes, you will also need to identify that font in the Model Data dialog box to indicate that it is supported by the model. From the Printer Data menu, choose the ModelData command to display the associated dialog box.


Predefined and Driver-Defined Values

A number of the UniTool dialog boxes specify predefined values that correspond to common paper sizes, paper qualities, paper sources, paper destinations, and text qualities. These same dialog boxes also provide a control in which you can type a driver-defined value; you should only specify a private driver-defined value if your printer does not support one of the predefined values. For example, there are five predefined text qualities:

  • Letter quality
  • Near letter-quality
  • Memo quality
  • Draft quality
  • Text quality

If the printer for which you are developing a minidriver supports a different text quality, you would type a string identifying that quality in the driver-defined control of the Text Qualities dialog box.

The predefined or driver-defined strings and values that you specify typically appear when you choose an application's Printer Setup command and Printer Setup Options dialog box.


Device Commands

The structures in the printer-data table contain device-command strings. There are three formats that you can use to type command strings in UniTool:

Format | Description
ASCII | Literal ASCII characters can be typed as part of a command string.
Formatted parameter | A formatted parameter is a parameter that is supplied by the Unidriver and sent to the printer in a format based on the specified conversion characters. These conversion characters are always preceded by the % character. The following contains the conversion characters that are supported by the Unidriver, as well as a brief description of each.

Character | Description
d | Unidriver converts the parameter to a decimal value. (For example, the value 12 is sent as '1' (31h) followed by '2' (32h).)
D | Unidriver converts the parameter to a signed decimal value. This is the same as the %d character except it is preceded by a sign.
c | Unidriver converts the parameter to a byte value. (For example, the value 12 is sent as FF (0Ch))
l | Unidriver converts the parameter to a 16-bit value with the Least Significant Byte (LSB) first. (For example, the value 12 is sent as FF (0Ch) followed by NULL (00h))
m | Unidriver converts the parameter to a 16-bit value with the Most Significant Byte (MSB) first. This is the same as %l except the order of the bytes is reversed.
q | Unidriver converts the parameter to a unique hexadecimal value formatted for Toshiba and Qume devices.

Hexadecimal Hexadecimal values are preceded by the following two characters: \x. For example, the hexadecimal value 0xFF is typed as \xFF in UniTool.

You type two different kinds of printer commands in UniTool. The first kind enables or disables certain features of the printer. For example, the command string ESCx3 enables letter-quality output of the Kodak Diconix 150 Plus printer. This command (ESCx3) is typed as \x1Bx\x03 in the Text Qualities dialog box. The string ESC was replaced by its ASCII representation (\x1B), the argument x was not altered, and the decimal value 3 was replaced by its hexadecimal equivalent (\x03). The second kind of command contains parameters supplied by the Unidriver at runtime (when the command is used). For example, the Immediate Line Feed command for the Diconix printer is used to advance the cursor in the positive y-direction with respect to the current cursor position. The command string for the Immediate Line Feed command has this syntax:

ESC J n

In this example, n is the number of 1/288th inch increments that the cursor will advance.


Master Units

Most printers support commands with a variety of resolutions. For example, the Immediate Line Feed command on the Kodak Diconix printer provides a resolution of 1/288th of an inch while the same printer supports vertical-graphics resolutions of 1/96th of an inch. To simplify the problem of handling various resolutions, the Unidriver uses a single, common coordinate system. The units in this coordinate system are called master units. Master units are the least common multiple of the various horizontal and vertical resolutions supported by the printer.

The Unidriver calculates the arguments for some printer commands by adding a value to the specified master units, multiplying the specified master units by a value, or dividing the specified master units by a value. For example, the vertical master unit for the Kodak Diconix printer is 1/576 of an inch; however, the printer's immediate line-feed command operates in 1/288 inch increments. When using this command, the Unidriver must convert the argument it supplies from vertical master units to the required units.

UniTool stores each printer command in a Command Descriptor (CD) data structure. In cases where the Unidriver needs to supply an argument to a particular command, such as the Immediate Line Feed command, UniTool stores additional data in an Extended Command-Descriptor (EXTCD) data structure. This data structure contains values by which the Unidriver should divide, multiply, increase, or limit command arguments. A special Units dialog box is provided for each printer command. In those cases where the Unidriver must convert master units, specify the appropriate values in the corresponding Units dialog box. In the case of the Immediate Line Feed command, master units must be divided by 2 prior to setting the parameter, therefore the sUnitDiv control contains the value 2.

The sMax control contains the value 255 (the maximum allowable value for this parameter) and the sMin control contains the value 1 (the minimum allowable value for this parameter).


Minidriver Callback Functions

A callback function is a developer-supplied function that executes in addition to or in place of one of the Microsoft-supplied Unidriver functions. A developer must provide a callback function whenever the Unidriver does not provide functionality that a printer requires.

For example, the Unidriver expects the topmost addressable pin on a 9-pin dot-matrix printer to correspond to bit-seven in a byte of graphics data, and the bottommost addressable pin to correspond to bit-zero. However, some printers (such as the older Okidata dot-matrix printers) reverse this ordering. To solve this problem, a developer must provide a callback function.

For a description of the callback functions, see the UNITOOL.HLP help file.


Minidriver Development

This section describes the hardware and software requirement for the UniTool application, and describes how to install and run the application. For more information about the dialog boxes and controls in the UniTool application, see the UniTool help file, UNITOOL.HLP.


Installing the UniTool Application

All the files needed to run the UniTool application are copied into the appropriate directories when you install the Windows 95 DDK.

The software components that are specific to UniTool are listed below, along with their directory location after the Windows 95 DDK is installed.

  • Include files PRINT.H and GDIDEFS.INC, which are on the path %DDKROOT%\INC16 after the Windows 95 DDK is installed. The system INCLUDE environment variable must identify the directory that contain these files; this can be done by running DDKENV.BAT with the appropriate parameters after the DDK is installed.
  • Include files MDEVICE.H, MINDRVRC.H, MINIDRIV.H, PFM.H, and UNIDRV.H, which are on the path %DDKROOT%\PRINTER\INC after the Windows 95 DDK is installed. The system INCLUDE environment variable must identify the directory that contains these files; this can be done by running the DDKENV.BAT file with the appropriate parameters.
  • The UniTool application (UNITOOL.EXE) and the UniTool help file (UNITOOL.HLP), which are on the path %DDKROOT%\PRINTER\BIN after the Windows 95 DDK is installed.
  • The UniTool setup information file (UNITOOL.INF), which is in %WINROOT% after the DDK is installed.
  • The Unitool configuration settings file (UNITOOL.INI), which is in %WINROOT% after the DDK is installed.
  • The minidriver source file (MINIDRIV.C), which is in %DDKROOT%\PRINTER\SAMPLES after the DDK is installed.
  • LIBINIT.ASM, which is in %DDKROOT%\PRINTER\SAMPLES after the DDK is installed.
  • The Windows 95 DDK environment batch file (DDKENV.BAT) which is in the directory %DDKROOT% after the Windows 95 DDK is installed. You can run this batch file with the parameters 16 and printer to establish the LIB and INCLUDE environment variable values you need to run UNITOOL.EXE.


Starting UniTool and Creating a Minidriver

Each time before you run the UniTool application, you must make sure the LIB and INCLUDE environment variables contain the values you need to run UniTool. You do this by clicking the Start button, selecting the Run option, and then entering the command

%DDKROOT%\DDKENV 16 PRINTER

where %DDKROOT% is the full path to the DDK root directory.

After you run the DDKENV batch file to establish the environment for creating 16-bit printer drivers, you can start the UniTool application by clicking the Windows 95 Start button and then selecting the Programs option, followed by the Windows 95 DDK option, followed by the Unitool option.

(You can also start UniTool by clicking the Start button, selecting the Run option, and entering the command

%DDKROOT%\PRINTER\BIN\UNITOOL

or using the Browse button to find UniTool.)

Once you have started UniTool, from the File menu, choose the New command. After you choose the New command, the Type of New File dialog box appears in the main window. Choose the MiniDriver button.

UniTool then displays a dialog box that prompts you for the name of your minidriver, the name of the directory in which it will be stored, and the name of the source minidriver. The Source Minidriver list box contains the names of several types of minidrivers. The selection you make depends on the type of printer for which you are developing a minidriver. If the printer's resolution and command set are compatible with that of a 9- or 24-pin Epson or IBM printer, choose the corresponding entry from the list box. Similarly, if the printer supports Hewlett Packard printers that use PCL, choose "HP PCL4 Minidriver" or "HP PCL5 Minidriver." However, if the printer's resolution or command set is unique and differs significantly from the available choices, choose "Generic Minidriver."

Once you have created your new minidriver directory and installed the appropriate files, you can begin initializing your minidriver's data table. If you've selected the Generic Minidriver as your starting point, or if your printer does not support the same resolutions as one of the compatible minidrivers, it will be necessary to specify master units. If, on the other hand, your printer uses the same resolutions as one of the source minidrivers, you can immediately begin specifying control information. For information on specifying master units and on specifying control information, see the UNITOOL.HLP help file.


Printer Drivers

Windows® 95 printer drivers manage all printer output for applications. For an overview of Windows 95 printer drivers, see About Windows 95 Printer Drivers .

Note You should develop a Windows printer driver only if the Unidriver does not support your printing device. If the Unidriver does support your device, you should use the UniTool application to develop a printer minidriver. For more information about the Unidriver, the UniTool application, and printer minidrivers, see About Printer Minidrivers.

If you are developing an advanced, next-generation printer, which is incompatible with the Windows 95 Unidriver or PSCRIPT.DRV, DESKJETC.DRV, or HPPLOT.DRV, then you will have to create a printer driver that fully implements all of the functions required by GDI. Documentation for doing this will be provided on the MSDN CD-ROM after initial shipment of the Windows 95 DDK. Some guidelines for developing a complete printer driver (instead of developing a minidriver that works with the Windows 95 Unidriver) are given in About Windows 95 Printer Drivers .

The printer driver functions and structures that are new for Windows 95, or are significantly modified, are listed in the table below.

Function or Structure | Description | Comment
DeviceCapabilties | Retrieves the capabilities of the printer device driver. | Windows 3.x drivers running under Windows 95 are strongly encouraged to export the DeviceCapabilities function. Printer drivers written to take advantage of the new Windows 95 printer support must export the DeviceCapabilities function. See the Windows 3.1 DDK "Device Driver Adaptation Guide" for a definition of the DeviceCapabilities function.
DEVMODE structure | Structure that contains information about the device initialization and environment of a printer. Applications pass this structure to ExtDeviceMode and DeviceCapabilities functions exported by a printer driver. | About a dozen new members have been added to the DEVMODE structure to support the new Windows 95 printer support. See New Function and Structure Reference for more information.
DrvGetPrinterData | Retrieves printer driver information from the registry. Typically used to initialize the DEVMODE structure. | See New Function and Structure Reference for more information.
DrvSetPrinterData | Stores data from the extended DEVMODE structure in the registry. | See New Function and Structure Reference for more information.
ExtDeviceMode | Retrieves or changes device-initialization information for a given driver, or displays a driver-supplied dialog box for configuring the driver. Applications call ExtDeviceMode when the user requests setting up the printer as part of preparing for a print job. | Windows 3.x drivers running under Windows 95 are strongly encouraged to export the ExtDeviceMode function. Printer drivers written to take advantage of the new Windows 95 printer support must export the ExtDeviceMode function.
ExtDeviceModePropSheet | Presents a property sheet to the user for controlling the attributes of a printer. | See New Function and Structure Reference for more information.
ExtTextOut | Writes text strings by converting characters in a given string into raster, vector, or outline glyphs and copies the glyphs to the given device or bit map. | For Windows 95, changes have been made to the 16-bit ExtTextOut function exported by GDI. These changes enable printer drivers to more easily support True Type fonts non-Windows ANSI character sets and True Type fonts using character sets with more than 256 characters.


New Function and Structure Reference

The printer driver functions and data structures that are new to Windows 95 or significantly modified in Windows 95 are included in this reference section.


DEVMODE

typedef struct _DEVMODE {
     char  dmDeviceName[CCHDEVICENAME];
    UINT  dmSpecVersion;
    UINT  dmDriverVersion;
    UINT  dmSize;
    UNIT  dmDriverExtra;
    DWORD dmFields;
    int   dmOrientation;
    int   dmPaperSize;
    int   dmPaperLength;
    int   dmPaperWidth;
    int   dmScale;
    int   dmCopies;
    int   dmDefaultSource;
    int   dmPrintQuality;
    int   dmColor;
    int   dmDuplex;
    int   dmYResolution;
    int   dmTTOption;
    int   dmCollate;
    TCHAR dmFormName[CCHFORMNAME];
    WORD  dmLogPixels;
    DWORD dmBitsPerPel;
    DWORD dmPelsWidth;
    DWORD dmPelsHeight;
    DWORD dmDisplayFlags;
    DWORD dmDisplayFrequency;
    DWORD dmICMMethod;
    DWORD dmICMIntent;
    DWORD dmMediaType;
    DWORD dmDitherType;
    DWORD dmReserved1;
    DWORD dmReserved2;
} DEVMODE;

Structure that contains information about the device initialization and environment of a printer. An application passes this structure to DeviceCapabilities and ExtDeviceMode functions exported by the driver. The DEVMODE structure is defined in PRINT.H.

DEVMODE members which are new to Windows 95 are defined below.

dmCollate Specifies whether collation should be used when printing multiple copies. This member can have one of the following values:

Value | Meaning
DMCOLLATE_TRUE | Collate when printing multiple copies.
DMCOLLATE_FALSE | Do not collate when making multiple copies.

Using DMCOLLATE_FALSE provides faster, more efficient output, since the data is sent to a page printer just once, no matter how many copies are required, and the printer is instructed to simply print the page again.

dmFormName | This member is unused for the first release of Windows 95.
dmLogPixels | Specifies the number of log pixels in the x direction. The value in this member should be equal to the value in the uLogPixels member of the GDIINFO structure.
dmBitsPerPel | Unused for printers. For display devices, specifies in bits per pixel the color resolution of the device.
dmPelsWidth | Unused for printers. For display devices, specifies the width, in pixels, of the visible device surface.
dmPelsHeight | Unused for printers. For display devices, specifies the height, in pixels, of the visible device surface.
dmDisplayFlags | Unused for printers. For display devices, specifies the display mode of the device.
dmDisplayFrequency | Unused for printers. For display devices, specifies the frequency of the device in particular modes.
dmICMMethod | Specifies which component, if any, will create the ICM color dictionaries. This member can have one of the following values:

Value | Meaning
DMICMMETHOD_SYSTEM | The Windows 95 System ICM library performs color matching.
DMICMMETHOD_NONE | ICM is disabled.
DMICMMETHOD_DRIVER | The driver performs color matching.
DMICMMETHOD_DEVICE | The device performs color matching.

The printer driver must provide a user interface for setting the dmICMMethod member of the DEVMODE structure. Most printer drivers support only the DMICMMETHOD_SYSTEM or DMICMMETHOD_NONE methods, although drivers for PostScript printers support all values.

dmICMIntent Specifies the ICM setting to be used for a particular document. This information is used to select specific color-matching algorithms. This member can have one of the following values:

Value | Meaning
DMICM_SATURATE | Optimizes for color saturation. Generally used for high-contrast presentation graphics when dithering is not desired.
DMICM_CONTRAST | Optimizes for color contrast. Generally used for photographic images when dithering is desired.
DMICM_COLORMETRIC | Optimizes to match an exact given color. Used when a particular color must be respected.

The dmICMIntent member of the DEVMODE structure is used primarily by applications that do not support ICM. ICM-capable functions can establish color-matching algorithms by using the ICM functions.

dmMediaType Specifies the type of media being printed on. The ICM library uses this information to compensate for different absorption of varying media. This member can have one of the following values:

Value | Meaning
DMICM_STANDARD | Plain paper.
DMICM_TRANSPARENCY | Transparencies.
DMICM_GLOSSY | Glossy paper.

A driver can define values for this member that are greater than the value DMMEDIA_USER.

dmDitherType Specifies the dither brush to be used for a particular document. The choice of brush will generally affect the available colors for the device. This member can have one of the following predefined values, or a driver can define a value for this member that is greater than DMDITHER_USER.

Value | Meaning
DMDITHER_NONE | Colors will not be dithered.
DMDITHER_COARSE | Dither with a coarse brush. Perform ordered, or halftone, dithering. Suitable for scanned photographs or other images that have continuous gradations in intensity and hue.
DMDITHER_FINE | Dither with a fine brush. Perform ordered, or halftone, dithering. Suitable for scanned photographs or other images that have continuous gradations in intensity and hue.
DMDITHER_LINEART | Line art dithering, which produces well-defined borders between black, white, and gray scalings. Not suitable for scanned photographs or other images that have continuous gradations in intensity and hue.
DMDITHER_ERRORDIFFUSION | Error diffusion dithering. Can preserve more detail of an image that has continuous gradations in intensity and hue than ordered, or halftone, dithering does.
DMDITHER_GRAYSCALE | Device does gray scaling.

dmReserved1 | Not used; must be zero.
dmReserved2 | Not used; must be zero.

Printer drivers that support the new members in the DEVMODE structure must set DEVMODE.dmSpecVersion to 0x0400. If a driver sets DEVMODE.dmSpecVersion to this value, the driver must also meet the following requirements:

  • The driver must always return 0x0400 to a DeviceCapabilities function call that uses a DC_VERSION argument.
  • The driver must use the new DEVMODE structure definition, even if it does not use any of the new members (it should initialize them to zero).
  • The driver must use DrvSetPrinterData to store printer driver settings and use DrvGetPrinterData to retrieve them.
  • The driver must be able to handle friendly user-defined printer names, which can be any string up to 32 characters in length (including the terminating NULL character). When an application passes the driver a friendly printer name, the driver must query the registry to determine what the corresponding printer model name is. The driver can use the DrvGetPrinterData function to do this.
  • If the DEVMODE data retrieved from the registry is incorrect, the driver must build a default DEVMODE and merge as many member values as possible, and then update the registry. Win32 applications can use the DEVMODE structure, so the driver must update DEVMODE.dmDeviceName with the current friendly printer name.
  • Private DEVMODE data must contain the printer model name or some way of determining the current printer model name.
  • The driver does not have to contain code that writes settings to INI files since these settings are now maintained on the registry. The driver may have to contain code that reads INI files.

In addition to the requirements listed above, there are two other more detailed requirements which are described below:

  • The driver must handle brushes differently than in Windows 3.x.
  • The driver must organize the private members of the DEVMODE structure into two groups: printer-sticky members and document-sticky members.


Differences in Handling Brushes

The driver must deal with brushes differently than in Windows 3.x. After an Enable function call, GDI calls the driver RealizeObject function twice with an OBJ_BRUSH argument: the first time to get size information and the second time to realize the brush. Under Windows 3.x the driver returned only a TRUE or FALSE value on the second call. Under Windows 95, upon success, the driver must return a WORD with two or more of the following bits set:

Bit Setting | Description
PBF_SOLIDCLRBRUSH | A solid (not dithered) brush was realized.
PBF_SOLIDMONOBRUSH | A monochrome (not colored) brush was realized.
PBF_SUCCESS | Brush successfully realized.

For example, if a solid white brush was realized, for a monochrome DC the driver must return PBF_SUCCESS+PBF_SOLIDMONOBRUSH. For a color DC the driver must return PBF_SUCCESS+PBF_SOLIDCLRBRUSH. This is because a solid white brush is not dithered in either monochrome or color.

If, for example, a solid red brush was realized, for a monochrome DC the driver must return PBF_SUCCESS. This is because a red brush is dithered in monochrome. For a color DC, when a solid red brush is realized, the driver must return SUCCESS+PBF_SOLIDCLR.

Note that if the driver fails to realize the brush, it should still return FALSE.


Organizing and Grouping Private DEVMODE Members

Conceptually, a DEVMODE structure for a printer device has always followed the model of a public block of data, used by both the application and the driver, and a private block of data used only by the driver. The public portion of DEVMODE has been extended in Windows 95 to contain more information useful to the application, driver, and other system components such as the Image Color Mapper (ICM). These extensions (new structure members) are defined above.

This topic concentrates on how a driver writer should structure the private portion of the DEVMODE structure used by his or her driver. Organization of the private block of DEVMODE data is determined by the "stickiness" of members in the private data block. Stickiness in general refers to how much document formatting information can be retained when a document is printed on a different model printer than it was originally formatted for, or is printed after the printer the document was originally formatted for is physically changed (for example, an optional paper source is added or removed).

Each property represented by a member in the private portion of DEVMODE has one of two types of stickiness:

  • Document-sticky properties settings can be controlled by software. Paper size, paper orientation, and margin sizes are all examples of document-sticky properties. Document-sticky properties are set with AdvancedSetUpDialog, ExtDeviceMode, and ExtDeviceModePropSheet function calls.
  • Printer-sticky properties cannot be controlled by software. These properties can be changed only by physically changing the printer. Currently installed memory size, optional paper sources, and font cartridges are all printer-sticky properties. DEVMODE members that represent printer-sticky properties are configurable only by the ExtDeviceModePropSheet function.

Note that document-sticky property settings can be affected by changes in document-sticky property settings. The printer driver user interface must warn the user and give him or her a chance to change document-sticky properties when a printer-sticky property setting changes.

Looking at the organization of DEVMODE, all the properties represented in the public block are document-sticky. For Windows 95 printer drivers, the properties represented in the private block are a mixture of document-sticky and printer-sticky. In the private DEVMODE block, all the members representing document-sticky properties should come first, followed by all the members representing printer-sticky properties.

Many Windows 3.x printer driver designs make no attempt to segregate document-sticky and printer-sticky properties. As a result, applications that cache the DEVMODE structure as part of the document end up carrying information that the driver cannot rely on the next time the document is loaded. Drivers must ignore printer-sticky information stored with the document.

Organizing the private block if the DEVMODE structure into a layer of all document-sticky properties followed by a layer of all the printer-sticky properties gets around this problem. By setting the DEVMODE.dmDriverExtra member value to the size of the document-sticky layer, the driver can insure that applications access only document-sticky properties. The size of the DEVMODE structure used by the DrvGetPrinterData and DrvSetPrinterData functions the driver uses is the entire DEVMODE structure.

DrvGetPrinterData
    DWORD DrvGetPrinterData(LPSTR lpPrinter, LPSTR lpProfile,
    DWORD lpType, LPBYTE lpPrinterData, DWORD cbData,
    LPDWORD lpNeeded)

Retrieves printer driver information from the registry. Typically used to initialize the DEVMODE structure.

  • Returns ERROR_SUCCESS, if successful; otherwise, returns one of the following error codes: ERROR_INVALID_PARAMETER or ERROR_INVALID_DATA (for the meaning of these error codes, see the winerror.h documentation).
lpPrinter | Friendly name that identifies the printer device.
lpProfile | Name of profile from which to retrieve data. Note that setting this parameter to INT_PD_PRINTER_DEVMODE (which is defined in PRINT.H), the default DEVMODE is used. Private profile data can be used by passing the lpProfile parameter from ExtDeviceMode (it is non-NULL) as this parameter.
lpType | Type of data being retrieved. Use REG_BINARY for binary data (see the Win32 SDK for other registry data type descriptions).
lpPrinterData | Far pointer to location at which retrieved data should be written.
cbSize | Buffer size at the location pointed to by the lpPrinterData parameter.
lpNeeded | Size of buffer needed for original profile data.

Printer drivers are strongly encouraged to use DevSetPrinterData to store all printer driver settings in the registry and to avoid using INI files wherever possible. The DevGetPrinterData can be used to retrieve the settings.

If the data has the REG_SZ, REG_MULTI_SZ, or REG_EXPAND_SZ types, then the lpPrinterData and dwSize parameter byte counts must include one for the terminating NULL character.


DrvSetPrinterData

DWORD DrvSetPrinterData(LPSTR lpPrinter, LPSTR lpProfile,
    DWORD lpType, LPBYTE lpPrinterData, DWORD dwSize)

Enables a printer driver to store data in the registry. The data can be stored under a unique key to be retrieved later. Typically used to store data from the extended DEVMODE structure in the registry.

  • Returns ERROR_SUCCESS, if successful; otherwise, returns one of the following error codes: ERROR_INVALID_PARAMETER, ERROR_INVALID_PRINTER_NAME, ERROR_MORE_DATA, or ERROR_INVALID_DATA (for the meaning of these error codes, see the winerror.h documentation).
lpPrinter | Friendly name that identifies the printer device.
lpProfile | Name of profile under which to save data. Note that setting this parameter to INT_PD_DEFAULT_DEVMODE (which is defined in PRINT.H), the default DEVMODE is used. Private profile data can be used by passing the lpProfile parameter from ExtDeviceMode (it is non-NULL) as this parameter.
lpType | Type of data being stored. Use REG_BINARY for binary data (see the Win32 SDK for other registry data type descriptions).
lpPrinterData | Far pointer to location of data to be saved.
dwSize | Buffer size at the location pointed to by the lpPrinterData parameter.

Printer drivers are strongly encouraged to use this functionality to store all printer driver settings and to avoid using INI files wherever possible.

Printer drivers may obtain the model name of the device, typically required by the device driver, by calling the DrvGetPrinterData function with the lpProfile parameter set to INT_PD_DEFAULT_MODEL.

If the data has the REG_SZ, REG_MULTI_SZ, or REG_EXPAND_SZ types, then the size of the data returned to the location pointed to by the lpPrinterData parameter will include the terminating NULL character.


ExtDeviceModePropSheet

int ExtDeviceModePropSheet(HWND hWnd, HINSTANCE hinstDriver,
    LPCSTR lpszDevice, LPCSTR lpszPort, DWORD dwReserved,
    LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam)

Presents a property sheet to the user for controlling the attributes of a printer.

  • Returns IDOK or IDCANCEL if successful; otherwise, returns -1.
hWnd | Parent window for the dialog box.
hinstDriver | Module instance of the device driver.
lpszDevice | Points to a null-terminated string that contains the friendly name of the printer.
lpszPort | Points to a null-terminated string that contains the name of the port to which the printer is connected, such as LPT1.
dwReserved | Unused; set to zero.
lpfnAddPage | See the definition of the ExtDeviceMode function. The printer driver enumerates property pages back to the caller using the lpfnAddPage and lParam parameters. The function specified by lpfnAddPage is called by the driver to enumerate each HPROPSHEETPAGE.
lParam | See the definition of the ExtDeviceMode function. The value of this parameter is passed back to the function specified by the lpfnAddPage parameter.

In order to support the new property sheet dialog boxes, printer drivers must fully support the new DEVMODE structure as well as this ExtDeviceModePropSheet DDI. For the basic information about property sheet management and manipulation, see the Win32 SDK documentation. The basic property sheet definitions can be found in PRSHT.H in %SDKROOT%\INC16 after the Win32 SDK is installed. The ExtDeviceModePropSheet definitions can be found in PRINT.H in %SDKROOT%\INC16.

When a printer driver receives an ExtDeviceModePropSheet call, it must build each of the property sheet dialogs it provides. The driver calls lpfnAddPage once for each property sheet it provides and should return from the ExtDeviceModePropSheet call only after all the property sheets have been added by calls to lpfnAddPage.

Note that since creating property sheets is an asynchronous process, the driver ExtDeviceModePropSheet function will return before the dialogs are actually created. Therefore, any data that is used to process the dialogs or update the system after the dialogs close must be dynamically allocated and a pointer to the structure passed in the PropSheetPage.lParam field. This data will then be accessible in the WM_INITDIALOG message and should be associated with that window. The simplest way to do this is to use

SetWindowLong(hWnd,DLG_USER,lpMyData)

A printer driver must assume that pointers passed to the ExtDeviceModePropSheet function will be invalid until the property sheet pages are actually created, so any data passed as parameters must be stored in the dynamically allocated structure.

The driver should use a release function to correctly terminate the property sheets (see the Win32 SDK documentation for more information about this). Terminating a property sheet also involves updating the default DEVMODE structure, sending a WM_DEVMODECHANGE message, freeing the allocated data structure, etc.


Print Spooler

The Windows 95 spooler is the component of the Windows 95 printer subsystem that enables print jobs to be routed to local and network printers. The spooler itself has numerous components, so it is also referred to as the printer system. Some of the printer system components can be written or modified by printer vendors (IHVs) and some are provided by Microsoft in binary form.


Printer System Components

The print spooler accepts a data stream prepared by GDI and/or a printer driver for output on a particular type of printer.

The spooler has two main functions:

  • To deliver data to printers for printing, either directly or by playing back spooled files. The spooler manages the events and format conversions that result in the data being output on an application-designated printer.
  • To manage a dynamic environment made up of printers, printer drivers, print providers, monitors, ports, and print jobs. The spooler maintains Registry information from which it can derive how many of these components are in the printer subsystem at any time and the unique name of each component. The spooler also keeps track of the current status of each component.


Spooler Components and IHV Development Opportunities

The components of the Windows 95 spooler are:

  • The Print Request Router (PRR)
  • The local print provider.
  • Network print providers.
  • Print processors.
  • Port monitors.
  • Print job language monitors for bidirectional printers.

Microsoft provides executables for the router and local print provider which a printer manufacturer cannot replace. For the other four spooler components, Microsoft provides default executables, but printer manufacturers may need to develop another version of one or more of these components to meet special needs.

The primary function of each spooler component is described in the following table, along with a general description of the printer vendor's development responsibilities for each component:

Component/Description | Development Requirement for Printer Manufacturer
Print Request Router (PRR): Routes a data stream to the local print provider or to a network print provider. | None. Microsoft provides the executable PRR and documents the functions it exports. The PRR cannot be replaced by an IHV.
Local print provider: Puts print jobs into spool files, manages despooling, and performs administrative tasks. In short, the local print provider is in charge of all local playback of spooled print jobs. | None. Microsoft provides the local print provider executable and documents the functions it exports. The local print provider cannot be replaced by an IHV.
Network print providers: Manage communication between a network and the Win32 printing API. A network print provider is basically a translation layer that converts print requests from the generic Win32 format to a vendor-specific form that can be used by the network. | Printer IHVs typically do not need to develop a network print provider. Network IHVs must develop a network print provider. Microsoft does not provide sample code for a network print provider in the Windows 95 DDK. For guidelines on how to develop a network print provider, see About Net Print Providers.
Print processors: Perform despooling (the conversion of spooled device-independent records into device-specific records). | Print processors and printer drivers work together. Microsoft provides a print processor executable that is the default, "WinPrint," and which handles two spool file formats: raw and EMF. Printer vendors may wish to develop another print processor if the vendor supports a spool file format different than the formats supported by the Microsoft-provided print processor. IHVs may also want to develop a print processor that provides filter functions.
Port monitors: Control the I/O port a physical printer is connected to. Typically communicates with VCOMM for device I/O, but may also call different interfaces such as Windows Sockets, SCSI, etc.). | None for printers that use parallel or serial ports because Microsoft supplies a port monitor that communicates with VCOMM to enable multiple monitors to share a device. IHVs with printers that connect to other types of ports (such as SCSI or Ethernet LAN cards) will have to develop a port monitor.
Language monitors: Control a bidirectional physical printer. Each language monitor is printer description language-specific. Communicates special printer events to the print provider beyond what parallel port status codes return. | If the printer manufacturer's device is bidirectional, the vendor may develop a language monitor for their printer. Microsoft provides sample source code for a PJL language monitor as a starting point. Note that a language monitor is not typically required for nonbidirectional devices.


Typical Printing Process Scenario Using a Raw Spool File

This section illustrates the major relationships between the spooler components during the printing process by walking through the sequence of calls between components during the spooling of a raw format spool file and subsequent playback (despooling) of the file to a bidirectional printer.

The following illustration shows the sequence of calls that start with an application initiating a print request by calling GDI (labeled step 1 in the illustration) and end with the local print provider writing a spool file to the disk (step 8) and starting a background thread that will eventually initiate the despooling process (step 9). The sequence of steps in the despooling process are shown in a separate illustration.

As illustrated above, a typical printing process scenario using a raw spool file would be executed as follows

  1. The application creates a DC and draws an object to the DC, for example a circle, and then calls GDI with a print request to a particular printer using that DC.
  2. GDI calls the printer driver with a request for instructions on how to render the circle on that particular printer.
  3. The printer driver returns the instructions on how to render the circle on the printer the driver is associated with. Note that all Windows 95 printer drivers are 16-bit code and communicate with 16-bit GDI.
  4. GDI passes the print request to 32-bit GDI because the Windows 95 spooler process is 32-bit code.
  5. GDI32 makes an interprocess call to the spooler process.
  6. SPOOL32.EXE calls the router to route the print job to the printer specified by the application. In this example, the router sends the print job to the local print provider. Note that the router could send the job to a printer on the network through the network print provider (which is not shown in the illustration). The default Windows 95 spooler spools the network jobs locally, so they show up on the local spooler queue, even those jobs bound for a Windows NT/Windows 2000 servers. A network print job is spooled and despooled on the client machine, not the server. It is only in the relatively late step of despooling that the remote print server is actually contacted. The way Windows 95 handles network print jobs contrasts with the way they are handled by Windows NT/Windows 2000 client machines, which use RPC to call the necessary printing APIs on the print server. This way, the print job never shows up on the local spooler queue and the spooling and despooling is handled by the print spooler on the print server. On Windows 95 RPC is not used by the default print spooler. A print spooler that does use RPC is available as an option for Windows 95 client machines.
  7. The router calls the local print provider with the print job.
  8. If the type of print job is not direct, the local print provider spools the print job to the disk as a raw-format spool file. Note that steps 1 through 8 can be repeated many times to build a complete spool file. In step 8, the local print provider appends each piece of the print job to the spool file until the application signals that the job is complete by issuing an EndDoc function. The difference between a direct print job and a spooled print job to the local print provider is apparent in the next illustration which shows the playback of this spooled file. When the local print provider is called by the print processor (through the router) with this same print job, the job type is direct instead of spooled. That results in the job going to the printer instead of being rewritten as another spool file.
  9. The local print provider starts a background thread that will determine the best time to start playing back the spool file to the printer. The next illustration shows the sequence of steps involved in playing back the raw spool file.

The following illustration shows the sequence of calls that start with the background thread application initiating the playback of a spooled file by calling a print processor (labeled step 10 in the illustration) and end with the local port monitor sending the print job through a port it controls to a connected printer (step 14).

As illustrated above, the sequence of calls that start with the background thread application initiating the playback of a spooled file and ending with the local port monitor sending the print job is executed as follows

  10. The main thread determines a good time to initiate the playback of a spooled file, based on the changing state of spooler subsystem resources monitors. When it is a good time, the main thread uses a StartDoc function call to start a new thread in the print processor to playback the spooled file.
  11. Because it is a StartDoc case, the print processor thread invokes the local print provider with a ReadPrinter function call to read part of the spool file off the disk. (Note that in this example case of a raw spool file, the print processor does not call GDI32. In the EMF spool file case, which are played back by the default print processor supplied by Microsoft, the print processor calls GDI32 to playback the metafile.)
  12. Because it is a StartDoc case, the print processor thread invokes the language monitor (through the local print provider) with a WritePrinter function call to send the data through the physical port connected with the bidirectional printer originally specified in step 1 of this whole process. For a raw spool file, the default print processor simply passes the data through, without changing or interpreting any of the information. Note that a language monitor is invoked in this example scenario because the destination printer is a bidirectional printer. For nonbidirectional printers, a port monitor would be invoked instead of a language monitor. Note also that although this example scenario shows the language monitor and port monitor as separate components, they can be integrated into one monitor.
  13. The language monitor calls the port monitor to send the data to the printer.
  14. The port monitor sends the raw data through the physical port to the connected printer. Note that steps 11 through 14 are repeated until the end-of-file is reached on the spool file (or the print job is canceled). Then the playback thread is terminated.


Typical Printing Process Scenario Using an EMF Spool File

This section illustrates the major relationships between the print spooler components, the printer driver, and GDI during the printing process using an EMF spool file. The presented scenario walks through the sequence of calls between components during the spooling of an EMF spool file and subsequent playback (despooling) of the file on a bidirectional printer.

The spooling and despooling of a raw file is a simpler scenario to walk through than the spooling and despooling of an EMF file, so you may want to read the raw file spooling and despooling scenario before you read this one. The raw spool handling scenario is described in Typical Printing Process Scenario Using a Raw Spool File.

If the raw spool file scenario is simpler, you might ask the question, "Why would an application want to use EMF spool files instead of raw spool files?" A set of EMF files (each EMF file is a logical representation of a printed page) are

  • More portable than raw files -- the same EMF file can be printed on any number of printers whereas a particular raw spool file can only be printed to one printer model.
  • The set of EMF files that represent all the pages in a print job are typically smaller in size, all together, than a raw file that contains the same print job.

Note that an application may not want to request EMF spooling if it is sending a print job to a PostScript printer because a PostScript raw print job is already condensed compared to a raw print sent to a raster printer.

Also, an EMF file is not always smaller than the comparable raw print file. This may especially be true for pages that are heavily-laden with shaded graphics. An application may want to use EMF spool files even in this case, because the return of the print spooler subsystem to the application will still be quicker in the EMF spool file case than the raw spool file case.


Spooling EMF Files

The following illustration shows the sequence of calls that start with an application initiating an EMF spooling request by calling GDI (labeled step 1 in the illustration) and the local print provider writing a print job description file to the disk and calling spooler process with an EndPage or EndDoc function call which signals the availability of an EMF file to despool (these two steps are labeled 8 and 9 in the illustration).

Note one major difference between the EMF spooling scenario shown in the following illustration and the raw print file spooling scenario. In the raw spooling scenario, the local print provider writes the raw spool file to the disk; in the EMF spooling scenario, the GDI writes the EMF spool file to disk and in the EMF despooling scenario it is GDI that reads the EMF spool file and generates the file that is actually printed.

As illustrated above, the EMF files spooling process is executed as follows

  1. The application creates a printer DC and draws an object to the DC, for example a circle, and then calls GDI with an EMF spooling request for a particular printer.
  2. GDI queries the printer driver to find out if the driver supports EMF spooling.
  3. If the driver supports EMF spooling, GDI changes the printer DC to an EMF DC and writes the instructions for rendering the circle to the DC (to the EMF file).
  4. GDI passes the print request to 32-bit GDI because the Windows 95 spooler process is 32-bit code.
  5. GDI32 makes an interprocess call to the spooler subsystem with a description of the print job.
  6. SPOOL32.EXE calls the router to pass the print job description to the print provider that can reach the printer specified by the application. In this example, the router sends the print job to the local print provider but it could send the job to a printer on the network through a network print provider (which is not shown in this picture). Note that the router could send the job to a printer on the network through the network print provider (which is not shown in the illustration). The default Windows 95 spooler spools the network jobs locally, so they show up on the local spooler queue, even those jobs bound for a Windows NT/Windows 2000 servers. A network print job is spooled and despooled on the client machine, not the server. It is only in the relatively late step of despooling that the remote print server is actually contacted. The way Windows 95 handles network print jobs contrasts with the way they are handled by Windows NT/Windows 2000 client machines, which use RPC to call the necessary printing APIs on the print server. This way, the print job never shows up on the local spooler queue and the spooling and despooling is handled by the print spooler on the print server. On Windows 95 RPC is not used by the default print spooler. A print spooler that does use RPC is available as an option for Windows 95 client machines.
  7. The router calls the local print provider.
  8. The local print provider creates a job description file and adds a record to the job description file each time it is called for the job, until all the EMF page files have been spooled and each EMF file name and location is recorded in the job description file.
  9. When the local print provider records the information about the last EMF file in the job, it calls the spooler process with an EndDoc function call. This signals the spooler process that a complete job is spooled and ready for despooling. Note that for a multipage job, steps 1 through 8 are repeated once for every page in the job.


Despooling EMF Files

The following illustration shows the sequence of calls and events that start with the spooler process initiating an event that signals the port thread that a spooled job, made up of one or more EMF files, is available for despooling and printing. This step is labeled 10 in the following illustration and the final step, where the print job is sent through the hardware port to the printer is labeled 24.

As illustrated above, the EMF files despooling process is executed as follows

  10. At the end of the EMF file spooling scenario, the spooler process sets the ReadyToPrint attribute on the print job and initiates an event that signals to the port thread that a job is available for printing.
  11. The port thread of the spooler process responds to the event by determining the best time to start despooling process and then, at that time, loads the print processor .
  12. When the print processor determines that the spooled file(s) have an EMF format, it calls GDI32 with the new Windows 95 gdiPlaySpoolStream function call.
  13. The GDI32 gdiPlaySpoolStream function reads a record from the job description file , which provides the fully-qualified path to an EMF spool file. Note here that through the job description file, which is essentially a list of path names to EMF files (one path per print job page), GDI32 knows about all the pages in the print job.
  14. The GDI32 gdiPlaySpoolStream function calls GDI, using a thunk built into GDI32, with the path to the EMF spool file (the list of rendering instructions for a page of the print job) to render the page. GDI knows about only one page in the print job at any point in time -- the page that is being rendered and printed. Note that all the thunking necessary to go from the 32-bit programming environment to the 16-bit programming environment is handled by the Microsoft-provided GDI32 and GDI components, the 16-bit printer driver is isolated from calls to and from the 32-bit environment.
  15. GDI calls the printer driver associated with the printer the application wants to use and obtains a DC for the printer.
  16. GDI reads page-rendering instructions from the spooled EMF file and passes them one at a time to the printer driver, which uses as many instructions as are necessary to render the first part of the page.
  17. When the 16-bit printer driver renders a part of the page, it passes the printer-specific raw page data back to 16-bit GDI.
  18. GDI passes the raw data to GDI32. Once again, the 16-bit printer driver is isolated from the transition from 16-bit to 32-bit programming environments. GDI32 passes the raw page data to the 32-bit print spooler process.

Steps 19 through 24, within the spooler process, are the same as the comparable steps described in the raw despooling scenario and result in part of the page appearing on the printer.

Steps 16 through 24 are repeated until an entire page is printed (all the rendering instructions in an EMF spool file have been used). The GDI32 gets the path to the EMF spool file for the next page of the print job and calls GDI to use the instructions in that EMF file to render the next page in the print job. When GDI32 has used up all the paths to EMF spool files in the job description file, the print job is finished.


Typical Direct Printing Process Scenario

This section illustrates the major relationships between the print spooler components, the printer driver, and GDI during the direct printing process -- when no spooling takes place. This scenario illustrates what happens when a direct printing job is carried out because the user has employed Details tab on the Printer Properties property sheet to set the Spool Settings to "Print directly to printer."

The presented scenario walks through the sequence of calls between printer system components between the time a direct print job is started by an application and the job's delivery to a bidirectional printer. Note that the application may not be aware of the fact that this is a direct print job, because the application does not know whether the user has set the "Print directly to printer" option or not.

The following illustration shows the sequence of calls and events that start with the application initiating a print job when the "Print directly to printer" option is set for the printer specified by the application to do the printing. This step is labeled 1 in the following illustration and the final step, where the print job is sent through the hardware port to the printer is labeled step 18. The direct print option of printing to a file instead of a printer is also shown in the illustration.

Important points to notice in this scenario are:

  • If the print job destination is a file, the spooler part of the printer system is not involved in fulfilling the direct print request. See steps 2, 3, and 4 of the scenario, which are dedicated to printing directly to a file specified by the application that initiated the print request.
  • In this example scenario, which starts with the application initiating a print job when the "Print directly to printer" option is set for the application-specified printer, if the print job destination is not a file, then the determination of whether the print request is a direct request is made by the local print provider StartDoc function (inside the spooler). That determination is based on the current setting of the printer specified in the print request, not on an attribute set in the print request itself. A print job is "direct" because the printer it is destined for is set to "Print directly to printer" when the print job is initiated (when the printing application executes a StartDoc function).

As illustrated above, a typical direct printing process scenario is executed as follows

  1. The application has a graphics object, for example a circle, to send to a printer. The application creates a DC and calls the GDI StartDoc function to initiate a print request for the printer. This request may also contain a file name if the application wants to print directly to a file.
  2. If the GDI StartDoc function determines that there is an output file name in the print request, then GDI returns success to the application and the application makes the call to draw the circle. GDI calls the printer driver associated with the specified printer to render the circle.
  3. In the case of printing directly to a file, the 16-bit printer driver returns the rendered circle to 16-bit GDI.
  4. Continuing with the case of printing directly to a file, GDI writes the rendered circle to the output file specified in the print request. GDI is the appropriate printer system component to write results of the direct print job to a file because it has the same current directory as the application, and the current directory information may be needed to generate a full path to the destination file. The printer subsystem (the spooler) does not know the application's current directory. So, in the case of a direct print job to a file, the 32-bit side of the printer system is not involved at all.
  5. If the GDI StartDoc function finds no output file name in the print request, then the destination must be the printer. GDI passes the print request to 32-bit GDI instead of returning to the application (and steps 3 and 4 of the scenario are skipped).
  6. GDI32 makes an interprocess call to the spooler process.
  7. SPOOL32.EXE calls the router to route the print job to the printer specified by the application.
  8. The router calls the local print provider with the print job request. The StartDocPrinter function within the local print provider checks whether the current configuration of the printer is "Print directly to printer." If the printer specified in the print request is currently set to "Print directly to printer," then the local print provider checks to see if the port associated with the requested printer is busy or not. If the port is busy with another print job on any printer attached to that port, for example despooling a previously spooled print job, then the local print provider returns an error condition to the application. If the port is not busy, the local print provider reserves the port exclusively for the direct print job and returns success to the application.
  9. When success is returned from the local print provider, the application makes the call to render the circle.
  10. GDI calls the printer driver associated with the specified printer to render the circle.
  11. The 16-bit printer driver returns the rendered circle to 16-bit GDI.
  12. GDI passes the print request to 32-bit GDI.
  13. GDI32 makes an interprocess call to the spooler process.
  14. SPOOL32.EXE calls the router to route the print job to the printer specified by the application.
  15. The router calls the local print provider WritePrinter function with the print job request. The local print provider recognizes the job as a direct print job for which it has reserved a port.
  16. The local print provider sends the print request to the language monitor associated with the requested printer (note that in this example, a bidirectional printer is being used). Note that the local print provider dedicates the use of the port to outputting the direct print job until the job is ended.
  17. The language monitor calls the port monitor to send data to the printer.
  18. The port monitor sends data through the physical port to the connected printer. Steps 10 through 18 are repeated until all the print job data is printed or the print job is canceled.


Spooler Compatibility Considerations

The Windows 95 spooler and Windows NT/Windows 2000 spooler are similar in many ways. One important difference is that in Windows NT/Windows 2000 the router, local print provider (local spooler), default print processor and default monitor components were each packaged in a separate DLL. In Windows 95, for performance reasons, the default router, local print provider, and port monitor are packaged in one DLL (SPOOLSS.DLL). If you decide to add a print processor, port monitor, or language monitor to the Windows 95 spooler subsystem, you will have to build a separate DLL that is callable by the spooler DLL. Guidelines on how to do this for print processors and port monitors are given in About Print Processors, About Port Monitors, and About Language Monitors. Instructions on how to install these DLLs, either by calling Win32 APIs or adding extensions to printer .INF files are given in Installing Printer Support. Sample source code for a print processor, port monitor, and language monitor are in the SAMPLES directory of the DDK.

Highlights of other similarities and differences between the Windows NT/Windows 2000 and Windows 95 spooler include:

  • The Windows 95 and Windows NT/Windows 2000 spooler APIs are compatible. However, there are some variations in data structures.
  • Language monitors are extensions to printer drivers in Windows 95. For more information, see About Language Monitors.
  • Windows 95 offers better bidirectional printer support than Windows NT/Windows 2000. For more information, see About Language Monitors.
  • Windows 95 has some print processor and monitor extensions. Print processor extensions are described in About Print Processors.
  • Windows 95 uses an enhanced metafiles (EMF) spool file format instead of the journal spool file format used by Windows NT/Windows 2000.


Definition of Terms

This section defines the most important terms used in describing the Windows 95 printer subsystem.

Print job | The print spooler organizes print requests from clients by creating a queue of print jobs. Each print job is destined for a particular printer. A print job may be spooled (written to a file on disk and printed later) or printed directly to the printer.
Printer spool files | Print jobs that are not printed directly are stored in spool files on disk. Two types of spool file formats are supported by the default Windows 95 spooler: the enhanced metafile (EMF) format, which is device-independent, and raw format, which is device dependent.
Enhanced metafile spool files | Enhanced metafiles (EMFs) are one type of spool file used by the default Windows 95 print spooler (raw files are the other type). EMFs are also the native graphics file format for Windows 95. EMF spool files are used to greatly reduce the amount of time between the time the application user initiates a print request and when control is returned back to the operating system. This is done by storing only the GDI function calls that produce the graphics object the application wants printed, allowing the much more time-consuming execution of the function calls to be carried out later, in the background, when the spool file is "played back." The way EMF spool files are encoded also provides the advantage of printer device-independence. In other words, a picture measuring 2 inches by 4 inches on a VGA display and stored in an EMF maintains those original dimensions when it is printed on a 300 dpi laser printer or a 75 dpi dot matrix printer.
Raw spool files | Raw spool files are device dependent. The spooled data is destined and formatted for a particular device and does not need to be printable on a different device. An example of a raw spool file is an encapsulated PostScript file, which is formatted to be understood by the PostScript printer for which it is destined, but which is just raw data to the Windows 95 spooler.
Port | The physical hardware through which a printer connects to the computer.
Bidirectional printer | A printer that supports two-way communication between the printer and code running on the computer to which the printer is connected. This two-way communication is used for two primary purposes: printer configuration and monitoring device status. An example of a bidirectional printer is an HP LaserJet 4Si.


Router and Local Print Provider

The Print Request Router (PPR) routes a data stream to the local print provider or to a network print provider. All printing tasks initiated by an application or a Windows 95 system component go through the PRR as the first step towards getting the job done in the spooler process. For an example of how the PRR is involved in both the process of spooling a print job and in the process of playing back (despooling) a print job, see Typical Printing Process Scenario Using a Raw Spool File and Typical Printing Process Scenario Using an EMF Spool File.

Microsoft provides the executable Print Request Router, which cannot be replaced by an IHV.

The local print provider puts jobs into spool files, manages despooling (playback of spooled files), and administers print jobs and open printers. For an example of how the local print provider puts jobs into spool files and manages the playback of spooled files, see Typical Printing Process Scenario Using a Raw Spool File and Typical Printing Process Scenario Using an EMF Spool File.

Microsoft provides the local print provider, which cannot be replaced by an IHV.

This section lists the APIs exported by the Microsoft-provided local print provider and then gives more details about how the router and local print provider administer print jobs and open printers.


Local Print Provider APIs

The APIs available from the local print provider are listed in About Net Print Providers. The APIs are documented in the Win32 SDK.


Print Spooler Administration APIs

Much of the Windows 95 print spooler code administers print process objects such as printers, print jobs, printer drivers, print processors, monitors, and ports. The functions that the print spooler offers to perform these administrative functions can be identified by the first few letters of each function name. For example, there are function names such as AddPrinter, AddJob, AddPrinterDriver, AddPrintProcessor, AddMonitor, and AddPort. All of these functions add objects to the print spooler environment. All of the functions identified in this paragraph are documented in the Win32 SDK.

Similarly, there is a set of functions which begin with Delete, such as DeletePrinter, which delete objects from the spooler environment. Another set of functions, whose names begin with Enum, enumerate the objects of a certain type currently in the spooler environment. An example of an enumeration function is EnumPrinters.

GetPrinter gets configuration data from a printer and SetPrinter sets configuration data on a printer. Functions that get and set configuration data on other objects in the spooler environment are also available, such as GetJob and SetJob.

The following table summarizes the operations that are performed by the Add, Delete, Enum, Get, and Set functions on each of the different objects in the spooler environment:

Function Type | Printer | Job | Printer Driver | Print Processor | Monitor | Port
Add | Yes | Yes | Yes | Yes | Yes | Yes
Delete | Yes | No | Yes | Yes | Yes | Yes
Enum | Yes | Yes | Yes | Yes | Yes | Yes
Get | Yes | Yes | Yes | Yes | No | No
Set | Yes | Yes | No | No | No | No

Although the local print provider accepts the calls to all of these spooler object administration functions, the code that actually administers each type of object (for example by entering or deleting information from the Registry) is distributed through the layers of the print spooler architecture. Printer and job management data such as printer settings and status and job settings and status are displayed at the top-most level of the system, the Shell user interface.


Installing Printer Support

Windows 95 supplies a default port monitor, language monitor, and print processor. See Spooler Components and IHV Development Opportunities for reasons you may want to develop one or more of these components for your device and package each component as a separate DLL. Once you have developed such a DLL, there are two methods of installing the component so it will be part of the spooler's environment:

  • Use Win32 APIs such as AddPrintProcessor and AddMonitor.
  • Use the printer-specific extensions to INF files provided by the Windows 95 printer installer.

For information about how to use the printer-specific extensions to INF files, as well as information about using the AddPrintProcessor and AddMonitor APIs, see Printer INF File Extensions.


Net Print Providers

In Windows 95, applications can control network printers and print jobs generically, regardless of the type of network that is running on the computer along with the application. This is done by routing printer requests to an installable translation layer, called a Network Print Provider (NPP), that converts the requests from the generic Win32 format to a vendor-specific form that can be used by the network or device.

Network hardware and software vendors must supply an NPP to manage communication between their network and the Win32® printing API. The NPP converts Win32 structures, commands and queries to forms that can be understood by the network the NPP supports and makes the appropriate network-specific print API calls. The NPP then converts the results of the API call to a form usable by Win32.

A Windows 95 workstation can run more that one print provider simultaneously. In fact, local printing support is implemented by a provider, the Local Print Provider, so even on a computer that is running only one network, two print providers are running. Additional Network Print Providers can also be running on this same computer.

Multiple print providers are supported via a routing mechanism, the Print Request Router (PRR), which is similar to the Multiple Network Router (MNR) used by network service providers. Calls that do not explicitly specify a handle to an open printer are handled by the PRR by passing the request to each print provider in turn until one accepts the request or all providers have failed.


Design and Implementation Notes

A Windows 95 Network Print Provider is implemented as a 32-bit dynamic link library (DLL) which is specific to its underlying networking software. At startup, the PRR enumerates installed print providers from the Registry and attempts to load each one. During the DLL load process, an NPP should verify that its associated network software is running and refuse to load if it is not.

Upon the successful loading of a Print Provider, the PRR calls its InitializePrintProvidor function by ordinal to obtain a table of entry points corresponding to the Win32 print APIs. Since all calls to the provider are made through the table, it is not necessary for the DLL to export any of the functions in the table by name.

Each table entry must point to a valid function. Print Providers are required to provide stubs for functions that they do not implement. For more information see Functions Implemented as Stubs.

The functions represented in the entry-point table fall into three different groups:

  • Functions that must be implemented for printing to take place.
  • Functions that must be implemented in order for the user to employ the Point and Print feature of the Windows 95 Shell.
  • Functions for which a network print provider must supply a stub.

The following sections list the functions in each of these categories.


Functions That a Network Print Provider Must Implement

The following functions are required for printing. They must be supported by all network Print Providers. For detailed information about each of these functions, see Reference.

Function Name | Description
AbortPrinter | Cancels and deletes the currently spooling job for the specified printer.
AddJob | Returns a full path and file name of a file that can be used to store a print job.
ClosePrinter | Closes the given printer object.
DeleteJob | Deletes a print job for a given printer.
EndDocPrinter | Ends a print job for the specified printer.
EndPagePrinter | Indicates the end of one page and the beginning of the next page.
EnumJobs | Initializes an array of either JOB_INFO_1 or JOB_INFO_2 structures with data describing the specified print jobs for the given printer.
EnumPrinters (Level 1) | Enumerates the available printers on the specified server.
GetPrinter (Level 2) | Retrieves data for the specified printer.
GetJob | Retrieves data about a print job for the specified printer.
InitializePrintProvidor | Fills a table of entry points for a print provider.
OpenPrinter | Returns a handle identifying the specified printer or print server.
ScheduleJob | Informs the print spooler that the specified job can be scheduled for printing.
SetJob | Pauses, resumes, cancels, or restarts the specified print job on the given printer. The function can also be used to set print job parameters such as the job priority, the document name, and so forth.
SetPrinter | Sets the specified printer by pausing printing, resuming printing, or clearing all print jobs. It can also be used to set printer data.
StartDocPrinter | Informs the print spooler that a document is to be spooled for printing.
StartPagePrinter | Informs the spooler that a page is about to be printed on the specified printer.
WritePrinter | Informs the print spooler that the specified data should be written to the specified printer.

The bulk of the information about these functions is also available in the Win32 Programmer's Reference. It is presented here in annotated form for ease of reference. The one data structure used by a Network Print Provider that is not described in the Win32 Programmer's Reference is documented in this section also. That is the PRINTPROVIDOR structure.

Other data structures that may possibly be used by the functions in a Windows 95 Network Print Provider are: ADDJOB_INFO_1, JOB_INFO_1, JOB_INFO_2, PRINTER_INFO_1, PRINTER_INFO_2, PRINTER_INFO_3, DRIVER_INFO_1, DRIVER_INFO_2, and PRINTER_DEFAULTS. These data structures used by are used by the Windows NT/Windows 2000 spooler and have the same definitions in Windows 95. You can find documentation for these structures in the Win32 Programmer's Reference.


Functions Required for Point and Print

Point and Print is a feature provided by the Windows 95 Shell that enables users to print to a network printer without having to manually install a new driver. The following additional functions are required to support Point and Print. For detailed information about each of these functions, see Reference.

Function Name | Description
GetPrinter (level 2) | Retrieves data for the specified printer.
GetPrinterDriver (level 3 required for full support) | Retrieves driver data for the specified printer.
GetPrinterDriverDirectory | Retrieves the path to the specified printer driver.


Functions Implemented as Stubs

The entry-point table that is filled by an NPP when its InitialPrintProvidor function is called is implemented as the PRINTPROVIDOR structure. Entry points for functions exist in the PRINTPROVIDOR table that an NPP must implement as stubs. These entry points are included in the PRINTPROVIDOR table for use by the Local Print Provider and to preserve source code compatibility with Windows NT/Windows 2000.

Print Providers must supply valid entry points for all functions in the PRINTPROVIDOR structure. Providers should supply stub functions that return correct error values for all unsupported functions. Unsupported functions should fail and set the last error code to ERROR_CALL_NOT_IMPLEMENTED. Setting this error code tells the PRR that your provider does not support the request and allows the PRR to try the next available provider.

The functions that a network print provider must implement as stubs are:

  • AddForm
  • AddMonitor
  • AddPort
  • AddPrinter
  • AddPrinterConnection
  • AddPrinterDriver
  • AddPrintProcessor
  • ConfigurePort
  • CreatePrinterIC
  • DeleteForm
  • DeleteMonitor
  • DeletePort
  • DeletePrinter
  • DeletePrinterConnection
  • DeletePrinterDriver
  • DeletePrinterIC
  • DeletePrintProcessor
  • EnumForms
  • EnumMonitors
  • EnumPrinterDrivers
  • EnumPrintProcessors
  • EnumPrintProcessorDatatypes
  • GetForm
  • GetPrinterData
  • PlayGdiScriptOnPrinterIC
  • PrinterMessageBox
  • SetForm
  • SetPrinterData
  • WaitForPrinterChange


Error Reporting

Most NPP functions return TRUE on success and FALSE to indicate failure. To provide more information when an error occurs, NPP functions can call the Win32 function SetLastError with an appropriate error code.

Print provider functions that take a printer or print server name as a parameter must return ERROR_INVALID_NAME if the print provider function determines that the specified printer or server does not exist on the network. This return value signals to the print request router (PRR) to pass the request on to the next print provider. Spooler calls that do not explicitly specify a handle to an open printer or server are handled by the PRR by passing the request to each print provider in turn until one accepts the request or all providers have failed.

Print provider functions that take a printer or server name as a parameter are:

  • EnumPrinters
  • GetPrinterDriverDirectory
  • GetPrintProcessorDirectory
  • OpenPrinter


Passing Buffers and Strings

A number of the NPP functions take as parameters the address and size of a buffer to be filled with a data structure of variable size. The buffer is allocated by the caller and passed to Win32, along with a DWORD parameter indicating the buffer's size in bytes. In many cases, an LPDWORD parameter is also passed in which the called function may indicate the number of bytes of data that it retrieved. The called function should compare the size of the buffer supplied by the caller with the number of bytes retrieved. If the supplied buffer is not large enough to contain at least one complete record, the NPP function should return failure, setting the last error code to ERROR_INSUFFICIENT_BUFFER.

NPP functions should store fixed-length structures contiguously starting at the beginning of the buffer, so that simple indexing can be used to access the Nth structure in an array of structures. If the returned data includes variable-length strings, the fixed-length data structures will contain pointers to these strings. The strings themselves will be placed at the end of the buffer. Note that pointers to strings or other variable length data are actual 32-bit pointers and are not offsets into the buffer.

Windows 95 uses DBCS ANSI/OEM character sets. When a buffer is used to pass and return strings, the specified buffer size represents the number of bytes that will fit, and not the number of characters. This differs from Windows NT/Windows 2000, which uses Unicode and allows the number of characters to be specified.


Reference

The Network Print Provider functions required for basic support and Point and Print are listed here in alphabetical order.


AbortPrinter

BOOL AbortPrinter(
HANDLE  hPrinter;    /* handle of printer object    */
);

Cancels and deletes the currently spooling job for the specified printer.

  • If the function succeeds, the return value is TRUE; otherwise, it is FALSE. To get extended error information, use the GetLastError function.
hPrinter Identifies the printer from which the spool file is deleted.

If the printer is not configured for spooling, this function has no effect.

The handle hPrinter is returned by the OpenPrinter function.


AddJob

BOOL AddJob(
    HANDLE hPrinter,    /* handle of printer object          */
    DWORD cLevel,       /* data-structure level              */
    LPBYTE pData,       /* address of data-structure array   */
    DWORD cbBuf,        /* count of bytes in array           */
    LPDWORD pcbNeeded,  /* address of variable that contains */
                        /* count of bytes required           */
);

Returns the full path name of a file that can be used to store a print job.

  • If the function succeeds, the return value is TRUE; otherwise, it is FALSE. To get extended error information, use the GetLastError function.
hPrinter | Identifies the printer for which the print job is intended.
cLevel | Specifies the version of the structure to which pData points. The value of this parameter must be 1.
pData | Points to an ADDJOB_INFO_1 structure.
cbBuf | Specifies the size, in bytes, of the buffer pointed to by pData.
pcbNeeded | Points to a variable that will be updated with the number of bytes copied or the number of bytes required. If cbBuf is less than the required number of bytes, pcbNeeded specifies the number of bytes required; if cbBuf is large enough, pcbNeeded specifies the number of bytes copied.

The file name returned in the ADDJOB_INFO_1 structure can be opened with the CreateFile function. Once the file is opened, data can be written to the file by calling the WriteFile function.

The job identifier returned in the ADDJOB_INFO_1 structure can be passed to the SetJob and ScheduleJob functions in order to control the print job.

The AddJob and ScheduleJob functions are not currently required for basic printing, but should be supported if at all possible. Currently, Windows 95 uses StartDocPrinter and EndDocPrinter for job submission and scheduling.


ClosePrinter

BOOL ClosePrinter(
HANDLE hPrinter      /* handle of printer object */
);

Closes the specified printer object.

  • If the function succeeds, the return value is TRUE; otherwise, it is FALSE. To get extended error information, use the GetLastError function.
hPrinter Identifies the printer object to be closed.


EndDocPrinter

BOOL EndDocPrinter(
HANDLE hPrinter    /* handle of printer object     */
);

Ends a print job for the specified printer.

  • If the function succeeds, the return value is TRUE; otherwise, it is FALSE. To get extended error information, use the GetLastError function.
hPrinter Identifies the printer for which the print job should be ended.

This function returns an error if the print job to be ended was not started by an earlier call to the StartDocPrinter function.


EndPagePrinter

BOOL EndPagePrinter(
HANDLE hPrinter        /* handle of printer object    */
);

Indicates the end of one page and the beginning of the next page.

  • If the function succeeds, the return value is TRUE; otherwise, it is FALSE. To get extended error information, use the GetLastError function.
hPrinter Identifies the printer for which the page will be concluded.

The printer handle hPrinter is obtained by calling the OpenPrinter function.

Each page in a print job begins with a StartPagePrinter function call and ends with an EndPagePrinter function call. The data for each page is written to the print file by using the WritePrinter function.


EnumJobs

BOOL EnumJobs(
  HANDLE  hPrinter,     /* handle of printer object                   */
  DWORD   dwFirstJob,   /* location of first job in print queue       */
  DWORD   dwNoJobs,     /* number of jobs to enumerate                */
  DWORD   dwLevel,      /* structure level                            */
  LPBYTE  lpbJob,       /* address of structure array                 */
  DWORD   dwBuf,        /* size of array, in bytes                    */
  LPDWORD lpdwNeeded    /* addr. of variable with no. of bytes copied */
                        /* (or required)                              */
  LPDWORD lpdwReturned  /* addr. of variable with no. of job info     */
                        /* structures copied                          */
);

Initializes an array of either JOB_INFO_1 or JOB_INFO_2 structures with data describing the specified print jobs for the specified printer.

  • If the function succeeds, the return value is TRUE; otherwise, it is FALSE. To get extended error information, use the GetLastError function.
hPrinter | Identifies a printer object.
dwFirstJob | Specifies the location of the first enumerated job in the print queue. For example, a value of 10 indicates that enumeration should begin at the tenth job.
dwNoJobs | Specifies the total number of print jobs to enumerate.
dwLevel | Specifies whether the function should use JOB_INFO_1 or JOB_INFO_2 structures to store data for the enumerated jobs. A value of 1 specifies that the JOB_INFO_1 structure should be used; a value of 2 specifies that the JOB_INFO_2 structure should be used.
lpbJob | Points to an array of either JOB_INFO_1 or JOB_INFO_2 structures.
dwBuf | Specifies the size, in bytes, of the array pointed to by lpbJob.
lpdwNeeded | Points to a value that specifies the number of bytes copied if the function succeeds; otherwise, this value specifies the number of bytes required.
lpdwReturned | Points to a value that specifies the number of JOB_INFO_1 or JOB_INFO_2 structures that were initialized.

The handle hPrinter is obtained by calling the OpenPrinter function.

The JOB_INFO_1 structure contains general print-job data; the JOB_INFO_2 structure is much more detailed.


EnumPrinters

BOOL EnumPrinters(
   DWORD   dwType,      /* printer type or types                   */
  LPTSTR  lpszName,    /* address of server name                  */
  DWORD   dwLevel,     /* structure level                         */
  LPBYTE  lpbPrinters, /* printer info array                      */
  DWORD   cbBuf,       /* number of bytes in printer info array   */
                       /* buffer provided by caller               */
  LPDWORD lpdwNeeded,  /* address of variable with count of bytes */
                       /* copied (or required)                    */
  LPDWORD lpdwReturned /* address of variable with count of job   */
                       /* info. structures copied                 */
);

Enumerates the available printers on the specified server.

  • If the function succeeds, the return value is TRUE; otherwise, it is FALSE. To get extended error information, use the GetLastError function.
dwType | Specifies the type of printers that the function should enumerate. This value can be any combination of the following constants:
 | PRINTER_ENUM_DEFAULT | Enumerates the default printer.
 | PRINTER_ENUM_LOCAL | Enumerates the locally installed printers.
 | PRINTER_ENUM_FAVORITE | Enumerates a list of favorite printers. This is essentially the list of printers that the user has made previous connections to.
 | PRINTER_ENUM_NAME | Enumerates the printer identified by lpszName. This could be a server lpszName, or a domain lpszName. If lpszName is NULL, available domains (that is, Network Print Providors) will be enumerated.
 | PRINTER_ENUM_REMOTE | Enumerates network printers.
 | PRINTER_ENUM_SHARED | Enumerates printers with the shared attribute.
lpszName | Points to a null-terminated string that specifies the name of the server for which to enumerate the printers. If this string is NULL, the local printers are enumerated.
dwLevel | Specifies the version of the structure to which lpbPrinters points. This value must be 1 or 2.
lpbPrinters | Points to an array of PRINTER_INFO_1 or PRINTER_INFO_2 structures. If dwLevel is 1, the array contains PRINTER_INFO_1 structures; if dwLevel is 2, the array contains PRINTER_INFO_2 structures.
cbBuf | Specifies the size, in bytes, of the array to which lpbPrinters points.
lpdwNeeded | Points to a value that specifies the number of bytes copied if the function succeeds or the number of bytes required if cbBuf is too small.
lpdwReturned | Points to a value that specifies the number of PRINTER_INFO_1 or PRINTER_INFO_2 structures that returned in the array to which the lpbPrinters parameter points.

Network print providers are only required to support two of the dwType parameter values: PRINTER_ENUM_REMOTE and PRINTER_ENUM_NAME.

There are four possible dispositions for a server name passed to a provider's EnumPrinters function by the PRR:

  1. The name is not correctly formed. It is not a valid name on the provider's network.
  2. The name is valid, but the server cannot be found.
  3. The name is valid and the server exists, but it does not respond properly.
  4. The name is valid and the server responds as expected.

Cases 1 and 2 indicate that the specified server does not exist on the network. In these cases, the PRR expects providers to return FALSE and to set the last error code to the value ERROR_INVALID_NAME.

Case 3 represents a network error. The provider should return FALSE and call the SetLastError function to an appropriate Win32 error code. Once a network error has been encountered, the PRR will perform no further enumeration.

Case 4 indicates success. The provider should return TRUE.


GetJob

BOOL GetJob(
  HANDLE  hPrinter,   /* handle of printer                    */
  DWORD   dwJobId,    /* job identifier value                 */
  DWORD   dwLevel,    /* data-structure level                 */
  LPBYTE  lpbJob,     /* address of data-structure array     */
  DWORD   cbBuf       /* count of bytes in array              */
  LPDWORD lpdwNeeded  /* address of value that contains count */
                      /* of bytes retrieved (or required)     */
);

Retrieves data about a print job for the specified printer.

  • If the function succeeds, the return value is TRUE; otherwise, it is FALSE. To provide extended error information, use the GetLastError function.
hPrinter | Identifies the printer for which the print job data is retrieved.
dwJobId | Identifies the print job for which data should be retrieved.
dwLevel | Specifies the version of the structure to which lpbJob points. This value must be either 1 or 2.
lpbJob | Points to an array that contains either a JOB_INFO_1 or a JOB_INFO_2 structure. If dwLevel is 1, this function stores the data in a JOB_INFO_1 structure; if dwLevel is 2, this function stores the data in a JOB_INFO_2 structure.
cbBuf | Specifies the size, in bytes, of the array.
lpdwNeeded | Points to a value that specifies the number of bytes copied if the function succeeds or the number of bytes required if cbBuf is too small.


GetPrinter

BOOL GetPrinter(
  HANDLE  hPrinter,   /* handle of printer object              */
  DWORD   dwLevel,    /* structure level                       */
  LPBYTE  lpbPrinter, /* address of structure array            */
  DWORD   cbBuf,      /* size, in bytes, of array              */
  LPDWORD lpdwNeeded  /* addr. of variable with count of bytes */
                      /* retrieved (or required)               */
);

Retrieves data for the specified printer.

  • If the function succeeds, the return value is TRUE; otherwise, it is FALSE. To get extended error information, use the GetLastError function.
hPrinter | Identifies the printer for which data is requested.
dwLevel | Specifies the version of the structure to which lpbPrinter points. This value must be 1, 2, or 3.
lpbPrinter | Points to an array of bytes that receives a PRINTER_INFO_1, PRINTER_INFO_2, or PRINTER_INFO_3 structure.
cbBuf | Specifies the size, in bytes, of the array to which lpbPrinter points.
lpdwNeeded | Points to a value that specifies the number of bytes copied if the function succeeds or the number of bytes required if cbBuf was too small.


GetPrinterDriver

BOOL GetPrinterDriver(
HANDLE  hPrinter,   /* printer object                        */
LPTSTR  lpszEnv,    /* address of environment                */
DWORD   dwLevel,    /* structure level                       */
LPBYTE  lpbDrvInfo, /* address of structure array            */
DWORD   cbBuf,      /* size, in bytes, of array              */
LPDWORD lpdwNeeded  /* addr. of variable with count of bytes */
                    /* retrieved (or required)               */
);

Retrieves driver data for the specified printer.

  • If the function succeeds, the return value is TRUE; otherwise, it is FALSE. To get extended error information, use the GetLastError function.
hPrinter | Identifies the printer for which to retrieve driver data.
lpszEnv | Points to a null-terminated string that specifies the environment. For example, "Windows 96 x86" specifies Windows 96 running on an Intel(r) 80386 or 80486 processor. If this string is NULL, the current environment of the caller/client (not of the destination/server) is used.
dwLevel | Specifies the version of the structure to which lpbDrvInfo points. This value must be either 1 or 2.
lpbDrvInfo | Points to either a DRIVER_INFO_1 or a DRIVER_INFO_2 structure. If dwLevel is 1, this array receives a DRIVER_INFO_1 structure; if dwLevel is 2, this array receives a DRIVER_INFO_2 structure.
cbBuf | Specifies the size, in bytes, of the array at which lpbDrvInfo points.
lpdwNeeded | Points to a value that specifies the number of bytes copied if the function succeeds or the number of bytes required if cbBuf is too small.

The printer handle hPrinter is obtained by calling the OpenPrinter function.

The DRIVER_INFO_2 structure contains a full path and file name that specifies the location of the printer driver. An application can use the path and file name to load a printer driver by calling the LoadLibrary function and supplying the path and file name as the single argument.


GetPrinterDriverDirectory

BOOL GetPrinterDriverDirectory(
  LPTSTR  lpszName,    /* address of server name                */
  LPTSTR  lpszEnv,     /* address of environment                */
  DWORD   dwLevel,     /* address of structure                  */
  LPBYTE  lpbDir,      /* address of structure array that       */
                       /* receives path                         */
  DWORD   cbBuf,       /* size, in bytes, of array              */
  LPDWORD lpdwNeeded   /* addr. of variable with count of bytes */
                       /* retrieved (or required)               */
);

Retrieves the path to the specified printer driver.

  • If the function succeeds, the return value is TRUE; otherwise, it is FALSE. To get extended error information, use the GetLastError function.
lpszName | Points to a null-terminated string that specifies the name of the server on which the printer driver resides. If this string is NULL, the path to the Local Print Provider is retrieved.
lpszEnv | Points to a null-terminated string that specifies the environment. For example, "Windows 96 x86" specifies Windows 96 running on an Intel(r) 80386 or 80486 processor. If this string is NULL, the current environment of the caller/client (not of the destination/server) is used.
dwLevel | Specifies the structure level. This value must be 1.
lpbDir | Points to an array of bytes that receives the path.
cbBuf | Specifies the size of the array to which lpbDir points.
lpdwNeeded | Points to a value that specifies the number of bytes copied if the function succeeds, or the number of bytes required if cbBuf is too small.


GetPrintProcessorDirectory

BOOL GetPrintProcessorDirectory(
  LPTSTR  lpszName,        /* address of server name           */
  LPTSTR  lpszEnv,         /* address of environment           */
  DWORD   dwLevel,         /* structure level                  */
  LPBYTE  lpbProcessorDir, /* address of structure array       */
  DWORD   cbBuf,           /* size, in bytes, of array         */
  LPDWORD lpdwNeeded       /* addr. of variable with count of  */
                           /* bytes retrieved (or required)    */
);

Retrieves the path for the print processor on the specified server.

  • If the function succeeds, the return value is TRUE; otherwise, it is FALSE. To get extended error information, use the GetLastError function.
lpszName | Points to a null-terminated string that specifies the name of the server. If this string is NULL, a local path is returned.
lpszEnv | Points to a null-terminated string that specifies the environment. For example, "Windows 96 x86" specifies Windows 96 running on an Intel(r) 80386 or 80486 processor. If this string is NULL, the current environment of the caller/client (not of the destination/server) is used.
dwLevel | Specifies the structure level. This value must be 1.
lpbProcessorDir | Points to an array of bytes into which the path is copied.
cbBuf | Specifies the size of the buffer to which lpbProcessorDir points.
lpdwNeeded | Points to a value that specifies the number of bytes copied if the function succeeds, or the number of bytes required if cbBuf is too small.


InitializePrintProvider

BOOL InitializePrintProvidor(
  LPPRINTPROVIDOR pPrintProvider,   /* address of entry point table */
  DWORD           cbPrintProvider,  /* size of entry point table    */
                                    /* in bytes                     */
  LPSTR           pFullRegistryPath
);

Fills a table of entry points for a print provider.

  • If the function succeeds, the return value is TRUE; otherwise, it is FALSE. To get extended error information, use the GetLastError function.
pPrintProvider | Points to a PRINTPROVIDOR structure that the Network Print Provider must fill out with entry points to all its API handling routines.
cbPrintProvider | Size, in bytes, of the buffer pointed to by pPrintProvider.
pFullRegistryPath | Points to an ASCIIZ string containing the full registry path to the print provider being initialized.


OpenPrinter

BOOL OpenPrinter(
  LPTSTR   pPrinterName,      /* address of printer or server name   */
  LPHANDLE phPrinter,         /* address of printer or server handle */
  LPPRINTER_DEFAULTS pDefault /* address of printer defaults         */
                              /* structure                           */
);

Returns a handle identifying the specified printer or print server.

  • If the function succeeds, the return value is TRUE; otherwise, it is FALSE. To get extended error information, use the GetLastError function.
pPrinterName | Points to a null-terminated string that specifies the friendly name of the printer or the network path name, such as a UNC name, for the print server. If you specify a friendly name, the handle returned by OpenPrinter refers to data structures on the local machine that describe the printer (even though the printer may be located on the network). If you specify a network path name, such as a UNC name, the returned handle refers to the data structures on the print server and all subsequent function calls (for example, a SetPrinter call) are passed directly to the specified server over the network. The choice of the printer name type (friendly name or network path name) has important implications, which are described in the comments below.
phPrinter | Points to a value that receives the handle identifying the opened printer or print server object.
pDefault | Points to a PRINTER_DEFAULTS structure. This value can be NULL.

The following is an example of the difference between specifying a friendly printer name and a network path name to a printer server in the pPrinterName parameter of an OpenPrinter call. If you specify the friendly name of a printer on the network, then you can use the returned handle in a subsequent SetPrinter call to change the port on the local machine that accesses that printer. However, if you specify a UNC name of a Windows NT/Windows 2000 print server in the OpenPrinter call, then a subsequent SetPrinter call to change the printer port will result in an error because the SetPrinter call is not acted upon on the local machine. The call is passed directly to the server over the network and will not succeed there because a Windows 95 client will never have sufficient access privileges to change a printer port on the Windows NT/Windows 2000 print server.

The pDefault parameter enables an application to specify the data type and device mode values that are used for printing documents submitted by the StartDocPrinter function. However, these values can be overridden by using the SetJob function once a document has been started.

The DesiredAccess member of the PRINTER_DEFAULTS data structure pointed to by the pDefault parameter specifies the types of access an application wishes to perform using the handle returned by OpenPrinter. If an application wishes to open a printer to perform administrative tasks, such as the SetPrinter function, it should open the printer with PRINTER_ALL_ACCESS access. If an application wishes only to perform basic printing operations, an access value that includes PRINTER_ACCESS_USE is sufficient.

Note that Windows 95 does not attempt to validate security at OpenPrinter time if you specify a friendly printer name, so whatever access flags are set in the PRINTER_DEFAULTS structure are ignored by the OpenPrinter function in this case. This is different than the way the OpenPrinter function works on Windows NT/Windows 2000 in this case; on Windows NT/Windows 2000 the access flags are used.

If a user does not hold permission to open the specified print server (specified by a network path name in pPrinterName parameter of the OpenPrinter call) with the desired access, the OpenPrinter call will fail, and GetLastError will return the value ERROR_ACCESS_DENIED.


PRINTPROVIDOR

typedef struct _PRINTPROVIDOR {
   BOOL (*fpOpenPrinter)(LPTSTR pPrinterName, LPHANDLE phPrinter,
        LPPRINTER_DEFAULTS pDefault);
    BOOL (*fpSetJob)(HANDLE hPrinter, DWORD JobId, DWORD Level,
        LPBYTE pJob, DWORD Command);
    BOOL (*fpGetJob)(HANDLE hPrinter, DWORD JobId, DWORD Level,
        LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded);
    BOOL (*fpEnumJobs)(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
        DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
        LPDWORD pcReturned);
    HANDLE (*fpAddPrinter)(LPTSTR pName, DWORD Level, LPBYTE pPrinter);
    BOOL (*fpDeletePrinter)(HANDLE hPrinter);
    BOOL (*fpSetPrinter)(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
        DWORD Command);
    BOOL (*fpGetPrinter)(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
        DWORD cbBuf, LPDWORD pcbNeeded);
    BOOL (*fpEnumPrinters)(DWORD Flags, LPTSTR Name, DWORD Level,
        LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded,
        LPDWORD pcReturned);
    BOOL (*fpAddPrinterDriver)(LPTSTR pName, DWORD Level,
        LPBYTE pDriverInfo);
    BOOL (*fpEnumPrinterDrivers)(LPTSTR pName, LPTSTR pEnvironment,
        DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded,
        LPDWORD pcReturned);
    BOOL (*fpGetPrinterDriver)(HANDLE hPrinter, LPTSTR pEnvironment,
        DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf,
        LPDWORD pcbNeeded);
    BOOL (*fpGetPrinterDriverDirectory)(LPTSTR pName,
        LPTSTR pEnvironment, DWORD Level, LPBYTE pDriverDirectory,
        DWORD cbBuf, LPDWORD pcbNeeded);
    BOOL (*fpDeletePrinterDriver)(LPTSTR pName, LPTSTR pEnvironment,
        LPTSTR pDriverName);
    BOOL (*fpAddPrintProcessor)(LPTSTR pName, LPTSTR pEnvironment,
        LPTSTR pPathName, LPTSTR pPrintProcessorName);
    BOOL (*fpEnumPrintProcessors)(LPTSTR pName, LPTSTR pEnvironment,
        DWORD Level, LPBYTE pPrintProcessorInfo, DWORD cbBuf,
        LPDWORD pcbNeeded, LPDWORD pcReturned);
    BOOL (*fpGetPrintProcessorDirectory)(LPTSTR pName,
        LPTSTR pEnvironment, DWORD Level, LPBYTE pPrintProcessorInfo,
        DWORD cbBuf, LPDWORD pcbNeeded);
    BOOL (*fpDeletePrintProcessor)(LPTSTR pName, LPTSTR pEnvironment,
        LPTSTR pPrintProcessorName);
    BOOL (*fpEnumPrintProcessorDatatypes)(LPTSTR pName,
        LPTSTR pPrintProcessorName, DWORD Level, LPBYTE pDataypes,
        DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned);
    DWORD (*fpStartDocPrinter)(HANDLE hPrinter, DWORD Level,
        LPBYTE pDocInfo);
    BOOL (*fpStartPagePrinter) (HANDLE hPrinter);
    BOOL (*fpWritePrinter)(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
        LPDWORD pcWritten);
    BOOL (*fpEndPagePrinter)(HANDLE hPrinter);
    BOOL (*fpAbortPrinter)(HANDLE hPrinter);
    BOOL (*fpReadPrinter)(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
        LPDWORD pNoBytesRead);
    BOOL (*fpEndDocPrinter)(HANDLE hPrinter);
    BOOL (*fpAddJob)(HANDLE hPrinter, DWORD Level, LPBYTE pData,
        DWORD cbBuf, LPDWORD pcbNeeded);
    BOOL (*fpScheduleJob)(HANDLE hPrinter, DWORD JobId);
    DWORD (*fpGetPrinterData)(HANDLE hPrinter, LPTSTR pValueName,
        LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded);
    DWORD (*fpSetPrinterData)(HANDLE hPrinter, LPTSTR pValueName,
        DWORD Type, LPBYTE pData, DWORD cbData);
    DWORD (*fpWaitForPrinterChange)(HANDLE hPrinter,  DWORD Flags);
    BOOL (*fpClosePrinter)(HANDLE hPrinter);
    BOOL (*fpAddForm)(HANDLE hPrinter, DWORD Level, LPBYTE pForm);
    BOOL (*fpDeleteForm)(HANDLE hPrinter, LPTSTR pFormName);
    BOOL (*fpGetForm)(HANDLE hPrinter, LPTSTR pFormName, DWORD Level,
        LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded);
    BOOL (*fpSetForm)(HANDLE hPrinter, LPTSTR pFormName, DWORD Level,
        LPBYTE pForm);
    BOOL (*fpEnumForms)(HANDLE hPrinter, DWORD Level, LPBYTE pForm,
        DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned);
    BOOL (*fpEnumMonitors)(LPTSTR pName, DWORD Level, LPBYTE pMonitors,
        DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned);
    BOOL (*fpEnumPorts)(LPTSTR pName, DWORD Level, LPBYTE pPorts,
        DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned);
    BOOL (*fpAddPort)(LPTSTR pName, HWND hWnd, LPTSTR pMonitorName);
    BOOL (*fpConfigurePort)(LPTSTR pName, HWND hWnd, LPTSTR pPortName);
    BOOL (*fpDeletePort)(LPTSTR pName, HWND hWnd, LPTSTR pPortName);
    HANDLE (*fpCreatePrinterIC)(HANDLE hPrinter, LPDEVMODEW pDevMode);
    BOOL (*fpPlayGdiScriptOnPrinterIC)(HANDLE hPrinterIC, LPBYTE pIn,
        DWORD cIn, LPBYTE pOut, DWORD cOut, DWORD ul);
    BOOL (*fpDeletePrinterIC)(HANDLE hPrinterIC);
    BOOL (*fpAddPrinterConnection)(LPTSTR pName);
    BOOL (*fpDeletePrinterConnection)(LPTSTR pName);
    DWORD (*fpPrinterMessageBox)(HANDLE hPrinter, DWORD Error,
        HWND hWnd, LPTSTR pText, LPTSTR pCaption, DWORD dwType);
    BOOL (*fpAddMonitor)(LPTSTR pName, DWORD Level,
        LPBYTE pMonitorInfo);
    BOOL (*fpDeleteMonitor)(LPTSTR pName, LPTSTR pEnvironment,
        LPTSTR pMonitorName);
} PRINTPROVIDOR, FAR *LPPRINTPROVIDOR;

To initialize each NPP, the PRR calls InitializePrintProvidor by ordinal, with a pointer to an empty PRINTPROVIDOR structure, which is filled and returned by the provider. All calls from the PRR to the PP are made to the addresses specified in this structure.

Although some entry points are not used for Windows 95 print providers, they are preserved in this structure to maintain compatibility with Windows NT/Windows 2000. For more information on this, see Functions Implemented As Stubs.


ScheduleJob

BOOL ScheduleJob(
  HANDLE hPrinter,   /* handle of printer object   */
  DWORD  dwJobID     /* job-identifier value       */
);

Informs the print spooler that the specified job can be scheduled for printing.

  • If the function succeeds, the return value is TRUE; otherwise, it is FALSE. To get extended error information, use the GetLastError function.
hPrinter | Identifies the printer for which the job is scheduled.
dwJobID | Specifies the print job being scheduled.

The printer handle hPrinter is obtained by calling the OpenPrinter function.

This function should be called after an application calls the AddJob function. ScheduleJob is not required for basic printing support, but should be implemented if possible.


SetJob

BOOL SetJob(
HANDLE hPrinter,   /* handle of printer object         */
DWORD  dwJob,      /* job-identification value         */
DWORD  dwLevel,    /* structure level                  */
LPBYTE lpbJob,     /* address of job info structures   */
DWORD  dwCommand   /* job-command value                */
);

Pauses, resumes, cancels, or restarts the specified print job on the given printer. This function can also be used to set print job parameters such as the job priority, document name, and so forth.

  • If the function succeeds, the return value is TRUE; otherwise, it is FALSE. To get extended error information, use the GetLastError function.
hPrinter | Identifies the printer.
dwJob | Specifies the print job.
dwLevel | Specifies the version of the structure to which lpbJob points. This value must be 0, 1, or 2.
lpbJob | Points to either a JOB_INFO_1 or JOB_INFO_2 structure. If dwLevel is 0, this pointer must be NULL; if dwLevel is 1, the array contains a JOB_INFO_1 structure and if dwLevel is 2, the array contains a JOB_INFO_2 structure.
dwCommand | Specifies the operation which should be performed. It can be one of the following values:
 | JOB_CONTROL_CANCEL | Deletes a print job.
 | JOB_CONTROL_PAUSE | Pauses a print job.
 | JOB_CONTROL_RESTART | Restarts a print job at the beginning of the job. A job can only be restarted if it is printing.
 | JOB_CONTROL_RESUME | Resumes a paused print job.

The SetJob function can be used to set various job parameters by supplying a pointer to a JOB_INFO_1 or JOB_INFO_2 structure that contains the necessary data.

To remove or delete all the print jobs for a particular printer, call the SetPrinter function and set the PRINTER_CONTROL_PURGE value.

The following fields of a JOB_INFO_1 or JOB_INFO_2 structure will be ignored on a call to SetJob: JobId, pPrinterName, pMachineName, pUserName, pDrivername, Size, Submitted, and Time.

The Win32 API documentation does not define whether or not operations specified by dwCommand should be performed if dwLevel is non-zero. In the Windows 95 local Print Provider however, dwCommand operations are only performed if dwLevel is zero. This is the suggested implementation.


SetPrinter

BOOL SetPrinter(
  HANDLE hPrinter,   /* handle of printer object                  */
  DWORD  dwLevel,    /* structure level                           */
  LPBYTE lpbPrinter, /* address of array containing printer data  */
  DWORD  dwCommand   /* printer-state command                     */
);

Sets the specified printer by pausing printing, resuming printing, or clearing all print jobs. It can also be used to set printer data.

  • If the function succeeds, the return value is TRUE; otherwise, it is FALSE. To get extended error information, use the GetLastError function.
hPrinter | Identifies the printer.
dwLevel | Specifies the version of the structure to which lpbPrinter points. This value must be 0, 1, 2, or 3.
lpbPrinter | Points to an array of bytes that may contain printer data. If dwLevel is 0, this pointer must be NULL; if dwLevel is 1, the array contains a PRINTER_INFO_1 structure. If dwLevel is 2, the array contains a PRINTER_INFO_2 structure. If dwLevel is 3, the array contains a PRINTER_INFO_3 structure.
dwCommand | Specifies the new printer state. This parameter can be zero or one of the values listed in the following table. If it is zero, the printer retains its original state and the printer data is reconfigured by using the structure to which lpbPrinter points. Valid values for the dwCommand parameter are:

PRINTER_CONTROL_PAUSE | Pauses the printer.
PRINTER_CONTROL_PURGE | Deletes all print jobs in the printer.
PRINTER_CONTROL_RESUME | Resumes a paused printer.

The handle hPrinter is obtained by calling the OpenPrinter function.

To modify the current printer settings, an application should call GetPrinter to retrieve the current settings into a PRINTER_INFO_1, PRINTER_INFO_2, or PRINTER_INFO_3 structure, modify the members of that structure as necessary, and then call the SetPrinter function.

The following fields of a PRINTER_INFO_2 or PRINTER_INFO_3 structure will be ignored on a call to the SetPrinter function: pServerName, pPrinterName, and cJobs.

Pausing a printer suspends scheduling of all print jobs for that printer, except for the one print job that may be currently printing. Print jobs can be submitted to a paused printer, but no jobs will be scheduled to print on that printer until printing is resumed. If a printer is cleared, all print jobs for that printer are deleted, except for the current print job.

Note that there are limits to using the SetPrinter function on a Windows 95 client to perform remote administrative tasks on a remote print server. ( SetPrinter operates on data structures that reside on a remote print server when the network path name, for example a UNC name, to that server is used in the OpenPrinter call that must be made before the SetPrinter call.) For example, the SetPrinter function cannot be used on a standard Windows 95 client to change the printer port on a remote server, regardless of what the server platform is (Windows 95, Windows NT/Windows 2000, or some other server platform). The fundamental reason, for the specific example of changing the remote printer port, is that the standard Windows 95 client does not support the RPC protocol.

In other cases, limits to the remote administration capability of the SetPrinter function on the Windows 95 client are determined by the type of server platform. A remote administration task may be carried out on one type of remote platform, for example a Windows 95 server, but not on another type, say a Windows NT/Windows 2000 server. (This is similar to the way the remote capability of the SetJob function is limited by the type of server platform.) The optimum match of client platform type to server platform is to use Windows NT/Windows 2000 for both, because Windows NT/Windows 2000 clients and servers can communicate using the RPC protocol.


StartDocPrinter

DWORD StartDocPrinter(
  HANDLE hPrinter,  /* handle of printer object           */
  DWORD dwLevel,    /* structure level                    */
  LPBYTE lpbDocInfo /* address of structure               */
);

Informs the print spooler that a document is to be spooled for printing.

  • If the function succeeds, the return value identifies the print job; otherwise, it is zero. To get extended error information, use the GetLastError function.
hPrinter | Identifies the printer.
dwLevel | Specifies the version of the structure to which lpbDocInfo points. This value must be 1 or 2.
lpbDocInfo | Points to a DOC_INFO_1 structure.

The printer handle hPrinter is obtained by calling the OpenPrinter function.

Although the value of the dwLevel parameter may be 1 or 2, the DOC_INFO_1 structure is always used. The members of that structure are all this function needs.

The return value will never be greater than ((2^ 31) - 1).


StartPagePrinter

BOOL StartPagePrinter(
HANDLE hPrinter  /* handle of printer object */
);

Informs the spooler that a page is about to be printed on the specified printer.

  • If the function succeeds, the return value is TRUE; otherwise, it is FALSE. To get extended error information, use the GetLastError function.
hPrinter Identifies a printer.

The printer handle hPrinter is obtained by calling the OpenPrinter function.

When an application has finished writing a page, it should call the EndPagePrinter function to inform the spooler that the page is complete.


WritePrinter

BOOL WritePrinter(
  HANDLE  hPrinter,     /* handle of printer object                  */
  LPVOID  pBuf,         /* address of array containing printer dataa */
  DWORD   cbBuf,        /* size, in bytes, of array                  */
  LPDWORD lpdwWritten   /* addr. of variable with written byte count */
);

Informs the print spooler that the specified data should be written to the specified printer.

  • If the function succeeds, the return value is TRUE; otherwise, it is FALSE. To get extended error information, use the GetLastError function.
hPrinter | Identifies the printer.
pBuf | Points to an array of bytes that contains the data that should be written to the printer.
cbBuf | Specifies the size, in bytes, of the array.
lpdwWritten | Points to a value that specifies the number of bytes of data that were written to the printer.


Print Processors

A print processor works in conjunction with a printer driver to despool data types for the spooler during print spool file playback. For more information about the relationship between print processors and printer drivers, as well as information about the spool file playback process, see the sections that describe the playback of spooled raw files and the playback of spooled EMF files in About the Print Spooler.

Microsoft provides a print processor executable that works with the printer driver shipped with Windows 95. Printer vendors may have to develop another print processor if

  • The vendor develops their own driver or
  • The vendor supports a data type different than the data types supported by the Microsoft print processor.

IHVs may also want to develop a print processor that provides filter functions.

A print processor developed by a printer vendor is a 32-bit dynamic-link library (DLL) that is called by the local print provider. A print processor must export certain functions to the local print provider and also shares certain global data structures with the local print provider.

After the Windows 95 DDK is installed, sample print processor source code is provided in the Windows 95 DDK sub directory \%DDKROOT%\PRINTER\SAMPLES\SPOOLER\WINPRINT.


Print Processor Design and Implementation Notes

The Microsoft-provided print processor recognizes two printer object data types:

  • Raw
  • Enhanced metafiles (EMFs)

Raw data streams can be printed directly or put into spool files. Raw spool files are device-dependent. The spooled data is destined and formatted for a particular device and does not need to be printable on a device that is different than that. An example of a raw spool file is an encapsulated PostScript file, which is formatted to be understood by the PostScript printer for which it is destined, but which is just raw data to the Windows 95 spooler subsystem.

Enhanced metafiles (EMF) spool files are used to greatly reduce the amount of time between the time the application user initiates a print request and when control is returned back to application by the operating system. This is done by recording the GDI function calls that produce the application's graphic object on the specified printer in an EMF-format file, called a print spool file. The spool file can be built quickly this way and then control is returned to the application. Later, using a background thread, the Windows 95 print spooler performs the more time-consuming task of executing the GDI calls so the graphic object comes out on the printer.

Use of EMF spool files has another advantage besides the speed with which a print request returns to the application: device-independence. The bulk of an EMF is an array of variable-sized records that encode the GDI function calls necessary to reproduce the picture when the EMF is "played back." EMF spool files encode graphics information in such a way as to maintain device independence. In other words, a picture measuring 2 inches by 4 inches on a VGA display and stored in an EMF maintains those original dimensions when it is printed on a 300 dpi laser printer or a 75 dpi dot matrix printer. The key to achieving this device independence is the storage of a reference device context, that is, the context of the device on which the picture was created. For an excellent introduction to the use of EMFs in the Win32 API, see the article "Enhanced Metafiles in Win32" by Dennis Crain on the Microsoft Developer's Network.

Note that the Microsoft-provided default print processor, which is part of SPOOL32.DLL, can perform EMF to raw conversion.

As shown in Typical Printing Process Scenario Using an EMF Spool File, GDI manages the EMF files, not the print processor. It is not noted in that section but it is important to realize that GDI deletes each EMF file as soon as it is finished with it (after each page of rendered print data is sent to the printer). This means that a print job cannot be repeated at the print spooler level. In this release of the Windows 95 print spooler, there is no way for the print processor to manage EMF files to enable a print job to be repeated at the print spooler level. In order to repeat a print job, applications send the data multiple times, which, for example, gives the application the opportunity to manage collating.


Compatibility with Windows 2000

Unlike the Windows NT/Windows 2000 print processor, the Windows 95 print processor has direct access to the spool file. This may be used in a print processor to look ahead in the spool file and optimize the playback of the spool file.

As shown in Typical Printing Process Scenario Using a Raw Spool File, during playback of a spooled raw file the print processor reads the spooled file a block at a time. Although the default print processor does not do this, a print processor can accumulate the entire spool file before passing it on to the port monitor for printing. (Depending upon the size of the spool file, the accumulation could take place either in a memory buffer or in a temporary file created by the print processor). Once the print processor has the entire spool file, it can randomly access any part of the spool file for information that would help in optimizing the printing of the information.


Required Functions

The following table describes the entry points that a print processor must export to the local spooler and the data structures that are shared between the print processor and local spooler.

Entry Point | Description
ClosePrintProcessor | Closes an instance of the specified print processor.
ControlPrintProcessor | Provides control over printing the document.
EnumPrintProcessorDataTypes | Returns the data types supported by the print processor.
InitializePrintProcessor | Sets up the function pointer table that registers with the spooler all the other entry points provided by the print processor (OpenPrintProcessor, ClosePrintProcessor, ControlPrintProcessor, EnumDatatypes, and PrintDocumentOnPrintProcessor).
OpenPrintProcessor | Opens an instance of the print processor for printing.
PrintDocumentOnPrintProcessor | Prints the document. In the default print processor, this is the function that actually plays back the spooled file. The ReadPrinter function call gets a block of data from the spool file and the WritePrinter function call sends the block of data to the printer.

One data structure is also defined, PRINTPROCESSORDOCUMENTDATA. This is a global data structure defined in WINSPLP.H that is used to share information between the print processor component and other components of the spooler subsystem.


Sample Print Processor

The default print processor provided by Microsoft in Windows 95 is part of the spooler subsystem DLL. If you need to develop another print processor, you need to package it as a separate DLL callable by the spooler subsystem. The "Reference" section names the APIs that your DLL needs to export to be called by the spooler subsystem, and defines the members of the data structures the spooler subsystem uses to share data with a print processor.

Only two APIs need to be exported by a print processor to appear in the .DEF file for the processor: InitializePrintProcessor and DllEntryPoint. The InitializePrintProcessor code loads the addresses (function pointers) of the other print processor functions that the local print provider will call. For an example of such code, see the InitializePrintProcessor function code in the sample print processor provided with the Windows 95 DDK. All the functions that the local print provider expects to call through the function pointer table are defined in the Reference section below.

The sample print processor code is on the path \DDK\PRINTER\SAMPLE after you install the Windows 95 DDK.

The key function in the sample print processor (WINPRINT) shipped with the Windows 95 DDK is the WinprintPrintDocumentOnPrintProcessor function, which initiates sending a spooled print job to the printer. This function uses calls to the GDI 32 function gdiPlaySpoolStream and the local print provider functions ReadPrinter and WritePrinter. The following reference information for these three functions and a pseudo code representation of the sample WinprintPrintDocumentOnPrintProcessor will make it easier for you to understand the sample print processor source code that is part of the Windows 95 DDK. The reference information is presented first, and then the pseudo code. Before you read the rest of this section, review Typical Printing Process Scenario Using an EMF Spool File.


gdiPlaySpoolStream

HDC gdiPlaySpoolStream(
    LPSTR   lpszDevice,
    LPSTR   lpszOutput,
    LPSTR   lpszSpoolFile,
    DWORD   JobId,
    LPDWORD lpcbBuf,
    HDC     hDC
);

The Microsoft-provided GDI 32 gdiPlaySpoolStream function plays back a spool file or a buffer of spool data, or deletes all the EMFs of a spool file.

  • Returns a non-NULL hDC if successful in playing back a spool file or buffer, or successfully delete all the EMFs for a spool file. If a buffer of data was played back, lpcbBuf contains the amount of data (number of bytes) that were actually processed. Otherwise, returns NULL upon failure.
lpszDevice | Specifies the name of the printer that prints the document, or NULL. If NULL, gdiPlaySpoolStream deletes all the .TMP files whose paths are listed in the job description file specified by the lpszSpoolFile parameter.
lpszOutput | Output file name from StartDoc, that will be passed back into StartDoc.
lpszSpoolFile | Spool file name or a buffer of spool data depending on the value in the lpcbBuf parameter.
JobId | Identifies the print job.
lpcbBuf | If lpcbBuf is NULL, lpszSpoolFile is a spool file name and this parameter is not used.
 | If lpcbBuf is non-NULL, lpszSpoolFile is a buffer of spool data and lpcbBuf points to the size of the buffer. Upon return, lpcbBuf points to the amount of data (number of bytes) in the buffer that was processed, since the buffer may not end at a spool data block boundary.
hDC | If the lpcbBuf parameter is NULL, the hDC parameter is not used by the gdiPlaySpoolStream function.
 | If the lpcbBuf parameter is non-NULL, the hDC parameter specifies the handle of the DC used to play back the spool buffer. If the lpcbBuf parameter is non-NULL and the hDC parameter is NULL, the very first buffer of the job is being played and there is not a valid handle to a DC yet.

If lpcbBuf is NULL, lpszSpoolFile points to the file name of the spool file to playback. Otherwise, lpszSpoolFile is the pointer to a buffer of spool data, and lpcbBuf points to the size of the buffer and upon return, lpcbBuf points to the number of bytes that were actually sent to the printer.

If the hDC parameter is NULL, then this is the first call made to play the spool file. Otherwise, the hDC parameter will contain the handle of the DC that gdiPlaySpoolStream will use to play the remainder of the spool file.


ReadPrinter

BOOL ReadPrinter(
    HANDLE  hPrinter,
    LPVOID  pBuf,
    DWORD   cbBuf,
    LPWORD  pNoBytesRead
);

The Microsoft-provided local print provider ReadPrinter function either reads data from a bidirectional printer or reads data from a spool file.

Returns TRUE if successful; FALSE otherwise.

hPrinter | Identifies an open printer associated with the print processor and must be obtained from a call to OpenPrinter before ReadPrinter is called. You must also call StartDocPrinter before the call to ReadPrinter and the setting of the dwMode member of the DOC_INFO_2 structure when the StartDocPrinter function call is made modifies the meaning of the subsequent ReadPrinter call. See the comments below for example code that illustrates how these function calls work together. If the dwMode member is set to DI_READ_SPOOL_JOB when the StartDocPrinter call is made, then the subsequent ReadPrinter call will read the spool file (which may contain either raw or EMF data). If dwMode is not set to DI_READ_SPOOL_JOB, then the subsequent ReadPrinter call will read status information from a bidirectional printer.
pBuf | Points to the buffer into which the data is read.
cbBuf | The size of the buffer (number of characters in the buffer).
pNoBytesRead | Points to a variable into which the ReadPrinter function puts the number of characters successfully read from the printer or spool file.

The ReadPrinter function call is always preceded by a call to the StartDocPrinter call. If you set the dwMode member of the DOC_INFO_2 structure to DI_READ_SPOOL_JOB before making the StartDocPrinter function call, the subsequent ReadPrinter function call will read the spool file identified in the pOutput member of the DOC_INFO_2 structure instead of reading status information from the bidirectional printer your print processor is associated with.

The structure definition for the DOC_INFO_2 structure is shown below.

typedef struct _DOC_INFO_2
{
   LPTSTR    pDocumentName;  //identifies document being printed
   LPTSTR    pOutputFile;    //identifies spool file
   LPTSTR    pDatatype;      //data type of spooled file
   DWORD     dwMode;         //flags
   DWORD     JobId;          //identifies print job being printed
}DOC_INFO_2;


WritePrinter

BOOL WritePrinter(
    HANDLE  hPrinter,
    LPVOID  pBuf,
    DWORD   cbBuf,
    LPWORD  pcWritten
);

The Microsoft-provided local print provider WritePrinter function writes raw data from a specified buffer location to a specified printer.

Returns TRUE if successful; FALSE otherwise.

hPrinter | Specifies the name of the printer to which to write the raw data. Identifies an open printer associated with the print processor and must be obtained from a call to OpenPrinter before WritePrinter is called. You must also call StartDocPrinter before the call to WritePrinter. Before making the StartDocPrinter call, set the dwMode member of the DOC_INFO_2 structure to DI_CHANNEL_WRITE to write the given raw data to the port the specified printer is associated with (this may be either a local port or a network port). See the comments in the ReadPrinter function definition for a definition of the DOC_INFO_2 structure.
pBuf | Points to the buffer that contains the raw data to be written to the printer.
cbBuf | Number of characters to print from the buffer.
pcWritten | Points to the variable in which the WritePrinter function returns the number of characters successfully written to the printer.


WinprintPrintDocumentOnPrintProcessor Function

Uses of the different forms of the gdiPlaySpoolStream and ReadPrinter functions are shown in the following pseudo code version of the WinprintPrintDocumentOnPrintProcessor function.

The WinprintPrintDocumentOnPrintProcessor function is supplied two parameters:

  • A handle to the print processor which the caller has obtained with a previous call to WinprintOpenPrintProcessor
  • A pointer to a PRINTPROCESSORDOCUMENTDATA structure, which is defined below.


Data Structure Definitions

The WinprintPrintDocumentOnPrintProcessor function uses two data structures: PRINTPROCESSORDOCUMENTDATA, a pointer to which is given as a parameter, and the global PRINTPROCESSORDATA structure.

typedef struct _PRINTPROCESSORDOCUMENTDATA
{
   LPDEVMODE pDevMode;       // printer device init and status info
   LPTSTR    pDatatype;      // datatype of document
   LPTSTR    pParameters;    // print processor parameters
   LPTSTR    pDocumentName;  //
   DWORD     JobId;          // print job assoc w/ document
   LPTSTR    pOutputFile;    // document spool file
   LPTSTR    pSpoolFileName; // full path to document spool file
   LPTSTR    pSepFile;       // file printed between jobs
}PRINTPROCESSORDOCUMENTDATA

The global PRINTPROCESSORDATA structure is defined below:

typedef struct _PRINTPROCESSORDATA
{
    DWORD   signature;
    DWORD   cb;
    struct _PRINTPROCESSORDATA FAR *pNext;
    DWORD   fsStatus;
    HANDLE  semPaused;
    DWORD   uDatatype;
    HANDLE  hPrinter;
    LPTSTR  pPrinterName;
} PRINTPROCESSORDATA, *PPRINTPROCESSORDATA;


Function Pseudo Code

The logic of the WinprintPrintDocumentOnPrintProcessor function is shown in the following pseudo code. Notice that the ReadPrinter function is used to read the spool file, rather than reading status data from the printer. When the WinprintPrintDocumentOnPrintProcessor function is called, the print processor already has a printer associated with it (has a handle to a printer). However, this handle, which was established in a prior OpenPrintProcessor function call, is used to write to printer.

if not called with a handle this print processor has open then
   set last error to ERROR_INVALID_HANDLE
   return FALSE
endif
if capable of using document datatype passed in
   move datatype into PRINTPROCESSORDATA structure
endif
if capable of using separator file type passed in
   print out the banner that separates this job from previous job
endif
move information about the document from PPRINTPROCESSORDATA structure to local DOC_INFO_2 structure, specifically:
(1) document name
(2) spool file filename
(3) spool file data type
(4) print job ID

call local print provider OpenPrinter function to open the printer that is already associated with the print processor for reading (the spool file).

call local print provider StartDocPrinter function with DI_READ_SPOOL_JOB flag set in JOB_INFO_2 structure to initiate reading of spool file.

if the spool file datatype is raw then
    call the local print processor StartDocPrinter with DI_CHANNEL_WRITE
    flag set in JOB_INFO_2 structure to enable sending spool file
    contents directly to printer through the local print provider.
    (If the spool file datatype is EMF, the print processor will send
    the spool file data through GDI32.)
endif

/* start of loop:
while there is still data to be read in the spool file, call the local print provider ReadPrinter function to read a block of data from the spool file. if the spool file data type is raw, the block of data is then sent directly to the printer by this print processor code; if the spool file data type is EMF, then this print processor code will use the gdiPlaySpoolStream function call to get GDI32 to manage the rendering and sending of the print data to the printer. */

                  while there is still data to be read in the spool file, call the
                  local print provider ReadPrinter function to read a block of data from
                  the spool file.

   trap special case of Print Processor paused between print out of
   pages (one page = one EMF file) and wait until unpaused

   trap special case of Print Processor aborted and document datatype is
   EMF and call GDI32 gdiPlaySpoolStream function to delete metafiles
   and DC
   /* Note the parameter list for this gdiPlaySpoolStream function call.
      This parameter list structure instructs gdiPlaySpoolStream to
      delete the spool file(s) and close the printer DC, etc.

      gdiPlaySpoolStream(
                         NULL,
                         NULL,
                         lpDoc->pSpoolFileName,
                         0,
                         0,
                         hDC);
      break;
   */

   if document datatype is raw, call the print provider WritePrinter
   function to send the spool file data directly to the printer.

   if document datatype is EMF then call GDI32 gdiPlaySpoolStream
   function to playback the EMF file.
   /* Note the structure of the parameter list in the gdiPlaySpoolStream
      function call used to actually render and send data to the printer
      from the EMF spool file. The hDC parameter is NULL the first
      time this function is called.

      hDC = gdiPlaySpoolStream(
                               pData->pPrinterName,
                               lpDoc->pOutputFile,
                               Buffer,
                               lpDoc->JobId,
                               &NoRead,
                               hDC
                               );
   */

      if gdiPlaySpoolStream does not return a DC handle and process the
      first block of spool file data OK, then call the GDI32
      gdiPlaySpoolStream function to delete metafiles.

/* end of loop */

if spool file data type is raw, call the local print provider EndDocPrinter function to end the document printing session.


Reference

This section defines the functions used with print processors. The definitions are presented in alphabetical order by function name.


ClosePrintProcessor

BOOL ClosePrintProcessor(
HANDLE  hPrintProcessor
);

Closes the specified instance of a print processor.

  • Returns TRUE if the operation is successful.
hPrintProcessor A handle to an open instance of a print processor to close.

ClosePrintProcessor frees all resources allocated at the time the instance was open.


ControlPrintProcessor

BOOL  WinprintControlPrintProcessor(
    HANDLE  hPrintProcessor,
    DWORD   Command,
    DWORD   JobId,
    LPTSTR  pDatatype,
    LPTSTR  pSpoolFile
);

Provides control over printing the current document.

  • Returns TRUE if the operation is successful.
hPrintProcessor | A handle to an open instance of a print processor to control.
Command | Commands used in the spooler's default local print processor are:
 | JOB_CONTROL_PAUSE | Pauses the print job.
 | JOB_CONTROL_RESUME | Resumes the print job at the point in the spool file where it was paused.
 | JOB_CONTROL_CANCEL | Cancels the print job.
JobId | Identifies the job associated with the spool file (not used by the default print processor).
pDatatype | Points to a memory location that contains the spool file datatype (PRINTPROCESSOR_TYPE_RAW or PRINTPROCESSOR_TYPE_EMF for the default print processor).
pSpoolFile | Points to the name of the spool file.

Calls to ControlPrintProcessor can occur asynchronously; the function should not wait for the result. For example, the function could set a flag and return immediately.


EnumPrintProcessorDataTypes

BOOL EnumPrintProcessorDatatypes(
    LPTSTR  pName,
    LPTSTR  pPrintProcessorName,
    DWORD   Level,
    LPSTR   pDatatypes,
    DWORD   cbBuf,
    LPDWORD pcbNeeded,
    LPDWORD pcReturned
);

Returns all the data types that the print processor supports.

  • Returns TRUE if the operation is successful.
pName | Specifies the name of the server on which the print processor is installed. On the local machine, the value of this parameter is NULL.
pPrintProcessorName | Points to the name of the print processor. For example, the name of the default print processor is "Winprint."
Level | Specifies the level number of the datatypes information structure to return. For example, if the value of the Level parameter is 1, an array of DATATYPES_INFO_1 structures are returned.
pDatatypes | Points to a buffer in which to return the array of datatype information structures.
cbBuf | Specifies the size, in bytes, of the buffer the pDatatypes parameter points to.
pcbNeeded | Points to the memory location in which the EnumPrintProcessorDataTypes function returns the number of bytes needed to enumerate all the datatypes the print processor supports. If the size of the buffer supplied by the caller is too small (cbBuf is less than the value pointed to by pcbNeeded) then an error message is returned and the caller can use the value pointed to by pcbNeeded to resize the buffer. If the size of the buffer supplied by the caller is adequate, then pcbNeeded points to the number of bytes that were copied into the buffer.
pcReturned | Points to the memory location that contains the number of datatype information structures in the array returned in the buffer pointed to by pDatatypes.


InitializePrintProcessor

BOOL InitializePrintProcessor(
    LPTSTR            pRegisterRoot,
    LPPRINTPROCESSOR  pPrintProcessor
);

Sets up the function pointer table that registers with the spooler all the other entry points provided by the print processor (OpenPrintProcessor, ClosePrintProcessor, ControlPrintProcessor, EnumPrintProcessorDatatypes, and PrintDocumentOnPrintProcessor).

  • Returns TRUE if the operation is successful.
pRegisterRoot | Identifies the initialized print processor.
pPrintProcessor | Points to the PRINTPROCESSOR structure to put the function pointers to this print processor's other functions (OpenPrintProcessor, ClosePrintProcessor, ControlPrintProcessor, EnumPrintProcessorDatatypes, and PrintDocumentOnPrintProcessor).

See the definition of the PRINTPROCESSOR data structure in the WINSPLP.H header file for more information.


OpenPrintProcessor

HANDLE OpenPrintProcessor(
LPTSTR   pPrinterName
);

Opens an instance of the print processor for printing on a specified printer.

  • Returns a handle which the caller can use in subsequent PrintDocumentOnPrintProcessor, ControlPrintProcessor, and ClosePrintProcessor function calls.
pPrinterName Points to the name of the available printer that can be called by WritePrinter.


PrintDocumentOnPrintProcessor

BOOL PrintDocumentOnPrintProcessor(
    HANDLE                        hPrintProcessor,
    LPPRINTPROCESSORDOCUMENTDATA  lpDoc
);

Prints the document.

  • Returns TRUE if the operation is successful.
hPrintProcessor | Handle of the print processor to use.
lpDoc | Points to the name of the document to print on the print processor.

The PrintDocumentOnPrintProcessor function is the heart of any print processor implementation. For that reason, pseudo code that describes the logic of the PrintDocumentOnPrintProcessor function implemented in the sample print processor supplied with the Windows 95 DDK is shown in Sample Print Processor.


PRINTPROCESSORDOCUMENTDATA

typedef struct _PRINTPROCESSORDOCUMENTDATA
{
    LPDEVMODE  pDevMode;
    LPTSTR     pDatatype;
    LPTSTR     pParameters;
    LPTSTR     pDocumentName;
    DWORD      JobId;
    LPTSTR     pOutputFile;      // spool file
    LPTSTR     pSpoolFileName;   // full path + filename
    LPTSTR     pSepFile;         // separator file
} PRINTPROCESSORDOCUMENTDATA, FAR *PPRINTPROCESSORDOCUMENTDATA, FAR

The PRINTPROCESSORDOCUMENTDATA structure holds global data about a document being printed on the print processor. A document is a name for a print job.

pDevMode | Points to a data structure that contains information about the device initialization and environment of a printer.
pDatatype | Points to the datatype of the document.
pParameters | Points to a null-terminated string that specifies print processor parameters.
JobId | Identifies the print job associated with the document.
pOutputFile | Points to the document spool file.
pSpoolFileName | Points to the full path and file name of the spool file.
pSepFile | Points to the file printed between print jobs.


Port Monitors

A port monitor controls the I/O port to which the physical printer is connected. For more information about the role of port monitors in the Windows 95 print spooler subsystem, see Typical Printing Process Scenario Using a Raw Spool File.

The local print monitor executable supplied by Microsoft controls parallel and serial I/O ports that may have a printer connected to them. A printer vendor needs to develop a port monitor if their printer connects to a different type of I/O port, such as a SCSI port or an Ethernet port on a network card in the local computer.

If your printer is connected to a parallel (or serial) port and you want to add data, such as printer control information, to the print stream going to the printer then develop a language monitor to do this and use the Microsoft-provided default port monitor instead of developing a port monitor of your own. When a language monitor is associated with a printer driver at printer installation time, all print data that flows from the printer driver to the printer goes through the language monitor before it goes through the port monitor and out to the printer. For information on how to use INF files to associate your custom language monitor with a printer driver at printer installation time, see Printer INF File Extensions.

Sample source code for a port monitor is provided in the Windows 95 DDK. After the Windows 95 DDK is installed, the sample port monitor source code is in the directory \%DDKROOT%\PRINTER\SAMPLES\SPOOLER\LOCALMON.


Local Port Monitor Design and Implementation Notes

A local port monitor isolates the spooler from printer port characteristics by presenting idealized printer ports to the spooler. The local port monitor supplied by Microsoft is the spooler system component that monitors the flow of print job data through physical parallel or serial ports. The local print monitor presents idealized ports to the spooler by masking the difference between parallel and serial ports, serializing I/O, and providing automatic buffering services. The local port monitor can also be used to multiplex one physical port to multiple virtual ports, each having a separate name and behavior.

A Windows 95 port monitor must offer half a dozen entry points to monitor printers connected to ports and send print job data through ports. The local monitor's OpenPort function is called at spooler startup for all ports with assigned printers and, if necessary, when another printer is added to the spooler's environment. The ClosePort function is called at spooler shutdown and may be called when a printer is removed form the spooler's environment. The ReadPort function is called to read status information from connected bidirectional printers.

The StartDocPort function is called to setup the port to send print job data to the printer, a sequence of one or more WritePort function calls provide the print job data the port monitor sends to the printer, and an EndDocPort function call is called when there is no more data to send for the print job.

The local port monitor must also provide four entry points that perform port management. The AddPort function is called when the spooler wants to add a port to its environment and the DeletePort function is called when the spooler wants to remove a port from its environment. The spooler calls the ConfigurePort function to configure a port and may offer a user interface to get some of the necessary configuration information. The spooler calls the EnumPorts function to get a list of ports currently maintained by the port monitor.


Required Functions

The following table describes the entry points that are exported by the port monitor.

Entry Point/Description | Comment
AddPort: A port management function that adds a port to the list of currently supported ports in the spooler environment. | Called by the spooler in order to add a port to the set of ports maintained by your monitor. The spooler calls this entry point when the user chooses the AddPort button from the Windows 95 Printer Properties dialog. You may have to implement user interface code to get all the information your AddPort function needs to create a port.
ClosePort: Closes a previously-opened port when no printers are connected to the port. | Called by the spooler to enable your monitor to clean up any resources, such as data structures, that are associated with one of the ports your port monitor is maintaining.
ConfigurePort: A port management function that configures the specified port. If the port is a COM port, configures the baud rate. If the port is a parallel port, configures retry parameters. If the port is a network port, may change the port address. | Called by the spooler when the user chooses the Port Settings button from the Windows 95 Printer Properties dialog. This enables your port monitor to present a user interface that allows a user to configure one of the ports maintained by your port monitor.
DeletePort: A port management function that frees the port monitor of any responsibility for managing the port or monitoring print jobs on the port. | Called by the spooler when the user chooses the Delete Port button from the Windows 95 Printer Properties dialog. When the DeletePort function is called in your port monitor, it should delete all knowledge of the specified port from your port monitor. This function will never be called when the specified port is in use (opened).
EndDocPort: Performs end-of-print-job tasks on the specified port. | EndDocPort is called after all the data in a print job has been passed to your port monitor using WritePort function calls.
EnumPorts: A port management function that provides a list of all the ports available for printing on the local machine through your port monitor. | Called by the spooler to get the list of ports maintained by your port monitor. The spooler calls all installed monitors in turn to build up a list of all the available ports.
GetPrinterDataFromPort: Gets data from a bidirectional printer by providing IEEE 1284 support. |
InitializeMonitorEx: Sets up the function pointer table that registers with the spooler all the other entry points provided by your port monitor. | Your port monitor should establish function pointers for a set of port management functions (AddPort, ConfigurePort, DeletePort, and EnumPorts) and a set of printer and print job monitoring functions (OpenPort, ClosePort, StartDocPort, EndDocPort, WritePort, and ReadPort).
OpenPort: Opens the specified port. | When the OpenPort function is called, it should set up all resources, such as initialized data structures, needed to print to the specified port.
ReadPort: Reads data from the printer. | The ReadPort function is called to get information from a bidirectional printer. If your ReadPort function can read data from the printer, it should return that raw data to the caller (which is probably a language monitor). If your ReadPort function cannot read any data from the printer within some appropriate time interval, it should return a failure code.
SetPortTimeOuts: Sets a time out value on an open port. |
StartDocPort: Performs the tasks it takes to start a print job on the specified port. | The StartDocPort function is called at the start of a print job. The StartDocPort function in your port monitor should setup whatever is needed for your port monitor to print the data that will be provided in subsequent WritePort and any subsequent ReadPort function calls.
WritePort: Writes data to the printer. | The WritePort function is called repeatedly to send blocks of data to the printer. The WritePort function in your port monitor can call the SetJob function to modify print job state information.


Sample Port Monitor

The default port monitor provided by Microsoft in Windows 95 is part of the spooler subsystem DLL. If you need to develop another port monitor, you need to package it as a separate DLL callable by the spooler subsystem. The Reference section of this section names the APIs that your DLL needs to export to be called by the spooler subsystem, and defines the members of the data structures the spooler subsystem uses to share information with a port monitor.

Only two APIs have to be exported by a port monitor such that they appear in the .DEF file for the monitor: InitializeMonitorEx and DllEntryPoint. The InitializeMonitorEx code loads the addresses (function pointers) of the other port monitor functions that the local print provider calls. For an example, see the InitializeMonitorEx function code in the sample port monitor code provided with the Windows 95 DDK. All the functions that the local print provider expects to call through the function pointer table are defined in the reference section.

The sample port monitor code is located in the SAMPLES directory after you install the Windows 95 DDK.


Reference

The following section of this section describes the functions listed in the preceding table. The descriptions are presented in alphabetical order by the name of the function or data structure.

All the port monitor functions return FALSE if the operation is unsuccessful. There are cases where the caller of a port monitor should call the Win32 API SetLastError before calling the port monitor function. This will enable the local spooler process to use the Win32 API GetLastError to get information about the cause of the failure and, for example, prompt the user.


AddPort

BOOL AddPort(
    LPTSTR   pName,
    HWND     hWnd,
    LPTSTR   pMonitorName
);

A port management function that adds a port to the list of currently supported ports in the spooler environment.

  • Returns TRUE if the operation is successful.
pName | Points to a zero-terminated string that specifies the name of the server to which the port is connected. If this string is NULL, the port is local.
hWnd | A handle to the parent window of the dialog box used by the AddPort function.
pMonitorName | Points to a zero-terminated string that specifies the monitor associated with the port.

The port monitor function AddPort browses the network to find existing ports and displays a dialog box for the user to get information needed to create the port. Your implementation of the AddPort function should call the EnumPorts function to validate the port name entered by the user to ensure no duplicate port names are added to the spooler environment.


ClosePort

BOOL ClosePort(
     HANDLE  hPort
);

Closes a previously-opened port when no printers are connected to the port.

Returns TRUE if the operation is successful.

hPort The handle of a port previously opened by a call to the OpenPort function.

The ClosePort function is called by the spooler to enable your monitor to clean up any resources, such as data structures, that are associated with one of the ports your port monitor is maintaining.


ConfigurePort

BOOL ConfigurePort(
    LPTSTR  pName,
    HWND    hWnd,
    LPTSTR  pPortName
);

A port management function that configures the specified port. If the port is a COM port, configures the baud rate. If the port is a parallel port, configures retry parameters. If the port is a network port, may change the port address.

  • Returns TRUE if the operation is successful.
pName | Points to a zero-terminated string that names the server on which the port named in the pPortName parameter exists.
hWnd | Handle to the parent window of the port-configuration dialog.
pPortName | Points to a zero-terminated string that names the port to be configured.

The ConfigurePort function is called by the spooler when the user chooses the Settings button from the Properties dialog. This enables your port monitor to present a user interface that allows a user to configure one of the ports maintained by your port monitor.


DeletePort

BOOL DeletePort(
    LPTSTR  pName,
    HWND    hWnd,
    LPTSTR  pPortName
);

A port management function that frees the port monitor of any responsibility for managing the port or monitoring print jobs on the port.

Returns TRUE if the operation is successful.

pName | Points to a zero-terminated string that names the machine on which the port specified in the pPortName parameter exists.
hWnd | Handle to the parent window of the port deletion dialog box.
pPortName | Points to a zero-terminated string that names the port to be deleted.

The DeletePort function is called when the spooler decides to delete a port from its environment. The port monitor is responsible for actually performing the deletion. The DeletePort function should delete all knowledge of the specified port from the port monitor state.

The DeletePort function will never be called when the specified port is in use (opened).


EndDocPort

BOOL EndDocPort(
HANDLE   hPort
);

Performs end-of-print-job tasks on the specified port.

  • Returns TRUE if the operation is successful.
hPort Handle of the port the document was printed on.

The port monitor function EndDocPort should free resources allocated by the previous call to StartDocPort.

EndDocPort is called after all the data in a print job has been passed to your port monitor using WritePort function calls. The EndDocPort function in your port monitor should call the SetJob function to delete the completed job from the queue when printing has been completed on the port.


EnumPorts

BOOL EnumPorts(
    LPTSTR   pName,
    DWORD    Level,
    LPBYTE   pPorts,
    DWORD    cbBuf,
    LPDWORD  pcbNeeded,
    LPDWORD  pcReturned
);

A port management function that provides a list of all the ports available for printing on the local machine through your port monitor. The spooler calls all installed monitors in turn to build up a list of all the available ports.

Returns TRUE if the operation is successful.

pName | Specifies the name of the machine on which to enumerate the ports. This parameter is set to NULL for the local machine.
Level | Specifies the version of the structure to which the pPorts parameter points. This value must be 1 or 2.
pPorts | Points to a buffer into which to copy the array of PORT_INFO_1 or PORT_INFO_2 structures that describe all the available ports.
cbBuf | Specifies the size of the buffer, in bytes, supplied by the caller and to which the pPorts parameter points.
pcbNeeded | Points to a value containing the required buffer size to return all of the port enumeration information (the array of PORT_INFO_1 or PORT_INFO_2 structures). If the cbBuf parameter value specified by the caller is too small, EnumPorts sets GetLastError to ERROR_INSUFFICIENT_BUFFER and the caller can obtain the number of bytes required from the memory location pointed to by pcbNeeded. If the cbBuf parameter value is sufficient to hold all the port enumeration information, then pcbNeeded points to the number of bytes actually used in the buffer.
pcReturned | Points to a variable that contains the number of PORT_INFO_1 or PORT_INFO_2 structures returned in the buffer pointed to by the pPorts parameter.

The machine does not need to have a printer defined for this function to work.


GetPrinterDataFromPort

BOOL GetPrinterDataFromPort(
    HANDLE   hPort,
    DWORD    ControlID,
    LPTSTR   pValueName,
    LPTSTR   lpInBuffer,
    DWORD    cbInBuffer,
    LPTSTR   lpOutBuffer,
    DWORD    cbOutBuffer,
    LPDWORD  lpcbReturned
);

Gets data from a bidirectional printer by providing IEEE 1284 support.

  • Returns TRUE if the operation is successful.
hPort | The handle of the port to which the bidirectional printer is connected.
ControlID | Specifies the control code for the operation.
pValueName | Ignored by the port monitor.
lpInBuffer | Points to a buffer containing the data required to perform the operation. This parameter can be NULL if the ControlID parameter specifies an operation that does not require input data.
cbInBuffer | Size of the input buffer, in bytes.
lpOutBuffer | Points to a buffer in which to return the specified operation's output data. This parameter can be NULL if the ControlID parameter specifies an operation that does not produce output data.
cbOutBuffer | Size of the output buffer, in bytes.
lpcbReturned | Points to a variable that receives the actual size, in bytes, of the output data returned in the output buffer.

The GetPrinterDataFromPort function can be used to make any IEEE 1284 specification IOCTL call.


InitializeMonitorEx

BOOL InitializeMonitorEx(
    LPTSTR     pRegisterRoot,
    LPMONITOR  pMonitor
);

Sets up the function pointer table that registers with the spooler all the other entry points provided by your port monitor. Your port monitor should establish function pointers for a set of port management functions (AddPort, ConfigurePort, DeletePort, and EnumPorts) and a set of printer and print job monitoring functions (OpenPort, ClosePort, StartDocPort, EndDocPort, WritePort, and ReadPort).

  • Returns TRUE if the operation is successful.
pRegisterRoot | A string which is the full registry path to a key under HKEY_LOCAL_MACHINE where the port monitor may store monitor-specific data for its own use. If the port monitor is deleted, the Windows 95 spooler will delete this registry key; the monitor does not need to do it.
pMonitor | Points to a MONITOR structure in which to set the pointers.

See the definition of the MONITOR structure data structure for more information. This structure is defined in the WINSPLP.H header file supplied with the DDK and is documented in About Language Monitors.


OpenPort

BOOL OpenPort(
    LPTSTR    pName,
    LPHANDLE  pHandle
);

Opens the specified port.

  • Returns TRUE if the operation is successful.
pName | Points to a port name.
pHandle | Points to the memory location into which to put the handle to the opened port.

The port monitor does not need to know the name of the printer that is connected to a port when OpenPort is called, the printer name will be supplied in a subsequent StartDocPort function call.

Note the difference between the port monitor OpenPort function parameter list and the language monitor OpenPortEx function parameter list which specifies both a port name and a printer name.


ReadPort

BOOL ReadPort(
    HANDLE   hPort,
    LPBYTE   pBuffer,
    DWORD    cbBuf,
    LPDWORD  pcbRead
);

Reads data from the printer.

  • Returns TRUE if the operation is successful.
hPort | Handle of the port to read.
pBuffer | Points to the buffer into which to read the data.
cbBuf | Specifies the size, in bytes, of the buffer pointed to by the pBuffer parameter.
pcbRead | The number of bytes read is put into the memory location pointed to by this parameter.

The ReadPort function supports bidirectional printers. If there is any data in the printer, the ReadPort function returns all the data. If there is no response from the printer, the ReadPort function waits long enough to ensure that there is no data coming from the printer and then returns an error.

The port monitor ReadPort function is called by a language monitor, which is the only component of the spooler subsystem that is capable of interpreting the data read from the printer. A language monitor can create a thread to asynchronously call the port monitor ReadPort function to query unsolicited data from the printer at timed intervals of say, a few seconds.

The port monitor ReadPort function must not alter the data stream read from the printer in any way, but just return it to the language monitor caller for interpretation.

The printer driver that is associated with the language monitor that interprets the data read from the printer can get that information by calling the new Windows 95 GDI functions DrvGetPrinterData and DrvSetPrinterData. Following are guidelines for calling DrvGetPrinterData and DrvSetPrinterData in your printer driver:

  • Your printer driver must be reentrant.
  • Do not use DrvGetPrinterData or DrvSetPrinterData calls within the printer driver Enable or Disable functions.
  • The ideal places to use DrvGetPrinterData or DrvSetPrinterData calls are in the printer driver DevInstall function or when the printer driver ExtDeviceMode function is called with the DM_Prompt flag set in the wMode parameter (at which time the driver is reentrant and ExtDeviceMode is not being called by the Enable function).


SetPortTimeOuts

BOOL SetPortTimeOuts(
    HANDLE          hPort,
    LPCOMMTIMEOUTS  lpCTO,
    DWORD           reserved    // must be set to 0
);

Sets time out values on an open port.

  • Returns TRUE if the operation is successful.
hPort | The handle of the port on which to set the time out values.
lpCTO | Points to a communications timeout (COMMTIMEOUTS) structure that contains the timeout values to set.
reserved | Reserved for future use. Must be set to 0.

The COMMTIMEOUTS structure definition is shown below:

typedef struct _COMMTIMEOUTS {
    DWORD  ReadIntervalTimeout;
    DWORD  ReadTotalTimeoutMultiplier;
    DWORD  ReadTotalTimeoutConstant;
    DWORD  WriteTotalTimeoutMultiplier;
    DWORD  WriteTotalTimeoutConstant;
} COMMTIMEOUTS, *LPCOMMTIMEOUTS;

For a full definition of each of the members of the COMMTIMEOUTS structure, see the Win32 Software Development Kit (SDK). Brief definitions for each of the members of the COMMTIMEOUTS structure are:

ReadIntervalTimeout | Specifies the maximum time, in milliseconds, allowed to elapse between the arrival of two characters. A value of 0 indicates interval time-outs are not to be used.
ReadTotalTimeoutMultiplier | The multiplier value, in milliseconds, used to calculate the total timeout period for read operations. For each read operation, this value is multiplied by the requested number of bytes.
ReadTotalTimeoutConstant | The constant value, in milliseconds, used to calculate the total timeout period for read operations. For each read operation, this value is added to the product of the value in ReadTotalTimeoutMultiplier and the requested number of bytes.
WriteTotalTimeoutMultiplier | The multiplier value, in milliseconds, used to calculate the total timeout period for write operations. For each write operation, this value is multiplied by the number of bytes to be written.
WriteTotalTimeoutConstant | The constant value, in milliseconds, used to calculate the total timeout period for write operations. For each write operation, this value is added to the product of the value in WriteTotalTimeoutMultiplier and the number of bytes to be written.


StartDocPort

BOOL StartDocPort(
    HANDLE  hPort,
    LPTSTR  pPrinterName,
    DWORD   JobId,
    DWORD   Level,
    LPBYTE  pDocInfo
);

Performs the tasks it takes to start a print job on the specified port.

  • Returns TRUE if the operation is successful.
hPort | The handle of the port to which the print job is being sent.
pPrinterName | Points to the zero-terminated string that is the name of the printer to which the job is being sent.
JobId | Identifies the job being sent to the spooler.
Level | The job level.
pDocInfo | Points to the document information.

The StartDocPort function is called at the start of a print job. The StartDocPort function in your port monitor should setup whatever is needed for your port monitor to print the data that will be provided in subsequent WritePort function calls.


WritePort

BOOL WritePort(
    HANDLE   hPort,
    LPBYTE   pBuffer,
    DWORD    cbBuf,
    LPDWORD  pcbWritten
);

Writes data to the printer.

  • Returns TRUE if the operation was successful. If unsuccessful, returns FALSE and continues, as a background thread, to try the write operation to the port. WritePort expects the caller to display a dialog that informs the user of the unsuccessful write operation.
hPort | The handle of the port to which to write the data.
pBuffer | Points to the buffer that contains the data to be written.
cbBuf | The size of the buffer, in bytes, pointed to by the pBuffer parameter.
pcbWritten | Points to a memory location in which to put the number of bytes written.

The port monitor WritePort function sends the data in the buffer pointed to by pBuffer to the printer. If an error is returned, the spooler displays a dialog box.

The WritePort function is called repeatedly to send blocks of data to the printer. The WritePort function in your port monitor can call the SetJob function to modify print job state information.


Language Monitors

There are two types of print monitors: language monitors and port monitors. Port monitors are described in About Port Monitors. For overview information about the relationship between a language monitor and a port monitor during the printing process, see Typical Printing Process Scenario Using a Raw Spool File.

Note The illustrations in Typical Printing Process Scenario Using a Raw Spool File show the language monitor and port monitor as separate components (each packaged in a separate DLL). However, if your language monitor calls only one particular port monitor, it may be to your advantage to build one component (one DLL) that integrates the language monitor and port monitor functionality. If your language monitor might call more than one port monitor, package the language monitor in a DLL separate from any of the port monitors.

Language monitors are typically necessary only for bidirectional printer devices. A bidirectional printer supports two-way communication between the printer and code running on the computer to which the printer is connected.

The two-way communication between computer and printer is used to configure the printer and to monitor printer status. The code running on the computer can request configuration and status information from the printer and/or the printer can send unsolicited status information to the computer whenever certain events occur on the printer. For the printer to understand the requests from the computer and for the computer to understand either solicited or unsolicited responses from the printer, a language has to be defined. For example, an HP LaserJet 4Si is an example of a bidirectional printer device and the printer job language (PJL) is a language that implements all the bidirectional communication functionality mentioned in this paragraph.

A language monitor can also be used to add data, such as printer control information, to the print stream going to the printer. When a language monitor is associated with a printer driver at printer installation time, all print data that flows from the printer driver to the printer goes through the language monitor before it goes through the port monitor and out to the printer. For information on how to use INF files to associate your custom language monitor with a printer driver at printer installation time, see Printer INF File Extensions.

An important implementation detail is that when the language monitor returns to the printer driver after adding bytes (such as printer control information) to the print stream, the language monitor must not increment the byte count of data sent to printer. For example, if the printer driver sends 1K bytes to the printer and the language monitor adds .25K bytes of information to the data stream before it goes to the port monitor and out to the printer, then when the language monitor returns to the printer driver, it must report that 1K bytes were sent to the printer, not 1.25K bytes.

Sample source code for a language monitor is provided in the Windows 95 DDK. After the Windows 95 DDK is installed, the sample language monitor source code is in the \%DDKROOT%\PRINTER\SAMPLES\SPOOLER\PJLMON directory.


Language Monitor Design and Implementation Notes

If your printer is bidirectional, you may develop a language monitor for the printer. The source code for a PJL language monitor is included in the Windows 95 DDK which you can use as a starting point for developing your own language monitor. For a full definition of the PJL language, see the Hewlett-Packard publication PJL Technical Reference Manual, Edition 5, September 1994.


Language Monitor and Port Monitor Relationships

In general, port monitor components deal with the relatively low-level communications protocol between the printer and computer. Language monitors deal with a higher-level communications exchange between printer and computer, as described in the section above.

Fundamental ideas about monitor components in the Windows 95 spooler architecture are:

  • At least one port monitor component is required for the spooler to output print jobs, while language monitors are completely optional.
  • Only port monitors send and receive signals through the hardware port a printer is connected to.
  • Only language monitors are able to parse the strings of data read from a port with a bidirectional printer attached. The language monitor calls the port monitor ReadPort or GetPrinterDataFromPort functions to get data from a bidirectional printer. The port monitor ReadPort and GetPrinterDataFromPort functions read any data available from the printer and pass that data back to the language monitor without changing it in any way and it is up to the language monitor to interpret the meaning of the data from the printer. The language monitor should use a GetPrinterDataFromPort function call if the bidirectional printer supports the IEEE 1284 standard; otherwise, it should use a ReadPort call. The language monitor can call either of these port monitor functions from a background thread on a periodic basis (say every few seconds), using a timer, to read unsolicited status information from a bidirectional printer. The source code for the sample language monitor supplied with the DDK, PJLMON, contains code that implements reading unsolicited printer status information in this way.

The spooler architecture diagram in Typical Printing Process Scenario Using a Raw Spool File illustrates these principles. It shows a spooler with one port monitor and one language monitor, and only the port monitor sends and receives through the hardware port. A diagram that showed the relationship between spooler components when the only local target printer is nonbidirectional would probably not show a language monitor component.

Note that it is possible to integrate the language monitor functionality and port monitor functionality into one component.


Required Functions

In addition to LibMain, a language monitor must export only one other function: InitializeMonitorEx. The InitializeMonitorEx function initializes a MONITOR structure with a set of pointers to other functions that the language monitor provides to other spooler components.

Port monitors as well as language monitors have an InitializeMonitorEx function, which uses a MONITOR structure for the same purpose. So function names, each function parameter list, and function value data type and meaning are the same for language monitors as for port monitors, with the exception of the OpenPort function. Port monitors point to an OpenPort function in their function pointer table and language monitors point to OpenPortEx.

Note The functions names InitializeMonitorEx and OpenPortEx are used in the Windows 95 monitors to differentiate them from the InitializeMonitor and OpenPort monitor functions in the Windows NT/Windows 2000 spooler. This is done because in these two cases, the parameter lists of the Windows 95 function and the comparable Windows NT/Windows 2000 function are incompatible.

The InitializeMonitorEx and OpenPortEx functions and the MONITOR structure are documented in Reference. For documentation on the other functions a language monitor offers the other spooler components, see About Port Monitors.


Installing a Language Monitor

For information on how to install a new language monitor in Windows 95, see Printer INF File Extensions.


Sample Language Monitor

This section describes the sample PJL language monitor source code shipped with the Windows 95 DDK. The source code builds an executable named PJLMON.DLL, so the sample language monitor will be called PJLMON in this section.

After the Windows 95 DDK is installed, the sample language monitor source code is in the \%DDKROOT%\PRINTER\SAMPLES\SPOOLER\PJLMON directory.

The C source code modules and their header files that make up the sample language monitor PJLMON are identified and briefly described in the following table. If you are developing a different language monitor, suggestions on how you might use each of the modules are also in the following table. Note that an object module, PARSEPJL.OBJ, is also part of the sample language monitor. This object module parses the data read from the printer, using PJL language rules. PARSEPJL.OBJ is included in the sample language monitor directory to enable you to build the language monitor. When you develop the object module that parses the printer status language your printer uses, you will have to substitute it for PARSEPJL.OBJ when you build your language monitor.

Source Module Name/Description | Comment
PJLMON.C |
Contains the InitializeMonitorEx and LibMain functions and all of the functions that InitializeMonitorEx puts pointers to in the MONITOR structure. | Contains two functions, CreateUstatusThread and UstatusThread, that manage the thread that handles unsolicited responses from the printer. The IsPJL and Find1284Key that determine if the printer connected to the port is bidirectional and if it is PJL-capable. Another interesting set of functions is ProcessPJLString, InterpretTokens, and ProcessParserError, which are the callers of the working parser functions in PARSEPJL.C.
UTILLM.C |
Utility functions that provide memory allocation, string handling, semaphore management, and debugging services. | Contains a function that finds a particular PINIPORT structure in an array of such structures.
SPLTYPES.H |
Header file for PJLMON.C | Defines the PINIPORT structure, which the sample language monitor uses to keep track of the status of the port being monitored. You may want to change the contents of this structure. This header file also defines PP_* constants which define the bit positions in the status member of the PINIPORT structure (port is open, sending data to the printer, PJL command was sent to printer, etc.).
LOCAL.H |
Header file for UTILLM.C |


Reference

The following topics describe the functions and structures used with language monitors that differ from the functions and structures used by port monitors.

GetPrinterDataFromPort

BOOL GetPrinterDataFromPort(
    HANDLE   hPort,
    DWORD    ControlID,
    LPTSTR   pValueName,
    LPTSTR   lpInBuffer,
    DWORD    cbInBuffer,
    LPTSTR   lpOutBuffer,
    DWORD    cbOutBuffer,
    LPDWORD  lpcbReturned
);

Gets data from a bidirectional printer by providing IEEE 1284 support.

  • Returns TRUE if the operation is successful.
hPort | The handle of the port to which the bidirectional printer is connected.
ControlID | Specifies the control code for the operation.
pValueName | A string that contains a name understood by both the language monitor and the printer driver with which it was associated at printer installation time. Since both the language monitor and printer driver are developed by a printer vendor, the developer can define a set of values for this pValueName parameter which the language monitor can interpret as requests for bidirectional printer status from the printer driver.
lpInBuffer | Points to a buffer containing the data required to perform the operation. This parameter can be NULL if the ControlID parameter specifies an operation that does not require input data.
cbInBuffer | Size of the input buffer, in bytes.
lpOutBuffer | Points to a buffer in which to return the specified operation's output data. This parameter can be NULL if the ControlID parameter specifies an operation that does not produce output data.
cbOutBuffer | Size of the output buffer, in bytes.
lpcbReturned | Points to a variable that receives the actual size, in bytes, of the output data returned in the output buffer.

The GetPrinterDataFromPort function can be used to make any IEEE 1284 specification IOCTL call.

The language monitor GetPrinterDataFromPort function is called by the printer driver associated with the language monitor at printer installation. If the language monitor does not have the bidirectional printer status information requested by the printer driver, the language monitor can call the port monitor GetPrinterDataFromPort or ReadPort function to get current printer status information.


InitializeMonitorEx

BOOL InitializeMonitorEx(
    LPTSTR     pRegisterRoot,
    LPMONITOR  pMonitor
);

Sets up the function pointer table that registers with the spooler all the other entry points provided by the language monitor (AddPort, ClosePort, ConfigurePort, EnumPorts, OpenPort, ReadPort, StartDocPort, and WritePort).

  • Returns TRUE if the operation is successful.
pRegisterRoot | Points to a string which is the path to a location in the registry where the language monitor can store internal information. The spooler will use this parameter value when the monitor is delete to go to the specified location in the registry and delete any information there.
pMonitor | Far pointer to a MONITOR structure in which to set the function pointers.

See the definition of the MONITOR structure data structure for more information. This structure is defined in the WINSPLP.H header file supplied with the DDK.


MONITOR

typedef struct _MONITOR {
     BOOL (WINAPI *pfnEnumPorts)(LPTSTR pName,DWORD Level,LPBYTE  pPorts,
         DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned);
    BOOL (WINAPI *pfnOpenPort)(LPTSTR  pName,PHANDLE pHandle);
    BOOL (WINAPI *pfnOpenPortEx)(LPTSTR  pPortName,
        LPTSTR  pPrinterName, PHANDLE pHandle, struct _MONITOR
        FAR *pMonitor);
    BOOL (WINAPI *pfnStartDocPort)(HANDLE  hPort, LPTSTR  pPrinterName,
        DWORD   JobId, DWORD   Level, LPBYTE  pDocInfo);
    BOOL (WINAPI *pfnWritePort)(HANDLE  hPort, LPBYTE  pBuffer,
        DWORD   cbBuf, LPDWORD pcbWritten);
    BOOL (WINAPI *pfnReadPort)(HANDLE hPort, LPBYTE pBuffer,
        DWORD  cbBuffer, LPDWORD pcbRead);
    BOOL (WINAPI *pfnEndDocPort)(HANDLE   hPort);
    BOOL (WINAPI *pfnClosePort)(HANDLE  hPort);
    BOOL (WINAPI *pfnAddPort)(LPTSTR   pName, HWND    hWnd,
        LPTSTR   pMonitorName);
    BOOL (WINAPI *pfnConfigurePort)(LPTSTR   pName, HWND  hWnd,
        LPTSTR pPortName);
    BOOL (WINAPI *pfnDeletePort)(LPTSTR   pName, HWND    hWnd,
        LPTSTR   pPortName);
    BOOL (WINAPI *pfnGetPrinterDataFromPort)(HANDLE hPort,
        DWORD ControlID, LPTSTR  pValueName, LPTSTR  lpInBuffer,
        DWORD   cbInBuffer, LPTSTR  lpOutBuffer, DWORD   cbOutBuffer,
        LPDWORD lpcbReturned);
    BOOL (WINAPI *pfnSetPortTimeOuts)(HANDLE  hPort,
        LPCOMMTIMEOUTS lpCTO, DWORD reserved);
} MONITOR, FAR *LPMONITOR;

When InitializeMonitorEx is called to initialize a language monitor, the caller provides a pointer to an empty MONITOR structure, which is filled in and returned by the language monitor.


OpenPortEx

BOOL OpenPortEx(
    LPTSTR     pPortName,
    LPTSTR     pPrinterName,
    LPHANDLE   pHandle,
    LPMONITOR  pMonitor
);

Opens a port for exchange of bidirectional information with the printer connected to a physical port that is managed by port monitor.

  • Returns TRUE if the operation is successful.
pPortName | Points to the name of the port to open (provided by the caller).
pPrinterName | Points to the name of the printer that is the destination of the print job (provided by the caller).
pHandle | Points to the memory location into which to put the handle to the opened port.
pMonitor | Points to a MONITOR structure.

The port handle that the language monitor puts in the location pointed to by pHandle is used by the print provider in subsequent calls to StartDocPort, WritePort, ReadPort, and EndDocPort.


Image Color Matching and Printer Drivers in Windows 95

This document provides an overview of how device color characterization profiles are installed, referenced in the registry, and selected and associated with printer drivers by Microsoft® Windows® 95 at run time. The Image Color Matching (ICM) technology provided with Windows 95 uses the industry standard ICC (International Color Consortium) version 3.0 specification for device color characterization profiles together with some Windows-specific optional tags in the profiles themselves. This document is not intended to be a replacement for the Windows 95 DDK documentation, but rather as a supplemental summary of those areas effecting printer support and ICM.


Overview

This document is broken down into several topics:

  • How to install color printer profiles.
  • How to use the ICC version 3.0 profile tags recognized by Windows 95.
  • How Windows 95 selects an ICC profile to use at run-time.
  • How ICM information is created and maintained in the registry.


Installing Color Profiles

Printer installation for Windows 95 is ideally driven by INF files to enable support of Plug and Play. The information below discusses how to reference an ICC profile (or profiles) within an INF file and describes the process that the printer setup code goes though to complete profile installation.


Adding Elements to the Printer INF File

An INF file that installs a printer can include a color profile for the printer with two added elements:

  • The name of the profile specified in the list of dependent files for the printer (which will allow the profile to be propagated/copied along with other printer driver files for "point and print" printer driver installation in Windows 95).
  • The destination directory for the profile specified as the \Windows\System\Color directory.

Further information and examples for each of these elements is given in the sections below.


Including the Profile in the Dependent File List

The color profile must be included in the list of dependent files (that is, included in the CopyFiles= list entry in the INF file). For general information about Windows 95 INF files, see About INF Files and the INF File Editor. For an example CopyFiles= list entry that includes a color profile, see the entry for the Kodak® ColorEase printer in the MSPRINT.INF file.

Multiple color profiles, which are used for different media types or driver configurations, can be included in the list of dependent files.


Copying the Profile to the Correct Subdirectory

The color profile must copied to the \Windows\System\Color directory. For an example of a qualified directory name in the INF file, see the entry for the Kodak ColorEase printer in the MSPRINT.INF file.


How the Installation Process Works

Assuming that the printer INF file is modified as outlined above, the printer setup code will detect all dependent files that should be copied to the \Windows\System\Color directory and call the UpdateICMRegKey function to attempt to install the color profile in the registry. No other action is taken by the printer setup code. For the profile to be installed correctly, the profile contents must contain the tags described in Overview of ICC 3.0 Profile Tags Used by Windows 95.


Overview of ICC 3.0 Profile Tags Used by Windows 95

For ICC version 3.0 color profiles to be used with Windows 95, a profile must support some tags and can, optionally, support some additional tags for greater flexibility. Information discussing how printer drivers map to various profiles is discussed in Mapping Color Profiles to Printer Drivers.


Required ICC Tag Values

Two tags in an ICC color profile are required for installation. (While these are the only tags used for profile installation, other profile tags are required to perform color matching after the installation is done.) The two tags required for installation are used to indicate the printer manufacturer and the specific model of printer from the manufacturer that the color profile is designed for. Windows 95 needs this information to associate Windows device drivers with profiles. Windows assigns no intrinsic meaning to the tags themselves; they are used in Windows to map between profiles and device drivers.


Using the icHeader.manufacturer Tag

The icHeader.manufacturer tag is of type icSignature (a four-byte identifier value according to the ICC specification). The 4 bytes contain ASCII values; they are typically the first 4 characters of name of the printer manufacturer and, most importantly, are unique from other company names and correspond to the name that is used/reported by the printer driver. (For a more detailed discussion of how profiles and drivers are paired at run time, see Mapping Color Profiles to Printer Drivers. Examples values for this tag are "EPSO" for Epson, "CANO" for Canon, "HP " for Hewlett-Packard, and so on.

The deviceMfgDescTag value is also read and placed in the registry under the ManufacturerTag key for clarity even though it serves no functional purpose there.


Using the icHeader.model Tag

The icHeader.model tag is of type icUInt32Number (an unsigned 32-bit identifier value according to the ICC specification). The 4 bytes are the identifier used to distinguish various printer models. The identifier must be unique for each model of printer that has identical icHeader.manufacturer tags and correspond to the name that is used/reported by the printer driver. (For a more detailed discussion of how profiles and drivers are paired at run time, see Mapping Color Profiles to Printer Drivers. The deviceModelDescTag value is also read and placed in the registry under the ModelTag key for clarity even though it serves no functional purpose there.


Optional Tag Values

Specifying icHeader.manufacturer and icHeader.model tags is all that is needed to install a single ICC profile for a given device. However, because a device may produce measurably varied results for the same color profile when configured differently, it may be useful to map multiple profiles for different configurations of the device. The optional profile tags described later in this section make this mapping possible when the printer configuration changes at run time.

The number of possible profiles directly maps to the matrix of possible configurations of the device. The issue of how profiles are chosen if an incomplete matrix of profiles is installed is discussed in a later section. For example, a printer model with 2 possible media types, 2 possible dither/halftone types, and 2 possible resolutions could have as many as 8 different profiles (2x2x2). Because profiles may not exist for each combination of configuration possibilities, there can be "an incomplete matrix of profiles."

Using optional tags enables Windows to differentiate printer configurations based on these variables, and the values these tags assume are closely tied to how the device driver reports these configuration differences to Windows itself. The optional tags correspond to the possible output media type used, the dither/halftone algorithm currently selected by the device driver, and the selected output resolution of the device. Information about each of the optional tags is listed below.


MS01 (media type)

MS01 is the signature of the tag used by Windows to track the media type. For a more complete discussion of tags and signatures, see the ICC version 3.0. The data size is of type icUInt32Number (an unsigned 32-bit identifier value according to the ICC specification). The purpose of this tag is to identify the current media type that the printer driver is configured for and map it to the appropriate ICC profile. It directly corresponds to the dmMediaType member of the printer driver's DEVMODE structure. It must be an exact match to map correctly. A more detailed discussion of run-time profile selection is given later in this section. If this tag is not defined within the profile, a key value of "MediaUnknown" is placed in the registry at installation time. For a complete description of values for this tag, see the Win32 SDK or Windows 95 DDK documentation about the DEVMODE structure.


MS02 (dither/halftone type)

MS02 is the signature of the tag used by Windows to track the currently selected dither/halftone algorithm used by the driver. For a more complete discussion of tags and signatures, see the ICC version 3.0 specification. The data size is of type icUInt32Number (an unsigned 32-bit identifier value according to the ICC specification). The purpose of this tag is to identify the current dither/halftone algorithm that the printer driver is configured for and to map it to the appropriate ICC profile. It directly corresponds to the dmDitherType member of the printer driver's DEVMODE structure. It must be an exact match to map correctly. A more detailed discussion of run-time profile selection is given in a later section. If this tag is not defined within the profile, a key value of "DitherUnknown" is placed in the registry at installation time. For a complete description of values for this tag, see the Win32 SDK or Windows 95 DDK documentation about the DEVMODE structure.


MS03 (resolution)

MS03 is the signature of the tag used by Windows to track the output resolution dot size. For a more complete discussion of tags and signatures, see the ICC version 3.0 specification. The data size is of type icUInt64Number (an unsigned 64-bit identifier value according to the ICC specification). The purpose of this tag is to identify the current raster resolution that the printer driver is configured for and map it to the appropriate ICC profile. It corresponds to the dmPrintQuality and dmYResolution members of the printer driver's DEVMODE structure. These map to the high and low double-word values in the eight-byte value respectively. Note that since the DEVMODE values are each a word quantity, the high word of each double-word is unused/reserved. They must be an exact match to map correctly. A more detailed discussion of run-time profile selection is given in a later section. If this tag is not defined in the profile, a key value of "ResolutionUnknown" is placed in the registry at installation time. For a complete description of values for this tag, see the Win32 SDK or Windows 95 DDK documentation.


Mapping Color Profiles to Printer Drivers

This section describes the process by which specific color profiles are mapped to a particular printer driver. The several ways that this can happen is largely determined by the capabilities supported by the printer driver.


Profile Selection Interfaces

The programming elements that graphics device interface (GDI) uses to obtain information used in ICM profile matching are the DeviceCapabilities function and the printer driver's DEVMODE structure. Windows 95 introduces two new DeviceCapabilities values, DC_ICC_MANUFACTURER and DC_ICC_MODEL. (DC_ICC_MANUFACTURER and DC_ICC_MODEL are defined as 23 and 24, respectively). A brief discussion of each is listed below. For a complete description of the DeviceCapabilities function, see the Win32 SDK and Windows 95 DDK documentation. Use of these values is strongly recommended, but not required. Cases in which printer drivers do not support these DeviceCapabilities values are discussed in a later section.

DC_ICC_MANUFACTURER returns a double-word value containing 4 bytes, which are interpreted as the four-byte manufacturer tag that is used for color profile matching. DC_ICC_MODEL returns a double-word value containing 4 bytes, which are interpreted as the four-byte model tag used for color profile matching.


Profile Selection Algorithms

GDI begins with a handle to a device context (hDC) to try to find a matching ICC color profile. GDI opens the ICM\prtr key in the registry (for a discussion of the registry, see a later section) to enumerate all of the printer manufacturers that have currently installed profiles. GDI must next obtain the four-byte manufacturer identifier and four-byte model identifier from the printer driver by using one of the two methods listed below. Windows 95 device driver developers are encouraged to support the new DeviceCapabilities indices used by the second method given below.


Profile Selection for Drivers That Do Not Support the New DeviceCapabilities Indices

If the driver does not return the manufacturer and model identifier to the DeviceCapabilities call, GDI constructs these from the (unfriendly) printer name (for example, the default printer name listed in the INF or the original dmDeviceName member of the DEVMODE structure, which the user may later change to a friendly name). The first four letters become the manufacturer identifier (that is, the icHeader.manufacturer tag). Spaces and hyphens are converted to spaces, and spaces are used to fill in afterward, if necessary. For example, "HP LaserJet" is read as "HP L" (0x48 0x50 0x32 0x4C), which is then converted to "HP " (0x48 0x50 0x32 0x32).

A CRC is applied to the whole name to get the model identifier (that is, the. icHeader.model tag). The CRC is given by the algorithm described at the end of this paper (which is actually the same algorithm used to construct parallel attached Plug and Play identifier values).


Profile Selection for Drivers That Do Support the New DeviceCapabilities Indices

If the driver does return the manufacturer and model to the DeviceCapabilities call, GDI simply takes those values and then proceeds, following these steps

  1. Selecting the Manufacturer and Model registry keys to use.

    Using the manufacturer and model identifiers for the driver, GDI attempts to open the manufacturer key and then the model key as a subkey of the manufacturer key. If these keys do not exist, the substitution lists described in the following section are searched next. If there are no substitutions for the manufacturer/model pair, there is no match and GDI fails to find the color profile required to perform image color matching.

  2. Selecting the best profile defined for the current printer driver settings and the selected Manufacturer and Model registry keys.

    GDI looks in the current DEVMODE structure for the hDC and uses the dmMediaType member value to open the associated key as a subkey of the model key. If the key does not exist, GDI calls the RegEnumKey function to find any media type and opens the first key enumerated. Note that in this scenario, where insufficient information is given to provide the optimally desired match, the decision to arbitrarily choose the first media type listed (which is purely installation-order dependent) is the only available option given the lack of any "gracefully failing" mapping schemes.

    GDI looks in the DEVMODE structure next for the dmDitherType member and tries to open the associated key as a subkey of the media key. If the key does not exist, GDI calls the RegEnumKey function to find any dither type and opens the first key enumerated. GDI then looks in the DEVMODE structure for the dmPrintQuality and dmYResolution members and tries to open the associated key as a subkey of the dither key. If the key does not exist, GDI calls the RegEnumKey function to find any resolution and opens the first key enumerated. At this point, GDI is at the level of the registry hierarchy where profiles names are stored. GDI first looks for the "default" value; if that value does not exist, it starts looking for values of the form profile00 to profile99. GDI uses the first profile it finds.

The logic of the two steps previously described is shown with the following pseudocode.

// search for appropriate manufacturer/model key in registry from which to get
// identity of color profile to use

if driver doesn't provides identifiers from new DeviceCapabilities call then
      get identifiers via checksum algorithm
if manufacturer/model registry key and driver manufacturer/model match then
   break;
   if GDI substitution list match found then
      locate manufacturer/model key for substitute driver
      break;
      if registry substitution list match found then
         locate manufacturer/model key for substitute driver
         break;
         end;      // no ICM possible because no appropriate
                   // manufacturer/model key found
      end if
   end if
end if

// use hDC to read current configuration values from DEVMODE structure for the
// printer driver and search prtr subkey branch of the found manufacturer/model // key for color profile that matches that current configuration.
// example prtr subkey branch looks like this:
// \prtr\EPSO\788D\107\ErrorDiffusion\00360x00360\profile00=epsonsty.icm
        \HP  \7645\MediaUnknown\DitherUnknown\ResolutionUnknown\profile00=hp.icm

if DEVMODE.dmMediaType value matches a value in a media subkey then
   look at dither subkeys on that branch
else
   call EnumRegType to enumerate media types and look at dither subkeys on
   branch of first media type found
end if
if DEVMODE.dmDitherType value matches a value in a dither subkey then
   look at the resolution subkeys in that branch
else
   call EnumRegType to enumerate dither types and look at resolution subkeys on
   branch of first dither type found
end if
if DEVMODE.dmPrintQuality and DEVNODE.dmYResolution values match a subkey then
   look at color profile identifier subkeys in that branch
else
   call EnumRegType to enumerate resolution types and look at color profile
   identifier subkeys on branch of first resolution found
end if

// at this point, one or more color profile identifier keys are being looked at
if key is DEFAULT then
   use value of that key as the color profile identifier
else     // keys are of form PROFILEnn, where nn = 00, 01, ... 99
   use value of key with smallest "nn" (use 00 in preference to 01, etc.) as the
   color profile identifier
end if


Constraints on Profile Selection Algorithms

Printers are not characterized independently of a driver; the driver is needed to tell the printer to put ink on the page. If you are characterizing a printer to be used with Windows, you have to be using a Windows printer driver. (PostScript devices can be excluded from this discussion because you can characterize them independently of Windows.) If you are using a Windows printer driver, you have access to the relevant values and can construct the ICC profile correctly.

Profile Substitutions

As noted earlier, substitution tables exist both in GDI (hard-coded) and in the registry (configurable) to address issues where it is desirable to have multiple devices referencing the same profile. The substitution tables hard-coded in GDI are for the HP® DeskJet® 3xx and 5xx series color printer drivers, which ship in Windows 95. The same functionality for other devices may be obtained by modifying the value for the SubstList key under the ICM key (for an overview of the registry hierarchy, see Registry Keys Reference to define mapping pairs.

The SubstList key is a string registry value and should consist of 16 character/byte sequences. The first eight bytes should be the four-byte manufacturer and four-byte model values that are being searched for, and the second eight bytes should be the four-byte manufacturer and four-byte model values that should be used in its place. Any number of 16-byte pairings may be used here.

An example would be using the Windows 95 drivers for the "HP DeskJet 1200C" (Manufacturer Tag = "HP ", Model Tag = "381C") and the "HP Color LaserJet (MS)" (Manufacturer Tag = "HP ", Model Tag = "5839"), and substituting the HP Color LaserJet profile for the 1200C profile. The SubstList value would need to be "HP 381CHP 5839". In hexadecimal notation, this is: 0x48 0x50 0x32 0x32 0x33 0x38 0x31 0x43 0x48 0x50 0x32 0x32 0x35 0x38 0x33 0x39.

Note that appending entries to a preexisting SubstList value cannot currently be done using an INF file, and it would require some code that reads the existing value and gracefully appends to it.


Registry Keys Reference

The ICM branch in the registry is under the following key:

\\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\ICM

The ICM key can have a SubstList subkey value, an array of pairs of manufacturer and model identifiers as described in "Profile Substitutions."

The ICM key has the following subkey branches:

\ICM\ICMatchers - color matcher ID to color matcher DLL file names
    \mntr - monitor profiles
    \ptrt - printer profiles
    \scnr - scanner profiles
    \link - defined in the ICC spec, unused by Windows
    \spac - defined in the ICC spec, unused by Windows
    \abst - defined in the ICC spec, unused by Windows

The last three keys are not used by GDI to find matching profiles for output devices. There is no substructure for these keys; they contain the names of profiles only. The scnr key has the substructure of manufacturer and model subkeys. The names of the profiles are in the model subkey. Windows installs profile names there, but does not look in the key for any reason.

The mntr key is structured by manufacturer and model identifiers. If the manufacturer key value is "none," there is no model subkey. The key might look like the following example:

\mntr\NEC \4FG \profile00 = c:\windows\system\color\nec.icm
               \profile01 = c:\windows\system\color\nec1.icm
          \5FG \profile00 = c:\windows\system\color\nec5fg.icm
     \HITA\34YU\profile00 = c:\windows\system\color\hitachi.icm
     \none\profile00 = c:\windows\system\color\mnebu18.icm
          \profile01 = c:\windows\system\color\mnebu21.icm

The \prtr key has more subkeys to track more printing variables. The subkeys, in order, are manufacturer, model, media, dither, and resolution. The key might look like the following example:

\prtr\EPSO\788D\107\ErrorDiffusion\00360x00360\profile00=epsonsty.icm
     \HP  \7645\MediaUnknown\DitherUnknown\ResolutionUnknown\profile00=hp.icm

These entries get built from information in the ICC profiles when they are installed. The installation process begins with the profile being opened and memory mapped in. First, the class of the profile is read; that determines the kind of device that the profile is for, such as prtr or link. Let us assume for the rest of this discussion that a prtr is being installed. A prtr key is created. The four-byte icHeader.manufacturer value is then read, and a key is created for it. A value is added to this key, which is the text equivalent of this key (for example, ManufacturerTag = Epson). This string is also pulled from the profile deviceMfgDescTag. The four-byte icHeader.model value is read, a key created for it, and the text string corresponding added as a value (for example, ModelTag = Color Stylus). This string is also pulled from the profile deviceModelDescTag.

The four-byte MS01 tag, which gives the media type, is read. For standard media types, the corresponding name is used; otherwise, a text string for the value is used. A key is created for it, but no values are added. If this tag does not exist, the default is MediaUnknown.

The four-byte MS02 tag, which gives the dither type, is read. For standard dither types, the corresponding name is used; otherwise, a text string for the value is used. A key is created for it, but no values are added. If this tag does not exist, the default is DitherUnknown.

The eight-byte MS03 tag , which gives the X and Y resolution in pixels per inch, is read. A key is created for it. If this tag does not exist, the default is ResolutionUnknown. Finally, the file name of the ICC profile is added as a value of the kind profileXX=profilename.icm. Of course, profiles could exist that match in these tags and yet differ in additional tags, such as lighting conditions or line frequency. This is why one might expect multiple profiles at the end of the chain. There might be one more value here as well, default=profileXX. In the case of multiple profiles, this is the one GDI will pick to match.


Checksum Algorithm Reference

The following section contains the details on how the Checksum algorithm generates identifier values for those device drivers that do not support the new ICM DeviceCapabilities indices.

If the driver does not return the manufacturer and model to the DeviceCapabilities call, GDI constructs these form the (unfriendly) printer name. A CRC is applied to the whole name to get the model identifier. The CRC is determined as follows:

WORD wCRC16a[16]={
    0000000,    0140301,    0140601,    0000500,
    0141401,    0001700,    0001200,    0141101,
    0143001,    0003300,    0003600,    0143501,
    0002400,    0142701,    0142201,    0002100,
};
WORD wCRC16b[16]={
    0000000,    0146001,    0154001,    0012000,
    0170001,    0036000,    0024000,    0162001,
    0120001,    0066000,    0074000,    0132001,
    0050000,    0116001,    0104001,    0043000,
};

void Get_CRC_CheckSum(PVOID pBuffer, ULONG ulSize, PULONG pulSeed)
{
  PBYTE    pb;
  BYTE    bTmp;

  for (pb=(BYTE *)pBuffer; ulSize; ulSize--, pb++)
  {
    bTmp=(BYTE)(((WORD)*pb)^((WORD)*pulSeed));    // Xor CRC with new char
    *pulSeed=((*pulSeed)>>8) ^ wCRC16a[bTmp&0x0F] ^ wCRC16b[bTmp>>4];
  }
}


Storage Technology Reference

The following topics describe the storage technology for the Windows® 95 DDK.


Layered Block Device Drivers

Layered block device drivers are 32-bit, flat-model device drivers that execute in protected mode. Windows® 95 uses layered block device drivers to manage input and output to block devices, such as disks and CD-ROM devices. These drivers support partitioned and non-partitioned removable media as well as conventional, SCSI, and floptical floppy drives.

Windows 95 also uses layered block device drivers to manage the operation of existing Windows 3.1 FastDisk drivers, Windows 3.1 FastDisk clients and hookers, MS-DOS-based real mode device drivers, and SCSI miniport drivers for Windows NT®/Windows 2000 and Windows 95.

Windows 95 uses a variety of device driver components to support different types of devices and software support. Each component corresponds to a specific layer and has specific responsibilities and requirements. Note that in a typical configuration, only a few of the layers are required for any given device. Only the layers that are required are associated with the device when the device is initialized.

In Windows 95, the layered block device driver components are:

Component | Item number(s) in the illustration | Description
File system drivers (FSD) | 7, 8, 9, 10 | Manages the high-level I/O requests from applications. The FSD processes requests from applications and initiates low-level I/O requests through the I/O supervisor. File system drivers are provided by Microsoft.
I/O supervisor (IOS) | 13 | Provides various services to file system drivers and other drivers in the system. The IOS register drivers, routes and queues I/O requests, sends asynchronous notifications to the drivers as needed, and provide services that drivers can use to allocate memory and complete I/O requests. The IOS also provides Blockdev services to support compatibility with BlockDev clients. The IOS is provided by Microsoft.
Volume tracking driver (volume tracker) | 14 | Works with a group of devices that share removability rules. The volume tracker ensures that the correct media is in the device and detects and reports improper media removal or insertion.
Type-specific driver (TSD) | 15, 16 | Works with all devices of a specific type, such as all CD-ROM devices. The TSD validates incoming I/O requests, converts logical requests to physical requests, and notifies the requester when the request is complete. The TSD may also initiate logical error recovery as needed for certain types of device, principally disk.
SCSI-izer | 20, 21 | Works with all SCSI devices of a given type, such as all SCSI disks. The SCSI-izer constructs SCSI Command Descriptor Blocks (CDBs) for a specific class and carries out device-level error recovery and logging.
Vendor-supplied driver (VSD) | 18, 19, 22, 23, 27 | Intercepts and processes I/O requests for a given block device. The VSD gives a vendor an efficient way to incorporate enhancements into an existing layered block device driver or to extend the capabilities of the driver to new but similar hardware.
SCSI port driver (SCSI manager) | 26 | Manages the interaction between the SCSI-izer and a SCSI miniport driver. The SCSI port driver initializes the miniport driver, converts the I/O request format, and carries out all interactions with the miniport driver. The SCSI port driver is provided by Microsoft.
Windows NT/2000 SCSI miniport driver | 30, 31 | Works with a specific set of SCSI adapters. The miniport driver detects and initializes the adapter, handles interrupts, transmits I/O requests to the device, and carries out adapter-level error recovery and logging.
Port driver | 24, 25, 27 | Works with a specific adapter, usually proprietary. For example, there are port drivers for IDE/ESDI and NEC floppy drivers. A port driver provides the same functionality as a combination of SCSI manager and miniport driver. The port driver detects and initializes the adapter, handles interrupts, transmits I/O requests to the device, and carries out adapter-level error recovery and logging.
Protect mode to real mode mapper | 17 | Provides the interface between a file system and an MS-DOS real mode driver. The real mode mapper manages MS-DOS-based device drivers while they operate in virtual 8086 mode. The mapper allows binary compatibility for MS-DOS drivers. The mapper is provided by Microsoft.
Real mode driver | 28 | An existing MS-DOS-based device driver. A real mode driver executes in virtual 8086 mode. Used when there is no protect-mode driver for a given adapter.

The relative position of these different components in the layered model is shown in the following illustration.

Note that the Windows 95 DDK block device documentation concentrates on disk and CD-ROM devices. For information about drivers for block devices other than disk and CD-ROM, see ASPI for Win32. The following abstract describes the usefulness of that documentation.

The Advanced SCSI Programming Interface (ASPI) has become an industry standard SCSI software interface. ASPI allows developers to write device drivers and applications that are independent of the specific host adapter platform used to connect SCSI peripherals. With ASPI, there is a single driver managing the host bus adapter, eliminating conflicts when multiple applications try to access the SCSI bus at the same time.

ASPI for Win32 describes the Advanced SCSI Programming Interface (ASPI) for the Win32 environment.

The ASPI manager for Win32 is implemented as a Dynamic Link Library (DLL) called Wnaspi32.dll. ASPI function calls can be used to retrieve information about installed SCSI host adapters and devices, and to execute SCSI I/O requests. The ASPI for Win32 layer is fully re-entrant, supporting multitasking and multithreaded operations. ASPI for Win32 defines the protocol between ASPI client applications and the ASPI Manager Wnaspi32.dll. It does not describe the protocol between Wnaspi32.dll and the target Win32 environment.


Floppy Disk Controller Arbitration in Windows 95

Another special topic in the block device documentation is floppy disk controller arbitration. Two floppy disk controller arbitration services are available to developers of backup software.

Service | Description
VFBACKUP_Lock_NEC | This service is called by VxDs to obtain exclusive control of the system floppy controller.
VFBACKUP_Unlock_NEC | This service is called by VxDs to release exclusive control of the system floppy controller.
VFBACKUP_Lock_All_Ports | This service is called by VxDs to prevent ALL access to the system floppy controller

Without using these services, real mode access gets detected by port access or DMA access from a VM. When the system floppy controller sees real mode access, the VM that attempts direct access is locked. If another VM is already locked on, the system floppy controller ignores the latest attempt to lock.

The services VFBACKUP_Lock_NEC and VFBACKUP_Unlock_NEC claim and release the system floppy controller for a given VM. Unlike the case where the system floppy controller detects port access and gives the floppy to a VM, when these services are used, there will not be a time-out, and the floppy can only be released when the lock fails, or a Terminate VM comes for the locking VM. Note that when a VM is locked on, the application causing the lock is responsible for dealing with the BIOS Motor Off command.

Do not attempt to use the VFBACKUP_Lock_Nec service before the system floppy controller driver is initialized. Note that if the system floppy controller driver is not loaded and a Windows backup application (such as Fastback.386 and others) is loaded, then the VFBACKUP system is unloaded and the VFBACKUP_Lock_Nec and VFBACKUP_Unlock_Nec service requests will fail. The way to check whether the VFBACKUP system is loaded is to use a VFBACKUP_GetVersion service request.


VFBACKUP_Lock_NEC

include vpicd.inc
include vfbackup.inc

mov     eax, flag
mov     ebx, handle
mov     ecx, addrInterruptProc
VxDCall VFBACKUP_Lock_NEC

This service is called by VxDs to obtain exclusive control of the system floppy controller. Once this returns successfully a lock is obtained granting exclusive access.

  • If successful, the carry bit is clear and, if a Ring 0 IRQ procedure is specified, eax contains the IRQHandle for IRQ6. If unsuccessful, the carry bit is set. Uses flags and interrupts are enabled upon exit.
flag
Indicates a VM or thread-based lock. A value of zero indicates a thread-based lock and a value of 1 indicates a VM-based lock. If the VM gaining exclusive control is the System VM, and a VM-based lock is specified, then ALL threads in the System VM will have access (including Explorer and other appslications). If you want only a specific thread in the system VM to have exclusive access, use a thread-based lock.
handle
Thread or VM handle.
addrInterruptProc
Address of the Ring 0 interrupt procedure, or specify zero for none.

If a Ring 0 interrupt procedure is specified, all subsequent interrupts for the system floppy controller will be passed to this procedure. The Ring 0 procedure will be treated just like a HW_INT_PROC defined for VPICD. (For further information on VPICD, see the Kernel services help file.) The handle returned is the IRQ handle that should be used by this Ring 0 procedure for all subsequent IRQ operations. Note: Do not attempt to release the IRQ handle when the application is done with it. You must only call the VFBACKUP_Unlock_NEC service in order to release the IRQ handle. If a Ring 0 interrupt procedure is not specified, then the interrupt will be reflected to the VM of the thread, or the VM that owns the lock.


VFBACKUP_Unlock_NEC

include vfbackup.inc

mov     ebx, handle
VxDCall VFBACKUP_Unlock_NEC

This service is called by VxDs to release exclusive control of the system floppy controller.

  • If successful, the carry bit is clear. If unsuccessful, the carry bit is set. Uses flags and interrupts are enabled upon exit.
handle
Thread or VM handle previously granted a lock by VFBACKUP_Lock_NEC.


VFBACKUP_Lock_All_Ports

include vfbackup.inc

VxDCall VFBACKUP_Lock_All_Ports

The floppy disk controller arbitration service VFBACKUP_Lock_All_Ports is used to prevent all access to the native floppy disk controller. The function VFBACKUP_Lock_NEC might not completely disable all I/O ports, particularly when the I/O ports are not trapped (such as direct I/O). This function calls Enable_Local_Trapping for each floppy disk I/O port to ensure that all I/Os are routed to the VFBACKUP I/O port handler. Next, a special flag is set that effectively turns the VFBACKUP I/O port handler into a "no op" (which does nothing). This service is useful when you want to disable FDC I/O activity caused by direct I/O. A typical usage might be to disable the BIOS's INT 08 floppy disk motor time-out function.

This function can only be called after VFBACKUP_Lock_NEC is called. The effect of this function is turned off when VFBACKUP_Unlock_NEC is called.


Device Drivers

Each layered block device driver is a dynamically loadable virtual device. The drivers work in conjunction with the IOS to carry out I/O operations for a given device. Although the drivers are VxDs, they do not use the standard virtual device services and APIs. The IOS provides the services and functions the device drivers need to complete their tasks.

Each driver belongs to at least one layer. Windows 95 permits a maximum of thirty-two layers, but a typical configuration will have at most 3 to 5 layers. Each layer is numbered, with layer zero at the top and layer thirty-one at the bottom. Every device driver sets one or more bits in a 32-bit flag to indicate within which layer(s) the driver belongs to.

Each layer has a specified level of functionality. A driver that belongs in a given layer must have this functionality. Drivers at higher layers generally deal with logical I/O operations on volumes. Drivers at lower layers carry out physical I/O to adapters. Drivers at other layers carry out transitions from a volume orientation to a logical device orientation; from logical device to physical device orientation; and from physical to adapter orientation. Drivers at these layers also carry out transitions from a volume relative logical I/O request to a device relative physical I/O request. Some layers are reserved.


Driver Loading

The IOS loads device drivers using the services of the VxD loader device, VXDLDR. The configuration manager directs the IOS to load given port and miniport drivers. The IOS automatically loads any "valued-added" drivers, such as the volume tracker and vendor-supplied drivers. In all cases, the files for these drivers must be in the SYSTEM\IOSUBSYS directory.

Note Some drivers are loaded by making specific entries in the SYSTEM.INI file.


Driver Initialization

The IOS initializes device drivers from the bottom up, from layer 31 to layer zero. Hence, the IOS initializes port drivers before a vendor-supplied drivers, vendor-supplied drivers before type-specific drivers, and so on.

The IOS initializes value-added drivers in groups, layer-by-layer. All drivers in a given layer are initialized before drivers in the next layer. The initialization order within a layer is not defined. This means you cannot depend on the drivers in a group being initialized in a given order or even that the order will remain the same from one boot operation to another.

A driver can belong to more than one layer. In such cases, the driver receives multiple initializations calls but will only be loaded once.


Driver Registration

When the IOS first loads a device driver, whether at boot time or later, it sends a SYS_DYNAMIC_DEVICE_INIT message to the driver. In response to this message, the driver is expected to register with the I/O supervisor. Registered device drivers receive notifications of certain events and configuration changes.

During registration, every driver must provide an entry point that the IOS can call to report asynchronous events. Asynchronous events include such things as device arrival, device departure, and time-out requests. If a driver also wishes to process I/O requests for a given device, it must also provide an I/O request entry point.


Safe Drivers and the Safe Driver List

A real mode driver is safe if its functionality does not exceed the functionality of the corresponding Windows 95 protect mode driver. If a real mode driver is safe, the protect mode driver can take over all I/O operations for the corresponding device. Otherwise, Windows 95 routes all I/O operations through the real mode driver.

An example of an unsafe driver is a real mode IDE/ESDI driver that uses dynamic encryption for security reasons. In this case, Windows 95 does not provide encryption, so Windows 95 should not allow the protect mode IDE/ESDI driver to take over the real mode driver. Any real mode driver that has the following functionality (not supported by Windows 95) is considered unsafe:

  • Data compression that is not compatible with DoubleSpace
  • Data encryption
  • Disk mirroring
  • Bad sector mapping
  • Fault tolerance, for example, maintenance of ECC correction on a separate disk
  • Vendor-specific IOCTLs
  • Microsoft-defined IOCTLs with vendor-extended features

The safe driver list is a Windows 95-maintained list of safe drivers. Each entry in the list identifies a driver or TSR that Windows 95 can take over with the corresponding protect mode driver. The list includes the following information:

  • Name of the driver or TSR. This should be same as the name present in the CONFIG.SYS or AUTOEXEC.BAT file.
  • Driver requirements
  • Whether it hooks INT 13h
  • Whether it needs to monitor INT 13h (regardless of whether the I/O is controlled by a protect mode driver)
  • Whether it accesses the hardware directly

Windows 95 does not store the version number of the driver or TSR in the list, so it is the responsibility of the vendor to change the name of the driver if a future version of the driver is enhanced in a manner that makes the driver safe or unsafe.

By default, the following drivers are considered safe:

  • MS-DOS 5-compatible real mode block device drivers
  • INT 13 monitors (hooks INT 13h for monitoring INT 13h I/O but does not access the hardware directly or modify the I/O buffer)
  • INT 13h hooker (hooks INT 13h for altering INT 13h I/O but does not access the hardware directly)
  • INT 13h driver (provides INT 13h functionality and directly accesses the hardware)
  • ASPI Manager (implements ASPI for MS-DOS specification)
  • CAM Manager (implements MS-DOS CAM specification)

If your real mode driver has higher performance or provides some functions that may not be present in the Windows 95 protect mode driver, you should remove the driver from the safe driver list. The system will use real mode to access your driver. Similarly, if your real mode driver that can be safely taken over by the protect mode drivers, add that driver to the safe driver list.

Note By default, Windows 95 assumes that a Master Boot Record (MBR) that contains code that hooks INT 13h is unsafe. You can override this default behavior and provide protected mode support is a VSD by using safe MBR INT13h hook routines. For more information, see About Vendor-Supplied Drivers.


Miniport Drivers

Although SCSI miniport drivers for Windows NT 3.1 are nearly 100% compatible with Windows 95, the following changes are recommended or required. This list does not include the changes that may be needed to support Plug and Play features.


Save/Restore State (Required)

The HW_ADAPTER_STATE function is called after FindAdapter with the SaveState parameter set equal to TRUE, indicating adapter state should be saved, and called before Windows 95 exit with SaveState set equal to FALSE, indicating the adapter state should be restored. This is necessary to support "Start Real Mode" feature of Windows 95 for adapters on which the real mode driver controlling the adapter is sensitive to transition from protected mode to real mode.

typedef BOOLEAN (*PHW_ADAPTER_STATE) (
    IN PVOID DeviceExtension,
    IN PVOID Context,
    IN BOOLEAN SaveState  );


Real Mode Initialized Hardware (Recommended)

Initialization for some SCSI adapters can be time consuming. The SCSI miniport driver will be passed a flag indicating that real mode initialization has taken place. This must be honored by miniport drivers whose initialization sequence is identical to real mode initialization and is excessively time consuming.

The RealModeInitialized member, a BOOLEAN, in the port configuration information will be set if Windows 95 can determine that real mode adapter initialization has occurred. The value of this member should be saved away in the device extension for the miniport driver and be used by the HW_INITIALIZE and possibly other routines.


Scatter/Gather Alignment Mask (Recommended)

The AlignmentMask member, a DWORD, in the port configuration information structure is used to indicate any alignment restrictions on scatter/gather buffer pointers and byte counts. For example, if an adapter required word alignment for scatter/gather, this variable would be set to 01b, and for doubleword alignment it would be set to 011b.


Configuration Information (Required)

Currently, most SCSI miniport drivers ignore configuration information passed in from the SCSI manager, and always "sniff" at I/O ports to identify hardware. Many adapters supported under Windows 95 have port ranges that conflict with other adapters, and are adversely affected by sniffing. For example, Artisoft Lantastic network adapters occupy a range of port addresses used by the Adaptec 154X adapters. Accessing these ports causes the system to lock up.

Windows 95 miniport drivers must honor configuration information. If the Access Range fields in the port configuration information structures are set to nondefault values on a call to FindAdapter, the miniport should verify that there is an adapter it supports at the location specified in the configuration information. If not, it should return an error. It should never "scan" for other adapters if the configuration information is nondefault.


Zero Out the New Entry Point (Required)

The miniport driver should zero out the Reserved PVOID field in HW-initialization data structure. This entry point will later be used for Plug and Play features.


Data Transfer Direction Bits in SRB for SCSI Miniports (Required)

The ASPI and CAM SCSI interfaces both have an option of not specifying the data transfer direction, thus requiring the hardware layer to determine the data transfer direction by examining the data phase entered into by the SCSI target. If both SRB_FLAGS_DATA_IN and SRB_FLAGS_DATA_OUT flags are set in the SRB, the miniport driver must determine the data direction by examining the data phase on the SCSI bus at the appropriate time, if the miniport needs to know the direction. If the miniport uses system DMA, the miniport must also set only the true direction bit and reset the other one in the SRB before calling ScsiPortIoMapTransfer when this case is encountered.


Removable Media Support

Windows 95 supports removable media. The following sections describe a number of features or considerations regarding removable media.


Partitionable Removable Media

Windows 95 supports existing removable media with MS-DOS compatible partitions. These partitions are usually created by third party supplied FDISK utilities.

Windows 95 FDISK will continue to create partitions on a removable media as long as these devices are INT 13 based. This is the current behavior of FDISK and will not be changed.


Drive Letter Assignment

The Registry key UserDriveLetterAssignment (located in HKEY_LOCAL_MACHINE\Enum\…) lets the user, via System Properties / Device Manager / Properties / Settings, lets the user specify a range of drive letters that will be reserved for each removable media drive during system initialization. If not specified by the user, the number of drive letters to be assigned will be based on the number of partitions on the media currently present at boot time. If the drive range is not specified by the user and no media is present at boot time then Windows 95 reserves one drive letter for each removable media.


Drive Geometry Redetermination

The IOS recalculates the disk geometry every time a media change is detected. This is necessary to be able to support variable size disks and variable size partitions.


Volume Tracking and FSD Volume Identification

Since all removable media do not have a serial number or have duplicate serial number (bulk formatted floppies), Windows 95 can not safely perform any volume tracking based on the volume serial number. To get around this problem, an FSD would always assign a unique serial number to a removable media on the very first MOUNT call to the media. (This operation is not necessary if the FSD generated unique number has already been written to this media). This number now identifies each media for volume tracking.


Volume Tracking and NEC Floppy Media Change Detection

No changeline support will be assumed until a changeline is actually detected by the system. Once a changeline has been detected, it will be honored for subsequent I/O request to the media. This will guarantee that Windows 95 continues to behave like MS-DOS 5 on older systems that do not support change line.


Electronic Drive Locking

The LOCK command will be generated by the protect mode FSD or cache as soon their buffers are dirty. The lock request can also be issued by real mode cache programs when their buffers are dirty. A lock request can also come from a MS-DOS-based or Windows-based applications.

The volume-tracking layer will only send the first LOCK command to the hardware but it will keep a depth counter for all the LOCK requests. Volume tracking layer will issue an UNLOCK command to the hardware when the LOCK count goes to zero. Volume tracking layer will wait for a predefined time before issuing the unlock to avoid excessive lock/unlock requests to the hardware.

The volume tracking layer will also hook MS-DOS Lock and UnLock IOCtl calls and INT 13 LOCK and UNLOCK requests to properly increase or decrease the LOCK depth counter.


Electronic Drive Ejection

A volume EJECT command can be generated either by an application, the Shell, or by the hardware when the user pushes the eject button.

The volume tracker will issue an INT 15 broadcast for every EJECT command it receives. If INT 15 is returned with a status that suggests that EJECT should not proceed, the command will not be sent to the hardware.

If the INT 15 broadcast is returned without error, the volume tracker will call every FSD that has mounted this media. FSDs are expected to flush their dirty buffers and issue unlocks in response to this request.

After all FSDs have flushed their buffers and have unlocked the volume, the volume tracker will make sure that the depth counter is zero before sending the EJECT command to the hardware.

If depth counter is still nonzero, the volume tracker will pop-up a warning message and will ask the user whether he wishes to continue with the EJECT request. If asked to continue, the volume tracker will issue unlock command and eject the volume.

Note INT 13 extensions and INT 15 eject broadcast commands are described in detail in a separate document.


Input and Output Supervisor

The IOS is a required system virtual device that carries out all control and management tasks for Windows 95 protected-mode drivers. The primary responsibilities of the IOS are to load and initialize protected-mode device drivers and to provide the services clients and device drivers need to make and complete requested I/O operations.

This part of the Windows 95 DDK Design and Implementation Guide describes the input and output supervisor (IOS). It also describes the IOS services that control and manage protected-mode device drivers, and that permit IOS clients (such as file system drivers) to generate I/O requests to be passed to the device drivers.


IOS Initialization

Windows 95 loads the IOS when it loads other static system virtual devices from the VMM32.VXD file. To initialize the IOS, Windows 95 sends SYS_CRITICAL_INIT and DEVICE_INIT messages to the IOS's control procedure. The IOS carries out all initialization tasks in response to these messages.

The IOS has a low initialization order value (IOS_INIT_ORDER), so it initializes before clients, such as the PAGEFILE and PAGESWAP virtual devices, and before virtual devices, such as INT13. This means the clients and virtual devices can call services in the IOS to register and carry out tasks.


Device Driver Loading

The IOS loads and initializes port drivers, miniport drivers, and value-added drivers. The IOS requires the files for these drivers to be located in the SYSTEM\IOSUBSYS directory and to have the following file name extensions:

Extension | Description
PDR | Port drivers, such as SCSIPORT, ESDI_506, and NEC
MPD | SCSI miniport drivers
VXD | Value-added drivers, such as the volume tracker and vendor-supplied drivers

The SYSTEM\IOSUBSYS directory is reserved for device drivers that are specifically designed for use with the IOS.

Note All other VxD Clients or virtual devices that use IOS services but are not specifically designed for the IOS should be stored in other directories (typically the SYSTEM directory) and explicitly loaded by the other Windows 95 VxD loading mechanisms:

  • When a DOS TSR or driver requests loading of a static VxD by chaining its request into the INT2F 1605 startup message
  • By indicating the VxD via "StaticVxD=…" in the Registry under HKLM\SYSTEM\CurrentControlSet\Services\VxD\.
  • By including device= entries in the SYSTEM.INI file.
  • By Dynamically loading it.

The IOS loads a given port or miniport driver only if the configuration manager sends a request to load that driver. The configuration manager sends a request if its hardware detection code locates an adapter. Currently, the configuration manager can detect the IDE and AHA154x SCSI adapters only. To support other adapters, the configuration manager forces the IOS to load all remaining miniport drivers. These drivers remain loaded only if they locate an adapter they can support. In general, any port driver that fails to locate hardware that it can support will be unloaded.

When the IOS loads a port driver, it carries out these steps

  1. Loads and initializes the port driver. The port driver must be present in the SYSTEM\IOSUBSYS directory.
  2. Loads all value-added drivers (files having the .VXD extension) that are not already loaded from the SYSTEM\IOSUBSYS directory.
  3. Initializes and configures the value-added drivers. If a value-added driver has not been previously loaded, the IOS initializes it by sending the SYS_DYNAMIC_DEVICE_INIT message. Otherwise, the IOS sends the driver an AEP_CONFIG_DCB function for each DCB created by the corresponding port driver.

To load a port or value-added driver, the IOS calls the VXDLDR_LoadDriver service (provided by the VxD loader) to load the driver. The IOS extracts the address of the driver's DRP structure from the DDB_Reference_Data member of the VxD_Desc_Block structure returned by this service. (You set this member when writing the device driver by specifying the DRP structure in the Declare_Virtual_Device statement.) The IOS uses the load group value (in the DRP_LGN member) to prepare for initialization of the driver. The load group identifies the layer at which the driver operates and needs initialization for. For example, the load group number (LGN) specifies the order in which the IOS initializes and configures the value-added drivers. In most cases, a driver sets a single bit in this member, but some drivers operate at several layers and must set multiple bits.

Although the DRP_eyecatch_str, DRP_ascii_name, DRP_create_date, and DRP_create_time members are not used during driver loading, a driver should set these members to valid values. Most drivers set all other members in the structure to zero.

See Also

DRP


Driver Initialization and Registration

The IOS initializes a device driver that has not been previously loaded by sending a SYS_DYNAMIC_DEVICE_INIT message to the driver's control procedure. It sends the message once for each load group to which the driver belongs. When the driver receives the message, it registers itself with the IOS by setting the DRP_aer and DRP_ilb members of its DRP structure and passing the address of the structure to the IOS_Register service. The IOS uses the DRP structure to register the driver and initialize internally maintained structures, such as the DVT structure, for the driver.

The driver must set the DRP_aer field to the address of the driver's asynchronous event routine. The IOS calls this routine, passing it asynchronous event packets (AEPs), when it wants the driver to carry out specific tasks. For example, to complete driver registration, the IOS calls the routine with a packet for an AEP_INITIALIZE function. This occurs before the IOS_Register service returns, so the driver must be prepared to process the call as part of its registration.

The driver also must set the DRP_ilb field to the address of a ILB structure for the driver. The IOS sets several members in the ILB structure, such as ILB_service_rtn, which the driver can use to call the corresponding IOS service routines to carry out useful tasks.

Because a driver needs the DRP structure only during initialization, the structure is typically defined in the driver's IDATA segment and is discarded after initialization. The ILB structure should not be discarded.

To manage the device drivers, the IOS creates a chain of DVT structures that contain information about the device driver, such as its file name and the address of its asynchronous event routine. The IOS initially adds a DVT structure to the chain for itself. Thereafter, the IOS adds a new DVT structure whenever a new driver or client first registers with the IOS. The IOS places the address of the DVT structure for a driver in the ILB structure, however, drivers should avoid modifying the DVT.

The IOS indicates whether the registration succeeded by setting the DRP_reg_result member. When the IOS_Register service returns, the driver must check the value of this member. If the registration is successful, the driver clears the carry flag and returns from processing the SYS_DYNAMIC_DEVICE_INIT message. Otherwise, the driver must set the carry flag and return.

See Also

DRP, DVT, ILB, IOS_Register


Load Group, Initialization Layer, and Registration Type

The DRP_LGN member for a driver specifies the driver's initialization layer and registration type. Each bit in the mask represents an initialization layer. The highest bits represent the lowest layers (those closest to the device); the lowest bits represent the highest layers.

The IOS initializes all drivers that belong to the lowest initialization layer first, and initializes drivers that belong to the highest initialization layer last. In general, the IOS initializes a driver only after it has initialized all other drivers belonging to lower layers. For a driver that belongs to multiple initialization layers, the IOS initializes the driver once for each layer it belongs to.

The IOS also uses the DRP_LGN member to determine the driver's registration type. The registration type determines which AEP functions to pass to the driver's asynchronous event routine during registration. There are the following registration types:

Registration Type | Load Group
Generic | DRP_CLASS_DRV, DRP_SCSI_LAYER, DRP_TSD, DRP_VOLTRK, DRP_VSD_1, DRP_VSD_2, DRP_VSD_3, DRP_VSD_4, DRP_VSD_5, DRP_VSD_6, DRP_VSD_7, DRP_VSD_8, DRP_VSD_9
Noncompliant | DRP_FSD, DRP_IFS, DRP_NT_PD
Port | DRP_ABIOS_PD, DRP_ABIOS_PREMPT_PD, DRP_ESDI_PD, DRP_ESDIEMUL_PD, DRP_MISC_PD, DRP_NEC_FLOPPY, DRP_NT_MPD, DRP_SOC_DRV, DRP_SOC_SER_DRV

The following sections describe the registration types.

See Also

DRP


Port Registration

The IOS carries out port registration for port drivers. Such drivers usually have direct access to the device hardware and typically register at the lowest initialization layers.

The IOS first sends a packet for an AEP_INITIALIZE function to the driver's asynchronous event routine. The packet consists of an AEP_bi_init structure in which the IOS has set these members:

AEP_func | AEP_INITIALIZE
AEP_lgn | Current initialization layer
AEP_bi_i_hdevnode | Address of device node for the driver
AEP_bi_i_dcb | Inquiry DCB structure
AEP_bi_flags | 0
AEP_bi_reference_data | Reference data from the driver's DRP structure

All other members are undefined.

When the driver receives this function, the driver creates one or more DDB structures using the ISP_CREATE_DDB function (sent to the IOS service routine whose address is given by the ILB_service_rtn member). The ISP_CREATE_DDB function creates a DDB structure of a given size and adds it to the chain of DDB structures associated with the DVT structure for the driver. After the driver has created the DDB structures, it indicates success by setting the AEP_result member to AEP_SUCCESS and returning to the IOS.

If a port driver successfully completes initialization, the IOS sends a AEP_DEVICE_INQUIRY function to the driver. The IOS sets the AEP_i_d_dcb member to the address of a DCB structure called the inquiry DCB. This structure includes a zero-based unit number identifying the unit that the IOS is querying. If the given unit exists, the driver sets the DCB_product_id, DCB_vendor_id and DCB_rev_level members to appropriate values and returns AEP_SUCCESS. The IOS then sends an AEP_CONFIG_DCB function to all the layer drivers.

If the given unit does not exist, the driver returns AEP_NO_INQ_DATA to direct the IOS to inquire about the next unit. If the given unit number is greater than the maximum number of units supported by the device, the driver returns AEP_NO_MORE_DEVICES to stop the inquiry. The IOS continues to send AEP_DEVICE_INQUIRY functions until the driver returns AEP_NO_MORE_DEVICES or the IOS has sent 128 (units zero through 127) functions for the given DDB structure.

The IOS automatically repeats the entire initialization sequence, starting with the AEP_INITIALIZE function, for the port driver if the port driver controls more than one controller. Although not typically needed, a port driver can also direct the IOS to repeat the initialization sequence by setting the AEP_bi_flags member to AEP_BI_FL_SEND_CONFIG_AGAIN.

If a SCSI port driver initializes successfully, IOS makes as many inquiries as is specified in AEP_bi_i_max_target member returned in response to the AEP_INITIALIZE function. The IOS uses the scan order specified by the AEP_bi_flags value. If AEP_BI_FL_SCSI_SCAN_DOWN is set, the IOS scans in the reverse order.

Then the IOS sends a packet for an AEP_CONFIG_DCB function. The packet consists of a AEP_dcb_config structure in which the IOS has set these members:

AEP_func | AEP_CONFIG_DCB
AEP_lgn | Current initialization layer
AEP_d_c_dcb | Initialized DCB structure
AEP_ddb | Current DDB structure

The driver processes the AEP_CONFIG_DCB function by setting the various members of the DCB structure to values specifying geometry information, such as cylinder count and sector count. The driver then inserts itself in the calldown list for the DCB by the ISP_INSERT_CALLDOWN function (sent to the IOS service routine whose address is given by the ILB_service_rtn member). The ISP_INSERT_CALLDOWN function places the address of the driver's I/O request handling routine in the list. To indicate success, the driver sets the AEP_result member to zero and returns to the IOS. To complete the function, the IOS creates a real DCB and fills it with information supplied by the driver.

The IOS completes port registration by sending the AEP_BOOT_COMPLETE function to all drivers. The function is a notification to the driver to unload itself if desired. For example, a VSD may choose to unload if it has determined that it has inserted itself in none of the DCBs in the system. A driver unloads itself by returning AEP_FAILURE. This directs the IOS to deregister and unload the driver. No DDB pointer is passed with the function, so the driver receives the call once only.

In some cases, the IOS may send an AEP_CONFIG_DCB command before sending an AEP_DEVICE_INQUIRY function. In particular, the IOS does this if the driver has set the DRP_IO_FOR_INQ_AEP bit in the DRP_feature_code member of its DRP structure. This bit indicates that the driver needs to issue I/O requests to process the AEP_DEVICE_INQUIRY function. During port registration, the IOS checks for this bit and passes a packet for an AEP_CONFIG_DCB function for the given DCB prior to calling AEP_DEVICE_INQUIRE functions. The driver processes this call by inserting the driver's I/O request handler in the calldown stack of the DCB.

See Also

AEP, DCB, DDB, DRP


Generic Registration

The IOS carries out generic registration for type-specific drivers, vendor-specific drivers, volume tracking drivers, and class drivers. The IOS first sends a packet for an AEP_INITIALIZE function to the driver's asynchronous event routine. The packet consists of an AEP_bi_init structure in which the AEP_func and AEP_i_lgn members are set but all other members are undefined. The packet notifies the driver that registration has started. No action by the driver is required. The IOS ignores the result value returned by the driver.

Next, the IOS sends one or more AEP_CONFIG_DCB functions. The packet for this function consists of an AEP_dcb_config structure in which the AEP_func, AEP_i_lgn, AEP_d_c_dcb, and AEP_ddb members are set. The IOS sends the function once for each DCB structure in the internal DCB chain. The AEP_ddb member is set to the address of the DDB created by the driver at initialization.

The driver checks the DCB type to determine whether to process requests associated with this DCB. If the DCB has the correct type, the driver inserts itself in the calldown list of the DCB by using the ISP_INSERT_CALLDOWN function (sent to the IOS service routine whose address is given by the ILB_service_rtn member). The ISP_INSERT_CALLDOWN function places the address of the driver's calldown routine in the list.

To complete generic registration, the IOS sends the AEP_BOOT_COMPLETE function to all drivers.

See Also

AEP, DCB


Noncompliant Registration

The IOS carries out no action for noncompliant registration. Noncompliant drivers or clients, such as IFS and FSD drivers, do not receive AEP functions and are not registered.


Calldown List

The calldown list identifies the drivers responsible for processing I/O requests issued for a DCB. The IOS uses the calldown list to determine which I/O request handling routines to call and what order to call them. The IOS creates the calldown list for a DCB during driver registration.

A driver inserts the address of its I/O request handler into the calldown list by using the ISP_INSERT_CALLDOWN function while processing the AEP_CONFIG_DCB function. The ISP_INSERT_CALLDOWN function creates a new entry for the list, consisting of an DCB_cd_entry structure, and copies relevant information from the ISP_calldown_insert structure passed with the function into the free entry. For example, the function sets the DCB_cd_io_address member to the value specified in the ISP_i_cd_req member. If a new list entry can not be created, the IOS returns a nonzero value in ISP_result field indicating the error. Few if any devices use more than five entries in the calldown list.

The IOS sorts the calldown list entries by load group number as specified by the DCB_cd_lgn field. When the IOS inserts a new entry, it places it in sorted order. For example, if a list contains three entries with load group numbers of 4, 7 and 31, the IOS will inserts a new entry having load group number 6 into the second slot in the list, moving the 7 and 31 entries down one slot each. Although a driver can direct the IOS to insert an entry relative to any given layer, most drivers insert their entries relative to their initialization layer.

While inserting a calldown list entry, each driver specifies the kind of functionality it needs from a higher layer by setting bits in the ISP_i_cd_flags member. If a driver supports the requested functionality, it clears the bit. Each driver should check these bits during registration to make sure drivers at lower levels on which they depend have cleared the necessary bits. After the IOS loads all drivers, the IOS checks the bits in the ISP_i_cd_flags member to make sure that the only bits left are those that the IOS can support.

See Also

DCB, ISP


Asynchronous Events

An asynchronous event is a request or a notification from the IOS to a driver that does not correspond to the normal processing of an I/O request. Asynchronous events can occur at any time: while registering the driver and while waiting for or processing I/O requests. The most common events are the events associated with driver registration, such as AEP_INITIALIZE, but other events can occur frequently. The following lists the possible asynchronous events:

AEP_1_SEC (8) | Notifies driver that one second has elapsed.
AEP_2_SECS (9) | Notifies driver that two seconds have elapsed.
AEP_4_SECS (10) | Notifies driver that four seconds have elapsed.
AEP_ASSOCIATE_DCB (12) | Associates a logical DCB with a physical DCB.
AEP_BOOT_COMPLETE (2) | Notifies driver to switch to run time operation.
AEP_CONFIG_DCB (3) | Configures physical device.
AEP_CREATE_VRP (18) | Notifies driver that a VRP has been created.
AEP_DBG_DOT_CMD (11) | Notifies driver of parameters for .I debug command.
AEP_DCB_LOCK (16) | Notifies driver that a logical DCB is about to be locked.
AEP_DESTROY_VRP (19) | Notifies driver that a VRP has been deleted.
AEP_DEVICE_INQUIRY (6) | Gets device identification data.
AEP_HALF_SEC (7) | Notifies driver that 1/2 second has elapsed.
AEP_INITIALIZE (0) | Initializes driver and interface.
AEP_IOP_TIMEOUT (5) | Notifies driver that time-out member in an IOP has been decremented to zero.
AEP_MOUNT_NOTIFY (17) | Notifies driver that a volume has been mounted.
AEP_PEND_UNCONFIG_DCB (21) | Notifies driver that a DCB is about to be removed.
AEP_REAL_MODE_HANDOFF (13) | Notifies driver that IFSMGR is about to hook in.
AEP_REFRESH_DRIVE (20) | Directs driver to refresh drive data.
AEP_SYSTEM_CRIT_SHUTDOWN (1) | Indicates a system critical shutdown.
AEP_SYSTEM_SHUTDOWN (14) | Indicates a system shutdown.
AEP_UNCONFIG_DCB (4) | Removes configuration of physical device.
AEP_UNINITIALIZE (15) | Uninitializes driver and interface.

The IOS notifies a driver of an asynchronous event by pushing the address of a structure, called an asynchronous event packet (AEP), on the stack and calling the driver's asynchronous event routine. The content and format of the structure varies from event to event, but all structures start with a standard header as defined by the AEP structure. This structure includes the AEP_func member that identifies the asynchronous event and the AEP_result member that the driver uses to indicate whether it processed the event or encountered an error. The IOS checks the value of AEP_result after the driver returns.

See Also

AEP


IOS Services

The IOS provides drivers and clients with memory management and timer services. There are the following services:

ISP_ALLOC_MEM (3) | Allocate block from IOS memory.
ISP_ASSOCIATE_DCB (6) | Associate DCB and relative drive number.
ISP_CREATE_DCB (1) | Create DCB.
ISP_CREATE_DDB (0) | Create DDB.
ISP_CREATE_IOP (2) | Allocate IOP.
ISP_DEALLOC_DDB (9) | Free DDB.
ISP_DEALLOC_MEM (4) | Free block of IOS memory.
ISP_DELETE_LDM_ENTRY (19) | Delete LDM entry.
ISP_DESTROY_DCB (10) | Free DCB.
ISP_DEVICE_ARRIVED (14) | Indicate that a device has arrived.
ISP_DEVICE_REMOVED (13) | Indicate that a device has been removed.
ISP_DISASSOCIATE_DCB (15) | Disassociate DCB and drive number.
ISP_DRIVE_LETTER_PICK (16) | Pick a drive letter.
ISP_FIND_LDM_ENTRY (18) | Find LDM entry.
ISP_GET_DCB (7) | Return DCB for logical volume.
ISP_GET_FIRST_NEXT_DCB (8) | Get first or next DCB.
ISP_INSERT_CALLDOWN (5) | Insert calldown entry in DCB.
ISP_QUERY_MATCHING_DCBS (11) | Ask for logical-to-physical info.
ISP_QUERY_REMOVE_DCB (12) | Ask if we can remove a device.
ISP_REGISTRY_READ (17) | Read registry.

A driver can use an IOS service to carry out a task by calling the IOS service routine after pushing the address of a structure, called an IOS service packet (ISP), on the stack. The address of the IOS service routine is in the ILB_service_rtn member of the ILB. The content and format of the structure to pass to the routine varies from service to service, but all structures start with a standard header as defined by the ISP structure. This structure includes the ISP_func member that identifies the service to carry out and the ISP_result member that the IOS uses to indicate whether it completed the service or encountered an error. The driver should check the value of ISP_result after the IOS returns.

See Also

DCB, DDB, ILB, IOP, ISP


Input and Output Requests

File system drivers and other clients use I/O requests to direct a device to carry out a given I/O operation. To submit a request, a client fills the members of an IOR structure (part of an IOP structure) and passes the address of the IOR to the IOS_SendCommand service. The IOS passes the IOR to the various drivers in the calldown chain. The IOS and device drivers update this structure as the request progresses through the chain. There are the following I/O requests:

IOR_ABORT_QUEUE (0x24) | Cancels queued requests.
IOR_CANCEL (0x03) | Cancels a previously issued command.
IOR_CLEAR_QUEUE (0x10) | Requests to clear NEC queues for device. Returns when queue is clear.
IOR_COMPUTE_GEOM (0x0C) | Determine device geometry information.
IOR_DOS_RESET (0x11) | Corresponds to INT 13h reset.
IOR_EJECT_MEDIA (0x08) | Ejects media.
IOR_FLUSH_DRIVE (0x27) | Flushes dirty data.
IOR_FLUSH_DRIVE_AND_DISCARD (0x28) | Flushes dirty data and discards queued data.
IOR_FORMAT (0x0E) | Formats a track.
IOR_FSD_EXT (0x29) | Sends private data to FSD layer.
IOR_GEN_IOCTL (0x0D) | Carries out a generic I/O control function.
IOR_LOAD_MEDIA (0x07) | Loads media.
IOR_LOCK_MEDIA (0x09) | Locks media.
IOR_MEDIA_CHECK (0x05) | Gets disk change status.
IOR_MEDIA_CHECK_RESET (0x06) | Gets and resets disk change status.
IOR_READ (0x00) | Reads data from device.
IOR_REQUEST_SENSE (0x0B) | Returns drive sense data.
IOR_RESTART_QUEUE (0x23) | Restarts the queue in the same manner as the IOS queuing services.
IOR_SCSI_PASS_THROUGH (0x0F) | Passes a SCSI command through to device.
IOR_SCSI_REQUEST (0x12) | Request for SCSI device.
IOR_SET_WRITE_STATUS (0x22) | Sets or clears write protect status.
IOR_SPIN_DOWN (0x25) | Directs the drive to stop spinning.
IOR_SPIN_UP (0x26) | Directs the drive to start spinning.
IOR_UNLOCK_MEDIA (0x0A) | Unlocks media.
IOR_VERIFY (0x02) | Verifies data on device.
IOR_WRITE (0x01) | Writes data to device.
IOR_WRITEV (0x04) | Writes and verifies data to device.

To generate a read request, for example, the client allocates an IOP using the ISP_CREATE_IOP service, fills the IOR with the data for the request, and passes the address of the IOR to the IOS_SendCommand service. The IOS passes the IOR to the volume tracker, which makes sure the correct media is loaded. The volume tracker passes the IOR to the disk TSD, which converts the volume relative address to a media relative address. The disk TSD passes the IOR to the port driver, which initiates a read operation at the device and returns control to the disk TSD. Throughout this process each driver that receives the IOR takes ownership of it. The port driver retains ownership of the IOR.

A client typically allocates the IOP by using the ISP_CREATE_IOP service. This ensures that the IOS can provide request time-out support and other services. The IOR is the only portion of the IOP that the client may access with the exception of the first 32-bit field of the IOP, which contains the 32-bit physical address of the IOP. The correct size for the IOP is contained in the VRP_max_req_size member in the VRP structure. The correct offset into the IOP of the IOR is the sum of the VRP_delta_to_ior member and the IOP address. A client can retrieve the VRP for a given device by using the IRS_GET_VRP function of the IOS_Requestor_Service service.

When the IOS receives an IOP, it sets the following IOP members:

IOP_physical_dcb | Address of the physical DCB
IOP_original_dcb | Address of the logical DCB
IOP_timer | Time-out value to 7.5 seconds
IOP_calldown_ptr | Address of the first layer in the calldown chain
IOP_callback_ptr | Address of IOS_iop_callback callback routine

After setting these members, the IOS calls the first layer in the calldown chain, typically the volume tracking driver. When the request is called back to IOS at IOS_iop_callback, contents of IOR_req_req_handle is placed on the stack, and IOR_callback is called.

See Also

IOP, IOR, IOS_SendCommand, VRP


Expansion Areas

An IOP contains, among other members, the expansion areas required by each driver that receives the IOP. When a driver receives an IOP, it can access its expansion area by using the offset in the DCB_cd_expan_off field to calculate the starting address of the area.

The IOS creates the expansion area for a driver when the driver inserts itself in to the calldown chain. The IOS reserves the number of bytes specified by the ISP_i_cd_expan_len member for the expansion area for the driver. As drivers add themselves to the calldown chain, the IOS keeps a running total of the bytes reserved for all the expansion areas. It keeps this total in the DCB_expansion_length field. The IOS uses this field to determine the offset to a new expansion area whenever a driver requests one.

After all drivers inserted themselves in the calldown chain, the IOS calculates the size of an IOP as the sum of a static IOP, including the IOP header and IOR structure, and the total size of the expansion areas as given by the DCB_expansion_length field. The IOS places this total IOP size in the VRP structure so that IOS clients that prepare requests can allocate an IOP of the correct size. All expansion areas are placed in front of the static IOP (the linear address is lower).

The expansion area offset a driver receives depends on the order in which the driver is initialized. The offsets into the expansion area are negative, so that a driver loading later will have a lower memory address pointing to its expansion offset.

Insertion Order | Size | Offset
3rd | Z | -(X+Y+Z)
2nd | Y | -(X+Y)
1st | X | -X

See Also

DCB, IOP, VRP


Calldowns

For each I/O request, the IOS determines which drivers to call and in what order to call them by using the calldown chain in the given DCB. Initially, the IOS sets the IOP_calldown_ptr member in the IOP structure to the address of the first entry in the calldown chain. Each driver in the chain is responsible for updating this member by setting it to the address of the next entry in the chain. A driver updates this member by obtaining the next calldown entry from the DCB_cd_next field of the current calldown entry. After updating, the current driver calls the next driver in the chain by pushing the address of the IOP on the stack and calling the next driver's entry point:

mov  eax,[ebx+IOP_calldown_ptr]   ; eax now points to calldown entry
mov  eax,[eax+DCB_cd_next]        ; eax now points to next calldown entry
mov  [ebx+IOP_calldown_ptr],eax   ; update the IOP's calldown pointer
push ebx                          ; place *IOP on stack
call [eax+DCB_cd_io_address]      ; call next layer
add  esp,4                            ; restore stack

See Also

DCB, DCB_cd_entry, IOP


Callbacks

While processing an I/O request, a driver can perform post-processing on the request by inserting the address of a callback routine in the IOP_callback_table member of the IOP and updating the IOP_callback_ptr member:

; get callback pointer
mov eax, [esi.IOP_callback_ptr]
; save callback address in table
mov [eax.iop_cb_address], offset32 vol_completion
; move down to next entry
add [esi.IOP_callback_ptr], size IOP_callback_entry

When calling back a request after completion or termination, each driver performs any necessary postprocessing, places the IOP address on the stack, and calls the next higher layer:

sub [ebx].IOP_callback_ptr, size IOP_callback_entry
                                  ; point to next available cb entry
mov eax, [ebx].IOP_callback_ptr   ; get pointer to next entry
push ebx                          ; place *IOP on stack
call [eax].IOP_cb_address         ; call back request
add esp, 4                        ; restore stack

See the HELPVSD sample in the DDK for details.

See Also

IOP


I/O Request Timeout

Each IOP has an IOP_timer member that the IOS initially sets to 15 (7.5 seconds). On each subsequent timer interrupt (approximately twice per second), the IOS decrements by one/half second the corresponding IOP_timer member in each outstanding IOP. If the IOP_timer member in any IOP becomes zero before the packet is freed, the IOS sends the AEP_TIMEOUT command to the asynchronous event routines for all drivers.

In this case, the IOS sets the AEP_i_t_o_iop member to the address of the affected IOP. If a driver has already processed this IOP, that driver sets the AEP_result member to zero; otherwise, it sets the member to nonzero. If a driver has processed the request but the adapter has failed to respond, the driver can correct the problem, such as resetting the adapter. If a driver is queuing the request and has not yet processed the request, it can simply reset the IOP_timer member with the value in the IOP_orig_timer field.

See Also

AEP, IOP


IOS Requestor Service Functions

The IOS requestor service functions carry various tasks for drivers and clients. There are the following requestor service functions:

IRS_FIRSTNXT_CHAR_DEV (9) | Returns the name of a character device.
IRS_GET_DRVINFO (2) | Returns information about the given drive.
IRS_GET_LOGICAL_DRVS (7) | Returns logical volumes on the given INT 13h unit.
IRS_GET_VRP (0) | Returns the VRP for a volume.
IRS_IS_DRVCOMPRESSED (10) | Returns a host drive if the given drive is compressed.
IRS_MEDIA_CHECK_RESET (3) | Checks media and resets changeline.
IRS_MOUNT_NOTIFY (8) | Notifies that a drive was just mounted.
IRS_QUERY_VOLUME_LOCK (6) | Notifies that the volume is about to be locked.
IRS_REAL_MODE_HANDOFF (5) | Notifies that real mode is about to take over.
IRS_REPLACE_VRP (1) | Replaces the currently active VRP.
IRS_SET_CUR_FLP_UNIT (4) | Sets the current floppy unit on single floppy systems.

A driver or client uses a function by passing the address of an IOS requestor service structure (IRS) to the IOS_Requestor_Service service. The content and format of the structure to pass to the service varies from function to function, but all structures start with a standard header as defined by the IRS structure. This structure includes the IRS_func member that identifies the function to carry out and the IRS_result member that the IOS uses to indicate whether it completed the function or encountered an error. The driver should check the value of IRS_result after the IOS returns.

See Also

IOS_Requestor_Service, IRS, VRP


IOS Protected-Mode Functions

IOS protected-mode functions are provided by IOS_PM_API_Handler, the interface routine for use with the Windows protected mode application interface. Clients retrieve the address of this function by using the Get PM API Vector Interrupt 2Fh, Function 1684h which returns a Ring 3 callable vector.


MS-DOS/Win32 Installable File System

Information in this preliminary release of the document is subject to change without notice. No part of this document may be reproduced or transmitted in any form or by any means, electronic or mechanical, for any purpose, without the express written permission of Microsoft Corporation.


Overview

This document describes the Installable File System (IFS) interface for the MS-DOS®/Win32® product. This interface is being defined to support multiple file systems on DOS/Win32. All file systems for this product will be supported through this interface. This includes FAT, Network Redirectors, CD-ROM, and HPFS or NTFS. The only file systems that are not expected to use this interface are existing INT 21h hooking file systems such as network redirectors. However we expect all major network vendors to provide a network IFS for this product.

The OS/2 and Windows NT®/Windows® 2000 IFS has been evaluated as an option for this interface. Due to the difference in the architectures of these systems, the OS/2 and Windows NT/Windows 2000 IFS interface is not easily adapted to the DOS architecture. The resulting size and performance of such an adaptation would be unacceptable.

The MS-DOS/Win32 product will support the VMM environment currently available in Windows, which supports the Virtual Device Driver (VxD) model. This allows the File Systems or File System Drivers (FSDs) to be implemented as 32-bit flat model VxD modules. They will run in protected mode in high memory and will not consume any real mode memory. A protected mode block device driver interface will be defined to support these FSDs. This will allow the protected mode FSDs to remain in protected mode through out the entire I/O operation. The system will only mode switch when transferring control from the V86 mode DOS app to the protected mode file system. For protected mode windows apps there will be no mode switching, unless compatibility requires I/O operations to go through the V86 mode INT 21h chain.

The IFS interface defines a set of functions needed to support file I/O operations originating from the Win32 API calls and from the DOS INT 21h calls. A single VxD module is used to manage the relevant calls from the Win32 API layer and the INT 21h interrupts. This VxD converts the API request into the IFS interface functions and routes it to the appropriate FSDs.

All of the components described here run in protect mode. This will allow DOS users to connect to and use heterogeneous file servers without using (hardly) any conventional memory.

The reader should be familiar with the section on file I/O APIs in the Microsoft Win32 Programmer's Reference before reviewing this document.


References

Win32 Documents |
[1] Microsoft Win32 Programmer's Reference | Defines base Win32 APIs and data structures including File, Print, Security, GDI, User, and so on.
[2] MS-DOS Programmer's Reference | Defines the various INT 21h APIs that MS-DOS supports.


Design Requirements

The design must not break Win 3.x redirectors (typically a shell that hooks INT 21h and INT 2Fh calls).

All existing INT 21h file I/O functions must be supported.

The Win32 file I/O API functions must be supported.

The components necessary to implement the design must use as little low, real mode memory (memory below 1 MB) as possible.


Non-Requirements

This design does not need to work in the Microsoft Windows NT/Windows 2000/Win32 environment. However, any common areas, such as user level entry points, should be the same.

The API for enumeration and browsing of network servers and network file resources in the Win32 API base specification are not part of this design. This design's functionality provides indirect support for the implementation of some of those APIs, but does not address this implementation directly.

The design does not specify the interface between the redirector(s) and the transport stack. However, we do have a goal of getting all the important outside vendors to use TDI as this interface.


Routing Requests to the FSDs

The FSDs provide the mapping from the file system disk format into the IFS interface functions. A redirector is an FSD that maps these functions on to a network rather than a local disk. The network redirector FSDs are vendor specific VxD's that interface to different back end file servers (that is, Novell, Banyan, and Lanman to name a few). They provide the network specific support required to service the Win32 and INT 21h IFS manager requests. Since there is no file system built into the system, at least one FSD is required for file I/O. There is also no explicit design limit on the number of FSDs that can be loaded in the system at the same time. At this time, there is a limit of ten local and ten remote FSDs that can be loaded. This limit is not rigid and can be easily increased. FSDs do not use or rely on most of the DOS data structures.

The IFS/INT 21h Manager determines the correct FSD to call for each file I/O request using handles or path names. Handles are first created by the IFS manager in response to a request like "open file." Each handle corresponds to a specific FSD, and this relationship is kept in a system file handle structure. When a handle is passed back to the IFS manager, it is used to locate the system file handle structure that identifies the FSD and the FSD specific handle for the request. When a path name is passed in a call to the IFS manager, the correct FSD is determined based on the drive letter or name. If this cannot be done, the FSDs are called in order until one of them accepts the call. There is no explicit ordering scheme to specify the order in which the FSDs are called. There is no explicit scheme for ordering the load order of FSDs at this time apart from the VxD device init order.

The following are a few different types of functions the IFS components will handle.

  • Functions that enumerate an available resource. This type of function will check for the resource on all FSDs running on the system. Each FSD will be called in order. In this case the order does not really matter since each FSD will be called.
  • Functions that search for a particular resource. This type of function will check each FSD in order until the resource is found. When the desired resource is found the search will stop. Any remaining FSDs will not be searched. If multiple FSDs contain a resource with the same name, the second one in the search order will not be found. It is up to the administrator of the system or network environment to avoid such conflicts.
  • Functions that are associated with a specific FSD. This type of function will typically make an association with an FSD through a prior call such as an "open". The IFS manager components will keep local data structures where possible to allow these functions to be directly dispatched to the desired FSD.


Loading and Initialization

As mentioned previously, all of the file I/O components will be loaded in high memory and will execute in protect mode. The ability to allocate high memory and switch in and out of protected mode will be supported through the VMM.

Windows 95 will support the loading of VxDs that are compatible with Windows 3.x. It will also support an enhanced VxD module that may be dynamically loaded and unloaded, and supports swappable memory objects.

The IFS components are started by loading the module that contains the IFS manager. The FSDs must be loaded after the IFS manager. There is no direct linkage from the IFS manager to the FSDs. Instead the FSDs are linked to a registration entry point in the IFS manager when they are loaded. The FSDs are required to call this registration routine during their initialization and pass a list of their entry points. The IFS manager entry point is exported as a VxD service. The FSDs are linked to this entry point through a delayed run-time linkage mechanism.

The FSDs will be loaded and initialized when the system starts up. Once they are loaded they will remain loaded until the system hardware is shutdown or rebooted. As discussed above, the swapping of pages in virtual memory is expected to occur.

The IFS manager and FSDs are initialized through the VxD initialization routine. These routines allow multiple levels of initialization. The FSD does not provide an initialization entry point to the IFS manager.


Application Programming Interface

The file I/O APIs provide support for the Win32 file I/O API functions as well as the DOS INT 21h API functions. The Win32 APIs are defined in the Microsoft Win32 Programmer's Reference. The INT 21h API is defined in the MS-DOS Programmer's Reference.


File System Drivers

The File System Driver provides the functionality required by the IFS manager to support the Win32 and INT 21h file API services in the system. The interface to the FSD is defined in two sections: the File I/O routines and the Client Named Pipe routines. The interface to these routines is defined later in this section.


Types of FSDs

There are three types of FSDs that may exist in the system: local, remote and character FSDs.


Local FSDs

A local FSD uses a block device driver to do I/O to a disk device. The FSD maintains a specific format on the disk device and supports the IFS interface by manipulating this disk format. When the first request is made for accessing a logical disk drive, a linkage between the FSD and the disk device driver is established through a mount operation initiated by the IFS. The mount operation allows the FSD to verify that it recognizes the disk format. The FSD can then create its own structures required to manage the specific disk volume in the drive. Local FSDs register with the IFS manager using the IFSMgr_RegisterMount service and get called on the FS_MountVolume entry point to be mounted on a volume. Once mounted, all requests are routed through the interface established as a result of the mount operation.


Remote FSDs

A remote FSD accesses a remote file server through a network connection. The FSD translates the IFS requests into a network specific protocol and transfers them across a network to a file server. A remote FSD is often referred to as a network redirector. The linkage between a logical drive and a network resource is established through a connection operation. The connection operation provides the redirector with a network resource name that the connection is being made to. If the name is valid for the redirector, it may create its own structures required to manage the network connection. Network redirectors register with the IFS manager using the IFSMgr_RegisterNet service and get called on the FS_ConnectResource entry point to establish a connection with a resource. Once connected, all requests are routed through the interface established as a result of the connect operation.


Character FSDs

A character FSD accesses character devices. It registers a set of device names with the IFS manager. Anytime there is a file system request on these device names, the IFS routes it to the character FSD to handle. On its first access, a character FSD can choose to mount a device or reject it. Once a device is mounted, the FSD will be called on all requests to that device name. The FSD can communicate with the actual device either directly or through a stack of character device drivers provided as part of the IO subsystem. This provides a very elegant and efficient way to access character devices. Character FSDs register with the IFS manager using the IFSMgr_RegisterCFSD service and get called on the FS_MountVolume entry point to be mounted on a character device. Once mounted, all requests are routed through the interface established as a result of the mount operation.

Both the mount and connection operations return a resource handle that is used by the IFS manager to identify the disk volume, character device or network resource for file operations. This resource handle may simply be a pointer to the FSD specific data structures used to manage the specific resource.


File Date and Time Formats

There are two date and time formats used by the Win32 and INT 21h APIs. The DOS time format is used in the INT 21h APIs. The date and time are stored as bit fields in a DWORD.

The hour, minute, and second are stored in the low-order word in the following format:

    +---------------+---------------+
    |H|H|H|H|H|M|M|M|M|M|M|S|S|S|S|S|
    +---------------+---------------+
    15                             0

Where "H" is the hour (zero through 23), "M" is the minute (zero through 59), and "S" is the number of seconds divided by 2. For the new Create Time APIs, additional precision has been added by specifying the 10 millisecond remainder in the 2-second interval that the DOS time format provides for. This remainder can be a value between zero and 199.

The year, month, and day are stored in the high-order word in the following format:

    +---------------+---------------+
    |Y|Y|Y|Y|Y|Y|Y|M|M|M|M|D|D|D|D|D|
    +---------------+---------------+
    15                             0

Where "Y" is the year minus 1980, "M" is the month (1 = January, 2 = February, etc.), and "D" is the day of the month (1 through 31).

The Win32 time format is used by the Win32 APIs. The date and time is stored in a 64-bit value that represents the number of 100 nanoseconds since January 1st, 1601. This date was chosen because it is 400 years prior to the start of a new century. At 100ns resolution 32 bits is good for about 429 seconds (or 7 minutes) and a 63-bit integer is good for about 29,247 years.


File System Concepts

This section discusses certain key concepts that are a part of the file system and are referred to numerous times through this document.


Canonicalized Paths

All path names that the IFS manager passes to the FSDs are in unicode. A canonicalized path name has a specific format that is described by the ParsedPath structure. It consists of a word giving the total length of the path name (including itself, but not including the NUL character), a word giving the offset of the last path element in the path name relative to the start of the path name and a sequence of PathElement structures. Each PathElement structure comprises a word giving the length of the path element (including itself) and a string of unicode characters that make up the name of the path element. The path name is always absolute and describes a path from the root of the volume. A normal path structure would have each path element separated by a path separator, such as "\" or "/". By passing in canonicalized paths to the FSDs, the need for each FSD to have its own parsing code has been eliminated. FSDs will get syntactically validated paths at all times and because of the canonicalized structure, it is very easy to traverse the path to perform operations. In addition to the canonicalized path, the IFS also passes in certain flags that give more information about the kind of path name such as whether the path name has wildcards or has long name components, etc. These are described in the following.

FILE_FLAG_LONG_PATH | This path name has long path components. If only this flag is set, the last path component is not a long name. On short name APIs, it is permissible for the path components to have long names. This is because an app could issue a short name call in a long current directory and we want this operation to work. If the app tries to change to a long name directory or create a long name using a short API, the IFS manager will truncate that name as per DOS rules. FSDs can have different searching semantics based on whether the path name has long components or not and this flag can be used to trigger this behavior.
FILE_FLAG_IS_LFN | The final element of this path name is a long name. FSDs can use this knowledge to do things differently. It may be necessary to store long names in a different format than short names. This flag can be used to trigger off such behavior without the FSD needing to scan the entire path name to figure out if it is trying to use a long name final element. Also, the fact that the final path element is a long name implies that the FSD should use long name semantics for matching.
FILE_FLAG_WILDCARDS | The path name passed in contains wildcards. Wildcards are valid only in the final path component and a path with wildcards elsewhere on the path will result in an error by the IFS manager and not passed down to FSDs. The wildcards could be either "?" characters or "*" characters. On the short name APIs, only the "?" character is valid as a wildcard. For long name APIs, both wildcard characters are valid. FSDs can use this flag to figure out whether they need to do wildcard matching during their file name search.
FILE_FLAG_HAS_STAR | The path name passed in contains the "*" character as a wildcard. FILE_FLAG_WILDCARDS is always set whenever this flag is set. This flag is given to provide additional information to FSDs about how to perform meta-matching. Meta-matching semantics are much simpler for the "?" character than for the "*" character and FSDs can use this fact to optimize meta-matching. However, it is recommended that all FSDs use the IFSMgr_MetaMatch service for doing meta-matching. This ensures a consistent interface to the user so that all file systems behave identically with respect to wildcard operations.
FILE_FLAG_HAS_DOT | The path name passed in contains a "." character. The IFS manager strips off trailing dots. Leading dots are preserved if there are other characters in the path element that are not dots. There is only one exception when the IFS manager allows a trailing dot. This is when there are wildcard characters present in the path component. This is to allow users to use matching semantics such as "*", which DOS allows, though, it does not strictly conform to the true regular expression matching semantics that the long name matching semantics use. Even in this case, multiple-trailing dots are stripped by the IFS manager, leaving only a single trailing dot.
FILE_FLAG_KEEP_CASE | The FSD should preserve the case of the name passed in when it stores it on disk. If this flag is not set, the FSD can ignore the case of the name. This flag is set for all LFN APIs and cleared for short-name APIs. This flag is also overloaded with another meaning. If this flag is set, then the FSDs should use LFN semantics. Otherwise, they should use short name semantics.

To determine whether LFN or short-name semantics need to be used on a given API, FSDs should look at FILE_FLAG_KEEP_CASE and FILE_FLAG_IS_LFN. If either or both of these flags are set, then the FSD should use LFN semantics. The FSD should not hardcode the usage of LFN semantics just because it is a new LFN-based API for example, the LFN-style FindFirst. There are certain cases, especially across the server when an LFN-style API may desire short name semantics. This is true for the LFN-style FindFirst when it is issued by the server. The server does it because it may have a long-name directory shared, which an application at the client end need not be aware of and can get to files by using short-name APIs.


Meta Character Matching Semantics

There are two kinds of meta-character matching semantics in operation: one for the short-name APIs and one for the long-name APIs. Both of these are described in the following.

The meta-character matching on short-name APIs is very simple. No "*" characters are allowed, "?" is the only wildcard character allowed. Any "*" characters passed in by the user are converted to "?" characters by the IFS manager before passing the name to the FSDs. The names are also fixed length, that is, the standard 8.3 name format. The algorithm used is the DOS algorithm, which just superimposes two 8.3 strings, with a "?" character standing for any character.

The meta-character matching on long-name APIs is more complex. It provides regular expression matching. The "*" character stands for zero or more characters, the "?" character stands for 1 character. The dot is not a special character on the long-name APIs, it is just another character that is part of the name. Users can thus do proper regular expression matching such as "a*.b*.c*". There are some special cases where true regular expression matching has been abandoned in favor of compatibility. For example, "*.*" strictly speaking means all file names that have a dot in them. However, because DOS users use this to mean all files, the long-name matching semantics have been changed to treat "*.*" to be equivalent to a "*" and match all files. "*." is another exception to the rule. In DOS, "*." means all files without an extension, which violates regular expression matching. However, this has been implemented for compatibility reasons.

FSDs should use the IFSMgr_MetaMatch services to do all meta-character matching. This service provides both short-name and long-name matching semantics and also encapsulates all the special cases that have been discussed above, so that FSDs do not need to take care of them. This also ensures that if we need to take care of more special cases in future, FSDs will not need to change, all changes can be made in the IFS manager and all FSDs will automatically work.


Must Match Attributes

There are certain new APIs that take must match attributes in as parameters. Must match attributes are different from normal search attributes that are passed in. It consists of two sets of attributes: a search attribute, and another attribute called the must match attribute, which is an additional filter on the attributes retrieved from the media. The basic formula for this is as follows:

(((MustMatchAttr & MediaAttr) ^ MustMatchAttr) & FILE_ATTRIBUTE_MUSTMATCH) == 0
where FILE_ATTRIBUTE_MUSTMATCH = 0x3F.

What this algorithm basically does is to match only those entries whose media attributes have at least one of the bits in the MustMatchAttr set. For example, if the user passes in attributes of 0x1016, 0x16 is the search attribute and 0x10 is the must match attribute. The search operation thus finds all directories and files. However, the must match attribute filters this additionally and so only directories are considered matches and are returned on the API. Notice that attribute bits are matched, not the entire attribute value, that is, an entry with the attribute of 0x14 (hidden directory) will also be matched with a must match attribute of 0x1016. This also means that there is no way to specify finding files/directories without a certain attribute set, you can only match for entries with a certain attribute set.


Swap File Handling

FSDs that handle media on which the swap file for Chicago resides, need to do certain special stuff to take care of it. The swap file is different from normal files and needs special handling for the system to keep working. The special considerations needed for the swap file are listed in the following:

  1. All data structures that are used for the swap file need to be locked down. All code paths that can be hit during swap-file IO should also be locked down. In other words, no paging can occur while an FSD is processing reads or writes to the swap file.
  2. It is advisable to not cache the swap-file data though this is not a must. This is because the swap-file data would just crowd out other more relevant data in the cache. The important thing to keep in mind is that no memory allocations can be made while doing swap-file I/O nor can any paging happen. This puts a pretty big restriction on any cache, in that, it cannot be dynamic and also has to be locked down. For these reasons, it makes much more sense to write the swap-file data directly to the disk without going through a cache. The IFS manager provides a special flag called R0_SWAPPER_CALL on FS_OpenFile and FS_ReadWrite to inform FSDs that this is swap-file I/O. In addition there are also special flags passed in to prevent read-aheads, write-behinds on the swap file. These are all described in Section 8.5 under the respective functions.
  3. The memory manager does swap-file I/O only at 4K boundaries and in multiples of 4K. Since swap-file transfers are guaranteed to be aligned, FSDs can optimize the swap-file code path without having to take care of any partial transfers, etc. In addition, the transfer addresses that the swap file passes down are all locked, so the FSDs can optimize further by not trying to lock the user pages in case of the swap file.
  4. The FSD should be reentrant with respect to I/O on the swap file. For example, the FSD may take semaphores around code that allocates clusters to prevent any other writers from coming in. However, reads and writes to the swap file need to be permitted at all times. This is also safe because such writes to the swap file will not grow the file. Besides, only the memory manager can access the swap file, no one else in the system is allowed to access it.
  5. There is one catch to (4) above. The memory manager can issue a call to grow or shrink the swap file. Obviously, the restrictions on memory allocation and paging do not apply in this case. The memory manager guarantees that size changes of the swap file will occur at a time when it is safe to do so and this operation can block. The other thing that the FSD needs to be aware of in this case is that, while the swap file is being grown or shrunk, there can be another write to the swap file. However, this I/O is guaranteed to be in the region within the old size of the swap file and not in the region that is being changed. Given this condition, it is fine to be reentered.


Memory Mapped File Handling

Memory mapped files in Chicago also need special handling by FSDs. A memory mapped file is basically an extension of the swap file. The memory mapped file now provides virtual memory for the system. This means that most of the restrictions that apply to the swap file also apply to memory mapped files. Thus, conditions (1), (3) and (4) listed in Swap File Handling for swap files apply directly to memory mapped files.

There are a few important differences, however:

  1. Unlike condition (2), it is fine to cache data for memory mapped files. In fact, it would be preferable to cache them. While this may sound contradictory, there are a lot of memory mapped files that can get loaded again and again by different processes, in which case, it would make sense to cache the file even though it is eventually going to become memory mapped.
  2. A memory mapped file cannot grow or shrink. Once a memory mapping is created to a file, the size of the mapping cannot change. It is conceivable that another process could open the same file and change its size, but this would cause an error during the memory mapping and, in itself, cannot affect system integrity.
  3. A file is not opened memory mapped, instead, it is opened as a normal file and then a memory mapping is created for it. This means that the FSD now needs to transform the status of a file from normal to a special memory mapped file. For this purpose, the IFS manager calls the FSDs at the time the memory mapping is created so that the FSDs can now mark that this is a memory mapped file and lock everything down (if not already locked). The IFS signals this by calling the FSD on a zero-length read with a special flag R0_MM_READ_WRITE. This interface is described in Section 8.5.23


Vendor-Supplied Drivers

A vendor-supplied driver (VSD) intercepts and processes I/O requests for a given block device. The VSD gives a vendor an efficient way to incorporate enhancements into an existing layered block device driver or to extend the capabilities of the driver to new but similar hardware. A VSD typically works with a given port driver or set of port drivers and therefore is retained in memory and used by Windows® 95 only if the given adapter supported by the port driver is present in the system.

This part of the Windows 95 DDK Design and Implementation Guide describes the responsibilities and requirements of a VSD and explains how to build and test a VSD.


Virtual Device Requirements

A VSD must be a dynamically-loadable virtual device that defines a control procedure. A VSD may define services using CreateFile and DeviceIoControl, examples of this are SMARTVSD.VXD and APIX.VXD, however using a VSD to implement services is the exception rather than the rule. The control procedure must process the SYS_DYNAMIC_DEVICE_INIT message. All other messages can be ignored.

The driver must have device name, a major and minor version number, and an initialization order. Although unique names are not required, a name that uniquely identifies the type of adapter supported by the driver is recommended. The initialization order for the driver must be UNDEFINED_INIT_ORDER.

The following example shows a typical virtual device declaration for a VSD:

DECLARE_VIRTUAL_DEVICE HELPVSD,\
    HELPVSD_MAJOR_VERSION, \
    HELPVSD_MINOR_VERSION,\
    HelpVSD_Control,,\
    UNDEFINED_INIT_ORDER\
    ,,,Drv_Reg_Pkt

In this example, Drv_Reg_Pkt is the name of the DRP structure (also known as the device registration packet) for the driver. The DRP structure is required for loading and registration. The following example is a typical DRP definition:

Drv_Reg_Pkt    DRP <EyeCatcher, DRP_VSD_9, offset32 Help_Async_Request,\
    offset32 vsd_ilb, HelpVSDName, HelpVSDRev, HelpVSDFeature,\
    HelpVSD_IF>

For successful loading, at least the DRP_LGN member of the structure must be set at when the driver is assembled. Other members must be set to zero if not initialized to valid values.

The I/O supervisor (IOS) loads and initializes all VSDs. To ensure that the IOS locates the driver, the VSD file must have the file name extension .VXD and the file must be placed in the SYSTEM\IOSUBSYS directory.

Warning Do not use a device entry in the SYSTEM.INI file to load a VSD.

See Also

DRP


Driver Initialization and Registration

To initialize the VSD, the IOS sends a SYS_DYNAMIC_DEVICE_INIT message to the driver's control procedure. When the driver receives the message, the driver must register with the IOS by passing the address of its DRP structure to the IOS_Register service. The VSD must set at least these DRP members:

DRP_LGN | The load group number for the VSD should be one of these values: DRP_VSD_1, DRP_VSD_2, DRP_VSD_3, DRP_VSD_4, DRP_VSD_5, DRP_VSD_6, DRP_VSD_7, DRP_VSD_8, or DRP_VSD_9.
DRP_aer | A VSD must provide an asynchronous event routine. The routine must handle these asynchronous event functions: AEP_CONFIG_DCB and AEP_BOOT_COMPLETE.
DRP_ilb | A VSD must provide an ILB structure to receive the addresses of the IOS service routines.

Most VSDs also set the DRP_eyecatch_str, DRP_ascii_name, DRP_revision, DRP_feature_code, and DRP_if_requirements members.

After the IOS_Register service returns, the VSD must check the DRP_reg_result member for the values DRP_REMAIN_RESIDENT or DRP_MINIMIZE to determine whether the registration was successful. If success, the driver clears the carry flag before returning to indicate that it successfully processed the SYS_DYNAMIC_DEVICE_INIT message. If DRP_reg_result is any other value, an error occurred and the driver must set the carry flag before returning.

See Also

DRP, IOS_Register


Asynchronous Event Processing

A VSD must process the AEP_CONFIG_DCB and AEP_BOOT_COMPLETE functions that it receives during driver registration.

When processing the AEP_CONFIG_DCB function, the VSD must determine whether the given DCB corresponds to the type of bus and block device it can support. If so, the driver inserts itself into the calldown list for the DCB by using the ISP_INSERT_CALLDOWN function of the ILB_service_rtn routine. The driver must set the ISP_i_cd_req member to the address of the I/O request routine for the VSD. Subsequently, this routine is called whenever an I/O request for the device associated with the DCB is issued.

When processing the AEP_BOOT_COMPLETE function, the VSD must determine whether it successfully detected any devices it can support. If not, the driver must set the AEP_result member to AEP_FAILURE. This ensures that the VSD will be removed from memory.

Depending on whether the VSD specified additional values in the DRP_feature_code member of its DRP structure it may need to process additional asynchronous event functions.

See Also

AEP, DCB, DRP, ILB_service_rtn, ISP


I/O Request Processing

A VSD receives I/O requests through its I/O request routine, that is, the routine the driver inserted in the calldown list when processing the AEP_CONFIG_DCB function.

When the driver receives a request, the IOP structure for the request is on the stack. The driver must check the IOR_func member to determine whether it should process the request. If the VSD does not recognize the request or does not include code to process the request, it must pass the request to the next driver in the calldown chain. Before the VSD passes a request to the next driver, the VSD must install its own callback procedure in the IOP structure. This ensures that the VSD receives notification when the request is complete and permits the VSD to pass this notification to drivers in layers above it.

A VSD that processes a request can do so in a variety of ways, such as:

  • Modify the request data before passing it to the next driver
  • Process the request without passing it to lower layers
  • Generate new requests and passing them through the calldown chain

If a VSD passes a modified request to the next driver in the calldown chain, the VSD must install its own callback procedure in the IOP structure to make sure that the VSD receives notification when the request is complete.

A VSD typically processes a request without passing it to lower layers if it can complete the request without accessing the device. In such cases, the VSD must set the IOR_result member to an appropriate value and call the callback procedure whose address is pointed to by the IOP_callback_ptr member.

If a VSD generates new I/O requests in response to a given request, the VSD must use I/O services such as the IOP_CREATE_IOP and IOP_DEALLOC_MEM functions to allocate and free memory for the corresponding IOP structures. A VSD can initiate an synchronous internal I/O request by calling the ILB_internal_request routine.

See Also

AEP, ILB_internal_request, IOP, IOR


Safe Master Boot Record INT 13h Hook Routines

By default, Windows 95 assumes that a Master Boot Record (MBR) that contains code that hooks INT 13h is unsafe. In such cases, Windows 95 prevents its protected mode drivers from taking over I/O operations for the device and instead uses the real mode mapper to pass I/O requests to the real mode code. This default behavior is intended to ensure that the extended functionality provided by the MBR INT 13h hook routine is still available after Windows 95 starts.

In some cases, this default behavior is not desirable. For example, if the extended functionality is also available in protected mode through a VSD, Windows 95 should not use the real mode mapper and instead should allow the protected mode driver to take over I/O operations. To prevent the default behavior, you can override it by installing safe MBR INT 13h hook routines. The first bytes of a safe routine have the following form:

SAFMBRSIG0  EQU  544e4924h  ; reverse of $INT
SAFMBRSIG1  EQU  46533331h  ; reverse of 13SF

SafeMBRHook  STRUC
    smhjmp  db  3 dup (?)  ; 3 bytes for short jmp instruction
    smhsig  db  8 dup (?)  ; Safe ID string = '$INT13SF'
    smhid   db  8 dup (?)  ; Vendor ID string
    smhnext dd  ?          ; seg:off address of prev int13
                           ;  handler
    smhflgs dd  ?          ; flags.
SafeMBRHook  ENDS

Although multiple INT 13h hook routines can be installed, all of the routines must be safe for Windows 95 to proceed with the loading and initializing the protected mode drivers for the device. During initialization and while processing of the SYS_DYNAMIC_DEVICE_INIT message, a VSD that is responsible for taking over the functionality of a hook routine must set the corresponding smhflgs field to 1. The VSD can check the smhid field to identify and verify the hook routine.

If the extended functionality provided by the real mode hook routine exceeds the capabilities of the protected mode port driver, the VSD is responsible for examining I/O requests made by the port driver during its initialization. To hook I/O before the port driver, the VSD can set the DRP_FC_NEED_PRELOAD value in the DRP_feature_code field of its DRP structure (NOTE: See DCB_dmd_preload flag, which corrects a DRP_FC_NEED_PRELOAD bug). In this case, the VSD receives the AEP_CONFIG_DCB function before the corresponding port driver and can process the DCB accordingly. The VSD can alternately use the DRP_FC_NEED_PRE_POST_LOAD value if necessary. This is the same as the DRP_FC_NEED_PRELOAD value except that the VSD receives two AEP_CONFIG_DCB calls for each DCB: one before the port driver and one after the layer drivers before the VSD's load group have been initialized. The VSD must take care not to insert twice into the same DCB.

See Also

DCB, DRP


Port Drivers

A port driver manages and controls the adapter for a given block device. The port driver detects and initializes the adapter, handles interrupts, transmits I/O requests to the device, and carries out adapter-level error recovery and logging. A port driver typically works with a specific, proprietary adapter and therefore is retained in memory and used by Windows® 95 only if the given adapter is present in the system.

This part of the Windows 95 DDK Design and Implementation Guide describes the responsibilities and requirements of a port driver and explains how to build and test a port driver for your adapter.


Virtual Device Requirements

A port driver must be a dynamically loadable virtual device that defines a control procedure but does not define services or APIs. The control procedure must process the SYS_DYNAMIC_DEVICE_INIT message. All other messages can be ignored.

The driver must have device name, a major and minor version number, and an initialization order. Although unique names are not required, the name that uniquely identifies the adapter supported by the driver is recommended. The initialization order for the driver must be UNDEFINED_INIT_ORDER.

The following example shows a typical virtual device declaration for a port driver

DECLARE_VIRTUAL_DEVICE PORT,\
    PORT_MAJOR_VERSION, \
    PORT_MINOR_VERSION,\
    PORT_Control,,\
    UNDEFINED_INIT_ORDER\
    ,,,Drv_Reg_Pkt

In this example, Drv_Reg_Pkt is the name of the DRP structure (also known as the device registration packet) for the driver. The DRP structure is required for loading and registration. The following example is a typical DRP definition:

Drv_Reg_Pkt DRP <EyeCatcher, DRP_MISC_PD, offset32 Port_Async_Request,\
    offset32 port_ilb, PortName, PortRev, PortFeature, Port_IF>

For successful loading, at least the DRP_LGN member of the structure must be set at when the driver is assembled. Other members must be set to zero if not initialized to valid values.

The I/O supervisor (IOS) loads and initializes all port drivers. To ensure that the IOS locates the port driver, the port driver file must have the file name extension .PDR and the file must be placed in the SYSTEM\IOSUBSYS directory.

Warning Do not use a device entry in the SYSTEM.INI file to load a port driver.

See Also

DRP


Driver Initialization and Registration

To initialize the port driver, the IOS sends a SYS_DYNAMIC_DEVICE_INIT message to the driver's control procedure. When the driver receives the message, the driver must register with the IOS by passing the address of its DRP structure to the IOS_Register service. The port driver must set at least these DRP members:

DRP_LGN | The load group number for the port driver should be one of these values: DRP_MISC_PD, DRP_ESDI_PD, DRP_ESDIEMUL_PD, DRP_ABIOS_PD, or DRP_ABIOS_PREMPT_PD.
DRP_aer | A port driver must provide an asynchronous event routine. The routine must handle these asynchronous event functions: AEP_INITIALIZE, AEP_CONFIG_DCB, AEP_DEVICE_INQUIRY, AEP_IOP_TIMEOUT, and AEP_BOOT_COMPLETE.
DRP_ilb | A port driver must provide an ILB structure to receive the addresses of the IOS service routines.

Most port drivers also set the DRP_eyecatch_str, DRP_ascii_name, DRP_revision, DRP_feature_code, and DRP_if_requirements members.

After the IOS_Register service returns, the port driver must check the DRP_reg_result member for the values DRP_REMAIN_RESIDENT or DRP_MINIMIZE to determine whether the registration was successful. If success, the port driver clears the carry flag before returning to indicate that it successfully processed the SYS_DYNAMIC_DEVICE_INIT message. If DRP_reg_result is any other value, an error occurred and the port driver must set the carry flag before returning.

See Also

DRP, IOS_Register


Asynchronous Event Processing

A port driver must process the AEP_INITIALIZE, AEP_DEVICE_INQUIRY, AEP_CONFIG_DCB, and AEP_BOOT_COMPLETE functions that it receives during driver registration.

When processing the AEP_INITIALIZE function, the port driver must:

  1. Allocate a DDB structure using the ISP_DDB_CREATE function of the ILB_service_rtn routine. You must allocate enough space for the members of the DDB structure and any driver-specific members needed to hold configuration information.
  2. Retrieve configuration information for the device, such as IRQ and base port address, by using the configuration manager services and save this information in the corresponding members of the DDB structure.
  3. Initialize the adapter hardware, if necessary.
  4. Set the IRQ handler for the device using the virtual PIC services and the updated members of the DDB structure.

If the port driver completes each initialization step successfully, it returns AEP_SUCCESS. Otherwise, the driver must free the allocated DDB structure by using the ISP_DEALLOC_DDB function and return AEP_FAILURE.

When processing an AEP_DEVICE_INQUIRY function, the port driver must determine whether a drive exists for the specified drive number. If a drive does not exist, the driver must set the AEP_result member to AEP_FAILURE; otherwise, set the member to AEP_SUCCESS. The port driver will continue to receive AEP_DEVICE_INQUIRY functions until all 127 possible drive numbers have been specified or the driver sets the AEP_result member to AEP_NO_MORE-DEVICES.

When processing the AEP_CONFIG_DCB function, the port driver must insert itself into the calldown list for the DCB by using the ISP_INSERT_CALLDOWN function of the ILB_service_rtn routine. The driver must set the ISP_i_cd_req member to the address of the I/O request routine for the port driver. Subsequently, this routine is called whenever an I/O request for the device associated with the DCB is issued.

When processing the AEP_BOOT_COMPLETE function, the port driver must determine whether it successfully detected any devices it can support. If not, the driver must set the AEP_result member to AEP_FAILURE. This ensures that the port driver will be removed from memory.

A port driver should also process the AEP_IOP_TIMEOUT function. The driver should examine the given IOP structure and determine whether the IOP is one which is being processed. If it is, the driver should reset the hardware (if needed) and either retry the request or indicate an error.

Depending on whether the port driver specified additional values in the DRP_feature_code member of its DRP structure it may need to process additional asynchronous event functions.

See Also

AEP, DDB, DRP, ILB_service_rtn, IOP, ISP


I/O Request Processing

A port driver receives I/O requests through its I/O request routine, that is, the routine the driver inserted in the calldown list when processing the AEP_CONFIG_DCB function.

When the driver receives a request, the IOP structure for the request is on the stack. The driver must check the IOR_func member to determine whether it can process the request. If the request is valid, the driver should carry out the request immediately if possible. If the device is not ready to carry out I/O operations, the driver should use the ILB_enqueue_iop routine to place the IOP and the corresponding DCB structure in the IOP queue, then return from the request. Later, when the device is ready, the driver can use the ILB_dequeue_iop routine to retrieve the IOP from the queue and process the request.

When the driver completes processing of a request, the driver must set the IOR_status member to an appropriate value and call the callback procedure whose address is pointed to by the IOP_callback_ptr member. If the driver can not process a request, either because the request fails or is invalid, the driver must set IOR_status and call the callback procedure.

When a port driver receives an I/O request, it expects the following members to be valid in the IOP and IOR structures:

IOR_func | Function to be performed.
IOP_physical_dcb | Address of physical DCB for the device.
IOR_xfer_count | Total size of transfer, if any.
IOR_sgd_lin_phys | Linear address of list of scatter/gather elements, if any.
IOR_num_sgds | Count of scatter/gather elements.

The port driver always updates the IOR_status member, setting it to a value that indicates the status of the completed request.

See Also

AEP, ILB_dequeue_iop, ILB_enqueue_iop, IOP, IOR


Interrupt Handling

A port driver must service any interrupts that occur for the corresponding devices. The driver should determine whether any outstanding requests is still being processed. If no request is being processed, the driver should check for additional requests in the IOP queue and begin processing the request at the top of the queue. If no requests are in the queue, the handler should return.


SCSI Miniport Drivers

SCSI miniport drivers are HBA-specific but OS-independent. That is, each miniport driver links itself against the SCSI port driver and calls only the port driver's ScsiPort Xxx routines to communicate with the system. HBA miniport drivers can be compiled to run on machines running Windows® 95 or Windows NT®/Windows® 2000. Each platform provides an OS-dependent port driver that exports the ScsiPort Xxx routines.

Every SCSI miniport driver must have at least the following system-defined routines:

  • DriverEntry to initialize the miniport driver
  • HwFindAdapter to determine how (or whether) driver-supported HBA(s) are configured in the machine
  • HwInitialize to initialize the HBA(s)
  • HwStartIo to start operations on the HBA for an incoming request
  • HwResetBus to handle bus-reset requests

Depending on the HBA and the driver designer, SCSI miniport drivers also can have any or all of the following system-defined routines:

  • HwInterrupt to handle HBA-generated interrupts, which is optional if and only if the miniport manages all I/O operations on its HBA by polling

However, using polling exclusively has an adverse effect on a miniport's performance and on its HBA's I/O throughput.

  • HwDmaStarted to set up an HBA transfer after the system DMA controller has been programmed by the port driver
  • HwDisableInterruptsCallback and HwEnableInterruptsCallback to handle deferred I/O processing if a particular operation takes a long time
  • HwTimer to time operations on the HBA that require long delays

    A miniport should have a HwTimer routine if it has no HwInterrupt routine so it can use the HwTimer routine for efficient polling of the HBA.

  • HwAdapterState, defined for compatibility with future MS-DOS versions

The following sections describe the requirements for and functionality of each of these miniport driver routines. For reference information about the services the SCSI port driver offers to a miniport driver, see Introduction to SCSI Port Driver Services Reference.

For a description of the error-handling requirements for SCSI miniport drivers, see Error Handling.


DriverEntry Routine

A DriverEntry routine is the initial entry point for each driver, including each SCSI miniport driver. A miniport's DriverEntry routine is called with two input arguments (of type PVOID) and must do the following:

  1. Initialize a HW_INITIALIZATION_DATA structure (on the stack) with zeros.
  2. Set driver-specific and HBA-specific values in the HW_INITIALIZATION_DATA fields, including the miniport driver's entry points. The following entry points must be set:
    • HwFindAdapter
    • HwInitialize
    • HwStartIo
    • HwResetBus The following entry points can be set to a driver-supplied routine or must be set to NULL:
    • HwInterrupt (NULL if the miniport uses polling exclusively)
    • HwDmaStarted
    • HwAdapterState (NULL)
  3. Set up any driver-determined context data that the miniport's HwFindAdapter routine uses.
  4. Call ScsiPortInitialize with the pointers that were input to the DriverEntry routine, the address of the filled-in HW_INITIALIZATION_DATA, and the address of the context data, if any.

A miniport driver can have a set of bus-type-specific HwFindAdapter routines if its HBA can be connected on various types of I/O bus. Such a miniport driver must modify the AdapterInterfaceType and HwFindAdapter fields in the HW_INITIALIZATION_DATA after each call to ScsiPortInitialize, possibly modify the context data for the new bus type, and call ScsiPortInitialize for each type of bus on which a supported HBA might be connected.

ScsiPortInitialize checks the validity of the HW_INITIALIZATION_DATA, collects and stores pertinent information in the device extension of a device object that it creates to represent the HBA, allocates memory for a PORT_CONFIGURATION_INFORMATION-type buffer, fills in as much configuration information as it can, and calls the miniport driver's HwFindAdapter routine, described in HwFindAdapter Routines.

If the miniport driver sets a particular AdapterInterfaceType value in the HW_INITIALIZATION_DATA but there is no bus of that type in the machine, the port driver returns STATUS_DEVICE_DOES_NOT_EXIST. It does not call the driver-supplied HwFindAdapter routine for that bus type. The miniport driver does not remain loaded if its HBA can be connected only to one or more types of bus that are not present in the machine.

Note that ScsiPortInitialize is responsible for the following before it returns control to the miniport's DriverEntry routine:

  • Setting up all necessary system objects
  • Getting configuration information from and setting configuration information in the registry
  • Allocating system resources on behalf of the miniport driver, including memory for the miniport-specified DeviceExtensionSize, SpecificLuExtensionSize, and/or SrbExtensionSize in which the miniport driver can maintain HBA-specific state, per-logical-unit state, and/or per-request state, respectively

The miniport driver defines the internal structure and contents of its device extension, logical unit extensions (if any), and SRB extensions (if any). A pointer to the device extension is an input argument to every system-defined miniport driver routine except DriverEntry. Many ScsiPort Xxx routines require this pointer as an argument.

When ScsiPortInitialize returns control, the DriverEntry routine propagates the return value of ScsiPortInitialize when DriverEntry itself returns control. If the miniport driver calls ScsiPortInitialize more than once, its DriverEntry routine should propagate the lowest return value.

ScsiPortInitialize can be called only from a miniport driver's DriverEntry routine. For more information about the HW_INITIALIZATION_DATA structure and ScsiPortInitialize, see the Introduction to SCSI Port Driver Services Reference.


HwFindAdapter Routines

The port driver fills in as much PORT_CONFIGURATION_INFORMATION as it can from the miniport's returned HW_INITIALIZATION_DATA and from the registry before calling a HwFindAdapter routine with a pointer to the configuration information buffer. In particular, the port driver always sets the following:

  • Length to sizeof(PORT_CONFIGURATION_INFORMATION)
  • AdapterInterfaceType to the miniport's HW_INITIALIZATION_DATA specification
  • InterruptMode to LevelSensitive if the AdapterInterfaceType is set to MicroChannel; otherwise, set to Latched

If the miniport has no HwInterrupt routine and, therefore, set this entry point to NULL in the HW_INITIALIZATION_DATA, this field is irrelevant.

  • AtdiskPrimaryClaimed to TRUE if a previously loaded driver is using the I/O port range 0x1F0 to 0x1FF
  • AtdiskSecondaryClaimed to TRUE if a previously loaded driver is using the I/O port range 0x170 to 0x17F
  • NumberOfAccessRanges to the miniport's HW_INITIALIZATION_DATA specification

The port driver also attempts to fill in the following fields with values from the registry:

  • SystemIoBusNumber set to zero if there is only one bus of a particular type in the machine

    Otherwise, the miniport's HwFindAdapter routine can be called for each bus of the given AdapterInterfaceType with an updated value for SystemIoBusNumber, or this value can be set to a value from the registry if the system detects an HBA on a particular bus.

  • AccessRanges elements, set with the RangeStart and RangeLength of each element, as well as whether each element is a RangeInMemory

    RangeInMemory set to FALSE indicates a range of ports in I/O space, rather than a memory-mapped range.

  • BusInterruptLevel or BusInterruptVector

This field is irrelevant if the miniport has no HwInterrupt routine.

  • DmaChannel or DmaPort if the HBA uses system DMA

    If the HBA is a busmaster or uses PIO, these fields in the PORT_CONFIGURATION_INFORMATION are irrelevant.

  • InitiatorBusId

A HwFindAdapter routine calls ScsiGetBusData and examines the returned bus-type-specific configuration information, such as POS data or EISA configuration data, for a supported HBA. If the input PORT_CONFIGURATION_INFORMATION AccessRanges elements have been filled in from the registry, the HwFindAdapter routine should use these addresses and should not scan for adapters at other locations.

If HwFindAdapter cannot find an HBA it supports, it should set Again to FALSE and return SP_RETURN_NOT_FOUND. If the HwFindAdapter routine finds a supported HBA but the input PORT_CONFIGURATION_INFORMATION has invalid data (such as an invalid DmaChannel or BusInterruptLevel on an EISA bus), it should set Again to FALSE and return SP_RETURN_BAD_CONFIG.

Note that setting Again to FALSE and returning control with SP_RETURN_NOT_FOUND or SP_RETURN_BAD_CONFIG indicates that a given I/O bus, identified by the SystemIoBusNumber in the input PORT_CONFIGURATION_INFORMATION buffer, has no HBAs connected that the miniport driver can support. It does not prevent the port driver from calling HwFindAdapter again with updated PORT_CONFIGURATION_INFORMATION to scan another I/O bus for HBA(s) if the machine has additional buses of the same AdapterInterfaceType.

When the HwFindAdapter routine finds an HBA it can support, this routine must fill in pertinent fields, as appropriate for its HBA and the given AdapterInterfaceType, in the input PORT_CONFIGURATION_INFORMATION buffer. Every miniport driver must fill in the AccessRanges information, converting each AccessRanges element's RangeStart value with ScsiPortConvertUlongToPhysicalAddress.

For an "AT-compatible" HBA, the HwFindAdapter routine should check the input Atdisk..Claimed fields and attempt to claim an "AT" range by resetting the value to TRUE.

The HwFindAdapter routine can set Again to TRUE to indicate it should be called again with exactly the same configuration information if another of its HBAs might be connected on the same I/O bus. For a supported HBA, the HwFindAdapter routine returns SP_RETURN_FOUND.

If the PORT_CONFIGURATION_INFORMATION buffer input to the HwFindAdapter routine has no configuration information from the registry, HwFindAdapter can set driver-defined default values for AccessRanges elements, InterruptLevel or BusInterruptVector, DmaChannel or DmaPort if the HBA uses system DMA, and InitiatorBusId, and, then, call ScsiPortGetBusData and examine the returned configuration information for a supported HBA on the I/O bus.

Certain ScsiPort Xxx routines can be called only from the miniport driver's HwFindAdapter routine(s), in particular, the following:

  • ScsiPortGetBusData to get BUS_DATA_TYPE-specific configuration information
  • ScsiPortGetDeviceBase to map the (bus-relative) base physical address range for an HBA to a system address range that the driver can use to communicate with the HBA by calling the ScsiPortReadXxx and ScsiPortWriteXxx routines
  • ScsiPortFreeDeviceBase to release such a mapped range if HwFindAdapter does not find an HBA it can support on a given I/O bus (as indicated by the PORT_CONFIGURATION_INFORMATION SystemIoBusNumber value)
  • ScsiPortGetUncachedExtension to allocate a DMA buffer shared between the system and a busmaster HBA

For more information about the PORT_CONFIGURATION_INFORMATION structure and these ScsiPort Xxx routines, see the Introduction to SCSI Port Driver Services Reference.

When a miniport driver's HwFindAdapter routine returns control, ScsiPortInitialize returns to the DriverEntry routine if the call(s) to HwFindAdapter indicated that the miniport driver could not support an HBA. Otherwise, ScsiPortInitialize claims resources in the registry, sets up necessary system objects (such as interrupt and adapter objects) on behalf of the miniport driver, and calls the miniport's HwInitialize routine, described in HwInitialize Routine.

In addition to the values it sets in the PORT_CONFIGURATION_INFORMATION buffer, ScsiPortInitialize also checks the registry for user-set values that disable any or all of the following:

  • Synchronous transfers on the HBA

The port driver ORs the default SrbFlags that it maintains for the HBA with SRB_FLAGS_DISABLE_SYNCH_TRANSFER.

  • Bus-disconnect operations on the HBA

The port driver ORs the default SrbFlags with SRB_FLAGS_DISABLE_DISCONNECT.

  • Tagged queuing

The port driver sets the TaggedQueuing Boolean that it maintains for the HBA to FALSE.

  • Internal queuing of requests on the HBA

The port driver sets the MultipleRequestPerLu Boolean that it maintains about the HBA to FALSE.

If any of the immediately preceding "disable" values are in the registry, it overrides whatever the HwFindAdapter routine sets in the PORT_CONFIGURATION_INFORMATION buffer. Note that temporarily disabling synchronous transfers, bus-disconnect operations, tagged queuing, and HBA internal request queuing can simplify using a debugger to trace request handling in a miniport driver that is under development.

Note also that the port driver uses the PORT_CONFIGURATION_INFORMATION values provided by a miniport's HwFindAdapter routine and/or in the registry to fill in the IO_SCSI_CAPABILITIES data for use by SCSI class drivers.


HwInitialize Routine

For each HBA found by the miniport driver, its HwInitialize routine is called to set up the HBA's registers and initial protocol state, if any.

If the HwInitialize routine enables interrupts on the HBA, the miniport's HwInterrupt routine will be called to handle any interrupts the device generates during the initialization.

If initializing the HBA causes a bus reset, the HwInitialize routine must call ScsiPortNotification with the NotificationType value ResetDetected.

When the HwInitialize routine returns control, ScsiPortInitialize sends SCSIOP_INQUIRY requests to the miniport driver, collecting the SCSI-II INQUIRYDATA about the devices on each bus and storing it for subsequent examination by SCSI class drivers. Each request to scan a SCSI bus for the INQUIRY data is sent to the miniport's HwStartIo routine, described in HwStartIo Routine.


HwStartIo Routine

As its name suggests, a HwStartIo routine is the entry point for incoming requests to peripheral devices on the HBA-driven bus(es). HwStartIo is called with pointers to an SRB and to the miniport's device extension for per-HBA state.

If the miniport's DriverEntry routine also requested that memory be allocated for logical unit extensions (see DriverEntry Routine), the HwStartIo routine calls ScsiPortGetLogicalUnit with the input device extension pointer and the PathId, TargetId, and Lun values from the input SRB.

If the DriverEntry routine requested that memory be allocated for SRB extensions, the SrbExtension field in each SRB contains a pointer to the miniport's per-request storage area. Note that a miniport driver must request that memory be allocated for SrbExtensions if it maintains per-request state information. It cannot use an SRB for this purpose. In particular, a miniport driver can write values into SRBs only for the following purposes and only in the following fields:

  • To return required status about each operation in the SrbStatus and ScsiStatus fields
  • If an underrun occurs, to update the DataTransferLength field
  • If it supports auto request sense and transfers request-sense information, to update the SenseInfoBufferLength

After the higher-level SCSI class drivers have loaded, most of the SRBs sent to the HwStartIo routine have the Function field set to SRB_FUNCTION_EXECUTE_SCSI. On receipt of such a request, the StartIo routine does the following:

  • Gets and/or sets up whatever context the miniport driver maintains in its device, logical unit, and/or SRB extensions

    For example, a miniport driver might set up a logical unit extension with pointers to the SRB itself and the SRB DataBuffer pointer, the SRB DataTransferLength value, and a driver-defined value (or CDB SCSIOP_xxx value) indicating the operation to be carried out on the HBA.

  • Calls an internal routine to program the HBA, as partially directed by the SRB Flags, for the requested operation

    For a device I/O operation, such an internal routine generally selects the target device and sends the CDB over the bus to the target logical unit.

If the miniport driver uses system DMA, it must call ScsiPortIoMapTransfer before programming the HBA to transfer data. ScsiPortIoMapTransfer sets up the system DMA controller and calls the miniport's HwDmaStarted routine, described in HwDmaStarted Routine, next.

A HwStartIo routine is also responsible for handling incoming SRBs with the Function field set to SRB_FUNCTION_ABORT_COMMAND. For an abort request, the miniport driver might need to verify that the given SRB has not been aborted already by calling ScsiPortGetSrb for the target logical unit and comparing the returned pointer to the current SRB's NextSrb value. If they are unequal, the current SRB has already been aborted, and the miniport driver should do the following:

  • Set the input SRB's SrbStatus to SRB_STATUS_ABORT_FAILED.
  • Call ScsiPortNotification with the NotificationType RequestComplete and with the input SRB.
  • Call ScsiPortNotification again with the NotificationType NextRequest, or with NextLuRequest if the HBA supports tagged queuing or multiple requests per logical unit.

Otherwise, the HwStartIo routine does the following:

  • Sets up context for the request in its device, logical unit, and/or SRB extensions
  • Programs the HBA to abort the given request

The port driver always sends its own reset-bus requests directly to the miniport's HwResetBus routine, described in HwResetBus Routine. However, it is possible for the HwStartIo routine to be called with an SRB in which the Function field is set to SRB_FUNCTION_RESET_BUS if a SCSI class driver requests this operation. The StartIo routine can simply call the HwResetBus routine to satisfy an incoming reset request.

If the HBA caches data internally, as indicated when the HwFindAdapter routine (see HwFindAdapter Routines) set up the PORT_CONFIGURATION_INFORMATION, the HwStartIo routine must support the SRB_FUNCTION_FLUSH and SRB_FUNCTION_SHUTDOWN requests. An SRB with its Function field set to SRB_FUNCTION_FLUSH tells the miniport driver to transfer data cached in the HBA, usually to a disk. The miniport should hold on to the flush request until all cached data has been transferred and, then, complete the flush request. (Such a flush request might originate when an application closes a file or the application itself is terminated.)

An SRB with its Function field set to SRB_FUNCTION_SHUTDOWN tells the miniport driver to complete transferring data, including flushing all cached data, out to the target device. The miniport driver should hold on to the shutdown request until no data remains in the HBA's internal cache for the target logical unit and, then, complete the shutdown request. Note that the miniport can be called with more than one shutdown request, possibly for the same LU or with several shutdown requests for different LUs, before the system itself is actually shut down.

Whether a miniport driver handles SRB_FUNCTION_IO_CONTROL requests depends on whether the HBA is to provide dedicated support for an application. Supporting this request allows a set of privately defined device I/O control requests to be sent directly to the miniport driver. For SRBs with the Function field set to SRB_FUNCTION_IO_CONTROL, the DataBuffer field contains a pointer to a system-defined SRB_IO_CONTROL structure containing the driver-defined and application-specified ControlCode. Note that system-defined device I/O control requests sent to SCSI class drivers are mapped to SRBs with the Function field set to SRB_FUNCTION_EXECUTE_SCSI.

Every HwStartIo routine must handle the receipt of an unsupported SRB_FUNCTION_xxx, as follows:

  1. Set the input SRB's SrbStatus to SRB_STATUS_INVALID_REQUEST.
  2. Call ScsiPortNotification with the NotificationType RequestComplete and with the input SRB.
  3. Call ScsiPortNotification again with the NotificationType NextRequest, or with NextLuRequest if the HBA supports tagged queuing or multiple requests per logical unit.

Every HwStartIo routine must return a Boolean value, indicating whether the input request was processed or should be resubmitted later (FALSE). However, the miniport eventually must call ScsiPortNotification twice for each SRB input to its StartIo routine: first, to complete the request (NotificationType RequestComplete) and, second, to tell the port driver to call the StartIo routine again with the next SRB (NotificationType NextRequest or NextLuRequest).

The HwStartIo routine of a miniport driver that manages its HBA exclusively by polling calls ScsiPortNotification with the NotificationType RequestTimerCall and a pointer to its HwTimer routine. For more information about the HwTimer routine, see HwTimer Routine.

The following SRB Function values are defined for use in future versions:

  • SRB_FUNCTION_RECEIVE_EVENT
  • SRB_FUNCTION_RELEASE_RECOVERY
  • SRB_FUNCTION_RESET_DEVICE
  • SRB_FUNCTION_TERMINATE_IO

The port driver processes requests with the following SRB Function values without calling the miniport driver:

  • SRB_FUNCTION_CLAIM_DEVICE
  • SRB_FUNCTION_RELEASE_QUEUE
  • SRB_FUNCTION_FLUSH_QUEUE
  • SRB_FUNCTION_ATTACH_DEVICE
  • SRB_FUNCTION_RELEASE_DEVICE

Miniport driver designers can assume that their miniports will never be sent an SRB with any of the immediately preceding Function values. The port driver handles these requests from SCSI class and filter drivers to protect these higher-level SCSI drivers from having to access any HBA-specific (or miniport-specific) state information in order to find their devices or cancel queued requests. This ensures that SCSI class and filter drivers have no dependencies on any particular model of HBA.

For more information about SRBs and the set of system-defined SRB_FUNCTION_xxx values, see the Introduction to SCSI Port Driver Services Reference.


HwDmaStarted Routine

A miniport driver whose HBA uses the system DMA controller must have a HwDmaStarted routine.

For a data transfer operation, such a miniport driver must call ScsiPortIoMapTransfer, passing in the pointers to its device extension for per-HBA data and the SRB requesting the transfer, along with a range of logical addresses for the buffer from which or into which the data will be transferred.

Note that the logical address range passed to ScsiPortIoMapTransfer either must be the mapped values for the input SRB's DataBuffer and DataTransferLength or a proper subset of this range. For most transfer requests, a miniport driver designer can assume that all data specified in the input SRB can be transferred in a single DMA operation. That is, the miniport driver might have to carry out more than one transfer operation to satisfy a given SRB only if the HBA provides application-dedicated support and the application sends large transfer requests directly to the miniport driver. Otherwise, it is the responsibility of SCSI class drivers to split up large transfer requests into a set of partial transfer requests, each sized to suit the capabilities of the HBA.

ScsiPortIoMapTransfer calls the miniport's HwDmaStarted routine when the system DMA controller is ready to transfer data between system memory and the HBA. HwDmaStarted must set up the HBA for the transfer operation.

When a transfer operation is complete, the miniport driver must call ScsiPortFlushDma before it calls ScsiPortNotification with the SRB and/or calls ScsiPortIoMapTransfer to set up the DMA controller again for a subrange in the buffer. ScsiPortFlushDma flushes any remaining data cached in the DMA controller. Note that ScsiPortFlushDma also can be called to cancel a system DMA transfer, even if the miniport's HwDmaStarted routine has not yet been called.

For more information about ScsiPortIoMapTransfer and ScsiPortFlushDma, see the Introduction to SCSI Port Driver Services Reference.


HwResetBus Routine

Every miniport driver must have a HwResetBus routine, which is called with a pointer to the miniport's device extension for HBA state and the PathId of the bus to be reset. If an attempted bus-reset operation fails (or times out), the miniport driver should call ScsiPortLogError and, then, program the HBA for a hard reset.

A bus-reset operation might require the miniport driver to clean up state it maintains in the device extension and/or logical unit extensions for devices on the bus. HwResetBus must complete any outstanding requests by calling ScsiPortCompleteRequest with the SrbStatus value SRB_STATUS_BUS_RESET or, for individual SRBs, ScsiPortNotification with this status.

After completing the bus-reset request and any outstanding requests, the miniport must call ScsiPortNotification (if it has not already done so) with the NotificationType NextRequest, or NextLuRequest if the HBA supports tagged queuing or multiple requests per logical unit.


HwInterrupt Routine

On entry, a HwInterrupt routine should determine if its HBA actually generated an interrupt. HwInterrupt must return FALSE as soon as possible if it detects a spurious interrupt so the interrupt service routine for the device that generated the interrupt can be called quickly.

Otherwise, a miniport's HwInterrupt routine is generally responsible for completing the I/O operation that caused the interrupt. Depending on the HBA and the design of the miniport, a HwInterrupt routine does some or all of the following:

  • Dismisses the interrupt on the HBA
  • Notifies (by calling ScsiPortNotification or ScsiPortCompleteRequest) the port driver if the HBA indicates that certain SCSI error conditions occurred during the operation and logging the error (see Error Handling)
  • Completing the requested operation that caused the interrupt, such as calling ScsiPortIoMapTransfer if the interrupt came in from a previously selected target TID and LU indicating a readiness to transfer data

When the HwInterrupt routine (or an internal miniport routine) completes an SRB, it calls ScsiPortNotification twice:

  1. First, with the NotificationType RequestComplete and the just satisfied request
  2. Next, with the NotificationType NextRequest, or with NextLuRequest if the HBA supports tagged queuing or multiple requests per logical unit

For better overall system performance, a miniport's HwInterrupt routine should do only the minimum necessary to process I/O requests. That is, the miniport should be designed to return control from the HwInterrupt routine as quickly as possible, rather than tying up a processor and preventing other drivers from servicing device interrupts.

If interrupt-driven I/O operations take a long time to complete, a miniport driver should have a pair of HwEnableInterruptsCallback and HwDisableInterruptsCallback routines. For example, if a miniport must poll for longer than 50 microseconds doing PIO, its HwInterrupt routine should not retain control of the CPU for the full polling interval in order to complete a requested operation. Instead, its HwInterrupt routine should do the following:

  1. Disable interrupts from the HBA.
  2. Set up the device extension with any context necessary to complete the operation.
  3. Call ScsiPortNotification with a pointer to the device extension, the NotificationType CallEnableInterrupts, and the miniport's HwEnableInterruptsCallback routine, described in HwEnableInterruptsCallback Routine.
  4. Return control.

ScsiPortNotification calls the HwEnableInterruptsCallback routine as an DPC.


HwEnableInterruptsCallback Routine

A HwEnableInterruptsCallback routine finishes processing a polled I/O operation without inhibiting I/O operations for other devices in the machine. When the HwEnableInterruptsCallback routine gets control, all system device interrupts are enabled except from the HBA. In other words, the miniport's HwInterrupt routine cannot be called and cannot disturb the context data it set up about the current operation while the HwEnableInterruptsCallback routine is running.

A HwEnableInterruptsCallback routine should do the following:

  1. Use the context that was set up for the operation in the input device extension to complete processing of the request that caused the interrupt.
  2. Call ScsiPortNotification with a pointer to the device extension, the NotificationType CallDisableInterrupts, and the miniport's HwDisableInterruptsCallback routine, described in HwDisableInterruptsCallback Routine.
  3. Return control.

ScsiPortNotification calls the HwDisableInterruptsCallback routine with a subset of the system device interrupts disabled: that is, no device interrupt with a system-assigned hardware priority (IRQL) less than or equal to the HBA's can interrupt.


HwDisableInterruptsCallback Routine

A HwDisableInterruptsCallback routine should do the following:

  1. Re-enable interrupts from the HBA.
  2. Return control.

Note that this routine must execute as quickly as possible to avoid tying up I/O operations for other devices in the machine. Consequently, a HwEnableInterruptsCallback must do no more than re-enable interrupts on the HBA before it returns control.


HwTimer Routine

A miniport driver that does not have a HwInterrupt routine because it manages all HBA I/O operations by polling should have a HwTimer routine. However, miniport drivers with HwInterrupt routines frequently have HwTimer routines as well.

While a miniport driver can call ScsiPortStallExecution to wait for a state change on the HBA, miniport drivers should never call this routine to wait for longer than one millisecond except, possibly, for an operation performed only when a miniport is initializing. ScsiPortStallExecution ties up the processor for the given interval, preventing other code in the system from doing useful work.

Instead of calling ScsiPortStallExecution with large input intervals and wasting many CPU cycles, a miniport driver should have a HwTimer routine. One or more HwTimer routines are particularly useful if the HBA does not generate a completion interrupt for every operation or if any commonly requested operation, such as a bus reset, takes longer than a millisecond.

After the HBA has been programmed for such an operation, the miniport driver calls ScsiPortNotification with the NotificationType RequestTimerCall, a pointer to the device extension containing context about the operation, its HwTimer routine, and a driver-determined interval.

HwTimer is called once for each such call to ScsiPortNotification, which can be called from the HwTimer routine itself. However, any call to ScsiPortNotification with the NotificationType RequestTimerCall overrides a preceding call for which the specified interval has not expired. That is, there is only one outstanding request to call a miniport's HwTimer routine at any given moment.

The interval passed in to ScsiPortNotification is in microseconds but the minimum resolution for each call is approximately ten milliseconds. An input interval of zero cancels the preceding request to call the HwTimer routine, provided it has not been called or dispatched for execution on another processor already. ScsiPortNotification calls the HwTimer routine either as a DPC or synchronized with the HwInterrupt routine so that it cannot execute concurrently while the HwTimer routine is running.


HwAdapterState Routine

SCSI miniport drivers should set this entry point to NULL in the HW_INITIALIZATION_DATA (see DriverEntry Routine). The HwAdapterState prototype is defined for compatibility with future versions of MS-DOS.


Error Handling

A SCSI miniport driver is responsible for handling and for notifying the port driver of the following kinds of SCSI errors, which should be set in the SrbStatus field before the driver completes the SRB it was processing when the error occurred:

  • SRB_STATUS_ERROR (if the HBA returns a nonspecific bus error)
  • SRB_STATUS_PARITY_ERROR
  • SRB_STATUS_UNEXPECTED_BUS_FREE
  • SRB_STATUS_SELECTION_TIMEOUT
  • SRB_STATUS_COMMAND_TIMEOUT
  • SRB_STATUS_MESSAGE_REJECTED
  • SRB_STATUS_NO_DEVICE
  • SRB_STATUS_NO_HBA
  • SRB_STATUS_DATA_OVERRUN (also returned for underruns)
  • SRB_STATUS_PHASE_SEQUENCE_FAILURE
  • SRB_STATUS_BUSY (TID busy)

For a data underrun, the miniport driver must update the SRB's DataTransferLength to indicate how much data actually was transferred.

Whenever the miniport driver encounters an HBA or bus error, it should call ScsiPortLogError with one of the following system-defined error codes:

  • SP_BUS_PARITY_ERROR
  • SP_UNEXPECTED_DISCONNECT (by the target LU)
  • SP_INVALID_RESELECTION
  • SP_BUS_TIME_OUT
  • SP_REQUEST_TIMEOUT
  • SP_PROTOCOL_ERROR
  • SP_INTERNAL_ADAPTER_ERROR
  • SP_IRQ_NOT_RESPONDING (if the miniport detects that the HBA is no longer generating interrupts)
  • SP_BAD_FW_ERROR ("FW" stands for "firmware")
  • SP_BAD_FW_WARNING

ScsiPortLogError allocates an error-log packet, sets it up, and logs the I/O error on behalf of the miniport driver to help users or system administrators monitor the condition of the HBA.


ASPI for Win32

The Advanced SCSI Programming Interface (ASPI) has become an industry standard SCSI software interface in the DOS, Windows®, OS/2, and Netware environments. ASPI allows developers to write device drivers and applications which are independent of the specific host adapter platform used to connect SCSI peripherals. With ASPI, there is a single driver managing the host bus adapter, eliminating conflicts when multiple applications try to access the SCSI bus at the same time.

With the arrival of Windows NT®/Windows® 2000 and Windows® 95, ASPI must be extended to allow applications to take full advantage of these new, 32-bit operating systems. This specification describes the Advanced SCSI Programming Interface (ASPI) for the Win32® environment.

Note: This specification defines the protocol between ASPI client applications and the ASPI Manager wnaspi32.dll. The specification does not describe the protocol between wnaspi32.dll and the target Win32 environment, since this implementation may vary between operating systems.


Definitions

ASPI: | Advanced SCSI Programming Interface.
SRB: | SCSI Request Block: Used by both drivers or application programs to send commands to the ASPI manager.
SCSI: | Small Computer Systems Interface.
DLL: | Dynamic Link Library.
ASPI Client: | An application or driver that uses ASPI to access SCSI devices.
ASPI Manager: | The service layer which processes ASPI requests.


Using ASPI for Win32 - An Overview

The ASPI manager for Win32 is implemented as a Dynamic Link Library (DLL) called wnaspi32.dll. ASPI function calls can be used to retrieve information about installed SCSI host adapters and devices, and to execute SCSI I/O requests. The ASPI for Win32 layer is fully re-entrant, supporting multitasking and multithreaded operations. To use ASPI for Win32, the following two functions must be imported from wnaspi32.dll into the client's Win32 application.

Function | Description
GetASPI32SupportInfo | This function returns the number of SCSI host adapters installed and ensures that the ASPI manager is initialized properly. Clients must call this function once at initialization time before the SendASPI32Command function can be accessed.
SendASPI32Command | This function handles requests for SCSI I/O.

The following SCSI I/O command codes are defined within the SendASPI32Command:

Value | Meaning
SC_HA_INQUIRY | Get information about installed host adapters, including the number of installed adapters.
SC_GET_DEV_TYPE | Get information about installed SCSI devices.
SC_EXEC_SCSI_CMD | Execute SCSI I/O.
SC_ABORT_SRB | Abort an outstanding I/O request.
SC_RESET_DEV | Reset an individual SCSI target.
SC_GET_DISK_INFO | Get information on disk type SCSI devices. (Not used with Windows NT/2000)


GetASPI32SupportInfo Function

Prototype: DWORD GetASPI32SupportInfo(VOID)

The GetASPI32SupportInfo function returns the number of host adapters installed and ensures that the ASPI manager is initialized properly. This function must be called once at initialization time, before SendASPI32Command is accessed. The number of host adapters returned represents the logical bus count, not the true physical adapter count. For host adapters with a single bus, the host adapter count and logical bus count are identical.

This function has no parameters.

The DWORD return value specifies the result of the ASPI request. The DWORD is encoded as follows:

Table 4-1. Return Values from GetASPI32SupportInfo Function

Length | Bit
 | Meaning
WORD | 31-16
 | Reserved = zero
BYTE | 15-8
 | Status

SS_COMP | ASPI request completed without error
SS_FAILED_INIT | ASPI manager unable to initialize; ASPI services not available

BYTE | 7-0
 | If Status = SS_COMP
 | Number of host adapters

Example

This example returns the current status of ASPI for Win32.

 DWORD ASPIStatus;
 BYTE NumAdapters;
 HWND hwnd;
    .
    .
 ASPIStatus = GetASPI32SupportInfo();
 switch ( HIBYTE(LOWORD(ASPIStatus)) )
  {
  case SS_COMP:
   /*
    * ASPI for Win32 is properly initialized
    */
   NumAdapters = LOBYTE(LOWORD(ASPIStatus));
   break;
  default:
   MessageBox( hwnd,
      "ASPI for Win32 is not initialized!!",
      NULL,
      MB_ICONSTOP );
   return FALSE;
  }
   .
   .


SendASPI32Command Function

Prototype: DWORD SendASPI32Command(LPSRB)

Declaration: LPSRB lpSRB;

The SendASPI32Command function handles all SCSI I/O requests. A command code is used to specify the type of I/O requested. SendASPI32Command is called with a pointer to a SCSI Request Block (SRB) structure. While SRB definition can vary depending on the ASPI command code, all SRBs include a standard SRB header:

typedef struct {

 BYTE  SRB_Cmd;      // ASPI command code
 BYTE  SRB_Status;   // ASPI command status byte
 BYTE  SRB_HaId;     // ASPI host adapter number
 BYTE  SRB_Flags;    // ASPI request flags
 DWORD SRB_Hdr_Rsvd; // Reserved, MUST = zero

} SRB_Header;

The SRB_Cmd field must contain the command code for the desired SCSI I/O operation. Each of these commands is described in the following sections. Possible values for SRB_Cmd include the following:

SC_HA_INQUIRY
SC_GET_DEV_TYPE
SC_EXEC_SCSI_CMD
SC_ABORT_SRB
SC_RESET_DEV
SC_GET_DISK_INFO

The SC_GET_DISK_INFO command is not used with Windows NT/Windows 2000.


Win32 ASPI Commands

Note In the following sections, fields marked with [OUT] are returned by the ASPI manager. Fields marked with [IN] are set by the ASPI client before they are sent to the ASPI manager. Fields marked as Reserved must be zeroed before the SRB is sent to the ASPI manager.


Host Adapter Inquiry Command

Prototype: DWORD SendASPI32Command(LPSRB)

Declaration: LPSRB lpSRB;

The SendASPI32Command function with command code SC_HA_INQUIRY is used to get information on the installed host adapter hardware, including the number of host adapters installed. The number of host adapters returned represents the logical bus count instead of the true physical adapter count. For host adapters that support single bus only, the host adapter count and logical bus count are identical. For host adapters that support multiple buses, the host adapter count represents the total logical bus count.

Parameter | Description
lpSRB | Points to the following SCSI request block

typedef struct {

 BYTE  SRB_Cmd;            // ASPI command code = SC_HA_INQUIRY
 BYTE  SRB_Status;         // ASPI command status byte
 BYTE  SRB_HaId;           // ASPI host adapter number
 BYTE  SRB_Flags;          // ASPI request flags
 DWORD SRB_Hdr_Rsvd;       // Reserved, MUST = zero
 BYTE  HA_Count;           // Number of host adapters present
 BYTE  HA_SCSI_ID;         // SCSI ID of host adapter
 BYTE  HA_ManagerId[16];   // String describing the manager
 BYTE  HA_Identifier[16];  // String describing the host adapter
 BYTE  HA_Unique[16];      // Host Adapter Unique parameters
 WORD  HA_Rsvd1;           // Reserved

} SRB_HAInquiry, *PSRB_HAInquiry;

Member | Description
SRB_Cmd | [IN] This field must contain SC_HA_INQUIRY.
SRB_Status | [OUT] On return, this field is the same as the return status defined in the following.
SRB_HaId | [IN] This field specifies which installed host adapter the request is intended for. Host adapter numbers are always assigned by the SCSI manager layer, beginning with zero.
SRB_Flags | [IN] Reserved = zero
SRB_Hdr_Rsvd | Reserved = zero
HA_Count | [OUT] The ASPI manager sets this field with the number of host adapters installed under ASPI. For example, a return value of 2 indicates that host adapters #0 and #1 are valid. To determine the total number of host adapters in the system, the SRB_HaId field should be set to zero, or GetASPI32SupportInfo can be used. The number of host adapters returned represents the logical bus count instead of the true physical adapter count. For host adapters that support single bus only, the host adapter count and logical bus count are identical.
HA_SCSI_ID | [OUT] The ASPI manager sets this field with the SCSI ID of the given host adapter.
HA_ManagerId[..] | [OUT] The ASPI manager fills this 16-character buffer with an ASCII string describing the ASPI manager. For ASPI for WIN32, the string "ASPI for WIN32" is returned.
HA_Identifier[..] | [OUT] The ASPI manager fills this 16-character buffer with a string describing the host adapter.
HA_Unique[..] | [OUT] The ASPI manager fills this 16-byte buffer with host adapter unique parameters. The returned buffer is encoded as follows:

Byte 15-8 | Reserved = zero
Byte 7-4 | Maximum Transfer Length.
Byte 3 | Maximum SCSI Targets. Indicates the maximum number of targets (SCSI IDs) the adapter supports. If this value is not set, it is assumed that there are 8 targets. (SCSI IDs zero thorugh 7).
Byte 2 | Adapter Unique Flags: Bits 7 through 2 and Bit 0 are reserved. If Bit 1 is 1, residual byte count reporting is supported; if Bit 1 is zero, residual byte count reporting is not supported.
Byte 1-0 | Buffer Alignment Mask. The host adapter requires data buffer alignment specified by the 16-bit value. A value of 0x0000 indicates no boundary requirements (byte alignment), 0x0001 word alignment, 0x0003 double-word, 0x0007 8-byte alignment, etc. The 16-bit value allows data buffer alignments of up to 65536-byte boundaries. Byte 1 is the most significant byte.

Value | Meaning
SS_COMP | SCSI/ASPI request has completed without error.
SS_INVALID_HA | Invalid host adapter number.

Residual Byte Length

Residual byte length is the number of bytes not transferred to, or received from, the target SCSI device. For example, if the ASPI buffer length for a SCSI Inquiry command is set for 100 bytes, but the target only returns 36 bytes; the residual length is 64 bytes. If the ASPI buffer length for a SCSI Write command is set for 514 bytes but the target only takes 512 bytes, the residual length is 2 bytes. ASPI modules can determine if the loaded ASPI manager supports residual byte length by issuing an Extended Host Adapter Inquiry command, as described in the previous section.

Example

This example of the Host Adapter Inquiry command gets host adapter hardware information from adapter #0.

 SRB_HAInquiry MySRB;
 DWORD ASPIStatus;
  .
  .
 MySRB.SRB_Cmd     = SC_HA_INQUIRY;
 MySRB.SRB_HaId    = 0;
 MySRB.SRB_Flags    = 0;
 MySRB.SRB_Hdr_Rsvd   = 0;
 ASPIStatus     = SendASPI32Command ( (LPSRB) &MySRB );
  .
  .


Get Device Type Command

Prototype: DWORD SendASPI32Command(LPSRB)

Declaration: LPSRB lpSRB;

The SendASPI32Command function with command code SC_GET_DEV_TYPE enables you to identify the devices available on the SCSI bus. A Win32 tape backup package, for example, can scan each target/LUN on each installed host adapter looking for a device type corresponding to sequential access devices. This eliminates the need for each Win32 application to duplicate the effort of scanning the SCSI bus for devices.

Parameter | Description
lpSRB | Points to the following SCSI request block

typedef struct {

 BYTE  SRB_Cmd;    // ASPI command code = SC_GET_DEV_TYPE
 BYTE  SRB_Status;   // ASPI command status byte
 BYTE  SRB_HaId;    // ASPI host adapter number
 BYTE  SRB_Flags;   // Reserved
 DWORD  SRB_Hdr_Rsvd;  // Reserved
 BYTE  SRB_Target;   // Target's SCSI ID
 BYTE  SRB_Lun;    // Target's LUN number
 BYTE  SRB_DeviceType;  // Target's peripheral device type
 BYTE  SRB_Rsvd1;   // Reserved for alignment

} SRB_GDEVBlock, *PSRB_GDEVBlock;

Table 4-4. Get Device Type Command

Member | Description
SRB_Cmd | [IN] This field must contain SC_GET_DEV_TYPE.
SRB_Status | [OUT] On return, this field will be the same as the return status defined in the following.
SRB_HaId | [IN] This field specifies which installed host adapter the request is intended for. Host adapter numbers are always assigned by the ASPI manager layer beginning with zero.
SRB_Flags | [IN] Reserved = zero
SRB_Hdr_Rsvd | Reserved = zero
SRB_Target | [IN] SCSI ID of target device.
SRB_Lun | [IN] Logical Unit Number (LUN) of device.
SRB_DeviceType | [OUT] The ASPI manager fills this field with the peripheral device type. This is derived from the Peripheral Device Type returned by the SCSI Inquiry command. Refer to the SCSI specification to learn more about the SCSI Inquiry command.

Table 4-5. Return Values from Get Device Type Command

Value | Meaning
SS_COMP | SCSI/ASPI request has completed without error.
SS_INVALID_HA | Invalid host adapter number.
SS_NO_DEVICE | SCSI device not installed.

Example

This example gets the peripheral device type from host adapter #0, target ID #4, and LUN #0.

 SRB_GDEVBlock MySRB;
 DWORD ASPIStatus;
   .
   .
 MySRB.SRB_Cmd    = SC_GET_DEV_TYPE;
 MySRB.SRB_HaId   = 0;
 MySRB.SRB_Flags   = 0;
 MySRB.SRB_Hdr_Rsvd  = 0;
 MySRB.SRB_Target   = 4;
 MySRB.SRB_Lun   = 0;
 ASPIStatus    = SendASPI32Command ( (LPSRB) &MySRB );
   .
 /****************************************************************/
 /* If MySRB.SRB_Status == SS_COMP, MySRB.SRB_DeviceType
 /* will contain the peripheral device type.
 /****************************************************************/
   .
   .


Execute SCSI I/O Command

Prototype: DWORD SendASPI32Command(lpSRB)

Declaration: LPSRB lpSRB;

The SendASPI32Command function with command code SC_EXEC_SCSI_CMD is used to execute a SCSI I/O command. Once an ASPI client has initialized, virtually all I/O is performed with this command.

Parameter | Description
lpSRB | Points to the following SCSI request block

typedef struct {

 BYTE  SRB_Cmd;      // ASPI command code = SC_EXEC_SCSI_CMD
 BYTE  SRB_Status;     // ASPI command status byte
 BYTE  SRB_HaId;      // ASPI host adapter number
 BYTE  SRB_Flags;     // ASPI request flags
 DWORD  SRB_Hdr_Rsvd;    // Reserved
 BYTE  SRB_Target;     // Target's SCSI ID
 BYTE  SRB_Lun;      // Target's LUN number
 WORD  SRB_Rsvd1;     // Reserved for Alignment
 DWORD  SRB_BufLen;     // Data Allocation Length
 BYTE  *SRB_BufPointer;    // Data Buffer Point
 BYTE  SRB_SenseLen;    // Sense Allocation Length
 BYTE  SRB_CDBLen;     // CDB Length
 BYTE  SRB_HaStat;     // Host Adapter Status
 BYTE  SRB_TargStat;    // Target Status
 void  (*SRB_PostProc)();   // Post routine
 void  *SRB_Rsvd2;     // Reserved
 BYTE  SRB_Rsvd3[16];    // Reserved for expansion
 BYTE  CDBByte[16];     // SCSI CDB
 BYTE  SenseArea[SENSE_LEN+2]; // Request Sense buffer

} SRB_ExecSCSICmd, *PSRB_ExecSCSICmd;

Table 4-6. Execute SCSI I/O Command

Member | Description
SRB_Cmd | [IN] This field must contain SC_EXEC_SCSI_CMD.
SRB_Status | [OUT]This field returns one of the following statuses:

SS_PENDING | SCSI request is in progress.
SS_COMP | SCSI/ASPI request has completed without error.
SS_ABORTED | SCSI command has been aborted.
SS_ABORT_FAIL | SCSI command abort failed.
SS_ERR | SCSI command completed with an error.
SS_INVALID_SRB | One or more parameters in the SCSI Request Block (SRB) are set incorrectly.
SS_INVALID_PATH_ID | SCSI ID and LUN are invalid.
SS_BUFFER_TO_BIG | The ASPI manager cannot handle the given transfer size.
SS_BUFFER_ALIGN | The ASPI manager cannot handle the alignment on this buffer. You must force the buffer into the alignment specified by the alignment mask returned as part of the SC_HA_INQUIRY command.
SS_SECURITY_VIOLATION | The application does not have the security privileges needed to perform the operation for the device.

SRB_HaId | [IN] This field specifies which installed host adapter the request is intended for. Host adapter numbers are always assigned by the SCSI manager layer beginning with zero.
SRB_Flags | [IN] The SRB flags field is defined as follows:

SRB_DIR_IN | Data transfer from SCSI target to host. Mutually exclusive with SRB_DIR_OUT.
SRB_DIR_OUT | Transfer from host to SCSI target. Mutually exclusive with SRB_DIR_IN.
SRB_EVENT_NOTIFY | Enable ASPI command event notification. This flag and the SRB_POSTING flag are mutually exclusive.
SRB_POSTING | Enable ASPI command completion posting. This flag and the SRB_EVENT_NOTIFY flag are mutually exclusive.
SRB_ENABLE_RESIDUAL COUNT | Enables reporting of residual byte count. This bit is only significant if the host adapter reports support for residual byte count from the SC_HA_INQUIRY command. Whenever a data underrun occurs, the SRB_BufLen field is updated to reflect the remaining bytes to transfer.

SRB_Hdr_Rsvd | Reserved = zero
SRB_Target | [IN] SCSI ID of target device.
SRB_Lun | [IN] Logical Unit Number (LUN) of device.
SRB_BufLen | [IN] This field indicates the number of bytes to be transferred. If the SCSI command to be executed does not transfer data (for example, Test Unit Ready, Rewind, etc.), this field must be set to zero. If residual byte length is supported and selected, this field is returned with the residual number of bytes (usually zero).
SRB_BufPointer | [IN] This field is a pointer to the data buffer.
SRB_SenseLen | [IN] This field indicates the number of bytes allocated at the end of the SRB for sense data. A request sense is automatically generated if a check condition is presented at the end of a SCSI command.
SRB_CDBLen | [IN] This field establishes the length, in bytes, of the SCSI Command Descriptor Block (CDB). This value is typically 6 or 10.
SRB_HaStat | [OUT] Upon completion of the SCSI command, the ASPI manager sets this field with the host adapter status as follows:

HASTAT_OK | Host adapter did not detect an error.
HASTAT_TIMEOUT | The time allocated for the transaction ran out.
HASTAT_COMMAND_TIMEOUT | SRB expired while waiting to be processed.
HASTAT_SEL_TO | Selection of target timed out.
HASTAT_MESSAGE_REJECT | While processing SRB, the adapter received a MESSAGE REJECT.
HASTAT_BUS_RESET | A bus reset was detected.
HASTAT_PARITY_ERROR | A parity error was detected.
HASTAT_REQUEST_SENSE_FAILED | The adapter failed in issuing a Request Sense after a check condition was reported by the target device.
HASTAT_DO_DU | Data overrun/underrun.
HASTAT_BUS_FREE | Unexpected Bus Free.
HASTAT_PHASE_ERR | Target Bus phase sequence failure.

SRB_TargStat [OUT] Upon completion of the SCSI command, the ASPI manager will record the specific status returned by the SCSI target:

STATUS_GOOD | No target status.
STATUS_CHKCOND | Check status (sense data is in SenseArea).
STATUS_BUSY | Specified Target/LUN is busy.
STATUS_RESCONF | Reservation conflict.

SRB_PostProc | [IN] If posting is enabled (SRB_POSTING flag), this field contains a pointer to a function. ASPI for Win32 calls this function upon completion of an ASPI request. If event notification is enabled (SRB_EVENT_NOTIFY flag), this field contains a handle to an event. ASPI for Win32 signals this event upon completion of an ASPI request.
CDBByte[..] | [IN] This field contains the CDB as defined by the target's SCSI command set. The length of the SCSI CDB is specified in the SRB_CDBLen field.
SenseArea[..] | [OUT] The SenseArea is filled with the sense data on a check condition. The maximum length of this field is specified in the SRB_SenseLen field. Note that the target can return fewer than the number of sense bytes requested.

Table 4-7. Return Values from Execute SCSI I/O Command

Value | Meaning
SS_PENDING | SCSI request is in progress.

Example

This example sends a SCSI Inquiry command to host adapter #0, target #0, LUN #0.

 SRB_ExecSCSICmd MySRB;
 DWORD ASPIStatus;
 char InquiryBuffer[32];
  .
  .
  .
 MySRB.SRB_Header    = SC_EXEC_SCSI_CMD;
 MySRB.SRB_HaId    = 0;
 MySRB.SRB_Flags    = SRB_DIR_IN | SRB_POSTING;
 MySRB.SRB_Hdr_Rsvd   = 0;
 MySRB.SRB_Target    = 0;
 MySRB.SRB_Lun    = 0;
 MySRB.SRB_BufLen    = 32;
 MySRB.SRB_SenseLen   = SENSE_LEN;
 MySRB.SRB_BufPointer  = InquiryBuffer;
 MySRB.SRB_CDBLen    = 6;
 MySRB.RB_PostProc   = PostProcedure;
 MySRB.CDBByte[0]    = SCSI_INQUIRY;
 MySRB.CDBByte[1]    = 0;
 MySRB.CDBByte[2]    = 0;
 MySRB.CDBByte[3]    = 0;
 MySRB.CDBByte[4]    = 32;
 MySRB.CDBByte[5]    = 0;
  .
 /***************************************************/
 /* Make sure all other reserved fields are zeroed
 /* before passing the SRB to ASPI for Win32
 /***************************************************/
  .
 ASPIStatus = SendASPI32Command ( (LPSRB) &MySRB );
  .
  .


Abort SCSI I/O Command

Prototype: DWORD SendASPI32Command(LPSRB)

Declaration: LPSRB lpSRB;

The SendASPI32Command function with command code SC_ABORT_SRB is used to request that a pending SRB be aborted. It should be issued on any I/O request that has not completed if the application wishes to time-out on that request. Success of the abort command is never assured.

Parameter | Description
lpSRB | Points to the following SCSI request block

typedef struct {

 BYTE  SRB_Cmd;    // ASPI command code = SC_ABORT_SRB
 BYTE  SRB_Status;   // ASPI command status byte
 BYTE  SRB_HaId;    // ASPI host adapter number
 BYTE  SRB_Flags;   // Reserved
 DWORD  SRB_Hdr_Rsvd;  // Reserved
 void  *SRB_ToAbort;  // Pointer to SRB to abort

} SRB_Abort, *PSRB_Abort;

Table 4-8. Abort SCSI I/O Command

Member | Description
SRB_Cmd | [IN] This field must contain SC_ABORT_SRB.
SRB_Status | [OUT] On return, this field will be the same as the return status defined in the following.
SRB_HaId | [IN] This field specifies which installed host adapter the request is intended for. Host adapter numbers are always assigned by the ASPI manager layer beginning with zero.
SRB_Flags | [IN] Reserved = zero
SRB_Hdr_Rsvd | Reserved = zero
SRB_ToAbort | [IN] This fields contains a pointer to the SRB which is to be aborted. The actual failure or success of the abort operation is indicated by the status eventually returned in this SRB.

Table 4-9. Return Values from Abort SCSI I/O Command

Value | Meaning
SS_COMP | SCSI/ASPI request has completed without error.
SS_INVALID_HA | Invalid host adapter number.
SS_INVALID_SRB | One or more parameters in the SCSI Request Block (SRB) are set incorrectly.

Example

This example shows how to abort a "stuck" SCSI I/O.

 SRB_ExecSCSICmd StuckSRB;
 SRB_Abort AbortSRB;
 DWORD ASPIStatus;
  .
  .
 AbortSRB.SRB_Cmd    = SC_ABORT_SRB;
 AbortSRB.SRB_HaId   = 0;
 AbortSRB.SRB_Flags   = 0;
 AbortSRB.SRB_Hdr_Rsvd  = 0;
 AbortSRB.SRB_ToAbort  = (LPSRB) &StuckSRB;
 ASPIStatus      = SendASPI32Command ( (LPSRB) &AbortSRB );
  .
  .


Reset SCSI Device Command

Prototype: DWORD SendASPI32Command(LPSRB)

Declaration: LPSRB lpSRB;

The SendASPI32Command function with command code SC_RESET_DEV is used to send a SCSI Bus Device reset to the specified target.

Parameter | Description
lpSRB | Points to the following SCSI request block

typedef struct {

 BYTE  SRB_Cmd;        // ASPI command code = SC_RESET_DEV
 BYTE  SRB_Status;     // ASPI command status byte
 BYTE  SRB_HaId;       // ASPI host adapter number
 BYTE  SRB_Flags;      // Reserved
 DWORD  SRB_Hdr_Rsvd;  // Reserved
 BYTE  SRB_Target;     // Target's SCSI ID
 BYTE  SRB_Lun;        // Target's LUN number
 BYTE  SRB_Rsvd1[12];  // Reserved for Alignment
 BYTE  SRB_HaStat;     // Host Adapter Status
 BYTE  SRB_TargStat;   // Target Status
 void  *SRB_PostProc;  // Post routine
 void  *SRB_Rsvd2;     // Reserved
 BYTE  SRB_Rsvd3[32];  // Reserved

} SRB_BusDeviceReset, *PSRB_BusDeviceReset;

Table 4-10. Reset SCSI Device Command

Member | Description
SRB_Cmd | [IN] This field must contain SC_RESET_DEV.
SRB_Status | [OUT] This field returns one of the following status:

SS_PENDING | SCSI request is in progress.
SS_COMP | SCSI/ASPI request has completed without error.
SS_ABORTED | SCSI command has been aborted.
SS_ABORT_FAIL | SCSI command abort failed.
SS_ERR | SCSI command completed with an error.
SS_INVALID_SRB | One or more parameters in the SCSI Request Block (SRB) are set incorrectly.
SS_INVALID_PATH_ID | SCSI ID and LUN are invalid.

SRB_HaId | [IN] This field specifies which installed host adapter the request is intended for. Host adapter numbers are always assigned by the SCSI manager layer beginning with zero.
SRB_Flags | [IN] Reserved = zero
SRB_Hdr_Rsvd | Reserved = zero
SRB_Target | [IN] SCSI ID of target device.
SRB_Lun | [IN] Logical Unit Number (LUN) of device. This field is ignored by ASPI for Win32, since SCSI Bus Device resets are done on a per-target basis only.
SRB_HaStat | [OUT] Upon completion of the SCSI command, the ASPI manager sets this field with the host adapter status to one of the following values:

HASTAT_OK | Host adapter did not detect an error.
HASTAT_TIMEOUT | The time allocated for the operation expired.
HASTAT_COMMAND_TIMEOUT | SRB expired while waiting to be processed.
HASTAT_SEL_TO | Selection of target timed out.
HASTAT_MESSAGE_REJECT | While processing SRB, the adapter received a MESSAGE REJECT.
HASTAT_BUS_RESET | A bus reset was detected.
HASTAT_PARITY_ERROR | A parity error was detected.
HASTAT_REQUEST_SENSE_FAILED | The adapter failed in issuing a request sense after a check condition was reported by the target device.
HASTAT_DO_DU | Data overrun/underrun.
HASTAT_BUS_FREE | Unexpected Bus Free.
HASTAT_PHASE_ERR | Target Bus phase sequence failure.

SRB_TargStat [OUT] Upon completion of the SCSI command, the ASPI manager sets this field with the target status as follows:

STATUS_GOOD | No target status.
STATUS_CHKCOND | Check status (sense data is in SenseArea).
STATUS_BUSY | Specified Target/LUN is busy.
STATUS_RESCONF | Reservation conflict.

SRB_PostProc [IN] If posting is enabled, ASPI for Win32 will post completion of an ASPI request to this function pointer.

Table 4-11. Return Values from Reset SCSI Device Command

Value | Meaning
SS_PENDING | SCSI request is in progress.

Example

This example issues a SCSI bus device reset to host adapter #0, target #5.

SRB_BusDeviceReset MySRB;
 DWORD ASPIStatus;
  .
  .
 MySRB.SRB_Header   = SC_RESET_DEV;
 MySRB.SRB_HaId   = 0;
 MySRB.SRB_Flags   = 0;
 MySRB.SRB_Hdr_Rsvd  = 0;
 MySRB.SRB_Target   = 5;
 MySRB.SRB_Lun   = 0;
 ASPIStatus     = SendASPI32Command ( (LPSRB) &MySRB );
  .
  .


Get SCSI Disk Information Command

Prototype: DWORD SendASPI32Command(LPSRB)

Declaration: LPSRB lpSRB;

The SendASPI32Command function with command code SC_GET_DISK_INFO is used to obtain information about a disk type SCSI device. The information returned includes BIOSint13h control and accessibility of the device, the drive's INT 13h physical drive number, and the geometry used by the INT 13h services for the drive.

Note: This command is not valid for Windows NT/Windows 2000, which does not use the INT 13 interface.

Parameter | Description
lpSRB | Points to the following SCSI request block

typedef struct {
 BYTE  SRB_Cmd;     // ASPI command code = SC_EXEC_SCSI_CMD
 BYTE  SRB_Status;    // ASPI command status byte
 BYTE  SRB_HaId;     // ASPI host adapter number
 BYTE  SRB_Flags;    // Reserved
 DWORD  SRB_Hdr_Rsvd;   // Reserved
 BYTE  SRB_Target;    // Target's SCSI ID
 BYTE  SRB_Lun;     // Target's LUN number
 BYTE  SRB_DriveFlags;   // Driver flags
 BYTE  SRB_Int13HDriveInfo; // Host Adapter Status
 BYTE  SRB_Heads;    // Preferred number of heads translation
 BYTE  SRB_Sectors;    // Preferred number of sectors translation
 BYTE  SRB_Rsvd1[10];   // Reserved

} SRB_GetDiskInfo, *PSRB_GetDiskInfo;

Table 4-12. Get SCSI Disk Information Command

Member | Description
SRB_Cmd | [IN] This field must contain SC_GET_DISK_INFO.
SRB_Status | [OUT] On return, this field will be the same as the return status defined in the following.
SRB_HaId | [IN] This field specifies which installed host adapter the request is intended for. Host adapter numbers are always assigned by the ASPI manager layer beginning with zero.
SRB_Flags | [IN] Reserved = zero
SRB_Hdr_Rsvd | Reserved = zero
SRB_Target | [IN] SCSI ID of target device.
SRB_Lun | [IN] Logical Unit Number (LUN) of device. This field is ignored by ASPI for Win32, since SCSI Bus Device resets are done on a per-target basis only.
SRB_DriveFlags | [OUT] Upon completion of the SCSI command, the ASPI manager sets this field as follows:

Bit 7-2 | Reserved
Bit 1-0 | These bits are encoded to reflect INT 13h control and accessibility to the device. Bit 1 is the most significant bit. DISK_NOT_INT13 Device is not controlled by INT 13h services DISK_INT13_AND_DOS Device is under INT 13h control and is claimed by DOS DISK_INT1 Device is under INT 13h control but not claimed by DOS

SRB_Int13DriveInfo | [OUT] Upon completion of the SCSI command, the ASPI manager sets this field with the physical drive number that INT 13h services assigned to the device. The valid drive numbers are 0x00 to 0xFF. This field is only valid if bits 1-0 of the SRB_DriveFlags were set to DISK_INT13_AND_DOS or DISK_INT13.
SRB_Heads | [OUT] Upon completion of the SCSI command, the ASPI manager sets this field to the number of heads the Int13h services is using for this device's geometry. The valid drive numbers are 0x00 to 0xFF. This field is only valid if bits 1-0 of the SRB_DriveFlags were set to DISK_INT13_AND_DOS or DISK_INT13.
SRB_Sectors | [OUT] Upon completion of the SCSI command, the ASPI manager sets this field to the number of sectors the INT 13h services is using for this device's geometry. The valid drive numbers are 0x00 to 0xFF. This field is only valid if bits 1-0 of the SRB_DriveFlags were set to DISK_INT13_AND_DOS or DISK_INT13.

Table 4-13. Return Values from Get SCSI Disk Information Command

Value | Meaning
SS_COMP | SCSI/ASPI request has completed without error.
SS_INVALID_HA | Invalid host adapter number.
SS_INVALID_SRB | One or more parameters in the SCSI Request Block (SRB) are set incorrectly.

Example

This example obtains disk information from device LUN 0, SCSI ID 2, attached to host adapter #0.

 SRB_GetDiskInfo MySRB;
 DWORD ASPIStatus;
  .
  .
 MySRB.SRB_Header.SRB_Cmd = SC_GET_DISK_INFO;
 MySRB.SRB_HaId    = 0;
 MySRB.SRB_Flags    = 0;
 MySRB.SRB_Hdr_Rsvd   = 0;
 MySRB.SRB_Target    = 2;
 MySRB.SRB_Lun    = 0;
 ASPIStatus     = SendASPI32Command ( (LPSRB) &MySRB );
  .
  .


Request Completion/Notification

Once an ASPI for Win32 SCSI request has been sent to the ASPI manager, there are three ways of being notified that the SCSI request has completed. The first and recommended method uses event notification. The second method uses callback (also referred to as posting). The third method uses polling.


Using Event Notification

Event notification is an ideal mechanism for notifying ASPI clients of the completion of an ASPI request. ASPI clients may block on this event until completion. Upon completion of a request, the ASPI for Win32 manager sets the event to the signaled state. The ASPI client must make sure that the event is not in a signaled state when an ASPI command request is submitted to the ASPI for Win32 manager. Event notification is illustrated in the following code, which sends a SCSI Inquiry command to target #2.

SRB_ExecSCSICmd MySRB;
HANDLE ASPICompletionEvent;
DWORD ASPIEventStatus;
DWORD ASPIStatus;
char InquiryBuffer[32];
.
/**************************************************/
/* Create event for MySRB.  Initial state         */
/* non-signaled, manual reset.                    */
/**************************************************/
if ((ASPICompletionEvent = CreateEvent(NULL,FALSE,FALSE,NULL)) == NULL)
   return FALSE;
/**************************************************/
/* Code is entered with 'MySRB' zeroed.           */
/**************************************************/
MySRB.SRB_Cmd     = SC_EXEC_SCSI_CMD;
MySRB.SRB_Flags     = SRB_DIR_SCSI|SRB_EVENT_NOTIFY;
MySRB.SRB_Target     = 2;
MySRB.SRB_BufLen     = 32;
MySRB.SRB_SenseLen    = SENSE_LEN;
MySRB.SRB_BufPointer   = InquiryBuffer;
MySRB.SRB_CDBLen     = 6;
MySRB.CDBByte[0]     = SCSI_INQUIRY;
MySRB.CDBByte[4]     = 32;
MySRB.SRB_PostProc    = ASPICompletionEvent;
.
.
ASPIStatus      = SendASPI32Command ( (LPSRB) &MySRB );
/**************************************************/
/* Block on event till signaled                   */
/**************************************************/
if ( MySRB.SRB_Status == SS_PENDING )
   ASPIEventStatus == WaitForSingleObject(ASPICompletionEvent, TIMEOUT);

/**************************************************/
/* Reset event to non-signaled state.             */
/**************************************************/
if (ASPIEventStatus == WAIT_OBJECT_0)
  ResetEvent(ASPICompletionEvent);
          .
          .


Using Callback

Callback (or posting) may also be used to receive notification that a SCSI request has completed. When callback is used, ASPI for Win32 posts completion by passing control to your callback function. For example, the following code segment sends a SCSI Inquiry command to target #2 during the WM_CREATE message.

LRESULT CALLBACK WndProc (HWND, UINT, UPARAM, LPARAM);
void APIENTRY ASPIPostProc (PSRB_ExecSCSICmd );

HWND  PostHWND;
HANDLE  hInstance;
     .
     .
     .
//****************************************************************************
//
// Function:  ASPIPostProc
//
// Description: If POSTING is enabled,  this function is called by ASPI
//     for Windows when the SCSI request has completed.  This
//     sample function simply posts a message to our Window
//     handle to indicate that the SCSI request has completed.
//
// DoneSRB  This parameter points to the ASPI SCSI Request Block (SRB)
//     which has completed.
//
// Returns    Nothing
//
//****************************************************************************
#ifdef WIN32
 void ASPIPostProc(PSRB_ExecSCSICmd DoneSRB)
 {
  PostMessage(PostHWND,WM_ASPIPOST,0,(LPARAM)DoneSRB);
  return;
 }
#else
 void _loadds __far __pascal ASPIPostProc(LPSRB DoneSRB)
 {
  PostMessage(PostHWND,WM_ASPIPOST,
     (WORD)((SRB_ExecSCSICmd6 far *)DoneSRB)->SRB_Status,
     (DWORD)DoneSRB);
  return;
 }
#endif

// **************************************************************************
// *
// * Procedure:  WndProc()
// *
// **************************************************************************
#ifdef WIN32
 LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,
 LPARAM lParam)
#else
 long __far __pascal _export WndProc(HWND hwnd,UINT message,WPARAM
 wParam,LPARAM lParam)
#endif
{
 HDC           hdc;
 PAINTSTRUCT   ps;
 TEXTMETRIC  tm;
 HMENU    hMenu;
 static short  cxClient, cyClient;
 int     i=0;
 WORD    status;
 #ifdef WIN32
  SRB_ExecSCSICmd *SRBPtr;
 #else
  SRB_ExecSCSICmd6 far *SRBPtr;
 #endif

 switch (message)
 {
  case WM_CREATE:
       hdc = GetDC(hwnd);
       SelectObject(hdc,GetStockObject(SYSTEM_FIXED_FONT));
       GetTextMetrics(hdc,&tm);
       cxChar = tm.tmAveCharWidth;
       cyChar = tm.tmHeight;
       ReleaseDC(hwnd,hdc);
       rect.top = 0;
       return zero;

  case WM_PAINT:
   InvalidateRect(hwnd,NULL,TRUE);
   hdc = BeginPaint(hwnd,&ps) ;
   EndPaint (hwnd,&ps) ;
   return zero ;

  case WM_SIZE:
   cxClient = LOWORD(lParam);
   cyClient = HIWORD(lParam);
   rect.right  = LOWORD(lParam);
   rect.bottom = HIWORD(lParam);
   UpdateWindow(hwnd);
   return zero;

  case WM_COMMAND:
   hMenu = GetMenu(hwnd);
   switch (wParam)
   {
    case ID_FILE_EXIT:
     SendMessage(hwnd,WM_CLOSE,0,0L);
     return zero;

    default:
     // 10 = target #0
     // 11 = target #1
     // 12 = target #2
     // 13 = target #3
     // 14 = target #4
     // 15 = target #5
     // 16 = target #6
     // 17 = target #7

     // Toggle the SCSI target scan status (ENABLED/DISABELD)
     if ((wParam >= 10 && wParam <= 17) ||
      (wParam >= 20 && wParam <= 27))
     {
      status = GetMenuState(hMenu,wParam,MF_BYCOMMAND) & MF_CHECKED;
      CheckMenuItem(hMenu,wParam,MF_BYCOMMAND | ((status) ? MF_UNCHECKED:MF_CHECKED));
     }
     return zero;
   }

  case WM_ASPIPOST:
   #ifdef WIN32
    SRBPtr = (PSRB_ExecSCSICmd)lParam;
   #else
    SRBPtr = (SRB_ExecSCSICmd6 far *)lParam;
   #endif
   DisplaySCSIID(hwnd,SRBPtr);
   ScanNextTarget(hwnd);
   return zero;

  case WM_DESTROY:
   PostQuitMessage(0) ;
   return zero ;
 }
 return DefWindowProc (hwnd, message, wParam, lParam) ;
}

When the post routine is called, this sample post handler will fill the wParam field with the status of ASPI command (SRB_Status) while the lParam field will contain a pointer to the SRB which has completed.


Polling

Polling is another method of determining SCSI request completion. This method is not recommended. After the command is sent and ASPI for Win32 returns control back to the calling application, you can then poll the status byte waiting for the command to complete. For example, the following code segment will execute a SCSI Inquiry command to target #2 using polling.

 SRB_ExecSCSICmd6 MySRB;
 DWORD ASPIStatus;
 char InquiryBuffer[32];
  .
  .
 /**************************************************/
 /* Code is entered with 'MySRB' zeroed.
 /**************************************************/
 MySRB.SRB_Cmd     = SC_EXEC_SCSI_CMD;
 MySRB.SRB_Flags     = SRB_DIR_SCSI;
 MySRB.SRB_Target     = 2;
 MySRB.SRB_BufLen     = 32;
 MySRB.SRB_SenseLen    = SENSE_LEN;
 MySRB.SRB_BufPointer   = InquiryBuffer;
 MySRB.SRB_CDBLen     = 6;
 MySRB.CDBByte[0]     = SCSI_INQUIRY;
 MySRB.CDBByte[4]     = 32;
  .
  .
 ASPIStatus      = SendASPI32Command ( (LPSRB) &MySRB );
                // Send Inquiry command
 while ( MySRB.SRB_Status == SS_PENDING );   // Wait till it's finished


Migrating to ASPI for Win32

If you have written ASPI or ASPI for Windows applications in the past, here are some key points to keep in mind when you migrate the applications to ASPI for Win32:

  • Although structure definitions have changed slightly to optimize alignment for 32-bit processors, structure names are consistent with those used in previous ASPI developer's kits. If you would like to use one source base for both 16-bit and 32-bit applications, make sure that you conditionally compile with the appropriate include files for each programming model. New 32-bit include files are available in the ASPI developer's kit. There are many #ifdef statements in the sample code.
  • The CDB area has been fixed in length at 16. Therefore, the sense data area no longer shifts location depending on command length. If you are developing an application targeted only at Win32, you no longer need to account for the "floating" sense buffer.
  • For requests requiring data transfers, the direction bits in the SRB Flags field must be set correctly. Direction bits are no longer optional for data transfers. For requests not requiring data transfers, the direction bits are ignored.
  • If you are using dynamic DLL linking, use LoadLibrary (winaspi32.dll) instead of LoadLibrary(winaspi.dll) in order to access ASPI for Win32. If you are using static DLL linking, use the wnaspi32.lib.
  • All pointers in Win32 are 32 bits (Flat model). Therefore, FAR references are not used.
  • When allocating memory, page locking and global allocations are not necessary.


Programming Guidelines

The following are additional guidelines for writing ASPI for Win32 applications.

  • ASPI for Win32 applications/clients should send an ASPI Abort command to terminate pending ASPI requests before exit.
  • SRBs and data buffers do not need to be in page-locked memory. The ASPI manager takes care of locking buffers and SRBs.
  • If an error SS_BUFFER_TO_BIG is returned by the SendASPI32Command routine, you should break the transfer down into 64 KByte transfers or less. For maximum compatibility, we recommend that you do not request transfer sizes larger than 64 KBytes unless your application requires it.
  • If you send an ASPI request with posting or callback enabled, the callback procedure will always be called. The post or callback routine is called as a standard C function. The caller (in this case, the ASPI manager) cleans up the stack.
  • ASPI for Win32 is fully re-entrant and permits overlapped, asynchronous I/O. Clients can send additional ASPI requests while others are pending completion. Be sure to use a separate SRB for each ASPI request.
  • Be sure to zero out all reserved fields before passing an SRB to ASPI for Win32.
  • Be sure that buffers are aligned according to the buffer alignment mask returned by the SC_HA_INQUIRY command. An alignment of at least a double word is recommended.
  • All SRB structures sent to SendASPI32Command should be compiled packed with byte alignment.
  • Some SCSI devices may have security restrictions that make them inaccessible for read/write operations. In operating systems where security is a feature, accessing a device where the application does not have sufficient security privilege results in a SS_SECURITY_VIOLATION error.
  • When scanning for devices, the SendASPI32Command may also return the status SS_NO_DEVICE in the SRB_Status field. Check for this exception in addition to the host adapter status HASTAT_SEL_TO. As previously mentioned, the callback procedure is always called, including this condition.
  • The SRB flags SRB_POSTING and SRB_EVENT_NOTIFY are mutually exclusive.


Scanning the SCSI Bus for Devices

scanscsi.exe is a very simple ASPI for Win16 and ASPI for Win32 application which scans the SCSI bus and displays the device name of each target it finds on the SCSI bus. When the program first comes up, you are prompted to select either ASPI posting or polling to detect completion of a SCSI request. The Scan menu enables you to configure which SCSI targets should be scanned and which should not:

The following scanscsi.c sample code also shows you how to free up the processor while SCSI operations are running in the background. This is very important, since Windows is currently a non-preemptive multitasking operating system. scanscsi.exe does minimal error checking and has no time-out code. Your application should be more robust.


Source Code for scanscsi.c

// **************************************************************************
//
//         Adaptec, Inc.
//
//         ASPI Developer's  Kit
//          Copyright 1992-1994
//
// **************************************************************************
//
//  This software contains the valuable trade secrets of Adaptec.
//  The software is protected under copyright laws as an
//  unpublished work of Adaptec.  Notice is for informational
//  purposes only and does not imply publication.  The user of this
//  software may make copies of the software for use with parts
//  manufactures by Adaptec or under license from Adaptec and for
//  no other use.
//
// **************************************************************************
//
//  Program Names:  SCAN16.EXE    SCAN32.EXE
//
//  Version:    v2.0      v2.0
//
//  Source Code:   SCANSCSI.C    SCANSCSI.C
//        SCANSCSI.RC    SCANSCSI.RC
//        RESOURCE.H    RESOURCE.H
//        SCAN16.DEF    SCAN32.DEF
//        SCAN16.MAK    SCAN32.MAK
//        SCSIDEFS.H    SCSIDEFS.H
//        WINASPI.H     WNASPI32.H
//
//  Description:   The ASPI test utility programs included here
//        will run on Windows 3.0 or later.  The utility
//        SCAN32.EXE was written for Windows 95 using the
//        ASPI for WIN32 specifications.  Both programs
//        open a window and loop continuously while
//        displaying all of the SCSI devices found on the
//        SCSI bus.  The user can exit at any time by
//        pressing ALT F4 or by selecting EXIT from the
//        applications menu.  The user can enable and
//        disable, on a per target basis, which SCSI targets
//        should get scanned.
//        You should have a basic understanding of writing
//        Windows applications before looking at this
//        source code.
//        Note that this sample code does minimal error
//        checking and no timeout handling.  Your application
//        should be more robust.  This code also demonstrates
//        the polling and posting techniques of determining
//        the completion of the SCSI command.  REFER TO THE
//        "ASPI FOR WINDOWS" SPECIFICATION FOR MORE
//        INFORMATION.
//
//
// **************************************************************************
#pragma pack(1)
#include <windows.h>
#include <string.h>
#include "resource.h"
#include "scsidefs.h"

#ifdef WIN32
 #include "wnaspi32.h"
#else
 #include "winaspi.h"
#endif

#ifdef WIN32
 LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
#else
 long FAR PASCAL WndProc(HWND,UINT,UINT,LONG);
#endif

void ScanNextTarget(HWND);

#ifdef WIN32
 void ASPIPostProc(PSRB_ExecSCSICmd);
 void DisplaySCSIID (HWND,void *);
#else
 void _loadds __far __pascal ASPIPostProc(LPSRB);
 void DisplaySCSIID (HWND,SRB_ExecSCSICmd6 far *);
#endif

HWND  PostHWND;
WORD   NumAdapters;
RECT   rect;
int    UsePosting;
char   szAppName[] = "SCANSCSI" ;
int    cxChar,cyChar;

#ifndef WIN32
 FARPROC   lpfnASPIPostProc;
#endif

// **************************************************************************
//
//            WINMAIN
//
// **************************************************************************
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
                    LPSTR lpszCmdParam, int nCmdShow)
{

 HWND        hwnd;
 MSG         msg ;
 WNDCLASS    wndclass ;

 #ifdef WIN32
  DWORD  ASPIStatus;
 #else
  WORD ASPIStatus;
 #endif

 if (!hPrevInstance)
 {
  wndclass.style    = CS_HREDRAW | CS_VREDRAW ;
  wndclass.lpfnWndProc  = WndProc ;
  wndclass.cbClsExtra   = zero ;
  wndclass.cbWndExtra   = zero ;
  wndclass.hInstance   = hInstance ;
  wndclass.hIcon    = LoadIcon (hInstance,MAKEINTRESOURCE(SCANSCSI)) ;
  wndclass.hCursor    = LoadCursor (NULL, IDC_ARROW) ;
  wndclass.hbrBackground  = GetStockObject (WHITE_BRUSH);
  wndclass.lpszMenuName  = MAKEINTRESOURCE(Menu1);
  wndclass.lpszClassName  = szAppName ;

  RegisterClass (&wndclass) ;
 }
 hwnd = CreateWindow (
    szAppName,      // window class name
    "SCANSCSI",     // window caption
    WS_OVERLAPPEDWINDOW,  // window style
    CW_USEDEFAULT,     // initial x position
    CW_USEDEFAULT,    // initial y position
    CW_USEDEFAULT,    // initial x size
    CW_USEDEFAULT,    // initial y size
    NULL,       // parent window handle
    NULL,       // window menu handle
    hInstance,     // program instance handle
    NULL) ;      // creation parameters

 ShowWindow (hwnd, nCmdShow) ;
// **************************************************************************
// *
// *  Here we check to make sure that ASPI for Windows is resident.
// *  If ASPI for Windows or ASPI for WIN32 is not resident it is
// *  suggested that you provide more user feedback/help than what is
// *  shown in this sample code.
// *
// **************************************************************************

#ifdef WIN32
  ASPIStatus = GetASPI32SupportInfo();
  switch (HIBYTE(LOWORD(ASPIStatus)))
#else
  ASPIStatus = GetASPISupportInfo();
  switch (HIBYTE(ASPIStatus))
#endif
  {
  case SS_COMP:      // ASPI for Windows is resident.
   #ifdef WIN32
    NumAdapters = (LOWORD(LOBYTE(ASPIStatus)));
   #else
    NumAdapters = LOBYTE(ASPIStatus);
   #endif
   MessageBox(hwnd,"ASPI for Windows is resident!",
       szAppName,MB_ICONINFORMATION);
   break;
  default:
   MessageBox(hwnd,"ASPI for Windows not available!",
       szAppName,MB_ICONSTOP);
   return zero;
  }

// **************************************************************************
// *
// *  This code demonstrates the posting abilities of ASPI for Windows
// *   as well as the polling technique.  Ask the user which method they
// *  would like to use to indicate completion of the SCSI request.
// *
// **************************************************************************
 UsePosting = MessageBox(hwnd,"Use ASPI for Windows Posting?",
        szAppName,
        MB_YESNO | MB_ICONQUESTION);

#ifndef WIN32       // NOTE: No need to lock buffers in WIN32.
 LockData(0);

 lpfnASPIPostProc = MakeProcInstance ((FARPROC)ASPIPostProc, hInstance);
#endif
 PostHWND = hwnd;
 if (UsePosting == IDYES)
 {
  ScanNextTarget(hwnd);
  while (GetMessage (&msg, NULL, 0, 0))
  {
   TranslateMessage (&msg) ;
   DispatchMessage (&msg) ;
  }
 }
 else
 {
  while (TRUE)
  {
   if (PeekMessage (&msg,NULL,0,0,PM_REMOVE))
   {
    if (msg.message == WM_QUIT)
     break;

    TranslateMessage(&msg);
    DispatchMessage(&msg);
   }
   else        // While the processor is free, check
    ScanNextTarget(hwnd);  // the SCSI bus status.
  }
 }

 ScanNextTarget(0);      // Finish any pending ASPI requests
 return msg.wParam ;
}
// **************************************************************************
// *
// *  Procedure: WndProc()
// *
// **************************************************************************
#ifdef WIN32
 LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,
 LPARAM lParam)
#else
 long __far __pascal _export WndProc(HWND hwnd,UINT message,WPARAM
 wParam,LPARAM lParam)
#endif
{
 HDC           hdc;
 PAINTSTRUCT   ps;
 TEXTMETRIC  tm;
 HMENU    hMenu;
 static short  cxClient, cyClient;
 int     i=0;
 WORD    status;

 #ifdef WIN32
  SRB_ExecSCSICmd *SRBPtr;
 #else
  SRB_ExecSCSICmd6 far *SRBPtr;
 #endif

 switch (message)
 {
  case WM_CREATE:
       hdc = GetDC(hwnd);
       SelectObject(hdc,GetStockObject(SYSTEM_FIXED_FONT));
       GetTextMetrics(hdc,&tm);
       cxChar = tm.tmAveCharWidth;
       cyChar = tm.tmHeight;
       ReleaseDC(hwnd,hdc);
       rect.top = 0;
       return zero;

  case WM_PAINT:
   InvalidateRect(hwnd,NULL,TRUE);
   hdc = BeginPaint(hwnd,&ps) ;
   EndPaint (hwnd,&ps) ;
   return zero ;

  case WM_SIZE:
   cxClient = LOWORD(lParam);
   cyClient = HIWORD(lParam);
   rect.right  = LOWORD(lParam);
   rect.bottom = HIWORD(lParam);
   UpdateWindow(hwnd);
   return zero;

  case WM_COMMAND:
   hMenu = GetMenu(hwnd);
   switch (wParam)
   {
    case ID_FILE_EXIT:
     SendMessage(hwnd,WM_CLOSE,0,0L);
     return zero;

    default:
     // 10 = target #0
     // 11 = target #1
     // 12 = target #2
     // 13 = target #3
     // 14 = target #4
     // 15 = target #5
     // 16 = target #6
     // 17 = target #7

     // Toggle the SCSI target scan status (ENABLED/DISABELD)
     if ((wParam >= 10 && wParam <= 17) ||
      (wParam >= 20 && wParam <= 27))
     {
      status = GetMenuState(hMenu,wParam,MF_BYCOMMAND) &
           MF_CHECKED;
      CheckMenuItem(hMenu,wParam,MF_BYCOMMAND | ((status) ?
      MF_UNCHECKED:MF_CHECKED));
     }
     return zero;
   }

  case WM_ASPIPOST:
   #ifdef WIN32
    SRBPtr = (PSRB_ExecSCSICmd)lParam;
   #else
    SRBPtr = (SRB_ExecSCSICmd6 far *)lParam;
   #endif
   DisplaySCSIID(hwnd,SRBPtr);
   ScanNextTarget(hwnd);
   return zero;

  case WM_DESTROY:
   PostQuitMessage(0) ;
   return zero ;
 }
 return DefWindowProc (hwnd, message, wParam, lParam) ;
}
// **************************************************************************
//
//  Function:  ScanNextTarget
//
// Description:  If polling is enabled, this function is called
//      whenever Windows is idle.  If a SCSI Inquiry command
//      is still in progress,  this routine will return
//      control back to the caller to free up the CPU. If
//      POSTING is enabled,  this function is called when the
//      SCSI Inquiry command has completed.
//
//  hwnd -   This parameter contains the Window handle where the
//      device names should be listed.  If hwnd equals zero,
//      this indicates that we're exiting this program and this
//      routine should return only after all outstanding ASPI
//      requests have completed.
//
// Returns -   Nothing
//
// **************************************************************************
void ScanNextTarget(HWND hwnd)
{
 HMENU    hMenu;
 static WORD  SRBIsPending=FALSE;
 static BYTE  target_id=7,adapter_id=0;
 static char  InquiryBuffer[100];
 WORD    status, j;
 #ifdef WIN32
  static  SRB_ExecSCSICmd ExecSRB;
 #else
  static  SRB_ExecSCSICmd6 ExecSRB;
 #endif
         // If the user is exiting the program, wait
         // until all pending ASPI requests are
 if (hwnd==0)     //  finished.
 {
  if (SRBIsPending==TRUE)
  {
   while (ExecSRB.SRB_Status == SS_PENDING);
  }
  return;
 }
// ***************************************************************************
// -
// -  If we are still waiting for the previous SCSI Inquiry to finish,
// - simply return back to the caller to free up the CPU.
// -
// ***************************************************************************
 if (UsePosting==IDNO && SRBIsPending==TRUE &&
  ExecSRB.SRB_Status==SS_PENDING)
 {
  return;
 }

 if (SRBIsPending==FALSE || UsePosting==IDYES)
 {
  hMenu = GetMenu(hwnd);
  target_id = (target_id + 1)%8; // Move to next SCSI ID#

  if (target_id == 0)
  {
   adapter_id++;
   if (adapter_id >= (BYTE)NumAdapters)
    adapter_id = 0;
  }

            // Here is where we check
  for (j=0;j<8;j++)     // the menu status.
  {
   status = GetMenuState(hMenu,target_id+10,MF_BYCOMMAND) &
        MF_CHECKED;

   if (status == 0)
   {
    target_id = (target_id + 1) % 8;  // Move to next SCSI ID#
    if (target_id == 0)
    {
     adapter_id++;
     if (adapter_id = (BYTE)NumAdapters)
     {
      adapter_id = 0;
     }
    }
   }
   else
    break;
  }

// Now we construct the SCSI Inquiry SRB and send it to ASPI!

  if (j == 8)      // Return if user disabled scanning of all
  {         //  SCSI targets.
   return;
  }
  ExecSRB.SRB_Cmd     = SC_EXEC_SCSI_CMD;
  ExecSRB.SRB_HaId     = adapter_id;
  ExecSRB.SRB_Flags    = SRB_DIR_IN | SRB_DIR_SCSI;
  ExecSRB.SRB_Target    = target_id;
  ExecSRB.SRB_BufPointer   = InquiryBuffer;
  ExecSRB.SRB_BufLen    = 32;
  ExecSRB.SRB_SenseLen   = SENSE_LEN;
  ExecSRB.SRB_CDBLen    = 6;
  ExecSRB.CDBByte[0]    = SCSI_INQUIRY;
  ExecSRB.CDBByte[1]    = 0;
  ExecSRB.CDBByte[2]    = 0;
  ExecSRB.CDBByte[3]    = 0;
  ExecSRB.CDBByte[4]    = 32;
  ExecSRB.CDBByte[5]    = 0;

  if (UsePosting == IDYES)
  {
   ExecSRB.SRB_Flags  |= SRB_POSTING;
   #ifdef WIN32
    ExecSRB.SRB_PostProc = (void *)ASPIPostProc;
   #else
    ExecSRB.SRB_PostProc = lpfnASPIPostProc;
   #endif
  }
  #ifdef WIN32
   SendASPI32Command(&ExecSRB);
  #else
   SendASPICommand((LPSRB)&ExecSRB);
  #endif
  SRBIsPending = TRUE;     // ASPI command in process
  return;
 }
 if (UsePosting == IDNO)
 {
  SRBIsPending=FALSE;      // Inquiry command has completed
  DisplaySCSIID(hwnd,&ExecSRB);
 }
 return;
}

// **************************************************************************
// Function:  DisplaySCSIID
//
// Description: This function will scroll the window down and display
//     the device name of the target we just sent a SCSI Inquiry
//     command.
//
// hwnd     - This parameter contains the window handle where the device
//     name should be displayed.
//
// ExecSRB  -  This parameter points to the ASPI SCSI Request Block (SRB)
//     which has completed.
//
// Returns:  Nothing
// **************************************************************************
#ifdef WIN32
void DisplaySCSIID ( HWND hwnd, SRB_ExecSCSICmd *ExecSRB)
#else
void DisplaySCSIID(HWND hwnd,SRB_ExecSCSICmd6 far *ExecSRB)
#endif
{
 HDC   hdc;
 char  string_buf[80];
 int   string_len;
 hdc = GetDC (hwnd);
 ScrollDC (hdc, 0, -cyChar, &rect, &rect, NULL, NULL);
 SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT));

 if (ExecSRB->SRB_Status==SS_COMP)
 {
  wsprintf ( string_buf,
      "Host Adapter #%d - SCSI ID #%d:  ",
      (BYTE) ExecSRB->SRB_HaId,
      (BYTE) ExecSRB->SRB_Target );
  #ifdef WIN32
   strncat(string_buf,&ExecSRB->SRB_BufPointer[8],28);
  #else
   lstrcat(string_buf,&ExecSRB->SRB_BufPointer[8] );
  #endif
  string_len = lstrlen(string_buf);
 }
 else
 {
  string_len = wsprintf (string_buf,
         "Host Adapter #%d - SCSI ID #%d:  %-32s",
         (BYTE)ExecSRB->SRB_HaId,
         (BYTE)ExecSRB->SRB_Target,
         (LPSTR)"No Device");
 }
 TextOut(hdc,cxChar,rect.bottom-cyChar,string_buf,string_len);

 ReleaseDC(hwnd,hdc);
 ValidateRect(hwnd,NULL);
 return;
}
// ***************************************************************************
//
// Function:   ASPIPostProc
//
// Description:  If POSTING is enabled,  this function is called by ASPI
//      for Windows when the SCSI request has completed.  This
//      sample function simply posts a message to our Window
//      handle to indicate that the SCSI request has completed.
//
// DoneSRB   This parameter points to the ASPI SCSI Request Block (SRB)
//      which has completed.
//
// Returns     Nothing
//****************************************************************************
#ifdef WIN32
 void ASPIPostProc(PSRB_ExecSCSICmd DoneSRB)
 {
  PostMessage(PostHWND,WM_ASPIPOST,0,(LPARAM)DoneSRB);
  return;
 }
#else
 void _loadds __far __pascal ASPIPostProc(LPSRB DoneSRB)
 {
  PostMessage (PostHWND,WM_ASPIPOST,
      (WORD)((SRB_ExecSCSICmd6 far *)DoneSRB)->SRB_Status,
      (DWORD)DoneSRB);
  return;
 }
#endif


Source Code for scan32.def

This module definition file is used for scanscsi in the Win32 environment.

Name | Scan32
Description | 'SCANSCSI Program'
Code | Preload moveable discardable
Data | Preload moveable multiple
Heapsize | 1024


ASPI for Win32 Definitions (wnaspi32.h)

//***************************************************************************
//
// Name:    WNASPI32.H
//
// Description: ASPI for Win32 definitions ('C' Language)
//
//***************************************************************************

#ifdef __cplusplus
extern "C" {
#endif

typedef void *LPSRB;
typedef void (*PFNPOST)();

DWORD SendASPI32Command    (LPSRB);
DWORD GetASPI32SupportInfo (VOID);

#define SENSE_LEN      14   // Default sense buffer length
#define SRB_DIR_IN      0x08  // Transfer from SCSI target to
             // host
#define SRB_DIR_OUT     0x10  // Transfer from host to SCSI
              // target
#define SRB_POSTING     0x01  // Enable ASPI posting
#define SRB_EVENT_NOTIFY    0x40  // Enable ASPI event notification
#define SRB_ENABLE_RESIDUAL_COUNT  0x04  // Enable residual byte count
             // reporting
#define SRB_DATA_SG_LIST    0x02  // Data buffer points to
              // scatter-gather list
#define WM_ASPIPOST     0x4D42  // ASPI Post message

//***************************************************************************
//       %%% ASPI Command Definitions %%%
//***************************************************************************
#define SC_HA_INQUIRY    0x00   // Host adapter inquiry
#define SC_GET_DEV_TYPE   0x01   // Get device type
#define SC_EXEC_SCSI_CMD   0x02   // Execute SCSI command
#define SC_ABORT_SRB    0x03   // Abort an SRB
#define SC_RESET_DEV    0x04   // SCSI bus device reset
#define SC_GET_DISK_INFO   0x06   // Get Disk information

//***************************************************************************
//          %%% SRB Status %%%
//***************************************************************************
#define SS_PENDING     0x00   // SRB being processed
#define SS_COMP     0x01   // SRB completed without error
#define SS_ABORTED     0x02   // SRB aborted
#define SS_ABORT_FAIL    0x03   // Unable to abort SRB
#define SS_ERR      0x04   // SRB completed with error

#define SS_INVALID_CMD    0x80   // Invalid ASPI command
#define SS_INVALID_HA    0x81   // Invalid host adapter number
#define SS_NO_DEVICE    0x82   // SCSI device not installed
#define SS_INVALID_SRB    0xE0   // Invalid parameter set in SRB
#define SS_BUFFER_ALIGN   0xE1   // Buffer alignment problem
#define SS_SECURITY_VIOLATION  0xE2   // Device access security violation
#define SS_FAILED_INIT    0xE4   // ASPI for windows failed init
#define SS_BUFFER_TO_BIG   0xE6   // Buffer size too big to handle!

//***************************************************************************
//       %%% Host Adapter Status %%%
//***************************************************************************
#define HASTAT_OK     0x00   // Host adapter did not detect an
              // error
#define HASTAT_SEL_TO    0x11   // Selection Timeout
#define HASTAT_DO_DU    0x12   // Data overrun data underrun
#define HASTAT_BUS_FREE   0x13   // Unexpected bus free
#define HASTAT_PHASE_ERR   0x14   // Target bus phase sequence
              // failure
#define HASTAT_TIMEOUT    0x09   // Timed out while SRB was
              // waiting to beprocessed.
#define HASTAT_COMMAND_TIMEOUT  0x0B   // While processing the SRB, the
              // adapter timed out.
#define HASTAT_MESSAGE_REJECT  0x0D   // While processing SRB, the
              // adapter received a MESSAGE
              // REJECT.
#define HASTAT_BUS_RESET   0x0E   // A bus reset was detected.
#define HASTAT_PARITY_ERROR  0x0F   // A parity error was detected.
#define HASTAT_REQUEST_SENSE_FAILED 0x10   // The adapter failed in issuing
              // REQUEST SENSE.

//***************************************************************************
//    %%% SRB - HOST ADAPTER INQUIRY - SC_HA_INQUIRY %%%
//***************************************************************************
typedef struct {
 BYTE  SRB_Cmd;    // ASPI command code = SC_HA_INQUIRY
 BYTE  SRB_Status;    // ASPI command status byte
 BYTE  SRB_HaId;    // ASPI host adapter number
 BYTE  SRB_Flags;    // ASPI request flags
 DWORD  SRB_Hdr_Rsvd;   // Reserved, MUST = zero
 BYTE  HA_Count;    // Number of host adapters present
 BYTE  HA_SCSI_ID;    // SCSI ID of host adapter
 BYTE  HA_ManagerId[16];  // String describing the manager
 BYTE  HA_Identifier[16];  // String describing the host adapter
 BYTE  HA_Unique[16];   // Host Adapter Unique parameters
 WORD  HA_Rsvd1;
} SRB_HAInquiry, *PSRB_HAInquiry;

//***************************************************************************
//     %%% SRB - GET DEVICE TYPE - SC_GET_DEV_TYPE %%%
//***************************************************************************
typedef struct {
 BYTE  SRB_Cmd;    // ASPI command code = SC_GET_DEV_TYPE
 BYTE  SRB_Status;    // ASPI command status byte
 BYTE  SRB_HaId;    // ASPI host adapter number
 BYTE  SRB_Flags;    // Reserved
 DWORD  SRB_Hdr_Rsvd;   // Reserved
 BYTE  SRB_Target;    // Target's SCSI ID
 BYTE  SRB_Lun;    // Target's LUN number
 BYTE  SRB_DeviceType;  // Target's peripheral device type
 BYTE  SRB_Rsvd1;
} SRB_GDEVBlock, *PSRB_GDEVBlock;
//***************************************************************************
//    %%% SRB - EXECUTE SCSI COMMAND - SC_EXEC_SCSI_CMD %%%
//***************************************************************************
typedef struct {
 BYTE  SRB_Cmd;    // ASPI command code = SC_EXEC_SCSI_CMD
 BYTE  SRB_Status;    // ASPI command status byte
 BYTE  SRB_HaId;    // ASPI host adapter number
 BYTE  SRB_Flags;    // ASPI request flags
 DWORD  SRB_Hdr_Rsvd;   // Reserved
 BYTE  SRB_Target;    // Target's SCSI ID
 BYTE  SRB_Lun;    // Target's LUN number
 WORD  SRB_Rsvd1;    // Reserved for Alignment
 DWORD  SRB_BufLen;    // Data Allocation Length
 BYTE  *SRB_BufPointer;  // Data Buffer Pointer
 BYTE  SRB_SenseLen;   // Sense Allocation Length
 BYTE  SRB_CDBLen;    // CDB Length
 BYTE  SRB_HaStat;    // Host Adapter Status
 BYTE  SRB_TargStat;   // Target Status
 void  (*SRB_PostProc)();  // Post routine
 void  *SRB_Rsvd2;    // Reserved
 BYTE  SRB_Rsvd3[16];   // Reserved for alignment
 BYTE  CDBByte[16];   // SCSI CDB
 BYTE  SenseArea[SENSE_LEN+2]; // Request Sense buffer
} SRB_ExecSCSICmd, *PSRB_ExecSCSICmd;

//***************************************************************************
//      %%% SRB - ABORT AN SRB - SC_ABORT_SRB %%%
//***************************************************************************
typedef struct {
 BYTE  SRB_Cmd;    // ASPI command code = SC_EXEC_SCSI_CMD
 BYTE  SRB_Status;    // ASPI command status byte
 BYTE  SRB_HaId;    // ASPI host adapter number
 BYTE  SRB_Flags;    // Reserved
 DWORD  SRB_Hdr_Rsvd;   // Reserved
 void  *SRB_ToAbort;   // Pointer to SRB to abort
} SRB_Abort, *PSRB_Abort;

//***************************************************************************
//    %%% SRB - BUS DEVICE RESET - SC_RESET_DEV %%%
//***************************************************************************
typedef struct {
 BYTE  SRB_Cmd;    // ASPI command code = SC_EXEC_SCSI_CMD
 BYTE  SRB_Status;    // ASPI command status byte
 BYTE  SRB_HaId;    // ASPI host adapter number
 BYTE  SRB_Flags;    // Reserved
 DWORD  SRB_Hdr_Rsvd;   // Reserved
 BYTE  SRB_Target;    // Target's SCSI ID
 BYTE  SRB_Lun;    // Target's LUN number
 BYTE  SRB_Rsvd1[12];   // Reserved for Alignment
 BYTE  SRB_HaStat;    // Host Adapter Status
 BYTE  SRB_TargStat;   // Target Status
 void  (*SRB_PostProc)();  // Post routine
 void  *SRB_Rsvd2;    // Reserved
 BYTE  SRB_Rsvd3[32];   // Reserved
} SRB_BusDeviceReset, *PSRB_BusDeviceReset;

//***************************************************************************
//    %%% SRB - GET DISK INFORMATION - SC_GET_DISK_INFO %%%
//***************************************************************************
typedef struct {
 BYTE  SRB_Cmd;    // ASPI command code = SC_EXEC_SCSI_CMD
 BYTE  SRB_Status;    // ASPI command status byte
 BYTE  SRB_HaId;    // ASPI host adapter number
 BYTE  SRB_Flags;    // Reserved
 DWORD  SRB_Hdr_Rsvd;   // Reserved
 BYTE  SRB_Target;    // Target's SCSI ID
 BYTE  SRB_Lun;    // Target's LUN number
 BYTE  SRB_DriveFlags;  // Driver flags
 BYTE  SRB_Int13HDriveInfo // Host Adapter Status
 BYTE  SRB_Heads;    // Preferred number of heads translation
 BYTE  SRB_Sectors;   // Preferred number of sectors translation
 BYTE  SRB_Rsvd1[10];   // Reserved
} SRB_GetDiskInfo, *PSRB_GetDiskInfo;

#ifdef __cplusplus
}
#endif


SCSI Definitions (scsidefs.h)

//***************************************************************************
//
// Name:    SCSIDEFS.H
//
// Description: SCSI definitions ('C' Language)
//
//***************************************************************************

//***************************************************************************
//       %%% TARGET STATUS VALUES %%%
//***************************************************************************
#define STATUS_GOOD    0x00   // Status Good
#define STATUS_CHKCOND    0x02   // Check Condition
#define STATUS_CONDMET    0x04   // Condition Met
#define STATUS_BUSY    0x08   // Busy
#define STATUS_INTERM    0x10   // Intermediate
#define STATUS_INTCDMET   0x14   // Intermediate-condition met
#define STATUS_RESCONF    0x18   // Reservation conflict
#define STATUS_COMTERM    0x22   // Command Terminated
#define STATUS_QFULL    0x28   // Queue full

//***************************************************************************
//      %%% SCSI MISCELLANEOUS EQUATES %%%
//***************************************************************************
#define MAXLUN      7    // Maximum Logical Unit Id
#define MAXTARG     7    // Maximum Target Id
#define MAX_SCSI_LUNS    64    // Maximum Number of SCSI LUNs
#define MAX_NUM_HA     8    // Maximum Number of SCSI HA's

//---------------------------------------------------------------------------
//
//       %%% SCSI COMMAND OPCODES %%%
//
//---------------------------------------------------------------------------
//***************************************************************************
//     %%% Commands for all Device Types %%%
//***************************************************************************
#define SCSI_CHANGE_DEF   0x40   // Change Definition (Optional)
#define SCSI_COMPARE    0x39   // Compare (O)
#define SCSI_COPY     0x18   // Copy (O)
#define SCSI_COP_VERIFY   0x3A   // Copy and Verify (O)
#define SCSI_INQUIRY    0x12   // Inquiry (MANDATORY)
#define SCSI_LOG_SELECT   0x4C   // Log Select (O)
#define SCSI_LOG_SENSE    0x4D   // Log Sense (O)
#define SCSI_MODE_SEL6    0x15   // Mode Select 6-byte (Device Specific)
#define SCSI_MODE_SEL10   0x55   // Mode Select 10-byte (Device Specific)
#define SCSI_MODE_SEN6    0x1A   // Mode Sense 6-byte (Device Specific)
#define SCSI_MODE_SEN10   0x5A   // Mode Sense 10-byte (Device Specific)
#define SCSI_READ_BUFF    0x3C   // Read Buffer (O)
#define SCSI_REQ_SENSE    0x03   // Request Sense (MANDATORY)
#define SCSI_SEND_DIAG    0x1D   // Send Diagnostic (O)
#define SCSI_TST_U_RDY    0x00   // Test Unit Ready (MANDATORY)
#define SCSI_WRITE_BUFF   0x3B   // Write Buffer (O)

//***************************************************************************
//     %%% Commands Unique to Direct Access Devices %%%
//***************************************************************************
#define SCSI_COMPARE    0x39   // Compare (O)
#define SCSI_FORMAT    0x04   // Format Unit (MANDATORY)
#define SCSI_LCK_UN_CAC   0x36   // Lock Unlock Cache (O)
#define SCSI_PREFETCH    0x34   // Prefetch (O)
#define SCSI_MED_REMOVL   0x1E   // Prevent/Allow medium Removal (O)
#define SCSI_READ6     0x08   // Read 6-byte (MANDATORY)
#define SCSI_READ10    0x28   // Read 10-byte (MANDATORY)
#define SCSI_RD_CAPAC    0x25   // Read Capacity (MANDATORY)
#define SCSI_RD_DEFECT    0x37   // Read Defect Data (O)
#define SCSI_READ_LONG    0x3E   // Read Long (O)
#define SCSI_REASS_BLK    0x07   // Reassign Blocks (O)
#define SCSI_RCV_DIAG    0x1C   // Receive Diagnostic Results (O)
#define SCSI_RELEASE    0x17   // Release Unit (MANDATORY)
#define SCSI_REZERO    0x01   // Rezero Unit (O)
#define SCSI_SRCH_DAT_E   0x31   // Search Data Equal (O)
#define SCSI_SRCH_DAT_H   0x30   // Search Data High (O)
#define SCSI_SRCH_DAT_L   0x32   // Search Data Low (O)
#define SCSI_SEEK6     0x0B   // Seek 6-Byte (O)
#define SCSI_SEEK10    0x2B   // Seek 10-Byte (O)
#define SCSI_SEND_DIAG    0x1D   // Send Diagnostics (MANDATORY)
#define SCSI_SET_LIMIT    0x33   // Set Limits (O)
#define SCSI_START_STP    0x1B   // Start/Stop Unit (O)
#define SCSI_SYNC_CACHE   0x35   // Synchronize Cache (O)
#define SCSI_VERIFY    0x2F   // Verify (O)
#define SCSI_WRITE6    0x0A   // Write 6-Byte (MANDATORY)
#define SCSI_WRITE10    0x2A   // Write 10-Byte (MANDATORY)
#define SCSI_WRT_VERIFY   0x2E   // Write and Verify (O)
#define SCSI_WRITE_LONG   0x3F   // Write Long (O)
#define SCSI_WRITE_SAME   0x41   // Write Same (O)

//***************************************************************************
//   %%% Commands Unique to Sequential Access Devices %%%
//***************************************************************************
#define SCSI_ERASE     0x19   // Erase (MANDATORY)
#define SCSI_LOAD_UN    0x1b   // Load/Unload (O)
#define SCSI_LOCATE    0x2B   // Locate (O)
#define SCSI_RD_BLK_LIM   0x05   // Read Block Limits (MANDATORY)
#define SCSI_READ_POS    0x34   // Read Position (O)
#define SCSI_READ_REV    0x0F   // Read Reverse (O)
#define SCSI_REC_BF_DAT   0x14   // Recover Buffer Data (O)
#define SCSI_RESERVE    0x16   // Reserve Unit (MANDATORY)
#define SCSI_REWIND    0x01   // Rewind (MANDATORY)
#define SCSI_SPACE     0x11   // Space (MANDATORY)
#define SCSI_VERIFY_T    0x13   // Verify (Tape) (O)
#define SCSI_WRT_FILE    0x10   // Write Filemarks (MANDATORY)

//***************************************************************************
//      %%% Commands Unique to Printer Devices %%%
//***************************************************************************
#define SCSI_PRINT     0x0A   // Print (MANDATORY)
#define SCSI_SLEW_PNT    0x0B   // Slew and Print (O)
#define SCSI_STOP_PNT    0x1B   // Stop Print (O)
#define SCSI_SYNC_BUFF    0x10   // Synchronize Buffer (O)

//***************************************************************************
//     %%% Commands Unique to Processor Devices %%%
//***************************************************************************
#define SCSI_RECEIVE    0x08   // Receive (O)
#define SCSI_SEND     0x0A   // Send (O)

//***************************************************************************
//    %%% Commands Unique to Write-Once Devices %%%
//***************************************************************************
#define SCSI_MEDIUM_SCN   0x38   // Medium Scan (O)
#define SCSI_SRCHDATE10   0x31   // Search Data Equal 10-Byte (O)
#define SCSI_SRCHDATE12   0xB1   // Search Data Equal 12-Byte (O)
#define SCSI_SRCHDATH10   0x30   // Search Data High 10-Byte (O)
#define SCSI_SRCHDATH12   0xB0   // Search Data High 12-Byte (O)
#define SCSI_SRCHDATL10   0x32   // Search Data Low 10-Byte (O)
#define SCSI_SRCHDATL12   0xB2   // Search Data Low 12-Byte (O)
#define SCSI_SET_LIM_10   0x33   // Set Limits 10-Byte (O)
#define SCSI_SET_LIM_12   0xB3   // Set Limits 10-Byte (O)
#define SCSI_VERIFY10    0x2F   // Verify 10-Byte (O)
#define SCSI_VERIFY12    0xAF   // Verify 12-Byte (O)
#define SCSI_WRITE12    0xAA   // Write 12-Byte (O)
#define SCSI_WRT_VER10    0x2E   // Write and Verify 10-Byte (O)
#define SCSI_WRT_VER12    0xAE   // Write and Verify 12-Byte (O)

//***************************************************************************
//      %%% Commands Unique to CD-ROM Devices %%%
//***************************************************************************
#define SCSI_PLAYAUD_10   0x45   // Play Audio 10-Byte (O)
#define SCSI_PLAYAUD_12   0xA5   // Play Audio 12-Byte 12-Byte (O)
#define SCSI_PLAYAUDMSF   0x47   // Play Audio MSF (O)
#define SCSI_PLAYA_TKIN   0x48   // Play Audio Track/Index (O)
#define SCSI_PLYTKREL10   0x49   // Play Track Relative 10-Byte (O)
#define SCSI_PLYTKREL12   0xA9   // Play Track Relative 12-Byte (O)
#define SCSI_READCDCAP    0x25   // Read CD-ROM Capacity (MANDATORY)
#define SCSI_READHEADER   0x44   // Read Header (O)
#define SCSI_SUBCHANNEL   0x42   // Read Subchannel (O)
#define SCSI_READ_TOC    0x43   // Read TOC (O)

//***************************************************************************
//      %%% Commands Unique to Scanner Devices %%%
//***************************************************************************
#define SCSI_GETDBSTAT    0x34   // Get Data Buffer Status (O)
#define SCSI_GETWINDOW    0x25   // Get Window (O)
#define SCSI_OBJECTPOS    0x31   // Object Postion (O)
#define SCSI_SCAN     0x1B   // Scan (O)
#define SCSI_SETWINDOW    0x24   // Set Window (MANDATORY)

//***************************************************************************
//    %%% Commands Unique to Optical Memory Devices %%%
//***************************************************************************
#define SCSI_UpdateBlk    0x3D   // Update Block (O)

//***************************************************************************
//    %%% Commands Unique to Medium Changer Devices %%%
//***************************************************************************
#define SCSI_EXCHMEDIUM   0xA6   // Exchange Medium (O)
#define SCSI_INITELSTAT   0x07   // Initialize Element Status (O)
#define SCSI_POSTOELEM    0x2B   // Position to Element (O)
#define SCSI_REQ_VE_ADD   0xB5   // Request Volume Element Address (O)
#define SCSI_SENDVOLTAG   0xB6   // Send Volume Tag (O)

//***************************************************************************
//     %%% Commands Unique to Communication Devices %%%
//***************************************************************************
#define SCSI_GET_MSG_6    0x08   // Get Message 6-Byte (MANDATORY)
#define SCSI_GET_MSG_10   0x28   // Get Message 10-Byte (O)
#define SCSI_GET_MSG_12   0xA8   // Get Message 12-Byte (O)
#define SCSI_SND_MSG_6    0x0A   // Send Message 6-Byte (MANDATORY)
#define SCSI_SND_MSG_10   0x2A   // Send Message 10-Byte (O)
#define SCSI_SND_MSG_12   0xAA   // Send Message 12-Byte (O)
//---------------------------------------------------------------------------
//
//       %%% END OF SCSI COMMAND OPCODES %%%
//
//---------------------------------------------------------------------------

//***************************************************************************
//      %%% Request Sense Data Format %%%
//***************************************************************************
typedef struct {
 BYTE  ErrorCode;    // Error Code (70H or 71H)
 BYTE  SegmentNum;    // Number of current segment descriptor
 BYTE  SenseKey;    // Sense Key(See bit definitions too)
 BYTE  InfoByte0;    // Information MSB
 BYTE  InfoByte1;    // Information MID
 BYTE  InfoByte2;    // Information MID
 BYTE  InfoByte3;    // Information LSB
 BYTE  AddSenLen;    // Additional Sense Length
 BYTE  ComSpecInf0;   // Command Specific Information MSB
 BYTE  ComSpecInf1;   // Command Specific Information MID
 BYTE  ComSpecInf2;   // Command Specific Information MID
 BYTE  ComSpecInf3;   // Command Specific Information LSB
 BYTE  AddSenseCode;   // Additional Sense Code
 BYTE  AddSenQual;    // Additional Sense Code Qualifier
 BYTE  FieldRepUCode;   // Field Replaceable Unit Code
 BYTE  SenKeySpec15;   // Sense Key Specific 15th byte
 BYTE  SenKeySpec16;   // Sense Key Specific 16th byte
 BYTE  SenKeySpec17;   // Sense Key Specific 17th byte
 BYTE  AddSenseBytes;   // Additional Sense Bytes
} SENSE_DATA_FMT;

//***************************************************************************
//       %%% REQUEST SENSE ERROR CODE %%%
//***************************************************************************
#define SERROR_CURRENT    0x70   // Current Errors
#define SERROR_DEFERED    0x71   // Deferred Errors

//***************************************************************************
//      %%% REQUEST SENSE BIT DEFINITIONS %%%
//***************************************************************************
#define SENSE_VALID    0x80   // Byte 0 Bit 7
#define SENSE_FILEMRK    0x80   // Byte 2 Bit 7
#define SENSE_EOM     0x40   // Byte 2 Bit 6
#define SENSE_ILI     0x20   // Byte 2 Bit 5

//***************************************************************************
//     %%% REQUEST SENSE SENSE KEY DEFINITIONS %%%
//***************************************************************************
#define KEY_NOSENSE    0x00   // No Sense
#define KEY_RECERROR    0x01   // Recovered Error
#define KEY_NOTREADY    0x02   // Not Ready
#define KEY_MEDIUMERR    0x03   // Medium Error
#define KEY_HARDERROR    0x04   // Hardware Error
#define KEY_ILLGLREQ    0x05   // Illegal Request
#define KEY_UNITATT    0x06   // Unit Attention
#define KEY_DATAPROT    0x07   // Data Protect
#define KEY_BLANKCHK    0x08   // Blank Check
#define KEY_VENDSPEC    0x09   // Vendor Specific
#define KEY_COPYABORT    0x0A   // Copy Abort
#define KEY_EQUAL     0x0C   // Equal (Search)
#define KEY_VOLOVRFLW    0x0D   // Volume Overflow
#define KEY_MISCOMP    0x0E   // Miscompare (Search)
#define KEY_RESERVED    0x0F   // Reserved

//***************************************************************************
//      %%% PERIPHERAL DEVICE TYPE DEFINITIONS %%%
//***************************************************************************
#define DTYPE_DASD     0x00   // Disk Device
#define DTYPE_SEQD     0x01   // Tape Device
#define DTYPE_PRNT     0x02   // Printer
#define DTYPE_PROC     0x03   // Processor
#define DTYPE_WORM     0x04   // Write-once read-multiple
#define DTYPE_CROM     0x05   // CD-ROM device
#define DTYPE_SCAN     0x06   // Scanner device
#define DTYPE_OPTI     0x07   // Optical memory device
#define DTYPE_JUKE     0x08   // Medium Changer device
#define DTYPE_COMM     0x09   // Communications device
#define DTYPE_RESL     0x0A   // Reserved (low)
#define DTYPE_RESH     0x1E   // Reserved (high)
#define DTYPE_UNKNOWN    0x1F   // Unknown or no device type

//***************************************************************************
//      %%% ANSI APPROVED VERSION DEFINITIONS %%%
//***************************************************************************
#define ANSI_MAYBE     0x0  // Device may or may not be ANSI approved stand
#define ANSI_SCSI1     0x1  // Device complies to ANSI X3.131-1986 (SCSI-1)
#define ANSI_SCSI2     0x2  // Device complies to SCSI-2
#define ANSI_RESLO     0x3  // Reserved (low)
#define ANSI_RESHI     0x7  // Reserved (high)


Windows 95 Support for Large IDE Drives

Microsoft® Windows® 95 supports drives whose characteristics exceed the standard INT 13h limitations. It does this by using geometry translation, INT 13 extensions, Logical Block Addressing (LBA) mode, or software mechanisms. Windows 95 Support for Large IDE Drives describes the methods Windows 95 uses to detect whether a drive needs support and explains how this support is implemented.


Support Mechanisms

Windows 95 checks for and takes over support for large IDE drives if the drives are also supported by the following mechanisms:

  • Geometry translation in BIOS. Windows 95 supports if it can determine the translation method.
  • INT 13 extensions in BIOS. For more information about the INT 13 extensions, see About Int 13 Extension APIs.
  • BIOS use of Logical Block Addressing (LBA) mode. Windows 95 uses LBA mode on the device, if the BIOS does.
  • One of these software mechanisms: Ontrack Disk Manager version 6.03 or greater, EZ-Drive API, or master boot record hooking. Windows 95 takes over the support of this in protected mode. For more information, see Software Mechanisms.

Microsoft strongly recommends that BIOS developers and OEMs help make sure that new computers having large IDE devices are fully supported by Windows 95.

For developers writing the BIOS to support an IDE drive, Microsoft recommends that you use one of the BIOS translation methods described in Support Mechanisms or use the INT 13 extensions. In particular, if the IDE device supports LBA, use the LBA addressing scheme.

For OEMs creating systems that include large IDE drives, Microsoft recommends that you make sure that BIOS support matches one of the support mechanisms that Windows 95 can take over.


Geometry Translation

To overcome the geometry limitations imposed by the INT 13h specification, some BIOS drivers translate the IDE drive's actual geometry into a geometry that will fit within the confines of the INT 13h limitations. For Windows 95 to support BIOS level geometry translation, it must be able to determine both the actual and apparent geometry that the BIOS is using. Windows 95 retrieves the apparent geometry from information returned by INT 13h, Function 8. There are three means used to determine actual disk geometry:

  • Extract from the Fixed Disk Parameter Table
  • Retrieve using the ATA IDENTIFY command
  • Retrieve using the Ontrack Disk Manager XBIOS function interface

If all three of these methods fail to produce actual geometry that allows correct access to the drive, the Windows 95 IDE driver unloads and disk access continues to go through the BIOS.


Geometry From Fixed Disk Parameter Table

The Fixed Disk Parameter Table (FDPT), a structure which is normally constructed by the BIOS at POST time, is utilized to determine actual geometry. The FDPT for the drive is referenced by the address contained in the INT 41h or INT 46h vectors for the master and slave drive, respectively, on the primary controller. The primary controller is the IDE controller whose base port address is 1F0h. For determination of actual disk geometry, the table must be constructed as described in the following:

FDPT_Apparent_Cyls    dw ?  ; # of apparent cylinders
FDPT_Apparent_Heads   db ?  ; # of apparent heads
FDPT_Signature        db ?  ; signature (Axh)
FDPT_Actual_SPT       db ?  ; # of actual sectors per track
FDPT_Precompensation  dw ?  ; write precompensation
FDPT_Reserved         db ?  ; reserved
FDPT_Control          db ?  ; drive control byte
FDPT_Actual_Cyls      dw ?  ; # of actual cylinders
FDPT_Actual_Heads     db ?  ; # of actual heads
FDPT_Landing          dw ?  ; landing zone
FDPT_Apparent_SPT     db ?  ; # of apparent sectors per track
FDPT_Checksum         db ?  ; checksum byte

The checksum of the entire table must be zero. Therefore, the checksum byte should be chosen to cause the summation of all of the bytes in the table to equal 00h. The signature must be set to Axh (only the high nibble is checked). These two characteristics indicate that translation is occurring in the BIOS, and that the actual geometry in the table is correct.

Once the two characteristics described above have been verified by Windows 95, the parameters for the actual number of heads, sectors per track, and cylinders are extracted from the table and are used as the actual geometry of the drive. Windows 95 then verifies that the actual and apparent geometry values that have been retrieved do indeed facilitate accessing the disk drive correctly.


Geometry From the ATA IDENTIFY Command

If the FDPT has not been enhanced by BIOS (as described in the previous section) or the IDE controller in question is not the primary controller and it is determined that the BIOS is doing translation, Windows 95 attempts to retrieve the actual disk geometry via information returned in the ATA IDENTIFY command. The actual geometry is extracted from the appropriate fields in the IDENTIFY data. Windows 95 then verifies that the actual and apparent geometry values that have been retrieved do indeed facilitate accessing the disk drive correctly.


Geometry From the Ontrack Disk Manager XBIOS

Windows 95 supports the Ontrack Disk Manager XBIOS driver. If Windows 95 detects version 6.03 or later of the driver (both the Master Boot Record and CONFIG.SYS driver versions), the Windows 95 IDE driver obtains the actual geometry and sector skew factor from the driver using the driver's function interface. For more information about the interface supported by this driver, see Ontrack Computer Systems.


Logical Block Addressing

Logical Block Addressing (LBA) mode for IDE drives is implemented as defined in the AT Attachment Specification. If Windows 95 determines that the IDE drive supports LBA, this mode of addressing is used to access the drive. Once it is determined that the drive supports LBA, Windows 95 verifies that the drive can be accessed correctly using this mode. Windows 95 will not use LBA mode for the drive unless the drive is accessed in LBA mode through the BIOS.


Software Mechanisms

Software mechanisms are typically used with older machines where the BIOS does not support big drives either through translation or INT 13 extensions. Windows 95 supports three software mechanisms. Any future software should subscribe to one of these methods:

  • The Ontrack scheme skews the whole disk. If you develop a scheme that skews the whole disk, you should respond to the Ontrack API so that Windows 95 can understand and take over in protect mode. For more information on this support, see Ontrack Computer Systems.
  • The EZ-Drive scheme skews just the MBR and leaves the rest of the disk alone. It skews the MBR specifically to sector 2 (from sector 1 assuming one-based numbering). If you develop a scheme that skews just the MBR, you should implement the EZ-Drive API so that Windows 95 can understand and take over in protect mode. For more information on this support, see EZ-Drive.
  • The MBR hook carries out the Western Digital and/or Phoenix EDD specification translation, but no skewing. If you develop a scheme that hooks the MBR, you need to make it a safe MBR hook so that Windows 95 can understand and take over in protect mode. For more information, see Safe MBR Hook.


Ontrack Computer Systems

This section describes two INT 13h API supported by XBIOS. These commands can be used by a device driver to obtain operating parameters from XBIOS. This will allow the device driver to take over XBIOS and retain full compatibility with it. This section was originally written with FASTDISK in mind but applies to any driver which needs compatibility with Ontrack Disk Manager and Ontrack Drive Rocket software.


What is XBIOS?

XBIOS is a term which describes a device driver shipped with many Ontrack products. It is a INT13 hooking device driver which accesses the AT ports directly. It provides all the INT13 opcodes defined in the original IBM AT BIOS in addition to many Ontrack proprietary commands. Some of these commands include a translator to access IDE drives larger than 528Mb, Read and Write Multiple, and IDE Identify to name a few.


Compatibility With Enhanced BIOS Features

Ontrack recommends that the FASTDISK driver perform all BIOS detection algorithms prior to looking for XBIOS. This allows future versions of XBIOS to incorporate standardized BIOS enhancement features without requiring changes to the FASTDISK driver. If the FASTDISK driver looks for XBIOS first, there may be features in XBIOS that the FASTDISK driver will miss.


Detecting XBIOS Resident in the System

;**********************************************************************
;* XBIOS Identify Command
;* The following code checks for the presence of XBIOS
;**********************************************************************
    mov   ax,0f900h
    mov   dx,80h
    int   13h
    jc    xbios_driver_not_resident
    test  dx,8000h
    jz    xbios_driver_not_resident
;Ontrack XBIOS driver is resident


Obtaining Configuration Information From XBIOS

;**********************************************************************
;*  XBIOS VxD Query Command
;*  The following code obtains information from XBIOS
;**********************************************************************
xbios_command_block STRUC
opcode     db ?  ;Input: XBIOS opcode 0Eh
reserved   db ?  ;Input: must be zero
bufoff     dw ?  ;Output: ptr to Ontrackr_Ref_Data
bufseg     dw ?  ;Output: ptr to Ontrackr_Ref_Data
xbios_command_block ENDS
;
packet  xbios_command_block <>
;
    push  ds                ;ES = DS
    pop   es                ;ES = DS
    mov   ax,0e000h         ;XBIOS opcode
    mov   bx,offset packet  ;ES:BX = ptr to xbios_command_block
    mov   [bx].opcode,0Eh   ;opcode 0E, VxD Query
    mov   [bx].reserved,0   ;reserved, must be zero
    mov   cx,0              ;signature validation
    mov   dl,80h            ;drive number
    int   13h               ;send it to XBIOS
    jc    VxD_query_not_supported    ;j--XBIOS did not understand
    cmp   cx,1234h          ;signature check?
    jne   VxD_query_not_supported    ;j--XBIOS did not understand

At this point, the bufoff and bufseg fields of the xbios_command_block contain a pointer to the Ontrackr_Ref_Data structure inside the XBIOS driver.

STRUCTURE DEFINITIONS

;**********************************************************************
;   Structure returned for VxD Query command.
;**********************************************************************
Ontrackr_Ref_Data  STRUC
VxD_Data_Size    dw size Ontrackr_Ref_Data  ;size of this struct (33h)
VxD_Chain_Mode   db ?
Drive1_Data      db size Ontrackr_VxD_Data dup(?)
Drive2_Data      db size Ontrackr_VxD_Data dup(?)
Drive3_Data      db size Ontrackr_VxD_Data dup(?)
Drive4_Data      db size Ontrackr_VxD_Data dup(?)
Ontrackr_Ref_Data  ENDS

Note The VxD_Chain_Mode field provides a mechanism for a device driver to "unhook" XBIOS from the INT13 chain. By placing any nonzero value into this field, XBIOS will simply jump to the next interrupt handler in the INT13 chain.

;**********************************************************************
;   Structure describing a drive controlled by XBIOS
;**********************************************************************
Ontrackr_VxD_Data  STRUC
VxD_INT13_Drive  db ?  ; INT13 drive number
VxD_Delta        dd ?  ; Delta skew value
VxD_Heads        db ?  ; Physical  heads (Word 3 of Identify Data)
VxD_SPT          db ?  ; Physical sectors per track (Word 6 of Identify Data)
VxD_MBS          db ?  ; Multiple Block Size (Blocking factor)
VxD_MBS_Flags    db ?  ; Read/Write Multiple disable flags
VxD_Base_Port    dw ?  ; Base port address (1F0/170)
VxD_IRQ_Channel  db ?  ; Hardware interrupt channel (14/15)
Ontrackr_VxD_Data  ENDS

;**********************************************************************
;Bit Definitions for VxD_MBS_Flags
;**********************************************************************
X_SUPPORT_MULTIPLE   EQU  00001000b   ;drive supports r/w multiple
X_READ_MULT_OFF      EQU  00000100b   ;do not use read multiple
X_WRITE_MULT_OFF     EQU  00000010b   ;do not use write multiple
;


Implementation Notes

If the XBIOS driver responds to the XBIOS Identify command but fails the XBIOS VxD Query Command, the FASTDISK driver should refuse to load. This provides backward compatibility with older XBIOS drivers in the field.

If the XBIOS driver returns a value other than 33h in the VxD_Data_Size field or something other than zero or 63 as the VxD_Delta value, the FASTDISK driver should refuse to load. This provides forward compatibility should there be changes or enhancements to XBIOS.

When a drive contains a nonzero value in the VxD_Delta field, the following rules apply:

  1. The INT13 geometry for the drive is presented as a 2**n by 63 translation where total cylinders are always less than or equal to 1024 and the head value doubles as drive capacity increases up to a maximum of 1024 x 255 x 63 or 8.4Gb. The INT13 geometry is always obtainable by using INT13 Function 8. The INT41/46 vector for such a drive also contains these values but does not contain the "A0" translation signature because of the sector skewing described later.
  2. The drive is configured to operate using the VxD_Heads and VxD_SPT values. These values are obtained during the XBIOS startup process from words 3 and 6 of the IDE Identify data.
  3. For every I/O request, the driver must perform a CHS-to-CHS translation with a sector skew added as described in the following.
    INT13 CHS -> Logical Block Address -> +VxD_Delta -> Drive CHS -> TaskFile

When a drive contains a nonzero value in the VxD_MBS field, the following rules apply:

  1. The drive has been configured with the Set Multiple Mode command to perform Read Multiple and Write Multiple at the blocking factor contained in the VxD_MBS field.
  2. The VxD_MBS_Flags bit descriptions are as follows:
    X_SUPPORT_MULTIPLE

    This bit is set if the drive supports Multiple Mode. This bit can be set even if the VxD_MBS field is zero. This bit is always set if VxD_MBS is nonzero.

    X_READ_MULT_OFF

    This bit is set if the drive has been set to Multiple Mode but should not issue Read Multiple commands. Some drives perform poorly under Read Multiple.

    X_WRITE_MULT_OFF

    This bit is set if the drive has been set to Multiple Mode but should not issue Write Multiple commands. Some drives perform poorly under Write Multiple.

  3. It has been our experience that single sector requests should never use the Read Multiple and Write Multiple commands. Most drives have a performance degradation in this case.
  4. If the driver performs a soft reset, the drive should be sent a Set Multiple Mode command. XBIOS already does this on INT13 Function 00 and 0D. This is needed because some drives do not retain their blocking factor through a soft reset.

The VxD_Base_Port and VxD_IRQ_Channel deal with XBIOS's secondary controller support. If the FASTDISK driver does not support secondary controllers, simply make sure that it does not register any of these drives.


EZ-Drive

Windows 95 supports Master Boot Record skewing using the EZ-Drive scheme by Micro House. Any other software that intends to skew just the MBR on the drive has to support the following API and skew the Master Boot Record as defined in the following. All other sectors on the drive are not skewed in this scheme.


Interrupt 13h, Function FFh

mov ah, 0FFh
mov dl, 80h
int 13h
jc error

Check install function for a Master Boot Record skewing driver.

  • Clears the carry flag, returns 55AAh in the AX register, and sets the ES:BX register pair to the address of the string "AERMH13Vxx", where xx is the version number of the EZ-Drive driver.

The ES in ES:BX must be the same segment as the segment of the actual INT 13 hook (at the INT 13 vector) for the MBR hooker.

Sector 1, the normal location of the Master Boot Record, contains the right boot software but a bogus partition table with a system type of 55H. The real partition table is kept at the same location in sector 2. Any disk geometry translation done by the software has to conform to the Enhanced Drive Parameter Table as defined by the Western Digital Enhanced IDE specification.


Safe MBR Hook

To create a safe MBR hook for translation, you can either write an MBR hooker and a corresponding VSD or just write an MBR hooker that sets the smhflgs member to 1. In either case, the MBR hooker must have a SafeMBRHook structure at the beginning of its hook routine, as described in About Vendor-Supplied Drivers.

You do not have to write a VSD if the MBR hooker only has functionality that the Windows 95 IDE driver already supports. In this case, the MBR hooker can set the smhflgs member to 1 on its own so that Windows 95 can take over in protect mode.

If the MBR hooker has functionality that is not already supported by Windows 95, for example, encryption, you must write a VSD or leave your MBR hooker marked as unsafe. If you write a VSD to support the extra functionality in protect mode, the VSD is responsible for setting the smhflgs member to 1 to indicate to Windows 95 that it is safe to take over in protect mode.


Joliet CD-ROM Recording Specification, ISO 9660:1988 Extensions for Unicode

While the CD-ROM media provides for cost-effective software distribution, the existing ISO 9660 file system contains a number of restrictions which interfere with simple and efficient distribution of files on a CD-ROM.

The read-only nature of CD-ROM media has led content authors to continue to use traditional magnetic media as their main avenue for creating applications. Each of the existing file systems for magnetic media contain various features which can not be represented on CD-ROM media using an unenhanced version of ISO 9660.

As content authors attempt to transfer their applications to the CD-ROM, they are likely to find that some of their work cannot be distributed on the CD-ROM media due to restrictions in the ISO 9660 format. This frustrates some content authors.

Because the CD-ROM media is mainly a distribution media, rather than a creative (read/write) media, it is necessary for the CD-ROM file system to support a superset of the creative media features. This fundamental flaw in the design of ISO 9660 has prompted several operating systems vendors to extend ISO 9660 in several ways. Some examples are Rock Ridge Interchange Protocol and Apple's use of the System Use Area to store finder flags.

Some of the ISO 9660 problems which are addressed by this specification include:

  • Character Set limitations.
  • File Name Length limitations
  • Directory Tree Depth limitations
  • Directory Name Format limitations
  • Wide Character (16-bit character) ambiguities

The general design approach used in the Joliet specification is to relax restrictions and resolve ambiguities in the ISO 9660:1988 specification so the practical goals can be met.


Overview

The Joliet specification utilizes the supplementary volume descriptor (SVD) feature of ISO 9660 to specify a set of files recorded within the Unicode character set.

The ISO 10646 character set specification may be identified by an ISO 2022 escape sequence. By recording this escape sequence in an ISO 9660 SVD, this technique for identifying the Unicode SVD is compliant with the ISO 9660 specification. It also retains interchange by not disrupting the files referenced through the primary volume descriptor (PVD).

All that remains is to resolve minor technical ambiguities within ISO 9660 which arise as the result of the use of wide characters.

Because the use of this particular escape sequence in an ISO 9660 SVD is unprecedented up to this time, several of the restrictions which are imposed by ISO 9660 may be relaxed without significantly disrupting information interchange between existing systems from a practical standpoint.

This design approach has several benefits. For instance, the use of the existing ISO 9660 standard allows for straightforward integration with existing extensions to ISO 9660. The designs for the System Use Sharing Protocol, Rock Ridge extensions for POSIX semantics, CD-XA System Use Area Semantics, Apple's Finder Flags and Resource Forks, all port in a straightforward manner to the Joliet specification.

Also, the use of a new SVD eliminates the danger of breaking software compatibility with existing ISO 9660 systems. Existing software will simply ignore the Unicode SVD, and will simply use the PVD instead. This compatibility "safety-valve" makes the goal of relaxing the file system's restrictions easier.

This document describes how a CD-ROM may be constructed so that names on the volume can be recorded in Unicode while remaining in compliance with ISO 9660. The particular ISO 10646 character sets used here are UCS-2 Level 1, UCS-2 Level 2, and UCS-2 Level 3.

The basic strategy of CD-ROM volume recognition is the Volume Recognition Sequence, which is a sequence of volume descriptors, recorded one per sector, starting at Sector 16 in the first track of the last session on the disc. A receiving system reads these sectors and chooses a particular volume descriptor from the sequence. This volume descriptor acts as a kind of anchor upon which the remainder of the volume is constructed.


Terminology and Notation

Joliet is based on the ISO 9660:1988 standard. Unless defined in this document, the terminology used shall be as defined in ISO 9660:1988.

The following notation is used in this document.


Decimal and Hexadecimal Notation

Numbers in decimal notation are represented by decimal digits, namely zero to 9.

Numbers in hexadecimal notation are represented by hexadecimal digits, namely zero to 9 and A to F, shown in parentheses. For instance, the hexadecimal number D0 shall be written as (D0).

A literal sequence of ASCII characters will be represented by those characters within single quotes. For instance, 'ABC' means the byte sequence (41)(42)(43).

References to characters in the ISO 2022 escape sequence will be given in comma-separated decimal nibble/nibble format, in hexadecimal format, and as ASCII characters, with equal signs between each format, all enclosed within parenthesis. For instance, the 3-byte ISO 2022 escape sequence for Shift-JIS is (2/4, 2/11, 3/10 = (24)(2B)(3A) = '$+:').


Joliet Recording Specification

The Joliet specification resolves the following ISO 9660 ambiguities for UCS-2 volumes:

  • Use a SVD with a UCS-2 (UNICODE) Escape Sequence.
  • The UCS-2 escape sequences used are: (25)(2F)(40), (25)(2F)(43), or (25)(2F)(45).
  • The default setting of Bit 0 of the SVD "Volume Flags Field" is zero.
  • The Unicode Wide characters shall be recorded in "Big Endian" (Motorola) format.
  • Special Directory Identifiers are recorded as single byte names containing (00) or (01).
  • SEPARATOR 1 and SEPARATOR 2 are encoded using an equivalent 16-bit code point.
  • Sort ordering is unchanged, except that all justification pad bytes are to be set to (00).

The Joliet specification recommends that several ISO 9660 restrictions be lifted on UCS-2 volumes. The Joliet specification allows for the following interchange rules:

  • The File or Directory Identifiers may be up to 128 bytes (64 unicode characters) in length.
  • Directory Identifiers may contain file name extensions.
  • The Directory Hierarchy may be recorded deeper than 8 levels.
  • The volume recognition sequence supports multisession. This is compatible with the CD-Bridge specification.

The Joliet specification may be extended through the use of the following specifications:

  • Mode 2 Form 2 extents and CD-DA extents, ("System Description CD-ROM XA")
  • System Use Sharing Protocol (not explicitly specified here)
  • RockRidge Interchange Protocol (not explicitly specified here)
  • Other future CD-ROM file system formats


Identifying an ISO 9660 SVD as Unicode (UCS-2)

SVD Escape Sequences Field

The Escape Sequences field of an ISO 9660 Supplementary Volume Descriptor (ISO 9660 Section 8.5.6) shall identify the character set used to interpret descriptor fields related to the Directory Hierarchy identified by the Volume Descriptor.

If the Escape Sequences field of an ISO 9660 SVD identifies any of the following UCS-2 escape sequences, then the descriptor fields related to the Directory Hierarchy identified by that Volume Descriptor shall be interpreted according to the identified UCS-2 character set.

ISO 2022 UCS-2 Escape Sequences

Standard | Level | Decimal | Hex Bytes | ASCII Char Equivalent
UCS-2 | Level 1 | 2/5, 2/15, 4/0 | (25)(2F)(40) | '%\@'
UCS-2 | Level 2 | 2/5, 2/15, 4/3 | (25)(2F)(43) | '%\C'
UCS-2 | Level 3 | 2/5, 2/15, 4/5 | (25)(2F)(45) | '%\E'

A "Unicode Volume" refers to the Volume Descriptor and Directory Hierarchy identified by a Supplementary Volume Descriptor containing an Escape Sequences field which identifies any of the above UCS-2 character sets.

SVD Volume Flags Field

The UCS-2 Level 1, UCS Level 2, and UCS-2 Level 3 escape sequences are considered to be registered according ISO 2735 for purposes of setting Bit 0 of the Volume Flags field of the SVD.

The nominal value of Bit 0 of the Volume Flags field for a Unicode SVD shall be ZERO.


Resolution of ISO 9660 Ambiguities for Wide Characters

This specification resolves ISO 9660 ambiguities with respect to wide (16-bit) character sets, such as the UCS-2 character set.

Wide Character Byte Ordering

All UCS-2 characters shall be recorded according to ISO 9660:1988 Section 7.2.2, 16-bit numerical value, most significant byte first ("Big Endian").

Allowed Character Set

All UCS-2 code points shall be allowed except for the following UCS-2 code points:

All code points between (00)(00) and (00)(1F), inclusive. (Control Characters)

(00)(2A) "*"(Asterisk)

(00)(2F) "/" (Forward Slash)

(00)(3A) ":" (Colon)

(00)(3B) ";" (Semicolon)

(00)(3F) "?" (Question Mark)

(00)(5C) "\" (Backslash)

Special Directory Identifiers

Section 7.6 of ISO 9660 describes the recording of reserved directory identifiers for the root, current, and parent directory identifiers as single (00) or single (01) bytes.

In a wide character set, it is not possible to represent a character in a single byte. The following portions of the ISO 9660:1988 specification referring to reserved directory identifiers are ambiguous.

The ISO 9660:1988 sections in question are as follows:

  • 6.8.2.2 Identification of directories
  • 7.6.2 Reserved Directory Identifiers
  • 9.1.11 File Identifier
  • 9.4.5 Directory Identifier

These special case directory identifiers are not intended to represent characters in a graphic character set. These characters are placeholders, not characters. Therefore, these definitions remain unchanged on a volume recorded in Unicode.

Simply put, Special Directory Identifiers shall remain as 8-bit values, even on a UCS-2 volume, where other characters have been expanded to 16-bits.

Root Directory

The Directory Identifier of a Directory Record describing the Root Directory shall consist of a single (00) byte.

Current Directory

The Directory Identifier of the first Directory Record of each directory shall consist of a single (00) byte.

Parent Directory

The Directory Identifier of the second Directory Record of each directory shall consist of a single (01) byte.

Separator Characters

The separator characters SEPARATOR 1 and SEPARATOR 2 are specified as 8-bit characters, which can not be represented in a wide character set, so the ISO 9660:1988 specification sections referring to SEPARATOR 1 and SEPARATOR 2 are ambiguous. The ISO 9660:1988 sections in question are as follows:

  • 7.4.3 Separators
  • 7.5.1 File Identifier format
  • 7.5.2 File Identifier length
  • 8.4.24 Abstract File Identifier
  • 8.4.25 Bibliographic File Identifier
  • 8.5.17 Copyright File Identifier
  • 8.5.19 Bibliographic File Identifier
  • 9.1.11 File Identifier

The values SEPARATOR 1 and SEPARATOR 2 shall be represented differently depending on the d1 character set.

In the case of an SVD identifying a UCS-2 character set, the values of SEPARATOR 1 and SEPARATOR 2 shall be recorded as a UCS-2 character with an equivalent code point value.

Otherwise, the definitions of SEPARATOR 1 and SEPARATOR 2 shall be recorded according to Section 7.4.3 of ISO 9660:1988.

Simply put, SEPARATOR 1 and SEPARATOR 2 shall be expanded to 16-bits.

Separator Representations

Separator | ISO 9660 1988 Volume Bit Combination | Unicode Volume UCS-2 Codepoint
SEPARATOR 1 | (2E) | (00)(2E)
SEPARATOR 2 | (3B) | (00)(3B)

Sort Ordering

ISO 9660 specifies the order of path table records within a path table, and specifies the order of directory records within a directory. These sorting algorithms assume an 8-bit character set is used. These sorting algorithms are ambiguous when used with wide characters.

The ISO 9660:1988 sections in question are as follows:

  • 6.9.1 Order of Path Table Records
  • 9.3 Order of Directory Records

The only change required is to redefine the value of the sort justification pad byte to zero (00).

Simply put, comparing the byte contents in all positions remains a suitable sorting algorithm for the descriptor fields recorded in a UCS-2 SVD Directory Hierarchy. This is one of the primary reasons for selecting the Big Endian format to represent all UCS-2 characters.

Natural Language Sorting

On a Unicode volume, the 16-bit UCS-2 code points are used to determine the Order of Path Table Records and the Order of Directory Records.

No attempt will be made to provide natural language sorting on the media. Natural language sorting may optionally be provided by a display application as desired.

Justification Pad Bytes

The sort ordering algorithms as specified in ISO 9660:1988 Sections 6.9.1 and 9.3 are acceptable except for the value of the justification "pad byte".

The value of the justification "pad byte" as specified in ISO 9660:1988 Section 6.9.1 shall be (00). This is changed from a value of (20) as specified in that same section.

The value of the justification "pad byte" as specified in ISO 9660:1988 Section 9.3 subsections (a) and (b) shall be (00). This is changed from a value of (20) as specified in those same sections.

The value of the justification "pad byte" as specified in ISO 9660:1988 Section 9.3 subsections (c) shall be (00). This is changed from a value of (30) as specified in that same section.

Simply put, set all the justification "pad bytes" to zero to simplify sorting.

Mandatory Sort Ordering.

Correct sort ordering is mandatory on UCS-2 volumes.

Descriptor Fields affected by the UCS-2 Escape Sequence

If a UCS-2 escape sequence is detected in a supplementary volume descriptor, the following descriptor fields referenced from that supplementary volume descriptor shall contain UCS-2 characters.

ISO 9660:1988 Section 8.5.4 System Identifier

ISO 9660:1988 Section 8.5.5 Volume Identifier

ISO 9660:1988 Section 8.5.13 Volume Set Identifier

ISO 9660:1988 Section 8.5.14 Publisher Identifier

ISO 9660:1988 Section 8.5.15 Data Preparer Identifier

ISO 9660:1988 Section 8.5.16 Application Identifier

ISO 9660:1988 Section 8.5.17 Copyright File Identifier

ISO 9660:1988 Section 8.5.18 Abstract File Identifier (missing section)

ISO 9660:1988 Section 8.5.19 Bibliographic File Identifier

ISO 9660:1988 Section 9.1.11 File Identifier

ISO 9660:1988 Section 9.4.5 Directory Identifier

ISO 9660:1988 Section 9.5.11 System Identifier (of Extended Attribute Record)

Relaxation of ISO 9660 Restrictions on UCS-2 Volumes

Several ISO 9660 restrictions will be relaxed to achieve a more useful recording specification. Joliet receiving systems shall be capable of receiving media recorded with restrictions which have been relaxed relative to ISO 9660.

Maximum File Identifier Length Increased

Joliet receiving systems shall receive directory hierarchies recorded with file identifiers longer than those allowed by ISO 9660 receiving systems.

ISO 9660 (Section 7.5.1) states that the sum of the following shall not exceed 30:

  • If there is a file name, the length of the file name.
  • If there is a file name extension, the length of the file name extension.

On Joliet compliant media, however, the sum as calculated above shall not exceed 128, to allow for longer file identifiers.

The above lengths shall be expressed as a number of bytes.

Maximum Directory Identifier Length Increased

Joliet receiving systems shall receive directory hierarchies recorded with file names longer than those allowed by ISO 9660 receiving systems.

ISO 9660 (Section 7.6.3) states that the length of a directory identifier shall not exceed 31.

On Joliet compliant media, however, the length of a directory identifier shall not exceed 128, to allow for longer directory identifiers.

The above lengths shall be expressed as a number of bytes.

Directory Names May Have File Name Extensions

ISO 9660 does not allow directory identifiers to contain file name extensions.

On Joliet compliant media, however, directory identifiers may contain file name extensions.

The Joliet directory identifier format shall be calculated according to ISO 9660 Section 7.5.1 "File Identifier format", with the exception that the length of a directory identifier may exceed 31, but shall not exceed 128.

In addition, the Joliet directory identifier format shall comply with ISO 9660 Section 7.6.2 "Reserved Directory Identifiers".

The directory identifier length shall be calculated according to ISO 9660 Section 7.5.2 "File Identifier length".

The above lengths shall be expressed as a number of bytes.

Maximum Directory Hierarchy Depth May Exceed 8 Levels

ISO 9660 (Section 6.8.2.1) specifies restrictions regarding the Depth of Directory Hierarchy. This section of ISO 9660 specifies that this number of levels in the hierarchy shall not exceed eight.

On Joliet compliant media, however, the number of levels in the hierarchy may exceed eight.

Joliet compliant media shall comply with the remainder of ISO 9660 Section 6.8.2.1, so that for each file recorded, the sum of the following shall not exceed 240:

  • the length of the file identifier;
  • the length of the directory identifiers of all relevant directories;
  • the number of relevant directories.

The above lengths shall be expressed as a number of bytes.


Extensions to Joliet

Joliet for Multisession Media

Multisession Recordings are Received

When provided with CD-ROM reader hardware with multisession capability, Joliet receiving systems shall receive media recorded using the multisession recording technique.

The details of this technique are provided in the following

Logical Sector Addressing on Multisession Recordings

Each sector on the media is assigned a unique Logical Sector Address.

Logical Sector Addresses zero and above increase linearly across the surface of the disc, regardless of session boundaries.

Logical Sector Address zero references the sector with Minute:Second:Frame address 00:02:00 in the first session. All other Logical Sector Addresses are relative to Minute:Second:Frame address 00:02:00 in the first session.

The conversion between Logical Sector Addresses and Minute:Second:Frame addresses is Logical Sector Address = (((Minute*60)+Seconds)*75) - 150.

Simply put, the Logical Sector Address on a multisession disc describes a flat address space.

Multisession Addressability

The data area for a volume may span multiple sessions.

For example, if a disc is recorded with 3 sessions, the directory hierarchy described by a volume descriptor in session 3 may reference logical sectors recorded in session 1, 2, or 3.

Multisession Volume Recognition Sequence

The Volume Recognition Sequence shall begin at the 16th logical sector of the first track of the last session on the disc.

This volume recognition sequence supersedes all other volume recognition sequences on the disc. The interpretation of the Volume Recognition Sequence is otherwise unchanged.

For example, consider a disc that contains 3 sessions, where session 1 starts at 00:00:00, session 2 starts at 10:00:00, and session 3 starts at 20:00:00. The Volume Recognition Sequence for this disc would start at Minute:Second:Frame address 20:00:16.

This technique is compatible with the CD-Bridge multisession technique.

Track Modes and Sector Forms

The data area for a Joliet volume on a CD-ROM shall be comprised of either Mode 1 or Mode 2 Form 1 sectors. CD-ROM media utilizing the multisession recording techniques outlined above may not contain any Mode 1 sectors anywhere on the media. Mode 1 sectors are allowed only on single-session media.

Mode 2 Form 2 sectors and CD-Digital Audio tracks may be recorded on the same media as a Joliet volume. In this case, the CD-XA extensions to Joliet may be utilized to identify Mode 2 Form 2 extents and CD-Digital Audio extents.

CD-Digital Audio tracks may not be recorded in sessions 2 and higher. If any CD-Digital Audio tracks are recorded, all the CD-Digital Audio tracks shall be recorded in the first session.

CD-XA Extensions to Joliet

CD-ROM discs utilizing the Joliet extensions to ISO 9660 and which also identify mode 2 form 2 extents or CD-Digital Audio extents shall be marked with a CD-ROM XA Label as specified in "System Description CD-XA" Section 2.1.

The CD-ROM XA Label shall be located at offset 1024 (byte position 1025) in the Joliet Supplementary Volume Descriptor. The identifying signature 'CD-XA001' shall be recorded starting at offset 1024 in the Joliet Supplementary Volume Descriptor. This identifying signature is equivalent to the hex bytes (43)(44)(2D)(58)(41)(30)(30)(31).

Mode 2 form 2 extents shall be identified using recording rules outlined in "System Description CD-XA", Section 2.7. In this case, Bit 12 of the Attributes field of the "XA System Use Information" shall be set to one to identify that the file contains mode 2 form 2 sectors. See the following for additional information regarding Data Length.

CD-Digital Audio extents shall be identified using recording rules outlined in "System Description CD-XA", Section 2.7. In this case, Bit 14 of the Attributes field of the "XA System Use Information" shall be set to one to identify that the file is comprised of an extent of CD-Digital Audio. See the following for additional information regarding Data Length.

If a file is marked such that either Bit 12 is set to one or Bit 14 is set to one in the Attributes field of the "XA System Use Information", then the Data Length field of the Directory Record shall be set to 2048 times the number of sectors contained in the extent. See ISO 9660:1988 Section 9.1.4.

Other Extensions to Joliet

The Joliet Extensions to ISO 9660 are designed to coexist with other extensions such as the "System Use Sharing Protocol" and "RockRidge Interchange Protocol". However, these protocols are not an integral part of the Joliet specification.

The method used to integrate these other protocols into Joliet is not defined here.


Bibliography

ISO 2022 - Information processing - ISO 7-bit and 8-bit coded character sets - Code extension techniques, International Organization for Standardization

ISO 9660 - Information processing - Volume and file structure of CD-ROM for information interchange, International Organization for Standardization, 1988-04-15

ISO 10149 : 1989 (E) - Information technology - Data interchange on read-only 120mm optical data discs (CD-ROM) "YellowBook", International Organization for Standardization, 1989-09-01

ISO 10646 - Information technology - Universal Multiple-Octet Coded Character Sets (UCS), International Organization for Standardization,

The Unicode Standard - Worldwide Character Encoding Version 1.0, The Unicode Consortium, Addison-Wesley Publishing Company, Inc., 1990-1991 Unicode, Inc., Volume 1

Orangebook, N. V. Philips and Sony Corporation, November 1990

System Description CD-XA, N. V. Philips and Sony Corporation, March 1991

System Use Sharing Protocol

RockRidge Interchange Protocol Joliet CD-ROM Extensions for Unicode 13


Compression

This part of the Windows® 95 DDK Design and Implementation Guide describes updates to the Microsoft Real-time Compression Interface and the DriveSpace programming interface as they are described in version 6.x of the Microsoft® MS-DOS® Programmer's Reference.


Microsoft Real-time Compression Interface

The Microsoft Real-time Compression Interface (MRCI) is a software interface that gives real-mode applications and device drivers success to compression services. The MRCI has been revised and enhanced for Windows 95. This section provides a summary of the revisions and enhancements.


32-bit Signature Values

A 32-bit MRCI client uses the sigOLD_EDX and sigNEW_EDX signature values to verify that an MRCI server has responded to the Detect MRCI Server (Interrupt 2Fh Function 04A12h) or Detect ROM BIOS MRCI Service (Interrupt 1Ah Function 0B001h) service. A 16-bit MRCI client uses the sigOLD_CX, sigNEW_CX, sigOLD_DX, and sigNEW_DX values.

Note that 32-bit MRCI clients must be virtual devices (VxDs). The Interrupt 2Fh interface is not directly callable from a Win32® application.


Server Capability Flags

Additional flag values have been added to indicate the new capabilities of an MRCI server. These value are returned in the mi_flCapability field of the MRCINFO structure as a result of calling the Detect MRCI Server or Detect ROM BIOS MRCI Server service. The values also double as operation codes that a client passes to the server entry point specified by the mi_pfnOperate field.

There are the following new flag values:

Value | Meaning
micapALTCOMP | Alternate compression
micapALTDECOMP | Alternate decompression
micapMRCI32 | Server has a 32-bit interface
micapSPRCOMP | SuperCompress™ compression


MRCREQUEST Structure

The MRCREQUEST structure has been revised. The mr_Reserved field has changed to mr_offUpdate, which is used for Update compression (micap_UPDCOMP) and Update SuperCompress (micap_SPRCOMP) compression only. When sending a request to a server, the mr_offUpdate field specifies the offset in the source buffer where the changed uncompressed data starts. The server responds to the request by copying, into mr_offUpdate, the offset in the destination buffer where the changed compressed data starts.


Error Values

The MRCI server operation function, pointed to by the mi_pfnOperate field of the MRCINFO structure, can return the following new error values if the requested operation fails:

Value | Meaning
MRCI_ERROR_INVALID_SIZE | Invalid buffer size.
MRCI_ERROR_BUFFER_TOO_SMALL | Work buffer is too small.
MRCI_ERROR_RESTART | Incremental compression was interrupted and must be restarted from the beginning.
MRCI_ERROR_CONTINUE | Incremental compression in not finished but can be continued.


DriveSpace Programming Interface

Microsoft MS-DOS version 6.x introduced the DriveSpace file system, which increases the storage capacity of disk drives by compressing data written to the drive. DriveSpace includes a programming interface that lets disk utility programs examine and manage disk drives containing compressed data. The DriveSpace programming interface is described in the MS-DOS Programmer's Reference for version 6.x. This section describes additional IOCTL functions that have been added to the DriveSpace programming interface for Windows 95.


Raw I/O IOCTL Functions

A client application can use the DriveSpace IOCTL functions (Interrupt 21h Function 4404h) to read and write raw data to a compressed volume. The following new IOCTL functions are provided:

Function letter | Action
r | DSRawRead
w | DSRawWrite

See Also

DSRawRead, DSRawWrite


Raw I/O IOCTL Data Packet

To perform a raw I/O operation, a client application passes a data packet consisting of a header defined by the DSHDR and DSRAWIO structures, followed by an array of RawClusterInfo structures that describe a set of clusters on which to operate. The IOCTL function returns a failure status in the dspResult field of the DSHDR structure if a normal write (that is, any write other than a raw write IOCTL) to the drive has occurred since the most recent previous raw I/O IOCTL. The failure status tells DEFRAG.EXE that its knowledge of the state of the drive may no longer be valid.

See Also

DSHDR, DSRAWIO, RawClusterInfo


Reading Fragmented Clusters

To read a fragmented cluster, the client must know how many sectors, including the fragment header, that the cluster consumes. Because the MDFAT entry gives only the size of the first fragment, the client must either read the fragment header and compute the total sector count, or issue a raw read IOCTL in which the rci_data field of the RawClusterInfo structure is NULL. Raw reads where the rci_pdata field is NULL return no raw data, but they do fill in the other fields in the RawClusterInfo structure. When a fragmented cluster is actually read, the fragmented header is stripped from the data that is returned; that is, the first byte in the data buffer contains the first byte of the cluster's raw data.

See Also

RawClusterInfo


Writing Fragmented Clusters

On version 3.0 CVFs, a client application can use the raw write IOCTL to write a fragmented cluster. To accomplish this, RCFFRAG must be set in the rci_flags field of the RawClusterInfo structure. In addition, the first sector of the data to be written must contain the fragment header exactly as it should appear on this disk. This means that a compressed cluster's data begins immediately following the fragment header in the first sector. An uncompressed cluster's data begins in the second sector of the data. The remainder of the first sector after the fragment header is usually padded with the DWORD value 45544550h. The FRAGHDR structure defines the format of the fragment header:

See Also

FRAGHDR, RawClusterInfo


DriveSpace Functions and Structures

DSRawRead

mov    ax, 4404h             ; IOCTL command
mov    bl, Drive             ; drive number (one-based)
mov    cx, size DataPacket   ; size of data packet
mov    dx, seg DataPacket    ; address of data packet
mov    ds, dx
mov    dx, offset DataPacket
int    21h

jc     error
cmp    DataPacket.dspResult, ; 'OK' ; test for success
jne    failure               ; call failed

Reads raw data from a compressed volume file (CVF) into a buffer.

  • Returns with the carry flag clear and the dspResult of the DSHDR structure set to 'OK' if the function succeeds; otherwise, the carry flag is set and AX contains one of these error values:
Value | Meaning
0001h | ERROR_INVALID_FUNCTION
0005h | ERROR_ACCESS_DENIED
0006h | ERROR_INVALID_HANDLE
000Dh | ERROR_INVALID_DATA

Drive
One-based driver number for a DriveSpace driver (1 = A, 2 = B, and so on). If there is more than one DriveSpace drive, any one of the corresponding drive numbers can be given.
DataPacket
Data packet consisting of a DSHDR structure, a DSRAWIO structure, and an array of RawClusterInfo structures. The dspCommand field of the DSHDR structure must be set to the letter 'R'. The buffer pointed to by the rci_pdata field of the RawClusterInfo structure receives the raw data.

See Also

DSHDR, DSRAWIO, RawClusterInfo

DSRawWrite

mov    ax, 4404h             ; IOCTL command
mov    bl, Drive             ; drive number (one-based)
mov    cx, size DataPacket   ; size of data packet
mov    dx, seg DataPacket    ; address of data packet
mov    ds, dx
mov    dx, offset DataPacket
int    21h

jc     error
cmp    DataPacket.dspResult, ; 'OK' ; test for success
jne    failure               ; call failed

Writes raw data from a buffer into a compressed volume file (CVF).

  • Returns with the carry flag clear and the dspResult of the DSHDR structure set to 'OK' if the function succeeds; otherwise, the carry flag is set and AX contains one of these error values:
Value | Meaning
0001h | ERROR_INVALID_FUNCTION
0005h | ERROR_ACCESS_DENIED
0006h | ERROR_INVALID_HANDLE
000Dh | ERROR_INVALID_DATA

Drive
One-based driver number for a DriveSpace driver (1 = A, 2 = B, and so on). If there is more than one DriveSpace drive, any one of the corresponding drive numbers can be given.
DataPacket
Data packet consisting of a DSHDR structure, a DSRAWIO structure, and an array of RawClusterInfo structures. The dspCommand field of the DSHDR structure must be set to the letter 'W'. The buffer pointed to by the rci_pdata field of the RawClusterInfo structure receives the raw data.

See Also

DSHDR, DSRAWIO, RawClusterInfo

DSHDR

DSHDR STRUC
    dspStamp    dw  ?  ; Identifying stamp ('DM')
    dspCommand  db  ?  ; Command ('R' or 'W')
    dspResult   dw  ?  ; see below
DSHDR ENDS

Defines the portion of the IOCTL header that is common to all DriveSpace Receive Control Data IOCTLs. Notice that WORD alphanumeric constants are shown as they would be defined for MASM. Thus, 'DM' is equivalent to 444Dh, and 'OK' is equivalent to 4B4Fh. When dumped as two consecutive bytes or as a text string, these values would appear as "MD" and "KO" respectively. The dspCommand field is typically an ASCII character. For the raw read IOCTL, dspCommand is set to 'r'; for raw writes, it is set to 'w'.

dsp_result
Can be one of these values:
Value | Meaning
DSRROK ('OK') | Success
DSRRWRITE (0001h) | Intervening write occurred
DSRRLOCK (0002h) | Buffer lock failed
DSRRIO (0003h) | I/O error
DSRRBADCLUS (0004h) | Invalid MDFAT index
DSRRUNALLOC (0005h) | Attempt to read unallocated cluster
DSRRBADSECTOR (0006h) | Bad starting sector
DSRRBADSIZE (0007h) | Bad cluster size
DSRRNOSIZE (0008h) | Uncompressed size unknown
DSRRNOTFREE (0009h) | Some target sectors were not free
DSRRXBOUND (000Ah) | Allocation crosses BitFAT boundary
DSRRNULLPTR (000Bh) | NULL pointer passed to write
DSRRSECCOUNT (000Ch) | Sector count mismatch
DSRRPKTSIZE (000Dh) | Packet size is too small
DSRRDATAWRITE (000Eh) | Data was written
DSRRBADFRAG (000Fh) | Bad fragment table

DSRAWIO

DSRAWIO STRUC
    dsr_hdr        db  SIZE DSHDR dup(?) ; Packet header
    dsr_flags      db  ?     ; Flags
    dsr_cclus      dw  ?     ; Count of clusters to operate on
    dsr_reserved0  dd  0     ; Reserved
    dsr_reserved1  dd  0     ; Reserved
DSRAWIO ENDS

Contains information about a raw I/O IOCTL operation. Immediately precedes an array of RawClusterInfo structures.

dsr_hdr
DSHDR structure that defines the header common to all DriveSpace Receive Control Data IOCTLs.
dsr_flags
Can be DSRFLOCKED (01h) if buffers are locked. Under normal circumstances, this field must be set to zero when the IOCTL is issued.
dsr_cclus
Number of RawClusterInfo structures follow the DSRAWIO structure. This is the same as the number of clusters on which to perform the action.
dsr_reserved0 and dsr_reserved1
Reserved; must be zero.

See Also

RawClusterInfo

RawClusterInfo

RawClusterInfo STRUC
    rci_pdata      dd  ?  ; Pointer to raw cluster data buffer
    rci_isecstart  dd  ?  ; Starting sector in sector heap
    rci_ifat       dw  ?  ; FAT index
    rci_csec       db  ?  ; Count of raw sectors
    rci_flags      db  ?  ; Flags
    rci_reserved   dd  0  ; Reserved
RawClusterInfo ENDS

Contains information used by the raw cluster I/O IOCTLs. All pointers are flat model pointers. The same structure is used for both reads and writes, but the fields are treated somewhat differently.

rci_pdata
Address of the buffer from which data is written or into which data is read. The size of the buffer, in sectors, is specified by rci_csec. The client must always specify a flat address regardless of the client's mode of execution. (For an MS-DOS program, the flat address is simply segment*16 + offset.) The data read or written is raw data; no compression or decompression is applied to the data. Reads return the data as it appears on the disk; writes do not modify the data before writing it to the disk. The address passed in rci_pdata may be valid only in the context of the client thread. For example, for V86 or Win32 clients.
rci_isecstart
Starting sector of the cluster specified by rci_imdfat. On reads, this field is ignored on input and filled with the value from the MDFAT entry before returning to the client. On writes, this field specifies the starting sector at which to write the cluster. A set of writes fails if any of the target sectors are not free, or if any of the target extents overlap.
rci_ifat
FAT index of the target cluster.
rci_csec
Count of sectors that the cluster actually occupies on the disk. On reads, if the actual size of the cluster does not exactly match this value, the read is cancelled.
rci_flags
Receives the values of the specified flags in the MDFAT entry to the client. On writes, this field specifies the settings of the flags for the cluster to be written. Setting RCFMARK on a write to a CVF whose version is less than 3.0 has no effect. The mark bit is intended for the use of the off-line recompressor to prevent it from trying to recompress clusters it either successfully or unsuccessfully recompressed the last time it ran. Raw write is the only means by which this bit can be set, and normal writes to a cluster clear the bit.

The rci_flags field can a combination of these values:
Value | Meaning
RCFMARK (01h) | Marked cluster
RCFFRAG (02h) | Fragmented cluster
RCFUNCOMP (04h) | Uncompressed cluster
RCFALLOC (08h) | Allocated cluster

rci_reserved
Reserved.

FRAGHDR

FRAGHDR STRUC
    fhcFrag    dd  ?         ; Count of fragments
    fhaFrag    dd  ? DUP (?) ; Variable size array of fragment entries
FRAGHDR ENDS

Contains information about fragmented clusters. The first sector of fragmented sections contains a FRAGHDR structure.

The count of sectors stored for each fragment header entry is actually the count of sectors in the fragment minus one. Also, the first entry in fhaFrag describes the first fragment in the cluster, just as the MDFAT entry does.

You can use the following values to retrieve information from a segment entry in the fhaFrag array:

Value | Meaning
FG_SECTORWIDTH (23) | Width of sector number
FG_SECTORSHIFT (0) | Shift sector number to low end
FG_SECTORMASK (((1 SHL FG_SECTORWIDTH) - 1) SHL FG_SECTORSHIFT) | Mask for sector number
FG_RESERVEDWIDTH (3) | Width of reserved bits
FG_RESERVEDSHIFT (FG_SECTORSHIFT + FG_SECTORWIDTH) | Shift reserved bits to low end
FG_RESERVEDMASK (((1 SHL FG_RESERVEDWIDTH) - 1) SHL FG_RESERVEDSHIFT) | Mask for reserved bits
FG_CSECWIDTH (6) | Width of sector count
FG_CSECSHIFT (FG_RESERVEDSHIFT + FG_RESERVEDWIDTH) | Shift sector count to low end
FG_CSECMASK (((1 SHL FG_CSECWIDTH) - 1) SHL FG_CSECSHIFT) | Mask for sector count


Input and Output Supervisor Reference

Input and Output Supervisor Reference describes the services, structures, and functions provided by the Windows® 95 Input and Output Supervisor (IOS).


Services

This section describes the services provided by the IOS.


IOS_BD_Command_Complete

mov esi, IOR  ; address of IOR
VxDCall IOS_BD_Command_Complete

Indicates a command has completed.

  • No return value.
IOR
Address of a IOR structure of completed command

See Also

IOR


IOS_BD_Register_Device

mov edi, BDD  ; BlockDev Device Descriptor
VxDCall IOS_BD_Register_Device
jc error

Registers a BlockDev device.

  • Carry flag is set on error.
BDD
Address of a BlockDev_Device_Descriptor structure.


IOS_Exclusive_Access

mov ah,  Type      ; type of handle
mov eax, DriveNum  ; drive to lock
mov ebx, Handle    ; handle of thread or VM
mov ecx, LockFlag  ; nonzero to lock, zero to unlock
VxDCall IOS_Exclusive_Access
jc error

Locks a given drive for exclusive access from one virtual machine (VM). Works only with DCB_type_floppy devices.

  • Carry flag is set on error.
DriveNum
Zero-based drive number of drive to lock or unlock.
Type
Type of handle specified by Handle. Can be IOSEA_LOCK_THREAD to indicate thread handle or zero to indicate VM handle.
Handle
Handle of thread or VM to receive exclusive access as specified by the Type parameter.
LockFlag
Can be nonzero to lock the given drive, or zero to unlock it.


IOS_Find_Int13_Drive

mov al, UnitNumber  ; int 13h unit number
VxDCall IOS_Find_Int13_Drive
jc error
mov [BDD], edi   ; address of BDD

Returns the BlockDev device descriptor (BDD) for the given INT 13h drive.

  • Returns the address of a BlockDev_Device_Descriptor structure.


IOS_Get_Device_List

VxDCall IOS_Get_Device_List
mov [BDD], edi   ; address of BDD or zero if none

Returns address of the first BlockDev device descriptor (BDD).

  • Returns the address of a BlockDev_Device_Descriptor structure.


IOS_Get_Version

#include <ios.h>

VxDCall IOS_Get_Version
jc  error
mov [Version], eax

Returns version number.

  • Carry flag is set on error.


IOS_Register

VxDCall IOS_Register, <<OFFSET32 DRP>>

Registers an IOS client or driver. The function copies the addresses of the various IOS linkage services to the I/O linkage block (ILB) of the client or driver and initializes structures maintained internally by the IOS.

  • Sets the DRP_reg_result member of the DRP structure.
DRP
Address of a DRP structure that contains information for registering the driver or client.

See Also

DRP, ILB


IOS_Requestor_Service

VxDCall IOS_Requestor_Service, <<OFFSET32 IRS>>

Carries out requested IOS services, such as retrieving information about the devices. If the service is successful, the IOS sets the IRS_result member of the IRS structure to indicate success.

  • No return value.
IRS
Address of an IRS structure that contains the information about the IOS service to carry out.

See Also

IRS


IOS_Send_Next_Command

mov edi, DCB  ; address of Device Descriptor Block
VxDCall IOS_Send_Next_Command

Sends the next command to a device.

  • No return value.
DCB
Address of the DCB structure identifying the device.

See Also

DCB


IOS_SendCommand

mov esi, CmdData  ; address of BCB or IOR
mov edi, DevData  ; address of BDD or DCB
VxDCall IOS_SendCommand

Directs the IOS to carry out a command specified by a BlockDev Command Block (BCB) or an I/O Request (IOR), depending on a given version flag.

  • No return value.
CmdData
Address of a IOR structure if the IOR_flags member is set to IORF_VERSION_002. Otherwise, this parameter is the address of a BlockDev_Command_Block structure.
DevData
Address of a DCB_bdd structure (member of a DCB if the IOR_flags member is set to IORF_VERSION_002. Otherwise, this parameter is the address of a BlockDev_Device_Descriptor structure.

Use of BCBs is provided for backward BlockDev client compatibility.

When passing command data in an IOR structure, the client or driver must set the IOR_vol_designtr, IOR_func, IOR_flags, and possibly IOR_callback members prior to calling the service. If the IORF_SYNC_COMMAND bit is not set, the IOS returns immediately but continues to carry out the I/O request asynchronously. When an asynchronous operation completes or terminates, the IOS notifies the requestor by calling the specified callback procedure (address in the IOR_callback member) and passing on the stack the value contained in IOR_req_req_handle member.

If the IORF_SYNC_COMMAND flag is set, the IOS waits until the I/O request completes or terminates before returning control to the requestor. In this case, the specified callback procedure is never called.

If the IORF_DOUBLE_BUFFER flag is set, the IOS transfers all data through buffers that are managed by the IOS. Clients typically use this flag with I/O requests for which direct DMA to the client's buffer is not possible. This flag may be used with read or write requests only. If the IORF_DOUBLE_BUFFER flag is set, the IOR_sgd_lin_phys member must be set to the 32-bit linear address of an array of scatter/gather descriptors, and the buffer address in each scatter/gather descriptor must also be a 32-bit linear address.

See Also

DCB, IOR


IOS_Set_Async_Time_Out

mov eax, Timeout  ; milliseconds to wait
mov edx, RefData  ; reference data
mov esi, Callback ; address of callback procedure
VxDCall IOS_Set_Async_Time_Out
mov [Result], esi  ; zero if not scheduled, otherwise handle

Same as the VMM service Set_Async_Timeout.

  • Returns the time-out handle if successful; returns zero if the time-out was not scheduled.
Timeout
Number of milliseconds to wait until time-out.
RefData
Reference data to return to the callback procedure.
Callback
Address of procedure to call when time-out occurs.

The callback procedure is called with ecx equal to the number of milliseconds that have elapsed since the actual time-out occurred. Time-outs are often delayed by 10 milliseconds or more since the normal system timer runs at 20 milliseconds or slower. If you need more accurate time-outs, then you must increase the timer interrupt frequency. See the VTD documentation in "Kernel Services" for more details on setting the timer interrupt rate.


IOS_Signal_Semaphore_No_Switch

mov eax, SemHandle ; semaphore handle
VxDCall IOS_Signal_Semaphore_No_Switch

Same as the VMM service Signal_Semaphore_No_Switch.

  • No return value.
SemHandle
Handle of the semaphore to signal.


IOS_Synchronous_Command

VxDCall IOS_Synchronous_Command

Not supported. Do not call.


IOSIdleStatus

VxDCall IOSIdleStatus
mov [Result], eax

Determines whether IOS is idle by walking the IOS heap looking for allocated IOPs. Do not call after allocating an IOP.

  • Returns zero if idle, nonzero otherwise.


IOSMapIORSToI21

mov ecx, ErrorCode  ; IOR error code
VxDCall IOSMapIORSToI21
mov [Int21Err], eax

Maps an IOR error code to its INT 21h equivalent.

  • Returns INT 21h error code.
ErroCode
Can be one the values specified for the IOR_result member of the IOR structure.

See Also

IOR


IOSMapIORSToI24

mov eax, ErrorCode  ; IOR error code
mov ecx, Function   ; IOR function
VxDCall IOSMapIORSToI24
mov [Int24Err], eax

Maps an IOR error code to its INT 24h equivalent.

  • Returns INT 24h error code.
ErrorCode
Can be one the values specified for the IOR_result member of the IOR structure.
Function
Can be one of the values specified for the IOR_func member of the IOR structure.

See Also

IOR


Structures

This section describes the structures used with IOS services and requests.


AEP

#include <aep.h>

typedef struct AEPHDR {
    USHORT AEP_func;       // function; see below
    USHORT AEP_result;     // result; set to zero if successful; see below
    ULONG  AEP_ddb;        // address of DDB
    UCHAR  AEP_lgn;        // current load group number (from DVT)
    UCHAR  AEP_align[3];   // reserved; don't use
} AEPHDR, *PAEPHDR;

Contains information for an asynchronous event function.

AEP_func
Function code. Can be one of these values:
AEP_1_SEC (8) | Notifies driver that one second has elapsed.
AEP_2_SECS (9) | Notifies driver that two seconds have elapsed.
AEP_4_SECS (10) | Notifies driver that four seconds have elapsed.
AEP_ASSOCIATE_DCB (12) | Associates a logical DCB with a physical DCB. Uses AEP_assoc_dcb structure. Sent when the ISP_ASSOCIATE_DCB service is called. A layer driver can specify additional logical volumes that are associated with a particular physical drive that the TSD cannot deduce for itself. These logical volumes need to be present in real mode as well as protected mode.
AEP_BOOT_COMPLETE (2) | Notifies driver to either unload or continue full operation. Uses AEP_boot_done structure. Sent when initialization is complete and at the end of loading, initializing, and registering a port driver. If the driver chooses to unload at this time it should return AEP_FAILURE in AEP_result. This deregisters and unloads the driver. No DDB pointer is passed with this call, so only one call is received. For instance a VSD can return failure if it has determined that it has not inserted itself in any one of the DCBs in the system.
AEP_CONFIG_DCB (3) | Configures physical device. Uses AEP_dcb_config structure. Sent during initialization so that all layer drivers have opportunity to examine the DCBs in the system, both physical and logical, typically created by port drivers. Made when each layer is initialized. Each layer driver can choose to insert itself in the call down list for the DCB if necessary. For example, a driver interested in seeing requests to a CDROM inserts itself in that DCB. A layer driver that satisfies a specific demand that is stipulated in the DCB dmd flags must turn off the demand bit, indicating to the layers above that the demand has been met.
AEP_CREATE_VRP (18) | Notifies driver that a VRP has been created. Uses AEP_vrp_create_destroy structure. Sent when a VRP goes into service, that is, when the IFSMGR determines that a VRP describes a newly mounted volume. VRPs are actually created any time a mount is attempted, but this message is not sent if the mount fails for any reason (among which is ERROR_VOLUME_EXISTS, a successful remount of a volume). The mounted volume must be a parent volume; this call is not issued when child volumes are successfully mounted. This call, made for symmetry with AEP_DESTROY_VRP, is informational only, so any response is ignored.
AEP_DBG_DOT_CMD (11) | Notifies driver of parameters for .I debug command. Uses AEP_dot_command structure. Provides a means for debug "dot" commands entered by the user into the windows system debugger to be propagated to each layer. A layer can easily implement support for a "dot" command without having to directly interface with the debugger. Each layer receives a call for each debug command that begins with ".I". In this call, the AEP_d_c_pkeyword member is a pointer to the subkeyword typed by the user. For example, if the user types ".IXYZ", the subkeyword is "XYZ". The AEP_d_c_key_len member contains the length of this subkeyword. The AEP_d_c_flags member indicates which numeric parameters are present. example, if the user types ".IXYZ 1 46", the flag values AEP_NUM_1_PRES and AEP_NUM_2_PRES are set, and AEP_d_c_num_1 and AEP_d_c_num_2 contain the hexadecimal values 1 and 46, respectively.
AEP_DCB_LOCK (16) | Notifies driver that a logical DCB is about to be locked. Uses AEP_lock_dcb structure. Linked to the IRS_QUERY_VOLUME_LOCK service, this AEP call notifies layer drivers that the IFSMGR is servicing an exclusive volume lock. Sent to all layer drivers to determine whether there are any volumes that are associated with a volume that about to be locked. For example, if a compression driver determines that one of its host volumes is about to be locked, the driver needs to indicate all the compressed volumes associated with the host by setting bits in the AEP_d_l_drives member. This ensures that the IFSMGR will lock all the compressed volumes as well. The layer drivers should stop carrying out any operations (such as caching) that are not appropriate on a locked volume. Also see the AEP_DRIVE_REFRESH call and the AEP_drive_refresh structure.
AEP_DESTROY_VRP (19) | Notifies driver that a VRP has been deleted. Uses AEP_vrp_create_destroy structure. Sent when a VRP "goes out of service", that is, when the IFSMGR determines that the volume and any child volumes associated with the volume have been fully unmounted by the FSD that mounted them. This call is used, for example, by the DBLSPACE VxD to determine when it can dispose of its data structures for a particular set of child volumes. This call is informational only, so any response is ignored.
AEP_DEVICE_INQUIRY (6) Gets device identification data. Uses AEP_inquiry_device structure. Intended for port drivers. The drive fills the DCB_product_id, DCB_vendor_id, DCB_rev_level, and DCB_inquiry_flags members. AEP_result can be set to AEP_NO_INQ_DATA to indicate no inquiry data available or AEP_NO_MORE_DEVICES to indicate that no more devices of this type exist. Your driver typically fills in the DCB_inquiry_flags field to indicate the type of storage device used.

For example, during the device inquiry phase, ESDI_506 (the default driver handling CD-ROM devices) issues an IDE hardware inquiry to the physical device. The returned device type (the first character in the returned Inquiry) is saved in the DCB_inquiry_flags field. IOS looks at the device type in this field to determine how large to make the DCB.

The dcb_inquiry_flags field returns the results of an ATA INQUIRY command. Its first byte contains the device type. There's an IOS routine named IOS_process_device that copies the inquiry DCB into a real DCB. It uses an "inquiry_type_table" to look up the various statistics for the target DCB, including its size. The i_t_scsi_type field listed below is obtained from the DCB_inquiry_flags field:

inquiry_table struc

i_t_scsi_type db ? ; scsi device type code.

i_t_ios_type db ? ; equivalent ios type.

i_t_dcb_size dw ? ; size of dcb for this type.

i_t_count dd ? ; pointer to counter for

; second part of device name.

i_t_sector_size dw ? ; default sector size in bytes.

i_t_sector_shift db ? ; default sector shift.

i_t_q_algo db ? ; queuing algorithm index.

inquiry_table ends

public inquiry_type_table

inquiry_type_table label byte

db SCSI_DASD_TYPE ; dasd (eg magnetic disk)

db DCB_type_disk

dw size DCB_disk

dd offset32 disk_count

dw 512

db 9

db DCB_q_sort

db SCSI_FLOPPY_TYPE ; floppy (removable media)

db DCB_type_floppy

dw size DCB_floppy ; enlarged for 3mode flags

dd offset32 floppy_count

dw 512

db 9

db DCB_q_sort

db REAL_MAPPER_TYPE ; real mode

db DCB_type_disk

dw size DCB_disk

dd offset32 disk_count

dw 512

db 9

db DCB_q_sort

db SCSI_SEQUENTIAL_TYPE ; sequential (eg magnetic

tape)

db DCB_TYPE_TAPE

dw size DCB

dd offset32 tape_count

dw 1

db 0

db DCB_q_fi_fo

db SCSI_PRINTER_TYPE ; printer

db DCB_type_printer

dw size DCB_disk

dd offset32 prnt_count

dw 1

db 0

db DCB_q_fi_fo

db SCSI_PROCESSOR_TYPE ; processor

db DCB_type_processor

dw size DCB

dd offset32 proc_count

dw 1

db 0

db DCB_q_fi_fo

db SCSI_WORM_TYPE ; worm (eg some optical disks)

db DCB_type_worm

dw size DCB

dd offset32 worm_count

dw 1

db 0

db DCB_q_sort

db SCSI_CDROM_TYPE ; cd-rom.

db DCB_type_cdrom

dw size DCB_cdrom

dd offset32 cdrm_count

dw 2048

db 11

db DCB_q_fi_fo

db SCSI_SCANNER_TYPE ; scanner.

db DCB_type_scanner

dw size DCB

dd offset32 scan_count

dw 1

db 0

db DCB_q_fi_fo

db SCSI_OPTICAL_TYPE ; optical memory (eg some

optical disks)

db DCB_type_disk ; treat as type disk

dw size DCB

dd offset32 omem_count

dw 512

db 9

db DCB_q_fi_fo

db SCSI_MEDIACHANGER_TYPE ; media changer

db DCB_type_changer

dw size DCB

dd offset32 juke_count

dw 1

db 0

db DCB_q_fi_fo

inquiry_table_unknown label byte

db 1fh ; unknown

db DCB_type_disk

dw size DCB_disk

dd offset32 unkn_count

dw 1

db 0

db DCB_q_fi_fo

inquiry_type_table_l equ ($-inquiry_type_table)/size inquiry_table

The size of the allocated DCB depends on the returned contents of the DCB_inquiry_flags. Failure to set DCB_inquiry_flags is likely to result in strange failures when the amount of memory allocated for the DCB is smaller than the amount you expect (to accommodate CDROM extensions etc.).
AEP_HALF_SEC (7) | Notifies driver that 1/2 second has elapsed.
AEP_INITIALIZE (0) | Initializes driver and interface. Uses AEP_bi_init structure. Sent during the registration of a layer driver. In the case of a port driver registration, the IOS checks to see if the initialization was successful. If so, the IOS sends an AEP_DEVICE_INQUIRY function to the driver. If the AEP_DEVICE_INQUIRY is successful, the IOS sends an AEP_CONFIG_DCB call to all the layer drivers. It then repeats the AEP_DCB_INQUIRY call. In the case of a SCSI port driver, the IOS makes as many inquiries as is specified in AEP_bi_i_max_target member returned in the AEP_INITIALIZE call. Also in the case of SCSI, the scan order can be specified in the AEP_bi_flags member. If AEP_BI_FL_SCSI_SCAN_DOWN is set, the scanning is done in the reverse order. The driver can also set AEP_BI_FL_SEND_CONFIG_AGAIN in AEP_bi_flags. If this is set, the IOS repeats the whole sequence of AEP_INITIALIZE, AEP_DEVICE_INQUIRY, and AEP_CONFIG_DCB again. This is typically not needed as IOS will call the port driver again if the port driver controls more than one controller. Note that in the case of a non-SCSI port drivers, the IOS sends down as AEP_DEVICE_INQUIRY until the driver sets AEP_NO_MORE_DEVICES in the AEP_result member. If the result of the AEP_DEVICE_INQUIRY is AEP_NO_INQ_DATA, the next location is inquired and there is no config call sent out.
AEP_IOP_TIMEOUT (5) | Notifies driver that time-out member in an IOP has been decremented to zero. Uses AEP_iop_timeout_occurred structure. Once an IOP is issued to the IOS using the IOS_SendCommand service, a 7.5 second timer is started on the IOP (the timer counts in 0.5 second increments). Unless the input and output is done and the IOP is released within 7.5 seconds, this timer goes to zero and all layer drivers are notified using this AEP call. Note that IOS clients using SCSI Passthrough establish the initial IOP_Timer value by setting the SRB's TimeoutValue accordingly.
AEP_MOUNT_NOTIFY (17) | Notifies driver that a volume has been mounted. Uses AEP_mnt_notify structure. Sent when the IFSMGR has successfully mounted a new volume, but before the operation which caused the mount has been completed. Intended to be used by drivers that create child volumes from special files on the volume (for example, a DBLSPACE driver which causes CVFs to appear as volumes). The driver should find such files and prepare them for mounting. Can also be used by other drivers that want to know when a new volume is mounted.
A driver can carry out one of these valid responses: 1. Associate the original volume with a different drive, for example, move the original volume from drive A to drive H. In this case, if the target drive is already in use, IFSMGR attempts to unmount the current volume for that drive. 2. Return a bitmap of child volumes to mount. The low-order bit corresponds to drive A and so forth. For each bit in the bitmap, the IFSMGR will send a mount child volume command to the same FSD that mounted the original volume. The child volumes and their parent (the original volume) share the same VRP; this is the mechanism by which the relationship among the volumes is maintained. 3. Return a bitmap set to zero. The IFSMGR takes no additional action regardless of any change in the drive number.
When moving a volume, either or both the original volume's effective and actual drives may be changed. For example, drive G is the host for DBLSPACE drive E, E and G are swapped (meaning if there were no compressed drive E, G would be known as E), and G is also host for another compressed drive H. E, G, and H are all visible in real mode. The user's first access may touch any of these drives first. Whichever drive letter is used first, G will be the first drive mounted. Thus, the Compressed Volume Manager will respond that the drive's effective name is really G and its actual name is really E.
AEP_PEND_UNCONFIG_DCB (21) | Notifies driver that a DCB is about to be removed. Uses AEP_dcb_unconfig_pend structure. First AEP function sent to a driver when a DCB is being destroyed. Upon receiving this function call, layer drivers are expected to stop and prevent all further input and output to the device.
AEP_REAL_MODE_HANDOFF (13) | Notifies driver that INT 21h vector is about to be hooked by the IFSMGR. Uses AEP_rm_handoff structure. Sent just prior to the INT 21h vector being hooked by the IFSMGR (in response to the IRS_rm_handoff function). Notifies the layer drivers that this is the last chance to carry out INT 21h function calls through MS-DOS.
AEP_REFRESH_DRIVE (20) | Uses AEP_drive_refresh structure. Informs the layer drivers that an exclusive lock on the volume specified in AEP_d_r_drive is being released. At this point, all on disk file system related data structures could have been moved. For more information about exclusive volume locking, see .
AEP_SYSTEM_CRIT_SHUTDOWN (1) | Indicates a system critical shutdown. Uses AEP_sys_crit_shutdown structure. Broadcast to the layer drivers at Sys_Critical_Exit time.
AEP_SYSTEM_SHUTDOWN (14) | Indicates a system shutdown. Uses AEP_sys_shutdown structure. Broadcast to the layer drivers at System_Exit time.
AEP_UNCONFIG_DCB (4) | Removes configuration of physical device. Uses AEP_dcb_unconfig structure. Sent when a DCB is being destroyed. A layer driver can carry out any action necessary to prepare for the removal of the DCB. For example, if the driver has inserted itself into the calldown of the DCB, it can decrement its internal count of DCBs. Layer drivers typically use such an internal count to determine whether they have inserted themselves into any DCBs. This helps the driver determine the appropriate action to take when it receives a subsequent AEP_BOOT_COMPLETE function. Before processing this message, first check the DCB to make sure it is yours.
AEP_UNINITIALIZE (15) | Uninitializes driver and interface. Uses AEP_bi_uninit structure. Broadcast during the process of deallocating a DDB. Port drivers respond by freeing or deallocating any resources that they may have allocated to handle input and output to the corresponding controller. (For port drivers, there is typically one DDB per controller.) For example, a driver should free IRQ and port trappings when it receives this call. Note that the DDB is part of the standard AEP header.

AEP_result
Result Flag. Can be one of these values:
AEP_SUCCESS (0) | No error occurred.
AEP_FAILURE (-1) | Error occurred.
AEP_NO_INQ_DATA | No inquiry data available.
AEP_NO_MORE_DEVICES | No more devices of this type exist.

See Also

DDB


AEP_assoc_dcb

typedef struct AEP_assoc_dcb {
    struct AEPHDR  AEP_a_d_hdr;  // AEP_ASSOCIATE_DCB
    PVOID  AEP_a_d_pdcb;         // address of physical DCB
    ULONG  AEP_a_d_drives;       // bitmap of associated logical drives
} AEP_assoc_dcb, *PAEP_assoc_dcb;

Contains information for an AEP_ASSOCIATE_DCB function.

See Also

AEP


AEP_bi_init

#include <aep.h>

typedef struct AEP_bi_init {
    struct AEPHDR  AEP_bi_i_hdr;   // Standard Header
    ULONG  AEP_bi_reference_data;  // optional value passed in from DRP
    UCHAR  AEP_bi_flags;           // flags; see below
    CHAR   AEP_bi_i_max_target;    // max scsi target id
    CHAR   AEP_bi_i_max_lun;       // max scsi lun
    ULONG  AEP_bi_i_dcb;           // init DCB for port drivers
    PVOID  AEP_bi_i_hdevnode;      // handle to devnode for this adapter
    PVOID  AEP_bi_i_regkey;        // registry key for this adapter
    UCHAR  AEP_bi_i_align[1];      // reserved; don't use
} AEP_bi_init, *PAEP_bi_init;

Contains information for an AEP_INITIALIZE function.

AEP_bi_flags
Flags. Can be one of these values:
AEP_BI_FL_SCSI_SCAN_DOWN (0x01) | Device requires reverse ID scanning.
AEP_BI_FL_SEND_CONFIG_AGAIN (0x02) | Device wants this configuration information again. If this is set, IOS reexecutes the entire sequence of AEP_INITIALIZE, AEP_INQUIRE, and AEP_CONFIG. This is typically not needed since IOS calls the port driver again if the port driver controls more than one controller.

See Also

AEP, DRP, DCB


AEP_bi_uninit

typedef struct AEP_bi_uninit {
    struct AEPHDR  AEP_bi_u_hdr;  // Standard Header
} AEP_bi_uninit, *PAEP_bi_uninit;

Contains information for an AEP_UNINITIALIZE function.

See Also

AEP


AEP_boot_done

#include <aep.h>

typedef struct AEP_boot_done {
    struct AEPHDR  AEP_b_d_hdr;  // AEP_BOOT_COMPLETE
} AEP_boot_done, *PAEP_boot_done;

Contains information for an AEP_BOOT_COMPLETE function.

See Also

AEP


AEP_dcb_config

typedef struct AEP_dcb_config {
    struct AEPHDR  AEP_d_c_hdr;  // Standard Header
    ULONG  AEP_d_c_dcb;          // 32-bit ptr to DCB
} AEP_dcb_config, *PAEP_dcb_config;

Contains information for an AEP_CONFIG_DCB function.

See Also

AEP, DCB


AEP_dcb_unconfig

typedef struct AEP_dcb_unconfig {
    struct AEPHDR  AEP_d_u_hdr;  // Standard Header
    ULONG  AEP_d_u_dcb;          // 32-bit offset of DCB
} AEP_dcb_unconfig, *PAEP_dcb_unconfig;

Contains information for an AEP_UNCONFIG_DCB function.

See Also

AEP, DCB


AEP_dcb_unconfig_pend

typedef struct AEP_dcb_unconfig_pend { /* */
    struct AEPHDR  AEP_d_u_p_hdr;  // AEP_PEND_UNCONFIG_DCB
    ULONG  AEP_d_u_p_dcb;          // 32-bit offset of DCB
} AEP_dcb_unconfig_pend, *PAEP_dcb_unconfig_pend;

Contains information for an AEP_PEND_UNCONFIG_DCB function.

See Also

AEP, DCB


AEP_dot_command

#include <aep.h>

typedef struct AEP_dot_command { /* */
    struct AEPHDR  AEP_i_t_o_hdr;  // Standard Header
    UCHAR  AEP_d_c_flags;     // flags; see below
    PVOID  AEP_d_c_pkeyword;  // address of keyword string; see below
    UCHAR  AEP_d_c_key_len;   // length of keyword; see below
    ULONG  AEP_d_c_num_1;     // first numeric parameter
    ULONG  AEP_d_c_num_2;     // second numeric parameter
    ULONG  AEP_d_c_num_3;     // third numeric parameter
} AEP_dot_command, *PAEP_dot_command;

Contains information for a AEP_DBG_DOT_CMD function.

AEP_d_c_flags
Flags. Can be one of these values:
AEP_D_C_NUM_1_PRES (0x01) | Numeric parameter 1 is present.
AEP_D_C_NUM_2_PRES (0x02) | Numeric parameter 2 is present.
AEP_D_C_NUM_3_PRES (0x04) | Numeric parameter 3 is present.

AEP_d_c_pkeyword
Address of a string specifying the command keyword.
AEP_d_c_key_len
Length in bytes of the keyword string. The length cannot exceed MAX_DOT_CMD_KEYWORD_SIZE.

See Also

AEP


AEP_drive_refresh

typedef struct AEP_drive_refresh {
    struct AEPHDR  AEP_d_r_hdr;  // AEP_REFRESH_DRIVE
    ULONG  AEP_d_r_drive;        // drive number
} AEP_drive_refresh, *PAEP_drive_refresh;

Contains information for an AEP_REFRESH_DRIVE function.

See Also

AEP


AEP_inquiry_device

#include <aep.h>

typedef struct AEP_inquiry_device {
    struct AEPHDR  AEP_i_d_hdr;  // Standard Header
    ULONG  AEP_i_d_dcb;          // address of DCB
} AEP_inquiry_device, *PAEP_inquiry_device;

Contains information for a AEP_DEVICE_INQUIRY function.

See Also

DCB, AEP


AEP_iop_timeout_occurred

#include <aep.h>

typedef struct AEP_iop_timeout_occurred {
    struct AEPHDR  AEP_i_t_o_hdr;  // Standard Header
    ULONG  AEP_i_t_o_iop;          // address of IOP that timed out
} AEP_iop_timeout_occurred, *PAEP_iop_timeout_occurred;

Contains information for a AEP_IOP_TIMEOUT function.

See Also

AEP, IOP


AEP_lock_dcb

typedef struct AEP_lock_dcb {
    struct AEPHDR  AEP_d_l_hdr;  // AEP_DCB_LOCK
    PVOID  AEP_d_l_pdcb;         // address of logical DCB
    ULONG  AEP_d_l_drives;    // bitmap of logical drives
    UCHAR  AEP_d_l_designtr;  // designator
    UCHAR  AEP_d_l_align[3];  // reserved; don't use
} AEP_lock_dcb, *PAEP_lock_dcb;

Contains information for a AEP_DCB_LOCK function.

See Also

AEP, DCB


AEP_mnt_notify

typedef struct AEP_mnt_notify {
    struct AEPHDR  AEP_m_n_hdr;  // AEP_MOUNT_NOTIFY
    PVOID  AEP_m_n_pvrp;         // VRP of drive
    ULONG  AEP_m_n_drivemap;     // bitmap of child volumes
    ULONG  AEP_m_n_drive;        // drive number of drive just mounted
    ULONG  AEP_m_n_effective_drive;  // effective drive number
    ULONG  AEP_m_n_actual_drive;     // actual drive number
} AEP_mnt_notify, *PAEP_mnt_notify;

Contains information for an AEP_MOUNT_NOTIFY function.

See Also

AEP, VRP


AEP_rm_handoff

typedef struct AEP_rm_handoff {
    struct AEPHDR  AEP_r_m_h_hdr;  // AEP_REAL_MODE_HANDOFF
} AEP_rm_handoff, *PAEP_rm_handoff;

Contains information for an AEP_REAL_MODE_HANDOFF function.

See Also

AEP


AEP_sys_crit_shutdown

typedef struct AEP_sys_crit_shutdown {
    struct AEPHDR  AEP_s_c_s_hdr;  // AEP_SYSTEM_CRIT_SHUTDOWN
} AEP_sys_crit_shutdown, *PAEP_sys_crit_shutdown;

Contains information for an AEP_SYSTEM_CRIT_SHUTDOWN function.

See Also

AEP


AEP_sys_shutdown

typedef struct AEP_sys_shutdown {
    struct AEPHDR  AEP_s_s_hdr;  // AEP_SYSTEM_SHUTDOWN
} AEP_sys_shutdown, *PAEP_sys_shutdown;

Contains information for an AEP_SYSTEM_SHUTDOWN function.

See Also

AEP


AEP_vrp_create_destroy

typedef struct AEP_vrp_create_destroy {
    struct AEPHDR  AEP_v_cd_hdr;   // AEP_CREATE_VRP or AEP_DESTROY_VRP
    PVOID  AEP_v_cd_pvrp;          // address of VRP
    ULONG  AEP_v_cd_drive;         // drive number
} AEP_vrp_create_destroy, *PAEP_vrp_create_destroy;

Contains information for AEP_CREATE_VRP and AEP_DESTROY_VRP functions.


DCB

#include <dcb.h>

typedef struct  _DCB {
    DCB_COMMON  DCB_cmn;              // common information
    ULONG  DCB_max_xfer_len;          // maximum transfer length

// Actual geometry data (as seen below the TSD)
    ULONG  DCB_actual_sector_cnt[2];  // number of sectors
    ULONG  DCB_actual_blk_size;       // actual block size of the device
    ULONG  DCB_actual_head_cnt;       // number of heads
    ULONG  DCB_actual_cyl_cnt;        // number of cylinders
    ULONG  DCB_actual_spt;            // number of sectors per track

    PVOID  DCB_next_ddb_dcb;          // link to next DCB on DDB chain
    PVOID  DCB_dev_node;              // address of dev node for device
    BYTE   DCB_bus_type;              // Bus type; see below
    BYTE   DCB_bus_number;            // channel (cable) within adapter
    UCHAR  DCB_queue_freeze;          // queue freeze depth counter
    UCHAR  DCB_max_sg_elements;       // max # s/g elements; see below

// Volume tracking layer use only
    UCHAR  DCB_io_pend_count;         // # of pending requests for DCB
    UCHAR  DCB_lock_count;            // # of LOCK MEDIA commands

// SCSI
    USHORT DCB_SCSI_VSD_FLAGS;        // Flags for SRB builder
    BYTE   DCB_scsi_target_id;        // SCSI target ID
    BYTE   DCB_scsi_lun;              // SCSI logical unit number
    BYTE   DCB_scsi_hba;              // prot-driver-relative adapter #
    BYTE   DCB_max_sense_data_len;    // Maximum sense length
    USHORT DCB_srb_ext_size;          // miniport srb extension length

    BYTE   DCB_inquiry_flags[8];      // Device inquiry flags
    BYTE   DCB_vendor_id[8];          // Vendor ID string
    BYTE   DCB_product_id[16];        // Product ID string
    BYTE   DCB_rev_level[4];          // Product revision level
    BYTE   DCB_port_name[8];          //
    UCHAR  DCB_current_unit;          // current unit #; see below

// Volume tracking layer use only
    ULONG  DCB_blocked_iop;           // address of requests for an
                                      //  inactive volume

    ULONG  DCB_vol_unlock_timer;      // unlock timer handle
    UCHAR  DCB_access_timer;          // time measure between accesses

// Volume tracking layer use only
    UCHAR  DCB_Vol_Flags;             // Volume tracking; see below

    BYTE  DCB_q_algo;                 // algorithm index; see below
    BYTE  DCB_unit_on_ctl;            // zero-based device number on ctlr
    ULONG  DCB_Port_Specific;         // bytes for port driver use
    ULONG  DCB_spindown_timer;        // timer for drive spin down

    DCB_BLOCKDEV  DCB_bdd;
} DCB, *PDCB;

Contains device control block information for physical devices.

DCB_bus_type
Bus type. Can be one of these values:
DCB_BUS_ESDI | ESDI BUS
DCB_BUS_SCSI | SCSI BUS
DCB_BUS_NEC | NEC BUS
DCB_BUS_SMART | SMART BUS
DCB_BUS_ABIOS | ABIOS BUS

DCB_max_sg_elements
Maximum number of scatter/gather elements. This value is set initially by the port driver, but may be more restrictively updated by other layer drivers.
DCB_current_unit
Used to emulate multiple logical devices with a single physical device.
DCB_vol_flags
Volume tracking flags. Can be one of these values:
DCB_VF_INHIBIT_LOCKING | Indicates locking is temporarily inhibited
DCB_VF_INHIBIT_IO | Indicates I/O is temporarily inhibited (event scheduled in volume tracker).
DCB_VF_INHIBIT_GEOM_RECOMPUTE | Indicates geometry recompute is temporarily inhibited.
DCB_VF_UNLOCK_SCHED | Indicates unlock event is scheduled.
DCB_VF_NEED_PHYS_RECOMP | Indicates that a mapper drive needs a compute geometry request sent to the physical drive with same number as the given logical drive.
DCB_VF_PROT_NEC_DRIVE | Indicates that this DCB has a corresponding protected mode physical NEC driver.

DCB_q_algo
Queuing algorithm index. Can be one of these values:
DCB_q_fi_fo | First in, first out.
DCB_q_sort | Special algorithm for disk.

See Also

DCB_COMMON, DCB_BLOCKDEV


DCB_BLOCKDEV

typedef struct  _DCB_BLOCKDEV {
    ULONG  DCB_BDD_Next;
    BYTE   DCB_BDD_BD_Major_Version;    // INIT <BDD_BD_Major_Ver>
    BYTE   DCB_BDD_BD_Minor_Version;    // INIT <BDD_BD_Minor_Ver>
    BYTE   DCB_BDD_Device_SubType;
    BYTE   DCB_BDD_Int_13h_Number;
    ULONG  DCB_BDD_flags;               // was BDD_Flags
    ULONG  DCB_BDD_Name_Ptr;

// Apparent geometry as seen by TSD and above
    ULONG  DCB_apparent_sector_cnt[2];  // # of sectors
    ULONG  DCB_apparent_blk_size;       // blk size of device
    ULONG  DCB_apparent_head_cnt;       // # of heads
    ULONG  DCB_apparent_cyl_cnt;        // # of cylinders
    ULONG  DCB_apparent_spt;            // # of secs/trk

    ULONG  DCB_BDD_Sync_Cmd_Proc;
    ULONG  DCB_BDD_Command_Proc;
    ULONG  DCB_BDD_Hw_Int_Proc;         // INIT <0>
    ULONG  DCB_BDP_Cmd_Queue_Ascending;
    ULONG  DCB_BDP_Cmd_Queue_Descending;
    ULONG  DCB_BDP_Current_Flags;
    ULONG  DCB_BDP_Int13_Param_Ptr;
    ULONG  DCB_BDP_Current_Command;
    ULONG  DCB_BDP_Current_Position[2];
    ULONG  DCB_BDP_Reserved[5];
    ULONG  DCB_fastdisk_bdd;            // set for DCBs created when a
                                        // fastdisk regs with the
                                        // blockdev BDD for it. Else 0.
} DCB_BLOCKDEV, *PDCB_BLOCKDEV;

Contains block device information. The initial set of members in this structure should not be re-ordered or modified in any way as the offset and the size of members must match those in BLOCKDEV.H for compatibility.


DCB_cd_entry

#include <dcb.h>

typedef struct  _DCB_cd_entry { /* */
    PVOID  DCB_cd_io_address;   // address of request routine
    ULONG  DCB_cd_flags;        // demand bits; see below
    ULONG  DCB_cd_ddb;          // driver's DDB pointer
    ULONG  DCB_cd_next;         // address of next cd entry
    USHORT DCB_cd_expan_off;    // offset of expansion area
    UCHAR  DCB_cd_layer_flags;  // flags for layer's use
    UCHAR  DCB_cd_lgn;          // load group number
} DCB_cd_entry, *pDCB_cd_entry;

Contains information about a calldown entry.

DCB_cd_flags
Can be one of these values:
DCB_dmd_srb_cdb | There must be an SRB and CDB for each IOR.
DCB_dmd_rsrv_1 | Reserved; must be zero.
DCB_dmd_logical | Media address must be logical and DCB must be for a logical device.
DCB_dmd_physical | Media adresses must be physical and DCB must be for a physical device.
DCB_dmd_small_memory | Data buffers must reside in in low 16M.
DCB_dmd_rsrv_2 | Reserved; must be zero.
DCB_dmd_rsrv_3 | Reserved; must be zero.
DCB_dmd_rsrv_4 | Reserved; must be zero.
DCB_dmd_not_512 | Sector size on the media is not 512 bytes.
DCB_dmd_word_align | Data buffers must be word aligned (see ILB_int_io_criteria_rtn).
DCB_dmd_dword_align | Data buffers must be doubleword aligned (see ILB_int_io_criteria_rtn).
DCB_dmd_phys_sgd | Scatter/gather descriptors must contain physical addresses (they will contain linear addresses if this demand bit is not set).
DCB_dmd_phys_sgd_ptr | Do not use (keep this bit clear). Originally intended for use in ILB_int_io_criteria_rtn.
DCB_dmd_do_a_b_toggling | For single floppy drive system, voltrack needs to do the toggling between A and B when accesses are made to these drive letters.
DCB_dmd_query_remov | Lower level must be called to check if media is removeable/has changed.
DCB_dmd_request_sns | Port driver cannot perform SCSI autosense.
DCB_dmd_lock_unlock_media | Media supports software locking.
DCB_dmd_load_eject_media | Media supports electronic eject.
DCB_dmd_clear_media_chg | Command to clear media change.
DCB_dmd_serialize | Layer requires request serialization.
DCB_dmd_prot_mode | Override real mode checks for this device; for example, ATAPI cdrom.
DCB_dmd_no_xclusive | Indicates exclusive access is not required for abs write.
DCB_dmd_pageability | Indicates that access to this volume can cause paging.
DCB_dmd_preload (0x00800000) (OSR2) Allows a "preload driver" access to a port driver's DCB before the port driver sees the DCB (via IOS_Register). Set this bit in your driver when you insert yourself into the calldown chain for a device. This flag was added to correct a bug in IOS.VXD in the retail version of Windows 95, where DRP_FC_NEED_PRELOAD did not work correctly. It occurs specifically on bus-mastering IDE controllers and SCSI controllers. The problem has been fixed in OSR2, and a fixed version of IOS.VXD is also available from our Web site (go to Error! Reference source not found. and search for IOSUPD.EXE).You will need to either use this fixed version of IOS, or run on OSR2 or a newer version of Windows 95/98, when using DCB_dmd_preload.

The basic problem is that IOS will wipe out the demand flags for a DCB when a preload driver inserts itself into the calldown chain for that DCB. This isn't a real problem for something like a standard IDE controller, which does not set any demand flags. It is a problem for SCSI controllers, particularly those that do bus-mastering, since the DCB's demand flags are used to indicate that the device requires physical addresses, etc.

See Also

IOR


DCB_COMMON

#include <dcb.h>

typedef struct  _DCB_COMMON {
    ULONG  DCB_physical_dcb;        // DCB for physical device
    ULONG  DCB_expansion_length;    // expansion length; see below
    PVOID  DCB_ptr_cd;              // address of calldown list
    ULONG  DCB_next_dcb;            // link to next DCB
    ULONG  DCB_next_logical_dcb;    // address of next logical dcb
    BYTE   DCB_drive_lttr_equiv;    // drive number; see below
    BYTE   DCB_unit_number;         // drive or unit #; see below
    USHORT DCB_TSD_Flags;           // TSD flags; see below

// Volume Tracking
    ULONG  DCB_vrp_ptr;             // address of VRP for this DCB
    ULONG  DCB_dmd_flags;           // demand bits; see below
    ULONG  DCB_device_flags;        // general purpose flags; see below
    ULONG  DCB_device_flags2;       // general purpose flags; see below
    ULONG  DCB_Partition_Start;     // partition start sector
    ULONG  DCB_track_table_ptr;     // address of track table buffer
                                    //  for ioctls
    ULONG  DCB_bds_ptr;             // DOS BDS corresp. to this DCB
                                    //  (logical DCB's only)
    ULONG  DCB_Reserved1;           // reserved; must be zero
    ULONG  DCB_Reserved2;           // reserved; must be zero
    BYTE   DCB_apparent_blk_shift;  // log of apparent_blk_size
    BYTE   DCB_partition_type;      // partition type
    USHORT DCB_sig;                 // padding and signature
    BYTE   DCB_device_type;         // device type; see below
    ULONG  DCB_Exclusive_VM;        // exclusive access handle
    UCHAR  DCB_disk_bpb_flags;      // BPB flags; see below
    UCHAR  DCB_cAssoc;              // # of assoc. logical drives
    UCHAR  DCB_Sstor_Host;          // indicates a sstor host volume
    USHORT DCB_user_drvlet;         // userdriveletter settings or 0xff
    USHORT DCB_Reserved3;           // reserved; must be zero
    ULONG  DCB_Reserved4;           // reserved; must be zero
} DCB_COMMON, *PDCB_COMMON;

Contains device control block information that is common to logical and physical devices.

DCB_expansion_length
Total length of IOP extension as filled in by the IOS. This excludes the size of the IOP size.
DCB_drive_lttr_equiv
Drive number. Can be zero for A, 1 for B, and so on. Set up during logical device associate processing.
DCB_unit_number
Either physical drive number (sequential drive number with high bit set) or unit number within TSD. May be set up for disk physical, disk logical DCB, or CD-ROM physical DCBs.
DCB_TSD_Flags
Flags for the TSD. Can be a combination of these values:
DCB_TSD_INVALID_PARTITION | Don't trust the BPB.
DCB_TSD_BAD_MBR | Bad master boot record; physical device only.
DCB_TSD_USER_LETTERS_CHECKED | User drive letters checked.
DCB_TSD_FIRST_USER_CHECK | User drive letters checked first time.
DCB_TSD_BID_SET_GEOM | All geometry set by BID.
DCB_TSD_USER_SET | User set the a drive letter range.
DCB_TSD_NO_USER_INT13 | User INT 13h disabled.
DCB_TSD_PROTMODE_INT_13 | Proteceted-mode only INT 13h.
DCB_TSD_MBPB_PBR | Recommend BPB set from PBR by TSD from INT 41h or INT 46h.
DCB_TSD_RBPB_INIT | Recommend BPB initialized by TSD.
DCB_TSD_MBPB_INIT | Media BPB initialized by TSD.
DCB_TSD_APPARENT_PBR | Apparent set from primary PBR by TSD.
DCB_TSD_APPARENT_ROM | Apparent set from ROM data by TSD.
DCB_TSD_ACTUAL_SET | Actual set from apparent by TSD.
DCB_TSD_ACTUAL_PRE_SET | Actual geometry set prior to TSD.
DCB_TSD_APPARENT_PRE_SET | Apparent geometry set prior to TSD.

DCB_dmd_flags
Demand flags for the topmost layer. Can be a combination of these values:
DCB_device_flags
General purpose flags. Can be a combination of these values:
DCB_DEV_SPINDOWN_SUPPORTED | Indicates drive supports spindown command.
DCB_DEV_SPUN_DOWN | Indicates drive is currently spun down.
DCB_DEV_IO_ACTIVE | Port driver use only. Indicates I/O has been received for this DCB.
DCB_DEV_INT13_CONFIGURED | This device has been configured as an INT 13h drive.
DCB_DEV_NO_ASPICAM | This DCB cannot handle ASPI or CAM requests.
DCB_DEV_REMOVAL_PENDING | Device is going away soon.
DCB_DEV_RMM_INT13 | Logical drives for this INT 13h device are controlled by the mapper.
DCB_DEV_TSD_PROCESSED | Device has been processed by a TSD.
DCB_DEV_SINGLE_FLOPPY | Equivalent to IRS_DRV_SINGLE_FLOPPY. Indicates that the dmd_a_b_toggling is not set in the floppy DCB.
DCB_DEV_REAL_MODE | Device must be controlled by a real mode driver, and should not be taken over in protected mode.
DCB_DEV_QUE_DESCEND | Current queuing direction is descending. Used by port drivers or IOS if DCB_SERIAL_CMD flag is set.
DCB_DEV_MEDIA_CHANGED | Hardware indicated media change.
DCB_DEV_INVALID_GEOM | Indicates the disk geometry has become invalid.
DCB_DEV_INHIBIT_SW_TIMED_SUPPORT | Inhibits the volume tracking layer from carrying out the 2 second timing actions for media change. This bit is typically set if DCB_DEV_SYNC_MED_CHG_SUPPORT is set. Drive is in read only mode.
DCB_DEV_ASYNC_MED_CHG_SUPPORT | Drive has hardware support to indicate by interrupt that disk door has been opened.
DCB_DEV_SYNC_MED_CHG_SUPPORT | Drive has hardware support to indicate media change; first access of the drive after a media changed returns an error.
DCB_DEV_PHYSICAL | Physical device.
DCB_DEV_LOGICAL | Logical device.
DCB_DEV_RMM | Real mode mapper DCB.
DCB_DEV_UNCERTAIN_MEDIA | Media may have been changed.
DCB_DEV_ROM_CFG_REQ | TSD must use ROM chain data.
DCB_DEV_MUST_CONFIGURE | Set at create DCB time and cleared after all layer drivers receive the AEP_CONFIG_DCB function for this DCB.
DCB_DEV_SSTOR_VOL | Set if this is SSTOR volume.
DCB_DEV_PAGING_DEVICE | Indicates that the paging drive is on this DCB.
DCB_CHAR_DEVICE | Indicates that this is a character device.
DCB_DEV_I13_IN_PROGRESS | Used in conjunction with RMM and the global DCB. Set when an INT 13h is in progress and cleared when the INT 13h is complete.
DCB_DEV_CACHE | BDF_CACHE
DCB_DEV_SERIAL_CMD | BDF_Serial_Cmd
DCB_DEV_REMOTE | BDF_Remote
DCB_DEV_REMOVABLE | BDF_Removable
DCB_DEV_WRITEABLE | BDF_Writeable
DCB_DEV_INT13_DRIVE | BDF_Int13_Drive

DCB_device_flags2
General purpose flags. Can be a combination of these values:
DCB_DEV2_THREAD_LOCK (1)
DCB_DEV2_ATAPI_DEVICE (2)
DCB_DEV2_DMF_DISK (4) | Indicates current media is DMF
DCB_DEV2_I13_COPY_PROT (8) | Indicates INT 13h copy protection access to one of the floppies.
DCB_DEV2_FAIL_FORMAT | Indicates that we cannot allow format
DCB_DEV2_FLOPTICAL | Indicates device is floptical
DCB_DEV2_IDE_FLOPTICAL (0x40) | (OSR2) indicates device is IDE floptical

Device type. Can be one of these values:
DCB_type_disk | All Direct Access Devices -- non-removable
DCB_type_tape | Sequencial Access Devices
DCB_type_printer | Printer Device
DCB_type_processor | Processor type device
DCB_type_worm | Write Once Read Many Device
DCB_type_cdrom | CD ROM Device
DCB_type_scanner | Scanner Device
DCB_type_optical_memory | Some Optical disk
DCB_type_changer | Changer device; for example, juke box
DCB_type_comm | Communication devices
DCB_type_floppy | Devices like floppy
DCB_type_optical_nec | NEC 5.25" optical disk

DCB_disk_bpb_flags
Can be zero or this value:
DCBF_DISK_BPB_USEFAKE Used in DISKTSD when handling the SetDeviceParameters IOCTL (Interrupt 21 Function 440Dh Minor Code 40h) to indicate the need to synthesize the BPB

See Also

DCB, DCB_cd_entry, IOS, IOP, VRP


DDB

#include <ddb.h>

typedef struct DDB { //
    ULONG  DDB_phys_addr;      // Physical address of ddb
    ULONG  DDB_Next_DDB;       // next DDB on DVT_DDB chain
    ULONG  DDB_Next_DDB_init;  // next DDB on DVT_DDB_init chain
    ULONG  DDB_dcb_ptr;        // address of first DCB owned by this DDB
    UCHAR  DDB_number_buses;   // # of buses supported by the adapter
    UCHAR  DDB_ios_flags;      // IOS flags; see below
    USHORT DDB_sig;            // DDB signature; also padding
    PVOID  DDB_dvt;            // address of this DDB's DVT
    PVOID  DDB_devnode_ptr;    // address of devnode for device
    PVOID  DDB_reserved;       // reserved; must be zero
} DDB , *pDDB;

Contains information about the device data block.

DDB_ios_flags
Private flags for the IOS. Non-IOS components must treat these as read-only. Can be a combination of these values:
DDB_IOS_FL_PENDING_REMOVAL
DDB_IOS_FL_PAGE_ALLOCED
DDB_IOS_FL_FIRST_ENUM_DONE_BIT
DDB_IOS_FL_PLEASE_DESTROY

See Also

DCB, DVT


DRP

#include <drp.h>

typedef struct DRP {
    CHAR   DRP_eyecatch_str[8];  // eye catcher string
    ULONG  DRP_LGN;              // load group number; see below
    PVOID  DRP_aer;              // addr of asynchronous event routine
    PVOID  DRP_ilb;              // address of ILB; see below
    CHAR   DRP_ascii_name[16];   // driver name; see below
    BYTE   DRP_revision;         // driver revision
    ULONG  DRP_feature_code;     // feature code; see below
    USHORT DRP_if_requirements;  // I/F requirements; see below
    UCHAR  DRP_bus_type;         // type of I/O bus; see below
    USHORT DRP_reg_result;       // registration result; see below
    ULONG  DRP_reference_data;   // data to pass with AEP_INITIALIZE
    UCHAR  DRP_reserved1[2];     // reserved
    ULONG  DRP_reserved2[1];     // reserved; must be zero
} DRP, *PDRP;

Contains driver registration packet information.

DRP_eyecatch_str
Eye catcher string. Must be "XXXXXXXX".
DRP_LGN
Load group mask for the driver. Can be a combination of these values:
DRP_IFS | Reserved for IFSMGR.
DRP_FSD | Installable file system layer.
DRP_FSD_EXT_1 | FSD extension, for example, DBLSPACE.
DRP_FSD_EXT_2 | FSD extension, for example, encryption.
DRP_VOLTRK | Post-volume tracking value added driver.
DRP_CLASS_DRV | Class driver.
DRP_TSD | Type specific driver (TSD).
DRP_VSD_1 | Driver is in vendor enhancement layer 1.
DRP_VSD_2 | Driver is in vendor enhancement layer 2.
DRP_VSD_3 | Driver is in vendor enhancement layer 3.
DRP_SCSI_LAYER | SCSI-izer.
DRP_VSD_4 | Driver is in vendor enhancement layer 4.
DRP_VSD_5 | Driver is in vendor enhancement layer 5.
DRP_VSD_6 | Driver is in vendor enhancement layer 6.
DRP_VSD_7 | Driver is in vendor enhancement layer 7.
DRP_VSD_8 | Driver is in vendor enhancement layer 8.
DRP_VSD_9 | Driver is in vendor enhancement layer 9.
DRP_MISC_PD | Other port drivers.
DRP_NT_MPD | SCSI miniport drivers.
DRP_NT_PD | Windows NT/2000, hardware-independent port driver.
DRP_ESDI_PD | ESDI port driver.
DRP_ESDIEMUL_PD | Port drivers for ESDI emulators.
DRP_ABIOS_PD | ABIOS port driver.
DRP_ABIOS_PREMPT_PD | ABIOS pre-empting port drivers.
DRP_NEC_FLOPPY | NEC floppy driver layer.
DRP_SOC_SER_DRV | Socket service drivers.
DRP_SOC_DRV | Socket drivers.
DRP_IOS_REG | Reserved for IOS registry.

All other values are reserved and must not be used.

DRP_ilb
Virtual address of the ILB structure that receives IOS linkage information.
DRP_ascii_name
16-byte string specifying the name of the driver.
DRP_feature_code
Feature code; must match the feature code in the DVT. Can be a combination of these values:
DRP_FC_SCAN_DOWN | BIOS scans targets from high to low.
DRP_FC_IO_FOR_INQ_AEP | Port driver needs to send I/O through IOP in response to an AEP_DEVICE_INQUIRY function. Results in AEP_CONFIG_DCB function for inquiry DCB.
DRP_FC_HALF_SEC | Notify driver every half second.
DRP_FC_1_SEC | Notify driver every second.
DRP_FC_2_SECS | Notify driver every two seconds.
DRP_FC_4_SECS | Notify driver every four seconds.
DRP_FC_DYNALOAD | Driver was dynamically loaded by IOS.
DRP_FC_NEED_PRELOAD | Driver needs to hook I/O even before the port driver. When set, the AEP_CONFIG_DCB function is received before the port driver. (NOTE: See DCB_dmd_preload flag, which corrects a DRP_FC_NEED_PRELOAD bug)
DRP_FC_NEED_PRE_POST_LOAD | Same as DRP_FC_NEED_PRELOAD except the drive will receive 2 AEP_CONFIG_DCB function calls for each DCB: one call before the port driver, and another after layers before its load group have been initialized. Note that care must be taken not to insert twice into the same DCB.

DRP_if_requirements
I/F requirements. Can be one of these values:
DRP_IF_ISA | Driver supports ISA platforms.
DRP_IF_EISA | Driver supports EISA platforms.
DRP_IF_MCA | Driver supports MCA platforms.
DRP_IF_STD | Driver supports all standard platforms.

DRP_bus_type
Type of I/O bus if port driver. Can be one of these values:
DRP_BT_ESDI | ESDI or ESDI emulator.
DRP_BT_SCSI | SCSI or SCSI emulator.
DRP_BT_FLOPPY | NEC FLOPPY or FLOPPY emulator.
DRP_BT_SMART | Smart device.
DRP_BT_ABIOS | ABIOS or ABIOS emulator.

DRP_reg_result
Registration result. Can be one of these values:
DRP_REMAIN_RESIDENT | Driver should remain resident.
DRP_MINIMIZE | Driver should minimize.
DRP_ABORT | Driver should not load.
DRP_INVALID_LAYER | Bad layer number; abort driver.

DRP_reference_data
Data to pass with subsequent AEP_INITIALIZE functions.

See Also

IOS_Register, AEP


DVT

#include <dvt.h>

typedef struct DVT {
    USHORT DVT_reserved_1;       // reserved for expansion to 32 bit
    ULONG  DVT_next_dvt;         // 16-bit offset to next DVT
    USHORT DVT_device_cnt;       // count of devices added/accepted
    PVOID  DVT_aer;              // addr of driver's async event routine
    ULONG  DVT_ddb;              // first DDB for this DVT
    ULONG  DVT_ddb_init;         // first DDB for this DVT/ICE
    CHAR   DVT_ascii_name[16];   // driver name
    CHAR   DVT_create_date[8];   // creation date
    CHAR   DVT_create_time[8];   // creation time
    CHAR   DVT_rev_level[4];     // revision level
    ULONG  DVT_feature_code;     // feature code
    USHORT DVT_if_requirements;  // i/f requirements
    BYTE   DVT_bus_type;         // I/O bus type; see below
    ULONG  DVT_reference_data;   // data passed in DRP upon reg
    CHAR   DVT_first_drive;      // unit number of first drive valid
                                 //  only for block devices
    CHAR   DVT_current_lgn;      // current load group number
    ULONG  DVT_LoadHandle;       // contains the VxD's load handle if
                                 //  we loaded the driver else zero
    CHAR   DVT_scsi_max_target;  // max target supported for SCSI
    CHAR   DVT_scsi_max_lun;     // max LUN supported for SCSI
    PVOID  DVT_entry_point;      // entry point into driver
                                 //  SCSI miniport only
    UCHAR  DVT_init_count;       // # of successful AEP_INITIALIZE calls
                                 //  port drivers only
    PVOID  DVT_reserved[2];      // reserved; must be zero
} _DVT;

Contains driver vector table information. The IOS creates a DVT structure for itself and then one for each driver during registration. The IOS's DVT provides a link to the first driver via the DVT_next_dvt member. The first driver can access the second driver's DVT via its DVT_next_dvt offset, and so on, providing a linked chain between the drivers' DVTs. Many of the members are set using values from the DRP structure provided by the driver.

DVT_bus_type
Input and output bus type. Can be one of these values:
DVT_BT_ESDI | ESDI or ESDI emulator
DVT_BT_SCSI | SCSI or SCSI emulator
DVT_BT_FLOPPY | NEC FLOPPY or FLOPPY emulator
DVT_BT_SMART | Smart device
DVT_BT_ABIOS | ABIOS or ABIOS emulator

DVT_feature_code
Feature code; must match the feature code in the DRP. Can be a combination of these values:
DVT_FC_SCAN_DOWN | BIOS scans targets from high to low.
DVT_FC_IO_FOR_INQ_AEP | Port driver needs to send I/O through IOP in response to an AEP_DEVICE_INQUIRY function. Results in AEP_CONFIG_DCB function for inquiry DCB.
DVT_FC_HALF_SEC | Notify driver every half second.
DVT_FC_1_SEC | Notify driver every second.
DVT_FC_2_SECS | Notify driver every two seconds.
DVT_FC_4_SECS | Notify driver every four seconds.
DVT_FC_DYNALOAD | Driver was dynaloaded by the IOS.
DVT_FC_NEED_PRELOAD | Driver needs to hook I/O even before the port driver. When set, the AEP_CONFIG_DCB function is received before the prot driver.
DVT_FC_NEED_PRE_POST_LOAD | Same as DVT_FC_NEED_PRELOAD except that the driver receives two AEP_CONFIG_DCB calls for each DCB: one call before the port driver, and another call after layer drivers before its load group have been initialized. Note that care must be taken not to insert twice in the same DCB.

See Also

DRP, AEP


ILB

#include <ilb.h>

typedef struct ILB {
    PFNISP ILB_service_rtn;          // addr of service routine; see below
    PVOID  ILB_dprintf_rtn;          // addr of dprintf routine; see below
    PVOID  ILB_Wait_10th_Sec;        // addr of wait routine; see below
    PVOID  ILB_internal_request;     // addr of request routine; see below
    PVOID  ILB_io_criteria_rtn;      // addr of IOR criteria routine
    PVOID  ILB_int_io_criteria_rtn;  // addr of IOP criteria routine
    ULONG  ILB_dvt;                  // offset to addr of driver's DVT
    ULONG  ILB_ios_mem_virt;         // addr of IOS memory pool; see below
    ULONG  ILB_enqueue_iop;          // addr of enqueue routine; see below
    ULONG  ILB_dequeue_iop;          // addr of dequeue routine
    ULONG  ILB_reserved_1;           // reserved; must be zero
    ULONG  ILB_reserved_2;           // reserved; must be zero
    USHORT ILB_flags;                //flags; see below
    CHAR   ILB_driver_numb;          // number of calls to AEP_INITIALIZE
    CHAR   ILB_reserved_3;           // reserved; must be zero
} ILB, *PILB;

Contains information about IOS linkage for a driver.

ILB_service_rtn
Address of IOS service routine.
ILB_dprintf_rtn
Address of IOS dprintf routine. Available only in debugging versions of the IOS.
ILB_Wait_10th_Sec
Address of CPU spin wait routine.
ILB_internal_request
Address of the internal I/O request routine.
ILB_io_criteria_rtn
Address of the IOR-criteria routine.
ILB_int_io_criteria_rtn
Address of the IOP-criteria routine.
ILB_ios_mem_virt
Address of IOS memory pool. This memory contains IOS internal structures, such as the IDA structure.
ILB_enqueue_iop
Address of the IOP enqueue routine.
ILB_dequeue_iop
Address of the IOP dequeue routine.
ILB_flags
.
ILB_driver_numb
Number of times the driver has been called with an AEP_INITIALIZE function.

See Also

DRP


ILB_dequeue_iop

cCall [ilb.ILB_dequeue_iop], <<OFFSET32 DCB>>
mov [IOP], eax  ; address of next IOP in queue

Removes an IOP from the current queue, whether descending or ascending. If removing the IOP leaves the queue empty, the routine makes the other queue current. Uses the ECX, EDX, and Flags registers.

  • Returns the address of the next IOP in the queue or returns zero if both queues are empty.
DCB
Address of a physical DCB structure.

See Also

ILB


ILB_dprintf_rtn

cCall [ilb.ILB_dprintf_rtn],<<OFFSET32 szFormat>, val1, ...>

Displays information on the debug terminal, providing a subset of the formatting provded by the C-runtime printf function. The function processes the given string, converting format control sequences in the string to characters or numbers, using the corresponding values passed as parameters.

  • No return value.
szFormat
Address of a null-terminated string. The string can contain any printable characters and any combination of the following format control sequences:
%b | Displays an 8-bit value as a hexadecimal integer. Must pass a doubleword value with the value to display in the low byte.
%c | Displays the character at the given address. Must pass a valid, 32-bit address.
%d | Displays the corresponding 32-bit value as a decimal integer. Must pass a doubleword value.
%e | Displays the corresponding 32-bit value as a hexadecimal integer. Must pass a doubleword value.
%i | Displays a 16-bit value as an unsigned decimal integer. Must pass a doubleword value with the value to display in the low word.
%j | Displays an 8-bit value as a unsigned decimal integer. Must pass a doubleword value with the value to display in the low byte.
%lx | Displays the 32-bit value at the given address as a hexadecimal integer. Must pass a valid, 32-bit address.
%p | Displays the given address in 16:16 (segment:offset) notation. Segment and offset values are displayed as hexadecimal integers.
%s | Displays the null-terminated string at the given address. Must pass a valid, 32-bit address.
%u | Displays the 16-bit value at the given address as an unsigned decimal integer. Must pass a valid, 32-bit address.
%w | Displays a 16-bit value as a hexadecimal integer. Must pass a doubleword value with the value to display in the low word.
%x | Displays the 16-bit value at the given address as a hexadecimal integer. Must pass a valid, 32-bit address.
%z | Displays a memory dump, consisting of a given number of bytes display as hexadecimal integers. Must pass a 16-bit value specifying the number of bytes to display and a valid, 32-bit address pointing to the bytes to display.
%% Displays the percent character (%).

val1
Value or address, depending on the corresponding format control sequence. Except for the %z format, there must be one 32-bit value passed for each format control sequence in the string. For %z, two 32-bit values must be passed.

See Also

ILB


ILB_enqueue_iop

cCall [ilb.ILB_enqueue_iop],<<OFFSET32 IOP>, <OFFSET32 DCB>>

Places the given IOP in the IOP queue. The position of the IOP depends on the queuing algorithm specified by the DCB_q_algo member. Uses EAX, ECX, EDX, and Flags registers.

  • No return value.
IOP
Address of the IOP structure to place in the queue.
DCB
Address of a physical DCB structure.

See Also

ILB


ILB_int_io_criteria_rtn

cCall [ilb.ILB_int_io_criteria_rtn],<<OFFSET32 IOP>>
or  eax, eax
jnz error

This service is used by IOS layer drivers located within the IOS layered driver hierarchy. IOS clients should use ILB_io_criteria_rtn instead.

The service ensures that total transfer count does not exceed the maximum allowed, checks for too many logical SGDs (Scatter-Gather Descriptors), and optionally audits linear buffer start addresses and buffer lengths for WORD or DWORD alignment.

If this service has been so requested, it will generate a list of physical SGD's into memory pointed to by IOR_sgd_lin_phys. It will work from either a single linear address (IORF_SCATTER_GATHER=FALSE) or from a linear scatter-gather list (IORF_SCATTER_GATHER=TRUE).

The physical SGD conversion service is performed by calling the _CopyPageTable function to obtain the list of page table entries (PTEs) corresponding to the linear address space(s) specified. Next, the service routine attempts to concatenate PTEs whose physical addresses are contiguous, into a single physical SGD if possible. The maximum allowed size of each physical SGD is 65535 bytes; this limit will be observed while concatenating physical SGDs. If processing of the linear address space(s) results in too many physical SGDs being created (IOR_num_sgds becomes greater than the smaller of 17 or DCB_max_sg_elements), the io_criteria routine reports an error. This service fails if any linear buffer (pointed to by IOR_buffer_ptr or the SGD field BD_SG_Buffer_Ptr) being processed is larger than 512K.

A successful call is indicated if the EAX register returns zero.

The following table lists the fields used by this service.

Table 1. Fields used by ILB_io_criteria_rtn:

Field | Usage | Purpose
DCB_apparent_blk_shift | Read | See IOR_flags & IORF_CHAR_COMMAND
DCB_device_flags & DCB_DEV_RMM | Read | If FALSE, uses physical DCB pointer (pDCB = pDCB->physical_dcb). If TRUE, uses logical (original) DCB.
DCB_dmd_flags & DCB_dmd_dword_align | Read | If this demand flag is set, criteria routine will verify that DWORD alignment of the I/O buffer is being adhered to.
DCB_dmd_flags & DCB_dmd_phys_sgd | Read | If set, criteria routine will attempt to create a list of up to 17 physical SGDs.
DCB_dmd_flags & DCB_dmd_phys_sgd_ptr | Read | This demand flag (originally intended to cause the IOR_sgd_lin_phys address to be a physical address instead of a linear address) is currently not implemented; do not set this bit, to avoid unpredictable results.
DCB_dmd_flags & DCB_dmd_word_align | Read | If this demand flag is set, criteria routine will verify that word alignment of the I/O buffer is being adhered to.
DCB_max_sg_elements | Read | See IOR_flags & IORF_SCATTER_GATHER.
DCB_max_xfer_len | Read | This is always a byte count. Used to audit IOR_xfer_count
DCB_physical_dcb | Read | Used to access the DCB; except if an RMM device, the IOP_original_DCB is used.
IOP_original_dcb | Read | Used to obtain pointer to logical DCB
IOR_buffer_ptr | Read | Points to either a linear buffer space, unless IORF_SCATTER_GATHER is set, in which case it points to a list of linear (logical) scatter-gather descriptors.
IOR_flags & IORF_CHAR_COMMAND | Read | If FALSE, the count specified in IOR_xfer_count is a block count, and must be shifted left by DCB_apparent_blk_shift to indicate the byte count
IOR_flags & IORF_IO_TOO_BIG | Write | Set if IOR_xfer_count is too long (this bit is tested after the criteria routine fails)
IOR_flags & IORF_PHYS_SGDS | Write | Set by criteria routine to indicate that the physical sgd (IOR_sgd_lin_phys) list was successfully set up.
IOR_flags & IORF_SCATTER_GATHER | Read | If set, criteria routine audits the actual number of logical SGD's pointed to by IOR_buffer_ptr, against the legal maximum, which is DCB_max_sg_elements.
IOR_func | Read | If IOR_func == IOR_SCSI_PASS_THROUGH, and IORF_SCATTER_GATHER==FALSE, the io_criteria routine will allow a "misaligned" address or count to succeed. For example, a count of 7 (odd) will actually succeed if the DCB_dmd_word_align bit is set and the start address is even. This is done to accommodate ASPI requests for example.
IOR_ios_private_1 & IOS_PR_FL_MAYBE_BAD_ALIGN | Read/ Write | Used as a temporary variable within the io_criteria routine.
IOR_num_sgds | Write | If DCB_dmd_phys_sgd is TRUE, the criteria routine will fill in this field to provide you with the number of physical SGD elements in IOR_sgd_lin_phys.
IOR_sgd_lin_phys | Read | Points to the physical scatter/gather descriptor list area. If DCB_dmd_phys_sgd is TRUE, the criteria routine will fill in this list to provide you with up to 17 physical addresses of the scatter-gather blocks.
IOR_xfer_count | Read | If IORF_SCATTER_GATHER=FALSE, this field contains the IOR_buffer_ptr's block or byte count; this count is audited by the criteria routine.

A successful call returns (zero). A nonzero value indicates an error. If an error occurs, use the following table to help pinpoint the cause of the error:

Table 2. ILB_io_criteria_rtn error conditions

IOP state before the io_criteria routine is called | Error condition description | Other indicators returned by io_criteria when error exit occurs
IORF_SCATTER_GATHER = TRUE, and dmd_dword_align or dmd_word_align demand flag(s) are TRUE | Either the start address or length of any of the linear scatter-gather descriptors failed the WORD or DWORD alignment check. Alignment checking is NOT performed if physical SGDs are requested and only one physical SGD is produced (since all adapters which have restrictions only have them for multiple SGDs) | None.
IORF_SCATTER_GATHER = FALSE, and dmd_dword_align or dmd_word_align demand flag(s) are TRUE | Either the start address (IOR_buffer_ptr) or length (IOR_xfer_count) failed the WORD or DWORD alignment check. Alignment checking is NOT performed if IOR_func = IOR_SCSI_PASS_THROUGH (such as in an ASPI request) | None.
 | The total transfer count (IOR_xfer_count; shifted left by DCB_apparent_blk_shift if IORF_CHAR_COMMAND is FALSE) is greater than DCB_max_xfer_len | IOR_flags bit IORF_IO_TOO_BIG is set to TRUE. This generally indicates to IOS that it must perform double buffering (breaking the transfer into smaller chunks).
DCB_dmd_phys_sgd = FALSE, and IORF_SCATTER_GATHER = TRUE | The number of logical SGDs set up (at IOR_buffer_ptr) is greater than DCB_max_sg_elements | None.
DCB_dmd_phys_sgd = TRUE | The total transfer count (IOR_xfer_count; shifted left by DCB_apparent_blk_shift if IORF_CHAR_COMMAND is FALSE) is greater than 512 * 1024 (512K) | IOR_flags bit IORF_IO_TOO_BIG is set to TRUE.
DCB_dmd_phys_sgd = TRUE | The number of physical SGDs that the io_criteria routine created from the logical (linear) SGDs is greater than 17 or greater than DCB_max_sg_elements | IOR_flags bit IORF_IO_TOO_BIG is set to TRUE. IOR_num_sgds contains the offending count.

See Also

ILB, IOP


ILB_internal_request

mov edi, offset32 IOP  ; address of IOP
mov ebx, offset32 DCB  ; address of logical or physical DCB
mov edx, vector        ; address of a calldown request routine
                       ;   or zero
call [ilb.ILB_internal_request]

Passes the given I/O request to a driver in the calldown chain. A device driver uses this routine to send I/O requests though the calldown chain without calling the IOS_SendCommand service. The driver can either send the I/O request to the driver at the next layer in the chain or to the top of the chain.

  • No return value.
IOP
Address of the IOP structure to pass through the calldown chain.
DCB
Address of a logical or physical DCB structure that contains the address of the calldown list.
vector
Address of the current I/O request routine or zero. If an address, the routine calls next driver in the calldown chain. If vector is zero, the routine calls the first driver in the chain.

See Also

ILB


ILB_io_criteria_rtn

cCall [ilb.ILB_io_criteria_rtn],<<OFFSET32 IOR>>
or  eax, eax
jnz error

This service performs the same function as the ILB_int_io_criteria_rtn routine, except it is used by IOS clients, above the layered hierarchy of the IOS, such as VFAT. ILB_int_io_criteria_rtn obtains a pointer to the DCB using the IOP_original_DCB field, while ILB_io_criteria_rtn obtains its DCB pointer from the VRP_device_handle field located in the VRP structure pointed to by the IOR_req_vol_handle field.

See Also

ILB, IOR


ILB_service_rtn

cCall [ilb.ILB_service_rtn],<<OFFSET32 ISP>>

Carries out the task specified by the ISP structure. A device driver or client uses this routine to carry out tasks such as allocating memory for an IOP structure.

  • No return value.
ISP
Address of the ISP structure that contains information about the task to carry out. For more information about the possible tasks, see the ISP structure.

See Also

ILB


ILB_Wait_10th_Sec

cCall [ilb.ILB_Wait_10th_Sec]

Waits for 1/10th second before returning. This routine has no parameters.

  • No return value.

See Also

ILB


IOP

#include <iop.h>

typedef struct _IOP {
    ULONG IOP_physical;        // physical address of IOP
    ULONG IOP_physical_dcb;    // address of physical DCB
    ULONG IOP_original_dcb;    // address of DCB designated by IOR
    USHORT IOP_timer;          // Request Control Block (RCB) current
                               //   timeout value
    USHORT IOP_timer_orig;     // original timeout value
    ULONG IOP_calldown_ptr;    // address of next calldown routine
    ULONG IOP_callback_ptr;    // address of current callback address
    ULONG IOP_voltrk_private;  // for use by volume tracking
    ULONG IOP_Thread_Handle;   // handle of thread originating
                               //   the I/O request
    ULONG IOP_VM_Handle        // handle of the Volume Manager
                               //   originating the I/O request.
                               //   Initialized in
                               //   <k>IOS_SendCommand</k>.
    ULONG IOP_srb;             // used by SCSI-izers to pass SRB
                               //   address to next layer
    ULONG IOP_reserved[2];     // reserved; must be zero
    IOP_callback_entry IOP_callback_table[IOP_CALLBACK_TABLE_DEPTH];
                               // RCB_CallBackTable
    BYTE  IOP_format_head;     // low level format data
    BYTE  IOP_format_xfer_rate;
    USHORT IOP_format_track;
    ULONG IOP_format_num_sectors;
    IOR IOP_ior;               // I/O request descriptor
} IOP, *pIOP;

Contains information about an I/O request.

See Also

IOR


IOR

#include <ior.h>

typedef struct _IOR {
    ULONG  IOR_next;            // client link; see below
    USHORT IOR_func;            // function; see below
    USHORT IOR_status;          // request status; see below
    ULONG  IOR_flags;           // request flags; see below
    CMDCPLT IOR_callback;       // address of callback; see below
    ULONG  IOR_start_addr[2];   // starting address; see below
    ULONG  IOR_xfer_count;      // # of sectors/bytes; see below
    ULONG  IOR_buffer_ptr;      // client buffer; see below
    ULONG  IOR_private_client;  // BlockDev/IOS client reserved
    ULONG  IOR_private_IOS;     // reserved space for IOS
    ULONG  IOR_private_port;    // private area for port driver
    union  urequestor_usage _ureq;  // requestor usage; see below
    ULONG  IOR_req_req_handle;  // request handle; see below
    ULONG  IOR_req_vol_handle;  // media handle; see below
    ULONG  IOR_sgd_lin_phys;    // first physical SGD; see below
    UCHAR  IOR_num_sgds;        // number of physical SGDs
    UCHAR  IOR_vol_designtr;    // drive letter; see below
    USHORT IOR_ios_private_1;   // reserved by IOS to force alignment
    ULONG  IOR_reserved_2[2];   // reserved for internal use
} IOR, *PIOR;

Contains information about an I/O request.

IOR_next
Client link for BCBs. Must be zero if IOR_flags is set to IORF_VERSION_002.
IOR_func
I/O request function. Can be one of these values:
IOR_READ | Reads the number of sectors/bytes as specified in IOR_xfer_count.
IOR_WRITE | Writes the number of sectors/bytes as specified in IOR_xfer_count.
IOR_VERIFY | Verifies the number of sectors/bytes as specified in IOR_xfer_count.
IOR_CANCEL | NOT SUPPORTED. Cancels the specified IOR.
IOR_WRITEV | Writes and verifies the number of sectors/bytes as specified in IOR_xfer_count. Some hardware (IDE, for example) does not support this function.
IOR_MEDIA_CHECK | Obsolete. Use IOR_MEDIA_CHECK_RESET instead. (Checks to see if media has changed, and returns status in IOR_status.)
IOR_MEDIA_CHECK_RESET | Checks to see if media has changed, and returns status in IOR_status.
IOR_LOAD_MEDIA | Performs a LOAD MEDIA operation on removable drives.
IOR_EJECT_MEDIA | Performs an EJECT MEDIA operation on removable drives. For disk and CD-ROM devices, applications are queried before eject, and the lock count is checked for zero. If one of these checks fails, the user is queried to see if he wants to proceed.
IOR_LOCK_MEDIA | Performs a LOCK MEDIA operation on removable drives. LOCK and UNLOCK MEDIA calls must be synchronized, as a depth counter is maintained by the IOS.
IOR_UNLOCK_MEDIA | Performs an UNLOCK MEDIA operation on removable drives. LOCK and UNLOCK MEDIA calls must be synchronized, as a depth counter is maintained by IOS. UNLOCK MEDIA is delayed by about 5 seconds.
IOR_REQUEST_SENSE | Performs REQUEST SENSE operation on removable drives. Currently supported for SCSI devices only.
IOR_COMPUTE_GEOM | Results in a reexamination of volume and device characteristics. When this command is received, each IOS layer assumes the device has changed, and performs whatever initialization required. For example, the disk TSD will reexamine the partitions of a device.
IOR_GEN_IOCTL | Function permits device-specific IOCTLs to be issued to IOS drivers. Standard 16-bit, MS-DOS IOCTLs (INT 21h Function 44xx) are supported, but 32-bit IOCTLs are not yet defined. For 16-bit IOCTLs, IOR_flags is set to IORF_16BIT_IOCTL and members of sdeffsd_req_usage structure in _ureq member are defined in the following. Note that macros are defined that provide an alias reference to these members. The macro names are equivalent to the member names listed in the following, with the leading underscore omitted. For example, _ureq.sdeffsd_req_usage._IOR_ioctl_drive can be referenced with the macro IOR_ioctl_drive.

_IOR_ioctl_drive | Input. 1-based drive number or device handle (from BX register)
_IOR_ioctl_function | Input. Function number (from AX register)
_IOR_ioctl_control_param | Input. Function parameter zero-extended to 32 bits (from CX register)
_IOR_ioctl_buffer_ptr | Input. Address of buffer, mapped to flat address (from DS:DX register)
_IOR_ioctl_client_params | Input. Address of additional parameters passed in from the caller. The IORF_16BIT_IOCTL flag must be used to determine the structure type. If it is a 16-bit IOCTL, the pointer will be to the CLIENT_REGS structure.
_IOR_ioctl_return | Output. Return value to be mapped to the IOCTL caller upon exit.
_IOR_ioctl_buffer_length | Output. Size of buffer pointed to by _IOR_ioctl_buffer_ptr. Not used by INT 21h Function 440Dh IOCTL calls.

IOR_FORMAT | Allows issuance of a low-level format packet as defined in the INT 13h specification. The IOR_format_address_field (same as IOR_sgd_lin_phys) member contains the low level sector map. See the IOP_format_* members of the IOP structure for additional information.
IOR_SCSI_PASS_THROUGH | Each layer passes this request down with modification to the SCSI port driver. The IOR must contain a pointer to a valid SRB. Also, the EBX register must point to the BDD portion of the DCB when IOS_SendCommand is called with a passthrough request.
IOR_CLEAR_QUEUE | Callback of request; indicates all requests issued prior to this request have been completed.
IOR_DOS_RESET | Issued in response to an INT 13h reset by the INT 13h VxD. Currently used only by and for the IOS floppy driver.
IOR_SCSI_REQUEST | A generic function that indicates the request is for SCSI. The SRB member in the IOR must be valid. Normally used by IOS layers to send internal requests to SCSI devices.
IOR_SET_WRITE_STATUS | Results in the correct setting of DCB_DEV_WRITABLE flag in the DCB if SUCCESS status is returned. Currently only supported by the IOS floppy driver. The IOS floppy driver must set or clear the DCB_DEV_WRITABLE bit in the physical DCB, and associated logical DCBs as applicable.
IOR_RESTART_QUEUE | A placeholder function that results in restarting of the queue provided by the IOS queuing services. Has no other effect. Should be sent after the DCB_QUEUE_FREEZE field has been decremented to zero.
IOR_ABORT_QUEUE | Causes each layer to call back each queued request with status of IORS_CANCELED.
IOR_SPIN_DOWN | Causes the specified drive to be spun down.
IOR_SPIN_UP | Causes the specified drive to be spun up.
IOR_FLUSH_DRIVE | Causes layer drivers to flush out dirty data. This is a synchronous function and should not be called at event/interrupt time.
IOR_FLUSH_DRIVE_AND_DISCARD | Causes layer drivers to flush out dirty data and then discard cached data. This is a synchronous function and should not be called at event/interrupt time.
IOR_FSD_EXT | Sends private command from an IOS client to the FSD extension layer (DRP_FSD_EXT_1 or DRP_FSD_EXT_2) such as a Compressed Volume Manager (CVM). This call is similar in intent and usage to IOR_GEN_IOCTL; however, it can be used in the swapper path, so, in general, the handling driver should not touch pageable code or data.

Not all drivers support all functions.

IOR_status
Status value. The function sets this member to IORS_SUCCESS (0) if it is successful. Otherwise, it sets the member to one of these values:
IORS_BIG_IO_BREAKUP_FAILED | Attempt to split big I/O failed.
IORS_BUSY | Device is busy.
IORS_CANCELED | Command was canceled.
IORS_CMD_IN_PROGRESS | Command is in progress, and can't be canceled.
IORS_DEVICE_ERROR | Error on recalib. drive, etc.
IORS_ERROR_DESIGNTR | Error occurred.
IORS_HW_FAILURE | General hardware failure.
IORS_ILLEGAL_ACCESS_MODE | CD-ROM read on audio or attempt play on data.
IORS_INVALID_CMD_PTR | Cancel of an invalid command.
IORS_INVALID_COMMAND | Command not supported or invalid.
IORS_INVALID_PARM | Invalid parameter.
IORS_INVALID_SECTOR | Old blockdev error code for requests on an invalid sector number.
IORS_LOCK_COUNT_EXCEEDED | Volume lock count exceeded.
IORS_LOCK_VIOLATION | Illegal access to locked device.
IORS_MEDIA_ERROR | Media failure.
IORS_MEMORY_ERROR | Error allocating DMA buffer space for I/O.
IORS_NO_DEVICE | Physical or logical device nonexistent.
IORS_NO_MEDIA | Media removed from device.
IORS_NOT_READY | Device not ready.
IORS_OUT_OF_SPACE | No space on media.
IORS_SUCCESS_WITH_ECC | Successful, but with ECC.
IORS_SUCCESS_WITH_RETRY | Successful, but retries required.
IORS_TIME_OUT | Device timed out.
IORS_UNCERTAIN_MEDIA | Media may have changed.
IORS_UNFORMATTED_MEDIA | Unformatted media.
IORS_UNREC_ERROR | Unrecoverable error.
IORS_VALID_EJECT_FAILED | Eject command was not accepted.
IORS_VOL_IN_USE | Volume is in use ; used for eject.
IORS_VOL_LOCKED | Eject received with drive locked.
IORS_VOL_NOT_LOCKED | Volume received unlock without lock.
IORS_VOL_NOT_REMOVABLE | Removable request to non-removable drive.
IORS_WRITE_PROTECT | Write protect error.
IORS_WRONG_MEDIA | Wrong media in drive.

IOR_flags
Flags. Can be a combination of these values:
IORF_16BIT_IOCTL | If set, 16-bit IOCTL; 32-bit otherwise.
IORF_AUDIO_DATA_READ | Indicates an audio data read.
IORF_BLOCKDEV_EMULATE | Request started as a BCB
IORF_BYPASS_A_B | Indicates that VOLTRK should bypass AB check.
IORF_BYPASS_QUEUE | Request should bypass IOS queuing (internal IOS driver use only).
IORF_BYPASS_VOLTRK | Request will not be volume tracked.
IORF_CHAR_COMMAND | Indicates transfer counts and scatter/gather buffer sizes are byte values.
IORF_CHAR_DEVICE | Indicates character device.
IORF_DATA_IN | Indicates a data read operation.
IORF_DATA_OUT | Indicates a data write operation.
IORF_DIRECT_IO | Such as INT 25h or INT 26h.
IORF_DONT_CACHE | Indicates that the BDCB data should not be cached.
IORF_DOUBLE_BUFFER | Indicates that the request is to be completed using double buffering. Client must ensure that both the SGD buffer pointers and IOR_sgd_lin_phys are virtual pointers. Typically, set this flag before the IOS_SendCommand, if the ILB_int_io_criteria_rtn call returned an error.
IORF_HIGH_PRIORITY | Binary priority indication.
IORF_IDE_RESERVED | Indicates I/O is for a physical device.
IORF_INHIBIT_GEOM_RECOMPUTE | Force inhibit of device geometry recomputation.
IORF_IO_TOO_BIG | Indicates I/O is too big for single pass (set by IOS criteria code).
IORF_LOGICAL_START_SECTOR | IOR_start_addr is logical.
IORF_NO_COMPRESS | Do not compress data.
IORF_PARTITION_BIAS_ADDED | Set by TSD only to indicate that it has added in the bias, as required by IORF_LOGICAL_START_SECTOR.
IORF_PHYS_CMD | Indicates I/O is for a physical device.
IORF_PHYS_SGDS | Indicates IOR_sgd_lin_phys valid. This flag is set if the ILB_io_criteria_rtn has created a list of physical scatter-gather descriptors in IOR_sgd_lin_phys.
IORF_POSTPONED_VOL_OPS
IORF_QUIET_VOLTRK | Indicates that volume tracking just return error when wrong media in drive (no dialog box).
IORF_SCATTER_GATHER | Indicates BDCB logical (linear) SGD list present.
IORF_SRB_VALID | Indicates that IOP_srb points to a valid SRB.
IORF_SWAPPER_IO | Request is from the swapper.
IORF_SYNC_CMD_DONE | Set by IOS only to indicate completion of synchronous command.
IORF_SYNC_COMMAND | Indicates synchronous command (complete before return from IOS).
IORF_VERSION_002 | Indicates use of extended BCB (IOR) format for request.
IORF_VOL_RETRY | Indicates volume tracking retried request (internal use only).
IORF_WIN32 | Indicates I/O is from 32 bit API.

IOR_callback
Address of the callback routine for asynchronous requests. The callback receives control after the request completes. This member is ignored if IOR_flags is set to IORF_SYNC_COMMAND.
IOR_start_addr
Volume-relative start address if IOR_flags is set to IORF_LOGICAL_START_SECTOR; otherwise, this member is a physical address. IOR_start_addr[0] contains the low order 32 bits and IOR_start_addr[1] contains the high order 32 bits.
IOR_xfer_count
Number of bytes to transfer if IOR_flags is set to IORF_CHAR_COMMAND; otherwise, number of sectors to transfer. Must be set to zero if the requested function does not involve a data transfer.
IOR_buffer_ptr
Address of the BlockDev client buffer. Contains the address of the data buffer or of a null-terminated list of SGD structures, depending on whether IOR_flags is set to IORF_SCATTER_GATHER. This member is ignored if the requested function does not involve a data transfer.
_ureq
Usage area for requestor. Is used for storing parameters and return values for IOCTLs.
IOR_req_req_handle
Request handle, a 32-bit value that is passed on the stack to the callback routine specified by the IOR_callback member. Any 32 bit value may be used, but this member often contains the address of this IOR or of the IOP which contains this IOR.
IOR_req_vol_handle
Requestor-provided media handle designating the media on which to carry out the requested function (VRP).
IOR_sgd_lin_phys
Address of the first physical scatter/gather descriptor (SGD). (Contrast with IOR_buffer_ptr, which points to the logical SGDs.) This is either a linear or physical address, depending on the drivers as indicated by the DCB demand bits.
IOR_num_sgds
Number of physical SGDs pointed to by the IOR_sgd_lin_phys member.
IOR_vol_designtr
Numeric representation of the drive letter designating the volume to perform the function on. A is zero, B is 1, C is 2, and so on.

See Also

IOP, SGD, urequestor_usage


IRS

#include <irs.h>

typedef struct IRS_header { /* */
    UCHAR IRS_func;    // function; see below
    UCHAR IRS_result;  // result: zero if successful
} IRS, *PIRS;

Contains information about an I/O-related service.

IRS_func
Function code. Can be one of these values:
IRS_GET_VRP | Allocates a new VRP and sets it as the current VRP for the given device. Uses IRS_vrp_get structure. This function is typically used by a file system driver (FSD).
The VRP represents a volume on a given device. In the case of a removable device, such as a floppy diskette, a new VRP is created for every new diskette that is inserted in the drive. The VRP also maintains information on whether the media specified by the VRP is the current media in the drive. Each file system should check VRP_event_flags to check if the media is changed or uncertain, prior to relying on any cached data. Volume tracking uses the VRP to determine if the correct media is in the drive.
IRS_REPLACE_VRP | Used when mounting or verifying media to set the current VRP. Uses IRS_vrp_replace structure. This function is typically used by a file system driver (FSD).
If IRS_v_r_old_vrp and IRS_v_r_new_vrp are zero, the IOS clears the uncertain status on the current VRP for the drive specified in IRS_v_r_designtr, as long as the IRS_v_r_flags value is not set to IRS_V_R_DEF.
If IRS_v_r_old_vrp is nonzero and IRS_v_r_new_vrp is zero, the IOS deallocates the VRP pointed to by IRS_v_r_old_vrp and also notifies all IOS drivers of the destruction of the VRP by issuing a AEP_DESTROY_VRP function.
If IRS_v_r_old_vrp is nonzero and IRS_v_r_new_vrp is nonzero, the IOS deallocates the old VRP and sets the VRP specified by IRS_v_r_new_vrp as the current VRP. This should be used when a verify has indicated that the media in the drive is an existing volume.
If IRS_v_r_old_vrp is zero and IRS_v_r_new_vrp is nonzero, the IOS is in the middle of mounting a new volume. The new VRP must be the VRP most recently made current for the given volume, using the IRS_GET_VRP call. In this case, the uncertain media status is cleared and an AEP_CREATE_VRP function is broadcast indicating the arrival of a new VRP in the system.
IRS_GET_DRVINFO | Returns information about the requested drive letter. Uses IRS_drv_get structure.
IRS_MEDIA_CHECK_RESET | Directs the IOS to issue an IOR_MEDIA_CHECK_RESET function to the device specified by the IRS_m_c_r_designtr member. This function checks if the media has changed since the last time the VRP was used and resets the status. Uses IRS_media_chk_reset structure.
IRS_SET_CUR_FLP_UNIT | If the floppy device for drive A supports A to B toggling, this function sets the current unit number for the device to A or B depending on the IRS_s_c_f_unit member. Uses IRS_cur_flp_unit_set structure.
IRS_REAL_MODE_HANDOFF | This is an internal IFSMGR call and should not be used. Directs the IOS to issue an AEP_REAL_MODE_HANDOFF function. This function indicates to device driver layers that this is the last opportunity to issue an INT 21h through MS-DOS. Uses IRS_rm_handoff structure.
IRS_QUERY_VOLUME_LOCK | Returns a bitmap of logical drives that are associated with a drive that is about to be locked. An example of this function is a drive with a compressed volume file on it. If drive D is a compression drive with drive C as the host, using this function on drive D returns a bit mask of 0h, indicating that no other drives will be changed. On the other hand, using this function on drive C returns a bit mask of 4h indicating that drive D will also be locked. Uses IRS_query_vollock structure.
IRS_GET_LOGICAL_DRVS | Returns all logical drive letters associated with the given INT 13h unit. Uses IRS_get_logical_drives structure.
IRS_MOUNT_NOTIFY | Issues an AEP_MOUNT_NOTIFY function to all IOS device drivers to indicate that the given drive and VRP are being mounted. The device layers return a bitmap of all child volumes that are affected. For more information, see AEP_MOUNT_NOTIFY in the AEP structure. Uses IRS_mnt_notify structure.
IRS_FIRSTNXT_CHAR_DEV | Finds names for character device drivers controlled by the IOS. The IRS_g_f_n_hndl member should be set to zero to find the first character driver; then all subsequent calls to find the next driver should use the IRS_g_f_n_hndl returned by the previous call. Uses IRS_frstnxt_char_dev structure.
IRS_IS_DRVCOMPRESSED | Given a logical drive number, this function attempts to determine if the drive is compressed. If it is compressed the flag IRS_I_D_C_COMP is set and the IRS_i_d_c_drive member indicates the host drive. In some cases, the IOS may not know that it is a compressed drive. Uses IRS_drv_comp structure.

IRS_result
Function result. It can be IRS_SUCCESS to indicates success or some other function-specific value.

See Also

IOS_Requestor_Service, AEP


IRS_cur_flp_unit_set

#include <irs.h>

typedef struct IRS_cur_flp_unit_set {  //
    UCHAR  filler9;         // IRS_SET_CUR_FLP_UNIT
    UCHAR  filler10;        // result; zero if successful
    UCHAR  IRS_s_c_f_unit;  // flp unit # 0 = A, 1 = B
} IRS_cur_flp_unit_set, *PIRS_cur_flp_unit_set;

Contains information for a IRS_SET_CUR_FLP_UNIT function.

See Also

IRS


IRS_drv_comp

#include <irs.h>

typedef struct IRS_drv_comp {
    struct IRS_header IRS_i_d_c_hdr;
    UCHAR  IRS_i_d_c_drive;  // drive number (0 = A:, ...)
    UCHAR  IRS_i_d_c_flags;  // flags; see below
} IRS_drv_comp, *PIRS_drv_comp;

Contains information for a IRS_IS_DRVCOMPRESSED function.

IRS_i_d_c_flags
Flags. Can be IRS_I_D_C_COMP to indicate that drive is compressed or IRS_I_D_C_PM_COMP to indicates that drive is compressed through protected mode.

See Also

IRS


IRS_drv_get

#include <irs.h>

typedef struct IRS_drv_get {
    UCHAR  IRS_filler_5;   // must be IRS_GET_DRVINFO
    UCHAR  IRS_filler_6;   // zero if successful
    UCHAR  IRS_DrvLetter;  // drive letter
    ULONG  IRS_DrvFlags;   // flags; see below
} IRS_drv, *PIRS_drv;

Contains information for a IRS_GET_DRVINFO function.

IRS_DrvLetter
Indicates the drive. Can be a hexadecimal number in the range 80h to 8fh for INT 13h devices or an upper or lowercase letter in the range of A to Z. If the drive letter requested is not a valid IOS device, then the call returns with a status of 1.
IRS_DrvFlags
Flags. Can be any combination of these values:
IRS_DRV_SINGLE_FLOPPY | Indicates a floppy device that performs drive letter toggling. The same physical device responds to both drive letters A and B.
IRS_DRV_RMM | Indicates that the requested drive uses the real mode mapper for logical disk access.
IRS_DRV_REMOTE | Indicates a remote (non local) drive.
IRS_DRV_REMOVABLE | Indicates a device that uses removable media.
IRS_DRV_INT13_DRIVE | Indicates a device that can be accessed using the INT 13h interface specification.
IRS_DRV_PAGEABLE | Indicates that the device drivers controlling this drive have pageable code in them.

Except for IRS_DRV_ON_INT13_DRIVE, these are numerically equivalent to their DCB counterparts.

See Also

IRS


IRS_frstnxt_char_dev

#include <irs.h>

typedef struct IRS_frstnxt_char_dev {
    struct IRS_header IRS_g_f_n_hdr;
    ULONG  IRS_g_f_n_hndl;  // handle for get next, zero for get first
    ULONG  IRS_g_f_n_ptr;   // pointer to 12 byte name buffer
} IRS_frstnxt_char_dev, *PIRS_frstnxt_char_dev;

Contains information for a IRS_FIRSTNXT_CHAR_DEV function.

See Also

IRS


IRS_get_logical_drives

#include <irs.h>

typedef struct IRS_get_logical_drives {
    struct IRS_header  IRS_g_l_d_hdr;
    UCHAR  IRS_g_l_d_designtr;  // int 13 unit designator for device
    ULONG  IRS_g_l_d_drivemap;  // Bitmap of logical drives
    UCHAR  IRS_g_l_d_pad;       // Pad structure to DWORD boundary
} IRS_get_logical_drives, *PIRS_get_logical_drives;

Contains information for a IRS_GET_LOGICAL_DRVS function.

See Also

IRS


IRS_media_chk_reset

#include <irs.h>

typedef struct IRS_media_chk_reset {
    UCHAR   filler7;             // must be IRS_MEDIA_CHECK_RESET
    UCHAR   filler8;             // result; see below
    UCHAR   IRS_m_c_r_designtr;  // volume designator for device
    ULONG   IRS_m_c_r_vrp;       // address of VRP for device
} IRS_media_chk_reset, *PIRS_media_chk_reset;

Contains information for a IRS_MEDIA_CHECK_RESET function.

filler8
Function result. Can be IRS_M_C_R_SUCCESS if media has not been changed or IRS_M_C_R_UNCERTAIN if media might have changed.
IRS_m_c_r_designtr
Zero-based drive number. Can be zero for A, 1 for B, and so on.

See Also

IRS, VRP


IRS_mnt_notify

#include <irs.h>

typedef struct IRS_mnt_notify {  //
    struct IRS_header  IRS_m_n_hdr;
    USHORT IRS_m_n_drive;            // Supplied Drive number (0 = A:, ...)
    void   *IRS_m_n_pvrp;            // Supplied VRP pointer
    ULONG  IRS_m_n_drivemap;         // Returned Bitmap of child volumes
    ULONG  IRS_m_n_effective_drive;  // Returned Effective drive number
    ULONG  IRS_m_n_actual_drive;     // Returned Actual drive number
} IRS_mnt_notify, *PIRS_mnt_notify;

Contains information for a IRS_MOUNT_NOTIFY function.

IRS_m_n_hdr.IRS_result
Result. Can be IRS_M_N_SUCCESS to indicate nothing to do or IRS_M_N_REMOUNT to remount the drive.

See Also

IRS


IRS_query_vollock

#include <irs.h>

typedef struct IRS_query_vollock {
    struct IRS_header  IRS_q_v_l_hdr;
    UCHAR  IRS_q_v_l_designtr;  // volume designator for device
    ULONG  IRS_q_v_l_drivemap;  // bitmap of logical drives
    UCHAR  IRS_q_v_l_pad;       // Pad structure to DWORD boundary
} IRS_query_vollock, *PIRS_query_vollock;

Contains information for a IRS_QUERY_VOLUME_LOCK function.

IRS_q_v_l_drivemap
Bitmap of logical drives. Bit 0 (least significant bit) corresponds to drive A, Bit 1 to drive B, and so on.

See Also

IRS


IRS_rm_handoff

#include <irs.h>

typedef struct IRS_rm_handoff {
    struct IRS_header  IRS_r_m_h_hdr;
    UCHAR  IRS_r_m_h_pad[2];  // Pad structure to DWORD boundary
} IRS_rm_handoff, *PIRS_rm_handoff;

Contains information for a IRS_REAL_MODE_HANDOFF function.

See Also

IRS


IRS_vrp_get

#include <irs.h>

typedef struct IRS_vrp_get {
    UCHAR  filler1;           // must be IRS_GET_VRP
    UCHAR  filler2;           // result; see below
    UCHAR  IRS_v_g_dev_type;  // device type; see below
    ULONG  IRS_v_g_designtr;  // volume ID or device name
    ULONG  IRS_v_g_handle;    // volume handle
    ULONG  IRS_v_g_vrp;       // address of VRP
} IRS_vrp_get, *PIRS_vrp_get;

Contains information for a IRS_GET_VRP function.

filler2
Function result. It is IRS_V_G_SUCCESS if the function is successful; otherwise it is one of these values:.
IRS_V_G_NO_DEVICE | Indicates no device present
IRS_V_G_UNCERTAIN_MEDIA | Indicates uncertain media

IRS_v_g_dev_type
Device type. Can be IRS_V_G_CHAR to direct the function to get the VRP for the character device named by in v_g_designtr.

See Also

VRP


IRS_vrp_replace

#include <irs.h>

typedef struct IRS_vrp_replace {
    UCHAR  filler3;           // IRS_REPLACE_VRP
    UCHAR  filler4;           // zero if successful
    UCHAR  IRS_v_r_designtr;  // address of VRP to deallocate
    UCHAR  IRS_v_r_flags;     // flags; see below
    ULONG  IRS_v_r_old_vrp;   // address of VRP to deallocate
    ULONG  IRS_v_r_new_vrp;   // address of new VRP or zero if none
} IRS_vrp_replace, *PIRS_vrp_replace;

Contains information for the IRS_REPLACE_VRP function.

IRS_v_r_flags
Flags indicating the mounting. Can be IRS_V_R_CHAR to indicate a character device or IRS_V_R_DEF.
IRS_v_r_new_vrp
Address of a new VRP structure. If this member is zero, the deallocated structure is not replaced.

See Also

VRP


ISP

#include <isp.h>

typedef struct ISP {
    USHORT ISP_func;    // function; see below
    USHORT ISP_result;  // result; zero if successful
} ISP, *PISP;

Contains information for an IOS service request.

ISP_func
Function to perform. Can be one of these values:
ISP_CREATE_DDB | Creates a device descriptor block (DDB). This is typically called by a port driver to create a per controller data structure when processing the AEP_INITIALIZE function. Uses ISP_ddb_create structure.
ISP_CREATE_DCB | Creates a device control block (DCB) for a physical device. Uses ISP_dcb_create structure.
ISP_CREATE_IOP | Creates an input and output packet (IOP). Uses ISP_IOP_create structure.
ISP_ALLOC_MEM | Allocates memory. Uses ISP_mem_alloc structure.
ISP_DEALLOC_MEM | Deallocates memory. Uses ISP_mem_dealloc structure.
ISP_INSERT_CALLDOWN | Inserts entry in calldown table. Typically used by a layer driver to insert its request entry point into the DCB call down list. This ensures that the driver will see all input and output requests to that device. The driver can also allocate a per I/O request packet area called the expansion area. This becomes part of the IOP and can be accessed when the request is being processed by each layer. Uses ISP_calldown_insert structure.
ISP_ASSOCIATE_DCB | Associates DCB with a relative drive number. This service is usually called by a TSD. The TSD is responsible for determining the logical drives associated with a physical drive. This service associates a logical drive letter with a logical DCB or an INT 13h drive number with a physical. In the case of logical association, this service calls IFSMGR and sends out a WM_DEVICECHANGE/DBT_DEVICEARRIVAL broadcast to notify the system of a volume arrival. Value add drivers also may need to make this call. For instance, a compression layer would call this service as and when it determines a compressed volume that is associated with a host. Uses ISP_dcb_associate structure.
ISP_GET_DCB | Returns the DCB for the given logical volume. Uses ISP_dcb_get structure.
ISP_GET_FIRST_NEXT_DCB | Returns the first or next DCB. Uses ISP_GET_FRST_NXT_DCB structure.
ISP_DEALLOC_DDB | Deallocates a DDB. Used typically by a port driver when the controller associated with the DDB is removed. The IOS sends an AEP_UNINITIALIZE function at this time and port drivers typically deallocate any resources that they may have allocated to handle I/O to the controller represented by that DDB. For instance, the driver frees IRQ, removes port trapping, and so on. Uses ISP_DDB_DEALLOC structure.
ISP_DESTROY_DCB | Destroys a DCB. Used when a device is removed, this service should be called at application time (Appy time) only. This service broadcasts an AEP_PEND_UNCONFIG_DCB to all the layer drivers to direct the drivers to stop generating new requests for this device. Execution blocks until all pending I/O to the device is complete; subsequent I/O requests to this DCB generate errors. For all logical drives associated with this physical device, the IFSMGR is notified of the volume removal. Also a WM_DEVICECHANGE/DBT_DEVICEREMOVECOMPLETE message is broadcast. The IOS sends an AEP_UNCONFIG_DCB function to all the layer drivers. The drivers do any necessary processing at this point. All VRPs and calldown nodes associated with the DCB are freed. Finally the DCB itself is freed. Uses ISP_DCB_DESTROY structure.
ISP_QUERY_MATCHING_DCBS | Determines whether matching logical and physical DCBs exist. Intended for use by the TSD to find any relationships it is unable to deduce. For example, in order to associate compressed volumes to a particular physical DCB, the DiskTSD queries all the layer drivers using this function. The function sends an AEP_ASSOCIATE_DCB function to all the layer drivers. The TSD then associates the additional logical volumes to the physical if the real mode mapper has not already claimed that logical volume. The real mode mapper may claim a logical volume if there is an unsafe device driver hooking the real mode driver chain for that volume. Uses ISP_QUERY_MATCH structure.
ISP_QUERY_REMOVE_DCB | Determines whether a device can be removed. Broadcasts a DBT_DEVICEQUERYREMOVE message and also queries the IFSMGR by calling the IFSMGR service QueryVolumeRemoval. This call can be failed by any application or the IFSMGR if they believe that this volume cannot be removed. This is an Appy time only service. Uses ISP_QUERY_REMOVE structure.
ISP_DEVICE_REMOVED | Indicates that a device has been removed. Broadcasts a DBT_DEVICEREMOVECOMPLETE message for all the logical volumes associated with the physical DCB. This is typically called if the media is ejected from the drive in which case ISP_DEV_REMOVED_FL_MEDIA_ONLY should be set. This is an Appy time only service. Uses ISP_DEV_REMOVED structure.
ISP_DEVICE_ARRIVED | Indicates that a device has arrived. Broadcasts a DBT_DEVICEARRIVAL message for all the logical volumes associated with the physical DCB. This is typically called if the media is inserted in the drive in which case ISP_DEV_REMOVED_FL_MEDIA_ONLY should be set. This is an Appy time only service. Uses ISP_DEV_ARRIVED structure.
ISP_DISASSOCIATE_DCB | Disassociates the logical drive number from the DCB that is currently associated to it. The IFSMGR is also notified of a volume removal. This is typically called by a value added driver when the volumes that it associated by using ISP_QUERY_MATCH are going away. Uses ISP_DISASSOC_DCB structure.
ISP_DRIVE_LETTER_PICK | Picks a drive letter. Uses ISP_pick_drive_letter structure. Provides a drive letter for a potential logical volume. This volume cannot be a volume that is visible in real mode, as the protect mode drive letter for that volume will match the real mode drive. The criteria for the search are specified in ISP_p_d_l_flags. If nothing is specified, the UserDriveLetterAssignment value in the registry for this DCB is read and a drive letter that falls in this range is provided. If there is no registry entry the next available drive letter is picked.
If the ISP_PDL_FL_USE_RANGE flag is set, the caller provides a search range starting with the letter in ISP_p_d_l_letter[0] and ending with the letter in ISP_p_d_l_letter[1]. The registry is read and a drive letter in the range that is an intersection of the registry range and the user range is picked. If all the letters in this range are used the next available drive letter is picked unless the ISP_PDL_FL_USER_ONLY flag is set in which case the call is failed.
In the case where a registry range is specified, when scanning for drive letters in this range, if a drive letter is already used then the following two flags provide additional directions to the service: ISP_PDL_FL_OK_RM_CD specifies that it is OK to pick the already used drive letter if it was a real mode CD drive; ISP_PDL_FL_OK_INVALID_RM specifies that it is OK to pick the already used drive letter if it is an invalid drive in real mode.
ISP_REGISTRY_READ | Reads registry information corresponding with the physical DCB provided. The parameter definitions are identical to those of VMM service _RegQueryValueEX. Other common registry values for devnodes, like class name, can also be read using this service for that DCB. Uses ISP_read_registry structure.
ISP_FIND_LDM_ENTRY | Finds an LDM entry for the specified drive. Uses ISP_FIND_LDM structure.
ISP_DELETE_LDM_ENTRY | Deletes an LDM entry for the specified drive. Deletion is accomplished by compacting the LDM table to copy over the deleted entry. Therefore, clients should not rely on a pointer to an LDM entry after yielding. Uses ISP_FIND_LDM structure.
ISP_BROADCAST_AEP | Broadcasts the given AEP to the entire driver architecture. Uses ISP_AEP_BROADCAST structure.

See Also

DCB, DDB, IOP, AEP


ISP_AEP_BROADCAST

#include <isp.h>

typedef struct ISP_AEP_BROADCAST {
    ISP    ISP_baep_hdr;        // Standard header
    PVOID  ISP_baep_paep;       // address of AEP to broadcast
} ISP_AEP_BROADCAST,*PISP_AEP_BROADCAST;

Contains information for ISP_BROADCAST_AEP function.

See Also

ISP, AEP


ISP_calldown_insert

#include <isp.h>

typedef struct ISP_calldown_insert {
    ISP    ISP_i_cd_hdr;        // Standard header
    ULONG  ISP_i_cd_dcb;        // address of DCB
    PVOID  ISP_i_cd_req;        // address of request routine; see below
    ULONG  ISP_i_cd_ddb;        // address of DDB
    USHORT ISP_i_cd_expan_len;  // size of IOP expansion; see below
    ULONG  ISP_i_cd_flags;      // demand flags
    UCHAR  ISP_i_cd_lgn;        // load group number; see below
    UCHAR  ISP_pad4[1];         // Pad to DWORD boundary
} ISP_calldown_insert, *PISP_calldown_insert;

Contains information for a ISP_INSERT_CALLDOWN function.

ISP_i_cd_req
Address of the request routine. The IOS routes normal I/O requests to this routine, allowing the driver to hook I/O requests.
ISP_i_cd_expan_len
Size of IOP expansion in bytes. This is the amount of memory that the IOS reserves for the driver in each IOP. If this member is zero, no memory is reserved.
ISP_i_cd_lgn
Load group number specifying the layer in the calldown list to insert the driver. This is typically the same value as the AEP_lgn member of the AEP structure.

See Also

DCB, DDB, IOP, ISP, AEP


ISP_dcb_associate

#include <isp.h>

typedef struct ISP_dcb_associate {
    ISP    ISP_d_a_hdr;    // Standard header
    ULONG  ISP_d_a_dcb;    // address of DCB
    CHAR   ISP_d_a_drive;  // relative drive number
    UCHAR  ISP_d_a_flags;  // flags
    UCHAR  ISP_pad5[2];    // Pad to DWORD boundary
} ISP_dcb_associate, *PISP_dcb_associate;

Contains information for a ISP_ASSOCIATE_DCB function.

ISP_d_a_flags
Can be ISP_D_A_FL_NOSHELLMSG to suppress the shell message.

See Also

DCB, ISP


ISP_dcb_create

#include <isp.h>

typedef struct ISP_dcb_create {  //
    ISP    ISP_dcb_hdr;   // Standard header
    USHORT ISP_dcb_size;  // size of DCB to create, in bytes
    ULONG  ISP_dcb_ptr;   // address of DCB
    UCHAR  ISP_pad1[2];   // Pad to DWORD boundary
} ISP_dcb_create, *PISP_dcb_create;

Contains information for a ISP_CREATE_DCB function.

See Also

DCB, ISP


ISP_DCB_DESTROY

#include <isp.h>

typedef struct ISP_DCB_DESTROY {
    ISP    ISP_ddb_d_hdr;  // Standard header
    ULONG  ISP_dcb_d_dcb;  // 32-bit offset of DCB to destroy
} ISP_DCB_DESTROY, *PISP_DCB_DESTROY;

Contains information for a ISP_DESTROY_DCB function.

See Also

DCB, ISP


ISP_dcb_get

#include <isp.h>

typedef struct ISP_dcb_get {
    ISP    ISP_g_d_hdr;    // Standard header
    ULONG  ISP_g_d_dcb;    // address of DCB reported by the ISP_GET_DCB service.
    ULONG  ISP_g_d_drive;  // relative drive number of desired drive info (0=a:. 1=b, etc.)
} ISP_dcb_get, *PISP_get_dcb;

Contains information for an ISP_GET_DCB function. Set the IORF_PHYS_CMD flag in the relative drive number field if obtaining information for a physical device.

See Also

DCB, ISP


ISP_ddb_create

#include <isp.h>

typedef struct ISP_ddb_create {  //
    ISP    ISP_ddb_hdr;    // Standard header
    USHORT ISP_ddb_size;   // size of DDB to create, in bytes
    ULONG  ISP_ddb_ptr;    // address of DDB
    UCHAR  ISP_ddb_flags;  // flags; see below
    UCHAR  ISP_pad0[1];    // Pad to DWORD boundary
} ISP_ddb_create, *PISP_ddb_create;

Contains information for the ISP_CREATE_DDB function.

ISP_ddb_flags
Flags. Can be ISP_DDB_FLAG_NEED_PHYS_CONTIG to indicate that the DDB must be physically contiguous. The DDB_phys_addr member is valid only if this value is set.

See Also

DDB, ISP


ISP_DDB_DEALLOC

#include <isp.h>

typedef struct ISP_DDB_DEALLOC {
    ISP    ISP_ddb_d_hdr;  // Standard header
    ULONG  ISP_ddb_d_ddb;  // address of DDB to deallocate
    ULONG  ISP_ddb_d_dvt;  // address of DVT
} ISP_DDB_DEALLOC, *PISP_DDB_DEALLOC;

Contains information for a ISP_DEALLOC_DDB function.

See Also

DDB, DVT, ISP


ISP_DEV_ARRIVED

#include <isp.h>

typedef struct ISP_DEV_ARRIVED {
    ISP    ISP_d_arrived_hdr;      // standard header
    PVOID  ISP_dev_arrived_pdcb;   // physical DCB pointer
    ULONG  ISP_dev_arrived_flags;  // flags; see below
} ISP_DEV_ARRIVED, *PISP_DEV_ARRIVED;

Contains information for a ISP_DEVICE_ARRIVED function.

ISP_dev_arrived_flags
Can be ISP_DEV_ARR_FL_MEDIA_ONLY to indicate only the medium is going away.

See Also

DCB, ISP


ISP_DEV_REMOVED

#include <isp.h>

typedef struct ISP_DEV_REMOVED {  //
    ISP    ISP_d_removed_hdr;      // standard header
    PVOID  ISP_dev_removed_pdcb;   // physical DCB pointer
    ULONG  ISP_dev_removed_flags;  // flags; see below
} ISP_DEV_REMOVED, *PISP_DEV_REMOVED;

Contains information for a ISP_DEVICE_REMOVED function.

ISP_dev_removed_flags
Can be ISP_DEV_REMOVED_FL_MEDIA_ONLY to indicate only the medium is going away.

See Also

DCB, ISP


ISP_DISASSOC_DCB

#include <isp.h>

typedef struct ISP_DISASSOC_DCB {  //
    ISP    ISP_dis_dcb_hdr;    // Standard header
    ULONG  ISP_dis_dcb_drive;  // Drive of associated logical DCB
} ISP_DISASSOC_DCB, *PISP_DISASSOC_DCB;

Contains information for a ISP_DISASSOCIATE_DCB

See Also

DCB, ISP


ISP_FIND_LDM

#include <isp.h>

typedef struct ISP_FIND_LDM {  //
    ISP ISP_fldm_hdr;      // Standard header
    ULONG ISP_fldm_drive;  // zero-based drive number
    PVOID ISP_fldm_pldm;   // returned pointer to LDM entry
} ISP_FIND_LDM, *PISP_FIND_LDM;

Contains information for a ISP_FIND_LDM_ENTRY or ISP_DELETE_LDM_ENTRY function. LDM refers to the Logical Device Map, pointed to by the IDA_logical_dev_map (see IDA.H).

See Also

ISP


ISP_GET_FRST_NXT_DCB

#include <isp.h>

typedef struct ISP_GET_FRST_NXT_DCB {
    ISP    ISP_gfnd_hdr;         // Standard header
    ULONG  ISP_gfnd_dcb_offset;  // address of current DCB; see below
    ULONG  ISP_gfnd_found_dcb;   // address of next DCB; see below
    BYTE   ISP_gfnd_dcb_type;    // device type or 0ffh
    UCHAR  ISP_pad7[3];          // Pad to DWORD boundary
} ISP_GET_FRST_NXT_DCB, *PISP_GET_FRST_NXT_DCB;

Contains information for a ISP_GET_FRST_NEXT_DCB function.

ISP_gfnd_dcb_offset
Address of the current DCB. To retrieve the first DCB in the chain, set this member to zero. Otherwise, use the value returned in ISP_gfnd_found_dcb from a previous call to get the next DCB.
ISP_gfnd_found_dcb
Address of the next DCB in the chain if the function result is zero. Otherwise, this member is not defined.
ISP_gfnd_dcb_type
Device type. Can be one of the device types defined for the DCB structure. If this is 0xFF the search is not restricted to a specific device type.

See Also

DCB


ISP_IOP_create

#include <isp.h>

typedef struct ISP_IOP_create {
    ISP    ISP_i_c_hdr;       // Standard header
    USHORT ISP_IOP_size;      // size of IOP to allocate, in bytes
    ULONG  ISP_delta_to_ior;  // offset to IOR within IOP
    ULONG  ISP_IOP_ptr;       // address of IOP
    UCHAR  ISP_i_c_flags;     // allocation flags; see below
    UCHAR  ISP_pad2[1];       // Pad to DWORD boundary
} ISP_IOP_alloc, *PISP_IOP_alloc;

Contains information for a ISP_CREATE_IOP function.

ISP_i_c_flags
Allocation flags. Can be one of these values:
ISP_M_FL_EXTERNAL_IOP | Allocates memory using VMMCall _HeapAllocate instead of IOP's private memory. The only difference between this call and ISP_M_FL_PERSISTENT_IOP, is that this IOP gets time-out support.
ISP_M_FL_INTERRUPT_TIME | Must be set if allocation is at asynchronous time.
ISP_M_FL_MUST_SUCCEED | If set, IOS will not fail the allocation. If set, the function might take some time to complete, awaiting for free memory.
ISP_M_FL_PERSISTENT_IOP | Allocation is for a long time IOP. Allocates memory using VMMCall _HeapAllocate instead of IOP's private memory heap. Also, the IOP is not added to the IOP time-out chain (the persistent IOP has no time-out support).
ISP_M_FL_SMART_ALLOC | Do system heap allocation if not MS-DOS pager. Checks IOS's IDA structure element IDAF_DOS_PAGER to determine if system is paging through DOS. If not paging through DOS, do a system heap allocation. Otherwise use IOS's memory management system.
ISP_M_FL_USE_SYSTEM_HEAP | Don't allocate from IOS heap. Instead, uses VMMCall _HeapAllocate.

See Also

IOP, ISP


ISP_mem_alloc

#include <isp.h>

typedef struct ISP_mem_alloc {
    ISP    ISP_mem_a_hdr;  // Standard header
    USHORT ISP_mem_size;   // size of memory to allocate, in bytes
    ULONG  ISP_mem_ptr;    // address of memory block (returned)
    USHORT ISP_mem_type;   // med type code for memory block. See header file med.h
    UCHAR  ISP_mem_flags;  // allocation flags; see below
    UCHAR  ISP_pad3[3];    // Pad to DWORD boundary
} ISP_mem_alloc, *PISP_mem_alloc;

Contains information for a ISP_ALLOC_MEM function.

ISP_mem_flags
Allocation flags. Can be a combination of these values:
ISP_M_FL_INTERRUPT_TIME | Must be set if allocation is at asynchronous time.
ISP_M_FL_MUST_SUCCEED | IOS will not fail the allocation.
ISP_M_FL_SMART_ALLOC | Do system Heap allocation if not MS-DOS pager. Checks IOS's IDA structure element IDAF_DOS_PAGER to determine if system is paging through DOS. If not paging through DOS, do a system heap allocation. Otherwise use IOS's memory management system.
ISP_M_FL_USE_SYSTEM_HEAP | Don't allocate from IOS heap.

When the IOS.VXD debug binary is installed (into the system\vmm32 directory), use your debugger's ".IMED" dot command to list IOS Memory Element Descriptor information.

See Also

ISP


ISP_mem_dealloc

#include <isp.h>

typedef struct ISP_mem_dealloc {
    ISP    ISP_mem_da_hdr;  // Standard header
    ULONG  ISP_mem_ptr_da;  // address of memory to dealloc
} ISP_mem_dealloc, *PISP_mem_dealloc;

Contains information for a ISP_DEALLOC_MEM function.

See Also

ISP


ISP_pick_drive_letter

#include <isp.h>

typedef struct ISP_pick_drive_letter {  //
    ISP    ISP_p_d_l_hdr;        // standard header
    PVOID  ISP_p_d_l_pdcb;       // physical DCB pointer
    UCHAR  ISP_p_d_l_letter[2];  // drive letter if no error
    UCHAR  ISP_p_d_l_flags;      // flags; see below
    UCHAR  ISP_p_d_l_pad[1];     // dword alignment
} ISP_pick_drive_letter, *PISP_pick_drive_letter;

Contains information for a ISP_DRIVE_LETTER_PICK function.

ISP_p_d_l_flags
Flags. Can be one of these values:
ISP_PDL_FL_USER_ONLY | Returns only user specified drive letter.
ISP_PDL_FL_OK_INVALID_RM | Okay to pick user specified drive letter for real mode letter if invalid partition.
ISP_PDL_FL_OK_RM_CD | Okay to pick user specified drive letter for real mode letter if CD-ROM.
ISP_PDL_FL_USE_RANGE | Use caller-specified drive range.
ISP_PDL_FL_RELEASE | Release a picked drive letter.

See Also

DCB, ISP


ISP_QUERY_MATCH

#include <isp.h>

typedef struct ISP_QUERY_MATCH {  //
    ISP    ISP_q_match_hdr;     // Standard header
    PVOID  ISP_q_match_pdcb;    // physical DCB pointer
    ULONG  ISP_q_match_drives;  // bitmap of associated logical DCBs
} ISP_QUERY_MATCH, *PISP_QUERY_MATCH;

Contains information for a ISP_QUERY_MATCHING_DCBS function.

See Also

DCB, ISP


ISP_QUERY_REMOVE

#include <isp.h>

typedef struct ISP_QUERY_REMOVE {
    ISP    ISP_q_remove_hdr;    // standard header
    PVOID  ISP_q_remove_pdcb;   // physical DCB pointer
    ULONG  ISP_q_remove_flags;  // flags; see below
} ISP_QUERY_REMOVE, *PISP_QUERY_REMOVE;

Contains information for a ISP_QUERY_REMOVE_DCB function.

ISP_q_remove_flags
Can be ISP_Q_REMOVE_FL_MEDIA_ONLY to indicate only the medium is going away.

See Also

DCB, ISP


ISP_read_registry

#include <isp.h>

typedef struct ISP_read_registry {  //
    ISP   ISP_r_r_hdr;        // standard header
    PVOID ISP_r_r_dcb;        // physical DCB pointer
    PVOID ISP_r_r_string;     // addr of null-terminated key name
    DWORD ISP_r_r_data_type;  // type of data stored in buffer
    DWORD ISP_r_r_data_size;  // size of buffer
    PVOID ISP_r_r_buffer;     // pointer to buffer for result
} ISP_read_registry, *PISP_read_registry;

Contains information for a ISP_REGISTRY_READ function.

ISP_r_r_string
Null-terminated string specifying the key name or one of these values:
REGSTR_VAL_SCSITID | SCSI target ID (ASCIZ string)
REGSTR_VAL_SCSILUN | SCSI LUN ID (ASCIZ string)
REGSTR_VAL_REVLEVEL | Revision Level (ASCIZ string)
REGSTR_VAL_PRODUCTID | Product ID from inquiry data (ASCIZ string)
REGSTR_VAL_MANUFACTURER | Vendor ID from inquiry data.
REGSTR_VAL_DEVTYPE | Device type as defined for DCB. (Binary value )
REGSTR_VAL_REMOVABLE | 1 if removable; zero if not. (Boolean)
REGSTR_VAL_CURDRVLET | Current drive letters. For example, CDF implies that C, D and F are currently assigned to this physical DCB. (ASCIZ string)
REGSTR_VAL_USRDRVLET | User drive range. For example, DG implies that the user specified a drive range starting from D and ending at G. See ISP_pick_drive_letter for more info. (ASCIZ string)
REGSTR_VAL_SYNCDATAXFER | SCSI only. 1 if syncdata enabled; zero if not. Default is 1 (ON) for Disks and zero (OFF) for CD-ROM. (Boolean)
REGSTR_VAL_AUTOINSNOTE | SCSI CD only. 1 if enabled; zero if not. Default is 1. (Boolean)
REGSTR_VAL_DISCONNECT | SCSI only. 1 if enabled; zero if not. Default is 1. (Boolean)
REGSTR_VAL_INT13 | 1 if INT 13h unit; zero if not. (Boolean)

See Also

DCB, ISP


LOG_DCB

#include <dcb.h>

typedef struct  _LOG_DCB {
    DCB_COMMON  DCB_cmn;
} LOG_DCB, *PLOG_DCB;

Contains the device control block information for logical disk devices.

See Also

DCB_COMMON


SGD

#include <sgd.h>

typedef struct _SGD {
    ULONG SG_buff_ptr    // address of data buffer; see below
    ULONG SG_buff_size   // number of bytes to transfer
} SGD, *PSGD;

Contains physical scatter/gather descriptors (SGDs). The IOP's IOR_SGD_lin_phys field points to a list of these physical SGDs, when the device driver demands physical SGDs (DCB_dmd_phys_sgd) Note that the creation of physical SGDs is performed in ILB_int_io_criteria_rtn.

SG_buff_ptr
Physical 32 bit address of buffer that contains or receives transferred data.

See Also

IOR, VRP


BlockDev_Scatter_Gather

#include <blockdev.h>

typedef struct BlockDev_Scatter_Gather{
        ULONG BD_SG_Count;   ; Block count; else byte count if IORF_CHAR_COMMAND set
        ULONG BD_SG_Buffer_Ptr;
}  _BlockDev_Scatter_Gather;

Contains logical scatter/gather descriptors (SGDs). If (IOR_flags & IORF_SCATTER_GATHER) is true, the IOP's IOR_buffer_ptr field points to a list of these logical SGDs. Note that this (logical) structure is different from the physical SGD structure.

BD_SG_buff_ptr
Logical 32 bit address of buffer that contains or receives transferred data.

See Also

IOR, VRP


type_sdeffsd_req_usage

#include <ior.h>

typedef struct type_sdeffsd_req_usage {
    USHORT _IOR_ioctl_drive;
    USHORT _IOR_ioctl_function;
    ULONG  _IOR_ioctl_control_param;
    ULONG  _IOR_ioctl_buffer_ptr;
    ULONG  _IOR_ioctl_client_params;
    ULONG  _IOR_ioctl_return;
} _type_sdeffsd_req_usage;

Contains information used with the IOR_GEN_IOCTL function.

See Also

IOR


urequestor_usage

#include <ior.h>

typedef union urequestor_usage { /* */
   ULONG  _IOR_requestor_usage[5];
   struct type_sdeffsd_req_usage sdeffsd_req_usage;
} _urequestor_usage;

Contains information used with the IOR_GEN_IOCTL function.

See Also

IOR, type_sdeffsd_req_usage


VRP

#include <vrp.h>

typedef struct _VRP {
    ULONG  VRP_demand_flags;      // demand flags; see below
    ULONG  VRP_event_flags;       // event flags; see below
    USHORT VRP_max_sgd;           // max # of scatter/gather descriptors
    USHORT VRP_max_req_size;      // max size of request packet
    ULONG  VRP_delta_to_ior;      // delta from IOP to IOR
    ULONG  VRP_block_size;        // block size of volume
    ULONG  VRP_fsd_hvol;          // FSD's volume handle
    ULONG  VRP_fsd_entry;         // file system request routine
    ULONG  VRP_device_handle;     // address of handle for device
    ULONG  VRP_partition_offset;  // partition bias for logical volumes
    ULONG  VRP_next_vrp;          // link to next VRP
    ULONG  VRP_logical_handle;    // pointer to logical device handle
    ULONG  VRP_reserved;          // reserved; must be zero
} VRP, *PVRP;
VRP_demand_flags
Demand flags to identify the device requirements the FSD must satisfy. Can be a combination of these values:
VRP_dmd_small_memory | Data buffers must reside in the lower 16 Mb of memory.
VRP_dmd_word_align | Data buffers must be word aligned.
VRP_dmd_dword_align | Data buffers must be double word aligned.
VRP_dmd_phys_sgd | Scatter/gather descriptors must contain physical addresses. If this value is not given, descriptors contain linear addresses.
VRP_dmd_phys_sgd_ptr | Address to the first scatter/gather descriptor (IOR_sgd_lin_phys) must be a physical address. If this value is not given, the first address must be a linear address.
VRP_dmd_do_a_b_toggling | Enable toggling between floppy drives A and B. When this value is set for a single floppy drive system, the volume tracker the toggles between the A and B drives when accessed.
VRP_dmd_removable_supp | Device is removable.
VRP_dmd_lock_unlock_media | Media supports software locking.
VRP_dmd_load_eject_media | Media supports electronic eject.
VRP_dmd_clear_media_chg | Media supports command to clear media change.
VRP_dmd_no_xcl_required | Media allows absolute read/writes without an exclusive lock.
VRP_dmd_pageability | Indicates that access to this volume can cause paging.

VRP_event_flags
Event flags to identify special events. The FSD may ignore these flags provided that it still prevents data corruption. In such cases, the FSD is notified of the event on the next I/O request to the volume. Can be a combination of these values:
VRP_ef_media_changed | The media containing this volume indicated change since most recent I/O operation.
VRP_ef_media_uncertain | The media containing this volume may have been changed since the most recent I/O operation.
VRP_ef_prompting | The media containing this volume is currently being prompted for.
VRP_ef_input_share | The input stream of a character device is sharable.
VRP_ef_output_share | The output stream of a character device is sharable.
VRP_ef_user_canceled | The user has hit CANCEL on a request for reinserting this volume.
VRP_ef_write_protected | This volume is currently write protected.
VRP_ef_real_mode_mapped | This volume is currently accessed through the real mode mapper.
VRP_ef_ios_locked | Device containing given volume is locked.

VRP_max_sgd
Maximum number of scatter/gather descriptors that may be built. The FSD should use the smaller of this value and 17.

See Also

IOP, IOR, IRS


SCSI Port Driver Services Reference

SCSI Port Driver Services Reference contains reference information about the support and services that a SCSI port driver provides for SCSI miniport drivers. The following topics describe the callback routines.


DriverEntry

ULONG DriverEntry(Argument1, Argument2)
IN PVOID  Argument1;
IN PVOID  Argument2;

An HBA-specific miniport driver must supply a routine explicitly named DriverEntry in order to be loaded.

  • Must zero all of the fields in the HW_INITIALIZATION_DATA structure and then initialize it. DriverEntry then calls ScsiPortInitialize, and returns the value returned by ScsiPortInitialize. If the HBA miniport driver supports more than one type of bus, such as MCA and ISA, it should call the ScsiPortInitialize routine once for each supported type. Such a miniport driver should return the lowest value returned by ScsiPortInitialize.
Argument1
Points to a context with which the HBA miniport driver should call ScsiPortInitialize.
Argument2
Points to a second context with which the HBA miniport driver should call ScsiPortInitialize.

A miniport DriverEntry routine allocates memory on its stack and initializes the HW_INITIALIZATION_DATA structure.

All of the fields in the HW_INITIALIZATION_DATA structure must be initialized. DriverEntry then calls ScsiPortInitialize, and it returns the value returned by ScsiPortInitialize.

See Also

HW_INITIALIZATION_DATA, ScsiPortInitialize


HwDmaStarted

PVOID HwDmaStarted(HwDeviceExtension)
IN PVOID  HwDeviceExtension;

If the adapter uses slave DMA, the miniport driver's HwDmaStarted routine is called after the system DMA controller has been set up for a DMA transfer.

HwDeviceExtension
Points to the miniport driver's storage for per-adapter data.

Miniport drivers of host adapters that are busmasters or use programmed I/O need not supply this routine.

See Also

ScsiPortIoMapTransfer


HwFindAdapter

ULONG HwFindAdapter(DeviceExtension, HwContext, BusInformation, ArgumentString,
    ConfigInfo, Again)
IN PVOID  DeviceExtension;
IN PVOID  HwContext;
IN PVOID  BusInformation;
IN PCHAR  ArgumentString;
IN OUT PPORT_CONFIGURATION_INFORMATION  ConfigInfo;
OUT PBOOLEAN  Again;

Returns information about the miniport driver's adapter in the PORT_CONFIGURATION_INFORMATION buffer.

  • Return one of the following status values:
Value | Meaning
SP_RETURN_FOUND | Indicates a host adapter was found and the configuration information was successfully determined.
SP_RETURN_ERROR | Indicates a host adapter was found but there was error obtaining the configuration information. If possible such an error should be logged.
SP_RETURN_BAD_CONFIG | Indicates the supplied configuration information was invalid.
SP_RETURN_NOT_FOUND | Indicates no host adapter was found for the supplied configuration information.

DeviceExtension
Supplies the HBA miniport driver's adapter data storage. This storage is initialized to zero before this routine is called by the OS-dependent port driver.
HwContext
Supplies the context value that was passed to ScsiPortInitialize.
BusInformation
Supplies bus-type-specific information that has been gathered. The format of this information depends on the particular bus type.
ArgumentString
Supplies a zero-terminated ASCII string. This string originates from the user and can be NULL.
ConfigInfo
Returns a pointer to the configuration information structure, which is filled by the HBA miniport driver. This structure is initialized with any known configuration information, such as SystemIoBusNumber. If possible, drivers should have a set of defaults that do not require any supplied configuration information.
Again
Indicates the HBA miniport driver wants the OS-specific port driver to call its HW_FIND_ADAPTER function again with a new DeviceExtension and the same ConfigurationInformation. This is used by the HBA miniport drivers that can search for more than one adapter on a bus.

This function is called by ScsiPortInitialize after the necessary storage has been allocated.

See Also

PORT_CONFIGURATION_INFORMATION


HwInitialize

BOOLEAN HwInitialize(DeviceExtension)
IN PVOID  DeviceExtension;

Initializes the HBA after a boot or a power failure.

  • Returns TRUE if initialization succeeds. Otherwise, returns FALSE and an error is logged.
DeviceExtension
Points to the HBA miniport driver's storage for adapter data.

This routine must initialize the hardware but should avoid resetting the SCSI bus. Interrupts can occur before this routine is called. If the bus is reset, it is reported by calling ScsiPortNotification.

See Also

ScsiPortNotification


HwInterrupt

BOOLEAN HwInterrupt(DeviceExtension)
IN PVOID  DeviceExtension;

Called when the HBA generates an interrupt.

  • Returns FALSE if this function finds that its host bus adapter is not interrupting. Otherwise, returns TRUE after clearing the interrupt.
DeviceExtension
Points to the HBA miniport driver's storage for adapter data.

See Also

ScsiPortNotification


HwResetBus

BOOLEAN HwResetBus(DeviceExtension, PathId)
IN PVOID  DeviceExtension;
IN ULONG  PathId;

Must reset a SCSI bus. The miniport should complete all pending requests.

  • Returns TRUE if the bus is successfully reset; otherwise, returns FALSE.
DeviceExtension
Points to the HBA miniport driver's storage for adapter data.
PathId
Supplies the path ID of the SCSI bus to be reset.

This function can be called even if the miniport driver is not ready for another request. The miniport does not have to send notification that the bus was reset.

See Also

ScsiPortCompleteRequest, ScsiPortNotification


HwStartIo

VOID HwStartIo(DeviceExtension, Srb)
IN PVOID  DeviceExtension;
IN PSCSI_REQUEST_BLOCK  Srb;

Called when the initial request is received and after each subsequent NextRequest or notification is received.

  • No return value.
DeviceExtension
Points to the HBA miniport driver's adapter data storage.
Srb
Points to the SCSI request block to be started.

After this call, the HBA miniport driver owns the request and is expected to complete it.

See Also

ScsiPortNotification


HwTimer

VOID HwTimer(DeviceExtension)
IN PVOID  DeviceExtension;

Called after the interval specified when the miniport driver called ScsiPortNotification with the RequestTimerCall NotificationType value.

  • No return value.
DeviceExtension
Specifies the HBA miniport driver's adapter data storage.

See Also

ScsiPortNotification


ScsiPortConvertPhysicalAddressToUlong

ULONG ScsiPortConvertPhysicalAddressToUlong(Address)
IN SCSI_PHYSICAL_ADDRESS  Address;

Truncates a SCSI_PHYSICAL_ADDRESS to a ULONG.

  • Returns the low-order part of the physical address.
Address
Specifies a value of type SCSI_PHYSICAL_ADDRESS.

See Also

ScsiPortGetPhysicalAddress


ScsiPortConvertUlongToPhysicalAddress

SCSI_PHYSICAL_ADDRESS ScsiPortConvertUlongToPhysicalAddress(UlongAddress)
IN ULONG  UlongAddress;

Takes a ULONG and extends it to a physical address.

  • Returns a SCSI_PHYSICAL_ADDRESS.
UlongAddress
Specifies a ULONG.

See Also

ACCESS_RANGE, ScsiPortGetDeviceBase, ScsiPortGetVirtualAddress


ScsiPortCompleteRequest

VOID ScsiPortCompleteRequest(HwDeviceExtension, PathId, TargetId, Lun, SrbStatus)
IN PVOID  HwDeviceExtension;
IN UCHAR  PathId;
IN UCHAR  TargetId;
IN UCHAR  Lun;
IN UCHAR  SrbStatus;

Completes all of the active requests for the specified logical unit.

  • No return value.
HwDeviceExtension
Points to the HBA miniport driver's storage for per-adapter data.
PathId
Specifies the SCSI bus or path ID.
TargetId
Specifies the target controller; -1 indicates all logical units on the host bus adapter.
Lun
Specifies the logical unit on the target controller(s); -1 indicates all logical units on the target controller(s).
SrbStatus
Identifies the completion status to be stored in the SrbStatus field of each SRB.

ScsiPortCompleteRequest can be called to complete requests after a bus reset, a device reset, or an abort, rather than calling ScsiPortNotification for each request.

See Also

SCSI_REQUEST_BLOCK, ScsiPortNotification


ScsiPortFlushDma

VOID ScsiPortFlushDma(DeviceExtension)
IN PVOID  DeviceExtension;

Flushes any data cached in the system DMA controller at the end of a transfer and terminates a system DMA transfer.

  • No return value.
DeviceExtension
Points to the HBA miniport driver's storage for per-adapter data.

ScsiPortFlushDma must be called after a data transfer operation is completed but before the request is completed or the next call is made to ScsiPortIoMapTransfer for this buffer. This function must be called after ScsiPortIoMapTransfer has been called even if no transfer has occurred or if the driver's HwDmaStarted function has not been called yet.

See Also

HwDmaStarted, ScsiPortIoMapTransfer


ScsiPortFreeDeviceBase

VOID ScsiPortFreeDeviceBase(HwDeviceExtension, MappedAddress)
IN PVOID  HwDeviceExtension;
IN PVOID MappedAddress;

Frees a block of I/O addresses or memory space previously mapped into the system address space.

  • No return value.
HwDeviceExtension
Points to the HBA miniport driver's storage for per-adapter data.
MappedAddress
Is the address to be freed. This pointer must be the same as that returned by ScsiPortGetDeviceBase.

If the HBA miniport driver determines that the device base is not needed, it should release the mapping by calling this function. For example, when the driver determines there are no support HBAs on an I/O bus, it should call ScsiPortFreeDeviceBase with each base address returned by the miniport driver's calls to ScsiPortGetDeviceBase.

ScsiPortFreeDeviceBase can be called only from HBA miniport driver's HwFindAdapter routine. Calls from other HBA miniport driver functions will result in system failure or an incorrect operation.

See Also

HwFindAdapter, ScsiPortGetDeviceBase


ScsiPortGetBusData

ULONG ScsiPortGetBusData(DeviceExtension, BusDataType, SystemIoBusNumber,
    Slotnumber, Buffer, Length)
IN PVOID  DeviceExtension;
IN ULONG  BusDataType;
IN ULONG  SystemIoBusNumber;
IN ULONG  SlotNumber;
IN PVOID  Buffer;
IN ULONG  Length;

Gets bus-type-specific information.

  • Returns the number of bytes that were actually returned.
DeviceExtension
Points to the HBA miniport driver's storage for per-adapter data.
BusDataType
Specifies the type of bus-specific data. Recognized information comes from CMOS, EISA, POS, CBUS, PCIC, and VME sources.
SystemIoBusNumber
Specifies which of the buses of the same type should be addressed. This value can be retrieved from the PORT_CONFIGURATION_INFORMATION structure.
SlotNumber
Specifies the slot to be accessed.
Buffer
Specifies where the retrieved data should be stored.
Length
Specifies the amount of data to retrieved.

This function can be called only from a miniport driver's HwFindAdapter routine. Calls to ScsiPortGetBusData from other miniport driver functions will result in system failure or an incorrect operation.

If Length is zero, the buffer is treated as a pointer to where the pointer to the buffer should be stored. The port driver will allocate a buffer for the data. The pointer to this buffer is returned in the location pointed to by Buffer. This data is valid only until this function is called again or HwFindAdapter returns.

In the case of the PCI bus, you can also access its configuration space using CONFIGMG_Call_Enumerator_Function. See KB article Q140730 (Accessing PCI Device's Configuration Space from Device Driver).

See Also

PORT_CONFIGURATION_INFORMATION, HwFindAdapter


ScsiPortGetDeviceBase

PVOID ScsiPortGetDeviceBase(HwDeviceExtension, BusType, SystemIoBusNumber,
    IoAddress, NumberOfBytes, InIoSpace)
IN PVOID  HwDeviceExtension;
IN INTERFACE_TYPE  BusType;
IN ULONG  SystemIoBusNumber;
IN SCSI_PHYSICAL_ADDRESS  IoAddress;
IN ULONG  NumberOfBytes;
IN BOOLEAN  InIoSpace;

Returns a mapped system address that must be used to adjust device address ranges in that HBA's ACCESS_RANGE elements.

  • Returns NULL if the address cannot be mapped.
HwDeviceExtension
Points to the HBA miniport driver's storage for adapter data.
BusType
Specifies the type of bus, such as ISA or MCA. This value can be retrieved from the PORT_CONFIGURATION_INFORMATION structure.
SystemIoBusNumber
Specifies on which bus the HBA is connected. This value can be retrieved from the PORT_CONFIGURATION_INFORMATION structure.
IoAddress
Specifies the starting physical base address for the HBA.
NumberOfBytes
Specifies the range, in bytes, that the mapping covers. The driver must not access the hardware outside of this range.
InIoSpace
Specifies whether the address is in I/O space; otherwise, it is in memory space.

ScsiPortGetDeviceBase can be called only from an HBA miniport driver's HwFindAdapter routine. Calls from other HBA miniport driver routines result in system failure or in an incorrect operation. ScsiPortGetDeviceBase can be called several times.

Windows NT/Windows 2000 machines can have several I/O buses, or the system can map I/O space to memory. In order to make HBA miniport drivers portable, the addresses they use must be translated. The returned base address should be added to all references made to the hardware. Driver writers should make no assumptions about how many bits are used in the returned base address.

The following KB article describes a bug in the ScsiPortGetDeviceBase function which appears when you attempt to do memory mapped I/O: Q169584, BUG: Win95: ScsiPortGetDeviceBase Does Not Return Linear Address.

Note that the problem described won't happen if you use I/O mapping.

This problem does not frequently appear because most SCSI cards (at least PCI cards) have both a memory window and an I/O window. SCSIPORT.PDR will always default to the I/O window in these cases, thus avoiding use of the memory window.

When you call ScsiPortGetDeviceBase, you should check the returned address against the actual physical address. If they are the same, you need to call _MapPhysToLinear to obtain a linear address; otherwise, assume that the bug has been corrected. This is to accommodate any future bug fix. Note that _MapPhysToLinear call "breaks" Windows NT/Windows 2000 miniport compatibility. If you want Windows NT/Windows 2000 compatibility, you need to do conditional compilation, resulting in a different binary miniport for Windows NT/Windows 2000.

In order to incorporate _MapPhysToLinear into your miniport, you will need to include the DDK's "vxd wrappers": Setup your code as described in the following. (See also Walt Oney's book, Systems Programming for Windows 95, page 131):

#define WANTVXDWRAPS
#include <vmm.h>
#include <vxdwraps.h>.

See Also

HwFindAdapter, ScsiPortFreeDeviceBase


ScsiPortGetLogicalUnit

PVOID ScsiPortGetLogicalUnit(HwDeviceExtension, PathId, TargetId, Lun)
IN PVOID  HwDeviceExtension;
IN UCHAR  PathId;
IN UCHAR  TargetId;
IN UCHAR  Lun;

Provides access to logical-unit-specific data for a device on the bus.

  • Returns a pointer to the storage for the requested logical unit. If the OS-specific port driver considers this logical unit to be unequipped, it returns NULL.
HwDeviceExtension
Points to the HBA miniport driver's storage for per-adapter data.
PathId
Identifies the SCSI bus.
TargetId
Identifies the target ID on the bus.
Lun
Identifies the logical unit number of the target device.

This storage can be used by the HBA miniport driver to store per-logical-unit data, such as saved data pointers. The storage is initialized to zero.

The OS-specific port driver can consider a logical unit to be unequipped if there is no active request for the logical unit and the device has never been successfully selected.


ScsiPortGetPhysicalAddress

SCSI_PHYSICAL_ADDRESS ScsiPortGetPhysicalAddress(HwDeviceExtension, Srb,
    VirtualAddress, Length)
IN PVOID  HwDeviceExtension;
IN PSCSI_REQUEST_BLOCK  Srb;    /* optional    */
IN PVOID  VirtualAddress;
OUT ULONG  *Length;

Translates a virtual address range to a physical address range for a DMA operation.

  • Returns the physical address of VirtualAddress which is used by a master host adapter to access memory.
HwDeviceExtension
Points to the miniport driver's storage for per-adapter data.
Srb
Points to a SCSI request block, if the VirtualAddress to be translated comes from an SRB's DataBuffer field; otherwise, this pointer is NULL.
VirtualAddress
Specifies the virtual address to be translated. The Srb pointer is required if the address came from the DataBuffer field of an SRB.
Length
See the following.

An Srb parameter is not required if the VirtualAddress is in an UncachedExtension, SenseInfoBuffer or the SrbExtension. If an Srb is provided, the VirtualAddress must be within the range of DataBuffer or must be the pointer from SenseInfoBuffer field specified by the Srb. This function can be called to translate an extension address only if NeedPhysicalAddresses was specified in the HW_INITIALIZATION_DATA structure.

ScsiPortGetPhysicalAddress can be used to build a scatter/gather list for data transfers that span pages. Note that the Length returned can be greater than the length of the DataBuffer specified in the Srb parameter.

The general function performed by ScsiPortGetPhysicalAddress follows:

  1. 1. If (Srb != NULL) && (VirtualAddress lies within the Srb's DataBuffer) scan the corresponding IOP's IOR_sgd_lin_phys field to obtain the desired SG element and physical offset within that element. The returned length is the number of bytes from the offset within the SG element, to the end of the SG element.

    (else)

  2. 2. If (VirtualAddress lies within the IOP Memory Pool)

    The physical address is obtained by finding the offset within the memory pool and adding IDA_ios_mem_phys to the offset value. The returned Length is ALWAYS 4096.

    (else)

  3. 3. _Obtain the physical address using _CopyPageTable(VirtualAddress/4096, 1, Pte, 0).

    PhysAddr = (Pte & 0xFFFFF000) + (VirtualAddress & 0xFFF).

    Pte is the Page Table Entry as described in the Pentium Processor Users Manual Volume 3.

    The returned Length is ALWAYS 4096.

Based on the above info, one cannot always rely on the returned Length containing the correct length; it may be longer than the actual buffers.

See Also

HW_INITIALIZATION_DATA, SCSI_REQUEST_BLOCK, ScsiPortGetUncachedExtension, ScsiPortGetVirtualAddress


ScsiPortGetSrb

PSCSI_REQUEST_BLOCK ScsiPortGetSrb(DeviceExtension, PathId, TargetId, Lun, QueueTag)
IN PVOID  DeviceExtension;
IN UCHAR  PathId;
IN UCHAR  TargetId;
IN UCHAR  Lun;
IN LONG  QueueTag;

Retrieves an active SCSI request for a particular logical unit.

  • Returns a pointer to a request for the specified logical unit. If there is no outstanding request for the specified logical unit or if the QueueTag value is invalid, then NULL is returned.
DeviceExtension
Points to the miniport driver's storage for per-adapter data.
PathId
Identifies the SCSI bus.
TargetId
Identifies the target ID on the bus.
Lun
Identifies the logical unit number of the target device.
QueueTag
Specifies the queue tag if the request is tagged; SP_UNTAGGED indicates that the request is not tagged.


ScsiPortGetUncachedExtension

PVOID ScsiPortGetUncachedExtension(HwDeviceExtension, ConfigInfo, NumberOfBytes)
IN PVOID  HwDeviceExtension;
IN PPORT_CONFIGURATION_INFORMATION  ConfigInfo;
IN ULONG  NumberOfBytes;

Allocates memory that can be used by both the CPU and host bus adapter for DMA or shared data.

  • Returns an address for the uncached extension. If the memory cannot be allocated, NULL is returned.
HwDeviceExtension
Points to the miniport driver's storage for per-adapter data.
ConfigInfo
Specifies information about the adapter's DMA capabilities. The following members must be filled-in: DmaChannel or DmaPort, DmaWidth, DmaSpeed, MaximumLength, ScatterGather, Master, NumberOfPageBreaks, AdapterInterfaceType, Dma32BitAddresses, SystemIoBusNumber, and AutoRequestSense.

Members that are not pertinent to the HBA, such as DmaChannel for an EISA master adapter, must be left alone.

NumberOfBytes
Indicates the size, in bytes, of the uncached extension to be allocated.

This function can be called only from HBA miniport driver's HwFindAdapter routine. Calls to ScsiPortGetUncachedExtension from other miniport driver functions will result in either a system failure or an incorrect operation.

Because new machines have caches and large memories, any memory shared between the host bus adapter and the CPU must be specially allocated. Mailboxes or I/O request queues in system memory are examples of this shared memory.

The allocation of memory can be done only once per HBA.

Use ScsiPortGetPhysicalAddress to find the physical address of the uncached extension.

Under Windows 95, this extension is allocated using the IOS memory pool (ISP_Alloc_Mem, memory type MED_MISC) if the amount of memory requested is less than or equal to 1024 bytes. Otherwise, the memory allocation is made using _PageAllocate, obtaining system memory (PG_SYS) with the following flags: PAGEZEROINIT, PAGEUSEALIGN (4K), PAGEFIXED, PAGECONTIG.

See Also

PORT_CONFIGURATION_INFORMATION, HwFindAdapter, ScsiPortGetPhysicalAddress


ScsiPortGetVirtualAddress

PVOID ScsiPortGetVirtualAddress(HwDeviceExtension, PhysicalAddress)
IN PVOID  HwDeviceExtension;
IN SCSI_PHYSICAL_ADDRESS  PhysicalAddress;

Maps a physical address to a virtual address.

  • Returns NULL if the PhysicalAddress parameter is invalid.
HwDeviceExtension
Points to the miniport driver's storage for per-adapter data.
PhysicalAddress
Specifies the physical address to be converted. The input address must have been returned by ScsiPortGetPhysicalAddress and must be from a noncached device extension or SRB extension.

See Also

ScsiPortGetPhysicalAddress


ScsiPortInitialize

ULONG ScsiPortInitialize(Argument1, Argument2, HwInitializationData, HwContext)
IN PVOID  Argument1;
IN PVOID  Argument2;
IN struct _HW_INITIALIZATION_DATA *HwInitializationData;
IN PVOID  HwContext;

Sets up system objects on behalf of the HBA miniport driver.

  • Returns a status value that is used as the return value for DriverEntry.
Argument1
Supplies the first parameter value with which the operating system called the HBA miniport driver's initialization routine.
Argument2
Supplies the second parameter value with which the operating system called the HBA miniport driver's initialization routine.
HwInitializationData
Supplies the initialization parameters for the HBA miniport driver.
HwContext
Supplies a context value which is later passed to the miniport driver's HwFindAdapter function. This context parameter can be used to store state between calls to the HwFindAdapter function.

ScsiPortInitialize is called by the HBA miniport driver's initial entry point (DriverEntry) after the miniport has zeroed and set up the HW_INITIALIZATION_DATA. If the HBA miniport driver can support more than one HBA, on different types of I/O buses, such as ISA and MCA, then the HBA miniport driver should call this function for each supported interface type.

See Also

DriverEntry, HW_INITIALIZATION_DATA, HwFindAdapter


ScsiPortIoMapTransfer

VOID ScsiPortIoMapTransfer(HwDeviceExtension, Srb, LogicalAddress, Length)
IN PVOID  HwDeviceExtension;
IN PSCSI_REQUEST_BLOCK  Srb;
IN ULONG  LogicalAddress;
IN ULONG  Length;

Sets up the system DMA controller for the miniport driver to transfer data through the HBA.

  • No return value.
HwDeviceExtension
Points to the miniport driver's storage for adapter data.
Srb
Point to the SCSI request block for the transfer.
LogicalAddress
Specifies the starting address of the buffer containing the data to be transferred.
Length
Specifies the length of the buffer containing data to be transferred.

ScsiPortIoMapTransfer is called by miniport drivers of HBAs that use the system DMA controller (slave DMA). This function must be called before the host bus adapter is set up to transfer data. The range specified by the LogicalAddress and Length must be within the buffer defined by the Srb.

After the OS-specific port driver has programmed the system DMA controller, the OS-specific port driver calls the HBA miniport driver's HwDmaStarted routine, which should program the HBA to begin the data transfer. Note that the HBA can interrupt between the call to ScsiPortIoMapTransfer and that to the HwDmaStarted routine.

See Also

HwDmaStarted, ScsiPortFlushDma


ScsiPortLogError

VOID ScsiPortLogError(HwDeviceExtension, Srb, PathId, TargetId, Lun, ErrorCode, UniqueId)
IN PVOID  HwDeviceExtension;
IN PSCSI_REQUEST_BLOCK  Srb;    /* optional    */
IN UCHAR  PathId;
IN UCHAR  TargetId;
IN UCHAR  Lun;
IN LONG  ErrorCode;
IN LONG  UniqueId;

Logs errors that are detected by the miniport driver or HBA.

  • No return value.
HwDeviceExtension
Identifies the HBA miniport driver's storage for adapter data.
Srb
Points to a SCSI request block if one is associated with the error.
PathId
Identifies the SCSI bus.
TargetId
Identifies the target ID on the bus.
Lun
Identifies the logical unit number of the target device.
ErrorCode
Specifies an error code indicating one of the following values as the type of error:
Values | Meaning
SP_PROTOCOL_ERROR | Indicates the HBA miniport driver detected a SCSI bus protocol error.
SP_BUS_PARITY_ERROR | Indicates a SCSI bus parity error was detected.
SP_INTERNAL_ADAPTER_ERROR | Indicates an internal HBA error was detected.
SP_UNEXPECTED_DISCONNECT | Indicates that a target disconnected unexpectedly.
SP_INVALID_RESELECTION | Indicates a logical unit reselected unexpectedly or with an invalid queue tag.
SP_BUS_TIME_OUT | Indicates a SCSI bus connection to a logical unit timed out.
SP_REQUEST_TIMEOUT | Indicates an operation to the controller has timed out.
SP_IRQ_NOT_RESPONDING | Indicates the card is not interrupting when expected.
SP_BAD_FW_ERROR | Indicates the driver has detected bad or old firmware. The device will not be used.
SP_BAD_FW_WARNING | Indicates the driver has detected a card with old or bad firmware which then results in reduced performance.

UniqueId
Specifies a unique identifier for the error. The value differentiates the error from other errors with the same ErrorCode. For some HBA miniport drivers, this identifies the line of code where the error was detected; for others, it is any additional information returned by the HBA.

All real errors should be logged; however, errors such as selection time out or reset detected should not be logged. Recoverable errors should be retried after they have been logged.

See Also

ScsiPortNotification


ScsiPortNotification

VOID ScsiPortNotification(NotificationType, HwDeviceExtension, ...)
IN SCSI_NOTIFICATION_TYPE  NotificationType;
IN PVOID  HwDeviceExtension;

Notifies the port driver if the HBA indicates that certain SCSI error conditions occurred during the operation.

  • No return value.
NotificationType
Specifies the type of notification.
Notification | Types
RequestComplete | Indicates the supplied Srb has finished. After this notification, the OS-specific port driver owns the request, so it must not be accessed by the HBA miniport driver.
NextRequest | Indicates the HBA miniport driver is ready for another request. This notification should be sent from the HW_STARTIO routine, as soon as the HBA miniport driver is ready for another request.
NextLuRequest | Indicates that the host bus adapter is ready for a another request and that an additional request can be sent for the specified logical unit. This value should be used only if the HBA can queue multiple requests and support auto request sense or tagged queuing.
ResetDetected | Indicates that the HBA has detected a reset on the SCSI bus. After this notification, the HBA miniport driver is still responsible for completing any active requests.
CallDisableInterrupts | Indicates that the miniport driver requires system interrupts to be re-disabled. While system interrupts remain enabled, the miniport driver's HW_INTERRUPT routine will not be called.
CallEnableInterrupts | Indicates that the miniport driver would like system interrupts re-enabled and passes the miniport's callback routine. Normally the miniport driver uses this notification to enable interrupts on the HBA.
RequestTimerCall | Indicates the miniport has requested a specified routine be called in a requested number of microseconds. This parameter requires two additional arguments.
A pointer to HW_TIMER, which is called after the time-out period specified in TimerValue.
TimerValue is a ULONG in microseconds. Note that the resolution of the timer is approximately 10 milliseconds.

HwDeviceExtension
Points to the miniport driver's storage for per-adapter data.

This function is used to notify the OS-specific port driver of various events.

ScsiPortNotification is called twice for each call to the miniport's HwStartIo routine. Once with the NotificationType NextRequest or NextLuRequest if the miniport supports tagged queuing or multiple requests per lu, and with a NotificationType RequestComplete and the just satisfied request.


ScsiPortReadPortBufferUchar

VOID ScsiPortReadPortBufferUchar(Port, Buffer, Count)
IN PUCHAR  Port;
IN PUCHAR  Buffer;
IN ULONG  Count;

Transfers a given number of unsigned byte values from an HBA's I/O port into the specified buffer.

  • No return value.
Port
Points to the port.
Buffer
Points to the buffer.
Count
Specifies the number of bytes to be read.

ScsiPortReadPortBufferUchar ensures that the data is transferred correctly.


ScsiPortReadPortBufferUlong

VOID ScsiPortReadPortBufferUlong(Port, Buffer, Count)
IN PULONG  Port;
IN PULONG  Buffer;
IN ULONG  Count;

Transfers a given number of ULONG values from an HBA's I/O port into the specified buffer.

  • No return value.
Port
Points to the port address.
Buffer
Points to the buffer.
Count
Specifies the number of ULONG values to read.

ScsiPortReadPortBufferUlong ensures that the data is transferred correctly.


ScsiPortReadPortBufferUshort

VOID ScsiPortReadPortBufferUshort(Port, Buffer, Count)
IN PUSHORT  Port;
IN PUSHORT  Buffer;
IN ULONG  Count;

Reads a given number of USHORT values from an HBA's I/O port into the specified buffer.

  • No return value.
Port
Points to the port.
Buffer
Points to the buffer.
Count
Specifies the number of USHORT values to read.

ScsiPortReadPortBufferUshort ensures that the data is transferred correctly.


ScsiPortReadPortUchar

UCHAR ScsiPortReadPortUchar(Port)
IN PUCHAR  Port;

Reads a value from the specified port/memory location.

  • Returns an unsigned byte from an HBA's I/O port.
Port
Points to the port.

ScsiPortReadPortUchar ensures that the data is transferred correctly.


ScsiPortReadPortUlong

ULONG ScsiPortReadPortUlong(Port)
IN PULONG  Port;

Reads a value from the specified port/memory location.

  • Returns a ULONG value from an HBA's I/O port.
Port
Points to the port address.

ScsiPortReadPortUlong ensures that the data is transferred correctly.


ScsiPortReadPortUshort

USHORT ScsiPortReadPortUshort(Port)
IN PUSHORT  Port;

Read a value from the specified port/memory location.

  • Returns a USHORT value from an HBA's I/O port.
Port
Points to the port.

This function ensures that the data is transferred correctly.


ScsiPortReadRegisterBufferUchar

VOID ScsiPortReadRegisterBufferUchar(Register, Buffer, Count)
IN PUCHAR  Register;
IN PUCHAR  Buffer;
IN ULONG  Count;

Transfers a specified number of unsigned bytes from the HBA's memory mapped register into the specified buffer.

Register
Points to the register.
Buffer
Points to the buffer.
Count
Specifies the number of bytes to be read.

ScsiPortReadRegisterBufferUchar ensures that the data is transferred correctly.


ScsiPortReadRegisterBufferUlong

VOID ScsiPortReadRegisterBufferUlong(Register, Buffer, Count)
IN PULONG  Register;
IN PULONG  Buffer;
IN ULONG  Count;

Transfers a specified number of ULONG values from the HBA's memory mapped register into the specified buffer.

  • No return value.
Register
Points to the register.
Buffer
Points to the buffer.
Count
Specifies the number of ULONG values to be read.

ScsiPortReadRegisterBufferUlong ensures that the data is transferred correctly.


ScsiPortReadRegisterBufferUshort

VOID ScsiPortReadRegisterBufferUshort(Register, Buffer, Count)
IN PUSHORT  Register;
IN PUSHORT  Buffer;
IN ULONG  Count;

Transfers a specified number of USHORT values from the HBA's memory mapped register into the specified buffer.

  • No return value.
Register
Points to the register.
Buffer
Points to the buffer.
Count
Specifies the number of USHORT values to be read.

ScsiPortReadRegisterBufferUshort ensures that the data has been transferred correctly.


ScsiPortReadRegisterUchar

UCHAR ScsiPortReadRegisterUchar(Register)
IN PUCHAR  Register;

Reads a value for the HBA's memory mapped register.

  • Returns an unsigned byte from the HBA's register.
Register
Points to the register.

ScsiPortReadRegisterUchar ensures that the data is transferred correctly.


ScsiPortReadRegisterUlong

ULONG ScsiPortReadRegisterUlong(Register)
IN PULONG  Register;

Reads a value from the specified memory mapped register address.

  • Returns a ULONG value from the HBA's register.
Register
Points to the register.

ScsiPortReadRegisterUlong ensures that data is transferred correctly.

This function was not correctly exported in SCSIPORT.PDR. See KB Article Q160667, Miniport Driver Fails Using Certain ScsiPort APIs, for more information.


ScsiPortReadRegisterUshort

USHORT ScsiPortReadRegisterUshort(Register)
IN PUSHORT  Register;

Reads a value from the specified memory mapped register address.

  • Returns a USHORT value from the HBA's register.
Register
Points to the register.

ScsiPortReadRegisterUshort ensures that the data is transferred correctly.

This function was not correctly exported in SCSIPORT.PDR. See KB Article Q160667, Miniport Driver Fails Using Certain ScsiPort APIs, for more information.


ScsiPortSetBusDataByOffset

ULONG ScsiPortGetBusData(DeviceExtension, BusDataType, SystemIoBusNumber,
    Slotnumber, Buffer, Offset, Length)
IN PVOID  DeviceExtension;
IN ULONG  BusDataType;
IN ULONG  SystemIoBusNumber;
IN ULONG  SlotNumber;
IN PVOID  Buffer;
IN ULONG  Length;

Sets bus-type-specific information for the specified bus and slot.

  • Returns the number of bytes that were actually set.
DeviceExtension
Points to the HBA miniport driver's storage for per-adapter data.
BusDataType
Specifies the type of bus-specific data. Recognized information comes from CMOS, EISA, POS, CBUS, PCIC, and VME sources.
SystemIoBusNumber
Specifies which of the buses of the same type should be addressed. This value can be retrieved from the PORT_CONFIGURATION_INFORMATION structure.
SlotNumber
Specifies the slot to be accessed.
Buffer
Specifies where the retrieved data should be stored.
Length
Specifies the amount of data to retrieved.

This function can be called only from a miniport driver's HwFindAdapter routine. Calls to ScsiPortGetBusData from other miniport driver functions will result in system failure or an incorrect operation.

If Length is zero, the buffer is treated as a pointer to where the pointer to the buffer should be stored. The port driver will allocate a buffer for the data. The pointer to this buffer is returned in the location pointed to by Buffer. This data is valid only until this function is called again or HwFindAdapter returns.

In the case of the PCI bus, you can also access its configuration space using CONFIGMG_Call_Enumerator_Function. See KB article Q140730 (Accessing PCI Device's Configuration Space from Device Driver).

See Also

PORT_CONFIGURATION_INFORMATION, HwFindAdapter


ScsiPortStallExecution

VOID ScsiPortStallExecution(Delay)
IN ULONG  Delay;

Stalls in the HBA miniport driver.

  • No return value.
Delay
Specifies the delay interval in microseconds.

This routine should be used sparingly and the total stall time in a HBA miniport driver routine must be less than 1 millisecond. In general, this routine should be called only when the driver must wait for a state change on the HBA that will not cause an interrupt, or for when the driver must delay between accesses to the HBA.


ScsiPortWritePortBufferUchar

VOID ScsiPortWritePortBufferUchar(Port, Buffer, Count)
IN PUCHAR  Port;
IN PUCHAR  Buffer;
IN ULONG  Count;

Transfers a given number of unsigned bytes from the specified buffer to an I/O port.

  • No return value.
Port
Points to the port.
Buffer
Points to a buffer.
Count
Specifies the number of bytes to be written.


ScsiPortWritePortBufferUlong

VOID ScsiPortWritePortBufferUlong(Port, Buffer, Count)
IN PULONG  Port;
IN PULONG  Buffer;
IN ULONG  Count;

Transfers a given number of ULONG values from the specified buffer to an I/O port.

  • No return value.
Port
Points to the port.
Buffer
Points to the buffer.
Count
Specifies the number of ULONG values to be written.


ScsiPortWritePortBufferUshort

VOID ScsiPortWritePortBufferUshort(Port, Buffer, Count)
IN PUSHORT  Port;
IN PUSHORT  Buffer;
IN ULONG  Count;

Transfers a given number of USHORT values from the specified buffer to an I/O port.

  • No return value.
Port
Points to the port.
Buffer
Points to the buffer.
Count
Specifies the number of USHORT values to be written.


ScsiPortWritePortUchar

VOID ScsiPortWritePortUchar(Port, Value)
IN PUCHAR  Port;
IN UCHAR  Value;

Transfers an unsigned byte value to an I/O port.

  • No return value.
Port
Points to the port.
Value
Specifies the value to be written to the port.


ScsiPortWritePortUlong

VOID ScsiPortWritePortUlong(Port, Value)
IN PULONG  Port;
IN ULONG  Value;

Transfers a ULONG value to an I/O port.

  • No return value.
Port
Points to the port.
Value
Specifies the value to be written to the port.


ScsiPortWritePortUshort

VOID ScsiPortWritePortUshort(Port, Value)
IN PUSHORT  Port;
IN USHORT  Value;

Transfers a USHORT value to an I/O port.

  • No return value.
Port
Points to the port.
Value
Specifies the value to be written to the port.


ScsiPortWriteRegisterBufferUchar

VOID ScsiPortWriteRegisterBufferUchar(Register, Buffer, Count)
IN PUCHAR  Register;
IN PUCHAR  Buffer;
IN ULONG  Count;

Transfers a given number of unsigned bytes from the specified buffer to a memory mapped register.

  • No return value.
Register
Points to the memory mapped register.
Buffer
Points to the buffer.
Count
Specifies the number of bytes to be written.


ScsiPortWriteRegisterBufferUlong

VOID ScsiPortWritePortBufferUlong(Register, Buffer, Count)
IN PULONG  Register;
IN PULONG  Buffer;
IN ULONG  Count;

Transfers a given number of ULONG values from the specified buffer to a memory mapped register.

  • No return value.
Register
Points to the memory mapped register.
Buffer
Points to the buffer.
Count
Specifies the number of ULONG values to be written.


ScsiPortWriteRegisterBufferUshort

VOID ScsiPortWritePortBufferUshort(Register, Buffer, Count)
IN PUSHORT  Register;
IN PUSHORT  Buffer;
IN ULONG  Count;

Transfers a given number of USHORT values from the specified buffer to a memory mapped register.

  • No return value.
Register
Points to the memory mapped register.
Buffer
Points to the buffer.
Count
Specifies the number of USHORT values to be written.


ScsiPortWriteRegisterUchar

VOID ScsiPortWriteRegisterUchar(Register, Value)
IN PCHAR  Register;
IN UCHAR  Value;

Transfers an unsigned byte value to a memory mapped register.

  • No return value.
Register
Points to the register.
Value
Specifies the value to be written to the register.


ScsiPortWriteRegisterUlong

VOID ScsiPortWriteRegisterUlong(Register, Value)
IN PLONG  Register;
IN ULONG  Value;

Transfers a ULONG value to a memory mapped register.

  • No return value.
Register
Points to the register.
Value
Specifies the value to be written to the register.


ScsiPortWriteRegisterUshort

VOID ScsiPortWriteRegisterUshort(Register, Value)
IN PSHORT  Register;
IN USHORT  Value;

Transfers a USHORT value to a memory mapped register.

  • No return value.
Register
Points to the register.
Value
Specifies the value to be written to the register.


ACCESS_RANGE

typedef struct _ACCESS_RANGE {
    SCSI_PHYSICAL_ADDRESS RangeStart;
    ULONG RangeLength;
    BOOLEAN RangeInMemory;
} ACCESS_RANGE, *PACCESS_RANGE;

An ACCESS_RANGE indicates to the system which port and memory range is being used by the HBA.

RangeStart
Specifies the starting address. This value should be set before the base offset returned from ScsiPortGetDeviceBase is added to the RangeStart.
RangeLength
Specifies the length, in bytes, or number of ports in the range. This value indicates the range actually decoded by the adapter. For example, if the adapter uses seven registers but responds to eight, the RangeLength should be set to 8.
RangeInMemory
Indicates the range is in memory, rather than in I/O space.

See Also

PORT_CONFIGURATION_INFORMATION, ScsiPortConvertUlongToPhysicalAddress, ScsiPortGetDeviceBase


HW_INITIALIZATION_DATA

typedef struct _HW_INITIALIZATION_DATA {
    ULONG HwInitializationDataSize;
    INTERFACE_TYPE AdapterInterfaceType;
    PHW_INITIALIZE HwInitialize;
    PHW_STARTIO HwStartIo;
    PHW_INTERRUPT HwInterrupt;
    PHW_FIND_ADAPTER HwFindAdapter;
    PHW_RESET_BUS_BUS HwResetBus;
    PHW_DMA_STARTED HwDmaStarted;
    PHW_ADAPTER_STATE HwAdapterState;
    ULONG DeviceExtensionSize;
    ULONG SpecificLuExtensionSize;
    ULONG SrbExtensionSize;
    ULONG NumberOfAccessRanges;
    PVOID Reserved;
    BOOLEAN MapBuffers;
    BOOLEAN NeedPhysicalAddresses;
    BOOLEAN TaggedQueuing;
    BOOLEAN AutoRequestSense;
    BOOLEAN MultipleRequestPerLu;
    BOOLEAN ReceiveEvent;
    BOOLEAN RealModeInitialized;
    BOOLEAN BufferAccessScsiPortControlled;
    UCHAR   MaximumNumberOfTargets;
    UCHAR   ReservedUchars[2];
    ULONG SlotNumber;
    ULONG BusInterruptLevel2;
    ULONG BusInterruptVector2;
    KINTERRUPT_MODE InterruptMode2;
    ULONG DmaChannel2;
    ULONG DmaPort2;
    DMA_WIDTH DmaWidth2;
    DMA_SPEED DmaSpeed2;
} HW_INITIALIZATION_DATA, *PHW_INITIALIZATION_DATA;

HW_INITIALIZATION_DATA provides hardware-specific initialization data for DriverEntry.

HwInitializationDataSize
Supplies the size of the structure, in bytes, as reported by the sizeof() function.
AdapterInterfaceType
Indicates the type of bus that the host bus adapter plugs into.
HwInitialize
Points to the HBA miniport driver's adapter initialization routine, which is a required entry point for all miniport drivers.
HwStartIo
Points to the HBA miniport driver's adapter start I/O routine. This is an optional entry point and it can be set to NULL.
HwInterrupt
Points to the HBA miniport driver's adapter interrupt service routine, a required entry point for all miniport drivers. For HBAs that don't use interrupts, this is an optional entry point; the field can be set to NULL.
HwFindAdapter
Points to the HBA miniport driver's find adapter routine, a required entry point for all miniport drivers.
HwResetBus
Points to the HBA miniport driver's reset SCSI bus routine, a required entry point for all miniport drivers.
HwDmaStarted
Points to the HBA miniport driver's DMA started routine. This is an optional entry point and it can be set to NULL for HBAs that are busmasters or that use PIO.
HwAdapterState
Points to the HBA miniport adapter routine. This is an optional entry point; the field can be set to NULL.
DeviceExtensionSize
Supplies the size, in bytes, required by the HBA miniport driver for its device extension. This storage is used by the HBA miniport driver to hold per-adapter information. This size is exclusive of the per-logical-unit data, defined next. A pointer to this storage is supplied with every call to the HBA miniport driver. This data is initialized to zero by the OS-specific port driver.
SpecificLuExtensionSize
Supplies the size, in bytes, of the per-logical-unit storage required by the HBA miniport driver. This data storage is used by the HBA miniport driver to hold per-logical-unit data. This data is initialized to zero by the OS-specific port driver. For some adapters this value can be zero.
SrbExtensionSize
Supplies the size, in bytes, of the per-request storage required by the HBA miniport driver. This data storage is used by the HBA miniport driver to hold data necessary to process the request. A pointer to this storage is in the SCSI_REQUEST_BLOCK. This storage is not initialized by the OS-specific port driver. This data is suitable for access by the host bus adapter hardware. For some adapters this value can be zero.
NumberOfAccessRanges
Supplies the number of access ranges used by the adapter. An access range is a range of either memory addresses or I/O port addresses. A typical card will use two ranges, one for the I/O ports and another for the memory address.
Reserved
Reserved for future use. Use of this member could cause problems in future releases.
MapBuffers
Indicates that all data buffer addresses must be mapped to virtual addresses for access by the HBA miniport driver.
NeedPhysicalAddresses
Indicates that the HBA miniport driver needs to translate extension addresses to physical addresses.
TaggedQueuing
Indicates whether the HBA miniport driver can support SCSI-II tagged queuing when TRUE.
AutoRequestSense
Indicates the host bus adapter can perform a request sense without a separate request. Only intelligent adapters with built-in firmware to perform the request sense should set this field to TRUE.
MultipleRequestPerLu
Indicates that the HBA miniport driver can queue multiple requests per logical unit. In particular, this is used by intelligent adapters that can queue the requests in the adapter. The SRB QueueTag field is used for these type of requests, but the SRB_FLAGS_QUEUE_ACTION_ENABLE is not set in the SrbFlags field. Note that the host bus adapter must support auto request sense to enable this feature.
ReceiveEvent
Indicates the adapter supports the receive event SRB for SCSI-II asynchronous events.
RealModeInitialized
Port configuration information if Windows 95 can determine that real mode adapter initialization has occurred. The value of this member should be saved away in the device extension for the miniport driver and be used by the HW_INITIALIZE and possibly other routines.
BufferAccessScsiPortControlled
Indicates that the miniport will not touch the data buffers directly. Used only in Windows 95, not in Windows NT/Windows 2000. Refer to KB Article Q116450, BufferAccessScsiPortControlled Flag Information.
MaximumNumberOfTargets
Indicator for wide SCSI.
ReservedUchars
Ensure quadword alignment.
SlotNumber
Specifies the slot to be accessed.
BusInterruptLevel2
Optional value for a second interrupt. This field is irrelevant if the miniport has no HwInterrupt routine.
BusInterruptVector2
Optional value for a second interrupt. This field is irrelevant if the miniport has no HwInterrupt routine.
InterruptMode2
Optional value for a second interrupt. This field is irrelevant if the miniport has no HwInterrupt routine.
DmaChannel2
Optional value for a second DMA channel.
DmaPort2
Optional port value for a second DMA channel.
DmaWidth2
Optional width value for a second DMA channel.
DmaSpeed2
Optional speed value for a second DMA channel.

The miniport driver must initialize the HW_INITIALIZATION_DATA buffer with zeros before it sets the value of each field.

See Also

ACCESS_RANGE, DriverEntry, HwInitialize, SCSI_REQUEST_BLOCK, ScsiPortInitialize, ScsiPortInitialize


PORT_CONFIGURATION_INFORMATION

typedef struct _PORT_CONFIGURATION_INFORMATION {
    ULONG Length;
    ULONG SystemIoBusNumber;
    INTERFACE_TYPE AdapterInterfaceType;
    ULONG BusInterruptLevel;
    ULONG BusInterruptVector;
    KINTERRUPT_MODE InterruptMode;
    ULONG MaximumTransferLength;
    ULONG NumberOfPhysicalBreaks;
    ULONG DmaChannel;
    ULONG DmaPort;
    DMA_WIDTH DmaWidth;
    DMA_SPEED DmaSpeed;
    ULONG AlignmentMask;
    ULONG NumberOfAccessRanges;
    ACCESS_RANGE (*AccessRanges)[];
    PVOID Reserved;
    UCHAR NumberOfBuses;
    UCHAR InitiatorBusId[8];
    BOOLEAN ScatterGather;
    BOOLEAN Master;
    BOOLEAN CachesData;
    BOOLEAN AdapterScansDown;
    BOOLEAN AtdiskPrimaryClaimed;
    BOOLEAN AtdiskSecondaryClaimed;
    BOOLEAN Dma32BitAddresses;
    BOOLEAN DemandMode;
    BOOLEAN MapBuffers;
    BOOLEAN NeedPhysicalAddresses;
    BOOLEAN TaggedQueuing;
    BOOLEAN AutoRequestSense;
    BOOLEAN MultipleRequestPerLu;
    BOOLEAN ReceiveEvent;
    BOOLEAN RealModeInitialized;
    BOOLEAN BufferAccessScsiPortControlled;
    UCHAR   MaximumNumberOfTargets;
    UCHAR   ReservedUchars[2];
    ULONG SlotNumber;
    ULONG BusInterruptLevel2;
    ULONG BusInterruptVector2;
    KINTERRUPT_MODE InterruptMode2;
    ULONG DmaChannel2;
    ULONG DmaPort2;
    DMA_WIDTH DmaWidth2;
    DMA_SPEED DmaSpeed2;
} PORT_CONFIGURATION_INFORMATION, *PPORT_CONFIGURATION_INFORMATION;

PORT_CONFIGURATION_INFORMATION provides port configuration information.

Length
Specifies the length of the PORT_CONFIGURATION_INFORMATION structure as return by sizeof(). Because this structure might grow in later releases, HBA miniport drivers should check that the Length is greater than or equal to the required length. This field is always initialized by the port driver.
SystemIoBusNumber
Specifies the system I/O bus to be scanned. This field is used for several ScsiPortXxxx calls and is always initialized by the port driver. Its value is zero for machines that have only one I/O bus of the given Adapter Interface Type.
AdapterInterfaceType
Specifies the type of the bus being scanned. This field is equal to the value being passed into ScsiPortInitialize in the HW_INITIALIZATION_DATA structure. This field is always initialized.
BusInterruptLevel
Specifies the bus interrupt request level. This value corresponds to the IRQL on some buses, such as ISA and MCA. The uninitialized value is zero and no interrupt is assumed. EISA cards must set this value to level if the card is configured for level-sensitive interrupts.
BusInterruptVector
Specifies the bus vector returned by the host bus adapter. This field is pertinent to I/O buses that use interrupt vectors. For ISA, EISA, and MCA I/O buses this field is unused. The uninitialized value is zero and no interrupt is assumed.
InterruptMode
Specifies whether this host bus adapter uses LevelSensitive or Latched interrupts. This value is always initialized to Latched. EISA cards must set this value
MaximumTransferLength
Specifies the maximum transfer length this adapter can support. This value should always be set by the HBA miniport driver. A value of 0xFFFFFFFF indicates unlimited. The uninitialized value is 0xFFFFFFFF.
NumberOfPhysicalBreaks
Specifies the maximum number of physical segments that a data buffer can have if the host bus adapter supports scatter/gather. A value of 0xFFFFFFFF indicates unlimited and is the uninitialized value.
DmaChannel
Specifies the DMA channel used by the host bus adapter. The uninitialized value is 0xFFFFFFFF.
DmaPort
Specifies the DMA port used by the host bus adapter. This is meaningful for MCA-type buses. The uninitialized value is zero.
DmaWidth
Specifies the width of the DMA transfer. The uninitialized value is zero. Accepted widths are 8, 16, 32, and maximum DMA widths.
DmaSpeed
Specifies the data transfer speed for EISA system buses. The default is compatibility timing. Accepted types are: compatible, type a, type b, type c, and maximum DMA speed.
AlignmentMask
Specifies a mask indicating the alignment boundary for buffers required by the HBA for transfer operations. Valid bitsets under Windows 95 or Windows 98 are 0 (byte aligned), 1 (word aligned) or 3 (DWORD aligned).
NumberOfAccessRanges
Specifies the number of access ranges that the adapter uses. This value is the same as was passed in to ScsiPortInitialize in the HW_INITIALIZATION_DATA structure. It indicates the number of array elements in the following field.
AccessRanges
Points to an array of ACCESS_RANGE structures. The number of elements is indicated by the NumberOfAccessRanges field. The driver should fill in each structure for the host bus adapter. The uninitialized values for the array elements are zero. AccessRanges will be NULL if NumberOfAccessRanges is zero.
Reserved
This field is reserved for system use and should be ignored by miniport drivers.
NumberOfBuses
Specifies the number of SCSI buses attached to the HBA. The uninitialized value is zero.
InitiatorBusId
Specifies the initiator bus ID used by the HBA. An entry should be set for each SCSI bus. The uninitialized value is 0xFF.
ScatterGather
Indicates the HBA supports scatter/gather. The uninitialized value is FALSE.
Master
Indicates the HBA is a busmaster. The uninitialized value is FALSE.
CachesData
Indicates the HBA caches data or maintains cached state on the peripherals, for example a controller that mirrors two disks would normally set this bit. When this bit is set, the OS-specific port driver notifies the HBA miniport driver of events such as a file system flush and system shutdown. The uninitialized value is FALSE.
AdapterScansDown
Indicates the BIOS for this adapter scans for SCSI bus targets from 7 to zero. The uninitialized value is FALSE.
AtdiskPrimaryClaimed
Indicates that the primary AT disk address range, 0x1F0 to 0x1FF, has been claimed. This field is set by adapters that emulate an AT disk controller and that want to prevent access by the AT disk driver. If this field is set, the HBA miniport driver should assume that an already loaded driver has claimed the device.
AtdiskSecondaryClaimed
Indicates that the secondary AT disk address range, 0x170 to 0x17F has been claimed. This field is set by adapters that emulate an AT disk controller and that want to prevent access by the AT disk driver. If this field is set, the HBA miniport driver should assume that an already loaded driver has claimed the device.
Dma32BitAddresses
Indicates that the HBA has 32 address lines and can access memory with physical addresses greater than 0x00FFFFFF.
DemandMode
Indicates the system DMA controller should be programmed for demand-mode rather than single-cycle operations.
MapBuffers
Indicates data buffers must be mapped into system virtual address ranges. The value is copied from HW_INITIALIZATION_DATA. The driver may update the value for each particular HBA.
NeedPhysicalAddresses
Indicates the driver needs to translate virtual addresses to physical ones. The value is copied from HW_INITIALIZATION_DATA. The driver may update the value for each particular HBA.
TaggedQueuing
Indicates the device supports SCSI-II tagged queuing. The value is copied from HW_INITIALIZATION_DATA. The driver may update the value for each particular HBA.
AutoRequestSense
Indicates the device supports auto request sense. The value is copied from HW_INITIALIZATION_DATA. The driver may update the value for each particular HBA. This member must be set before ScsiPortGetUncachedExtension is called.
MultipleRequestPerLu
Indicates the device supports multiple requests per logical unit. The value is copied from HW_INITIALIZATION_DATA. The driver may update the value for each particular HBA.
ReceiveEvent
Indicates the device supports receive event operation. The uninitialized value is zero.
RealModeInitialized
Indicates the real-mode driver has initialized the card. This field is always initialized by ScsiPort.
RealModeInitialized
Indicates that the real-mode driver has initialized the card. This field is always initialized by ScsiPort.
BufferAccessScsiPortControlled
Indicates that the miniport will not touch the data buffers directly. Used only in Windows 95, not in Windows NT/Windows 2000. Refer to KB Article Q116450, BufferAccessScsiPortControlled Flag Information.

MaximumNumberOfTargets

Indicator for wide SCSI.

ReservedUchars[2]
Ensure quadword alignment.
ULONG SlotNumber
Adapter slot number.
ULONG BusInterruptLevel2
Optional value for a second interrupt. This field is irrelevant if the miniport has no HwInterrupt routine.
ULONG BusInterruptVector2
Optional value for a second interrupt. This field is irrelevant if the miniport has no HwInterrupt routine.
ULONG DmaChannel2
Optional value for a second DMA interrupt.
ULONG DmaPort2
Optional port value for a second DMA interrupt.
DMA_WIDTH DmaWidth2
Optional width value for a second DMA interrupt.
DMA_SPEED DmaSpeed2

Optional speed value for a second DMA interrupt.

DMA information for a second channel.

The specific fields initialized depend on the HBA miniport driver and the information available to the OS-specific port driver. All uninitialized fields are set to a default value.

All HBA miniport drivers should have at least one set of defaults to use for relevant fields if a value is not specified. All relevant fields should be updated by the HBA miniport driver.

SCSI class drivers, which load later than miniport drivers, depend on the information supplied by HwFindAdapter to customize their subsequent requests. For example, the MaximumTransferLength and NumberOfPhysicalBreaks values supplied by the miniport driver control whether class driver must split large transfer requests into a set of partial transfers to suit the limits of the HBA.

See Also

ACCESS_RANGE, HwFindAdapter, ScsiPortInitialize


SCSI_REQUEST_BLOCK

typedef struct _SCSI_REQUEST_BLOCK {
    USHORT Length;
    UCHAR Function;
    UCHAR SrbStatus;
    UCHAR ScsiStatus;
    UCHAR PathId;
    UCHAR TargetId;
    UCHAR Lun;
    UCHAR QueueTag;
    UCHAR QueueAction;
    UCHAR CdbLength;
    UCHAR SenseInfoBufferLength;
    ULONG SrbFlags;
    ULONG DataTransferLength;
    ULONG TimeOutValue;
    PVOID DataBuffer;
    PVOID SenseInfoBuffer;
    struct _SCSI_REQUEST_BLOCK *NextSrb;
    PVOID OriginalRequest;
    PVOID SrbExtension;
    ULONG QueueSortKey;
    UCHAR Cdb[16];
} SCSI_REQUEST_BLOCK, *PSCSI_REQUEST_BLOCK;
Length
Specifies the length, in bytes, of the request block.
Function
Specifies the operation to be performed.
Operation | Meaning
SRB_FUNCTION_EXECUTE_SCSI | A SCSI device I/O request should be executed on the target logical unit.
SRB_FUNCTION_ABORT_COMMAND | A SCSIMESS_ABORT message should be sent to cancel the request pointed to by the NextSrb field. If this is tagged queue request, then a SCSIMESS_ABORT_WITH_TAG message should be used. If the indicated request has been completed, this request should be completed normally. Only the Function, PathId, TargetId, Lun, and NextSrb fields are valid.
SRB_FUNCTION_RESET_DEVICE | The SCSI target controller should be reset using the SCSIMESS_BUS_DEVICE_RESET message. The HBA miniport driver should complete any active requests for the target controller. Only the Function, TargetId and PathId fields are valid.
SRB_FUNCTION_TERMINATE_IO | A SCSIMESS_TERMINATE_IO_PROCESS message should be sent to cancel the request pointed to by the NextSrb field. If the indicated request has already completed, this request should be completed normally. Only the Function, PathId, TargetId, Lun, and NextSrb fields are valid.
SRB_FUNCTION_RELEASE_RECOVERY | A SCSIMESS_RELEASE_RECOVERY message should be sent to the target controller. Only the Function, PathId, TargetId and Lun fields are valid.
SRB_FUNCTION_RECEIVE_EVENT | The HBA should be prepared to receive an Asynchronous Event Notification from the addressed target. The DataBuffer indicates where the data should be placed.
SRB_FUNCTION_SHUTDOWN | The system is being shut down. The request is passed to the miniport driver if CachesData was set to TRUE in the PORT_CONFIGURATION_INFORMATION data. The miniport driver can receive several of these notifications before all system activity is actually stopped; however, the last shutdown notification will occur after the last start I/O. Only the Function, PathId, TargetId and Lun fields are valid.
SRB_FUNCTION_FLUSH | The miniport should flush any cached data for the device. The request is passed to the miniport driver if CachesData is TRUE in the PORT_CONFIGURATION_INFORMATION data. Only the Function, PathId, TargetId and Lun fields are valid.
SRB_FUNCTION_IO_CONTROL | The request is an I/O control request. The SRB DataBuffer points to an SRB_IO_CONTROL header followed by the data area. The value in DataBuffer can be used by the driver, regardless of the value of MapBuffers field. If the HBA miniport driver supports this request, it should execute the request and notify the OS-specific port driver when it has completed it, using the normal mechanism of ScsiPortNotification with RequestComplete and NextRequest. Only the Function, SrbFlags, TimeOutValue, DataBuffer, DataTransferLength and SrbExtension are valid.

SrbStatus
Returns the status of the completed request. This field should be set by the HBA miniport driver before it notifies the OS-specific driver that the request has completed to one of the following:
Status | Meaning
SRB_STATUS_PENDING | Indicates the request in progress. The OS-specific port driver will initialize the SrbStatus to this value. This value should not be set by the HBA miniport driver.
SRB_STATUS_SUCCESS | Indicates the request was completed successfully.
SRB_STATUS_ABORTED | Indicates the request was aborted.
SRB_STATUS_ABORT_FAILED | Indicates an attempt to abort the request failed. This status is returned for a SRB_FUNCTION_ABORT_COMMAND request when the specified request cannot be located.
SRB_STATUS_ERROR | Indicates the request was completed with an error in the SCSI bus status.
SRB_STATUS_BUSY | Indicates the device could not accept the request at this time.
SRB_STATUS_INVALID_REQUEST | Indicates the miniport driver does not support the request.
SRB_STATUS_INVALID_PATH_ID | Indicates the PathId specified in the SRB doesn't exist.
SRB_STATUS_NO_DEVICE | Indicates the device did not respond.
SRB_STATUS_TIMEOUT | Indicates the request timed out.
SRB_STATUS_SELECTION_TIMEOUT | Indicates the SCSI device selection timed out.
SRB_STATUS_COMMAND_TIMEOUT | Indicates the target did not complete the command within the time limit.
SRB_STATUS_MESSAGE_REJECTED | Indicates the target rejected a message. This is normally returned for message type requests such as SRB_FUNCTION_TERMINATE_IO.
SRB_STATUS_BUS_RESET | Indicates a bus reset occurred while this request was being executed.
SRB_STATUS_PARITY_ERROR | Indicates a parity error occurred on the SCSI bus and that a retry failed.
SRB_STATUS_REQUEST_SENSE_FAILED | Indicates the request sense command failed. This is returned only if the controller performs auto request sense.
SRB_STATUS_NO_HBA | Indicates the HBA does not respond.
SRB_STATUS_DATA_OVERRUN | Indicates that a data overrun or underrun error occurred. The SRB's DataTransferLength field should be updated.
SRB_STATUS_UNEXPECTED_BUS_FREE | Indicates the target disconnected unexpectedly.
SRB_STATUS_PHASE_SEQUENCE_ FAILURE | Indicates the adapter detected an illegal phase sequence failure error.
SRB_STATUS_BAD_SRB_BLOCK_LENGTH | Indicates the SRB has an invalid length.
SRB_STATUS_REQUEST_FLUSHED | Indicates the request for status was stopped.
SRB_STATUS_INVALID_LUN | Indicates the LUN in the SRB is invalid.
SRB_STATUS_INVALID_TARGET_ID | Indicates the TargetID in the SRB is invalid.
SRB_STATUS_BAD_FUNCTION | Indicates the SRB function code is not supported.
SRB_STATUS_ERROR_RECOVERY | Indicates the request was completed with an error in the SCSI bus status and that the INITIATE RECOVERY message was received.
SRB_STATUS_AUTOSENSE_VALID | Indicates information returned in the SenseInfoBuffer is valid.

ScsiStatus
Returns the SCSI status that was returned by the HBA or target device. If the status is not SUCCESS, the SrbStatus should be set to SRB_STATUS_ERROR.
PathId
Indicates the SCSI port or bus for the request. This value is zero-based.
TargetId
Indicates the target controller on the bus.
Lun
Indicates the logical unit.
QueueTag
Indicates the queue tag, which was assigned by the OS-specific port driver. If this field is used for tagged queuing, the HBA supports internal queuing of requests to LUs.
QueueAction
Indicates the tagged-queuing message to be used when the SRB_FLAGS_QUEUE_ACTION_ENABLE flag is set. These values are defined in the SCSI-II specification.
CdbLength
Indicates the length, in bytes, of the command descriptor block.
SenseInfoBufferLength
Indicates the length, in bytes, of the request-sense buffer.
SrbFlags
Indicates various parameters and options about the request. The following values can be entered.
Value | Meaning
SRB_FLAGS_QUEUE_ACTION_ENABLE | Indicates tagged-queue actions are to be enabled.
SRB_FLAGS_DISABLE_AUTOSENSE | Indicates that request sense information should not be returned.
SRB_FLAGS_DATA_IN | Indicates data will be transferred from the device to the system.
SRB_FLAGS_DATA_OUT | Indicates data will be transferred from the system to the device.
SRB_FLAGS_NO_DATA_TRANSFER | Indicates no data transfer with this request. If this is set, the flags SRB_FLAGS_DATA_OUT and SRB_FLAGS_DATA_IN are both clear.
SRB_FLAGS_DISABLE_SYNCH_ TRANSFER | Indicates the HBA should not attempt to negotiate synchronous transfer with this request.
SRB_FLAGS_BYPASS_FROZEN_ QUEUE | Not used by the miniport driver.
SRB_FLAGS_NO_QUEUE_FREEZE | Not used by the miniport driver.
SRB_FLAGS_IS_ACTIVE | Not used by the miniport driver.
SRB_FLAGS_ALLOCATED_FROM_ ZONE | Indicates whether the SRB was allocated from a zone buffer. If TRUE, a class driver must call ExInterlockedFreeToZone to release the SRB; otherwise, it must call ExFreePool.
SRB_FLAGS_DISABLE_DISCONNECT | Indicates the HBA should not allow the target to disconnect from the SCSI bus during processing of this request.
SRB_FLAGS_ENABLE_ADAPTER_ CACHE | Indicates that the HBA can cache the data for this transfer request; otherwise, the data should be read or written to the device before the request has been completed. The adapter is responsible for ensuring that inconsistencies do not occur. For example, if a write occurs with caching enabled and, then, a read occurs without caching enabled, the adapter must return the last data written.

DataTransferLength
Indicates the length, in bytes, of the data buffer. If an underrun occurs, this field should be updated with the number of bytes actually transferred.
TimeOutValue
Indicates the minimum time, in seconds, the request can execute before it is considered to have timed out. HBA miniport drivers are not required to time requests, because the port driver already does.
DataBuffer
Points to the data buffer. HBA miniport drivers should not use this value as a data pointer unless the miniport set MapBuffers to TRUE in the SCSI_HW_INITIALIZATION_DATA structure or for SRB_FUNC_IO_CONTROL requests. In the case of SRB_FUNCTION_IO_CONTROL requests, however, miniport drivers can use this value as a data pointer regardless of the value of MapBuffers.
SenseInfoBuffer
Points to the request-sense buffer. HBA-specific drivers are not required to provide request sense data after a CHECK CONDITION. HBA miniport drivers should not use this value as a data pointer unless the miniport set MapBuffers to TRUE in the SCSI_HW_INITIALIZATION_DATA structure. The physical address of the extension can be obtained by calling ScsiPortGetPhysicalAddress.
NextSrb
Indicates the SCSI_REQUEST_BLOCK to which this request applies.
SrbExtension
Points to the Srb extension. This field should not be used if a length of zero was specified in the SCSI_HW_INITIALIZATION_DATA structure. This data extension is not initialized by the OS-specific port driver, and the miniport-determined data can be accessed directly by the HBA. The physical address of the extension can be obtained by calling ScsiPortGetPhysicalAddress.
Cdb
Supplies the SCSI-II command descriptor block to be sent to the target device.

See Also

HW_INITIALIZATION_DATA, ScsiPortGetPhysicalAddress, ScsiPortGetSrb, ScsiPortNotification, SRB_IO_CONTROL


SRB_IO_CONTROL

typedef struct _SRB_IO_CONTROL {
    ULONG HeaderLength;
    UCHAR Signature[8];
    ULONG Timeout;
    ULONG ControlCode;
    ULONG ReturnCode;
    ULONG Length;
} SRB_IO_CONTROL, *PSRB_IO_CONTROL;
HeaderLength
Is sizeof(SRB_IO_CONTROL).
Signature
Indicates the type of HBA this request is for. This signature is used to prevent conflicts in ControlCode values between vendors and should be a string of ASCII characters. If the HBA miniport driver does not recognize the signature it completes the request with a status of SRB_STATUS_INVALID_REQUEST.
Timeout
Indicates the minimum time, in seconds, the request can execute before it is considered to have timed out. HBA miniport drivers are not required to time requests.
ControlCode
Indicates the operation to be performed. There are no operations defined by this specification. Values must be defined by the driver with a set of private I/O control codes with which the application can make device control requests.
ReturnCode
Returns a code for examination by the requesting application.
Length
Indicates the length of the following data area. This area can be divided for the particular operation into input and output areas. The DataBuffer will be copied to the requestor limited by the updated DataTransferLength.

This structure is used by applications to send requests directly to an application-dedicated HBA. Note that such an application must set up requests to program the HBA.

See Also

SCSI_REQUEST_BLOCK


MS-DOS/Win32 File System Driver Reference

Information in this preliminary release of the document is subject to change without notice. No part of this document may be reproduced or transmitted in any form or by any means, electronic or mechanical, for any purpose, without the express written permission of Microsoft Corporation.


File System Driver Interface

The interface to the File System Driver (FSD) routines are defined as a C language callable interface so that the FSD VxD may be written in C, if desired. The FSD routines will only be called by the IFS manager, either directly or via the file system API hookers, if any.

Each FSD routine takes a single pointer as an input parameter. This pointer refers to an I/O request structure that defines input and output parameters for the FSD routines. On entry to an FSD routine, the I/O request structure is filled in by the IFS manager with the parameters relevant to the specific request.

The FSD routine then performs its function and fills in the required result information in the I/O request structure before returning.

The following are the parameters that exist in the I/O request structure that is passed to the FSD routines. Many of these parameters are overlaid with others to clarify the parameter names and compress the passed structure to a smaller size. For a further description of the basic structures, the reader is referred to the include file ifs.h.

I/O Request Structure Parameters:

unsigned int |
ir_length | Length of user buffer for reads/writes. This field is also overlaid with the following fields on other calls.
ir_attr | Attribute information for path-based calls.
ir_pathSkip | Number of path elements consumed by a connect operation.
unsigned char |
ir_flags | Miscellaneous status flags for various operations.
uid_t |
ir_user | User ID for a file system request. This field is overlaid with the following fields on certain calls:
ir_drivenum | Logical drive number, used for mounting a drive.
sfn_t |
ir_sfn | System File Number. This value is provided to the FSD only as a unique identifier for the file. The specific value and its meaning are private to the IFS manager and should not be interpreted by the FSD. This field can be overlaid with other fields on some calls:
ir_lananum | Lan Address Number.
ir_tuna | Used for tunnelling information.
pid_t |
ir_pid | Process ID of requesting task. This value is provided to the FSD only as a unique identifier for the process. The specific value and its meaning are private to the IFS manager and should not be interpreted by the FSD.
path_t |
ir_ppath | Pointer to path name. Path names are not restricted to the DOS 8.3 format, they may be long names. The path names are passed in as unicode strings. The path names are also in canonical form that makes it easier for FSDs to walk the path. This format has been described in Section 8.3.1.
aux_t |
ir_aux1 | This structure is used for miscellaneous parameters and is a union of different field types. The field definitions overlaid with this particular field are as follows:

ubuffer_t |
ir_data2 | Pointer to secondary data buffer used on some APIs.
vfunc_t |
ir_vfunc | Pointer to volume function table.
hfunc_t |
ir_hfunc | Pointer to handle function table.
path_t |
ir_ppath2 | Pointer to second unicode path name passed in on some APIs. The format is identical to ir_ppath.
unsigned long |
ir_volh | Pointer to volume handle on mount calls.

ubuffer_t |
ir_data | Pointer to user data buffer. This field is overlaid with the following field:
ir_ptuninfo | Pointer to tunnelling information.
unsigned short |
ir_options | Request handling options. This field is overlaid with the following fields:
ir_sectors | Contains sectors per cluster value.
ir_status | Contains status information for named pipes.
unsigned short |
ir_error | Error code (zero if OK).
rh_t |
ir_rh | FSD Resource Handle. This handle is private to the FSD and is not interpreted by the IFS manager. It is used to identify the disk volume, or network resource connection where the I/O operation is to be performed.
fh_t |
ir_fh | FSD File Handle. This handle is private to the FSD and is not interpreted by the IFS manager.
pos_t |
ir_pos | File position for request. This is an offset into the file relative to the beginning of the file. This field is overlaid with the following other fields:
ir_size | Initial size of file, used on creates and truncates.
ir_conflags | Flags used for connect operations.
ir_attr2 | Second set of attributes, used on Rename calls.
aux_t |
ir_aux2 | This structure is used for miscellaneous parameters and is a union of different field types. The field definitions overlaid with this particular field are as follows:

unsigned long |
ir_numfree | Number of free clusters value.
unsigned long |
ir_locklen | Record length for region locking.
unsigned int |
ir_msglen | Message length value for named pipes and mailslots.
dos_time |
ir_dostime | DOS date value.
unsigned long |
ir_timeout | Time-out value.
void * |
ir_password | Pointer to password data for connect operations.
unsigned short |
ir_prtlen | Length of printer setup string.
unsigned short |
ir_prtflags | Various printer flags.
unsigned long |
ir_firstclus | First cluster of a file.
unsigned long |
ir_mntdrv | Driveletter for mount operation.
void * |
ir_cregptr | Pointer to client register structure.
string_t |
ir_uFName | Pointer to case-preserved file name in unicode.

aux_t |
ir_aux3 | This structure is used for miscellaneous parameters and is a union of different field types. The field definitions overlaid with this particular field are as follows:

string_t |
ir_upath | Pointer to unparsed path name in unicode.
void * |
ir_scratch | Scratch buffer for special calls to network FSDs.

pevent |
ir_pev | Pointer to event structure for asynchronous requests.
fsdwork_t |
ir_fsd | Available space for FSD use. The structure is 16 DWORDs in size and may be defined as desired by the FSD.


FSD File I/O Interface

Each file I/O routine and its I/O request parameters are given in the following. All of the FSD routines receive the ID of the requesting process in the ir_pid field and return success (zero) or failure (nonzero). If failure, the error code is returned in the ir_error field. The error code values that should be returned are the DOS extended error code set.


FS_CloseFile

FS_CloseFile(
 PIOREQ pir
 )

A currently open file is closed through FS_CloseFile. This routine handles the Win32 function: CloseHandle(); and INT 21h functions: 10h, and 3Eh.

This routine must clean up record locks belonging to the process for the file being closed.

ir_rh
Supplies handle to disk volume or network resource that contains the file.
ir_fh
Supplies FSD file handle.
ir_sfn
Supplies system file number.
ir_options
Supplies processing options.
Processing Option Values:

The following options may be specified:

Value | Meaning
FILE_NO_LAST_ACCESS_DATE | Do not update last access date on the close operation even if it is currently enabled for the volume. This flag is a special flag that is passed in when a volume is locked down not allowing writes, so that there are no write operations done to the disk in all cases.
FILE_CLOSE_FOR_LEVEL3_LOCK | This is a special flag informing the FSD that this close operation is being done on a Level 3 lock request by user. The FSD needs to do some special processing for files that have file record locks on them when a Level 3 lock is taken. For more details, refer to the volume locking specification.
FILE_CLOSE_NO_IO | This flag informs the FSD that no I/O operation should be done during this close operation. This is usually because the resource the file was opened on is no longer available. FSDs should just clean up their internal data structures and return when this flag is set.

ir_flags
Supplies close flags.
Close Flag Values:

One of the following flags will be specified.

Value | Meaning
CLOSE_HANDLE | Ordinary close, flush buffers.
CLOSE_FOR_PROCESS | Last close for process, flush buffers, and free locks the process owns.
CLOSE_FINAL | Final close of file, last process that had the file open. The FSD should free any FSD-allocated memory associated with this file, flush buffers, and free locks.

ir_user
Supplies user ID for this request.
ir_pid
Supplies process ID for this request.
ir_error | Returns status of the operation (zero if no error, the error code otherwise).
ir_pos | Returns a pointer to the list of file record locks for this open file. This pointer should be returned only if the FILE_CLOSE_FOR_LEVEL3_LOCK flag is passed in. This list is then passed in to the FSD on a subsequent open call to FS_OpenFile. A NULL value should be returned if there are no active file record locks on this file. Volume locking is described in detail in the volume locking specification.

When the Level 3 lock is taken, the IFS manager issues a CLOSE_FINAL on all open handles for the corresponding volume. It also passes in the FILE_CLOSE_FOR_LEVEL3_LOCK flag in ir_options to indicate this to the FSD. In this case, the FSD should not free the record locks on the file as it would normally. Instead, it should just return a pointer to the list of active record locks for the file. This pointer is then passed in on the FS_OpenFile call when the IFS manager reopens the file for access.


FS_CommitFile

FS_CommitFile(
 PIOREQ pir
 )

The cached buffers for a specific file are committed to disk through FS_CommitFile. This routine handles the Win32 function: FlushFileBuffers(); and Int21 function: 68h.

All of the cached or buffered data for a specific file must be written out to disk when this function is called.

ir_rh
Supplies handle to disk volume or network resource that contains the file.
ir_fh
Supplies FSD file handle.
ir_sfn
Supplies system file number.
ir_options
Supplies processing options.
Processing Option Values:

The following options may be specified:

Value | Meaning
FILE_NO_LAST_ACCESS_DATE | Do not update last access date on the close operation even if it is currently enabled for the volume. This flag is a special flag that is passed in when a volume is locked down not allowing writes, so that there are no write operations done to the disk in all cases.
FILE_COMMIT_ASYNC | Commit the data for the file to the disk asynchronously. If this option is not passed in, the commit must flush the dirty data for the open file synchronously to the disk.

ir_user
Supplies user ID for this request.
ir_pid
Supplies process ID for this request.
  • Returns status of the operation (zero if no error, the error code otherwise).

The FILE_COMMIT_ASYNC flag is provided as an optimization. By default, commits are synchronous and do not return to the user without flushing the data to the disk. There are certain kinds of applications that make a high number of commit calls and committing the data asynchronously substantially improves the performance of such applications. The IFS manager turns this flag on based on a system registry setting. FSDs should not attempt to interpret the system registry settings independent of the IFS manager. There are certain situations such as the presence of volume locks, when the IFS manager forces all commit operations to be synchronous.


FS_ConnectNetResource

FS_ConnectNetResource(
 PIOREQ pir
 )

A connection is made to a network resource through FS_ConnectNetResource.

ir_ppath
Supplies a pointer to the canonicalized unicode network resource path name to connect to. The path name may contain more than just the network resource address name. Wildcards are not allowed on the path name.
ir_password
Supplies an optional pointer to the security credentials needed to connect to the network resource, otherwise this is set to NULL. Note that the password is passed in whatever format the user passed to the IFS manager, it is not converted to unicode format.
ir_options
Supplies connection options.
Connection Option Values:

One of the following options will be specified.

Value | Meaning
RESOPT_UNCREQUEST | UNC style path based anonymous connection request.
RESOPT_DEVATTACH | Explicit device redirection.
RESOPT_UNCCONNECT | Explicit UNC style connection.
RESOPT_DISCONNECTED | Connection is to be setup disconnected, without touching the net.
RESOPT_NO_CREATE | Do not create a resource for this connection, just verify the connection exists.
RESOPT_STATIC | This connection is established at startup and disconnected only at shutdown, no user APIs can disconnect it.

ir_flags
Supplies resource type.
Connection Resource Type Values:

One of the following resource types will be specified.

Value | Meaning
RESTYPE_WILD | Wild card resource type.
RESTYPE_DISK | Disk resource.
RESTYPE_SPOOL | Spooled printer resource.
RESTYPE_CHARDEV | Character device resource.
RESTYPE_IPC | Interprocess communication resource.

ir_fh
Supplies the IFS system resource handle for the network resource connection. This is passed back in to the IFS manager on certain calls. The FSD should not attempt to interpret this in any fashion, it is provided only for identification purposes.
ir_uFname
Pointer to the case-preserved file name component in unicode.
ir_upath
Pointer to the unparsed user path name in unicode.
ir_user
Supplies user ID for this request.
ir_lananum
Supplies the LAN address number, which is typically used only for mailslots. The ifs manager does not store this value.
ir_conflags
Indicates whether the connect operation was initiated via a user API request or via an FSD directly.
Connection Flag Values:
Value | Meaning
FALSE | The connection has been initiated by a user API request.
TRUE | The connection has been initiated via an FSD request.

ir_pid
Supplies process ID for this request.
ir_fh | Returns the previous IFS system resource handle if the specified resource was previously connected. If this is a new connection, then the FSD should leave this field unchanged.
ir_rh | Returns the handle to the network resource that a connection was made to. This handle is used to identify an existing connection and is passed back to the provider during file operations on the network resource. The value of this handle is not interpreted by the Win32 or INT 21h Managers, it is only used to identify the network resource.
ir_pathSkip | Number of path elements consumed by the connect operation. The IFS manager then parses the rest of the path based on this return value. Typically, the network FSD will consume the servername and sharename components of the passed in path.
ir_flags | Returns the correct resource type if the resource type passed in on the request was RESTYPE_WILD. For all other values of the resource type, this field need not be updated by the FSD.
ir_vfunc | Returns a pointer to a function table, in the FSD, containing a list of the FSD name based file I/O entry points.

Function Table Structure:
Value | Meaning
vfn_version | IFS version number.
vfn_revision | IFS interface revision number.
vfn_size | Number of function entry points in table.
vfn_func[NUM_VOLFUNC] | Array of pointers to volume-based functions as described in the following:

Volume Based Functions:
Value | Meaning
vfn_func[VFN_DELETE] | Pointer to FS_DeleteFile function.
vfn_func[VFN_DIR] | Pointer to FS_Dir function.
vfn_func[VFN_FILEATTRIB] | Pointer to FS_FileAttributes function.
vfn_func[VFN_FLUSH] | Pointer to FS_FlushVolume function.
vfn_func[VFN_GETDISKINFO] | Pointer to FS_GetDiskInfo function.
vfn_func[VFN_OPEN] | Pointer to FS_OpenFile function.
vfn_func[VFN_RENAME] | Pointer to FS_RenameFile function.
vfn_func[VFN_SEARCH] | Pointer to FS_SearchFile function.
vfn_func[VFN_QUERY] | Pointer to FS_QueryResourceInfo function.
vfn_func[VFN_DISCONNECT] | Pointer to FS_DisconnectNetResource function.
vfn_func[VFN_UNCPIPEREQUEST] | Pointer to FS_NamedPipeRequest function for named pipes.
vfn_func[VFN_IOCTL16DRIVE] | Pointer to FS_Ioctl16Drive function.
vfn_func[VFN_GETDISKPARMS] | Function not defined for network resources, FSD must return pointer to error function.
vfn_func[VFN_FINDOPEN] | Pointer to function for FS_FindFirstFile function.
vfn_func[VFN_DASDIO] | Function not supported for network resources, FSD must return pointer to error function.

ir_error Returns status of the operation (zero if no error, the error code otherwise).

This function will be called for each connection made to the network resource. The same network resource handle should be returned for multiple connections to a single network resource.


FS_DeleteFile

FS_DeleteFile(
 PIOREQ pir
 )

A file is deleted through FS_DeleteFile. This routine handles the Win32 function: DeleteFile(); and INT 21h functions: 13h, and 41h.

ir_ppath
Supplies a pointer to the canonicalized unicode path name to delete. Wildcards are allowed on the file name specification.
ir_rh
Supplies handle to disk volume or network resource that contains the file.
ir_attr
Supplies must-match and search attributes. Path parsing flags are also provided as advisory information for the FSDs.
Search Attribute Values:

Any combination of the following attributes may be specified, causing those files to be included with normal files in the search.

Value | Meaning
FILE_ATTRIBUTE_HIDDEN | Include hidden file in search.
FILE_ATTRIBUTE_SYSTEM | Include system file in search.
FILE_ATTRIBUTE_DIRECTORY | Include subdirectories in search.
FILE_ATTRIBUTE_VOLUMELABEL | Search for volume label.
Must-Match Attribute Values:

The must-match attributes can be any of the following attributes.

Value | Meaning
FILE_ATTRIBUTE_READONLY | Match read-only files.
FILE_ATTRIBUTE_HIDDEN | Match hidden files.
FILE_ATTRIBUTE_SYSTEM | Match system files.
FILE_ATTRIBUTE_DIRECTORY | Match subdirectories.
FILE_ATTRIBUTE_ARCHIVE | Match archived files.
FILE_ATTRIBUTE_VOLUMELABEL | Match volume label.
Path Parsing Flags:

The following path parsing flags are passed in.

Value | Meaning
FILE_FLAG_WILDCARDS | Wildcard characters present in path name.
FILE_FLAG_HAS_STAR | Path has the asterisk as a wildcard character.
FILE_FLAG_LONG_PATH | Path has a long name component.
FILE_FLAG_KEEP_CASE | Preserve the case of the file name passed in when storing on disk. This also implies that this call should use long name semantics for its processing.
FILE_FLAG_HAS_DOT | File name component has a dot in its name.
FILE_FLAG_IS_LFN | File name component is a long name.

ir_uFname
Pointer to the case-preserved file name component in unicode.
ir_upath
Pointer to the unparsed user path name in unicode.
ir_user
Supplies user ID for this request.
ir_pid
Supplies process ID for this request.
ir_error Returns status of the operation (zero if no error, the error code otherwise).

If an FSD does not support long file names on a volume and it gets a path that contains long names, it should fail the call. The FSD should not attempt to truncate the path name because there is a possibility of deleting the wrong file. Any truncation that needs to be done will be done by the IFS manager before the FSD is called. If an FSD does not support a wildcard delete, it must return an ERROR_INVALID_FUNCTION. The IFS manager watches for this error code and then proceeds to split the wildcard delete into a sequence of Find and Delete operations on non-wildcard file names.


FS_Dir

FS_Dir(
 PIOREQ pir
 )

Directory operations (change, make, and remove) are performed through FS_Dir. This routine handles the Win32 functions: CreateDirectory(), RemoveDirectory(), and SetCurrentDirectory(); and INT 21h functions: 39h, 3Ah, and 3Bh.

ir_ppath
Supplies a pointer to the unicode canonicalized directory path name for the operation. Wildcards are not allowed on the path name.
ir_flags
Supplies the command type to perform.
Command Type Values:

One of the following types will be specified.

Value | Meaning
CREATE_DIR | Make a new directory.
DELETE_DIR | Remove an existing directory.
CHECK_DIR | Check if the directory exists.
QUERY83_DIR | Return a pure 8.3 path name for the path passed in, which possibly has mixed components.
QUERYLONG_DIR | Return a pure LFN path name for the path passed in, which possibly has mixed components.

ir_rh
Supplies handle to disk volume or network resource that contains the directory.
ir_ppath2
Supplies pointer to buffer to contain the unicode pure path name on the QUERY83_DIR and QUERYLONG_DIR commands. This parameter is not valid for the other commands.
ir_attr
Supplies path parsing flags for the path name.
Path Parsing Flags:

The following path parsing flags are passed in.

Value | Meaning
FILE_FLAG_LONG_PATH | Path has a long name component.
FILE_FLAG_KEEP_CASE | Preserve the case of the file name passed in when storing on disk. This also implies that this call should use long name semantics for its processing.
FILE_FLAG_HAS_DOT | File name component has a dot in its name.
FILE_FLAG_IS_LFN | File name component is a long name.

ir_uFname
Pointer to the case-preserved file name component in unicode.
ir_upath
Pointer to the unparsed user path name in unicode.
ir_user
Supplies user ID for this request.
ir_pid
Supplies process ID for this request.
ir_error | Returns status of the operation (zero if no error, the error code otherwise).
ir_ppath2 | Contains the pure 8.3 or LFN path name on the QUERY83_DIR and QUERYLONG_DIR commands respectively. This parameter is not returned on the other commands. The FSD must return a canonicalized unicode path name.

If an FSD does not support long file names on a volume and it gets a LFN path name, it should fail the call. The QUERY83_DIR command should be failed on volumes that have no 8.3 names e.g. HPFS. However, The QUERYLONG_DIR command should never be failed. On a volume that has no LFNs, it should just return the 8.3 version passed in. Note that if a volume supports LFNs, the path name passed in can be a mixture of long name and short-name components. The FSD should be able to handle this and should not make any assumptions about the path name passed in.


FS_DirectDiskIO

FS_DirectDiskIO(
 PIOREQ pir
 )

Absolute disk read and write operations are performed through FS_DirectDiskIO. This supports the DOS functions: INT 25h and INT 26h.

ir_rh
Supplies handle to resource.
ir_flags
Supplies flags for the type of operation.
Operation Type Flags:
Value | Meaning
DIO_ABS_READ_SECTORS | Absolute disk read operation.
DIO_ABS_WRITE_SECTORS | Absolute disk write operation.
DIO_SET_LOCK_CACHE_STATE | Set the cache state while a volume lock is in progress.

ir_user
Supplies user ID for this request.
ir_pid
Supplies process ID for this request.
Operation Type DIO_ABS_READ_SECTORS and DIO_ABS_WRITE_SECTORS:
ir_pos | Supplies the absolute sector number the read or write operation starts at.
ir_length | Supplies the number of sectors to be read or written.
ir_data | Supplies a pointer to the buffer the data is to be read from or written into.

Operation Type DIO_SET_LOCK_CACHE_STATE:
ir_options Supplies options for setting the cache state while a volume lock is in progress.

Cache State Values:
Value | Meaning
DLC_LEVEL0LOCK_TAKEN | Set the cache state for a Level 0 lock type. The cache should be invalidated when a Level 0 lock is taken and the cache must remain in the writethrough mode for the duration of this lock until the FSD is called with the DLC_LEVEL0LOCK_RELEASED option.
DLC_LEVEL0LOCK_RELEASED | Revert the cache state to what it was before the lock was taken. The FSD should store the previous cache state so that it can restore it when the lock is released.
DLC_LEVEL3LOCK_TAKEN | Set the cache state for a Level 3 lock type. The cache should be invalidated when a Level 0 lock is taken and the cache must remain in the writethrough mode for the duration of this lock until the FSD is called with the DLC_LEVEL3LOCK_RELEASED option.
DLC_LEVEL3LOCK_RELEASED | Revert the cache state to what it was before the lock was taken. The FSD should store the previous cache state so that it can restore it when the lock is released.

ir_error Returns status of the operation (zero if no error, the error code otherwise).

The operation to set the cache state while the volume lock is in progress is part of the support necessary for exclusive access support. Volume locking is described in detail in the volume locking specification. Any FSD that does not support direct disk operations should fail this function, for example, network FSDs. The IFS does not explicitly fail these calls on any particular kind of FSD. In order to access FAT32 volumes, the ABS_EXTENDED_DASDIO bit must be set in ir_options or the request will fail. This bit is defined in the IFS.H header file found in the Windows 98 DDK.


FS_DisconnectResource

FS_DisconnectResource(
 PIOREQ pir
 )

An existing network connection or a mount on a local drive is removed through FS_DisconnectResource.

ir_rh
Supplies handle to resource that is to be disconnected or dismounted.
ir_flags
Supplies flags for the disconnect or dismount operation.
Disconnect Flag Values:
Value | Meaning
DISCONNECT_NORMAL | Normal disconnect operation, complete all pending I/O operations and disconnect the resource.
DISCONNECT_NO_IO | Disconnect the resource without doing any I/O operation. Pending I/O operations should be discarded. This will typically be called on volumes that have gone away, usually due to user action.
DISCONNECT_SINGLE | Disconnect this resource alone. There are certain cases where multiple resources can be associated to one another and come and go as a unit. This flag is passed in to prevent all the resources from going away on associated resources. This is typically the case on compressed drives.

ir_user
Supplies user ID for this request.
ir_pid
Supplies process ID for this request.
ir_pev
Supplies a pointer to an event handle. This value is a valid pointer if the disconnect function is called at event time. If the function is called during normal application execution time, this pointer will be NULL.
ir_error Contains status of the operation (zero if no error, the error code otherwise).

The IFS manager will ensure that all files on the resource have been closed before this call is made. The DISCONNECT_NO_IO case is the only situation in which this may not be true. If the DISCONNECT_NO_IO flag is passed in and the FSD has pending I/O operations on the volume it should return an error back on the disconnect operation so that the IFS manager can notify the user of this situation. Note that this function can be called at event time, FSDs should not make any assumptions about when this function is called.


FS_EnumerateHandle

FS_EnumerateHandle(
 PIOREQ pir
 )

This function handles the Win32 function: GetFileInformationByHandle() and the DOS INT 21h function: 440dh, subfunction 086dh. In addition, it also handles certain operations that are needed for volume locking support in the IFS manager.

ir_rh
Supplies handle to disk volume or network resource that contains the file.
ir_sfn
Supplies system file number.
ir_flags
Supplies operation type.
Operation Type Values:
Value | Meaning
ENUMH_GETFILEINFO | Get information about the file.
ENUMH_GETFILENAME | Get the path name of the file.
ENUMH_GETFINDINFO | Get information about the find handle so that a find can be resumed after a volume lock is released.
ENUMH_RESUMEFIND | Resume a find based on the information returned on the ENUMH_GETFINDINFO operation called previously.
ENUMH_RESYNCFILEDIR | Resynchronize the directory cluster and position for a file that could have been moved. However, the file's data blocks will not have moved.
ENUMH_MAPCACHEBLOCK | (Windows 98 and later) This service maps a zero-relative page number (4K) within a file into a VCACHE buffer and returns the address of the VCACHE buffer header to the caller. This API is strictly intended for use by the operating system. Its purpose is to make more efficient use of system memory by reducing double caching of EXE and DLL files.

ir_fh
Supplies the FSD file handle on the ENUMH_GETFILEINFO, ENUMH_GETFILENAME and the ENUMH_RESYNCFILEDIR operations. Supplies the FSD find handle on the ENUMH_GETFINDINFO and ENUMH_RESUMEFIND operations.
ir_ppath
Supplies the path name on ENUMH_RESUMEFIND and ENUMH_RESYNCFILEDIR operations. Supplies a pointer to a buffer the path name is to be returned in on the ENUMH_GETFINDINFO and ENUMH_GETFILENAME operations. This parameter is not valid on the ENUMH_GETFILEINFO operation.
ir_data
Supplies a pointer to the structure filled in on the ENUMH_GETFILEINFO operation. The contents of this structure are described in the following. This parameter is not valid on other operations.
ir_options
Supplies special options. This field is valid only on the ENUMH_RESYNCFILEDIR operation.
ENUMH_RESYNCFILEDIR Options:
Value | Meaning
RESYNC_INVALIDATEMETACACHE | Indicates that any meta-caches associated with this open file should be flushed. This could include file extent caches, name caches, etc.

ir_user
Supplies user ID for this request.
ir_pid
Supplies process ID for this request.
ir_error
Contains status of the operation (zero if no error, the error code otherwise) for all operations.
Operation Type ENUMHGETFILEINFO:
Value | Meaning
ir_data | Returns information about the file filled into the BY_HANDLE_FILE_INFORMATION structure described in the following.

BY_HANDLE_FILE_INFORMATION Structure:
Value | Meaning
bhfi_dwFileAttributes | Returns the attributes of the file.
bhfi_ftCreationTime | Returns the creation time of the file in the Win32 FileTime structure format described in the following.

Win32 FileTime Structure:
Value | Meaning
dwLowDateTime | Returns the low double word of the time in Win32 format.
dwHighDateTime | Returns the high double word of the time in Win32 format.

bhfi_ftLastAccessTime | Returns the last access time of the file in the Win32 FileTime structure format described above.
bhfi_ftLastWriteTime | Returns the last access time of the file in the Win32 FileTime structure format described above.
bhfi_dwVolumeSerialNumber | Returns the serial number of the volume the file is on.
bhfi_nFileSizeHigh | Returns the high 32-bits of the file size.
bhfi_nFileSizeLow | Returns the low 32-bits of the file size.
bhfi_nNumberOfLinks | Returns the number of links to the file.
bhfi_nFileIndexHigh | Returns the high 32-bits of a unique index to the file. This index needs to be valid only while the file is open and is typically used to determine if multiple handles point to the same open file.
bhfi_nFileIndexLow | Returns the low 32-bits of a unique index to the file.

Operation Type ENUMHGETFILENAME:
Value | Meaning
ir_ppath | Returns the path name to the open file in a unicode canonicalized path format. This path can be passed back to the FSD to open the file.

Operation Type ENUMHGETFINDINFO:
Value | Meaning
ir_ppath | Returns the path name to the last file found on the find handle in a unicode canonicalized path format. This path can be passed back to the FSD to resume the find at this path name. This is typically done during volume locking.

The following function is applicable to Windows 98 and later. See Knowledge Base article Q223282 for more information about the ENUMH_MAPCACHEBLOCK function:

Operation Type ENUMH_MAPCACHEBLOCK: |
Value | Meaning
ir_pos | Supplies zero-relative cache block number to map (from beginning of file)
ir_length | Number of cache blocks to map (1)
ir_data | Set to 0 initially. If successful, returns VCACHE handle for cache block.
ir_error | Returns 0 if successful. Returns ERROR_ACCESS_DENIED if unsuccessful.

Details about volume-locking support and about how these volume-locking operations are used to ensure a consistent system while a volume lock is in progress are given in the volume-locking specification. Any local FSD that allows direct disk operations must also support the volume-locking support functions. Note that the ENUMH_RESYNCFILEDIR operation can only be called on files that are left open by the IFS manager across a Level 3 volume lock. Typically, memory-mapped files and Win32 executables and DLLs fall into this category of files. However, disk utilities are allowed to move these files even though they are open, with certain restrictions.


FS_FileAttributes

FS_FileAttributes(
 PIOREQ pir
 )

File attributes are set and retrieved and file system information is returned through FS_FileAttributes. This routine handles the Win32 functions: GetAttributesFile(), SetAttributesFile() and GetVolumeInfo(); and INT 21h function: 43h.

ir_ppath
Supplies a pointer to the canonicalized unicode path name. Wildcards are not allowed on the path name.
ir_rh
Supplies handle to disk volume or network resource that contains the file.
ir_flags
Supplies desired command type to perform.
Command Type Values:

One of the following types will be specified.

Value | Meaning
GET_ATTRIBUTES | Get the file attributes.
SET_ATTRIBUTES | Set the file attributes.
GET_ATTRIB_COMP_FILESIZE | Return the uncompressed size in bytes for the specified file or directory. Note that the root directory also has a valid physical size.
SET_ATTRIB_MODIFY_DATETIME | Set the last modification date for the file.
GET_ATTRIB_MODIFY_DATETIME | Get the last modification date for the file.
SET_ATTRIB_LAST_ACCESS_DATETIME | Set the last access date for the file.
GET_ATTRIB_LAST_ACCESS_DATETIME | Get the last access date for the file.
SET_ATTRIB_CREATION_DATETIME | Set the creation date for the file.
GET_ATTRIB_CREATION_DATETIME | Get the creation date for the file.

ir_attr
Supplies the path parsing flags. Also supplies the new file attribute on the SET_ATTRIBUTE command.
Attribute Values:

Any combination of the following attributes may be specified on the SET_ATTRIBUTES command.

Value | Meaning
FILE_ATTRIBUTE_READONLY | Read-Only file.
FILE_ATTRIBUTE_HIDDEN | Hidden file.
FILE_ATTRIBUTE_SYSTEM | System file.
FILE_ATTRIBUTE_ARCHIVE | Archive file.

Path Parsing Flags:

The following path parsing flags are passed in.

FILE_FLAG_LONG_PATH | Path has a long name component.
FILE_FLAG_KEEP_CASE | Preserve the case of the file name passed in when storing on disk. This also implies that this call should use long name semantics for its processing.
FILE_FLAG_HAS_DOT | File name component has a dot in its name.
FILE_FLAG_IS_LFN | File name component is a long name.

ir_uFname
Pointer to the case-preserved file name component in unicode.
ir_upath
Pointer to the unparsed user path name in unicode.
ir_user
Supplies user ID for this request.
ir_pid
Supplies process ID for this request.
Operation Type SET_ATTRIB_*:
ir_dostime
Supplies the current file date and time on all the get commands. The date and time is in DOS format. For GET_LAST_ACCESS_DATETIME, if only the date is supported, the time field should be set to zero.
ir_options
Supplies the 10 millisecond interval on the GET_ATTRIB_CREATION_DATETIME function.
ir_error | Returns status of the operation (zero if no error, the error code otherwise).
Operation Type GET_ATTRIBUTES:
Value | Meaning
ir_attr | Returns current attributes of the file on a GET_ATTRIBUTES command.
Operation Type GET_ATTRIBUTES or GET_ATTRIB_COMP_FILESIZE:
ir_size | Returns the physical (uncompressed) size in bytes of the file or directory specified.
Operation Type GET_ATTRIB_*:
ir_dostime | Returns the current file date and time on all the get commands. The date and time is in DOS format. For SET_LAST_ACCESS_DATETIME, if only the date is supported, the time field should be set to zero.
ir_options | Returns the 10 millisecond interval on the SET_ATTRIB_CREATION_DATETIME function.

If an FSD does not support long file names on a volume and it gets a LFN API call on that volume, it should fail the call. The function should not be failed if any of the date and time fields are not supported by a particular file system. A value of zero should be returned in those date and time fields that are not supported.


FS_FileDateTime

FS_FileDateTime(
 PIOREQ pir
 )

The file modification date and time is set and retrieved through FS_FileDateTime. This routine handles the INT 21h function: 57h.

ir_rh
Supplies handle to disk volume or network resource that contains the file.
ir_fh
Supplies FSD file handle.
ir_sfn
Supplies system file number.
ir_flags
Supplies desired command type to perform.
Command Type Values:

One of the following types will be specified.

Value | Meaning
GET_MODIFY_DATETIME | Get the file modification date and time.
SET_MODIFY_DATETIME | Set the file modification date and time.
GET_LAST_ACCESS_DATETIME | Get the last access date and time for the file.
SET_LAST_ACCESS_DATETIME | Set the last access date and time for the file.
GET_CREATION_DATE_TIME | Get the creation date and time for the file.
SET_CREATION_DATE_TIME | Set the creation date and time for the file.

ir_dostime
Supplies new date and time for file on all the set commands. The date and time is in DOS format. For SET_LAST_ACCESS_DATETIME, the time field may be zero indicating that last access time is not supported.
ir_options
Supplies the 10 millisecond intervals for additional precision for the creation time. This field is valid only on the SET_CREATION_DATE_TIME command.
ir_user
Supplies user ID for this request.
ir_pid
Supplies process ID for this request.
ir_error | Returns status of the operation (zero if no error, the error code otherwise).
ir_dostime | Returns current file date and time on all the get commands. The date and time is in DOS format. For GET_LAST_ACCESS_DATETIME, if only the date is supported, the time field should be set to zero.
ir_options | Returns the 10 millisecond interval on the GET_CREATION_DATE_TIME.

Any fields that are not supported will have an input value if zero. If the FSD does not support any of the date and time fields it should return zero and not fail the call. The creation time has additional precision over the normal DOS time of 2-second intervals - it gives a precision up to 10 milliseconds, the new parameter specifying the number of 10 millisecond intervals beyond the 2 second precision already stored in the DOS time.


FS_FileSeek

FS_FileSeek(
 PIOREQ pir
 )

The current file position is set or obtained through FS_FileSeek. This routine handles the Win32 function GetFileSize(); and INT 21h functions: 23h, and 42h.

ir_rh
Supplies handle to disk volume or network resource that contains the file.
ir_fh
Supplies FSD file handle.
ir_sfn
Supplies system file number.
ir_flags
Supplies the type of seek method to perform.
Seek Method Values:

One of the following seek methods will be specified.

Value | Meaning
FILE_BEGIN | Position is an absolute offset from the beginning of the file.
FILE_END | Position is a signed offset relative to the end of the file.

ir_pos
Supplies the file seek offset.
ir_user
Supplies user ID for this request.
ir_pid
Supplies process ID for this request.
ir_error | Returns status of the operation (zero if no error, the error code otherwise).
ir_pos | Returns the current file position.

The FILE_BEGIN method is provided as an optimization only and may otherwise be ignored. The idea is simply to allow the FSD to do read-ahead based on this information if it chooses to. There is no guarantee that file I/O will take place at the passed file position however.


FS_FindClose

FS_FindClose(
 PIOREQ pir
 )

A Win32 find file context operation is closed through FS_FindClose. This routine handles the Win32 function: FindClose() and the INT 21h function 71A1h.

ir_fh
Supplies the find context handle obtained in a previous call to FS_FindFirstFile.
ir_rh
Supplies handle to disk volume or network resource that contains the file.
ir_sfn
Supplies system file number.
ir_user
Supplies user ID for this request.
ir_pid
Supplies process ID for this request.
ir_error Returns status of the operation (zero if no error, the error code otherwise).


FS_FindFirstFile

FS_FindFirstFile(
 PIOREQ pir
 )

A Win32 find first operation is performed through FS_FindFirstFile. A find context handle is created and is passed on FS_FindNextFile to continue the search. This routine handles the Win32 function: FindFirstFile() and the INT 21h function 714Eh.

ir_ppath
Supplies a pointer to the canonicalized unicode path name that the search is to begin at. Wildcards are allowed on the path name.
ir_rh
Supplies handle to disk volume or network resource where the search is being done.
ir_attr
Supplies must-match and search attributes. Path parsing flags are also provided as advisory information for the FSDs.
Search Attribute Values:

Any combination of the following attributes may be specified, causing those files to be included with normal files in the search.

Value | Meaning
FILE_ATTRIBUTE_HIDDEN | Include hidden file in search.
FILE_ATTRIBUTE_SYSTEM | Include system file in search.
FILE_ATTRIBUTE_DIRECTORY | Include subdirectories in search.
FILE_ATTRIBUTE_VOLUMELABEL | Search for volume label.
Must-Match Attribute Values:

The must-match attributes can be any of the following attributes.

FILE_ATTRIBUTE_READONLY | Match read-only files.
FILE_ATTRIBUTE_HIDDEN | Match hidden files.
FILE_ATTRIBUTE_SYSTEM | Match system files.
FILE_ATTRIBUTE_DIRECTORY | Match subdirectories.
FILE_ATTRIBUTE_ARCHIVE | Match archived files.
FILE_ATTRIBUTE_VOLUMELABEL | Match volume label.
Path Parsing Flags:

The following path parsing flags are passed in.

Value | Meaning
FILE_FLAG_WILDCARDS | Wildcard characters present in path name.
FILE_FLAG_HAS_STAR | Path has the asterisk as a wildcard character.
FILE_FLAG_LONG_PATH | Path has a long name component.
FILE_FLAG_KEEP_CASE | Preserve the case of the file name passed in when storing on disk. This also implies that this call should use long name semantics for its processing.
FILE_FLAG_HAS_DOT | File name component has a dot in its name.
FILE_FLAG_IS_LFN | File name component is a long name.

ir_uFname
Pointer to the case-preserved file name component in unicode.
ir_upath
Pointer to the unparsed user path name in unicode.
ir_hfunc
Supplies a pointer to a function pointer structure, containing a list of the FSD find file entry points.
ir_data
Supplies a pointer to buffer where the find data for a file that is found is returned.
ir_sfn
Supplies system file number.
ir_user
Supplies user ID for this request.
ir_pid
Supplies process ID for this request.
ir_error | Returns status of the operation (zero if no error, the error code otherwise).
ir_fh | Returns the FSD find context handle that is passed in by the IFS manager on subsequent calls to FS_FindNextFile and FS_FindClose.
ir_hfunc | Returns a filled in function pointer structure, containing a list of the FSD find file entry points. The structure is filled in as follows:

Function Pointer Structure:
Value | Meaning
hf_read | Returns pointer to FS_FindNextFile function.
hf_write | Function is not defined, FSD must return pointer to an error function.
hf_misc | Returns a pointer to a function table structure, in the FSD, containing a list of the remaining FSD handle based file I/O entry points.

Function Table Structure:
hm_version | IFS version number.
hm_revision | IFS interface revision number.
hm_size | Number of function entry points in table.
hm_func[NUM_HNDLMISC] | Returns an array of pointers to the handle-based functions as described in the following:
hm_func[HM_SEEK] | Undefined function, must return pointer to an error function.
hm_func[HM_CLOSE] | Returns pointer to FS_FindClose function.
hm_func[HM_COMMIT] | Undefined function, must return pointer to an error function.
hm_func[HM_FILELOCKS] | Undefined function, must return pointer to an error function.
hm_func[HM_FILETIMES] | Undefined function, must return pointer to an error function.
hm_func[HM_PIPEREQUEST] | Undefined function, must return pointer to an error function.
hm_func[HM_HANDLEINFO] | Undefined function, must return pointer to an error function.
hm_func[HM_ENUMHANDLE] | Returns a pointer to the FS_EnumerateHandle function.

ir_data Returns find data for a file filled in the buffer in the following format if there was no error.

Find Data Structure:
dwFileAttributes Returns the file attributes of the file found.

Attribute Values:

Any valid combination of the following attributes may be returned.

Value | Meaning
FILE_ATTRIBUTE_READONLY | Read-only file.
FILE_ATTRIBUTE_HIDDEN | Hidden file.
FILE_ATTRIBUTE_SYSTEM | System file.
FILE_ATTRIBUTE_DIRECTORY | Subdirectory.
FILE_ATTRIBUTE_ARCHIVE | Archive file.
FILE_ATTRIBUTE_VOLUMELABEL | Volume label found.

ftCreationTime Returns the file creation time in the Win32 FileTime structure format.

Win32 FileTime Structure:
Value | Meaning
dwLowDateTime | Returns the low double word of the time in Win32 format.
dwHighDateTime | Returns the high double word of the time in Win32 format.

ftLastAccessTime | Returns the file last access time in Win32 FileTime structure format defined above.
ftLastWriteTime | Returns the file last write time in Win32 FileTime structure format defined above.
nFileSizeHigh | Returns the high 32-bits of the file size.
nFileSizeLow | Returns the low 32-bits of the file size.
cFileName | Returns the unicode long file name that was found.
CAlternateFileName | Returns the unicode alternate alias name (short file name) of the file that was found.

ir_pos Returns the find resume key for this find next operation. The operation of this key is described in the following.

Local FSDs need to return and also be able to take a find resume key as a parameter. This has been provided to optimize finds across the network by the server. The server typically does a bunch of find first/next operations and stores the information for each of them in a buffer, effectively providing some buffering on find next operations to prevent every find next operation from causing net traffic.

However, the network redirector might discard or reuse the buffers if necessary. In that case, the find operation needs to be resumed at that point where a findnext buffer is not valid, which is different from the point at which the find next operation was stopped at the server machine. To facilitate this, the server passes in a find resume key to the IFS which is then passed in to the FSDs, so they can throw away their current find next state and restart the find next at the point specified by the resume key. This means that the resume key must store enough information so that the find can be restarted at a particular point.

For example, on a FAT file system, the find resume key could be a combination of the cluster number and the index within the cluster of the directory entry last found. This way, when the resume key is passed in, the find next can be restarted at the correct spot. This does not need to be done by network FSDs, it is only local FSDs that handle drives that can be shared that need to implement this functionality.

This API should use LFN matching semantics for its operations only if either or both the FILE_FLAG_KEEP_CASE and FILE_FLAG_IS_LFN are set. The FSD should not assume that this API will always use LFN matching semantics by default. These flags are passed in by the IFS to indicate that LFN matching semantics need to be used. By default, this API will have LFN matching semantics. However, there are certain special cases, such as on the peer server, where a call that comes in via an LFN API still needs short-name matching semantics. If the FSD does not support LFNs on the volume, it should return an error on this function.


FS_FindNextFile

FS_FindNextFile(
 PIOREQ pir
 )

A Win32 find next operation is performed through FS_FindNextFile. The find context handle created by FS_FindFirstFile is passed to continue the search. This routine handles the Win32 function: FindNextFile() and the INT 21h function 714Fh.

ir_rh
Supplies handle to disk volume or network resource where the search is being done.
ir_fh
Supplies the find context handle obtained in a previous call to FS_FindFirstFile.
ir_data
Supplies a pointer to buffer where the find data for a file that is found is returned.
ir_sfn
Supplies system file number.
ir_options
Supplies options on the find next operation.
Find Next Option Values:
Value | Meaning
FILE_FIND_RESTART | Restart the find at the position designated by the find resume key passed in ir_pos. The operation of this key is described in greater detail in the following.

ir_pos
Supplies the find resume key. This parameter is passed in only if the FILE_FIND_RESTART option is specified.
ir_user
Supplies user ID for this request.
ir_pid
Supplies process ID for this request.
ir_error | Returns status of the operation (zero if no error, the error code otherwise).
ir_data | Returns find data for a file filled in the buffer in the following format if there was no error.

Find Data Structure:
Value | Meaning
dwFileAttributes | Returns the file attributes of the file found.

Attribute Values:

Any valid combination of the following attributes may be returned.

Value | Meaning
FILE_ATTRIBUTE_READONLY | Read-only file.
FILE_ATTRIBUTE_HIDDEN | Hidden file.
FILE_ATTRIBUTE_SYSTEM | System file.
FILE_ATTRIBUTE_DIRECTORY | Subdirectory.
FILE_ATTRIBUTE_ARCHIVE | Archive file.
FILE_ATTRIBUTE_VOLUMELABEL | Volume label found.

ftCreationTime Returns the file creation time in the Win32 FileTime structure format.

Win32 FileTime Structure:
Value | Meaning
dwLowDateTime | Returns the low double word of the time in Win32 format.
dwHighDateTime | Returns the high double word of the time in Win32 format.

ftLastAccessTime | Returns the file last access time in Win32 FileTime structure format defined above.
ftLastWriteTime | Returns the file last write time in Win32 FileTime structure format defined above.
nFileSizeHigh | Returns the high 32-bits of the file size.
nFileSizeLow | Returns the low 32-bits of the file size.
cFileName | Returns the unicode long file name that was found.
CAlternateFileName | Returns the unicode alternate alias name (short file name) of the file that was found.

ir_pos Returns the find resume key for this find next operation. The operation of this key is described above in the FS_FindFirstFile API documentation.


FS_FlushVolume

FS_FlushVolume(
 PIOREQ pir
 )

The cached buffers for the file systems are committed to disk through FS_FlushVolume. This routine handles the INT 21h function: 0Dh.

All of the cached or buffered data for the file system must be written out to disk when this function is called.

ir_rh
Supplies handle to disk volume or network resource on which data needs to be flushed out.
ir_options
Supplies processing options.
Processing Option Values:

The following option may be specified.

Value | Meaning
VOL_DISCARD_CACHE | Indicator to discard cached/buffered data. If this option is specified then all data buffers associated with the volume should be discarded.
VOL_REMOUNT | This flag can only be specified alone. The FSD should discard any current cached information about this volume and mount the volume again. If there are any open files or pending I/O on this volume, the operation should be failed. Typically, this function is used by disk utilities that have reformatted a volume so that its disk geometry has changed. It provides the means to indicate to an FSD that the volume geometry of a volume it is mounted on has changed and should be re-read.

ir_user
Supplies user ID for this request.
ir_pid
Supplies process ID for this request.
ir_error Returns status of the operation (zero if no error, the error code otherwise).


FS_GetDiskInfo

FS_GetDiskInfo(
 PIOREQ pir
 )

Information about a disk is obtained through FS_GetDiskInfo. This routine handles the Win32 function: GetDiskFreeSpace(); and INT 21 functions: 1Bh, 1Ch, and 36h.

ir_rh
Supplies handle to disk volume or network resource to get info on.
ir_flags
Supplies special flags for this function.
GetDiskInfo Flags:
GDF_NO_DISK_HIT This flag is a hint flag to the FSD. It specifies that the FSD should, if possible, return a close approximation to the freespace on the disk without accessing the disk in any fashion. This is an optimization that is used by some components in the system. It is not mandatory to implement this except in certain special cases. See the notes in the following for more details.

ir_user
User ID for this request.
ir_pid
Process ID for this request.
ir_error | Returns status of the operation (zero if no error, the error code otherwise).
ir_length | Returns number of bytes per sector.
ir_size | Returns total number of allocation units.
ir_data | Returns an optional pointer to the file allocation table (FAT) identification byte. This is only required for local FAT file systems.
ir_sectors | Returns number of sectors per allocation unit.
ir_numfree | Returns number of free allocation units.

The GDF_NO_DISK_HIT flag must be supported by an FSD that is using the IOS for its operation, reports itself as a protect-mode drive, and is also servicing the paging volume. Even in this case, the FSD can return a value of -1 to indicate that it cannot provide an approximation to the disk free size. This negates the optimization. In all other cases, FSDs can safely ignore this flag and perform the normal operation to get the disk free space by hitting the disk, if necessary.


FS_GetDiskParms

FS_GetDiskParms(
 PIOREQ pir
 )

This function handles INT 21h function 32h ( Get DPB address ). The FSD must return the real mode address of the DOS DPB for the drive and must update the real mode DPB if necessary. An FSD can fail this call if it does not maintain DPBs.

ir_rh
Supplies volume handle for the disk resource.
ir_user
Supplies user id for this request.
ir_pid
Supplies process id for this request.
ir_error | Returns status of the operation (zero if no error, the error code otherwise).
ir_aux1 | Returns DPB real-mode address. High word contains the segment and the low word contains the offset of the DPB.


FS_Ioctl16Drive

FS_Ioctl16Drive(
 PIOREQ pir
 )

All IOCtl operations are performed through FS_Ioctl16Drive. This routine handles INT 21h function 44h.

ir_rh
Supplies the volume handle for the disk resource.
ir_flags
Supplies the IOCtl sub-function. The sub-function numbers are the same as the IOCtl sub-functions defined in DOS.
ir_options
Supplies special options for the IOCtl operation.
IOCtl Options:
Value | Meaning
IOCTL_PKT_LINEAR_ADDRESS | This flag specifies that the IOCtl parameter packet's address should not be picked up from the client registers, which is the default. In this case, the linear address of the packet is passed in ir_data. Any pointers in the packet have been resolved to be normal V86 addresses.

ir_cregptr
Supplies a pointer to the client register structure. The FSD picks up all its parameters directly from the client registers. The only exception is when the IOCTL_PKT_LINEAR_ADDRESS option is specified.
ir_data
Supplies the linear address of the IOCtl packet if the IOCTL_PKT_LINEAR_ADDRESS flag is specified.
ir_user
Supplies user ID for this request.
ir_pid
Supplies process ID for this request.
ir_error | Returns status of the operation (zero if no error, the error code otherwise).
ir_cregptr | Returns the appropriate register values for the corresponding IOCtl.

In most cases, the FSD would just pass this request down to the driver. For some requests, it might want to look at the requests, so that it can flush its cache for instance. There are some IOCtl requests that the FSD might have to process on its own, for example, Get/Set Media Id. Except for some cases, the IFS manager usually does not translate any of the pointers that are passed in the registers. It is the responsibility of the FSD or the driver that handles the IOCtl request to perform all pointer translations.


FS_LockFile

FS_LockFile(
 PIOREQ pir
 )

File record lock and unlock is performed through FS_LockFile. This routine handles the Win32 functions: LockFile(), and UnlockFile(); and INT 21h function: 5Ch.

ir_rh
Supplies handle to disk volume or network resource that contains the file.
ir_fh
Supplies FSD file handle.
ir_sfn
Supplies system file number.
ir_flags
Supplies lock type to be performed.
Lock Type Values:

One of the following types will be specified.

Value | Meaning
LOCK_REGION | Region is to be locked.
UNLOCK_REGION | Region is to be unlocked.

ir_options
Supplies special options for the lock/unlock operation.
Lock Option Values:
Value | Meaning
LOCKF_RD | This option specifies that the FSD should implement the special read lock semantics that Netware supports. See the following for more details about this.
LOCKF_NW | This option is specified if the lock and unlock operations should be implemented as per the Netware semantics. Netware semantics for the lock and unlock operations are different from DOS semantics.

ir_locklen
Supplies length of lock region.
ir_pos
Supplies file position offset to lock region.
ir_user
Supplies user ID for this request.
ir_pid
Supplies process ID for this request.
ir_error Returns status of the operation (zero if no error, the error code otherwise).

Netware has different semantics for the lock and unlock operations. It has a read lock that allows processes to read from the file but not write to the file. There can be multiple, overlapping read locks by different processes on a file. A read lock can be promoted to a write lock provided there are no other read locks by other processes on that region. Similarly, a write lock can be demoted to a read lock. The traditional DOS locking semantics are similar to the Netware write lock semantics. It does not allow overlapping locks on a file and there is no concept of lock promotion or demotion. For additional details on the Netware semantics, please refer to Netware documentation.


FS_MountVolume

FS_MountVolume(
 PIOREQ pir
 )

The linkage between an FSD and a disk volume is established and discontinued through FS_MountVolume.

ir_flags
Supplies mount type to be performed.
Mount Type Values:

One of the following types will be specified.

Value | Meaning
IR_FSD_MOUNT | Mount a disk volume. This usually happens on the first access to the media or if the media is removable and the volume has changed.
IR_FSD_VERIFY | Verify that the volume mounted has not changed.
IR_FSD_UNLOAD | The disk resource has disappeared, unmount this volume unconditionally.
IR_FSD_MOUNT_CHILD | This volume is a child volume of an already mounted volume. Child volumes are treated as a single unit along with the parent volume. Compressed volumes, such as DoubleSpace have child volumes or CVFs associated with a parent volume. The FSD should chain all these resources so that when it is called to unmount the parent volume, all the child volumes are also unmounted.
IR_FSD_MAP_DRIVE | Switch the driveletter for the volume. Driveletters are typically switched when mounting compressed media. The FSD should use the new driveletter while referring to this volume.
IR_FSD_UNMAP_DRIVE | Switch the driveletter back to the original drive. When a compressed volume gets unmounted, the driveletter needs to be switched back. The FSD should now use this driveletter to refer to the volume.

Operation Type IR_FSD_MOUNT:
Value
Meaning
ir_volh
Supplies a system volume handle. The system volume handle is used by the IOS to identify a volume and is typically passed down to the IOS by the FSD on an I/O operation.
ir_mntdrv
Drive identifier for the drive to be mounted.
ir_fh
Supplies the IFS resource handle for this volume. This is to be used purely for identification purposes only.
ir_rh
Supplies the linear address of the head of the DOS DPB chain. The ifs manager makes sure that there is a DPB structure corresponding to this drive on this chain. The FSD will need to walk the DPB list to find the DPB for this drive.
Operation Type IR_FSD_VERIFY:
This operation is not called by the IFS manager, the FSD is directly called by the volume tracking driver.
Operation Type IR_FSD_UNLOAD:
This operation is not called by the IFS manager, the FSD is directly called by the volume tracking driver.
Operation Type IR_FSD_MOUNT_CHILD:
Value
Meaning
ir_rh
Supplies the FSD resource handle for the parent volume.
ir_fh
Supplies the IFS resource handle for the parent volume. This is to be used purely for identification purposes only.
ir_volh
Supplies the system volume handle for the parent volume.
ir_mntdrv
Drive identifier for the drive to be mounted.
Operation Type IR_FSD_MAP_DRIVE:
Value
Meaning
ir_rh
Supplies the FSD resource handle for the volume.
ir_options
Supplies the new driveletter for the volume.
ir_fh
Supplies the IFS resource handle for the parent volume. This is to be used purely for identification purposes only.
Operation Type IR_FSD_UNMAP_DRIVE:
This operation is not called by the IFS manager, it is called directly by the driver.
ir_error Returns status of the operation (zero if no error, the error code otherwise). There is a special error of ERROR_VOLUME_EXISTS that can be returned by the FSD if it already has a resource mounted on the volume that is valid. See the following for details.

Operation Type IR_FSD_MOUNT, IR_FSD_MOUNT_CHILD:
Value | Meaning
ir_rh Returns an FSD volume handle to the disk volume for mount on a successful mount.

This handle is used to identify the disk volume and is passed back to the FSD during file operations on the specified disk volume. The value of this handle is not interpreted by the IFS managers, it is only used to identify the disk volume.

If the special error of ERROR_VOLUME_EXISTS is returned, then this field should contain the previous system volume handle. The IFS manager uses this returned system volume handle to identify the IFS resource handle for this volume.

ir_vfunc | Returns a pointer to a function table, in the FSD, containing a list of the FSD name based file I/O entry points. This field should not be returned if an error status of ERROR_VOLUME_EXISTS is returned.

Function Table Structure:
Value | Meaning
vfn_version | IFS version number.
vfn_revision | IFS interface revision number.
vfn_sizec | Number of function entry points in table.
vfn_func[NUM_VOLFUNC] | Array of pointers to volume-based functions as described in the following:

Volume Based Functions:
Value | Meaning
vfn_func[VFN_DELETE] | Pointer to FS_DeleteFile function.
vfn_func[VFN_DIR] | Pointer to FS_Dir function.
vfn_func[VFN_FILEATTRIB] | Pointer to FS_FileAttributes function.
vfn_func[VFN_FLUSH] | Pointer to FS_FlushVolume function.
vfn_func[VFN_GETDISKINFO] | Pointer to FS_GetDiskInfo function.
vfn_func[VFN_OPEN] | Pointer to FS_OpenFile function.
vfn_func[VFN_RENAME] | Pointer to FS_RenameFile function.
vfn_func[VFN_SEARCH] | Pointer to FS_SearchFile function.
vfn_func[VFN_QUERY] | Pointer to FS_QueryResourceInfo function.
vfn_func[VFN_DISCONNECT] | Pointer to FS_DisconnectResource function.
vfn_func[VFN_UNCPIPEREQUEST] | Function not defined for volume mounts, FSD must return pointer to error function.
vfn_func[VFN_IOCTL16DRIVE] | Pointer to FS_Ioctl16Drive function.
vfn_func[VFN_GETDISKPARMS] | Pointer to FS_GetDiskParms function.
vfn_func[VFN_FINDOPEN] | Pointer to FS_FindFirstFile function.
vfn_func[VFN_DASDIO] | Pointer to FS_DirectDiskIO function.

ir_tuna Returns flags about whether FSD wants tunnelling to be done on this volume.

Tunnelling Flag Values:
Value | Meaning
IR_TUNA_NOTUNNEL | No tunnelling should be done on this volume.
IR_TUNA_FSDTUNNEL | The FSD implements tunnelling on its own on this volume.
IR_TUNA_IFSTUNNEL | The IFS must enable its default tunnelling support on this volume.

Operation Type IR_FSD_VERIFY:

This operation is not called by the IFS manager, the FSD is directly called by the volume tracking driver.

Operation Type IR_FSD_UNLOAD:

This operation is not called by the IFS manager, the FSD is directly called by the volume tracking driver.

Operation Type IR_FSD_MAP_DRIVE:

This operation has no other explicit return status.

Operation Type IR_FSD_UNMAP_DRIVE:

This operation is not called by the IFS manager, it is called directly by the driver.

An IR_FSD_MOUNT operation is performed when the disk is initially accessed and when the media has changed. The FSD should examine the disk volume and determine if it recognizes the file system disk format. If the volume is recognized, the FSD should save the information it requires about the volume and return a handle for the volume. The IFS manager uses the returned volume handle to indicate to the FSD which disk volume a path-named I/O request should be performed on. The volume handle is also used to track the disk volumes that may be in a removable media drive.

The FSD must verify if the disk volume has already been mounted. If it has been previously mounted then the previously returned system volume handle and FSD volume handle should be returned. Otherwise the disk volume will be considered a separate volume.

If the FSD determines that the media is a new volume, the FSD should save the system volume handle and drive identifier. The system volume handle should be used by the FSD during disk I/O requests to identify the disk volume to the I/O system. The drive identifier should be used by the FSD during a mount to verify that a previously mounted volume is on the same drive.


FS_OpenFile

FS_OpenFile(
 PIOREQ pir
 )

All file open and create operations are handled through FS_OpenFile. This routine handles the Win32 functions: OpenFile(), and CreateFile(); and INT 21h functions: 0Fh, 16h, 3Ch, 3Dh, 5Ah, 5Bh, 6Ch and 716Ch.

ir_ppath
Supplies a pointer to the canonicalized unicode path name to the file that is to be opened. Wildcards are not allowed on the path name.

If ir_ppath is NULL, it indicates that this is a special kind of open where there is no path available, only cluster and directory information is available. This special kind of open is issued by the IFS manager when it is taking over a file handle left open by a TSR before booting into Windows. For such files, the IFS manager extracts the information from DOS about the cluster number and the directory position for the open file. The FSD needs to locate the file given this information. A pointer to a structure containing this information is passed in ir_uFName. Note that this kind of open can be issued only on FAT file systems because the only native system supported by MS-DOS is the FAT file system.

ir_rh
Supplies handle to disk volume or network resource where the file is to be opened.
ir_sfn
Supplies system file number.
ir_flags
Supplies desired access and sharing mode info.
Desired Access Values:

One of the following values may be specified.

Value | Meaning
ACCESS_READONLY | Open for read-only access.
ACCESS_WRITEONLY | Open for write-only access.
ACCESS_READWRITE | Open for read and write access.
ACCESS_EXECUTE | Open for execute access.
Sharing Mode Values:

This defines the file access granted to other processes. One of the following modes may be specified.

SHARE_COMPATIBILITY | Open in compatibility mode.
SHARE_DENYREADWRITE | Open for exclusive access.
SHARE_DENYWRITE | Open allowing read-only access.
SHARE_DENYREAD | Open allowing write-only access.
SHARE_DENYNONE | Open allowing other processes access.
SHARE_FCB | Open in the special FCB mode.

ir_options
Supplies the open action to take if file exists or not. Also supplies some special options that are independent of the open action.
Open Action Values:

One of the following actions or a combination of actions may be specified. Specifies the action to take if the file exists or not exists.

Value | Meaning
ACTION_CREATENEW | Create a new file. Fail if the file already exists.
ACTION_CREATEALWAYS | Create a new file. If the file already exists open it and set its new length and attributes.
ACTION_OPENEXISTING | Open an existing file. Fail if the file does not exist.
ACTION_OPENALWAYS | Open an existing file. If the file does not exist, create a new file.
ACTION_REPLACEEXISTING | Open an existing file and set its new length. Fail if the file does not exists.
Special Options:

The following special options can also be passed in on this API.

Value | Meaning
OPEN_FLAGS_COMMIT | The file should be opened in writethrough mode, that is, all data should be written synchronously to the disk. The data can be cached, but no dirty data should remain in the cache across calls to write to the file.
OPEN_FLAGS_NO_CACHE | Read/write operations to this file should not be cached. There should be no data kept in the cache for this file. This also means that the file system should not do read-aheads and other optimizing techniques on this file.
OPEN_FLAGS_NO_COMPRESS | The file should not be compressed when it is created or changed.
OPEN_FLAGS_ALIAS_HINT | This is valid only on a create operation. The caller can pass in a number from zero to 65535 to be used as a hint by the FSD for the numeric tail if it is auto-generating names. If the FSD does not auto-generate names, this flag should be ignored. This is purely an advisory option.
OPEN_FLAGS_REOPEN | The file is being reopened by IFS manager when a Level 3 volume lock is released (the file was temporarily closed by IFS manager for the duration of the Level 3 volume lock).
R0_SWAPPER_CALL | This operation is on the swap file. The swap file needs special handling as has already been discussed in Section 8.3.4.

ir_attr
Supplies new file attribute for create operations. These attributes should be ignored when an existing file is opened or truncated. It also supplies advisory path parsing flags.
Attribute Values:

Any combination of the following attributes may be specified or returned.

Value | Meaning
FILE_ATTRIBUTE_READONLY | Read-only file.
FILE_ATTRIBUTE_HIDDEN | Hidden file.
FILE_ATTRIBUTE_SYSTEM | System file.
FILE_ATTRIBUTE_DIRECTORY Subdirectory.

The following attribute will only be specified by itself. It will not be combined with any of the other attributes.

FILE_ATTRIBUTE_VOLUMELABEL | Volume label.
Path Parsing Flags:

The following path parsing flags are passed in.

FILE_FLAG_LONG_PATH | Path has a long name component.
FILE_FLAG_KEEP_CASE | Preserve the case of the file name passed in when storing on disk. This also implies that this call should use long name semantics for its processing.
FILE_FLAG_HAS_DOT | File name component has a dot in its name.
FILE_FLAG_IS_LFN | File name component is a long name.

ir_uFName
Pointer to the case-preserved file name component in unicode if ir_ppath is a valid pointer. If ir_ppath is NULL, then this field contains a pointer to an open information structure SFTOpenInfo as described in the following.
SFTOpenInfo Structure:
Value | Meaning
soi_dirclus | Supplies the logical cluster number of the directory cluster for the open file.
soi_dirind | Supplies the index of the directory entry of the open file in the directory cluster pointed at by soi_dirclus.

soi_dirname
Supplies the 11-character name of the open file in FCB format.
ir_upath
Pointer to the unparsed user path name in unicode.
ir_hfunc
Supplies a pointer to a function pointer structure.
ir_ptuninfo
Supplies a pointer to a tunnelling structure. A NULL pointer is passed in this field if there is no tunnelling information. The tunnelling structure is described in the following.
Tunnelling Structure:
Value | Meaning
tuni_bfContents | Specifies flags for the tunnelling information passed in.

Tunnelling Info Flag Values:
Value | Meaning
TUNI_CONTAINS_ALTNAME | Alternate unicode name is available in structure.
TUNI_CONTAINS_CREATIONT | Creation time for file available.
TUNI_CONTAINS_LASTACCESST | Last access time for file available.
TUNI_CONTAINS_LASTWRITET | Last modification time for file available.

tuni_pAltName
Supplies the alternate name in unicode that should be used for this file.
tuni_ftCreationTime
Supplies the creation time in the Win32 FileTime structure format specified in the following.
Win32 FileTime Structure:
Value | Meaning
dwLowDateTime | Supplies the low double word of the time in Win32 format.
dwHighDateTime | Supplies the low double word of the time in Win32 format.

tuni_ftLastAccessTime
Supplies the last access time in the Win32 FileTime structure format described above.
tuni_ftLastWriteTime
Supplies the last modification time in the Win32 FileTime structure format described above.
ir_pos
Supplies the pointer to the list of file record locks returned previously on FS_CloseFile when a volume lock is in progress. This parameter is NULL if there were no file record locks active on the file at the time it was closed. If the OPEN_FLAGS_ALIAS_HINT flag is set, this field supplies the hint value to be used for the numeric tail. FSDs should first check for the OPEN_FLAGS_ALIAS_HINT flag. If it is set, this field provides the hint value. If not set, this field supplies the pointer to the lock list.
ir_fh
Supplies the FSD file handle associated with this file before the file was closed. This parameter should be used only if there were file record locks active on the file, in other words, ir_pos is non-NULL. This parameter is passed in to the FSD so that it can identify the lock corresponding to the handle that is being reopened and keep its data structures consistent. Volume locking is described in detail in the volume locking specification.
ir_user
Supplies user ID for this request.
ir_pid
Supplies process ID for this request.
ir_error | Returns status of the operation (zero if no error, the error code otherwise).
ir_fh | Returns the FSD file handle identifying the opened file.
ir_dostime | Returns the file modification date and time (in DOS format).
ir_hfunc | Returns a filled in function pointer structure. The structure is filled in as follows:

Function Pointer Structure:
Value | Meaning
hf_read | Returns pointer to FS_ReadFile function.
hf_write | Returns pointer to FS_WriteFile function.
hf_misc | Returns a pointer to a function table structure, in the FSD, containing a list of the remaining FSD handle based file I/O entry points.

Function Table Structure:
Value | Meaning
hm_version | IFS version number.
hm_revision | IFS interface revision number.
hm_size | Number of function entry points in table.
hm_func[NUM_HNDLMISC] | Returns an array of pointers to the handle-based functions as described in the following:
hm_func[HM_SEEK] | Pointer to FS_SeekFile function.
hm_func[HM_CLOSE] | Pointer to FS_CloseFile function.
hm_func[HM_COMMIT] | Pointer to FS_CommitFile function.
hm_func[HM_FILELOCKS] | Pointer to FS_LockFile function.
hm_func[HM_FILETIMES] | Pointer to FS_FileTime function.
hm_func[HM_PIPEREQUEST] | Pointer to FS_NamedPipeUNCRequest function.
hm_func[HM_HANDLEINFO] | Pointer to FS_NamedPipeHandleInfo function.
hm_func[HM_ENUMHANDLE] | Pointer to FS_EnumerateHandle function.

ir_options Returns the action performed by the FSD.

Return Action Values:

One of the following actions may be returned.

Value | Meaning
ACTION_OPENED | An existing file has been opened.
ACTION_CREATED | A new file has been created.
ACTION_REPLACED | An existing file has been truncated.

ir_size | Returns the file size when an existing file is opened. The size is currently placed in the SFT in the DOS data structures.
ir_attr | Returns the file attribute (state for named pipes).

Return Attribute Values:

Any combination of the following attributes may be returned.

Value | Meaning
FILE_ATTRIBUTE_READONLY | Read-Only file.
FILE_ATTRIBUTE_HIDDEN | Hidden file.
FILE_ATTRIBUTE_SYSTEM | System file.
FILE_ATTRIBUTE_DIRECTORY | Subdirectory.
FILE_ATTRIBUTE_ARCHIVE Archive file.

This attribute cannot be returned in combination with other attributes.

FILE_ATTRIBUTE_VOLUMELABEL | Volume label.

If an FS does not support long file names on a volume and it gets a LFN API call on that volume, it should fail the call. Tunnelling is described separately in another Section. Tunnelling is supported only on local drives. Therefore, network FSDs do not need to honor the tunnelling information.


FS_QueryResourceInfo

FS_QueryResourceInfo(
 PIOREQ pir
 )

FS_QueryResourceInfo returns information about the resource in question. It returns the name of the resource and other relevant information. This routine handles the Win32 function GetVolumeInfo().

ir_rh
Supplies handle to the resource.
ir_options
Supplies the level of information requested.
Information Levels:
Level 0 | Return the name of the resource. This request should be processed only by network FSDs. Local FSDs should fail this call.
Level 1 | Return Level 0 information and additional information about the resource type and status. This request should be processed only by network FSDs. Local FSDs should fail this call.
Level 2 | Return information about the name of the file system on the resource and other file system specific information. This request should be processed by both network and local FSDs.

ir_ppath
Supplies a pointer to the buffer to contain the unicode name of the resource that is returned by the FSD. This field is a parameter only on the Level 0 and 1 requests.
ir_data
Supplies pointer to a buffer where the file system name is to be returned. This field is supplied only for a Level 2 request.
ir_length
Supplies the maximum length of the buffer the file system name is to be returned in. This field is supplied only for a Level 2 request.
ir_user
Supplies user ID for this request.
ir_pid
Supplies process ID for this request.
ir_error | Returns status of the operation (zero if no error, the error code otherwise).
Level 0 Request
ir_ppath | Returns the name of the resource in unicode.
Level 1 Request
ir_ppath | Returns the name of the resource in unicode.
ir_options | Returns information about the status of the resource.

Resource Status Values:
Value | Meaning
RESSTAT_OK | Connection to resource is still valid.
RESSTAT_PAUSED | Connection to resource paused by workstation.
RESSTAT_DISCONN | Resource is disconnected.
RESSTAT_ERROR | Resource cannot be reconnected due to error.
RESSTAT_CONN | First connection to resource in progress.
RESSTAT_RECONN | Reconnection to resource in progress.

ir_flags Returns connection resource type.

Connection Resource Type Values:
Value | Meaning
RESTYPE_WILD | Wild card resource type.
RESTYPE_DISK | Disk resource.
RESTYPE_SPOOL | Spooled printer resource.
RESTYPE_CHARDEV | Character device resource.
RESTYPE_IPC | Interprocess communication resource.

Level 2 Request
ir_length | Returns the maximum length of a single path component (excluding the NUL character) supported by the file system in the low word and the maximum length of the path (including the NUL character) supported by the file system in the high word. This value should be returned only on a Level 2 request.
ir_options | Returns flags associated with the specified file system. This value should be returned only for a Level 2 request.

Filesystem Flag Values:
Value | Meaning
FS_CASE_IS_PRESERVED | The case of the file name is preserved when it is stored on the disk.
FS_UNICODE_STORED_ON_DISK | The long file name is stored in unicode on the disk.
FS_VOL_SUPPORTS_LONG_NAMES | The file system supports long file names on this volume.
FS_VOL_IS_COMPRESSED | The file system does data compression on this volume.

ir_pos Returns the cache block size of the file system that is handling the volume.

Level 0 and 1 requests should be honored only by network FSDs. Local FSDs should fail these requests with an ERROR_INVALID_FUNCTION.


FS_ReadFile

FS_ReadFile(
 PIOREQ pir
 )

Operations that read from a normal file are handled through FS_ReadFile. This routine handles the Win32 function: ReadFile(); and INT 21h functions: 14h, 21h, 27h, and 3Fh.

ir_rh
Supplies handle to disk volume or network resource that contains the file.
ir_fh
Supplies FSD file handle.
ir_sfn
Supplies system file number.
ir_data
Supplies a pointer to the data buffer to read into.
ir_length
Supplies number of bytes of data to read.
ir_pos
Supplies file position to begin reading at.
ir_options
Supplies processing options.
Processing Option Values:

Any combination of the following options may be specified.

Value | Meaning
R0_NO_CACHE | File data should not be cached, that is, no read-ahead or caching on the read operation.
R0_SWAPPER_CALL | This read operation is issued for the swap-file by the memory manager. Any FSD that allows paging to be done through it needs to observe some special rules to make the system work smoothly. These have already been described in Section 8.3.4 of this document.
R0_MM_READ_WRITE | This flag is passed in to indicate a read operation to a memory-mapped file. There is one special case in which it is used to indicate that a memory mapping has been created to an existing open file. This is when a read of zero bytes is issued, that is, ir_length contains zero. When this special case is indicated, the FSD needs to lock down all data structures associated with the open file to prevent deadlocks. This is done prior to any other user-initiated reads are done to this memory-mapped file. This has already been described in Section 8.3.5 of this document. In all other cases, this flag indicates that the current read operation is for a memory-mapped file. The FSD needs to treat these operations in a special manner as described in Section 8.3.5.

ir_user
Supplies user ID for this request.
ir_pid
Supplies process ID for this request.
ir_error | Returns status of the operation (zero if no error, the error code otherwise).
ir_length | Returns number of bytes actually read.
ir_pos | Returns new file position.

This operation may take place asynchronously, and it is recommended that the implementation of this function be async when ever possible. To do this, the function may return STATUS_PENDING to allow the caller to continue processing while the operation completes. If STATUS_PENDING is returned, the IFSMgr_CompleteAsync service in the IFSMGR must be called when the operation completes. The address of the I/O request packet must be passed to identify the completed request.


FS_RenameFile

FS_RenameFile(
 PIOREQ pir
 )

A file is renamed through FS_RenameFile. This routine handles the Win32 function, MoveFile(); and INT 21h functions: 17h, and 56h.

ir_ppath
Supplies a pointer to the canonicalized unicode source path name to be renamed. The path name may contain wildcards only if it is an 8.3 path name. Long file name paths will not contain wildcards.
ir_rh
Supplies handle to disk volume or network resource that contains the file.
ir_attr
Supplies wildcard search attributes and advisory path parsing flags for the source path.
Search Attribute Values:

Any combination of the following attributes may be specified, causing those files to be included with normal files in the search.

Value | Meaning
FILE_ATTRIBUTE_HIDDEN | Include hidden file in search.
FILE_ATTRIBUTE_SYSTEM | Include system file in search.
FILE_ATTRIBUTE_DIRECTORY Include subdirectories in search.

The following attribute will only be specified by itself. It will not be combined with any of the other attributes.

FILE_ATTRIBUTE_VOLUMELABEL | Search for volume label only.
Path Parsing Flags:

The following path parsing flags are passed in.

Value | Meaning
FILE_FLAG_WILDCARDS | Wildcard characters present in path name.
FILE_FLAG_LONG_PATH | Path has a long name component.
FILE_FLAG_KEEP_CASE | Preserve the case of the file name passed in when storing on disk. This also implies that this call should use long name semantics for its processing.
FILE_FLAG_HAS_DOT | File name component has a dot in its name.
FILE_FLAG_IS_LFN | File name component is a long name.

ir_ppath2
Supplies a pointer to the canonicalized unicode destination path name to rename to.
ir_attr2
Supplies wildcard search attributes and advisory path parsing flags for the destination path.
Search Attribute Values:

Any combination of the following attributes may be specified, causing those files to be included with normal files in the search.

Value | Meaning
FILE_ATTRIBUTE_HIDDEN | Include hidden file in search.
FILE_ATTRIBUTE_SYSTEM | Include system file in search.
FILE_ATTRIBUTE_DIRECTORY Include subdirectories in search.

The following attribute will only be specified by itself. It will not be combined with any of the other attributes.

FILE_ATTRIBUTE_VOLUMELABEL | Search for volume label only.
Path Parsing Flags:

The following path parsing flags are passed in.

Value | Meaning
FILE_FLAG_WILDCARDS | Wildcard characters present in path name.
FILE_FLAG_LONG_PATH | Path has a long name component.
FILE_FLAG_KEEP_CASE | Preserve the case of the file name passed in when storing on disk. This also implies that this call should use long name semantics for its processing.
FILE_FLAG_HAS_DOT | File name component has a dot in its name.
FILE_FLAG_IS_LFN | File name component is a long name.

ir_ptuninfo
Supplies a pointer to a tunnelling structure. A NULL pointer is passed in this field if there is no tunnelling information. The tunnelling structure is described in the following.
Tunnelling Structure:
Value | Meaning
tuni_bfContents | Specifies flags for the tunnelling information passed in.
Tunnelling Info Flag Values:
Value | Meaning
TUNI_CONTAINS_ALTNAME | Alternate unicode name is available in structure. This is the name to be used for the destination of the rename.
TUNI_CONTAINS_CREATIONT | Creation time for file available.
TUNI_CONTAINS_LASTACCESST | Last access time for file available.
TUNI_CONTAINS_LASTWRITET | Last modification time for file available.

tuni_pAltName
Supplies the alternate name in unicode that should be used for this file.
tuni_ftCreationTime
Supplies the creation time in the Win32 FileTime structure format specified in the following.
Win32 FileTime Structure:
Value | Meaning
dwLowDateTime | Supplies the low double word of the time in Win32 format.
dwHighDateTime | Supplies the low double word of the time in Win32 format.
tuni_ftLastAccessTime | Supplies the last access time in the Win32 FileTime structure format described above.
tuni_ftLastWriteTime | Supplies the last modification time in the Win32 FileTime structure format described above.

ir_uFname
Pointer to the case-preserved file name component of the destination path in unicode.
ir_user
Supplies user ID for this request.
ir_pid
Supplies process ID for this request.
ir_error Returns status of the operation (zero if no error, the error code otherwise).

If an FSD does not support long file names on a volume and it gets a LFN API call on that volume, it should fail the call. Note that FS_RenameFile can also rename entire directory trees. Obviously, the FSD cannot validate if all paths of the renamed directory can be accessed, some subdirectories may not be accessible any more if the path becomes longer than the maximum allowed path. The FSD should check for cyclic directory renames and fail them. A rename of a file to itself should not failed, the FSD should just return success and do nothing. Local FSDs also need to honor the tunnelling information if they do not implement tunnelling on their own. Tunnelling is not supported on network drives. Therefore, network FSDs do not need to support this. Tunnelling is described separately in another section of this document.


FS_SearchFile

FS_SearchFile(
 PIOREQ pir
 )

All DOS find first and find next operations are performed through FS_SearchFile. This routine handles the INT 21h functions: 11h, 12h, 4Eh, and 4Fh.

ir_ppath
Supplies a pointer to the canonicalized unicode path name to search for. This is passed in only for a SEARCH_FIRST operation and is set to NULL on find next requests. Wildcards are allowed on the path name.
ir_rh
Supplies handle to disk volume or network resource where the path name is to be searched for.
ir_flags
Supplies the operation to perform.
Search Operation Values:
Value | Meaning
SEARCH_FIRST | Do a FindFirst operation on the path passed in.
SEARCH_NEXT | Do a FindNext operation on the path passed in on the SEARCH_FIRST operation.

ir_attr
Supplies wildcard search attributes. This is supplied only for SEARCH_FIRST requests.
Search Attribute Values:

Any combination of the following attributes may be specified, causing those files to be included with normal files in the search.

Value | Meaning
FILE_ATTRIBUTE_HIDDEN | Include hidden file in search.
FILE_ATTRIBUTE_SYSTEM | Include system file in search.
FILE_ATTRIBUTE_DIRECTORY Include subdirectories in search.

The following attribute will only be specified by itself. It will not be combined with any of the other attributes.

FILE_ATTRIBUTE_VOLUMELABEL | Search for volume label only.

ir_uFname
Pointer to the case-preserved file name component in unicode.
ir_upath
Pointer to the unparsed user path name in unicode.
ir_data
Supplies a pointer to the search info structure that is described in the following.
ir_user
Supplies user ID for this request.
ir_pid
Supplies process ID for this request.
ir_error | Returns status of the operation (zero if no error, the error code otherwise).
ir_data | Returns the information about the find in the search info structure. The contents of the supplied structure is the same as the information returned on a path based INT 21h search function. On a successful return the search info structure returns information required for a find next request that is filled in by the FSD. This information is stored in the users address space and is passed back on find next requests.

Search Info Structure:
Value | Meaning
se_key | Search key structure that contains information pertinent to the search operation that is in progress.
Search Key Structure:
Value | Meaning
sk_drive | Drive value. This field is set by the IFS manager and will be overwritten. The FSD should not change this field.
sk_pattern[11] | Returns file name pattern being searched for. This field is set and used by the FSD to continue the search operation. The file name must be stored in the FCB 8.3 format.
sk_attr | Search attributes. This field is set and used by the FSD to continue searches.
sk_localFSD[4] | Returns local FSD continuation fields. These bytes should be used to save the information required to continue the search operation. The typical values saved are those used to locate the directory and the last entry with in the directory.
sk_netFSD[2] | Returns remote FSD continuation fields. These bytes should be used to save the information required to continue the search operation by network FSDs.
sk_ifsmgr[2] | Reserved for use by the IFS manager.

se_attrib Returns attributes of matched file.

Return Attribute Values:

Any combination of the following attributes may be returned.

Value | Meaning
FILE_ATTRIBUTE_READONLY | Read-Only file.
FILE_ATTRIBUTE_HIDDEN | Hidden file.
FILE_ATTRIBUTE_SYSTEM | System file.
FILE_ATTRIBUTE_DIRECTORY | Subdirectory.
FILE_ATTRIBUTE_ARCHIVE Archive file.

This attribute cannot be returned in combination with other attributes.

FILE_ATTRIBUTE_VOLUMELABEL | Volume label.

se_time | Returns DOS file time of matched file. This field is set by the FSD.
se_date | Returns DOS file date of matched file. This field is set by the FSD.
se_size | Returns size of matched file. This field is set by the FSD.
se_name[13] | Returns file name of matched file. This field is set by the FSD to the matching file name found by the search. The file name must be stored as an 8.3 format ASCIIZ string.

ir_firstclus Returns first cluster of the file. This field is needed only for FCB-based search operations and is updated separately by the IFS. This field is valid only for FAT-based file systems. A zero value should be returned by non-FAT-based FSDs.


FS_WriteFile

FS_WriteFile(
 PIOREQ pir
 )

Operations that write to a normal file are handled through FS_WriteFile. This routine handles the Win32 function: WriteFile(); and INT 21h functions: 15h, 22h, 28h, and 40h.

ir_rh
Supplies handle to disk volume or network resource that contains the file.
ir_fh
Supplies FSD file handle.
ir_sfn
Supplies system file number.
ir_data
Supplies a pointer to the data buffer to write.
ir_length
Supplies number of bytes of data to write.
ir_pos
Supplies file position to begin writing.
ir_options
Supplies processing options.
Processing Option Values:

Any combination of the following options may be specified.

Value | Meaning
R0_NO_CACHE | File data should be written directly to the disk without going through the cache.
R0_SWAPPER_CALL | This read operation is issued for the swap-file by the memory manager. Any FSD that allows paging to be done through it needs to observe some special rules to make the system work smoothly. These have already been described in Section 8.3.4 of this document.
R0_MM_READ_WRITE | This flag is passed in to indicate a write operation to a memory-mapped file. The FSD needs to treat these operations in a special manner as described in Section 8.3.5.

ir_user
Supplies user ID for this request.
ir_pid
Supplies process ID for this request.
ir_error | Returns status of the operation (zero if no error, the error code otherwise).
ir_length | Returns number of bytes actually written.
ir_pos | Returns the new file position.

A write of zero bytes to the file, (ir_length = zero), is used to set the end of file position. The FSD should truncate or extend the file to the passed file position.

This operation may take place asynchronously, and it is recommended that the implementation of this function be async when ever possible. To do this, the function may return STATUS_PENDING to allow the caller to continue processing while the operation completes. If STATUS_PENDING is returned, the Complete_Async() service in the IFSMGR must be called when the operation completes. The address of the I/O request packet must be passed to identify the completed request.


FSD Named Pipe Interface

The Win32 named pipe APIs require special support from the FSDs. The named pipe functions are provided in addition to the FSD File I/O Interface. Only client named pipe functions are supported under Chicago at this time and these are defined here.

The client named pipe functions will be supported by the local named pipe file system and may optionally be supported by network redirectors. A local disk file system will not provide these functions. Some of these functions are used by both client and server applications.

Each client named pipe routine and its I/O request parameters are given in the following. These routines follow the same calling convention of the FSD file I/O routines defined above. All of the FSD routines receive the ID of the requesting process in the ir_pid field and return success or failure info in the ir_error field.


FS_NamedPipeRequest

FS_NamedPipeRequest(
 PIOREQ pir
 )

All of the handle-based named pipe functions are called through FS_NamedPipeRequest using a subfunction command value.

ir_flags
Supplies the named pipe subfunction command to perform.
Subfunction Command Values:

One of the following commands will be specified.

Value | Meaning
PIPE_QHandState | Refers to the FS_GetNamedPipeHandleState function.
PIPE_SetHandState | Refers to the FS_SetNamedPipeHandleState function.
PIPE_QInfo | Refers to the FS_GetNamedPipeInfo function.
PIPE_Peek | Refers to the FS_PeekNamedPipe function.
PIPE_Transact | Refers to the FS_TransactNamedPipe function.

ir_*
Specific to each function.
  • Returns status based on the command performed, described in the following.

These individual commands are discussed separately in the following topics.


FS_GetNamedPipeHandleState

FS_GetNamedPipeHandleState(
 PIOREQ pir
 )

Information about a given named pipe handle is obtained through FS_GetNamedPipeHandleState. This routine handles the Win32 function: GetNamedPipeHandleState().

ir_rh
Supplies handle to local NP FS or network resource that contains the named pipe.
ir_fh
Supplies FSD file handle of an opened named pipe.
ir_sfn
Supplies system file number.
ir_data
Supplies an optional pointer to a handle data structure where additional handle information is placed.
Handle Data Structure:
Value | Meaning
hd_curinst | Return value, see following.
hd_size | Return value, see following.
hd_wtimeout | Return value, see following.
hd_length | Supplies the length of the username buffer.
hd_name | Supplies an optional pointer to a buffer where the username of the client application is returned. This parameter is only valid on a handle to the server end of a named pipe, it is invalid on a handle to the client end of a named pipe.

ir_length
Supplies the length of the handle data structure.
ir_error | Returns status of the operation (zero if no error, the error code otherwise).
ir_options | Returns pipe mode state.

Pipe Mode State Values:

Any combination of the following mode states may be returned.

Value | Meaning
PIPE_NOWAIT | Nonblocking mode is to be used for this handle. If not specified blocking mode will be used.
PIPE_READMODE_MESSAGE | Read pipe as a message stream. If not specified the pipe will be read as a byte stream.

ir_data Returns a filled in handle data structure where additional handle information is placed.

Handle Data Structure:
Value | Meaning
hd_curinst | Returns the number of current pipe instances.
hd_size | Returns the maximum number of bytes that will be collected on the client machine before transferring to the server. The returned value is ignored on a handle to the server end of a named pipe or when the client and server applications are on the same machine.
hd_wtimeout | Returns the collection time-out value (in milliseconds). The collection time-out is the maximum time that can pass before a remote named pipe transfers buffered information over the network. This value will be NULL if the handle is for the server end of a named pipe or when client and server applications are on the same machine.
hd_length | Supplied value, contains the length of the username buffer.
hd_name | Returns the buffer filled in with the username of the client application if this is a handle to the server end of a named pipe.


FS_SetNamedPipeHandleState

FS_SetNamedPipeHandleState(
 PIOREQ pir
 )

Information about a given named pipe handle is set through FS_SetNamedPipeHandleState. This routine handles the Win32 function: SetNamedPipeHandleState().

ir_rh
Supplies handle to local NP FS or network resource that contains the named pipe.
ir_fh
Supplies FSD file handle of an opened named pipe.
ir_sfn
Supplies system file number.
ir_options
Supplies pipe mode state.
Pipe Mode State Values:

Any combination of the following options may be specified.

Value | Meaning
PIPE_NOWAIT | Nonblocking mode is to be used for this handle. If not specified blocking mode will be used.
PIPE_READMODE_MESSAGE | Read pipe as a message stream. If not specified the pipe will be read as a byte stream.

ir_length
Supplies the length of the handle data structure.
ir_data
Supplies an optional pointer to a handle data structure where additional handle information is placed.
Handle Data Structure:
Value | Meaning
hd_size | Supplies the maximum number of bytes that will be collected on the client machine before transferring to the server. This value will be set to NULL if the handle is for the server end of a named pipe or when the client and server applications are on the same machine.
hd_timeout | Supplies the collection time-out value (in milliseconds). The collection time-out is the maximum time that can pass before a remote named pipe transfers buffered information over the network. This value will be NULL if the handle is for the server end of a named pipe or when client and server applications are on the same machine.

ir_error Returns status of the operation (zero if no error, the error code otherwise).


FS_GetNamedPipeInfo

FS_GetNamedPipeInfo(
 PIOREQ pir
 )

Information about a given named pipe is obtained through FS_GetNamedPipeInfo. This routine handles the Win32 function: GetNamedPipeInfo().

ir_rh
Supplies handle to local NP FS or network resource that contains the named pipe.
ir_fh
Supplies FSD file handle of an opened named pipe.
ir_sfn
Supplies system file number.
ir_options
Supplies the information level requested.
ir_length
Supplies the length of the pipe info structure.
ir_data
Supplies an optional pointer to a pipe info structure where the named pipe information is placed.
Pipe Info Structure:
Value | Meaning
pi_type | Return value, see the following.
pi_outsize | Return value, see the following.
pi_insize | Return value, see the following.
pi_maxinst | Return value, see the following.
pi_curinst | Return value, see the following.
pi_length | Supplies the length of the username buffer.
pi_name | Supplies an optional pointer to a buffer where the pipe name is returned.

ir_error | Returns status of the operation (zero if no error, the error code otherwise).
ir_data | Supplies an optional pointer to a pipe info structure where the named pipe information is placed.

Pipe Info Structure:
Value | Meaning
pi_type | Returns the type of named pipe.
Named Pipe Type Values:

Any combination of the following flags may be returned.

Value | Meaning
PIPE_END_SERVER | The handle is the server end of a named pipe.
PIPE_TYPE_MESSAGE | The pipe is a message stream pipe. If not specified the pipe is a byte stream pipe.

pi_outsize | Returns the size in bytes of the outgoing data buffer. A return value of zero indicates the buffer is allocated as needed.
pi_insize | Returns the size in bytes of the incoming data buffer. A return value of zero indicates the buffer is allocated as needed.
pi_maxinst | Returns the maximum number of pipe instances that can be created. Besides numeric values, the following special value may be returned.

Max Instances Special Values:
Value | Meaning
PIPE_UNLIMITED_INSTANCES | This is an indicator that the maximum number is requested. The value of the equate may be higher or lower than the implementation limit, which may vary over time.

pi_curinst | Returns the current number of pipe instances that can be created. Besides numeric values, the following special value may be returned.
pi_length | Supplied value, contains the length of the username buffer.
pi_name | Returns the username buffer filled in with the pipe name.


FS_PeekNamedPipe

FS_PeekNamedPipe(
 PIOREQ pir
 )

This function is used to preview the named pipe's data without removing it. The named pipe's data is copied into a buffer for previewing. This routine handles the Win32 function: PeekNamedPipe().

ir_rh
Supplies handle to local NP FS or network resource that contains the named pipe.
ir_fh
Supplies FSD file handle of an opened named pipe.
ir_sfn
Supplies system file number.
ir_data
Supplies a pointer to the data buffer to read into.
ir_length
Supplies number of bytes of data to read.
ir_error | Returns status of the operation (zero if no error, the error code otherwise).
ir_length | Returns number of bytes actually read.
ir_size | Returns number of bytes of data that were available to read.
ir_msglen | Returns number of bytes of data left in this message. This will be zero for a byte-stream pipe.
ir_status | Returns the current state of the pipe.

Current Pipe State Values:
Value | Meaning
NP_DISCONNECTED | The pipe has been create or disconnected, but is not yet connected.
NP_LISTENING | The pipe has been connected, but has not yet been opened by the client.
NP_CONNECTED | The pipe has been opened by the client.
NP_CLOSING | Either the client has closed and the server has not disconnected, or the server has closed and the client has not closed the pipe.


FS_TransactNamedPipe

FS_TransactNamedPipe(
 PIOREQ pir
 )

Data is written to and read from a named pipe in a single request through FS_TransactNamedPipe. This routine handles the Win32 function: TransactNamedPipe().

ir_rh
Supplies handle to local NP FS or network resource that contains the named pipe.
ir_fh
Supplies FSD file handle of an opened named pipe.
ir_sfn
Supplies system file number.
ir_data2
Supplies a pointer to the output data buffer to write to the pipe.
ir_size
Supplies the size in bytes of the write (output) buffer.
ir_data
Supplies a pointer to the input buffer that receives data from the pipe.
ir_length
Supplies the size in bytes of the read (input) buffer.
ir_error | Returns status of the operation (zero if no error, the error code otherwise).
ir_length | Returns number of bytes actually read from the pipe.

This operation may take place asynchronously, and it is recommended that the implementation of this function be async when ever possible. To do this, the function may return STATUS_PENDING to allow the caller to continue processing while the operation completes. If STATUS_PENDING is returned, the Complete_Async() service in the IFSMGR must be called when the operation completes. The address of the I/O request packet must be passed to identify the completed request.


FS_NamedPipeUNCRequest

FS_NamedPipeUNCRequest(
 PIOREQ pir
 )

All of the UNC path-based named pipe functions are called through FS_NamedPipeUNCRequest using a subfunction command value.

ir_flags
Supplies the named pipe subfunction command to perform.
Subfunction Command Values:

One of the following commands will be specified.

Value | Meaning
PIPE_Call | Refers to the FS_CallNamedPipe function.
PIPE_Wait | Refers to FS_WaitNamedPipe function.

ir_*
Specific to each function.
ir_error Returns status of the operation (zero if no error, the error code otherwise).

These individual commands are discussed separately in the following topics.


FS_CallNamedPipe

FS_CallNamedPipe(
 PIOREQ pir
 )

The equivalent of CreateFile, perhaps WaitNamedPipe, TransactNamedPipe, and CloseFileData in a single request is performed through FS_CallNamedPipe. This routine handles the Win32 function: CallNamedPipe().

ir_ppath
Supplies a pointer to the canonicalized pipe name in unicode.
ir_rh
Supplies handle to local NP FS or network resource that contains the named pipe.
ir_data2
Supplies a pointer to the output data buffer to write to the pipe.
ir_size
Supplies the size in bytes of the output buffer.
ir_data
Supplies a pointer to the input buffer that receives data from the pipe.
ir_length
Supplies the size in bytes of the input buffer.
ir_options
Supplies the priority of the caller.
ir_timeout
Supplies the number of milliseconds to wait for the named pipe to be available. Besides numeric values, the following special values may be returned.
Time-out Special Values:
Value | Meaning
NMPWAIT_NO_WAIT | Do not wait for the named pipe. If the named pipe is not available an error is returned.
NMPWAIT_WAIT_FOREVER | No time-out.
NMPWAIT_USE_DEFAULT_WAIT | Use default time-out set in call to FS_CreateNamedPipe.

ir_error | Returns status of the operation (zero if no error, the error code otherwise).
ir_length | Returns number of bytes actually read from the pipe.


FS_WaitNamedPipe

FS_WaitNamedPipe(
 PIOREQ pir
 )

A named pipe is waited for to be available through FS_WaitNamedPipe. This routine handles the Win32 function: WaitNamedPipe().

ir_ppath
Supplies a pointer to the pipe name in canonicalized unicode format.
ir_rh
Supplies handle to local NP FS or network resource that contains the named pipe.
ir_options
Supplies the priority of the caller.
ir_timeout
Supplies the number of milliseconds to wait for the named pipe to be available. Besides numeric values, the following special values may be specified.
TimeOut Special Values:
Value | Meaning
NMPWAIT_WAIT_FOREVER | No time-out.
NMPWAIT_USE_DEFAULT_WAIT | Use default time-out set in call to FS_CreateNamedPipe.

  • Returns status based on the command performed, described in the following topics.


FS_NamedPipeHandleInfo

FS_NamedPipeHandleInfo(
 PIOREQ pir
 )

This call gets and sets the handle buffering information for the named pipe handle that is passed in.

ir_rh
Supplies the handle to the named pipe resource.
ir_fh
Supplies the named pipe FSD file handle.
ir_flags
Supplies the command to perform.
Command Values:
Value | Meaning
HINFO_GET | Get the current handle buffering information.
HINFO_SETALL | Set all of the handle buffering parameters.
HINFO_SETCHARTIME | Set the handle buffer time-out alone.
HINFO_SETCHARCOUNT | Set value for the maximum handle buffer count alone.

ir_options
Supplies the information requested (must be 1 for now).
ir_data
Supplies pointer to the information buffer.
ir_length
Supplies size of the information buffer.
ir_error | Returns status of the operation (zero if no error, the error code otherwise).
ir_length | Returns the size of the information copied into the information buffer for the HINFO_GET command. This is not a return on any of the other commands.

An error is returned if the information buffer is not large enough to receive the information for the HINFO_GET command, or if the size does not match the expected size of the data for the appropriate set information commands.


File System API Hook

This hook is very similar to the way TSRs work in DOS but with a few important differences. The hook interposes itself between the IFS manager and the FSD. The hooker gets control before the FSD is called to perform the function and it can do anything it wants. Hookers can do one of four things when they get called on a hooked call:

  1. Ignore the call and chain on to the previous hooker in the hook chain.
  2. Process the call and return directly to the IFS manager.
  3. Change the call or make multiple calls to the FSD directly, and then return to the IFS manager.
  4. It can call down the chain and do some processing on the way back.

Basically, the hooker has complete control over how it wants to process the call. The hooker gets exactly the same information that the FSD gets, it gets the pointer to the IOREQ structure and can interpret this according to the IFS-FSD interface description given in Section 8.5. In addition, it also gets information about the operation that is being performed, the drive or resource on which the operation is being done, the type of resource (for example, net or local), and, on path-based APIs, the codepage that is being used.

The preferred method for hookers to perform other functions while on a hooked call is to use the Ring 0 APIs. It is usually quite safe to issue a Ring 0 API call while on a file system API hook, the IFS manager is reentrant. There are, however, certain special cases in which the hook cannot make these calls. These restrictions are listed in the following.

  1. If the call being hooked is issued for a swap-file operation, that is, ir_options contains the R0_SWAPPER_CALL flag, then the call must be processed without reentering the IFS manager via the Ring 0 APIs. This can cause additional paging and can lead to a deadlock. Note that multiple calls read/write I/O calls can be made to the FSD, however, the calls must all specify the R0_SWAPPER_CALL flag so that the FSD does special handling for it.
  2. The same restrictions mentioned above also apply to memory-mapped files, that is, read/write I/O operations with the R0_MM_READ_WRITE flag specified in ir_options.

Another important restriction on file system API hookers applies to paging I/O, that is, I/O with the R0_SWAPPER_CALL or R0_MM_READ_WRITE bits set in ir_options. Any code that is executed in the file system hook during paging I/O must be locked down. If the hook causes additional paging activity on a paging I/O, system deadlocks can result. This also means that the code executed during paging I/O cannot perform memory allocations or call any services that can cause paging.

One important difference this hook has when compared to TSRs is that it can be removed at any time, even if there are other hookers after it. For purposes of chaining on, the IFS manager returns a pointer to a variable containing the address of the previous hooker. This double indirection enables the IFS manager to let a hook be removed at any point of time.

File hooks that deregister dynamically need to take care. The IFS manager does not prevent a hook from being deregistered. A hook function that provides crucial functionality that the system or other file hooks depend on cannot deregister itself dynamically. For example, if data encryption is provided by a file hook, the file hook cannot deregister dynamically. Doing so would almost certainly cause a system crash. The same caveat also applies to file hooks that bypass other file hooks beneath them in the chain and call the FSD directly. They need to make sure that there are no other crucial file API hookers beneath that need to process the call as well. The IFS manager does not provide any information about the presence or absence of such crucial file hookers.


Find Change Notification

The IFS manager provides support for the Win32 APIs: FindFirstChangeNotify(), FindNextChangeNotify() and FindCloseChangeNotify(). The support is done entirely in the IFS manager so that the individual FSDs do not each need to have code for change notifications. FSDs are not aware of the presence of change notification. The FindNextChangeNotify and FindCloseChangeNotify functions are sent down the hook before eventually being processed in the IFS manager. The FindFirstChangeNotify is not sent down the file system API hook. It is strongly recommended that file system API hookers do not attempt to hook these APIs in any fashion. Since the notification event itself cannot be suppressed, it serves no purpose to hook these functions.

While the Win32 API is supported in toto for the most part, there are differences in the semantics of some filters. These are enumerated in the following.

  1. The FILE_NOTIFY_CHANGE_SIZE and FILE_NOTIFY_CHANGE_LAST_WRITE filters are triggered only when the file is closed. In addition, the notification is done only for files that are opened in the specified path or subtree after the FindFirstChangeNotify is registered. Changes to files that were open prior to the FindFirstChangeNotify call will not trigger the above-mentioned notification events.
  2. The FILE_NOTIFY_CHANGE_SECURITY filter is not supported.


Win31 Compatible Filesystem Mode

The IFS manager supports a special Win31 compatible file system mode. There is a registry switch that can be turned on to put the IFS manager in the Win31 compatible mode. Long names are not allowed in this mode. Most of the long name APIs are converted to their short name equivalents. New APIs that do not have such equivalents are mostly supported with some exceptions that are described in the following. Individual FSDs do not need to do anything special to support this mode. The IFS manager does the appropriate mappings so that the FSDs get only short names when the Win31 file system mode is in operation.

A number of the new functions are failed. The list of functions that are failed is given in the following.

Interrupt 21h Function 5704h | Get Last Access Date and Time
Interrupt 21h Function 5705h | Set Last Access Date and Time
Interrupt 21h Function 5706h | Get Creation Date and Time
Interrupt 21h Function 5707h | Set Creation Date and Time

There are other functions which are converted to their short name equivalents. The list of such functions is given in the following.

Interrupt 21h Function 7139h | Make Directory
Interrupt 21h Function 713Ah | Remove Directory
Interrupt 21h Function 713Bh | Change Directory
Interrupt 21h Function 7141h | Delete File
Interrupt 21h Function 7143h | Get or Set File Attributes
Interrupt 21h Function 7147h | Get Current Directory
Interrupt 21h Function 7156h | Rename File
Interrupt 21h Function 7160h | Get Canonicalized Path Name
Interrupt 21h Function 716Ch | Create or Open File

There are other functions that are translated appropriately internally within the IFS manager so that they are processed as short name functions even though they are coming in via the new LFN APIs. These are functions which need to be supported but do not have an equivalent in the old short name API set. The list of these functions is given in the following.

Interrupt 21h Function 714Eh | Find First File
Interrupt 21h Function 714Fh | Find Next File
Interrupt 21h Function 71A1h | Find Close
Interrupt 21h Function 71A0h | Get Volume Information
Interrupt 21h Function 71A6h | Get File Info By Handle
Interrupt 21h Function 71A7h | File Time To DOS Time and DOS Time To File Time


Installable File System Services

The IFS services are functions within the IFS manager that are exported to FSDs. These functions are provided to help the FSD support the routines called by the IFS. Some services are C callable and use C parameter passing and C return conventions. C callable services use the C6 386 _cdecl calling sequence. Return values for C callable services are usually returned in EAX for long and EDX:EAX for quad-words. Services that are C callable have C prototypes defined for them and preserve the normal C registers i.e. EBX, ESI, EDI and the segment registers. Other services use register conventions and are callable only from assembly language.


Versioning Services

The following topics describe the versioning services.


IFSMgr_GetVersion

An FSD that wants to register with the IFS manager must call this service to verify that it is running with the correct version of the IFS manager. This function is not C callable.

Nothing.
Carry flag clear if no error, set if IFS manager is not loaded.
[EAX] = Version number of the IFS manager if no error.
Register Usage

EAX, Flags.


FSD Registration Services

The following topics describe the FSD Registration services.


IFSMgr_RegisterCFSD

IFSMgr_RegisterCFSD(
 pIFSFunc pfunc,
 unsigned long FSD_IFS_Version,
 string_t * ppDeviceNames
 )

An FSD that emulates a character device registers with the IFS manager by calling this service. If the version number passed in matches, the FSD will be registered for the list of character devices it requests for. Whenever a file system call is made to the character device name, the appropriate FSD will be called on its function entry points.

pfunc
Supplies a pointer to the FSD mount entry point. (FS_MountVolume)
FSD_IFS_Version
Supplies the version of the IFS manager that the FSD can support.
ppDeviceNames
Supplies a pointer to a set of pointers to unicode device name strings that need to be registered as character devices with the IFS manager. The list of pointers to device name strings is terminated by a NULL. There has to be at least one device name pointer. Each device name string is in unicode and has the format of a PathElement structure that has already been described in Section 8.3.1.
  • Returns the provider ID ( -1 if error ) which can be used by FSDs to identify certain special requests hooked by them.


IFSMgr_RegisterMailSlot

IFSMgr_RegisterMailslot(
 pIFSFunc pfunc,
 unsigned long FSD_IFS_Version
 )

An FSD that provides mailslots is registered with the IFS manager by calling the IFSMgr_RegisterMailSlot service. It is this service that makes the FSD module become recognized by the IFS manager. A pointer to the mailslot function entry point is passed to the IFS manager. The IFS manager will not mount the provider if the version number passed in does not match its version.

pfunc
Supplies a pointer to the FSD connect entry point. (FS_ConnectNetResource)
FSD_IFS_Version
Supplies version of the IFS manager the FSD can support.
  • Returns the provider ID ( -1 if error ) which can be used by FSDs to identify certain special requests hooked by them.


IFSMgr_RegisterMount

IFSMgr_RegisterMount(
 pIFSFunc pfunc,
 unsigned long FSD_IFS_Version,
 unsigned long FSDType
 )

An FSD that manages a local media registers with the IFS manager by calling the IFSMgr_RegisterMount service. It is this service that makes the FSD module become recognized by the IFS manager. A pointer to the FSD mount entry point is passed to the IFS manager. The IFS manager will not mount the FSD if the version number passed in does not match its version. This service should be called only by local FSDs.

pfunc
Supplies a pointer to the FSD mount entry point. (FS_MountVolume)
FSD_IFS_Version
Supplies version of the IFS manager the FSD can support.
FSDType
Supplies the type of FSD that is registering.
FSD Type Values:
Value | Meaning
NORMAL_FSD | The FSD is a standard FSD.
DEFAULT_FSD | The FSD is a default FSD. It is mounted by the IFS manager if all standard FSDs refuse to mount the drive. There can be only one default FSD in the system at any time. If a default FSD is already present when this call is made, the call will be failed.

  • Returns the provider ID ( -1 if error ) which can be used by FSDs to identify certain special requests hooked by them.


IFSMgr_RegisterNet

IFSMgr_RegisterNet(
 pIFSFunc pfunc,
 unsigned long FSD_IFS_Version,
 unsigned long NetID
 )

An FSD that manages a remote resource is registered with the IFS manager by calling the IFSMgr_RegisterNet service. It is this service that makes the FSD module become recognized by the IFS manager. A pointer to the FSD connect entry point is passed to the IFS manager.The IFS manager will not register the FSD if the version number passed in does not match its version.

pfunc
Supplies a pointer to the FSD connect entry point. (FS_ConnectNetResource)
FSD_IFS_Version
Supplies version of the IFS manager the FSD can support.
NetID
Supplies an identification for the kind of network provider. A list of supported net providers is defined in the file winnetwk.h which is part of the SDK.
  • Returns the provider ID ( -1 if error ) which can be used by FSDs to identify certain special requests hooked by them.


Heap Management Services

The following topics describe the Heap Management services.


IFSMgr_RegisterHeapUser

IFSMgr_RegisterHeapUser(
 pIFSFunc pheapfunc,
 unsigned long flag
 )

This service registers a heap reclamation routine with the IFS manager. The IFS manager provides heap allocation services to the FSDs. An FSD that uses the heap services provided by the IFS manager can register a heap reclamation routine with the IFS manager that is called to free unused heap allocations. This service is not valid until the IFS manager performs Sys_Critical_Init during initialization. If the IFS manager is unable to add this user to the heap registry, it returns without indicating any error. All this means is that the heap cleaning routine for this user will never be called and it is not a serious failure.

pheapfunc
Supplies pointer to FSD heap reclamation routine.
flag
Supplies options available only under the debug version. The flag value is ignored in the retail version.
Flag Values:
Value | Meaning
DEBUG_FENCE_ON | This enables checking heap overruns in the debug version. If an heap overrun is detected, it breaks into the debugger.

  • No return value.


IFSMgr_GetHeap

IFSMgr_GetHeap(
 unsigned long size
 )

This service allocates a block of memory from the heap and returns a pointer to the allocated memory. This service is not valid until the IFS manager performs Sys_Critical_Init during initialization.

size
Supplies the size of memory to be allocated from the heap. The maximum supported size is 32K.
  • Returns a pointer to the allocated memory. Returns NULL if the request could not be satisfied.


IFSMgr_RetHeap

IFSMgr_RetHeap(
 void * pMemPtr
 )

This service frees a block of memory previously allocated from the heap. This service is not valid until the IFS manager performs Sys_Critical_Init during initialization.

pMemPtr
Supplies pointer to memory that is to be returned to the heap pool.
  • No return value.


IFSMgr_CheckHeap

IFSMgr_CheckHeap(
 void * pMemptr,
 char * pFilename,
 unsigned int Line
 )

This service works only on debug builds of the IFS manager. On non-debug builds, it returns success without doing anything. This service checks the consistency of the entire heap and of the heap allocation whose pointer is passed in. If there is any inconsistency, the IFS manager puts out an error message and breaks into the debugger. The error message is generated in an infinite loop so you cannot continue from this point on.

pMemPtr
Supplies pointer to memory allocated from the heap whose consistency needs to be checked.
pFilename
Supplies pointer to source file that the service is being called from.
Line
Supplies line number in the source file this service is being called from.
  • Returns 1 if any inconsistency was discovered in the heap allocation or the heap. Returns zero if there were no problems with the heap.


IFSMgr_CheckHeapItem

IFSMgr_CheckHeapItem(
 void * pMemptr,
 char * pFilename,
 unsigned int Line
 )

This service works only on debug builds of the IFS manager. On non-debug builds, it returns success without doing anything. This service checks the consistency of the heap allocation whose pointer is passed in. If there is any inconsistency, the IFS manager puts out an error message and breaks into the debugger. The debug message is generated in an infinite loop so you cannot continue from this point on.

pMemPtr
Supplies pointer to memory allocated from the heap whose consistency needs to be checked.
pFilename
Supplies pointer to source file that the service is being called from.
Line
Supplies line number in the source file this service is being called from.
  • Returns 1 if any inconsistency was discovered in the heap allocation. Returns zero if there were no problems with the heap allocation.


IFSMgr_FillHeapSpare

This service is provided to fill the heap spare block. The heap spare block contains a few pages of memory that can be used for emergency allocation purposes by the heap manager in the IFS manager. Typically, it can be used for allocations during system critical errors if there is insufficient memory. By filling the heap spare block, an FSD can ensure that it can allocate memory in a critical situation. The IFS manager itself makes sure the heap spare is filled on every API into it. This routine should be called only at application execution time. It cannot be called at interrupt time or critical event time.

Nothing.
  • Nothing.
Register Usage
Flags.


Time Management Services

The following topics describe the Time Management services.


IFSMgr_Get_NetTime

This service is provided for FSDs to find the time elapsed in seconds. This is the net time format.

Nothing.
[EAX] | Number of seconds elapsed since 1/1/1970 with the time expressed in UTC.
[EDX] | Millisecond remainder in the 1 second interval.

Register Usage

EAX, ECX, EDX, Flags.


IFSMgr_Get_DOSTime

This service returns the current date and time in DOS format. The time returned is always the local time.

Nothing.
[EAX] | High word contains the date in DOS format. Low word contains the time in DOS format.
[EDX] | Millisecond count remainder in 2 seconds, always a value between zero and 1999.
Register Usage

EAX, ECX, EDX, Flags.


IFSMgr_NetToDosTime

IFSMgr_NetToDosTime(
 unsigned long NetTime
 )

This service converts the time passed in the net time format into the DOS time format. Note that the net time passed in is in UTC, but the DOS time returned is local time. The conversion is done as part of the service.

NetTime
Time in net time format, that is, number of seconds since 1/1/1970 in UTC format.
  • The time is returned in the DOS format in the dostime_t structure.


IFSMgr_DosToNetTime

IFSMgr_DosToNetTime(
 dostime_t DosTime
 )

This services converts the time passed in DOS local time format to net time format which is in UTC.

DosTime
DOS time filled in the dostime_t structure.
  • Returns the time in the net time format in UTC.


IFSMgr_DosToWin32Time

IFSMgr_DosToWin32Time(
 dostime_t DosTime
 )

This service converts the time passed in DOS format in local time to the Win32 style time in UTC.

DosTime
DOS time filled in the dostime_t structure.
  • Returns the Win32 time in UTC filled in the _FILETIME structure.


IFSMgr_Win32ToDosTime

IFSMgr_Win32ToDosTime(
 _FILETIME Win32Time
 )

This service converts the time passed in Win32 format in UTC to DOS time format in local time.

Win32Time
Win32 time filled in the _FILETIME structure.
  • Returns the time in DOS format filled in the dostime_t structure.


IFSMgr_NetToWin32Time

IFSMgr_NetToWin32Time(
 unsigned long NetTime
 )

This service converts the time in net time format to the Win32 time format. Both these formats use UTC time.

NetTime
Time in net time format.
  • Returns time in Win32 time format.


IFSMgr_Win32ToNetTime

IFSMgr_Win32ToNetTime(
 _FILETIME Win32Time
 )

This service converts the time in Win32 time format to the net time format. Both these formats use UTC time.

Win32Time
Time in Win32 time format in the _FILETIME structure.
  • Returns the time in net time format.


IFSMgr_GetTimeZoneBias

IFSMgr_GetTimeZoneBias( )

This service returns the time zone bias. The time zone bias is the value that needs to be added to the local time to get UTC time. The time zone bias is returned in minutes.

Nothing.
  • Returns the time zone bias in minutes.


Network Management Services

The following topics describe the Network Management services.


IFSMgr_SetupConnection

IFSMgr_SetupConnection(
 pioreq pir,
 unsigned int Options,
 unsigned int ResType
 )

This service can be called by an FSD to obtain a connection to a resource dynamically. This cannot be used to connect to a network drive directly since a driveletter cannot be specified. It is provided for special network FSD requirements. The IFS manager allocates an IFS internal request structure, which contains the Ioreq as its first element. When the IFS manager passes the address of the Ioreq to an FSD, it is also passing the address of the IFS request structure. On certain functions, such as Server Enumeration functions, the network FSD calls the IFSMgr_SetupConnection service to perform a connection with the Ioreq address it was originally passed. The IFS manager establishes the connection by calling the FSD on the FS_ConnectResource API and fills in the fields in the IFS request structure that the Ioreq is a part of. The network FSD never needs to look at any of the fields in the IFS request structure. It can now use this initialized Ioreq to perform other operations. When it is done, it can free the connection by calling the IFSMgr_DerefConnection service described in the following.

ir_ppath
Supplies the parsed canonicalized unicode path name the connection is to be performed to.
ir_password
Supplies password string (if any). This string is not in unicode; it is in the same context it was originally passed in by the user.
Connection Option Values:

One of the following options will be specified.

Value | Meaning
RESOPT_UNCREQUEST | UNC style path based anonymous connection request.
RESOPT_DEVATTACH | Explicit device redirection.
RESOPT_UNCCONNECT | Explicit UNC style connection.
RESOPT_DISCONNECTED | Connection is to be setup disconnected, without touching the net.
RESOPT_NO_CREATE | Do not create a resource for this connection, just verify the connection exists.
RESOPT_STATIC | This connection is established at startup and disconnected only at shutdown, no user APIs can disconnect it.
ResType | Supplies resource type for connection.

Connection Resource Type Values:

One of the following resource types will be specified.

Value | Meaning
RESTYPE_WILD | Wild card resource type.
RESTYPE_DISK | Disk resource.
RESTYPE_SPOOL | Spooled printer resource.
RESTYPE_CHARDEV | Character device resource.
RESTYPE_IPC | Interprocess communication resource.

  • This function has no return value other than in ir_error. Appropriate fields in the Ioreq are filled in.
IOREQ Structure: |
Value | Meaning
ir_error | Returns zero if successful, the error code if failure.
ir_rh | Returns the resource handle for the connection if success.
ir_ppath | Returns a pointer to the tail of the original path name after the server and share name.
ir_options | Returns special server security information.


IFSMgr_DerefConnection

IFSMgr_DerefConnection(
 pioreq pir
 )

This service is called to disconnect a resource previously connected using the IFSMgr_SetupConnection service. For this service to work, the same IO request structure that was passed to the IFSMgr_SetupConnection service must be passed in. The IFS relies on the validity of certain fields in the associated IFS request structure that were initialized when the connection was originally established. This service can be only called to disconnect a connection that was previously established using the IFSMgr_SetupConnection service.

pir
Supplies pointer to IO request structure. This should be the same IOREQ structure that was used to do the connection via the IFSMgr_SetupConnection service.
  • This function has no return value.


IFSMgr_ServerDOSCall

This service is provided so that FSDs that need to do a server DOS call to obtain certain services need not do an INT 21h call anymore. They can directly call this service now. The parameters for this service are passed in registers.

[EBX]
Handle of current VM.
[ECX]
Function number.
[ESI]
Pointer to extended 32-bit DPL. This structure looks as follows:
DPL32 Structure:
DPL32_EAX | Supplies EAX register.
DPL32_EBX | Supplies EBX register.
DPL32_ECX | Supplies ECX register.
DPL32_EDX | Supplies EDX register.
DPL32_ESI | Supplies ESI register.
DPL32_EDI | Supplies EDI register.
DPL32_EBP | Supplies EBP register.
DPL32_UID | Supplies the user id.
DPL32_PID | Supplies the process id.
DPL32_DTA | Supplies a flat pointer to the DTA.
DPL32_FLAGS | Supplies special flags.

DPL32 Flag Values:
Value | Meaning
DPL32_USE_ANSI | Requests the IFS manager to assume that the path strings passed in are in Windows ANSI.
DPL32_USE_OEM | Requests the IFS manager to assume that the path strings passed in are in the current OEM codepage.
DPL32_USE_UNICODE | Requests IFS manager to assume everything is passed in unicode. By default, the IFS manager selects the codepage based on the current thread context.
DPL32_8_3_MATCHING | If this flag is set, the IFS manager will force 8.3 matching semantics on the path name passed in even though it came in via an LFN API. The path can contain long names, but the file name itself cannot be a long name. This API is provided because the server may have to issue an LFN API call on a call that originated as a normal API at the client end if the sharename is long. However, a normal LFN API has LFN matching semantics and this poses compatibility issues for old-style apps.

DPL32_PAD
Filler bytes to align structure.
[EBP]
Pointer to client register frame.
Carry clear | Request was processed. Client registers set appropriately to indicate status of the call.
Carry set | Request was not processed by the IFS manager.


IFSMgr_MakeMailslot

IFSMgr_MakeMailslot(
 pMSFunc pmsfunc,
 path_t pmsname,
 unsigned int * pmshand
 )

This service creates a new mailslot for a VxD.

pmsfunc
Supplies pointer to function to be called for mailslot reads.
pmsname
Supplies pointer to ASCIIZ mailslot name without the "\MAILSLOT\"
pmshand
Supplies pointer to variable to contain mailslot handle returned by the IFS manager.
  • Returns the error code if error, zero if successful.
pmshand Returns the mailslot handle created by the IFS manager.


IFSMgr_DeleteMailslot

IFSMGR_DeleteMailSlot(
 unsigned int pHandle
 )
pHandle
Supplies the mailslot handle.
  • Returns the error code if error, zero if successful.


IFSMgr_WriteMailslot

IFSMgr_WriteMailslot(
 path_t pmsname,
 char far * pdata,
 unsigned short len,
 unsigned char lana,
 string_t rname,
 void * xtra
 )

This service writes data to a mailslot and is called by the mailslot provider (FSD).

pmsname
Supplies pointer to the unicode canonicalized mailslot name without the "\MAILSLOT\"
pdata
Supplies pointer to buffer containing the data to be written.
len
Supplies length of data.
lana
Supplies Lan Address Number.
rname
Supplies name of the resource.
xtra
Supplies special information used to browse on IPX. This is used internally within the system.
  • Returns the error code if error, zero if successful.


IFSMgr_SetErrString

IFSMgr_SetErrString(
 char * errstr,
 unsigned int errorcode,
 unsigned int table
 )

This service takes error strings from other VxDs and stores them for use when handling GetErrorText ( INT 2fh function 5 ). It also handles strings for use by IFSMgr_Popup. There are two tables: the error code table and the device name table. The error code table contains the strings for the GetErrorText function and the device name table contains the strings for use by the IFSMgr_Popup service. Note that the memory containing the error strings must be left in memory. The IFS manager does not copy the error strings, it just stores the pointers to them.

errstr
Supplies pointer to ASCIIZ error message string.
errorcode
Supplies error number of the error message.
table
Supplies the table indicator: Zero means error code table, 1 means device name table.
  • Returns zero for success, error code if failure.

ERROR_ACCESS_DENIED is returned if the error code is already in the table.


IFSMgr_GetErrString

IFSMgr_GetErrString(
 unsigned int errorcode,
 unsigned int table
 )

This service returns a pointer to the error string for the passed in error code, if it is present in the table.

errorcode
Supplies error number of the error message.
table
Supplies the table indicator: Zero means error code table, 1 means device name table.
  • Returns pointer to error string if present in table, returns NULL if the message is not found.


IFSMgr_SetReqHook

IFSMgr_SetReqHook(
 unsigned int Request,
 void * Preamble
 )

This service has been provided for FSDs to hook interrupt functions that the IFS manager normally does not hook or to override the default handlers that the IFS manager has for hooked interrupt functions. Use this function upon initialization only. Currently, this interface is supported only on INT 21h calls. An FSD can call and pass in the address of a preamble routine for a given INT 21h function. Whenever that INT 21h call is issued, the FSD's preamble gets called. The FSD can either accept or reject the INT 21h on its preamble. If it accepts it, the FSD is then called for that INT 21h via the IFSMgr_NetFunction service, which is described later in this document. Note that for INT 21h functions that are already hooked by the IFS manager which the FSD is trying to override, the FSD will not be called via the IFSMgr_NetFunction service if the request is accepted.

Request
Supplies interrupt function to be hooked. High word contains the interrupt level to be hooked; low word contains the function number. Currently, the interrupt level can only be 21h and the function number is the value in register AH.
Preamble
Supplies the address of the preamble function that is to be called when the hooked INT 21h function occurs.
  • Returns the address of the previous preamble. The FSD must call this preamble if it rejects a request on its preamble. Returns zero if an error is encountered on this function.

The interface to the preamble function called by the IFS manager on a hooked INT 21h request is described in the following. Preamble functions must chain if they reject a request.

[EBX]
Current VM handle.
[ECX]
Function number (user AH).
[EBP]
Pointer to client register structure.
[ESI]
Provider ID ( initialized to ANYPROID )
Request hooked:

Carry flag set.

[ESI] Provider ID of FSD that is hooking the call. This is optional, the FSD can leave this field unchanged. If a specific provider ID is returned, the call will be seen only by that FSD. Otherwise, all FSDs will be able to see the hooked call.
Request not hooked:

The FSD must jump to the address of the previous preamble returned on the call to IFSMgr_SetReqHook with the entry conditions preserved.

Register Usage

If request is hooked, EBX and EBP must be preserved and the other registers can be destroyed. If request is not hooked, all registers must be preserved.


IFSMgr_SetPathHook

IFSMgr_SetPathHook(
 void * PathCheckFunc
 )

This service has been provided for FSDs to check for special path prefixes and process them separately. The FSD can register a routine with the IFS manager that is called every time a path is parsed. If this is a prefix the FSD wants to process, it can claim it and the IFS manager will then call the FSD directly on the path-based operation.

PathCheckFunc
Supplies address of path checking preamble function to be called by the IFS manager.
  • Returns the address of the previous path checking function. The IFS manager always has a default function that fails the path check hook.

The interface to the path checking preamble function is described in the following. Preamble functions must chain on if they reject a request. If the preamble function hooks the path, it can update the

[ESI]
Pointer to unicode path name. Note: this path name has not been canonicalized.
[EDI]
Pointer to destination buffer to contain the parsed path.
  • Request hooked:

    Carry flag clear.

[EAX] | Length of the last path element consumed by the FSD.
[EBX] | Pointer in the input string to the beginning of the last path element consumed by the FSD.
[EDX] | Provider ID of the FSD that claimed the path.
[ESI] | Pointer to source unicode path name - possibly updated.
[EDI] | Pointer to destination buffer - possibly updated. If the destination buffer is updated, it must be maintained in the ParsedPath format described earlier.

Request not hooked:

FSD must jump to the address of the previous path checking preamble, returned on the call to IFSMgr_SetPathHook, with the entry conditions preserved.

Register Usage

If request hooked, EDX, ESI, EDI must contain valid values and all other registers can be used. If request is not hooked, all registers must be preserved.


IFSMgr_NetFunction

IFSMgr_NetFunction(
 pioreq pir,
 pUserRegs pRegs,
 int proId,
 int flags
 )

This service is provided to export certain functions most of which are specific to the network FSDs. These functions can come from a variety of sources: INT 21h and INT 2fh functions that the IFS hooks but does not support, INT 21h functions that the IFS does not support that are hooked via IFSMgr_SetReqHook and internal IFS manager broadcast functions to notify FSDs of certain happenings. It is not possible to document the different functions that different FSDs might hook. What is documented here are the internal broadcasts that the IFS manager issues and the general interface of the IFSMgr_NetFunction API. FSDs that need to see these calls need to hook the IFSMgr_NetFunction service using the VMM Hook_Device_Service service. The IFS manager has a stub installed for the IFSMgr_NetFunction service that returns error if no one else has hooked the service.

pir
Supplies the IOREQ structure. The actual fields used in IOREQ vary based on the function type and are described in the following.
pRegs
Supplies pointer to the client register structure.
User AX
Supplies the function type. Depending on the type of function the IOREQ structure is appropriately initialized. If this is an INT 21h that is not processed by the IFS manager but has been hooked by the FSD via the IFSMgr_SetReqHook function, this field contains the original AX value that the user issued the INT 21h with. There are a via INT 2fh requests that are also routed through this service with AX containing the original INT 2fh function numbers in AX. FSDs that need to process them should look for them.
Function Type:
Value | Meaning
NF_PROCEXIT | This function is broadcast whenever a process exits for FSDs to do any cleanup, if necessary. For normal resources, the IFS manager takes care of cleanup and calls the FSDs at process exit time. Only FSDs that need to maintain special per process resources that the IFS does not know about need to monitor this call.
NF_DRIVEUSE | This function is broadcast whenever a new drive appears in the system. This need not necessarily be a network drive.
NF_DRIVEUNUSE | This function is broadcast whenever a drive goes away. This need not necessarily be a net drive.
NF_GETPRINTJOBID | This function is broadcast when the IFS manager needs a print job ID from the FSD. This is used only for network FSDs.
NF_PRINTERUSE | This function is broadcast whenever a network printer is attached.
NF_PRINTERUNUSE | This function is broadcast whenever a network printer is disconnected.
proId | Supplies the provider ID the call is meant for–could be all providers (ANYPROID) also depending on the function type. This is described in the following.

flags
Supplies special flags. This flag is currently a Boolean flag–it is set if this is a Win32 API call and clear if it is not a Win32 API call.
Function NF_PROCEXIT:
Value | Meaning
ir_pid | Supplies process ID of exiting process.
proId | ANYPROID.

Function NF_DRIVEUSE:
Value | Meaning
ir_rh | Supplies FSD resource handle to the drive that has just appeared.
ir_flags | Supplies driveletter (1-based) of drive that has just appeared.
ir_aux1.aux_ul | Supplies provider ID of the provider handling the new drive.
proId | ANYPROID.

Function NF_DRIVEUNUSE:
Value | Meaning
ir_rh | Supplies FSD resource handle to the drive that has gone away.
ir_flags | Supplies driveletter (1-based) of drive that has gone away.
ir_aux1.aux_ul | Supplies provider ID for the deleted drive.
proId | ANYPROID.

Function NF_GETPRINTJOBID:
Value | Meaning
ir_rh | Supplies FSD resource handle to the printer.
ir_data | Supplies pointer to the user buffer where the print job ID is to be filled in.
proId | Provider ID of provider handling the printer resource.

Function NF_PRINTERUSE:
Value | Meaning
ir_rh | Supplies FSD resource handle to the new printer.
ir_flags | Supplies printer index of new printer. The printer index is a value from zero through 8 for LPT1 - LPT9. PRN has the same index as LPT1.
proId | Supplies provider ID of provider who is handling the new printer.

Function NF_PRINTERUNUSE:
Value | Meaning
ir_rh | Supplies FSD resource handle to the printer that just got disconnected.
ir_flags | Supplies printer index of printer being disconnected. Look above for details about this field.
proId | Supplies provider ID of provider who was handling the disconnected printer.

Hooked Int 21h Function:
Value | Meaning
ir_ppath | Supplies pointer to parsed path buffer that can be used by the FSD. The IFS manager does not initialize this field with anything.
proId | Provider returned by the hooking FSD on its preamble return. The details are described in Section 8.11.5.9.

  • The internal functions: NF_PROCEXIT, NF_DRIVEUSE, NF_DRIVEUNUSE, NF_PRINTERUSE, NF_PRINTERUNUSE have no return values. For all other functions, the return value is the same as what is returned in ir_error.
ir_error Returns zero if success, error code if failure.


IFSMgr_UseAdd

IFSMgr_UseAdd(
 pioreq pir,
 int proId,
 netuse_info *pinfo
 )

This service is called by an FSD to perform a network use operation to connect to a network resource. This service is normally not necessary to use. Most connections are done by the IFS manager directly. This is needed only for certain private APIs that the IFS manager does not understand.

pir
Supplies pointer to IOREQ structure. If a NULL is passed in for the IOREQ pointer, the IFS manager allocates an IOREQ structure for the duration of this call. In this case, the caller also needs to pass in the pinfo parameter so that the IOREQ structure can be appropriately initialized. The IOREQ structure is freed before return from the service.
IOREQ Structure:
Value | Meaning
ir_data | Supplies flat pointer to use_info_2 structure described in the following.

Use_Info_2 Structure:
Value Meaning

The fields that need to be initialized are described in the following. All other fields should be set to zero.

ui2_local | Supplies the ASCIIZ string the resource is to be connected to, for exanple, a device name or drive letter.
ui2_remote | Supplies the ASCIIZ resource name that is to be connected.
ui2_password | Supplies the ASCIIZ string for the password of the resource, if any. This pointer should be NULL if there is no password for this resource.
ui2_asg_type | Supplies resource type for connection.

Connection Resource Type Values:

One of the following resource types will be specified.

Value | Meaning
USE_WILDCARD | Wild card resource type.
USE_DISKDEV | Disk resource.
USE_SPOOLDEV | Spooled printer resource.
USE_CHARDEV | Character device resource.
USE_IPC | Interprocess communication resource.

ui2_res_type
Supplies resource name type.
Resource Name Type Values:
Value | Meaning
USE_RES_UNC | Resource name is UNC. Currently, this is the only supported flag and ui2_res_type must always be set to this.

ir_flags
Supplies the connection status. This field has only two values: it is one if the connection should be set up disconnected, zero if it should be set up connected.
ir_conflags
Supplies the source of the connection. This must be set to a nonzero value because the connection is not via a normal API level call.
proId
Supplies the provider ID of the provider requesting the connection.
pinfo
Supplies an optional pointer to a netuse_info structure. This should only be passed in if the provider has no IOREQ available, that is, NULL is passed in the pir field. The fields that need to be initialized are described in the following. All other fields should be set to zero.
Netuse_Info Structure:
Value | Meaning
nu_data | Supplies a pointer to a use_info_2 struct that is initialized as described above.
nu_flags | Supplies flags for the request.
FSD_NETAPI_USEOEM | This flag is set if you are passing in OEM strings, otherwise strings are assumed to be ANSI.
FSD_NETAPI_STATIC | This flag is set for a connection that will only be removed at shutdown time.
FSD_NETAPI_USELFN | This flag specifies that the remote name passed in should be treated as a long name. Otherwise, it is treated as a short name.
nu_rsvd | Must be set to 0xff always.

  • Returns zero if no error, error code otherwise.
IOREQ Structure: |
ir_error | Returns zero if no error, error code otherwise.


IFSMgr_InitUseAdd

IFSMgr_InitUseAdd(
 struct use_info_2 * pui2,
 int proId,
 int fStatic,
 int lana
 )

This service is called by an FSD to perform a network use operation to connect to a network resource at initialization time. The connection is always set up in the disconnected state.

pui2
Supplies pointer to use_info_2 structure filled in as follows:
Use_Info_2 Structure:

The fields that need to be initialized are described in the following. All other fields should be set to zero.

Value | Meaning
ui2_local | Supplies the ASCIIZ string the resource is to be connected to, for example, a device name or drive letter or UNC name.
ui2_remote | Supplies the ASCIIZ resource name that is to be connected.
ui2_password | Supplies the ASCIIZ string for the password of the resource, if any. This pointer should be NULL if there is no password for this resource.
ui2_asg_type | Supplies resource type for connection.

Connection Resource Type Values:

One of the following resource types will be specified.

Value | Meaning
USE_WILDCARD | Wild card resource type.
USE_DISKDEV | Disk resource.
USE_SPOOLDEV | Spooled printer resource.
USE_CHARDEV | Character device resource.
USE_IPC | Interprocess communication resource.

ui2_res_type
Supplies resource name type.
Resource Name Type Values:
Value | Meaning
USE_RES_UNC | Resource name is UNC. Currently, this is the only supported flag and ui2_res_type must always be set to this.

proId
Supplies the provider ID of the provider requesting the connection.
fStatic
Supplies the state for the connection. This has only two states: nonzero for a static connection and zero for a normal connection. The user cannot delete a static connection.
lana
Supplies the LAN address number.
  • Returns zero if success, error code otherwise.


IFSMgr_UseDel

IFSMgr_UseDel(
 pioreq pir,
 int proId,
 netuse_info *pinfo
 )

This service is called by an FSD to perform a network delete use operation to delete a connection to a network resource.

pir
Supplies pointer to IOREQ structure. If a NULL is passed in for the IOREQ pointer, the IFS manager allocates an IOREQ structure for the duration of this call. In this case, the caller also needs to pass in the pinfo parameter so that the IOREQ structure can be appropriately initialized. The IOREQ structure is freed before return from the service.
ir_data
Supplies the ASCIIZ string the resource to be disconnected is currently connected to, for example, a device name or drive letter or UNC name.
ir_flags
Supplies the force level to use for the disconnection. There are four possible force levels: from zero through 3. The force level has different semantics based on the type of connection. These are described in the following. Note that static connections cannot be blasted by any of these force levels. They are disconnected only when the system shuts down.
UNC Disconnection Force Values:
Value | Meaning
FORCE LEVEL 0 | Fails if there are any open files. If there are multiple UNC connections to the same resource, this disconnects only one of them.
FORCE LEVEL 1 | Fails if there are any open files. It blasts all UNC connections to the resource if there are no open files.
FORCE LEVEL 2, 3 | Forces open files closed and then destroys all UNC connections to the resource. Any references to these open files that have been forced closed will be failed by the IFS manager.

Drive-based Disconnection Force Values:
Value | Meaning
FORCE LEVEL 0, 1 | Fails if there are any open files on the resource or if it is the current drive.
FORCE LEVEL 2 | Force closes open files and then disconnects the drive. The disconnection will be failed on Level 2 if the drive to be disconnected is the current drive.
FORCE LEVEL 3 | Force closes open files and disconnects the drive even if it is the current drive.

Device-based Disconnection Force Values:
Value | Meaning
FORCE LEVEL 0, 1 | Fails if there are any open files. If there are no open files, the device will be disconnected.
FORCE LEVEL 2, 3 | Force closes any open files and then disconnects the device.

proId
Supplies the provider of the provider requesting the disconnect.
pinfo
Supplies an optional pointer to a netuse_info structure, this should only be passed in if the provider has no IOREQ available, that is, NULL is passed in on the pir parameter above. The fields that need to be initialized are described in the following. All other fields should be set to zero.
Netuse_Info Structure:
Value | Meaning
nu_data | Supplies the ASCIIZ string the resource to be disconnected is currently connected to, for example, a device name or drive letter or UNC name.
nu_level | Disconnect force level.
nu_flags | Supplies flags for the request.
FSD_NETAPI_USEOEM | Is set if you are passing in OEM strings, otherwise strings are assumed to be ANSI.
FSD_NETAPI_USELFN | This flag specifies that the remote name passed in should be treated as a long name. Otherwise, it is treated as a short name.

nu_rsvd
Must be set to 0xff always.
ir_error Returns zero if success, error code if failure. Returns zero if no error, error code otherwise.


IFSMgr_DelAllUses

IFSMgr_DelAllUses(
 int proId,
 int force
 )

This service is called by an FSD to remove all redirections to drives managed by that FSD. This service is usually called at shutdown time to disconnect all connections by an FSD.

proId
Supplies the provider ID of the FSD whose connections need to be disconnected.
force
Supplies the force level to be used for all disconnections. The force level semantics are basically the same as described in Section 8.11.5.15 with the addition of a new force level.
Disconnection Force Values:
Value | Meaning
FORCE LEVEL 0, 1, 2, 3 | The semantics are the same as those described in Section 8.11.5.15.
FORCE LEVEL 4 | Disconnect static connections also. This can be done only at shutdown time.

  • Returns zero if successful, error code if failure.


IFSMgr_DoDelAllUses

IFSMgr_DoDelAllUses(
 pioreq pir
 )

This service performs the same function as IFSMgr_DelAllUses. The only difference is that this service needs the IOREQ structure and so can be called only on a call to the FSD by the IFS manager.

ir_flags
Supplies force level to be used for deleting the connections. The force level semantics are basically the same as described in Section 8.11.5.15 with the addition of a new force level.
Disconnection Force Values:
Value | Meaning
FORCE LEVEL 0, 1, 2, 3 | The semantics are the same as those described in Section 8.11.5.15.
FORCE LEVEL 4 | Disconnect static connections also. This can be done only at shutdown time.

ir_proid
Supplies the provider ID of the FSD whose connections need to be disconnected. If this field contains ANYPROID, all network connections belonging to all network FSDs will be disconnected.
ir_error Returns zero if success, error code if failure. There is no explicit return value to this service.


IFSMgr_FSDMapFHToIOREQ

IFSMgr_FSDMapFHToIOREQ(
 pioreq pir,
 unsigned short DOSHandle
 )

This service has been provided for FSDs to map a DOS handle to the corresponding FSD and IFS internal handle structures. Typically, this is used by FSDs that have applications that manipulate a file using DOS functions and then use the same handle on private services provided only by the FSD. The FSD can then use this service to convert the DOS handle to its corresponding internal file handle structures. This service works only if the provider ID of the FSD that is servicing the DOS file handle matches the provider ID that the FSD passes in as a parameter on this service.

Value
Meaning
pir
Supplies pointer to the IOREQ structure.
ir_proid
Supplies the provider ID of the FSD that is invoking this service.
DOSHandle
Supplies the DOS file handle for the file.
  • Returns the value in ir_error.
IOREQ Structure: |
Value | Meaning
ir_error | Returns zero if successful, retures an error code if it fails.
ir_rh | Returns the FSD resource handle for the resource the file is on.
ir_fh | Returns the FSD file handle for this file.
ir_pos | Returns the current file position.


IFSMgr_CheckDelResource

IFSMgr_CheckDelResource(
 void * pIFSResourceHandle
 int force,
 int fDelFlag
 )

This service is called by an FSD to delete all connections to a particular resource. There is an option on the service which can be used to check if the disconnection can happen at the force level that is passed in without actually deleting the connection.

pIFSResourceHandle
Supplies the IFS system resource handle. This should be the same system resource handle that is passed in to the FSD on the FS_ConnectResource API in ir_fh.
force
Supplies the force level for the disconnection. Please refer to Section 8.11.14 for details on the force levels.
fDelFlag
This is a Boolean flag that is TRUE (nonzero) if the resource is to be deleted and FALSE (zero) if the IFS manager should check for deletion without error without actually deleting the resource.
  • Returns zero if deletion was successful, error code if failure.


IFSMgr_SetupFailedConnection

IFSMgr_SetupFailedConnection(
 pioreq pir,
 unsigned long * pProId
 )

This service is called for VxDs that try to emulate network services when the network provider is not available. Typically, this kind of service would be used by VxDs that provide remote networking capabilities. It provides the VxD an opportunity to fake a connection after all registered net providers have been unable to connect to the resource.

pir
Supplies pointer to the IOREQ structure. The fields in the IOREQ are setup exactly the same as for the FS_ConnectNetResource FSD API. Please refer to Section 8.5.3 for details.
pProId
Supplies the pointer to a variable in which the VxD that provides the connection fills in its provider id.
  • This is the same as the value in ir_error.
IOREQ Structure: This structure should be filled in with the same return values as the FS_ConnectNetResource API. Please refer to Section 8.5.3 for details. |
pProId | Returns the provider ID of the VxD that provides the connection. If the VxD is unable to provide the connection, it should not update this field.


IFSMgr_SetLoopBack

IFSMgr_SetLoopBack(
 char * pszUNCPath,
 char * pszLocalPath
 )

This service is intended for a server to add a loopback path to the IFS manager's loopback path list. The loopback path would create a network connection for a local drive.

pszUNCPath
Supplies a pointer to the UNC name in form \\<server>\<share>. This string should be in ANSI.
pszLocalPath
Supplies a pointer the local path the loopback is to. The local path should be in the <drive>:<path> format.
  • Returns zero if success, error code if failure.


IFSMgr_ClearLoopBack

IFSMgr_ClearLoopBack(
 char * pszUNCPath
 )

This service is provided for a server to remove previously added loopback path from the IFS manager's loopback path list.

pszUNCPath
Supplies a pointer to the UNC name of the loopback path in form \\<server>\<share>. This string should be in ANSI.
  • Returns zero if success, error code if failure.


Event Management Services

The following topics describe the Event Management services.


IFSMgr_Block

IFSMgr_Block(
 unsigned long key
 )

This service has been provided for FSDs to block a thread, for instance when asynchronous requests are being processed. An FSD can call this service with the key to block waiting for an event to complete. This service does not return until the corresponding wake call has been issued on the blocked key via the IFSMgr_Wakeup service. Event processing is enabled while this block is in progress.

key
Supplies unique identification for the caller of the service. Usually, the address of the appropriate structure itself is passed in as the key so that a wakeup request can be matched with the block request.
  • This service has no return value.


IFSMgr_BlockNoEvents

IFSMgr_BlockNoEvents(
 unsigned long key
 )

This service has been provided for FSDs to block a thread. This service does not return until the corresponding wake call has been issued on the blocked key via the IFSMgr_Wakeup service. The important difference between this service and the IFSMgr_Block service is that this service blocks with events disabled. FSDs that use this service must be very careful about when they use this service to prevent the possibility of deadlocks occurring in the system.

key
Supplies unique identification for the caller of the service. Usually, the address of the appropriate structure itself is passed in as the key so that a wakeup request can be matched with the block request.
  • This service has no return value.


IFSMgr_WakeUp

IFSMgr_WakeUp(
 unsigned long key
 )

This service wakes up a VM that was previously blocked using the IFSMgr_Block service. Typically, this would be called on the completion of an asynchronous request.

key
Supplies unique identification for the caller of the service. The key passed in must be the same as the key passed in to the IFSMgr_Block or IFSMgr_BlockNoEvents service for the function to work correctly.
  • This service has no return value.


IFSMgr_Yield

IFSMgr_Yield(
 )

This service resumes the execution of a VM so that interrupts and events can be processed. It issues a Resume_Exec VMM call to immediately execute the current virtual machine.

None.


IFSMgr_SchedEvent

IFSMgr_SchedEvent(
 pevent pev,
 unsigned long time
 )

This service schedules a time-out for the time passed in and calls the event function passed in by the FSD when the time-out event occurs. Note that the event function may not be called immediately when the time-out occurs. If there are hardware interrupts or high priority events in progress, the event function will be called at the earliest possible time it is safe to do so. The event is always scheduled i.e. the callback will not be done immediately and it runs only when interrupts have been enabled in the VM. If the time parameter is set to zero, this function behaves similarly to IFSMGR_QueueEvent.

pev
Supplies pointer to an event structure.
Event Structure:
Value | Meaning
ev_handle | Must be zero. This field is for use by the IFS manager only.
ev_flags | Supplies event type.

Event Type:
Value | Meaning
EVF_TASKTIME | Event must be called at task time only. The IFS manager allocates an IO request packet for these events. No IO request packets are allocated for events that are not to be called at task time.
EVF_VMEVENT | This is a VM event; it has to run in a specific VM that is passed in.
EVF_NOTCRIT | This causes a priority event to be scheduled to run on a thread that does not own the critical section. This flag should be used for events that can cause context switches and do not need a critical section to run in. This flag cannot be used in combination with EVF_VMEVENT but can be used in combination with EVF_TASKTIME.
EVF_NOTNESTEXEC | This causes a restricted event to be scheduled that runs only when there is no nested execution in progress. It can be scheduled as a global or a VM event, that is, EVF_VMEVENT can be passed in combination with this flag. In addition, EVF_TASKTIME can also be specified to indicate whether an IOREQ is needed or not. An event that can cause a nested execution to happen should use this flag. Otherwise, it can lead to deadlock situations.

ev_func
Supplies pointer to event function.
ev_VMHand
Supplies VM handle, needed only if the EVF_VMEVENT flag is set.
time
Supplies the time-out, specified in milliseconds. The event will be generated only after the time-out has expired.
  • This service has no return value.


EVFunc

EventFunction(
 pevent pev,
 pioreq pir
 )

The event function is called by the IFS manager when it gets the callback from the VMM. The interface to the event function is described in the following. The IFS manager allocates an IOREQ structure if this is a task time event. An IOREQ is not allocated for a VM event.

pev
Supplies pointer to the event structure. This event structure is the same as what was passed in on the IFSMgr_SchedEvent service when the event was scheduled. The IFS manager does not pass in any values in this structure.
pir
Supplies pointer to the IOREQ structure. The event function can use this IOREQ structure for calling the IFS manager. A NULL pointer is passed in if this is not a task-time event. Event functions that handle non-task-time events should not use the IOREQ at all.
IOREQ Structure:
ir_user Supplies user id.

  • No return value is expected from the event function.


IFSMgr_QueueEvent

IFSMgr_QueueEvent(
 pevent pev,
 )

This service queues an event that is to be called at the earliest time it is safe to do so, such as no pending hardware interrupts. Unlike the IFSMgr_SchedEvent time-out mentioned above, there is no time-out before the event function is called.

pev
Supplies pointer to an event structure.
Event Structure:
Value | Meaning
ev_handle | Must be zero. This field is only for IFS manager use.
ev_flags | Supplies event type.

Event Type:
Value | Meaning
EVF_TASKTIME | Event must be called at task time only. The IFS manager allocates an IO request packet for these events. No IO request packets are allocated for events that are not to be called at task time.
EVF_VMEVENT | This is a VM event; it has to run in a specific VM that is passed in.
EVF_NOTCRIT | This causes a priority event to be scheduled to run on a thread that does not own the critical section. This flag should be used for events that can cause context switches and do not need a critical section to run in. This flag cannot be used in combination with EVF_VMEVENT but can be used in combination with EVF_TASKTIME.
EVF_NOTNESTEXEC | This causes a restricted event to be scheduled that runs only when there is no nested execution in progress. It can be scheduled as a global or a VM event; EVF_VMEVENT can be passed in combination with this flag. In addition, EVF_TASKTIME can also be specified to indicate whether an IOREQ is needed or not. An event that can cause a nested execution to happen should use this flag. Otherwise, it can lead to deadlock situations.

ev_func
Supplies pointer to event function.
ev_VMHand
Supplies VM handle, needed only if flag EVF_VMEVENT is set.
  • This service has no return value.

The event function is called back in exactly the same fashion as described in Section 8.11.6.5 above.


IFSMgr_KillEvent

IFSMgr_KillEvent(
 pevent pev,
 )

This service kills a pending event that could have been scheduled using the IFSMgr_SchedEvent or queued using the IFSMgr_QueueEvent services. If the event was scheduled and the time-out has not yet occurred, the time-out is also cancelled.

pev
Supplies pointer to an event structure. This must be the same event structure that was previously used to register the event using the IFSMgr_SchedEvent or IFSMgr_QueueEvent services.
  • This service has no return value.


IFSMgr_FreeIoreq

IFSMgr_FreeIoreq(
 pioreq pir
 )

This service is provided to free an IO request structure that is allocated by the IFS manager when it calls an FSD back on a scheduled or queued event. After the FSD has completed its event processing, it must call this service to free the IO request packet. If the IO request packet is not freed, it may delay or prevent event processing for other FSDs.

pir
Supplies pointer to the IO request structure to be freed. This must be the same pointer that was passed to the FSD when the event function was called.
  • This service has no return value.


IFSMgr_RunScheduledEvents

IFSMgr_RunScheduledEvents

This service runs any pending events that were queued by requests to IFSMgr_SchedEvent or IFSMgr_QueueEvent and returns. It returns a status indicating whether or not any events were run.

None.
  • Carry flag clear, pending events were run.

    Carry flag set, no pending events.

Registers Used

None.


Path Parsing and Codepage Conversion Services

The following topics describe the Path Parsing and Codepage Conversion services.


IFSMgr_MetaMatch

IFSMgr_MetaMatch(
 string_t pUniPattern,
 string_t pUniName,
 int matchSem
 )

This service provides meta-character pattern matching which is needed by FSDs when searching for files. There are a number of different meta-matching semantics that are provided. The caller should specify the appropriate semantics based on the kind of meta-matching desired. All FSDs should use this service to search for files so that the entire system works consistently. Besides, if the meta-matching semantics are changed at a later point of time, the FSDs can work unchanged with the new semantics. This service takes care of both single and double byte character sets, so FSDs do not need to do any localization work.

There are three possible name formats that can be passed in under different situations to do meta-matching. All of them use the unicode character set. These are as follows:

FCB Name Format:
This format refers to a name or pattern as it occurs in a DOS directory entry. It consists of a "primary" component that is always 8 unicode characters long and an "extension" component that is always 3 unicode characters long. If necessary, primary or extension components are "right padded" with unicode space characters until they meet their respective length requirements. There is no intervening dot character between primary and extension components. In this format the routine assumes that both the name and pattern are upcased unicode. If the name was obtained from the media in OEM and was converted to unicode it is in upcased form, because it was stored that way. The IFS manager always passes patterns in upcased unicode form.
8.3 Name Format:
This format refers to a name or pattern as it occurs when a name is passed to a DOS name-based file I/O function (DOS FCB-style functions are excluded for the purposes of this definition). It consists of a "primary" component that is at least 1 but 8 or fewer unicode chars long, and an "extension" component that is zero to 3 unicode chars long. If a name has an extension, there is one intervening dot character between the primary and extension component. If the name has no extension, there is no dot character after the primary component. The IFS manager will never pass an 8.3-format name with a trailing dot.
Long Name Format:
This format refers to a name or pattern as it occurs when a name is passed to the new DOS long-name-based file I/O functions. Such a name is just a unicode character string. They have no extension per-se. The dot character in such a name is treated just like any other character. Note that an 8.3-format name is just a special case of a long-format name, in that only 1 dot character is allowed. The IFS manager will never pass a long-format name with a trailing dot. The IFS manager can, however, pass a long-format pattern with a trailing dot if and only if the pattern contains meta characters. See the following for the reason this is done.

There are a number of different meta-matching semantics that can be applied. There are also certain special rules about how names in the different formats are treated under the different meta-matching semantics. The scenarios an FSD will encounter while doing meta-matching and the appropriate parameters and name formats to use for each of these are described in the following:

Short Name API Matching Short Names From Media:
This service should be called with UFLG_DOS set. If there are meta-characters present in the pattern, UFLG_META must also be passed in. This will yield DOS compatible matching rules. Both the pattern and the name should be in unicode FCB name format whenever UFLG_DOS is set.
Short Name API Matching Long Names From Media:
This is not supported by this service. If an FSD wants to support this, it will have to figure out its own rules to perform the appropriate mappings. In general, it is not recommended that FSDs support this. For example, the FAT file system FSD provides short-name aliases for each long name and matches these short names on short name APIs to circumvent this issue.
Long Name API Matching Short Names From Media:
This service should be called with UFLG_NT set. If there are meta-characters present in the pattern, UFLG_META should also be passed in. In this case, the pattern can be anything allowed on the long-name APIs. However, the short name should be in 8.3-format (not FCB-format) and in the unicode character set. There are, however, certain special quirks in DOS that create complications while matching short names. These are described in the following.
DOS has name matching idiosyncrasies with respect to short names (that is, 8.3 format) that do not have an "extension" and how they must be matched with patterns containing embedded or trailing dots. The following rule must be observed in order to get DOS compatible match behavior when this service is called from a long name API which is matching names which are stored on media in 8.3 format (that is, as short names). The rule is true irrespective of whether the matching pattern has meta characters in it or not.
RULE: For this special case, we make a distinction between the following two kinds of short names:

  1. Having no dots in the name at all: This is the case of a short name with a primary component only.
  2. An embedded dot. The name has a dot but the last character in the name is not a dot. This is the case of a short name with both primary and extension components.
If the short name to be matched has an embedded dot, then nothing needs to be done to the name. The match can be done directly by calling this service. If the short name to be matched does not have a dot and the matching pattern has a dot, then append a trailing dot to the short name before calling this service.
Following this rule will yield MS-DOS and Windows NT/Windows 2000 compatible match results when using long name APIs to match short names retrieved from the media. The IFS manager passes a bit flag to FSDs indicating whether a matching pattern has a dot in it. This can be used by the FSDs to easily construct a name that can be correctly matched with a pattern.
Long Name API Matching Long Names From Media:
This service should be called with UFLG_NT set. If there are meta-characters present in the pattern, UFLG_META should also be passed in. In this case, both the pattern and the name can be anything allowed on the long-name APIs. Long-name APIs matching long names have no quirks. In long names, dots are just another character and are not accorded any special treatment. Dots are stored in long names as just another character. There is no need to add or remove dots from a long name prior to calling this service to match them.

pUniPattern
Supplies the matching pattern in unicode in the appropriate name format, as discussed above.
pUniName
Supplies the file name in unicode to be matched against the pattern. The name should be in the appropriate format, as discussed above.
matchSem
Supplies flags that determine the matching semantics to be used.
Meta-Matching Semantics Flags:
UFLG_NT | Matching follows strict Windows NT/2000 semantics. These are the semantics used for matching long names on the long-name APIs.
UFLG_DOS | Matching follows strict DOS semantics. These are the semantics used for matching short names on the short-name APIs. This refers to the 11 character fixed-length DOS FCB format.
UFLG_NT_DOS | Matching follows Windows NT/2000 semantics with certain exceptions applied to the strict regular expression matching that UFLG_NT implements. Exceptions to regular expression matching are applied, like assuming a name which has no dots will match a pattern which fully matches the name but ends in a "?" or ends in a "*.*" or ends in a ".*". If neither UFLG_NT or UFLG_NT_DOS is specified, the matching defaults to DOS semantics.
UFLG_META | The matching pattern contains meta-characters.

  • Returns zero if the name did not match the pattern. Returns a nonzero value if the name matches the pattern.


IFSMgr_TransMatch

IFSMgr_TransMatch(
 pioreq pir,
 srch_entry * pse,
 string_t pattern,
 _WIN32_FIND_DATA * pFindBuf
 )

This service converts a search buffer that is in the old DOS format (using the DTA) to a Win32 find buffer format with all the file names in unicode. Optionally, if a valid pattern is passed in, it will perform long name matching semantics on the name that has been found. This service can be used to support long name matching semantics on volumes that allow only DOS semantics. The search can be done in the normal DOS style and then be filtered further and converted to the Win32 find buffer format by calling this service. This service calls IFSMgr_MetaMatch internally for its meta-matching, so it provides the same uniform matching semantics.

pir
Supplies pointer to the IOREQ structure.
pse
Supplies pointer to DOS search buffer structure srch_entry. The relevant fields are described in the following:
Srch_Entry Structure:
Value | Meaning
se_key | Search key structure srch_key which contains information pertinent to the search operation that is in progress. This provides no input parameters.
se_attrib | Returns attributes of matched file.

Return Attribute Values:

Any combination of the following attributes may be returned.

Value | Meaning
FILE_ATTRIBUTE_READONLY | Read-Only file.
FILE_ATTRIBUTE_HIDDEN | Hidden file.
FILE_ATTRIBUTE_SYSTEM | System file.
FILE_ATTRIBUTE_DIRECTORY | Subdirectory.
FILE_ATTRIBUTE_ARCHIVE Archive file.

This attribute cannot be returned in combination with other attributes.

FILE_ATTRIBUTE_VOLUMELABEL | Volume label.

se_timeM
Returns DOS file time of matched file. This field is set by the FSD.
se_date
Returns DOS file date of matched file. This field is set by the FSD.
se_size
Returns size of matched file. This field is set by the FSD.
se_name[13]
Returns file name of matched file. This field is set by the FSD to the matching file name found by the search. The file name must be stored as an 8.3 format ASCIIZ string.
pattern
Supplies pattern to be matched in unicode long name format. Note that the 8.3 format is also acceptable since it is just a subset of the long name format.
pFindBuf
Supplies the pointer to the _WIN32_FIND_DATA buffer to contain the results of the find. Note that the file name strings in this buffer are unicode, so the buffer allocation needs to take care of this.
  • Returns zero if the name did not match the pattern or meta-matching was not requested for by passing in a NULL pattern. Returns nonzero value if the name matches the pattern.
IOREQ Structure: |
ir_pos | Returns the continuation key for the find. This is extracted from the sk_localFSD field in the srch_key structure se_key.
ir_data | Returns the Win32 find structure _WIN32_FIND_DATA filled in as follows:

Find Data Structure: |
dwFileAttributes | Returns the file attributes of the file found.

Attribute Values: |
Value | Meaning Any valid combination of the following attributes may be returned.
FILE_ATTRIBUTE_READONLY | Read-only file.
FILE_ATTRIBUTE_HIDDEN | Hidden file.
FILE_ATTRIBUTE_SYSTEM | System file.
FILE_ATTRIBUTE_DIRECTORY | Subdirectory.
FILE_ATTRIBUTE_ARCHIVE | Archive file.
FILE_ATTRIBUTE_VOLUMELABEL | Volume label found.

ftCreationTime Returns the file creation time in the Win32 FileTime structure format.

Win32 FileTime Structure: |
Value | Meaning
dwLowDateTime | Returns the low double word of the time in Win32 format.
dwHighDateTime | Returns the high double word of the time in Win32 format.

ftLastAccessTime | Returns the file last access time in Win32 FileTime structure format defined above.
ftLastWriteTime | Returns the file last write time in Win32 FileTime structure format defined above.
nFileSizeHigh | Returns the high 32-bits of the file size.
nFileSizeLow | Returns the low 32-bits of the file size.
cFileName | Returns the unicode long file name that was found.
CAlternateFileName | Returns the unicode alternate alias name (short file name) of the file that was found.


UniToBCSPath

UniToBCSPath(
 unsigned char * pBCSPath,
 ParsedPath * pUniPath,
 unsigned int maxLength,
 int charSet
 )

This service converts a canonicalized unicode path name to a normal path name in the specified BCS character set, that is, the path element lengths are converted into proper path separators in addition to the character set conversion. Currently, the Windows ANSI codepage or the current OEM codepage in the system can be specified for the conversion. It is important to note that the source and destination buffers cannot be the same nor can they overlap. They should be two separate buffers. This service does not terminate the converted path with a NUL character, the caller of the service needs to do this, if necessary.

pBCSSPath
Supplies a flat pointer to a destination buffer for the converted BCS path.
pUniPath
Supplies a flat pointer to a canonicalized unicode path name in the ParsedPath structure format that needs to be converted into a BCS path. The pointer should be pointing at the pp_elements field of the ParsedPath structure.
maxLength
Supplies the maximum length in bytes of the destination buffer, excluding the NUL character.
charSet
Supplies the BCS character set the unicode path needs to be converted to.
BCS Character Set Values:
Value | Meaning
BCS_WANSI | Specifies that the conversion should be done to the Windows ANSI codepage.
BCS_OEM | Specifies that the conversion should be done to currently active OEM codepage.

  • Returns the number of bytes in the converted unicode string and flags in the _QWORD structure format described in the following.
_QWORD Structure: The fields in this structure are filled in as follows. |
ddLower | Returns the number of bytes in the converted unicode string. Under the standard C parameter conventions, this field is returned in register [EAX].
ddUpper | Returns special flags about the mapping operation. Under the standard C parameter conventions, this field is returned in register [EDX].

Mapping Flag Values: |
Value | Meaning
MAP_FLAG_LOSS | Indicates that a loss occurred during the conversion. This will typically happen if the BCS character has no corresponding character in the unicode character set. The replacement character for this case is the underscore character "_", ASCII code 0x5f.
MAP_FLAG_TRUNCATE | Indicates that the destination buffer was not large enough to contain the converted BCS path.

pBCSPath Filled in with the converted BCS path.


UniToBCS

UniToBCSPath(
 unsigned char * pBCSStr,
 string_t  pUniStr,
 unsigned int length,
 unsigned int maxLength,
 int charSet
 )

This service maps a unicode string to a BCS string in the specified character set. Currently, the Windows ANSI codepage or the current OEM codepage in the system can be specified for the conversion. It is important to note that the source and destination buffers cannot be the same nor can they overlap. They should be two separate buffers. This service does not terminate the converted path with a NUL character, the caller of the service needs to do this, if necessary.

pBCSStr
Supplies a flat pointer to a destination buffer to contain the converted BCS string.
pUniStr
Supplies a flat pointer to the source unicode string that needs to be converted into a BCS string.
length
Supplies the length in bytes of the unicode input string.
maxLength
Supplies the maximum length in bytes of the destination buffer, excluding the NUL character.
charSet
Supplies the BCS character set the unicode path needs to be converted to.
BCS Character Set Values:
Value | Meaning
BCS_WANSI | Specifies that the conversion should be done to the Windows ANSI codepage.
BCS_OEM | Specifies that the conversion should be done to currently active OEM codepage.

  • Returns the number of bytes in the converted unicode string and flags in the _QWORD structure format described in the following.
_QWORD Structure: The fields in this structure are filled in as follows. |
Value | Meaning
ddLower | Returns the number of bytes in the converted unicode string. Under the standard C parameter conventions, this field is returned in register [EAX].
ddUpper | Returns special flags about the mapping operation. Under the standard C parameter conventions, this field is returned in register [EDX].

Mapping Flag Values: |
Value | Meaning
MAP_FLAG_LOSS | Indicates that a loss occurred during the conversion. This will typically happen if the BCS character has no corresponding character in the unicode character set. The replacement character for this case is the underscore character "_", ASCII code 0x5f.
MAP_FLAG_TRUNCATE | Indicates that the destination buffer was not large enough to contain the converted BCS string.

pBCSStr Filled in with the converted BCS string.


BCSToUni

BCSToUni(
 string_t  pUniStr,
 unsigned char * pBCSStr,
 unsigned int length,
 int charSet
 )

This service maps the BCS string in the specified character set to a unicode string. Only the Windows ANSI and currently configured OEM codepage can be specified for the BCS string. It is important to note that the source and destination buffers cannot be the same nor can they overlap. They should be two separate buffers. This service does not terminate the converted path with a NUL character, the caller of the service needs to do this, if necessary.

pUniStr
Supplies a flat pointer to a destination buffer for the converted unicode string.
pBCSStr
Supplies a flat pointer to the source BCS string that needs to be converted into a unicode string.
length
Supplies the length in bytes of the BCS input string.
charSet
Supplies the character set the BCS string uses.
BCS Character Set Values:
Value | Meaning
BCS_WANSI | Specifies that the BCS string uses the Windows ANSI codepage.
BCS_OEM | Specifies that the BCS string uses the currently active OEM codepage.

  • Returns the number of bytes in the converted unicode string and flags in the _QWORD structure format described in the following.
_QWORD Structure: The fields in this structure are filled in as follows. |
Value | Meaning
ddLower | Returns the number of bytes in the converted unicode string. Under the standard C parameter conventions, this field is returned in register [EAX].
ddUpper | Returns special flags about the mapping operation. Under the standard C parameter conventions, this field is returned in register [EDX].

Mapping Flag Values: |
Value | Meaning
MAP_FLAG_LOSS | Indicates that a loss occurred during the conversion. This will typically happen if the BCS character has no corresponding character in the unicode character set. The replacement character for this case is the underscore character "_", ASCII code 0x5f.
MAP_FLAG_TRUNCATE | Indicates that a malformed multi-byte character was detected, that is, a lead byte for a multi-byte character was found without a tail byte. This can happen either because the string passed in was malformed or because the length passed in was incorrect so as to fall at the boundary between a lead byte and a trail byte.


BCSToBCS

BCSToBCS(
 unsigned char * pDest,
 unsigned char * pSrc,
 int dstCharSet,
 int srcCharSet,
 unsigned int MaxLen
 )

This service maps a BCS string to another BCS string. Currently, the only conversions supported are from OEM to Windows ANSI and vice versa. It takes care of double-byte encoding.

pDest
Supplies a pointer to the destination buffer. The destination buffer must be long enough for the path.
pSrc
Supplies a pointer to the source buffer.
dstCharSet
Supplies the character set the destination string needs.
BCS Character Set Values:
Value | Meaning
BCS_WANSI | Specifies that the BCS string uses the Windows ANSI codepage.
BCS_OEM | Specifies that the BCS string uses the currently active OEM codepage.

srcCharSet
Supplies the character set the source string is in.
BCS Character Set Values:
Value | Meaning
BCS_WANSI | Specifies that the BCS string uses the Windows ANSI codepage.
BCS_OEM | Specifies that the BCS string uses the currently active OEM codepage.

MaxLen
Supplies the maximum length the destination path should be, that is, the size of the buffer.
  • Returns the number of bytes in the converted unicode string and flags in the _QWORD structure format described in the following.
_QWORD Structure: |
Value | Meaning The fields in this structure are filled in as follows.
ddLower | Returns the number of bytes in the converted unicode string. Under the standard C parameter conventions, this field is returned in register [EAX].
ddUpper | Returns special flags about the mapping operation. Under the standard C parameter conventions, this field is returned in register [EDX].

Mapping Flag Values: |
Value | Meaning
MAP_FLAG_LOSS | Indicates that a loss occurred during the conversion. This will typically happen if the BCS character has no corresponding character in the unicode character set. The replacement character for this case is the underscore character "_", ASCII code 0x5f.
MAP_FLAG_TRUNCATE | Indicates that a malformed multi-byte character was detected, that is, a lead byte for a multi-byte character was found without a tail byte. This can happen either because the string passed in was malformed or because the length passed in was incorrect so as to fall at the boundary between a lead byte and a trail byte.

pDest Contains buffer filled in with the converted BCS string.


UniCharToOEM

UniCharToOEM(
 unsigned short uniChar
 )

This service maps a unicode character to its equivalent in the current OEM codepage. If there is no corresponding character in the OEM codepage, it is converted to an underscore character (ASCII code 0x5f).

uniChar
Supplies the unicode character that needs to be converted into OEM.
  • Returns the corresponding character in the current OEM codepage, "_" if no such character. If the OEM codepage used double-byte encoding, [AH] contains the lead byte and [AL] contains the trail byte. On a single-byte encoding, [AL] contains the OEM character.


UniToUpper

UniToUpper(
 string_t pUniUpStr,
 string_t pUniStr,
 unsigned int length
 )

This service converts a mixed-case unicode string into an uppercased unicode string. For this service, the source and destination buffers can be the same, that is, the upcasing is done in place.

pUniUpStr
Supplies a flat pointer to the destination buffer to contain the upcased unicode string.
pUniStr
Supplies a flat pointer to the unicode string in mixed-case that needs to be upcased.
length
Supplies the length in bytes of the unicode source string.
  • Returns the number of bytes in the uppercased unicode string.
pUniUpStr Returns the upcased unicode string.


CreateBasis

CreateBasis(
 string_t pBasisName,
 string_t pUniName,
 unsigned int length
 )

This service maps a long name format case-preserved unicode name into an uppercased "basis" name which is also in unicode but in the FCB-format, that is, it has a "primary" name with 8 characters and a 3-character "extension" immediately following it with no intervening dot character. For this service, the source and destination buffers must be different.

The following rules are used to create the basis name:

  1. Leading dots and trailing dots are ignored in generating the basis name.
  2. Embedded whitespace characters are ignored in generating the basis name.
  3. The first three non-whitespace characters after the last embedded dot in the name form the 'extension'.
  4. The first 8 characters of the name form the 'primary' name. If there are dot characters before the first 8 characters (excluding leading dots), then the 'primary' name is that part of the name until the first dot character is hit.
  5. The long name syntax allows for certain special characters which are not allowed in the old DOS syntax. These characters are all replaced by an "_" character. In addition, any unicode character which is part of the newly formed basis name but is not translatable in the current OEM codepage is replaced by an "_" character.
pBasisName
Supplies a flat pointer to the buffer the basis name is to be returned in. This buffer must be at least 22 bytes long.
pUniName
Supplies a flat pointer to the unicode name from which the basis name needs to be generated.
length
Supplies the length in bytes of the unicode input name.
  • Returns the state of the mapping operation. These flags can be used to determine what information has been lost as a result of the mapping.
Mapping Flag Values: |
Value | Meaning
BASIS_LOSS | Indicates that either a unicode character in the input long-name could not be mapped into a corresponding unicode character in the OEM codepage or there were characters in the long name not allowed in the basis name. In both cases, the "_" is the replacement character.
BASIS_UPCASE | Indicates that a unicode character in the long-name had to be upcased for the basis name.
BASIS_TRUNC | Indicates that the input name did not fit into the standard DOS 8.3 style name. Either the primary name, extension or other components allowed in the long name were truncated during the mapping process. The output basis name is valid, but a truncated form of the long name passed in.
BASIS_EXT | Indicates that the created basis name has an extended character in it, that is, a character whose OEM Codepoint value is greater than 0x80. This extended character is, however, translatable in the current OEM codepage.

pBasisName Returns the generated basis name in this buffer.


MatchBasisName

MatchBasisName(
 string_t pBasisName,
 string_t pName
 )

This service compares two FCB-format unicode strings. One string is the "basis" name created from a long-name using the CreateBasis service. The other is a the FCB-format name retrieved from the OEM directory entry and converted to unicode by calling the BCSToUni service. The basis and the name are then "matched". This matching is different from normal matching. The name retrieved from the media could have a numeric tail on the primary name if it was an auto-generated name. This service compares the part of the primary name without the numeric tail and the extension of the directory name to the corresponding parts of the basis name. If there is a match, then the basis name is considered to match the directory name.

This helps during auto-generation of a unique name with a numeric tail. Instead of sequentially generating a name with increasing values for the numeric tail and searching the entire directory for each generated name to check if it is unique, the entire directory can be walked once looking for a match with the basis name. Any number that does not already exist as a numeric tail for the matched primary name can now be used as a numeric tail for the basis name without checking further for uniqueness. While this scheme may not generate the most accurate numeric tail for a given basis name, it is certainly far more efficient than scanning the directory for each auto-generated name.

pBasisName
Supplies a pointer to the basis name in FCB unicode format that needs to be matched.
pName
Supplies a pointer to the directory name in FCB unicode format that needs to be matched with the basis name.
  • Returns the value of the numeric tail on the directory name passed in. A value of zero means the basis name and the directory name do not match. A value of -1 indicates that the basis name and the directory name match, but there was no numeric tail on the directory name. Any other value is the value of the numeric tail on the directory name. The values for the numeric tail can range from 1 to 9999999.


AppendBasisTail

AppendBasisTail(
 string_t pBasisName,
 int tail
 )

This service inserts a numeric tail into a "basis" name previously constructed by calling the CreateBasis service. If the numeric tail (which is always a single-byte encoding), when appended to the primary name of the basis results in a primary name that is longer than 8 bytes, the primary name is truncated from the right until the truncated primary name with the numeric tail fits in an 8-byte multi-byte OEM string. This routine takes care of multi-byte encodings while generating the basis name and ensures that when the unicode basis name is converted into a BCS string, the primary name will still not exceed 8 bytes. A typical numeric tail has the form "~xxx" where xxx stands for the numeric value the tail is to be generated from.

pBasisName
Supplies a flat pointer to the basis name into which the numeric tail needs to be inserted.
tail
Supplies the value of the numeric tail that needs to be inserted.
  • Returns zero if the insertion failed because an invalid value was given for the numeric tail. Returns a nonzero value if the numeric tail was successfully inserted.
pBasisName Returns the basis name with the numeric tail inserted into it.


FCBToShort

FCBToShort(
 string_t p83Name,
 string_t pFCBName,
 int trailDot
 )

This service translates a name in unicode FCB-format to the unicode 8.3 format. If the FCB-format name has an extension, the 8.3-format name will have a dot character automatically inserted between the primary and extension components. If the FCB-format name does not have an extension, the 8.3-format name will only have a primary name. A trailing dot may still be inserted depending on the state of the trailDot flag. The source and destination buffers must be different for this service. The trailing dot capability is mostly used whenever a name that exists on the media as a short name only is being prepared for matching with LFN semantics.

p83Name
Supplies a flat pointer to the destination buffer to contain the 8.3-format output name. It must be at least 24 bytes in length.
pFCBName
Supplies a flat pointer to the source FCB-format name. This must be 22 bytes in length and in the proper FCB-format.
trailDot
Supplies a Boolean flag which indicates whether a trailing dot is to be appended to the output name when there is no extension. If the flag is set (nonzero value), a trailing dot is appended to the primary name. If the flag is clear (value of zero), no trailing dot is appended to the primary name.
  • Returns the number of bytes in the output name including the dot character inserted between the primary and extension components.


ShortToFCB

ShortToFCB(
 string_t pFCBName,
 string_t p83Name,
 unsigned int length
 )

This service translates a unicode 8.3-format name into a unicode FCB-format name. Different buffers must be used for the source and destination names.

pFCBName
Supplies a flat pointer to the destination buffer to contain the FCB-format name. This buffer must be at least 22 bytes in length.
p83Name
Supplies a flat pointer to the source 8.3-format name.
length
Supplies the length in bytes of the source 8.3-format name.
  • Returns the number of bytes in the output FCB-format name. Since the FCB-format is a fixed length format, the value returned is always 22.


ShortToLossyFCB

ShortToLossyFCB(
 string_t pFCBName,
 string_t p83Name,
 unsigned int length
 )

This service translates a unicode 8.3-format name into an FCB-format unicode name that is valid in the OEM namespace. Characters not valid in the OEM namespace are translated to underscores ("_"). This service is a variant of ShortToFCB and checks to see if a given unicode character can be converted into its corresponding BCS character in the current OEM codepage. ShortToFCB does not perform this check.

pFCBName
Supplies a flat pointer to the destination buffer to contain the FCB-format name. This buffer must be at least 22 bytes in length.
p83Name
Supplies a flat pointer to the source 8.3-format name.
length
Supplies the length in bytes of the source 8.3-format name.
  • Returns 1 if the conversion was successful, zero if there was a conversion error. Note that the conversion of a character into an underscore is not considered an error.


IFSMgr_GetConversionTablePtrs

IFSMgr_GetConversionTablePtrs(
 )

This service returns pointers to the various conversion tables used within the IFS manager to perform the various codepage conversions and the uppercasing. This is done to avoid duplicating these tables in the system. There should be no real reason for any FSD to use these tables for direct conversions, FSDs should just call the IFS manager services to do the appropriate conversions. The service is provided for situations where the IFS manager services cannot be called to do the conversions. The tables are AVL-tree-based run-length encoded structures, a discussion of the format of these tables is out of the scope of this document.

Nothing.
  • Returns a flat pointer to the _ConvTables structure containing pointers to the various conversion tables. This structure is filled in as follows:
_ConvTables Structure: |
Value | Meaning
ct_length | Returns the number of tables pointers are returned to. Currently, this is always six.
ct_UniToWinAnsiTbl | Returns a flat pointer to the table for converting from unicode format to Windows ANSI format.
ct_UniToOemTbl | Returns a flat pointer to the table for converting from unicode format to the current OEM codepage format.
ct_WinAnsiToUniTbl | Returns a flat pointer to the table for converting from Windows ANSI format to the unicode format.
ct_OemToUniTable | Returns a flat pointer to the table for converting from the current OEM codepage format to the unicode format.
ct_UniToUpperDeltaTbl | Returns a flat pointer to a table of deltas which is used in upcasing a unicode character. This is the table of values that need to be subtracted from a unicode character's value to upcase it. These values are different for different ranges of unicode characters.
ct_UniToUpperTbl | Returns a pointer to a table that is used for upcasing a unicode character. This table contains an index into the UniToUpperDelta table for each unicode character. The delta value in the UniToUpperDelta table corresponding to this index is then subtracted from the current codepoint value of the unicode character to give the upcased unicode character.


IFSMgr_FSDParsePath

IFSMgr_FSDParsePath(
 pioreq pir
 )

This service calls the IFS manager's parse routine. It provides a way for an FSD to parse a given path if it is called via private APIs. There is never a reason to do this on calls routed through the IFS manager.

pir
Supplies the pointer to the IOREQ structure.
IOREQ Structure:
Value | Meaning
ir_data | Supplies the pointer to the buffer that contains the path to be parsed.
ir_ppath | Supplies the pointer to the buffer to contain the parsed path. Note that this is an optional parameter. If this field contains the default invalid value of 0xFFFFFBBB, the parse code will automatically allocate a path buffer.

  • Returns the flags from the parse operation. This return value is not valid if the ir_error field in the IOREQ is nonzero indicating there was a parse error.
Path Parsing Flags: |
Value | Meaning
FILE_FLAG_WILDCARDS | Wildcard characters present in path name.
FILE_FLAG_HAS_STAR | Path has the asterisk as a wildcard character.
FILE_FLAG_LONG_PATH | Path has a long name component.
FILE_FLAG_KEEP_CASE | Preserve the case of the file name passed in when storing on disk. This also implies that this call should use long name semantics for its processing.
FILE_FLAG_HAS_DOT | File name component has a dot in its name.
FILE_FLAG_IS_LFN | File name component is a long name.

pir Returns filled in IOREQ structure.

IOREQ Structure: |
Value | Meaning
ir_error | Returns zero if success, error code if failure.
ir_ppath | Returns a pointer to the buffer containing the parsed path.


IFSMgr_ParseOneElement

IFSMgr_ParseOneElement(
 string_t pPathElem
 )

This service takes a single path element as an input and return the path parsing flags for it. Typically, this can be used to check if a given file name is an 8.3-name or a long name. This service cannot handle a full-fledged path and returns an error if the path passed in has path separators in it. There is a known bug in this function, see Knowledge Base article Q225489 for details.

pPathElem
Supplies a pointer to a single path element.
  • Returns the path parsing flags for the path element if successful. Returns -1 if there was an error while parsing the path element.
Path Parsing Flags: |
Value | Meaning
FILE_FLAG_WILDCARDS | Wildcard characters present in path name.
FILE_FLAG_HAS_STAR | Path has the asterisk as a wildcard character.
FILE_FLAG_LONG_PATH | Path has a long name component.
FILE_FLAG_KEEP_CASE | Preserve the case of the file name passed in when storing on disk. This also implies that this call should use long name semantics for its processing.
FILE_FLAG_HAS_DOT | File name component has a dot in its name.
FILE_FLAG_IS_LFN | File name component is a long name.


File Sharing Services

The following topics describe the File Sharing services.


IFSMgr_CheckAccessConflict

IFSMgr_CheckAccessConflict(
 int fSoftCompatibleDisable,
 fmode_t pfmode,
 int (*pfn)( fmode_t *, const void *),
 const void * FSDCookie
 )

This service validates the desired access and sharing mode and determines if it can be granted. The FSD is expected to maintain an open file table and a list of processes currently sharing the file. An enumeration function is passed in as part of the parameters. The FSD's enumeration function is called to enumerate the various instances of the open file. The IFS manager then checks the sharing and access modes for each open instance of the file to see if the desired access and sharing mode can be permitted.

fSoftCompatibleDisable
Supplies a flag to indicate whether "Soft Compatibility" is enabled or not. Soft compatibility is disabled if this flag is set and enabled if the flag is cleared.
pfmode
Supplies a pointer to a fmode_t structure. This structure is described in the following.
Fmode_t Structure:
fm_uid | This field provides the user ID for the process.
fm_cookie0 | This is a field where the caller can store anything. For example, this could be a pointer to an open file table structure.
fm_cookie1 | This is also a field where the caller can store anything. For example, this could be the pointer to a particular instance of the open file.
fm_mode | This field provides the desired sharing and access mode.
fm_attr | This field provides the attributes of the open file.

pfn
Supplies the pointer to the enumeration function.
FSDCookie
Supplies one of the parameters for the enumeration function.
  • Returns zero if the desired sharing mode can be granted, error code if it cannot be granted.
EnumerateOpenFileInstance(
 fmode_t pfname,
 const void * FSDCookie
 )

The enumeration function described above is called with a pointer to a fmode_t structure that is to be filled in and the FSDCookie parameter that was supplied by the caller. This parameter should contain enough information for the FSD to traverse its list of instances for an open file one by one. For each open instance, the function fills in the fields in the fmode_t structure that was passed in and returns to the IFS manager. The parameters for the enumeration function are described in the following.

pfname
Supplies a pointer to a fmode_t structure that is to be filled in by the enumeration function as described previously.
FSDCookie
Supplies the caller's passed in parameter.
  • Returns 1 if the enumeration was successful and the fmode_t structure has been filled in. Returns zero if all instances have been enumerated.


IFSMgr_LockFile

IFSMgr_LockFile(
 void ** ppFSDLockListHead,
 unsigned long LockOffset,
 unsigned long LockLength,
 unsigned long LockOwner,
 void * pOpenFileInstance,
 unsigned long fLockSemantics
 )

This service locks a region of an open file. This service supports two kinds of locking semantics: DOS and Netware. DOS semantics do not allow overlapping locks and a lock prevents any access to that region of the file by another process. On the other hand, Netware's locking semantics provides for overlapping read locks and non-overlapping write locks. It also has the concept of lock promotion of a read lock to a write lock and vice versa. For more details on the Netware locking semantics, please refer to the appropriate Netware documentation.

ppFSDLockListHead
Supplies a pointer to a variable that is to contain the pointer to the list of locks.
LockOffset
Supplies the starting offset in the file of the region to be locked.
LockLength
Supplies the length of region in the file to be locked.
LockOwner
Supplies the process ID of the process requesting the lock.
pOpenFileInstance
Supplies a pointer to the structure that describes the current open file instance.
fLockSemantics
Supplies flags indicating what kind of locking semantics are operative.
Lock Semantics Flags:
Value | Meaning
LOCKF_DOS | Indicates that DOS semantics are to be applied for the lock request.
LOCKF_NW | Indicate that Netware semantics are to be applied for the lock request.
LOCKF_RD | Indicates that a read lock should be taken. This value is allowed only with LOCKF_NW. DOS semantics do not have the concept of a read lock.
LOCKF_WR | Indicates that a write lock should be taken.

  • Returns zero if success, error code if failure.
ppFSDLockListHead The pointer to the lock list is stored in this variable on a successful return.

The IFS manager maintains a list of active locks on the file. The head of this list is stored in the variable pointed to by ppFSDLockListHead. The FSD should not attempt to interpret this list in any fashion, it is only for use by the IFS manager. Typically, the head for the list of locks would be a part of the open file information structure and would be maintained on a per-open-file basis. All locks on this open file are part of this list, irrespective of which process and which open file instance they belong to.

When you create a new file, make sure that the pointer pointed to by ppFSDLockListHead is initialized to NULL. Then, do not make any changes to this pointer; *ppFSDLockListHead is a "cookie" that is automatically maintained by IFS manager.


IFSMgr_UnlockFile

IFSMgr_UnlockFile(
 void ** ppFSDLockListHead,
 unsigned long LockOffset,
 unsigned long LockLength,
 unsigned long LockOwner,
 void * pOpenFileInstance,
 unsigned long fLockSemantics
 )

This service unlocks a previously locked region of an open file. The offset and the length of the region to be unlocked should correspond exactly to a previously locked region. This is true even in the case where there are overlapping locks. The IFS manager just walks the list of locks on the file and sees if it finds a match with one of them. If it does, it frees that lock entry from the list.

ppFSDLockListHead
Supplies a pointer to a variable that contains the pointer to the list of locks.
LockOffset
Supplies the starting offset in the file of the region to be locked.
LockLength
Supplies the length of region in the file to be locked.
LockOwner
Supplies the process ID of the process requesting the lock.
pOpenFileInstance
Supplies a pointer to the structure that describes the current open file instance.
fLockSemantics
Supplies flags indicating what kind of locking semantics are operative.
Lock Semantics Flags:
Value | Meaning
LOCKF_DOS | Indicates that DOS semantics are to be applied for the lock request.
LOCKF_NW | Indicate that Netware semantics are to be applied for the lock request.
LOCKF_RD | Indicates that a read lock should be taken. This value is allowed only with LOCKF_NW. DOS semantics do not have the concept of a read lock.
LOCKF_WR | Indicates that a write lock should be taken.

  • Returns zero if success, error code if failure.
ppFSDLockListHead The lock list head stored in this variable might have been updated.


IFSMgr_RemoveLocks

IFSMgr_RemoveLocks(
 void ** ppFSDLockListHead,
 unsigned long LockOwner,
 void *  pOpenFileInstance
 )

This service is called to remove the locks on a file.

ppFSDLockListHead
Supplies a pointer to a variable that contains the pointer to the list of locks.
LockOwner
Supplies the process ID of the process requesting the lock. A special process ID of zero can be passed in to remove all locks for a given file instance. Typically, this special value would be passed in when a process is terminating and its open file instance is being closed but there are still other processes that have the file open.
pOpenFileInstance
Supplies a pointer to the structure that describes the current open file instance. A special value of zero can be passed in to remove the locks by the specified process for all instances of the open file.
  • No return value.
ppFSDLockListHead The lock list head stored in this variable might have been updated or set to NULL.

There is one special case. If both the LockOwner and the pOpenFileInstance parameters are passed in as zero, then all active locks on the file are removed. This would usually be done when there are no open instances for an open file and the open file structure is being freed. If an open file is deleted, that would be another situation where all active locks on the file need to be removed.


IFSMgr_CheckLocks

IFSMgr_CheckLocks(
 void * pFSDLockListHead,
 unsigned long Offset,
 unsigned long Length,
 unsigned long Process,
 void * pOpenFileInstance,
 unsigned long fOperation
 )

This service checks if the specified I/O operation can be done on the file without violating any of the locks that are active on the open file. It walks the list of locks active on the open file and checks if the current I/O operation violates any of the locks.

pFSDLockListHead
Supplies a pointer to the head of the list of locks.
Offset
Supplies the starting offset in the file of the region the I/O operation is to be done to.
Length
Supplies the length of the I/O operation.
Process
Supplies the process ID of the process performing the I/O operation.
pOpenFileInstance
Supplies a pointer to the structure that describes the current open file instance.
fOperation
Supplies flags indicating what kind of I/O operation is being done.
I/O Operation Flags:
Value | Meaning
LOCKF_RD | Indicates that a read operation is being done.
LOCKF_WR | Indicates that a write operation is being done.

  • Returns zero if I/O operation can be done, error code if the I/O operation violates any of the active locks.


IFSMgr_CountLocks

IFSMgr_CountLocks(
 void * pFSDLockListHead,
 void * pOpenFileInstance
 )

This services returns a count of the number of locks on an open file for a specified open file instance.

pFSDLockListHead
Supplies a pointer to the head of the list of locks.
pOpenFileInstance
Supplies a pointer to the structure that describes the current open file instance.
  • Returns the number of locks for the specified open file instance.


IFSMgr_UnassignLockList

IFSMgr_UnassignLockList(
 void * pFSDLockListHead
 )

This service is provided for supporting volume locking. FSDs that do not allow direct disk I/O and consequently volume locking, do not need to make use of this service. Under the volume locking scheme, the IFS manager "temporarily" closes all open files on the volume when a Level 3 lock is taken. These files are later reopened by the IFS manager when there is an access to them. If such an open file has active locks, they need to be restored when the file is reopened. To facilitate this, this service walks the entire list of locks and marks them inactive instead of freeing them. Later, when the file is reopened by the IFS manager, the locks are reinstated by calling IFSMgr_ReassignLockFileInst. The FSD is passed a special status on this "virtual close" operation on a Level 3 lock. The FSD needs to look for this status and at that time call this service instead of calling IFSMgr_RemoveLocks to remove the locks.

pFSDLockListHead
Supplies a pointer to the head of the list of locks.
  • Nothing.


IFSMgr_ReassignLockFileInst

IFSMgr_ReassignLockFileInst(
 void * pFSDLockListHead,
 void * pOldOpenFileInstance,
 void * pNewOpenFileInstance
 )

This service is provided for the FSD to activate any previously active locks for a given file instance. When the file is reopened by the IFS manager on the release of the Level 3 lock, it provides an indication to the FSD that the file being reopened previously had active locks on it. In addition, the FSD is passed the pointer to the original lock list which was deactivated by calling IFSMgr_UnassignLockList previously. There is one more problem activating the lock, that is, since the open file structure as well as the open file instance structures were freed on the "virtual close", the file instance field in the lock structure could be invalid. To work around this, the IFS manager also passes in the pointer to the old file instance structure. Armed with these pieces of information, the locks for each open file instance can be reactivated and the entire lock list can thus be reconstructed.

pFSDLockListHead
Supplies a pointer to the head of the list of locks. This pointer is the same as what it was before the "virtual close" on the Level 3 lock.
pOldOpenFileInstance
Supplies the old value of the file instance structure pointer.
pNewOpenFileInstance
Supplies the new value for the file instance structure pointer after the file has been reopened.
  • Nothing.


Plug and Play Services

The following topics describe the services.


NotifyVolumeArrival

NotifyVolumeArrival(
 unsigned int drive
 )

This service is called by the IOS to notify the IFS manager of the arrival of a Plug and Play drive. This service should not be called by other VxDs directly. VxDs should interface with the IOS and let the IOS do the notification to the IFS manager. When this service is completed, the new drive has been registered as a valid IFS drive.

drive
Supplies the zero-based logical drive number of the new device.
  • None.


QueryVolumeRemoval

QueryVolumeRemoval(
 unsigned int drive
 )

This service is called by the IOS to notify the IFS manager of the pending removal of a plug-and-play drive. This service should not be called by other VxDs directly. VxDs should interface with the IOS and let the IOS do the notification to the IFS manager. This service calls IOS_Requestor_Service with IRS_QUERY_VOLUME_LOCK, to obtain the bitmap of drive letters associated with the volume. The member IRS_q_v_l_designtr contains the logical drive number zero = A: etc. Next, QueryVolumeRemoval tests for any open file handles (except those handles opened as type FIND_CHANGE_NOTIFY) on any of the drive letters (in other words, partitions) associated with the volume.

This service is called in the following places:

ISP_Query_Remove
CONFIG_START (sets CR_NEED_RESTART if any open files on RMM volumes)
CONFIGMG_QueryRemoveSubtree

drive
Supplies the zero-based logical drive number of the new device.
  • Returns zero if the query was successful. Returns a nonzero value if the query was failed.


NotifyVolumeRemoval

NotifyVolumeRemoval(
 unsigned int drive
 )

This service is issued by the IOS to notify the IFS manager of the removal of a Plug and Play drive. This service checks if there are open files or pending I/O operations on the drive that is being removed and puts up a warning dialog to the user in this case because there could be possible data loss. When this service is completed, the drive passed in is no longer a valid drive.

drive
Supplies the zero-based logical drive number of the new device.
  • None.


IFSMgr_PNPEvent

IFSMgr_PNPEvent(
 unsigned int Message,
 unsigned int Resource,
 unsigned int Flags
 )

This service broadcasts a Plug and Play event to all devices and applications in the system. The broadcast is issued on a number of operations which are listed in the following. It returns the result of the operation. On query operations, an error is returned if any of the recipients of the broadcast refuses the query. Valid devices include local and net drives as well as network transports and resources. When a network transport or resource is removed, all drives attached to them are removed as well.

Message
Supplies the operation for which the broadcast is being issued. The defined operations are described in the following.
Message Values:
Value | Meaning
DBT_DEVICEARRIVAL | The system has detected a new device.
DBT_DEVICEQUERYREMOVE | The system is in the process of querying a device for removal. This may be failed by any recipient of the broadcast.
DBT_DEVICEQUERYREMOVEFAILED | The query for removal of the device was failed. The device will not be removed.
DBT_DEVICEREMOVEPENDING | The device is in the process of being removed, but is still available.
DBT_DEVICEREMOVECOMPLETE | The device has been removed from the system.
DBT_TYPESPECIFIC | This is a type specific event, currently unimplemented.

Resource
Supplies the zero-based drive number of a volume-based device that is going away or the resource identification of the network transport or resource that is going away.
Flags
Supplies various flags for the broadcast.
Flag Values:
Value | Meaning
PNPT_VOLUME | Indicates a Plug and Play volume is going away. There are supplemental flags that can be set along with this flag.

Supplemental Flag Values:
Value | Meaning
DBTF_VOLUME | Indicates that a local volume is going away.
DBTF_NET | Indicates that a network volume is going away.
PNPT_NET | Indicates the a network resource or transport is going away. There are supplemental flags that indicate exactly which system component is being removed.

Supplemental Flags Values:
Value | Meaning
DBTF_RESOURCE | Indicates that a network resource is going away.
DBTF_XPORT | Indicates that a network transport is going away.

  • Returns zero if the broadcast was successful. A nonzero error code is returned if an error was encountered. This service has nonstandard error return values. The valid error return values for this service are listed in the following.
Error Return Values: |
Value | Meaning
PNPE_QUERY_REFUSED | The query request was rejected by at least one of the recipients.
PNPE_BAD_ARGS | Bad parameters were passed as input to the service.
PNPE_UNDEFINED | An undefined error was encountered during the broadcast.


_VolFlush

_VolFlush(
 unsigned int Volume,
 int Flags
 )

This service is called to flush a volume. The flush can just cause dirty buffers to be written or it can force all cached data in the FSD to be discarded in addition. This is usually called before a volume is being removed to flush all dirty buffers to disk.

Volume
Supplies a zero-based drive number for the volume that needs to be flushed.
Flags
The flag values are listed in the following.
Flush Flag Values:
Value | Meaning
VOL_DISCARD_CACHE | Indicates that any file system data that is cached should be discarded.

  • Returns zero if success, error code if failure.


Services for Win32 Support

The following topics describe the services for Win32 support.


IFSMgr_Win32DupHandle

IFSMgr_Win32DupHandle(
 pid_t srcPid,
 pid_t dstPid,
 unsigned long * pDupHandle,
 unsigned char Flags,
 unsigned long globalNWHandle,
 unsigned long * fReturnFlags
 )

This service is intended solely for the purpose of the Win32 subsystem. It should not be used by any other VxD in the system. It provides a duplicate handle for a given handle which is used for handle inheritance and memory-mapping. This service uses different methods to duplicate file handles based on whether the file handle is handled by the IFS manager, or by DOS, or by a third-party net-provider such as Netware.

srcPid
Supplies the process ID (DOS PSP) of the process that owns the file handle.
dstPid
Supplies the process ID (DOS PSP) of the process that needs a copy of this file handle.
pDupHandle
Supplies the handle number of the file handle that needs to be duplicated.
Flags
Supplies options for the duplication of the handle.
DupHandle Flags:
Value | Meaning
DUP_NORMAL | Indicates that this is a normal inter-process duplication.
DUP_MEMORY_MAPPED | Indicates that this is a duplication that needs to be done for memory-mapped files. The duplication for a memory-mapping done to a file is done in a special manner.

globalNWHandle
Supplies a global handle used for duplication. This parameter is passed in only if the duplication is being done on a system running real-mode Netware NetX. Duplication of handles on Netware redirectors needs to be done in a special fashion.
fReturnFlags
Supplies a pointer to a variable that contains status flags the IFS manager returns.
  • Returns zero if success, error code if failure.
fReturnFlags Contains status flags returned by the IFS manager if the operation succeeded. The status flags are defined in the following.

Status Flags: |
Value | Meaning
WDUP_RMM_DRIVE | This flag is returned only if the DUP_MEMORY_MAPPED flag is passed in on the input parameters. It indicates that the memory-mapping has been done to a file that does not have protect-mode drivers, it uses real-mode drivers. The Win32 subsystem deals with this situation in a different manner.
WDUP_NETWARE_HANDLE | This flag is returned if the IFS manager detected that the handle belonged to a Netware-managed drive. The IFS manager does special processing for this case and the Win32 subsystem also does special processing.


IFSMgr_Win32_Get_Ring0_Handle

This service is provided only for the use of the Win32 subsystem and should not be used by anyone else.

[EBX]
File handle to be converted.
  • Carry flag clear, handle successfully mapped.
[EBX] | Special Ring 0 handle corresponding to handle passed in.
[EDX] | Current file position for the file handle passed in.

Carry flag set, handle was not mapped. EBX is not changed on failure.

Registers Used

EAX, ECX, Flags.


IFSMgr_Win32MapExtendedHandleToSFT

IFSMgr_Win32MapExtendedHandleToSFT(
 unsigned long ExtHandle,
 unsigned long ExtPSP,
 unsigned short * pSFN
 )

This service is provided only for the use of the Win32 subsystem and should not be used by anyone else. It maps an extended handle to a DOS handle. The service must be called in the context of the DOS VM.

ExtHandle
Supplies the extended handle that needs to be mapped.
ExtPSP
Supplies the PSP of the process the extended handle belonged to.
pSFN
Supplies a pointer to the variable to contain the SFN value returned by the IFS manager.
  • Returns zero if success, error code if failure.
pSFN Contains the SFN value on a successful return.


IFSMgr_Win32MapSFTToExtendedHandle

IFSMgr_Win32MapSFTToExtendedHandle(
 unsigned short DOSHandle,
 unsigned long * pExtHandle
 )

This service is provided solely for the use of the Win32 subsystem. It maps a DOS handle to an extended handle. The service must be called in the context of the DOS VM. The service is failed if the DOS handle does not belong to the IFS manager.

DOSHandle
Supplies the DOS handle that is to be mapped.
pExtHandle
Supplies a pointer to the variable that is to contain the mapped extended handle.
  • Returns zero if success, error code if failure.
pExtHandle Contains the mapped extended handle if the operation was successful.


IFSMgr_Win32GetVMCurdir

IFSMgr_Win32GetVMCurdir(
 unsigned long Drive,
 char * pCurdirBuf
 )

This service is provided solely for use by the Win32 subsystem. It returns the current directory in the current VM context for a specified drive. The current directory string can have long names. It is always returned in the current OEM codepage.

Drive
Supplies the zero-based drive number of the drive whose current directory is needed.
pCurdirBuf
Supplies a pointer to the buffer to contain the current directory. This buffer should be at least MAX_PATH bytes in size.
  • Returns zero if success, error code if failure.
pCurdirBuf Contains the current directory for the specified drive on a successful return. The current directory path is returned without the preceding "<drive>:\" string, that is, the current directory string for the root directory consists of the null string.


Miscellaneous Services

The following topics describe miscellaneour services.


IFSMgr_CompleteAsync

IFSMgr_CompleteAsync(
 pioreq pir
 )

This function is called by the FSD on completion of an asynchronous read or write operation. The IFS manager then decides what is to be done based on the information contained in the IOREQ. To indicate that the FSD is doing asynchronous processing, it has to return a special STATUS_PENDING error code on the call to perform the operation.

pir
Supplies the Ioreq that was initially passed to the FSD to initiate the asynchronous operation. This Ioreq must be the one that is passed back. The fields of the Ioreq were filled in by the IFS manager according to the operation that was performed.
  • This service has no return value.


IFSMgr_Ring0_FileIO

This service provides a register-based VxD callable interface to the common file system functions. Other VxDs in the system can use this service to make file system calls without having to issue INT 21h calls. An FSD itself can call this interface to do file system operations in certain situations. The different functions provided as part of this service are described in the following. Since these calls can be made only by 'trusted' system components, the IFS manager does not do any parameter validation on them. Users of this service should be very careful to check that they are passing in valid parameters.

OpenCreateFile

This interface is the same as the interface for the INT 21h extended open function (06Ch ). If the R0_OPENCREATFILE function code is used, the operation is done in an independent context, so that handle is globally accessible from any VM. If the R0_OPENCREAT_IN_CONTEXT function code is used, the operation is done in the context of the current thread and process.

[EAX]
R0_OPENCREATFILE or RO_OPENCREAT_IN_CONTEXT
[BX]
Open mode and other flags. The flags are exactly the same as those on the INT 21h function 6Ch. Please refer to the specification of the INT 21h function for details.
[CX]
Attributes to use on a create operation.
[DL]
Action to be performed. Look at the INT 21h, function 6ch documentation for details.
[DH]
Special flags that are available only on this API. This register is reserved and not used on the INT 21h, function 6Ch API.
Special Ring 0 API Open Flags:
Value | Meaning
R0_NO_CACHE SHR 8 | Indicates that reads and writes on the file should not be cached. All operations will be directly done to the disk.
R0_SWAPPER_CALL SHR 8 | Indicates that the I/O operation is being performed to the system swap file. This is a privileged call that should be set only by the memory manager when it is doing I/O to page stuff in and out of the disk. The file system that handles swap-file I/O needs to ensure certain conditions to prevent deadlocks. These are described in Section 8.3.4 of this document.
OPEN_FLAGS_NO_COMPRESS SHR 8 | The file should not be compressed when it is created or changed.

[ESI]
Flat pointer to the path name of the file to be opened/created.
  • Carry flag clear, operation was successful.
[AX] | Handle to opened file.
[CX] | Actual action performed. For the return values, please refer to the document describing the INT 21h, function 6Ch API.

Carry flag set, an error occurred. [AX] contains the error code.
Registers Used

EAX, ECX, Flags.

ReadFile

This function is called to read a file previously opened by OpenCreateFile. The handle must be one returned from the OpenCreateFile service described above, it cannot be a handle opened by issuing an INT 21h. If the R0_READFILE_IN_CONTEXT function code is specified, the read operation is done in the current thread context. To use this function, the handle must have previously been opened using the R0_OPENCREAT_IN_CONTEXT function. The R0_READFILE function processes the read operation in the global context.

[EAX]
R0_READFILE or R0_READFILE_IN_CONTEXT. If opening as a memory mapped file, OR this value using (R0_MM_READ_WRITE shl 16).
[EBX]
File handle.
[ECX]
Count of bytes to be read. This can be a full 32-bit transfer count.
[EDX]
Position in file the read operation needs to start at.
[ESI]
Flat pointer to the buffer the data is to read into.
  • Carry flag clear, no error.
[ECX] Number of bytes actually read.

Carry flag set, an error occurred. [AX] contains the error code.

Registers Used

EAX, ECX, Flags.

WriteFile

This function is called to write to a file previously opened by OpenCreateFile. The handle must be one returned from the OpenCreateFile service described above, it cannot be a handle opened by issuing an INT 21h. If the R0_WRITEFILE_IN_CONTEXT function code is specified, the read operation is done in the current thread context. To use this function, the handle must have previously been opened using the R0_OPENCREAT_IN_CONTEXT function. The R0_READFILE function processes the read operation in the global context.

[EAX]
R0_WRITEFILE or R0_WRITEFILE_IN_CONTEXT
[EBX]
File handle.
[ECX]
Count of bytes to be written. This can be a full 32-bit transfer count.
[EDX]
Position in file the write operation needs to start at.
[ESI]
Flat pointer to the buffer that contains the data to be written.
  • Carry flag clear, no error.
[ECX] Number of bytes actually written.

Carry flag set, an error occurred. [AX] contains the error code.

Registers Used

EAX, ECX, Flags.

CloseFile

This function is called to close a file previously opened by OpenCreateFile. The handle must be one returned from the OpenCreateFile service described above, it cannot be a handle opened by issuing an INT 21h.

[EAX]
R0_CLOSEFILE
[EBX]
File handle
  • Carry flag clear, no error.

    Carry flag set, an error occurred. [AX] contains the error code.

Registers Used

EAX, Flags.

GetFileSize

This function is called to get the size of a file previously opened by OpenCreateFile. The handle must be one returned from the OpenCreateFile service described above, it cannot be a handle opened by issuing an INT 21h.

[EAX]
R0_GETFILESIZE
[EBX]
File handle
  • Carry flag clear, no error.
[EAX] Size of the file in bytes.

Carry flag set, an error occurred. [AX] contains the error code.

Registers Used

EAX, Flags.

FindFirstFile

This function is called to perform a FindFirst operation. This function provides the same functionality as the FindFirst INT 21h function 714Eh and supports long file names.

[EAX]
R0_FINDFIRSTFILE
[CX]
Must match attributes to be used for the find operation.
[ESI]
Flat pointer to path name the find operation is to be done on.
[EDX]
Flat pointer to buffer to contain the results of the find operation. This buffer should be in the _WIN32_FIND_DATA structure format.
  • Carry flag clear, no error.
[EAX] Find context handle to be used for a subsequent FindNextFile operation.

The find data buffer is filled in appropriately.

Carry flag set, an error occurred. [AX] contains the error code.

Registers Used

EAX, Flags.

FindNextFile

This function is called to perform a FindNext operation. The handle used for this call must be one obtained by calling the FindFirstFile service described above, it cannot be a handle obtained by issuing an INT 21h call.

[EAX]
R0_FINDFIRSTFILE
[EBX]
Find context handle obtained by calling FindFirstFile.
[EDX]
Flat pointer to buffer to contain the results of the find operation. This buffer should be in the _WIN32_FIND_DATA structure format.
  • Carry flag clear, no error.

    The find data buffer is filled in appropriately.

    Carry flag set, an error occurred. [AX] contains the error code.

Registers Used

EAX, Flags.

FindCloseFile

This function is called to terminate a Find operation. The handle used for this call must be one obtained by calling the FindFirstFile service described above, it cannot be a handle obtained by issuing an INT 21h call.

[EAX]
R0_FINDCLOSEFILE
[EBX]
Find context handle obtained by calling FindFirstFile.
  • Carry flag clear, no error.

    Carry flag set, an error occurred. [AX] contains the error code.

Registers Used

EAX, Flags.

FileAttributes

This function is called to get or set the current attributes of a file. It provides the same functionality as the INT 21h function 7143h.

[AH]
R0_FILEATTRIBUTES
[AL]
GET_ATTRIBUTES to get the attributes of a file.

SET_ATTRIBUTES to set the attributes of a file.

[CX]
Attributes of the file, valid only for the SET_ATTRIBUTES operation.
[ESI]
Flat pointer to a path name for the file whose attributes need to be returned.
  • Carry flag clear, no error.
[CX] Attributes of the file returned only on the GET_ATTRIBUTES operation.

Carry flag set, an error occurred. [AX] contains the error code.

Registers Used

EAX, ECX, Flags.

RenameFile

This function is called to rename a file. This provides the same functionality as the INT 21h function 7156h.

[EAX]
R0_RENAMEFILE
[ESI]
Flat pointer to source path name of file name that is to be renamed.
[EDX]
Flat pointer to destination path name to which the file name is to be renamed.
  • Carry flag clear, no error.

    Carry flag set, an error occurred. [AX] contains the error code.

Registers Used
Flags.

DeleteFile

This function is called to delete a file. This provides the same functionality as the INT 21h function 7141h.

[EAX]
R0_DELETEFILE
[CX]
Attributes for the delete operation. This has the search attribute and the must-match attribute just like the INT 21h, function 7141h. Refer to the documentation of the INT 21h function for details about the attributes.
[ESI]
Flat pointer to path name of file(s) to be deleted. Wildcards are allowed.
  • Carry flag clear, no error.

    Carry flag set, an error occurred. [AX] contains the error code.

Registers Used
Flags.

LockFile

This function is called to perform record locking operations on files. This provides the same functionality as the INT 21h function 5Ch. The handle passed in should be obtained by calling the OpenCreateFile function described above, it cannot be a handle obtained by issuing an INT 21h call. Note that this operation is always done in the current context because it makes no sense to have a file lock in a global context. Hence, the OpenCreateFile should have been done using the context-sensitive R0_OPENCREAT_IN_CONTEXT function code.

[AH]
R0_FILELOCKS
[AL]
LOCK_REGION to take a record lock.

UNLOCK_REGION to release a record lock.

[EBX]
Handle to file.
[ECX]
Process ID of the process on whose behalf the locking operation is to be issued.
[EDX]
Offset of the region that is to be locked.
[ESI]
Length of the region that is to be locked.
  • Carry flag clear, no error.

    Carry flag set, an error occurred. [AX] contains the error code.

Registers Used
Flags.

GetDiskFreeSpace

This function returns the current disk free space statistics. It provides the same functionality as INT 21h function 36h.

[EAX]
R0_GETDISKFREESPACE
[DL]
1-based driveletter whose disk freespace is desired (zero = default drive, 1= A, 2 = B,...)
  • Carry flag clear, no error.
[AX] | Number of sectors per cluster.
[BX] | Number of available clusters on disk.
[CX] | Number of bytes per sector.
[DX] | Total number of clusters on disk.

Carry flag set, an error occurred. [AX] contains the error code.

Registers Used

AX, BX, CX, DX, Flags.

ReadAbsoluteDisk

This function is called to read absolute sectors from the disk. It provides the same functionality as the INT 25h interface.

[AH]
R0_ABSDISKREAD
[AL]
Zero-based driveletter the operation is to be done on (zero = A, 1 = B,...).
[ECX]
Number of sectors to read.
[EDX]
Starting sector number for the read.
[ESI]
Flat pointer to buffer the read is to be done into.
  • Carry flag clear, no error.

    Carry flag set, an error occurred. [AX] contains the error code.

Registers Used
Flags.

WriteAbsoluteDisk

This function is called to write absolute sectors to the disk. It provides the same functionality as the INT 26h interface.

[AH]
R0_ABSDISKWRITE
[AL]
Zero-based driveletter the operation is to be done on (zero = A, 1 = B,...).
[ECX
Number of sectors to write.
[EDX]
Starting sector number for the write.
[ESI]
Flat pointer to buffer containing the data to be written.
  • Carry flag clear, no error.

    Carry flag set, an error occurred. [AX] contains the error code.

Registers Used
Flags.

IoctlHandle

This function is called to do a handle-based IOCtl. It is currently used by certain system components and should not be used by other VxDs. Other than the registers documented here, the rest of the IOCtl parameters depend on the specific IOCtl being used and should be the same as that for the corresponding INT 21h IOCtl sub-function.

[AH]
R0_IOCTLHANDLE
[AL]
IOCtl sub-function code.
[EBX]
File or device handle.
  • Carry flag clear, no error.

    Carry flag set, an error occurred. [AX] contains the error code.

Registers Used

EAX, Flags.


IFSMgr_Ring0GetDriveInfo

This service returns information about whether a given drive is managed by the IFS manager and whether it is being handled by protect or real-mode drivers. This information can be useful for certain purposes e.g. for paging.

[EDX]
Zero-based driveletter of the desired drive.
  • Carry clear, this is a drive that is managed by the IFS manager. Other information about the drive:
[EAX] Additional drive information:

Drive Information Flags: |
IFS_DRV_RMM | This drive is an IFS drive but it uses real-mode drivers. There are no protect-mode drivers to service this drive.
IFS_DRV_DOS_DISK_INFO | This drive is a special drive such as a compressed real-mode drive that has no protect-mode driver. For these drivers to work, the DOS get disk info call needs to be sent down for correct results. This information is utilized by certain other components in the system for various purposes.

Carry set, this is not an IFS drive. It is handled by DOS or a third-party provider.

Registers Used

EAX, Flags.


IFSMgr_InstallFileSystemApiHook

IFSMgr_InstallFileSystemApiHook(
 pIFSFileHookFunc HookFunc
 )

This service is called to install a file system API hook. This should be called by a VxD that wants to hook the file system API calls and do special processing on them. The IFS manager returns a pointer to a variable that contains the address of the next hooker in the chain. If the FSD wants to chain the call on, it should dereference this pointer to get the address of the function of the previous file system API hooker. This field is always valid. If this is the first hooker in the chain, the IFS manager automatically installs a default function which simply routes the call onward. So, hookers do not need to check if there is a previous hooker while chaining on, there is always a previous hooker.

HookFunc
Supplies the address of the hook function that is to be called by the IFS manager on a call.
  • Returns a pointer to a variable that contains the address of the previous hook function in the chain, if successful. If this function is failed for reasons such as out of memory, the return value is zero.


FileSystemApiHookFunction

FileSystemApiHookFunction(
 pIFSFunc FSDFnAddr,
 int FunctionNum,
 int Drive,
 int ResourceFlags,
 int CodePage,
 pioreq pir
 )

The hook function is called on every API call that the IFS manager needs to call the FSDs on. The hook function is called with the following parameters:

FSDFnAddr
Supplies the address of the FSD function that is to be called for this API.
FunctionNum
Supplies the function that is being performed. This is usually one of the list of functions described in Section 8.5. Exceptions are noted as appropriate. They are as follows:
Function Type Values:
Value | Meaning
IFSFN_READ | Read a file.
IFSFN_WRITE | Write a file.
IFSFN_FINDNEXT | FindNext operation on a handle.
IFSFN_FCNNEXT | FindFirstChangeNotifyNext function.
IFSFN_SEEK | Seek on a file.
IFSFN_CLOSE | Close a file handle.
IFSFN_FINDCLOSE | Close a find context handle.
IFSFN_FCNCLOSE | Close a find change notify context handle.
IFSFN_COMMIT | Commit a file.
IFSFN_FILELOCKS | Lock a region of a file.
IFSFN_FILETIMES | Get/set time of a file.
IFSFN_PIPEREQUEST | Handle-based pipe request. See Section 8.6.1
IFSFN_HANDLEINFO | Handle information on pipes. See Section 8.6.3.
IFSFN_ENUMHANDLE | Enumerate information about handle.
IFSFN_CONNECT | Connect/mount a resource (net, local or character FSD).
IFSFN_DELETE | Delete a file.
IFSFN_DIR | Directory-based operations.
IFSFN_FILEATTRIB | Get/set attributes of a file.
IFSFN_FLUSH | Flush a resource.
IFSFN_GETDISKINFO | Get disk free space.
IFSFN_OPEN | Open/create a file.
IFSFN_RENAME | Rename a file.
IFSFN_SEARCH | DOS-style search operation.
IFSFN_QUERY | Query information about resource.
IFSFN_DISCONNECT | Disconnect/unmount a resource (net, local or character FSD).
IFSFN_UNCPIPEREQ | UNC-path based pipe request. See Section 8.6.2.
IFSFN_IOCTL16DRIVE | IOCtl operation.
IFSFN_GETDISKPARMS | Get disk parameters.
IFSFN_FINDOPEN | LFN-style FindFirst operation.
IFSFN_DASDIO | Direct disk access operations.

Drive
Supplies the 1-based drive the operation is being performed on (-1 if UNC).
ResourceFlags
Supplies the kind of resource the operation is being performed on.
Resource Flags:
Value | Meaning
IFSFH_RES_UNC | UNC resource.
IFSFH_RES_NETWORK | Network drive.
IFSFH_RES_LOCAL | Local drive.
IFSFH_RES_CFSD | Character device.

CodePage
Supplies the codepage that the user string was passed in on.
CodePage Values:
Value | Meaning
BCS_WANSI | Windows ANSI codepage.
BCS_OEM | Currently configured OEM codepage.

pir
Supplies pointer to IOREQ structure. This structure is filled in based on the function being performed as described in Section 8.5.
  • The function return value again depends on the function being processed. The hooker needs to preserve the same return behavior that is expected of the FSD for each of the different APIs if it hooks any of the calls.


IFSMgr_RemoveFileSystemApiHook

IFSMgr_RemoveFileSystemApiHook(
 pIFSFileHookFunc HookFunc
 )

This service is called to remove a previously installed a file system API hook. This function will always succeed unless an invalid parameter is passed in. There is no situation in which a previously installed hook cannot be removed. However, hookers that provide basic functionality that the system depends upon should never unhook themselves until the system shuts down. Otherwise, the behavior of the entire system will be affected. However, the IFS manager does not do any explicit checking to prevent this case from happening.

HookFunc
Supplies the address of the hook function to be removed. This should the same as the function that was previously installed to hook the file system APIs.
  • Returns zero if the hook was successfully removed. Returns -1 if the hook was not removed. The only way this function can fail is if an invalid function address is passed in.


IFSMgr_CDROM_Attach

IFSMgr_CDROM_Attach(
 unsigned long Drive,
 unsigned long * pVRP,
 int fDoMount
 )

This service is used by the CD-ROM FSD while doing asynchronous operations. It indicates to the IFS manager that it has a reference to the resource so that it will not disappear while the operation is still in effect. It also has an option to not mount even if the volume needs to be mounted. This can be used by FSDs that perform asynchronous operations.

Drive
Supplies the zero-based drive number of the drive the attachment needs to be done to.
pVRP
Supplies a pointer to the variable in which the IFS manager returns the system volume handle for this drive. This handle is later used to pass requests down to the IOS.
fDoMount
Supplies a boolean flag indicating whether a mount operation is allowed or not. A value of TRUE indicates that the mount operation can be done, if necessary. An error is returned if a mount is needed, but is not allowed.
  • Returns zero if successful. If a mount was needed, but not allowed by the caller using the fDoMount flag, an error code of -1 is returned. If the mount was allowed, but there were errors mounting the drive, the appropriate error code is returned.
pVRP Contains the system volume handle for the specified drive on a successful return.


IFSMgr_CDROM_Detach

IFSMgr_CDROM_Detach(
 unsigned long Drive,
 unsigned long VRP
 )

This service is called by the CD-ROM driver to detach a drive after a preceding attach call. The IFS manager looks for the drive with the correct system volume handle and then performs the detach on that volume.

Drive
Supplies the zero-based drive number of the drive the detachment needs to be done for.
VRP
Supplies the system volume handle of the volume to be detached.
  • Nothing.


IFSMgr_FSDUnmountCFSD

IFSMgr_UnmountCFSD(
 unsigned long IFSResHandle
 )

This service can be used by a character FSD to unmount itself from any of the devices it is currently mounted on. The IFS manager will automatically unmount it when the device goes away.

IFSResHandle
Supplies the IFS resource handle for the character device. This was passed in to the CFSD in ir_fh when the device was mounted.
  • Returns zero if the device was successfully unmounted, error code if failure.


IFSMgr_MountChildVolume

IFSMgr_MountChildVolume(
 unsigned long VRP,
 unsigned long Drive
 )

This service is used to mount a child volume that is associated with a parent volume. Typically, compression drivers like DRVSPACE use this to create the host and child drives.

VRP
Supplies the system volume handle for the parent volume the child volume is associated to.
Drive
Supplies the zero-based drive number for the drive unit the child is to be mounted on.
  • Returns zero if success, error code if failure.

The IFS manager looks for a parent volume with the same system volume handle as the one passed in. If one is found, a drive mapping is created for the child volume and it is mounted.


IFSMgr_UnmountChildVolume

IFSMgr_UnmountChildVolume(
 unsigned long VRP,
 unsigned long Drive
 )

This service is used to unmount a previously mounted child volume and remove its mapping to the host volume. Note that the host volume is not unmounted, it still remains valid. The host volume is unmounted only when the host drive itself goes away.

VRP
Supplies the system volume handle for the child volume.
Drive
Supplies the zero -based drive number for the drive unit the child is on.
  • Returns zero if success, error code if failure.


IFSMgr_SwapDrives

IFSMgr_SwapDrives(
 unsigned long VRP,
 unsigned long drive1,
 unsigned long drive2
 )

This service is provided to allow the drive letters of the host and child volumes to be swapped. Some compressed volume drivers do this. The FSD that manages the host and child volumes is also notified of the drive change.

VRP
Supplies the system volume handle for the parent and child drives. Both drives have to use the same system volume handle because they are logical mappings.
drive1
Supplies the zero-based drive number of one of the parent or child drives.
drive2
Supplies the zero -based drive number of the other drive in the pair.
  • Returns zero if drives swapped successfully, error code if failure.

Note that this function does not need to differentiate between the parent and child drives. It is irrelevant which is which as far as swapping them is concerned.


IFSMgr_FSDGetCurrentDrive

IFSMgr_FSDGetCurrentDrive(
 pioreq pir
 )

This service returns the current drive for the VM and thread context that this request originally came in on. The IOREQ stores the state of the original request.

pir
Supplies the pointer to the IOREQ structure that this call originally came in on.
  • Returns the 1-based current drive number on the original context.


_GetMappedErr

_GetMappedErr(
 unsigned int Function,
 unsigned int ExtErr
 )

This service maps the extended error code for a given INT 21h function on to the allowed set of error codes for that particular function and returns the error that DOS would have returned on the INT 21h API. DOS returns a restricted set of errors on the INT 21h API and stores the detailed error information in its extended error variables.

Function
Supplies the INT 21h function number that would have been passed in AH on an INT 21h call.
ExtErr
Supplies the extended error code.
  • Returns the mapped error code that is valid for the function passed in.


IFSMgr_GetLockState

IFSMgr_GetLockState(
 unsigned long Drive,
 unsigned long * pLockType,
 unsigned long * pLockFlags,
 unsigned long * pLockOwner
 )

This service returns information about volume locks on a given drive.

Drive
Supplies the zero-based drive number to query the volume lock information for.
pLockType
Supplies a pointer to the variable to contain the type of volume lock in effect.
pLockFlags
Supplies a pointer to the variable to contain flags for the volume lock in effect.
pLockOwner
Supplies a pointer to the variable to contain the process ID of the process owning the volume lock.
  • Returns zero if success, error code if failure.
pLockType Returns the current lock level in effect. The lock level can take on the values listed in the following.

Lock Type Values: |
Value | Meaning
-1 | This indicates that no lock is currently in effect.
0 | This indicates that a Level 0 lock is currently in effect.
1 | This indicates that a Level 1 lock is currently in effect.
2 | This indicates that a Level 2 lock is currently in effect.
3 | This indicates that a Level 3 lock is currently in effect.

pLockFlags Returns flags operative for the current lock level, if any.

Lock Flag Values: |
Value | Meaning
LOCKP_ALLOW_WRITES | Indicates that the volume lock taken allows writes to happen while it is in effect. If this flag is not set and a volume lock is in effect, the volume lock does not allow writes to happen. This flag is not valid for a Level 0 lock, it is valid on all other lock levels.
LOCKP_FAIL_MEM_MAPPING | Indicates that memory-mapping operations cannot be done while the volume lock is effect. If this flag is not set and a volume lock is in effect, memory-mappings are allowed while the volume lock is operative. This flag is not valid for a Level 0 lock, it is valid on all other lock levels.
LOCKP_LOCK_FOR_FORMAT | Indicates that the volume is locked for a format operation. This flag is valid only when the lock level is 0. If this flag is not and a Level 0 lock is in effect, the volume is not locked for formatting.

pLockOwner Returns the process ID of the process owning the lock. Note that this is an internally generated process ID and does not refer to any specific data structure. It is purely to be used for identification purposes without any interpretations done on it.


QueryPhysLock

This service is used to query if the current process owns the physical volume lock on the INT 13h drive passed in. The IFS manager checks its internal data structures to see if this process is also the owner of the physical lock.

[EAX]
Supplies the INT 13h unit number for the disk the operation is being done on.
  • Carry clear, current process owns the volume lock.

    Carry set, current process does not own the volume lock.

Registers Used
EAX, ECX, EDX, Flags.


Miscellaneous Debugging Services

The following topics describe the miscellaneous debugging services.


IFSMgr_Printf

IFSMgr_Printf(
 char * pfstr,
 . . .
 )

This service prints a string to the debugging console. It uses either Windows debug services or prints it directly via the COM port. This service is available only on debug versions of the IFS manager. On the non-debug version, this service returns without doing anything. This service takes a variable number of arguments depending on the format string passed in. This service is not available until the IFS manager has finished its Device_Init during device initialization.

pfstr
Supplies pointer to formatting string. Formats currently understood are:
Format Specifications:
Value | Meaning
%c | Single character.
%[l]d, %[l]x | Long integer or long unsigned hexadecimal integer.
%[F]s | Far string.
%p | Far pointer to void. Address printed in selector:offset format.
%% Prints the '%' character.

The other parameters are all arguments to the print function. There could be a variable number of these depending on the formatting string.

  • This service has no return value.


IFSMgr_AssertFailed

IFSMgr_AssertFailed(
 char * pmsg,
 char * pfname,
 unsigned long line
 )

This service causes an assertion failure message to be printed and breaks into the debugger. This service is available only on debug versions of the IFS manager. On the non-debug version, this service returns without doing anything. This service is not available until the IFS manager has finished its Device_Init during device initialization.

pmsg
Supplies pointer to the ASCIIZ message string of the failure message.
pfname
Supplies pointer to the ASCIIZ file name string of the source file the failure occurred in.
line
Supplies line number in the source file the failure occurred at.
  • This service has no return value.


IFSMgr_LogEntry

IFSMgr_LogEntry(
 char * pname,
 unsigned long info1,
 unsigned long info2,
 int sdepth,
 unsigned int mask
 )

This service makes a log entry in the IFS manager's trace log. The IFS manager keeps a trace log in memory for debugging purposes. The contents of this log can be seen by using the debugger. This service is available only on debug versions of the IFS manager. On the non-debug version, this service returns without doing anything. This service is not available until the IFS manager has finished its Sys_Crit_Init during device initialization.

pname
Supplies pointer to string of four characters to put into the log.
info1
Supplies first doubleword of information stored in the log.
info2
Suplies second doubleword of information stored in the log.
sdepth
Supplies stack depth for return address ( number of procedures ).
mask
Supplies the type of the log information.
Log Information Type:
Value | Meaning
LOG_MISC | Miscellaneous information.
LOG_APITRACE | Information about trace APIs.
LOG_REFS | Information about log reference counts.
LOG_EVENTS | Information about the event queue.
LOG_NCBS | Information about NCBs.
LOG_CACHE | Information about the redirector cache.
LOG_HEAP | Information about the heap.
LOG_DATAGRAM | Information about datagram NCBs.
LOG_VBRNCBS | Information about Vbrowse NCBs.
LOG_VBRINFO | Other Vbrowse information.

  • This service has no return value.


IFSMgr_DebugMenu

IFSMgr_DebugMenu(
 pIFSMenu pm
 )

This service prints the debug service menu that is passed in and returns the address of the handler routine for the menu item that the user selected. The FSD passes in a table of menu strings and handler addresses, one for each menu item. The IFS manager displays the entire menu and then returns the address of the handler routine associated with the menu item the user selects. The user can hit ESC to quit the menu without selecting anything. This service is available only on debug versions of the IFS manager. On the non-debug version, this service returns without doing anything. This service is not available until the IFS manager has finished its Sys_Crit_Init during device initialization.

pm
Supplies pointer to menu structure which is an array of IFSMenu structures.
IFSMenu Structure:
Value | Meaning
pMenu_string | Supplies menu string to display. A NULL pointer for the string indicates end of the list of menu items.
pMenuHandler | Supplies handler for this menu item.

  • Returns the address of the menu handler for the menu item selected by the user. Returns NULL if the user did not select any menu item.


IFSMgr_DebugVars

IFSMgr_DebugVars(
 )

This service returns a pointer to the debug variables structure in the IFS manager. This service is available only on debug versions of the IFS manager. On the non-debug version, this service returns a NULL pointer. This service is not available until the IFS manager has finished its Sys_Crit_Init during device initialization.

No entry parameters.
  • Returns a pointer to the IFS debug variables structure which is as follows:
IFSDebugVars Structure: |
Value | Meaning
idv_rev | Revision level of the DebugVars structure.
idv_lmask | Trace logging mask.
idv_debugbits | Debugging control bits.

IDB_NOISYBROWSER | Noisy debug output from the browser.
IDB_NOISYMSSNGR | Noisy debug output from the messenger.


IFSMgr_GetDebugString

IFSMgr_GetDebugString(
 char * prompt,
 char * buffer,
 unsigned int len
 )

This service fetches an input string from the user through the debug console. It displays the prompt passed in by the caller of the service and returns the string entered by the user in response to the prompt. This service is available only on debug versions of the IFS manager. On the non-debug version, this service returns without doing anything.

prompt
Supplies pointer to prompt string to display to user.
buffer
Supplies pointer to buffer to contain user response string.
len
Supplies length of buffer.
  • Returns zero if the user hit ESC during input indicating the user response is invalid. Returns 1 if the buffer contains a string.


IFSMgr_GetDebugHexnum

IFSMgr_GetDebugHexnum(
 char * prompt,
 unsigned long * phexval
 )

This service fetches a long hex value from the user through the debug console. It displays the prompt passed in by the caller of the service, converts what the user types in to a hex value and returns this hex value. This service is available only on debug versions of the IFS manager. On the non-debug version, this service returns without doing anything.

prompt
Supplies pointer to prompt string to display to user.
phexval
Supplies pointer to long variable to contain the hex value.
  • Returns zero if the user hit ESC during input indicating the user response is invalid. Returns 1 if the buffer contains a string.


IFSMgr_DbgSetFileHandleLimit

IFSMgr_DbgSetFileHandleLimit(
 unsigned long MaxHandles
 )

This service allows the caller to set a limit on the maximum number of available extended handles in the system. By default, this value is 65024. However, in order to test boundary conditions where the system can run out of file handles, the ceiling value can be changed to a smaller number. This service is available only on debug versions of the IFS manager. On non-debug versions, this service returns without doing anything.

MaxHandles
Supplies the value for the maximum number of allowed extended handles in the system. This value should be a multiple of 256.
  • Returns the maximum handle limit before it was set to the new value passed in if successful. Returns zero if failure.

If the value for the maximum number of handles is not a multiple of 256, an error is returned.


Compatibility

These FSDs must be able to support all of the function interfaces that they may have provided in previous implementations for compatibility. An example of such an interface is network APIs that are used to manage the network. An existing application that uses these interfaces must be able to continue to run. This support must be implemented by the FSD. Since many of these interfaces are implemented by hooking interrupts, there is a possibility of overlap in the FSD specific functions. The IFS manager provides services to hook and service other interrupts and these services should be used by the FSDs. The FSDs must manage these functions with the intent that other FSDs exist in the system at the same time. In most cases, this simply means chaining on to allow other FSDs to handle requests that are intended for them.


File Naming Conventions

File path names are referred to here as a two-part name, the volume name and the path name. The volume name identifies the disk drive or volume that is defined. This is sometimes referred to as the root path name. The Path name identifies the directory and file name on the volume.


Volume Name Conventions

The volume name identifies the file system that is being referenced. For local file systems the volume name is the "drive:" syntax. For network file systems the volume name identifies the network file resource. There is no consistent naming convention that has been followed by network vendors. Each network defined the convention for volume names in a different way. To get around this, a typed naming convention is being defined that will support the different naming conventions used by different networks.


Path Name Conventions

Path name conventions are the rules used to form names that uniquely identify files in a given file system. Although each file system can have specific rules about how individual components in a directory or file name are formed, all file systems follow the same general conventions for combining components. For example, although the FAT file system requires that file and directory names have the 8.3 file name format, and LongFileNames ( LFN ) FAT file system allows names to be any length, both file systems use the backslash (\) character to separate directory names and the file name when forming a path.


Path Names in the FAT File System

Valid FAT-system file names have the following form:

[\][directory\]filename[.extension]

The directory parameter specifies the directory that contains the file's directory entry. This value must be followed by a backslash (\) to separate it from the file name. If the specified directory is not in the current directory, directory must include the names of all directories in the path, separated by backslashes. The root directory is specified by using a backslash at the beginning of the name. For example, if the directory abc is in the directory sample and sample is in the root directory, the correct directory specification is \sample\abc. A directory name consists of any combination of up to eight letters, digits, or the following special characters:

$ \% ' - _ @ ~ ` ! ( )

A directory name can also have an extension, which is any combination of up to three letters, digits, or special characters, preceded by a period (.). The file name and extension parameters specify the file. File name can be any combination of up to eight letters, digits, or the following special characters:

$ \% ' - _ @ ~ ` ! ( )

Extension can be any combination of up to three letters, digits, or special characters, preceded by a period.


Path Names with LFN Support

With LFN support, file names can be up to 255 characters long (excluding the NUL character). The period (.) is a valid file name character and can be used as many times as desired. The following special characters can also be used in LFNs.

: + , ; = [ ]

Blank spaces can be used anywhere in an LFN, but blank spaces and periods at the end of a file name are ignored. There is no requirement that LFN file names have extensions; however, many applications still create and use them.

An LFN can be all uppercase, all lowercase, or mixed case. The case is preserved for directory listings but is ignored in file searches and all other system operations. Therefore, in a given directory, there cannot be more than one file with the same name when the only difference is case.


Int 13 Extension APIs

These APIs are designed to extend the PC ROM BIOS INT 13h functionality, to support disks with more than 1024 cylinders, and to add support for software control of drive locking for removable media.


Data Structure

The fundamental data structure is the disk address packet, which is based on an absolute sector number. It is up to the INT 13h implementation to convert this to physical parameters appropriate to the media.

disk_addr_pkt   struc
    packet_size     db     16       ; size of packet in bytes
    reserved        db      0       ; reserved, must be zero
    block_count     dw      ?       ; number of blocks to transfer
    buffer_addr     dd      ?       ; address of transfer buffer
    block_num       dq      ?       ; starting absolute block number
disk_addr_pkt   ends

Packet size is included in the structure to provide for future modifications. It contains the size of the address packet in bytes, including the size byte. For this version, it must always be set to 16. If packet size is not at least 16, then the request is rejected with (AH)=01h and CF=1. Packet sizes greater than 16 are not rejected by this version. The caller is responsible for understanding the level of support of any specific implementation before invoking an INT 13h extension.

Block count is, on input, the number of blocks to be transferred, and on output, the number of blocks actually transferred. A block count of zero means zero blocks will be transferred.

The buffer address is the 32-bit (segment:offset) address of the buffer to transfer data to or from.

Block number refers to the absolute block from the beginning of the disk, regardless of partitions. The first block is numbered zero. In general, it is assumed that block numbering goes in order of all blocks on a track, interleaved as appropriate, followed by all blocks on the following tracks in that cylinder in head order, followed by the first block on the first track of the next cylinder. This ordering is not intended to exclude remapping of bad tracks or blocks to other disk regions, or to prevent other optimizations based on location of consecutively numbered blocks.


Register Conventions

The INT 13h extensions adhere, as much as possible, to the following registers conventions:

ds:si ==> disk address packet
dl    ==> drive number
ah    ==> function code/return status

The distinction between "removable" disks numbered zero through 7Fh and "fixed" disks numbered 80h-FFh differ somewhat from existing INT 13h implementations. Drives numbered zero through 7Fh are the same as they are regarded in the present INT 13h standard, removable drives that can be inserted and ejected at arbitrary times, without necessarily any software control or notification. Drives numbered 80h-FFh include traditional fixed disks, but also include advanced removable drives that must support changeline and software locking and unlocking. New functions have been included in this specification to support these types of drives.

Return codes are the same as defined for the standard INT 13h interface, but include the following new error codes:

B0h | Volume not locked in drive
B1h | Volume locked in drive
B2h | Volume not removable
B3h | Volume in use
B4h | Lock count exceeded
B5h | Valid eject request failed


API Subsets

It is permissible for an implementor to support only certain subsets of the API defined in this proposal. However, these subsets are well defined, and each must be supported in its entirety. Currently there are two API subsets defined.

The first defines the set of functions necessary to support access to large disks, using the disk address packet structure. This subset comprises the functions Check Extensions Present (41h), Extended Read (42h), Extended Write (43h), Verify Sectors (44h), Extended Seek (47h), and Get Drive Parameters (48h).

The second subset defines the functions needed to support software control of drive locking and ejecting, and comprises the functions Check Extensions Present (41h), Lock/Unlock Drive (45h), Eject Drive (46h), Get Drive Parameters (48h), Get Extended Disk Change Status (49h), and the INT 15h

Removable Media Eject Intercept. If a removable media drive is placed in the drive number range 80h-FFh, then it must support the removable drive control API subset.

The API subsets supported on a particular implementation can be determined through the Check Extensions Present function, which returns a bitmap of subsets usable for a particular drive.

If the API subset support bitmap indicates a function is not supported and that function is subsequently invoked, the request is rejected with (AH)=01h and CF=1.


Check Extensions Present

Entry:
    AH = 41h
    BX = 55AAh
    DL = Drive number
Exit:
    carry clear
        AH = Major version of extensions
        AL = Internal Use Only
        BX = AA55h
        CX = API subset support bitmap
    carry set
        AH = error code = 01h, Invalid Command

This function is used to check for the presence of the INT 13h extensions for a particular drive. If the carry flag is returned set, the extensions are not supported for this drive.

If the carry flag is returned cleared, BX must be checked for the value AA55h to confirm that the extensions are present. If this value is correct, the value of CX must then be checked to determine what subset of this API is supported on this drive. At least one subset must be supported. Bit 0 of CX set indicates that the extended disk access subset is supported. Bit 1 of CX set indicates that the removable drive control subset is supported. All other bits are reserved, and must be returned zero.

For this version of the specification, major version must be returned 1. The major version is incremented when this API changes. (AL) may be used by the BIOS implementor as a minor version/revision field. However, it must not be tested by invoking software.


Extended Read

Entry:
    AH = 42h
    DL = Drive number
    DS:SI = Disk address packet

Exit:
    carry clear
       AH = 0
    carry set
       AH = error code

This function reads sectors from disk to memory

In the event of an error, the block_count field of the disk address packet is filled in with the number of blocks read before the error occurred.


Extended Write

Entry:
    AH = 43h
    AL
        bit 0 = 0 Write with verify off
              = 1 Write with verify on
        bits 7-1 = reserved, set to 0
    DL = Drive number
    DS:SI = Disk address packet
Exit:
    carry clear
        AH = 0
    carry set
        AH = error code

This function writes sectors from memory to disk

If write with verify is not supported, the BIOS rejects the request with (AH)=01h, CF=1. Function 48h can be used to detect whether write with verify is supported.

In the event of an error, the block_count field of the disk address packet is filled in with the number of blocks written before the error occurred.


Verify Sectors

Entry:
    AH = 44h
    DL = Drive number
    DS:SI = Disk address packet
Exit:
    carry clear
        AH = 0
    carry set
        AH = error code

This function verifies blocks without transferring data between disk and system memory.

In the event of an error, the block_count field of the disk address packet is filled in with the number of blocks verified before the error occurred.


Lock/Unlock Drive

Entry:
    AH = 45h
    AL
        = 0 Lock volume in drive
        = 1 UnLock volume in drive
        = 02 Return lock/unlock status
        = 03h-FFh - reserved
    DL = Drive number
Exit:
    carry clear
        AH = 0
    carry set
        AH = error code.

This function logically locks/unlocks removable media in a specifed drive.

This function must be supported for all removable drives numbered 80h and above. If a fixed disk supports the Removable Drive Control API subset, then this function is always returned with success, (AH)=0h.

There must be support for up to 255 locks per drive. A drive may not be physically unlocked until all locks to that drive have been matched with a corresponding unlock. Excess unlock calls must be returned with carry set and AH = B0h, Drive not locked.

If the number of locks supported value would be exceeded on a lock request, then the request is rejected with carry set and AH = B4h, Lock count exceeded.

Locking a drive without media present is a valid operation.

On return from a lock or unlock request, (AL) contains the lock state of the drive as maintained by the BIOS. This is mainly provided for unlock requests for when the lock count remains greater than zero after the request has been satisfied. In this case, the drive remains locked.

Any physical locking and unlocking of the drive is implementation dependent, but system software will operate on the assumption that a locked drive cannot be removed without an unlock request.


Eject Removable Drive

Entry:
    AH = 46h
    AL = 0h, reserved
    DL = Drive number
Exit:
    carry clear
        AH = 0
    carry set
        AH = error code

This function logically ejects a media from the specified drive.

This function must be supported for all removable drives numbered 80h and above. If a fixed disk supports the Removable Drive Control API subset, then this function is always returned with carry set and AH = B2h, Volume not removable. An attempt to eject media locked in a drive must return with carry set and AH = B1h, Volume locked in drive.

This function represents a request to remove the volume in the specified drive. Whether the drive is actually ejected is implementation dependent, but system software that issues or observes this call should flush any buffers it is holding for that volume.

If this call is issued for a drive without media, the request is returned with carry set and AH = 31h, No media in drive.

If this call is issued to an unlocked, removable media drive with media present, the INT 13h code must invoke INT 15h (AH)=52h to determine if it may proceed with the ejection request. If the ejection request is rejected, then the error code returned in (AH) is the same as the INT 15h error code. If the ejection request is accepted and issued and subsequently fails, the request is returned with carry set and AH = B5h.


Extended Seek

Entry:
    AH = 47h
    DL = Drive number
    DS:SI = Disk address packet

Exit:
    carry clear
        AH = 0
    carry set
        AH = error code

This function positions disk head at a specified sector


Get Drive Parameters

Entry:
    AH = 48h
    DL = Drive number
    DS:SI = address of result buffer.
Exit:
    carry clear
        AH = 0
        DS:SI = result buffer, filled in with the following structure:
            info_size     dw 26  ; size of information buffer
            flags         dw ?   ; information flags
            cylinders     dd ?   ; number of cylinders on disk
            heads         dd ?   ; number of heads on disk
            sec_per_track dd ?   ; number of sectors per track
            sectors       dq ?   ; number of sectors on requested disk
            sector_size   dw ?   ; number of bytes per sector
    carry set
        AH = error code

This function returns physical characteristics of a specified drive

The info_size fields contains the size in bytes of the buffer passed in and returned, including this field. It must be set by the caller before invoking this function, indicating the size of the buffer passed in. It will also be filled in on return, indicating the size of the buffer returned. The returned size cannot be larger than the passed-in size. This mechanism allows the returned values of this function to be extended in the future with a minimum of compatibility problems.

The flags field is used to return additional information about the disk characteristics. Currently, Bits zero through 6 are defined. The others are reserved and must be set to zero by the implementor.

Bit 0 has the following meaning:

0 = DMA boundary errors may occur

1 = DMA boundary errors will be handled transparently

If this bit set, it indicates that the ROM BIOS will handle DMA boundary error conditions automatically, and DMA boundary errors (error code 09h) will never be returned to the caller.

Bit 1 has the following meaning:

0 = Cylinder/head/sector-per-track info not supplied

1 = Cylinder/head/sector-per-track info valid

Bit 1 will be clear for block devices for which traditional geometry descriptions are inappropriate.

Bit 2 has the following meaning:

0 = Drive is not removable

1 = Drive is removable

Bit 3 has the following meaning:

0 = Drive does not support write with verify

1 = Drive supports write with verify

Bit 3 indicates whether the Write with Verify (4301h) is supported on this drive.

Bit 4 has the following meaning:

0 = Drive does not have change line support

1 = Drive has change line support

Bit 4 must be set for removable drives accessed through drive numbers 80h and above, as well as appropriate drives numbered zero through 7Fh.

Bit 5 has the following meaning:

0 = Drive is not lockable

1 = Drive is lockable

Bit 5 must be set for removable drives accessed through drive numbers 80h and above, as well as appropriate drives numbered zero through 7Fh.

Bit 6 has the following meaning:

0 = CHS values are for the media that is currently in the drive (removable media only); values must be returned for the media if the media is in the drive.

1 = CHS values are maximum supported by the drive (when there is no media in the drive).


Get Extended Disk Change Status

Entry:
    AH = 49h
    DL = Drive number
Exit:
    if change-line inactive (media has not been changed)
        carry clear
            AH = 0
    if change-line active (media may have been changed)
        carry set
            AH = 06h

This function returns disk change status of a specified drive.

If this function returns with carry flag set, the media has not necessarily been changed; the change line can be activated by simply unlocking and locking the drive door without removing the media.

This function corresponds to INT 13h Function 16h, but explicitly allows any drive number to be passed in. If a fixed disk supports the Removable Drive Control API subset, then this function always returns with carry clear and (AH) = zero.


INT 15h Removable Media Eject Intercept

Entry:
    AH = 52h
    DL = Drive number
Exit:
    carry clear
        AH = 0
        Implies ejection may proceed
    carry set
        AH = error code, B1h or B3h
        Implies ejection must be rejected

This intercept is called in response to a software request (INT 13h, AH=46h, Eject drive) to eject a disk from a removable media drive. Typically a user will press an eject button or use a software command to request that a particular volume be ejected. The code that handles this request will issue this INT 15h function before actually honoring the request. By default the INT 15h handler returns with ejection accepted status. A disk cache program could hook this INT 15h call, and return acceptance or rejection based on the state of its buffers for this disk. It could also be used by operating system software as a media changed signal.


Device Driver IOCTLs

Two new generic IOCTLs have been added to the resident block device driver to allow access to the removable media support in extended Int13 BIOSs that support the calls. Other block device writers should implement these as well. The calls are:

LOCK/UNLOCK
EJECT


LOCK/UNLOCK

mov bx, DriveNum  ; drive number 0=default, 1=A, 2=B ...
mov ch, 8         ; device category must be 8
mov cl, 48h       ; LOCK/UNLOCK minor number
mov ax, 440D      ; generic IOCTL function number
mov dx, seg ParamBlock
mov ds, dx
mov dx, offset ParamBlock
int 21h
jnc success
mov [ErrorValue], ax

Locks or unlocks the drive.

  • On error sets the Carry flag and the AX register to one of these error values:
01h | Function not supported
B0h | Volume not locked in drive
B2h | Volume not removable
B4h | Lock count exceeded

DriveNum (BX)
Specifies the drive for the operation. Can be zero through for the default drive, 1 for A, 2 for B, and so on.
ParamBlock (DS:DX)
Address of the parameter block for the function. The block has two byte fields. The first is LOCK_UNLOCK_OP, which has one of the following values:
0 | Lock volume in drive
1 | UnLock volume in drive
02 | Return lock/unlock status

The values 03h through 0FFh are reserved.

The second byte field is filled on return from the call as the lock status of the drive.


EJECT

mov bx, DriveNum  ; drive number, 0=default, 1=A, 2=B, ...
mov ch, 8         ; device category must be 8
mov cl, 49h       ; EJECT minor number
mov ax, 440Dh     ; generic IOCTL function number
int 21h
jnc success
mov [ErrorValue], ax

This is a simple call through with no additional parameters. If the call is successful (CY flag is clear) then on return the specified drive will be ejected. If more than one drive letter is pointed to a single physical drive number, then the drive will remain locked as long as any of the relevant drive letters are locked.

  • On error, sets the Carry flag and the AX register to one of these error values:
01h | Function not supported
B1h | Volume locked in drive
B2h | Volume not removable
B5h | Valid eject request failed

DriveNum (BX)
Specifies the drive for the operation. Can be zero for default drive, 1 for A, 2 for B and so on.


Virtual Machine Manager (VMM)

This documentation describes the Windows® 95 DDK Virtual Machine Manager (VMM).


Virtual Machine Manager Overview

The virtual machine manager (VMM) is the 32-bit protected-mode operating system at the core of Windows 95. Its primary responsibility is to create, run, monitor, and terminate virtual machines. The VMM provides services that manage memory, processes, interrupts, and protection faults. The VMM works with virtual devices, 32-bit protected-mode DLLs, to allow the virtual devices to intercept interrupts and faults to control the access that an application has to hardware devices and installed software.

Both the VMM and virtual devices run in a single, 32-bit, flat model address space at privilege level 0 (also called ring 0). The system creates two global descriptor table (GDT) selectors, one for code and the other for data, and uses these selectors in the CS, DS, SS, and ES segment registers. Both selectors have a base address of zero and a limit of 4 gigabytes (GBs), so all the segment registers point to the same address space. The VMM and virtual devices never change these registers.

The VMM provides multiple-threaded, preemptive multitasking. It runs multiple applications simultaneously by sharing CPU (central processing unit) time between the threads in which the applications and virtual machines run. The VMM is also non-reentrant. This means that virtual devices must synchronize access to the VMM services. The VMM provides services, such as semaphores and events, to help virtual devices prevent reentering the VMM.

The virtual machine manager provides a variety of services, messages, macros, and structures to help virtual devices manage their corresponding hardware devices and services. The following sections introduce the services and provide details about how to call the individual services, messages, macros, and structures.


Paging Through MS-DOS

When run on hardware for which 32-bit drivers are not available, Windows 95 may be forced to use MS-DOS® and/or the BIOS for access to the paging device. When paging through MS-DOS, the VMM changes its behavior in significant ways, and new rules apply to existing VxDs. Windows 95 will also page through MS-DOS if the system is running in safe mode.

Make sure to test your VxD on a configuration that pages through MS-DOS. One way to accomplish this is to go to the Control Panel, and select System, Performance, File System, Troubleshooting, then 'Disable all 32-bit protect-mode disk drivers'.

Special circumstances that apply to paging through MS-DOS will be noted as they arise.


Pageable VxDs

This section describes how paging works using the Windows 3.1 model. Then, changes to the model for Windows 95 are described.

Under Windows 3.1, VxD code segments are always locked. This implies that VxD code is normally not preempted, with the following exceptions:

  • If interrupts are enabled, hardware interrupts may be serviced. Therefore, any data structures that may be accessed by hardware interrupts must be protected by disabling interrupts during the access. (And obviously, any data structures accessed by a hardware interrupt must be locked.)
  • Accessing swappable memory may result in the code being pre-empted, even if interrupts are disabled. (The VMM might need to wait for the page to arrive from the swap device.) Therefore, any data structures that exist in swappable memory must be protected by some sort of synchronization mechanism; merely disabling interrupts is not good enough.
  • Calling a service that adjusts execution priorities may result in the code being pre-empted if the result of the adjustment is that the current virtual machine no longer has the highest execution priority in the system.
  • Calling a service that allocates or frees memory from the system heap or pages from the page allocator may result in the code being pre-empted if the swap file needs to be adjusted to account for the memory being allocated or freed.

The terms pageable and swappable are synonymous. The VMM uses paging as its form of memory management. It does not swap segments or tasks. Where you see the word swap or a derivative thereof, substitute the corresponding form of the word page.

Windows 95 supports VxD with pageable code segments. While this has the benefits of allowing rarely-used code segments to get paged out, thus freeing up memory, it does come at the cost of adding more rules to follow.

Here are additional rules that apply to Windows 95 pageable VxDs. They are in addition to the existing rules from Windows 3.1.

  • Pageable code and data may not be accessed by a hardware interrupt.
  • Code in pageable segments may be preempted at any time by the paging system, even if interrupts are disabled. Thus, care should be taken to protect data structures from corruption by unsynchronized access. Consider the following code fragment:
        pushfd                 ; Disable interrupts to protect a global
    cli                    ; variable, so that the update is atomic
    mov eax, pHead         ; Get the head of the list
    mov ecx, [eax].pNext   ; And delete it from the list
    mov     pHead, ecx
    popfd                  ; End of critical section

    If this code fragment resides in pageable memory, then it may be possible for code to interrupt this sequence and corrupt the linked list. Using standard synchronization techniques such as semaphores, you can serialize access to the data structure, but since there are hidden possibilities for deadlocks, the safest way to guarantee the correctness of the code is to keep it in locked memory. Furthermore, the data in which the linked list resides should also reside in locked memory.

    If Windows 95 is paging through MS-DOS, allowing VxD code segments to be paged out would be catastrophic. In such situations, the VMM automatically locks all VxD code segments (and VxDLdr does the same for dynamically-loaded VxDs).


Bitness

Some services alter their behavior depending on whether the virtual machine is running in 16-bit or 32-bit protected mode. The VMM determines whether a virtual machine is in 16-bit or 32-bit protected mode by recording whether the virtual machine entered protected mode (via the DPMI services) as a 16-bit or 32-bit application. It does not check whether the current CS is a 16-bit or 32-bit code segment. This means that if a 16-bit DPMI client happens to create a 32-bit code segment and switch to it, the VMM will still treat it like a 16-bit application and use only the low word of the extended registers.

For compatibility reasons, the Windows 95 system virtual machine executes as a 16-bit DPMI client. That implies that every Win32 application is considered a 16-bit application by the VMM. As a result, Win32 applications cannot communicate with VxDs by the same means that 16-bit Windows applications can (software interrupts, callbacks, VxD services, etc). Win32 applications must use the DeviceIOControl interface to communicate with VxDs that support device I/O calls.


Deadlocks

With the greater degree of multi-tasking available in Windows 95, the opportunity for deadlocking the system grows enormously. Moreover, some operations, while not deadlocking the system, effectively shut off multi-tasking until the operation completes. The section on events will discuss various deadlock issues related to events. Here are some other issues:

Remember that there are two components in the system which together control whether a thread may run. VxDs interact with the ring 0 scheduler and time slicer, whose rules for choosing which thread may run can be oversimplified to 'run the highest priority thread not blocked on a ring 0 synchronization object'. Meanwhile, there is also a ring 3 scheduler implemented in Kernel32 which has its own rules for which thread may run, based on things applications do, such as WaitForSingleObject or GetMessage. In order for a thread to run at ring 3, both schedulers must agree that the thread is runnable.

For example, a common scenario is for a VxD to block thread A at ring 0 and wait until thread B does some work at ring 3. If thread A owns some resource at ring 3 which thread B requires, then the system grinds to a halt because thread B cannot run until thread A releases the resource, but thread A is waiting for thread B to do something.

Another common scenario is for a VxD to attempt to acquire a resource at event or timeout time which the current thread already owns. This results in even shorter deadlock chain, where a thread ends up waiting for itself. Examples of this will be given in the Events section, but the general rule is not to block inside an event or timeout. Even if you don't deadlock the system, you will almost certainly cause multi-tasking to halt until the thread unblocks.

Another scenario is to call Begin_Critical_Section, followed by some other operation which blocks on a synchronization object. 'Blocking with the critical section' usually deadlocks the system because large numbers of important system operations require the critical section in order to proceed. By holding onto the critical section while waiting for something else, those other important system operations cannot be carried out.

Yet another situation is for thread A to go into a Resume_Exec loop, waiting for some operation to be performed by thread B. Resume_Exec does not block but merely processes events, so if thread B does not have sufficiently high priority, it will never run and thus thread A will wait forever.


Hook procedures

Windows 95 provides additional services that allow a virtual device to unhook various services that it had previously hooked. This has become increasingly important with the introduction of dynamically-loaded VxDs. In order to support this feature, new requirements have been imposed on VxDs which hook device services or faults.

The hook procedure passed in the ESI register to Hook_Device_Service, Hook_V86_Fault, Hook_PM_Fault, and Hook_VMM_Fault must be one declared with the BeginProc macro (defined in vmm.h) with the HOOK_PROC attribute. You are required to pass a new-style hook procedure even if you never plan to unhook the service. Failure to comply will prevent other devices from unhooking the service. Windows 95 supports old-style hook procedures solely for backwards-compatibility. Support for old-style hook procedures may be removed in a future version of Windows, so it is imperative that you convert all your hook procedures to the new style when building for Windows 95. (New-style hook procedures are downward-compatible with Windows 3.1, so there is no loss of amenity there.)

Here is a sample hook procedure, and the code that installs and removes it.

VxD_LOCKED_DATA_SEG
pPrevHook dd 0
VxD_LOCKED_DATA_ENDS

BeginProc MyHook, HOOK_PROC, pPrevHook, LOCKED

    pushfd                  ; Remember, hooks must preserve all regs
    pushad                  ;
    Trace_Out  "An MS-DOS app is starting"
    popad
    popfd
    jmp        [pPrevHook]  ; Chain to previous hook

EndProc MyHook

    ...
    ; Install the hook to watch for MS-DOS apps starting
    mov      esi, offset32 MyHook
    GetVxDServiceOrdinal eax, DOSMGR_Begin_V86_App
    VMMCall  Hook_Device_Service
    jc       Error
IFDEF    WIN31COMPAT
    mov  pPrevHook, esi    ; Windows 3.1 requires this
                           ; Optional in Windows 95 provided
                           ; MyHook is a HOOK_PROC
ENDIF

    ...
    ; Remove the hook that watches for MS-DOS apps starting
    mov      esi, offset32 MyHook
    GetVxDServiceOrdinal eax, DOSMGR_Begin_V86_App
    VMMCall  Unhook_Device_Service
    jc       Error

Observe that the value returned in ESI need not be stored into pPrevHook under Windows 95; the VMM automatically does this. (This also closes race conditions that occur if you hook an asynchronous service and a hardware interrupt arrives before you can save the answer.) Moreover, you should never attempt to modify the value in pPrevHook yourself; VMM assumes that it is the only code which will modify the value, because it uses that value to walk the hook chain. Furthermore, you must never attempt to 'unhook' the service by passing pPrevHook as the ESI to a Hook_Device_Service or Hook_XX_Fault call, for that too will mess up the bookkeeping.

For fault hooks, there is another twist. If there was no previous fault hook, zero is returned in ESI, for compatibility with Windows 3.1, but the address of the system default fault handler is returned in pPrevHook anyway. This allows you to pass a fault through instead of being forced to handle it. Sample code to install the hook procedure would then look like

    mov      esi, offset32 MyHook
    mov      eax, 6            ; Invalid opcode fault
    VMMCall  Hook_VMM_Fault
    jc       Error
IFDEF    WIN31COMPAT
    mov      pPrevHook, esi    ; DO NOT DO THIS FOR WINDOWS 95
ENDIF

The hook itself would look like this

BeginProc MyHook, HOOK_PROC, pPrevHook, LOCKED

    pushfd                    ; Remember, hooks must preserve all regs
    pushad                    ;
    Trace_Out  "An invalid opcode fault"
    popad
IFDEF  WIN31COMPAT            ; THIS IS NOT NECESSARY FOR WINDOWS 95
    cmp        [pPrevHook], 0 ; Was there a previous hook
    jnz        @F             ; Yes, chain to it
    popfd                     ; No, just return (nothing better to do)
    retd
@@:
ENDIF
    popfd
    jmp    [pPrevHook]        ; Chain to previous hook

EndProc MyHook

Observe how the Windows 95 hook mechanism removes the need to alter behavior depending on whether there was a previous fault handler.


Tips and Traps

This section describes common problems that VxD writers encounter and suggests ways to avoid them.


Tips

Tip
To avoid canceling a timeout after it has been dispatched, ensure that the timeout callback procedure immediately set the variable that holds the timeout handle to zero.
Tip
To avoid canceling a timeout twice by mistake, use the following method:
    xor     esi, esi
    xchg    [hTimeOut], esi
    VMMCall Cancel_Time_Out

If this code is executed twice by mistake, the second time will not cause any harm. Note, however, that there is still an opportunity for a race condition to occur between the xchg instruction and the call to the Cancel_Time_Out service. To be extra sure that you don't cancel the wrong timeout by mistake, put the routine in locked code. If the timeout being cancelled is an asynchronous timeout, you also need to disable interrupts.

Tip
To enumerate all of the threads in the System VM, you can't just call Get_Initial_Thread_Handle to retrieve the System VM (or Get_Sys_Thread_Handle), and then call Get_Next_Thread_Handle until you retrieve the handle of a VM whose parent is not the System VM (or until you get back where you started). The reason is that the initial thread handle happens to be the last thread in the list, so the next time you call Get_Next_Thread_Handle, you will be bumped into the next VM and think the game is over. Instead, call Get_Sys_Thread_Handle, and then call Get_Next_Thread_Handle repeatedly until you get back to the system thread handle. For each thread along the way, skip it if the parent VM is not the System VM.


Traps

The following are all real problems that were encountered by virtual device developers:

Trap
Forgetting to zero-initialize the thread data slot. Remember that thread data slots are not zero-initialized. When one is allocated, you have to go through every thread in the system and initialize each one.
Trap
Forgetting to free memory associated with a thread data slot when a thread terminates. When a thread terminates, don't forget to free the contents of the thread data slot while you still can; otherwise, the memory will be leaked.
Trap
Scheduling too many events. The VMM has only a limited amount of space to record events. The space does not grow until the next time the VMM processes events with the critical section free. Scheduling thousands of events in rapid succession will crash the machine. Coalesce duplicate events to reduce the demand on the event heap.
Trap
Allocating too many list elements. As with events, the VMM has a limited amount of space for allocating list elements (unless the list uses the heap, in which case list elements come from the heap and this remark does not apply). Also, as with events, the space for list elements grows only the next time the VMM processes events with the critical section free. Allocating thousands of list elements in rapid succession will crash the machine. If you need thousands of list elements, you should reconsider your data structure.
Trap
Forgetting to pass a priority value in the EAX register to Call_Restricted_Event or Call_Priority_VM_Event. The result is that the thread or virtual machine gets boosted by a random amount, and the system seems to freeze for extended periods of time. (The debugging version of Windows 95 reports this problem.)
Trap
Calling the registry at unrestricted event time. Unless you set the PEF_WAIT_NOT_NEST_EXEC restriction when scheduling the event, it is possible that the event may be dispatched on a thread that is already in the registry. This deadlocks the system. (The debugging version of Windows 95 reports this problem.)
Trap
Leaving events outstanding when you unload. Dynamically-loaded device drivers must remove all hooks and cancel all events, timeouts, and callbacks before they unload. Otherwise, the hook, event, timeout, or callback causes a jump to an invalid location when the appropriate condition is met. If you need to leave a hook or callback in place (for example, because the unhook failed, or there is no way to cancel the callback), put the hook or callback in a static code segment so that it remains loaded even after your VxD unloads. Of course, the stub in the static code segment shouldn't do anything unless the rest of the VxD is already loaded. (The debugging version of Windows 95 reports many cases of this problem, but not all of them.)
Trap
Looping without blocking. Remember that going into a Resume_Exec loop does not actually block the current thread; it merely processes events. If the current thread is the highest-priority thread, nothing happens until the loop ends. For additional discussion of this problem, see Events.
Trap
Assuming registers don't change across a call. This typically happens when calling a service whose name begins with an underscore (which in most cases indicates that the service uses the C calling and register convention) and assuming that the EAX, ECX, or EDX registers are be preserved across the call. (The debugging version of Windows 95 often intentionally modifies those registers in an attempt to catch code that relies on this non-feature.)
Trap
Assuming stack parameters don't change across a call. The C calling convention permits the called function to modify the input parameters, so don't rely on their values being preserved across a call. The following example is wrong:
push    0              ; flags
push    nPages         ; number of pages to lock
push    page           ; first page to lock
VMMCall _LinPageLock   ; Lock them
; do stuff
VMMCall _LinPageUnlock ; Unlock them
add     esp, 12

The LinPageLock service is allowed to damage the top three double-words on the stack, resulting in garbage being passed to LinPageUnlock. (The debugging version of Windows 95 often intentionally modifies input parameters, in an attempt to catch code that relies on this non-feature.)

Trap
Confusing VMSTAT_PM_Exec with VMSTAT_PM_Use32Mask. When deciding whether to use 16-bit or 32-bit offsets from the client, the rule is that you should use a 32-bit offset if the VMSTAT_PM_Exec bit is set, and if one of the VMSTAT_PM_Use32Mask bits is set. If a VxD checks only the VMSTAT_PM_Use32Mask bits, it may end up using 32-bit offsets even though the virtual machine is not in protected mode.
Trap
Leaving files open. If a virtual device opens files, it should close them before giving control back to the virtual machine. Since open files are tracked on a per-VM and per-PSP basis, the application on which you opened the file might create another file or might exit, causing the PSP to change, at which point the file handle becomes invalid. Also, having files open causes the virtual IFS Manager device to have problems when it attempts to transition to the protected-mode file system.
Trap
Changing the DS or ES selectors. The CS, DS, ES, and SS selectors must remain as flat selectors at all times. Do not load any other values into those registers, even temporarily. Doing so will crash the system.
Trap
Setting the direction flag. The direction flag must remain clear (up) whenever control passes to the VMM or another virtual device. You can set the direction flag to the 'down' state, but you must clear the flag before yielding control. (The debugging version of Windows 95 attempts to catch this error.)
Trap
Canceling events the wrong way. If an event is scheduled as a VM Event, it must be cancelled with the Cancel_VM_Event service. Similarly, global events must be cancelled with Cancel_Global_Event, thread events must be cancelled with Cancel_Thread_Event, and restricted events must be cancelled with Cancel_Restricted_Events. Failing to observe these rules results in corrupted memory. (The debugging version of Windows 95 attempts to catch this error.)
Trap
Race conditions between timeouts, events, and hardware interrupts. VxD's often initiate an operation and then schedule a timeout that cancels the operation if it takes too long. A race condition can occur if the timeout is dispatched just as the operation completes. This is particularly true if the user is running high-speed communications software at the same time, because communication interrupts will be streaming in, causing the VxD to schedule and cancel many timeouts. If the VxD cancels a timeout after it has been dispatched, and the system has already recycled the handle and given it to another VxD, . the first VxD would end up canceling the other VxD's timeout by mistake.
Trap
Assuming that MapPhysToLinear(N, 1, 0) = MapPhysToLinear(0, 1, 0) + N. This was never guaranteed, but it happened to be true under Windows 3.1 by accident. This is not true under Windows 95.
Trap
Passing the wrong number of arguments to a service. This happens most often with the HeapFree service because the VxD writer forgets that there is a second parameter of flags (which must be zero). In general, VxD writers tend to forget to pass flags to services that accept a bitmask of flags as the last parameter. This results in the service picking up stack garbage as the flags parameter. (The debugging version of Windows 95 attempts to catch this error.)
Trap
Assuming that the high word is always zero. Many VxDs that interface to DLLs at ring 3 pass a function code in the AX register to the VxD's protected-mode entry point, but the VxD looks at the entire EAX register to parse the function code. This code tended to work by accident under Windows 3.1 because the high words of extended registers were usually zero. This is no longer true under Windows 95.
Trap
Forgetting to disable interrupts when hooking an asynchronous service. Remember that asynchronous services can be called at hardware interrupt time. If a hardware interrupt occurs after a hook is installed, but before the pointer is saved in a place where the hook procedure can get to it, the interrupt can result in a call to the service before the hook is ready.
Trap
Using Begin_Nest_Exec inappropriately. Any protected-mode procedure called from a nested execution block must be in a nondiscardable segment, must access only data in nondiscardable segments, and may not switch to a 32-bit stack. (This means, in particular, that only interrupt-safe Windows functions can be called, because anything else might thunk to Win32.) Although these restrictions existed in Windows 3.1 as well, Windows 3.1 almost never spent any time on a 32-bit stack, unless a WINMEM32 or Win32s application was running. But now that Windows 95 has Win32 support built-in, the system spends a large percentage of its time on a 32-bit stack, so the window of opportunity for error is much greater. If you need to call functions that do not respect these restrictions, use an application time event, coupled with the _SHELL_CallDll service, passing lpszDll = 0 and lpszProcName equal to the 16:16 address.

Trap

Doing invalid things at hardware interrupt time.

Inside a hardware interrupt, you are restricted to the following operations:

  • Accessing locked code.
  • Accessing locked data.
  • Calling VMM event services.
  • Calling other VMM and VxD services which are documented as "asynchronous services".

A very common error is to violate the third rule and call a service that was not designed to be called during a hardware interrupt.

Trap

Doing invalid things at hardware interrupt time.

Inside a hardware interrupt, you are restricted to the following operations:

  • Accessing locked code.
  • Accessing locked data.
  • Calling VMM event services.
  • Calling other VMM and VxD services which are documented as "asynchronous services".


Breakpoints and Callbacks

Breakpoints and callbacks provide a mechanism for transferring control from ring 3 to ring 0 in a controlled manner.

Callbacks are typically given by VxDs to applications so that the application can call back into the VxD as part of a service request. The application performs a far call indirect to the callback address. VMM will perform a Simulate_Far_Return before dispatching the callback to the VxD that installed it. The VxD typically inspects and/or modifies client registers, then returns. Execution then resumes in the application at the instruction following the "call far".

Breakpoints are typically installed by a VxD into existing V86-mode code that needs to be patched. When execution reaches the breakpoint, VMM dispatches the breakpoint directly to the VxD that installed it. The VxD typically inspects and/or modifies client registers, then moves the client (E)IP register past the breakpoint so as to resume execution. Note that, unlike callbacks, it is the VxD's responsibility to adjust the client (E)IP register to point to the location where execution should resume when servicing of the breakpoint is complete. If you forget to do this, the breakpoint will merely be hit again immediately.

Since there are no facilities for freeing breakpoints or callbacks, they should be treated as scarce resources. Dynamically-loaded VxDs which allocate callbacks should save the callback in a static data segment so a new callback is not allocated each time the VxD is loaded.

Note Breakpoints are supported only for V86-mode code. Moreover, protected-mode callbacks are not supported from a Win32 application. If a Win32 application needs to communicate with a VxD, it must use the DeviceIoControl mechanism.

There are the following break point and callback services:

Service | Description
Allocate_V86_Call_Back | Allocates a V86-mode callback.
Allocate_PM_Call_Back | Allocates a protected-mode callback.
Call_When_VM_Returns | Installs a return-from-interrupt callback.
Install_V86_Break_Point | Installs a breakpoint callback.
Remove_V86_Break_Point | Removes a V86 breakpoint.


Allocate_PM_Call_Back

include vmm.inc

mov     edx, RefData            ; reference data (any doubleword)
mov     esi, OFFSET32 Callback  ; callback function to call
VMMCall Allocate_PM_Call_Back

jc      error
mov     [CallbackAddr], eax     ; selector:offset for callback

Registers a callback function that 16-bit protected-mode applications can call. Virtual devices use this service to provide an interface that is available to device drivers and applications in a VM. Uses EAX, Flags.

Returns with the carry flag clear if successful, or set otherwise. If successful, the EAX register contains a selector:offset address that can be called (far call) from within a protected-mode VM. Note that the selector:offset is not callable from a Win32 program. A Win32 program must use the DeviceIoControl function to communicate with a VxD.

RefData
Reference data to be passed to the callback procedure. Can be any 32-bit value, but is typically the address of a driver-defined structure.
Callback
Address of the callback procedure. For more information about the callback procedure, see below.

The system calls the callback procedure as follows:

mov     ebx, VM             ; current VM handle
mov     edi, hCurThread     ; current thread handle
mov     edx, RefData        ; reference data
mov     ebp, OFFSET32 crs   ; points to Client_Reg_Struc
call    [Callback]

The VM parameter is a handle identifying the current virtual machine. The RefData parameter is the value supplied when the callback procedure was installed, and crs points to a Client_Reg_Struc structure containing the register values for the virtual machine at the time it called the PM callback address. The callback may read and modify the client registers; any changes made will be seen by the calling application when control returns to it.

See Also

Allocate_V86_Call_Back


Allocate_V86_Call_Back

include vmm.inc

mov     edx, RefData            ; reference data (any doubleword)
mov     esi, OFFSET32 Callback  ; callback function to call
VMMCall Allocate_V86_Call_Back

jc      error
mov     [CallbackAddr], eax     ; segment:offset for callback

Registers a callback function that V86 mode applications can call. Virtual devices use this service to provide an interface that is available to software in a VM. Uses EAX, Flags.

Returns with the carry flag clear if successful, or set otherwise. If successful, the EAX register contains a segment:offset address that can be called (far call) from within a V86-mode VM.

RefData
Reference data to be passed to the callback procedure. Can be any 32-bit value, but is typically the address of a driver-defined structure.
Callback
Address of the callback procedure. For more information about the callback procedure, see below.

The system calls the callback procedure as follows:

mov     ebx, VM             ; current VM handle
mov     edi, hCurThread     ; current thread handle
mov     edx, RefData        ; reference data
mov     ebp, OFFSET32 crs   ; points to Client_Reg_Struc
call    [Callback]

The VM parameter is a handle identifying the current virtual machine. The RefData parameter is the value supplied when the callback procedure was installed, and crs points to a Client_Reg_Struc structure containing the register values for the virtual machine.

See Also

Allocate_PM_Call_Back


Call_When_VM_Returns

include vmm.inc

mov     eax, TimeOut            ; milliseconds until time out
mov     edx, RefData            ; reference data
mov     esi, OFFSET32 Callback  ; address of callback function
VMMCall Call_When_VM_Returns

Installs a callback function that receives control when a virtual machine executes the iret instruction for the current interrupt. Uses Client_CS, Client_EIP, Flags.

No return value.

TimeOut
Number of milliseconds to wait before calling the callback procedure. The time out occurs only if the iret instruction is not executed before the specified time elapses. If this parameter is positive, the system calls the callback when time elapses. If this parameter is negative, the system calls the callback when time elapses and calls it again when the iret instruction is executed. If this parameter is zero, the system ignores the time out.
RefData
Reference data to be passed to the callback procedure. Can be any 32-bit value, but is typically the address of a driver-defined structure.
Callback
Address of the callback procedure. For more information about the callback procedure, see below.

A virtual device typically uses this service in a callback procedure that it installed using the Hook_V86_Int_Chain service. This service directs the system to replace the return address for the interrupt with the address of the callback procedure. That is, the system pushes the callback procedure address on the stack when it creates the stack frame for the interrupt. The system then passes the interrupt to the virtual machine.

When the virtual machine executes the iret instruction, the callback procedure receives control and can carry out tasks. After the callback procedure returns, the system restores the original interrupt return address and execution continues as if returning from the interrupt.


Note

The preceding description implies that the only meaningful place to use Call_When_VM_Returns is when a Simulate_Far_Call or Build_Int_Stack_Frame is going to happen soon. (As noted, this is typically done inside the callback installed by Hook_V86_Int_Chain.) In particular, in order to hook the back end of a simulated interrupt, you must call Call_When_VM_Returns before the interrupt itself is simulated. If the interrupt or far call has already been simulated, Call_When_VM_Returns will not do what you want. (The name of the service is rather unfortunate. It really means "Call when the VM returns to where it is now", and not "Call when the VM executes a return instruction".)

The system calls this callback procedure as follows:

mov     ebx, VM             ; current VM handle
mov     edi, hCurThread     ; current thread handle
mov     edx, RefData        ; reference data
mov     ebp, OFFSET32 crs   ; points to a Client_Reg_Struc
call    [Callback]

The VM parameter is a handle identifying the current virtual machine. The RefData parameter is the value supplied when the callback procedure was installed, and the crs parameter points to a Client_Reg_Struc structure containing the register values for the virtual machine.

If the system calls the callback procedure as a result of a time out, it sets the carry flag before calling the procedure. If the system calls the callback a second time (once for a time out and once for the iret instruction), the system sets the zero flag before calling the procedure a second time. The value of the zero flag is indeterminate unless the TimeOut parameter specifies a negative value.

In other words,

  • If you passed TimeOut = 0, then the callback is called when the VM returns and at no other time.
  • If you passed TimeOut > 0, then the callback should begin like this:
    jc      timed_out;  Timeout notification
                 ;  Otherwise, the VM returned
                 ;  before the timeout expired
  • If you passed TimeOut < 0, then the callback should begin like this:
    jc      timed_out    ;  Timeout notification
                     ;  Otherwise, the VM returned
jnz         normal_return;  VM returned with no timeout
                     ; Else, VM returned with timeout

See Also

Hook_V86_Int_Chain


Install_V86_Break_Point

include vmm.inc

mov     eax, BreakAddr           ; break point address
mov     edx, RefData             ; reference data
mov     esi, OFFSET32 Callback   ; address of callback procedure
VMMCall Install_V86_Break_Point

jc      not_installed

Inserts a break point in V86 memory of the current virtual machine, and installs a break-point callback procedure to receive control when the break point occurs. A virtual device, such as the virtual MS-DOS manager, can use this service to place patches in the BIOS. Uses Flags.

Returns with the carry flag clear if successful, or set otherwise.

BreakAddr
Specifies the V86 address to place the break point. The address must be specified as a segment:offset pair, and must specify RAM. Once installed, the break point must not be moved.
RefData
Reference data to be passed to the callback procedure. Can be any 32-bit value, but is typically the address of a driver-defined structure.
Callback
Address of the callback procedure. For more information about the callback procedure, see below.

Virtual devices typically place V86 break points in global virtual device memory during device initialization. For example, the XMS driver in the virtual V86MMGR device inserts a breakpoint in the real-mode XMS driver during device initialization. Thereafter, all calls to the real-mode XMS driver are intercepted by the virtual XMS driver.

The segment address specified when installing a V86 break point must be the segment address in the CS register when the virtual machine executes the break point. For example, if the break point is placed at 0100:0000 but the virtual machine executes the break point at the address 00FF:0010h, an error occurs even though the virtual machine executed a valid break point.

When the virtual machine executes the break point, the system calls the callback procedure as follows:

mov     eax, BreakAddr          ; address of breakpoint
mov     ebx, VM                 ; current VM handle
mov     edx, OFFSET32 RefData   ; reference data
mov     esi, BreakLinAddr       ; linear address of break point
mov     ebp, OFFSET32 crs       ; points to a Client_Reg_Struc

The BreakAddr parameter is the V86 address of the break point. The VM parameter is a handle identifying the current virtual machine and the RefData parameter is the value specified when the callback procedure was installed. The BreakLinAddr parameter specified the linear address of the break point and the crs parameter points to a Client_Reg_Struc structure containing the register values for the specified virtual machine.

The Client_CS and Client_IP registers contain the address of the break point. The virtual device must change these registers to prevent the break point from being executed again when the virtual machine resumes. A virtual device can change the register by simulating the instruction that was patched, incrementing the Client_IP register past the patch, jumping to another address using the Simulate_Far_Jmp service, or returning from an interrupt handler using the Simulate_Iret service.

When the virtual device receives the System_Exit message, it must remove any break point that it placed in global V86 code, that is, code loaded before Windows was loaded. The virtual device can remove a V86 break point using the Remove_V86_Break_Point service.

See Also

Remove_V86_Break_Point


Remove_V86_Break_Point

include vmm.inc

mov     eax, BreakAddr        ; V86 address of break point
VMMCall Remove_V86_Break_Point

Removes a V86 break point that was installed using the Install_V86_Break_Point service. It restores the original contents of the memory automatically. Uses Flags.

Returns with the carry flag clear if successful, set otherwise.

BreakAddr
Address of the break point to remove. The address must be a segment:offset pair.

In Windows 95, removing a breakpoint does not free the resources associated with it. Thus, repeatedly installing and removing the same breakpoint will slowly leak resources.

See Also

Install_V86_Break_Point


Debugging

There are the following debugging services:

Service | Description
_Assert_Range | Validates a pointer to any structure
Clear_Mono_Screen | Clears the secondary display.
Debug_Convert_Hex_Binary | Converts hexadecimal to binary.
Debug_Convert_Hex_Decimal | Converts a number to decimal.
_Debug_Flags_Service | Asserts various conditions.
_Debug_Out_Service | (Windows 95 and later) Sends a null-terminated ASCII string to the debugging device and stops the debugger if one is running.
_Debug_Printf_Service | (Windows 95 and later) Prints a C-style formatted string to the debugging device.
Debug_Test_Cur_VM | Asserts that EBX is the current VM handle.
Debug_Test_Valid_Handle | Asserts that EBX is a valid VM handle.
Disable_Touch_1st_Meg | Disables the first megabyte of memory.
Enable_Touch_1st_Meg | Enables the first megabyte of memory.
Get_Debug_Options | Checks for command-line debugging options.
Get_Mono_Chr | Gets the character/attribute from the secondary display.
Get_Mono_Cur_Pos | Gets the cursor position from the secondary display.
In_Debug_Chr | Reads one character from the debugging device.
Is_Debug_Chr | Checks if a character is ready on the debugging device.
Log_Proc_Call | Logs the caller of the current procedure.
Out_Debug_Chr | Writes one character to the debugging device.
Out_Debug_String | (Windows 3.1x) Writes a string to the debugging device with optional embedded parameters.
Out_Mono_Chr | Writes one character to the secondary display.
Out_Mono_String | Writes a string to the secondary display.
Queue_Debug_String | Queues a debugging string.
Set_Mono_Cur_Pos | Sets the cursor position for the secondary display.
Test_Reenter | Asserts that VMM has not been re-entered.
_Trace_Out_Service | (Windows 95 and later) Writes a null-terminated ASCII string to the debugging device.
Validate_Client_Ptr | Validates the client register pointer.


_Assert_Range

#include vmm.h

_Assert_Range(DWORD pStruc, DWORD ulSize, DWORD sSignature,
              DWORD lSignatureOffset, DWORD ulFlags);

Verifies that a pointer to any structure is valid. Uses the C calling convention.

Returns nonzero in the EAX register if the structure is valid; otherwise, returns zero.

pStruc
Structure pointer to validate.
ulSize
Size of the structure in bytes.
sSignature
A DWORD value to validate.
lSignatureOffset
Offset in bytes to sSignature.
ulFlags
Validation flags. May be one or more of these values:
ASSERT_RANGE_NULL_BAD | Return failure for NULL pointers. May not be combined with ASSERT_RANGE_NULL_OK.
ASSERT_RANGE_NULL_OK | Return success for NULL pointers. May not be combined with ASSERT_RANGE_NULL_BAD.
ASSERT_RANGE_NO_DEBUG | Do not output a debugging message on failure when debugger is present. This flag is ignored if no debugger is installed.

The following validation steps are taken

  1. If pStruc is a null pointer, its validity is determined by which of the ASSERT_RANGE_NULL_BAD or ASSERT_RANGE_NULL_OK flags is passed.
  2. Otherwise, pStruc must be a pointer to valid data of length ulSize bytes.
  3. Furthermore, if sSignature is nonzero, then the DWORD at pStruc + lSignatureOffset must be equal to sSignature.

For example, suppose you have a structure defined as follows:

struct ABC {
    DWORD member1;
    BYTE  member2[20];
    DWORD dwSignature;
};

// Every valid ABC has ABCSIGNATURE stored in the dwSignature field.

#define ABCSIGNATURE 0x31415926

If you want to check whether some pointer variable p is a valid pointer to a ABC, except that null pointers are okay, then you would write

if (!_Assert_Range(p, sizeof(SAMPLE), ABCSIGNATURE,
    offsetof( SAMPLE, dwSignature), ASSERT_RANGE_NULL_OK)) {
       return ERROR_INVALID_PARAMETER;
    }

This service can be called only at a time when page faults can safely be handled. It cannot be called at hardware interrupt time, nor at any other time when paging is not allowed. Since this service touches the memory at pStruc as part of the validation (even if sSignature is zero), if pStruc points to a phys/linear region owned by memory-mapped hardware, there may be unusual side-effects.


Clear_Mono_Screen

include vmm.inc

VMMCall Clear_Mono_Screen

Clears the secondary display screen by filling it with spaces, and setting character attributes to normal. Uses Flags.

No return value.

This service has no effect in the retail version of Windows. It is intended to be used with the debugging version.

See Also

Out_Mono_Chr


Debug_Convert_Hex_Binary

include vmm.inc

mov     al, Number              ; number to convert
VMMCall Debug_Convert_Hex_Binary

mov     [BinNum], eax           ; binary number

Converts an 8-bit value to a 32-bit value representing a binary number. The new value consists of eight 4-bit values, each of which is either 0 or 1. Uses EAX.

  • Returns the converted number in the EAX register.
Number
Value to convert.

This service is typically used in conjunction with the Trace_Out macro to display values in binary notation.

The following example prints, "The converted value is 01011001".

mov     al, 01011001b
VMMCall Debug_Convert_Hex_Binary
Trace_Out 'Converted value is #EAX'

See Also

Debug_Convert_Hex_Decimal, Trace_Out


Debug_Convert_Hex_Decimal

include vmm.inc

mov     eax, Number              ; number to convert
VMMCall Debug_Convert_Hex_Decimal

mov     [BinNum], eax           ; binary number

Converts an 8-bit value to a 32-bit value representing a decimal number. The new value consists of eight 4-bit values, each in the range 0 through 9. Uses EAX.

  • Returns the converted number in the EAX register.
Number
Specifies the number to convert.

This service is typically used in conjunction with the Trace_Out macro to display values in decimal notation.

The following example prints, "The converted value is 00003141".

mov     eax, 3141
VMMCall Debug_Convert_Hex_Decimal
Trace_Out 'Converted value is #EAX'

See Also

Debug_Convert_Hex_Binary, Trace_Out


_Debug_Flags_Service

include vmm.inc

push    flags
VMMCall _Debug_Out_Service

Asserts various conditions. This is an asynchronous service.

No return value.

flags
Specifies the debug flags. It can be a combination of the following values:
Value | Meaning
DFS_NEVER_REENTER | VMM has not been re-entered (see below).
DFS_TEST_REENTER | VMM has not been re-entered (see below).
DFS_NOT_SWAPPING | The current thread is not in the middle of a paging operation.
DFS_TEST_CLD | Assert that the processor direction flag is cleared.
DFS_TEST_BLOCK | Assert that NoBlock_Count is set to zero.
DFS_LOG | Log this procedure (if requested).
DFS_PROFILE | Increment profile count and validate the segment registers.
DFS_ENTER_NOBLOCK | Increment the NoBlock_Count.
DFS_EXIT_NOBLOCK | Decrement the NoBlock_Count.

The DFS_NEVER_REENTER and DFS_TEST_REENTER bits differ in their interaction with the Begin_Reentrant_Execution service. When the Begin_Reentrant_Execution service is called, the VMM re-entry count is reset to zero, even though the VMM has mostly like actually been re-entered. The DFS_TEST_REENTER bit checks this fake re-entry count, whereas the DFS_NEVER_REENTER bit checks the true re-entry count (which is unaffected by Begin_Reentrant_Execution).

The DFS_ENTER_NOBLOCK and DFS_EXIT_NOBLOCK flags increment and decrement a counter which is checked by the DFS_TEST_BLOCK bit. If the DFS_TEST_BLOCK bit is set when this internal counter is nonzero, the debugger will be notified if it is installed.

The DFS_LOG bit calls the Log_Proc_Call service on behalf of the caller.

The DFS_PROFILE bit causes the service to increment a DWORD variable generated by the BeginProc macro. Do not set this bit manually; let the BeginProc macro do it for you.

This service has no effect in the retail version of Windows. It is intended to be used with the debugging version.

As a rule, you should never call this service directly. It is generated automatically by macros in vmm.h and debug.h.

The BeginProc macro automatically calls this service with the DFS_LOG bit, as well as the DFS_TEST_REENTER if the procedure being declared is not an asynchronous service, and the DFS_TEST_BLOCK flag if the procedure is in pageable code. In the case of an exported service, the BeginProc macro also generates a DWORD profiling count and sets the DFS_PROFILE bit.

The ENTER_NOBLOCK, EXIT_NOBLOCK, and ASSERT_MIGHT_BLOCK macros in debug.h should be used to manipulate the block-related DFS bits.


_Debug_Out_Service

include vmm.inc

push    OFFSET32 String
VMMCall _Debug_Out_Service

(Windows 95 and later) Sends a null-terminated ASCII string to the debugging device and stops the debugger if one is running. This is an asynchronous service.

No return value.

String
String to display for debugging purposes.

See the documentation of the Out_Debug_String service for a list of supported placeholders. The Debug_Out_Service will do the requisite pushfd and pushad operations.

This service preserves all registers and flags.

You should not call this service directly. Use the Debug_Out macro instead.

This service has no effect in the retail version of Windows. It is intended to be used with the debugging version.


_Debug_Printf_Service

include vmm.inc

push    pArgs
push    pFormat
VMMCall _Debug_Printf_Service
add     esp, 8

(Windows 95 and later) Prints debug output. This is an asynchronous service. Uses the C calling convention.

No return value.

pFormat
C-style "printf" format string.
pArgs
Address of the array of substitution arguments.

The %-escapes understood by _Debug_Printf_Service are the same ones supported by wdeb386. (_Debug_Printf_Service merely calls the debugger to display the string.)

The total size of the output cannot exceed 256 bytes.

pArgs is a pointer to the substitution arguments, rather than being the first substitution itself. This service would more accurately have been named _Debug_Vprintf_Service.

This service has no effect in the retail version of Windows. It is intended to be used with the debugging version.


Debug_Test_Cur_VM

include vmm.inc

mov     ebx, VM         ; VM handle to check
VMMCall Debug_Test_Cur_VM

Asserts that the specified virtual machine is also the current virtual machine. The service crashes the current virtual machine if the VM parameter does not identify the current virtual machine handle. This is an asynchronous service.

No return value. This service does not return if the handle is not valid.

VM
Handle of the virtual machine to check.

Do not call this service directly. Use the Assert_Cur_VM_Handle macro instead.

This service has no effect in the retail version of Windows. It is intended to be used with the debugging version.

See Also

Crash_Cur_VM


Debug_Test_Valid_Handle

include vmm.inc

mov     ebx, VM       ; VM handle to validate
VMMCall Debug_Test_Valid_Handle

Determines whether the specified virtual machine handle is valid. This is an asynchronous service.

No return value. This service does not return if the handle is not valid.

VM
Specifies the virtual machine handle to check.

Do not call this service directly. Use the Assert_VM_Handle macro instead.

This service has no effect in the retail version of Windows. It is intended to be used with the debugging version.

See Also

Assert_VM_Handle


Disable_Touch_1st_Meg

include vmm.inc

VMMCall Disable_Touch_1st_Meg

Disables the first 1 megabyte of memory for the current virtual machine. This is an asynchronous service.

No return value.

See the description of Enable_Touch_1st_Meg for more information.

Do not call this service directly. Use the End_Touch_1st_Meg macro instead.

This service has no effect in the retail version of Windows. It is intended to be used with the debugging version.

See Also

Enable_Touch_1st_Meg


Enable_Touch_1st_Meg

include vmm.inc

VMMCall Enable_Touch_1st_Meg

Enables the first 1 megabyte of memory for the current virtual machine. The service sets the present bit for the first page directory allowing a virtual device to access addresses in the range. This is an asynchronous service.

No return value.

In the debugging version of Windows, VxDs are normally not permitted to access memory below the 1MB boundary, so as to help catch null pointer errors. If you need to access memory below the 1MB boundary, you should normally access it at the high linear address instead. However, in the rare cases where you need to access to memory at its low linear address, this service temporarily grants access to the first megabyte of memory. You should then re-disable the first megabyte of memory when you are finished, as demonstrated in the following example:

    Begin_Touch_1st_Meg
    mov eax, ds:[40h]           ; get int 10h vector
    End_Touch_1st_Meg

(Note that this is not the recommended way of getting a VM's interrupt vector. The proper way is to use the Get_Instanced_V86_Int_Vector service.)

Do not call this service directly. Use the Begin_Touch_1st_Meg macro instead.

This service has no effect in the retail version of Windows. It is intended to be used with the debugging version.

See Also

Begin_Touch_1st_Meg, Disable_Touch_1st_Meg


Get_Debug_Options

include vmm.inc

mov     al, Char            ; debugging option
VMMCall Get_Debug_Options

Determines whether the given character was specified as a command-line debugging option when Windows was started. Uses Flags.

Returns with the zero flag set if the character was specified as a debugging option, clear otherwise.

Char
Debugging option to check for.

This service is available only during initialization. This service has no effect in the retail version of Windows. It is intended to be used with the debugging version.

See Also

Test_Debug_Installed


Get_Mono_Chr

include vmm.inc

VMMCall Get_Mono_Chr
mov     byte ptr [Char], al         ; character value
mov     byte ptr [Attr], ah         ; character attribute

Retrieves the character and attribute value at the current cursor position. Uses EAX, Flags.

Returns with the character in the AL register and the attribute in the AH register.

This service has no effect in the retail version of Windows. It is intended to be used with the debugging version.

See Also

Out_Mono_Chr, Set_Mono_Cur_Pos


Get_Mono_Cur_Pos

include vmm.inc

VMMCall Get_Mono_Cur_Pos
mov     byte ptr [Column], dl         ; current column position
mov     byte ptr [Row], dh            ; current row position

Retrieves the current cursor position for the secondary display. Uses flags.

Returns with the column in the DL register, and the row in the AH register.

This service has no effect in the retail version of Windows. It is intended to be used with the debugging version.

See Also

Set_Mono_Cur_Pos


In_Debug_Chr

include vmm.inc

VMMCall In_Debug_Chr
mov     byte ptr [Char], al     ; character from debug device

Reads a character from the debugging device. Uses EAX.

Returns with the character read in the AL register. If the ESCAPE key or CTRL+C key combination was pressed, the service sets the zero flag.

This service has no effect in the retail version of Windows. It is intended to be used with the debugging version.

See Also

Is_Debug_Chr


Is_Debug_Chr

include vmm.inc

VMMCall Is_Debug_Chr
jz      no_character            ; zero flag set if no character available

mov     byte ptr [Char], al     ; character from debugging device

Checks for a character from the debugging device. Uses EAX, Flags.

Returns with the zero flag clear if a character is available, set otherwise. If a character is available, it is returned in the AL register.

This service has no effect in the retail version of Windows. It is intended to be used with the debugging version.

See Also

In_Debug_Chr


Log_Proc_Call

include vmm.inc

VMMCall Log_Proc_Call

Creates a debugging message that identifies which service or virtual device called the service that called Log_Proc_Call. This service is intended to be used only for debugging, and it creates the message only if the user has turned on call logging. This is an asynchronous service.

No return value.

When the BeginProc macro creates a new service, the macro generates a call to Log_Proc_Call if the DEBUG symbol is defined and the NO_LOG attribute is not specified as a parameter to BeginProc.

The service adds the message to the debugging queue using the Queue_Out macro.

Do not call this service directly. Use the BeginProc macro instead.

This service has no effect in the retail version of Windows. It is intended to be used with the debugging version.

See Also

BeginProc, Queue_Out


Out_Debug_Chr

include vmm.inc

mov     al, Char        ; character to write
VMMCall Out_Debug_Chr

Writes a character to the debugging device. Uses EAX.

No return value.

Char
Specifies the character to write to the debugging device.

This service has no effect in the retail version of Windows. It is intended to be used with the debugging version.

See Also

Out_Debug_String


Out_Debug_String

include vmm.inc

pushfd                              ; save flags on stack
pushad                              ; save registers on stack
mov     esi, OFFSET32 String        ; points to string to write
VMMCall Out_Debug_String
popad
popfd

(Windows 3.1x) Writes a null-terminated string to the debugging device (typically the COM1 serial port). If the string contains register placeholders, Out_Debug_String replaces these with the actual register values in hexadecimal, or the symbolic label nearest to the specified addresses. Uses all registers and flags.

No return value.

String
Points to a null-terminated string specifying the message to write to the debugging device. Out_Debug_String uses the lods instruction to process characters in the string, so the DS register must specify the correct segment selector for the string.

The string can contain one or more placeholders having the following forms:
Placeholder | Description
#register | Displays the current value of the specified register. For example, the service replaces #AX with the value of the AX register. The register must not be the name of a segment register.
?register | Displays the label nearest the address specified by the registers. For example, the service replaces ?EAX with the VMM code segment label nearest the address in the EAX register. The register must not be the name of a segment register.
?register:register | Displays the label nearest the address specified by the registers. For example, the service replaces ?AX:EBX with the label in the segment specified by the AX register that is nearest to the address in the EBX register. The register must not be the name of a segment register.

This service has no effect in the retail version of Windows. It is intended to be used with the debugging version.

If the string contains placeholders, Out_Debug_String requires the caller to use the pushfd and pushad instructions before carrying out a near call to this service.

See Also

Trace_Out


Out_Mono_Chr

include vmm.inc

mov     al, Char        ; character to write
VMMCall Out_Mono_Chr

mov     eax, 0          ; write character and attribute
mov     bl, Char        ; character to write
mov     bh, Attr        ; attribute to write
VMMCall Out_Mono_Chr

Writes a character to the current position on the secondary display.

If the EAX register is not zero, the service writes the character in the AL register and applies the normal attribute. Otherwise, it writes the character and attribute pair in the BX register. Uses Flags.

No return value.

Char
Specifies the character to write to the secondary display.
Attr
Specifies the attribute to apply to the character when written.

If the linefeed or carriage return character is written, the service automatically adjusts the cursor position, scrolling the screen if necessary.

This service has no effect in the retail version of Windows. It is intended to be used with the debugging version.

See Also

Out_Mono_String


Out_Mono_String

include vmm.inc

mov     esi, OFFSET32 String        ; points to string to write
VMMCall Out_Mono_String

Writes the specified null-terminated string to the secondary display. If the string contains register placeholders, Out_Mono_String replaces these with the actual register values (in hexadecimal), or the symbolic label nearest to the specified addresses. Uses all registers and flags.

No return value.

String
Points to a null-terminated string specifying the message to write to the debugging device. Out_Mono_String uses the lods instruction to process characters in the string, so the DS register must specify the correct segment selector for the string.

The string can contain one or more placeholders having the following forms:
Placeholder | Description
#register | Displays the current value of the specified register. For example, the service replaces #AX with the value of the AX register. The register must not be the name of a segment register.
?register | Displays the label nearest the address specified by the registers. For example, the service replaces ?EAX with the VMM code segment label nearest the address in the EAX register. The register must not be the name of a segment register.
?register:register | Displays the label nearest the address specified by the registers. For example, the service replaces ?AX:EBX with the label in the segment specified by the AX register that is nearest to the address in the EBX register. The register must not be the name of a segment register.

This service has no effect in the retail version of Windows. It is intended to be used with the debugging version.

See Also

Mono_Out, Out_Debug_String


Queue_Debug_String

include vmm.inc

push    Value1             ; will be used as #EAX or ?EAX
push    Value2             ; will be used as #EBX or ?EBX

Queues a string and corresponding values for display at a later time. The message remains queued until the user enters the .lq command using the debugger. Uses Flags.

No return value.

Value1
Value to queue with the string. If the string contains the #EAX or ?EAX placeholder, this value is used when the string is displayed.
Value2
Value to queue with the string. If the string contains the #EBX or ?EBX placeholder, this value is used when the string is displayed.
String
Address of the null-terminated string to queue. It can contain one or more of the following register placeholders: #AX, #EAX, ?EAX, #BX, #EBX, ?EBX, ?AX:EBX, ?BX:EAX.

Do not call this service directly. Use the Queue_Out macro instead.

This service has no effect in the retail version of Windows. It is intended to be used with the debugging version.

See Also

Out_Debug_String


Set_Mono_Cur_Pos

include vmm.inc

mov     dl, Column      ; current column position
mov     dh, Row         ; current row position
VMMCall Set_Mono_Cur_Pos

Sets the current cursor position for the secondary display. Uses Flags.

No return value.

Column
Column position.
Row
Row position.

This service has no effect in the retail version of Windows. It is intended to be used with the debugging version.

See Also

Get_Mono_Cur_Pos


Test_Reenter

include vmm.inc

VMMCall Test_Reenter

Checks the re-entry count for the VMM and values of the DS, ES, and SS registers. This is an asynchronous service.

No return value.

If the re-entry count is not zero or the segment registers are not equal to the VMM data segment selector, the service displays an error message at the debugging terminal. This service is intended to be used only for debugging.

When the BeginProc macro creates a new service, the macro generates a call to Test_Reenter if the SERVICE attribute is specified with BeginProc and the DEBUG symbol is defined.

See Also

BeginProc


_Trace_Out_Service

include vmm.inc

push OFFSET32 String
VMMCall _Trace_Out_Service

(Windows 95 and later) Sends a null-terminated ASCII string to the debugging device.

No return value.

String
String to display for debugging purposes.

See the documentation of the Out_Debug_String service for a list of supported placeholders. _Trace_Out_Service will do the requisite pushfd and pushad operations.

You should not call this service directly. Use the Trace_Out macro instead.

Example:

Trace_Out 'The value of EAX is #EAX'

This service has no effect in the retail version of Windows. It is intended to be used with the debugging version.


Validate_Client_Ptr

include vmm.inc

mov     ebp, OFFSET32 crs       ; points to a Client_Reg_Struc
VMMCall Validate_Client_Ptr

Asserts that the address in the EBP register points to the Client_Reg_Struc structure for the current thread. This is an asynchronous service.

No return value. If the address is not correct, the service crashes the current virtual machine and does not return.

If the current re-entry count for the VMM is not zero, this service returns immediately without checking the client register pointer.

You should not call this service directly. Use the Assert_Client_Ptr macro instead.

This service has no effect in the retail version of Windows. It is intended to be used with the debugging version.


Events

The Windows 95 virtual machine manager (VMM) is a multiple threaded, non-reentrant operating system. Because it is non-reentrant, virtual devices (VxDs) that process hardware interrupts must have some method of synchronizing their calls to the VMM. For this reason, Windows 95 has the concept of "event" processing.

Events are requests from VxDs that a callback procedure be called at a more propitious time. An event is made of the following pieces of information:

  • The procedure to be called (the event callback procedure).
  • An arbitrary 32-bit reference data to pass to the event callback procedure.
  • Information describing the conditions under which the event callback procedure may be called.
  • An optional priority boost associated with the event.
  • An optional timeout associated with the event.

If one of the prerequisites for an event is that it be called when the current virtual machine or current thread is a particular thread, it is said that the event is scheduled 'for' that thread or virtual machine. The act of calling the event callback procedure is referred to as 'processing' the event.

When a VxD is entered because of an asynchronous interrupt such as a hardware interrupt, the VxD can call only a small subset of services. The VxD can:

  • Call any Virtual PIC Device (VPICD) service.
  • Call any asynchronous VMM service.
  • Schedule events.

Devices that service hardware interrupts often need to use services other than those referred to above. When this is the case, the VxD must schedule an event. That is, the VxD calls an event service such as Schedule_VM_Event, specifying a callback function that the VMM calls when it is safe to call synchronous services.

You can schedule global events or events that a specific to a VM or thread. The callback function for a global event may be called at any time. However, a VM event callback function is always called with the specified VM as the current VM. Similarly a thread event callback function is always called with the specified thread as the current thread.

Certain services can only be called if no VM owns the critical section. To schedule an event such that the callback function is only called when the critical section is not owned, you can use the Call_Restricted_Event service with the PEF_WAIT_NOT_CRIT flag. You can schedule a critical section callback function by using the Call_When_Not_Critical service. For more information about critical sections, see Synchronization.

VM events are often useful for virtual devices that do not service hardware interrupts and can be scheduled at any time except during a Non-Maskable Interrupt (NMI).

Restricted events, which are the most general type of event, are new for Windows 95. When scheduling a restricted event, you can specify a number of "restrictions", or conditions that must be met before the event callback will be called.

Services whose names are of the form Call_XX_Event have the option either to schedule an event or to call the event callback procedure immediately without scheduling an event. The event will be scheduled if the VMM is processing a hardware interrupt that interrupted the VMM, or if the event is virtual machine-specific or thread-specific and the requested virtual machine or thread is not the current virtual machine or thread. The event will also be scheduled if the PEF_ALWAYS_SCHED bit is set, assuming the service supports such a bit. (Not all do.) This list of conditions is intended to be informative and not comprehensive. The VMM reserves the right to choose to schedule the event under conditions not explicitly listed above.

See Also

Call_Priority_VM_Event, Call_When_Not_Critical, Call_Restricted_Event


Canceling Events

Services whose names are of the form Cancel_XX_Event must be used only to cancel events scheduled by the corresponding Schedule_XX_Event or Call_XX_Event service. It is an error to pass (for example) a thread event handle to Cancel_VM_Event.

Services which cancel events also allow zero to be passed as the event handle, which is simply ignored. The standard paradigm for scheduling, processing, and canceling events is as follows:

Scheduling the event:

mov         esi, OFFSET32 MyEvent
VMMCall Schedule_Global_Event
mov     hMyEvent, esi            ; Save handle for cancellation

Processing the event:

BeginProc MyEvent
mov     hMyEvent, 0   ; VERY FIRST THING is
                      ; to zero out the handle
;   .
;   .                   Do other event stuff
;   .
ret                   ; Finished with the event
EndProc MyEvent

Canceling the event:

xor      esi, esi             ; Atomically set hMyEvent to 0
xchg     hMyEvent, esi        ; and retrieve previous value
VMMCall  Cancel_Global_Event  ; Cancel if still outstanding


Event Processing

Events are processed whenever the VMM is about to transfer control from ring 0 to ring 3. One common example of this is returning from ring 0 back to an application running inside a virtual machine. A second example is when a nested execution service like Resume_Exec or Exec_Int is about to transfer control to ring 3 code..

Events are also processed when a thread is blocked on a synchronization object, provided that the Blk_Svc_Ints flag was passed to the corresponding synchronization service. (Such a thread is known as 'blocked servicing events'.) That a thread which is ostensibly blocked on a synchronization object can be called upon to do work while waiting for that synchronization object is a common source of confusion (or horror) for developers familiar with other operating systems. Failure to consider this is a common source of system deadlocks, so this document will attempt to highlight frequently encountered scenarios where particular caution must be exercised.

Note Event processing is secondary to the scheduler. An event scheduled for a thread or virtual machine may meet all its restrictions, but will nevertheless not be processed if the scheduler does not choose to run that thread or virtual machine. In simplified terms, the scheduler chooses the highest-priority thread in the system which satisfies the following criterion:

(Not suspended) and ((Is not blocked) or ((Is blocked servicing events) and (contains events which have met the restrictions)))

This has some subtle consequences.

Spinning in a Resume_Exec loop is not the same as being blocked on a synchronization object, although it does process events. This has not been an uncommon source of deadlocks. Thread A initiates an asynchronous operation, then goes into a Resume_Exec loop, processing events and checking for the asynchronous operation to complete, which breaks the loop. Meanwhile, the code that completes the operation resides in an event callback procedure whose event was scheduled for thread B. If the priority of thread B does not exceed that of thread A, the event will never be processed, because the scheduler only pays attention to the highest-priority unblocked thread.

Note also that unless otherwise explicitly noted, there is no guarantee on the order in which events are processed.


Event Callbacks

When the VMM calls an event callback function, it enters the function with the following registers set:

Register | Contents
EBX | Current VM handle
EDX | Programmer-defined reference data specified when the event service routine was installed
EDI | Current thread handle.
EBP | Client register structure
Interrupts | Enabled
Direction | Clear (up)

Note Some types of events can pass additional information in other registers, and other types of events do not always pass all the information listed above. Exceptions are noted.

The event callback procedure can modify EAX, EBX, ECX, EDX, ESI, and EDI. It must return with interrupts enabled and the direction flag cleared.

Since events are not synchronized with the virtual machine, the contents of the client registers are unpredictable. Altering the contents of the client registers can cause the virtual machine to get very confused. You must save the client state before modifying the client registers, then restore them before returning from the event.

Since event callbacks can be called while the current thread is blocked on a semaphore or other synchronization object, events should be extremely careful not to create deadlocks by attempting to claim a resource that may already be owned by the current thread. For example, consider a thread which takes a resource, then blocks waiting for some other operation to complete, with the intention of releasing the resource after the other operation has completed. While waiting for the semaphore to be signaled, that thread is used to perform an event callback is which attempts to take the same resource. The system is now deadlocked, because the event will wait indefinitely for the resource, which cannot be released until the event returns.

There are many important examples of this deadlock risk which are common sources of problems, so they will be given explicit attention.

Event callbacks may not touch pageable data or otherwise cause paging unless it can be ensured that the thread processing the event callback is not in the middle of its own swapping operation. One way to ensure this is to schedule the event as PEF_Wait_Not_Crit, because the critical section is held during paging. Another way to is to check explicitly whether paging is allowed now (e.g., PAGESWAP_Test_IO_Valid). Note that allocating memory from the VMM page manager or heap manager may result in paging, so services like _PageAllocate and _HeapFree are also forbidden unless it has already been determined that the thread is not paging. List management functions like List_Allocate are safe to call, provided the list was not created with the LF_HEAP or LF_SWAP bits.

Event callbacks may not access the registry unless it can be ensured that the thread processing the event callback is itself not active in the registry. This can be done by using the PEF_Wait_Not_Nested_Exec restriction on the event.

Even if you have ensured that blocking on a semaphore or other synchronization object will not cause a deadlock, bear in mind that blocking at event time seriously impacts the system's ability to multitask smoothly. The thread that got selected to service an event might own resources at ring 3, such as the Win16Mutex, for which other threads are waiting. (Indeed, the fact that the thread is running at all makes it much more likely that it owns such a resource.) While the event is in progress, those resources remain held by the thread even though the thread isn't doing anything with them.

Thus, as a general rule, you should not block at event time.


Reference

There are the following groups of event services:

Group | Elements
Global event services | Call_Global_Event, Cancel_Global_Event, GlobalEventCallback, Schedule_Global_Event
VM and thread event services | Call_VM_Event, Cancel_Thread_Event, Cancel_VM_Event, EventCallback, Schedule_Thread_Event, Schedule_VM_Event
Priority event services | Call_Priority_VM_Event, Cancel_Priority_VM_Event, PriorityEventCallback
Restricted event services | Call_Restricted_Event, Cancel_Restricted_Event, RetrictedEventCallback
Miscellaneous event services | _AtEventTime, Register_PEF_Provider


Global Event Services

Global events are the least restrictive events. They can be processed by any thread or virtual machine.


Call_Global_Event

include vmm.inc

mov     esi, OFFSET32 GlobalEventCallback
mov     edx, RefData
VMMCall Call_Global_Event
mov     [EventHandle], esi

Calls the specified event callback function immediately or schedules a global event. This is an asynchronous service. Uses Flags. If the system decides to schedule the event, it is not defined what order the events are processed.

Returns zero in ESI zero if the service calls the callback function. Otherwise, returns the event handle in ESI. The event handle can be used in subsequent calls to the Cancel_Global_Event service to cancel the event.

EventCallback
Address of the callback function to install.
RefData
Address of reference data to pass to the event callback function.

Any virtual machine can process the event, so the system does not switch tasks before calling the function. The callback function can carry out any actions, and use any VMM services. For a description of the callback function, see GlobalEventCallback. For information about event callback functions, see Event Callbacks.

See Also

Cancel_Global_Event, GlobalEventCallback, Schedule_Global_Event


Cancel_Global_Event

include vmm.inc

mov     esi, EventHandle
VMMCall Cancel_Global_Event

Cancels an event that was previously scheduled using the Schedule_Global_Event or Call_Global_Event service. A virtual device must not attempt to cancel an event if the callback function for the event has already been called. This is an asynchronous service.

No return value.

EventHandle
Handle of the event to cancel. This parameter can be zero to indicate that no event should be canceled.

The event callback function typically sets the event handle to zero so that subsequent calls by the virtual machine to this service do not cause errors.

See Also

Call_Global_Event, Schedule_Global_Event


GlobalEventCallback

mov     ebx, VMHandle
mov     edx, RefData
mov     ebp, OFFSET32 Client_Reg_Struc
call    [GlobalEventCallback]

Performs programmer-defined processing of a global event. GlobalEventCallback is a programmer-defined callback function installed by the Call_Global_Event or Schedule_Global_Event service. The callback function can modify the EAX, EBX, ECX, EDX, ESI, and EDI registers. It must return with interrupts enabled and the direction flag clear (up).

No return value.

VMHandle
Handle of the current virtual machine.
RefData
Reference data supplied when the event was scheduled.
Client_Reg_Struc
Address of a Client_Reg_Struc structure containing the contents of the virtual machine's registers.

For additional information about event callbacks, see Event Callbacks.

See Also

Call_Global_Event, Cancel_Global_Event, Client_Reg_Struc, Schedule_Global_Event


Schedule_Global_Event

include vmm.inc

mov     esi, OFFSET32 GlobalEventCallback
mov     edx, RefData
VMMCall Schedule_Global_Event
mov     [EventHandle], esi

Schedules a global event, which is an event that does not require a specific virtual machine to process it. Since any virtual machine can process the event, the system does not switch tasks before calling the function. This is an asynchronous service. The order in which events are processed is not defined. In other words, if two global events are scheduled, it is not defined which one is processed first.

Returns the event handle in ESI. The handle can be used in a subsequent call to the Cancel_Global_Event service to cancel the event.

GlobalEventCallback
Address of the callback function. For more information about the callback function, see GlobalEventCallback.
RefData
Reference data to be passed to the event callback function.

The callback function can carry out any actions and use any VMM services, subject to the remarks in GlobalEventCallback.

See Also

Call_Global_Event, Cancel_Global_Event, GlobalEventCallback


VM and Thread Event Services

The following topics describe the VM and Thread event services.


Call_VM_Event

include vmm.inc

mov     ebx, VMHandle
mov     esi, OFFSET32 EventCallback
mov     edx, RefData
VMMCall Call_VM_Event
mov     [EventHandle], esi

Calls the event callback function immediately or schedules an event for the specified virtual machine. This is an asynchronous service. Uses Flags

Returns zero in ESI if the service calls the callback function. Otherwise, returns the event handle in ESI. The event handle can be used in subsequent calls to the Cancel_VM_Event service to cancel the event.

VMHandle
Handle of the virtual machine to process the event. This value must be a valid VM handle.
EventCallback
Address of the callback function to install. For more information about the callback function, see EventCallback.
RefData
Reference data to pass to the event callback function.

Since the specified virtual machine must process the event, the system carries out a task switch if necessary before calling the function. The callback function can carry out any actions and use any VMM services.

For additional information about event callbacks, see Event Callbacks.

See Also

Cancel_VM_Event, EventCallback, Schedule_VM_Event


Cancel_Thread_Event

include vmm.inc

mov     edi, ThreadHandle
mov     esi, EventHandle
VMMCall Cancel_Thread_Event

Cancels an event that was previously scheduled using the Schedule_Thread_Event service. A virtual device must not attempt to cancel an event if the callback function for the event has already been called. This is an asynchronous service. Uses Flags

No return value.

ThreadHandle
Handle of the thread for which the event is to be canceled. This value must be a valid thread handle and it must equal the thread handle used when the event was originally scheduled.
EventHandle
Handle of the event to cancel. This parameter can be zero to indicate that no event should be canceled.

The event callback function typically sets the event handle to zero so that subsequent calls by the thread to this service do not cause errors.

See Also

Schedule_Thread_Event


Cancel_VM_Event

include vmm.inc

mov     ebx, VMHandle
mov     esi, EventHandle
VMMCall Cancel_VM_Event

Cancels an event that was previously scheduled using the Schedule_VM_Event or Call_VM_Event service. A virtual device must not attempt to cancel an event if the callback function for the event has already been called. This is an asynchronous service. Uses Flags.

No return value.

VMHandle
Handle of the virtual machine for which the event is to be canceled. This value must be a valid thread handle and it must equal the thread handle used when the event was originally scheduled.
EventHandle
Handle of the event to cancel. This parameter can be zero to indicate that no event should be canceled.

The event callback function typically sets the event handle to zero so that subsequent calls by the virtual machine to this service do not cause errors.

Do not use this service to cancel events scheduled using the Call_Priority_VM_Event, Call_Thread_Event, or Call_Restricted_Event service. You must cancel priority events using the Cancel_Priority_VM_Event service.

See Also

Call_Priority_VM_Event, Call_VM_Event, Cancel_Priority_VM_Event, Schedule_VM_Event


EventCallback

mov     ebx, VMHandle
mov     edi, ThreadHandle
mov     edx, RefData
mov     ebp, OFFSET32 Client_Reg_Struc
call    [EventCallback]

Performs programmer-defined processing of a event for a virtual machine. EventCallback is a programmer-defined callback function installed by the Call_VM_Event, Schedule_Thread_Event, or Schedule_VM_Event service. The callback function can modify the EAX, EBX, ECX, EDX, ESI, and EDI registers.

No return value.

VMHandle
Handle of the current virtual machine.
ThreadHandle
Handle of the current thread.
RefData
Reference data supplied when the event was originally scheduled.
Client_Reg_Struc
Address of a Client_Reg_Struc structure containing the contents of the virtual machine's registers.

For additional information about event callbacks, see Event Callbacks.

See Also

Call_VM_Event, Cancel_VM_Event, Client_Reg_Struc, Schedule_Thread_Event, Schedule_VM_Event


Schedule_Thread_Event

include vmm.inc

mov     edi, ThreadHandle
mov     esi, OFFSET32 EventCallback
mov     edx, RefData
VMMCall Schedule_Thread_Event
mov     [EventHandle], esi

Schedules an event for the specified thread. This is an asynchronous service.

Returns the event handle in ESI. The event handle can be used in subsequent calls to the Cancel_Thread_Event service to cancel the event.

ThreadHandle
Handle of the thread to process the event.
EventCallback
Address of the callback function. For more information about the callback function, see EventCallback.
RefData
Reference data to pass to the callback function.

Since the specified thread must process the event, the system carries out a task switch (if necessary) before calling the function. The callback function can carry out any actions, and use any VMM services. The system completes the event processing before the VMM returns from the current interrupt. For additional information about event callbacks, see Event Callbacks.

See Also

Cancel_Thread_Event, EventCallback, Schedule_Global_Event, Schedule_VM_Event


Schedule_VM_Event

include vmm.inc

mov     ebx, VMHandle
mov     esi, OFFSET32 EventCallback
mov     edx, RefData
VMMCall Schedule_VM_Event
mov     [EventHandle], esi

Schedules an event for the specified virtual machine. This is an asynchronous service.

Returns the event handle in ESI. The event handle can be used in subsequent calls to the Cancel_VM_Event service to cancel the event.

VMHandle
Handle of the virtual machine to process the event. This value must be a valid VM handle.
EventCallback
Address of the callback function. For more information about the callback function, see EventCallback.
RefData
Reference data to pass to the callback function.

Since the specified virtual machine must process the event, the system carries out a task switch (if necessary) before calling the callback function. The function can carry out any actions and use any VMM services. The system completes the event processing before the VMM returns from the current interrupt.

For additional information about event callbacks, see Event Callbacks.

See Also

Call_VM_Event, Cancel_VM_Event, EventCallback, Schedule_Global_Event, Schedule_Thread_Event


Priority Event Services

The following topics describe the Priority Event services.


Call_Priority_VM_Event

include vmm.inc

mov     eax, PriorityBoost
mov     ebx, VMHandle
mov     ecx, Flags
mov     edx, RefData
mov     esi, OFFSET32 PriorityEventCallback
mov     edi, TimeOut
VMMCall Call_Priority_VM_Event
mov     [EventHandle], esi

Calls the callback function immediately or schedules a priority event for the specified virtual machine. This is an asynchronous service. Uses Flags and ESI.

Returns zero in ESI if the callback function was called immediately. Otherwise, returns the event handle in ESI. The handle can be used in a subsequent call to the Cancel_Priority_VM_Event service to cancel the event.

PriorityBoost
Priority boost for the virtual machine. This parameter must be a value such that when added to the current execution priority, the result is within the range Reserved_Low_Boost to Reserved_High_Boost. This parameter can be 0 if no boost is necessary. Common priority boost values, from lowest to highest, are as follows:
Value | Meaning
Reserved_Low_Boost | Reserved for use by system.
Cur_Run_VM_Boost | Use to boost the priority of each virtual machine, in turn, forcing them to run for their allotted time slices.
Low_Pri_Device_Boost | Use for operations that need timely processing but are not time critical.
High_Pri_Device_Boost | Use for time-critical operations that should not circumvent the critical section boost.
Critical_Section_Boost | Use to boost the priority of the virtual machine whenever it enters a critical section (calls Begin_Critical_Section).
Time_Critical_Boost | Use for operations that require immediate processing, even when another virtual machine is in a critical section. For example, VPICD uses this when simulating hardware interrupts.
Reserved_High_Boost | Reserved for use by system.

Forgetting to pass a priority value in the EAX register is a common error.

VMHandle
Handle of the virtual machine to process the event. This value must be a valid VM handle.
Flags
A combination of these action flags:
Value | Meaning
PEF_Always_Sched | Event is always scheduled, meaning the callback function is never called immediately.
PEF_Dont_Unboost | Priority of the virtual machine is not reduced after return from callback function.
PEF_Time_Out | Specifies that time-out value in the EDI register should be used. Available in Windows version 3.1 or later.
PEF_Wait_For_STI | Callback function is not called until the virtual machine enables interrupts in all threads.
PEF_Wait_Not_Crit | Callback function is not called until the virtual machine is not in a critical section or time-critical operation.
PEF_Wait_Not_Time_Crit, PEF_Wait_Not_HW_Int | Callback function is not called until the thread priority is below TIME_CRITICAL_BOOST. Useful to prevent an event from occurring while an interrupt is being simulated into a VM.

All other values are reserved.

RefData
Reference data to pass to the callback function.
EventCallback
Address of the callback function to install. For more information about the callback function, see PriorityEventCallback.
TimeOut
Number of milliseconds until the event times out. The service uses this parameter only if the PEF_Time_Out value is specified by Flags.

The system carries out a task switch to the specified virtual machine if it is not the current virtual machine. If PriorityBoost is not zero, the service boosts the priority of the virtual machine before calling the callback function.

If the amount of time specified by TimeOut elapses before the system can switch to the virtual machine, the system sets the carry flag and calls the callback function immediately regardless of which virtual machine is currently running. In this case, any requested priority boost is canceled even if Flags specified the PEF_Dont_Unboost value. The callback function should always check the carry flag to determine whether a time out occurred.

For additional information about event callbacks, see Event Callbacks.

See Also

Adjust_Exec_Priority, Begin_Critical_Section, Call_When_Not_Critical, Call_VM_Event, Cancel_Priority_VM_Event, PriorityEventCallback, Call_Restricted_Event


Cancel_Priority_VM_Event

include vmm.inc

mov     esi, EventHandle
VMMCall Cancel_Priority_VM_Event

Cancels an event that was previously scheduled using the Call_Priority_VM_Event service. A virtual device must not attempt to cancel an event if the callback function for the event has already been called. Uses ESI, Flags

No return value.

EventHandle
Handle of the event to cancel. This parameter can be zero to indicate that no event should be canceled.

The event callback function typically sets the event handle to zero so that subsequent calls by the virtual machine to this service do not cause errors.

This service cancels any priority boost associated with the event, even if the PEF_Dont_Unboost value was specified when the event was scheduled.

Do not use this service to cancel events scheduled using the Call_VM_Event or Schedule_VM_Event services. You must cancel virtual machine events using the Cancel_VM_Event service.

See Also

Call_Priority_VM_Event, Call_VM_Event, Cancel_VM_Event, Schedule_VM_Event


PriorityEventCallback

mov     ebx, VMHandle
mov     edi, ThreadHandle
mov     edx, RefData
mov     ebp, OFFSET32 Client_Reg_Struc
;set up CY flag if appropriate
call    [PriorityEventCallback]

Performs programmer-defined processing of a priority event for a virtual machine or thread. PriorityEventCallback is a programmer-defined callback function installed by the Call_Priority_VM_Event service. The callback function can modify the EAX, EBX, ECX, EDX, ESI, EDI, and Flags registers. It must return with interrupts enabled and the direction flag clear (up).

Clears the carry flag if the event did not time out; otherwise, sets the carry flag.

VMHandle
Handle of the current virtual machine. If a timeout occurs, this handle may not be valid. In such cases, the callback function should use the Get_Cur_VM_Handle service to get the handle of the current virtual machine.
ThreadHandle
Handle of the current thread. If a timeout occurs, this handle may not be valid. In such cases, the callback function should use the Get_Cur_Thread_Handle service to get the handle of the current thread.
RefData
Reference data supplied when the event was scheduled.
Client_Reg_Struc
Address of a Client_Reg_Struc structure containing the contents of the virtual machine's registers.

If the PEF_Time_Out bit was set when the event was scheduled, additional information is given in the flags register, as described in Call_Priority_VM_Event. Such an event callback procedure should begin as follows:

mov         hThisEvent, 0    ; (See 'Canceling Events')
                         ; (Must preserve carry!)
jc          Event_Timed_Out  ; Carry set means event timed out
                         ; Else event processed normally

If a timeout occurs, any priority boost is automatically canceled, even if the PEF_Dont_Unboost flag was specified in the Call_Priority_VM_Event function that initiated the event.

For additional information about event callbacks, see Event Callbacks.

See Also

Call_Priority_VM_Event, Client_Reg_Struc, Get_Cur_Thread_Handle, Get_Cur_VM_Handle


Restricted Event Services

The following topics describe the Restricted Event services.


Call_Restricted_Event

include vmm.inc

mov     eax, PriorityBoost
mov     ebx, Handle
mov     ecx, Flags
mov     edx, RefData
mov     esi, OFFSET32 RestrictedProc
mov     edi, Timeout
VMMCall Call_Restricted_Event
mov     [EventHandle], esi

Combines the functionality of the Call_VM_Event, Call_When_VM_Ints_Enabled, Call_When_Not_Critical, and Adjust_Exec_Priority services into one service.

The service allows a VxD to specify flags which place restrictions on when the VMM can call the event callback function. Restrictions include such things as the event callback function can be called only when interrupts are enabled, only when the critical section is unowned, and so on.

As with all event services, this service can be called from an interrupt handler. This is an asynchronous service. Uses ESI and Flags.

Returns zero in ESI if the callback function was called immediately. Otherwise, returns the event handle in ESI. The handle can be used in a subsequent call to the Cancel_Restricted_Event service to cancel the event.

PriorityBoost
Priority boost for the virtual machine. This parameter must be a value such that when added to the current execution priority, the result is within the range Reserved_Low_Boost to Reserved_High_Boost. This parameter can be 0 if no boost is necessary. Common priority boost values, from lowest to highest, are as follows:
Value | Meaning
Reserved_Low_Boost | Reserved for use by system.
Low_Pri_Device_Boost | Use for operations that need timely processing but are not time critical.
High_Pri_Device_Boost | Use for time-critical operations that should not circumvent the critical section boost.
Critical_Section_Boost | Use to boost the priority of the virtual machine whenever it enters a critical section (calls Begin_Critical_Section).
Time_Critical_Boost | Use for operations that require immediate processing, even when another virtual machine is in a critical section. For example, VPICD uses this when simulating hardware interrupts.
Reserved_High_Boost | Reserved for use by system.

For global events, the priority boost only goes into effect after restrictions have been met; that is, just before the VMM calls the event callback function. For VM events, the priority boost is originally applied to the whole VM, but will be moved to the thread that the event is called on unless Flags specifies the PEF_Dont_Unboost flag.

Forgetting to pass a priority value in the EAX register is a common error.

Handle
If the PEF_Thread_Event flag is specified, this parameter contains the handle of the thread for which the event callback is requested. Otherwise, the value of this parameter is zero when the event is a global event or the handle of the virtual machine for which the VM event callback is requested.
Flags
A combination of these action flags:
Value | Meaning
PEF_Always_Sched | Event is always scheduled, meaning the callback function is never called immediately.
PEF_Dont_Unboost | Priority of the virtual machine or thread is not reduced after return from callback function.
PEF_Thread_Event | Handle is the handle of the thread for which the event is requested. The callback function is called only in the context of the thread.
PEF_Time_Out | The time-out value in the EDI register should be used. Available in Windows version 3.1 or later.
PEF_Wait_For_STI | Callback function is not called until the virtual machine enables interrupts in all threads.
PEF_Wait_Not_HW_Int | Callback function is not called while the VPICD is simulating a hardware interrupt.
PEF_Wait_In_PM | Callback function is not called until the virtual machine or thread is executing in protected mode. Use this flag with caution — it may never happen for VM other than the system VM unless an MS-DOS Protected Mode Interface (DPMI) application is running.
PEF_Wait_Not_Crit | Callback function is not called until the virtual machine is not in a critical section or time-critical operation. See remarks below.
PEF_Wait_Not_Nested_Exec | Callback function is not called while the virtual machine is in a nested execution block.
PEF_Wait_For_Thread_STI | Callback function is not called until interrupts are enabled at ring 3 in the current thread.
PEF_Ring0_Event | Callback function completes at ring 0. See remarks below.
PEF_Wait_Crit | Callback function is not called until (1) the critical section is free, or (2) the critical section is owned by the current thread. See remarks below.
PEF_Wait_Crit_VM | Callback function is called when critical section not owned by other thread in VM. See remarks below.
PEF_Process_Last | See description below.

All other values are reserved.

RefData
Reference data to pass to the callback function.
EventCallback
Address of the callback function to install. For more information about the callback function, see RestrictedEventCallback.
TimeOut
Number of milliseconds until the event times out. The service uses this parameter only if the PEF_Time_Out value is specified by Flags.

If a timeout occurs before the restrictions are met, the event callback will be called with carry set.

A VxD uses the Call_Restricted_Event service for purposes that include the following:

  • To wait until a virtual machine enables interrupts and the critical section is free so the VxD can call MS-DOS or some other non-reentrant code.
  • To boost a virtual machine's priority and wait until the virtual machine enables interrupts to simulate an interrupt type event. For example, the VNETBIOS uses this service for asynchronous network request POST call-backs.
  • To force an event to be processed in another virtual machine by boosting the virtual machines execution priority.

Global restricted events can happen in any VM that meets the restriction. VM-restricted events can only happen in the specified VM; and now that multiple threads are supported in the system VM, restricted thread events can be specified to only happen in the one thread context (although specifying that interrupts must be enabled for a thread event will only happen when interrupts are enabled in all threads of that VM.)

The PEF_Wait_Not_Crit flag will delay the processing of the event until the critical section is free and the priority of the current thread or virtual machine is less than Critical_Section_Boost. One should be careful not to pass too large a PriorityBoost when this flag is set. (In particular, passing a PriorityBoost greater than or equal to Critical_Section_Boost will prevent the event from ever satisfying its own restrictions.)

The PEF_Wait_For_Thread_STI flag differs from the PEF_Wait_For_STI flag in that the former checks the status of only the current thread, whereas the latter checks the status of all threads in the virtual machine. The two flags may not be combined.

The PEF_Ring0_Event flag indicates that the event can complete entirely at ring 0 without faulting. The requirements for 'ring 0' events are very strict, and apply to the event callback procedure and anything it calls, directly or indirectly. Although some rules in the system are relaxed if 32-bit disk access is enabled, these rules remain in full force. Ring 0 events must restrict memory accesses to locked code and locked data. They must not call Begin_Nest_Exec, Resume_Exec, Exec_VxD_Int, Exec_Int, or any service or procedure that in turn calls one of those services. They must not block on any synchronization objects. They must not adjust any thread's execution priority. In brief, they must guarantee that they will carry out their work to completion without running any code at ring 3, and without causing a task switch. In exchange for these guarantees, ring 0 events can be processed even if a thread has specifically requested that events not be processed. Ring 0 events are very dangerous. It is strongly recommended that they be avoided entirely. The flag is listed here for completeness.

The PEF_Wait_Crit flag indicates that the event may be processed only if the current thread owns the critical section, or if the critical section is unowned. This restriction may be applied only to global events (Handle = 0). The event callback can then be assured that it can call Begin_Critical_Section without blocking. PEF_Wait_Crit events allow you to ensure that a section of code be executed as soon as possible under the protection of the critical section. In Windows 3.1, this was done by a chain of events which repeatedly determine the critical section owner, then either perform the requested action or reschedule the same event for the current critical section owner and trying again. Since the ownership of the critical section can change between the time the event is scheduled and the time the event is processed, this chain of events may continue for several iterations before finally completing. (If you draw a picture, you can see why this is informally known as 'chasing the critical section'.) Starting with Windows 95, the PEF_Wait_Crit flag is the recommended way of accomplishing this.

The PEF_Wait_Crit_VM flag may be set only if Handle is equal to the System VM handle. It indicates that the event may be processed when the current thread is a thread in the System VM, and one of the following conditions is also met: (1) The critical section is unowned. (2) The critical section is owned by the current thread. (3) The critical section is owned by a thread not in the System VM. Writers of virtual device drivers should not normally have need for this flag. It is documented here for completeness.

The PEF_Process_Last allows a limited degree of control over the order in which events are processed. Normally, global events are processed first, then VM events, then thread events. This flag causes the event to be removed from consideration during the initial check for processable events. If the initial check fails to find any events, then a second pass is made during which this event can be selected. The only time this flag should be set is on a VM event (Handle is a valid VM handle), to indicate that the current thread should have no thread events when the VM event is processed. It does not add the event to the end of a list. Writers of virtual device drivers should not normally have need for this flag. It is documented here for completeness.

See Also

Adjust_Exec_Priority, Begin_Critical_Section, Call_VM_Event, Call_When_Not_Critical, Call_When_VM_Ints_Enabled, Cancel_Restricted_Event, RestrictedEventCallback


Cancel_Restricted_Event

include vmm.inc

mov     esi, EventHandle
VMMCall Cancel_Restricted_Event

Cancels an event that was previously scheduled using the Call_Restricted_Event service. A virtual device must not attempt to cancel an event if the callback function for the event has already been called. Uses ESI, Flags

No return value.

EventHandle
Handle of the event to cancel. This parameter can be zero to indicate that no event should be canceled.

The event callback function typically sets the event handle to zero so that subsequent calls by the virtual machine to this service do not cause errors.

This service cancels any priority boost associated with the event, even if the PEF_Dont_Unboost value was specified when the event was scheduled.

Do not use this service to cancel events scheduled using the Call_VM_Event or Schedule_VM_Event services. You must cancel virtual machine events using the Cancel_VM_Event service.

See Also

Call_Restricted_Event, Call_VM_Event, Cancel_VM_Event, RestrictedEventCallback, Schedule_VM_Event


RestrictedEventCallback

include vmm.inc

mov     ebx, VMHandle
mov     edi, ThreadHandle
mov     edx, RefData
mov     ebp, OFFSET32 Client_Reg_Struc
call    [RestrictedEventCallback]

Performs programmer-defined processing of a restricted event for a virtual machine or thread. RestrictedEventCallback is a programmer-defined callback function installed by the Call_Restricted_Event service. The callback function can modify the EAX, EBX, ECX, EDX, ESI, EDI, and Flags registers. The callback function must return with interrupts enabled and the direction flag clear (up).

VMHandle
Handle of the current virtual machine. If a timeout occurs, this handle may not be valid. In such cases, the callback function should use the Get_Cur_VM_Handle service to get the handle of the current virtual machine.
ThreadHandle
Handle of the current thread. If a timeout occurs, this handle may not be valid. In such cases, the callback function should use the Get_Cur_Thread_Handle service to get the handle of the current thread.
RefData
Reference data supplied by the virtual machine that initiated the priority event.
Client_Reg_Struc
Address of a Client_Reg_Struc structure containing the contents of the virtual machine's registers.

If a timeout occurs, any priority boost is automatically canceled, even if the PEF_Dont_Unboost flag was specified in the Call_Restricted_Event function that initiated the event.

If the PEF_Time_Out bit was set when the event was scheduled, additional information is given in the flags register, as described in Call_Restricted_Event. Such an event callback procedure should begin as follows:

mov  hThisEvent, 0         ; (See 'Canceling Events')
                       ; (Must preserve carry!)
jc   Event_Timed_Out       ; Carry set means event timed out
                       ; Else event processed normally

For additional information about event callbacks, see Event Callbacks.

See Also

Call_Restricted_Event, Cancel_Restricted_Event, Client_Reg_Struc, Get_Cur_Thread_Handle, Get_Cur_VM_Handle


Miscellaneous Event Services

The following topics describe the miscellaneous event services.


_AtEventTime

include vmm.inc

VMMCall  AtEventTime
mov      fEvent, eax

Tests whether the current thread is processing an event. Uses EAX, ECX, EDX, and Flags

Returns non-zero in EAX if the thread is processing an event, zero otherwise.


Register_PEF_Provider

include vmm.inc

mov     eax, PEFFlag
mov     ecx, 0 ; reserved, must be zero
VMMCall Register_PEF_Provider
jc      Error_Handler
mov     [VM_State_Off], eax

Retrieves the offset of the restricted-event flags in a virtual machine's control block. An external component can set the flags to indicating whether a restricted condition is met. Uses EAX and Flags.

Returns the offset of the restricted-event flags (a double-word value). An external component can toggle flag bits at this offset. Setting a bit means the corresponding restriction is not met.

PEFFlag
Flag bit to set or clear. Currently, the only valid flag is PEF_WAIT_NOT_HW_INT_BIT.

The VPICD uses this service to indicate whether it is simulating a hardware interrupt into a VM. It sets the PEF_WAIT_NOT_HW_INT_BIT bit when it is about to simulate an interrupt into a virtual machine, and clears the bit when it finishes simulating the interrupt.

This service is intended to be used by only by internal Windows components, it is not for general use.

See Also

Call_Restricted_Event, Cancel_Restricted_Event


I/O Trapping

The VMM provides the Install_IO_Handler service to install a callback procedure to handle protection faults for a given port. When a virtual device calls Install_IO_Handler, the VMM sets the appropriate bit in the I/O permission map (IOPM) and registers the procedure. When a virtual machine executes an instruction that reads or writes data from an I/O port, the 80386 looks up the port number in the I/O permission map. If the corresponding bit in the IOPM is set, then the instruction will cause a protection fault that results in calling the registered procedure.

There are the following I/O services:

Service | Description
Disable_Global_Trapping | Disables global I/O trapping (I/O works directly with hardware and is not intercepted).
Disable_Local_Trapping | Disables local I/O trapping (I/O works directly with hardware and is not intercepted).
Enable_Global_Trapping | Enables global I/O trapping (I/O requests are trapped instead of working directly with hardware). Enabled by default at system startup.
Enable_Local_Trapping | Enables local I/O trapping (I/O requests are trapped instead of working directly with hardware).
Install_IO_Handler | Install an I/O callback procedure.
Install_Mult_IO_Handlers | Install I/O handlers for multiple ports.
Remove_IO_Handler | Removes the I/O handler for the specified port and disables trapping for that port.
Remove_Mult_IO_Handlers | Repeatedly calls the Remove_IO_Handler service for each entry in the VxD_IO_Table, removing the specified IO handlers.
Simulate_IO | Reduces complex I/O instructions to simpler I/O operations.
_Simulate_VM_IO | Simulate ring 3 port I/O from the current vm (inside a ring 0 VxD).


Disable_Global_Trapping

include vmm.inc

mov     edx, Port           ; I/O port number
VMMCall Disable_Global_Trapping

Disables I/O port trapping for the specified I/O port (I/O works directly with hardware and is not intercepted). This applies to every virtual machine. Uses Flags.

No return value.

Port
Number of the I/O port for which global trapping is to be disabled.

This service must not be used unless an I/O callback procedure has been installed for the given port using the Install_IO_Handler or Install_Mult_IO_Handlers service during initialization. In particular, you should not attempt to alter the port trapping state of a port for which you did not personally install an I/O handler. Altering the port trapping state of a port owned by another virtual device driver may cause that other driver to get confused.

The system applies the current global trapping state for each new virtual machine as it is created. When the system first starts, global trapping is enabled by default.

See Also

Enable_Global_Trapping, Install_IO_Handler, Install_Mult_IO_Handlers


Disable_Local_Trapping

include vmm.inc

mov     ebx, VM         ; VM handle
mov     edx, Port       ; I/O port number
VMMCall Disable_Local_Trapping

Disables I/O port trapping for the specified I/O port (I/O works directly with hardware and is not intercepted). This applies only to the specified virtual machine. Uses Flags.

No return value.

VM
Handle of the virtual machine for which to disable I/O trapping.
Port
Number of the I/O port for which trapping is disabled.

This service must not be used unless an I/O callback procedure has been installed for the given port using the Install_IO_Handler or Install_Mult_IO_Handlers service during initialization. In particular, you should not attempt to alter the port trapping state of a port for which you did not personally install an I/O handler. Altering the port trapping state of a port owned by another virtual device driver may cause that other driver to get confused.

See Also

Enable_Local_Trapping, Install_IO_Handler, Install_Mult_IO_Handlers


Enable_Global_Trapping

include vmm.inc

mov     edx, Port           ; I/O port number
VMMCall Enable_Global_Trapping

Enables I/O port trapping for the specified port (I/O requests are trapped instead of working directly with hardware). Enabled by default at system startup. This applies to every virtual machine. Uses Flags.

No return value.

Port
Number of the I/O port for which global trapping is to be enabled.

This service must not be used unless an I/O callback procedure has been installed for the given port using the Install_IO_Handler or Install_Mult_IO_Handlers service during initialization. In particular, you should not attempt to alter the port trapping state of a port for which you did not personally install an I/O handler. Altering the port trapping state of a port owned by another virtual device driver may cause that other driver to get confused.

The system applies to current global trapping state to each new virtual machine as it is created. When the system first starts, global trapping is enabled by default.

See Also

Disable_Global_Trapping, Install_IO_Handler, Install_Mult_IO_Handlers


Enable_Local_Trapping

include vmm.inc

mov     ebx, VM         ; VM handle
mov     edx, Port       ; I/O port number
VMMCall Enable_Local_Trapping

Enables I/O port trapping for the specified port (I/O requests are trapped instead of working directly with hardware). This applies to the specified virtual machine only. Uses Flags.

No return value.

VM
Handle of the virtual machine for which to enable I/O trapping.
Port
Number of the I/O port for which trapping is enabled.

This service must not be used unless an I/O callback procedure has been installed for the given port using the Install_IO_Handler or Install_Mult_IO_Handlers service during initialization. In particular, you should not attempt to alter the port trapping state of a port for which you did not personally install an I/O handler. Altering the port trapping state of a port owned by another virtual device driver may cause that other driver to get confused.

See Also

Disable_Local_Trapping, Install_IO_Handler, Install_Mult_IO_Handlers


Install_IO_Handler

include vmm.inc

mov     esi, IOCallback     ; points to callback procedure
mov     edx, Port           ; I/O port number
VMMCall Install_IO_Handler

jc      not_installed       ; carry flag set if procedure not installed

Installs a callback procedure for I/O port trapping, and enables trapping for the specified port. Only one procedure may be installed for a given port. For Windows 95, this service can be called following initialization. Uses Flags.

Returns with the carry flag clear if successful, set otherwise.

IOCallback
Address of the callback procedure. For more information about the callback procedure, see below.
Port
Number of the I/O port trap.

The service returns an error if a callback procedure is already installed for the specified port or the system limit for I/O callback procedures has been reached.

The system calls the callback procedure whenever a program in a virtual machine attempts to access the specified I/O port, and I/O trapping is enabled. The system calls the procedure as follows:

mov     ebx, VM             ; current VM handle
mov     ecx, IOType         ; type of I/O
mov     edx, Port           ; port number
mov     ebp, OFFSET32 crs   ; points to a Client_Reg_Struc
mov     eax, Data           ; output data (if I/O type is output)
call    [IOCallback]

mov     [Data], eax         ; input data (if I/O type is input)

The VM parameter specifies the current virtual machine, the Port parameter specifies the I/O port, and the crs parameter points to a Client_Reg_Struc structure containing the register contents for the current virtual machine.

The IOType parameter specifies the type of input or output operation requested and determines whether the callback procedure receives data in the EAX register or must return data in the EAX register. The IOType parameter can be a combination of the following values:

Value | Meaning
Addr_32_IO | Use 32-bit address offsets for input or output string operations. If this value is not given, the 16-bit offsets are used.
Byte_Input | Input a single byte; place in AL if String_IO not given.
Byte_Output | Output a single byte from AL if String_IO not given.
Dword_Input | Input a double word; place in EAX if String_IO not given.
Dword_Output | Output a double word from EAX if String_IO not given.
Rep_IO | Repeat the input or output string operation the number of times specified by the Client_CX field in the Client_Reg_Struc structure. (The number of repetitions is stored in the Client_ECX field if Addr_32_IO is also set.)
Reverse_IO | Decrement string address on each input or output operation. If this value is not given, the string address is incremented on each operation.
String_IO | Input or output a string. The high 16-bits specifies segment address of buffer containing the string to output or to receive the string input.
Word_Input | Input a word; place in AX if String_IO not given.
Word_Output | Output a word from AX if String_IO not given.

The Data parameter is used only for when I/O type is for output.

A virtual machine can disable trapping of a port for every or for specific virtual machines by using the Disable_Global_Trapping and Disable_Local_Trapping services.

See Also

Remove_IO_Handler, Disable_Global_Trapping, Disable_Local_Trapping, Install_Mult_IO_Handlers


Install_Mult_IO_Handlers

include vmm.inc

mov     edi, OFFSET32 IOTable   ; points to an I/O table
VMMCall Install_Mult_IO_Handlers

jnc     installed               ; carry flag clear if all procedures installed
mov     [BadPort], edx          ; I/O port number that failed

Installs I/O callback procedures for one or more I/O ports. For Windows 95, this service can be called following initialization. Uses Flags.

Returns with the carry flag clear if all callback procedures were installed, set otherwise. If the carry flag is set, the EDX register contains the number of the I/O port for which the procedure could not be installed.

IOTable
Address of an I/O table created using the Begin_Vxd_IO_Table, End_Vxd_IO_Table, and Vxd_IO macros. For more information about the table, see below.

This service repeatedly calls the Install_IO_Handler service until all entries in the specified I/O table have been installed.

A virtual device can create an I/O table using the Begin_Vxd_IO_Table, End_Vxd_IO_Table, and Vxd_IO macros. The following example shows a table containing three entries for ports 30, 31, and 32:

Begin_Vxd_IO_Table  My_IO_Table
Vxd_IO              30,IO_Handler_1
Vxd_IO              31,IO_Handler_2
Vxd_IO              32,IO_Handler_1
End_Vxd_IO_Table    My_IO_Table

See Also

Begin_Vxd_IO_Table, End_Vxd_IO_Table, Install_IO_Handler, Vxd_IO


Remove_Mult_IO_Handlers

include vmm.inc

mov     edi, OFFSET32 VxD_IO_Table
VMMCall Remove_Mult_IO_Handlers

Repeatedly calls the Remove_IO_Handler service for each entry in the VxD_IO_Table, removing the specified IO handlers. Uses flags.

No return value.

VxD_IO_Table
A table of IO port numbers and associated procedure names. This table should have the following format:
Begin_Vxd_IO_Table  Table_Name
Vxd_IO       <port #>,<procedure name>
...
Vxd_IO       <port #>,<procedure name>
Vxd_IO       <port #>,<procedure name>
End_Vxd_IO_Table    Table_Name


Remove_IO_Handler

include vmm.inc

mov     edx, IO_Port_Address
VMMCall Remove_IO_Handler
jc      IO_Handler_Does_Not_Exist

Removes the I/O handler for the specified port and disables trapping for that port. Uses flags.

Sets the carry flag if the I/O handler does not exist.

IO_Port_Address
Address of the port for which the handler should be removed.

The I/O handler removed by this service is a procedure that was installed with the Install_IO_Handler service.


Simulate_IO

include vmm.inc

mov     eax, Data          ; data for output operations
mov     ebx, VM            ; current VM handle
mov     ecx, IOType        ; type of I/O operation
mov     edx, Port          ; I/O port number
mov     ebp, OFFSET32 crs  ; address of Client_Reg_Struc
VMMJmp  Simulate_IO

mov     [Data], eax        ; data for input operation

Reduces complex I/O instructions to simpler I/O operations. An I/O callback procedure typically jumps to this service whenever the procedure receives a type of I/O that it does not directly support. Uses EAX, EBX, ECX, EDI, EDX, ESI, Flags.

Returns with the input data in the EAX register, if the IOType parameter specifies an input operation. The size of the value in the EAX register is implied by the operation type.

Data
Data for an output operation. This parameter is used only if the IOType parameter specifies an output operation.
VM
Handle of the current virtual machine.
IOType
Type of I/O operation, as specified in a call to an I/O trap procedure. Can be one or more of these values:
Value | Meaning
Addr_32_IO | Uses 32-bit address offsets for input or output string operations. If this value is not given, the 16-bit offsets are used.
Byte_Input | Inputs a single byte; place in AL if String_IO is not given.
Byte_Output | Outputs a single byte from AL if String_IO is not given.
Dword_Input | Inputs a doubleword; place in EAX if String_IO is not given.
Dword_Output | Outputs a doubleword from EAX if String_IO is not given.
Rep_IO | Repeats the input or output string operation the number of times specified by the Client_CX field in the Client_Reg_Struc structure. (The number of repetitions is stored in the Client_ECX field if Addr_32_IO is also set.)
Reverse_IO | Decrements string address on each input or output operation. If this value is not given, the string address is incremented on each operation.
String_IO | Inputs or outputs a string. The high 16-bits specifies the segment address of the buffer containing the string to output, or to receive the string input.
Word_Input | Inputs a word; place in AX if String_IO is not given.
Word_Output | Outputs a word from AX if String_IO is not given.

Port
Number of the I/O port through which to carry out the operation. If word I/O is requested, then Port+1 is also used. If dword I/O is requested, then Port+1 through Port+3 are also used.
crs
Address of a Client_Reg_Struc structure containing the register contents for the current virtual machine.

The parameters to this service are identical to the parameters passed to an I/O callback procedure. A callback procedure should jump to this service, using the VMMJmp macro, with all of the registers in the same state as when the procedure was called. The procedure may modify the ESI and EDI register before jumping, if necessary.

See Also

Dispatch_Byte_IO, Emulate_Non_Byte_IO


_Simulate_VM_IO

include vmm.inc

mov     edx, PortID
mov     ecx, IOType
mov     eax, OutputData
VMMCall _Simulate_VM_IO
mov     [InputData], eax

Simulates ring 3 port I/O from a VxD.

If the service is called to simulate input, EAX will receive the input value.

PortID
Identifies the port for which input or output is simulated.
IOType
Specifies the type of I/O. It can be one of the following values:
Value | Meaning
Byte_Input | Inputs a single byte.
Byte_Output | Outputs a single byte.
Dword_Input | Inputs a doubleword.
Dword_Output | Outputs a doubleword.
Word_Input | Inputs a word.
Word_Output | Outputs a word.

OutputData
The data to be output. (This parameter is only used if the service is called to simulate output.)

This service is called to simulate ring 3 port I/O from a (ring 0) VxD executing in the current VM. It is useful for VxDs that need to alter the state of other VxDs. For example, a VxD could perform a simulated EOI by calling this procedure with:

mov     al, 20h
mov     edx, 20h
mov     ecx, Byte_Output
VMMCall Simulate_VM_IO

Which is the same as a ring 3 VM executing:

mov     al, 20h
out         20h, al


Free Physical Page Management

Free physical pages are unused physical addresses that the VMM can assign to committed pages when they are paged in. The Windows loader initializes the list of free physical pages. If the loader does not find certain pages that are actually available, virtual devices can use VMM services to add these to the free list.

The _AddFreePhysPage service notifies the memory manager of additional physical pages. The _PageResetHandlePAddr service also makes new physical pages available to the memory manager. However, this service simultaneously maps a range of pages in the specified memory block to the new physical pages.

Virtual devices must not attempt to add physical pages that are already under the control of the memory manager. You can determine whether physical pages exist and are recognized by the memory manager by using the _GetPhysPageInfo service.

The system creates linear address aliases for physical memory only when requested through the _MapPhysToLinear service. This is different from Windows 3.1, which created a giant linear address region to alias all of physical memory. (The change is required in order to support machines with more than 16MB of memory.) Therefore, it is imperative that linear address aliases for physical memory always be obtained through calls to _MapPhysToLinear. Do not assume that _MapPhysToLinear(N, 1, 0) is the same as _MapPhysToLinear(0, 1, 0) + N for all values of N. When you create a linear address alias, the second parameter indicates the number of bytes for which an alias is required; it is only for this number of bytes that the mapping of linear addresses to physical addresses remains contiguous. Linear address aliases are valid until the system is shut down.

See Also

_AddFreePhysPage, _GetPhysPageInfo, _MapPhysToLinear, _PageResetHandlePAddr


_AddFreePhysPage

include vmm.inc

VMMCall _AddFreePhysPage, <PhysPgNum, nPages, flags>

mov     [PagesAdded], eax       ; 0 = none, 1 = some, 2 = all

Adds one or more physical pages to the free memory pool. Virtual devices use this service to add pages that the Windows loader could not find, but that the virtual device did find. For example, the V86MMGR device adds any unused physical pages it finds when using the Global EMM Import function of a 386 LIMulator. Uses EAX, ECX, EDX, and Flags.

This service is only available during initialization, and only in Windows version 3.1 and later.

Returns with one of these values in the EAX register:

Value | Meaning
0 | None of the specified physical pages were added to the free pool.
1 | Some, but not all, of the specified physical pages were added.
2 | All of the specified physical pages were added.

PhysPgNum
Physical page number of the first page to add. The page number must be greater than or equal to 110h; only extended memory pages may be added to the pool. The specified pages must be read/write physical memory pages, and must be available for use at any time.
nPages
Number of physical pages to add.
flags
Operation flags. Can be zero or the following value:
Value | Meaning
AFPP_RECEXIT | The physical memory being added will be automatically restored to its original state (original contents, and in an unused and unmapped state) immediately before System_Exit. No more than 32 pages can be added per call using this feature; to add more than 32 pages, make multiple calls.

A virtual device must not attempt to use pages once it has added them to the free pool, or attempt to add pages that are already available to the system.

This service returns an error if the number of pages to add exceeds the limit of the internal data structure the system uses to manage the free pool. The internal data structure is allocated during initialization and cannot be modified.

Most virtual devices do not need to use this service.

See Also

_GetFreePageCount


_GetPhysPageInfo

#include <vmm.h>

ULONG EXTERNAL GetPhysPageInfo(ULONG iPage, ULONG nPages, ULONG flags);

Indicates whether any, all, or none of the specified physical pages exist. This service is available even after initialization, but is pageable, meaning that if it is called after initialization, it may block and/or cause a task-switch before returning. Uses EAX, ECX, EDX, and flags.

Returns PHYSINFO_NONE (0) if the pages are nonexistent, PHYSINFO_SOME (1) if the some of the pages exist, and PHYSINFO_ALL (2) if the all the pages exist.

iPage and nPages
Page number of the first physical page in the range, and the number of physical pages in the range.
flags
Must be zero.


_MapPhysToLinear

include vmm.inc

VMMCall _MapPhysToLinear, <PhysAddr, nBytes, flags>

cmp     eax, 0FFFFFFFFh     ; 0FFFFFFFFh if not addressable
je      not_addressable
mov     [Address], eax      ; address of first byte

Returns the linear address of the first byte in the specified range of physical addresses. Uses EAX, ECX, EDX and Flags.

Returns the ring-0 linear address of the first byte of the physical region, if successful. The EAX register contains 0FFFFFFFFh if the specified range is not addressable.

PhysAddr
32-bit physical address of the start of the region to examine. Physical addresses start at 0, thus the address of physical page 0A0h is 0A0000h.
nBytes
Length of the physical region, in bytes. The service uses this parameter to verify that the entire range is addressable.
flags
Operation flags. Must be zero.

This service is intended to be used to examine device-specific physical memory. Virtual devices must not use this service for any other purpose.

Because physical addresses do not move, the linear address returned by this service remains valid until the system is shut down. Virtual devices should be careful not to use this service in a manner that wastes linear address space.

The following example returns a linear address for 64 kilobytes of memory starting at the physical page 0A0h:

VMMCall _MapPhysToLinear,<0A0000h,10000h,0>

Since physical memory is mapped contiguously, the linear address for page 0A1h is 4096 bytes beyond the return linear address. Note, however, that no information can be concluded about the linear addresses for physical pages 9Fh or 0B0h, because they lie outside the 64KB range requested. If a virtual device needs linear address aliases for those pages, it must call _MapPhysToLinear separately for those pages.


_PageResetHandlePAddr

include vmm.inc

VMMCall _PageResetHandlePAddr, <hMem, PgOff, nPages, PhysPgNum, flags>

or      eax, eax                ; nonzero if substituted, zero if error
jz      not_substituted

Substitutes one or more pages in a memory block with physical pages not previously available to the system. This service is similar to the _AddFreePhysPage service, but allows memory to be used in a slightly different way. Uses EAX, ECX, EDX and Flags.

Returns a nonzero value in the EAX register if successful, zero otherwise.

hMem
Handle (base linear address) of a memory block. This handle must have been previously created using the _PageAllocate or _PageReAllocate service.
PgOff
Offset in pages from the start of the memory block to the first page to be substituted.
nPages
Number of pages to substitute.
PhysPgNum
Number of the first physical page to substitute into the memory block. The page number must be greater than or equal to 110h; only extended memory pages may be added to the block. The specified pages must be read/write physical memory pages, and must be available for use at any time.
flags
Operation flags. Must be 0.

This service is only available for Windows version 3.1 and later.

This service returns an error if the sum of the PgOff and nPages parameters is greater than the size of the memory block.

A virtual device must not attempt to use pages once it has added them to the free pool, or attempt to add pages that are already available to the system.

This service returns an error if the number of pages to add exceeds the limit of the internal data structure the system uses the manage the free pool. The internal data structure is allocated during initialization and cannot be modified.

This service converts pages that are substituted into the block to fixed pages. These pages are always locked, and cannot be unlocked.

This service maps a new physical page in at the specified locations and puts the existing physical memory in the free list. The contents of the freed pages are not preserved.

Most virtual devices do not need to use this service.

See Also

_AddFreePhysPage


Memory Allocation

The following topics describe memory allocation.


Sparse Memory Allocation

A "sparse memory" block is a range of linear addresses in which not all pages are necessarily available for use. The owner of a sparse memory block is responsible for making pages available ("committing") and removing pages ("decommitting"), as it sees fit. Accessing a page which is not committed will raise a protection exception. The sparse memory functions allow a VxD to manage linear address space in roughly the same way as the Win32 "VirtualAlloc" and related functions.

Sparse memory allocation services allocate pages in two steps. First, you reserve a range of pages; then you commit pages as they are needed. Reserving pages sets the corresponding linear addresses aside for a specific purpose, but does not consume any physical storage. Committing pages allocates physical storage for them. Free pages are those that are neither reserved nor committed.

Suppose a virtual device uses a data structure that must be contiguous and that varies in size over time. By reserving a large range of pages, and committing them as needed, the virtual device can efficiently grow the data structure. Because the reserved pages are guaranteed to be available, growing the structure never requires copying it to a new location.

To reserve a range of pages, use the _PageReserve service. Collectively, the pages reserved in a single call to the _PageReserve service comprise a memory block. The base linear address returned by _PageReserve identifies the block. For example, you specify this address when you free the block using the _PageFree service.

To commit pages, use the _PageCommit service. This service allocates physical storage for a range of pages, and enables you to specify whether the pages are fixed (permanently locked) and what their privileges are. (Committing pages fixed rather than locked is more efficient if your VxD will never unlock the pages.) All pages committed at one time must be in the same memory block — that is, they must have been reserved by a single call to the _PageReserve service. To decommit pages, use the _PageDecommit service. Decommitting pages is different from freeing a memory block because the pages remain reserved.

The _PageCommit service allocates physical memory purely on the basis of availability, such that there is no correlation between linear and physical addresses. Virtual device may sometimes require pages to be physically contiguous — for example, when allocating a DMA buffer. Using the _PageCommitContig service, you can commit pages that are physically contiguous, and may also specify a physical alignment and a range of allowable physical addresses.

The _PageCommitPhys service maps a range of pages to the specified physical addresses. The pages are considered committed. However, no physical memory is allocated by this service. That is, the service does not verify that the specified physical addresses are available, and not does update the list of free physical pages. The specified physical addresses must be outside the control of the memory manager, or otherwise under the control of the virtual device. For more information about the memory manager's use of physical memory, see Free Physical Page Management.

See Also

_PageCommit, _PageCommitContig, _PageCommitPhys, _PageDecommit, _PageFree, _PageReserve


Page Allocation

The VMM provides a set of page allocation services that do not separately reserve and commit pages. Internally, these services simply reserve and commit pages in one step by calling the appropriate sparse memory management services.

To allocate pages, use the _PageAllocate service. The service allocates (reserves and commits) a memory block, and returns the block's base linear address. The address is identical to the address returned by the _PageReserve service. To free the memory block, pass the linear address by using the _PageFree service.

You can change the size of a memory block after it is allocated by using the _PageReAllocate service. The service attempts to change the committed size of the object without changing its base address. However, if necessary the service reserves a new memory block and copies the existing pages to it.

To determine the size of a memory block, use the _PageGetSizeAddr service. This service returns the reserved size of the block, which may be greater than the number of committed pages in the memory block. You can get information about the amount of available memory by using the _PageGetAllocInfo and _GetFreePageCount services.

Because these services use the sparse memory management services internally, it is possible to use the two groups of services in combination. For example, you might allocate a memory block using _PageAllocate and then decommit certain pages in that memory block using the _PageDecommit service. However, combining these services is generally not recommended because doing so might break assumptions made by the page allocation services. For example, the _PageReAllocate service assumes that all committed pages in a memory block are contiguous, which may not be the case if sparse memory allocation services have been used on the same region.

See Also

_PageGetAllocInfo, _GetFreePageCount, _PageGetSizeAddr, _PageReAllocate, _PageReserve, _PageFree


Heap Allocation

You can use the system heap to allocate memory objects of any size, rather than allocating in units of pages.

To allocate a memory object on the heap, use the _HeapAllocate service. You can change the size of the memory object using the _HeapReAllocate service and free it using the _HeapFree service. To determine the size of a memory object, use the _HeapGetSize service.

There are three system heaps: the locked heap, the swappable heap, and the init heap. The init heap is discarded at the end of Init_Complete. The locked and swappable heaps remain available as long as the system is running. Memory allocated into the swappable heap is swappable; your VxD must be careful not to access it at a time when paging is not allowed.

The system provides no memory protection for memory objects on the heap. It also does not compact the heap. Therefore, virtual devices should avoid using the heap in such a way as to severely fragment it.

See Also

_HeapAllocate, _HeapFree, _HeapGetSize, _HeapReAllocate


Sparse Memory Allocation Services

Sparse memory allocation services enable virtual devices to allocate pages in two steps: reserving linear addresses, and then committing physical storage as needed.


_PageCommit

#include <vmm.h>

ULONG EXTERNAL _PageCommit(ULONG page, ULONG npages, ULONG hpd,
    ULONG pagerdata, ULONG flags);

Commits physical pages to a range of linear addresses.

Returns a nonzero value if successful, zero otherwise.

page and npages
Linear page number to commit the first physical page to, and the number of pages to commit. The entire range of linear addresses must have been previously reserved by a single call to the _PageReserve service.
hpd
Handle of a registered pager (returned by the _PagerRegister service) or one of these values:
PD_ZEROINIT | Swappable zero-initialized.
PD_NOINIT | Swappable uninitialized.
PD_FIXED | Fixed uninitialized (must also pass in PC_FIXED flag).
PD_FIXEDZERO | Fixed zero-initialized (must also pass in PC_FIXED flag).

pagerdata
A pager-defined 32-bit value to be stored with the page. Must be zero if the hpd parameter does not identify a registered pager.
flags
One or more of the following values:
PC_FIXED | The pages are permanently locked. If you know that the memory will remained locked throughout its lifetime, it is more efficient to use PC_FIXED than PC_LOCKED.
PC_LOCKED | The pages are initially present and locked, but may be unlocked in the future.
PC_LOCKEDIFDP | The pages are locked only if the virtual pageswap device uses MS-DOS or BIOS functions to write pages to the hardware. (Note that in such a case, the pages are locked and not fixed.)
PC_STATIC | The pages are committed even if the linear addresses were reserved using the PR_STATIC flag. If the linear address had been reserved with PR_STATIC and the PC_STATIC flag is not passed to _PageCommit, the function will fail.
PC_USER | The pages are accessible at ring 3.
PC_WRITEABLE | The pages are writeable.
PC_INCR | Increments the pager-defined 32-bit value associated with each page in the specified range.

If the PC_LOCKED, PC_LOCKEDIFDP, or PC_FIXED flag is specified, none of the pages in the range of linear addresses specified by the page and npages parameters can already be committed. If none of these flags are specified, the range can include committed pages; however, recommitting already-committed pages is inefficient and should be avoided.

See Also

_PagerRegister, _PageReserve


_PageCommitContig

#include <vmm.h>

ULONG EXTERNAL _PageCommitContig(ULONG page, ULONG npages, ULONG flags,
    ULONG alignmask, ULONG minphys, ULONG maxphys);

Commits physically contiguous pages to a range of linear addresses. omitting physically contiguous pages is typically required only when interacting with hardware devices that impose external constraints on the physical properties of the memory on which they operate.

Returns the base physical address if successful, –1 otherwise.

page and npages
Linear page number to commit the first physical page to, and the number of pages to commit. The entire range of linear addresses must have been previously reserved by a single call to the _PageReserve service, and none of the linear pages can be already committed. If the PC_NOLIN flag is specified, page is ignored.
flags
Zero or more of these values:
PC_USER | The pages are accessible at ring 3.
PC_WRITEABLE | The pages are writeable.
PCC_ZEROINIT | The pages are zero initialized.
PCC_NOLIN | The pages are not mapped to any linear addresses. If PCC_NOLIN is passed, raw physical pages are allocated and the raw physical address is returned. Pages allocated in this way cannot be freed; they belong permanently to the caller. The PCC_NOLIN flag must not be combined with any of the other flags.

alignmask
Value specifying the physical alignment of the memory. Can be one of these values:
0x00 | 4 K alignment
0x01 | 8 K alignment
0x03 | 16 K alignment
0x07 | 32 K alignment
0x0F | 64 K alignment
0x1F | 128 K alignment

minphys and maxphys
Minimum and maximum physical page numbers for new pages.

The pages allocated will be greater than or equal to minphys and strictly less than maxphys. For example, to ensure that the pages returned will lie below the 16MB boundary, pass minphys=0x0000 and maxphys=0x1000. If you do not wish to impose restrictions on the physical page numbers, pass minphys=0 and maxphys=-1.

This service is typically used when communicating with hardware devices which have peculiar requirements on the physical address on which they operate. The _PageCommit service does not ensure the physical properties of the pages committed.

Pages allocated by this service are allocated as PC_FIXED.


_PageCommitPhys

#include <vmm.h>

ULONG EXTERNAL _PageCommitPhys(ULONG page, ULONG npages, ULONG physpg,
    ULONG flags);

Commits a specified physical page or range of physical pages to a range of linear addresses.

Returns a nonzero value if successful, zero otherwise.

page and npages
Linear page number to commit the first physical page to, and the number of pages to commit. The entire range of linear addresses must have been reserved by a single call to the _PageReserve service, and none of the linear pages can be already committed.
physpg
Physical page number of the first page to commit. All of the physical pages committed must be either outside the control of the memory manager (for example, a memory-mapped device or video memory) or otherwise under the control of the virtual device driver making the call (for example, previously allocated and locked, or obtained by a previous call to PageCommitContig with the PCC_NOLIN flag). By default, all pages in the linear address region are mapped to the page number specified by physpg. To commit a region of physical pages to a corresponding region of linear addresses, use the PC_INCR flag.
flags
One or more of these values:
PC_INCR The linear pages are mapped to an equal number of contiguous physical pages. That is, the physical page number is incremented for each linear page committed.

If this flag is not specified, all of the linear pages are mapped to the same physical page.

PC_USER | The pages are accessible at ring 3.
PC_WRITEABLE | The pages are writeable.

Memory committed through this service should not be touched while processing a hardware interrupt, since the page tables mapping the memory may be swapped out. Calling LinPageLock on the range will lock down any associated page tables and allow safe interrupt-time access.


_PageDecommit

#include <vmm.h>

ULONG EXTERNAL _PageDecommit(ULONG page, ULONG npages, ULONG flags);

Decommits physical storage from a specified range of linear addresses.

Returns a nonzero value if success, zero otherwise.

page and npages
Linear page number of first page to decommit, and the number of pages to decommit. The entire range of linear addresses must have been reserved by a single call to the _PageReserve service.

While the specified range can include pages that are already decommitted, this is not recommended.

flags
Must be zero.


_PageFree

// C syntax
#include <vmm.h>

ULONG EXTERN _PageFree(PVOID hMem, DWORD flags);

// assembler syntax
include vmm.inc

VMMCall _PageFree, <hMem, flags>
or      eax, eax        ; nonzero if freed, zero if error
jz      failed

Frees the specified memory block. Uses EAX.

Returns a nonzero value in the EAX register if successful, zero otherwise.

hMem
Base linear address of the memory block to free. This value must have been returned by the _PageAllocate, _PageReAllocate, or _PageReserve service. You may not free only part of a memory block.
flags
Operation flags. Can be zero or PR_STATIC, which specifies that the memory block being freed was allocated as PC_STATIC. If the memory block was allocated as PC_STATIC, but the PR_STATIC field is not also specified, the free will fail.

Virtual devices that allocate PG_VM or PG_HOOKED pages must free these pages when the associated virtual machine is destroyed. PG_SYS pages do not need to be freed when Windows exits.

If a virtual device maps a memory block into the V86 address space (using the _MapIntoV86 service), it should unmap the memory block before attempting to free it.

It is not an error to free memory which is all or partially locked.

It is not necessary to decommit the memory inside a memory block before freeing it. Freeing a memory block automatically decommits its contents.

See Also

_PageAllocate, _PageReAllocate


_PageReserve

#include <vmm.h>

ULONG EXTERNAL _PageReserve(ULONG page, ULONG npages, ULONG flags);

Reserves a range of linear addresses in the current context without allocating any physical storage.

Returns the linear address of the first reserved page if successful, – 1 otherwise.

page
Linear page number of the start of the range, or one of these values:
PR_PRIVATE | Anywhere in current ring 3 private arena.
PR_SHARED | Anywhere in the ring 3 shared arena.
PR_SYSTEM | Anywhere in the system arena.

If an explicit page is specified, the memory manager attempts to allocate that linear page address. If the linear address is already in use, the service fails.

npages
Number of linear pages to reserve.
flags
Zero or more of these values:
PR_FIXED | Prevents _PageReAllocate from moving the pages.
PR_STATIC | Disallows commit, decommit and free operations unless a static flag is specified.
PR_4MEG | Forces the reserved address to be aligned on a four-megabyte boundary. This flag is ignored if the page parameter specifies a specific address.

Before touching any linear page reserved by this service, you must commit physical storage to the page using the _PageCommit, _PageCommitContig, or _PageCommitPhys service.

See Also

_PageCommit, _PageCommitContig, _PageCommitPhys


Page Allocation Services

Page allocation services allocate blocks of pages, without separately reserving and committing them.


_GetFreePageCount

include vmm.inc

VMMCall _GetFreePageCount, <flags>

mov     dword ptr [FreePages], eax      ; number of free pages
mov     dword ptr [LockablePages], edx  ; number of lockable pages

Returns the number of pages in the free list. This service also returns the number of free pages that can be allocated as locked pages. Uses EAX, ECX, EDX, and flags.

Returns the number of free pages in the EAX register and the number of pages available for allocation as locked pages in the EDX register.

flags
Operation flags. Must be zero.

Virtual devices can allocate pages by using the _PageAllocate, _PageCommit, _PageCommitContig, or _PageCommitPhys service.

In a demand-paged virtual memory system such as Windows, the number of free pages is usually very close to 0, so the count of pages available for locking is usually a better indicator of available memory. However, virtual devices must not rely on the count of free pages being less than or equal to the count of pages to lock. No guarantees can be made about the length of time the information returned by this service remains accurate.

See Also

_PageAllocate


_PageAllocate

// C syntax
#include <vmm.h>

ULONG EXTERN _PageAllocate(ULONG nPages, ULONG pType, ULONG VM,
    ULONG AlignMask, ULONG minPhys, ULONG maxPhys, ULONG *PhysAddr,
    ULONG flags);

; assembler syntax
include vmm.inc

VMMCall _PageAllocate, <nPages, pType, VM, AlignMask, minPhys,
    maxPhys, <OFFSET32 PhysAddr>, flags>

test    eax, eax             ; returns 0 on error
jz      error

mov     [Address], eax       ; linear address of allocated memory block

Allocates a block of memory consisting of the specified number of pages. This service reserves linear address space for the memory block, and depending on the value of the flags parameter, may also map the linear addresses to physical memory, locking the pages in memory. The service returns a memory handle that can be used in subsequent memory management functions to lock, unlock, reallocate, and free the memory block. Uses EAX, ECX, EDX, and flags.

Returns the ring-0 linear address of the memory block (in the EAX register). For compatibility with Windows 3.1, the same value is returned in EDX. For Windows 3.1, EAX was the memory handle and EDX the memory address. For Windows 95, the handle and the linear address are always the same. Both registers are zero if an error occurs, such as insufficient memory.

nPages
Number of pages to allocate for the memory block. This parameter must not be zero.
pType
Value specifying the type of pages to allocate. Must be PG_HOOKED, PG_SYS, or PG_VM. If PG_SYS is specified, the pages are allocated in the system arena. Otherwise, they are allocated in the ring 3 shared arena. There is no real difference between the PG_HOOKED and PG_VM types.
VM
Handle of the virtual machine for which to allocate the pages. This parameter applies to pages allocated using the PG_VM and PG_HOOKED values only. This parameter must be zero if the nType parameter specifies PG_SYS.
AlignMask
Alignment mask that defines acceptable starting page numbers for the memory block. This parameter can be one of the following values:
Value | Meaning
00000000h | Physical address is a multiple of 4K.
00000001h | Physical address is a multiple of 8K.
00000003h | Physical address is a multiple of 16K.
00000007h | Physical address is a multiple of 32K.
0000000Fh | Physical address is a multiple of 64K.
0000001Fh | Physical address is a multiple of 128K.

This parameter is used only if the flags parameter specifies the PAGEUSEALIGN value.

minPhys
Minimum acceptable physical page number in the memory block. All page numbers must be greater than or equal to this value. This parameter is used only if the flags parameter specifies the PAGEUSEALIGN value. To impose no restriction on the minimum page number, pass zero for this parameter.
maxPhys
Maximum acceptable physical page number in the memory block. All page numbers must be less than this value. This parameter is used only if the flags parameter specifies the PAGEUSEALIGN value. To impose no restriction on the maximum page number, pass the value 100000h (4GB) for this parameter. NOTE: If _PageAllocate is called with a maxPhys value of 0xFFFFFFFF, this service does not fail due to the invalid parameter, but instead attempts to allocate the memory below 16MB using a maxPhys value of 0x1000. This behavior can cause _PageAllocate to fail mysteriously, particularly for large memory blocks. If you attempt to allocate a large block, say 16MB (0x1000 pages) of memory and specify a maxPhys value of 0xFFFFFFFF, _PageAllocate will always fail, even if there is sufficient free memory in the system.
Specifying 0xFFFFFFFF for the maxPhys parameter is a common error when failing to recognize that the parameter requires a page number, not a full physical address. Running the debug version of vmm.vxd will display the following messages that are helpful in finding this problem:
PageAllocate: maxphys parameter is greater than 4gig (0x100000)
PageAllocate: maxphys = -1, remapping to 16meg
The maximum value that should be specified for MaxPhys is 0x100000.
PhysAddr
Address of a four-byte buffer that receives the physical address of the start of the memory block. The service uses this parameter only if the flags parameter specifies the PAGECONTIG and PAGEUSEALIGN values. The service ignores this parameter if it is zero.
flags
Operation flags. Can be zero or more of these values:
Value | Meaning
PAGECONTIG | Allocates contiguous physical pages to create the memory block. This value is ignored if the PAGEUSEALIGN value is not also specified.
PAGEFIXED Locks the allocated pages in memory at a fixed linear address, and prevents the pages from subsequently being unlocked or moved. The service locks the memory block regardless of the type of virtual page swap device present.

the page will remain locked throughout its life, use PAGEDFIXED; it's more efficient than PAGELOCKED.

PAGELOCKED | Locks the allocated pages in the memory. The pages can be subsequently unlocked using the _PageUnLock service. The service locks the memory block regardless of the type of virtual page swap device present.
PAGELOCKEDIFDP Locks the allocated pages in the memory only if the virtual page swap device uses MS-DOS or BIOS functions to write to the hardware. If the pages are locked, they can be subsequently unlocked using the _PageUnLock service.

A virtual device must not specify the PAGELOCKEDIFDP value until after it has received the Init_Complete message.

PAGELOCKED and PAGELOCKEDIFDP values are mutually exclusive.

PAGEUSEALIGN | Allocates pages using the alignment and physical addresses specified by the AlignMask, minPhys, and maxPhys parameters. If this value is specified, PAGEFIXED must also be specified.
PAGEZEROINIT | Fills the memory block with zeros. If this value is not given, the contents of the memory block are undefined.

All other values are reserved.

This service reserves linear address space by calling the _PageReserve service, and then commits physical storage by calling the _PageCommit service. The address returned by this service can be used in the same manner as the linear address returned by the _PageReserve service.

Unless the PAGELOCKED, PAGELOCKEDIFDP, or PAGEFIXED value is specified, the allocated pages are not initially present in physical memory. The system maps a page into physical memory (pages it in) when a virtual device attempts to access the page. You can force a page to be present by using the _PageLock service.

Virtual devices use the PAGEUSEALIGN value to allocate buffers for use by the device which have additional alignment restrictions enforced by the hardware. For example, a DMA may require buffers to start at addresses that are a multiple of 64K or 128K. When allocating such buffers, the PAGECONTIG value is often used in combination with PAGEUSEALIGN.

See Also

_PageFree, _PageLock, _PageReAllocate, _PageUnLock


_PageGetAllocInfo

include vmm.inc

VMMCall _PageGetAllocInfo, <flags>

mov     [Lockable], edx     ; count of lockable pages

Returns the number of pages that can be allocated as locked or fixed memory. Uses EAX, ECX, EDX, and Flags.

Returns the number of pages available for allocating as locked pages in the EDX register. The value returned in the EAX register is undefined. (This peculiar return convention is for Windows 3.1 compatibility.)

flags
Operation flags. Must be zero.

Virtual devices must not rely on being able to allocate all pages specified by this service. In general, virtual devices should allocate memory as needed, and not attempt to allocate all available memory.

See Also

_PageAllocate


_PageGetSizeAddr

include vmm.inc

VMMCall _PageGetSizeAddr, <hMem, flags>

test    eax, eax            ; returns zero if error

mov     [Pages], eax        ; number of pages in memory block
mov     [Address], edx      ; ring-0 linear address of memory block

Returns the size and linear address of a memory block. Uses EAX, ECX, EDX, and Flags.

Returns the number of pages in the memory block in the EAX register. For compatibility with Windows 3.1, the ring-0 linear address of the memory block is returned in the EDX register. Both registers are zero if an error occurs. (Under Windows 95, handles and addresses are the same, so the return value in EDX is relatively meaningless.)

hMem
Base linear address of the memory block for which to return information. This parameter may be a handle returned by the _PageAllocate or _PageReAllocate service, or may be a linear address returned by the _PageReserve service.
flags
Operation flags. Must be zero.

The return value specifies the number of reserved pages for the memory block, which may be greater than the number of committed pages. For example, if the _PageReAllocate service is used to reduce the size of a memory block, the number of virtual pages reserved for that block may remain unchanged.

See Also

_PageAllocate, _PageReAllocate


_PageReAllocate

// C syntax
#include <vmm.h>

ULONG EXTERN _PageReAllocate(ULONG hMem, ULONG nPages, ULONG flags);

; assembler syntax

VMMCall _PageReAllocate, <hMem, nPages, flags>

test    eax, eax        ; zero in eax if error
jz      error

mov     [Address], eax  ; new linear address

Resizes and optionally reinitializes an existing memory block. The service can increase or decrease the number of pages in the memory block. Uses EAX, ECX, EDX and flags.

Returns the ring-0 linear address of the block (in the EAX register). For compatibility with Windows 3.1, the same value is returned in the EDX register.

Both registers are zero if an error occurs, such as insufficient memory, an invalid memory address, or the wrong memory type. In this case, the original memory block is unchanged.

hMem
Base linear address of the memory block to reallocate. In most cases, this should be a value returned by the _PageAllocate or _PageReAllocate service. If this parameter is a linear address returned by the _PageReserve service, see the cautions below.
nPages
Number of pages in the reallocated memory block. This parameter must not be zero. To free a memory block, use the _PageFree service.
flags
Operation flags. Can be zero or more of these values:
Value | Meaning
PAGELOCKED | Locks the allocated pages in the memory. The pages can be subsequently unlocked using the _PageUnLock service. The service locks the memory block regardless of the type of virtual page swap device present.
PAGELOCKEDIFDP Locks the allocated pages in memory only if the virtual page swap device uses MS-DOS or BIOS functions to write to the hardware. If the pages are locked, they can be subsequently unlocked using the _PageUnLock service.

A virtual device must not specify the PAGELOCKEDIFDP value until after the Init_Complete message has been processed by all virtual devices.

PAGENOCOPY | Does not preserve contents of existing pages. If this value is not given, the service preserves the contents of each existing page by copying the contents of the old memory block into the corresponding pages of the new block.
PAGEZEROINIT | Fills any new pages with zeros. All existing pages remain unchanged.
PAGEZEROREINIT | Fills all pages, new and existing, with zeros.

All other values are reserved.

This service changes the number of committed pages for the memory block. It attempts to do so without changing the base linear address. If necessary, however, the service reserves a new memory block, copies the old data into it, and then frees the existing memory object.

If you use this service with sparse memory management services, such as _PageReserve, _PageCommit, and _PageDecommit, you must ensure that all committed pages are contiguous and that the first committed page is at the start of the memory block's reserved address range. If pages have been committed sparsely, the service may return an error or free pages unexpectedly. You can reallocate a memory block that has no committed pages. For example, you could call _PageReserve and then _PageReAllocate.

If the specified base linear address identifies a fixed memory block (allocated using the PAGEFIXED value), this service implicitly allocates fixed pages for the new memory block. The service returns an error if the block cannot be reallocated without changing the base linear address.

If the specified base linear address identifies an aligned memory block (allocated using the PAGEUSEALIGN value), this service returns an error.

If the specified base linear address identifies a memory block allocated by _PageReserve with the PR_STATIC flag, this service returns an error.

Virtual devices must never rely on the new and old starting addresses being equal.

The action specified by the PAGELOCKEDIFDP value is available only after the virtual page swap device has been initialized.

See Also

_PageAllocate, _PageFree, _PageLock, _PageReserve, _PageUnLock


Heap Services

Heap allocation services enable virtual devices to allocate memory objects of arbitrary size, rather than in units of pages.


_HeapAllocate

// C syntax
#include <vmm.h>

ULONG EXTERN _HeapAllocate(ULONG nbytes, ULONG flags);

; assembler syntax
include vmm.inc

VMMCall _HeapAllocate, <nbytes, flags>

or      eax, eax            ; zero if error
jz      not_allocated
mov     [Address], eax      ; address of memory block

Allocates a block of memory from the system heap. Uses EAX, ECX, EDX, and flags.

Returns the address of the block in the EAX register if successful, zero otherwise.

nbytes
Specifies the size in bytes of the block to allocate. Must not be zero.
flags
Allocation flags. Can be zero or more of these values.
Value | Meaning
HEAPLOCKEDIFDP | Allocates a memory block in locked memory only if MS-DOS or BIOS functions are used for paging. Otherwise, the memory block is allocated in pageable memory.
HEAPINIT | Allocates a memory block that is automatically freed after initialization. This value can only be specified during initialization.
HEAPSWAP | Allocates a memory block in pageable memory.
HEAPZEROINIT | Fills the memory block with zeros. If this value is not given, the initial content of the memory block is undefined.

All other values are reserved.

Only one of the values HEAPINIT, HEAPSWAP, or HEAPLOCKEDIFDP can be specified. If none of these values is specified, the block is allocated in fixed memory.

This service aligns allocated block on doubleword boundaries, however, the block size does not have to be a multiple of 4.

Since the system offers no protection on the heap, virtual devices must provide their own protection to prevent overrunning allocated blocks.

The system offers no compaction on the heap; all memory blocks on the heap are fixed. Virtual devices must not to use the heap in such a way as to severely fragment it.

See Also

_HeapFree, _HeapReAllocate


_HeapFree

// C syntax
#include <vmm.h>

ULONG EXTERNAL _HeapFree(ULONG hAddress, ULONG flags);

; Assembler syntax
include vmm.inc

VMMCall _HeapFree, <hAddress, flags>

or      eax, eax            ; nonzero if freed, zero if error
jz      not_freed

Frees an existing memory block in the system heap. Uses EAX, ECX, EDX, and Flags.

Returns a nonzero value in the EAX register if successful, zero otherwise.

hAddress
Address of the memory block to free. This address must have been previously returned by the _HeapAllocate or _HeapReAllocate service.
flags
Operation flags. Must be 0.

Although the system can usually recover from an attempt to free an invalid address, you should not rely on this.

See Also

_HeapAllocate, _HeapReAllocate


_HeapGetSize

// C syntax
#include <vmm.h>

ULONG EXTERNAL _HeapGetSize(ULONG hAddress, ULONG flags);

; assembler syntax
include vmm.inc

VMMCall _HeapGetSize, <hAddress, flags>

or      eax, eax        ; zero if error
jz      error
mov     [Size], eax     ; size in byte of memory block

Returns the size, in bytes, of an existing block in the system heap. Uses EAX, ECX, EDX, and Flags.

Returns the of the block in the EAX register if successful, zero otherwise.

hAddress
Address of the memory block. This address must have been previously returned by the _HeapAllocate or _HeapReAllocate service.
flags
Operation flags. Must be 0.

Although the system can usually recover from an attempt to get the size of an invalid address, you should not rely on this.

See Also

_HeapAllocate


_HeapReAllocate

//C syntax
#include <vmm.h>

ULONG EXTERNAL _HeapReAllocate(ULONG hAddress, ULONG nbytes, ULONG flags);

; assembler syntax
include vmm.inc

VMMCall _HeapReAllocate, <hAddress, nbytes, flags>

or      eax, eax        ; zero if error
jz      error
mov     [Address], eax  ; address of reallocated block

Reallocates or reinitializes a memory block in the system heap. Uses EAX, ECX, EDX, and Flags.

Returns the address of the reallocated block in the EAX register if successful, zero otherwise.

hAddress
Address of the memory block. This address must have been previously returned by the _HeapAllocate or _HeapReAllocate service.
nbytes
New size, in bytes, of the block. Must not be zero.
flags
Allocation flags. Can be zero or more of these values:
Value | Meaning
HEAPNOCOPY | Does not preserve contents of existing bytes. If this value is not given, the service preserves the contents of existing bytes by copying the contents of the old memory block into the new block.
HEAPZEROINIT | Fills any new bytes in the memory block with zeros. All existing bytes remain unchanged.
HEAPZEROREINIT | Fills all bytes, new and existing, with zeros.

All other values are reserved.

If this service is successful, it frees the old memory block, making the old address invalid. Virtual devices must never rely on the old and new addresses being the same. If this service returns an error, the old memory block is not freed and the old address remains valid.

Since the system offers no protection on the heap, virtual devices must provide their own protection to prevent overrunning allocated blocks.

The system offers no compaction on the heap; all memory blocks on the heap are fixed. Virtual devices must not use the heap in such a way as to severely fragment it.

Although the system can usually recover from an attempt to reallocate an invalid address, you should not rely on this.

See Also

_HeapAllocate, _HeapFree


Page Mapping and Address Spaces

The following topics describe page mapping and address spaces.


Pages and Page Translation

The 32-bit linear address space used by the Intel 80386 and later microprocessors is divided into 4 kilobyte units called pages. Each page can be assigned specific permissions, and can be mapped to any 4K section of physical memory. The base physical address of a page is its page frame address. A page can also be marked not present, in which case it does not map to any physical memory.

Page mapping is possible because of page translation, the mechanism by which the CPU translates linear addresses to physical addresses. A linear address can be viewed as a combination of two values: a 20-bit page number, and a 12-bit offset (4K = 2 bytes). The CPU uses the page number to locate a page descriptor, which contains a page frame address and other information. Adding the offset to the page frame address yields a physical address. A page that is marked not present does not map to any physical address. Attempting to access such a page triggers a page fault. Typically, a page is marked not present if has been temporarily swapped out to disk or if no physical storage has been allocated for the page. In addition, virtual devices may mark a hooked page as not present in order to trigger a page fault every time the page is accessed. The system does something similar for instanced pages. Page descriptors are organized into page tables. By creating more than one set of page tables, the system can define more than one address space, each with a unique mapping of pages to physical storage. Virtual devices should not manipulate page tables directly. (Doing so is virtually guaranteed to result in incompatibilities with future versions of Windows.) However, a virtual device can use VMM services to get information about the current address space and to change the way pages are mapped to physical storage.


Arenas

The system divides the linear address space into four areas, called arenas, each of which is managed differently.

The DOS arena spans linear addresses in the range MINDOSLADDR through MAXDOSLADDR, and is used for virtual machines (VMs). The DOS arena is itself divided into several areas. For more information about the DOS arena, see V86 Address Space Mapping and Allocation.

The private arena spans linear addresses in the range MINPRIVATELADDR through MAXPRIVATELADDR. This arena is used for code and data that is private to a Win32 process. The mapping of pages in this arena to physical storage depends on the current memory context, as does which pages are reserved.

The shared arena spans linear addresses in the range MINSHAREDLADDR through MAXSHAREDLADDR. This arena is used for ring-3 shared code and data, such as 16-bit Windows applications and DLLs, DPMI memory, and 32-bit system DLLs. The mapping of pages in this arena does not depend on the current VM or memory context.

The system arena spans linear addresses in the range MINSYSTEMLADDR through MAXSYSTEMLADDR. This arena is used for code and data for the VMM and virtual devices.

The last four megabytes of the linear address space is permanently invalid and is not part of any arena. Because zero is a valid address, you should use an address in this permanently invalid region to denote an invalid pointer. To be extra safe, you can use the value 0xFFFE0000, which lies right in the middle of the invalid region.

See Also

_GetNulPageHandle


Memory Contexts

The system uses memory contexts to create a private linear address space for each Win32 application. The current memory context determines the mapping of pages in the private arena, the linear address range from MINPRIVATELADDR through MAXPRIVATELADDR.

Most memory context services are for the exclusive use of the system. Virtual devices should only use the _GetCurrentContext service.

To access data in the private arena from a different memory context or at interrupt time, map the data to globally addressable pages by using the _LinPageLock service with the PAGEMAPGLOBAL flag. Do not change the current context for this purpose.

See Also

_GetCurrentContext, _LinPageLock


Page Locking and Mapping

A virtual device cannot access swappable pages while processing hardware interrupts because doing so may trigger a page fault. A virtual device can avoid page faults by committing pages as fixed, or by temporarily locking pages when necessary — for example, during a device input or output operation. Locking a page forces it to remain physically present at a fixed address until it is unlocked.

You can lock a range of pages by using the _LinPageLock service. The pages remain locked until they are unlocked using the _LinPageUnLock service. The system maintains a lock count for each page. Thus, you can lock a page more than once. You must unlock a page once for each time it is locked unless you specify the PL_TOTALUNLOCK flag to bring the lock count to zero. (But don't use the PL_TOTALUNLOCK flag. It is mentioned here only for completeness.)

You can specify the PAGELOCKEDIFDP flag with the _LinPageLock service, in which case the pages are locked only if the pager uses MS-DOS or BIOS functions to perform file operations. You should use this flag for pages that need to be touched while a virtual device owns the critical section. Because MS-DOS is not reentrant, it cannot be called while the critical section is owned. For the same reason, VxD_PAGEABLE_CODE_SEG and VxD_PAGEABLE_DATA_SEG segments are automatically locked when MS-DOS is used for paging.

Warning You cannot call memory manager services while any virtual machine holds the critical section, unless you ensure that MS-DOS is not used for paging. For more information about critical sections, see Synchronization.

If a virtual device must access a range of pages in the private arena regardless of the current memory context, it must map the pages to a range linear addresses outside the private arena. To do so, use the _LinPageLock service with the PAGEMAPGLOBAL flag. When you unlock the pages using the _LinPageUnlock service, you must specify the same flag to undo the mapping. You must also pass the global alias as the page to unlock rather than the original private page. Failure to observe either of these two rules will leak critical system memory and eventually crash the machine.

You can use the _PageLock and _PageUnLock services to lock a range of pages. However, these services are more difficult to use than the _LinPageLock and _LinPageUnLock services, and offer no performance advantage. Also, you cannot map pages into shared memory by using the _PageLock service. The _PageLock and _PageUnLock services exist primarily for compatibility with Windows 3.1 virtual devices.

Do not attempt to lock uncommitted pages. You can verify that all pages in a given range are committed by using the _PageCheckLinRange service. Locking pages that were committed as fixed has no effect, but consumes just as much time as locking swappable pages.

In addition to the services described here, the VMM provides services for mapping pages into VMs. For more information about such services, see V86 Address Space Mapping and Allocation. For information about services that convert selector:offset addresses to linear addresses, see Selector Management.

See Also

_LinPageLock, _LinPageUnLock, _PageLock, _PageUnLock, _PageCheckLinRange


Miscellaneous Page Management Services

A virtual device must not modify page tables directly. However, a virtual device can retrieve a copy of a page table to analyze. To do so, use the _CopyPageTable service.

Virtual device drivers (VxDs) which need to communicate with hardware devices may have need to convert a linear address (such as one provided by an application) into a physical address.

To convert a linear address into a physical address

  1. Lock the memory to prevent its physical address from changing. This can typically be accomplished via the LinPageLock() service.
  2. Use CopyPageTable() to access the page table information, which includes the physical address.
  3. Use the values obtained in step (2) to program the hardware device.
  4. When the physical address is no longer needed (when the I/O operation has completed), unlock the memory (typically via LinPageUnlock()). Note that once the pages have been unlocked, the values obtained in step (2) are no longer valid.

Example:

; This code fragment illustrates how a linear address can be converted

; to a physical address.

;

; It converts the 3 pages starting at pgStart to a physical address.

; (Page numbers are equal to linear addresses shifted right by 12.

; One page is equal to 4K.)

;

    sub    esp, 3 * 4        ; temporary buffer for CopyPageTable

    VMMCall    _LinPageLock, <pgStart, 3, 0>

    test    eax, eax

    jz    error            ; could not lock the memory

    mov    esi, esp

    VMMCall    _CopyPageTable, <pgStart, 5, esi, 0>

    test    eax, eax

    jz    errorUnlock        ; unexpected error

                    ; go straight to unlock

;

;    Use the values obtained by CopyPageTable. For this sample,

;    we merely print them to the debugging terminal.

;

    mov    eax, [esi][0]

    and    eax, NOT 0FFFh

    Trace_Out "Page pgStart is at physical address #EAX"

    mov    eax, [esi][4]

    and    eax, NOT 0FFFh

    Trace_Out "Page pgStart+1 is at physical address #EAX"

    mov    eax, [esi][8]

    and    eax, NOT 0FFFh

    Trace_Out "Page pgStart+2 is at physical address #EAX"

;

;    We are now finished with the physical addresses. Release

;    the lock to tell the memory manager that it's okay to move

;    the pages in memory again.

;

errorUnlock:

    VMMCall    _LinPageUnlock, <pgStart, 3, 0>

error:

    add    esp, 3 * 4        ; clean the stack
;
; This code fragment illustrates how a linear address can be converted
; to a physical address.
;
; It converts the 3 pages starting at pgStart to a physical address.
; (Page numbers are equal to linear addresses shifted right by 12.
; One page is equal to 4K.)
;
    sub    esp, 3 * 4        ; temporary buffer for CopyPageTable

    VMMCall    _LinPageLock, <pgStart, 3, 0>
    test    eax, eax
    jz    error            ; could not lock the memory

    mov    esi, esp
    VMMCall    _CopyPageTable, <pgStart, 5, esi, 0>
    test    eax, eax
    jz    errorUnlock        ; unexpected error
                    ; go straight to unlock
;
;    Use the values obtained by CopyPageTable.  For this sample,
;    we merely print them to the debugging terminal.
;

    mov    eax, [esi][0]
    and    eax, NOT 0FFFh
    Trace_Out "Page pgStart is at physical address #EAX"

    mov    eax, [esi][4]
    and    eax, NOT 0FFFh
    Trace_Out "Page pgStart+1 is at physical address #EAX"

    mov    eax, [esi][8]
    and    eax, NOT 0FFFh
    Trace_Out "Page pgStart+2 is at physical address #EAX"

;
;    We are now finished with the physical addresses.  Release
;    the lock to tell the memory manager that it's okay to move
;    the pages in memory again.
;
errorUnlock:
    VMMCall    _LinPageUnlock, <pgStart, 3, 0>

error:
    add    esp, 3 * 4        ; clean the stack

To retrieve high-level information about a range of pages, use the _PageQuery function.

Each committed page has a specific set of permissions, which determine whether the page can be written to and whether it is accessible in user mode (ring 3). To change the permissions for a range of pages, use the _PageModifyPermissions service.

Because zero is a valid address, you should use an address in the permanently invalid region of linear address space to denote an invalid pointer.

See Also

_CopyPageTable, _GetNulPageHandle, _PageModifyPermissions, _PageQuery


Obsolete Memory Management Services

The following services are obsolete. If called, they immediately return zero in the EAX register:

_GetGlblRng0V86IntBase _MapFreePhysReg _SetFreePhysRegCalBk _UnmapFreePhysReg _XchgFreePhysReg

In addition, the _GetSysPageCount and _GetVMPgCount services do not return meaningful values, and the _GetSetPageOutCount and _PageOutDirtyPages services have been deleted.


Memory Context Services

Memory context services control the mapping of pages in the private arena. With the exception of the _GetCurrentContext service, these services are for the exclusive use of the VMM, and are documented here only to satisfy the reader's curiosity.


_ContextCreate

#include <vmm.h>

PVOID EXTERNAL _ContextCreate(void);

Creates a new memory context. The tasking and scheduling component uses this service to create a private linear address space for a new Win32 application. Do not call this service.

  • Returns the handle of the new context if successful, zero otherwise.

The private linear address space corresponds to linear addresses in the range MINPRIVATELADR through MAXPRIVATELADDR. A memory context is destroyed using the ContextDestroy service.

See Also

_ContextDestroy


_ContextDestroy

#include <vmm.h>

ULONG EXTERNAL _ContextDestroy(PCD hcd);

Destroys a memory context created by the _ContextCreate service. Do not call this service.

Returns a nonzero value if successful, zero otherwise.

hcd
Zero to free the private memory in the current context, or the handle of the dying context to perform final clean-up.

To destroy a memory context, this service must be called twice. The first call must be from within the dying memory context, and the hcd parameter must be zero. The second call must be from a different context, and the hcd parameter must be the handle of the dying context.

See Also

_ContextCreate


_ContextSwitch

#include <vmm.h>

PVOID EXTERNAL _ContextSwitch(PVOID hcd);

Changes the current memory context. The current memory context determines the mapping of pages in the private arena. Do not call this service.

Returns the handle of the outgoing context.

hcd
Context handle returned by the _ContextCreate service.

See Also

_ContextCreate


_GetCurrentContext

#include <vmm.h>

PVOID EXTERNAL _GetCurrentContext(void);

Determines the current memory context. Do not call this service.

Returns the handle of the current context.

See Also

_ContextSwitch


_PageAttach

#include <vmm.h>

ULONG EXTERNAL _PageAttach(ULONG page, PCD hcontextsrc, ULONG npages);

Maps a range of linear pages in the current memory context to the same physical storage that those pages are mapped to in a specified context (the source context). Do not call this service.

Returns a nonzero value if successful, zero otherwise.

page and npages
Linear page number of the first page to map, and the number of pages to map.
hcontextsrc
Handle of the source memory context.

This service should only be called by the Win32 program loader, which uses it to map the pages containing a program image from one context into another.

The pages in the source context must be committed, and the pages in the current context must be reserved but not committed. After _PageAttach is called, the pages in the current context can be regarded as committed pages — for example, they can be decommitted, freed, or mapped into another memory context.


Page Locking and Mapping Services

Page locking and mapping services are used to make a range of swappable pages physically present, or to make a range of private pages available in any memory context.


_LinPageLock

include vmm.inc

VMMCall _LinPageLock, <page, npages, flags>
or      eax, eax                ; nonzero if locked, zero if error
jz      not_locked

#include <vmm.h>

ULONG EXTERNAL _LinPageLock(ULONG page, ULONG npages, ULONG flags);

Locks one or more pages starting at the specified linear page number. Locking a page forces it to become physically present and to remain so until it is unlocked. This service is similar to the _PageLock service. Uses EAX, ECX, EDX, and Flags.

Returns a nonzero value if successful, zero otherwise. If the PAGEMAPGLOBAL flag is specified, the successful return value is the base linear address of the new linear mapping.

page and npages
Linear page number of the first page in the range, and the number of pages in the range. All of the pages in the range must be committed.
flags
Zero or one of these values:
PAGELOCKEDIFDP | Lock the pages only if the virtual pageswap device uses MS-DOS or BIOS functions to write pages to the hardware.
PAGEMAPGLOBAL | Map a global linear address to the locked range so that the memory can be accessed out of the current context. Cannot be specified with PAGELOCKEDIFDP.
PAGEMARKDIRTY | Mark the pages as if they have been written to. This flag is intended for a VxD that needs to modify the pages, but the CPU doesn't recognize the modifications. For example, the CPU may not recognize DMA write operations, or write operations using the address returned when the PAGEMAPGLOBAL flag is used.

A page can be locked more than once, in which case it must be unlocked once for each time it is locked. Unlock pages using the _LinPageUnLock service.

See Also

_LinMapIntoV86, _LinPageUnLock, _PageLock


_LinPageUnLock

include vmm.inc

VMMCall _LinPageUnLock, <page, npages, flags>
or      eax, eax         ; nonzero if successful, zero otherwise
jz      not_unlocked

#include <vmm.h>

ULONG EXTERNAL _LinPageUnLock(ULONG page, ULONG npages, ULONG flags);

Unlocks one or more pages starting at the specified linear page number. This service is similar to the _PageUnLock service. Uses EAX, ECX, EDX, and Flags.

Returns a nonzero value if successful, zero otherwise.

page and npages
Linear page number of the first page to unlock, and the number of pages to unlock. All of the pages in the range must be committed. If freeing a global alias, these must describe the location and size of the alias and not the originally locked address.
flags
Zero or one of these values:
PAGELOCKEDIFDP | Unlock the pages only if the virtual pageswap device uses MS-DOS or BIOS functions to write pages to the hardware.
PL_TOTALUNLOCK | Bring lock count to zero. This flag should only be used by the SetResetV86Pageable service.
PAGEMAPGLOBAL | This flag must be used to delete a global linear mapping created by a previous call to the _LinPageLock service. If this flag is specified, the value of the page parameter must be the linear address that was returned by _LinPageLock, but shifted by 12 bits to the right.

See Also

_LinPageLock, _PageUnLock, _SetResetV86Pageable


_PageCheckLinRange

include vmm.inc

VMMCall _PageCheckLinRange, <page, nPages, flags>

mov     [Pages], eax    ; number of committed pages at start of range

#include <vmm.h>

ULONG EXTERNAL _PageCheckLinRange (ULONG page, ULONG npages,
    ULONG flags);

Determines whether all pages in the specified range of linear addresses are committed. Uses EAX, ECX, EDX, and Flags.

Returns the actual number of contiguous committed pages in the EAX register. In particular, the return value is zero if the first page in the specified range is not committed.

page
Page number of the first page to check. A page number is a ring-0 linear address shifted right by 12 bits.
nPages
Number of pages to check.
flags
Operation flags. Must be zero.

Virtual devices typically use this service to validate an address range before specifying the range in a call to the _LinPageLock or _LinMapIntoV86 service.

See Also

_LinMapIntoV86, _LinPageLock


_PageLock

include vmm.inc

VMMCall _PageLock, <hMem, nPages, PageOff, flags>

or      eax, eax        ; nonzero if locked, zero if error
jz      not_locked

Locks one or more pages in the specified memory block. Uses EAX, ECX, EDX, and Flags.

Returns a nonzero value in the EAX register if successful, zero otherwise.

hMem
Handle (base linear address) of the memory block that contains the pages to lock. This value have been previously returned by the _PageAllocate, _PageReAllocate, or _PageReserve service.
nPages
Number of pages to lock.
PageOff
Offset in pages from the start of the memory block to the first page to lock.
flags
Operation flags. Can be zero or the PAGELOCKEDIFDP value. All other values are reserved.

If the PAGELOCKEDIFDP value is specified, pages are locked only if the virtual swap device uses MS-DOS or BIOS functions to write pages to the hardware. The PAGELOCKEDIFDP value cannot be used until after the Init_Complete message has been processed.

The _LinPageLock service is the preferred method of locking pages.

This service returns an error if the sum of the PageOff and nPages parameters is greater than the number of pages in the memory block.

This service has no effect on memory blocks allocated using the PAGEFIXED value; such memory is always locked.

Virtual devices must not assume that the requested number of pages can always be locked.

Each page in a memory block has an individual lock count. This service increments the lock count each time the page is locked, and decrements the count each time the page is unlocked. The lock count must be zero for the page to be unlocked. This means that if the handle is locked 5 times, it has to be unlocked 5 times. Virtual devices must not leave handles locked when not needed.

See Also

_PageAllocate, _PageUnLock


_PageUnLock

include vmm.inc

VMMCall _PageUnLock, <hMem, nPages, PageOff, flags>

or      eax, eax            ; nonzero if unlocked, zero if error
jz      not_unlocked

Unlocks one or more pages in the specified memory block. Uses EAX, ECX, EDX, and Flags.

Returns a nonzero value in the EAX register if successful, zero otherwise.

hMem
Handle (base linear address) of the memory block that contains the pages to unlock. This value have been previously returned by the _PageAllocate, _PageReAllocate, or _PageReserve service.
nPages
Number of pages to unlock.
PageOff
Offset in pages from the start of the block to the first page to unlock.
flags
Operation flags. Can be zero or more of these values:
Value | Meaning
PAGELOCKEDIFDP Unlocks pages only if the virtual page swap device use MS-DOS or BIOS functions to write to the hardware. If the virtual page swap device writes directly to the hardware, this service returns immediately without unlocking the pages.

PAGELOCKEDIFDP value cannot be used until after the Init_Complete message has been processed.

PAGEMARKPAGEOUT | Marks pages for immediate swapping, if this service sets the lock count for the pages to zero. This service marks the pages by clearing the P_ACC bit for each page. The PAGEMARKPAGEOUT value should only be used if the pages are unlikely to be accessed for some time.

All other values are reserved.

This service returns an error if the sum of the PageOff and nPages parameters is greater than the number of pages in the memory block. It also returns an error if the specified pages are not already locked.

Each page in a memory block has an individual lock count. This service increments the lock count each time the page is locked, and decrements the count each time the page is unlocked. The lock count must be zero for the page to be unlocked. This means that if the handle is locked 5 times, it has to be unlocked 5 times. Virtual devices must not leave handles locked when not needed.

See Also

_PageLock


Miscellaneous Page Management Services

Miscellaneous page management services enable you to analyze pages, set page permissions, specify that pages are no longer in use, and get a handle to the system nul page.


_CopyPageTable

include vmm.inc

VMMCall _CopyPageTable, <LinPgNum, nPages, <OFFSET32 PageBuf>, flags>

mov     [Copied], eax           ; nonzero if copied, zero otherwise

Copies one or more page-table entries to the specified buffer. Virtual devices, such as the virtual DMA device, use this service to analyze the mapping of linear to physical addresses. Uses EAX, ECX, EDX, and Flags.

Returns a nonzero value in the EAX register if the copy is successful, zero otherwise. The return value is zero if at least one of the specified page table entries was in a region where the corresponding page directory entry is not present. If zero is returned, the contents of the output buffer are undefined.

LinPgNum
Number of the first page table entry to copy. This parameter must be in the range 0 through 0FFFFFh. Numbers in the range 0 through 10Fh specify pages in the 1 megabyte V86 address space of the current virtual machine. Page numbers for other virtual machines can be computed using the CB_High_Linear field in the control block of each virtual machine.
nPages
Number of page-table entries to copy.
PageBuf
Address of the buffer to receive the page-table entries. This buffer must be large enough to receive the specified number of entries. Each entry is 4 bytes.
flags
Operation flags. Must be zero.

This service copies the page table, so writing to the buffer does not affect the content of the actual page table. The system does not update the buffer when changes to the actual page table are made, so no guarantees are made about the length of time the information in the buffer remains accurate.


_GetNulPageHandle

include vmm.inc

VMMCall _GetNulPageHandle

mov     [NulPage], eax          ; handle of system nul page

Returns the memory handle of the system nul page. This page can be mapped to unused regions of the address space to prevent page faults. The system nul page can be mapped to multiple locations in the system, so its contents are always random. Uses EAX.

Returns the memory handle of the system nul page in the EAX register.

The null page handle is the one exception to the otherwise uniform rule that memory handles and memory addresses are the same. The handle returned by _GetNulPageHandle can be used in the following (and only in the following) ways: It can be passed as the source page handle in _MapIntoV86, or as the source physical page for _PageCommitPhys, in order to map or commit null pages. As a special case, you can also pass the null page handle to _PageGetSizeAddr, although the return value is not entirely meaningful.

See Also

_MapIntoV86, _PageCommitPhys, _PageGetSizeAddr


_PageModifyPermissions

#include <vmm.h>

ULONG EXTERNAL _PageModifyPermissions(ULONG page, ULONG npages,
    ULONG permand, ULONG permor);

Modifies the permissions for pages in the specified range. Uses EAX, ECX, EDX and Flags.

Returns the previous permissions of the first page in the range if successful, –1 otherwise. If an error occurs, the service returns without modifying any permissions.

page and npages
Linear page number if the first page in the range, and the number of pages in the range. All of the specified pages must be committed. None of the pages may be static unless the permor parameter specifies the PC_STATIC flag.
permand
AND mask to combine with the existing permissions for each page. Can be PC_USER, PC_WRITEABLE, or both. To withhold a permission, do not specify the corresponding flag.
permor
OR mask to combine with the existing permissions for each page. Can be PC_USER, PC_WRITEABLE, or both. To grant a permission, specify the corresponding flag. To change the permissions of static pages, this parameter must also include the PC_STATIC flag.

For more information about permission flags, see the description of the _PageCommit service.

See Also

_pagecommit


_PageQuery

#include <vmm.h>

ULONG EXTERNAL _PageQuery(ULONG pbase,
    PMEMORY_BASIC_INFORMATION pmbi,     ULONG cbmbi);

Retrieves information about a range of virtual pages. This service carries out the work for the _VirtualQuery function in the Win32 API. Uses EAX, ECX, EDX and Flags.

Returns the count of bytes filled in return structure (0 if error)

pbase
Linear address of the first page in the range. This address is rounded down to the nearest page boundary. The range includes all consecutive pages starting at this address that share the following attributes:
  • The pages share the same state: committed, reserved, or free.
  • If the initial page is not free, all pages were reserved by the same call to the _PageReserve service.
  • The pages share the same read and write privileges: read-only, read-write, or no access.
pmbi and cbmbi
Address of a MEMORY_BASIC_INFORMATION structure that receives information about the range of pages, and the size of the structure in bytes.


Pagers

A pager is a component or body of code that the VMM calls to move pages in and out of memory. Every committed page is associated with a pager except for hooked pages, instanced pages, and pages committed using _PageCommitPhys. Virtual devices can register pagers by using VMM services. Additional services enable virtual devices to immediately write pages to the swap file, or to discard pages that no longer contain valid information.

A pager is defined by a PD (pager descriptor) structure. This structure contains the addresses of pager functions. The VMM calls pager functions when a page needs be moved in or out of memory (paged in or out). The VMM calls other pager functions when it detects that a page has been accessed, and when a page is decommitted.

The VMM has four internal pagers that correspond to the following page types: fixed zero-initialized, swappable zero-initialized, fixed initialized, and swappable initialized. Fixed pages are paged in when committed, and are never paged out.

A virtual device can register a pager by using the _PagerRegister service. The VWIN32 device registers pagers to support memory mapped files. The service returns a handle that can be specified when pages are committed. To deregister a pager, use the _PagerDeregister service. To retrieve information about an existing pager, use the _PagerQuery service.

Registered pages that use MS-DOS functions to perform file operations must be able to do so during hardware interrupt processing. A file is identified by a file handle and a PSP. Any PSP created after Windows starts is instanced, and therefore may not be addressable by MS-DOS when a hardware interrupt occurs. Therefore, a virtual device must use the Get_PSP_Segment service to retrieve a PSP that is in global memory. It can then initialize the PSP with appropriate values and use nested execution services to call MS-DOS functions.

A virtual device can force a range of committed pages to be immediately paged out by using the _PageFlush service. This service calls the appropriate pager function to page out each page, but the pages remain present.

When referring to a page, the term "virgin" means that the page contents have never been altered. Virgin pages typically do not need to be paged out because they can always be regenerated, either by doing nothing (for uninitialized pages), zero-initialization (for zero-initialized pages), or by reading from a disk file (for demand-paged executables). The term "tainted" refers to a page whose contents have been altered. Tainted pages typically need to be saved to disk (either in the swap file or to a memory-mapped file) because their contents cannot be regenerated otherwise.

If the content of a range of pages is invalid or does not need to be preserved, you can discard the pages by using the _PageDiscardPages service. The pages remain committed, but are considered virgin pages. Therefore, they are not written to disk when they are next paged out, and are not read from disk when they are next paged in. Optionally, the pages can immediately be made not present.

See Also

Get_PSP_Segment, _PageDiscardPages, _PageFlush, _PagerDeregister, _PagerQuery, _PagerRegister, PD


_PageChangePager

include vmm.h

ULONG EXTERNAL PageChangePager(ULONG Page, ULONG nPages, ULONG hpd,
    ULONG pagerdata, ULONG flags)

Changes the pager or pager data for a range of pages. This service should only be used to modify the information for pages and pagers under the control of the caller. Uses EAX, ECX, EDX and Flags.

Returns a non-zero value if successful, zero otherwise.

Page
Linear page number of the first page to modify. All pages of the specified range must be committed and within the same memory object.
nPages
Number of pages to modify.
hpd
Handle of the page descriptor to set in each of the pages in the range. This parameter is used only if the PCP_CHANGEPAGE flag is specified.
pagerdata
New value to store in the page data double-word of each page in the range. This parameter is used only if the PCP_CHANGEPAGERDATA flag is specified.
flags
Operation flags. Can be one or more of these values:
PCP_CHANGEPAGER | Change the pager for the specified range of pages. The hpd parameter specifies the handle of the page descriptor to set in each of the pages.
PCP_CHANGEPAGERDATA | Store the pagerdata value in the page data double-word of each page in the range.
PCP_VIRGINONLY | Change only virgin pages.
PC_INCR | Increment the specified pager data for each page in the range before storing it.

If PCP_CHANGEPAGER is specified, the old pager's pd_taintedfree or pd_virginfree callback function is called, just as if the pages had been decommitted.

See Also

pd


_PageDiscardPages

#include <vmm.h>

ULONG EXTERNAL _PageDiscardPages(ULONG Page, ULONG VM, ULONG nPages,
    ULONG flags);

Marks pages as not recently accessed, making them more likely page-out candidates. The pages can optionally be marked discarded as well, which reverts them to a virgin state, avoiding the need even to page them out. Uses EAX, ECX, EDX, and Flags.

Returns a nonzero value in the EAX register if successful, zero otherwise.

Page
Linear page number of the first page to mark as page-out candidates. All pages of the specified range must be committed. If the pages are associated with a virtual machine, they must be marked V86Pageable.
VM
Handle of the virtual machine containing the pages to mark as page-out candidates. This parameter is required if the Page parameter is less than 110h; otherwise it is ignored.
nPages
Number of pages to mark as page-out candidates.
flags
Operation flags. Can be zero or more of these values:
Value | Meaning
PAGEDISCARD | Immediately makes the pages not present. If this value is not specified, the page remains present but is marked not recently accessed.
PAGEZEROINIT | Fills the pages with zeros when they are next paged in. This value is ignored unless PAGEDISCARD is also specified. If this value is not given, the content of the pages is undefined. See the following comments section for additional remarks.

All other values are reserved.

It is an error to attempt to discard pages that are not committed. This service ignores pages that are not present (that is, already paged out) or are locked (and cannot be paged out). This service affects only pages that are subject to demand paging.

The PAGEDISCARD flag causes the system to revert the pages to their virgin state as well as removing the pages from memory. The PAGEZEROINIT flag may only be passed for pages that were originally allocated as normal swappable memory, either uninitialized or zero-initialized; that is, PD_ZEROINIT or PD_NOINIT. It is an error to attempt to PAGEZEROINIT pages that belong to any other type of pager (because they won't know what to do).

See Also

_SetResetV86Pageable


_PageFlush

#include <vmm.h>

ULONG EXTERNAL _PageFlush(ULONG page, ULONG npages);

Writes a range of committed pages to the backing file by calling the appropriate pager function. This service does not mark the pages as not-present.

Returns a nonzero value if successful, zero otherwise.

page, npages
Linear page number of the first page to write, and the number of pages to write.


_PagerDeregister

#include <vmm.h>

ULONG EXTERNAL _PagerDeregister(ULONG hpd)

Informs the system that a type of pager is no longer used. All pages using this pager should be freed before calling this service.

Returns a nonzero value if successful, zero otherwise.

hpd
Handle of the registered pager to deregister.


_PagerQuery

#include <vmm.h>

ULONG EXTERNAL _PagerQuery(ULONG hpd, PPD ppd);

Retrieves information about a registered pager.

Returns a nonzero value if successful, zero otherwise.

hpd
Handle of the registered pager.
ppd
Address of a PD structure that receives information about the pager.

See Also

PD


_PagerRegister

#include <vmm.h>

ULONG EXTERNAL _PagerRegister(PPD ppd);

Inform system of a new type of pager.

Returns the handle of the registered pager if success, zero otherwise.

ppd
Address of a PD structure containing information about the pager. The system makes its own copy of the structure.

The handle returned by this service may be passed to the _PageCommit service, thus placing the committed pages under the control of the registered pager.

See Also

_PageCommit, PD


PD

#include <vmm.h>

typedef ULONG _cdecl FUNPAGE(PULONG ppagerdata, PVOID ppage,
    ULONG faultpage);
typedef FUNPAGE *PFUNPAGE;

typedef struct pd_s {
    PFUNPAGE pd_virginin;
    PFUNPAGE pd_taintedin;
    PFUNPAGE pd_cleanout;
    PFUNPAGE pd_dirtyout;
    PFUNPAGE pd_virginfree;
    PFUNPAGE pd_taintedfree;
    PFUNPAGE pd_dirty;
    ULONG pd_type;
} PD, *PPD;

Pager-descriptor structure. Contains pointers to a pager's callback functions, and information about the overcommit characteristics of the pages the pager manages.

pd_virginin and pd_taintedin
Addresses of the pager functions that the system calls swap a page into memory. If the page has never been written to, the system calls the function specified by the pd_virginin member; otherwise it calls the function specified by the pd_taintedin member.

These functions must return a nonzero value if successful, or zero otherwise. The parameters have the following meanings:
ppagerdata | Address of a pager-defined 32-bit value stored with the virtual page. The pager can modify this value during page in and out operations, but not at other times.
ppage | Ring-zero physical address of the page.
faultpage | Linear page number that triggered a page fault. A pager should not attempt to access this page number. Note that the same page can be mapped to more than one linear address.

pd_cleanout and pd_dirtyout
Addresses of the pager functions that the system calls to swap a page out of memory. If the page has not been written to since it was last paged out, the system calls the function specified by the pd_cleanout member; otherwise it calls the function specified by the pd_dirtyout member.

These functions must return a nonzero value if successful, or zero otherwise. The parameters have the following meanings:
ppagerdata | Address of a pager-defined 32-bit value stored with the virtual page. The pager can modify this value during page in and out operations, but not at other times.
ppage | Ring-zero physical address of the page.
faultpage | Always – 1.

pd_virginfree and pd_taintedfree
Addresses of the pager functions that the system calls when the last reference to a virtual page controlled by the pager is decommitted. If the page has never been written to since it was committed, the system calls the function specified by the pd_virginfree member; otherwise it calls the function specified by the pd_taintedfree member.

The return value of these functions is ignored. The parameters have the following meanings:
ppagerdata | Address of a pager-defined 32-bit value stored with the virtual page. The pager can modify this value during page in and out operations, but not at other times.
ppage | Ring-zero physical address of the page if it is in memory, NULL otherwise.
faultpage | Linear page number of the page being decommitted.

pd_dirty
Address of the pager function that the memory manager calls when it detects that a page has been written to. If a page is dirtied in more than one memory context, this function is called once for each context.

The return value of this function is ignored. The parameters have the following meanings:
ppagerdata | Address of a pager-defined 32-bit value stored with the virtual page. The pager can modify this value during page in and out operations, but not at other times.
ppage | Undefined.
faultpage | Linear page number of the dirtied page.

pd_type
Value specifying the overcommit characteristics of the pages associated with this pager. Can be one of these values:
PD_SWAPPER | Pages controlled by this pager may be paged out.
PD_PAGERONLY | Pages controlled by this pager are never paged out to the swap file. If this value is specified, the VMM calls the pager's virgin-in function as soon as a page is committed; the tainted-in and page-out functions are never called.

See Also

_PagerRegister


Selector Management

Previous Next

Selector

A selector identifies a protected-mode segment. The VMM provides services for creating and destroying selectors, and for converting between selector:offset and flat addresses. Because virtual devices use a flat memory model, these services are used primarily to share memory with 16-bit protected mode applications.

Each segment has a base linear address, limit, and specific permissions. The limit (size) is measured either in bytes or pages depending on the segment's granularity. The properties of a segment are contained in a hardware-defined data structure called a segment descriptor.

Segment descriptors are contained in two arrays called the global descriptor table (GDT) and the local descriptor table (LDT). There is only one GDT, whereas there is a different LDT for each protected mode virtual machine (VM). If bit 2 (value 4) of a selector is zero, the selector is an index into the GDT; otherwise it is an index into the current LDT.

Virtual devices should not modify the GDT or LDT directly. To define a new segment, use the _Allocate_GDT_Selector or _Allocate_LDT_Selector service. You can modify a segment descriptor by using the _SetDescriptor service. For example, you might allocate multiple selectors and then use the _SetDescriptor service to change the base address and limit associated with all but the first selector. You can retrieve the descriptor associated with a selector by using the _GetDescriptor service. To free a selector, use the _Free_GDT_Selector or _Free_LDT_Selector service.

A segment descriptor is a 64-bit structure consisting of several bit fields. You can use the _BuildDescriptorDWORDs service to initialize a selector, rather than performing the necessary bit field operations yourself. You can use the return value of this service when you allocate or change a descriptor.

You can give an application read-only access to system data without allocating a selector. The _GetAppFlatDSAlias service returns a selector that maps the entire linear address space. The selector has read-only access to ensure system integrity. To give an application read-write access to system data, you should allocate a selector with an appropriate base address and limit.

A virtual device can convert a selector:offset address to a flat linear address by using the _SelectorMapFlat service.

See Also

_GetAppFlatDSAlias, _GetDescriptor, _SelectorMapFlat, _SetDescriptor, _Allocate_GDT_Selector, _Allocate_LDT_Selector, _BuildDescriptorDWORDs, _Free_GDT_Selector, _Free_LDT_Selector


Selector Allocation Services

The following topics describe the selector allocation services.


_Allocate_GDT_Selector

include vmm.inc

VMMCall _Allocate_GDT_Selector, <DescDWORD1, DescDWORD2, flags>

mov     ecx, eax                    ; zero in eax and edx if error
or      ecx, edx
jz      error

mov     [Selector], eax             ; new selector
mov     word ptr [GDTSel], dx       ; selector for the GDT
ror     edx, 10h
mov     word ptr [SelCount], dx     ; number of selectors in GDT

Creates a new selector and adds it to the Global Descriptor Table (GDT). Uses EAX, ECX, EDX, and Flags.

Returns the following values in the EAX and EDX registers if successful:

Register | Description
EAX | Contains the new selector.
EDX | Contains the selector for and the size of the GDT. The low 16 bits contains the selector for the GDT, and the high 16 bits contains the size of the GDT expressed as the number of selectors in the table.

The service returns zero in both registers if an error occurs.

DescDWORD1
High-order doubleword of the segment descriptor. This parameter contains the high 16 bits of the base address, the high 4 bits of the limit, and the status and type bits.
DescDWORD2
Low-order doubleword of the segment descriptor. This parameter contains the low 16 bits of the base address and limit.
flags
Operation flags. Must be 0.

Although this service returns the selector for the GDT, virtual devices should not attempt to edit the GDT directly. Virtual devices can instead use the _SetDescriptor service to change selectors in the GDT.

Virtual devices should use the _BuildDescriptorDWORDs service to set the DescDWORD1 and DescDWORD2 parameters to the appropriate values.

This service sets the RPL of the selector to the DPL of the selector set in the DescDWORD1 parameter.

See Also

_Allocate_LDT_Selector, _Free_GDT_Selector


_Allocate_LDT_Selector

include vmm.inc

VMMCall _Allocate_LDT_Selector, <VM, DescDWORD1, DescDWORD2,
    Count, flags>

Creates a new selector or selectors, and adds them to the Local Descriptor Table (LDT) for the specified virtual machine. Uses EAX, ECX, EDX, and Flags.

Returns the following values in the EAX and EDX registers if successful:

Register | Description
EAX | Contains the new selector. If Count is greater than 1, EAX contains only the first selector. The second selector is EAX+8, the third EAX+16, and so on. The high 16 bits of the selector are always zero.
EDX | Contains the selector for and the size of the local descriptor table (LDT). The low 16 bits contains the selector for the LDT, and the high 16 bits contains the size of the LDT expressed as the number of selectors in the table.

The service returns zero in both registers if an error occurs

VM
Handle of the virtual machine to receive the selectors.
DescDWORD1
High-order doubleword of the segment descriptor. This parameter contains the high 16 bits of the base address, the high 4 bits of the limit, and the status and type bits.
DescDWORD2
Low-order doubleword of the segment descriptor. This parameter contains the low 16 bits of the base address and limit.
Count
Number of contiguous LDT selectors to allocate if the flags parameter does not specify the ALDTSpecSel value. Otherwise, this parameter specifies the LDT selector to allocate.
flags
Specifies the operation flags. Can be zero or the following value:
Value Meaning
ALDTSpecSel Allocates the LDT selector specified by the Count parameter. The service copies the descriptor data to the specified LDT entry and returns the selector. If the LDT selector is already allocated, the service returns an error value instead.

this value is not given, the service allocates the number of selectors specified by Count.

All other values are reserved.

The service returns an error if an invalid descriptor is specified, the LDT is full, an invalid virtual machine handle is specified, or a selector is already allocated.

Although this service returns a selector for the LDT, virtual devices should not attempt to edit the LDT directly. A virtual device should use the _SetDescriptor service to change an LDT selector rather than edit the LDT.

This service sets the RPL of the selector to the DPL of the selector set in the DescDWORD1 parameter.

LDT selectors are only valid when the virtual machine for which they are created is the current virtual machine. However, a virtual device can use the _SelectorMapFlat service to examine the region described by an LDT selector in virtual machines that are not the current virtual machine.

Although this service can create multiple selectors, the _Free_LDT_Selector service cannot free multiple selectors. Multiple selectors must be freed individually.

When this service creates multiple selectors, it gives each selector the same descriptor values. It does not change the base address for each selector. It is up to the virtual device to edit the selectors, and assign appropriate base addresses.

Virtual devices should not rely on specific hard-coded LDT selectors, and therefore, they should avoid using the ALDTSpecSel value.

See Also

_Allocate_GDT_Selector, _Free_LDT_Selector


_BuildDescriptorDWORDs

include vmm.inc

VMMCall _BuildDescriptorDWORDs, <DESCBase, DESCLimit, DESCType, DESCSize, flags>

mov     [DescDWORD1], edx       ; high doubleword of descriptor
mov     [DescDWORD2], eax       ; low doubleword of descriptor

Builds the descriptor parameter used in calls to the _Allocate_GDT_Selector and _Allocate_LDT_Selector services. Uses EAX, ECX, EDX, and Flags.

Returns the low-order doubleword of the segment descriptor in the EAX register and the high-order doubleword in the EDX register.

DESCBase
32-bit value specifying the segment's linear base address.
DESCLimit
20-bit value specifying the segment limit.
DESCType
Present bit, DPL, and type fields for the descriptor (bits 8–15 of the high doubleword). All bits except bits 0 – 7 of this parameter must be zero.
DESCSize
Granularity and big/default fields for the descriptor (bits 20–23 of the high doubleword). All bits except bits 4 – 7 of this parameter must be zero.
flags
Operation flags. Can be zero or the following value:
Value | Meaning
BDDExplicitDPL | Uses the DPL bits in the DESCType parameters. If this value is not given, the service sets the DPL bits to be equal to the RPL bits for protected-mode applications.

All other values are reserved.

Virtual devices must not rely on the privilege level at which protected-mode applications run. When creating selectors for protected-mode applications, a virtual device should not specify the BDDExplicitDPL value. This provides a convenient way to build descriptors without knowing the protection level for protected-mode applications.

See Also

_Allocate_GDT_Selector, _Allocate_LDT_Selector


_Free_GDT_Selector

include vmm.inc

VMMCall _Free_GDT_Selector, <Selector, flags>

or      eax, eax            ; nonzero if freed, zero if error
jz      not_freed

Frees a GDT selector previously allocated using the _Allocate_GDT_Selector service. Uses EAX, ECX, EDX, and Flags.

Returns a nonzero value in the EAX register if successful, zero otherwise.

Selector
Selector to free. The selector must have been previously created using the _Allocate_GDT_Selector service.
flags
Operation flags. Must be 0.

Certain system selectors cannot be freed since they are required for Windows operation. (Remember, free only those selectors created by calling _Allocate_GDT_Selector.) This service ignores the RPL bits of the selector.

See Also

_Allocate_GDT_Selector, _Free_LDT_Selector


_Free_LDT_Selector

include vmm.inc

VMMCall _Free_LDT_Selector, <VM, Selector, flags>

Frees a LDT selector previously allocated using the _Allocate_LDT_Selector service. Uses EAX, ECX, EDX, and Flags.

Returns a nonzero value in the EAX register if successful, zero otherwise.

VM
Handle of the virtual machine to which the selector belongs.
Selector
Selector to free. The selector must have been previously created using the _Allocate_LDT_Selector service.
flags
Operation flags. Must be 0.

This service ignores the RPL bits of the selector.

See Also

_Allocate_LDT_Selector, _Free_GDT_Selector


Miscellaneous Selector Services

The following topics describe the miscellaneour selector services.


_GetAppFlatDSAlias

include vmm.inc

VMMCall _GetAppFlatDSAlias

mov     [FlatData], eax         ; read-only GDT selector

Returns a ring-3, read-only, GDT selector that provides access to the same memory as the system's ring-0 data segment selector. Virtual devices use this service to support protected-mode APIs that let protected-mode applications read from the same memory as the virtual device. Uses EAX.

Returns the selector in the EAX register.

Since more than one virtual device may use this selector, a virtual device must never attempt to free the selector using the _Free_GDT_Selector service. Also, a virtual device should not attempt to create a read/write selector using this selector. If a virtual device requires an application to write to any portion of system memory, the virtual device should build its own selector with a base and limit that specifies just the memory the application must modify.

See Also

_Free_GDT_Selector


_GetDescriptor

include vmm.inc

VMMCall _GetDescriptor, <Selector, VM, flags>

mov     ecx, eax                ; zero in eax and edx if error
or      ecx, edx
jz      error

mov     [DescDWORD1], edx       ; high doubleword of descriptor
mov     [DescDWORD2], eax       ; low doubleword of descriptor

Retrieves a copy of the descriptor associated with the given LDT or GDT selector. Uses EAX, ECX, EDX, and Flags.

Returns the low-order doubleword of the descriptor in the EAX register and the high-order doubleword in the EDX register. Both registers contain zero if an error occurs.

Selector
GDT or LDT selector.
VM
Handle of the virtual machine to which the specified LDT selector belongs. This parameter is ignored if the Selector parameter is a GDT selector.
flags
Operation flags. Must be 0.

This service ignores the high 16-bits of the Selector parameter; the 80386 CPU often sets these bits to random values when doubleword operations are performed on segment registers.

This service ignores the RPL bits of the selector.

See Also

_BuildDescriptorDWORDs, _SetDescriptor


_SelectorMapFlat

include vmm.inc

VMMCall _SelectorMapFlat, <VM, Selector, flags>

cmp     eax, 0FFFFFFFFh         ; 0FFFFFFFFh if error
je      error
mov     [Address], eax          ; base address of selector

Returns the base linear address of segment identified by the specified GDT or LDT selector. Uses EAX, ECX, EDX, and Flags.

Returns the base linear address in the EAX register if successful, 0FFFFFFFFh otherwise.

VM
Handle of the virtual machine to which the specified selector belongs. This parameter is not used if Selector is a GDT selector. This parameter must be valid for LDT selectors.
Selector
GDT or LDT selector.
flags
Operation flags. Must be 0.

The address mapper uses this service to convert pointers, consisting of selector and offset pairs, to flat-model linear addresses suitable for use as parameters for the _LinMapIntoV86 service.

This service ignores the high 16 bits of the Selector parameter; the 80386 CPU often sets these bits to somewhat random values when doubleword operations are performed on segment registers.

See Also

_LinMapIntoV86


_SetDescriptor

include vmm.inc

VMMCall _SetDescriptor, <Selector, VM, DescDWORD1, DescDWORD2, flags>

or      eax, eax        ; nonzero if set, zero if error
jz      not_set

Sets (changes) the descriptor associated with the given selector. Uses EAX, ECX, EDX, and Flags.

Returns a nonzero value in the EAX register if successful, zero otherwise.

Selector
GDT or LDT selector to set.
VM
Handle of the virtual machine to which the specified LDT selector belongs. This parameter is ignored if the Selector parameter is a GDT selector.
DescDWORD1
High-order doubleword of the new segment descriptor. This parameter contains the high 16 bits of the base address, the high 4 bits of the limit, and the status and type bits.
DescDWORD2
Low-order doubleword of the new segment descriptor. This parameter contains the low 16 bits of the base address and limit.
flags
Operation flags. Must be 0.

This service ignores the high 16-bits of the Selector parameter; the 80386 CPU often sets these bits to random values when doubleword operations are performed on segment registers.

The service ignores the RPL bits of the selector.

See Also

_GetDescriptor


System-Internal Memory Management

System-internal memory management services are used internally, and should not be used by virtual devices. They are as follows:

Service | Description
_GetDemandPageInfo | Retrieves information used for demand paging.
_MMGR_Toggle_HMA | Enables or disables the HMA.
_SetLastV86Page | Sets last page in V86 address space.
Set_Physical_HMA_Alias | Sets the physical HMA alias.


_GetDemandPageInfo

include vmm.inc

VMMCall _GetDemandPageInfo, <<OFFSET32 DemandInfo>, flags>

Retrieves information used for demand paging, copying the information to the specified structure. This service is for exclusive use by the virtual paging device. Uses Flags.

No return value.

DemandInfo
Address of a DemandInfoStruc structure containing information for demand paging.
flags
Operation flags. Must be zero.


_MMGR_Toggle_HMA

include vmm.inc

VMMCall _MMGR_Toggle_HMA, <VM, flags>

cmp     flags, MMGRHMAQuerry
jne     did_toggle
mov     [HMAState], eax     ; 0 if disabled, 1 if enabled

did_toggle:
or      eax, eax           ; nonzero if enabled/disabled, zero if error
jz      error

Enables or disables the high memory area (HMA). The V86MMGR XMS device uses this service to control the state of the HMA for a specified virtual machine, and to notify the instance data manager that the state is changing. If your virtual device needs to toggle the HMA, use the V86MMGR_Toggle_HMA service instead of this one. This service is for exclusive use by the V86MMGR XMS device. Uses EAX.

Returns a value in the EAX register, the meaning of which depends on the operation specified by the flags parameter. If the flags parameter specifies the MMGRHMAEnable or MMGRHMADisable operation, the service returns a nonzero if successful, zero otherwise.

If the flags parameter specifies the MMGRHMAQuerry operation, the service returns a nonzero value if the HMA is enabled, and zero if disabled.

VM
Handle of the virtual machine.
flags
Operation flags. Can be one or more of these values:
Value | Meaning
MMGRHMADisable | Disables the HMA, causing addresses greater than 1 megabyte to be wrapped back to addresses in pages 0 through 0Fh.
MMGRHMAEnable Enables the HMA, allowing addresses greater than 1 megabyte to access pages 100h through 10Fh. If the MMGRHMAPhysical value is given, the service maps physical pages 100h through 10Fh into the linear pages 100h through 10Fh for the virtual machine, enabling the global HMA for this virtual machine and which all virtual machines share.

the MMGRHMAPhysical value is not given, the service marks the linear pages 100h through 10Fh as not present system pages. To prevent a system crash when these pages are accessed, the virtual device must provide its own physical pages to map into these linear pages. This effectively creates a local HMA that is specific to the given virtual machine.

MMGRHMAQuerry | Returns the current state of the HMA for the virtual machine.
MMGRHMAPhysical | Specifies whether the service maps physical pages 100h through 10Fh into the HMA or expects the virtual device to map some other physical pages into the area. The value is used only if the MMGRHMAEnable value is also given.

The MMGRHMAEnable, MMGRHMADisable, MMGRHMAQuerry values are mutually exclusive.

All other values are reserved.

This service can fail if the MMGRHMAEnable and MMGRHMAPhysical values are given, but the system is already using the physical pages 100h through 10Fh for some other purpose.

A virtual device must not call this service unless it has already used the _Assign_Device_V86_Pages service to assign the pages 100h through 10Fh to itself. For this reason, this service is intended to be used by one and only one virtual device.

When the system creates a virtual machine, it disables the HMA and causes the virtual machine to operate like an 8086 processor. To override this default, the virtual device responsible for the HMA must enable the HMA while processing the VM_Critical_Init message.

Virtual devices must not identify instance data in the HMA.

See Also

_Assign_Device_V86_Pages, VM_Critical_Init


_SetLastV86Page

include vmm.inc

VMMCall _SetLastV86Page, <PgNum, flags>

or      eax, eax            ; nonzero if set, zero if error
jz      not_set

Sets the page number of the last page in V86 memory for the current virtual machine. This service is intended for exclusive use by the virtual V86 memory manager device, and is only available for Windows version 3.1 or later. Uses EAX.

Returns a nonzero value in the EAX register if successful, zero otherwise.

PgNum
New linear page number for the last V86 page.
flags
Operation flags. Must be zero.

This service is intended to help the V86MMGR support backfill machines. These machines have unused, unoccupied memory from the end of MS-DOS memory (typically at 512K) up to 640K (page 0A0h). On such machines, it is desirable to fill out (backfill) this unoccupied space so that virtual machines provide memory up to 640k.

See Also

_GetLastV86Page


Set_Physical_HMA_Alias

include vmm.inc

mov     esi, Entries        ; points to page-table entries for physical HMA alias
VMMCall Set_Physical_HMA_Alias

Defines an HMA alias for pages 100h through 10Fh. This service is for the exclusive use of the XMS driver, a part of the virtual V86MMGR device, and is only available during initialization. Uses EAX, ECX, EDI, ESI, Flags.

No return value.

Entries
Address of an array of 16 page-table entries, which define the physical HMA alias.

This service does not map new pages into the HMA. Instead, the virtual device must call the _MMGR_Toggle_HMA service with the MMGRHMAPhysical value after the calling this service. This service specifies which pages are mapped when the MMGRHMAPhysical value is specified in a call to the _MMGR_Toggle_HMA service.

See Also

_MMGR_Toggle_HMA


DemandInfoStruc

include vmm.inc

DemandInfoStruc struc
DILin_Total_Count  dd  ?          ; pages in linear addr. space
DIPhys_Count       dd  ?          ; see below
DIFree_Count       dd  ?          ; see below
DIUnlock_Count     dd  ?          ; see below
DILinear_Base_Addr dd  ?          ; always zero
DILin_Total_Free   dd  ?          ; see below
DIPage_Faults      dd  ?          ; total page faults
DIPage_Ins         dd  ?          ; calls to pagers to page in
DIPage_Outs        dd  ?          ; calls to pagers to page out
DIPage_Discards    dd  ?          ; calls to pagers to discard
DIInstance_Faults  dd  ?          ; instance page faults
DIPagingFileMax    dd  ?          ; see below
DIPagingFileInUse  dd  ?          ; see below
DICommit_Count     dd  ?          ; total committed pages
DIReserved         dd  2 DUP (?)  ; reserved; do not use
DemandInfoStruc ends

The DemandInfoStruc structure contains information about pages that are subject to demand paging. The _GetDemandPageInfo service fills in the members of this structure.

DIPhys_Count
Specifies the total number of physical pages managed by the memory manager.
DIFree_Count
Specifies the number of pages currently in the free pool.
DIUnlock_Count
Specifies the number of pages that are currently unlocked. Free pages are always unlocked.
DILin_Total_Free
Total number of free virtual pages in the current memory context. This value includes only pages in the private arena, the linear address range controlled by the memory context services.
DIPagingFileMax
Current maximum size of the swap file, in pages. This member is zero if swapping is turned off.
DIPagingFileInUse
Number of swap file pages currently in use. This value reflects the number of pages by which physical memory is overcommitted. It is zero if swapping is turned off or if physical memory is available for all swappable pages.

See Also

_GetDemandPageInfo


V86 Address Space Mapping and Allocation

There are the following V86 address space mapping and allocation services:

_Add_Global_V86_Data_Area
_AddInstanceItem
_Allocate_Device_CB_Area
_Allocate_Global_V86_Data_Area
_Allocate_Temp_V86_Data_Area
_Assign_Device_V86_Pages
_Deallocate_Device_CB_Area
_DeAssign_Device_V86_Pages
_Free_Temp_V86_Data_Area
_Get_Device_V86_Pages_Array
_GetFirstV86Page
_GetInstanceInfo
_GetLastV86Page
_GetV86PageableArray
_LinMapIntoV86
_MapIntoV86
_ModifyPageBits
_PhysIntoV86
_SetResetV86Pageable
_TestGlobalV86Mem
Hook_V86_Page
InstDataStruc
Unhook_V86_Page


HMA and Address Wrapping

In real mode or V86 mode it is possible to form a linear address as large as 10FFEFh (FFFF0h + FFFFh), or roughly 1MB + 64K. On the 8086, which has only 20 address lines, linear addresses greater than 1MB wrap to first 64K of physical memory. Incredibly, some software designed for the 8086 relies on this behavior.

The largest address that can be formed in V86 mode is FFFF:FFFF, which is equivalent to the linear address 10FFEFh (FFFF0h + FFFFh).


Instanced Pages

An instanced page is a page that contains both global and local data. At any given time, a instanced page is marked present for one VM, and not present for all other VMs.


Structure of the DOS Arena

The DOS arena is the range of linear addresses from MINDOSLADDR through MAXDOSLADDR, and is used for virtual machines (VMs). The DOS arena is divided into several areas, paralleling the organization of memory under MS-DOS in real mode. The following illustration shows the structure of the DOS arena: The V86 global area is used for MS-DOS system code, device drivers, and TSRs. Pages in the global area are mapped such that linear and physical addresses are identical. Data in the global area that is not shared by all VMs must be instanced using the _AddInstanceItem service.

The V86 private area is used for MS-DOS application code and data. Pages in this address range are mapped to different physical storage for each VM. The first page of the V86 private area depends on the size of the V86 global area. To get the page numbers of the first and last pages in the V86 private area, use the _GetFirstV86Page and _GetLastV86Page services.

The V86-Mode Memory Manager (V86MMGR) manages the pages in the V86 private area. During device initialization, the V86MMGR assigns the pages to itself by using the _Assign_Device_V86_Pages service.

Video memory is managed by the video display device (VDD). The VDD assigns the pages in this range to itself during device initialization. It then installs its own page fault handler for the pages by using the Hook_V86_Page service.

The VM control block heap is used by virtual devices to allocate memory that is local to each VM. To allocate memory from the VM control block heap, use the _Allocate_Device_CB_Area service.

See Also

_AddInstanceItem, _Allocate_Device_CB_Area, _Assign_Device_V86_Pages, Hook_V86_Page, _GetFirstV86Page, _GetLastV86Page


Memory Mapping and Hooked Pages

The _Assign_Device_V86_Pages service assigns to a virtual device one or more pages of the V86 address space.

The _DeAssign_Device_V86_Pages service frees a region in the V86 address space that was previously assigned using the _Assign_Device_V86_Pages service.

The _Get_Device_V86_Pages_Array service gets a copy of the assignment array used by the _Assign_Device_V86_Pages and _DeAssign_Device_V86_Pages services.

The _LinMapIntoV86 service maps one or more pages into the V86 address space of the specified virtual machine.

The _MapIntoV86 service maps one or more pages of a memory block into the V86 address space of the specified virtual machine.

The _PhysIntoV86 service maps the specified physical pages in the V86 address space.

The _GetInstanceInfo service retrieves a value indicating whether the given VM address range is fully instanced, partially instanced, or not instanced.

The _TestGlobalV86Mem service tests whether a V86 address range is global, local, or instanced.

The _GetFirstV86Page service gets the page number of the first page in the current virtual machine.

The _GetLastV86Page service gets the page number of the last page of V86 memory in the current virtual machine.

The Hook_V86_Page service installs a callback procedure to handle faults for the specified page.

The _ModifyPageBits service modifies the page attribute bits for pages in the V86 address space of a virtual machine.


Memory Allocation for Virtual Machines

The _Allocate_Device_CB_Area service allocates an area in the control block of the current virtual machine for exclusive use by the virtual device.

The _Add_Global_V86_Data_Area service adds a region to the list of regions available for allocation as global V86 data areas.

The _Allocate_Global_V86_Data_Area service allocates a block of memory from the global V86 data area.

The _Allocate_Temp_V86_Data_Area service allocates a block of memory from the global V86 data area.

The _Free_Temp_V86_Data_Area service frees a block allocated using the _Allocate_Temp_V86_Data_Area service.


_Add_Global_V86_Data_Area

include vmm.inc

VMMCall _Add_Global_V86_Data_Area, <LinAddr, nBytes, flags>

or      eax, eax        ; nonzero if added, zero if error
jz      not_added

Adds a region to the list of regions available for allocation as global V86 data areas. This service is only available during initialization, and only for Windows version 3.1 or later. Uses EAX, ECX, EDX, Flags.

Returns a nonzero value in the EAX register if successful, zero otherwise.

LinAddr
Linear address of the first byte of the region. This address must be less than 100000h, and must not lie between the first and last V86 page for the specified virtual machine.
nBytes
Size of the region, in bytes.
flags
Operation flags. Must be zero.

This service supports virtual devices, such as the virtual MS-DOS manager and the V86MMGR device, which can manage high memory above the last V86 page. The service lets these devices add available regions that would otherwise go unused. Typically, such regions are non-page-aligned fragments that cannot be used for normal operations requiring page-aligned memory.

Calls to this service should be made during processing of the Sys_Critical_Init message. Virtual devices should not wait for the Device_Init or Init_Complete messages because most of the allocation of global V86 data areas is done while processing the Device_Init message.

If this service adds a region that is above the last V86 page, virtual devices should not attempt to allocate the region until the Sys_Critical_Init message has been processed.

See Also

_Allocate_Global_V86_Data_Area


_AddInstanceItem

include vmm.inc

VMMCall _AddInstanceItem, <<OFFSET32 InstStruc>, flags>

or      eax, eax        ; nonzero if added, zero if error
jz      not_added

Identifies a region of instance data in the V86 address space. Uses EAX, ECX, EDX, and Flags.

Returns a nonzero value in the EAX register if successful, zero otherwise.

InstStruc
Address of an InstDataStruc structure containing information about the block of memory to instance.
flags
Operation flags. Must be zero.

To prevent errors, a virtual device must not change the location and content of any InstDataStruc structures until after the system has completed its initialization. To achieve this, a virtual can either statically allocate the structures in its INIT data segment or dynamically allocate the structures on the system heap using the _HeapAllocate service. If the structures are in the INIT data segment, the system automatically frees the structure when it reclaims the INIT segment space. If the structures are in the system heap, the virtual device must free the structures using the _HeapFree service while processing the Sys_VM_Init message.

If a virtual device the structures on the system heap, it must not attempt to reallocate the structure before system initialization has completed because this invalidates the structure address.

Only one, contiguous region of instance data can be identified with each structure. The virtual device can cut down the call overhead and data space requirements by coalescing adjacent blocks of instance data and identifying the coalesced blocks as a single instance item.

See Also

InstDataStruc


_Allocate_Device_CB_Area

include vmm.inc

VMMCall _Allocate_Device_CB_Area, <nBytes, flags>

or      eax, eax        ; zero if error
jz      not_allocated

mov     [Offset], eax   ; offset from start of control block to new area

Allocates an area in the control block of all virtual machines for exclusive use by the virtual device. Virtual devices typically uses this service to allocate space to store data that is specific to a given virtual machine. This service is only available during initialization. Unlike Windows 3.1 which restricted this service to initialization, Windows 95 supports this service after initialization. Uses EAX, ECX, EDX, and Flags.

Returns, in the EAX register, the offset of the new area relative to the start of the control block, if successful. The EAX register is zero if an error occurs, such as insufficient memory to satisfy the request.

nBytes
Number of bytes to allocate.
flags
Operation flags. Must be zero.

If this service returns an error, the virtual device should consider this a fatal error and respond accordingly.

Although this service aligns the new area on a doubleword boundary and rounds the nBytes parameter up to the next multiple of 4, the virtual device must not rely on this behavior.

The service fills the newly allocated area with zeros. When the system creates a new virtual machine, it fills all bytes of the control block with zeros.

See Also

_Deallocate_Device_CB_Area


_Allocate_Global_V86_Data_Area

include vmm.inc

VMMCall _Allocate_Global_V86_Data_Area, <nBytes, flags>

or      eax, eax        ; zero if error
jz      error
mov     [Address], eax  ; ring-0 linear address of block

Allocates a block of memory from the global V86 data area. The block is for exclusive use by the virtual device. Virtual devices use this service to allocate memory for device-specific objects that must be accessible to both the virtual device and software running in the virtual machine. This service is only available during initialization. Uses EAX, ECX, EDX, and Flags.

Returns the ring-0 linear address of the block in the EAX register if successful, zero otherwise.

If GVDAInquire is given, EAX contains the size in bytes of the largest block that satisfies the request, but that does not move the first V86 page. EAX contains zero if all such requests move the first V86 page.

nBytes
Number of bytes to allocate. This parameter should be a multiple of 4096.
flags
Operation flags. Can be zero or more of these values:
Value | Meaning
GVDADWordAlign | Aligns block on a doubleword boundary. If no alignment value is given, the service aligns the block on a byte boundary.
GVDAHighSysCritOK Informs the service that the virtual device can manage a block that resides in high MS-DOS memory. The service allocates from high MS-DOS memory only if such memory is available (for example, implemented as XMS UMBs) and the virtual device specifies this value. A virtual device can use this value only while processing the Sys_Critical_Init message.

When first allocated, a block in high MS-DOS memory may not be immediately usable since memory supporting the area may not yet have been mapped. The system maps the memory for the area at some time during the Sys_Critical_Init message, but there is no guarantee as to when.

GVDAHighSysCritOK value is only available for Windows version 3.1 or later.

GVDAInquire Returns the size in bytes of the largest block that satisfies the requested alignment but does not require the first V86 page to be moved. The nBytes parameter is not used if this value is specified.

A virtual device typically uses this value, while processing the Init_Complete message, to allocate portions of the global V86 data area that might otherwise go unused. The GVDAInquire value is only available for Windows version 3.1 or later.

GVDAInstance | Creates an instance data block allowing the virtual device to maintain different values in the block for each virtual machine. If this value is not given, the service creates a global block in which the same data is available to all virtual machines.
GVDAOptInstance | Allows the virtual machine manager to determine whether to create an instance data block or a global data block.
GVDAPageAlign Aligns block on a page (4 kilobyte) boundary. If no alignment value is given, the service aligns the block on a byte boundary.

GVDAWordAlign, GVDADWordAlign, GVDAParaAlign, and GVDAPageAlign values are mutually exclusive.

GVDAParaAlign | Aligns block on a paragraph (16-byte) boundary. If no alignment value is given, the service aligns the block on a byte boundary.
GVDAReclaim Unmaps any physical pages in the block while mapping the system nul page into the block. The service places unmapped physical pages in the free list. This value only applies if the GVDAPageAlign value is also given. If this value is not given, the service ignores any physical pages it unmaps. It is up to the virtual device to reclaim these pages.

GVDAReclaim and GVDAInstance values are mutually exclusive.

GVDAWordAlign | Aligns block on a word boundary. If no alignment value is given, the service aligns the block on a byte boundary.
GVDAZeroInit | Fills the block with zeros. If this value is not given, the initial content of the block is undefined.

All other values are reserved.

If this service returns an error, the virtual device should consider this a fatal error and respond accordingly.

The size returned when the GVDAInquire value is given may be less than a reasonable minimum. For instance, if GVDAPageAlign is specified, the return size may be less than 4096. It is up to the virtual device to check for this.

For blocks allocated with GVDAInstance, this service calls automatically calls the _AddInstanceItem service.

The _Allocate_Global_V86_Data_Area service is not available and must not be called if the virtual device has allocated a temporary block using the _Allocate_Temp_V86_Data_Area service. The virtual device must free the block before it can call the _Allocate_Global_V86_Data_Area service.

If GVDAReclaim is not given, the virtual device should reclaim the physical addresses of any unmapped physical pages, and map the pages to other addresses. A virtual device reclaims the physical addresses by using the _CopyPageTable service to retrieve the page-table entries for the system virtual machine. The virtual device can then use the _PhysIntoV86 service to map the physical pages into the V86 address space.

See Also

_CopyPageTable, _PhysIntoV86


_Allocate_Temp_V86_Data_Area

include vmm.inc

VMMCall _Allocate_Temp_V86_Data_Area, <nBytes, flags>

or      eax, eax        ; zero if error
jz      error
mov     [Address], eax  ; address of temporary block

Allocates a block of memory from the global V86 data area. The block is for exclusive use by the virtual device during system initialization only. A virtual device typically allocates a temporary block to serve as a buffer for calls to MS-DOS or BIOS functions. A virtual device makes such calls using the Simulate_Int service while inside a nested execution block. This service is only available during initialization. Uses EAX, ECX, EDX, and Flags.

Returns the ring-0 linear address of the block in the EAX register if successful, zero otherwise.

nBytes
Number of bytes to allocate.
flags
Operation flags. Must be zero.

This service always aligns the temporary block on a paragraph boundary and fills the block with zeros.

Virtual devices must free the temporary block as soon as possible. The system provides only one temporary data area, therefore only one temporary block can be allocated at a time. Attempts to allocate a temporary block when it is already allocated will result in an error.

See Also

_Free_Temp_V86_Data_Area


_Assign_Device_V86_Pages

include vmm.inc

VMMCall _Assign_Device_V86_Pages, <VMLinrPage, nPages, VM, flags>

or      eax, eax            ; nonzero if assigned, zero if error
jz      not_assigned

Assigns to a virtual device one or more pages of the V86 address space. Uses EAX, ECX, EDX, and Flags.

Returns a nonzero value in the EAX register if successful, zero otherwise.

VMLinrPage
Linear page number of the first page of V86 address space to assign. The page number must be in the range 0 through 10Fh.
nPages
Number of pages to assign. The service returns an error if the page range does not fall entirely within the V86 address space, or if any page in the range is already assigned.
VM
Handle of a virtual machine, or zero. If this parameter is a valid handle, the page assignments are made in the context of the specified virtual machine. If this parameter is zero, the page assignments are made globally.
flags
Operation flags. Must be 0.

A virtual device can make global assignments at any time, including during device initialization. For global assignments, the VM parameter must be zero. The virtual device must not attempt to assign a page that is already assigned. A virtual device can make local assignments only after device initialization is complete.

See Also

_DeAssign_Device_V86_Pages


_Deallocate_Device_CB_Area

include vmm.inc

VMMCall _Deallocate_Device_CB_Area, <Control_Block_Offset, Flags>

Deallocates part of each virtual machine's control-block, which was previously allocated by _Allocate_Device_CB_Area. Uses EAX, ECX, EDX and Flags.

Returns zero on error, nonzero on success.

Control_Block_Offset
Control block offset previously allocated by the _Allocate_Device_CB_Area service.
Flags
Must be zero.

The Control_Block_Offset must be a valid offset that was returned by a previously successful call to _Allocate_Device_CB_Area. Do not pass an invalid value to deallocate.

See Also

_Allocate_Device_CB_Area


_DeAssign_Device_V86_Pages

include vmm.inc

VMMCall _DeAssign_Device_V86_Pages, <VMLinrPage, nPages, VM, flags>

or      eax, eax        ; nonzero if unassigned, zero if error
jz      not_unassigned

Frees a region in the V86 address space which was previously assigned using the _Assign_Device_V86_Pages service. Uses EAX, ECX, EDX, and Flags.

Returns a nonzero value in the EAX register if successful, zero otherwise.

VMLinrPage
Linear page number of the first page to free. The page number must be in the range 0 through 10Fh.
nPages
Number of pages to free. The service returns an error if the page range does not fall entirely within the V86 address space, or if any page in the range is not assigned.
VM
Handle of a virtual machine, or zero. If this parameter is a valid handle, the assigned pages are freed in the context of the specified virtual machine. If this parameter is zero, the page assignments are freed globally.
flags
Operation flags. Must be 0.

This service only works after device initialization is complete.

A virtual device must not attempt to free pages that have not been assigned, or attempt to globally free pages that were only assigned in the context of a specific virtual machine.

See Also

_Assign_Device_V86_Pages


_Free_Temp_V86_Data_Area

include vmm.inc

VMMCall _Free_Temp_V86_Data_Area

or      eax, eax        ; nonzero if freed, zero if error
jz      not_freed

Frees a block allocated using the _Allocate_Temp_V86_Data_Area service. This service is only available during initialization. Uses EAX, ECX, EDX, and Flags.

Returns a nonzero value in the EAX register if successful, zero otherwise.

The _Allocate_Global_V86_Data_Area service is not available while a temporary block is allocated. The virtual device must free the block before the _Allocate_Global_V86_Data_Area service can be called.

This service invalidates the address of the temporary block. Attempting to use the address can cause a system crash.

See Also

_Allocate_Temp_V86_Data_Area


_Get_Device_V86_Pages_Array

include vmm.inc

VMMCall _Get_Device_V86_Pages_Array, <VM, <OFFSET32 ArrayBuf>, flags>

or      eax, eax        ; nonzero if retrieved, zero if error
jz      not_retrieved

Gets a copy of the assignment array used by the _Assign_Device_V86_Pages and _DeAssign_Device_V86_Pages services. Virtual devices use the assignment array to determine which regions of the V86 address space are currently assigned, and which are available. Uses EAX, ECX, EDX, and Flags.

Returns a nonzero value in the EAX register if successful, zero otherwise.

VM
Handle of the virtual machine for which to retrieve the assignment array. If this parameter is zero, the service retrieves the global assignment array.
ArrayBuf
Address of a 36-byte buffer that receives the assignment array.
flags
Operation flags. Must be 0.

The assignment array consists of 110h bits, each of which represents a single page in the V86 address space. A page is assigned if the corresponding bit is 1.

The global assignment array does not indicate which pages are available. A page is available for global assignment only if it is neither globally nor locally assigned. To determine whether a page is available for global assignment, a virtual device must check the global assignment array, and then check the assignment arrays for each virtual machine.

See Also

_Assign_Device_V86_Pages, _DeAssign_Device_V86_Pages


_GetFirstV86Page

include vmm.inc

VMMCall _GetFirstV86Page

mov     [FirstPage], eax        ; first page of V86 memory

Gets the page number of the first page in the current virtual machine. Uses EAX.

Returns the page number in the EAX register.

The first page in a virtual machine moves during virtual device initialization, so the page number returned by this service during initialization will not be valid at any later time.

See Also

_GetLastV86Page


_GetLastV86Page

include vmm.inc

VMMCall _GetLastV86Page

mov     [LastPage], eax     ; last page in V86 memory

Returns the page number of the last page of V86 memory for the current virtual machine. This service is only available for Windows version 3.1 or later. Uses EAX.

Returns the page number in the EAX register.

The last page in V86 memory moves during initialization. Virtual devices that retrieve the last page when processing initialization messages must retrieve the page number again to use it later.

See Also

_GetFirstV86Page


_GetInstanceInfo

include vmm.inc

VMMCall _GetInstanceInfo, <pRegion, cbRegion>
mov     [InstanceInfo], eax

Retrieves a value indicating whether the given VM address range is fully instanced, partially instanced, or not instanced. Uses EAX, ECX, EDX, and Flags.

Returns, in EAX, a value identifying the region's state if the function succeeds. In can be one of these values:

Value | Meaning
INSTINFO_NONE (0) | Region is not instanced.
INSTINFO_SOME (1) | Region is partially instanced.
INSTINFO_ALL (2) | Region is fully instanced.

pRegion
Linear v86 address of region.
cbRegion
Size of region in bytes.


_GetV86PageableArray

include vmm.inc

VMMCall _GetV86PageableArray, <VM, <OFFSET32 ArrayBuf>, flags>

or      eax, eax            ; nonzero if array retrieved, zero if error
jz      error

Returns a copy of the bit array of pages whose behavior has been modified using the _SetResetV86Pageable service. Virtual devices use this service to determine whether regions in the V86 address space in a virtual machine have had the normal lock and unlock behavior modified. Uses EAX, ECX, EDX, and Flags.

Returns a nonzero value in the EAX register if successful, zero otherwise.

VM
Handle of the virtual machine to examine.
ArrayBuf
Address of the buffer to receive the array. The array contains 100h bits (32 bytes), one bit for each page in the range 0 through 100h. If a bit is set, the lock and unlock behavior for the corresponding page is disabled. Otherwise, the behavior is enabled.
flags
Operation flags. Must be 0.

All bits in the returned bit array are zero if the VMStat_PageableV86 value is not given in the CB_VM_Status field of the control block for the virtual machine.

See Also

_SetResetV86Pageable


_LinMapIntoV86

include vmm.inc

VMMCall _LinMapIntoV86, <HLinPgNum, VM, VMLinPgNum, nPages, flags>
or      eax, eax            ; zero if error
jz      not_mapped
mov     [V86Address], eax   ; V86 address for mapped pages

Maps one or more pages into the V86 address space of the specified virtual machine. This service is similar to the _MapIntoV86 service. Uses EAX, ECX, EDX, and Flags.

Returns a nonzero value in the EAX register if successful, zero otherwise. If EAX is nonzero, the EDX register contains the V86-mode address to which the specified pages are mapped. Otherwise, the value of EDX is undefined.

HLinPgNum
Linear page number of the first page to map. A linear page number is a ring-0 linear address shifted right by 12 bits.
VM
Handle of the virtual machine for which memory is mapped.
VMLinPgNum
Linear page number of an address in the V86 address space. The service maps the specified pages to this address if the HLinPgNum parameter does not already specify a valid V86 address. This parameter must be a page number in the range 10h through 10Fh.
nPages
Number of pages to map.
flags
Operation flags. Can be zero or the MAPV86_IGNOREWRAP value. This value enables the caller to treat the high memory area (HMA) simply as an extension of the V86 address space, whether or not wrap is enabled.

If MAPV86_IGNOREWRAP is specified and wrap is enabled, the service updates only the HMA alias mapping for pages in the HMA, not the currently-visible mapping. The HMA corresponds to page numbers 100h through 10Fh.

A virtual device typically uses this service to map buffers having protected-mode addresses into the V86 address space. This gives software running in the virtual machine a means of passing data to and receiving data from the virtual device.

If HLinPgNum is a V86 page number (that is less than or equal to 100h), this service returns HLinPgNum immediately and does nothing else. Otherwise, the service returns VMLinPgNum.

If the specified linear pages belong to a free physical region, this service calls the _PhysIntoV86 service to carry out the request.

If the specified linear pages belong to the high addressing region for a virtual machine, this service maps the memory from that virtual machine into the virtual machine specified by the VM parameter. The V86MMGR device uses this capability to map a region of V86 address space which is currently local to one VM into a global region that is addressable by all virtual machines. Virtual devices must not use this capability directly; they should always use the V86MMGR services to map local memory into global memory.

Although a virtual device can map the same page into multiple addresses in the V86 address space, this is not recommended.

For each mapped page, this service sets the P_USER, P_PRES, and P_WRITE bits, but clears the P_DIRTY and P_ACC bits. The service sets the page type to be identical to the page type for the pages at the specified protected-mode linear address.

If the virtual page swap device uses MS-DOS or BIOS functions to write to the device, this service automatically locks all mapped pages and unlocks any previously mapped pages.

If a virtual device no longer needs the mapped region, it should map the system nul page into the V86 address space using the _MapIntoV86 service. A virtual device can retrieve the handle for the system nul page using the _GetNulPageHandle service.

This service accepts V86 page numbers between 10h and the page number returned by the _GetFirstV86Page service. This supports virtual devices that use the _Allocate_Global_V86_Data_Area service. Mapping a region which spans across the first V86 page is not allowed. Mapping pages in this region to other addresses can easily crash the system, and should be avoided.

See Also

_Allocate_Global_V86_Data_Area, _GetFirstV86Page, _GetNulPageHandle, _MapIntoV86, _PageLock, _PhysIntoV86


_MapIntoV86

include vmm.inc

VMMCall _MapIntoV86, <hMem, VM, VMLinPgNum, nPages, PageOff, flags>

or      eax, eax            ; nonzero if pages mapped, zero if error
jz      not_mapped

Maps one or more pages of a memory block into the V86 address space of the specified virtual machine. Uses EAX, ECX, EDX, and Flags.

Returns a nonzero value in the EAX register if successful, zero otherwise.

hMem
Handle (base linear address) of the memory block to map. This address must have been returned by the PageAllocate, PageReAllocate, or _PageReserve service.
VM
Handle of the virtual machine for which to map the memory.
VMLinPgNum
Linear page number in the virtual machine's address space. The service maps the first page to the corresponding linear address in the V86 address space. This parameter must be in the range 10h through 10Fh.
nPages
Number of pages to map.
PageOff
Offset in pages from the beginning of the memory block to the first page to map.
flags
Operation flags. Can be one of these values:
Value | Meaning
PageDEBUGNulFault | Enables page faults for system nul pages. If the memory block contains system nul pages, a page fault occurs whenever a nul page is accessed. This value only applies when running the debugging version of the Windows virtual machine manager. If this value is not given or the debugging version is not running, no page faults occur.
MAPV86_IGNOREWRAP | If the specified pages are in the high memory area (HMA) and wrap is on, only update the HMA alias mapping, not the currently visible mapping. The HMA corresponds to pages in the range 100h to 10Fh. This allows the caller to treat the HMA simply as an extension of the V86 address space, regardless of whether wrap is enabled.

All other values are reserved.

A virtual device typically uses this service to map buffers having protected-mode addresses into the V86 address space. This gives software running in the virtual machine a means of passing data to and receiving data from the virtual device.

The service returns an error if the sum of the PageOff and nPages parameters is greater than the size of the memory block.

Although a virtual device can map the same page into multiple addresses in the V86 address space, this is not recommended.

For each mapped page, this service sets the P_USER, P_PRES, and P_WRITE bits and clears the P_DIRTY and P_ACC bits.

If the virtual page swap device uses MS-DOS or BIOS functions to write to the hardware, _MapIntoV86 automatically locks the mapped pages and unlocks any previously mapped pages. If the virtual page swap device writes directly to the hardware, this service neither locks nor unlocks the pages.

If a virtual device no longer needs the mapped region, it should map the system nul page into the V86 address space using the _MapIntoV86 service. A virtual device can retrieve the handle of the system nul page using the _GetNulPageHandle service.

This service accepts V86 page numbers between 10h and the page number returned by the _GetFirstV86Page service. This supports virtual devices that use the _Allocate_Global_V86_Data_Area service. Mapping a region which spans across the first V86 page is not allowed. Mapping pages in this region to other addresses can easily crash the system and should be avoided.

See Also

_Allocate_Global_V86_Data_Area, _GetFirstV86Page, _GetNulPageHandle, _LinMapIntoV86


_ModifyPageBits

include vmm.inc

VMMCall _ModifyPageBits, <VM, VMLinPgNum, nPages, bitAND, bitOR, pType, flags>

or      eax, eax            ; nonzero if modified, zero if error
jz      not_modified

Modifies the page attribute bits for pages in the V86 address space of a virtual machine. Virtual devices use this service to modify page permissions, or to mark a hooked page as not present. Uses EAX, ECX, EDX, and Flags.

Returns a nonzero value in the EAX register if successful, zero otherwise.

VM
Handle of the virtual machine owning the pages to modify.
VMLinPgNum
Linear page number of the first page to modify. All pages must be in the 1 megabyte V86 address space. Page numbers below the first page of the specified virtual machine or above 10Fh cause an error.
nPages
Number of pages to modify.
bitAND
AND mask for the page attribute bits. All bits except P_PRES, P_WRITE, and P_USER must be one. The P_PRES, P_WRITE, and P_USER bits can be zero or one to clear or preserve the corresponding page attributes.
bitOR
OR mask for the page attribute bits. All bits except P_PRES and P_WRITE must be zero. The P_PRES and P_WRITE bits can be 0 or 1 to preserve or set the corresponding page attributes.
pType
Page type. This parameter can be either PG_IGNORE or PG_HOOKED, but must be PG_HOOKED if the P_PRES bit of the bitAND parameter is zero. This parameter has no real effect.
flags
Operation flags. Must be zero.

This service always clears the P_DIRTY and P_ACC bits regardless of the AND and OR mask values.

This service can be used to mark a range of pages as not present (clear the P_PRES bit). In this case, fault handlers must have been previously installed for the specified pages using the Hook_V86_Page service, and the pType parameter must be PG_HOOKED.

This service cannot be used to set the P_PRES bit. Use the _MapIntoV86 or _PhysIntoV86 service to make pages present.

If using the P_WRITE bit to simulate ROM in a virtual machine, a virtual device should map the pages using the _PhysIntoV86 service and immediately call the _ModifyPageBits service to clear the P_WRITE bit.

See Also

Hook_V86_Page, _MapIntoV86, _PhysIntoV86


_PhysIntoV86

include vmm.inc

VMMCall _PhysIntoV86, <PhysPage, VM, VMLinPgNum, nPages, flags>

or      eax, eax                ; nonzero if mapped, zero if an error
jz      not_mapped

Maps the specified physical pages in the V86 address space. This service is similar to the _MapIntoV86 service, but takes physical page numbers instead of memory handles. Virtual devices use this service to associate physical device memory (such as the video memory) with a particular virtual machine. Uses EAX, ECX, EDX, and Flags.

Returns a nonzero value in the EAX register if successful, zero otherwise.

PhysPage
Physical page number of the start of the region to map. A physical page number is a physical address shifted right by 12 bits.
VM
Handle of the virtual machine for which the memory is mapped.
VMLinPgNum
Linear page number in the virtual machine's address space. The service maps the first physical page to the corresponding linear address in the V86 address space. This parameter must be in the range 10h through 10Fh.
nPages
Number of pages to map.
flags
Operation flags. Can be zero or the MAPV86_IGNOREWRAP value. This value enables the caller to treat the high memory area (HMA) simply as an extension of the V86 address space, whether or not wrap is enabled.

If MAPV86_IGNOREWRAP is specified and wrap is enabled, the service updates only the HMA alias mapping for pages in the HMA, not the currently-visible mapping. The HMA corresponds to page numbers 100h through 10Fh.

If more than one physical page is specified, this service maps the pages contiguously. If the physical memory is not contiguous, the virtual device must make individual calls for each page.

Virtual devices must not map physical pages that do not contain actual memory, or that belong to some other device.

For each mapped page, this service sets the P_USER, P_PRES, and P_WRITE bits, but clears the P_DIRTY and P_ACC bits.

See Also

_MapIntoV86


_SetResetV86Pageable

include vmm.inc

VMMCall _SetResetV86Pageable, <VM, VMLinPgNum, nPages, flags>

or      eax, eax    ; nonzero if set or reset, zero if error
jz      error

Modifies the locking and unlocking behavior associated with a specific range of V86 memory. Uses EAX, ECX, EDX, and Flags.

Returns a nonzero value in the EAX register if successful, zero otherwise.

VM
Handle of the virtual machine for which the behavior is modified.
VMLinPgNum
Linear page number of the first page in 1 megabyte V86 address space to modify. This parameter must not be below the page number for the first V86 page, or above 100h.
nPages
Number of pages to modify.
flags
Operation flags. Can be one of these values:
Value | Meaning
PageClearV86IntsLocked | Disables locking of all V86 memory that cannot be paged regardless of whether the virtual page swap device uses MS-DOS or BIOS functions.
PageClearV86Pageable | Enables normal locking behavior.
PageSetV86IntsLocked | Enables locking of all V86 memory that cannot be paged regardless of whether the virtual page swap device uses MS-DOS or BIOS functions.
PageSetV86Pageable | Disables normal locking behavior of _MapIntoV86 and allows V86 memory to be paged.

All other values are reserved.

This service is intended to be used to support protected-mode applications running in a virtual machine. Virtual devices must not use this service for any other purpose.

This service returns an error if the VMStat_PageableV86 or VMStat_V86IntsLocked state is inconsistent with the specified PageSetV86Pageable, PageClearV86Pageable, PageSetV86IntsLocked, or PageClearV86IntsLocked values.

This service returns an error if the PageClearV86Pageable or PageSetV86IntsLocked values are given, but the service cannot lock the specified memory.

The V86MMGR device uses the PageSetV86IntsLocked value for virtual machines which are created with their base memory specified as locked.

Virtual device should avoid manipulating the locking and unlocking behavior of regions above page 0A0h. A virtual device should not modify these pages unless it owns a global or local region set by the _Assign_Device_V86_Pages service.

If the PageSetV86IntsLocked or PageClearV86IntsLocked value is given, the service applies the modification to every page that that cannot be paged. For this reason the VMLinPgNum and nPages parameters should be set to zero.

By default, the _MapIntoV86 service locks the memory it maps. For a virtual machine running a protected-mode application, it is desirable change this default behavior.

See Also

_Assign_Device_V86_Pages


_TestGlobalV86Mem

include vmm.inc

VMMCall _TestGlobalV86Mem, <VMLinAddr, nBytes, flags>

mov     [Result], eax           ; 0 if local, 1 if global, 2 if mixed,
                                ; 3 if includes instance data region

Tests whether a V86 address range is global, local, or instanced. Uses EAX, ECX, EDX, and Flags.

Returns one of these values in the EAX register:

0 | Address range either contains local memory, or is not a valid V86 address range.
1 | Address range contains global memory.
2 | Address range contains both local and global memory.
3 | Address range contains global memory, but also includes an instance data region.

VMLinAddr
Ring-0 linear address of the first byte of the V86 address range. For example, the linear address of the V86 address 02C1h:0FC5h is 3BD5h (02C10h + 0FC5h).
nBytes
Size of the V86 address range, in bytes.
flags
Operation flags. Must be zero.

Global V86 memory has addresses that are valid and identical in all virtual machines. Local memory has addresses that are only valid in one virtual machine. Instanced memory has addresses that are valid in all virtual machines, but the content of the memory varies with each virtual machine.

This service may incorrectly report the type of memory in addresses above page 0A0h (in the device adapter area). If this service returns global for memory in this area, it is global. If the service returns local, however, the memory may actually be global. Generally, this region is local.

Operations involving global address ranges typically do not need to be virtualized since the range is valid and addressable in all virtual machines. Operations involving local address ranges may have to be virtualized since it is possible for software, such as an interrupt handler, to use a local address in the wrong virtual machine.


Hook_V86_Page

include vmm.inc

mov     eax, PageNum            ; page number
mov     esi, OFFSET32 Callback  ; points to address of trap routine
VMMCall Hook_V86_Page

Installs a callback procedure to handle faults for the specified page. Virtual devices, such as the virtual display device, use this service to detect when particular address ranges are accessed. Uses Flags.

Returns with the carry flag clear if successful, set otherwise. The service fails if the specified page number is invalid or the page is already hooked.

PageNum
Page number of the V86 page to install the callback procedure for. This number must be within the range specified by the number of the last V86 page and 0FFh.
Callback
Address of the callback procedure to install. For more information about the callback procedure, see below.

The system calls the callback procedure whenever a page fault occurs for the specified page regardless of the current virtual machine. It calls the procedure as follows:

mov     eax, Page     ; faulting page number
mov     ebx, VM       ; current VM handle
call    [Callback]

The Page parameter specifies the number of the page that caused the page fault, and the VM parameter is the handle of the current virtual machine. The EBP register does not point to a client register structure.

The callback procedure must either map physical memory into pages causing the page fault, or terminate the virtual machine. In unusual circumstances, the virtual device may need to map the system nul page into the faulting page.

Virtual devices must not rely on the contents of the CR2 (page fault) register. Instead, the callback procedure must use the Page parameter to determine which page caused the fault.

Call Unhook_V86_Page to remove the hook procedure.

See Also

Unhook_V86_Page


InstDataStruc

include vmm.inc

InstDataStruc struc
InstLinkF     dd      ?   ; reserved; do not use
InstLinkB     dd      ?   ; reserved; do not use
InstLinAddr   dd      ?   ; linear address of start of block
InstSize      dd      ?   ; size of block in bytes
InstType      dd      ?   ; type of the block
InstDataStruc ends

The InstDataStruc structure contains information about an instance data block.

InstLinkF
Reserved. This field is filled by the instance data manager, and must not be used.
InstLinkB
Reserved. This field is filled by the instance data manager, and must not be used.
InstLinAddr
Specifies the linear address of the start of the block of instance data. Thus, the correct value for 40:2F would be 42F.
InstSize
Specifies the size in bytes of the instance data block.
InstType
Specifies the instance data type. It can be one of the following values:
Value | Meaning
ALWAYS_FIELD | Indicates that the field must always be switched when a virtual machine is switched. All instance data specified by devices should be of this type.
INDOS_FIELD | Reserved for special types of MS-DOS internal data which only need to be switched with the virtual machine if the virtual machine is currently InDOS.
OPTIONAL_FIELD | Indicates optional instance data.

See Also

_AddInstanceItem


Unhook_V86_Page

include vmm.inc

mov eax, PageNum
mov esi, TrapProc
VMMCall Unhook_V86_Page

jc error

Allows VxDs to stop intercepting page faults in portions of the V86 address space of every virtual machine. It is used to undo the work of the Hook_V86_Page service. Uses Flags.

You must specify a page number and address of a call-back routine to this service. If the given page is currently hooked with the specified call-back routine, the hook will be removed. Otherwise, the carry flag will be set on return to indicate error.

After being unhooked the page will be mapped to a null page.

Returns with the carry flag clear if successful; otherwise sets the carry flag.

PageNum
Page number (Last_VM_Page - 10Fh) to unhook.
TrapProc
Address of callback procedure.

See Also

Hook_V86_Page


Error Conditions

There are the following error condition services:

Service | Description
Crash_Cur_VM | Terminates the current VM.
Fatal_Error_Handler | Terminates Windows.
Fatal_Memory_Error | Terminates Windows.


Crash_Cur_VM

include vmm.inc

VMMCall Crash_Cur_VM

Terminates the current VM.

  • This service does not return.

A virtual device should call this service when a catastrophic error has occurred in the VM, such as executing an illegal instruction or attempting to program a piece of hardware in a way incompatible with the device virtualization.

If the system VM is the current VM, Windows quits with a fatal error without explicitly crashing the other VMs.


Fatal_Error_Handler

include vmm.inc

mov     esi, <MsgPtr>       ; points to message to display
mov     eax, <ErrFlags>     ; exit flags
VMMCall Fatal_Error_Handler

Terminates Windows by informing all initialized virtual devices that an unrecoverable error has occurred and should return to real mode (optionally printing an error message). A virtual device should call this service when it detects a fatal error.

  • This service does not return.
MsgPtr
Address of a null-terminated string specifying the message to display. If this parameter is 0, no message is displayed.
ErrFlags
Exit flags. Can be the following value:
Value | Meaning
EF_Hang_On_Exit | Hangs the system on a fatal exit.

All other values are reserved.

This service should not be called directly. Use the Fatal_Error macro instead.

See Also

Fatal_Error, Fatal_Memory_Error


Fatal_Memory_Error

include vmm.inc

VMMCall Fatal_Memory_Error

Terminates Windows, and displays an error message indicating that there was not enough memory to initialize one or more virtual devices. A virtual device should call this service during initialization if there is not enough memory to initialize.

  • This service does not return.

This service uses the Fatal_Error_Handler service to terminate Windows. Fatal_Memory_Error sets the exit flags to zero before calling the Fatal_Error_Handler.

See Also

Fatal_Error_Handler


Information Services

There are the following information services:

Service | Description
Get_Cur_VM_Handle | Returns current virtual machine handle.
Get_Next_VM_Handle | Returns the next valid virtual machine handle.
Get_Sys_VM_Handle | Returns the system virtual machine handle.
Get_VMM_Reenter_Count | Returns number of time VMM re-entered.
Get_VMM_Version | Returns the VMM version number.
GetSet_HMA_Info | Returns or sets HMA information.
Test_Cur_VM_Handle | Tests for current virtual machine handle.
Test_DBCS_Lead_Byte | Tests for legal DBCS lead byte.
Test_Debug_Installed | Tests for debugger.
Test_Sys_VM_Handle | Test for system virtual machine handle.
Validate_VM_Handle | Validates a virtual machine handle.


Get_Cur_VM_Handle

include vmm.inc

VMMCall Get_Cur_VM_Handle

mov     [VM], ebx         ; current VM handle

Gets the handle of the currently running virtual machine. This is an asynchronous service. Uses EBX, Flags.

  • Returns the handle of the current virtual machine in the EBX register.

See Also

Get_Sys_VM_Handle, Test_Cur_VM_Handle


Get_Next_VM_Handle

include vmm.inc

mov     ebx, VM           ; VM handle
VMMCall Get_Next_VM_Handle

mov     [NextVM], ebx     ; next VM handle

Returns the handle of the next virtual machine in the virtual machine list maintained by the system. Uses EBX, Flags.

  • Returns the handle of the next virtual machine in the EBX register.
VM
Handle of a virtual machine. The return value identifies the next virtual machine after the specified virtual machine.

Although each virtual machine appears only once in the list, the order of the handles is not guaranteed. The list is circular, so a virtual device scanning the list should stop scanning when the latest handle returned is equal to the first handle returned.

The following example modifies the state of every virtual machine by using the Get_Next_VM_Handle service to retrieve handles of all valid virtual machines:

    VMMCall Get_Cur_VM_Handle

Scan_Loop:

    ; modify the VM state

    VMMCall Get_Next_VM_Handle
    VMMCall Test_Cur_VM_Handle
    jne     Scan_Loop

See Also

Get_Cur_VM_Handle, Test_Cur_VM_Handle


GetSet_HMA_Info

include vmm.inc

mov     ecx, Action         ; zero to get, nonzero to set
mov     dx, A20Enable       ; A20 enable count (if ecx is nonzero)
VMMCall GetSet_HMA_Info

mov     [NoGlobalHMA], eax  ; nonzero if no global HMA user
mov     [XMSCallAddr], ecx  ; loader XMS call address
mov     [A20Enable], edx    ; A20 enable count before Windows started

Gets and sets information related to the high-memory area (HMA) region. This service is always valid (not restricted to initialization). Uses EAX, ECX, EDX, Flags.

  • Returns the following information in the following registers:
Register | Description
EAX | Specifies whether a global HMA user is present. If this register is 0, Windows did not allocate the HMA meaning either there is a global HMA user or there is no HMA. If this register is nonzero, Windows has allocated the HMA, meaning there is no global HMA user.
ECX | Specifies the V86-mode address (segment:offset) that Windows used to call the XMS driver when loading. The segment address is in the high 16 bits of the register.
EDX | Specifies the A20 enable count before Windows started.

Action
Value specifying whether to get or set information. If zero, the service gets the HMA information; otherwise it sets the information.
A20Enable
A20 enable count to set for the Windows VMM loader. The service uses this parameter only if the Action parameter is nonzero.

This service lets the XMS driver (in the V86MMGR device) determine whether a global HMA user existed before Windows started and gives the driver access to the HMA enable count. Other devices should not call this service.

The global HMA flag and loader XMS call address cannot be set.


Get_Sys_VM_Handle

include vmm.inc

VMMCall Get_Sys_VM_Handle

mov     [SysVM], ebx            ; system VM handle

Retrieves the handle of the system virtual machine. This is an asynchronous service. Uses EBX, Flags.

  • Returns the handle of the system virtual machine in the EBX register.

See Also

Get_Cur_VM_Handle, Test_Sys_VM_Handle


Get_VMM_Reenter_Count

include vmm.inc

VMMCall Get_VMM_Reenter_Count

jecxz   not_reentered           ; ecx is zero if VMM not re-entered
mov     [Count], ecx            ; otherwise, number of times re-entered

Returns the number of times the VMM has been re-entered as a result of a hardware interrupt, page fault, or other processor exception. Virtual devices typically use this service to determine whether they can call VMM services that do not re-enter. Uses Flags.

  • Returns the number of times the VMM has been reentered in the ECX register (zero if the VMM has not been reentered).

If this service returns a nonzero value, a virtual device may call only VMM services that are asynchronous. If a virtual device must call other VMM services, the virtual device can schedule an event using a service such as Schedule_Global_Event. The system calls the event's callback procedure when all VMM services are available.

The Call_Global_Event and Call_VM_Event services call this service to determine whether the event callback procedure should be called immediately.

See Also

Call_Global_Event, Call_VM_Event, Schedule_Global_Event, Schedule_VM_Event


Get_VMM_Version

include vmm.inc

VMMCall Get_VMM_Version

mov     [Major], ah         ; major version number
mov     [Minor], al         ; minor version number
mov     [Debug], ecx        ; debug development revision number

Returns the version number for the Windows virtual machine manager (VMM). Uses EAX, Flags.

  • Returns with the carry flag clear and the following values in the following registers:
Register | Description
AH | Specifies the major version number. For Windows version 95, this number is 4.
AL | Specifies the minor version number. For Windows version 95, this number is 0.
ECX | Specifies the debug development revision number.


Test_Cur_VM_Handle

include vmm.inc

mov     ebx, VM             ; VM handle to test
VMMCall Test_Cur_VM_Handle

je      is_current          ; zero flag set if current VM handle

Determines whether the given virtual machine handle is the handle of the currently running virtual machine. This is an asynchronous service. Uses Flags.

  • Returns with the zero flag set if the given handle identifies the current virtual machine, clear otherwise.
VM
Virtual machine handle to test.

See Also

Get_Cur_VM_Handle, Test_Sys_VM_Handle


Test_DBCS_Lead_Byte

include vmm.inc

mov     eax, Value   ; value to test
VMMCall Test_DBCS_Lead_Byte

jc      not_valid    ; carry flag set if not legal DBCS lead byte

Determines whether the given value is in the legal range for a DBCS lead byte. Uses Flags.

  • Returns with the carry flag clear if the specified value is in the legal range for DBCS lead bytes, set otherwise.
Value
Value to test.

For non-DBCS versions of Windows, this service always sets the carry flag.


Test_Debug_Installed

include vmm.inc

VMMCall Test_Debug_Installed

je      not_installed       ; zero flag set if not installed

Determines whether a debugger is currently connected. is running. This is not the same as checking whether the debugging version of the Windows VMM is running. Uses Flags.

  • Returns with the zero flag set if a debugger is not installed, clear otherwise.


Test_Sys_VM_Handle

include vmm.inc

mov     ebx, VM             ; VM handle to test
VMMCall Test_Sys_VM_Handle

je      is_system           ; zero flag set if system VM handle

Determines whether the given virtual machine handle is the handle of the system virtual machine. This is an asynchronous service. Uses Flags.

  • Returns with the zero flag set if the given handle identifies the system virtual machine, clear otherwise.
VM
Virtual machine handle to test.

See Also

Get_Sys_VM_Handle, Test_Cur_VM_Handle


Validate_VM_Handle

include vmm.inc

mov     ebx, VM             ; VM handle to test
VMMCall Validate_VM_Handle

jc      not_valid           ; carry flag set if VM handle not valid

Determines whether the specified virtual machine handle is valid. This is an asynchronous service. Uses Flags.

  • Returns with the carry flag set if the handle is not valid, clear otherwise.
VM
Virtual machine handle to test.

See Also

Test_Cur_VM_Handle, Test_Sys_VM_Handle


Initialization Information

There are the following initialization information services:

Service | Description
Convert_Boolean_String | Converts string to a Boolean value.
Convert_Decimal_String | Converts a string to a decimal value.
Convert_Fixed_Point_String | Converts a string to a fixed-point value.
Convert_Hex_String | Converts a string to a hexadecimal value.
Get_Config_Directory | Returns to the WINDOWS directory.
Get_Environment_String | Returns the value of an environment variable.
Get_Exec_Path | Returns the full path of Windows VMM.
Get_Machine_Info | Returns machine information.
Get_Name_Of_Ugly_TSR | Returns the name of uncooperative TSR.
Get_Next_Arena | Returns information about the MS-DOS arena.
Get_Next_Profile_String | Returns the value of the next profile string.
Get_Profile_Boolean | Returns the value of a Boolean entry.
Get_Profile_Decimal_Int | Returns the value of a decimal entry.
Get_Profile_Fixed_Point | Returns the value of a fixed-point entry.
Get_Profile_Hex_Int | Returns the value of a hexadecimal entry.
Get_Profile_String | Returns value of a profile string.
Get_PSP_Segment | Returns the segment address of a PSP.
Get_Set_Real_DOS_PSP | Gets or sets the PSP for the specified VM
GetDOSVectors | Returns original interrupt handler addresses.
Locate_Byte_In_ROM | Locates a byte value in system ROM.
OpenFile | Opens a file and returns an MS-DOS file handle.
VMM_GetSystemInitState | Retrieves the current system initialization state.


Convert_Boolean_String

include vmm.inc

mov     edx, OFFSET32 String    ; address of Boolean string
VMMCall Convert_Boolean_String

jc      not_valid               ; carry set if invalid string
mov     [Result], eax           ; 0 if false, -1 if true

Converts a string representing a Boolean value, and returns either – 1 or 0 to indicate that the string is true or false. This service is available during initialization only. Uses EAX, Flags.

  • Returns with the carry flag is clear if the string represents a valid Boolean value, set otherwise. If the carry flag is clear, the EAX register contains either 0 (false) or – 1 (true).
String
Address of a null-terminated string representing a Boolean value.

Valid boolean strings that signify false are 0, False, N, No, and Off. Valid boolean strings that signify true are 1, On, True, Y, and Yes. Non-English versions of Windows may have language-specific additions to this list.

See Also

Convert_Decimal_String, Convert_Fixed_Point_String, Convert_Hex_String


Convert_Decimal_String

include vmm.inc

mov     edx, OFFSET32 String  ; address of decimal string
VMMCall Convert_Decimal_String

mov     [Value], eax          ; decimal value of string
mov     [TermChar], edx       ; address of terminating character

Converts a string representing a decimal number into a value. The service also returns a pointer to the character in the string that marked the end of the decimal number. This service is only valid during initialization. Uses EAX, EDX, Flags.

  • Returns the value of the decimal string in the EAX register, and the address of the terminating character (first unparseable character) in the EDX register.
String
Address of the null-terminated string to convert. The string can be any combination of decimal digits and may preceded by a plus sign (+) or minus sign (-) to indicate a positive or negative value.

If the string is empty or does not contain a valid decimal integer, the service returns zero in the EAX register and the address of the first character in the EDX register.

See Also

Convert_Boolean_String, Convert_Fixed_Point_String, Convert_Hex_String


Convert_Fixed_Point_String

include vmm.inc

mov     ecx, Places      ; number of decimal places
mov     edx, String      ; address of fixed-point string
VMMCall Convert_Fixed_Point_String

mov     [Value], eax     ; fixed-point value
mov     [TermChar], edx  ; address of terminating character

Converts a string representing a fixed-point number into a fixed-point value. The service also returns a pointer to the character in the string that marked the end of the number. This service is only valid during initialization. Uses EAX, EDX, Flags.

  • Returns the normalized value of the fixed-point number in the EAX register, and the address of the terminating character in the EDX register. The actual value is equal to .
Places
Number of digits after the decimal point to convert. The service skips over any extra digits without calculating them into the fixed-point value.
String
Address of the null-terminated string to convert. For more information about the format of the string, see below.

A fixed-point number is a decimal number that consists of an integer, a fraction, or a combination of integer and fraction. The integer can be any combination of decimal digits and may be preceded by a plus sign (+) or a minus sign (-) to indicate a positive or negative fixed-point value. The fraction can be any combination of decimal digits but must be preceded with a decimal point (.).

See Also

Convert_Boolean_String, Convert_Decimal_String, Convert_Hex_String


Convert_Hex_String

include vmm.inc

mov     edx, OFFSET32 String  ; address of hexadecimal string
VMMCall Convert_Hex_String

mov     [Value], eax          ; value of string
mov     [TermChar], edx       ; address of terminating character

Converts a string representing a hexadecimal number into a value. The service also returns a pointer to the character in the string that marked the end of the hexadecimal number. This service is only valid during initialization. Uses Flags.

  • Returns the value of the hexadecimal string in the EAX register, and the address of the terminating character in the EDX register. If the letter H terminates the number, EDX contains the address the character after the H.
String
Address of the null-terminated string to convert. The string can be any combination of hexadecimal digits (0–9, A-F), and may terminated with an uppercase or lowercase letter H.

See Also

Convert_Boolean_String, Convert_Decimal_String, Convert_Fixed_Point_String


Get_Config_Directory

include vmm.inc

VMMCall Get_Config_Directory

mov     [WinDir], edx  ; address of the directory name

Gets the name of the directory containing the Windows configuration files, such as SYSTEM.INI. For Windows 95, this service is available following initialization. Uses EDX, Flags.

  • Returns, in the EDX register, the address of a null-terminated string containing the fully qualified path of the configuration directory. The string always ends with a backslash (\).

If the WINDIR environment variable is defined when Windows starts, the string associated with WINDIR is returned, regardless of whether it specifies the actual directory where SYSTEM.INI is located.


GetDOSVectors

include vmm.inc

VMMCall GetDOSVectors

mov     [Int23], eax  ; V86 address of original Int 23 handler
mov     [Int24], edx  ; V86 address of original Int 24 handler

Returns the Interrupt 23h and Interrupt 24h vectors originally set by MS-DOS for the Windows virtual machine manager (VMM). This service is valid only during initialization. Uses EAX, EDX.

  • Returns the Interrupt 23h vector in the EAX register and the Interrupt 24h vector in the EDX register. Each register contains a V86-mode address, with the segment in the high-order word, and the offset in the low-order word.

Virtual devices must not use this service; this service is reserved for exclusive use by the virtual MS-DOS manager.

When Windows starts, the VMM changes the original Interrupt 23h and 24h vectors to the addresses of its own handlers. When a virtual machine starts, the virtual MS-DOS manager resets these vectors to the original handlers using this service to retrieve the original addresses.

See Also

Get_PSP_Segment


Get_Environment_String

include vmm.inc

mov     esi, OFFSET32 Variable  ; environment variable name
VMMCall Get_Environment_String

jc      not_found               ; carry set if variable not found
mov     [Value], edx            ; addr. of null-terminated string

Returns the value of the specified environment variable. For Windows 95, this service is available following initialization. Uses EDX, Flags.

  • Returns with the carry flag clear if successful, set otherwise. If the carry flag is clear, the EDX register contains the address of a null-terminated string specifying the value of the environment variable.
Variable
Address of a null-terminated string specifying the name of an MS-DOS environment variable. This service is not sensitive to case, so the name may be given in any combination of uppercase and lowercase letters. If zero is passed, the service returns a pointer to the environment block. Additional information about the environment block follows the environment variables comment.

Environment variables, set using the MS-DOS set command, are a limited resource. Although some virtual devices use environment variables as a way to set operating parameters, this is not recommended unless the variable is used by a set of programs, MS-DOS device drivers, and virtual devices.

When zero is passed as the name of the environment variable, a pointer to the 'global environment' is returned in the EDX register. The global environment has the same format as in MS-DOS: A packed array of zero-terminated ASCII strings, each of the form '<variable>=<value>', all terminated by an extra null byte. The VMM also creates a fake 16-byte MS-DOS arena header in front of the environment block so that you can determine its size:

GLOBAL_ENVIRONMENT_HEADER struc
        db        'M'
        dw        0FFFFh
        dw        paraSize            ; Size in paragraphs, not incl. header
        db        11 dup (?)        ; Padding
GLOBAL_ENVIRONMENT_HEADER ends

Do not attempt to resize the environment. You may, however, edit the environment, provided you do so during system initialization. Changes to the global environment after system initialization will not take effect the way you expect.

Do not keep pointers into the global environment. The global environment moves around during the running of the system, so any pointer you keep into it may be stale by the time you use it. If you need to retain the value of an environment variable, make a private copy.


Get_Exec_Path

include vmm.inc

VMMCall Get_Exec_Path

mov     [Path], edx     ; address of full path of VMM32.VXD
mov     [Length], ecx   ; count of chars up to and including the
                        ;   last backslash (\).

Gets the fully qualified path of the Windows virtual machine manager (VMM). For Windows 95, this service is available following initialization. Uses ECX, EDX, Flags.

  • Returns, in the EDX register, the address of a null-terminated string containing the fully qualified path of the VMM (VMM32.VXD). The ECX register contains the length of the directory portion of the string, up to and including the last backslash (\).


Get_Machine_Info

include vmm.inc

VMMCall Get_Machine_Info
mov     [Major], AH     ; MS-DOS major version number
mov     [Minor], AL     ; MS-DOS minor version number
mov     [OEM], BH       ; MS-DOS OEM serial number
mov     [Model], BL     ; machine model byte
shr     EBX, 16         ; machine type flags returned in the
mov     [Type], BX      ;   high-order word of EBX
mov     [SysConf], ECX  ; address of System Config. Parameters
mov     [Equip], EDX    ; equipment flags

Returns information about the computer system that Windows is running on. Uses EAX, EBX, ECX, EDX, Flags.

  • Returns the following information in the following registers:
Register | Description
AH | MS-DOS major version number
AL | MS-DOS minor version number
BH | MS-DOS OEM serial number
BL | Machine model byte (from address F000:FFFE in system ROM)
EBX | Machine type flags, in the high-order word. For a list of possible values, see below.
ECX | Ring 0 linear address to System Configuration Parameters (as returned from BIOS service Interrupt 15h, AH=C0h). Applies only to PS/2 or computers with extended BIOS. See the PS/2 BIOS documentation for details.
EDX | Equipment flags (as returned from Interrupt 11h)

The machine type flags, returned in the high-order word of the EBX register, can include zero or more of these values:

Value | Meaning
GMIF_80486 | 80486 processor or higher
GMIF_PCXT | PCXT accelerator
GMIF_MCA | Micro Channel
GMIF_EISA | EISA
GMIF_CPUID | CPUID instruction supported by this processor

The address returned in the ECX register points to a copy of the system configuration parameters because the actual parameters may have been moved into a buffer which is subject to page remapping.

Note The CPUID instruction is supported by the Intel® Pentium™ processor and other non-Pentium processors. CPU support of the CPUID instruction does not guarantee that the CPU is a Pentium processor.


Get_Name_Of_Ugly_TSR

include vmm.inc

VMMCall Get_Name_Of_Ugly_TSR

jz      no_ugly_TSR         ; zero flag set if no ugly TSRs present
mov     [Name], eax         ; first 4 characters of TSR name
mov     [Name+4], ebx       ; last 4 characters of TSR name

Returns the name of an uncooperative TSR. This service is available only during initialization, and only for Windows version 3.1 and later. Uses EAX, EBX, Flags.

  • Returns with the zero flag clear if any uncooperative TSRs are present, set otherwise. If the zero flag is clear, the EAX and EBX registers contain the first four and last four characters of the TSR name. Otherwise both registers are zero.

During its real-mode initialization, the virtual MS-DOS manager checks for and records the names of any TSRs that may prevent other MS-DOS programs from running. Get_Name_Of_Ugly_TSR checks the list and returns one of the TSR names (if any) so that virtual devices can determine whether they can successfully operate. Although more than one ugly TSR may be present in the list, the service chooses only one name to return.


Get_Next_Arena

include vmm.inc

mov     ecx, 0              ; must be zero
VMMCall Get_Next_Arena

mov     [Data], eax         ; data value
mov     [Flags], ecx        ; high MS-DOS memory flags
mov     [Memory], edx       ; points to array of Common_Memory_struc

Returns a pointer to an MS-DOS data structure. Uses EAX, ECX, EDX, Flags.

Virtual devices must not use this service; it is intended for exclusive use by the virtual MS-DOS manager.

  • Returns the following values in the following registers:
Register | Description
EAX | Contains a data value.
ECX | Contains the high MS-DOS flags. For more information, see below.
EDX | Contains the address of an array of Common_Memory_struc structures. For more information, see below.

The high MS-DOS flags, returned in the ECX register, can be zero or more of these values:

Value | Meaning
GNA_HiDOSLinked | Set if high MS-DOS arenas were linked in when Windows was started.
GNA_IsHighDOS | Set if high MS-DOS arenas exist.

The EDX register contains the address of an array of Common_Memory_Struc structures, each specifying the address and size of a high MS-DOS memory segment. The last element in the array contains zero. The structure has the following form:

Common_Memory_struc struc
  CM_seg    dw  ?   ; segment address of start
  CM_size   dw  ?   ; size in paragraphs
Common_Memory_struc ends


Get_Next_Profile_String

include vmm.inc

mov     edx, Profile    ; points to the previous entry value
mov     edi, Keyname    ; points to the keyname for the entry
VMMCall Get_Next_Profile_String

jc      no_next         ; carry flag set if no more entries
mov     [Next], edx     ; address of next profile string

Searches the SYSTEM.INI file for the next entry with a given keyname following the specified entry. Virtual devices typically use this service if they have more than one entry with the same keyname. This service is available only during initialization. Uses EDX, Flags.

  • Returns with the carry flag clear if an entry is found, set otherwise. If the carry flag is clear, the EDX register contains the address of the next string with the specified keyname.
Profile
Address of a null-terminated string specifying the value of the previous entry. The string must have been previously returned using the Get_Profile_String or Get_Next_Profile_String service.
Keyname
Points to a null-terminated string identifying the keyname for the entry.

A virtual device retrieves the first string using the Get_Profile_String service, then uses Get_Next_Profile_String to retrieve all subsequent entries. In all cases, the virtual device must not modify the returned string.

See Also

Get_Profile_String


Get_Profile_Boolean

include vmm.inc

mov     eax, Default            ; default value
mov     esi, OFFSET32 Profile   ; points to section name
mov     edi, OFFSET32 Keyname   ; points to entry name
VMMCall Get_Profile_Boolean

jc      not_found               ; carry set if entry not found
jz      no_value                ; zero set if entry has no value

mov     [Value], eax            ; 0 or -1 returned in EAX

Returns the value of a Boolean entry in the SYSTEM.INI file. This service is only available during initialization. Uses Flags.

  • Returns with the carry and zero flags clear if the entry is found. In this case, the EAX register contains – 1 or 0 indicating that the entry value evaluates to true or false, respectively.

    If the carry flag is clear and the zero flag is set, the entry exists but has no corresponding value. If the carry flag is set, the entry does not exist or is not a valid boolean string. In these cases, the EAX register contains the value of the Default parameter.

Default
Default value to return if the entry has no corresponding value, does not exist, or is not a valid boolean string.
Profile
Address of a null-terminated string identifying the section in the SYSTEM.INI file to search. Can be zero, in which case the service searches the [386Enh] section.
Keyname
Address of a null-terminated string specifying keyname to search for.

Valid boolean strings that signify false are 0, False, N, No, and Off. Valid boolean strings that signify true are 1, On, True, Y, and Yes. Non-English versions of Windows may have language-specific additions to this list.

See Also

Get_Profile_Decimal_Int, Get_Profile_Fixed_Point, Get_Profile_Hex_Int


Get_Profile_Decimal_Int

include vmm.inc

mov     eax, Default            ; default value
mov     esi, OFFSET32 Profile   ; points to section name
mov     edi, OFFSET32 Keyname   ; points to entry name
VMMCall Get_Profile_Decimal_Int

jc      not_found               ; carry set if entry not found
jz      no_value                ; zero set if entry has no value

mov     [Value], eax            ; entry value

Returns the value of a decimal-number entry in the SYSTEM.INI file. This service is only available during initialization. Uses Flags.

  • Returns with the carry and zero flags clear if the entry is found. In this case, the EAX register contains the value of the decimal number.

    If the carry flag is clear and the zero flag is set, the entry exists but has no corresponding value. If the carry flag is set, the entry does not exist or does not represent a decimal number. In these cases, the EAX register contains the value of the Default parameter.

Default
Default value to return if the entry has no corresponding value, does not exist, or does not represent a decimal number.
Profile
Address of a null-terminated string identifying the section in the SYSTEM.INI file to search. Can be zero, in which case the service searches the [386Enh] section.
Keyname
Address of a null-terminated string specifying keyname to search for.

A valid decimal number consists of one or more decimal digits and contains no embedded spaces or decimal points. The decimal number can be preceded with a plus sign (+) or minus sign (-) to indicate a positive or negative number, respectively.

See Also

Get_Profile_Boolean, Get_Profile_Fixed_Point, Get_Profile_Hex_Int


Get_Profile_Fixed_Point

include vmm.inc

mov     eax, Default            ; default value
mov     ecx, Places             ; number of digits after decimal point
mov     esi, OFFSET32 Profile   ; points to section name
mov     edi, OFFSET32 Keyname   ; points to entry name
VMMCall Get_Profile_Fixed_Point

jc      not_found               ; carry flag set if entry not found
jz      no_value                ; zero flag set if entry has no value

mov     [Value], eax            ; entry value

Returns the value of a fixed-point-number entry in the SYSTEM.INI file. This service is only available during initialization. Uses Flags.

  • Returns with the carry and zero flags clear if the entry is found. In this case, the EAX register contains the normalized value of the fixed-point number. The actual value is equal to

    If the carry flag is clear and the zero flag is set, the entry exists but has no corresponding value. If the carry flag is set, the entry does not exist or does not represent a fixed-point number. In these cases, the EAX register contains the value of the Default parameter.

Default
Default value to return if the entry has no corresponding value, does not exist, or does not represent a fixed-point number.
Places
Number of digits after the decimal point to convert. The service skips over any extra digits without calculating them into the fixed-point value.
Profile
Address of a null-terminated string identifying the section in the SYSTEM.INI file to search. Can be zero, in which case the service searches the [386Enh] section.
Keyname
Address of a null-terminated string specifying keyname to search for.

A fixed-point number is a decimal number that consists of an integer, a fraction, or a combination of integer and fraction. The integer can be any combination of decimal digits and may be preceded by a plus sign (+) or a minus sign (-) to indicate a positive or negative fixed-point value. The fraction can be any combination of decimal digits but must be preceded with a decimal point (.).

See Also

Get_Profile_Boolean, Get_Profile_Decimal_Int, Get_Profile_Hex_Int


Get_Profile_Hex_Int

include vmm.inc

mov     eax, Default            ; default value
mov     esi, OFFSET32 Profile   ; points to section name
mov     edi, OFFSET32 Keyname   ; points to entry name
VMMCall Get_Profile_Hex_Int

jc      not_found               ; carry set if entry not found
jz      no_value                ; zero set if entry has no value

mov     [Value], eax            ; entry value

Returns the value of a hexadecimal-number entry in the SYSTEM.INI file. This service is only available during initialization. Uses Flags.

  • Returns with the carry and zero flags clear if the entry is found. In this case, the EAX register contains the value of the hexadecimal number.

    If the carry flag is clear and the zero flag is set, the entry exists but has no corresponding value. If the carry flag is set, the entry does not exist or does not represent a hexadecimal number. In these cases, the EAX register contains the value of the Default parameter.

Default
Default value to return if the entry has no corresponding value, does not exist, or does not represent a hexadecimal number.
Profile
Address of a null-terminated string identifying the section in the SYSTEM.INI file to search. Can be zero, in which case the service searches the [386Enh] section.
Keyname
Address of a null-terminated string specifying keyname to search for.

A valid hexadecimal number consist of any combination of hexadecimal digits (0–9, A-F), and can be terminated with the uppercase or lowercase letter H.

See Also

Get_Profile_Boolean, Get_Profile_Decimal_Int, Get_Profile_Fixed_Point


Get_Profile_String

include vmm.inc

mov     edx, OFFSET32 Default   ; optional default string
mov     esi, OFFSET32 Profile   ; section name
mov     edi, OFFSET32 Keyname   ; entry name
VMMCall Get_Profile_String

jc      not_found               ; carry set if entry not found
mov     [Value], edx            ; address of profile string

Searches the SYSTEM.INI file for a specified entry, and returns a pointer to a null-terminated string representing the entry value. This service is only available during initialization. Uses EDX, Flags.

  • Returns with the carry flag clear if the entry is found, set otherwise. If the carry flag is clear, the EDX register contains the address of the null-terminated string representing the entry value.
Default
Address of a null-terminated string to be returned if the entry is not found, or has no current value.
Profile
Address of a null-terminated string identifying the section in the SYSTEM.INI file to search. Can be zero, in which case the service searches the [386Enh] section.
Keyname
Address of a null-terminated string specifying keyname to search for.

A virtual device must not modify the string pointed to by the EDX register. If modification is required, copy the string and modify the copy.

See Also

Get_Next_Profile_String


Get_PSP_Segment

include vmm.inc

VMMCall Get_PSP_Segment

mov     [PSP], eax          ; segment address of PSP

Returns the segment address of program segment prefix (PSP) for the Windows virtual machine manager (VMM32.VSD). This service is only available during initialization. Uses EAX, Flags.

  • Returns the PSP segment address in the EAX register. The high-order word is zero. To convert the segment address to a linear address, shift it left by 4 bits.

Virtual devices typically use this service to retrieve values from the PSP that can not be retrieved using the Get_Exec_Path and Get_Environment_String services.

See Also

Get_Environment_String, Get_Exec_Path


Get_Set_Real_DOS_PSP

include vmm.inc

mov ebx, VMHandle
mov ax, NewPSP
mov ecx, dwFlags
VMMCall Get_Set_Real_DOS_PSP

Gets or sets the PSP for the specified VM. Uses the EAX, ECX, and EDX registers.

  • If performing a set operation, returns the previous PSP value in the AX register. If performing a get operation, returns the current PSP value in the AX register.
VMHandle
Handle to the VM.
NewPSP
New PSP to set if dwFlags is GSRDP_Set.
dwFlags
Specify GSRDP_Set to set the PSP to a new value. Or, specify zero to retrieve the current PSP value.


Locate_Byte_In_ROM

include vmm.inc

mov     al, Byte            ; byte to locate
VMMCall Locate_Byte_In_ROM

jc      not_found           ; carry flag set if byte not found
mov     [Location], eax     ; linear address of byte

Scans the system ROM for a specified byte. Virtual devices use this service to locate single-byte instructions, such as the iret instruction, that must be protected from modification by programs running in a virtual machine. This service is only available during initialization. Uses EAX, Flags.

  • Returns the carry flag clear if the byte was found. The EAX register contains the linear address of the byte. The carry flag is set if the byte was not found or the user disabled the service.
Byte
Byte value to search for.

Users can disable this service by setting to false the SystemROMBreakpoint setting in the [386Enh] section of the SYSTEM.INI file.


OpenFile

include vmm.inc

mov     edx, OFFSET32 Filename  ; address of name of file to open
mov     edi, OFFSET32 Buffer    ; buffer to receive full path
VMMCall OpenFile

jc      not_found               ; carry set if file not found
mov     [Handle], eax           ; MS-DOS file handle

Opens the specified file for reading (in compatibility mode). For Windows 95, this service can be called during or following initialization. Uses EAX, Flags.

  • Returns with the carry flag clear if successful, set otherwise. If the carry flag is clear, the EAX register contains an MS-DOS file handle.
Filename
Address of a null-terminated string specifying the name of the file to open.
Buffer
Address of a buffer that receives the full path of the file, if found. If this service is called during initialization, the buffer must be at least 128 bytes. If this service is called following initialization, the buffer size, in bytes, must be at least VMM_OPENFILE_BUF_SIZE.

If the specified filename includes a drive letter or path, the service looks for the file only in the specified drive and directory. Otherwise, the service searches for the file in the directories specified by the following:

  • WINDIR environment variable
  • First command-line argument (argv[0]) of Windows
  • Current working directory
  • PATH environment variable

Otherwise, the service does not search for the file. In either case, the service attempts to opens the file for reading (in compatibility mode), and returns the MS-DOS file handle if it is successful.

If WINDIR and PATH environment variables are not well formed, this service cannot guarantee that the full path copied to the Buffer parameter will be well formed.

This service fails if the current virtual machine cannot support a call to the Exec_Int service.

This service fails during initialization if the virtual machine has already used the _Allocate_Temp_V86_Data_Area service to allocate the temporary buffer.

See Also

_Allocate_Temp_V86_Data_Area, Exec_Int


VMM_GetSystemInitState

include vmm.inc

VMMCall VMM_GetSystemInitState

mov [InitState], eax

Retrieves the current system initialization state. Uses EAX, ECX, Flags.

  • Returns the current system initialization state in the EAX register.

    The following table identifies initialization milestones and return values for VMM_GetSystemInitState. Milestones are listed in the table in chronological order. When a milestone completes, this service returns the value (one of the values) listed to the right of the milestone. The first value is returned if the first milestone has not been completed.

Milestone | VMM_GetSystemInitState return value
SYS_CRITICAL_Init is broadcast | SYSSTATE_PRESYSCRITINIT (00000000h)
DEVICE_INIT is broadcast | SYSSTATE_PREDEVICEINIT (10000000h)
INIT_COMPLETE is broadcast | SYSSTATE_PREINITCOMPLETE (20000000h)
 | SYSSTATE_VXDINITCOMPLETED (40000000h)
KERNEL32_INITIALIZED is broadcast | SYSSTATE_KERNEL32INITED (50000000h)
KERNEL32_SHUTDOWN is broadcast | SYSSTATE_KERNEL32TERMINATED (A0000000h) STATE_PRESYSVMTERMINATE (B0000000h)
SYS_VM_TERMINATE is broadcast | SYSSTATE_PRESYSTEMEXIT (E0000000h)
SYSTEM_EXIT is broadcast | SYSSTATE_PRESYSTEMEXIT2 (E4000000h)
SYSTEM_EXIT2 is broadcast | SYSSTATE_PRESYSCRITEXIT (F0000000h)
SYS_CRITICAL_EXIT is broadcast | SYSSTATE_PRESYSCRITEXIT2 (F4000000h)
SYS_CRITICAL_EXIT2 is broadcast |
Return to real mode | SYSSTATE_POSTSYSCRITEXIT2 (FFF00000h)
DEVICE_REBOOT_NOTIFY is broadcast (See Device_Reboot_Notify function) | SYSSTATE_PREDEVICEREBOOT (0xFFFF0000)
CRIT_REBOOT_NOTIFY is broadcast (See Crit_Reboot_Notify function) | SYSSTATE_PRECRITREBOOT (0xFFFFF000)
REBOOT_PROCESS REBOOT_PROCESS REBOOT_PROCESS REBOOT_PROCESSOR is broadcast (See Reboot_Processor function) | SYSSTATE_PREREBOOTCPU (0xFFFFFF00)

VMM.H contains the above definitions.

Future versions of Windows may have additional initialization states with values between the ones defined here, which implies that you should use a relational comparison to test the initialized state. Currently, this service returns zero in ECX, but additional information may be returned in this register in the future.


Linked Lists

There are the following linked list services:

Service | Description
List_Allocate | Allocates a new node for a list.
List_Attach | Attaches a node to the head of the list.
List_Attach_Tail | Attaches a node to the end of the list.
List_Create | Creates a list.
List_Deallocate | Deallocates a node.
List_Destroy | Destroys a list.
List_Get_First | Returns the address of the first node.
List_Get_Next | Returns the address of next node in the list.
List_Insert | Inserts a node into a list.
List_Remove | Removes a node from the list.
List_Remove_First | Removes the first node in list.


List_Allocate

include vmm.inc

mov     esi, List       ; list handle
VMMCall List_Allocate

jc      not_allocated   ; carry flag set if error
mov     [Node], eax     ; address of new node

Allocates a new node for the specified list. A virtual device can attach the new node to the list using the List_Attach, List_Attach_Tail or List_Insert service. The contents of the new node are undefined. Uses EAX, Flags.

  • Returns with the carry flag clear and the address of the new node in the EAX register if successful. For lists created using the LF_Alloc_Error value, the service returns with the carry flag set if a node cannot be allocated. For other lists, the service does not return if a node cannot be allocated. (It crashes the current virtual machine instead.)
List
Handle of the list.

If the list is created using the LF_Use_Heap value, this service calls the _HeapAllocate service for each node, in which case all the rules regarding heap access apply to List_Allocate as well.

Otherwise, the service allocates nodes from a pool of free nodes. This avoids the overhead of calling the _HeapAllocate service for every node allocation. This non-reliance on _HeapAllocate has both positive and negative consequences. On the positive side, it means that List_Allocate can be called at times when _HeapAllocate cannot be called, such as during hardware interrupts. On the negative side, this means that if the VMM cannot satisfy the allocation request from its pool of free nodes, it cannot obtain more memory from the heap because it might not be safe to call _HeapAllocate at the time the call to List_Allocate made. VMM maintains an emergency pool of memory into which it can dip when faced with this situation. The emergency pool is refreshed from the system heap at a time when _HeapAllocate is safe to call.

The consequence of this tradeoff is that virtual devices should not allocate large numbers of nodes in rapid succession from lists not marked LF_Use_Heap, because that would dry up the free list and emergency pool, causing List_Allocate to fail.

See Also

List_Attach, List_Attach_Tail, List_Create, List_Deallocate, List_Insert


List_Attach

include vmm.inc

mov     esi, List       ; list handle
mov     eax, Node       ; address of node to attach
VMMCall List_Attach

Attaches a list node to the head (front) of a list. A virtual device can attach a node to any list that has a matching node size and was created with the same flags. (It is an error, for example, to attach a node allocated from a list created as LF_Use_Heap to a list created without that flag, even if the node sizes agree.) This service can be used, for example, to move a node from one list to another. Uses Flags.

  • No return value.
List
Handle of the list. The handle must have been previously created using the List_Create service.
Node
Address of the node to attach. The node must have been previously created using the List_Allocate service.

The service attaches the node to the head of the list. Subsequent calls to the List_Get_First service return the address of this node. The address of the previous head of the list can be retrieved using the List_Get_Next service.

See Also

List_Allocate, List_Create, List_Get_First, List_Get_Next, List_Remove, List_Remove_First


List_Attach_Tail

include vmm.inc

mov     esi, List   ; list handle
mov     eax, Node   ; address of node to attach
VMMCall List_Attach_Tail

Attaches a list node to the tail (end) of a list. A virtual device can attach a node to any list that has a matching node size and was created with the same flags. (It is an error, for example, to attach a node allocated from a list created as LF_Use_Heap to a list created without that flag, even if the node sizes agree.) This service can be used, for example, to move a node from one list to another. Uses Flags.

  • No return value.
List
Handle of the list. The handle must have been previously created using the List_Create service.
Node
Address of the node to attach. The node must have been previously created using the List_Allocate service.

The service attaches the node to the end of the list. A virtual device can retrieve the address of the node by calling the List_Get_Next service and specifying the address of the previous end of the list.

See Also

List_Allocate, List_Create, List_Get_Next, List_Remove


List_Create

include vmm.inc

mov     eax, Flags      ; creation flags
mov     ecx, NodeSize   ; size in bytes of each node in list
VMMCall List_Create

jc      error           ; carry flag set if error
mov     [List], esi     ; list handle

Creates a new list and returns a list handle that virtual devices use in subsequent calls to other list services. Uses ESI, Flags.

  • Returns with the carry flag clear and the list handle in the ESI register, if successful. The carry flag is set if an error occurs.
Flags
Creation flags. Can be zero or more of these values:
Value | Meaning
LF_Alloc_Error | Directs the List_Allocate service to returns with carry flag set if new node could not be allocated.
LF_Async | Creates an asynchronous list that can be used while processing interrupts.
LF_Use_Heap | Allocates nodes on the system heap. This value must not be used in combination with the LF_Async value.
LF_Swap | Allocates nodes from the swappable system heap. This value must not be used in combination with the LF_Async value.

NodeSize
Size, in bytes, of each node in the list.

If a virtual device requires large nodes, it should specify the LF_Use_Heap value to force the nodes to be allocated from the system heap. All allocate and deallocate calls for lists created in this way use the _HeapAlloc and _HeapFree services to create and destroy nodes.

To access a list during hardware interrupts, a virtual device must set the LF_Async value when creating the list. This forces list operations to be atomic operations which cannot be re-entered. When using an asynchronous list, the virtual device must disable interrupts before calling the list services. The virtual device must disable interrupts even if when not calling during an interrupt. The virtual device must use the pushf, cli, and popf instructions to disable and re-enable interrupts. It must not use the sti instruction to enable interrupts unless other documentation states that this is permitted.

If the LF_Alloc_Error value is not specified, the system crashes the current virtual machine if the List_Allocate service fails. If this value is specified, List_Allocate returns with the carry flag set when an allocation fails.

If the LF_Swap value is specified, then list nodes are allocated from the swappable system heap. Consequently, all list services related to swappable list nodes become subject to constraints on accessing swappable memory.

See Also

List_Allocate, List_Deallocate, List_Destroy


List_Deallocate

include vmm.inc

mov     esi, List       ; list handle
mov     eax, Node       ; address of node to free
VMMCall List_Deallocate

Frees the specified node. Once a virtual device frees a node, it must not attempt to use the node. Uses EAX, Flags.

  • No return value.
List
Handle of the list. The handle must have been previously created using the List_Create service.
Node
Address of the node to free. The node must have been previously created using the List_Allocate service.

This service normally never destroys a node. Instead, the service places the node back in the free pool. The node can then quickly be reclaimed when the List_Allocate service is called. If the list is created using the LF_Use_Heap value, this service calls the _HeapFree service for each node.

See Also

_HeapFree, List_Allocate, List_Create


List_Destroy

include vmm.inc

mov     esi, List       ; list handle
VMMCall List_Destroy

Frees all nodes in a list, and destroys the list handle. Once a virtual device destroys a list, it must not attempt to use the list handle. Uses ESI, Flags.

  • No return value.
List
Handle of the list. The handle must have been previously created using the List_Create service.

See Also

List_Create


List_Get_First

include vmm.inc

mov     esi, List       ; list handle
VMMCall List_Get_First

jz      empty_list      ; zero flag set if list is empty
mov     [Node], eax     ; address of first node

Returns the address of the first node in a list. Uses EAX, Flags.

  • Returns with the zero flag clear and the address of the first node in the EAX register if successful. If the list is empty, the zero flag is set and EAX is zero.
List
Handle of the list. The handle must have been previously created using the List_Create service.

See Also

List_Attach, List_Create, List_Get_Next


List_Get_Next

include vmm.inc

mov     esi, List       ; list handle
mov     eax, Node       ; address of node
VMMCall List_Get_Next

jz      empty_list      ; zero set if no more nodes in list
mov     [Node], eax     ; address of next node

Returns the next node in a list after the specified node. This service is typically used in conjunction with the List_Get_First service to scan an entire list. Uses EAX, Flags.

  • Returns with the zero flag clear and the address of the next node in the EAX register if successful. If there are no more nodes, the zero flag is set and EAX is zero.
List
Handle of the list. The handle must have been previously created using the List_Create service.
Node
Address of a node in the list. The address must have been previously retrieved using the List_Get_First or List_Get_Next service.

See Also

List_Create, List_Get_First


List_Insert

include vmm.inc

mov     esi, List    ; list handle
mov     eax, NewNode ; address of node to insert
mov     ecx, Node    ; address of node to insert after (0 to attach to head)
VMMCall List_Insert

Inserts a node immediately after the specified node in a list. A virtual device can insert a node into any list that has a matching node size and was created with the same flags. (It is an error, for example, to attach a node allocated from a list created as LF_Use_Heap to a list created without that flag, even if the node sizes agree.) This can be used, for example, to move a node from one list to another. Uses Flags.

  • No return value.
List
Handle of the list. The handle must have been previously created using the List_Create service.
NewNode
Address of the node to insert. The node must have been previously created using the List_Allocate service.
Node
Address of a node in the list. The address must have been previously retrieved using the List_Get_First or List_Get_Next service. If this parameter is zero, the service attaches the new node to the head of the list.

This service inserts the new node between the specified node and the node immediately following the specified node. A virtual device can retrieve the address of the new node by calling the List_Get_Next service, and specifying the Node parameter.

See Also

List_Attach, List_Attach_Tail


List_Remove

include vmm.inc

mov     esi, List       ; list handle
mov     eax, Node       ; address of node to remove
VMMCall List_Remove

jc      not_removed     ; carry flag set if error

Removes the specified node from the list. Uses EAX, Flags.

  • Returns with the carry flag clear if successful, set otherwise.
List
Handle of the list. The handle must have been previously created using the List_Create service.
Node
Address of the node to remove. The node must have been previously retrieved using the List_Get_First or List_Get_Next service.

This service does not deallocate the node. It is up to the virtual device to free the node, or attach it to another list.

See Also

List_Create, List_Remove_First


List_Remove_First

include vmm.inc

mov     esi, List       ; list handle
VMMCall List_Remove_First

jz      list_empty      ; zero flag set if list is empty
mov     [Node], eax     ; address of node removed

Removes the first node from a list. Uses EAX, Flags.

  • Returns with the zero flag clear if successful, or set if the list is empty. The EAX register contains the address if the removed node, or zero if none.
List
Handle of the list. The handle must have been previously created using the List_Create service.

This service does not free the node. It is up to the virtual device to free the node, or attach it to another list.

See Also

List_Create, List_Remove


Miscellaneous Services

There are the following miscellaneous services:

Service | Description
_AddReclaimableItem | Identifies regions of VM memory that can be reclaimed.
Begin_Reentrant_Execution | Start re-entrant execution.
_CallRing3 | Reserved for internal use.
Close_Boot_Log | Closes the system boot log.
Directed_Sys_Control | Jumps to the VxD's device-control procedure.
EnableDisable_Boot_Log | Enables or disables boot logging from the virtual machine manager (VMM).
End_Reentrant_Execution | End re-entrant execution.
_EnumReclaimableItem | Enumerates reclaimable regions of VM memory declared by a previous call to the _AddReclaimableIem.
Get_Boot_Flags | Retrieves the boot-time flags.
Get_DDB | Determines whether or not a VxD is installed for the specified device and returns a DDB (Device Description Block) for that device if it is installed.
GetSetDetailedVMError | Gets and sets error information.
_GetVxDName | Retrieves the name of the VxD that contains the specified linear address.
Hook_Device_PM_API | Installs a protected-mode API callback.
Hook_Device_Service | Installs a hook for a device service.
Hook_Device_V86_API | Installs a V86-mode API callback.
Install_Exception_Handler | Installs an exception handler.
_LocalizeSprintf | To be supplied.
_LocalizeStackSprintf | To be supplied.
Log_Fault_Call_Out | Callout service that the VMM calls when it is about to report a fault to the user.
Map_Flat | Converts a V86 or protected-mode address.
Map_Lin_To_VM_Addr | Converts a linear address.
MMGR_SetNULPageAddr | Sets the physical address of system nul page.
Open_Boot_Log | Opens the system boot log.
_Register_Win32_Services | Copies the location of the calling VxD's Win32 service-table in the DDB.
Remove_Exception_Handler | Removes an exception handler.
Set_Boot_Flags | Sets the boot-time flags.
Set_Delete_On_Exit_File | Adds a file to the list to delete when exiting.
_SetReclaimableItem | Marks as fully reclaimable or restorable, the regions of reclaimable VM memory declared by a previous call to the _AddReclaimableItem service.
Set_System_Exit_Code | Sets the Windows exit code value.
System_Control | Sends a control message to all virtual devices.
Unhook_Device_Service | Unhooks a device service.
VMM_Add_DDB | Adds a Vxd_Desc_Block structure (DDB or Device Description Block) to the appropriate location in the device list (the locations are based on the initialization order).
VMM_GetDDBList | Retrieves the address of the DDB (Device Description Block) list.
VMM_GetVxDLocationList | Returns the address of the VxD location list in EAX, returns the count of VxDs in EDX, and returns the list size (in bytes) in ECX.
VMM_Remove_DDB | Removes a Vxd_Desc_Block structure (DDB or Device Description Block) from the device list.
VMMAddImportModuleName | Adds the specified import-module name to an internal table.


_AddReclaimableItem

#include vmm.h

_AddReclaimableItem(ReclaimStruc *pReclaim, DWORD Flags);

Identifies regions of VM memory that may be reclaimable. Uses C calling convention and the EAX, ECX, EDX, and Flags registers.

  • Returns non-zero in the EAX register if successful; otherwise returns zero in EAX.
pReclaim
Address of ReclaimStruc structure to add. The callback in the RS_CallBack member of the ReclaimStruc structure is called using the CDECL calling and register conventions, and has no defined return value. The reference data for the callback, if any, is not passed separately, since it is already available in the ReclaimStruc.
Flags
Reserved; must be 0.

If a region is already reclaimable, then RS_RECLAIM should be specified in the RS_Flags member of the specifed ReclaimStruc structure. Otherwise, a subsequent call to _SetReclaimableItem must be made to set RS_RECLAIM sometime prior to Init_Complete in order for the block to be re-used.

If the block's contents must be restored prior to System_Exit, then RS_RESTORE must also be specified in the RS_Flags member. If an optional callback address is also provided, then it will be called immediately after the contents have been restored, prior to System_Exit.

If the system elects to not use a fully-reclaimable block (for example, if the block's alignment or size makes it unsuitable), it will still call the caller's callback address, if any, so that any external references to the block can still be restored.

In the unlikely event a block marked reclaimable cannot later be reclaimed, call _SetReclaimableItem with the RS_RECLAIM flag clear.

See Also

_EnumReclaimableItem, ReclaimStruc, _SetReclaimableItem


Begin_Reentrant_Execution

include vmm.inc

VMMCall Begin_Reentrant_Execution

mov     [Count], ecx        ; re-entrancy count

Starts re-entrant execution. Virtual devices use this service when hooking VMM faults (re-entrant processor exceptions) so that they may call nonasynchronous VMM or virtual device services, or execute a virtual machine. Uses ECX, Flags.

Most virtual devices have no reason to use this service. Do not use this service to avoid scheduling events on hardware interrupts.

  • Returns the old re-entrancy count in the ECX register. This count must be passed to the End_Reentrant_Execution service.

See Also

End_Reentrant_Execution


_CallRing3

This service is reserved for the Shell VxD to implement application-time events. Do not call this service directly. To call ring 3 code from a VxD, use the SHELL_CallAtAppyTime service.


Close_Boot_Log

include vmm.inc

VMMCall Close_Boot_Log

Requests that the system boot log be closed.

  • No return value.

See Also

EnableDisable_Boot_Log, Open_Boot_Log


Directed_Sys_Control

include vmm.inc

mov     ecx, DDB
VMMCall Directed_Sys_Control

Jumps to the VxD's device-control procedure. Use this service instead of calling the control procedure directly.

  • Return value depends on the message sent to the virtual device.
DDB
VxD's DDB (Device Description Block) that contains device control procedure. All other registers are passed unaltered to the control procedure.


EnableDisable_Boot_Log

include vmm.inc

move    eax, fEnable
VMMCall EnableDisable_Boot_Log

Enables or disables boot logging from the virtual machine manager (VMM). This service is intended to be used by the system (IOS) to indicate whether it is safe to write to the disk; other VxDs should not use this service. Uses Flags.

  • No return value.
fEnable
Enable flag. If non-zero, enables boot logging; if zero, disables it.

See Also

Close_Boot_Log, Open_Boot_Log


End_Reentrant_Execution

include vmm.inc

mov     ecx, Count      ; re-entrancy count
VMMCall End_Reentrant_Execution

Ends re-entrant execution. A virtual device that calls the Begin_Reentrant_Execution service must call this service before returning. Uses Flags.

  • No return value.
Count
Re-entrancy count previously returned by the Begin_Reentrant_Execution service.

See Also

Begin_Reentrant_Execution


_EnumReclaimableItem

#include vmm.h

DWORD _EnumReclaimableItem(DWORD enumKey, ReclaimStruc *pReclaim,
    DWORD Flags);

Enumerates regions of potentially reclaimable VM memory that were added by a previous call to the _AddReclaimableItem service. The items are enumerated in ascending order according to their addresses. Uses C calling convention and the EAX, ECX, EDX, and Flags registers.

  • Returns the enumeration key in EAX for each reclaimable region, or zero if there are no reclaimable regions or the last region has been enumerated.
enumKey
Enumeration key. Set this parameter to zero to begin enumeration. Subsequent calls to this service specify enumeration keys returned by previous calls.
pReclaim
Address of the ReclaimStruc structure that receives information about a reclaimable region.
Flags
Reserved; must be 0.

See Also

_AddReclaimableItem, ReclaimStruc, _SetReclaimableItem


Get_Boot_Flags

include vmm.inc

VMMCall Get_Boot_Flags

mov [BootFlags], eax

Retrieves the boot-time flags. Uses Flags.

  • Returns the boot time flags in the EAX register which may be one of the following:
BOOT_CLEAN | (00000001H)
BOOT_DOSCLEAN | (00000002H)
BOOT_NETCLEAN | (00000004H)
BOOT_INTERACTIVE | (00000008H)


Get_DDB

include vmm.inc

mov     eax, Device_ID
mov     edi, Device_Name
VMMCall Get_DDB
mov     [DDB], ecx

Determines whether or not a VxD is installed for the specified device and returns a DDB (Device Description Block) for that device if it is installed. Uses ECX, flags.

  • Returns a DDB for the specified device if the function succeeds; otherwise, returns zero.
Device_ID
The device identifier. This parameter can be zero for name-based devices.
Device_Name
An eight-character device name that is padded with blank characters. This parameter is only required if Device_ID is zero. The device name is case-sensitive.


GetSetDetailedVMError

include vmm.inc

mov     ebx, VM       ; VM handle or 0 if Create_VM error
mov     ecx, GetSet   ; zero if get, nonzero zero if set
mov     eax, Error    ; error code if ecx nonzero
mov     edx, RefData  ; reference data if ecx is nonzero
VMMCall GetSetDetailedVMError

jz      no_error_info   ; zero set if no error information

mov     [Error], eax    ; error code
mov     [RefData], edx  ; reference data for the error code

Sets detailed error code for a virtual machine crash or start-up error. This service is only available for Windows version 3.1 or later. Uses EAX, EDX, Flags.

  • Returns with the zero flag clear if detailed error information was found, set otherwise. If the zero flag is clear, the EAX register contains an error code and the EDX register contains reference data associated with the error code.
VM
Handle of the virtual machine. If this parameter is zero, the service gets or sets error information for the Create_VM message.
GetSet
Value specifying the action to take. If zero, the service retrieves error information. If nonzero, the service sets error information.
Error
Error code to set. This parameter is ignored if the GetSet parameter is zero. There are the following error code values:
Value | Meaning
GSDVME_CrtNoMsg | Problem creating the VM. The system will not display any error message; it is the responsibility of the virtual device to use the SHELL_Message service to display a custom error message.
GSDVME_DevNuke | Device-specific problem.
GSDVME_DevNukeHdwr | Device-specific problem caused by software running in the virtual machine.
GSDVME_InsMemEMS | Available EMS memory is less than requested; set by the virtual V86 mode memory manager.
GSDVME_InsMemV86 | Insufficient V86 memory; set by the virtual V86 mode memory manager.
GSDVME_InsMemV86Hi | Insufficient high MS-DOS memory; set by the virtual MS-DOS manager.
GSDVME_InsMemVid | Insufficient base video memory; set by the virtual display device.
GSDVME_InsMemVM | Insufficient base virtual machine memory for control block or instance buffer.
GSDVME_InsMemXMS | Available XMS memory is less than requested; set by the virtual V86 mode memory manager.
GSDVME_InsV86Space | Available V86 address space is less than requested; set by the virtual V86 mode memory manager.
GSDVME_InvalFlt | Invalid fault.
GSDVME_InvalGpFlt | Invalid GP fault.
GSDVME_InvalInst | Attempt to execute an invalid instruction.
GSDVME_InvalPgFlt | Invalid page fault.
GSDVME_InsMemDev | Could not allocate base virtual machine memory for device.
GSDVME_NukeNoMsg | Fatal problem forcing the VM to be destroyed. The system will not display any error message; it is the responsibility of the virtual device to use the SHELL_Message service to display a custom error message.
GSDVME_OkNukeMask | Reserved for the exclusive use of the virtual MS-DOS manager.
GSDVME_PrivInst | Attempt to execute a privileged instruction.
GSDVME_UserNuke | User requested running virtual machine be terminated.

Error values that have the high word set to 2 are intended to be used when a virtual machine fails on start up.

RefData
Reference data to set. If the Error parameter is GSDVME_PrivInst, GSDVME_InvalInst, GSDVME_InvalPgFlt, GSDVME_InvalGpFlt, or GSDVME_InvalFlt, this parameter is the address of a VMFaultInfo structure that contains data associated with the error. Otherwise, RefData is a pointer to an eight-character buffer giving the name of the virtual device that reported the error.

This parameter is ignored if the GetSet parameter is zero. This parameter is zero if there is no associated reference data.


_GetVxDName

#include vmm.h

_GetVxDName(DWORD laddr, DWORD pszName);

mov [BaseAddr], eax

Retrieves the name of the VxD that contains the specified linear address.

  • Returns the base address of the VxD in the EAX register if successful; otherwise returns 0 in EAX. Uses C calling convention.
laddr
Linear address to locate.
pszName
Buffer to receive the object name. If the function fails, pszName is filled in with the ASCII version of laddr. This buffer must be at least 80 bytes in size.

Object names consist of the VxD name, segment number, and offset; for example, VTDAPI(03) + 27C.


Hook_Device_PM_API

include vmm.inc

mov     eax, ID                 ; device ID
mov     esi, OFFSET32 Callback  ; points to new API callback
VMMCall Hook_Device_PM_API

Installs an API callback procedure allowing a virtual device to intercept calls to the protected-mode API of another virtual device. This service is intended to support virtual devices that need to monitor calls to the APIs of other virtual devices. Most virtual devices will never need this service. Uses ESI, Flags.

  • Returns with the carry flag clear if successful, set if the specified virtual device does not support a protected-mode API. If successful, the ESI register contains the address of the previous callback procedure.
ID
Identifier of the virtual device to monitor.
Callback
Address of the callback procedure to install. For more information about the callback procedure, see below.

The system calls the callback procedure whenever an application in a virtual machine calls the API for the specified virtual machine. The system calls the callback as follows:

mov     ebx, VM             ; current VM handle
mov     ebp, OFFSET32 crs   ; points to Client_Reg_Struc
call    [Callback]

The VM parameter is a handle identifying the current virtual machine and the crs parameter points to a Client_Reg_Struc structure containing the register values of the current virtual machine. Other registers contain the parameter values intended for the API.

The callback procedure can carry out tasks, but eventually must pass execution to the previous API callback procedure, preserving the EBX and EBP registers when it calls.

See Also

Hook_Device_V86_API


Hook_Device_Service

include vmm.inc

GetVxDServiceOrdinal eax, Service
mov     esi, OFFSET32 HookProc  ; points to the hook procedure to install
VMMCall Hook_Device_Service

jc      not_installed           ; carry flag set if error
IF WIN31COMPAT
mov     [Real_Proc], esi
ENDIF

Allows one virtual device to monitor or replace the services of another virtual device, or of the VMM itself. Uses ESI, Flags.

  • Returns with the carry flag clear if successful, set otherwise. If successful, the ESI register contains the address of the specified service.
Service
Virtual device or VMM service to hook.
HookProc
Address of the hook procedure to install. The hook procedure is called with the same parameters as the service specified by the Service parameter.

When a dynamically-loaded VxD is unloaded, it must remove any service hook procedures it has installed by using the Unhook_Device_Service service.

Virtual devices that use this service must use extreme care to preserve the full functionality of the virtual device whose services are monitored or replaced.

More than one virtual device can hook a device service. The last hook installed is the first one called.

The hook procedure must save and restore registers that are not modified by the hooked service. Also, if flags are a passed as an entry or exit parameter, the hook procedure must also preserve the flags.

If the hooked service uses the C calling convention, the hook procedure must copy the entire parameter stack frame before attempting to call the hooked service. If the hooked service uses a register-based calling convention, the hook procedure must preserve all registers, even registers that are not currently used as input or output parameters.

The hook procedure must have been declared with the HOOK_PROC attribute to the BeginProc macro.

See Also

Unhook_Device_Service


Hook_Device_V86_API

include vmm.inc

mov     eax, ID                 ; device ID
mov     esi, OFFSET32 Callback  ; points to new API callback
VMMCall Hook_Device_V86_API

Installs an API callback procedure allowing a virtual device to intercept calls to the V86 mode API of another virtual device. This service is intended to support virtual devices that need to monitor calls to the APIs of other virtual devices. Most virtual devices will never need this service. Uses ESI, Flags.

  • Returns with the carry flag clear if successful, set if the specified virtual device does not support a V86-mode API. If successful, the ESI register contains the address of the previous callback procedure.
ID
Identifier of the virtual device to monitor.
Callback
Address of the callback procedure to install. For more information about the callback procedure, see below.

The system calls the callback procedure whenever an application in a virtual machine calls the API for the specified virtual machine. The system calls the callback as follows:

mov     ebx, VM             ; current VM handle
mov     ebp, OFFSET32 crs   ; points to Client_Reg_Struc
call    [Callback]

The VM parameter is a handle identifying the current virtual machine and the crs parameter points to a Client_Reg_Struc structure containing the register values of the current virtual machine. Other registers contain the parameter values intended for the API.

The callback procedure can carry out tasks but eventually must pass execution to the previous API callback procedure, preserving the EBX and EBP registers when it calls.

See Also

Hook_Device_PM_API


Install_Exception_Handler

include vmm.inc

mov     esi, Exception          ; points to an Exception_Handler_Struc
VMMCall Install_Exception_Handler

jc      not_installed           ; carry flag set if error

Installs a ring-0 exception handler. Uses Flags.

  • Returns with the carry flag clear if successful, set otherwise.
Exception
Address of an Exception_Handler_Struc structure containing information about the exception handler to install.

The system saves a pointer to the specified Exception_Handler_Struc structure instead of copying it. Therefore, the structure must not be in pageable memory, and must not be freed or overwritten until the exception handler is removed.

The system calls the exception handler only if the exception occurs within the range of addresses specified by the EH_StartIP and EH_EndIP fields in the Exception_Handler_Struc structure. The system calls the exception handler with the stack and all registers in same state as when exception occurred.

You can use the Remove_Exception_Handler service to remove an exception handler that was installed using this service.

See Also

Exception_Handler_Struc, Remove_Exception_Handler


_LocalizeSprintf

$include vmm.inc

VMMCall _LocalizeSprintf, <pOutBuf, pmab, RelativeMessageNumber,
    Param1, Param2, ...>

Format a localizable string. Uses EAX, ECX, EDX, and Flags.

  • No return value.
pOutBuf
Address of a buffer to receive formatted message. No limit checking is done on the buffer.
pmab
Address of a message anchor block constructed by the message macros.
RelativeMessageNumber
Message number relative to the base message number for the message class.
Param1, Param2, ...
Parameters for the formatted message.

Virtual devices typically use the LOCALIZE_SPRINTF macro instead of calling this service directly.


_LocalizeStackSprintf

This service is for internal use only. Use one of the PUSH_SPRINTF macros instead of this service.


Log_Fault_Call_Out

include vmm.inc

mov     edi, ThreadHandle
mov     esi, FaultNumber
mov     eax, OFFSET32 EventProc
mov     edx, UpperStackLimit
mov     ebp, FrameClient_Regs
VMMCall Log_Fault_Call_Out
jnc     not_handled

This is a callout service that the VMM calls when it is about to report a fault to the user. It is provided so that a supplemental VxD can hook this service and log faults that are reported. The supplemental VxD can also handle the fault notification itself and indicate to the VMM that it shouldn't duplicate the notification. Virtual deices should not call this service directly.

  • Sets the carry flag if the notification has been handled, indicating that the VMM should not do its own notification.
VMHandle
Handle of the current virtual machine.
FaultNumber
Number of the fault to report.
FrameClient_Regs
Ring 0 client registers of the fault stack frame.
EventProc
Address of the event procedure for the event being processed, address of the timeout procedure associated with the timeout being processed, or zero if neither an event nor a timeout was processed.
UpperStackLimit
Upper limit of stack used by event being processed, or garbage if neither an event nor a timeout was processed.

Before calling this service (that is, on entry to the hook procedure), the stack looks like this:

esp    <undefined area between the current ESP and EBP-16>
ebp-16  -> saved gs
ebp-12  -> saved fs
ebp-8   -> saved es
ebp-4   -> saved ds
ebp     -> pushad frame
        -> error code
        -> faulting eip
        -> faulting cs
        -> flags
edx     -> upper limit of stack used by event being processed

Notifications can not be suppressed if the fault was not caused by an event or timeout.

This service can modify any of the registers


Map_Flat

include vmm.inc

mov     ah, SegOffset    ; client register containing the segment
mov     al, OffOffset    ; client register containing the offset
VMMCall Map_Flat

cmp     eax, -1         ; -1 if error
je      error
mov     [LinAddr], eax  ; ring-0 linear address

Converts the address contained in the specified client registers to a linear address. The given address is either a selector:offset or segment:offset address, depending on the execution mode of the current virtual machine. Uses EAX, Flags.

  • Returns a ring-0 linear address in the EAX register if successful, – 1 if the specified selector is invalid.
SegOffset
Offset of the client register containing the segment address or selector.
OffOffset
Offset of the client register containing the offset address. Can be – 1, in which case the offset address is zero.

The SegOffset and OffOffset parameters specify offsets, in bytes, relative to the beginning of the Client_Reg_Struc structure for the current virtual machine.

Before converting an address, Map_Flat checks the current execution mode and, for protected-mode applications, the bitness of the DPMI client. If the virtual machine is running a 32-bit protected mode application, it uses 32-bit address offsets. For V86 and 16-bit protected-mode applications, it uses 16-bit address offsets and ignores the high word if the OffOffset parameter specifies a 32-bit register.

The following example converts the address Client_DS:Client_DX and returns the linear address in EAX:

mov     ax, (Client_DS SHL 8) + Client_DX
VMMCall Map_Flat

It is typically more convenient to use the Client_Ptr_Flat macro instead.

See Also

Client_Ptr_Flat


Map_Lin_To_VM_Addr

include vmm.inc

mov     eax, LineAddr   ; linear address to convert
mov     ecx, Limit      ; segment limit in bytes
VMMCall Map_Lin_To_VM_Addr

jc      error           ; carry flag set if error
mov     [SegSel], cx    ; segment or selector
mov     [Offset], edx   ; address offset

Converts a 32-bit ring-0 linear address into an V86 or protected-mode address. This service converts the address for use with the current execution mode of the current virtual machine. Uses ECX, EDX, Flags.

  • Returns with the carry flag clear if successful, set otherwise. If the carry flag is clear, the CX register contains the segment address or selector, and the EDX register contains the offset address. The offset is always zero if the virtual machine is running a protected-mode application.
LinAddr
Linear address to convert.
Limit
Zero-based segment limit (0 specifies a one-byte segment, 1 is a two-byte segment, and so on). This parameter is used only if the service creates an LDT selector.

If the virtual machine is running in V86 mode, the LineAddr parameter must specify a linear address that is within the 1 megabyte V86 address space of the current virtual machine. The service returns a segment:offset pair.

If the virtual machine is running a protected-mode application, the service returns a selector:offset pair. This service creates a new selector in the current virtual machine's LDT if the specified base and limit values do not match a selector the service previously allocated. The service returns an error if no LDT is available.

A virtual device must never free a selector that is returned by this service. For this reason, this service should be used sparingly.

See Also

Map_Flat


MMGR_SetNULPageAddr

include vmm.inc

mov     eax, PhysAddr       ; physical address for system nul page
VMMCall MMGR_SetNULPageAddr

Sets the physical address of the system nul page. Uses Flags.

This service is for the exclusive use of the virtual V86MMGR device. The virtual device calls this service, while processing the Init_Complete message, to set the address of a known nonexistent page in the system.

  • No return value.
PhysAddr
Physical address of the system nul page. This parameter is the page number for the nul page shifted left by 12 bits.

See Also

_GetNulPageHandle


Open_Boot_Log

include vmm.inc

VMMCall Open_Boot_Log
xor     eax, eax
jnz     log_not_enabled

Opens the system boot log. Any data written to the system boot log after calling this service is appended to the end of the log. Uses EAX and Flags.

  • Returns zero in EAX if boot logging is enabled, or non-zero otherwise.

See Also

Close_Boot_Log, EnableDisable_Boot_Log


_Register_Win32_Services

include vmm.inc

push    OFFSET32 Service_Table
push    DDB_Offset
VMMCall _Register_Win32_Services

Copies the location of the calling VxD's Win32 service-table in the DDB (Device Description Block). Uses ESP, flags.

  • No return value.
DDB_Offset
Specifies the offset to the DDB.
Service_Table
The calling VxD's Win32 service table.

If the VxD ID is below the CDEVIDSYS value, it is recorded in the apWin32SvcTbl table in order to allow fast dispatching.

A bit in the DDB_Flags member is set to indicate that this service has been called.


Remove_Exception_Handler

include vmm.inc

mov     esi, Exception          ; points to an Exception_Handler_Struc
VMMCall Remove_Exception_Handler

jc      not_removed             ; carry flag set if error

Removes the specified exception handler. Uses Flags.

  • Returns with the carry flag clear if successful, set otherwise.
Exception
Address of an exception handler structure containing information about the exception handler to remove. This exception handler must have been previously installed using the Install_Exception_Handler service.

See Also

Install_Exception_Handler


Set_Boot_Flags

include vmm.inc

mov eax, BootFlags
VMMCall Set_Boot_Flags

Sets the boot-time flags. Virtual devices should have no need to call this service. Uses Flags.

  • No return value
BootFlags
Boot time flags. Can be one of the following:
BOOT_CLEAN | (00000001H)
BOOT_DOSCLEAN | (00000002H)
BOOT_NETCLEAN | (00000004H)
BOOT_INTERACTIVE | (00000008H)


_SetReclaimableItem

#include vmm.h

DWORD _SetReclaimableItem(DWORD enumKey, ReclaimStruc *pReclaim,
    DWORD Flags);

Marks as fully reclaimable or restorable, the regions of reclaimable VM memory declared by a previous call to the _AddReclaimableItem service. Uses C calling convention and the EAX, ECX, EDX, and Flags registers.

  • Returns non-zero in the EAX register if successful; otherwise returns zero in EAX.
enumKey
Enumeration key. Set this parameter to zero to begin enumeration. Subsequent calls to this service specify enumeration keys returned by previous calls.
pReclaim
Address of ReclaimStruc structure to copy. The callback in the RS_CallBack member of the ReclaimStruc structure is called using the CDECL calling and register conventions, and has no defined return value. The reference data for the callback, if any, is not passed separately, since it is already available in the ReclaimStruc.
Flags
Reserved; must be 0.

If the block's contents must be restored prior to System_Exit, RS_RESTORE must also be specified in the RS_Flags member. If the RS_Callback member specifies the address of an optional callback function, the function is called immediately after the contents have been restored, prior to System_Exit.

If the system does not use a fully-reclaimable block (for example, if the block's alignment or size makes it unsuitable), it still calls the caller's callback address, if any, so that any external references to the block can still be restored.

If a block marked reclaimable cannot later be reclaimed, call SetReclaimableItem with the RS_RECLAIM flag clear.

See Also

_AddReclaimableItem, _EnumReclaimableItem, ReclaimStruc


Set_Delete_On_Exit_File

include vmm.inc

mov     esi, Filename       ; points to filename to add
VMMCall Set_Delete_On_Exit_File

jc      not_added           ; carry flag set on error

Adds the specified filename to the list of files to delete when Windows terminates. Uses All registers except EBX, EBP, and the segment registers.

This service is for the exclusive use of the virtual swap file device; other virtual devices must not use this service.

  • Returns with the carry flag clear if the service adds a file to the list, set otherwise.
Filename
Address of a null-terminated string identifying the file to delete. The string must specify a drive letter and full path.


Set_System_Exit_Code

include vmm.inc

mov     al, ExitCode        ; exit code to set
VMMCall Set_System_Exit_Code

Sets the exit code value that Windows returns to MS-DOS when Windows terminates. The system copies this value to the AL register when it executes the MS-DOS End Program function (Interrupt 21h Function 4Ch). Uses EDX, Flags.

This service is intended for the exclusive use of the virtual shell device.

  • No return value.
ExitCode
Exit code value.

This exit code is associated only with the exit of the system not the system virtual machine.

In the case of an abnormal termination, the system may set its own exit code value and ignore the value set by this service.


System_Control

include vmm.inc

mov     eax, Message    ; system control message
mov     ebx, VM         ; VM handle (if needed by message)
mov     esi, Param1     ; message-specific parameter
mov     edi, Param2     ; message-specific parameter
mov     edx, Param3     ; message-specific parameter
VMMCall System_Control

jc      error           ; carry flag set if error

Sends system control messages to all the virtual devices and, depending on the message, to the VMM. Uses Flags, and possibly other registers depending on the service.

  • Returns with the carry flag clear if successful, set otherwise.

    If the Create_VM message is specified and the service is successful, the EBX register contains the new virtual machine handle.

    If the Create_Thread message is specified and the service is successful, the EDI register contains the new thread handle.

Message
System control message to send. Can be one of the values listed in VMM Messages, or a private message in the reserved private system control range described above.
VM
Handle of a virtual machine. This parameter is not required by every system control message.
Param1
Message-specific parameter.
Param2
Message-specific parameter.
Param3
Message-specific parameter.

Although virtual devices may receive many of the system control messages, they may send only the following messages:

Message | Description
Create_VM | May only be sent by the virtual shell device.
Destroy_VM | May only be sent by the virtual shell device.
Set_Device_Focus | May be sent by any virtual device. If the device ID is zero, all devices with a focus that can be set, must set their focus to the specified virtual machine.
End_PM_App | May only be sent by the virtual MS-DOS manager.

The system never uses message numbers in the range BEGIN_RESERVED_PRIVATE_SYSTEM_CONTROL through END_RESERVED_PRIVATE_SYSTEM_CONTROL, which remain free for use by virtual devices. Microsoft has not defined a protocol for virtual devices to reserve regions of the private system control message space and thus avoid accidentally colliding.

Virtual devices must send and reply to messages correctly to prevent erratic system behavior.

This service uses the ECX register, therefore the register cannot be used to pass data through to the virtual device receiving the control message.


Unhook_Device_Service

Previous Next

Unhook_Device_Servicef

include vmm.inc

GetVxDServiceOrdinal eax, Servicemov esi, HookProc
VMMCall Unhook_Device_Service

Unhooks a device service that was previously hooked with the Hook_Device_Service service. Uses Flags.

  • Clears the carry flag if successful; otherwise sets the carry flag because of one of the following errors:

    The service number is invalid.

    The hook procedure could not be found in the chain.

    A non-HookProc hook existed in the chain.

ServiceOrdinal
The high word is the VxD ID and the low word is the service number. If the VxD ID is UNDEFINED_DEVICE_ID, then the EDI register should contain the address of the eight character space-padded VxDName.
Service
Name of the service being unhooked.
HookProc
Hook procedure to remove from the list.

In order for Hook_Device_Service to succeed, the hook to be unhooked and all hooks that were made after the specified hook must have been declared as Hook_Proc's using the BeginProc macro. This macro is provided to correctly generate the procedure header necessary for creating a hook chain that can be processed quickly and still allows hooks to be removed from the chain.

See Also

BeginProc, Hook_Device_Service


VMM_Add_DDB

include vmm.inc

mov     edi, OFFSET32 ddb
VMMCall VMM_Add_DDB
jc      DDB_Already_Exists;

Adds a Vxd_Desc_Block structure (DDB or Device Description Block) to the appropriate location in the device list (the locations are based on the initialization order).

  • Clears the carry flag if the DDB was added to the internal list; the carry flag is set if a duplicate entry already exists.
ddb
A Vxd_Desc_Block structure that contains the driver version numbers, the addresses of various required procedures, and so on.

Virtual devices should call this service with extreme caution. DDBs added in this manner are treated by the virtual machine manager as full-fledged VxDs. If you want to load a VxD, you would be much better off using the VxD loader services than trying to manipulate the DDB list directly.


VMM_GetDDBList

include vmm.inc

VMMCall VMM_GetDDBList
mov     [DDBList], eax

Retrieves the address of the DDB (Device Description Block) list. Uses EAX.

  • Returns the DDB list address in EAX.

Virtual devices can walk the list of DDBs by following the DDB_Next field in the DDB. The end of the list is marked with a DDB_Next field equal to zero. Note that the DDB list can change as a result of dynamically-loaded VxDs, so virtual devices should not attempt to retain the value returned by this service for an extended period of time.


VMM_GetVxDLocationList

include vmm.inc

VMMCall VMM_GetVxDLocationList
jz      ErrorHandler
mov     [TableAddress], eax
mov     [VxDCount], edx
mov     [TableSize], ecx

Returns the address of the VxD location list in EAX, returns the count of VxDs in EDX, and returns the list size (in bytes) in ECX. Uses EAX, ECX, and EDX.

  • Returns the address of the VxD if the function succeeds; otherwise, sets the zero flag.

The VxD location list is a packed array of variable-length Device_Location_List structures.


VMM_Remove_DDB

include vmm.inc

mov     edi, OFFSET32 ddb
VMMCall VMM_Remove_DDB
jc      DDB_Not_Found

Removes a Vxd_Desc_Block structure (DDB or Device Description Block) from the device list.

  • Clears the carry flag if the DDB was removed; the carry flag is set if the DDB was not found.
ddb
A Vxd_Desc_Block structure that contains the driver version numbers, the addresses of required procedures, and so on.

Virtual devices should call this service with extreme caution. DDBs removed in this manner are removed from the system without being given any opportunity to clean up. If you want to unload a VxD, you would be much better off using the VxD loader services than trying to manipulate the DDB list directly. Removing a DDB at a bad time destabilizes the system.


VMMAddImportModuleName

include vmm.inc

mov     esi, OFFSET32 Mod_Lngth_And_Name
VMMCall VMMAddImportModuleName
mov     [Internal_Index], eax;
jc      Name_Already_Present

Adds the specified import-module name to an internal table.

  • Returns the internal index for the module name in EAX. Sets the carry flag if the module name is already present; otherwise, clears the carry flag.
Mod_Lngth_And_Name
The module-name string. The first byte of this string specifies the number of characters in the string; the remaining bytes contain the actual characters.

The first byte of the module-name string must specify the length of the string in bytes. The remaining bytes contain the ASCII characters that compose the string.

This service is reserved for the VxDLDR device. Other virtual devices should not use this service.


Sprintf

include vmm.inc

VMMCall _Sprintf, <pOutBuf, pFormat, Param1, Param2, ...>

Formats a string in a manner analogous to the C procedure. This service uses the C calling convention. Uses EAX, ECX, EDX and Flags.

  • Returns the number of bytes written to the output buffer, not including the terminating null.
pOutBuf
Address of a buffer that receives the formatted string. There is no limit checking performed on the buffer; it must be large enough to handle the formatted output.
pFormat
Address of an ASCIIZ format string.
Param1, Param2, ...
Optional parameters. It is an error to pass too few parameters to satisfy the format string. String insertions may not exceed 255 bytes in length.


ReclaimStruc

ReclaimStruc     STRUC
    RS_Linear    DD ?
    RS_Bytes     DD ?
    RS_CallBack  DD ?
    RS_RefData   DD ?
    RS_HookTable DD ?
    RS_Flags     DD ?
ReclaimStruc   ENDS

Contains information about a region of VM memory.

RS_Linear
Low (i.e., less than 1meg+64K) address of region.
RS_Bytes
Size of region in bytes.
RS_CallBack
Function to call prior to System_Exit, NULL if none.
RS_RefData
Reference data passed to callback, if any.
RS_HookTable
Address of Reclaim_Hook_Table as defined in int2fapi.h, NULL if none.
RS_Flags
May be any combination of the following:
RS_RECLAIM | (00000001H)
RS_RESTORE | (00000002H)
RS_DOSARENA | (00000004H)


String Management

There are the following string management services:

Service | Description
_lmemcpy | Performs a forward memory move.
_lstrcmpi | Compares two strings.
_lstrcpyn | Copies a string into a buffer.
_lstrlen | Determines the length of a string.
_lstrupr | Converts lowercase characters in a string to uppercase.


_lmemcpy

include vmm.inc

cld
VMMCall _lmemcpy, <OFFSET32 pvDst, OFFSET32 pvSrc, dwNumBytes>
mov     OFFSET32 pBuf, eax
mov     OFFSET32 pEndBuf, edx

Performs a forward memory move. Unlike the KERNEL function of a similar name, this service does not support backward memory moves. If the source and destination buffers overlap, the results of this service are undefined. Uses the C calling convention. Uses EAX, ECX, EDX, and Flags. The direction flag must be clear.

  • Returns the address of the beginning of the destination buffer in EAX, and the address of the end of the buffer in EDX.
pvDst
Address of the destination buffer.
pvSrc
Address of the source buffer.
dwNumBytes
Number of bytes to move to the destination buffer.

Note The VxD that calls this service is responsible for enabling or disabling interrupts as appropriate. Interrupts must be disabled if atomicity is desired, enabled if pageable data is involved.

No validation is done on any of the parameters of this service.

This is an asynchronous service.


_lstrcmpi

include vmm.inc

VMMCall _lstrcmpi, <OFFSET32 pString1, OFFSET32 pString2>
cmp     eax, 0
je      strings_equal
jg      string1_greater
jl      string2_greater

Compares two strings by checking the first characters against each other, the second characters against each other, and so on, until it finds an inequality or reaches the ends of the strings. The service returns a value based on the result of the last comparison. For example, _lstrcmpi determines that "abcz" is greater than "abcdefg" and returns a positive number. Uses the C calling convention. Uses EAX, ECX, EDX, and Flags.

  • Returns zero in EAX if the two strings are equal, a positive value if pString1 is greater that pString2, and a negative value if pString1 is less than pString2.
pString1, pString2
Addresses of the strings to compare.

With a double-byte character set (DBCS) version of Windows, this service can compare two DBCS strings.

Unlike some other string functions, this service resides in pageable memory. It must only be called when pageable code can be executed.

Until the INIT_COMPLETE phase of VxD initialization, this service will not correctly convert case for non-US English languages. A VxD should delay all calls to this function until the INIT_COMPLETE phase of VxD initialization.


_lstrcpyn

include vmm.inc

cld
VMMCall _lstrcpyn, <OFFSET32 pszDst, OFFSET32 pszSrc, dwBufSize>
mov     pszDst, eax
mov     cbUnused, ecx
mov     pszNull, edx

Copies a zero-terminated ASCII string to a sized buffer. Uses the C calling convention. Uses EAX, ECX, EDX, and Flags. The direction flag must be clear.

  • Returns the following information:
EAX | Address of the destination buffer.
ECX | Number of unused bytes in the buffer, not including the terminating null character.
EDX | Address of the terminating null byte in the destination buffer.

pszDst
Address of destination buffer.
pszSrc
Address of source buffer.
dwBufSize
Size, in bytes, of the destination buffer. Set this parameter to – 1 if the size is unlimited.

If the destination buffer is larger than the source string, the unused portion of the buffer is not padded with null characters. If the destination buffer is smaller than the source string (dwBufSize - 1), characters from the source string are copied, followed by a (premature) terminating null character. If dwBufSize is set to zero, no bytes are copied to the destination buffer.

Setting pszSrc to zero is equivalent to specifying a null source string. This service accesses only bytes from pszSrc that are copied. If the destination buffer fills before the end of the source buffer is reached, the remaining bytes of the source buffer are not accessed.

The source and destination buffers must not overlap. This is an asynchronous service.


_lstrlen

include vmm.inc

VMMCall _lstrlen, <OFFSET32 psz>

Determines the length of a null-terminated ASCII string. The length does not include the terminating null character. Uses the C calling convention. Uses EAX, ECX, EDX, and Flags. The direction flag must be clear.

  • Returns the following information:
EAX | Length, in bytes, of the string.
EDX | Address of the terminating null character, or undefined if psz is NULL.

psz
Address of the string.

Setting pszSrc to zero is equivalent to specifying a null source string. This service will crash if pszSrc is set to anything other than the address of a null-terminated ASCII string

This is an asynchronous service.


_strupr

include vmm.inc

VMMCall _strupr, <OFFSET32 psz>

Converts any lowercase characters in the specified string to uppercase. Uses the C calling convention. Uses EAX, ECX, EDX, and Flags.

  • Returns, in EAX, the address of the converted string.
psz
Address of string to convert.

Unlike some other string functions, this service resides in pageable memory. It must only be called when pageable code can be executed.

Until the INIT_COMPLETE phase of VxD initialization, this service will not correctly convert case for non-US English languages. A VxD should delay all calls to this function until the INIT_COMPLETE phase of VxD initialization.


Timing Services

The following topics describe the timing services.


Timing Query Services

Time query services allow a virtual device to obtain information about how long the system, a virtual machine, or a thread has been executing, in milliseconds.

When the system creates a thread or virtual machine, it sets the execution time for the thread or virtual machine to zero. The system increases the execution time only when the thread or virtual machine actually runs. Therefore the execution does not reflect the length of time the thread or virtual machine has existed, but indicates the amount of time the thread or virtual machine has run. Note however that any code executed in the indicated thread or virtual machine contributes to the tally; it is not the case that one second of thread execution time or virtual machine execution time translates into one second of actual CPU time given to the application.

For each query service there are two variants, the standard form and the last updated form (for example, _GetThreadExecTime and _GetLastUpdatedThreadExecTime). The standard form returns the time to millisecond accuracy, whereas the last updated form returns the time only to an accuracy of approximately 50 milliseconds. The difference is that the standard form will ask the timer device to give the time to millisecond accuracy, and use the result to compute the value to return, whereas the last updated form returns the value most recently obtained by a standard form call, or by the timer device explicitly updating the system clock (which happens on every timer tick).

If the interval being measured is on the order of seconds or minutes, the last updated form is sufficient because a 50 milliseconds variation will not make a noticeable difference. If the interval being measured is less than one half second, you may be better off with the standard form.

Note also that all of the query services return 32-bit unsigned values. This value overflows every 49 1/2 days. If a virtual device is sensitive to rollover, it should schedule a time-out every 30 days.

Make certain to handle the boundary cases correctly. For example, the following code is incorrect when the system time is close to rollover.

VMMCall Get_System_Time
add    eax, 60000      ; Do it for one minute
mov    StopTime, eax
...
VMMCall Get_System_Time
cmp     eax, StopTime  ; Q: Time to stop?
jae     StopMe         ; Y: Stop doing it

If the operation starts less than one minute before a timer rollover, the operation will halt prematurely, because StopTime will contain a very small number due to addition overflow. Conversely, if the operation starts slightly earlier than one minute before timer rollover, it may never stop because StopTime will be extremely close to 0xFFFFFFFF. The correct way to handle the boundary cases is as follows:

VMMCall Get_System_Time
mov    StartTime, eax
...
VMMCall Get_System_Time
sub    eax, StartTime
cmp    eax, 60000      ; Q: Time to stop?
jae    StopMe          ; Y: Stop doing it


Time-Out Callback Procedures

When the specified amount of time has elapsed for a time-out, the callback procedure is called. For asynchronous time-outs, the callback procedure is called at hardware interrupt time; for other time-outs, the callback procedure is called at unrestricted event time. At hardware interrupt time, only asynchronous services may be called. See Events for restrictions on what can and cannot be done at event time.

All time-out callback procedures receive a tardiness value in the ECX register. This value is the number of milliseconds by which the time-out is late. For example, if you scheduled a time-out for 100 milliseconds, but it does not get dispatched until 115 milliseconds have elapsed, the ECX register will contain the value 15. Time-outs are often delayed by 10 milliseconds or more, because the normal system timer runs at 20 milliseconds or slower. If a virtual device needs more accurate time-outs, it must increase the timer interrupt frequency using virtual timer device (VTD) services.

Note that the value in ECX is accurate only to the last updated resolution. If you need the tardiness to millisecond resolution, you must first ensure that the virtual machine manager originally scheduled the time-out to millisecond resolution (see Timing Query Services), then use the following algorithm to convert the last-updated resolution to system-time resolution:

; On entry, ECX = tardiness in milliseconds relative to
; Last_Updated_System_Time
VMMCall  Get_Last_Updated_System_Time
sub    ecx, eax      ;ECX = Remove Last_Updated_System_Time bias
VMMCall  Get_System_Time
add    ecx, eax      ; ECX = Apply System_Time bias
                     ; ECX = true tardiness to millisecond resolution

Alternatively, you could record the system time when the time-out was scheduled, and subtract it from the current system time at the time the callback is made, rather than doing the above.

If you need to convert the tardiness of a thread time-out or virtual machine time-out, you should use _GetLastUpdatedThreadExecTime and _GetThreadExecTime, or Get_Last_Updated_VM_Exec_Time and Get_VM_Exec_Time, respectively. Note that, since _GetLastUpdatedThreadExecTime and _GetThreadExecTime use the C calling convention, you need to preserve the EDX and ECX registers around the calls.


Cancel_Time_Out

include vmm.inc

mov     esi, TimeOut     ; time-out handle
VMMCall Cancel_Time_Out

Cancels a time-out that was scheduled using the Set_Async_Time_Out, Set_Thread_Time_Out, Set_VM_Time_Out or Set_Global_Time_Out service. Uses Flags. This is an asynchronous service.

  • No return value.
TimeOut
Handle of the time-out to cancel. If this parameter is zero, the service returns immediately (does nothing). If this parameter is non zero, it must be the handle of a time-out which has not yet been processed or canceled.

This service makes the time-out handle invalid; the virtual device must not attempt to use the handle in subsequent calls to services.

See Also

Set_Global_Time_Out, Set_VM_Time_Out


Get_Last_Updated_System_Time

include vmm.inc

VMMCall Get_Last_Updated_System_Time

mov     [SysTime], eax          ; system time in milliseconds

The Get_Last_Updated_System_Time service returns the time in milliseconds since Windows was started. This service is accurate to approximately 50 milliseconds. This is an asynchronous service. Uses EAX, Flags.

  • Returns in the EAX register, the elapsed time, in milliseconds, since Windows was started.

See Timing Query Services for a discussion of timer rollover and a comparison of Get_System_Time with Get_Last_Updated_System_Time.

See Also

Get_System_Time


_GetLastUpdatedThreadExecTime

include vmm.inc

VMMCall _GetLastUpdatedThreadExecTime, <ThreadHandle>
mov     [ThreadExecTime], eax;

Retrieves the amount of time in milliseconds that the specified thread has run. This service is accurate to approximately 50 milliseconds. This is an asynchronous service. This service uses the C calling convention. Uses EAX, ECX, EDX, and Flags.

  • Returns in the EAX register, the amount of time, in milliseconds, that the thread has executed.
ThreadHandle
Handle of the thread to obtain execution time information for.

See Timing Query Services for a definition of thread execution time, a discussion of timer rollover, and a comparison of _GetThreadExecTime with _GetLastUpdatedThreadExecTime.


Get_Last_Updated_VM_Exec_Time

include vmm.inc

mov    ebx, [VMHandle]
VMMCall Get_Last_Updated_VM_Exec_Time

mov     [ExecTime], eax     ; time in milliseconds that VM has run

Returns the amount of time that the specified virtual machine has run. This service is accurate to approximately 50 milliseconds. This is an asynchronous service. Uses EAX, Flags.

  • Returns in the EAX register the execution time, in milliseconds, for the specified virtual machine.
VMHandle
Handle of the virtual machine to obtain execution time information for.

When the system creates a virtual machine, it sets the execution time for the virtual machine to zero. The system increases the execution time only when the virtual machine actually runs. Therefore the execution does not reflect the length of time the virtual machine has existed, but indicates the amount of time the current virtual machine has run. Note however that any code executed in the indicated virtual machine contributes to the tally; it is not the case that one second of virtual machine execution time translates into one second of actual CPU time given to the application.

See Timing Query Services for a definition of virtual machine execution time, a discussion of timer rollover, and a comparison of Get_VM_Exec_Time with Get_Last_Updated_VM_Exec_Time.

See Also

Get_VM_Exec_Time


Get_System_Time

include vmm.inc

VMMCall Get_System_Time

mov     [SysTime], eax          ; system time in milliseconds

Returns the time in milliseconds since Windows started. This service is accurate to 1 millisecond. This is an asynchronous service. Uses EAX, Flags.

  • Returns in the EAX register the elapsed time, in milliseconds, since Windows was started.

See Timing Query Services for a discussion of timer rollover and a comparison of Get_System_Time with Get_Last_Updated_System_Time.

See Also

Get_Last_Updated_System_Time


Get_System_Time_Address

include vmm.inc

VMMCall Get_System_Time_Address
mov     [System_Time_Addr], eax

Retrieves the address of the system-time variable.

  • Returns in the EAX register the address of the system time variable.

The system time variable is the 32-bit value returned by the Get_Last_Updated_System_Time service. This service is provided as a convenience (primarily to C-language callers), so that the return value can be stored into a pointer variable and accessed directly, thus avoiding the overhead of a C wrapper and dynalink call.


_GetThreadExecTime

include vmm.inc

VMMCall _GetThreadExecTime, <hThread>
mov     [ExecTime], eax

Retrieves the amount of time that a particular thread has executed. The value returned indicates the amount of time the specified task has been the currently running thread. Uses EAX, Flags.

  • Returns in EAX the amount of time in milliseconds that thread has executed.
hThread
Handle of the thread to get the execution time for.

This service can be called at interrupt time.

See Timing Query Services for a definition of thread execution time, a discussion of timer rollover, and a comparison of _GetThreadExecTime with _GetLastUpdatedThreadExecTime.


Get_VM_Exec_Time

include vmm.inc

mov  ebx, [VMHandle]
VMMCall Get_VM_Exec_Time

mov     [ExecTime], eax     ; time in milliseconds that VM has run

Returns the amount of time that the specified virtual machine has run. This service is accurate to 1 millisecond. This is an asynchronous service. Uses EAX, Flags.

  • Returns in the EAX register the execution time for the specified virtual machine.
VMHandle
Handle of the virtual machine to obtain the execution time information for.

See Timing Query Services for a definition of virtual machine execution time, a discussion of timer rollover, and a comparison of Get_VM_Exec_Time with Get_Last_Updated_VM_Exec_Time.

See Also

Get_Last_Updated_VM_Exec_Time


Async_Time_Out_Proc

include vmm.inc

mov  ecx, Tardiness
mov  edx, Reference_Data

call [Async_Time_Out_Proc]

Callback procedure installed by Set_Async_Time_Out.

  • No return value.
Tardiness
Number of extra milliseconds that have elapsed.
Reference_Data
Data that is returned by the callback procedure to the calling procedure.

Note Asynchronous time-outs do not receive a pointer to the client registers in the EBP register.

Asynchronous time-outs differ from other time-outs in that they are called at hardware interrupt time. Thus, stricter rules are in force during the time-out callback. The time-out callback procedure may only call asynchronous services, must reside in locked code, and must restrict itself to locked code and data.


Set_Async_Time_Out

include vmm.inc

mov     eax, TimeOut_Delay
mov     edx, Reference_Data
mov     esi, Async_Time_Out_Proc
VMMCall Set_Async_Time_Out
mov     [TimeOut_Handle], esi

Schedules a time-out callback procedure that will be called after the specified length of time. Uses ESI, flags. This is an asynchronous service.

  • If the time-out was scheduled, returns in ESI a handle that identifies it; otherwise, ESI is zero.
TimeOut_Delay
The specified number of milliseconds that must transpire before the time-out occurs.
Reference_Data
Data that's returned to the procedure.
Async_Time_Out_Proc
A callback procedure that is called when the time-out occurs.


Set_Global_Time_Out

include vmm.inc

mov     eax, Time                       ; number of milliseconds
mov     edx, RefData                    ; reference data
mov     esi, OFFSET32 TimeOutCallback   ; callback procedure
VMMCall Set_Global_Time_Out

mov     [TimeOut], esi                  ; time-out handle

Schedules a time-out to occur after the specified number of milliseconds has elapsed. Uses ESI, Flags. This is an asynchronous service.

  • Returns the handle of the time-out in the ESI register if successful, zero if the time-out could not be scheduled.
Time
Number of milliseconds to wait before calling the time-out callback procedure. This is a signed DWORD. The maximum value is 0x7FFFFFFF.
RefData
Reference data to be passed to the callback procedure.
TimeOutCallback
Address of the callback procedure. For more information about the callback procedure, see below.

The system calls the time-out callback procedure when the specified number of milliseconds elapse. The system calls the procedure as follows:

mov     ebx, VMHandle      ; current VM handle
mov     ecx, Tardiness     ; number of milliseconds since time-out
mov     edx, RefData       ; reference data
mov     ebp, OFFSET32 crs  ; points to Client_Reg_Struc
call    [TimeOutCallback]

The VMHandle parameter is a handle specifying the current virtual machine. The RefData parameter specifies the reference data for the callback procedure, and the crs parameter points to a Client_Reg_Struc structure that contains the register values for the current virtual machine.

The Tardiness parameter specifies the number of milliseconds that have elapsed since the actual time-out occurred. See Time-Out Callback Procedures for a description of this value.

See Also

Set_VM_Time_Out


Thread_Time_Out_Proc

include vmm.inc

mov  ebx, VMHandle
mov  ecx, Tardiness
mov  edx, Reference_Data
mov  edi, ThreadHandle
mov  ebp, OFFSET32 Client_Reg_Struc
call [Thread_Time_Out_Proc]

The thread time-out callback procedure is called when the corresponding thread has executed for the amount of time specified when the time-out was set.

VMHandle
Handle of current virtual machine.
Tardiness
Number of extra milliseconds that have elapsed. See Time-Out Callback Procedures for a description of this value.
Reference_Data
Reference data originally provided when the time-out was scheduled.
ThreadHandle
Handle of current thread.
Client_Reg_Struc
Address of Client_Reg_Struc structure containing the contents of the virtual machine's registers.

The time-out will occur after the thread has run for the specified number of milliseconds. If there is more than one thread executing, it may take more than the specified time to occur. See Time-Out Callback Procedures for more information about time-out callbacks.


Set_Thread_Time_Out

include vmm.inc

mov     eax, TimeOut_Delay
mov     edx, Reference_Data
mov     esi, OFFSET32 Thread_Time_Out_Proc
mov     edi, ThreadHandle
VMMCall Set_Thread_Time_Out
mov     [TimeOut_Handle], esi

Schedules a time-out that will occur after the specified thread has executed for the specified length of time. Uses ESI, flags. This is an asynchronous service.

  • If the time-out was scheduled, ESI contains a handle that identifies it; otherwise, ESI is zero.
TimeOut_Delay
The specified number of milliseconds that must transpire in the thread before the time-out occurs.
Reference_Data
Data that is provided to the callback procedure.
Thread_Time_Out_Proc
A callback procedure that is called when the time-out occurs.

The time-out will occur after the thread has run for the specified number of milliseconds. If there is more than one thread executing, it may take more than the specified time to occur. See Timing Query Services for more information about time-outs.


Set_VM_Time_Out

include vmm.inc

mov     eax, Time                       ; number of milliseconds
mov     ebx, VMHandle                   ; VM handle
mov     edx, RefData                    ; reference data
mov     esi, OFFSET32 TimeOutCallback   ; callback procedure
VMMCall Set_VM_Time_Out

mov     [TimeOut], esi                  ; time-out handle

Schedules a time-out that occurs after the specified virtual machine has run for the specified length of time. The system calls the time-out callback procedure only after the virtual machine has run for Time milliseconds. Time that elapses while other virtual machines run is not counted. Uses ESI, Flags. This is an asynchronous service.

  • Returns the handle of the time-out in the ESI register if successful, zero if the time-out could not be scheduled.
Time
Number of milliseconds to wait before calling the time-out callback procedure.
VMHandle
Handle of the virtual machine.
RefData
Reference data to be passed to the callback procedure.
TimeOutCallback
Address of the callback procedure. For more information about the callback procedure, see below.

The system calls the time-out callback procedure after the virtual machine has run for the specified number of milliseconds. The system calls the procedure as follows:

mov     ebx, VMHandle       ; current VM handle
mov     ecx, Tardiness      ; number of milliseconds since time-out
mov     edx, RefData        ; reference data
mov     ebp, OFFSET32 crs   ; points to Client_Reg_Struc
call    [TimeOutCallback]

The VMHandle parameter is a handle specifying the virtual machine for which the time-out was scheduled. The RefData parameter specifies the reference data for the callback procedure, and the crs parameter points to a Client_Reg_Struc structure that contains the register values for the virtual machine.

The Tardiness parameter specifies the number of milliseconds that have elapsed since the actual time-out occurred. See Timing Query Services for more information about time-outs.

See Also

Set_Global_Time_Out


Update_System_Clock

include vmm.inc

mov     ecx, Time           ; elapsed time in milliseconds
VMMCall Update_System_Clock

Updates the current system time, and the current virtual machine's execution time. Uses Flags.

This service is reserved for exclusive use by the virtual timer device. If other virtual devices call this service, the VMM timing services will behave incorrectly.

  • No return value.
Time
Number of milliseconds that have elapsed since the last call to this service. The service adds this amount to the system time maintained by the VMM.

The virtual timer device must disabled interrupts before calling this service.


Nested Execution

The following terms are defined.

client state | The state of the registers in a virtual machine.
nested execution | The execution of code in a virtual machine at the direction of a virtual device.
nested execution block | A block of code in virtual device that is delimited by calls to Begin_Nest_Exec (or Begin_Nest_V86_Exec) and End_Nest_Exec.


Nested Execution

Often, a virtual device (VxD) handles an interrupt or fault by calling code in a virtual machine (VM). The code might be an MS-DOS routine or a BIOS interrupt handler, for example. When the virtual device calls into the virtual machine, it must do so within the context of a nested execution block, which is a block of code delimited by calls to Begin_Nest_Exec (or Begin_Nest_V86_Exec) and End_Nest_Exec.

Begin_Nest_Exec changes the execution mode of the virtual machine to the mode of the application running in the VM. For example, if the virtual machine is running a protected-mode program but happens to be in V86 mode at the moment, Begin_Nest_Exec changes the virtual machine to protected-mode. Begin_Nest_Exec is typically used to call callback procedures registered by an application.

Begin_Nest_V86_Exec is like Begin_Nest_Exec, except that it forces the mode of the virtual machine to V86-mode, even if the program running in the virtual machine is a protected-mode program. Begin_Nest_V86_Exec is typically used to call the BIOS, a TSR, or other V86-mode code.

End_Nest_Exec restores the virtual machine to its original mode, regardless of how nested execution was entered.

The code in the virtual machine can modify the virtual machines registers. It is rarely desirable that changes to the registers resulting from nested execution be propagated back to the virtual machine when nested execution is complete. To be able to restore the state of the virtual machine after the code executes, a virtual device must save the state of the virtual machine's registers before entering a nested execution block. To save the registers, a virtual device can use the Save_Client_State service, which stores the registers in a buffer, or the Push_Client_State macro, which pushes the registers onto the virtual device's stack. After completing the nested execution block, the virtual device can restore the registers by calling the Restore_Client_State service or using the Pop_Client_State macro.

Once inside a nested execution block, a virtual device uses simulation services, followed by the Resume_Exec service to call into a virtual machine. Alternatively, a virtual machine can use the Exec_Int service, which combines the functionality of Simulate_Int and Resume_Exec. Multiple calls to Resume_Exec can occur while inside a single nested execution block; you don't need to exit and re-enter nested execution if you need to simulate multiple operations.

For the curious: So how does your virtual device manage to regain control after a Resume_Exec? When Begin_Nest_Exec or Begin_Nest_V86_Exec is called, the virtual machine manager changes the mode of the virtual machine, then points the client CS:EIP registers at a pre-allocated breakpoint address. When far calls or interrupts are simulated, this breakpoint gets pushed onto the client's stack as the return address. Then when the simulated call or interrupt returns, it returns to this breakpoint address, at which point the virtual machine manager regains control, does some bookkeeping, and returns control to your virtual device. When End_Nest_Exec is called, the mode of the virtual machine is restored, and the original CS:EIP is replaced. This information is provided to aid in understanding nested execution; Microsoft reserves the right to alter the details of the implementation in future versions of Windows, so you shouldn't rely on it.


Examples

Nested execution suffers from being relatively important yet poorly-understood. To help close the gap, various examples illustrating common scenarios are given here. All of the examples assume that EBX contains the handle of the current virtual machine and that EBP contains a pointer to the client registers.

The first example is the prototypical case, where a virtual device wishes to obtain information from MS-DOS. Note that in general, this is a dangerous thing to do without first ensuring that the call will not result in MS-DOS being re-entered.

Push_Client_State               ; Save all registers
VMMCall Begin_Nest_V86_Exec     ; Enter nested execution in V86-mode
mov     [ebp.Client_AH], 30h    ; 30h = get MS-DOS version #
mov     eax, 21h                ; Execute an Int 21h in the
VMMCall Exec_Int                ; current VM to call MS-DOS
mov     ax, [ebp.Client_AX]     ; Load MS-DOS version into AX register
VMMCall End_Nest_Exec           ; end of nested exec calls
Pop_Client_State                ; Restore all registers when done
                                ; At this point, AX = MS-DOS version

Notice that the Exec_Int service was used here to simulate and execute the interrupt. It is equivalent to calling Simulate_Int followed by Resume_Exec.

For software interrupts, an alternative method is to execute the interrupt "directly" from ring zero:

mov  ah, 30h         ; 30h = get MS-DOS version #
push dword ptr 21h
VMMCall Exec_VxD_Int ; Execute the Int 21h directly
                     ; At this point, AX = MS-DOS version

This mechanism's main benefit is convenience. The drawback is that all changes to registers (other than segment registers) made by the software interrupt are propagated back into ring 0. This is dangerous because the software interrupt might modify a register you expected to be preserved. This is particularly true of software interrupts 21h and 13h, which are often hooked by TSRs or device drivers which do not preserve all the registers properly. Specifically, we've found TSRs and even BIOSes which destroy the high words of extended registers across these calls.

Furthermore, the Exec_VxD_Int method cannot be used to call services which return information in segment registers, because the ring zero segment registers SS, DS and ES must always remain equal to flat selector.

Another drawback to the Exec_VxD_Int method is that it is not always available. For example, translation services for Int 21h calls is not ready until DOSMGR and IFSMGR complete their initialization; similar remarks apply to Int 13h calls and provided by BIOSXLAT and INT13. Attempting to Exec_VxD_Int an MS-DOS call before the translation services are ready will result in very random behavior. Other services might not even be translated at all. (For example, you cannot use Exec_VxD_Int to call Int 33h because nobody provides translation services for that software interrupt.)

The moral of the story is that you should exercise caution when using Exec_VxD_Int.

Sometimes software interrupts aren't enough. You might find it necessary to call a far procedure in V86-mode, possibly with arguments passed on the stack or in registers. Suppose that you need to call a procedure in V86-mode (for example, a TSR or a device driver) with a word parameter on the stack and with a function code in the DX register. The procedure returns with a 'retf' instruction, relying on the caller to clean the stack on return.

Push_Client_State            ; Save client state on stack
VMMCall Begin_Nest_V86_Exec  ; Prepare to execute V86-mode code
mov     ax, wStackParameter  ; the parameter that goes on the stack
VMMCall Simulate_Push        ; Push it onto the client stack
mov     [ebp].Client_DX, 0   ; Function code in client DX
mov     cx, segV86Proc       ; CX = segment of the V86-mode procedure
movzx   edx, word ptr ofsV86Proc ; EDX = offset of the V86-mode
                                 ;   procedure (hiword must be 0)
VMMCall Simulate_Far_Call    ; Make it look like client did a "call far"
                             ;   instruction
VMMCall Resume_Exec          ; Run the procedure until it returns
VMMCall Simulate_Pop         ; Pop the parameter off the stack
                             ; <<Inspect the return value here>>
VMMCall End_Nest_Exec        ; Finished with nested execution
Pop_Client_State             ; Restore client state from stack

Note There is no equivalent to Exec_VxD_Int for far procedures. You have to use nested execution explicitly.

A final example is a callback procedure registered by an application. Suppose that an application registered an address that it expects to be called back asynchronously based on some condition. You can call the procedure back with the following mechanism, assuming that the procedure uses the Pascal calling convention and takes two arguments:

Push_Client_State         ; Save client state on stack
VMMCall Begin_Nest _Exec  ; Prepare to execute application-mode code
mov     ax, wParam1       ; Pascal calling convention says
VMMCall Simulate_Push     ; you push arguments from left to right
mov     ax, wParam2
VMMCall Simulate_Push
mov     cx, segAppProc    ; CX = segment of the procedure to call
mov     edx, word ptr ofsAppProc  ; EDX = offset of the procedure to
                                  ;   call (hiword must be 0 if V86 or
                                  ;   16-bit PM)
VMMCall Simulate_Far_Call ; Make it look like client did a "call
                          ;   far" instruction
VMMCall Resume_Exec       ; Run the procedure until it returns
VMMCall End_Nest_Exec     ; Finished with nested execution
Pop_Client_State          ; Restore client state from stack

Be aware that this mechanism does not work for Win32 applications. Note also that this callback is made completely asynchronously with respect to the application. At a minimum, you should wait until the client interrupt flag is clear.


Begin_Nest_Exec

include vmm.inc

VMMCall Begin_Nest_Exec

Starts a nested execution block. This service is used in conjunction with the End_Nest_Exec service to create a nested execution block in which a virtual device may call Exec_Int, Resume_Exec, and the various simulation services. Virtual devices use these services to call software in the virtual machine. Uses Client_CS, Client_IP, and Flags.

  • Returns a break point in Client_CS and Client_IP that is used by nested execution services.

While in a nested execution block, a virtual device may call the Exec_Int and Resume_Exec services any number of times.

If one of these calls changes the virtual machine registers, these changes are also made to the client state. Before creating the nested execution block, a virtual device should save the client state by using the Save_Client_State service. After ending the nested execution block, a virtual device should restore the client state by using the Restore_Client_State service.

This service forces the virtual machine into protected-mode execution if there is a protected-mode application running in the current virtual machine. Otherwise, the virtual machine remains in V86 mode. The End_Nest_Exec service restores the virtual machine to its mode prior to the call to Begin_Nest_Exec.

This service automatically switches the virtual machine to the locked protected-mode stack (unless the VM is already using the locked stack) and End_Nest_Exec switches it back. This allows most devices to change execution modes without worrying about demand paging issues.

See Also

Begin_Nest_V86_Exec, End_Nest_Exec, Exec_Int, Restore_Client_State, Resume_Exec, Save_Client_State


Begin_Nest_V86_Exec

include vmm.inc

VMMCall Begin_Nest_V86_Exec

Sets the current virtual machine to V86 mode and prepares the virtual machine for nested execution. This service is used in conjunction with the End_Nest_Exec service to create a nested execution block in which a virtual device may call the Exec_Int, Resume_Exec, and various simulation services. Virtual devices use these services to call software in the virtual machine. Uses Client_CS, Client_IP, and Flags

  • Returns a break point in Client_CS and Client_IP that is used by nested execution services.

When in a nested execution block, a virtual device may call the Exec_Int and Resume_Exec services any number of times.

This service should only be used by virtual devices that convert protected-mode calls into V86 calls. For example, the virtual MS-DOS manager uses this service to map calls to MS-DOS functions (Interrupt 21h) issued by protected-mode programs into calls to MS-DOS functions in V86 mode.

This service should be used by virtual devices that need to be sure that they are calling V86-mode code. A typical usage is translating a protected-mode call into a V86-mode call. After the parameters are translated, Begin_Nest_V86_Exec is used to ensure that the subsequent simulation is into V86-mode.

If the current VM is the System VM, Begin_Nest_V86_Exec will also call VMMCall Begin_V86_Serialization, which uses the V86 mutex to serialize all System VM threads through the System VM's V86 mode of execution.

This service saves the current execution mode of the virtual machine, and End_Nest_Exec restores the mode.

See Also

Begin_Nest_Exec, End_Nest_Exec, Exec_Int, Resume_Exec


Begin_V86_Serialization

include vmm.inc

mov     ecx, flags
VMMCall Begin_V86_Serialization

Serializes access to V86 mode among all threads in the system VM by using a mutex called the "V86 mutex". Because the mutex is taken automatically when Begin_Nest_V86_Exec is called while in the system VM context, a VxD typically does not directly call this service. A VxD might call this service when it needs to perform a nested execution operation into protected mode, and the operation will be reflected into V86 mode at the end of the protected mode chain. Using this service would prevent the VxD's thread from potentially getting blocked at the end of the protected mode chain. Uses Flags.

  • No return value.
flags
Operation flags. Can be a combination of these values:
Block_Svc_Ints | Service events (and simulated interrupts) in the VM if the thread blocks for the critical section.
Block_Svc_If_Ints_Locked | Service events (and simulated interrupts) in the VM if the thread blocks for the critical section and the VMStat_V86IntsLocked flag is set.
Block_Enable_Ints | Service interrupt events in the VM even if the VM does not currently have interrupts enabled (force interrupts to be enabled). This flag is relevant only if either Block_Svc_Ints or Block_Svc_If_Ints_Locked is set.
Block_Thread_Idle | If the thread blocks for the critical section this thread should be considered idle.

There is a hierarchy between the V86 mutex and the critical section mutex. The V86 mutex can be taken in the system VM when the critical section is owned by another VM, but in the system VM the critical section can only be owned if the V86 mutex is already owned. Calling Begin_Critical_Section in a thread in the system VM takes both mutexes.

The critical section mutex serializes access to V86 mode for all VMs. Since the System VM contains one or more threads, the system-VM-specific V86 mutex is used to serialize access to V86 mode at the thread level. Thus, when Begin_Critical_Section is called when in the System VM, both mutexes are used to ensure that the V86 mode is serialized in the System VM both at the thread level and the VM level.

Each call to Begin_V86_Serialization should have a corresponding call to End_V86_Serialization.

See Also

Begin_Critical_Section, Begin_Nest_V86_Exec, End_V86_Serialization


End_Nest_Exec

include vmm.inc

VMMCall End_Nest_Exec

Ends a nested execution block. This service is used in conjunction with the Begin_Nest_Exec or Begin_Nest_V86_Exec service to create a nested execution block in which virtual devices may call the Exec_Int and Resume_Exec services. Uses Client_CS, Client_IP, Flags

  • Returns, in Client_CS and Client_IP, the original values saved when the nested execution block was created.

A virtual device must end all nested execution blocks before returning to the virtual machine manager.

This service restores the execution mode to the mode prior to the start of the nested execution block. It also restores the Client_CS and Client_IP registers, but does not restore any other client registers. A virtual device should save and restore other registers using the Save_Client_State and Restore_Client_State macros.

See Also

Begin_Nest_Exec, Begin_Nest_V86_Exec, Exec_Int, Restore_Client_State, Resume_Exec, Save_Client_State


End_V86_Serialization

include vmm.inc

VMMCall End_V86_Serialization

Decrements the usage count of the V86 mutex. When the count reaches zero, the mutex is no longer owned by the current system VM thread. (For more information, see the description of the Begin_V86_Serialization service.) Uses Flags.

  • No return value.

See Also

Begin_V86_Serialization


Exec_Int

include vmm.inc

mov     eax, Interrupt
VMMCall Exec_Int

Simulates the specified interrupt, and resumes execution of the virtual machine. This service may only be called in a nested execution block created using the Begin_Nest_Exec or Begin_Nest_V86_Exec service. Uses Flags

  • No return value.
Interrupt
Number of the interrupt to simulate.

When in a nested execution block, this service can be called any number of times.

This service is comparable to combining the Simulate_Int and Resume_Exec services.

See Also

Begin_Nest_Exec, Begin_Nest_V86_Exec, Resume_Exec


Exec_VxD_Int

include vmm.inc

push    dword ptr Interrupt
VMMCall Exec_VxD_Int

Executes the specified software interrupt. Virtual devices use this service to call MS-DOS or BIOS functions outside the context of a nested execution block.

  • Returns values in one or more registers, depending on the function of the specified interrupt.
Interrupt
Number of the interrupt to execute.

Before calling this service, a virtual device must set registers to values that are appropriate for the specified software interrupt. This service supports all MS-DOS and BIOS functions that are supported in protected-mode programs.

This service does not change the client registers and flags, so there is no need for the virtual device to save and restore the client register structure. This service also pops the interrupt number from the stack.

Interrupts will only be routed through virtual device interrupt hooks. They will bypass any hook the application has installed in protected mode. This may be a problem, for example, if an application hooks Int 21h to watch file opens and then a VxD uses this service to open a file (the application would not see the file open). DO NOT CHANGE DS or ES before calling this service. You should always use the ring 0 linear address of the data instead of changing the selector value. This may require using the _SelectorMapFlat service to determine the base of a selector.

Do not call services that will change DS or ES.. Mappers should return valid pointers without changing the segment register value, but calls that explicitly change the DS or ES selectors should never be called. For example, if a call returns a pointer in DS:(E)DX then this would be OK to call since the mapper would convert the ponter to use the ring 0 linear address in EDX without modifying DS. However, if a service returns a selector only then you should not use Exec_VxD_Int to call it. This can normally be made to work by using code similar to the following:

Push_Client_State

VMMcall Begin_Nest_(V86_)Exec

. . .

(Fiddle with client registers)

. . .

VMMcall Exec_Int

. . .

(Get segments/selectors)

. . .

VMMcall End_Nest_Exec

Pop_Client_State

Upon exit, all registers and flags modified by interrupt will be changed. The interrupt number on the stack will have been removed. If called within a must complete section and a fatal error occurred while executing the interrupt the carry flag will be set.

In Windows 3.1, if you called Exec_VxD_Int at a time when there was no protected-mode app in the VM and if someone then did a Begin_Nest_Exec (not Begin_Nest_V86_Exec), the system VM would crash. This problem has been corrected in Windows 95.

The following examples calls the MS-DOS function Get Version (Interrupt 21h, Function 30h):

mov     ax, 3000h
push    dword ptr 21h
VMMCall Exec_VxD_Int
mov     [Major], al     ; major MS-DOS version
mov     [Minor], ah     ; minor MS-DOS version


Get_Nest_Exec_Status

include vmm.inc

VMMCall Get_Nest_Exec_Status

Retrieves information about whether the current thread is in nested ring 3 execution. Uses EAX, ECX, EDX, and Flags.

  • Returns with the Z-flag set if the thread is not in nested execution. Otherwise, returns the following:
Register | Meaning
EAX | Original ring 3 EIP
EDX | Original ring 3 CS
ESI | Original ring 3 SS:SP
ECX | Ring 0 stack pointer returned from Resume_Exec or Exec_Int, if ; waiting for completion of ring 3 code.

There should be no need for a virtual device to call this service.


Restore_Client_State

include vmm.inc

mov     esi, Buffer
VMMCall Restore_Client_State

Restores a thread execution state that was saved using the Save_Client_State service. Uses Flags

  • No return value.
Buffer
Address of the buffer containing the client state previously saved using the Save_Client_State service.

This service can have the following side effects:

  • Changes the execution mode if the state being restored is in a different execution mode from the current one.
  • May change the state of the current virtual machine's interrupt flag and cause the system to call event callback procedures that were previously scheduled using the Call_When_VM_Ints_Enabled and Call_Priority_VM_Event services.

This service is typically not called directly; a virtual device typically uses the Pop_Client_State macro which, in turn, calls this service.

See Also

Call_Priority_VM_Event, Save_Client_State


Resume_Exec

include vmm.inc

VMMCall Resume_Exec

Executes the current virtual machine immediately. This service may only be called in a nested execution block created using the Begin_Nest_Exec or Begin_Nest_V86_Exec service. Uses Flags

  • No return value.

This service can be used any number of times in a nested execution block.

This service returns when the virtual machine returns to the same point it was at when Begin_Nest_Exec was called.

See Also

Begin_Nest_Exec, Begin_Nest_V86_Exec


Save_Client_State

include vmm.inc

mov     edi, Buffer
VMMCall Save_Client_State

Copies the contents of the current thread's Client_Reg_Struc structure to the specified buffer. The saved state can later be restored by calling the Restore_Client_State service. Uses Flags.

  • No return value.
Buffer
Address of the buffer to receive the client state. The buffer must have the same size as a Client_Reg_Struc structure.

Virtual devices typically use this service to save client registers prior to creating a nested execution block with the Begin_Nest_Exec or Begin_Nest_V86_Exec service.

Never attempt to restore the client state by directly copying saved register values back to the Client_Reg_Struc structure; this will almost certainly cause the virtual machine manager to crash.

This service is typically not called directly; a virtual device typically uses the Push_Client_State macro which, in turn, calls this service.

See Also

Begin_Nest_Exec, Begin_Nest_V86_Exec, Client_Reg_Struc, Restore_Client_State


Protected-Mode Execution

Term | Definition
locked protected mode stack | After switching a virtual machine to protected mode, a virtual device must lock into physical memory the protected mode stack used by the virtual machine so the stack won't be removed by demand paging.
protected mode application control block | Storage that is allocated when a virtual machine enters protected mode. When a virtual machine switches to protected mode, all virtual machines are notified, and one of the pieces of information included in the notification is a pointer to the protected mode application control block.

There are the following protected-mode execution services:

Allocate_PM_App_CB_Area | Get_Cur_PM_App_CB
Begin_Use_Locked_PM_Stack | Set_PM_Exec_Mode
End_Use_Locked_PM_Stack | Set_V86_Exec_Mode
Exec_PM_Int |


Allocate_PM_App_CB_Area

include vmm.inc

mov     ecx, Size
VMMCall Allocate_PM_App_CB_Area
mov     [acb], eax

Requests that additional space be reserved in the application control block when a virtual machine enters protected mode. This service is only available during initialization. Uses EAX.

  • Returns, in EAX, the offset from the beginning of the application control block to the memory block reserved by the virtual device.
Size
Number of bytes to reserve for the control block.


Begin_Use_Locked_PM_Stack

include vmm.inc

VMMCall Begin_Use_Locked_PM_Stack

Moves the current virtual machine to the protected-mode locked stack. Doing so serves two purposes: It helps ensure that the client stack does not overflow (in case the client was previously on a very small private stack), and it ensures that the memory used by the stack is always available. Uses Flags.

  • Returns the address of the locked stack in Client_SS and Client_SP if the stack was not already locked. Otherwise, these registers remain unchanged.

Before calling this service, the virtual device must ensure that the current virtual machine is running in protected mode. This means the VMStat_PM_Exec value must be specified in the CB_VM_Status field of the control block for the virtual machine.

The Begin_Nest_Exec service automatically switches to the locked stack if the system determines that the virtual machine should be placed into (or be left in) protected-mode execution. Since most virtual devices rely on the Begin_Nest_Exec service to switch stacks, this service is only useful for virtual devices, such as the virtual PIC device, which explicitly change the execution mode of a virtual machine.

A virtual device can call this service any number of times. Only the first call switches stacks; all subsequent calls increment a counter. If a virtual device locks the stack, it must eventually unlock it using the End_Use_Locked_PM_Stack service.

For Windows 95, the size of the protected-mode locked stack is 4K bytes.

See Also

Begin_Nest_Exec, End_Use_Locked_PM_Stack


End_Use_Locked_PM_Stack

include vmm.inc

VMMCall End_Use_Locked_PM_Stack

Unlocks the protected-mode stack. This service decrements the locked-stack counter, and restores the previous stack of the virtual machine if the counter is zero. To unlock the stack, a virtual device must call this service once for each call made to the Begin_Use_Locked_PM_Stack service. Uses Flags.

  • Returns Client_SS, Client_SP, and Client_EIP to the values they had before the Begin_Use_Locked_PM_Stack service was called, if locked-stack counter drops to zero. Otherwise, these registers remain unchanged.

See Also

Begin_Use_Locked_PM_Stack


Exec_PM_Int

include vmm.inc

mov     eax, Interrupt
VMMCall Exec_PM_Int
jc      ErrorHandler

Simulates the specified interrupt in a protected mode virtual machine while in nested execution. Uses flags.

  • Sets the carry flag if an error occurs.
Interrupt
Interrupt to be simulated.

This service is intended to be used only by the Windows kernel; external virtual devices should not use it. External virtual devices should use the Exec_Int service instead.

Exec_PM_Int is similar to Exec_VxD_Int except the register information for the interrupt are taken from the current client registers instead of the current ring 0 machine registers.

All DOS and BIOS calls that are supported in protected mode programs are supported by this service.

All client registers and flags modified by the interrupt will be changed in the client virtual machine.

The simulated interrupts will be routed through virtual-device interrupt hooks; however, they will bypass any hook that the application has installed in protected mode.

If the service is called within a must-complete section and a fatal error occurs, the carry flag is set and the client registers are left in an unknown state.

See Also

Exec_Int


Get_Cur_PM_App_CB

include vmm.inc

mov     ebx, VMHandle
VMMCall Get_Cur_PM_App_CB
mov     [ControlBlock], edi

Retrieves a pointer to the application control block for a protected-mode application. Uses EDI.

  • Returns the address of the application control block in EDI.
VMHandle
Handle of the virtual machine in which the protected-mode application is running.

It is an error to call this service if the virtual machine is not running a protected-mode application.


Set_PM_Exec_Mode

include vmm.inc

VMMCall Set_PM_Exec_Mode

Forces the current virtual machine into protected mode. If the current virtual machine is already in protected mode, this service has no effect. Uses Flags.

  • No return value.

Whenever possible, a virtual device should use the Begin_Nest_Exec service instead of this service.

Changing the execution mode of a virtual machine does not change the virtual machine's EAX, EBX, ECX, EDX, ESI, EDI, and EBP registers or most flags. The VM flag and IOPL flags change. The DS, ES, FS, GS, SS, ESP, CS, and EIP registers are restored to the previous values for V86 mode.

See Also

Begin_Nest_Exec, Set_V86_Exec_Mode


Set_V86_Exec_Mode

include vmm.inc

VMMCall Set_V86_Exec_Mode

Forces the current virtual machine into V86 mode. If the current virtual machine is already in V86 mode, this service has no effect. Uses Flags.

  • No return value.

Whenever possible, a virtual device should use the Begin_Nest_V86_Exec service instead of this service.

Changing the execution mode of a virtual machine does not change the virtual machine's EAX, EBX, ECX, EDX, ESI, EDI, and EBP registers or most flags. The VM flag and IOPL flags change. The DS, ES, FS, GS, SS, ESP, CS, and EIP registers are restored to the previous values for V86 mode.

See Also

Begin_Nest_V86_Exec, Set_PM_Exec_Mode


Processor Faults

A processor fault (also called a processor exception) is an interruption of execution typically caused by the currently running program rather than by an external source. There are the following processor fault services:

Service | Description
Get_Fault_Hook_Addrs | Returns addresses for fault handlers.
Get_NMI_Handler_Addr | Returns NMI handler address.
Hook_Invalid_Page_Fault | Installs a hook procedure for page faults.
Hook_NMI_Event | Installs a non-maskable interrupt event procedure.
Hook_PM_Fault | Installs a fault handler for protected mode.
Hook_V86_Fault | Installs a fault handler for V86 mode.
Hook_VMM_Fault | Installs a fault handler for VMM.
NMIEventCallback | Developer-defined callback function for a NMI event.
Set_NMI_Handler_Addr | Sets the NMI handler address.
Unhook_Invalid_Page_Fault | Removes a hook procedure for page faults.
Unhook_NMI_Event | Unhooks a non-maskable interrupt event procedure.
Unhook_PM_Fault | Removes the hook procedure for the specified protected-mode fault.
Unhook_V86_Fault | Removes the hook procedure for the specified virtual 8086 mode fault.
Unhook_VMM_Fault | Removes the hook procedure for the specified fault.


Get_Fault_Hook_Addrs

include vmm.inc

mov     eax, FaultNo      ; fault number
VMMCall Get_Fault_Hook_Addrs

Returns addresses of the V86 mode, protected-mode, and VMM fault handlers for a specified fault. Uses Flags.

  • Returns with the carry flag clear if successful, set otherwise. If the carry flag is clear, the following registers contain the following values:
Register | Description
EDI | Contains the address of the handler for VMM faults. This register contains zero if no handler has been installed.
EDX | Contains the address of the handler for V86 mode faults. This register contains zero if no handler has been installed.
ESI | Contains the address of the handler for protected-mode faults. This register contains zero if no handler has been installed.

FaultNo
Fault number for which to retrieve information.

A virtual device cannot get the hook address for the Non-Maskable Interrupt (Interrupt 2). It must use the Get_NMI_Handler_Addr and Set_NMI_Handler_Addr services to hook Interrupt 2.

See Also

Get_NMI_Handler_Addr, Set_NMI_Handler_Addr


Get_NMI_Handler_Addr

include vmm.inc

VMMCall Get_NMI_Handler_Addr

mov     [NMI], esi          ; offset to current NMI handler

Returns the address of the current Non-Maskable Interrupt (NMI) handler. Uses ESI, Flags.

  • Returns the offset of the current NMI handler in the ESI register.

If a virtual device needs to hook the Non-Maskable Interrupt it must first call this service to get and save the original NMI handler address. The virtual device can then install the new NMI handler by using the Set_NMI_Handler_Addr service. The new handler should create an NMI handler chain by passing execution to the original NMI handler whenever it does not process the NMI.

See Also

Set_NMI_Handler_Addr


Hook_Invalid_Page_Fault

include vmm.inc

mov     esi, OFFSET32 Callback  ; procedure to install
VMMCall Hook_Invalid_Page_Fault

jc      not_installed           ; carry flag set if procedure not installed

Installs a procedure to handle any invalid-page faults not handled by the system invalid-page-fault handler. Uses Flags.

  • Returns with the carry flag clear if successful, set otherwise.
Callback
Address of the procedure to install. For more information about the procedure, see below.

The system enables interrupts, and calls the procedure as follows:

mov     ebx, VM             ; current VM handle
mov     edi, OFFSET32 ipf   ; points to an IPF_Data
call    [Callback]

jc      not_corrected       ; carry flag set if procedure did
                            ; not correct fault

The VM parameter is a handle identifying the current virtual machine, and the ipf parameter points to an IPF_Data structure containing information about the page fault.

If the callback procedure handles the page fault (for example, by mapping a page into the VM or by altering the page protections), it should return carry clear. Otherwise, the callback should return carry set to indicate that the system should pass the fault to the next procedure in the chain.

The procedure may use all registers except the segment registers.

See Also

Unhook_Invalid_Page_Fault


Hook_NMI_Event

include vmm.inc

mov     esi, OFFSET32 NmiProc
VMMCall Hook_NMI_Event

Installs a Non-Maskable Interrupt (NMI) event procedure. Virtual devices use this service to install event procedures to carry out tasks that are not permitted in NMI handlers. This service is available only during initialization. Uses Flags.

  • No return value.
NmiProc
Address of NMI event procedure. For more information about the procedure, see NMIEventCallback.

The system calls each installed NMI event procedure after the last handler in the NMI handler chain has executed. If more than one NMI event procedure is installed, the system calls the procedures in the order in which they were installed.

See Also

NMIEventCallback, Unhook_NMI_Event


Hook_PM_Fault

include vmm.inc

mov     eax, FaultNo          ; fault number to hook
mov     esi, OFFSET32 FaultProc ; points to a fault handler
VMMCall Hook_PM_Fault

jc      not_installed           ; carry flag set if not installed
; The following line is optional. See the following comments section.
mov     [Previous], esi         ; points to previous fault handler (if any)

Installs a fault handler procedure for faults encountered by protected mode applications. Virtual devices typically install fault handlers while processing the Sys_Critical_Init control message to handle faults, such as general protection faults, that the VMM fault handlers cannot handle. The VMM installs its fault handlers only after the Sys_Critical_Init control message. Virtual devices install fault handlers after Sys_Critical_Init to handle faults before the fault is passed to the VMM fault handlers. Uses ESI, Flags.

  • Returns with the carry flag clear if successful, set otherwise. If the carry flag is clear, and if FaultProc is a hook procedure, the address of the previous handler is stored into the hook variable. If there was no previous handler, the address of the default handler is stored in the hook variable. Whether or not FaultProc is a hook procedure, the ESI register contains the address of the previous fault handler (zero if there was no previous handler). The return value in ESI exists solely for backwards compatibility with Windows 3.1.
FaultNo
Fault number for which to install the fault handler. The fault number cannot be 02h.
Interrupt range (hex)
Description
0-1F
Intel processor faults
20-3F
Windows faults
40-41
Debugger
42-4F
Not used
50-5F
VPICD-reserved (hardware interrupt vectors). If you hook these you should ensure that the behavior of your hook does not interfere with the normal operation of VPICD.
FaultProc
Points to the fault handler to install, which should be a hook procedure in order to be compatible with future versions of Windows. For more information about the handler, see below.

A virtual device can install a fault handler while processing the Sys_Critical_Init message or at a later time. When a fault occurs, fault handlers installed after the Sys_Critical_Init message receive control first, the VMM fault handlers receive control next, and fault handlers installed during the Sys_Critical_Init message receive control last. (Of course, dynamically-loaded VxDs have no choice but to install the fault handler after Sys_Critical_Init, since they haven't yet been loaded at the time the Sys_Critical_Init message is broadcast.

The system disables interrupts, and calls the fault handler as follows:

mov     ebx, VM                 ; current VM handle
mov     ebp, OFFSET32 crs       ; points to a Client_Reg_Struc
call    [FaultProc]

The VM parameter is a handle identifying the current virtual machine, and the crs parameter points to a Client_Reg_Struc structure containing the register values for the current virtual machine.

If the fault procedure does not process the fault, it should pass the fault to the previous fault handler as stored into the hook variable, making sure that all registers are preserved (not just the registers containing input parameters).

The default fault handler calls the fault vector installed by the protected-mode application. (Protected-mode fault hooks gain control before the application sees the fault.)

If the fault handler processes the fault, the handler should return without chaining by executing a near ret instruction (not an iret instruction).

The fault handler can modify the EAX, EBX, ECX, EDX, ESI, and EDI registers.

Do not use this service to install a fault handler for the Non-Maskable Interrupt (NMI). Instead, a virtual device must use the Get_NMI_Handler_Addr and Set_NMI_Handler_Addr services.

Do not use this service to install handlers for hardware interrupts. Instead, a virtual device must use virtual PIC device services.

See Also

Hook_V86_Fault, Hook_VMM_Fault


Hook_V86_Fault

include vmm.inc

mov     eax, FaultNo         ; fault number
mov     esi, OFFSET32 FaultProc ; points to a fault handler
VMMCall Hook_V86_Fault

jc      not_installed        ; carry flag set if not installed
; The following line is optional. See the following comments section.
mov     [Previous], esi      ; points to previous fault handler (if any)

Installs a fault handler procedure for V86 mode faults. Virtual devices typically install fault handlers while processing the Sys_Critical_Init message to handle faults, such as general protection faults, that the VMM fault handlers cannot handle. The VMM installs its fault handlers after the Sys_Critical_Init control message. Virtual devices install fault handlers after Sys_Critical_Init to handle faults before the fault is passed to the VMM fault handlers. Uses ESI, Flags.

  • Returns with the carry flag clear if successful, set otherwise. If the carry flag is clear, and if FaultProc is a hook procedure, the address of the previous handler is stored in the hook variable. If there was no previous handler, the address of the default handler is stored in the hook variable. Regardless of whether FaultProc is a hook procedure, the ESI register contains the address of the previous fault handler (zero if there was no previous handler). The return value in ESI exists solely for backward compatibility with Windows 3.1.
FaultNo
Fault number for which to install the fault handler. The fault number cannot be 02h.
Interrupt range (hex)
Description
0-1F
Intel processor faults
20-3F
Windows faults
40-41
Debugger
42-4F
Not used
50-5F
VPICD-reserved (hardware interrupt vectors). If you hook these you should ensure that the behavior of your hook does not interfere with the normal operation of VPICD.
FaultProc
Address of the fault handler to install. For more information about the handler, see below.

A virtual device can install a fault handler while processing the Sys_Critical_Init message or at a later time. When a fault occurs, fault handlers installed after the Sys_Critical_Init message receive control first, the VMM fault handlers receive control next, and fault handlers installed during the Sys_Critical_Init message receive control last. (Of course, dynamically-loaded VxDs have no choice but to install the fault handler after Sys_Critical_Init, because they haven't yet been loaded at the time the Sys_Critical_Init message is broadcast.)

The system disables interrupts and calls the fault handler as follows:

mov     ebx, VM                 ; current VM handle
mov     ebp, OFFSET32 crs       ; points to a Client_Reg_Struc
call    [FaultProc]

The VM parameter is a handle identifying the current virtual machine, and the crs parameter points to a Client_Reg_Struc structure containing the register values for the current virtual machine.

If the fault procedure does not process the fault, it should pass the fault to the previous fault handler, as stored into the hook variable, making sure that all registers are preserved (not just the registers containing input parameters).

The default fault handler crashes the virtual machine, except for faults 0 (divide), 1 (trace), 3 (breakpoint), 4 (overflow), 5 (bound), and 7 (coprocessor), which are reflected as interrupts.

If the fault handler processes the fault, or if there is no previous fault handler, the handler should return without chaining by executing a near ret instruction (not an iret instruction).

The fault handler can modify the EAX, EBX, ECX, EDX, ESI, and EDI registers.

Do not use this service to install a fault handler for the Non-Maskable Interrupt (NMI). Instead, a virtual device must use the Get_NMI_Handler_Addr and Set_NMI_Handler_Addr services.

Do not use this service to install handlers for hardware interrupts. Instead, a virtual device must use virtual PIC device services.

See Also

Hook_PM_Fault, Hook_VMM_Fault


Hook_VMM_Fault

include vmm.inc

mov     eax, FaultNo            ; fault number
mov     esi, OFFSET32 FaultProc ; points to a fault handler
VMMCall Hook_VMM_Fault

jc      not_installed           ; carry flag set if not installed
; The following line is optional. See the following comments section.
mov     [Previous], esi         ; points to previous fault handler (if any)

Installs a fault handler procedure for faults encountered by VMM or other virtual devices. Virtual devices typically install fault handlers while processing the Sys_Critical_Init control message to handle faults, such as general protection faults, that the VMM fault handlers cannot handle. The VMM installs its fault handlers after the Sys_Critical_Init control message. Virtual devices install fault handlers after Sys_Critical_Init to handle faults before the fault is passed to the VMM fault handlers. Uses ESI, Flags.

  • Returns with the carry flag clear if successful, set otherwise. If the carry flag is clear, and if FaultProc is a hook procedure, the address of the previous handler is stored into the hook variable. If there was no previous handler, the address of the default handler is stored into the hook variable. Regardless of whether FaultProc is a hook procedure, the ESI register contains the address of the previous fault handler (zero if there was no previous handler). The return value in ESI exists solely for backwards compatibility with Windows 3.1.
FaultNo
Fault number for which to install the fault handler. The fault number cannot be 02h.
Interrupt range (hex)
Description
0-1F
Intel processor faults
20-3F
Windows faults
40-41
Debugger
42-4F
Not used
50-5F
VPICD-reserved (hardware interrupt vectors). If you hook these you should ensure that the behavior of your hook does not interfere with the normal operation of VPICD.
FaultProc
Address of the fault handler to install. For more information about the handler, see below.

A virtual device can install a fault handler while processing the Sys_Critical_Init message, or at a later time. When a fault occurs, fault handlers installed after the Sys_Critical_Init message receive control first, the VMM fault handlers receive control next, and fault handlers installed during the Sys_Critical_Init message receive control last. (Of course, dynamically-loaded VxDs have no choice but to install the fault handler after Sys_Critical_Init, since they haven't yet been loaded at the time the Sys_Critical_Init message is broadcast.)

The system disables interrupts and calls the fault handler as follows:

mov     ebx, VM                 ; current VM handle
mov     ebp, OFFSET32 stkfrm    ; points to VMM re-entrant stack frame
call    [FaultProc]

The VM parameter is a handle identifying the current virtual machine, and the stkfrm parameter points to the VMM re-entrant fault stack frame.

The EBP register does not point to a client register structure.

The fault handler may call asynchronous services only.

If the fault handler does not process the fault, it should pass the fault to the previous fault handler (if any), making sure that all registers are preserved (not just the registers containing input parameters).

If the fault handler processes the fault or if there is no previous fault handler, the handler should return without chaining by executing a near ret instruction (not an iret instruction).

The fault handler can modify the EAX, EBX, ECX, EDX, ESI, and EDI registers.

Do not use this service to install a fault handler for the Non-Maskable Interrupt (NMI). Instead, a virtual device must use the Get_NMI_Handler_Addr and Set_NMI_Handler_Addr services.

Do not use this service to install handlers for hardware interrupts. Instead, a virtual device must use virtual PIC device services.

See Also

Hook_PM_Fault, Hook_V86_Fault


NMIEventCallback

include vmm.inc

mov     ebx, VMHandle
mov     ebp, OFFSET32 crs
call    [NmiProc]

Performs programmer-defined processing that is not permitted in a Non-Maskable Interrupt (NMI) handler. NMIEventCallback is a programmer-defined callback function installed by the Hook_NMI_Event service. An NMIEventCallback function can be re-entered; that is, it can be interrupted by another NMI.

  • No return value.
VMHandle
Handle of the current virtual machine.
crs
Address of a Client_Reg_Struc structure containing the contents of the virtual machine's registers.

See Also

Client_Reg_Struc, Hook_NMI_Event, Unhook_NMI_Event


Set_NMI_Handler_Addr

include vmm.inc

mov     esi, OFFSET32 nmi       ; points to new NMI handler
VMMCall Set_NMI_Handler_Addr

Sets the Non-Maskable Interrupt (NMI) vector to the address of the specified NMI handler. Uses Flags.

  • No return value.
nmi
Address of the new NMI handler.

To install an NMI handler, a virtual device must retrieve and save the current NMI handler address using the Get_NMI_Handler_Addr service, and set the new address using Set_NMI_Handler_Addr.

The NMI handler must not call VMM or virtual device services. This restriction includes calls to asynchronous VMM services. The NMI handler can examine and modify local data in the VxD_LOCKED_DATA_SEG segment, but it must not attempt to access any other memory, including virtual machine and V86 memory. If a virtual device needs to use VMM services in response to an NMI, it should install an NMI event handler using the Hook_NMI_Event service.

The NMI handler must not execute the iret instruction. Instead, it must jump to the address of the previous NMI handler (retrieved using the Get_NMI_Handler_Addr service). The CPU ignores additional NMIs until it executes the iret instruction. Because no NMI handlers in the chain execute this instruction, the handlers are guaranteed not to be re-entered.

Some computers require the latch at port 70h be reset to enable further NMIs. To simplify NMI processing for other NMI handlers, the virtual-parity device (PARITY) automatically resets this latch.

See Also

Get_NMI_Handler_Addr, Hook_NMI_Event


Unhook_Invalid_Page_Fault

include vmm.inc

mov     esi, OFFSET32 HookProc     ; points to hook procedure to remove
VMMCall Unhook_Invalid_Page_Fault

Removes the specified hook procedure from the invalid-page-fault chain. Uses Flags.

  • Returns with the carry flag clear if successful, set otherwise.
HookProc
Address of the hook procedure to remove. This procedure must have been previously installed using the Hook_Invalid_Page_Fault service.

See Also

Hook_Invalid_Page_Fault


Unhook_NMI_Event

include vmm.inc

mov     esi, OFFSET32 NmiProc
VMMCall Unhook_NMI_Event

Cancels a Non-Maskable Interrupt (NMI) event procedure that was installed earlier by the Hook_NMI_Event function. Uses Flags.

  • No return value.
NmiProc
Address of the NMI event procedure to cancel. For more information about the procedure, see NMIEventCallback.

See Also

Hook_NMI_Event, NMIEventCallback


Unhook_PM_Fault

include vmm.inc

mov     eax, FaultNo
mov     esi, OFFSET32 Hook_Proc
VMMCall Unhook_PM_Fault
jc      Error_Handler

Removes the hook procedure for the specified protected mode fault. Uses flags.

  • Clears the carry flag if successful; sets the carry flag on the following conditions:
  • Invalid fault number passed in EAX.
  • ESI does not point to a hook procedure.
  • Hook procedure could not be found.
  • A non-hook procedure was found in the chain of procedures.
FaultNo
Specifies the fault number.
Hook_Proc
Address of the hook procedure to be removed.

The specified hook procedure must have been declared using the BeginProc macro with the HOOK_PROC attribute in order to generate the necessary header.

See Also

BeginProc


Unhook_V86_Fault

include vmm.inc

mov     eax, FaultNo
mov     esi, OFFSET32 Hook_Proc
VMMCall Unhook_V86_Fault
jc      Error_Handler

Removes the hook procedure for the specified virtual 8086-mode fault. Uses flags.

  • Clears the carry flag if successful; sets the carry flag on the following conditions:
  • Invalid fault number passed in EAX.
  • ESI does not point to a hook procedure.
  • Hook procedure could not be found.
  • A non-hook procedure was found in the chain of procedures.
FaultNo
Specifies the fault number.
Hook_Proc
Address of the hook procedure to be removed.

The specified hook procedure must have been declared using the BeginProc macro with the HOOK_PROC attribute in order to generate the necessary header.

See Also

BeginProc


Unhook_VMM_Fault

include vmm.inc

mov     eax, FaultNo
mov     esi, OFFSET32 Hook_Proc
VMMCall Unhook_VMM_Fault
jc      Error_Handler

Removes the hook procedure for the specified ring 0 fault. Uses flags.

  • Clears the carry flag if successful; sets the carry flag on the following conditions:
  • Invalid fault number passed in EAX.
  • ESI does not point to a hook procedure.
  • Hook procedure could not be found.
  • A non-hook procedure was found in the chain of procedures.
FaultNo
Specifies the fault number.
Hook_Proc
Address of the hook procedure to be removed.

The specified hook procedure must have been declared using the BeginProc macro with the HOOK_PROC attribute in order to generate the necessary header.

See Also

BeginProc


Registry

There are the following registry services:

_GetRegistryKey _GetRegistryPath _RegCreateDynKey _RegCloseKey _RegCreateKey _RegDeleteKey _RegDeleteValue _RegEnumKey _RegEnumValue _RegFlushKey _RegOpenKey _RegQueryInfoKey _RegQueryMultipleValues _RegQueryValue _RegQueryValueEx _RegRemapPreDefKey _RegSetValue _RegSetValueEx

Note that the registry is read-only when the processor is in real mode.


_GetRegistryKey

#include <vmmreg.h>

_GetRegistryKey(DWORD dwType, LPSTR lpszDeviceName,
                DWORD dwFlags, LPHKEY lphDevKey);

Gets a registry key handle for the given device name under the branch of the registry tree specified by the dwType parameter. Uses C calling convention. Caller should use _RegCloseKey to close the returned HKEY.

  • Returns ERROR_SUCCESS if the function was successful. Otherwise, an error code is returned, possibly one of the following:
ERROR_INVALID_PARAMETER
ERROR_REGISTRY_IO_FAILED
ERROR_REGISTRY_CORRUPT
ERROR_BADDB
ERROR_FILE_NOT_FOUND

dwType
Defines the registry branch for the key. Must be REGTYPE_CLASS, REGTYPE_VXD or REGTYPE_ENUM.
lpszDevName
Address of null terminated string specifying device name.
dwFlags
Flags for the registry. Must be either REGKEY_OPEN or REGKEY_CREATE_IFNOTEXIST.
lphKey
Address of the buffer that receives the HKEY.


_GetRegistryPath

include vmm.inc

VMMCall _GetRegistryPath, <OFFSET32 ThisDDB, OFFSET32 UserBuff,
    UserBuffSize>

Retrieves the path to the registry location where information about a VxD is stored. This service is available only during initialization. Uses C calling convention.

  • Returns, in EAX, the length of the string copied to UserBuff if the function succeeds. If UserBuff is too small, EAX contains the required size of the buffer. If the service fails, the return value is zero.
ThisDDB
Address of the descriptor block (VxD_Desc_Block) for the virtual device.
UserBuff
Address of the buffer that receives the registry path.
UserBuffSize
Size, in bytes, of the buffer pointed to by UserBuff.


_RegCloseKey

include vmm.h

LONG _RegCloseKey(HKEY hkey)

Closes a previously opened key. See the documentation for the Win32 function of the same name for additional information.

  • Returns ERROR_SUCCESS if the function succeeds. Otherwise, an error code is returned, possibly one of the following:
ERROR_BADKEY
ERROR_REGISTRY_CORRUPT

hkey
Handle of the key to close.

The handle for the given key should not be used after it has been closed, because it will no longer be valid. Key handles should not be left open any longer than necessary.

See Also

_RegOpenKey


_RegCreateDynKey

include vmm.h

RegCreateDynKey(LPSTR lpszName, LPVOID KeyContext, PPROVIDER pInfo,
    PPVALUE pValList, DWORD dwNumVals, HKEY FAR * pKeyHandle);

Creates the specified registry key under HKEY_DYN_DATA. Values under HKEY_DYN_DATA are maintained by the VxDs that create them. The VMM will call the appropriate VxD's enumeration entry point when a value is enumerated or queried.

  • Returns ERROR_SUCCESS if the function succeeds. Otherwise, an error code is returned, possibly one of the following:
ERROR_ACCESS_DENIED
ERROR_INSUFFICIENT_MEMORY
ERROR_CANNOT_OPEN_REGFILE
ERROR_REGFILE_READERROR
ERROR_REGFILE_WRITEERROR
ERROR_REGKEY_INVALIDKEY

lpszName
Name of the key to create:
KeyContext
Four bytes of context that will be passed to the owning VxD when its enumeration entry point is called.
pInfo
Address of a PROVIDER structure (see vmmreg.h) that specifies the enumeration entry points for a key.
pValList
Address of an array of PVALUE structures (see vmmreg.h) that specify the value names and other attributes for the values under lpszName.
dwNumVals
Number of PVALUE structures in the pValList array.
pKeyHandle
Address of the variable to receive the handle of the newly created key, lpszName.


_RegCreateKey

include vmm.h

LONG _RegCreateKey(HKEY hkey, LPTSTR lpszSubKey, PHKEY phkResult)

Creates the specified key or opens the key if it already exists in the registry. Caller should use RegCloseKey to close the returned key. See the documentation for the Win32 function of the same name for additional information.

  • Returns ERROR_SUCCESS if the function succeeds. Otherwise, an error code is returned, possibly one of the following:
ERROR_KEY_DELETED
ERROR_BADKEY
ERROR_REGISTRY_IO_FAILED
ERROR_REGISTRY_CORRUPT
ERROR_BADDB
ERROR_OUTOFMEMORY

hkey
Handle of the open key or one of the predefined keys::
HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
HKEY_CURRENT_CONFIG

lpszSubKey
Address of null-terminated string specifying the name of a key that this service creates or opens.
phkResult
Points to a variable that receives the handle of the opened or created key.

The key addressed by lpszSubKey must be a subkey of the key identified by hkey.

The key referenced by hkey cannot have HKEY_DYN_DATA as an ancestor (see RegCreateDynKey).

The lpszSubKey parameter cannot be NULL unless hkey is one of the predefined keys.

This service can be used to create keys several levels deep by specifying a subkey string with several keys separated by backslashes.

Of the predefined key values, only HKEY_LOCAL_MACHINE is available to VxDs during initialization time. The entire registry space can only be accessed after VxD initialization is complete.

See Also

_RegDeleteKey


_RegDeleteKey

include vmm.h

LONG _RegDeleteKey(HKEY hkey, LPTSTR lpszSubKey)

Deletes the specified key. Do not use this service to delete a key that has subkeys. See the documentation for the Win32 function of the same name for additional information.

  • Returns ERROR_SUCCESS if the function succeeds. Otherwise, an error code is returned, possibly one of the following:
ERROR_FILE_NOT_FOUND
ERROR_KEY_DELETED
ERROR_REGISTRY_IO_FAILED
ERROR_REGISTRY_CORRUPT
ERROR_BADDB

hkey
Handle of an open key or one of the predefined keys:
HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
HKEY_CURRENT_CONFIG
HKEY_DYN_DATA

lpszSubKey
Address of null-terminated string specifying the name of the key to delete.

Of the predefined key values, only HKEY_LOCAL_MACHINE is available to VxDs during VxD initialization time. The entire registry space can only be accessed after VxD initialization is complete.

See Also

_RegCreateKey


_RegDeleteValue

include vmm.h

LONG _RegDeleteValue(HKEY hkey, LPTSTR lpszValue)

Removes a named value from the given registry key. See the documentation for the Win32 function of the same name for additional information.

  • Returns ERROR_SUCCESS if the function succeeds. Otherwise, an error code is returned, possibly one of the following:
ERROR_FILE_NOT_FOUND
ERROR_KEY_DELETED
ERROR_BADKEY
ERROR_REGISTRY_IO_FAILED
ERROR_REGISTRY_CORRUPT
ERROR_BADDB

hkey
Handle of an open key or one of the predefined keys:
HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
HKEY_CURRENT_CONFIG

lpszValue
Address of null-terminated string that contains the name of the value to remove.

Of the predefined key values, only HKEY_LOCAL_MACHINE and HKEY_DYN_DATA are available to VxDs during initialization time. The entire registry space can only be accessed after VxD initialization is complete.


_RegEnumKey

include vmm.h

LONG _RegEnumKey(HKEY hkey, DWORD iSubKey, LPTSTR lpszName, DWORD cchName)

Enumerates subkeys of the given open registry key; retrieves the name of one subkey each time the service is called. See the documentation for the Win32 function of the same name for additional information.

  • Returns ERROR_SUCCESS if the function succeeds. Otherwise, an error code is returned, possibly one of the following:
ERROR_NO_MORE_ITEMS
ERROR_KEY_DELETED
ERROR_MORE_DATA
ERROR_BADKEY
ERROR_REGISTRY_IO_FAILED
ERROR_REGISTRY_CORRUPT
ERROR_BADDB

hkey
Handle of an open key or one of the predefined keys:
HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
HKEY_CURRENT_CONFIG
HKEY_DYN_DATA

iSubKey
Index of subkey to be retrieved; should be zero for the first call to this service and incremented for each subsequent call

Because subkeys are not ordered, any new subkey will have an arbitrary index.

lpszName
Address of buffer that receives the subkey name, including terminating null character.
cchName
Size in bytes of buffer; should include space for terminating null character.

To retrieve the index of the last subkey, use RegQueryInfoKey or increment iSubKey until ERROR_NO_MORE_ITEMS is returned.

Of the predefined key values, only HKEY_LOCAL_MACHINE and HKEY_DYN_DATA are available to VxDs during initialization time. The entire registry space can only be accessed after VxD initialization is complete.

The caller should reinitialize the variable containing the buffer size on each subsequent call to this service.


_RegEnumValue

include vmm.h

LONG _RegEnumValue(HKEY hkey, DWORD iValue, LPTSTR lpszValue,
    LPDWORD lpcchValue, LPDWORD lpdwReserved, LPDWORD lpdwType,
    LPBYTE lpbData, LPDWORD lpcbData)

Enumerates values for the given open registry key; the service copies one indexed value name and data block for the key each time it is called. See the documentation for the Win32 function of the same name for additional information.

  • Returns ERROR_SUCCESS if the function succeeds. Otherwise, an error code is returned, possibly one of the following:
ERROR_NO_MORE_ITEMS
ERROR_KEY_DELETED
ERROR_MORE_DATA
ERROR_BADKEY
ERROR_REGISTRY_IO_FAILED
ERROR_REGISTRY_CORRUPT
ERROR_BADDB

hkey
Handle of an open key or one of the predefined keys:
HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
HKEY_CURRENT_CONFIG
HKEY_DYN_DATA

iValue
Index of the value to retrieve; should be zero for first call to this service and then incremented for each subsequent call. Because values are not ordered, any new value will have an arbitrary index.
lpszValue
Address of buffer that receives name of the value, including the terminating null character.
lpcchValue
Address of variable that specifies the length of the buffer in bytes, including the terminating null character.
lpdwReserved
Reserved; must be NULL.
lpdwType
Address of variable that receives the type code for the value entry. It can be one of these standard values or other value (which is treated like REG_BINARY):
REG_BINARY | Binary data in any form.
REG_SZ | A null-terminated UNICODE or ANSI string.

This parameter can be NULL if the type code is not required.

lpbData
Address of variable that receives the data for the value entry. This parameter can be NULL if the data is not required.
lpcbData
Address of variable that specifies the size, in bytes, of the buffer pointed to by lpbData. When the service returns, the variable contains the number of bytes stored in the buffer.

This parameter can be NULL only if lpbData is NULL.

Of the predefined key values, only HKEY_LOCAL_MACHINE and HKEY_DYN_DATA are available to VxDs during initialization time. The entire registry space can only be accessed after VxD initialization is complete.

The caller should reinitialize the variable containing the buffer size on each subsequent call to this service.


_RegFlushKey

include vmm.h

LONG _RegFlushKey(HKEY hkey)

The specified key is written to the registry file on the disk. This service should be avoided for performance reasons. Windows will automatically flush the registry to the disk. See the documentation for the Win32 function of the same name for additional information.

  • Returns ERROR_SUCCESS if the function succeeds. Otherwise, an error code is returned, possibly one of the following:
ERROR_KEY_DELETED
ERROR_OUTOFMEMORY
ERROR_BADKEY
ERROR_REGISTRY_IO_FAILED
ERROR_REGISTRY_CORRUPT
ERROR_BADDB

hkey
Handle of an open key or one of the predefined keys:
HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
HKEY_CURRENT_CONFIG

Of the predefined key values, only HKEY_LOCAL_MACHINE is available to VxDs during initialization time. The entire registry space can only be accessed after VxD initialization is complete.


_RegOpenKey

include vmm.h

LONG _RegOpenKey(HKEY hkey, LPTSTR lpszSubKey, PHKEY phkResult)

Opens the specified key. Caller should use RegCloseKey to close the returned key. See the documentation for the Win32 function of the same name for additional information.

  • Returns ERROR_SUCCESS if the function succeeds. Otherwise, an error code is returned, possibly one of the following:
ERROR_KEY_DELETED
ERROR_BADKEY
ERROR_FILE_NOT_FOUND
ERROR_OUTOFMEMORY
ERROR_REGISTRY_IO_FAILED
ERROR_REGISTRY_CORRUPT
ERROR_BADDB

hkey
Handle of an open key or one of the predefined keys:
HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
HKEY_CURRENT_CONFIG
HKEY_DYN_DATA

lpszSubKey
Address of a null-terminated string containing the name of the key to open.
phkResult
Address of variable that receives handle of opened key.

The key opened by this service is a subkey of the key which hkey identifies.

If lpszSubKey is NULL or a pointer to an empty string, the service returns hkey.

Of the predefined key values, only HKEY_LOCAL_MACHINE and HKEY_DYN_DATA are available to VxDs during initialization time. The entire registry space can only be accessed after VxD initialization is complete.

See Also

_RegCloseKey


_RegQueryInfoKey

include vmm.h

DWORD _RegQueryInfoKey(HKEY hKey, LPTSTR lpszClass,
    LPDWORD lpcchClass, LPDWORD lpdwReserved, LPDWORD lpcSubKeys,
    LPDWORD lpcchMaxSubKey, LPDWORD lpcchMaxClass, LPDWORD lpcValues,
    LPDWORD lpcchMaxValueName, LPDWORD lpcbMaxValueData,
    LPDWORD lpcbSecurityDescriptor, PFILETIME lpftLastWriteTime)

Retrieves information about a specified registry key. See the documentation for the Win32 function of the same name for additional information.

  • Returns ERROR_SUCCESS if the function succeeds. Otherwise, an error code is returned, possibly one of the following:
ERROR_KEY_DELETED
ERROR_BADKEY
ERROR_REGISTRY_IO_FAILED
ERROR_REGISTRY_CORRUPT
ERROR_BADDB

hkey
Handle of an open key or one of the predefined keys:
HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
HKEY_CURRENT_CONFIG
HKEY_DYN_DATA

lpszClass
Address of a buffer that receives the key's class name. Currently, this parameter is not supported.
lpcchClass
Size of the buffer pointed to by the lpszClass parameter on input and length of string returned in lpszClass on output. Currently, this parameter is not supported.
lpdwReserved
Reserved, must be NULL.
lpcSubKeys
Address of the buffer that receives the number of subkeys contained by the specified key.
lpcchMaxSubKey
Address of a variable that receives the length of the key's subkey with the longest name. The count returned does not include the terminating null character.
lpcchMaxClass
Address of a variable that receives the length of the longest string specifying a subkey class. Currently, this parameter is not supported.
lpcValues
Address of a variable that receives the number of values associated with the key.
lpcchMaxValueName
Address of a variable that receives the length of the key's longest value name. The count returned does not include the terminating null character.
lpcbMaxValueData
Address of a variable that receives the length of the longest data component among the key's values.
lpcbSecurityDescriptor
Address of a variable that receives the length of the key's security descriptor. Currently, this parameter is not supported.
lpftLastWriteTime
Address of variable that receives a FILETIME structure, indicating the last time the key or any of its value entries was modified. Currently, this parameter is not supported.

Of the predefined key values, only HKEY_LOCAL_MACHINE and HKEY_DYN_DATA are available to VxDs during initialization time. The entire registry space can only be accessed after VxD initialization is complete.


_RegQueryMultipleValues

include vmm.h

DWORD _RegQueryMultipleValues(HKEY hKey, PVALENT pValent,
    DWORD dwNumVals, LPSTR lpValueBuf, LPDWORD lpTotSize)

Retrieves the values for the names specified in the pValent parameter for the specified key in the registry. See the documentation for the Win32 function of the same name for additional information.

  • Returns ERROR_SUCCESS if the function succeeds. Otherwise, an error code is returned, possibly one of the following:
ERROR_KEY_DELETED
ERROR_MORE_DATA
ERROR_BADKEY
ERROR_REGISTRY_IO_FAILED
ERROR_REGISTRY_CORRUPT
ERROR_BADDB

hkey
Handle of an open key or one of the predefined keys:
HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
HKEY_CURRENT_CONFIG
HKEY_DYN_DATA

pValent
Array of VALENT structures specifying value names to retrieve values for. The VALENT structure has the following format:
typedef struct value_ent {
    PCHAR ve_valuename;
    DWORD ve_valuelen;
    DWORD ve_valueptr;
    DWORD ve_type;
} VALENT;
dwNumVals
Number of VALENT structures in the pValent array.
lpValueBuf
Address of a buffer that receives the value data.
lpTotSize
Number of bytes in the lpValueBuf parameter.

RegQueryMultipleValues is useful for dynamic key providers because it assures consistency of data by retrieving multiple values in an atomic operation. For all keys, this service, is more efficient than calling RegQueryValue multiple times, particularly across a network since it can retrieve the values with one network transaction.

Of the predefined key values, only HKEY_LOCAL_MACHINE and HKEY_DYN_DATA are available to VxDs during initialization time. The entire registry space can only be accessed after VxD initialization is complete.


_RegQueryValue

include vmm.h

LONG _RegQueryValue(HKEY hkey, LPTSTR lpszSubKey, LPTSTR lpszValue,
    PLONG pcbValue)

Retrieves the value associated with the unnamed value for a specified key in the registry. See the documentation for the Win32 function of the same name for additional information.

  • Returns ERROR_SUCCESS if the function succeeds. Otherwise, an error code is returned, possibly one of the following:
ERROR_KEY_DELETED
ERROR_MORE_DATA
ERROR_BADKEY
ERROR_REGISTRY_IO_FAILED
ERROR_REGISTRY_CORRUPT
ERROR_BADDB

hkey
Handle of an open key or one of the predefined keys:
HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
HKEY_CURRENT_CONFIG
HKEY_DYN_DATA

lpszSubKey
Address of string that contains name of the subkey of the hkey parameter for which a value is to be retrieved.
lpszValue
Address of string that contains name of the subkey of the hkey parameter for which a value is to be retrieved. If this parameter is NULL and pcbValue is not NULL this service returns ERROR_SUCCESS and returns the size of the buffer needed the variable pointed to by pcbValue.
pcbValue
Address of variable specifying the size, in bytes, of the lpszValue buffer. The buffer should be big enough to contain the terminating null character. On return, the variable contains the size of the data copied to the buffer. If the passed in size is not big enough, the variable will contain the size needed and ERROR_MORE_DATA will be returned.

Of the predefined key values, only HKEY_LOCAL_MACHINE and HKEY_DYN_DATA are available to VxDs during initialization time. The entire registry space can only be accessed after VxD initialization is complete.


_RegQueryValueEx

include vmm.h

LONG _RegQueryValueEx(HKEY hkey, LPTSTR lpszValueName,
    LPDWORD lpdwReserved, LPDWORD lpdwType, LPBYTE lpbData,
    LPDWORD lpcbData)

Retrieves the type and data for a specified value name associated with an open registry key. See the documentation for the Win32 function of the same name for additional information.

  • Returns ERROR_SUCCESS if the function succeeds. Otherwise, an error code is returned, possibly one of the following:
ERROR_KEY_DELETED
ERROR_MORE_DATA
ERROR_FILE_NOT_FOUND
ERROR_REGISTRY_IO_FAILED
ERROR_REGISTRY_CORRUPT
ERROR_BADDB

hkey
Handle of an open key or one of the predefined keys:
HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
HKEY_CURRENT_CONFIG
HKEY_DYN_DATA

lpszValueName
Points to a null-terminated string containing the name of the value to be queried.
lpdwReserved
Reserved; must be NULL.
lpdwType
Address of variable that receives the type code for the value entry. This parameter can be NULL if the type is not required. The type can be any value or one of the standard values:
REG_BINARY | Binary data in any form.
REG_SZ | A null-terminated UNICODE or ANSI string.

lpbData
Address of buffer that receives the data for the value entry. This parameter can be NULL if the data is not required.
lpcbData
Address of variable that specifies size, in bytes, of the buffer addressed by lpbData.

Of the predefined key values, only HKEY_LOCAL_MACHINE and HKEY_DYN_DATA are available to VxDs during initialization time. The entire registry space can only be accessed after VxD initialization is complete.


_RegRemapPreDefKey

include vmm.h

DWORD _RegRemapPreDefKey(HKEY hKey, HKEY hkRootKey)

Changes the current predefined hkRootKey to point to the given open key, specified by hKey. This operation is only allowed on HKEY_CURRENT_USER, HKEY_CURRENT_CONFIG. This service is intended for use by the system and is not for general use by drivers.

  • Returns ERROR_SUCCESS if the function succeeds. Otherwise, an error code is returned, possibly one of the following:
ERROR_KEY_DELETED
ERROR_BADKEY
ERROR_REGISTRY_IO_FAILED
ERROR_REGISTRY_CORRUPT
ERROR_BADDB

hKey
A previously opened key.
hkRootKey
One of HKEY_CURRENT_USER or HKEY_CURRENT_CONFIG.

This function invalidates all open handles opened through the previous HKEY_CURRENT_USER or HKEY_CURRENT_CONFIG.


_RegSetValue

include vmm.h

LONG _RegSetValue(HKEY hkey, LPTSTR lpszSubKey, DWORD fdwType,
    LPTSTR lpszData, DWORD cbData)

Associates a value with the specified key; this value is of type REG_SZ and does not have a value name. See the documentation for the Win32 function of the same name for additional information.

  • Returns ERROR_SUCCESS if the function succeeds. Otherwise, an error code is returned, possibly one of the following:
ERROR_FILE_NOT_FOUND
ERROR_KEY_DELETED
ERROR_BADKEY
ERROR_REGISTRY_IO_FAILED
ERROR_REGISTRY_CORRUPT
ERROR_BADDB

hkey
Handle of an open key or one of the predefined keys:
HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
HKEY_CURRENT_CONFIG

lpszSubKey
Address of null-terminated string that contains the name of the subkey of the hkey parameter for which the value is associated. If this is an empty string, the value will be associated with the key identified by the hkey parameter.
fdwType
Type of information to be stored. Must be REG_SZ.
lpszData
Address of null-terminated string containing value to set for the given key.
cbData
Length in bytes of string at which lpszData points, not including the terminating null character.

If the key specified by lpszSubKey does not exist, this service will create it.

Value lengths are limited by available memory. Long values (more than 2048 bytes) should be stored as files with the filenames stored in the registry.

Of the predefined key values, only HKEY_LOCAL_MACHINE is available to VxDs during initialization time. The entire registry space can only be accessed after VxD initialization is complete.


_RegSetValueEx

include vmm.h

LONG _RegSetValueEx(HKEY hkey, LPTSTR lpszValueName,
    DWORD dwReserved, DWORD fdwType, LPBYTE lpbDta, DWORD cbData)

Stores data in the value field of an open registry key; the service can also set additional value and type information for the given key. See the documentation for the Win32 function of the same name for additional information.

  • Returns ERROR_SUCCESS if the function succeeds. Otherwise, an error code is returned, possibly one of the following:
ERROR_KEY_DELETED
ERROR_OUTOFMEMORY
ERROR_REGISTRY_IO_FAILED
ERROR_REGISTRY_CORRUPT
ERROR_BADDB

hkey
Handle of the open key or one of these predefined values:
HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS

lpszValueName
Points to a null-terminated string containing the name of the value to set. If a value with this name is not already present in the key, the function adds it to the key. If this parameter is NULL or points to an empty string, the fdwType must be REG_SZ and this service will set the same value as RegSetValue.
lpdwReserved
Reserved; must be NULL.
fdwType
The type code for the value entry. It can be one of these values:
REG_BINARY | Binary data in any form.
REG_SZ | A null-terminated UNICODE or ANSI string.

lpbData
Address of buffer that receives the data for the value entry.
lpcbData
Address of variable that specifies size, in bytes, of the buffer addressed by lpbData. If the type is REG_SZ this must include the terminating null character.

If the key specified by lpszSubKey does not exist, this service will create it.

Value lengths are limited by available memory. Long values (more than 2048 bytes) should be stored as files with the filenames stored in the registry.

Of the predefined key values, only HKEY_LOCAL_MACHINE is available to VxDs during initialization time. The entire registry space can only be accessed after VxD initialization is complete.


Return Values for Registry Services

The following list of error values is not comprehensive. It is included here to give you an idea of the kinds of errors to expect. Future versions of Windows may return new error codes, or return slightly different error codes under analogous circumstances.

Value | Meaning
ERROR_SUCCESS | The function was successful.
ERROR_NO_MORE_ITEMS | There are no more keys or values to enumerate.
ERROR_MORE_DATA | Passed in buffer is not large enough to hold the entire value.
ERROR_FILE_NOT_FOUND | The specified key was not found in the registry database.
ERROR_KEY_DELETED | HKEY passed to service has been deleted since it was opened.
ERROR_CANTOPEN ERROR_CANTREAD | Aliases of ERROR_FILE_NOT_FOUND for 16 bit code.
ERROR_ACCESS_DENIED | Attempt to write to a key for which code does not have write access.
ERROR_OUTOFMEMORY | Insufficient memory to open the registry key or insufficient memory to load the required data from the registry file.

The following may be returned when calling the registry services incorrectly:

ERROR_BADKEY | The subkey string contains an invalid character or the handle identifying the key is invalid.
ERROR_LOCK_FAILED | Registry reentered while blocked by same process.
ERROR_INVALID_PARAMETER | Parameter is required and not specified, an invalid pointer or otherwise not valid.

The following indicate a system problem. The system contains procedures for recovering from these errors, mostly involving rebooting:

ERROR_BADDB ERROR_REGISTRY_CORRUPT | Registry data structures corrupt.
ERROR_REGISTRY_IO_FAILED | The registry file cannot be found or it was already opened by another application. A full disk or problem reading or writing to the disk may also cause this error.

When an HKEY is specified as an input parameter, it must be an HKEY returned from one of the registry services or one of the following predefined keys:

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
HKEY_CURRENT_CONFIG
HKEY_DYN_DATA

Of the predefined key values, only HKEY_LOCAL_MACHINE and HKEY_DYN_DATA are available to VxDs during initialization time. The entire registry space can only be accessed after VxD initialization is complete.

The key names are in OEM character set with some variations. Prior to completion of VxD initialization, all key names referenced must not contain any characters in the extended character set (character whose value is greater than 127). After VxD initialization, the entire character set is available.


Primary Scheduler

Windows 95 is a multiple-threaded, preemptive multitasking operating system. Each task running in the system virtual machine can consist of one or more threads of execution. A task running in a non-system virtual machine can have only one thread. The Windows 95 virtual machine manager (VMM) includes a primary scheduler that determines whether a particular thread receives processor time. This section describes the primary scheduler and its related VMM services.


Execution Priority

The primary scheduler assigns an execution priority value to a each thread. The VMM grants processor time only to threads that share the highest execution priority. A thread with an execution priority lower than the highest priority does not receive any processor time; that is, it is suspended. (Note that this should not be confused with the concept of a virtual machine being suspended.)

The VMM assigns an execution priority to a thread when the thread is created. The VMM and virtual devices can subsequently raise or lower the execution priority, causing the processor to switch from one thread to another. If the new thread belongs to a different virtual machine, the VMM performs a task switch to the new virtual machine, making it the current virtual machine. The VMM often temporarily raises the execution priority for a thread that needs to service a high-priority device event, such as an interrupt that must be serviced in a timely manner.

A virtual device can raise or lower the priority of a thread by calling the Adjust_Exec_Priority or Adjust_Thread_Exec_Priority service. Use Adjust_Thread_Exec_Priority to adjust the execution priority of a thread in the system virtual machine, and Adjust_Exec_Priority to adjust the execution priority of the thread in a non-system virtual machine. If you specify the handle of the system virtual machine in a call to Adjust_Exec_Priority, the VMM adjusts the priority of the system virtual machine's initial thread.

See Also

Adjust_Exec_Priority, Adjust_Thread_Exec_Priority


Creating and Terminating Threads

A virtual device can use the VMMCreateThread service to create a new thread in the system virtual machine. The new thread runs in protected mode at ring three. VMMCreateThread returns a handle identifying the new thread. The virtual device can use the handle in subsequent services which control the execution of the thread, such as Adjust_Thread_Exec_Priority.

Before creating the new thread, VMMCreateThread broadcasts the Create_Thread control message to all virtual devices in the system. A virtual device typically responds by allocating any structures it needs to support the thread. By setting the carry flag, a virtual device that cannot support the new thread can prevent the thread from being created.

After the new thread is created, VMMCreateThread broadcasts the Thread_Init control message to all virtual devices. This message passes the handle of the new thread to the virtual devices, and gives the devices an opportunity to perform initialization procedures that must take place in the context of the new thread.

A virtual device can use the VMMTerminateThread service to destroy a thread created by a previous call to VMMCreateThread. The VMMTerminateThread service will not destroy the initial thread of a virtual machine, nor will it destroy the currently executing thread.

Before terminating a thread, VMMTerminateThread broadcasts the Terminate_Thread control message to all virtual devices. When the thread is no longer being scheduled, the Thread_Not_Executeable control message is broadcast to all virtual devices. Finally, the Destroy_Thread control message is broadcast, signaling that it is safe for virtual devices to free resources associated with the thread.

See Also

Adjust_Thread_Exec_Priority, Create_Thread, Destroy_Thread, Terminate_Thread, Thread_Not_Executeable, VMMCreateThread, VMMTerminateThread


Controlling Virtual Machine Execution

The Close_VM and Nuke_VM services terminate the specified virtual machine. Close_VM gives all virtual devices an opportunity to clean up before the virtual machine terminates by first broadcasting the Close_VM_Notify message to all virtual devices. By comparison, Nuke_VM does not broadcast any notifications before terminating the virtual machine. A virtual device should use Nuke_VM only to terminate a virtual machine that has not terminated normally and does not respond to Close_VM.

The VMM maintains a suspend count for each non-system virtual machine. The execution of a non-system virtual machine is suspended whenever its suspend count is greater than zero. Calling Suspend_VM increments the suspend count; calling Resume_VM decrements it. (As noted previously, this sense of the word "suspend" when applied to virtual machines is different from the sense when applied to threads.)

A virtual device receives the VM_Suspend control message when Suspend_VM changes a virtual machine's suspend count from 0 to 1. It receives the VM_Resume control message when Resume_VM changes the count from 1 to 0. A virtual device can prevent the virtual machine from resuming by setting the carry flag in response to VM_Resume. A virtual device cannot prevent a virtual machine from being suspended. The No_Fail_Resume_VM service is similar to Resume_VM except that it doesn't allow a virtual device to prevent a virtual machine from resuming.

See Also

Close_VM, No_Fail_Resume_VM, Nuke_VM, Suspend_VM, Resume_VM, VM_Resume, VM_Suspend


Task and Thread Switching

A virtual device can use the Call_When_Task_Switched service to install a callback function that the VMM calls whenever the processor switches from one task to another. The callback remains in effect until it is removed by calling the Cancel_Call_When_Task_Switched service.

Similarly, a virtual device can use the Call_When_Thread_Switched service to install a callback function that the VMM calls whenever the processor switches from one thread to another. It can remove the callback function by calling the Cancel_Call_When_Thread_Switched service.

Thread-switch and task-switch callbacks are called extremely frequently and should be written for maximum speed.

See Also

Call_When_Task_Switched, Call_When_Thread_Switched, Cancel_Call_When_Task_Switched, Cancel_Call_When_Thread_Switched


Adjust_Exec_Priority

include vmm.inc

mov     eax, PriorityBoost
mov     ebx, VMHandle
VMMCall Adjust_Exec_Priority

Raises or lowers the execution priority of the specified virtual machine. The service adds the specified boost to the virtual machine's current execution priority. Uses Flags.

  • No return value.
PriorityBoost
A signed integer value representing the positive or negative priority boost for the virtual machine. This parameter must be a value such that when added to the current execution priority, the result is within the range Reserved_Low_Boost to Reserved_High_Boost. The following lists some common priority boost values, from lowest to highest:
Value | Meaning
Reserved_Low_Boost | Reserved for use by system.
Cur_Run_VM_Boost | Use to boost the priority of each virtual machine, in turn, forcing them to run for their allotted time slices.
Low_Pri_Device_Boost | Use for operations that need timely processing but are not time critical.
High_Pri_Device_Boost | Use for time-critical operations that should not circumvent the critical section boost.
Critical_Section_Boost | Use to boost the priority of the virtual machine whenever it enters a critical section (calls Begin_Critical_Section).
Time_Critical_Boost | Use for operations that require immediate processing, even when another virtual machine is in a critical section. For example, VPICD uses this when simulating hardware interrupts.
Reserved_High_Boost | Reserved for use by system.

VMHandle
Handle of the virtual machine.

Because the nonsuspended virtual machine with the highest execution priority is always the current virtual machine, this service causes a task switch under two circumstances:

  • The execution priority of the current virtual machine is lowered (EAX is negative), and there is another virtual machine with a higher priority that is not suspended.
  • The execution of a nonsuspended virtual machine which is not the current virtual machine is raised (EAX is positive) higher than the current virtual machine's execution priority.

Even if the current virtual machine is in a critical section, a task switch will still occur if the priority of another nonsuspended virtual machine is raised higher than the current virtual machine's priority. However, this will only occur when a virtual machine is given a time-critical boost, for example, to simulate a hardware interrupt.

It is often more convenient to call the Call_Priority_VM_Event service than to call this service directly.

See Also

Adjust_Thread_Exec_Priority, Begin_Critical_Section, Call_Priority_VM_Event


Adjust_Thread_Exec_Priority

include vmm.inc

mov     eax, PriorityBoost
mov     edi, ThreadHandle
VMMCall Adjust_Thread_Exec_Priority

Raises or lowers the execution priority of the specified thread. The service adds the specified boost to the thread's current execution priority. Uses Flags.

  • No return value.
PriorityBoost
A signed integer value representing the positive or negative priority boost for the thread. This parameter must be a value such that when added to the current execution priority, the result is within the range Reserved_Low_Boost to Reserved_High_Boost. The following lists some common priority boost values, from lowest to highest:
Value | Meaning
Reserved_Low_Boost | Reserved for use by system.
Cur_Run_VM_Boost | Use to boost the priority of each thread, in turn, forcing them to run for their allotted timeslices.
Low_Pri_Device_Boost | Use for operations that need timely processing but are not time critical.
High_Pri_Device_Boost | Use for time-critical operations that should not circumvent the critical section boost.
Critical_Section_Boost | Use to boost the priority of the thread whenever it enters a critical section (calls Begin_Critical_Section).
Time_Critical_Boost | Use for operations that require immediate processing, even when another thread is in a critical section. For example, VPICD uses this when simulating hardware interrupts.
Reserved_High_Boost | Reserved for use by system.

ThreadHandle
Handle of the thread.

Because the nonsuspended thread with the highest execution priority is always the current thread, this service causes a task switch under two circumstances:

  • The execution priority of the current thread is lowered (EAX is negative), and there is another thread with a higher priority that is not suspended.
  • The execution priority of a nonsuspended thread which is not the current thread is raised (EAX is positive) higher than the current thread's execution priority.

Even if the current thread is in a critical section, a task switch will still occur if the priority of another nonsuspended thread is raised higher than the current thread's priority. However, this will only occur when a thread is given a time-critical boost, for example, to simulate a hardware interrupt.

It is often more convenient to call the Call_Priority_VM_Event service than to call this service directly.

See Also

Adjust_Exec_Priority, Begin_Critical_Section, Call_Priority_VM_Event


Thread Creation and Termination

A virtual device uses the services described in this section to create and destroy threads in the system virtual machine. Also, a virtual device receives the following messages when creating or destroying threads in the system VM:

Message | Description
Create_Thread | A new thread is being created.
Destroy_Thread | A non-initial thread is about to be destroyed
Terminate_Thread | A non-initial thread is about to terminate.
Thread_Not_Executeable | A non-initial thread has stopped executing.
Thread_Init | A new thread was created.

For a description of these messages, see VMM Messages.

See Also

Create_Thread, Destroy_Thread, Terminate_Thread, Thread_Not_Executeable, Thread_Init


VMMCreateThread

VMMCall VMMCreateThread, <initial_ss, initial_esp, initial_cs,
    initial_eip, initial_ds, initial_es, ThreadType, InitCallback,
    RefData>
or      eax, eax
jz      thread_not_created

Creates a protected mode thread in the system virtual machine and starts it executing in ring 3 at the instruction specified by CS:EIP. Uses all registers and Flags.

  • Returns the handle of the new thread in EAX if successful; otherwise, returns 0 in EAX.
initial_ss, initial_esp, initial_cs, initial_eip, initial_ds, initial_es
Ring 3 protected mode registers used to start the thread.
ThreadType
Programmer-defined DWORD value a VxD can use to uniquely identify the threads that it creates. Typically, this value is a pointer to the VxD's DDB because the pointer is unique among VxDs. This value is stored in the TCB_ThreadType field of the thread's control block.
InitCallback
Ring 0 initialization function that is called after the Thread_Init message is sent.
RefData
Programmer-defined DWORD value that is passed, in EDX, to the InitCallback function.

This service is intended for use only by Windows internal system components. A virtual device should not use this service because it can cause the system to become unstable.

The client registers are initialized to the values specified by the procedure parameters. The values must be valid values for ring 3; do not use ring 0 selectors.

The Create_Thread and Thread_Init messages are sent to all virtual devices, and the timeslice scheduler is notified to start scheduling the thread.

See Also

Create_Thread, Thread_Init, VMMTerminateThread


VMMTerminateThread

include vmm.inc

mov     edi, ThreadHandle
VMMCall VMMTerminateThread

Destroys the specified thread. Uses all registers and Flags.

  • Returns only if the thread cannot be destroyed.
ThreadHandle
Handle of the thread to destroy.

This service is intended for use only by Windows internal system components. A virtual device should not use this service because it can cause the system to become unstable.

Do not use this service to terminate the initial thread of a virtual machine. Use the Close_VM service instead.


Virtual Machine Execution Control

A virtual device uses the functions described in this section to suspend, resume, and destroy virtual machines. Also, a virtual device receives the following messages when suspending, resuming, and destroying virtual machines:

Message | Description
Close_VM_Notify | A virtual machine is terminating.
VM_Resume | A virtual machine is resuming after having been suspended.
VM_Suspend | A virtual machine is being suspended.

For a description of these messages, see VMM Messages.

See Also

Close_VM_Notify, VM_Resume, VM_Suspend


_Call_On_My_Stack

include vmm.inc

VMMCall _Call_On_My_Stack, <<OFFSET32 pfnCallback>, dwLParam,
    <OFFSET32 pStack>, dwStackSize>

Temporarily switches a ring 0 stack to a different locked block of memory. A VxD can use this service to perform an operation that requires more than 4K bytes of stack space (each thread is limited to 4K bytes of ring 0 stack space.) This service switches to the new stack and then calls the given callback function with the LParam parameter pushed on the new stack. When the callback function returns, the service switches back to the original ring 0 stack, and then returns control to the caller. This service can handle nested calls. Uses the C calling convention. Uses EAX, ECX, EDX, and Flags.

  • No return value.
pfnCallback
Address of callback function. This function must be declared using the C calling convention.
dwLParam
Double-word parameter to push on the new stack before calling the callback function.
pStack
Stack pointer (value of ESP register). The stack can be as many pages as needed as long as they are all locked. Because the stack grows towards smaller addresses, this parameter should be the upper limit of the stack, not the lower limit.
dwStackSize
The size, in bytes, of the temporary stack.


Close_VM

include vmm.inc

mov     eax, TimeOut
mov     ebx, VMHandle
mov     ecx, Flags
VMMCall Close_VM

Attempts to close the virtual machine, allowing all virtual devices an opportunity to clean up before the virtual machine terminates. Uses Flags.

  • No return value.
TimeOut
Number of milliseconds the service must wait before calling the Nuke_VM service to force the virtual machine to close.
VMHandle
Handle of the virtual machine to close.
Flags
Action to take:
Value Meaning
CVF_Continue_

CVF_Continue_

CVF_Continue_

CVF_Continue_Exec

Return to the virtual machine after scheduling the closing event even if the virtual machine is being closed.

Whenever possible, a virtual device should use this service instead of the Nuke_VM or Crash_Cur_VM service.

See Also

Nuke_VM


No_Fail_Resume_VM

include vmm.inc

mov     ebx, VMHandle
VMMCall No_Fail_Resume_VM

Resumes the execution of a virtual machine previously suspended by the Suspend_VM service. Unlike the Resume_VM service, this service never returns an error. Uses Flags

  • No return value.
VMHandle
Handle of the virtual machine to resume.

This service decrements the suspend count, and places the virtual machine in the ready-processes queue if the new count is zero. The system carries out a task switch to the resumed virtual machine if the virtual machine has a higher priority than the current virtual machine.

If the virtual machine cannot be resumed for some reason, the system notifies the user of the problem and handles the error automatically, resuming the virtual machine when there is sufficient memory available.

See Also

Resume_VM, Suspend_VM


Nuke_VM

include vmm.inc

mov     ebx, VMHandle
VMMCall Nuke_VM

Closes a virtual machine that has not yet terminated normally. Uses ECX, EDX, and Flags

  • No return value. If VMHandle specifies the current or system virtual machine, this service never returns.
VMHandle
Handle of the virtual machine to destroy. If this parameter specifies the system virtual machine, a fatal error occurs and Windows terminates.

The virtual shell device typically calls this service to close a virtual machine whenever the user chooses to end the task without going through normal application shutdown procedures.

This service should be used with caution.

See Also

Close_VM


Resume_VM

include vmm.inc

mov     ebx, VMHandle
VMMCall Resume_VM
jc      not_resumed

Resumes the execution of a virtual machine previously suspended by the Suspend_VM service. Uses Flags.

  • Clears the carry flag if the suspend count is zero and the virtual machine is in the ready-processes queue; otherwise, sets the carry flag.
VMHandle
Handle of the virtual machine to resume.

This service decrements the suspend count, and places the virtual machine in the ready-processes queue if the new count is zero. The system carries out a task switch to the resumed virtual machine if the virtual machine has a higher priority than the current virtual machine.

An error can occur if a virtual device cannot lock the memory handles for the specified virtual machine. The system notifies every virtual device of the request to resume a virtual machine, and any virtual device can deny the request. In such cases, this service returns with the carry flag set and the virtual machine remains suspended with a suspend count of 1.

See Also

No_Fail_Resume_VM, Suspend_VM


Suspend_VM

include vmm.inc

mov     ebx, VMHandle
VMMCall Suspend_VM
jc      not_suspended

Suspends the execution of a specified virtual machine. This service fails if the specified virtual machine either owns the critical section, or is the system virtual machine. Uses Flags.

  • Clears the carry flag if the virtual machine is suspended; otherwise, sets the carry flag.
VMHandle
Handle of the virtual machine to suspend.

An error occurs if the virtual machine is in a critical section, or if the VMHandle parameter specifies the system virtual machine.

This service increments the suspend count for the virtual machine. If the virtual machine was not already suspended, the system notifies virtual devices of the suspension by sending a VM_Suspend message to the control procedure for each virtual device. A virtual device must not refuse to suspend a virtual machine. If a virtual machine remains suspended, subsequent calls to Suspend_VM do not cause the VM_Suspend notification.

When a virtual machine is suspended, the system sets the VMStat_Suspended bit in the CB_VM_Status field of the virtual machine's control block. Although virtual devices may examine and modify the contents of the control block of a virtual machine, the virtual devices must not examine or modify any memory owned by a suspended virtual machine unless the virtual device previously locked that memory.

Note that the actual suspension of a virtual machine may be delayed for various reasons. When the suspension is delayed, the service returns success, but the actual suspension does not take effect until later.

See Also

No_Fail_Resume_VM, Resume_VM, VM_Suspend


Task and Thread Switching

A virtual device uses the following services and callback functions to receive notifications and perform operations when the processor switches to a different thread or task.


Call_When_Task_Switched

include vmm.inc

mov     esi, OFFSET32 TaskSwitchCallback
VMMCall Call_When_Task_Switched

Installs a task-switched callback function which the system calls whenever it carries out a task switch. This service should be used sparingly, and the callback function should be optimized for speed.

  • No return value.
TaskSwitchCallback
Address of the callback function to install. For more information about the callback function, see TaskSwitchCallback.

Some virtual devices must save the state of a hardware device every time a task switch occurs and restore the hardware state for the virtual machine that is about to be run. However, virtual machine events can often be used in place of using this service.

Virtual devices can install any number of callback functions. The system calls each one in the order installed, until all functions have been called.

See Also

Call_When_Idle, Call_When_Not_Critical, Call_When_Thread_Switched, Cancel_Call_When_Task_Switched, TaskSwitchCallback


Call_When_Thread_Switched

include vmm.inc

mov     esi, OFFSET32 ThreadSwitchCallback
VMMCall Call_When_Thread_Switched

Installs a callback function which the system calls whenever it switches to a different thread or task. This service should be used sparingly, and the callback function should be optimized for speed. Uses Flags.

  • No return value.
ThreadSwitchCallback
Address of the callback function to install. For more information about the callback function, see ThreadSwitchCallback.

Virtual devices can install any number of callback functions. The system calls each one in the order installed, until all functions have been called.

See Also

Call_When_Idle, Call_When_Not_Critical, Call_When_Task_Switched, Cancel_Call_When_Thread_Switched, ThreadSwitchCallback


Cancel_Call_When_Task_Switched

mov     esi, OFFSET32 TaskSwitchCallback
VMMCall Cancel_Call_When_Task_Switched
jc      not_removed

Removes a callback function installed by a previous call to Call_When_Task_Switched. Uses Flags.

  • Clears the carry flag if the function is removed; otherwise, sets the carry flag.
TaskSwitchCallback
Address of callback function to remove.

See also Call_When_Task_Switched


Cancel_Call_When_Thread_Switched

mov     esi, OFFSET32 ThreadSwitchCallback
VMMCall Cancel_Call_When_Thread_Switched
jc      not_removed

Removes a callback function installed by a previous call to Call_When_Thread_Switched. Uses Flags.

  • Clears the carry flag if the function is removed; otherwise, sets the carry flag.
ThreadSwitchCallback
Address of callback function to remove.

See Also

Call_When_Thread_Switched


TaskSwitchCallback

mov     eax, OldVMHandle
mov     ebx, CurVMHandle
call    [TaskSwitchCallback]

Performs programmer-defined processing whenever a task switch occurs. TaskSwitchCallback is a programmer-defined callback function installed by the Call_When_Task_Switched service. Uses Flags.

  • No return value.
OldVMHandle
Handle of the previous virtual machine.
CurVMHandle
Handle of the current virtual machine.

The callback function can carry out any operation and can modify the EAX, EBX, ECX, EDX, ESI, EDI, and Flags registers.

See Also

Call_When_Task_Switched


ThreadSwitchCallback

mov     eax, OldThreadHandle
mov     edi, CurThreadHandle
call    [ThreadSwitchCallback]

Performs programmer-defined processing whenever the system switches to a different thread. ThreadSwitchCallback is a programmer-defined callback function installed by the Call_When_Thread_Switched service. Uses Flags.

  • No return value.
OldThreadHandle
Handle of the previous thread.
CurThreadHandle
Handle of the current thread.

The callback function can carry out any operation and can modify the EAX, EBX, ECX, EDX, ESI, EDI, and Flags registers.

See Also

Call_When_Thread_Switched


Thread Information

A virtual device uses the following services to retrieve thread information.


_GetLastUpdatedThreadExecTime

See _GetLastUpdatedThreadExecTime in Timing Services.


_GetThreadExecTime

See also _GetThreadExecTime in Timing Services.


_GetThreadTerminationStatus

include vmm.inc

VMMCall _GetThreadTerminationStatus, <ThreadHandle>
mov     StatusFlags, eax

Retrieves the termination status of the specified thread. Uses C calling convention. Uses EAX, ECX, EDX, and Flags.

  • Returns a combination of these values in EAX:
THREAD_TERM_STATUS_CRASH_PEND | The virtual machine associated with the thread is terminating because a catastrophic error occurred.
THREAD_TERM_STATUS_NUKE_PEND | The thread is in a must-complete section. The associated virtual machine will be closed when it reaches the end of the section.
THREAD_TERM_STATUS_SUSPEND | The thread is in a must-complete section. The associated virtual machine will be suspended when it reaches the end of the section.

If the return value is 0, the thread is not in a must-complete section and the virtual machine is not about to be suspended or closed.

ThreadHandle
Handle of the thread.


Get_Cur_Thread_Handle

include vmm.inc

VMMCall Get_Cur_Thread_Handle
mov     [hThread], edi

Returns a handle identifying the currently executing thread. Uses EDI and Flags.

  • Returns a handle in EDI that identifies the currently executing thread.

This service can be called at interrupt time.


Get_Initial_Thread_Handle

include vmm.inc

mov     ebx, [VMHandle]
VMMCall Get_Initial_Thread_Handle
mov     [hThread], edi

Returns a handle identifying a thread that was created at the same time that the virtual machine was created. Uses EDI and Flags.

  • Returns a handle in EDI that identifies the VM's initial thread.
VMHandle
Identifies the virtual machine for which the thread was created.

This service can be called at interrupt time.


Get_Next_Thread_Handle

include vmm.inc

VMMCall Get_Next_Thread_Handle
mov     [hThread], edi

Retrieves the handle of the next thread in the current virtual machine. If the current thread is the last thread, the service retrieves the handle off the first thread in the next virtual machine. Uses EDI and Flags.

  • Returns a handle in EDI that identifies the next thread.

This service can be called at interrupt time.


Get_Sys_Thread_Handle

include vmm.inc

VMMCall Get_Sys_Thread_Handle
mov     [hSysThread], EDI

Returns a handle identifying the system thread. Uses EDI and Flags.

  • Returns a handle identifying the system thread in EDI.

This service can be called at interrupt time.


Get_Thread_Win32_Pri

include vmm.inc

mov edi, ThreadHandle
VMMCall Get_Thread_Win32_Pri

mov [BasePriority], eax
mov [CurrentPriority], ecx
mov [TimeDecayBoost], edx
mov [InversionPriority], esi

Retrieves the Win32 priority of the specified thread. Uses EAX, ECX, EDX, ESI, Flags.

  • If successful, the EAX, ECX, and EDX registers contain the following:
EAX | absolute Win32 base priority (0-31)
ECX | absolute Win32 current priority (0-31)
EDX | time decay boost if any
ESI | inversion priority if any

ThreadHandle
Handle to the thread to retrieve the priority for.


Thread Data Slots

A virtual device uses the following services to allocate and free thread data slots.


_AllocateThreadDataSlot

include vmm.inc

VMMCall _AllocateThreadDataSlot
cmp eax, 0
je  error
mov [DataSlotOffset], eax

Allocates a thread data slot. Uses C calling conventions.

  • Returns an offset to the data slot, if the service succeeds; otherwise, returns zero.

A thread data slot is a DWORD value associated with each thread. The thread data slot offset gives the location of the thread data slot that you allocated, relative to the thread handle. Essentially, _AllocateThreadDataSlot works for threads just like _Alloc_VM_CB_Area works for virtual machines, except that the size of the memory block is always four bytes for thread data slots, whereas it is user-defined for virtual machine control blocks.

Note that thread data slots are not zero-initialized. If this is important, you should zero-initialize the thread data slot yourself.

Since thread data slots are only four bytes, if you need to record more than four bytes of data on a per-thread basis, the traditional mechanism is to store a pointer to a data block in the thread data slot. Don't forget to free the data block when the thread is destroyed, or you will leak memory.

Thread data slots are scarce resources. They should be freed when no longer needed.


_FreeThreadDataSlot

include vmm.inc

VMMCall _FreeThreadDataSlot, <DataSlotOffset>

Frees a thread data slot. Uses C calling conventions.

  • No return value.
DataSlotOffset
A valid data slot offset that was previously allocated by _AllocateThreadDataSlot.

See Also

_AllocateThreadDataSlot


Thread Debugging and Testing

A virtual device uses the following services to debug threads and to test the validity of thread handles.


Debug_Test_Cur_Thread

include vmm.inc

mov     edi, [hThread]
VMMCall Debug_Test_Cur_Thread

Determines whether hThread identifies the current thread. If it is not, the service sends an error message to the debugger before returning. This service is valid only with the debugging kernel. Preserves all registers and flags.

  • No return value.
hThread
Handle of the thread to test.

This service is typically not called directly. Virtual devices use the Assert_Cur_Thread_Handle macro instead.


Debug_Test_Valid_Thread_Handle

include vmm.inc

mov     edi, [hThread]
VMMCall Debug_Test_Valid_Thread_Handle

Determines whether hThread is a valid thread handle. If it is not, the service sends an error message to the debugger before returning. This service is valid only with the debugging kernel. Uses no registers; the Flags register is preserved.

  • No return value.
hThread
Handle of the thread to validate.

This service is typically not called directly. Virtual devices use the Assert_Cur_Thread_Handle macro instead.


Test_Cur_Thread_Handle

include vmm.inc

mov     edi, [hThread]
VMMCall Test_Cur_Thread_Handle
je      Is_Current_Thread

Tests hThread to determine whether or not it identifies the currently executing thread. Uses Flags.

  • Sets the zero flag if hThread identifies the currently executing thread.
hThread
Handle of the thread to test.


Test_Initial_Thread_Handle

include vmm.inc

mov     edi, [hThread]
VMMCall Test_Initial_Thread_Handle
je      Is_Initial_Thread

Determines if the thread identified by hThread was the initial thread for a VM. Uses Flags.

  • Sets the carry flag if hThread identifies the initial thread for the VM.
hThread
Handle of the thread to test.

This service can be called at interrupt time.


Test_Sys_Thread_Handle

include vmm.inc

mov     edi, hThread
VMMCall Test_Sys_Thread_Handle
je      Is_System_Thread

Determines whether the thread identified by hThread is the system thread. Uses Flags.

  • Sets the zero flag if the thread identified by hThread is the system thread.
hThread
Handle of the thread to test. This must be a valid thread handle.

This service can be called at interrupt time.


Validate_Thread_Handle

include vmm.inc

mov     edi, [hThread]
VMMCall Validate_Thread_Handle
jc      Invalid_Handle

Tests validity of thread identified by hThread. Uses Flags.

  • The carry flag is not set if the thread is valid; otherwise it is set.
hThread
Handle of thread being tested.

This service can be called at interrupt time.


Time-Slice Scheduler

The virtual machine manager (VMM) includes a time-slice scheduler that determines how much processor time to grant to virtual machines. This section describes the time-slice scheduler.


Terms

The following terms are related to the time-slice scheduler:

Term | Definition
background priority | The time-slice priority of a virtual machine that does not have the execution focus.
background virtual machine | A virtual machine that does not have the execution focus.
base priority | The unboosted time-slice priority of a thread. A thread's base priority depends on its priority class.
block | The temporary halting of the execution of a thread or virtual machine while it waits for a needed resource to be freed.
boost | An increase or decrease in the time-slice priority of a thread.
dynamic boost | An temporary increase or decrease in the time-slice priority of a thread, brought about by either the VMM or a virtual device.
exclusive execution | The execution of a virtual machine to the exclusion of all other non-system virtual machines. When a virtual machine has the execution focus and is executing exclusively, the VMM suspends all other non-system virtual machines. The VMM never suspends the system virtual machine.
execution focus | A property of the virtual machine with which the user is currently working. The virtual machine with the execution focus runs in the foreground and its priority is boosted.
foreground priority | The time-slice priority assigned to a virtual machine that has the execution focus.
foreground virtual machine | The virtual machine that has the execution focus.
high priority class | A group of time-slice priority values associated with high priority threads.
idle | The state of a thread or virtual machine that is runnable but needs input before continuing.
idle priority class | A group of time-slice priority values associated with idle threads.
idle thread | A thread that runs only when there are no higher priority threads to run.
initial thread | The first thread created in a virtual machine. The system virtual machine can have many thread, non-system virtual machines have only one thread.
inversion boost | An increase in the time-slice priority of a thread that owns a resource so that the priority matches that of the highest-priority thread that blocks on the resource.
inversion priority | In priority inversion prevention, the time-slice priority to which the owner thread is raised. Also see priority inversion prevention.
normal priority class | A group of time-slice priority values associated with threads that are not idle, high priority, or real time.
priority class | A group of priority values associated with threads of a particular type. Also see idle priority class, normal priority class, high priority class, and real-time priority class.
priority inversion list | A list, maintained internally by the VMM, that contains information used to raise the priority of threads that own resources on which other threads block. Also see priority inversion prevention.
priority inversion prevention | A technique the VMM uses to prevent a form of deadlock in which a low priority thread that owns a resource is unable to run because of its low priority, and a higher priority thread that also needs the resource remains blocked while waiting for the resource to be freed.
real-time priority class | A group of priority values associated with threads that perform time-critical tasks.
round robin | The sequential, cyclical allocation of processor time to all threads of the same priority.
schedule | Allocating processor time to a virtual machine or thread.
static boost | Raising or lowering a thread's time-slice priority with no time decay.
suspend | To halt a process temporarily.
system idle priority | A priority of 0, which is reserved for system use.
system thread | The first thread created in the system virtual machine.
thread | The basic entity to which the VMM allocates processor time. A thread can execute any part of the application's code, including a part currently being executed by another thread. All threads of a process share the virtual address space, global variables, and operating system resources of the process.
thread group | Two or more threads whose priorities are boosted at the same time.
thread starvation | A situation in which a thread does not receive adequate processor time because its time-slice priority is too low.
time-slice | A brief period of time during which a thread receives control of the processor.
time-slice execution flags | A set of flags, defined in the VMM include files, that can be set in the control block of a virtual machine or thread and control aspects of how the thread is scheduled.
time-slice granularity | The duration of a time-slice.
time-slice list | A list of the threads that the VMM is currently scheduling.
time-slice priority | A number associated with a thread and used by the VMM to determine the amount of processor time to grant to the thread.
time-slice quantum | The average duration of all time slices.
time-decayed boost | Raising or lowering of a thread's time-slice priority, followed by a return to the base priority over several subsequent time slices.


Priority Model

The time-slice scheduler controls the amount of processor time each virtual machine and application thread receives by setting priorities for them. This section describes priorities and how the time slicer assigns them.


Priorities and Priority Classes

Threads, including separate virtual machine and application threads, have 32 possible priorities, which are divided into four priority classes: idle, normal, high, and real time. Furthermore, the normal priority class is divided into foreground and background subclasses. The following table shows how priorities are divided into classes:

Class | Priorities
Idle | 1-6, 15 (15 if the base-relative real-time thread priority is specified)
Normal |
Background | 1 or 5-9, 15 (1 if the base-relative idle thread priority is specified)
Foreground | 1 or 7-11 or 15
High | 1 or 11-15
Real time | 16-31

Priority 0 is reserved for system use as the system idle priority. Classifying priorities helps to define dynamically variable priority ranges and establishes application guidelines to prevent monopolizing the system with simple set-priority system calls.


Preemption

All 32 priorities are preemptive of priorities lower than themselves. This means that a runnable thread of one priority preempts all lower priority threads. Threads that are running at the same priority are scheduled in a round robin fashion.


Time-Slice Quanta

All time slices are for a statistically constant period of time, called the time-slice quantum. This means that, although two time slices may have different periods, the average period of any large time slice sample remains constant.


Dynamic Priority Boosting and Timed Decay

A thread with a priority that is lower than the real-time priority class can have its priority dynamically boosted to respond more quickly to system events or to enhance overall system throughput. For example, a thread that is just becoming unblocked receives a boost in priority so that, among other threads with the same priority, it will be chosen to execute next. A dynamically boosted thread automatically loses a specified amount of boost for every time slice that it executes. This is called timed decayed boosting, and is used whenever dynamic priority boosting is indicated. Also, when the system detects that a boosted thread no longer needs its boost, the system may return the thread to its original base priority.


Thread Starvation

If a thread's priority remains low for too long, it can be starved for processor time. The time slicer includes an algorithm that prevents thread starvation by temporarily boosting threads that have not been scheduled within a reasonable amount of time. Reasonable is defined as a number of milliseconds calculated by multiplying the size of the time-slice quantum by the number of executable threads, then multiplying the result by an internal threshold value.

The system cannot dynamically change the priority of a thread that belongs to the real-time priority class. Real-time threads are excluded from the thread starvation algorithm; moreover, real-time threads can starve threads of other priority classes in spite of the starvation algorithm.

An idle thread is one that runs only when there are no higher priority threads to run. All priorities in the idle priority class except the system reserved 0 priority are included in the thread starvation algorithm.

Idle, normal, and high priority class threads are normally not starved. Within these priority classes, the system dynamically boosts the priorities of starving threads using time decayed boost functions. During every starvation detection interval (which varies depending on the number of runnable threads) the system recalculates the dynamic priorities of all idle, normal, and high priority threads based on the recent processor usage. When the system finds a thread that has not run for an extended period, the system gives it a timed decayed boost to the highest priority possible for threads of the normal priority class. By adjusting both the period of time between checks and the acceptable starvation level of threads, the system prevents starvation while efficiently setting the priorities of threads.


Blocking and Unblocking

Usually, when a thread attempts to get access to a resource which is unavailable, such as a semaphore, mutex, critical section, or synchronization object, the thread stops running while waiting for the resource to become available. This is called blocking. Unless a thread happens to block at exactly the time its time-slice quantum has expired, blocking prevents the thread from completing a full time slice. When the resource waited on becomes available, the blocked thread is unblocked and runs the next time it is scheduled.


Unblock Boosting

If, before completing a time slice, a thread blocks and unblocks but is left at the same priority, it will effectively have its time slice reduced to the time it uses between the unblock and block operations. This is because the scheduler does not have any reason to schedule the newly unblocked thread before any other threads running at the same priority. This gives threads that do not need to block on resources a great advantage when competing for processor time.

To allow threads which block and unblock to compete effectively for processor time, the time slicer dynamically boosts the priority of a thread when it blocks.


Monopolization of Processor by Blocking

A system that boosts priorities when threads block can have problems with threads that monopolize the system by blocking and unblocking very quickly. Without checks in place to prevent this, a thread could block and unblock so quickly that it essentially maintains the priority of its boosted state.

To prevent this kind of monopolization, the elapsed time since a thread was scheduled to run is totaled whenever the thread blocks. When the total reaches or exceeds the quantum period, the total is reset and the thread is blocked with an unboosted priority. Effectively, the thread is back in the runnable queue at its base priority.


Priority Inversion Boosting

A synchronization problem that can occur in a system with preemptive priorities is that threads that own system resources may not be able to run when other, higher priority threads are executing. This can cause a situation in which a thread remains blocked on a resource owned by a thread that is unable to run. If threads at a higher priority than the resource owning thread do not block, the resource may never be freed. To prevent this problem, the system uses a technique called priority inversion prevention in which the system boosts the priority of the thread that owns a resource to at least the priority of any thread that blocks on the resource.

The Windows 95 time slicer's algorithm for priority-inversion-prevention is associative. This means that, once a priority inversion boost is in place, the boosted thread maintains the same priority as the boosting thread.

When threads are suspended by events not related to blocking on resources, they will simply lose their current time slice, and will not be block boosted.


Compatibility with the Primary Scheduler

For simplicity, and to remain compatible with the primary scheduler, threads boosted by the primary scheduler are beyond the time slicer's control. When threads or virtual machines are boosted by virtual devices, the time slicer does not track this boosting and will consider them to be boosted to the real time priority. The time slicer continues to request the primary scheduler to schedule the next available thread at the same priority as the currently executing thread whenever a quantum expires. This allows time slicing to continue in a round robin fashion between boosted threads, but prevents the time slicer and primary scheduler from "fighting."


Execution Focus Services

The following Execution Focus services are described.


Get_Execution_Focus

include vmm.inc

VMMCall Get_Execution_Focus
mov     [Focus], ebx

Retrieves the handle of the virtual machine that currently has the execution focus. This virtual machine is called the foreground virtual machine. This is an asynchronous service. Uses EBX and Flags.

  • Returns the handle in EBX.

See Also

Set_Execution_Focus


Set_Execution_Focus

include vmm.inc

mov     ebx, VMHandle
VMMCall Set_Execution_Focus
jc      focus_not_set

Assigns the execution focus to the specified virtual machine. Uses Flags.

  • Clears the carry flag if the execution focus is assigned; otherwise, sets the carry flag.
VMHandle
Handle of the virtual machine to receive the execution focus.

When a virtual machine receives the execution focus, the system suspends all other virtual machines except the system virtual machine and background virtual machines.

Only the system virtual machine can assign the execution focus to other virtual machines; a non-system virtual machine can only assign the execution focus to itself.

See Also

Get_Execution_Focus


Virtual Machine Execution Control Services

The following topics describe the services provided.


Call_When_Idle

include vmm.inc

mov     esi, OFFSET32 IdleCallback
VMMCall Call_When_Idle
jc      error

Installs a system-idle callback function. The system calls this function whenever the Windows kernel signals that Windows is idle and all other virtual machines are also idle. Virtual devices typically use this service to perform background operations. For example, the memory manager uses this service to asynchronously write dirty pages to the backing store. Uses Flags.

  • Clears the carry flag is clear if the callback function is installed. Otherwise, sets the carry flag.
IdleCallback
Address of the callback function to install. For more information about the callback function, see IdleCallback.

Virtual devices can install any number of idle callback functions. The system calls each one, in the order installed, until one of the functions clears the carry flag. A system-idle callback function remains installed until it is explicitly removed by the Cancel_Call_When_Idle service.

See Also

IdleCallback


Cancel_Call_When_Idle

include vmm.inc

mov     esi, OFFSET32 IdleCallback
VMMCall Cancel_Call_When_Idle
jc      not_removed

Removes a callback function installed by a previous call to Call_When_Idle. Uses Flags.

  • Clears the carry flag if the function is removed; otherwise, sets the carry flag.
IdleCallback
Address of callback function to remove.

See Also

Call_When_Idle


IdleCallback

include vmm.inc

mov     ebx, SysVMhandle
mov     edi, SysThreadHandle
mov     ebp, OFFSET32 Client_Reg_Struc
call    [IdleCallback]
jc      pass_to_next

Performs programmer-defined processing whenever the Windows kernel signals that Windows is idle and all other virtual machines are also idle. IdleCallback is a programmer-defined callback function installed by the Call_When_Idle service.

  • Sets the carry flag to pass the call to the next idle callback function; clears the carry flag to prevent the call from being passed.
SysVMHandle
Handle of the system virtual machine.
SysThreadHandle
Handle of the system thread.
Client_Reg_Struc
Address of a Client_Reg_Struc structure that contains the registers of the system virtual machine.

The callback function can carry out any operation and can modify EAX, EBX, ECX, EDX, ESI, EDI, and Flags. If the operation takes a significant amount of time, the function should clear the carry flag before returning to prevent other callbacks from being called. Otherwise, the function should set the carry flag and return.

See Also

Call_When_Not_Critical, Call_When_Task_Switched


Release_Time_Slice

include vmm.inc

VMMCall Release_Time_Slice

In the system thread, this service idles the thread until the Wake_Up_VM service is called on behalf of the thread. In other threads in the system virtual machine, this service releases the current time slice if there is another thread of equal or greater priority ready to run. In non-system virtual machines, this service idles the thread. Uses Flags.

  • No return value.

The semantics of this service differ from Windows 3.1 because the two systems have different time slicing algorithms.

See Also

Wake_Up_VM


Time_Slice_Sleep

include vmm.inc

mov eax, Timeout
VMMCall Time_Slice_Sleep

Makes the current thread idle for a specified number of milliseconds. The thread can be woken if either Wake_Up_VM is called on the thread's VM or the specified number of milliseconds elapses. Uses Flags.

  • Clears the zero flag if the sleep timed out. Sets the zero flag if the sleep was woken up prematurely.
TimeOut
Signed timeout in milliseconds to use.

This service should not be used as a timeout function. The timeout passed in is treated as the maximum time the thread will sleep, but it may wake up earlier. This function will return when either someone calls Wake_Up_VM on this VM or when this timeout or the previous timeout set for this VM expires. A timeout of 0 will yield.

A VxD should avoid calling this service while owning the critical section; doing so makes the system appear to hang for the TimeOut duration.


Time_Slice_Wake_Sys_VM

include vmm.inc

VMMCall Time_Slice_Wake_Sys_VM

Wakes up the system VM from an idle state. Similar to Wake_Up_VM except that Wake_Up_VM will not cause the system thread to return to ring 3 and try scheduling 16-bit applications again. Returns after completely waking the system thread and VM interrupts are on. This service should be called only by the Vwin32 device. Uses Flags.

  • No return value.

See Also

Wake_Up_VM


Wake_Up_Thread

include vmm.inc

mov     ThreadHandle
VMMCall Wake_Up_Thread

Awakens an idle thread. For the system thread, this service sets the base Win32 priority back to what it was before the thread went idle. For all other threads, the service simply removes any negative decay boost. "Use Flags."

  • No return value.
ThreadHandle
Handle of thread to awaken.


Wake_Up_VM

include vmm.inc

mov     ebx, VM
VMMCall Wake_Up_VM

Restores an idle virtual machine, allowing the system to schedule the virtual machine for subsequent time slices. A virtual machine is idle if it has called the Release_Time_Slice service, or has set the VMStat_Idle flag in the CB_VM_Status field of its control block. Uses Flags.

  • No return value.
VMHandle
Handle of the virtual machine to restore.

If the specified virtual machine is not idle, this service returns immediately (does nothing). Do not attempt to make a thread idle by merely setting the VMStat_Idle bit in the CB_VM_Status field. Use the Release_Time_Slice or Time_Slice_Sleep service to make a thread idle.

See Also

Release_Time_Slice


Time-Slice Priority Services

The following topics describe the services provided.


Boost_With_Decay

include vmm.inc

mov     edi, ThreadHandle
mov     eax, BoostAmount
mov     ecx, DecayAmount
VMMCall Boost_With_Decay

Boosts a thread's time-slice priority for one time slice, then adjusts the boost by the specified decay amount for subsequent time slices until the thread's original base priority is reached. Uses Flags.

  • No return value.
ThreadHandle
Handle of the thread to boost.
BoostAmount
A signed integer value representing the number of milliseconds to lengthen or shorten the time slice.
DecayAmount
A signed integer value representing the number of milliseconds to lengthen or shorten each subsequent time slice. A positive value shortens subsequent time slices; a negative value lengthens them.

The BoostAmount and DecayAmount values must be either both positive or both negative.


Get_Thread_Win32_Pri

See Get_Thread_Win32_Pri in Primary Scheduler.


Get_Time_Slice_Priority

include vmm.inc

mov     ebx, VMHandle
VMMCall Get_Time_Slice_Priority
mov     [Flags], eax
mov     [Foreground], ecx
mov     [Background], edx
mov     [CPUTime], esi

Retrieves the time-slice execution flags for the specified virtual machine. Also, for backward compatibility, this service also retrieves values for certain obsolete parameters. Uses EAX, ECX, EDX, ESI, and Flags.

  • • Returns values in these registers:
EAX One of the following time-slice execution flags:

VMStat_Exclusive | Virtual machine is executing to the exclusion of all other threads
VMStat_Background | Virtual machine is executing in the background
VMStat_High_Pri_Back | Virtual machine is executing in the background, but with a boost in time-slice priority

ECX | Set to 10,000 if the virtual machine is time-critical and has almost exclusive execution priority; otherwise, ECX is set to 100. In previous versions of Windows, this value indicates the foreground time-slice priority.
EDX | Obsolete. The low-order word is always 50, and the high-order word is always zero. In previous versions of Windows, this value indicates the background time-slice priority.
ESI | Obsolete. Always specifies 100. In previous versions of Windows, this value indicates the percentage of processor usage.

VMHandle
Handle of the virtual machine for which to retrieve information.

See Also

Get_Time_Slice_Granularity, Set_Time_Slice_Priority


Set_Thread_Static_Boost

include vmm.inc

mov     edi, ThreadHandle
mov     eax, BoostAmount
VMMCall Set_Thread_Static_Boost

Boosts a thread's time-slice priority by the specified amount with no time decay. Uses Flags.

  • No return value.
ThreadHandle
Handle of the thread to boost.
BoostAmount
A signed integer value representing the number of milliseconds to lengthen or shorten the time slice.

See Also

Set_VM_Static_Boost


Set_Thread_Win32_Pri

include vmm.inc

mov     edi, ThreadHandle
mov     eax, Priority
VMMCall Set_Thread_Win32_Pri
jc      priority_not_set

Sets the base Win32 priority of the given thread, removing any timed decay boost associated with the thread. Uses EAX, ECX, EDX, and Flags.

  • Clears the carry flag if the priority is set; otherwise, sets it.
ThreadHandle
Handle of the thread.
Priority
Absolute Win32 base priority. This must be a value from 0 to 31.

See Also

Get_Thread_Win32_Pri


Set_Time_Slice_Priority

include vmm.inc

mov     eax, Flags
mov     ebx, VMHandle
mov     ecx, Foreground
mov     edx, Background
VMMCall Set_Time_Slice_Priority

Sets the time-slice execution flags and the foreground and background priorities for the specified virtual machine. Uses EAX and Flags.

  • Clears the carry flag if the time-slice priority is set; otherwise, sets the carry flag.
Flags
One of the following status flags:
VMStat_Exclusive | Virtual machine is executing to the exclusion of all other threads
VMStat_Background | Virtual machine is executing in the background
VMStat_High_Pri_Back | Virtual machine is executing in the background, but with a boost in time-slice priority

VMHandle
Handle of the virtual machine to change.
Foreground
Foreground time-slice priority. The high word must be 0.
Background
Background time-slice priority. The high word must be 0.

To change the time-slice priority, a virtual machine should retrieve the current time-slice priority using the Get_Time_Slice_Priority service, modify the returned values, and use the modified values as input parameters to this service. The following example assigns a virtual machine to the background:

mov     ebx, [VMHandle]
VMMCall Get_Time_Slice_Priority
or      eax, VMStat_Background
VMMCall Set_Time_Slice_Priority

See Also

Get_Time_Slice_Priority, Set_Time_Slice_Granularity


Set_VM_Static_Boost

include vmm.inc

mov     ebx, VMHandle
mov     eax, BoostAmount
VMMCall Set_VM_Static_Boost

Boosts a virtual machine's time-slice priority by the specified amount with no time decay. If VMHandle identifies the system virtual machine, the service boosts all threads in the virtual machine by the specified amount. Uses Flags.

  • No return value.
VMHandle
Handle of the virtual machine to boost.
BoostAmount
A signed integer value representing the number of milliseconds to lengthen or shorten the time slice.

See Also

Set_Thread_Static_Boost


Time-Slice Period Services

The following topics describe the services provided.


Adjust_Execution_Time

include vmm.inc

mov     eax, Time
mov     ebx, VMHandle
VMMCall Adjust_Execution_Time

Adjusts the duration of a virtual machine's time slice. Virtual devices, such as the virtual COM device, use this service to temporarily increase the amount of time a virtual machine is allowed to execute, such as when the virtual machine is receiving an unusually high number of interrupts. Uses Flags.

  • No return value.
Time
A signed integer value representing the number of milliseconds to lengthen or shorten the time slice.
VMHandle
Handle of the virtual machine to adjust.

This service adjusts the time slice regardless of the virtual machine's time-slice priority.

If the specified virtual machine is not on the time-slice list, this service returns immediately (does nothing). This service can not force a non-runnable virtual machine to execute. That is, a virtual machine that does not have the VMStat_Background flag set cannot be forced to run in the background by increasing the duration of its time slice.

This service can lengthen or shorten the time slice for a virtual machine. However, shortening the time slice is not recommended because it defeats the purpose of multitasking.

Use this service with caution — it can cause other processes to be starved for processor time.

See Also

Get_Time_Slice_Granularity, Set_Time_Slice_Granularity


Get_Time_Slice_Info

include vmm.inc

VMMCall Get_Time_Slice_Info
mov     [Scheduled], eax
mov     [Current], ebx
mov     [Idle], ecx

Retrieves the number of virtual machines currently scheduled by the time slicer, and the number of virtual machines that are idle. This service can be called at interrupt time. Uses EAX, EBX, ECX, and Flags.

  • Returns values in these registers:
EAX | Number of virtual machines scheduled
EBX | Handle of the currently scheduled virtual machine
ECX | Number of scheduled virtual machines currently idle

See Also

Get_Time_Slice_Granularity


Time-Slice Granularity Services

The following topics describe the services provided.


Get_Time_Slice_Granularity

include vmm.inc

VMMCall Get_Time_Slice_Granularity
mov     [Granularity], eax

Retrieves the current time-slice granularity. This value specifies the minimum number of milliseconds a virtual machine runs before being rescheduled. Uses EAX and Flags.

  • Returns the granularity value in EAX.

See Also

Set_Time_Slice_Granularity


Set_Time_Slice_Granularity

include vmm.inc

mov     eax, Time
VMMCall Set_Time_Slice_Granularity

Sets the minimum time-slice granularity, the minimum number of milliseconds a virtual machine can run before being rescheduled. Uses Flags.

  • No return value.
Time
Minimum time-slice granularity, in milliseconds.

Small time-slice granularity values make multitasking appear smoother, but require high

numbers of task switches and increase execution overhead. Large values allow more time for the virtual machines to execute, but may make execution look intermittent to the user.

The limit for the maximum time-slice granularity is 250 milliseconds.

See Also

Get_Time_Slice_Granularity


Thread Groups

The following topics describe the thread groups.


Attach_Thread_To_Group

include vmm.inc

mov     eax, ThreadInGroup
mov     edi, ThreadToAdd
VMMCall Attach_Thread_To_Group

Adds a thread to a thread group. A virtual device creates thread groups so that it can boost the priority of all the threads in the group with a single call to the Set_Group_Static_Boost service. Uses Flags.

  • No return value.
ThreadInGroup
Handle of a thread that belongs to a group.
ThreadToAdd
Handle of a thread to add to the group to which ThreadInGroup belongs.

If ThreadToAdd already belongs to a group, it is removed from the current group before being added to the new group.

See Also

Detach_Thread_From_Group, Set_Group_Static_Boost


Detach_Thread_From_Group

include vmm.inc

mov     ThreadHandle
VMMCall Detach_Thread_From_Group

Removes a thread from any thread group to which may belong. Uses Flags.

  • No return value.
ThreadHandle
Handle of thread to remove from any thread group.

See Also

Attach_Thread_To_Group


Set_Group_Static_Boost

include vmm.inc

mov     edi, ThreadHandle
mov     eax, BoostAmount
VMMCall Set_Group_Static_Boost

Boosts the time-slice priorities of all thread in a thread group by the specified amount with no time decay. Uses Flags.

  • No return value.
ThreadHandle
Handle of a thread in a thread group.
BoostAmount
A signed integer value representing the number of milliseconds to lengthen or shorten the time slice.

See Also

Attach_Thread_To_Group


Priority Inversion Services

The following topics describe the services provided.


Release_Inversion_Pri

include vmm.inc

mov     eax, BoostHandle
VMMCall Release_Inversion_Pri
jc      not_released

Removes the given thread from the priority inversion list, deallocates the memory associated with the list entry, and invalidates the handle to the list entry. Uses Flags.

  • Clears the carry flag if successful; otherwise sets it.
BoostHandle
Handle of an entry in the priority inversion list.

After removing the thread from the list, the service sets the new time-slice priority as follows:

priority = MAX((all inversion priorities), (Win32BasePri + TimeDecayBoost))

See Also

Release_Inversion_Pri_ID, Reset_Inversion_Pri


Release_Inversion_Pri_ID

include vmm.inc

mov     eax, ID
mov     edi, ThreadHandle
VMMCall Release_Inversion_Pri_ID

Removes all entries from the priority inversion list that have the specified identifier and that were added by the given thread. The entries were added by a previous call to the Set_Inversion_Pri service. Uses EAX and Flags.

  • Returns the number of entries removed in EAX.
ID
Identifier of entries to remove.
ThreadHandle
Handle of thread that added entries to the priority inversion list.

See Also

Release_Inversion_Pri, Reset_Inversion_Pri


Reset_Inversion_Pri

include vmm.inc

mov     edx, BoostHandle
mov     eax, Priority
VMMCall Reset_Inversion_Pri

Adjusts a thread's time-slice priority without associating the priority with a timed decay boost. If the new priority is less than the current priority, the service reduces the priority by the difference. Uses EAX, ECX, and EDX.

  • No return value.
BoostHandle
Handle of an existing inversion priority boost.
Priority
New time-slice priority for the thread associated with BoostHandle.

See Also

Release_Inversion_Pri, Release_Inversion_Pri_ID, Set_Inversion_Pri


Set_Inversion_Pri

include vmm.inc

mov     edi, TargetThread
mov     ebx, BoosterThread
mov     eax, Priority
mov     edx, BoostID
VMMCall Set_Inversion_Pri
jc      error
mov     [InvertHandle], eax

Adds the given target thread to the priority inversion list. While a thread remains in the list, it has the same time-slice priority as that of the thread with the highest priority in the list. Uses EAX and Flags.

  • Returns, in EAX, the handle of the inversion list entry for the given thread. Clears the carry flag if successful; sets it if an error occurs.
TargetThread
Handle of the thread to add to the priority inversion list.
BoosterThread
Handle of the thread that is adding the target thread to the inversion list. This parameter need not be the current thread. Also, 0 is valid.
Priority
Absolute Win32 priority required by the target thread.
BoostID
Identifier to associate with the entry in the priority inversion list. If a virtual device does not use this parameter, it should set it to zero.

A virtual device can use the handle returned by this service in a subsequent call to Release_Inversion_Pri to remove the thread from the inversion list.

See Also

Reset_Inversion_Pri


Synchronization

A virtual device uses the synchronization services to coordinate the execution of threads and virtual machines. The following terms are related to synchronization:

Term | Definition
block ID | A programmer-defined 32-bit value associated with one or more blocked threads.
claim | A request on the part of a virtual device to enter a critical section.
claim count | A system-defined variable that indicates the number of times the owner of a critical section has claimed the section.
context switch | The act of turning the CPU's "attention" from one thread to another.
critical section | A block of program code that accesses a shared system resource.
critical section owner | The thread or virtual machine that is currently executing in a critical section.
must-complete count | A system-defined variable that indicates the number of times the owner of a must-complete section has claimed the section.
must-complete section | A block of code that must be executed in its entirety before any other thread or virtual machine can run.
mutex | A synchronization object that ensures only one thread at a time can access a shared resource. A thread must have ownership of the mutex before it can access the resource. The thread blocks if the mutex is owned by another thread.
reentry count | A system-defined variable that indicates the number of times the owner of a mutex has called the _EnterMutex service after gaining ownership.
semaphore | An synchronization object that maintains a token count between zero and some maximum value. The object's state is signaled when its token count is greater than zero, and not-signaled when its count is zero.
signal | To increase the token count of a semaphore.
semaphore token count | The value associated with a semaphore. The initial token count is set when the semaphore is created. A signal operation increments the token count, and a wait operation decrements it.


Critical Sections

A critical section is a section of code that accesses a shared resource. When a virtual machine (VM) is executing code in a critical section, no other VM can execute code within their critical sections. By placing code that accesses shared resources within critical sections, shared resources are protected from simultaneous access by two or more VMs.

It is useful to think of the system as having a single, shared resource called the critical section which can represent any resource critical to the operation of all VMs. Only when a VM owns the critical section can it access the critical resource.

When a VM requests the critical section, it is said to have "claimed" the critical section. A VM that is executing code in the critical section is said to "own" the critical section. The VMM maintains an internal variable, called the claim count, that reflects the number of times the owner has claimed the critical section. Calling Begin_Critical_Section or Claim_Critical_Section increments the claim count; calling End_Critical_Section, End_Critical_Section_No_Block, or Release_Critical_Section decrements it. The owner releases the critical section only when the claim count is zero, allowing another VM to claim ownership. The claim count is not incremented when a VM attempts to claim the critical section while another virtual machine already owns it.

When one VM owns the critical section and a second VM attempts to claim ownership, the system blocks the second VM. Flags specified in the call to Begin_Critical_Section determine how the VM responds to interrupts while it is blocked. You should set the appropriate flags so that the VM processes hardware interrupts in a timely manner.

The system boosts the execution priority of a VM the when it first gains ownership of the critical section. This means that the system switches to another task only if the VM blocks on a semaphore or if a time-critical event occurs in another VM.

While the critical section is owned by any VM, you must not take any action that might cause MS-DOS to be reentered. If MS-DOS is used for paging, such actions include calling memory management services and touching pageable memory. Note that VxD_PAGEABLE_CODE_SEG and VxD_PAGEABLE_DATA_SEG segments are automatically locked if MS-DOS is used for paging.

A virtual device can request the VMM to notify it when a virtual machine has released the critical section by using the Call_When_Not_Critical or Call_Restricted_Event services. Note that the Call_When_Not_Critical service is equivalent to the following restricted event call:

xor    eax, eax        ; no boost
xor    ebx, ebx        ; global
mov    ecx, PEF_Wait_Not_Crit

VMMCall Call_Restricted_Event

These services can be used to install a callback function that the VMM calls when the critical section is released. A virtual device typically uses the callback function to perform tasks that the must done only when no virtual machine owns the critical section. The system removes the callback function after calling it. To remove a restricted event callback function before it is called, use the Cancel_Restricted_Event service. For Windows 95, the Cancel_Call_When_Not_Critical service is a no-op, so if you need to be able to cancel the event, use Call_Restricted_Event with PEF_Wait_Not_Crit, and cancel it with Cancel_Restricted_Event.

The Get_Crit_Section_Status and Get_Crit_Status_No_Block services retrieve the claim count and the handle of the current owner of the critical section. When a virtual device released the critical section, the system sometimes delays the release while it processes events. Get_Crit_Section_Status allows the system to blocks the current virtual machine, if necessary, while completing any delayed releases. Get_Crit_Status_No_Block, on the other hand, returns immediately with the claim count and owner handle. Get_Crit_Status_Thread is similar to Get_Crit_Section_Status except that it retrieves the handle of the thread that owns the critical section, rather than the handle of the virtual machine.


Critical Section Services

The following topics describe the services provided.


Begin_Critical_Section

include vmm.inc

mov     ecx, Flags
VMMCall Begin_Critical_Section

Claims a critical section for the current thread. Only one thread at a time can enter a critical section. If a virtual device calls this service after another thread has entered a critical section, the system blocks the calling thread until the critical section is released. Uses Flags.

  • No return value.
Flags
Action to take when interrupts occur while the thread is blocked waiting for the critical section. This parameter can be a combination of the following values:
Block_Enable_Ints | Service interrupts in the virtual machine even if the virtual machine does not currently have interrupts enabled. This forces interrupts to be enabled. This value is only relevant if either Block_Svc_Ints or Block_Svc_If_Ints_Locked is set.
Block_Svc_If_Ints_Locked | Service events and simulated interrupts in the virtual machine if the thread blocks for the critical section and the VMStat_V86IntsLocked flag is set.
Block_Svc_Ints | Service events and simulated interrupts in the virtual machine if the thread blocks for the critical section.
Block_Thread_Idle | Consider the thread to be idle if it blocks for the critical section.

The Block_Poll value is reserved and must not be used with this service.

The system maintains a count of claims for critical sections and releases the critical section only when an equal number of Begin_Critical_Section and End_Critical_Section services have been called. Calling Begin_Critical_Section before the critical section is released does not increment the claim count.

When the critical section is first claimed, the system boosts the execution priority of the current virtual machine by the Critical_Section_Boost value (as described for the Adjust_Exec_Priority service). While a virtual machine is in a critical section, the system will switch to another task only if the virtual machine blocks on a semaphore or the other task has a time-critical operation, such as simulating hardware interrupts.

If the current VM is the System VM, Begin_Critical_Section also claims the V86 mutex.

See Also

Adjust_Exec_Priority, End_Critical_Section


Call_When_Not_Critical

include vmm.inc

mov     esi, CritSecCallback
mov     edx, RefData
VMMCall Call_When_Not_Critical

This function is not implemented in Windows 95. For Windows 3.11 and below, this function installs a critical-section callback function. The system calls this function when a virtual device releases the critical section. Uses Flags.

  • No return value.
CritSecCallback
Address of the callback function to install. For more information, see CritSecCallback.
RefData
Address of reference data to pass to the callback function.

The system does not execute the callback until the current virtual machine's execution priority is less than the Critical_Section_Boost value even if the current virtual machine is not in a critical section. This allows a virtual device to release the critical section and process any simulated interrupts before the system calls the callback function.

Virtual devices can install any number of callback functions, but the system calls only the most recent function on the list when the critical section is released. The system removes the callback function from the list as it calls the function. This is a common point of confusion. Unlike services like Call_When_Task_Switched, which install a hook permanently, the Call_When_Not_Critical service removes the callback once it is dispatched.

Under Windows 95, use Call_Restricted_Event with PEF_Wait_Not_Crit, and cancel it with Cancel_Restricted_Event instead, since the Cancel_Call_When_Not_Critical function is a no-op.

If the critical section is taken when this function is called (it is necessary to schedule the event instead of immediately calling your function), it schedules a restricted event as follows:

xor    eax, eax        ; no boost
xor    ebx, ebx        ; global
mov    ecx, PEF_Wait_Not_Crit

VMMCall Call_Restricted_Event

See Also

Call_When_Idle, Call_When_Task_Switched, CritSecCallback


Cancel_Call_When_Not_Critical

mov     esi, OFFSET32 CritSecCallback
VMMCall Cancel_Call_When_Not_Critical
jc     not_removed

Remove references to the specified callback function installed by a previous call to Call_When_Not_Critical. Uses Flags.

This function is a no-op (it does nothing) under Windows 95.

  • Clears the carry flag if one or more references are removed; otherwise, sets the carry flag.
CritSecCallback
Address of callback function.

See Also

Call_When_Not_Critical


Claim_Critical_Section

include vmm.inc

mov     eax, Claims
mov     ecx, Flags
VMMCall Claim_Critical_Section

Increments the claim count by the specified value. It has the same effect as calling the Begin_Critical_Section service repeatedly. Uses Flags.

  • No return value.
Claims
Number of times to claim the critical section. Zero is a valid number, but is ignored. Claims must be a value less than 65536, otherwise this function treats it as if it were zero.
Flags
Action to take when interrupts occur while the virtual machine is blocked waiting for the critical section. This parameter can be a combination of the following values:
Block_Enable_Ints | Service interrupts in the virtual machine even if the virtual machine does not currently have interrupts enabled. This forces interrupts to be enabled. This flag is relevant only if either Block_Svc_Ints or Block_Svc_If_Ints_Locked is set.
Block_Svc_If_Ints_Locked | Service events and simulated interrupts in the virtual machine if the thread blocks for the critical section and the VMStat_V86IntsLocked flag is set.
Block_Svc_Ints | Service events and simulated interrupts in the virtual machine if the thread blocks for the critical section.
Block_Thread_Idle | Consider the thread to be idle if it blocks for the critical section.

The Block_Poll value is reserved and must not be used with this service.

See Also

Adjust_Exec_Priority, Begin_Critical_Section, End_Critical_Section


CritSecCallback

mov     ebx, VMHandle
mov     edi, ThreadHandle
mov     edx, RefData
mov     ebp, OFFSET32 Client_Reg_Struc
call    [CritSecCallback]

Performs programmer-defined processing when a virtual device releases the critical section. CritSecCallback is a programmer-defined callback function installed by the Call_When_Not_Critical service. Uses Flags.

  • No return value.
VMHandle
Handle of the current virtual machine.
ThreadHandle
Handle of the current thread.
RefData
Reference data from the virtual device that installed the callback function.
Client_Reg_Struc
Address of a Client_Reg_Struc structure containing the registers of the current virtual machine.

The callback function can carry out any operation and can modify the EAX, EBX, ECX, EDX, ESI, EDI, and Flags registers.

See Also

Call_When_Not_Critical


End_Crit_And_Suspend

include vmm.inc

VMMCall End_Crit_And_Suspend
jc      not_released

Releases the critical section and immediately suspends the current virtual machine. Virtual devices use this service to block a virtual machine until another virtual machine can process an event. Uses Flags.

  • Clears the carry flag if successful, sets it otherwise.

This service releases the critical section only if the virtual machine has claimed the section once. This service returns an error if the system could not suspend the virtual machine, or could not release the critical section because the claim count was not 1. In such cases, the service does not decrement the claim count and the critical section is not released.

The following example uses this service to display a dialog box in the system virtual machine. The Show_Dialog_Box function enters a critical section to prevent the Call_Priority_VM_Event service from switching to the system virtual machine immediately. It then calls End_Crit_And_Suspend which blocks the current virtual machine. The Show_Dialog_Event function runs in the system virtual machine and actually displays the dialog box. When it is finished it resumes the virtual machine that called Show_Dialog_Box by calling the Resume_VM service.

Show_Dialog_Box:
    VMMCall Get_Crit_Section_Status
    jc      Cant_Do_It                  ; critical section already
                                        ; claimed

    VMMCall Begin_Critical_Section
    mov     eax, Low_Pri_Device_Boost
    VMMCall Get_System_VM_Handle
    mov     ecx, 11b
    mov     edx, OFFSET32 Dialog_Box_Data_Structure
    mov     esi, OFFSET32 Show_Dialog_Event
    VMMCall Call_Priority_VM_Event
    VMMCall End_Crit_And_Suspend
    jc      Did_Not_Work
    ; When End_Crit_And_Suspend returns, the dialog box
    ; will have been displayed

Show_Dialog_Event:
    ; Call Windows to display the dialog box

    mov     ebx, [Suspended_VM_Id]
    VMMCall Resume_VM
    jc      Error
    ret

The End_Crit_And_Suspend service predates most of the synchronization services provided by Windows 95 and exists primarily for backward compatibility. New virtual devices should avoid this service, since there are better mechanisms available.

See Also

End_Critical_Section, Resume_VM, Suspend_VM


End_Critical_Section

include vmm.inc

VMMCall End_Critical_Section

Releases the critical section if the current thread owns the section and the claim count is zero. Uses Flags.

  • No return value.

This service decrements the claim count and releases the critical section if the new count is zero. Since releasing the critical section lowers the execution priority of the current thread, this service causes a task switch if a nonsuspended thread has higher priority.

It is extremely risky for a virtual device to end a critical section it did not enter, or which it entered from a thread other than the current thread.

See Also

Begin_Critical_Section, End_Crit_And_Suspend


Get_Crit_Section_Status

include vmm.inc

VMMCall Get_Crit_Section_Status

mov     [VMHandle], ebx
mov     [Claims], ecx
jc      high_priority

If the critical-section claim count is non-zero, this function returns the critical-section claim count in ECX and a handle identifying the virtual machine that owns the critical section in EBX.

If the critical-section claim count is zero, and the current VM is the system VM, this function inspects the V86 mutex count. If the V86 mutex count is non-zero, this function returns the V86 mutex count in the high word of ECX, and a handle identifying the virtual machine that owns the V86 mutex in EBX.

If none of the above applies (in the case where the returned ECX contains 0) this routine returns the current virtual machine handle in EBX.

Uses flags.

  • The carry flag is set if the current virtual machine has an execution priority greater than or equal to Critical_Section_Boost, such as during a hardware interrupt simulation.

Windows 3.1 sometimes delays releasing the critical section until events are processed. This service causes the system to complete any delayed releases before the service returns the status. This may cause a task switch if another virtual machine has a delayed release.

If a virtual device must ensure that it owns the critical section to successfully complete an operation, it should call this service to make sure that the critical section status is up to date.

This is not an asynchronous service; it must not be called at interrupt time.

See Also

Get_Crit_Status_No_Block


Get_Crit_Status_No_Block

include vmm.inc

VMMCall Get_Crit_Status_No_Block

mov     [VMHandle], ebx
mov     [Claims], ecx
jc

Performs the same service as Get_Crit_Section_Status, except unlike the Get_Crit_Section_Status service, this service returns immediately (without blocking) even if a delayed request to release the critical section is pending. This service is only available for Windows version 3.1 or later. Uses Flags.

See Also

End_Critical_Section, Get_Crit_Section_Status


Get_Crit_Status_Thread

include vmm.inc

VMMCall Get_Crit_Status_Thread

If the critical-section claim count is non-zero, this function returns the critical-section claim count in ECX and a handle identifying the thread that owns the critical section in EDI.

If the critical-section claim count is zero, and the current VM is the system VM, this function inspects the V86 mutex count. If the V86 mutex count is non-zero, this function returns the V86 mutex count in the high word of ECX, and a handle identifying the thread that owns the V86 mutex in EDI.

If none of the above applies (in the case where the returned ECX contains 0) this routine returns the current thread handle in EDI.

Uses flags. Sets the carry flag if the thread is in a time-critical operation such as hardware interrupt simulation.

This service may be called at interrupt time.

This service differs from Get_Crit_Section_Status and Get_Crit_Status_No_Block in that it returns a thread handle.

See Also

Get_Crit_Section_Status, Get_Crit_Status_No_Block


Release_Critical_Section

include vmm.inc

mov     ecx, Claims
VMMCall Release_Critical_Section

Decrements the claim count by the specified value. It has the same effect as calling the End_Critical_Section section repeatedly. Uses Flags.

  • No return value.
Claims
Number of times to release ownership of critical section. Zero is a valid number, but is ignored.

It is extremely risky for a virtual device to end a critical section it did not enter, or which it entered from a thread other than the current thread.

See Also

Claim_Critical_Section, End_Critical_Section


Must-Complete Section Services

The following topics describe the must-complete services.


_EnterMustComplete

VMMCall _EnterMustComplete

Increments the must-complete count for the current thread, causing it to enter a must-complete section. Uses the C calling convention. Uses EAX, ECX, EDX, and Flags.

  • No return value.

A virtual device can call this service recursively.

For each call to _EnterMustComplete, there must be a corresponding call to _LeaveMustComplete.

This service ensures that the thread is not suspended or killed (via Suspend_VM or Nuke_VM) by another thread while executing a section of critical code. This service is usually used to protect a thread while it owns an important shared resource or state information. If the thread were killed or suspended while it owned such a resource, all other threads would be blocked.

While in a must complete, any suspends or nukes will be postponed until the last _LeaveMustComplete. A must-complete does not change priorities or thread switching in any way.

A VxD can also enter a must complete section automatically by using the MUTEX_MUST_COMPLETE flag with the _CreateMutex service.

See Also

_EnterMutex, _LeaveMustComplete


_ExecIntMustComplete

include vmm.inc

mov     eax, Interrupt
VMMCall _ExecIntMustComplete

Simulates the specified interrupt, and resumes execution of the virtual machine, causing it to enter a must-complete section. This service may only be called in a nested execution block created using the Begin_Nest_Exec or Begin_Nest_V86_Exec service. Uses Flags

  • No return value.
Interrupt
Number of the interrupt to simulate.

When in a nested execution block, this service can be called any number of times.

This service is comparable to combining the Simulate_Int and _ResumeExecMustComplete services.

See Also

Begin_Nest_Exec, Begin_Nest_V86_Exec, Resume_Exec, _ResumeExecMustComplete


_ExecVxDIntMustComplete

include vmm.inc

push dword ptr Interrupt
VMMCall _ExecVxDIntMustComplete

Executes the specified software interrupt. Uses registers and flags modified by the interrupt.

  • One or more registers may contain return values depending on the function of the specified interrupt.
Interrupt
Specifies the number of the interrupt to execute.

This service should be used with the _EnterMustComplete service.

The _ExecVxDIntMustComplete service is similar to the Exec_VxD_Int service with the following exceptions: it may be called within a must-complete section; and if a fatal error occurs while executing the interrupt, this service sets the carry flag leaving the general purpose registers in an unknown state. (The carry flag may also be set by the interrupt that is called. A VxD can use the _GetThreadTerminationStatus service to differentiate between these two cases.)

See Also

_EnterMustComplete, Exec_VxD_Int, _GetThreadTerminationStatus


_LeaveMustComplete

include vmm.inc

cCall    _LeaveMustComplete

Decrements the must-complete count for the calling thread. Uses the C calling convention. Uses EAX, ECX, EDX, and Flags.

  • No return value.

See Also

_EnterMustComplete, _LeaveMutex


_ResumeExecMustComplete

include vmm.inc

VMMCall _ResumeExecMustComplete

Executes the current virtual machine immediately, causing it to enter a critical section. This service may only be called in a nested execution block created using the Begin_Nest_Exec or Begin_Nest_V86_Exec service. Uses Flags.

  • No return value.

This service can be used any number of times in a nested execution block.

This service returns when the virtual machine returns to the same point it was at when Begin_Nest_Exec was called.

See Also

Begin_Nest_Exec, Begin_Nest_V86_Exec, _ExecIntMustComplete, Resume_Exec


Semaphore Services

The following topics describe the semaphore services.


Create_Semaphore

include vmm.inc

mov     ecx, TokenCount
VMMCall Create_Semaphore
jc      error
mov     [Semaphore], eax

Allocates memory for and initializes a new semaphore. Uses EAX and Flags.

  • Returns the semaphore handle in EAX and clears the carry flag, if successful; otherwise, sets the carry flag.
TokenCount
Initial count of tokens.

See Also

Destroy_Semaphore, Signal_Semaphore, Wait_Semaphore


Destroy_Semaphore

include vmm.inc

mov     eax, Semaphore
VMMCall Destroy_Semaphore

Destroys the specified semaphore. Uses Flags.

  • No return value.
Semaphore
Handle of the semaphore to delete.

Destroying a semaphore while threads are still blocked on it will crash the system.

See Also

Create_Semaphore


Signal_Semaphore

include vmm.inc

mov     eax, SemaphoreHandle
VMMCall Signal_Semaphore

Signals a semaphore, releasing (unblocking) a single thread if there are any threads blocked waiting for the semaphore. The threads are released in order of priority; that is, the highest priority thread is released first even if it has been blocked for the shortest time. When signaling the semaphore causes a higher priority thread to be released and the VMM has not been reentered, an immediate context switch to the higher priority thread occurs. This service returns with interrupts enabled. Uses Flags.

  • No return value.
SemaphoreHandle
Handle of the semaphore to signal.

See Also

Create_Semaphore, Signal_Semaphore_No_Switch, Wait_Semaphore


Signal_Semaphore_No_Switch

include vmm.inc

mov     eax, SemaphoreHandle
VMMCall Signal_Semaphore_No_Switch

Signals a semaphore, releasing (unblocking) a single thread if there are any threads blocked waiting for the semaphore. The threads are released in order of priority; that is, the highest priority thread is released first even if it has been blocked for the shortest time. Unlike the Signal_Semaphore service, this service never causes an immediate context switch. Instead any threads that need to be released are released the next time events are serviced. This service also differs in that it preserves the state of processor interrupt mask; that is, if interrupts are disabled on entry they are still disabled when this service returns. Uses Flags.

  • No return value.
SemaphoreHandle
Handle of the semaphore.

See Also

Create_Semaphore, Signal_Semaphore, Wait_Semaphore


Wait_Semaphore

include vmm.inc

mov     eax, SemaphoreHandle
mov     ecx, Flags
VMMCall Wait_Semaphore

Blocks the current thread until the semaphore is signaled using the Signal_Semaphore service. Uses Flags

  • No return value.
SemaphoreHandle
Handle of the semaphore on which to wait.
Flags
Action to take when interrupts occur while the thread is blocked waiting for the semaphore. This parameter can be a combination of the following values:
Block_Enable_Ints | Service interrupts in the virtual machine even if the virtual machine does not currently have interrupts enabled. This forces interrupts to be enabled. This value is only relevant if either Block_Svc_Ints or Block_Svc_If_Ints_Locked is set.
Block_Force_Svc_Ints | Service events and simulated interrupts in the thread even when the critical section is not available. Be careful when using this flag. If it is used when any VMM or real mode MS-DOS resources are held, it will cause deadlocks to occur. If in doubt, do not use this flag.
Block_Poll | Do not switch away from the blocked virtual machine unless another virtual machine has higher priority.
Block_Svc_If_Ints_Locked | Service events and simulated interrupts in the virtual machine even if the thread blocks for the semaphore and the VMStat_V86IntsLocked flag is set.
Block_Svc_Ints | Service events and simulated interrupts in the virtual machine even if the virtual machine is blocked. Events are only serviced when the critical section is available or owned by the blocked thread unless the Block_Force_Svc_Ints flag is also set. Then when events are serviced, the critical section is taken and held while they are serviced. This is necessary to prevent a deadlock from occurring when an event tries to enter the critical section and blocks while holding system-wide resources.
Block_Thread_Idl

Block_Thread_Idl

Block_Thread_Idl

Block_Thread_Idle

Consider the thread idle when it blocks on the semaphore.

This service blocks if the semaphore's token count is zero or less. Otherwise, it decrements the token count and returns immediately. If the token count is not zero (meaning the Signal_Semaphore service has been called), Wait_Semaphore decrements the token count and returns immediately.

See Also

Create_Semaphore, Signal_Semaphore


Mutex Services

The following topics describe the services provided.


_CreateMutex

include vmm.h

DWORD SERVICE _CreateMutex(LONG Boost, ULONG Flags)

Allocates memory for and initializes a mutex. The priority boost is stored in the mutex, and is used to boost a thread's priority when it acquires the mutex. When a thread blocks waiting for the mutex it is given one half of the priority boost. Uses EAX, ECX, EDX, and flags.

  • Returns a handle identifying the new mutex if the function succeeds; otherwise returns NULL.
Boost
The amount by which the thread that owns the mutex should be boosted.
Flags
Execution options. It can be the following value:
Value | Meaning
MUTEX_MUST_COMPLETE | A "must-complete" section is entered each time the mutex is entered.


_DestroyMutex

include vmm.h

DWORD SERVICE _DestroyMutex(DWORD hmtx)

Frees memory allocated for a mutex. The mutex cannot be in use when this function is called. Uses EAX, ECX, EDX, and flags.

  • Returns a non-zero value if successful; otherwise, returns zero.
hmtx
Handle of mutex that will be destroyed.


_EnterMutex

include vmm.inc

VMMCall     _EnterMutex, <MutexHandle, Flags>

Enters a mutex. If the mutex is unowned, the calling thread becomes the owner and execution continues. If the mutex is owned by another thread, the calling thread blocks until the mutex is available. If this thread already owns the mutex, the reentry count is incremented and execution continues. Uses C Calling Convention: Uses EAX, ECX, EDX, and Flags.

  • No return value.
MutexHandle
Handle of the mutex.
Flags
Action to take when interrupts occur while the virtual machine is blocked for the mutex. This parameter can be a combination of the following values:
Block_Enable_Ints | Service interrupts in the virtual machine even if the virtual machine does not currently have interrupts enabled. This forces interrupts to be enabled. This value is only relevant if either Block_Svc_Ints or Block_Svc_If_Ints_Locked is set.
Block_Svc_If_Ints_Locked | Service events and simulated interrupts in the virtual machine if the thread blocks for the mutex and the VMStat_V86IntsLocked flag is set.
Block_Svc_Ints | Service events and simulated interrupts in the virtual machine if the thread blocks for the mutex.
Block_Thread_Idle | Consider the thread to be idle if it blocks for the mutex.

The Block_Poll value is reserved and must not be used with this service.

If the mutex has a priority boost and the mutex is entered for the first time, the execution priority of the current thread is boosted by the same amount.

See Also

_EnterMustComplete, _LeaveMutex


_GetMutexOwner

include vmm.inc

VMMCall   _GetMutexOwner, <MutexHandle>
mov     Owner, eax

Retrieves the handle of the thread that owns the specified mutex. Uses C calling convention: Uses EAX, ECX, EDX, and Flags.

  • Returns the handle in EAX or zero if the mutex is unowned.
MutexHandle
Handle of the mutex.


_LeaveMutex

include vmm.inc

cCall    _LeaveMutex, <MutexHandle>

Leaves a mutex. If the reentry count of the mutex is greater than one, this function decrements the reentry count. If the reentry count is one, it becomes unowned and the highest priority thread waiting for the mutex is released.

  • No return value.
MutexHandle
Handle of the mutex.

This service causes a context switch if the execution priority of the released thread is higher

priority than the current thread.

Only the thread owning a mutex can leave it.

When the critical section is freed, any threads waiting for the critical section are released.

See also

_EnterMutex, _LeaveMustComplete


Thread-Blocking Services

The following topics describe the services provided.


_BlockOnID

include vmm.inc

VMMCall _BlockOnID, <ThreadID, Flags>

Records the identifier (ID) to be used to block the current thread. The actual blockage of a thread is signaled with _SignalID. Uses the C calling convention. Uses flags.

  • No return value.
ThreadID
The programmer-defined ID used to block the thread.
Flags
Actions to take when interrupts occur while the virtual machine is blocked. This parameter can be a combination of the following values:
Value | Meaning
Block_Enable_Ints | Service interrupts in the virtual machine even if it does not currently have interrupts enabled. This forces interrupts to be enabled. This value is only relevant if either Block_Svc_Ints or Block_Svc_If_Ints is set.
Block_Svc_If_Ints_Locked | Service interrupts in the virtual machine even if the virtual machine is blocked, and the VMStat_V86IntsLocked flag is set.
Block_Svc_Ints | Service interrupts in the virtual machine even if the virtual machine is blocked.
Block_Thread_Idl

Block_Thread_Idl

Block_Thread_Idl

Block_Thread_Idle

Consider the thread to be idle if it blocks for the critical section.

Typically, the ThreadID consists of 32-bit linear address of something related to the object being blocked on, because that helps ensure uniqueness. When the same ID is passed to SignalID, the blocked thread reawakens. When a thread reawakens, it must check whether the wakeup was valid or spurious.

This service always blocks the current thread on the ID passed. Multiple threads may block on the same ID. When the ID is signaled with _SignalID all of the threads currently blocked on the ID will unblock.

Block IDs are not guaranteed to be unique to the caller; an unrelated piece of code may signal the ID in order to awaken a thread that it has blocked and cause this one to be spuriously awakened. Therefore when this service returns the caller must check for a spurious wake up and call _BlockOnID again if this has occurred. Typically a user maintained flag is used for this. The flag is set before calling _BlockOnID the first time and cleared when _SignalID is called.

The Block ID is traditionally the address of an object somehow related to the reason why the virtual device needs to block. Be aware of race conditions that may occur if _BlockOnID is called after the ID is signaled. For example, if a virtual device initiates an operation, it may be that the operation completes and the Block ID is signaled before the virtual device gets to call _BlockOnID to wait for the signal. The virtual device ends up blocking waiting for a signal that has already arrived.

See Also

_SignalID


_SignalID

include vmm.inc

VMMCall _SignalID, <ID>

Signals an ID. Threads currently blocked on this ID will be unblocked.

  • No return value.
ID
Value used to identify blocked threads.

This service does not cause an immediate context switch; instead any threads that need to be released are released the next time events are serviced.

This service preserves the state of the interrupt mask.


Virtual Machine Interrupts and Callbacks

There are the following virtual machine interrupt and callback services:

Service | Description
Build_Int_Stack_Frame | Builds a stack frame for an interrupt.
Call_When_VM_Ints_Enabled | Installs an interrupts-enabled callback.
Disable_VM_Ints | Disables interrupts for the virtual machine.
Enable_VM_Ints | Enables interrupts for the virtual machine.
Get_Instanced_V86_Int_Vector | Returns a real-mode interrupt address instanced per VM.
Get_Inst_V86_Int_Vec_Base | Retrieves the address of a 400h-byte memory block that contains the current interrupt vectors for the given VM.
Get_PM_Int_Type | Returns the type of interrupt vector.
Get_PM_Int_Vector | Returns a protected-mode interrupt address.
Get_V86_Int_Vector | Returns a real-mode interrupt address.
Hook_V86_Int_Chain | Installs a hook procedure for a V86 interrupt.
Set_PM_Int_Type | Sets the protected-mode interrupt type.
Set_PM_Int_Vector | Sets a protected-mode interrupt vector.
Set_V86_Int_Vector | Sets a real-mode interrupt vector.
Simulate_Far_Call | Simulates a far call.
Simulate_Far_Jmp | Simulates a jump.
Simulate_Far_Ret | Simulates a far return.
Simulate_Far_Ret_N | Simulates a far return with parameters.
Simulate_Int | Simulates an interrupt.
Simulate_Iret | Simulates a return from an interrupt.
Simulate_Pop | Simulates a pop instruction.
Simulate_Push | Simulates a push instruction.
Test_VM_Ints_Enabled | Determines whether the current VM interrupts are enabled or disabled.
Unhook_V86_Int_Chain | Removes the hook procedure for the specified interrupt.


Build_Int_Stack_Frame

include vmm.inc

mov     cx, Segment        ; code segment of routine to call
mov     edx, Offset        ; offset of routine to call
VMMCall Build_Int_Stack_Frame

Prepares the current virtual machine to execute an interrupt routine. This service saves the current Client_CS, Client_IP, and Client_Flags registers on the virtual machine's stack and sets the Client_CS and Client_IP registers to the address of the interrupt routine specified by the Segment and Offset parameters. When execution resumes in the virtual machine (such as when the Resume_Exec service is called), the virtual machine executes the interrupt routine. The interrupt routine continues to run until it executes an iret instruction. Uses Client_CS, Client_EIP, Client_ESP, Client_Flags, Flags.

  • No return value.
Segment
Segment address or segment selector for the code segment containing the interrupt routine.
Offset
Offset of interrupt routine. If the specified code segment is a 16-bit segment, the high word of this parameter must be 0.

The following example executes the interrupt routine in the code segment specified by

My_Segment at the offset My_Offset:

VMMCall Begin_Nest_Exec
mov     cx, [My_Segment]
mov     edx, [My_Offset]
VMMCall Build_Int_Stack_Frame
VMMCall Resume_Exec
VMMCall End_Nest_Exec

See Also

Simulate_Far_Call


Call_When_VM_Ints_Enabled

include vmm.inc

mov     edx, RefData            ; reference data
mov     esi, OFFSET32 Callback  ; points to callback procedure
VMMCall Call_When_VM_Ints_Enabled

Installs a callback procedure that the system calls when the virtual machine enables interrupts. This service calls the callback procedure immediately if interrupts are already enabled. Virtual devices use this service to ensure that virtual machine interrupts are enabled before carrying out some action, such as calling a callback procedure in the virtual machine. Uses Client_Flags, Flags.

  • No return value.
RefData
Reference data to be passed to the callback procedure.
Callback
Address of the callback procedure to install. For more information about the callback procedure, see below.

It is usually more convenient to use the Call_Priority_VM_Event service instead of calling this service directly. However, this service is faster. The callback procedure is automatically uninstalled when it is called.

The system calls the callback procedure as follows:

mov     ebx, VM                  ; current VM handle
mov     edx, OFFSET32 RefData    ; points to reference data
mov     ebp, OFFSET32 crs        ; points to a Client_Reg_Struc
call    [Callback]

The VM parameter is a handle identifying the current virtual machine, the RefData parameter points to the reference data specified when the callback procedure was installed, and the crs parameter points to a Client_Reg_Struc structure containing the register values for the virtual machine.

The callback procedure may use the EAX, EBX, ECX, EDX, ESI, EDI, and Flags registers.

See Also

Call_When_Idle, Call_When_Not_Critical, Call_When_Task_Switched


Disable_VM_Ints

include vmm.inc

VMMCall Disable_VM_Ints

Disables interrupts during virtual machine execution for the current virtual machine. This has the same effect as the virtual machine executing a cli instruction. Uses Flags.

  • No return value.

Virtual devices should use this service instead of changing the Client_Flags directly, so that the virtual machine manager can do necessary associated bookkeeping.

See Also

Enable_VM_Ints


Enable_VM_Ints

include vmm.inc

VMMCall Enable_VM_Ints

Enables interrupts during virtual machine execution for the current virtual machine. This has the same effect as the virtual machine executing an sti instruction. Uses Flags.

  • No return value.

Virtual devices use this service to permit callback procedures installed by the Call_When_Ints_Enabled or Call_Priority_VM_Event service to be called. The system does not call these callback procedures immediately. Instead, it waits until the next event occurs. This means the virtual machine's state does not change while this service executes.

Virtual devices should use this service instead of changing the Client_Flags directly, so that the virtual machine manager can do necessary associated bookkeeping.

See Also

Call_Priority_VM_Event, Call_When_VM_Ints_Enabled, Disable_VM_Ints


Get_Instanced_V86_Int_Vector

include vmm.inc

mov eax, InterruptNumber
mov ebx, VMHandle
VMMCall Get_Instanced_V86_Int_Vector

mov dword ptr [Handler], eax

Retrieves the address of the routine that handles the specified interrupt from a V86 interrupt table.

  • Returns the address of the routine that handles the specified interrupt in the EAX register if successful; otherwise returns 0 in EAX. The high word of the EAX register contains the segment address of the interrupt-handling routine, and the low word of the EAX register contains the offset.
InterruptNumber
The interrupt number that causes the interrupt routine to be called.
VMHandle
VM handle.

The interrupt table is instanced per VM. For performance reasons, this service retrieves the address of the interrupt-handling routine without causing an instance fault. This service is preferred over accessing the interrupt vector table directly.


Get_Inst_V86_Int_Vec_Base

include vmm.inc

mov     VMHandle
VMMCall Get_Inst_V86_Int_Vec_Base
mov     [Address], ecx

Retrieves the address of a 400h-byte memory block that contains the current interrupt vectors for the given VM. This function can be used in place of the Get_Instanced_V86_Int_Vector service to examine multiple interrupt vectors. Uses ECX and Flags.

  • Returns, in ECX, the address of a memory block that contains the current interrupt vectors.
VMHANDLE
Handle of the virtual machine.

Be careful when using this service. Your code must reside in page locked memory and must not touch pageable memory, including instance pages, and must not yield while using the pointer returned by this service.

A VxD must not use this pointer to modify interrupt vectors because doing so can cause the system to become unstable. To be safe, use the Get_Instanced_V86_Int_Vector service instead of Get_Inst_V86_Int_Vec_Base.

See Also

Get_Instanced_V86_Int_Vector


Get_PM_Int_Type

include vmm.inc

mov     eax, Interrupt    ; number of interrupt to check
VMMCall Get_PM_Int_Type

mov     [Type], edx       ; 0 if trap gate, else interrupt gate

Determines whether a protected-mode interrupt vector is an interrupt gate or trap-gate type interrupt. Uses EDX, Flags.

  • Returns zero in the EDX register if the interrupt corresponds to a trap gate, a nonzero value if the it corresponds to an interrupt gate.
Interrupt
Number of the interrupt to check.

An interrupt that passes through an interrupt gate automatically clears the interrupt flag bit to disable interrupts. Interrupts that pass through a trap gate do not modify the interrupt bit. All protected-mode interrupts default to the trap-gate type, but virtual devices such as the virtual PIC device, may change some trap gates to interrupt gates so that hardware interrupts disable interrupts. The virtual PIC device leaves software interrupts, such as Interrupt 21h, unchanged. This avoids an unnecessary ring transition by eliminating the need for the software interrupt handlers to execute an sti instruction.

See Also

Get_PM_Int_Vector, Set_PM_Int_Type


Get_PM_Int_Vector

include vmm.inc

mov     eax, Interrupt      ; number of interrupt to check
VMMCall Get_PM_Int_Vector

mov     [Segment], cx       ; selector for interrupt routine
mov     [Offset], edx       ; offset to interrupt routine

Returns the address of the interrupt routine for the specified protected-mode interrupt in the current virtual machine. Uses ECX, EDX, Flags.

  • Returns the selector in the CX register and the offset in the EDX register. The high word of the EDX register is zero if the code segment is a 16-bit segment. The zero flag is set if the interrupt address points to the default interrupt handler, or clear if a virtual device has hooked the interrupt.
Interrupt
Number of the interrupt to check.

The system maintains a protected-mode interrupt vector table for each virtual machine. By default, each table entry points to a protected-mode breakpoint procedure that reflects the interrupt to V86 mode.

See Also

Get_PM_Int_Type, Set_PM_Int_Vector


Get_V86_Int_Vector

include vmm.inc

mov     eax, Interrupt      ; number of interrupt to check
VMMCall Get_V86_Int_Vector

mov     [Segment], cx       ; segment addr. for interrupt routine
mov     [Offset], edx       ; offset of interrupt routine

Returns the address of the interrupt routine for the specified real-mode interrupt in the current virtual machine. Uses ECX, EDX, Flags.

  • Returns the segment address in the CX register and the offset in the EDX register. The high word of the EDX register is always zero.
Interrupt
Number of the interrupt to check.

See Also

Get_PM_Int_Vector, Set_V86_Int_Vector


Hook_V86_Int_Chain

include vmm.inc

mov     eax, Interrupt          ; number of interrupt to hook
mov     esi, OFFSET32 HookProc  ; points to hook procedure
VMMCall Hook_V86_Int_Chain

jc      not_installed           ; carry flag set if procedure not installed

Installs a hook procedure that the system calls whenever the specified interrupt occurs. Virtual devices use this service to monitor software interrupts, and simulated hardware interrupts in V86 mode. Unlike Windows 3.1 in which this service was available only during initialization, Windows 95 allows V86 interrupt hooks to be installed after initialization is complete. Uses Flags.

  • Returns with the carry flag clear if successful, set otherwise.
Interrupt
Number of the interrupt for which to install the hook procedure.
HookProc
Address of the hook procedure. For more information about the hook procedure, see below.

The system calls the hook procedure whenever the corresponding interrupt occurs, a virtual device calls the Simulate_Int service, or the system simulates a hardware interrupt. This means a hook procedure must make no assumptions about the origin of the interrupt.

The system calls the procedure as follows:

mov     eax, Interrupt      ; number of interrupt hooked
mov     ebx, VM             ; current VM handle
mov     ebp, OFFSET32 crs   ; points to a Client_Reg_Struc
call    [HookProc]

jc      pass_to_next        ; carry set if interrupt not serviced

The Interrupt parameter is the number of the current interrupt, the VM parameter is a handle identifying the current virtual machine, and the crs parameter points to a Client_Reg_Struc structure containing the register values of the current virtual machine. If the hook procedure services the interrupt, it must clear the carry flag to prevent the system from passing the interrupt to the next hook procedure.

Any number of virtual devices can install a hook procedure for a given interrupt. The system always calls the last hook procedure first. A hook procedure either services the interrupt or directs the system to pass the interrupt to the next hook procedure. If no hook procedure services the interrupt, the system reflects the interrupt to the virtual machine.

This service is recommended instead of hooking the V86 interrupt vector directly.

See Also

Set_V86_Int_Vector, Simulate_Int


Simulate_Far_Call

include vmm.inc

mov     cx, Segment       ; segment containing procedure
mov     edx, Offset       ; offset of procedure
VMMCall Simulate_Far_Call

Simulates a far call to a procedure in the current virtual machine. This service sets the Client_CS and Client_IP registers to the specified procedure address after saving the original Client_CS and Client_IP registers on the stack of the current virtual machine. When the virtual machine resumes execution (such as when the Resume_Exec service is called), the system executes the specified procedure and returns only when the procedure executes a far ret instruction. Uses Client_CS, Client_EIP, Client_SP, Flags.

  • No return value.
Segment
Selector or segment address of the code segment containing the procedure.
Offset
Offset of the procedure to call. If the code segment is a 16-bit segment, the high word must be zero.

See Also

Build_Int_Stack_Frame, Simulate_Far_Jmp


Simulate_Far_Jmp

include vmm.inc

mov     cx, Segment       ; segment containing procedure
mov     edx, Offset       ; offset of procedure
VMMCall Simulate_Far_Jmp

Simulates a far jump to a procedure in the current virtual machine. This service sets the Client_CS and Client_IP registers to the specified address. When the virtual machine resumes execution (such as when the Resume_Exec service is called), the system executes the specified procedure. Uses Client_CS, Client_EIP, Flags.

  • No return value.
Segment
Selector or segment address of the code segment containing the procedure.
Offset
Offset of the procedure to jump to. If the code segment is a 16-bit segment, the high word must be zero.

See Also

Simulate_Far_Call


Simulate_Far_Ret

include vmm.inc

VMMCall Simulate_Far_Ret

Simulates a far return in the current virtual machine. This service pops the top two words (or doublewords) from the stack of the current virtual machine, and copies these values to the Client_CS and Client_EIP or Client_IP registers. Uses Flags.

  • No return value.

This services pops two word values from the stack if the segment containing the address is a 16-bit segment. Otherwise, this service pops two doubleword values.

See Also

Simulate_Far_Call, Simulate_Far_Ret_N


Simulate_Far_Ret_N

include vmm.inc

mov     eax, Bytes          ; number of bytes to pop from stack
VMMCall Simulate_Far_Ret_N

Simulates a far return in the current virtual machine. This service pops the top two words (or doublewords) from the stack of the current virtual machine, and places the values in the Client_CS and Client_EIP or Client_IP registers. It then adds the specified value to the Client_ESP or Client_SP register, effectively popping any pushed parameters from the stack. Uses Client_CS, Client_EIP, Client_ESP, Flags.

  • No return value.
Bytes
Number of bytes to pop from the stack.

See Also

Simulate_Far_Call, Simulate_Far_Ret


Simulate_Int

include vmm.inc

mov     eax, Interrupt      ; interrupt number
VMMCall Simulate_Int

Simulates an interrupt in the current virtual machine. The service first calls any hook procedures set by the Hook_V86_Int_Chain service. If no hook procedure services the interrupt, this service pushes the Client_Flags, Client_CS, and Client_IP registers on the stack of the current virtual machine. When the virtual machine resumes execution (such as when an Resume_Exec service is called), the system carries out the simulated interrupt and executes the corresponding V86 mode interrupt routine. Uses Client_CS, Client_EIP, Client_Flags, Flags.

  • No return value.
Interrupt
Number of the interrupt to simulate.

The virtual PIC device uses this service to simulate hardware interrupts. Other virtual devices use the Exec_Int service to simulate interrupts.

If the virtual machine is currently in V86 mode, this service simulates a V86 interrupt. Otherwise, the service simulates a protected-mode interrupt. Simulating an interrupt in a virtual machine running a protected-mode application can have undesirable effects if the corresponding interrupt attempts to reflect the interrupt to V86 mode.

Virtual devices that need immediate execution of an interrupt should use the Exec_Int service in a nested execution block.

See Also

Exec_Int


Simulate_Iret

include vmm.inc

VMMCall Simulate_Iret

Simulates a return from an interrupt. This service pops the top three word or doubleword values from the stack of the current virtual machine, and places the values in the Client_Flags, Client_CS, and Client_EIP or Client_IP registers. Uses Client_CS, Client_EIP, Client_ESP, Client_Flags, Flags.

  • No return value.

This service pops three word values from the stack if the segment corresponding to the return address is a 16-bit segment. Otherwise, the service pops three doubleword values.

See Also

Simulate_Int


Simulate_Pop

include vmm.inc

VMMCall Simulate_Pop

mov     [Value], eax        ; value popped from stack

Returns the word or doubleword value at the top of the stack of the current virtual machine, and adds two or four to the Client_ESP register. Uses Client_ESP, EAX, Flags.

  • Returns the value popped from virtual machine stack in the EAX register. The high word is zero if in V86 mode, or the virtual machine is running a 16-bit program.

See Also

Simulate_Push


Simulate_Push

include vmm.inc

mov     eax, Value          ; value to push
VMMCall Simulate_Push

Pushes a word or doubleword value on the stack of the current virtual machine and subtracts two or four from the Client_ESP register. Uses Client_ESP, Flags.

  • No return value.
Value
Value to push on the stack. In V86 mode or when the virtual machine is running a 16-bit program, only the low word is pushed.

See Also

Simulate_Pop


Set_PM_Int_Type

include vmm.inc

mov     eax, Interrupt  ; interrupt number
mov     edx, Type       ; 0 if trap gate, else interrupt gate
VMMCall Set_PM_Int_Type

Sets the gate type for a protected-mode interrupt vector. Uses Flags.

  • No return value.
Interrupt
Number of the interrupt to set.
Type
Type of gate to set. If this parameter is zero, the service sets a trap gate; if nonzero, it sets an interrupt gate.

An interrupt passing through an interrupt gate automatically clears the interrupt flag bit to disable interrupts. Interrupts passing through a trap gate do not modify the interrupt bit. All protected-mode interrupts default to the trap gate type, but virtual devices such as the virtual PIC device, may change some trap gates to interrupt gates so that hardware interrupts disable interrupts. The virtual PIC device leaves software interrupts, such as Interrupt 21h, unchanged. This avoids an unnecessary ring transition by eliminating the need for the software interrupt handlers to execute an sti instruction.

See Also

Get_PM_Int_Type, Set_PM_Int_Vector


Set_PM_Int_Vector

include vmm.inc

mov     eax, Interrupt       ; interrupt number
mov     cx, Segment          ; selector for interrupt routine
mov     edx, Offset          ; offset of interrupt routine
VMMCall Set_PM_Int_Vector

Sets the specified protected-mode interrupt vector to the address of the given interrupt routine. Updates the IDT. Uses Flags.

  • No return value.
Interrupt
Number of the interrupt to set.
Segment
Selector of the code segment containing the interrupt routine.
Offset
Offset to the interrupt routine. If the code segment containing the routine is a 16-bit segment, the high word of this parameter must be zero.

If the Set_PM_Int_Vector service is called before the Sys_VM_Init message, the installed interrupt routine becomes part of the default interrupt vector table for every virtual machine. Otherwise, this service affects the interrupt vector table for the current virtual machine only. By default, each table entry points to a protected-mode breakpoint procedure that reflects the interrupt to V86 mode.

See Also

Get_PM_Int_Vector, Set_PM_Int_Type, Set_V86_Int_Vector


Set_V86_Int_Vector

include vmm.inc

mov     eax, Interrupt   ; interrupt number
mov     cx, Segment      ; segment address of interrupt routine
mov     edx, Offset      ; offset of interrupt routine
VMMCall Set_V86_Int_Vector

Sets the specified real-mode interrupt vector to the address of the given interrupt routine. This routine updates the real-mode interrupt vector located in real mode memory space (located in the first 0x400 bytes of real memory space). Uses Flags.

  • No return value.
Interrupt
Number of the interrupt to set.
Segment
Segment address of the code segment containing the interrupt routine.
Offset
Offset of the interrupt routine. The high word must be zero.

If the Set_V86_Int_Vector service is called before the Sys_VM_Init message, the installed interrupt routine becomes part of the default interrupt vector table for every virtual machine. Otherwise, this service affects the interrupt vector table for the current virtual machine only.

See Also

Get_V86_Int_Vector, Set_PM_Int_Vector


Test_VM_Ints_Enabled

include vmm.inc

mov     ebx, VMHandle
mov     ebp, OFFSET32 Client_Reg_Struc
VMMCall Test_VM_Ints_Enabled
jz      VM_Interrupts_Disabled

Determines whether the current VM interrupts are enabled or disabled. Uses flags.

  • The zero flag is clear if the VM's interrupts are enabled; the zero flag is set if they are disabled.
VMHandle
Handle of the virtual machine to be tested.
Client_Reg_Struc
Address of Client_Reg_Struc structure containing the contents of the virtual machine's registers.

Simply checking the interrupt flag in the client registers is not a sufficient means of testing the condition of a VM's interrupts since another thread in the VM may have disabled the interrupts.


Unhook_V86_Int_Chain

include vmm.inc

mov     eax, Interrupt
mov     esi, OFFSET32 Hook_Proc
VMMCall Unhook_V86_Int_Chain
jc      Error_Handler

Removes the hook procedure for the specified interrupt. Uses flags.

  • Sets the carry flag if the interrupt number is invalid or the procedure was not found.
Interrupt
The interrupt for which the hook procedure should be removed.
Hook_Proc
The hook procedure which should be removed.

The hook procedure being removed must have been installed using the Hook_V86_Int_Chain.


VMM Macros

This section is an alphabetic listing of the virtual machine manager (VMM) macros. There are these macros:

ArgVar | Mono_Out
Assert_Client_Ptr | Mono_Out_At
Assert_Cur_Thread_Handle | pCall
Assert_Cur_VM_Handle | Pop_Client_State
Assert_Ints_Disabled | Push_Client_State
Assert_Ints_Enabled | Queue_Out
Assert_Thread_Handle | RestoreReg
Assert_VM_Handle | Return
Assumes_Fall_Through | SaveReg
Begin_Control_Dispatch | sCall
Begin_Service_Table | ShiftState
Begin_Touch_1st_Meg | Trace_Out
Begin_VxD_IO_Table | VMMCall
BeginProc | VMMJmp
CallRet | VxD_CODE_ENDS
cCall | VxD_CODE_SEG
Client_Ptr_Flat | VxD_DATA_ENDS
Control_Dispatch | VxD_DATA_SEG
Debug_Out | VxD_ICODE_ENDS
Debug_Printf | VxD_ICODE_SEG
Declare_Virtual_Device | VxD_IDATA_ENDS
Dispatch_Byte_IO | VxD_IDATA_SEG
Dword_Align | VxD_IO
Emulate_Non_Byte_IO | VxD_LOCKED_CODE_ENDS
End_Control_Dispatch | VxD_LOCKED_CODE_SEG
End_Service_Table | VxD_LOCKED_DATA_ENDS
End_Touch_1st_Meg | VxD_LOCKED_DATA_SEG
End_VxD_IO_Table | VxD_PAGEABLE_CODE_ENDS
EndProc | VxD_PAGEABLE_CODE_SEG
Fatal_Error | VxD_REAL_INIT_ENDS
GetVxDServiceOrdinal | VxD_REAL_INIT_SEG
IO_Delay | VxDCall
IsDebugOnlyLoaded | VxDint
LeaveProc | VxDJmp
LocalVar |


ArgVar

include vmm.inc

ArgVar varname, size, used

Declares a stack argument for a procedure.

  • No return value.
varname
Specifies the name of the variable.
size
A numeric expression specifying the size of the variable in bytes. The words BYTE, WORD, and DWORD, are acceptable as synonyms for 1, 2, and 4, respectively. If the value is not a multiple of four, the variable is padded to the nearest multiple of four.
used
An optional parameter, normally omitted. If present and identical to the word NOTUSED, indicates that this parameter is not used. In such case, the ArgVar macro will point the name at an intentionally undefined symbol.

This macro is used in writing assembly-language procedures which use the C, Pascal, or StdCall calling convention.

If the variable is a WORD, then two additional symbols are defined: varnameL refers to the low byte and varnameH refers to the high byte. If the variable is a DWORD, then six additional symbols are defined: varnameL refers to the low word, varnameLL to the low byte of the low word, varnameLH to the high byte of the low word, varnameH to the high word, varnameHL to the low byte of the high word, and varnameHH to the high byte of the high word.

When the EndProc is reached, the names of all ArgVar variables are set to an intentionally undefined symbol so that they cannot be used by accident later. (This behavior can be overridden by using the KEEPFRAMEVARS attribute on EndProc.) Here is an example procedure that uses these macros. The example procedure doesn't do anything interesting, but it illustrates the proper use of the macros.

BeginProc MyProc, CCALL

ArgVar Param1, DWORD
ArgVar Param2, WORD
ArgVar Param3, 12    ; third parameter is a 12-byte structure,
                     ;   passed by value

LocalVar Local1, DWORD
LocalVar Local2, <size FOO>

EnterProc
SaveReg <ebx, esi>
lea  eax, Local2    ; eax now points to a FOO structure on the stack
mov  cx, Param2     ; cx contains the value of Param2
mov  Local1LL, ch   ; Store ch into the low byte of the low
                    ;   word of Local1
lea  edx, Param3    ; edx points to the 128-byte structure on the stack
RestoreReg <esi, ebx>
LeaveProc
Return
EndProc MyProc

The above example illustrates several important points.

  • The first thing after the BeginProc is an optional list of ArgVars, naming the procedure arguments.
  • Immediately following the ArgVars is an optional list of LocalVars, naming the procedure local variables.
  • Immediately following the LocalVars is the EnterProc macro, which sets up the procedure local stack frame.
  • The body of the procedure may use the SaveReg and RestoreReg macros to push and pop values from the stack. Using SaveReg and RestoreReg is mandatory if you use the ESP attribute on the BeginProc macro, otherwise the macros will access the wrong stack variables because you moved the stack pointer behind their back. Furthermore, the macros do not track jump instructions, so jumping around inside an ESP procedure is fraught with peril. Unless you know what you're doing, you might be better off just not using the ESP attribute.
  • To return from a procedure, use the LeaveProc, then Return macros. Each procedure must contain exactly one LeaveProc and one Return.

See Also

Debug_Test_Valid_Handle


Assert_Cur_Thread_Handle

include debug.inc

Assert_Cur_Thread_Handle ThreadHandle, level

Asserts that the specified register is equal to the handle of the current thread.

  • No return value.
ThreadHandle
Specifies the register containing the thread handle to check. The macro is more efficient if the thread handle is in the EDI register, but any 32-bit register is allowed.
level
Optional parameter which specifies the debugging level for which the macro should generate code. The default is DeblevelNormal.

This macro does not generate code unless the DEBUG symbol is defined. If the macro generates code, the code calls the Debug_Test_Cur_Thread_Handle service.

See Also

Debug_Test_Valid_Handle


Assert_Client_Ptr

include debug.inc

Assert_Client_Ptr reg, level

Asserts that the specified register is a pointer to the current set of client registers.

  • No return value.
reg
Specifies the register containing the pointer to check. The macro is more efficient if the client pointer is in the EBP register, but any 32-bit register is allowed.
level
Optional parameter which specifies the debugging level for which the macro should generate code. The default is DeblevelNormal.

This macro does not generate code unless the DEBUG symbol is defined. If the macro generates code, the code calls the Validate_Client_Ptr service.

See Also

Debug_Test_Valid_Handle


Assert_Cur_VM_Handle

include debug.inc

Assert_Cur_VM_Handle VM, level

Asserts that the specified register is equal to the handle of the current virtual machine.

  • No return value.
VM
Specifies the register containing the virtual machine handle to check. The macro is more efficient if the thread handle is in the EBX register, but any 32-bit register is allowed.
level
Optional parameter which specifies the debugging level for which the macro should generate code. The default is DeblevelNormal.

This macro does not generate code unless the DEBUG symbol is defined. If the macro generates code, the code calls the Debug_Test_Cur_VM_Handle service.

See Also

Debug_Test_Valid_Handle


Assert_Ints_Disabled

include debug.inc

Assert_Ints_Disabled

Asserts that interrupts are currently disabled.

  • No return value.

If the DEBUG symbol is defined, the macro generates code which checks that interrupts are disabled. If interrupts are enabled, the generated code will print an error message and stop in the debugger if a debugger is installed.

See Also

Debug_Test_Valid_Handle


Assert_Ints_Enabled

include debug.inc

Assert_Ints_Enabled

Asserts that interrupts are currently disabled.

  • No return value.

If the DEBUG symbol is defined, the macro generates code which checks that interrupts are enabled. If interrupts are disabled, the generated code will print an error message and stop in the debugger if a debugger is installed.

See Also

Debug_Test_Valid_Handle


Assert_Thread_Handle

include debug.inc

Assert_Thread_Handle ThreadHandle, level, USES_FLAGS

Asserts that the specified thread handle is valid.

  • No return value. The macro does not return if the handle is not valid.
ThreadHandle
Specifies the register containing the thread handle to check. The macro is more efficient if the thread handle is in the EDI register, but any 32-bit register is allowed.
level
Optional parameter which specifies the debugging level for which the macro should generate code. The default is DeblevelNormal.
USES_FLAGS
Optional parameter which, if equal to the literal USES_FLAGS, indicates that the macro is allowed to modify the flags register. The default is to preserve flags.

This macro does not generate code unless the DEBUG symbol is defined. If the macro generates code, the code calls the Debug_Test_Valid_Thread_Handle service.

See Also

Debug_Test_Valid_Handle


Assert_VM_Handle

include debug.inc

Assert_VM_Handle VM, level, USES_FLAGS

Determines whether the specified virtual machine handle is valid.

  • No return value. The macro does not return if the handle is not valid.
VM
Specifies the register containing the virtual machine handle to check. The macro is more efficient if the virtual machine handle is in the EBX register, but any 32-bit register is allowed.
level
Optional parameter that specifies the debugging level for which the macro should generate code. The default value is DevlevelNormal.
USES_FLAGS
Optional parameter which, if equal to the literal USES_FLAGS, indicates that the macro is allowed to modify the flags register. The default value preserves flags.

This macro is only available in the debugging version of Windows.

This macro does not generate code unless the DEBUG symbol is defined. If the macro generates code, the code calls the Debug_Test_Valid_Handle service.

See Also

Debug_Test_Valid_Handle


Assumes_Fall_Through

include debug.inc

Assumes_Fall_Through labelname

Asserts at compile time that the indicated label comes next.

  • No return value.
labelname
Name of the label to check.

This macro may be used when one procedure falls through to another, so that an error will be raised at compile time if the condition is not met. Example:

BeginProc FirstProc
    mov        eax, 1
    Assumes_Fall_Through SecondProc        ; fall through to SecondProc
EndProc FirstProc

BeginProc SecondProc
    ... do something with EAX ...
    retd
EndProc SecondProc

If anybody ever inserts code between FirstProc and SecondProc, the Assumes_Fall_Through macro will raise an error, thus catching the bug automatically. This may look stupid here, but imagine if there was a 200-line comment block between the two procedures.

See Also

Debug_Test_Valid_Handle


Begin_Control_Dispatch

include vmm.inc

Begin_Control_Dispatch DeviceName

Builds a table for dispatching messages passed to the control procedure for the specified virtual device. This macro is used in conjunction with the Control_Dispatch and End_Control_Dispatch macros.

  • No return value.
DeviceName
Name of the virtual device. The macro uses this parameter to construct the label for the control procedure (appends _Control to the end of this name). This control procedure label must also be specified in the Declare_Virtual_Device macro.

The Control_Dispatch macro can be used without Begin_Control_Dispatch, but then it the programmer's responsibility to declare a procedure in locked code (VxD_LOCKED_CODE_SEG), and clear the carry flag for any unprocessed messages. The advantage in using Begin_Control_Dispatch macro is when a large number of messages are processed by a device. The macro builds a jump table which usually requires less code than the sequence of compare and jump instructions that are generated when Control_Dispatch is used alone.

The following example builds a complete dispatch table for the virtual device named MyDevice:

Begin_Control_Dispatch MyDevice
Control_Dispatch  Device_Init, MyDeviceInitProcedure
Control_Dispatch  Sys_VM_Init, MyDeviceSysInitProcedure
Control_Dispatch  Create_VM,   MyDeviceCreateVMProcedure
End_Control_Dispatch MyDevice

An alternative method for writing the control procedure is as follows:

BeginProc MyDevice_Control
Control_Dispatch  Device_Init, MyDeviceInitProcedure
Control_Dispatch  Sys_VM_Init, MyDeviceSysInitProcedure
Control_Dispatch  Create_VM,   MyDeviceCreateVMProcedure
clc                                              ; Don't forget
ret                                              ; these two lines!
EndProc MyDevice_Control

If you use the CallType variant of the Control_Dispatch macro, you may not use the Begin_Control_Dispatch macro; you must use this alternative method.

NOTE Do not combine Begin_Control_Dispatch with private system control codes. The following code snippet causes the assembler to appear to hang:

    Begin_Control_Dispatch VDEVICE

    ; <other Control_Dispatch macros go here>
    Control_Dispatch BEGIN_RESERVED_PRIVATE_SYSTEM_CONTROL OnPrivateSysCtrl

    End_Control_Dispatch VDEVICE

Cause

=====

When you use the Begin_Control_Dispatch and End_Control_Dispatch macros, the vmm.inc header file builds a jump table to perform the dispatch. Since BEGIN_RESERVED_PRIVATE_SYSTEM_CONTROL has numerical value 70000000h, the vmm.inc header file attempts to build a jump table with over 1.8 billion entries. This causes the assembler to appear to hang.

Workaround

Replace Begin_Control_Dispatch with a BeginProc and End_Control_Dispatch with clc / ret / EndProc. The above code snippet would be transformed as follows:

    BeginProc VDEVICE_Control, LOCKED

    ; <other Control_Dispatch macros go here>
    Control_Dispatch BEGIN_RESERVED_PRIVATE_SYSTEM_CONTROL OnPrivateSysCtrl

    clc
    ret
    EndProc VDEVICE_Control

See Also

Control_Dispatch, Declare_Virtual_Device, End_Control_Dispatch


BeginProc

include vmm.inc

BeginProc ProcName, Attributes

Marks the start of a procedure having the specified attributes.

  • No return value.
ProcName
Name of the procedure to create.
Attributes
One or more procedure attributes. Can be any number of these attributes, with multiple attributes separated by commas:
Attribute | Description
HIGH_FREQ | Specifies a frequently called procedure. The macro aligns the start of the procedure on a doubleword boundary to optimize calls to the procedure.
PUBLIC | Creates a global procedure that other procedures in the virtual device can call.
PCALL | Use the Pascal calling convention.
CCALL | Use the C calling convention.
SCALL | Use the StdCall calling convention.
ESP | Use ESP instead of EBP to access arguments. See caveats below.
HOOK_PROC, hook_var | This procedure is being used to hook a service or fault. See remarks below.
segment_type | Place the procedure in the segment_type code segment. Valid segment types are LOCKED, INIT, PAGEABLE, STATIC, DEBUG_ONLY, SYSEXIT, INT21, RARE, W16, W32, VMCREATE, VMDESTROY, THCREATE, THDESTROY, VMSUSPEND, VMRESUME, PNP, DOSVM, and LOCKABLE.

If the DEBUG symbol is defined, then the following keywords are also recognized. (If the DEBUG symbol is not defined, then the following keywords have no effect.)
Attribute | Description
NO_LOG | Prevents entry to this procedure from being logged via Log_Call_Proc.
SERVICE | Indicates that this procedure is an exported service. Additional code is generated to ensure that the service is not called asynchronously, as well some code for system performance profiling, and checking that basic ring 0 assumptions are not violated.
ASYNC_SERVICE | The same as SERVICE, except that the check that the service is not called asynchronously is not performed.
NO_PROFILE | If the procedure is a service, disables the generation of code which does performance profiling.
NO_TEST_CLD | Disables the normal check that the processor direction flag is clear (up).
TEST_BLOCK | Generate code to check on entry to the procedure that there are no outstanding ENTER_NOBLOCK calls. This is the default if the procedure resides in pageable code. See _Debug_Flags_Service for more information.
TEST_REENTER | Generate code to check on entry to the procedure that VMM has not been re-entered. See _Debug_Flags_Service for more information.
NEVER_REENTER | Generate code to check on entry to the procedure that VMM has not been re-entered, not even when Begin_Reentrant_Execution has been called. See _Debug_Flags_Service for more information.
NOT_SWAPPING | Generate code to check on entry to the procedure that the current thread is not swapping. See _Debug_Flags_Service for more information.

If a procedure is marked ASYNC_SERVICE, then it must be re-entrant, must not call synchronous services, and must restrict itself to locked code and data. Asynchronous services may be called by interrupt handling routines when processing interrupts. Therefore, virtual devices which export asynchronous services must be prepared for the service to be called any time interrupts are disabled.

Marking a procedure as PCALL, SCALL, or CCALL indicates to the ArgVar, LocalVar, EnterProc, LeaveProc and Return macros how code should be generated to access procedure parameters and local variables, and how code should be generated to return to the calling procedure.

If a procedure is marked ESP, then extra care must be taken to maintain the assumptions made by the ArgVar and LocalVar macros. All stack pushes must be performed with the SaveReg macro, and all stack pops must be performed with the RestoreReg macro. You may not adjust the stack manually, and you may not jump over code that adjusts the stack. These are relatively severe restrictions, but that's the way it is. If you can't live within them, then don't use the ESP attribute. Nobody's forcing you.

If a procedure will be passed to Hook_Device_Service, Hook_V86_Fault, Hook_PM_Fault, or Hook_VMM_Fault, then it must be marked with the HOOK_PROC attribute so that the service can be unhooked. This is important, even if you do not plan to unhook the service or fault yourself. Failure to comply may prevent other virtual devices from unhooking the service. The hook_var parameter is the name of the variable into which the address of the previous hook will be stored. See the discussion of hook procedure in the Overview for additional information about hook procedures.

If a segment type is provided, then the procedure will be placed in the segment named VxD_segment_type_CODE_SEG. This is provided for convenience in procedure-level page tuning.

See Also

EndProc


Begin_Service_Table

include vmm.inc

Begin_Service_Table DeviceName
Begin_Service_Table DeviceName, DefSegment

Marks the start of the service table for a virtual device. A virtual device uses the service table to export the names and addresses of its services. Other virtual devices can use the VxDCall macro to call these services.

  • No return value.
DeviceName
Name of the virtual device. This name is used to create a macro, named DeviceName_Service, that is used in the table to define each exported service. For more information about the macro, see below.
DefSegment
Not used with Windows95 VxDs. This parameter exists solely for compatibility with Windows 3.1 VxDs.

A virtual device exports its services by defining the symbol Create_DeviceName_Service_Table before using the Begin_Service_Table macro. Virtual devices that call these service also use the Begin_Service_Table macro but must not define the Create_DeviceName_Service_Table symbol.

The complete service table has the following form:

Begin_Service_Table DeviceName

DeviceName_Service Procedure, LocalSeg

.

.

.

End_Service_Table DeviceName

The DeviceName_Service macro, created by Begin_Service_Table, adds the specified service to the table. A table may have any number of these macros.

The Procedure parameter specifies the name of the service to add to the table. If RESERVED is given, the macro reserves an entry in the table instead of adding a procedure.

The LocalSeg parameter specifies which segment contains the procedure. This parameter is optional and exists for compatibility with Windows 3.1. You shouldn't need to provide a local segment.

See Also

End_Service_Table, VxD_LOCKED_DATA_SEG


Begin_Touch_1st_Meg

include debug.inc

Begin_Touch_1st_Meg

Enables the first 1 megabyte of memory for the current virtual machine. Virtual devices use this macro to examine and modify addresses in the first megabyte. This macro is intended to be used for debugging purposes.

  • No return value.

This macro does not generate code unless the DEBUG symbol is defined. If the macro generates code, the code calls the Enable_Touch_1st_Meg service.

See Also

Enable_Touch_1st_Meg, End_Touch_1st_Meg


Begin_VxD_IO_Table

include vmm.inc

Begin_VxD_IO_Table TableName

Marks the beginning of an I/O table. Virtual devices use the macro in conjunction with the End_VxD_IO_Table and VxD_IO macros to create a table of I/O callback procedures for the Install_Mult_IO_Handlers service.

TableName
Name of the table. This parameter can be used in subsequent calls to the Install_Mult_IO_Handlers to specify the address of the table.

See Also

Install_Mult_IO_Handlers, End_VxD_IO_Table, VxD_IO


CallRet

include vmm.inc

CallRet Procedure

Calls or jumps to the specified procedure, depending on whether the DEBUG symbol is defined. If DEBUG is defined, the macro generates a call to the procedure followed by a return instruction. Otherwise, the macro generates a jump to the procedure.

  • No return value.
Procedure
Name of the procedure or service to call.

See Also

Log_Proc_Call


cCall

include vmm.inc

cCall Procedure
cCall Procedure, Param1, Flags
cCall Procedure, <Param1, Param2, Param3, ..., ParamN>, Flags

Pushes the specified parameters on the stack and calls the specified procedure. When the procedure returns, the macro pops the parameters from the stack.

  • The return value depends on the specified procedure.
Procedure
Name of the procedure to call. This parameter can be either a local or public procedure, but must be defined within the virtual device making the call.
Param1, Param2, Param3, ..., ParamN
Optional parameters to pass to the procedure. If more than one parameter is given, they must be separated with commas and enclosed in angle brackets (<>).
Flags
Optional parameter, that if set to the value PRESERVE_FLAGS, causes the cCall macro to preserve the flags register on return from the called procedure. The cCall macro normally changes the contents of the flags register as part of its cleanup operations.

This macro pushes the parameters using the C-language calling convention, in order from right to left, then removes the parameters from the stack after the procedure returns. It also assumes that the called procedure follows the C-language register conventions, viz., that the EAX, ECX, EDX, and flags registers may be modified by the call, and that the return value is placed in the EAX register (and sometimes also the EDX register). If your procedure does not follow these rules, you should not use the cCall macro.

See Also

VMMCall, VxDCall


Client_Ptr_Flat

include vmm.inc

Client_Ptr_Flat LinAddr, Segment, Offset
Client_Ptr_Flat LinAddr, Segment, Offset, USES_EAX

Converts the specified segment:offset or selector:offset or segment:offset pair from the client register into a linear address.

  • Returns the linear address in the register specified by the LinAddr parameter, if successful. If the specified selector is invalid, the service returns – 1 in the specified register.
LinAddr
32-bit register to receive the linear address.
Segment
Client segment register containing the segment address or selector to convert.
Offset
Client register containing the address offset to convert. If this optional parameter is not given, the macro converts the address using address offset 0. You can specify either a 16-bit or 32-bit general-purpose register. The macro will use the low word or the full 32-bit register, depending on whether the client is in 16-bit or 32-bit mode.
USES_EAX
If the word USES_EAX is appended to the macro call, the macro will use the EAX register as a scratch register. Normally the macro preserves all registers except LinAddr. The macro is slightly more efficient if it is allowed to damage the EAX register.

The Client_Ptr_Flat macro uses the Map_Flat service.

This example converts the address Client_DS:Client_(E)DX, and places the corresponding linear address in the EAX register:

Client_Ptr_Flat eax, DS, DX

See Also

Map_Flat


Control_Dispatch

include vmm.inc

Control_Dispatch Message, Procedure
Control_Dispatch Message, Procedure, CallType, <Param1, Param2, ...>

Dispatches the given control message to the specified procedure.

  • No return value.
Message
Identifies the control message. Can be one of the following values:
Value | Description
Begin_PM_App | A protected-mode application is starting.
Close_VM_Notify | A virtual machine is closing.
Create_Thread | New thread being created.
Create_VM | A virtual machine is being created.
Critical_Reboot_Notify | System is restarting (interrupt disabled).
Debug_Query | Requests for virtual device's debugging interface.
Destroy_Thread | Thread being destroyed.
Destroy_VM | A virtual machine is being destroyed.
Device_Init | Virtual devices initializing (interrupts enabled).
Device_Reboot_Notify | System is restarting (interrupts enabled).
End_PM_App | A protected-mode application is ending.
Init_Complete | All virtual devices have initialized.
PNP_New_Devnode | New devnode (directed).
Power_Event | Power is being suspended or resumed.
Reboot_Processor | Virtual device must restart system if it can.
Set_Device_Focus | A virtual device is taking the focus.
Sys_Critical_Exit | System is terminating (interrupt disabled).
Sys_Critical_Init | Virtual devices initializing (interrupts disabled).
Sys_VM_Init | System VM is being created.
Sys_Dynamic_Device_Exit | Dynamic VxD being unloaded (directed).
Sys_Dynamic_Device_Init | Dynamic VxD being loaded (directed).
Sys_VM_Terminate | System VM is being destroyed.
System_Exit | System is terminating (interrupts enabled).
Terminate_Thread | Thread being terminated.
Thread_Init | Thread being initialized.
Thread_Not_Executeable | Thread has stopped executing.
VM_Critical_Init | Virtual machine being created (interrupts disabled).
VM_Init | Virtual machine being created (interrupts enabled).
VM_Not_Executable | Virtual machine has stopped executing.
VM_Resume | Virtual machine execution resumed.
VM_Suspend | Virtual machine execution suspended.
VM_Terminate | Virtual machine begin destroyed.
W32_DeviceIoControl | Win32 DeviceIoControl entry (directed).

Another value defined in vmm.h is also acceptable.

Procedure
Name of the procedure to which to dispatch the message.
CallType
Optional parameter that describes the calling convention employed by the procedure. The default value indicates that the procedure is called directly without any special pre- or post-processing. Otherwise, the value may be cCall, pCall, or sCall, indicating that the procedure should be called with the C, Pascal, or StdCall calling convention, respectively. See below for additional remarks.
Param1, Param2, ...
Optional parameters to be passed to the procedure. Typically, registers are pushed as parameters. See below for additional remarks.

This macro is typically used in conjunction with the Begin_Control_Dispatch and End_Control_Dispatch macros to build a dispatch table. The Control_Dispatch macro can be used without the Begin_Control_Dispatch macro, but becomes the programmer's responsibility to declare a procedure in locked code (VxD_LOCKED_CODE_SEG), and clear the carry flag for any messages not processed.

If you use the CallType variant of this macro, then this macro may not be combined with the Begin_Control_Dispatch and End_Control_Dispatch macros.

See Also

Begin_Control_Dispatch, End_Control_Dispatch


Debug_Out

include debug.inc

Debug_Out String
Debug_Out String, level

Writes the specified string to the debugging device, and halts in the debugger if a debugger is attached.

  • No return value.
String
String to display. The string must be enclosed in double quotation marks. The string can contain register placeholders in the same forms as described for the Out_Debug_String service.
level
Optional symbol indicating the debugging level for which code should be generated. If the value of the Deblevel symbol is greater than or equal to level, then code is generated. Otherwise, code is not generated. The symbol can be DeblevelNormal or DeblevelMax. The default is DeblevelNormal.

Additional macros exist, such as Debug_OutX, where X is a conditional jump type, i.e., something that can follow the letter j to form a conditional jump instruction. In such case, the debug-out is performed only if the condition is satisfied.

Examples:

; The following message is printed only if Deblevel  Deblevelmax
Debug_Out "Error!  Mumble mumble", Deblevelmax
cmp    nFrobs, 5
Debug_OutA "Error! More than 5 frobs!"

cmp [esi].dwSignature, 31415927h
Debug_OutNZ "Error!  Invalid signature!"

The assembler generates code for the macro only if the constant DEBUG is defined before including the DEBUG.INC file.

See Also

Out_Debug_String, Test_Debug_Installed


Debug_Printf

include debug.inc

Debug_Printf FormatString, <Param1, Param2, ...>, level

Writes the specified string to the debugging device, using C-style formatting.

  • No return value.
FormatString
Format string for output. This string may contain C-style formatting sequences.
Param1, Param2, ...
Substitution arguments for the format string. This parameter is optional; if omitted, the FormatString must not contain any % substitutions. Moreover, there must be enough parameters to correspond to the number of substitutions required by the format string.
level
Optional symbol indicating the debugging level for which code should be generated. If the value of the Deblevel symbol is greater than or equal to level, then code is generated. Otherwise, code is not generated. The symbol can be DeblevelNormal or DeblevelMax. The default is DeblevelNormal.

The assembler generates code for the macro only if the constant DEBUG is defined before including the DEBUG.INC file, in which case it uses _Debug_Printf_Service to do the work. See the description of _Debug_Printf_Service for additional remarks and restrictions.

See Also

Out_Debug_String, Test_Debug_Installed


Declare_Virtual_Device

include vmm.inc

Declare_Virtual_Device Name, MajorVer, MinorVer, CtrlProc, DeviceNum,
                       InitOrder, V86Proc, PMProc

Defines the name, device number, control procedure, and other attributes of a virtual device. Every virtual device must use the Declare_Virtual_Device macro.

  • No return value.
Name
Name of the virtual device.
MajorVer
Value specifying the major version number for the virtual device.
MinorVer
Value specifying the minor version number for the virtual device.
CtrlProc
Name of the control procedure for the virtual device. The control procedure handles all system control messages sent to the virtual device. For most virtual devices, this parameter is the name of the procedure created by the Begin_Control_Dispatch macro.
DeviceNum
Device identifier for the virtual device. If the virtual device replaces an existing virtual device, the device identifier must be identical to the device identifier of the virtual device being replaced. Otherwise, the value must be Undefined_Device_ID or a value previously obtained from Microsoft.

Since Windows 95 supports name-based VxD services, it is no longer necessary to obtain a virtual device identifier from Microsoft. Instead, set the DeviceNum to Undefined_Device_ID and use name-based services to access your VxD. (Do not make up device numbers.)

InitOrder
Value specifying the initialization order of the virtual device relative to other virtual devices. If you are replacing an existing virtual device, this value must be the same as that of the device you are replacing. If your device is not sensitive to initialization order, use Undefined_Init_Order. If your device needs to initialize at a particular time relative to another device, make the initialization order relative to the init order of that other device. When doing so, use a generous offset such as XX_Init_Order + 00040000h or XX_Init_Order – 0004000h, so as to allow room for additional devices to be inserted later. Do not use values like XX_Init_Order + 1 or XX_Init_Order – 1. Do not use VMM_Init_Order or Debug_Init_Order.
V86Proc
Name of the V86-mode API procedure. This procedure processes any calls to the virtual device made by V86-mode applications running in a virtual machine. This parameter is optional.
PMProc
Name of the protected-mode API procedure. This procedure processes any calls to the virtual device made by protected-mode applications running in a virtual machine. This parameter is optional.

See Also

Begin_Control_Dispatch


Dispatch_Byte_IO

include vmm.inc

Dispatch_Byte_IO In_Proc, Out_Proc

Checks the size of the I/O request and dispatches the request to either the Simulate_IO service, or to the specified single-byte input or output procedure. I/O callback procedures use this macro to simplify processing of I/O requests.

  • No return value.
In_Proc
Name of the procedure to carry out a single-byte input operation. If this parameter is the Fall_Through keyword, the macro ignores input operations.
Out_Proc
Name of the procedure to carry out a single-byte output operation. If this parameter is the Fall_Through keyword, the macro ignores output operations.

The EAX, EBX, ECX, EDX, and EBP registers must contain values specified as valid input parameters for the Simulate_IO service. Dispatch_Byte_IO checks the ECX register for the I/O type. If this type specifies an I/O request that is larger than a byte, the macro jumps to the Simulate_IO service.

See Also

Emulate_Non_Byte_IO, Simulate_IO


Dword_Align

include vmm.inc

Dword_Align SegName

Aligns the specified segment on a doubleword boundary by inserting nop instructions.

  • No return value.
SegName
Name of the segment to align. This parameter can be _TEXT, _ITEXT, or _LTEXT.


Emulate_Non_Byte_IO

include vmm.inc

Emulate_Non_Byte_IO

Checks the size of the I/O request and jumps to the Simulate_IO service if the request is larger than a byte. I/O callback procedures use this macro to simplify processing of I/O requests.

  • No return value.

The EAX, EBX, ECX, EDX, and EBP registers must contain values specified as valid input parameters for the Simulate_IO service. Emulate_Non_Byte_IO checks the ECX register for the I/O type. If this type specifies an I/O request that is larger than a byte, the macro jumps to the Simulate_IO service.

See Also

Dispatch_Byte_IO, Simulate_IO


End_Control_Dispatch

include vmm.inc

End_Control_Dispatch DeviceName

Marks the end of a dispatch table for a virtual device. This macro is used in conjunction with the Control_Dispatch and Begin_Control_Dispatch macros to build the table.

  • No return value.
DeviceName
Name of the virtual device. This name must have been used with the Begin_Control_Dispatch macro that started the table.

See Also

Begin_Control_Dispatch, Control_Dispatch


EndProc

include vmm.inc

EndProc ProcName
EndProc ProcName, NoCheck

Marks the end of a procedure definition. This macro is used in conjunction with the BeginProc macro to define a procedure in a virtual device.

  • No return value.
ProcName
Name of the procedure. This name must have been used in the BeginProc macro that started the procedure definition.
NoCheck
If the optional NoCheck keyword is provided, then the normal compile-time checks for stack balance and proper use of the ArgVar, LocalVar, EnterProc, LeaveProc, and Return macros is suppressed. The default value performs the checks.

See Also

BeginProc


End_Service_Table

include vmm.inc

End_Service_Table DeviceName, DefSegment

Marks the end of the service table for a virtual machine. This macro is used in conjunction with the Begin_Service_Table macro to create a service table.

  • No return value.
DeviceName
Name of the virtual device. This name must be the same as specified by the corresponding Begin_Service_Table macro.
DefSegment
Not used by Windows95 VxDs and should be omitted. This parameter exists for compatibility with Windows 3.1 VxDs.

See Also

Begin_Service_Table


End_Touch_1st_Meg

include debug.inc

End_Touch_1st_Meg

Disables the first 1 megabyte of memory for the current virtual machine. Virtual devices use this macro in conjunction with the Begin_Touch_1st_Meg macro to examine and modify addresses in the first megabyte. This macro is intended to be used for debugging purposes.

  • No return value.

This macro does not generate code unless the DEBUG symbol is defined. If the macro generates code, the code calls the Disable_Touch_1st_Meg service.

See Also

Begin_Touch_1st_Meg, Disable_Touch_1st_Meg


End_VxD_IO_Table

include vmm.inc

End_VxD_IO_Table TableName

Marks the end of an I/O table. Virtual devices use the macro in conjunction with the Begin_VxD_IO_Table and VxD_IO macros to create a table of I/O callback procedures for the Install_Mult_IO_Handlers service.

  • No return value.
TableName
Name of the I/O table. This parameter must have been previously defined in a matching Begin_VxD_IO_Table macro.

See Also

Begin_VxD_IO_Table


Fatal_Error

include vmm.inc

Fatal_Error Msg_Ptr, Exit_Flags

Calls the Fatal_Error_Handler service which terminates Windows. A virtual device typically calls this macro in response to an unrecoverable error. The macro passes the Msg_Ptr and Exit_Flags parameters (if given) to Fatal_Error_Handler.

  • This macro never returns.
Msg_Ptr
Address of a null-terminated string. This parameter is optional.
Exit_Flags
Exit flags. This optional parameter can be the following value:
Value | Meaning
EF_Hang_On_Exit | Hangs the system on a fatal exit.

The following example quits Windows without displaying an error message:

Fatal_Error

The following example quits Windows, and prints the error message pointed to by My_Err_Msg:

Fatal_Error <OFFSET32 My_Err_Msg>

See Also

Fatal_Error_Handler


GetVxDServiceOrdinal

include vmm.inc

GetVxDServiceOrdinal reg, ServiceName

#include <vmm.h>

DWORD dwServiceOrdinal = GetVxDServiceOrdinal(ServiceName);

Obtains the virtual device service ordinal, for use by Hook_Device_Service.

  • The assembly language macro returns the ordinal for the named service in the specified register. The C language macro returns the ordinal as its return value.
reg
Register to receive the virtual device service ordinal.
ServiceName
Name of service for which to obtain the ordinal.

This macro must be used whenever you need to obtain a virtual device service ordinal. The method employed by Windows 3.1 no longer works.

Example:

    GetVxDServiceOrdinal eax, DOSMGR_Begin_V86_App
    mov      esi, offset32 BeginPmAppHook
    VMMCall  Hook_Device_Service

VxD_REAL_INIT_SEG


IO_Delay

include vmm.inc

IO_Delay

Delays the execution of the next instruction so that an I/O device has time to carry out an I/O operation.

  • No return value.

This macro generates a jmp instruction to the next instruction.


IsDebugOnlyLoaded

include debug.inc

IsDebugOnlyLoaded
IsDebugOnlyLoaded labelname

Skips to the named label if debug-only segments are not loaded. Yes, this macro's name is backwards.

  • If labelname is omitted, sets the zero flag if debug-only segments are not present.
labelname
Optional label to jump to if debug-only segments are not loaded. If omitted, this macro sets flags as described above.

This macro must be used whenever code that is unconditionally loaded calls into code or accesses memory in debug-only segments, lest you accidentally access objects that don't exist. Example:

    IsDebugOnlyLoaded notracing
    call    Tracing            ; the Tracing procedure resides in a debug-only segment
notracing:

See Also

Debug_Test_Valid_Handle


LeaveProc

include vmm.inc

LeaveProc
LeaveProc PRESERVE_FLAGS

Prepares to exit a procedure by removing local stack variables.

  • No return value.
PRESERVE_FLAGS
An optional parameter, normally omitted. If present and identical to the word PRESERVE_FLAGS, indicates that the act of removing local stack variables should not modify the flags register. This is in violation of the C, Pascal, and StdCall calling conventions (that flags are unimportant) and generates slower code, so it should be avoided if at all possible.

This macro is used in writing assembly-language procedures which use the C, Pascal, or StdCall calling convention. See the description of the ArgVar macro for additional information.

See Also

Debug_Test_Valid_Handle


LocalVar

include vmm.inc

LocalVar varname, size
LocalVar varname, size, PACK

Declares a stack local variable for a procedure.

  • No return value.
varname
Specifies the name of the variable.
size
A numeric expression specifying the size of the variable in bytes. The words BYTE, WORD, and DWORD, are acceptable as synonyms for 1, 2, and 4, respectively. If the value is not a multiple of four, the variable is padded to the next multiple of four.
PACK
An optional parameter, normally omitted. If present and identical to the word PACK, indicates that the traditional padding to the next multiple of four is suppressed. Packing local variables should be done with care, lest you end up with a total size of local variables not a multiple of four.

This macro is used in writing assembly-language procedures which use the C, Pascal, or StdCall calling convention. See the description of the ArgVar macro for additional information.

If the variable is a WORD, then two additional symbols are defined: varnameL refers to the low byte and varnameH refers to the high byte. If the variable is a DWORD, then six additional symbols are defined: varnameL refers to the low word, varnameLL to the low byte of the low word, varnameLH to the high byte of the low word, varnameH to the high word, varnameHL to the low byte of the high word, and varnameHH to the high byte of the high word.

When the EndProc is reached, the names of all LocalVar variables are set to an intentionally undefined symbol so that they cannot be used by accident later. (This behavior can be overridden by using the KEEPFRAMEVARS attribute on EndProc.) Here is an example of the PACK attribute:

LocalVar MyLocal, DWORD
LocalVar First, BYTE, PACK
LocalVar Second, BYTE, PACK
LocalVar Third, BYTE, PACK
LocalVar Fourth, BYTE, PACK

This example declares eight bytes of local variables. The first four bytes are a DWORD, named MyLocal. The fifth byte is a BYTE variable named First, the sixth a BYTE variable named Second, the seventh a BYTE variable named Third, and the eighth a BYTE variable named Fourth. If the PACK attributes were omitted, this sequence of declarations would have created twenty bytes of local variables, with three bytes of padding inserted after each BYTE variable. Note carefully that the BYTE variables come in groups of four so as to maintain stack dword alignment.

See Also

Debug_Test_Valid_Handle


Mono_Out

include debug.inc

Mono_Out String, nocrlf

Calls the Out_Mono_String service to display the given string.

  • No return value.
String
String to display, enclosed in double quotation marks. The string can contain register placeholders in the same forms as described for the Out_Mono_String service.
nocrlf
Optional parameter specifying that the macro should not append a carriage return and newline character combination to the string. If this parameter is not given, the macro appends the character combination by default.

The assembler generates code for the macro only if the DEBUG constant is defined before including the DEBUG.INC file.

The following example writes a string to the secondary display device:

Mono_Out "Element not found"

The following example writes a string containing the value of the AX register to the debugging device:

Mono_Out "AX value is #AX"

See Also

Out_Mono_String


Mono_Out_At

include debug.inc

Mono_Out_At Row, Column, String, nocrlf

Calls the Set_Mono_Cur_Pos service to position the cursor, then calls the Out_Mono_String service to display the given string.

  • No return value.
Row and Column
Row and column number at which to position the cursor before displaying the string.
String
String to display, enclosed in double quotation marks. The string can contain register placeholders in the same forms as described for the Out_Mono_String service.
nocrlf
Optional parameter specifying that the macro should not append a carriage return and newline character combination to the string. If this parameter is not given, the macro appends the character combination by default.

The assembler generates code for the macro only if the DEBUG constant is defined before including the DEBUG.INC file.

The following example writes a string starting at the position (10,10) on the secondary display device:

Mono_Out_At 10,10,"Element not found"

See Also

Out_Mono_String, Set_Mono_Cur_Pos


pCall

include vmm.inc

pCall Procedure
pCall Procedure, Param1
pCall Procedure, <Param1, Param2, Param3, ..., ParamN>

Pushes the specified parameters on the stack and calls the specified procedure. The called procedure is expected to remove the parameters from the stack.

  • The return value depends on the specified procedure.
Procedure
Name of the procedure to call. This parameter can be either a local or public procedure, but must be defined within the virtual device making the call.
Param1, Param2, Param3, ..., ParamN
Parameters to pass to the procedure. If more than one parameter is given, they must be separated with commas and enclosed in angle brackets (<>). Parameters are optional.

This macro pushes the parameters using the Pascal-language calling convention, in order from left to right. It also assumes that the called procedure follows the Pascal-language register conventions, viz., that the EAX, ECX, EDX, and flags registers may be modified by the call, and that the return value is placed in the EAX register (and sometimes also the EDX register). If your procedure does not follow these rules, you should not use the pCall macro.

See Also

VMMCall, VxDCall


Pop_Client_State

include vmm.inc

Pop_Client_State
Pop_Client_State USES_ESI

Restores the client registers for the virtual machine.

  • No return value.
USES_ESI
Optional parameter specifying that the macro may use the ESI register as a scratch register. Normally, Pop_Client_State preserves all registers. Slightly more efficient code is generated if ESI may be used.

This macro must not be used unless the Push_Client_State macro was previously used to save the client registers.

See Also

Push_Client_State


Push_Client_State

include vmm.inc

Push_Client_State
Push_Client_State USES_ESI

Copies the client state to the protected-mode stack.

  • No return value.
USES_ESI
Optional parameter specifying that the macro may use the ESI register as a scratch register. Normally, Push_Client_State preserves all registers. Slightly more efficient code is generated if ESI may be used.

This macro reserves space on the stack for the client registers.

A virtual device must use the Pop_Client_State macro to restore the client registers, and free the reserve stack space.

See Also

Pop_Client_State


Queue_Out

include debug.inc

Queue_Out String, Value1, Value2

Calls the Queue_Debug_String service to queue the given string for display at a later time.

  • No return value.
String
String to display, enclosed in double quotation marks. The string can contain register placeholders in the same forms as described for the Queue_Debug_String service.
Value1
Value to queue with the string. If the string contains the #EAX or ?EAX placeholder, this value is used when the string is displayed.
Value2
Value to queue with the string. If the string contains the #EBX or ?EBX placeholder, this value is used when the string is displayed.

The assembler generates code for the macro only if the DEBUG constant is defined before including the DEBUG.INC file.

The following example queues a string:

Queue_Out "Element not found"

The following example queues a string containing the value of the EAX register to the debugging device:

Queue_Out "EAX value is #EAX", EAX

See Also

Queue_Debug_String


RestoreReg

include vmm.inc

RestoreReg <reg1, reg2, reg3, ...>

Pops values off the stack.

  • No return value.

RestoreReg pops the values off the stack in the order specified. Note that if this is to match a corresponding SaveReg, the values need to be specified in reverse order in the RestoreReg, compared to the SaveReg. The arguments are typically the names of registers, but can be anything that can validly follow the 'pop' opcode. The special name 'fd' pops flags via the 'popfd' instruction and the special name 'ad' pops all registers via the 'popad' instruction.

Using the RestoreReg macro instead of coding the corresponding instructions manually is required if the procedure is using an ESP-based stack frame.

See the description of the ArgVar macro for additional information.

See Also

Debug_Test_Valid_Handle


Return

include vmm.inc

Return

Return from a procedure, possibly removing stack arguments as well.

  • No return value.

This macro is used in writing assembly-language procedures which use the C, Pascal, or StdCall calling convention. If the Pascal or StdCall calling convention is used, the procedure will remove parameters from the stack on return. f the C calling convention is used, then it is the caller's responsibility to remove the parameters from the stack.

See the description of the ArgVar macro for additional information.

See Also

Debug_Test_Valid_Handle


SaveReg

include vmm.inc

SaveReg <reg1, reg2, reg3, ...>

Push registers or other things onto the stack.

  • No return value.

This macro pushes each of its arguments onto the stack in the order specified. The arguments are typically the names of registers, but can be anything that can validly follow the 'push' opcode. The special name 'fd' pushes flags via the 'pushfd' instruction and the special name 'ad' pushes all registers via the 'pushad' instruction.

Using the SaveReg macro instead of coding the corresponding instructions manually is required if the procedure is using an ESP-based stack frame.

See the description of the ArgVar macro for additional information.

See Also

Debug_Test_Valid_Handle


sCall

include vmm.inc

sCall Procedure
sCall Procedure, Param1
sCall Procedure, <Param1, Param2, Param3, ..., ParamN>

Pushes the specified parameters on the stack and calls the specified procedure. The called procedure is expected to remove the parameters from the stack.

  • The return value depends on the specified procedure.
Procedure
Name of the procedure to call. This parameter can be either a local or public procedure, but must be defined within the virtual device making the call.
Param1, Param2, Param3, ..., ParamN
Parameters to pass to the procedure. If more than one parameter is given, they must be separated with commas and enclosed in angle brackets (<>). Parameters are optional.

This macro pushes the parameters using the StdCall calling convention, in order from left to right. It also assumes that the called procedure follows the StdCall-language register conventions, viz., that the EAX, ECX, EDX, and flags registers may be modified by the call, and that the return value is placed in the EAX register (and sometimes also the EDX register). If your procedure does not follow these rules, do not use the sCall macro.

See Also

VMMCall, VxDCall


ShiftState

include vkd.inc

ShiftState Mask, Compare

Sets the EBX register with the shift state mask and shift state compare value required for a call to the VKD_Define_Hot_Key service.

  • No return value.
Mask
Shift state bits that should be excluded before the comparison is done.
Compare
Value to compare.


Trace_Out

include debug.inc

Trace_Out String, nocrlf
Trace_Out String, level

Writes the specified string to the debugging device, but continues execution. Compare the Debug_Out macro, which stops execution if a debugger is attached.

  • • No return value.
String
String to display, enclosed in double quotation marks. The string can contain register placeholders in the same forms as described for the Out_Debug_String service.
level
Optional symbol indicating the debugging level for which code should be generated. If the value of the Deblevel symbol is greater than or equal to level, then code is generated. Otherwise, code is not generated. The symbol can be DeblevelNormal or DeblevelMax. The default is DeblevelNormal.
nocrlf
Optional parameter specifying that the macro should not append a carriage return and newline character combination to the string. If this parameter is not given, the macro appends the character combination by default.

The assembler generates code for the macro only if the DEBUG constant is defined before including the DEBUG.INC file.

There are additional macros Trace_OutX, where X is a conditional jump type, i.e., something that can follow the letter j to form a conditional jump instruction. In such case, the trace-out is performed only if the condition is satisfied.

The following example writes a string to the debugging device:

Trace_Out "Element not found"

The following example writes a string containing the value of the AX register to the debugging device if the zero flag is set:

Trace_OutZ "AX value is #AX"

See Also

Out_Debug_String


VMMCall

include vmm.inc

VMMCall Service, Parameters

Pushes the specified parameters on the stack, and calls the specified VMM service. When the service returns, the macro pops the parameters from the stack.

  • The return value is as specified for the given service.
Service
Name of the service to call. This parameter can be any service that is explicitly defined in the service table for the VMM.
Parameters
Parameters to pass to the service. If more than one parameter is given, they must be separated with commas enclosed in angle brackets (<>). This parameter is optional.

This macro is identical to the VxDCall macro, except that it also validates that the service being called is a VMM service.

See Also

VxDCall, VMMJmp


VMMJmp

include vmm.inc

VMMJmp Service

Jumps to the specified VMM service.

  • No return value.
Service
Name of the service to jump to. This parameter can be any service that is explicitly defined in the service table for the VMM.

This macro is identical to the VxDJmp macro, except that it also validates that the service being called is a VMM service.

See Also

VMMCall, VxDJmp


VxDCall

include vmm.inc

VxDCall Service

Pushes the specified parameters on the stack, and then calls the specified virtual device service. When the service returns, the macro pops the parameters from the stack.

  • The return value is as specified for the given service.
Service
Name of the service to call. This parameter can be any service that is explicitly defined in the service table for a virtual device.
Parameters
Parameters to pass to the service. If more than one parameter is given, they must be separated with commas enclosed in angle brackets (<>). This parameter is optional.

If parameters are passed, it is assumed that the called service conforms to the C-language parameter-passing and register-usage convention: Parameters are passed from right to left, and the service returns a value in the EAX register (possibly also the EDX register), modifying the ECX and flags register along the way. The C-language calling convention dictates that the caller is responsible for cleaning the stack parameters, but the called procedure is allowed to modify them. Do not assume that the called procedure will leave stack parameters unchanged.

The macro creates a dynamic link in the form of an int 20h instruction followed by a value identifying the service. When the interrupt is executed, the VMM replaces the dynamic link with a call instruction.

See Also

VMMCall, VxDJmp


VxD_CODE_ENDS

include vmm.inc

VxD_CODE_ENDS

Defines the end of a code segment. Virtual devices use this macro with in conjunction with the VxD_CODE_SEG macro to create segments for non-initialization code.

  • No return value.

This macro is equal to the VxD_LOCKED_CODE_ENDS macro.

See Also

VxD_CODE_SEG, VxD_LOCKED_CODE_ENDS


VxD_CODE_SEG

include vmm.inc

VxD_CODE_SEG

Defines the start of a code segment. Virtual devices use this segment for all code that is not explicitly for initialization of the device.

  • No return value.

This macro creates a 32-bit segment named _LTEXT. The segment is assembled for flat model memory so segment registers CS, DS, ES, and SS are assumed to be flat.

This macro is equal to the VxD_LOCKED_CODE_SEG macro.

See Also

VxD_CODE_ENDS, VxD_DATA_SEG, VxD_ICODE_SEG, VxD_LOCKED_CODE_SEG


VxD_DATA_ENDS

include vmm.inc

VxD_DATA_ENDS

Defines the end of a data segment. Virtual devices use this macro with in conjunction with the VxD_DATA_SEG macro to create segments for non-initialization data.

  • No return value.

This macro is equal to the VxD_LOCKED_DATA_ENDS macro.

See Also

VxD_DATA_SEG, VxD_LOCKED_DATA_ENDS


VxD_DATA_SEG

include vmm.inc

VxD_DATA_SEG NoAlign

Defines the start of a data segment. Virtual devices use this segment for all data that is not explicitly for the initialization of the device.

  • No return value.
NoAlign
Specifies that data be aligned at the next byte. If this optional parameter is not given, the macro aligns data at the next available doubleword.

This macro creates a 32-bit segment named _LDATA.

This macro is equal to the VxD_LOCKED_DATA_SEG macro.

See Also

VxD_CODE_SEG, VxD_DATA_ENDS, VxD_IDATA_SEG, VxD_LOCKED_DATA_SEG


VxD_ICODE_ENDS

include vmm.inc

VxD_ICODE_ENDS

Defines the end of an initialization code segment. Virtual devices use this macro in conjunction with the VxD_ICODE_SEG macro to create initialization code.

  • No return value.

See Also

VxD_ICODE_SEG


VxD_ICODE_SEG

include vmm.inc

VxD_ICODE_SEG

Defines the start of an initialization code segment. Virtual devices typically use this segment for code that initializes the corresponding device. The system discards the segment after the initialization is complete (after the Init_Complete message has been processed by all virtual devices).

  • No return value.

This macro creates a 32-bit segment named _ITEXT. The segment is assembled for flat model memory so segment registers CS, DS, ES, and SS are assumed to be flat.

See Also

VxD_CODE_SEG, VxD_ICODE_ENDS, VxD_IDATA_SEG


VxD_IDATA_ENDS

include vmm.inc

VxD_IDATA_ENDS

Defines the end of an initialization data segment. Virtual devices use this macro with in conjunction with the VxD_IDATA_SEG macro to create initialization data.

  • No return value.

See Also

VxD_IDATA_SEG


VxD_IDATA_SEG

include vmm.inc

VxD_IDATA_SEG

Defines the start of an initialization data segment. Virtual devices typically use this segment for data used to initialize the corresponding device. The system discards the segment after the initialization is complete (after the Init_Complete message has been processed by all virtual devices).

  • No return value.

This macro creates a 32-bit segment named _IDATA.

See Also

VxD_DATA_SEG, VxD_ICODE_SEG, VxD_IDATA_ENDS


VxDint

include vmm.inc

VxDint Int_Number

Executes the specified software interrupt. This macro pushes the interrupt number on the stack, and calls the Exec_VxD_Int service.

  • Returns values in one or more registers, depending on the function of the specified interrupt.
Int_Number
Number of the software interrupt to execute.

See Also

Exec_VxD_Int


VxD_IO

include vmm.inc

VxD_IO  Port, IOCallback

Adds an I/O callback procedure and I/O port number to an I/O table. Virtual devices use the macro in conjunction with the Begin_VxD_IO_Table and End_VxD_IO_Table macros to create a table of I/O callback procedures for the Install_Mult_IO_Handlers service.

  • No return value.
Port
Number of the I/O port to be trapped.
IOCallback
Name of the I/O callback procedure. For information about the callback procedure, see below.

The I/O table can contain any number of VxD_IO macros. Each macro must specify an unique I/O port number, but the same I/O callback procedure can be assigned to more than one port. In such case, the I/O callback procedure can use the EDX register to determine which port was accessed by the virtual machine.

After a virtual device installs the callback procedures, the system calls a procedure whenever a program in the virtual machine attempts to access the corresponding port. The system calls the procedure as follows:

mov     ebx, VM             ; current VM handle
mov     ecx, IOType         ; type of I/O
mov     edx, Port           ; port number
mov     ebp, OFFSET32 crs   ; points to a Client_Reg_Struc
mov     eax, Data           ; output data (if I/O type is output)
call    [IOCallback]

mov     [Data], eax         ; input data (if I/O type is input)

The VM parameter specifies the current virtual machine, Port specifies the I/O port, and crs points to a Client_Reg_Struc structure containing the register contents for the current virtual machine.

The IOType parameter specifies the type of input or output operation requested, and determines whether the callback procedure receives data in the EAX register or must return data in the EAX register. The IOType parameter can be a combination of the following values:

Value | Meaning
Addr_32_IO | Use 32-bit address offsets for input or output string operations. If this value is not given, the 16-bit offsets are used.
Byte_Input | Input a single byte; place in AL if String_IO not given.
Byte_Output | Output a single byte from AL if String_IO not given.
Dword_Input | Input a double word; place in EAX if String_IO not given.
Dword_Output | Output a double word from EAX if String_IO not given.
Rep_IO | Repeat the input or output string operation the number of times specified by the Client_CX field in the Client_Reg_Struc structure. (Client_ECX if Addr_32_IO is set.)
Reverse_IO | Decrement string address on each input or output operation. If this value is not given, the string address is incremented on each operation.
String_IO | Input or output a string. The high 16-bits specifies segment address of buffer containing the string to output or to receive the string input.
Word_Input | Input a word; place in AX if String_IO not given.
Word_Output | Output a word from AX if String_IO not given.

In memory, an I/O table consists of a VxD_IOT_Hdr structure followed by one or more VxD_IO_Struc structures. The first word in the table specified the number of entries. Each entry consists of a word specifying the port number and a double word specifying the 32-bit offset of the callback procedure.

The Data parameter is used only when I/O type is for output.

See Also

Begin_VxD_IO_Table, End_VxD_IO_Table, Install_Mult_IO_Handlers


VxDJmp

include vmm.inc

VxDJmp Service

Jumps to the specified virtual device service.

  • No return value.
Service
Name of the service to jump to. This parameter can be any service that is explicitly defined in the service table for a virtual device.

The macro creates a dynamic link in the form of an int 20h instruction followed by a value identifying the service. When the interrupt is executed, the VMM replaces the dynamic link with a jmp instruction.

See Also

VMMJmp, VxDCall


VxD_LOCKED_CODE_ENDS

include vmm.inc

VxD_LOCKED_CODE_ENDS

Defines the end of a code segment. Virtual devices use this macro in conjunction with the VxD_LOCKED_CODE_SEG macro to create segments for non-initialization code.

  • No return value.

This macro is equal to the VxD_CODE_ENDS macro.

See Also

VxD_CODE_ENDS, VxD_LOCKED_CODE_SEG


VxD_LOCKED_CODE_SEG

include vmm.inc

VxD_LOCKED_CODE_SEG

Defines the start of a code segment. Virtual devices use this segment for all code that is not explicitly for initialization of the device.

  • No return value.

This macro creates a 32-bit segment named _LTEXT. The segment is assembled for flat model memory so segment registers CS, DS, ES, and SS are assumed to be equal.

This macro is equal to the VxD_CODE_SEG macro.

See Also

VxD_CODE_SEG, VxD_LOCKED_CODE_ENDS


VxD_LOCKED_DATA_ENDS

include vmm.inc

VxD_LOCKED_DATA_ENDS

Defines the end of a data segment. Virtual devices use this macro in conjunction with the VxD_LOCKED_DATA_SEG macro to create segments for non-initialization data.

  • No return value.

This macro is equal to the VxD_DATA_ENDS macro.

See Also

VxD_DATA_ENDS, VxD_LOCKED_DATA_SEG


VxD_LOCKED_DATA_SEG

include vmm.inc

VxD_LOCKED_DATA_SEG NoAlign

Defines the start of a data segment. Virtual devices use this segment for all data that is not explicitly for initialization of the device.

  • No return value.
NoAlign
Optional parameter specifying that data be aligned at the next byte. If this optional parameter is not given, the macro aligns data at the next available doubleword.

This macro creates a 32-bit segment named _LDATA.

This macro is equal to the VxD_DATA_SEG macro.

See Also

VxD_DATA_SEG, VxD_LOCKED_DATA_ENDS


VxD_PAGEABLE_CODE_ENDS

include vmm.inc

VxD_PAGEABLE_CODE_ENDS

Defines the end of a pageable code segment. Virtual devices use this macro in conjunction with the VxD_PAGEABLE_CODE_SEG macro.

  • No return value.

At any given time, pageable code may be paged out to the system swap file. For this reason, any code that may be executed during hardware interrupt processing must not be in a VxD_PAGEABLE_CODE_SEG segment.

Code in a VxD_PAGEABLE_CODE_SEG segment is actually locked if MS-DOS or BIOS functions are used for paging.

See Also

VxD_CODE_ENDS, VxD_LOCKED_CODE_ENDS, VxD_PAGEABLE_CODE_SEG


VxD_PAGEABLE_CODE_SEG

include vmm.inc

VxD_PAGEABLE_CODE_SEG

Defines the start of a pageable code segment. Virtual devices use this macro in conjunction with the VxD_PAGEABLE_CODE_ENDS macro.

  • No return value.

At any given time, pageable code may be paged out to the system swap file. For this reason, any code that may be executed during hardware interrupt processing must not be in a VxD_PAGEABLE_CODE_SEG segment.

Code in a VxD_PAGEABLE_CODE_SEG segment is actually locked if MS-DOS or BIOS functions are used for paging.

See Also

VxD_CODE_SEG, VxD_LOCKED_CODE_SEG, VxD_PAGEABLE_CODE_ENDS


VxD_REAL_INIT_ENDS

include vmm.inc

VxD_REAL_INIT_ENDS

Defines the end of a real-mode initialization segment. Virtual devices use this macro with in conjunction with the VxD_REAL_INIT_SEG macro to create initialization code for real-mode execution.

  • No return value.

See Also

VxD_REAL_INIT_SEG


VxD_REAL_INIT_SEG

include vmm.inc

VxD_REAL_INIT_SEG

Defines the start of a real-mode initialization segment. Virtual devices typically use this segment for code that initializes the corresponding device before Windows changes to protected-mode execution. The system discards the segment after the initialization is complete.

  • No return value.

This macro creates a 16-bit segment named _RCODE. The segment is assembled for the real-mode tiny model memory so segment registers CS, DS, ES, and SS are assumed to be equal.

See Also

VxD_ICODE_SEG, VxD_REAL_INIT_ENDS


VMM Messages

This section is an alphabetic listing of the system control messages sent to virtual devices by the virtual machine manager (VMM). Other components (for example, Vcomm, Vwin32, and the Configuration Manager) also direct system control messages to particular VxDs. Consult documentation for those other components for additional information.

In this section, the term "general registers" refers to the registers consisting of EAX, EBX, ECX, EDX, ESI, EDI, and EBP.

The purpose of the xx2 messages (such as SYS_VM_TERMINATE2 and VM_TERMINATE2) is to address a problem in Windows 3.1 where exit-like messages were sent in increasing initialization order, which created complicated dependencies in a layered device architecture. For example, suppose virtual device B always requires virtual device A. This is traditionally solved by giving virtual device A a lower initialization order. This solves the problem at initialization, but since Windows 3.1 sent shutdown messages in increasing initialization order, virtual device A would get the shutdown message first and uninstall itself. Then virtual device B got into trouble when it received the shutdown message because it requires services from virtual device A, which is already gone. There are various ways of working around this problem, none of them entirely satisfactory.

By introducing xx2 messages which are sent in reverse initialization order, virtual devices A and B can perform their shutdown on the xx2 message, in which case virtual device B will shut down first, while virtual device A is still ready to service requests, and only after B has finished processing the shutdown message will it then be given to virtual device A.

Note that these messages are sent by the virtual machine manager or other system components. Virtual devices should not send these messages on their own, unless otherwise indicated.


Begin_Message_Mode

include vmm.inc

mov     ebx, VMHandle
mov     eax, Begin_Message_Mode
VMMCall System_Control

Notifies the virtual display, keyboard, and mouse devices to prepare to display messages and read input from the keyboard. The system sends this message to all virtual devices in order to prepare the system for a full-screen error message (informally known as a 'blue-screen message' because of the color traditionally used for such messages). The virtual device may modify all general registers and flags.

  • This message cannot be failed. The virtual device must return carry clear from this message.
VMHandle
Handle of the virtual machine entering message mode.

This message is usually processed only by the virtual keyboard, mouse, and display devices.

See Also

End_Message_Mode


Begin_PM_App

include vmm.inc

mov     ebx, VMHandle
mov     edx, Flags
mov     edi, OFFSET32 acb
mov     eax, Begin_PM_App
VMMCall System_Control

Notifies the virtual device that the system is starting a protected-mode application. The virtual device may modify all general registers and flags.

  • The virtual device returns with carry clear if the virtual device can support the protected-mode application. Otherwise, it returns carry set to indicate an error, in which case the program is not allowed to enter protected mode.
VMHandle
Handle of the current virtual machine.
Flags
Bitmask of flags. Only one flag is currently supported:
Value | Meaning
BPA_32_Bit | Application has 32-bit segments. If this value is not given, the application has 16-bit segments.

All other values are reserved.

abc
Address of an application control block, which is a pmcb_s structure. A virtual device can allocate memory in the application control block with the Allocate_PM_App_CB_Area service.

Protected-mode applications may nest. Virtual devices are notified for each application, and each application has its own application control block.

See Also

End_PM_App, pmcb_s


Close_VM_Notify

include vmm.inc

mov     ebx, VMHandle
mov     edx, Flags
mov     eax, Close_VM_Notify
VMMCall System_Control

Notifies a virtual device that the Close_VM service has been called and the specified virtual machine is terminating. The virtual device may use all general registers and flags.

  • This message cannot be failed. The virtual device must return carry clear.
VMHandle
Handle of the virtual machine to close.
Flags
Operation flag. Can be this value:
Value | Meaning
CVNF_Crit_Close | The virtual machine has not released the critical section.

All other values are reserved.

See Also

Close_VM, Close_VM_Notify2


Close_VM_Notify2

include vmm.inc

mov     ebx, VMHandle
mov     edx, Flags
mov     eax, Close_VM_Notify2
VMMCall System_Control

Similar to Close_VM_Notify, except that Close_VM_Notify2 is sent only to virtual devices marked version 4.0 and it is sent in reverse device initialization order. Close_VM_Notify2 is sent immediately after Close_VM_Notify.

See Also

Close_VM, Close_VM_Notify


Create_Thread

include vmm.inc

mov     edi, ThreadHandle
mov     eax, Create_Thread
VMMCall System_Control

Notifies a virtual device that the system is creating a new thread. Virtual devices typically create and initialize any structures needed to support the new thread. The virtual device may use all general registers and flags.

  • The virtual device returns with carry clear to allow the thread to be created, or with carry set to prevent it from being created.
ThreadHandle
Handle of the thread being created. The thread being created is not the current thread.

If the virtual device sets the carry flag to prevent creation the thread, it should free any system resource it may have allocated to support the thread.

Interrupt simulation is not permitted in the new thread during this message.

Note that this message is not sent when a new virtual machine is created, even though each virtual machine also comes with a thread. Therefore, if you need to do something whenever a new thread is created, even if it is the thread of a virtual machine, you need to perform the operation on the VM_Create message as well.

See Also

VMMCreateThread, Thread_Init


Create_VM

include vmm.inc

mov     ebx, VMHandle
mov     eax, Create_VM
VMMCall System_Control

Notifies a virtual device that the system is creating a new virtual machine. Virtual devices typically initialize data associated with the virtual machine, such as data in the control block for the virtual machine. The virtual device may use all general registers and flags.

  • The virtual device returns carry clear if the virtual device can support the new virtual machine. Otherwise, it returns with carry set to indicate an error and prevent the system from creating the virtual machine.
VMHandle
Handle of the new virtual machine.

Note that this message is delivered out of context; the new virtual machine has not yet started executing. Virtual devices typically ignore this message and act on the VM_Init message instead.

See Also

Destroy_VM


Crit_Reboot_Notify

include vmm.inc

mov     eax, Crit_Reboot_Notify
VMMCall System_Control

Notifies a virtual device that the system is about to restart. Virtual devices typically prepare for restarting by cleaning up data or resetting devices. The system disables interrupts before it sends this message. The virtual device may use all general registers and flags.

  • This message cannot be failed. The virtual device must return carry clear.

The virtual device must not enable interrupts, nor is simulated interrupt activity allowed. See the description of the Device_Reboot_Notify message for additional information.

See Also

Crit_Reboot_Notify2, Device_Reboot_Notify


Crit_Reboot_Notify2

include vmm.inc

mov     eax, Crit_Reboot_Notify2
VMMCall System_Control

Similar to Crit_Reboot_Notify, except that Crit_Reboot_Notify2 is sent only to virtual devices marked version 4.0 and it is sent in reverse device initialization order. Crit_Reboot_Notify2 is sent immediately after Crit_Reboot_Notify.

See Also

Crit_Reboot_Notify, Device_Reboot_Notify


Debug_Query

include vmm.inc

mov     eax, Debug_Query
VMMCall System_Control

Notifies a virtual device that the user has typed ".VxDNAME" in the debugger. (that is, a period followed by the name of the VxD.) This is a directed system control message. The virtual device typically responds to the message by displaying a menu of debugging services and reading command input from the user via In_Debug_Chr. The virtual device may use all general registers and flags.

  • This message cannot be failed. The virtual device must return carry clear.

The handler for this message must not be in pageable memory. A Windows 95 VxD should placed the handler in the Debug_Only code segment.


Destroy_Thread

include vmm.inc

mov     edi, ThreadHandle
mov     eax, Destroy_Thread
VMMCall System_Control

Notifies a virtual device that the specified non-initial thread is about to be destroyed. This is a virtual device's last chance to free resources associated with the thread before the thread goes away. The virtual device may modify all general registers and flags.

  • This message cannot be failed. The virtual device must return carry clear.
ThreadHandle
Handle of the thread.

Interrupt simulation is not permitted in the thread during this message.

This message is sent only to virtual devices marked 4.0, and it is sent in reverse initialization order. When a virtual machine is destroyed, no Destroy_Thread message is sent. Use the Destroy_VM message instead.

See Also

VMMCreateThread, Create_Thread, Destroy_VM


Destroy_VM

include vmm.inc

mov     ebx, VMHandle
mov     eax, Destroy_VM
VMMCall System_Control

Notifies the virtual device that the system is about to destroy the virtual machine. Virtual devices typically remove any data associated with the specified virtual machine. The virtual device may use all general registers and flags.

  • This message cannot be failed. The virtual device must return carry clear.
VMHandle
Handle of the virtual machine about to be destroyed.

The Destroy_VM message is sent to all virtual devices in initialization order.

The virtual device must not call the Simulate_Int or Exec_Int service in the specified virtual machine.

Considerable time can elapse between receipt of the VM_Not_Executeable message and this message. Once all virtual devices return from the Destroy_VM and Destroy_VM2 messages, the virtual machine is destroyed and the handle becomes invalid.

See Also

Create_VM, Destroy_VM2, VM_Not_Executeable


Destroy_VM2

include vmm.inc

mov     ebx, VMHandle
mov     eax, Destroy_VM2
VMMCall System_Control

Similar to Destroy_VM, except that Destroy_VM2 is sent only to all Windows 95 virtual devices in reverse initialization order. Destroy_VM2 is sent immediately after Destroy_VM. The Destroy_VM2 message is not sent to Windows 3.1 virtual devices.

See Also

Create_VM, Destroy_VM, VM_Not_Executeable


Device_Init

include vmm.inc

mov     ebx, SysVMHandle
mov     esi, OFFSET32 CommandTail
mov     eax, Device_Init
VMMCall System_Control

Directs the virtual device to initialize itself. The virtual device typically allocates memory for a device-specific section in the control block, allocates other memory areas, hooks interrupts and I/O ports, and specifies instance data. The virtual device may use all general registers and flags.

  • The virtual device returns carry clear if it initialized successfully. If the virtual device returns carry set, the system considers the device as having failed to initialize and removes it from the list of VxDs loaded in the system. Before returning carry set, a virtual device must release all resources it had claimed during previous initialization phases.
SysVMHandle
Handle of the system virtual machine.
CommandTail
Address of the command tail retrieved from the program segment prefix (PSP) of VMM32.VXD. The first byte in the command tail specifies the length in bytes of the tail.

The virtual device should allocate a device-specific section in the control block of the system virtual machine and then initialize the section.

The virtual device can call the Simulate_Int and Exec_Int services in the system virtual machine.

For dynamically loaded VxDs, the EBX register does not contain a VM handle.

See Also

Init_Complete, Sys_Critical_Init


Device_Reboot_Notify

include vmm.inc

mov     eax, Device_Reboot_Notify
VMMCall System_Control

Notifies the virtual device that the system is about to restart. Interrupts remain enabled while virtual devices process this message. The virtual device may modify all general registers and flags.

  • This message cannot be failed. The virtual device must return carry clear.

When the system is about to be rebooted abnormally, virtual devices will first receive the Device_Reboot_Notify message (and possibly also the Device_Reboot_Notify2 message), at which time interrupts are enabled and simulated interrupt activity is allowed (although not encouraged). Next, virtual devices receive the Crit_Reboot_Notify message (and possibly also the Crit_Reboot_Notify2 message) with interrupts disabled, during which time interrupts must not be enabled by the virtual device, and at which time simulated interrupt activity is not allowed. Finally, virtual devices receive the Reboot_Processor message, which all devices except the virtual keyboard device should ignore.

See Also

Crit_Reboot_Notify, Device_Reboot_Notify2, Reboot_Processor


Device_Reboot_Notify2

include vmm.inc

mov     eax, Device_Reboot_Notify2
VMMCall System_Control

Similar to Device_Reboot_Notify, except that Device_Reboot_Notify2 is sent only to virtual devices marked version 4.0 and it is sent in reverse device initialization order. Device_Reboot_Notify2 is sent immediately after Device_Reboot_Notify.

See Also

Crit_Reboot_Notify, Device_Reboot_Notify


End_Message_Mode

include vmm.inc

mov     ebx, VMHandle
mov     eax, End_Message_Mode
VMMCall System_Control

Directs the virtual device to end message-mode processing. The virtual device may modify all general registers and flags.

  • This message cannot be failed. The virtual device must return carry clear.
VMHandle
Handle of the virtual machine leaving message mode.

See Also

Begin_Message_Mode, End_Message_Mode2


End_Message_Mode2

include vmm.inc

mov     ebx, VMHandle
mov     eax, End_Message_Mode2
VMMCall System_Control

Similar to End_Message_Mode, except that End_Message_Mode2 is sent only to virtual devices marked version 4.0 and it is sent in reverse device initialization order. End_Message_Mode2 is sent immediately after End_Message_Mode.

See Also

Begin_Message_Mode, End_Message_Mode


End_PM_App

include vmm.inc

mov     ebx, VMHandle
mov     edi, OFFSET32 acb
mov     eax, End_PM_App
VMMCall System_Control

Notifies the virtual device that a protected-mode application is ending. The virtual device may modify all general registers and flags.

  • This message cannot be failed. The virtual device must return carry clear.
VMHandle
Handle of the current virtual machine.
abc
Address of the application control block for the application that is terminating.

See Also

Begin_PM_App, End_PM_App2


End_PM_App2

include vmm.inc

mov     ebx, VMHandle
mov     edi, OFFSET32 acb
mov     eax, End_PM_App2
VMMCall System_Control

Similar to End_PM_App, except that End_PM_App2 is sent only to virtual devices marked version 4.0 and it is sent in reverse device initialization order. End_PM_App2 is sent immediately after End_PM_App.

See Also

Begin_PM_App, End_PM_App


Init_Complete

include vmm.inc

mov     ebx, SysVMHandle
mov     esi, OFFSET32 CommandTail
mov     eax, Init_Complete
VMMCall System_Control

Notifies the virtual device that the system and virtual devices have initialized successfully. Virtual devices that use V86 memory typically search for available pages, in the range 0xA0h through 100h, when processing this message. The virtual device may modify all general registers and flags.

  • Clears the carry flag if the virtual device successfully completes its initialization. Otherwise, sets the carry flag to prevent the system from loading the virtual device.
SysVMHandle
Handle of the system virtual machine.
CommandTail
Address of the command tail retrieved from the program segment prefix (PSP) of VMM32.VXD. The first byte in the command tail specifies the length in bytes of the tail.

The system sends this message just before it releases its INIT pages and takes the instance snapshot.

Virtual devices can use the Simulate_Int and Exec_Int services to execute code in the system virtual machine.

See Also

Device_Init


PNP_NEW_DEVNODE

include vmm.inc
include configmg.inc

mov     ebx, hDevnode
mov     edx, LoadType
mov     eax, PNP_NEW_DEVNODE
VMMCall System_Control

Notifies a dynamically loadable VxD that a new device node has been loaded. Uses the C calling convention. This is a directed system control message. The virtual device may modify the EAX, ECX, EDX, and Flags registers, but it must preserve the EBX, EDI, ESI, and EBP registers.

  • The virtual device returns a configuration manager return value (CR_) in EAX. The carry flag must be set if a value other than CR_SUCCESS is returned. It doesn't hurt to return carry set even if you are returning CR_SUCCESS, so it's safest to always return carry set.
hDevnode
Handle of the new device node.
LoadType
Type of functionality that the VxD should handle. Can be one of these values:
Value | Meaning
DLVXD_LOAD_DEVLOADER | Device loader
DLVXD_LOAD_DRIVER | Device driver
DLVXD_LOAD_ENUMERATOR | Device enumerator


Power_Event

include vmm.inc
include power.inc

mov     esi, Event
mov     edi, OFFSET32 Return
mov     eax, Power_Event
VMMCall System_Control

Notifies the virtual device that a power event has just occurred. The virtual device may modify all general registers and flags.

  • The virtual device must return with carry clear, even to fail the call. See the description of Return for information on how to fail the call.
Event
Type of power event. Can be one of these values:
Value | Meaning
PWR_CRITICALRESUME | Resume critical operations after suspension.
PWR_SUSPENDREQUEST | Suspend operation.
PWR_SUSPENDRESUME | Resume operation after suspension.

Return
Address of the doubleword that receives the return value, which can be one of these values:
Value | Meaning
PWR_FAIL | Virtual device failed to process the event.
PWR_OK | Virtual device processed the event successfully.

All other values are reserved.

To fail the call, a virtual device should store the value PWR_FAIL in the doubleword pointed to by Return. For the call to succeed, the virtual device must leave the doubleword pointed to by Return unchanged. If a VxD stores PWR_OK through Return, it might overwrite a PWR_FAIL value that was written there by the previous device.

Only the virtual power device (VPOWERD) is permitted to send this message to devices. The EBX register must be zero on entry. The EDX register is reserved.

Note This message is sent for compatibility with Windows 3.1 virtual devices. New virtual devices should use the VPOWERD_Register_Power_Handler service to be notified of changes in power state.


Query_Destroy

include vmm.inc

mov     ebx, VMHandle
mov     eax, Query_Destroy
VMMCall System_Control

Directs the virtual device to display a warning message if the destruction of the specified virtual machine will disrupt the operation of the virtual device. The virtual shell device sends this message before attempting to destroy a virtual machine that has not terminated normally. The virtual device may modify all general registers and flags.

  • Sets the carry flag if the destruction of the virtual machine will disrupt the virtual device. Otherwise, clears the carry flag.
VMHandle
Handle of the virtual machine to destroy.

Virtual devices that set the carry flag must also display a message box, using the SHELL_Message service to inform the user of the potential problem. The user can then decide whether to continue destroying the virtual machine.

See Also

Destroy_VM


Reboot_Processor

include vmm.inc

mov     eax, Reboot_Processor
VMMCall System_Control

Directs the virtual device to restart the computer. The system continues to call the virtual devices until one that can restart the computer (usually the virtual keyboard device) does so. The virtual device may modify all general registers and flags.

  • This message cannot be failed. The virtual device must return carry clear.

See Also

Crit_Reboot_Notify


Set_Device_Focus

include vmm.inc

mov     ebx, VMHandle
mov     edx, VID
mov     esi, Flags
mov     edi, AssocVMHandle
mov     eax, Set_Device_Focus
VMMCall System_Control

Sets the focus of the specified virtual device to the specified virtual machine. The virtual device may modify all general registers and flags.

  • This message cannot be failed. The virtual device must return carry clear.
VMHandle
Handle of the virtual machine.
VID
Identifier of the virtual device that should change its focus. If this parameter is zero, all virtual devices should change their focus to the indicated virtual machine. Otherwise, all devices whose device IDs are different from VID should ignore the message.
Flags
Flags specifying how to set the focus if the VID parameter is zero. Can be this value:
Value | Meaning
1 | Used by the virtual shell device to determine which virtual machine to set focus for. If this value is given, the AssocVMHandle parameter may specify a virtual machine.

All other values are reserved.

AssocVMHandle
Handle of a virtual machine associated with a problem. This parameter is zero if there is no such virtual machine. This parameter is used only if the Flags parameter is set to 1.

A virtual device that is instructed to change its focus should take steps, such as disabling I/O trapping, to allow the specified virtual machine to run as fast as possible.

This is one of the few messages that arbitrary virtual devices are permitted to send. Typically, a virtual device sends this message with EDX = ESI = 0, to indicate that all devices should set the focus to the indicated virtual machine.


Sys_Critical_Exit

include vmm.inc

mov     eax, Sys_Critical_Exit
VMMCall System_Control

Notifies the virtual device that the system is exiting either normally or as a result of a crash. Virtual devices should reset their associated hardware to allow for a return to the state before Windows was started. The virtual device may modify all general registers and flags.

  • This message cannot be failed. The virtual device must return carry clear.

This message is sent with interrupts disabled and the virtual device must not enable interrupts while this message is being processed.

The handler for this message must not be in pageable memory, and must not call the Simulate_Int or Exec_Int service.

See Also

Sys_Critical_Exit2, Sys_Critical_Init, Sys_VM_Terminate


Sys_Critical_Exit2

include vmm.inc

mov     eax, Sys_Critical_Exit2
VMMCall System_Control

Similar to Sys_Critical_Exit, except that Sys_Critical_Exit2 is sent only to virtual devices marked version 4.0 and it is sent in reverse device initialization order. Sys_Critical_Exit2 is sent immediately after Sys_Critical_Exit.

See Also

Sys_Critical_Exit, Sys_Critical_Init, Sys_VM_Terminate


Sys_Critical_Init

include vmm.inc

mov     ebx, SysVMHandle
mov     esi, OFFSET32 CommandTail
mov     eax, Sys_Critical_Init
VMMCall System_Control

Notifies the virtual device that Windows is starting. The system sends this message to direct virtual devices to carry out, as quickly as possible, the minimum number of tasks needed to prepare the device for enabled interrupts. This message is sent with interrupts disabled, and the virtual device must not enable interrupts while handling this message. The virtual device may modify all general registers and flags.

  • Clears the carry flag if the virtual device initialized successfully. Otherwise, sets the carry flag to prevent the system from loading the virtual device.
SysVMHandle
Handle of the system virtual machine.
CommandTail
Address of the command tail retrieved from the program segment prefix (PSP) of VMM32.VXD. The first byte in the command tail specifies the length in bytes of the tail.

While processing this message, virtual devices typically initialize any critical functions needed to support interrupts, and claim any V86 pages required to support the device. For example, the virtual display device claims the video memory. If a virtual device provides services, it should initialize any data associated with those services.

The virtual device must not use the Simulate_Int or Exec_Int services. Also it must not access conventional memory unless it is certain that the memory will be there. This means, for example, that scanning memory for the signature of a TSR is not allowed. Upper memory blocks are also off-limits because the V86MMGR device has yet to set them up.

See Also

Device_Init, Sys_Critical_Exit


Sys_VM_Init

include vmm.inc

mov     ebx, SysVMHandle
mov     eax, Sys_VM_Init
VMMCall System_Control

Directs the virtual device to initialize the state of the software in the system virtual machine. For example, the virtual display device issues an Interrupt 10h function to set the initial display mode. The virtual device may modify all general registers and flags.

  • This message cannot be failed. The virtual device must return carry clear.
SysVMHandle
Handle of the system virtual machine.

This message is the System VM version of the VM_Init message. It is sent after the instance snapshot has been completed and initialization code and data have been discarded.

See Also

VM_Init


Sys_VM_Terminate

include vmm.inc

mov     ebx, SysVMHandle
mov     eax, Sys_VM_Terminate
VMMCall System_Control

Notifies the virtual device that the system virtual machine is terminating. The system sends this message only after all other virtual machines have terminated, and only when the system is terminating normally. The virtual device may modify all general registers and flags.

  • This message cannot be failed. The virtual device must return carry clear.
SysVMHandle
Handle of the system virtual machine.

The virtual device can use the Simulate_Int and Exec_Int services in the system virtual machine.

See Also

Sys_VM_Terminate2, VM_Terminate


Sys_VM_Terminate2

include vmm.inc

mov     ebx, SysVMHandle
mov     eax, Sys_VM_Terminate2
VMMCall System_Control

Similar to Sys_VM_Terminate, except that Sys_VM_Terminate2 is sent only to virtual devices marked version 4.0 and it is sent in reverse device initialization order. Sys_VM_Terminate2 is sent immediately after Sys_VM_Terminate.

See Also

Sys_VM_Terminate, VM_Terminate


System_Exit

include vmm.inc

mov     ebx, SysVMHandle
mov     eax, System_Exit
VMMCall System_Control

Notifies the virtual device that the system is terminating, either normally or as a result of a crash. Interrupts remain enabled while virtual devices process this message. The virtual device may modify all general registers and flags.

  • This message cannot be failed. The virtual device must return carry clear.
SysVMHandle
Handle of the system virtual machine.

The virtual device must not call the Simulate_Int or Exec_Int service, but the virtual device may modify the system virtual machine memory to restore the system state to allow Windows to exit without complication.

The system restores the instance snapshot before sending this message.

The virtual device may not access pageable data during the processing of the System_Exit message because the swap file may be in a bad state (which is why the system is crashing in the first place), or the swap file may already have been closed. Virtual devices that wish to access pageable data during System_Exit must lock the data during Sys_VM_Terminate. During a system crash, the Sys_VM_Terminate message is not sent, so the virtual device should have some way of determining during System_Exit whether or not it was able to lock its data; if not, it should skip any procedures which use the pageable data.

See Also

Sys_Critical_Exit, Sys_VM_Terminate, System_Exit2


System_Exit2

include vmm.inc

mov     ebx, SysVMHandle
mov     eax, System_Exit2
VMMCall System_Control

Similar to System_Exit, except that System_Exit2 is sent only to virtual devices marked version 4.0 and it is sent in reverse device initialization order. System_Exit2 is sent immediately after System_Exit.

See Also

Sys_Critical_Exit, System_Exit


Terminate_Thread

include vmm.inc

mov     edi, ThreadHandle
mov     eax, Terminate_Thread
VMMCall System_Control

Notifies a virtual device that the specified non-initial thread is about to terminate. Virtual devices typically free resources associated with the thread. The virtual device may modify all general registers and flags.

  • This message cannot be failed. The virtual device must return carry clear.
ThreadHandle
Handle of the thread being terminated.

This message is sent only to virtual devices marked 4.0, and it is sent in reverse initialization order. When a virtual machine terminates, no Terminate_Thread message is sent. Use the VM_Terminate message instead.

See Also

VMMTerminateThread, VM_Terminate


Thread_Init

include vmm.inc

mov     edi, ThreadHandle
mov     eax, Thread_Init
VMMCall System_Control

Notifies a virtual device that a new thread was created. Virtual devices typically perform initialization procedures that must take place in the context of the new thread. The virtual device may modify all general registers and flags.

  • This message cannot be failed. The virtual device must return carry clear.
ThreadHandle
Handle of the new thread. This is also the current thread.

Interrupt simulation is not permitted in the new thread during this message.

See Also

VMMCreateThread, Create_Thread


Thread_Not_Executeable

include vmm.inc

mov     edi, ThreadHandle
mov     eax, Thread_Not_Executeable
VMMCall System_Control

Notifies a virtual device that the specified non-initial thread has stopped executing. Virtual devices typically free resources associated with the thread. The virtual device may modify all general registers and flags.

  • This message cannot be failed. The virtual device must return carry clear.
ThreadHandle
Handle of the thread.

Interrupt simulation is not permitted in the thread during this message.

This message is sent only to virtual devices marked 4.0, and it is sent in reverse initialization order. When a virtual machine stops executing, no Thread_Not_Executeable message is sent. Use the VM_Not_Executeable message instead.

See Also

VM_Not_Executeable


VM_Critical_Init

include vmm.inc

mov     ebx, VMHandle
mov     eax, VM_Critical_Init
VMMCall System_Control

Directs the virtual device to initialize itself for the new virtual machine. This message is sent with interrupts disabled, and the virtual device must not enable interrupts while processing the message. The virtual device may modify all general registers and flags.

  • Clears the carry flag if the virtual device initialized successfully. Otherwise, sets the carry flag to prevent the virtual machine from being created.
VMHandle
Handle of the virtual machine to create.

The virtual device must not use the Simulate_Int or Exec_Int services in the specified virtual machine.

See Also

Create_VM, VM_Init


VM_Init

include vmm.inc

mov     ebx, VMHandle
mov     eax, VM_Init
VMMCall System_Control

Directs the virtual device to initialize the state of the software in the new virtual machine. For example, the virtual display device issues Interrupt 10h to set the initial display mode. The system enables interrupts before sending this message. The virtual device may modify all general registers and flags.

  • Clears the carry flag if the virtual device initialized the virtual machine successfully. Otherwise, sets the carry flag to prevent the system from creating the virtual machine.
VMHandle
Handle of the virtual machine to create.

The virtual device can use the Simulate_Int and Exec_Int services in the specified virtual machine.

See Also

Create_VM, VM_Critical_Init


VM_Not_Executeable

include vmm.inc

mov     ebx, VMHandle
mov     edx, Flags
mov     eax, VM_Not_Executeable
VMMCall System_Control

Notifies the virtual device that the virtual machine is no longer capable of executing. The system sends this message as the first phase of terminating the virtual machine. The virtual device may modify all general registers and flags.

  • This message cannot be failed. The virtual device must return carry clear.
VMHandle
Handle of the virtual machine.
Flags
Reason the virtual machine is no longer executable. Can be one of these values:
Value | Meaning
VNE_Crashed | Virtual machine has crashed.
VNE_Nuked | Virtual machine was destroyed while active.
VNE_CreateFail | Some device failed Create_VM.
VNE_CrInitFail | Some device failed VM_Critical_Init.
VNE_InitFail | Some device failed VM_Init.

When destroying a running virtual machine, the system sends this message first and never sends the VM_Terminate message.

The virtual device must not call the Simulate_Int or Exec_Int service in the specified virtual machine.

See Also

VM_Not_Executeable2, VM_Terminate


VM_Not_Executeable2

include vmm.inc

mov     ebx, VMHandle
mov     edx, Flags
mov     eax, VM_Not_Executeable2
VMMCall System_Control

Similar to VM_Not_Executeable, except that VM_Not_Executeable2 is sent only to virtual devices marked version 4.0 and it is sent in reverse device initialization order. VM_Not_Executeable2 is sent immediately after VM_Not_Executeable.

See Also

VM_Not_Executeable, VM_Terminate


VM_Resume

include vmm.inc

mov     ebx, VMHandle
mov     eax, VM_Resume
VMMCall System_Control

Notifies the virtual device that the virtual machine is resuming after having been suspended. The virtual device should lock any resources, and prepare internal data structures for the virtual machine to start running again. The virtual device may modify all general registers and flags.

  • Clears the carry flag is clear if the virtual device can support resumption of the virtual machine. Otherwise, sets the carry flag to prevent the system from resuming the virtual machine.
VMHandle
Handle of the virtual machine to resume.

The system never sends the VM_Resume message without having first sent a VM_Suspend message.

See Also

VM_Suspend


VM_Suspend

include vmm.inc

mov     ebx, VMHandle
mov     eax, VM_Suspend
VMMCall System_Control

Notifies the virtual device that the system is suspending execution of the virtual machine. The virtual device should unlock any resources associated with the virtual machine. The virtual device may modify all general registers and flags.

  • This message cannot be failed. The virtual device must return carry clear.
VMHandle
Handle of the virtual machine to suspend.

The virtual machine remains suspended until explicitly resumed. The system sends the VM_Suspend message when the virtual machine's suspend count changes from zero to one, and not every time the Suspend_VM service is called. Similarly, it sends a VM_Resume message when the virtual machine's suspend count changes from one to zero, and not every time the Resume_VM service is called.

The CB_VM_Status field in the control block for the virtual machine specifies whether the virtual machine is suspended.

See Also

Resume_VM, Suspend_VM, VM_Resume, VM_Suspend2


VM_Suspend2

include vmm.inc

mov     ebx, VMHandle
mov     eax, VM_Suspend2
VMMCall System_Control

Similar to VM_Suspend, except that VM_Suspend2 is sent only to virtual devices marked version 4.0 and it is sent in reverse device initialization order. VM_Suspend2 is sent immediately after VM_Suspend.

See Also

VM_Resume, VM_Suspend


VM_Terminate

include vmm.inc

mov     ebx, VMHandle
mov     eax, VM_Terminate
VMMCall System_Control

Notifies the virtual device that the system is terminating the specified virtual machine. The system sends this message when a virtual machine terminates normally. The virtual device may modify all general registers and flags.

  • This message cannot be failed. The virtual device must return carry clear.
VMHandle
Handle of the virtual machine being terminated.

The virtual machine can call the Simulate_Int and Exec_Int services in the specified virtual machine.

See Also

System_Exit, VM_Not_Executeable, VM_Terminate2


VM_Terminate2

include vmm.inc

mov     ebx, VMHandle
mov     eax, VM_Terminate2
VMMCall System_Control

Similar to VM_Terminate, except that VM_Terminate2 is sent only to virtual devices marked version 4.0 and it is sent in reverse device initialization order. VM_Terminate2 is sent immediately after VM_Terminate.

See Also

System_Exit, VM_Not_Executeable, VM_Terminate


W32_DEVICEIOCONTROL

include VMM.INC

mov ebx, VMHandle
mov eax, W32_DEVICEIOCONTROL
mov esi, OFFSET32 dioparams
VMMCall System_Control

Passes a control code and related information to a virtual device driver.

Parameters

VMHandle
Handle of the virtual machine.
dioparams
Address of a DIOCParams structure containing a control code and information that the VxD needs to process the control code.

Return Values

Returns one of the following values in the EAX register:

0 | The control code processed successfully.
– 1 | An asynchronous operation is in progress. A VxD must return this value only if the lpoOverlapped member of the DIOCParams structure is not NULL.
Error code | An error occurred.

Remarks

This message is sent to a VxD when an application specifies the name of a VxD in the CreateFile function and when an application specifies the device handle of the VxD in a call to the DeviceIoControl or CloseHandle function. This message uses the ESI register. If the I/O control code is DIOC_Open, then you may return 0 to allow the handle to be opened or a nonzero value to disallow the operation, in which case the application will receive the error ERROR_NOT_SUPPORTED. The VxD cannot return a special error code in response to DIOC_Open. See VMM Structures in this documentation for more information.


About VMM Structures

This section contains an alphabetic listing of the structures used with virtual machine manager (VMM) services. There are these structures:

cb_s
Client_Reg_Struc
Exception_Handler_Struc
IPF_Data
pmcb_s
Pushad_Struc
tcb_s
VMFaultInfo


pmcb_s

include vmm.inc

pmcb_s  struc
PMCB_Flags   dd  ?  ; control-block flags
PMCB_Parent  dd  ?  ; parent of the protected-mode application
pmcb_s  ends

Application control block. Contains information about a protected-mode application.

See Also

Get_Cur_PM_App_CB


Client_Reg_Struc

include vmm.inc

Client_Reg_Struc   struc
Client_EDI      dd      ?       ; client's EDI
Client_ESI      dd      ?       ; client's ESI
Client_EBP      dd      ?       ; client's EBP
                dd      ?       ; ESP when pusha instruction is executed
Client_EBX      dd      ?       ; client's EBX
Client_EDX      dd      ?       ; client's EDX
Client_ECX      dd      ?       ; client's ECX
Client_EAX      dd      ?       ; client's EAX
Client_Error    dd      ?       ; doubleword error code
Client_EIP      dd      ?       ; EIP
Client_CS       dw      ?       ; CS
                dw      ?       ;   (padding)
Client_EFlags   dd      ?       ; EFLAGS
Client_ESP      dd      ?       ; ESP
Client_SS       dw      ?       ; SS
                dw      ?       ;   (padding)
Client_ES       dw      ?       ; ES
                dw      ?       ;   (padding)
Client_DS       dw      ?       ; DS
                dw      ?       ;   (padding)
Client_FS       dw      ?       ; FS
                dw      ?       ;   (padding)
Client_GS       dw      ?       ; GS
                dw      ?       ;   (padding)
Client_Alt_EIP  dd      ?
Client_Alt_CS   dw      ?
                dw      ?
Client_Alt_EFlags  dd   ?
Client_Alt_ESP  dd      ?
Client_Alt_SS   dw      ?
                dw      ?
Client_Alt_ES   dw      ?
                dw      ?
Client_Alt_DS   dw      ?
                dw      ?
Client_Alt_FS   dw      ?
                dw      ?
Client_Alt_GS   dw      ?
                dw      ?
Client_Reg_Struc   ends

The Client_Reg_Struc structure contains the CPU register values of the virtual device or other program calling a service.


cb_s

include vmm.inc

cb_s    struc
CB_VM_Status        dd   ?  ; VM status; see below
CB_High_Linear      dd   ?  ; base linear address; see below
CB_Client_Pointer   dd   ?  ; see below
CB_VMID             dd   ?  ; virtual machine ID
CB_Signature        dd   ?  ; see below
cb_s    ends

Virtual machine control block. Contains information about and the status of a virtual machine. The handle of a virtual machine is also the address of its corresponding cb_s structure. All fields in this structure are read-only.

CB_VM_Status
Value specifying the status of the virtual machine. Can be zero or more of these values:
Value | Meaning
VMStat_Awakening | Virtual machine is waking up after being blocked on a semaphore.
VMStat_Background | Virtual machine runs in the background.
VMStat_Blocked | Virtual machine is blocked on a semaphore.
VMStat_Closing | Virtual machine has received a Close_VM message.
VMStat_Creating | Virtual machine is being created.
VMStat_Exclusive | Virtual machine is in exclusive mode.
VMStat_High_Pri_Back | Virtual machine has high priority background execution.
VMStat_Idle | Virtual machine has released its time slice.
VMStat_Not_Executable | Virtual machine is partially destroyed.
VMStat_PageableV86 | Virtual machine has pageable V86 memory (protected-mode application). The default behavior for one or more pages in V86 memory has been modified and the _GetV86PageableArray service returns at least one nonzero bit in the array.
VMStat_PM_App | Virtual machine contains a protected-mode application.
VMStat_PM_Exec | Virtual machine execution currently in a protected-mode application.
VMStat_PM_Use32 | Virtual machine contains a 32-bit protected-mode application.
VMStat_Suspended | Virtual machine is not scheduled.
VMStat_TS_Sched | Virtual machine is scheduled by the time slicer.
VMStat_V86IntsLocked | Virtual machine locks any V86 memory that cannot be paged. Locking regardless of the pager type has been enabled for the virtual machine.
VMStat_VxD_Exec | Virtual machine has received a call from a virtual device.

CB_High_Linear
Base address of the virtual machine's memory in the ring-0 linear address space. Virtual devices can access memory in a virtual machine by adding the appropriate V86-mode linear address to this value.
CB_Client_Pointer
Address of a Client_Reg_Struc structure containing the register values for the virtual machine.
CB_VMID
Virtual machine identifier.
CB_Signature
Value VMCB_ID.

See Also

Close_VM, Client_Reg_Struc


Exception_Handler_Struc

include vmm.inc

Exception_Handler_Struc struc
EH_Reserved     dd      ?
EH_Start_EIP    dd      ?
EH_End_EIP      dd      ?
EH_Handler      dd      ?
Exception_Handler_Struc ends

The Exception_Handler_Struc structure contains information about a ring-0 exception handler.

EH_Reserved
Reserved; must be zero.
EH_Start_EIP
Specifies the starting address of the exception handler's supported range of addresses.
EH_End_EIP
Specifies the ending address of the exception handler's supported range of addresses.
EH_Handler
Points to the exception handler.

See Also

Install_Exception_Handler


IPF_Data

include vmm.inc

IPF_Data    struc
IPF_LinAddr     dd  ?   ; CR2 address of fault
IPF_MapPageNum  dd  ?   ; possible converted page number of fault
IPF_PTEEntry    dd  ?   ; contents of PTE that faulted
IPF_FaultingVM  dd  ?   ; may not = current VM (IPF_V86PgH set)
IPF_Flags       dd  ?   ; flags
IPF_Data    ends

The IPF_Data structure contains information about the current invalid page fault.

IPF_LinAddr
Specifies the CR2 address of the page fault. Do not read from the CR2 register directly; use this value instead.
IPF_MapPageNum
Specifies the possible converted page number of the fault.
IPF_PTEEntry
Specifies the contents of the page-table entry that caused the fault.
IPF_FaultingVM
Specifies the handle identifying the virtual machine that caused the fault. This is not necessarily the current virtual machine.
IPF_Flags
Specifies the invalid page-fault flags. It can be a combination of the following values:
Value | Meaning
IPF_InvTyp | Page has invalid not-present type.
IPF_PgDir | Page directory entry not present (not-present page table).
IPF_PgErr | Page swap device could not page for some reason.
IPF_PM | Page fault caused by virtual machine running in protected mode.
IPF_ReFlt | Re-entrant page fault.
IPF_V86 | Page fault caused by virtual machine running in V86 mode.
IPF_V86Pg | Unexpected not-present page in V86.
IPF_V86PgH | Unexpected not-present page in V86 at high linear address.
IPF_VMM | Page fault caused by a virtual device.

Invalid page faults occur in a virtual machine other than the current virtual machine if the high linear address of the virtual machine is accessed. In this case, the IPF_FaultingVM field is set to the handle of the virtual machine that owns the high linear address.

See Also

Hook_Invalid_Page_Fault


Pushad_Struc

include vmm.inc

Pushad_Struc struc
Pushad_EDI  dd  ?  ; EDI register at time of pushad
Pushad_ESI  dd  ?  ; ESI register at time of pushad
Pushad_EBP  dd  ?  ; EBP register at time of pushad
Pushad_ESP  dd  ?  ; ESP register at time of pushad
Pushad_EBX  dd  ?  ; EBX register at time of pushad
Pushad_EDX  dd  ?  ; EDX register at time of pushad
Pushad_ECX  dd  ?  ; ECX register at time of pushad
Pushad_EAX  dd  ?  ; EAX register at time of pushad
Pushad_Struc ends

Describes the stack frame built by the pushad instruction. Its typical uses are to reach back into a 'pushad' frame to recover a value that was saved in it, or to shove a value into it to be restored by a subsequent 'popad'.


tcb_s

include vmm.inc

tcb_s    struc
TCB_Flags            dd  ?  ; thread status flags; see below
TCB_Reserved1        dd  ?  ; reserved for use by VMM
TCB_Reserved2        dd  ?  ; reserved for use by VMM
TCB_Signature        dd  ?  ; SCHED_OBJ_THREAD_ID
TCB_ClientPtr        dd  ?  ; address of client registers
TCB_VMHandle         dd  ?  ; VM to which this thread belongs
TCB_ThreadId         dw  ?  ; thread ID
TCB_PMLockOrigSS     dw  ?  ; client SS at Begin_Use_Locked_PM_Stack
TCB_PMLockOrigESP    dd  ?  ; client ESP at Begin_Use_Locked_PM_Stack
TCB_PMLockOrigEIP    dd  ?  ; client EIP at Begin_Use_Locked_PM_Stack
TCB_PMLockStackCount dd  ?  ; number of outstanding
                            ;   Begin_Use_Locked_PM_Stack calls
TCB_PMLockOrigCS     dw  ?  ; client CS at Begin_Use_Locked_PM_Stack
TCB_PMPSPSelector    dw  ?  ; used by Vwin32
TCB_ThreadType       dd  ?  ; used by Vwin32
TCB_pad1             db  ?  ; padding
TCB_pad2             db  ?  ; padding
TCB_extErrLocus      db  ?  ; used by Vwin32
TCB_extErrAction     db  ?  ; used by Vwin32
TCB_extErrClass      db  ?  ; used by Vwin32
TCB_extErrPtr        dd  ?  ; used by Vwin32
tcb_s ends

Thread control block. Contains information about, and the status of, a thread. The handle of a thread is also the address of its corresponding tcb_s structure. All fields in this structure are read-only.

TCB_Flags
Value specifying the status of the thread. Can be zero or more of these values:
Value | Meaning
THFLAG_Suspended | Thread is not scheduled.
THFLAG_Not_Executeable | Thread has stopped executing.
THFLAG_Thread_Creation | Thread being created.
THFLAG_Thread_Blocked | Thread is blocked on a semaphore.
THFLAG_Ring0_Thread | Thread runs completely at ring 0.
THFLAG_ANSI THFLAG_OEM THFLAG_UNICODE THFLAG_RESERVED | Used by Vwin32 to indicate file system character set.
THFLAG_Extended_Handles | Thread uses extended handles.
THFLAG_Open_As_Immovable_File | Used by Vwin32 to prevent defragmenter from moving an open file.

These bits are read-only. Virtual devices should not attempt to modify any of these bits. Some of the descriptions might not be directly meaningful; don't worry. Only Vwin32 really cares about them.

TCB_Reserved1, TCB_Reserved2
Reserved by VMM for internal bookkeeping.
TCB_Signature
The value SCHED_OBJ_THREAD_ID.
TCB_ClientPtr
Pointer to thread client registers.
TCB_VMHandle
Handle of VM to which this thread belongs.
TCB_ThreadId
16-bit value that uniquely identifies the thread during its lifetime. Note that thread IDs are recycled. When a thread is destroyed, its ID becomes available for use.
TCB_PMLockOrigSS, TCB_PMLockOrigESP, TCB_PMLockStackCount, and TCB_PMLockOrigCS
Used internally by the Begin_Use_Locked_PM_Stack service.
TCB_PMPSPSelector, TCB_ThreadType, TCB_extErrLocus, TCB_extErrAction, TCB_extErrClass, and TCB_extErrPtr
Used internally by Vwin32.

See Also

Close_VM, Client_Reg_Struc


VMFaultInfo

include vmm.inc

VMFaultInfo    struc
VMFI_EIP   dd      ?   ;
VMFI_CS    dw      ?   ;
VMFI_Ints  dw      ?   ;
VMFaultInfo    ends

The VMFaultInfo structure contains data that describes the client state at the time of a fault in the virtual machine.

VMFI_EIP and VMFI_CS
Specifies the value of the instruction pointer and the code segment address at the time the fault occurred.
VMFI_Ints
Indicates the interrupt request lines (IRQs) that were in service when the fault occurred. Bit 0 is set if IRQ 0 was in service, bit 1 is set if IRQ 1 was in service, and so on.

See Also

GetSetDetailedVMError


DMA Devices

This section describes the interfaces of the virtual direct memory access device (VDMAD). Virtual devices that support hardware that requires direct memory access (DMA) transfers should use the services provided by the virtual DMA device to carry out these transfers.

The virtual DMA device virtualizes direct memory access devices and provides services that other virtual devices use to carry data transfers using DMA channels.


Reference

The following is an alphabetic listing of the virtual direct memory access (DMA) device services services and structures.

VDMAD_Copy_From_Buffer

VDMAD_Copy_To_Buffer

VDMAD_Default_Handler

VDMAD_Disable_Translation

VDMAD_Enable_Translation

VDMAD_Get_EISA_Adr_Mode

VDMAD_Get_Region_Info

VDMAD_Get_Version

VDMAD_Get_Virt_State

VDMAD_Lock_DMA_Region

VDMAD_Mask_Channel

VDMAD_Phys_Mask_Channel

VDMAD_Phys_Unmask_Channel

VDMAD_Release_Buffer

VDMAD_Request_Buffer

VDMAD_Reserve_Buffer_Space

VDMAD_Scatter_Lock

VDMAD_Scatter_Unlock

VDMAD_Set_EISA_Adr_Mode

VDMAD_Set_EISA_Phys_State

VDMAD_Set_IO_Address

VDMAD_Set_Phys_State

VDMAD_Set_PS2_Phys_State

VDMAD_Set_Region_Info

VDMAD_Set_Virt_State

VDMAD_Unlock_DMA_Region

VDMAD_Unlock_DMA_Region_No_Dirty

VDMAD_UnMask_Channel

VDMAD_Unvirtualize_Channel

VDMAD_Virtualize_Channel

All VDMAD services are consistent with DMA services as defined by the VDS specifications.


Services

The following topics describe the services provided.


VDMAD_Copy_From_Buffer

include vdmad.inc

mov ebx, BufferID
mov esi, OFFSET32 Region
mov edi, OFFSET32 BufferOffset
mov ecx, BufferSize
VxDcall VDMAD_Copy_From_Buffer
jc ErrorHandler

Allows another device to copy data from the VDMAD buffer to the DMA region associated with that buffer. Uses EAX, flags

  • The carry flag is clear if the data if the function succeeds. Otherwise, the carry flag is set and the AL register contains one of the following error values:
0Ah | DMA_Invalid_Buffer: invalid buffer ID supplied.
0Bh | DMA_Copy_Out_Range: (ESI + ECX) is greater than buffer size.

BufferID
Buffer identifier.
Region
Address of linear region.
BufferOffset
Offset within the buffer to the start of copying.
BufferSize
Buffer size in bytes.

This service is called after the VDMAD_Request_Buffer service, after a memory write transfer and before the VDMAD_Release_Buffer service.


VDMAD_Copy_To_Buffer

include vdmad.inc

mov ebx, BufferID
mov esi, OFFSET32 Region
mov edi, OFFSET32 BufferOffset
mov ecx, BufferSize
VxDcall VDMAD_Copy_To_Buffer
jc ErrorHandler

Allows another device to copy data into the VDMAD buffer from the DMA region associated with that buffer. Uses EAX, flags

  • The carry flag is clear if the function succeeds. Otherwise, the carry flag is set and the AL register contains one of the following error values:
0Ah | DMA_Invalid_Buffer: Invalid buffer ID supplied.
0Bh | DMA_Copy_Out_Range: (ESI + ECX) is greater than buffer size.

BufferID
Buffer identifier.
Region
Address of linear region.
BufferOffset
Offset within the buffer to the start of copying.
BufferSize
Buffer size in bytes.

This service is called after the VDMAD_Request_Buffer service, and before starting a memory-read transfer.


VDMAD_Default_Handler

include vdmad.inc

mov eax, DMA_Handle
mov ebx, VMHandle
VxDcall VDMAD_Default_Handler

Specifies the default DMA channel I/O callback procedure. Uses All

  • This service has no return value.
DMA_Handle
Handle of the DMA.
VMHandle
Handle of the VM.

The callback procedure receives notifications of virtual state changes, and configures the physical state to start DMA transfers.


VDMAD_Disable_Translation

include vdmad.inc

mov eax, DMA_Handle
mov ebx, VMHandle
VxDcall VDMAD_Disable_Translation
jc ErrorHandler

Disables the automatic translation done for the standard DMA channels. Uses flags

  • Clears the carry flag if the function succeeds, otherwise the carry flag is set.
DMA_Handle
Handle of the DMA.
VMHandle
Handle of the VM.

If a V86 application, a driver, or a protected-mode application uses the DMA services through INT 4B, it must determine actual physical addresses for DMA transfers.

A disable count is maintained, so a matching call to VDMAD_Enable_Translation is required for each call to this service to re-enable translation.


VDMAD_Enable_Translation

include vdmad.inc

mov eax, DMA_Handle
mov ebx, VMHandle
VxDcall VDMAD_Enable_Translation

Decrements the disable count associated with a standard DMA channel. Uses flags

  • Clears the carry flag if successful, otherwise sets the carry flag.
DMA_Handle
Specifies the DMA handle.
VMHandle
Specifies the virtual machine handle.

If the disable count goes to 0, the automatic translation is re-enabled.

This service clears the zero flag if automatic translation is re-enabled.


VDMAD_Get_EISA_Adr_Mode

include vdmad.inc

mov eax, Channel
mov ebx, DMA_Handle
VxDcall VDMAD_Get_EISA_Adr_Mode

Returns the EISA extended mode. Uses ECX, flags

  • The CL register contains one of the following values:
0 | 8-bit I/O, with count in bytes
1 | 16-bit I/O, with count in words and address shifted
2 | 32-bit I/O, with count in bytes
3 | 16-bit I/O, with count in bytes

Channel
Number of channel, it must be in the range 0 to 7.
DMA_Handle
Handle of DMA.

The hardware does not allow for reading the extended mode for a channel, so VDMAD defaults to the ISA defaults (channels 0-3 are byte channels, and 5-7 are word channels with word addresses and counts). A SYSTEM.INI setting can specify an alternate setting.


VDMAD_Get_Region_Info

include vdmad.inc

mov eax, DMA_Handle
VxDcall VDMAD_Get_Region_Info
mov [Buffer], bl
mov [LockFlag], bh
mov Region, esi
mov [RegionSize], ecx

Returns data describing the current region assigned to a DMA handle. This data includes the buffer identifier, page status, region address, and buffer size. Uses EBX, ECX, ESI

  • Returns information about the current region:
BL | Specifies the buffer identifier.
BH | Specifies whether pages are locked (zero is not locked, nonzero is locked).
ESI | Specifies the linear region.
ECX | Specifies the size of the buffer in bytes.

DMA_Handle
Handle of the DMA.

The data returned by this service can be used by a handler when it calls following services:

VDMAD_Unlock_DMA_Region

VDMAD_Release_Buffer

VDMAD_Copy_To_Buffer

VDMAD_Copy_From_Buffer


VDMAD_Get_Version

include vdmad.inc

VxDcall VDMAD_Get_Version
mov MajorVersion, ah
mov MinorVersion, al
mov BufferSize, ecx

Returns the major and minor version numbers of the virtual DMA device as well as the size of the buffer if one exists. Uses EAX, ECX, flags

  • Clears the carry flag if successful and returns the following version and buffer-size information:
AH | Major version number
AL | Minor version number
ECX | Buffer size in bytes.

A buffer is not available until the Init_Complete message is issued. If the buffer has not been allocated, ECX will contain zero when the service returns.


VDMAD_Get_Virt_State

include vdmad.inc

mov eax, DMA_Handle
mov ebx, VMHandle
VxDcall VDMAD_Get_Virt_State

Allows a channel owner to determine the current virtual state of the channel. Uses ECX, EDX, ESI, flags

  • If translation is enabled, the ESI register contains the high linear address of the user's DMA region. The high linear address is used so that the DMA can proceed even if a different virtual machine is actually running at the time of the transfer.

    If translation is not enabled, the ESI register contains the physical byte address programmed (shifted left 1, for word ports).

    The ECX register contains count in bytes.

    The DL register contains the mode. This is the same as the 8237 mode byte with channel number removed and the following DMA_masked and DMA_requested values set as appropriate:

DMA_masked | Channel masked and not ready for a transfer.
DMA_requested | Software request flag set.

The DH register contains the extended mode (ignored on non-PS/2 machines that do not have extended DMA capabilities).

DMA_Handle
Handle of DMA.
VMHandle
Handle of VM.

The virtual state consists of all the information necessary to physically program the DMA channel for a DMA transfer (linear address of target region, byte length of region, mode of transfer, and state of mask bit and software request bit).


VDMAD_Lock_DMA_Region

include vdmad.inc

mov esi, OFFSET32 DMA_Region
mov ecx, RegionSize
mov dl, Alignment
VxDcall VDMAD_Lock_DMA_Region
jc ErrorHandler

Attempts to lock a region of memory for a DMA transfer. Uses EAX, ECX, EDX, and flags

  • Clears the carry flag and copies the DMA address into EDX if the function succeeds. Otherwise, sets the carry flag and copies the number of bytes that can be locked into ECX (starting from ESI); the AL registers contains one of the following error values:
1 | DMA_Not_Contiguous: Region not contiguous.
2 | DMA_Not_Aligned: Region crossed physical alignment boundary.
3 | DMA_Lock_Failed: Unable to lock pages.

DMA_Region
Address of the DMA region.
RegionSize
Number of bytes in the DMA region.
Alignment
Region alignment. This parameter can be one of the following values:
1 | Region must be aligned on 64K page boundary.
2 | Region must be aligned on 128K page boundary.

The service first verifies that the region is mapped to contiguous pages of physical memory, then it determines whether the region results in a DMA bank (page) wrap.

Typically, each channel has a base address register and a page address register. The base address register is incremented after each byte or word is transferred. If the increment of this 16-bit register results in the roll over from 0FFFFh to 0, then the transfer wraps to the start of the DMA bank because the page register is not updated. Normally MS-DOS watches for this condition and adjusts Interrupt 13h parameters to split transfers to avoid this wrap, but MS-DOS does not account for the difference between linear and physical addresses with Windows, so VDMAD checks again to prevent wrap from occurring.

If these checks pass, the service calls the memory manager to lock the physical pages.

This service does not check to see if the region is within some physical maximum constraint. If the region can be locked, then it locks the memory, and it is up to the caller to check to see if the physical region is acceptable. If the region is not acceptable, then the caller should unlock the region and perform a buffered DMA transfer.

This service must be called before a DMA transfer is started, that is, before the physical state is set for a channel and before it is unmasked.


VDMAD_Mask_Channel

include vdmad.inc

mov eax, DMA_Handle
VxDcall VDMAD_Mask_Channel

Masks a channel so that it will not attempt any further DMA transfers. Uses flags

  • This service has no return value.
DMA_Handle
Handle of DMA.


VDMAD_Phys_Mask_Channel

include vdmad.inc

mov eax, [DMA_Handle]
VxDCall VDMAD_Phys_Mask_Channel

Masks the channel without checking the terminal count.

  • • No return value.
DMA_Handle
Handle of the DMA.

This service is asynchronous.


VDMAD_Phys_Unmask_Channel

include vdmad.inc

mov edx, DMA_Handle
mov ebx, VMHandle
VxDcall VDMAD_Phys_Unmask_Channel

Used by VxD clients to unmask the channel without checking for terminal count. This service may be used directly by VxDs performing DMA transfers.

  • No return value.
DMA_Handle
Handle of the DMA.
VMHandle
Handle of the VM.

This service is asynchronous.


VDMAD_Release_Buffer

include vdmad.inc

mov ebx, Buffer
VxDcall VDMAD_Release_Buffer
jc ErrorHandler

Releases the VDMAD buffer assigned to a DMA channel from a previous call to the VDMAD_Request_Buffer service. Uses flags

  • Clears the carry flag if the buffer is released. Otherwise, sets the carry flag.
Buffer
Identifier of buffer.

This service will exit from a critical section, making the DMA buffer becomes available for other users. Any data in the buffer is not automatically copied, so the VDMAD_Copy_From_Buffer service must be called if the data is important.


VDMAD_Request_Buffer

include vdmad.inc

mov esi, OFFSET32 DMA_Region
mov ecx, RegionSize
VxDcall VDMAD_Request_Buffer
jc ErrorHandler

Reserves the DMA buffer for a DMA transfer. Uses EAX, EBX, ESI, flags

  • Clears the carry flag if the service is successful. The EBX register contains the buffer identifier, and the EDX register contains the physical address of the buffer.

    Otherwise, the carry flag is set and the AL register contains one of the following error values:

5 | DMA_Buffer_Too_Small: Region request is too large for buffer.
6 | DMA_Buffer_In_Use: Buffer already in use.

DMA_Region
Address of the actual DMA region.
RegionSize
Size of the DMA region in bytes.


VDMAD_Reserve_Buffer_Space

include vdmad.inc

mov eax, PageCount
mov ecx, MaxAddress
VxDcall VDMAD_Reserve_Buffer_Space

Allows other devices that are going to handle DMA to make sure that VDMAD allocates a buffer large enough for any transfers that they might require. Uses flags

  • No return value.
PageCount
Number of pages requested.
MaxAddress
Maximum physical address that can be included in a DMA transfer. If this parameter is zero, there is no limit.

This service also allows a device to specify a maximum physical address that would be valid for the device's DMA requests. During the Init_Complete phase of initialization, VDMAD allocates the DMA buffer using all of the constraints specified by other devices. For example, the buffer is at least as big as the largest size specified by the calls to this service, and it allocates below the lowest maximum physical addresses specified.

This service is only available before the Init_Complete message.


VDMAD_Scatter_Lock

include vdmad.inc

mov ebx, VMHandle
mov al, Flags
mov edi, OFFSET32 DDS
VxDcall VDMAD_Scatter_Lock
jc ErrorHandler

Attempts to lock all pages mapped to a DMA region and returns the addresses of those pages. Uses EDX, ESI, flags.

  • Clears the carry flag and sets the zero flag if the entire region is locked. Clears the carry flag and the zero flag if a portion of the region is locked. Otherwise, sets the carry flag.
VMHandle
Handle of the virtual machine.
Flags
Operation flags. The parameter can be one of the following values:
0 | Fills the DDS table with physical addresses and sizes of the physical regions that make up the DMA region.
1 | Fills the DDS table with the actual page table entries.
2 | Prevents not-present pages from being locked. This value is ignored if bit 0 is not set.

DDS
Address of the extended DDS (DMA Descriptor Structure) to receive the information.

Upon returning, the EDX register contains the number of table entries needed to describe whole region, and the DDS_size field specifies the number of bytes locked. If the request was for page table copy (AL set to 1 or 3), then The ESI register contains an offset into first page for start of the region.


VDMAD_Scatter_Unlock

include vdmad.inc

mov ebx, VMHandle
mov al, Flags
mov edi, OFFSET32 DDS
VxDcall VDMAD_Scatter_Unlock
jc ErrorHandler

Attempts to unlock all pages locked by a previous call to the VDMAD_Scatter_Lock service. Uses flags

  • Clears the carry flag if the lock counts have been decremented. Otherwise, the carry flag is set.
VMHandle
Specifies the virtual machine handle.
Flags
Specifies the operation flags. The parameter can be one of the following values:
0 | Fills the DDS table with physical addresses and sizes of the physical regions that make up the DMA region.
1 | Fills the DDS table with the actual page table entries.
2 | Prevents not-present pages from being locked. This value is ignored if bit 0 is not set.
4 | Prevents pages from being marked as dirty. If bits 0 and 1 are set but 2 is clear, then not-present pages are not marked.

DDS
Points to the extended DDS (DMA Descriptor Structure) to receive the information.

If bits 0 and 1 in the AL register are set, the table at the end of the DDS is not required to unlock the previously locked pages; otherwise, the table is not used and caller need not maintain the table after the lock call.


VDMAD_Set_EISA_Adr_Mode

include vdmad.inc

mov eax, Channel
mov ebx, DMA_Handle
mov cl, Mode
VxDcall VDMAD_Set_EISA_Adr_Mode

Sets the EISA extended mode. Uses flags

  • No return value.
Channel
Specifies the channel number. It must be in the range 0 to 7.
DMA_Handle
Specifies the DMA handle.
Mode
I/O mode. It can be one of the following values:
0 | 8-bit I/O, with count in bytes
1 | 16-bit I/O, with count in words and address shifted
2 | 32-bit I/O, with count in bytes
3 | 16-bit I/O, with count in bytes


VDMAD_Set_EISA_Phys_State

include vdmad.inc

mov eax, [DMA_Handle]
mov ebx, [VMHandle]
mov edx, [Mode]
VxDCall VDMAD_Set_EISA_Phys_State

Programs the DMA controller state for a channel. Uses flags.

  • No return value.
DMA_Handle
Handle of the DMA.
VMHandle
Handle of the virtual machine.
Mode
Requested mode. The extended mode is specified in DH, the mode itself is specified in DL.

This service should be used instead of VDMAD_Set_Phys_State for EISA systems. The VDMAD_Set_Region service must be called prior to calling VDMAD_Set_EISA_Phys_State.


VDMAD_Set_IO_Address

include vdmad.inc

mov eax, Channel_Number
mov edx, Port_Number
VxDcall VDMAD_Set_IO_Address

Changes the port associated with the given DMA channel to be used in the programmed I/O mode. This service is for use only on PS/2 computers. The Windows 95 I/O subsystem uses this service to determine if the port associated with a DMA channel is in its default location. In most cases, there should be no need for any other VxD to use this service.

  • No return value.
Channel_Number
Number of the channel.
Port_Number
Number of the I/O port.


VDMAD_Set_Phys_State

include vdmad.inc

mov eax, DMA_Handle
mov ebx, VMHandle
mov dl, Mode
mov dh, Ext_Mode
VxDcall VDMAD_Set_Phys_State

Programs the DMA controller state for a channel. Uses Flags

  • No return value.
DMA_Handle
Handle of the DMA.
VMHandle
Handle of the VM.
Mode
Mode.
Ext_Mode
Extended mode.

This service takes the location and size of the buffer from the information passed in a previous call, to the VDMAD_Set_Region_Info service.


VDMAD_Set_PS2_Phys_State

include vdmad.inc

mov eax, [DMA_Handle]
mov ebx, [VMHandle]
mov edx, [Mode]
VxDCall VDMAD_Set_PS2_Phys_State

Programs the DMA controller state for a channel. Uses flags.

  • No return value.
DMA_Handle
Handle of the DMA.
VMHandle
Handle of the virtual machine.
Mode
Requested mode. The extended mode is specified in DH, the mode itself is specified in DL.

This service should be used instead of VDMAD_Set_Phys_State for PS2 systems if a micro channel is detected at initialization time. The VDMAD_Set_Region service must be called prior to calling VDMAD_Set_PS2_Phys_State.


VDMAD_Set_Region_Info

include vdmad.inc

mov eax, DMA_Handle
mov bl, Buffer
mov bh, LockStatus
mov esi, OFFSET32 Region
mov ecx, RegionSize
mov edx, OFFSET32 PhysAddress
VxDcall VDMAD_Set_Region_Info

Sets information about the current region assigned to a DMA handle. Uses flags

  • No return value.
DMA_Handle
Handle of the DMA.
Buffer
Identifier for buffer.
LockStatus
Status of pages (zero if not locked, nonzero if locked).
Region
Address of region.
RegionSize
Size of region in bytes.
PhysAddress
Physical address for the transfer.

This service must be called before calling the VDMAD_Set_Phys_State service.


VDMAD_Set_Virt_State

include vdmad.inc

mov eax, DMA_Handle
mov ebx, VMHandle
mov esi, OFFSET32 Address
mov ecx, Size
mov dl, Mode
mov dh, ExtMode
VxDcall VDMAD_Set_Virt_State

Modifies the virtual state of a DMA channel. Uses flags

  • No return value.
DMA_Handle
Handle of the DMA.
VMHandle
Handle of the VM.
Address
A high linear address or a physical byte address. If translation is enabled, this parameter is the high linear address of the user's DMA region. A high linear address is used so that the DMA can proceed even if a different virtual machine is actually running at the time of the transfer. If translation is not enabled, this parameter specifies a physical byte address programmed (shifted left 1, for word ports).
Size
Specifies the count in bytes.
Mode
Specifies the mode. This is the same as the 8237 mode byte with the channel number removed, and the following DMA_masked and DMA_requested values set as appropriate:
DMA_masked | Channel masked and not ready for a transfer.
DMA_requested | Software request flag set.

ExtMode
Specifies the extended mode (ignored on non-PS/2 machines that do not have extended DMA capabilities).

This service is used when a channel owner wants to change the virtual state of a channel from how the virtual machine programmed it. This might be used to split a DMA request into smaller pieces.


VDMAD_Unlock_DMA_Region

include vdmad.inc

mov esi, OFFSET32 DMA_Region
mov ecx, Size
VxDcall VDMAD_Unlock_DMA_Region
jz ErrorHandler

Unlocks the DMA region previously locked to a channel. Uses flags

  • Clears the carry flag if successful, otherwise the carry flag is set.
DMA_Region
Linear address of the actual DMA region.
Size
Size in bytes of the DMA region.

This service is called after a DMA transfer is complete and the channel has been masked, preventing the controller from attempting any further transfers to the programmed address.


VDMAD_Unlock_DMA_Region_No_Dirty

include vdmad.inc

mov esi, OFFSET32 DMA_Region
mov ecx, Size
VxDcall VDMAD_Unlock_DMA_Region_No_Dirty
jc  error

Unlocks the DMA region previously locked to a channel but does not mark each page in the region as dirty. In most cases, the VDMAD_Unlock_DMA_Region service should be used. However, if you are performing a memory read operation, (for example, doing DMA output to a device) and you know that the page has not been touched, VDMAD_Unlock_DMA_Region_No_Dirty may be used to prevent the page from being marked as dirty. Uses Flags.

  • Clears the carry flag if successful, otherwise the carry flag is set.
DMA_Region
Linear address of the DMA region.
Size
Size in bytes of the DMA region.


VDMAD_UnMask_Channel

include vdmad.inc

mov eax, DMA_Handle
mov ebx, VMHandle
VxDcall VDMAD_UnMask_Channel

Physically unmasks a channel so that DMA transfers can proceed. Uses flags

  • No return value.
DMA_Handle
Handle of the DMA.
VMHandle
Handle of the virtual machine.


VDMAD_Unvirtualize_Channel

include vdmad.inc

mov eax, DMA_Handle
VxDcall VDMAD_Unvirtualize_Channel
jc error

Allows a VxD to release its virtualization of a standard DMA channel. The previously registered callback procedure will not be called again. The channel is available for virtualization by other VxDs. VDMAD will continue to trap the I/O for the channel, but will not change the physical state of the channel as a result of any VM I/O. Uses EAX, EDX, Flags

  • Clears the carry flag if successful. Sets the carry flag if the DMA_Handle is invalid.
DMA_Handle
Handle of the DMA.


VDMAD_Virtualize_Channel

include vdmad.inc

mov eax, Channel
move esi, OFFSET32 CallbackProc
VxDcall VDMAD_Virtualize_Channel
jz ErrorHandler

Allows another virtual device to claim ownership of a standard DMA channel. Uses EAX, EDX, flags

  • Clears the carry flag and places the DMA handle in EAX if the function is successful, otherwise sets the carry flag.
Channel
Number of channel.
CallbackProc
Address of the callback procedure. If this parameter is zero, no callback procedure is called.

The system calls the callback procedure by passing it the following input parameters:

EAX     ; DMA handle
EBX     ; virtual machine handle

The procedure can modify EAX, EBX, ECX, EDX, ESI, EDI, and flags.

In some cases a virtual device does not allow a virtual machine to perform DMA to a channel. Instead, the virtual device handles programming based on a private API and not on virtualized hardware I/O. This means it is possible to pass a zero to specify no callback procedure. VDMAD continues to trap the I/O for the channel, but never changes the physical state of the channel as a result of any virtual machine I/O.

The new owner registers a callback procedure that is called whenever the virtual state of the channel is changed as a result of I/O carried out in a virtual machine.


Structures

The following topics describe the structures provided.


DMA_Descriptor_Struc

include vdmad.inc

DMA_Descriptor_Struc STRUC
DDS_size      dd    ? ; see below
DDS_linear    dd    ? ; see below
DDS_seg       dw    ? ; see below
DDS_bufferID  dw    ? ; see below
DDS_physical  dd    ? ; see below
DMA_Descriptor_Struc ENDS

Describes the DMA region.

DDS_size
Size in bytes of the of the DMA region.
DDS_linear
Linear address of the DMA region.
DDS_seg
Segment or selector of the DMA region.
DDS_bufferID
This field is filled in by the Request DMA Buffer service and possibly the Lock DMA Region service.
DDS_physical
This field is filled in by the Lock DMA Region and Request DMA Buffer services.

DDS_linear and DDS_seg specify a 48-bit segment:offset pointer for virtual 8086 mode, or a selector:offset pointer for protected mode programs. Note that if the linear address has already been determined then you may set the DDS_seg to 0 and place the linear address in the linear offset field. It is possible to specify 32-bit offsets, even with real mode segment values; this makes it much easier for device drivers to split up DMA transfers, by simply modifying the offset without having to modify the segment/selector.


Extended_DDS_Struc

include vdmad.inc

Extended_DDS_Struc STRUC
           dd  ?    ; DDS_size see DMA_Descriptor_Struc
           dd  ?    ; DDS_linear see DMA_Descriptor_Struc
           dw  ?    ; DDS_seg see DMA_Descriptor_Struc
           dw  ?    ; reserved
DDS_avail  dw  ?
DDS_used   dw  ?
Extended_DDS_Struc ENDS

Describes the DMA region.

DDS_avail
The number of physical regions/page table entries that immediately follows the Extended_DDS_Struc structure.
DDS_used
The number of table entries filled in with physical regions information.


MS-DOS Manager

The virtual MS-DOS manager virtualizes the elements of the MS-DOS operating system, such as device drivers and internal flags. This device also manages instance data for MS-DOS.


Reference

The virtual MS-DOS manager provides the following services:

DOSMGR_Add_Device

DOSMGR_Alloc_Local_Sys_VM_Mem

DOSMGR_Begin_V86_App

DOSMGR_BackFill_Allowed

DOSMGR_Copy_VM_Drive_State

DOSMGR_Enable_Indos_Polling

DOSMGR_End_V86_App

_DOSMGR_Exec_VM

DOSMGR_Get_DOS_Crit_Status

DOSMGR_Get_IndosPtr

DOSMGR_Get_Version

DOSMGR_Init_UMB_Area

DOSMGR_Instance_Device

DOSMGR_LocalGlobalReg

DOSMGR_Remove_Device

_DOSMGR_Set_Exec_VM_Data


DOSMGR_Add_Device

include dosmgr.inc

mov     ebx, VMAdd
mov     eax, OFFSET32 Device_Header
VxDcall DOSMGR_Add_Device
jc      error_handler

Adds a device to the device list. Uses Flags.

  • Clears the carry flag if successful; otherwise, sets the carry flag if the device could not be added to device list.
VMAdd
Handle of the virtual machine to add device to. If this parameter is zero, the device is added to all virtual machines.
Device_Header
Address of device header. This address must be in low memory (less than 100000h).

The address of this device for the chain is computed as:

(eax >> 4) & 0FFFFh : (eax & 000Fh)

This service links the device into the list but does not call it. If the device needs to be initialized, the caller must do it. This service adds the device to the end of the device chain. Therefore, this service cannot be used to replace an existing device. This service applies to character devices only. Block devices cannot be added with this service.

All devices put on the list this way are removed when Windows exits, including any devices added by virtual mode code.

The only supported method to add a device globally is to use the service _Allocate_Global_V86_Data_Area to allocate memory to contain the device header, initialize it, then call this routine to add it to the list. Global devices must be added during the Device_Init message. They cannot be added later. Local devices must be added at the VM_Init, VM_Critical_Init or Sys_VM_Init message or they will be global because they will be part of the initial VM state.

If this device hooks an interrupt and it is a local device, the vector must be set in the appropriate virtual machine during the VM_Init, VM_Critical_Init or Sys_VM_Init message.

A global device can also work this way, hooking the vector in every virtual machine. This allows the global device to be removed before Windows exits. The other method for a global device is to hook the vector during the Device_Init message which makes the hook part of the initial virtual machine state. Such a hook must be removed during the Sys_Critical_Exit message, or the vector will point to a nonexistent device after Windows exits.


DOSMGR_Alloc_Local_Sys_VM_Mem

include dosmgr.inc

mov ax, NumParagraphs
VxDcall DOSMGR_Alloc_Local_Sys_VM_Mem

Reserves local V86 memory in the system VM. Uses EAX and Flags.

  • Returns in the AX register the offset in paragraphs from the First V86 Page to the start of the reserved area.

The offset returned is an offset from First V86 Page which is returned by the service GetFirstV86Page. This page is not valid until the start of the Sys_VM_Init System_Control broadcast. So, a client of this service must watch for that control call, then call GetFirstV86Page and add the offset returned by this service to determine the actual location of the reserved memory. The memory is actually not ready until the SHELL VxD calls DOSMGR to do the initial exec, so the memory is only available after the SHELL VxD's Sys_VM_Init handler. Also note that this service is an initialization time only service, so it must be called before the end of the Init_Complete control call.


DOSMGR_BackFill_Allowed

include dosmgr.inc

VxDcall DOSMGR_BackFill_Allowed
jc      no_backfilling

Specifies whether the MS-DOS configuration allows for low-memory backfills. The V86MMGR device calls this service. Uses Flags.

  • Clears the carry flag if backfilling is allowed; otherwise, set the carry flag.

This service depends on the high MS-DOS state. Certain high MS-DOS configurations prevent low memory 640K backfill from being possible.


DOSMGR_Begin_V86_App

include vmm.inc
include dosmgr.inc

; Install a hook procedure
GetVxDServiceOrdinal eax, DOSMGR_Begin_V86_App
mov esi, OFFSET32 HookProc
VMMcall Hook_Device_Service

jc error

This service is called internally by DOSMGR when a V86-mode application is about to begin execution. The application has been loaded and relocated, but its code has not yet been run. VxDs which wish to be notified of this activity must hook this service. VxDs must not call this service directly. The hook procedure must be a 4.0 Hook_Proc style procedure.

VxDs which monitor resources may wish to hook this service (and the corresponding DOSMGR_End_V86_App) in order to allocate and free resources for each MS-DOS-based application. To monitor Windows-based applications, VxDs should monitor the system control calls related to threads.

The system calls the hook procedure as follows:

mov ebx, VMHandle
mov esi, HighLinearPSP
mov dx,  AppPSP
call HookProc
VMHandle
VM that performed the int 21h.
HighLinearPSP
High linear address of the program segment prefix (PSP) of the application which is about to run.
AppPSP
Segment value of the PSP of the application which is about to be run.

Any VxD which hooks this service must pass the call down to the previously-installed hook, preserving all registers (except Flags), even registers reserved for future use.

Do not assume that the high word of the EDX register will be zero.


DOSMGR_Copy_VM_Drive_State

include dosmgr.inc

mov     ebx, VMCopyTo
mov     esi, VMCopyFrom
VxDcall DOSMGR_Copy_VM_Drive_State

Copies the drive and current directory state of all drives from one virtual machine to another virtual machine. This service can be called during a Create_VM message since it does not simulate calls or interrupts in either virtual machine; it just copies instance data from one to the other. Uses Flags.

  • No return value.
VMCopyTo
Handle of the virtual machine to receive a copy of the drive state.
VMCopyFrom
Handle of the virtual machine from which to copy the drive state.

This service does not change the current drive of the destination virtual machine.

This service does not disturb the InitDrvDir value set using the _DOSMGR_Set_Exec_VM_Data service if it is called before the _DOSMGR_Exec_VM service. The processing of InitDrvDir occurs during calls to the _DOSMGR_Exec_VM service.


DOSMGR_Enable_Indos_Polling

include dosmgr.inc

VxDcall DOSMGR_Enable_Indos_Polling

Enables the InDOS polling for the Windows session. This allows TSR drivers that hook Interrupt 21h, and claim the critical section by setting the internal MS-DOS InDOS flag to continue to operate normally.

This service is intended for use by the virtual DOSNET device so that it can enable polling if the installed network requires it. The virtual device must not call this service during a Sys_Critical_Init message. Uses Flags.

  • Clears the carry flag if InDOS polling is enabled; otherwise, sets the carry flag to indicate polling was already enabled.

Enabling InDOS polling has a severe impact on overall system performance.

This service overrides the InDOSPOLLING value specified in the SYSTEM.INI file. Since the virtual MS-DOS manager evaluates the SYSTEM.INI file during the Init_Complete message, a virtual device must call this service during the Device_Init message.


DOSMGR_End_V86_App

include vmm.inc
include dosmgr.inc

; Install a hook procedure

GetVxDServiceOrdinal eax, DOSMGR_End_V86_App
mov esi, OFFSET32 HookProc
VMMcall Hook_Device_Service

jc error

This service is called internally by DOSMGR when a V86-mode application has ended execution. VxDs which wish to be notified of this activity must hook this service. VxDs must not call this service directly. The hook procedure must be a 4.0 Hook_Proc style procedure.

VxDs which monitor resources may wish to hook this service (and the corresponding DOSMGR_Begin_V86_App) in order to allocate and free resources for each MS-DOS-based application. To monitor Windows-based applications, VxDs should monitor the system control calls related to threads.

The system calls the hook procedure as follows:

mov ebx, VMHandle
mov esi, HighLinearPSP
mov dx,  AppPSP
mov cx, AppExitCode
VMHandle
VM that performed the int 21.
HighLinearPSP
High linear address of the program segment prefix (PSP) which is terminating.
AppPSP
Segment value of the PSP of the application which is terminating.
AppExitCode
Application exit code. This is the value which will be returned in AX when the parent calls Get Child-Program Return Value (Interrupt 21h function 4Dh).
CH | Application exit type
CH = 0 | Normal termination
CH = 1 | Terminated via Ctrl+C
CH = 2 | Terminated due to critical error (e.g., disk I/O error)
CH = 3 | Terminated and stayed resident
CL | Application return code (application-specific value)

Any VxD which hooks the service must pass the call down to the previously-installed hook, preserving all registers, (except Flags) even registers reserved for future use.

Do not assume that the high bytes of the EDX and ECX registers will be zero.


_DOSMGR_Exec_VM

include dosmgr.inc

VxDcall _DOSMGR_Exec_VM <VMHandle, V86Size, CallBack, RefData>

Schedules the execution specified by a previous call to the _DOSMGR_Set_Exec_VM_Data service, and sets other parameters of the execution.

  • No return value.
VMHandle
Handle of the current virtual machine.
V86Size
Size in pages of the virtual machine. This service does not map these pages; the value is simply used to set the MS-DOS size of the virtual machine.
CallBack
Callback procedure to call when the virtual machine terminates. If this parameter is zero, no callback is called.
RefData
Reference data to pass to the callback procedure.

The system calls the callback when the virtual machine terminates. The callback receives the following input parameters:

EBP | points to a Client_Reg_Struc
EBX | virtual machine handle
EDX | points to reference data

The callback must preserve the EBX, EBP, and segment registers. After the callback returns, the system carries out the normal virtual machine termination sequence. At this time, the virtual machine is still in a running state. The callback can delay termination by delaying its return. However, the callback must simulate interrupts into the virtual machine to keep the scheduler moving if it is holding termination.


DOSMGR_Get_DOS_Crit_Status

include dosmgr.inc

VxDcall DOSMGR_Get_DOS_Crit_Status

Specifies whether it is possible to call MS-DOS at the current time (that is, whether MS-DOS is in a critical section).

This service is intended for use by the virtual page swap device to determine whether MS-DOS is currently available to page. This is an asynchronous service. Uses Flags.

  • Sets the zero flag if MS-DOS can be called; otherwise, clears the zero flag if MS-DOS is in a critical section, and must not be called.

This service does not specify whether Windows is in a critical section, nor does it specify which virtual machine has ownership of MS-DOS.


DOSMGR_Get_IndosPtr

include dosmgr.inc

VxDcall DOSMGR_Get_IndosPtr

Retrieves the linear address of the MS-DOS InDOS and ErrorMode flags. Uses EAX and Flags.

  • Returns the linear address (V86 mode address) of InDOS and ErrorMode word in EAX. The low byte is the ErrorMode variable, the high byte is InDOS.

This is a low linear address. To examine the value in a virtual machine which is not the current virtual machine, the virtual device must add the virtual-machine high-linear address to this value.


DOSMGR_Get_Version

include dosmgr.inc

VxDcall DOSMGR_Get_Version

Retrieves the virtual MS-DOS manager version number. Uses EAX and Flags.

  • Returns the version number in EAX. AH contains the major version number, and AL contains the minor version number.


DOSMGR_Init_UMB_Area

include dosmgr.inc

VxDcall DOSMGR_Init_UMB_Area

Initializes the MS_DOS upper memory block.

  • Clears the carry flag if successful.


DOSMGR_Instance_Device

include dosmgr.inc

mov     esi, OFFSET32 Device_Name
VxDcall DOSMGR_Instance_Device

Instances the installed MS-DOS character device driver. This service is only valid during the Init_Complete message. Uses Flags.

  • Clears the carry flag if the device is instanced; otherwise, sets the carry flag to indicate one of the following errors:
    • No device with this name in device list
    • Device is in MS-DOS RAM BIOS (Segment of device == 70h)
    • User overrides with the global setting in SYSTEM.INI
Device_Name
Address of the 8-character device name. This name must exactly match the name as it found in the device header in low memory. Characters must be in uppercase; case conversion is not performed. Names shorter than 8 characters must be padded with spaces. The colon (:) must not be used.

This service applies only to installed character devices (where the device segment is not equal to 70h). It cannot instance devices that are in the MS-DOS RAM BIOS because there is no way to determine their start and end addresses. It is the job of MS-DOS instancing to correctly instance things related to character devices in the MS-DOS RAM BIOS.

This service instances the entire device. It cannot differentiate code and data.

This service is available only during the Init_Complete message. The service is in the ICODE segment so it becomes invalid after the Init_Complete message. Calls to the _AddInstanceItem service are also invalid after Init_Complete.

Do not use this service to instance devices added with the service DOSMGR_Add_Device. To instance an added device, a virtual device must call the _AddInstanceItem service or use the GVDAInstance flag in the _Allocate_Global_V86_Data_Area service.


DOSMGR_LocalGlobalReg

include dosmgr.inc

mov     edx, PageStart
mov     edi, PageEnd
VxDcall DOSMGR_LocalGlobalReg
mov     [Page_Range_Flag], eax

Determines whether the indicated V86 memory region is local or global memory The VMM memory manager calls this service whenever the TestGlobalV86Mem service is called. This service is only available for Windows version 3.1 and later. Uses EAX and Flags.

  • Returns a page range flag in EAX. It can be one of these values:
0 | Page range is local.
1 | Page range is global.
2 | Page range is partially global and partially local.
3 | Page range is unknown.

PageStart and PageEnd
Page numbers of the start and end of the region.

This service returns 3 unless the region is in a local high MS-DOS region.

This service supports high MS-DOS configurations for MS-DOS version 5.0 or later. Other load high configurations are supported only if the corresponding software hooks this service or the TestGlobalV86Mem service.

This service is page (4K) granular and not byte granular.


DOSMGR_Remove_Device

include dosmgr.inc

mov     ebx, VMRemove
mov     eax, OFFSET32 [Device_Header]
VxDcall DOSMGR_Remove_Device

Removes a device from the device list. The device must have been previously added using the DOSMGR_Add_Device service. Uses Flags.

  • Clears the carry flag if is successful; otherwise, sets the carry flag if the device could not be removed from device list.
VMRemove
Handle of the virtual machine from which to remove the device. If this parameter is zero, the device is removed from all virtual machines.
Device_Header
Address of device header. This parameter must be a low memory linear address (less than 100000h).

Global calls to DOSMGR_Add_Device should not be mixed with local calls to DOSMGR_Remove_Device for the same device. All DOSMGR_Add_Device devices are automatically removed when Windows quits.

This service removes the link to the device from the device list. It does not free any memory or resources that the device may have created or allocated.


_DOSMGR_Set_Exec_VM_Data

include dosmgr.inc

VxDcall _DOSMGR_Set_Exec_VM_Data, <VM, CommTail, PRGName, InitDrvDir>

Sets the data for the initial execution into a virtual machine. It is reserved for exclusive use by the virtual shell device. This service can be called during the Create_VM message because it does not simulate calls or interrupts into the virtual machine; it just sets instance data.

  • No return value.
VM
Handle of the virtual machine to set execution data for.
CommTail
Address of the command tail for the execution. The tail can be up to 128 bytes. The first byte must specify the number of bytes in the tail; the last byte must be 0Dh.
PRGName
Address of a null-terminated string specifying the name of the program to execute.
InitDrvDir
Address of a null-terminated string specifying the initial directory and drive for the virtual machine. The drive letter must be a capital letter. The string must be less than or equal to 64 characters, including null terminator.

If this parameter is zero, the service does not set the default directory. This form of the service is made by the DOSMGR_Exec_VM service. Other virtual devices should not use this form.

This service must be called before calling the _DOSMGR_Exec_VM service.


Page Swapping

This section describes the interfaces of the virtual paging device (PAGESWAP) and the virtual page swap device (PAGEFILE). The virtual paging device manages all demand-paging operations for Windows, determining which pages can be saved or retrieved from disk. This device uses the virtual swap file device to read and write pages to disk. The swap file device manages the virtual memory swapping file and carries out all read and write operations requested by the paging device.


Paging Device Services

The following topics describe the paging device services.


PageSwap_Init_File

VxDcall PageSwap_Init_File
jc      error_handler
mov     pager_type, bl     ; pager type returned in BL

Called by the memory manager at the end of device initialization to create the swap file. Uses EAX, EBX, ECX, EDX, Flags.

  • Returns with the carry flag set on error. Otherwise, the carry flag is clear and the BL register contains the type of page swap device: 1 if none, 2 if the swap device uses MS-DOS, 3 if the swap device uses the Windows 95 layered device driver.


PageSwap_Get_Version

VxDcall PageSwap_Get_Version
jc      not_installed      ; carry set if not installed
mov     version, eax       ; version number (Windows 95 is 400h)
mov     maxsize, ecx       ; max. size of swap file in pages
mov     pager_type, bl     ; pager type; see below

Gets the virtual paging device version number, the type of paging in effect, and the maximum size of the paging file in pages. Uses Flags.

  • Returns with the carry flag clear and zero in EAX if the pager is not installed. Otherwise, the carry flag is clear and these registers contain these values:
EAX | Version number of paging device. Major version in AH, minor in AL.
ECX | Maximum size of the swap file, in pages. This value is valid only after device initialization.
BL | Type of page swap device: 1 if none, 2 if the swap device uses MS-DOS, 3 if the swap device uses the Windows 95 layered device driver.


PageSwap_Test_IO_Valid

VxDcall PageSwap_Test_IO_Valid
jc      paging_not_permitted

Determines whether paging to or from disk can be performed. Uses Flags.

  • Returns with carry clear if paging is permitted. Otherwise, the carry flag is set, indicating you should avoid operations that may cause paging.


PageSwap_Grow_File

mov     ecx, cPages    ; number of pages to grow by
VxDcall PageSwap_Grow_File
mov     newsize, ecx   ; new size of the file, in pages
mov     maxsize, ebx   ; maximum size of the file, in pages

Increases the size of the swap file by the specified number of pages. Uses EAX, EBX, Flags.

  • Returns the new size of the swap file in the EAX register, and the maximum size in the EBX register. The maximum size may be less than when the file was created.
cPages
Number of pages to grow the swap file by.

If the file cannot grow by the requested number of pages, the new size will be less than requested and equal to the maximum size.


PageSwap_Read_Or_Write

mov     ch, read_or_write  ; PF_Read_Data or PF_Write_Data
mov     edi, filepos       ; file position, in pages
mov     esi, pPage         ; linear address of memory to touch
VxDcall PageSwap_Read_Or_Write
or      eax, eax
jz      error_handler

Reads a page from disk or writes a page to disk. Uses Flags.

  • Returns a nonzero value in EAX if successful, zero otherwise.
read_or_write
Value indicating whether to read from or write to the swap file. Can be PF_Read_Data or PF_Write_Data.
filepos
Offset in the swap file to read from or write to, in pages.
pPage
Linear address of the memory page to read from or write to.


Page Swap Device Services

The following topics describe the page swap device services.


PageFile_Init_File

VxDcall PageFile_Init_File
mov     max_size, ebx      ; maximum swap file size, in pages
mov     current_size, eax  ; current swap file size, in pages
or      ebx, ebx
jz      error_handler      ; ebx = 0 on error

Called by PAGESWAP to initialize the swap file. Can only be called at initialization time. Uses EAX, EBX, ECX, EDX, Flags.

  • Returns with zero in the EBX register if an error occurs. Otherwise, EAX contains the swap file's current size and EBX its maximum size, in pages.


PageFile_Clean_Up

Obsolete. Uses Flags.

  • Returns with the carry flag clear.


PageFile_Get_Size_Info

VxDcall PageFile_Get_Size_Info
jc      not_installed      ; carry set if not installed
mov     filesize, eax      ; size of the paging file, in pages
mov     abs_max_size, ebx  ; absolute max. size of paging file, in pages
mov     max_poss_size, ecx ; max. possible size of paging file, in pages
mov     min_size, edx      ; min. size of paging file, in pages
mov     pager_type, bl     ; pager type; see below

Retrieves information about the size of the paging file. Uses Flags.

  • Returns with the carry flag set and zero in EAX if the pager is not installed. Otherwise, the carry flag is clear and these registers contain these values:
EAX | Current size, in pages, of the paging file.
EBX | Absolute maximum size of the paging file, in pages. The size determined by the value of the MaxPagingFile entry in SYSTEM.INI. If no value is specified, the size is set to 2 gigabytes. The size is zero if paging is off.
ECX | Current maximum possible size of the paging file, in pages, given the current amount of free disk space.
EDX | Minimum size of the paging file, in pages. The size determined by the value of the MinPagingFile entry in SYSTEM.INI. If no value is specified, the minimum size zero.
ESI | Address of a null terminated string that contains the full path name of the swap file. Do not write to this pointer. If EBX is zero, ESI is undefined.


PageFile_Get_Version

VxDcall PageFile_Get_Version
jc      not_installed      ; carry set if not installed
mov     version, eax       ; version number (400h for Windows 95)
mov     maxsize, ecx       ; max. size of swap file in pages
mov     pager_type, bl     ; pager type; see below

Gets the virtual paging device version number, the type of paging in effect, and the maximum size of the paging file in pages. Uses Flags.

  • Returns with the carry flag set and zero in EAX if the pager is not installed. Otherwise, the carry flag is clear and these registers contain these values:
EAX | Version number of paging device. Major version in AH, minor in AL.
ECX | Maximum size of the swap file, in pages. This value is valid only after device initialization.
BL | Type of page swap device: 1 if none, 2 if the swap device uses MS-DOS, 3 if the swap device uses the Windows 95 layered device driver. This value is not valid until the PageFile_Init_File service has been called.


PageFile_Test_IO_Valid

VxDcall PageFile_Test_IO_Valid
jc      paging_not_permitted

Determines whether paging to or from disk can be performed. Uses Flags.

  • Returns with carry clear if paging is permitted. Otherwise, the carry flag is set, indicating you should avoid operations that may cause paging.


PageFile_Grow_File

mov     ecx, cPages    ; number of pages to grow by
VxDcall PageFile_Grow_File
mov     newsize, ecx   ; new size of the file, in pages
mov    maxsize, ebx   ; maximum size of the file, in pages

Increases the size of the swap file by the specified number of pages. Uses EAX, EBX, Flags.

  • Returns the new size of the swap file in the EAX register, and the maximum size in the EBX register. The maximum size may be less than when the file was created.
cPages
Number of pages to grow the swap file by.

If the file cannot grow by the requested number of pages, the new size will be less than requested and equal to the maximum size.


PageFile_Read_Or_Write

mov     ch, read_or_write  ; PF_Read_Data or PF_Write_Data
mov     edi, filepos       ; file position, in pages
mov     esi, pPage         ; linear address of memory to touch
VxDcall PageSwap_Read_Or_Write
or      eax, eax
jz      error_handler

Reads a page from disk or writes a page to disk. Uses Flags.

  • Returns a nonzero value in EAX if successful, zero otherwise.
read_or_write
Value indicating whether to read from or write to the swap file. Can be PF_Read_Data or PF_Write_Data.
filepos
Offset in the swap file to read from or write to, in pages.
pPage
Linear address of the memory page to read from or write to.


PageFile_Cancel

VxDcall PageFile_Cancel

Cancels a previously issued read or write operation. This service should only be called if the swap device uses the Windows 95 layered device driver. Uses Flags.


PageFile_Set_Async_Manager

mov     eax, FSD_Entry             ; entry in FSD
VxDcall PageFile_Set_Async_Manager
jc      error_handler

An FSD offering asynchronous page-outs stores an internal entry that a VxD can call to register a callback function that the system calls when the FSD is idle. This service can only be called during initialization. Uses Flags.

The first caller of this service registers the callback function, pointing to the Async Manager for Pagefile. Subsequent calls to this routine will fail, returning with carry flag set.

VFAT typically calls this service, registering VFAT_Register_MMCallBack. Each subsequent call to the PageFile_Call_Async_Manager service is actually a call to the FSD_Entry callback function indicated in the sample code above.

See also the following KB article: Q223294 - INFO: The Windows 98 PageFile_Call_Async_Manager Service.

  • Clears the carry flag is successful, and sets it otherwise.
FSD_Entry
Entry in FSD.


PageFile_Call_Async_Manager

mov     eax, OFFSET32 Callback       ; address of callback function
VxDcall PageFile_Call_Async_Manager
jc      errorhandler
mov     eax, pageout_entry

Uses flags. Memory Manager calls this service and supplies the service (which is in reality inside VFAT; see PageFile_Set_Async_Manager) with a pointer to a Filesystem Idle routine mmFsIdle (in the Memory Manager). VFAT later calls this function when VFAT is completely idle (all pending VFAT writes have been written), so Memory Manager can execute asynchronous writes:

ULONG INTERNAL mmFsIdle(void);

• Returns a pointer to a function that Memory Manager uses to perform the (async) writes to the pagefile:

extern int (CDECL *pfnAsyncPageOut)(PVOID pvBuffer, ULONG ibFileOffset);

  • Clears the carry flag if successful; sets the carry flag if asynchronous paging is not supported.
Callback

Address of callback function. Registers a callback function that the system calls when the FSD is idle, and retrieves the FSD entry for asynchronous page-outs. This service can only be called during initialization. Uses Flags.

  • Returns the FSD asynchronous pageout entry in EAX and clears the carry flag if successful; otherwise, sets the carry flag.
Callback


Virtual Programmable Interrupt Controller

The virtual programmable interrupt controller (VPICD) virtualizes the programmable interrupt controller (PIC), allowing other virtual devices to support hardware devices, such as disk drives and communications ports, that use hardware interrupts to signal input or status changes. The VPICD routes hardware interrupts to other virtual devices, provides services that allow virtual devices to request interrupts, and simulates hardware interrupts into virtual machines.


Default Interrupt Handling

The VPICD emulates the functions of the programmable interrupt controller (PIC). This entails reflecting interrupts into virtual machines and simulating I/O, such as recognizing when a virtual machine issues an end of interrupt (EOI). When VPICD initializes, it sets up a default interrupt handler for every interrupt request (IRQ). These handlers determine which virtual machine an interrupt should be reflected into, and they arbitrate conflicts between virtual machines that attempt to unmask the same interrupt.

An interrupt that is unmasked when Windows is started is considered a global interrupt. A global interrupt will always be reflected into the currently executing virtual machine, and any virtual machine can mask or unmask the IRQ. If a virtual machine unmasks an IRQ that was masked when Windows was started, it owns that IRQ. All interrupts for owned IRQs are reflected to the owner. If another virtual machine attempts to unmask the interrupt, the second virtual machine is terminated, and Windows may direct the user to restart the computer.

If another virtual device virtualizes an IRQ, it is up to that device to determine which virtual machines receive interrupts and arbitrate conflicts. Once an IRQ is virtualized, the VPICD no longer provides default handling for that IRQ.


Virtualizing an IRQ

A virtual device hooks a specific IRQ by calling the VPICD_Virtualize_IRQ service and passing it a pointer to a VPICD_IRQ_Descriptor structure containing the number of the IRQ and the addresses of the callback procedures to support the interrupt. If another virtual device has already virtualized the IRQ, the call fails if either of the virtual devices is unable to share the IRQ. Both virtual devices must set the VPICD_Opt_Can_Share value in the VID_Options field of the structure to permit sharing.


Virtualized IRQ Callback Procedures

A virtual device may specify the following callback procedures when it virtualizes an interrupt:

VID_EOI_Proc

VID_Hw_Int_Proc

VID_IRET_Proc

VID_Mask_Change_Proc

VID_Virt_Int_Proc

The VID_Hw_Int_Proc procedure is required. The other callback procedures are optional and are used to inform a virtual device whenever the state of the virtualized IRQ changes. For example, the VID_Virt_Int_Proc procedure is called whenever an interrupt is simulated into a virtual machine and the VID_Mask_Change_Proc procedure is called whenever a virtual machine masks or unmasks the interrupt.

Callback procedures may modify EAX, EBX, ECX, EDX, ESI, and Flags registers. Although they are called with interrupts disabled, they can enable them. If the procedures perform a lot of processing, interrupts should be enabled.


Using the VID_IRET_Proc Callback

The VID_IRET_Proc procedure can be used to help prevent stack overflows when an interrupt routine in a virtual machine attempts to process too many simulated interrupts. Consider the following interrupt routine, a routine that is very common in actual terminal applications:

push    ax              ; push AX, DX is the
push    dx              ; minimum possible
    .
    .                   ; read a byte from the COM port
    .
mov     al, 20h         ; non-specific EOI
out     20h, al         ; EOI the PIC
sti                     ; enable interrupts
    .
    .                   ; do other stuff
    .
pop     dx
pop     ax
iret

In this routine, if an interrupt occurs after the sti but before the iret instruction, control re-enters the interrupt routine and the amount of data on the stack grows by 10 bytes (6 bytes for the return address and 4 bytes for the saved AX and DX registers). Since the virtual communications device (VCD) may queue hundreds of bytes of data before the virtual machine begins processing simulated interrupts, this interrupt routine can potentially be re-entered hundreds of times (requiring several kilobytes of stack space) unless the VCD delays its request for the next simulated interrupt until after the iret instruction is executed. Installing the VID_IRET_Proc procedure lets the VCD delay the request, preventing the interrupt routine from being re-entered.

The virtual timer device uses similar logic to prevent sending too many timer interrupts to a virtual machine.


Bimodal Interrupt Handlers

The virtual programmable interrupt controller device provides the following API functions to install and remove bimodal interrupt handlers:

VPICD_API_Get_Ver

VPICD_Install_Handler

VPICD_Remove_Handler


Reference

The VPICD provides the following services.

VPICD_Auto_Mask_At_Inst_Swap

VPICD_Begin_Inst_Page_Swap

VPICD_Call_When_Hw_Int

VPICD_Clear_Int_Request

VPICD_Convert_Handle_To_IRQ

VPICD_Convert_Int_To_IRQ

VPICD_Convert_IRQ_To_Int

VPICD_End_Inst_Page_Swap

VPICD_Force_Default_Behavior

VPICD_Force_Default_Owner

VPICD_Get_Complete_Status

VPICD_Get_IRQ_Complete_Status

VPICD_Get_Status

VPICD_Get_Version

VPICD_Get_Virtualization_Count

VPICD_Phys_EOI

VPICD_Physically_Mask

VPICD_Physically_Unmask

VPICD_Set_Auto_Masking

VPICD_Set_Int_Request

VPICD_Test_Phys_Request

VPICD_Virtual_EOI

VPICD_Virtualize_IRQ


Programmable Interrupt Controller Services

The following topics describe the programmable interrupt controller services.


VPICD_Auto_Mask_At_Inst_Swap

include vpicd.inc

mov     eax, IRQHandle
VxDcall VPICD_Begin_Inst_Page_Swap
jc      errorhandler

Sets the state of an IRQ so that it is automatically masked when the virtual memory manager swaps data in an instance page. This allows a VxD to touch instance memory at interrupt time. This service can not be called at interrupt time. Uses Flags.

  • Clears carry flag if successful.
IRQHandle
Handle of the IRQ.


VPICD_Begin_Inst_Page_Swap

VxDcall VPICD_Begin_Inst_Page_Swap

Informs VPICD to begin masking interrupts that must be held off until instance data copies are complete. This service should be called only by the virtual machine manger's instance page-swap code. Uses Flags.

  • No return value.


VPICD_Call_When_Hw_Int

include vpicd.inc

pushfd
cli
mov     esi, OFFSET32 Callback
VxDcall VPICD_Call_When_Hw_Int
popfd
mov     [Next_Callback], esi

Installs a callback procedure for hardware interrupts. The system calls the callback procedure whenever a hardware interrupt occurs. The caller must disable interrupts before calling this service. Uses ESI and Flags.

  • Returns, in ESI, the address of the next procedure in the callback chain.
Callback
Address of the callback procedure. When the system calls the procedure, EBX contains the handle of the current virtual machine.

Although any virtual device can use this service, the service is intended for use by the virtual DMA device to detect completion of DMA transfers. On systems with hardware devices that interrupt frequently, use of this service should be avoided. Installing a callback procedure to process every hardware interrupt can have a major impact on performance.

The callback procedure is responsible for chaining to the next handler in the interrupt chain. It also must preserve the EBX register for the next handler.


VPICD_Clear_Int_Request

include vpicd.inc

mov     eax, IRQHandle
mov     ebx, VMHandle
VxDcall VPICD_Clear_Int_Request

Resets an IRQ request that was previously set by a call to the VPICD_Set_Int_Request service. Uses Flags.

  • No return value.
IRQHandle
Handle of the IRQ to clear.
VMHandle
Handle of the VM.

If the IRQ is being shared and another device has also set the virtual IRQ, this service does not reset the virtual request immediately. Instead, the request is reset only after the other device calls VPICD_Clear_Int_Request.


VPICD_Convert_Handle_To_IRQ

include vpicd.inc

mov     eax, IRQHandle
VxDcall VPICD_Convert_Handle_To_IRQ
mov     [IRQNum], esi

Retrieves the number of the IRQ corresponding to the specified IRQ handle. Uses ESI and Flags.

  • Returns the IRQ number in ESI.
IRQHandle
Handle of a virtualized IRQ.


VPICD_Convert_Int_To_IRQ

include vpicd.inc

mov     ebx, VMHandle
mov     eax, VecNum
VxDcall VPICD_Convert_Int_To_IRQ
jc      not_mapped
mov     [IRQNum], eax

Retrieves the IRQ number (if any) corresponding to the specified interrupt vector number. Uses EAX and Flags.

  • Returns the IRQ number in EAX and clears the carry flag if the interrupt vector number is mapped to an IRQ; otherwise sets carry flag.
VMHandle
Handle of VM for which to do the conversion.
VecNum
Interrupt vector number.

Since virtual machines can map IRQ numbers of the virtual PIC to any interrupt vector numbers, virtual devices should always explicitly check which interrupt vector is mapped to a particular IRQ.


VPICD_Convert_IRQ_To_In

include vpicd.inc

mov     eax, IRQNum
mov     ebx, VMHandle
VxDcall VPICD_Convert_IRQ_To_Int
jc      not_valid
mov     [VecNum], eax

Retrieves the interrupt vector number that corresponds to the specified IRQ number for the given virtual machine. Uses EAX and Flags.

  • Returns an interrupt vector number in EAX and clears the carry flag if the IRQ number is valid; otherwise sets the carry flag.
IRQNum
IRQ number.
VMHandle
Handle of the virtual machine.

Since virtual machines can map IRQ numbers of the virtual PIC to any interrupt vector numbers, virtual devices should always explicitly check which interrupt vector is mapped to a particular IRQ.


VPICD_End_Inst_Page_Swap

VxDcall VPICD_Begin_Inst_Page_Swap

Informs VPICD to stop masking interrupts that must be held off until instance data copies are complete. This service should be called only by the virtual machine manger's instance page-swap code. Uses Flags.

  • No return value.


VPICD_Force_Default_Behavior

include vpicd.inc

mov     eax, IRQHandle
VxDcall VPICD_Force_Default_Behavior

Unvirtualizes an IRQ. This allows a virtual device to remove virtualization of an IRQ when it processes a System_Exit message. Uses Flags.

  • No return value.
IRQHandle
Handle of the IRQ to unvirtualize.

This service invalidates the IRQ handle. After calling this service, a virtual device must not attempt to use the IRQ handle.


VPICD_Force_Default_Owner

include vpicd.inc

mov     eax, IRQNum
mov     ebx, VMHandle
VxDcall VPICD_Force_Default_Owner

jc      errorhandler

Forces VPICD's default interrupt handler to direct a specified IRQ to a particular virtual machine, or to make the IRQ global so that any virtual machine can receive the interrupt. Uses Flags.

  • Clears the carry flag if the service sets the owner to the specified virtual machine. If the service could not set the owner, such as if the IRQ has been virtualized or the IRQ number is not valid, the carry flag is set.
IRQNum
Number of the IRQ for which ownership is set. The high word of the IRQNum may be one of the following:
VPICD_FDO_NO_CON

VPICD_FDO_NO_CON

VPICD_FDO_NO_CON

VPICD_FDO_NO_CONTENTION

Specifies that VPICD should not indicate contention on a non-virtualized IRQ to the user.
VPICD_FDO_FAVOR_FOCUS Specifies that VPICD should request interrupts into the execution focus VM instead of the current VM, if the critical section is not owned.

VMHandlle
Handle of the virtual machine to receive ownership. If this parameter is 0, the IRQ is given global ownership and any virtual machine can receive the interrupt.


VPICD_Get_Complete_Status

include vpicd.inc

mov     eax, IRQHandle
mov     ebx, VMHandle
VxDcall VPICD_Get_Complete_Status

mov     [Status], ecx

Retrieves the complete status for a virtual IRQ in a specified virtual machine. Uses ECX and Flags.

  • Returns a combination of these status flag values in ECX:
VPICD_STAT_GLOBAL |
VPICD_STAT_IN_SERVICE | The IRQ is virtually in service.
VPICD_STAT_IRET_PENDING | A virtual iret instruction is pending.
VPICD_STAT_OWNED_BY_VM |
VPICD_STAT_PHYS_IN_SERV | The IRQ is physically in service.
VPICD_STAT_PHYS_MASK | The IRQ is physically masked.
VPICD_STAT_PHYS_REQ | The physical interrupt request has been set.
VPICD_STAT_VIRT_DEV_REQ | The virtual interrupt request has been set by the calling virtual device.
VPICD_STAT_VIRT_MASK | The virtual machine has masked the IRQ.
VPICD_STAT_VIRT_R VPICD_STAT_VIRT_R VPICD_STAT_VIRT_R VPICD_STAT_VIRT_REQ | The virtual interrupt request for the virtual machine has been set (by a virtual device, not necessarily the caller).

IRQHandle
Handle of the IRQ for which to receive status.
VMHandle
Handle of the virtual machine.


VPICD_Get_IRQ_Complete_Status

include vpicd.inc

mov     eax, IRQNum
VxDcall VPICD_Get_IRQ_Complete_Status
jc      already_virtualized
mov     [Status], ecx

Retrieves the complete status for the specified IRQ. This service is similar to VPICD_Get_Complete_Status, except that it takes an IRQ number as a parameter instead of an IRQ handle. Uses ECX and Flags.

  • Sets the carry flag if the IRQ has been virtualized; otherwise clears the carry flag. ECX contains a combination of these status flag values:
VPICD_Stat_In_Service | The IRQ is virtually in service.
VPICD_Stat_IRET_Pending | A virtual iret is pending.
VPICD_Stat_Phys_In_Serv | The IRQ is physically in service.
VPICD_Stat_Phys_Mask | The IRQ is physically masked.
VPICD_Stat_Phys_Req | The physical interrupt request has been set.
VPICD_Stat_Virt_Mask | The virtual machine has masked the IRQ.
VPICD_Stat_Virt_R VPICD_Stat_Virt_R VPICD_Stat_Virt_R VPICD_Stat_Virt_Req | The virtual interrupt request for the virtual machine has been set (by a virtual device, not necessarily the caller).

IRQNum
Number of the IRQ for which to retrieve status.

Virtual devices typically use this service to inspect an IRQ before attempting to virtualize it, or to inspect the state of another virtual device's interrupt. Since the service indicates whether an IRQ has been virtualized, virtual devices use this service to avoid conflicts when more than one device may want to use an IRQ.


VPICD_Get_Status

include vpicd.inc

mov     eax, IRQHandle
mov     ebx, VMHandle
VxDcall VPICD_Get_Status
mov     [Status], ecx

Retreves the status for a virtual IRQ in a specified virtual machine. Although this service does not return the complete status, it returns the most commonly used information and is much faster than the VPICD_Get_Complete_Status service. Uses ECX and Flags.

  • Returns a combination of the following status flag values in ECX:
VPICD_Stat_In_Service | The IRQ is virtually in service.
VPICD_Stat_IRET_Pending | A virtual iret instruction is pending.
VPICD_STAT_GLOBAL | VPICD is treating the IRQ as a global IRQ. Interrupts get requested into the current VM at the time of the real hardware interrupt. This applies only to IRQs which have not been virtualized.
VPICD_STAT_OWNED_BY_VM | The IRQ is owned by the current VM. This applies only to IRQs which have not been virtualized.

IRQHandle
Handle of the IRQ for which to receive status.
VMHandle
Handle of the virtual machine.


VPICD_Get_Version

include vpicd.inc

VxDcall VPICD_Get_Version

mov     byte ptr [Major], ah
mov     byte ptr [Minor], al
mov     [Flags], ebx
mov     [MaxIRQ], ecx

Retrieves the VPICD major and minor version numbers. Uses EAX, EBX, ECX, and Flags.

  • Clears the carry flag and returns these values:
AH | Specifies the major version number for the virtual PIC device.
AL | Specifies the minor version number for the virtual PIC device.
EBX | Specifies the configuration flag for the PIC. The flag can be the following value:

1 System has a master/slave (PC/AT-type) configuration. If this value is not given, the system has a single PIC (PC/XT-type) configuration.

All other values are reserved.

ECX
Specifies the maximum IRQ supported. It is either 07h or 0Fh.


VPICD_Get_Virtualization_Count

include vpicd.inc

mov eax, IRQ_Number
VxDcall VPICD_Get_Virtualization_Count
mov [VirtCount], eax

Gets the number of times an IRQ has been virtualized. Uses EAX.

  • Returns the virtualization count in the EAX register.
IRQ_Number The IRQ number.


VPICD_Phys_EOI

include vpicd.inc

mov     eax, IRQHandle
VxDcall VPICD_Phys_EOI
  • Ends a physical interrupt and allows further hardware interrupts from the specified IRQ. Uses No return value.
IRQHandle
Handle of the IRQ.

An interrupt that is physically in service will not suppress interrupts to lower priority IRQs since VPICD does not prioritize hardware interrupts. Therefore, it is acceptable for an interrupt to be physically in service for any arbitrary length of time.


VPICD_Physically_Mask

include vpicd.inc

mov     eax, IRQHandle
VxDcall VPICD_Physically_Mask

Masks the specified IRQ on the hardware PIC. This suppresses all hardware interrupts on the IRQ until the VPICD_Physically_Unmask or VPICD_Set_Auto_Masking service is called. Uses Flags.

  • No return value.
IRQHandle
Handle of the IRQ.


VPICD_Physically_Unmask

include vpicd.inc

mov     eax, IRQHandle
VxDcall VPICD_Physically_Unmask

Unmasks the specified IRQ on the hardware PIC. Uses Flags.

  • No return value.
IRQHandle
Handle of the IRQ.

This service unmasks the physical IRQ without regard to mask state of the virtual machines. Even if every VM has masked the virtual IRQ, this service unmasks the physical IRQ.


VPICD_Set_Auto_Masking

include vpicd.inc

mov     eax, IRQHandle
VxDcall VPICD_Set_Auto_Masking

Enables automatic masking for the specified IRQ. When automatic masking is enabled, the system automatically masks the physical IRQ if all virtual machines have masked the corresponding virtual IRQs. However, if at least one virtual machine has the IRQ unmasked, the physical IRQ remains unmasked. Uses Flags.

  • No return value.
IRQHandle
Handle of the IRQ.

Automatic masking is the default for every IRQ. It can be overridden by the VPICD_Physically_Mask and VPICD_Physically_Unmask services.


VPICD_Set_Int_Request

include vpicd.inc

mov     eax, IRQHandle
mov     ebx, VMHandle
VxDcall VPICD_Set_Int_Request

Sets a virtual interrupt request for the specified IRQ and virtual machine. Setting the request causes the system to simulate an interrupt. Although the simulation may occur immediately, in many cases it may not until a later point in time. Uses Flags.

  • No return value.
IRQHandle
Handle of the IRQ to set.
VMHandle
Handle of the virtual machine.

The interrupt is not simulated immediately if any of the following conditions are present:

  • The virtual machine has interrupts disabled
  • The virtual machine has masked the IRQ
  • A higher priority virtual IRQ is in service
  • The virtual machine is suspended, or not able to run

However, since the interrupt may be simulated immediately, a virtual device that has a virtual interrupt handler must be able to handle a call to the handler before this service returns.

Setting an interrupt request does not guarantee that the interrupt will be simulated. For example, if the VM has masked the interrupt and never unmasks it, the interrupt is never simulated. Also, a call to the VPICD_Clear_Int_Request service made before the virtual interrupt is simulated prevents the interrupt simulation.

The virtual VPIC device simulates a level-triggered PIC. This means that once a virtual EOI occurs, another interrupt will be simulated immediately unless the virtual interrupt request is cleared.


VPICD_Test_Phys_Request

include vpicd.inc

mov     eax, IRQHandle
VxDcall VPICD_Test_Phys_Request
jc      irq_set

Determines whether the physical (hardware PIC) interrupt request is set for the specified IRQ. Uses Flags.

  • Clears the carry flag if the physical interrupt request is set.
IRQHandle
Handle of the IRQ.


VPICD_Virtual_EOI

include vpicd.inc

mov     eax, IRQHandle
mov     ebx, VMHandle
VxDcall VPICD_Virtual_EOI

Allows another VxD to send VPICD a virtual EOI for the specified IRQ. The EOI handlers are called like a normal EOI.

  • No return value.
IRQHandle
Handle of the IRQ to set.
VMHandle
Handle of the virtual machine.


VPICD_Virtualize_IRQ

include vpicd.inc

mov     edi, OFFSET32 vid
VxDcall VPICD_Virtualize_IRQ
jc      errorhandler
mov     [IRQHand], eax

Assigns a virtual interrupt request to the calling virtual device. This is not an asynchronous service. Uses EAX, Flags

  • If the carry flag is clear, the EAX register contains the handle for the virtual IRQ. This handle is used for all subsequent communication with the virtual PIC device.

    The carry flag is set to indicate an error such as the IRQ has already been virtualized, or the IRQ number is not valid.

vid
Address of a VPICD_IRQ_Descriptor structure containing information about the virtual IRQ. The VID_IRQ_Number and VID_Hw_Int_Proc fields in the VPICD_IRQ_Descriptor structure must be set before calling this service.

The IRQ can be shared by up to 32 virtual devices if every virtual device specifies the VPICD_Opt_Can_Share value in the VID_Options field of the VPICD_IRQ_Descriptor structure.


VPICD_VM_SlavePIC_Mask_Change

include vpicd.inc

mov     ebx, VMHandle
mov     ecx, bMask
VxDcall VPICD_VM_SlavePIC_Mask_Change

VxDs may hook this service to be notified if a VM has masked or unmasked IRQ 2 which effectively masks/unmasks IRQ 8 through IRQ 15. Uses all registers.

  • This service has no return value.
VMHandle
VM handle.
bMask
This flag is zero if the IRQ is being unmasked; otherwise it is non-zero.


Programmable Interrupt Controller APIs

The following is an alphabetic listing of the virtual programmable interrupt controller APIs.


VPICD_API_Get_Version

include bimodint.inc

mov     ax, VPICD_API_Get_Version
call    [lpfnVPICD]
jc      errorhandler
mov     [Major], ah
mov     [Minor], al

Retrieves the major and minor version numbers for the virtual PIC device.

  • Returns, in AX, the major and minor version numbers and clears the carry flag, if successful.
lpfnVPICD
Entry-point address of the API handler for the virtual PIC device.


VPICD_Install_Handler

include bimodint.inc

les     di, bis
mov     ax, VPICD_Install_Handler
call    [lpfnVPICD]
jc      errorhandler

Installs a bimodal interrupt handler for the IRQ specified by the BIS_IRQ_Number field in the Bimodal_Int_Struc structure.

  • Clears the carry flag if successful. Otherwise, sets the carry flag to indicate an error such as the IRQ has already been virtualized or the IRQ number is not valid.
bis
Address of a Bimodal_Int_Struc structure containing information about the interrupt handler to install.
lpfnVPICD
Specifies the entry point address of the API handler for the virtual PIC device.

This function virtualizes the specified IRQ and creates supervisor-mode selectors for the interrupt handler's code, data, and additional segments (if any). The function also sets the supervisor-mode API handler.


VPICD_Remove_Handler

include bimodint.inc

les     di, bis
mov     ax, VPICD_Remove_Handler
call    [lpfnVPICD]
jc      error

Removes a bimodal interrupt handler for the IRQ specified by the BIS_IRQ_Number field in the Bimodal_Int_Struc structure.

  • Clears the carry flag if successful; sets it if an error occurs. The function returns an error if the IRQ has not been virtualized, or the IRQ number is not valid.
bis
Address of a Bimodal_Int_Struc structure containing information about the interrupt handler to remove.
lpfnVPICD
Entry-point address of the API handler for the virtual PIC device.

This function unvirtualizes the specified IRQ, and frees the supervisor-mode selectors for the interrupt handler's code, data, and additional segments (if any).


Programmable Interrupt Controller Callbacks

The following is an alphabetic listing of the virtual programmable interrupt controller callback procedures.


VID_EOI_Proc

include vpicd.inc

mov     eax, IRQHandle
mov     ebx, VMHandle
call    VID_EOI_Proc

Handles the end of an interrupt. The system calls this procedure whenever a hardware interrupt handler in the virtual machine issues an EOI. The procedure typically calls the VPICD_Clear_Int_Request and VPICD_Phys_EOI services to clear the virtual interrupt and end the physical interrupt.

  • The system disables interrupts before calling this procedure. The procedure can re-enable No return value.
IRQHandle
Handle for the interrupt request.
VMHandle
Handle of the current virtual machine.

This procedure is typically used by a virtual device, such as the virtual mouse device, that lets a corresponding MS-DOS driver process hardware interrupts. The virtual device reflects the interrupt to the virtual machine that owns the mouse. The MS-DOS driver services the interrupt, and issues an EOI. At this point, the system calls the VID_EOI_Proc procedure.


VID_Hw_Int_Proc

include vpicd.inc

mov     eax, IRQHandle
mov     ebx, VMHandle
call    VID_Hw_Int_Proc
jc      not_handled

Handles hardware interrupts for a virtual device. The system calls the procedure whenever a hardware interrupt occurs. Typically, VID_Hw_Int_Proc services the physical device, calls the VPICD_Phys_EOI service to end the physical interrupt, and sets the virtual IRQ request for a specific virtual machine.

The system disables interrupts before calling this procedure. The procedure can re-enable interrupts if necessary. Uses EAX, EBX, ECX, EDX, ESI, and Flags.

  • Clears the carry flag if it processed the interrupt. If the IRQ can be shared, the procedure can direct the system to pass the interrupt to the next handler by setting the carry flag. In this case, it must not process the interrupt.
IRQHandle
Handle of the interrupt request.
VMHandle
Handle of the current virtual machine.

The VMM services the procedure is allowed to call is limited. If processing the interrupt requires use of restricted services, this procedure should use the Schedule_Call_Global_Event service to schedule an event that performs the additional processing.

This procedure must return using the ret instruction, not an iret instruction.


VID_IRET_Proc

include vpicd.inc

clc
cmp     [TimeOut],0
jz      no_timeout
stc

no_timeout:
mov     eax, IRQHandle
mov     ebx, VMHandle
call    VID_IRET_Proc

Handles attempts by a virtual machine to return from an interrupt. The system calls this procedure whenever a virtual machine executes an iret instruction, or whenever a time out occurs for a simulated interrupt.

The system disables interrupts before calling this procedure. The procedure can re-enable interrupts if necessary. Uses EAX, EBX, ECX, EDX, ESI, and Flags.

  • No return value.
IRQHand
Handle of the interrupt request.
VM
Handle of the current virtual machine.

This procedure is useful for devices that must simulate large numbers of interrupts in a short period of time. For example, the virtual COM device simulates an interrupt, allows one character to be read from the COM port, and waits for the virtual machine to execute an iret instruction before putting more data into the virtual COM receive buffer.


VID_Mask_Change_Proc

include vpicd.inc

mov     eax, IRQHandle
mov     ebx, VMHandle
mov     ecx, Mask
call    VID_Mask_Change_Proc

Processes attempts to mask or unmask the specified IRQ. The system calls this procedure whenever a virtual machine attempts to mask or unmask an interrupt.

The system disables interrupts before calling this procedure. The procedure can re-enable interrupts if necessary. Uses EAX, EBX, ECX, EDX, ESI, and Flags.

  • No return value.
IRQHandle
Handle for the interrupt request.
VMHandle
Handle of the current virtual machine.
Mask
Masked flag. This parameter is nonzero if the IRQ is being masked, and is zero if it is being masked.

A virtual device typically uses this procedure to detect contention for a device. The default interrupt routines use this callback to detect conflicts with nonglobal interrupts.


VID_Virt_Int_Proc

include vpicd.inc

mov     eax, IRQHandle
mov     ebx, VMHandle
call    VID_Virt_Int_Proc

Handles virtual interrupts for a virtual device. The system calls the procedure whenever a simulated interrupt occurs. The procedure is useful for implementing critical sections around a simulated hardware interrupt.

The system disables interrupts before calling this procedure. The procedure can re-enable interrupts if necessary. Uses EAX, EBX, ECX, EDX, ESI, and Flags.

  • No return value.
IRQHandle
Handle of the interrupt request.
VMHandle
Handle of the current virtual machine.

A virtual device requests a virtual interrupt by using the VPICD_Set_Int_Request service. Once set, the system simulates the interrupt at a convenient point in time. The call to this procedure signals that the simulated interrupt is underway, and can no longer be canceled using the VPICD_Clear_Int_Request service.

A virtual device that uses this procedure usually also uses the VID_Virt_IRET_Proc procedure to detect the end of the simulated interrupt.


Bimodal_Int_Struc

include bimodint.inc

Bimodal_Int_Struc     STRUC
BIS_IRQ_Number        dw    ? ; IRQ number
BIS_VM_ID             dw    0 ; see below
BIS_Next              dd    ? ; next Bimodal_Int_Struc in chain
BIS_Reserved1         dd    ? ; see below
BIS_Reserved2         dd    ? ; see below
BIS_Reserved3         dd    ? ; reserved; do not use
BIS_Reserved4         dd    ? ; reserved; do not use
BIS_Flags             dd    0 ; bimodal interrupt flags; must be 0
BIS_Mode              dw    0 ; see below
BIS_Entry             dw    ? ; see below
BIS_Control_Proc      dw    ? ; see below
                      dw    ?
BIS_User_Mode_API     dd    ? ; see below
BIS_Super_Mode_API    dd    ? ; see below
BIS_User_Mode_CS      dw    ? ; see below
BIS_User_Mode_DS      dw    ? ; see below
BIS_Super_Mode_CS     dw    ? ; see below
BIS_Super_Mode_DS     dw    ? ; see below
BIS_Descriptor_Count  dw    ? ; see below
Bimodal_Int_Struc     ENDS

Contains information for a bimodal interrupt.

BIS_VM_ID
Handle of the virtual machine; this field is used by the virtual PIC device.
BIS_Reserved1
Reserved for IRQ handle; this field is used by the virtual PIC device.
BIS_Reserved2
Reserved for BIS address; this field is used by the virtual PIC device.
BIS_Mode
Flag for user or supervisor mode. It is 0 for user mode; 4 for supervisor mode.
BIS_Entry
Offset to the interrupt service routine for this interrupt.
BIS_Control_Proc
Offset to the control procedure for this interrupt.
BIS_User_Mode_API
Address of the user-mode API procedure for this interrupt. The procedure must check for, and carry out these functions:
BIH_API_Call_Back | Calls specified callback procedure when given virtual machine runs.
BIH_API_EOI | End interrupt.
BIH_API_Get_IRR | Retrieve the set state of the physical IRQ.
BIH_API_Get_ISR | Retrieve service state of the physical IRQ.
BIH_API_Get_Mask | Retrieve the mask state of the physical IRQ.
BIH_API_Mask | Mask the physical IRQ.
BIH_API_Unmask | Unmask the physical IRQ.

BIS_Super_Mode_API
Address of the supervisor-mode API procedure for this interrupt; this field is set by the virtual PIC device.
BIS_User_Mode_CS
Selector for the user-mode code segment for the interrupt handler.
BIS_User_Mode_DS
Selector for the user-mode data segment for the interrupt handler.
BIS_Super_Mode_CS
Selector for the supervisor-mode code segment for the interrupt handler; this field is set by the virtual PIC device.
BIS_Super_Mode_DS
Selector for the supervisor-mode data segment for the interrupt handler; this field is set by the virtual PIC device.
BIS_Descriptor_Count
Number of additional EBIS_Sel_Struc structures immediately following this structure.


EBIS_Sel_Struc

include bimodint.inc

EBIS_Sel_Struc STRUC
EBIS_User_Mode_Sel  dw  ?
                    dw  ?
EBIS_Super_Mode_Sel dw  ?
EBIS_Sel_Struc ENDS

Contains user- and supervisor-mode selectors for extra segments used by a bimodal interrupt handler.

EBIS_User_Mode_Sel
User-mode selector for an extra segment.
EBIS_Super_Mode_Sel
Supervisor-mode selector for an extra segment; this field is used by the virtual PIC device.


VPICD_IRQ_Descriptor

include vpicd.inc

VPICD_IRQ_Descriptor  STRUC
    VID_IRQ_Number       dw   ?
    VID_Options          dw   0
    VID_Hw_Int_Proc      dd   ?
    VID_Virt_Int_Proc    dd   0
    VID_EOI_Proc         dd   0
    VID_Mask_Change_Proc dd   0
    VID_IRET_Proc        dd   0
    VID_IRET_Time_Out    dd   500
    VID_Hw_Int_Ref       dd   ?
VPICD_IRQ_Descriptor  ENDS

Contains information about a virtualized IRQ.

VID_IRQ_Number
Number of the IRQ to virtualize.
VID_Options
Options for virtualizing the IRQ. It can be a combination of the following values:
VPICD_OPT_READ_HW_IRR | Reads the hardware interrupt register.
VPICD_OPT_CAN_SHARE | Virtual IRQ can be shared.
VPICD_OPT_REF_DATA | Set this bit if you want to pass reference data in the VID_Hw_Int_Ref member to your hardware interrupt handler.
VPICD_OPT_VIRT_INT_REJECT | Within your virtual interrupt procedure, set this bit and return with the carry flag set if you no longer want the interrupt virtualized.
VPICD_OPT_SHARE_PMODE_ONLY | This bit is only used in debug Windows and you must also set the bit VPICD_OPT_CAN_SHARE. If set, the system displays a debug warning message if VPICD_Set_Int_Request is called. .

VID_Hw_Int_Proc
Address of the callback procedure that handles hardware interrupts for this IRQ.
VID_Virt_Int_Proc
Address of the callback procedure that handles virtual interrupts for this IRQ.
VID_EOI_Proc
Address of the callback procedure that handles end-of-interrupt commands for this IRQ.
VID_Mask_Change_Proc
Address of the callback procedure that handles changes to the IRQ mask for this IRQ.
VID_IRET_Proc
Address of the callback procedure that handles iret instructions for this IRQ.
VID_IRET_Time_Out
Maximum amount of time in milliseconds that the virtual PIC device allows before the time out occurs.
VID_Hw_Int_Ref
Reference data that the system passes to the hardware interrupt handler. The VID_Options bit VPICD_OPT_Ref_Data must be set in order for the data to be passed to the handler.

Time outs are very important to prevent Windows from hanging while simulating a hardware interrupt.


V86-Mode Memory Manager

The V86MMGR manages memory for V86-mode applications. It supports the Expanded Memory Specification (EMS) and the Extended Memory Specification (XMS), is responsible for allocating the base memory for new virtual machines, and translates calls made from protected-mode applications to V86-mode API functions.


API Translation

API translation is required for any V86-mode API function that takes a pointer as a parameter; functions that take no parameters or receive value parameters need no translation. By default, Windows reflects interrupts into V86 mode without translation, so functions that need translation must be intercepted by a virtual device. For example, the virtual MS-DOS manager intercepts Interrupt 21h to translate for calls to MS-DOS system functions such as Read File or Device and Load and Execute Program.

Most virtual devices use the V86MMGR_Xlat_API service to translate function parameters. If a function takes a pointer, this service changes the pointer to an address in the translation copy buffer (in the V86 address space), and copies the corresponding data to that address.

Unfortunately, some API functions are too complex to be translated by the V86MMGR_Xlat_API service. For example, the service cannot translate functions that take pointers to structures that contain more pointers. In such cases, the virtual device must provide custom translations to convert all pointers and copy all corresponding data. Another example is a function that uses a buffer that is larger than the current translation copy buffer. The virtual device can customize the translation by dividing the call into several operations using a smaller buffer.

A virtual device that translates calls to API functions must install a protected-mode interrupt handler to carry out the translations. The interrupt handler must be the last handler in the protected-mode interrupt chain, therefore the virtual device must install it using the Set_PM_Int_Vector service when processing either the Sys_Critical_Init or Device_Init message. The handler must be fully initialized before the system begins sending the Init_Complete message. This allows virtual devices to use the Exec_VxD_Int service while processing the message. None of the V86MMGR translation services, except for V86MMGR_Set_Mapping_Info, should be called during the Sys_Critical_Init or Device_Init messages. Only one virtual device should translate a given API function call.

In many cases, a virtual device combines use of the V86MMGR_Xlat_API service with custom translations. The virtual device typically uses the Xlat_API_Jmp_To_Proc macro with the service to identify functions that need custom translation.

Virtual devices must adjust V86 segment registers when translating functions. To do so, a virtual device can modify the alternate client registers (such as Client_Alt_DS) when the virtual machine status is executing in protected-mode (the CB_VM_Status field in the control block specifies VMStat_Pm_Exec). When in protected-mode, these registers contain the V86 segment registers and stack pointer. They will contain the protected-mode segment registers and stack pointer when the virtual machine is in V86-mode execution.


Setting the Copy Buffer and Map Page Sizes

The V86MMGR_Set_Mapping_Info service defines the minimum amount of translation buffer and global V86 map address space required by a virtual device. By default, the translation copy buffer size is 4 kilobytes and there are no global mapping pages. If these defaults are not adequate, a virtual device can set new values by using this service. For example, the VNETBIOS device uses this service to ensure that there will be adequate global page mapping space to map network buffers.

If multiple virtual devices call this service, the V86MMGR uses the largest value specified when allocating buffer space. In other words, if 10 virtual devices request a two-page copy buffer, this service set the copy buffer size to two pages (not 20). While a large copy buffer can speed up I/O operations, it requires extra memory to be allocated for each virtual machine. Virtual devices should keep the copy buffer size as small as possible.

This service must be called during the Sys_Critical_Init or Device_Init phase of device initialization.


API Mapping

The V86MMGR_Xlat_API service copies the data, it does not map it. Some virtual devices, however, need to map pages from extended address space into the 1 megabyte V86 address space. For example, the virtual NetBIOS device uses mapping to ensure that the proper physical memory is updated (regardless of which virtual machine is running) when an asynchronous network function completes execution. When memory is mapped using V86MMGR_Map_Pages, the service maps it to the same linear address in every virtual machine.

Mapping must not be used as an alternative to copying. It is faster to copy memory than to map it, because the memory manager does not need to perform any page table mapping and locking. Mapping also uses an address space in all virtual machines. Therefore, the mapping services should only be used for API functions that require memory mapped to the same address in every virtual machine. For the same reason, mapping must not be used to implement interprocess communication. If an IPC interface is needed, it should be implemented for protected-mode applications (which can share memory) or by copying the data.


Initialization Services

V86MMGR provides initialization services that other virtual devices use to set the base memory and EMS and XMS memory limits when a virtual machine is first created. There are the following initialization services:


V86MMGR_Allocate_V86_Pages

include v86mmgr.inc
mov     ebx, VMHandle
mov     esi, DesiredSize
mov     edi, MinimumSize
mov     ecx, Flags
VxDcall V86MMGR_Allocate_V86_Pages
jc      error_handler
mov     [NumPages], eax

Allocates and maps the base V86 memory for a virtual machine. Uses EAX, Flags.

  • Returns with the carry flag clear if successful, or set otherwise. If the service succeeds, the actual number of pages allocated and mapped to the VM is returned in the EAX register. This value does not include the space from zero to the first VM page.
VMHandle
Handle of the VM.
DesiredSize and MinimumSize
Desired size and minimum size of the VM address space, in kilobytes. These sizes include the address range from zero through the first VM page.
Flags
Memory attributes for the VM. Can be zero or this flag:
AV86PLocked (bit number AV86PLockedBit) Specifies that the VM memory is to be always locked, regardless of the pager type or whether the VM is suspended.

If an error occurs, this service calls the GetSetDetailedVMError service to set an error value.


V86MMGR_Get_EMS_XMS_Avail

Do not use this service. Attempting to do so may result in unexpected behavior.

<!--include v86mmgr.inc

mov     ebx, VMHandle
VxDcall V86MMGR_Get_EMS_XMS_Avail
mov     [LargestFreeBlockXMS], eax
mov     [AvailableEMS], ecx
mov     [TotalEMS], edx
mov     [TotalXMS], edi

Gets the current EMS and XMS usage information for a VM. Uses all registers except EBX, EBP, and the segment registers.

  • Returns with the carry flag clear and these values in these registers:
EAX | Largest free XMS memory block, in kilobytes.
ECX | Amount of available EMS memory, in units of 16 K.
EDX | Total EMS memory size for the VM, in units of 16 K. This value does not take into account the minimum EMS limit for the VM.
EDI | Total XMS memory size for the VM, in kilobytes. This value does not take into account the minimum XMS limit for the VM.

To determine the minimum EMS and XMS limits, use the V86MMGR_Get_EMS_XMS_Limits service.

VMHandle
Handle of the VM to get the information for.

This service is always available for versions of V86MMGR greater than 3.1. For version 3.1, the service may or may not be available. To find out, you can attempt to hook the service using the Hook_Device_Service service. If the hook fails, the service is not available. Otherwise, the service is available, and you should unhook it by calling Hook_Device_Service again. The service is not available for versions prior to 3.1.-->


V86MMGR_Get_EMS_XMS_Limits

include v86mmgr.inc

mov     ebx, VMHandle
VxDcall V86MMGR_Get_EMS_XMS_Limits
mov     [MinEMS], eax       ; min EMS kilobytes (multiple of 4)
mov     [MaxEMS], edx       ; max EMS kilobytes (multiple of 4)
mov     [MinXMS], esi       ; min XMS kilobytes (multiple of 4)
mov     [MaxXMS], edi       ; max XMS kilobytes (multiple of 4)
mov     [fHMAEnabled], ecx  ; 1 if HMA is enabled, 0 otherwise

Gets the current EMS and XMS limits. Uses all registers except EBX, EBP, and segment registers.

  • Returns with these values in these registers:
EAX | Minimum EMS kilobytes (multiple of 4)
ECX | Access to HMA is disabled (if zero) or enabled (if 1)
EDI | Maximum XMS kilobytes (multiple of 4)
EDX | Maximum EMS kilobytes (multiple of 4)
ESI | Minimum XMS kilobytes (multiple of 4)

VMHandle
Handle of the virtual machine to get the EMS and XMS limits of.


V86MMGR_Get_Version

include v86mmgr.inc

VxDcall V86MMGR_Get_Version
mov     [MajorVersion], ah
mov     [MinorVersion], al

Gets the V86MMGR version number. Uses EAX, Flags.

  • Returns with the major version number in AH, the minor version number in AL, and the carry flag clear.


V86MMGR_Set_EMS_XMS_Limits

include v86mmgr.inc

mov     ebx, VMHandle
mov     eax, MinEMS
mov     edx, MaxEMS
mov     esi, MinXMS
mov     edi, MaxXMS
mov     ecx, Flags
VxDcall V86MMGR_Set_EMS_XMS_Limits
jc      error_handler

Sets the EMS and XMS memory limits for a VM. A VxD should only call this service when processing the Create_VM control message. Uses Flags.

This service must be made during the Create_VM message for it to work properly. This service should not be called on the system virtual machine. Uses Flags.

Returns with the carry flag clear if successful, or set otherwise.

VMHandle
Handle of the VM to set limits for. Cannot be the system VM.
MinEMS and MaxEMS
Minimum and maximum EMS limits for the VM, in kilobytes. Specify zero for both values to disable EMS memory; specify -1 to leave the current EMS limits unchanged.
MinXMS and MaxXMS
Minimum and maximum XMS limits for the VM, in kilobytes. The XMS limits do not include the high memory area (HMA). Specify zero for both values to disable XMS memory; specify -1 to leave the current XMS limits unchanged.
Flags
Flags. Can be zero or more of these values.
EMS_XMS_Limit_DisableHMA (bit number EMS_XMS_Limit_DisableHMABit) | Disables access to the HMA.
EMS_XMS_Limit_EnableHMA (bit number EMS_XMS_Limit_EnableHMABit) | Enables access to the HMA.
EMS_XMS_Limit_XMS_Is_Locked (bit number EMS_XMS_Limit_XMS_Is_LockedBit) | Lock XMS memory
EMS_XMS_Limit_EMS_Is_Locked (bit number EMS_XMS_Limit_EMS_Is_LockedBit) | Lock EMS memory.

If neither EMS_XMS_Limit_DisableHMA nor EMS_XMS_Limit_EnableHMA is specified, the HMA state (enabled or disabled) is not changed.

The service fails if there is insufficient memory for the minimum allocation request. In this case, the service uses the GetSetDetailedVMError service to set error values. Some of the limits may have been set; use the V86MMGR_Get_EMS_XMS_Limits service to determine the new settings.


API Translation and Mapping Services

V86MMGR provides services that other virtual devices use to translate V86-mode API function calls when made by protected-mode applications. API translation consists of converting addresses provided by a protected-mode application into V86-mode addresses. The services copy data to the translation copy buffer, allocate buffer space, map memory into global V86 address space, and perform other functions necessary for API translation. The services work only for the current virtual machine.

V86MMGR provides the following API translation and mapping services:

Applications can also translate API functions without installing a virtual device by using DPMI functions.


V86MMGR_Allocate_Buffer

include v86mmgr.inc

mov     ebp, OFFSET32 ClientRegisters
mov     ebx, VMHandle
mov     ecx, NumBytes
stc                      ; set carry flag to copy, clear otherwise
lfs     esi, FarPtrMem   ; extended memory to copy if carry set
VxDcall V86MMGR_Allocate_Buffer
jc      error_handler
mov     [BytesCopied], ecx
mov     [FarPtrBuffer], edi

Allocates a portion of the current virtual machine's translation buffer, and optionally copies data into the buffer. Uses ECX, EDI, Flags.

  • Returns with the carry flag clear if successful, or set otherwise. If successful, these registers contain these values:
ECX | Actual number of bytes allocated in the translation buffer. Because this may be less than than the NumBytes parameter, you should preserve this value to pass to the V86MMGR_Free_Buffer service. For more information, see below.
EDI | Virtual 8086-mode address of the allocated portion of the translation buffer. The segment address is in the high-order word, the offset address in the low-order word.

ClientRegisters
Address of a Client_Reg_Struc structure containing the register values of the current VM.
VMHandle
Handle of the current VM. The VM must be in protected mode.
NumBytes
Number of bytes to copy if the carry flag is set, or the size of the buffer to allocate otherwise.
FarPtrMem
Selector and offset address (in FS and ESI) of the extended memory to copy, if the carry flag is set. This parameter is ignored if the carry flag is clear.

If the carry flag is set on entry, the service may return successfully (with the carry flag clear) yet allocate fewer bytes than are specified by NumBytes parameter. This is because the service ensures that number of bytes to copy plus the offset in ESI does not extend beyond the segment limit for the selector in FS.

The buffers are maintained as a stack. Therefore, the last buffer allocated must be the first buffer freed. To free a buffer allocated by this service, use the V86MMGR_Free_Buffer service.


V86MMGR_Free_Buffer

include v86mmgr.inc

mov     ebp, OFFSET32 ClientRegisters
mov     ebx, VMHandle
mov     ecx, NumBytes
stc                     ; set carry flag to copy, clear otherwise
lfs     esi, FarPtrMem  ; buffer to receive data if carry set
VxDcall V86MMGR_Free_Buffer

Frees a buffer that was allocated by the V86MMGR_Allocate_Buffer service, and optionally copies data from the translation buffer. Uses Flags.

  • No return value.
ClientRegisters
Address of a Client_Reg_Struc structure containing the register values of the current VM.
VMHandle
Handle of the current virtual machine. The current virtual machine must be in protected mode.
NumBytes
Number of bytes to free (returned from the V86MMGR_Allocate_Buffer service).
FarPtrMem
Selector and offset address (in FS and ESI) of the extended memory buffer to receive the contents of the freed translation buffer if the carry flag is set. This parameter is ignored if the carry flag is clear.

The buffers are maintained as a stack. Therefore, the last buffer allocated must be the first buffer freed.


V86MMGR_Free_Page_Map_Region

include v86mmgr.inc

mov     esi, MapHandle
VxDcall V86MMGR_Free_Page_Map_Region

Unmaps pages that were mapped by the V86MMGR_Map_Pages service. Uses ESI, Flags.

  • No return value.
MapHandle
Specifies the map handle to free.

After a call to this service, the old map buffer address contains null.


V86MMGR_Get_Mapping_Info

include v86mmgr.inc

VxDcall V86MMGR_Get_Mapping_Info
mov     [NumReservedPages], ch
mov     [NumAvailablePages], cl

Gets information about the current page mapping areas. Uses ECX, Flags.

  • Returns with the total number of pages reserved for global mapping in the CH register, and the number of pages available (not in use) for global mapping in the CL register.


V86MMGR_Get_VM_Flat_Sel

include v86mmgr.inc

mov     ebx, VMHandle
VxDcall V86MMGR_Get_VM_Flat_Sel
mov     [Selector], eax

Gets a selector that points to the base of the virtual 8086-mode address space of the specified VM. Uses EAX, Flags.

  • Returns the selector in EAX (the high-order word is zero).
VMHandle
Handle of a VM.

This is useful for 32-bit applications since this selector can be used to point to any address in the virtual machine's V86 address space. The selector is writable, and has a limit of 11000h bytes so that the high memory area is also addressable.

The selector returned is in the specified virtual machine's LDT. Therefore, the selector is only valid to use when the virtual machine is running (is the current virtual machine).


V86MMGR_Get_Xlat_Buff_State

include v86mmgr.inc

mov     ebx, VMHandle
VxDcall V86MMGR_Get_Xlat_Buff_State

Gets information about the current mapping buffer status. Uses EAX, ECX, EDX, Flags.

  • Returns with these values in these registers:
EAX | The V86 segment of the translation buffer; the high word is zero.
ECX | The number of bytes of the buffer not in use.
EDX | The total size of the buffer in bytes; the maximum size is 10000h.

VMHandle
Handle of the VM.

Always call this service to find the segment of the translation buffer. Because the buffer can move at any time, a virtual device should never make any assumptions about the size or location of the buffer.


V86MMGR_Load_Client_Ptr

include v86mmgr.inc

mov     ebx, VMHandle
mov     ebp, OFFSET32 ClientRegisters
mov     ah, IdSegmentReg
mov     al, IdOffsetReg
VxDcall V86MMGR_Load_Client_Ptr

Loads the FS:ESI register pair with the far pointer in the specified client registers. Uses ESI, Flags, FS.

  • Returns with the specified client pointer in the FS:ESI register pair.
VMHandle
Handle of the current VM. The VM must be in protected mode.
ClientRegisters
Address of a Client_Reg_Struc structure containing the register values of the current VM.
IdSegmentReg and IdOffsetReg
Values identifying the client's segment register and offset register. These values refer to Client_Reg_Struc structure fields. For example, to load the pointer in the virtual machine's DS:(E)DX register pair:
mov     ax, (Client_DS * 100h) + Client_DX
VxDcall V86MMGR_Load_Client_Ptr

If the virtual machine is running a 16-bit protected-mode application, the high word of the offset in ESI is set to zero. Otherwise, if the virtual machine is running a 32-bit program or is in VxD_Exec_Mode, the high word of ESI is not set to zero. This allows most translation procedures to operate correctly without the need to test the execution mode of the current virtual machine.


V86MMGR_Map_Pages

include v86mmgr.inc

mov     esi, LinAddr
mov     ecx, NumBytes
VxDcall V86MMGR_Map_Pages
jc      error_handler
mov     [MapHandle], esi
mov     [MapBuffer], edi

Maps the specified buffer into every virtual machine at the same address using page mapping. If the contents of memory are changed in one virtual machine, that change will be reflected in the original buffer as well in all other virtual machines. Uses EDI, ESI, Flags.

  • Returns with the carry flag clear if successful, or set otherwise. If successful, the ESI register contains the map handle (used to free the map region), and the EDI register contains the linear address of the map buffer.

    If the carry flag is clear, the memory is mapped. The ESI register contains the map handle (used to free the map region), and the EDI register contains the linear address of map buffer (always less than 1 megabyte).

LinAddr
Linear address of the buffer map. Can be zero, in which case the service reserves the map region without mapping any memory.
NumBytes
Number of bytes to map.

If the address specified in ESI is zero, no memory is mapped, but a global linear address range is allocated. It is then up to the caller to map appropriate pages into virtual machines. Use the linear address returned in EDI for the base page to map memory into.


V86MMGR_Set_Mapping_Info

include v86mmgr.inc

mov     al, MinCopyBuffer
mov     ah, MaxCopyBuffer
mov     bl, MinPrivateMapping
mov     bh, MinSharedMapping
mov     cl, MaxGlobalMapping
VxDcall V86MMGR_Set_Mapping_Info

Notifies the V86MMGR mapper services of the amount of space a virtual device requires for calls to the mapper service calls. Uses Flags.

  • No return value.
MinCopyBuffer and MaxCopyBuffer
Minimum required size and the maximum desired size, in pages, of the translation copy buffer. The default size is one page.
MinPrivateMapping
Minimum number of pages required for private global mapping region.
MinSharedMapping
Minimum number of pages required for shared global mapping region.
MaxGlobalMapping
Maximum number of pages desired for the global page mapping region. The default is zero pages.

Virtual devices with an initialization order less than V86MMGR_Init_Order must call this service while processing the Sys_Critical_Init or Device_Init control message. Other virtual devices must call this service during Sys_Critical_Init. V86MMGR uses these settings when it processes the Device_Init message.


V86MMGR_Set_Xlat_Buff_State

include v86mmgr.inc

mov     ebx, VMHandle
mov     eax, BufferSeg
mov     ecx, FreeSize
mov     edx, BufferSize
VxDcall V86MMGR_Set_Xlat_Buff_State

Switches to an alternate mapping buffer. Uses Flags.

  • No return value.
VMHandle
Handle of a VM. Any VM is valid.
BufferSeg
Virtual 80806-mode segment address of the translation buffer. The high-order word must be zero.
FreeSize
Number of bytes currently not in use in the buffer.
BufferSize
Total size of the buffer, in bytes. The maximum size is 10000h.

This feature is provided for protected-mode TSR programs which may need to switch to a private translation buffer before executing protected mode MS-DOS calls because the default buffer may be full. A virtual device should get the current translation buffer state, set the new state, perform any MS-DOS call, and then set the state back to the original values.


V86MMGR_Xlat_API

include v86mmgr.inc

mov     ebx, VMHandle
mov     ebp, OFFSET32 ClientRegisters
mov     edx, OFFSET32 Script
VxDcall V86MMGR_Xlat_API

Interprets a translation script. Uses EDX, Flags.

  • Returns with the carry flag clear if successful, or set otherwise.
VMHandle
Handle of the current VM.
ClientRegisters
Address of a Client_Reg_Struc structure containing the register values for the current VM.
Script
Address of the script to interpret. You can create translation scripts using macros defined in V86MMGR.INC.


Miscellaneous Services

The following topics describe the miscellaneous services provided.


V86MMGR_GetPgStatus

include v86mmgr.inc

mov     ebx, VMHandle
mov     ecx, PageNum
VxDcall V86MMGR_GetPgStatus

Gets the status of a page. This service is only available for Windows version 3.1 and later. Uses EAX, Flags.

  • Returns with one of these values in the EAX register:
V86PS_EMM | Page belongs to EMM driver.
V86PS_MAP | Page belongs to mapper.
V86PS_UMB | Page is part of a UMB.
V86PS_XMS | Page belongs to XMS driver.

The V86PS_XMS value is not necessarily set.

VMHandle
Handle of the virtual machine to get information for. If this parameter is zero, the service retrieves global information.
PageNum
Page number in the virtual 8086-mode address space. Must be in the rage 0 through 110h.

You can use this service to determine various aspects of what a specific page is being used for. This service can be called with any page number in the 0 through 110h range, but it is intended to return useful information only for pages above the last V86 page. One particular use of this service is to determine if a page is part of an imported high-memory UMB.

This service will not work if called during the Sys_Critical_Init message. The service is not valid until the Device_Init message. Calls during Device_Init only return useful information if paging import from a LIMulator/UMBulator is performed. In cases where no paging import exists, the information will not be correct until after the Init_Complete message.


V86MMGR_LocalGlobalReg

include v86mmgr.inc

mov     edx, FirstPageNum
mov     edi, LastPageNum
VxDcall V86MMGR_LocalGlobalReg
mov     [Result], eax

Determines whether the indicated V86 memory region is local or global memory. This VMM memory manager calls this service whenever the TestGlobalV86Mem service is called. Uses EAX, Flags.

This service is only available for Windows version 3.1 and later.

  • Returns with one of these values in the EAX register.
0 | Page range is local.
1 | Page range is global.
2 | Page range is partially global and partially local.
3 | Page range is unknown.

FirstPageNum and LastPageNum
Page numbers of the first and last page in the region.

This service is intended to support UMBs. UMB regions are local or global, depending on the free per virtual machine UMB list.


V86MMGR_NoUMBInitCalls

include v86mmgr.inc

VxDcall V86MMGR_NoUMBInitCalls

Supports QEMM version 5.x. This service is called by the VMM before the Sys_Critical_Init message is done, and allows the XMSUMBINITCALLS=FALSE setting in the SYSTEM.INI file.

This service is only available for Windows version 3.1 and later.


V86MMGR_ResetBasePages

include v86mmgr.inc

mov     ebx, VMHandle
mov     eax, FirstPageNum
mov     ecx, NumPages
VxDcall V86MMGR_ResetBasePages
jc      error_handler

Used by the virtual MS-DOS manager to manipulate MS-DOS related memory associated with the base memory handle of a virtual machine. Uses Flags.

  • Returns with the carry flag clear if successful, set otherwise.
VMHandle
Handle of the virtual machine.
FirstPageNum and NumPages
Linear or physical page number of the first page to manipulate, and the number of pages to manipulate.


V86MMGR_SetAvailMapPgs

include v86mmgr.inc

mov     eax, FirstPageNum
mov     ecx, NumPages
VxDcall V86MMGR_SetAvailMapPgs
jc      error_handler

Relinquishes regions above the last V86 page to the V86MMGR's mapper services for use as a mapper region. This service is only available for Windows version 3.1 and later. Uses Flags.

  • Returns with the carry flag clear if successful, set otherwise.
FirstPageNum and NumPages
Page number of the first page in the region, and the number of pages in the region.

Virtuals devices other than the V86MMGR can relinquish regions above the last V86 page to the V86MMGR's mapper services for use as a mapper region. These regions usually overlap with V86MMGR XMS UMB import pages, but this is not required. A virtual device can hand over a page that it has already marked as owned by the device in the Device_V86_Pages array. The V86MMGR marks the page as one it owns (even though it did not actually do the _Assign_Device_V86_Pages for it).

Once a region is relinquished, the virtual device must not attempt to access it. These regions may only be marked as in-use by the V86MMGR XMS driver. This happens when the region overlaps XMS UMB import pages.

This routine has a global effect. It does not take a virtual machine handle argument.


V86MMGR_SetLocalA20

include v86mmgr.inc
VxDcall V86MMGR_SetLocalA20

Changes the default global behavior of A20 to local if the HMA is global. This service has no effect if the HMA is not global. This service is only available for Windows version 3.1 and later. Uses Flags.

  • No return value.

When there is a global HMA user, the A20 state associated with the HMA is also global. Changing A20 in a virtual machine changes it in all virtual machines simultaneously. Some global A20 users (such as MS-DOS 5.0) desire that the A20 state be local, even though the HMA is global.

The V86MMGR device does a V86 Interrupt 2Fh device broadcast which also can set this state. This service is effectively a duplicate of the broadcast service which can be called by a virtual device. It is not an error if the state is set using both methods.

This service cannot be called after the Init_Complete system control message is processed, which occurs before the first VM is created. Essentially, this limits the use of this service to the Device_Initialization section of VxDs, and to static VxDs only (no dynamically loaded VxDs).


Translation Macros

You invoke translation macros in a virtual device's data segment to create translation scripts, which are used with the V86MMGR_Xlat_API service. For more information, see There are the following translation macros:


Xlat_API_ASCIIZ

Xlat_API_ASCIIZ  Segment, Offset

Copies a null-terminated string from the protected-mode address into the translation copy buffer, and converts the address to a V86-mode address.

  • No return value.
Segment
Register containing the selector of the protected-mode address.
Offset
Register containing the offset of the protected-mode address.

This macro does not copy the string back after the call is complete. This macro fails if there is not enough room in the translation buffer to copy the string.

For example, Rename File (Interrupt 21h Function 56h) is called with two null-terminated filenames. The following script translates this function:

Rename_API:
    Xlat_API_ASCIIZ   ds, dx
    Xlat_API_ASCIIZ   es, di
    Xlat_API_Exec_Int 21h


Xlat_API_Calc_Len

Xlat_API_Calc_Len  Segment, Offset, Calc_Proc_Addr

Copies a calculated number of bytes from the protected-mode address to the translation copy buffer, and converts the address into a V86-mode address.

  • No return value.
Segment
Register containing the selector for the protected-mode address.
Offset
Register containing the offset for the protected-mode address.
Calc_Proc_Addr
Name of the callback procedure that calculates the length, in bytes, of the data to copy. The V86MMGR_Xlat_API service calls the callback procedure with the FS:ESI register pair pointing to the buffer. The callback procedure must return the number of bytes to copy in the ECX register, and must preserve all other registers.

The V86MMGR_Xlat_API service fails if there is not enough room in the translation buffer to copy the specified number of bytes.

For example, Buffered Keyboard Input (Interrupt 21h Function 0Ah) can have a buffer size from 3 to 257 bytes; the size depends on the value of the first byte in the buffer. The following script and callback procedure translates this function:

VxD_DATA_SEG
Buff_Keyboard_Input_API:
    Xlat_API_Calc_Len ds, dx, Calc_Input_Buff_Size
    Xlat_API_Exec_Int 21h
VxD_DATA_ENDS

VxD_CODE_SEG
BeginProc Calc_Input_Buff_Size
    movzx  ecx, BYTE PTR fs:[esi]
    add    ecx, 2
    ret
EndProc Calc_Input_Buff_Size
VxD_CODE_ENDS


Xlat_API_Exec_Int

Xlat_API_Exec_Int  IntNum

Reflects the specified interrupt into V86 mode. When the interrupt returns, the V86MMGR_Xlat_API service terminates the script and returns to the virtual device that called it.

  • No return value.
IntNum
Interrupt to execute.


Xlat_API_Fixed_Len

Xlat_API_Fixed_Len  Segment, Offset, Length

Copies a fixed number of bytes from the specified protected-mode address to the translation copy buffer and converts the address into a V86-mode address.

  • No return value.
Segment
Specifies the segment register containing the selector for the protected-mode address.
Offset
Specifies the register containing the offset for the protected-mode address.
Length
Specifies the length (in bytes) of the data to copy. The V86MMGR_Xlat_API service fails if there is not enough room in the translation buffer to copy the specified number of bytes.

For example, Get Current Directory (Interrupt 21h Function 47h) is called with the DS:SI register pair pointing to a 64-byte buffer. The following script translates this function:

DOS_Get_Current_Directory_API:
    Xlat_API_Fixed_Len ds, si, 64
    Xlat_API_Exec_Int  21h


Xlat_API_Jmp_To_Proc

Xlat_API_Jmp_To_Proc  Proc_Name

Transfers control to the specified translation procedure.

Proc_Name
Name of the custom translation procedure. The V86MMGR_Xlat_API service calls the translation procedure with these values in these registers:
EBX | Handle of the current VM.
EBP | Address of the Client_Reg_Struc structure containing the client register values for the current VM.
EDX | Address of the next entry in the translation script, if any.

The translation procedure can either carry out the complete translation, or use the V86MMGR_Xlat_API to carry out portions of the translation. The procedure must increment the EDX register for each byte it reads from the script, and must preserve all other registers. It should return with the carry flag clear if successful, or set otherwise.


Xlat_API_Return_Ptr

Xlat_API_Return_Ptr  Segment, Offset

Gets the protected-mode address pointing to data retrieved by a function. This macro is used for functions that return addresses.

  • No return value.
Segment
Register to receive the selector for the returned address.
Offset
Register to receive the offset for the returned address.

For 16-bit protected-mode applications, this macro creates an LDT selector if an appropriate selector does not already exist. For 32-bit protected-mode applications, the macro always returns the same selector as the V86MMGR_VM_Flat_Selector service and adjusts the offset to point to the data. The V86MMGR_Xlat_API service fails if it can not create an appropriate LDT selector.

Although this macro is placed before the Xlat_API_Exec_Int macro in a translation script, the returned address is created after the interrupt has been executed.

The following example translates the return value of Interrupt 15h Function 0C0h. On PS/2 computers, this function returns a pointer to hardware information in the ES:BX register pair.

Get_Machine_Info:
    Xlat_API_Return_Ptr es, bx
    Xlat_API_Exec_Int   15h


Xlat_API_Return_Seg

Xlat_API_Return_Seg  Segment

Returns a protected-mode selector pointing to the segment retrieved by a function.

  • No return value.
Segment
Segment register to receive the protected-mode selector.

Although this macro is placed before the Xlat_API_Exec_Int macro in a translation script, the selector is created after the interrupt has been executed.

If an appropriate selector does not already exist, the macro automatically creates one. This service fails if it cannot create an appropriate LDT selector.

The following example translates the return value of Interrupt 15h Function 0C1h, which returns the segment address of the EBIOS data area in the ES register.

Get_EBIOS_Selector:
    Xlat_API_Return_Seg es
    Xlat_API_Exec_Int   15h


Xlat_API_Var_Len

Xlat_API_Var_Len  Segment, Offset, Length

Copies a specified number of bytes from the protected-mode address to the translation copy buffer and converts the address into a V86-mode address.

  • No return value.
Segment
Segment register containing the selector for the protected-mode address.
Offset
Register containing the offset for the protected-mode address.
Length
Register containing the length in bytes of the data to copy. The V86MMGR_Xlat_API service fails if there is not enough room in the translation buffer to copy the specified number of bytes.

For example, Write String (Interrupt 10h Function 0Eh) is called with the ES:BP register pair pointing to the string to print and the CX register specifying the number of bytes to display. The following script translates this function:

Int_10h_Write_String:
    Xlat_API_Var_Len  es, bp, cx
    Xlat_API_Exec_Int 10h


Virtual-Device (VxD) Loader

A dynamically loadable VxD can be loaded and unloaded at any time. (By contrast, static VxDs can be loaded only when the system is initialized and cannot be unloaded.) A dynamically loadable VxD can be loaded by another VxD using the services provided by the dynamic VxD loader (VXDLDR), by a 16-bit, ring-3 application using protected- and virtual-86 mode API, or by a Win32 application using the DeviceIOControl function. For more information about DeviceIOControl, see the Guide to Programming Windows 95.

Dynamically loaded VxDs are new for this release of Windows. Dynamically loadable VxDs are useful when a VxD is needed only once, because when it is no longer needed it can be unloaded. If a device monopolizes many system resources but is used rarely or intermittently, the VxDs could be loaded and unloaded again whenever required. (Networks are a good example of this.) If a VxD is required to temporarily modify the capabilities of a device, it can be loaded and used without forcing the user to restart their computer. In addition, the Plug and Play architecture is dependent on dynamically loadable VxDs. When the system starts, it determines what devices are present, then uses the VxD loader to load VxDs for those devices. The protected-mode block-device driver model (Dragon) also requires dynamically loadable VxDs.

Dynamically loadable VxDs use the same file format as static VxDs. VxDs are labeled as dynamically loadable by using the module flags. The real-mode VxD loader accepts both static and dynamically loadable VxDs; this allows a VxD binary file to be both dynamically loadable and static. The VxD loader (VXDLDR) loads only VxDs that are marked as dynamically loadable.

Applications can use the VXDLDR_LoadDevice service to load a dynamically loadable VxD and the VXDLDR_UnloadDevice service to unload one. The VXDLDR_GetVersion service retrieves the version number of VXDLDR.


Initialization

Dynamically loadable VxDs do not receive SYS_CRITICAL_INIT, DEVICE_INIT, or INIT_COMPLETE messages. Instead, their control procedure is sent a SYS_DYNAMIC_DEVICE_INIT message when the device is being initialized and a SYS_DYNAMIC_DEVICE_EXIT message when the VxD is being unloaded. (The control procedure has the option of rejecting either the load or the unload request.)

A VxD that processes all 5 of these messages can be both dynamically loadable and static.

When a dynamically loadable VxD receives the SYS_DYNAMIC_DEVICE_EXIT message it should release any resources and hooks it has acquired. No cleanup is performed by the services that unload the device. For example, if the VxD is using the Hook_V86_Int_Chain and Call_When_Idle VMM services, it should call the Unhook_V86_Int_Chain and Cancel_Call_When_Idle services when it receives SYS_DYNAMIC_DEVICE_EXIT.

If a VxD or its initialization module specifies zero for the Flags parameter of the VXDLDR_LoadDevice function it must handle its own initialization. In this case, it should use the VXDLDR_DevInitSucceeded or VXDLDR_DevInitFailed service to inform the system of the initialization's outcome. If the initialization succeeds, the initialization module should send the SYS_DYNAMIC_DEVICE_INIT message to the VxD. (If VXDLDR_INIT_DEVICE is specified for the Flags parameter, the system does this work for you.)

When creating a dynamically loadable VxD, the InitOrder parameter of the Declare_Virtual_Device macro specifies the position of the VxD in the VMM's internal list of loaded devices.


Building Dynamically Loadable VxDs

Building a dynamically loadable VxD requires a change to the build procedure. The module-definition file should specify that the VxD being linked is a dynamically loadable VxD. This is accomplished by adding the keyword DYNAMIC at the end of the LIBRARY line, following the device's name.


Limitations of Dynamically Loadable VxDs

Some limitations are imposed on dynamically loadable VxDs.

  • If a dynamically loadable VxD provides VXD services, it cannot be dynamically unloaded.
  • Dynamically loadable VxDs must release any acquired resources when they are unloaded; the system does not release the resources automatically.
  • Certain non-releasable resources (for example, V86/PM break points) should not be reallocated every time a dynamically loadable VxD is loaded. Because the static data and code segments are never unloaded, they should be used to store the resources and then reused when the VxD is loaded again.
  • The following services are provided only during initialization and are not available to dynamically loadable VxDs.
_Add_Global_V86_Data_Area | Get_Next_Arena
_AddFreePhysPage | Get_Next_Profile_String
_AddInstanceItem | Get_Profile_Boolean
_Allocate_Global_V86_Data_Area | Get_Profile_Decimal_Int
_Allocate_Temp_V86_Data_Area | Get_Profile_Fixed_Point
_Free_Temp_V86_Data_Area | Get_Profile_Hex_Int
Get_Profile_String | GetDOSVectors
_SetLastV86Page | Locate_Byte_In_ROM
Allocate_PM_App_CB_Area | MMGR_SetNULPageAddr
Convert_Boolean_String | OpenFile
Convert_Decimal_String | PageSwap_Init_File
Convert_Fixed_Point_String | Set_Physical_HMA_Alias
Convert_Hex_String | V86MMGR_NoUMBInitCalls
DOSMGR_BackFill_Allowed | V86MMGR_Set_Mapping_Info
DOSMGR_Enable_Indos_Polling | V86MMGR_SetAvailMapPgs
DOSMGR_Instance_Device | V86MMGR_SetLocalA20
Get_Name_Of_Ugly_TSR | VDMAD_Reserve_Buffer_Space


Protected-mode API Elements

Before calling any protected-mode API functions, an application must retrieve VXDLDR's protected-mode API address by using Interrupt 2Fh function 1684h (Get Device API Entry Point Address).

xor     di, di
mov     es, di                           ;es:di = 0 on entry
mov     ax, 1684h                        ;function number
mov     bx, VXDLDR_Device_ID             ;device ID
int     2Fh                              ;get protected-mode API address
mov     ax, es                           ;if es:di=0:0, VXDLDR
or      ax, di                           ;   was not loaded (by default,
jz      vxdldr_not_there                 ;   it is loaded under Windows 95)
mov     word ptr [_VXDLDRCallAddr], di   ;segment in high-order word
mov     word ptr [_VXDLDRCallAddr+2], es ;offset in low-order word

This example stores the selector:offset address used to call VXDLDR in a doubleword variable called _VXDLDRCallAddr. To call protected-mode API functions, an application calls this address after placing the command code in AX. The function names corresponding to these command codes are Get VXDLDR Version, Load Device, and Unload Device.


Reference

The VxD loader exports eight services, provides three protected-mode functions and provides eight services for the Portable Exectuable (PE) Loader.

Group | Elements
Services and Structures | VXDLDR_DevInitFailed, VXDLDR_DevInitSucceeded, VXDLDR_GetDeviceList, VXDLDR_GetVersion, VXDLDR_LoadDevice, VXDLDR_Notify, VXDLDR_UnloadDevice, VXDLDR_UnloadMe, DeviceInfo, ObjectInfo
Protected- and Virtual-Mode Functions | Get VXDLDR Version, Load Device, Unload Device
Control Messages | SYS_DYNAMIC_DEVICE_EXIT, SYS_DYNAMIC_DEVICE_INIT
PE Loader Services | _PELDR_LoadModule, _PELDR_GetModuleHandle, _PELDR_GetModuleUsage, _PELDR_GetEntryPoint, _PELDR_GetProcAddress, _PELDR_AddExportTable, _PELDR_RemoveExportTable, _PELDR_FreeModule


Services

The following sections describe the API elements associated withVXDLDR.


VXDLDR_DevInitFailed

include vxdldr.inc

mov     edx [DeviceHandle]
VxDcall VXDLDR_DevInitFailed

Informs the VxD loader that a device initialization failed. Uses EAX.

  • The carry flag is clear if the function is successful. Otherwise, the carry flag is set and EAX contains the error code. For a list of possible error codes, see the VXDLDR_LoadDevice service.
DeviceHandle
Handle of the device as returned by VXDLDR_LoadDevice.

This service is called after a VxD has loaded and failed to initialize a dynamically loadable VxD. (The module must initialize the VxD when the VXDLDR_LoadDevice service is called with the Flags parameter set to zero.)


VXDLDR_DevInitSucceeded

include vxdldr.inc

mov     edx [DeviceHandle]
VxDcall VXDLDR_DevInitSucceeded
jc      errorhandler

Informs the VxD loader that a device has been initialized. Uses EAX.

  • The carry flag is clear if the function is successful. Otherwise, the carry flag is set and EAX contains the error code. For a list of possible error codes, see the VXDLDR_LoadDevice service.
DeviceHandle
Handle of the device as returned by VXDLDR_LoadDevice.

This service is called after a VxD has loaded and initialized a dynamically loadable VxD, sending the SYS_DYNAMIC_DEVICE_INIT message. (The module must initialize the VxD when the VXDLDR_LoadDevice service is called with the Flags parameter set to zero.)


VXDLDR_GetDeviceList

include vxdldr.inc

VxDcall VXDLDR_GetDeviceList

Retrieves the address of the first DeviceInfo structure in VXDLDR's device list.

  • Returns the address of the first DeviceInfo structure in EAX.


VXDLDR_GetVersion

include vxdldr.inc
VxDcall VXDLDR_GetVersion

Retrieves the version number of the VxD loader.

  • Returns the version number of VXDLDR in EAX. The major version number is in AH and the minor version number is in AL.


VXDLDR_LoadDevice

include vxdldr.inc

mov     edx, [Devicename]
mov     eax, [Flags]
VxDcall VXDLDR_LoadDevice
jc      errorhandler

Loads a VxD into memory. Uses EAX and EDX.

  • Returns the address of the device-descriptor block in EAX and the device handle in EDX when the function is successful. Otherwise, it sets the carry flag and EAX contains the error code, which can be one of the following values:
Value | Meaning
VXDLDR_ERR_BAD_DEVICE_FILE | Specified VxD file is not usable.
VXDLDR_ERR_DEVICE_REFUSED | Specified device operation not allowed.
VXDLDR_ERR_DUPLICATE_DEVICE | Specified operation has already occurred for the given device.
VXDLDR_ERR_FILE_OPEN_ERROR | Unable to open specified file.
VXDLDR_ERR_FILE_READ | Unable to read specified file.
VXDLDR_ERR_IN_DOS | System error.
VXDLDR_ERR_NO_SUCH_DEVICE | Specified device not found.
VXDLDR_ERR_OUT_OF_MEMORY | Out of memory.

Devicename
Address of a null-terminated string specifying the filename of the VxD.
Flags
Indicates whether the device is initialized by the system or by the calling VxD. If this parameter is VXDLDR_INIT_DEVICE, the device is initialized by the system. Otherwise, this parameter should be zero, and the calling VxD should initialize the device and send the SYS_DYNAMIC_DEVICE_INIT message.

If you call this function without specifying the VXDLDR_INIT_DEVICE flag, you must call either the VXDLDR_DevInitSucceeded or VXDLDR_DevInitFailed service to free system resources associated with the VxD before calling VXDLDR_UnloadDevice to unload the VxD.


VXDLDR_Notify

include vmm.inc
include vxdldr.inc

; Install a hook procedure
mov esi, OFFSET32 HookProc
VMMcall Hook_Device_Service

jc error

This service is called internally by VXDLDR at various stages of its operation. Devices which need to be notified of VXDLDR activity should hook this service.

The system calls the hook procedure as follows:

mov eax, NotificationCode
; other registers depending on the NotificationCode
call HookProc
NotificationCode
The notification code. Note that other registers may be used depending on the notification code. The following VXDLDR notification codes are defined:
Code | Meaning
Ordinal of VXDLDR_Notify | General notification.
VXDLDR_NOTIFY_OBJECTUNLOAD | A dynamic object is being uloaded.

Register | Meaning
EDI | Address of the DeviceInfo structure for device being unloaded
EBX | Address of the ObjectInfo structure for object being unloaded.
EDX | Object number.

Each hook must preserve all registers and propagate the call down the chain. Any registers not explicitly defined are reserved for future extension of this service.

Do not use the DI_DDB member in the DeviceInfo structure because the DDB may have been freed.


VXDLDR_UnloadDevice

include vxdldr.inc

mov     ebx [DeviceID]
VxDcall VXDLDR_UnloadDevice
jc      errorhandler

Unloads a VxD from memory. Uses EAX.

  • The carry flag is clear if the function is successful. Otherwise, the carry flag is set and EAX contains the error code. For a list of possible error codes, see the VXDLDR_LoadDevice service.
DeviceID
Identifier of the device to be unloaded. If this value is -1, EDX should contain the address of a null-terminated string giving the module name of the VxD.


VXDLDR_UnloadMe

include vxdldr.inc

mov bx, VxD_ID
VxDcall VXDLDR_UnloadMe
jc error

Unloads a self-loaded VxDfrom memory.

  • Clears the carry flag if successful, otherwise sets the carry flag.
VxD_ID
The ID of the VxD. If the ID is UNDEFINED_DEVICE_ID, then put the address of a null-terminated string containing the VxD name into DS:EDX.


DeviceInfo

struct DeviceInfo {
    struct DeviceInfo *DI_Next;
    UCHAR  DI_Loaded;
    struct VxD_Desc_Block *DI_DDB;
    USHORT DI_DeviceID;
    CHAR   *DI_ModuleName;
    ULONG  DI_Signature;
    ULONG  DI_ObjCount;
    struct ObjectInfo *DI_ObjInfo;
    ULONG  DI_V86_API_CSIP;
    ULONG  DI_PM_API_CSIP;
};

Contains information about a VxD.

DI_Next
Address of the next DeviceInfo structure in the list of devices maintained by VXDLDR. When there are no more devices, this element is NULL.
DI_Loaded
Nonzero if the VxD is currently loaded.
DI_DDB
Address of the VxD_Desc_Block structure for the VxD.
DI_DeviceID
The device identifier for the VxD.
DI_ModuleName
Address of the name of the VxD module.
DI_Signature
A unique value used by the system to verify the structure.
DI_ObjCount
Number of ObjectInfo structures pointed to by the DI_ObjInfo member.
DI_ObjInfo
Address of an array of ObjectInfo structures. Each ObjectInfo structure describes one of the VxD's memory objects.
DI_V86_API_CSIP
Save area for the virtual-86 mode entry point.
DI_PM_API_CSIP
Save area for the protected-mode entry point.


ObjectInfo

struct ObjectInfo {
    ULONG OI_LinearAddress;  // starting address of object
    ULONG OI_Size;           // size of object (in bytes)
    ULONG OI_ObjType;        // see below
    ULONG OI_Resident;       // see below
};

Contains information about a memory object in a VxD.

OI_ObjType
Object type, which can be one of the following values.
Constant | Value | Meaning
RCODE_OBJ | -1 | Real-mode stub (ignored for dynamically loadable VxDs)
LCODE_OBJ | 0x01 | Locked code segment
LDATA_OBJ | 0x02 | Locked data segment
PCODE_OBJ | 0x03 | Pageable code segment
PDATA_OBJ | 0x04 | Pageable data segment
SCODE_OBJ | 0x05 | Static code segment (dynamically loadable VxDs only)
SDATA_OBJ | 0x06 | Static data segment (dynamically loadable VxDs only)
CODE16_OBJ | 0x07 | 16-bit V86 segment
ICODE_OBJ | 0x11 | Initialization-time only code segment
IDATA_OBJ | 0x12 | Initialization-time only data segment
ICODE16_OBJ | 0x13 | Initialization-time only 16-bit V86 segment

OI_Resident
Whether or not the memory object is static. This value is zero for VxDs that are not dynamically loadable.

The DeviceInfo structure includes the address of an array of ObjectInfo structures that describe a VxDs memory objects.


Protected- and Virtual-Mode Functions

In the following function descriptions, VXDLDR's protected-mode API address is referred to as _VXDLDRCallAddr. For more information about retrieving this address, see .


Get VXDLDR Version

mov     ax, 0
call    [_VXDLDRCallAddr]

Retrieves the version number of the VxD loader. Uses DX.

  • Returns the version number of VXDLDR in DX if successful.


Load Device

lds     dx, [VxDFilename]
mov     ax, 1
call    [_VXDLDRCallAddr]

Loads a VxD. Uses AX.

  • The carry flag is clear if the function is successful. Otherwise, the carry flag is set and AX contains the error code. For a list of possible error codes, see the VXDLDR_LoadDevice service.
DS:DX
Address of null-terminated string giving the filename of the VxD to load.


Unload Device

mov     bx, VxDID
mov     ax, 2
call    [_VXDLDRCallAddr]

Unloads a VxD. Uses AX.

  • The carry flag is clear if the function is successful. Otherwise, the carry flag is set and AX contains the error code. For a list of possible error codes, see the VXDLDR_LoadDevice service.
BX
The identifier of the VxD to unload. If BX is -1, DS:DX should contain the address of a null-terminated string giving the module name of the VxD to unload.


Control Messages

The following control messages are sent to dynamically loadable VxDs.


SYS_DYNAMIC_DEVICE_EXIT

mov     eax, SYS_DYNAMIC_DEVICE_EXIT
call    [VSAMPLED_Control]
jc      error_handler
VSAMPLED_Control
The address of the device control procedure, as specified in the Declare_Virtual_Device macro.

Control dispatches for dynamically loadable VxDs should be in locked memory, such as memory locked using the VxD_LOCKED_CODE_SEG macro.


SYS_DYNAMIC_DEVICE_INIT

mov     eax, SYS_DYNAMIC_DEVICE_INIT
call    [VSAMPLED_Control]
jc      error_handler

Notifies a dynamically loadable VxD that it is being loaded and that it should perform any required initialization.

VSAMPLED_Control
The address of the device control procedure, as specified in the Declare_Virtual_Device macro.

This message is sent by the system when the VXDLDR_LoadDevice service is called with the Flags parameter equal to VXDLDR_INIT_DEVICE. Otherwise, this message is sent by the application that initializes the VxD.

While processing this message, dynamically loadable virtual devices typically initialize any critical functions needed to support interrupts and claim any V86 pages required to support the device.

Control dispatches for dynamically loadable VxDs should be in locked memory, such as memory locked using the VxD_LOCKED_CODE_SEG macro.


PE Loader Services

The PE loader provides an interface that allows a Plug-N-Play DevLoader (or other layered device architecture) to load portable executable device drivers into ring-0 address space. The following provides information about the Portable Exectuable (PE) Loader services for the VXDLDR device.


_PELDR_AddExportTable

include vxdldr.inc

LRESULT CDECL PELDR_AddExportTable(PHPEEXPORTTABLE phExportTable,
    PSTR pszModuleName, ULONG cExportedFunctions, ULONG cExportedNames,
    ULONG ulOrdinalBase, PVOID *pExportNameList,
    PUSHORT pExportOrdinals, PVOID *pExportAddrs, PHLIST phList);

Adds an export table to the export table list. Uses C calling conventions.

  • Returns PELDR_ERR_NOERROR if successful, otherwise returns PELDR_ERR_MEM_NOMEMORY which means there is insufficient memory to complete the request.
phExportTable
Address of an HPEEXPORTTABLE that receives the handle to the export table on successful return.
pszModuleName
Address of a null-terminated string containing the module name. For example: "VXDLDR.VXD".
cExportedFunctions
Number of exported functions.
cExportedNames
Number of exported names.
ulOrdinalBase
Base value for ordinal table.
pExportNameList
Address of an array of pointers to null-terminated strings. This list contains the exported names of the module.
pExportOrdinals
Address of an array of ordinals. This array must have a one to one correspondence with the exported name list.
pExportAddrs
Address of an array of exported addresses. This array is used during import resolution. The ordinal is an index into this array.
phList
Address of a list handle of export tables. This parameter is specified when a client restricts the export table list. If NULL, the global export table list is used. If the handle pointed to by phList is NULL, a new local export table list is created.

The pointers and data referenced by pszModuleName, pExportNameList, pExportOrdinals, pExportAddrs, and phList must remain valid until the export table is removed using _PELDR_RemoveExportTable.


_PELDR_FreeModule

#include <vxdldr.h>

LRESULT CDECL PELDR_FreeModule(HPEMODULE hModule, PHLIST phList);

Decrements usage count of given module and frees the module when usage count reaches zero.

  • Returns the module load count if successful, otherwise returns PELDR_ERR_INVALIDHANDLE if the specified handle is not valid.
hModule
A handle to a module. This parameter must be a valid handle returned by _PELDR_LoadModule or _PELDR_GetModuleHandle.
phList
A pointer to a list handle of export tables. This parameter is specified when a client restricts the export table list. If NULL, the global export table list is used.


_PELDR_GetEntryPoint

#include <vxdldr.h>

PVOID PELDR_GetEntryPoint(HPEMODULE hModule);

Returns the address of the entry point of the given module. Uses C calling conventions.

  • Returns the address of the entry point of the given module or NULL if the module handle is invalid.
hModule
A handle to a module. This parameter must be a valid handle returned by _PELDR_LoadModule or _PELDR_GetModuleHandle.


_PELDR_GetModuleHandle

#include <vxdldr.h>

HPEMODULE PELDR_GetModuleHandle(PSTR pFileName);

Gets the module handle to the given a file name. Uses C calling conventions.

  • Returns NULL if the module is not found, otherwise the return value is the handle of the module.
pFileName
A pointer to a null terminated string containing the file name of the module.

Note It is not necessary to specify the full path of the executable. Module information is stored by the filename (8.3 format).


_PELDR_GetModuleUsage

#include <vxdldr.h>

LRESULT CDECL PELDR_GetModuleUsage(HPEMODULE hModule);

Gets the usage count of the given module. Uses C calling conventions.

  • Returns the usage count or PELDR_ERR_INVALIDHANDLE if the specified handle is not valid.
hModule
A handle to a module. This parameter must be a valid handle returned by _PELDR_LoadModule or _PELDR_GetModuleHandle.


_PELDR_GetProcAddress

#include vxdldr.h

PVOID CDECL PELDR_GetProcAddress(HPEMODULE hModule,
    PVOID FuncName, PHLIST phList);

Returns the address of the specified exported dynamic-link library (DLL) function.

  • Returns the address of to the function entry point or NULL if the function is not found.
hModule
A handle to a module or pointer to a null-terminated string containing the module name. If this parameter is a handle to a module it must be a valid handle returned by _PELDR_LoadModule or _PELDR_GetModuleHandle.
pFuncName
Address of a null-terminated string containing the function name or specifies the function's ordinal value. If this parameter is an ordinal value, it must be in the low-order word; the high-order word must be zero.
phList
Address of a list handle of export tables. This parameter is specified when a client restricts the export table list. If NULL, the global export table list is used.


_PELDR_InitCompleted

#include <vxdldr.h>

LRESULT CDECL PELDR_GetModuleUsage(HPEMODULE  hModule);

Decommits memory in INIT sections. This function should be used when the caller has completed the module specific initialization sequence and the INIT section is no longer required.

  • Returns the module load count if successful, otherwise returns PELDR_ERR_INVALIDHANDLE if the specified handle is not valid.
hModule
A handle to a module. This parameter must be a valid handle returned by _PELDR_LoadModule or _PELDR_GetModuleHandle.


_PELDR_LoadModule

#include <vxdldr.h>

LRESULT CDECL PELDR_LoadModule(PHPEMODULE  phModule,
    PSTR pFileName, PHLIST phList);
  • Loads a portable executable, performs relocation fixups and resolves imports. Uses C calling Returns PELDR_ERR_NOERROR if successful, otherwise returns a non-zero error number. Possible error return values include the following:
PELDR_ERR_FILE_UNABLETOOPEN | Unable to open the specified file.
PELDR_ERR_MEM_NOMEMORY | Insufficient memory to complete the request.
PELDR_ERR_IMAGE_INVALIDSIZE | Module image size is invalid.
PELDR_ERR_IMAGE_INVALIDFORMAT | The specified file is not a valid portable executable type binary.
PELDR_ERR_FILE_READER PELDR_ERR_FILE_READER PELDR_ERR_FILE_READER PELDR_ERR_FILE_READERROR | A read error occurred while loading the file.

phModule
Address of the handle to receive the module handle on successful return.
pFileName
Address of a null terminated string containing the path and filename to the executable. If the path is not specified, the path of the VMM32 executable is used.
phList
Address of the list handle of export tables. This parameter is specified when a client restricts the export table list. If NULL, the global export table list is used. If the handle pointed to by phList is NULL, a new local export table list is created.

Note This function does not load modules to resolve external dependencies, instead, this function assumes that the caller is loading modules in the appropriate order to resolve dynamic link dependencies. During system initialization (up to the Init_Complete notification), _PELDR_LoadModule will check the V86MMGR translation buffer state and automatically allocate a temporary global V86 data area for I/O buffering if the translation buffer does not exist.


_PELDR_LoadModuleEx

#include <vxdldr.h>

LRESULT CDECL PELDR_LoadModuleEx(PHPEMODULE  phModule,
    PSTR pFileName, PHLIST phList, DWORD dwFlag);

Loads a portable executable, performs relocation fixups and resolves imports. Uses C calling conventions.

This service is similar to _PELDR_LoadModule, except that _PELDR_LoadModuleEx includes the following additional parameter:

dwFlag
Flag that specifies whether resources are freed when the portable executable is loaded. If this parameter is PELDR_LOADFLAG_FREERESOURCES, resources are freed; otherwise, they are not.


_PELDR_RemoveExportTable

#include <vxdldr.h>

LRESULT CDECL PELDR_RemoveExportTable(HPEEXPORTTABLE hExportTable,
    PHLIST phList);

Removes an export table from the export table list.

  • Returns PELDR_ERR_NOERROR successful, otherwise returns PELDR_ERR_INVALIDHANDLE if the specified handle is not valid.
hExportTable
A handle to an export table. This parameter must be a valid handle as returned by _PELDR_AddExportTable.
phList
A pointer to a list handle of export tables. This parameter is specified when a client restricts the export table list. If NULL, the global export table list is used.


Virtual File Cache Services (VCACHE)

Four types of virtual file caching services are defined for Windows 95: lookup cache services, memory manager services, debug services, and miscellaneous services. The following sections introduce these services.


Lookup Cache Services

The lookup cache is a separate caching subsystem that allows arbitrary keys to be associated with arbitrary data. This data is stored in the registry and is persistent. Note that the caches themselves live in locked memory, the registry is used as a backup store and is updated periodically as a background process - so _VCache_Lookup and _VCache_UpdateLookup can be called at event time.

Service | Description
_VCache_CloseLookupCache | Closes a look-up cache.
_VCache_CreateLookupCache | Creates/Opens a look-up cache.
_VCache_DeleteLookupCache | Deletes a look-up cache.
_VCache_Lookup | Retrieves data associated look-up key.
_VCache_UpdateLookup | Updates/Creates a key entry in a look-up cache.


Memory Manager Services

These services are to be used only by the memory manager.

Service | Description
VCache_RelinquishPage | Returns a page to the memory manager.
VCache_UseThisPage | Creates a new page for the cache.


Debug Services

There are these debug services:

Service | Description
VCache_RecalcSums | Recalculates buffer checksums.
VCache_TestHandle | Validates a cache block handle.
VCache_VerifySums | Verifies checksums for a buffer.


Miscellaneous Services

There are these miscellaneous services:

Service | Description
VCache_AdjustMinimum | Adjusts the minimum buffer quota.
VCache_CheckAvail | Checks available space for a data transfer
VCache_Deregister | Deregisters a cache associated with an FSD.
VCache_Enum | Enumerates the cache blocks.
VCache_FindBlock | Locates a block of data in a cache.
VCache_FreeBlock | Places a cache block on the free list.
VCache_GetSize | Reports the cache size.
VCache_GetStats | Returns cache statistics.
VCache_Get_Version | Get version number.
VCache_Hold | Increments the hold count of a buffer.
VCache_MakeMRU | Marks a block as most-recently-used.
VCache_Register | Register a buffer discard function with VCache.
VCache_SwapBuffers | Swaps two cache buffers.
VCache_TestHold | Returns hold count of a buffer.
VCache_Unhold | Decrements the hold count of a buffer.


Lookup Cache Services

The following topics describe the services provided.


_VCache_CloseLookupCache

_VCache_CloseLookupCache( HLOOKUP _hnd_ )

Closes an open lookup cache.

  • Returns zero in EAX on success or an appropriate Win32 error value otherwise.


_VCache_CreateLookupCache

_VCache_CreateLookupCache (char *lpszName, DWORD nMaxElems, DWORD Flags,
    HLOOKUP *phlookup );

Creates a new (or opens an existing) lookup cache.

  • Returns zero in EAX on success or an appropriate Win32 error value otherwise.
lpszName
Name of the lookup cache. This value must be a valid registry key name.
nMaxElems
Maximum number of elements in the cache. When this limit is reached, adding new keys will in old keys being aged out, LRU style.
Flags
Reserved. This value must be zero.
phlookup
Address of the DWORD that will receive the opened cache handle.


_VCache_DeleteLookupCache

_VCache_DeleteLookupCache( char *lpszName )

Deletes a lookup cache.

  • Returns zero in EAX on success or an appropriate Win32 error value otherwise.


_VCache_Lookup

_VCache_Lookup( HLOOKUP hLookup, unsigned long keylen, void *pKey,
    unsigned long *pdatalen,void *pData )

Moves a specified key value to the head of the cache LRU list and retrieves the associated data.

  • Returns zero in EAX on success or an appropriate Win32 error value otherwise.
hLookup
Handle of previously opened cache.
keylen
Length, in bytes, of the supplied key value.
pKey
Address of the key value.
pdatalen
Length, in bytes, of the destination buffer.
pData
Address of destination buffer.


_VCache_UpdateLookup

_VCache_UpdateLookup( HLOOKUP hLookup, unsigned long keylen, void *pKey,
    unsigned long datalen, void *pData )

If an existing key is present, it's associated data is updated with pData. Otherwise a new key entry is generated, aging the LRU entry if the cache is full.

  • Returns zero in EAX on success or an appropriate Win32 error value otherwise.
hLookup
Handle of previously opened cache
keylen
Length, in bytes, of the supplied key value.
pKey
Address of the key value.
datalen
Length, in bytes, of the destination buffer.
pData
Address of the destination buffer.


Memory Manager Services

The following topics describe the services provided.


VCache_RelinquishPage

Returns a page to the memory manager. Uses flags.

  • Returns the result in EAX. The value is the linear address of the located page or zero.

    This service tries to find a page it can return to the memory manager. In general it will only fail if all pages are currently reserved, held, or dirty.


VCache_UseThisPage

Add a a page to the cache. Uses flags.

  • No return value.

EAX contains the address of the page to add.

By virtue of this routine, the memory manager makes a new page available to the cache.


Debug Services

The following topics describe the services provided.


VCache_RecalcSums

Recalculate buffer checksums. Uses flags.

  • No return value.

On entry, EAX contains sector size for this block

On entry, ESI contains the cache block handle.

This routine will compute a sector by sector checksum of a buffer's contents and save the sums for later verification by calling VCache_VerifySums. An FSD should recalculate the checksums whenever the contents of a buffer are change but the buffer is not going to be made dirty. EG: by reading data into the buffer.


VCache_TestHandle

Test the validity of a cache buffer handle.

  • No return value.

On entry, AH contains the FSD ID.

On entry, ESI contains the cache buffer handle.


VCache_VerifySums

Verifies buffer checksums. Uses all the registers except ESI.

  • No return value; however, the Zero flag is set if the checksums match.

On entry, EAX contains the block sector size, in bytes.

On entry, ESI contains the cache block handle.

This routine verifies that the correct dirty bits for a buffer are set. This is done by calculating checksums of the buffer contents sector by sector and comparing against stored sums. The checksums are set by calling VCache_RecalcSums for the block.

This service only checks the sectors that aren't marked dirty.


Miscellaneous Services

The following topics describe the services provided.


VCache_AdjustMinimum

Adjusts the client's minimum buffer quota. Uses EAX, EBX, ECX, EDX, EDI, ESI, and flags.

  • No return value; however, the Carry flag is cleared if the quota is adjusted. If the quota is not adjusted, the Carry flag is set.

On entry, AH contains the FSD ID.

On entry, ECX contains the new buffer quota.


VCache_CheckAvail

Checks the availability of a specified number of buffers. Uses EAX, EBX, ECX, EDX, and flags

  • Returns the number of available buffers in EAX. In addition, the Carry flag is clear if the specified number of buffers is available. If fewer buffers are available, the Carry flag is set.

On entry, AH contains the FSD ID.

On entry, ECX contains the number of buffers needed.

An FSD can call VCache_CheckAvail to decide whether to cache a data transfer or use a direct transfer instead.


VCache_Deregister

Deregisters a cache and its associated resources. Uses EAX, EBX, ECX, EDX, EDI, ESI, and flags.

  • No return value.

On entry, AH contains an FSD ID of the cache to deregister.

An FSD must call this function to tell VCache that it no longer needs any cache resources.

Each cache ID is unique. They are not recycled.


VCache_Enum

Enumerates cache blocks for a specified FSD. Uses all registers.

  • No return value.

On entry, AH contains the FSD ID.

On entry, EDX contains the function to call for each buffer.

On entry, EBX, ECX, and EBP can contain information to pass to the callback function. This information will be forwarded unchanged to the callback function.

The callback function passed will be invoked for each block as follows:

On entry of the callback function, ESI contains the cache block handle.

On entry of the callback function, the Zero flag is clear if the block is held or is set if the block is free.

On entry of the callback function, EBX, ECX, and EBP contain information forwarded from VCache_Enum.

If the callback function changes EBX, ECX, or EBP, the changed values will be passed to subsequent invocations of the function. That is, this service does not preserve the values of EBX, ECX, and EBP across the call.


VCache_FindBlock

Looks up data in virtual cache and can create a buffer if one is not found. Always uses EAX, ESI, and flags. If creating a buffer, ECX and EDX are also used.

  • Returns information in the following locations:
Location | Contents or settings
Carry flag | Set if the block is not found. Clear if the block is found.
ESI | contains the cache block handle if the block is found or created. Otherwise, ESI contains the value zero.
Zero flag | set if the buffer is not locked.
EAX | contains the address of the buffer if ESI is nonzero.

When a buffer is created, the value of its FSD private fields are set to zero.

On entry, AL contains one or more of the following options that determine how VCache_FindBlock acts:

Option | Description
VCFB_Create | create buffer if not found
VCFB_Hold | hold buffer if found
VCFB_LowPri | low priority create
VCFB_MakeMRU | make buffer most recently used
VCFB_MustCreate | creation must succeed if there are any clean, unheld buffers (only valid with VCFB_Create)
VCFB_RemoveFromLRU | remove buffer from LRU list entirely (for buffers that will be held for a long time). Cannot be used with VCFB_MakeMRU.

Other options are obsolete and ignored.

On entry, AH contains the file system identifier.

On entry, EBX contains key1 information that includes the sector and byte #.

On entry, EDI contains key2 information that includes the volume id and file id.

NOTE: (0, 0) is not a valid key value.


VCache_FreeBlock

Put cache block onto free list. Uses ECX, EDX, and flags.

  • No return value.

On entry, ESI contains the cache block handle.

VCache_FreeBlock invalidates the contents of a buffer and places the buffer at the LRU end of the MRU/LRU list. VCache_FreeBlock assumes that the file system has already performed any cleanup required, so the buffer flush routine will not be called.


VCache_GetSize

Retrieves the cache size. Uses EAX, EDX.

  • Returns information in the following locations:
Location | Contents
EAX | contains the current number of blocks in the cache if AH is zero. Contains the current quota of the FSD if AH contains an FSD ID (maximum number of block the FSD can own).
EDX | contains the maximum number of cache blocks.

On entry, AH contains the FSD ID or zero.


VCache_GetStats

Retrieve cache statistics. Uses EBX, ECX, EDI.

  • Returns statistics in the following registers:
Register | Contents on exit
EBX | Number of cache misses to one of the last 26 discarded cache blocks since the last call to VCache_GetStats.
ECX | Number of cache hits to one of the last 26 LRU cache blocks since the last call to VCache_GetStats.
EDX | Base address of range reserved for VCache.
EDI | Number of cache blocks discarded since the last call to VCache_GetStats.

This service returns some statistics used by the memory manager to tune how much memory is available for VCache and how much for paging.

When the statistics are queried, the counts are cleared. Therefore, if an application other than the memory manager uses this service, system performance will suffer.


VCache_Get_Version

Get version number. Uses EAX, EBX, Flags.

  • Returns the version number in EAX.

The version number returned during development will be bumped any time something in the VCache service interface changes.


VCache_Hold

Hold a buffer. Uses flags and preserves the contents of the carry flag.

  • No return value.

On entry, ESI contains the cache block handle.

VCache_Hold increments the buffer hold count to prevent the buffer from being recycled.


VCache_MakeMRU

Make block "most recently used." Uses EAX, ECX, EDX, and flags.

  • No return value.

On entry, ESI contains the cache block handle.

This service is used when an FSD wants to update a buffer's access information without the overhead of calling VCache_FindBuffer.


VCache_Register

Registers an FSD with cache. Uses EAX, flags.

  • Returns in AL a one-byte identifier that the FSD will use to identify itself when issuing FindBlock requests.

On entry, ESI contains the value of a buffer discard procedure. This value cannot be -1.

On entry, ECX contains the minimum number of blocks to reserve for this FSD.

An FSD must call this function to register a buffer discard function with VCache.

This service can only be called during DEVICE_INIT.


VCache_SwapBuffers

Given two cache block handles, this procedure swaps the buffers associated with the handles. The blocks must be owned by the same client and they must both be held. Uses EAX and flags.

  • No return value; however, the Carry flag is cleared if the blocks are swapped. If the blocks are not swapped, the Carry flag is set.

On entry, ESI contains the handle of the first cache block.

On entry, EDI contains the handle of the second cache block.


VCache_TestHold

Test hold status of a buffer. Uses EAX, flags

  • Returns the value of the buffer hold count in EAX. If the buffer can be released (the hold count is zero), the Zero flag is set.

On entry, ESI contains the cache block handle.


VCache_Unhold

Release a buffer hold. Uses flags and preserves the carry bit.

  • No return value; however, the Zero flag is set if the buffer is released.

On entry, ESI contains the cache block handle.

VCache_Unhold decrements the buffer's hold counter. When the hold counter reaches zero, the buffer can be recycled. If the buffer is recycled, the file system will be notified so that it can flush the buffers contents.


Virtual Math Coprocessor

The virtual math coprocessor device virtualizes the math coprocessor, allowing multiple virtual machines to preserve the state of the coprocessor across task switches. This section describes the interfaces of the virtual math coprocessor device (VMCPD).


Reference

The VMCPD provides the following services:

VMPCD_Get_CR0_State

VMPCD_Get_Thread_State

VMCPD_Get_Version

VMCPD_Get_Virt_State

VMCPD_Set_CR0_State

VMPCD_Set_Thread_State

VMCPD_Set_Virt_State


Virtual Math Coprocessor Services

The following topics describe the services provided.


VMPCD_Get_CR0_State

mov edi, ThreadHandle
VxDcall VMPCD_Get_CR0_State
mov [CR0_Flags], eax

Retrieves the current state of the EM (emulate), MP (math present), and TS (task switched) coprocessor flags for the given thread. The flags are retrieved from the CR0 register. Uses EDI, EAX, and Flags.

  • Returns the coprocessor flags in EAX.
ThreadHandle
Handle of the thread.


VMPCD_Get_Thread_State

mov esi, OFFSET 32 SaveBuffer
mov edi ThreadHandle
VxDcall VMPCD_Get_Thread_State

Retrieves the current state (environment and register stack) of the floating point unit (FPU) for the given thread. Uses Flags.

  • No return value.
SaveBuffer
Address of a buffer that receives the state information.
ThreadHandle
Handle of thread for which to retrieve the FPU state.


VMCPD_Get_Version

include vmcpd.inc

VxDcall VMCPD_Get_Version
mov [Major], ah
mov [Minor], al
mov [Coprocessor_Flag], ecx

Retrieves the VMCPD version number. Uses EAX, ECX, and Flags.

  • Returns the version number in EAX. AH contains the major version number; AL contains the minor version number. ECX contains one of these values:
0 | No coprocessor
2 | 80287
3 | 80387


VMCPD_Get_Virt_State

include vmcpd.inc

mov ebx, VMHandle
VxDcall VMCPD_Get_Virt_State
mov [Virt_State], al

Retrieves the virtual state of EM and MP bits for the given virtual machine. Uses EAX, and Flags.

  • Returns the virtual state of EM and MP bits in AL. Bit 0 specifies the MPv bit; bit 1 the EMv bit.
VMHandle
Handle of the virtual machine.


VMCPD_Set_CR0_State

mov edi, ThreadHandle
mov eax, CR0_Flags
VxDcall VMCPD_Set_CR0_State

Sets the state of the EM (emulate) and MP (math present) coprocessor flags for the given thread. Uses EAX, EDX, EDI, and Flags.

  • No return value.
ThreadHandle
Handle of the thread.
CR0_Flags
Coprocessor CR0 flags to set.


VMPCD_Set_Thread_State

mov esi, OFFSET32 RestoreBuffer
mov edi, ThreadHandle
VxDcall VMPCD_Set_Thread_State

Sets the state of the floating point unit (FPU) for the given thread. Uses Flags.

  • No return value.
RestoreBuffer
Address of a buffer that contains the state information to set.
ThreadHandle
Handle of thread for which to set the FPU state.


VMCPD_Set_Virt_State

include vmcpd.inc

mov ebx, VMHandle
mov al, Virt_State
VxDcall VMCPD_Set_Virt_State

Sets the virtual state of EM and MP bits for the given virtual machine. Uses Flags.

  • No return value.
VMHandle
Handle of the virtual machine.
Virt_State
New virtual state of the EM and MP bits. Bit 0 sets the MPv bit; bit 1 the EMv bit.


Virtual Power Device

The virtual power device (VPOWERD) provides power management support for the Windows 95 operating system. It works in conjunction with the system BIOS or other power management software to provide a system-independent interface to power management services. This means virtual devices and device drivers written for Windows 95 use VPOWERD services for power management rather than access the power management software directly.

VPOWERD supports power management software written to the Advanced Power Management (APM) specifications, versions 1.0 and 1.1. VPOWERD does not support the UPS functionality provided by APM 1.1.


Power Management Services

The VPOWERD services let other virtual devices determine the power management capabilities of the system, check the current system power status, set the system power management level or device power state, and set a power handler. There are these VPOWERD services:

_VPOWERD_Deregister_Power_Handler

_VPOWERD_Get_APM_BIOS_Version

_VPOWERD_Get_Power_State

_VPOWERD_Get_Power_Management_Level

_VPOWERD_Get_Power_Status

_VPOWERD_Get_Version

_VPOWERD_OEM_APM_Function

_VPOWERD_Register_Power_Handler

_VPOWERD_Restore_Power_On_Defaults

_VPOWERD_Set_Device_Power_State

_VPOWERD_Set_Power_Management_Level

_VPOWERD_Set_System_Power_State


Power Messages

VPOWERD broadcasts WM_POWERBROADCAST messages to notify applications and Windows-based drivers of changes to the system power state. These broadcasts can be initiated by the user, the timer, or the BIOS. Only user-initiated messages allow for user interaction. In all other cases, drivers must respond to the messages on their own. For detailed information about WM_POWERBROADCAST messages, see the Microsoft Win32 Programmer's Reference.

The Configuration Manager notifies ring-0, plug and play device drivers of power changes by sending configuration messages to these drivers instead of WM_POWERBROADCAST messages. The drivers respond to the configuration messages in a similar manner as Windows-based device drivers respond to the corresponding WM_POWERBROADCAST messages. For more information about configuration messages, see the Configuration Manager documentation.

If the system is running APM 1.1 and a low-level driver rejects a request to change the power mode to suspend or standby, VPOWERD sends a "last request rejected" notification to the BIOS if the request was initiated by the BIOS. Similarly, VPOWERD sends "busy processing last request" notifications to the BIOS as needed.


Power Handler

Power handler services are intended for use by Configuration Manager only. Virtual devices that require notification of power changes should install a message hook procedure using the _SHELL_HookSystemBroadcast service.

A power handler is a device-driver-supplied routine that carries out power-related tasks during power suspension and resumption. VPOWERD calls all registered power handlers as part of its normal sequence of shutting down and starting up power.

VPOWERD typically schedules an application-time event, using the SHELL_CallAtAppyTime service, when the request to suspend occurs. Within the application-time event, VPOWERD calls each handler once for each POWERFUNC_SUSPEND value. It orders the calls such that all handlers receive a POWERFUNC_SUSPEND_PHASE1 call before any receives a POWERFUNC_SUSPEND_PHASE2 call and so on.

When power is resumed, VPOWERD calls each handler once for each POWERFUNC_RESUME value. It orders the calls such that all handlers receive a POWERFUNC_SUSPEND_PHASE2 call before any receives a POWERFUNC_SUSPEND_PHASE1 call.

VPOWERD calls the handlers in the order specified by their initialization order, as given when a handler is registered. The PFG_REVERSE is set for the suspend messages and not for the resume messages. That is, VPOWERD normally calls the suspend in reverse load order, like a shutdown, so that the highest priority devices get suspended last yet resume first.

If at any point a handler fails a call, VPOWERD restores the system to the previous state. For example, if a handler rejects a POWERFUNC_SUSPEND_PHASE2 call, VPOWERD makes POWERFUNC_RESUME_PHASE2 and subsequent POWERFUNC_RESUME_PHASE1 calls to all handlers that had previously accepted the suspension.


Services

The following topics describe the power management services provided.


_VPOWERD_Deregister_Power_Handler

POWERRET _VPOWERD_Deregister_Power_Handler(POWER_HANDLER power_handler);

Deregisters a power handler from the event notification queue.

This is intended for use by Configuration Manager only. Virtual devices that require notification of power changes should install a message hook procedure using the _SHELL_HookSystemBroadcast service.

  • Returns PR_SUCCESS if successful, or one of the error values beginning with PR_ listed in VPOWERD.H.
power_handler
Address of the callback function to remove from the notification queue.

This service may only be called synchronously, that is, not at interrupt time.


_VPOWERD_Get_APM_BIOS_Version

DWORD _VPOWERD_Get_APM_BIOS_Version(VOID);

Retrieves the version of the current connection to the APM BIOS. If the service returns a valid version (that is 1.0 or 1.1), an APM BIOS exists in the system.

  • Returns one of these values:
0x0000 | No APM connection exists.
0x0100 | An APM 1.0 connection has been made.
0x0101 | An APM 1.1 connection has been made.


_VPOWERD_Get_Power_State

POWERRET _VPOWERD_Get_Power_State(POWER_DEVICE_ID Power_Device_ID,
    LPPOWER_STATE lpPower_State);

Retrieves the power state of a device or class of devices by passing the request directly to the APM BIOS. This function is available only for APM 1.1 connections.

  • Returns PR_SUCCESS if successful, or one of the error values beginning with PR_ listed in VPOWERD.H.
Power_Device_ID
APM 1.1 identifier of the device. Use the Plug and Play BIOS function Get APM 1.1 ID Table (Function 0Bh) to retrieve an identifier.
lpPower_State
Address of a variable that receives the power state for a device. Can receive one of these values:
PSTATE_APM_ENABLED (0x0000) | On
PSTATE_STANDBY (0x0001) | Standby
PSTATE_SUSPEND (0x0002) | Suspended
PSTATE_OFF (0x0003) | Off
0x0030 thru 0x007F | OEM-defined device states

All other values are reserved.

If Power_Device_ID specifies a class of devices (that is, the identifier has the form 0xxxFF), the function returns successfully only if the service _VPOWERD_Set_Device_Power_State has been previously used to set the state for that identifier.

This function does not supported the global system identifier 0x0001.


_VPOWERD_Get_Power_Management_Level

DWORD _VPOWERD_Get_Power_Management_Level(VOID);

Retrieves the power management level of the system.

  • Returns one of these values:
PMLEVEL_OFF | Power management off.
PMLEVEL_STANDARD | BIOS power management on.
PMLEVEL_ADVANCED | Both BIOS and cooperative power management on.


_VPOWERD_Get_Power_Status

POWERRET _VPOWERD_Get_Power_Status(POWER_DEVICE_ID Power_Device_Id,
    LPPOWER_STATUS lpPower_Status);

Retrieves the power status of the system, such as whether the system is running on AC or DC power, whether the battery is currently charging, and how much battery life currently remains.

  • Returns PR_SUCCESS if successful, or one of the error values beginning with PR_ listed in VPOWERD.H.
Power_Device_ID
APM 1.1 identifier of the device. Use the Plug and Play BIOS function Get APM 1.1 ID Table (Function 0Bh) to retrieve an identifier.
lpPower_Status
Address of a POWER_STATUS structure that receives the power status.


_VPOWERD_Get_Version

DWORD _VPOWERD_Get_Version(VOID);

Retrieves the version number of the VPOWERD device.

  • Clears the carry flag and returns a non-zero value if the VPOWERD device is loaded. The low-order word of the return value contains the VPOWERD version. The high-order byte contains the major version number and the low-order byte contains the minor version number.

    For example, the function returns 0x400 for version 4.0 of the VPOWER device.


_VPOWERD_OEM_APM_Function

POWERRET _VPOWERD_OEM_APM_Function(LPOEM_APM_REGS lpOEM_APM_Regs);

Carries out an OEM-specific APM 1.1 function by passing the function number and parameters directly to the BIOS. This function is available only for APM 1.1 connections.

  • Returns PR_SUCCESS if successful, otherwise an OEM-defined error value. In either case, the service sets members of the OEM_APM_REGS structure to appropriate values.
lpOEM_APM_Regs
Address of a OEM_APM_REGS structure that contains information about the function to carry out.

To get an OEM ID, refer to the APM 1.1 specification.


_VPOWERD_Register_Power_Handler

POWERRET _VPOWERD_Register_Power_Handler(POWER_HANDLER Power_Handler,
    DWORD Priority);

Registers a power handler to be notified of standby, suspend, and resume events.

This is intended for use by Configuration Manager only. Virtual devices that require notification of power changes should install a message hook procedure using the _SHELL_HookSystemBroadcast service.

  • Returns POWER_SUCCESS if successful, or one of the error values beginning with PR_ listed in VPOWERD.H.
Power_Handler
Address of the callback function that is notified of power management events. For more information about this callback, see the VPowerHandlerProc function.
Priority
Notification-order value. Callback functions with high values, relative to other callback functions, receive power-suspension event notifications before the other callbacks, but receive power-resumption event notifications after others.

This service may only be called synchronously, that is, not at interrupt time.


_VPOWERD_Restore_Power_On_Defaults

POWERRET _VPOWERD_Restore_Power_On_Defaults(VOID);

Reinitializes all APM BIOS power-on defaults. This service is intended to be used only by the operating system.

  • Returns PR_SUCCESS if successful, or one of the error values beginning with PR_ listed in VPOWERD.H.


_VPOWERD_Set_Device_Power_State

POWERRET _VPOWERD_Set_Device_Power_State(
    POWER_DEVICE_ID Power_Device_ID, POWER_STATE Power_State);

Sets the power management state for a given device by passing the request directly to the APM BIOS. This service is available only for APM 1.1 connections.

  • Returns PR_SUCCESS if successful, or one of the error values beginning with PR_ listed in VPOWERD.H.
Power_Device_ID
APM 1.1 identifier of the device. Use the Plug and Play BIOS function Get APM 1.1 ID Table (Function 0Bh) to retrieve an identifier.
Power_State
Power state for the device. Can be one of these values:
PSTATE_APM_ENABLED (0x0000) | On
PSTATE_STANDBY (0x0001) | Standby
PSTATE_SUSPEND (0x0002) | Suspended
PSTATE_OFF (0x0003) | Off
0x0030 thru 0x007F | OEM-defined device states

All other values are reserved.

This service returns 0x0001 if the power management level is off and 0x000B if the power management level is standard.


_VPOWERD_Set_Power_Management_Level

POWERRET _VPOWERD_Set_Power_Management_Level(DWORD Power_Management_Level);

Sets the power management level of the system.

  • Returns PR_SUCCESS if successful, or one of the error values beginning with PR_ listed in VPOWERD.H.
Power_Management_Level
Power management level. Can be one of these values:
PMLEVEL_OFF | Disables both BIOS and cooperative power management.
PMLEVEL_STANDARD | Enables BIOS power management but disables cooperative power management.
PMLEVEL_ADVANCE

PMLEVEL_ADVANCE

PMLEVEL_ADVANCE

PMLEVEL_ADVANCED

Enables both BIOS and cooperative power management.

When APM 1.1 is available, this service uses the APM Engage/Disengage and Enable/Disable Power Management functions.


_VPOWERD_Set_System_Power_State

POWERRET _VPOWERD_Set_System_Power_State(POWER_STATE Power_State,
    DWORD Request_Type);

Sets system power state to low- or no-power state. If a low-power state is set, this service returns successfully after power is restored. If a no-power state, this service never returns and the system loses all power. This service must be called at Appy Time.

  • Returns PR_SUCCESS if successful,or one of the error values beginning with PR_ listed in VPOWERD.H.
Power_State
Power state for the device. Can be one of these values:
PSTATE_STANDBY (0x0001) | Standby
PSTATE_SUSPEND (0x0002) | Suspended
PSTATE_OFF (0x0003) | Off

All other values are reserved.

Request_Type
Type of request. Can be one of these values:
REQTYPE_USER_INITIATED (0x00000000) | Request is User-initiated.
REQTYPE_TIMER_INITIATED (0x00000001) | Request is Timer-initiated.
REQTYPE_FORCED_REQUEST (0x00000002) | Force acceptance of request.
REQTYPE_BIOS_CRITICAL_SUSPEND (0x00000004) | Request is BIOS Critical Suspend.

Windows 95 does not support the APM 1.1 OEM-defined system states.


VPowerHandlerProc

POWERRET VPowerHandlerProc(POWERFUNC PowerFunc, ULONG Flags);

A driver-supplied callback function that receives notifications of power management events. This function must be registered using the _VPOWERD_Register_Power_Handler service and must be in locked code.

This is intended for use by Configuration Manager only. Virtual devices that require notification of power changes should install a message hook procedure using the _SHELL_HookSystemBroadcast service.

  • Returns PR_SUCCESS if it handles the event successfully, or one of the error values beginning with PR_ listed in VPOWERD.H.
PowerFunc
Power function. Can be one of these values:
PF_SUSPEND_PHASE1
PF_SUSPEND_PHASE2
PF_RESUME_PHASE2
PF_RESUME_PHASE1
PF_BATTERY_LOW
PF_POWER_STATUS_CHANGE
PF_UPDATE_TIME

Flags
Power flags. Can be one of these values:
PFG_UI_ALLOWED (0x00000001)
PFG_CANNOT_FAIL (0X00000002)
PFG_REQUEST_VETOED (0X00000004) | Indicates that the user may not be available to answer questions prior to the suspend operation. If this value is not given, higher levels of software may attempt some user interaction prior to accepting a suspend request.
PFG_REVERSE (0x00000008) | Clear for suspend operations, set on resume.
PFG_STANDBY (0x00000010) | Indicates a standby request when set as opposed to a suspend request.
PFG_CRITICAL (0x00000020) | Set to notify power handlers of critical resume operations so that they may attempt to resume their clients as best as possible. Critical suspends do not reach the power handlers in order to maintain compliance with the APM 1.1 specification.

Although the callback function is called from within application time, the function must not use application-time services when interrupts are disabled.


Structures

This section describes the power management structures.


OEM_APM_BYTE_REGS

typedef struct _OEM_APM_BYTE_REGS {
    WORD OEMAPM_Reserved1[6];
    BYTE OEMAPM_BL;
    BYTE OEMAPM_BH;
    WORD OEMAPM_Reserved2;
    BYTE OEMAPM_DL;
    BYTE OEMAPM_DH;
    WORD OEMAPM_Reserved3;
    BYTE OEMAPM_CL;
    BYTE OEMAPM_CH;
    WORD OEMAPM_Reserved4;
    BYTE OEMAPM_AL;
    BYTE OEMAPM_AH;
    WORD OEMAPM_Reserved5;
    BYTE OEMAPM_Flags;
    BYTE OEMAPM_Reserved6[3];
} OEM_APM_BYTE_REGS;

Contains values representing the values in the 8-bit CPU registers.


OEM_APM_DWORD_REGS

typedef struct _OEM_APM_DWORD_REGS {
    DWORD OEMAPM_EDI;
    DWORD OEMAPM_ESI;
    DWORD OEMAPM_EBP;
    DWORD OEMAPM_EBX;
    DWORD OEMAPM_EDX;
    DWORD OEMAPM_ECX;
    DWORD OEMAPM_EAX;
    DWORD OEMAPM_Reserved14;
} OEM_APM_DWORD_REGS;

Contains values representing the values in the 32-bit CPU registers.


OEM_APM_REGS

typedef union _OEM_APM_REGS {
    struct _OEM_APM_BYTE_REGS ByteRegs;
    struct _OEM_APM_WORD_REGS WordRegs;
    struct _OEM_APM_DWORD_REGS DwordRegs;
} OEM_APM_REGS;
typedef OEM_APM_REGS * LPOEM_APM_REGS;

Contains information about the CPU registers that can be used by OEM-specific APM functions. This structure is a representation in memory of the values of the CPU registers.


OEM_APM_WORD_REGS

typedef struct _OEM_APM_WORD_REGS {
    WORD OEMAPM_DI;
    WORD OEMAPM_Reserved7;
    WORD OEMAPM_SI;
    WORD OEMAPM_Reserved8;
    WORD OEMAPM_BP;
    WORD OEMAPM_Reserved9;
    WORD OEMAPM_BX;
    WORD OEMAPM_Reserved10;
    WORD OEMAPM_DX;
    WORD OEMAPM_Reserved11;
    WORD OEMAPM_CX;
    WORD OEMAPM_Reserved12;
    WORD OEMAPM_AX;
    WORD OEMAPM_Reserved13[3];
} OEM_APM_WORD_REGS;

Contains values representing the values in the 16-bit CPU registers.


POWER_STATUS

typedef struct _POWER_STATUS {
    BYTE PS_AC_Line_Status;
    BYTE PS_Battery_Status;
    BYTE PS_Battery_Flag;
    BYTE PS_Battery_Life_Percentage;
    WORD PS_Battery_Life_Time
} POWER_STATUS;

Contains information about the APM BIOS power status. With the exception of the BatteryLifeTime parameter, this information is structured identically to that specified in the APM 1.1 specification.

PS_AC_Line_Status
AC line status. Can be 00h for off-line, 01h for on-line, or 02h for on backup power (that is, on an uninterruptible power supply). It is 0FFh if the AC status is unknown. All other values are reserved.
PS_Battery_Status
Battery charge status. Can be 00h for high charge, 01h for low charge, 02h for critical, 03h for charging, and 0FFh for unknown status. All other values are reserved.
PS_Battery_Flag
Battery status. Can be a combination of 01h for high charge, 02h for low charge, 04h for critical, 08h for charging, and 080h for no system battery. all other bit values are reserved. This member is 0FFh if status is unknown.
PS_Battery_Life_Percentage
Percentage of Full Charge remaining. Can be a value in the range 0 to 100, or 0xFF if the battery life is unknown. All other values are reserved.
PS_Battery_Life_Time
Number of seconds of battery life remaining, or 0FFFFFFFFh if the life time is unknown.

When PS_AC_Line_Status is 02h (on backup power), the power status values apply to the system's backup battery.

Since PS_Battery_Flag and PS_Battery_Life_Time are not supported by an APM 1.0 BIOS, VPOWERD returns 0FFh and 0FFFFFFFFh in these fields when connected to an APM 1.0 BIOS. The PS_Battery_Flag value should be used preferentially over the PS_Battery_Status value. The PS_Battery_Status specifies only the most recently changed status item since the last call to the BIOS power status function and therefore is supported only for backward compatibility with older systems not capable of reporting the PS_Battery_Flag value.


Virtual Shell Device (SHELL)

The virtual shell device (SHELL) provides services that virtual devices use to display messages, resolve contention between devices, post Window messages to applications and VxDs, monitor changes to virtual machine properties, and carry out two-way communication with Windows-based applications or DLLs. This section describes the interfaces of the virtual shell device.


Application Time Events

Application time (also known as 'Appy time, a play on the words "Happy" and "Application") occurs when the system VM runs in the context of an application. At application time, VxDs can perform any operations that Windows-based applications can. For example, a VxD can load DLLs, link to exported functions, and call the functions.

The system does not automatically notify VxDs when application time occurs. To receive notification, you must use the _SHELL_CallAtAppyTime service to install a callback procedure. The system calls this procedure once and only once when application time next occurs. An arbitrary amount of time may elapse between the call to _SHELL_CallAtAppyTime and a call to the callback procedure. The system does not dispatch application time events while the critical section is held or while the system VM is blocked on any semaphores. There are no guarantees as to the order in which application time events are dispatched.

There are periods of time during which application time is not available, such as during system initialization and system shutdown. Application time may also be momentarily unavailable during the normal operation of the system. You can determine whether application time is available by using the _SHELL_QueryAppyTimeAvailable service. A zero return value means that application time events are not currently available. Even if application time is not available, you can still call _SHELL_CallAtAppyTime. In such cases, the system places the requested event on a queue and does not dispatch the event until application time becomes available. Application time never becomes available if system shutdown is in progress.

Although application time is not available during system initialization, you can still use _SHELL_CallAtAppyTime to request notification as soon as application time is available. This is especially useful for VxDs that need to carry out tasks while the graphical shell starts. For example, an accessibility VxD may use the ShellExecute function during application time to start a screen reader or magnifying glass application. This is important for users who would otherwise find the standard network logon dialog box inaccessible. (The system displays the network logon dialog box before it processes the Startup folder, so placing an accessibility application in the Startup folder does not solve the problem.)

You can cancel an application time event that has not yet been dispatched by using the _SHELL_CancelAppyTimeEvent service. The service requires either the handle of the event as returned by _SHELL_CallAtAppyTime or zero. Attempting to cancel a dispatched event can crash the system. To prevent crashes, most VxDs set the event handle to zero while processing the event. _SHELL_CancelAppyTimeEvent ignores calls in which the handle is zero.

When an application time event is dispatched, the following services are available:

_SHELL_CallDll

_SHELL_FreeLibrary

_SHELL_GetProcAddress

_SHELL_LoadLibrary

_SHELL_LocalAllocEx

_SHELL_LocalFree

These services are similar to the Windows functions having corresponding names. For example, the _SHELL_LoadLibrary service loads the given DLL and returns an instance handle that can be used to dynamically link to exported functions.


Two-way Communication

Two-way communication occurs when a VxD receives information from and sends information to a Windows application. A 16-bit application can send information to a VxD by calling the protected-mode API procedure for the VxD. Use Get Device Entry Point Address (Interrupt 2Fh Function 1684h) to retrieve the address of this procedure. A Win32 application can use the DeviceIOControl function to communicate with a VxD.

A VxD can send information to an application by using a variety of shell services. For example, a VxD can use the services associated with appy time events, such as _SHELL_CallDll, to call a DLL and pass it data. A VxD can also use services such as _SHELL_BroadcastSystemMessage and _SHELL_PostMessage, to post messages to the queues of one or more Windows-based applications.

The _SHELL_BroadcastSystemMessage service is a convenient way to send a window message to a list of recipient windows. A VxD can also intercept these broadcast messages by installing a callback procedure using the _SHELL_HookSystemBroadcast service. The system calls the procedure whenever the _SHELL_BroadcastSystemMessage is called. The _SHELL_UnhookSystemBroadcast service removes the callback procedure.

The _SHELL_PostMessage service calls the Windows PostMessage function. If a VxD calls the _SHELL_PostMessage service when the current VM is not the system VM, the system schedules the message and does not actually post the message until the system VM receives CPU time. If the current VM is the system VM, the system may call the PostMessage function immediately.

When the call to PostMessage is actually made, the system notifies the VxD of the message result by calling a callback procedure specified by the VxD when it called _SHELL_PostMessage. The VxD must be prepared for failure at two points: immediate failure returned by _SHELL_PostMessage and eventual failure passed to the callback procedure.

If the current VM is the system VM, the system may call the callback procedure before _SHELL_PostMessage returns. To prevent this, use the SPM_UM_AlwaysSchedule value in the uMsg parameter.

Do not make multiple, successive calls to _SHELL_PostMessage. This can fill up the message queue of the window and exhaust available memory.

Do not block the system VM while waiting for the PostMessage function callback. This will deadlock the system.


VM Properties

You can use the SHELL_Hook_Properties service to install a callback procedure to monitor changes the user makes to VM properties. The SHELL_Unhook_Properties service removes the callback procedure when you no longer need to monitor changes.


Miscellaneous

The miscellaneous services let you carry out tasks such as starting applications and checking for user activity. There are the following miscellaneous services:

_SHELL_ShellExecute

SHELL_Update_User_Activity


Shell Service API

The shell services API let applications use the shell VxD to carry out useful tasks, such as enumerating the property groups associated with a given virtual machine.


Reference

This section provides detailed reference information for the shell services. The information is separated into the following functional groups.

Group | Elements
Windows 3.x Compatible | SHELL_Event, SHELL_Get_Version, SHELL_Message, SHELL_Resolve_Contention, SHELL_SYSMODAL_Message
Application Time Events | _SHELL_CallAtAppyTime, _SHELL_CallDll, _SHELL_CancelAppyTimeEvent, _SHELL_FreeLibrary, _SHELL_GetProcAddress, _SHELL_LoadLibrary, _SHELL_LocalAllocEx, _SHELL_LocalFree, _SHELL_QueryAppyTimeAvailable
Two-way Communication | _SHELL_BroadcastSystemMessage, _SHELL_HookSystemBroadcast, _SHELL_PostMessage, _SHELL_PostShellMessage, _SHELL_UnhookSystemBroadcast
VM Properties | SHELL_Hook_Properties, SHELL_Unhook_Properties
Miscellaneous | _SHELL_ShellExecute, SHELL_Update_User_Activity
Shell Service API | SHSV_Enumerate_Properties, SHSV_Get_Version, SHSV_GiveSYSVMfocus, SHSV_Install_New_Task_Manager, SHSV_Set_ScreenSaver_Info, SHSV_Update_Properties, SHSV_WinExec, SHSV_WinExecWait


Windows 3.x Compatible Services

The following topics describe the compatible services.


SHELL_Event

include shell.inc
mov ebx, Handle                  ; virtual machine handle
mov ecx, Event                   ; event number
mov ax, wParam                   ; word parameter for event
mov esi, OFFSET32 Callback       ; address of event callback proc
mov edx, OFFSET32 ReferenceData  ; reference data for the callback
VxDcall SHELL_Event

jc  error
mov [EventHandle], eax           ; event handle only if callback is used

Posts an event in the Windows shell to WINOLDAPP. Uses EAX and Flags.

  • Clears the carry flag if the event is placed in the queue. If a event callback procedure is given, the EAX register contains the handle of the event. The carry flag is set to indicate an error, such as the WINOLDAPP is not present or there is insufficient memory for placement.
Handle
Virtual machine handle for the event.
Event
Event number.
wParam
16-bit parameter value for the event. The high 16 bits specify the special boost flags.
Callback
Address of the callback procedure for the event. If this parameter is zero, no callback procedure is called. For more information about the callback procedure, see the comments section.
ReferenceData
Address of reference data for the event callback procedure.

The system calls the callback procedure with the following input parameters:

mov edx, ReferenceData    ; points to reference data
mov ebp, ClientReg        ; points to a WINOLDAPP Client_Reg_Struc frame
call [Callback]

If the carry flag is clear on entry, the event was processed and the EBP register points to a Client_Reg_Struc structure containing the register values after the event returned. If the carry flag is set, the event could not be placed in the queue and only the EDX register contains valid data. In both cases, the EBX register does not contain a virtual machine handle.


SHELL_Get_Version

include shell.inc
VxDcall SHELL_Get_Version
jc  error
mov [Major], ah
mov [Minor], al

Returns the version number for the virtual shell device. Uses EAX and Flags.

  • Clears the carry flag, copies the major version number to the AH register and the minor version number to AL.


SHELL_GetVMInfo

include shell.inc
mov ebx, Handle   ; virtual machine handle
VxDcall SHELL_GetVMInfo

mov [hwnd], dx    ; WinOldAp window handle for VM
mov [Flags], eax  ; flags for virtual machine

Retrieves PIF information settings for a virtual machine. This service is only available for Windows version 3.1 and later. Uses EAX, ECX, EDI, EDX, ESI, and Flags.

  • Sets the DX register to the handle of the WinOldAp window corresponding to the VM and sets the EAX register to one or more of these flag values:
SGVMI_ALTENTERdis | ALT+ENTER is reserved.
SGVMI_ALTESCdis | ALT+ESC is reserved.
SGVMI_ALTPRTSCdis | ALT+PRTSC is reserved.
SGVMI_ALTSPACEdis | ALT+SPACEBAR is reserved.
SGVMI_ALTTABdis | ALT+TAB is reserved.
SGVMI_ClsExit | Close on exit enabled.
SGVMI_CTRLESCdis | CTRL+ESC is reserved.
SGVMI_EMS_Lock | EMS hands locked.
SGVMI_FastPaste | Allow fast paste enabled.
SGVMI_HasHotKey | Has a shortcut key.
SGVMI_NoHMA | No HMA.
SGVMI_Polling | Polling detection enabled.
SGVMI_PRTSCdis | PRTSC is reserved.
SGVMI_V86_Lock | V86 memory locked.
SGVMI_Windowed | The virtual machine runs in a window.
SGVMI_XMS_Lock | XMS hands locked.

The undefined bits in the EAX register are reserved. Do not depend on them being zero. The high 16 bits of the EDX register are reserved.

Handle
Handle of the virtual machine to examine.

This service is not valid until after all virtual devices have processed the Create_VM message. This service if called during a Create_VM message will not return proper PIF information. The ECX, EDX, ESI, and EDI register contents are reserved.


SHELL_Message

include shell.inc
mov ebx, Handle             ; virtual machine handle
mov eax, Flags              ; message box flags
mov ecx, OFFSET32 Message   ; address of message text
mov edi, OFFSET32 Caption   ; address of caption text
mov esi, OFFSET32 Callback  ; address of callback
mov edx, ReferenceData      ; reference data for callback
VxDcall SHELL_Message

jc  error
or eax, eax                 ; nonzero if success

Displays a message box using the Windows shell. Uses EAX and Flags.

  • Clears the carry flag and sets the EAX register to a nonzero value if successful. Otherwise, sets the carry flag to indicate an error such as insufficient memory to display the message.
Handle
Handle of the virtual machine responsible for the message.
Flags
Message box flags. See the MB_ symbols in the SHELL.INC file.
Message
Address of a null-terminated string containing the message text.
Caption
Address of a null-terminated string containing the caption text. If this parameter is zero, the service uses the standard caption. If this parameter points to an empty string, the message box has no caption.
Callback
Address of the callback procedure to process the user's response when the message box returns. If this parameter is zero, no callback procedure is called.
ReferenceData
Reference data to pass to the callback procedure.

The strings pointed to by the ECX and EDI registers must remain valid until the callback procedure is called. In other words, the memory for those strings should not be freed until the callback is made.

The system calls the callback procedure after the user closes the message box. The callback receives the following input parameters:

mov eax, Response       ; response code from the message box
mov edx, ReferenceData  ; points to reference data
call [Callback]

The response code in the EAX register is one of the ID symbols defined in the SHELL.INC file. The EBX register may or may not contain the current virtual machine handle when the callback is called. The callback must not rely on its value. If this service returns an error, a virtual device can use the SHELL_SYSMODAL_Message service to force the system to display a message.


SHELL_Resolve_Contention

include shell.inc
mov eax, OwnerHandle  ; virtual machine handle of device owner
mov ebx, OtherHandle  ; virtual machine handle of contender
mov esi, OFFSET32 DeviceName  ; address of device name
VxDcall SHELL_Resolve_Contention

jc  cannot_resolve
mov [WinnerHandle], ebx  ; virtual machine handle of new owner

Resolves contention for the MS-DOS shell. Uses EBX and Flags.

  • Clears the carry flag and copies the virtual machine handle of contention winner to the EBX register if successful. Otherwise, sets the carry flag to indicate that contention could not be resolved.
OwnerHandle
Handle of virtual machine of the current device owner.
OtherHandle
Handle of the contending virtual machine. This parameter must identify the current virtual machine.
DeviceName
Address of an 8-byte string identifying the name of the device in contention. The name must be in uppercase letters, and be padded with spaces if necessary. This string must remain valid until SHELL_Resolve_Contention returns.


SHELL_SYSMODAL_Message

include shell.inc
mov ebx, Handle            ; virtual machine handle
mov eax, Flags             ; message box flags
mov ecx, OFFSET32 Message  ; address of message
mov edi, OFFSET32 Caption  ; address of caption
VxDcall SHELL_SYSMODAL_Message

mov [Response], eax        ; response code from message box

Displays a system modal message box in the Windows shell. Uses EAX and Flags.

  • Returns the response code from the message box in the EAX register. A response code can be one of the ID symbols defined in the SHELL.INC file.
Handle
Specifies the handle of the virtual machine responsible for the message.
Flags
Specifies the message box flags. See the MB_ symbols in the SHELL.INC file. The MB_SYSTEMMODAL value must be given.
Message
Address of a null-terminated string specifying the message text.
Caption
Address of a null-terminated string specifying the caption text. If this parameter is zero, the service uses the standard caption. If this parameter points to an empty string, the message box has no caption.

The strings pointed to by the ECX and EDI registers must remain valid until SHELL_Sysmodal_Message returns.


Application Time Events

The following topics describe the application time events.


_SHELL_CallAtAppyTime

include shell.inc
VxDcall _SHELL_CallAtAppyTime, <<OFFSET32 pfnCallback>,
    dwRefData, dwFlags, dwTimeout>
cmp eax, 0
je  error
mov [EventHandle], eax  ; application time event handle

Installs a callback procedure for an application time event. Uses C calling conventions.

  • Returns the handle of the application time event in the EAX register if successful. Otherwise, returns zero indicating insufficient memory.
pfnCallback
Address of the callback procedure to be called when the system VM reaches the application time state. For more information about the procedure, see the comments below.
dwRefData
Reference data to pass to the callback procedure.
dwFlags
Event flag. Can be one of these values:
CAAFL_RING0 | Ring zero event.
CAAFL_TIMEOUT | Time out the event after the duration specified by dwTimeout.

dwTimeout
Time out duration.

This is an asynchronous service.

The system calls the callback procedure whenever the system VM is in a quiet state. The system calls the procedure using the C calling conventions as follows:

cCall [pfnCallback], <dwRefData, dwFlags>

The dwRefData parameter is the same value passed to the _SHELL_CallAtAppyTime service. No return value is required. The dwFlags parameter is a bitmask of flags describing the conditions under which the callback procedure is made. If the CAAFL_TIMEOUT bit is set, the timeout duration elapsed before application time could be reached, in which case the system is not at application time, and you cannot use application-time-only services. All other bits of dwFlags are reserved.

If application time is not currently available, the event is scheduled for a time when application time is available. If application time never becomes available (for example, if the application time event is scheduled while the system is shutting down), the event is never dispatched.


_SHELL_CallDll

include shell.inc
VxDcall _SHELL_CallDll, <<OFFSET32 lpszDll>, <OFFSET32 lpszProcName>,\
    cbArgs, <OFFSET32 lpvArgs>>
mov [ReturnValue], eax

Loads the given 16-bit library, creates a dynamic link to the given function, thunks the function arguments, and calls the function at ring 3. After return from the function, this service frees the library.

  • Returns the value returned from the function if successful. Otherwise, returns zero to indicate an error, such as unable to link to function. If the service can not load the given library, it returns a value range 0 through 31 to indicate the error.
lpszDll
Address of a null-terminated string specifying the filename of the DLL to load, or zero to indicate that lpszProcName is a 16:16 raw address.
lpszProcName
Address of a null-terminated string specifying the name of the function to call, or the ordinal of the function to call, or a raw 16:16 address to call. See the following comments for additional information .
cbArgs
Number of bytes of arguments to pass.
lpvArgs
Address of buffer that contains the function arguments. The arguments must be placed in the buffer in the same order as they are pushed on the ring 3 stack. This order depends on whether the function being called uses PASCAL or C calling conventions. The size, in bytes, of each argument must be as required by the function being called.

This service may be called only during application time. Failure to observe this restriction may crash the system. This service is capable of calling only 16-bit DLLs.

The procedure being called must conform to the C or PASCAL calling conventions. Parameters must be accepted on the stack, not in registers; register contents on entry to the procedure are undefined. The procedure must preserve the SI, DI, and BP registers.

If the lpszDll parameter is zero, the lpszProcName is treated as a raw 16:16 pointer with the selector in the high word and the offset in the low word. The procedure at the indicated address is called, with the parameters pushed as in the normal case. This is the only way 16-bit code should be called at application time. Do not attempt to use Begin_Nest_Exec at application time, because it will crash the machine if a timer tick comes in at the wrong time. Do not use the _CallRing3 service because it may crash the machine if the Windows 16-bit memory manager has performed a GlobalCompact.

The following simple example illustrates the basic idea of the _SHELL_CallDll service.

/* PASCAL calling convention passes arguments backwards */
struct tagEXITWINDOWARGS {
    WORD  wReserved;
    DWORD dwReturnCode;
} ewa = { 0, EW_REBOOTWINDOWS };
SHELL_CallDll("USER", "EXITWINDOWS", sizeof(ewa), &ewa);

The following example illustrates how a string parameter can be passed, as well as calling the target DLL by ordinal rather than by name:

#define ordWinExec  166
/* PASCAL calling convention passes arguments backwards */
struct tagWINEXECARGS {
....WORD  nCmdShow;
....DWORD lpszCmdLine;
} wea = { SW_NORMAL, 0 };

wea.lpszCmdLine = SHELL_LocalAllocEx(LPTR + LMEM_STRING, 0,
    "MyProg.exe");
SHELL_CallDll("KERNEL", ordWinExec, sizeof(wea), &wea);
SHELL_LocalFree(wea.lpszCmdLine);

The following example illustrates how raw 16:16 addresses can be called. This is handy if the address didn't come from a DLL, but was registered by an application. It is also handy if you will be calling into your DLL many times in quick succession, because the normal _SHELL_CallDll loads the library, calls the function, and then frees it. Each LoadLibrary loads the DLL from the disk anew, wasting time with disk I/O. Instead, load it once, do all the calls, and then free it when done.

HINSTANCE hinst;
FARPROC lpfnMyFunction;

struct tagMYFUNCTIONARG {
    WORD wParam;
} mfa = { 0 };

hinst = SHELL_LoadLibrary("MYDLL");
if (hinst < 32) return ERROR;
lpfnMyFunction = SHELL_GetProcAddress(hinst, "MYFUNCTION");
if (lpfnMyFunction == 0) {
    SHELL_FreeLibrary(hinst); return ERROR;
}

/* Now call MyFunction three times with arg 0, 1, and 2. */
mfa.wParam = 0;
SHELL_CallDll(0, lpfnMyFunction, sizeof(mfa), &mfa);

mfa.wParam = 1;
SHELL_CallDll(0, lpfnMyFunction, sizeof(mfa), &mfa);

mfa.wParam = 2;
SHELL_CallDll(0, lpfnMyFunction, sizeof(mfa), &mfa);

/* Finished. Free the library. */
SHELL_FreeLibrary(hinst);
return OK;

There is no way to distinguish between a DLL function that happened to return a value in the range 0 through 31 from the inability to load the DLL. If such fine control is necessary, you should use the method described in the third example.


_SHELL_CancelAppyTimeEvent

include shell.inc
VxDcall _SHELL_CancelAppyTimeEvent, <EventHandle>

Cancels subsequent calls to the callback procedure associated with the given application time event handle. Uses C calling conventions.

  • No return value.
EventHandle
Handle of the application time event to cancel. The handle must have been previously returned by the _SHELL_CallAtAppyTime service.

This is not an asynchronous service.

For convenience, zero is a valid parameter value, in which case the service does nothing and returns immediately.


_SHELL_FreeLibrary

include shell.inc
VxDcall SHELL_FreeLibrary, <Handle>

Frees the given 16-bit library, removing it from memory if the reference count decrements to zero. This service is a thunk for the FreeLibrary function. Use C calling conventions.

  • No return value.
Handle
Instance handle returned from a previous call to the SHELL_LoadLibrary service.

This service may be called only during application time. Failure to observe this restriction may crash the system.


_SHELL_GetProcAddress

include shell.inc
VxDcall SHELL_GetProcAddress, <Handle, <OFFSET32 lpszProcName>>
mov [ProcAddress], eax

Retrieves the address of a function exported by the given 16-bit library. Uses C calling conventions.

  • Returns the 16:16 address of the function if successful. Otherwise, returns zero.
Handle
Instance handle returned from a previous call to the SHELL_LoadLibrary service.
lpszProcName
Address of a null-terminated string specifying the name of the function or the ordinal for the function. If an ordinal is given, the ordinal must be in the low 16 bits; the high 16 bits must be zero.

This service may be called only during application time. Failure to observe this restriction may crash the system.


_SHELL_LoadLibrary

include shell.inc
VxDcall SHELL_LoadLibrary, <<OFFSET32 lpszDll>
mov [Handle], eax

Loads the given 16-bit library. This service is a thunk for the LoadLibrary function. Use C calling conventions.

  • Returns a handle to instance of library if successful. Otherwise, returns an error value in the range 0 through 31. These are the same error values as for the 16-bit LoadLibrary function.
lpszDll
Address of a null-terminated string specifying the filename of the DLL to load.

This service may be called only during application time. Failure to observe this restriction may crash the system. This service is capable of loading only 16-bit DLLs.


_SHELL_LocalAllocEx

include shell.inc
VxDcall SHELL_LocalAllocEx, <fl, cb, <OFFSET32 lpvBuf>>
mov [Handle], eax
mov [LinearAddress], edx

Allocates memory from the local heap of the message server application. Uses C calling conventions.

  • Returns the 16:16 address of the allocated block in the EAX register and a 32-bit linear address in the EDX register if successful. Otherwise, returns zero in both EAX and EDX.
fl
Flags. Can be a combination of these values:
LMEM_ZEROINIT | Fill block with zeroes.
LMEM_FIXED | Allocate non-moveable memory.
LPTR | Same as LMEM_ZEROINIT and LMEM_FIXED.
LMEM_STRING | Allocate a block having the same size in bytes as a null-terminated string. The cb parameter must be zero and lpvBuf must be the address of the null-terminated string.

Do not use LMEM_MOVEABLE or LMEM_DISCARDABLE.

cb
Size of block to allocate, in bytes.
lpvBuf
Address of buffer containing initialization data or NULL if no initialization is needed. The contents of this buffer will be copied into ring 3.

This service may be called only during application time. Failure to observe this restriction may crash the system.

The message server application runs without a window on the Windows desktop. VxDs should be frugal with the use of this memory since it is a limited resource. Because Windows moves segments, the 32-bit linear address returned in EDX becomes invalid as soon as control is given to the Windows memory manager. The 16:16 pointer remains valid however.


_SHELL_LocalFree

include shell.inc
VxDcall SHELL_LocalFree, <Handle>

Frees the memory that was allocated by SHELL_LocalAllocEx. Uses C calling conventions.

  • No return value.
Handle
Handle of block of memory previously allocated by the SHELL_LocalAllocEx service. The handle must be the value previously returned in the EAX register by _SHELL_LocalAllocEx.

This service may be called only during application time. Failure to observe this restriction may crash the system.


_SHELL_QueryAppyTimeAvailable

include shell.inc
VxDcall _SHELL_QueryAppyTimeAvailable
or eax, eax
jz not_available

Specifies whether application time events are available to VxDs. Application time events are available only after Windows initializes; they cease to be available when Windows begins to shutdown or if the message server GP faults. Uses C calling conventions.

  • Returns nonzero in the EAX register if application time events are available. Otherwise, returns zero.

This is an asynchronous service.

This service does not specify whether the system is currently in an appy-time state. The message server may GP fault if a call to the CallRing3 service by a VxD GP faults. Under such conditions, application time is permanently disabled until the system shuts down and restarts.


_SHELL_BroadcastSystemMessage

include shell.inc
VxDcall SHELL_BroadcastSystemMessage, <dwFlags, \
    <OFFSET32 lpdwRecipients>, uMsg, wParam, lParam>

mov [Result], eax  ; 1 if success, 0 if some recipients failed
                   ;   broadcast, -1 if broadcast failed

Broadcasts a message to a specified list of top-level windows and devices. This is a ring 0 version of the Windows BroadcastSystemMessage function. Use C calling conventions.

  • Returns one of these values in the EAX register:
0 | At least one recipient returned FALSE from the broadcast message.
1 | All components returned TRUE from the broadcast message.
-1 | The message could not be broadcast. Indicates an error, such as unable to allocate a selector alias for the lParam buffer or the broadcast was attempted at an inappropriate time.

dwFlags
Flags identifying the kind of broadcast to perform. See BroadcastSystemMessage() in the Win32 SDK for a list of valid values.
lpdwRecipients

Pointer to a variable that contains and receives information about the recipients of the message. See BroadcastSystemMessage() in the Win32 SDK for a list of valid values. When the function returns, this variable receives a combination of these values identifying which recipients actually received the message. If this parameter is NULL, the function broadcasts to all recipients.

.

uMsg
Message number. The high 16 bits must be zero.
wParam
16-bit message parameter in the low 16 bits. The high 16 bits must be zero. Valid values for wParam depend on the message number in uMsg.
lParam
32-bit message parameter. The value of lParam depends on the message number in uMsg.

If Windows is active, the SHELL_BroadcastSystemMessage service can be called only during an application time event. Windows is active if application time is available; use the SHELL_QueryAppyTimeAvailable service to determine whether application time is available. If Windows is not active, SHELL_BroadcastSystemMessage sends the broadcast message only to VxDs. Attempting to broadcast a system message at an inappropriate time may result in unpredictable behavior on the part of the system.


_SHELL_HookSystemBroadcast

include shell.inc
VxDcall SHELL_HookSystemBroadcast, <<OFFSET32 pfnHandler>, \
    dwRef, dwCallOrder>
mov [Handle], eax  ; handle of broadcast callback procedure

Installs a callback procedure into the broadcast notification chain. The chain monitors calls to the _SHELL_BroadcastSystemMessage service and to the Windows BroadcastSystemMessage function. Uses C calling conventions.

  • Returns the handle of the installed callback procedure in the EAX register if successful. Otherwise, returns zero.
pfnHandler
Address of the callback procedure. For more information about the procedure, see the comments below.
dwRef
Reference data for the callback procedure.
dwCallOrder
Call order. Must be zero for non-zero virtual devices. If more than one callback procedure is installed to monitor the broadcast service, the call order specifies the order in which the given callback procedure is called relative to the other callback procedures. Procedures with equal call orders are called in an unspecified (but consistent) order.

The system calls the callback procedure whenever a VxD calls the _SHELL_BroadcastSystemMessage service. The system calls the procedure using the C calling conventions as follows:

VxDcall [pfnHandler], <uMsg, wParam, lParam, dwRef>

The uMsg parameter is the message number and wParam is the 16-bit message parameter. For both uMsg and wParam, the low 16 bits contain the parameter value and the high 16 bits are reserved. The lParam parameter is the 32-bit message parameter and dwRef is the same reference data value passed to _SHELL_HookSystemBroadcast.

The return value from the callback procedure is ignored if the broadcast is not a BSF_QUERY. Otherwise, the procedure should return a nonzero value to allow the broadcast to continue, or zero to fail the message and halt the broadcast. The procedure should return 1 for any messages it does not understand.

If the callback procedure is installed while a broadcast in progress, it is unspecified whether the hook will receive that broadcast. It will, regardless, receive all subsequent broadcasts.


_SHELL_PostMessage

include shell.inc
VxDcall _SHELL_PostMessage, <hwnd, uMsg, wParam, lParam, \
    <OFFSET32 pfnCallback>, dwRefData>
or   eax, eax
jz   not_posted

Schedules a message for posting to the given window and optionally installs a callback procedure to be notified when the PostMessage function actually posts the message. Uses C calling conventions.

  • Returns nonzero in the EAX register if successful. Otherwise, returns zero indicating an error such as insufficient memory.
hwnd
Handle of a window. The upper 16 bits are reserved and must be zero.
uMsg
Message value in the lower 16-bits. The upper 16 bits contain scheduling information and can be one of these values:
SPM_UM_DoNotWaitForCrit | Do not wait for the critical section to become free before posting the message.
SPM_UM_AlwaysSchedule | Always schedule the postmessage event. See comments below.

If WM_NULL (0) is given in the lower 16 bits, the service does not post a message but does call the callback procedure indicating success.

wParam
16-bit message parameter in the lower 16-bits. The upper 16 bits are reserved and must be zero.
lParam
32-bit message parameter.
pfnCallback
Address of the callback procedure to call when the message has been posted. This parameter can be zero if no callback is needed. For more information about the procedure, see the comments below.
dwRefData
Reference data for the callback procedure.

The system calls the callback procedure when the PostMessage function successfully posts the message into the queue of the given window. The system calls the procedure using the C calling conventions as follows:

cCall [pfnCallback], <dwRc, dwRefData>

The dwRefData parameter is the same value as passed to _SHELL_PostMessage. The dwRc parameter is the value returned by the PostMessage function. If this parameter is nonzero, the message was posted; otherwise, it was not posted.

When the callback procedure receives control, the system VM has been boosted by High_Pri_Device_Boost.


_SHELL_PostShellMessage

include shell.inc
VxDcall _SHELL_PostShellMessage, <wParam, lParam>

Posts a message to the current shell window. Uses C calling conventions.

  • No return value.
wParam
Lower 16 bits contain wParam. Upper 16 bits are reserved and must be zero.
lParam
32-bit lParam.

Do not make multiple, successive calls to _SHELL_PostShellMessage. This can fill up the message queue of the window and exhaust available memory.


_SHELL_UnhookSystemBroadcast

include shell.inc
VxDcall SHELL_UnhookSystemBroadcast, <Handle>

Removes a callback procedure from the broadcast notification chain. Uses C calling conventions.

  • No return value.
Handle
Handle of callback procedure to remove. This handle must have been previously returned by the _SHELL_HookSystemBroadcast service. For convenience, zero is a valid parameter value, in which case the service does nothing and returns immediately.


VM Properties

The following topics describe the VM properties.


SHELL_Hook_Properties

mov eax, GroupID            ; property group identifier
mov edx, OFFSET32 DllName   ; address of property group DLL
mov esi, OFFSET32 Callback  ; address of callback procedure
VxDcall  SHELL_Hook_Properties

jc   error

Installs a callback procedure that monitors changes to the properties of virtual machines. The GroupID parameter identifies what group of property data the procedure is associated with. The system calls the procedure simply to notify it of changes the user has made to properties associated with a new or existing VM. This means the procedure can examine the property data but cannot make changes. Uses EAX, ECX, EDX, and Flags.

  • Clears the carry flag if successful. Otherwise, sets the carry flag to indicate an error, such as invalid property identifier or insufficient memory.
GroupID
Property group identifier. Can be either a valid group ordinal, such as GROUP_TASK (as defined in PIF.H), or the address of a null-terminated string specifying the name of a custom PIF group. The string must not be longer than PIFEXTSIGSIZE (16) characters, including the terminating null character.
DllName
Address of a null-terminated string specifying the name of the property group DLL. This parameter can be NULL if no DLL exists.
Callback
Address of the callback procedure. For more information about the procedure, see the comments below.

If addresses are given for the GroupID and DllName parameters, the addresses must remain valid for the duration of system operation.

The system calls the callback procedure immediately after Create_VM processing and whenever the properties for a existing VM are changed. The system calls the procedure as follows:

mov ebx, Handle            ; virtual machine handle
mov edx, OFFSET32 Data     ; address of property data
mov edi, OFFSET32 Ordinal  ; address of property ordinal
call [Callback]

The Handle parameter is the handle of the virtual machine being changed. The Data parameter is the address of the property data associated with the virtual machine. The Ordinal parameter is the address of a 32-bit variable that contains the property ordinal. If the property ordinal is zero, the variable is immediately followed by a null-terminated string specifying the name of the property group. No name is given if the ordinal is not zero. The callback requires no return value.


SHELL_Unhook_Properties

include shell.inc
mov eax, GroupID  ; property group identifier
mov esi, OFFSET32 Callback  ; address of callback procedure
VxDcall SHELL_Unhook_Properties

jc  error

Removes the callback procedure from association with the given property group. Uses EAX, ECX, EDX, and Flags.

  • Clears the carry flag if successful. Otherwise, sets the carry flag to indicate an error such as an invalid property identifier.
GroupID
Property group identifier. Can be NULL, a valid group ordinal such as GROUP_TASK (as defined in PIF.H), or the address of a null-terminated string specifying the name of a custom PIF group. If GroupID is NULL, the service checks all property groups and removes the callback procedure from each group it is associated with.
Callback
Address of the callback procedure. For more information about the procedure, see SHELL_Hook_Properties.


_SHELL_ShellExecute

include shell.inc
VxDcall _SHELL_ShellExecute, <ShexPacket>

Opens the file specified in the shex_ibFile member of the SHEXPACKET structure. The _SHELL_ShellExecute service calls the Windows ShellExecute function. Uses C calling conventions.

  • Return the value from the Windows ShellExecute function in the EAX register.
ShexPacket
Flat pointer to a SHEXPACKET structure.

This is an application-time-only service.

Note The SHEXPACKET contains no pointers. All pointer-like values are byte offsets from the start of the packet. For example, the name of the file to be opened is stored at ShexPacket + ibFile.


SHELL_Update_User_Activity

include shell.inc
VxDcall SHELL_Update_User_Activity

Notifies the shell VxD that user input has occurred. This information is used to determine whether the user is actively using the system, which controls things such as the screen saver.

  • No return value.

This is an asynchronous service.

This service is intened to be called by virtual devices that handle user input, such as the virtual mouse device (VMD) and virtual keyboard device (VKD). A graphics tablet driver, for example, can call this service when it detects activity on the tablet, so that the screen saver does not interrupt a user who is in the middle of using the tablet.


SHEXPACKET STRUC

shex_dwTotalSize  DD  ?
shex_dwSize       DD  ?
shex_ibOp         DD  ?
shex_ibFile       DD  ?
shex_ibParams     DD  ?
shex_ibDir        DD  ?
shex_ibEnv        DD  ?
shex_nCmdShow     DD  ?
rgchBaggage       DB  ? dup (?) ; variable-sized field
SHEXPACKET ENDS
shex_dwTotalSize
Size in bytes of the SHEXPACKET structure plus the size of optional information in the rgchBaggage member.
shex_dwSize
Must be equal to the size of the SHEXPACKET structure, not including the rgchBaggage.
shex_ibOp
Operation to perform. Specify 0 to open the file. Any other value is a relative offset from the pointer to this structure to a null-terminated string naming the operation to perform.
shex_ibFile
File to open or print. This is a relative offset from the pointer to this structure to a null-terminated string naming the file.
shex_ibParams
Optional parameters passed to the application when the shex_ibFile member specifies an executable file. The parameters are a relative offset from the pointer to this structure to a null-terminated string. Specify zero if there are no optional parameters or if shex_ibFile specifies a document file.
shex_ibDir
Working directory. If zero, the Windows directory will be used as the working directory. Otherwise, it is a relative offset from the pointer to this structure to a null-terminated string.
shex_ibEnv
Environment block to pass to the program. If zero, the master environment will be given to the program. Otherwise, it is a relative offset from the pointer to this structure to an environment block. This field is ignored for MS-DOS-based applications, which will always receive a copy of the master environment.
shex_nCmdShow
How the application window is to be shown. Refer to the documentation for the Windows function ShowWindow for valid values.
shex_rgchBaggage
Optional variable-length information. The rgchBaggage member contains the optional null-terminated strings for the shex_ibOp, shex_ibFile, shex_ibParams, shex_ibDir, and shex_ibEnv members. Those members contain relative offsets to the appropriate string in the shex_rgchBaggage member.


Virtual Timer API

The virtual timer device virtualizes the hardware timer. The device provides services that applications can use to set the interrupt rate for the timer. This section describes the application programmer interface of the virtual timer device (VTDAPI).


Calling VTDAPI Functions

The VTDAPI provides services for ring 3 components. To obtain the VTDAPI entry point, an application must first call Get Device Entry Point Address (Interrupt 2Fh Function 1684h). For example:

include vtdapi.inc

mov ax, 1684h             ; Get Device Entry Point
mov bx, VTDAPI_DEVICE_ID  ; device identifier
xor di, di                ; initialize di
mov es, di                ; initialize es
int 2Fh                   ; multiplex interrupt

mov [VTDAPI_Addr], di
mov [VTDAPI_Addr+2], es       ; es:di contains entry point address
cmp VTDAPI_Addr, 0
jz  NotInstalled


Reference

The VTDAPI provides the following services:

VTDAPI_Begin_Min_Int_Period

VTDAPI_End_Min_Int_Period

VTDAPI_Get_Int_Period

VTDAPI_Get_Sys_Time

VTDAPI_Get_System_Time_Selector

VTDAPI_Get_Version

VTDAPI_Start_User_Timer

VTDAPI_Stop_User_Timer

VTDAPI_Timer_Start

VTDAPI_Timer_Stop


VTDAPI_Begin_Min_Int_Period

; Obtain the entry point address in VTDAPI_Addr
mov cx, InterruptPeriod
mov ax, VTDAPI_Begin_Min_Int_Period
call VTDAPI_Addr

Sets the minimum interrupt period being used globally. Performs boundary checking on the structure elements passed, and uses VTD to set the minimum timer interrupt period.

  • Returns TIMERR_NOERROR in AX if successful, otherwise returns TIMERR_NOCANDO.
InterruptPeriod
The requested interrupt period in milliseconds.


VTDAPI_End_Min_Int_Period

; Obtain the entry point address in VTDAPI_Addr
mov ax, VTDAPI_End_Min_Int_Period
call VTDAPI_Addr

Clears the minimum interrupt period being used by Windows 95 which was previously set by a call to VTDAPI_Begin_Min_Int_Period.

  • Returns TIMERR_NOERROR in AX if successful, otherwise returns TIMERR_NOCANDO which usually means this request was not matched by a call to VTDAPI_Begin_Min_Int_Period.


VTDAPI_Get_Int_Period

; Obtain the entry point address in VTDAPI_Addr
mov ax, VTDAPI_Get_Int_Period
call VTDAPI_Addr

Retrieves the current minimum interrupt period being used globally.

  • Returns the current minimum period in milliseconds as a double-word in DX:AX.


VTDAPI_Get_Sys_Time

; Obtain the entry point address in VTDAPI_Addr
mov ax, VTDAPI_Get_Sys_Time
call VTDAPI_Addr

Retrieves the current system time.

  • Returns the current system time in milliseconds as a double-word in DX:AX.


VTDAPI_Get_System_Time_Selector

; Obtain the entry point address in VTDAPI_Addr
mov ax, VTDAPI_Get_System_Time_Selector
call VTDAPI_Addr

Retrieves the number of milliseconds since the system was started or restarted. Meaningful only in protected mode.

  • Returns in AX a read-only selector to a double-word that contains the number of milliseconds since the system was started if successful; otherwise returns zero.


VTDAPI_Get_Version

include vtdapi.inc

; Obtain the entry point address in VTDAPI_Addr
mov bx, SEG RequestStruc
mov es, bx
mov bx, OFFSET RequestStruc
mov ax, VTDAPI_Get_Version
call VTDAPI_Addr

Retrieves the version number of the driver, the shortest interrupt period supported by the hardware, the longest interrupt period supported by the driver. Uses Flags, EAX, EDI.

  • Returns TRUE in AX and RequestStruc is filled in with information about the driver if successful; otherwise returns FALSE.
RequestStruc
Address of Request structure which has the following form:
Request Struc
    DAPI_Version       dd
    VTDAPI_Min_Period  dd
    VTDAPI_Max_Period  dd
Request Ends


VTDAPI_Start_User_Timer

; Obtain the entry point address in VTDAPI_Addr
mov di, SEG TimerParams
mov es, di
mov bx, OFFSET TimerParams
mov ax, VTDAPI_Start_User_Timer
call VTDAPI_Addr

mov word ptr [Timer_ID+2], dx
mov word ptr [Timer_ID], ax

Starts the timer and register a timer callback to be called at periodic intervals. Limited to 32 timers.

  • Returns a 32-bit handle to the timer.
TimerParams
Address of VTDAPI_Timer_Parameters structure.


VTDAPI_Stop_User_Timer

; Obtain the entry point address in VTDAPI_Addr
les bx, [Timer_ID]
mov ax, VTDAPI_Stop_User_Timer
call VTDAPI_Addr

Stop a previously registered timer. The timer handle is invalid after this call and must not be reused.

  • Returns TIMERR_NOERROR in AX if successful; otherwise returns TIMERR_NOCANDO.
Timer_ID
32-bit handle to the timer returned from VTDAPI_Start_User_Timer.


VTDAPI_Timer_Start

; Obtain the entry point address in VTDAPI_Addr
mov di, SEG TimerParams
mov es, di
mov bx, OFFSET TimerParams
mov ax, VTDAPI_Timer_Start
call VTDAPI_Addr

mov [Timer_ID], ax

Register a timer callback to be called at periodic intervals. Limited to 32 timers.

  • Returns a 16-bit handle to the timer if successful; otherwise returns zero.
TimerParams
Address of VTDAPI_Timer_Parameters structure.


VTDAPI_Timer_Stop

; Obtain the entry point address in VTDAPI_Addr
mov cx, Time_ID
mov ax, VTDAPI_Timer_Stop
call VTDAPI_Addr

Stop a previously registered periodic or asynchronous timer. The timer handle is invalid after this call and must not be reused.

  • Returns TIMERR_NOERROR in AX if successful; otherwise returns TIMERR_NOCANDO.
Timer_ID
16-bit handle to the timer returned from VTDAPI_Timer_Start.


VTDAPI_Timer_Parameters

VTDAPI_Timer_Parameters Struc
    VTDAPI_Timer_Period      dw  ?  ; see below
    VTDAPI_Timer_Resolution  dw  ?  ; see below
    VTDAPI_Timer_IPCS        dd  ?  ; see below
    VTDAPI_Timer_Inst        dd  ?  ; see below
    VTDAPI_Timer_Flags       dw  ?  ; see below
VTDAPI_Timer_Parameters Ends

Describes the timer.

VTDAPI_Timer_Period
The time-out value in milliseconds.
VTDAPI_Timer_Resolution
The resolution of the timer. The resolution is the frequency of the base used for generating the timer ticks.
VTDAPI_Timer_IPCS
The address of the timer handler.
VTDAPI_Timer_Inst
Optional, user-defined data passed to the timer handler.
VTDAPI_Timer_Flags
Timer flags. Can be one of these values:
TIME_ONESHOT (0000H) | Single-shot timer.
TIME_PERIODIC (0001H) | Repeating, periodic timer..


Virtual Timer Device (VTD)

The virtual timer device virtualizes the hardware timer. The device provides services that other virtual devices can use to set the interrupt rate for the timer, and to disable I/O port trapping for the timer in a given virtual machine. This section describes the interfaces of the virtual timer device (VTD).


Reference

The VTD provides the following services:

VTD_Begin_Min_Int_Period

VTD_Disable_Trapping

VTD_Enable_Trapping

VTD_End_Min_Int_Period

VTD_Get_Date_And_Time

VTD_Get_Interrupt_Period

VTD_Get_Real_Time

VTD_Get_Version

VTD_Update_System_Clock


VTD_Begin_Min_Int_Period

include vtd.inc

mov eax, Int_Period
VxDcall VTD_Begin_Min_Int_Period
jc  errorhandler

Used by virtual devices to ensure a minimum accuracy for system timing. When this service is called, if the interrupt period specified is lower than the current timer interrupt frequency, the interrupt period will be set to the new frequency. Uses Flags.

  • Clears the carry flag if the interrupt period is set; otherwise, the specified interrupt period is not valid.
Int_Period
Desired interrupt period.

Until a matching call to the VTD_End_Min_Int_Period service is made, the timer interrupt frequency is guaranteed to never be slower than the value specified.

A virtual device should call this service only once before calling VTD_End_Min_Int_Period.

Typically the Begin_Min_Int_Period and End_Min_Int_Period services are used by devices such as execution profilers that need extremely accurate timing. VMM system time-out services rely on the VTD to keep time. Therefore, if the timer interrupts are more frequent, the accuracy of the time-out services will be greater.

Fast timer interrupt periods can be very expensive in terms of total system performance. For example, on some machines a timer interrupt of 1 millisecond will degrade total machine throughput by 10 percent, and increase disk I/O by 50 percent.


VTD_Disable_Trapping

include vtd.inc

mov ebx, VMHandle
VxDcall VTD_Disable_Trapping

Forces the VTD to stop I/O trapping on the timer ports for a specified virtual machine. The VTD_Enable_Trapping service must be called once for every call made to this service. Uses Flags.

  • No return value.
VMHandle
Virtual machine handle.

It is sometimes necessary to temporarily disable I/O trapping for virtual machine code that reads the timer in extremely tight timing loops. A good example is the hard drive BIOS code that reads the ports hundreds of times per disk transfer. The overhead of servicing the I/O traps would cause disk performance to slow significantly.

If this service is called n times, then VTD_Enable_Trapping must also be called n times before trapping is re-enabled. This allows nested calls to this service by more than one virtual device.


VTD_Enable_Trapping

include vtd.inc

mov ebx, VMHandle
VxDcall VTD_Enable_Trapping

Reenables timer I/O port trapping after the VTD_Disable_Trapping service has been called. This service must be made once for every call to VTD_Disable_Trapping. Only when every disable call has been matched by a call to this service will port trapping be re-enabled. Uses Flags.

  • No return value.
VMHandle
Virtual machine handle.


VTD_End_Min_Int_Period

include vtd.inc

mov eax, Int_Period
VxDcall VTD_End_Min_Int_Period
jc  errorhandler

Allows a virtual device to remove a timer interrupt period that it set earlier through the VTD_Begin_Min_Int_Period service. Uses Flags.

  • Clears the carry flag if successful; otherwise, the specified interrupt period is not valid.
Int_Period
Value passed earlier to VTD_Begin_Min_Int_Period.


VTD_Get_Date_And_Time

include vtd.inc

VxDCall VTD_Get_Date_And_Time
mov dword ptr [Time], eax
mov dword ptr [Date], edx

Returns the date and time. Uses EAX, EDX, Flags.

  • Returns the time in milliseconds in the EAX register and the days since January 1, 1980 in the EDX register.


VTD_Get_Interrupt_Period

include vtd.inc

VxDcall VTD_Get_Interrupt_Period
mov [Int_Period], eax

Retrieves the current timer interrupt frequency. Uses Flags.

  • Returns, in EAX, the length of time between ticks, in milliseconds.


VTD_Get_Real_Time

include vtd.inc

VxDcall VTD_Get_Real_Time
mov [time_hi], edx
mov [time_lo], eax

Retrieves the number of real time clock ticks that have elapsed since the current Windows session was started. Uses EAX, EDX, and Flags. This is an asynchronous service.

  • Returns the current system time based on an unit of 0.8 microseconds, in EDX:EAX. The EDX register contains the high doubleword of the time and EAX the low doubleword.


VTD_Get_Version

include vtd.inc

VxDcall VTD_Get_Version

Retrieves the version number, and the range of interrupt periods allowed by this virtual device. Uses EAX, EBX, ECX, and Flags.

  • Returns the version number in EAX. AH contains the major version number, and AL contains minor version number. Also returns, in EBX, the fastest possible interrupt period (in milliseconds), and, in ECX, the slowest possible interrupt period (in milliseconds). Clears the carry flag.


VTD_Update_System_Clock

include vtd.inc

VxDcall VTD_Update_System_Clock

Updates the system clock. This service should be called only by the VMM. Virtual devices should call the Get_System_Time service. Uses Flags.

  • No return value.


VWIN32 Services

This section contains information about the VWIN32 services. The VWIN32 VxD provides developers of VxDs with a variety of useful services, some of which may be used when implementing asynchronous procedure calls (APC), synchronization, and device input and output control.

Some of the VWIN32 services may be used for asynchronous procedure calls and synchronization. APCs and Win32 events are both mechanisms which can be used to synchronize ring 3 code with ring 0 code. You can create a ring 3 event, get a VxD handle to that event with the function OpenVxDHandle exported by KERNEL32, then use either _VWIN32_WaitSingleObject or _VWIN32_WaitMultipleObjects from ring 0 to wait on the event. These must be called from task time, and not from within VMM events.

To signal the event, you can use the standard ring 3 functions for setting or pulsing events, or you can use the ring 0 services _VWIN32_SetWin32Event and VWIN32_PulseWin32Event. The ring 0 Win32 event services can be called from within VMM events.

The services VWIN32_EnterCrstR0 and VWIN32_LeaveCrstR0 may be used to manage access to critical sections. To enable mutually exclusive access to a shared resource, each thread calls VWIN32_EnterCrstR0 to request ownership of the critical section before executing any section of code that accesses the protected resource. If another thread currently owns the critical section object, VWIN32_EnterCrstR0 blocks the execution of the calling thread indefinitely until the other thread releases its ownership. If the critical section object is currently unowned, the system grants ownership to the requesting thread so it can access the resource. When it has finished executing the protected code, the thread uses the VWIN32_LeaveCrstR0 function to relinquish ownership, enabling another thread to become owner and access the protected resource.

The VWIN32 services VWIN32_DIOCCompletionRoutine and VWIN32_GetCurrentProcessHandle are useful for VxDs that implement device input and output control (IOCTL) services. VWIN32_DIOCCompletionRoutine sets the state of the specified event object to signaled when I/O is complete. VxDs can use VWIN32_GetCurrentProcessHandle to tag the current device IOCTL connection or request with an ID. By using a process ID, the device can cleanup more easily on process termination.

There are a variety of other general purpose VWIN32 services such as _VWIN32_Get_Thread_Context, _VWIN32_Set_Thread_Context, VWIN32_GetCurrentDirectory, and VWIN32_TerminateApp. See the Reference section for a complete listing of the various VWIN32 services.

The following VWIN32 services can only be called when the current VM is the system VM:

_VWIN32_PulseWin32Event

_VWIN32_ResetWin32Event

_VWIN32_SetWin32Event

_VWIN32_WaitMultipleObjects

_VWIN32_WaitSingleObject


Reference

The following services are for internal use only by Windows 95 components:

_VWIN32_CheckDelayedNpxTrap

_VWIN32_Emulate_Npx

_VWIN32_FaultPopup

_VWIN32_Npx_Exception

_VWIN32_QueueKernelAPC

VWIN32_BlueScreenPopup

VWIN32_GetContextHandle

VWIN32_IFSRIPWhenLev2Taken


_VWIN32_CloseVxDHandle

Closes a VxD handle. A VxD handle is a ring 0 event handle created by the function OpenVxDHandle.

  • Returns a non-zero value in EAX if successful; otherwise returns zero in EAX if the event was invalid.
EAX
Ring 0 handle to an event.


_VWIN32_CopyMem

Copies memory with protection from faults.

  • Returns a non-zero value in EAX if successful; otherwise returns zero if the source or destination faults. Uses C calling conventions.
pSrc
Source address.
pDest
Destination address.
cb
Count of bytes to copy.
pcbDone
Address of a DWORD that receives the number of bytes that were copied. Ignored if NULL.


_VWIN32_CreateRing0Thread

Provides a service for ring 0 clients to create Win32 threads that execute only at ring 0, which allows the use of Win32 blocking functions. Preserves EBX, EDI, ESI, EBP, and segment registers.

  • Returns a Win32 ring 3 handle in EAX and a ring 0 thread handle in EDX if successful; otherwise EAX contains 0.
ECX
The size of the ring 3 stack for the thread being created. The recommended stack size is 4096.
EDX
DWORD to pass to startup function specified in ESI.
EBX
Pointer to ring 0 function where execution starts.
ESI
If this is a synchronous thread create, specify FALSE. Otherwise the value is the address of a callback procedure that is called if the create fails. The DWORD parameter passed in EDX is passed to the callback procedure.


_VWIN32_Get_Thread_Context

Copies the registers for the specified thread to the pcontext buffer. Uses C calling conventions.

  • Returns non-zero value if successful; zero otherwise.
ptcb
Ring 0 thread handle. Indicates the thread to get the context for.
pcontext
Address of a CONTEXT structure that receives the appropriate context of the specified thread. The value of the ContextFlags member of this structure specifies which portions of a thread's context are retrieved.

This function does not validate the context record address.


_VWIN32_IsClientWin32

This service determines whether the current thread client is currently executing Windows 32-bit code. It does not indicate whether the thread belongs to a Win32-based application. If the thread is in a nested execution, it looks at the current nested state. Uses Flags.

  • Returns non-zero value in EAX if the client is executing Windows 32-bit code; otherwise returns zero.


_VWIN32_PulseWin32Event

Provides a single operation that sets (to signaled) the state of the specified event object and then resets it (to nonsignaled) after releasing the appropriate number of waiting threads. Preserves EBX, EDI, ESI, EBP, and segment registers.

  1. Returns a non-zero value in EAX if successful; otherwise returns zero in EAX if the event was invalid.
EAX
VxD handle that identifies the event object. A VxD handle is a ring 0 event handle created by the function OpenVxDHandle.

The event object is set to a signaled state. If it is a manual reset event, all threads currently blocked on this event are unblocked if possible. If it is an auto reset event, one waiting thread is unblocked. Before returning, this function resets the event to nonsignaled.

This service can only be called when the current VM is the system VM.


_VWIN32_QueueUserApc

Queues a call to the specified ring 3 code in the specified thread and returns. The thread must have been placed in an alertable wait state by using one of the following Win32 functions: SleepEx, WaitForMultipleObjectsEx, or WaitForSingleObjectEx. (To make an alertable wait state, set the fAlertable parameter in these Win32 functions to TRUE.) This service may be called at event time, but not at interrupt time. Uses EAX, ECX, EDX, and Flags.

  • Returns a non-zero value in EAX and clears the zero flag if successful in queuing the asynchronous procedure call (APC). If unable to allocate memory for the APC, EAX contains 0 and the zero flag is set.
pfnRing3APC
Flat offset of ring 3 asynchronous procedure. If 0, the thread is only awakened.
dwParam
DWORD parameter to pass to APC.
ptcb
Ring 0 thread handle. If -1, use kernel service thread.


_VWIN32_ResetWin32Event

Sets the state of the specified event object to nonsignaled. Uses EAX, ECX, EDX, and Flags.

  • Returns a non-zero value in EAX if successful; otherwise returns zero in EAX if the event was invalid.
EAX
VxD handle that identifies the event object. A VxD handle is a ring 0 event handle created by the function OpenVxDHandle.

This service can only be called when the current VM is the system VM.


_VWIN32_Set_Thread_Context

Copies the register values from the pcontext buffer to the specified thread's current register set. Uses EAX, ECX, EDX, and Flags..

  • Returns non-zero value if successful; zero otherwise.
ptcb
Ring 0 thread handle. Indicates the thread to set the context for.
pcontext
Address of a CONTEXT structure that contains the context to be set in the specified thread. The value of the ContextFlags member of this structure specifies which portions of a thread's context to set. Some values in the CONTEXT structure that cannot be specified are silently set to the correct value. This includes bits in the CPU status register that specify the privileged processor mode, global enabling bits in the debugging register, and other states that must be controlled by the operating system.

This function does not validate the context record address.


_VWIN32_SetWin32Event

Sets the state of the specified event object to signaled. Uses EAX, ECX, EDX, and Flags.

  • Returns a non-zero value in EAX if successful; otherwise returns zero in EAX if the event was invalid.
EAX
VxD handle that identifies the event object. A VxD handle is a ring 0 event handle created by the function OpenVxDHandle.

The event object is set to a signaled state. If it is a manual reset event, it remains in the signaled state until it is explicitly reset and all threads currently blocked on this event are unblocked. If it is an auto reset event, one waiting thread is unblocked.

This service can only be called when the current VM is the system VM.


_VWIN32_WaitMultipleObjects

This function returns either when one or all of the specified objects are in the signaled state, or when the specified time-out interval elapses. It links multiple wait nodes to the current thread and specified synchronization objects, and blocks on the synchronization objects if necessary. Uses EAX, ECX, EDX, and Flags.

  • For information about the return value, see the Win32 ring 3 function WaitForMultipleObjects in the Microsoft Win32 Software Development Kit (SDK).
ECX
Number of objects in the wait array.
ESI
Pointer to array of VxD handles which can be waited on. A VxD handle is a ring 0 event handle created by the function OpenVxDHandle.
EDX
The time-out interval, in milliseconds. The function returns if the interval elapses, even if the wait conditions specified in the AX register are not satisfied. If zero, the function tests the states of the specified objects and returns immediately. If -1, the function's time-out interval never elapses.
AH
Wait Flags. If -1, the function returns when all objects in the wait array are signaled. If 0, the function returns when any one of the objects is signaled. In the latter case, the return value indicates the object whose state caused the function to return.
AL
If non-zero value, the function returns when APCs are queued. The calling thread will deliver the APC by using SleepEx, WaitForMultipleObjectsEx, or WaitForSingleObjectEx at ring 3.

This service can only be called when the current VM is the system VM.


_VWIN32_WaitSingleObject

This function only returns when the specified object is in the signaled state or when the time-out interval elapses. Uses EAX, ECX, EDX, and Flags.

  • For information about the return value, see the Win32 ring 3 function WaitForSingleObject in the Microsoft Win32 Software Development Kit (SDK).
EBX
VxD handle which can be waited on. A VxD handle is a ring 0 event handle created by the function OpenVxDHandle.
EDX
The time-out interval, in milliseconds. The function returns if the interval elapses, even if the object's state is nonsignaled. If zero, the function tests the object's state and returns immediately. If -1, the function's time-out interval never elapses.
EAX
Flag that indicates if this is an alertable wait. Specifies whether the function returns when the system queues an I/O completion routine for execution by the calling thread. If TRUE, the function returns and the completion routine is executed. If FALSE, the function does not return, and the completion routine is not executed.

A completion routine is queued, but is not executed. The thread must run at ring 3 for this to happen. A completion routine is queued for execution when the ReadFileEx or WriteFileEx function in which it was specified has been completed. The wait function returns and the completion routine is executed only if this flag is TRUE, and the calling thread is the thread that initiated the read or write operation.

This service can only be called when the current VM is the system VM.


OpenVxDHandle

DWORD OpenVxDHandle(HANDLE hSource);

This function is exported by KERNEL32.DLL for DLLs or applications that have associated VxDs that need to set ring 3 events from ring 0. When a ring 3 event handle is used as the source, the handle returned from this function can be passed to a VxD and used to set the event at ring 0 with the service _VWIN32_SetWin32Event.

The VxD Handle must be closed at ring 0 with _VWIN32_CloseVxDHandle or the object will never get freed. The event can be set from any thread in the system VM at VMM32 event time.

  • Returns a DWORD that specifies a VxD handle; otherwise returns 0L if the event handle specified in the hSource parameter is not valid.
hSource
Event handle in the current process to convert to a VxD handle.


VWIN32_ActiveTimeBiasSet

Notifies VxDs when the ActiveTimeBias registry entry is set. This service is called whenever the time zone is changed, or the daylight/standard setting is changed. To receive notification, VxDs hook this service. Uses Flags.

  • Clears the carry flag if successful; otherwise sets the carry flag.

This service is called whenever the ActiveTimeBias registry entry is set, which may or may not mean that the value has changed.

If you hook this service, you must chain the call and pass this call to other VxDs who have also hooked this service. If you do not chain this call, the system will become unstable.


VWIN32_DIOCCompletionRoutine

This function is called by VxDs that implement device input and output control (IOCTL) services when I/O is complete. The function sets the state of the specified event object to signaled. Uses EAX, EDX.

  • This service has no return value.
EBX
VxD handle contained in the O_Internal member of the OVERLAPPED structure that identifies the event object. A VxD handle is a ring 0 event handle created by the function OpenVxDHandle.


VWIN32_EnterCrstR0

The VWIN32_EnterCrstR0 function waits for ownership of the specified critical section object. The function returns when the calling thread is granted ownership. Uses EAX, ECX, EDX.

  • Returns with the carry flag set if there was a fault accessing critical section.
EDX
Pointer to critical section object.


VWIN32_Get_Version

Retrieves the version number of the VWIN32 VxD. Uses EAX.

  • Returns the driver version number in the EAX register.


VWIN32_GetCurrentDirectory

Returns the current directory, if the current thread is a Win32 thread.

  • Fills the buffer with the current directory and sets the EAX register to 0 if successful. Otherwise, if the current thread is not a Win32 thread, sets EAX to -1.
ESI
Address of buffer for the current directory. The buffer must be at least as large as MAX_PATH.

If the current VM is not the system VM, or if the current thread is not a 32-bit thread, the function returns an error. In this case, use the VMM service Exec_VxD_Int to call Interrupt 21h Function 47h, Get Current Directory.


VWIN32_GetCurrentProcessHandle

Retrieves the current ring 3 process handle.

  • Returns the current process handle.

VxDs that support device input and output control (IOCTL)services use this service to tag the current device IOCTL connection or request with an ID. By using a process ID, the device can cleanup more easily on process termination.


VWIN32_LeaveCrstR0

The VWIN32_LeaveCrstR0 function releases ownership of the specified critical section object. Uses EAX, EBX, ECX, EFlags.

  • This function has no return value.
EDX
Pointer to the critical section object.


VWIN32_SysErrorBox

Displays a system modal error box. Uses EAX and Flags.

  • Returns the user's response to the dialog box in EAX. A return value of 0 indicates an error.
EBX
Address of the VSEB structure. The VSEB structure has the following format:
typedef struct vseb_s {
    DWORD vseb_resp;       // response; indicates buton user pressed
    WORD  vseb_b3;         // style for button 3
    WORD  vseb_b2;         // style for button 2
    WORD  vseb_b1;         // style for button 1
    DWORD vseb_pszCaption; // text for caption bar
    DWORD vseb_pszText;    // message text
} VSEB;


VWIN32_TerminateApp

Terminates a Windows-based application. Uses Flags.

  • This service has no return value.
EDI
A ring 0 handle of a thread in the process to kill.


VSEB

typedef struct vseb_s {
    DWORD vseb_resp;
    WORD  vseb_b3;
    WORD  vseb_b2;
    WORD  vseb_b1;
    DWORD vseb_pszCaption;
    DWORD vseb_pszText;
} VSEB;

Structure that describes the system modal dialog box that the service VWIN32_SysErrorBox displays.

vseb_resp
Response. Indicates which button the user pressed. May be one of the following:
1 | User selected button 1.
2 | User selected button 2.
3 | User selected button 3.

vseb_b1, vseb_b2, vseb_b3
The button text for each button on the dialog box. Choose from the following:
1 | Button with "OK"
2 | Button with "Cancel"
3 | Button with "&Yes"
4 | Button with "&No"
5 | Button with "&Retry"
6 | Button with "&Abort"
7 | Button with "&Ignore
8 | Button with "Close"
9 | Button with "&Help"

To make one of the buttons the default, combine the value 0x8000 with one of the above values.

vseb_pszCaption
Address of a null-terminated string used for the dialog box caption title.
vseb_pszText
Address of a null-terminated string containing the message to be displayed.


NDIS WAN Miniport Driver Configuration and Registry Information for Windows 95

In the current implementation of the NDIS WAN and WAN TAPI Service Provider (WANTSP) components, the only avenue for adapter configuration is through the Advanced page of the WAN (ISDN) adapter, accessed via the Network control panel. ISDN adapters are currently treated like network cards; this documentation describes how to add support for configuration property pages accessible through TAPI for WAN devices, specifically, ISDN adapters.


Registry Layout - ISDN Devices

The Windows® 95 ISDN Support software is designed to support Windows 2000 NDIS WAN Miniports unmodified. This means the various Miniport drivers that exist today which read and write nonstandard, driver-specific data to the registry (in the driver's registry key). However, for these drivers, the WANTSP will not allow TAPI apps to set or invoke the device properties.

This documentation describes a standard configuration interface using the WANTSP and a registry layout which must be adopted in order to support this interface. Old drivers must be modified to conform to the standard if they wish full Windows 95 compatibility.


Windows 2000 Driver Layout

The standard NT/Windows 2000 WAN Miniport places driver-specific data as well as common ISDN configuration data under its own driver key. Aside from a few NDIS values, the value names in this key are completely specific to the driver and lack conformity with other drivers. An example of a Windows NT/Windows 2000 driver's registry key follows.

\HKLM\System\CurrentControlSet\Services\ISDNAdapter1\
            BoardName = (LPSTR) "ISDNBoardName"
            BoardType = (LPSTR) "ISDNBoardType"
            DeviceVxDs = (LPSTR) "driver.sys"
            DevLoader = (LPSTR) "*ndis"
            DriverDesc = (LPSTR) "ISDN Adapter Description"
            EnumPropPages = (LPSTR) "netdi.dll,EnumPropPages"
            InfPath = (LPSTR) "COMPANYX.INF"
            InterruptNumber = (BINARY) 04 00 00 00
            IOBaseAddress = (BINARY) 02 00 00 00
            NumChannels = (LPSTR) "2"
            Phone1 = (LPSTR) "5551111"
            Phone2 = (LPSTR) "5552222"
            SPID1 = (LPSTR) "015551111000"
            SPID2 = (LPSTR) "015552222000"
            SwitchType = (LPSTR) "1"

Note that in the preceding example, the values (and value names) in italics may differ between drivers. Some ISDN adapters support multiple physical lines. Following is an example of a card which supports two physical ISDN lines.

\HKLM\System\CurrentControlSet\Services\ISDNAdapter2\
            BoardName = (LPSTR) "ISDNBoard - 2 Lines"
            BoardType = (LPSTR) "ISDNBoardType - 2 Lines"
            DeviceVxDs = (LPSTR) "driver.sys"
            DevLoader = (LPSTR) "*ndis"
            DriverDesc = (LPSTR) "ISDN 2 Line Adapter"
            EnumPropPages = (LPSTR) "netdi.dll,EnumPropPages"
            InfPath = (LPSTR) "COMPANYX.INF"
            IOBaseAddress = (BINARY) 04 00 00 00
            Line0.NumChannels = (LPSTR) "2"
            Line0.Phone1 = (LPSTR) "5551111"
            Line0.Phone2 = (LPSTR) "5552222"
            Line0.SPID1 = (LPSTR) "015551111000"
            Line0.SPID2 = (LPSTR) "015552222000"
            Line0.SwitchType = (LPSTR) "1"
            Line1.NumChannels = (LPSTR) "2"
            Line1.Phone1 = (LPSTR) "5553333"
            Line1.Phone2 = (LPSTR) "5554444"
            Line1.SPID1 = (LPSTR) "015553333000"
            Line1.SPID2 = (LPSTR) "015554444000"
            Line1.SwitchType = (LPSTR) "1"
            NumberOfLines = (LPSTR) "2"

As in the previous example, all values in italics are specific to the driver, they may have different names or not be present in other driver layouts. In the preceding example, the driver values are in a "flat key" format, for example, all the values are contained in the root key. Currently, this is the only method supported by NDIS for drivers to use. The WAN TAPI Service Provider uses a hierarchical key layout which it will map to a flat key layout for the drivers to read. The values which are mapped to the flat layout are described in the following topic, Windows 95 Layout.


Windows 95 Layout

To support a variety of ISDN boards, the Windows® 95 registry layout adopts a hierarchy of lines and channels for each driver. In this context, lines are the actual physical ISDN lines that plug into the adapter. (This is different from TAPI's logical line device.) For example, the first adapter shown (see preceding) would have only one line while the second adapter would have two. Each line has a number of channels which depends on the type of ISDN line. A ISDN BRI line has two B-channels maximum although only one may actually be used. An ISDN PRI line has up to 23 or 31 B-channels, depending on whether it is in North America or Europe. Conceivably, a driver could have 31 channels for each of the lines the adapter supports.

A skeletal example of a Windows 95 driver registry key follows. A description of this driver key layout follows the example.

\HKLM\System\CurrentControlSet\
    Services\Net\
        0000\
            <PnP config values>
            BoardName = (LPSTR) "ISDNBoard - 1 Line"
            BoardType = (LPSTR) "ISDNBoardType - 1 Line"
            DeviceVxDs = (LPSTR) "driver.sys"
            DevLoader = (LPSTR) "*ndis"
            DriverDesc = (LPSTR) "ISDN Adapter"
            EnumPropPages = (LPSTR) "netdi.dll,EnumPropPages"
            InfPath = (LPSTR) "COMPANYX.INF"
            InterruptNumber = (BINARY) 05 00 00 00
            NumberOfLines = (STRING) "1"
            Line0.SwitchType = (STRING) "1"
            Line0.Properties = (STRING) "0"
            Line0.Channel0.Properties = (STRING) "0"
            Line0.Channel0.Phone = (STRING) "5551111"
            Line0.Channel0.SPID = (STRING) "015551111000"
            Line0.Channel1.Properties = (STRING) "0"
            Line0.Channel1.Phone = (STRING) "5552222"
            Line0.Channel1.SPID = (STRING) "015552222000"
            TAPI\
                DeviceCaps = (BINARY) 00 00 ... 00 00
                Properties = (BINARY) 00 00 00 00
                VendorConfig = (BINARY) 00 00 ... 00 00
                Line0\
                    LineCaps = (BINARY) 00 00 ... 00 00
                    Properties = (BINARY) 00 00 00 00
                    SwitchType = (BINARY) 00 00 00 00
                    VendorConfig = (BINARY) 00 00 ... 00 00
                    Channel0\
                        ChannelCaps = (BINARY) 00 00 00 00
                        Properties = (BINARY) 00 00 00 00
                        Phone = (STRING) ""
                        SPID = (STRING) ""
                        VendorConfig = (BINARY) 00 00 ... 00 00
                    Channel1\
                        ChannelCaps = (BINARY) 00 00 00 00
                        Properties = (BINARY) 00 00 00 00
                        Phone = (STRING) ""
                        SPID = (STRING) ""
                        VendorConfig = (BINARY) 00 00 ... 00 00

The driver key contains one child key per physical line that plugs into the adapter. These key names are displayed as LineX, where X is a monotonically increasing decimal number. Similarly, each LineX key contains one child key per B-channel that the line supports. These key names are displayed as ChannelY, where Y is a monotonically increasing decimal number. The WANTSP provides a mapping between the flat key layout used by the driver and the hierarchical layout used by the ISDN UI. The values which are mapped by the WANTSP are the following:

Line level mappings. These two values are mapped for all lines present.

LineX.SwitchType | STRING | This value corresponds to the SwitchType setting for the particular line. It represents the selected bit flag corresponding to a particular switch, for example, ISDN_SWITCH_NI1. It is stored as a STRING key, and it should be read by the driver as NdisParameterHexInteger.
LineX.Properties | STRING | This is a four-byte value containing the current line configuration settings. The legal values are the ISDN_LINE_* manifest constants. This key controls whether the line is active or inactive. It is stored as a STRING key, and it should be read by the driver as NdisParameterHexInteger. If not present it should be interpreted as ISDN_LINE_DEFAULT.

Channel level mappings. These two values are mapped for all channels present for each line present.

LineX.ChannelY.SPID | STRING | This value corresponds to the SPID setting for the particular channel. This value should be used as the Service Profile ID corresponding to this B channel. This value will be numeric only with no separators.
LineX.ChannelY.Phone | STRING | This value corresponds to the Phone setting for the particular channel. This value should be used as the directory number (w/o area code) corresponding to this B channel. This value will be numeric only with no separators.
LineX.ChannelY.Properties | STRING | This is a four-byte value containing the current channel configuration settings. The legal values are the ISDN_LINE_* manifest constants. This key controls whether the channel is active or inactive. It is stored as a STRING key, and it should be read by the driver as NdisParameterHexInteger. If not present it should be interpreted as ISDN_CHANNEL_DEFAULT.

The registry value names, types, and descriptions for the \Net\xxxx\TAPI registry key are as follows:

Properties | BINARY | This is a four-byte value containing the current configuration flags for the device. The legal values are the ISDN_* manifest constants. This key controls whether the device is active or inactive.
DeviceCaps | BINARY | Capabilities of the driver. This is five DWORDs in size, and determines the entire contents of the ISDNDEVCAPS structure (see the following).
VendorConfig | BINARY | Optional value that contains opaque, driver specific data related to the driver.

The registry value names, types, and descriptions for the \Net\xxxx\TAPI\LineX registry keys are as follows:

Properties | BINARY | This is a four-byte value containing the current line configuration settings. The legal values are the ISDN_LINE_* manifest constants. This key controls whether the line is active or inactive.
LineCaps | BINARY | Capabilities of the line. This is seven DWORDs in size, and determines the entire contents of the ISDNLINECAPS structure (see the following).
SwitchType | BINARY | This is a four-byte value containing the current switch setting.
VendorConfig | BINARY | Optional value that contains opaque, driver specific data related to the specific line.

The registry value names, types, and descriptions for the \Net\xxxx\TAPI\LineX\ChannelY registry keys are as follows:

Properties | BINARY | This is a four-byte value containing the current channel configuration settings. The legal values are the ISDN_CHANNEL_* constants. This key controls whether the channel is active or inactive.
ChannelCaps | BINARY | This is a four-byte value containing the configuration flags for the channel. These flags are effective only if the device is capable of the respective support. The legal values are the ISDN_CHANNEL_* constants. These flags represent the capability of the channel.
Phone | STRING | The phone number of the channel. See LineX.ChannelY.Phone.
SPID | STRING | The SPID of the channel. See LineX.ChannelY.SPID.
VendorConfig | BINARY | Optional value that contains opaque, driver specific data related to the specific line.


Windows 95 Sample INF

The following is a sample section of a Windows® 95 INF file which would create the required registry keys during the driver's installation. Note in particular the DeviceCaps and LineCaps entries which are the binary versions of the corresponding structures ISDNDEVCAPS and ISDNLINECAPS, described in the following.

;****************************************************************************
; TAPI ISDN Configuration
;****************************************************************************
HKR,,NumberOfLines,,1
HKR,TAPI,Properties,1,00,00,00,00
HKR,TAPI,DeviceCaps,1,14,00,00,00, 00,00,00,00, 00,00,00,00, 01,00,00,00, 01,00,00,00
HKR,TAPI\Line0,Properties,1,00,00,00,00
HKR,TAPI\Line0,SwitchType,1,00,00,00,00
HKR,TAPI\Line0,LineCaps,1,1c,00,00,00, 00,00,00,00, 03,00,00,00, ff,00,00,00, 03,00,00,00, 02,00,00,00, 02,00,00,00
HKR,TAPI\Line0\Channel0,Properties,1,00,00,00,00
HKR,TAPI\Line0\Channel0,ChannelCaps,1,00,00,00,00
HKR,TAPI\Line0\Channel0,SPID,,""
HKR,TAPI\Line0\Channel0,Phone,,""
HKR,TAPI\Line0\Channel1,Properties,1,00,00,00,00
HKR,TAPI\Line0\Channel1,ChannelCaps,1,00,00,00,00
HKR,TAPI\Line0\Channel1,SPID,,""
HKR,TAPI\Line0\Channel1,Phone,,""


Data Structures

A common data structure is needed to transfer device configuration between the WANTSP and the device properties. The data structure must be extensible for future devices and capabilities. For an ISDN device, the data structure must also support multiple lines and channels.

The following ISDN structures are provided:

ISDNDEVCAPS

ISDNLINECAPS


ISDNDEVCAPS

The ISDN device capabilities are enumerated in the ISDNDEVCAPS structure. These capabilities are assumed to apply to the device in general. The capabilities are not line specific.

typedef struct tagISDNDEVCAPS {
    DWORD    cbSize;         /* size of the ISDNDEVCAPS structure */
    DWORD    dwFlags;        /* flags for the device (ISDN_*) */
    DWORD    nSubType;       /* device subtype (ISDN_SUBTYPE_*) */
    DWORD    cLinesMax;      /* number of physical lines supported */
    DWORD    cActiveLines;   /* number of active physical lines */
    } ISDNDEVCAPS, FAR * LPISDNDEVCAPS;

The field descriptions follow:

cbSize | The size of the entire ISDNDEVCAPS structure.
dwFlags Device capability options. This is a bit field, where the possible flags are:
ISDN_DEFAULT        Default settings
nSubType The device subtype. This is a bit field, where the possible flags are:
ISDN_SUBTYPE_INTERNAL    The device is an internal adapter
ISDN_SUBTYPE_PCMCIA      The device is a PCMCIA card
cLinesMax | Refers to the number of physical lines the device supports. An ISDN device must have at least one physical line. This field must match the number of LineX keys that are in the driver registry key.
cActiveLines Refers to the number of physical lines that are active on the device, for example, the number of physical lines attached to the adapter.

This value is derived from the number of LineX keys that have the ISDN_LINE_INACTIVE bit set in their Properties value. This value is determined at run time and should be set to zero in the INF.


ISDNLINECAPS

The ISDN device's physical line capabilities are enumerated in the ISDNLINECAPS structure.

typedef struct tagISDNLINECAPS {
   DWORD   cbSize;          /* size of entire structure */
   DWORD   dwFlags;         /* flags for the line (ISDN_LINE_*) */
   DWORD   dwChannelFlags;  /* flags for the channels (ISDN_CHAN_*) */
   DWORD   dwSwitchType;    /* switches supported */
   DWORD   dwSpeedType;     /* speed type */
   DWORD   cChannelsMax;    /* number of B-channels per line supported */
   DWORD   cActiveChannels; /* number of active channels */
   } ISDNLINECAPS, FAR * LPISDNLINECAPS;

The field descriptions follow:

cbSize | The size of the entire ISDNLINECAPS structure.
dwFlags Line capability options. This is a bit field, where the possible flags are:
ISDN_LINE_DEFAULT     Default settings
ISDN_LINE_INACTIVE    The line can be inactive
dwChannelFlags Channel capability options. This is a bit field, where the possible flags are:
ISDN_CHAN_DEFAULT     Default settings
ISDN_CHAN_INACTIVE    The channel can be inactive
ISDN_CHAN_SPEED_ADJUST    Connection speed can adjust downwards
dwSwitchType Refers to the switch types that this line supports. This is a bit field, where any or all of the following flags may be set.
ISDN_SWITCH_NONE    No switch
ISDN_SWITCH_AUTO    Automatic
ISDN_SWITCH_ATT     AT&T ESS 5
ISDN_SWITCH_NI1     National ISDN 1
ISDN_SWITCH_NTI     Northern Telecom DMS 100
ISDN_SWITCH_INS64   NT&T (Japan)
ISDN_SWITCH_1TR6    Deutsche Telecom
ISDN_SWITCH_VN3     French Telecom
ISDN_SWITCH_NET3    European Switch
ISDN_SWITCH_AUS     Australian Switch
ISDN_SWITCH_BEL     Belgium Switch
dwSpeedType Refers to the speed and data types that the channels on this line support. This is a bit field, where any or all of the following flags may be set.
ISDN_SPEED_56K_VOICE    56kbps voice
ISDN_SPEED_56K_DATA     56kbps data
ISDN_SPEED_64K_DATA     64kbps data
ISDN_SPEED_128K_DATA    128kbps data
cChannelsMax | Refers to the number of B-channels the physical line has. This field must match the number of ChannelY keys that are in the line registry key of the driver.
cActiveChannels | Refers to the number of B-channels that are active on the line. This value is derived from the number of ChannelY keys that have the ISDN_CHAN_INACTIVE bit set in their Properties value. This value is determined at run time and should be set to zero in an INF.


ISDN Constants

// Flags for ISDNDEVCAPS
#define ISDN_DEFAULT               0x00000000L

// Subtype ordinals for ISDNDEVCAPS
#define ISDN_SUBTYPE_INTERNAL      0x00000000L
#define ISDN_SUBTYPE_PCMCIA        0x00000001L

// Flags for ISDNLINECAPS
#define ISDN_LINE_DEFAULT          0x00000000L
#define ISDN_LINE_INACTIVE         0x00000001L

// Channel flags for ISDNLINECAPS
#define ISDN_CHAN_DEFAULT          0x00000000L
#define ISDN_CHAN_INACTIVE         0x00000001L
#define ISDN_CHAN_SPEED_ADJUST     0x00000002L

// Switch type for ISDNLINECAPS
#define ISDN_SWITCH_NONE           0x00000000L
#define ISDN_SWITCH_AUTO           0x00000001L
#define ISDN_SWITCH_ATT            0x00000002L
#define ISDN_SWITCH_NI1            0x00000004L
#define ISDN_SWITCH_NTI            0x00000008L
#define ISDN_SWITCH_INS64          0x00000010L
#define ISDN_SWITCH_1TR6           0x00000020L
#define ISDN_SWITCH_VN3            0x00000040L
#define ISDN_SWITCH_NET3           0x00000080L    // retained for
                                // backward compatibility
#define ISDN_SWITCH_DSS1           0x00000080L
#define ISDN_SWITCH_AUS            0x00000100L
#define ISDN_SWITCH_BEL            0x00000200L

// Speed type for ISDNLINECAPS
#define ISDN_SPEED_NONE            0x00000000L
#define ISDN_SPEED_56K_VOICE       0x00000001L
#define ISDN_SPEED_56K_DATA        0x00000002L
#define ISDN_SPEED_64K_DATA        0x00000004L
#define ISDN_SPEED_128K_DATA       0x00000008L

// Options for ISDNLINECAPS
#define ISDN_LINEOPT_DEFAULT       0x00000000L
#define ISDN_LINEOPT_CHANNELID     0x00000001L
#define ISDN_LINEOPT_FIXEDCOUNT    0x00000002L

// Options for channel
#define ISDN_CHANOPT_DEFAULT       0x00000000L
#define ISDN_CHANOPT_SHOW_STATUS   0x00000001L
#define ISDN_CHANOPT_ENABLE_LOG    0x00000002L
#define ISDN_CHANOPT_INACTIVE_TIMEOUT    0x00000004L


WAN TAPI Service Provider

Each TAPI line device enumerated by the WANTSP will not necessarily map to a physical line. Usually for an ISDN board each B channel is mapped to a TAPI line device. This means an ISDN board that has one physical line will have two line devices available to TAPI apps. Similarly, a board which has 2 physical lines would have 4 line devices enumerated by the WANTSP. It is the driver's responsibility to return a unique line device name for each line device it exposes to the WANTSP.


ISDN User Interface Handler

The ISDN User Interface DLL (ISDNUI) will handle all the default ISDN device property pages. It will also provide the mechanism to allow vendors to add their own pages to the device properties.


Thunk Layer

A thin thunk layer is required because the WANTSP DLL is 16 bit while ISDNUI will be 32 bit. The ISDNUI must be 32 bit in order to support 32-bit shell extensions.


Shell Extension Support

The Shell Extension support is currently under development and is not described in this release.


ISDN Configuration Pages

As for any TAPI device, the properties for the ISDN line device are accessible through the specific TAPI app, through the TAPI lineConfigDialogEdit function. Properties are provided on a per-connection basis. (Note that a connection is associated with a particular line device.) In addition, vendors will be able to add their own pages to the line device properties.


Connection Configuration

The ISDN connection properties consists of one standard Connection page. Optional vendor-supplied pages can be added. These pages should allow the user to change or view any attributes that pertain to the specific connection in context. Alternatively, settings that are specific to the physical line (that do not change across connections) should be reserved for the Line properties. For example, SPIDs and phone numbers do not change across connections, therefore these settings would be reserved for the Line properties.


General Page

The General Page has been removed.


Connection Page

The Connection page includes settings that are applied to all the channels used for the connection. The controls are divided into two groups: speed preferences and call preferences.

Speed preference.
The speed preference combination drop-down contains the following options:

56K Voice

56K Data

64K Data

128K Data

The contents of this combination box are limited by the capabilities of the device. Unsupported speeds are removed from the list. The default selection is the highest setting.

Only connect at this speed.
When this checkbox is marked, the connection will fail if the specified speed type cannot be established.
Show connection status.
Shows a modem-lights-like applet for these channels, when marked.
Record connection status to file.
This checkbox indicates whether to record the ISDN connection progression to a log file. The log file is titled ISDNLOG.TXT and can be found in the Windows folder.
Disconnect a call...
Allows the user to specify the inactivity time-out for the channels.
Advanced.
This button invokes the properties of the physical line. See Line Configuration.


Line Configuration

The ISDN line properties consists of the standard Line page. Optional vendor-supplied pages can also be added. These pages should allow the user to change or view any attributes related to the physical line that do not change across connections.


Line Page

The Line page includes settings that relate to the physical line. These settings should be independent of any specific connection information, such as channel speed or dialing time-outs. Changing these settings will probably require a system restart.

Friendly name and icon.
The icon is to be determined. The picture currently uses an internal adapter as a placeholder. The friendly name of the line is derived from the physical line number (base-zero) and converted to a friendlier term. For example, Line 0 would be displayed as 1st Line.
Switch Type.
This combination box contains the list of switches supported by the adapter. These switches include the following:
(None)

Automatic

ATT: AT&T ESS 5

NI1: National ISDN 1

NTI: Northern Telecom DMS 100

INS64: NT&T (Japan)

1TR6: Deutsche Telecom

VN3: French Telecom

NET3: European Switch

DSS1: Euro-ISDN

Australian National

Belgium National

Channel settings.
This list view contains a list of all the B-channels for the physical line. There are three columns in this list view:
Channel:
Indicates the channel number (zero based).
Phone Number:
Specifies the phone number of the channel. This is displayed in TAPI's canonical address form.
SPID:
Indicates the SPID of the channel.
Modify.
The button invokes the Channel Settings dialog. This allows the user to assign a phone number and SPID to the selected channel. If no channel is selected, this button is disabled.


Channel Settings Dialog

The Channel Settings dialog allows the user to assign a phone number and SPID to the selected channel.

Group box.
The group box label indicates which channel is being set.
Switch Type.
This is a static text field that reflects the current switch type of the physical line. This field serves to remind the user, in case she questions the derived SPID number.
Phone Number.
The edit box accepts standard keystrokes acceptable for a phone number in canonical address form. If the user enters a noncanonical phone number, the dialog will convert it once OK is clicked.
SPID.
This edit box accepts numerical data which should contain the Service Profile ID provided by the telephone company.
Determine SPID automatically.
When marked, the SPID is generated according to the phone number (not currently implemented). Otherwise, the SPID field is enabled to allow the user to manually enter the SPID.


Windows 95 NDIS WAN Miniports

The primary documentation for developing NDIS WAN miniport drivers is the Network Drivers section in the Windows NT® 3.51 DDK. The following information assumes that the reader is already familiar with the Windows NT® 3.51 DDK documentation and network driver development. This documentation provides additional details for developing NDIS 3.1 WAN miniport drivers for Windows® 95 as noted in the Windows NT 3.51 DDK documentation:

If your MAC driver will have both a Windows NT/Windows 2000 and Windows 95 version, it is best to develop and perfect the Windows NT/Windows 2000 version first. Code written for Windows NT/Windows 2000 easily translates to Windows 95, but the reverse is not necessarily true.


Certification

To get information on testing your hardware for the Designed for Windows 95 logo, send email to whqlinfo@microsoft.com, or visit the web site at http://www.microsoft.com/windows/thirdparty.htm.


Installation and Windows 95 INFs

The files on the support disk are meant to be installed by the NDISWAN.INF. A properly written INF for the adapter will bind it automatically to the NDISWAN protocol as well as trigger the NDISWAN.INF install itself.

In the sample INF file, isdntest.inf, there are several sections that should be included in an INF for a miniport driver. The [BoardName.ndi] section includes a CopyFiles line for the [BoardName.inf.CopyFiles] section. This section will copy the NDISWAN.INF file as well as the INF for the adapter into the Windows\Inf directory and rebuild the driver database file. This is necessary so the Network Control Panel will be able to locate the NDISWAN protocol and automatically bind it to the miniport driver.

Under the [BoardName.ndi.reg] section, there is a Required Components subsection which all miniport drivers using NDISWAN should have. These lines will ensure that a miniport driver is not installed without the NDISWAN support protocol. In the Interfaces subsection, WAN Miniports which need the WAN Wrapper services should specify ndiswan as the DefUpper interface and the range should only include ndiswan. These WAN Miniport drivers should not include a ndis3, ndis2, or odi value which would let them bind to upper layer protocols directly.

The NDISWAN.INF currently adds the WAN SP if there is only one installed TAPI SP. If more than one SP is installed, you will need to manually add the WAN SP using the Telephony Control Panel. This will removed in the future when the install wizard is introduced.


Architecture

The architecture of the NDIS WAN support in Windows® 95 is slightly different from Windows NT®/Windows® 2000 though all the differences are internal and should not affect a properly written driver. In Windows 95, the Connection Wrapper and the NDISWAN protocol have been combined into one VxD while the Dial Up Networking Adapter (PPPMAC.VXD) is used as the WAN Wrapper. This differs from Windows NT/Windows 2000 where the NDISWAN protocol is combined with the NDISWAN adapter (which serves as the WAN Wrapper), while the Connection Wrapper (NDISTAPI.SYS) functions as a separate driver.


How to Build the Sample Driver

To build a sample driver

  1. You must have the Win32® SDK and the Windows NT 3.51 DDK installed. The Windows NT 3.51 DDK is available though Microsoft Developer's Network Level 2 subscriptions. For more information about subscribing to MSDN level 2, send Internet e-mail to msdn@microsoft.com.
  2. When you set up the DDK, it will modify the INCLUDE environment variable. In addition to the default settings for this parameter, you should add \ddk\src\network\inc. This assumes that the DDK is installed in \ddk.
  3. Use the BUILD command (as documented in the DDK) to generate the driver. You may have to manually create the following subdirectory under the sample driver directory: TARGET\I386\FREE


Windows 2000 and Windows 95 Differences

Following are the differences between Windows® 95 and Windows NT®/Windows® 2000.

  • The following device state (defined in ISDNTEST.H from the Sample Driver) must be supported for Windows 95: LINEDEVSTATE_REMOVED.
  • The sample driver demonstrates the minimum recommended device state capabilities for Windows 95 compatibility.
  • Differences exist between the Windows NT/Windows 2000 TAPI header files and the Windows 95 TAPI header files that may result in unexpected options or states being sent to the driver. Once such case is ulLineStates of the LINE_DEV_CAPS structure in which Windows 95 supports an extra option. In this case, a driver should be aware of, but quietly ignore these extra options or states.
  • Functions that reside in run-time libraries or the Windows NT/Windows 2000 kernel are not available on Windows 95. This includes the Rtl functions, Kernel functions (for example, KeRaiseIrql, KeInitializeSpinLock, KeQuerySystemTime) and nonintrinsic ANSI C functions. Conversely, drivers should avoid using Windows 95 VMM services since they will reduce portability.
  • The DriverEntry structure passed in cannot be used to override the default device control routine by replacing the IRP_MJ_DEVICE_CONTROL function. Currently, there is not a supported way to access the DeviceIOCtl interface of a PE module under Windows 95.
  • You must use the BINARY_COMPATIBLE flag when compiling drivers for Windows 95.


Windows 3.1 DDK Documentation Release Notes

The Window 3.1 DDK legacy printing documentation is included in its entirety as a convenience for driver writers. While some information may be outdated or obsolete by newer material contained in the Windows 98 documentation, other information may still be pertinent. Programmers are encouraged to refer to this material as required and to supplement the Windows 98 documentation with information presented here.


Introduction

This document describes Microsoft® Windows® UniTool — a new printer-driver development tool which you use to create a Windows printer driver that uses the Microsoft Windows Universal Printer Driver dynamic-link library (UNIDRV.DLL). The printer driver, referred to as a minidriver, contains data which describes the printer's capabilities, commands, and its resident fonts. The code in a minidriver forwards graphics device interface (GDI) calls to the Universal Printer Driver. The Universal Printer Driver carries out the appropriate actions on the device (such as printing text, rendering bitmaps, or advancing a page).


About This Manual

The Microsoft Windows Minidriver Development Guide contains eight sections and four appendixes.

Title | Contents
Overview of Microsoft Windows Printer Drivers | Describes the original and the new printer-driver development environments for Windows.
Getting Started | Describes the setup and installation of the UniTool application and the new driver-development environment.
Specifying Master Units and Minidriver Data | Describes master units, the process used to determine these units, and the process used to specify these units in UniTool.
Specifying Control Information | Describes the process used to specify page-control and cursor-movement commands and data in UniTool.
Specifying Paper Information | Describes the process used to specify paper-size, paper-quality, paper-source, and paper-destination commands and data in UniTool.
Specifying Graphics Information | Describes the process used to specify resolution, compression, color, and rectangle-fill commands and data in UniTool.
Specifying Font Information | Describes the process used to create Printer Font Metric (PFM) files, Character-Translation Tables (CTT), as well as the process used to specify text-quality, font-cartridge, font-simulation, and downloadable-font commands and data in UniTool.
Specifying Printer Model Data | Describes the process used to specify model-specific data such as the supported resolutions, paper sizes, paper sources, font simulations, and so on.
Appendix A Minidriver Callback Functions | Describes two callback functions that a minidriver developer may supply.
Appendix B UniTool Error Messages | Describes the error messages which UniTool issues.
Appendix C Printer Font Metric Data Structure for the Universal Printer Driver | Describes the data structure used by all PFM files that are supported by Windows Universal Printer Driver.
Appendix D Character-Translation Table File Formats | Describes the purpose of a character-translation table (CTT), and how the Universal Printer Driver uses the table.

Sections Specifying Master Units and Minidriver Data through Specifying Printer Model Data contain examples based on the development of minidrivers for the Kodak Diconix 150 Plus, the Hewlett-Packard PaintJet, and the Hewlett-Packard LaserJet IIP printers. The Kodak Diconix printer is an ink-jet printer that uses a command set which is similar to the Epson and IBM dot-matrix printer command set. The Hewlett-Packard PaintJet printer is a color ink-jet printer. The Hewlett-Packard LaserJet IIP printer is a laser printer that uses the Hewlett-Packard Printer Control Language (PCL). Most of the examples that you will see in sections Specifying Master Units and Minidriver Data through Specifying Printer Model Data are based on the Kodak Diconix minidriver and the Hewlett-Packard LaserJet printers; however, the section in Specifying Graphics Information that describes color support is based entirely on the Hewlett-Packard PaintJet.

How to Use This Manual

If you are unfamiliar with printer drivers for Windows, or if you are unfamiliar with the new UniTool application, you should begin by reading Overview of Microsoft Windows Printer Drivers. This section describes printer drivers, their purpose, and their content. It also describes important details about the new printer-driver development environment.

After you've read Overview of Microsoft Windows Printer Drivers section, install the required software and configure the necessary files. Read Getting Started to learn this process.

After you learn the general concepts (described in Overview of Microsoft Windows Printer Drivers) and after you've installed the required software (as described in Getting Started), you're ready to begin initializing the data table for your minidriver. Sections Specifying Master Units and Minidriver Data through Specifying Printer Model Data describe this process.

After you've initialized the data table you can build your minidriver and begin testing it.

Document Conventions

The following conventions are used throughout this manual to define syntax.

Convention | Meaning
Bold text | Denotes a term or character to be typed literally, such as a function name (Control) or a structure (GDIINFO). You must type these terms exactly as shown.
Italic text | Denotes a placeholder or variable: You must provide the actual value. For example, the command sequence (ESC(snS)) requires you to substitute values for n. BEGIN . . . END Represents an omitted portion of a sample application.
Small Caps | Indicate the names of keys, key sequences, and key combinations — for example, ALT + SPACEBAR.
Full Caps | Indicate file names and paths, most type and structure names (which are also bold), and constants.
Monospace | Sets off code examples and shows syntax spacing.


Overview of Microsoft Windows Printer Drivers

This section describes a Microsoft® Windows® printer driver, its function, and its components. This section also describes the old and new printer driver interfaces.


Description of a Printer Driver

A Microsoft® Windows® printer driver is an executable file that performs the tasks in the following list:

  • Retrieves device capabilities and metrics for an application.
  • Prepares the device for printing (by selecting the requested font, graphics resolution, paper orientation, paper source, and so on).
  • Converts GDI calls into device commands which generate output on a page of printer paper.


Loading and Initializing a Printer Driver

Windows loads a printer driver and initializes related data structures when an application creates a printer-device context. There are two large, related data structures: the first describes the printer to GDI, the second describes the application's device context (pens, brushes, fonts, and so on) to the printer driver. These structures are described later in this section.


Interaction Between an Application and the Driver

After a Windows application creates a printer-device context, it can render output on the printer by calling GDI functions.

When an application calls a GDI function, the following occurs

  1. GDI calls the appropriate functions in the driver.
  2. If the function is a query or information function, the driver returns the requested data.
  3. If the function is an output function, the driver creates a device-command string.


The Components of a Printer Driver

A Windows printer driver consists of code and data. The code includes functions which configure the printer, retrieve printer capabilities, and render output. The data includes structures which describe the supported printer resolutions, color capabilities, device-resident fonts, curve-drawing capabilities, line-drawing capabilities, and so on.


Required Printer Driver Functions

All Windows printer drivers must support 24 required functions that are called by Windows GDI. These functions initialize the device, return device data, set the printer mode, and generate output. The following sections briefly describe these functions. For more information about these functions, see the Microsoft Windows Device Driver Adaptation Guide.

Initialization Functions

The initialization functions start and stop print jobs, allocate memory for a driver's data structures, deallocate memory that was used by a driver's data structures, and so on. The following table briefly describes each function.

Function | Description
Control | The Control function performs device-dependent operations such as starting a print job, canceling a print job, processing a new band of bitmap data, and so on.
Disable | The Disable function deallocates memory used by the printer driver's data structures, and unloads the driver from memory if no other device contexts (DCs) exist for this device.
Enable | The Enable function allocates memory for and initializes the members within the driver's PDEVICE data structure. This data structure contains device-dependent data and device-state information.
WEP | The WEP (Windows Exit Program) function signals that the driver DLL will be removed from memory, or signals that Windows is shutting down.

Information Functions

The information functions retrieve color, font, pen, and brush information for a printer. The following table briefly describes each function.

Function | Description
ColorInfo | The ColorInfo function translates physical colors to logical colors and logical colors to physical colors.
DevGetCharWidth | The DevGetCharWidth function returns width values for characters in a given printer font.
DeviceBitmap | The DeviceBitmap function is not supported in the current release of Windows. It must be implemented as a stub function.
EnumDFonts | The EnumDFonts function enumerates the fonts available on a printer.
EnumObj | The EnumObj function enumerates the pens and brushes (if any) which are available on a printer.

Output Functions

The output functions render output on a printer. The following table briefly describes each function.

Function | Description
DevBitBlt | The DevBitBlt function sets pels on a page of printer paper. These pels correspond to bits in a source bitmap.
DevExtTextOut | The DevExtTextOut function renders text as well as a background pattern.
Output | The Output function renders a shape on a page of printer paper.
Pixel | The Pixel function sets a single pel on a page of printer paper.
ScanLR | The ScanLR function sets pels that appear on a single row or scan.
StrBlt | The StrBlt function renders scaled bitmaps.

Attribute Functions

The attribute functions initialize data structures for the printer driver. The following table briefly describes each function.

Function | Description
RealizeObject | The RealizeObject function initializes a data structure for the specified pen, brush, font, and so on.
SetAttribute | The SetAttribute function is not supported in the current release of Windows. It must be implemented as a stub function.

Printer-Mode Functions

The printer-mode functions display special dialog boxes. The following table briefly describes each function.

Function | Description
DeviceMode | The DeviceMode function displays a dialog box that allows a user to select printer options such as paper size, paper orientation, output quality, and so on.
ExtDeviceMode | The ExtDeviceMode function also displays a dialog box that allows a user to select printer options such as paper size, paper orientation, output quality, and so on. Printer drivers written for Windows 3.x and later versions support this function.

Printer-Escape Functions

The printer-escape functions support device-specific operations. The following table briefly describes these functions.

Function | Description
AbortDoc | The AbortDoc escape function signals the abnormal cancellation of a print job.
BandInfo | The BandInfo escape function returns information about a band of bitmap data.
EndDoc | The EndDoc escape function signals the end of a print job.
NextBand | The NextBand escape function prints a band of bitmap data.
QueryEscSupport | The QueryEscSupport escape function specifies whether the driver supports a specified escape.
SetAbortDoc | The SetAbortDoc escape function calls an application's cancellation procedure.
StartDoc | The StartDoc escape function signals the beginning of a print job.

The previous list of printer escapes is a list of escapes supported by the Microsoft Windows Universal Printer Driver (UNIDRV.DLL). It is not a comprehensive list of all Windows escape functions. Most of the escape functions now have equivalent Windows API functions with Windows 3.1. The escapes are supported for backward compatibility, but application developers are encouraged to start using the new API calls.


Required Printer Driver Data Structures

There are two fundamental data structures used by GDI and a Windows printer driver: They are the GDIINFO and the PDEVICE data structures. The members of the GDIINFO data structure are initialized by Windows, and the members of the PDEVICE data structure are initialized by the printer driver.

GDIINFO Structure

The GDIINFO data structure contains device data required by GDI. This structure has the following format:

    typedef struct _GDIINFO {
        int dpVersion
        int dpTechnology
        int dpHorzSize
        int dpVertSize
        int dpHorzRes
        int dpVertRes
        int dpBitsPixel
        int dpPlanes
        int dpNumBrushes
        int dpNumPens
        int futureuse
        int dpNumFonts
        int dpNumColors
        int dpDEVICEsize
        unsigned dpCurves
        unsigned dpLines
        unsigned dpPolygonals
        unsigned dpText
        unsigned dpClip
        unsigned dpRaster
        int dpAspectX
        int dpAspectY
        int dpAspectXY
        int dpStyleLen
        POINT dpMLoWin
        POINT dpMLoVpt
        POINT dpMHiWin
        POINT dpMHiVpt
        POINT dpELoWin
        POINT dpELoVpt
        POINT dpEHiWin
        POINT dpEHiVpt
        POINT dpTwpWin
        POINT dpTwpVpt
        short int dpLogPixelsX
        short int dpLogPixelsY
        short int dpDCManage
        short int dpCaps1
        long int dpSpotSizeX
        long int dpSpotSizeY
        short int dpPalColors
        short int dpPalReserved
        short int dpPalResolution
    } GDIINFO;

This data structure contains three types of data:

  • Driver-management data
  • Driver-capabilities data
  • Driver-dimension data

The driver-management data specifies how GDI should manage multiple device contexts for a given driver.

The driver-capabilities data specifies physical capabilities of the device such as the number of predefined brushes and pens, the number of pure colors that the device supports, the device's curve-, line-, and polygon-rendering capabilities, and so on.

The driver-dimension data specifies the physical dimensions of the printable portion of a piece of printer paper, the number of bits required to represent a single dot on the page, the aspect ratio, and so on.

PDEVICE Structure

The PDEVICE data structure contains data that describes the current device context to the driver. This data includes an identifier for the current device font (if one is selected), a value specifying the output mode (portrait or landscape), an identifier for the selected paper tray, paper size, and so on. The format of this structure is device dependent.


Change in the Printer Driver Interface

The original Microsoft® Windows® printer driver interface required that a driver developer code, test, and debug the 24 required driver functions. This was a time-consuming task that required a thorough understanding of Windows, the Windows Graphics Device Interface (GDI), the printer hardware, and the printer command set. Developers continue to use this interface to develop Windows printer drivers for pen plotters, daisy-wheel printers, Adobe PostScript printers, and printers that use printer-control languages which are similar to PostScript.

The new Windows printer driver interface provides two dynamic-link libraries: UNIDRV.DLL and DMCOLOR.DLL which contain the 24 required functions. (The functions in DMCOLOR.DLL support color printers). By providing these functions, a driver developer no longer needs a thorough understanding of Windows and GDI in order to develop a printer driver. Using the new interface, a developer who understands the hardware and command set for a printer can develop a driver with comparatively little effort. In addition to providing the two dynamic-link libraries, Microsoft also provides the source code for a minidriver. A minidriver is an executable file that forwards calls from the Windows GDI to UNIDRV.DLL. In addition to forwarding GDI calls, the minidriver maintains a collection of data structures which are referred to as the printer's data table. A data table contains data such as the printer's resolution, color capabilities, metrics for device fonts, and so on. A data table also contains the strings which correspond to various printer commands. Using the new Windows application, UniTool (UNITOOL.EXE), a driver developer initializes the structure members in a printer's data table.

It is possible and sometimes necessary for a developer to create a second type of minidriver which contains data and private code. A developer must provide private code whenever the Universal Printer Driver does not provide functionality required by a printer. For example, UNIDRV.DLL expects the pins on a 9-pin dot-matrix printer to be ordered such that the topmost addressable pin corresponds to bit-seven in a byte of graphics data and the bottommost addressable pin corresponds to bit-zero. However, some printers (such as the older Okidata dot-matrix printers) reverse this ordering. The only solution to this and similar problems is to provide developers with the ability to supply private callback functions which perform device-specific operations. A callback function is a developer-supplied function which executes in addition to or in place of one of the Microsoft-supplied Universal Printer Driver functions. For a complete description of the various callback functions, see Appendix A, Minidriver Callback Functions.


UniTool, the Driver Data Table, and Printer Commands

The UniTool application provides an organized means of typing in printer data and command strings that become part of a minidriver's data table. Using this application, its menus, and its dialog boxes, a driver developer specifies data such as the supported text resolutions, graphics resolutions, paper sizes, font metrics, and so on. In addition, a developer specifies the printer commands which begin a document, end a document, select a paper size, select a paper source, reset the printer to its default state, and so on. In addition to specifying the data and commands described above, a developer can use UniTool to create device-font files and character-translation tables.


Driver Resources

The minidriver contains four types of resources:

  • Printer data resources
  • Font data resources
  • CTT data resources
  • String table resources

The first three resource types correspond to three commands which appear in the application's main menu — when you enter values or printer commands in one of the application's dialog boxes, you're actually initializing or altering the data in one of these resources. The fourth resource type, string table, contains strings that were specified in a number of the dialog boxes.

Note These resources are interrelated — when you alter one resource, it is likely that you will also need to alter another. For example, when you create a new font file using the Fonts menu and associated dialog boxes, you will also need to identify that font in the ModelData dialog box to indicate that it is supported by the model. From the Printer Data menu, choose the ModelData command to display the associated dialog box.


Driver Data Table

The driver data table consists of 15 data structures. Following are the

structures and a brief description of each.

Structure | Description
COMPRESSMODE | Identifies a data-compression mode and specifies the printer-command strings which select this mode. This structure also contains the printer-command strings which select the specified compression mode.
CURSORMOVE | Specifies the limitations of the printer's cursor-movement commands. This structure also contains the command strings which move the printer's cursor.
DEVCOLOR | Specifies the printer's color capabilities. This structure also contains the command strings which enable color output.
DOWNLOADINFO | Specifies the printer-command strings which download fonts.
FONTCART | Identifies a font cartridge. This structure also contains the printer-command strings which select the specified cartridge and identifies the fonts on that cartridge.
FONTSIMULATION | Specifies the printer-command strings which enable and disable bold, italic, underline, and strikethrough font simulations.
MODELDATA | Specifies the characteristics of a single printer model. (A single minidriver may support several models of a manufacturer's printer.)
PAGECONTROL | Specifies the printer-command strings which initialize the printer, select the paper orientation, and so on.
PAPERDEST | Identifies a paper output bin that collects pages. This structure also contains the printer command strings which select the specified bin.
PAPERQUALITY | Specifies a media type (that is, plain paper, coated paper, or transparency) on which the printer is capable of printing. This structure also contains the printer-command strings which configure the printer for printing on a particular medium.
PAPERSIZE | Specifies the dimensions of a piece of paper on which the printer is capable of printing. This structure also contains the printer-command strings which configure the printer for the specified paper size.
PAPERSOURCE | Identifies a paper bin or feeding mechanism. This structure also contains the printer-command strings which select the specified paper bin or feeding mechanism.
RECTFILL | Specifies the printer's rectangle-fill capabilities. This structure also contains the command strings which fill rectangular regions.
RESOLUTION | Specifies a horizontal and vertical raster-graphics resolution that the printer supports. This structure also contains the printer-command strings which select the specified resolution.
TEXTQUALITY | Identifies a text quality which the printer supports (that is, draft, near letter, or letter). This structure also contains the printer-command strings which select the specified text quality.

Most of the structures in the printer's data table correspond to one or more of the dialog boxes that appear in the UniTool application. By setting the controls in the dialog boxes, you actually initialize the members of these structures.


Predefined and Driver-Defined Values

A number of the UniTool dialog boxes specify predefined values that correspond to common paper sizes, paper qualities, paper sources, paper destinations, and text qualities. These same dialog boxes also provide a control in which you can type a driver-defined value; you should only specify a private driver-defined value if your printer does not support one of the predefined values. For example, there are five predefined text qualities:

  • Letter quality
  • Near letter quality
  • Memo quality
  • Draft quality
  • Text quality

If the printer for which you are developing a minidriver supports a different text quality, you would type a string identifying that quality in the driver-defined control of the Text Qualities dialog box.

The predefined or driver-defined strings and values which you specify will typically appear when you choose an application's Printer Setup command and Printer Setup Options dialog box.


Device Commands

The structures in the printer data table contain device-command strings. There are three formats that you can use to type command strings in UniTool:

Format | Description
ASCII | Literal ASCII characters can be typed as part of a command string.
Hexadecimal | Hexadecimal values are preceded by the following two characters: \x. For example, the hexadecimal value 0xFF would be typed as \xFF in UniTool.
Formatted parameter | A formatted parameter is a parameter that is supplied by the Universal Printer Driver, and sent to the printer in a format based on the specified conversion characters. These conversion characters are always preceded by the percent (%) character.

The following table contains the conversion characters which are supported by the Universal Printer Driver, as well as a brief description of each.

Character | Description
d | The Universal Printer Driver will convert the parameter to a decimal value. (For example, the value 12 will be sent as '1' (31h) followed by '2' (32h).)
D | The Universal Printer Driver will convert the parameter to a signed decimal value. This is the same as the %d character except it is preceded by a sign.
c | The Universal Printer Driver will convert the parameter to a byte value. (For example, the value 12 will be sent as FF (0Ch))
l | The Universal Printer Driver will convert the parameter to a 16-bit value with the Least Significant Byte (LSB) first. (For example, the value 12 will be sent as FF (0Ch) followed by NULL (00h))
m | The Universal Printer Driver will convert the parameter to a 16-bit value with the Most Significant Byte (MSB) first. This is the same as %l except the order of the bytes is reversed.
q | The Universal Printer Driver will convert the parameter to a unique hexadecimal value formatted for Toshiba and Qume devices.

There are two types of printer commands which you will type in UniTool. The first type enables or disables certain features of the printer. For example, the command string ESCx3 enables letter-quality output of the Kodak Diconix 150 Plus printer. This command (ESCx3) is typed as \x1Bx\x03 in the Text Qualities dialog box. The string ESC was replaced by its ASCII representation (\x1B), the argument x was not altered, and the decimal value 3 was replaced by its hexadecimal equivalent (\x03). The second type of command contains parameters that are supplied by the Universal Printer Driver at runtime (when the command is used). For example, the Immediate Line Feed command for the Diconix printer is used to advance the cursor in the positive y-direction with respect to the current cursor position. The command string for the Immediate Line Feed command has the following syntax:

ESC J n

In this example, n is the number of 1/288th inch increments that the cursor will advance. The ESC string was again replaced by its ASCII representation (\x1B), the argument J was not altered, and the variable n was replaced by the conversion character indicating that it is a byte value (%c).


Master Units

Most printers support commands with a variety of resolutions. For example, the Immediate Line Feed command on the Kodak Diconix printer provides a resolution of 1/288th of an inch while the same printer supports vertical-graphics resolutions of 1/96th of an inch. To simplify the problem of handling various resolutions, the Universal Printer Driver uses a single, common coordinate system. The units in this coordinate system are called master units. Master units are the least common multiple of the various horizontal and vertical resolutions supported by the printer. (For more information about master units, how they are computed, and how they are specified, see Specifying Master Units and Minidriver Data.)

Converting Master Units

The Universal Printer Driver calculates the arguments for some printer commands by adding a value to the specified master units, multiplying the specified master units by a value, or dividing the specified master units by a value. For example, in the case of the Kodak Diconix printer, the vertical master unit is 1/576 of an inch; however, the printer's immediate line-feed command operates in 1/288 inch increments. When using this command, the Universal Printer Driver must convert the argument it supplies from vertical master units to the required units.

UniTool stores each printer command in a Command Descriptor (CD) data structure. In cases where the Universal Printer Driver will need to supply an argument to a particular command, such as the Immediate Line Feed command, UniTool stores additional data in an Extended Command-Descriptor (EXTCD) data structure. This data structure contains values by which the Universal Printer Driver should divide, multiply, increase, or limit command arguments. A special Units dialog box is provided for each printer command. In those cases where the Universal Printer Driver must convert master units, specify the appropriate values in the corresponding Units dialog box. In the case of the Immediate Line Feed command, master units must be divided by 2 prior to setting the parameter, therefore the sUnitDiv control contains the value 2.

The sMax control contains the value 255 (the maximum allowable value for this parameter) and the sMin control contains the value 1 (the minimum allowable value for this parameter). Once you've read this section and understand the fundamental concepts of developing a minidriver, you're ready to set up the development environment. The next section, Getting Started, explains how this is done.


Getting Started

This section describes how you should set up the minidriver-development environment and how you should start the Microsoft® Windows® UniTool application.


Required Hardware and Software

Before you begin developing your driver, you'll need to set up the development environment. This environment includes the following hardware:

  • A 286- or 386-based computer with a clock speed of 16MHz or above.
  • At least 2 megabytes or more of memory (4 megabytes is recommended for 386 enhanced mode).
  • A fast hard disk for compiling and linking.
  • An EGA or VGA display.
  • A Microsoft® Mouse (or any other mouse compatible with Windows®).
  • The printer for which you are creating a minidriver.
  • Printer accessories such as font cartridges, sheet-feeders, paper cassettes, and so on.

The development environment includes the following languages, tools, and software:

  • The Microsoft C Compiler version 6.0.
  • The tools and files included with the Microsoft Windows 3.1 Software Development Kit.
  • The Windows 3.1 retail product and various Windows applications (for debugging and testing the more complicated areas of your driver and device).
  • Two library files (SLIBCEW.LIB and LIBW.LIB). The MS-DOS® LIB environment variable must identify the directory that contains these files.
  • The following include files: PRINT.H, GDIDEFS.INC, MINDRVRC.H, and DECLARE.H. The MS-DOS INCLUDE environment variable must identify the directories that contains these files.
  • The UniTool application (UNITOOL.EXE).
  • The UniTool information file (UNITOOL.INF).
  • The UniTool help file (UNITOOL.HLP).
  • The minidriver source file (MINIDRIV.C).
  • The minidriver makefile (MAKEFILE).


Installing the UniTool Application

In order to run the UniTool application, you'll need to copy certain files from the Microsoft® Windows® Device Driver Kit onto your hard disk. Among these files are UNITOOL.EXE, UNITOOL.INF, and UNITOOL.HLP. The first file is the UniTool application, the second is an information file, and the third is a help file. Because some of these files are compressed, use the expand command to decompress them as you copy them to your hard disk.

Use the following procedure

  1. Copy EXPAND.EXE from the root directory of the minidriver disk to your TOOLS directory on your hard drive, and make sure your path includes this directory. Make sure that the TOOLS directory appears before your DOS directory in the path (MS-DOS® 5.0 has its own expand command).
  2. Copy the include files provided on the disk to the INC directory on your hard drive. These files are compressed; you must use the expand command to decompress the files:
    expand a:\INC\*.* c:\INC
    Make sure that your MS-DOS environment variable, INCLUDE, is set to INC.
  3. Copy the library files provided on the disk to the LIB directory on your hard drive. These files are compressed as well. To expand the files, type:
    expand a:\LIB\*.* c:\LIB
    Make sure that your MS-DOS environment variable, LIB, is set to LIB.
  4. Create a directory on your hard drive called UNITOOL, and copy the files UNITOOL.EXE and UNITOOL.HLP, which are located in the UNITOOL directory on the Minidriver disk to the UNITOOL directory on your hard drive. These files are not compressed. Also, update your MS-DOS path to include this UNITOOL directory.
  5. Copy the file UNITOOL.INF located in the UNITOOL directory on the minidriver disk to your WINDOWS directory. This file must be copied to the WINDOWS directory on your computer. It is not compressed.


Starting UniTool and Creating a Minidriver

Once you have installed the files, you can start UniTool and begin creating a minidriver.

To start UniTool

  1. From the Program Manager File menu, choose the Run command.
  2. Type unitool in the Command Line text box.
  3. Choose the OK button.

Once you have started UniTool, from the File menu, choose the New command. After you choose the New command, the Type of New File dialog box appears in the Main window. Choose the MiniDriver button. UniTool displays a second dialog box that prompts you for the name of your minidriver, the name of the directory in which it will be stored, and the name of the source minidriver. The Source Minidriver list box contains the names of six types of minidrivers:

  • Base Driver
  • Epson 9-Pin Driver
  • Epson 24-Pin Driver
  • IBM 24-Pin Driver
  • HP Driver for HP printers that use Printer Control Language (PCL)
  • HP PaintJet Driver

The selection you make depends on the type of printer for which you are developing a minidriver. If the printer's resolution and command set are compatible with that of a 9- or 24-pin Epson or IBM printer, choose the corresponding entry from the list box. Similarly, if the printer supports Hewlett-Packard printers that use PCL, choose HPPCL Driver. However, if the printer's resolution or command set is unique and differs significantly from the available choices, choose Base Driver.

The new minidriver will be named DICONIX.DRV, its source files will be stored in the C:\driver\minidriv\diconix directory, and these files will actually be modifications of the files for the 9-pin Epson minidriver. (The Diconix printer emulates both Epson and IBM printers; however, the default emulation and the factory switch settings are Epson compatible. Therefore, the Epson 9-Pin Driver was chosen as the minidriver source. However, unlike most 9-pin printers that are Epson compatible, the horizontal and vertical resolutions supported by the Diconix differ from the horizontal and vertical resolutions supported by the Epson printer. This means that it will be necessary to specify new master units for the Diconix minidriver.)

Once you've created your new minidriver directory and installed the appropriate files, you can begin initializing your minidriver's data table. If you've selected the Base Driver as your starting point, or if your printer does not support the same resolutions as one of the compatible minidrivers, it will be necessary to specify master units. See Specifying Master Units and Minidriver Data, for help in accomplishing this task. If, on the other hand, your printer uses the same resolutions as one of the source minidrivers, you can immediately begin specifying control information. See Specifying Control Information, for help in accomplishing this task.


Specifying Master Units and Minidriver Data

Most printers support commands with a variety of resolutions. For example, the Immediate Line Feed command on the Kodak Diconix printer operates with a vertical resolution of 1/288th of an inch while the same printer operates with a vertical-graphics resolutions of 1/96th of an inch. To simplify the problem of handling various resolutions, the Microsoft® Windows® Universal Printer Driver uses a single, common coordinate system. The units in this coordinate system are called master units. Master units are the least-common multiple of the various horizontal and vertical resolutions supported by the printer. The MiniDriver Data dialog box contains controls that you use to specify the vertical and horizontal master units for a printer. From the Printer Data menu, choose the MiniDriverData command.

In addition to specifying master units, this dialog box contains controls to specify a Generic Printer Characterization (GPC) Specification version number, a minidriver version number, the printer's technology, and the absence or presence of a private help file. The GPC Specification refers to the format of data resources contained in the minidriver.


Specification Version Number

The Major box contains the version number of the GPC Specification for which the minidriver was created. For current minidrivers, this control should contain the value 1.

Diconix 150 Plus

The Major box contains the value 1.

HP LaserJet IIP

The Major box contains the value 1.


Minidriver Version Number

The Minor box contains the version number of the minidriver. This value can be any integer between 0 and 255.

If the driver has already been built and installed with Control Panel, changing this value and rebuilding the minidriver will cause the Universal Printer Driver to rebuild the driver's font-summary file. A font-summary file contains a list of fonts currently available for a particular printer model either internally or by the use of downloadable fonts and the font installer. For those printers using a Windows® printer driver that can download soft fonts using a font installer (as with the HP LaserJets and HP DeskJets), the Universal Printer Driver will build a font-summary file.

Diconix 150 Plus

The Minor box contains the value 1, specifying that this is the first version of the minidriver.

HP LaserJet IIP

The Minor box contains the value 41, specifying that this is the forty-first version of the minidriver.


Horizontal Master Units

The Xdpi box contains the value that specifies the horizontal master unit. This value is the least-common multiple of the selected horizontal cursor-movement command and the supported graphics resolutions.

In the example for the Diconix printer, the horizontal master unit is 960 dots per inch (dpi). This value is the least-common multiple of the following graphics and cursor-movement resolutions:

  • 80 dpi (normal/expanded-mode graphics)
  • 160 dpi (normal/expanded-mode graphics)
  • 320 dpi (normal/expanded-mode graphics)
  • 12 dpi (default font-character width)

A minidriver typically supports three graphics resolutions: low, medium, and high. In the case of the Diconix, there are four horizontal graphics resolutions: 80, 96, 160, and 320. Because the 96 dpi resolution does not factor evenly into any of the others, this resolution has not been used. The remaining three values (80, 160, and 320) are used to support horizontal graphics resolutions. In the case of the HP LaserJet IIP printer, each of the supported graphics resolutions (75, 150, and 300) factor evenly into the specified least-common multiple of 300.

Many dot-matrix and laser printers support commands that move the cursor (or print head) horizontally across the page; however, some dot-matrix printers do not. In this case, the Universal Printer Driver uses the space character from the narrowest printer font to move the cursor (or print head) horizontally across the page. (For more information about the horizontal cursor-movement command, see Specifying Control Information.) Because Diconix printer falls into the latter category, the space character from the narrowest printer font (a 12 pitch font) is selected as the horizontal space command. This means that the resolution of the horizontal cursor-movement command for the Diconix printer is 1/12th of an inch.

Diconix 150 Plus

The Xdpi box contains the value 960. This value specifies the least-common multiple of the selected graphics and horizontal-movement resolutions.

HP LaserJet IIP

The Xdpi box contains the value 300. This value specifies the least-common multiple of the selected horizontal resolutions.


Vertical Master Units

The Ydpi control contains the value that specifies the vertical master unit. This value is the least-common multiple of the selected line spacing and graphics resolutions.

In the example for the Diconix printer, the vertical master unit is 576 dpi. This value is the least common multiple of the following line spacing and graphics resolutions:

  • 1/288-inch (line spacing)
  • 1/96-inch (normal-mode graphics)

As mentioned previously, a minidriver for a dot-matrix printer typically supports three graphics resolutions: low, medium, and high. However, in the case of the Diconix printer, there are only two vertical graphics resolutions, and the higher of the two requires that a dip switch in the printer be toggled from its default factory setting. (Minidrivers should ideally support the default switch settings for printers. However, in some cases this may not be possible.) In addition, the higher resolution requires interlaced output in the y-direction. Because the higher resolution would force the user to alter the factory settings and because this higher resolution results in slower printing (due to the interlaced graphics), the lower resolution (96 dpi) was chosen.

The Diconix printer supports six line-spacing commands which provide the following vertical resolutions:

  • 1/8-inch (line spacing)
  • 7/72-inch (line spacing)
  • 7/96-inch (line spacing)
  • 1/6-inch (line spacing)
  • n/216-inch (line spacing)
  • n/288-inch (line spacing)

Of these resolutions, the finest (288 dpi) was chosen for the Diconix.

In the case of the HP LaserJet IIP, the resolution used for the line-spacing command and the vertical resolution for graphics output are equivalent (300 dpi).

Diconix 150 Plus

The Ydpi box contains the value 576. This value is the least common multiple of the 1/288 inch Line Spacing command and the 1/96 inch vertical graphics resolution.

HP LaserJet IIP

The Ydpi box contains the value 300.

Note A printer's aspect ratio is the ratio formed by the x- and the y-printer resolution values. The aspect ratio for most printers is 1 (for example, the HP LaserJet IIP supports a 300 dpi resolution in both the vertical and horizontal directions). However, in the case of the Diconix printer, this ratio is 3.333 (320/96) for the highest resolution. Whenever possible, avoid using aspect ratios greater than 2 in order to produce the highest quality.


Updating the Minidriver Resolution and Measurement Data

A number of the data structures in a minidriver's data table contain measurement values (that is, graphics resolutions, paper sizes, unprintable-region dimensions, line-feed values, and so on). Each of the values is specified in master units. The Update References control indicates whether or not UniTool should update each measurement in each data structure. If this control is checked and you choose the OK button, UniTool will update all measurements; otherwise UniTool will leave the original measurement values. If some of the measurements do not factor evenly into the new master units and the Update References box is checked, UniTool will issue an error message which identifies the faulty value.


Printer Technology

The fTechnology button displays the fTechnology dialog box. This dialog box contains controls that identify the device technology used by the printer. Currently there is only one control in this dialog box: GPC_TECH_PCL4. This control should only be selected if a minidriver uses the HP PCL Level 4 page-description language.

Diconix 150 Plus

The GPC_TECH_PCL4 box is not checked.

HP LaserJet IIP

The GPC_TECH_PCL4 box is checked.


General Information

The fGeneral button displays the fGeneral dialog box. This dialog box contains controls that specify general information about a minidriver. Currently there is only one control in this dialog box: GPC_PRIVATE_HELP. This control should only be selected if a minidriver developer supplies a private help file that should replace the standard help file (UNIDRV.HLP).

Diconix 150 Plus

The GPC_PRIVATE_HELP box is not checked.

HP LaserJet IIP

The GPC_PRIVATE_HELP box is not checked.

Once you have initialized the controls in the MiniDriver Data dialog box, from the Printer Data menu, choose the Control Info command and begin typing information that describes your printer's page-control and cursor-movement commands and capabilities.


Specifying Control Information

This section describes how you should specify page-control and cursor-movement commands and data for your printer. Page-control commands are sent to the printer by the Microsoft® Windows® Universal Printer Driver to begin a document, to begin a page, to end a document, to end a page, to cancel a print job, and so on. Cursor-movement commands are sent to the printer to move the cursor (which is sometimes called the print head) horizontally across the page, vertically down (and sometimes up) the page, and so on.


Specifying Page Control Commands

Each printer provides a unique set of commands that control the printing of a document or a page. These commands are called page-control commands. For example, these commands initialize the device prior to printing a document, initialize the device prior to printing a page, cancel the printing of a document, print multiple copies of a document, and so on.

The PAGECONTROL dialog box contains controls in which you specify these commands as well as controls which specify the order in which the Universal Printer Driver should send the commands to your printer.


Beginning the Document

The PC_OCD_BEGINDOC box contains the printer command or commands which the Universal Printer Driver issues in order to begin printing a document. The commands sent at the beginning of a document should reset the cursor (or print head) to the upper-left corner of a page, clear the printer's buffers, initialize the printer configuration to a known state, and perform any necessary, related tasks. Some common begin-document commands are the printer reset, carriage return, buffer clear, top-of-form, character-set selection, and so on. It is sometimes necessary to set less-common (and less-obvious) commands for particular printers. For example, a raster printer may require unique dip-switch settings for foreign character sets and it may be necessary to insert additional begin-document commands to take these settings into account.

Diconix 150 Plus

For the Diconix 150 Plus, the Reset command (ESC@) returns the printer to the default conditions specified by the current dip-switch settings. The Cancel command (ESC M) deletes all data from the print buffer.

To specify the Reset and Cancel combination, type the following in the PC_OCD_BEGIN_DOC box:

\x1B@\x1BM

HP LaserJet IIP

For the HP LaserJet IIP, the Reset command (ESCE) returns the printer to its default settings and the Perforation Skip command (ESC &l0L) disables the printer's perforation skip feature.

To specify the Reset and Perforation Skip combination, type the following in the PC_OCD_BEGIN_DOC box:

\x1BE\x1B&l0L


Beginning the Page

The PC_OCD_BEGIN_PAGE box contains the printer command or commands that the Universal Printer Driver issues prior to printing each page of a document. For some printers, the begin-page command may be as simple as a single carriage return; for other printers, it may be necessary to send other commands as well.

Diconix 150 Plus

For the Diconix 150 Plus, the Carriage Return command (0x0d) is required to return the cursor (or print head) to the left edge of the page.

To specify the Carriage Return command, type the following in the PC_OCD_BEGIN_PAGE box:

\x0D

HP LaserJet IIP

For the HP LaserJet IIP, no command is required at the beginning of a new page.


Enabing Duplex-On Printing

The PC_OCD_DUPLEX_ON box contains the printer command which the Universal Printer Driver issues to enable duplex (double-sided) printing. The Universal Printer Driver will not process the duplex-on command unless the MD_DUPLEX box is checked in the fGeneral dialog box.

Diconix 150 Plus

The Diconix 150 Plus does not support duplex printing; therefore the PC_OCD_DUPLEX_ON box is empty.

HP LaserJet IIP

For the HP LaserJet IIP, two separate commands are required to enable duplex printing. One command enables duplex printing in portrait mode and the other in landscape mode. These commands are entered in the PC_OCD_DUPLEX_VERT and PC_OCD_DUPLEX_HORZ boxes. The PC_OCD_DUPLEX_ON box is empty.


Ending the Document

The PC_OCD_ENDDOC box contains the printer commands which the Universal Printer Driver issues to end a document. The carriage return is a common end-document command--it's used to position the cursor in the left margin. Other end-document commands vary from printer to printer; however, it is typical to return a printer to its original (or default) state.

Diconix 150 Plus

For the Diconix 150 Plus, the Carriage Return (0x0d) command is required to return the cursor to the left edge of the page after printing a document.

To specify the Carriage Return command, type the following in the PC_OCD_ENDDOC box:

\x0D

HP LaserJet IIP

For the HP LaserJet IIP, the Reset command (\x1BE) is required to reset the printer to its default settings.

To specify the Reset command, type the following in the PC_OCD_ENDDOC box:

\x1BE


Ending the Page

The PC_OCD_ENDPAGE box contains the printer command or commands which the Universal Printer Driver issues to end a page.

Diconix 150 Plus

For the Diconix 150 Plus, no command is required at the end of each page; therefore, the PC_OCD_ENDPAGE box is empty.

HP LaserJet IIP

For the HP LaserJet IIP, no command is required at the end of each page; therefore, the PC_OCD_ENDPAGE box is empty.


Enabling Duplex-Off Printing

The PC_OCD_DUPLEX_OFF box contains the command or commands which the Universal Printer Driver issues to disable duplex (double-sided) printing.

Diconix 150 Plus

The Diconix printer does not support duplex printing; therefore, the PC_OCD_DUPLEX_OFF box is empty.

HP LaserJet IIP

For the HP LaserJet IIP, the Duplex Off command (ESC&l0S) is required to disable duplex printing.

To specify the Duplex Off command, type the following in the PC_OCD_DUPLEX_OFF box:

\x1B&l0S


Canceling the Document

The PC_OCD_ABORT box contains the command or commands which the Universal Printer Driver issues to cancel the current document.

Diconix 150 Plus

For the Diconix 150 Plus, the Reset command (ESC@) returns the printer to its default settings and the Cancel command (ESCM) deletes all data from the print buffer.

To specify the Reset and Cancel combination, type the following in the PC_OCD_ABORT box:

\x1B@\x18

HP LaserJet IIP

For the HP LaserJet IIP, the Reset command (ESCE) returns the printer to its default settings.

To specify the Reset command, type the following in the PC_OCD_ABORT box:

\x1BE


Portrait Mode

The PC_OCD_PORTRAIT box contains the command or commands which the Universal Printer Driver issues to print in portrait mode. A printer should only support the portrait-mode command if it also supports device fonts for both portrait and landscape modes.

Diconix 150 Plus

The Diconix 150 Plus printer does not support commands which set the page orientation; therefore, the PC_OCD_PORTRAIT box is empty.

HP LaserJet IIP

For the HP LaserJet IIP, the Portrait Orientation command (ESC&l0O) is required to render output in portrait mode.

To specify the Portrait Orientation command, type the following in the PC_OCD_PORTRAIT box:

\x1B&l0O


Landscape Mode

The PC_OCD_LANDSCAPE box contains the command or commands which the Universal Printer Driver issues to print output in landscape mode. A printer should only support the landscape-mode command if it also supports device fonts for both portrait and landscape modes.

Diconix 150 Plus

The Diconix 150 Plus printer does not support commands which set the page orientation; therefore, the PC_OCD_LANDSCAPE box is empty.

HP LaserJet IIP

For the HP LaserJet IIP, the Landscape Orientation command (ESC&l1O) is required to render output in portrait mode.

To specify the Landscape Orientation command, type the following in the PC_OCD_LANDSCAPE box:

\x1B&l1O


Multiple Copies

The PC_OCD_MULT_COPIES box contains the command or commands which the Universal Printer Driver issues to print multiple copies of a document. (The Universal Printer Driver will not process the multiple copies command unless the MD_COPIES box is checked in the fGeneral dialog box.)

Diconix 150 Plus

The Diconix 150 Plus printer does not support a command which enables multiple-copy printing; therefore the PC_OCD_MULT_COPIES box is empty.

HP LaserJet IIP

For the HP LaserJet IIP, the Number of Copies command (ESC&lnX) is required to print n copies of a document.

To specify the Number of Copies command, type the following in the PC_OCD_MULT_COPIES box:

\x1B&l%dX


Enabling Vertical-Duplex Printing

The PC_OCD_DUPLEX_VERT box contains the command or commands which the Universal Printer Driver issues to enable vertical-duplex printing. (When pages are printed in vertical-duplex mode, they are printed in such a way that the top and bottom edges of consecutive pages may be bound; when pages are printed in horizontal-duplex mode, they are printed in such a way that the left and right edges of consecutive pages may be bound.)

Diconix 150 Plus

The Diconix 150 Plus printer does not support a command which enables duplex printing in either the vertical or horizontal directions; therefore, the PC_OCD_DUPLEX_VERT box is empty.

HP LaserJet IIP

For the HP LaserJet IIP, the Vertical Duplex command (ESC&l1S) is required to enable vertical duplex printing.

To specify the Vertical Duplex command, type the following in the PC_OCD_DUPLEX_VERT box:

\x1B&l1S


Enabling Horizontal-Duplex Printing

The PC_OCD_DUPLEX_HORZ box contains the command or commands which the Universal Printer Driver issues to enable horizontal-duplex printing.

Diconix 150 Plus

The Diconix 150 Plus printer does not support duplex binding; therefore the PC_OCD_DUPLEX_HORZ box is empty.

HP LaserJet IIP

For the HP LaserJet IIP, the Horizontal Duplex command (ESC&l2S) is required to enable horizontal duplex printing.

To specify the Horizontal Duplex command, type the following in the PC_OCD_DUPLEX_HORZ box:

\x1B&l2S


Maximum Number of Copies

The Max # Copies box specifies the maximum number of copies that the user can request.

Diconix 150 Plus

If a printer does not support multiple copies, this box can be left empty; however, for the sake of clarity, the box contains the value 1 for the Diconix minidriver.

HP LaserJet IIP

The HP LaserJet IIP printer allows a maximum of 99 copies; therefore, the Max # Copies box contains the value 99.


Adding Page-Control Data to Your Driver

Once you've specified the necessary commands and the ordering of those commands, you can add the page-control data to your driver's data table. You can do this by choosing the Add or OK buttons.

The driver-data table contains two types of control information: page-control data and cursor-movement data. Once you've set the controls in the PAGECONTROL dialog box, from the Control Info cascading menu in the Printer Data menu, choose the CursorMove command. You can then begin specifying cursor-movement data.


Specifying Cursor Movement Commands

Each printer provides a unique set of commands that control the vertical and horizontal movement of the cursor (or print head) across the page. These commands are called cursor-movement commands. Some of these commands move the cursor with respect to the current position, or with respect to the page origin, and require information about the distance to be moved. Some of these commands move the cursor a fixed distance (these commands include the carriage return, linefeed, and formfeed). On some printers, the cursor-movement commands are somewhat primitive; for example, horizontal movement can only be achieved by sending a space character from a particular font. On other printers, a single command is available to move the cursor in both horizontal and vertical direction. The coordinate system used by cursor movement commands is based on the origin at the upper-left corner of the page. Positive movement is considered to be moving down the page (for y-movement commands), or moving to the right (for x-movement commands).

The CURSORMOVE dialog box contains controls in which you specify the cursor-movement commands and other related information which the Universal Printer Driver requires.


Absolute-Horizontal Cursor Movement

The CM_OCD_XM_ABS box contains the printer command or commands which move the cursor horizontally with respect to the page origin. For most printers, the corresponding Units dialog box will contain values that the Universal Printer Driver will use to calculate the argument(s) for the absolute horizontal cursor-movement command.

Diconix 150 Plus

The Diconix 150 Plus printer does not support an absolute horizontal cursor-movement command; therefore, the CM_OCD_XM_ABS box is empty.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Horizontal Cursor Positioning command (ESC*pnX) moves the cursor to a new position with respect to the page origin. The variable n specifies a horizontal distance in 1/300 inch units.

To specify the absolute Horizontal Cursor Positioning command, type the following in the CM_OCD_XM_ABS box:

\x1B*p%dX


Relative-Horizontal Cursor Movement

The CM_OCD_XM_REL box contains the printer command or commands which move the cursor horizontally with respect to the current position. By default, the Universal Printer Driver assumes that the CM_OCD_XM_REL command moves the cursor to the right of the current position. If the relative-horizontal

cursor movement command used by your printer allows movement to either the left or right of the current position, set the CM_XM_REL_LEFT bit in the CURSORMOVE fXMove dialog box. For most printers, the corresponding Units dialog box will contain the values that the Universal Printer Driver will use to calculate the argument for the relative-horizontal cursor-movement command arguments from horizontal master units.

Diconix 150 Plus

The Diconix 150 Plus printer does not support a relative horizontal cursor-movement command that moves the cursor in the positive x-direction with respect to the current cursor location; therefore, the CM_OCD_XM_REL box is empty.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Horizontal Cursor Positioning command (ESC*p+nX) moves the cursor to a new position with respect to the current horizontal-cursor location. The plus sign (+) indicates that the movement is in the positive x-direction relative to the current cursor location. The variable n specifies a distance in 1/300 inch units.

To specify the relative Horizontal Cursor Positioning command, type the following in the CM_OCD_XM_ABS box:

\x1B*p+%dX


Relative-Left Cursor Movement

The CM_OCD_XM_RELLEFT box contains the printer command or commands which move the cursor horizontally in the negative x-direction with respect to the current cursor position. This ability is provided for printers that support different cursor-movement commands. For most printers, the corresponding Units dialog box will contain values that the Universal Printer Driver will use to calculate the arguments for the relative left horizontal cursor-movement command.

Diconix 150 Plus

The Diconix 150 Plus printer does not support an horizontal cursor-movement command that moves the cursor in the negative x-direction with respect to the current cursor location; therefore, the CM_OCD_XM_RELLEFT box is empty.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Horizontal Cursor Positioning command (ESC*p-nX) moves the cursor to a new position with respect to the current horizontal-cursor location. The minus sign (-) indicates that the movement is in the negative x-direction relative to the current cursor location. The variable n specifies the distance of movement in 1/300 inch units.

To specify the relative Horizontal Cursor Positioning command, type the following in the CM_OCD_XM_RELLEFT box:

\x1B*p-%dX


Absolute-Vertical Cursor Movement

The CM_OCD_YM_ABS box contains the printer command or commands which move the cursor vertically with respect to the page origin. For most printers, the corresponding Units dialog box will contain values that the Universal Printer Driver will use to calculate the argument for the absolute-vertical cursor-movement command.

Diconix 150 Plus

The Diconix 150 Plus printer does not support an absolute-vertical cursor-movement command; therefore, the CM_OCD_YM_ABS box is empty.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Vertical Cursor Positioning command (ESC*pnY) moves the cursor to a new position with respect to the page origin. The variable n specifies the distance of movement in 1/300 inch units.

To specify the absolute Vertical Cursor Positioning command, type the following in the CM_OCD_YM_ABS box:

\x1B*p%dY


Relative-Vertical Cursor Movement

The CM_OCD_YM_REL box contains the printer command or commands which move the cursor in the positive y-direction with respect to the current position. For most printers, the corresponding Units dialog box contains values that the Universal Printer Driver will use to calculate the argument for the relative-vertical cursor-movement command arguments from vertical master units.

Diconix 150 Plus

For the Diconix 150 Plus printer, the Immediate Line Feed command (ESCJn) moves the cursor by n units in the positive y-direction with respect to the current cursor location. The variable n specifies the distance of movement in 1/288 inch units.

To specify the Immediate Line Feed command, type the following in the CMD_OCD_YM_REL box:

\x1BJ%c

HP LaserJet IIP

For the HP LaserJet IIP printer, the relative Vertical Cursor Positioning command (ESC*p+nY) moves the cursor by n units in the positive y-direction with respect to the current cursor location. The variable n specifies the distance of movement in 1/300 inch units.

To specify the relative Vertical Cursor Positioning command, type the following in the CMD_OCD_YM_REL box:

\x1B*p+%dY


Relative-Up Cursor Movement

The CM_OCD_YM_RELUP box contains the printer command or commands which move the cursor in the negative y-direction with respect to the current position. For most printers, the corresponding Units dialog box will contain values that the Universal Printer Driver will use to calculate the argument for the relative-up cursor-movement command arguments from master units.

NOTE A driver should not attempt to use the CM_OCD_YM_RELUP cursor movement command on a non-laser printer.

Diconix 150 Plus

The Diconix 150 Plus printer does not support a command that moves the cursor back up the page; therefore, the CM_OCD_YM_RELUP box is empty.

HP LaserJet IIP

For the HP LaserJet IIP printer, the relative Vertical Cursor Positioning command (ESC*p-nY) moves the cursor by n units in the negative y-direction with respect to the current cursor location. The variable n specifies the distance of movement in 1/300 inch units.

To specify the relative Vertical Cursor Positioning command, type the following into the CMD_OCD_YM_REL box:

\x1B*p-%dY


Line Spacing Increment Value

The CM_OCD_YM_LINESPACING box contains the printer command or commands which set the line spacing increment value for the printer. This is the amount of increment that occurs at each linefeed. For some printers, the corresponding Units dialog box contains values by which the line spacing increment value command arguments must be multiplied or divided. The Units dialog box also contains values which must be added to command arguments, maximum values for command arguments, and minimum values for command arguments.

Diconix 150 Plus

For the Diconix 150 Plus printer, the Line Spacing command (ESC3n) is required to set the value which the printer will use for subsequent linefeed operations. The variable n specifies a line spacing value in 1/288 inch increments.

To specify the Line Spacing command, type the following in the CM_OCD_YM_LINESPACING box:

\x1B3%c

HP LaserJet IIP

The HP LaserJet IIP printer does not support a command which sets the line-spacing increment value.


Relative Horizontal-and-Vertical Movement

The CM_OCD_XY_REL box contains the printer command or commands which move the cursor horizontally and vertically with respect to the current cursor position. For some printers, the corresponding Units dialog box contains values by which the relative horizontal-and-vertical movement command arguments must be multiplied or divided. The Units dialog box also contains values which must be added to command arguments, maximum values for command arguments, and minimum values for command arguments. This command is not supported by version 1.0 of the Microsoft Windows Universal Printer Driver.


Absolute Horizontal-and-Vertical Movement

The CM_OCD_XY_ABS box contains the printer command or commands which move the cursor vertically and horizontally with respect to the page origin. For some printers, the corresponding Units dialog box contains values by which the relative horizontal-and-vertical movement command arguments must be multiplied or divided. The Units dialog box also contains values which must be added to command arguments, maximum values for command arguments, and minimum values for command arguments. This command is not supported by version 1.0 of the Microsoft Windows Universal Printer Driver.


Carriage Returns

The CM_OCD_CR box contains the printer command or commands which cause a carriage return.

Diconix 150 Plus

For the Diconix 150 Plus printer, the Carriage Return command (0x0D) causes a carriage return.

To specify the Carriage Return command, type the following in the CM_OCD_CR box:

\x0D

HP LaserJet IIP

For the HP LaserJet IIP printer, the Carriage Return command (0x0D) causes a carriage return.

To specify the Carriage Return command, type the following in the CM_OCD_CR box:

\x0D


Linefeeds

The CM_OCD_LF box contains the printer command or commands which cause a linefeed.

Diconix 150 Plus

For the Diconix 150 Plus printer, the Line Feed command (0x0A) causes a linefeed.

To specify the linefeed command, type the following in the CM_OCD_LF box:

\x0A

HP LaserJet IIP

For the HP LaserJet IIP printer, the Line Feed command (0x0A) causes a linefeed.

To specify the Line Feed command, type the following in the CM_OCD_LF box:

\x0A


Formfeeds

The CM_OCD_FF box contains the printer command or commands which cause a formfeed.

Diconix 150 Plus

For the Diconix 150 Plus printer, the Form Feed command (0x0C) causes a formfeed.

To specify the Form Feed command, type the following in the CM_OCD_FF box:

\x0C

HP LaserJet IIP

For the HP LaserJet IIP printer, the Form Feed command (0x0C) causes a formfeed.

To specify the Form Feed command, type the following in the CM_OCD_FF box:

\x0C


Backspacing

The CM_OCD_BS box contains the printer command or commands which cause a backspace. This command is only required for printers that support device fonts which use byte-paired character-translation tables (CTTs). For more information about CTTs, see Creating a Character-Translation Table.

Diconix 150 Plus

For the Diconix 150 Plus printer, the Backspace command (0x08) moves the cursor in the negative x-direction by the width of the current font's space character.

To specify the Backspace command, type the following in the CM_OCD_BS box:

\x08

HP LaserJet IIP

For the HP LaserJet IIP printer, the Backspace command (0x08) moves the cursor in the negative x-direction by the width of the current font's space character.

To specify the Backspace command, type the following in the CM_OCD_BS box:

\x08


Enabling Unidirectional Printing

The CM_OCD_UNI_DIR box contains the printer command or commands which enable unidirectional printing. (In order to enable unidirectional printing, the RES_BO_UNIDIR box in the fBlockOut resolution dialog box must be checked. If this box is not checked, the Universal Printer Driver will ignore these commands.)

Diconix 150 Plus

For the Diconix 150 Plus printer, the Unidirectional Printing On command (ESCU1) enables unidirectional printing.

To specify the Unidirectional Printing On command, type the following in the CM_OCD_UNI_DIR box:

\x1BU\x01


Disabling Unidirectional Printing

The CM_OCD_UNI_DIR_OFF box contains the printer command or commands which disable unidirectional printing. (In order to enable unidirectional printing, the RES_BO_UNIDIR box in the fBlockOut resolution dialog box must be checked. If this box is not checked, the Universal Printer Driver will ignore these commands.)

Diconix 150 Plus

For the Diconix 150 Plus printer, the Unidirectional Printing Off command (ESCU0) disables unidirectional printing.

To specify the Unidirectional Printing Off command, type the following in the CM_OCD_UNI_DIR_OFF box:

\x1BU\x00


Pushing the Stack

The CM_OCD_PUSH_POS box contains the printer command or commands which push the current position onto the printer's internal stack.

Diconix 150 Plus

The Diconix 150 Plus printer does not provide an internal stack for printer commands; therefore, the CM_OCD_PUSH_POS box is empty.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Push Cursor Position command (ESC&f0S) stores the current cursor position on an internal stack.

To specify the Push Cursor Position command, type the following string in the CM_OCD_PUSH_POS box:

\x1B&f0S


Popping the Stack

The CM_OCD_POP_POS box contains the printer command or commands which pops the current position off of the printer's internal stack.

Diconix 150 Plus

The Diconix 150 Plus printer does not provide an internal stack for printer commands; therefore, the CM_OCD_POP_POS box is empty.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Pop Cursor Position command (ESC&f1S) stores the current cursor position on an internal stack.

To specify the Pop Cursor Position command, type the following in the CM_OCD_POP_POS box:

\x1B&f1S


Printer Horizontal-Movement Capabilities

The fXMove dialog box contains controls which you use to specify the horizontal cursor-movement capabilities for a printer. The following lists names of the controls and provides a brief description.

Control | Description
CM_XM_NO_POR_GRX | Specifies that the printer does not support horizontal cursor-movement and in portrait mode.
CM_XM_NO_LAN_GRX | Specifies that the printer does not support horizontal cursor-movement and in landscape mode.
CM_XM_RESET_FONT | Specifies that the Universal Printer Driver must re-select the current font after each horizontal cursor-movement command is issued.
CM_XM_FAVOR_ABS | Specifies that the Universal Printer Driver should send absolute- rather than relative-horizontal cursor movement commands.
CM_XM_REL_LEFT | Specifies that the command specified in the CM_OCD_XM_REL box can move the cursor in both the positive and the negative x-direction.

Diconix 150 Plus

For the Diconix 150 Plus printer, none of the boxes are checked.

HP LaserJet IIP

For the HP LaserJet IIP printer, the CM_XM_NO_POR_GRX box is checked because the printer does not support horizontal cursor-movement commands when in graphics mode and portrait orientation. The CM_XM_FAVOR_ABS box is also checked, indicating that the Universal Printer Driver should send absolute rather than relative horizontal cursor-movement commands.


Printer Vertical-Movement Capabilities

The fYMove dialog box contains controls which you use to specify the vertical cursor-movement capabilities for a printer. The following lists names of the controls and provides a brief description.

Control | Description
CM_YM_FAV_ABS | Specifies that the Universal Printer Driver should send absolute rather than relative y-movement commands.
CM_YM_REL_UP | Specifies that the printer's relative y-movement command will move the print head in both the positive and the negative y-direction.
CM_YM_NO_POR_GRX | Specifies that the printer does not support vertical cursor movement in graphics mode and in portrait orientation.
CM_YM_NO_LAN_GRX | Specifies that the printer does not support vertical cursor movement in graphics mode and in landscape orientation.
CM_YM_CR | Specifies that the Universal Printer Driver should send a carriage-return command to the printer before sending any y-movement commands.
CM_YM_LINESPACING | Specifies that the Universal Printer Driver should use the line spacing command for vertical movement.

Diconix 150 Plus

For the Diconix 150 Plus printer, the CM_YM_CR box is checked to indicate that the Universal Printer Driver should send a carriage-return command prior to sending any y-movement commands. The CM_YM_LINESPACING box is also checked, indicating that the Universal Printer Driver should use the Line Spacing command for vertical movement.

HP LaserJet IIP

For the HP LaserJet IIP printer, the CM_YM_FAV_ABS box is checked to indicate that the Universal Printer Driver should send absolute instead of relative vertical movement commands.


Adding the Cursor-Movement Data to Your Driver

Once you've specified the necessary commands and the ordering of those commands, you should add the cursor-movement data to your driver's data table. You can do this by choosing the Add or OK buttons.

The driver data table contains two types of control information: page-control data and cursor-movement data. Once you've set the controls in both of these dialog boxes, you can begin specifying paper information.


Specifying Paper Information

This section describes how you should specify paper-size, paper-quality, paper-source, and paper-destination commands and data for your printer.


Supported Paper Sizes

After you specify control information for your printer in the PAGECONTROL and CURSORMOVE dialog boxes, you should specify paper-size information. The Paper Sizes dialog box contains controls which you use to specify printer data such as whether a particular paper size is driver defined or predefined, the paper dimensions, the cursor origin, the unprintable-region dimensions, and so on. From the Printer Data menu, choose the Paper Info command, and then the Size command.

Diconix 150 Plus

For the Diconix 150 Plus printer, there are two supported paper sizes. The first is 8.5 x 11 and the second is defined by the user.

HP LaserJet IIP

For the HP LaserJet IIP printer, there are four supported paper sizes and four supported envelope sizes. The following list identifies each:

  • 8.5 x 11 inches
  • Legal (8.5 x 14 inches)
  • Executive (7.25 x 10.5 inches)
  • A4 (210 x 297 millimeters)
  • Envelope #10 (4.125 x 9 inches)
  • Envelope DL (110 x 220 millimeters)
  • Envelope C5 (162 x 229 millimeters)
  • Envelope C3 (324 x 458 millimeters)

The examples in the following sections are based on the first paper size initialized for each minidriver. In both instances, this is for 8.5 x 11 paper.


Specifying Whether the Paper Size Is Predefined or Driver-Defined

The Predefined and Driver Defined buttons specify whether the data that describes the name of a single paper size is selected from the predefined names supplied by the Universal Printer Driver or by the minidriver. This information will be presented to the user (prior to Microsoft® Windows® 3.1, applications had no way of obtaining the name of a paper size other than via its predefined ID value).

Diconix 150 Plus

For the Diconix 150 Plus, the Predefined control is set.

HP LaserJet IIP

For the HP LaserJet IIP, the Predefined control is set.


Predefined Paper Sizes

The Paper Sizes dialog box for predefined paper sizes lists options that identify unique paper sizes. The following list contains these options and a brief description.

Paper-Size String | Description
Letter 8.5 x 11 inches | Identifies a paper size of 8.5 by 11 inches.
Letter Small 8.5 x 11 inches | Identifies a small-letter paper size of 8.5 by 11 inches.
Tabloid 11 x 17 inches | Identifies a tabloid paper size of 11 by 17 inches.
Ledger 17 x 11 inches | Identifies a ledger paper size of 17 by 11 inches.
Legal 8.5 x 14 inches | Identifies a legal paper size of 8.5 by 14 inches.
Statement 5.5 x 8.5 inches | Identifies a statement paper size of 5.5 by 8.5 inches.
Executive 7.5 x 10 inches | Identifies an executive paper size of 7.5 by 10 inches.
A3 297 x 420 millimeters | Identifies the A3 European paper-size which measures 11.88 by 16.8 inches.
A4 210 x 297 millimeters | Identifies the A4 European paper-size which measures 8.4 by 11.88 inches.
A4 Small 210 x 297 millimeters
Identifies the small A4 European paper-size which measures 8.4 by 11.88 inches.
A5 148 x 210 millimeters | Identifies the A5 European paper-size which measures 5.92 by 8.4 inches.
B4 250 x 354 millimeters | Identifies the B4 European paper-size which measures 10 by 14.16 inches.
B5 182 x 257 millimeters | Identifies the B5 European paper-size which measures 7.28 by 10.28 inches.
Folio 8.5 x 13 inches | Identifies the folio paper-size which measures 8.5 by 13 inches.
Quarto 215 x 275 millimeters | Identifies the quarto paper-size which measures 8.6 by 11 inches.
10 x 14 inches | Identifies the 10 by 14 inch paper size.
11 x 15 inches | Identifies the 11 by 15 inch paper size.
Note 8.5 x 11 inches | Identifies the 8.5 by 11 inch paper size.
Envelope #9 3.875 x 8.875 inches | Identifies the #9 envelope-size which measures 3.875 by 8.875 inches.
Envelope #10 4.125 x 9.5 inches | Identifies the #10 envelope-size which measures 4.875 by 9.5 inches.
Envelope #11 4.5 x 10.375 inches | Identifies the #11 envelope-size which measures 4.5 by 10.375 inches.
Envelope #12 4 x 11 inches | Identifies the #12 envelope-size which measures 4 by 11 inches.
Envelope #14 5 x 11.5 inches | Identifies the #14 envelope-size which measures 5 by 11.5 inches.
C size sheet | Identifies the C-size sheet which measures 17 by 22 inches.
D size sheet | Identifies the D-size sheet which measures 22 by 34 inches.
E size sheet | Identifies the E-size sheet which measures 34 by 44 inches.
Envelope DL 110 x 220 millimeters | Identifies the DL envelope-size which measures 4.4 by 8.8 inches.
Envelope C5 162 x 229 millimeters | Identifies the C5 envelope-size which measures 6.48 by 9.16 inches.
Envelope C3 324 x 458 millimeters | Identifies the C3 envelope-size which measures 12.96 by 18.32 inches.
Envelope C4 229 x 324 millimeters | Identifies the C4 envelope-size which measures 9.16 by 12.96 inches.
Envelope C6 114 x 162 millimeters | Identifies the C6 envelope-size which measures 4.56 by 6.48 inches.
Envelope C65 114 x 229 millimeters | Identifies the C65 envelope-size which measures 4.56 by 9.16 inches.
Envelope B4 250 x 353 millimeters | Identifies the B4 envelope-size which measures 10 by 14.12 inches.
Envelope B5 176 x 250 millimeters | Identifies the B5 envelope-size which measures 7.04 by 10 inches.
Envelope B6 176 x 125 millimeters | Identifies the B6 envelope-size which measures 7.04 by 5 inches.
Envelope Monarch 3.875 x 7.5 inches | Identifies the Monarch envelope-size which measures 3.875 by 7.5 inches.
6 3/4 Envelope 3.625 x 6.5 inches | Identifies the 6 3/4 envelope-size which measures 3.625 by 6.5 inches.
US Std Fanfold 14.875 x 11 inches | Identifies the US Standard Fanfold paper-size which measures 14.875 by 11 inches.
German Std Fanfold 8.5 x 12 inches | Identifies the German Standard Fanfold paper-size which measures 8.5 by 12 inches.
German Legal Fanfold 8.5 x 13 inches | Identifies the German Legal Fanfold paper-size which measures 8.5 by 13 inches.

Diconix 150 Plus

For the Diconix 150 Plus printer, the Letter 8.5 x 11 inch string is selected.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Letter 8.5 x 11 inch string is selected.


Specifying Driver-Defined Paper Sizes

The Driver Defined control identifies a driver-defined paper size. If the Driver Defined control is set, the appropriate string describing the name of the paper size should be entered in this box.

Diconix 150 Plus

The example for the Diconix 150 Plus printer is based on a predefined paper size; therefore, this box is empty.

HP LaserJet IIP

The example for the HP LaserJet IIP printer is based on a predefined paper size; therefore, this box is empty.


Paper Width

The X Size box contains a value which specifies the width of the page in master units. If the paper size is predefined, UniTool provides this value; however, if the paper size is defined by the user, the minidriver developer must specify this value.

Diconix 150 Plus

For the Diconix 150 Plus printer, the value that appears in the X Size box is 8160. UniTool determined this value by multiplying the paper width (8.5 inches) by the horizontal master unit (960 dots per inch).

HP LaserJet IIP

For the HP LaserJet IIP printer, the value that appears in the X Size box is 2550. UniTool determined this value by multiplying the paper width (8.5 inches) by the horizontal master unit (300 dots per inch).


Paper Height

The Y Size box contains a value which specifies the height of a page of paper in master units. If the paper size is predefined, UniTool will provide this value; however, if the paper size is defined by the user, you must specify this value.

Diconix 150 Plus

For the Diconix 150 Plus printer, the value that appears in the Y Size box is 6336. UniTool determined this value by multiplying the paper height (11 inches) by the vertical-master unit (576 dots per inch).

HP LaserJet IIP

For the HP LaserJet IIP printer, the value that appears in the Y Size box is 3300. UniTool determined this value by multiplying the paper height (11 inches) by the vertical-master unit (300 dots per inch).


Selecting the Paper Size

The Select String box contains the device command which selects a particular paper size. For laser printers, a device command to select a page size is usually required. For non-laser printers, use a device command to set page size, if the command is available. In either case, if using a page-size selection command, set the PS_EJECTFF bit in the fGeneral dialog box.

Diconix 150 Plus

For the Diconix 150 Plus printer, the default paper size is 8.5 x 11 inches; therefore, no command is required.

HP LaserJet IIP

While some of these individual commands may appear unnecessary, they are used to prevent problems on some particular printers. For the HP LaserJet IIP printer, the Page Size command (ESC&l2A) selects the 8.5 x 11 inch paper size; the Line Spacing command (ESC&l4D) selects a vertical line spacing of 4 lines per inch; the Top Margin command (ESC&l1E) specifies that the top margin is the height of 1 line; and the Text Length command (ESC&l42F) specifies that there are 42 lines per page.

To specify a combination of these commands, type the following in the Select String box:

\x1B&l2a4d1e42F


Unprintable Region Dimensions

One common aspect in printing technology is that many printers do not have the ability to print text and graphics on some portion of the page, referred to as the unprintable region. The reasons for an unprintable region vary according to the individual device. For example, most laser printers have an unprintable region that varies with different page sizes. Many narrow carriage dot matrix printers can only print 8 inches of text or graphics. Additionally, the use of sheet feeders on many non-laser printers can introduce an unprintable region on the top and/or bottom of the page.

In order to obtain correct output when using different combinations of printer models, paper sizes, and paper sources, it is important that a minidriver specify information about the size and placement of the unprintable regions of a printer in the appropriate location in the minidriver.

For more information about limitations imposed by a specific printer model, see Specifying Printer Model Data.

For more information about limitations imposed by a paper-feed method, see Specifying Paper Sources later in this section.

The Unprintable Regions control contains four boxes which specify the size of the unprintable regions at the top, bottom, left, and right side of a particular paper size. The unprintable region described for a paper size is that region where output is clipped as a result of physical limitations imposed by the printer's hardware.

In order to determine the unprintable region for a given paper size, perform several trial-and-error tests. General values may be obtained by following the steps listed below:

To determine the location of the printer's physical boundaries

  1. Create an ASCII text file using a line width that exceeds the paper width and a page length that exceeds the paper height.
  2. Copy the file to the printer.
  3. Measure the distance from the left edge of the paper to the left edge the text.
  4. Measure the distance from the right edge of the paper to the right edge of the text.
  5. Measure the distance from the top of the paper to the first line of text.
  6. Measure the distance from the bottom of the paper to the last line of text.

To determine the unprintable region

  1. Convert the four values obtained above into master units.
  2. Enter these values in the unprintable-region controls.


Verifying the Accuracy of the Unprintable Region Values

Once your minidriver is built and installed, test the accuracy of the values which you entered in the Unprintable Regions boxes. To do this, there are two approaches that may be taken. The first is to use PRNTTEST.EXE, which is included in the Printer Compatibility Test Suite in the Windows 3.1 Device Driver Kit, and run the printable region test provided. The other method requires a Windows graphics or desktop publishing package, and you should follow the steps listed below:

To test the accuracy of the values entered in the Unprintable Regions boxes

  1. Open a Windows graphics or desktop publishing application that will render straight lines the entire length and width of the page.
  2. Render four lines: two horizontal lines and two vertical lines. The top horizontal line should appear one inch below the top of the page, the bottom horizontal line should appear one inch above the bottom of the page, the left vertical line should appear one inch from the left edge of the page and the right vertical line should appear one inch from the right edge of the page.
  3. Print the page.
  4. Examine the intersections of the vertical and horizontal lines.

The lines in the upper-left corner should intersect one inch below the top of the page and one inch from the left edge of the page. If this is not the case, it may be necessary to adjust the cursor origin. For example, if the horizontal line at the top of the page is 1.125 inches from the top and the horizontal line at the bottom of the page is .875 inches from the bottom, it would be necessary to increment the Y cursor origin by .125 inches (if you set the cursor origin in the Paper Sizes dialog box, you must also check the MD_USE_CURSOR_ORG box in the ModelData fGeneral dialog box).

Diconix 150 Plus

For the Diconix 150 Plus printer, the hardware limits the printable page width to 6.875 inches. Because this limit is imposed by the model, and not by the paper size, it is expressed in the ModelData data structure and not in the paper-size data structure. (This same limit applies to any paper size, and is not specific to letter-sized paper.) This means that the left, right, top, and bottom unprintable regions on the Diconix are all set to 0. The size of the unprintable top and bottom margins vary depending upon the paper source. Therefore the sizes of the unprintable top and bottom regions are expressed in the paper-source data structure.

HP LaserJet IIP

For the HP LaserJet IIP printer, the hardware limits the printable-page width to 8.047 inches. This means that the left and right unprintable regions on this printer measure ((8.5 - 8.047)/2) inches or .2267 inches. Converted to horizontal-master units, this value is expressed as (.21875 * 300) or 68--the value entered in the Left and Right boxes of the Unprintable Regions control.

The printer hardware also limits the printable page height to 10.995 inches. This means that the top and bottom unprintable regions on this printer measure ((11 - 10.5)/2) inches or .25 inches. Converted to vertical master units, this value is expressed as (.25 * 300) or 75--the value entered in the Top and Bottom boxes of the Unprintable Regions control.


Cursor Origin

The Cursor Origin group box in the Paper Sizes dialog box contains four controls which specify the cursor-origin coordinates for portrait and landscape mode. These coordinates are specified in master units. By default, the Microsoft Windows Universal Printer Driver aligns the cursor origin with the intersection of the top and left unprintable regions. If it is necessary to alter the origin for your printer, you must also check the MD_USE_CURSOR_ORG box in the ModelData fGeneral dialog box (generally, it is only necessary to set these values for printers that use a page-description language such as the HP PCL printers).

Diconix 150 Plus

For the Diconix 150 Plus printer, the default cursor origin is used for both the portrait and landscape print modes; therefore, the four boxes in the Cursor Origin control are empty.

HP LaserJet IIP

For the HP LaserJet IIP printer, the default cursor origin was used for portrait mode; therefore, the Portrait X box contains the value specified in the Left Unprintable Region box (68) and the Portrait Y box contains the value specified in the Top Unprintable Region box (75). However, the default cursor origin is not satisfactory for landscape mode. In this mode, it is necessary to adjust the cursor origin in order to obtain the desired output on the page. The Landscape X box contains the value 60 and the Landscape Y box contains the value 66.


Specifying General Data

The fGeneral button displays the fGeneral dialog box which contains four checkboxes.

The following list describes the four checkboxes in this dialog box:

Control | Description
PS_CENTER | Specifies that the Universal Printer Driver should center the printable region on the page.
PS_ROTATE | Specifies that the Universal Printer Driver should swap the x- and y- paper-size dimensions (if this control is set, the Universal Printer Driver will not swap the margin widths).
PS_SUGGEST_LNDSCP | Specifies that landscape mode should be the suggested orientation for printing when this paper size is selected.
PS_EJECTFF | Specifies that the Universal Printer Driver can eject a page of this paper size using the form-feed command instead of y-movement commands.

Diconix 150 Plus

For the Diconix 150 Plus printer, none of the boxes are checked.

HP LaserJet IIP

For the HP LaserJet IIP printer, none of the boxes are checked.


Paper Type

The Paper Size and Paper Source dialog boxes contain an fPaperType button that displays an fPaperType dialog box. This dialog box is used to match paper sizes (legal, letter, and so on) to paper sources (trays, bins, or other paper-feed mechanisms). The corresponding bit must be set in both the PAPER SIZE data structure and the PAPER SOURCE data structure for the combination to be valid. The name assigned to each bit is provided for convenience.

The following list describes the four controls in this dialog box.

Control | Description
PS_T_STD | Specifies that this paper size corresponds to the standard paper source.
PS_T_LARGE | Specifies that this paper size corresponds to the large paper source.
PS_T_ENV | Specifies that this paper size corresponds to the envelope paper source.
PS_T_LRGENV | Specifies that this paper size corresponds to the large-envelope paper source.

Diconix 150 Plus

For the Diconix 150 Plus printer, PS_T_STD is selected for the 8.5 by 11-inch paper size. This control is also selected for the tractor-feed and sheet-feed paper sources in the Paper Source dialog box.

HP LaserJet IIP

For the HP LaserJet IIP printer, PS_T_STD is selected for the 8.5 by 11-inch paper size. This control is also selected for the upper bin, lower bin, and manual feed paper sources in the Paper Source dialog box.


Specifying Paper Qualities

The Paper Qualities dialog box is provided for printers such as the HP PaintJet which must regulate the flow of ink based on the paper quality or type (that is, rag, bond, transparencies, and so on).

Neither the Diconix 150 Plus nor the HP LaserJet IIP printer supports a paper-qualities command; therefore, the controls in the respective dialog box for each printer's minidriver are empty.


Specifying Whether the Paper Quality Is Predefined or Driver-Defined

The Predefined and Driver Defined options specify whether the data and commands in the Paper Qualities dialog box correspond to predefined or driver-defined paper qualities. The Predefined and Driver Defined options also specify whether the description of a single paper quality presented to the user is selected from the predefined names supplied by the Universal Printer Driver, or by the minidriver.


Predefined Paper Quality

The Paper Quality Name control which appears adjacent to the Predefined option displays a list box which contains two strings that identify the predefined paper qualities. The following contains these options and a brief description of their meaning.

Control | Description
Paper | Specifies paper as the output medium (as opposed to transparency).
Transparency | Specifies a transparency as the output medium (as opposed to paper).


Driver-Defined Paper Quality

The Paper Quality Name control which appears adjacent to the Driver Defined text in the Paper Quality Name control identifies a driver-defined paper quality.


Selecting the Paper Quality

The Select String control selects the paper quality specified in one of the two Paper Quality Name controls.


Specifying Paper Sources

After you've specified the paper sizes and qualities for your printer, you should specify the paper sources.

Diconix 150 Plus

For the Diconix 150 Plus printer, there are two supported paper sources. The following contains the constants used to identify these sources as well as a brief description of the constant.

Constant | Description
DMBIN_TRACTOR | Specifies tractor-feed capabilities.
DMBIN_MANUAL | Specifies manual-feed capabilities.

HP LaserJet IIP

For the HP LaserJet IIP printer, there are four supported paper sources. The following identifies each.

Constant | Description
DMBIN_UPPER/ONLY | Specifies upper-paper tray capabilities.
DMBIN_ENVMANUAL | Specifies manual envelope-feed capabilities.
DMBIN_MANUAL | Specifies manual-feed capabilities.
DMBIN_LOWER | Specifies lower-paper tray capabilities.

The examples in the following sections are based on the first paper source that was initialized for each minidriver. In the case of the Diconix, the first paper source specifies tractor-feed data; in the case of the HP LaserJet IIP, the first paper source specifies upper-tray data.


Specifying Whether the Paper Source Is Predefined or Driver-Defined

The Predefined and Driver Defined Source Name options specify whether the data and commands in the Paper Sources dialog box are predefined or driver defined. The Predefined and Driver Defined options also specify whether the description of a single paper quality presented to the user is selected from the predefined names supplied by the Universal Printer Driver or by the minidriver.

Diconix 150 Plus

For the Diconix 150 Plus, the Predefined button is selected.

HP LaserJet IIP

For the HP LaserJet IIP, the Predefined button is selected.


Predefined Paper Source

The Source Name box specifies the names of 12 possible paper sources from which one can be selected. The following contains the names and a brief description of each.

Paper Source | Description
DMBIN_UPPER/ONLY | Upper bin
DMBIN_LOWER | Lower bin
DMBIN_MIDDLE | Middle bin
DMBIN_MANUAL | Manual feed
DMBIN_ENVELOPE | Envelope feed
DMBIN_ENVMANUAL | Manual-envelope feed
DMBIN AUTO | Automatic-sheet feeder
DMBIN_TRACTOR | Tractor feed
DMBIN_SMALLFMT | Small-format paper
DMBIN_LARGEFMT | Large-format paper
DMBIN_LARGECAPACITY | Large-capacity bin
DMBIN_CASSETTE | Paper cassette

Diconix 150 Plus

For the Diconix 150 Plus, the primary paper source is the tractor-feed mechanism; therefore, DMBIN_TRACTOR is selected.

HP LaserJet IIP

For the HP LaserJet IIP, the primary paper source is the upper-paper tray; therefore, DMBIN_UPPER/ONLY is selected.


Driver-Defined Paper Source

The Source Name box for driver-defined paper sources contains the name of a unique paper source. This box is provided for printers with paper sources that are not identified in the list of predefined selections.

Diconix 150 Plus

For the Diconix 150 Plus printer, the paper source was predefined; therefore, the driver-defined box is empty.

HP LaserJet IIP

For the HP LaserJet IIP printer, the paper source was predefined; therefore, the driver-defined box is empty.


Selecting the Paper Source

The Select String box contains the printer command or commands which select the paper source identified in the Paper Sources dialog box.

Diconix 150 Plus

For the Diconix 150 Plus printer, the default paper source uses the tractor-feed mechanism; therefore, it was not necessary to select this source.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Paper Source command (ESC&l1H) designates that the upper-paper tray should be used as the paper source.

To specify the Paper Source command, type the following in the Select String box:

\x1B&l1H


Unprintable Regions

The Unprintable Regions control contains two boxes which specify the height of the unprintable regions found at the top and bottom of a page of paper. These values specify the amount of space that becomes unprintable due to the paper-feed mechanism. Typically, sheet feeders will be the only type of paper source that introduces an unprintable region. (These values are not the same values entered in the Paper Sizes dialog box.)

Diconix 150 Plus

For the Diconix 150 Plus printer, the paper-feed mechanism does not create a unique unprintable region; therefore, the Top and Bottom boxes contain the value -1.

HP LaserJet IIP

For the HP LaserJet IIP printer, the paper-feed mechanism does not create a unique unprintable region; therefore, the Top and Bottom boxes contain the value -1.


General Paper Source Information

The fGeneral button displays the fGeneral dialog box. The controls in this dialog box allow you to specify general information relating to the paper-source selection.

The PSRC_EJECTFF box should be checked if the printer ejects a page of paper by sending a form-feed command; the checkbox should not be selected if the printer ejects the page by sending y-movement commands.

The PRSC_MAN_PROMPT box should be checked if the user should be prompted to insert a new piece of paper prior to printing each page.

Diconix 150 Plus

For the Diconix 150 Plus printer, the printer ejects a page by sending a form-feed command; therefore, the PSRC_EJECTFF box is checked.

HP LaserJet IIP

For the HP LaserJet IIP printer, the printer ejects a page by sending a form-feed command; therefore, the PSRC_EJECTFF box is checked.


Specifying Paper Destinations

Previous Next

5.4 Specifying Paper Destinations

After you've initialized the controls in one or more Paper Source dialog boxes for your printer, you should specify paper-destination data and commands in the Paper Destinations dialog box (if your printer supports the ability to control sending output to different destinations).

Neither the Diconix 150 Plus or the HP LaserJet IIP printer supports a paper-destination command (or command set); therefore, the controls in the respective dialog box for each printer's minidriver are empty.


Specifying Whether the Destination Is Predefined or Driver-Defined

The Predefined and Driver Defined options specify whether the data and commands are predefined or driver defined.


Predefined Paper Destination

The Destination Name control contains a listbox that identifies predefined destinations. If the Predefined option is selected, you should choose one of the entries in this list box.


Driver-Defined Destination

The Driver Defined Destination Name option identifies driver-defined paper destinations. If the Driver Defined option is selected, type the name of the of the paper destination in this box.


Selecting the Destination of the Paper

The Select String control contains the printer command which selects the paper destination identified in the Destination Name control.

Once you've typed the appropriate values for the paper destinations which your printer supports, you should begin entering graphics information for your printer.


Specifying Graphics Information

This section describes how you should specify resolution, graphics-data compression, color, and rectangle-fill commands and data for your printer.

In some instances, the sample Diconix 150 Plus and Hewlett-Packard LaserJet IIP minidrivers support multiple sets of commands and data. For example, both minidrivers contain three RESOLUTION dialog boxes. In this section, the first dialog box from any set of multiple dialog boxes is used for the example. In both cases, the first dialog box supports the highest graphics resolution.


Specifying Resolution Data

All printers support one or more horizontal and vertical resolutions for raster graphics output. A resolution is an integer value specified in dots-per-inch (dpi), which indicates the number of distinct dots that the print head or ink-jet can apply along the x- or the y-axis.

The Diconix 150 Plus supports the following three resolutions:

X-resolution | Y-resolution
80 | 96
160 | 96
320 | 96

The HP LaserJet IIP supports the following three resolutions:

X-resolution | Y-resolution
75 | 75
150 | 150
300 | 300

The RESOLUTION dialog box contains controls which you use to specify resolution data such as the text resolution, graphics resolution, color capabilities at a given resolution, methods of sending blocks of graphics data, and so on.


Display Format

The Display Format box contains the conversion specification for the resolution string. The most common conversion specification is %d x %d. Values displayed with this string would appear as the following in a the Print Setup dialog: 320 x 96. In cases where two parameters are supplied in the display format string, the x-resolution will always be enumerated first. For more information about using device commands in UniTool, see Device Commands, in Overview of Microsoft Windows Printer Drivers.

Diconix 150 Plus

For the Diconix 150 Plus printer, the Display Format box contains the following conversion specification:

%d x %d

HP LaserJet IIP

For the HP LaserJet IIP printer, the Display Format box contains the following conversion specification:

%d dots per inch


Scale Factors

The Scale Factors control contains four boxes that specify horizontal and vertical scale factors for raster graphics and text output using device fonts. Unlike all other values specified in the minidriver, the scale factors are expressed in dots per inch rather than master units. However, the values specified must still factor evenly into master units.

Text scale factors are used to describe the resolution at which device fonts were digitized, and graphic scale factors are used to describe the resolution at which individual pixels are placed upon the page. However, since graphic scale factors are tracked internally as logarithmic ratios to text scale factors, graphic scale factors must always either be equal to the text scale factors or equal to a text scale factor divided by a power of 2. For example, a text scale factor of 300 dots per inch may use a graphic scale factor of 300, 150 (300/2), of 75 (300/4), but not a graphic scale factor of 100.

For most laser printers, text and graphics are sent to the printer in separate bands. The coordinates of where each object will be placed in a given band on the page are based upon these scale factors. For example, the HP LaserJet IIP supports one of several resolutions with an x and y text scale factor of 300 dots per inch, and a graphics scale factor of 75 dots per inch. When using this resolution, text printed using device fonts output will be at 300 dpi accuracy, but raster graphic objects output will be at 75 dpi accuracy.

For most dot-matrix and ink-jet printers, text and graphics are sent to the printer in the same band. The coordinates for placement in a given band are based upon the graphic scale factors. For these printers, the text and graphic scale factors should always be the same. Attempting to set different scale factors will not change output quality, and will cause Microsoft® Windows® to not enumerate TrueType fonts when this resolution is selected.

Note TrueType fonts will not be available for those resolutions where the text scale factor does not equal the graphic scale factor unless the driver supports downloading TrueType fonts. For more information about downloading fonts, see Specifying Downloadable Font Commands and Data.

Diconix 150 Plus

For the Diconix 150 Plus minidriver, the text and graphics resolutions are identical; therefore, the X DPI boxes contain the value 320 and the Y DPI boxes contain the value 96.

HP LaserJet IIP

For the HP LaserJet IIP minidriver, the device fonts were digitized at the highest printer resolution (300 dpi); therefore, at the highest graphics resolution, each Scale Factors box contains the value 300.


Graphics Dump Data

The fDump dialog box contains controls which specify how the printer processes bytes of graphics data, whether the printer supports color at the specified resolution. You display the fDump dialog box by double-clicking the fDump entry in the Resolution Bitwords list box.

The following list describes the significance of the controls in the fDump dialog box:

Control | Meaning
RES_DM_GDI | Specifies that each byte of bitmapped data corresponds to 8 consecutive horizontal pixels of bitmapped data. This is the same format used by the Windows Graphics Device Interface (GDI).
RES_DM_LEFT_BOUND | Specifies that the Universal Printer Driver should attempt to minimize the amount of raster data sent to the printer in each band. The Universal Printer Driver will do this by substituting cursor-movement commands in place of white space raster data to the left of the bounding rectangle that contains all the raster data in the band that can be printed. If this bit is not set, the Universal Printer Driver will control horizontal positioning of raster data by moving to the leftmost printing position on the page and padding the null raster data.
RES_DM_COLOR | Specifies that the printer supports color output at the specified resolution.

Diconix 150 Plus

For the Diconix 150 Plus printer, each byte of bitmapped data corresponds to a vertical column (not a horizontal row) of 8 adjacent pixels; therefore, the RES_DM_GDI box is not checked. The optimization described for the RES_DM_LEFT_BOUND bit are preferred, so that bit is checked. This printer does not support color output at any resolution, so the RES_DM_COLOR box is not checked.

HP LaserJet IIP

For the HP LaserJet IIP printer, each byte of data corresponds to 8 consecutive horizontal pixels, so the RES_DM_GDI box is checked. However, this printer does not support color output at any resolution, so the RES_DM_COLOR box is not checked.


Graphics Block Data

The fBlockOut dialog box contains controls which specify how the Universal Printer Driver formats each block of raster-graphic data to be sent to the printer. A block is defined as having a height of n scan lines where n is equal to the sNPins control. (For more information about the sNPins control, see Number of Pins.) The fBlockOut dialog box controls the following bits:

  • Whether the Universal Printer Driver should strip leading, embedded, and trailing blanks from the bitmap data prior to sending the data to the printer.
  • Whether the Universal Printer Driver needs to reset the currently selected device font after printing bitmap data.
  • Whether the printer requires undirectional printing with the specified resolution.
  • Whether the printer cannot fire adjacent pins in the print head.
  • Whether the Universal Printer Driver needs to reset the raster data-compression mode after printing bitmap data.
  • Whether the minidriver provides a callback function which alters bitmap data prior to printing.

The following table briefly describes the controls in the fBlockOut dialog box.

Control | Description
RES_BO_LEADING_BLNKS | Specifies that the Universal Printer Driver should strip any leading, non-printing graphic data from the beginning of each block of raster data sent to the printer.
RES_BO_TRAILING_BLNKS | Specifies that the Universal Printer Driver should strip any trailing, nonprinting graphic data from the end of each block of raster data sent to the printer.
RES_BO_ENCLOSED_BLNKS | Specifies that the Universal Printer Driver should strip any enclosed, nonprinting graphic data from anywhere within each block of raster data sent to the printer, if the number of bytes of nonprinting raster data exceeds that value listed in the sMinBlankSkip control in the RESOLUTION dialog box.
RES_BO_RESET_FONT | Specifies that the Universal Printer Driver should reset the currently selected device font after printing a block of raster-bitmap data.
RES_BO_UNIDIR | Specifies that the Universal Printer Driver should enable unidirectional printing, from the data in the CURSORMOVE dialog box, when using this resolution. Some printers require this for correct horizontal alignment of output.
RES_BO_NO_ADJACENT | Specifies that the Universal Printer Driver should be aware that vertically adjacent pins on the print head may not be fired simultaneously.
RES_BO_RESET_CMP | Specifies that the Universal Printer Driver should reset the raster data-compression mode after entering graphics mode.
RES_BO_CB_FILTER_GRX | Specifies that the Universal Printer Driver should use code provided by the driver to alter raster graphic data.

Note The term strip raster graphics data means that Universal Printer Driver will substitute available cursor-movement commands in place of nonprinting raster-graphic data. This usually results in a performance gain because cursor-movement commands typically require less data when sent to the printer. Most printers will benefit from using the RES_BO_TRAILING_BLNKS bit. However, due to differences in the resolutions of cursor-movement commands and graphics resolutions, care must be exercised when using the RES_BO_LEADING_BLNKS and RES_BO_ENCLOSED_BLNKS bits to ensure that horizontal misalignment of graphic output does not occur.

Diconix 150 Plus

For the Diconix 150 Plus printer, the RES_BO_TRAILING_BLNKS box is checked in order to delete trailing blanks from a bitmap. However, the RES_BO_LEADING_BLNKS and RES_BO_ENCLOSED_BLNKS boxes are not checked because the available methods of moving the cursor do provide a high enough degree of accuracy.

HP LaserJet IIP

For the HP LaserJet IIP printer, the RES_BO_ENCLOSED_BLNKS box is checked in order to delete blanks enclosed in the bitmap. The RES_BO_TRAILING_BLNKS box is also checked in order to delete trailing blanks from a bitmap. However, the RES_BO_LEADING_BLNKS box is not checked. (The performance of HP PCL minidrivers is significantly reduced when this box is checked and the Universal Printer Driver removes leading blanks from a bitmap.)


Graphics Cursor Data

The fCursor dialog box contains controls that describe how the printer positions the cursor after rendering a block of raster data (a block of raster data is a row of bits in a bitmap produced by 1 pass of the print head). In order to enter the graphics cursor data for your printer, you should determine whether the printer positions the cursor after rendering a graphics block by:

  • Aligning it with the left edge of the original row of graphics data.
  • Aligning it with the left edge of the page.
  • Aligning it with the start of the next block of graphics data.
  • Aligning it with the origin of the new graphics data (PCL only).

If, after printing a block of data, your printer aligns the cursor with the left edge of the original block, set the RES_CUR_X_POS_ORG control. If, after printing a block of data, your printer aligns the cursor with the left edge of the printable region, set the RES_CUR_X_POS_AT_0 control. If, after printing a block of data, your printer also moves the cursor in the positive y direction to the next block, set the RES_CUR_Y_POS_AUTO control.

If your printer uses the Hewlett-Packard Printer Control Language (PCL), and you have checked the RES_BO_ENCLOSED_BLNKS box in the fBlockOut dialog box, you should also check the RES_CUR_CR_GRX_ORG box in the fCursor dialog box. (This is because PCL printers redefine the left edge of a block of graphics data when internal blanks are removed. By setting the RES_CUR_CR_GRX_ORG box, you set a flag that informs the Universal Printer Driver that it must reset the left-edge coordinates.)

Diconix 150 Plus

For the Diconix 150 Plus printer, none of the boxes are checked.

HP LaserJet IIP

For the HP LaserJet IIP printer, the RES_CUR_X_POS_ORG box is checked because the printer aligns the cursor with the left edge of the original block after rendering a row of data. The RES_CUR_Y_POS_AUTO box is checked because the printer moves the cursor to the start of the next row of data. The RES_CUR_GRX_ORG box is checked because the RES_BO_ENCLOSED_BLNKS box is checked in the fBlockOut dialog box.


Number of Pins

The sNPins box in the RESOLUTION dialog box contains a value that specifies the minimum height (in pixels) of lines of raster data that the Universal Printer Driver will evaluate at one time. This is typically, but not always, the number of pins (or jets) used by the printer for each vertical slice of graphic output produced by one pass of the print head. When the value of sNPins is equal to the value of sPinsPerPass, this is referred to as noninterlaced graphics output.


Interlaced Graphics

In some cases it is possible to create a higher resolution than a native one by vertically interlacing graphics (rendering each block of graphics data in two passes). In order to accomplish this, the printer must support a vertical cursor-movement command that uses a resolution at least twice as fine as the native vertical-graphics resolution being used. The Universal Printer Driver accomplishes this by sending the first block of raster data as normal, but during the second pass, the print-head position is incremented in the y-direction by a value that is less than or equal to the height of a single pin or jet. In order to render bitmaps correctly, the Universal Printer Driver requires the number of pins used by the printer for interlaced graphics. If the height of a block of graphics data is less than the height of the specified pins, the Universal Printer Driver will add null graphics data to the block.

An example of this is found in many 9-pin dot-matrix drivers. Typically, a 9-pin printer will support a 240 X 72 dpi resolution as its highest native mode, but also has a vertical-movement command that operates in 1/144 inch. The Universal Printer Driver may support a 240 X 144 dpi resolutions if the driver sets sPinsPerPass to 8 (the number of pins fired in one pass), sets sNPins to 16 (the number of pins fired in two passes), and supports the 1/144-inch vertical command.

Diconix 150 Plus

For the Diconix 150 Plus printer, the sNPins box contains the value 8; this is the number of jets used by the printer for noninterlaced graphics.

HP LaserJet IIP

For the HP LaserJet IIP printer, the sNPins box contains the value 1.


Vertical Text Offset

The sTextYOffset box contains a value that specifies the difference between the baseline of printer fonts and the baseline of GDI fonts. If the baseline of device fonts differs from the baseline of GDI fonts and an application mixes the two fonts on a line, the text will appear uneven. In order to prevent this from occurring, the Universal Printer Driver requires a value that specifies the difference between the two baselines. This value is specified in master units.

Diconix 150 Plus

For the Diconix 150 Plus printer, the baseline of printer fonts is identical to the baseline of GDI fonts; therefore, the sTextYOffset box contains the value zero.

HP LaserJet IIP

For the HP LaserJet IIP printer, the baseline of printer fonts is identical to the baseline of GDI fonts; therefore, the sTextYOffset box contains the value zero.


Minimum Number of Blanks

The sMinBlankSkip box contains a value that specifies the minimum number of bytes of null data that must occur before the Universal Printer Driver begins removing embedded blanks from the block of bitmap data. If you use the Universal Printer Driver to remove most of the null raster data sent to the printer to reduce data transmission, printing and performance time may increase if this value is too small due to print-head movement when switching from graphics mode to cursor movement commands. It is suggested that dot-matrix minidrivers use values no smaller than the number of bytes of raster data required for 2 inches of output.

Diconix 150 Plus

For the Diconix 150 Plus printer, the sMinBlankSip box contains the value zero.

HP LaserJet IIP

For the HP LaserJet IIP printer, the sMinBlankSkip box contains the value 32; this means that the Universal Printer Driver will not strip blank data from a bitmap unless there are at least 32 consecutive NULL bytes.


Spot Diameter

The sSpotDiameter box contains a value that specifies a special value used by the Universal Printer Driver to rasterize graphic data and compensate for overlapping pixels. The value entered will affect the lightness or darkness of printed raster-graphic images. The user can adjust this setting through Control Panel. Double-click on the Printers icon in Control Panel, choose the Setup button in the Printers dialog box, and choose the Options button to display the Options dialog box. The user can adjust the intensity of printed output using the Intensity scroll bar in the Options dialog box. The following table lists spot diameters for common resolutions supported by 9-pin, 24-pin, and ink-jet printers.

Printer | Resolution | Diameter
9-pin | 240 x 144 | 170
 | 120 x 144 | 140
 | 120 x 100 | 100
24-pin | 360 x 180 | 170
 | 180 x 180 | 140
 | 120 x 180 | 120
Ink-Jet | 360 x 360 | 100
 | 180 x 180 | 100
 | 120 x 180 | 100

Diconix 150 Plus

For the Diconix 150 Plus printer, the sSpotDiameter box contains the value 100.

HP LaserJet IIP

For the HP LaserJet IIP printer, the sSpotDiameter box contains the value 100.


Select Resolution

The Select Resolution box contains the command which selects the designated printer resolution.

Diconix 150 Plus

The Diconix 150 Plus printer integrates the selection of the resolution with the Send Block command; therefore this box is empty.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Raster Graphics Resolution command (ESC*tnR) selects the resolution for graphics output where n specifies a resolution of 75, 100, 150, or 300 dpi. To specify the Select Resolution command for 300 dpi graphics, type the following in the Select Resolution box:

\x1B*t300R


Begin Graphics

The Begin Graphics box contains the command which is sent to the printer to enable graphics output. (Those printers that provide a specific command to select a graphics resolution may also provide a command to enter graphics mode.)

Diconix 150 Plus

The Diconix 150 Plus printer automatically begins rendering graphics when it receives a Send Block command; therefore, the Begin Graphics box is empty.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Start Raster Graphics command (ESC*rnA) signals the start of raster graphics and specifies the location of the left margin. If n is 1, the current cursor location defines the left margin for the graphics output; if n is 0, the left edge of the page defines the left margin for the graphics output.

To specify the Start Raster Graphics command using the current cursor location as the left margin, type the following in the Begin Graphics box:

\x1B*r1A


End Graphics

The End Graphics box contains the command which is sent to the printer to disable graphics output. (Those printers which provide a specific command to disable a graphics resolution may also provide a command to end the processing of graphics data.)

Diconix 150 Plus

The Diconix 150 Plus printer automatically ends graphics output after it processes the last byte of graphics data; therefore, this control is not initialized.

HP LaserJet IIP

For the HP LaserJet IIP printer, the End Raster Graphics command (ESC*rB) disables raster graphics output. To specify the End Raster Graphics command, type the following in the End Graphics box:

\x1B*rB


Send Block

The Send Block box contains the command which processes or sends one or more blocks (or rows) of graphics data.

Diconix 150 Plus

For the Diconix 150 Plus printer, the Quadruple-Density 8-Bit Graphics command (ESCZn1n2d1...dn) processes multiple blocks (that is, an entire bitmap) at the 320 x 96 dpi resolution. The arguments n1 and n2 specify the total number of bytes of graphics data: n1 is the remainder when this number is divided by 256, and n2 is the quotient. The arguments d1 through dn represent the actual bytes of graphics data.

To specify the Quadruple-Density 8-Bit Graphics command, type the following in the Send Block box:

\x1BZ%l

HP LaserJet IIP

For the HP LaserJet IIP printer, the Transfer Raster Data command (ESC*bnW) processes a single block of raster data at the specified resolution. The argument n specifies the count of bytes of raster data.

To specify the Transfer Raster Data command, type the following in the Send Block box:

\x1B%dW


Adding Resolution Data to Your Minidriver

Once you've specified:

  • Display format
  • Scale factors
  • Dump data
  • Block data
  • Cursor data
  • Dither data
  • Minimum bitmap height
  • Vertical text offset
  • Spot diameter

you should add this data to the minidriver's data table. In order to do this, choose either the Add Res or the OK pushbuttons. There are four Graphics Info commands: Resolution, Compression, Color, and RectFill. Now that you've initialized the Resolution component, you should select the Compression option in the Graphics Info menu and enter the appropriate data for your printer.


Specifying Graphics Compression Data

Some printers support the ability to receive raster-graphic data in a compressed format, which typically results in increased performance. The increased performance is due to the reduced amount of data that needs to be sent to the printer to print bitmaps. If your printer supports compression of graphics data (that is, bitmaps) using run-length encoding (RLE) or Tag Information File Format (TIFF) version 4.0, you should specify the related data and commands in the Compression Modes dialog box. This dialog box contains controls which identify the compression scheme, specify the Begin Compression command, and specify the End Compression command. The Universal Printer Driver version 1.0 only supports TIFF 4.0 compression.

The Diconix 150 Plus printer does not support data compression; the HP LaserJet IIP printer supports both run-length encoding and TIFF. The LaserJet examples are based on the dialog box that contains commands for TIFF encoding.


Compression Type

The Compression Type box identifies the type of compression commands which appear in the dialog.

Diconix 150 Plus

The Diconix 150 Plus printer does not support compression; therefore the Compression Type box is empty.

HP LaserJet IIP

The HP LaserJet IIP printer supports run-length encoding as specified in the Compression Type box.


Begin Compression

The Begin Compression box contains the printer command which enables the compression of graphics data.

Diconix 150 Plus

For the Diconix 150 Plus printer, the Begin box is empty.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Set Compression Mode command (ESC*bnM) enables and disables various types of graphics compression. If n is 0, graphics compression is disabled; if n is 1, run-length encoding is enabled; if n is 2, TIFF encoding is enabled; and if n is 3, delta-row compression is enabled.

To specify the Set Compression Mode command to enable run-length encoding, type the following in the Begin box:

\x1B*b1M


End Compression

The End Compression box contains the printer command which disables the compression of graphics data.

Diconix 150 Plus

For the Diconix 150 Plus printer, the End box is empty.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Set Compression Mode command (ESC*bnM) enables and disables various types of graphics compression. If n is 0, graphics compression is disabled; if n is 1, run-length encoding is enabled; if n is 2, TIFF encoding is enabled; and if n is 3, delta-row compression is enabled.

To specify the Set Compression Mode command to disable TIFF encoding, type the following in the Begin box:

\x1B*b0M


Specifying Color Support

Most printers support one of two color methods: planar or pixel. Devices which use the pixel method send all of the RGB data for a single pixel at once, typically using at least two bytes per single pixel. The Universal Printer Driver does not support color on printers which require color-raster graphic data using the pixel method.

Printers which use the planar method send the color data for a single pixel in several passes (planes). The value that results from combining the data for one pixel in each plane determines the color that pixel will assume. Devices that use the planar method typically use 3 or 4 color planes. A three-plane model represents cyan data in one plane, yellow data in a second plane, and magenta data in a third plane. By combining inks from these three basic colors (Cyan, Yellow, and Magenta), the device is able to render images of up to eight colors. A four-plane model is identical to the three-plane model except for the addition of a fourth plane that represents black data. (In the three-plane model, cyan, yellow, and magenta ink is combined in equal parts to create black output.)

Until recently, most color printers used planar models to represent color images; therefore, the current version of the DMCOLOR library and the UniTool application support this model (rather than the pixel model). A minidriver developer can provide a callback function to convert planar color data into pixel color data; however, in some instances, the converted data will not take advantage of a printer's color-output capabilities. For example, DMCOLOR allows a maximum of eight colors (Cyan, Blue, Magenta, Red, Yellow, Green, White, and Black). This means that DMCOLOR converts any 256-color pixel image into an 8-color planar image. If a printer is capable of supporting 256 colors, it would not be able to display the original image, even if it provided the callback function. Obviously, some printers are better supported by the original Microsoft® Windows® driver interface.

The DEVCOLOR dialog box contains controls which you use to specify the color capabilities of printers that render color output. These controls allow you to specify values such as the number of color planes supported by printers that use a color-plane format, the number of bits per pixel supported by printers that use a bit-per-pixel format, the device commands which select colors, and so on. Because neither the Diconix nor the HP LaserJet IIP printers provide color support, this section contains information for an additional printer — the Hewlett-Packard PaintJet.


Number of Color Planes

The sPlanes box contains a value that specifies the number of color planes supported by the printer.

HP PaintJet

For the PaintJet printer, the sPlanes box contains the value 3.


Number of Bits per Pixel

The sBitsPixel box contains a value that specifies the number of bits of data required for each color pixel.

HP PaintJet

For the Hewlett-Packard PaintJet printer, 1 bit in each plane corresponds to a single pixel; therefore, the sBitsPixel box contains 1.


General Color Data

Choosing the fGeneral button displays the fGeneral dialog box. This dialog box contains three boxes which specify general color capabilities for a printer.

The following table provides a brief description each control.

Control | Description
DC_PRIMARY_RGB | If this bit is set, sPlanes must equal 3 with the Universal Printer Driver. The Universal Printer Driver will first send data for the red plane, followed by the blue and green planes. The printer will then convert this data into an index into its own color palette to obtain the 8 basic colors. If this bit is not set, the Universal Printer Driver sends black data first (only if the DC_EXTRACT_BLACK bit is set, followed by data for the cyan, magenta and yellow planes.)
DC_EXTRACT_BLK | If this bit is set, sPlanes must equal 4. This control specifies that the printer renders black using a separate ink or ribbon. (If this control is not set, the Universal Printer Driver assumes that the printer renders black by mixing the other colors.)
DC_SEND_CR | Specifies that the Universal Printer Driver must send a carriage return to clear the output buffer prior to processing the next plane of color-raster data.

HP PaintJet

For the HP PaintJet printer, the DC_PRIMARY_RGB box is checked since the printer uses the RGB color model.


Color-Plane Selection

The Planes Colors control contains four boxes which specify the commands that render the color graphics output.

HP PaintJet

For the Hewlett-Packard PaintJet printer, the 1st Plane and 2nd Plane boxes contain the Transfer Raster Data by Plane command (ESC*bnV) where n specifies the number of bytes of raster data.

To specify the Transfer Raster Data by Plane command, type the following in the 1st Plane and 2nd Plane controls:

\x1B*b%dV

The 3rd Plane box contains the Transfer Raster Data by Row command (ESC*bnW). This command differs from the previous command in that it moves the current active position (CAP) to the next row of data.

To specify the Transfer Raster Data by Row command, type the following in the 3rd Plane control:

\x1B*b%dW

Because the PaintJet printer uses three-plane technology, the 4th Plane box is empty.

Note If the DC_PRIMARY_RGB bit is set in the fGeneral dialog box, the Universal Printer Driver will use the device commands to send a color plane of graphics data instead of sending block commands from the resolution section when color is enabled.


Text-Color Selection

The Text Color control contains four boxes which specify the commands that render the color text output.

HP PaintJet

For the HP PaintJet printer, the Black, Red, Green, and Yellow boxes contain the corresponding Text Color command (ESC&vnS) which renders text using the specified color. If n is 0, the text color is black; if n is 1, the text color is red; if n is 2, the text color is green; if n is 3, the text color is yellow, and so on.

To select black text, type the following Text Color command in the Black box:

\x1B&v0S

To select red text, type the following Text Color command in the Red box:

\x1B&v1S

To select green text, type the following Text Color command in the Green box:

\x1B&v2S

To select yellow text, type the following Text Color command in the Yellow box:

\x1B&v3S

To select blue text, type the following Text Color command in the Blue box:

\x1B&v4S

To select magenta text, type the following Text Color command in the Magenta box:

\x1B&v5S

To select cyan text, type the following Text Color command in the Cyan box:

\x1B&v6S

To select white text, type the following Text Color command in the White box:

\x1B&v7S


Color Mode Control

The ocdSetColorMode control contains the command or commands which are required to initialize a printer to process color data.

HP PaintJet

For the PaintJet printer, the Set Number of Planes Per Row command (ESC*rnU) is required to initialize the printer for color data processing. The argument n specifies the number of planes of color data.

To specify the Set Number of Planes Per Row command, type the following in the ocdSetColorMode box:

\x1B*r3U

After you specify the color-selection commands for your printer, from the Printer Data menu, choose the Graphics Info cascading menu. From the Graphics Info menu, choose the RectFill command. You can then begin entering rectangle-fill commands and data.


Specifying Rectangle-Fill Capabilities

The RECTFILL dialog box contains controls which specify rectangle-fill data and commands for printers with rectangle-fill capabilities. Typically, the only printers which provide these capabilities are printers that support a page-control language such as the Hewlett-Packard PCL. The data supplied in the RECTFILL dialog box describes the printer's minimum and maximum gray levels, the cursor position at the conclusion of a rectangle-fill operation, and so on. The commands supplied in the RECTFILL dialog box specify the rectangle's dimensions and fill pattern.


Minimum Gray Level

The wMinGray box contains the minimum percentage value that the Universal Printer Driver can pass as an argument in the printer's gray-fill command.

Diconix 150 Plus

The wMinGray box is empty.

HP LaserJet IIP

For the HP LaserJet IIP printer, the minimum percentage of black pixels is 1. (This means that there is 1 black pixel for every 99 white pixels in the minimum shade or fill pattern.)


Maximum Gray Level

The wMaxGray box contains the maximum value that the Universal Printer Driver can pass as an argument in the printer's gray-fill command.

Diconix 150 Plus

The wMaxGray box is empty.

HP LaserJet IIP

For the HP LaserJet IIP printer, the maximum percentage of black pixels is 100. (This means that there are 100 black pixels and 0 white pixels in the maximum shade or fill pattern.)


General Data

Choosing the fGeneral button displays the fGeneral dialog box. This dialog box contains four boxes which specify general rectangle-fill data.

The following table provides a brief description of each box.

Box | Description
RF_WHITE_ABLE | If this box is checked, the printer supports a white-fill command; if this box is not checked, the printer does not support this command.
RF_MIN_IS_WHITE | If this box is checked, the minimum gray scale supported by the printer is actually white; if this box is not checked, the minimum gray scale contains black pixels.
RF_CUR_X_END | If this box is checked, the cursor is aligned with the right edge of the rectangle after a rectangle-fill operation occurs. If this box is not checked, the cursor is positioned at the rectangle origin after the fill occurs.
RF_CUR_Y_END | If this box is checked, the cursor is aligned with the bottom edge of the rectangle after a rectangle-fill operation occurs. If this box is not checked, the cursor is positioned at the rectangle origin after the fill occurs.

Diconix 150 Plus

None of the boxes are checked.

HP LaserJet IIP

The RF_WHITE_ABLE box is checked to indicate that the HP LaserJet IIP can use the White-fill command.


Rectangle Width

The X Size box contains the printer command which sets the rectangle width.

Diconix 150 Plus

For the Diconix 150 Plus printer, the X Size box is empty.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Horizontal Rectangle Size command (ESC*cnA) specifies the rectangle's width in 1/300 inch units. The argument n specifies the number of units.

To specify the Horizontal Rectangle Size command, type the following in the X Size box:

\x1B*c%dA


Rectangle Height

The Y Size box contains the printer command which sets the rectangle height.

Diconix 150 Plus

For the Diconix 150 Plus printer, the Y Size box is empty.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Vertical Rectangle Size command (ESC*cnB) specifies the rectangle's height in 1/300 inch units. The argument n specifies the number of units.

To specify the Vertical Rectangle Size command, type the following in the Y Size box:

\x1B*c%dB


Filling a Rectangle with Gray

The Gray Fill box contains the printer command or commands which fill a rectangle with a shade of gray.

Diconix 150 Plus

For the Diconix 150 Plus printer, the Gray Fill box is empty.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Area Fill ID and the Fill Rectangular Area commands are combined into a single command. The Area Fill ID command (ESC*cnG) specifies the shade of gray, and the Fill Rectangular Area command (ESC*cnP) fills a rectangular area.

For the Area Fill ID command, n specifies the percent of shading. For the Fill Rectangular Area command, n specifies the type of fill. The following lists the type of fill and its value.

Value | Fill
0 | Black
1 | White
2 | Shading
3 | Cross-hatch
5 | Current pattern

To specify the combination, type the following in the Gray Fill box:

\x1B*c%dG2P


Filling a Rectangle with White

The White Fill box contains the printer command or commands which fill a rectangle with white.

Diconix 150 Plus

The White Fill box is empty.

HP LaserJet IIP

The White Fill box is empty.


Specifying the Hatch Pattern

The Hatch Fill box contains the printer command or commands which fill a rectangle with a hatched pattern.

Diconix 150 Plus

For the Diconix 150 Plus printer, the Hatch Fill box is empty.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Area Fill ID and the Fill Rectangular Area are combined into a single command. The Area Fill ID command (ESC*cnG) specifies the hatch pattern and the Fill Rectangular Area command (ESC*cnP) fills a rectangular area. The argument n specifies the hatch pattern is the Area Fill ID command; n specifies the type of fill in the Fill Rectangular Area command. The following table contains the command and its respective values and patterns.

Command | Value | Hatch or Fill
Area Fill ID | 1 | Horizontal hatch pattern
 | 2 | Vertical hatch pattern
 | 3 | Right-diagonal hatch pattern
 | 4 | Left-diagonal hatch pattern
 | 5 | Horizontal and vertical cross-hatch pattern
Fill Rectangular Area | 0 | Black
 | 1 | White
 | 2 | Shading
 | 3 | Cross hatch
 | 5 | Current pattern

To specify the combination, type the following in the Hatch Fill box:

\x1B*c%dG3P

Once you've entered the appropriate values in the rectangle-fill dialog boxes, you should begin entering font information for your printer.


Specifying Font Information

This section describes how you should specify font information for your printer. This information includes the Printer Font Metric (PFM) file, the Character-Translation Table (CTT), the text-quality commands and data, the font-cartridge commands and data, the font-simulation commands and data, and the downloadable-font commands and data.


Specifying Printer Font Metrics

Printers render text using one of two types of fonts: device fonts or fonts provided by Windows. The two fonts differ with respect to the location of the font's character data. The character data for device fonts is stored in the printer or in a detachable font cartridge. The character data for a Microsoft® Windows® font is stored on disk. This means that printers render text faster with device fonts because the bitmap or vector data is resident on the device, and does not require downloading from disk to the printer.

In order to render text with device fonts and in order to retrieve font data for application queries, the Microsoft Windows Universal Printer Driver requires special font data or printer font metrics. This data is stored in a PFM file. The data includes:

  • A bit flag specifying whether the font is a bitmap or a vector font
  • The point size
  • The resolutions at which the font was digitized
  • The leading values
  • The font name
  • The printer command which selects the font
  • The printer command which cancels the selection of the font

The PFM dialog box contains controls in which you specify a printer's font-metrics and font-selection commands. The examples in the following sections are based on a 12-pitch device font for the Diconix 150 Plus printer.

The Microsoft Windows Device Driver Adaptation Kit also contains a Printer Font Metrics (PFM) Editor for editing fonts. For more information about the editor, see the Microsoft Windows Printers and Fonts Kit.


Font Type

The Type control contains the decimal representation of a 16-bit flag. The following list describes the significance of the bits in this flag. Bit 15 is the high-order bit of the high byte; bit 0 is the low-order bit of the low-order byte.

Bit | Description
0 | Specifies that the font is a scalable font if set; otherwise the font is a bitmap font.
1 | Reserved; must be zero.
2 | Specifies that character data is stored at the location specified by BitsOffset if set; otherwise the character data appears immediately after the header information. (This bit is only valid for font files that contain bitmap data.)
3-6 | Reserved; must be zero.
7 | Specifies that the font is a device font if set; otherwise the font is a GDI font.
8-15 | Reserved; must be zero.

Note Version 1.0 of the Microsoft Windows Universal Printer Driver does not support scalable device fonts, so the Type value must be set to 128 for all device fonts.

Diconix 150 Plus

The device fonts for the Diconix printer are bitmapped fonts, therefore bit 0 is not set. Bit 1 is reserved and must be set to 0. Since the PFM file describes a device font and the bitmap character data does not appear in the PFM file, bit 2 is not set. Bits 3 through 6 are reserved and must be set to 0. The only bit set for any of the Diconix device fonts is bit 7. The decimal representation of the resultant 16-bit value is 128, which is the value that must be specified for version 1.0 of the Microsoft Windows Universal Printer Driver.


Point Size

The Points control contains the point size for the font. The point size is determined by measuring the vertical distance from the bottom edge to the top edge of a character cell for a font. The value is specified in printer's points; each printer's point is equivalent to approximately 1/72 of an inch.

Note Most applications do not use this box to display point sizes to the user because it is incapable of expressing fractional point sizes. Most applications calculate point size as the sum of the value of the PixHeight and Internal Leading controls in the PFM dialog box.

Diconix 150 Plus

For the Diconix 150 Plus printer, the point size is 10.


Vertical Resolution

Most printer manufacturers digitize their fonts at the highest resolution supported by the printer. The VertRes control contains the vertical resolution that the printer manufacture used to digitize a font. This value is specified in dots-per-inch (dpi).

Diconix 150 Plus

For the Diconix 150 Plus printer, the fonts were digitized at a vertical resolution of 96 dpi. However, in order to prevent possible confusion with calculations between master units in the minidriver data and the units used to express values in the PFM files, the value is 576.


Horizontal Resolution

The HorzRes control contains a horizontal resolution value that the printer manufacture used to digitize a font.

Diconix 150 Plus

For the Diconix 150 Plus printer, the fonts were digitized at a horizontal resolution of 320 dpi.


Ascent

The Ascent control contains a value that specifies the distance from the baseline to the top of a character cell. The value is specified in vertical-resolution units.

Diconix 150 Plus

For the Diconix 150 Plus printer, this distance is 7.25 printer points or 58 dpi.


Internal Leading

The Internal Leading control contains a value that specifies an amount of space reserved in each character cell for accent characters and so on. For most 9- and 24-pin printers, this value should be 0. (The point size specified by most applications is the sum of the PixHeight and Internal Leading values.)

Note Some of the PFM files supplied with the Microsoft® Windows® Device Driver Kit reflect values that are compatible with earlier versions of Windows-based printer drivers. For example, Epson and IBM printers have values that are not listed here. However, for recently created drivers, font metric values should reflect how the printer produces device fonts.

Diconix 150 Plus

For the Diconix 150 Plus printer, this value is 0. The device fonts for the Diconix do not support internal leading.


External Leading

The External Leading control contains a value that specifies the ideal amount of space that should appear between two rows of text printed using a particular font.

Most dot-matrix printer manufacturers suggest printing device fonts at 6 lines to the inch. The External Leading value should be increased or decreased so that the sum of PixHeight and External Leading meet this guideline.

Diconix 150 Plus

For the Diconix 150 Plus printer, this value is 2 printer points or 16 master units.


Identifying Italic Fonts

The Italic control indicates whether the PFM file contains data for an italic font. The control should be set to 1 if it does; otherwise it should be set to 0.

Diconix 150 Plus

For the Diconix 150 Plus printer, this value is 0 because the font used for the example is not italicized.


Identifying Underline Fonts

The Underline control indicates whether the PFM file contains data for an underlined font. The control should be set to 1 if it does; otherwise it should be set to 0.

Diconix 150 Plus

For the Diconix 150 Plus printer, this value is 0 since the font used for the example is not underlined.


Identifying Strikeout Fonts

The Strikeout control indicates whether the PFM file contains data for a strikeout font. The control should be set to 1 if it does; otherwise it should be set to 0.

Diconix 150 Plus

For the Diconix 150 Plus printer, this value is 0 since the font used for the example is not a strikeout font.


Font Weight

The Weight control contains a value that specifies the relative density or weight of characters rendered using the font. Valid weights can range from 100 to 1000 using increments of the value 100; 400 specifies normal weight, 700 specifies bold, and so on. Valid weights must be a multiple of 100.

Diconix 150 Plus

For the Diconix 150 Plus printer, this value is 400 since the bitmaps for the sample font render normal characters.


Character Set

The Char Set control contains a value that identifies the character set associated with a font. This value is 0 if the font uses the Windows ANSI character set; this value is 1 if the font is an IBM PC hardware font (code page 437); this value is 2 if the font uses a special symbol set. Whenever possible, a minidriver should support the Windows ANSI character set.

Diconix 150 Plus

For the Diconix 150 Plus printer, this value is 0 because the Diconix device fonts use the Windows ANSI character set.


Pixel Width

The PixWidth control contains a value that specifies the character width for fixed-pitch raster fonts. This value is specified using the horizontal-resolution units. (If the font is a variable-width device font, this value is 0.)

Diconix 150 Plus

For the Diconix 150 Plus printer, this value is 57.


Pixel Height

The PixHeight control contains a value that specifies the character height of fixed-pitch device fonts. This value is specified using vertical-resolution units.

Diconix 150 Plus

For the Diconix 150 Plus printer, this value is 80.


Pitch and Family

The Pitch and Family control contains an integer value that corresponds to a 16-bit binary value. This value is set by choosing the appropriate controls in the Font Pitch and Family dialog box. You display the Font Pitch and Family dialog box by choosing the ? button. The Pitch value in the Font Pitch and Family dialog box indicates if the font is fixed pitch or proportionally spaced. The Family value affects which screen font Windows will display for this device font.

Diconix 150 Plus

For the Diconix 150 Plus printer, the pitch is fixed and the family is Roman in the Font Pitch and Family dialog box. The corresponding value of 16 appears in the PFM dialog box.


Average Width

The Average Width control specifies the average character width for proportionally spaced and fixed-pitch fonts. If the font is a proportionally spaced font, UniTool will calculate this value based on the information entered in the font-width table. If the font is a fixed-pitch font, the developer must enter this value (which is equivalent to the width of each character).

Diconix 150 Plus

For the Diconix 150 Plus printer, this value is 57.


Maximum Width

The Max. Width control contains a value that specifies the width of the widest character in a font. For fixed-pitch fonts, this value will always be equivalent to the value specified in the Average Width control. For proportionally spaced fonts, UniTool will calculate and insert this value in the control (using values from the character-width table).

Diconix 150 Plus

For the Diconix 150 Plus printer, this value is 57.


Identifying the First Character

The First Char control contains a value that identifies the ASCII decimal value for the first character found in a font's character set.

Diconix 150 Plus

For the Diconix 150 Plus printer, this value is 32 (which corresponds to the space character).


Identifying the Last Character

The Last Char control contains a value that identifies the ASCII decimal value for the last character found in a font's character set.

Diconix 150 Plus

For the Diconix 150 Plus printer, this value is 126, which corresponds to the tilde (~).


Identifying the Default Character

The Default Char control contains a value that identifies the character which Windows renders when a character outside the range defined for First Char through Last Char is requested. This value is a zero-based offset from the first character identified in the Default Char control.

Diconix 150 Plus

For the Diconix 150 Plus printer this value is 14, which corresponds to the period (.).


Identifying the Break Character

The Break Char control contains a value that identifies the character used to define word breaks. This value is a zero-based offset from the first character identified in the First Char control.

Diconix 150 Plus

For the Diconix 150 Plus printer this value is 0, which corresponds to the space character.


Bitmap Width

The Width Bytes control specifies the width in bytes of each row of pels for characters in a raster font. (This value is only required for PFM files which contain bitmapped font data.)

Diconix 150 Plus

For the Diconix 150 Plus printer, this value is 0.


Device Name

The Device Name control contains an optional ASCII string that specifies the name of the printer.

Diconix 150 Plus

For the Diconix 150 Plus printer, this string is Diconix 150 Plus.


Face Name

The Face Name control contains an ASCII string that specifies the name of the font. If a printer supports multiple fonts with the same font name and point size but different pitches, the string should also contain the pitch value. Pitch values should be expressed in terms of characters-per-inch (cpi). The font name in a minidriver must be unique.

Diconix 150 Plus

For the Diconix 150 Plus printer, this string is Roman(12cpi).


Device Fonts Character Widths Dialog Box

If the Pitch and Family value is set to indicate that you are editing a PFM file for a variable-pitch device font, you may enter values to describe the width of each character in the Device Font Character Widths dialog box. To display the dialog box, choose the FontWidth button. You may enter widths for all characters that fall between the First Char and Last Char ASCII character values already entered. The widths entered here are expressed in horizontal resolution units. If the font uses a character-translation table, the widths entered here should reflect the widths of the characters the printer actually produces when sent the values from the character-translation table.


Extended Text Metrics Dialog Box

You may also enter optional values for extended text metrics. Only applications that specifically request this information from a driver will use the values entered here. To display the Extended Text Metrics dialog box, press the Ext.TextMetrics button. For more information about the controls in this dialog box, see the Microsoft Windows Printers and Fonts Kit.


Kern Pairs Dialog Box

You may also enter optional values for kern pairs. Only applications that specifically request this information from a driver will use the values entered here. To display the Kern Pairs dialog box, choose the KernPair button. For more information about the controls in this dialog box, see the Microsoft Windows Printers and Fonts Kit.


Kern Tracks Dialog Box

You may also enter optional values for kern tracks. Only applications that specifically request this information from a driver will use the values entered here. To display the Kern Tracks dialog box, choose the KernTrack button. For information about the controls in this dialog box, see the Microsoft Windows Printers and Fonts Kit.


Font Selection

The Font Select control contains the printer command which selects a particular font.

Diconix 150 Plus

For the Diconix 150 Plus printer, the Elite Mode On command (ESCM) selects 10-point and 12-pitch Roman font.

To specify the Elite Mode On command, type the following in the Font Select box:

\x1BM

Note Depending on the printer model, font selection commands may require a combination of printer commands to select the desired font.


Canceling Font Selection

The Font UnSelect control contains the printer command which cancels a font selection. For printers that have no x-cursor movement command and rely on the width of the space character to perform horizontal movement, this command selects the font or pitch that causes the printer to move the desired amount for a space character. This command is also required if a printer's font selection command will enable attributes which cannot be disabled by a subsequent font select command or inhibit the use of other commands used in the driver.

Diconix 150 Plus

For the Diconix 150 Plus printer, there is no command that cancels the selection of the default font when the printer's switches are set to the factory default; therefore, the Font UnSelect box is empty.


Vertical Adjustments

The Y Moved and the Y Adjust controls contain vertical offsets that are required to align a font's baseline with the GDI baseline. If these baselines differ, Windows will shift the font baseline by the Y Adjust value prior to rendering text. Once the text is rendered, Windows will shift the font baseline back to the proper position using the Y Moved value. Typically, it is not necessary to adjust the Y position for device fonts.

Diconix 150 Plus

For the Diconix 150 Plus printer, these controls contain the value 0.


Private Font Data

The Private Data control provides a means of storing 16-bits of private data. If a minidriver provides a private function (or private functions) for processing device fonts, it can store data used by these functions using this control.

Diconix 150 Plus

For the Diconix 150 Plus printer, this control contains the value 0.


Identifying a Character-Translation Table

The Trans Tab control identifies the character-translation table associated with a font. A character-translation table provides a method of remapping the extended characters used for device fonts to the Windows ANSI set. In the Trans Tab control, negative values identify predefined translation-tables, positive values identify minidriver-defined translation tables, and a value of zero indicates that the CTT is identified in the minidriver's model data. For more information about character-translation tables (CTT), see Creating a Character-Translation Table.

Diconix 150 Plus

For the Diconix 150 Plus printer, this control contains the value 0 since the font uses the CTT specified in the ModelData dialog box.


The Character Shift Amount

The Shift control contains a value that specifies a horizontal distance in horizontal-resolution units. This distance is an offset that the Universal Printer Driver uses to shift individual characters from a particular font. It is required for fonts with characters that are not centered in the bounding box. The Universal Printer Driver uses a negative shift value to shift characters to the right, and a positive shift value to shift characters to the left. Shift amounts are intended to be used when characters do not fall in the center of the bounding box defined by font metrics.

Diconix 150 Plus

For the Diconix 150 Plus printer, this control contains the value 0.


Disabling Font Simulations

The fCaps button displays a dialog box with seven checkbox controls. These controls disable certain font simulations for a particular device font.

The following list provides a brief description of each control.

Control | Description
DF_NOITALIC | Specifies that the device font cannot be italicized using the italic simulation.
DF_NOUNDER | Specifies that the device font cannot be underlined using the underline simulation.
DF_XM_CR | Specifies that the Universal Printer Driver should send a carriage-return command after rendering a line of text with this font.
DF_NO_BOLD | Specifies that the device font cannot be made bold sing the bold simulation.
DF_NO_DOUBLE_UNDERLINE | Specifies that the device font cannot be double-underlined using the double-underline simulation.
DF_NO_STRIKETHRU | Specifies that the device font cannot be struck through using the strikethrough simulation.
DF_BKSP_OK | Specifies that a single backspace will be sent when using a character-translation table that uses strikeover characters. If this bit is not set, and the font uses a CTT, explicit x-movement commands are required.

Diconix 150 Plus

For the Diconix 150 Plus printer, all font simulations are supported; therefore, none of the checkboxes were selected. After you have created PFM files for your printer's fonts, you should create a character-translation table (CTT).


Creating a Character-Translation Table

A character-translation table maps characters from a printer's character set to the Windows® ANSI character set using the printer's device font character set. All printer drivers for Windows should support the Windows ANSI character set. If a font uses the translation table identified in the printer's Model Data dialog box, the value in this control should be 0. If the font requires a predefined CTT which is provided by the Universal Printer Driver, this value should be that CTT's ID multiplied by -1; if the font requires a minidriver-defined CTT, this value should be a positive integer.

There are two predefined character-translation tables that are furnished by the Universal Printer Driver. The tables and corresponding code page are outlined in the following table.

CTT ID | CTT (Code Page)
-1 | IBM Code Page 437
-2 | IBM Code Page 850
-3 | IBM Code Page 863

Windows uses a modified ANSI character set to identify printable characters. The current version of this set contains 256 entries. For more information about the Microsoft Windows ANSI character set, see the Microsoft Windows Device Driver Adaptation Guide. Some printers, like most dot-matrix printers, will use the same extended characters for all device fonts. For this type of printer, a minidriver may either specify a character-translation table through the ModelData dialog box and set the Trans Tab value in the PFM dialog box in each PFM file to 0, or may set all of the Trans Tab values in each PFM file to the appropriate ID value.

Other printers, like the HP LaserJet IIP, use a different set of extended characters for each font. For this type of printer, a minidriver should set each of the Trans Tab values in every PFM file to the ID value appropriate for that font.

Once it has been determined which extended character set (or sets) is used for some or all of the device fonts, character-translation tables must be provided to map the device's extended characters to the Windows ANSI set.

If the font uses extended characters that match either code page 437 or 850, a minidriver may use one of the predefined character-translation tables provided by the Universal Printer Driver. Simply enter the CTT ID from the table in the Trans Tab control.

If the font does not use extended characters at all (either does not print them at all, or the characters are italicized versions of the characters below ASCII 127), a character-translation table is not needed. For these printers, the Last Char in the PFM dialog box should be set to 127 (or whatever the last printing ASCII value is), and the character described by the Default character in the PFM file will be used whenever an extended character is requested.

If the font uses some other combination of extended characters, it will be necessary for the minidriver to provide its own character-translation table to perform the remapping. Using the CTT dialog box, you can specify which character codes map to which printer symbols.


Identifying the First Character

The First Char control in the CTT dialog box contains a value that identifies the first character in the character-translation table. The extended characters used by HP LaserJet IIP printer vary depending upon the individual font being used. In the previous illustration, a character-translation table for a font using the ECMA-94 character set is shown. The first character in the translation table is 128. Characters below this value do not use the character-translation table, and are sent directly to the printer.


Identifying the Last Character

The Last Char control in the CTT dialog contains a value that identifies the last character in the character-translation table.

Because the character-translation table for the ECMA-94 character set from the HP LaserJet IIP driver supports characters 128 through 255, the value in this control is 255.


Character Codes

The remaining controls in the CTT dialog box allow you to specify a character code or device-command/character-code sequence which maps a character code (or device-command/character-code sequence) to a particular entry in the Windows ANSI set.

For example, the character code 161 in the Windows ANSI character set is an inverted exclamation point. If this character is available on the printer, the required printer commands should be placed in the control labeled 161 in the translation table. If the character from the Windows ANSI set is not available, the default character for that font should be placed at that location in the character-translation table instead.

There are three types of character-translation tables. UniTool will determine which one is appropriate to save the CTT file based on the information that was entered.

The first type is a simple 1-to-1 translation, where each character code consists of a single byte. In this type of CTT, the Universal Printer Driver will send the character value that was entered in the edit control every time that the ASCII value shown before the edit control is requested.

The second type is a 2-to-1 translation, where each character code consists of either one of two characters. In this type of CTT, the Universal Printer Driver will send the first character value that was entered in the edit control, and then use either a backspace character or x-movement commands to move the current position back to where it was before the first character was printed. The Universal Printer Driver then sends the second character.

The third type is a variable-length translation, where each character code consists of a variable length string containing a printer command. In this type of CTT, the Universal Printer Driver sends the command that was entered in the edit control when the edit control value is requested.

Once you have created a CTT, you should begin entering the commands and data associated with the Font Info command in the Printer Data menu.


Text Quality

The Text Qualities dialog box contains controls which you use to identify a text quality and to specify the printer command which selects that text quality. Typically, text quality only varies for dot-matrix printers. Laser printers, such as the HP LaserJet IIP provide one text quality or resolution. The examples in this section for the Diconix 150 Plus printer are based on the commands and data corresponding to letter-quality output.


Specifying Whether the Quality is Predefined or Driver Defined

The Predefined and Driver Defined buttons indicate whether a Text Qualities dialog box contains data for one of the five predefined qualities or whether the dialog box contains data for a driver-defined text quality. These buttons are mutually exclusive — only one can be selected.

Diconix 150 Plus

For the Diconix 150 Plus printer, the predefined button is selected.

HP LaserJet IIP

For the HP LaserJet IIP printer, the predefined button is selected by default. (All other controls in this dialog box are empty.)


Predefined Text Quality

The Text Quality Name box appears adjacent to the Predefined button. This box lists five common text qualities:

  • Letter Quality
  • Near-Letter Quality
  • Memo
  • Draft Quality
  • Text Quality

Diconix 150 Plus

For the Diconix 150 Plus printer, Letter Quality appears in the box.

HP LaserJet IIP

The Text Quality Name box is empty.


Driver-Defined Text Quality

The Text Quality Name box for driver-defined text qualities appears adjacent to the Driver Defined button. This control lists a text quality which was entered by a minidriver developer.

Diconix 150 Plus

The Text Quality Name box for driver-defined text qualities is empty.

HP LaserJet IIP

The Text Quality Name box for driver-defined text qualities is empty.


Specifying Text Quality

The Select String box contains the printer command which selects the text quality identified in the Text Quality Name box.

Diconix 150 Plus

For the Diconix 150 Plus printer, the Text Quality command (ESCxn) selects a text quality. The argument n identifies the requested quality; if n is 0, draft quality is selected; if n is 1, near-letter quality is selected; if n is 3, letter-quality is selected.

To specify the Text Quality command, type the following in the Select String box:

\x1Bx\x03

HP LaserJet IIP

The Select String box is empty.

Once you have entered the text-quality commands and data for your printer, you should begin entering the font-cartridge commands and data.


Specifying Font-Cartridge Data

Some printers provide a slot for removable cartridges that contain device fonts. The Font Cartridge dialog box contains controls which you use to identify supported cartridges and the fonts which they contain.

The examples in the following sections are based on the Microsoft® 1A cartridge which is one of 33 cartridges supported by the HP LaserJet printer.


Cartridge Name

The Name of Cartridge box contains a string that specifies a font-cartridge name.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Name of Cartridge box contains the string Z: Microsoft 1A which identifies the Microsoft 1A font cartridge.


Portrait Font Names

The Portrait Fonts box contains strings that specify the names of portrait fonts supported by a cartridge. UniTool copies the names of all the PFM font files used by the minidriver into this control, and the minidriver developer specifies which fonts are supported on a particular cartridge by choosing the correct names with the cursor and then clicking the mouse button.

HP LaserJet IIP

For the HP LaserJet IIP printer, sixteen of the 303 device fonts are supported on the Microsoft 1A cartridge. The strings which identify these fonts (numbered 184 - 191 and 193 - 200) are highlighted.


Landscape Font Names

The Landscape Fonts box contains strings that specify the names of landscape fonts supported by a cartridge. UniTool copies the names of all the PFM font files used by the minidriver into this control and the minidriver developer specifies which fonts are supported on a particular cartridge by choosing the correct names with the cursor and then clicking the mouse button.

HP LaserJet IIP

For the HP LaserJet IIP printer, one of the 303 device fonts is supported in landscape mode on the Microsoft 1A cartridge. The string which identifies this font (numbered 192) is highlighted.


Font-Simulation Commands and Data

A font-simulation is a capability of simulating italic, bold, underlined, or strikeout text from a normal device font. The FONTSIMULATION dialog box contains controls which you use to identify the font-simulation commands and data that your printer supports. Most printers provide at least some font simulations for device fonts. The font-simulation commands described in this dialog are assumed to be applicable to all device fonts. There are two exceptions:

  • A separate PFM file for fonts is defined in the minidriver.
  • The fGeneral dialog box in the PFM file inhibits font simulations.

Note To enable the bold, italic, and strikeout font simulations for a single printer model, the corresponding bits in the fGeneral dialog box in the MODELDATA data structure for each printer model must be set.

If a printer is not capable of simulating bold, italic, underline, or strikeout text, GDI will perform the simulation instead. However, GDI simulations are slower than device simulations.


Enabling Bold Simulation

The FS_OCD_BOLD_ON box contains the command which enables bold simulations for a printer.

Diconix 150 Plus

For the Diconix 150 Plus printer, the Emphasized Mode On command (ESCE) enables bold simulations.

To specify the Emphasized Mode On command, type the following in the FS_OCD_BOLD_ON box:

\x1BE

HP LaserJet IIP

For the HP LaserJet IIP printer, the Stroke Weight command (ESC(snB) specifies the thickness of the strokes that compose a character. If n is -3, the stroke is thin; if n is 0, the stroke is normal; if n is 3, the stroke is bold.

However, because the TC_EA_DOUBLE check box in the fText dialog box is not checked, the Universal Printer Driver will not perform bold simulations. The command to select bold is included in a font simulation structure to override the TC_EA_DOUBLE check box.

To specify the Stroke Weight command which enables bold output, type the following in the FS_OCD_BOLD_ON box:

\x1B(s3B


Disabling Bold Simulation

The FS_OCD_BOLD_OFF box contains the command which disables bold simulations for a printer.

Diconix 150 Plus

For the Diconix 150 Plus printer, the Emphasized Mode Off command (ESCF) disables bold simulations.

To specify the Emphasized Mode Off command, type the following in the FS_OCD_BOLD_OFF box:

\x1BF

HP LaserJet IIP

For the HP LaserJet IIP printer, the Stroke Weight command (ESC(snB) specifies the thickness of the strokes that compose a character. If n is -3, the stroke is thin; if n is 0, the stroke is normal; if n is 3, the stroke is bold.

To specify the Stroke Weight command which disables bold output, type the following in the FS_OCD_BOLD_OFF box:

\x1B(s0B


Enabling Italic Simulation

The FS_OCD_ITALIC_ON box contains the command which enables italic simulations for a printer.

Diconix 150 Plus

For the Diconix 150 Plus printer, the Italic Mode On command (ESC4) enables italic simulations.

To specify the Italic Mode On command, type the following in the FS_OCD_ITALIC_ON box:

\x1B4

HP LaserJet IIP

For the HP LaserJet IIP, in the FS_OCD_ITALIC_ON box, the font-style command is (ESC(snS). If n is 1, the characters are italicized; if n is 0, the characters are plain text.

However because the TC_IA_ABLE check box in the fText dialog box is not checked, the Universal Printer Driver will not perform italic simulations. The command to select italics is included in a font simulation structure to override the TC_IA_ABLE check box.

To specify italic output, type the following in the FS_OCD_ITALIC_ON box:

\x1B(s1S


Disabling Italic Simulation

The FS_OCD_ITALIC_OFF box contains the command which disables italic simulations for a printer.

Diconix 150 Plus

For the Diconix 150 Plus printer, the Italic Mode Off command (ESC5) disables italic simulations.

To specify the Italic Mode Off command, type the following in the FS_OCD_ITALIC_OFF box:

\x1B5

HP LaserJet IIP

For the HP LaserJet IIP, in the FS_OCD_ITALIC_OFF box, the font-style command (ESC(snS) specifies if the font is italicized or plain text. If n is 1, the characters are italicized; if n is 0, they are plain text.

To specify plain text, type the following in the FS_OCD_ITALIC_OFF box:

\x1B(s0S


Enabling Underline Simulation

The FS_OCD_UNDERLINE_ON box contains the command which enables underline simulations for a printer.

Diconix 150 Plus

For the Diconix 150 Plus printer, the Underline Mode command (ESC-n) enables and disables the underline font simulation. If n is 1, the font simulation is enabled; if n is 0, the font simulation is disabled.

To specify the Underline Mode command, type the following in the FS_OCD_UNDERLINE_ON box:

\x1B-\x01

HP LaserJet IIP

For the HP LaserJet IIP printer, the Underline command (ESC&dnD) enables fixed- and floating-position underlining. If n is 0, fixed-position underlining is enabled; if n is 1, floating-position underlining is enabled. The Universal Printer Driver will perform underline simulations.

To specify the Underline command, type the following in the FS_OCD_UNDERLINE_ON box:

\x1B&dD


Disabling Underline Simulation

The FS_OCD_UNDERLINE_OFF box contains the command which disables underline simulations for a printer.

Diconix 150 Plus

For the Diconix 150 Plus printer, the Underline Mode command (ESC-n) enables and disables the underline font simulation. If n is 1, the font simulation is enabled; if n is 0, the font simulation is disabled.

To specify the Underline Mode command, type the following in the FS_OCD_UNDERLINE_OFF box:

\x1B-\x00

HP LaserJet IIP

For the HP LaserJet IIP printer, the Disable Underline command (ESC&d@) disables fixed- and floating-position underlining.

To specify the Disable Underline command, type the following in the FS_OCD_UNDERLINE_OFF box:

\x1B&d@


Enabling Double-Underline Simulation

The FS_OCD_DOUBLEUNDERLINE_ON box contains the command which enables double-underline simulations for a printer.

Diconix 150 Plus

The Diconix 150 Plus printer does not support double-underlining; therefore, the FS_OCD_DOUBLEUNDERLINE_ON box is empty.

HP LaserJet IIP

The HP LaserJet IIP printer does not support double-underlining; therefore, the FS_OCD_DOUBLEUNDERLINE_ON box is empty.


Disabling Double-Underline Simulation

The FS_OCD_DOUBLEUNDERLINE_OFF box contains the command which disables double-underline simulations for a printer.

Diconix 150 Plus

The Diconix 150 Plus printer does not support double-underlining; therefore, the FS_OCD_DOUBLEUNDERLINE_OFF box is empty.

HP LaserJet IIP

The HP LaserJet IIP printer does not support double-underlining; therefore, the FS_OCD_DOUBLEUNDERLINE_OFF box is empty.


Enabling Strikethrough Simulation

The FS_OCD_STRIKETHRU_ON box contains the command which enables the strikethrough simulations for a printer.

Diconix 150 Plus

The Diconix 150 Plus printer does not support strikethrough text; therefore, the FS_OCD_STRIKETHRU_ON box is empty.

HP LaserJet IIP

The HP LaserJet IIP printer does not support strikethrough text; therefore, the FS_OCD_STRIKETHRU_ON box is empty.


Disabling Strikethrough Simulation

The FS_OCD_STRIKETHRU_OFF control contains the command which disables the strikethrough simulations for a printer.

Diconix 150 Plus

The Diconix 150 Plus printer does not support strikethrough text; therefore, the FS_OCD_STRIKETHRU_OFF box is empty.

HP LaserJet IIP

The HP LaserJet IIP printer does not support strikethrough text; therefore, the FS_OCD_STRIKETHRU_OFF box is empty.

Once you have entered the font-simulation commands and data for your printer, you should either begin entering the commands and data for downloadable device fonts, or you should begin entering model data for your printer. (If your printer supports the HP PCL, you should enter commands and data to download device fonts; if your printer supports a different page-description language or technology, skip the downloadable-font commands and begin entering model data.)


Specifying Downloadable-Font Commands and Data

The DOWNLOADINFO dialog box contains controls which support the commands and data required to download soft fonts for Hewlett Packard printers which operate using HP's Printer Control Language (PCL). Downloading fonts to other types of printer models is not supported by the Universal Printer Driver version 1.0. A soft font is a special font that is stored on a disk and copied or downloaded to the printer's RAM prior to use. A soft font has two components: the font-descriptor component and the character-descriptor component. The font-descriptor component specifies the font's metrics (measurements such as the character-cell dimensions, pitch, x-height, stroke weight, and so on). The character-component contains bitmaps for individual characters in a soft font. Soft fonts are temporary as opposed to permanent cartridge- or ROM-resident fonts. When a printer is reset, soft fonts are deleted. This information is needed to download TrueType fonts to the HP LaserJet Series II, and later HP LaserJet printers. The Universal Printer Driver supports downloading TrueType fonts as bitmapped fonts, but not as downloaded scalable fonts.


Font ID Value Limits

The HP PCL requires that a special identifier be assigned to a soft font prior to downloading. The Min and Max ID boxes specify the minimum and maximum allowable font ID value.

Note The ID values listed will only apply to downloaded TrueType fonts. Other downloaded fonts installed with the font installer use ID values supplied to the font installer.

HP LaserJet IIP

The Minimum ID box specifies the minimum allowable font ID value which is 1; the Maximum ID box specifies the maximum allowable font ID value.


Bitmap Font Information

The cbBitMapFontDescriptor and cbBitMapCharDescriptor controls specify the size in bytes of the font, and character descriptors for a bitmapped font.

HP LaserJet IIP

For the HP LaserJet IIP printer, the font descriptor requires 64 bytes; therefore the cbBitMapFontDescriptor box contains the value 64. The character descriptor for each symbol in the font requires 16 bytes; therefore, the cbBitMapCharDescriptor contains the value 16.


Scalable Font Information

The cbScaleFontDescriptor and cbScaleCharDescriptor controls specify the size, in bytes, of the font and character descriptors for a vector font. Because the Universal Printer Driver does not support downloading scalable fonts, these controls are disabled.

HP LaserJet IIP

The cbScaleFontDescriptor and cbScaleCharDescriptor boxes are empty.


Maximum Font Count

The sMaxFontCount box specifies the maximum number of fonts which may be downloaded at any given point in time.

HP LaserJet IIP

For the HP LaserJet IIP printer, the sMaxFontCount box contains the value -1; this means that the number of fonts that may be downloaded to the printer at any given time is unlimited (except by available printer memory).


General Font Information

The fGeneral button displays the fGeneral dialog box. This dialog box contains seven boxes which specify printer limitations and features related to downloaded fonts.

The following table provides a brief description of each control.

Control | Description
DLI_GEN_CNT | Specifies that the number of downloaded fonts is limited by a fixed integer value.
DLI_GEN_MEMORY | Specifies that the number of downloaded fonts is limited by available memory.
DLI_GEN_DIJOB | Specifies that the printer downloads fonts on a per-job basis.
DLI_GEN_DLPAGE | Specifies that the printer downloads fonts on a per-page basis.
DLI_GEN_PT_IDS | Specifies that the printer requires a font ID value in order to make the font temporary or permanent.
DLI_GEN_FNTDEL | Specifies that the printer supports a command that deletes single downloaded fonts.
DLI_GEN_ALLFNTDEL | Specifies that the printer supports a command that deletes all downloaded fonts.

HP LaserJet IIP

For the HP LaserJet IIP printer, the DLI_GEN_MEMORY box is checked because the number of downloaded fonts is limited by printer memory; the DLI_GEN_PT_IDS box is checked because the printer requires a font ID value; the DLI_GEN_FNTDEL box is checked because the printer supports a command which deletes single downloaded fonts; and the DLI_GEN_ALLFNTDEL box is checked because the printer supports a command which deletes all downloaded fonts.


Font Format Information

The fFormat button displays the fFormat dialog box. This dialog box contains controls that the Universal Printer Driver uses for TrueType support on Hewlett-Packard printers that use PCL.

The following table provides a brief description of each control.

Control | Description
DLI_FMT_PCL | Specifies that the printer uses the Hewlett-Packard Page Control Language (PCL)
DLI_FMT_INCREMENT | Specifies that the printer should download only those characters required to print a single job. If this box is not checked, the Universal Printer Driver downloads the entire character set to the printer for a given font.

HP LaserJet IIP

For the HP LaserJet IIP printer, the DLI_FMT_PCL box is checked because the printer supports Hewlett-Packard's PCL, and the DLI_FMT_INCREMENT box is checked because the printer should use an incremental download rather than downloading the entire character set for a given font.


Begin Download Job Box

The BEGIN_DL_JOB box contains the command to begin downloading.

HP LaserJet IIP

The BEGIN_DL_JOB box is empty.


Begin Font Download Box

The BEGIN_FONT_DL control contains the command to begin downloading fonts.

HP LaserJet IIP

The BEGIN_FONT_DL box is empty.


Set Font ID Box

The SET_FONT_ID box contains the command that sets the ID of the font. This command assigns an integer value to a downloadable font. This integer value is the value that the Universal Printer Driver uses to refer to the font.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Assign Font ID command (ESC*cnD) assigns an ID value to a font. This value can be used to select or delete the font after it is downloaded.

To specify the Assign Font ID command, type the following in the SET_FONT_ID box:

\x1B*c%dD


Send Font Descriptor Box

The SEND_FONT_DESCRIPTOR control contains the command which downloads the font-descriptor data to a printer.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Font Descriptor command (ESC)snW) downloads font descriptor data to the printer for the font whose ID is specified by the argument n. Font Descriptor data is data that is common to all characters in a font; this data includes: the dimensions of the character cell, the orientation of the characters, the x-height, the stroke weight, the first character code, the last character code, and so on.

To specify the Font Descriptor command, type the following string in the SEND_FONT_DESCRIPTOR box:

\x1B)s%dW


Select Font ID Box

The SELECT_FONT_ID box contains the command which selects the downloadable font identified by a particular integer value.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Font Selection by ID command (ESC(nX) selects the downloaded font with the ID value of n.

To specify the Font Selection by ID command, type the following string in the SELECT_FONT_ID box:

\x1B(%dX


Set Character Code Box

The SET_CHAR_CODE box contains the command which identifies the next character to be printed.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Character Code command (ESC*cnE) designates the character code that will be associated with the next character to be downloaded.

To specify the Character Code command, type the following in the SET_CHAR_CODE box:

\x1B*c%dE


Send Character Descriptor Box

The SEND_CHAR_DESCRIPTOR box contains the command which downloads the character-descriptor and character-data components for a font.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Character Descriptor and Data command (ESC(snW) downloads n bytes of character descriptors and character data for a font.

To specify the Character Descriptor and Data command, type the following in the SEND_CHAR_DESCRIPTOR box:

\x1B(s%dW


End Font Download Box

The END_FONT_DL box contains the command which signals the completion of the download-font process.

HP LaserJet IIP

The END_FONT_DL box is empty.


Permanent Font Box

The MAKE_PERM box contains the command which makes a downloadable font permanent.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Font Control command (ESC*cnF) deletes downloaded fonts, makes downloaded fonts temporary, makes downloaded fonts permanent, and so on. If n is 5, the font is made permanent.

To specify the Font Control command that makes a font permanent, type the following in the MAKE_PERM box:

\x1B*c5F


Temporary Font Box

The MAKE_TEMP box contains the command which makes a downloadable font temporary.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Font Control command (ESC*cnF) deletes downloaded fonts, makes downloaded fonts temporary, makes downloaded fonts permanent, and so on. If n is 4, the font is made temporary.

To specify the Font Control command that makes a font temporary, type following in the MAKE_TEMP box:

\x1B*c4F


End Download Job Box

The END_DL_JOB control contains the command which signals the completion of a print-job that used downloaded fonts.

HP LaserJet IIP

In the example for the HP LaserJet IIP printer, this command is not required, and the control is empty.


Delete Font Box

The DEL_FONT box contains the command which deletes a single downloaded font from the printer's memory.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Font Control command (ESC*cnF) deletes downloaded fonts, makes downloaded fonts temporary, makes downloaded fonts permanent, and so on. If n is 2, the font whose ID was last specified is deleted.

To specify the Font Control command that deletes the last identified downloaded font, type the following in the DEL_FONT box:

\x1B*c2F


Delete All Fonts Box

The DEL_ALL_FONTS control contains the command which deletes all downloaded fonts from the printer's memory.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Font Control command (ESC*cnF) deletes downloaded fonts, makes downloaded fonts temporary, makes downloaded fonts permanent, and so on. If n is 0, all downloaded fonts are deleted.

To specify the Font Control command which deletes all downloaded fonts, type the following in the DEL_ALL_FONTS box:

\x1B*c0F

After entering the font information for your printer from the Printer Data menu, you choose the ModelData command and enter the model-specific data for your printer.


Specifying Printer Model Data

After you specify master units, control information, paper information, graphics information, and font information for your printer, you need to enter model-specific data.


Specifying Model Data

You will enter most of your model-specific data in the ModelData dialog box.


The Model Name

The Name of Model control contains text which specifies a printer's model name. This text should be an exact match of the corresponding text in the file CONTROL.INF.

Diconix 150 Plus

The CONTROL.INF file contains the following entry for the Diconix minidriver:

5:DICONIX.DRV, "Diconix 150 Plus", "DEVICESPECIFIC"

The text that appears after the minidriver name (Diconix 150 Plus) in the .INF file is the text that also appears in the Name of Model control.

HP LaserJet IIP

The CONTROL.INF file contains the following entry for the LaserJet minidriver:

7:HPPCL.DRV,7:unidrv.dll,"HP LaserJet IIP", "DEVICESPECIFIC"

The first string surrounded by quotation marks (HP LaserJet IIP) is the string that also appears in the Name of Model control.

NOTE If a driver supports two models that are identical except for the name, enter both names separated by a percentage mark (%) in the Name of Model control. This is how the HP LaserJet IIP and HP LaserJet IIP Plus are supported.


Page-Size Limits

The Page Size Limits controls specify the minimum allowable physical page size, and the maximum printable region widths and heights (in master units) that are allowed for user-defined paper sizes. If your minidriver supports user-defined paper sizes, and you have initialized the appropriate controls in the Paper Sizes dialog box, you will also need to set the Page Size Limits controls.

Diconix 150 Plus

For the Diconix 150 Plus printer, the maximum allowable printable width is imposed by the model itself, and is set to 6624 (6.9 inches as expressed in master units). The Diconix printer does not impose any paper-length constraints. For example, an arbitrary length of 24 inches was chosen that translates into 13,824 vertical master units (24 * 576 = 13,824).

The minimum allowable width for the Diconix printer is imposed by the rubber rollers on the bail arm. These rollers can be adjusted from 6 to 8 inches apart imposing the smallest allowable paper width of 6 inches which translates into 1,924 horizontal master units (6 * 320 = 1,924). The minimum allowable height is the distance from the entrance of the paper-feed slot to the top bail arm. This distance is 3.5 inches or 2,016 vertical master units (3.5 * 576 = 2,016).

HP LaserJet IIP

For the HP LaserJet IIP printer, the maximum allowable printable width is 8 inches. This value translates into 2400 horizontal master units (8 * 300 = 2400). The maximum allowable printable height is 13 inches. This value translates into 3900 master units (13 * 300 = 3900). The minimum allowable page width and height is one inch. This value translates into 300 master units (1 * 300 = 300).


Supported Attributes in the ModelData Dialog Box

The Supported Attributes list box lists the names of fourteen dialog boxes. The values and strings that appear in these dialog boxes correspond to values and strings which were entered in the corresponding dialog boxes accessible through the cascading menus in the Printer Data menu. By double-clicking any of the entries in the Supported Attributes list box, you display a dialog box with data previously entered through the commands and corresponding dialog boxes in the Printer Data menu. Here, you may indicate which data applies to your device and which does not; you may also specify values to which the driver will default when it is first installed. The following list briefly describes each of the fourteen dialog boxes accessible from the Supported Attributes list box.

Dialog Box | Description
Resolutions | Specifies the default, supported, and unsupported printer resolutions. The values which appear in this dialog correspond to values which were entered in the RESOLUTION dialog box.
Paper Sizes | Specifies the default, supported, and unsupported paper sizes. The values which appear in this dialog box correspond to values which were entered in the Paper Sizes dialog box.
Paper Qualities | Specifies the default, supported, and unsupported paper qualities. The values which appear in this dialog box correspond to values which were entered in the Paper Qualities dialog box.
Paper Sources | Specifies the default, supported, and unsupported input paper trays. The values which appear in this dialog box correspond to values which were entered in the Paper Sources dialog box.
Paper Destinations | Specifies the default, supported, and unsupported output paper trays. The values which appear in this dialog box correspond to values which were entered in the Paper Destination dialog box.
Text Qualities | Specifies the default, supported, and unsupported text qualities. The values which appear in this dialog box correspond to values which were entered in the Text Qualities dialog box.
Compression Modes | Specifies the default, supported, and unsupported compression modes. The values which appear in this dialog box correspond to values which appear in the Compression Modes dialog box.
Font Cartridges | Specifies the default, supported, and unsupported font cartridges. The values which appear in this dialog box correspond to values which appear in the Font Cartridge dialog box.
Color Models | Specifies the default, supported, and unsupported color models. The values which appear in this dialog box correspond to values which were entered in the DEVCOLOR dialog box.
Page Control | Specifies the supported page-control command set.
Cursor Move | Specifies the supported cursor-movement data.
Font Simulation | Specifies the supported font simulation.
RectFill | Specifies the supported rectangle fills.
Download Info | Specifies the supported download information for printer fonts.


Default and Supported Printer Resolutions

The Resolutions dialog box identifies the default, the supported, and the unsupported printer resolutions. The default resolution appears in the dropdown list box that appears at the top of the dialog box. The supported resolutions are the highlighted resolutions that appear in the list box below the dropdown list box.

The following list describes each of the controls in this dialog box.

Control | Description
Default | Specifies the default printer resolution.
List box | Lists the available resolutions for this printer.
Enable All | Enables all resolutions which appear in the list box.
Inhibit All | Inhibits all resolutions which appear in the list box.
Cancel | Cancels current edit changes.
OK | Saves current edit changes.

Diconix 150 Plus

The Diconix 150 Plus printer supports a low-, medium- and high-resolution of 80 x 96, 160 x 96, and 320 x 96 dpi respectively.

HP LaserJet IIP

The HP LaserJet IIP printer supports a low-, medium-, and high-resolution of 75 x 75, 150 x 150, and 300 x 300 dpi respectively.


Default and Supported Paper Sizes

The Paper Sizes dialog box identifies the default and supported paper sizes. The default paper size appears in the dropdown list box at the top of the dialog box. The supported paper sizes are highlighted in the list box below the dropdown list box.

The following list describes each of the controls in this dialog:

Control | Description
Default | Specifies the default paper size.
List box | Lists the available paper sizes for this printer.
Enable All | Enables all paper sizes which appear in the list box.
Inhibit All | Inhibits all paper sizes which appear in the list box.
Cancel | Cancels current edit changes.
OK | Saves current edit changes.

Diconix 150 Plus

The Diconix 150 Plus printer supports 8.5 x 11 inch as well as user-defined paper sizes.

HP LaserJet IIP

The HP LaserJet IIP printer supports 8.5 x 11 inch, 8.5 x 14 inch, and 210 x 297-millimeter paper sizes.


Default and Supported Paper Qualities

The Paper Qualities dialog box identifies the default and supported paper qualities. The following list describes each of the controls in this dialog box.

Control | Description
Default | Specifies the default paper quality.
List box | Lists the available paper qualities for this printer.
Enable All | Enables all paper qualities which appear in the list box.
Inhibit All | Inhibits all paper qualities which appear in the list box.
Cancel | Cancels current edit changes.
OK | Saves current edit changes.

Diconix 150 Plus

The Diconix 150 Plus does not support paper-quality commands.

HP LaserJet IIP

The HP LaserJet IIP does not support paper-quality commands.


Default and Supported Paper Sources

The Paper Sources dialog box identifies the default and supported paper sources. The default paper source appears in the dropdown list box at the top of the dialog box. The supported paper sources are highlighted in the list box below the dropdown list box.

The following list describes each of the controls in this dialog box.

Control | Description
Default | Specifies the default paper-source identifier.
List box | Lists the available paper-source identifiers for this printer.
Enable All | Enables all paper-source identifiers which appear in the list box.
Inhibit All | Inhibits all paper-source identifiers which appear in the list box.
Cancel | Cancels current edit changes.
OK | Saves current edit changes.

Diconix 150 Plus

The Diconix 150 Plus printer supports tractor- and manual-feed paper sources.

HP LaserJet IIP

The HP LaserJet IIP printer supports an upper-tray or manual-feed paper sources.


Default and Supported Paper Destinations

The Paper Destinations dialog box identifies the default and supported paper destinations. The following list describes each of the controls in this dialog box.

Control | Description
Default | Specifies the default paper-destination identifier.
List box | Lists the available paper-destination identifiers for this printer.
Enable All | Enables all paper-destination identifiers which appear in the list box.
Inhibit All | Inhibits all paper-destination identifiers which appear in the list box.
Cancel | Cancels current edit changes.
OK | Saves current edit changes.

Diconix 150 Plus

The Diconix 150 Plus printer does not support multiple paper destinations.

HP LaserJet IIP

The HP LaserJet IIP printer does not support multiple paper destinations.


Default and Supported Text Qualities

The Text Qualities dialog box identifies the default and supported text qualities. The default text quality appears in the dropdown list box at the top of the dialog box. The supported text qualities are highlighted in the list box.

The following list describes each of the controls in this dialog box.

Control | Description
Default | Specifies the default text-quality identifier.
List box | Lists the available text-quality identifiers for this printer.
Enable All | Enables all text-quality identifiers which appear in the list box.
Inhibit All | Inhibits all text-quality identifiers which appear in the list box.
Cancel | Cancels current edit changes.
OK | Saves current edit changes.

Diconix 150 Plus

The Diconix 150 Plus printer supports letter-, near-letter-, and draft-quality text output.

HP LaserJet IIP

The HP LaserJet IIP printer does not support multiple text qualities.


Default and Supported Compression Modes

The Compression dialog box identifies the default and supported graphics-data compression modes. The following list describes each of the controls in this dialog box.

Control | Description
Default | Specifies the default color model.
List box | Lists the available color models for this printer.
Enable All | Enables all color models which are identified in the list box.
Inhibit All | Inhibits all color models which are identified in the list box.
Cancel | Cancels current edit changes.
OK | Saves current edit changes.

Diconix 150 Plus

The Diconix 150 Plus printer does not support compression.

HP LaserJet IIP

The HP LaserJet IIP printer supports TIFF and run-length encoding (RLE) compression, with TIFF as the default.


Default and Supported Font Cartridges

The Font Cartridges dialog box identifies the default and supported font cartridges.

Control | Description
Default | Specifies the default font cartridge.
List box | Lists the available font cartridges for this printer.
Enable All | Enables all font cartridges which are identified in the list box.
Inhibit All | Inhibits all font cartridges which are identified in the list box.
Cancel | Cancels current edit changes.
OK | Saves current edit changes.

Diconix 150 Plus

The Diconix 150 Plus printer does not support detachable font cartridges.

HP LaserJet IIP

The HP LaserJet IIP printer supports 33 different font cartridges:

  • HP: WordPerfect
  • HP: ProCollection
  • HP: Global Text
  • HP: Great Start
  • HP: TextEquations
  • HP: Polished Worksheets
  • HP: Persuasive Presentations
  • HP: Forms, Etc
  • HP: Bar Codes & More
  • A: Courier(R)
  • B: Times(R) Proportional 1
  • C: International 1
  • D: Prestige Elite
  • E: Letter Gothic
  • F: Times Proportional 2
  • G: Legal Elite
  • H: Legal Courier
  • J: Math Elite
  • K: Math Times
  • L: Courier P&L
  • M: Prestige Elite P&L
  • N: Letter Gothic P&L
  • P: Times Roman(R) P&L
  • Q: Memo 1
  • R: Presentations 1
  • S1: Courier Document 1
  • S2: Times/Helvetica(R) Report 1
  • T: Tax 1
  • U: Forms Portrait
  • V: Forms Landscape
  • Y: PC Courier 1
  • Z: Microsoft 1
  • Z1A: Microsoft 1A


Default and Supported Color Models

The Color Models dialog box identifies the default and supported color models. The following list describes each of the controls in this dialog box.

Control | Description
Default | Specifies the default color model.
List box | Lists the available color models for this printer.
Enable All | Enables all color models which are identified in the list box.
Inhibit All | Inhibits all color models which are identified in the list box.
Cancel | Cancels current edit changes.
OK | Saves current edit changes.

Diconix 150 Plus

The Diconix 150 Plus does not support color output.

HP LaserJet IIP

The HP LaserJet IIP does not support color output.


Supported Page Controls

The PAGECONTROL dialog box identifies the supported page-control commands. These commands are sent to the printer to begin a document, begin a new page, and cancel the printing of a document.

Control | Description
List box | Lists the available page-control data for this printer.
Inhibit All | Inhibits all page-control data which is identified in the list box.
Cancel | Cancels current edit changes.
OK | Saves current edit changes.

Diconix 150 Plus

The Diconix 150 Plus supports a single set of page-control commands.

HP LaserJet IIP

The HP LaserJet IIP supports a single set of page-control commands.


Supported Cursor Movements

The CURSORMOVE dialog box identifies the supported cursor-movement commands. These commands are sent to the printer to move the cursor (or print head) horizontally and vertically across a page of paper.

Control | Description
List box | Lists the available cursor-movement data for this printer.
Inhibit All | Inhibits all cursor-movement data which is identified in the list box.
Cancel | Cancels current edit changes.
OK | Saves current edit changes.

Diconix 150 Plus

The Diconix 150 Plus supports a single set of cursor-movement commands.

HP LaserJet IIP

The HP LaserJet IIP supports the second of two sets of cursor-movement commands.


Supported Font Simulations

The FontSimulation dialog box identifies the supported font-simulation commands. These commands are sent to the printer to simulate bold, italic, underline, double-underline, strike-through, and proportional-space fonts. The following list describes each of the controls in this dialog box.

Control | Description
List box | Lists the available font-simulation data for this printer.
Inhibit All | Inhibits all font-simulation data which is identified in the list box.
Cancel | Cancels current edit changes.
OK | Saves current edit changes.

Diconix 150 Plus

The Diconix 150 Plus supports a single set of font-simulation commands.

HP LaserJet IIP

The HP LaserJet IIP supports a single set of font-simulation commands.


Supported Rectangle Fills

The Rectangle Fill dialog box identifies the supported rectangle-fill commands. The following list describes each of the controls in this dialog box.

Control | Description
List box | Lists the available rectangle-fill data for this printer.
Inhibit All | Inhibits all rectangle-fill data which is identified in the list box.
Cancel | Cancels current edit changes.
OK | Saves current edit changes.

Diconix 150 Plus

The Diconix 150 Plus does not support a rectangle-fill command.

HP LaserJet IIP

The HP LaserJet IIP does not support either of the two available rectangle-fill commands.


Supported Download Information

The Download Info dialog box identifies the supported download-info commands. These commands download fonts to the printer. The following list describes each of the controls in this dialog box.

Control | Description
List box | Lists the available download-info commands and data for this printer.
Inhibit All | Inhibits all download-info commands and data which are identified in the list box.
Cancel | Cancels current edit changes.
OK | Saves current edit changes.

Diconix 150 Plus

The Diconix 150 Plus does not support a download-info command.

HP LaserJet IIP

The HP LaserJet IIP does not support any of the three available download-info commands.


Specifying Printer Capabilities

The Capability Bitfields list box lists the names of eight selections. Of these eight, only three contain information used by the Microsoft® Windows® Universal Printer Driver. These three selections and their descriptions are provided in the following list.

Name | Description
fGeneral | Specifies the general capabilities of the printer model. These capabilities include double-sided printing, scrolling the cursor in the negative y-direction, and so on.
fText | Specifies the text-rendering capabilities of the printer model in portrait mode.
fLText | Specifies the text-rendering capabilities of the printer model in landscape mode.


Specifying General Printer Capabilities

The fGeneral dialog box identifies printer capabilities such as double-sided printing, multiple-copy printing, font rotation capabilities, bitmap rotation capabilities, and so on.

The following list describes each of the controls in this dialog box.

Control | Description
MD_SERIAL | Specifies that the output must be sorted sequentially in the y-direction, because the printer cannot scroll backwards.
MD_PARAMETERIZE | Specifies that the printer supports Hewlett-Packard Printer Control Language parameterized escape sequences.
MD_ROTATE_FONT_ABLE | Specifies that the printer can rotate hardware fonts to match the current paper orientation. Fonts supplied by Windows (TrueType, bitmap, and vector)are always available in both orientations.
MD_COPIES | Specifies that the printer supports multiple-copy printing.
MD_DUPLEX | Specifies that the printer supports double-sided printing.
MD_NO_ADJACENT | Specifies that the printer cannot fire adjacent pins on the print head in all resolutions. If adjacent pins can be fired in some resolutions but not others, this should be indicated for each resolution.
MD_LANDSCAPE_GRX_ABLE | Specifies that the printer can rotate a graphic image (or bitmap) to match the current paper orientation. If the printer is unable to rotate graphics, the Universal Printer Driver will perform the graphic rotation.
MD_ALIGN_BASELINE | Specifies that the printer aligns text output on the baseline rather than the top of the character bounding-box (the default alignment is the top of the bounding box).
MD_FONT_MEMCFG | Specifies that the memory available with this printer is reserved for downloaded fonts only. If this box is not checked, the memory is available for bitmaps as well. For more information about printer memory configuration, see Printer-Memory Configuration.
MD_LANDSCAPE_RT90 | Specifies that the printer rotates 90 degrees in the counterclockwise direction for landscape output (this means that the right side of a page or image is printed first). If this control is not set, the default rotation of 270 degrees in the clockwise direction is assumed. Only set this control if the printer supports a set-orientation command.
MD_USE_CURSOR_ORIG | Specifies that the cursor origin is calculated using the values entered in the cursor origin controls of the Paper Sizes dialog box. If the MD_USE_CURSOR_ORIG is not set, the cursor origin is the upper-left corner of the printable region.

Diconix 150 Plus

For the Diconix 150 Plus printer, the MD_SERIAL box is checked.

HP LaserJet IIP

For the HP LaserJet IIP printer, the MD_PARAMETERIZE, MD_COPIES, MD_ALIGN_BASELINE, MD_LANDSCAPE_RT90, and MD_USE_CURSOR_ORIG boxes are checked.


Specifying Portrait- and Landscape-Text Capabilities

The fText and fLText dialog boxes identify text-rendering capabilities in portrait and landscape mode when the selected font is a device font. (The fLText dialog box is identical to the fText dialog box; the fText dialog box specifies text rendering capabilities in portrait mode, and the fLText dialog box specifies text rendering capabilities in landscape mode.)

The following list describes each of the controls in the two dialog boxes.

Control | Description
TC_OP_CHARACTER | Indicates that the device can place device fonts at any pixel location. This is required for any device that supports device fonts.
TC_OP_STROKE | Indicates the device may omit any stroke of a device font.
TC_CP_STROKE | Indicates that device fonts may be clipped to a pixel boundary.
TC_CR_90 | Indicates that device fonts may only be rotated at 90-degree increments.
TC_CR_ANY | Indicates that device fonts may be rotated at any angle.
TC_SF_X_YINDEP | Indicates that device fonts may be scaled separately in the x and y direction.
TC_SA_DOUBLE | Indicates that device fonts may be scaled to twice their original size.
TC_SA_INTEGER | Indicates that device fonts may be scaled by any integer multiple.
TC_SA_CONTIN | Indicates that device fonts may be scaled by any amount, but the x and y ratios are preserved.
TC_EA_DOUBLE | Indicates that the device can make device fonts bold. If this bit is not set for minidrivers, GDI will attempt to bold device fonts by printing them twice.
TC_IA_ABLE | Indicates that the device driver has the ability to italicize device fonts. If this bit is not set, GDI will assume italics are not available.
TC_UA_ABLE | Indicates that the device driver has the ability to underline device fonts. If this bit is not set, GDI will underline the device fonts.
TC_SO_ABLE | Indicates that the device driver has the ability to strikeout device fonts. If this bit is not set, GDI will strikeout the device fonts.
TC_RA_ABLE | Indicates that GDI should enumerate any raster fonts available for this device in response to the EnumFonts function. If this bit is not set, GDI supplied raster fonts will not be enumerated in response to EnumFonts, although device fonts, TrueType fonts, and GDI vector fonts will continue to be enumerated.
TC_VA_ABLE | Indicates that GDI should enumerate any vector fonts available for this device in response to the EnumFonts function. If this bit is not set, vector fonts will not be available.
TC_RESERVED | Reserved; do not use.

Diconix 150 Plus

For the Diconix 150 Plus printer, the TC_OP_CHARACTER, TC_EA_DOUBLE, TC_IA_ABLE, TC_UA_ABLE, and the TC_RA_ABLE boxes are checked.

HP LaserJet IIP

For the HP LaserJet IIP printer, the TC_UA_ABLE box is checked.


Left Margin Width

The sLeftMargin box contains a value which specifies the width of the unprintable region on the left edge of the page. Typically, this value is only set for dot-matrix printers; it is specified in master units.

Diconix 150 Plus

For the Diconix 150 Plus printer, the maximum printable page width is 6.9 inches. Subtracting this value (6.9 inches) from the width of a page of paper (8.5 inches) leaves 1.6 inches for the borders of the page. Dividing 1.6 inches by 2 leaves .8 inches. This is the width of the left and right borders. Converting this value to horizontal master units (using the Xdpi value from the master-units dialog box), we obtain the value 768. This is the value that appears in the sLeftMargin box.

HP LaserJet IIP

For the HP LaserJet IIP printer, the unprintable left-margin measures .166 inches. Converting to master units (300 * .166 = 50), this value is entered in the sLeftMargin box.


Maximum Page Width

The sMaxPhysWidth box contains a value which specifies the maximum allowable physical page width in master units.

Diconix 150 Plus

For the Diconix 150 Plus printer, the maximum physical page width the printer can handle is 8.5 inches. Converting this value to horizontal master-units (using the Xdpi value from the master-units dialog box), we obtain the value 8160. This is the value that appears in the sMaxPhysWidth control.

HP LaserJet IIP

For the HP LaserJet IIP printer, the maximum printable page width is 8.5 inches. Converting this value to horizontal master units (300 * 8.5 = 2550), we obtain the value entered in the sMaxPhysWidth box.


Maximum Number of Fonts per Page

The sMaxFontsPage box contains a value which specifies the maximum number of device fonts that can appear on a single page. If there is no such limit for a printer, this value should be -1.

Diconix 150 Plus

For the Diconix printer, there is no limit to the number of device fonts allowed on a page; therefore, the sMaxFontsPage box contains the value -1.

HP LaserJet IIP

For the HP LaserJet IIP printer, there is no limit to the number of device fonts allowed on a page; therefore, the sMaxFontPage box contains the value -1.


Number of Cartridge Slots

The sCartSlots control contains a value which specifies the number of font-cartridge slots which appear on the printer.

Diconix 150 Plus

For the Diconix 150 Plus printer, the sCartSlots box contains the value 0.

HP LaserJet IIP

For the HP LaserJet IIP printer, the sCartSlots box contains the value 1.


Default Character-Translation Table

The Default CTT ID box contains a value which identifies the default character-translation table (CTT). If a single character-translation table is to be used for all device fonts, the ID value for that CTT should be entered here. If the Universal Printer Driver should not use a CTT, this value should be 0; if the Universal Printer Driver should use its own CTT, this value should be that CTT's ID multiplied by -1; if the Universal Printer Driver should use a driver-supplied CTT, this value should be that CTT's ID.

Diconix 150 Plus

For the Diconix 150 Plus printer, the Default CTT ID box contains the value 1.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Default CTT ID box contains the value 0.


Default Font ID

The Default Font ID box contains a value which identifies the default font that the Universal Printer Driver should use for text output when an application fails to request a specific font. It is suggested that the default font be set to a fixed pitch font: 10 point and 10 characters per inch, if at all possible.

Diconix 150 Plus

For the Diconix 150 Plus printer, the Default Font ID box contains the value 1.

HP LaserJet IIP

For the HP LaserJet IIP printer, the Default Font ID box contains the value 225.


LookAhead Region

The LookAhead Region box contains a value which specifies the length of the Lookahead Region in master units. This value should be 0 for most printer models; however, a nonzero value is required for HP DeskJet printers.

Diconix 150 Plus

For the Diconix 150 Plus printer, the LookAhead Region box contains the value 0.

HP LaserJet IIP

For the HP LaserJet IIP printer, the LookAhead Region box contains the value 0.


Device Fonts

The Resident Fonts button displays a dialog box which contains two list boxes. The list box on the left side contains the names of portrait-mode device fonts. The list box on the right side contains the names of landscape-mode device fonts.

Diconix 150 Plus

For the Diconix 150 Plus printer, the only resident font is 10-point Times Roman for portrait mode.

HP LaserJet IIP

For the HP LaserJet IIP printer, several fonts are available in both portrait and landscape orientation and are selected in each control.


Printer-Memory Configuration

The Memory Config button displays a dialog box which contains a list of possible printer memory configurations. If your printer supports Hewlett-Packard PCL and the driver supports downloadable fonts, you should select all possible memory configurations available for your device. A memory configuration is defined as the amount of RAM available on the printer to store raster bitmap graphics and downloaded font information. The Universal Printer Driver will use this information to make sure it does not send more data to the printer than it is capable of handling. If the user attempts to print a document requiring more available memory than the printer possesses, the Universal Printer Driver will display an error message and send only as much information as the device can process.

The value in the left column specifies the amount of memory available to the Universal Printer Driver to store downloaded font data and bitmap raster data. The value in the right column specifies the amount of memory that will be displayed as available. Because the printer typically reserves some memory for its own use, these two values are rarely the same. The list of memory configurations ranges from 65K/128K to 5212K/5.5M.

Diconix 150 Plus

For the Diconix 150 Plus printer, no memory configurations have been selected.

HP LaserJet IIP

For the HP LaserJet IIP printer, the 369/512K, 1419K/1.5M, 2243K/2.5M, 3467K/3.5M and 4491K/4.5M configurations are selected. The HP LaserJet IIP comes with 512K of memory.

At this point, you should have initialized all of the necessary data for your minidriver. You can build the driver by exiting the UniTool application, entering MS-DOS, and moving to the directory that contains your driver files. Type the xmsmake command to compile and link your minidriver.


Appendix A Minidriver Callback Functions

This appendix describes minidriver callback functions. A callback is a function supplied by a minidriver developer that the Microsoft Windows Universal Printer Driver calls at a particular point in time. The current version of the Universal Printer Driver supports two callbacks: the first is the FilterGraphics function and the second is the Dump function.


The FilterGraphics Function

The FilterGraphics function prepares a buffer of raster data (which it receives from the Universal Printer Driver) for rendering on the printer. The FilterGraphics function is necessary if a printer does not process graphics data in the manner supported by the Universal Printer Driver. For example, when the Universal Printer Driver passes a byte of raster data to a 9-pin dot-matrix printer, it orders the individual bits so that bit 7 corresponds to the top-most pin and bit 0 corresponds to the bottom-most pin. If a given printer addresses pins in a different format, it must provide a FilterGraphics function to correctly order the bits in each byte of data.


FilterGraphics Function Syntax

The FilterGraphics function has the following syntax:

short FAR PASCAL FilterGraphics(lpdv, lpBuf, len)
LPBYTE  lpdv;  /* points to private data required */
              /* by the Universal Printer Driver. */
LPSTR   lpBuf; /* points to buffer of graphics data. */
WORD    len;   /* length of buffer in bytes. */

The following list provides a brief description of the parameters.

Parameter | Description
lpdv | Points to private data required by the Universal Printer Driver. The FilterGraphics function passes this pointer as an argument to the CBFilterGraphics function which is exported by the Universal Printer Driver.
lpBuf | Points to the len parameter (which contains the length of the buffer of graphics data in bytes).
len | Specifies the length of the buffer to which the lpBuf parameter points.

The return value specifies the number of bytes of processed data if the function is successful.

Prior to returning, the FilterGraphics function must call the WriteSpoolBuf function which is exported by the Universal Printer Driver. This function has the following syntax:

short FAR PASCAL WriteSpoolBuf(lpdv, lpNewBuf, newlen)
LPBYTE  lpdv;       /* points to private data. */
LPSTR   lpNewBuf;   /* points to buffer of altered graphics data. */
WORD    newlen;     /* length of buffer in bytes. */

The following list provides a brief description of each parameter.

Parameter | Description
lpdv | Points to private data which was originally supplied by the Universal Printer Driver.
lpNewBuf | Points to the len parameter (which contains the length of the buffer of graphics data in bytes). This new graphics data was prepared by the FilterGraphics function.
len | Specifies the length of the buffer to which the lpNewBuf parameter points.


The BlockOut Function

In addition to providing the code for the function in the file DRIVERNAME.C, a minidriver developer must also:

  • Check the RES_BO_CB_FILTER_GRX box in the fBlockOut dialog box.

    From the Printer Data menu, choose the Graphics Info command. From the Graphics Info cascading menu, choose the Resolution command. From the RESOLUTION dialog box, you can select the fBlockOut entry in the Resolution Bitwords list box. This displays the fBlockOut dialog box.

  • Export the BlockOut function (using an ordinal value of 300) in the EXPORTS section of the minidriver's module-definition file. Import the WriteSpoolBuf function (using an ordinal value of 300) in the IMPORTS section of the minidriver's module-definition file.


The Dump Function

The Dump function converts (or rasterizes) Windows raster data into data that a printer can process. A minidriver developer can specify when Windows should call the Dump function. For example, a driver developer can specify that Windows should only call Dump when portrait mode is set.


Dump Function Syntax

The Dump function has the following syntax:

short FAR PASCAL Dump(lpdv, lpptCursor, fMode)
LPDV lpdv;          /* points to a Universal Printer Driver structure. */
LPPOINT lpptCursor; /* points to the cursor position. */
WORD fMode;         /* specifies the printer mode. */
Parameter | Description
lpdv Points to a the Universal Printer Driver data structure with the following syntax:
typedef struct _DEV {
  short iType;     /* identifies the printer type. */
  short oBruteHdr; /* offset to bitmap header. */
  HANDLE hMd;      /* minidriver handle. */
  LPSTR lpMd;      /* minidriver pointer. */
}
lpptCursor | Points to a POINT structure that contains the current cursor coordinates; these coordinates are relative to the cursor origin.
fMode | Identifies the printer mode.


Additional Dump Function Tasks

In addition to providing the code for the function in the file DRIVERNAME.C, a minidriver developer must also:

  • Make sure that any driver using its own Dump function must compile MINIDRIVE.C using the -DNOENABLE and -DNODISABLE switches. The linker will report errors due to conflicting function names otherwise.
  • Assume that device fonts will not be supported by the Dump function for serial printers.
  • Issue all of the required cursor-movement commands when rendering graphics data.
  • Return the final cursor position after processing the last band of graphics data.

The Universal Printer Driver calls the Dump function once for each band of graphics data. (A band of graphics data is equivalent to the amount of data rendered by a single horizontal pass of the print head when the printer is operating in a noninterlaced mode.) The last band rendered by the Dump function may be narrower than the width of the print head.


Appendix B UniTool Error Messages

Microsoft UniTool provides two ways of checking the data described in the minidriver for possible problems and reporting that information back to you. From the Options menu, you can choose two commands: Validate Dialog Boxes and Validate Now!.


Validate Dialog Boxes

The Validate Dialog Boxes command may be chosen or canceled at the discretion of the UniTool user. When it is chosen, whenever you display a dialog box and choose OK, Next, or Previous (that is, any choice that will cause the current dialog box contents to be saved rather than ignored), UniTool will perform some limited error checking on the contents of that dialog box. If any potential problems are found, a new dialog box listing all the potential problems will be displayed, and you may choose to ignore these warnings or return to the dialog box to correct them. All of the error messages, along with a corresponding explanation, are listed at the end of this appendix. If the Validate Dialog Boxes command is not chosen, error checking will not occur. This command is enabled by default.


Validate Now!

The Validate Now! command on the Options menu performs some limited error checking on the contents of the entire minidriver file currently loaded. If any potential problems are found, a new dialog box listing all the potential problems is displayed. All of the error messages, along with a corresponding explanation, are listed at the end of this appendix.


The MiniDriver Data Dialog Box

The following error messages are associated with the MiniDriver Data dialog box.

List | Description
Illegal GPC Major Version | UniTool issues this message if the value Number, must be 0<=n<=1 specified in the Major box is not 0 or 1.
Illegal GPC Minor Version | UniTool issues this message if the value Number, must be 0<=n<=255 specified in the Minor box is outside of the specified range (0 - 255).
Structure-Name Conversion error | UniTool issues this message whenever the new master units result in a round-off error after they are divided into a specified member in the MODELDATA, RESOLUTION, PAPER-SIZE, PAPER-SOURCE, CURSOR-MOVEMENT, or RECTANGLE-FILL data structures. For example, if the sLeftMargin box of the ModelData dialog box contains the value 179, and the horizontal master unit was changed from 360 to 180, the conversion error message would appear because 89.5/180 cannot be expressed as an integer value. UniTool also replaces the data structure identified by Structure-Name with the appropriate string.


The ModelData Dialog Box

The following error messages are associated with the ModelData dialog box.

List | Description
Every Model must havea name! | UniTool issues this message if a string is not entered in the Name of Model box.
sLeftMargin must be non-negative | UniTool issues this message if a negative value is entered in the sLeftMargin box.
sMaxPhysWidth must be > 0 | UniTool issues this message if a value less than or equal to zero is entered in the sMaxPhysWidth box.
Max Page Width must be equal to 0 or equal -1 | UniTool issues this message if a value that is > 0 or less than -1 is entered in the Max-Width page size limits box.
Max Page Height must be > 0 or equal -1 | UniTool issues this message if a value that is equal to 0 or less than -1 is entered in the Max-Height page size limits box.
Min Page Width must be > 0 | UniTool issues this message if a value that is less than or equal to 0 is entered in the Min-Width page size limits box.
MODELDATA Min Page Height must always be > 0 | UniTool issues this message if a value that is less than or equal to 0 is entered in the Min-Height page size limits box.
Default Font ID must refer to a valid font | UniTool issues this message if a value in the Default Font ID box is entered that does not identify a valid font resource.
Default CTT ID must refer to a valid CTT | UniTool issues this message if a value in the Default CTT ID box is entered that does not identify a valid character-translation table.
Look Ahead Region must be non-negative | UniTool issues this message if a value that is negative is entered in the LookAhead Region box.
sCartSlots must be non-negative | UniTool issues this message if a negative value is entered in the sCartSlots box.
minidriver name supports Font Cartridges, but has no Cartridge slots | UniTool issues this message if the developer enters the value 0 in the sCartSlots box and selected one or more font cartridges in the supported-attributes Font Cartridges dialog box. The Font Cartridges dialog box is associated with the ModelData dialog box.
minidriver name has no PageControl! | UniTool issues this message if the developer fails to identify supported page-control commands and data in the ModelData dialog box.
minidriver name has no CursorMove! | UniTool issues this message if the developer fails to identify supported cursor-movement commands and data in the ModelData dialog box.
minidriver name has no Resolutions! | UniTool issues this message if the developer fails to identify supported-resolution commands and data in the ModelData dialog box.
minidriver name has no Paper Sizes! | UniTool issues this message if the developer fails to identify supported paper-size commands and data in the ModelData dialog box.
minidriver name: Memory Values not used for non-HPPCL devices | UniTool issues this message if the minidriver chooses one of the listed memory configurations in the ModelData dialog box for a printer that does not use PCL.


The RESOLUTION Dialog Box

The following error messages are associated with the RESOLUTION dialog box.

List | Description
Every RESOLUTION must have a format string | UniTool issues this message if a format string for the selected resolution is not entered.
minidriver name Illegal Text X DPI value | UniTool issues this message if an invalid horizontal text resolution is entered.
minidriver name Illegal Text Y DPI value | UniTool issues this message if an invalid vertical text resolution is entered.
minidriver name Illegal Graphics X DPI value | UniTool issues this message if an invalid horizontal graphics resolution is entered.
minidriver name Illegal Graphics Y DPI value | UniTool issues this message if an invalid vertical graphics resolution is entered.
minidriver name: sNPins must be 1,8,16,32,40,48... | UniTool issues this message if an illegal value is entered in the sNPins box.
minidriver name: sPinsPerPass must be 1,8,16,32,40,48... | UniTool issues this message if an illegal value is entered in the sPinsPerPass box.
minidriver name: sMinBlankSkip must be >= 0 | UniTool issues this message if an illegal value is entered in the sMinBlankSkip box.
minidriver name :sMinBlankSkip should be > 0 | UniTool issues this message if a negative value is entered in the sMinBlankSkip box and the RES_BO_ENCLOSED_BLNKS box is checked in the fBlockOut dialog box.
minidriver name: Spot Diameters must be > 0 | UniTool issues this message if a negative value is entered in the sSpotDiameter box.
minidriver name: Unknown iDitherBrush | UniTool issues this message if an undefined value is entered in the iDitherBrush box.
minidriver name: RES_DM_GDI conflicts with sNPins or sPinsPerPass | UniTool issues this message if a value greater than 1 is entered for sNPins or sPinsPerPass and the RES_DM_GDI box is checked in the fBlockOut dialog box.


The Paper Sizes Dialog Box

The following error messages are associated with the Paper Sizes dialog box.

List | Description
minidriver name :Illegal X Size | UniTool issues this message if an illegal paper width is entered.
minidriver name :Illegal Y Size | UniTool issues this message if an illegal paper height is entered.
minidriver name :Illegal Top Margin | UniTool issues this message if an illegal top-margin height is entered.
minidriver name | UniTool issues this message if an illegal :Illegal Bottom Margin bottom-margin height is entered.
minidriver name :Illegal Left Margin | UniTool issues this message if an illegal left-margin width is entered.
minidriver name :Illegal Right Margin | UniTool issues this message if an illegal right-margin width is entered.
minidriver name :Illegal fPaperType bit(s) set | UniTool issues this message if the developer selects an illegal paper-type box.


The Font Cartridge Dialog Box

The following error message is associated with the Font Cartridge dialog box.

List | Description
Font Cartridge Must have a Name | UniTool issues this message if the developer fails to enter a string identifying the selected font cartridge.


The PAGECONTROL Dialog Box

The following error message is associated with the PAGECONTROL dialog box.

List | Description
minidriver name :Max Copy Count must be >= 0 | UniTool issues this message if a value for the maximum copy count that is less than 0 is entered.


The CURSORMOVE Dialog Box

The following error messages are associated with the CURSORMOVE dialog box.

List | Description
minidriver name :sMult !=0 or 1 for abs. Y move | UniTool issues this message if the value entered in the sUnitMult box of the associated Units dialog box is not 0 or 1.
minidriver name :sMult !=0 or 1 for rel. Y move | UniTool issues this message if the value entered in the sUnitMult box of the associated Units dialog box is not 0 or 1.
minidriver name :sMult !=0 or 1 for rel. up Y move | UniTool issues this message if the value entered in the sUnitMult box of the associated Units dialog box is not 0 or 1.
minidriver name :sMult !=0 or 1 for linespacing Y move | UniTool issues this message if the value entered in the sUnitMult box of the associated Units dialog box is not 0 or 1.


The FONTSIMULATION Dialog Box

The following error messages are associated with the FONTSIMULATION dialog box.

List | Description
minidriver name :sBoldExtra must be >= 0 | UniTool issues this message if a negative value is entered in the sBoldExtra box.
minidriver name :sItalicExtra must be >= 0 | UniTool issues this message if a negative value is entered in the sItalicExtra box.
minidriver name :sBoldItalicExtra must be >= 0 | UniTool issues this message if a negative value is entered in the sBoldItalicExtra box.


The DEVCOLOR Dialog Box

The following error messages are associated with the DEVCOLOR dialog box.

List | Description
minidriver name :sPlanes must = 3 or 4 | UniTool issues this message if a value is entered in the sPlanes box which is not equal to 3 or 4.
minidriver name :sBitsPerPixel must = 1 | UniTool issues this message if a value is entered in the sBitsPerPixel box that is not equal to 1.
minidriver name :DC_PRIMARY_RGB conflicts w/ number of planes | UniTool issues this message if the developer's DC_PRIMARY_RGB selection contradicts the specified number of planes.
minidriver name :DC_EXTRACT_BLACK conflicts w/ number of planes | UniTool issues this message if the developer's DC_EXTRACT_BLACK selection contradicts the specified number of planes.


The DOWNLOADINFO Dialog Box

The following error messages are associated with the DOWNLOADINFO dialog box.

List | Description
minidriver name :Bitmap Font Descriptor must be > 0 | UniTool issues this message if a bitmap font-descriptor value that is negative is entered.
minidriver name :Bitmap Char Descriptor must be > 0 | UniTool issues this message if a bitmap character-descriptor value that is negative is entered.
minidriver name :fFormat DLI_FMT_PCL not set | UniTool issues this message if the developer fails to check the DLI_FMT_PCL box for a PCL printer.


The Printer Font Metric Dialog Box

The following error messages are associated with the Printer Font Metric (PFM) dialog box.

List | Description
minidriver name :Type must = 128 | UniTool issues this message if the value in the Type box does not equal 128.
minidriver name :Points must be > 0 | UniTool issues this message if a point size value that is less than or equal to zero is entered.
minidriver name :VertRes must be > 0 | UniTool issues this message if a vertical resolution value that is less than or equal to zero is entered.
minidriver name :HorizRes must be > 0 | UniTool issues this message if a horizontal resolution value that is less than or equal to zero is entered.
minidriver name :Ascent must be > 0 | UniTool issues this message if a value in the Ascent box that is less than or equal to zero is entered.
minidriver name :Weight should be 400 or 700 | UniTool issues this message if a value in the weight box that is not equal to either 400 or 700 is entered.
minidriver name :CharSet must be 0,1, or 2 | UniTool issues this message if a value in the Char Set box that is not equal to 0, 1, or 2 is entered.
minidriver name :AvgWidth must be > 0 | UniTool issues this message if a negative value is entered in the Average Width box.
Kerning Info will be lost! Continue? | UniTool issues this message if kerning information will be lost.


The Character Translation Table Dialog Box

The following error messages are associated with the Character Translation Table (CTT) dialog box.

List | Description
Must be 0 < n < 255 | UniTool issues this message if the specified character code is not an integer value between 1 and 255.
Can't have LastChar < FirstChar | UniTool issues this message if the specified character code for the first character is greater than the specified character code for the last character.


General Errors

The following error messages are general errors which UniTool issues.

List | Description
No errors were found! | UniTool issues this message if no errors were found after the developer chooses the Validate Now! command.
Numeric Value required! | UniTool issues this message if the developer enters a non-numeric value instead of a numeric value.
Illegal string! | UniTool issues this message if an illegally formatted string is entered.
Global Memory Allocation failed | UniTool issues this message if it is not able to allocate required memory. If this error occurs, exit UniTool and the Windows application without attempting to save data.
Can't Save File! minidriver name | UniTool issues this message when it cannot save the file using the specified filename.
Can't Find File! minidriver name | UniTool issues this message if it cannot find the requested file.
Bad Format GPC file | UniTool issues this message if the developer requests that it load a GPC file with an illegal format.
Newer version of UniTool needed to read this file | UniTool issues this message if the developer must load a newer version of UniTool in order to edit the specified GPC file.
Save Failed, restoring original files | UniTool issues this message if it cannot save a GPC file, and must therefore restore the original files.
Can't read font file: minidriver name | UniTool issues this message if it cannot read the specified font file.
Bad format Font file: minidriver name | UniTool issues this message if the format of the specified font file is illegal.
Not a device font PFM file: minidriver name | UniTool issues this message if the specified font files do not correspond to a device font.
Can't read PFMEXTENSION, unable to access DRIVERINFO | UniTool issues this message if it cannot parse the PFMEXTENSION data structure in the PFM file. (If UniTool cannot parse the PFMEXTENSION structure, it will not be able to read the DRIVERINFO structure.)
Can't read RC File: minidriver name | UniTool issues this message if it is not able to read the specified font file.
Bad Format RC File | UniTool issues this message if the specified RC file uses an illegal format.
Can't save RC File: minidriver name | UniTool issues this message if it cannot save the specified resource file.
Can't find string with requested ID | UniTool issues this message if the GPC file contains an entry in its string table that is not present in the corresponding RC file.
Unresolved STRINGTABLE reference for ID:minidriver name | UniTool issues this message if it cannot resolve the specified string-table reference.
Unable to retrieve font file names, Can't save file | UniTool issues this message if it cannot retrieve the specified font files, and therefore save the corresponding resource file.
Unable to retrieve CTT file names, Can't save file | UniTool issues this message if it cannot retrieve the specified CTT files, and therefore save the corresponding resource file.
Unable to retrieve RC strings, Can't save file | UniTool issues this message if it cannot retrieve strings, Can't save the minidriver's resource strings, and therefore cannot save the file.
RC file doesn't reference GPC file:minidriver name | UniTool issues this message if the specified resource file does not contain a reference to the listed GPC file.
RC file lists duplicate font files | UniTool issues this message if the specified resource file contains duplicate font-file entries.
RC file lists duplicate CTT files | UniTool issues this message if the specified resource file contains duplicate CTT entries.
RC file has non-contiguously numbered font files | UniTool issues this message if the specified resource file contains noncontiguous identifiers for minidriver font files.
STRINGTABLE missing END statement | UniTool issues this message if the specified resource file contains a string table that is missing an END statement.
Illegal STRINGTABLE entry in:minidriver name | UniTool issues this message if the specified resource file contains an illegal string-table entry.
Illegal GPC file entry:minidriver name | UniTool issues this message if it cannot parse the entry for the GPC file which appears in the resource file.
Illegal Font file entry:minidriver name | UniTool issues this message if it cannot parse the entry for a font file which appears in the specified resource file.
Illegal CTT file entry:minidriver name | UniTool issues this message if it cannot parse the entry for a CTT file which appears in the specified resource file.
GPC and/or RC file is read only,Save will be disabled:minidriver name | UniTool issues this message if either the specified resource file or the associated GPC file was saved with read-only permission.
Illegal DRV name, must be between 1-8 chars | UniTool issues this message if the developer specifies a minidriver name that exceeded 8 characters.
Must Provide a Destination Directory | UniTool issues this message if the directory name (that is specified as part of the minidriver name) is not valid.
Can't change drives: minidriver name | UniTool issues this message if it cannot switch to the specified driver.
Can't create directory:minidriver name | UniTool issues this message if it cannot create the specified directory.
Can't find minidriver name in UNITOOL.INF | UniTool issues this message if it cannot find an entry for the specified minidriver in the UNITOOL.INF file.
Can't find UNITOOL.INF in Windows directory | UniTool issues this message if it cannot locate the file named UNITOOL.INF.
Can't add atom for minidriver name | UniTool issues this message if it cannot process a string. If this error occurs, exit UniTool and Windows.
Requested CTT ID value already used by: minidriver name | UniTool issues this message if the specified CTT identifier is already in use.
Replacement CTT ID doesn't exist! | UniTool issues this message if the specified replacement CTT does not exist.
Can't save CTT reference change in: minidriver name | UniTool issues this message if it is not able to save the font file after a reference to a CTT was changed.
Can't update Read Only file: minidriver name | UniTool issues this message if it is not able to save a font file which was saved with read-only permissions.
Default Font ID in: minidriver name Is no longer valid! | UniTool issues this message if it deletes a font file that contained the minidriver's default font.
No structures of this type have been defined | UniTool issues this message if the developer attempts to modify data that has not been defined.
Target Directory doesn't exist, Create? | UniTool issues this message if the specified directory does not exist.
OverWrite the file: minidriver name | UniTool issues this message prior to overwriting and existing minidriver file.


Appendix C Printer Font Metric Data Structure for the Universal Printer Driver

The following structure is used by all Printer Font Metrics (PFM) files used by drivers that are supported by the Microsoft Windows Universal Driver.

    typedef struct
    {
        short   sSize;       // size of this structure.
        short   iVersion;    // version number.
        WORD    fCaps;       // members describing capabilities.
        short   iFontID;     // unique font ID defined by the driver.
        short   sYAdjust;    // adjust y position before output character
                             // used by double height character.
        short   sYMoved;     // cursor moved after printing this font.
        short   iTransTab;   // index to translation table resource.
        short   sUnderlinePos;
        short   sDoubleUnderlinePos;
        short   sStrikeThruPos;
        LOCD    locdSelect;  // long offset to command descriptor.
        LOCD    locdUnSelect;// long offset to command descriptor to
                             // cancel selection.
        WORD    wPrivateData;// private data to be used by minidriver.
        short   sShift;      // number of pixels to shift each character.
    } DRIVERINFO;

Members

sSize
Specifies the size of the structure.
iVersion
Specifies the version number of this structure. This specification describes version 0x0100 (implied decimal for version 1.00).
fCaps
Specifies the bit flags describing capabilities.
Value | Meaning
DF_NOITALIC | This font cannot be italicized using FONTSIMULATION.
DF_NOUNDER | This font cannot be underlined using FONTSIMULATION.
DF_XM_CR | A carriage return is sent after using this font.
DF_NOBOLD | This font cannot be made bold using FONTSIMULATION.
DF_NO2UNDERLINE | This font cannot produce double underlines using FONTSIMULATION.
DF_NOSTRIKETHRU | This font cannot be struck through using FONTSIMULATION.
DF_BKSP_OK | This fonts uses a CTT_WTYPE_PAIRED character-translation table to determine how to overstrike characters. If it is set, it is assumed that a single backspace character can be used to move the cursor to the start of the bounding box of the previous character prior to overstriking. If it is not set, it is assumed that explicit x-movement commands are required to position the cursor for an overstrike. If the font does not use a CTT_WTYPE_PAIRED translation table, this flag is ignored.

iFontID
Reserved; do not use.
sYAdjust
Specifies the distance to move the current y position, as expressed in master units, before printing characters in this font and size. This member is primarily used for double-height characters, and the specified distance to align the baseline accurately.
sYMoved
Specifies the distance to move the y position, as expressed in master units, after printing with this font and size. This member is also used to compensate for fonts that do not restore the cursor to the correct y position. It is primarily used for double-height characters.
iTransTab
Specifies the index to character-translation table resource for this font. This may zero, a positive, or negative number. If this is zero, use the character-translation table referred to in the ModelData dialog box for this model. If this is a negative number, the Universal Printer Driver will take the absolute value and use its own character-translation table resource with this ID. If this is a positive value, the Universal Printer Driver will use the driver-defined character-translation table resource with this ID value.
sUnderlinePos
Specifies the position of the hardware underline created by FS_OCD_ST_UNDERLINE_ON from the bottom of the character-bounding box. This member is measured in master units.
sDoubleUnderlinePos
Specifies the position of the hardware double underline created by FS_OCD_ST_DOUBLEUNDERLINE_ON from the bottom of the character-bounding box. This member is measured in master units.
sStrikeThruPos
Specifies the position of the hardware strikethrough created by FS_OCD_ST_STRIKETHRU from the bottom of the character-bounding box. This member is measured in master units.
locdSelect
Specifies the long offset to the command descriptor to select this font.
locdUnSelect
Specifies the long offset to the command descriptor to cancel the selection of this font. This member is NOOCD if not used.
wPrivateData
Specifies the private data to be used by the minidriver.
sShift
Specifies the number of pixels to shift each character to the left or right. Negative numbers shift to the right; positive numbers shift to the left.


Appendix D Character-Translation Table File Formats

A character-translation table is used by Microsoft Windows and the Microsoft Windows Universal Printer Driver to remap characters from the printer's native character and symbol set to the Windows ANSI set. The Universal Printer Driver will provide support for some of the common code pages and symbol sets, so that this data will not need to be redundant in a large number of individual printer drivers. It is intended that printer drivers supporting devices with less common code pages and symbol sets will contain their own character-translation table resources. Any given driver can mix and match either of these types of character-translation tables as needed. Character-translation tables provided by the Universal Printer Driver are referenced from the minidriver through negative numbers that correspond to the resource ID values (from the Universal Printer Driver), and character-translation tables provided by the minidriver are referenced by positive numbers corresponding to the resource ID values (from the minidriver).


Predefined Translation Tables

The Universal Printer Driver will provide support for some of the common code pages and symbol sets, and allow drivers to support less common ones.

The list of character-translation tables currently supported by the Universal Printer Driver is as follows:

#define CTT_CP437 -1 \\ IBM Code Page 437.

#define CTT_CP850 -2 \\ IBM Code Page 850.


TRANSTAB Structure

There are three formats of character-translation tables available for use.

The first is a single byte-to-byte translation used for simple remappings.

The second is a single byte-to-two bytes translation, where the second character is used to overstrike the first. The DI_BKSP_OK flag determines how the cursor should be repositioned to overstrike the second character.

The third allows a single byte-to-variable length string that may contain commands to change symbol sets, or whatever else is necessary, to create the desired character. This difference between these formats is transparent to the user, but UniTool creates the character-translation table in the format resulting in the smallest file size depending upon the actual translations specified by the user. Any printer commands sent from the CTT cannot change the permanent state of the printer.

    typedef struct {
        WORD    wType;            // indicates type of translation table.
        BYTE    chFirstChar;
        BYTE    chLastChar;
        union
            {
            short    psCode[1];
            BYTE     bCode[1];
            BYTE     bPairs[2][1];
            } uCode;
    } TRANSTAB;

Members

wType
Specifies the type of translation table.
Value | Meaning
CTT_WTYPE_COMPOSE | uCode is an array of 16-bit offsets from the beginning of the file pointing to the strings to use for translation. The length of the translated string is the difference between the next offset and the current offset. Please note that an additional offset is needed (dfLastChar + 1) to provide a means to read the length of the string for the translation of the last character.
CTT_WTYPE_DIRECT | uCode is a byte array of one-to-one translation table from chFirstChar to chLastChar.
CTT_WTYPE_PAIRED | uCode contains an array of paired, unsigned bytes. If only one character is needed to do the translation, then the second byte is zero, otherwise the second byte is struck over the first byte.

chFirstChar
First character in character-translation table.

chLastChar

Last character in character-translation table.


Glossary

This glossary contains terms and acronyms of interest to driver writers.


A

AC-3
An audio standard for delivering 5.1 audio developed by Dolby Laboratories. This system compresses six channels of digital audio into 384 Kbps versus 4 Mbps uncompressed.
accelerated graphics port (AGP)
A technology that provides a dedicated, high speed port through which large blocks of 3D texture data can be moved between the computer's graphics controller and system memory.
accelerator
In DirectX Video Acceleration, the functional unit that executes simple but high-rate operations such as IDCT, MCP, display format conversion.
access control entry
An individual entry in an access control list (ACL). An access control entry (ACE) contains an SID and describes the access rights to a system resource by a specific user or group of users. Each object has a set of all ACEs, which is used to determine whether an access request to the object is granted.

See also security descriptor.

access control list
An ordered list of access control entries (ACEs).
access point (AP)
A base station that controls an 802.11 LAN Basic Service Set (BSS). Access points are required for 802.11 infrastructure configurations.
access right
A permission granted to a process to manipulate a specified object in a particular way (by calling a system service). Different system object types support different access rights, which are stored in an object's access control list (ACL).

See also ACL.

access violation
An attempt to execute a memory operation that is not allowed by the underlying page protection. Applies to memory operations; does not apply to checking user-mode access rights to objects by the Security Manager.

See also probe and SEH.

There are four types of access violations. An access violation occurs if you attempt:

  • An invalid operation, such as writing to a read-only page.
  • To access memory beyond the limit of the current program's address space (known as a length violation).
  • To access a page to which the system forbids access. For example, code is not allowed to run in the low-order 64K of the system's user-mode address space in order to simplify the detection of NULL pointer references.
  • To access a page that is currently resident but dedicated to the use of a system component. For example, user-mode code is not allowed access a page that the kernel is using.
ACE
See access control entry and advanced computing environment .
ACK
Acknowledge control packet. A control packet used by a destination station to acknowledge the receipt of a packet of data.
ACL
See access control list.
ACPI
Advanced Configuration and Power Interface. An abstract interface that defines a power management and configuration mechanism for hardware and operating systems. Part of the industry-wide OnNow Initiative, ACPI is defined in the industry-sponsored ACPI Specification.
Active Server Page (ASP)
A server-side scripting environment used to create Web pages and build Web applications. Active Server Pages (ASPs) are files that contain HTML tags, text, and script commands. ASPs can call ActiveX components to perform tasks such as connecting to a database, performing a business calculation, or creating a printer Web page.

See also COM Interfaces for Printer Web Pages.

ad hoc mode
Enables direct communication between stations. Ad hoc mode does not require an infrastructure. Stations operating in ad hoc mode operate in an Independent BSS (IBSS) without an ESS.
adapter object
An object type available only in kernel mode, defined by the I/O Manager and supported by the underlying HAL component. An adapter object represents a hardware bus adapter or DMA controller channel. Adapter objects "connect" different kinds of devices on the bus or DMA controller, each device (or kind of device) with its own driver.
Adobe Font Metrics (AFM)
Files that contain font metrics and pair kerning information for Type 1 fonts. Also called PostScript fonts.
ADPCM
Adaptive Differential Pulse Code Modulation. An encoding format for storing audio information in a digital format.
ADSL
Asymmetric Digital Subscriber Line. A method for moving data over regular phone lines. An ADSL circuit is much faster than a regular phone connection, and the wires coming into the subscriber's premises are the same (copper) wires used for regular phone service.
advanced computing environment
A consortium of hardware and software companies formed to promote an open computing environment.
advanced RISC computing
A RISC-based computer architecture standard, associated with the ACE consortium. Advanced RISC computing (ARC) machines include both RISC- and CISC-based platforms, and supply the following components to the operating system loader:
  • On ACPI-compliant platforms, a set of machine firmware that supports bootstrap loading and execution as an "abstracted" set of ARC routines and ARC devices.
  • On non-ACPI-compliant platforms, the NT-based operating system provides a hardware recognizer (Ntdetect) that detects the necessary devices to bootstrap the system. Ntdetect queries the ROM BIOS and builds a hardware database that emulates the RISC-based ARC firmware.
  • On both kinds of platforms, a HAL that interfaces between the hardware and the system. See also HAL.

Device drivers for certain types of devices create an alias between the names of their device objects and the corresponding ARC device name by calling IoAssignArcName.

affinity
  1. A programmer-defined attribute of a process and/or thread on a multiprocessor platform:
    • For a process, affinity is the programmer-determined set of processors on which its threads are permitted to run.
    • For a thread, affinity by default is identical to that of the process to which it belongs; otherwise, its affinity must be a proper subset of the default process affinity.
  2. The set of processors on which a particular interrupt is enabled in a given machine.
agent
Software that runs on a client computer for use by administrative software running on a server. Agents are typically used to support administrative actions, such as detecting system information or running services.
alert
A Boolean value that provides a way to break into a thread's execution at a point where the thread either:
  • Is in an alertable wait state (as specified when the wait service was called).
  • Polls the alerted flag.
alpha blending
A technique by which the color in a source bitmap is combined with that in a destination bitmap to produce a new destination bitmap.

GDI performs per-pixel alpha blending, according to the formula: Blend = Alpha * Source + (1 - Alpha) * Destination. This formula is used to compute the alpha blend at each pixel, for each of the red, green, and blue color channels.

AML
ACPI Machine Language. Pseudocode for a virtual machine supported by an ACPI-compatible operating system and in which ACPI control methods are written. The AML encoding definition is provided in the Advanced Configuration and Power Interface Specification.
analog simultaneous voice and data (ASVD)
A signaling method that mixes voice and data.
anamorphic
Unequally scaled in vertical and horizontal dimensions.
animation
The display of a series of graphic images, simulating motion. Animation can be frame-based or cast-based.
APC
See asynchronous procedure call .
ARC
See Advanced RISC Computing.
ASL
ACPI Source Language. The programming-language equivalent for AML. ASL is compiled into AML images. The ASL statements are defined in the Advanced Configuration and Power Interface Specification.
aspect ratio
The relationship between the width and height of an image. When an image is displayed on different screens, the aspect ratio must be kept the same to avoid either vertical or horizontal stretching.
associated IRP
One of a set of IRPs, created by the highest-level driver in a chain of layered drivers, that specifies some part of an I/O request to be sent on to a lower-level driver. When all associated IRPs in the set have been processed, the I/O Manager completes the original request.

See also IRP.

association
The exchange of information about the station and BSS capabilities. The process of association occurs after authentication is completed. A station that has completed the process of association can receive and transmit data frames.
ASVD
See analog simultaneous voice and data.
asymmetric compression
A system that requires more processing capability to compress than to decompress an image. It is typically used for the mass distribution of programs on media such as CD-ROM, where significant expense can be incurred for the production and compression of the program, but the playback system must be low cost.

Compare with symmetric compression

asynchronous I/O
A model for I/O in which the operations carried out to satisfy I/O requests do not necessarily occur in sequence. The application that originally made the request can continue executing (rather than waiting for its I/O to complete), the I/O Manager or a higher-level driver can reorder I/O requests as they are received, and a lowest-level driver can start an I/O operation on a device before it has completed the preceding request, particularly in a multiprocessor machine.
asynchronous procedure call
A kernel-defined control object which represents a procedure that is called asynchronously. Asynchronous procedure calls (APCs) are thread-context dependent; that is, they are queued to a particular thread for execution. There are three different types of APCs in the kernel:
  • User APC—used by certain asynchronous system services to allow user-mode applications or protected subsystems to synchronize thread execution with the completion of an operation or with an event such as a timer's expiration. User APCs are, by default, disabled; that is, they are queued to the user-mode thread, but are not executed, except at well-defined points in the program. Specifically, they can be executed only when an application or protected subsystem has either called a wait service and has enabled alerts to occur, or called the test-alert service.
  • Kernel APC—normal kernel-mode APCs. They are much like a normal user APC except that they are executable by default. That is, they are enabled except when the thread is already executing a Kernel APC. (Note that a special Kernel APC always pre-empts a normal Kernel APC.)
  • Special Kernel APC—an APC that cannot be blocked, except by running at a raised IRQL. Special Kernel APCs are executed at APC_LEVEL IRQL (see IDT), in kernel mode. These types of APCs are used by the system to force a thread to execute a procedure in the thread's context. For example, when the I/O Manager needs to get back into the context of the original requestor of the I/O operation so that it can copy buffers, and so forth. In order to do this, the I/O Manager must be able to access the virtual address space of the thread/process, and the most efficient way to complete the operation is to be in the calling thread's context.
asynchronous rendering
A display driver supports asynchronous rendering if it can hand off a batch of one or more DDI drawing operations to the graphics coprocessor, returning immediately to GDI. In order to perform graphics operations of its own, GDI must synchronize itself with the bitmap or surface. To do this, GDI calls a display driver-implemented synchronization routine called either DrvSynchronize (for device-managed surfaces) or DrvSynchronizeSurface (for arbitrary surfaces).

See synchronization routine.

AT
Command set A telecommunication (AT) device control protocol. This protocol is used to control modems.

See also, TIA-602 and V.25ter.

ATA
AT Attachment. An integrated bus usually used between host processors and disk drives. Used interchangeably with IDE.
ATAPI
AT Attachment Packet Interface. A hardware and software specification that documents the interface between a host computer and CD-ROM drives using the ATA bus.
ATM
Asynchronous transfer mode. A transmission protocol that segments user traffic into small, fixed-size units called cells, which are transmitted to their destination, where they are reassembled into the original traffic. During transmission, cells from different users may be intermixed asynchronously to maximize utilization of network resources.
audio class
The class of filters that deal with PCM (Pulse Code Modulation) or similar digitized data or analog signals.
authentication
The interchange of information between the access point and the station, where each side proves the knowledge of a given password. Authentication is required before a station can join a BSS through an access point that the station has located.
AV/C
The protocol used to communicate with Audio/Video Control (AV/C) devices. Examples of AV/C devices include Mini Digital Video Camcorders and time-shifting digital recorders.


B

backing store
A mass-storage device such as a disk that serves as backup "memory" for paging when physical memory is full.

See also paging file.

balance set
The set of processes processes whose threads are eligible for execution.

A process is either included in or excluded from the balance set. A kernel-mode process remains in the balance set while any of its threads owns a mutex object. Each thread that owns one or more mutexes continues to run until it releases its last mutex, when the thread is suspended. Until every thread has released every mutex, the process remains part of the balance set.

At any given moment, the balance set depends on the amount of physical memory (pages) available to back the virtual address space associated with each active process. If a physical memory shortage occurs, the Memory Manager first reduces the working set for each active process to its minimum, and then removes processes from the balance set, if necessary.

See also dispatch state and working set.

bank
See banked memory.
bank manager
Code that maps banked memory for CPU access.
banked callback
A callback routine provided by the display drive to enable GDI to access banked memory. GDI cannot directly access banked memory that is associated with a banked frame buffer. Consequently, the display driver of a device with such a frame buffer must divide the frame buffer into a series of contiguous banks and provide a means for GDI to perform its draw operations to the appropriate frame buffer banks. That is, GDI is made to write data to one bank of the frame buffer before being moved to subsequent banks, as necessary, to complete the draw operation through a mechanism referred to as "banked callbacks."
banked memory
Memory that is partitioned into distinct blocks. Prior to the advent of PCI devices, most video cards could expose only 64 KB of video memory to the system at a time. This memory was present at physical address 0xa0000. The video card typically had considerably more than 64 KB of memory, and would map views of this larger frame buffer into the 64 KB window. This process was referred to as banking. A bank is one 64 KB block of the frame buffer. The current bank is the bank that is visible to the CPU.
based section
A section allocated at the same virtual address for each process that has a view of the section.

See also section and view.

Basic Service Set (BSS)
A cell in an 802.11 LAN. An 802.11 LAN uses a cellular architecture that divides the system into a number of cells.
Basic Service Set identifier (BSSID)
Identifies a Basic Service Set.(BSS).

See also, Basic Service Set.

BCB
See buffer control block .
big-endian
A processor memory architecture in which byte N is the most significant, and in conventional layout diagrams, is the leftmost byte of:
  • A word composed of bytes N and (N + 1).
  • A doubleword composed of bytes N, (N + 1), (N + 2), and (N + 3).
  • A K-byte memory entity composed of bytes N, (N + 1),...,(N + K – 1).

The address of the preceding word, doubleword, or K-byte entity is its most significant byte, N.

Some RISC processors can be configured for either big-endian or little-endian byte addressing. For a big-endian configuration, the most significant bit of a 16-bit short value is the leftmost bit at byte N, while the least significant bit is the rightmost bit of byte (N + 1).

The terms "big-endian" and "little-endian" are derived from Jonathan Swift's Gulliver's Travels.

See also little-endian.

BIOS
Basic input/output system. A set of low-level routines that works closely with the hardware to support the transfer of information between elements of the system, such as memory, disks, and the monitor. Although critical to performance, the BIOS is usually invisible to the end user; however, programmers can access it.
BIOS enumerator
In a non-ACPI Plug and Play system, the BIOS enumerator identifies the hardware devices on the motherboard of the computer. The BIOS supports a programming interface that allows all Plug and Play computers to be queried in a common manner.
bit-block transfer
A programming technique that manipulates blocks of bits in memory that represent the color and other attributes of a rectangular block of pixels forming a screen image. The bit block is moved through a computer's video RAM as a unit so that its pixels can be rapidly displayed in a desired location on the screen. The bits can also be altered: light and dark portions of an image can be reversed, for example. Successive displays can thus be used to change the appearance of an image or to move it around on the screen. Some computers contain special graphics hardware to manipulate bit blocks on the screen independently of the contents of the rest of the screen. This speeds the animation of small shapes, because a program need not constantly compare and redraw the background around the moving shape. Also called bitblt or blt.

A stretched bit-block transfer copies a rectangular block of pixels to a rectangle of different size at a different location.

A non-stretched bit-block transfer copies a rectangular block of pixels to a rectangle of the same size at a different location.

bitmap
See standard format bitmap.
boot driver
A driver required to start the system.

For more information, see the topic Installing a Boot Driver.

bpp
Bits per pixel. The number of bits used to represent the color value of each pixel in a digitized image.
bps
Bits per second. The number of bits transferred per second in a data communications system. A measure of speed.
BRI
See ISDN Basic Rate Interface.
brightness
The value that is associated with a pixel to represent its gray value, ranging from black to white.
broadcast architecture
The set of technologies that enable PCs to receive broadcast data.
brush origin
The coordinate of a pixel on a device's surface that is aligned with the upper left pixel of the brush's pattern.
BRUSHOBJ
A GDI user object that contains information that describes a brush object. Brush objects are used to define fill patterns.
BSSID
See Basic Service Set identifier.
buffer control block (BCB)
An opaque Cache Manager structure that is used to maintain state as a file system pins and releases data (for example, its volume structure) in the cache.
bus enumerator
See enumerator.


C

cabinet file
A "cabinet" of compressed installation files, with a file extension of .cab.

For more information about .cab files, see the Platform SDK documentation.

cache
A special memory subsystem in which frequently used data values are duplicated for quick access. Cache memory is always faster than RAM.
Cache Manager
A system component that provides file caching support for file system drivers.
call management
The process used to set up and tear down calls. The call management process also controls the operational parameters of the call. The term "call," and therefore "call management," describes processes that refer to a higher level of call control, rather than those processes responsible for the physical connection.
CAM
See common access method .
Card Services
Under Windows 95, a protected-mode system component that is a VxD linked with the PCMCIA bus driver. Card Services passes the event notification from socket services to the PCMCIA bus driver, provides information from the computer's cards to the PCMCIA bus driver, and sets up the configuration for cards in the adapter sockets.
CCB
See context control block .
CCITT
Comite Consultatif Internationale de Telegraphie et Telephonie (Consultative Committee for International Telephone and Telegraph). An international standards organization dedicated to creating communications protocols that enable global compatibility for the transmission of voice, data, and video across all computing and telecommunications equipment.
CDB
Command descriptor block. A structure defined by the SCSI-II standard and used to communicate requests to a target device on a SCSI bus.
CDFS
Compact disc file system. Controls access to the contents of CD-ROM drives.
CD-ROM
Acronym for compact disc read-only memory.
character translation table (CTT)
Used in print minidrivers that are created for NT-based operating systems. CTTs are translated to RLE files.
chase
To follow a linked list, queue, or other software-defined path. For example, when a file system encounters a symbolic link file within a path specification, it "chases the symbolic link" to redirect operations to the target file.

See also symbolic link.

checked build
A version of the system that has been compiled with debug symbols and built with special support for debugging under-development components, such as new drivers.

See also free build.

child process
When a new NT-native process is created by calling a system service, the caller must specify a "parent" process from which the new process inherits its token, quota, and base run-time priority for threads. The new process can optionally inherit any or all of the following from the specified parent process:
  • A copy of the parent's virtual address space
  • All object handles that were opened with the inheritance attribute
  • Debugging and exception handling ports

However, any user-mode process becomes a wholly independent peer to its so-called parent process as soon as it has been created. After process creation, any process-to-process dependencies become the responsibility of a protected subsystem, such as the Win32 or POSIX subsystem.

A kernel-mode-only process has the initial system process as its parent.

chroma, chrominance
The color portion of the video signal that includes hue and saturation information. Requires luminance, or light intensity, to make it visible.
CID
See client identifier .
CIE
Commission International de l'Eclairage. The (International Commission on Illumination). Developer of color-matching systems.
class
See Device Setup Classes and Device Interface Classes.
class driver
A higher-level driver that typically provides hardware-independent support for a class of physical devices. A class driver generally communicates with a lower-level miniclass driver or port driver, using a combination of device I/O control requests (IOCTLs), callbacks, and support routines.

The system supplies class drivers for keyboard, mouse, and storage devices, among others.

For more information, see the topic Layered Driver Architecture.

See also, descriptions of device-specific technologies in this documentation.

class GUID
A GUID that identifies a particular class.
class installer
A Win32 DLL that performs installation operations for devices in a particular device setup class.

For more information, see the topic Writing a Class Installer.

client identifier (CID)
A unique value that identifies a thread.
client/server model
A model for structuring applications or operating systems such that the system is divided into server processes, each of which provides a set of specialized services to client processes.
clip region
A rectangle or set of rectangles used to control which portions of an image are displayed.
clip region locking
A mechanism by which GDI ensures that a clip region will not change during a drawing operation. To prevent a clip region from being changed during such operation, GDI acquires a lock for the region, thereby controlling access to the data structures that could affect clipping.
clip window
A rectangular region that is used to mask an area in a document or image. Only the portion of the document or image that lies inside the clipping region appears when the document is printed or the image is displayed.
CLIPOBJ
A GDI user object that describes the clip region used when drawing. This region can be enumerated as a series of rectangles.
CMYK
The color space that is often implemented on printers. The acronym represents the four colors: Cyan, Magenta, Yellow, and Black.
codec
Coder-decoder. A filter that compresses or decompresses a data stream.
Co-installer
A co-installer is a Win32® DLL that augments the device installation operations performed by a class installer.

Co-installers can be class-specific (class co-installers) or device-specific (device co-installers).

For more information, see the topic Writing a Co-installer.

collided page fault
A page fault caused by one thread while an in-page I/O operation for another thread is being performed on the same page.
color index
An index into an array of RGB values.
color keying
The process of superimposing one image over another for special effects.
COM
  1. The Component Object Model; the core of OLE. COM defines how OLE objects and their clients interact within processes or across process boundaries.
  2. A legacy serial port.
commitment
The Memory Manager's current system-wide total of memory pages that has been committed to either physical memory or a page file.
common access method (CAM)
An interface definition for SCSI devices.
Common Property Sheet User Interface (CPSUI)
A user-mode dynamic-link library that enables developers to create property sheet pages that have a standard appearance.
compatibility mode
An asynchronous, host-to-peripheral parallel port channel defined in the IEEE 1284–1944 standard. Compatible with existing peripherals that attach to the Centronics-style PC parallel port.
compatible ID
An ID used by the PnP Manager to locate an INF file for a device whose hardware ID cannot be found. Compatible IDs have the same format as hardware IDs, although compatible IDs are typically more generic than hardware IDs.

A device can have zero, one, or more compatible IDs.

If a vendor ships an INF file with a match in a driver node entry for a compatible ID, the vendor should ensure that their INF file can support all the hardware that matches that compatible ID. Because a compatible-ID match is not as strong as a hardware-ID match, the PnP Manager prompts for confirmation from the user before processing the INF file.

See also, device ID, hardware ID, instance ID, and device instance ID.

For more information, see the topic Device Identification Strings.

component
In DirectX Video Acceleration, one of three color channels {Y, Cb, Cr }.
component prediction block
In DirectX Video Acceleration, a prediction block whose attributes apply to either one of luminance or chrominance.
composite prediction block
In DirectX Video Acceleration, a prediction block whose attributes apply to both luminance and chrominance.
composite video
A signal that combines the luminance, chrominance, and synchronized video information onto a single line. This has been the most prevalent NTSC video format.
compressed video
A digital video image or segment that has been processed to reduce the amount of data required to accurately represent the content.
context
The execution state of a thread at any given moment:
  • For a user-mode thread, the platform-dependent register state, kernel stack, TEB, and user stack in the address space of the process to which the thread belongs.
  • For a kernel-mode thread, the platform-dependent register state and kernel stack.

Kernel-mode threads have neither a TEB nor a user-mode context, but they must have an associated process.

See also process object.

Most kernel-mode drivers do not have a context in this sense. Unless a driver (such as an FSD) creates its own process and/or thread(s), it does not have its own stack space or register state. For each driver, the set of objects it owns and the IRPs that it can access in the device queue associated with its device object or any driver-created internal queue(s) can be considered all or part of its context.

context control block (CCB)
An internal file system structure, in which a file system maintains the per-file object state for an open instance of a file.

See also FCB and DCB.

context record
A system-defined structure that contains the current register state for an exception handler.

See also SEH.

contrast
The range of light and dark values in a picture; or a measure of brightness in an image. The range between the lightest tones and the darkest tones in an image.
control method
A definition of how an ACPI-compatible operating system can perform a simple hardware task. For example, the operating system invokes control methods to read the temperature of a thermal zone. Control methods are written in an encoded language called AML. An ACPI-compatible system must provide a minimal set of control methods in the ACPI tables. The operating system provides a set of well-defined control methods that ACPI table developers can reference in their control methods.
control objects
A class of kernel-defined object types, used to manage all kernel-mode operations except dispatching and synchronization.

See also dispatcher objects.

Control objects include APC, DPC, device queue, interrupt, and process objects. Note that all control object types except processes are kernel-mode-only objects, invisible to user-mode code. User-mode APC objects are also "invisible" in the sense that they look more like user-supplied routines to be called on return from certain system services (such as a request to read a file) than like objects.

controller object
A kernel-mode-only object type, defined by the I/O Manager. A controller object represents a hardware controller or channel. The driver calls the IoAllocateController function to carry out synchronized I/O on attached devices. Controller objects "connect" a set of similar devices attached to a controller with a single driver.
controllerless modem
A modem that consists of a DSP without the usual microcontroller. The host CPU provides the AT command interpreter, modem-control functions, and v.42bis implementation. Also called a host-based controller.

Compare with software modem.

critical section
A piece of code that temporarily has exclusive access to a resource, such as device-state data stored in a device extension to which access must be synchronized among some number of routines.
CSA
Connection and Streaming Architecture. Kernel-mode streaming in WDM.
CTS
Clear To Send. A control packet used by a destination station to indicate its readiness to receive data. A destination station responds to a Request To Send (RTS) by transmitting a CTS.

See also, RTS.


D

DACL
See discretionary access control list .
DAT
Digital audio tape. A consumer recording and playback media for high-quality audio.
data circuit equipment
See data circuit-terminating equipment.
data circuit-terminating equipment (DCE)
Data circuit-terminating equipment is required to attach data terminal equipment (DTE) to a network or serial line. Data circuit-terminating equipment (DCE) includes devices such as modems and ISDN terminal adapters.
data communications equipment
See data circuit-terminating equipment.
data flow
An arbitrary method of defining a class of connection between devices. Facilitates identification of pin pairs that present compatible flow values, and therefore are more likely to be able to establish a connection.

For more information, see the topic KSPROPERTY_PIN_COMMUNICATION.

data sink pin
See Pin Connections.
data source pin
See Pin Connections.
data terminal equipment (DTE)
Includes devices that are the source or destination of data. These devices are connected by data circuit-terminating equipment. Data terminal equipment includes devices such as PCs and printers.
DCB
See directory control block .
DCE
See data circuit-terminating equipment.
DDC
Display data channel. A standard that defines a communications channel between a monitor and the display adapter to which it is connected. This channel provides a method for the monitor to convey its identity to the display adapter.
deadlock
A run-time error condition that occurs when two threads of execution are blocked, each waiting to acquire a resource that the other holds, and both unable to continue running.
decorated INF section
An INF file section whose name contains a suffix ("decoration") that identifies a particular platform and/or operating system. For example, [SourceDisksNames.x86] and [aha154x.ntx86] are examples of decorated section names. Decorated sections contain installation information that is only relevant to the platform and/or operating system specified by the suffix.

For more information, see the topic Creating INF Files for Multiple Platforms and Operating Systems.

deferred procedure call (DPC)
A queued call to a kernel-mode function that will usually be executed at a later time. DPCs are used by drivers to schedule I/O operations that do not have to take place in an ISR at a high IRQL, and can instead be safely postponed until the processor IRQL has been lowered.

For more information, see the topic DPC Objects and DPCs.

DPCs can also be used with timers. For more information, see the topic Timer Objects and DPCs.

design space
See notional space.
despooling
The conversion of spooled device-independent records into device-specific records.
device
A device object, or hardware, or software functionality such as a codec.
device class
Either a device setup class or a device interface class.
device co-installer
See co-installer.
device context (DC)
A structure that defines a set of graphic objects and their associated attributes, and the graphic modes that affect output. The graphic objects include a pen for line drawing, a brush for painting and filling, a bitmap for copying or scrolling parts of the screen, a palette for defining the set of available colors, a region for clipping and other operations, and a path for painting and drawing operations.

Conceptually, a device context is a link between a Windows-based application, a device driver, and an output device such as a display, printer, or plotter.

device driver interface (DDI)
A set of functions that are implemented by the operating system for use by drivers.
device ID
A vendor-defined string that identifies a device. The format is <enumerator>\<enumerator-specific-device-ID>. For example:
    root\*PNP0F08
    PCI\VEN_1000&DEV_0001&SUBSYS_00000000&REV_02

The underlying bus driver for a device returns the device ID to the PnP Manager in response to an IRP_MN_QUERY_ID request. The PnP Manager uses the device ID to create a subkey for the device in the registry.

In the list of hardware IDs for a device, the device ID should be listed as the most specific hardware ID.

See also hardware ID, compatible ID, instance ID, and device instance ID.

For more information, see the topic Device Identification Strings.

device instance
A physical piece of hardware. For example, if Company ABC manufactures a CD-ROM drive with a model name of XYZ, and if a particular system includes two of these drives, then there are two instances of device model XYZ.
device instance ID
A system-supplied string that identifies a device instance. This string consists of a device ID and an additional, instance-specific instance ID. The string format is:

<enumerator>\<enumerator-specific-device-ID>\<instance-specific-ID>

For example:

PCI\VEN_1000&DEV_0001&SUBSYS_00000000&REV_02\1&08

The PnP Manager assigns a device instance ID to each device node in a system's device tree.

See also device ID, hardware ID, compatible ID, and instance ID.

For more information, see the topic Device Identification Strings.

device interface
Device functionality that a driver exposes to applications or other system components. Each device interface is a member of a system-defined or vendor-defined device interface class.

A driver can expose instances of zero, one, or more than one device interface class for a device. For example, a device could have a joystick and a keypad, and the device's driver stack could expose instances of three interface classes for the device: a joystick, a keypad, and a combined joystick/keypad.

device interrupt request level (DIRQL)
The IRQL at which a given device interrupts.

See also IRQL and IDT.

device management
The exchange of requests and responses that control and configure the operational state of a device. Device management requires the use of a Communication Class interface.
device node
See devnode.
device object
A kernel-mode object, defined by the I/O Manager, that represents a physical, logical, or virtual device. Each driver calls IoCreateDevice to create and initialize a device object for each physical, logical, or virtual device that the driver services. PnP drivers create three kinds of device objects: bus drivers create PDOs, function drivers create FDOs, and filter drivers create filter DOs. A device is "visible" to end users as a named file object, and to user-mode code (protected subsystems) through a named device interface.

For more information, see the topic Introduction to Device Objects.

See also device extension, devnode, and driver object.

device palette
See palette.
device power policy owner
The driver for a device that controls its power policy, determining when it sleeps and when it wakes. Typically, the function driver for the device assumes this role, requesting power IRPs to put the device to sleep or to wake it up.
device queue object
A kernel-mode-only, kernel-defined control object type used to queue I/O requests for subsequent processing. A device queue object has an associated executive spin lock and a state (Busy or Not Busy).

An I/O request, called a "queue entry," is not actually placed in the queue unless the state of the device queue object is already Busy:

  • On the transition from Not Busy to Busy, the driver is expected to service the queue entry immediately because that entry is not queued.
  • Subsequent requests while the state is Busy are queued in FIFO or key-sorted order.
  • An attempt to remove a queue entry from an empty queue causes a transition from Busy to Not Busy.
  • An attempt to remove a queue entry from an empty queue when the state is Not Busy is a programming error, which causes the system to "bug check" (in other words, to "crash") in a checked build.

For more information, see the topic Driver-Managed IRP Queues.

device space
The coordinate space that measures 227 units in height by 227 units in width, in which the x coordinate increases toward the right and the y coordinate increases downward. The only transformation allowed in device space is translation, which ensures that the origin in device space maps to the proper location on the physical device (that is, in physical device space).

See also design space.

device stack
A chain of attached device objects that represent the drivers for a device.

For PnP devices, the device object at the bottom of the device stack is the PDO created by the underlying bus driver. Typically, there is an FDO somewhere in the chain above the PDO. The FDO is created by the function driver for the device. Filter DOs are attached above and below the FDO.

The PDO is created by the underlying bus driver when it enumerates the device. The FDO and filter DOs are created by their respective function and filter drivers and are attached to the stack by those drivers' AddDevice routines.

device tree
Contains information about the devices present on the system.

The operating system builds this tree when the machine boots, using information from drivers and other components, and updates the tree as devices are added or removed. The device tree is hierarchical, with devices on a bus represented as "children" of the bus adapter or controller. You can view the hierarchy of devices in the device tree using the Device Manager, if you choose the UI option that displays devices by connection.

Each node of the device tree is a device node, or devnode.

For more information, see the topic Device Tree.

device-dependent bitmap (DDB)
A data structure that describes a bit image by specifying the width and height of a rectangular region in pixels; the width of the array that maps entries from the device palette to pixels; and the device's color format in terms of color planes and bits per pixel. A DDB is device-managed, as opposed to being engine-managed.

See device-independent bitmap.

device-independent bitmap (DIB)
Information on the bitmap is stored in a data structure containing information such as color format, resolution, and color palette for the device on which the image appears; an array of bits that maps RGB triplets to pixels; and a data-compression identifier that indicates which, if any, data compression scheme was used to reduce the size of the array of bits. A DIB is a GDI bitmap that can be rendered accurately on different devices because it contains a color table that can be read by the rendering device driver. These are standard format bitmaps created and supported by GDI through EngCreateBitmap. A DIB is engine-managed, as opposed to being device-managed.

See device-dependent bitmap.

device-managed surface
A surface managed by a particular output device, rather than by the Graphics Engine (kernel-mode GDI). There are two types of device-managed surfaces: standard-format bitmaps, and nonstandard-format surfaces.

A standard-format bitmap can be either opaque or non-opaque. These terms indicate whether GDI has information about the location and format of the bitmap. For a standard-format bitmap that is opaque, the display driver must handle all rendering tasks done on the surface. For a standard-format bitmap that is non-opaque, the display driver handles some rendering tasks, and can refer others back to GDI.

A display driver calls on GDI to create a nonstandard-format surface. After creating the surface, GDI returns a surface handle to the display driver, which must carry out all subsequent operations pertaining to the surface. One type of nonstandard-format surface is the device-dependent bitmap (DDB), which is supported to allow drivers such as the VGA driver perform faster bitmap-to-screen block transfers.

For more information, see the topic Surface Types.

devnode
An internal structure that represents a device on the system.

There is a devnode for each device on a machine and the devnodes are organized into a hierarchical device tree. The PnP Manager creates a devnode for a device when the device is configured.

A devnode contains the device stack (the device objects for the device's drivers) and information about the device such as whether the device has been started and which drivers have registered for notification on the device.

digital simultaneous voice and data (DSVD)
A signaling method that mixes data and digitized voice.
direct memory access (DMA)
A method of transferring data between a device and main memory without intervention by the CPU. DMA is handled by the device itself (bus-mastering or first-party DMA) or by a DMA controller chip in the system (slave or third-party DMA).
directory control block (DCB)
An internal NT file system structure in which a file system maintains state for an open instance of a directory file.
directory file
A file that points to or lists a set of named file objects.

Note that on-disk directory files are represented in the kernel as file objects, not as object directory objects.

See also file object and object directory object.

directory object
See object directory object.
DirectX
A set of multimedia APIs that Microsoft provides.
DIRQL
See device interrupt request level .
discretionary access control list (DACL)
Part of the security descriptor for an object. The DACL can be applied to a newly created object in order to restrict access to the object.

See also ACE , access right, ACL and security descriptor.

disk controller
A special-purpose chip and circuitry that directs and controls reading from and writing to a computer's disk drive. Also called a hard disk controller (HDC).
dispatch routine
An IRP-processing routine in a kernel-mode driver. Drivers export entry points for these routines through a dispatch table in the DRIVER_OBJECT structure.

For more information, see the topic Writing Dispatch Routines.

dispatch state
At any given moment, a thread can be in one of the following states:
  • initialized
  • ready – queued and eligible for dispatch to a processor
  • standby – ready and selected to execute, but a context switch to the thread has not yet occurred
  • running
  • waiting – suspended until a particular dispatcher object is set to the Signaled state
  • terminated
dispatcher objects
A class of kernel-defined object types that are used to manage dispatching and synchronization. See also control objects.

Dispatcher objects have a state (either Signaled or Not Signaled), and are arguments to the wait services or kernel wait routines (KeWait Xxx). Dispatcher objects include: events, (kernel-mode-only) mutexes, queues, semaphores, threads, and timers.

Kernel-mode threads synchronize their operations by waiting on one or more dispatcher objects, or by waiting on other objects, such as user-mode file objects, that contain "hidden" kernel-mode dispatcher objects.

It is a fatal error to wait on a dispatcher object at IRQL >= DISPATCH_LEVEL.

display power management signaling (DPMS)
A standard that defines display power management states and provides a standard method for the display controller to signal to the display to enter into those states.
distribution system (DS)
The backbone that connects the access points of an 802.11 LAN. The distribution system can use Ethernet or another wired or wireless network architecture.
dithering
A technique used to create the illusion of varying shades of gray on a monochrome display or printer, or additional colors on a color display or printer. Dithering treats areas of an image as groups of dots that are colored in different patterns. Similar to halftones in photography.
DLL
Dynamic-link library.
DMA
See direct memory access .
DMI
Desktop Management Interface. A framework created by the DMTF.
DMTF
Desktop Management Task Force. DMTF specifications define industry-standard interfaces for instrumentation providers and management applications.
dock
To insert a portable computer into a base unit. Cold docking means the computer must begin from a power-off state and restart before docking. Hot docking means the computer can be docked while running at full power.

See also warm docking.

docking station
The base computer unit into which a user can insert a portable computer, expanding it to a desktop equivalent. A typical docking station provides drive bays, expansion slots, the ports that would be provided by an equivalent desktop computer, and AC power.
document-sticky
A printer property page setting that applies only to a single document. For example, the left and right margins of a particular document are document-sticky settings.

Contrast with printer-sticky.

dongle
A physical device, attached to a PC's I/O port, that adds hardware capabilities.
DPC
See deferred procedure call .
drawing functions
A set of functions that a display driver can implement to perform rendering operations. The DDI drawing functions are shown in the following list. These functions perform many kinds of rendering operations, including alpha blends, bit block transfers, rendering lines, color fills, and displaying text.

DrvAlphaBlend
DrvBitBlt
DrvCopyBits
DrvDitherColor
DrvFillPath
DrvGradientFill
DrvLineTo
DrvPlgBlt
DrvRealizeBrush
DrvStretchBlt
DrvStretchBltROP
DrvStrokeAndFillPath
DrvStrokePath
DrvTextOut
DrvTransparentBlt

driver node
A device entry in an INF file's INF Models Section. Each of these entries identifies a device's device identification strings, and references other sections within the INF file that identify the device's installation components, including driver files, service information, device-specific co-installers, registry entries, and so forth.
driver object
A kernel-mode object that represents a driver's load image and is used by the I/O Manager to locate certain entry points in the driver.

For more information, see the topic Introduction to Driver Objects.

driver stack
A chain of drivers that support the operations of a device. For more information, see the topic Layered Driver Architecture.
DS
See distribution system.
DSP
Digital signal processor. An integrated circuit designed for high-speed data manipulations. Used in audio, communications, image manipulation, and other data-acquisition and data-control applications.
DSVD
See digital simultaneous voice and data.
DTE
See data terminal equipment.
DVD
Digital video disc. Digital data storage that encompasses audio, video, and computer data.


E

EA
Extended attribute. An EA is viewed as an untyped name-value pair that is defined by the user to describe extended information about a file. Typical system uses are to store the icon for an image, to indicate that the file is a symbolic link, and so on.
ECC
Error correction code.
ECP
Extended capabilities port. An asynchronous, 8-bit-wide parallel channel defined by IEEE 1284—1944. This channel provides PC-to-peripheral and peripheral-to-PC data transfers.
EISA
Extended industry standard architecture. A standard that defines the architecture of (and interface to) the extended PC I/O bus.

See also ISA.

electronic program guide (EPG)
The on-screen user interface that allows users to select, manage, and search television programs and other content-viewing options.
engine-managed surface
A device-independent bitmap (DIB) that is created and managed by GDI. GDI can handle any or all drawing operations for the surface. For a surface to be engine-managed, it must be a DIB.

For more information, see the topic Surface Types.

enhanced metafile (EMF)
A type of spool file used by print spoolers on NT-based operating systems. An EMF reduces the time it takes for control to be returned to an application that makes a print request.. The GDI function calls that produce the application's graphics object are stored directly in the EMF. The time-consuming execution of these stored GDI functions is carried out later, in the background, when the spool file is played back.

Using EMF spool files also promotes printer device independence. For example, a picture that measures 2 inches by 4 inches on a VGA display and that is stored in an EMF maintains these original dimensions, regardless of the printer's resolution.

enumerator
A system component that discovers PnP devices based on a PnP hardware standard. For Windows 2000 and later, these tasks are carried out by PnP bus drivers in partnership with the PnP Manager. A device is typically enumerated by its parent bus driver, such as the PCI or PCMCIA bus driver. Some devices are enumerated by a bus filter driver, such as the ACPI driver.
ESS
See Extended Service Set.
event object
A user-mode object upon which one or more threads can wait until the event is set to the Signaled state. Every user-mode event object is implemented through the use of a kernel-mode event object. A kernel-mode event object is an instance of a kernel-defined dispatcher object type.

Each event object can be classified as either of the following:

  • When a synchronization event (also called an autoclearing event) is set to the Signaled state, a single thread that was waiting on the event is released (its dispatch state makes a transition from waiting to ready, standby, or running), and the event is automatically reset to the Not-Signaled state.
  • When a notification event is set to the Signaled state, all threads that were waiting on the event are released, and the event remains in the Signaled state until it is explicitly reset to the Not-Signaled state.
event set
A uniquely identified set that represents a group of items about which a client can be notified.
exception
A synchronous error condition that results from the execution of a particular machine instruction.

See also SEH.

exclusive device
A device for which a miniport driver is dedicated to supporting a single kernel-mode driver. A video adapter is considered an exclusive device.
executive
The collection of kernel-mode components that form the NT-based operating system. Executive components include executive support, the kernel, the Memory Manager, the Cache Manager, process structure, interprocess communication (LPC and RPC), the Object Manager, the I/O Manager, the Configuration Manager, the hardware abstraction layer (HAL), and the Security Reference Monitor. Each executive component, with the exception of the Cache Manager and the HAL, supplies a specialized set of native system services. Every executive component also exports a set of kernel-mode support routines for use by other executive components.

Kernel-mode drivers also call kernel-mode support routines supplied by executive components, including (but not limited to) routines beginning with the prefix "Ex" for Ex(ecutive) Support. Other support routines of interest to drivers begin with the prefixes Ke(rnel), Po (for Power), Ps (for Process Structure), Ob(ject), Io (for I/O Manager), Mm (for Memory Manager), Se(curity Manager), Rtl (Run-Time Library), and FsRtl (for File System Run-Time Library).

Note that drivers, including device, intermediate, and file system drivers, are considered part of the executive after they are loaded. The "operating system" visible to end users is actually a protected subsystem that runs in user mode on top of the executive, and calls system services. That is, the executive is hidden from end users by a subsystem-supplied interface that emulates Windows®, POSIX, or some other operating system.

See also Zw routines.

executive worker threads
See system worker threads.
extended display identification data (EDID)
A format that lets the display supply the host with information about its identity and capabilities independent of the communications protocol used between the monitor and host.
Extended Service Set (ESS)
A complete 802.11 wireless network. An ESS is composed of different base service sets and their respective access points, as well as the distribution system. An ESS appears to be a single 802 network to the upper layers of the OSI model.


F

FAT
File allocation table. As an adjective, a file system, originally a type of file system native to MS-DOS®.

As a noun, the logical structure describing a disk partition for the FAT file system.

fault tolerance
A feature of the NT-based operating system that includes the end-user-visible Win32® Disk Administrator utility supported by a system-supplied intermediate driver, ftdisk. The ftdisk driver handles disk partition mirroring, striping, and volume set management.
FCB
File control block. An internal file system structure in which a file system maintains state for an open file.
FDC
Floppy disk drive controller. A special-purpose chip and associated circuitry that directs and controls reading from and writing to a computer's floppy disk drive.
FDO
Functional device object. A device object created by a PnP function driver using IoCreateDevice. The FDO represents the device for the function driver.

For more information, see the topic Types of WDM Device Objects.

See also physical device object and filter device object.

file object
An object that is visible in user mode and that represents an open instance of a file, device, directory, or volume. A file object is accessed through the file handle that is returned by a protected subsystem's API function. This function calls down to a system service that opens (or creates) a file. Callers of the I/O system services can wait on a file handle.

At any given moment, several file objects can be associated with a single, shared data file, but each such file object has a unique handle and an object-specific value for the current file pointer.

A file object is sometimes called a persistent object because the entity that backs any run-time set of file objects is retained across system boots.

filter
An entity that represents a collection of related connection points called pins, which have some internal routing. Under DirectShow® this is a user-mode entity (an instance of a COM object normally implemented by a DLL), and under WDM Streaming this is a kernel-mode entity (a device object that is normally implemented by a kernel driver).
filter device object
A device object created by a filter driver. The filter device object (filter DO) represents the device for the filter driver.

For more information, see the topic Types of WDM_Device Objects.

flush mechanism
A mechanism that enables GDI to synchronize itself to the current state of a surface. In addition to providing a synchronization routine, a display driver can also activate either a time-based flush mechanism or programmatic flush mechanism. It does this by setting the flGraphicsCaps2 member of the DEVINFO structure to one of the following flag values:
  • GCAPS2_SYNCTIMER—Causes the driver's synchronization routine to be called periodically (GDI calls the driver's synchronization routine every 50 ms.). Drivers that batch DDI calls must specify this flag. By doing so, these drivers avoid problems such as lag in a software cursor's movement or in drawing that is performed in bursts.

    GDI passes the DSS_TIMER_EVENT flag to DrvSynchronizeSurface when this synchronization routine is called due to a periodic event.

  • GCAPS2_SYNCFLUSH—Causes the driver's synchronization routine to be called whenever the Win32® GdiFlush function (described in the Platform SDK documentation) is called. Drivers that perform asynchronous rendering must specify this flag and provide a synchronization routine.

    GDI passes the DSS_FLUSH_EVENT flag to DrvSynchronizeSurface when this synchronization routine is called due to a flush-based event.

    See also asynchronous rendering.

FONTOBJ
A GDI user object that is used to give a driver access to information about a particular instance of a font. As an accelerator, the driver is allowed to access the public members of the FONTOBJ structure.
FOURCC
In the original Microsoft® Windows® multimedia APIs, media types were tagged with 32-bit values created from four 8-bit character codes, known as FOURCCs.
fps
Frames per second.
fragmentation threshold
The size at which packets are divided into smaller packets to be transmitted on an 802.11 LAN. The IEEE 802.11-1997 standard requires packets that exceed the fragmentation threshold to be divided into smaller packets and transmitted as a sequence of data/ACK transactions. The fragmentation threshold is determined on a station-by-station basis.
frame buffer
Dedicated memory on a video adapter that can hold the contents of a single screen image. One type of frame buffer is the linear frame buffer, in which memory is mapped linearly into CPU address space. The other type of frame buffer is the banked frame buffer, so-called because its memory is partitioned into contiguous segments, or "banks." Most currently-manufactured video accelerators have linear frame buffers.
free build
A "production" or "retail" build of the operating system. Free builds of the system are compiled and built without symbols or support for debugging under-development components. This makes the free build smaller in size and faster than a checked build due to the lack of debugging symbols and checks.

See also checked build.

FS
A file system. An FS is a file system driver that registers itself with the I/O Manager as an active file system. Several file systems can be active at the same time. File systems are dynamically located when a volume is mounted or when a remote name is being resolved. The I/O Manager calls the registered FSs in turn until one file system "recognizes" the volume structure or remote name.

Examples of system-supplied file systems are FAT, NTFS, CDFS, the LAN Manager redirector, NPFS (named pipe file system), and RAW.

See also IFS.

FSD
File system driver. The FSD refers to the portion of a driver that executes in the context of the caller, to which an I/O request is dispatched when the request is originally made. The FSD has no process virtual address space and no particular thread context because it operates in the context of whoever happens to call it.

An FSD also executes in the context of the lower-level (intermediate or mass-storage device) driver's DPC routine when the I/O operation is being completed if the FSD indicated that it should be called upon completion of the IRP.

The term FSD normally refers to the device driver part of a file system driver when the driver also has an FSP associated with it; otherwise, it is simply called a file system.

FSP
File system process. FSP usually refers to a set of device-dedicated or system-worker threads that assist a file system driver (FSD), but can also refer to a kernel-mode process set up by an FSD. FSP threads are generally used when a file system driver requires a thread context in which to work. An example is when the driver must wait without tying up the calling thread. An FSP kernel-mode process is used only when an FSD must have a driver-specific process address space in which its device-dedicated threads execute. Most file system drivers conserve system memory and improve performance by not creating their own kernel-mode processes.

Communication between the FSD and the FSP threads is performed through the use of a communication region. This region is generally allocated in a device object's device extension and consists of an interlocked queue and a synchronization event.

Note that any driver (not just file systems) can create one or more device-dedicated threads, and a file system driver can use system worker threads. In particular, a driver should create a thread for I/O operations that use synchronization mechanisms (such as events, timers, semaphores, mutexes, and so on) other than spin locks. Such a driver's thread can wait for an indefinite, nonzero interval on a kernel-defined dispatcher object, but context switches to the thread slow down such a driver's I/O operations.

See also device object, device extension, and event object.

full duplex
In terms of data flow, full duplex indicates a bidirectional data flow.
full-motion video
Video reproduction at 30 frames per second (NTSC-original signals) or 25 frames per second (PAL-original signals).
functional device object
See FDO.


G

gamma ramp
A lookup table (LUT) of numeric values used to compensate for a particular monitor's color response. The table is divided into three parts (one each for red, green, and blue), with each part containing 256 lookup values.

A gamma ramp is used to map the range of possible intensities for each color to a limited number (256) of values. An IHV chooses these values so that the transition from one color intensity to the next is as smooth as possible, given that the eye perceives changes in light intensity nonlinearly.

DirectDraw® takes a pixel from the frame buffer, and examines it in terms of its individual red, green, and blue color components. Each component is represented by a value from 0 to 65535. DirectDraw takes the original value, and uses it as an index into a 256-element array (the ramp), where each element contains a value that replaces the original one. DirectDraw performs this "look-up and replace" process for each color component of each pixel within the frame buffer, thereby changing the final colors for all of the on-screen pixels. For more information, see the Platform SDK documentation.

generic printer description (GPD)
A text-based file used to describe a printer that is printing from Microsoft® Windows® 2000 and later using the Universal Printer Driver (Unidrv). A GPD contains information about the printer features that Unidrv presents in the user interface to allow the user to configure the printer.

A GPD also contains the printer commands and attributes that enable Unidrv to generate the correct printer-ready output data when the user prints from a Windows-based application. Creating a printer driver for Windows 2000 and later can be as simple as creating a GPD file if there is no custom functionality beyond what Unidrv provides.

glyph
The actual shape (bit pattern, outline, and so forth) of a character image. For example, an italic 'a' and a roman 'a' are two different glyphs that represent the same underlying character. Synonymous with "character image" or simply "image."
glyph translation table (GTT)
A table that maps characters with the bitmaps used to display those characters.
gradient fill
A technique used to fill a rectangular or triangular region with color that changes smoothly across the region. For rectangular regions, the gradient fill can be specified as top to bottom, or left to right.

See DrvGradientFill.

graphics capabilities bits (GCAPS)
A driver specifies its graphics capabilities by setting GCAPS_Xxx and GCAPS2_Xxx flags in the flGraphicsCaps and flGraphicsCaps2 members of the DEVINFO structure. GDI obtains the GCAPS when it calls the driver's DrvEnablePDEV routine.
graphics device interface (GDI)
Consists of Win32® GDI and kernel-mode GDI. Win32 GDI is a user-mode API used by Win32 applications that require graphics support. Kernel-mode GDI interfaces directly with kernel-mode graphics drivers, as well as the window manager. Kernel-mode GDI exports several services and functions that can be called by device drivers to perform a host of drawing and graphics-related operations. This eliminates the need for graphics drivers to implement much of the required graphics functionality.

The Win32 GDI library that is directly accessible to Win32 applications can be found in gdi32.dll. It fields calls to the functions listed in wingdi.h and passes the application-supplied information to kernel-mode GDI by way of executive system services in the NT-based operating system. The kernel-mode GDI library is found in win32k.sys. Kernel-mode GDI communicates with a graphics driver by calling the driver's implementations of the DDI functions listed in winddi.h.

graphics engine
Another name for GDI.

See also the kernel-mode GDI definition under GDI.

GUID
Globally unique identifier. A 16-byte quantity that is unique, having been generated from the unique identifier on a network card, the current date and time, and a sequence number. This combination of variables is used to allow any party to create identifiers that will be guaranteed not to match another GUID.


H

HAL
See hardware abstraction layer.
hardware abstraction layer (HAL)
An NT-based operating system component that provides platform-specific support for the NT kernel, the I/O Manager, kernel-mode debuggers, and the lowest-level device drivers. The HAL exports routines that abstract platform-specific hardware details about caches, I/O buses, interrupts, and so forth, and provides an interface between the platform's hardware and the system software. For example, the HAL implements a routine to map each device driver's bus-relative device interrupt vector to a system-assigned vector with a corresponding platform-specific hardware priority (DIRQL), as well as several routines that provide DMA-transfer support.
hardware branch
The hardware archive root key in the registry that is a superset of the memory-resident hardware tree. Although the hardware tree contains information only about those devices currently detected and running in the system, the registry contains a complete list of all hardware ever installed on the particular computer. The hardware root key is \\Hkey_Local_Machine\Hardware.
hardware exception
See SEH.
hardware ID
A vendor-defined string used by the PnP Manager to find an INF-file match for a device. A hardware ID has one of the following formats:
<enumerator>\<enumerator-specific-device-ID>
This is a typical hardware ID format. For example, PCI\VEN_1011&DEV_0021&SUBSYS_00000000&REV_02.
*<enumerator-specific-ID>
The asterisk indicates that the device is supported by more than one enumerator, such as ISAPNP and the BIOS.
<device-class-specific-ID>
An existing device class that has established its own naming convention might use a format that differs from the first two formats shown above. For information on their hardware ID formats, see the hardware specification for such buses.

A device can have one or more hardware IDs.

New enumerators should follow one of the first two formats shown above.

See also Device ID, Compatible ID, Instance ID, and Device Instance ID.

For more information, see the topic Device Identification Strings.

hardware priority
See IDT and IRQL.
hardware tree
A record in RAM of the current system configuration based on the configuration information for all devices in the hardware branch of the registry. The hardware tree is created each time the system is started or whenever a dynamic change occurs to the system configuration.
HBA
Host bus adapter. A hardware device that "connects" the operating system and a SCSI bus. A SCSI miniport driver manages the lower layers of the SCSI-II protocol on the HBA.

See miniport driver. See also port driver, class driver, SFD, and SCSI.

HCD
Host controller driver. For USB, HCD defines a driver stack that controls the USB chipset to which a device is attached.
HCL
Hardware compatibility list.

See WHQL.

HCT
Hardware compatibility tests. A suite of tests from WHQL to verify hardware and device driver operations under a specific operating environment. These tests exercise the combination of a device, a software driver, and an operating system under controlled conditions to verify that all components operate properly.
HDEV
A handle to a device object. Every NT-based operating system display driver needs a handle to its device object; this handle is of type HDEV. An object of this type is created by GDI at driver initialization and is stored by the driver for use when calling GDI engine services.

The term hdev, in lower-case, is typically used as the name of a function parameter or structure member of type HDEV.

heap
See pool memory.
heap manager
The portion of the display driver responsible for managing the frame buffer memory.
Heatherington escape sequence
A reliable technique used in modems to switch between data mode and command mode.
hibernate state
System power state S4, in which power is off exactly as for the shutdown state (S5), but the system can resume quickly from a file written to disk before power down.
hibernation file
A system-image file that is written to disk immediately before a system transition to system state S4. On reboot, the hibernate file is loaded so that the system can resume from its previous location.
HID
Human Input Device.
hook
A callback function that handles I/O port and board memory accesses. Synonymous with handler.
host CPU
In DirectX® video acceleration, the programmable processor that controls the overall function of video decode (high-level operations).
hue
The color tint of an image. The color of the analog video signal is determined by three factors: hue, saturation, and luminance.
hyperspace
A block of virtual memory somewhere in kernel space, dedicated to the use of the Memory Manager. Every instance of a user-mode virtual address space has an associated hyperspace area where the Memory Manager maintains internal data (such as page table pages and WSLs) for the current process.

See also kernel space and user space.


I

I/O control code
See IOCTL.
ICD
Installable Client Driver. An OpenGL driver model in which the driver is responsible for implementing the entire OpenGL pipeline. Intended for high-end graphics cards that implement most of the OpenGL pipeline in hardware.
IDB
Interrupt dispatch block. An internal structure used by the kernel.
IDE
Integrated Device Electronics. A type of disk-drive interface where the controller electronics reside on the drive itself, eliminating the need for a separate adapter card.
IDT
Interrupt dispatch table. A kernel-defined call table with a platform-dependent number of first-level entries (some for DIRQL ISRs) and second-level entries for interrupt transfer routines (dependent on a first-level ISR). For symmetric multiprocessor platforms, the kernel sets up an IDT for each processor.

The kernel reserves eight first-level entries per IDT for its own use; the remaining first-level entries can be connected to a platform-specific I/O bus interrupt by the HAL or to a device interrupt. The kernel's reserved entries (in low-to-high IRQL priority) are defined by the following constants:

  • PASSIVE_LEVEL – execute thread
  • APC_LEVEL – execute special kernel APC; page fault
  • DISPATCH_LEVEL – dispatch (execute DPC)
  • WAKE_LEVEL – debugger execution
  • CLOCK2_LEVEL – interval-timer execution
  • REQUEST_LEVEL – interprocessor request
  • POWER_LEVEL – power failure notification
  • HIGH_LEVEL – machine checks or bus errors

The set of software and hardware interrupt vectors mapped to these constants is platform-dependent, but none can be connected to a driver's interrupt object. Note that the constants PASSIVE_LEVEL through DISPATCH_LEVEL and WAKE_LEVEL correspond to software interrupt vectors. DIRQLs for device drivers usually have hardware priority higher than DISPATCH_LEVEL but lower than CLOCK2_LEVEL.

See also multiprocessor machine.

IEEE 1284 Bi-Directional Parallel Peripheral Interface
An interface standard that adds bidirectional communication capabilities to a peripheral device that is connected to a computer's parallel port.
IETF
Internet Engineering Task Force.
IFS
Installable file system. See FS.
image color management (ICM)
A technology developed by Microsoft that ensures that a color image, graphic or text object is rendered as close as possible to its original intent on any device, despite differences in imaging technologies and color capabilities between devices.
independent configuration
See ad hoc mode.
independent hardware vendor (IHV)
A third-party hardware vendor.
independent software vendor (ISV)
A third-party software vendor.
INF File
A text-based file containing information required by the system to install a device's software components.

For more information, see the topic Creating an INF File.

infrastructure configuration
An infrastructure configuration is an 802.11 LAN configuration that makes it possible for stations to communicate with access points. The access points communicate through portals that are part of a distribution system. Each access point serves the stations in a Basic Service Set (BSS), and the set of BSSs defines an Extended Service Set (ESS).
INI file
An initialization file. Commonly used in Windows 3.x and earlier, INI files have been used by both the operating system and individual applications to store persistent settings related to an application, driver, or piece of hardware. In later Windows operating systems, INI files are supported for backward compatibility, but the registry is the preferred location for storing such settings.
input class
The class of filters that provide an interface for HID hardware, including USB and legacy devices, as well as proprietary and other HID hardware, under the WDM HID architecture.
installation root
During an installation, the directory (on the distribution medium) that contains the INF file currently in use. After an INF file is copied to the system's INF directory, the INF file's installation root continues to reference the distribution medium, unless an installation application copies the INF file by calling SetupCopyOEMInf (described in the Platform SDK).

All directory paths specified within an INF file are specified relative to the installation root.

instance ID
A string that distinguishes a device from other devices of the same type on a machine. An instance ID is a string (without any path-separator characters) that contains serial-number information, if supported by the underlying bus, or some kind of location information. The format of the string is bus specific.

If the UniqueID device capability (see DEVICE_CAPABILITIES) is FALSE for the device, then the instance ID is unique on the device's bus. If the UniqueID capability is TRUE, then the concatenation of the device ID and the instance ID uniquely identifies the device across the entire system.

If the UniqueID device capability is FALSE, the PnP Manager modifies the instance ID reported by the device's underlying bus driver to add information about the device's parent and thus makes the ID unique on the machine.

An instance ID is persistent across system boots.

See also device ID, hardware ID, compatible ID, and device instance ID.

For more information, see the topic Device Identification Strings.

integral subsystem
A protected subsystem (server) that performs an essential operating system task. The integral subsystems include the Local Security Authority, the Security Accounts Manager, the Session Manager, and the network server.

See also protected subsystem.

Integrated Services Digital Network
Integrated Services Digital Network (ISDN) is a set of standards for integrating services such as voice data and video. There are two types of ISDN interfaces, the basic rate interface and the primary rate interface. Windows supports the basic rate interface as a modem class device.
inter
In DirectX® video acceleration, the representation of picture content by first encoding a prediction of an area of the picture using some previously-decoded picture and then optionally adding a signal that represents the deviation from that prediction.
interface
A set of methods and properties exported by an object type.
inter-integrated circuit (I2C)
The I2C bus is a standard protocol two-wire (clock and data) serial data bus.
inter-integrated circuit (IIC)
See I2C.
interlaced
  1. A scanning method that divides the screen into two fields, alternately drawing odd-numbered and even-numbered scan lines.
  2. A scheme to display a video image by displaying alternate scan lines in two discrete fields. Interlaced signals are used in broadcast video and are required for video to be compliant with NTSC.
intermediate driver
An intermediate driver processes I/O requests "between" the highest-level driver (frequently a file system driver) and the lowest-level driver that controls the hardware device for which the request is bound.

See also class driver and layered driver.

Examples of intermediate drivers include the ftdisk driver, which supports fault tolerance, other filter drivers, and many class drivers, particularly those layered over mass-storage device drivers.

interpolation
The process of averaging pixel information when scaling an image. When reducing the size of an image, pixels are averaged to create a single new pixel; when an image is scaled up in size, additional pixels are created by averaging pixels of the smaller image.
interrupt
An asynchronous hardware signal that is detected by the processor. An interrupt usually indicates that a peripheral device needs service. An interrupt causes the processor to save the current state, to branch to a fixed location, and to resume execution at that location.

See also IDT.

interrupt dispatch table
See IDT.
interrupt object
A kernel-mode-only, kernel-defined control object type, used to connect a hardware interrupt source (see DIRQL ) and an ISR to an IDT entry, or to connect an ISR and an interrupt transfer routine (dependent on the ISR at its IRQL) to a second-level IDT entry.

Each interrupt object:

  • Can be associated with a single IDT entry (and, therefore, with a single processor in an SMP machine)
  • Is either LevelSensitive or Latched, depending on the platform, I/O bus, or device
  • Can be one of several interrupt objects associated with a given IDT entry if and only if every interrupt object for that entry is of a single type (LevelSensitive or Latched)

For a second-level IDT entry, an ISR (such as an ISR for a bus adapter that is associated with a first-level IRQL) routes the interrupt to the device-specific interrupt transfer routine for service, using its entry in the IDT.

When more than one set of interrupt objects is connected to the same first-level IDT entry, the corresponding ISRs are called in the same order in which they were connected.

For more information, see the topic Interrupt Objects and ISRs.

intra
In DirectX Video Acceleration, the representation of picture content without prediction using any previously-decoded picture as a reference.
invalid page
A page-sized range of virtual addresses for which a page fault occurs when any address in the range is referenced. For drivers, referencing an invalid page causes a fatal page fault unless the driver is running at an IRQL <= APC_LEVEL when the reference occurs.
IOCTL
I/O control code. A system-defined or vendor-defined control code used to identify I/O control operations that are requested by sending IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL.

For more information, see the topic Defining I/O Control Codes.

IPC
Interprocess communication. The NT-based system has two defined, message-passing mechanisms for IPC:

LPC, defining the port object type with a server process that supplies system (port) services to local (using the same physical memory on a single system) client processes

RPC, with a system-supplied run-time library that implements such RPC capabilities as binding a client process in one address space with a server process in another address space and sending necessary messages to make a remote procedure call possible

IRB
I/O request block. An IRB is a block of data that describes an operation to perform.
IrDA
Infrared Data Association.
IRP
I/O request packet. An IRP is the basic I/O Manager structure used to communicate with drivers and to allow drivers to communicate with each other. A packet consists of two different parts:

Header, or fixed part of the packet – This is used by the I/O Manager to store information about the original request, such as the caller's device-independent parameters, the address of the device object upon which a file is open, and so on. It is also used by drivers to store information such as the final status of the request. See also device object.

I/O stack locations – Following the header is a set of I/O stack locations, one per driver in the chain of layered drivers for which the request is bound. Each stack location contains the parameters, function codes, and context used by the corresponding driver to determine what it is supposed to be doing.

IRP sink pin
Responds to IOCTL_KS_READ_STREAM and IOCTL_KS_WRITE_STREAM requests.

See pin connections.

IRP source pin
Issues IOCTL_KS_READ_STREAM and IOCTL_KS_WRITE_STREAM requests.

See pin connections.

IRP_MJ_Xxx
IRP major function code. One of a predefined class of IRPs that a driver can accept.

For more information, see the topic IRP Major Function Codes.

IRQ
Interrupt request line. A hardware line over which a peripheral device, bus controller, other processor, or the kernel signals a request for service to the microprocessor.

See interrupt.

IRQL
Interrupt request level. The hardware priority level at which a given kernel-mode routine runs, masking off interrupts with an equivalent or lower IRQL on the processor. A routine can be preempted by an interrupt with a higher IRQL.

Running at raised IRQL on a given processor has no effect on the IRQL of any other processor in a symmetric multiprocessor machine.

For more information, see the topic Managing Hardware Priorities.

See also IDT, interrupt object, IRQ, ISR, multiprocessor machine, and priority.

ISA
Industry standard architecture. A standard defining the architecture of the PC I/O bus.

Also called AT bus standard.

ISDN
See Integrated Services Digital Network.
ISDN basic rate interface
ISDN basic rate interface (BRI) consists of one D channel and two B channels. The ISDN D channel is used for signaling. The B channels each provide 64 Kbps of data capacity with a combined capability of 128 Kbps. The second B channel can be configured to support voice or data traffic.
ISDN primary rate interface
In the United States, ISDN primary rate interface (PRI) consists of one D channel and 23 B channels. The D channels are used for signaling. The B channels each provide 64 Kbps of data capacity with a combined capability of 1472 Kbps.
ISDN terminal adapter
An ISDN terminal adapter is a device that is used as a modem in a Windows ISDN installation.
ISDN-TA
See ISDN terminal adapter.
ISO
International Standards Organization.
isochronous transfer
A transfer type that provides a steady, timing-critical data transmission without regard to guaranteed delivery of data.
isolation
The Plug and Play process by which cards on an ISA bus are distinguished from each other after system startup.
ISR
Interrupt service routine. A routine whose purpose is to service a device when it generates an interrupt.

For more information, see the topic Interrupt Objects and ISRs.


J

JPEG
Joint Photographic Experts Group.


K

kernel mode
The privileged processor mode in which NT-based operating system executive code runs. A driver or thread running in kernel mode has access to system memory and hardware.

See also executive and user mode.

kernel space
A block of virtual memory, dedicated to the use of kernel-mode code. Generally, the kernel space is a range of high-order virtual addresses around one to two gigabytes in size.

See also system space, hyperspace, pool memory, and user space.

kernel streaming object
An individual kernel streaming component represented to a client as a file object. Includes filters, pins, clocks, and allocators.

See also FILE_OBJECT.

key object
An object type defined by the Configuration Manager that represents an entry in the registry database. Each instance of a key object represents a registry node, that is, part of a registry path to a set of subkeys, or it contains value entries.

See also registry and value entry.


L

LAN
Local area network. A group of computers and other devices dispersed over a relatively limited area and connected by a communications link that enables any device to interact with any other device on the network.

Compare with WAN.

language monitor
A type of print monitor that provides a full-duplex communications path between the print spooler and bidirectional printers. It can also add printer control information to the data stream.
latched interrupt
An interrupt that occurs at the transition from deasserted to asserted on the IRQ line.

Also called an edge-triggered interrupt.

For more information, see the topic level-sensitive interrupt.

layered driver
One of a collection of drivers that respond to the same IRPs.

See class driver and intermediate driver.

For more information, see the topic Layered Driver Architecture.

LBN
Logical block number. A logical block number identifies a physical block on a disk, using a logical address rather than physical disk values (for cylinder, track, and sector). For a disk with N blocks (in other words, "sectors"), the corresponding LBNs are numbered 0 through (N – 1).

See also MCB and VBN.

legacy driver
A Windows driver that does not support WDM. Legacy drivers usually do not support Plug and Play or power management. When possible, these drivers should be upgraded.

For more information, see the topic Upgrading a Legacy Driver.

level-sensitive interrupt
An interrupt that occurs when the signal is asserted on the IRQ line.

For more information, see the topic latched interrupt.

linear frame buffer
Dedicated memory on a video adapter, that can hold the contents of a single screen image. A linear frame buffer is one in which the memory is linearly addressable, or "flat." This is in contrast to banked frame buffers, in which memory is partitioned into segments, or "banks."
little-endian
Refers to a processor memory architecture in which the byte layout is as follows:
  • Byte N is the least significant (and, in conventional layout diagrams, the "rightmost") byte of:
    • A word composed of bytes N and (N + 1).
    • A doubleword composed of bytes N, (N + 1), (N + 2), and (N + 3).
    • A K-byte memory entity composed of bytes N, (N + 1),...,(N + K – 1).

The address of the preceding word, doubleword, or K-byte entity is its least significant byte, N.

Intel microprocessors always support little-endian addressing. Some RISC microprocessors can be configured for either big-endian or little-endian addressing. For a little-endian configuration, the least significant bit of a 16-bit short value is the "rightmost" bit at byte N, while the most significant bit is the "leftmost" bit of byte (N + 1).

See also big-endian.

local bus
Usually refers to a system bus that is directly connected to the microprocessor on a system board. Used colloquially to refer to system board buses located closer to the microprocessor than are ordinary expansion buses (that is, with less buffering). This proximity to the microprocessor means that system board buses are capable of greater throughput.
logical memory
A HAL-provided mapping between system physical memory and a device-accessible address range.

See also map.

lookaside list
A system-managed queue from which entries of a fixed size can be allocated and into which entries can be deallocated dynamically. Callers of the Ex(ecutive) Support lookaside list routines can use a lookaside list to manage any dynamically sized set of fixed-size buffers or structures with caller-determined contents.

For example, the I/O Manager uses a lookaside for fast allocation and deallocation of IRPs and MDLs. As another example, some of the system-supplied SCSI class drivers use lookaside lists to allocate and release memory for SRBs.

lossy compression
The original data is not completely recoverable. Although image quality may suffer, many experts believe that up to 95 percent of the data in a typical image may be discarded without a noticeable loss in apparent resolution.
LPC
Local procedure call.

See also IPC and port object.

LSA
Local Security Authority. An integral subsystem responsible for managing security access tokens for users.
LU
Logical unit. From a SCSI-II HBA driver's point of view, a physical or virtual peripheral device, addressable through a TID, attached to a SCSI bus.

See also TID.

LUID
Locally unique identifier.

See SID.

luminance
Describes the black-and-white component of a video signal. The amount of luminance contained in a video signal is directly related to the amount of light intensity. Also, brightness; one of the three image characteristics coded in composite television (represented by the letter Y).

See YUV.


M

MAC
See media access control.
MACL
Mandatory access control list. A part of the security descriptor for each object in a system with a B1 or higher security rating from the U.S. National Computer Security Center.
map
  1. To translate a virtual address into a physical address or vice versa. See also MDL.
  2. To translate a bus-relative address into a logical address to be used by a device as if it were a physical address. See also HAL.
  3. To alias a bus-relative interrupt vector to a system-assigned interrupt vector.
map register
An internal structure used by the HAL during DMA to alias a device-accessible logical page to a page of physical memory.

See also DMA.

MCB
Map control block. An MCB is a structure used by file systems in mapping the VBNs for a file to the corresponding LBNs on the disk.
MDL
Memory descriptor list. An opaque structure, defined by the Memory Manager, that uses an array of physical page frame numbers (PFNs) to describe the pages that back a virtual memory range.
media access control
The IEEE 802.11-1997 standard specifies a media access control (MAC) layer. The MAC layer allows stations to operate using either an independent configuration, or an infrastructure configuration.

The MAC layer provides the following services:

  • Authentication (station service)
  • Deauthentication (station service)
  • Privacy (station service)
  • MSDU delivery (station service)
  • Association (distribution system service)
  • Disassociation (distribution system service)
  • Distribution (distribution system service)
  • Integration (distribution system service)
  • Reassociation (distribution system service)
memory descriptor list (MDL)
An opaque structure, defined by the Memory Manager, that uses an array of physical page frame numbers (PFNs) to describe the pages that contain a virtual memory range.
method
A routine supplied as part of an interface to an object type. A method handles standard operations (such as open, close, delete, parse, dump, and read or reset security attributes) on every instance of the object type.
MIDI
Musical Instrument Digital Interface. A serial cable and data communication standard. Most references only involve the data standard, which is a byte stream used for controlling musical instruments, and for storing the output of such instruments.
miniclient driver (MCD)
A graphics interface whose primary goal is to allow straightforward, low-overhead hardware acceleration for OpenGL. The MCD is designed for all but very high-end 3D hardware accelerators. As such, it allows vendors to fully accelerate OpenGL at the rasterization level.
minidriver
A hardware-specific DLL that uses a Microsoft-provided class driver to accomplish most actions through function calls and that provides only device-specific controls.
minidriver development tool (MDT)
An application that simplifies the development of Unidrv minidrivers.

For more information, see the topic Microsoft Minidriver Development Tool.

miniport driver
A device-specific kernel-mode driver linked to a port driver, usually implemented as a dynamic-link library, that provides an interface between the port driver and the system. Windows operating systems define the architecture of the following kinds of miniport drivers:
  1. An HBA-specific driver, linked against the system-supplied SCSI port driver, that drives one or more SCSI buses, or a mass-storage device driver that uses the NT SCSI port driver as its interface to the system.
  2. A video-adapter-specific driver, linked against the system-supplied video port driver, that supports a corresponding display driver.
    1. A network-adapter-specific driver, linked against the system-supplied NDIS library.
mirror driver
  1. A shadow driver or RAID1 driver.

    An intermediate (layered somewhere between an FS and a disk DD) driver whose responsibility is to maintain a duplicate of a disk partition.

    The system-supplied fault-tolerant disk driver, ftdisk, is a mirror driver.

  2. A display driver for a virtual device that mirrors the drawing operations of one or more additional physical display devices.

    When video mirroring is active, each time the system draws to the primary video device at a location inside the mirrored area, a copy of the draw operation is executed on the mirrored video device in real time. With this mirroring scheme, you can simultaneously draw the same output to several video devices. Since the driver allocates memory dynamically for targets, the number of displays that your system can support depends on how much free memory you have at mirror time.

monitor profile
A type of device profile used for color management. This profile contains information about how to convert colors in a monitor's color space and color gamut into colors in a device-independent color space. Any user-mode application, such as a setup program or a word processor with graphics capabilities, can use a monitor profile, provided that Image Color Management (ICM) has been enabled, and that the application has knowledge of the profile's format.
motion vector arithmetic
In DirectX® video acceleration, operations that convert motion vectors to prediction block addresses.
mount
Operation that requests a file system to make a volume useable by the I/O Manager. This is done by filling in the information in a VPB to indicate the serial number and label of the volume, as well as by filling in the pointer to the file system's device object that represents the "volume" mounted on the real device.

See VPB.

MPEG
Motion Picture Experts Group.
MSDN®
Microsoft Developer Network.
MTD
Memory technology driver. A protected-mode driver that works with Windows 95 protected-mode PC Card software to enable form-factor cards, such as flash memory cards. Such memory cards and their related drivers do not provide full Plug and Play capabilities.
multifunction device
A piece of hardware that supports multiple discrete capabilities, such as audio, mixer, and music, on a single card. This device is sometimes treated as a bus that can be enumerated to locate the devices on that bus.

For more information, see the topic Supporting Multifunction Devices.

multiprocessor machine
A platform with more than one CPU. The NT-based operating system is designed to run on multiprocessor machines, usually configured to be:
  • Homogenous – all CPUs are identical, and either all have identical coprocessors or none has a coprocessor.
  • Closely coupled – all CPUs share memory and have uniform access to memory.
  • Symmetric– every CPU can access memory, handle any interrupt, and access I/O control registers just like every other CPU in the system. Note that any version of Windows that runs on a symmetric multiprocessor machine also runs unchanged on a uniprocessor machine based on the same CPU.

While Windows can run on asymmetric platforms, configured with a master CPU that handles all IRQs and one or more slave CPUs as long as the platform is both homogenous and closely coupled, the system has been designed to run primarily on symmetric multiprocessor platforms because SMP machines have better performance characteristics, particularly for I/O.

music class
The class of filters that deal with music data, such as MIDI.


N

native services
See system services.
NDIS
Network Driver Interface Specification. The interface for network drivers used in Windows and Windows NT/Windows 2000. NDIS provides transport independence for network vendors because all transport drivers call the NDIS interface to access the network.
nibble mode
An asynchronous, peripheral-to-host channel defined in the IEEE 1284-1944 standard. Provides a channel for the peripheral to send data to the host, which is commonly used as a means of identifying the peripheral.
NLS
National language support. A set of routines that give applications access to locale-specific information.

See also Unicode.

NMI
Nonmaskable interrupt. An interrupt that cannot be overruled by another service request. A hardware interrupt is called nonmaskable if it bypasses and takes priority over interrupt requests generated by software, the keyboard, and other devices.
noninterlaced
The method of scanning all lines on a display from top to bottom in sequential order at a specific rate per second. Unlike television, which uses an interlaced scanning method, computers typically use noninterlaced monitors.
nonpaged pool
See pool memory.
notional space
A coordinate system font designers use when they design fonts. For example, PostScript fonts are designed in 1000x1000 unit character cells. Before a glyph in a particular font can be rendered on an output device, its notional space coordinates must be first be transformed into device space coordinates. These coordinates must then be transformed into coordinates suitable for the physical device.

Most of the metrics returned in the IFIMETRICS structure are given in terms of notional space coordinates.

Also called design space.

NtDetect
See Advanced RISC Computing.
NTF files
Binary files used for describing the device fonts of Postscript-compatible printers. In Windows 2000 and later, Adobe Font Metrics (AFM) files must be converted to NTF files.
NTFS
A file system, native to NT-based operating systems, that supports file system and file data recovery, extremely large storage media, file-granular compression, and various other features.
NTSC
National Television System Committee of the Electronics Industries Association (EIA). The standards-setting body for television and video in the United States.
NTSC format
A color-television format having 525 scan lines, a field frequency of 60 Hz, a broadcast bandwidth of 4 MHz, a line frequency of 15.75 KHz, a frame frequency of 1/30 of a second, and a color subcarrier frequency of 3.58 MHz.

See also PAL format and SECAM.

NTVDM
The NT-based operating system virtual DOS machine. Also called VDM.


O

object
A single, run-time instance of a system-defined object type. Objects visible in user mode include process, thread, section, file, event, semaphore, key, timer, port, object directory, symbolic link, I/O completion port, and token objects.

Many user-mode objects are implemented through the use of a corresponding kernel-mode object, including processes, threads, events, semaphores, and timers.

Kernel-mode-only objects include APC, DPC, device queue, interrupt, mutex, driver, device, adapter, controller, and stream file objects.

See also object type and opaque.

object directory object
A type defined by the Object Manager and used to implement hierarchical object names.

Note that file system directories are implemented as file objects, not as object directory objects.

object type
An opaque data structure that defines a protected entity implemented and manipulated by the operating system. For example, the system service that reads a file operates on an open file object.

Every user-visible object has:

  • A type (whose name must be unique).
  • Two parts:

A header that is operated on by the Object Manager

A body that is operated on by type-specific system services

  • A set of standardized rules for object creation, deletion, protection, access, management, and naming

User-visible objects can be implemented using kernel-mode objects.

Kernel-mode objects are visible to (and, except for certain fields in driver and device objects, directly accessible only by) the executive component that defined a given object type. They are indirectly accessible to other kernel-mode code through the type-specific support routines exported by the defining component. For example, KeInitializeDeviceQueue operates on device queue objects.

See also opaque.

off-screen memory
Video memory whose contents do not appear on the video display. Off-screen memory can be used for double buffering, a technique in which a complex graphics image that requires numerous graphics operations can be completely rendered before it is displayed. After each image has been displayed, another image can be constructed in the same way, providing an effective way to achieve animation.
OLE
Object linking and embedding. A way to transfer and share information among applications. OLE is based on the COM programming model and binary standard.
OnNow
A computer industry initiative to make computers more power efficient, reducing startup time and adding the ability to shut off idle devices.
opaque
Pertains to any data structure, including a system-defined object, that is defined with a deliberately hidden internal structure known only to the executive component that defined the type. However, the defining component supplies system services and, usually, kernel-mode support routines to manipulate opaque objects. User-mode data types also can be opaque.


P

page frame
A block of contiguous physical memory used to store the contents of a virtual page. Note that the virtual page size and page frame size are usually identical, but that a page frame size is actually microprocessor-dependent.
paged pool
See pool memory.
paging file
A system file containing the contents of virtual pages that have been paged out of memory.

See also backing store and system paging file.

palette
A mapping between color indexes and 24-bit RGB color values. The color indexes can be any bit depth, but are typically 1-, 4-, or 8-bits per pixel. GDI typically uses the palette mapping in reverse. That is, an application specifies an RGB color value for drawing and GDI must locate the color index that causes the device to display that color.

A driver specifies its palette so that GDI can determine how different color indexes are to appear on the device. If the palette for a device can be changed to hold a different set of colors, it is called a settable palette.

A device palette is the palette for a physical device. When the device sends image data to the monitor, the device palette is used. A device can have only one device palette.

palette realization
A palette is "realized" when a display driver sets its internal hardware palette to match changes in a device palette.

For video hardware that supports palettes that can be set, GDI calls the DrvSetPalette DDI in the display driver when it has finished mapping colors into the device palette requested by the application. GDI passes the new palette to the display driver, and the driver queries the PALOBJ to set its internal hardware palette to match the palette changes for the video hardware.

PALOBJ
A GDI user object that represents an indexed color palette.
partial print provider
A print provider that supplies limited functionality and works in conjunction with an NT-based operating system local print provider.

For more information, see the topic Writing a Network Print Provider.

PATHOBJ
A GDI user object used to describe a set of lines and Bezier curves that are to be stroked or filled. Associated functions allow the lines and curves to be enumerated for the driver.
PC 97
The 1997–98 requirements for PC system and peripheral design for the "Designed for Microsoft Windows" logo, as defined in the PC 97 Hardware Design Guide.
PC 98
The 1998–99 requirements for PC system and peripheral design for the Designed for Microsoft Windows logo, as defined in the PC 98 Checklist, which is an addendum to the PC 97 Hardware Design Guide.
PC card
A trademark of PCMCIA. A removable device that is designed to be plugged into a PCMCIA slot and used as a memory-related peripheral.
PCI
Peripheral component interconnect. A dynamically configurable I/O bus, described by the PCI Local Bus Specification published by the PCI SIG.
PCM
Pulse code modulation (PCM) is a subclass of the Microsoft waveform (.wav) file format. In PCM, data for .wav files is stored using linear samples. In contrast, ADPCM records the deltas between samples.
PCMCIA
Personal Computer Memory Card International Association.
PCR
Processor control registers. An internal data structure in which the kernel stores per-processor information.
PDEV
A logical representation of a physical device. A PDEV is a private, driver-defined data structure containing all the information and data that represents the associated physical device. As part of enabling a PDEV, a driver provides information to GDI that describes the requested device and its capabilities. Important information that the driver gives GDI is a set of flags that allow GDI to determine what kinds of operations the PDEV (and the requested device) supports. For example, GDI can test the flags returned as part of the PDEV to determine whether or not the requested device can handle Bezier curves and geometric wide lines.

The term pdev, in lower-case, is typically used as the name of a function parameter or structure member of type PDEV.

A related type, DHPDEV, is a device handle of a PDEV structure. The term dhpdev, in lower-case, is typically used as the name of a function parameter or structure member of type DHPDEV.

PDO
See physical device object.
PEB
Process environment block.
PFN
Page frame number. Also, the database in which the Memory Manager maintains information about every physical page in the system. Each PFN is an index for a physical page in the array of records that makes up the PFN database.

See also PTE.

physical device object (PDO)
A device object created by a bus driver using IoCreateDevice. The PDO, which represents the device for the bus driver, is at the bottom of the device stack for a device.

For more information, see the topic Types of WDM Device Objects.

physical layer
The 802.11 physical layer provides wireless hardware services. These services are required to support the services that the media access control (MAC) layer provides.

The IEEE 802.11-1997 standard provides several options for the physical layer:

  • Frequency-hopping spread spectrum providing 1 Mbps operation, with 2 Mbps optional.
  • Direct-sequence spread spectrum providing both 1 Mbps and 2 Mbps operation.
  • Infrared providing 1 Mbps operation, with 2 Mbps optional.
PIC
Programmable interrupt controller.
pin
A set of filter-defined properties in Kernel Streaming and DirectShow® that specify a connection endpoint. For example, audio input can be described by a pin on a filter.
pin factory
A set of properties that describes a potential connection point to a filter, and is used to generate pin instances of that category. Each pin factory has a filter-unique identifier that allows support of pin-specific properties or data formats. This is a zero-based count by which the pin factory can be identified. The count stays constant between creation of pin instances.
pin instance
An instance created by a pin factory representing one end of a connection point between filters. A pin instance represents the embodiment of a connection using a particular data format and communications methodology. Used for control and data flow. Pin instances support, at minimum, a connection property set.
PIO
Programmed input/output. A technique for making data transfers between a device and system memory, using remapped system-space virtual addresses rather than DMA.
Plain Old Telephone Service
Plain Old Telephone Service (POTS) is analog telecommunications service. Until the 1970s, POTS was the only telephone service offered by local telecommunications providers.

See also PSTN.

plex
Single complete copy of a volume. A volume is composed of one or more plexes. Since all plexes are identical, the volume manager can retrieve data from any of the volume's plexes during a read operation. The volume manager spreads reads among volume plexes, in order to balance the I/O load on the physical media and maximize read performance.

An application or a kernel-mode component can read data from a particular plex instead of letting the volume manager pick one by using the IOCTL_VOLUME_READ_PLEX I/O control code.

plotter characterization data (PCD)
A DLL that provides device-specific information to a graphics plotter driver.
PnP
Plug and Play. For more information, see the topic Plug and Play.
pointer exclusion
A bit-block transfer in which the pointer's image is not copied to the destination. This means that if you are copying a portion of the screen, and the pointer is currently in that portion of the screen, the pointer should not be included in the copy. In the past, pointer exclusion was implemented by turning the pointer off before the copy, and turning it back on after the copy. This is no longer required with windows layering.
polling
A coding technique that wastes CPU cycles in a driver while waiting for a physical device to update its registers. Drivers should never implement polling loops and should minimize the interval they specify in calls to KeStallExecutionProcessor (no longer than 50 microseconds) if they must poll their devices.
pool memory
Regions located in kernel space from which memory blocks can be allocated and deallocated dynamically. (Some other systems call this "heap memory.") The Memory Manager creates two kinds of pools for system use and for use by drivers via Ex(ecutive) Support routine calls:
  • Paged pool is a based region that can be paged in and out of a process's working set. Each process has its own set of PTEs (Page Table Entries) that map paged pool into its address space. Touching a page in this pool can cause a page fault at any time, so drivers should allocate only those data structures accessed exclusively at IRQL PASSIVE_LEVEL or APC_LEVEL (see IDT) from paged pool.
  • Nonpaged pool is a based region for which all processes share a set of PTEs. The Memory Manager guarantees that nonpaged pool is resident in physical memory at all times; therefore, this region can be accessed from any process's address space without causing a page fault. However, nonpaged pool is a limited system resource.

Drivers should allocate from paged pool for entities that are accessed exclusively at or below IRQL APC_LEVEL and in a nonarbitrary thread context. They should minimize their usage of nonpaged pool by "saving" it for data that must be accessed at or above IRQL DISPATCH_LEVEL. Allocations of contiguous or noncached memory come from nonpaged pool.

The Memory Manager allocates entities from both pools using a buddy scheme.

See also kernel space.

port driver
A lowest-level driver that responds to a set of system-defined device control requests and, possibly, to an additional set of driver-defined (private) device control requests, sent down by a corresponding class driver. A port driver insulates class drivers from the specifics of HBAs and synchronizes operations for all its class drivers. Some examples of system-supplied port drivers include the following:
  1. The SCSI port driver that supports a set of device-type-specific class drivers, and possibly SFDs, above it and one or more HBA-specific miniport drivers, and possibly nonSCSI mass-storage device drivers, which link themselves to this OS-dependent port driver (implemented as a dynamic-link library) and call its ScsiPort Xxx routines.
  2. The video port driver that supports display drivers and adapter-specific, kernel-mode miniport drivers, which link themselves to the OS-dependent port driver (implemented as a dynamic-link library) and call its VideoPort Xxx routines.
  3. The parallel port driver.

    In general, any driver of a device that is a so-called "intelligent controller" or a bus adapter can be a port driver if it communicates with one or more class drivers according to an established protocol and synchronizes access to the controller or bus.

    See also class driver, miniport driver, ScsiPort routines, and VideoPort routines.

port monitor
A type of print monitor that is responsible for providing a communications path between the user-mode print spooler and the kernel-mode port drivers that access I/O port hardware.
port object
An instance of an object type representing a conduit for messages between local (server/client) processes. It is used in the LPC (Local Procedure Call) model as an object accessible to user-mode processes through system services. The server (called) process defines a named connection port object and sets up two (unnamed) communication port objects when a client (caller) process connects to the named port.
portal
A portal is a device that connects an 802.11 LAN with another 802 LAN, or with the distribution system.
POSIX
Portable operating system for UNIX. A protected subsystem that supports the POSIX standard.
PostScript printer description (PPD)
A file read by the generic PostScript driver as part of device initialization. PPD files conform to specifications published by Adobe Corporation and are supplied by PostScript printer manufacturers.
POTS
See Plain Old Telephone Service.
power policy
The set of rules that determine how and when a system or device changes power state.

For more information see the topics, System Power Policy and Managing Device Power Policy.

PRCB
Processor control block. An extension of the PCR.
prediction address
In DirectX® video acceleration, the location of the prediction block within an implementation-specific design.
prediction block
In DirectX® video acceleration, the block filtered from reference block.
prediction macroblock
In DirectX® video acceleration, the macroblock prediction including all color channels.
prediction plane
In DirectX® video acceleration, the array of samples formed prior to combining of macroblock prediction. Each plane represents a set of prediction blocks, usually collected from one frame location. Planes are combined to form a single macroblock prediction.
preimaging
The process of building a movie frame in a memory buffer before it is displayed.
PRI
See ISDN Primary Rate Interface.
primary display
Also referred to as primary monitor and primary display device. The primary display in a multiple monitor system is the one that contains the origin (0,0). Other than this, the primary display in Windows 2000 and later can be any display.
primary monitor
See primary display.
print monitor
A user-mode DLL responsible for directing a print data stream from the print spooler to an appropriate port driver.

For more information, see the topic Writing a Print Monitor.

print processor
A user-mode DLL responsible for converting a print job's spooled data into a format that can be sent to a print monitor.

For more information, see the topic Writing a Print Processor.

Printer Control Language (PCL)
A page description language developed by Hewlett Packard (HP) and used by many HP laser and inkjet printers.
Printer Font Metrics (PFM)
Files that describe fonts for a printer.
printer job language (PJL)
A language that implements communication between a bidirectional printer device and a computer. PJL was defined and implemented by Hewlett-Packard.
printer-sticky
A printer property page setting that applies to a single printer. For example, the amount of memory installed on a particular printer is a printer-sticky setting.

Contrast with document-sticky.

priority
An attribute of a thread that determines when and how often the thread is scheduled to run. For a running thread, its priority falls into either of two classes, each class having sixteen levels:
  • Variable priority class has values in the range 0 to 15. This class is used by most threads.

Threads with variable priority are always preemptible; that is, they are scheduled to run round-robin with other threads at the same level. In general, the kernel manages a variable-priority thread as follows: when the thread is interactive with a user, its priority is high (given a boost); otherwise, its priority decays by one level per quantum that the thread runs until it reaches its original programmer-defined base priority level.

  • Real-time priority class has values in the range 16 to 31. This class is used by time-critical threads, making such a thread preemptible only by a thread with higher priority.

Note that any thread, whatever its priority attribute, is always preemptible by a software or hardware interrupt.

priority boosts
A set of system-defined constant values, supplied when drivers complete an IRP. For example, when drivers for interactive devices call IoCompleteRequest, they usually specify a device-type-specific priority boost value. The boost is added to the priority of the user-mode thread that originally requested the I/O operation to compensate for that thread's wait on the I/O.
probe
To check whether a memory access of a particular kind (such as read) to a data entity, such as a handle for an object or a buffer, is allowed without causing an access violation. Note that user-supplied parameter values are always probed and captured on the kernel stack before a system service gets control in kernel mode. The system service is responsible for probing whatever a captured pointer accesses.
process object
A kernel-defined control object type, representing the virtual address space and control information necessary for the execution of a set of thread objects. A user-mode process object defines the base priority, default affinity, and directory table base value for its threads and for any child processes it creates. Every user-visible process object is implemented through the use of an embedded kernel-mode process object.

A kernel-mode-only process object must be initialized before any thread objects that belong to the process.

property
An aspect of the device or stream that can be set or retrieved, such as volume level.
property set
A uniquely identified set that represents types of related information.
property set
A technique defined to set and get properties on a driver. Each property set has a unique identifier, which represents types of related information and is used to access the property set.
property sets (WDM Streaming property sets)
WDM Streaming-defined mechanism to set and get properties on a driver.
protected subsystem
A server that appears to perform operating system functions for its native applications and subsystem-specific drivers by calling system services. A protected subsystem runs in user mode and its interface to end users emulates another operating system, such as Windows or POSIX, on top of the NT kernel.

See also integral subsystem.

Pscript
Abbreviation for the Microsoft Postscript Printer Driver.
PSTN
See Public Switched Telephone Network.
PTE
Page table entry. The Memory Manager uses a PTE to represent the state of a virtual page.
Public Switched Telephone Network (PSTN)
The public telephone network provided by local and long-distance telecommunications carriers. This network includes both a digital backbone and the analog wiring still used in many residences. The term Plain Old Telephone Service (POTS) is often used to refer to PSTN, but this term should be distinguished from PSTN since it is limited to the analog portion of the PSTN.
pulse
To set an event to the Signaled state, satisfy as many waiters on the event as possible, and to reset the event to the Not-Signaled state.
Px64
A draft standard for motion video compression in videophone and teleconferencing applications, designed for 64-Kbps transmission channels. Also called CCITT Recommendation H.261.


Q

quantum
A time slice. A brief period of time during which a given thread executes in a multitasking operating system before it is subject to being rescheduled against other threads at the same priority.
quota
A per-process limit on the use of system resources.

For each process, the system sets limits on certain system resources the process's threads can use, including quotas for paging-file, paged-pool, and nonpaged-pool usage, and so on. For example, the Memory Manager "charges quota" against the process as its threads use page-file, paged-pool, or nonpaged-pool memory; it also updates these values when threads release memory.


R

RAID
Redundant array of inexpensive disks. Alternate meanings include redundant array of independent disks and redundant array of inexpensive devices.
raise an exception
A deliberate transfer of control to an exception handler when an exception occurs. A kernel-mode component, including any kernel-mode driver, cannot raise an exception while running at IRQL >= DISPATCH_LEVEL without bringing down the system.

See also SEH.

raised IRQL
Generally, any interrupt request level that is greater than PASSIVE_LEVEL, typically written as IRQL > PASSIVE_LEVEL or IRQL >= APC_LEVEL.

Because most kernel-mode drivers rarely run at IRQL = APC_LEVEL, this DDK often uses "raised IRQL" to mean IRQL >= DISPATCH_LEVEL. Writers of file system drivers, which sometimes run at IRQL = APC_LEVEL, should refer to IFS Kit documentation for information about the IRQL at which file system driver routines are called.

For more information, see the topic Managing Hardware Priorities.

See also DIRQL, IDT, and IRQL.

RAMDAC
RAM digital-to-analog converter. A chip built into some VGA and SVGA display adapters that translates the digital representation of a pixel into the analog information needed by the monitor to display it. The presence of a RAMDAC chip usually enhances overall display performance.
range
A finite and discrete sequence of values. Note that a virtual address range can be backed by a set of discontiguous physical pages or by a file stored in discontiguous sectors on disk.
raster operation (ROP)
A bitwise operation applied to the bits of color data for the replicated brush and the bits of color data for the target rectangle on the display. There are 256 ROPs in Windows.
rasterization
The conversion of vector graphics (images described mathematically as points connected by straight lines) to equivalent images composed of pixel patterns that can be stored and manipulated as sets of bits.
RAW
A system-supplied FSD that is the "last resort" for all I/O requests requiring file system support. When the I/O Manager calls active file systems to mount a volume, RAW is always called last because it supports all disk and tape media.

However, RAW supplies very primitive file handling capabilities. That is, it does not impose any on-disk file structure or metadata structures for the information on the media; it simply allows read/write access to the logical blocks on the physical disk. For example, it treats the whole disk as a single file and supplies physical-disk-level VBN access to the disk.

RAW is not an acronym.

raw device
A device running in raw mode.
raw mode
The mode of operation in which a device's driver stack does not include a function driver. A device running in raw mode is being controlled primarily by the bus driver. Upper-level, lower-level, and/or bus filter drivers might be included in the driver stack.

If a bus driver can control a device in raw mode, it sets RawDeviceOK in the DEVICE_CAPABILITIES structure.

realized brush
A data structure containing information and accelerators that the display driver needs in order to fill an area with a pattern.
receive signal strength indication (RSSI)
Indicates a measure of the strength of the radio signal that is being received. The greater the signal, the better the reception.
Redbook audio
The data format standard for conventional audio CDs used in home stereo systems.
redirector
A system-supplied (network) file system driver that provides access to files on remote machines.
reference block
In DirectX Video Acceleration, the block area extracted from reference frame buffer.
region
A range of virtual addresses. When a user-mode caller creates a section or maps a view, it must specify a region. The Memory Manager rounds the specified region's starting address down to the nearest 64K boundary and rounds its size in bytes up to the next host-page-size boundary.
registry
A configuration registry. A database containing configuration and control data for the system, including which file systems and drivers to load at system boot time. The Configuration Manager exports system services to manipulate registry key objects contained in the database.

See also key object.

residual difference decoding
In DirectX® video acceleration, decoding of the waveform that represents the error signal that has been encoded to represent whatever signal remains after motion-compensated prediction as appropriate. This may entail simply an intra representation of a non-predicted waveform or an inter difference after prediction.
resolution
Number of pixels per unit of area. A display with a finer grid contains more pixels and thus has a higher resolution and is capable of reproducing greater detail in an image.
resource
  1. An entity (such as a device object, file object, section object, variable, structure, or buffer) visible to one or more processes.
  2. In kernel mode, a system-defined type of opaque variable manipulated by the Ex..Resource Xxx support routines. A shared resource is a multiprocessor-safe synchronization mechanism, rather like a gating semaphore with a dynamic limit value. Drivers, usually file systems, can use one or more resource variables to control access to a memory entity, such as a file or database, on a multiple-reader (shared access), single-writer (exclusive access) basis.

    In particular, file systems that support caching files and paging I/O share certain resource variables with the Cache and Memory Managers.

resource descriptor
An entry in a resource requirements list, specifying a range of hardware resources that a device instance is capable of using, or an entry in a resource list, specifying a hardware resource that has been assigned to a device instance.
resource interchange file format (RIFF)
A tagged-file specification used to define standard formats for multimedia files. The tagged-file structure helps prevent compatibility problems that often occur when file-format definitions change over time. Because each piece of data in the file is identified by a standard header, an application that does not recognize a given data element can skip over the unknown information.
RGB
Red-green-blue. The primary colors in color video. Often used to describe a video color-recording scheme and the equipment that uses it. Also, a computer color-display output signal comprised of separately controllable red, green, and blue signals (as opposed to composite video, in which signals are combined prior to output).

Compare with CMYK.

RIFF chunk
A chunk whose ID is RIFF, and that includes an identifying code and zero or more sub-chunks, the contents of which depend on the form type.
RIFF file
A file whose format complies with one of the published RIFF forms. Examples of RIFF files include WAVE files for waveform audio data, RMID files for MIDI sequences, and RDIB files for bitmaps.
RIFF form
A file-format specification based on the RIFF standard.
RISC
Reduced instruction set computer. A type of microprocessor design that focuses on rapid and efficient processing of a relatively small set of instructions. RISC architecture limits the number of instructions that are built into the microprocessor, but optimizes each so it can be carried out very rapidly.
RLE bitmaps
A run-length encoded (RLE) bitmap is compressed to reduce disk and memory storage required for the bitmap. The encoding format is specified in the biCompression member of the BITMAPINFO structure (described in the Platform SDK documentation).
RPC
Remote procedure call. A call from a thread of one process (the client) to a thread of another process (that server) that exists in a different address space, usually on another networked machine.

See also IPC.

RSSI
See receive signal strength indication.
Rtl routines
Run-Time Library routines. There are two general sets of (C) Run-Time Library routines supplied with the system, one each for user mode and for kernel mode. All kernel-mode drivers can call the kernel-mode Rtl Xxx routines.
RTS
Request To Send. A control packet used by a station to indicate that it has data to send. After sending an RTS, the station must receive a Clear To Send (CTS) from the destination station before transmitting data packets.

See also, CTS.

RTS threshold
The RTS threshold is the packet size at which packet transmission is governed by the RTS/CTS transaction. The IEEE 802.11-1997 standard allows for short packets to be transmitted without RTS/CTS transactions. Each station can have a different RTS threshold. RTS/CTS is used when the data packet size exceeds the defined RTS threshold.
run
As a noun:
  1. Within an MCB, a contiguous range of VBNs mapped to a contiguous range of LBNs (also called an "extent").
  2. Slang for a quantum, as in "when the thread is given the run.…"

    As a verb:

  3. To execute on a processor.
run-time priority inversion
A condition that can occur when threads with mismatched priority attributes share resources or when a higher priority thread waits for a lower priority thread to complete some action. Such an inversion occurs whenever:
  • A high priority thread is blocked, waiting for a lower priority thread to release a shared resource or to complete an action (and probably to set a dispatcher object to the Signaled state).
  • This lower priority thread is also blocked, because many other higher priority threads are ready for execution, so they will be run first.

Under these circumstances, the waiting high-priority thread undergoes a run-time priority inversion, because one or more lower priority threads will run before it does. Note that two threads with mismatched priorities must be very careful to avoid deadlocks if they "share" a resource in a mutually exclusive manner (that is, only one thread at a given time can access the resource).

See also priority, resource, and deadlock.


S

S/PDIF
Sony/Phillips Digital Interface. The current standard for digital connection to consumer audio devices is the S/PDIF connector. Microsoft is encouraging the use of USB or IEEE 1394 as the digital connection between stereo equipment and PCs rather than adapting S/PDIF to meet PC needs.
SACL
System access control list. A part of the security descriptor for an object, used to maintain per object auditing information.

See also security descriptor, ACE, and ACL.

SAM
Security Account Manager. An integral subsystem that maintains a database of information on user accounts, including passwords, any account groups a given user belongs to, the access rights each user is allowed, and any special privileges a given user has.
sampling
The first step in the process of converting an analog signal into a digital representation. Accomplished by measuring the value of the analog signal at regular intervals (called samples). These values are then encoded to provide a digital representation of the analog signal.
saturation
The extremes of operating range wherein the output is constant, regardless of changes in input.
SCSI
Small computer system interface (pronunciation: "scuzzy"). SCSI drivers are assumed to comply with the ANSI SCSI-II standard. In addition, the operating system supplies an operating system-specific SCSI port driver, implemented as a dynamic-link library, and several device-type-specific class drivers, together with defined interfaces to HBA-specific SCSI miniport drivers and additional class drivers.
ScsiPort routines
An interface to HBA-specific miniport drivers exported by the system-supplied SCSI port driver. SCSI miniport drivers call these routines to obtain all operating system-specific system support they need to carry out I/O operations.

Drivers of nonSCSI mass-storage devices, implemented as a pseudoSCSI miniport, also can use this interface.

SDK
Software development kit.
SECAM
Sequential Couleur a Memoire (Sequential Color with Memory). The television standard for France, Russia, and most of Eastern Europe. As with PAL, SECAM is based on a 50-Hz power system, but it uses a different encoding process and displays 819 horizontal lines per frame at a scan rate of 25 frames per second (50 fields per second).

See also NTSC format and PAL format.

section object
A user-mode object type, representing a memory entity that can be mapped onto a range of virtual addresses in a process's address space. Note that creating or opening a section object does not allocate physical memory.

An opened section object can be either:

  • File-backed – The original entity resides as a file on a disk.
  • Page-backed – The original entity resides either in a paging file controlled by the Memory Manager or (wholly or partially) in physical memory where storage is page-granular and the page size is microprocessor-dependent.

Unnamed sections are not sharable, but a view into an unnamed section can be mapped through the creating process's handle. Named sections are shareable. All sections are inheritable by child processes.

See also view.

security descriptor
A data structure used to hold per-object security information, including the object's owner, group, protection attributes, and audit information.

See also ACE, ACL, SACL, and SID.

security violation
A user-mode (protected subsystem) attempt to access an object by passing its handle to a system service without having the correct, granted access rights for the requested operation.

Note that the security component does not check the access rights on object handles used by kernel-mode code. However, the I/O Manager and network server driver can force a security access check on object handles.

See also ACE and ACL.

SEH
Structured exception handling. A system feature that supports controlled transfers to exception handlers when certain runtime exceptions occur. The system traps the following general kinds of exceptions:
  1. Hardware-defined faults or traps, such as,
    • Access violations (see also access violation)
    • Data-type misalignments (such as a 16-bit entity aligned on an odd-byte boundary)
    • Illegal and privileged instructions
    • Invalid lock sequences (attempting to execute an invalid sequence of instructions within an interlocked section of code)
    • Integer divides by zero and overflows
    • Floating-point divides by zero, overflows, underflows, and reserved operands
    • Breakpoints and single steps (to support debuggers)
  2. System software-defined exceptions, such as,
    • Guard-page violations (attempting to load or store data from or to a location within a guard page)
    • Page-read errors (attempting to read a page into memory and encountering a concurrent I/O error)
    • Paging file quota exceeded (attempting to commit backing store for a page currently being removed from a process's working set).

    The system supplies standard exception handlers for data-type alignment faults and for ANSI/IEEE Std 754-1985 floating-point faults.

    Both user-mode and kernel-mode code can set up custom exception handlers using the except, try, and finally constructs supplied by system-compatible C compilers and supported by the Rtl Xxx (Run-Time Library). An exception handler can be associated with each call frame in the function-call hierarchy of a program. A CONTEXT record contains the register state for each exception handler.

    See also Rtl routines.

semaphore object
A user-mode semaphore gates access to resources, allowing some maximum number of threads, as specified when the semaphore object was created, to access the resources protected by the semaphore.

Each user-mode semaphore also has an associated current count, representing how many additional threads can acquire the semaphore. When the current count is zero, a thread attempting to acquire the semaphore waits until the count is incremented when another thread releases that semaphore. Every user-mode semaphore object is implemented through the use of a kernel-mode semaphore object.

A kernel-mode semaphore is an instance of a kernel-defined dispatcher object type.

Any semaphore object has either of two uses:

  • A counting semaphore gates access to a resource by allowing some number of threads up to a specified limit to access the resource while the semaphore is set to the Signaled state (semaphore count is nonzero).
  • A binary semaphore gates access to a single resource, if and only if the limit is set to one and it is not possible for the semaphore to be over-Signaled (set to the Signaled state when it is already in the Signaled state). A binary semaphore gates exclusive access to a resource.

However, using a semaphore with a limit of one to gate access is not the same thing as using a mutex: semaphores have no ownership, deadlocks are possible, and the owner's priority is unaffected.

sequencer
A hardware or software functionality that interprets a time stamped music data stream, and sends packets to music hardware at specified time intervals.
sequencer
Hardware or software functionality that interprets a time-stamped music data stream and sends packets to music hardware as their time comes due.
server
  1. A process with one or more threads that accept requests from client processes. See also client/server model.
  2. Any file system driver that provides remote access to files, named pipes, comm devices, and/or print devices.
Service Set identifier (SSID)
Identifies a network consisting of one or more access points. Such a network is also known as an Extended Service Set (ESS).
Session Manager
An integral subsystem that starts and keeps track of logon sessions and serves as an intermediary between protected subsystems.
setup class
See Device Setup Classes.
setup GUID
A GUID identifying a device setup class.
SetupAPI
A DLL that exports the general Setup functions and device installation functions that Setup applications call when installing devices.

For more information, see the topic Device Installation Components.

SFD
SCSI filter driver. An add-on driver that is layered above an existing SCSI class driver. An SFD intercepts requests for a particular SCSI peripheral device that has special features (not shared by other SCSI devices of its class), or that does not accept standard SCSI-II CDBs, in order to set up device-specific requests.
SID
Security identifier. A value, unique across time and space, that identifies a process in the security system. SIDs can either identify an individual process, usually containing a user's logon identifier, or a group of processes.
Signaled
One of two possible states for kernel-defined dispatcher objects, which support synchronization. When the kernel sets such an object to the Signaled state, any threads waiting on the object are released from their wait and become eligible for execution.
single-byte coding scheme
A character encoding scheme, such as ASCII, that uses a byte to represent each character.

See also Unicode.

sink
In terms of device stacking in DirectShow®, indicates that a pin represents possible connections that are attached to, rather than those that attach.

Compare with source.

sleep state
A system or device state other than the System Working State (S0) or Device Working State (D0).
smart battery subsystem
A battery subsystem that conforms to the ACPI requirements and implementation defined in Smart Battery Charger Specification and related specifications.
SMBus
A two-wire interface based on the I²C protocol. The SMBus is a low-speed bus that provides positive addressing for devices, as well as for bus arbitration.
SMBus interface
ACPI defines a standard hardware and software communications interface between an operating system bus driver and an SMBus controller using an embedded controller.
SMP machine
Symmetric multiprocessor machine.

See multiprocessor machine.

SMPTE timecode
An 80-bit standardized edit time code adopted by the Society of Motion Picture and Television Engineers.

See timecode.

software modem
Performs signal processing on the host CPU and implements the controller using V.42bis. The modem hardware consists of a telephone-line interface and digital-to-analog and analog-to-digital conversion circuitry. The hardware does not contain a DSP or a microcontroller. Also host-based signal processing or pumpless modem.

Compare with controllerless modem.

source
In terms of device stacking in kernel streaming or ActiveMovie, indicates that a pin represents possible connections that attach, rather than those that are attached to.

Compare with sink.

special pool
A part of the non-paged memory pool. When Driver Verifier is active and the Special Memory Pool option is selected, certain memory requests will be allocated from the special pool. This allows Driver Verifier to monitor the driver's memory usage for overruns and underruns.

For more information, see the topic Driver Verifier.

See also pool memory.

SPI
Service Provider Interface. A component in Microsoft networking, TAPI, and other communications technologies.
SRB
SCSI request block. A system-defined structure that is used to communicate I/O requests from a SCSI class driver to the SCSI port driver, which relays such requests to appropriate HBA-specific miniport drivers. Pseudominiport drivers of nonSCSI mass-storage devices, which link themselves with the SCSI port driver and rely on a SCSI class driver for the same type as their device(s), translate the information in SRBs into device-specific commands.
SSID
See Service Set identifier.
standard format bitmap
Single plane, packed-pixel (where the data for each pixel is stored in a contiguous manner) format bitmaps created and supported by GDI through EngCreateBitmap. Each scan line of the bitmap is aligned on a four-byte boundary. Standard format bitmaps code information at a rate of 1, 4, 8, 16, or 32 bits per pixel.
static VxD
A VxD that is loaded statically during system startup. A static VxD can be loaded in a number of different ways, including device enumeration by the Plug and Play static device enumerator.
stream file object
A virtual file representing on-disk data associated with a file, some of which might not be part of the physical file that backs a file object. For example, a stream file object makes it possible to cache the EAs or ACL for a file object together with the file data. FS-created stream file objects also make it possible to cache a copy of the on-media metadata describing the contents of each FS-mounted volume.

See also volume file.

streaming
The process of transferring information from a storage device, such as a hard disk or CD-ROM, to a device driver. Rather than transferring all the information in a single data copy, the information is transferred in smaller parts over a period of time, typically while the application is performing other tasks.
stripe driver
A type of "RAID driver." An intermediate driver whose job is to get better performance for file accesses than the underlying disk driver can. A stripe driver is layered somewhere between the FSD and a disk device driver. It distributes pieces of each file over a set of partitions concurrently, thereby cutting down on synchronous read/write time for the file.

The system-supplied fault tolerant disk driver, ftdisk, is a (RAID5) stripe driver.

STROBJ
A GDI text string user object that contains an enumeration of glyph handles and positions for the device driver.
subject
The combination of a (security) token and of an associated program that may use system services.

See also token.

subunit
Any unit on an AV/C device. An example of an AV/C device would be a Mini DV camcorder (accessed via the IEEE 1394 bus). Subunits on the camcorder include a camera subunit and a tape subunit.
surface
Drawing and text output require a surface, associated with the requested device, on which to draw. Such a device surface is a subset of an array of 2 (28) by 2 (28) pixels. These pixels are addressed by pairs of 28-bit signed numbers; the upper leftmost pixel of the device surface is given the coordinates (0,0). The device surface lies in the lower right quadrant of this coordinate space, where both coordinates are nonnegative. A surface is associated with a particular PDEV.
SURFOBJ
A GDI user object that describes a surface. A device driver usually calls methods on a surface object only when the surface object represents a GDI bitmap or a device-managed surface.
SVGA
Super VGA. A video adapter with special features, such as support for high-resolution modes or additional colors, that is also VGA-compatible.
S-Video
Also Y/C video. A video signal that separates the luminance and color (Y and C) components of the signal for improved quality over composite video. The type of video signal used in the Hi8 and S-VHS videotape formats. It transmits luminance and color portions separately, using multiple wires, thus avoiding the NTSC encoding process and its inevitable loss of picture quality.
symbolic link
  1. An instance of the symbolic link object type, representing a "soft alias" that equates one name to another within the Object Manager's name space.
  2. A file object with special properties. When a symbolic link file is encountered as a component of a pathname, rather than opening the file itself, the file system is redirected to a target file.

    Note that the I/O Manager does not actually use a symbolic link object to implement symbolic link files; it uses a file object.

symbolic link object
An instance of a type defined by the Object Manager, used to translate a reference to one named object into a different name.
symmetric compression
A compression system that requires equal processing capability for compression and decompression of an image. This form of compression is used in applications in which both compression and decompression are used frequently. Examples include still-image databasing, still-image transmission (color fax), video production, video mail, videophones, and video conferencing.

Compare with asymmetric compression.

synchronization routine
A routine that synchronizes GDI with a particular surface. A display driver that supports asynchronous rendering can batch together one or more drawing operations to be performed by its graphic coprocessor. Such a display driver must implement a synchronization routine that GDI can call, a routine that notifies GDI that it is safe for it to carry out its own graphics operations. The synchronization routine to be implemented is named DrvSynchronize (for device-managed surfaces) or DrvSynchronizeSurface (for arbitrary surfaces) .
system paging file
A system file containing the contents of paged pool allocations that are currently paged out to backing store.

See also pool memory and paging file.

system services
The set of native, user-mode routines exported by the executive for use only by protected subsystems. Each system service has a name of the form TwoLettersXxxYyy where:
  • TwoLetters is the prefix for all system services.
  • Xxx is usually a verb, describing the operation of a given service.
  • Yyy is generally the object type the service operates on.

See also Zw routines.

system space
See kernel space.
system space
A block of virtual memory dedicated to the use of kernel-mode code. Generally, the NT system space is a range of high-order virtual addresses around one to two gigabytes in size. Also called kernel space.
System Working State
System state S0, the fully on, fully operational power state.


T

tag file
A file used by Setup to determine if a user has inserted the correct removable medium during a device installation. This file can contain anything, or nothing. It can be one of the files to be installed, a cabinet file containing files to be installed, or a separate non-installation file. A tag file should be unique to each version of each removable medium used for an installation. Tag files are specified in INF SourceDisksNames sections.
tagged file format
A file format in which data is tagged by using standard headers that identify information type and length.
tape miniclass driver
A SCSI-device-specific driver linked with the system-supplied SCSI tape class driver. If a tape miniclass driver calls only routines in the tape class driver, the miniclass driver can be portable across Microsoft operating systems that support Win32 applications.
TAPI
Telephony Application Program Interface. A set of Win32-based calls that applications use to control modems and telephones by routing application function calls to the appropriate service provider DLL for a modem.
TB
Translation buffer.

See TLB.

TEB
Thread environment block.
Telecommunications Industry Association (TIA)
A national trade organization that represents companies in the telecommunications industry. The TIA contributes to the development of communications and networking standards.
telephony
Telephone technology. The conversion of sound into electrical signals, its transmission to another location, and its reconversion to sound, with or without the use of connecting wires.
TIA
See Telecommunications Industry Association.
TID
Target identifier. One of up to eight target controllers on a SCSI-II bus through which peripheral devices are addressable, either as numbered TIDs or as logical units (LUs) subordinate to a particular TID.
TIES
See time independent escape sequence.
tile
Repetition of a brush pattern, to cover an entire device surface.
time independent escape sequence (TIES)
Time independent escape sequence (TIES) provides a means to switch between command mode and data mode on an analog modem. TIES is an alternate method to the Heatherington escape sequence. TIES was developed by a group of modem manufacturers in 1991.
timecode
For MPEG, frame-by-frame address code time reference recorded on the spare track of a videotape or inserted in the vertical blanking interval. It is an eight-digit number, encoding time in hours, minutes, seconds, and video frames (for example, 02:04:48:26).
timer object
A timer object is an instance of a kernel-defined dispatcher object type. User-mode timer objects can be used to synchronize the execution of specific actions, optionally an APC, with time. Kernel-mode timer objects are used to synchronize the execution of specific actions, in particular a DPC, with time.

For more information, see the topic Timer Objects and DPCs.

TLB
Translation lookaside buffer.

(Not directly accessible by system software for the i386; otherwise, an on-chip virtual-to-physical-page address translation cache for high-end x86 and MIPS microprocessors.)

toaster device
A hypothetical peripheral device of an unknown class.
token object
A security object type, representing an authenticated user process. Every process has an assigned token, which becomes the default token for each of that process's threads. However, an individual thread can be assigned a token that overrides this default.
trap handler
A body of code in the kernel to which the processor transfers control when an interrupt or exception occurs. The trap handler determines the type of condition that caused the interrupt or exception and transfers control to an ISR or exception handler.
triangle texture fill
A texture fill in which the surface of a three-dimensional image is partitioned into a mesh of triangles, each of which is filled with the same texture.
True Type font substitute (TTFS)
For printers that provide hardware-resident or cartridge fonts, a font substitution table can be specified. By providing a font substitution table, you specify hardware-resident or cartridge fonts that can be substituted for TrueType fonts that must be downloaded. When Unidrv receives text in such a TrueType font, it first checks to see if the font substitution table contains a hardware-resident substitution for the font. If Unidrv finds a substituted resident font, and if the font metrics (such as character set, weight, italic, orientation, and so on) are compatible, the resident font is used.
tuple
A data structure defined by the PCMCIA to describe a single, specific characteristic of a PC card device. Tuples are chained together to form the CIS, which describes to system software the PC Card's resource requirements and other characteristics. Tuples consist of a tuple code, an offset to the next tuple, and a number of bytes specific to the tuple.
TWAIN
API for image acquisition developed by an association of industry leaders. The specification is available from http://www.twain.org.


U

UART
Universal asynchronous receiver-transmitter. A module composed of a single integrated circuit, which contains both the receiving and transmitting circuits required for asynchronous serial communication.
UNC
Universal naming convention.
Unicode
A standard, fixed-width, 16-bit character encoding scheme that the system uses to provide NLS support for locale-specific natural languages.

See also NLS.

Unidrv
Abbreviation for the Microsoft Universal Printer Driver.
Unidrv font metrics (UFM)
A set of metrics that describe a particular Unidrv font.
Unimodem
Universal modem driver. A driver-level component that uses modem description files to control its interaction with the communications driver, VCOMM.
upper memory block (UMB)
An upper memory block is a contiguous block of memory starting at an address above 640 KB. MS-DOS® distinguishes between conventional memory (addresses between 0 and 640 KB) and upper memory (addresses above 640 KB).
UPS
Uninterruptible power supply. A device connected between a computer and a power source that ensures that electrical flow to the computer is not interrupted because of a blackout and, in most cases, protects the computer against potentially damaging events such as power surges and brownouts.
USB
Universal Serial Bus. An extension dynamic configurable bus for standard computer architectures as defined in the Universial Serial Bus Specification, published by the USB Implementers Forum.
USB class
The class of filters under WDM that provides a bus interface and bus enumerator for USB.
USB communication interface
A communication interface is a USB interface that conforms to the Communications Class definition. Such an interface identifies itself as using the Communication Class.
USB data interface
A data interface is a USB interface that conforms to the Data Class definition. Such an interface identifies itself as using the Data Class.
USB management element
A management element is a type of USB pipe that manages the communication device and its interfaces. Currently, only the default pipe is used for this purpose.
USB master interface
A Communication Class interface that is designated to be the master of zero or more interfaces. The interfaces that the master interface controls create a complete function in a USB communication device. The master interface accepts management requests for the union.

See also USB union.

USB notification element
A type of USB pipe. Although a notification element is not required to be an interrupt pipe, a notification element is typically defined in this way.
USB union
The relationship that exists between one or more interfaces that combine to form a functional unit.
user mode
The nonprivileged processor mode in which application code, including protected subsystem code, executes. User-mode applications cannot gain access to system data except by calling subsystem-supplied functions, which, in turn, call system services.

See also kernel mode.

user space
A block of virtual memory, dedicated to the use of the current user-mode process. Generally, user space is a range of low-order virtual addresses around two gigabytes in size.

See also hyperspace, kernel space, section object, and view.


V

V.25ter
V.25 is the ITU-T standard for Serial Asynchronous Automatic Dialing and Control, commonly known as the "AT" command set.
V.4
V.4 is an ITU-T standard for the general structure of signals over the public telephone network. The V.4 standard governs the data transmission of signals created from international alphabet number 5 code.
valid page
A virtual page that is currently in physical memory.

See also invalid page.

value entry
A named value with assigned data within a registry key.

See also registry and key object.

VBN
Virtual block number. A virtual block number identifies a block (in other words, "sector") relative to the start of a file. For a file with N blocks of data, the corresponding VBNs are numbered 1 through N.
VCACHE
In Windows, a 32-bit protected-mode cache driver.
VCB
Volume control block. An internal file system structure in which a file system maintains state about a mounted volume.
VCOMM
In Windows, a 32-bit protected-mode communications driver.
VCR
Video cassette recorder. An analog magnetic recording and playback machine. Usually used for recording and viewing full-motion video; also useful as a data backup device.
VDM
Virtual DOS machine. A protected subsystem that emulates MS-DOS and DOS-based Windows.
vertical blanking interval (VBI)
The length of time required to move a graphics display's electron beam from the bottom scan line back up to the top scan line.
VGA
Video graphics array. A video adapter that supports 640x480-pixels color resolution. Video display standard for boot devices under Windows operating systems. Provides medium-resolution text and graphics.
video codecs
Full-color video. Requires 3 bytes per pixel, at 640x480 resolution; equals nearly 1 MB of digital data per frame. This means that a developer could easily use 1 GB of hard-disk space by storing less than one minute of uncompressed digital video information.
Video Electronics Standards Association (VESA)
An organization that sets standards for video devices.
video port extensions (VPE)
The video port extensions to DirectX®. Driver developers for devices with a hardware video port should implement these extensions. The hardware video port is a dedicated connection between video devices, typically between an MPEG device or NTSC decoder and the video card. This dedicated connection carries horizontal sync (Hsync) and vertical sync (Vsync) information with the video data. The hardware video port and overlay can use this sync information to flip automatically between multiple buffers, writing to one surface while the overlay displays another. This allows tear-free video without burdening the application.
video request packet (VRP)
A mechanism used to communicate device I/O control requests from a display driver to its corresponding adapter-specific miniport driver. For example, when a display driver calls EngDeviceIoControl, this function calls a system service causing the NT-based operating system I/O Manager to set up an IRP and call the Microsoft-supplied video port driver with that IRP. The video port driver uses the IRP to set up a VRP in a VIDEO_REQUEST_PACKET structure. The video port driver then calls the corresponding video miniport driver's StartIo entry point with the VRP.
VideoPort routines
An interface to adapter-specific miniport drivers exported by the system-supplied video port driver. Video miniport drivers call these routines to obtain all system support they need to carry out I/O operations.
view
A whole or partial mapping of a section object in the virtual address space of a process. Note that mapping a view of a section that is backed by an executable image file, in effect, "loads" the image. Except during the system boot process, the NT-based system uses memory-mapped I/O, rather than a loader, to start program execution.
virtual device driver (VDD)
A device driver that operates in user mode and communicates with a corresponding device driver in kernel mode. A VDD supports only special-purpose hardware devices from an MS–DOS application. The VDD acts as a layer between MS-DOS applications and the hardware attached to the machine running an NT-based operating system.

For more information, see the topic Virtual Device Drivers for MS-DOS Applications or Special Hardware.

virtual DOS machine (VDM)
See Windows NT virtual DOS machine and NTVDM.
virtual memory
A view of memory that does not necessarily correspond to the underlying physical memory structure. For example, a given range of virtual addresses might be mapped to and backed by some number of discontiguous physical pages, even though the corresponding virtual pages can be accessed as a single, contiguous range.
VM
Virtual machine. Software that mimics the performance of a hardware device. For example, a software program that allows applications written for an Intel processor to be run on a Motorola chip interprets the Intel machine instructions, becoming a virtual Intel machine.
VMCB
Volume map control block. An opaque structure that stores VBN-to-LBN mappings for an IFS's volume file.
volume
Volume is the general term that refers to all of the following entities that you can create and use on a computer running Windows:
  • Primary partition
  • Logical drive in an extended partition
  • Volume set
  • Stripe set
  • Mirror set
  • Stripe set with parity

A volume has a single drive letter assigned to it, and is formatted for use by a file system.

volume file
A virtual file, maintained by certain file systems, whose contents map metadata structures of the on-disk file system. A volume file is a type of stream file.
VPB
Volume parameter block. A VPB is a structure, defined by the I/O Manager, that maps a file system's volume device object to the device or partition upon which the volume is mounted. The file system's device object is actually used to represent the volume (VPB) mounted on the actual device (physical device object). Device objects for physical disks, tapes, CD ROMs, and RAM disks have associated VPBs.

See also mount.

VRP
Video request packet. A structure used to communicate device I/O control requests from a display driver to its corresponding adapter-specific miniport driver. For example, when a display driver calls EngDeviceIoControl, this function calls a system service and the I/O Manager sets up an IRP and calls the system-supplied video port driver with that IRP. The video port driver uses the IRP to set up a VRP and calls the corresponding video miniport driver's StartIo entry point with the VRP.
VxD
Virtual device driver. A device driver that runs at the privileged ring 0 protected mode of the microprocessor. Can extend the services of the Windows kernel, supervise hardware operations, or perform both functions. Such driver files are usually named according to the scheme VxD, where x refers to the device or service supported.


W

waking
In power management, the transition from a sleeping state to the working state.
WAN
Wide area network. A communications network that connects geographically separated areas.

Compare with LAN.

warm docking
A method of removing or installing a mobile system in a docking station with which the computer can be docked or undocked while in a reduced power state, such as suspend.
WDM
See Windows Driver Model.
WEP
See wired equivalent privacy.
WEP key
A wired equivalent privacy (WEP) key is a pre-shared key used in an 802.11 LAN for authentication or encryption, or for both.
Win32 API
A 32-bit application programming interface for Windows-based operating systems.
window turn
Turning a window refers to the process of filling an MCB with the appropriate retrieval pointers in order to map a VBN for a file to an LBN for a disk.
Windows File Protection (WFP)
A new feature of Windows 2000 and later, WFP prevents setup programs that are not part of the operating system from overwriting shared system files.

WFP protects system files (typically DLLs and EXEs) by running in the background and detecting attempts to replace protected system files.

Windows Hardware Quality Lab (WHQL)
A Microsoft group whose purpose is to ensure hardware functionality across the Windows® Family of Operating Systems.
Windows NT virtual DOS machine
A protected environment subsystem that emulates MS-DOS and 16-bit Windows within NT-based operating systems. A VDM is created whenever a user starts an MS-DOS application on an NT-based operating system.
Windows on Win32 (WOW)
A protected subsystem that runs within a VDM process. It provides a 16-bit Windows environment capable of running any number of 16-bit Windows applications on an NT-based operating system.
wired equivalent privacy
Wired equivalent privacy (WEP) is a set of security services used to protect 802.11 wireless networks from unauthorized access. WEP services prevent network intrusions that can result from unauthorized persons using hardware similar to that deployed on the protected network. Additionally, WEP services prevent the capture of wireless LAN traffic, also known as eavesdropping.
working set
The set of pages that are resident for a given process while it has one or more running threads.

The size of each process's working set is bounded by a minimum number of pages that the Memory Manager guarantees to be resident while the process has one running thread and by a maximum. However, the NT kernel does not necessarily constrain a process's working set to its maximum if many free pages are available.

See also balance set and quota.

WORM
Write-once, read many.
WSL
Working set list. The set of WSLEs for the current process.
WSLE
Working set list entry.


X

XFORMOBJ
A GDI user object that describes an arbitrary linear two-dimensional transform, such as for geometric wide lines. The transform can be downloaded to the driver.
XLATEOBJ
A GDI user object that is used to translate color indexes from one palette to another.


Y

YUV
The method of color encoding for transmitting color video images while maintaining compatibility with black-and-white video. Uses less bandwidth than the three separate video signals in an RGB video transmission. Consists of two major components: luminance (Y), which corresponds to the brightness of an image pixel, and chrominance (UV or CrCb), which corresponds to the color of an image pixel.


Z

Zw routines
See Zw Xxx Routines. See also system services.


What's new in Windows 98/Windows 2000 IMM/IME

The Windows(R) 98 and Windows 5.0 IMM/IME architecture retains the Windows(R) 95/Windows NT(R) 4.0 design with some improvements to better support intelligent IME development and integration of IME with Windows. These changes are listed here.

Note The Platform SDK provides IME API documentation for application development. For information on IME development, refer to the Microsoft Windows NT Device Driver Kit documentation.

New IME function for applications

The following new IME functions allow applications to communicate with IMM/IME:

  • ImmAssociateContextEx
  • ImmDisableIME
  • ImmGetImeMenuItems

New functions for IME developers

The following new functions allow IMEs to communicate with IMM and applications:

  • ImmRequestMessage
  • ImeGetImeMenuItems

Supporting reconversion

This is a new IME feature that allows you to re-convert a string that has already been inserted into the application's document.

This function will help intelligent IMEs to get more information about the converted result and improve conversion accuracy and performance.

Adding IME menu items into the Context menu of the system Pen icon

This new feature provides a way for IMEs to insert the IME menu items into the Context menu of System Pen Icon in System Tray.

New bits and values for IME

The following new bits support new conversion modes:

  • IME_CMODE_FIXED
  • IME_SMODE_CONVERSATION
  • IME_PROP_COMPLETE_ON_UNSELECT

Edit control enhancement for IME

Through the two new edit control messages (EM_SETIMESTATUS and EM_GETIMESTATUS), applications can manage IME status for edit controls.

IME-related actions for SystemParametersInfo

New uiAction for SystemParametersInfo SPI_GET/SETSHOWIMEUI are added into Windows 98 and Windows 2000. These new SPI_xx parameters are used to show or hide the IME status bar. It is a system global switch.

Two New IMR messages

IMR_QUERYCHARPOSITION and IMR_DOCUMENTFEED are added to Windows 98 and Windows 2000.

When an IME needs the information about the coordinate of a character in the composition string, the IME can send IMR_QUERYCHARPOSITION to the application.

With IMR_DOCUMENTFEED, an IME can get the document context from the applicationand use it for advanced intelligent conversion.

64-bit compliant

Two new structures (TRANSMSG and TRANSMSGLIST) are added into IMM32. They areused by INPUTCONTEXT and ImeToAsciiEx to receive IME translated message.

IME_PROP_ACCEPT_WIDE_VKEY

This new property is added into Windows 2000 so IME can handle the injectedUnicode by SendInput API. ImeProcessKey and ImeToAsciiEx APIs are updated to handle injected Unicode as well. The injected Unicode can be used by applicationand handwriting programs to put Unicode strings into input queue.


Win32 Multilingual IME Overview for IME Development

This documentation introduces the basics on how to develop an IME for Windows® 95, Windows® 98, and Windows® NT/2000. It is also a supplement to the Win32® Multilingual IME API reference for IME development

The following main topics are discussed:

Overview

IME User Interface

IME Input Context

Generating Messages

ImeSetCompositionString

Soft Keyboard

Reconversion

IME Menu Functions

IME Help File

Windows NT/2000 Issues

IME File Format and Data Structures

Overview

Beginning with Windows 95 and Windows NT® 4.0, Input Method Editors (IMEs) are provided as a dynamic-link library (DLL), in contrast to the IMEs for the Windows 3.1 East Asian Edition. Each IME runs as one of the multilingual keyboard layouts. In comparison to the Windows 3.1 IME, the new Win32 Multilingual Input Method Manager (IMM) and Input Method Editor (IME) architecture provide the following advantages:

  • Run as a component of the multilingual environment
  • Offer multiple Input Contexts for each application task
  • Keep one active IME per each application thread
  • Give information to the application through message looping (no message order broken)
  • Offer strong support for both IME-aware and IME-unaware applications

To fully utilize these advantages, an application needs to support the new Win32 IMM/IME application interface.

In order to maintain maximum compatibility with existing Windows 95 and Windows NT 4.0 IMEs, Windows 98 and Windows 2000 have not changed significantly in design. However, new features have been added in order to provide better system integration and to support more intelligent IMEs.

Note IME developers must use the immdev.h in DDK, which is a superset of the imm.h in the SDK or other development tools.

Windows 98 and Windows 2000 IMM/IME

The Windows 98 and Windows 2000 IMM/IME architecture retains the Windows 95 and Windows NT 4.0 design. However, some changes have been made in order to support intelligent IME development and integration of the IME with Windows. These changes include:

  • New IME functions that allow applications to communicate with the IMM/IME. These include:

    ImmAssociateContextEx

    ImmDisableIME

    ImmGetImeMenuItems

  • New functions that allow the IME to communicate with IMM and applications. These include:

    ImmRequestMessage

    ImeGetImeMenuItems

  • Supporting reconversion

    This is a new IME feature that allows you to reconvert a string that has already been inserted into the application's document. This function will help intelligent IMEs to get more information about the converted result and improve conversion accuracy and performance. This feature requires that the application and the IME cooperate.

  • Adding IME menu items to the Context menu of the System Pen icon

    This new feature provides a way for an IME to insert its own menu items into the Context menu of the System Pen icon in the system bar and in applications.

  • New bits and flags for the IME

    The following new bits support new conversion modes:

    IME_CMODE_FIXED

    IME_SMODE_CONVERSATION

    IME_PROP_COMPLETE_ON_UNSELECT

  • Edit control enhancement for the IME

    Through two new edit control messages, EM_SETIMESTATUS and EM_GETIMESTATUS, applications can manage IME status for edit controls.

  • Changing IME Pen Icon and Tooltips

    Through three new messages, INDICM_SETIMEICON, INDICM_SETIMETOOLTIPS, and INDICM_REMOVEDEFAULTMENUITEMS, IME can change the system Pen Icon and Tooltips in the system task bar.

  • Two new IMR messages

    IMR_QUERYCHARPOSITION and IMR_DOCUMENTFEED help the IME and application to communicate position and document information.

  • 64-bit compliant

    Two new structures (TRANSMSG and TRANSMSGLIST) are added into IMM32. They are used by INPUTCONTEXT and ImeToAsciiEx to receive IME translated message.

  • IME_PROP_ACCEPT_WIDE_VKEY

    This new property is added into Windows 2000 so IME can handle the injected Unicode by SendInput API. ImeProcessKey and ImeToAsciiEx APIs are updated to handle injected Unicode as well. The injected Unicode can be used by application and handwriting programs to put Unicode strings into input queue.

Win32 IME Structure

A new Win32 IME has to provide two components. One is the IME Conversion Interface and the other is the IME User Interface. The IME Conversion Interface is provided as a set of functions that are exported from the IME module. These functions are called by the IMM. The IME User Interface is provided in the form of windows. These windows receive messages and provide the user interface for the IME.

IME Aware Applications

One of the main advantages of the new Win32 IME architecture is that it provides better communication logic between the application and the IME. Following is an example of how an application could be involved with the IME:

  • IME Unaware Applications

    These kinds of applications never intend to control the IME. However, as long as it accepts DBCS characters, a user can type any DBCS character to the application using IME.

  • ME Half-aware Applications

    These kinds of applications typically control the various contexts of the IME, such as open and close, and composition form, but it does not display any user interface for the IME.

  • IME Full-aware Applications

    These kinds of applications typically want to be fully responsible for displaying any information given by the IME.

In Windows 95 and Windows NT 4.0 or later, one IME unaware application will be supported with one Default IME window and one Default Input Context.

An IME half-aware application will create its own IME window(s), also called an application IME window, using a predefined system IME class, and may or may not handle its own Input Context given to the application.

An IME fully aware application will handle the Input Context by itself and will display any necessary information given by the Input Context not using the IME window.

IME User Interface

The IME User Interface includes the IME window, the UI window, and the components of the UI window.

Features

An IME class is a predefined global class that carries out any user interface portion of the IME. The normal characteristics of an IME class are the same as with other common controls. Its window instance can be created by CreateWindowEx. As with static controls, the IME class window does not respond to user input by itself, but receives various types of control messages to realize the entire user interface of the IME. An application can create its own IME window(s) by using this IME class or by obtaining the Default IME window through ImmGetDefaultIMEWnd. In comparison to Windows 3.1, an application that wants to control the IME with these window handles (an IME-aware application) can now achieve the following benefits:

  • The new IME includes candidates listing windows. Each application can have its own window instance of the UI so a user can stop in the middle of any operation to switch to another application. In the Windows 3.1 Japanese Edition, the user had to first exit an operation before switching to another application.
  • Since the IME User Interface window is informed about an application's window handle, it can provide several default behaviors for the application. For example, this can include automatic repositioning of the IME window, automatic tracing of the window caret position, and mode indication for each application.

Even though the system provides only one IME class, there are two kinds of IME window. One is created by the system for the DefWindowProc function especially for an IME unaware program. The IME User Interface for the DefWindowProc function is shared by all IME unaware windows of a thread and is called the default IME window in this documentation. The other windows are created by IME aware applications and are called the application IME window.

Default and Application IME Window

The system creates a default IME window at thread initialization time, which is given to a thread automatically. This window then handles any IME user interface for an IME unaware application.

When the IME or IMM generates WM_IME_xxx messages, an IME unaware application passes them to DefWindowProc. Then, DefWindowProcB sends necessary messages to the default IME window, which provides default behavior of the IME User Interface for an unaware application. An IME aware application also uses this window when it does not hook messages from the IME. An application can use its own application IME window when it is necessary.

IME Class

The Win32 systems provides an IME class in the system. This class is defined by the user just as the predefined Edit class is. The system IME class handles the entire UI of the IME and handles entire control messages from the IME and application, including IMM functions. An application can create its own IME User Interface by using this class. The system IME class, itself, is not replaced by any IME, but is kept as a predefined class.

This class has a window procedure that actually handles the WM_IME_SELECT message. This message has the hKL of the newly selected IME. The system IME class retrieves the name of the class defined by each IME with this hKL. Using this name, the system IME class creates a UI window of the currently active IME.

UI Class from IME

In this design, every IME is expected to register its own UI class for the system. The UI class provided by each IME should be responsible for IME-specific functionality. The IME may register the classes that are used by the IME itself when the IME is attached to the process. This occurs when DllEntry is called with DLL_PROCESS_ATTACH. The IME then has to set the UI class name in the lpszClassName parameter, which is the second parameter of ImeInquire.

The UI class should be registered with CS_IME specified in the style field so every application can use it through the IME class. The UI class name (including the null terminator) can consist of up to 16 characters and may be increased in future versions.

The cbWndExtra of the UI class has to be 2 * sizeof(LONG). The purpose of this WndExtra is defined by the system (for example, IMMGWL_IMC and IMMGWL_PRIVATE).

The IME can register any class and create any window while working in an application.

The following sample shows how to register the IME User Interface Class:

BOOL WINAPI DLLEntry (
    HINSTANCE    hInstDLL,
    DWORD        dwFunction,
    LPVOID       lpNot)
{
switch(dwFunction)
    {
case DLL_PROCESS_ATTACH:
hInst= hInstDLL;
            wc.style          = CS_MYCLASSFLAG | CS_IME;
            wc.lpfnWndProc    = MyUIServerWndProc;
            wc.cbClsExtra     = 0;
            wc.cbWndExtra     = 2 * sizeof(LONG);
            wc.hInstance      = hInst;
            wc.hCursor        = LoadCursor( NULL, IDC_ARROW );
            wc.hIcon          = NULL;
            wc.lpszMenuName   = (LPSTR)NULL;
wc.lpszClassName  = (LPSTR)szUIClassName;
wc.hbrBackground  = NULL;
if( !RegisterClass( (LPWNDCLASS)&wc ) )
return FALSE;
            wc.style          = CS_MYCLASSFLAG | CS_IME;
            wc.lpfnWndProc    = MyCompStringWndProc;
            wc.cbClsExtra     = 0;
            wc.cbWndExtra     = cbMyWndExtra;
            wc.hInstance      = hInst;
            wc.hCursor        = LoadCursor( NULL, IDC_ARROW );
            wc.hIcon          = NULL;
            wc.lpszMenuName   = (LPSTR)NULL;
wc.lpszClassName  = (LPSTR)szUICompStringClassName;
wc.hbrBackground  = NULL;
if( !RegisterClass( (LPWNDCLASS)&wc ) )
return FALSE;
break;
case DLL_PROCESS_DETACH:
UnregisterClass(szUIClassName,hInst);
UnregisterClass(szUICompStringClassName,hInst);
break;
    }
return TRUE;
}

UI Window

The IME windows of the IME class are created by the application or by the system. When the IME window is created, the UI window provided by the IME itself is created and owned by the IME window.

Each UI window contains the current Input Context. This Input Context can be obtained by calling GetWindowLong with IMMGWL_IMC when the UI window receives a WM_IME_xxx message. The UI window can refer to this Input Context and handles the messages. The Input Context from GetWindowLong with IMMGWL_IMC is available at any time during the UI window procedure, except when handling a WM_CREATE message.

The cbWndExtra of the UI windows cannot be enhanced by the IME. When the IME needs to use the extra byte of the window instance, the UI window uses SetWindowLong and GetWindowLong with IMMGWL_PRIVATE. This IMMGWL_PRIVATE provides a LONG value extra of the window instance. When the UI window needs more than one LONG value extra for private use, the UI window can place a handle for a memory block into the IMMGWL_PRIVATE area.The UI window procedure can use DefWindowProc, but the UI window cannot pass a WM_IME_xxx message to DefWindowProc. Even if the message is not handled by the UI window procedure, the UI window does not pass it to DefWindowProc.

The following sample demonstrates how to allocate and use a block of private memory:

LRESULT UIWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HIMC hIMC;
HGLOBAL hMyExtra;

switch(msg){
case WM_CREATE:
// Allocate the memory block for the window instance.
hMyExtra = GlobalAlloc(GHND,size_of_MyExtra);
if (!hMyExtra)
MyError();
// Set the memory handle into IMMGWL_PRIVATE
SetWindowLong(hWnd, IMMGWL_PRIVATE, (LONG)hMyExtra);
                :
                :
break;
case WM_IME_xxxx:
// Get IMC;
hIMC = GetWindowLong(hWnd,IMMGWL_IMC);
// Get the memory handle for the window instance.
hMyExtra = GetWindowLong(hWnd, IMMGWL_PRIVATE);
lpMyExtra = GlobalLock(hMyExtra);
                :
                :
GlobalUnlock(hMyExtra);
break;
            :
            :

case WM_DESTROY:
// Get the memory handle for the window instance.
hMyExtra = GetWindowLong(hWnd, IMMGWL_PRIVATE);
// Free the memory block for the window instance.
GlobalFree(hMyExtra);
break;

default:
return DefWindowProc(hWnd, msg, wParam, lParam);
    }
}

The UI window must perform all tasks by referring to the Input Context that is currently selected. When a window of an application is activated, the UI window receives a message that contains the current Input Context. The UI window then uses that Input Context. Thus, the Input Context must contain all the information needed by the UI window to display the composition window, the status window, and so forth.

The UI window refers to the Input Context, but does not need to update it. However, if the UI window wants to update the Input Context, it should call the IMM functions. Because the Input Context is managed by the IMM, the IMM along with the IME should be notified when the Input Context is changed.

For example, the UI window occasionally needs to change the conversion mode of the Input Context when the user clicks the mouse. At this point, the UI window should call ImmSetConversionMode. The ImmSetConversionMode function creates a notification for NotifyIME and the UI window with WM_IME_NOTIFY. If the UI window wants to change the display of the conversion mode, the UI window should wait for a WM_IME_NOTIFY message.

Components of the UI Window

The UI window can register and show the composition window and the status window by referring to the current Input Context. The class style of the components of the UI window must include the CS_IME bit. A window instance of the UI window gets information about the composition string, font, and position from the current Input Context.

When a window of the application is getting focused, the system gives the Input Context to this window and sets the current Input Context to the UI window. The system then sends a WM_IME_SETCONTEXT message with the handle of its Input Context to the application. The application then passes this message to the UI window. If current Input Context is replaced by another Input Context, the UI window should repaint the composition window. Any time the current Input Context is changed, the UI window displays a correct composition window. Thus, the status of the IME is assured.

A UI window can create a child window or pop-up window to display its status, composition string, or candidate lists. However, these windows have to be owned by the UI window and created as disabled windows. Any windows that are created by the IME should not get the focus.

IME Input Context

Each window is associated with an IME Input Context. The IMM uses the Input Context to maintain IME status, data, and so forth, and communicate with the IME and with applications.

Default Input Context

By default, the system creates a default Input Context for each thread. All IME unaware windows of the thread share this context.

Application-Created Input Context

A window of an application can associate its window handle to an Input Context to maintain any status of the IME, including an intermediate composition string. Once an application associates an Input Context to a window handle, the system automatically selects the context whenever the window is activated. In this way, an application is free from complicated in and out focus processing.

Using the Input Context

When an application or system creates a new Input Context, the system prepares the new Input Context with the components of the IMC (IMCC). These include hCompStr, hCandInfo, hGuideLine, hPrivate, and hMsgBuf. Basically, the IME does not need to create the Input Context and the components of the Input Context. The IME can change the size of them and lock them to get the pointer for them.

Accessing the HIMC

When an IME accesses the Input Context, the IME has to call ImmLockIMC to get the pointer of the Input Context. ImmLockIMC increments the IMM lock count for IMC, while ImmUnlockIMC decrements the IMM lock count for IMC.

Accessing the HIMCC

When an IME accesses a component of the Input Context, the IME has to call ImmLockIMCC to get the pointer of the IMCC. ImmLockIMCC increments the IMM lock count for IMCC, while ImmUnlockIMC decrements the IMM lock count for IMCC. ImmReSizeIMCC can resize the IMCC to the size specified in the input parameter.

On occasion, an IME needs to create a new component in the Input Context. The IME can call ImmCreateIMCC to do so. To destroy a newly created component in the Input Context, the IME can call ImmDestroyIMCC.

The following example shows how to access the IMCC and change the size of a component:

LPINPUTCONTEXT lpIMC;
LPCOMOSITIONSTRING lpCompStr;
HIMCC hMyCompStr;

if (hIMC)    // It is not NULL context.
{
lpIMC = ImmLockIMC(hIMC);
if (!lpIMC)
    {
MyError( "Can not lock hIMC");
return FALSE;
    }

// Use lpIMC->hCompStr.
lpCompStr = (LPCOMPOSITIONSTRING)ImmLockIMCC(lpIMC->hCompStr);
// Access lpCompStr.
ImmUnlockIMCC(lpIMC->hCompStr);

// ReSize lpIMC->hCompStr.
if (!(hMyCompStr = ImmReSizeIMCC(lpIMC->hCompStr,dwNewSize))
    {
MyError("Can not resize hCompStr");
ImmUnlockIMC(hIMC);
return FALSE;
    }
lpIMC->hCompStr = hMyCompStr;
ImmUnlockIMC(hIMC);
}

Generating Messages

IMEs need to generate IME messages. When an IME initiates the conversion process, the IME has to generate a WM_IME_STARTCOMPOSITION message. If the IME changes the composition string, the IME has to generate a WM_IME_COMPOSITION message.

There are two ways an IME can generate a message: one is by using the lpdwTransKey buffer provided by ImeToAsciiEx, and the other is by calling ImmGenerateMessage.

Using lpTransMsgList to Generate Messages

Events initiated by IMEs are realized as generating messages to the window associated with the Input Context. Basically, IMEs use the lpTransMsgList provided by the parameter of ImeToAsciiEx to generate the message. The IMEs put the messages into the lpTransMsgList buffer when ImeToAsciiEx is called.

The buffer specified by lpTransMsgList in the ImeToAsciiEx function is provided by the system. This function can place messages in this buffer all at one time. The real number of messages that can be placed is given at the first double word of the buffer. However, if the ImeToAsciiEx function wants to generate more messages than the given number, ImeToAsciiEx can put all the messages into hMsgBuf in the Input Context and then return the number of messages.

When the return value of ImeToAsciiEx is larger than the specified value in lpTransMsgList, the system does not pick up the messages from lpTransMsgList. Instead, the system looks up hMsgBuf in the Input Context, which is passed as a parameter of ImeToAsciiEx.

Following is the code sample for ImeToAsciiEx implementation:

UINT
ImeToAsciiEx(
uVirKey,
uScanCode,
lpbKeyState,
lpTransMsgList,
fuState,
hIMC
)

{
    DWORD dwMyNumMsg = 0;

. . .

    // Set the messages that the IME wants to generate.
    pTransMsgList->TransMsg[0].message =msg;
    pTransMsgList->TransMsg[0].wParam = wParam;
    pTransMsgList->TransMsg[0].lParam = lParam;

    // Count the number of the messages that the IME wants to generate.
    dwMyNumMsg++;

. . .

    return dwMyNumMsg;
}

Using the Message Buffer to Generate Messages

Even if ImeToAsciiEx is not called, IMEs can still generate the message to the window associated with the Input Context by using the message buffer of the Input Context. This message buffer operates as a handle of a memory block and the IME puts the messages into this memory block. The IME then calls the ImmGenerateMessage function, which sends the messages stored in the message buffer to the proper window.

Following is the code sample for ImmGenerateMessage implementation.

MyGenerateMesage(HIMC hIMC, UINT msg, WPARAM wParam, LPARAMlParam)
{
    LPINPUTCONTEXT lpIMC;
    HGLOBAL hTemp;
        LPTRANSMSG lpTransMsg;
DWORD dwMyNumMsg = 1;

    // Lock the Input Context.
    lpIMC = ImmLockIMC(hIMC);
    if (!lpIMC) ….. // Error!
// re-allocate the memory block for the message buffer.
hTemp = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + dwMyNumMsg) * sizeof(TRANSMSG));
if (!hTemp) ….// Error!
lpIMC->hMsgBuf = hTemp;
// Lock the memory for the message buffer.
lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf);
if (!lpTransMsg) …. // Error!

// Set the messages that the IME wants to generate.
lpTransMsg[lpIMC->dwNumMsg].message = msg;
lpTransMsg[lpIMC->dwNumMsg].wParam = wParam;
lpTransMsg[lpIMC->dwNumMsg].lParam = lParam;

// Set the number of the messages.
lpIMC->dwNumMsgBuf += dwMyNumMsg;

// Unlock the memory for the message buffer and the Input Context.
ImmUnlockIMCC(lpIMC->hMsgBuf);
ImmLockIMC(hIMC);

// Call ImmGenerateMessage function.
ImmGenerateMessage(hIMC);
}

WM_IME_COMPOSITION Message

When an IME generates a WM_IME_COMPOSITION message, the IME specifies lParam as the GCS bits. The GCS bits then inform the available members of the COMPOSITIONSTRING structure. Even if the IME does not update and a member is available, the IME can set the GCS bits.

When an IME generates a WM_IME_COMPOSITION message, the IME can also change the string attribute and clause information all at once.

ImeSetCompositionString

The ImeSetCompositionString function is used by applications to manipulate the IME composition string. By specifying different flags, an application can change composition string, attribute, clause, and so forth.

The second parameter of this function, dwIndex, specifies how the composition string should be adjusted in an IME. It includes values such as SCS_SETSTR ,SCS_CHANGEATTR, SCS_CHANGECLAUSE, SCS_QUERYRECONVERTSTRING. Each value represents a specific feature.

ImeSetCompositionString Capability

When an IME does not have the capability of ImeSetCompositionString, it will not specify any SCS capability in the IMEINFO structure. When an IME can handle ImeSetCompositionString, it sets the SCS_COMPSTR bit. If an IME can generate the reading string from the composition string, it will set the SCS_CAP_MAKEREAD bit.

If an IME has SCS_CAP_COMPSTR capability, ImeSetCompositionString will be called. In response to this call, the IME should use the new composition string generated by an application and then generate a WM_IME_COMPOSITION message.

SCS_SETSTR

If dwIndex of ImeSetCompositionString is SCS_SETSTR, the IME can clean up all the COMPOSITIONSTR structures of hIMC.

If necessary, the IME can also update the candidate information and generate the candidate message WM_IME_NOTIFY with the submessage as IMN_OPENCANDIDATE, CHANGECANDIDATE, or IMN_CLOSECANDIDATE.

An IME needs to respond to the application requirement based on different input parameters as follows:

  • If the lpRead parameter of ImeSetCompositonString is available:

    The IME should create the composition string from the reading string contained in lpRead. The IME then creates the attribute and clause information for both the new composition string and reading string of lpRead. The IME generates a WM_IME_COMPOSITION message with either GCS_COMP or GCS_COMPREAD. On occasion, an IME may finalize the conversion automatically. The IME can then generate a WM_IME_COMPOSITION message with either GCS_RESULT or GCS_RESULTREAD instead of GCS_COMPxxx.

  • If the lpComp parameter of ImeSetCompositonString is available:

    The IME should create the composition attribute and clause information from the composition string contained in lpComp. The IME then generates a WM_IME_COMPOSITION message with GCS_COMP. If the IME has the capability of SCS_CAP_MAKEREAD, the IME should also make the new reading string at the same time. The IME then generates a WM_IME_COMPOSITION message with either GCS_COMP orGCS_COMPREAD. On occasion, an IME may finalize the conversion automatically. The IME can then generate a WM_IME_COMPOSITION message with either GCS_RESULT or GCS_RESULTREAD instead of GCS_COMPxxx.

  • If both lpRead and lpComp are available:

    The IME should create the composition string and the reading string accordingly. In this case, the IME does not need to follow lpComp and lpRead completely. If an IME cannot find the relation between lpRead and lpComp specified by the application, it should correct the composition string. The IME can then create the attribute and clause information for both the new composition string and reading string of lpRead. The IME then generates a WM_IME_COMPOSITION message with either GCS_COMP or GCS_COMPREAD. On occasion, the IME may finalize the conversion automatically. The IME can then generate a WM_IME_COMPOSITION message with either GCS_RESULT or GCS_RESULTREAD instead of GCS_COMPxxx.

SCS_CHANGEATTR

SCS_CHANGEATTR effects only attribute information. The IME should not update the composition string, the clause information of the composition string, the reading of the composition string, or the clause information of the reading of the composition string.

The IME first has to check whether the new attribute is acceptable or not. It then sets the new attribute in the COMPOSITIONSTRING structure of hIMC. Last, the IME generates a WM_IME_COMPOSITION message.

If necessary, the IME can update the candidate information and generate the candidate messages WM_IME_NOTIFY with the submessage as IMN_OPENCANDIDATE, CHANGECANDIDATE, or IMN_CLOSECANDIDATE of WM_IME_NOTIFY.

For this feature, an IME cannot finalize the composition string.

An IME needs to respond to the application requirement based on different input parameters as follows:

  • If the lpRead parameter of ImeSetCompositonString is available:

    The IME should follow the new attribute in lpRead and then create a new attribute of the composition string for the current composition string. In this case, the clause information does not change.

    The IME generates a WM_IME_COMPOSITION message with either GCS_COMP or GCS_COMPREAD. If an IME cannot accept the new attribute contained in lpRead, it does not generate any messages and returns FALSE.

  • If the lpComp parameter of ImeSetCompositonString is available:

    The IME follows the new attribute in lpComp. In this case, the clause information does not change.

    If the capability of the IME has SCS_CAP_MAKEREAD and the reading string is available, the IME should create a new attribute of the reading of the composition string for the current reading of the composition string.

  • If both lpRead and lpComp are available:

    If the IME can accept the new information, it sets the new information in the COMPOSITION structure of hIMC and generates a WM_IME_COMPOSITION message with either GCS_COMP or GCS_COMPREAD.

SCS_CHANGECLAUSE

SCS_CHANGECLAUSE effects the string and attribute for both the composition string and the reading of the composition string.

If necessary, an IME can update the candidate information and generate the candidate message WM_IME_NOTIFY with the submessages as IMN_OPENCANDIDATE, CHANGECANDIDATE, or IMN_CLOSECANDIDATE.

An IME needs to respond to the application requirement based on different input parameters. Following are the instances in which an IME cannot finalize the composition string.

  • If the lpRead parameter of ImeSetCompositonString is available:

    The IME follows the new reading clause information of lpRead and has to correct the attribute of the reading of the composition string. The IME can then update the composition string, the attribute, and the clause information of the composition string. The IME generates a WM_IME_COMPOSITION message with either GCS_COMP or GCS_COMPREAD.

  • If the lpComp parameter of ImeSetCompositonString is available:

    The IME follows the new clause information and has to correct the composition string and the attribute of the composition string. Then, the IME can update the reading attribute and the clause information of the reading attribute. The IME generates a WM_IME_COMPOSITION message with either GCS_COMPSTR or GCS_COMPREAD.

  • If both lpRead and lpComp are available:

    If the IME can accept the new information, it sets the new information in the COMPOSITION structure of hIMC and generates a WM_IME_COMPOSITION message with either GCS_COMP or GCS_COMPREAD.

Soft Keyboard

Soft Keyboard is a special window displayed by the IME. Because some IMEs have special reading characters, an IME can provide a soft keyboard to display these special reading characters. In this way, the user does not have to remember the reading character for each key. For example, an IME can use bo po mo fo for its reading characters, while another IME can use radicals for its reading characters.

An IME can change the reading characters of keys and notify the user of these key changes, depending on the conversion state. For example, during candidate selection time, an IME can show just the selection keys to the user.

An IME can also create its own user interface for a soft keyboard or use the system predefined soft keyboard. If an IME wants to use the system predefined soft keyboard, it needs to specify UI_CAP_SOFTKBD in the fdwUICaps member of the IMEINFO structure when ImeInquire is called.

An IME needs to call ImmCreateSoftKeyboard to create the soft keyboard window . It can also call ImmShowSoftKeyboard to show or hide the soft keyboard. Because the soft keyboard window is one component of the UI window, the owner should be the UI window as well.

There are different types of soft keyboards. Each one is designed for a specific country/region or special purpose. An IME can change the reading characters on the soft keyboard by using one of two methods: IMC_SETSOFTKBDSUBTYPE or IMC_SETSOFTKBDDATA.

Reconversion

Reconversion is a new IME function for Windows 98 and Windows 2000. It provides the capability to reconvert a string that is already inserted in an application's document. Specifically, whatever the string is, an IME is instructed to recognize the string, convert it to the reading or typing information, and then display the candidate list.

New and advanced intelligent IMEs are capable of recognizing and interpreting a complete sentence. When an IME is supplied with better information about a string, such as full sentence and string segmentation, it can accomplish better conversion performance and accuracy. For example, by supplying an entire sentence as opposed to just the reconverted strings, the IME can reconvert the string without having to first convert to reading or typing information.

Editing after the determination is harder than before today. This is because determination will discard most of the information undetermined string had, like reading, phrases, and part of speech. Reconversion will get these information back, making editing after the determination as easier as before the determination. Users will be able to choose different homonym words from candidates, change phrase break and let IME analyze again, and so forth.

The RECONVERTSTRING structure can store the entire sentence and point to the string that will be reconverted by dwStartOffset and dwLen. If dwStartOffset is zero and dwLen is the length of the string, the entire string is reconverted by the IME.

Simple Reconversion

The simplest reconversion is when the target string and the composition string are the same as the entire string. In this case, dwCompStrOffset and dwTargetStrOffset are zero, and dwStrLen, dwCompStrLen, and dwTargetStrLen are the same value. An IME will provide the composition string of the entire string that is supplied in the structure, and will set the target clause by its conversion result.

Normal Reconversion

For an efficient conversion result, the application should provide the RECONVERTSTRING structure with the information string. In this case, the composition string is not the entire string, but is identical to the target string. An IME can convert the composition string by referencing the entire string and then setting the target clause by its conversion result.

Enhanced Reconversion

Applications can set a target string that is different from the composition string. The target string (or part of the target string) is then included in a target clause in high priority by the IME. The target string in the RECONVERTSTRING structure must be part of the composition string. When the application does not want to change the user's focus during the reconversion, the target string should be specified. The IME can then reference it.

IME Cancel Reconversion

When a user cancels the composition string generated by the reconversion, the IME should determine the original reconverted string. Otherwise, the application will loose the string.

SCS_SETRECONVERTSTRING and SCS_QUERYRECONVERTSTRING Flags

Applications can ask an IME to reconvert the string by calling ImmSetCompositionString. They can use either the SCS_SETSTR flag or the SCS_SETRECONVERTSTRING flag to create a new composition string. However, by using SCS_SETRECONVERTSTRING, the application can pass RECONVERTSTRING to the IME for better conversion efficiency.

Initially, the application should call ImmSetCompositionString with SCS_QUERYRECONVERTSTRING. The selected IME can then adjust the given RECONVERTSTRING structure for appropriate reconversion. The application then calls ImmSetCompositionString with SCS_SETRECONVERTSTRING to request that the IME generate a new composition string. If the application asks the IME to adjust the RECONVERTSTRING structure by calling SCS_QUERYRECONVERTSTRING, efficient reconversion can be accomplished.

SCS_SETRECONVERTSTRING or SCS_QUERYRECONVERTSTRING can be used only for IMEs that have an SCS_CAP_SETRECONVERTSTRING property. This property can be retrieved by using the ImmGetProperty function.

IMR_RECONVERTSTRING and IMR_CONFIRMRECONVERTSTRING Messages

When an IME wants to reconvert, it can ask the application to provide the string to be reconverted. For example, when a user presses the Reconversion key or selects the Reconversion button in the IME status window, the IME sends a WM_IME_REQUEST message with IMR_RECONVERTSTRING to get the target string. Initially, the IME needs to send this with NULL lParam in order to get the required size of RECONVERTSTRING. The IME then prepares a buffer to receive the target string and sends the message again with the pointer of the buffer in lParam.

After the application handles IMR_RECONVERTSTRING, the IME may or may not adjust the RECONVERTSTRING structure given by the application. Finally, the IME sends a WM_IME_REQUEST message with IMR_CONFIRMRECONVERTSTRING to confirm the RECONVERTSTRING structure.

If the application returns TRUE for IMR_CONFIRMRECONVERTSTRING, the IME generates a new composition string based on the RECONERTSTRING structure in the IMR_CONFIRMRECONVERTSTRING message. If the application returns FALSE, the IME generates a new composition string based on the original RECONVERTSTRING structure given by the application in the IMR_RECONVERTSTRING message. An IME will not generate a composition string for reconversion before IMR_CONFIRMRECONVERTSTRING.

The given string should not be changed by SCS_QUERYRECONVERTSTRING or IMR_CONFIRMRECONVERTSTRING. An IME can change only CompStrOffset, CompStrLen, TargetStrOffset, and TargetStrLen to re-confirm it.

IME Menu Functions

The purpose of this function set is to reduce the IME-related icon in the system task bar. It is a new feature for Windows 98 and Windows 2000.

The Windows system program installs two icons in the task bar when the current hKL is an IME. One icon is the System ML icon that indicates the current keyboard layout in the system task bar. The other is the System Pen icon that shows the IME status of the focused window.

Usually, an IME places an additional icon in the task bar. The context menu for this icon is completely dependent on the IME. Having IME icons in a task bar is a quick way for a user to access an IME's special functions. However, there are three icons associated with the IME and these additional icons may be more than a user wants to deal with.

If the system provides a way for an IME to insert IME menu items into the System Pen icon, the IME then does not need to add its extra icons to the task bar.

The IMM calls the IME function ImeGetImeMenuItems to get the IME menu items.

An application can use ImmGetImeMenuItems to get an IME's special menu items, which it can add to its context menu. By calling ImmNotify, the selected items can be processed by the IME.

IME Menu Notification

When an application wants to handle an IME's menu items, it can call ImmNotifyIME. When the menu items added by the IME are selected, NotifyIME is called under the focused thread.

IME Help File

The IME help file is a new function added into Windows 98 and Windows NT. The right click menu of the System Pen Icon has two menu items. One is the setting for the IME system and is used to change the setting of the selected IME of the focus thread. The other menu item is an online Help file that has never been enabled. Thus, this menu item is always grayed. The purpose of this menu item was to display an IME's online Help. However, because the system does not provide the IME with a way to specify the name of the IME help file, the system task bar program is not able to display it.

IME_ESC_GETHELPFILENAME

The IME_ESC_GETHELPFILENAME escape allows an IME to specify its help file name. On return from the function, the (LPTSTR)lpData is the full path file name of an IME's help file.

If the help content is HTML help format, please make sure the help file extension is .chm so the Windows User knows which help engine to start.

Indicator Manager for IME

By using a set of messages defined in Windows 98 and Windows 2000, an IME can change the icon and ToolTip string for the System Pen icon on the system task bar.

Indicator Window

An IME can get the window handle of the indicator by using FindWindow with INDICATOR_CLASS.

// Get the window handle of Indicator.
hwndIndicator = FindWindow(INDICATOR_CLASS, NULL);
if (!hwndIndicator)
{
// There is no indicator window. Tray does not have System Pen icon.
return FALSE;
}
// Call PostMessage to change Pen icon.
PostMessage(hwndIndicator, INIDCM_SETIMEICON, nIconIndex, hMyKL);

Note Due to the internal design requirement in the task bar manager, the IME must use PostMessage for INDICM_xxx messages.

Messages

IMEs can send the following messages to the Indicator window to perform different tasks:

INDICM_SETIMEICON

INDICM_SETIMETOOLTIPS

INDICM_REMOVEDEFAULTMENUITEMS

Windows NT and Windows 2000 Issues

The following topics primarily describe the special issues related to Windows NT/2000. However, some of these issues may also apply to Windows 98.

IME and Localized Language Compatibility

Windows 2000 has full-featured IME support in any localized language version. That is, an IME can be installed and used with any Windows 2000 language. IME developers should test their IME on these environments. This new feature also requires IME developers to prepare their IME help content to include correct charset and font information so it shows up correctly on different language operating systems.

Also, IME developers should develop Unicode IME for Windows 2000. Unicode IMEs will work with Unicode applications under any system locale. For non-Unicode IMEs, the user must change the system locale to support the same language that the IME supports in order to use them.

Unicode Interface

Along with the ANSI version of the IMM/IME interface originally supported by Windows 95, Windows NT and Windows 98 support Unicode interface for the IME. To communicate with the system by Unicode interface, an IME should set the IME_PROP_UNICODE bit of the fdwProperty member of the IMEINFO structure, which is the first parameter of the ImeInquire function. Although ImeInquire is called to initialize the IME for every thread of the application process, the IME is expected to return the same IMEINFO structure on a single system. Windows 98 supports all the Unicode functions, except for ImmIsUIMessage.

Security Concerns

There are two primary security concerns for Windows NT. One involves named objects and the other involves Winlogon.

Named Objects

An IME may want to create various named objects that should be accessed from multiple processes on the local system. Such objects may include file, mutex, or event. Since a process might belong to a different user who is interactively logging onto the system, the default security attribute (created by the system when an IME creates an object with the NULL parameter as the pointer to the security attribute) may not be appropriate for all processes on the local system.

On Windows NT, the first client process of the IME may be the Winlogon process that lets a user log onto the system. Since the Winlogon process belongs to the system account during the log-on session and is alive until the system shuts down, named objects created by the IME with the default security attribute during the log-on session cannot be accessed through other processes belonging to a logged-on user.

A sample IME source code that creates the security attribute appropriated for named objects is provided in the Microsoft Platform DDK. By using the sample code, IME writers can create various named objects that can be accessed from all client processes of the IME on the local system. The security attribute allocated by the sample code is per process. An IME that frequently creates named objects may want to initialize the security attribute attach time and free the security attribute at the process detach time. An IME that does not create named objects often may want to initialize the security attribute just before the creation of the named object and then free the security attribute just after the object is created.

Winlogon

Since a user in the log-on session has not been granted the access right to the system yet, information provided by an IME's configuration dialog boxes can create security problems. Even though, the system administrator can configure the system so such an IME cannot be activated on the log-on session. A well-behaved IME should not allow users to open configure dialog boxes if the client process is a Winlogon process. An IME can check if the client process executing a log-on session is a Winlogon process by checking the IME_SYSTEMINFO_WINLOGON bit of the dwSystemInfoFlags parameter of ImeInquire.

IME File Format and Data Structures

The following topics discuss the IME file format and data structures used by the IME.

IME File Format

An IME needs to specify the following fields correctly in the version information resource. This includes the fixed file information part and the variable length information part. Please refer to the Microsoft Platform SDK for detailed information on version information resource.

Following are the specific settings the IME file should include:

dwFileOS
The dwFileOS should be specified in the root block of the version information. The dwFileOS should be VOS__WINDOWS32 for Windows 95 and Windows NT IMEs.
dwFileType
The dwFileType should be specified in the root block of the version information. The value is VFT_DRV.
dwFileSubtype
The dwFileSubtype should be specified in the root block of the version information. The value is VFT2_DRV_INPUTMETHOD.
FileDescription
The FileDescription is specified in the language-specific block of the version information. This should include the IME name and the version. This string is for display purposes only. Currently, the string length is 32 TCHARS, but may be extended in a future version.
ProductName
The ProductName is specified in the language-specific block of the version information.
Charset ID and Language ID
The code page (character set ID) and language ID are specified in the variable information block of the version information resource. If there are many code pages (character set ID) and language IDs are specified in the block, the IME uses the first code page ID to display the text and uses the first language ID for the IME language. The charset ID and language ID must match the IME language instead of the resource language. The file name of IME is 8.3.

IME Registry Contents

The IME HKEY_CURRENT_USER registry contains an Input Method key. The following table describes the contents of this Input Method.

Key | Contents
Input Method | There are four value names: Perpendicular Distance, Parallel Distance, Perpendicular Tolerance, and Parallel Tolerance. The near caret operation IME refers to these values. If these four value names are not present, a near operation IME can set a default value, depending on the IME
 | Value Name | Value Data
 | Perpendicular Distance | Distance is perpendicular to the text escapement. This is the perpendicular distance (pixels) from the caret position to the composition window without the font height and width. The near caret operation IME will adjust the composition window position according to this value and Parallel Distance. It is in REG_DWORD format.
 | Parallel Distance | Distance (pixels) is parallel to the text escapement. This is the parallel distance from the caret position to the composition window. It is in REG_DWORD format.
 | Perpendicular Tolerance | Tolerance (pixels) is perpendicular to the text escapement. This is the perpendicular distance from the caret position to the composition window. The near caret operation IME will not refresh its composition window if the caret movement is within this tolerance. It is in REG_DWORD format.
 | Parallel Tolerance | Tolerance (pixels) is parallel to the text escapement. This is the parallel distance from the caret position to the composition window. It is in REG_DWORD format.

An IME can place the per-user setting into:

Under HKEY_CURRENT_USER\Software\<Company Name>\Windows\CurrentVersion\<IME Name>.

An IME can place the per computer setting into:

Under HKEY_LOCAL_MAACHINE\Software\<Company Name>\Windows\CurrentVersion\<IME Name>.

IMM and IME Data Structures

The following structures are used for IMM and IME communication. IMEs can access these structures directly, but applications cannot.

INPUTCONTEXT

The INPUTCONTEXT structure is an internal data structure that stores Input Context data.

typedef struct tagINPUTCONTEXT {
HWND  hWnd;
BOOL  fOpen;
POINT  ptStatusWndPos;
POINT  ptSoftKbdPos;
DWORD  fdwConversion;
DWORD  fdwSentence;
union {
            LOGFONTA    A;
            LOGFONTW    W;
} lfFont;
COMPOSITIONFORM  cfCompForm;
CANDIDATEFORM  cfCandForm[4];
HIMCC  hCompStr;
HIMCC  hCandInfo;
HIMCC  hGuideLine
HIMCC  hPrivate;
DWORD  dwNumMsgBuf;
HIMCC  hMsgBuf;
DWORD  fdwInit
DWORD  dwReserve[3];
} INPUTCONTEXT;

Members

hWnd
Window handle that uses this Input Context. If this Input Context has shared windows, this must be the handle of the window that is activated. It can be reset with ImmSetActiveContext.
fopen
Present status of opened or closed IME.
ptStatusWndPos
Position of the status window.
ptSoftKbdPos
Position of the soft keyboard.
fdwConversion
Conversion mode that will be used by the IME composition engine.
fdwSentence
Sentence mode that will be used by the IME composition engine.
lfFont
LogFont structure to be used by the IME User Interface when it draws the composition string.
cfCompForm
COMPOSITIONFORM structure that will be used by the IME User Interface when it creates the composition window.
cfCandForm[4]
CANDIDATEFORM structures that will be used by the IME User Interface when it creates the candidate windows. This IMC supports four candidate forms.
hCompStr
Memory handle that points to the COMPOSITIONSTR structure. This handle is available when there is a composition string.
hCandInfo
Memory handle of the candidate. This memory block has the CANDIDATEINFO structure and some CANDIDATELIST structures. This handle is available when there are candidate strings.
hGuideLine
Memory handle of GuideLine. This memory block has the GUIDELINE structure. This handle is available when there is guideline information.
hPrivate
Memory handle that will be used by the IME for its private data area.
dwNumMsgBuf
Number of messages that are stored in the hMsgBuf.
hMsgBuf
Memory block that stores the messages in TRANSMSG format. The size of the buffer should be able to store the dwNumMsgBuf amount of TRANSMSGs. This buffer was previously defined in Windows 95/98 and Windows NT 4.0 IME document as the format as [Message1] [wParam1] [lParam1] {[Message2] [wParam2] [lParam2]{...{...{...}}}}, andall values are double word for Win32 platforms.
fdwinit
Initialize flag. When an IME initializes the member of the INPUTCONTEXT structure, the IME has to see the bit of this member. The following bits are provided.
Bit | Description
INIT_STATUSWNDPOS | Initialize ptStatusWndPos.
INIT_CONVERSION | Initialize fdwConversion.
INIT_SENTENCE | Initialize fdwSentence.
INIT_LOGFONT | Initialize lfFont.
INIT_COMPFORM | InitializecfCompForm.
INIT_SOFTKBDPOS | Initialize ptSoftKbdPos.

dwReserve[3]
Reserved for future use.

Note During a call to ImeToAsciiEx, an IME can generate the messages into the lpdwTransKey buffer. However, if an IME wants to generate the messages to the application, it can store the messages in hMsgBuf and call ImmGenerateMessage. The ImmGenerateMessage function then sends the messages in hMsgBuf to the application.

COMPOSITIONSTR

The COMPOSITIONSTR structure contains the composition information. During conversion, an IME places conversion information into this structure.

typedef struct tagCOMPOSITIONSTR {
DWORD  dwSize;
DWORD  dwCompReadAttrLen;
DWORD  dwCompReadAttrOffset;
DWORD  dwCompReadClsLen;
DWORD  dwCompReadClsOffset;
DWORD  dwCompReadStrLen;
DWORD  dwCompReadStrOffset;
DWORD  dwCompAttrLen;
DWORD  dwCompAttrOffset;
DWORD  dwCompClsLen;
DWORD  dwCompClsOffset;
DWORD  dwCompStrLen;
DWORD  dwCompStrOffset;
DWORD  dwCursorPos;
DWORD  dwDeltaStart;
DWORD  dwResultReadClsLen;
DWORD  dwResultReadClsOffset;
DWORD  dwResultReadStrLen;
DWORD  dwResultReadStrOffset;
DWORD  dwResultClsLen;
DWORD  dwResultClsOffset;
DWORD  dwResultStrLen;
DWORD  dwResultStrOffset;
DWORD  dwPrivateSize;
DWORD  dwPrivateOffset;
} COMPOSITIONSTR;

Members

dwSize
Memory block size of this structure.
dwCompReadAttrLen
Length of the attribute information of the reading string of the composition string.
dwCompReadAttrOffset
Offset from the start position of this structure. Attribute information is stored here.
dwCompReadClsLen
Length of the clause information of the reading string of the composition string.
dwCompReadClsOffset
Offset from the start position of this structure. Clause information is stored here.
dwCompReadStrLen
Length of the reading string of the composition string.
dwCompReadStrOffset
Offset from the start position of this structure. Reading string of the composition string is stored here.
dwCompAttrLen
Length of the attribute information of the composition string.
dwCompAttrOffset
Offset from the start position of this structure. Attribute information is stored here.
dwCompClsLen
Length of the clause information of the composition string.
dwCompClsOffset
Offset from the start position of this structure. Clause information is stored here.
dwCompStrLen
Length of the composition string.
dwCompStrOffset
Offset from the start position of this structure. The composition string is stored here.
dwCursorPos
Cursor position in the composition string.
dwDeltaStart
Start position of change in the composition string. If the composition string has changed from the previous state, the first position of such a change is stored here.
dwResultReadClsLen
Length of the clause information of the reading string of the result string.
dwResultReadClsOffset
Offset from the start position of this structure. Clause information is stored here.
dwResultRieadStrLen
Length of the reading string of the result string.
dwResultReadStrOffset
Offset from the start position of this structure. Reading string of the result string is stored at this point.
dwResultClsLen
Length of the clause information of the result string.
dwResultClsOffset
Offset from the start position of this structure. Clause information is stored here.
dwResultStrLen
Length of the result string.
dwResultStrOffset
Offset from the start position of this structure. Result string is stored here.
dwPrivateSize
Private area in this memory block.
dwPrivateOffset
Offset from the start position of this structure. Private area is stored here.

Note For Unicode: All dw*StrLen members contain the size in Unicode characters of the string in the corresponding buffer. Other dw*Len and dw*Offset members contain the size in bytes of the corresponding buffer.

The format of the attribute information is a single-byte array and specifies the attribute of string. The following values are provided. Those not listed are reserved.

Value | Content
ATTR_INPUT | Character currently being entered.
ATTR_TERGET_CONVERTED | Character currently being converted (already converted).
ATTR_CONVERTED | Character given from the conversion.
ATTR_TERGET_NOTCONVERTED | Character currently being converted (yet to be converted).
ATTR_FIXEDCONVERTED | Characters will not be converted anymore.
ATTR_INPUT_ERROR | Character is an error character and cannot be converted by the IME.

Following is a description of the content for the values provided in the preceding table.

Content | Description
Character currently being entered. | Character that the user is entering. If this is Japanese, this character is a hiragana, katakana, or alphanumeric character that has yet to be converted by the IME.
Character currently being converted (already converted). | Character that has been selected for conversion by the user and converted by the IME.
Character given from conversion. | Character which the IME has converted.
Character currently being converted (yet to be converted). | Character that has been selected for conversion by the user and not yet converted by the IME. If this is Japanese, this character is a hiragana, katakana, or alphanumeric character that the user has entered.
Character is an error character and cannot be converted by the IME. | Character is an error character and the IME cannot convert this character. For example, some consonants cannot be combined.

Comments

The length of the attribute information is the same as the length of the string. Each byte corresponds to each byte of the string. Even if the string includes DBCS characters, the attribute information has the information bytes of both the lead byte and the second byte.

For Windows NT Unicode, the length of the attribute information is the same as the length in Unicode character counts. Each attribute byte corresponds to each Unicode character of the string.

The format of the clause information is a double-word array and specifies the numbers that indicate the position of the clause. The position of the clause is the position of the composition string, with the clause starting from this position. At the least, the length of information is two double words. This means the length of the clause information is 8 bytes. The first double word has to be zero and is the start position of the first clause. The last double word has to be the length of this string. For example, if the string has three clauses, the clause information has four double words. The first double word is zero. The second double word specifies the start position of the second clause. The third double word specifies the start position of the third clause. The last double word is the length of this string.

For Windows NT Unicode, the position of each clause and the length of the string is counted in Unicode characters.

The dwCursorPos member specifies the cursor position and indicates where the cursor is located within the composition string, in terms of the count of that character. The counting starts at zero. If the cursor is to be positioned immediately after the composition string, this value should be equal to the length of the composition string. In the event there is no cursor, a value of -1 is specified here. If a composition string does not exist, this member is invalid.

For Windows NT Unicode, the cursor position is counted in Unicode characters.

CANDIDATEINFO

The CANDIDATEINFO structure is a header of the entire candidate information. This structure can contain 32 candidate lists at most, and these candidate lists have to be in the same memory block.

typedef struct tagCANDIDATEINFO {
DWORD  dwSize;
DWORD  dwCount;
DWORD  dwOffset[32];
DWORD  dwPrivateSize;
DWORD  dwPrivateOffset;
} CANDIDATEINFO;

Members

dwSize
Memory block size of this structure.
dwCount
Number of the candidate lists that are included in this memory block.
dwOffset[32]
Contents are the offset from the start position of this structure. Each offset specifies the start position of each candidate list.
dwPrivateSize
Private area in this memory block.
dwPrivateOffset
Offset from the start position of this structure. The private area is stored here.

GUIDELINE

The GUIDELINE structure contains the guideline information that the IME sends out.

typedef struct tagGUIDELINE {
DWORD  dwSize;
DWORD  dwLevel;  // the error level.
// GL_LEVEL_NOGUIDELINE,
// GL_LEVEL_FATAL,
// GL_LEVEL_ERROR,
// GL_LEVEL_WARNNING,
// GL_LEVEL_INFORMATION
    DWORD dwIndex;  // GL_ID_NODICTIONARY and so on.
    DWORD dwStrLen;  // Error Strings, if this is 0, there is no error string.
DWORD  dwStrOffset;
DWORD  dwPrivateSize;
DWORD  dwPrivateOffset;
} GUIDELINE;

Note For Unicode, the dwStrLen member specifies the size in Unicode characters of the error string. Other size parameters such as dwSize dwStrOffset, dwPrivateSize contain values counted in bytes.

Members

dwLevel
The dwLevel specifies error level. The following values are provided.
Value | Description
GL_LEVEL_NOGUIDELINE | No guideline present. If the old guideline is shown, the UI should hide the old guideline.
GL_LEVEL_FATAL | Fatal error has occurred. Some data may be lost.
GL_LEVEL _ERROR | Error has occurred. Handling may not be continued.
GL_LEVEL _WARNING | IME warning to user. Something unexpected has occurred, but the IME can continue handling.
GL_LEVEL _INFORMATION | Information for the user.

dwIndex
The following values are provided.
Value | Description
GL_ID_UNKNOWN | Unknown error. The application should refer to the error string.
GL_ID_NOMODULE | IME cannot find the module that the IME needs.
GL_ID_NODICTIONARY | IME cannot find the dictionary or the dictionary looks strange.
GL_ID_CANNOTSAVE | Dictionary or the statistical data cannot be saved.
GL_ID_NOCONVERT | IME cannot convert anymore.
GL_ID_TYPINGERROR | Typing error. The IME cannot handle this typing.
GL_ID_TOOMANYSTROKE | Two many keystrokes for one character or one clause.
GL_ID_READINGCONFLICT | Reading conflict has occurred. For example, some vowels cannot be combined.
GL_ID_INPUTREADING | IME prompts the user now it is in inputting reading character state.
GL_ID_INPUTRADICAL | IME prompts the user now it is in inputting radical character state.
GL_ID_INPUTCODE | IME prompts the user to input the character code state.
GL_ID_CHOOSECANIDATE | IME prompts the user to select the candidate string state.
GL_ID_REVERSECONVERSION | IME prompts the user to provide the information of the reverse conversion. The information of reverse conversion can be obtained through ImmGetGuideLine(hIMC, GGL_PRIVATE. lpBuf, dwBufLen).The information contained in lpBuf is in CANDIDATELIST format.
GL_ID_PRIVATE_FIRST | ID located between GL_ID_PRIVATE_FIRST and GL_ID_PRIVATE_LAST is reserved for the IME. The IME can freely use these IDs for its own GUIDELINE.
GL_ID_PRIVATE_LAST | ID located between GL_ID_PRIVATE_FIRST and GL_ID_PRIVATE_LAST is reserved for the IME. The IME can freely use these IDs for its own GUIDELINE.

dwPrivateSize
Private area in this memory block.
dwPrivateOffset
Offset from the start position of this structure. The private area is stored here.

IME Management Structures

The following topics describe the structures used to manage IMEs.

IMEINFO

The IMEINFO structure is used internally by IMM and IME interfaces.

typedef struct tagIMEInfo {
    DWORD  dwPrivateDataSize;  // The byte count of private data in an IME context.
    DWORD  fdwProperty;  // The IME property bits. See description below.
    DWORD  fdwConversionCaps;  // The IME conversion mode capability bits.
    DWORD  fdwSentenceCaps;  // The IME sentence mode capability.
    DWORD  fdwUICaps;  // The IME UI capability.
    DWORD  fdwSCSCaps;  // The ImeSetCompositionString capability.
    DWORD  fdwSelectCaps;  // The IME inherit IMC capability.
} IIMEINFO;

Members

dwPrivateDataSize
Byte count of the structure.
fdwProperty
HIWORD of fdwProperty contains the following bits, which are used by the application.
Bit | Description
IME_PROP_AT_CARET | Bit On indicates that the IME conversion window is at caret position. Bit Off indicates a near caret position operation IME.
IME_PROP_SPECIAL_UI | Bit On indicates that the IME has a special UI. The IME should set this bit only when it has an nonstandard UI that an application cannot display. Typically, an IME will not set this flag.
IME_PROP_CANDLIST_START_FROM_1 | Bit ON indicates that the UI of the candidate list string starts from zero or 1. An application can draw the candidate list string by adding the 1, 2, 3, and so on in front of the candidate string.
IME_PROP_UNICODE | If set, the IME is viewed as Unicode IME. System and IME will communicate through Unicode IME interface. If clear, IME will use ANSI interface to communicate with system.
IME_PROP_COMPLETE_ON_
UNSELECT 		New property bit defined for Windows 98 and Windows 2000. If set, the IME will complete the composition string when the IME is deactivated. If clear, the IME will cancel the composition string when the IME is deactivated (such as from a keyboard layout change).

The LOWORD of fdwProperty contains the following bits, which are used by the system.
Bit | Description
IME_PROP_END_UNLOAD | Bit On indicates that the IME will unload when there is no one using it.
IME_PROP_KBD_CHAR_FIRST | Before the IME translates the DBCS character, the system first translates the characters by keyboard. This character is passed to the IME as an information aid. No aid information is provided when this bit is off.
IME_PROP_NEED_ALTKEY | IME needs the ALT key passed to ImeProcessKey.
IME_PROP_IGNORE_UPKEYS | IME does not need the UP key passed to ImeProcessKey.
IME_PROP_ACCEPT_WIDE_VKEY | Windows 2000: If set, the IME processes the injected Unicode that came from the SendInput function by using VK_PACKET. If clear, IME might not process the injected Unicode and the injected Unicode might be sent to application directly.

fdwConversionCaps
Same definition as the conversion mode. If the relative bit is off, the IME does not have the capability to handle the conversion mode no matter whether the corresponding bit of the conversion mode is on or off.
Conversion mode | Description
IME_CMODE_KATAKANA | Bit On indicates that the IME supports KATAKANA mode. Otherwise, it does not.
IME_CMODE_NATIVE | Bit On indicates that the IME supports NATIVE mode. Otherwise, it does not.
IME_CMODE_FULLSHAPE | Bit On indicates that the IME supports full shape mode. Otherwise, it does not.
IME_CMODE_ROMAN | Bit On indicates that the IME supports ROMAN input mode. Otherwise, it does not.
IME_CMODE_CHARCODE | Bit On indicates that the IME supports CODE input mode. Otherwise, it does not.
IME_CMODE_HANJACONVERT | Bit On indicates that the IME supports HANJA convert mode. Otherwise, it does not.
IME_CMODE_SOFTKBD | Bit On indicates that the IME supports soft keyboard mode. Otherwise, it does not.
IME_CMODE_NOCONVERSION | Bit On indicates that the IME supports No-conversion mode. Otherwise, it does not.
IME_CMODE_EUDC | Bit On indicates that the IME the IME supports EUDC mode. Otherwise, it does not.
IME_CMODE_SYMBOL | Bit On indicates that the IME supports SYMBOL mode. Otherwise, it does not.
IME_CMODE_CHARCODE | Set to 1 if the IME supports character code input mode, but zero if it does not.
IME_CMODE_FIXED | Set to 1 if the IME supports fixed conversion mode, but zero if not. This mode allows preconversion by the IME, but not full conversion. An example of this is Fixed Conversion Mode with DBCS HIRAGANA ROMAN. Under this mode, the IME can convert key input characters to DBCS HIRAGANA by Roman Conversion. However, it prevents conversion from DBCS HIRAGANA to Kanji characters.

fdwSentenceCaps
Same constant definition as the sentence mode. If the relative bit is off, the IME does not have the capability to handle the sentence mode no matter if the corresponding bit of sentence mode is on or off.
Conversion mode | Description
IME_SMODE_PLAURALCLAUSE | Bit On indicates that the IME supports plural clause sentence mode.
IME_SMODE_SINGLECONVERT | Bit On indicates that the IME supports single character sentence mode.
IME_SMODE_AUTOMETIC | Bit On indicates that the IME supports automatic sentence mode.
IME_SMODE_PHRASEPREDICT | Bit On indicates that the IME supports phrase predict sentence mode.
IME_SMODE_CONVERSATION | IME uses conversation mode. This is useful for chat applications. Chat applications can change the sentence mode of the IME to conversation style. This is a new mode for Windows 98 and Windows 2000.

fdwUICaps
The fdwUICaps bits specify the UI ability of the IME. The following bits are provided.
Bit | Description
UI_CAP_2700 | UI supported when LogFont escape is zero or 2700.
UI_CAP_ROT90 | UI supported when LogFont escape is zero, 900, 1800, or 2700.
UI_CAP_ROTANY | UI supported with any escape.
UI_CAP_SOFKBD | IME uses soft keyboard provided by the system.

fdwSCSCaps
The fdwSCSCaps bits specify the SetCompositionString capability that the IME has. The following bits are provided.
Bit | Description
SCS_CAP_COMPSTR | IME can generate the composition string by SCS_SETSTR.
SCS_CAP_MAKEREAD | When calling ImmSetCompositionString with SCS_SETSTR, the IME can create the reading of the composition string without lpRead. Under the IME that has this capability, the application does not need to set lpRead for SCS_SETSTR.

fdwSelectCaps
The fdwSelectCaps capability is for the application. When a user changes the IME, the application can determine if the conversion mode will be inherited or not by checking this capability. If the newly selected IME does not have this capability, the application will not receive the new mode and will have to retrieve the mode again. The following bits are provided.
Bit | Description
SELECT_CAP_CONVMODE | IME has the capability of inheritance of conversion mode at ImeSelect.
SELECT_CAP_SENTENCE | IME has the capability of inheritance of sentence mode at ImeSelect.

Structures Used for IME Communication

The following topics describe the structures used for communication with IMEs.

CANDIDATELIST

The CANDIDATELIST structure contains information about a candidate list.

typedef struct tagCANDIDATELIST {
    DWORD  dwSize;  // the size of this data structure.
    DWORD  dwStyle;  // the style of candidate strings.
    DWORD  dwCount;  // the number of the candidate strings.
    DWORD  dwSelection;  // index of a candidate string now selected.
    DWORD  dwPageStart;  // index of the first candidate string show in the candidate window. It maybe varies with page up or page down key.
    DWORD  dwPageSize;  // the preference number of the candidate strings shows in one page.
    DWORD  dwOffset[];  // the start positions of the first candidate strings. Start positions of other (2nd, 3rd, ..) candidate strings are appened after this field. IME can do this by reallocating the hCandInfo memory handle. So IME can access dwOffset[2] (3rd candidate string) or dwOffset[5] (6st candidate string).
// TCHAR  chCandidateStr[];  // the array of the candidate strings.
} CANDIDATELIST;

Members

dwsize
Size, in bytes, of the structure, the offset array, and all candidate strings.
dwStyle
Candidate style values. It can be one or more of the following values.
Value | Meaning
IME_CAND_UNKNOWN | Candidates are in a style other than listed here.
IME_CAND_READ | Candidates have the same reading.
IME_CAND_CODE | Candidates are in one code range.
IME_CAND_MEANING | Candidates have the same meaning.
IME_CAND_RADICAL | Candidates are composed of same radical character.
IME_CAND_STROKES | Candidates are composed of same number of strokes.

For the IME_CAND_CODE style, the candidate list has a special structure depending on the value of the dwCount member. If dwCount is 1, the dwOffset member contains a single DBCS character rather than an offset, and no candidate string is provided. If the dwCount member is greater than 1, the dwOffset member contains valid offsets, and the candidate strings are text representations of individual DBCS character values in hexadecimal notation.

dwCount
Number of candidate strings.
dwSelection
Index of the selected candidate string.
dwPageStart
Index of the first candidate string in the candidate window. This varies as the user presses the Page Up and Page Down keys.
dwPageSize
Number of candidate strings to be shown in one page in the candidate window. The user can move to the next page by pressing IME-defined keys, such as the Page Up or Page Down key. If this number is zero, an application can define a proper value by itself.
dwOffset
Offset to the start of the first candidate string, relative to the start of this structure. The offsets for subsequent strings immediately follow this member, forming an array of 32-bit offsets.

Comments

The CANDIDATELIST structure is used for the return of ImmGetCandidateList . The candidate strings immediately follow the last offset in the dwOffset array.

COMPOSITIONFORM

The COMPOSITIONFORM structure is used for IMC_SETCOMPOSITIONWINDOW and IMC_SETCANDIDATEPOS messages.

typedef tagCOMPOSITIONFORM {
DWORD  dwStyle;
POINT  ptCurrentPos;
RECT  rcArea;
}COMPOSITIONFORM;

Members

dwStyle
Position style. The following values are provided.
Value | Meaning
CFS_DEFAULT | Move the composition window to the default position. The IME window can display the composition window outside the client area, such as in a floating window.
CFS_FORCE_POSITION | Display the upper-left corner of the composition window at exactly the position given by ptCurrentPos. The coordinates are relative to the upper-left corner of the window containing the composition window and are not subject to adjustment by the IME.
CFS_POINT | Display the upper-left corner of the composition window at the position given by ptCurrentPos. The coordinates are relative to the upper-left corner of the window containing the composition window and are subject to adjustment by the IME.
CFS_RECT | Display the composition window at the position given by rcArea. The coordinates are relative to the upper-left of the window containing the composition window.

ptCurrentPos
Coordinates of the upper-left corner of the composition window.
rcArea
Coordinates of the upper-left and lower-right corners of the composition window.

Comments

When the style of the COMPOSITIONFORM structure is CFS_POINT or CFS_FORCE_POINT, the IME will draw the composition string from the position specified by ptCurrentPos of the COMPOSITIONFORM structure that is given by the application. If the style has CFS_RECT, the composition string will be inside the rectangle specified by rcArea. If not, rcArea will be the client rectangle of the application window.

When the application specifies the composition font, the composition window is rotated as the escapement of the composition font. The direction of the composition string follows the escapement of the font in a composition window. The IME then draws the composition string. Following is an example of this process using various values for the escapement of the composition font:

  • Escapement of the composition font is zero

    Typically, the escapement of the composition font is zero. When this is the case, ptCurrentPos of the composition form structure points to the left and top of the string. All IMEs support this type.

  • Escapement of the composition font is 2700

    This is in the case of a vertical writing. When the application provides the vertical writing, the application can set the 2700 escapement in the composition font set by ImmCompositoinFont. The composition string will then be drawn downward. IMEs that have UI_CAP_2700, UI_CAP_ROT90, or UI_CAP_ROTANY capability will support this type of composition window.

  • Escapement of the composition font is 900 or 1800

    IMEs that have UI_CAP_ROT90 or UI_CAP_ROTANY capability will support this type of composition window.

  • Escapement of the composition font is any value

    IMEs that have UI_CAP_ROTANY capability will support this type of composition window.

Note UI_CAP_ROT90 and UI_CAPS_ANY are the option for the enhancement of the IME. UI_CAP_2700 is recommended.

CANDIDATEFORM

The CANDIDATEFORM structure is used for IMC_GETCANDIDATEPOS and IMC_SETCANDIDATEPOS messages.

typedef tagCANDIDATEFORM {
DWORD  dwIndex;
DWORD  dwStyle;
POINT  ptCurrentPos;
REC  rcArea;
} CANDIDATEFORM;

Members

dwIndex
Specifies the ID of the candidate list. Zero is the first candidate list, 1 is the second one, and so on up to 3.
dwStyle
Specifies CFS_CANDIDATEPOS or CFS_EXCLUDE. For a near-caret IME, the dwStyle also can be CFS_DEFAULT. A near-caret IME will adjust the candidate position according to other UI components, if the dwStyle is CFS_DEFAULT.
ptCurrentPos
Depends on dwStyle. When dwStyle is CFS_CANDIDATEPOS, ptCurrentPos specifies the recommended position where the candidate list window should be displayed. When dwStyle is CFS_EXCLUDE, ptCurrentPos specifies the current position of the point of interest (typically the caret position).
rcArea
Specifies a rectangle where no display is allowed for candidate windows in the case of CFS_EXCLUDE.

STYLEBUF

The STYLEBUF structure contains the identifier and name of a style.

typedef struct tagSTYLEBUF {
DWORD  dwStyle;
TCHAR  szDescription[32]
} STYLEBUF;

Members

dwStyle
Style of register word.
szDescription
Description string of this style.

Note The style of the register string includes IME_REGWORD_STYLE_EUDC. The string is in EUDC range:

IME_REGWORD_STYLE_USER_FIRST and IME_REGWORD_STYLE_USER_LAST.

The constants range from IME_REGWORD_STYLE_USER_FIRST to IME_REGWORD_STYLE_USER_LAST and are for private IME ISV styles. The IME ISV can freely define its own style.

SOFTKBDDATA

The SOFTKBDDATA defines the DBCS codes for each virtual key.

typedef struct tagSOFTKBDDATA {
UINT  uCount;
WORD  wCode[][256]
} SOFTKBDDATA;

Members

uCount
Number of the 256-word virtual key mapping to the internal code array.
wCode[][256]
256-word virtual key mapping to the internal code array. There may be more than one 256-word arrays.

Note It is possible for one type of soft keyboard to use two 256-word arrays. One is for the nonshift state and the other is for the shift state. The soft keyboard can use two internal codes for displaying one virtual key.

RECONVERTSTRING

The RECONVERTSTRING structure defines the strings for IME reconversion. It is the first item in a memory block that contains the strings for reconversion.

typedef struct _tagRECONVERTSTRING {
DWOPD  dwSize;
DWORD  dwVersion;
DWORD  dwStrLen;
DWORD  dwStrOffset;
DWORD  dwCompStrLen;
DWORD  dwCompStrOffset;
DWORD  dwTargetStrLen;
DWORD  dwTargetStrOffset;
} RECONVERTSTRING;

Members

dwSize
Memory block size of this structure.
dwVersion
Reserved by the system. This must be zero.
dwStrlen
Length of the string that contains the composition string.
dwStrOffset
Offset from the start position of this structure. The string containing the reconverted words is stored at this point.
dwCompStrLen
Length of the string that will be the composition string.
dwCompStrOffset
Offset of the string that will be the composition string.
dwTargetStrLen
Length of the string that is related to the target clause in the composition string.
dwTargetStrOffset
Offset of the string that is related to the target clause in the composition string.

Note The RECONVERTSTRING structure is a new structure for Windows 98 and Windows 2000. The dwCompStrOffset and dwTargetOffset members are the relative position of dwStrOffset. For Windows NT Unicode, dwStrLen, dwCompStrLen, and dwTargetStrLen are the TCHAR count, and dwStrOffset, dwCompStrOffset, and dwTargetStrOffset are the byte offset.

Comments

If an application starts the reconversion process by calling ImmSetCompositionString with SCS_SETRECONVERTSTRING and SCS_QUERYRECONVERTSTRING, the application is then responsible for allocating the necessary memory for this structure as well as the composition string buffer. The IME should not use the memory later. If the IME starts the process, it should allocate the necessary memory for the structure and the composition string buffer.

IMEMENUITEMINFO

The IMEMENUITEMINFO structure contains information about IME menu items.

typedef _tagIMEMENUITEMINFO {
UINT  cbSize;
UINT  fType;
UINT  fState;
UINT  wID;
HBITMAP  hbmpChecked;
HBITMAP  hbmpUnchecked;
DWORD  dwItemData;
TCHAR  szString[48];
HBITMAP  hbmpItem;
} IMEMENUITEMINFO;

Members

cbSize
Size of the structure in bytes
fType
Menu item type. This member can be one or more of the following values.
Value | Meaning
IMFT_RADIOCHECK | Displays checked menu items using a radio-button mark instead of a check mark if the hbmpChecked member is NULL.
IMFT_SEPARATOR | Specifies that the menu item is a separator. A menu item separator appears as a horizontal dividing line. The hbmpItem and szString members are ignored.
IMFT_SUBMENU | Specifies that the menu item is a submenu.

fState
Menu item state. This member can be one or more of the following values.
Value | Meaning
IMFS_CHECKED | Checks the menu item. For more information about checked menu items. See the hbmpChecked member.
IMFS_DEFAULT | Specifies that the menu item is the default. A menu can contain only one default menu item, which is displayed in bold.
IMFS_DISABLED | Disables the menu item so it cannot be selected, but does not gray it out.
IMFS_ENABLED | Enables the menu item so it can be selected. This is the default state.
IMFS_GRAYED | Disables the menu item and grays it out so it cannot be selected.
IMFS_HILITE | Highlights the menu item.
IMFS_UNCHECKED | Unchecks the menu item. For more information about unchecked menu items, see the hbmpUnchecked member.
IMFS_UNHILITE | Removes the highlight from the menu item. This is the default state.

wID
Application-defined 16-bit value that identifies the menu item.
hbmpChecked
Handle to the bitmap to display next to the item if it is checked. If this member is NULL, a default bitmap is used. If the IMFT_RADIOCHECK type value is specified, the default bitmap is a bullet. Otherwise, it is a check mark.
hbmpUnchecked
Handle to the bitmap to display next to the item if it is not checked. If this member is NULL, no bitmap is used.
dwItemData
Application-defined value associated with the menu item.
szString
Content of the menu item. This member is a null-terminated string.
hbmpItem
Bitmap handle to display.

Note The IMEMENUITEMINFO structure is a new structure for Windows 98 and Windows 2000. The Unicode version of this structure has the szString member as the WCHAR.

TRANSMSG

The TRANSMSG structure contains transferred message, used by ImeToAsciiEx to receive IME generated message.

typedef _tagTRANSMSG {
UINT  message;
WPARAM  wParam;
LPARAM  lParam;
} TRANSMSG;

Members

message
Specify message identify
wParam
Specify additional information about the message. The exact meaning depends on the value of the message member.
lParam
Specify additional information about the message. The exact meaning depends on the value of the message member.

Note This structure is added for future 64-bit Windows NT platform. This structure will be used together with TRANSMSGLIST by ImeToAsciiEx to replace the formerly used LPDWORD lpdwTransBuf. Using this structure will still keep the data in memory with the same offset and keep backward compatible.

TRANSMSGLIST

The TRANSMSGLIST structure contains transferred message list returned from ImeToAsciiEx.

typedef _tagTRANSMSGLIST {
UINT  uMsgCount;
TRANSMSG  TransMsg[1];
} TRANSMSGLIST;

Members

uMsgCount
Specify the message number in TransMsg array.
TransMsg
Includes TRANSMSG data array.

Note This structure is added for future 64-bit Windows NT platform. This structure will be used by ImeToAsciiEx to replace the formerly used LPDWORD lpdwTransBuf. Using this structure will still keep the data in memory with the same offset and keep backward compatible.


Win32 Multilingual IME Application Programming Interface

This documentation contains the application programming interface reference for Input Method Editor (IME)development. The following functions are intended to be used by the IME.

IMM UI Functions

Following are the Input Method Manager (IMM) functions that can be accessed from the UI window. They are also used by applications to change IME status.

ImmGetCompositionWindow

ImmSetCompositionWindow

ImmGetCandidateWindow

ImmSetCandidateWindow

ImmGetCompositionString

ImmSetCompositionString

ImmGetCompositionFont

ImmSetCompositionFont

ImmGetNumCandidateList

ImmGetCandidateList

ImmGetGuideLine

ImmGetConversionStatus

ImmGetConversionList

ImmGetOpenStatus

ImmSetConversionStatus

ImmSetOpenStatus

ImmNotifyIME

ImmCreateSoftKeyboard

ImmDestroySoftkeyboard

ImmShowSoftKeyboard

Please refer to the Input Method Editor (IME) functions in the Platform SDK for information about these functions.

IMM Support Functions

The following topics contain IMM functions that support and are used by the IME.

ImmGenerateMessage

The IME uses the ImmGenerateMessage function to send messages to the hWnd of hIMC. The messages to be sent are stored in hMsgBuf of hIMC.

BOOL WINAPI
  ImmGenerateMessage(
    HIMC  hIMC
    )

Parameters

hIMC
Input context handle containing hMsgBuf.

Return Values

If the function is successful, the return value is TRUE. Otherwise, the return value is FALSE.

Comments

This is a general purpose function. Typically, an IME uses this function when it is notified about the context update through ImmNotifyIME from IMM. In this case, even if IME needs to provide messages to an application, there is no keystroke in the application's message queue.

An IME User Interface should not use this function when it only wants to update the UI appearance. The IME User Interface should have been updated when the IME is informed about the updated Input Context. It is recommended that you use this function from the IME only when the IME changes the Input Context without any keystroke given and needs to inform an application of the change.

ImmRequestMessage

The ImmRequestMessage function is used to send a WM_IME_REQUEST message to the application.

LRESULT WINAPI
  ImmRequestMessage(
    HIMC  hIMC,
    WPARAM  wParam,
    LPARAM  lParam
    )

Parameters

hIMC
Target input context handle.
wParam
wParam for the WM_IME_REQUEST message.
lParam
lParam for the WM_IME_REQUEST message.

Return Values

The return value is the return value of the WM_IME_REQUEST message.

Comments

This function is new for Windows® 98 and Window 2000, and is used by the IME to send a WM_IME_REQUEST message to the application. The IME may want to obtain some guidelines from the application in defining the position of the candidate or composition window. But in an IME fully aware (true in-line) application, the application usually does not set the composition window position. When the IME makes a request to the application, it receives the WM_IME_REQUEST message. The IME should make a request to the application by calling the ImmRequestMessage function and not by calling SendMessage

The following is a list of submessages that the IME can send to applications through the ImmRequestMessage function:

IMR_COMPOSITIONWINOW

IMR_CANDIDATEWINDOW

IMR_COMPOSITIONFONT

IMR_RECONVERTSTRING

IMR_CONFIRMRECONVERTSTRING

IMR_QUERYCHARPOSITION

IMR_DOCUMENTFEED

Please refer to the Input Method Editor (IME) functions in the Platform SDK for information about these messages.

HIMC and HIMCC Management Functions

The following topics contain the HIMC and HIMCC management functions.

ImmLockIMC

The ImmLockIMC function increases the lock count for the IMC. When the IME needs to see the INPUTCONTEXT structure, it calls this function to get the pointer of the INPUTCONTEXT structure.

LPINPUTCONTEXT WINAPI
  ImmLockIMC(
    HIMC  hIMC
    )

Parameters

hIMC
Input context handle.

Return Values

If the function is successful, it returns a pointer to the INPUTCONTEXT structure. Otherwise, it returns NULL.

ImmUnlockIMC

The ImmUnlockIMC function decrements the lock count for the IMC.

BOOL WINAPI
  ImmUnlockIMC(
    HIMC  hIMC
    )

Parameters

hIMC
Input context handle.

Return Values

If the lock count of the IMC is decremeted to zero, the return value is FALSE. Otherwise, the return value is TRUE.

ImmGetIMCLockCount

The ImmGetIMCLockCount is used to get the lock count of the IMC.

HIMCC WINAPI
  ImmGetIMCLockCount(
    HIMC  hIMC
    )

Parameters

hIMC
Input context handle

Return Values

If the function is successful, the return value is the lock count of the IMC. Otherwise, the return value is NULL.

ImmCreateIMCC

The ImmCreateIMCC function creates a new component as a member of the IMC.

HIMCC WINAPI
  ImmCreateIMCC(
    DWORD  dwSize
    )

Parameters

dwSize
Size of the new IMC component.

Return Values

If the function is successful, the return value is the IMC component handle (HIMCC). Otherwise, the return value is NULL.

Comments

The IMC component created by this function is initialized as zero.

ImmDestroyIMCC

The ImmDestroyIMCC function is used by the IME to destroy the IMC component that was created as a member of the IMC.

HIMCC WINAPI
  ImmDestroyIMCC(
    HIMCC  hIMCC
    )

Parameters

hIMCC
Handle of the IMC component.

Return Values

If the function is successful, the return value is NULL. Otherwise, the return value is equal to the HIMCC.

ImmLockIMCC

The ImmLockIMCC function is used by the IME to get the pointer for the IMC component that was created as a member of the IMC. The ImmLockIMC function increases the lock count for the IMCC.

LPVOID WINAPI
  ImmLockIMCC(
    HIMCC  hIMCC
    )

Parameters

hIMCC
Handle of the IMC component.

Return Values

If the function is successful, the return value is the pointer for the IMC component. Otherwise, the return value is NULL.

ImmUnlockIMCC

The ImmUnlockIMC function decrements the lock count for the IMCC.

BOOL WINAPI
  ImmUnlockIMCC(
    HIMCC  hIMCC
    )

Parameters

hIMCC
Handle of the IMC component.

Return Values

If the lock count of the IMCC is decremeted to zero, the return value is FALSE. Otherwise, the return value is TRUE.

ImmReSizeIMCC

The ImmReSizeIMCC function changes the size of the component.

HIMCC WINAPI
  ImmReSizeIMCC(
    HIMCC  hIMCC,
    DWORD  dwSize
    )

Parameters

hIMCC
Handle of the IMC component.
dwSize
New size of the IMC component.

Return Values

If the function is successful, the return value is the new HIMCC. Otherwise, the return value is NULL.

ImmGetIMCCSize

The ImmGetIMCCLockCount function is used to get the size of the IMCC.

DWORD WINAPI
  ImmGetIMCCSize(
    HIMCC  hIMCC
    )

Parameters

hIMCC
Handle of the IMC component.

Return Values

Size of the IMCC.

ImmGetIMCCLockCount

The ImmGetIMCCLockCount function is used to get the lock count of the IMCC.

DWORD WINAPI
  ImmGetIMCCLockCount(
    HIMCC  hIMCC
    )

Parameters

hIMCC
Handle of the IMC component.

Return Values

If the function is successful, the return value is the lock count of the IMCC. Otherwise, the return value is zero.

IME Hot Keys and Hot Key Functions

The IME hot key is used for changing the IME input mode and for switching the IME. The IME hot key used to switch directly to an IME is called a direct switching hot key.

The direct switching hot key ranges from IME_HOTKEY_DSWITCH_FIRST to IME_HOTKEY_DSWITCH_LAST. It is registered by an IME or Control Panel when the IME or an end user wants such a hot key. The IME hot key is effective in all IMEs, regardless which IME is active.

There are several predefined hot key functionalities in the IMM. The IMM itself provides the functionality (different handling routines) of those hot key functions. Every hot key funtionality has a different hot key ID in IMM and each ID has its own functionality according to the specific requirements of each country/region. Note that an application cannot add another predefined hot key ID into the system.

Following are the predefined hot key identifiers.

Hot Key ID | Description
IME_CHOTKEY_IME_NONIME_TOGGLE | Hot key for Simplified Chinese Edition. This hot key toggles between the IME and non-IME.
IME_CHOTKEY_SHAPE_TOGGLE | Hot key for Simplified Chinese Edition. This hot key toggles the shape conversion mode of the IME.
IME_CHOTKEY_SYMBOL_TOGGLE | Hot key for Simplified Chinese Edition. This hot key toggles the symbol conversion mode of the IME. The symbol mode indicates that the user can input Chinese punctuation and symbols (full shape characters) by mapping it to the punctuation and symbol keystrokes of the keyboard.
IME_JHOTKEY_CLOSE_OPEN | Hot key for Japanese Edition. This hot key toggles between closed and opened.
IME_THOTKEY_IME_NONIME_TOGGLE | Hot key for (Traditional) Chinese Edition. This hot key toggles between the IME and non-IME.
IME_THOTKEY_SHAPE_TOGGLE | Hot key for (Traditional) Chinese Edition. This hot key toggles the shape conversion mode of the IME.
IME_THOTKEY_SYMBOL_TOGGLE | Hot key for (Traditional) Chinese Edition. This hot key toggles the symbol conversion mode of the IME.

The other kind of hot key is the IME private hot key, but there is no functionality for this kind of hot key. It is just a placeholder for a hot key value. An IME can get this value by calling ImmGetHotKey. If an IME supports this functionality for one hot key ID, it will perform the functionality every time it finds this key input.

Following are the currently defined private IME hot key IDs.

Hot Key ID | Description
IME_ITHOTKEY_RESEND_RESULSTR | Hot key for (Traditional) Chinese Edition. This hot key should trigger the IME to resend the previous result string to the application. If the IME detects that this hot key is pressed, it needs to resend the previous result string to this application.
IME_ITHOTKEY_PREVIOUS_COMPOSITION | Hot key for (Traditional) Chinese Edition. This hot key should trigger the IME to bring up the previous composition string to the application.
IME_ITHOTKEY_UISTYLE_TOGGLE | Hot key for (Traditional) Chinese Edition. This hot key should trigger the IME UI to toggle the UI style between caret-related UI and the caret-unrelated UI.
IME_ITHOTKEY_RECONVERTSTRING | Hot key for (Traditional) Chinese Edition. This hot key should trigger the IME to make a reconversion. This is a new ID for Windows 98 and Windows 2000.

ImmGetHotKey

The ImmGetHotKey function gets the value of the IME hot key.

BOOL WINAPI
  ImmGetHotKey(
    DWORD  dwHotKeyID,
    LPUINT  lpuModifiers,
    LPUINT  lpuVKey,
    LPHKL  lphKL
    )

Parameters

dwHotKeyID
Hot key identifier.
lpuModifiers
Combination keys with the hot key. It includes ALT (MOD_ALT), CTRL (MOD_CONTROL), SHIFT (MOD_SHIFT), left-hand side (MOD_LEFT), and right-hand side (MOD_RIGHT).

The key up flag (MOD_ON_KEYUP) indicates that the hot key is effective when the key is up. The modifier ignore flag (MOD_IGNORE_ALL_MODIFIER) indicates that the combination of modifiers is ignored in hot key matching.

lpuVKey
Virtual key code of this hot key.
lphKL
HKL of the IME. If the return value of this parameter is not NULL, this hot key can switch to the IME with this HKL.

Return Values

If the function is successful, the return value is TRUE. Otherwise, the return value is FALSE.

Comments

This function is called by the Control Panel.

ImmSetHotKey

The ImmSetHotKey function sets the value of the IME hot key.

OOL WINAPI
  ImmSetHotKey(
    DWORD  dwHotKeyID,
    UINT  uModifiers,
    UINT  uVKey,
    hKL  hKL
    )

Parameters

dwHotKeyID
Hot key identifier.
uModifiers
Combination keys with the hot key. It includes ALT (MOD_ALT), CTRL (MOD_CONTROL), SHIFT (MOD_SHIFT), left-hand side (MOD_LEFT), and right-hand side (MOD_RIGHT).

The key up flag (MOD_ON_KEYUP) indicates that the hot key is effective when the key is up. The modifier ignore flag (MOD_IGNORE_ALL_MODIFIER) indicates that the combination of modifiers is ignored in hot key matching.

uVKey
Virtual key code of this hot key.
hKL
HKL of the IME. If this parameter is specified, this hot key can switch to the IME with this HKL.

Return Values

If the function is successful, the return value is TRUE. Otherwise, the return value is FALSE.

Comments

This function is called by the Control Panel. For a key that does not indicate a specific keyboard hand side, the uModifiers should specify both sides (MOD_LEFT|MODE_RIGHT).

IMM Soft Keyboard Functions

The following topics contain the IMM functions that are used by the IME to manipulate the soft keyboard.

ImmCreateSoftKeyboard

The ImmCreateSoftKeyboard function creates one type of soft keyboard window.

HWND WINAPI
  ImmCreateSoftKeyboard(
    UINT  uType,
    UINT  hOwner,
    int  x,
    int  y
    )

Parameters

uType
Specifies the type of the soft keyboard.
Utype | Description
SOFTKEYBOARD_TYPE_T1 | Type T1 soft keyboard. This kind of soft keyboard should be updated by IMC_SETSOFTKBDDATA.
SOFTKEYBOARD_TYPE_C1 | Type C1 soft keyboard. This kind of soft keyboard should be updated by IMC_SETSOFTKBDDATA with two sets of 256-word array data. The first set is for nonshift state, and the second is for shift state.

hOwner
Specifies the owner of the soft keyboard. It must be the UI window.
x
Specifies the initial horizontal position of the soft keyboard.
y
Specifies the initial vertical position of the soft keyboard.

Return Values

This function returns the window handle of the soft keyboard.

ImmDestroySoftKeyboard

The ImmDestroySoftKeyboard function destroys the soft keyboard window.

BOOL WINAPI
  ImmDestroySoftKeyboard(
    HWND  hSoftKbdWnd
    )

Parameters

hSoftKbdWnd
Window handle of the soft keyboard to destroy.

Return Values

If the function is successful, the return value is TRUE. Otherwise, the return value is FALSE.

ImmShowSoftKeyboard

The ImmShowSoftKeyboard function shows or hides the given soft keyboard.

BOOL WINAPI
  ImmShowSoftKeyboard(
    HWND  hSoftKbdWnd,
    int  nCmdShow
    )

Parameters

hSoftKbdWnd
Window handle of the soft keyboard.
nCmdShow
Shows the state of the window. The following values are provided.
NcmdShow | Meaning
SW_HIDE | Hides the soft keyboard.
SW_SHOWNOACTIVATE | Displays the soft keyboard

Return Values

If the function is successful, the return value is TRUE. Otherwise, the return value is FALSE.

Messages

The following topics contain the messages that the UI window receives.

WM_IME_SETCONTEXT

The WM_IME_SETCONTEXT message is sent to an application when a window of the application is being activated. If the application does not have an application IME window, the application has to pass this message to the DefWindowProc and should return the return value of the DefWindowProc. If the application has an application IME window, the application should call ImmIsUIMessage.

WM_IME_SETCONTEXT
wParam (BOOL) = fSet;
lParam = lISCBits;

Parameters

fSet
fSet is TRUE when the Input Context becomes active for the application. When it is FALSE, the Input Context becomes inactive for the application.
lISCBits
lISCBits consists of the following bit combinations.
Value | Description
ISC_SHOWUICOMPOSITIONWINDOW | Shows the composition window.
ISC_SHOWUIGUIDWINDOW | Shows the guide window.
ISC_SHOWUICANDIDATEWINDOW | Shows the candidate window of Index 0.
(ISC_SHOWUICANDIDATEWINDOW << 1) | Shows the candidate window of Index 1.
(ISC_SHOWUICANDIDATEWINDOW << 2) | Shows the candidate window of Index 2.
(ISC_SHOWUICANDIDATEWINDOW << 3) | Shows the candidate window of Index 3.

Return Values

The return value is the return value of DefWindowProc or ImmIsUIMessage.

Comments

After an application calls DefWindowProc( or ImmIsUIMessage with WM_IME_SETCONTEXT, the UI window receives WM_IME_SETCONTEXT. If the bit is on, the UI window shows the composition, guide, or candidate window as the bit status of lParam.

If an application draws the composition window by itself, the UI window does not need to show its composition window. The application then has to clear the ISC_SHOWUICOMPOSITIONWINDOW bit of lParam and call DefWindowProc or ImmIsUIMessage with it.

WM_IME_CONTROL

The WM_IME_CONTROL message is a group of sub messages used to control the IME User Interface. An application uses this message to interact with the IME window created by the application.

WM_IME_CONTROL
wParam = wSubMessage ;
lParam(LPVOID) = lpData;

Parameters

wSubMessage
Submessage value.
LpData
Dependent on each wSubMessage.

The following topics contain the submessages classified by the wSubMessage value.

Except for IMC_GETSOFTKBDSUBTYPE, IMC_SETSOFTKBDSUBTYPE, IMC_SETSOFTKBDDATA, IMC_GETSOFTKBDFONT, IMC_SETSOFTKBDFONT, IMC_GETSOFTKBDPOS and IMC_SETSOFTKBDPOS, it is recommended that applications use IMM APIs instead of the IMC messages to communicate with the IME window.

IMC_GETCANDIDATEPOS

The IMC_GETCANDIDATEPOS message is sent by an application to the IME window to get the position of the candidate window. The IME can adjust the position of a candidate window in respect to the screen boundary. In addition, an application can obtain the real position of a candidate window to determine whether to move it to another position.

WM_IME_CONTROL
IMC_GETCANDIDATEPOS = wSubMessage;
lParam(LPCANDIDATEFORM) = lpCANDIDATENFORM;

Parameters

lpCANDIDATENFORM
Buffer to retrieve the position of the candidate window.

Return Values

If the message is successful, the return value is zero. Otherwise, the return value is nonzero.

Comments

In return, the IME will fill the CANDIDATEFORM pointed to by lpCANDIDATENFORM with the client coordinates of the application's focus window. The UI window receives this message. An application should specify lpCANIDATEFORM->dwIndex to 0 ~ 3 to obtain a different candidate window position. (For example, index 0 is a top-level candidate window.)

IMC_GETCOMPOSITONFONT

The IMC_GETCOMPOSITONFONT message is sent by an application to the IME window to obtain the font to use in displaying intermediate characters in the composition window.

WM_IME_CONTROL
IMC_GETCOMPOSITIONFONT = wSubMessage;
(LPLOGFONT)lParam = lpLogFont;

Parameters

lpLogFont
Buffer to retrieve the LOGFONT.

Return Values

If the message is successful, the return value is zero. Otherwise, the return value is nonzero.

Comments

The UI window does not receive this message.

IMC_GETCOMPOSITONWINDOW

The IMC_GETCOMPOSITONWINDOW message is sent by an application to the IME window to get the position of the composition window. An IME can adjust the position of a composition window, and an application can obtain the real position of composition window to determine whether to move it to another position.

WM_IME_CONTROL
IMC_GETCOMPOSITIONWINDOW = wSubMessage;
lParam(LPCOMPOSITIONFORM) = lpCOMPOSITIONFORM;

Parameters

lpCOMPOSITIONFORM
Buffer to retrieve the position of the composition window.

Return Values

If the message is successful, the return value is zero. Otherwise, the return value is nonzero.

Comments

In return, the IME will fill the CANDIDATEFORM pointed to by lpCANDIDATENFORM with the client coordinates of the application's focus window. The UI window receives this message.

IMC_GETSOFTKBDFONT

The IMC_GETSOFTKBDFONT message is sent by the IME to the soft keyboard window to obtain the font to use for character display in the soft keyboard window.

WM_IME_CONTROL
IMC_GETSOFTKBDFONT = wSubMessage;
lParam(LPLOGFONT) = lpLogFont;

Parameters

lpLogFont
Buffer to retrieve the LOGFONT.

Return Values

If the message is successful, the return value is zero. Otherwise, the return value is nonzero.

IMC_GETSOFTKBDPOS

The IMC_GETSOFTKBDPOS message is sent by an IME to the soft keyboard window to obtain the position of the soft keyboard window.

WM_IME_CONTROL
wSubMessage= IMC_GETSOFTKBDPOS;
lParam = 0;

Parameters

lParam
Not used.

Return Values

The return value specifies a POINTS structure that contains the x and y coordinates of the position of the soft keyboard window, in screen coordinates.

Comments

The POINTS structure has the following form:

typedef struct tagPOINTS { /* pts */
SHORT x;
SHORT y;
} POINTS;

IMC_GETSOFTKBDSUBTYPE

The IMC_GETSOFTKBDSUBTYPE message is sent by an IME to the soft keyboard window to obtain the subtype of the soft keyboard window set by IMC_SETSOFTKBDSUBTYPE.

WM_IME_CONTROL
IMC_GETSOFTKBDSUBTYPE = wSubMessage;
0 = lParam;

Parameters

lParam
Not used.

Return Values

The return value is the subtype of the soft keyboard set by IMC_SETSOFTKBDSUBTYPE. A return value of -1 indicates failure.

IMC_GETSTATUSWINDOWPOS

The IMC_GETSTATUSWINDOWPOS message is sent by an application to the IME window to get the position of the status window.

WM_IME_CONTROL
IMC_GETSTATUSWINDOWPOS = wSubMessage;
0 = lParam;

Parameters

lParam
Not used.

Return Values

The return value specifies a POINTS structure that contains the x and y coordinates of the position of the status window, in screen coordinates.

Comments

The POINTS structure has the following form:

typedef struct tagPOINTS { /* pts */
SHORT x;
SHORT y;
} POINTS;

The UI window receives the message.

IMC_SETCANDIDATEPOS

The IMC_SETCANDIDATEPOS message is sent by an application to the IME window to specify the display position of a candidate window. In particular, this applies to an application that displays composition characters by itself, but uses the IME UI to display candidates.

WM_IME_CONTROL
IMC_SETCANDIDATEPOS = wSubMessage= ;
lParam(LPCANDIDATEFORM) = lpCANDIDATEFORM;

Parameters

lpCANDIDATEFORM
Buffer includes the candidate window position information.

Return Values

If the message is successful, the return value is zero. Otherwise, the return value is nonzero.

Comments

The UI window does not receive this message.

IMC_SETCOMPOSITONFONT

The IMC_SETCOMPOSITONFONT message is sent by an application to the IME window to specify the font to use in displaying intermediate characters in the composition window.

WM_IME_CONTROL
IMC_SETCOMPOSITIONFONT = wSubMessage;
lParam(LPLOGFONT) = lpLogFont;

Parameters

lpLogFont
Buffer includes the LOGFONT data to set.

Return Values

If the message is successful, the return value is zero. Otherwise, the return value is nonzero.

Comments

The UI window does not receive this message.

IMC_SETCOMPOSITONWINDOW

The IMC_SETCOMPOSITONWINDOW message is sent by an application to the IME window to set the style of the composition window in the current active Input Context. Once an application sets the style, the IME user interface then follows the style specified in the Input Context.

WM_IME_CONTROL
IMC_SETCOMPOSITIONWINDOW  =SubMessage;
lParam(LPCOMPOSITIONFORM) = lpCOMPOSITIONFORM;

Parameters

lpCOMPOSITIONFORM
COMPOSITIONFORM structure includes the new styles for the composition window.

Return Values

If the message is successful, the return value is zero. Otherwise, the return value is nonzero.

Comments

The IME user interface uses a default style for the composition window that is equal to the CFS_POINT style. If an application has not specified a composition style in its Input Context, the IME user interface retrieves the current caret position and window client area when it opens the composition window (in client coordinates). The UI window does not receive this message.

IMC_SETSOFTKBDDATA

The IMC_SETSOFTKBDDATA message is sent by the IME to the soft keyboard window to specify the character code to use for displaying characters in the soft keyboard window.

WM_IME_CONTROL
IMC_SETSOFTKBDDATA = wSubMessage;
lParam(LPSOFTKBDDATA) = lpSoftKbdData;

Parameters

lpSoftKbdData
Points to the buffer to specify the character code to use for displaying characters.

Return Values

If the message is successful, the return value is zero. Otherwise, the return value is nonzero.

Comments

The UI window does not receive this message.

IMC_SETSOFTKBDSUBTYPE

The IMC_SETSOFTKBDSUBTYPE message is sent by the IME to the soft keyboard window to specify the subtype to use for displaying characters in the soft keyboard window. It also can be used for IME-specific purposes.

WM_IME_CONTROL
IMC_SETSOFTKBDSUBTYPE = wSubMessage;
lParam = lSubType;

Parameters

lSubType
Specifies the subtype to set.

Return Values

The return value is the subtype. A return value of -1 indicates failure.

Comments

The UI window does not receive this message, and the SOFTKEYBOARD_TYPE_T1 does not use this information. The IME sends this message so the soft keyboard will not change the displayed reading characters. The IME can use the SOFTKEYBOARD_TYPE_T1 soft keyboard to define the meaning of this message and can obtain this data by using IMC_GETSOFTKBDSUBTYPE.

IMC_SETSOFTKBDFONT

The IMC_SETSOFTKBDFONT message is sent by the IME to the soft keyboard window to specify the font to use in displaying characters in the soft keyboard window.

WM_IME_CONTROL
IMC_SETSOFTKBDFONT = wSubMessage;
lParam(LPLOGFONT) = lpLogFont;

Parameters

lpLogFont
Points to the LOGFONT to be set.

Return Values

If the message is successful, the return value is zero. Otherwise, the return value is nonzero.

Comments

The UI window does not receive this message.

IMC_SETSOFTKBDPOS

The IMC_SETSOFTKBDPOS message is sent by the UI window to soft keyboard window to set the position of the soft keyboard window.

WM_IME_CONTROL
IMC_SETSOFTKBDPOS = wSubMessage;
lParam(POINTS) = ptsPt;

Parameters

ptsPt
Specifies a POINTS structure that contains the x and y coordinates of the position of the soft keyboard window, in screen coordinates.

Return Values

If the message is successful, the return value is zero. Otherwise, the return value is nonzero.

Comments

The POINTS structure has the following form:

typedef struct tagPOINTS { /* pts */
SHORT x;
SHORT y;
} POINTS;

IMC_SETSTATUSWINDOWPOS

The IMC_SETSTATUSWINDOWPOS message is sent by an application to the IME window to set the position of the status window.

WM_IME_CONTROL
IMC_SETSTATUSWINDOWPOS = wSubMessage;
lParam(POINTS) = ptsPt;

Parameters

ptsPt
Specifies a POINTS structure that contains the x and y coordinates of the position of the status window, in screen coordinates.

Return Values

If the message is successful, the return value is zero. Otherwise, the return value is nonzero.

Comments

The POINTS structure has the following form:

typedef struct tagPOINTS { /* pts */
SHORT x;
SHORT y;
} POINTS;

WM_IME_COMPOSITION

The WM_IME_COMPOSITION message is sent to an application when the IME composition status is changed (by the user). The message consists of two bytes of composition character. The IME user interface window changes its appearance when it processes this message. An application can call ImmGetCompositionString to obtain the new composition status.

WM_IME_COMPOSITION
wParam = wChar;
lParam = lAttribute;

Parameters

wChar
Consists of two bytes of DBCS character that is the latest change of composition character.
lAttribute
Contains the following flag combinations. Basically, the flag indicates how the composition string or character has changed. An application checks this to retrieve necessary information.
Value | Description
GCR_ERRORSTR | Updates the error string.
GCR_INFORMATIONSTR | Updates the information string.
GCS_COMPATTR | Updates the attribute of the composition string.
GCS_COMPCLAUSE | Updates clause information of the composition string.
GCS_COMPREADATTR | Updates the attributes of the reading string of the current composition.
GCS_COMPREADCLAUSE | Updates the clause information of the reading string of the composition string.
GCS_COMPREADSTR | Updates the reading string of the current composition.
GCS_COMPSTR | Updates the current composition string.
GCS_CURSORPOS | Updates the cursor position in composition string.
GCS_DELTASTART | Updates the starting position of any changes in composition string.
GCS_RESULTCLAUSE | Updates clause information of the result string.
GCS_RESULTREADCLAUSE | Updates clause information of the reading string.
GCS_RESULTREADSTR | Updates the reading string.
GCS_RESULTSTR | Updates the string of the composition result.

The following style bit values are provided for WM_IME_COMPOSITION.
Value | Description
CS_INSERTCHAR | An IME specifies this value when wParam shows a composition character that should be inserted into the current insertion point. An application should display a composition character if it processes this bit flag.
CS_NOMOVECARET | An IME specifies this value when it does not want an application to move the caret position as a result of processing WM_IME_COMPOSITION. For example, if an IME specifies a combination of CS_INSERTCHAR and CS_NOMOVECARET, it means that an application should insert a character given by wParam to the current caret position, but should not move the caret. Subsequent WM_IME_COMPOSITION messages containing the GCS_RESULTSTR flag will replace this character.

Return Values

None

Comments

When an application wants to display composition characters by themselves, it should not pass this message to the application IME user interface window or to DefWindowProc. The DefWindowProc function processes this message to pass to the Default IME window. An IME should send this message to an application even when the IME only cancels the current composition. This message should also be used to notify an application or IME UI to erase the current composition string.

See Also

ImmGetCompositionString

WM_IME_COMPOSITIONFULL

The WM_IME_COMPOSITIONFULL message is sent to an application when the IME user interface window cannot increase the size of the composition window. An application should specify how to display the IME UI window when it receives this message.

WM_IME_COMPOSITIONFULL
0 = wParam
0 = lParam

Parameters

wParam
Not used.
lParam
Not used.

Return Values

None

Comments

This message is a notification, which is sent to an application by the IME user interface window and not by the IME itself. The IME uses SendMEssage to send this notification.

See Also

IMC_SETCOMPOSITONWINDOW

WM_IME_ENDCOMPOSITION

The WM_IME_ENDCOMPOSITION message is sent to an application when the IME ends composition.

WM_IME_ENDCOMPOSITION
0 = wParam
0 = lParam

Parameters

wParam
Not used.
lParam
Not used.

Return Values

None

Comments

When an application wants to display composition characters by themselves, it should not pass this message to the application IME UI window or to DefWindowProc. DefWindowProc processes this message to pass it to the default IME window.

WM_IME_SELECT

The WM_IME_SELECT message is sent to the UI window when the system is about to change the current IME.

WM_IME_SELECT
wParam(BOOL) = fSelect
lParam = hKL

Parameters

fSelect
TRUE if the IME is newly selected. Otherwise, it is FALSE if the IME is unselected.
hKL
Input language handle of the IME.

Return Values

None

Comments

The system IME class uses this message to create a new UI window and destroy an old UI window for an application or system. DefWindowProc processes this message to pass the information to the default IME window. The default IME window then sends this message to its UI window.

WM_IME_STARTCOMPOSITION

The WM_IME_STARTCOMPOSITION message is sent immediately before an IME generates a composition string as a result of a user's keystroke. The UI window opens its composition window when it receives this message.

WM_IME_STARTCOMPOSITION
0 = wParam
0 = lParamx

Parameters

wParam
Not used.
lParam
Not used.

Return Values

None

Comments

When an application wants to display composition characters by themselves, it should not pass this message to the application IME window or to DefWindowProc. The DefWindowProc function processes this message to pass it to the default IME window.

WM_IME_NOTIFY

The WM_IME_NOTIFY message is a group of submessages that notifies an application or UI window of the IME status.

WM_IME_NOTIFY
wSubMessage= wParam; //submessage ID
lParam= lParam; // depends on the submessage

The following topics contain the submessages classified by the value of wSubMessage.

IMN_CLOSESTATUSWINDOW

The IMN_CLOSESTATUSWINDOW message is sent when an IME is about to close a status window.

WM_IME_NOTIFY
IMN_CLOSESTATUSWINDOW = wSubMessage;
0 = lParam;

Parameters

lParam
Not used.

Return Values

None

Comments

The UI window closes the status window when it receives this message.

IMN_OPENSTATUSWINDOW

The IMN_OPENSTATUSWINDOW message is sent when an IME is about to create a status window. An application then processes this message and displays a system window for the IME itself.

An application can obtain information about the system window by calling the ImmGetConversionStatus function.

WM_IME_NOTIFY
IMN_OPENSTATUSWINDOW = wSubMessage;
0 = lParam;

Parameters

lParam
Not used.

Return Values

None

Comments

The UI window creates a status window when it receives this message.

See Also

ImmGetConversionStatus

IMN_OPENCANDIDATE

The IMN_OPENCANDIDATE message is sent when an IME is about to open a candidate window. An application then processes this message and calls ImmGetCandidateCount and ImmGetCandidateList to display the candidate window itself.

WM_IME_NOTIFY
IMN_OPENCANDIDATE = wSubMessage;
lParam = lCandidateList;

Parameters

lCandidateList
Shows which candidate list should be updated. For example, if bit 0 is 1, the first candidate list should be updated. If bit 31 is 1, the 32nd candidate list should be updated.

Return Values

None

Comments

The UI window creates a candidate window when it receives this message.

See Also

ImmGetCandidateListCount, ImmGetCandidateList, WM_IME_CHANGECANDIDATE

IMN_CHANGECANDIDATE

The IMN_CHANGECANDIDATE message is sent when an IME is about to change the content of a candidate window. An application then processes this message to display the candidate window itself.

WM_IME_NOTIFY
IMN_CHANGECANDIDATE = wSubMessage;
lParam = lCandidateList;

Parameters

lCandidateList
Shows which candidate list should be updated. For example, if bit 0 is 1, the first candidate list should be updated. If bit 31 is 1, the 32nd candidate list should be updated.

Return Values

None

Comments

The UI window redraws a candidate window when it receives this message.

See Also

ImmGetCandidateCount, ImmGetCandidateList

IMN_CLOSECANDIDATE

The IMN_CLOSECANDIDATE message is sent when an IME is about to close a candidate window. An application processes this message to obtain information about the end of candidate processing.

WM_IME_NOTIFY
IMN_CLOSECANDIDATE = wSubMessage;
lParam = lCandidateList;

Parameters

lCandidateList
Shows which candidate list should be closed. For example, if bit 0 is 1, the first candidate list should be updated. If bit 31 is 1, the 32nd candidate list should be updated.

Return Values

None

Comments

The UI window destroys a candidate window when it receives this message.

IMN_SETCONVERSIONMODE

The IMN_SETCONVERSIONMODE message is sent when the conversion mode of the Input Context is updated. When the application or UI window receives this message, either one can call ImmGetConversionStatus to obtain information about the status window.

WM_IME_NOTIFY
IMN_SETCONVERSIONMODE = wSubMessage;
0 = lParam;

Parameters

lParam
Not used.

Return Values

None

Comments

The UI window redraws the status window if the status window shows the conversion mode.

IMN_SETSENTENCEMODE

The IMN_SETSENTENCEMODE message is sent when the sentence mode of the Input Context is updated. When the application or UI window receives this message, either one can call ImmGetConversionStatus to obtain information about the status window.

WM_IME_NOTIFY
IMN_SETSENTENCEMODE = wSubMessage;
0 = lParam;

Parameters

lParam
Not used.

Return Values

None

Comments

The UI window redraws the status window if the status window shows the sentence mode.

IMN_SETOPENSTATUS

The IMN_SETOPENSTATUS message is sent when the open status of the Input Context is updated. When the application or UI window receives this message, either one can call ImmGetOpenStatus to obtain information.

WM_IME_NOTIFY
IMN_SETOPENSTATUS = wSubMessage;
0 = lParam;

Parameters

lParam
Not used.

Return Values

None

Comments

The UI window redraws the status window if the status window shows the open/close status.

IMN_SETCANDIDATEPOS

The IMN_SETCANDIDATEPOS message is sent when an IME is about to move the candidate window. An application processes this message to obtain information about the end of candidate processing.

WM_IME_NOTIFY
IMN_SETCANDIDATEPOS = wSubMessage;
lParam = lCandidateList;

Parameters

lCandidateList
Shows which candidate list should be moved. For example, if bit 0 is 1, the first candidate list should be updated. If bit 31 is 1, the 32nd candidate list should be updated.

Return Values

None

Comments

The UI window moves a candidate window when it receives this message.

IMN_SETCOMPOSITIONFONT

The IMN_SETCOMPOSITIONFONT message is sent when the font of the Input Context is updated. When the application or UI window receives this message, either one can call ImmGetCompositionFont to obtain information about the composition font.

WM_IME_NOTIFY
IMN_SETCOMPOSITIONFONT = wSubMessage;
0 = lParam;

Parameters

lParam
Not used.

Return Values

None

Comments

The composition component of the UI window uses the font information by calling ImmGetCompositionFont to draw the text of the composition string.

IMN_SETCOMPOSITIONWINDOW

The IMN_SETCOMPOSITIONWINDOW message is sent when the composition form of the Input Context is updated. When the UI window receives this message, the cfCompForm of the Input Context can be referenced to obtain the new conversion mode.

WM_IME_NOTIFY
IMN_SETCOMPOSITIONWINDOW = wSubMessage;
0 = lParam;

Parameters

lParam
Not used.

Return Values

None

Comments

The composition component of the UI window uses cfCompForm to show the composition window.

IMN_GUIDELINE

The IMN_GUIDELINE message is sent when an IME is about to show an error or information. When the application or UI window receives this message, either one can call ImmGetGuideLine to obtain information about the guideline.

WM_IME_NOTIFY
IMN_GUIDELINE = wSubMessage;
0 = lParam;

Parameters

lParam
Not used. Has to be zero.

Return Values

None

Comments

The UI window can create an information window when it receives this message and show the information string.

See Also

ImmGetGuideLine, GUIDELINE structure

IMN_SOFTKBDDESTROYED

The IMN_SOFTKBDDESTROYED message is sent to the UI window when the soft keyboard is destroyed.

WM_IME_NOTIFY
IMN_SOFTKBDDESTROYED = wSubMessage;
0 = lParam;

Parameters

lParam
Not used. Has to be zero.

Return Values

None

WM_IME_KEYDOWN and WM_IME_KEYUP

The WM_IME_KEYDOWN and WM_IME_KEYUP messages are sent to an application when an IME needs to generate a WM_KEYDOWN or WM_KEYUP message. The value sent is the same as the original Windows WM_KEYDOWN and WM_KEYUP value (English version).

WM_IME_KEYDOWN / WM_IME_KEYUP
 wParam(int) = nVirtKey; // virtual-key code
lParam = lKeyData; // key data

Parameters

nVirtKey
Value of wParam. Specifies the virtual key code of the nonsystem key.
lKeyData
Value of lParam. Specifies the repeat count, scan code, extended key flag, context code, previous key state flag, and transition state flag. It is the same as for the original Windows WM_KEYDOWN and WM_KEYUP messages

Return Values

None

Comments

An application can handle this message the same way as the WM_KEYDOWN and WM_KEYUP message. Otherwise, DefWindowProc processes this message to generate a WM_KEYDOWN or WM_KEYUP message with the same wParam and lParam parameters. This message is usually generated by the IME to maintain message order.

WM_IME_CHAR

The WM_IME_CHAR message is sent to an application when the IME gets a character of the conversion result. The value that is sent is similar to the original Windows WM_CHAR (English version). The difference is that wParam can include two bytes of character.

WM_IME_CHAR
wParam = wCharCode;
lParam = lKeyData;

Parameters

wCharCode
Includes two bytes for an FE character. For NT Unicode application, it includes one Unicode character.
lKeyData
Same as the original Windows WM_CHAR (English Version). Following are the available bits and their description.
Value | Description
0 – 15 | Repeat count. Since the first byte and second byte are continuous, this is always 1.
16 – 23 | Scan Code. Scan code for a complete FE character.
24 – 28 | Not used.
29 | Context code.
31 | Conversion state.

Return Values

None

Comments

If the application does not handle this message, the DefWindowProc function processes this message to generate WM_CHAR messages. If the application is not Unicode based and wCharCode includes 2 bytes of DBCS character, the DefWindowProc function will generate two WM_CHAR messages, each message containing 1 byte of the DBCS character. If the message just includes an SBCS character, DefWindowProc generates only one WM_CHAR message.

VK_PROCESSKEY

The VK_PROCESSKEY message is sent to an application as a wParam of WM_KEYDOWN or WM_KEYUP. When this virtual key is generated, either the real virtual key is saved in the Input Context or the messages that were generated by IME are stored in the Input Context. The system either restores the real virtual key or posts the messages that are stored in the message buffer of the Input Context.

WM_KEYDOWN /WM_KEYUP
VK_PROCESSKEY = wParam;
1 = lParam;

Parameters

lParam
Must be 1.

INDICM_SETIMEICON

This message is sent to the Indicator window when the IME wants to change the icon for System Pen icon. This message can be accepted when the selected hKL of the focused window is the same as the sender IME.

INDICM_SETIMEICON
wParam = nIconIndex;
hKL = lParam;

Parameters

nIconIdex
Index for the icon resource of the IME file. If this value is (-1), the Indicator restores the original icon provided by the system.
lKey
hKL that is the sender IME.

Return Values

A nonzero value indicates failure. Otherwise, zero is returned.

Comments

Due to the internal design requirement in the task bar manager, the IME must use PostMessage for INDICM_xxx messages.

INDICM_SETIMETOOLTIPS

This message is sent to the Indicator window when the IME wants to change the Tooltip string for the System Pen icon. This message can be accepted when the selected hKL of the focused window is the same as the sender IME.

INDICM_SETIMETOOLTIPS
wParam = hAtom;
lParam = hKL;

Parameters

hAtom
Global ATOM value for the Tooltip string. If this value is (-1), the Indicator restores the original tips provided by the system.
lKey
hKL that is the sender IME.

Return Values

A nonzero indicates failure. Otherwise, zero is returned.

Comments

Due to the internal design requirement in the task bar manager, the IME must use PostMessage for INDICM_xxx messages. The global ATOM must be retrieved by GlobalAddAtom or GlobalFindAtom.

INDICM_REMOVEDEFAULTMENUITEMS

This message is sent to the Indicator window when the IME wants to remove the default menu items of the System Pen icon.

INDICM_REMOVEDEFAULTMENUITEMS
wParam = wValue;
lParam = hKL;

Parameters

wValue
wValue is a combination of the following bits.
Value | Description
RDMI_LEFT | Removes the menu items of the left click menu.
RDMI_RIGHT | Removes the menu items of the right click menu.

If wValue is zero, all default menu items are restored.

lKey
hKL that is the sender IME.

Return Values

A nonzero indicates failure. Otherwise, zero is returned.

Comments

Due to the internal design requirement in the task bar manager, the IME must use PostMessage for INDICM_xxx messages.

IME Interface Functions

IMEs are provided as dynamic-link libraries (DLLs). The Input Method Manager (IMM) should handle all installed IMEs. Because IMEs are changeable at run time without rebooting, the IMM will have a structure to maintain all the entry points of each IME.

The following topics contain all the common IME functions. These functions should not be called by an application directly.

ImeInquire

For Windows 95, Windows 98, and Windows NT 3.51

The ImeInquire function handles initialization of the IME. It also returns an IMEINFO structure and the UI class name of the IME.

BOOL
  ImeInquire(
    LPIMEINFO  lpIMEInfo,
    LPTSTR  lpszWndClass,
    LPCTSTR  lpszData
    )

Parameters

lpIMEInfo
Pointer to the IME info structure.
lpszWndClass
Window class name that should be filled by the IME. This name is the IME's UI class.
lpszData
IME option block. NULL for this version.

For Windows NT 4.0 and Windows 2000

BOOL
  ImeInquire(
    LPIMEINFO  lpIMEInfo,
    LPTSTR lpszWndClass,
    DWORD  dwSystemInfoFlags
    )

Parameters

lpIMEInfo
Pointer to the IME info structure.
lpszWndClass
Window class name that should be filled by the IME. This name is the IME's UI class.
dwSystemInfoFlags
Varying system information provided by the system. The following flags are provided.
Flag | Description
IME_SYSINFO_WINLOGON | Tells the IME that the client process is the Winlogon process. The IME should not allow users to configure the IME when this flag is specified.
IME_SYSINFO_WOW16 | Tells the IME that the client process is a 16-bit application.

Return Values

If the function is successful, the return value is TRUE. Otherwise, the return value is FALSE.

ImeConversionList

The ImeConversionList function obtains a converted result list from another character or string.

DWORD
  IMEConversionList(
    HIMC  hIMC,
    LPCTSTR  lpSrc,
    LPCANDIDATELIST  lpDst,
    DWORD  dwBufLen,
    UINT  uFlag
    )

Parameters

hIMC
Input context handle.
lpSrc
Character string to be converted.
lpDst
Pointer to the destination buffer.
dwBufLen
Length of the destination buffer.
uFlag
Currently can be one of the following three flags.
Flag | Description
GCL_CONVERSION | Specifies the reading string to the lpSrc parameter. The IME returns the result string in the lpDst parameter.
GCL_REVERSECONVERSION | Specifies the result string in the lpSrc parameter. The IME returns the reading string in the lpDst parameter.
GCL_REVERSE_LENGTH | Specifies the result string in the lpSrc parameter. The IME returns the length that it can handle in GCL_REVERSECONVERSION. For example, an IME cannot convert a result string with a sentence period to a reading string. As a result, it returns the string length in bytes without the sentence period.

Return Values

The return value is the number of bytes of the result string list.

Comments

This function is intended to be called by an application or an IME without generating IME-related messages. Therefore, an IME should not generate any IME-related messages in this function.

ImeConfigure

The ImeConfigure function provides a dialog box to use to request optional information for an IME.

BOOL
  ImeConfigure(
    HKL  hKL,
    HWND  hWnd,
    DWORD  dwMode,
    LPVOID  lpData
    )

Parameters

hKL
Input language handle of this IME.
hWnd
Parent window handle.
dwMode
Mode of dialog. The following flags are provided.
Flag | Description
IME_CONFIG_GENERAL | Dialog for general purpose configuration.
IME_CONFIG_REGWORD | Dialog for register word.
IME_CONFIG_SELECTDICTIONARY | Dialog for selecting the IME dictionary.

lpData
Pointer to VOID, which will be a pointer to the REGISTERWORD structure only if dwMode==IME_CONFIG_REGISTERWORD. Otherwise, lpData should just be ignored.

This also can be NULL with the IME_CONFIG_REGISTER mode, if no initial string information is given.

Return Values

If the function is successful, the return value is TRUE. Otherwise, the return value is FALSE.

Comments

An IME checks lpData in the following way in the pseudo code.

if (dwmode != IME_CONFIG_REGISTERWORD)
    {
// Does original execution
    }
else if (IsBadReadPtr(lpdata, sizeof(REGISTERWORD))==FALSE)
    {

if (IsBadStringPtr(PREGISTERWORD(lpdata)->lpReading, (UINT)-1)==FALSE)
    {
// Set the reading string to word registering dialogbox
    }
if (IsBadStringPtr(PREGISTERWORD(lpdata)->lpWord, (UINT)-1)==FALSE)
    {
// Set the word string to word registering dialogbox
    }
    }

ImeDestroy

The ImeDestroy function terminates the IME itself.

BOOL
  ImeDestroy(
    UINT  uReserved
    )

Parameters

uReserved
Reserved. Currently, it should be zero. For this version, the IME should return FALSE if it is not zero.

Return Values

If the function is successful, the return value is TRUE. Otherwise, the return value is FALSE.

ImeEscape

The ImeEscape function allows an application to access capabilities of a particular IME not directly available though other IMM functions. This is necessary mainly for country/region-specific functions or private functions in the IME.

LRESULT
  ImeEscape(
    HIMC  hIMC,
    UINT  uEscape,
    LPVOID  lpData
    )

Parameters

hIMC
Input context handle
uEscape
Specifies the escape function to be performed.
lpData
Points to the data required for the specified escape.

The ImeEscape function supports the following escape functions.

uEscape | Meaning
IME_ESC_QUERY _SUPPORT | Checks for implementation. If this escape is not implemented, the return value is zero.
IME_ESC_RESERVED_FIRST | Escape that is between IME_ESC_RESERVED_FIRST and IME_ESC_RESERVED_LAST is reserved by the system.
IME_ESC_RESERVED_LAST | Escape that is between IME_ESC_RESERVED_FIRST and IME_ESC_RESERVED_LAST is reserved by the system.
IME_ESC_PRIVATE_FIRST | Escape that is between IME_ESC_PRIVATE_FIRST and IME_ESC_PRIVATE_LAST is reserved for the IME. The IME can freely use these escape functions for its own purposes.
IME_ESC_PRIVATE_LAST | Escape that is between IME_ESC_PRIVATE_FIRST and IME_ESC_PRIVATE_LAST is reserved for the IME. The IME can freely use these escape functions for its own purposes.
IME_ESC_SEQUENCE_TO_ INTERNAL | Escape that is Chinese specific. An application that wants to run under all East Asian platforms should not use this. It is for the Chinese EUDC editor. The *(LPWORD)lpData is the sequence code, and the return value is the character code for this sequence code. Typically, the Chinese IME will encode its reading character codes into sequence 1 to n.
IME_ESC_GET_EUDC_ DICTIONARY | Escape that is Chinese specific. An application that wants to run under all East Asian platforms should not use this. It is for the Chinese EUDC editor. On return from the function, the (LPTSTR)lpData is filled with the full path file name of the EUDC dictionary. The size of this buffer pointed by lpData should be greater or egual to MAX_PATH * sizeof(TCHAR). Note: Windows 95/98 and Windows NT 4.0 EUDC editor expect IMEs just use the buffer up to 80*sizeof(TCHAR).
IME_ESC_SET_EUDC_ DICTIONARY | Sets the EUDC dictionary file. On input, the lpData parameter is the pointer to a null-terminated string specifying the full path. For use by the Chinese EUDC editor; do not use in other applications.
IME_ESC_MAX_KEY | Escape that is Chinese specific. An application that wants to run under all East Asian platforms should not use this. It is for the Chinese EUDC editor. The return value is the maximum keystrokes for a EUDC character.
IME_ESC_IME_NAME | Escape that is Chinese specific. An application that wants to run under all East Asian platforms should not use this. It is for the Chinese EUDC editor. On return from the function, the (LPTSTR) is the IME name to be displayed on the EUDC editor. The size of this buffer pointed to by lpData should be greater or equal to 16 * sizeof(TCHAR).
IME_ESC_SYNC_HOTKEY | Escape that is (Traditional) Chinese specific. An application that wants to run under all East Asian platforms should not use this. It is for synchronizing between different IMEs. The input parameter *(LPDWORD)lpData is the IME private hot key ID. If this ID is zero, this IME should check every private hot key ID it concerns.
IME_ESC_HANJA_MODE | Escape that is Korean specific. An application that wants to run under all East Asian platforms should not use this. It is for conversion from Hangeul to Hanja. The input parameter (LPSTR)lpData is filled with Hangeul characters that will be converted to Hanja and its null-terminated string. When an application wants to convert any Hangeul character to a Hanja character by using the same method as the Hanja conversion when the composition character is present, the application only needs to request this function. The IME will then set itself as the Hanja conversion mode.
IME_ESC_GETHELPFILENAME | Escape that is the name of the IME's help file. On return from the function, the (LPTSTR)lpData is the full path file name of the IME's help file. The path name should be less than MAX_PATH * sizeof(TCHAR). This is added to Windows 98 and Windows 2000. Note: Windows 98 expects the path length is less than 80 TCHARs.
IME_ESC_PRIVATE_HOTKEY | lpdata points to a DWORD that contains the hot key ID (in the range of IME_HOTKEY_PRIVATE_FIRST and IME_HOTKEY_PRIVATE_LAST). After the system receives the hot key request within this range, the IMM will dispatch it to the IME using the ImeEscape function. Note: Windows® 95 does not support this escape.

Return Values

If the function fails, the return value is zero. Otherwise, the return value depends on each escape function.

Comments

Parameter validation should be inside each escape function for robustness.

When uEscape is IME_ESC_QUERY _SUPPORT, lpData is the pointer to the variable that contains the IME escape value. Following is an example that can be used to determine if the current IME supports IME_ESC_GETHELPFILENAME.

DWORD dwEsc = IME_ESC_GETHELPFILENAME;

LRESULT lRet = ImmEscape(hKL, hIMC, IME_ESC_QUERYSUPPORT, (LPVOID)&dwEsc);

See Also

ImmEscape

ImeSetActiveContext

The ImeSetActiveContext function notifies the current IME active Input Context.

BOOL
  ImeSetActiveContext(
    HIMC  hIMC,
    BOOL  fFlag
    )

Parameters

hIMC
Input context handle.
fFlag
Two flags are provided. TRUE indicates activated and FALSE indicates deactivated.

Return Values

If the function is successful, the return value is TRUE. Otherwise, the return value is FALSE.

Comments

The IME is informed by this function about a newly selected Input Context. The IME can carry out initialization, but it is not required.

See Also

ImeSetActiveContext

ImeProcessKey

The ImeProcessKey function preprocesses all the keystrokes given through the IMM and returns TRUE if that key is necessary for the IME with a given Input Context.

BOOL
  ImeProcessKey(
    HIMC  hIMC,
    UINT  uVirKey,
    DWORD  lParam,
    CONST LPBYTE  lpbKeyState
    )

Parameters

hIMC
Input context handle
uVirKey
Virtual key to be processed.
lParam
lParam of key messages.
lpbKeyState
Points to a 256-byte array that contains the current keyboard state. The IME should not modify the content of the key state.

Return Values

If the function is successful, the return value is TRUE. Otherwise, the return value is FALSE.

Comments

The system decides whether the key is handled by IME or not by calling this function. If the function returns TRUE before the application gets the key message, the IME will handle the key. The system will then call the ImeToAsciiEx function. If this function returns FALSE, the system recognizes that the key will not be handled by the IME and the key message will be sent to the application.

For IMEs that support IME_PROP_ACCEPT_WIDE_VKEY on Windows 2000, ImeProcessKey will receive full 32 bit value for uVirKey, which is injected by using SendInput API through VK_PACKET. uVirKey will include 16-bit Unicode in hiword even the IME may be ANSI version.

For IMEs that do not support IME_PROP_ACCEPT_WIDE_VKEY, Unicode IME's ImeProcessKey will receive VK_PACKET with zero'ed hiword. Unicode IME still can return TRUE so ImeToAsciiEx will be called with the injected Unicode. ANSI IME's ImeProcessKey will not receive anything. The injected Unicode will be discarded if the ANSI IME is open. If the ANSI IME is closed, the injected Unicode message will be posted to application's queue immediately.

NotifyIME

The NotifyIME function changes the status of the IME according to the given parameters.

BOOL
  NotifyIME(
    HIMC  hIMC,
    DWORD  dwAction,
    DWORD  dwIndex,
    DWORD  dwValue
    )

Parameters

hIMC
Input context handle.
dwAction
Following are the context items that an application can specify in the dwAction parameter.
Context Item | Description
NI_OPENCANDIDATE | Application has the IME open the candidate list. If the IME opens the candidate list, the IME sends a WM_IME_NOTIFY (subfunction is IMN_OPENCANDIDATE) message.
dwIndex | Index of the candidate list to be opened.
dwValue | Not used.
NI_CLOSECANDIDATE | Application has the IME close the candidate list. If the IME closes the candidate list, the IME sends a WM_IME_NOTIFY (subfunction is IMN_CLOSECANDIDATE) message.
dwIndex | Index of the candidate list to be closed.
dwValue | Not used.
NI_SELECTCANDIDATESTR | Application selects one of the candidates.
dwIndex | Index of the candidate list to be selected.
dwValue | Index of the candidate string in the selected candidate list.
NI_CHANGECANDIDATELIST | Application changes the currently selected candidate.
dwIndex | Index of the candidate list to be selected.
dwValue | Not used.
NI_SETCANDIDATE_PAGESTART | Application changes the page starting index of the candidate list.
dwIndex | Index of the candidate list to be changed.
dwValue | New page start index.
NI_SETCANDIDATE_PAGESIZE | Application changes the page size of the candidate list.
dwIndex | Index of the candidate list to be changed.
dwValue | New page size.
NI_CONTEXTUPDATED | Application or system updates the Input Context.
dwIndex When the value of dwValue is IMC_SETCONVERSIONMODE, dwIndex is the previous conversion mode.

When the value of dwValue is IMC_SETSENTENCEMODE, dwIndex is the previous sentence mode.

For any other dwValue, dwIndex is not used.
dwValue One of following values used by the WM_IME_CONTROL message:

IMC_SETCANDIDATEPOS

IMC_SETCOMPOSITIONFONT

IMC_SETCOMPOSITIONWINDOW

IMC_SETCONVERSIONMODE

IMC_SETSENTENCEMODE

IMC_SETOPENSTATUS
NI_COMPOSITIONSTR | Application changes the composition string. This action takes effect only when there is a composition string in the Input Context.
dwIndex The following values are provided for dwIndex:

CPS_COMPLETE

To determine the composition string as the result string.

CPS_CONVERT

To convert the composition string.

CPS_REVERT

To revert the composition string. The current composition string will be canceled and the unconverted string will be set as the composition string.

CPS_CANCEL

To clear the composition string and set the status as no composition string.
dwValue | Not used.

dwIndex
Dependent on uAction.
dwValue
Dependent on uAction.

Return Values

If the function is successful, the return value is TRUE. Otherwise, the return value is FALSE.

See Also

ImmNotifyIME

ImeSelect

The ImeSelect function is used to initialize and uninitialize the IME private context.

BOOL
  ImeSelect(
    HIMC  hIMC,
    BOOL  fSelect
    )

Parameters

hIMC
Input context handle
fSelect
Two flags are provided. TRUE indicates initialize and FALSE indicates uninitialize (free resource).

Return Values

If the function is successful, the return value is TRUE. Otherwise, the return value is FALSE.

ImeSetCompositionString

The ImeSetCompositionString function is used by an application to set the IME composition string structure with the data contained in the lpComp or lpRead parameters. The IME then generates a WM_IME_COMPOSITION message.

BOOL WINAPI
  ImeSetCompositionString(
    HIMC  hIMC,
    DWORD  dwIndex,
    LPCVOID  lpComp,
    DWORD  dwCompLen,
    LPCVOID  lpRead,
    DWORD  dwReadLen
    );

Parameters

hIMC
Input context handle.
dwIndex
The following values are provided for dwIndex.
Value | Description
SCS_SETSTR | Application sets the composition string, the reading string, or both. At least one of the lpComp and lpRead parameters must point to a valid string. If either string is too long, the IME truncates it.
SCS_CHANGEATTR | Application sets attributes for the composition string, the reading string, or both. At least one of the lpComp and lpRead parameters must point to a valid attribute array.
SCS_CHANGECLAUSE | Application sets the clause information for the composition string, the reading string, or both. At least one of the lpComp and lpRead parameters must point to a valid clause information array.
SCS_QUERYRECONVERTSTRING | Application asks the IME to adjust its RECONERTSTRINGSTRUCTRE. If the application calls the ImeSetCompositionString function with this value, the IME adjusts the RECONVERTSTRING structure. The application can then pass the adjusted RECONVERTSTRING structure to this function with SCS_RECONVERTSTRING. The IME will not generate any WM_IMECOMPOSITION messages.
SCS_SETRECONVERTSTRING | Application asks the IME to reconvert the string contained in the RECONVERTSTRING structure.

lpComp
Pointer to the buffer that contains the updated string. The type of string is determined by the value of dwIndex.
dwCompLen
Length of the buffer in bytes.
lpRead
Pointer to the buffer that contains the updated string. The type of string is determined by the value of dwIndex. If the value of dwIndex is SCS_SETRRECONVERTSTRING or SCS_QUERYRECONVERTSTRING, lpRead will be a pointer to the RECONVERTSTRING structure that contains the updated reading string. If the selected IME has the value SCS_CAP_MAKEREAD, this can be NULL.
dwReadLen
Length of the buffer in bytes.

Comments

For Unicode, dwCompLen and dwReadLen specifies the length of the buffer in bytes, even if SCS_SETSTR is specified and the buffer contains a Unicode string.

SCS_SETRECONVERTSTRING or SCS_QUERYRECONVERTSTRING can be used only for IMEs that have an SCS_CAP_SETRECONVERTSTRING property. This property can be retrieved by using the ImmGetProperty function.

ImeToAsciiEx

The ImeToAsciiEx function generates a conversion result through the IME conversion engine according to the hIMC parameter.

UINT
  ImeToAsciiEx(
    UINT  uVirKey,
    UINT  uScanCode,
    CONST LPBYTE  lpbKeyState,
    LPTRANSMSGLIST  lpTransMsgList,
    UINT  fuState,
    HIMC  hIMC
    )

Parameters

uVirKey
Specifies the virtual key code to be translated. When the property bit IME_PROP_KBD_CHAR_FIRST is on, the upper byte of the virtual key is the aid character code.

For Unicode, the upper word of uVirKey contains the Unicode character code if the IME_PROP_KBD_CHAR_FIRST bit is on.

uScanCode
Specifies the hardware scan code of the key to be translated.
LpbKeyState
Points to a 256-byte array that contains the current keyboard state. The IME should not modify the content of the key state.
lpTransMsgList
Point to a TRANSMSGLIST buffer to receive the translated message result. This was defined as a double word buffer in Windows 95/98 and Windows NT 4.0 IME document, and the double word buffer format is [Length of the pass in translated message buffer] [Message1] [wParam1] [lParam1] {[Message2] [wParam2] [lParam2]{...{...{...}}}}.
fuState
Active menu flag.
hIMC
Input context handle.

Return Values

The return value indicates the number of messages. If the number is greater than the length of the translated message buffer, the translated message buffer is not enough. The system then checks hMsgBuf to get the translation messages.

Comments

On Windows 2000, a new 32bit-width virtual key code, using VK_PACKET in LOBYTE of wParam and the high word is Unicode, can be injected by using SendInput.

For ANSI IMEs that support IME_PROP_ACCEPT_WIDE_VKEY, ImeToAsciiEx may receive up to 16bit ANSI code for a character. It will be packed as below. The character is injected from SendInput API through VK_PACKET.

24-31 bit | 16-23 bit | 8-15 bit | 0-7 biy
Reserved | Trailing DBCS byte(if any) | Leading byte | VK_PACKET

See Also

ImmToAsciiEx

ImeRegisterWord

The ImeRegisterWord function registers a string into the dictionary of this IME.

BOOL WINAPI
  ImeRegisterWord(
    LPCTSTR  lpszReading,
    DWORD  dwStyle,
    LPCTSTR  lpszString
    )

Parameters

lpszReading
Reading string of the registered string.
dwStyle
Style of the registered string. The following values are provided.
Value | Description
IME_REGWORD_STYLE_EUDC | String is within the EUDC range
IME_REGWORD_STYLE_USER_FIRST to IME_REGWORD_STYLE_USER_LAST Constants range from IME_REGWORD_STYLE_USER_FIRST to IME_REGWORD_STYLE_USER_LAST and are used for private styles of the IME ISV. The IME ISV can freely define its own style. For example:

#define MSIME_NOUN (IME_REGWORD_STYLE_USER_FIRST)

#define MSIME_VERB (IME_REGWORD_STYLE_USER_FISRT +1)

lpszString
String to be registered.

Return Values

If the function is successful, the return value is TRUE. Otherwise, the return value is FALSE.

ImeUnregisterWord

The ImeUnregisterWord function removes a registered string from the dictionary of this IME.

BOOL WINAPI
  ImeUnregisterWord(
    LPCTSTR  lpszReading,
    DWORD  dwStyle,
    LPCTSTR  lpszString
    )

Parameters

lpszReading
Reading string of the registered string.
dwStyle
Style of the registered string. Please refer to the ImeRegisterWord function for a description of dwStyle.
lpszString
String to be unregistered.

Return Values

If the function is successful, the return value is TRUE. Otherwise, the return value is FALSE.

ImeGetRegisterWordStyle

The ImeGetRegisterWordStyle function gets the available styles in this IME.

UINT WINAPI
  ImeGetRegisterWordStyle(
    UINT  nItem,
    LPSTYLEBUF  lpStyleBuf
    )

Parameters

nItem
Maximum number of styles that the buffer can hold.
lpStyleBuf
Buffer to be filled.

Return Values

The return value is the number of the styles copied to the buffer. If nItems is zero, the return value is the buffer size in array elements needed to receive all available styles in this IME.

ImeEnumRegisterWord

The ImeEnumRegisterWord function enumerates the information of the registered strings with specified reading string, style, and registered string data.

UINT WINAPI
  ImeEnumRegisterWord(
    hKL  hKL,
    REGISTERWORDENUMPROC  lpfnEnumProc,
    LPCTSTR  lpszReading,
    DWORD  dwStyle,
    LPCTSTR  lpszString,
    LPVOID  lpData
    )

Parameters

hKL
Input language handle.
lpfnEnumProc
Address of callback function.
lpszReading
Specifies the reading string to be enumerated. If lpszReading is NULL, ImeEnumRegisterWord enumerates all available reading strings that match the specified dwStyle and lpszString parameters.
dwStyle
Specifies the style to be enumerated. If dwStyle is NULL, ImeEnumRegisterWord enumerates all available styles that match the specified lpszReading and lpszString parameters.
lpszString
Specifies the registered string to be enumerated. If lpszString is NULL, ImeEnumRegisterWord enumerates all registered strings that match the specified lpszReading and dwStyle parameters.
lpData
Address of application-supplied data.

Return Values

If the function is successful, the return value is the last value returned by the callback function. Its meaning is defined by the application.

Comments

If all lpszReading dwStyle, and lpszString parameters are NULL, ImeEnumRegisterWord enumerates all registered strings in the IME dictionary. If any two of the input parameters are NULL, ImeEnumRegisterWord enumerates all registered strings matching the third parameter.

ImeGetImeMenuItems

The ImeGetImeMenuItems function gets the menu items that are registered in the IME menu.

DWORD WINAPI
  ImeGetImeMenuItems(
    HIMC  hIMC,
    DWORD  dwFlags,
    DWORD  dwType,
    LPIMEMENUITEMINFO  lpImeParentMenu,
    LPIMEMENUITEMINFO  lpImeMenu,
    DWORD  dwSize
    )

Parameters

hIMC
The lpMenuItem contains menu items that are related to this input context.
dwFlags
Consists of the following bit combinations.
Bit | Description
IGIMIF_RIGHTMENU | If this bit is 1, this function returns the menu items for the right click Context menu.

dwType
Consists of the following bit combinations.
Bit | Description
IGIMII_CMODE | Returns the menu items related to the conversion mode.
IGIMII_SMODE | Returns the menu items related to the sentence mode.
IGIMII_CONFIGURE | Returns the menu items related to the configuration of IME.
IGIMII_TOOLS | Returns the menu items related to the IME tools.
IGIMII_HELP | Returns the menu items related to IME help.
IGIMII_OTHER | Returns the menu items related to others.
IGIMII_INPUTTOOLS | Returns the menu items related to the IME input tools that provide the extended way to input the characters.

lpImeParentMenu
Pointer to the IMEMENUINFO structure that has MFT_SUBMENU in fType. ImeGetImeMenuItems returns the submenu items of this menu item. If this is NULL, lpImeMenu contains the top-level IME menu items.
lpImeMenu
Pointer to the buffer to receive the contents of the menu items. This buffer is the array of IMEMENUITEMINFO structure. If this is NULL, ImeGetImeMenuItems returns the number of the registered menu items.
dwSize
Size of the buffer to receive the IMEMENUITEMINFO structure.

Return Values

The return value is the number of the menu items that were set into lpIM. If lpImeMenu is NULL, ImeGetImeMenuItems returns the number of menu items that are registered in the specified hKL.

Comments

ImeGetImeMenuItems is a new function for Windows 98 and Windows 2000.


Input Method Editor (IME)

Beginning with Microsoft® Windows® 95 and Windows NT® 4.0, and continuing with Windows 2000, Input Method Editors (IMEs) are provided as a dynamic-link library (DLL) for use in entering characters into foreign language applications, in contrast to the IMEs for the Windows 3.1 East Asian Edition. An IME for each language runs as one of the multilingual keyboard layouts. In comparison to the old Windows 3.1 IME, the new Win32 Multilingual Input Method Manager (IMM) and Input Method Editor (IME) architecture provide the following advantages:

  • Run as a component of the multilingual environment localization.
  • Offer multiple input contexts for each application task.
  • Keep one active IME per each application thread.
  • Give information to the application through message looping (does not break apps message order).

As an example, to enter Japanese characters using a standard U.S. keyboard on a localized Japanese version of Windows 2000, you must use an IME.

IME provides several different methods of entering Hiragana, Hurigana,Katakana, Kanji, and Romaji characters using IME, WX2, VJ2, and ATOK7. The IME input method is used by default. To change the default input method, run IME from the Program Manager "Nihon go jin ka" group.

To invoke IME, you must use the key combination ALT+~ or ALT+` to launch 4 applications (located in the lower right hand corner on your desktop). These applications provide several Japanese characters you can enter into your document. To disable IME, you must use the same key combination of ALT+ ~ or ALT+ ` again.

There are basically two groups of Windows NT 4.0: European versions of NT, and East Asian versions of NT. The European versions ( English, French, German, Russian, Polish, etc.) are almost identical to each other, and the only differences between the different versions of NT in this group are the resources in each dll and exe (if the dlls contain resources). The resources in each system dll or exe would, of course, be containing strings and dialogs in different versions. The main thing you need to pay attention to when you are testing IME in this group is to make sure that the font you have chosen to display text is a font that can display strings in a certain language; otherwise, European versions of NT are the same as the English version.


East Asian Platforms

On Microsoft® Windows NT® 4.0 or Windows® 9.x non-Asian platforms, there is no IME support. Starting from Windows 2000, IME is supported on all language operating systems. When developing applications, please make sure your code can handle Asian languages. Pay attention to the following things:

  • Test all windows that accept character input to make sure they can accept and handle non-ASCII characters correctly.
  • Make sure the font can handle all the different language input characters.
  • Make sure that all your dialogs still look good and are big enough for your strings.


The Task Bar

The Microsoft® Windows® system program installs two icons in the task bar when the current hKL is an IME. One icon is the System ML icon that indicates the current keyboard layout in the system task bar. The other is the System Pen icon that shows the IME status of the focused window.

Usually, an IME places an additional icon in the task bar. The context menu for this icon is completely dependent on the IME. Having IME icons in a task bar is a quick way for a user to access an IME's special functions. However, there are three icons associated with the IME and these additional icons may be more than a user wants to deal with.


For Further Information

Path for IME documentation shipped with the Microsoft® Windows® 2000 DDK:

\ntddk\src\ime\docs

You can also refer to the IME samples under \ntddk\src\ime to develop your own IME.

Additional IME information can be found in the Microsoft Platform SDK, under this heading in the Table of Contents:

Windows Base Services

International Features

Input Method Editor


Large Memory Enabled Device Driver Hardware and Software Requirements

Development Platform

The hardware requirements for developing device drivers that are Large Memory Enabled (LME) for Microsoft® Windows® 2000 Datacenter Server using PAE [Physical Address Extension] memory are similar to those for common, current development systems and do not require large investments. In any case, the minimum platform is the same as for Windows 2000 Professional, and the required development environment is the Windows 2000 DDK. Check with the system manufacturer for specific chipset and BIOS compliance, if the system is to have more than 4GB of physical RAM installed. Also, the use of two processors in the development system can make it easier to detect synchronization problems. Finally, even if more than 4GB of RAM is not installed, additional memory will make development and testing more rapid.

Testing Platform

Final testing for correct implementation of an LME driver and use of memory beyond 32 bits must occur on Microsoft® Windows® 2000 DataCenter Server. Testing must occur on a system with more than 4GB of physical memory. Testing of a device and driver's correct use of PAE is required for the Microsoft DataCenter HCT and logo.

General Information

All the physical memory in the system is treated as general purpose memory by Microsoft® Windows® 2000 Datacenter Server. The operating system can use this memory for caching and virtual memory management without major changes.

Applications that require more physical memory than is provided by the 4GB virtual address space can use the AWE API set to map from a designated window in the application's virtual address space into the physical memory region allocated for that window. Applications will be able to do I/O from those mapped memory pool regions. Unmodified applications will also be capable of I/O at physical addresses above 4GB while only being aware of a 4GB virtual address space.

Direct I/O is supported for the entire physical address space if the network and storage devices and drivers support dual address cycle and 64-bit addressing.

The kernel virtual memory space organization for PAE-X86 is unchanged from the standard Windows 2000 kernel, providing an easier migration path for the device drivers. For example, the maximum non-paged pool remains at 256 MB.

Although double buffering of I/O from 32-bit devices and drivers is transparent in that the operating system can manage these operations, the performance impact is large for high performance I/O devices such as 100BaseT, 1000BaseT, FDDI, or ATM network adapters. This applies as well for storage adapters, such as those for SCSI-2, SCSI-3 or Fibre Channel. To gauge the impact, an example of poor performance is ISA, where devices can only physically address the first 16MB because of 24-bit addressing limitations. The negative performance impact grows as the physical memory in the system increases. For example, on a system with 4GB of physical memory, no double buffering occurs and there is no impact. On a system with 8GB of physical memory, more than one half of all I/O operations would occur from addresses above 4GB. A system with 16GB of physical memory would have more than three-quarters of all I/O operations originating at addresses beyond 4GB.

Device and Driver Requirements for Windows 2000 DataCenter

Microsoft has proposed the following requirements for devices and drivers designed for Microsoft® Windows® 2000 DataCenter systems. These requirements must be met so that the system or components can be placed on the Windows 2000 Datacenter Server Hardware Compatibility List (HCL).

  • All SCSI-2, SCSI-3, and Fibre Channel storage adapters and device drivers for Windows 2000 DataCenter must be Dual Address Cycle or 64-bit capable.
  • All 100BaseT, Gigabit, ATM [OC3 and higher], FDDI, 16/100 Mb TR, and SAN adapters and device drivers for Windows 2000 DataCenter must be Dual Address Cycle or 64-bit capable.
  • Every device and its 64-bit driver must be tested in 8GB (or greater) Intel Architecture systems running PAE or in similarly equipped Alpha systems, even if the device has a previously tested and listed 32-bit driver and is listed on the general Windows 2000 HCL.
  • PCI adapters restricted to 32-bit address space will not be listed on the HCL for Windows 2000 DataCenter, but will be supported if they are not on the primary data path for the DataCenter system. The primary data path is defined as either the highest performance network connection(s) in the system for client-to-server and/or server-to-server communications, or as the path(s) on which the majority of storage capacity and/or the system paging file(s) exist.
  • No ISA cards will be tested, validated, listed on the HCL or supported by Microsoft for Windows 2000 DataCenter.

Under the Windows Logo Program, both servers and workstations require that for systems capable of supporting more than 4GB of memory (described as "64-bit platforms"), PCI cards must be capable of addressing the complete physical address space on the platform.

This means that 32-bit PCI adapters must be able to support the Dual Address Cycle (DAC) function or natively support 64-bit addressing to permit them to transfer 64-bit addresses (that is, addresses that are above the low 4GB address space). Adapters that cannot provide this support will not be able to access the full address space on a PAE-capable platform.

Additional information about this and 64-bit PCI adapters is available to members of the PCI Special Interest Group (SIG). The General Component Protocol Checklist from the PCI SIG includes approximately 45 tests either related to or specifically regarding DAC adapters.

For EIDE, ATA, 10BaseT, 4 MB Token Ring, and so on, these adapters are relatively low-bandwidth and are unlikely to be used for heavy I/O loads. They will not be included on the HCL for Windows 2000 DataCenter, but may be needed for remote control access or other purposes.

For more information about Windows Logo Program requirements, see http://www.microsoft.com/hwdev/winlogo/99logo.htm. See also the Hardware Design Guide Version 2.0 for Microsoft Windows NT Server, available at http://www.microsoft.com/hwdev/serverdg.htm.

Microsoft cannot verify every possible card of the thousands that exist in order to rigorously test the adapters and drivers for Windows 2000 DataCenter Server. Therefore, manufacturers should choose their highest performing, most reliable adapters for this effort and plan to provide 64-bit devices and LME drivers by RC1 of Windows 2000 Datacenter Server that will immediately follow the release of the other Windows 2000 products; Professional, Server and Advanced Server.

These requirements will go into effect when the Windows 2000 DataCenter operating system ships. If you have comments or questions about these requirements, please send e-mail to hwlogo@microsoft.com. Please include your name, title, company name, and phone/fax numbers.

Programming Considerations: 64-bit Addressability Is Not Win64

While the physical addresses used are 64-bit for both PAE kernel and Win64, pointers are not. There are other differences as well. Device drivers must be recompiled for Win64; as 32-bit device drivers, even those capable of addressing 64-bit address spaces are absolutely not supported on Win64.

PVOID64 does not work with PAE kernel memory. If used, the return is invalid as only the first 32 bits are correct and a random 32 bits are placed in the return for the rest. Developers writing to support PAE systems using LME drivers should only use PHYSICAL_ADDRESS (which can also be used for address calculations). Do not use PVOID, PVOID64, ULONGLONG, or any other type.

No executables or buffers can be executed within an AWE window. The AWE API does not permit executable code (.exe, .dll, .sys, and so on) to execute from within an AWE window region in the process's virtual memory or in the mapped physical memory pool that the process is utilizing. Also, AWE window address ranges and memory pools cannot be used as data buffers for graphics or video calls. Thus, video, graphics, and other device drivers may not use the AWE API. The kernel, however, does use all physical memory as general purpose memory.


Infrared Device Miniport Development Introduction

This section contains information about:

  • DBGCON, a utility for gathering debug data from the checked version of IRDA.SYS.
  • SLEDGE, a Winsock-compatible stress test application.
  • SNIFFIR, a COM-based application that can monitor infrared packets.

DbgCon

DBGCON allows monitoring the activity in the IrDA protocol stack without using the kernel debugger. Execute DBGCON, and it will begin displaying debug data from the protocol stack. You may press the ESC key to modify what debug data is displayed, or press the Q key to quit. DBGCON will only work with the checked version of IRDA.SYS.

DBGCON debug options:

  • RXFRAME: (default off) Display IrLAP header of frame received from miniport.
  • TXFRAME: (default off) Display IrLAP header of frame to be transmitted to miniport.
  • MAC: (default off) Not used.
  • NDIS: (default off) Display IRDA.SYS lower edge activity (not too useful).
  • LAPLOG: (default off) Display IrLAP event/actions logging.
  • LAP: (default off) Display IrLAP information (little output).
  • LMP: (default off) Display full IrLMP debugging.
  • LMP_CONN: (default off) Display LMPDU connection information.
  • LMP_CREDIT: (default off) Display TinyTPP credit information.
  • LMP_IAS: (default off) Display IrLMP IAS information.
  • TDI: (default off) Display upper edge activity.
  • TDI_IRP: (default off) Display Irp requests from TDI client.
  • WARN: (default on) Display minor errors.
  • ERROR: (default on) Display severe errors.
  • Output: Debugger: (default off) Select this to cause IRDA to direct its debug output to the kernel debugger.
  • Output: Console: (default on) Select this to cause IrDA to direct its debug output to DBGCON.

Sledge

Sledge is a stress utility used by Microsoft to test the IrDA protocol and miniports. It opens multiple connections between two computers, sends data both ways in random-sized packets, and reports the results.

A copy of Sledge must be running on both systems. One will be the server, the other the client.

On the server, execute Sledge and issue the following commands:

SERV-IRSOCK ON (required)

GO (required)

On the client, execute Sledge and issue these commands:

IRSOCK 10 2 (required command, parameters are adjustable)

GO

There are other Sledge commands to adjust the parameters of the test. Enter a question mark (?) at the prompt for a list. Some parameters of note:

  • SERV-RECV-LEN #: Adjusts the server read size. A value of 2040 would be most efficient for Infrared.
  • PACKET-LEN min max: Adjust the client send size. Min 2040 and max 2040 will force it to use the largest IrDA packet size.

Sniffir

Sniffir is an infrared monitoring utility. It requires no drivers and operates on a SIR device that has been exposed through a Microsoft® WIN32® COM port. It will run on Intel Microsoft Windows NT®/Windows® 2000 and Windows 9X platforms. It will log packets coming from both ends of a connection pair, at speeds up to 115200 baud.

It currently supports the following hardware:

  • Most laptop generic SIR implementations
  • Extended Systems JetEye

To use Sniffir, align the infrared adapters in a triangle so that the sniffing adapter can see both connected adapters and vice versa. Sniffir should, by default, begin sniffing at 9600 baud, but if the connection speed changes, Sniffir should change to match at any speed that it supports.

Because Sniffir is primarily a SIR utility, it may incorrectly report information relating to MIR or FIR speeds.

Notes

Miniports: Min Turnaround Time: It seems that the custom has become to implement min turnaround time in the miniport via NdisStallExecution(). The problem is that NdisStallExecution() effects a freeze on the system for the duration of the call, and nothing else can happen. Since the largest min turnaround time is 10 milliseconds, the impact on overall system performance is large. In the case of the NSC driver, we were able to reduce CPU utilization significantly by changing from NdisStallExecution() to using NDIS Timers.

Installation and Plug and Play: Installation of some infrared devices is more complex than it should be. The most common reasons for this are machine-specific BIOS issues. Some FIR implementations plug and play incorrectly. They may advertise themselves only via the generic SIR device IDs. As a result of this, many FIR implementations will be installed by default as SIR, and the user will be required to Change driver in the control panel to achieve FIR functionality. There is little that can be done for the existing installed base that have this problem, but it is a caution to vendors to do it right. To insure proper operation, the device ID of a given infrared device should be unique to that hardware, so that both controller and transceiver type can be configured without any user intervention.

Winsock: The interface to the IrDA stack is described in the Platform SDK documentation.

Common IrDA Miniport mistakes

DMA: Some vendors have implemented programming DMA via direct I/O under Win9X, bypassing NDIS. This is not recommended under any circumstances in Windows NT/Windows 2000. Drivers that do this may be rejected from inclusion on the Windows NT/Windows 2000 CD release.

NDIS: MiniportSendPackets(): Miniports must not expect NDIS to serialize calls to MiniportSendPackets(). MiniportSendPackets() can and will be called several times before even one packet has been completed.

NDIS: MiniportSendPackets(): Some drivers have mistakenly kept the PacketArray which is passed to the miniport in this call. This is illegal. NDIS assumes that when MiniportSendPackets() returns, all necessary data has been taken from the array, and NDIS is free to fill in new data, even before the packets indicated in the call have been completed.

NDIS: NdisMIndicateReceivePacket(): Receive packets indicated to the protocol may be held for an indefinite period. Many miniports indicate packets which are resident in the miniport's receive DMA buffer, then restart DMA, which can corrupt the packet before the protocol has released it. Developers who want to avoid the overhead of copying packets from their receive DMA buffers should inspect the mechanism in NSCIRDA.SYS. It manages the DMA buffer so that it indicates packets to the protocol and still starts to receive DMA in the unused portion of the buffer.


STORPORT: High Performance Port Driver for Storage Devices

Introduction

Over the years, a number of limitations with the current SCSI port driver have surfaced with regard to its ability to manage traffic over high-performance buses. These limitations have been difficult to address without a significant investment on the part of the driver writer. With the STOR port driver, Microsoft is addressing some of these issues.

Our three primary design goals with the STOR port driver are:

  • Improve performance over SCSIPORT, both in terms of throughput and in terms of the system resources that are utilized. STORPORT performance should be on par with, or better than, the performance of a monolithic port driver.
  • Improve the SCSI miniport interface to address the needs of high-end storage vendors, particularly host-based RAID and Fiber Channel vendors.
  • Add a manageability infrastructure for configuration and management of host-based RAID adapters.

These goals are met by providing a new port driver. To better utilize the investment vendors have made in SCSI miniports, and to decrease the development time for writing miniport drivers, the STOR port driver follows the SCSI port/miniport architecture with very few modifications. The changes to the SCSI port interface are in areas where the STOR port driver can achieve measurable speed increases by using different algorithms, or to add features necessary to support newer buses.

New Features

The following topics discuss areas where the STOR port driver improves upon the SCSI port driver.

Improvements in the I/O model

This section describes the improved I/O model that the STOR port driver provides and compares this model with that of the SCSI port driver.

Full-Duplex Mode

The STOR port driver supports a new I/O model tailored specifically for high-performance buses. In the new I/O model, access to the miniport's StartIo routine does not need to be synchronized with the miniport's interrupt service routine (ISR). This full-duplex mode allows requests to be completed at the same time new requests are being queued to the driver. The performance enhancements of the full-duplex mode can be significant, but drivers must be written to take advantage of it. By default, drivers run in half-duplex mode and do not utilize the benefits of a full duplex driver.

Full-duplex mode can be set by initializing the SynchronizationMode member of the miniport's PORT_CONFIGURATION_INFORMATION structure to StorSynchronizeFullDuplex during the miniport's HwFindAdapter routine.

Unsynchronized HwBuildIo Routine

The original intent of the SCSI port/miniport architecture was that the port driver would do most of the work of building an I/O request. In this model, the miniport's HwStartIo routine merely transmits the built SRB to the hardware with little modification. Over time, as non-SCSI devices have become supported through the SCSI port driver, more processing of the I/O request has become necessary in the miniport's HwStartIo routine. Unfortunately, work done in the miniport's HwStartIo routine is done while interrupts are disabled, at a raised I/O request level. Therefore, the more processing done in the HwStartIo, the more system performance suffers. To address this problem, Microsoft has added a HwBuildIo routine that is called just prior to the miniport's HwStartIo routine without any synchronization locks held and at a lower I/O request level (IRQL).

The HwBuildIo routine should translate the SRB to a more convenient data structure, build scatter-gather lists, or do other per-SRB processing. Since no locks are held during the HwBuildIo routine, the driver should not access data other than the SRB itself and data in the SRB extension. If access to other structures is required for part of the processing, that part should still be performed in the HwStartIo routine.

BOOLEAN
HwStorBuildIo(
    IN PVOID DeviceExtension,
    IN PSCSI_REQUEST_BLOCK Srb
    );

Performance Hint: The HwBuildIo routine and the full-duplex mode can be used together to improve performance.

Synchronization

If a miniport uses full-duplex mode, or if it implements an HwBuildIo routine, it may still be necessary to provide synchronized access to the miniport's device extension. The STOR port driver exposes a single primitive that allows synchronizing access with the driver's interrupt routine to data in other structures.

typedef
BOOLEAN
(*PSTOR_SYNCHRONIZED_ACCESS)(
  IN PVOID HwDeviceExtension,
  IN PVOID Context
  );

VOID
StorPortSynchronizeAccess(
    IN PVOID HwDeviceExtension,
    IN PSTOR_SYNCHRONIZED_ACCESS SynchronizedAccessRoutine
    IN PVOID Context
    );

Note: For better performance, write your driver to spend less time executing the synchronized access routine.

Scatter-Gather Lists

The SCSI port driver has complete access to a set of scatter-gather list structures that define the memory ranges and physical addresses of an I/O request. Although the port driver has this information, the current architecture forces a miniport driver to manually discover and build its own scatter-gather list structure (STOR_SCATTER_GATHER_LIST) through repeated calls to the StorPortGetPhysicalAddress function. This strategy is wasteful both in terms of the number of machine instruction and in terms of code complexity. Instead, the STOR port driver, provides the miniport driver with access to the system's scatter-gather list structure directly, reducing the number of calls the miniport has to make into the port driver to build its private scatter-gather data structures.

Miniports use the following call to obtain a scatter-gather list for a specific SRB:

struct STOR_SCATTER_GATHER_ELEMENT {
    STOR_PHYSICAL_ADDRESS PhysicalAddress;
    ULONG Length;
    ULONG_PTR Reserved;
};

struct STOR_SCATTER_GATHER_LIST {
    ULONG NumberOfElements;
    ULONG_PTR Reserved;
    STOR_SCATTER_GATHER_ELEMENT List[];
};

PSTOR_SCATTER_GATHER_LIST
StorPortGetScatterGatherList(
    IN PVOID DeviceExtension,
  IN PSCSI_REQUEST_BLOCK Srb
    );

The scatter-gather list that is returned is valid only until the request is completed. The memory for the scatter-gather list does not otherwise have to be freed or released.

Performance Hint: The miniport should perform any necessary translation of the STORPORT-supplied scatter-gather list to a miniport specific format in the miniport's HwBuildIo routine.

Mapping Buffers

Setting MapBuffers to TRUE in the PORT_CONFIGURATION_INFORMATION structure requires the port driver to allocate and map a range of system virtual memory for all I/O buffers. This requires an extra per-request allocation that runs through an expensive path in the system. Since STORPORT miniports are required to support DMA-based I/O, few if any miniports will need to access the SRB's data buffer through a system-wide virtual address for standard read and write requests. With this in mind, STORPORT defines new values for the MapBuffers member:

STOR_MAP_NO_BUFFERS = 0
STOR_MAP_ALL_BUFFERS = 1
STOR_MAP_NON_READ_WRITE_BUFFERS = 2

Mapping non-read/write buffers provides fast access to the important SCSI requests—the read and write requests—while permitting miniports to continue to emulate non-read/write requests. When mapping non-read/write buffers, the following SCSI operations must be executed without accessing the underlying memory for the request through virtual memory:

SCSIOP_READ
SCSIOP_WRITE
SCSIOP_READ6
SCSIOP_WRITE6

Queue Management

The SCSI port driver exposed little support for explicit queue management. Newer non-SCSI buses and higher performance buses need better queue management. The miniport driver requires more access to the device queues, with the ability to pause and resume queues for a variety of conditions. In STORPORT, several queue management primitives are exposed to the miniport, giving them more control over how items are queued to their devices.

The STORPORT queue model is as follows. All requests are queued in the port driver on per-logical-unit queues. Each logical unit can have a maximum of 254 outstanding requests, and when this request limit is reached, further requests to that logical unit are held by STORPORT until the number of outstanding requests to the logical unit drops below 254. There are no explicit limits on the number of requests that can be outstanding to an adapter, although the limit of 254 per logical unit is maintained. For example, an adapter with 55 logical-units attached to it could post up to a maximum of 13,970 (55 × 254) requests to storage devices at one time. See the following diagram for a description of the port driver's queuing model.

If the adapter itself is ready to receive a request, when a logical unit is ready to receive a request, the miniport's HwBuildIo routine and HwStartIo routines are invoked in order.

Unlike SCSIPORT, STORPORT allows miniports to signal the port driver about busy conditions. These communications are handled by the following eight routines, which allow the miniport to signal when either the logical unit or the adapter is paused or busy. While a device is paused or busy, no requests are sent to the device. Any request that is completed with busy status (SRB_STATUS_BUSY and SCSISTAT_BUSY) will be retried indefinitely until it is completed or is failed by the device.

StorPortPauseDevice – Pause a device for a specified period of time.

StorPortResumeDevice – Resume a paused device.

StorPortPause – Pause an adapter for a specified period of time.

StorPortResume – Resume a paused adapter.

StorPortDeviceBusy – Make a device busy until the device queue has completed a specified number of I/O requests.

StorPortDeviceReady – Make a busy device ready to receive requests again.

StorPortBusy – Make an adapter busy until it has completed a specified number of I/O requests.

StorPortReady – Make a busy adapter ready to receive requests again.

In addition adding to the explicit queue management routines, the STOR port driver removes some of the implicit queue management routines. The NextRequest and NextLuRequest notifications will be ignored.

Error Management

The following sections describe how STORPORT.SYS manages errors.

Multi-tier Reset

The STOR port driver implements a more advanced reset scheme than SCSIPORT. Resetting the entire bus is an expensive operation, even under SCSI; on advanced buses such as Fiber Channel, a bus reset might not be possible. To solve this, STORPORT implements a multi-tier reset operation that allows more control over a reset operation. To support multi-tier reset, miniports must support the reset-device and reset-logical-unit SRB functions described later in this document.

SRB_FUNCTION_DEVICE_RESET
The SCSI target controller should be reset, if possible. The HBA miniport driver should complete any active requests for the target controller. Only the Function, TargetId, and PathId members of the SRB are valid.

SRB_FUNCTION_LOGICAL_UNIT_RESET
The SCSI logical unit should be reset, if possible. The HBA miniport driver should complete any active requests for the logical unit. Only the Function, PathId, TargetId, and Lun members of the SRB are valid.

When possible, the STOR port driver and related higher-level drivers will attempt to reset the logical unit, followed by the device, then followed by the bus. This sequence generates significantly fewer bus-reset operations.

Extended Device Status

The STOR port driver has been extended to understand more transport-specific errors and conditions, such as link down, Fiber Channel SCN, LIP, and so on.

In the future this section will document errors and describe the mechanism used to access errors.

RAID Management Interface

Miniport drivers for host-based RAID devices are required to support the RAID management infrastructure by implementing the WMI management interface described here. Higher-level services such as Microsoft Volume Management software will use these interfaces to query and modify a RAID adapter's storage configuration.

STORPORT exposes a management interface through WMI. WMI is an object-based interface definition language that has native support built into the kernel of all Windows operating systems. The management interface exposes the RAID Management Interface through four WMI classes: a class representing an Adapter, a Disk Array, a Physical Disk, and an I/O Channel on an adapter. See the following figure for a better understanding.

These four classes are described as follows:

  • An adapter (Controller, Card, HBA) is implemented by an instance of the RAID_Adapter class. Multiple adapters of the same type can exist on the system at the same time.
  • A disk array (Logical Drive, Disk Group) is exposed through an instance of the RAID_ DiskArray class. Each adapter can expose zero or more disk arrays at the same time.
  • A physical disk (Spindle, Drive) is exposed through an instance of the RAID_PhysicalDisk class. Each adapter can have zero or more physical disks connected to it. Physical disks are always connected through a single I/O channel.
  • A channel (bus) is exposed through the RAID_IoChannel class. Each adapter has one or more channels that connect it to its physical disks.

The Management Interface section contains a complete Managed Object Format (MOF) file that describes the management interface. For more information on MOF file syntax, see MOF Syntax for WMI Data and Event Blocks

Porting Guide

The STOR port/miniport interface is designed to be as similar to the SCSI port/miniport interface as possible, so porting should be relatively painless. The basic recompilation can be done by changing the include declaration and link library specification as described in the following section. The next section discusses the requirements a SCSI miniport driver needs to meet to be able to target STORPORT. Following that is a description of how to port from SCSIPORT to STORPORT.

Requirements for Using STORPORT with an Adapter

One way the STOR port driver improves performance and enhances stability is by removing support for legacy devices. Support for legacy devices complicates the port driver, slowing down both port-driver development and testing. Following is a list of required features an adapter and its miniport must support to be a candidate to port to STORPORT.

  • Bus-mastering DMA. STORPORT does not support either programmed I/O or slave-mode DMA.
  • Scatter-gather I/O. Drivers must support at least 16 physical breaks in their scatter-gather list implementation. Drivers should be able to support up to 255 physical breaks in the same manner as SCSI miniports.
  • Bus-width DMA. STOR port will not copy memory to perform data transfers. An adapter that runs on a machine that can address more than 32-bits of address space must support 64-bit addressing. For example, an adapter that runs on an IA-32 machine that has Pentium Address Extensions must support full 64-bit addressing.
  • SCSI Tagged Queuing. The STOR port driver will issue up to 254 requests per logical unit. Older miniports that make use of the fact that SCSI port never issued more than 254 requests per adapter must be modified to work correctly under STORPORT.
  • SCSI Auto-request sense. Disabling is not supported.
  • Support for larger sense buffers. STOR miniports must not make assumptions about the size of sense buffers; the size passed in the SRB must be used.
  • Plug and Play. Because STOR miniports must be enabled for Plug and Play, all shared resource acquisition and management is done by the port driver.
  • RAID Management Interface. Miniports for host-based RAID adapters must support the WMI-based RAID Management Interface. For more information about the RAID Management Interface, see the RAID Management Interface section.
  • Booting through optional ROM BIOS if booting from the adapter is supported. The Windows boot loader will not support booting from adapters that do not implement optional ROM BIOS, or adapters with disabled optional ROM BIOS. Current SCSI cards can boot either using the adapter optional ROM BIOS or using a mini SCSI port driver embedded in the Windows boot loader. Booting using the boot loader will not be supported for STOR miniports.
  • Adapters that expose virtual logical units are required to support SCSI Inquiry Vital Product Data pages 00h, 80h, and 83h. For example, a host-based RAID adapter must respond a SCSI Inquiry command with Vital Product Data Page set to 00h (supported vital product data pages), 80h (unit serial number page), and 83h (device identification page). These commands can be handled either by the adapter's firmware or synthesized in the miniport.

Porting to STORPORT

To quickly convert a SCSI port driver to a STOR port driver

  1. Change all instances of SCSI include commands to RAID includes.
    Replace #include <scsi.h> with #include <storport.h> in all source and header files.

    If both the scsi.h and storport.h header files are included, a compile time error will occur.

  2. Replace scsiport.lib with storport.lib in your build scripts, that is, in the sources or makefile file.
  3. Make certain all expanded structures are properly initialized.

    The sizes of both the HW_INITIALIZATION_DATA structure and the PORT_CONFIGURATION_INFORMATION structure have changed, so make certain the new fields are properly initialized.

The STORPORT header file, storport.h, currently retains both ScsiPort-prefixed commands and StorPort-prefixed command to facilitate porting from SCSIPORT.

Hardware Initialization

The STOR port driver follows the SCSI port driver's PnP initialization model. During the driver's DriverEntry routine, the miniport calls the StorPortInitialize routine with a HW_INITIALIZATION_DATA structure describing the hardware it supports. Later, when the Windows 2000 PnP Manager calls the port driver's StartDevice routine, the port driver calls the miniport's HwStorFindAdapter routine with a PORT_CONFIGURATION_INFORMATION structure followed by HwStorInitialize to initialize the adapter.

A STOR miniport's initialization sequence follows the SCSI miniport's initialization sequence very closely. This section discusses the HW_INITIALIZATION_DATA the miniport passes to the port driver's StorPortInitialize routine.

The following list specifies how each member of the STORPORT HW_INITIALIZATION_DATA must be initialized.

HwInitializationDataSize
Specifies the size of the HW_INITIALIZATION_DATA structure in bytes, as returned by sizeof(). This member has the same meaning as in the SCSI port driver.
AdapterInterfaceType
STORPORT does not support legacy buses; therefore, ISA, EISA, MicroChannel, and TurboChannel buses are not supported.
HwInitialize
Pointer to the miniport's HwStorInitialize routine, which is a required entry point for all miniport drivers. This member has the same purpose as in the SCSI port driver.
HwStartIo
Pointer to the miniport's HwStorStartIo routine, which is a required entry point for all miniport drivers. This member has the same purpose as in the SCSI port driver.
HwInterrupt
Pointer to the miniport's HwStorInterrupt routine, which is a required entry point for all miniport drivers. This member has the same purpose as in the SCSI port driver.
HwFindAdapter
Pointer to the miniport's HwStorFindAdapter routine, which is a required entry point for all miniport drivers. This member has the same purpose as in the SCSI port driver.
HwResetBus
Pointer to the miniport's HwStorResetBus routine, which is a required entry point for all miniport drivers. This member has the same purpose as in the SCSI port driver.
DeviceExtensionSize
Specifies the size in bytes required by the miniport driver for its per-adapter device extension. This member has the same purpose as in the SCSI port driver.
SpecificLuExtensionSize
Specifies the size in bytes required by the miniport driver for its per-logical-unit storage, if any. This member has the same purpose as in the SCSI port driver.
SrbExtensionSize
Specifies the size in bytes required by the miniport driver for its per-request storage, if any. Because STORPORT miniports require support of scatter-gather lists, and the per-SRB scatter-gather lists are usually allocated in the SRB extension, this member is rarely zero. This member has the same purpose as in the SCSI port driver.
NumberOfAccessRanges
Specifies how many access ranges the adapter uses. Each is a range either of memory addresses or I/O port addresses. This member has the same purpose as in the SCSI port driver.
MapBuffers
The MapBuffers member is extended in a compatible manner. The STOR port driver does not support mapping system addresses for all I/O requests. Instead, a partial buffer mapping mode is supported. In this mode, all buffers for non-read and write requests have system virtual address mapped for them. The new values are as follows:

STOR_MAP_NO_BUFFERS = 0
STOR_MAP_ALL_BUFFERS = 1
STOR_MAP_NON_READ_WRITE_BUFFERS = 2

SCSI_MAP_NON_READ_WRITE_BUFFERS means that all buffers for non-read and non-write requests are mapped to system virtual address space; that is, the SRB's DataBuffer member is accessible to the miniport.

NeedPhysicalAddresses
STOR miniport drivers must support bus-master DMA, so this member always has a value of TRUE.
TaggedQueuing
STOR miniport drivers must supported tagged queuing, so this member is always has a value of TRUE.
AutoRequestSense
STOR miniport drivers must support SCSI Auto-Request Sense, so this members always has a value of TRUE.
MultipleRequestsPerLu
STOR miniport drivers must support SCSI tagged queuing, so this member is always has a value of TRUE.
HwAdapterControl
Pointer to the miniport's HwStorAdapterControl routine. Because STOR miniport drivers require PnP support, this is a required routine.
HwBuildIo
Pointer to an optional HwStorBuildIo routine that is invoked prior to the miniport's HwStorStartIo routine. The implementation of this routine is described in the Unsynchronized HwBuildIo Routine section later in this document.

The following members of the HW_INITIALIZATION_DATA structure are not used by the STOR port driver, and should be initialized to zero.

VendorIdLength
Because STOR miniport drivers must support PnP, this member is ignored.
VendorId
Because STOR miniport drivers must support PnP, this member is ignored.
DeviceIdLength
Because STOR miniport drivers must support PnP, this member is ignored.
DeviceId
BecauseSTOR miniport drivers must support PnP, this member is ignored.
ReceiveEvent
The STOR port driver ignores this member.
HwAdapterState
STORPORT does not support legacy drivers; therefore, this member must be NULL.
HwDmaStarted
STORPORT does not support slave-mode DMA; therefore, this member must be NULL.

FindAdapter and Port Configuration Information

When the Windows 2000 PnP manager discovers hardware associated with the driver, it notifies the STOR port driver to start its associated device. Next, the port driver calls the miniport driver's HwStorFindAdapter routine, passing in a PORT_CONFIGURATION_INFORMATION structure.

In a PnP driver, HwStorFindAdapter does not physically search for the adapter; instead, the miniport should check if the adapter can be initialized using the parameters specified in the PORT_CONFIGURATION_INFORMATION structure, and should store any values of the port configuration structure that might be required for device extension.

The following list specifies how each member of the miniport's PORT_CONFIGURATION_INFORMATION structure should be used.

Length
Specifies the size of the PORT_CONFIGURATION_INFORMATION structure in bytes, as returned by sizeof(). In effect, this member, which is always initialized by a port driver specific to the operating system, indicates the version of this structure used by the port driver. This member has the same purpose as in the SCSI port driver.
MaximumTransferLength
Specifies the maximum number of bytes the HBA can transfer in a single transfer operation. By default, the value of this member is SP_UNINITIALIZED_VALUE, which indicates an unlimited maximum transfer size. This member has the same purpose as in the SCSI port driver.
NumberOfPhysicalBreaks
Specifies the maximum number of breaks between address ranges that a data buffer can have for the creation of scatter-gather lists. In other words, the number of scatter-gather lists entries the adapter can support minus one. This member has the same purpose as in the SCSI port driver.
AlignmentMask
Is a mask indicating the alignment boundary for buffers required by the adapter for transfer operations. A miniport driver should set this mask to indicate any alignment restrictions on scatter-gather buffer pointers if the adapter supports scatter-gather. This member has the same purpose as in the SCSI port driver.
NumberOfBuses
Specifies the number of buses controlled by the adapter. By default, the value of this member is zero. This member has the same purpose as in the SCSI port driver.
CachesData
TRUE indicates the adapter caches data or maintains cached state on the peripherals. By default, the value of this member is FALSE. If this is set to TRUE, the operating system-specific port driver notifies the miniport driver when certain system events occur, such as file system cache flushes and system shutdown. This member has the same purpose as in the SCSI port driver.
AdapterScansDown
TRUE indicates the BIOS for the HBA scans for SCSI bus targets from seven to zero. By default, the value of this member is FALSE. This member has the same purpose as in the SCSI port driver.
MaximumNumberOfTargets
Specifies the number of target peripherals the adapter can control. By default, the value of this member is initialized to SCSI_MAXIMUM_TARGETS. A miniport can set this member to a lesser value if the HBA has more limited capabilities or to a greater value, indicating that the HBA has wide-SCSI or Fiber Channel capabilities. This member has the same purpose as in the SCSI port driver.
DeviceExtensionSize
Specifies the size in bytes required by the miniport driver for its per-adapter extension. This member has the same purpose as in the SCSI port driver.
SpecificLuExtensionSize
Specifies the size in bytes required by the miniport driver for its per-logical-unit extension. This member has the same purpose as in the SCSI port driver.
SrbExtensionSize
Specifies the size in bytes required by the miniport driver for its per-request storage. This member has the same purpose as in the SCSI port driver.
MapBuffers
Specifies whether the miniport required data buffers to be mapped to system virtual memory or not. For more information on buffer mappings, see the "Mapping Buffers" section.
ResetTargetSupported
TRUE indicates that the miniport driver has the ability to reset a target device in response to an SRB_FUNCTION_RESET_DEVICE request from the port driver. By default, the value of this member is FALSE. This member has the same purpose as in the SCSI port driver.
MaximumNumberOfLogicalUnits
Specifies the maximum number of logical units per target the HBA can control. By default, the value of this member is SCSI_MAXIMUM_LOGICAL_UNITS. This member has the same purpose as in the SCSI port driver.
SynchronizationModel
Specifies the I/O synchronization model the miniport driver supports, either full-duplex mode or half-duplex-mode. For more information, see the "Full-Duplex Mode" section.

Because the STOR port driver targets only PnP-capable adapters, and due to other restrictions of STOR port driver, the members of the PORT_CONFIGURATION_INFORMATION structure that can be written to under the SCSI port driver are read-only when running under the STOR port driver. These members follow:

SystemIoBusNumber
Initialized by the STOR port driver, not modified by the miniport driver. This member has the same purpose as in the SCSI port driver.
AdapterInterfaceType
Initialized by the STOR port driver, not modified by the miniport driver. This member has the same purpose as in the SCSI port driver.
BusInterruptLevel
Initialized by the STOR port driver, not modified by the miniport driver.
BusInterruptVector
Initialized by the STOR port driver, not modified by the miniport driver.
InterruptMode
Initialized by the STOR port driver, not modified by the miniport driver.
DmaChannel
Initialized by the STOR port driver, not modified by the miniport driver.
DmaPort
Initialized by the STOR port driver, not modified by the miniport driver.
DmaWidth
Initialized by the STOR port driver, not modified by the miniport driver.
DmaSpeed
Initialized by the STOR port driver, not modified by the miniport driver.
AccessRanges
Initialized by the STOR port driver, not modified by the miniport driver.
InitiatorBusId
Initialized by the STOR port driver, not modified by the miniport driver.
ScatterGather
Because STORPORT miniports must support scatter-gather, this member is initialized to TRUE by the STOR port driver and cannot be modified by the miniport.
Master
Because STORPORT miniports must support bus mastering DMA, this member is initialized to TRUE by the STOR port driver and cannot be modified by the miniport.
AtdiskPrimaryClaimed
The STOR port driver does not use this member.
AtdiskSecondaryClaimed
The STOR port driver does not use this member.
Dma32BitAddresses
Because STORPORT miniports must support bus-width DMA, this value will always be TRUE and is not modifiable by the miniport.
DemandMode
Because the STOR port driver does not support slave-mode DMA, this member is always initialized to FALSE and cannot be modified by the miniport.
NeedPhysicalAddresses
Because STORPORT miniports must support scatter/gather lists, this member is initialized to TRUE by the port driver and cannot be modified by the miniport.
TaggedQueuing
Because miniports must support tagged-queuing, this member is initialized to TRUE by the port driver and cannot be modified by the miniport.
AutoRequestSense
STORPORT miniport drivers must support auto-request sense, so this member is initialized to TRUE. It cannot be modified by the miniport.
MultipleRequestPerLu
STORPORT miniports must support multiple requests issued to a logical unit at time. For more information on queuing, see the Queue Management section.
ReceiveEvent
This member is not used by the STOR port driver and is always FALSE.
RealModeInitialized
This member is not used by the STOR port driver and is always FALSE.
BufferAccessScsiPortControlled
Ignored by the STOR port driver, always TRUE.
SlotNumber
Initialized by the STOR port driver, not modifiable by the miniport.
BusInterruptLevel2
Initialized by the STOR port driver, not modifiable by the miniport driver.
BusInterruptVector2
Initialized by the STOR port driver, not modifiable by the miniport.
InterruptMode2
Initialized by the STOR port driver, not modifiable by the miniport.
DmaChannel2
Initialized by the STOR port driver, not modifiable by the miniport.
DmaPort2
Initialized by the STOR port driver, not modifiable by the miniport.
DmaWidth2
Initialized by the STOR port driver, not modifiable by the miniport.
DmaSpeed2
Initialized by the STOR port driver, not modifiable by the miniport.
Dma64BitAddresses
STOR port adapters are required to support bus-width DMA, therefore, any adapter that runs on a 64-bit machine or a PAE machine should initialize this value to SCSI_DMA64_MINIPORT_SUPPORTED.
WmiDataProvider
STOR miniports are required to support the basic WMI infrastructure; therefore this member will always be TRUE. Additionally, STOR miniports for Fiber Channel adapters are expected to support the SAN Management HBA API through WMI. STOR miniports for host-based RAID adapters are required to support the RAID Management Interface.

Techniques

This section discusses the important features of the STOR port driver, focusing on the differences between STORPORT and SCSIPORT.

STORPORT miniport drivers must always be prepared to receive another I/O request after their HwStorStartIo routine has completed. A miniport that works with SCSI port would explicitly signal the port driver that it is prepared to handle another request using the StorPortNotification function, passing in either NextRequest or NextLuRequest. A miniport that works with STORPORT, on the other hand, must be prepared to receive another request as soon as its HwStorStartIo routine completes.

If the miniport cannot handle the request at the time it is submitted, it should use the queue management functions to mark the device queue as busy and complete the request with SRB_STATUS_BUSY.

Miniport Interface

A STOR miniport driver is responsible for implementing the following interface and exposing it through its HW_INITIALIZATION_DATA structure when initializing.

HwStorInitialize

Initialize the miniport after a reboot or power failure occurs.

BOOLEAN
  HwStorInitialize(
    IN PVOID  DeviceExtension
    );

Comments

This function provides the same functionality as as HwScsiInitialize. For more information, see the Windows DDK.

HwStorStartIo

The port driver supplied by the operating system calls HwStorStartIo one time for each incoming I/O request.

BOOLEAN
  HwStorStartIo(
    IN PVOID  DeviceExtension,
    IN PSCSI_REQUEST_BLOICK  Srb
    );

Comments

This function has the same functionality as HwScsiStartIo. For more information, see the Windows DDK.

HwStorInterrupt

The port driver supplied by the operating system calls HwStorInterrupt after the HBA generates an interrupt. Since the STOR port driver does not support programmed I/O, this function is required for all STOR miniport drivers.

BOOLEAN
  HwStorInterrupt(
    IN PVOID  DeviceExtension
    );

Comments

STORPORT does not support the SCSI CallEnableInterrupts or CallDisableInterrupts notifications. If a miniport cannot process its interrupt quickly, it should use the SCSI port driver instead.

For more information, see HwScsiInterrupt in the Windows DDK.

HwStorFindAdapter

HwStorFindAdapter uses the supplied configuration to determine whether a specific HBA is supported and, if so, to return configuration information about that adapter.

BOOLEAN
  HwStorFindAdapter(
    IN PVOID  DeviceExtension,
    PVOID  Reserved1,
    PVOID  Reserved2,
    IN PVOID  ArgumentString,
    IN OUT PPORT_CONFIGURATION_INFORMATION  PortConfiguration,
    PUCHAR  Reserved3
    );

Parameters

DeviceExtension
Supplies a per-adapter storage area.
Reserved1, Reserved2, Reserved3
Reserved parameters, do not use.
ArgumentString
Supplies a NULL-terminated string with context information about the driver.
PortConfiguration
Supplies an initialized PORT_CONFIGURATION_INFORMATION structure that the miniport uses during initialization. For further discussion about what fields the port driver initializes, and what fields need to be initialized by the miniport, see the "FindAdapter and Port Configuration Information section".

Comments

Because the STOR port driver supports only PnP devices, the HwContext, BusInformation and Again parameters to HwStorFindAdapter are not supplied to a STOR miniport driver. Furthermore, the PORT_CONFIGURATION_INFORMATION structure will always fully specify all adapter resources required to start the adapter. Unlike HwScsiFindAdapter, miniport writers should not supply default parameters if those provided in the PORT_CONFIGURATION_INFORMATION structure are incorrect.

For more information, see HwScsiFindAdapter.

HwStorResetBus

Resets a given SCSI bus.

BOOLEAN
  HwStorResetBus(
    IN PVOID  DeviceExtension,
    IN ULONG  PathId
    );

Comments

For more information, see HwScsiResetBus.

HwStorAdapterControl

A miniport driver's HwStorAdapterControl routine is called to perform synchronous operations to control the state or behavior of an adapter, such as stopping or restarting the HBA for power management.

BOOLEAN
  HwStorAdapterControl(
    IN PVOID  DeviceExtension,
    IN SCSI_ADAPTER_CONTROL_TYPE  ControlType,
    IN PVOID  Parameters
    );

Parameters

ControlType specifies one of the following:

ScsiQuerySupportedControlTypes – Required.

ScsiStopAdapter – Required.

ScsiRestartAdapter – Required.

ScsiSetBootConfig – Not used.

ScsiSetRunningConfig – Not used.

Comments

Because STOR miniport drivers must support PnP, this function is required for all STORPORT miniport drivers. The control types ScsiStopAdapter and ScsiRestartAdapter must be supported.

Port Interface

The STOR port/miniport interface is the set of functions STOR miniport drivers use to implement their driver. As with all miniport drivers, general-purpose Windows DDK functions should not be used. Instead, by using the functions exposed by the port driver, the authors of the miniport driver can ensure the miniport is compatible with newer versions of the Windows operating systems.

StorPortInitialize

StorPortInitilize initializes the operating system-supplied STORPORT driver, saving the HwInitializationData value for use later when initializing the adapter. This routine must be called from the miniport's DriverEntry routine.

ULONG
  StorPortInitialize(
    IN PVOID  Argument1,
    IN PVOID  Argument2,
    IN PHW_INITIALIZATION_DATA  HwInitializationData,
    IN PVOID  Unused
    );

Comments

For more information, see ScsiPortInitialize. Because STOR miniport drivers must support PnP, the STOR port driver does not use the HwContext parameter passed to ScsiPortInitialize.

StorPortFreeDeviceBase

Frees a range of device I/O memory that was mapped by StorPortGetDeviceBase.

VOID
  StorPortFreeDeviceBase(
    IN PVOID  HwDeviceExtension,
    IN PVOID  MappedAddress
    );

Comments

For more information, see ScsiPortFreeDeviceBase.

StorPortGetBusData

Retrieve the bus-specific configuration information necessary to initialize the HBA.

ULONG
  StorPortGetBusData(
    IN PVOID  DeviceExtension,
    IN ULONG  BusDataType,
    IN ULONG  SystemIoBusNumber,
    IN ULONG  SlotNumber,
    IN PVOID  Buffer,
    IN ULONG  Length
    );

Comments

For more information, see ScsiPortGetBusData.

StorPortSetBusDataByOffset

Write bus-specific configuration information.

ULONG
  StorPortSetBusDataByOffset(
    IN PVOID  DeviceExtension,
    IN ULONG   BusDataType,
    IN ULONG  SystemIoBusNumber,
    IN ULONG  SlotNumber,
    IN PVOID  Buffer,
    IN ULONG  Offset,
    IN ULONG  Length
    );

Comments

For more information, see ScsiPortSetBusDataByOffset.

StorPortGetDeviceBase

StorPortGetDeviceBase is used to map an I/O address to system address space prior to reading or writing to the port/register.

PVOID
  StorPortGetDeviceBase(
    IN PVOID  HwDeviceExtension,
    IN INTERFACE_TYPE  BusType,
    IN ULONG  SystemIoBusNumber,
    IN SCSI_PHYSICAL_ADDRESS  IoAddress,
    IN ULONG  NumberOfBytes,
    IN BOOLEAN  InIoSpace
    );

Comments

This routine supports only addresses that were assigned to the driver by the system PnP manager.

For more information, see ScsiPortGetDeviceBase.

StorPortGetLogicalUnit

Return a pointer to the miniport's per-logical-unit storage area.

PVOID
  StorPortGetLogicalUnit(
    IN PVOID  HwDeviceExtension,
    IN UCHAR  PathId,
    IN UCHAR  TargetId,
    IN UCHAR  Lun
    );

Comments

For more information, see ScsiPortGetLogicalUnit.

StorPortGetSrb

Not implemented in the STORPORT driver.

PSCSI_REQUEST_BLOCK
  StorPortGetSrb(
    IN PVOID  DeviceExtension,
    IN UCHAR  PathId,
    IN UCHAR  TargetId,
    IN UCHAR  Lun,
    IN LONG  QueueTag
    );

StorPortGetPhysicalAddress

Convert a given virtual address range to a physical address range for a DMA operation.

STOR_PHYSICAL_ADDRESS
  StorPortGetPhysicalAddress(
    IN PVOID  HwDeviceExtension,
    IN PSCSI_REQUEST_BLOCK  Srb,
    IN PVOID  VirtualAddress,
    OUT ULONG  *Length
    );

Comments

For more information, see ScsiPortGetPhysicalAddress in the Windows DDK.

StorPortGetVirtualAddress

Retrieve a virtual address that maps to a given physical address. The physical address must be an address that is obtained through a call to StorPortGetPhysicalAddress.

PVOID
  StorPortGetVirtualAddress(
    IN PVOID  HwDeviceExtension,
    IN STOR_PHYSICAL_ADDRESS  PhysicalAddress
    );

Comments

For more information, see ScsiPortGetVirtualAddress.

StorPortGetUncachedExtension

Allocate an uncached common buffer to be shared by the CPU and the device. Bus-master devices use common buffer space for DMA transfers.

PVOID
StorPortGetUncachedExtension(
    IN PVOID HwDeviceExtension,
    IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
    IN ULONG NumberOfBytes
    );

Comments

For more information, see ScsiPortGetUncachedExtension.

StorPortNotification

Notify the operating system-supplied port driver of certain events.

VOID
  StorPortNotification(
    IN SCSI_NOTIFICATION_TYPE  NotificationType,
    IN PVOID  HwDeviceExtension,
    ...
    );

NotificationType can be:

RequestComplete – Same as SCSI port.

ResetDetected – Same as SCSI port.

NextRequest – Not necessary. The STOR port driver is written with the assumption that the miniport driver will be ready to process the next request as soon as it returns from its HwStorStartIo routine. Therefore, this request is not necessary.

NextLuRequest – Not necessary.

CallDisableInterrupts – Not supported.

CallEnableInterrupts – Not supported.

RequestTimerCall – Has the same meaning that it has when used with SCSI port.

WMIEvent – Has the same meaning that it has when used with SCSI port.

WMIRegister – Has the same meaning that it has when used with SCSI port.

Comments

The NextRequest and NextLuRequest values are not necessary. The CallDisableInterrupts and CallEnableInterrupts flags are not supported.

StorPortLogError

Notify the port driver that an error occurred. The port driver will log an error to the system event log.

VOID
  StorPortLogError(
    IN PVOID  HwDeviceExtension,
    IN PSCSI_REQUEST_BLOCK  Srb OPTIONAL,
    IN UCHAR  PathId,
    IN UCHAR  TargetId,
    IN UCHAR  Lun,
    IN ULONG  ErrorCode,
    IN ULONG  UniqueId
    );

Comments

For more information, see ScsiPortLogError.

StorPortCompleteRequest

Complete all outstanding requests setting the SRB status value to SrbStatus.

VOID
  StorPortCompleteRequest(
    IN PVOID  HwDeviceExtension,
    IN UCHAR  PathId,
    IN UCHAR  TargetId,
    IN UCHAR  Lun,
    IN UCHAR  SrbStatus
    );

Comments

For more information, see ScsiPortCompleteRequest.

StorPortMoveMemory

Copy memory from one buffer to another.

VOID
  StorPortMoveMemory(
    IN PVOID  WriteBuffer,
    IN PVOID  ReadBuffer,
    IN ULONG  Length
    );

Comments

For more information, see ScsiPortMoveMemory.

StorPortStallExecution

Stall the miniport driver.

VOID
  StorPortStallExecution(
    IN ULONG  Delay
    );

Comments

This function has the same effect as ScsiPortStallExecution

StorPortConvertUlong64ToPhysicalAddress

Convert a ULONG64 value to a physical address.

STOR_PHYSICAL_ADDRESS
  StorPortConvertUlong64ToPhysicalAddress(
    IN ULONG64  UlongAddress
    );

Comments

For more information, see ScsiPortConvertUlongToPhysicalAddress. All addresses in STORPORT are expressed as 64-bit values.

StorPortConvertPhysicalAddressToUlong64

Convert a STOR_PHYSICAL_ADDRESS address to a ULONG64 value.

ULONG64
  StorPortConvertPhysicalAddressToUlong64(
    IN STOR_PHYSICAL_ADDRESS  Address
    );

Comments

For more information, see ScsiPortConvertPhysicalAddressToUlong. All addresses in STORPORT are expressed as 64-bit values.

StorPortValidateRange

This function is not implemented by STORPORT.

BOOLEAN
  StorPortValidateRange(
    IN PVOID  HwDeviceExtension,
    IN INTERFACE_TYPE  BusType,
    IN ULONG  SystemIoBusNumber,
    IN STOR_PHYSICAL_ADDRESS  IoAddress,
    IN ULONG  NumberOfBytes,
    IN BOOLEAN  InIoSpace
    );

StorPortDebugPrint

Print a debug string to the kernel debugger, if the debugger is attached.

VOID
  StorPortDebugPrint(
    IN ULONG  DebugPrintLevel,
    IN PCCHAR  DebugMessage,
    ...
    );

Comments

To see these debug strings, the driver writer must set nt!kd_storport_mask. This follows the new system-wide debug print mechanism.

StorPortReadPortXXXX

Read a value from a specified port address. The type (XXXX value above) can be ULONG, USHORT, or UCHAR. A buffered version is also supported.

XXXX
  StorPortReadPortXXXX(
    IN PUCHAR  Port
    );

Comments

For more information, see the routines ScsiPortReadPortXXX. For instance, ScsiPortReadPortBufferUchar, ScsiPortReadPortBufferUlong, ScsiPortReadPortBufferUshort, etc..

StorPortReadRegisterXXXX

Read a value from a specified register address. The type can be ULONG, USHORT, or UCHAR. A buffered version is also supported.

XXXX
  StorPortReadRegisterXXXX(
    IN PUCHAR  Register
    );

Comments

For more information, see the routines ScsiPortReadRegisterBufferXXX. For instance, ScsiPortReadRegisterBufferUchar, ScsiPortReadRegisterBufferUlong, etc..

StorPortWritePortXXXX

Write a value to a specified register address. The type can be ULONG, USHORT, or UCHAR. A buffered version is also supported.

VOID
  StorPortWritePortXXXX(
    IN PUCHAR  Port,
    IN UCHAR  Value
    );

Comments

For more information, see the routines ScsiPortWritePortXXX. For instance, ScsiPortWritePortUchar, ScsiPortWritePortUlong, etc.

StorPortWriteRegisterXXXX

Write a value to a specified register address. The type can be ULONG, USHORT, or UCHAR. A buffered version is also supported.

VOID
  StorPortWriteRegisterXXXX(
    IN PUCHAR  Register,
    IN UCHAR  Value
    );

Comments

For more information, see ScsiPortWriteRegisterBufferXXXX.For instance, see ScsiPortWriteRegisterBufferUchar, ScsiPortWriteRegisterBufferUlong, etc.

StorPortPauseDevice

Pauses a specific logical unit device for some period of time. When the time-out expires, I/O requests will be resumed to the device.

BOOLEAN
  StorPortPauseDevice(
    IN PVOID  HwDeviceExtension,
    IN UCHAR  PathId,
    IN UCHAR  TargetId,
    IN UCHAR  Lun
    IN ULONG  TimeOut
    );

StorPortResumeDevice

Resume a previously paused logical unit.

BOOLEAN
  StorPortResumeDevice(
    IN PVOID  HwDeviceExtension,
    IN UCHAR  PathId,
    IN UCHAR  TargetId,
    IN UCHAR  Lun
    );

Comments

For more information, see StorPortPauseDevice.

StorPortPause

Pause an adapter for a specified period of time. All requests to the adapter are held until the time-out expires or the device resumes. All requests to all targets attached to the adapter will be held until the adapter is resumed or the time-out expires.

BOOLEAN
  StorPortPause(
    IN PVOID  HwDeviceExtension,
    IN ULONG  TimeOut
    );

Comments

Pausing a device does not imply an error.

Parameters

HwDeviceExtension
Device extension of the adapter to pause.
TimeOut
The time-out interval to be applied to the adapter. Specified in seconds.

StorPortResume

Resume a paused adapter.

BOOLEAN
  StorPortResume(
    IN PVOID  HwDeviceExtension
    );

Comments

For more information, see StorPortPause.

StorPortDeviceBusy

Notify the port driver that the specified logical unit is currently busy handling outstanding requests. The port driver will not issue any new requests to the logical unit until the logical unit's queue has been drained to a sufficient level where processing can continue.

BOOLEAN
  StorPortDeviceBusy(
    IN PVOID  HwDeviceExtension,
    IN UCHAR  PathId,
    IN UCHAR  TargetId,
    IN UCHAR  Lun,
    IN ULONG  RequestsToComplete
    );

Comments

This is not considered an error; no error log is generated.

StorPortDeviceReady

Notify the port driver that the device is again ready to handle new requests. It is not generally necessary to notify the target that new requests are desired.

BOOLEAN
  StorPortDeviceReady(
    IN PVOID  HwDeviceExtension,
    IN UCHAR  PathId,
    IN UCHAR  TargetId,
    IN UCHAR  Lun
    );

StorPortBusy

Notify the port driver that the adapter is currently busy handling outstanding requests. The port driver will hold any requests until the adapter has completed enough outstanding requests so that it may continue processing requests.

BOOLEAN
  StorPortBusy(
    IN PVOID  HwDeviceExtension,
    IN ULONG  RequestsToComplete
    );

Parameters

HwDeviceExtension
Device extension for the miniport.
RequestsToComplete
The number of requests that the adapter must complete before resuming I/O requests to the miniport. If RequestsToComplete is greater than the number of currently outstanding requests, the port driver will complete all outstanding requests to the adapter before resuming requests. If RequestsToComplete is (ULONG) –1, requests will not be resumed until the driver calls StorPortReady().

StorPortReady

Notify the port driver that the adapter is no longer busy.

BOOLEAN
  StorPortReady(
    IN PVOID  HwDeviceExtension
    );

StorPortGetScatterGatherList

Retrieve the associated scatter-gather list for the specified SRB. The pointer to the scatter-gather list that is returned is valid only until the request is completed. The memory for the scatter-gather list that is returned does not otherwise need to be freed. The miniport driver must not modify the returned scatter-gather list.

PSTOR_SCATTER_GATHER_LIST
  StorPortGetScatterGatherList(
    DeviceExtension,
    IN PSCSI_REQUEST_BLOCK Srb
    );

Comments

This routine is new to the STOR port driver.

StorPortSynchronizeAccess

Provide synchronized access to a miniport's device extension. Miniports that operate in full-duplex mode, and that access information that is shared between their HwStartIo routine and interrupt-service routine, must use this routine to access the shared data in a synchronized manner.

VOID
  StorPortSynchronizeAccess(
    IN PVOID  HwDeviceExtension,
    IN PSTOR_SYNCHRONIZED_ACCESS  SynchronizedAccessRoutine
    IN PVOID  Context
    );

Comments

For more information on synchronization routines, see KeSynchronizeExecution.

Management Interface

 [WMI,
 Dynamic,
 Provider("WmiProv"),
 Locale("MS\\0x409"),
 guid("984562c8-f94d-4945-ba1c-c3169f9c59ec"),
 Description ("An abstraction representing a single instance a RAID Adapter "
         "card attached to the system.")]

class RAID_Adapter {

  //
  // Required members for all WMI classes.
  //

  [key, read]
  string InstanceName;

  [read]
  boolean Active;

  //
  // Human readable product information about the card.
  //

  [read, WmiDataId(1)]
  string Manufacturer;

  [read, WmiDataId(2)]
  string Product;

  [read, WmiDataId(3)]
  string Revision;

  //
  // List of disk arrays configured for this adapter.
  //

  [read, WmiDataId(4)]
  uint32 DiskArrayCount;

  [read, WmiSizeIs("DiskArrayCount"), WmiDataId(5)]
  RAID_DiskArray Arrays[];

  //
  // List of physical disks attached to this adapter.
  //

  [read, WmiDataId(6)]
  uint32 PhysicalDiskCount;

  [read, WmiSizeIs("PhysicalDiskCount"), WmiDataId(7)]
  RAID_PhysicalDisk PhysicalDisks[];

  //
  // Methods
  //

  [Implemented,
   WmiMethodId(1),
   Description ("Create an empty disk array.")]
  boolean
  CreateArray(
    [out] RAID_DiskArray NewArray);

  [Implemented,
   WmiMethodId(2),
   Description ("Delete an existing disk array.")]
  boolean
  DeleteArray(
    [in] RAID_DiskArray Array);
};

[WMI,
 Dynamic,
 Locale("MS\\0x409"),
 Provider("WMIProv"),
 guid("4a70077a-51af-48c6-a290-0b7203e37ecf"),
 Description ("An abstraction representing a single disk array or logical unit "
        "exposed by a RAID adapter.")]
class RAID_DiskArray {

  //
  // Required members for WMI classes.
  //

  [key, read]
  string InstanceName;

  [read]
  boolean Active;

  [read, WmiDataId(1)]
  uint64 Size;

  [read, WmiDataId(2)]
  uint32 StripeSize;

  //
  // Note: the write policy is dynamically configurable.
  //

  [read, write, WmiDataId(3),
   Values{"Write Back", "Write Through"},
   DefineValues{"RAID_WritePolicy_WriteBack",
           "RAID_WritePolicy_WriteThrough"},
   ValueMap{"0", "1"}]
  uint32 WritePolicy;

  //
  // Note: the read policy is dynamically configurable.
  //

  [read, write, WmiDataId(4),
   Values{"Normal", "Adaptive"},
   DefinedValues{"RAID_ReadPolicy_Normal",
            "RAID_ReadPolicy_Adaptive"},
   ValueMap{"0", "1"}]
  uint32 ReadPolicy;

  //
  // Note: the cache policy is dynamically configurable.
  //

  [read, write, WmiDataId(5),
   Values {"Cache Enabled", "Cache Disabled"},
   DefinedValues {"RAID_CachePolicy_CachedIo",
           "RAID_CachePolicy_DirectIo"},
   ValueMap {"0", "1"}]
  uint32 CachePolicy;

  [read, write,
   Description ("Should the array be automatically rebuilt on failure."),
   WmiDataid(6)]
  boolean AutoRebuild;

  [read, WmiDataId(7),

   Values{"Not configured",
          "Just a bunch of disks (Spanning)",
      "Raid Level 0 (Striping)",
      "Raid Level 1 (Mirroring)",
      "Raid Level 3 (Striping with Dedicated Parity)",
      "Raid Level 5 (Striping with Distributed Parity)",
      "Raid Level 0+1 (Striping with Mirroring)",
      "Raid Level 0+3 (Striping with RAID 3)",
      "Raid Level 0+5 (Striping with RAID 5)"},

   DefineValues{"RAID_Redundancy_NotConfigured",
           "RAID_Redundancy_JBOD",
           "RAID_Redundancy_Raid0",
           "RAID_Redundancy_Raid1",
           "RAID_Redundancy_Raid3",
           "RAID_Redundancy_Raid5"
          "RAID_Redundancy_Raid10",
          "RAID_Redundancy_Raid30",
          "RAID_Redundancy_Raid50"},

   ValueMap{"-2", "-1", "0", "1", "3", "5", "10", "30", "50"}]

  sint32 Redundancy;

  //
  // List of physical disks that form this logical disk.
  //

  [read, WmiDataId(8)]
  uint32 PhysicalDiskCount;

  [read, WmiSizeIs("PhysicalDiskCount"), WmiDataId(9)]
  RAID_PhysicalDisk PhysicalDisks[];

  //
  // Methods for configuring the array.
  //

  [implemented, WmiMethodId(1),
   Description ("Configure the array.")]
   boolean
   Configure(
     [in] sint32 Redundancy,
    [in] uint64 Size,
    [in] uint32 StripeWidth
    );

  [Implemented, WmiMethodId(2)]
  boolean
  DeleteConfiguration(
    );

  [Implemented, WmiMethodId(3),
   Description ("Assign a physical disk to an array. If the array "
           "has already been configured, extend the array to "
          "include the disk (if possible). Otherwise, add "
          "the disk as a data member.")]
  boolean
  AddDataDisk(
    [in] RAID_PhysicalDisk PhysicalDisk
    );

  [Implemented, WmiMethodId(4)]
  boolean
  RemoveDataDisk(
    [in] RAID_PhysicalDisk PhysicalDisk
    );

  [Implemented, WmiMethodId(5)]
  boolean
  AddSpareDisk(
    [in] RAID_PhysicalDisk PhysicalDisk
    );

  [Implemented, WmiMethodId(6)]
  boolean
  RemoveSpareDisk(
    [in] RAID_PhysicalDisk PhysicalDisk
    );
};

[WMI,
 Dynamic,
 Locale("MS\\0x409"),
 Provider("WMIProv"),
 guid("fcc31373-a7d0-4ffb-be65-9e82ff2169e6"),
 Description ("An abstraction representing a physical disk attached to a RAID "
         "adapter card. Physical disks are grouped together to form "
        "disk arrays.")]
class RAID_PhysicalDisk {

  //
  // Required members for all WMI classes.
  //

  [key, read]
  string InstanceName;

  [read]
  boolean Active;

  //
  // Size in bytes of the disk.
  //

  [read, WmiDataId(1)]
  uint64 Size;

  //
  // Human readable product information about the card.
  //

  [read, WmiDataId(2)]
  string Manufacturer;

  [read, WmiDataId(3)]
  string Product;

  [read, WmiDataId(4)]
  string Revision;

  //
  // Io channel this disk is on.
  //

  [read, WmiDataId(5)]
  RAID_IoChannel IoChannel;

  [read, WmiDataid(6),

   Values {"Online"
        "Dead",
       "Busy"},

   DefineValues {"RAID_DiskStatus_Online",
                 "RAID_DiskStatus_Dead",
       "RAID_DiskStatus_Busy"},

   ValueMap {"0", "1", "2"}]
  uint32 Status;

  //
  // Methods
  //

  [Implemented, WmiMethodId(1),
     Description ("Perform a low-level format of the drive, erasing"
           "all data.")]
  boolean
  Format();
};

[WMI,
 Dynamic,
 Locale("MS\\0x409"),
 guid("92e6fa29-013e-446f-b9a1-cfb03d59212a"),
 Provider("WMIProv"),
 Description ("An abstraction representing an I/O channel on a RAID card. "
         "Each disk is connected to the adapter by exactly one "
        "I/O channel. Disk arrays my span multiple I/O channels")]
class RAID_IoChannel {

  //
  // Required members for all WMI classes.
  //

  [key, read]
  string InstanceName;

  [read]
  boolean Active;

  [read, WmiDataId(1)]
  string Description;

  [read, WmiDataId(2)]
  uint32 Speed;

  [read, WmiDataId(3),

   Values {"Online",
               "Dead"},

   DefineValues {"RAID_ChannelStatus_Online",
                "RAID_ChannelStatus_Dead"},

   ValueMap {"0", "1"}]
  uint32 Width;
};


Intel Processors Machine Check Architectures in Microsoft Windows

Microsoft Windows generic hardware abstraction layers (HAL) for Intel architectures (halx86.dll, halapic.dll, halmps.dll, halia64.dll) support the Machine Check Architectures (MCA) for the Intel Pentium® Pro and Itanium™ processors. The HAL enables Machine Check Exception (MCE) reporting for all implementation-defined errors.

Intel Pentium Pro Processor Machine Check

The Machine Check Exception (MCE) is processor exception 18. The handler for MCE is implemented as a task gate for maximum reliability of the exception handler. The HAL provides a generic exception handler for all errors that cause an exception. This handler reports the machine check exception code on the screen and causes the operating system to halt gracefully, reducing the possibility of persistent data corruption.

In addition, the HAL also provides MCA specific interface that can be used by drivers to:

  • Read the MCA banks to detect an error that does not generate an exception.

    One case where an error does not generate an exception is if the bit controlling reporting of the machine check error for a specific bank (MCi_CTL.Eej bit) is turned cleared. There are also some corrected errors that don't generate MCE and are logged in the MCA banks.

  • Obtain control (to possibly log errors to NVRAM) when the MCE handler is invoked by providing two callback routines — ExceptionCallback and DpcCallback.

Machine Check Exception Handling

If the MCA exception handler detects only Intel Pentium® technology (style) MCE support on the platform, it does the following:

  • If an MCA driver is registered with the HAL, call the MCA driver ExceptionCallback function providing the contents of P5_MC_ADDR and P5_MC_TYPE register values. This callback routine can log the register values in NVRAM and return.
  • Call KeBugCheckEx with the following four parameters, to halt the system:
    1. Low 32 bits of P5_MC_TYPE MSR
    2. Always zero
    3. High 32 bits of P5_MC_ADDR MSR
    4. Low 32 bits of P5_MC_ADDR MSR

If MCA support (Pentium Pro processor) on the platform is detected, the exception handler determines if the error is restartable. If not, it does the following:

  • Calls the MCA Driver ExceptionCallback routine to give the MCA driver a chance to log the errors in NVRAM.
  • Calls KeBugCheckEx with the following four parameters, to halt the system:
    1. MCA bank number that generated MCE
    2. Address field from MCi_ADDR MSR for this MCA bank
    3. High 32 bits of MCi_STATUS MSR for this MCA bank
    4. Low 32 bits of MCi_STATUS MSR for this MCA bank

If the error is restartable, the exception handler queues a DPC which, when called, reports the MCA bank error to the MCA driver through the DpcCallback routine.

Intel Itanium Processor Machine Check

Machine checks, including Machine Check Aborts, cause Itanium™ processor execution to vector to the Processor Abstraction Layer (PAL) PALE_CHECK code in the Itanium ISA. When PALE_CHECK has finished processing, it passes control to the System Abstraction Layer (SAL) SAL_ENTRY code in the Itanium ISA, which in turn branches to the SAL MCA handler: SAL_CHECK.

Uncorrected machine checks refer to errors that cannot be corrected at PAL or SAL layers. These may still be fully or partially recoverable at the operating system layer. At that time, the control flow differs between corrected and uncorrected machine checks.

For corrected machine checks, the operating system corrected error interrupt handlers will be invoked some time after returning to the interrupted process.

For uncorrected machine checks, SAL exposes an interface to register an OS_MCA callback. After validating this entry point, SAL_CHECK branches to it and provides an error record that will allow the operating system to recover whenever possible. The error record passed by SAL must comply, at a minimum, with the V3.0 SAL specification, Error Record Structures, Appendix B, January 2001. The HAL exposes interfaces for the OEMs to register a driver, and provides the error record to the driver. This enables the OEMs to assist the generic HAL MCA handler by attempting recovery of platform-specific errors and maintaining the integrity of the platform.

For Itanium PAL, SAL, and operating system MCA handler's details, please refer to http://www.intel.com/design/ia-64/manuals.

The Itanium reference HAL provides an MCA-specific interface that can be used by drivers to:

  • Register for delivery of an ExceptionCallback function during uncorrected error processing. This callback returns an error severity value to the standard HAL OS_MCA, allowing OEM error recovery. The driver also registers a DpcCallback, which will be performed should the driver recover during ExceptionCallback processing.
  • Register for delivery of two additional DpcCallbacks. These are delivered during corrected error processing for CPU corrected errors and/or platform corrected errors.
  • Read the error records during DpcCallback processing.

Machine Check Exception Handling

After collecting the MCA log, the standard HAL MCA handler calls the MCA driver ExceptionCallback function providing the MCA record. This allows the MCA driver to process the log and makes appropriate consideration with regards to the stability of the system. This callback function returns an error severity value to let the HAL know if it should consider the event as fatal, recoverable, or corrected by the MCA driver. In case of a corrected event and if registered, the MCA driver's DpcCallback is then called for asynchronous log collection by the driver.

In case of an OS_MCA uncorrected event, the HAL calls KeBugCheckEx with the bugcheck code MACHINE_CHECK_EXCEPTION and the following four parameters to halt the system:

  1. HAL Itanium™ MCA type, which values could be:

    HAL_BUGCHECK_MCA_ASSERT = 1

    HAL_BUGCHECK_MCA_GET_STATEINFO = 2

    HAL_BUGCHECK_MCA_CLEAR_STATEINFO = 3

    HAL_BUGCHECK_MCA_FATAL = 4

    The last value should be the expected only for the MCA driver, the other values are HAL internal error values.

  2. MCA log address.
  3. MCA maximum log size.
  4. SAL status of the last SAL interface.

MCA Interface for Drivers

The Intel generic HALs provide the following Intel Pentium® Pro and Itanium™ technology MCA-specific interface for drivers:

  • HalSetSystemInformation with the HAL_QUERY_INFORMATION_CLASS parameter set to HalMcaRegisterDriver. This allows a driver to register MCA callbacks with the HAL. Additionally, the Itanium driver can use a HAL_QUERY_INFORMATION_CLASS parameter set to HalCmcRegisterDriver or HalCpeRegisterDriver for delivery of Corrected CPU errors (CMC) and Corrected Platform Errors (CPE).
  • HalQuerySystemInformation with the HAL_QUERY_INFORMATION_CLASS parameter set to HalMcaLogInformation. This allows a driver to read the MCA log. Additionally, the Itanium driver can use a HAL_QUERY_INFORMATION_CLASS parameter set to HalCmcLogInformation or HalCpeLogInformation to read MCA logs from CMCs and CPEs.

HalSetSystemInformation

HalSetSystemInformation can be used to register MCA driver with the HAL.

NTSTATUS
HalSetSystemInformation(
    IN HAL_QUERY_INFORMATION_CLASS      InformationClass,
    IN ULONG  BufferSize,
    OUT PVOID  Buffer,
    );

Parameters

InformationClass
Specify HalMcaRegisterDriver to register MCA driver's callback routines with the HAL. There are two callback routines — ExceptionCallback and DpcCallback. The ExceptionCallback routine is called during the Machine Check Exception handler nonrestartable error processing, before it issues a bugcheck for the system. The DpcCallback routine is called when the MCA error is restartable. For Itanium™ systems, specify HalCmcRegisterDriver to register a driver's Corrected CPU Error DpcCallback routine, and HalCpeRegisterDriver to register a driver's Corrected Platform Error DpcCallback.
BufferSize
Specifies the size, in bytes, of the buffer supplied by the caller.
Buffer
Pointer to a caller-supplied buffer of type MCA_DRIVER_INFO.
//
// Structure to record the callbacks from driver
//
typedef struct _MCA_DRIVER_INFO {
    PDRIVER_EXCPTN_CALLBACK ExceptionCallback;  -  NULL for Itanium corrected error registration
    PKDEFERRED_ROUTINE      DpcCallback;
    PVOID                   DeviceContext;
} MCA_DRIVER_INFO, *PMCA_DRIVER_INFO;
ExceptionCallback
The driver-supplied routine to be called when Machine Check Exception occurs for uncorrected errors. A driver explicitly can not utilize any kernel services or spinlock routines. The handler is restricted to the same constraints as a driver operating at highest IRQL.
DpcCallback
A driver-supplied routine that is called for corrected errors that caused Machine Check Exception. This routine must be called at DISPATCH_LEVEL.
DeviceContext
The device-specific context for this MCA Driver.

Headers

Declared in ntddk.h. Include ntddk.h.

Return Value

HalSetSystemInformation returns STATUS_SUCCESS if the registration is successful.

Comments

HalSetSystemInformation must be called before an MCA driver can use any of the other interface routines. Only one MCA driver can be registered with the HAL at any given time.

HalQuerySystemInformation

HalQuerySystemInformation can be used to read MCA banks' status registers.

NTSTATUS
HalQuerySystemInformation(
    IN HAL_QUERY_INFORMATION_CLASS  InformationClass,
    IN ULONG  BufferSize,
    OUT PVOID  Buffer,
    OUT PULONG  ReturnedLength
    );

Parameters

InformationClass
Specify HalMcaLogInformation to read the current MCA error log. If any of the uncorrected Machine Check errors is found, it is returned in the buffer. For Itanium™ systems, specify HalCmcLogInformation to read the current corrected CPU error log and HalCpeLogInformation to read the current corrected platform error log.
BufferSize
Specifies the size, in bytes, of the buffer supplied by the caller.
Buffer
Points to a caller-supplied buffer of type MCA_EXCEPTION that will contain the information returned by this routine. For Itanium, the returned information must be compliant, at a minimum, with the V3.0 SAL specification, Error Record Structures, January 2001, Appendix B. For Pentium Pro, the information is as described in the following code sample.
typedef union _MCI_STATS {
struct {
    USHORT  McaCod;
    USHORT  MsCod;
    ULONG  OtherInfo   : 25;
    ULONG  Damage    : 1;
    ULONG  AddressValid  : 1;
    ULONG  MiscValid  : 1;
    ULONG  Enabled    : 1;
    ULONG  UnCorrected  : 1;
    ULONG  OverFlow  : 1;
    ULONG  Valid    : 1;
} MciStats;

ULONGLONG  QuadPart;
} MCI_STATS, *PMCI_STATS;

typedef union _MCI_ADDR{
  struct {
    ULONG Address;
    ULONG Reserved;
  } MciAddr;

  ULONGLONG  QuadPart;
} MCI_ADDR, *PMCI_ADDR;

typedef struct _MCA_EXCEPTION {

  ULONG        VersionNumber;  // Version number of this record type
  MCA_EXCEPTION_TYPE    ExceptionType;  // MCA or MCE
  LARGE_INTEGER     TimeStamp;  // exception recording timestamp
  ULONG        ProcessorNumber;// processor number

  union {
    struct {
      UCHAR      BankNumber;    // bank number
      MCI_STATS    Status;
      MCI_ADDR    Address;
      ULONGLONG    Misc;
    } Mca;

    struct {
      ULONGLONG  McAddress;  // physical address for the cycle causing the error
      ULONGLONG  McType;   // cycle specification causing the error
    } Mce;
  } u;

} MCA_EXCEPTION, *PMCA_EXCEPTION;
ReturnedLength
Specifies the number of bytes returned in Buffer.

Headers

Declared in ntddk.h. Include ntddk.h.

Return Value

HalQuerySystemInformation returns STATUS_SUCCESS if an error log exists.

Comments

This function returns the first error. It is the MCA driver's responsibility to call this routine again to see if there are any more errors available.


Physical Address Extension (PAE)

PAE Memory Support

Microsoft will be supporting Physical Address Extension (PAE) memory in both the Microsoft® Windows® 2000 Advanced Server and Datacenter products.

  • Advanced Server PAE memory support will extend to 8 gigabytes (GB) of physical RAM
  • Datacenter Server PAE memory support will extend to 32 GB of physical RAM

To ensure the highest possible performance and quality for customers purchasing or upgrading systems capable of supporting more than 4 GB of RAM, special Large (PAE) Memory Support hardware compatibility list (HCL) categories will be established, which will provide a listing of the systems, devices, and drivers that have passed testing of this particular capability. Only devices that are listed on the Large Memory Support HCL will be supported by Microsoft when more than 4GB of RAM is installed in the system.

HCL Testing

Vendors who want to have their systems and devices tested, listed, and supported must send their equipment to the Windows Hardware Quality Lab [WHQL], following these basic guidelines:

  • Systems capable of supporting more than 4GB of RAM must be submitted to WHQL at the maximum configuration the system supports for both processors and memory.
  • Component adapters that are 32 bit must have already been submitted.

Note No further submissions to WHQL will be accepted for Large Memory testing and listing of 32-bit adapters. 64-bit component adapters and device drivers may be submitted now and in the future for Large Memory testing and listing.

Operating System Support

The PAE mode kernel will not be enabled by default for systems that can support more than 4 GB of RAM. This new behavior will be evident in Release Candidate 2 of Windows 2000 Advanced Server and Beta 1 of Windows 2000 Datacenter Server, scheduled for simultaneous release. These operating systems will boot by default in normal mode (support for only 4 GB of RAM).

To boot the system and utilize PAE memory, it will be necessary add the "/PAE" switch to the corresponding entry in the BOOT.INI file. If a problem should arise, Safe Mode may be used, and that will cause the system to boot using normal kernels (support for only 4GB of RAM) even if the /PAE switch is part of the BOOT.INI file. The PAE mode kernel requires an Intel Architecture processor, Pentium Pro or later, more than 4GB of RAM, and either Windows 2000 Advanced Server or Windows 2000 Datacenter Server.

Adapter and Driver Issues: LME and DAC Capable

All physical memory is treated as general-purpose memory, so no new APIs are needed to access I/O above the 4 GB physical memory address. Also, direct I/O can be done for greater than 4 GB physical addresses (this requires Dual Address Cycle (DAC) capable or 64-bit PCI devices). Devices and drivers that can perform direct I/O beyond 4 GB are considered Large Memory Enabled (LME).

Because Windows 2000 does not have a kernel PAE or LME API or interface, the PAE-X86 kernel ensures that many items are identical to the standard kernel, including:

  • Kernel memory space organization is unchanged.
  • PCI BAR remains the same.
  • Registry flags work the same.
  • Non-paged pool size remains the same.
  • 3GT feature will be supported for up to 16 GB RAM.
  • IMAGE_FILE_LARGE_ADDRESS_AWARE will continue to work
  • "Well-known" kernel addresses remain in the same locations.

However, careful device driver development is still required. Hardware devices should be DAC or 64-bit capable with LME drivers; otherwise, the device will function as "legacy" 32 bit and will be double buffered, with lower relative performance.

Although double-buffering can have a relatively small impact (single percentage points) on 8 GB systems, this is enough to impact I/O intensive tasks such as database activity. This is also dependent on a number of factors beyond Microsoft's control, such as hardware design and device driver optimizations such as interrupt moderation and efficient use of the PCI bus. As the amount of physical memory increases, so does the negative performance impact in comparison to DAC/64-bit devices and LME drivers.

What to Avoid in Drivers

  1. Do not use Pvoid64. Using Pvoid64 anywhere will return incorrect information because this call does not return valid information on the Intel Architecture platform. It is supported only for purposes of maintaining symmetry with the Compaq Alpha platform, where the call does work. Instead, use PHYSICAL_ADDRESS.

    Note This does not apply for NDIS miniports. Also, miniports such as USB and others that are relatively low performance need not be rewritten to be LME as the performance gain or loss is not significant. They should, however, correctly use the kernel interfaces for Windows 2000 and not try to trick the operating system by use of undocumented and unsupported shortcuts.

  2. Do not call MmGetPhysicalAddress() on a locked buffer, discard the high 32 bits, and then program the adapter to DMA into the resultant address. This will certainly result in corrupted memory, lost I/O, and system failure. If this call is made, ensure that all address information returned is used and that the driver correctly operates with that 64-bit address.
  3. Do not use PVOID when manipulating physical addresses. Because PVOID is only 32 bits, address truncation will take place and memory corruption will result.
  4. Do not use ULong when manipulating physical addresses because this has exactly the same precautions and behavior as PVOID: system failure.
  5. Do not indicate support for scatter/gather in the DEVICE_DESCRIPTION when not true to avoid the buffering provided by HAL (the "mapping registers").
  6. If the driver cannot support 64-bit addresses, do not call IoMapTransfer(...) without having an AdapterControl(...) function (again, to avoid mapping registers), and do not supply zero as the value for MapRegisterBase. This will fail.

Other functions and calls might cause failures. This list will be expanded as more information becomes available and will be in later revisions of the Windows 2000 DDK, which is available at http://www.microsoft.com/ddk/ and distributed through MSDN™.

Guidelines for NDIS Miniports and SCSI Miniports

Guidelines for NDIS Miniports on PAE Systems

There are two mechanisms for 64 bit address-capable network cards to operate above the 4GB mark:

1. Use Scatter Gather DMA.

  • Miniports need to call NdisMInitializeScatterGatherDma with Dma64Addresses = TRUE.
  • Miniports need to be deserialized.
  • Refer to entry for NdisMInitializeScatterGatherDma in the DDK documentation.
  2. Use Map Registers

Miniports need to call NdisMAllocateMapRegisters with DmaSize = NDIS_DMA_64BITS.

Refer to the entry for NdisMAllocateMapRegisters in the DDK documentation.

General Guidelines

  • Shared memory allocated using NdisMAllocateSharedMemory is guaranteed not to cross a 4GB boundary.
  • NDIS_PER_PACKET_INFO_FROM_PACKET(ScatterGatherListPacketInfo) will never return NULL for miniports that support ScatterGatherDma.
  • No SCATTER_GATHER_ELEMENT will cross a 4 GB boundary. If a virtual memory buffer does cross a 4 GB boundary, it will be broken into two ScatterGatherElements.

Guidelines for 32 Bit Address-Only Network Devices

  • Properly written NDIS drivers will work as-is on PAE systems, but will have a significant negative performance impact that grows as the amount of installed RAM increases.
  • NdisMStartBufferPhysicalMapping will copy all fragments above the 4 GB address space to memory that is below the 4 GB mark.

Guidelines for 64 bit Address-Capable SCSI Miniports
(Including All Related Adapters for SCSI 2)

  • Miniports need to support scatter/gather DMA. They must not call any of the slave-mode DMA routines: ScsiPortFlushDma or ScsiPortIoMapTransfer.
  • Miniports should check the value of Dma64BitAddresses in PORT_CONFIGURATION_INFORMATION to determine whether 64-bit PAs are supported. If 64-bit PAs are supported, the miniport should change its extension sizes to account for the larger physical addresses (if necessary) and set the Dma64BitAddresses field to SCSI_DMA64_MINIPORT_SUPPORTED before calling ScsiPortGetUncachedExtension.
  • Miniports must not attempt to access data buffers using virtual addresses unless they have set the MapBuffers bit in the PORT_CONFIGURATION_INFORMATION structure. The exceptions to this rule are INQUIRY and REQUEST_SENSE operations that will always have a valid virtual address.
  • Use SCSI_PHYSICAL_ADDRESS to access all physical addresses.
  • Uncached extensions and SRB extensions will not cross the 4 GB boundary.
  • No scatter/gather element will cross the 4 GB boundary.

Guidelines for Legacy SCSI Miniports

  • Miniports need to support scatter/gather DMA. They must not call any of the slave-mode DMA routines: ScsiPortFlushDma or ScsiPortIoMapTransfer.
  • Miniports must not attempt to access data buffers using virtual addresses unless they have set the MapBuffers bit in the PORT_CONFIGURATION_INFORMATION structure. The exceptions to this rule are INQUIRY and REQUEST_SENSE operations that will always have a valid virtual address.
  • Miniports should not set the MapBuffers bit unless absolutely necessary, because providing valid virtual addresses to a 32-bit driver on a LME system is costly.

Creating and Testing LME Drivers

  1. Do not try to add more features into the driver when modifying it for a Large Memory system. Instead, modify the driver as little as possible to ensure LME capabilities.
  2. Always use the most recent version of the HCT provided on the WHQL web site at http://www.microsoft.com/hwtest/.
  3. Test using all available tools from Microsoft such as DevCtl in the HCT and the Driver Verifier functionality in the Registry.
  4. Test both on systems with greater than 4 GB of physical memory and on systems with less than 4 GB of system memory.
  5. Test legacy drivers to ensure there is no corruption due to incorrect use of calls such as MmGetPhysicalAddress.
  6. Test specifically for PAE systems. This requires a minimum installed RAM of 6 GB.
  • Use the NOLOWMEM switch in the BOOT.INI file:
    • Guarantees a 64-bit physical address (PA) above 4 GB.
    • Hides pages below 4 GB.
    • Fills pages below 4 GB with unique patterns.
    • Task Manager will display roughly total RAM minus ~4 GB.
  • Use DevCtl – supplied with the HCT:
    • Deliberately attacks drivers through IOCTLs.
    • Tests exception handling and failure modes, and unexpected entry points into the driver.
    • Queries with buffers too small to contain returns.
    • Checks IOCTL/FSCTL for:
    • Missing, small or garbage buffers.
    • Data changing asynchronously.
    • Bad pointers.
    • Buffer mapping changing asynchronously.
    • Issues requests both synchronously and asynchronously to the device.
    • Tests IRP cancels, delays and nulls
    • Checks leak, pooltag and lookaside .information.
  • Use Driver Verifier – part of the product
    • All pool allocations are segregated to check for corruption.
    • Extreme memory pressure—whenever IRQL or spin lock is acquired, try to page out the driver; catches fatal errors.
    • All spin lock, IRQL, and pool requests and releases are extensively error checked: double releases of spin locks, usage of uninitialized variables, other forms of pool corruption, and so on.

Troubleshooting DAC Support and LME Drivers

These steps can help OEMs, IHVs, and customers determine if there are any issues relating to the system board, buses, or adapters in supporting DAC and LME.

  1. If the driver fails at initialization, check with the system OEM to determine whether all PCI buses present in the system support DAC.
  2. If a network adapter driver performs a bug check immediately upon a network connection, determine whether all buses support DAC, again by checking with the OEM.
  3. If the PCI buses on the system are all DAC capable, check whether the hardware device is compliant with PCI 2.1.
  4. If the bus supports DAC and the device is PCI 2.1 compliant, check the driver for assumptions being made about physical addresses.

Documentation that will be included with both Windows 2000 Advanced Server and Datacenter Server to the customer concerning PAE memory support is included below.

Hardware Requirements for PAE

The system must meet the following minimum requirements:

  • x86 Pentium Pro processor or later
  • More than 4 GB of RAM
  • 450 NX or compatible chipset and support, or later

Determine Whether Network and Storage Adapters Support PAE

  1. Consult the Windows 2000 Hardware Compatibility List (HCL) at the Microsoft Web site (http://www.microsoft.com/windows/compatible/). Search for "Large Memory" on the Web site.
  2. If your hardware is not supported, update hardware or select different hardware on which to enable PAE. If appropriate, contact the hardware vendor.
  3. If you update your hardware, it is recommended that you back up your system before doing so. If necessary, consult user documentation for information on backing up your system.

Enable PAE x86

To enable PAE x86:

  1. Locate the Boot.ini file, which is typically in the root folder (for example, C:/) and remove its Read-Only and Hidden attributes.
  2. Open the Boot.ini file with a text editor, and then add the /PAE parameter to the ARC path, as shown in bold format in the following example:

    multi(0)disk(0)rdisk(0)partition(2)\WINNT="Windows 2000 Datacenter Server" /PAE /basevideo /sos

  3. On the File menu, click Save.
  4. Restore the Read-Only attribute to the Boot.ini file.

Troubleshooting Specific Programs

Problem: The computer will not start after PAE is enabled.
Cause: Your hardware may not support PAE.

Solution: Start the system and run Safe Mode, which disables PAE. Then remove the /PAE parameter from the Boot.ini file. To run Safe Mode:

  1. When you see the message "Please select the operating system to start," press F8.
  2. Use the arrow keys to highlight the appropriate Safe Mode option, and then press ENTER.

Note NUM LOCK must be off before the arrow keys on the numeric keypad will function.

Problem: After PAE is enabled, the computer runs for a time and then displays a Stop error.
Cause: Your hardware may not support PAE.

Solution: Determine whether your hardware supports PAE by consulting the Windows 2000 HCL at http://www.microsoft.com/windows/compatibility/. Search for "Large Memory" on the Web site.

If your hardware does not support PAE, or if the problem persists and you continue to believe that PAE may be the cause, disable PAE by removing the /PAE parameter from the Boot.ini file.

WHQL, HCT, and HCL for Large Memory

The HCL will be modified to include a new listing category —Large Memory— that will list all components that either support greater than 4 GB [DAC and LME adapters and drivers] or have been tested and known to function correctly in PAE systems [legacy adapters and drivers].

Systems capable of supporting more than 4GB RAM support must be submitted to WHQL at the maximum configuration the system supports for both processors and memory, but there will be no separate Large Memory category for these computers because they must pass testing in a PAE-enabled configuration to be listed at all.

Not every device and driver has been, or can be, tested and listed for the LME HCL. However, many OEMs and IHVs have been consulted in creating this Large Memory list. At this time, Microsoft does not plan to include any further 32-bit devices and adapters in the Large Memory HCL listings, because of the negative performance impact double buffering has on system performance. Microsoft is encouraging vendors to submit new, 64-bit adapters and drivers for Windows 2000 Advanced Server and Datacenter Server systems supporting more than 4 GB of memory, which will be accepted by the WHQL for testing and listing in the LME HCL categories.

Note There are no Large Memory HCL listings for many adapter types. Examples include Video, IEEE 1394, and USB and others, where, at this time, testing has exposed no problems operating in a PAE environment. In the case of Video, this is not an input device for systems with more than 4 GB of memory. In the case of IEEE 1394 and USB devices, these do not presently function as primary data path devices for this class of system. Other device classes such as Keyboards, Mice, Internal Modems, Audio, Smart Cards, Digital Cameras, IRDA Network, Scanner, Video Conference, Flash RAM, DVD-MPEG, Joystick and TV Tuners that do not presently have Large Memory HCL listings have also been found to present no problems at this time, although testing continues.

Legacy devices are a small subset of tested, known functional 32-bit devices and drivers from some of the hardware device categories on the HCL. These are listed primarily so a customer can replace a failed or unsupported component that may be out of production and no longer available with one known to function correctly in Large Memory systems. These devices and drivers do require double buffering of I/O, but have been tested in systems with greater than 4 GB of RAM and are known to function correctly.

LME devices — Large Memory Enabled adapters — are the (currently) small set of DAC/64-bit adapters and associated LME drivers for Storage and Network I/O. These are current devices that are DAC/64-bit capable for interfaces such as SCSI 2, SCSI 3, SCSI X, and Fibre Channel storage and for 100BaseT, Gigabit, ATM, FDDI, 100 Mb TR, and WSDP-SAN for networking. These devices are typically part of the primary data path, which is defined as the data path over which the bulk of network I/O to clients and/or servers traverses for networking, the path over which the bulk of disk I/O traverses, or where the page files reside.

Microsoft believes that tight control of permitted systems and adapter/driver pairs, in the same manner as the present Cluster HCL, will allow stable operations by customers.

Microsoft also plans to perform long-haul stress testing to identify issues that might not be discovered in a relatively quick Hardware Compatibility Test (HCT) test pass.

The key issue to remember is that customers for large systems will not accept poorly written or unstable code from any source. The challenge is to make that code as bulletproof as possible and to identify the resulting stability as a "feature."

Storage Adapters

Vendor | Adapter
Adaptec | AHA-3940AUW
 | AHA-3944AUWD
 | AIC-7895
 | AHA-2940U2W
AMI | MegaRaid Ultra 428
 | MegaRaid 438
HP | NetRaid 3si
LSI | SYM22910(64bit)
Mylex | DAC960PG
 | DAC960PJ
Compaq | SMART 2/DH
 | SMART 2/SL
 | SMART Array 3100ES
 | PCI Fibre Channel
IBM | ServerRAID III Ultra
Qlogic | 1040 (64bit)
 | 1041(64bit)
 | 1240(64bit)
 | QL2100(64bit)
Emulex | LP-8000(64bit)
 | LP-7000(64bit)
ATAPI |

Network Adapters

Ethernet

Vendor | Device
3Com | 3Com Fast EtherLink XL 10/100Mb TX Ethernet NIC (3C905B-TX)
3Com | Fast EtherLink XL 10/100Mb T4 Ethernet (3C905-T4)
3Com | Fast EtherLink XL 10/100Mb TX Ethernet (3C905-TX)
Adaptec | Adaptec ANA-62011/TX 64-bit PCI Fast Ethernet Adapter
Adaptec | Adaptec ANA-69011 32-bit PCI Fast Ethernet Adapter
Adaptec | Adaptec ANA62022 64-bit 2 port PCI Fast Ethernet Adapter
Adaptec | Adaptec ANA62044 64-bit 4 port PCI Fast Ethernet Adapter
Allied Telesyn | AT-2560-B PCI/100 Ethernet Adapter
Allied Telesyn | AT-2560-C PCI/100 Ethernet Adapter
Alteon | Alteon Networks PCI Gigabit Ethernet Adapter 1.10.1
Compaq | Compaq NC6133 Gigabit Module
Compaq | Compaq NC6134 Gigabit Module
Compaq | Compaq 10/100 WOL
Compaq | Compaq Fast Ethernet NIC NC3120
Compaq | Compaq 10/100 TX PCI Intel WOL UTP Controller
Compaq | Compaq Fast Ethernet NIC NC3121
Hewlett Packard | HP 10/100TX PCI LAN Adapter
Hewlett Packard | HP NetServer 10/100TX PCI LAN Adapter (pn#701637)
IBM | EtherJet PCI
IBM | IBM 100/10-B EtherJet PCI Adapter
IBM | IBM 100/10-C EtherJet PCI Adapter
IBM | IBM Netfinity 10/100 Ethernet
IBM | IBM Netfinity Gigabit Ethernet SX Adapter
Intel | Intel 82542-based Gigabit Adapter
Intel | Intel (R) PRO/100+ PCI Adapter
Intel | Intel 8255x-based PCI Ethernet Adapter (10/100)
Intel | Intel (R) PRO/100+ Dual-Port Server Adapter
Intel | Intel (R) PRO/100+ Management Adapter
Intel | Intel (R) PRO/100+ Server Adapter
Intel | Intel (R) PRO/100B PCI Adapter (TX)
Intel | Intel (R) PRO/100B PCI Adapter (T4)
Intel | Intel (R) PRO/100 WfM PCI Adapter
Intel | Intel(R) PRO/100+ Management Adapter
Level One Communications | Level One Communications NetCelerator Family Adapter
Microdyne | Microdyne NE10/100-C PCI Adapter
Olicom | RapidFire Fast Ethernet Adapter (OC-2327)
Samsung | Samsung SmartEther100 SC1100-B LAN Adapter
Samsung | Samsung SmartEther100 SC1100-C LAN Adapter

Token Ring

IBM | IBM Turbo Token Ring PCI Adapter
IBM | IBM 16/4 TRN PCI 2
Madge | Smart 16/4/100 PCI
Madge | Smart 16/4/100 PCI-HS
Madge | Presto PCI 2000
Madge | Smart 16/4 PCI Ringnode
Madge | Presto PCI
Madge | Smart 16/4 PCI Ringnode (BM) Mk2
Madge | Smart 16/4 PCI Ringnode (BM) Mk1
Madge | Madge Presto PCI rev 2
Madge | Madge Presto PCI Mk2
Madge | Madge Smart 16/4 PCI Ringnode Mk3
Olicom | Olicom Rapid Fire 3530 Token-Ring 100 PCI Adapter

FDDI

SysKonnect | SysKonnect FDDI PCI Adapter SK-5521 (SK-NET FDDI-UP)
SysKonnect | SysKonnect FDDI PCI Adapter SK-5522 (SK-NET FDDI-UP DAS)
SysKonnect | SysKonnect FDDI PCI Adapter SK-5541 (SK-NET FDDI-FP)
SysKonnect | SysKonnect FDDI PCI Adapter SK-5543 (SK-NET FDDI-LP)
SysKonnect | SysKonnect FDDI PCI Adapter SK-5544 (SK-NET FDDI-LP DAS)
SysKonnect | SysKonnect FDDI PCI Adapter SK-5821 (SK-NET FDDI-UP64)
SysKonnect | SysKonnect FDDI PCI Adapter SK-5822 (SK-NET FDDI-UP64 DAS)
SysKonnect | SysKonnect FDDI PCI Adapter SK-5841 (SK-NET FDDI-FP64)
SysKonnect | SysKonnect FDDI PCI Adapter SK-5844 (SK-NET FDDI-LP64 DAS)
SysKonnect | SysKonnect FDDI PCI Adapter SK-5843 (SK-NET FDDI-LP64)
Compaq | Compaq Netelligent 100 FDDI PCI SAS UTP part#242506-004
Compaq | Compaq Netelligent 100 FDDI PCI DAS UTP
Compaq | Compaq Netelligent 100 FDDI PCI SAS Fiber MIC
Compaq | Compaq Netelligent 100 FDDI PCI SAS Fiber SC
Compaq | Compaq Netelligent 100 FDDI PCI DAS Fiber SC

ATM

Fore Systems | ForeRunner HE 622
Fore Systems | ForeRunner HE 155
Olicom | OC 6161/6162


1394API.DLL

Introduction

1394API.DLL in conjunction with 1394DIAG.SYS or 1394VDEV.SYS provide ring 3 support for all 1394 DDI's. This document will detail all API's exported by 1394API.DLL and proper implementation of these API's. Additional information about using several of these API's can be found in the definition of the IOCTL_1394_CLASS requests in the DDK.

Windows Applications

Windows based clients using 1394API.DLL are required to register during initialization using the RegisterClient API. When the client terminates, it must call the DeRegisterClient API.

After a client registers its hWnd, it can expect to receive messages when a 1394 bus reset or a 1394 device change occurs. It will receive either a NOTIFY_DEVICE_CHANGE message when a 1394 device is added/removed, or a NOTIFY_BUS_RESET when a 1394 bus reset occurs.

NOTIFY_DEVICE_CHANGE

The client will receive this message whenever a 1394 device has been added or removed. When the client receives this notification, it is required to call the GetDeviceList API to get an updated list of devices available.

NOTIFY_BUS_RESET

The client will receive this message whenever a 1394 bus reset occurs.

Console Applications

The use of the RegisterClient and DeRegisterClient API's is meant for the application to receive notification of bus resets and device changes. It is not possible for a console application to receive these notifications. Instead, the console application will call the GetDeviceList API in order to get a list of devices available. No other action is required by a console application.

The 1394API.DLL API

The following routines are exported by 1394api.dll.

RegisterClient

DWORD
WINAPI
RegisterClient(
  HWND  hWnd
  );

This API will register the client with 1394API.DLL. The window handle passed into RegisterClient will notify the client of 1394 bus resets and device changes.

DeRegisterClient

DWORD
WINAPI
DeRegisterClient(
  HWND    hWnd
  );

This API will deregister the client with 1394API.DLL. This will stop 1394 bus reset and device change notifications.

GetDeviceList

DWORD
WINAPI
GetDeviceList(
  PDEVICE_DATA    DeviceData
  );
typedef struct _DEVICE_LIST {
    CHAR    DeviceName[255];
} DEVICE_LIST, *PDEVICE_LIST;

typedef struct _DEVICE_DATA {
    ULONG        numDevices;
    DEVICE_LIST  deviceList[10];
} DEVICE_DATA, *PDEVICE_DATA;

This API is called with the DeviceData struct. It is used to obtain the symbolic link names of physical 1394 Diagnostic Devices (1394diag.sys) 1394API.DLL supports a maximum of 10 1394 devices on one PC. This is an arbitrary limit and can be increased. The number of 1394 devices available is returned in numDevices and the symbolic link names of available 1394 devices are stored in DeviceName.

GetVirtualDeviceList

DWORD
WINAPI
GetVirtualDeviceList(
  PDEVICE_DATA    DeviceData
  );
typedef struct _DEVICE_LIST {
    CHAR    DeviceName[255];
} DEVICE_LIST, *PDEVICE_LIST;

typedef struct _DEVICE_DATA {
    ULONG        numDevices;
    DEVICE_LIST  deviceList[10];
} DEVICE_DATA, *PDEVICE_DATA;

This API is called with the DeviceData struct. It is used to obtain the symbolic link names of virtual 1394 Diagnostic Devices (1394vdev.sys) 1394API.DLL supports a maximum of 10 1394 devices on one PC. This is an arbitrary limit and can be increased. The number of 1394 devices available is returned in numDevices and the symbolic link names of available 1394 devices are stored in DeviceName.

AddVirtualDriver

DWORD
WINAPI
AddVirtualDriver(
HWND                        hWnd
  PVIRT_DEVICE     pVirtualDevice
ULONG                    BusNumber
  );
hWnd
A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.
typedef struct _VIRT_DEVICE {
        ULONG            fulFlags;
        ULARGE_INTEGER        InstanceID;
        PSTR            DeviceID;
} VIRT_DEVICE, *PVIRT_DEVICE
fulFlags
These flags correspond with the values defined in the IEEE1394_API_REQUEST structure. Valid values are:

IEEE1394_REQUEST_FLAG_UNICODE

IEEE1394_REQUEST_FLAG_PERSISTENT

IEEE1394_REQUEST_FLAG_USE_LOCAL_HOST_EUI

InstanceID

A 64-bit number used to identify this instance of the virtual device.

DeviceID

Supplies a buffer containing a null-terminated string to be used for generating the device ID for this device.

This API is used to load a virtual 1394 driver. Detailed functionality of this API can be found in the 1394 DDI documentation.

RemoveVirtualDriver

DWORD
WINAPI
RemoveVirtualDriver(
HWND                        hWnd
  PVIRT_DEVICE     pVirtualDevice
ULONG                    BusNumber
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

typedef struct _VIRT_DEVICE {
        ULONG            fulFlags;
        ULARGE_INTEGER        InstanceID;
        PSTR            DeviceID;
} VIRT_DEVICE, *PVIRT_DEVICE

fulFlags

These flags correspond with the values defined in the IEEE1394_API_REQUEST structure.  Valid values are:

IEEE1394_REQUEST_FLAG_UNICODE

IEEE1394_REQUEST_FLAG_PERSISTENT

IEEE1394_REQUEST_FLAG_USE_LOCAL_HOST_EUI

InstanceID

A 64-bit number used to identify this instance of the virtual device.

DeviceID

Supplies a buffer containing a null-terminated string to be used for generating the device ID for this device.

This API is used to remove a virtual 1394 driver that was previously loaded via AddVirtualDevice. Detailed functionality of this API can be found in the 1394 DDI documentation.

DiagnosticMode

void
WINAPI
DiagnosticMode(
  HWND  hWnd,
  PSTR  szBusName,
  BOOL  bMode
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szBusName

The symbolic link name for the bus driver on which to toggle diagnostic mode. If bAll=TRUE, then this value can be set to NULL.

bMode

Set this flag to TRUE to enable diagnostic mode and FALSE to disable diagnostic mode.

bAll

Set this flag to TRUE to enable diagnostic mode on all available 1394 host controllers.

This API will enabled/disable diagnostic mode on a specified 1394 bus. If enabled, then any device plugged into this 1394 host controller will be enumerated as a 1394 Test Device, loading 1394DIAG.SYS.

AllocateAddressRange

ULONG
WINAPI
AllocateAddressRange(
  HWND  hWnd,
  PSTR  szDeviceName,
  PALLOCATE_ADDRESS_RANGE  allocateAddressRange,
BOOL  bAutoAlloc
);

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

typedef struct _ALLOCATE_ADDRESS_RANGE {
    ULONG            fulAllocateFlags;
    ULONG            fulFlags;
    ULONG            nLength;
    ULONG            MaxSegmentSize;
    ULONG            fulAccessType;
    ULONG            fulNotificationOptions;
    ADDRESS_OFFSET   Required1394Offset;
    HANDLE           hAddressRange;
    UCHAR                  Data[1];
} ALLOCATE_ADDRESS_RANGE, *PALLOCATE_ADDRESS_RANGE;

fulAllocateFlags

This is specific to 1394API.DLL. This value supports the following flags:

ASYNC_ALLOC_USE_MDL

Data

This element provides the backing store for the allocated address range.  The 1394 bus driver maps all asynchronous requests to this address space.  When allocating this structure the caller must ensure that this element contains the necessary space for the backing store so that the Data field contains nLength bytes.  If the bAutoAlloc flag is used this is not necessary.

bAutoAlloc

This flags instructs 1394api.dll to allocate the necessary backing store for the allocated address range itself, when set to true.  If this flag is set to false the passed in structure must provide the necessary space for the backing store of the allocated address ranges.

This API is used to allocate an address range. Detailed functionality of this API can be found in the 1394 DDI documentation.

FreeAddressRange

ULONG
WINAPI
FreeAddressRange(
  HWND  hWnd,
  PSTR  szDeviceName,
  HANDLE  hAddressRange
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

hAddressRange

The handle for the address range to be freed.  This value is returned by a prior call to AllocateAddressRange.

This API is used to free an address range. Detailed functionality of this API can be found in the 1394 DDI documentation.

GetAddressData

ULONG
WINAPI
GetAddressData(
  HWND  hWnd,
  PSTR  szDeviceName,
  PGET_ADDRESS_DATA  getAddressData,
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

typedef struct _GET_ADDRESS_DATA {
    HANDLE       hAddressRange;
    ULONG        nLength;
    ULONG        ulOffset;
    UCHAR        Data[1];
} GET_ADDRESS_DATA, *PGET_ADDRESS_DATA;

hAddressRange

The handle for the Address range whose data you are interested in.  This is returned by a prior call to AllocateAddressRange.

nLength

The length in bytes of the data you are interested in reading.

ulOffset

The offset in bytes into the allocated address range from which you want to start reading.

Data

This data buffer provides the area to read the contents of the 1394 address range into.  The caller of this API must ensure that this element contains enough space to hold nLength bytes of data.This API is used to read the current data contents of a previously allocated 1394 address range.  This is necessary since a node cannot target 1394 Asynchronous Read requests to itself.

SetAddressData

ULONG
WINAPI
SetAddressData(
  HWND  hWnd,
  PSTR  szDeviceName,
  PSET_ADDRESS_DATA  setAddressData,
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

typedef struct _SET_ADDRESS_DATA {
    HANDLE       hAddressRange;
    ULONG        nLength;
    ULONG        ulOffset;
    UCHAR        Data[1];
} SET_ADDRESS_DATA, *PSET_ADDRESS_DATA;

hAddressRange

The handle for the Address range whose data you are interested in.  This is returned by a prior call to AllocateAddressRange.

nLength

The length in bytes of the data you are interested in writing.

ulOffset

The offset in bytes into the allocated address range from which you want to start writing.

Data

This data buffer provides the area to write the contents of the 1394 address range into.  The caller of this API must ensure that this element contains enough space to hold nLength bytes of data and should specify the values to write here.

This API is used to write the current data contents of a previously allocated 1394 address range.  This is necessary since a node cannot target 1394 Asynchronous Write requests to itself.

AsyncRead

ULONG
WINAPI
AsyncRead(
  HWND  hWnd,
  PSTR  szDeviceName,
  PASYNC_READ  asyncRead,
  BOOL  bAutoAlloc
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

bAutoAlloc

If this flag is set to TRUE, then AsyncRead will automatically allocate the necessary buffer to complete the operation. If this flag is set to FALSE, the client will be required to pass in a large enough buffer the complete this request.

typedef struct _ASYNC_READ {
    ULONG        bRawMode;
    ULONG        bGetGeneration;
    IO_ADDRESS   DestinationAddress;
    ULONG        nNumberOfBytesToRead;
    ULONG        nBlockSize;
    ULONG        fulFlags;
    ULONG        ulGeneration;
    UCHAR        Data[1];
} ASYNC_READ, *PASYNC_READ;

bRawMode

If this value is set to TRUE, then the bus and node number specified in the DestinationAddress will be used. If FALSE, these values are ignored.  This flags must be set to TRUE when sending this request to a virtual diagnostic driver (1394vdev.sys)

bGetGeneration

If this value is set to TRUE, then the generation count will automatically be set to the current generation count. If FALSE, then the generation count will be taken from the ulGeneration variable specified in the async read request.

Data

This buffer provides the area to store the result of the 1394 Asychronous Read operation.  It is the responsibility of the caller of this API to ensure there is sufficient area where to store nNumberOfBytesToRead of data.

This API is used to perform an asynchronous read. Detailed functionality of this API can be found in the 1394 DDI documentation.

AsyncWrite

ULONG
WINAPI
AsyncWrite(
  HWND  hWnd,
  PSTR  szDeviceName,
  PASYNC_WRITE  asyncWrite,
  BOOL  bAutoAlloc
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

bAutoAlloc

If this flag is set to TRUE, then AsyncWrite will automatically allocate the necessary buffer to complete the operation. If this flag is set to FALSE, the client will be required to pass in a large enough buffer the complete this request.

typedef struct _ASYNC_WRITE {
    ULONG        bRawMode;
    ULONG        bGetGeneration;
    IO_ADDRESS   DestinationAddress;
    ULONG        nNumberOfBytesToWrite;
    ULONG        nBlockSize;
    ULONG        fulFlags;
    ULONG        ulGeneration;
    UCHAR        Data[1];
} ASYNC_WRITE, *PASYNC_WRITE;

bRawMode

If this value is set to TRUE, then the bus and node number specified in the DestinationAddress will be used. If FALSE, these values are ignored.

bGetGeneration

If this value is set to TRUE, then the generation count will automatically be set to the current generation count. If FALSE, then the generation count will be taken from the ulGeneration variable specified in the async write request.

Data

This buffer provides the area from which the data portion of the 1394 Asychronous Write operation.  It is the responsibility of the caller of this API to ensure there is sufficient area where to store nNumberOfBytesToWrite of data.

This API is used to perform an asynchronous write. Detailed functionality of this API can be found in the 1394 DDI documentation.

AsyncLock

ULONG
WINAPI
AsyncLock(
  HWND  hWnd,
  PSTR  szDeviceName,
  PASYNC_LOCK  asyncLock
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

typedef struct _ASYNC_LOCK {
    ULONG        bRawMode;
    ULONG        bGetGeneration;
    IO_ADDRESS   DestinationAddress;
    ULONG        nNumberOfArgBytes;
    ULONG        nNumberOfDataBytes;
    ULONG        fulTransactionType;
    ULONG        fulFlags;
    ULONG        Arguments[2];
    ULONG        DataValues[2];
    ULONG        ulGeneration;
    ULONG        Buffer[2];
} ASYNC_LOCK, *PASYNC_LOCK;

bRawMode

If this value is set to TRUE, then the bus and node number specified in the DestinationAddress will be used. If FALSE, these values are ignored.

bGetGeneration

If this value is set to TRUE, then the generation count will automatically be set to the current generation count. If FALSE, then the generation count will be taken from the ulGeneration variable specified in the async lock request.

This API is used to perform an asynchronous lock. Detailed functionality of this API can be found in the 1394 DDI documentation.

AsyncStream

ULONG
WINAPI
AsyncStream(
  HWND  hWnd,
  PSTR  szDeviceName,
  PASYNC_STREAM  asyncStream,
  BOOL  bAutoAlloc
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

bAutoAlloc

If this flag is set to TRUE, then AsyncStream will automatically allocate the necessary buffer to complete the operation. If this flag is set to FALSE, the client will be required to pass in a large enough buffer the complete this request.

typedef struct _ASYNC_STREAM {
    ULONG        nNumberOfBytesToStream;
    ULONG        fulFlags;
    ULONG        ulTag;
    ULONG        nChannel;
    ULONG        ulSynch;
    ULONG        nSpeed;
    UCHAR        Data[1];
} ASYNC_STREAM, *PASYNC_STREAM;
‹ ›

This API is used to perform an asynchronous lock. Detailed functionality of this API can be found in the 1394 DDI documentation.

AsyncStartLoopbackEx

void
WINAPI
AsyncStartLoopback(
  HWND  hWnd,
  PSTR  szDeviceName,
  PASYNC_LOOPBACK_PARAMS_EX  asyncLoopbackParamsEx
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

typedef struct _ASYNC_LOOPBACK_PARAMS_EX {
    HWND            hWnd;
    PSTR            szDeviceName;
    BOOLEAN         bKill;
    BOOLEAN             bRawMode;
    HANDLE          hThread;
    UINT            ThreadId;
    ULONG           ulLoopFlag;
    ULONG           nIterations;
    ULONG           ulPass;
    ULONG           ulFail;
    ULONG           ulIterations;
    IO_ADDRESS  Destination;
    ULONG           nMaxBytes;
} ASYNC_LOOPBACK_PARAMS, *PASYNC_LOOPBACK_PARAMS;

Input

bRawMode

If TRUE this flags indicated that the bus and node address specified in the Destination structure shall be used to target all asynchronous transactions.  If FALSE, the bus and node addresses shall be ignored.  Requests aimed at virtual devices must set this flag to TRUE.

ulLoopFlag

Specified the type of async loopback to issue. Valid flags are:

ASYNC_LOOPBACK_READ

ASYNC_LOOPBACK_WRITE

ASYNC_LOOPBACK_LOCK

ASYNC_LOOPBACK_RANDOM_LENGTH

nIterations

Number of iterations to run.  If 0 is specified the loopback thread will continue to run until it is stopped with a call to StopAsyncLoopbackEx.

Destination

Address to use for async command.  The bus number and node number will be ignored unless bRawMode is set to TRUE.

nMaxBytes

Max number of bytes used for any single async command.

Output

ulPass

Number of iterations that have passed.

ulFail

Number of iterations that have failed.

ulIterations

Total number of iterations.

1394API.DLL automatically fills in the rest of the parameters.

This API is used to start asynchronous loopback.

AsyncStopLoopbackEx

void
WINAPI
AsyncStopLoopbackEx(
  PASYNC_LOOPBACK_PARAMS_EX    asyncLoopbackParamsEx
  );

asyncLoopbackParamsEx

This value is set to a prior asyncLoopbackParams  issued with the AsyncStartLoopback API.

This API is used stop asynchronous loopback.

IsochAllocateBandwidth

ULONG
WINAPI
IsochAllocateBandwidth(
  HWND  hWnd,
  PSTR  szDeviceName,
  PISOCH_ALLOCATE_BANDWIDTH  isochAllocateBandwidth
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

typedef struct _ISOCH_ALLOCATE_BANDWIDTH {
    ULONG        nMaxBytesPerFrameRequested;
    ULONG        fulSpeed;
    HANDLE       hBandwidth;
    ULONG        BytesPerFrameAvailable;
    ULONG        SpeedSelected;
} ISOCH_ALLOCATE_BANDWIDTH, *PISOCH_ALLOCATE_BANDWIDTH;

This API is used to allocate isochronous bandwidth. Detailed functionality of this API can be found in the 1394 DDI documentation.

IsochAllocateChannel

ULONG
WINAPI
IsochAllocateChannel(
  HWND                hWnd,
  PSTR                szDeviceName,
  PISOCH_ALLOCATE_CHANNEL    isochAllocateChannel
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

typedef struct _ISOCH_ALLOCATE_CHANNEL {
    ULONG            nRequestedChannel;
    ULONG            Channel;
    LARGE_INTEGER        ChannelsAvailable;
} ISOCH_ALLOCATE_CHANNEL, *PISOCH_ALLOCATE_CHANNEL;

This API is used to allocate an isochronous channel. Detailed functionality of this API can be found in the 1394 DDI documentation.

IsochAllocateResources

ULONG
WINAPI
IsochAllocateResources(
  HWND   hWnd,
  PSTR  szDeviceName,
  PISOCH_ALLOCATE_RESOURCES  isochAllocateResources
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

typedef struct _ISOCH_ALLOCATE_RESOURCES {
    ULONG        fulSpeed;
    ULONG        fulFlags;
    ULONG        nChannel;
    ULONG        nMaxBytesPerFrame;
    ULONG        nNumberOfBuffers;
    ULONG        nMaxBufferSize;
    ULONG        nQuadletsToStrip;
    HANDLE       hResource;
} ISOCH_ALLOCATE_RESOURCES, *PISOCH_ALLOCATE_RESOURCES;

This API is used to allocate isochronous resources. Detailed functionality of this API can be found in the 1394 DDI documentation.

IsochAttachBuffers

ULONG
WINAPI
IsochAttachBuffers(
  HWND  hWnd,
  PSTR   szDeviceName,
  PISOCH_ATTACH_BUFFERS  isochAttachBuffers,
BOOL        bAutoAlloc,
BOOL        bAutoFill
);

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

typedef struct _RING3_ISOCH_DESCRIPTOR {
    ULONG        fulFlags;
    ULONG        ulLength;
    ULONG        nMaxBytesPerFrame;
    ULONG        ulSynch;
    ULONG        ulTag;
    CYCLE_TIME   CycleTime;
    ULONG        bUseCallback;
    ULONG        bAutoDetach;
    UCHAR        Data[1];
} RING3_ISOCH_DESCRIPTOR, *PRING3_ISOCH_DESCRIPTOR;
//
// struct used to pass in with IOCTL_ISOCH_ATTACH_BUFFERS
//
typedef struct _ISOCH_ATTACH_BUFFERS {
    HANDLE               hResource;
    ULONG                nNumberOfDescriptors;
    ULONG                ulBufferSize;
    ULONG                pIsochDescriptor;
    RING3_ISOCH_DESCRIPTOR    R3_IsochDescriptor[1];
} ISOCH_ATTACH_BUFFERS, *PISOCH_ATTACH_BUFFERS;

bAutoAlloc

If this flag is set to TRUE all of the necessary buffers will be allocated by 1394, based upon the values set in the first buffer, which must still be passed in.

bAutoFill

If this flag is set to TRUE each byte of the buffers attached are filled incrementally, beginning with 0.

This API is used to attach isochronous buffers. Detailed functionality of this API can be found in the 1394 DDI documentation.

IsochDetachBuffers

ULONG
WINAPI
IsochDetachBuffers(
  HWND  hWnd,
  PSTR  szDeviceName,
  PISOCH_DETACH_BUFFERS  isochDetachBuffers
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

typedef struct _ISOCH_DETACH_BUFFERS {
    HANDLE       hResource;
    ULONG        nNumberOfDescriptors;
    PVOID        pIsochDescriptor;
} ISOCH_DETACH_BUFFERS, *PISOCH_DETACH_BUFFERS;

This API is used to detach isochronous buffers. Detailed functionality of this API can be found in the 1394 DDI documentation.

IsochFreeBandwidth

ULONG
WINAPI
IsochFreeBandwidth(
  HWND      hWnd,
  PSTR      szDeviceName,
  HANDLE    hBandwidth
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

hBandwidth

The handle to the bandwidth resource to be freed.  This was returned from a prior call to IsochAllocateBandwidth.

This API is used to free isochronous bandwidth. Detailed functionality of this API can be found in the 1394 DDI documentation.

IsochFreeChannel

ULONG
WINAPI
IsochFreeChannel(
  HWND      hWnd,
  PSTR      szDeviceName,
  ULONG     nChannel
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

nChannel

The isochronous channel to be freed.  This was returned from a prior call to IsochAllocateChannel.

This API is used to free an isochronous channel. Detailed functionality of this API can be found in the 1394 DDI documentation.

IsochFreeResources

ULONG
WINAPI
IsochFreeResources(
  HWND      hWnd,
  PSTR      szDeviceName,
  HANDLE    hResource
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

hResource

The handle to the isochronous resource to be freed.  This was returned in a prior call to IsochAllocateResources.

This API is used to free isochronous resources. Detailed functionality of this API can be found in the 1394 DDI documentation.

IsochListen

ULONG
WINAPI
IsochListen(
  HWND      hWnd,
  PSTR      szDeviceName,
  PISOCH_LISTEN   isochListen
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

typedef struct _ISOCH_LISTEN {
    HANDLE       hResource;
    ULONG        fulFlags;
    CYCLE_TIME   StartTime;
} ISOCH_LISTEN, *PISOCH_LISTEN;

This API is used to start an isochronous listen. Detailed functionality of this API can be found in the 1394 DDI documentation.

IsochQueryCurrentCycleTime

ULONG
WINAPI
IsochQueryCurrentCycleTime(
  HWND      hWnd,
  PSTR      szDeviceName,
  PCYCLE_TIME   CycleTime
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

CycleTime

The current isochronous cycle time.

This API is used to query current isochronous cycle time. Detailed functionality of this API can be found in the 1394 DDI documentation.

IsochQueryResources

ULONG
WINAPI
IsochQueryResources(
  HWND            hWnd,
  PSTR            szDeviceName,
  PISOCH_QUERY_RESOURCES   isochQueryResources
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

typedef struct _ISOCH_QUERY_RESOURCES {
    ULONG            fulSpeed;
    ULONG            BytesPerFrameAvailable;
    LARGE_INTEGER        ChannelsAvailable;
} ISOCH_QUERY_RESOURCES, *PISOCH_QUERY_RESOURCES;

This API is used to query isochronous resources. Detailed functionality of this API can be found in the 1394 DDI documentation.

IsochSetChannelBandwidth

ULONG
WINAPI
IsochSetChannelBandwidth(
  HWND               hWnd,
  PSTR               szDeviceName,
  PISOCH_SET_CHANNEL_BANDWIDTH   isochSetChannelBandwidth
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

typedef struct _ISOCH_SET_CHANNEL_BANDWIDTH {
    HANDLE       hBandwidth;
    ULONG        nMaxBytesPerFrame;
} ISOCH_SET_CHANNEL_BANDWIDTH, *PISOCH_SET_CHANNEL_BANDWIDTH;

This API is used to set isochronous channel bandwidth. Detailed functionality of this API can be found in the 1394 DDI documentation.

IsochStop

ULONG
WINAPI
IsochStop(
  HWND      hWnd,
  PSTR      szDeviceName,
  PISOCH_STOP   isochStop
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

typedef struct _ISOCH_STOP {
    HANDLE       hResource;
    ULONG        fulFlags;
} ISOCH_STOP, *PISOCH_STOP;

This API is used to stop isochronous talks/listens. Detailed functionality of this API can be found in the 1394 DDI documentation.

IsochTalk

ULONG
WINAPI
IsochTalk(
  HWND      hWnd,
  PSTR      szDeviceName,
  PISOCH_TALK   isochTalk
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

typedef struct _ISOCH_TALK {
    HANDLE        hResource;
    ULONG        fulFlags;
    CYCLE_TIME    StartTime;
} ISOCH_TALK, *PISOCH_TALK;

This API is used to start an isochronous talk. Detailed functionality of this API can be found in the 1394 DDI documentation.

IsochStartLoopback

void
WINAPI
IsochStartLoopback(
  HWND            hWnd,
  PSTR            szDeviceName,
  PISOCH_LOOPBACK_PARAMS   isochLoopbackParams
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

typedef struct _ISOCH_LOOPBACK_PARAMS {
    HWND                hWnd;
    PSTR                szDeviceName;
    BOOLEAN             bKill;
    BOOLEAN             bLoopback;
    HANDLE              hThread;
    UINT                ThreadId;
    ULONG               ulLoopFlag;
    ULONG               nIterations;
    ULONG               ulPass;
    ULONG               ulFail;
    ULONG               ulIterations;
    ISOCH_ATTACH_BUFFERS        isochAttachBuffers;
} ISOCH_LOOPBACK_PARAMS, *PISOCH_LOOPBACK_PARAMS;

Input

ulLoopFlag

Specified the type of async loopback to issue. Valid flags are:

RESOURCE_USED_IN_LISTENING

RESOURCE_USED_IN_TALKING

nIterations

Number of iterations to run.  If 0 is specified the isoch loopback will continue until it is stopped via a call to IsochStopLoopback.

isochAttachBuffers

This attach buffer request needs to be filled in correctly in order to start isoch loopback. Refer to the IsochAttachBuffers API.

Output

ulPass

Number of iterations that have passed.

ulFail

Number of iterations that have failed.

ulIterations

Total number of iterations.

1394API.DLL automatically fills in the rest of the parameters.

This API is used to start isochronous loopback. Detailed functionality of this API can be found in the 1394 DDI documentation.

IsochStopLoopback

void
WINAPI
IsochStopLoopback(
  PISOCH_LOOPBACK_PARAMS   isochLoopbackParams
  );

isochLoopbackParams

This value is set to a prior isochLoopbackParams issued with the

IsochStartLoopback API.

This API is used to stop isochronous loopback. Detailed functionality of this API can be found in the 1394 DDI documentation.

GetLocalHostInformation

ULONG
WINAPI
GetLocalHostInformation(
  HWND               hWnd,
  PSTR               szDeviceName,
  PGET_LOCAL_HOST_INFORMATION   GetLocalHostInfo,
  BOOL               bAutoAlloc
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

bAutoAlloc

If this flag is set to TRUE, then GetLocalHostInformation will automatically allocate the necessary buffer to complete the operation. This buffer will be freed before the call completes but the information determined will be written to the windows specified by hWnd.  If this flag is set to FALSE, the client will be required to pass in a large enough buffer the complete this request.

typedef struct _GET_LOCAL_HOST_INFORMATION {
    ULONG        Status;
    ULONG        nLevel;
    ULONG        ulBufferSize;
    UCHAR        Information[1];
} GET_LOCAL_HOST_INFORMATION, *PGET_LOCAL_HOST_INFORMATION;

Status

This returns the Status of the requested call. In the case where nLevel = 5 or 6 (retrieve config rom or specified address range), then Status will be equal to ERROR_INSUFFICIENT_BUFFER and the required buffer size will be specified in the Information data struct (GET_LOCAL_HOST_INFO5 or 6).

This API is used to get local host information. Detailed functionality of this API can be found in the 1394 DDI documentation.

Get1394AddressFromDeviceObject

ULONG
WINAPI
Get1394AddressFromDeviceObject(
  HWND         hWnd,
  PSTR         szDeviceName,
  PGET_1394_ADDRESS   Get1394Address
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

typedef struct _GET_1394_ADDRESS {
    ULONG            fulFlags;
    NODE_ADDRESS     NodeAddress;
} GET_1394_ADDRESS, *PGET_1394_ADDRESS;

This API is used to get a 1394 address from a device object. Detailed functionality of this API can be found in the 1394 DDI documentation.

Control

ULONG
WINAPI
Control(
  HWND         hWnd,
  PSTR         szDeviceName
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

This API is specific to 1394 host controllers. It is not supported and will return an error STATUS_UNSUPPORTED. Detailed functionality of this API can be found in the 1394 DDI documentation.

GetMaxSpeedBetweenDevices

ULONG
WINAPI
GetMaxSpeedBetweenDevices(
  HWND               hWnd,
  PSTR               szDeviceName,
  PGET_MAX_SPEED_BETWEEN_DEVICES   GetMaxSpeedBetweenDevices
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

typedef struct _GET_MAX_SPEED_BETWEEN_DEVICES {
    ULONG        fulFlags;
    ULONG        ulNumberOfDestinations;
    ULONG        hDestinationDeviceObjects[64];
    ULONG        fulSpeed;
} GET_MAX_SPEED_BETWEEN_DEVICES, *PGET_MAX_SPEED_BETWEEN_DEVICES;

This API is used to get the max speed between devices. Detailed functionality of this API can be found in the 1394 DDI documentation.

SetDeviceXmitProperties

ULONG
WINAPI
SetDeviceXmitProperties(
  HWND            hWnd,
  PSTR            szDeviceName,
  PDEVICE_XMIT_PROPERTIES   DeviceXmitProperties
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

typedef struct _DEVICE_XMIT_PROPERTIES {
    ULONG        fulSpeed;
    ULONG        fulPriority;
} DEVICE_XMIT_PROPERTIES, *PDEVICE_XMIT_PROPERTIES;

This API is used to set device xmit properties. Detailed functionality of this API can be found in the 1394 DDI documentation.

GetConfigurationInformation

ULONG
WINAPI
GetConfigurationInformation(
  HWND            hWnd,
  PSTR            szDeviceName
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

This API is used to retrieve configuration information. Detailed functionality of this API can be found in the 1394 DDI documentation.

BusReset

ULONG
WINAPI
BusReset(
  HWND      hWnd,
  PSTR      szDeviceName,
  ULONG      fulFlags
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

fulFlags

Any flag to be passed in as defined by 1394 DDI spec.

This API is used to generate a 1394 bus reset. Detailed functionality of this API can be found in the 1394 DDI documentation.

GetGenerationCount

ULONG
WINAPI
GetGenerationCount(
  HWND      hWnd,
  PSTR      szDeviceName,
  PULONG      GenerationCount
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

GenerationCount

Returns the current generation count.

This API is used to retrieve the current generation count. Detailed functionality of this API can be found in the 1394 DDI documentation.

SendPhyConfigurationPacket

ULONG
WINAPI
SendPhyConfigurationPacket(
  HWND            hWnd,
  PSTR            szDeviceName,
  PPHY_CONFIGURATION_PACKET   PhyConfigurationPacket
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

typedef struct _PHY_CONFIGURATION_PACKET {
    ULONG        PCP_Phys_ID:6;        // Byte 0 - Bits 0-5
    ULONG        PCP_Packet_ID:2;    // Byte 0 - Bits 6-7
    ULONG        PCP_Gap_Count:6;    // Byte 1 - Bits 0-5
    ULONG        PCP_Set_Gap_Count:1;    // Byte 1 - Bit 6
    ULONG        PCP_Force_Root:1;    // Byte 1 - Bit 7
    ULONG        PCP_Reserved1:8;    // Byte 2 - Bits 0-7
    ULONG        PCP_Reserved2:8;    // Byte 3 - Bits 0-7
    ULONG        PCP_Inverse;        // Inverse quadlet
} PHY_CONFIGURATION_PACKET, *PPHY_CONFIGURATION_PACKET;

This API is used to send a phy configuration packet. Detailed functionality of this API can be found in the 1394 DDI documentation.

GetSpeedTopologyMaps

ULONG
WINAPI
GetSpeedTopologyMaps(
  HWND            hWnd,
  PSTR            szDeviceName,
  PSPEED_TOPOLOGY_MAP      SpeedTopologyMap,
  BOOL            bAutoAlloc
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

bAutoAlloc

If this flag is set to TRUE, then GetSpeedTopologyMaps will automatically allocate the necessary buffer to complete the operation. If this flag is set to FALSE, the client will be required to pass in a large enough buffer the complete this request.

typedef struct _SPEED_TOPOLOGY_MAP {
    ULONG            ulBufferSize;
    SPEED_MAP        SpeedMap;
    TOPOLOGY_MAP        TopologyMap;
} SPEED_TOPOLOGY_MAP, *PSPEED_TOPOLOGY_MAP;

ulBufferSize

If bAutoAlloc = TRUE, then this value is ignored. Otherwise, this value must specify the size of the SpeedTopologyMap buffer. If the buffer is not large enough to store the contents of the Speed and Topology map, then this value will represent the buffer size needed to complete this operation and an error equal to ERROR_INSUFFICIENT_BUFFER will be returned.

This API retrieves the 1394 speed and topology maps. Detailed functionality of this API can be found in the 1394 DDI documentation.

BusResetNotification

ULONG
WINAPI
BusResetNotification(
  HWND         hWnd,
  PSTR         szDeviceName,
  ULONG         fulFlags
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

fulFlags

Flag to be passed in as defined by 1394 DDI spec.

This API is used to register bus reset notification. Detailed functionality of this API can be found in the 1394 DDI documentation.

SetLocalHostInformation

ULONG
WINAPI
SetLocalHostInformation(
  HWND               hWnd,
  PSTR               szDeviceName,
  PSET_LOCAL_HOST_INFORMATION   SetLocalHostInfo
  );

hWnd

A handle to an edit control can be passed in for debug output for this API. If no debug output is desired, a NULL value can be passed in.

szDeviceName

The symbolic link name for the device to use for this API. A list of available device names can be retried using the GetDeviceList or GetVirtualDeviceList API.

typedef struct _SET_LOCAL_HOST_INFORMATION {
    ULONG        nLevel;
    ULONG        ulBufferSize;
    UCHAR        Information[1];
} SET_LOCAL_HOST_INFORMATION, *PSET_LOCAL_HOST_INFORMATION;

This API is used to set local host information. Detailed functionality of this API can be found in the 1394 DDI documentation.


Using PCI IDs with Windows

This specification describes the use of PCI IDs by Windows operating systems and highlights why these IDs are critical in providing a true Plug and Play experience to Windows users. It also explains the rules associated with assigning IDs and provides examples of ID assignments for plug-in cards, motherboard implementations, and chipset integrations. In addition, it provides the testing criteria applied by Windows Hardware Quality Labs (WHQL) for the Microsoft Windows Logo program for hardware.

This specification includes and expands upon the PCI Local Bus Specification, Version 2.2. For detailed information on the location of IDs referenced in this specification, see PCI 2.2.

This specification does not currently cover AC97 devices or riser cards.

For information about obtaining a PCI Vendor ID, or to obtain the PCI 2.2 specification, see http://www.pcisig.com/

For more information about other issues related to PCI implementations for Windows operating systems, see http://www.microsoft.com/hwdev/PCI/.

Definition of Terms

This document uses multiple acronyms and terms, as defined in this section.

class code (CC)
24-bit value located at offset 9, divided into base Class, subclass, and programming interface.
device ID (DID)
16-bit value located at offset 2.
PCI device
Electrical component that conforms to the PCI specification.
revision ID (REV)
8-bit value located at offset 8.
subsystem ID (SID)
16-bit value located at offset 2E.

The SID is the ID assigned by the manufacturer to uniquely identify the device.

subsystem vendor ID (SVID)
16-bit value located at offset 2C.

The SVID is the ID assigned to the manufacturer by the PCI SIG.

vendor ID (VID)
16-bit value located at offset 0.

Introduction

Microsoft Windows operating systems — including Windows 95/98, Windows 2000, and later versions of these operating systems — use combinations of six PCI values to create an ID that is unique to the device. The operating system reads and concatenates the VID, DID, SID, SVID, REV, and CC to create a multiple ID assignment for each device.

The ID assignment will range from using all six components to using only the CC component, such as for bridges.

The operating system can use these IDs for the following purposes:

  • To install or uninstall drivers.
  • To install different or special versions of drivers.
  • To identify broken devices or specific implementations of devices.
  • To apply any exception processing required.
  • To detect the presence of a new device.
  • To remove a device.

The operating system implements the following sequence to find and use these IDs:

  1. The PCI driver scans the hardware to find buses, devices, and functions.
  2. The PCI driver reads configuration space and creates IDs.
  3. The PCI driver applies any exceptions needed, which could include enabling and disabling features, applying workarounds, or setting flags in the exception table.

    Note Any exceptions applied here will be to the bus.

  4. The PCI driver installs the device driver.
  5. The PCI driver loads the device driver.
  6. The device driver applies any exceptions needed to the device, which could include enabling or disabling features, applying workarounds, or setting flags.
  7. The PCI driver notifies the device driver to initialize the device.

The operating system inherently relies on the IDs of devices. A change in any of the IDs of a device between boots or sleep/resume cycles can have devastating effects. A change in an SID when resuming from sleep state would, at a minimum, trigger a Plug and Play event. The operating system would detect the new device ID and install a new instance of the device. The best-case example would be that the same driver is loaded for this instance. However, if the device has a custom driver or exceptions have been applied, adverse effects would occur. The worst-case example would be if the SID of the primary video controller changed during a resume state, causing a surprise removal of the device that has a driver loaded. A race condition would result between the loaded driver being unloaded and the new driver being loaded, which would cause the system to hang.

Note The INF file parsing code for Windows 95 (original and OEM service releases) will stop searching INF files once a match is found. If the DID &VID entry in an INF file is found before the DID&VID&SID&SVID entry is found, only the driver associated with the DID&VID entry will be loaded.

Rules for Assigning SIDs and SVIDs for Plug-in Cards

There is one simple rule for assigning the SID and SVID for PCI and Mini PCI plug-in cards:

All new card designs must have a new, unique SID assigned by the card manufacturer.

A new card design is defined as any design that incorporates new devices requiring any circuit board or supporting component changes.

Changes that Require an Update of the SID for Plug-in Cards

Some events require the SID of a card to be updated. Use the following guideline to determine whether an updated SID is needed:

If anything changes that is external to the PCI devices (chips) on the plug-in card, the SID must be updated.

Note A change in a chip on a card does not require a change in SID. However, an installation of an updated chip that has followed the ID rules for devices can cause a change of the driver for that chip due to a new ID being read. An example is a REV change from 1 to 2.

Examples of when SID updates are needed:

• Any board layout changes, including bug fixes and cost-reduction changes.

• Any component value changes on the card, including resistors and capacitors.

• Any SKU change — for example, adding an S-Video connector to a card that has the capability but only has a VGA out connector.

The following are examples of SID and SVID assignments for add-on cards using different manufacturers and devices.

Example: Add-on video card produced by manufacturer AAAA, using a device produced by company DDDD

Description | DID | VID | SID | SVID
Video device on new video card model xx | 1111 | DDDD | 0001 | AAAA
Video device on model xx-s (added S-Video out) | 1111 | DDDD | 0002 | AAAA

Example: Multifunction network/modem add-on card produced by manufacturer AAAA, using devices from company CCCC

Description | DID | VID | SID | SVID
Network PCI device | 2222 | CCCC | 0005 | AAAA
Modem PCI device | 1111 | CCCC | 0005 | AAAA

Example: Multifunction network/modem add-on card produced by manufacturer AAAA, using devices from company AAAA

Description | DID | VID | SID | SVID
Network PCI device | 3333 | AAAA | 0010 | AAAA
Modem PCI device | 1111 | AAAA | 0010 | AAAA

Example: Multifunction network/modem add-on card produced by manufacturer AAAA, using devices from companies CCCC and DDDD

Description | DID | VID | SID | SVID
Network PCI device | 2222 | CCCC | 0007 | AAAA
Modem PCI device | 5555 | DDDD | 0007 | AAAA

Rules for Assigning SIDs and SVIDs for Devices Integrated on a Motherboard

There is one simple rule for assigning the SID and SVID for PCI devices integrated on a motherboard.

All new motherboard designs must have a new, unique SID assigned by the manufacturer.

Note It is recommended that all integrated devices on a motherboard are assigned the same SID value.

The operating system relies on being able to uniquely identify a device and each implementation of that device. For example, for form factor reasons, computer manufacturer AAAA decides not to connect the USB controller integrated in the south bridge of a specific design (a popular south bridge in current production). They inadvertently leave the pins as "no connects," causing an interrupt storm under a certain condition. AAAA ships 700,000 systems before the problem is discovered. In order to apply a fix for the Windows® operating system that does not adversely affect every component using the south bridge, the device and implementation must be able to be uniquely identified.

Example: SID and SVID assignments of a motherboard produced by manufacturer AAAA, using devices produced by the companies CCCC, DDDD, EEEE, and TTTT

Description | DID | VID | SID | SVID
Video PCI device | 1212 | CCCC | 0105 | AAAA
USB PCI device | 4545 | CCCC | 0105 | AAAA
Audio PCI device | 3434 | EEEE | 0105 | AAAA
Network PCI device | 2222 | CCCC | 0105 | AAAA
Modem PCI device | 1111 | DDDD | 0105 | AAAA
CardBus PCI device | 4444 | TTTT | 0105 | AAAA

Changes that Require an Update of the SID for Motherboards

Some events require the SID of a motherboard to be updated. Use the following guideline to determine whether an updated SID is needed:

If anything changes that is external to the PCI devices (chips) on the motherboard, the SID of all devices must be updated.

Note A change in a chip on a motherboard does not require a change in SID. However, an installation of an updated chip that has followed the ID rules for devices can cause a change of the driver for that chip due to a new ID being read. An example is a REV value change from 1 to 2.

Examples of when updates are needed:

• Any board layout changes, including bug fixes and cost-reduction changes.

• Any component value changes on the motherboard, including resistors and capacitors.

• Any SKU change, for example, a motherboard SKU that removes an integrated modem that was on the board when the SIDs were originally assigned.

Rules for Assigning VIDs for PCI Devices

The VID is always the Vendor ID assigned by the PCI SIG for the device or chip manufacturer.

Rules for Assigning DIDs for PCI Devices

The DID is a value assigned by the device manufacturer that, in conjunction with the VID and REV values, uniquely identifies the PCI device. This number must be tracked by the device manufacturer and never used again in combination with the VID.

Changes that Require an Update of the DID for PCI Devices

Examples of when DID updates are needed:

• If the manufacturer makes a modification during the life of a PCI device that causes any change in any exposed registers or software interfaces, or makes a feature enhancement, the DID must be updated to a new, unique value.

• If an existing device is integrated into a new multifunction package, the DID for that device must change.

Rules for Assigning and Updating the REV for PCI Devices

The REV is a value assigned by the device manufacturer that identifies the revision number of the device.

The REV must be updated if any rules in the following section apply to changes made to the device.

Changes that Require an Update of the REV for PCI Devices

Examples of when updates are needed:

• Any bug fix, feature, or performance update that does not change the software interface.

Note A software interface change requires a DID update.

• Integration of device design into a multifunction packaging design.

Note This causes all REV values for devices in the package to change.

• Any change in process technology used in production or any change in package type that does not change the software interface, but changes the functionality with respect to system software.

Note When changes in process technology or packaging do not result in changes to the system software interface or functionality, it is still recommended (but not required) that the REV be updated.

The following are examples of REV and DID assignments for integrating devices into an existing multifunction package.

Example: REV and DID assignments for a network device being integrated into a multifunction package already containing USB, ATA, and video devices by device manufacturer CCCC

Description | DID | VID | REV
Devices before integration |  |  |
Discrete network PCI device | 1111 | CCCC | 1
Integrated USB PCI device | 2222 | CCCC | 2
Integrated video PCI device | 3333 | CCCC | 2
Integrated ATA PCI device | 4444 | CCCC | 3
Devices after integration |  |  |
Network PCI device in a new package | 5555 | CCCC | 1
USB PCI device in a new package | 2222 | CCCC | 3
Video PCI device in a new package | 3333 | CCCC | 3
ATA PCI device in a new package | 4444 | CCCC | 4

Example: REV and DID assignments for adding another USB device into a multifunction package already containing USB, ATA, and video devices by device manufacturer CCCC

Description | DID | VID | REV
Devices before integration |  |  |
Integrated USB PCI device | 2222 | CCCC | 2
Integrated video PCI device | 3333 | CCCC | 2
Integrated ATA PCI device | 4444 | CCCC | 3
Devices after integration |  |  |
New USB PCI device in a new package | 2222 | CCCC | 3
USB PCI device in a new package | 2222 | CCCC | 3
Video PCI device in a new package | 3333 | CCCC | 3
ATA PCI device in a new package | 4444 | CCCC | 4

Rules for Assigning CCs for PCI Devices

CC assignments must comply with the PCI 2.2 specification.

Windows Logo Program Test Criteria and Driver Requirements for PCI IDs

The following are test criteria that WHQL will use to develop tests for the Windows® Logo Program for hardware:

• The test will read and properly concatenate PCI IDs and verify their uniqueness.

• The test will verify IDs after suspend/resume cycle.

• Hot-plug test will be required for PCI devices that support hot-plug capabilities.

• Submissions of a device that has only a REV update will also be validated using a previous version of the driver with the same DID and VID.

This specification provides a hardware baseline that WHQL will use for testing. Driver requirements and rules are provided by the PCI ID requirements for PCI drivers, published by Microsoft. See http://www.microsoft.com/hwdev/winlogo/ for more information.


Kernel Enhancements for Windows XP

Microsoft has made many enhancements to the kernel of the next release of the Microsoft® Windows® operating system, Windows XP. This section provides an overview of the new features and changes in the kernel for Windows XP, intended for system and peripheral designers, driver developers, and firmware developers who are creating products that run on Windows XP.

This documentation assumes that the reader is familiar with related concepts and issues for Windows 2000. For more information, see the Windows Driver Development Kit and the Windows 2000 Resource Kit (available through MSDN® Professional subscription or through Microsoft Press®).

Kernel improvements are significant because the kernel provides low-level operating system functions, including thread scheduling, interrupt and exception dispatching, multiprocessor synchronization, and a set of routines and basic objects used by the rest of the operating system to implement higher-level constructs.

This documentation describes the kernel improvements for Windows XP, which include:

  • Registry

    Larger registries, limited only by available system disk space. Improved algorithms for faster queries.

  • Support

    Cross-session debugging, new quit and detach command for debugging without killing the application, and built-in user mode heap-leak detection.

  • I/O Subsystem

    New input/output (I/O) interfaces for performance enhancement, while retaining compatibility with Windows 2000 drivers. Kernel-mode support routines for File System Filter driver improvements. Support for performance measurements in retail code, and improved low-memory performance.

  • Memory Management

    Broad range of improvements, including logical prefetch to improve boot and logon performance, reduced paged pool usage, enhanced terminal server support, support of giant drivers, and Windows XP execution from ROM.

  • Power Management

    Native support for processor performance control, including Intel SpeedStep Technology, AMD PowerNow!, and Transmeta LongRun for longer mobile computer battery life. Hibernate, standby, and resume performance have been greatly improved.

  • Improved Boot and Logon Performance

    When a Windows XP system is first booted, data is saved about all logical disk read operations. On later boots, this information is used to pre-fetch these files in parallel with other boot operations.

  • Headless Support

    For "lights-out" datacenter deployment and remote administration.

  • ccNUMA Support

    Provides better performance for Cache Coherent–Non Uniform Memory Architecture (ccNUMA) computers, as well as an interface to let applications tailor their execution characteristics in the ccNUMA environment.

The Windows XP kernel improvements provide new opportunities for independent software vendors (ISV), independent hardware vendors (IHV), and other value-added providers working with Windows 2000. Windows XP provides compatibility with Windows 2000 devices and drivers, while providing new routines, enhancements, and other features that can be leveraged into future products and services.


Registry Enhancements

As with Windows 2000, the registry plays a key role in the configuration and control of Windows XP. The registry, which resides on the disk as multiple files called hives, was originally designed as a repository for system configuration data. Although most people think of the registry as static data stored on the hard disk, it is also a window into various in-memory structures maintained by the Windows XP executive and kernel.

The registry code is redesigned for Windows XP, providing enhanced performance while remaining transparent to applications by using existing registry programming interfaces. Windows XP registry enhancements provide performance improvements, including the following areas:

  • Converting a delayed close table to a Least Recently Used (LRU) list.
  • Reducing Kernel Control Block (KCB) lock contention with do not lock registry exclusive and do not touch volatile information.
  • Providing a security cache to eliminates duplicate security descriptors.

The new registry implementation delivers two key benefits:

  • Larger registries
  • Faster queries

Larger Registries

Windows XP supports larger registries than previous versions of the kernel, which were effectively limited to about 80 percent of the total size of paged pool. The new implementation is limited only by available system disk space.

A tendency to use the registry more like a database developed among registry consumers, which increased demands on registry size. The original design of the registry kept all of the registry files in the paged-pool, which, in the 32-bit kernel, is effectively limited at approximately 160 MB because of the layout of the kernel virtual address space. A problem arose because, as larger registry consumers such as Terminal Services and COM appeared, a considerable amount of paged-pool was used for the registry alone, potentially leaving too little memory for other kernel-mode components.

Windows XP solves this problem by moving the registry out of paged pool and using the cache manager to do an in-house management of mapped views of the registry files. The mapped views are mapped in 256-KB chunks into system cache space instead of paged pool.

Faster Queries

Another issue that affected registry performance in earlier versions is the locality problem. Related cells are spread through the entire registry files. Accessing certain information, such as attributes of a key, could degenerate into page-faults, which lowers performance.

The Windows XP registry uses an improved algorithm for allocating new cells that keeps related cells in closer proximity — such as keeping cells on the same page or nearby pages, which solves the locality problem and reduces the page faults incurred when accessing related cells. A new hive structure member tracks freed cells instead of relying on linked freed cells. When future cells are allocated, the freed cell list and a vicinity argument are used to ensure the allocation is in the same bin as the hive.

Windows XP improves the way the registry handles big data. In versions before Windows XP, if an inefficient application constantly increased a value with a small increment, it created a sparse and wasteful registry file. Windows XP solves this problem with a big cell implementation where cells larger than 16 KB are split into increments of 16-KB chunks. This reduces fragmentation when the data length of a value is increased within a certain threshold.


Support Enhancements

Numerous product support enhancements have been built into Windows XP, including enhancements to the kernel that improve the debugger shipped with Windows XP and the DDK. These enhancements include:

  • Kernel changes for improved debugging
  • Built-in heap leak detection
  • New heap performance counters

Kernel Changes for Improved Debugging

The debuggers for Windows XP have been redesigned and include tools such as WinDbg, KD, and CDB. Although the new debugger will also work with Windows NT® 4 and Windows 2000, some features are only available when debugging Windows XP. There is also a 64-bit version of all of the debuggers to debug Intel Itanium-based servers running Windows XP.

Kernel enhancements available only for debugging under Windows XP include:

  • Cross-session debugging
  • Quit and detach
  • Debugging over an IEEE 1394 port
  • Dynamic control over debug-child flag
  • Improved KD serial bandwidth usage
  • Loading updated driver files through KD
  • Control over whether terminating a debugger also terminates the debuggee

The Windows XP debugger and debugger documentation are available at http://www.microsoft.com/ddk/debugging.

Cross Session Debugging

Windows XP supports cross-session debugging. Previously, all debugging was done against the Microsoft Win32® environment subsystem (csrss.exe) running on the computer. This caused potential problems, because on Terminal Services each client has its own Csrss process, so that debugging could not be done across terminal sessions. For example, if User1 logged in running Notepad, a second user, such as a system administrator, couldn't perform a terminal session into the same server and debug User1's Notepad process. The debugger code for Windows XP, along with accompanying kernel changes, supports such cross session debugging scenario.

Quit and Detach

Windows XP makes it possible to debug a user-mode application and then detach the debugger, without killing the application. This functionality is supported by a new debugger command, qd (quit and detach), which supports detaching the debugger from an application. The debugger command q has the default behavior of killing the application.

Example: Using Quit and Detach

Using Windows XP, it is possible to investigate an application with a non-crashing problem without killing the application.

To investigate the application

  1. Attach to the process using the debugger.
  2. Debug the application.
  3. Detach the debugger using qd.

Example: Using qd and the .dump Command

When debugging a production machine or other computer you don't want to block with debugging, you can take advantage of qd and .dump command; these commands let you generate a dump file. The .dump command works on any version of Windows NT 4, Windows 2000, or Windows XP if you use the new Windows XP debugger.

To use qd and .dump

  1. Attach to the process using the debugger.
  2. Generate a dump file for the application, using the .dump command.
  3. Detach the debugger using qd.
  4. Analyze the dump file using the debugger (WinDBG -z <dumpfile>) without disturbing the original application.

Debugging over an IEEE 1394 Port

The debugger and debuggee machines running Windows XP can be connected through IEEE 1394 ports. IEEE 1394 provides much better debugger performance than serial port debugging. For details on how to use IEEE 1394 debugging and other debugger features, see http://www.microsoft.com/ddk/debugging.

Dynamic Control over Debug-child Flag

When a process is created for debugging, either the DEBUG_PROCESS or DEBUG_ONLY_THIS_PROCESS flag is used, indicating whether child processes should also be debugged. DebugActiveProcess always debugs with the DEBUG_ONLY_THIS_PROCESS flag. Prior to Windows XP, these flag settings were permanent, but system changes in Windows XP now allow the state of the flag to be changed. This allows debuggers more flexibility in whether child processes are debugged, because the flag can be changed at any time.

Improved KD Serial Bandwidth Usage

Improvements in the kernel debugger protocol reduce the amount of data sent back and forth between the target machine and the kernel debugger, improving debugging performance over slow kernel debugger links.

Loading Updated Driver Files Through KD

Enhancements to the kernel debugger protocol and the kernel now allow the kernel to demand-load driver files from a properly configured kernel debugger. When the system loads a driver, it now queries the kernel debugger to see if the kernel debugger wants to provide the file for the driver in question. If so, the file content is downloaded from the kernel debugger and used. This avoids extra reboots just to copy driver files.

Control over Whether Terminating a Debugger Also Terminates the Process Being Debugged

Prior to Windows XP, terminating a debugger would always kill all processes being debugged by the debugger. The new DebugSetProcessKillOnExit routine allows a debugger to control this behavior and select either a detach or the default kill.

Built-in User Heap Leak Detection

Windows XP provides built-in user mode heap-leak detection. Poorly written or miscoded applications can "leak" heap memory. In earlier versions before Windows XP, when this situation arose, special tools were needed on the server to help identify the cause of the memory leak. User-mode component heap allocation leaks can be seen in two ways:

  • Leak detection when the process is exiting
  • Using a debugger extension to investigate leaks

Leak Detection when the Process Is Exiting

Leak detection is made every time a process is cleanly exiting. It doesn't work if the process is terminated with TerminateProcess() or TerminateThread() / ExitThread() for the last thread in the process; but for most applications this is not a problem.

To enable leak detection when the process is exiting, set the registry key as follows:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\ImageName]

"ShutdownFlags"="3"

Using a Debugger Extension to Investigate Leaks

Windows XP allows you to use a debugger extension to investigate leaks. This is useful because using leak detection when the process is exiting doesn't work for processes such as Explorer.exe, Services.exe, and others that are not cleanly shut down. In such cases, you can attach an NTSD to the process and use the new debugger extension !heap -l to create a similar list. If the size or contents of the block aren't enough to determine whether the program is leaking, you can enable the debug options to get stack traces for these blocks.

!heap -l Usage Example

0:011>!heap -l
Scanning VM ...
Entry   User   Heap   Segment    Size PrevSize Flags
--------------------------------------------------------------------
00178908 00178910 00170000 00000000    258    258 busy extra
....... << other 20 blocks >>
005278a8 005278b0 00520000 00000000    40    80 busy extra
22 leaks detected.

0:011> dc 178908 + 20 l1
00178928 002787bc

0:011> dds 002787bc
002787bc abcdaaaa
002787c0 00000001
002787c4 0000000b
002787c8 00000001
002787cc 0000021a
002787d0 00071000
002787d4 00000000
002787d8 002787dc
002787dc 6a252a35 ntdll!RtlAllocateHeapSlowly+0x5b
002787e0 6a2505a4 ntdll!RtlAllocateHeap+0xa26
002787e4 6a206b0f ntdll!RtlDosPathNameToNtPathName_U+0xd9
002787e8 6a20bc48 ntdll!hOpenFile+0x2e
002787ec 6a20bfff ntdll!bOpenAndMapDB+0x17
002787f0 6a20c1ab ntdll!pdbOpenDatabase+0x2d
002787f4 6a20e4e2 ntdll!trGetMatchingExe+0x1ec
002787f8 6a20b145 ntdll!LdrpInstallAppcompatBackend+0xa0
002787fc 6a2117c6 ntdll!LdrpInitializeProcess+0x9f6
00278800 6a2041a0 ntdll!LdrpInitialize+0x256
00278804 6a2180db ntdll!KiUserApcDispatcher+0x7

In this example, the bug is in hOpenFile, which didn't free the string returned by RtlDosPathNameToNtPathName_U. In all, 22 heap allocations were not freed when the application was exited. The heap address that was allocated is in the entry column, and the size is in the size column. If the GlobalFlag for Stack Backtrace was enabled, then analysis could show the actual functions that allocated the heap memory. This can be done several ways:

  • Use !heap –k <address>, using the address of the heap that is shown to be leaking.

    -Or-

  • As shown in the example, go to the end of the leaking heap allocation, find the stack number that allocated the heap, and dump the structure ntdll!RtlpStackTraceDataBase. This structure holds all of the stack back traces. The stack back traces will be in numerical order, so dump the structure until you get to the stack number you are looking for and then dds <address>, where <address> is the address in the RtlpStackTraceDataBase where your stack number resides.

Note In some cases false positives are seen, such as applications that keep encoded pointers and blocks passed as contexts to local procedure call (LPC) ports. In addition, this doesn't work for an application that has its own heap, such as Microsoft Office applications, or for paged heap enabled with the /full option.

Additional Heap Counters

Another important new feature in Windows XP is heap performance monitoring. Performance Monitor (Perfmon) can display about 20 heap-related counters: amount of memory reserved and committed per heap, number of blocks allocated and freed for three class sizes, average allocated and free time, lock contention, and others. Perfmon will display these counters when the following registry key is set:

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PerfProc\Performance]

"DisplayHeapPerfObject"=dword:00000001

Only the process heap and the heaps with higher usage are monitored.


I/O Subsystem Enhancements

The I/O subsystem consists of kernel components that provide an interface to hardware devices for applications and other mandatory system components. Windows XP enhances the I/O subsystem while retaining complete compatibility with drivers written for Windows 2000. This compatibility was essential because the I/O subsystem provides the interface to all devices, and too many changes to process I/O can break existing applications and drivers.

Enhancements were made by adding new routines, available to drivers written to take advantage of the new Windows XP functionality. For this reason, while existing Windows 2000 drivers will work with Windows XP, they must be rewritten to take advantage of the new I/O improvements, including the following:

  • New cancel queue
  • File system filter driver routines
  • Improved low-memory performance
  • I/O throttling
  • Direct Memory Access (DMA) improvements
  • WebDAV Redirector
  • System Restore
  • Volume Snapshot Service

New Cancel Queue

Rather than having drivers perform device queuing and handling the I/O request packet (IRP) cancellation race, Windows XP I/O automates this process. In Windows XP, drivers handle IRP queuing and do not have to handle IRP cancellations. Intelligence in the queuing process lets the I/O routines handle requests rather than drivers in cases where the I/O is canceled. A common problem with cancellation of IRPs in a driver is synchronization between the cancel lock or the InterlockedExchange in the I/O Manager with the driver's queue lock.

Windows XP abstracts the cancel logic in the routines while allowing the driver to implement the queue and associated synchronization. The driver provides routines to insert and remove IRPs from a queue, and it provides a lock to be held while calling these routines. The driver ensures that the memory for the queue comes from the correct pool. When the driver actually wants to insert something into the queue, it does not call its insertion routine, but instead calls IoCsqInsertIrp.

To remove an IRP from the queue, the driver can either specify an IRP to be retrieved, or pass NULL, and the first IRP in the queue will be retrieved. Once the IRP has been retrieved, it cannot be canceled; it is expected that the driver will process the IRP and complete it quickly.

File System Filter Driver Routines

Several new kernel-mode support routines provide greater all-around reliability. Microsoft worked with third-party developers to test their filter drivers. If a driver crashed attempting to perform illegal functions, together we determined the functionality required, and provided kernel-mode support routines to let them accomplish what needed to be done without harming the rest of the system. These routines are included in the Windows Installable File System (IFS) Kit for Windows XP.

Improved Low-Memory Performance

Windows XP is more resilient during periods of low memory because "must succeed" allocations are no longer permitted. Earlier versions of the kernel and drivers contained memory allocation requests that had to succeed even when the memory pool was low. These allocations would crash the system if no memory were available. Two important I/O allocation routines used "must succeed," with the first being for IRP allocation, and the other for Memory Descriptor List (MDL) allocations. If memory couldn't be allocated, the system would blue screen if these routines were used. For Windows XP, kernel components and drivers are no longer allowed to request "must succeed" allocations; memory allocation routines will not allocate memory if the pool is too low. These changes allow drivers and other components to take appropriate error actions, rather than an extreme approach such as bug checking a machine.

I/O Throttling

Another improvement for low-memory conditions is I/O throttling. If the system can't allocate memory, it throttles down to process one page at a time, if necessary, using freely allocated resources. This allows the system to continue at a slower pace until more resources are available.

DMA Improvements

Three new entries are added to the end of the DMA_OPERATIONS structure. These three entries will be accessible to any driver, which uses IoGetDmaAdapter. To safely check whether the new functionality exists, the driver should set the version field of the DEVICE_DESCRIPTION structure provided to IoGetDmaAdapter to DEVICE_DESCRIPTION_VERSION2.

The current Hardware Abstraction Layers (HAL), which don't support the new interface, will fail the operation because of the version number. HALs that support this feature will understand the new version and will succeed the request, assuming all the other parameters are in order. The driver should try to access these new function pointers only when the driver successfully gets the adapter using DEVICE_DESCRIPTION_VERSION2.

WebDAV Redirector

Windows XP includes a new component — the WebDAV redirector. The WebDAV redirector allows applications on Windows XP to connect to the Internet, and to natively read and write data on the Internet. The WebDAV protocol is an extension to Hypertext Transfer Protocol (HTTP) that allows data to be written to HTTP targets such as the Microsoft MSN® Web Communities. The WebDAV redirector provides file system-level access to these servers in the same that the existing redirector provides access to SMB/CIFS servers.

One way to access a WebDAV share is to use the net use command, for example:

NET USE * http://webserver/davscratch

To connect to an MSN Community, use http://www.msnusers.com/yourcommunityname/files/ as the target. The credentials you need in this case are your Passport credentials; enter these details in the Connect Using Different User Name dialog if you are using mapped network drive, or use the /u: switch with the net use command. For example:

net use http://www.msnusers.com/fooname/files /u:yourpassportaccount@hotmail.com

The simplest ways to create a WebDAV share are:

  • Use Microsoft Internet Information Server (IIS). In IIS, you only need to make a directory browsable to access it through WebDAV and allow writes, and you can also save to it.
  • Use MSN Communities. File Cabinets in MSN Communities are WebDAV shares. For details about how to use this MSN file cabinet, see http://communities.msn.com/filecabinets.

System Restore

System Restore is a combination of a file system filter driver and user-mode services that provide a way for user to unwind configuration operations and restore a system to an earlier configuration. System Restore includes a file system filter driver called Sr.sys, which helps to implement a copy-on-write process. System Restore is a feature only of Windows XP Personal and the 32-bit version of Windows XP Professional; and it is not a feature of the server versions of Windows XP.

Volume Snapshot Service

A volume snapshot is a point-in-time copy of that volume. The snapshot is typically used by a backup application so that it may backup files in a consistent manner, even though the files may be changing during the backup. Windows XP includes a framework for orchestrating the timing for a snapshot, as well as a storage filter driver, not a file system filter driver, that uses a copy-on-write technique in order to create a snapshot.

One important new snapshot-related I/O Control (IOCTL) that affects file systems is IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES. This is actually intended for interpretation by file systems, even though it is an IOCTL. This is because all file systems should pass the IOCTL down to a lower-level driver that is waiting to process the IOCTL after the file system. The choice of an IOCTL instead of an FSCTL ensures that even legacy file system drivers will pass the IOCTL down.

This IOCTL is sent by the Volume Snapshot Service. When a file system such as NTFS receives the IOCTL, it should flush the volume and hold all file resources to make sure that nothing more gets dirty. When the IRP completes or is canceled, the file system then releases the resources and returns.

Changes in Existing I/O Features

Windows XP includes several changes in existing I/O features, including:

  • FAT32 on DVD-RAM

    DVD-RAM disks can appear as both CD/DVD devices and as rewriteable disks. Windows XP will allow DVD-RAM media in DVD-RAM drives to be formatted and used with the FAT32 file system.

  • Defragmentation APIs

    Since the release of Windows NT 4.0, the NTFS file system has exposed APIs that allow a user-mode application to query the allocated ranges of files on disk, and optimize file arrangements in order to defragment (or carefully fragment) files in order to minimize seeks while processing file I/O. In Windows 2000, these APIs have a number of limitations; for example, they do not function on the master file table (MFT), the PageFile, or NTFS attributes. The feature set in Windows XP changes the behavior on NTFS as follows:

    • The defragmentation APIs will no longer defragment data by using the system cache. This means encrypted files will no longer need to be opened with read access.
    • NTFS will now defragment at the cluster boundary for non-compressed files. In Windows 2000, this was limited to the page granularity for non-compressed files.
    • NTFS will now defragment the MFT. This was not allowed in Windows 2000. This is through the regular code path, so there is no limit to how much at once can be moved, and any part of it can be moved other than the first 0x10 clusters. If there is no available space in the MFT to describe the change, then it will be rejected. The API can move an MFT segment even if a file with its File Entry in that section is currently open.
    • NTFS will now defragement for cluster sizes greater than 4 KB. NTFS will now defragment Reparse points, bitmaps, and attribute_lists. These can now be opened for file read attributes and synchronize. The files are named using the regular syntax (file:name:type); for example:

      foo:$i30:$INDEX_ALLOCATION
      foo::$DATA
      foo::$REPARSE_POINT
      foo::$ATTRIBUTE_LIST

    • NTFS's QueryBitmap FSCTL will now return results on a byte boundary rather than page boundary.
    • NTFS will now defragment all parts of a stream, up to and including the allocation size. In Windows 2000, it was not possible to defragment the file tail between valid data length (VDL) and end of file (EOF).
    • You can now defragment into or out of the MFT Zone. The MFT Zone is now just an NTFS-internal hint for the NTFS allocation engine.
    • It is possible to Pin an NTFS file so that it may not be defragmented using FSCTL_MOVE_FILE. This is done by calling FSCTL_MARK_HANDLE and passing MARK_HANDLE_PROTECT_CLUSTERS as an argument. This stays in effect until the handle is closed.
  • Large Files

    Windows XP and Windows 2000 Service Pack 2 are able to create sections on arbitrarily large mapped files. A constraint that had existed in earlier versions of the memory manager (creating Prototype Page Table entries for all pages in the section) does not apply, because the Windows XP memory manager can reuse prototype page table entries (PPTE) for any parts of a section that do not have a mapped view. In fact, it only creates PPTEs for active views based on the view size (not the section size).

  • Verifiers

    There are new Verifier levels in addition to a new deadlock verifier.

  • Read-only NTFS

    NTFS will now mount read-only on an underlying read-only volume. If the volume requires a log restart or a Chkdsk, the mount will fail.

  • New flag: FILE_READ_ONLY_VOLUME

    GetVolumeInformation now returns a FILE_READ_ONLY_VOLUME for read-only volumes.

  • Remote Storage Service (RSS) on MO media
  • Encrypting File System (EFS)

    The Client Side Caching database can now be encrypted.

  • Default NTFS ACL The default access control list (ACL) on NTFS volumes has been strengthened.
  • Read-only flag on directories

    The Read-only attribute has no defined effect on folders. However, in Windows XP, Windows Explorer is using this attribute on a folder to indicate that there is extra metadata in the folder that the shell should look at. This is a performance optimization.

  • Write-through mode

    On hot-plug media, the FAT file system will work in WriteThrough mode. This is to eliminate corruption that could occur on media such as CompactFlash when it is unplugged from the system without using the Safely Remove Hardware user interface.

Read-only Kernel and HAL Pages

On many Windows XP-based systems, the kernel and HAL pages will be marked read-only. This has affected drivers that were attempting to patch system code, dispatch tables, or data structures. The change to read-only kernel and HAL does not happen on all systems:

  • On systems with less than 256 MB RAM, the read-only restriction is used.
  • On systems with 256 MB or more RAM, the read-only restriction isn't used because Windows XP uses large pages to map the kernel and HAL.
  • On all systems, the read-only restriction is used for all driver code because drivers are never mapped with large pages.
  • Driver Verifier disables large pages, so you can enable this on any machine of any size in order to test your code.

New Filter Driver Functions

Windows XP includes several new filter driver function, including:

  • SetShortName. This is a new Win32 function to set the short name of a file on NTFS.
  • GetVolumePathNamesForVolumeName. This new function allows you to list all VolumePaths that a VolumeName may be mounted on.
BOOL
  GetVolumePathNamesForVolumeName(
    LPCWSTR  lpszVolumeName,
    LPWSTR  lpszVolumePathNames,
    DWORD  cchBufferLength,
    PDWORD  lpcchReturnLength
    )

This routine returns a Multi-Sz list of volume path names for the given volume name. The returned lpcchReturnLength will include the extra tailing null characteristic of a Multi-Sz, unless ERROR_MORE_DATA is returned. In such a case, the list returned is as long as possible and may contain a part of a volume path.

Parameters

lpszVolumeName
Supplies the volume name.
lpszVolumePathNames
Returns the volume path names.
cchBufferLength
Supplies the size of the return buffer.
lpcchReturnLength
Returns the number of characters copied back to the return buffer on success or the total number of characters necessary for the buffer on ERROR_MORE_DATA.

Return Value

FALSE
Failure.
TRUE
Success.
  • FileIdBothDirectoryInformation and FileIdFullDirectoryInformation. These two new FileInfo changes have been added to the file information class enumeration. The new file information classes can be passed as FileInformationClass parameter values to ZwQueryInformationFile, ZwSetInformationFile, and IRP_MN_QUERY_DIRECTORY.
  • SetFileValidData. NTFS has the concept of Valid Data Length on a file stream. This is a way to preserve the C2 'Object Reuse' requirement but not force file systems to write zeroes into file-tails. Definitions:
    • VDL = 'Valid Data Length'. Each stream has such a value.
    • EOF = Allocated file length. Each stream has such a value.
    • File Tail = the region from VDL to EOF. Clearly, each stream has such a region and it may be zero length.

By definition, VDL must be less than or equal to the EOF. Any reads from the file tail are implicitly returned as zeroes by NTFS. Any writes into the file tail cause VDL to be increased to equal the end of this write, and any data between the previous VDL and the start of this write are written to be zeroes. In Windows XP, we have added an NTFS-only function call to set the Valid Data Length on a file, available to administrative users with SeManageVolumePrivilege (described later in this section).

Expected users include:

  • A Restore application that has the ability to pour the raw clusters directly onto the disk through hardware channel. This provides a method for informing the file system that the range contains valid user data and it can be returned to the user.
  • Multimedia/database tools that need to create large files, but not pay the zero-filling cost during the following times:
    (a) file extend time (the cost here is to make the extend a synchronous operation)
    (b) create time (the cost here is filling the file with zeroes)
  • Served-metadata cluster file systems that need to remotely extend the file, then "pump in" the data directly to the disk device.
  • SeManageVolumePrivilege. The SeManageVolumePrivilege will let non-administrators and remote users do administrative disk tasks on a machine. With Windows XP, this privilege is only used to allow non-administrators and remote users make the SetValidData call. In the future, it will allow validated users to perform actions on the disk currently restricted to administrators.
  • IoAllocateWorkItem and IoQueueWorkItem. These routines supersede ExInitializeWorkItem and ExQueueWorkItem, and are essential to support driver unloading.
  • IoGetDiskDeviceObject. Returns the disk device object associated with a file system volume device object. The disk device object need not be an actual disk but in general associated with storage.


Memory Management Enhancements

Windows XP provides improved memory management. The memory manager provides the system services to allocate and free virtual memory, share memory between processes, map files into memory, flush virtual pages to disk, retrieve information about a range of virtual pages, change the protection of virtual pages, and lock the virtual pages into memory. The memory manager also provides a number of services, such as allocating and deallocating physical memory and locking pages in physical memory for DMA transfers, to other kernel-mode components inside the executive as well as to device drivers.

Memory management enhancements include the following:

  • Logical prefetcher for faster boot and application launch
  • Enhanced memory management for better scalability
  • Reduced paged pool usage
  • Increased number of system Page Table Entries (PTE)
  • Support of giant drivers

Logical Prefetcher for Faster Boot and Application Launch

When a Windows XP system is booted, data is saved about all logical disk read operations. On later boots, this information is used to prefetch these files in parallel with other boot operations. During boot and application launch, a Windows system demands and pages a sizable amount of data in small chunks (4 KB to 64 KB), seeking between files, directories, and metadata. The Logical Prefetcher, which is new for Windows XP, brings much of this data into the system cache with efficient asynchronous disk I/Os that minimize seeks. During boot, the Logical Prefetcher finishes most of the disk I/Os that need to be done for starting the system in parallel to device initialization delays, providing faster boot and logon performance.

Logical prefetching is accomplished by tracing frequently accessed pages in supported scenarios and efficiently bringing them into memory when the scenario is launched again. When a supported scenario is started, the transition page faults from mapped files are traced, recording which page of a file is accessed. When the scenario has completed (either the machine has booted or the application started), the trace is picked up by a user-mode maintenance service, the Task Scheduler. The information in the trace is used to update or create a prefetch-instructions file that specifies which pages from which files should be prefetched at the next launch.

The user-mode service determines which pages to prefetch by looking at how successful prefetching has been for that scenario in the past, and which pages were accessed in the last several launches of the scenario. When the scenario is run again, the kernel opens the prefetch instructions file and asynchronously queues paging I/O for all of the frequently accessed pages. The actual disk I/Os are sorted by the disk drivers to go up the disk once to load all pages that are not already in memory. This minimizes seeks, cuts down on disk time, and increases performance. The kernel also prefetches the file system metadata for the scenario, for example, MFT entries and directory files. Because prefetching is useful only when the required data is not in memory, the applications that are launched frequently are not traced and prefetched each time.

Settings for Logical Prefetch

Registry setting:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session
Manager\Memory Management\PrefetchParameters
RootDirPath - Key Name
Reg_SZ     _ Data Type
Prefetch    - Value <default>

Value Names:

EnablePrefetcher (DWORD)
0x00000001= application launch prefetching
0x00000002= boot prefetching

Parameters are ANDed, so if all were enabled, the setting would be 0x00000003. The setting takes effect immediately. In Windows XP Server editions and later versions, only the boot prefetch is enabled by default. Application prefetch can be enabled by the registry setting cited here. The system boot prefetch file is in the %systemroot%\Prefetch directory. Although these prefetch-readable files can be opened using Notepad, they contain binary data that will not be recognized by Notepad. If you are going to view these file, make them read only or copy them to a different location before opening.

Scalability Improvements Due to Reduced Lock Contention

After significant analysis to identify the resource synchronization incurring the highest contention, the memory management subsystem has gone through numerous changes for Windows XP to reduce Page Frame Number (PFN), address windowing, system PTE, and dispatcher lock contention. The changes removed numerous unnecessary locks and in many cases redesigned the type of locking done, improving both scalability and performance.

Improved Caching and Backup Due to Dynamic Paged Pool Usage

A major redesign of some internal Memory Manager structures causes substantially less paged pool to be consumed, allowing for greater caching capacity and faster response.

Paged pool is now only allocated while a view is active and even then, only for an amount proportional to the actual view size. When a view is unmapped, that pool is then immediately available for reclaiming if the system detects that overall pool usage is high. This can be done because the pool can be dynamically reallocated and repopulated later if the caller requests the view again. Paged pool used to be allocated for an amount proportional to the section (file) size, regardless of the actual views that were ever used.

  • File backup of any size can now be accomplished, from a machine of any size. File back up of any size is possible because prototype PTEs are dynamically constructed and trimmed. It is possible to back up a 500-GB file from a 32-MB client, whereas previously you couldn't back it up at all.
  • Much greater availability of paged pool for any component that needs it, since the major amount of it (prototype PTEs) can now automatically grow and shrink dynamically in response to how the system is being used.

Improved Server Scaling Due to Individual Page Charging

Greater scalability by reducing memory requirements for some operations. For example, a Web server that serves the same 4K page to 10,000 clients would require 40 MB, so that a lack of space could result in refusing requests. With Windows XP, only one page is charged, because the system knows that it's the same page, not 10,000 separate pages. This provides a substantial boost in scalability.

Improved Terminal Server and Network Server Scaling Due to Increased Number of System PTEs

The number of system Page Table Entries (PTE) has been increased to a maximum of approximately 1.3 GB, of which just under 1 GB is virtually contiguous. This is approximately twice as many PTEs as were available in Windows 2000 and six times more than in Windows NT 4.0. This is subject to system configuration, such as RAM, registry switches, and other factors. Currently, a system must:

  • Be booted without the /3GB switch.
  • Have 128 MB or more of RAM.
  • Not have the registry key set that allows this RAM to be used for system cache (as it must be used for system PTEs instead).
  • Not have registry keys set to make session space or system mapped views larger than the default 48 MB.

On an x86-based systems with 256 MB, the changes made it possible to allocate a 960-MB contiguous mapping. The new mapping is made to keep the PTEs contiguous; by not freeing this second huge chunk of PTEs into the generally available pool until the initial (smaller) PTE pool cannot satisfy a request. Thus, the system will not fragment a big PTE before a driver can access it. Drivers should only experience contention for this resource from another driver that wants a huge chunk, instead of from small random system or driver allocations that happen to occur first.

These extra PTEs also greatly enhance any configuration where PTE usage is critical, for example Terminal Server scenarios, network servers with many concurrent I/Os, and so on.

Support of Giant Drivers Due to Increased Number of System PTEs

Windows XP supports giant driver mappings. Although video drivers are the most obvious benefactors, this also enables other specialized drivers that support large amounts of dedicated RAM. Windows XP supports nearly a gigabyte of virtual continuous space for a driver. This compares to support of about 220 KB for Windows 2000 and about 100 KB for Windows NT 4.0.

Support of Direct Execution from ROM

Windows XP supports executing applications directly from ROM. This enables products like Windows NT Embedded to ship on ROMs, allowing manufacturers to ship systems without disk drives for specific markets.


Power Management Enhancements

Windows XP brings improvements to the Power Manager, while continuing to support legacy drivers. The Power Manager, which is responsible for managing power usage for the system, administers the system-wide power policy and tracks the path of power IRPs through the system. As with Windows 2000, the Power Manager requests power operations by sending IRP_MJ_POWER requests to drivers. A request can specify a new power state or can query whether a change in power state is feasible. When sleep, hibernation, or shut down is required, the Power Manager sends an IRP_MJ_POWER request to each leaf node in the device tree requesting the appropriate power action. The Power Manager considers the following in determining whether the system should sleep, hibernate, or shut down:

  • System activity level
  • System battery level
  • Shutdown, hibernate, or sleep requests from applications
  • User actions, such as pressing the power button
  • Control Panel settings

Power management works on two levels, one applying to individual devices and the other to the system as a whole. The Power Manager, part of the operating system kernel, manages the power level of the entire system. If all drivers in the system support power management, the Power Manager can manage power consumption on a system-wide basis, utilizing not only the fully-on and fully-off states, but also various intermediate system sleep states.

Legacy drivers that were written before the operating system included power management support will continue to work as they did previously. However, systems that include legacy drivers cannot enter any of the intermediate system sleep states; they can operate only in the fully on or fully off states as before. Device power management applies to individual devices. A driver that supports power management can turn its device on when it is needed, and off when it is not in use. Devices that have the hardware capability can enter intermediate device power states. The presence of legacy drivers in the system does not affect the ability of newer drivers to manage power for their devices.


Improved Boot and Logon Performance

Customer research has shown that one of the most frequently requested features that users want from their computers is fast system startup, whether from cold boot or when resuming from standby or hibernation. When a Windows XP system is first booted, data is saved about all logical disk read operations. On later boots, this information is used to prefetch these files in parallel with other boot operations. The Windows XP operating system has improved startup times, which provides opportunities for system manufacturers who want to improve boot and resume times for new computers. Windows XP has several improvements in the boot and resume processes, including:

  • Boot loader improvements
  • Operating system boot improvements
  • Operating system hibernation improvements
  • Operating system standby resume improvements

Boot Loader Improvements

The key boost to boot loader performance is through optimizing the disk reads. The Windows XP boot loader (Ntldr) caches file and directory metadata in large chunks in a most-recently-used manner, which reduces disk seeking. Each system file is now read with a single I/O operation. The resulting improvement in Windows XP is that the boot loader is approximately four to five times faster than in Windows 2000. Additionally, redundant PS/2-compatible mouse checks were removed from Ntldr.

Boot loader enhancements also provide similar improvements in hibernation resume times, mainly by streamlining the I/O paths used by Ntldr to read the hibernation image. The hibernation file is compressed as it is written, and for efficiency, the compression algorithm overlaps with the file I/O. However, when resuming from hibernation, Ntldr is using the BIOS to perform the I/O; therefore, it is not feasible to overlap the disk I/O reads with the decompression.

Operating System Boot Improvements

Optimizing operating system load in Windows XP is achieved by overlapping device initialization with the required disk I/Os, and by removing or delaying loading all other processes and services from boot that are unnecessary at boot time. When tuning a system for fast booting, it is crucial to look at both the efficiency of device initialization and the disk I/Os. Windows XP initializes device drivers in parallel to improve boot time. Instead of waiting for each device sequentially, many can now be brought up in parallel. The slowest device has the greatest effect on boot. Overlapped device initialization can be viewed with the Bootvis.exe tool.

For more information, see http://www.microsoft.com/hwdev/fastboot/.

For optimizing boot time, device drivers should only do what is required to initialize the device during boot, and defer all else to post-boot. The goal is that the device is usable after boot, but does not delay boot unnecessarily. Device drivers should never hold spin locks except for very short time, particularly during boot, as this defeats any parallelism.

Examples of gains made by overlapping device initialization with disk I/O include:

  • For computers not in a domain, network initialization is now done in parallel to boot. Winlogon will not wait for network initialization for computers in a workgroup; however, those computers in a domain will still wait.
  • Serial Plug and Play is now overlapped. Serial Plug and Play detects attached serial devices. This used to take 2.5 to 3 seconds for normal computers, and could take several minutes in large servers with lots of ports.
  • Protocol binding is now done in parallel to boot. Previously, NDIS caused boot delays while binding protocols to adapters, due to the adapter negotiating link speed with hubs and switches. This also affects computers having network adapters without network cables attached.
  • ATAPI boot disk enumeration has been improved from approximately 6 seconds to 2 seconds. Boot disk enumeration stalls all disk I/O during boot.

    In addition, several other services are now initialized in parallel to boot.

Operating System Hibernation Improvements

During hibernation, all devices are powered off, and the system's physical memory is written to disk in the system hibernation file, Hiberfil.sys. Before Windows XP writes to the hibernation file, all memory pages on the zero, free, and standby lists are freed; these pages do not need to be written to disk. Memory pages are also compressed before being written.

To optimize the hibernation process in Windows XP, several improvements have been implemented. The compression algorithm has been optimized to compress and decompress large blocks (64 KB) of data. In addition, the compression is overlapped with the disk write. As the current data block is being transferred to the disk, the next block of data is being compressed. Overlapping the compression with disk writes makes the compression time virtually free. Also, the hibernation file is written using IDE DMA instead of PIO mode. Most modern IDE controllers and disks achieve their best performance only in DMA mode.

Operating System Standby Resume Improvements

During resume from standby, the operating system sends S0 IRPs to devices to indicate the change in system power state. As noted in the Power Management section of this paper, device drivers typically request D0 IRPs to change their device power state. The operating system is responsible for notifying each device in the correct order. There are two key ordering rules that must be followed to prevent deadlocks:

  • A device cannot be turned on until its parent is turned on.
  • All non-paged devices must be turned on before any paged device is turned on.

Because many devices may take significant time to go from D3 to D0, the key to good resume performance is to overlap device initialization as much as possible. The ordering chosen by the operating system is important in maximizing parallelism.

The following changes have been implemented to optimize the resume performance in Windows XP:

  • The Sx IRP dispatching engine has been rewritten to maximize potential parallelism.
  • USER has been changed to dispatch power events asynchronously, instead of tying up a worker thread waiting for them to complete.
  • NDIS.SYS has been changed to complete S0 IRPs immediately, instead of waiting for D0 to complete and then initializing on a lower priority thread.
  • Worker thread stacks are locked in memory before starting power operations, and unlocked when resume is complete.
  • The kernel Plug and Play manager has been changed so it does not tie up a worker thread with an enumerate operation while waiting for power operations to complete.
  • Pcmcia.sys, Kbdclass.sys, and Mouclass.sys have been changed to initialize in the background.

Windows XP Boot and Resume Tools

Windows XP has the ability to trace boot and resume metrics, and to dump the resulting information to a binary file viewable through Bootvis.exe and other tools. Bootvis.exe displays various time-interlocked graphs showing such things as CPU Usage, Disk I/O, Driver Delays and resume activity. Bootvis.exe can show many types of useful details; the best way to start is by dragging an area on the graph and either double-clicking it or right-clicking to use the context menu to see what options are available. The operating system instrumentation starts about one second after the boot loader loads. Overall boot time shown in Bootvis.exe should add BIOS power-on self test (POST) time + one second. Taking boot traces with Driver Delays will lengthen boot by two to three seconds. The resulting binary file will be several megabytes in size.

Information on using Bootvis.exe and improving boot and resume can be found at http://www.microsoft.com/hwdev/fastboot/.


Headless Support

Windows XP provides native support for "headless server" operation on server platforms — that is, support for operating without a local display or input devices. Microsoft and Intel worked with the computer industry to define firmware and hardware requirements for server operations that include requirements for headless operation under Windows XP as part of Hardware Design Guide Version 3.0 for Microsoft Windows 2000 Server, which is available for download at http://www.microsoft.com/hwdev/serverdg.htm.

Additionally, Microsoft provides detailed documentation on how to design hardware and firmware that integrates well with headless server support included in Windows XP. For additional technical information about Windows support for headless operation, see http://www.microsoft.com/hwdev/headless/.

Providing Out-of-Band Management

Windows provides many mechanisms for remotely managing a system when the operating system is loaded, fully initialized, and the system is functioning. This type of system management is called "in-band" management, and it typically occurs over the network. However, a different solution is required for managing a system when Windows network software is unavailable. For example, when the system has failed, when Windows is not loaded, when the system is in the process of loading, or when Windows is fully loaded, but the Windows network software is not available. Remote management that does not rely on Windows network software is called "out-of-band" management.

The goal for out-of-band management is to always return the system to a fully functioning state where in-band management is available. Making both in-band and out-of-band management available remotely are key components of headless functionality. With the exception of hardware replacement, all administrative functions that can be accomplished locally should be available remotely. For example, the following capabilities should be available for remote management:

  • Power on a system that is currently off.
  • Change BIOS settings or view POST results.
  • Choose the operating system and set operating system options.
  • Interact with specific diagnostic and recovery tools.
  • View system blue screens.
  • Reset a system.

To accommodate the many possible system operation states, careful thought must be given to hardware, firmware, and operating system functionality to ensure a comprehensive and complementary implementation of out-of-band management capabilities. Each system component must contribute to a coherent, complementary solution in order to avoid expensive, confusing administration.

Implementing Headless Support in Windows XP

A headless solution requires that local console I/O dependencies be removed from the operating system. Windows XP supports operating without a keyboard, mouse, or monitor attached to the system. On an ACPI-enabled system, Windows XP supports operating without a legacy 8042 keyboard controller. Windows XP also includes support for systems without VGA/display hardware.

Based on built-in Windows support, a USB-capable system running Windows XP can support hot plugging the mouse and keyboard while the operating system is running, and a system with a VGA card can support hot plugging a monitor.

In Windows XP, out-of-band console I/O support is provided for all Windows kernel components—the loader, setup, recovery console, operating system kernel, and blue screens — and for a text-mode management console available after Windows XP has initialized, which is called the Special Administration Console. This functionality is called the Emergency Management Services (EMS). This I/O conforms to the following by default:

9600 baud
1 stop bit
No parity
8 data bits
Hardware flow control

Output conventions are defined in Standardizing Out-of-Band Management Console Output and Terminal Emulation (VT-UTF8 and VT100+), available at http://www.microsoft.com/hwdev/headless/.

Note These settings were chosen because they are the current "standard" configuration in UNIX administration and allow interoperability. However, additional settings are supported and may be passed through the Serial Port Console Redirection Table; documentation is available on the web at http://www.microsoft.com/hwdev/headless/.

Designing Hardware and Firmware

There are three key areas that must be addressed to provide a high-quality headless platform that is cleanly integrated with Windows XP EMS:

  • Management port hardware: Windows XP will support a standard legacy serial port.

    The headless functionality in Windows XP supports a standard 16550 serial port at the legacy address of COM1, COM2, COM3, or COM4, 3F8, 2F8, 3E8, and 2E8, respectively, or a UART at well-known non-legacy address. A server must provide at least one UART interface capable of being used by Windows XP EMS. See the item "Passing of the out-of-band communication channel configuration information from the firmware to Windows XP" below for more information on making the location of the UART well known. A separate debug port must also be available and may not be the same port as used for EMS.

    When using a serial port connection to access Windows EMS support, all serial cables must be null modem cables that support the Carrier Detect (CD) signal. Windows will not provide console I/O if Carrier Detect is not active.

    Note: Cables with Carrier Detect shorted to Ready to Send (RTS) will work.

  • Standardized firmware and service processor management console user interfaces: It is important the system firmware and out-of-band management service processor user interface be available via the same out-of-band communication channel as the EMS. The firmware must cleanly hand off the communication channel to the EMS during the boot process. The firmware must use the same terminal definition as Windows XP EMS, which includes using the same keystrokes to represent not standardized keystrokes, such as F12.
  • Passing of the out-of-band communication channel configuration information from the firmware to Windows XP: This is achieved via the Serial Port Console Redirection Table or optionally, on 64-bit systems, the EFI Console Device Path.

For more information, see http://www.microsoft.com/hwdev/headless/.


Hot-Add Memory and Memory Mirroring Support

Windows XP introduces hot-add memory support, which will allow memory devices to be added to a machine and be made available to the operating system and applications as part of the normal memory pool — without turning the machine off or rebooting.

Hot-add memory support will be especially appreciated by enterprise system administrators who need to add memory resources to keep up with production demands, but are working with systems that require continuous (24x7) availability. This action would typically require shutting down the system and interrupting service. With the hot-add feature, service performance can be increased without service interruption.

Removal of memory regions will not be supported in Windows XP. A memory upgrade, which requires removing and then adding memory, will also not be supported in Windows XP.

Memory mirroring (different from hot-add) is also introduced in Windows XP, providing increased availability for extremely high-end systems (for example, Stratus, and so on).

Caution This feature will operate only on servers that have hardware support for adding memory while the server is operating. Most existing servers do not have this type of hardware support and could be damaged if memory is installed while the power is on. Consult the server operator's manual for more information. A small number of new servers will offer the ability to add memory while the server is operating. For these servers, the act of installing memory will automatically invoke the hot-add memory feature in the operating system.


ccNUMA Support

Windows XP supports ccNUMA and NUMA-"lite" designs. This provides for near:far memory access time ratios of 1:3 or less.

Note For optimal performance with Windows 2000 and later operating systems, it is recommended that system designers who are building platforms that present memories with different access times keep the ratio for access to "near" versus "far" memories relative to a given microprocessor at a 1:3 ratio or less, as seen by the operating system.

As processor speeds relative to bus speeds and the number of processors in symmetric multi-processor (SMP) systems have increased, the system bus and main memory have become a significant bottleneck. The trend in High Performance Computing (HPC) over the last decade has been to reduce dependence on a single system bus or system memory by building smaller systems (nodes), each with their own processors and memory, then providing a high-speed cache coherent interconnect network to form a larger system. Access from a processor to node local memory is fast, as is the case with small SMP systems. Access to memory in another node is much slower. Earlier systems using this approach could result in as much as a 50 times decrease in performance for remote versus local access.

Today, the difference has been reduced significantly, but is still (usually) in the range of two to three times as long to access remote memory (versus local). Operating systems such as Windows 2000, which have been designed for SMP systems, can work acceptably on these newer systems; but significant performance gains are possible if the operating system is aware of underlying architecture. Windows XP contains code to take advantage of the memory available in both the current processor node as well as memory assigned to other processor nodes.

Per Node Memory Allocation

An effective method for improving performance on a ccNUMA machine is to ensure that the processors use the memory closest to them. This guideline includes continuously running threads on the same processor node. Page coloring is used in Windows 2000 to ensure that page allocation is spread as much as possible throughout the physical address space of the system. To achieve good page placement in a ccNUMA system, each node will have its own palette of colors. Page allocation is round-robin within the palette of the node containing the threads ideal processor. If no pages are available in the palette, then we will round-robin from all colors in all palettes.

Per Node Scheduling

The thread scheduler has been changed to examine and favor the following processor configurations:

  • A thread's ideal processor
  • Any real processor that is in the same node as the threads ideal processor
  • Any logical processor that is in the same node as the threads ideal processor
  • The highest numbered processor in the same node as the threads ideal processor

If this prioritization fails, then Windows XP will only consider other processor nodes if the average processor utilization of the other nodes is lower than the average utilization of the ideal node.

OEM Support for ccNUMA

For Windows XP to utilize these additions for proper ccNUMA support, original equipment manufacturers (OEM) must supply a HAL to identify and talk to the hardware in a way that Windows XP can understand. There is a BIOS feature that, if used on the OEM hardware, can function properly out of the box with the Itanium-based HAL that ships with Windows XP. This is the Static Resource Affinity Table (SRAT).

Static Resource Affinity Table

With the current Enterprise market trend to build large-scale systems out of "nodes" of smaller scale systems, the best performance is typically achieved when processors use memory that is physically located in the same smaller system node as the processor, rather than using memory located in other nodes.

SRAT, as described in the ACPI specification, can be used to describe the physical location of processors and memory in large-scale systems (such as ccNUMA) to Windows, allowing threads and memory to be grouped in an optimal manner.

The SRAT contains topology information for all the processors and memory present in a system at system boot, including memory that can be hot removed. The topology information identifies the sets of processors and physical memory ranges in the system, enabling a tight coupling between the processors and memory ranges in a node.

The ACPI 2.0 specification introduces the concept of proximity domains within a system. Devices in a system that belong to a proximity domain are tightly coupled, or "closer," to each other than to other devices in the system. For example, in a ccNUMA machine consisting of several nodes interconnected through a switch, the latency of memory accesses from a processor to memory on the same node would typically be shorter than the latency of memory accesses on other nodes. The operating system should use this affinity information to determine the allocation of memory resources and the scheduling of software threads, therefore improving performance on large systems.

Including the methods that provide affinity information in the ACPI Namespace enables a generic mechanism that provides topology information. This information can be used to resolve scenarios in which components such as processors and memory can be hot added and hot removed from the system.

The Proximity method (_PXM) included in the ACPI 2.0 specification enables the specification of affinity between various devices in the ACPI Namespace. The _PXM method associated with a device in the ACPI Namespace returns a domain number. All devices that return the same domain number belong to the same proximity domain. In addition, specifying memory, processor devices, and the methods for identifying and removing these devices, enables the infrastructure for supporting hot-plug memory. However, defining the proximity and hot-plug information in the ACPI Namespace (instead of static ACPI tables) makes it unavailable to the operating system until the ACPI components of the operating system load.

Depending on the load order of the ACPI components with respect to the operating system construction of memory pools and processor startup, affinity and memory hot-plug information in the ACPI Namespace might not be available at the desired system startup phase. The SRAT addresses this problem and makes the affinity and hot-remove memory information available to the operating system in a static fashion before the ACPI components load. This information is needed only at boot time; only processors and memory present at boot time are represented. Unpopulated "slots" for memory and processors that can be hot added do not need to be represented.

The SRAT uses the concept of proximity domains to provide resource affinity information, similar to the domains used in the ACPI 2.0 specification. However, the domain numbers provided by the SRAT do not need to be identical to those used in the ACPI 2.0 Namespace. The SRAT is intended to enable operating system optimizations for the Windows Datacenter Server class of machines with multiple processors and ccNUMA characteristics. These machines must also support the APIC/SAPIC interrupt model.

How the Operating System Can Use SRAT

The SRAT is provided as an intermediate step to enable features such as ccNUMA optimizations on Windows Datacenter Server class machines until the capabilities of accessing the ACPI 2.0 Namespace are available at the desired startup phase. Until these capabilities are available, the operating system will scan and use the information provided in the SRAT at boot time. However, after these capabilities are integrated in the operating system, the operating system will no longer use the SRAT or the information provided in the ACPI namespace.

The SRAT provides data for the performance optimization of ccNUMA systems. The use of fine-grained interleaving, in which the memory is interleaved across the nodes at a small granularity, is mutually exclusive with respect to ccNUMA optimizations. The BIOS should not provide an SRAT if fine-grained interleaving is enabled. Fine-grained interleaving should be disabled if the SRAT is provided. It is expected that ccNUMA optimization will provide superior performance over fine-grained interleaving. Furthermore, the operating system will not support hot-plugging memory in the presence of interleaving.

The operating system will scan the SRAT only at boot time. The BIOS/system is expected to retain the proximity information used by the operating system at boot time across the lifetime of the operating system instance (until the next boot). This specifically implies that the BIOS/system retains the system topology across a system sleep state transition in which processor or memory context is lost (S2–S5), such that the proximity information provided by the SRAT at operating system boot time is valid across the transition. If the system topology is not retained, memory viewed as "local" to a set of processors could potentially become "non-local" memory on return from the sleep state and have an adverse impact on system performance.

The BIOS can use the Prepare to Sleep (_PTS) method to initiate the process of saving all information necessary to replicate the system topology. The BIOS can also use the sleep state argument that is provided by the operating system to the _PTS method to determine if the state save is required. If memory or processor hot-plug were not supported, providing a deterministic selection of boot processor/processor order in the Multiple APIC Description Table (MADT) and programming of the memory regions would be sufficient to ensure identical system topology on return from the sleep state.

The BIOS must reconstruct the SRAT on system reboot similar to the MADT.


Windows XP Support for New Partition Table Format

Windows XP supports the Extensible Firmware Interface (EFI), a new standard for the interface provided by the firmware that boots PCs. Microsoft will support EFI as the only firmware interface to boot the 64-bit version of Windows for Itanium-based systems. Because the 64-bit version of Windows will not boot with BIOS or with the system abstraction layer (SAL) alone, EFI is a requirement for all Itanium-based systems to boot Windows.

Windows XP also supports the Globally Unique Identifier (GUID) Partition Table (GPT), which was introduced as part of the EFI initiative. GPT complements the older Master Boot Record (MBR) partitioning scheme that has been common to PCs. GPT allows use of very large disks. The number of partitions on a GPT disk is not constrained by temporary schemes such as container partitions, as defined by the MBR Extended Boot Record (EBR).

The GPT disk partition format is well defined and fully self-identifying. Data critical to platform operation is located in partitions and not in unpartitioned or hidden sectors. GPT disks use primary and backup partition tables for redundancy and CRC32 fields for improved partition data structure integrity. The GPT partition format uses version number and size fields for future expansion. Each GPT partition has a GUID and a partition content type, so no coordination is necessary to prevent partition identifier collision. Each GPT partition has a 36-character Unicode name, which means that any software can present a human-readable name for the partition without any additional understanding of the partition.

For information about the EFI standard, see http://www.microsoft.com/hwdev/efi/.


Windows XP Support for Itanium-based Systems

Windows XP for Intel® Itanium™-based systems is a fully featured 64-bit operating system that is compatible with most existing 32-bit applications. The 64-bit Windows operating system will provide high availability, advanced scalability, and large memory support based on the Intel Itanium chip with its extensive multiprocessing features, powerful floating-point arithmetic extensions, and multimedia-specific instructions. 64-bit Windows and the Itanium microprocessor are designed to address the most demanding business needs of today's Internet-based world including e-commerce, data mining, online transaction-processing, memory-intensive high-end graphics, complex mathematics, and high-performance multimedia applications.

The Microsoft vision is to make a broad portfolio of applications available, including leading Microsoft applications on 64-bit Windows. To achieve this goal, Microsoft will provide a rich set of development tools that will make it easy to write new applications and port existing ones. The 64-bit Windows platform will bring the following benefits to developers and end users:

  • The full advantage of Intel Itanium-based architecture for reliability, high performance, and high availability
  • Compatibility with Windows 2000-compatible applications and existing Win32-based applications
  • API-level compatibility between the Microsoft Win64® API and the Win32® API.
  • Scalability of virtual memory up to 16 terabytes (TB)
  • Interoperability with systems based on existing 32-bit architectures

Benefiting from 64-bit Architecture

A 64-bit operating system supports far more virtual memory than a 32-bit operating system. For example, 32-bit Windows XP supports 4 GB of virtual memory, while 64-bit Windows supports 16 TB of virtual memory. Non-paged pool increases substantially, up to 128 GB for the 64-bit platform compared to 256 MB maximum for the 32-bit platform. With these new higher limits, the scalability that the 64-bit platform offers is enormous in terms of terminal server clients, page pools, network connections, and so on.

  • Each application can support more users. All or part of each application must be replicated for each user, which requires additional memory.
  • Each application has access to larger amounts of memory, which can increase performance in some scenarios.
  • Each application has more memory for data storage and manipulation. Databases can store more of their data in the physical memory of the system. Data access is faster because disk reads are not necessary.
  • Applications can manipulate large amounts of data easily and more reliably. Video composition for motion picture work requires 64-bit Windows for this reason. Modeling for scientific and financial applications benefits greatly from memory-resident data structures that are not possible on 32-bit versions of Windows.

There are also important benefits for businesses:

  • Increased productivity. Knowledge workers can spend their time thinking and producing, rather than waiting for the software to finish its tasks.
  • Lower cost of ownership. Each server can support larger numbers of users and applications, so your business will require fewer servers. This translates directly into less management overhead—one of the highest costs in any computing environment.
  • New application opportunities. New applications can be designed without the barriers imposed by 32-bit Windows. Data-intensive tasks that are impossible today can be done with 64-bit Windows.

Designing for 64-Bit Compatible Interfaces

Porting drivers or software created for 32-bit Windows to 64-bit Windows should not create any problems for distributed applications, whether they use Remote Procedure Calls (RPC) or DCOM. The RPC programming model specifies well-defined data sizes and integer types that are the same size on each end of the connection. In addition, in the LLP64 abstract data model developed for 64-bit Windows, only the pointers expand to 64 bits—all other integer data types remain 32 bit. Because pointers are local to each side of the client/server connection and are usually transmitted as NULL or non-NULL markers, the marshaling engine can handle different pointer sizes on either end of a connection transparently.

However, backward compatibility issues arise when you add new data types or methods to an interface, change old data types, or use data types inappropriately.

For more information on developing for the 64-bit system, see http://msdn.microsoft.com/library/default.asp?URL=/library/psdk/buildapp/64bitwin_410z.htm.


Components Removed

Several Windows 2000 components are removed in Windows XP:

  • POSIX subsystem
  • OS/2 subsystem
  • NEC PC98 support
  • SGI 320 and SGI 540 support


Designed for Windows XP Logo Program Requirements

Requirements for the Windows Logo Program for hardware that apply specifically for systems or peripherals that will receive the "Designed for Windows XP" are defined in Microsoft Windows Logo Program System and Device Requirements, Version 2.0,
available on the web site at http://www.microsoft.com/hwdev/winlogo/.

Windows Hardware Quality Labs (WHQL) is providing the Hardware Compatibility Tests (HCT) for Windows XP. For information, see http://www.microsoft.com/hwtest/.


References

For the Windows XP debugger, see http://www.microsoft.com/ddk/debugging.

For more information on improving boot and resume, see http://www.microsoft.com/hwdev/fastboot/.

For more information on headless support, see http://www.microsoft.com/hwdev/headless/.

For more information on the PCI Hot-Plug Specification, see http://www.pcisig.com.

For more information on the ACPI specification, see http://www.microsoft.com/hwdev/onnow.

For more information on developing for the 64-bit system, see http://msdn.microsoft.com/library/default.asp?URL=/library/psdk/buildapp/64bitwin_410z.htm.

For information about memory and I/O resource allocations for PCI-to-PCI bridges, see http://www.microsoft.com/hwdev/pci/pcibridge-cardbus.htm.


Acronyms

ACL – access control list

ACPI – Advanced Configuration and Power Interface

API – application programming interface

APM – Advanced Power Management

BIOS – basic input/output system

ccNUMA – Cache Coherent – Non Uniform Memory Architecture

CD – Carrier Detect

DDK – Driver Development Kit

DMA – direct memory access

DVD-RAM – Digital Video Disk Random Access Memory

EBR – Extended Boot Record

EFI – Extensible Firmware Interface

EFS – Encrypting File System

EMS – Emergency Management Services

EOF – end of file

FAT – file allocation table

GPT – GUID partition table

GUID – globally unique identifier

HAL – hardware abstraction layer

HCT – Hardware Compatibility Test

HPC – high performance computing

HTTP – Hypertext Transfer Protocol

IDE – Integrated Device Electronics

IFS – Installable File System

IHV – independent hardware vendors

IIS – Microsoft Internet Information Server

I/O – input/output

IOCTL – I/O Control

IRP – I/O request packet

ISV – independent software vendor

KCB – kernel control block

LED – light-emitting diode

LPC – local procedure call

LRU – least recently used

MADT – multiple APIC description table

MBR – Master Boot Record

MDL – Memory Descriptor List

MFT – master file table

MSN – Microsoft Network

NDIS – Network Driver Interface Specification

NTFS – NT File System

Ntldr – NT Loader

OEM – original equipment manufacturer

PCI – Peripheral Component Interconnect

PFN – page frame number

PIO – programmed I/O

POST – power-on self test

PPTE – prototype page table entries

PTE – page table entries

RAM – random access memory

RPC – remote procedure call

RSS – Remote Storage Service

RTS – Ready to Send

SAL – system abstraction layer

SMP – symmetric multi-processor

SRAT – static resource affinity table

TB – Terabyte

USB – universal serial bus

VDL – valid data length

WDM – Windows Driver Model

WHQL – Windows Hardware Quality Labs


NdisRetrieveUlong

NdisRetrieveUlong retrieves a ULONG value from the source address, avoiding alignment faults.

VOID
  NdisRetrieveUlong(
    IN PULONG  DestinationAddress,
    IN PULONG  SourceAddress
    );

Parameters

DestinationAddress
Pointer to a ULONG-aligned location in which to store the value.
SourceAddress
Pointer to a location from which to retrieve the ULONG value.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

The given DestinationAddress is assumed to be aligned on a ULONG boundary.

Callers of NdisRetrieveUlong can be running at any IRQL if the given addresses are in nonpaged pool. Otherwise, callers must be running at IRQL < DISPATCH_LEVEL.

See Also

NdisStoreUlong


NdisScheduleWorkItem

NdisScheduleWorkItem inserts a given work item into a queue from which a system worker thread removes the item and gives control to the callback function that the driver previously supplied to NdisInitializeWorkItem.

NDIS_STATUS
  NdisScheduleWorkItem(
    IN PNDIS_WORK_ITEM  WorkItem
    );

Parameters

WorkItem
Pointer to the work item that was set up by a preceding call to NdisInitializeWorkItem.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

A call to NdisScheduleWorkItem allows an NDIS driver to defer some driver-determined operation that could or should be done at a lower IRQL than the raised IRQL at which it is currently running to its worker-thread callback function.

The driver's callback is run within a system thread context at IRQL PASSIVE_LEVEL later. This caller-supplied function is responsible for reclaiming the storage that the driver allocated for WorkItem. For example, if the driver called NdisAllocateMemory to provide a context area to NdisInitializeWorkItem, its callback function should make the reciprocal call to NdisFreeMemory with WorkItem before it returns control.

A driver must not wait for its callback routine to complete an operation if it is already holding one synchronization object and might attempt to acquire another. For example, a NDIS driver should release any currently held spin lock(s), and so forth before it calls NdisScheduleWorkItem. A highest level NDIS protocol driver also must release any currently held semaphores, mutexes, resource variables, and so forth before it calls NdisScheduleWorkItem. Releasing all synchronization resources before queuing a synchronous worker-thread operation prevents deadlocks.

A serialized miniport driver should never attempt to queue a worker-thread callback routine, because there is no way for such a driver to synchronize access to its NIC context area(s) with a worker-thread callback. Consequently, such a serialized NDIS driver cannot share anything in its per-adapter context area with a worker-thread callback function without causing intermittent system crashes.

Callers of NdisScheduleWorkItem must be running at IRQL <= DISPATCH_LEVEL.

See Also

NdisFreeMemory, NdisInitializeWorkItem


NdisFreeString

NdisFreeString releases storage that was allocated by NdisInitializeString for a buffered string.

VOID
  NdisFreeString(
    IN NDIS_STRING  String
    );

Parameters

String
NDIS_STRING type that describes the string to release. For Windows 2000 and later, NDIS defines the NDIS_STRING type as a UNICODE_STRING type.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

An NDIS driver typically calls NdisInitializeString during initialization—for example, to set up names passed to the Ndis Xxx Configuration functions. For each call that it makes to NdisInitializeString, a driver must make a corresponding call to NdisFreeString. When releasing buffers allocated during initialization, a driver must call NdisFreeString before the driver's initialization function returns control.

NdisFreeString must be used only for freeing buffers that were allocated with NdisInitializeString.

Callers of NdisFreeString run at IRQL PASSIVE_LEVEL.

See Also

ANSI_STRING, DriverEntry of NDIS Protocol Drivers, MiniportInitialize, NdisFreeMemory, NdisInitializeString, NdisOpenAdapter, NdisRegisterProtocol, ProtocolBindAdapter, UNICODE_STRING


NDIS_SET_ORIGINAL_PACKET

NDIS_SET_ORIGINAL_PACKET sets the information in a given packet descriptor to the information from a packet descriptor that was originally indicated up by a lower-level driver.

  NDIS_SET_ORIGINAL_PACKET(
    IN/OUT PNDIS_PACKET  Packet,
    IN PNDIS_PACKET  OriginalPacket
    );

Parameters

Packet
Pointer to a packet descriptor that NDIS_SET_ORIGINAL_PACKET sets from the original packet descriptor in OriginalPacket or points to the current packet descriptor if OriginalPacket is NULL.
OriginalPacket
Pointer to a packet descriptor that was originally indicated up by a lower-level driver.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If intermediate drivers are present in a layered stack of NDIS drivers, those intermediate drivers must repackage packets that they receive before indicating the packets up to the next layer. In this situation, intermediate drivers should call NDIS_SET_ORIGINAL_PACKET to set the contents of a new packet from a packet that was indicated up by a lower-level driver. To retrieve a packet that was received from a lower-level driver, drivers call the NdisGetReceivedPacket function. To obtain a pointer to the original packet that was indicated up by the lowest-level driver in the layered stack, drivers call the NDIS_GET_ORIGINAL_PACKET macro and pass the pointer to the received packet. Using this method of retrieving and repackaging, each driver in the layered stack can access the out-of-band (OOB) data block that is associated with packets that are received from the network without requiring that packets be copied to each layer.

Before calling NDIS_SET_ORIGINAL_PACKET, intermediate drivers must allocate a packet descriptor and map this packet descriptor's chain of buffer descriptors to the original packet descriptor's chain of buffer descriptors. Intermediate drivers should always allocate their packet descriptors from packet pools that the drivers set up during initialization.

Callers of this macro can be running at any IRQL.

Example

The following example code retrieves a packet that was received from the driver below, obtains the original packet from OldPkt, and then sets MyPkt with the original-packet contents.

// Get the original packet, which could be the received packet
// or the packet originating from the lowest-level driver.
// This result is based on the number of layered drivers in the stack.
// Then, set the result on the packet that will be indicated to the
// next level so the OOB data block is accessible.
//
OldPkt = NdisGetReceivedPacket(BindingHandle, MacReceiveContext);
NdisDprAllocatePacket(&Status, &MyPkt, RecvPacketPoolHandle);
MyPkt->Private.Head = OldPkt->Private.Head;
MyPkt->Private.Tail = OldPkt->Private.Tail;
NDIS_SET_ORIGINAL_PACKET(MyPkt, NDIS_GET_ORIGINAL_PACKET(OldPkt));

See Also

NdisDprAllocatePacket, NDIS_GET_ORIGINAL_PACKET, NdisGetReceivedPacket, NDIS_PACKET, NDIS_PACKET_EXTENSION, NDIS_PACKET_EXTENSION_FROM_PACKET, NDIS_PER_PACKET_INFO_FROM_PACKET


ProtocolCmMakeCall

The ProtocolCmMakeCall function is a required function that sets up media specific parameters for a virtual connection (VC) and activates the virtual connection.

NDIS_STATUS
  ProtocolCmMakeCall(
    IN NDIS_HANDLE  CallMgrVcContext,
    IN OUT PCO_CALL_PARAMETERS  CallParameters,
    IN NDIS_HANDLE  NdisPartyHandle  OPTIONAL,
    OUT PNDIS_HANDLE  CallMgrPartyContext  OPTIONAL
    );

Parameters

CallMgrVcContext
Specifies the handle to a call manager-allocated context area in which the call managers maintains its per-VC state. The call manager supplied this handle to NDIS from its ProtocolCoCreateVc function.
CallParameters
Pointer to a CO_CALL_PARAMETERS structure that contains the parameters, specified by a connection-oriented client, for this outgoing call.
NdisPartyHandle
Specifies a handle, supplied by NDIS, that uniquely identifies the initial party on the multipoint virtual connection. This handle is opaque to the call manager and reserved for NDIS library use. This handle is NULL if the client is not setting up an outgoing multipoint call.
CallMgrPartyContext
On return, specifies a handle to a call manager-supplied context area in which the call manager maintains state about the initial party on the multipoint call. If NdisPartyHandle is NULL, this handle must be set to NULL.

Return Value

ProtocolCmMakeCall returns the status of its operation(s) as one of the following values:

NDIS_STATUS_SUCCESS
Indicates that the call manager successfully allocated the necessary resources to make the call and was able to activate the virtual connection with the miniport driver.
NDIS_STATUS_PENDING
Indicates that the call manager will complete the request to make a call asynchronously. When the call manager has completed all operations for making a call, it must call NdisCmMakeCallComplete to signal NDIS that this call has been completed.
NDIS_STATUS_RESOURCES
Indicates that the call manager was unable to allocate and/or initialize its resources for activating the virtual connection as requested by the client.
NDIS_STATUS_NOT_SUPPORTED
Indicates that the call manager was unable to activate a virtual connection because the caller requested invalid or unavailable features in the call parameters specified at CallParameters.

Headers

Declared in Ndis.h. Include Ndis.h.

Comments

If ProtocolCmMakeCall is given an explicit NdisPartyHandle, this VC was created by the client for a multipoint call. The call manager must allocate and initialize any necessary resources required to maintain state information and control a multipoint call. Such resources include, but are not limited to, memory buffers, data structures, events, and other similar resources. If the call manager cannot allocate or initialize the needed resources for its state area(s), it should return control to NDIS with NDIS_STATUS_RESOURCES.

ProtocolCmMakeCall communicates with network control devices or other media-specific actors, as necessary, to make a connection between the local node and a remote node based on the call parameters specified at CallParameters. Such actions could include, but are not limited to, communication with switching hardware, communications with a network control station, or other actions as appropriate to the network medium.

If a call manager is required to communication with networking hardware (e.g. a networking switch) it should use a virtual connection to the network control device that it established in its ProtocolBindAdapter function. Call managers communicate with their network hardware through the miniport driver by calling NdisCoSendPackets. Miniport drivers with integrated call-management support will not call NdisCoSendPackets, but rather will transmit the data themselves.

After a call manager has done all necessary communication with its networking hardware as required by its medium, call managers must call NdisCmActivateVc.

If this call was a multipoint call, after the call manager has communicated with the networking hardware, verified call parameters, and allocated and initialized its per-party state data, the address of its state block should be set in the handle CallMgrPartyContext before returning control to NDIS. The handle is set by dereferencing the handle and storing a pointer to the state block as the value of the handle. For example:

*CallMgrPartyContext = SomeBuffer ;

If ProtocolCmMakeCall has completed the required operations for its network and the VC has been successfully activated through NdisCmActivateVc, ProtocolCmMakeCall should return control as quickly as possible with a status of STATUS_SUCCESS.

After ProtocolCmMakeCall returns control to NDIS, the call manager should expect to take no further actions on this call to set it up. ProtocolCmMakeCall is responsible for establishing the connection so that the client can make data transfers over the network on this VC. However, the call manager can be called subsequently to modify the call's quality of service, to add or drop parties if this is a multipoint VC, and eventually to terminate this call.

ProtocolCmMakeCall must be written so that it can run at IRQL DISPATCH_LEVEL.

See Also

NdisClMakeCall, NdisCmActivateVc, NdisCmMakeCallComplete, ProtocolCoCreateVc


Structures Used by NDIS Drivers

The NDIS-defined and system-defined structures described here are multifunction or alternative structure parameters; that is, pointers to these structures are either passed in calls to more than one Ndis Xxx, MiniportXxx, or ProtocolXxx function, or a pointer to more than one of these structures are passed in calls to the same function.

For more information about structures for which a pointer is passed only to a single Ndis Xxx, MiniportXxx, or ProtocolXxx function, see the specific function.

The structures described in this section are listed in alphabetic order.


Registration and Deregistration of NDIS Miniport Drivers with WMI

NDIS automatically registers with WMI each instance of a miniport driver (that is, each functional device object created by NDIS in response to a successful return of MiniportInitialize). After a miniport driver instance is registered as a data provider with WMI, WMI clients can send it queries and sets and register to receive miniport driver status indications. A miniport driver does not have to explicitly register with WMI; NDIS automatically does this for the miniport driver after the miniport driver initializes.

When the miniport driver is unloaded (that is, after the miniport driver's MiniportHalt function returns), NDIS automatically deregisters the miniport driver instance with WMI so that WMI will no longer send queries or sets to the miniport driver.

For each miniport driver instance registered with WMI, NDIS registers GUIDs (globally unique identifiers) that each correspond to a particular OID or a miniport driver status indication. For each miniport driver, NDIS registers GUIDs for a standard set of required OIDs and miniport driver status indications. For more information, see Standard Miniport Driver OIDs Registered with WMI and Standard Miniport Driver Status Registered with WMI. If a miniport driver supports custom OIDs or status indications NDIS also registers GUIDs for these with WMI. For more information, see Customized OIDs and Status Indications.

For connection-oriented miniport drivers, NDIS also registers any named VCs. Only VCs that a call manager, integrated miniport call manager (MCM), or connection-oriented client has named with NdisCoAssignInstanceName are visible to WMI clients. For more information, see Support for Named VCs.


Ardis Wireless OIDs

The Ardis network conforms to current DataTAC technology. Therefore, Ardis-specific wireless OIDs are obsolete and should not be used. Definitions for these OIDs are still included for informational and historical purposes. Use DataTAC-specific wireless OIDs in DataTAC Wireless OIDs instead.

The following chart summarizes Ardis-specific wireless OIDs.

Q | S | Indication | Name
M |  |  | OID_WW_ARD_SNDCP
M |  |  | OID_WW_ARD_TMLY_MSG
M |  |  | OID_WW_ARD_DATAGRAM


Passing Media-Specific Information from a Connectionless Protocol Driver

Before sending a packet, a protocol driver can call NdisSetPacketFlags to set protocol-defined flags in the NDIS-private portion of the packet descriptor. Such flags are not defined by NDIS, but are defined for use by a cooperating pair of protocol and lower level NDIS drivers. The structure of the Private member of an NDIS_PACKET is opaque to all NDIS drivers and is accessed to read and, in some cases, to write using NDIS-supplied functions or macros.

More media-specific information can be passed by a protocol driver in the OOB block associated with each NDIS_PACKET-type descriptor. The definition of the OOB block is:

typedef struct _NDIS_PACKET_OOB_DATA {
    union {
         ULONGLONG      TimeToSend;
         ULONGLONG      TimeSent;
          };
         ULONGLONG      TimeReceived;
         UINT           HeaderSize;
         UINT           SizeMediaSpecificInfo;
         PVOID          MediaSpecificInformation;
         NDIS_STATUS    Status;
} NDIS_PACKET_OOB_DATA, *PNDIS_PACKET_OOB_DATA;

The structure of individual records within a driver-allocated buffer at MediaSpecificInformation is defined as follows:

typedef struct MediaSpecificInformation {
    UINT                NextEntryOffset;
    NDIS_CLASS_ID       ClassId;
    UINT                Size;
    UCHAR               ClassInformation[1];
} MEDIA_SPECIFIC_INFORMATION;

The ClassId member is an NDIS-defined enumeration that defines the type of information found at ClassInformation[1]. Currently, there are two class IDs for connectionless media in use across Microsoft operating systems that support Win32: NdisClassWirelessWanMbxMailbox, and NdisClassIrdaPacketInfo.

If the protocol driver knows that the underlying NIC driver to which it is sending packets uses OOB data, the protocol can set the following OOB structure members:

  • Request that the packet be sent at a specific time by setting the TimeToSend member using the NDIS_SET_PACKET_TIME_TO_SEND macro. This macro passes the requested time in system time units. The protocol can call NdisGetCurrentSystemTime in order to obtain the current system time with which to calculate a requested send time.
  • Pass media-specific information in a protocol-allocated buffer at MediaSpecificInformation using the NDIS_PACKET_SET_MEDIA_SPECIFIC_INFO macro to set this member to the address of the buffer. The protocol driver sets the ClassId member of the MediaSpecificInformation structure to the value indicating the type of data and passes the information in the ClassInformation member and the size in bytes of this information in Size. The protocol driver is responsible for allocating a buffer to contain any media-specific data records and for setting up the pointer to this buffer at MediaSpecificInformation.


NOTIFICATION_INFO

The bus driver passes NOTIFICATION_INFO to pass information to the driver-provided notification routine for a driver-allocated address range in the computer's IEEE 1394 address space. The bus driver calls the notification routine when it receives an asynchronous I/O request packet for that address.

typedef struct _NOTIFICATION_INFO {
  PMDL  Mdl;
  ULONG  ulOffset;
  ULONG  nLength;
  ULONG  fulNotificationOptions;
  PVOID  Context;
  PADDRESS_FIFO  Fifo;
  PVOID  RequestPacket;
  PMDL  ResponseMdl;
  PVOID *  ResponsePacket;
  PULONG  ResponseLength;
  PKEVENT *  ResponseEvent;
} NOTIFICATION_INFO, *PNOTIFICATION_INFO;

Members

Mdl
If non-NULL, Mdl specifies the MDL for the allocated address range.
ulOffset
Specifies the byte offset with the MDL that corresponds to the address that received a request packet. Only used when Mdl is non-NULL.
nLength
Specifies the number of bytes affected by the request packet. Only used when Mdl is non-NULL.
fulNotificationOptions
Specifies which type of event triggered the bus driver to call the notification routine. The possible events the bus driver can return are: NOTIFY_FLAGS_AFTER_READ, NOTIFY_FLAGS_AFTER_WRITE, or NOTIFY_FLAGS_AFTER_LOCK. Only used when Mdl is non-NULL.
Context
Pointer to specific context data for this allocated address range. The driver supplies this data through the u.AllocateAddressRange.Context member of the IRB for the original REQUEST_ALLOCATE_ADDRESS_RANGE request.
Fifo
Pointer to the ADDRESS_FIFO structure containing the FIFO element just completed. Only used if the driver submitted an ADDRESS_FIFO list in the original REQUEST_ALLOCATE_ADDRESS_RANGE request.
RequestPacket
If non-NULL, RequestPacket points to the original request packet. The bus driver only supplies this if the device driver did not supply an MDL or an ADDRESS_FIFO list in the original REQUEST_ALLOCATE_ADDRESS_RANGE request.
ResponseMdl
If non-NULL, ResponseMdl points to an uninitialized MDL. The driver must initialize this MDL for a non-pageable buffer, and fill the buffer with the response packet. The bus driver only supplies this if the device driver did not supply an MDL or an ADDRESS_FIFO list in the original REQUEST_ALLOCATE_ADDRESS_RANGE request.
ResponsePacket
If non-NULL, ResponsePacket points to a memory location that the driver fills in with a pointer to the beginning of its response packet. The bus driver only supplies this if the device driver did not supply an MDL or an ADDRESS_FIFO list in the original REQUEST_ALLOCATE_ADDRESS_RANGE request.
ResponseLength
If non-NULL, ResponseLength points to a memory location that the driver fills in with the length of its response packet. The bus driver only supplies this if the device driver did not supply an MDL or an ADDRESS_FIFO list in the original REQUEST_ALLOCATE_ADDRESS_RANGE request.
ResponseEvent
If non-NULL, ResponseEvent points to a memory location that the driver fills in with the kernel event the bus driver should use to signal that it has completed sending the response packet. The bus driver only supplies this if the device driver did not supply an MDL or an ADDRESS_FIFO list in the original REQUEST_ALLOCATE_ADDRESS_RANGE request.

Comments

When a driver allocates an address range on the computer's IEEE 1394 address space, it may require the bus driver to notify it for some or all request packets sent to the allocated addresses. As part of the original allocate request, the driver may either require the bus driver to forward each packet to the driver for handling, or it may require the bus driver to handle the packet and merely notify the device driver when it has finished. See REQUEST_ALLOCATE_ADDRESS_RANGE for details.

If the device driver provides no backing store, the bus driver forwards each packet to the device driver to handle. The bus driver passes NULL for Mdl, and passes the packet in RequestPacket. The bus driver also passes pointers to memory locations that the device driver must fill in with the buffer for the response packet (in ResponsePacket), the buffer length (in ResponseLength), and an MDL for the buffer (in ResponseMdl). The bus driver also supplies a memory location the driver can use to pass a kernel event object in ResponseEvent. If the device driver provides an event object, the bus driver will use it to signal the driver when it has finished sending the response packet.

If the driver provides backing store in the original allocate address range request, the bus driver uses the driver's notification routine to signal that it has completed reading or writing data from the backing store. It passes the MDL of the backing store in the Mdl member, and the starting location and size within the associated buffer in ulOffset and nLength. The bus driver also passes the type of event that led to notification in fulNotificationOptions.

If the device driver is using a linked list of ADDRESS_FIFO's as backing store, the bus driver returns the list element it popped off in Fifo.


DirectSound Stream Data Format

Uses a KSDATAFORMAT_DSOUND structure.

DataFormat.FormatSize = sizeof(KSDATAFORMAT_DSOUND);
DataFormat.Flags      = 0;
DataFormat.SampleSize = 0;
DataFormat.Reserved   = 0;
DataFormat.MajorFormat = STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO);
DataFormat.SubFormat   = STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM);
DataFormat.Specifier   = STATICGUIDOF(KSDATAFORMAT_SPECIFIER_DSOUND);
BufferDesc.Flags       = KSDSOUND_BUFFER_LOCHARDWARE;
BufferDesc.Control     = KSDSOUND_BUFFER_CTRL_3D;
BufferDesc.WaveFormatEx.wFormatTag       = WAVE_FORMAT_PCM;
BufferDesc.WaveFormatEx.nChannels        = 2;
BufferDesc.WaveFormatEx.nSamplesPerSec   = 22050;
BufferDesc.WaveFormatEx.nAvgBytesPerSec  = 88200;
BufferDesc.WaveFormatEx.nBlockAlign      = 4;
BufferDesc.WaveFormatEx.wBitsPerSample   = 16;
BufferDesc.WaveFormatEx.cbSize           = 0;


KSPROPERTY_AEC_MODE

The KSPROPERTY_AEC_MODE property is used to control an AEC node's mode of operation. This is an optional property of an AEC node.

Get | Set | Target | Property descriptor type | Property value type
Yes | Yes | Pin | KSNODEPROPERTY | ULONG

Comments

The property value is of type ULONG and can be set to one of the following mode constants:

  • AEC_MODE_PASS_THROUGH

    In pass-through mode, the AEC node allows capture and render data to simply pass through the node without being modified.

  • AEC_MODE_HALF_DUPLEX

    The AEC algorithm is running in half-duplex mode, which is similar in operation to a speaker phone. In this mode, the speaker volume is muted whenever the local person's speech has a higher volume level than the remote person's.

  • AEC_MODE_FULL_DUPLEX

    The AEC algorithm is running in full-duplex mode.

The default mode is pass-through. When the filter containing the AEC node is created or the node is reset, the node is initially configured in pass-through mode.

In the initial release of Windows XP, the AEC algorithm that the AEC system filter uses does not support the half-duplex mode.

See Also

KSNODETYPE_ACOUSTIC_ECHO_CANCEL


Audio Helper Object Interfaces

The Port Class Library implements a variety of helper objects that provide functionality that is of general use to adapter drivers. These helper objects provide implementation for DMA support, interrupt handling, resource-list management, and registry access. This section provides details on the interfaces that are exposed by those objects.

The following interfaces are described in this section:

IDmaChannel

A master-slave DMA channel with an associated common buffer.

IDmaChannelSlave

A set of methods relating to DMA slave operations

IInterruptSync

A synchronization mechanism to coordinate access. This interface supports synchronization with interrupt-service routines.

IRegistryKey

This interface provides access to a registry key.

IResourceList

A list of resources such as I/O ports, DMA channels, and interrupts.

IServiceGroup

This interface is used to demultiplex interrupt-service requests.

IServiceSink

This interface represents a single interrupt-service request.


IMiniportWaveCyclicStream::Silence

The Silence method is used to copy silence samples to a specified buffer. Callers of Silence can run at any IRQL.

NTSTATUS
  Silence(
    IN PVOID  Buffer,
    IN ULONG  ByteCount
    );

Parameters

Buffer
Pointer in kernel virtual-address space to the start of the buffer to which the silence samplings are to be written.
ByteCount
The length of the buffer in bytes.

Return Value

Silence returns STATUS_SUCCESS if the call was successful. Otherwise, the method returns an appropriate error code.

Headers

Declared in portcls.h. Include portcls.h.


AvcResponseCode

The AvcResponseCode enumeration type is used to indicate the type of response received by a subunit driver from its AV/C subunit through AVC_FUNCTION_COMMAND or AVC_FUNCTION_SEND_RESPONSE function codes.

typedef enum _tagAvcResponseCode {
    AVC_RESPONSE_NOTIMPL          = 0x08,
    AVC_RESPONSE_ACCEPTED         = 0x09,
    AVC_RESPONSE_REJECTED         = 0x0a,
    AVC_RESPONSE_IN_TRANSITION    = 0x0b,
    AVC_RESPONSE_STABLE           = 0x0c,
    AVC_RESPONSE_IMPLEMENTED      = 0x0c,
    AVC_RESPONSE_CHANGED          = 0x0d,
    AVC_RESPONSE_INTERIM          = 0x0f
} AvcResponseCode;

Enumerators

AVC_RESPONSE_NOTIMPL
Indicates the subunit does not support the specified control command.
AVC_RESPONSE_ACCEPTED
Indicates the subunit does implement the specified control command and that subunit state permits execution of the command. Note: Command execution may not have completed by the time the AVC_RESPONSE_ACCEPTED has been returned.
AVC_RESPONSE_REJECTED
Specifies a response indicating the command or request was rejected.
AVC_RESPONSE_IN_TRANSITION
Specifies a response indicating the command or request was accepted.
AVC_RESPONSE_STABLE
Indicates the subunit implements the command. Same meaning as AVC_RESPONSE_IMPLMENTED.
AVC_RESPONSE_IMPLEMENTED
Indicates the subunit implements the command. Same meaning as AVC_RESPONSE_STABLE.
AVC_RESPONSE_CHANGED
Indicates the subunit state has changed.
AVC_RESPONSE_INTERIM
Indicates the subunit is unable to respond with either AVC_RESPONSE_ACCEPTED or AVC_RESPONSE_REJECTED within the 100 millisecond timeframe for responses. The subunit will ultimately return a response frame with either a AVC_RESPONSE_ACCEPTED or AVC_RESPONSE_REJECTED code.

Headers

Declared in avc.h. Include avc.h.

See Also

AVC_FUNCTION_COMMAND, AVC_FUNCTION_SEND_RESPONSE, AVC_FUNCTION


Bug Check 0xDE: POOL_CORRUPTION_IN_FILE_AREA

The POOL_CORRUPTION_IN_FILE_AREA bug check has value 0x000000DE. This signifies that a driver corrupted pool memory used for holding pages destined for disk.

Parameters

None.

Cause

When the Memory Manager dereferenced the file, it discovered the corruption in pool memory.


IA64_OPTIMIZATION

See MSC_OPTIMIZATION.


CM_Delete_DevNode_Key

Do not use this function. Use device installation functions instead.


Ordering of Commands

The Order group box contains 13 controls which you use to specify the order of the page-control commands. Some printers (such as the Hewlett-Packard printers that use PCL) require a specific ordering of the page-control commands in order to process pages correctly; other printers (such as the Diconix) work satisfactorily using the default ordering. Once you've entered the appropriate commands for your printer, you also need to specify the order in which the Universal Printer Driver should send them to the printer.

The default values that appear in these controls begin with the number 1 in the upper-left corner and proceed down the left column, to the top of the right column and then down the right column.

Diconix 150 Plus

The Diconix printer uses the default values.

HP LaserJet IIP

The HP LaserJet IIP printer requires the unique ordering specified in the following list:

  • PC_ORD_BEGINDOC
  • PC_ORD_PAPER_SOURCE
  • PC_ORD_PAPER_SIZE
  • PC_ORD_ORIENTATION
  • PC_ORD_RESOLUTION
  • PC_ORD_BEGINPAGE
  • PC_ORD_MULT_COPIES
  • PC_ORD_DUPLEX
  • PC_ORD_DUPLEX_TYPE


CPSFUNC_SET_DATABLOCK

The CPSFUNC_SET_DATABLOCK function code causes the ComPropSheet function to store a caller-supplied data block. Use this function code to make one property sheet page's information available to other pages.

ComPropSheet Parameters

hComPropSheet
Group parent handle.
Function
CPSFUNC_SET_DATABLOCK
lParam1
Pointer to a CPSUIDATABLOCK structure describing the data block to be stored.
lParam2
Caller-defined DWORD-sized identifier value, used to identify the supplied CPSUIDATABLOCK structure in subsequent calls to ComPropSheet using the CPSFUNC_QUERY_DATABLOCK function code.

ComPropSheet Return Value

If the operation succeeds, ComPropSheet returns a value representing the number of bytes stored; otherwise it returns a value less than or equal to zero.

Headers

Declared in compstui.h. Include compstui.h.

Comments

Typically, this function code is used by a _CPSUICALLBACK-typed callback function, when the function's CPSUICBPARAM structure contains a Reason value of CPSUICB_REASON_KILLACTIVE, to save values associated with a page before it becomes inactive.


Multimatrix Vertex Blending Algorithm

This algorithm assumes only two matrices are being used.

On matrix change, update the following four matrices:

Matrix | Computation
Current Transform Matrix (CTM) | CTM = WORLD * VIEW * PROJ
Secondary CTM (parent coordinates) | CTM2 = WORLD1 * VIEW * PROJ
Inverse transpose of CTM | ITCTM = (CTMT)-1
Inverse transpose of CTM2 (required if lighting) | ITCTM2 = (CTM2T)-1

Note that in some cases it may be more efficient to blend the matrices first using the vertex's weights, and then do only one (matrix)X(vertex) multiplication.

FVF Code Changes

The key API impact of multimatrix vertex blending is the addition of the vertex blending weight parameters to the position component of the flexible vertex format (FVF). These parameters are stored as 32-bit IEEE single precision floats. They are indicated as present in the input vertex data by the addition of four new bit patterns for the FVF code: D3DVFV_XYZB2, D3DVFV_XYZB3, D3DVFV_XYZB4, and D3DVFV_XYZB5.

Note that these codes identify extra DWORDs of space that may alternatively be allocated to other uses, such as particle radius or fog parameter, depending on which features are enabled.

Note If the number of blend weights specified is one less than the number of matrices currently being blended, then the weight assigned to the last matrix is defined to be (1.0 - Bt), where Bt is the total of the other weights for that vertex.

D3DTRANSFORMSTATE Changes

Multimatrix blending also requires the specification of three additional world transform matrices.

In addition to the original world transform matrices, D3DTRANSFORMSTATE_WORLD (which might be thought of as "D3DTRANSFORMSTATE_WORLD0"), D3DTRANSFORMSTATE_VIEW, and D3DTRANSFORMSTATE_PROJECTION, there are now the following world transform matrices, described in the DirectX SDK documentation:

  • D3DTRANSFORMSTATE_WORLD1, the second matrix to blend
  • D3DTRANSFORMSTATE_WORLD2, the third matrix to blend
  • D3DTRANSFORMSTATE_WORLD3, the fourth matrix to blend

Note that these are not consecutively enumerated after the original D3DTRANSFORMSTATE_WORLD.

Matrices that are not defined by this call, but are enabled for blending, are assumed to default to identity matrices.

D3DRENDERSTATETYPE Changes

A new render state has been defined to enable and control multimatrix vertex blending operations: D3DRENDERSTATE_VERTEXBLEND, described in the DirectX SDK documentation. The value of this render state can be one of the following D3DVERTEXBLENDFLAGS enumerators:

  • D3DVBLEND_DISABLE (use only the world matrix specified by the D3DTRANSFORMSTATE_WORLD transformation state)
  • D3DVBLEND_1WEIGHT (blend between the two world matrices specified by the D3DTRANSFORMSTATE_WORLD and D3DTRANSFORMSTATE_WORLD1 transformation states)
  • D3DVBLEND_2WEIGHTS (blend between the three world matrices specified by the D3DTRANSFORMSTATE_WORLD, D3DTRANSFORMSTATE_WORLD1, and D3DTRANSFORMSTATE_WORLD2 transformation states)
  • D3DVBLEND_3WEIGHTS (blend between four world matrices specified by the D3DTRANSFORMSTATE_WORLD, D3DTRANSFORMSTATE_WORLD1, D3DTRANSFORMSTATE_WORLD2, and D3DTRANSFORMSTATE_WORLD3 transformation states)

For a description of the D3DTRANSFORMSTATE_WORLDn transformation states, see D3DTRANSFORMSTATETYPE in the DirectX SDK documentation.

Even though additional blending world matrices may have been defined with the IDirect3DDevice7::SetTransform method (described in the Direct3D SDK documentation), the contributions (that is, weights) of any matrices beyond the number specified in this render state are set to zero.


Copying Volume Textures in the DP2 Stream

A new DP2 token, D3DDP2OP_VOLUMEBLT, has been added to support optimal copying and updating of volume textures. This token is very similar to the existing D3DDP2OP_TEXBLT that copies and updates textures but has been extended to support sub-volume (box) copying rather than simple rectangles.


Texture Coordinate Transformations

Texture coordinate transformations are enabled for DirectX 7.0.

Texture transforms are vertex-level transformation operations. These operations can be performed by any transform and lighting-enabled HAL driver and by any HAL device type.

Texture transforms are enabled by defining 4X4 matrices associated with each texture stage. All of the key state and data structures used by the software implementation of the geometry pipeline are available at the DDI level.

Using texture transformations, texture coordinates can be moved, relative to the vertices they are being drawn from. The texture transform describes how the texture coordinates are moved inside the texture map. Every time a texture transform is applied, the matrix changes the coordinates of the texture. The standard world matrix is used in these transformations.

At the API level, the IDirect3DDevice7::SetTransform method (described in the Direct3D SDK documentation) defines the texture transform matrix associated with the texture currently bound to the i-th texture stage. This matrix should be applied to the texture coordinates of that texture during rendering. Note that the same vertex-level texture coordinate set can be used at different stages with a separate texture transform matrix that may apply different textures.

The operation of the texture transform is controlled by the IDirect3DDevice7::SetTextureStageState method (described in the Direct3D SDK documentation) using the D3DTSS_TEXTURETRANSFORMFLAGS flag.

The D3DTEXTURETRANSFORMFLAGS enumerated type, described in the DirectX SDK documentation, is used to control the dimension of the texture coordinate set that is generated by the texture coordinate transformation operation, and to control whether any perspective division should be applied to it.

D3DTTFF_DISABLE indicates that the texture coordinates are passed directly to the hardware.

The number of the D3DTTFF_COUNTn flag signals how many texture coordinates are going to be present. Note that this does not necessarily equate to the dimension of the textures themselves, if projected textures are used.

If projected textures are used, the D3DTTFF_PROJECTED flag is set to indicate that the texture coordinates are to be divided by the last (COUNTth) element of the texture coordinate set. Thus, for a 2D projected texture, the count would be three, since the first two elements are divided by the third, resulting in two floats for a 2D texture lookup. That is, both D3DTTFF_COUNT2 and D3DTTFF_COUNT3 | D3DTTFF_PROJECTED refer to a 2D texture.

For non-projected textures:

  • D3DTTFF_COUNT1 indicates that the rasterizer should expect 1D texture coordinates.
  • D3DTTFF_COUNT2 indicates that the rasterizer should expect 2D texture coordinates.
  • D3DTTFF_COUNT3 indicates that the rasterizer should expect 3D texture coordinates.
  • D3DTTFF_COUNT4 indicates the rasterizer should expect 4D texture coordinates.

The first byte encodes a count of texture coordinates expected to be used by the texture at a particular stage. Setting this to zero causes no texture transformation to be applied even if one was defined by the IDirect3DDevice7::SetTransform method. This is the number that will be output from the texture coordinate transform stage.

The number of texture coordinates passed into the texture transform is defined by the Direct3D API FVF code.

D3DTSS_TEXTURETRANSFORMFLAGS defaults to D3DTFF_DISABLED with no D3DTTFF_PROJECTED flag set. The texture transform matrices default to 4X4 identity matrices.

On non-transform-and-lighting HAL devices (that is, those that require transformation operations on the host processor), the output vertices will be provided to the driver with the appropriate DDI-level FVF code that may differ from the one specified at the API level. Devices that do not support hardware-accelerated transform and lighting may still do projected textures, and therefore the drivers must still respond to the D3DTSS_TEXTURETRANSFORMFLAGS.


DDK Header File and Naming Issues

In order to simplify the task of having a single code base for the DirectX portion of your display driver for both Windows 98/Me and Windows 2000 and later, changes have been made to the naming conventions used for DDI data structures. Previously, d3dnthal.h contained definitions of the Direct3D DDI data structures with a naming convention that included the letters "NT." For example, on Windows 2000 the data structure associated with the D3dDrawPrimitives2 token to set a palette was called D3DNTHAL_DP2SETPALETTE. In d3dhal.h for Windows 98/Me, the equivalent data structure was called D3DHAL_DP2SETPALETTE.

For DirectX 8.0, we have changed this naming scheme to use only the Windows 98/Me naming style. d3dnthal.h as shipped with the DDK no longer contains the Windows 2000 style names. Currently, this rationalization applies to Direct3D data structures only and not DirectDraw DDI data structures. See D3DNTHAL_Xxx Structures for a list of structures affected by the change.

The DirectX 8.0 DDK introduces a new DDI-only header file called d3dhalex.h. This header file contains optional helper definitions and macros. Currently, this header contains some macros to assist with reporting D3DCAPS8 to the runtime.


Debugging Tools for NT-Based Operating Systems

The Microsoft® Windows® DDK includes the Debugging Tools for Windows package. This package contains four debuggers:

  • WinDbg

    A graphical debugger for debugging both user-mode and kernel-mode code.

  • KD

    A console program for debugging kernel-mode drivers.

  • CDB

    A console program for debugging user-mode applications and drivers.

  • NTSD

    A variation of CDB. A copy of this program is also located in the system32 directory of Windows.

The debuggers in the Debugging Tools for Windows package can run on all NT-based operating systems. They can debug any applications, services, or drivers that run on these operating systems. They do not support Windows 95/98/Me.

The Debugging Tools for Windows package includes documentation on WinDbg, KD, CDB, and NTSD, along with tips on how to debug various kinds of drivers and applications, how to create and analyze a crash dump file, how to run a remote debugging session, and how to use debugger extension commands. This package also includes several additional debugging tools and support tools.

Which debugger you use depends on the type of driver you're debugging and the target operating system. WinDbg and KD are most commonly used to debug drivers on NT-based operating systems.

In addition, the Microsoft Visual Studio® debugger can be used to debug user-mode programs on all Windows operating systems. See the Visual Studio documentation for details on this debugger.

Installing the Debuggers

To install Debugging Tools for Windows from the Windows DDK, start the DDK setup program and look for the link on the DDK installation splash screen. Selecting this link will let you install the debuggers to a location of your choice.

You can also download the latest version of the Debugging Tools for Windows package from http://www.microsoft.com/ddk/debugging. This package is often updated, and includes the latest debuggers, debugger extensions, and documentation.

After the installation is complete, the debugger shortcuts can be found in Start | Programs | Debugging Tools for Windows.


DdUpdateOverlay

DdUpdateOverlay repositions or modifies the visual attributes of an overlay surface.

DWORD
  (APIENTRY *PDD_SURFCB_UPDATEOVERLAY)(
    PDD_UPDATEOVERLAYDATA  lpUpdateOverlay
    );

Parameters

lpUpdateOverlay
Points to a DD_UPDATEOVERLAYDATA structure that contains the information required to update the overlay.

Return Value

DdUpdateOverlay returns one of the following callback codes:

DDHAL_DRIVER_HANDLED

DDHAL_DRIVER_NOTHANDLED

Headers

Declared in ddrawint.h. Include winddi.h.

Comments

DdUpdateOverlay shows, hides, or repositions an overlay surface on the screen. It also sets attributes of the overlay surface, such as the stretch factor or type of color key to be used.

The driver should determine whether it has the bandwidth to support the overlay update request. The driver should use dwFlags to determine the type of request and how to process it.

The driver/hardware must stretch or shrink the overlay accordingly when the rectangles specified by rDest and rSrc are different sizes.

Note that DdFlip is used for flipping between overlay surfaces, so performance for DdUpdateOverlay is not critical.

DD_UPDATEOVERLAYDATA

The DD_UPDATEOVERLAYDATA structure contains information necessary for updating an overlay surface.

typedef struct _DD_UPDATEOVERLAYDATA {
  PDD_DIRECTDRAW_GLOBAL  lpDD;
  PDD_SURFACE_LOCAL  lpDDDestSurface;
  RECTL  rDest;
  PDD_SURFACE_LOCAL  lpDDSrcSurface;
  RECTL  rSrc;
  DWORD  dwFlags;
  DDOVERLAYFX  overlayFX;
  HRESULT  ddRVal;
  VOID  *UpdateOverlay;
} DD_UPDATEOVERLAYDATA;

Members

lpDD
Points to a DD_DIRECTDRAW_GLOBAL structure that represents the DirectDraw object.
lpDDDestSurface
Points to a DD_SURFACE_LOCAL structure that represents the DirectDraw surface to be overlaid. This value can be NULL if DDOVER_HIDE is specified in dwFlags.
rDest
Specifies a RECTL structure that contains the x, y, width, and height of the region on the destination surface to be overlaid.
lpDDSrcSurface
Points to a DD_SURFACE_LOCAL structure that describes the overlay surface.
rSrc
Specifies a RECTL structure that contains the x, y, width, and height of the region on the source surface to be used for the overlay.
dwFlags
Specifies how the driver should handle the overlay. This member can be a combination of any of the following flags:
Flag | Meaning
DDOVER_ADDDIRTYRECT | Should be ignored by the driver.
DDOVER_AUTOFLIP | The driver should autoflip the overlay whenever the hardware video port autoflips. Drivers that support VPE need only check this flag.
DDOVER_BOB | The driver should display each field of VPE object data individually without causing any jittery artifacts. This flag pertains to both VPE and decoders that want to do their own flipping in kernel mode using the kernel-mode video transport functionality.
DDOVER_BOBHARDWARE | Indicates that bob will be performed by hardware rather than by software or emulation. Drivers that support VPE need only check this flag.
DDOVER_DDFX | The driver should show the overlay surface using the attributes specified by the overlayFX member.
DDOVER_HIDE | The driver should hide the overlay; that is, the driver should turn this overlay off.
DDOVER_INTERLEAVED | The overlay surface is composed of interleaved fields. Drivers that support VPE need only check this flag.
DDOVER_KEYDEST | The driver should use the color key associated with the destination surface.
DDOVER_KEYDESTOVERRIDE | The driver should use the dckDestColorKey member of the DDOVERLAYFX structure (described in the DirectDraw SDK documentation) as the destination color key instead of the color key associated with the destination surface.
DDOVER_KEYSRC | The driver should use the color key associated with the destination surface.
DDOVER_KEYSRCOVERRIDE | The driver should use the dckSrcColorKey member of the DDOVERLAYFX structure (described in the DirectDraw SDK documentation) as the source color key instead of the color key associated with the destination surface.
DDOVER_OVERRIDEBOBWEAVE | Bob/weave decisions should not be overridden by other interfaces. If the overlay mixer sets this flag, DirectDraw will not allow a kernel-mode driver to use the kernel-mode video transport functionality to switch the hardware between bob and weave mode.
DDOVER_REFRESHALL | Should be ignored by the driver.
DDOVER_REFRESHDIRTYRECTS | Should be ignored by the driver.
DDOVER_SHOW | The driver should show the overlay; that is, the driver should turn this overlay on.

overlayFX
Specifies a DDOVERLAYFX structure (described in the DirectDraw SDK documentation) that describes additional effects that the driver should use to update the overlay. The driver should use this structure only if one of DDOVER_DDFX, DDOVER_KEYDESTOVERRIDE, or DDOVER_KEYSRCOVERRIDE are set in the dwFlags member.
ddRVal
Specifies the location in which the driver writes the return value of the DdUpdateOverlay callback. A return code of DD_OK indicates success.
UpdateOverlay
Is used by the DirectDraw API and should not be filled in by the driver.

See Also

DdSetColorKey, DdSetOverlayPosition


DrvAlphaBlend

DrvAlphaBlend provides bit-block transfer capabilities with alpha blending.

BOOL
  DrvAlphaBlend(
    IN SURFOBJ  *psoDest,
    IN SURFOBJ  *psoSrc,
    IN CLIPOBJ  *pco,
    IN XLATEOBJ  *pxlo,
    IN RECTL  *prclDest,
    IN RECTL  *prclSrc,
    IN BLENDOBJ  *pBlendObj
    );

Parameters

psoDest
Points to a SURFOBJ that identifies the surface on which to draw.
psoSrc
Points to a SURFOBJ that identifies the source surface.
pco
Points to a CLIPOBJ. The CLIPOBJ_Xxx service routines are provided to enumerate the clip region as a set of rectangles. This enumeration limits the area of the destination that is modified. Whenever possible, GDI simplifies the clipping involved. However, unlike DrvBitBlt, DrvAlphaBlend might be called with a single rectangle in order to prevent round-off errors in clipping the output.
pxlo
Points to an XLATEOBJ that specifies how color indices should be translated between the source and destination surfaces. If pxlo is NULL, no translation is needed.

If the source surface is palette-managed, its colors are represented by indices into a lookup table of RGB color values. In this case, the XLATEOBJ can be queried for a translate vector that allows the device driver to quickly translate any source index into a color index for the destination.

The situation is more complicated when, for example, the source is RGB but the destination is palette-managed. In this case, the closest match to each source RGB value must be found in the destination palette. The driver can call the XLATEOBJ_iXlate service routine to perform this matching operation.

prclDest
Points to a RECTL structure that defines the rectangular area to be modified. This rectangle is specified in the coordinate system of the destination surface and is defined by two points: upper left and lower right. The two points that define the rectangle are always well ordered. The rectangle is lower-right exclusive; that is, its lower and right edges are not a part of the blend.

The driver should be careful to do proper clipping when writing the pixels because the specified rectangle might overhang the destination surface.

DrvAlphaBlend is never called with an empty destination rectangle.

prclSrc
Points to a RECTL structure that defines the area to be copied. This rectangle is specified in the coordinate system of the source surface, and is defined by two points: upper left and lower right. The two points that define the rectangle are always well ordered. The rectangle is lower-right exclusive; that is, its lower and right edges are not a part of the blend.

The source rectangle will never exceed the bounds of the source surface, and so will never overhang the source surface.

DrvAlphaBlend is never called with an empty source rectangle.

The mapping is defined by prclSrc and prclDest. The points specified in prclDest and prclSrc lie on integer coordinates, which correspond to pixel centers. A rectangle defined by two such points is considered to be a geometric rectangle with two vertices whose coordinates are the given points, but with 0.5 subtracted from each coordinate. (POINTL structures are shorthand notation for specifying these fractional coordinate vertices.)

pBlendObj
Points to a BLENDOBJ structure that describes the blending operation to perform between the source and destination surfaces. This structure is a wrapper for the BLENDFUNCTION structure, which includes necessary source and destination format information not available in the XLATEOBJ. The BLENDFUNCTION structure is defined in the Platform SDK documentation. Its members are defined as follows:

BlendOp defines the blend operation to be performed. Currently this value must be AC_SRC_OVER, which means that the source bitmap is placed over the destination bitmap based on the alpha values of the source pixels. There are three possible cases that this blend operation should handle. These are described in the Comments section.

BlendFlags is reserved and is currently set to zero.

SourceConstantAlpha defines the constant blend factor to apply to the entire source surface. This value is in the range of [0,255], where 0 is completely transparent and 255 is completely opaque.

AlphaFormat defines whether the surface is assumed to have an alpha channel. This member can optionally be set to the following value:

AC_SRC_ALPHA
The source surface can be assumed to be in a pre-multiplied alpha 32bpp "BGRA" format; that is, the surface type is BMF_32BPP and the palette type is BI_RGB. The alpha component is an integer in the range of [0,255], where 0 is completely transparent and 255 is completely opaque.

Return Value

DrvAlphaBlend returns TRUE upon success. Otherwise, it reports an error and returns FALSE.

Headers

Declared in winddi.h. Include winddi.h.

Comments

The driver can support a bit-block transfer with alpha blending between the following surfaces:

  • From one device-managed surface to another device-managed surface.
  • From one GDI-managed standard format bitmap to another GDI-managed standard format bitmap.
  • From one device-managed surface to a GDI-managed surface, and vice versa.

The driver can punt calls to EngAlphaBlend.

The driver will never be called with overlapping source and destination rectangles on the same surface.

The three possible cases for the AC_SRC_OVER blend function are:

  • The source bitmap has no per-pixel alpha (AC_SRC_ALPHA is not set), so the blend is applied to the pixel's color channels based on the constant source alpha value specified in SourceConstantAlpha as follows:
    Dst.Red = Round(((Src.Red * SourceConstantAlpha) +
    ((255 – SourceConstantAlpha) * Dst.Red)) / 255);
Dst.Green = Round(((Src.Green * SourceConstantAlpha) +
    ((255 – SourceConstantAlpha) * Dst.Green)) / 255);
Dst.Blue = Round(((Src.Blue * SourceConstantAlpha) +
    ((255 – SourceConstantAlpha) * Dst.Blue)) / 255);
/* Do the next computation only if the destination bitmap
    has an alpha channel. */
Dst.Alpha = Round(((Src.Alpha * SourceConstantAlpha) +
    ((255 – SourceConstantAlpha) * Dst.Alpha)) / 255);
  • The source bitmap has per-pixel alpha values (AC_SRC_ALPHA is set), and SourceConstantAlpha is not used (it is set to 255). The blend is computed as follows:
    Dst.Red = Src.Red +
    Round(((255 – Src.Alpha) * Dst.Red) / 255);
Dst.Green = Src.Green +
    Round(((255 – Src.Alpha) * Dst.Green) / 255);
Dst.Blue = Src.Blue +
    Round(((255 – Src.Alpha) * Dst.Blue) / 255);
/* Do the next computation only if the destination bitmap
    has an alpha channel. */
Dst.Alpha = Src.Alpha +
    Round(((255 – Src.Alpha) * Dst.Alpha) / 255);
  • The source bitmap has per-pixel alpha values (AC_SRC_ALPHA is set), and SourceConstantAlpha is used (it is not set to 255). The blend is computed as follows:
    Temp.Red = Round((Src.Red * SourceConstantAlpha) / 255);
Temp.Green = Round((Src.Green * SourceConstantAlpha) / 255);
Temp.Blue = Round((Src.Blue * SourceConstantAlpha) / 255);
/* The next computation must be done even if the
    destination bitmap does not have an alpha channel. */
Temp.Alpha = Round((Src.Alpha * SourceConstantAlpha) / 255);

/* Note that the following equations use the just-computed
   Temp.Alpha value: */
Dst.Red = Temp.Red +
    Round(((255 – Temp.Alpha) * Dst.Red) / 255);
Dst.Green = Temp.Green +
    Round(((255 – Temp.Alpha) * Dst.Green) / 255);
Dst.Blue = Temp.Blue +
    Round(((255 – Temp.Alpha) * Dst.Blue) / 255);
/* Do the next computation only if the destination bitmap
    has an alpha channel.  */
Dst.Alpha = Temp.Alpha +
    Round(((255 – Temp.Alpha) * Dst.Alpha) / 255);

The Round(x) function rounds to the nearest integer, computed as:

Trunc(x + 0.5);

DrvAlphaBlend can be optionally implemented in graphics drivers. It can be provided to handle some kinds of alpha blends, such as blends where the source and destination surfaces are the same format and do not contain an alpha channel.

A hardware implementation can use floating point or fixed point in the blend operation. Compatibility tests will account for some numerical error in the results; please see Special Effects in Display Drivers for information about maximum permissible error. When using fixed point, an acceptable approximation to the term x/255 is (x*257)/65536. Incorporating rounding, the expression:

((255 - Src.Alpha) * Dst.Red) / 255

can then be approximated as:

temp = ((255 - Src.Alpha) * Dst.Red) + 128;
result = (temp + (temp >> 8)) >> 8;

The driver hooks DrvAlphaBlend by setting the HOOK_ALPHABLEND flag when it calls EngAssociateSurface. If the driver has hooked DrvAlphaBlend and is called to perform an operation that it does not support, the driver should have GDI handle the operation by punting the data in a call to EngAlphaBlend.

See Also

DrvBitBlt, DrvPlgBlt, DrvStretchBlt, DrvStretchBltROP, DrvTransparentBlt, EngAlphaBlend, EngBitBlt, EngPlgBlt, EngStretchBlt, EngStretchBltROP, EngTransparentBlt


Ensuring Correct Version Numbers for Windows 98/Me Drivers

This topic applies only to Windows 98/Me.

With DirectX, version numbers have become very important for Windows 98/Me device drivers. If a device driver is shipped with the wrong version number or a version number that uses the wrong format, the end user will encounter difficulties when any DirectX application is installed.

Note Setup for Windows 98/Me now supports the DriverVer directive in INF files. This directive provides a way to add version information for the driver package, including the driver file and the INF file itself, to the INF file. By using and updating the DriverVer directive, driver packages can be safely and definitively replaced by future versions of the same package. For more information on this directive, see http://microsoft.com/hwdev/wdm/DrvVer.htm.

The following table gives the range of version numbers appropriate for IHV- or OEM-supplied Windows 98/Me drivers for compatibility with various versions of DirectX.

Target System | Version Number From: | Version Number Up Through:
Windows 98-only drivers (DirectX5) | 4.05.00.0000 | 4.05.00.9999
DirectX 1.0-compatible drivers | 4.02.00.0095 | 4.03.00.1096
DirectX 2.0-compatible drivers | 4.03.00.1096 | 4.03.00.2030
DirectX 3.0-compatible drivers | 4.03.00.2030 | 4.04.00.0000
DirectX 5.0-compatible drivers | 4.10.01.0000 | 4.10.01.9999
DirectX 6.0-compatible drivers | 4.11.01.0000 | 4.11.01.9999
Windows 98/Me DirectX 7.0-compatible drivers | 4.12.01.0000 | 4.12.01.9999
Windows 2000 and later DirectX 7.0-compatible drivers | 5.12.01.0000 | 5.12.01.9999
Windows 98/Me DirectX 8.0-compatible drivers | 4.13.01.0000 | 4.13.01.9999
Windows 2000 and later DirectX 8.0-compatible drivers | 5.13.01.0000 | 5.13.01.9999

For device drivers that do not support DirectX, the version number must be greater than 4.00.00.0095 and less than 4.02.00.0095. For example, if a display device driver is a Windows 3.1 display driver or a Windows 95-only display driver, a version number of 4.01.00.0000 would be correct.

Conversely, a version number of 4.03.00.0000 for this driver would be incorrect. Device drivers that support DirectX on Windows 95 only should have a version number equal to or greater than 4.02.00.0095 and less than 4.04.00.0000.

Device drivers that support DirectX and are compatible with Windows 98/Me should have a version number equal to or greater than 4.10.01.0000 and less than 4.10.02.0000.

Using version numbers equal to or greater than 4.10.02.0000 will have unpredictable results on future versions of Windows and DirectX.

Storing Internal Version Numbers

In addition to the format that Microsoft requires for the version number, many vendors have expressed the desire to store an internal version number for product support and testing purposes. Every DirectX driver has one version number that is stored in duplicate: one binary version stored as two DWORDs, and one string version. The binary version cannot be modified.

The string version, however, can be appended in the following way:

  1. The vendor creates a version number, as described earlier in this article. This version number will be used "as is" in the binary version number.
  2. The vendor uses this version number as the basis for the string version number. If desired, a vendor-specific version string can be appended to the existing version number to form the complete string version number. The vendor-specific string and the version number will be separated by a "-" (hyphen character).

For example, if "4.03.00.2100" is the version number for a DirectX-compliant display driver, and the vendor uses the "xx.xx.xx" number format internally, then the combined string version number in the driver will be "4.03.00.2100-xx.xx.xx".

When the customer checks the version number of the driver (by selecting the file in Windows Explorer, choosing Properties, and then clicking the Version tab), Windows displays the string version. The vendor's product support should be able identify the vendor-specific portion of the version number if it exists and take appropriate action.


Triple Buffering

Increasing the number of buffers that can hold a primary surface increases display performance. It is preferable to have at least three flippable surfaces (some games utilize five or more). When there are only two surfaces and a page flip occurs, the display delays until the monitor's vertical retrace is finished. The delay is necessary to ensure that the back buffer isn't written on before it is finished being displayed. With triple buffering, the third surface is always writable; since it is a back buffer and available to draw on immediately (as shown in the following figure). In a game that does not use sprite memory, 3D rendering using triple buffering is 20 to 30 percent faster than double buffering.

Triple Buffering

The flipping structures in the preceding figure are the same as those in Tearing, only now three buffers are utilized. Because one buffer is almost always writable (because it is not involved in a flip) the driver does not have to wait for the display scan to finish before allowing the back buffer to be written to again.

The following is a brief explanation of flipping and blitting in a triple-buffered system, using the labels from the preceding figure. The example begins with surface pixel memory 11 being displayed. This is the primary surface pointed to by the front buffer (fpVidMem in the sample code supplied with the Windows DDK). At some point, it becomes desirable to blt to the surface at pixel memory 22. Since fpVidMem points to the surface beginning at 11 (not 22) and the flip status is false (no flip is occurring on the requested surface), the blt can proceed. The driver locks the surface, writes to it, and then unlocks it. To display that surface, a flip must occur. The DirectDraw front buffer object can now change fpVidMem (the display memory pointer) to make the surface at 22 the primary surface. Since no flip is pending, the display pointers are exchanged (see the bottom half of the preceding figure), and the flip status is set to TRUE. The front buffer now points to surface pixel memory 22, the back buffer points to surface pixel memory 33, and the third buffer object points to surface pixel memory 11 (the old primary surface). Unlike with double buffering, DirectDraw is free to write to the back buffer at this time. In other words, DirectDraw can write to surface pixel memory 33 because no flip is pending. This circular flipping process continues endlessly to provide smooth animation and faster game play and video playback for applications that utilize DirectDraw.


DD_SURFACE_INT

DD_SURFACE_INT contains the DirectDrawSurface object's interface information.

typedef struct _DD_SURFACE_INT {
  PDD_SURFACE_LOCAL  lpLcl;
} DD_SURFACE_INT;

Members

lpLcl
Points to a DD_SURFACE_LOCAL structure that describes a unique surface object.


IDirectInputJoyConfig8 Callback

The IDirectInputJoyConfig8 interface contains only the following callback:

DIEnumJoyTypeProc


Initialize

In DirectX 5.0 and later, the Initialize callback signals the driver about the identity of the device. This callback replaces the joystick identification callback (see Joystick Identification Callback) used in previous versions of DirectX.

HRESULT
  (__stdcall *INITIALIZERTN)(
    DWORD  dwDeviceID,
    LPDID_INITPARAMS  lpInitParams
    );

Parameters

dwDeviceID
Indicates the joystick ID number being used. The Windows joystick subsystem allocates external IDs.
lpInitParams
Pointer to a DID_INITPARAMS structure that contains the initialization parameters.

Return Value

When access is being started, returns S_OK on success; otherwise returns an error value if the driver cannot service this ID. The result is ignored if access is being stopped.


IPrintCorePS2::GetGlobalAttribute

The IPrintCorePS2::GetGlobalAttribute method retrieves the global attribute list or the value of a specific global attribute.

STDMETHOD
  (GetGlobalAttribute) (
    THIS_
    IN PDEVOBJ  pdevobj,
    IN DWORD  dwFlags,
    IN PCSTR  pszAttribute,
    OUT PDWORD  pdwDataType,
    OUT PBYTE  pbData,
    IN DWORD  cbSize,
    OUT PDWORD  pcbNeeded
    ) PURE;

Parameters

pdevobj
Points to a DEVOBJ structure.
dwFlags
Is reserved and must be set to zero.
pszAttribute
Points to a caller-supplied buffer containing an ASCII string specifying the single attribute requested. If this parameter is NULL, the caller is requesting a list of all supported global attribute names, as opposed to specifying a specific global attribute name.
pdwDataType
Points to a memory location that will receive a value specifying the data type of the requested attribute. This value is an enumerator of the EATTRIBUTE_DATATYPE enumeration, which is defined in printoem.h.
pbData
Points to a caller-supplied buffer that will receive the requested data. To simply query for the number of bytes needed to fulfill a request, set this parameter to NULL.
cbSize
Specifies the size, in bytes of the buffer pointed to by pbData.
pcbNeeded
Points to a memory location that will receive the actual size, in bytes, of the requested data.

Return Value

This method must return one of the values shown in the following table:

Return Value | Meaning
S_OK | The method succeeded.
E_OUTOFMEMORY | The value in cbSize was smaller than the number of bytes to be written to the output buffer (the buffer pointed to by pbData). The method was called with pbData set to NULL.
E_INVALIDARG | The method attempted to query for a nonexistent attribute. The pdevobj parameter pointed to an invalid driver context object.
E_FAIL | The method failed.

Headers

Declared in prcomoem.h. Include prcomoem.h.

Comments

If this method is called with its pszAttribute and pbData parameters set to NULL, the method will return with *pcbNeeded set to the number of bytes needed for the list of all supported global attribute names. If the method is called a second time, with pszAttribute set to NULL and pbData pointing to a buffer of the size specified in *pcbNeeded in the previous call, the method will return with *pdwDataType set to kADT_ASCII (an enumerator of the EATTRIBUTE_DATATYPE enumerated type) and pbData pointing to a NULL-delimited list of all supported global attribute names. This list will be terminated with two NULL characters.

To reduce the need to make two calls per data access, pass the method an output buffer of a fixed size (1 KB, for example), and then check the function return value. If the method returns S_OK, the buffer will already contain the data of interest. If the method returns E_OUTOFMEMORY, the value in *pcbNeeded will be the buffer size needed to hold the data of interest. The caller should then allocate a buffer of that larger size and proceed with a second call to the method.

This method is supported for any Pscript5 render plug-in.

For more information, see Using GetGlobalAttribute.

See Also

DEVOBJ, IPrintCorePS2::GetFeatureAttribute, IPrintCorePS2::GetOptionAttribute


DirectSound Architecture

The following topics are discussed in this section:

  • Architectural Overview
  • The DirectSound HAL
  • DirectSound and Wave Drivers


IDsDriver::Open

The IDsDriver::Open method is called by DirectSound to acquire the device for its exclusive use. The driver should acquire the hardware and allocate any necessary structures. Once this method has been called, the Wave portion of the driver should be unable to acquire the use of the hardware; the Wave portion should recognize the device as already allocated.

HRESULT Open( );

Return Values

Returns DS_OK if successful, or DSERR_INVALIDPARAM otherwise.

Remarks

DirectSound guarantees that it only calls the IDsDriver::CreateSoundBuffer, IDsDriver::DuplicateSoundBuffer, and IDsDriver::GetCaps methods when it successfully opens the device through the IDsDriver::Open method.

This method should not increment the reference count on the DirectSound object. The reference count of an object should only be changed by the IUnknown methods AddRef and Release.


Driver Information

The DriverInfo group box at the bottom of the PFM dialog box contains the printer commands which select and cancel the selection of the font as well as additional data that some printers require to render text with a specific font.


GdiGetPageCount

The GdiGetPageCount function returns the number of pages in a print job.

DWORD WINAPI
  GdiGetPageCount(
    HANDLE  SpoolFileHandle
    );

Parameters

SpoolFileHandle
Caller-supplied spool file handle, obtained by a previous call to GdiGetSpoolFilehandle.

Return Value

If the operation succeeds, the function returns the number of pages in the current print job. Otherwise the function returns zero.

Headers

Declared in winsplp.h. Include winsplp.h.

Comments

The GdiGetPageCount function is exported by gdi32.dll for use within a print processor's PrintDocumentOnPrintProcessor function.

Note The GdiGetPageCount function does not return until all pages have been spooled, even if the print server administrator has specified that print jobs should be printed during spooling. Therefore, this function should not be used unless it is necessary to obtain the total page count before document processing can begin, such as for printing pages in reverse order.

Usually, a better method for determining the page count is to count the number of calls made to GdiGetPageHandle.

For additional information about this set of functions, see Using GDI Functions for Print Processors.


EngGetCurrentThreadId

EngGetCurrentThreadId identifies an application's current thread.

HANDLE
  EngGetCurrentThreadId(
    VOID
    );

Return Value

EngGetCurrentThreadId returns the 4-byte identifer of the application's thread.

Headers

Declared in winddi.h. Include winddi.h.

Comments

This function is available in Windows XP and later.

Callers of EngGetCurrentThreadId should treat the returned ID as a read-only value.

Callers of EngGetCurrentThreadId can be running at any IRQL.

See Also

EngGetCurrentProcessId, EngGetProcessHandle


End Block

The End Block box contains the command which terminates or ends the processing of a block of graphics data.

Diconix 150 Plus

The Diconix 150 Plus printer stops processing graphics data at the conclusion of the command specified in the Send Block box; therefore, the End Block box is empty.

HP LaserJet IIP

The HP LaserJet IIP printer processes a single block (or row) of data at a time; therefore it was not necessary to enter a command to terminate the processing of graphics data, and the End Block box is empty.


HidP_UsageListDifference

The HidP_UsageListDifference routine returns the differences between two arrays of HID usages.

NTSTATUS
  HidP_UsageListDifference(
    IN PUSAGE  PreviousUsageList,
    IN PUSAGE  CurrentUsageList,
    OUT PUSAGE  BreakUsageList,
    OUT PUSAGE  MakeUsageList,
    IN ULONG  UsageListLength
    );

Parameters

PreviousUsageList
Pointer to a list of usages that the routine compares with the list of usages in CurrentUsageList.
CurrentUsageList
Pointer to a list of usages that the routine compares with the list of usages in PreviousUsageList.
BreakUsageList
Pointer to a caller-allocated buffer that, on return, contains a list of the usages that are in PreviousUsageList, but not in CurrentUsageList.
MakeUsageList
Pointer to a caller-allocated buffer that, on return, contains a list of the usages that are in CurrentUsageList, but not in PreviousUsageList.
UsageListLength
Specifies the length, in array elements, of the buffers provided at CurrentUsageList and PreviousUsageList.

Return Value

HidP_UsageListDifference returns HIDP_STATUS_SUCCESS.

Headers

Declared in hidpi.h. Include hidpi.h.

Comments

A client can use this routine to compare two usage lists, for example, to determine the change in button state between two usage lists returned by two HidP_GetButtons calls.

If the input usage lists have different lengths, a client should set UsageListLength to the length of the larger list.

The routine interprets a zero usage in an input usage list as a delimiter that ends the list. Any usages after a zero in a list are not processed. Unused usages in an output list are set to zero.

HidP_UsageListDifference runs at IRQL = PASSIVE_LEVEL.

See Also

HidP_UsageAndPageListDifference


HID Structures for Minidrivers

This section describes the system-defined structures in the Microsoft® Windows® input architecture that the HID class driver uses to communicate with a HID minidriver.

See also:

  • Reserved HID Routines and Data Types, which lists system-defined components in the Windows input architecture that are reserved for internal system use.
  • HID Structures for Clients, which describes system-defined structures that HID clients use to communicate with the HID class driver.
  • System Structures, for information about general operating system-defined structures that are not described here.

For more information about Windows support for HID, see

Windows Input Architecture and

USB HID Standard

The structures described in this section are listed in alphabetical order.


ExReleaseResourceLite

ExReleaseResourceLite releases a specified executive resource owned by the current thread.

VOID
  ExReleaseResourceLite(
    IN PERESOURCE  Resource,
    );

Parameters

Resource
Pointer to an executive resource owned by the current thread.

Include

ntddk.h

Comments

Callers of ExReleaseResourceLite must be running at IRQL <= DISPATCH_LEVEL.

See Also

ExAcquireResourceExclusiveLite, ExAcquireResourceSharedLite, ExAcquireSharedStarveExclusive, ExAcquireSharedWaitForExclusive, ExGetCurrentResourceThread, ExInitializeResourceLite, ExReinitializeResourceLite, ExReleaseResourceLite, ExTryToAcquireResourceExclusiveLite


HalGetInterruptVector

HalGetInterruptVector is obsolete and is exported only to support existing drivers. Drivers of PnP devices are assigned resources by the PnP Manager, which passes resource lists with each IRP_MN_START_DEVICE request. Drivers that must support a legacy device that cannot be enumerated by the PnP Manager should use IoReportDetectedDevice and IoReportResourceForDetection.

ULONG
  HalGetInterruptVector(
    IN INTERFACE_TYPE  InterfaceType,
    IN ULONG  BusNumber,
    IN ULONG  BusInterruptLevel,
    IN ULONG  BusInterruptVector,
    OUT PKIRQL  Irql,
    OUT PKAFFINITY  Affinity
    );

See Also

HalAssignSlotResources, HalGetBusData, HalGetBusDataByOffset, IoAssignResources, IoQueryDeviceDescription, IoConnectInterrupt, IoReportDetectedDevice, IoReportResourceForDetection


READ_PORT_BUFFER_ULONG

READ_PORT_BUFFER_ULONG reads a number of ULONG values from the specified port address into a buffer.

VOID
  READ_PORT_BUFFER_ULONG(
    IN PULONG  Port,
    IN PULONG  Buffer,
    IN ULONG  Count
    );

Parameters

Port
Points to the port, which must be a mapped memory range in I/O space.
Buffer
Points to a buffer into which an array of ULONG values is read.
Count
Specifies the number of ULONG values to be read into the buffer.

Include

wdm.h or ntddk.h

Comments

The size of the buffer must be large enough to contain at least the specified number of ULONG values.

Callers of READ_PORT_BUFFER_ULONG can be running at any IRQL, assuming the Buffer is resident and the Port is resident, mapped device memory.


KeWaitForSingleObject

KeWaitForSingleObject routine puts the current thread into a wait state until the given dispatcher object is set to a signaled state or (optionally) until the wait times out.

NTSTATUS
  KeWaitForSingleObject(
    IN PVOID  Object,
    IN KWAIT_REASON  WaitReason,
    IN KPROCESSOR_MODE  WaitMode,
    IN BOOLEAN  Alertable,
    IN PLARGE_INTEGER  Timeout  OPTIONAL
    );

Parameters

Object
Pointer to an initialized dispatcher object (event, mutex, semaphore, thead, or timer) for which the caller supplies the storage.
WaitReason
Specifies the reason for the wait. A driver should set this value to Executive, unless it is doing work on behalf of a user and is running in the context of a user thread, in which case it should set this value to UserRequest.
WaitMode
Specifies whether the caller waits in KernelMode or UserMode. Lowest-level and intermediate drivers should specify KernelMode. If the given Object is a mutex, the caller must specify KernelMode.
Alertable
Specifies a Boolean value that is TRUE if the wait is alertable and FALSE otherwise.
Timeout
Pointer to a time-out value that specifies the absolute or relative time at which the wait is to be completed (optional). A negative value specifies an interval relative to the current time. The value should be expressed in units of 100 nanoseconds. Absolute expiration times track any changes in the system time; relative expiration times are not affected by system time changes.

Include

wdm.h or ntddk.h

Return Value

KeWaitForSingleObject can return one of the following:

STATUS_SUCCESS
The dispatcher object specified by the Object parameter satisfied the wait.
STATUS_ALERTED
The wait was completed because of an alert to the thread.
STATUS_USER_APC
A user APC was delivered to the current thread before the specified Timeout interval expired.
STATUS_TIMEOUT
A time-out occurred before the object was set to a signaled state. This value can be returned when the specified set of wait conditions cannot be immediately met and Timeout is set to zero.

Note that the NT_SUCCESS macro recognizes all of these status values as "success" values.

Comments

The current state of the specified Object is examined to determine whether the wait can be satisfied immediately. If so, the necessary side effects are performed on the object. Otherwise, the current thread is put in a waiting state and a new thread is selected for execution on the current processor.

The Alertable parameter specifies whether the thread can be alerted and its wait state consequently aborted. If the value of this parameter is FALSE then the thread cannot be alerted, no matter what the value of the WaitMode parameter or the origin of the alert. The only exception to this rule is that of a terminating thread. Under certain circumstances a terminating thread can be alerted while it is in the process of winding down. A thread is automatically made alertable, for instance, when terminated by a user with a CTRL+C.

If the value of Alertable is TRUE and one of the following conditions is present, the thread will be alerted:

  1. If the origin of the alert is an internal, undocumented kernel-mode routine used to alert threads.
  2. The origin of the alert is a user-mode APC, and the value of the WaitMode parameter is UserMode.

In the first of these two cases, the thread's wait is satisfied with a completion status of STATUS_ALERTED; in the second case, it is satisfied with a completion status of STATUS_USER_APC.

The thread must be alertable for a user-mode APC to be delivered. This is not the case for kernel-mode APCs. A kernel-mode APC can be delivered and executed even though the thread is not alerted. Once the APC's execution completes, the thread's wait resumes. A thread is never alerted, nor is its wait aborted, by the delivery of a kernel-mode APC.

The delivery of kernel-mode APCs to a waiting thread does not depend on whether the thread can be alerted. If the kernel-mode APC is a special kernel-mode APC, then the APC is delivered provided that IRQL < APC_LEVEL. If the kernel-mode APC is a normal kernel-mode APC, then the APC is delivered provided that the following three conditions hold: (1) IRQL < APC_LEVEL, (2) no kernel APC is in progress, and (3) the thread is not in a critical section.

A special consideration applies when the Object parameter passed to KeWaitForSingleObject is a mutex. If the dispatcher object waited on is a mutex, APC delivery is the same as for all other dispatcher objects during the wait. However, once KeWaitForSingleObject returns with STATUS_SUCCESS and the thread actually holds the mutex, only special kernel-mode APCs are delivered. Delivery of all other APCs, both kernel-mode and user-mode, is disabled. This restriction on the delivery of APCs persists until the mutex is released.

If the WaitMode parameter is UserMode, the kernel stack can be swapped out during the wait. Consequently, a caller must never attempt to pass parameters on the stack when calling KeWaitForSingleObject using the UserMode argument. If you allocate the event on the stack, you must set the WaitMode parameter to KernelMode.

It is especially important to check the return value of KeWaitForSingleObject when the WaitMode parameter is UserMode or Alertable is TRUE, because KeWaitForSingleObject might return early with a status of STATUS_USER_APC or STATUS_ALERTED.

All long term waits that can be aborted by a user should be UserMode waits and Alertable should be set to FALSE.

Where possible, Alertable should be set to FALSE and WaitMode should be set to KernelMode, in order to reduce driver complexity. The principal exception to this is when the wait is a long term wait.

For additional information, see Do Waiting Threads Receive Alerts and APCs?

If no Timeout is supplied, the calling thread remains in a wait state until the Object is signalled.

A Timeout of zero allows the testing of a set of wait conditions and for the conditional performance of any side effects if the wait can be immediately satisfied, as in the acquisition of a mutex.

Callers of KeWaitForSingleObject must be running at IRQL <= DISPATCH_LEVEL. Usually, the caller must be running at IRQL = PASSIVE_LEVEL and in a nonarbitrary thread context. A call while running at IRQL = DISPATCH_LEVEL is valid if and only if the caller specifies a Timeout of zero. That is, a driver must not wait for a nonzero interval at IRQL = DISPATCH_LEVEL.

See Also

ExInitializeFastMutex, KeBugCheckEx, KeInitializeEvent, KeInitializeMutex, KeInitializeSemaphore, KeInitializeTimer, KeWaitForMultipleObjects, KeWaitForMutexObject


KeAcquireSpinLock

KeAcquireSpinLock acquires a spin lock so the caller can synchronize access to shared data in a multiprocessor-safe way by raising IRQL.

VOID
  KeAcquireSpinLock(
    IN PKSPIN_LOCK  SpinLock,
    OUT PKIRQL  OldIrql
    );

Parameters

SpinLock
Pointer to an initialized spin lock for which the caller provides the storage.
OldIrql
Pointer to a variable that is set to the current IRQL when this call occurs.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Drivers for Windows XP and later should use the more efficient and reliable KeAcquireInStackQueuedSpinLock routine.

The current IRQL is saved in OldIrql. Then, the current IRQL is reset to DISPATCH_LEVEL, and the specified spin lock is acquired.

The OldIrql value must be specified when the spin lock is released with KeReleaseSpinLock.

Spin locks can cause serious problems if not used judiciously. In particular, no deadlock protection is performed and dispatching is disabled while the spin lock is held. Therefore:

  • The code within a critical region guarded by an spin lock must neither be pageable nor make any references to pageable data.
  • The code within a critical region guarded by a spin lock can neither call any external function that might access pageable data or raise an exception, nor can it generate any exceptions.
  • The caller should release the spin lock with KeReleaseSpinLock as quickly as possible.

Callers of KeAcquireSpinLock must be running at IRQL <= DISPATCH_LEVEL.

See Also

KeAcquireInStackQueuedSpinLock, KeAcquireSpinLockAtDpcLevel, KeInitializeSpinLock, KeReleaseSpinLock


RtlStoreUlong

RtlStoreUlong stores a ULONG value at a particular address, avoiding alignment faults.

VOID
  RtlStoreUlong(
    IN PULONG  Address,
    IN ULONG  Value
    );

Parameters

Address
Points to a location in which to store a given ULONG value.
Value
Specifies a ULONG value to be stored.

Include

wdm.h or ntddk.h

Comments

The caller can be running at any IRQL if Address points to nonpaged pool. Otherwise, the caller must be running at IRQL < DISPATCH_LEVEL.

See Also

RtlRetrieveUlong


RtlClearAllBits

RtlClearAllBits sets all bits in a given bitmap variable to zero.

VOID
  RtlClearAllBits(
    IN PRTL_BITMAP  BitMapHeader
    );

Parameters

BitMapHeader
Points to an initialized bitmap header for the caller's bitmap variable.

Include

ntddk.h

Comments

Callers of RtlClearAllBits must be running at IRQL < DISPATCH_LEVEL if the memory containing the bitmap variable or at BitMapHeader is pageable. Otherwise, RtlClearAllBits can be called at any IRQL.

See Also

RtlAreBitsClear, RtlAreBitsSet, RtlClearBits, RtlFindSetBits, RtlFindSetBitsAndClear, RtlInitializeBitMap, RtlNumberOfSetBits


UNICODE_STRING

The UNICODE_STRING structure is used to define UNICODE strings.

typedef struct _UNICODE_STRING {
  USHORT  Length;
  USHORT  MaximumLength;
  PWSTR  Buffer;
} UNICODE_STRING *PUNICODE_STRING;

Members

Length
The length in bytes of the string stored in Buffer.
MaximumLength
The maximum length in bytes of Buffer.
Buffer
Points to a buffer used to contain a string of wide characters.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

The STRING structure is used to pass UNICODE strings.

If the string is NULL terminated, Length does not include the trailing NULL.

The MaximumLength is used to indicate the length of Buffer so that if the string is passed to a conversion routine such as RtlUnicodeStringToAnsiString the returned string does not exceed the buffer size.

See Also

OEM_STRING, ANSI_STRING, RtlAnsiStringToUnicodeSize, RtlAnsiStringToUnicodeString, RtlFreeAnsiString, RtlInitAnsiString, RtlUnicodeStringToAnsiString


CDROM_TOC_CD_TEXT_DATA

Device control IRPs with a control code of IOCTL_CDROM_READ_TOC_EX and a format of CDROM_READ_TOC_EX_FORMAT_CDTEXT return their output data in this structure followed by a series of descriptors of type CDROM_TOC_CD_TEXT_DATA_BLOCK.

typedef struct _CDROM_TOC_CD_TEXT_DATA {
  UCHAR  Length[2];
  UCHAR  Reserved1;
  UCHAR  Reserved2;
  CDROM_TOC_CD_TEXT_DATA_BLOCK  Descriptors[0];
} CDROM_TOC_CD_TEXT_DATA, *PCDROM_TOC_CD_TEXT_DATA;

Members

Length
Indicates the number of bytes to be transferred in response to the IOCTL_CDROM_READ_TOC_EX IOCTL. This length value does not include the length of the Length member itself.
Reserved1
Reserved.
Reserved2
Reserved.
Descriptors
Zero or more text data block descriptors of type CDROM_TOC_CD_TEXT_DATA_BLOCK.

Headers

Declared in ntddcdrm.h. Include ntddcdrm.h.

See Also

IOCTL_CDROM_READ_TOC_EX, CDROM_READ_TOC_EX, CDROM_TOC_CD_TEXT_DATA_BLOCK


IOCTL_TAPE_GET_DRIVE_PARAMS

Operation

Returns information about the tape drive's capabilities, such as its default block size, maximum and minimum block sizes, maximum partition count, whether the drive has EEC, compression, data padding, and report-setmark capabilities, that is, which configurable features the drive supports, including the EOT warning zone size.

Input

Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location indicates the size in bytes of the parameter buffer, which must be >= sizeof(TAPE_GET_DRIVE_PARAMETERS). For a description of the TAPE_GET_DRIVE_PARAMETERS structure see TapeMiniGetDriveParameters.

Output

The driver returns the TAPE_GET_DRIVE_PARAMETERS data in the buffer at Irp->AssociatedIrp.SystemBuffer.

I/O Status Block

The Information field is set to the number of bytes returned. The Status field is set to STATUS_SUCCESS or possibly to STATUS_INFO_LENGTH_MISMATCH, STATUS_IO_DEVICE_ERROR, STATUS_DEVICE_DATA_ERROR, STATUS_NO_SUCH_DEVICE, STATUS_IO_TIMEOUT, or STATUS_DEVICE_NOT_READY.

Headers

Defined in ntddtape.h; Include ntddtape.h.


WNODE_SINGLE_ITEM

A WNODE_SINGLE_ITEM contains the value of a single data item in an instance of a data block.

typedef struct tagWNODE_SINGLE_ITEM {
  struct _WNODE_HEADER    WnodeHeader;
  ULONG  OffsetInstanceName;
  ULONG  InstanceIndex;
  ULONG  ItemId;
  ULONG  DataBlockOffset;
  ULONG  SizeDataItem;
  UCHAR  VariableData[];
} WNODE_SINGLE_ITEM, *PWNODE_SINGLE_ITEM;

Members

WnodeHeader
Is a WNODE_HEADER structure that contains information common to all WNODE_XXX structures, such as the buffer size, the GUID that represents a data block associated with a request, and flags that provide information about the WNODE_XXX data being passed or returned.
OffsetInstanceName
Indicates the offset from the beginning of this structure to the dynamic instance name, if any, aligned on a USHORT boundary. This member is valid only if WNODE_FLAG_STATIC_INSTANCE_NAMES is clear in WnodeHeader.Flags. If the data block was registered with static instance names, WMI ignores OffsetInstanceName.
InstanceIndex
Indicates the index into the driver's list of static instance names of this instance. This member is valid only if the data block was registered with static instance names and WNODE_FLAG_STATIC_INSTANCE_NAME is set in WnodeHeader.Flags. If the data block was registered with dynamic instance names, WMI ignores InstanceIndex.
ItemId
Specifies the ID of the data item to set.
DataBlockOffset
Indicates the offset from the beginning of this structure to the new value for the data item.
SizeDataItem
Indicates the size of the data item.
VariableData
Contains additional data, including the dynamic instance name if any, padding so the data value begins on an 8-byte boundary, and the new value for the data item.

Comments

WMI passes a WNODE_SINGLE_ITEM with an IRP_MN_CHANGE_SINGLE_ITEM request to set the value of a data item in an instance of a data block.

A driver builds a WNODE_SINGLE_ITEM to generate an event that consists of a single data item.

See Also

WNODE_EVENT_ITEM, WNODE_HEADER


IOCTL_Xxx

The following control requests are not changed to internal device control requests. Kbdclass skips the current IRP stack location and sends these requests down the device stack to be completed by the lower-level drivers:

IOCTL_GET_SYS_BUTTON_CAPS

IOCTL_GET_SYS_BUTTON_EVENT

IOCTL_HID_GET_DRIVER_CONFIG

IOCTL_HID_SET_DRIVER_CONFIG

IOCTL_HID_GET_POLL_FREQUENCY_MSEC

IOCTL_HID_SET_POLL_FREQUENCY_MSEC

IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS

IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS

IOCTL_HID_GET_COLLECTION_INFORMATION

IOCTL_HID_GET_COLLECTION_DESCRIPTOR

IOCTL_HID_FLUSH_QUEUE

IOCTL_HID_SET_FEATURE

IOCTL_HID_GET_FEATURE

IOCTL_GET_PHYSICAL_DESCRIPTOR

IOCTL_HID_GET_HARDWARE_ID

IOCTL_HID_GET_MANUFACTURER_STRING

IOCTL_HID_GET_PRODUCT_STRING

IOCTL_HID_GET_SERIALNUMBER_STRING

IOCTL_HID_GET_INDEXED_STRING


KS Data Formats and Data Ranges

The following sections introduce the basics of data formats and data ranges: specifying data formats and ranges, and negotiating data formats.

Specifying a KS Data Format or Data Range

KS Data Format Negotiation


KS_COMPRESSION

The KS_COMPRESSION structure defines the compression of frames on an output pin.

typedef struct {
    ULONG RatioNumerator;
    ULONG RatioDenominator;
    ULONG RatioConstantMargin;
} KS_COMPRESSION, *PKS_COMPRESSION;

Members

RatioNumerator
Numerator of the compression/expansion ratio.
RatioDenominator
Denominator of the compression/expansion ratio.
RatioConstantMargin
Specifies a scalar constant to apply to the compression ratio. Set to zero for no compression.

Headers

Declared in ks.h. Include ks.h.

Comments

For compression, specify a fraction less than 1. For instance, a compressor might specify 1:3. For decompression, specify a fraction greater than 1. A decompressor, for instance, might specify 3:1.


KsSynchronousIoControlDevice

The KsSynchronousIoControlDevice function performs a synchronous device I/O control on the target device object. It waits in a nonalertable state until the I/O completes. This function can only be called at PASSIVE_LEVEL.

KSDDKAPI NTSTATUS NTAPI
  KsSynchronousIoControlDevice(
    IN PFILE_OBJECT  FileObject,
    IN KPROCESSOR_MODE  RequestorMode,
    IN DWORD  IoControl,
    IN PVOID  InBuffer,
    IN ULONG  InSize,
    OUT PVOID  OutBuffer,
    IN ULONG  OutSize,
    OUT PULONG  BytesReturned
    );

Parameters

FileObject
Indicates the file object to fill in the first stack location with.
RequestorMode
Indicates the processor mode to place in the IRP if one needs to be generated.
IoControl
Specifies the I/O control to send.
InBuffer
Points to the device input buffer.
InSize
Specifies the size in bytes of the device input buffer.
OutBuffer
Points to the device output buffer.
OutSize
Specifies the size in bytes of the device output buffer.
BytesReturned
Points to the place in which to put the number of bytes returned.

Return Value

KsSynchronousIoControlDevice returns the result of the device I/O control.

Headers

Declared in ks.h. Include ks.h.


KsAllocateDefaultClockEx

The KsAllocateDefaultClockEx function allocates and initializes the default clock structure.

KSDDKAPI NTSTATUS NTAPI
  KsAllocateDefaultClockEx(
    OUT PKSDEFAULTCLOCK* DefaultClock,
    IN PVOID Context OPTIONAL,
    IN PFNKSSETTIMER SetTimer OPTIONAL,
    IN PFNKSCANCELTIMER CancelTimer OPTIONAL,
    IN PFNKSCORRELATEDTIME CorrelatedTime OPTIONAL,
    IN const KSRESOLUTION* Resolution OPTIONAL,
    IN ULONG Flags    );

Parameters

DefaultClock
Specifies the caller-allocated shared default clock structure. The current time is set to zero and the state is set to KSSTATE_STOP. Upon successful completion of this routine, the structure indicated by this pointer will contain a reference to the default clock. The data returned should be treated as opaque and reserved for system use.
Context
Optionally contains the context of the alternate time facilities. This must be set if a timer or correlated time function is used.
SetTimer
Optionally contains an alternate function to use in generating DPC timer callbacks based on a Presentation Time. If this is set, this function will be used to set timers based on deltas to the current Presentation Time in order to generate event notifications. If an alternate function is passed in to set timers, a corresponding CancelTimer function must also be passed. This is set to NULL if the default KeSetTimerEx function is to be used to approximate the next notification time. This would normally be set only if a CorrelatedTime function was being used. The function must have the same characteristics as the default function.
CancelTimer
Optionally contains an alternate function to use in cancelling outstanding timer callbacks. If an alternate function is passed in to cancel timers, a corresponding SetTimer function must also be passed. This is set to NULL if the default KeCancelTimer function is to be used. The function must have the same characteristics as the default function.
CorrelatedTime
Optionally contains an alternate function to retrieve both the Presentation and Physical Time in a correlated manner. This allows the clock owner to completely determine the current time. This is set to NULL if the default KeQueryPerformanceCounter function is to be used to regulate time progression.
Resolution
Optionally contains an alternate Granularity and/or Error factor for the clock. This can only be used only if an alternate timer or correlated time function are being provided. An alternate Granularity may be specified if an alternate correlated time is being used, else the structure element must be zero. An alternate Error may be specified if an alternate timer is being used, else the structure element must be zero.
Flags
Reserved, set to zero.

Return Value

The KsAllocateDefaultClockEx function returns STATUS_SUCCESS if successful, or a memory error if unsuccessful.

Headers

Declared in ks.h. Include ks.h.

Comments

The internal DefaultClock.ReferenceCount element is initialized to one by the KsAllocateDefaultClock function. The element is incremented and decremented as each notification DPC is queued and completed. When the structure is to be freed, the element is used to determine if the owner of the clock should free the structure or if a pending DPC should free it asynchronously.

The function can only be called at PASSIVE_LEVEL.

See Also

KsFreeDefaultClock , KsAllocateDefaultClock


_IOS_LockDrive

Summary

This service locks the specified drive for exclusive access. All I/O requests (IOR) for this drive will fail after it is locked, except those routed through the appropriate routine (returned by _IOS_LockDrive). This service cannot be used on the drive containing the swap file or non-removable media.

Entry/Exit

The service expects the drive number as the parameter passed in (TOS+4) and will return, in EAX, either a NULL (failure) or the entry point for all IOR into the locked drive.

Note Drive numbering starts with zero for drive letter A and counts up from there. If drive F is to be locked, for instance, you should pass in a five.

Usage

Following the prescribed rules for accessing IOS routines, this service function may be used to request a lock on a drive, usually removable media. The return value indicates success or failure. Failure may happen under any number of circumstances:

  • The drive is already locked
  • The drive is a paging device
  • The drive is not a removable device
  • The drive specified does not exist

The lock, once successfully obtained, will automatically be released after a timeout period of 60 seconds if no commands are sent to the returned IOR entry point. You can call the IOR entry with an empty request to refresh the timer.

This service uses (writes to) EAX, ECX, EDX, and Flags.

See Also

IOS_IsDriveLocked, IOS_UnlockDrive, LockCD Demo


The Microsoft Windows DDK Online

The Microsoft Windows
DDK Docs Online!

Welcome! OSR welcomes you to the only place on the web where you can view the Windows DDK documentation online! Through special arrangement with Microsoft, OSR is making the latest, most up-to-date, version of the DDK documentation available to the driver development community here on our web site. Plus, you get access to OSR's exclusive annotations and comments on many of the DDK functions.

The online Windows DDK is the latest available version available (often more recent than the latest MSDN release). This version of the Windows DDK includes support for developing drivers under Windows Me, Windows 2000, and Windows Codename Whistler.

We'll be updating both the DDK and the annotations regularly, so please check back often.

The version of the DDK Docs currently on our web site is part of the Beta 2 release of Windows codename Whistler (Windows XP). As mentioned on every page in the DDK, the documentation dealing with Whistler is preliminary, and subject to change prior to final release.

You can download the latest supported DDK for Windows 2000 and Windows Me from the Microsoft DDK website.

While You're Here... Make sure you participate in the Windows DDK Bug Bash Contest! Every person who files a legitimate technical bug gets a free hardcopy Win2K DDK Doc Set!

Microsoft, Windows, and the Windows Logo are registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries and the Windows Logo is used under license from Microsoft.


NDIS Debugger Extensions

You can use NDIS debugger extensions to set up NDIS debug tracing and, with Windows 2000 and later versions of the operating system, to examine NDIS data structures. When you set up NDIS debug tracing, you are actually enabling one or more levels of DbgPrint statements within NDIS, which, in most cases, provides enough information to successfully debug most network driver problems.

The following sections describe NDIS debugger extensions to use on various types of network drivers:

NDIS Debug Extensions For Windows 2000 and Later

NDIS Debug Extensions For Windows NT 4.0

NDIS Debug Extensions For Windows Me

NDIS Debug Extensions For Windows 98

NDIS WAN Debug Extensions For NT-Based Operating Systems


NDIS Debug Extensions For Windows Me

For Windows Me, you can use a checked version of the NDIS library of functions (Ndis.vxd) plus debugging options in NDIS to produce debug output for various network drivers. You enable most of these debugging options in the registry. You can set one debugging option only during a debugger session; it is not available in the registry. You can also use debugging options in the network class installer (Netdi.dll) to produce debug output during network setup and installation.

The following topics describe debugging options that you set in the registry and the debugging option that you set in the debugger:

Setting NDIS Debugging Options in the Registry

Setting NDIS Debugging Options in the Debugger

Setting Debugging Options in the Network Class Installer

Note You must disable System File Protection (SFP) before you copy the checked version of Ndis.vxd to the Windows\System directory of the target computer. To ensure that SFP is disabled, either start from the Microsoft Windows Me startup floppy or start Windows Me in safe mode. To start in safe mode, press F8 when Windows Me starts, and then select safe mode from the menu of boot options.


Related Materials

Following is a list of related materials:

  • Display Specification/Revision 1.20 7/27/95 - Windows® 95 DDK for PC-9800 series.


INetCfgComponentBindings::BindTo

The BindTo method activates all binding paths that a network component shares with another specified network component.

HRESULT
  BindTo(
    IN INetCfgComponent  *pnccItem
    );

Parameters

pnccItem
Pointer to the INetCfgComponent interface for the network component that BindTo uses to activate binding paths.

Return Value

Returns zero (S_OK) if successful; otherwise, returns a nonzero error code.

Headers

Defined in Netcfgx.h. Include Netcfgx.h.

Comments

If the INetCfg interface for the current networking configuration was not granted the write lock, BindTo returns NETCFG_E_NO_WRITE_LOCK.

See Also

INetCfg, INetCfgComponent


Handling an IRP_MN_SURPRISE_REMOVAL Request

The Windows 2000 and later PnP Manager sends this IRP to notify drivers that a device has been unexpectedly removed from the machine and is no longer available for I/O ("surprise" removal).

All PnP drivers must handle this IRP. Proper handling of the IRP enables the drivers and the PnP Manager to:

  1. Release hardware resources assigned to the device and make them available to another device.

    As soon as a device is physically removed from the machine, its hardware resources should be freed. The PnP Manager can then reassign the resources to another device, including the same device, which a user might hot-plug back into the machine.

  2. Minimize the risk of data loss and system disruption.

    When a user removes a hot-plug device without first using the Unplug or Eject Hardware applet, the surprise-removal can hang the machine, crash the machine, and/or cause data loss.

    The best way to avoid such disruption is for the device vendor to implement a locking mechanism for hot-plug devices. Such a mechanism ensures that the device is removed in a controlled fashion. The PnP Manager alerts components accessing the device that the device is being removed, so that they can perform orderly clean-up and removal.

    In case a device does not have a locking mechanism or is attached to another device that does not lock, its drivers must handle an IRP_MN_SURPRISE_REMOVAL request. Handling this IRP does not prevent disruption from a surprise removal, but it minimizes the impact by stopping I/O to the device as soon as the removal is detected and the drivers handle the IRP.

A surprise removal is detected in one of the following ways:

  • If the bus has hot-plug notification, it notifies the device's parent bus driver that the device has disappeared. The bus driver calls IoInvalidateDeviceRelations. In response, the PnP Manager queries the bus driver for its children (IRP_MN_QUERY_DEVICE_RELATIONS for BusRelations). The PnP Manager determines that the device is not in the new list of children and initiates its surprise-removal operations for the device.
  • The bus is enumerated for another reason and the surprise-removed device is not included in the list of children. The PnP Manager initiates its surprise removal operations.
  • The function driver for the device determines that the device is no longer present (because, for example, its requests repeatedly time out). The bus might be enumerable but it does not have hot-plug notification. In this case, the function driver calls IoInvalidateDeviceState. In response, the PnP Manager sends an IRP_MN_QUERY_PNP_DEVICE_STATE request to the device stack. The function driver sets the PNP_DEVICE_FAILED flag in the PNP_DEVICE_STATE bitmask indicating that the device has failed.

The PnP Manager sends an IRP_MN_SURPRISE_REMOVAL at IRQL PASSIVE_LEVEL in the context of a system thread.

The PnP Manager sends this IRP to drivers before notifying user-mode applications and other kernel-mode components. After the IRP completes, the PnP Manager sends an EventCategoryTargetDeviceChange notification with GUID_TARGET_DEVICE_REMOVE_COMPLETE to kernel-mode components that registered for such notification on the device.

The IRP_MN_SURPRISE_REMOVAL IRP is handled first by the top driver in the device stack and then by each next lower driver. All PnP drivers must handle this IRP and must set STATUS_SUCCESS.

A driver for a PnP device must be prepared to handle an IRP_MN_SURPRISE_REMOVAL at any time after the driver's AddDevice routine is called.

In response to an IRP_MN_SURPRISE_REMOVAL, a driver must do the following:

  1. Prevent any new I/O to the device.

    A driver should process subsequent close, clean-up, power, and PnP requests, but the driver must prevent any new I/O to the device. A driver must fail any subsequent IRPs that the driver would have handled if the device were present, besides close, clean-up, and PnP IRPs.

    A driver can set a bit in the device extension to indicate that the device has been surprise-removed. The driver's dispatch routines should check this bit.

  2. Fail outstanding I/O requests on the device.
  3. Continue to pass down any IRPs that the driver does not handle for the device.
  4. In a parent bus driver, power down the bus slot if the driver is capable of doing so. Call PoSetPowerState to notify the Power Manager. For additional information, see Power Management.
  5. Disable device interfaces with IoSetDeviceInterfaceState.
  6. Release the device's hardware resources (interrupts, I/O ports, memory registers, and DMA channels).
  7. Clean up any device-specific allocations, memory, events, etc.

    A driver could postpone such clean-up until it receives the subsequent IRP_MN_REMOVE_DEVICE request, but if a legacy component has an open handle that cannot be closed, the remove IRP will never be sent.

  8. Leave the device object attached to the device stack.

    Do not detach and delete the device object until the subsequent IRP_MN_REMOVE_DEVICE request.

  9. Finish the IRP.

    In a function or filter driver:

    • Set Irp->IoStatus.Status to STATUS_SUCCESS.
    • Set up the next stack location with IoSkipCurrentIrpStackLocation and pass the IRP to the next lower driver with IoCallDriver.
    • Propagate the status from IoCallDriver as the return status from the DispatchPnP routine.
    • Do not complete the IRP.

    In a bus driver (that is handling this IRP for a child PDO):

    • Set Irp->IoStatus.Status to STATUS_SUCCESS.
    • Complete the IRP (IoCompleteRequest) with IO_NO_INCREMENT.
    • Return from the DispatchPnP routine.

After this IRP succeeds and all open handles to the device are closed, the PnP Manager sends an IRP_MN_REMOVE_DEVICE request to the device stack. In response to the remove IRP, drivers detach their device objects from the stack and delete them. If a legacy component has a handle open to the device and it leaves the handle open despite I/O failures, the PnP Manager never sends the remove IRP.

All drivers should handle this IRP and should note that the device has been physically removed from the machine. Some drivers, however, will not cause adverse results if they do not handle the IRP. For example, a device that consumes no system hardware resources and resides on a protocol-based bus, such as USB or 1394, cannot tie up hardware resources because it does not consume any. There is no risk of drivers attempting to access the device after it has been removed because the function and filter drivers access the device only through the parent bus driver. Because the bus supports removal notification, the parent bus driver is notified when the device disappears and the bus driver fails all subsequent attempts to access the device.

On Windows 98/Me, the PnP Manager does not send this IRP. If a user removes a device without first using the appropriate user interface, the PnP Manager sends only an IRP_MN_REMOVE_DEVICE request to the drivers for the device. All WDM drivers must handle both IRP_MN_SURPRISE_REMOVAL and IRP_MN_REMOVE_DEVICE. The code for IRP_MN_REMOVE_DEVICE should check whether the driver received a prior surprise-remove IRP and should handle both cases.


Providing Device Property Pages

A co-installer or class installer should supply a custom device property page if its device or class has any individual properties that a user can set. Such properties might include default playback volume for a CD-ROM drive or speaker volume for a modem. The Device Manager displays the property page any time a user clicks on Properties for the device. For versions of Microsoft® Windows NT® prior to Windows 2000, users set such information through Control Panel applets. Driver software written for Windows® 2000 and later should provide property pages instead.

Although you can write a class installer that provides custom property pages, it's generally preferable to provide this functionality in a co-installer, along with other device- or device-class-specific features.

The Platform SDK documentation provides comprehensive documentation of property pages and the Win32® functions that manipulate them. This chapter supplements the Platform SDK documentation with the following information specific to device installation:

Required Support for Device Property Pages

Handling DIF_ADDPROPERTYPAGE_ADVANCED Requests

Property Page Callback Function

Handling Windows Messages for Property Pages


Device Power States

A device power state describes the power state of a particular device. Device power states are named Dx, where x is a state number between 0 and 3. The state number is inversely related to power consumption: higher numbered states use less power.

Device power states are defined in terms of the following criteria:

  • Power consumption: How much power does the device use?
  • Device context: How much of its operational context does the device retain in this state?
  • Device driver behavior: What must the drivers for the device do to restore the device to the fully operational state?
  • Restore time: How long does it take to restore the device to the fully operational state?
  • Wake-up capability: Can the device request wake-up from this state? In general, if a device can request wake-up from a given power state (D2, for example), it can also request wake-up from any higher-powered state (D1).

The exact definitions of the power states are device-specific. Not all devices define all the states; many devices define only the D0 and D3 states. See the relevant Device Class Power Management Reference Specification (available through the Microsoft Hardware Development website at www.microsoft.com/hwdev) to find out which device states are defined for a specific device and what the operational requirements are for each state.

The power state of a device need not match the power state of the system. For example, some devices can be in the off (D3) state even though the system is in the working (S0) system power state. Usually, a device's power state is no higher than that of the system because many devices get their power from the system. Devices that are enabled to wake the system are exceptions, however; such devices are typically in a low-latency sleeping state (D1 or D2) when the system is in a sleeping state.

Note that some devices are capable of several different low power modes within a single device power state. Such a device can use these modes if its driver can automatically switch the device from one mode to another without changing the device power state. As a general rule, however, if there is no user-perceptible difference between the modes, the device should use only the lowest power mode. If a low power mode, such as a low speed, adversely affects performance or is not transparent to software other than the device driver, the hardware should not automatically use it. See the Device Class Power Management Reference Specifications for details.

A driver or the Power Manager can request a device power state transition, and all drivers must be prepared to handle IRPs that request such transitions. For details, see:

Sending IRP_MN_QUERY_POWER or IRP_MN_SET_POWER for Device Power States

Handling IRP_MN_QUERY_POWER for Device Power States

Handling IRP_MN_SET_POWER for Device Power States

Like the system, a device can transition from the working state (D0) to any sleeping state (D1-D3) and from any sleeping state to the working state.


Data Class Interface

The Data Class interface is described by a standard USB Interface Descriptor followed by two endpoint descriptors. The two endpoint descriptors in the Data Class interface define standard USB Bulk-type endpoints: one Bulk-IN and one Bulk-OUT. The following table defines the prominent fields of the Data Class Interface Descriptor.

Offset (bytes) | Field | Size (bytes) | Value | Description
5 | bInterfaceClass | 1 | 0Ah | Data Interface Class code.
6 | bInterfaceSubClass | 1 | 00h | Data Class SubClass code.
7 | bInterfaceProtocol | 1 | 00h | Data Class Protocol code.


IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS

Operation

The IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS request sets a COM port to a basic operating mode. Serial's basic operating mode reads and writes one byte at a time, and does not use handshake flow control or timeouts. The basic operation mode is suitable for use by a driver that uses a subset of the 16550 UART interface. Examples of such drivers include a mouse driver or a graphics pad driver for older hardware that use a 16450 UART.

The IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS request returns the operating mode settings that are in use just before Serial sets the basic operation mode. A client uses an IOCTL_SERIAL_INTERNAL_RESTORE_SETTINGS request to restore a previous operating mode. A client should treat the operating mode settings as opaque. Serial does not verify the settings when the settings are restored. Note also that a replacement driver for Serial might implement a different set of basic settings.

Input

The Parameters.DeviceIoControl.OutputBufferLength is set to the size in bytes of a SERIAL_BASIC_SETTINGS structure.

Output

The AssociatedIrp.SystemBuffer points to a client-allocated SERIAL_BASIC_SETTINGS structure that Serial uses to output the current configuration.

I/O Status Block

If the request is successful, the Information member is set to the size in bytes of SERIAL_BASIC_SETTINGS. Otherwise, the Information member is set to zero.

The Status member is set to one of the following values:

STATUS_SUCCESS
STATUS_BUFFER_TOO_SMALL
The value of Parameters.DeviceIoControl.OutputLength is less than the size in bytes of a SERIAL_BASIC_SETTINGS structure.
STATUS_CANCELLED
STATUS_DELETE_PENDING
STATUS_PENDING


Requesting and Responding to SMB Alarm Notifications

The SMB host controller can notify a client driver when an SMB device reports an alarm. To register for alarm notification, an SMB client sends an IRP_MJ_INTERNAL_DEVICE_CONTROL IRP to the host controller.

The client driver calls IoAllocateIrp to allocate the IRP, calls IoGetNextIrpStackLocation to set the pointer to the IRP stack, then sets values in the IRP as follows:

  • Irp –> UserBuffer to a location to receive the returned notification handle (PVOID)
  • IrpStack –> MajorFunction to IRP_MJ_INTERNAL_DEVICE_CONTROL
  • IrpStack –> Parameters.DeviceIoControl.IoControlCode to SMB_REGISTER_ALARM_NOTIFY
  • IrpStack –> Parameters.DeviceIoControl.Type3InputBuffer to the address of an SMB_REGISTER_ALARM structure containing information about the requested alarm
  • IrpStack –> Parameters.DeviceIoControl.InputBufferLength to the size of the SMB_REGISTER_ALARM structure
  • IrpStack –> Parameters.DeviceIoControl.OutputBufferLength to the size of the location allocated for the handle

The SMB_REGISTER_ALARM structure specifies the range of addresses at which the driver requests notification, a pointer to a notification function to be called when the alarm occurs, and a pointer to the context to be passed to the notification function. Typically the context is the device extension in the client driver's FDO.

If the input or output buffer is too small, or if the SMB class driver cannot allocate sufficient space for its alarm record, then the IRP fails. Otherwise, the SMB class driver registers the alarm notification and returns a registration handle at the specified location.

To remove the notification, the client driver sends an IRP_MJ_INTERNAL_DEVICE_CONTROL request with IoControlCode SMB_DEREGISTER_ALARM_NOTIFY, and passes a pointer to the handle in Type3InputBuffer. In response, the class driver deletes its alarm notification.

The class driver acquires a spin lock on the SMB device when it registers or unregisters the notification. In either case, it releases this lock before completing the IRP.

In its notification function, the client driver handles the alarm as appropriate for its device. The SMB class driver passes the bus address at which the alarm occurred as a parameter to the notification function, along with two bytes of alarm data. The significance of the data is device-dependent.


IStiUSD::UnLockDevice

A still image minidriver's IStiUSD::UnLockDevice method unlocks a device that was locked by a previous call to IStiUSD::LockDevice.

STDMETHODIMP
  UnLockDevice(
    VOID
    );

Parameters

None

Return Value

If the operation succeeds, the method should return S_OK. Otherwise, it should return one of the STIERR-prefixed error codes defined in stierr.h.

Headers

Declared in stiusd.h. Include stiusd.h.

Comments

If a driver's IStiUSD::LockDevice method called CreateFile, then IStiUSD::UnlockDevice should call CloseHandle.

See Also

IStiDevice::UnLockDevice


ILB_int_io_criteria_rtn

cCall [ilb.ILB_int_io_criteria_rtn],<<OFFSET32 IOP>>
or  eax, eax
jnz error

This service is used by IOS layer drivers located in the IOS layered driver hierarchy. IOS clients should use ILB_io_criteria_rtn instead.

The service ensures that total transfer count does not exceed the maximum allowed, checks for too many logical SGDs (Scatter-Gather Descriptors), and optionally audits linear buffer start addresses and buffer lengths for WORD or DWORD alignment.

If this service has been so requested, it will generate a list of physical SGDs into memory pointed to by IOR_sgd_lin_phys. It will work from either a single linear address (IORF_SCATTER_GATHER=FALSE) or from a linear scatter-gather list (IORF_SCATTER_GATHER=TRUE). In the latter case, the SGD list is terminated with a zero-count SGD.

The physical SGD conversion service is performed by calling the _CopyPageTable function to obtain the list of page table entries (PTEs) that correspond to the linear address space(s) specified. Next, the service routine attempts to concatenate PTEs whose physical addresses are contiguous, into a single physical SGD if possible. The maximum allowed size of each physical SGD is 65535 bytes; this limit will be observed while concatenating physical SGDs. If the processing of the linear address space(s) results in too many physical SGDs being created (IOR_num_sgds becomes greater than the smaller of 17 or DCB_max_sg_elements), the io_criteria routine reports an error. This service fails if any linear buffer (pointed to by IOR_buffer_ptr or the SGD field BD_SG_Buffer_Ptr) being processed is larger than 512K.

A successful call is indicated if the EAX register returns 0.

If this call is unsuccessful, it generally indicates that IOS needs to perform double-buffering to successfully complete the request; set the IORF_DOUBLE_BUFFER bit in IOR_flags before calling IOS_SendCommand.

The following table lists the fields used by this service.


Using Spin Locks - An Example

Previous Next

Using Spin Locks – An Example

Minimizing the time that a driver holds spin locks can significantly improve both the performance of the driver and of the system overall. For example, consider the following figure, which shows how an interrupt spin lock protects device-specific data that must be shared between an ISR and the StartIo and DpcForIsr routines in an SMP machine.

Using an Interrupt Spin Lock

  1. While the driver's ISR runs at DIRQL on one processor, its StartIo routine runs at DISPATCH_LEVEL on a second processor. The Kernel interrupt handler holds the InterruptSpinLock for the driver's ISR, which accesses protected, device-specific data, such as state or pointers to device registers (SynchronizeContext), in the driver's device extension. The StartIo routine, which is ready to access SynchronizeContext, calls KeSynchronizeExecution, passing a pointer to the associated interrupt object(s), the shared SynchronizeContext, and the driver's SynchCritSection routine (AccessDevice in the previous figure).

    Until the ISR returns, thereby releasing the driver's InterruptSpinLock, KeSynchronizeExecution spins on the second processor, preventing AccessDevice from touching SynchronizeContext. However, KeSynchronizeExecution also raises IRQL on the second processor to the SynchronizeIrql of the interrupt object(s), thereby preventing another device interrupt from occurring on that processor so that AccessDevice can be run at DIRQL as soon as the ISR returns. However, higher DIRQL interrupts for other devices, clock interrupts, and power-fail interrupts can still occur on either processor.

  2. When the ISR queues the driver's DpcForIsr and returns, AccessDevice runs on the second processor at the SynchronizeIrql of the associated interrupt object(s) and accesses SynchronizeContext. Meanwhile, the DpcForIsr is run on another processor at DISPATCH_LEVEL IRQL. The DpcForIsr also is ready to access SynchronizeContext, so it calls KeSynchronizeExecution with the same parameters as the StartIo routine did in Step 1.

    When KeSynchronizeExecution acquires the spin lock and runs AccessDevice on behalf of the StartIo routine, the driver-supplied synchronization routine AccessDevice is given exclusive access to SynchronizeContext. Because AccessDevice runs at the SynchronizeIrql, the driver's ISR cannot acquire the spin lock and access the same area until the spin lock is released, even if the device interrupts on another processor while AccessDevice is executing.

  3. AccessDevice returns, releasing the spin lock. The StartIo routine resumes running at DISPATCH_LEVEL on the second processor. KeSynchronizeExecution now runs AccessDevice on the third processor, so it can access SynchronizeContext on behalf of the DpcForIsr. However, if a device interrupt had occurred before the DpcForIsr called KeSynchronizeExecution in Step 2, the ISR might run on another processor before KeSynchronizeExecution could acquire the spin lock and run AccessDevice on the third processor.

As the previous figure shows, while a routine running on one processor holds a spin lock, every other routine trying to acquire that spin lock gets no work done. Each routine trying to acquire an already held spin lock simply spins on its current processor until the holder releases the spin lock. When a spin lock is released, one and only one routine can acquire it; every other routine currently trying to acquire the same spin lock will continue to spin.

The holder of any spin lock runs at raised IRQL: either at DISPATCH_LEVEL for an executive spin lock, or at a DIRQL for an interrupt spin lock. Callers of KeAcquireSpinLock and KeAcquireInStackQueuedSpinLock run at DISPATCH_LEVEL until they call KeReleaseSpinLock or KeReleaseInStackQueuedSpinLock to release the lock. Callers of KeSynchronizeExecution automatically raise IRQL on the current processor to the SynchronizeIrql of the interrupt object(s) until the caller-supplied SynchCritSection routine exits and KeSynchronizeExecution returns control. See Calling Support Routines that Use Spin Locks for more information.

Keep in mind the following fact about using spin locks:

All code that runs at a lower IRQL cannot get any work done on the set of processors occupied by a spin-lock holder and by other routines trying to acquire the same spin lock.

Consequently, minimizing the time a driver holds spin locks results in significantly better driver performance and contributes significantly to better overall system performance.

As the previous figure shows, the Kernel interrupt handler executes routines running at the same IRQL in a multiprocessor machine on a first-come, first-served basis. The Kernel also does the following:

  • When a driver routine calls KeSynchronizeExecution, the Kernel causes the driver's SynchCritSection routine to run on the same processor from which the call to KeSynchronizeExecution occurred (see Steps 1 and 3).
  • When a driver's ISR queues its DpcForIsr, the Kernel causes the DPC to run on the first available processor on which IRQL falls below DISPATCH_LEVEL. This is not necessarily the same processor from which the IoRequestDpc call occurred (see Step 2).

A driver's interrupt-driven I/O operations might tend to be serialized in a uniprocessor machine, but the same operations can be truly asynchronous in an SMP machine. As the previous figure shows, a driver's ISR could run on CPU4 in an SMP machine before its DpcForIsr begins processing an IRP for which the ISR has already handled a device interrupt on CPU1.

In other words, you should not assume that an interrupt spin lock can protect operation-specific data that the ISR saves when it runs on one processor from being overwritten by the ISR when a device interrupt occurs on another processor before the DpcForIsr or CustomDpc routine runs.

Although a driver could try to serialize all interrupt-driven I/O operations to preserve data collected by the ISR, that driver would not run much faster in an SMP machine than in a uniprocessor machine. To get the best possible driver performance while remaining portable across uniprocessor and multiprocessor platforms, drivers should use some other technique to save operation-specific data obtained by the ISR for subsequent processing by the DpcForIsr.

For example, an ISR can save operation-specific data in the IRP it passes to the DpcForIsr. A refinement of this technique is to implement a DpcForIsr that consults an ISR-augmented count, processes the count's number of IRPs using ISR-supplied data, and resets the count to zero before returning. Of course, the count must be protected by the driver's interrupt spin lock because its ISR and a SynchCritSection would maintain its value dynamically.


USBCAMD New Services Code Example

The camera minidriver sends an IRP_MN_QUERY_INTERFACE to itself to access USBCAMD version 2.0 services. This IRP will be processed by the USBCAMD minidriver library, which will return a direct-call interface to the camera minidriver. The camera minidriver should not send IRP_MN_QUERY_INTERFACE to USBCAMD until after the camera minidriver has received a SRB_INITIALIZATION_COMPLETE notification.

The following code demonstrates how a camera minidriver sends the IRP_MN_QUERY_INTERFACE request.

    KeInitializeEvent(&Event, NotificationEvent, FALSE);
    Irp = IoBuildSynchronousFsdRequest(
        IRP_MJ_PNP,
        pDeviceObject,
        NULL,
        0,
        NULL,
        &Event,
        &IoStatusBlock);

    if (Irp) {
        Irp->RequestorMode = KernelMode;
        IrpStackNext = IoGetNextIrpStackLocation(Irp);
        //
        // Create an interface query out of the Irp.
        //
        IrpStackNext->MinorFunction = IRP_MN_QUERY_INTERFACE;
        IrpStackNext->Parameters.QueryInterface.InterfaceType = (GUID*)&GUID_USBCAMD_INTERFACE;
        IrpStackNext->Parameters.QueryInterface.Size = sizeof(*pUsbcamdInterface);
        IrpStackNext->Parameters.QueryInterface.Version = USBCAMD_VERSION_200;
        IrpStackNext->Parameters.QueryInterface.Interface = (PINTERFACE)pUsbcamdInterface;
        IrpStackNext->Parameters.QueryInterface.InterfaceSpecificData = NULL;
        Status = IoCallDriver(pDeviceObject, Irp);
        if (Status == STATUS_PENDING) {
            //
            // This waits using KernelMode, so that the stack, and therefore the
            // event on that stack, is not paged out.
            //
            KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
            Status = IoStatusBlock.Status;
        }

    } else {
        Status = STATUS_INSUFFICIENT_RESOURCES;
    }

IRP_MN_QUERY_INTERFACE will return an interface of the type USBCAMD_INTERFACE, which is essentially a table of function pointers.


KSPROPERTY_TVAUDIO_CURRENTLY_AVAILABLE_MODES

The KSPROPERTY_TVAUDIO_CURRENTLY_AVAILABLE_MODES property is used to retrieve the available TVAudio modes for the device.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | Yes
Set (Write) | No | N/A

Property Data

The Mode member of the KSPROPERTY_TVAUDIO_MODE_S structure is used to specify the audio mode. It contains a bitwise ORing of the KS_TVAUDIO_MODE_* flags indicating the modes supported by the device at the time the information was requested.

Ranges and Default Values

None

See Also

KSPROPERTY_TVAUDIO_MODE_S


KSPROPERTY_VIDEOPROCAMP_BRIGHTNESS

The KSPROPERTY_VIDEOPROCAMP_BRIGHTNESS property is used to set and get the brightness setting. Brightness is also known as black level. Modifying the brightness setting shifts the entire video signal equally for all luminance values.

Property Support Requirements

Property Request | Property is Supported | Property Support is Required
Get (Read) | Yes | No
Set (Write) | Yes | No

Property Data

The Value member of the KSPROPERTY_VIDEOPROCAMP_S structure is used to specify the brightness. This value is expressed in IRE units times 100 for NTSC sources. For non-NTSC sources, the units are arbitrary, with zero representing blanking and 10000 representing pure white.

Ranges and Default Values

Every video capture driver must define a range and default value for this property. The required range must be a subset of -10000 to 10000, and the default value must be 750 (7.5 IRE). The value type must be VT_I4.

See Also

KSPROPERTY_VIDEOPROCAMP_S


AgpCommitVirtual

AgpCommitVirtual maps reserved virtual memory to an associated range of AGP-decodable physical addresses.

PVOID
  (*PAGP_COMMIT_VIRTUAL)(
    IN PVOID  HwDeviceExtension,
    IN PVOID  VirtualReserveContext,
    IN ULONG  Pages,
    IN ULONG  Offset
    );

Parameters

HwDeviceExtension
Points to the miniport driver's device extension.
VirtualReserveContext
Identifies a reserved virtual address range. The context handle was obtained from AgpReserveVirtual.
Pages
Specifies the number of pages of virtual memory to commit.
Offset
Specifies the page offset at which to commit the pages. The offset is applied to the reserved physical address range associated with PhysicalReserveContext

Return Value

AgpCommitVirtual returns the virtual address for the base of the committed pages if the mapping succeeded; otherwise returns NULL.

Headers

Declared in videoagp.h. Include video.h.

Comments

A video miniport driver must first reserve virtual addresses and associate them with AGP-decodable physical memory by calling AgpReserveVirtual before it calls this function.

When a miniport driver calls AgpCommitVirtual, Pages pages of virtual memory are locked down and mapped to the AGP-decodable physical address range.This range begins Offset pages into the physical address range associated with VirtualReserveContext. An application can access committed virtual memory as if it were contiguous.

A miniport driver must reserve and commit both physical and virtual memory before an application can use AGP-decodable physical memory.

Callers of AgpCommitVirtual must be running at IRQL = PASSIVE_LEVEL.

See Also

AgpFreeVirtual, AgpReservePhysical, AgpReserveVirtual


VideoPortWritePortUlong

VideoPortWritePortUlong writes a ULONG value to a mapped I/O port.

VOID
  VideoPortWritePortUlong(
    IN PULONG  Port,
    IN ULONG  Value
    );

Parameters

Port
Points to the port. The given Port must be in a mapped I/O-space range returned by VideoPortGetDeviceBase.
Value
Specifies a ULONG value to be transferred to the adapter.

Return Value

None

Headers

Declared in video.h. Include video.h.

Comments

A miniport driver's HwVidInterrupt or HwVidSynchronizeExecutionCallback function can call VideoPortWritePortUlong.

Callers of VideoPortWritePortUlong can be running at any IRQL, provided that the memory pointed to by the Port parameter is resident, mapped device memory.

See Also

VideoPortGetDeviceBase


Setting and Clearing a Communication Mode for a Parallel Device

A client can set the communication mode of a parallel device using the following device control requests:

  • IOCTL_IEEE1284_GET_MODE returns the current communication protocols set on the device. The port does not have to be locked to use this request.
  • IOCTL_IEEE1284_NEGOTIATE negotiates a new communication mode. The parallel port must be allocated and the IEEE 1284.3 device selected.
  • IOCTL_INTERNAL_DISCONNECT_IDLE sets the communication mode to IEEE_COMPATIBLE. The parallel port must be allocated and the IEEE 1284.3 device selected.

A kernel mode driver can also use the following parallel device callback routines to determine, set, and clear IEEE 1284 communication modes:

  • DetermineIeeeModes determines the IEEE communication modes that the parallel port supports.
  • NegotiateIeeeMode sets the fastest IEEE communication mode that the parallel port bus driver supports from among the modes specified by the caller.
  • TerminateIeeeMode sets the communication mode to IEEE 1284-compatibility mode.
  • IeeeFwdToRevMode changes the data transfer direction from forward to reverse (from write to read).
  • IeeeRevToFwdMode changes the transfer direction from reverse to forward (from read to write).

For more information on the communication modes that the parallel port bus driver supports, see the modes NONE through ECP_ANY that are defined in the include file ntddpar.h in the Windows DDK.


Setting and Clearing the Communication Mode on a Parallel Port

A client sets the communication mode on a parallel port by using the following internal device control requests:

IOCTL_INTERNAL_PARALLEL_SET_CHIP_MODE

IOCTL_INTERNAL_PARALLEL_CLEAR_CHIP_MODE

A kernel-mode driver can also use the following parallel port callback routines:

TrySetChipMode

ClearChipMode

A client must first allocate a parallel port before it can set or clear the communication mode.

A client must first clear the communication mode before it can set a new communication mode. Clearing the communication mode returns the host chipset to IEEE 1284-compatibility mode.

To determine the current mode, a client can use an IOCTL_INTERNAL_GET_PARALLEL_PNP_INFO request, which returns a PARALLEL_PNP_INFORMATION structure that contains information about the current communication mode.


Set_DevNode_PowerStateTable

The Power State Table maps system states to device states for a given device. The ACPI driver calls the Set_DevNode_PowerStateTable service to set the Power State Table for a device.

CONFIGRET
  CONFIGMG_Set_DevNode_PowerStateTable(
    DEVNODE  dnDevNode,
    PVOID  pPowerTable,
    ULONG  ulFlags
    );

Parameters

dnDevNode
Handle to the device node from which to set the Power State Table.
pPowerTable
Pointer to the Power State Table for the device represented by the specified device node.
ulFlags
Reserved. Currently must be zero.


KSPROPERTY_VIDEOPROCAMP_HUE

The KSPROPERTY_VIDEOPROCAMP_HUE read/write property is used to set and retrieve the hue setting.

The KSPROPERTY_VIDEOPROCAMP_S.Value member specifies the hue value expressed in degrees * 100. Value range is from –18000 to 18000 ( –180 to +180 degrees), and the default is zero. Note that a particular device may only implement a subset of this range.


wiasReadMultiple

The wiasReadMultiple function retrieves multiple property values from a WIA item.

HRESULT
  wiasReadMultiple(
    BYTE  *pWiasContext,
    ULONG  ulCount,
    const PROPSPEC  *ps,
    PROPVARIANT  *pv,
    PROPVARIANT  *pvOld
    );

Parameters

pWiasContext
Pointer to a WIA service context.
ulCount
Specifies the number of properties to read.
ps
Pointer to the first element of an array of PROPSPEC structures, containing the properties to read.
pv
Pointer to the first element of an array of PROPVARIANT structures. Upon return, these structures contain new values for the properties.
pvOld
Pointer to the first element of an array of PROPVARIANT structures previously allocated by the minidriver. Upon return, the array contains the previous values of the property data. If this information is not needed, this parameter can be set to NULL.

Return Value

On success, the function returns S_OK. If the function fails, it returns a standard COM error or one of the WIA_ERROR_XXX errors (described in the Platform SDK documentation).

Headers

Declared in wiamdef.h. Include wiamdef.h.

Comments

This function reads multiple properties from a WIA item. When the call succeeds, the minidriver must call PropVariantClear on each element in the array specified by the pv parameter. See IPropertyStorage::ReadMultiple for more information.

PROPSPEC, PROPVARIANT, PropVariantClear, and IPropertyStorage::ReadMultiple are described in the Platform SDK documentation.

This function is available in Windows Me and in Windows XP and later.

See Also

wiasWriteMultiple


CWiauPropertyList::SetAccessSubType

The CWiauPropertyList::SetAccessSubType method resets a property's access and subtype.

VOID
  SetAccessSubType(
    INT  index,
    ULONG  Access,
    ULONG SubType
    );

Parameters

index
Specifies the property's index in the property list.
Access
Specifies the type of access for the property, usually either WIA_PROP_READ (read-only) or WIA_PROP_RW (read/write).
SubType
Specifies the property subtype, one of WIA_PROP_FLAG, WIA_PROP_LIST, WIA_PROP_RANGE, or WIA_PROP_NONE. The first three constants indicate, respectively, that a property is a set of flag values, a list of values, or a range of values. The fourth constant indicates that a property is none of these.

Return Value

None

Headers

Declared in wiautil.h. Include wiautil.h and wiamindr.h.

Comments

This method is available in Windows XP and later.

The WIA_PROP_XXX constants are defined in the Platform SDK documentation.

A property's access and subtype are set originally in a call to the CWiauPropertyList::DefineProperty method.

See Also

CWiauPropertyList::DefineProperty


Caching Registered Memory

SAN service providers can cache RDMA buffers that are exposed for either local or remote access to improve performance.

Caching RDMA Buffers Exposed for Local Access

The Windows Sockets switch calls a SAN service provider's WSPRegisterMemory extension function on behalf of an application to register all data buffers that serve as either the local receiving RDMA buffer in a call to the WSPRdmaRead extension function or the local RDMA source in a call to the WSPRdmaWrite extension function. As part of this registration process, the SAN service provider must lock down these buffers to regions of physical memory and register them with the SAN NIC. Both of these operations are resource intensive. Therefore, the SAN service provider should use caching to reduce the overhead of these registrations. If the SAN service provider uses caching, the performance of applications that reuse buffers for data transfers improves.

SAN service providers should cache and release RDMA buffers that are exposed for local access as described in the following list:

  1. When the switch calls the WSPDeregisterMemory extension function to release a buffer, the SAN service provider should leave the buffer registered with the SAN NIC and locked down to a region of physical memory. The SAN service provider should also add the buffer to a cache of registered buffers, in case the buffer is used again in a subsequent RDMA operation, and secure possession of the buffer as described in the next list item.
  2. A SAN service provider caches memory registrations based on virtual addresses. When the SAN service provider caches a buffer's registration, the SAN service provider's proxy driver must call the MmSecureVirtualMemory function to secure possession of that registered buffer so that the operating system notifies the switch if the buffer is released (for example, if an application calls the VirtualFree function to release a virtual address range back to the operating system).
  3. When the switch subsequently calls WSPRegisterMemory to register a buffer, the SAN service provider should check its cache to determine if the buffer is already registered. If the SAN service provider finds the buffer in its cache, the SAN service provider should not perform any further registration action.
  4. Before the virtual-to-physical mappings of the registered buffer subsequently change, the switch calls each SAN service provider's WSPMemoryRegistrationCacheCallback extension function. Each SAN service provider's proxy driver, in turn, must call the MmUnsecureVirtualMemory function to release ownership of the buffer. In addition, each SAN service provider must remove the buffer from its cache and must remove the buffer registration from the SAN NIC.
  5. Before the connection between a local SAN socket and a remote peer is closed, the SAN service provider should release any cached buffers.

Note The proxy driver must use the try/except mechanism around the MmSecureVirtualMemory and MmUnsecureVirtualMemory calls to prevent operating system crashes. For more information about how a proxy driver secures and releases buffers, see Securing and Releasing Ownership of Virtual Addresses. For more information on try/except, see the Visual C++® documentation. For information on VirtualFree, see the Platform SDK documentation.

Caching RDMA Buffers Exposed for Remote Access

The Windows Sockets switch calls a SAN service provider's WSPRegisterRdmaMemory extension function to register all data buffers that serve as either the remote RDMA target of a remote WSPRdmaWrite call or the remote RDMA source of a remote WSPRdmaRead call. That is, the switch exposes these buffers for access by a remote peer. After data transfers from these buffers are completed, the switch calls the SAN service provider's WSPDeregisterRdmaMemory extension function to release these buffers so that they are no longer accessible from the remote peer.

SAN service providers should cache RDMA buffers that are exposed for remote access as described in the following list:

  1. When the Switch calls WSPDeregisterRdmaMemory to release a buffer, the SAN service provider should leave the buffer locked in physical memory and registered with the SAN NIC. The SAN service provider should also add the buffer to a cache of registered buffers, in case the buffer is used again in a subsequent RDMA operation. However, the SAN service provider should take appropriate action to ensure that the remote peer can no longer access the buffer.

    Note If the buffer can only be made inaccessible by the SAN service provider removing the buffer registration from the SAN NIC, the SAN service provider must do so. However, the SAN service provider should leave the buffer locked down to a region of physical memory. This scenario does not provide the best possible performance but is better than no caching.

  2. To cache RDMA buffers exposed for remote access, the SAN service provider and its proxy driver should use the caching techniques as described in the preceding list for RDMA buffers that are exposed for local access.
  3. When the switch subsequently calls WSPRegisterRdmaMemory to register a buffer, the SAN service provider should check its cache to determine if the buffer is already registered. If the SAN service provider finds the buffer in its cache, the SAN service provider should simply expose the buffer for remote access, no further registration action is required. However, if the buffer registration was previously removed from the SAN NIC, the SAN service provider should register the buffer again.
  4. To release RDMA buffers exposed for remote access, the SAN service provider and its proxy driver should use the techniques as described in the preceding list.


WSPStartupEx

WSPStartupEx initiates the Windows Sockets switch's use of a SAN service provider.

int
  WSPStartupEx(
    IN WORD  wVersionRequested,
    OUT LPWSPDATA  lpWSPData,
    IN LPWSAPROTOCOL_INFOW  lpProtocolInfo,
    IN LPWSPUPCALLTABLEEX  lpUpcallTable,
    OUT LPWSPPROC_TABLE  lpProcTable
    );

Parameters

wVersionRequested
Highest version of Windows Sockets SPI supported by the switch. The high-order byte specifies the minor version (revision) number; the low-order byte specifies the major version number.
lpWSPData
Pointer to a WSPDATA structure in which the SAN service provider returns information about itself.
lpProtocolInfo
Pointer to a WSAPROTOCOL_INFOW structure that specifies the characteristics of the protocol that is required for transferring data. Note that the switch passes the protocol-information structure of the TCP/IP protocol, not the protocol-information structure of the SAN service provider itself.
lpUpcallTable
Pointer to a WSPUPCALLTABLEEX structure that specifies the extended up-call dispatch table of the Windows Sockets Direct interface. The WSPUPCALLTABLEEX structure is defined as:
typedef struct _WSPUPCALLTABLEEX {
    LPWPUCLOSEEVENT                lpWPUCloseEvent;
    LPWPUCLOSESOCKETHANDLE         lpWPUCloseSocketHandle;
    LPWPUCREATEEVENT               lpWPUCreateEvent;
    LPWPUCREATESOCKETHANDLE        lpWPUCreateSocketHandle;
    LPWPUFDISSET                   lpWPUFDIsSet;
    LPWPUGETPROVIDERPATH           lpWPUGetProviderPath;
    LPWPUMODIFYIFSHANDLE           lpWPUModifyIFSHandle;
    LPWPUPOSTMESSAGE               lpWPUPostMessage;
    LPWPUQUERYBLOCKINGCALLBACK     lpWPUQueryBlockingCallback;
    LPWPUQUERYSOCKETHANDLECONTEXT  lpWPUQuerySocketHandleContext;
    LPWPUQUEUEAPC                  lpWPUQueueApc;
    LPWPURESETEVENT                lpWPUResetEvent;
    LPWPUSETEVENT                  lpWPUSetEvent;
    LPWPUOPENCURRENTTHREAD         lpWPUOpenCurrentThread;
    LPWPUCLOSETHREAD               lpWPUCloseThread;
    LPWPUCOMPLETEOVERLAPPEDREQUEST lpWPUCompleteOverlappedRequest;
} WSPUPCALLTABLEEX, FAR * LPWSPUPCALLTABLEEX;
lpProcTable
Pointer to a WSPPROC_TABLE structure that receives a table of pointers to the SAN service provider's entry points.

Return Value

Returns zero if successful; otherwise, returns one of the following error codes:

WSASYSNOTREADY
Underlying network subsystem not ready for network communication.
WSAVERNOTSUPPORTED
SAN service provider does not support the requested version of Windows Sockets SPI.
WSAEPROCLIM
Limit reached on the number of clients supported by the Windows Sockets implementation.
WSAEFAULT
Either lpWSPData or lpProcTable is invalid.

Headers

Defined in Ws2san.h. Include Ws2san.h. Requires Windows Sockets version 2.2.

Comments

The switch calls a SAN service provider's WSPStartupEx function before calling any of the SAN service provider's other functions. The switch does not call a SAN service provider's other functions until the WSPStartupEx function returns successfully.

In the call to the WSPStartupEx function, the switch passes the following to the SAN service provider:

The highest version of Windows Sockets SPI that the switch supports.

A pointer to a WSAPROTOCOL_INFOW structure. Note that the switch passes information on the TCP/IP protocol rather than information for the SAN service provider. The SAN service provider uses this information to determine whether it was loaded by the switch, by another layered service provider, or the Windows Sockets interface (Ws2_32.dll). A SAN service provider could expose one set of entry points to the switch and another set to applications that load the SAN service provider directly.

A pointer to the switch's up-call dispatch table. The SAN service provider uses this table to make up calls. Up calls are calls to Windows Sockets SPI functions that are prefixed with WPU. The switch intercepts and processes these up calls. A SAN service provider must use the WPUCompleteOverlappedRequest function referenced in the extended up-call dispatch table to complete overlapped I/O.

If the WSPStartupEx function succeeds, the SAN service provider passes the following back to the switch:

A pointer to a WSPDATA structure in which the SAN service provider returns information about itself.

A table of pointers to most of the SAN service provider's functions through lpProcTable. For a list of these functions, see Windows Sockets SPI Functions Required for SANs. To retrieve pointers to a SAN service provider's extension functions, the switch calls the SAN service provider's WSPIoctl function. For a list of the extension functions, see Windows Sockets Direct Extensions.

If the version specified by the switch in wVersionRequested is equal to or higher than the lowest version that the SAN service provider supports, the SAN service provider returns zero for success and its version information in a WSPDATA structure at lpWSPData. The SAN service provider specifies its version information in the wVersion member of this structure, it does not assign a value to the wHighVersion member of this structure. The switch only examines the value that the SAN service provider returns in the wVersion member. If the value in the wVersion member of WSPDATA is unacceptable to the switch, it immediately calls the SAN service provider's WSPCleanup function. In this case, the switch continues to use the TCP/IP service provider and could initiate and use other SAN service providers.

Note that SAN service providers must specify version 2.2 or higher in the wVersion member of WSPDATA.

The switch can call the WSPStartupEx function for the SAN service provider multiple times if the switch requires that the SAN service provider return information in a pointer to the WSPDATA structure more than once. On each such call, the switch can specify any version number that the SAN service provider supports. For each successful WSPStartupEx call that the switch makes, the switch makes a corresponding WSPCleanup call. For example, if the switch calls WSPStartupEx three times, the switch makes three corresponding calls to WSPCleanup. In the first two WSPCleanup calls, the SAN service provider should do nothing except decrement an internal counter. In the final WSPCleanup call, the SAN service provider should release all previously allocated resources.

See Also

WSAPROTOCOL_INFOW, WSPCleanup, WSPDATA, WSPIoctl


WSPGetOverlappedResult

WSPGetOverlappedResult returns the results of an asynchronous (overlapped) operation on a socket. This operation previously indicated that it was pending completion.

BOOL
  WSPGetOverlappedResult(
    IN SOCKET  s,
    IN LPWSAOVERLAPPED  lpOverlapped,
    OUT LPDWORD  lpcbTransfer,
    IN BOOL  fWait,
    OUT LPDWORD  lpdwFlags,
    OUT LPINT  lpErrno
    );

Parameters

s
Descriptor that identifies the socket. The switch specified this socket when it called the SAN service provider's WSPRecv, WSPSend, WSPRdmaRead, WSPRdmaWrite, or WSPIoctl function to start the overlapped operation.
lpOverlapped
Pointer to a WSAOVERLAPPED structure that the switch specified when it started the overlapped operation.
lpcbTransfer
Pointer to a variable that receives the number of bytes that were actually transferred by a send or receive operation, or by WSPIoctl.
fWait
Boolean value that is TRUE to specify that WSPGetOverlappedResult must wait for the pending overlapped operation to complete before returning; and FALSE to specify that if the overlapped operation is still pending, WSPGetOverlappedResult must return FALSE and, at lpErrno, WSA_IO_INCOMPLETE.
lpdwFlags
Pointer to a variable that receives one or more flags that supplement the completion status. If the switch called WSPRecv to initiate the overlapped operation, lpdwFlags receives the results value for the flags that were specified in the WSPRecv call.
lpErrno
Pointer to a variable that receives the error code.

Return Value

Returns TRUE if successful; otherwise, returns FALSE and, at lpErrno, one of the following error codes:

WSAENETDOWN
Network subsystem failed.
WSAENOTSOCK
Descriptor is not a socket.
WSA_INVALID_HANDLE
The hEvent member of the WSAOVERLAPPED structure does not contain a valid handle to an event object.
WSA_INVALID_PARAMETER
One of the parameters is unacceptable.
WSA_IO_INCOMPLETE
The I/O operation has not yet completed. The SAN service provider can only return this error if the switch passed FALSE to the fWait parameter.

Headers

Defined in Ws2spi.h. Include Ws2spi.h. Requires Windows Sockets version 2.0.

Comments

The Windows Sockets switch calls a SAN service provider's WSPGetOverlappedResult function to obtain the results of an overlapped (asynchronous) operation that was previously started on a specific socket but not completed. The results reported are those of the specified socket's last overlapped operation to which the specified pointer to a WSAOVERLAPPED structure was provided, and for which the operation's results were pending. The switch can call the WSPRecv, WSPRdmaRead, WSPSend, WSPRdmaWrite, or WSPIoctl function to start an overlapped operation on a socket. These functions can return SOCKET_ERROR and the WSA_IO_PENDING error code to indicate that an overlapped operation started and that completion of that operation occurs later. If an I/O operation is pending, the function that started the operation can call the Win32® ResetEvent function to reset the hEvent member of the WSAOVERLAPPED structure to the nonsignaled state. After the pending operation completes, the operating system sets the event object to the signaled state.

If the switch set fWait to TRUE, WSPGetOverlappedResult blocks and waits for the event object to be set to the signaled state to determine whether the pending overlapped operation completed. The switch can set fWait to TRUE only if it also selected event-based completion notification when it requested the I/O operation. If another form of notification was selected, the usage of the hEvent member of the WSAOVERLAPPED structure is different, and setting fWait to TRUE causes unpredictable results.

If WSPGetOverlappedResult returns TRUE, the overlapped operation completed successfully and the SAN service provider updated the value at lpcbTransfer. If WSPGetOverlappedResult returns FALSE, one of the following occurred:

The overlapped operation did not complete

The overlapped operation completed but with errors

Completion status could not be determined due to errors in one or more parameters passed to WSPGetOverlappedResult.

On failure, the SAN service provider does not update the value at lpcbTransfer and sets the value at lpErrno to indicate the cause of the failure. Either WSPGetOverlappedResult or the associated overlapped operation can be the cause of the failure.

Interaction with WPUCompleteOverlappedRequest

The behavior of the WPUCompleteOverlappedRequest function places some constraints on how a SAN service provider implements WSPGetOverlappedResult because only the Offset and OffsetHigh members of the WSAOVERLAPPED structure are exclusively controlled by the SAN service provider even though the SAN service provider's WSPGetOverlappedResult function must retrieve three values (byte count, flags, and error) from the structure. A SAN service provider can retrieve these three values any way it chooses as long as it interacts with the behavior of WPUCompleteOverlappedRequest properly. The following sequence presents a typical implementation:

  1. At the start of an I/O operation, the SAN service provider sets the Internal member of the WSAOVERLAPPED structure to WSS_OPERATION_IN_PROGRESS.
  2. After the I/O operation is complete, the SAN service provider performs the following actions:
    • Sets OffsetHigh to the Windows Sockets error code resulting from the I/O operation
    • Sets Offset to the flags resulting from the I/O operation
    • Calls WPUCompleteOverlappedRequest and passes the number of bytes transferred.
  3. WPUCompleteOverlappedRequest eventually sets the InternalHigh member of the WSAOVERLAPPED structure to the number of bytes transferred and then sets Internal to a value other than WSS_OPERATION_IN_PROGRESS.
  4. After the switch calls the SAN service provider's WSPGetOverlappedResult function, the SAN service provider checks the value in Internal. If the value is WSS_OPERATION_IN_PROGRESS, the SAN service provider waits for the event object (hEvent member) to be set to the signaled state or returns an error, based on the value that the switch passed to fWait. If the value is not WSS_OPERATION_IN_PROGRESS, or after the operating system signals the event object, the SAN service provider returns the number of bytes transferred, operation result error code, and flags in the InternalHigh, OffsetHigh, and Offset members respectively.

See Also

WSAOVERLAPPED, WSPRecv, WSPSend, WSPConnect, WSPAccept, WSPIoctl, WSPRdmaRead, WSPRdmaWrite